Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net

Pull more networking updates from David Miller:
 "Ok, everything from here on out will be bug fixes."

1) One final sync of wireless and bluetooth stuff from John Linville.
   These changes have all been in his tree for more than a week, and
   therefore have had the necessary -next exposure.  John was just away
   on a trip and didn't have a change to send the pull request until a
   day or two ago.

2) Put back some defines in user exposed header file areas that were
   removed during the tokenring purge.  From Stephen Hemminger and Paul
   Gortmaker.

3) A bug fix for UDP hash table allocation got lost in the pile due to
   one of those "you got it..  no I've got it.." situations.  :-)

   From Tim Bird.

4) SKB coalescing in TCP needs to have stricter checks, otherwise we'll
   try to coalesce overlapping frags and crash.  Fix from Eric Dumazet.

5) RCU routing table lookups can race with free_fib_info(), causing
   crashes when we deref the device pointers in the route.  Fix by
   releasing the net device in the RCU callback.  From Yanmin Zhang.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (293 commits)
  tcp: take care of overlaps in tcp_try_coalesce()
  ipv4: fix the rcu race between free_fib_info and ip_route_output_slow
  mm: add a low limit to alloc_large_system_hash
  ipx: restore token ring define to include/linux/ipx.h
  if: restore token ring ARP type to header
  xen: do not disable netfront in dom0
  phy/micrel: Fix ID of KSZ9021
  mISDN: Add X-Tensions USB ISDN TA XC-525
  gianfar:don't add FCB length to hard_header_len
  Bluetooth: Report proper error number in disconnection
  Bluetooth: Create flags for bt_sk()
  Bluetooth: report the right security level in getsockopt
  Bluetooth: Lock the L2CAP channel when sending
  Bluetooth: Restore locking semantics when looking up L2CAP channels
  Bluetooth: Fix a redundant and problematic incoming MTU check
  Bluetooth: Add support for Foxconn/Hon Hai AR5BBU22 0489:E03C
  Bluetooth: Fix EIR data generation for mgmt_device_found
  Bluetooth: Fix Inquiry with RSSI event mask
  Bluetooth: improve readability of l2cap_seq_list code
  Bluetooth: Fix skb length calculation
  ...
diff --git a/CREDITS b/CREDITS
index 370b4c7..d8fe12a 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3814,8 +3814,8 @@
 D: Author of the longest-living linux bug
 
 N: Jonathan Woithe
-E: jwoithe@physics.adelaide.edu.au
-W: http://www.physics.adelaide.edu.au/~jwoithe
+E: jwoithe@just42.net
+W: http:/www.just42.net/jwoithe
 D: ALS-007 sound card extensions to Sound Blaster driver
 S: 20 Jordan St
 S: Valley View, SA 5093
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 2214f12..49c0513 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -218,8 +218,6 @@
 	- directory with info about Linux on Motorola 68k architecture.
 magic-number.txt
 	- list of magic numbers used to mark/protect kernel data structures.
-mca.txt
-	- info on supporting Micro Channel Architecture (e.g. PS/2) systems.
 md.txt
 	- info on boot arguments for the multiple devices driver.
 memory-barriers.txt
diff --git a/Documentation/ABI/testing/debugfs-pfo-nx-crypto b/Documentation/ABI/testing/debugfs-pfo-nx-crypto
new file mode 100644
index 0000000..685d5a4
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-pfo-nx-crypto
@@ -0,0 +1,45 @@
+What:		/sys/kernel/debug/nx-crypto/*
+Date:		March 2012
+KernelVersion:	3.4
+Contact:	Kent Yoder <key@linux.vnet.ibm.com>
+Description:
+
+  These debugfs interfaces are built by the nx-crypto driver, built in
+arch/powerpc/crypto/nx.
+
+Error Detection
+===============
+
+errors:
+- A u32 providing a total count of errors since the driver was loaded. The
+only errors counted here are those returned from the hcall, H_COP_OP.
+
+last_error:
+- The most recent non-zero return code from the H_COP_OP hcall. -EBUSY is not
+recorded here (the hcall will retry until -EBUSY goes away).
+
+last_error_pid:
+- The process ID of the process who received the most recent error from the
+hcall.
+
+Device Use
+==========
+
+aes_bytes:
+- The total number of bytes encrypted using AES in any of the driver's
+supported modes.
+
+aes_ops:
+- The total number of AES operations submitted to the hardware.
+
+sha256_bytes:
+- The total number of bytes hashed by the hardware using SHA-256.
+
+sha256_ops:
+- The total number of SHA-256 operations submitted to the hardware.
+
+sha512_bytes:
+- The total number of bytes hashed by the hardware using SHA-512.
+
+sha512_ops:
+- The total number of SHA-512 operations submitted to the hardware.
diff --git a/Documentation/ABI/testing/dev-kmsg b/Documentation/ABI/testing/dev-kmsg
new file mode 100644
index 0000000..281ecc5
--- /dev/null
+++ b/Documentation/ABI/testing/dev-kmsg
@@ -0,0 +1,90 @@
+What:		/dev/kmsg
+Date:		Mai 2012
+KernelVersion:	3.5
+Contact:	Kay Sievers <kay@vrfy.org>
+Description:	The /dev/kmsg character device node provides userspace access
+		to the kernel's printk buffer.
+
+		Injecting messages:
+		Every write() to the opened device node places a log entry in
+		the kernel's printk buffer.
+
+		The logged line can be prefixed with a <N> syslog prefix, which
+		carries the syslog priority and facility. The single decimal
+		prefix number is composed of the 3 lowest bits being the syslog
+		priority and the higher bits the syslog facility number.
+
+		If no prefix is given, the priority number is the default kernel
+		log priority and the facility number is set to LOG_USER (1). It
+		is not possible to inject messages from userspace with the
+		facility number LOG_KERN (0), to make sure that the origin of
+		the messages can always be reliably determined.
+
+		Accessing the buffer:
+		Every read() from the opened device node receives one record
+		of the kernel's printk buffer.
+
+		The first read() directly following an open() always returns
+		first message in the buffer; there is no kernel-internal
+		persistent state; many readers can concurrently open the device
+		and read from it, without affecting other readers.
+
+		Every read() will receive the next available record. If no more
+		records are available read() will block, or if O_NONBLOCK is
+		used -EAGAIN returned.
+
+		Messages in the record ring buffer get overwritten as whole,
+		there are never partial messages received by read().
+
+		In case messages get overwritten in the circular buffer while
+		the device is kept open, the next read() will return -EPIPE,
+		and the seek position be updated to the next available record.
+		Subsequent reads() will return available records again.
+
+		Unlike the classic syslog() interface, the 64 bit record
+		sequence numbers allow to calculate the amount of lost
+		messages, in case the buffer gets overwritten. And they allow
+		to reconnect to the buffer and reconstruct the read position
+		if needed, without limiting the interface to a single reader.
+
+		The device supports seek with the following parameters:
+		SEEK_SET, 0
+		  seek to the first entry in the buffer
+		SEEK_END, 0
+		  seek after the last entry in the buffer
+		SEEK_DATA, 0
+		  seek after the last record available at the time
+		  the last SYSLOG_ACTION_CLEAR was issued.
+
+		The output format consists of a prefix carrying the syslog
+		prefix including priority and facility, the 64 bit message
+		sequence number and the monotonic timestamp in microseconds.
+		The values are separated by a ','. Future extensions might
+		add more comma separated values before the terminating ';'.
+		Unknown values should be gracefully ignored.
+
+		The human readable text string starts directly after the ';'
+		and is terminated by a '\n'. Untrusted values derived from
+		hardware or other facilities are printed, therefore
+		all non-printable characters in the log message are escaped
+		by "\x00" C-style hex encoding.
+
+		A line starting with ' ', is a continuation line, adding
+		key/value pairs to the log message, which provide the machine
+		readable context of the message, for reliable processing in
+		userspace.
+
+		Example:
+		7,160,424069;pci_root PNP0A03:00: host bridge window [io  0x0000-0x0cf7] (ignored)
+		 SUBSYSTEM=acpi
+		 DEVICE=+acpi:PNP0A03:00
+		6,339,5140900;NET: Registered protocol family 10
+		30,340,5690716;udevd[80]: starting version 181
+
+		The DEVICE= key uniquely identifies devices the following way:
+		  b12:8        - block dev_t
+		  c127:3       - char dev_t
+		  n8           - netdev ifindex
+		  +sound:card0 - subsystem:devname
+
+Users:		dmesg(1), userspace kernel log consumers
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
new file mode 100644
index 0000000..5bc8a47
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -0,0 +1,737 @@
+What:		/sys/bus/iio/devices/iio:deviceX
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Hardware chip or device accessed by one communication port.
+		Corresponds to a grouping of sensor channels. X is the IIO
+		index of the device.
+
+What:		/sys/bus/iio/devices/triggerX
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		An event driven driver of data capture to an in kernel buffer.
+		May be provided by a device driver that also has an IIO device
+		based on hardware generated events (e.g. data ready) or
+		provided by a separate driver for other hardware (e.g.
+		periodic timer, GPIO or high resolution timer).
+		Contains trigger type specific elements. These do not
+		generalize well and hence are not documented in this file.
+		X is the IIO index of the trigger.
+
+What:		/sys/bus/iio/devices/iio:deviceX/buffer
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Directory of attributes relating to the buffer for the device.
+
+What:		/sys/bus/iio/devices/iio:deviceX/name
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Description of the physical chip / device for device X.
+		Typically a part number.
+
+What:		/sys/bus/iio/devices/iio:deviceX/sampling_frequency
+What:		/sys/bus/iio/devices/iio:deviceX/buffer/sampling_frequency
+What:		/sys/bus/iio/devices/triggerX/sampling_frequency
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Some devices have internal clocks.  This parameter sets the
+		resulting sampling frequency.  In many devices this
+		parameter has an effect on input filters etc rather than
+		simply controlling when the input is sampled.  As this
+		effects datardy triggers, hardware buffers and the sysfs
+		direct access interfaces, it may be found in any of the
+		relevant directories.  If it effects all of the above
+		then it is to be found in the base device directory.
+
+What:		/sys/bus/iio/devices/iio:deviceX/sampling_frequency_available
+What:		/sys/.../iio:deviceX/buffer/sampling_frequency_available
+What:		/sys/bus/iio/devices/triggerX/sampling_frequency_available
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		When the internal sampling clock can only take a small
+		discrete set of values, this file lists those available.
+
+What:		/sys/bus/iio/devices/iio:deviceX/oversampling_ratio
+KernelVersion:	2.6.38
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Hardware dependent ADC oversampling. Controls the sampling ratio
+		of the digital filter if available.
+
+What:		/sys/bus/iio/devices/iio:deviceX/oversampling_ratio_available
+KernelVersion:	2.6.38
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Hardware dependent values supported by the oversampling filter.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled no bias removal etc) voltage measurement from
+		channel Y. In special cases where the channel does not
+		correspond to externally available input one of the named
+		versions may be used. The number must always be specified and
+		unique to allow association with event codes. Units after
+		application of scale and offset are microvolts.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_raw
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled) differential voltage measurement equivalent to
+		channel Y - channel Z where these channel numbers apply to the
+		physically equivalent inputs when non differential readings are
+		separately available. In differential only parts, then all that
+		is required is a consistent labeling.  Units after application
+		of scale and offset are microvolts.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw
+KernelVersion:	3.2
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw capacitance measurement from channel Y. Units after
+		application of scale and offset are nanofarads.
+
+What:		/sys/.../iio:deviceX/in_capacitanceY-in_capacitanceZ_raw
+KernelVersion:	3.2
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw differential capacitance measurement equivalent to
+		channel Y - channel Z where these channel numbers apply to the
+		physically equivalent inputs when non differential readings are
+		separately available. In differential only parts, then all that
+		is required is a consistent labeling.  Units after application
+		of scale and offset are nanofarads.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_temp_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_tempX_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_temp_x_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_temp_y_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_temp_z_raw
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled no bias removal etc) temperature measurement.
+		If an axis is specified it generally means that the temperature
+		sensor is associated with one part of a compound device (e.g.
+		a gyroscope axis). Units after application of scale and offset
+		are milli degrees Celsuis.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_tempX_input
+KernelVersion:	2.6.38
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Scaled temperature measurement in milli degrees Celsius.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_x_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_raw
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Acceleration in direction x, y or z (may be arbitrarily assigned
+		but should match other such assignments on device).
+		Has all of the equivalent parameters as per voltageY. Units
+		after application of scale and offset are m/s^2.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_x_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_y_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_z_raw
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Angular velocity about axis x, y or z (may be arbitrarily
+		assigned) Data converted by application of offset then scale to
+		radians per second. Has all the equivalent parameters as
+		per voltageY. Units after application of scale and offset are
+		radians per second.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_incli_x_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_incli_y_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_incli_z_raw
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Inclination raw reading about axis x, y or z (may be
+		arbitrarily assigned). Data converted by application of offset
+		and scale to Degrees.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_z_raw
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Magnetic field along axis x, y or z (may be arbitrarily
+		assigned).  Data converted by application of offset
+		then scale to Gauss.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_x_peak_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_peak_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_peak_raw
+KernelVersion:	2.6.36
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Highest value since some reset condition.  These
+		attributes allow access to this and are otherwise
+		the direct equivalent of the <type>Y[_name]_raw attributes.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_xyz_squared_peak_raw
+KernelVersion:	2.6.36
+Contact:	linux-iio@vger.kernel.org
+Description:
+		A computed peak value based on the sum squared magnitude of
+		the underlying value in the specified directions.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_x_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_tempY_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_temp_offset
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		If known for a device, offset to be added to <type>[Y]_raw prior
+		to scaling by <type>[Y]_scale in order to obtain value in the
+		<type> units as specified in <type>[y]_raw documentation.
+		Not present if the offset is always 0 or unknown. If Y or
+		axis <x|y|z> is not present, then the offset applies to all
+		in channels of <type>.
+		May be writable if a variable offset can be applied on the
+		device. Note that this is different to calibbias which
+		is for devices (or drivers) that apply offsets to compensate
+		for variation between different instances of the part, typically
+		adjusted by using some hardware supported calibration procedure.
+		Calibbias is applied internally, offset is applied in userspace
+		to the _raw output.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_scale
+What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_z_scale
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		If known for a device, scale to be applied to <type>Y[_name]_raw
+		post addition of <type>[Y][_name]_offset in order to obtain the
+		measured value in <type> units as specified in
+		<type>[Y][_name]_raw documentation.  If shared across all in
+		channels then Y and <x|y|z> are not present and the value is
+		called <type>[Y][_name]_scale. The peak modifier means this
+		value is applied to <type>Y[_name]_peak_raw values.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_x_calibbias
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_calibbias
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias
+What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias
+What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias
+What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias
+What:		/sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibbias
+What:		/sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Hardware applied calibration offset. (assumed to fix production
+		inaccuracies).
+
+What		/sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale
+what		/sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale
+what		/sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Hardware applied calibration scale factor. (assumed to fix
+		production inaccuracies).  If shared across all channels,
+		<type>_calibscale is used.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
+What:		/sys/.../iio:deviceX/in_voltageX_scale_available
+What:		/sys/.../iio:deviceX/in_voltage-voltage_scale_available
+What:		/sys/.../iio:deviceX/out_voltageX_scale_available
+What:		/sys/.../iio:deviceX/in_capacitance_scale_available
+KernelVersion:	2.635
+Contact:	linux-iio@vger.kernel.org
+Description:
+		If a discrete set of scale values are available, they
+		are listed in this attribute.
+
+What		/sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Hardware applied gain factor. If shared across all channels,
+		<type>_hardwaregain is used.
+
+What:		/sys/.../in_accel_filter_low_pass_3db_frequency
+What:		/sys/.../in_magn_filter_low_pass_3db_frequency
+What:		/sys/.../in_anglvel_filter_low_pass_3db_frequency
+KernelVersion:	3.2
+Contact:	linux-iio@vger.kernel.org
+Description:
+		If a known or controllable low pass filter is applied
+		to the underlying data channel, then this parameter
+		gives the 3dB frequency of the filter in Hz.
+
+What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_raw
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled, no bias etc.) output voltage for
+		channel Y.  The number must always be specified and
+		unique if the output corresponds to a single channel.
+
+What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY&Z_raw
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled, no bias etc.) output voltage for an aggregate of
+		channel Y, channel Z, etc.  This interface is available in cases
+		where a single output sets the value for multiple channels
+		simultaneously.
+
+What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown_mode
+What:		/sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown_mode
+KernelVersion:	2.6.38
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Specifies the output powerdown mode.
+		DAC output stage is disconnected from the amplifier and
+		1kohm_to_gnd: connected to ground via an 1kOhm resistor
+		100kohm_to_gnd: connected to ground via an 100kOhm resistor
+		three_state: left floating
+		For a list of available output power down options read
+		outX_powerdown_mode_available. If Y is not present the
+		mode is shared across all outputs.
+
+What:		/sys/.../iio:deviceX/out_votlageY_powerdown_mode_available
+What:		/sys/.../iio:deviceX/out_voltage_powerdown_mode_available
+KernelVersion:	2.6.38
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Lists all available output power down modes.
+		If Y is not present the mode is shared across all outputs.
+
+What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown
+What:		/sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown
+KernelVersion:	2.6.38
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Writing 1 causes output Y to enter the power down mode specified
+		by the corresponding outY_powerdown_mode. Clearing returns to
+		normal operation. Y may be suppressed if all outputs are
+		controlled together.
+
+What:		/sys/bus/iio/devices/iio:deviceX/events
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Configuration of which hardware generated events are passed up
+		to user-space.
+
+What:		/sys/.../iio:deviceX/events/in_accel_x_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_x_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_accel_y_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_y_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_accel_z_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_z_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_x_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_x_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_y_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_y_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_z_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_z_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_magn_x_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_magn_x_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_magn_y_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_magn_y_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_magn_z_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_magn_z_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_tempY_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_tempY_thresh_falling_en
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Event generated when channel passes a threshold in the specified
+		(_rising|_falling) direction. If the direction is not specified,
+		then either the device will report an event which ever direction
+		a single threshold value is passed in (e.g.
+		<type>[Y][_name]_<raw|input>_thresh_value) or
+		<type>[Y][_name]_<raw|input>_thresh_rising_value and
+		<type>[Y][_name]_<raw|input>_thresh_falling_value may take
+		different values, but the device can only enable both thresholds
+		or neither.
+		Note the driver will assume the last p events requested are
+		to be enabled where p is however many it supports (which may
+		vary depending on the exact set requested. So if you want to be
+		sure you have set what you think you have, check the contents of
+		these attributes after everything is configured. Drivers may
+		have to buffer any parameters so that they are consistent when
+		a given event type is enabled a future point (and not those for
+		whatever event was previously enabled).
+
+What:		/sys/.../iio:deviceX/events/in_accel_x_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_x_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_accel_y_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_y_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_accel_z_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_z_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_x_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_x_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_y_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_y_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_z_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_anglvel_z_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_magn_x_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_magn_x_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_magn_y_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_magn_y_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_magn_z_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_magn_z_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_voltageY_supply_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_voltageY_supply_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_voltageY_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_voltageY_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_tempY_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_tempY_roc_falling_en
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Event generated when channel passes a threshold on the rate of
+		change (1st differential) in the specified (_rising|_falling)
+		direction. If the direction is not specified, then either the
+		device will report an event which ever direction a single
+		threshold value is passed in (e.g.
+		<type>[Y][_name]_<raw|input>_roc_value) or
+		<type>[Y][_name]_<raw|input>_roc_rising_value and
+		<type>[Y][_name]_<raw|input>_roc_falling_value may take
+		different values, but the device can only enable both rate of
+		change thresholds or neither.
+		Note the driver will assume the last p events requested are
+		to be enabled where p is however many it supports (which may
+		vary depending on the exact set requested. So if you want to be
+		sure you have set what you think you have, check the contents of
+		these attributes after everything is configured. Drivers may
+		have to buffer any parameters so that they are consistent when
+		a given event type is enabled a future point (and not those for
+		whatever event was previously enabled).
+
+What:		/sys/.../events/in_accel_x_raw_thresh_rising_value
+What:		/sys/.../events/in_accel_x_raw_thresh_falling_value
+What:		/sys/.../events/in_accel_y_raw_thresh_rising_value
+What:		/sys/.../events/in_accel_y_raw_thresh_falling_value
+What:		/sys/.../events/in_accel_z_raw_thresh_rising_value
+What:		/sys/.../events/in_accel_z_raw_thresh_falling_value
+What:		/sys/.../events/in_anglvel_x_raw_thresh_rising_value
+What:		/sys/.../events/in_anglvel_x_raw_thresh_falling_value
+What:		/sys/.../events/in_anglvel_y_raw_thresh_rising_value
+What:		/sys/.../events/in_anglvel_y_raw_thresh_falling_value
+What:		/sys/.../events/in_anglvel_z_raw_thresh_rising_value
+What:		/sys/.../events/in_anglvel_z_raw_thresh_falling_value
+What:		/sys/.../events/in_magn_x_raw_thresh_rising_value
+What:		/sys/.../events/in_magn_x_raw_thresh_falling_value
+What:		/sys/.../events/in_magn_y_raw_thresh_rising_value
+What:		/sys/.../events/in_magn_y_raw_thresh_falling_value
+What:		/sys/.../events/in_magn_z_raw_thresh_rising_value
+What:		/sys/.../events/in_magn_z_raw_thresh_falling_value
+What:		/sys/.../events/in_voltageY_supply_raw_thresh_rising_value
+What:		/sys/.../events/in_voltageY_supply_raw_thresh_falling_value
+What:		/sys/.../events/in_voltageY_raw_thresh_rising_value
+What:		/sys/.../events/in_voltageY_raw_thresh_falling_value
+What:		/sys/.../events/in_tempY_raw_thresh_rising_value
+What:		/sys/.../events/in_tempY_raw_thresh_falling_value
+What:		/sys/.../events/in_illuminance0_thresh_falling_value
+what:		/sys/.../events/in_illuminance0_thresh_rising_value
+what:		/sys/.../events/in_proximity0_thresh_falling_value
+what:		/sys/.../events/in_proximity0_thresh_rising_value
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Specifies the value of threshold that the device is comparing
+		against for the events enabled by
+		<type>Y[_name]_thresh[_rising|falling]_en.
+		If separate attributes exist for the two directions, but
+		direction is not specified for this attribute, then a single
+		threshold value applies to both directions.
+		The raw or input element of the name indicates whether the
+		value is in raw device units or in processed units (as _raw
+		and _input do on sysfs direct channel read attributes).
+
+What:		/sys/.../events/in_accel_x_raw_roc_rising_value
+What:		/sys/.../events/in_accel_x_raw_roc_falling_value
+What:		/sys/.../events/in_accel_y_raw_roc_rising_value
+What:		/sys/.../events/in_accel_y_raw_roc_falling_value
+What:		/sys/.../events/in_accel_z_raw_roc_rising_value
+What:		/sys/.../events/in_accel_z_raw_roc_falling_value
+What:		/sys/.../events/in_anglvel_x_raw_roc_rising_value
+What:		/sys/.../events/in_anglvel_x_raw_roc_falling_value
+What:		/sys/.../events/in_anglvel_y_raw_roc_rising_value
+What:		/sys/.../events/in_anglvel_y_raw_roc_falling_value
+What:		/sys/.../events/in_anglvel_z_raw_roc_rising_value
+What:		/sys/.../events/in_anglvel_z_raw_roc_falling_value
+What:		/sys/.../events/in_magn_x_raw_roc_rising_value
+What:		/sys/.../events/in_magn_x_raw_roc_falling_value
+What:		/sys/.../events/in_magn_y_raw_roc_rising_value
+What:		/sys/.../events/in_magn_y_raw_roc_falling_value
+What:		/sys/.../events/in_magn_z_raw_roc_rising_value
+What:		/sys/.../events/in_magn_z_raw_roc_falling_value
+What:		/sys/.../events/in_voltageY_supply_raw_roc_rising_value
+What:		/sys/.../events/in_voltageY_supply_raw_roc_falling_value
+What:		/sys/.../events/in_voltageY_raw_roc_rising_value
+What:		/sys/.../events/in_voltageY_raw_roc_falling_value
+What:		/sys/.../events/in_tempY_raw_roc_rising_value
+What:		/sys/.../events/in_tempY_raw_roc_falling_value
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Specifies the value of rate of change threshold that the
+		device is comparing against for the events enabled by
+		<type>[Y][_name]_roc[_rising|falling]_en.
+		If separate attributes exist for the two directions,
+		but direction is not specified for this attribute,
+		then a single threshold value applies to both directions.
+		The raw or input element of the name indicates whether the
+		value is in raw device units or in processed units (as _raw
+		and _input do on sysfs direct channel read attributes).
+
+What:		/sys/.../events/in_accel_x_thresh_rising_period
+What:		/sys/.../events/in_accel_x_thresh_falling_period
+hat:		/sys/.../events/in_accel_x_roc_rising_period
+What:		/sys/.../events/in_accel_x_roc_falling_period
+What:		/sys/.../events/in_accel_y_thresh_rising_period
+What:		/sys/.../events/in_accel_y_thresh_falling_period
+What:		/sys/.../events/in_accel_y_roc_rising_period
+What:		/sys/.../events/in_accel_y_roc_falling_period
+What:		/sys/.../events/in_accel_z_thresh_rising_period
+What:		/sys/.../events/in_accel_z_thresh_falling_period
+What:		/sys/.../events/in_accel_z_roc_rising_period
+What:		/sys/.../events/in_accel_z_roc_falling_period
+What:		/sys/.../events/in_anglvel_x_thresh_rising_period
+What:		/sys/.../events/in_anglvel_x_thresh_falling_period
+What:		/sys/.../events/in_anglvel_x_roc_rising_period
+What:		/sys/.../events/in_anglvel_x_roc_falling_period
+What:		/sys/.../events/in_anglvel_y_thresh_rising_period
+What:		/sys/.../events/in_anglvel_y_thresh_falling_period
+What:		/sys/.../events/in_anglvel_y_roc_rising_period
+What:		/sys/.../events/in_anglvel_y_roc_falling_period
+What:		/sys/.../events/in_anglvel_z_thresh_rising_period
+What:		/sys/.../events/in_anglvel_z_thresh_falling_period
+What:		/sys/.../events/in_anglvel_z_roc_rising_period
+What:		/sys/.../events/in_anglvel_z_roc_falling_period
+What:		/sys/.../events/in_magn_x_thresh_rising_period
+What:		/sys/.../events/in_magn_x_thresh_falling_period
+What:		/sys/.../events/in_magn_x_roc_rising_period
+What:		/sys/.../events/in_magn_x_roc_falling_period
+What:		/sys/.../events/in_magn_y_thresh_rising_period
+What:		/sys/.../events/in_magn_y_thresh_falling_period
+What:		/sys/.../events/in_magn_y_roc_rising_period
+What:		/sys/.../events/in_magn_y_roc_falling_period
+What:		/sys/.../events/in_magn_z_thresh_rising_period
+What:		/sys/.../events/in_magn_z_thresh_falling_period
+What:		/sys/.../events/in_magn_z_roc_rising_period
+What:		/sys/.../events/in_magn_z_roc_falling_period
+What:		/sys/.../events/in_voltageY_supply_thresh_rising_period
+What:		/sys/.../events/in_voltageY_supply_thresh_falling_period
+What:		/sys/.../events/in_voltageY_supply_roc_rising_period
+What:		/sys/.../events/in_voltageY_supply_roc_falling_period
+What:		/sys/.../events/in_voltageY_thresh_rising_period
+What:		/sys/.../events/in_voltageY_thresh_falling_period
+What:		/sys/.../events/in_voltageY_roc_rising_period
+What:		/sys/.../events/in_voltageY_roc_falling_period
+What:		/sys/.../events/in_tempY_thresh_rising_period
+What:		/sys/.../events/in_tempY_thresh_falling_period
+What:		/sys/.../events/in_tempY_roc_rising_period
+What:		/sys/.../events/in_tempY_roc_falling_period
+What:		/sys/.../events/in_accel_x&y&z_mag_falling_period
+What:		/sys/.../events/in_intensity0_thresh_period
+What:		/sys/.../events/in_proximity0_thresh_period
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Period of time (in seconds) for which the condition must be
+		met before an event is generated. If direction is not
+		specified then this period applies to both directions.
+
+What:		/sys/.../iio:deviceX/events/in_accel_mag_en
+What:		/sys/.../iio:deviceX/events/in_accel_mag_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_mag_falling_en
+What:		/sys/.../iio:deviceX/events/in_accel_x_mag_en
+What:		/sys/.../iio:deviceX/events/in_accel_x_mag_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_x_mag_falling_en
+What:		/sys/.../iio:deviceX/events/in_accel_y_mag_en
+What:		/sys/.../iio:deviceX/events/in_accel_y_mag_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_y_mag_falling_en
+What:		/sys/.../iio:deviceX/events/in_accel_z_mag_en
+What:		/sys/.../iio:deviceX/events/in_accel_z_mag_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_z_mag_falling_en
+What:		/sys/.../iio:deviceX/events/in_accel_x&y&z_mag_rising_en
+What:		/sys/.../iio:deviceX/events/in_accel_x&y&z_mag_falling_en
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Similar to in_accel_x_thresh[_rising|_falling]_en, but here the
+		magnitude of the channel is compared to the threshold, not its
+		signed value.
+
+What:		/sys/.../events/in_accel_raw_mag_value
+What:		/sys/.../events/in_accel_x_raw_mag_rising_value
+What:		/sys/.../events/in_accel_y_raw_mag_rising_value
+What:		/sys/.../events/in_accel_z_raw_mag_rising_value
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		The value to which the magnitude of the channel is compared. If
+		number or direction is not specified, applies to all channels of
+		this type.
+
+What:		/sys/bus/iio/devices/iio:deviceX/trigger/current_trigger
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		The name of the trigger source being used, as per string given
+		in /sys/class/iio/triggerY/name.
+
+What:		/sys/bus/iio/devices/iio:deviceX/buffer/length
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Number of scans contained by the buffer.
+
+What:		/sys/bus/iio/devices/iio:deviceX/buffer/bytes_per_datum
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Bytes per scan.  Due to alignment fun, the scan may be larger
+		than implied directly by the scan_element parameters.
+
+What:		/sys/bus/iio/devices/iio:deviceX/buffer/enable
+KernelVersion:	2.6.35
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Actually start the buffer capture up.  Will start trigger
+		if first device and appropriate.
+
+What:		/sys/bus/iio/devices/iio:deviceX/buffer/scan_elements
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Directory containing interfaces for elements that will be
+		captured for a single triggered sample set in the buffer.
+
+What:		/sys/.../buffer/scan_elements/in_accel_x_en
+What:		/sys/.../buffer/scan_elements/in_accel_y_en
+What:		/sys/.../buffer/scan_elements/in_accel_z_en
+What:		/sys/.../buffer/scan_elements/in_anglvel_x_en
+What:		/sys/.../buffer/scan_elements/in_anglvel_y_en
+What:		/sys/.../buffer/scan_elements/in_anglvel_z_en
+What:		/sys/.../buffer/scan_elements/in_magn_x_en
+What:		/sys/.../buffer/scan_elements/in_magn_y_en
+What:		/sys/.../buffer/scan_elements/in_magn_z_en
+What:		/sys/.../buffer/scan_elements/in_timestamp_en
+What:		/sys/.../buffer/scan_elements/in_voltageY_supply_en
+What:		/sys/.../buffer/scan_elements/in_voltageY_en
+What:		/sys/.../buffer/scan_elements/in_voltageY-voltageZ_en
+What:		/sys/.../buffer/scan_elements/in_incli_x_en
+What:		/sys/.../buffer/scan_elements/in_incli_y_en
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Scan element control for triggered data capture.
+
+What:		/sys/.../buffer/scan_elements/in_accel_type
+What:		/sys/.../buffer/scan_elements/in_anglvel_type
+What:		/sys/.../buffer/scan_elements/in_magn_type
+What:		/sys/.../buffer/scan_elements/in_incli_type
+What:		/sys/.../buffer/scan_elements/in_voltageY_type
+What:		/sys/.../buffer/scan_elements/in_voltage-in_type
+What:		/sys/.../buffer/scan_elements/in_voltageY_supply_type
+What:		/sys/.../buffer/scan_elements/in_timestamp_type
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Description of the scan element data storage within the buffer
+		and hence the form in which it is read from user-space.
+		Form is [be|le]:[s|u]bits/storagebits[>>shift].
+		be or le specifies big or little endian. s or u specifies if
+		signed (2's complement) or unsigned. bits is the number of bits
+		of data and storagebits is the space (after padding) that it
+		occupies in the buffer. shift if specified, is the shift that
+		needs to be applied prior to masking out unused bits. Some
+		devices put their data in the middle of the transferred elements
+		with additional information on both sides.  Note that some
+		devices will have additional information in the unused bits
+		so to get a clean value, the bits value must be used to mask
+		the buffer output value appropriately.  The storagebits value
+		also specifies the data alignment.  So s48/64>>2 will be a
+		signed 48 bit integer stored in a 64 bit location aligned to
+		a a64 bit boundary. To obtain the clean value, shift right 2
+		and apply a mask to zero the top 16 bits of the result.
+		For other storage combinations this attribute will be extended
+		appropriately.
+
+What:		/sys/.../buffer/scan_elements/in_accel_type_available
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		If the type parameter can take one of a small set of values,
+		this attribute lists them.
+
+What:		/sys/.../buffer/scan_elements/in_voltageY_index
+What:		/sys/.../buffer/scan_elements/in_voltageY_supply_index
+What:		/sys/.../buffer/scan_elements/in_accel_x_index
+What:		/sys/.../buffer/scan_elements/in_accel_y_index
+What:		/sys/.../buffer/scan_elements/in_accel_z_index
+What:		/sys/.../buffer/scan_elements/in_anglvel_x_index
+What:		/sys/.../buffer/scan_elements/in_anglvel_y_index
+What:		/sys/.../buffer/scan_elements/in_anglvel_z_index
+What:		/sys/.../buffer/scan_elements/in_magn_x_index
+What:		/sys/.../buffer/scan_elements/in_magn_y_index
+What:		/sys/.../buffer/scan_elements/in_magn_z_index
+What:		/sys/.../buffer/scan_elements/in_incli_x_index
+What:		/sys/.../buffer/scan_elements/in_incli_y_index
+What:		/sys/.../buffer/scan_elements/in_timestamp_index
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		A single positive integer specifying the position of this
+		scan element in the buffer. Note these are not dependent on
+		what is enabled and may not be contiguous. Thus for user-space
+		to establish the full layout these must be used in conjunction
+		with all _en attributes to establish which channels are present,
+		and the relevant _type attributes to establish the data storage
+		format.
+
+What:		/sys/.../iio:deviceX/in_anglvel_z_quadrature_correction_raw
+KernelVersion:	2.6.38
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to read the amount of quadrature error
+		present in the device at a given time.
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 7c22a532..6df4e6f 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -135,6 +135,17 @@
 		for the device and attempt to bind to it.  For example:
 		# echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id
 
+		Reading from this file will list all dynamically added
+		device IDs in the same format, with one entry per
+		line. For example:
+		# cat /sys/bus/usb/drivers/foo/new_id
+		8086 10f5
+		dead beef 06
+		f00d cafe
+
+		The list will be truncated at PAGE_SIZE bytes due to
+		sysfs restrictions.
+
 What:		/sys/bus/usb-serial/drivers/.../new_id
 Date:		October 2011
 Contact:	linux-usb@vger.kernel.org
@@ -157,6 +168,10 @@
 		match the driver to the device.  For example:
 		# echo "046d c315" > /sys/bus/usb/drivers/foo/remove_id
 
+		Reading from this file will list the dynamically added
+		device IDs, exactly like reading from the entry
+		"/sys/bus/usb/drivers/.../new_id"
+
 What:		/sys/bus/usb/device/.../avoid_reset_quirk
 Date:		December 2009
 Contact:	Oliver Neukum <oliver@neukum.org>
@@ -189,7 +204,7 @@
 Description:
 		Some information about whether a given USB device is
 		physically fixed to the platform can be inferred from a
-		combination of hub decriptor bits and platform-specific data
+		combination of hub descriptor bits and platform-specific data
 		such as ACPI. This file will read either "removable" or
 		"fixed" if the information is available, and "unknown"
-		otherwise.
\ No newline at end of file
+		otherwise.
diff --git a/Documentation/ABI/testing/sysfs-class-extcon b/Documentation/ABI/testing/sysfs-class-extcon
new file mode 100644
index 0000000..20ab361
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-extcon
@@ -0,0 +1,97 @@
+What:		/sys/class/extcon/.../
+Date:		February 2012
+Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+		Provide a place in sysfs for the extcon objects.
+		This allows accessing extcon specific variables.
+		The name of extcon object denoted as ... is the name given
+		with extcon_dev_register.
+
+		One extcon device denotes a single external connector
+		port. An external connector may have multiple cables
+		attached simultaneously. Many of docks, cradles, and
+		accessory cables have such capability. For example,
+		the 30-pin port of Nuri board (/arch/arm/mach-exynos)
+		may have both HDMI and Charger attached, or analog audio,
+		video, and USB cables attached simulteneously.
+
+		If there are cables mutually exclusive with each other,
+		such binary relations may be expressed with extcon_dev's
+		mutually_exclusive array.
+
+What:		/sys/class/extcon/.../name
+Date:		February 2012
+Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+		The /sys/class/extcon/.../name shows the name of the extcon
+		object. If the extcon object has an optional callback
+		"show_name" defined, the callback will provide the name with
+		this sysfs node.
+
+What:		/sys/class/extcon/.../state
+Date:		February 2012
+Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+		The /sys/class/extcon/.../state shows and stores the cable
+		attach/detach information of the corresponding extcon object.
+		If the extcon object has an optional callback "show_state"
+		defined, the showing function is overriden with the optional
+		callback.
+
+		If the default callback for showing function is used, the
+		format is like this:
+		# cat state
+		USB_OTG=1
+		HDMI=0
+		TA=1
+		EAR_JACK=0
+		#
+		In this example, the extcon device have USB_OTG and TA
+		cables attached and HDMI and EAR_JACK cables detached.
+
+		In order to update the state of an extcon device, enter a hex
+		state number starting with 0x.
+		 echo 0xHEX > state
+
+		This updates the whole state of the extcon dev.
+		Inputs of all the methods are required to meet the
+		mutually_exclusive contidions if they exist.
+
+		It is recommended to use this "global" state interface if
+		you need to enter the value atomically. The later state
+		interface associated with each cable cannot update
+		multiple cable states of an extcon device simultaneously.
+
+What:		/sys/class/extcon/.../cable.x/name
+Date:		February 2012
+Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+		The /sys/class/extcon/.../cable.x/name shows the name of cable
+		"x" (integer between 0 and 31) of an extcon device.
+
+What:		/sys/class/extcon/.../cable.x/state
+Date:		February 2012
+Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+		The /sys/class/extcon/.../cable.x/name shows and stores the
+		state of cable "x" (integer between 0 and 31) of an extcon
+		device. The state value is either 0 (detached) or 1
+		(attached).
+
+What:		/sys/class/extcon/.../mutually_exclusive/...
+Date:		December 2011
+Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+		Shows the relations of mutually exclusiveness. For example,
+		if the mutually_exclusive array of extcon_dev is
+		{0x3, 0x5, 0xC, 0x0}, the, the output is:
+		# ls mutually_exclusive/
+		0x3
+		0x5
+		0xc
+		#
+
+		Note that mutually_exclusive is a sub-directory of the extcon
+		device and the file names under the mutually_exclusive
+		directory show the mutually-exclusive sets, not the contents
+		of the files.
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index 840f7d6..45000f0 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -96,16 +96,26 @@
 		is read-only.  If the device is not enabled to wake up the
 		system from sleep states, this attribute is not present.
 
-What:		/sys/devices/.../power/wakeup_hit_count
-Date:		September 2010
+What:		/sys/devices/.../power/wakeup_abort_count
+Date:		February 2012
 Contact:	Rafael J. Wysocki <rjw@sisk.pl>
 Description:
-		The /sys/devices/.../wakeup_hit_count attribute contains the
+		The /sys/devices/.../wakeup_abort_count attribute contains the
 		number of times the processing of a wakeup event associated with
-		the device might prevent the system from entering a sleep state.
-		This attribute is read-only.  If the device is not enabled to
-		wake up the system from sleep states, this attribute is not
-		present.
+		the device might have aborted system transition into a sleep
+		state in progress.  This attribute is read-only.  If the device
+		is not enabled to wake up the system from sleep states, this
+		attribute is not present.
+
+What:		/sys/devices/.../power/wakeup_expire_count
+Date:		February 2012
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_expire_count attribute contains the
+		number of times a wakeup event associated with the device has
+		been reported with a timeout that expired.  This attribute is
+		read-only.  If the device is not enabled to wake up the system
+		from sleep states, this attribute is not present.
 
 What:		/sys/devices/.../power/wakeup_active
 Date:		September 2010
@@ -148,6 +158,17 @@
 		not enabled to wake up the system from sleep states, this
 		attribute is not present.
 
+What:		/sys/devices/.../power/wakeup_prevent_sleep_time_ms
+Date:		February 2012
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute
+		contains the total time the device has been preventing
+		opportunistic transitions to sleep states from occuring.
+		This attribute is read-only.  If the device is not enabled to
+		wake up the system from sleep states, this attribute is not
+		present.
+
 What:		/sys/devices/.../power/autosuspend_delay_ms
 Date:		September 2010
 Contact:	Alan Stern <stern@rowland.harvard.edu>
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index e7be75b..5dab364 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -9,31 +9,6 @@
 
 		/sys/devices/system/cpu/cpu#/
 
-What:		/sys/devices/system/cpu/sched_mc_power_savings
-		/sys/devices/system/cpu/sched_smt_power_savings
-Date:		June 2006
-Contact:	Linux kernel mailing list <linux-kernel@vger.kernel.org>
-Description:	Discover and adjust the kernel's multi-core scheduler support.
-
-		Possible values are:
-
-		0 - No power saving load balance (default value)
-		1 - Fill one thread/core/package first for long running threads
-		2 - Also bias task wakeups to semi-idle cpu package for power
-		    savings
-
-		sched_mc_power_savings is dependent upon SCHED_MC, which is
-		itself architecture dependent.
-
-		sched_smt_power_savings is dependent upon SCHED_SMT, which
-		is itself architecture dependent.
-
-		The two files are independent of each other. It is possible
-		that one file may be present without the other.
-
-		Introduced by git commit 5c45bf27.
-
-
 What:		/sys/devices/system/cpu/kernel_max
 		/sys/devices/system/cpu/offline
 		/sys/devices/system/cpu/online
diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom
index 0130d66..8d55a83 100644
--- a/Documentation/ABI/testing/sysfs-driver-wacom
+++ b/Documentation/ABI/testing/sysfs-driver-wacom
@@ -9,15 +9,24 @@
 		or 0 otherwise. Writing to this file one of these values
 		switches reporting speed.
 
+What:		/sys/class/leds/0005\:056A\:00BD.0001\:selector\:*/
+Date:		May 2012
+Kernel Version:	3.5
+Contact:	linux-bluetooth@vger.kernel.org
+Description:
+		LED selector for Intuos4 WL. There are 4 leds, but only one LED
+		can be lit at a time. Max brightness is 127.
+
 What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led
 Date:		August 2011
 Contact:	linux-input@vger.kernel.org
 Description:
 		Attribute group for control of the status LEDs and the OLEDs.
 		This attribute group is only available for Intuos 4 M, L,
-		and XL (with LEDs and OLEDs) and Cintiq 21UX2 and Cintiq 24HD
-		(LEDs only). Therefore its presence implicitly signifies the
-		presence of said LEDs and OLEDs on the tablet device.
+		and XL (with LEDs and OLEDs), Intuos 5 (LEDs only), and Cintiq
+		21UX2 and Cintiq 24HD (LEDs only). Therefore its presence
+		implicitly signifies the presence of said LEDs and OLEDs on the
+		tablet device.
 
 What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status0_luminance
 Date:		August 2011
@@ -40,10 +49,10 @@
 Date:		August 2011
 Contact:	linux-input@vger.kernel.org
 Description:
-		Writing to this file sets which one of the four (for Intuos 4)
-		or of the right four (for Cintiq 21UX2 and Cintiq 24HD) status
-		LEDs is active (0..3). The other three LEDs on the same side are
-		always inactive.
+		Writing to this file sets which one of the four (for Intuos 4
+		and Intuos 5) or of the right four (for Cintiq 21UX2 and Cintiq
+		24HD) status LEDs is active (0..3). The other three LEDs on the
+		same side are always inactive.
 
 What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led1_select
 Date:		September 2011
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index b464d1276..31725ff 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -172,3 +172,62 @@
 
 		Reading from this file will display the current value, which is
 		set to 1 MB by default.
+
+What:		/sys/power/autosleep
+Date:		April 2012
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/power/autosleep file can be written one of the strings
+		returned by reads from /sys/power/state.  If that happens, a
+		work item attempting to trigger a transition of the system to
+		the sleep state represented by that string is queued up.  This
+		attempt will only succeed if there are no active wakeup sources
+		in the system at that time.  After every execution, regardless
+		of whether or not the attempt to put the system to sleep has
+		succeeded, the work item requeues itself until user space
+		writes "off" to /sys/power/autosleep.
+
+		Reading from this file causes the last string successfully
+		written to it to be returned.
+
+What:		/sys/power/wake_lock
+Date:		February 2012
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/power/wake_lock file allows user space to create
+		wakeup source objects and activate them on demand (if one of
+		those wakeup sources is active, reads from the
+		/sys/power/wakeup_count file block or return false).  When a
+		string without white space is written to /sys/power/wake_lock,
+		it will be assumed to represent a wakeup source name.  If there
+		is a wakeup source object with that name, it will be activated
+		(unless active already).  Otherwise, a new wakeup source object
+		will be registered, assigned the given name and activated.
+		If a string written to /sys/power/wake_lock contains white
+		space, the part of the string preceding the white space will be
+		regarded as a wakeup source name and handled as descrived above.
+		The other part of the string will be regarded as a timeout (in
+		nanoseconds) such that the wakeup source will be automatically
+		deactivated after it has expired.  The timeout, if present, is
+		set regardless of the current state of the wakeup source object
+		in question.
+
+		Reads from this file return a string consisting of the names of
+		wakeup sources created with the help of it that are active at
+		the moment, separated with spaces.
+
+
+What:		/sys/power/wake_unlock
+Date:		February 2012
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/power/wake_unlock file allows user space to deactivate
+		wakeup sources created with the help of /sys/power/wake_lock.
+		When a string is written to /sys/power/wake_unlock, it will be
+		assumed to represent the name of a wakeup source to deactivate.
+		If a wakeup source object of that name exists and is active at
+		the moment, it will be deactivated.
+
+		Reads from this file return a string consisting of the names of
+		wakeup sources created with the help of /sys/power/wake_lock
+		that are inactive at the moment, separated with spaces.
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 66725a3..bc3d9f8c 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -6,7 +6,7 @@
 # To add a new book the only step required is to add the book to the
 # list of DOCBOOKS.
 
-DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
+DOCBOOKS := z8530book.xml device-drivers.xml \
 	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
 	    writing_usb_driver.xml networking.xml \
 	    kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 7160652..00687ee 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -212,19 +212,6 @@
      <sect1><title>PCI Hotplug Support Library</title>
 !Edrivers/pci/hotplug/pci_hotplug_core.c
      </sect1>
-     <sect1><title>MCA Architecture</title>
-	<sect2><title>MCA Device Functions</title>
-           <para>
-              Refer to the file arch/x86/kernel/mca_32.c for more information.
-           </para>
-<!-- FIXME: Removed for now since no structured comments in source
-X!Earch/x86/kernel/mca_32.c
--->
-	</sect2>
-	<sect2><title>MCA Bus DMA</title>
-!Iarch/x86/include/asm/mca_dma.h
-	</sect2>
-     </sect1>
   </chapter>
 
   <chapter id="firmware">
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
index 07a9c48..eee7142 100644
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -1289,7 +1289,7 @@
  * Sparc assembly will do this to ya.
  */
 C_LABEL(cputypvar):
-        .asciz "compatability"
+        .asciz "compatibility"
 
 /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */
         .align 4
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index 31df1aa..deb71ba 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -918,7 +918,7 @@
         <title>HSM violation</title>
         <para>
         This error is indicated when STATUS value doesn't match HSM
-        requirement during issuing or excution any ATA/ATAPI command.
+        requirement during issuing or execution any ATA/ATAPI command.
         </para>
 
 	<itemizedlist>
diff --git a/Documentation/DocBook/mcabook.tmpl b/Documentation/DocBook/mcabook.tmpl
deleted file mode 100644
index 467ccac..0000000
--- a/Documentation/DocBook/mcabook.tmpl
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
-
-<book id="MCAGuide">
- <bookinfo>
-  <title>MCA Driver Programming Interface</title>
-  
-  <authorgroup>
-   <author>
-    <firstname>Alan</firstname>
-    <surname>Cox</surname>
-    <affiliation>
-     <address>
-      <email>alan@lxorguk.ukuu.org.uk</email>
-     </address>
-    </affiliation>
-   </author>
-   <author>
-    <firstname>David</firstname>
-    <surname>Weinehall</surname>
-   </author>
-   <author>
-    <firstname>Chris</firstname>
-    <surname>Beauregard</surname>
-   </author>
-  </authorgroup>
-
-  <copyright>
-   <year>2000</year>
-   <holder>Alan Cox</holder>
-   <holder>David Weinehall</holder>
-   <holder>Chris Beauregard</holder>
-  </copyright>
-
-  <legalnotice>
-   <para>
-     This documentation 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.
-   </para>
-      
-   <para>
-     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.
-   </para>
-      
-   <para>
-     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
-   </para>
-      
-   <para>
-     For more details see the file COPYING in the source
-     distribution of Linux.
-   </para>
-  </legalnotice>
- </bookinfo>
-
-<toc></toc>
-
-  <chapter id="intro">
-      <title>Introduction</title>
-  <para>
-	The MCA bus functions provide a generalised interface to find MCA
-	bus cards, to claim them for a driver, and to read and manipulate POS 
-	registers without being aware of the motherboard internals or 
-	certain deep magic specific to onboard devices.
-  </para>
-  <para>
-	The basic interface to the MCA bus devices is the slot. Each slot
-	is numbered and virtual slot numbers are assigned to the internal
-	devices. Using a pci_dev as other busses do does not really make
-	sense in the MCA context as the MCA bus resources require card
-	specific interpretation.
-  </para>
-  <para>
-	Finally the MCA bus functions provide a parallel set of DMA
-	functions mimicing the ISA bus DMA functions as closely as possible,
-	although also supporting the additional DMA functionality on the
-	MCA bus controllers.
-  </para>
-  </chapter>
-  <chapter id="bugs">
-     <title>Known Bugs And Assumptions</title>
-  <para>
-	None.	
-  </para>
-  </chapter>
-
-  <chapter id="pubfunctions">
-     <title>Public Functions Provided</title>
-!Edrivers/mca/mca-legacy.c
-  </chapter>
-
-  <chapter id="dmafunctions">
-     <title>DMA Functions Provided</title>
-!Iarch/x86/include/asm/mca_dma.h
-  </chapter>
-
-</book>
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
index 6628b4b..3625209 100644
--- a/Documentation/DocBook/media/Makefile
+++ b/Documentation/DocBook/media/Makefile
@@ -70,6 +70,8 @@
 	VIDIOC_SUBDEV_ENUM_MBUS_CODE \
 	VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
 	VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
+	VIDIOC_SUBDEV_G_SELECTION \
+	VIDIOC_SUBDEV_S_SELECTION \
 
 TYPES = \
 	$(shell perl -ne 'print "$$1 " if /^typedef\s+[^\s]+\s+([^\s]+)\;/' $(srctree)/include/linux/videodev2.h) \
@@ -193,7 +195,7 @@
 #
 
 install_media_images = \
-	$(Q)cp $(OBJIMGFILES) $(MEDIA_OBJ_DIR)/media_api
+	$(Q)cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api
 
 $(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64
 	$(Q)base64 -d $< >$@
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index c7a4ca5..e633c09 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -531,6 +531,139 @@
 				here are referring to what can be found in the TMCC-structure -
 				independent of the mode.</para>
 		</section>
+		<section id="DTV-ATSCMH-FIC-VER">
+			<title><constant>DTV_ATSCMH_FIC_VER</constant></title>
+			<para>Version number of the FIC (Fast Information Channel) signaling data.</para>
+			<para>FIC is used for relaying information to allow rapid service acquisition by the receiver.</para>
+			<para>Possible values: 0, 1, 2, 3, ..., 30, 31</para>
+		</section>
+		<section id="DTV-ATSCMH-PARADE-ID">
+			<title><constant>DTV_ATSCMH_PARADE_ID</constant></title>
+			<para>Parade identification number</para>
+			<para>A parade is a collection of up to eight MH groups, conveying one or two ensembles.</para>
+			<para>Possible values: 0, 1, 2, 3, ..., 126, 127</para>
+		</section>
+		<section id="DTV-ATSCMH-NOG">
+			<title><constant>DTV_ATSCMH_NOG</constant></title>
+			<para>Number of MH groups per MH subframe for a designated parade.</para>
+			<para>Possible values: 1, 2, 3, 4, 5, 6, 7, 8</para>
+		</section>
+		<section id="DTV-ATSCMH-TNOG">
+			<title><constant>DTV_ATSCMH_TNOG</constant></title>
+			<para>Total number of MH groups including all MH groups belonging to all MH parades in one MH subframe.</para>
+			<para>Possible values: 0, 1, 2, 3, ..., 30, 31</para>
+		</section>
+		<section id="DTV-ATSCMH-SGN">
+			<title><constant>DTV_ATSCMH_SGN</constant></title>
+			<para>Start group number.</para>
+			<para>Possible values: 0, 1, 2, 3, ..., 14, 15</para>
+		</section>
+		<section id="DTV-ATSCMH-PRC">
+			<title><constant>DTV_ATSCMH_PRC</constant></title>
+			<para>Parade repetition cycle.</para>
+			<para>Possible values: 1, 2, 3, 4, 5, 6, 7, 8</para>
+		</section>
+		<section id="DTV-ATSCMH-RS-FRAME-MODE">
+			<title><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></title>
+			<para>RS frame mode.</para>
+			<para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_rs_frame_mode {
+	ATSCMH_RSFRAME_PRI_ONLY  = 0,
+	ATSCMH_RSFRAME_PRI_SEC   = 1,
+} atscmh_rs_frame_mode_t;
+</programlisting>
+		</section>
+		<section id="DTV-ATSCMH-RS-FRAME-ENSEMBLE">
+			<title><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></title>
+			<para>RS frame ensemble.</para>
+			<para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_rs_frame_ensemble {
+	ATSCMH_RSFRAME_ENS_PRI   = 0,
+	ATSCMH_RSFRAME_ENS_SEC   = 1,
+} atscmh_rs_frame_ensemble_t;
+</programlisting>
+		</section>
+		<section id="DTV-ATSCMH-RS-CODE-MODE-PRI">
+			<title><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></title>
+			<para>RS code mode (primary).</para>
+			<para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_rs_code_mode {
+	ATSCMH_RSCODE_211_187    = 0,
+	ATSCMH_RSCODE_223_187    = 1,
+	ATSCMH_RSCODE_235_187    = 2,
+} atscmh_rs_code_mode_t;
+</programlisting>
+		</section>
+		<section id="DTV-ATSCMH-RS-CODE-MODE-SEC">
+			<title><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></title>
+			<para>RS code mode (secondary).</para>
+			<para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_rs_code_mode {
+	ATSCMH_RSCODE_211_187    = 0,
+	ATSCMH_RSCODE_223_187    = 1,
+	ATSCMH_RSCODE_235_187    = 2,
+} atscmh_rs_code_mode_t;
+</programlisting>
+		</section>
+		<section id="DTV-ATSCMH-SCCC-BLOCK-MODE">
+			<title><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></title>
+			<para>Series Concatenated Convolutional Code Block Mode.</para>
+			<para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_block_mode {
+	ATSCMH_SCCC_BLK_SEP      = 0,
+	ATSCMH_SCCC_BLK_COMB     = 1,
+} atscmh_sccc_block_mode_t;
+</programlisting>
+		</section>
+		<section id="DTV-ATSCMH-SCCC-CODE-MODE-A">
+			<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></title>
+			<para>Series Concatenated Convolutional Code Rate.</para>
+			<para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_code_mode {
+	ATSCMH_SCCC_CODE_HLF     = 0,
+	ATSCMH_SCCC_CODE_QTR     = 1,
+} atscmh_sccc_code_mode_t;
+</programlisting>
+		</section>
+		<section id="DTV-ATSCMH-SCCC-CODE-MODE-B">
+			<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></title>
+			<para>Series Concatenated Convolutional Code Rate.</para>
+			<para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_code_mode {
+	ATSCMH_SCCC_CODE_HLF     = 0,
+	ATSCMH_SCCC_CODE_QTR     = 1,
+} atscmh_sccc_code_mode_t;
+</programlisting>
+		</section>
+		<section id="DTV-ATSCMH-SCCC-CODE-MODE-C">
+			<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></title>
+			<para>Series Concatenated Convolutional Code Rate.</para>
+			<para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_code_mode {
+	ATSCMH_SCCC_CODE_HLF     = 0,
+	ATSCMH_SCCC_CODE_QTR     = 1,
+} atscmh_sccc_code_mode_t;
+</programlisting>
+		</section>
+		<section id="DTV-ATSCMH-SCCC-CODE-MODE-D">
+			<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></title>
+			<para>Series Concatenated Convolutional Code Rate.</para>
+			<para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_code_mode {
+	ATSCMH_SCCC_CODE_HLF     = 0,
+	ATSCMH_SCCC_CODE_QTR     = 1,
+} atscmh_sccc_code_mode_t;
+</programlisting>
+		</section>
 	</section>
 	<section id="DTV-API-VERSION">
 	<title><constant>DTV_API_VERSION</constant></title>
@@ -774,6 +907,33 @@
 				<listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
 			</itemizedlist>
 		</section>
+		<section id="atscmh-params">
+			<title>ATSC-MH delivery system</title>
+			<para>The following parameters are valid for ATSC-MH:</para>
+			<itemizedlist mark='opencircle'>
+				<listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-FIC-VER"><constant>DTV_ATSCMH_FIC_VER</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-PARADE-ID"><constant>DTV_ATSCMH_PARADE_ID</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-NOG"><constant>DTV_ATSCMH_NOG</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-TNOG"><constant>DTV_ATSCMH_TNOG</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SGN"><constant>DTV_ATSCMH_SGN</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-PRC"><constant>DTV_ATSCMH_PRC</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-MODE"><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-ENSEMBLE"><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-PRI"><constant>DTV_ATSCMH_CODE_MODE_PRI</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-SEC"><constant>DTV_ATSCMH_CODE_MODE_SEC</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SCCC-BLOCK-MODE"><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-A"><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-B"><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
+			</itemizedlist>
+		</section>
 	</section>
 	<section id="frontend-property-cable-systems">
 	<title>Properties used on cable delivery systems</title>
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
index 7dc65c5..7c49fac 100644
--- a/Documentation/DocBook/media/v4l/biblio.xml
+++ b/Documentation/DocBook/media/v4l/biblio.xml
@@ -197,4 +197,33 @@
       <title>NTSC-4: United States RBDS Standard</title>
     </biblioentry>
 
+    <biblioentry id="iso12232">
+      <abbrev>ISO&nbsp;12232:2006</abbrev>
+      <authorgroup>
+	<corpauthor>International Organization for Standardization
+(<ulink url="http://www.iso.org">http://www.iso.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>Photography &mdash; Digital still cameras &mdash; Determination
+      of exposure index, ISO speed ratings, standard output sensitivity, and
+      recommended exposure index</title>
+    </biblioentry>
+
+    <biblioentry id="cea861">
+      <abbrev>CEA-861-E</abbrev>
+      <authorgroup>
+	<corpauthor>Consumer Electronics Association
+(<ulink url="http://www.ce.org">http://www.ce.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>A DTV Profile for Uncompressed High Speed Digital Interfaces</title>
+    </biblioentry>
+
+    <biblioentry id="vesadmt">
+      <abbrev>VESA&nbsp;DMT</abbrev>
+      <authorgroup>
+	<corpauthor>Video Electronics Standards Association
+(<ulink url="http://www.vesa.org">http://www.vesa.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>VESA and Industry Standards and Guidelines for Computer Display Monitor Timing (DMT)</title>
+    </biblioentry>
+
   </bibliography>
diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
index c79278a..4101aeb 100644
--- a/Documentation/DocBook/media/v4l/common.xml
+++ b/Documentation/DocBook/media/v4l/common.xml
@@ -724,41 +724,49 @@
 }
       </programlisting>
     </example>
+  </section>
   <section id="dv-timings">
 	<title>Digital Video (DV) Timings</title>
 	<para>
-	The video standards discussed so far has been dealing with Analog TV and the
+	The video standards discussed so far have been dealing with Analog TV and the
 corresponding video timings. Today there are many more different hardware interfaces
 such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry
 video signals and there is a need to extend the API to select the video timings
 for these interfaces. Since it is not possible to extend the &v4l2-std-id; due to
-the limited bits available, a new set of IOCTLs is added to set/get video timings at
+the limited bits available, a new set of IOCTLs was added to set/get video timings at
 the input and output: </para><itemizedlist>
 	<listitem>
-	<para>DV Presets: Digital Video (DV) presets. These are IDs representing a
+	<para>DV Timings: This will allow applications to define detailed
+video timings for the interface. This includes parameters such as width, height,
+polarities, frontporch, backporch etc. The <filename>linux/v4l2-dv-timings.h</filename>
+header can be used to get the timings of the formats in the <xref linkend="cea861" /> and
+<xref linkend="vesadmt" /> standards.
+	</para>
+	</listitem>
+	<listitem>
+	<para>DV Presets: Digital Video (DV) presets (<emphasis role="bold">deprecated</emphasis>).
+	These are IDs representing a
 video timing at the input/output. Presets are pre-defined timings implemented
 by the hardware according to video standards. A __u32 data type is used to represent
 a preset unlike the bit mask that is used in &v4l2-std-id; allowing future extensions
-to support as many different presets as needed.</para>
-	</listitem>
-	<listitem>
-	<para>Custom DV Timings: This will allow applications to define more detailed
-custom video timings for the interface. This includes parameters such as width, height,
-polarities, frontporch, backporch etc.
-	</para>
+to support as many different presets as needed. This API is deprecated in favor of the DV Timings
+API.</para>
 	</listitem>
 	</itemizedlist>
+	<para>To enumerate and query the attributes of the DV timings supported by a device,
+	applications use the &VIDIOC-ENUM-DV-TIMINGS; and &VIDIOC-DV-TIMINGS-CAP; ioctls.
+	To set DV timings for the device, applications use the
+&VIDIOC-S-DV-TIMINGS; ioctl and to get current DV timings they use the
+&VIDIOC-G-DV-TIMINGS; ioctl. To detect the DV timings as seen by the video receiver applications
+use the &VIDIOC-QUERY-DV-TIMINGS; ioctl.</para>
 	<para>To enumerate and query the attributes of DV presets supported by a device,
 applications use the &VIDIOC-ENUM-DV-PRESETS; ioctl. To get the current DV preset,
 applications use the &VIDIOC-G-DV-PRESET; ioctl and to set a preset they use the
-&VIDIOC-S-DV-PRESET; ioctl.</para>
-	<para>To set custom DV timings for the device, applications use the
-&VIDIOC-S-DV-TIMINGS; ioctl and to get current custom DV timings they use the
-&VIDIOC-G-DV-TIMINGS; ioctl.</para>
+&VIDIOC-S-DV-PRESET; ioctl. To detect the preset as seen by the video receiver applications
+use the &VIDIOC-QUERY-DV-PRESET; ioctl.</para>
 	<para>Applications can make use of the <xref linkend="input-capabilities" /> and
 <xref linkend="output-capabilities"/> flags to decide what ioctls are available to set the
 video timings for the device.</para>
-	</section>
   </section>
 
   &sub-controls;
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index bce97c5..ea42ef8 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2407,6 +2407,54 @@
 	  <para>Added <link linkend="jpeg-controls">JPEG compression control
 	  class</link>.</para>
         </listitem>
+        <listitem>
+	  <para>Extended the DV Timings API:
+	  &VIDIOC-ENUM-DV-TIMINGS;, &VIDIOC-QUERY-DV-TIMINGS; and
+	  &VIDIOC-DV-TIMINGS-CAP;.</para>
+        </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 3.5</title>
+      <orderedlist>
+        <listitem>
+	  <para>Added integer menus, the new type will be
+	  V4L2_CTRL_TYPE_INTEGER_MENU.</para>
+        </listitem>
+        <listitem>
+	  <para>Added selection API for V4L2 subdev interface:
+	  &VIDIOC-SUBDEV-G-SELECTION; and
+	  &VIDIOC-SUBDEV-S-SELECTION;.</para>
+        </listitem>
+        <listitem>
+	  <para> Added <constant>V4L2_COLORFX_ANTIQUE</constant>,
+	  <constant>V4L2_COLORFX_ART_FREEZE</constant>,
+	  <constant>V4L2_COLORFX_AQUA</constant>,
+	  <constant>V4L2_COLORFX_SILHOUETTE</constant>,
+	  <constant>V4L2_COLORFX_SOLARIZATION</constant>,
+	  <constant>V4L2_COLORFX_VIVID</constant> and
+	  <constant>V4L2_COLORFX_ARBITRARY_CBCR</constant> menu items
+	  to the <constant>V4L2_CID_COLORFX</constant> control.</para>
+        </listitem>
+        <listitem>
+	  <para> Added <constant>V4L2_CID_COLORFX_CBCR</constant> control.</para>
+        </listitem>
+        <listitem>
+	  <para> Added camera controls <constant>V4L2_CID_AUTO_EXPOSURE_BIAS</constant>,
+	  <constant>V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE</constant>,
+	  <constant>V4L2_CID_IMAGE_STABILIZATION</constant>,
+	  <constant>V4L2_CID_ISO_SENSITIVITY</constant>,
+	  <constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>,
+	  <constant>V4L2_CID_EXPOSURE_METERING</constant>,
+	  <constant>V4L2_CID_SCENE_MODE</constant>,
+	  <constant>V4L2_CID_3A_LOCK</constant>,
+	  <constant>V4L2_CID_AUTO_FOCUS_START</constant>,
+	  <constant>V4L2_CID_AUTO_FOCUS_STOP</constant>,
+	  <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant> and
+	  <constant>V4L2_CID_AUTO_FOCUS_RANGE</constant>.
+	  </para>
+        </listitem>
       </orderedlist>
     </section>
 
@@ -2508,6 +2556,10 @@
 ioctls.</para>
         </listitem>
         <listitem>
+	  <para>&VIDIOC-DECODER-CMD; and &VIDIOC-TRY-DECODER-CMD;
+ioctls.</para>
+        </listitem>
+        <listitem>
 	  <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
 ioctls.</para>
         </listitem>
@@ -2515,6 +2567,10 @@
 	  <para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
         </listitem>
         <listitem>
+	  <para>&VIDIOC-ENUM-DV-TIMINGS;, &VIDIOC-QUERY-DV-TIMINGS; and
+	  &VIDIOC-DV-TIMINGS-CAP; ioctls.</para>
+        </listitem>
+        <listitem>
 	  <para>Flash API. <xref linkend="flash-controls" /></para>
         </listitem>
         <listitem>
@@ -2523,6 +2579,14 @@
         <listitem>
 	  <para>Selection API. <xref linkend="selection-api" /></para>
         </listitem>
+        <listitem>
+	  <para>Sub-device selection API: &VIDIOC-SUBDEV-G-SELECTION;
+	  and &VIDIOC-SUBDEV-S-SELECTION; ioctls.</para>
+        </listitem>
+        <listitem>
+	  <para><link linkend="v4l2-auto-focus-area"><constant>
+	  V4L2_CID_AUTO_FOCUS_AREA</constant></link> control.</para>
+        </listitem>
       </itemizedlist>
     </section>
 
@@ -2538,6 +2602,17 @@
 <constant>VIDIOC_S_MPEGCOMP</constant> ioctls. Use Extended Controls,
 <xref linkend="extended-controls" />.</para>
         </listitem>
+        <listitem>
+	  <para>&VIDIOC-G-DV-PRESET;, &VIDIOC-S-DV-PRESET;, &VIDIOC-ENUM-DV-PRESETS; and
+	  &VIDIOC-QUERY-DV-PRESET; ioctls. Use the DV Timings API (<xref linkend="dv-timings" />).</para>
+        </listitem>
+        <listitem>
+	  <para><constant>VIDIOC_SUBDEV_G_CROP</constant> and
+	  <constant>VIDIOC_SUBDEV_S_CROP</constant> ioctls. Use
+	  <constant>VIDIOC_SUBDEV_G_SELECTION</constant> and
+	  <constant>VIDIOC_SUBDEV_S_SELECTION</constant>, <xref
+	  linkend="vidioc-subdev-g-selection" />.</para>
+        </listitem>
       </itemizedlist>
     </section>
   </section>
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index b84f25e..676bc46 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -285,18 +285,92 @@
 	  <row id="v4l2-colorfx">
 	    <entry><constant>V4L2_CID_COLORFX</constant></entry>
 	    <entry>enum</entry>
-	    <entry>Selects a color effect. Possible values for
-<constant>enum v4l2_colorfx</constant> are:
-<constant>V4L2_COLORFX_NONE</constant> (0),
-<constant>V4L2_COLORFX_BW</constant> (1),
-<constant>V4L2_COLORFX_SEPIA</constant> (2),
-<constant>V4L2_COLORFX_NEGATIVE</constant> (3),
-<constant>V4L2_COLORFX_EMBOSS</constant> (4),
-<constant>V4L2_COLORFX_SKETCH</constant> (5),
-<constant>V4L2_COLORFX_SKY_BLUE</constant> (6),
-<constant>V4L2_COLORFX_GRASS_GREEN</constant> (7),
-<constant>V4L2_COLORFX_SKIN_WHITEN</constant> (8) and
-<constant>V4L2_COLORFX_VIVID</constant> (9).</entry>
+	    <entry>Selects a color effect. The following values are defined:
+	    </entry>
+	  </row><row>
+	  <entry></entry>
+	  <entry></entry>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_COLORFX_NONE</constant>&nbsp;</entry>
+		  <entry>Color effect is disabled.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_ANTIQUE</constant>&nbsp;</entry>
+		  <entry>An aging (old photo) effect.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_ART_FREEZE</constant>&nbsp;</entry>
+		  <entry>Frost color effect.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_AQUA</constant>&nbsp;</entry>
+		  <entry>Water color, cool tone.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_BW</constant>&nbsp;</entry>
+		  <entry>Black and white.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_EMBOSS</constant>&nbsp;</entry>
+		  <entry>Emboss, the highlights and shadows replace light/dark boundaries
+		  and low contrast areas are set to a gray background.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_GRASS_GREEN</constant>&nbsp;</entry>
+		  <entry>Grass green.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_NEGATIVE</constant>&nbsp;</entry>
+		  <entry>Negative.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_SEPIA</constant>&nbsp;</entry>
+		  <entry>Sepia tone.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_SKETCH</constant>&nbsp;</entry>
+		  <entry>Sketch.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_SKIN_WHITEN</constant>&nbsp;</entry>
+		  <entry>Skin whiten.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_SKY_BLUE</constant>&nbsp;</entry>
+		  <entry>Sky blue.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_SOLARIZATION</constant>&nbsp;</entry>
+		  <entry>Solarization, the image is partially reversed in tone,
+		  only color values above or below a certain threshold are inverted.
+		  </entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_SILHOUETTE</constant>&nbsp;</entry>
+		  <entry>Silhouette (outline).</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_VIVID</constant>&nbsp;</entry>
+		  <entry>Vivid colors.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_COLORFX_SET_CBCR</constant>&nbsp;</entry>
+		  <entry>The Cb and Cr chroma components are replaced by fixed
+		  coefficients determined by <constant>V4L2_CID_COLORFX_CBCR</constant>
+		  control.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_COLORFX_CBCR</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Determines the Cb and Cr coefficients for <constant>V4L2_COLORFX_SET_CBCR</constant>
+	    color effect. Bits [7:0] of the supplied 32 bit value are interpreted as
+	    Cr component, bits [15:8] as Cb component and bits [31:16] must be zero.
+	  </entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CID_ROTATE</constant></entry>
@@ -2023,7 +2097,7 @@
 		<entry>integer</entry>
 	      </row>
 	      <row><entry spanname="descr">Cyclic intra macroblock refresh. This is the number of continuous macroblocks
-refreshed every frame. Each frame a succesive set of macroblocks is refreshed until the cycle completes and starts from the
+refreshed every frame. Each frame a successive set of macroblocks is refreshed until the cycle completes and starts from the
 top of the frame. Applicable to H264, H263 and MPEG4 encoder.</entry>
 	      </row>
 
@@ -2183,7 +2257,7 @@
 		<entry>integer</entry>
 	      </row>
 	      <row><entry spanname="descr">The Video Buffer Verifier size in kilobytes, it is used as a limitation of frame skip.
-The VBV is defined in the standard as a mean to verify that the produced stream will be succesfully decoded.
+The VBV is defined in the standard as a mean to verify that the produced stream will be successfully decoded.
 The standard describes it as "Part of a hypothetical decoder that is conceptually connected to the
 output of the encoder. Its purpose is to provide a constraint on the variability of the data rate that an
 encoder or editing process may produce.".
@@ -2196,7 +2270,7 @@
 		<entry>integer</entry>
 	      </row>
 	      <row><entry spanname="descr">The Coded Picture Buffer size in kilobytes, it is used as a limitation of frame skip.
-The CPB is defined in the H264 standard as a mean to verify that the produced stream will be succesfully decoded.
+The CPB is defined in the H264 standard as a mean to verify that the produced stream will be successfully decoded.
 Applicable to the H264 encoder.</entry>
 	      </row>
 
@@ -2775,6 +2849,51 @@
 	  <row><entry></entry></row>
 
 	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_EXPOSURE_BIAS</constant>&nbsp;</entry>
+	    <entry>integer menu</entry>
+	  </row><row><entry spanname="descr"> Determines the automatic
+exposure compensation, it is effective only when <constant>V4L2_CID_EXPOSURE_AUTO</constant>
+control is set to <constant>AUTO</constant>, <constant>SHUTTER_PRIORITY </constant>
+or <constant>APERTURE_PRIORITY</constant>.
+It is expressed in terms of EV, drivers should interpret the values as 0.001 EV
+units, where the value 1000 stands for +1 EV.
+<para>Increasing the exposure compensation value is equivalent to decreasing
+the exposure value (EV) and will increase the amount of light at the image
+sensor. The camera performs the exposure compensation by adjusting absolute
+exposure time and/or aperture.</para></entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row id="v4l2-exposure-metering">
+	    <entry spanname="id"><constant>V4L2_CID_EXPOSURE_METERING</constant>&nbsp;</entry>
+	    <entry>enum&nbsp;v4l2_exposure_metering</entry>
+	  </row><row><entry spanname="descr">Determines how the camera measures
+the amount of light available for the frame exposure. Possible values are:</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_EXPOSURE_METERING_AVERAGE</constant>&nbsp;</entry>
+		  <entry>Use the light information coming from the entire frame
+and average giving no weighting to any particular portion of the metered area.
+		  </entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_EXPOSURE_METERING_CENTER_WEIGHTED</constant>&nbsp;</entry>
+		  <entry>Average the light information coming from the entire frame
+giving priority to the center of the metered area.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_EXPOSURE_METERING_SPOT</constant>&nbsp;</entry>
+		  <entry>Measure only very small area at the center of the frame.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
 	    <entry spanname="id"><constant>V4L2_CID_PAN_RELATIVE</constant>&nbsp;</entry>
 	    <entry>integer</entry>
 	  </row><row><entry spanname="descr">This control turns the
@@ -2857,13 +2976,107 @@
 	  <row>
 	    <entry spanname="id"><constant>V4L2_CID_FOCUS_AUTO</constant>&nbsp;</entry>
 	    <entry>boolean</entry>
-	  </row><row><entry spanname="descr">Enables automatic focus
-adjustments. The effect of manual focus adjustments while this feature
+	  </row><row><entry spanname="descr">Enables continuous automatic
+focus adjustments. The effect of manual focus adjustments while this feature
 is enabled is undefined, drivers should ignore such requests.</entry>
 	  </row>
 	  <row><entry></entry></row>
 
 	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUTO_FOCUS_START</constant>&nbsp;</entry>
+	    <entry>button</entry>
+	  </row><row><entry spanname="descr">Starts single auto focus process.
+The effect of setting this control when <constant>V4L2_CID_FOCUS_AUTO</constant>
+is set to <constant>TRUE</constant> (1) is undefined, drivers should ignore
+such requests.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUTO_FOCUS_STOP</constant>&nbsp;</entry>
+	    <entry>button</entry>
+	  </row><row><entry spanname="descr">Aborts automatic focusing
+started with <constant>V4L2_CID_AUTO_FOCUS_START</constant> control. It is
+effective only when the continuous autofocus is disabled, that is when
+<constant>V4L2_CID_FOCUS_AUTO</constant> control is set to <constant>FALSE
+</constant> (0).</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row id="v4l2-auto-focus-status">
+	    <entry spanname="id">
+	      <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant>&nbsp;</entry>
+	    <entry>bitmask</entry>
+	  </row>
+	  <row><entry spanname="descr">The automatic focus status. This is a read-only
+	  control.</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_AUTO_FOCUS_STATUS_IDLE</constant>&nbsp;</entry>
+		  <entry>Automatic focus is not active.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_AUTO_FOCUS_STATUS_BUSY</constant>&nbsp;</entry>
+		  <entry>Automatic focusing is in progress.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_AUTO_FOCUS_STATUS_REACHED</constant>&nbsp;</entry>
+		  <entry>Focus has been reached.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_AUTO_FOCUS_STATUS_FAILED</constant>&nbsp;</entry>
+		  <entry>Automatic focus has failed, the driver will not
+		  transition from this state until another action is
+		  performed by an application.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row><entry spanname="descr">
+Setting <constant>V4L2_LOCK_FOCUS</constant> lock bit of the <constant>V4L2_CID_3A_LOCK
+</constant> control may stop updates of the <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant>
+control value.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row id="v4l2-auto-focus-range">
+	    <entry spanname="id">
+	      <constant>V4L2_CID_AUTO_FOCUS_RANGE</constant>&nbsp;</entry>
+	    <entry>enum&nbsp;v4l2_auto_focus_range</entry>
+	  </row>
+	  <row><entry spanname="descr">Determines auto focus distance range
+for which lens may be adjusted. </entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_AUTO_FOCUS_RANGE_AUTO</constant>&nbsp;</entry>
+		  <entry>The camera automatically selects the focus range.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_AUTO_FOCUS_RANGE_NORMAL</constant>&nbsp;</entry>
+		  <entry>Normal distance range, limited for best automatic focus
+performance.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_AUTO_FOCUS_RANGE_MACRO</constant>&nbsp;</entry>
+		  <entry>Macro (close-up) auto focus. The camera will
+use its minimum possible distance for auto focus.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_AUTO_FOCUS_RANGE_INFINITY</constant>&nbsp;</entry>
+		  <entry>The lens is set to focus on an object at infinite distance.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
 	    <entry spanname="id"><constant>V4L2_CID_ZOOM_ABSOLUTE</constant>&nbsp;</entry>
 	    <entry>integer</entry>
 	  </row><row><entry spanname="descr">Specify the objective lens
@@ -2932,6 +3145,295 @@
 be used, for example, to filter out the fluorescent light component.</entry>
 	  </row>
 	  <row><entry></entry></row>
+
+	  <row id="v4l2-auto-n-preset-white-balance">
+	    <entry spanname="id"><constant>V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE</constant>&nbsp;</entry>
+	    <entry>enum&nbsp;v4l2_auto_n_preset_white_balance</entry>
+	  </row><row><entry spanname="descr">Sets white balance to automatic,
+manual or a preset. The presets determine color temperature of the light as
+a hint to the camera for white balance adjustments resulting in most accurate
+color representation. The following white balance presets are listed in order
+of increasing color temperature.</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_MANUAL</constant>&nbsp;</entry>
+		  <entry>Manual white balance.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_AUTO</constant>&nbsp;</entry>
+		  <entry>Automatic white balance adjustments.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_INCANDESCENT</constant>&nbsp;</entry>
+		  <entry>White balance setting for incandescent (tungsten) lighting.
+It generally cools down the colors and corresponds approximately to 2500...3500 K
+color temperature range.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_FLUORESCENT</constant>&nbsp;</entry>
+		  <entry>White balance preset for fluorescent lighting.
+It corresponds approximately to 4000...5000 K color temperature.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_FLUORESCENT_H</constant>&nbsp;</entry>
+		  <entry>With this setting the camera will compensate for
+fluorescent H lighting.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_HORIZON</constant>&nbsp;</entry>
+		  <entry>White balance setting for horizon daylight.
+It corresponds approximately to 5000 K color temperature.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_DAYLIGHT</constant>&nbsp;</entry>
+		  <entry>White balance preset for daylight (with clear sky).
+It corresponds approximately to 5000...6500 K color temperature.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_FLASH</constant>&nbsp;</entry>
+		  <entry>With this setting the camera will compensate for the flash
+light. It slightly warms up the colors and corresponds roughly to 5000...5500 K
+color temperature.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_CLOUDY</constant>&nbsp;</entry>
+		  <entry>White balance preset for moderately overcast sky.
+This option corresponds approximately to 6500...8000 K color temperature
+range.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_WHITE_BALANCE_SHADE</constant>&nbsp;</entry>
+		  <entry>White balance preset for shade or heavily overcast
+sky. It corresponds approximately to 9000...10000 K color temperature.
+</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row id="v4l2-wide-dynamic-range">
+	    <entry spanname="id"><constant>V4L2_CID_WIDE_DYNAMIC_RANGE</constant></entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Enables or disables the camera's wide dynamic
+range feature. This feature allows to obtain clear images in situations where
+intensity of the illumination varies significantly throughout the scene, i.e.
+there are simultaneously very dark and very bright areas. It is most commonly
+realized in cameras by combining two subsequent frames with different exposure
+times. <footnote id="ctypeconv"><para> This control may be changed to a menu
+control in the future, if more options are required.</para></footnote></entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row id="v4l2-image-stabilization">
+	    <entry spanname="id"><constant>V4L2_CID_IMAGE_STABILIZATION</constant></entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Enables or disables image stabilization.
+	      <footnoteref linkend="ctypeconv"/></entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_ISO_SENSITIVITY</constant>&nbsp;</entry>
+	    <entry>integer menu</entry>
+	  </row><row><entry spanname="descr">Determines ISO equivalent of an
+image sensor indicating the sensor's sensitivity to light. The numbers are
+expressed in arithmetic scale, as per <xref linkend="iso12232" /> standard,
+where doubling the sensor sensitivity is represented by doubling the numerical
+ISO value. Applications should interpret the values as standard ISO values
+multiplied by 1000, e.g. control value 800 stands for ISO 0.8. Drivers will
+usually support only a subset of standard ISO values. The effect of setting
+this control while the <constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>
+control is set to a value other than <constant>V4L2_CID_ISO_SENSITIVITY_MANUAL
+</constant> is undefined, drivers should ignore such requests.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row id="v4l2-iso-sensitivity-auto-type">
+	    <entry spanname="id"><constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>&nbsp;</entry>
+	    <entry>enum&nbsp;v4l2_iso_sensitivity_type</entry>
+	  </row><row><entry spanname="descr">Enables or disables automatic ISO
+sensitivity adjustments.</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_CID_ISO_SENSITIVITY_MANUAL</constant>&nbsp;</entry>
+		  <entry>Manual ISO sensitivity.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>&nbsp;</entry>
+		  <entry>Automatic ISO sensitivity adjustments.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row id="v4l2-scene-mode">
+	    <entry spanname="id"><constant>V4L2_CID_SCENE_MODE</constant>&nbsp;</entry>
+	    <entry>enum&nbsp;v4l2_scene_mode</entry>
+	  </row><row><entry spanname="descr">This control allows to select
+scene programs as the camera automatic modes optimized for common shooting
+scenes. Within these modes the camera determines best exposure, aperture,
+focusing, light metering, white balance and equivalent sensitivity. The
+controls of those parameters are influenced by the scene mode control.
+An exact behavior in each mode is subject to the camera specification.
+
+<para>When the scene mode feature is not used, this control should be set to
+<constant>V4L2_SCENE_MODE_NONE</constant> to make sure the other possibly
+related controls are accessible. The following scene programs are defined:
+</para>
+</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_NONE</constant>&nbsp;</entry>
+		  <entry>The scene mode feature is disabled.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_BACKLIGHT</constant>&nbsp;</entry>
+		  <entry>Backlight. Compensates for dark shadows when light is
+		  coming from behind a subject, also by automatically turning
+		  on the flash.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_BEACH_SNOW</constant>&nbsp;</entry>
+		  <entry>Beach and snow. This mode compensates for all-white or
+bright scenes, which tend to look gray and low contrast, when camera's automatic
+exposure is based on an average scene brightness. To compensate, this mode
+automatically slightly overexposes the frames. The white balance may also be
+adjusted to compensate for the fact that reflected snow looks bluish rather
+than white.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_CANDLELIGHT</constant>&nbsp;</entry>
+		  <entry>Candle light. The camera generally raises the ISO
+sensitivity and lowers the shutter speed. This mode compensates for relatively
+close subject in the scene. The flash is disabled in order to preserve the
+ambiance of the light.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_DAWN_DUSK</constant>&nbsp;</entry>
+		  <entry>Dawn and dusk. Preserves the colors seen in low
+natural light before dusk and after down. The camera may turn off the flash,
+and automatically focus at infinity. It will usually boost saturation and
+lower the shutter speed.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_FALL_COLORS</constant>&nbsp;</entry>
+		  <entry>Fall colors. Increases saturation and adjusts white
+balance for color enhancement. Pictures of autumn leaves get saturated reds
+and yellows.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_FIREWORKS</constant>&nbsp;</entry>
+		  <entry>Fireworks. Long exposure times are used to capture
+the expanding burst of light from a firework. The camera may invoke image
+stabilization.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_LANDSCAPE</constant>&nbsp;</entry>
+		  <entry>Landscape. The camera may choose a small aperture to
+provide deep depth of field and long exposure duration to help capture detail
+in dim light conditions. The focus is fixed at infinity. Suitable for distant
+and wide scenery.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_NIGHT</constant>&nbsp;</entry>
+		  <entry>Night, also known as Night Landscape. Designed for low
+light conditions, it preserves detail in the dark areas without blowing out bright
+objects. The camera generally sets itself to a medium-to-high ISO sensitivity,
+with a relatively long exposure time, and turns flash off. As such, there will be
+increased image noise and the possibility of blurred image.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_PARTY_INDOOR</constant>&nbsp;</entry>
+		  <entry>Party and indoor. Designed to capture indoor scenes
+that are lit by indoor background lighting as well as the flash. The camera
+usually increases ISO sensitivity, and adjusts exposure for the low light
+conditions.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_PORTRAIT</constant>&nbsp;</entry>
+		  <entry>Portrait. The camera adjusts the aperture so that the
+depth of field is reduced, which helps to isolate the subject against a smooth
+background. Most cameras recognize the presence of faces in the scene and focus
+on them. The color hue is adjusted to enhance skin tones. The intensity of the
+flash is often reduced.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_SPORTS</constant>&nbsp;</entry>
+		  <entry>Sports. Significantly increases ISO and uses a fast
+shutter speed to freeze motion of rapidly-moving subjects. Increased image
+noise may be seen in this mode.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_SUNSET</constant>&nbsp;</entry>
+		  <entry>Sunset. Preserves deep hues seen in sunsets and
+sunrises. It bumps up the saturation.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_SCENE_MODE_TEXT</constant>&nbsp;</entry>
+		  <entry>Text. It applies extra contrast and sharpness, it is
+typically a black-and-white mode optimized for readability. Automatic focus
+may be switched to close-up mode and this setting may also involve some
+lens-distortion correction.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_3A_LOCK</constant></entry>
+	    <entry>bitmask</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">This control locks or unlocks the automatic
+focus, exposure and white balance. The automatic adjustments can be paused
+independently by setting the corresponding lock bit to 1. The camera then retains
+the settings until the lock bit is cleared. The following lock bits are defined:
+</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_LOCK_EXPOSURE</constant></entry>
+		  <entry>Automatic exposure adjustments lock.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_LOCK_WHITE_BALANCE</constant></entry>
+		  <entry>Automatic white balance adjustments lock.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_LOCK_FOCUS</constant></entry>
+		  <entry>Automatic focus lock.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row><entry spanname="descr">
+When a given algorithm is not enabled, drivers should ignore requests
+to lock it and should return no error. An example might be an application
+setting bit <constant>V4L2_LOCK_WHITE_BALANCE</constant> when the
+<constant>V4L2_CID_AUTO_WHITE_BALANCE</constant> control is set to
+<constant>FALSE</constant>. The value of this control may be changed
+by exposure, white balance or focus controls.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
 	</tbody>
       </tgroup>
     </table>
@@ -3476,7 +3978,7 @@
 	    <entry spanname="id"><constant>V4L2_CID_JPEG_CHROMA_SUBSAMPLING</constant></entry>
 	    <entry>menu</entry>
 	  </row>
-	  <row id="jpeg-chroma-subsampling-control">
+	  <row id="v4l2-jpeg-chroma-subsampling">
 	    <entry spanname="descr">The chroma subsampling factors describe how
 	    each component of an input image is sampled, in respect to maximum
 	    sample rate in each spatial dimension. See <xref linkend="itu-t81"/>,
@@ -3486,7 +3988,7 @@
 	    from RGB to Y'CbCr color space.
 	    </entry>
 	  </row>
-	  <row>
+	  <row id = "v4l2-jpeg-chroma-subsampling">
 	    <entrytbl spanname="descr" cols="2">
 	      <tbody valign="top">
 		<row>
@@ -3538,12 +4040,12 @@
 	    </entry>
 	  </row>
 	  <row id="jpeg-quality-control">
-	    <entry spanname="id"><constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant></entry>
+	    <entry spanname="id"><constant>V4L2_CID_JPEG_COMPRESSION_QUALITY</constant></entry>
 	    <entry>integer</entry>
 	  </row>
 	  <row>
 	    <entry spanname="descr">
-	      <constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control
+	      <constant>V4L2_CID_JPEG_COMPRESSION_QUALITY</constant> control
 	      determines trade-off between image quality and size.
 	      It provides simpler method for applications to control image quality,
 	      without a need for direct reconfiguration of luminance and chrominance
@@ -3551,7 +4053,7 @@
 
 	      In cases where a driver uses quantization tables configured directly
 	      by an application, using interfaces defined elsewhere, <constant>
-	      V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control should be set
+	      V4L2_CID_JPEG_COMPRESSION_QUALITY</constant> control should be set
 	      by driver to 0.
 
 	      <para>The value range of this control is driver-specific. Only
@@ -3599,4 +4101,172 @@
       to <xref linkend="itu-t81"/>, <xref linkend="jfif"/>,
       <xref linkend="w3c-jpeg-jfif"/>.</para>
     </section>
+
+    <section id="image-source-controls">
+      <title>Image Source Control Reference</title>
+
+      <note>
+	<title>Experimental</title>
+
+	<para>This is an <link
+	linkend="experimental">experimental</link> interface and may
+	change in the future.</para>
+      </note>
+
+      <para>
+	The Image Source control class is intended for low-level
+	control of image source devices such as image sensors. The
+	devices feature an analogue to digital converter and a bus
+	transmitter to transmit the image data out of the device.
+      </para>
+
+      <table pgwide="1" frame="none" id="image-source-control-id">
+      <title>Image Source Control IDs</title>
+
+      <tgroup cols="4">
+	<colspec colname="c1" colwidth="1*" />
+	<colspec colname="c2" colwidth="6*" />
+	<colspec colname="c3" colwidth="2*" />
+	<colspec colname="c4" colwidth="6*" />
+	<spanspec namest="c1" nameend="c2" spanname="id" />
+	<spanspec namest="c2" nameend="c4" spanname="descr" />
+	<thead>
+	  <row>
+	    <entry spanname="id" align="left">ID</entry>
+	    <entry align="left">Type</entry>
+	  </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+	  </row>
+	</thead>
+	<tbody valign="top">
+	  <row><entry></entry></row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry>
+	    <entry>class</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">The IMAGE_SOURCE class descriptor.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_VBLANK</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Vertical blanking. The idle period
+	    after every frame during which no image data is produced.
+	    The unit of vertical blanking is a line. Every line has
+	    length of the image width plus horizontal blanking at the
+	    pixel rate defined by
+	    <constant>V4L2_CID_PIXEL_RATE</constant> control in the
+	    same sub-device.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_HBLANK</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Horizontal blanking. The idle
+	    period after every line of image data during which no
+	    image data is produced. The unit of horizontal blanking is
+	    pixels.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_ANALOGUE_GAIN</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Analogue gain is gain affecting
+	    all colour components in the pixel matrix. The gain
+	    operation is performed in the analogue domain before A/D
+	    conversion.
+	    </entry>
+	  </row>
+	  <row><entry></entry></row>
+	</tbody>
+      </tgroup>
+      </table>
+
+    </section>
+
+    <section id="image-process-controls">
+      <title>Image Process Control Reference</title>
+
+      <note>
+	<title>Experimental</title>
+
+	<para>This is an <link
+	linkend="experimental">experimental</link> interface and may
+	change in the future.</para>
+      </note>
+
+      <para>
+	The Image Source control class is intended for low-level control of
+	image processing functions. Unlike
+	<constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant>, the controls in
+	this class affect processing the image, and do not control capturing
+	of it.
+      </para>
+
+      <table pgwide="1" frame="none" id="image-process-control-id">
+      <title>Image Source Control IDs</title>
+
+      <tgroup cols="4">
+	<colspec colname="c1" colwidth="1*" />
+	<colspec colname="c2" colwidth="6*" />
+	<colspec colname="c3" colwidth="2*" />
+	<colspec colname="c4" colwidth="6*" />
+	<spanspec namest="c1" nameend="c2" spanname="id" />
+	<spanspec namest="c2" nameend="c4" spanname="descr" />
+	<thead>
+	  <row>
+	    <entry spanname="id" align="left">ID</entry>
+	    <entry align="left">Type</entry>
+	  </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+	  </row>
+	</thead>
+	<tbody valign="top">
+	  <row><entry></entry></row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IMAGE_PROC_CLASS</constant></entry>
+	    <entry>class</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">The IMAGE_PROC class descriptor.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_LINK_FREQ</constant></entry>
+	    <entry>integer menu</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Data bus frequency. Together with the
+	    media bus pixel code, bus type (clock cycles per sample), the
+	    data bus frequency defines the pixel rate
+	    (<constant>V4L2_CID_PIXEL_RATE</constant>) in the
+	    pixel array (or possibly elsewhere, if the device is not an
+	    image sensor). The frame rate can be calculated from the pixel
+	    clock, image width and height and horizontal and vertical
+	    blanking. While the pixel rate control may be defined elsewhere
+	    than in the subdev containing the pixel array, the frame rate
+	    cannot be obtained from that information. This is because only
+	    on the pixel array it can be assumed that the vertical and
+	    horizontal blanking information is exact: no other blanking is
+	    allowed in the pixel array. The selection of frame rate is
+	    performed by selecting the desired horizontal and vertical
+	    blanking. The unit of this control is Hz. </entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_PIXEL_RATE</constant></entry>
+	    <entry>64-bit integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Pixel rate in the source pads of
+	    the subdev. This control is read-only and its unit is
+	    pixels / second.
+	    </entry>
+	  </row>
+	  <row><entry></entry></row>
+	</tbody>
+      </tgroup>
+      </table>
+
+    </section>
 </section>
diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml
index 0916a73..4afcbbe 100644
--- a/Documentation/DocBook/media/v4l/dev-subdev.xml
+++ b/Documentation/DocBook/media/v4l/dev-subdev.xml
@@ -76,11 +76,12 @@
     <wordasword>format</wordasword> means the combination of media bus data
     format, frame width and frame height.</para></note>
 
-    <para>Image formats are typically negotiated on video capture and output
-    devices using the <link linkend="crop">cropping and scaling</link> ioctls.
-    The driver is responsible for configuring every block in the video pipeline
-    according to the requested format at the pipeline input and/or
-    output.</para>
+    <para>Image formats are typically negotiated on video capture and
+    output devices using the format and <link
+    linkend="vidioc-subdev-g-selection">selection</link> ioctls. The
+    driver is responsible for configuring every block in the video
+    pipeline according to the requested format at the pipeline input
+    and/or output.</para>
 
     <para>For complex devices, such as often found in embedded systems,
     identical image sizes at the output of a pipeline can be achieved using
@@ -276,11 +277,11 @@
     </section>
 
     <section>
-      <title>Cropping and scaling</title>
+      <title>Selections: cropping, scaling and composition</title>
 
       <para>Many sub-devices support cropping frames on their input or output
       pads (or possible even on both). Cropping is used to select the area of
-      interest in an image, typically on a video sensor or video decoder. It can
+      interest in an image, typically on an image sensor or a video decoder. It can
       also be used as part of digital zoom implementations to select the area of
       the image that will be scaled up.</para>
 
@@ -288,26 +289,179 @@
       &v4l2-rect; by the coordinates of the top left corner and the rectangle
       size. Both the coordinates and sizes are expressed in pixels.</para>
 
-      <para>The crop rectangle is retrieved and set using the
-      &VIDIOC-SUBDEV-G-CROP; and &VIDIOC-SUBDEV-S-CROP; ioctls. Like for pad
-      formats, drivers store try and active crop rectangles. The format
-      negotiation mechanism applies to crop settings as well.</para>
+      <para>As for pad formats, drivers store try and active
+      rectangles for the selection targets of ACTUAL type <xref
+      linkend="v4l2-subdev-selection-targets">.</xref></para>
 
-      <para>On input pads, cropping is applied relatively to the current pad
-      format. The pad format represents the image size as received by the
-      sub-device from the previous block in the pipeline, and the crop rectangle
-      represents the sub-image that will be transmitted further inside the
-      sub-device for processing. The crop rectangle be entirely containted
-      inside the input image size.</para>
+      <para>On sink pads, cropping is applied relative to the
+      current pad format. The pad format represents the image size as
+      received by the sub-device from the previous block in the
+      pipeline, and the crop rectangle represents the sub-image that
+      will be transmitted further inside the sub-device for
+      processing.</para>
 
-      <para>Input crop rectangle are reset to their default value when the input
-      image format is modified. Drivers should use the input image size as the
-      crop rectangle default value, but hardware requirements may prevent this.
-      </para>
+      <para>The scaling operation changes the size of the image by
+      scaling it to new dimensions. The scaling ratio isn't specified
+      explicitly, but is implied from the original and scaled image
+      sizes. Both sizes are represented by &v4l2-rect;.</para>
 
-      <para>Cropping behaviour on output pads is not defined.</para>
+      <para>Scaling support is optional. When supported by a subdev,
+      the crop rectangle on the subdev's sink pad is scaled to the
+      size configured using the &VIDIOC-SUBDEV-S-SELECTION; IOCTL
+      using <constant>V4L2_SUBDEV_SEL_COMPOSE_ACTUAL</constant>
+      selection target on the same pad. If the subdev supports scaling
+      but not composing, the top and left values are not used and must
+      always be set to zero.</para>
+
+      <para>On source pads, cropping is similar to sink pads, with the
+      exception that the source size from which the cropping is
+      performed, is the COMPOSE rectangle on the sink pad. In both
+      sink and source pads, the crop rectangle must be entirely
+      contained inside the source image size for the crop
+      operation.</para>
+
+      <para>The drivers should always use the closest possible
+      rectangle the user requests on all selection targets, unless
+      specifically told otherwise.
+      <constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant> and
+      <constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant> flags may be
+      used to round the image size either up or down. <xref
+      linkend="v4l2-subdev-selection-flags"></xref></para>
+    </section>
+
+    <section>
+      <title>Types of selection targets</title>
+
+      <section>
+	<title>ACTUAL targets</title>
+
+	<para>ACTUAL targets reflect the actual hardware configuration
+	at any point of time. There is a BOUNDS target
+	corresponding to every ACTUAL.</para>
+      </section>
+
+      <section>
+	<title>BOUNDS targets</title>
+
+	<para>BOUNDS targets is the smallest rectangle that contains
+	all valid ACTUAL rectangles. It may not be possible to set the
+	ACTUAL rectangle as large as the BOUNDS rectangle, however.
+	This may be because e.g. a sensor's pixel array is not
+	rectangular but cross-shaped or round. The maximum size may
+	also be smaller than the BOUNDS rectangle.</para>
+      </section>
 
     </section>
+
+    <section>
+      <title>Order of configuration and format propagation</title>
+
+      <para>Inside subdevs, the order of image processing steps will
+      always be from the sink pad towards the source pad. This is also
+      reflected in the order in which the configuration must be
+      performed by the user: the changes made will be propagated to
+      any subsequent stages. If this behaviour is not desired, the
+      user must set
+      <constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant> flag. This
+      flag causes no propagation of the changes are allowed in any
+      circumstances. This may also cause the accessed rectangle to be
+      adjusted by the driver, depending on the properties of the
+      underlying hardware.</para>
+
+      <para>The coordinates to a step always refer to the actual size
+      of the previous step. The exception to this rule is the source
+      compose rectangle, which refers to the sink compose bounds
+      rectangle --- if it is supported by the hardware.</para>
+
+      <orderedlist>
+	<listitem>Sink pad format. The user configures the sink pad
+	format. This format defines the parameters of the image the
+	entity receives through the pad for further processing.</listitem>
+
+	<listitem>Sink pad actual crop selection. The sink pad crop
+	defines the crop performed to the sink pad format.</listitem>
+
+	<listitem>Sink pad actual compose selection. The size of the
+	sink pad compose rectangle defines the scaling ratio compared
+	to the size of the sink pad crop rectangle. The location of
+	the compose rectangle specifies the location of the actual
+	sink compose rectangle in the sink compose bounds
+	rectangle.</listitem>
+
+	<listitem>Source pad actual crop selection. Crop on the source
+	pad defines crop performed to the image in the sink compose
+	bounds rectangle.</listitem>
+
+	<listitem>Source pad format. The source pad format defines the
+	output pixel format of the subdev, as well as the other
+	parameters with the exception of the image width and height.
+	Width and height are defined by the size of the source pad
+	actual crop selection.</listitem>
+      </orderedlist>
+
+      <para>Accessing any of the above rectangles not supported by the
+      subdev will return <constant>EINVAL</constant>. Any rectangle
+      referring to a previous unsupported rectangle coordinates will
+      instead refer to the previous supported rectangle. For example,
+      if sink crop is not supported, the compose selection will refer
+      to the sink pad format dimensions instead.</para>
+
+      <figure id="subdev-image-processing-crop">
+	<title>Image processing in subdevs: simple crop example</title>
+	<mediaobject>
+	  <imageobject>
+	    <imagedata fileref="subdev-image-processing-crop.svg"
+	    format="SVG" scale="200" />
+	  </imageobject>
+	</mediaobject>
+      </figure>
+
+      <para>In the above example, the subdev supports cropping on its
+      sink pad. To configure it, the user sets the media bus format on
+      the subdev's sink pad. Now the actual crop rectangle can be set
+      on the sink pad --- the location and size of this rectangle
+      reflect the location and size of a rectangle to be cropped from
+      the sink format. The size of the sink crop rectangle will also
+      be the size of the format of the subdev's source pad.</para>
+
+      <figure id="subdev-image-processing-scaling-multi-source">
+	<title>Image processing in subdevs: scaling with multiple sources</title>
+	<mediaobject>
+	  <imageobject>
+	    <imagedata fileref="subdev-image-processing-scaling-multi-source.svg"
+	    format="SVG" scale="200" />
+	  </imageobject>
+	</mediaobject>
+      </figure>
+
+      <para>In this example, the subdev is capable of first cropping,
+      then scaling and finally cropping for two source pads
+      individually from the resulting scaled image. The location of
+      the scaled image in the cropped image is ignored in sink compose
+      target. Both of the locations of the source crop rectangles
+      refer to the sink scaling rectangle, independently cropping an
+      area at location specified by the source crop rectangle from
+      it.</para>
+
+      <figure id="subdev-image-processing-full">
+	<title>Image processing in subdevs: scaling and composition
+	with multiple sinks and sources</title>
+	<mediaobject>
+	  <imageobject>
+	    <imagedata fileref="subdev-image-processing-full.svg"
+	    format="SVG" scale="200" />
+	  </imageobject>
+	</mediaobject>
+      </figure>
+
+      <para>The subdev driver supports two sink pads and two source
+      pads. The images from both of the sink pads are individually
+      cropped, then scaled and further composed on the composition
+      bounds rectangle. From that, two independent streams are cropped
+      and sent out of the subdev from the source pads.</para>
+
+    </section>
+
   </section>
 
   &sub-subdev-formats;
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index b815929..fd6aca2 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -543,12 +543,13 @@
 with the &VIDIOC-REQBUFS; ioctl (&v4l2-requestbuffers; <structfield>count</structfield>) minus one.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-buf-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry></entry>
 	    <entry>Type of the buffer, same as &v4l2-format;
 <structfield>type</structfield> or &v4l2-requestbuffers;
-<structfield>type</structfield>, set by the application.</entry>
+<structfield>type</structfield>, set by the application. See <xref
+linkend="v4l2-buf-type" /></entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
@@ -568,7 +569,7 @@
 linkend="buffer-flags" />.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-field;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>field</structfield></entry>
 	    <entry></entry>
 	    <entry>Indicates the field order of the image in the
@@ -630,11 +631,12 @@
 standards, see <xref linkend="standard" />.</para></entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-memory;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>memory</structfield></entry>
 	    <entry></entry>
 	    <entry>This field must be set by applications and/or drivers
-in accordance with the selected I/O method.</entry>
+in accordance with the selected I/O method. See <xref linkend="v4l2-memory"
+	    /></entry>
 	  </row>
 	  <row>
 	    <entry>union</entry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml
index 7b27409..c1c62a9 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml
@@ -1,4 +1,4 @@
-    <refentry>
+    <refentry id="pixfmt-srggb10">
       <refmeta>
 	<refentrytitle>V4L2_PIX_FMT_SRGGB10 ('RG10'),
 	 V4L2_PIX_FMT_SGRBG10 ('BA10'),
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
new file mode 100644
index 0000000..8eace3e
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
@@ -0,0 +1,29 @@
+    <refentry id="pixfmt-srggb10dpcm8">
+      <refmeta>
+	<refentrytitle>
+	 V4L2_PIX_FMT_SBGGR10DPCM8 ('bBA8'),
+	 V4L2_PIX_FMT_SGBRG10DPCM8 ('bGA8'),
+	 V4L2_PIX_FMT_SGRBG10DPCM8 ('BD10'),
+	 V4L2_PIX_FMT_SRGGB10DPCM8 ('bRA8'),
+	 </refentrytitle>
+	&manvol;
+      </refmeta>
+      <refnamediv>
+	<refname id="V4L2-PIX-FMT-SBGGR10DPCM8"><constant>V4L2_PIX_FMT_SBGGR10DPCM8</constant></refname>
+	<refname id="V4L2-PIX-FMT-SGBRG10DPCM8"><constant>V4L2_PIX_FMT_SGBRG10DPCM8</constant></refname>
+	<refname id="V4L2-PIX-FMT-SGRBG10DPCM8"><constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant></refname>
+	<refname id="V4L2-PIX-FMT-SRGGB10DPCM8"><constant>V4L2_PIX_FMT_SRGGB10DPCM8</constant></refname>
+	<refpurpose>10-bit Bayer formats compressed to 8 bits</refpurpose>
+      </refnamediv>
+      <refsect1>
+	<title>Description</title>
+
+	<para>The following four pixel formats are raw sRGB / Bayer formats
+	with 10 bits per colour compressed to 8 bits each, using DPCM
+	compression. DPCM, differential pulse-code modulation, is lossy.
+	Each colour component consumes 8 bits of memory. In other respects
+	this format is similar to <xref
+	linkend="pixfmt-srggb10">.</xref></para>
+
+      </refsect1>
+    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index 31eaae2..f5ac15e 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt.xml
@@ -673,6 +673,7 @@
     &sub-srggb8;
     &sub-sbggr16;
     &sub-srggb10;
+    &sub-srggb10dpcm8;
     &sub-srggb12;
   </section>
 
@@ -876,11 +877,6 @@
 	    <entry>'S561'</entry>
 	    <entry>Compressed GBRG Bayer format used by the gspca driver.</entry>
 	  </row>
-	  <row id="V4L2-PIX-FMT-SGRBG10DPCM8">
-	    <entry><constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant></entry>
-	    <entry>'DB10'</entry>
-	    <entry>10 bit raw Bayer DPCM compressed to 8 bits.</entry>
-	  </row>
 	  <row id="V4L2-PIX-FMT-PAC207">
 	    <entry><constant>V4L2_PIX_FMT_PAC207</constant></entry>
 	    <entry>'P207'</entry>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia
new file mode 100644
index 0000000..e32ba53
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia
@@ -0,0 +1,614 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+  <dia:diagramdata>
+    <dia:attribute name="background">
+      <dia:color val="#ffffff"/>
+    </dia:attribute>
+    <dia:attribute name="pagebreak">
+      <dia:color val="#000099"/>
+    </dia:attribute>
+    <dia:attribute name="paper">
+      <dia:composite type="paper">
+        <dia:attribute name="name">
+          <dia:string>#A4#</dia:string>
+        </dia:attribute>
+        <dia:attribute name="tmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="bmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="lmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="rmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="is_portrait">
+          <dia:boolean val="false"/>
+        </dia:attribute>
+        <dia:attribute name="scaling">
+          <dia:real val="0.49000000953674316"/>
+        </dia:attribute>
+        <dia:attribute name="fitto">
+          <dia:boolean val="false"/>
+        </dia:attribute>
+      </dia:composite>
+    </dia:attribute>
+    <dia:attribute name="grid">
+      <dia:composite type="grid">
+        <dia:attribute name="width_x">
+          <dia:real val="1"/>
+        </dia:attribute>
+        <dia:attribute name="width_y">
+          <dia:real val="1"/>
+        </dia:attribute>
+        <dia:attribute name="visible_x">
+          <dia:int val="1"/>
+        </dia:attribute>
+        <dia:attribute name="visible_y">
+          <dia:int val="1"/>
+        </dia:attribute>
+        <dia:composite type="color"/>
+      </dia:composite>
+    </dia:attribute>
+    <dia:attribute name="color">
+      <dia:color val="#d8e5e5"/>
+    </dia:attribute>
+    <dia:attribute name="guides">
+      <dia:composite type="guides">
+        <dia:attribute name="hguides"/>
+        <dia:attribute name="vguides"/>
+      </dia:composite>
+    </dia:attribute>
+  </dia:diagramdata>
+  <dia:layer name="Background" visible="true" active="true">
+    <dia:object type="Standard - Box" version="0" id="O0">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-0.4,6.5"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-0.45,6.45;23.1387,16.2"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-0.4,6.5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="23.48871579904775"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="9.6500000000000004"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O1">
+      <dia:attribute name="obj_pos">
+        <dia:point val="0.225,9.45"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="0.175,9.4;8.225,14.7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="0.225,9.45"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7.9499999999999975"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="5.1999999999999975"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#a52a2a"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O2">
+      <dia:attribute name="obj_pos">
+        <dia:point val="3.175,10.55"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.125,10.5;7.925,14.45"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="3.175,10.55"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="4.6999999999999975"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.8499999999999979"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#0000ff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O3">
+      <dia:attribute name="obj_pos">
+        <dia:point val="3.725,11.3875"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.725,10.7925;6.6025,13.14"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#sink
+crop
+selection#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="3.725,11.3875"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#0000ff"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O4">
+      <dia:attribute name="obj_pos">
+        <dia:point val="1.475,7.9"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="1.475,7.305;1.475,8.0525"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="1.475,7.9"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O5">
+      <dia:attribute name="obj_pos">
+        <dia:point val="0.426918,7.89569"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="0.426918,7.30069;3.90942,8.84819"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#sink media
+bus format#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="0.426918,7.89569"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#a52a2a"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O6">
+      <dia:attribute name="obj_pos">
+        <dia:point val="17.4887,7.75"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="17.4887,7.155;21.8112,8.7025"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#source media
+bus format#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="17.4887,7.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#8b6914"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O7">
+      <dia:attribute name="obj_pos">
+        <dia:point val="17.5244,9.5417"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="17.4744,9.4917;22.2387,13.35"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="17.5244,9.5417"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="4.6643157990477508"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.758300000000002"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#8b6914"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O8">
+      <dia:attribute name="obj_pos">
+        <dia:point val="17.5244,13.3"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.12132,13.2463;17.5781,14.4537"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="17.5244,13.3"/>
+        <dia:point val="3.175,14.4"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O7" connection="5"/>
+        <dia:connection handle="1" to="O2" connection="5"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O9">
+      <dia:attribute name="obj_pos">
+        <dia:point val="17.5244,9.5417"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.12162,9.48832;17.5778,10.6034"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="17.5244,9.5417"/>
+        <dia:point val="3.175,10.55"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O7" connection="0"/>
+        <dia:connection handle="1" to="O2" connection="0"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O10">
+      <dia:attribute name="obj_pos">
+        <dia:point val="22.1887,13.3"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="7.82132,13.2463;22.2424,14.4537"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="22.1887,13.3"/>
+        <dia:point val="7.875,14.4"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O7" connection="7"/>
+        <dia:connection handle="1" to="O2" connection="7"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O11">
+      <dia:attribute name="obj_pos">
+        <dia:point val="22.1887,9.5417"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="7.82161,9.48831;22.2421,10.6034"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="22.1887,9.5417"/>
+        <dia:point val="7.875,10.55"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O7" connection="2"/>
+        <dia:connection handle="1" to="O2" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Geometric - Perfect Circle" version="1" id="O12">
+      <dia:attribute name="obj_pos">
+        <dia:point val="23.23,10.5742"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="23.18,10.5242;24.13,11.4742"/>
+      </dia:attribute>
+      <dia:attribute name="meta">
+        <dia:composite type="dict"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="23.23,10.5742"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="line_width">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="line_colour">
+        <dia:color val="#000000"/>
+      </dia:attribute>
+      <dia:attribute name="fill_colour">
+        <dia:color val="#ffffff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="0"/>
+        <dia:real val="1"/>
+      </dia:attribute>
+      <dia:attribute name="flip_horizontal">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="flip_vertical">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="subscale">
+        <dia:real val="1"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O13">
+      <dia:attribute name="obj_pos">
+        <dia:point val="24.08,10.9992"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="24.03,10.6388;32.4953,11.3624"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="24.08,10.9992"/>
+        <dia:point val="32.3835,11.0007"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O12" connection="3"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O14">
+      <dia:attribute name="obj_pos">
+        <dia:point val="25.3454,10.49"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="25.3454,9.895;29.9904,10.6425"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#pad 1 (source)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="25.3454,10.49"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Geometric - Perfect Circle" version="1" id="O15">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-1.44491,11.6506"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-1.49491,11.6006;-0.54491,12.5506"/>
+      </dia:attribute>
+      <dia:attribute name="meta">
+        <dia:composite type="dict"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-1.44491,11.6506"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="line_width">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="line_colour">
+        <dia:color val="#000000"/>
+      </dia:attribute>
+      <dia:attribute name="fill_colour">
+        <dia:color val="#ffffff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="0"/>
+        <dia:real val="1"/>
+      </dia:attribute>
+      <dia:attribute name="flip_horizontal">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="flip_vertical">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="subscale">
+        <dia:real val="1"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O16">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-9.61991,12.09"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-9.67,11.7149;-1.33311,12.4385"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="-9.61991,12.09"/>
+        <dia:point val="-1.44491,12.0756"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O15" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O17">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-7.39291,11.49"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-7.39291,10.895;-3.58791,11.6425"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#pad 0 (sink)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-7.39291,11.49"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+  </dia:layer>
+</dia:diagram>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg
new file mode 100644
index 0000000..18b0f5d
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="43cm" height="10cm" viewBox="-194 128 844 196" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="-8" y="130" width="469.774" height="193"/>
+  <g>
+    <rect style="fill: #ffffff" x="4.5" y="189" width="159" height="104"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="4.5" y="189" width="159" height="104"/>
+  </g>
+  <g>
+    <rect style="fill: #ffffff" x="63.5" y="211" width="94" height="77"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="63.5" y="211" width="94" height="77"/>
+  </g>
+  <text style="fill: #0000ff;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="74.5" y="227.75">
+    <tspan x="74.5" y="227.75">sink</tspan>
+    <tspan x="74.5" y="243.75">crop</tspan>
+    <tspan x="74.5" y="259.75">selection</tspan>
+  </text>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="29.5" y="158">
+    <tspan x="29.5" y="158"></tspan>
+  </text>
+  <text style="fill: #a52a2a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="8.53836" y="157.914">
+    <tspan x="8.53836" y="157.914">sink media</tspan>
+    <tspan x="8.53836" y="173.914">bus format</tspan>
+  </text>
+  <text style="fill: #8b6914;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="349.774" y="155">
+    <tspan x="349.774" y="155">source media</tspan>
+    <tspan x="349.774" y="171">bus format</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="350.488" y="190.834" width="93.2863" height="75.166"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="350.488" y="190.834" width="93.2863" height="75.166"/>
+  </g>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="350.488" y1="266" x2="63.5" y2="288"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="350.488" y1="190.834" x2="63.5" y2="211"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="443.774" y1="266" x2="157.5" y2="288"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="443.774" y1="190.834" x2="157.5" y2="211"/>
+  <g>
+    <ellipse style="fill: #ffffff" cx="473.1" cy="219.984" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="473.1" cy="219.984" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="473.1" cy="219.984" rx="8.5" ry="8.5"/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="481.6" y1="219.984" x2="637.934" y2="220.012"/>
+    <polygon style="fill: #000000" points="645.434,220.014 635.433,225.012 637.934,220.012 635.435,215.012 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="645.434,220.014 635.433,225.012 637.934,220.012 635.435,215.012 "/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="506.908" y="209.8">
+    <tspan x="506.908" y="209.8">pad 1 (source)</tspan>
+  </text>
+  <g>
+    <ellipse style="fill: #ffffff" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-192.398" y1="241.8" x2="-38.6343" y2="241.529"/>
+    <polygon style="fill: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-147.858" y="229.8">
+    <tspan x="-147.858" y="229.8">pad 0 (sink)</tspan>
+  </text>
+</svg>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-full.dia b/Documentation/DocBook/media/v4l/subdev-image-processing-full.dia
new file mode 100644
index 0000000..a0d7829
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-full.dia
@@ -0,0 +1,1588 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+  <dia:diagramdata>
+    <dia:attribute name="background">
+      <dia:color val="#ffffff"/>
+    </dia:attribute>
+    <dia:attribute name="pagebreak">
+      <dia:color val="#000099"/>
+    </dia:attribute>
+    <dia:attribute name="paper">
+      <dia:composite type="paper">
+        <dia:attribute name="name">
+          <dia:string>#A4#</dia:string>
+        </dia:attribute>
+        <dia:attribute name="tmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="bmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="lmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="rmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="is_portrait">
+          <dia:boolean val="false"/>
+        </dia:attribute>
+        <dia:attribute name="scaling">
+          <dia:real val="0.49000000953674316"/>
+        </dia:attribute>
+        <dia:attribute name="fitto">
+          <dia:boolean val="false"/>
+        </dia:attribute>
+      </dia:composite>
+    </dia:attribute>
+    <dia:attribute name="grid">
+      <dia:composite type="grid">
+        <dia:attribute name="width_x">
+          <dia:real val="1"/>
+        </dia:attribute>
+        <dia:attribute name="width_y">
+          <dia:real val="1"/>
+        </dia:attribute>
+        <dia:attribute name="visible_x">
+          <dia:int val="1"/>
+        </dia:attribute>
+        <dia:attribute name="visible_y">
+          <dia:int val="1"/>
+        </dia:attribute>
+        <dia:composite type="color"/>
+      </dia:composite>
+    </dia:attribute>
+    <dia:attribute name="color">
+      <dia:color val="#d8e5e5"/>
+    </dia:attribute>
+    <dia:attribute name="guides">
+      <dia:composite type="guides">
+        <dia:attribute name="hguides"/>
+        <dia:attribute name="vguides"/>
+      </dia:composite>
+    </dia:attribute>
+  </dia:diagramdata>
+  <dia:layer name="Background" visible="true" active="true">
+    <dia:object type="Standard - Box" version="0" id="O0">
+      <dia:attribute name="obj_pos">
+        <dia:point val="15.945,6.45"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="15.895,6.4;26.4,18.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="15.945,6.45"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="10.404999999254942"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="12.449999999999992"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#ff765a"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O1">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-0.1,3.65"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-0.15,3.6;40.25,20.85"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-0.1,3.65"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="40.300000000000004"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="17.149999999999999"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Geometric - Perfect Circle" version="1" id="O2">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-1.05,7.9106"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-1.1,7.8606;-0.15,8.8106"/>
+      </dia:attribute>
+      <dia:attribute name="meta">
+        <dia:composite type="dict"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-1.05,7.9106"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="line_width">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="line_colour">
+        <dia:color val="#000000"/>
+      </dia:attribute>
+      <dia:attribute name="fill_colour">
+        <dia:color val="#ffffff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="0"/>
+        <dia:real val="1"/>
+      </dia:attribute>
+      <dia:attribute name="flip_horizontal">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="flip_vertical">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="subscale">
+        <dia:real val="1"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Geometric - Perfect Circle" version="1" id="O3">
+      <dia:attribute name="obj_pos">
+        <dia:point val="40.3366,9.8342"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="40.2866,9.7842;41.2366,10.7342"/>
+      </dia:attribute>
+      <dia:attribute name="meta">
+        <dia:composite type="dict"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="40.3366,9.8342"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="line_width">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="line_colour">
+        <dia:color val="#000000"/>
+      </dia:attribute>
+      <dia:attribute name="fill_colour">
+        <dia:color val="#ffffff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="0"/>
+        <dia:real val="1"/>
+      </dia:attribute>
+      <dia:attribute name="flip_horizontal">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="flip_vertical">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="subscale">
+        <dia:real val="1"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O4">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-9.225,8.35"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-9.27509,7.97487;-0.938197,8.69848"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="-9.225,8.35"/>
+        <dia:point val="-1.05,8.3356"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O2" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O5">
+      <dia:attribute name="obj_pos">
+        <dia:point val="41.1866,10.2592"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="41.1366,9.89879;49.6019,10.6224"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="41.1866,10.2592"/>
+        <dia:point val="49.4901,10.2607"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O3" connection="3"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O6">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-6.998,7.75"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-6.998,7.155;-3.193,7.9025"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#pad 0 (sink)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-6.998,7.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O7">
+      <dia:attribute name="obj_pos">
+        <dia:point val="42.452,9.75"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="42.452,9.155;47.097,9.9025"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#pad 2 (source)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="42.452,9.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O8">
+      <dia:attribute name="obj_pos">
+        <dia:point val="0.275,6"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="0.225,5.95;8.275,11.25"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="0.275,6"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7.9499999999999975"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="5.1999999999999975"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#a52a2a"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O9">
+      <dia:attribute name="obj_pos">
+        <dia:point val="3.125,6.8"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.075,6.75;7.875,10.7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="3.125,6.8"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="4.6999999999999975"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.8499999999999979"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#0000ff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O10">
+      <dia:attribute name="obj_pos">
+        <dia:point val="1.525,4.45"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="1.525,3.855;1.525,4.6025"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="1.525,4.45"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O11">
+      <dia:attribute name="obj_pos">
+        <dia:point val="0.476918,4.44569"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="0.476918,3.85069;3.95942,5.39819"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#sink media
+bus format#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="0.476918,4.44569"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#a52a2a"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O12">
+      <dia:attribute name="obj_pos">
+        <dia:point val="16.6822,9.28251"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="16.6322,9.23251;24.9922,17.9564"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="16.6822,9.28251"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="8.2600228398861297"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="8.6238900617957164"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#00ff00"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O13">
+      <dia:attribute name="obj_pos">
+        <dia:point val="16.6822,17.9064"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.05732,10.5823;16.7499,17.9741"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="16.6822,17.9064"/>
+        <dia:point val="3.125,10.65"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O12" connection="5"/>
+        <dia:connection handle="1" to="O9" connection="5"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O14">
+      <dia:attribute name="obj_pos">
+        <dia:point val="16.6822,9.28251"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.06681,6.74181;16.7404,9.3407"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="16.6822,9.28251"/>
+        <dia:point val="3.125,6.8"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O12" connection="0"/>
+        <dia:connection handle="1" to="O9" connection="0"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O15">
+      <dia:attribute name="obj_pos">
+        <dia:point val="24.9422,17.9064"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="7.75945,10.5845;25.0077,17.9719"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="24.9422,17.9064"/>
+        <dia:point val="7.825,10.65"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O12" connection="7"/>
+        <dia:connection handle="1" to="O9" connection="7"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O16">
+      <dia:attribute name="obj_pos">
+        <dia:point val="24.9422,9.28251"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="7.76834,6.74334;24.9989,9.33917"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="24.9422,9.28251"/>
+        <dia:point val="7.825,6.8"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O12" connection="2"/>
+        <dia:connection handle="1" to="O9" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O17">
+      <dia:attribute name="obj_pos">
+        <dia:point val="16.7352,7.47209"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="16.7352,6.87709;22.5602,8.42459"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#sink compose
+selection (scaling)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="16.7352,7.47209"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#00ff00"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O18">
+      <dia:attribute name="obj_pos">
+        <dia:point val="20.4661,9.72825"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="20.4161,9.67825;25.5254,13.3509"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="20.4661,9.72825"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5.009308462554376"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.5726155970598077"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#a020f0"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O19">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.475,5.2564"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="34.475,4.6614;38.7975,6.2089"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#source media
+bus format#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="34.475,5.2564"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#8b6914"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O20">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.4244,8.6917"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="34.3744,8.6417;39.4837,12.3143"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="34.4244,8.6917"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5.009308462554376"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.5726155970598077"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#8b6914"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O21">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.4244,12.2643"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="20.4125,12.2107;34.478,13.3545"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="34.4244,12.2643"/>
+        <dia:point val="20.4661,13.3009"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O20" connection="5"/>
+        <dia:connection handle="1" to="O18" connection="5"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O22">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.4244,8.6917"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="20.4125,8.63813;34.478,9.78182"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="34.4244,8.6917"/>
+        <dia:point val="20.4661,9.72825"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O20" connection="0"/>
+        <dia:connection handle="1" to="O18" connection="0"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O23">
+      <dia:attribute name="obj_pos">
+        <dia:point val="39.4337,12.2643"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="25.4218,12.2107;39.4873,13.3545"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="39.4337,12.2643"/>
+        <dia:point val="25.4754,13.3009"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O20" connection="7"/>
+        <dia:connection handle="1" to="O18" connection="7"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O24">
+      <dia:attribute name="obj_pos">
+        <dia:point val="39.4337,8.6917"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="25.4218,8.63813;39.4873,9.78182"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="39.4337,8.6917"/>
+        <dia:point val="25.4754,9.72825"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O20" connection="2"/>
+        <dia:connection handle="1" to="O18" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O25">
+      <dia:attribute name="obj_pos">
+        <dia:point val="16.25,5.15"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="16.25,4.555;21.68,6.1025"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#sink compose
+bounds selection#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="16.25,5.15"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#ff765a"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Geometric - Perfect Circle" version="1" id="O26">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-1.02991,16.6506"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-1.07991,16.6006;-0.12991,17.5506"/>
+      </dia:attribute>
+      <dia:attribute name="meta">
+        <dia:composite type="dict"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-1.02991,16.6506"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="line_width">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="line_colour">
+        <dia:color val="#000000"/>
+      </dia:attribute>
+      <dia:attribute name="fill_colour">
+        <dia:color val="#ffffff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="0"/>
+        <dia:real val="1"/>
+      </dia:attribute>
+      <dia:attribute name="flip_horizontal">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="flip_vertical">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="subscale">
+        <dia:real val="1"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O27">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-9.20491,17.09"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-9.255,16.7149;-0.918107,17.4385"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="-9.20491,17.09"/>
+        <dia:point val="-1.02991,17.0756"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O26" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O28">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-6.95,16.45"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-6.95,15.855;-3.145,16.6025"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#pad 1 (sink)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-6.95,16.45"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O29">
+      <dia:attribute name="obj_pos">
+        <dia:point val="0.390412,14.64"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="0.340412,14.59;6.045,18.8"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="0.390412,14.64"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5.604587512785236"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="4.1099999999999994"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#a52a2a"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O30">
+      <dia:attribute name="obj_pos">
+        <dia:point val="2.645,15.74"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="2.595,15.69;5.6,18.3"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="2.645,15.74"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="2.904999999254942"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2.5100000000000016"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#0000ff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O31">
+      <dia:attribute name="obj_pos">
+        <dia:point val="1.595,12.99"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="1.595,12.395;1.595,13.1425"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="1.595,12.99"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O32">
+      <dia:attribute name="obj_pos">
+        <dia:point val="17.945,12.595"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="2.58596,12.536;18.004,15.799"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="17.945,12.595"/>
+        <dia:point val="2.645,15.74"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O36" connection="0"/>
+        <dia:connection handle="1" to="O30" connection="0"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O33">
+      <dia:attribute name="obj_pos">
+        <dia:point val="17.945,15.8"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="2.58772,15.7427;18.0023,18.3073"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="17.945,15.8"/>
+        <dia:point val="2.645,18.25"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O36" connection="5"/>
+        <dia:connection handle="1" to="O30" connection="5"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O34">
+      <dia:attribute name="obj_pos">
+        <dia:point val="21.7,15.8"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="5.49307,15.7431;21.7569,18.3069"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="21.7,15.8"/>
+        <dia:point val="5.55,18.25"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O36" connection="7"/>
+        <dia:connection handle="1" to="O30" connection="7"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O35">
+      <dia:attribute name="obj_pos">
+        <dia:point val="21.7,12.595"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="5.49136,12.5364;21.7586,15.7986"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="21.7,12.595"/>
+        <dia:point val="5.55,15.74"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O36" connection="2"/>
+        <dia:connection handle="1" to="O30" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O36">
+      <dia:attribute name="obj_pos">
+        <dia:point val="17.945,12.595"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="17.895,12.545;21.75,15.85"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="17.945,12.595"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="3.7549999992549452"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.2049999992549427"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#00ff00"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O37">
+      <dia:attribute name="obj_pos">
+        <dia:point val="22.1631,14.2233"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="22.1131,14.1733;25.45,16.7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="22.1631,14.2233"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="3.2369000000000021"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2.4267000000000003"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#a020f0"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O38">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.6714,16.2367"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="34.6214,16.1867;37.9,18.75"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="34.6714,16.2367"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="3.178600000000003"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2.4632999999999967"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#8b6914"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O39">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.6714,18.7"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="22.1057,16.5926;34.7288,18.7574"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="34.6714,18.7"/>
+        <dia:point val="22.1631,16.65"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O38" connection="5"/>
+        <dia:connection handle="1" to="O37" connection="5"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O40">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.6714,16.2367"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="22.1058,14.166;34.7287,16.294"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="34.6714,16.2367"/>
+        <dia:point val="22.1631,14.2233"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O38" connection="0"/>
+        <dia:connection handle="1" to="O37" connection="0"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O41">
+      <dia:attribute name="obj_pos">
+        <dia:point val="37.85,18.7"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="25.3425,16.5925;37.9075,18.7575"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="37.85,18.7"/>
+        <dia:point val="25.4,16.65"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O38" connection="7"/>
+        <dia:connection handle="1" to="O37" connection="7"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O42">
+      <dia:attribute name="obj_pos">
+        <dia:point val="37.85,16.2367"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="25.3427,14.166;37.9073,16.294"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="37.85,16.2367"/>
+        <dia:point val="25.4,14.2233"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O38" connection="2"/>
+        <dia:connection handle="1" to="O37" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Geometric - Perfect Circle" version="1" id="O43">
+      <dia:attribute name="obj_pos">
+        <dia:point val="40.347,16.7742"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="40.297,16.7242;41.247,17.6742"/>
+      </dia:attribute>
+      <dia:attribute name="meta">
+        <dia:composite type="dict"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="40.347,16.7742"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="line_width">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="line_colour">
+        <dia:color val="#000000"/>
+      </dia:attribute>
+      <dia:attribute name="fill_colour">
+        <dia:color val="#ffffff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="0"/>
+        <dia:real val="1"/>
+      </dia:attribute>
+      <dia:attribute name="flip_horizontal">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="flip_vertical">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="subscale">
+        <dia:real val="1"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O44">
+      <dia:attribute name="obj_pos">
+        <dia:point val="41.197,17.1992"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="41.147,16.8388;49.6123,17.5624"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="41.197,17.1992"/>
+        <dia:point val="49.5005,17.2007"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O43" connection="3"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O45">
+      <dia:attribute name="obj_pos">
+        <dia:point val="42.4624,16.69"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="42.4624,16.095;47.1074,16.8425"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#pad 3 (source)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="42.4624,16.69"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O46">
+      <dia:attribute name="obj_pos">
+        <dia:point val="9.85,4.55"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="9.85,3.955;12.7275,6.3025"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#sink
+crop
+selection#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="9.85,4.55"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#0000ff"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O47">
+      <dia:attribute name="obj_pos">
+        <dia:point val="27.65,4.75"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="27.65,4.155;30.5275,6.5025"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#source
+crop
+selection#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="27.65,4.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#a020f0"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O48">
+      <dia:attribute name="obj_pos">
+        <dia:point val="10.55,6.6"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="7.7135,6.39438;10.6035,7.11605"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="10.55,6.6"/>
+        <dia:point val="7.825,6.8"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#0000ff"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O9" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O49">
+      <dia:attribute name="obj_pos">
+        <dia:point val="10.45,6.55"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="5.48029,6.48236;10.5176,15.8387"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="10.45,6.55"/>
+        <dia:point val="5.55,15.74"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#0000ff"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O30" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O50">
+      <dia:attribute name="obj_pos">
+        <dia:point val="27.5246,6.66071"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="25.406,6.59136;27.594,9.82122"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="27.5246,6.66071"/>
+        <dia:point val="25.4754,9.72825"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#a020f0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O18" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O51">
+      <dia:attribute name="obj_pos">
+        <dia:point val="27.5036,6.68935"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="25.2161,6.62775;27.5652,14.331"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="27.5036,6.68935"/>
+        <dia:point val="25.4,14.2233"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#a020f0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O37" connection="2"/>
+      </dia:connections>
+    </dia:object>
+  </dia:layer>
+</dia:diagram>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-full.svg b/Documentation/DocBook/media/v4l/subdev-image-processing-full.svg
new file mode 100644
index 0000000..3322cf4
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-full.svg
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="59cm" height="18cm" viewBox="-186 71 1178 346" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <g>
+    <rect style="fill: #ffffff" x="318.9" y="129" width="208.1" height="249"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #ff765a" x="318.9" y="129" width="208.1" height="249"/>
+  </g>
+  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="-2" y="73" width="806" height="343"/>
+  <g>
+    <ellipse style="fill: #ffffff" cx="-12.5" cy="166.712" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.5" cy="166.712" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.5" cy="166.712" rx="8.5" ry="8.5"/>
+  </g>
+  <g>
+    <ellipse style="fill: #ffffff" cx="815.232" cy="205.184" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.232" cy="205.184" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.232" cy="205.184" rx="8.5" ry="8.5"/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-184.5" y1="167" x2="-30.7361" y2="166.729"/>
+    <polygon style="fill: #000000" points="-23.2361,166.716 -33.2272,171.734 -30.7361,166.729 -33.2449,161.734 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-23.2361,166.716 -33.2272,171.734 -30.7361,166.729 -33.2449,161.734 "/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="823.732" y1="205.184" x2="980.066" y2="205.212"/>
+    <polygon style="fill: #000000" points="987.566,205.214 977.565,210.212 980.066,205.212 977.567,200.212 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="987.566,205.214 977.565,210.212 980.066,205.212 977.567,200.212 "/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-139.96" y="155">
+    <tspan x="-139.96" y="155">pad 0 (sink)</tspan>
+  </text>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="849.04" y="195">
+    <tspan x="849.04" y="195">pad 2 (source)</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="5.5" y="120" width="159" height="104"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="5.5" y="120" width="159" height="104"/>
+  </g>
+  <g>
+    <rect style="fill: #ffffff" x="62.5" y="136" width="94" height="77"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="62.5" y="136" width="94" height="77"/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="30.5" y="89">
+    <tspan x="30.5" y="89"></tspan>
+  </text>
+  <text style="fill: #a52a2a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="9.53836" y="88.9138">
+    <tspan x="9.53836" y="88.9138">sink media</tspan>
+    <tspan x="9.53836" y="104.914">bus format</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="333.644" y="185.65" width="165.2" height="172.478"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #00ff00" x="333.644" y="185.65" width="165.2" height="172.478"/>
+  </g>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="358.128" x2="62.5" y2="213"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="185.65" x2="62.5" y2="136"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="358.128" x2="156.5" y2="213"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="185.65" x2="156.5" y2="136"/>
+  <text style="fill: #00ff00;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="334.704" y="149.442">
+    <tspan x="334.704" y="149.442">sink compose</tspan>
+    <tspan x="334.704" y="165.442">selection (scaling)</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="409.322" y="194.565" width="100.186" height="71.4523"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="409.322" y="194.565" width="100.186" height="71.4523"/>
+  </g>
+  <text style="fill: #8b6914;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="689.5" y="105.128">
+    <tspan x="689.5" y="105.128">source media</tspan>
+    <tspan x="689.5" y="121.128">bus format</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="688.488" y="173.834" width="100.186" height="71.4523"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="688.488" y="173.834" width="100.186" height="71.4523"/>
+  </g>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="688.488" y1="245.286" x2="409.322" y2="266.018"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="688.488" y1="173.834" x2="409.322" y2="194.565"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="788.674" y1="245.286" x2="509.508" y2="266.018"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="788.674" y1="173.834" x2="509.508" y2="194.565"/>
+  <text style="fill: #ff765a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="325" y="103">
+    <tspan x="325" y="103">sink compose</tspan>
+    <tspan x="325" y="119">bounds selection</tspan>
+  </text>
+  <g>
+    <ellipse style="fill: #ffffff" cx="-12.0982" cy="341.512" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.0982" cy="341.512" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.0982" cy="341.512" rx="8.5" ry="8.5"/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-184.098" y1="341.8" x2="-30.3343" y2="341.529"/>
+    <polygon style="fill: #000000" points="-22.8343,341.516 -32.8254,346.534 -30.3343,341.529 -32.8431,336.534 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-22.8343,341.516 -32.8254,346.534 -30.3343,341.529 -32.8431,336.534 "/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-139" y="329">
+    <tspan x="-139" y="329">pad 1 (sink)</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="7.80824" y="292.8" width="112.092" height="82.2"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="7.80824" y="292.8" width="112.092" height="82.2"/>
+  </g>
+  <g>
+    <rect style="fill: #ffffff" x="52.9" y="314.8" width="58.1" height="50.2"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="52.9" y="314.8" width="58.1" height="50.2"/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="31.9" y="259.8">
+    <tspan x="31.9" y="259.8"></tspan>
+  </text>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="358.9" y1="251.9" x2="52.9" y2="314.8"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="358.9" y1="316" x2="52.9" y2="365"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="434" y1="316" x2="111" y2="365"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="434" y1="251.9" x2="111" y2="314.8"/>
+  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #00ff00" x="358.9" y="251.9" width="75.1" height="64.1"/>
+  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="443.262" y="284.466" width="64.738" height="48.534"/>
+  <g>
+    <rect style="fill: #ffffff" x="693.428" y="324.734" width="63.572" height="49.266"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="693.428" y="324.734" width="63.572" height="49.266"/>
+  </g>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="693.428" y1="374" x2="443.262" y2="333"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="693.428" y1="324.734" x2="443.262" y2="284.466"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="757" y1="374" x2="508" y2="333"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="757" y1="324.734" x2="508" y2="284.466"/>
+  <g>
+    <ellipse style="fill: #ffffff" cx="815.44" cy="343.984" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.44" cy="343.984" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.44" cy="343.984" rx="8.5" ry="8.5"/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="823.94" y1="343.984" x2="980.274" y2="344.012"/>
+    <polygon style="fill: #000000" points="987.774,344.014 977.773,349.012 980.274,344.012 977.775,339.012 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="987.774,344.014 977.773,349.012 980.274,344.012 977.775,339.012 "/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="849.248" y="333.8">
+    <tspan x="849.248" y="333.8">pad 3 (source)</tspan>
+  </text>
+  <text style="fill: #0000ff;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="197" y="91">
+    <tspan x="197" y="91">sink</tspan>
+    <tspan x="197" y="107">crop</tspan>
+    <tspan x="197" y="123">selection</tspan>
+  </text>
+  <text style="fill: #a020f0;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="553" y="95">
+    <tspan x="553" y="95">source</tspan>
+    <tspan x="553" y="111">crop</tspan>
+    <tspan x="553" y="127">selection</tspan>
+  </text>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x1="211" y1="132" x2="166.21" y2="135.287"/>
+    <polygon style="fill: #0000ff" points="158.73,135.836 168.337,130.118 166.21,135.287 169.069,140.091 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" points="158.73,135.836 168.337,130.118 166.21,135.287 169.069,140.091 "/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x1="209" y1="131" x2="115.581" y2="306.209"/>
+    <polygon style="fill: #0000ff" points="112.052,312.827 112.345,301.65 115.581,306.209 121.169,306.355 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" points="112.052,312.827 112.345,301.65 115.581,306.209 121.169,306.355 "/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="550.492" y1="133.214" x2="514.916" y2="186.469"/>
+    <polygon style="fill: #a020f0" points="510.75,192.706 512.147,181.613 514.916,186.469 520.463,187.168 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="510.75,192.706 512.147,181.613 514.916,186.469 520.463,187.168 "/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="550.072" y1="133.787" x2="510.618" y2="275.089"/>
+    <polygon style="fill: #a020f0" points="508.601,282.312 506.475,271.336 510.618,275.089 516.106,274.025 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="508.601,282.312 506.475,271.336 510.618,275.089 516.106,274.025 "/>
+  </g>
+</svg>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia
new file mode 100644
index 0000000..0cd50a7
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia
@@ -0,0 +1,1152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+  <dia:diagramdata>
+    <dia:attribute name="background">
+      <dia:color val="#ffffff"/>
+    </dia:attribute>
+    <dia:attribute name="pagebreak">
+      <dia:color val="#000099"/>
+    </dia:attribute>
+    <dia:attribute name="paper">
+      <dia:composite type="paper">
+        <dia:attribute name="name">
+          <dia:string>#A4#</dia:string>
+        </dia:attribute>
+        <dia:attribute name="tmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="bmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="lmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="rmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="is_portrait">
+          <dia:boolean val="false"/>
+        </dia:attribute>
+        <dia:attribute name="scaling">
+          <dia:real val="0.49000000953674316"/>
+        </dia:attribute>
+        <dia:attribute name="fitto">
+          <dia:boolean val="false"/>
+        </dia:attribute>
+      </dia:composite>
+    </dia:attribute>
+    <dia:attribute name="grid">
+      <dia:composite type="grid">
+        <dia:attribute name="width_x">
+          <dia:real val="1"/>
+        </dia:attribute>
+        <dia:attribute name="width_y">
+          <dia:real val="1"/>
+        </dia:attribute>
+        <dia:attribute name="visible_x">
+          <dia:int val="1"/>
+        </dia:attribute>
+        <dia:attribute name="visible_y">
+          <dia:int val="1"/>
+        </dia:attribute>
+        <dia:composite type="color"/>
+      </dia:composite>
+    </dia:attribute>
+    <dia:attribute name="color">
+      <dia:color val="#d8e5e5"/>
+    </dia:attribute>
+    <dia:attribute name="guides">
+      <dia:composite type="guides">
+        <dia:attribute name="hguides"/>
+        <dia:attribute name="vguides"/>
+      </dia:composite>
+    </dia:attribute>
+  </dia:diagramdata>
+  <dia:layer name="Background" visible="true" active="true">
+    <dia:object type="Standard - Box" version="0" id="O0">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-0.4,6.5"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-0.45,6.45;39.95,22.9"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-0.4,6.5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="40.299999999999997"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="16.349999999999998"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O1">
+      <dia:attribute name="obj_pos">
+        <dia:point val="0.225,9.45"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="0.175,9.4;8.225,14.7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="0.225,9.45"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7.9499999999999975"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="5.1999999999999975"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#a52a2a"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O2">
+      <dia:attribute name="obj_pos">
+        <dia:point val="2.475,10.2"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="2.425,10.15;7.225,14.1"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="2.475,10.2"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="4.6999999999999975"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.8499999999999979"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#0000ff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O3">
+      <dia:attribute name="obj_pos">
+        <dia:point val="3,11.2"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3,10.605;5.8775,12.9525"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#sink
+crop
+selection#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="3,11.2"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#0000ff"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O4">
+      <dia:attribute name="obj_pos">
+        <dia:point val="1.475,7.9"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="1.475,7.305;1.475,8.0525"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="1.475,7.9"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O5">
+      <dia:attribute name="obj_pos">
+        <dia:point val="0.426918,7.89569"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="0.426918,7.30069;3.90942,8.84819"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#sink media
+bus format#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="0.426918,7.89569"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#a52a2a"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O6">
+      <dia:attribute name="obj_pos">
+        <dia:point val="16.6822,9.28251"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="16.6322,9.23251;24.9922,17.9564"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="16.6822,9.28251"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="8.2600228398861297"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="8.6238900617957164"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#00ff00"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O7">
+      <dia:attribute name="obj_pos">
+        <dia:point val="16.6822,17.9064"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="2.41365,13.9886;16.7436,17.9678"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="16.6822,17.9064"/>
+        <dia:point val="2.475,14.05"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O6" connection="5"/>
+        <dia:connection handle="1" to="O2" connection="5"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O8">
+      <dia:attribute name="obj_pos">
+        <dia:point val="16.6822,9.28251"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="2.42188,9.22939;16.7353,10.2531"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="16.6822,9.28251"/>
+        <dia:point val="2.475,10.2"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O6" connection="0"/>
+        <dia:connection handle="1" to="O2" connection="0"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O9">
+      <dia:attribute name="obj_pos">
+        <dia:point val="24.9422,17.9064"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="7.11553,13.9905;25.0017,17.9659"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="24.9422,17.9064"/>
+        <dia:point val="7.175,14.05"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O6" connection="7"/>
+        <dia:connection handle="1" to="O2" connection="7"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O10">
+      <dia:attribute name="obj_pos">
+        <dia:point val="24.9422,9.28251"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="7.12249,9.23;24.9947,10.2525"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="24.9422,9.28251"/>
+        <dia:point val="7.175,10.2"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O6" connection="2"/>
+        <dia:connection handle="1" to="O2" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O11">
+      <dia:attribute name="obj_pos">
+        <dia:point val="16.7352,7.47209"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="16.7352,6.87709;22.5602,8.42459"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#sink compose
+selection (scaling)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="16.7352,7.47209"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#00ff00"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O12">
+      <dia:attribute name="obj_pos">
+        <dia:point val="19.1161,9.97825"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="19.0661,9.92825;24.1754,13.6009"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="19.1161,9.97825"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5.009308462554376"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.5726155970598077"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#a020f0"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O13">
+      <dia:attribute name="obj_pos">
+        <dia:point val="27.1661,7.47209"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="27.1661,6.87709;30.0436,9.22459"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#source
+crop
+selection#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="27.1661,7.47209"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#a020f0"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O14">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.575,7.8564"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="34.575,7.2614;38.8975,8.8089"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#source media
+bus format#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="34.575,7.8564"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#8b6914"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O15">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.5244,11.2917"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="34.4744,11.2417;39.5837,14.9143"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="34.5244,11.2917"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5.009308462554376"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.5726155970598077"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#8b6914"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O16">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.5244,14.8643"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="19.062,13.4968;34.5785,14.9184"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="34.5244,14.8643"/>
+        <dia:point val="19.1161,13.5509"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O15" connection="5"/>
+        <dia:connection handle="1" to="O12" connection="5"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O17">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.5244,11.2917"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="19.062,9.92418;34.5785,11.3458"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="34.5244,11.2917"/>
+        <dia:point val="19.1161,9.97825"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O15" connection="0"/>
+        <dia:connection handle="1" to="O12" connection="0"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O18">
+      <dia:attribute name="obj_pos">
+        <dia:point val="39.5337,14.8643"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="24.0713,13.4968;39.5878,14.9184"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="39.5337,14.8643"/>
+        <dia:point val="24.1254,13.5509"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O15" connection="7"/>
+        <dia:connection handle="1" to="O12" connection="7"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O19">
+      <dia:attribute name="obj_pos">
+        <dia:point val="39.5337,11.2917"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="24.0713,9.92418;39.5878,11.3458"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="39.5337,11.2917"/>
+        <dia:point val="24.1254,9.97825"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O15" connection="2"/>
+        <dia:connection handle="1" to="O12" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Geometric - Perfect Circle" version="1" id="O20">
+      <dia:attribute name="obj_pos">
+        <dia:point val="39.98,12.0742"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="39.93,12.0242;40.88,12.9742"/>
+      </dia:attribute>
+      <dia:attribute name="meta">
+        <dia:composite type="dict"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="39.98,12.0742"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="line_width">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="line_colour">
+        <dia:color val="#000000"/>
+      </dia:attribute>
+      <dia:attribute name="fill_colour">
+        <dia:color val="#ffffff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="0"/>
+        <dia:real val="1"/>
+      </dia:attribute>
+      <dia:attribute name="flip_horizontal">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="flip_vertical">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="subscale">
+        <dia:real val="1"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O21">
+      <dia:attribute name="obj_pos">
+        <dia:point val="40.83,12.4992"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="40.78,12.1388;49.2453,12.8624"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="40.83,12.4992"/>
+        <dia:point val="49.1335,12.5007"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O20" connection="3"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O22">
+      <dia:attribute name="obj_pos">
+        <dia:point val="42.0954,11.99"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="42.0954,11.395;46.7404,12.1425"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#pad 1 (source)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="42.0954,11.99"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Geometric - Perfect Circle" version="1" id="O23">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-1.44491,11.6506"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-1.49491,11.6006;-0.54491,12.5506"/>
+      </dia:attribute>
+      <dia:attribute name="meta">
+        <dia:composite type="dict"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-1.44491,11.6506"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="line_width">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="line_colour">
+        <dia:color val="#000000"/>
+      </dia:attribute>
+      <dia:attribute name="fill_colour">
+        <dia:color val="#ffffff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="0"/>
+        <dia:real val="1"/>
+      </dia:attribute>
+      <dia:attribute name="flip_horizontal">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="flip_vertical">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="subscale">
+        <dia:real val="1"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O24">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-9.61991,12.09"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-9.67,11.7149;-1.33311,12.4385"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="-9.61991,12.09"/>
+        <dia:point val="-1.44491,12.0756"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O23" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O25">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-7.39291,11.49"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-7.39291,10.895;-3.58791,11.6425"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#pad 0 (sink)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-7.39291,11.49"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O26">
+      <dia:attribute name="obj_pos">
+        <dia:point val="19.4911,13.8333"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="19.4411,13.7833;24.5504,17.4559"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="19.4911,13.8333"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5.009308462554376"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.5726155970598077"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#a020f0"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Box" version="0" id="O27">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.4994,17.2967"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="34.4494,17.2467;39.5587,20.9193"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="34.4994,17.2967"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5.009308462554376"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="3.5726155970598077"/>
+      </dia:attribute>
+      <dia:attribute name="border_width">
+        <dia:real val="0.10000000149011612"/>
+      </dia:attribute>
+      <dia:attribute name="border_color">
+        <dia:color val="#8b6914"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O28">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.4994,20.8693"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="19.4311,17.3459;34.5594,20.9293"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="34.4994,20.8693"/>
+        <dia:point val="19.4911,17.4059"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O27" connection="5"/>
+        <dia:connection handle="1" to="O26" connection="5"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O29">
+      <dia:attribute name="obj_pos">
+        <dia:point val="34.4994,17.2967"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="19.4311,13.7733;34.5594,17.3567"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="34.4994,17.2967"/>
+        <dia:point val="19.4911,13.8333"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O27" connection="0"/>
+        <dia:connection handle="1" to="O26" connection="0"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O30">
+      <dia:attribute name="obj_pos">
+        <dia:point val="39.5087,20.8693"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="24.4404,17.3459;39.5687,20.9293"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="39.5087,20.8693"/>
+        <dia:point val="24.5004,17.4059"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O27" connection="7"/>
+        <dia:connection handle="1" to="O26" connection="7"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O31">
+      <dia:attribute name="obj_pos">
+        <dia:point val="39.5087,17.2967"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="24.4404,13.7733;39.5687,17.3567"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="39.5087,17.2967"/>
+        <dia:point val="24.5004,13.8333"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#e60505"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="4"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O27" connection="2"/>
+        <dia:connection handle="1" to="O26" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Geometric - Perfect Circle" version="1" id="O32">
+      <dia:attribute name="obj_pos">
+        <dia:point val="39.855,18.7792"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="39.805,18.7292;40.755,19.6792"/>
+      </dia:attribute>
+      <dia:attribute name="meta">
+        <dia:composite type="dict"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="39.855,18.7792"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="0.84999999999999787"/>
+      </dia:attribute>
+      <dia:attribute name="line_width">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="line_colour">
+        <dia:color val="#000000"/>
+      </dia:attribute>
+      <dia:attribute name="fill_colour">
+        <dia:color val="#ffffff"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="line_style">
+        <dia:enum val="0"/>
+        <dia:real val="1"/>
+      </dia:attribute>
+      <dia:attribute name="flip_horizontal">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="flip_vertical">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="subscale">
+        <dia:real val="1"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O33">
+      <dia:attribute name="obj_pos">
+        <dia:point val="40.705,19.2042"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="40.655,18.8438;49.1203,19.5674"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="40.705,19.2042"/>
+        <dia:point val="49.0085,19.2057"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O32" connection="3"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Text" version="1" id="O34">
+      <dia:attribute name="obj_pos">
+        <dia:point val="41.9704,18.695"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="41.9704,18.1;46.6154,18.8475"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#pad 2 (source)#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="0.80000000000000004"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="41.9704,18.695"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+      <dia:attribute name="valign">
+        <dia:enum val="3"/>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O35">
+      <dia:attribute name="obj_pos">
+        <dia:point val="27.3,9.55"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="24.0146,9.49376;27.3562,10.255"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="27.3,9.55"/>
+        <dia:point val="24.1254,9.97825"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#a020f0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O12" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - Line" version="0" id="O36">
+      <dia:attribute name="obj_pos">
+        <dia:point val="27.3454,9.53624"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="24.4311,9.46695;27.4147,13.9265"/>
+      </dia:attribute>
+      <dia:attribute name="conn_endpoints">
+        <dia:point val="27.3454,9.53624"/>
+        <dia:point val="24.5004,13.8333"/>
+      </dia:attribute>
+      <dia:attribute name="numcp">
+        <dia:int val="1"/>
+      </dia:attribute>
+      <dia:attribute name="line_color">
+        <dia:color val="#a020f0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="1" to="O26" connection="2"/>
+      </dia:connections>
+    </dia:object>
+  </dia:layer>
+</dia:diagram>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg
new file mode 100644
index 0000000..2340c0f
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="59cm" height="17cm" viewBox="-194 128 1179 330" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="-8" y="130" width="806" height="327"/>
+  <g>
+    <rect style="fill: #ffffff" x="4.5" y="189" width="159" height="104"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="4.5" y="189" width="159" height="104"/>
+  </g>
+  <g>
+    <rect style="fill: #ffffff" x="49.5" y="204" width="94" height="77"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="49.5" y="204" width="94" height="77"/>
+  </g>
+  <text style="fill: #0000ff;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="60" y="224">
+    <tspan x="60" y="224">sink</tspan>
+    <tspan x="60" y="240">crop</tspan>
+    <tspan x="60" y="256">selection</tspan>
+  </text>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="29.5" y="158">
+    <tspan x="29.5" y="158"></tspan>
+  </text>
+  <text style="fill: #a52a2a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="8.53836" y="157.914">
+    <tspan x="8.53836" y="157.914">sink media</tspan>
+    <tspan x="8.53836" y="173.914">bus format</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="333.644" y="185.65" width="165.2" height="172.478"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #00ff00" x="333.644" y="185.65" width="165.2" height="172.478"/>
+  </g>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="358.128" x2="49.5" y2="281"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="185.65" x2="49.5" y2="204"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="358.128" x2="143.5" y2="281"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="185.65" x2="143.5" y2="204"/>
+  <text style="fill: #00ff00;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="334.704" y="149.442">
+    <tspan x="334.704" y="149.442">sink compose</tspan>
+    <tspan x="334.704" y="165.442">selection (scaling)</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="382.322" y="199.565" width="100.186" height="71.4523"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="382.322" y="199.565" width="100.186" height="71.4523"/>
+  </g>
+  <text style="fill: #a020f0;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="543.322" y="149.442">
+    <tspan x="543.322" y="149.442">source</tspan>
+    <tspan x="543.322" y="165.442">crop</tspan>
+    <tspan x="543.322" y="181.442">selection</tspan>
+  </text>
+  <text style="fill: #8b6914;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="691.5" y="157.128">
+    <tspan x="691.5" y="157.128">source media</tspan>
+    <tspan x="691.5" y="173.128">bus format</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="690.488" y="225.834" width="100.186" height="71.4523"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="690.488" y="225.834" width="100.186" height="71.4523"/>
+  </g>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="690.488" y1="297.286" x2="382.322" y2="271.018"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="690.488" y1="225.834" x2="382.322" y2="199.565"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.674" y1="297.286" x2="482.508" y2="271.018"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.674" y1="225.834" x2="482.508" y2="199.565"/>
+  <g>
+    <ellipse style="fill: #ffffff" cx="808.1" cy="249.984" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="808.1" cy="249.984" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="808.1" cy="249.984" rx="8.5" ry="8.5"/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="816.6" y1="249.984" x2="972.934" y2="250.012"/>
+    <polygon style="fill: #000000" points="980.434,250.014 970.433,255.012 972.934,250.012 970.435,245.012 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="980.434,250.014 970.433,255.012 972.934,250.012 970.435,245.012 "/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="841.908" y="239.8">
+    <tspan x="841.908" y="239.8">pad 1 (source)</tspan>
+  </text>
+  <g>
+    <ellipse style="fill: #ffffff" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-192.398" y1="241.8" x2="-38.6343" y2="241.529"/>
+    <polygon style="fill: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-147.858" y="229.8">
+    <tspan x="-147.858" y="229.8">pad 0 (sink)</tspan>
+  </text>
+  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="389.822" y="276.666" width="100.186" height="71.4523"/>
+  <g>
+    <rect style="fill: #ffffff" x="689.988" y="345.934" width="100.186" height="71.4523"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="689.988" y="345.934" width="100.186" height="71.4523"/>
+  </g>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="689.988" y1="417.386" x2="389.822" y2="348.118"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="689.988" y1="345.934" x2="389.822" y2="276.666"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.174" y1="417.386" x2="490.008" y2="348.118"/>
+  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.174" y1="345.934" x2="490.008" y2="276.666"/>
+  <g>
+    <ellipse style="fill: #ffffff" cx="805.6" cy="384.084" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="805.6" cy="384.084" rx="8.5" ry="8.5"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="805.6" cy="384.084" rx="8.5" ry="8.5"/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="814.1" y1="384.084" x2="970.434" y2="384.112"/>
+    <polygon style="fill: #000000" points="977.934,384.114 967.933,389.112 970.434,384.112 967.935,379.112 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="977.934,384.114 967.933,389.112 970.434,384.112 967.935,379.112 "/>
+  </g>
+  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="839.408" y="373.9">
+    <tspan x="839.408" y="373.9">pad 2 (source)</tspan>
+  </text>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="546" y1="191" x2="492.157" y2="198.263"/>
+    <polygon style="fill: #a020f0" points="484.724,199.266 493.966,192.974 492.157,198.263 495.303,202.884 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="484.724,199.266 493.966,192.974 492.157,198.263 495.303,202.884 "/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="546.908" y1="190.725" x2="495.383" y2="268.548"/>
+    <polygon style="fill: #a020f0" points="491.242,274.802 492.594,263.703 495.383,268.548 500.932,269.224 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="491.242,274.802 492.594,263.703 495.383,268.548 500.932,269.224 "/>
+  </g>
+</svg>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index 8ae3887..015c561 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -28,8 +28,8 @@
 	<firstname>Hans</firstname>
 	<surname>Verkuil</surname>
 	<contrib>Designed and documented the VIDIOC_LOG_STATUS ioctl,
-the extended control ioctls and major parts of the sliced VBI
-API.</contrib>
+the extended control ioctls, major parts of the sliced VBI API, the
+MPEG encoder and decoder APIs and the DV Timings API.</contrib>
 	<affiliation>
 	  <address>
 	    <email>hverkuil@xs4all.nl</email>
@@ -96,6 +96,17 @@
 	  </address>
 	</affiliation>
       </author>
+
+      <author>
+	<firstname>Sakari</firstname>
+	<surname>Ailus</surname>
+	<contrib>Subdev selections API.</contrib>
+	<affiliation>
+	  <address>
+	    <email>sakari.ailus@iki.fi</email>
+	  </address>
+	</affiliation>
+      </author>
     </authorgroup>
 
     <copyright>
@@ -112,6 +123,7 @@
       <year>2009</year>
       <year>2010</year>
       <year>2011</year>
+      <year>2012</year>
       <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
 Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
 	Pawel Osciak</holder>
@@ -128,6 +140,28 @@
 applications. -->
 
       <revision>
+	<revnumber>3.5</revnumber>
+	<date>2012-05-07</date>
+	<authorinitials>sa, sn</authorinitials>
+	<revremark>Added V4L2_CTRL_TYPE_INTEGER_MENU and V4L2 subdev
+	    selections API. Improved the description of V4L2_CID_COLORFX
+	    control, added V4L2_CID_COLORFX_CBCR control.
+	    Added camera controls V4L2_CID_AUTO_EXPOSURE_BIAS,
+	    V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, V4L2_CID_IMAGE_STABILIZATION,
+	    V4L2_CID_ISO_SENSITIVITY, V4L2_CID_ISO_SENSITIVITY_AUTO,
+	    V4L2_CID_EXPOSURE_METERING, V4L2_CID_SCENE_MODE,
+	    V4L2_CID_3A_LOCK, V4L2_CID_AUTO_FOCUS_START,
+	    V4L2_CID_AUTO_FOCUS_STOP, V4L2_CID_AUTO_FOCUS_STATUS
+	    and V4L2_CID_AUTO_FOCUS_RANGE.
+	</revremark>
+	<date>2012-05-01</date>
+	<authorinitials>hv</authorinitials>
+	<revremark>Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and
+	VIDIOC_DV_TIMINGS_CAP.
+	</revremark>
+      </revision>
+
+      <revision>
 	<revnumber>3.4</revnumber>
 	<date>2012-01-25</date>
 	<authorinitials>sn</authorinitials>
@@ -433,7 +467,7 @@
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.3</subtitle>
+ <subtitle>Revision 3.5</subtitle>
 
   <chapter id="common">
     &sub-common;
@@ -491,10 +525,12 @@
     &sub-dbg-g-register;
     &sub-decoder-cmd;
     &sub-dqevent;
+    &sub-dv-timings-cap;
     &sub-encoder-cmd;
     &sub-enumaudio;
     &sub-enumaudioout;
     &sub-enum-dv-presets;
+    &sub-enum-dv-timings;
     &sub-enum-fmt;
     &sub-enum-framesizes;
     &sub-enum-frameintervals;
@@ -529,6 +565,7 @@
     &sub-querycap;
     &sub-queryctrl;
     &sub-query-dv-preset;
+    &sub-query-dv-timings;
     &sub-querystd;
     &sub-prepare-buf;
     &sub-reqbufs;
@@ -540,6 +577,7 @@
     &sub-subdev-g-crop;
     &sub-subdev-g-fmt;
     &sub-subdev-g-frame-interval;
+    &sub-subdev-g-selection;
     &sub-subscribe-event;
     <!-- End of ioctls. -->
     &sub-mmap;
diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
index 73ae8a6..765549f 100644
--- a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
@@ -48,6 +48,12 @@
   <refsect1>
     <title>Description</title>
 
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental"> experimental </link>
+      interface and may change in the future.</para>
+    </note>
+
     <para>This ioctl is used to create buffers for <link linkend="mmap">memory
 mapped</link> or <link linkend="userp">user pointer</link>
 I/O. It can be used as an alternative or in addition to the
@@ -94,16 +100,18 @@
 	    <entry>The number of buffers requested or granted.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-memory;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>memory</structfield></entry>
 	    <entry>Applications set this field to
 <constant>V4L2_MEMORY_MMAP</constant> or
-<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
+<constant>V4L2_MEMORY_USERPTR</constant>. See <xref linkend="v4l2-memory"
+/></entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-format;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>format</structfield></entry>
-	    <entry>Filled in by the application, preserved by the driver.</entry>
+	    <entry>Filled in by the application, preserved by the driver.
+	    See <xref linkend="v4l2-format" />.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml
index b4f2f25..f1bac2c 100644
--- a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml
@@ -65,7 +65,7 @@
 	&cs-str;
 	<tbody valign="top">
 	  <row>
-	    <entry>&v4l2-buf-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry>Type of the data stream, set by the application.
 Only these types are valid here:
@@ -73,7 +73,7 @@
 <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
 <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
 defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
-and higher.</entry>
+and higher. See <xref linkend="v4l2-buf-type" />.</entry>
 	  </row>
 	  <row>
 	    <entry>struct <link linkend="v4l2-rect-crop">v4l2_rect</link></entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml
new file mode 100644
index 0000000..6673ce5
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml
@@ -0,0 +1,211 @@
+<refentry id="vidioc-dv-timings-cap">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_DV_TIMINGS_CAP</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_DV_TIMINGS_CAP</refname>
+    <refpurpose>The capabilities of the Digital Video receiver/transmitter</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_dv_timings_cap *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_DV_TIMINGS_CAP</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental"> experimental </link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>To query the available timings, applications initialize the
+<structfield>index</structfield> field and zero the reserved array of &v4l2-dv-timings-cap;
+and call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all supported DV timings,
+applications shall begin at index zero, incrementing by one until the
+driver returns <errorcode>EINVAL</errorcode>. Note that drivers may enumerate a
+different set of DV timings after switching the video input or
+output.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-bt-timings-cap">
+      <title>struct <structname>v4l2_bt_timings_cap</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>min_width</structfield></entry>
+	    <entry>Minimum width of the active video in pixels.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>max_width</structfield></entry>
+	    <entry>Maximum width of the active video in pixels.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>min_height</structfield></entry>
+	    <entry>Minimum height of the active video in lines.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>max_height</structfield></entry>
+	    <entry>Maximum height of the active video in lines.</entry>
+	  </row>
+	  <row>
+	    <entry>__u64</entry>
+	    <entry><structfield>min_pixelclock</structfield></entry>
+	    <entry>Minimum pixelclock frequency in Hz.</entry>
+	  </row>
+	  <row>
+	    <entry>__u64</entry>
+	    <entry><structfield>max_pixelclock</structfield></entry>
+	    <entry>Maximum pixelclock frequency in Hz.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>standards</structfield></entry>
+	    <entry>The video standard(s) supported by the hardware.
+	    See <xref linkend="dv-bt-standards"/> for a list of standards.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>capabilities</structfield></entry>
+	    <entry>Several flags giving more information about the capabilities.
+	    See <xref linkend="dv-bt-cap-capabilities"/> for a description of the flags.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[16]</entry>
+	    <entry></entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-dv-timings-cap">
+      <title>struct <structname>v4l2_dv_timings_cap</structname></title>
+      <tgroup cols="4">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>type</structfield></entry>
+	    <entry>Type of DV timings as listed in <xref linkend="dv-timing-types"/>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[3]</entry>
+	    <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
+	  </row>
+	  <row>
+	    <entry>union</entry>
+	    <entry><structfield></structfield></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>&v4l2-bt-timings-cap;</entry>
+	    <entry><structfield>bt</structfield></entry>
+	    <entry>BT.656/1120 timings capabilities of the hardware.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>__u32</entry>
+	    <entry><structfield>raw_data</structfield>[32]</entry>
+	    <entry></entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="dv-bt-cap-capabilities">
+      <title>DV BT Timing capabilities</title>
+      <tgroup cols="2">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>Flag</entry>
+	    <entry>Description</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_BT_CAP_INTERLACED</entry>
+	    <entry>Interlaced formats are supported.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_BT_CAP_PROGRESSIVE</entry>
+	    <entry>Progressive formats are supported.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_BT_CAP_REDUCED_BLANKING</entry>
+	    <entry>CVT/GTF specific: the timings can make use of reduced blanking (CVT)
+or the 'Secondary GTF' curve (GTF).
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_BT_CAP_CUSTOM</entry>
+	    <entry>Can support non-standard timings, i.e. timings not belonging to the
+standards set in the <structfield>standards</structfield> field.
+	    </entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
index 0be17c2..509f001 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
@@ -48,6 +48,10 @@
   <refsect1>
     <title>Description</title>
 
+    <para>This ioctl is <emphasis role="bold">deprecated</emphasis>.
+    New drivers and applications should use &VIDIOC-ENUM-DV-TIMINGS; instead.
+    </para>
+
     <para>To query the attributes of a DV preset, applications initialize the
 <structfield>index</structfield> field and zero the reserved array of &v4l2-dv-enum-preset;
 and call the <constant>VIDIOC_ENUM_DV_PRESETS</constant> ioctl with a pointer to this
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml
new file mode 100644
index 0000000..24c3bf4
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml
@@ -0,0 +1,119 @@
+<refentry id="vidioc-enum-dv-timings">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUM_DV_TIMINGS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUM_DV_TIMINGS</refname>
+    <refpurpose>Enumerate supported Digital Video timings</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_enum_dv_timings *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_ENUM_DV_TIMINGS</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental"> experimental </link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>While some DV receivers or transmitters support a wide range of timings, others
+support only a limited number of timings. With this ioctl applications can enumerate a list
+of known supported timings. Call &VIDIOC-DV-TIMINGS-CAP; to check if it also supports other
+standards or even custom timings that are not in this list.</para>
+
+    <para>To query the available timings, applications initialize the
+<structfield>index</structfield> field and zero the reserved array of &v4l2-enum-dv-timings;
+and call the <constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all supported DV timings,
+applications shall begin at index zero, incrementing by one until the
+driver returns <errorcode>EINVAL</errorcode>. Note that drivers may enumerate a
+different set of DV timings after switching the video input or
+output.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-enum-dv-timings">
+      <title>struct <structname>v4l2_enum_dv_timings</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>index</structfield></entry>
+	    <entry>Number of the DV timings, set by the
+application.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[3]</entry>
+	    <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
+	  </row>
+	  <row>
+	    <entry>&v4l2-dv-timings;</entry>
+	    <entry><structfield>timings</structfield></entry>
+	    <entry>The timings.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>The &v4l2-enum-dv-timings; <structfield>index</structfield>
+is out of bounds.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml
index 347d142..81ebe48 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml
@@ -71,7 +71,7 @@
 pixelformat</structfield> field.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-buf-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry>Type of the data stream, set by the application.
 Only these types are valid here:
@@ -81,7 +81,7 @@
 <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>,
 <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
 defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
-and higher.</entry>
+and higher. See <xref linkend="v4l2-buf-type" />.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
index 9b8efcd..46d5a04 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
@@ -285,7 +285,7 @@
 	  <row>
 	    <entry><constant>V4L2_IN_CAP_CUSTOM_TIMINGS</constant></entry>
 	    <entry>0x00000002</entry>
-	    <entry>This input supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
+	    <entry>This input supports setting video timings by using VIDIOC_S_DV_TIMINGS.</entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_IN_CAP_STD</constant></entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
index a64d5ef..4280200 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
@@ -170,7 +170,7 @@
 	  <row>
 	    <entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry>
 	    <entry>0x00000002</entry>
-	    <entry>This output supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
+	    <entry>This output supports setting video timings by using VIDIOC_S_DV_TIMINGS.</entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_OUT_CAP_STD</constant></entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml
index 01a50640..c4ff3b1 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-crop.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml
@@ -100,14 +100,14 @@
 	&cs-str;
 	<tbody valign="top">
 	  <row>
-	    <entry>&v4l2-buf-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry>Type of the data stream, set by the application.
 Only these types are valid here: <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
 <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
 <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
 defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
-and higher.</entry>
+and higher. See <xref linkend="v4l2-buf-type" />.</entry>
 	  </row>
 	  <row>
 	    <entry>&v4l2-rect;</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml
index 7940c11..61be9fa 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml
@@ -48,6 +48,12 @@
 
   <refsect1>
     <title>Description</title>
+
+    <para>These ioctls are <emphasis role="bold">deprecated</emphasis>.
+    New drivers and applications should use &VIDIOC-G-DV-TIMINGS; and &VIDIOC-S-DV-TIMINGS;
+    instead.
+    </para>
+
     <para>To query and select the current DV preset, applications
 use the <constant>VIDIOC_G_DV_PRESET</constant> and <constant>VIDIOC_S_DV_PRESET</constant>
 ioctls which take a pointer to a &v4l2-dv-preset; type as argument.
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
index 4a8648a..eda1a29 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
@@ -7,7 +7,7 @@
   <refnamediv>
     <refname>VIDIOC_G_DV_TIMINGS</refname>
     <refname>VIDIOC_S_DV_TIMINGS</refname>
-    <refpurpose>Get or set custom DV timings for input or output</refpurpose>
+    <refpurpose>Get or set DV timings for input or output</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
@@ -48,12 +48,15 @@
 
   <refsect1>
     <title>Description</title>
-    <para>To set custom DV timings for the input or output, applications use the
-<constant>VIDIOC_S_DV_TIMINGS</constant> ioctl and to get the current custom timings,
+    <para>To set DV timings for the input or output, applications use the
+<constant>VIDIOC_S_DV_TIMINGS</constant> ioctl and to get the current timings,
 applications use the <constant>VIDIOC_G_DV_TIMINGS</constant> ioctl. The detailed timing
 information is filled in using the structure &v4l2-dv-timings;. These ioctls take
 a pointer to the &v4l2-dv-timings; structure as argument. If the ioctl is not supported
 or the timing values are not correct, the driver returns &EINVAL;.</para>
+<para>The <filename>linux/v4l2-dv-timings.h</filename> header can be used to get the
+timings of the formats in the <xref linkend="cea861" /> and <xref linkend="vesadmt" />
+standards.</para>
   </refsect1>
 
   <refsect1>
@@ -83,12 +86,13 @@
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>width</structfield></entry>
-	    <entry>Width of the active video in pixels</entry>
+	    <entry>Width of the active video in pixels.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>height</structfield></entry>
-	    <entry>Height of the active video in lines</entry>
+	    <entry>Height of the active video frame in lines. So for interlaced formats the
+	    height of the active video in each field is <structfield>height</structfield>/2.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
@@ -125,32 +129,52 @@
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>vfrontporch</structfield></entry>
-	    <entry>Vertical front porch in lines</entry>
+	    <entry>Vertical front porch in lines. For interlaced formats this refers to the
+	    odd field (aka field 1).</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>vsync</structfield></entry>
-	    <entry>Vertical sync length in lines</entry>
+	    <entry>Vertical sync length in lines. For interlaced formats this refers to the
+	    odd field (aka field 1).</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>vbackporch</structfield></entry>
-	    <entry>Vertical back porch in lines</entry>
+	    <entry>Vertical back porch in lines. For interlaced formats this refers to the
+	    odd field (aka field 1).</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>il_vfrontporch</structfield></entry>
-	    <entry>Vertical front porch in lines for bottom field of interlaced field formats</entry>
+	    <entry>Vertical front porch in lines for the even field (aka field 2) of
+	    interlaced field formats.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>il_vsync</structfield></entry>
-	    <entry>Vertical sync length in lines for bottom field of interlaced field formats</entry>
+	    <entry>Vertical sync length in lines for the even field (aka field 2) of
+	    interlaced field formats.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>il_vbackporch</structfield></entry>
-	    <entry>Vertical back porch in lines for bottom field of interlaced field formats</entry>
+	    <entry>Vertical back porch in lines for the even field (aka field 2) of
+	    interlaced field formats.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>standards</structfield></entry>
+	    <entry>The video standard(s) this format belongs to. This will be filled in by
+	    the driver. Applications must set this to 0. See <xref linkend="dv-bt-standards"/>
+	    for a list of standards.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>flags</structfield></entry>
+	    <entry>Several flags giving more information about the format.
+	    See <xref linkend="dv-bt-flags"/> for a description of the flags.
+	    </entry>
 	  </row>
 	</tbody>
       </tgroup>
@@ -211,6 +235,90 @@
 	</tbody>
       </tgroup>
     </table>
+    <table pgwide="1" frame="none" id="dv-bt-standards">
+      <title>DV BT Timing standards</title>
+      <tgroup cols="2">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>Timing standard</entry>
+	    <entry>Description</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_BT_STD_CEA861</entry>
+	    <entry>The timings follow the CEA-861 Digital TV Profile standard</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_BT_STD_DMT</entry>
+	    <entry>The timings follow the VESA Discrete Monitor Timings standard</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_BT_STD_CVT</entry>
+	    <entry>The timings follow the VESA Coordinated Video Timings standard</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_BT_STD_GTF</entry>
+	    <entry>The timings follow the VESA Generalized Timings Formula standard</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+    <table pgwide="1" frame="none" id="dv-bt-flags">
+      <title>DV BT Timing flags</title>
+      <tgroup cols="2">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>Flag</entry>
+	    <entry>Description</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_FL_REDUCED_BLANKING</entry>
+	    <entry>CVT/GTF specific: the timings use reduced blanking (CVT) or the 'Secondary
+GTF' curve (GTF). In both cases the horizontal and/or vertical blanking
+intervals are reduced, allowing a higher resolution over the same
+bandwidth. This is a read-only flag, applications must not set this.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_FL_CAN_REDUCE_FPS</entry>
+	    <entry>CEA-861 specific: set for CEA-861 formats with a framerate that is a multiple
+of six. These formats can be optionally played at 1 / 1.001 speed to
+be compatible with 60 Hz based standards such as NTSC and PAL-M that use a framerate of
+29.97 frames per second. If the transmitter can't generate such frequencies, then the
+flag will also be cleared. This is a read-only flag, applications must not set this.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_FL_REDUCED_FPS</entry>
+	    <entry>CEA-861 specific: only valid for video transmitters, the flag is cleared
+by receivers. It is also only valid for formats with the V4L2_DV_FL_CAN_REDUCE_FPS flag
+set, for other formats the flag will be cleared by the driver.
+
+If the application sets this flag, then the pixelclock used to set up the transmitter is
+divided by 1.001 to make it compatible with NTSC framerates. If the transmitter
+can't generate such frequencies, then the flag will also be cleared.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_FL_HALF_LINE</entry>
+	    <entry>Specific to interlaced formats: if set, then field 1 (aka the odd field)
+is really one half-line longer and field 2 (aka the even field) is really one half-line
+shorter, so each field has exactly the same number of half-lines. Whether half-lines can be
+detected or used depends on the hardware.
+	    </entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
   </refsect1>
   <refsect1>
     &return-value;
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index b17a7aa..e3d5afcd 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -265,6 +265,32 @@
 These controls are described in <xref
 		linkend="flash-controls" />.</entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_CLASS_JPEG</constant></entry>
+	    <entry>0x9d0000</entry>
+	    <entry>The class containing JPEG compression controls.
+These controls are described in <xref
+		linkend="jpeg-controls" />.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_CLASS_IMAGE_SOURCE</constant></entry>
+	    <entry>0x9e0000</entry> <entry>The class containing image
+	    source controls. These controls are described in <xref
+	    linkend="image-source-controls" />.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_CLASS_IMAGE_PROC</constant></entry>
+	    <entry>0x9f0000</entry> <entry>The class containing image
+	    processing controls. These controls are described in <xref
+	    linkend="image-process-controls" />.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_CLASS_JPEG</constant></entry>
+	    <entry>0x9d0000</entry>
+	    <entry>The class containing JPEG compression controls.
+These controls are described in <xref
+		linkend="jpeg-controls" />.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
index 17fbda1..52acff1 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
@@ -116,7 +116,7 @@
 	<colspec colname="c4" />
 	<tbody valign="top">
 	  <row>
-	    <entry>&v4l2-buf-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry></entry>
 	    <entry>Type of the data stream, see <xref
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
index 66e9a52..69c178a 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
@@ -95,14 +95,14 @@
 &v4l2-modulator; <structfield>index</structfield> field.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-tuner-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field. The type must be set
+&v4l2-tuner; <structfield>type</structfield> field. See The type must be set
 to <constant>V4L2_TUNER_RADIO</constant> for <filename>/dev/radioX</filename>
 device nodes, and to <constant>V4L2_TUNER_ANALOG_TV</constant>
 for all others. The field is not applicable to modulators, &ie; ignored
-by drivers.</entry>
+by drivers. See <xref linkend="v4l2-tuner-type" /></entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-parm.xml b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml
index 19b1d85..f83d2cd 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-parm.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml
@@ -75,11 +75,12 @@
 	&cs-ustr;
 	<tbody valign="top">
 	  <row>
-	    <entry>&v4l2-buf-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry></entry>
 	    <entry>The buffer (stream) type, same as &v4l2-format;
-<structfield>type</structfield>, set by the application.</entry>
+<structfield>type</structfield>, set by the application. See <xref
+	    linkend="v4l2-buf-type" /></entry>
 	  </row>
 	  <row>
 	    <entry>union</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml
index 71741da..bd015d1 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml
@@ -148,7 +148,7 @@
 <structfield>service_lines</structfield>[1][0] to zero.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-buf-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry>Type of the data stream, see <xref
 		  linkend="v4l2-buf-type" />. Should be
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
index 91ec2fb..62a1aa2 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
@@ -107,7 +107,7 @@
 field is not quite clear.--></para></entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-tuner-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry spanname="hspan">Type of the tuner, see <xref
 		linkend="v4l2-tuner-type" />.</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
index 7bde698..fa7ad7e 100644
--- a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
@@ -48,6 +48,12 @@
   <refsect1>
     <title>Description</title>
 
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental"> experimental </link>
+      interface and may change in the future.</para>
+    </note>
+
     <para>Applications can optionally call the
 <constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
 to the driver before actually enqueuing it, using the
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml
index 23b17f6..1bc8aeb 100644
--- a/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml
@@ -49,6 +49,10 @@
   <refsect1>
     <title>Description</title>
 
+    <para>This ioctl is <emphasis role="bold">deprecated</emphasis>.
+    New drivers and applications should use &VIDIOC-QUERY-DV-TIMINGS; instead.
+    </para>
+
     <para>The hardware may be able to detect the current DV preset
 automatically, similar to sensing the video standard. To do so, applications
 call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
new file mode 100644
index 0000000..44935a0
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
@@ -0,0 +1,104 @@
+<refentry id="vidioc-query-dv-timings">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_QUERY_DV_TIMINGS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_QUERY_DV_TIMINGS</refname>
+    <refpurpose>Sense the DV preset received by the current
+input</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_dv_timings *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+	<varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_QUERY_DV_TIMINGS</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental"> experimental </link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>The hardware may be able to detect the current DV timings
+automatically, similar to sensing the video standard. To do so, applications
+call <constant>VIDIOC_QUERY_DV_TIMINGS</constant> with a pointer to a
+&v4l2-dv-timings;. Once the hardware detects the timings, it will fill in the
+timings structure.
+
+If the timings could not be detected because there was no signal, then
+<errorcode>ENOLINK</errorcode> is returned. If a signal was detected, but
+it was unstable and the receiver could not lock to the signal, then
+<errorcode>ENOLCK</errorcode> is returned. If the receiver could lock to the signal,
+but the format is unsupported (e.g. because the pixelclock is out of range
+of the hardware capabilities), then the driver fills in whatever timings it
+could find and returns <errorcode>ERANGE</errorcode>. In that case the application
+can call &VIDIOC-DV-TIMINGS-CAP; to compare the found timings with the hardware's
+capabilities in order to give more precise feedback to the user.
+</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>ENOLINK</errorcode></term>
+	<listitem>
+	  <para>No timings could be detected because no signal was found.
+</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>ENOLCK</errorcode></term>
+	<listitem>
+	  <para>The signal was unstable and the hardware could not lock on to it.
+</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>ERANGE</errorcode></term>
+	<listitem>
+	  <para>Timings were found, but they are out of range of the hardware
+capabilities.
+</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
index 36660d3..e6645b9 100644
--- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
@@ -127,7 +127,7 @@
 flag yet always return an &EINVAL;.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-ctrl-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry>Type of control, see <xref
 		linkend="v4l2-ctrl-type" />.</entry>
@@ -215,11 +215,12 @@
 
     <table pgwide="1" frame="none" id="v4l2-querymenu">
       <title>struct <structname>v4l2_querymenu</structname></title>
-      <tgroup cols="3">
+      <tgroup cols="4">
 	&cs-str;
 	<tbody valign="top">
 	  <row>
 	    <entry>__u32</entry>
+	    <entry></entry>
 	    <entry><structfield>id</structfield></entry>
 	    <entry>Identifies the control, set by the application
 from the respective &v4l2-queryctrl;
@@ -227,18 +228,38 @@
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
+	    <entry></entry>
 	    <entry><structfield>index</structfield></entry>
 	    <entry>Index of the menu item, starting at zero, set by
 	    the application.</entry>
 	  </row>
 	  <row>
+	    <entry>union</entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry></entry>
 	    <entry>__u8</entry>
 	    <entry><structfield>name</structfield>[32]</entry>
 	    <entry>Name of the menu item, a NUL-terminated ASCII
-string. This information is intended for the user.</entry>
+string. This information is intended for the user. This field is valid
+for <constant>V4L2_CTRL_FLAG_MENU</constant> type controls.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>__s64</entry>
+	    <entry><structfield>value</structfield></entry>
+	    <entry>
+              Value of the integer menu item. This field is valid for
+              <constant>V4L2_CTRL_FLAG_INTEGER_MENU</constant> type
+              controls.
+            </entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
+	    <entry></entry>
 	    <entry><structfield>reserved</structfield></entry>
 	    <entry>Reserved for future extensions. Drivers must set
 the array to zero.</entry>
@@ -292,6 +313,20 @@
 <constant>VIDIOC_QUERYMENU</constant> ioctl.</entry>
 	  </row>
 	  <row>
+	    <entry><constant>V4L2_CTRL_TYPE_INTEGER_MENU</constant></entry>
+	    <entry>&ge; 0</entry>
+	    <entry>1</entry>
+	    <entry>N-1</entry>
+	    <entry>
+              The control has a menu of N choices. The values of the
+              menu items can be enumerated with the
+              <constant>VIDIOC_QUERYMENU</constant> ioctl. This is
+              similar to <constant>V4L2_CTRL_TYPE_MENU</constant>
+              except that instead of strings, the menu items are
+              signed 64-bit integers.
+            </entry>
+	  </row>
+	  <row>
 	    <entry><constant>V4L2_CTRL_TYPE_BITMASK</constant></entry>
 	    <entry>0</entry>
 	    <entry>n/a</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
index 7be4b1d..d7c9505 100644
--- a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
@@ -92,18 +92,19 @@
 	    <entry>The number of buffers requested or granted.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-buf-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry>Type of the stream or buffers, this is the same
 as the &v4l2-format; <structfield>type</structfield> field. See <xref
 		linkend="v4l2-buf-type" /> for valid values.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-memory;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>memory</structfield></entry>
 	    <entry>Applications set this field to
 <constant>V4L2_MEMORY_MMAP</constant> or
-<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
+<constant>V4L2_MEMORY_USERPTR</constant>. See <xref linkend="v4l2-memory"
+/>.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
index 18b1a82..407dfce 100644
--- a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
@@ -73,10 +73,11 @@
 field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-tuner-type;</entry>
+	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
 	    <entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field.</entry>
+&v4l2-tuner; <structfield>type</structfield> field. See <xref
+	    linkend="v4l2-tuner-type" /></entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml
index 0619732..4cddd78 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml
@@ -58,9 +58,12 @@
     <title>Description</title>
 
     <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
+      <title>Obsolete</title>
+
+      <para>This is an <link linkend="obsolete">obsolete</link>
+      interface and may be removed in the future. It is superseded by
+      <link linkend="vidioc-subdev-g-selection">the selection
+      API</link>.</para>
     </note>
 
     <para>To retrieve the current crop rectangle applications set the
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
new file mode 100644
index 0000000..208e9f0
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
@@ -0,0 +1,228 @@
+<refentry id="vidioc-subdev-g-selection">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_G_SELECTION, VIDIOC_SUBDEV_S_SELECTION</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_G_SELECTION</refname>
+    <refname>VIDIOC_SUBDEV_S_SELECTION</refname>
+    <refpurpose>Get or set selection rectangles on a subdev pad</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_subdev_selection *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_SUBDEV_G_SELECTION, VIDIOC_SUBDEV_S_SELECTION</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>The selections are used to configure various image
+    processing functionality performed by the subdevs which affect the
+    image size. This currently includes cropping, scaling and
+    composition.</para>
+
+    <para>The selection API replaces <link
+    linkend="vidioc-subdev-g-crop">the old subdev crop API</link>. All
+    the function of the crop API, and more, are supported by the
+    selections API.</para>
+
+    <para>See <xref linkend="subdev"></xref> for
+    more information on how each selection target affects the image
+    processing pipeline inside the subdevice.</para>
+
+    <section>
+      <title>Types of selection targets</title>
+
+      <para>There are two types of selection targets: actual and bounds.
+      The ACTUAL targets are the targets which configure the hardware.
+      The BOUNDS target will return a rectangle that contain all
+      possible ACTUAL rectangles.</para>
+    </section>
+
+    <section>
+      <title>Discovering supported features</title>
+
+      <para>To discover which targets are supported, the user can
+      perform <constant>VIDIOC_SUBDEV_G_SELECTION</constant> on them.
+      Any unsupported target will return
+      <constant>EINVAL</constant>.</para>
+    </section>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-selection-targets">
+      <title>V4L2 subdev selection targets</title>
+      <tgroup cols="3">
+        &cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL</constant></entry>
+	    <entry>0x0000</entry>
+	    <entry>Actual crop. Defines the cropping
+	    performed by the processing step.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS</constant></entry>
+	    <entry>0x0002</entry>
+	    <entry>Bounds of the crop rectangle.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL</constant></entry>
+	    <entry>0x0100</entry>
+	    <entry>Actual compose rectangle. Used to configure scaling
+	    on sink pads and composition on source pads.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
+	    <entry>0x0102</entry>
+	    <entry>Bounds of the compose rectangle.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-selection-flags">
+      <title>V4L2 subdev selection flags</title>
+      <tgroup cols="3">
+        &cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant></entry>
+	    <entry>(1 &lt;&lt; 0)</entry> <entry>Suggest the driver it
+	    should choose greater or equal rectangle (in size) than
+	    was requested. Albeit the driver may choose a lesser size,
+	    it will only do so due to hardware limitations. Without
+	    this flag (and
+	    <constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant>) the
+	    behaviour is to choose the closest possible
+	    rectangle.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant></entry>
+	    <entry>(1 &lt;&lt; 1)</entry> <entry>Suggest the driver it
+	    should choose lesser or equal rectangle (in size) than was
+	    requested. Albeit the driver may choose a greater size, it
+	    will only do so due to hardware limitations.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant></entry>
+	    <entry>(1 &lt;&lt; 2)</entry>
+	    <entry>The configuration should not be propagated to any
+	    further processing steps. If this flag is not given, the
+	    configuration is propagated inside the subdevice to all
+	    further processing steps.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-selection">
+      <title>struct <structname>v4l2_subdev_selection</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>which</structfield></entry>
+	    <entry>Active or try selection, from
+	    &v4l2-subdev-format-whence;.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>pad</structfield></entry>
+	    <entry>Pad number as reported by the media framework.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>target</structfield></entry>
+	    <entry>Target selection rectangle. See
+	    <xref linkend="v4l2-subdev-selection-targets">.</xref>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>flags</structfield></entry>
+	    <entry>Flags. See
+	    <xref linkend="v4l2-subdev-selection-flags">.</xref></entry>
+	  </row>
+	  <row>
+	    <entry>&v4l2-rect;</entry>
+	    <entry><structfield>rect</structfield></entry>
+	    <entry>Selection rectangle, in pixels.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[8]</entry>
+	    <entry>Reserved for future extensions. Applications and drivers must
+	    set the array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
+	<listitem>
+	  <para>The selection rectangle can't be changed because the
+	  pad is currently busy. This can be caused, for instance, by
+	  an active video stream on the pad. The ioctl must not be
+	  retried without performing another action to fix the problem
+	  first. Only returned by
+	  <constant>VIDIOC_SUBDEV_S_SELECTION</constant></para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>The &v4l2-subdev-selection;
+	  <structfield>pad</structfield> references a non-existing
+	  pad, the <structfield>which</structfield> field references a
+	  non-existing format, or the selection target is not
+	  supported on the given subdev pad.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index f7ade3b..59c080f 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -218,16 +218,16 @@
 Linux kernel development process currently consists of a few different
 main kernel "branches" and lots of different subsystem-specific kernel
 branches.  These different branches are:
-  - main 2.6.x kernel tree
-  - 2.6.x.y -stable kernel tree
-  - 2.6.x -git kernel patches
+  - main 3.x kernel tree
+  - 3.x.y -stable kernel tree
+  - 3.x -git kernel patches
   - subsystem specific kernel trees and patches
-  - the 2.6.x -next kernel tree for integration tests
+  - the 3.x -next kernel tree for integration tests
 
-2.6.x kernel tree
+3.x kernel tree
 -----------------
-2.6.x kernels are maintained by Linus Torvalds, and can be found on
-kernel.org in the pub/linux/kernel/v2.6/ directory.  Its development
+3.x kernels are maintained by Linus Torvalds, and can be found on
+kernel.org in the pub/linux/kernel/v3.x/ directory.  Its development
 process is as follows:
   - As soon as a new kernel is released a two weeks window is open,
     during this period of time maintainers can submit big diffs to
@@ -262,20 +262,20 @@
 	released according to perceived bug status, not according to a
 	preconceived timeline."
 
-2.6.x.y -stable kernel tree
+3.x.y -stable kernel tree
 ---------------------------
-Kernels with 4-part versions are -stable kernels. They contain
+Kernels with 3-part versions are -stable kernels. They contain
 relatively small and critical fixes for security problems or significant
-regressions discovered in a given 2.6.x kernel.
+regressions discovered in a given 3.x kernel.
 
 This is the recommended branch for users who want the most recent stable
 kernel and are not interested in helping test development/experimental
 versions.
 
-If no 2.6.x.y kernel is available, then the highest numbered 2.6.x
+If no 3.x.y kernel is available, then the highest numbered 3.x
 kernel is the current stable kernel.
 
-2.6.x.y are maintained by the "stable" team <stable@vger.kernel.org>, and
+3.x.y are maintained by the "stable" team <stable@vger.kernel.org>, and
 are released as needs dictate.  The normal release period is approximately
 two weeks, but it can be longer if there are no pressing problems.  A
 security-related problem, instead, can cause a release to happen almost
@@ -285,7 +285,7 @@
 documents what kinds of changes are acceptable for the -stable tree, and
 how the release process works.
 
-2.6.x -git patches
+3.x -git patches
 ------------------
 These are daily snapshots of Linus' kernel tree which are managed in a
 git repository (hence the name.) These patches are usually released
@@ -317,13 +317,13 @@
 accepted, or rejected.  Most of these patchwork sites are listed at
 http://patchwork.kernel.org/.
 
-2.6.x -next kernel tree for integration tests
+3.x -next kernel tree for integration tests
 ---------------------------------------------
-Before updates from subsystem trees are merged into the mainline 2.6.x
+Before updates from subsystem trees are merged into the mainline 3.x
 tree, they need to be integration-tested.  For this purpose, a special
 testing repository exists into which virtually all subsystem trees are
 pulled on an almost daily basis:
-	http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
+	http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
 	http://linux.f-seidel.de/linux-next/pmwiki/
 
 This way, the -next kernel gives a summary outlook onto what will be
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 30b656e..31d302b 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,3 +1,3 @@
 obj-m := DocBook/ accounting/ auxdisplay/ connector/ \
 	filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \
-	pcmcia/ spi/ timers/ watchdog/src/
+	pcmcia/ spi/ timers/ watchdog/src/ misc-devices/mei/
diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX
index 91c24a1..36420e1 100644
--- a/Documentation/arm/00-INDEX
+++ b/Documentation/arm/00-INDEX
@@ -4,8 +4,6 @@
 	- requirements for booting
 Interrupts
 	- ARM Interrupt subsystem documentation
-IXP2000
-	- Release Notes for Linux on Intel's IXP2000 Network Processor
 msm
 	- MSM specific documentation
 Netwinder
diff --git a/Documentation/arm/IXP2000 b/Documentation/arm/IXP2000
deleted file mode 100644
index 68d21d9..0000000
--- a/Documentation/arm/IXP2000
+++ /dev/null
@@ -1,69 +0,0 @@
-
--------------------------------------------------------------------------
-Release Notes for Linux on Intel's IXP2000 Network Processor
-
-Maintained by Deepak Saxena <dsaxena@plexity.net>
--------------------------------------------------------------------------
-
-1. Overview
-
-Intel's IXP2000 family of NPUs (IXP2400, IXP2800, IXP2850) is designed
-for high-performance network applications such high-availability
-telecom systems. In addition to an XScale core, it contains up to 8
-"MicroEngines" that run special code, several high-end networking 
-interfaces (UTOPIA, SPI, etc), a PCI host bridge, one serial port,
-flash interface, and some other odds and ends. For more information, see:
-
-http://developer.intel.com
-
-2. Linux Support
-
-Linux currently supports the following features on the IXP2000 NPUs:
-
-- On-chip serial
-- PCI
-- Flash (MTD/JFFS2)
-- I2C through GPIO
-- Timers (watchdog, OS)
-
-That is about all we can support under Linux ATM b/c the core networking
-components of the chip are accessed via Intel's closed source SDK. 
-Please contact Intel directly on issues with using those. There is
-also a mailing list run by some folks at Princeton University that might
-be of help:  https://lists.cs.princeton.edu/mailman/listinfo/ixp2xxx
-
-WHATEVER YOU DO, DO NOT POST EMAIL TO THE LINUX-ARM OR LINUX-ARM-KERNEL
-MAILING LISTS REGARDING THE INTEL SDK.
-
-3. Supported Platforms
-
-- Intel IXDP2400 Reference Platform
-- Intel IXDP2800 Reference Platform
-- Intel IXDP2401 Reference Platform
-- Intel IXDP2801 Reference Platform
-- RadiSys ENP-2611
-
-4. Usage Notes
-
-- The IXP2000 platforms usually have rather complex PCI bus topologies
-  with large memory space requirements. In addition, b/c of the way the
-  Intel SDK is designed, devices are enumerated in a very specific
-  way. B/c of this this, we use "pci=firmware" option in the kernel
-  command line so that we do not re-enumerate the bus.
-
-- IXDP2x01 systems have variable clock tick rates that we cannot determine 
-  via HW registers. The "ixdp2x01_clk=XXX" cmd line options allow you
-  to pass the clock rate to the board port.
-
-5. Thanks
-
-The IXP2000 work has been funded by Intel Corp. and MontaVista Software, Inc.
-
-The following people have contributed patches/comments/etc:
-
-Naeem F. Afzal
-Lennert Buytenhek
-Jeffrey Daly
-
--------------------------------------------------------------------------
-Last Update: 8/09/2004
diff --git a/Documentation/arm/SPEAr/overview.txt b/Documentation/arm/SPEAr/overview.txt
index 253a35c..28a9af9 100644
--- a/Documentation/arm/SPEAr/overview.txt
+++ b/Documentation/arm/SPEAr/overview.txt
@@ -17,14 +17,14 @@
   SPEAr (Platform)
 	- SPEAr3XX (3XX SOC series, based on ARM9)
 		- SPEAr300 (SOC)
-			- SPEAr300_EVB (Evaluation Board)
+			- SPEAr300 Evaluation Board
 		- SPEAr310 (SOC)
-			- SPEAr310_EVB (Evaluation Board)
+			- SPEAr310 Evaluation Board
 		- SPEAr320 (SOC)
-			- SPEAr320_EVB (Evaluation Board)
+			- SPEAr320 Evaluation Board
 	- SPEAr6XX (6XX SOC series, based on ARM9)
 		- SPEAr600 (SOC)
-			- SPEAr600_EVB (Evaluation Board)
+			- SPEAr600 Evaluation Board
 	- SPEAr13XX (13XX SOC series, based on ARM CORTEXA9)
 		- SPEAr1300 (SOC)
 
@@ -51,10 +51,11 @@
   Common file for machines of spear3xx family is mach-spear3xx/spear3xx.c and for
   spear6xx is mach-spear6xx/spear6xx.c. mach-spear* also contain soc/machine
   specific files, like spear300.c, spear310.c, spear320.c and spear600.c.
-  mach-spear* also contains board specific files for each machine type.
+  mach-spear* doesn't contains board specific files as they fully support
+  Flattened Device Tree.
 
 
   Document Author
   ---------------
 
-  Viresh Kumar, (c) 2010 ST Microelectronics
+  Viresh Kumar <viresh.kumar@st.com>, (c) 2010-2012 ST Microelectronics
diff --git a/Documentation/blackfin/bfin-gpio-notes.txt b/Documentation/blackfin/bfin-gpio-notes.txt
index d36b01f..d245f39 100644
--- a/Documentation/blackfin/bfin-gpio-notes.txt
+++ b/Documentation/blackfin/bfin-gpio-notes.txt
@@ -53,7 +53,7 @@
 
 3. But there are some exceptions
     - Kernel permit the identical GPIO be requested both as GPIO and GPIO
-    interrut.
+    interrupt.
     Some drivers, like gpio-keys, need this behavior. Kernel only print out
     warning messages like,
 	bfin-gpio: GPIO 24 is already reserved by gpio-keys: BTN0, and you are
diff --git a/Documentation/cgroups/resource_counter.txt b/Documentation/cgroups/resource_counter.txt
index 95b24d7..f3c4ec3 100644
--- a/Documentation/cgroups/resource_counter.txt
+++ b/Documentation/cgroups/resource_counter.txt
@@ -77,11 +77,11 @@
 	where the charging failed.
 
  d. int res_counter_charge_locked
-			(struct res_counter *rc, unsigned long val)
+			(struct res_counter *rc, unsigned long val, bool force)
 
 	The same as res_counter_charge(), but it must not acquire/release the
 	res_counter->lock internally (it must be called with res_counter->lock
-	held).
+	held). The force parameter indicates whether we can bypass the limit.
 
  e. void res_counter_uncharge[_locked]
 			(struct res_counter *rc, unsigned long val)
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 0038318..47a154f 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -98,7 +98,8 @@
 		  8 = /dev/random	Nondeterministic random number gen.
 		  9 = /dev/urandom	Faster, less secure random number gen.
 		 10 = /dev/aio		Asynchronous I/O notification interface
-		 11 = /dev/kmsg		Writes to this come out as printk's
+		 11 = /dev/kmsg		Writes to this come out as printk's, reads
+					export the buffered printk records.
 		 12 = /dev/oldmem	Used by crashdump kernels to access
 					the memory of the kernel that crashed.
 
@@ -846,13 +847,7 @@
 		    ...
 		 31 = /dev/tap15	16th Ethertap device
 
- 36 block	MCA ESDI hard disk
-		  0 = /dev/eda		First ESDI disk whole disk
-		 64 = /dev/edb		Second ESDI disk whole disk
-		    ...
-
-		Partitions are handled in the same way as IDE disks
-		(see major number 3).
+ 36 block	OBSOLETE (was MCA ESDI hard disk)
 
  37 char	IDE tape
 		  0 = /dev/ht0		First IDE tape
diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
new file mode 100644
index 0000000..c63097d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -0,0 +1,65 @@
+* AT91's Analog to Digital Converter (ADC)
+
+Required properties:
+  - compatible: Should be "atmel,at91sam9260-adc"
+  - reg: Should contain ADC registers location and length
+  - interrupts: Should contain the IRQ line for the ADC
+  - atmel,adc-channel-base: Offset of the first channel data register
+  - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
+    device
+  - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC
+  - atmel,adc-num-channels: Number of channels available in the ADC
+  - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
+    defined in the datasheet
+  - atmel,adc-status-register: Offset of the Interrupt Status Register
+  - atmel,adc-trigger-register: Offset of the Trigger Register
+  - atmel,adc-vref: Reference voltage in millivolts for the conversions
+
+Optional properties:
+  - atmel,adc-use-external: Boolean to enable of external triggers
+ 
+Optional trigger Nodes:
+  - Required properties:
+    * trigger-name: Name of the trigger exposed to the user
+    * trigger-value: Value to put in the Trigger register
+      to activate this trigger
+  - Optional properties:
+    * trigger-external: Is the trigger an external trigger?
+
+Examples:
+adc0: adc@fffb0000 {
+	compatible = "atmel,at91sam9260-adc";
+	reg = <0xfffb0000 0x100>;
+	interrupts = <20 4>;
+	atmel,adc-channel-base = <0x30>;
+	atmel,adc-channels-used = <0xff>;
+	atmel,adc-drdy-mask = <0x10000>;
+	atmel,adc-num-channels = <8>;
+	atmel,adc-startup-time = <40>;
+	atmel,adc-status-register = <0x1c>;
+	atmel,adc-trigger-register = <0x08>;
+	atmel,adc-use-external;
+	atmel,adc-vref = <3300>;
+
+	trigger@0 {
+		trigger-name = "external-rising";
+		trigger-value = <0x1>;
+		trigger-external;
+	};
+	trigger@1 {
+		trigger-name = "external-falling";
+		trigger-value = <0x2>;
+		trigger-external;
+	};
+
+	trigger@2 {
+		trigger-name = "external-any";
+		trigger-value = <0x3>;
+		trigger-external;
+	};
+
+	trigger@3 {
+		trigger-name = "continuous";
+		trigger-value = <0x6>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt b/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt
new file mode 100644
index 0000000..539adca
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt
@@ -0,0 +1,38 @@
+* NXP LPC32xx Main Interrupt Controller
+  (MIC, including SIC1 and SIC2 secondary controllers)
+
+Required properties:
+- compatible: Should be "nxp,lpc3220-mic"
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupt-parent: Empty for the interrupt controller itself
+- #interrupt-cells: The number of cells to define the interrupts. Should be 2.
+  The first cell is the IRQ number
+  The second cell is used to specify mode:
+      1 = low-to-high edge triggered
+      2 = high-to-low edge triggered
+      4 = active high level-sensitive
+      8 = active low level-sensitive
+      Default for internal sources should be set to 4 (active high).
+- reg: Should contain MIC registers location and length
+
+Examples:
+	/*
+	 * MIC
+	 */
+	mic: interrupt-controller@40008000 {
+		compatible = "nxp,lpc3220-mic";
+		interrupt-controller;
+		interrupt-parent;
+		#interrupt-cells = <2>;
+		reg = <0x40008000 0xC000>;
+	};
+
+	/*
+	 * ADC
+	 */
+	adc@40048000 {
+		compatible = "nxp,lpc3220-adc";
+		reg = <0x40048000 0x1000>;
+		interrupt-parent = <&mic>;
+		interrupts = <39 4>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/lpc32xx.txt b/Documentation/devicetree/bindings/arm/lpc32xx.txt
new file mode 100644
index 0000000..56ec8dd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/lpc32xx.txt
@@ -0,0 +1,8 @@
+NXP LPC32xx Platforms Device Tree Bindings
+------------------------------------------
+
+Boards with the NXP LPC32xx SoC shall have the following properties:
+
+Required root node property:
+
+compatible: must be "nxp,lpc3220", "nxp,lpc3230", "nxp,lpc3240" or "nxp,lpc3250"
diff --git a/Documentation/devicetree/bindings/arm/mrvl.txt b/Documentation/devicetree/bindings/arm/mrvl.txt
deleted file mode 100644
index d8de933..0000000
--- a/Documentation/devicetree/bindings/arm/mrvl.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Marvell Platforms Device Tree Bindings
-----------------------------------------------------
-
-PXA168 Aspenite Board
-Required root node properties:
-	- compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168";
diff --git a/Documentation/devicetree/bindings/arm/mrvl/intc.txt b/Documentation/devicetree/bindings/arm/mrvl/intc.txt
new file mode 100644
index 0000000..80b9a94
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl/intc.txt
@@ -0,0 +1,40 @@
+* Marvell MMP Interrupt controller
+
+Required properties:
+- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc" or
+  "mrvl,mmp2-mux-intc"
+- reg : Address and length of the register set of the interrupt controller.
+  If the interrupt controller is intc, address and length means the range
+  of the whold interrupt controller. If the interrupt controller is mux-intc,
+  address and length means one register. Since address of mux-intc is in the
+  range of intc. mux-intc is secondary interrupt controller.
+- reg-names : Name of the register set of the interrupt controller. It's
+  only required in mux-intc interrupt controller.
+- interrupts : Should be the port interrupt shared by mux interrupts. It's
+  only required in mux-intc interrupt controller.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source.
+- mrvl,intc-nr-irqs : Specifies the number of interrupts in the interrupt
+  controller.
+- mrvl,clr-mfp-irq : Specifies the interrupt that needs to clear MFP edge
+  detection first.
+
+Example:
+	intc: interrupt-controller@d4282000 {
+		compatible = "mrvl,mmp2-intc";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		reg = <0xd4282000 0x1000>;
+		mrvl,intc-nr-irqs = <64>;
+	};
+
+	intcmux4@d4282150 {
+		compatible = "mrvl,mmp2-mux-intc";
+		interrupts = <4>;
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		reg = <0x150 0x4>, <0x168 0x4>;
+		reg-names = "mux status", "mux mask";
+		mrvl,intc-nr-irqs = <2>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
new file mode 100644
index 0000000..117d741
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
@@ -0,0 +1,14 @@
+Marvell Platforms Device Tree Bindings
+----------------------------------------------------
+
+PXA168 Aspenite Board
+Required root node properties:
+	- compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168";
+
+PXA910 DKB Board
+Required root node properties:
+	- compatible = "mrvl,pxa910-dkb";
+
+MMP2 Brownstone Board
+Required root node properties:
+	- compatible = "mrvl,mmp2-brownstone";
diff --git a/Documentation/devicetree/bindings/arm/mrvl/timer.txt b/Documentation/devicetree/bindings/arm/mrvl/timer.txt
new file mode 100644
index 0000000..9a6e251
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl/timer.txt
@@ -0,0 +1,13 @@
+* Marvell MMP Timer controller
+
+Required properties:
+- compatible : Should be "mrvl,mmp-timer".
+- reg : Address and length of the register set of timer controller.
+- interrupts : Should be the interrupt number.
+
+Example:
+	timer0: timer@d4014000 {
+		compatible = "mrvl,mmp-timer";
+		reg = <0xd4014000 0x100>;
+		interrupts = <13>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/spear.txt b/Documentation/devicetree/bindings/arm/spear.txt
index f8e54f0..aa5f355 100644
--- a/Documentation/devicetree/bindings/arm/spear.txt
+++ b/Documentation/devicetree/bindings/arm/spear.txt
@@ -6,3 +6,21 @@
 Required root node property:
 
 compatible = "st,spear600";
+
+Boards with the ST SPEAr300 SoC shall have the following properties:
+
+Required root node property:
+
+compatible = "st,spear300";
+
+Boards with the ST SPEAr310 SoC shall have the following properties:
+
+Required root node property:
+
+compatible = "st,spear310";
+
+Boards with the ST SPEAr320 SoC shall have the following properties:
+
+Required root node property:
+
+compatible = "st,spear320";
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt
new file mode 100644
index 0000000..c25a0a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt
@@ -0,0 +1,16 @@
+NVIDIA Tegra20 MC(Memory Controller)
+
+Required properties:
+- compatible : "nvidia,tegra20-mc"
+- reg : Should contain 2 register ranges(address and length); see the
+  example below. Note that the MC registers are interleaved with the
+  GART registers, and hence must be represented as multiple ranges.
+- interrupts : Should contain MC General interrupt.
+
+Example:
+	mc {
+		compatible = "nvidia,tegra20-mc";
+		reg = <0x7000f000 0x024
+		       0x7000f03c 0x3c4>;
+		interrupts = <0 77 0x04>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt
new file mode 100644
index 0000000..e47e73f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt
@@ -0,0 +1,18 @@
+NVIDIA Tegra30 MC(Memory Controller)
+
+Required properties:
+- compatible : "nvidia,tegra30-mc"
+- reg : Should contain 4 register ranges(address and length); see the
+  example below. Note that the MC registers are interleaved with the
+  SMMU registers, and hence must be represented as multiple ranges.
+- interrupts : Should contain MC General interrupt.
+
+Example:
+	mc {
+		compatible = "nvidia,tegra30-mc";
+		reg = <0x7000f000 0x010
+		       0x7000f03c 0x1b4
+		       0x7000f200 0x028
+		       0x7000f284 0x17c>;
+		interrupts = <0 77 0x04>;
+	};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-nmk.txt b/Documentation/devicetree/bindings/gpio/gpio-nmk.txt
new file mode 100644
index 0000000..ee87467
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-nmk.txt
@@ -0,0 +1,31 @@
+Nomadik GPIO controller
+
+Required properties:
+- compatible            : Should be "st,nomadik-gpio".
+- reg                   : Physical base address and length of the controller's registers.
+- interrupts            : The interrupt outputs from the controller.
+- #gpio-cells           : Should be two:
+                            The first cell is the pin number.
+                            The second cell is used to specify optional parameters:
+                              - bits[3:0] trigger type and level flags:
+                                  1 = low-to-high edge triggered.
+                                  2 = high-to-low edge triggered.
+                                  4 = active high level-sensitive.
+                                  8 = active low level-sensitive.
+- gpio-controller       : Marks the device node as a GPIO controller.
+- interrupt-controller  : Marks the device node as an interrupt controller.
+- gpio-bank             : Specifies which bank a controller owns.
+- st,supports-sleepmode : Specifies whether controller can sleep or not
+
+Example:
+
+                gpio1: gpio@8012e080 {
+                        compatible = "st,nomadik-gpio";
+                        reg =  <0x8012e080 0x80>;
+                        interrupts = <0 120 0x4>;
+                        #gpio-cells = <2>;
+                        gpio-controller;
+                        interrupt-controller;
+                        supports-sleepmode;
+                        gpio-bank = <1>;
+                };
diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
index 1e34cfe..05428f3 100644
--- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
@@ -3,19 +3,25 @@
 Required properties:
 - compatible : Should be "mrvl,pxa-gpio" or "mrvl,mmp-gpio"
 - reg : Address and length of the register set for the device
-- interrupts : Should be the port interrupt shared by all gpio pins, if
-- interrupt-name : Should be the name of irq resource.
-  one number.
+- interrupts : Should be the port interrupt shared by all gpio pins.
+  There're three gpio interrupts in arch-pxa, and they're gpio0,
+  gpio1 and gpio_mux. There're only one gpio interrupt in arch-mmp,
+  gpio_mux.
+- interrupt-name : Should be the name of irq resource. Each interrupt
+  binds its interrupt-name.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells: Specifies the number of cells needed to encode an
+  interrupt source.
 - gpio-controller : Marks the device node as a gpio controller.
 - #gpio-cells : Should be one.  It is the pin number.
 
 Example:
 
 	gpio: gpio@d4019000 {
-		compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+		compatible = "mrvl,mmp-gpio";
 		reg = <0xd4019000 0x1000>;
-		interrupts = <49>, <17>, <18>;
-		interrupt-name = "gpio_mux", "gpio0", "gpio1";
+		interrupts = <49>;
+		interrupt-name = "gpio_mux";
 		gpio-controller;
 		#gpio-cells = <1>;
 		interrupt-controller;
diff --git a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
index 071eb3c..b891ee21 100644
--- a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
+++ b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
@@ -3,34 +3,31 @@
 Required properties :
 
  - reg : Offset and length of the register set for the device
- - compatible : should be "mrvl,mmp-twsi" where CHIP is the name of a
+ - compatible : should be "mrvl,mmp-twsi" where mmp is the name of a
    compatible processor, e.g. pxa168, pxa910, mmp2, mmp3.
    For the pxa2xx/pxa3xx, an additional node "mrvl,pxa-i2c" is required
    as shown in the example below.
 
 Recommended properties :
 
- - interrupts : <a b> where a is the interrupt number and b is a
-   field that represents an encoding of the sense and level
-   information for the interrupt.  This should be encoded based on
-   the information in section 2) depending on the type of interrupt
-   controller you have.
+ - interrupts : the interrupt number
  - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
+   services interrupts for this device. If the parent is the default
+   interrupt controller in device tree, it could be ignored.
  - mrvl,i2c-polling : Disable interrupt of i2c controller. Polling
    status register of i2c controller instead.
  - mrvl,i2c-fast-mode : Enable fast mode of i2c controller.
 
 Examples:
 	twsi1: i2c@d4011000 {
-		compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+		compatible = "mrvl,mmp-twsi";
 		reg = <0xd4011000 0x1000>;
 		interrupts = <7>;
 		mrvl,i2c-fast-mode;
 	};
 	
 	twsi2: i2c@d4025000 {
-		compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+		compatible = "mrvl,mmp-twsi";
 		reg = <0xd4025000 0x1000>;
 		interrupts = <58>;
 	};
diff --git a/Documentation/devicetree/bindings/i2c/pnx.txt b/Documentation/devicetree/bindings/i2c/pnx.txt
new file mode 100644
index 0000000..fe98ada
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/pnx.txt
@@ -0,0 +1,36 @@
+* NXP PNX I2C Controller
+
+Required properties:
+
+ - reg: Offset and length of the register set for the device
+ - compatible: should be "nxp,pnx-i2c"
+ - interrupts: configure one interrupt line
+ - #address-cells: always 1 (for i2c addresses)
+ - #size-cells: always 0
+ - interrupt-parent: the phandle for the interrupt controller that
+   services interrupts for this device.
+
+Optional properties:
+
+ - clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz
+
+Examples:
+
+	i2c1: i2c@400a0000 {
+		compatible = "nxp,pnx-i2c";
+		reg = <0x400a0000 0x100>;
+		interrupt-parent = <&mic>;
+		interrupts = <51 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	i2c2: i2c@400a8000 {
+		compatible = "nxp,pnx-i2c";
+		reg = <0x400a8000 0x100>;
+		interrupt-parent = <&mic>;
+		interrupts = <50 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <100000>;
+	};
diff --git a/Documentation/devicetree/bindings/input/spear-keyboard.txt b/Documentation/devicetree/bindings/input/spear-keyboard.txt
new file mode 100644
index 0000000..4a846d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/spear-keyboard.txt
@@ -0,0 +1,20 @@
+* SPEAr keyboard controller
+
+Required properties:
+- compatible: "st,spear300-kbd"
+
+Optional properties, in addition to those specified by the shared
+matrix-keyboard bindings:
+- autorepeat: bool: enables key autorepeat
+- st,mode: keyboard mode: 0 - 9x9, 1 - 6x6, 2 - 2x2
+
+Example:
+
+kbd@fc400000 {
+	compatible = "st,spear300-kbd";
+	reg = <0xfc400000 0x100>;
+	linux,keymap = < 0x00030012
+			 0x0102003a >;
+	autorepeat;
+	st,mode = <0>;
+};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt b/Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt
new file mode 100644
index 0000000..41cbf4b
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt
@@ -0,0 +1,16 @@
+* NXP LPC32xx SoC Touchscreen Controller (TSC)
+
+Required properties:
+- compatible: must be "nxp,lpc3220-tsc"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: The TSC/ADC interrupt
+
+Example:
+
+	tsc@40048000 {
+		compatible = "nxp,lpc3220-tsc";
+		reg = <0x40048000 0x1000>;
+		interrupt-parent = <&mic>;
+		interrupts = <39 0>;
+	};
diff --git a/Documentation/devicetree/bindings/input/twl6040-vibra.txt b/Documentation/devicetree/bindings/input/twl6040-vibra.txt
new file mode 100644
index 0000000..5b1918b
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/twl6040-vibra.txt
@@ -0,0 +1,37 @@
+Vibra driver for the twl6040 family
+
+The vibra driver is a child of the twl6040 MFD dirver.
+Documentation/devicetree/bindings/mfd/twl6040.txt
+
+Required properties:
+- compatible : Must be "ti,twl6040-vibra";
+- interrupts: 4, Vibra overcurrent interrupt
+- vddvibl-supply: Regulator supplying the left vibra motor
+- vddvibr-supply: Regulator supplying the right vibra motor
+- vibldrv_res: Board specific left driver resistance
+- vibrdrv_res: Board specific right driver resistance
+- viblmotor_res: Board specific left motor resistance
+- vibrmotor_res: Board specific right motor resistance
+
+Optional properties:
+- vddvibl_uV: If the vddvibl default voltage need to be changed
+- vddvibr_uV: If the vddvibr default voltage need to be changed
+
+Example:
+/*
+ * 8-channel high quality low-power audio codec
+ * http://www.ti.com/lit/ds/symlink/twl6040.pdf
+ */
+twl6040: twl6040@4b {
+	...
+	twl6040_vibra: twl6040@1 {
+		compatible = "ti,twl6040-vibra";
+		interrupts = <4>;
+		vddvibl-supply = <&vbat>;
+		vddvibr-supply = <&vbat>;
+		vibldrv_res = <8>;
+		vibrdrv_res = <3>;
+		viblmotor_res = <10>;
+		vibrmotor_res = <10>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/misc/bmp085.txt b/Documentation/devicetree/bindings/misc/bmp085.txt
new file mode 100644
index 0000000..91dfda2
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/bmp085.txt
@@ -0,0 +1,20 @@
+BMP085/BMP18x digital pressure sensors
+
+Required properties:
+- compatible: bosch,bmp085
+
+Optional properties:
+- chip-id: configurable chip id for non-default chip revisions
+- temp-measurement-period: temperature measurement period (milliseconds)
+- default-oversampling: default oversampling value to be used at startup,
+  value range is 0-3 with rising sensitivity.
+
+Example:
+
+pressure@77 {
+	compatible = "bosch,bmp085";
+	reg = <0x77>;
+	chip-id = <10>;
+	temp-measurement-period = <100>;
+	default-oversampling = <2>;
+};
diff --git a/Documentation/devicetree/bindings/mtd/orion-nand.txt b/Documentation/devicetree/bindings/mtd/orion-nand.txt
new file mode 100644
index 0000000..b2356b7
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/orion-nand.txt
@@ -0,0 +1,50 @@
+NAND support for Marvell Orion SoC platforms
+
+Required properties:
+- compatible : "mrvl,orion-nand".
+- reg : Base physical address of the NAND and length of memory mapped
+	region
+
+Optional properties:
+- cle : Address line number connected to CLE. Default is 0
+- ale : Address line number connected to ALE. Default is 1
+- bank-width : Width in bytes of the device. Default is 1
+- chip-delay : Chip dependent delay for transferring data from array to read
+               registers in usecs
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+nand@f4000000 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	cle = <0>;
+	ale = <1>;
+	bank-width = <1>;
+	chip-delay = <25>;
+	compatible = "mrvl,orion-nand";
+	reg = <0xf4000000 0x400>;
+
+	partition@0 {
+		label = "u-boot";
+		reg = <0x0000000 0x100000>;
+		read-only;
+	};
+
+	partition@100000 {
+		label = "uImage";
+		reg = <0x0100000 0x200000>;
+	};
+
+	partition@300000 {
+		label = "dtb";
+		reg = <0x0300000 0x100000>;
+	};
+
+	partition@400000 {
+		label = "root";
+		reg = <0x0400000 0x7d00000>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
index 1ad80d5..f31b686 100644
--- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
+++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
@@ -1,4 +1,4 @@
-Flexcan CAN contoller on Freescale's ARM and PowerPC system-on-a-chip (SOC).
+Flexcan CAN controller on Freescale's ARM and PowerPC system-on-a-chip (SOC).
 
 Required properties:
 
diff --git a/Documentation/devicetree/bindings/net/lpc-eth.txt b/Documentation/devicetree/bindings/net/lpc-eth.txt
new file mode 100644
index 0000000..585021a
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/lpc-eth.txt
@@ -0,0 +1,24 @@
+* NXP LPC32xx SoC Ethernet Controller
+
+Required properties:
+- compatible: Should be "nxp,lpc-eth"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain ethernet controller interrupt
+
+Optional properties:
+- phy-mode: String, operation mode of the PHY interface.
+  Supported values are: "mii", "rmii" (default)
+- use-iram: Use LPC32xx internal SRAM (IRAM) for DMA buffering
+- local-mac-address : 6 bytes, mac address
+
+Example:
+
+	mac: ethernet@31060000 {
+		compatible = "nxp,lpc-eth";
+		reg = <0x31060000 0x1000>;
+		interrupt-parent = <&mic>;
+		interrupts = <29 0>;
+
+		phy-mode = "rmii";
+		use-iram;
+	};
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt
new file mode 100644
index 0000000..3664d37
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt
@@ -0,0 +1,108 @@
+ST Microelectronics, SPEAr pinmux controller
+
+Required properties:
+- compatible	: "st,spear300-pinmux"
+		: "st,spear310-pinmux"
+		: "st,spear320-pinmux"
+- reg		: Address range of the pinctrl registers
+- st,pinmux-mode: Mandatory for SPEAr300 and SPEAr320 and invalid for others.
+	- Its values for SPEAr300:
+		- NAND_MODE		: <0>
+		- NOR_MODE		: <1>
+		- PHOTO_FRAME_MODE	: <2>
+		- LEND_IP_PHONE_MODE	: <3>
+		- HEND_IP_PHONE_MODE	: <4>
+		- LEND_WIFI_PHONE_MODE	: <5>
+		- HEND_WIFI_PHONE_MODE	: <6>
+		- ATA_PABX_WI2S_MODE	: <7>
+		- ATA_PABX_I2S_MODE	: <8>
+		- CAML_LCDW_MODE	: <9>
+		- CAMU_LCD_MODE		: <10>
+		- CAMU_WLCD_MODE	: <11>
+		- CAML_LCD_MODE		: <12>
+	- Its values for SPEAr320:
+		- AUTO_NET_SMII_MODE	: <0>
+		- AUTO_NET_MII_MODE	: <1>
+		- AUTO_EXP_MODE		: <2>
+		- SMALL_PRINTERS_MODE	: <3>
+		- EXTENDED_MODE		: <4>
+
+Please refer to pinctrl-bindings.txt in this directory for details of the common
+pinctrl bindings used by client devices.
+
+SPEAr's pinmux nodes act as a container for an abitrary number of subnodes. Each
+of these subnodes represents muxing for a pin, a group, or a list of pins or
+groups.
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Required subnode-properties:
+- st,pins : An array of strings. Each string contains the name of a pin or
+  group.
+- st,function: A string containing the name of the function to mux to the pin or
+  group. See the SPEAr's TRM to determine which are valid for each pin or group.
+
+  Valid values for group and function names can be found from looking at the
+  group and function arrays in driver files:
+  drivers/pinctrl/spear/pinctrl-spear3*0.c
+
+Valid values for group names are:
+For All SPEAr3xx machines:
+	"firda_grp", "i2c0_grp", "ssp_cs_grp", "ssp0_grp", "mii0_grp",
+	"gpio0_pin0_grp", "gpio0_pin1_grp", "gpio0_pin2_grp", "gpio0_pin3_grp",
+	"gpio0_pin4_grp", "gpio0_pin5_grp", "uart0_ext_grp", "uart0_grp",
+	"timer_0_1_grp", timer_0_1_pins, "timer_2_3_grp"
+
+For SPEAr300 machines:
+	"fsmc_2chips_grp", "fsmc_4chips_grp", "clcd_lcdmode_grp",
+	"clcd_pfmode_grp", "tdm_grp", "i2c_clk_grp_grp", "caml_grp", "camu_grp",
+	"dac_grp", "i2s_grp", "sdhci_4bit_grp", "sdhci_8bit_grp",
+	"gpio1_0_to_3_grp", "gpio1_4_to_7_grp"
+
+For SPEAr310 machines:
+	"emi_cs_0_to_5_grp", "uart1_grp", "uart2_grp", "uart3_grp", "uart4_grp",
+	"uart5_grp", "fsmc_grp", "rs485_0_grp", "rs485_1_grp", "tdm_grp"
+
+For SPEAr320 machines:
+	"clcd_grp", "emi_grp", "fsmc_8bit_grp", "fsmc_16bit_grp", "spp_grp",
+	"sdhci_led_grp", "sdhci_cd_12_grp", "sdhci_cd_51_grp", "i2s_grp",
+	"uart1_grp", "uart1_modem_2_to_7_grp", "uart1_modem_31_to_36_grp",
+	"uart1_modem_34_to_45_grp", "uart1_modem_80_to_85_grp", "uart2_grp",
+	"uart3_8_9_grp", "uart3_15_16_grp", "uart3_41_42_grp",
+	"uart3_52_53_grp", "uart3_73_74_grp", "uart3_94_95_grp",
+	"uart3_98_99_grp", "uart4_6_7_grp", "uart4_13_14_grp",
+	"uart4_39_40_grp", "uart4_71_72_grp", "uart4_92_93_grp",
+	"uart4_100_101_grp", "uart5_4_5_grp", "uart5_37_38_grp",
+	"uart5_69_70_grp", "uart5_90_91_grp", "uart6_2_3_grp",
+	"uart6_88_89_grp", "rs485_grp", "touchscreen_grp", "can0_grp",
+	"can1_grp", "pwm0_1_pin_8_9_grp", "pwm0_1_pin_14_15_grp",
+	"pwm0_1_pin_30_31_grp", "pwm0_1_pin_37_38_grp", "pwm0_1_pin_42_43_grp",
+	"pwm0_1_pin_59_60_grp", "pwm0_1_pin_88_89_grp", "pwm2_pin_7_grp",
+	"pwm2_pin_13_grp", "pwm2_pin_29_grp", "pwm2_pin_34_grp",
+	"pwm2_pin_41_grp", "pwm2_pin_58_grp", "pwm2_pin_87_grp",
+	"pwm3_pin_6_grp", "pwm3_pin_12_grp", "pwm3_pin_28_grp",
+	"pwm3_pin_40_grp", "pwm3_pin_57_grp", "pwm3_pin_86_grp",
+	"ssp1_17_20_grp", "ssp1_36_39_grp", "ssp1_48_51_grp", "ssp1_65_68_grp",
+	"ssp1_94_97_grp", "ssp2_13_16_grp", "ssp2_32_35_grp", "ssp2_44_47_grp",
+	"ssp2_61_64_grp", "ssp2_90_93_grp", "mii2_grp", "smii0_1_grp",
+	"rmii0_1_grp", "i2c1_8_9_grp", "i2c1_98_99_grp", "i2c2_0_1_grp",
+	"i2c2_2_3_grp", "i2c2_19_20_grp", "i2c2_75_76_grp", "i2c2_96_97_grp"
+
+Valid values for function names are:
+For All SPEAr3xx machines:
+	"firda", "i2c0", "ssp_cs", "ssp0", "mii0", "gpio0", "uart0_ext",
+	"uart0", "timer_0_1", "timer_2_3"
+
+For SPEAr300 machines:
+	"fsmc", "clcd", "tdm", "i2c1", "cam", "dac", "i2s", "sdhci", "gpio1"
+
+For SPEAr310 machines:
+	"emi", "uart1", "uart2", "uart3", "uart4", "uart5", "fsmc", "rs485_0",
+	"rs485_1", "tdm"
+
+For SPEAr320 machines:
+	"clcd", "emi", "fsmc", "spp", "sdhci", "i2s", "uart1", "uart1_modem",
+	"uart2", "uart3", "uart4", "uart5", "uart6", "rs485", "touchscreen",
+	"can0", "can1", "pwm0_1", "pwm2", "pwm3", "ssp1", "ssp2", "mii2",
+	"mii0_1", "i2c1", "i2c2"
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
new file mode 100644
index 0000000..e4acdd8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
@@ -0,0 +1,49 @@
+Freescale i.MX audio complex with SGTL5000 codec
+
+Required properties:
+- compatible : "fsl,imx-audio-sgtl5000"
+- model : The user-visible name of this sound complex
+- ssi-controller : The phandle of the i.MX SSI controller
+- audio-codec : The phandle of the SGTL5000 audio codec
+- audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names could be power
+  supplies, SGTL5000 pins, and the jacks on the board:
+
+  Power supplies:
+   * Mic Bias
+
+  SGTL5000 pins:
+   * MIC_IN
+   * LINE_IN
+   * HP_OUT
+   * LINE_OUT
+
+  Board connectors:
+   * Mic Jack
+   * Line In Jack
+   * Headphone Jack
+   * Line Out Jack
+   * Ext Spk
+
+- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
+- mux-ext-port : The external port of the i.MX audio muxer
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+sound {
+	compatible = "fsl,imx51-babbage-sgtl5000",
+		     "fsl,imx-audio-sgtl5000";
+	model = "imx51-babbage-sgtl5000";
+	ssi-controller = <&ssi1>;
+	audio-codec = <&sgtl5000>;
+	audio-routing =
+		"MIC_IN", "Mic Jack",
+		"Mic Jack", "Mic Bias",
+		"Headphone Jack", "HP_OUT";
+	mux-int-port = <1>;
+	mux-ext-port = <3>;
+};
diff --git a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt
new file mode 100644
index 0000000..601c518
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt
@@ -0,0 +1,17 @@
+* Freescale MXS audio complex with SGTL5000 codec
+
+Required properties:
+- compatible: "fsl,mxs-audio-sgtl5000"
+- model: The user-visible name of this sound complex
+- saif-controllers: The phandle list of the MXS SAIF controller
+- audio-codec: The phandle of the SGTL5000 audio codec
+
+Example:
+
+sound {
+	compatible = "fsl,imx28-evk-sgtl5000",
+		     "fsl,mxs-audio-sgtl5000";
+	model = "imx28-evk-sgtl5000";
+	saif-controllers = <&saif0 &saif1>;
+	audio-codec = <&sgtl5000>;
+};
diff --git a/Documentation/devicetree/bindings/sound/mxs-saif.txt b/Documentation/devicetree/bindings/sound/mxs-saif.txt
new file mode 100644
index 0000000..c37ba61
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mxs-saif.txt
@@ -0,0 +1,36 @@
+* Freescale MXS Serial Audio Interface (SAIF)
+
+Required properties:
+- compatible: Should be "fsl,<chip>-saif"
+- reg: Should contain registers location and length
+- interrupts: Should contain ERROR and DMA interrupts
+- fsl,saif-dma-channel: APBX DMA channel for the SAIF
+
+Optional properties:
+- fsl,saif-master: phandle to the master SAIF.  It's only required for
+  the slave SAIF.
+
+Note: Each SAIF controller should have an alias correctly numbered
+in "aliases" node.
+
+Example:
+
+aliases {
+	saif0 = &saif0;
+	saif1 = &saif1;
+};
+
+saif0: saif@80042000 {
+	compatible = "fsl,imx28-saif";
+	reg = <0x80042000 2000>;
+	interrupts = <59 80>;
+	fsl,saif-dma-channel = <4>;
+};
+
+saif1: saif@80046000 {
+	compatible = "fsl,imx28-saif";
+	reg = <0x80046000 2000>;
+	interrupts = <58 81>;
+	fsl,saif-dma-channel = <5>;
+	fsl,saif-master = <&saif0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
new file mode 100644
index 0000000..1ac7b16
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
@@ -0,0 +1,32 @@
+NVIDIA Tegra30 AHUB (Audio Hub)
+
+Required properties:
+- compatible : "nvidia,tegra30-ahub"
+- reg : Should contain the register physical address and length for each of
+  the AHUB's APBIF registers and the AHUB's own registers.
+- interrupts : Should contain AHUB interrupt
+- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
+  request selector for the first APBIF channel.
+- ranges : The bus address mapping for the configlink register bus.
+  Can be empty since the mapping is 1:1.
+- #address-cells : For the configlink bus. Should be <1>;
+- #size-cells : For the configlink bus. Should be <1>.
+
+AHUB client modules need to specify the IDs of their CIFs (Client InterFaces).
+For RX CIFs, the numbers indicate the register number within AHUB routing
+register space (APBIF 0..3 RX, I2S 0..5 RX, DAM 0..2 RX 0..1, SPDIF RX 0..1).
+For TX CIFs, the numbers indicate the bit position within the AHUB routing
+registers (APBIF 0..3 TX, I2S 0..5 TX, DAM 0..2 TX, SPDIF TX 0..1).
+
+Example:
+
+ahub@70080000 {
+	compatible = "nvidia,tegra30-ahub";
+	reg = <0x70080000 0x200 0x70080200 0x100>;
+	interrupts = < 0 103 0x04 >;
+	nvidia,dma-request-selector = <&apbdma 1>;
+
+	ranges;
+	#address-cells = <1>;
+	#size-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt
new file mode 100644
index 0000000..dfa6c03
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt
@@ -0,0 +1,15 @@
+NVIDIA Tegra30 I2S controller
+
+Required properties:
+- compatible : "nvidia,tegra30-i2s"
+- reg : Should contain I2S registers location and length
+- nvidia,ahub-cif-ids : The list of AHUB CIF IDs for this port, rx (playback)
+  first, tx (capture) second. See nvidia,tegra30-ahub.txt for values.
+
+Example:
+
+i2s@70002800 {
+	compatible = "nvidia,tegra30-i2s";
+	reg = <0x70080300 0x100>;
+	nvidia,ahub-cif-ids = <4 4>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt b/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt
new file mode 100644
index 0000000..04b14cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt
@@ -0,0 +1,14 @@
+NVIDIA Tegra audio complex for TrimSlice
+
+Required properties:
+- compatible : "nvidia,tegra-audio-trimslice"
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8903 audio codec
+
+Example:
+
+sound {
+	compatible = "nvidia,tegra-audio-trimslice";
+	nvidia,i2s-controller = <&tegra_i2s1>;
+	nvidia,audio-codec = <&codec>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt
new file mode 100644
index 0000000..c4dd39c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt
@@ -0,0 +1,54 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-wm8753"
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the WM8753's pins, and the jacks on the board:
+
+  WM8753 pins:
+
+  * LOUT1
+  * LOUT2
+  * ROUT1
+  * ROUT2
+  * MONO1
+  * MONO2
+  * OUT3
+  * OUT4
+  * LINE1
+  * LINE2
+  * RXP
+  * RXN
+  * ACIN
+  * ACOP
+  * MIC1N
+  * MIC1
+  * MIC2N
+  * MIC2
+  * Mic Bias
+
+  Board connectors:
+
+  * Headphone Jack
+  * Mic Jack
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8753 audio codec
+Example:
+
+sound {
+	compatible = "nvidia,tegra-audio-wm8753-whistler",
+		     "nvidia,tegra-audio-wm8753"
+	nvidia,model = "tegra-wm8753-harmony";
+
+	nvidia,audio-routing =
+		"Headphone Jack", "LOUT1",
+		"Headphone Jack", "ROUT1";
+
+	nvidia,i2s-controller = <&i2s1>;
+	nvidia,audio-codec = <&wm8753>;
+};
+
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt b/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt
new file mode 100644
index 0000000..b3629d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt
@@ -0,0 +1,16 @@
+* NXP LPC32xx SoC ADC controller
+
+Required properties:
+- compatible: must be "nxp,lpc3220-adc"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: The ADC interrupt
+
+Example:
+
+	adc@40048000 {
+		compatible = "nxp,lpc3220-adc";
+		reg = <0x40048000 0x1000>;
+		interrupt-parent = <&mic>;
+		interrupts = <39 0>;
+	};
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt b/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt
new file mode 100644
index 0000000..02ea23a
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt
@@ -0,0 +1,26 @@
+* ST SPEAr ADC device driver
+
+Required properties:
+- compatible: Should be "st,spear600-adc"
+- reg: Address and length of the register set for the device
+- interrupt-parent: Should be the phandle for the interrupt controller
+  that services interrupts for this device
+- interrupts: Should contain the ADC interrupt
+- sampling-frequency: Default sampling frequency
+
+Optional properties:
+- vref-external: External voltage reference in milli-volts. If omitted
+  the internal voltage reference will be used.
+- average-samples: Number of samples to generate an average value. If
+  omitted, single data conversion will be used.
+
+Examples:
+
+	adc: adc@d8200000 {
+		compatible = "st,spear600-adc";
+		reg = <0xd8200000 0x1000>;
+		interrupt-parent = <&vic1>;
+		interrupts = <6>;
+		sampling-frequency = <5000000>;
+		vref-external = <2500>;	/* 2.5V VRef */
+	};
diff --git a/Documentation/devicetree/bindings/usb/isp1301.txt b/Documentation/devicetree/bindings/usb/isp1301.txt
new file mode 100644
index 0000000..5405d99
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/isp1301.txt
@@ -0,0 +1,25 @@
+* NXP ISP1301 USB transceiver
+
+Required properties:
+- compatible: must be "nxp,isp1301"
+- reg: I2C address of the ISP1301 device
+
+Optional properties of devices using ISP1301:
+- transceiver: phandle of isp1301 - this helps the ISP1301 driver to find the
+               ISP1301 instance associated with the respective USB driver
+
+Example:
+
+	isp1301: usb-transceiver@2c {
+		compatible = "nxp,isp1301";
+		reg = <0x2c>;
+	};
+
+	usbd@31020000 {
+		compatible = "nxp,lpc3220-udc";
+		reg = <0x31020000 0x300>;
+		interrupt-parent = <&mic>;
+		interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
+		transceiver = <&isp1301>;
+		status = "okay";
+	};
diff --git a/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt b/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt
new file mode 100644
index 0000000..29f12a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt
@@ -0,0 +1,28 @@
+* NXP LPC32xx SoC USB Device Controller (UDC)
+
+Required properties:
+- compatible: Must be "nxp,lpc3220-udc"
+- reg: Physical base address of the controller and length of memory mapped
+  region.
+- interrupts: The USB interrupts:
+              * USB Device Low Priority Interrupt
+              * USB Device High Priority Interrupt
+              * USB Device DMA Interrupt
+              * External USB Transceiver Interrupt (OTG ATX)
+- transceiver: phandle of the associated ISP1301 device - this is necessary for
+               the UDC controller for connecting to the USB physical layer
+
+Example:
+
+	isp1301: usb-transceiver@2c {
+		compatible = "nxp,isp1301";
+		reg = <0x2c>;
+	};
+
+	usbd@31020000 {
+		compatible = "nxp,lpc3220-udc";
+		reg = <0x31020000 0x300>;
+		interrupt-parent = <&mic>;
+		interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
+		transceiver = <&isp1301>;
+	};
diff --git a/Documentation/devicetree/bindings/usb/ohci-nxp.txt b/Documentation/devicetree/bindings/usb/ohci-nxp.txt
new file mode 100644
index 0000000..71e28c1
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ohci-nxp.txt
@@ -0,0 +1,24 @@
+* OHCI controller, NXP ohci-nxp variant
+
+Required properties:
+- compatible: must be "nxp,ohci-nxp"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: The OHCI interrupt
+- transceiver: phandle of the associated ISP1301 device - this is necessary for
+               the UDC controller for connecting to the USB physical layer
+
+Example (LPC32xx):
+
+	isp1301: usb-transceiver@2c {
+		compatible = "nxp,isp1301";
+		reg = <0x2c>;
+	};
+
+	ohci@31020000 {
+		compatible = "nxp,ohci-nxp";
+		reg = <0x31020000 0x300>;
+		interrupt-parent = <&mic>;
+		interrupts = <0x3b 0>;
+		transceiver = <&isp1301>;
+	};
diff --git a/Documentation/devicetree/bindings/usb/spear-usb.txt b/Documentation/devicetree/bindings/usb/spear-usb.txt
new file mode 100644
index 0000000..f8a464a
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/spear-usb.txt
@@ -0,0 +1,39 @@
+ST SPEAr SoC USB controllers:
+-----------------------------
+
+EHCI:
+-----
+
+Required properties:
+- compatible: "st,spear600-ehci"
+- interrupt-parent: Should be the phandle for the interrupt controller
+  that services interrupts for this device
+- interrupts: Should contain the EHCI interrupt
+
+Example:
+
+	ehci@e1800000 {
+		compatible = "st,spear600-ehci", "usb-ehci";
+		reg = <0xe1800000 0x1000>;
+		interrupt-parent = <&vic1>;
+		interrupts = <27>;
+	};
+
+
+OHCI:
+-----
+
+Required properties:
+- compatible: "st,spear600-ohci"
+- interrupt-parent: Should be the phandle for the interrupt controller
+  that services interrupts for this device
+- interrupts: Should contain the OHCI interrupt
+
+Example:
+
+	ohci@e1900000 {
+		compatible = "st,spear600-ohci", "usb-ohci";
+		reg = <0xe1800000 0x1000>;
+		interrupt-parent = <&vic1>;
+		interrupts = <26>;
+	};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 82ac057..107d8ad 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -8,6 +8,7 @@
 apm	Applied Micro Circuits Corporation (APM)
 arm	ARM Ltd.
 atmel	Atmel Corporation
+bosch	Bosch Sensortec GmbH
 cavium	Cavium, Inc.
 chrp	Common Hardware Reference Platform
 cortina	Cortina Systems, Inc.
diff --git a/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt b/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt
new file mode 100644
index 0000000..7c7f688
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt
@@ -0,0 +1,13 @@
+* NXP PNX watchdog timer
+
+Required properties:
+- compatible: must be "nxp,pnx4008-wdt"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+Example:
+
+	watchdog@4003C000 {
+		compatible = "nxp,pnx4008-wdt";
+		reg = <0x4003C000 0x1000>;
+	};
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index d1d4a17..fbb2411 100755
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -28,7 +28,8 @@
 		"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
 		"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
 		"lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
-		"drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137");
+		"drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137",
+		"drxk_pctv");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -730,6 +731,23 @@
     "$fwfile";
 }
 
+sub drxk_pctv {
+    my $sourcefile = "PCTV_460e_reference.zip";
+    my $url = "ftp://ftp.pctvsystems.com/TV/driver/PCTV%2070e%2080e%20100e%20320e%20330e%20800e/";
+    my $hash = "4403de903bf2593464c8d74bbc200a57";
+    my $fwfile = "dvb-demod-drxk-pctv.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url . $sourcefile);
+    verify($sourcefile, $hash);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/PCTV\ 70e\ 80e\ 100e\ 320e\ 330e\ 800e/32\ bit/emOEM.sys", 0x72b80, 42692, $fwfile);
+
+    "$fwfile";
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
diff --git a/Documentation/dvb/opera-firmware.txt b/Documentation/dvb/opera-firmware.txt
index 93e784c..fb66831 100644
--- a/Documentation/dvb/opera-firmware.txt
+++ b/Documentation/dvb/opera-firmware.txt
@@ -8,7 +8,7 @@
 
 Then run
 
-./get_dvb_firware opera1
+./get_dvb_firmware opera1
 
 and after that you have 2 files:
 
@@ -24,4 +24,4 @@
 in kernel config and have hotplug running).
 
 
-Marco Gittler <g.marco@freenet.de>
\ No newline at end of file
+Marco Gittler <g.marco@freenet.de>
diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt
index 74e6c77..6e16849 100644
--- a/Documentation/dynamic-debug-howto.txt
+++ b/Documentation/dynamic-debug-howto.txt
@@ -2,17 +2,17 @@
 Introduction
 ============
 
-This document describes how to use the dynamic debug (ddebug) feature.
+This document describes how to use the dynamic debug (dyndbg) feature.
 
-Dynamic debug is designed to allow you to dynamically enable/disable kernel
-code to obtain additional kernel information. Currently, if
-CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_dbg() calls can be
-dynamically enabled per-callsite.
+Dynamic debug is designed to allow you to dynamically enable/disable
+kernel code to obtain additional kernel information.  Currently, if
+CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_dbg() calls can
+be dynamically enabled per-callsite.
 
 Dynamic debug has even more useful features:
 
- * Simple query language allows turning on and off debugging statements by
-   matching any combination of 0 or 1 of:
+ * Simple query language allows turning on and off debugging
+   statements by matching any combination of 0 or 1 of:
 
    - source filename
    - function name
@@ -20,17 +20,19 @@
    - module name
    - format string
 
- * Provides a debugfs control file: <debugfs>/dynamic_debug/control which can be
-   read to display the complete list of known debug statements, to help guide you
+ * Provides a debugfs control file: <debugfs>/dynamic_debug/control
+   which can be read to display the complete list of known debug
+   statements, to help guide you
 
 Controlling dynamic debug Behaviour
 ===================================
 
 The behaviour of pr_debug()/dev_dbg()s are controlled via writing to a
-control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs
-filesystem, in order to make use of this feature. Subsequently, we refer to the
-control file as: <debugfs>/dynamic_debug/control. For example, if you want to
-enable printing from source file 'svcsock.c', line 1603 you simply do:
+control file in the 'debugfs' filesystem. Thus, you must first mount
+the debugfs filesystem, in order to make use of this feature.
+Subsequently, we refer to the control file as:
+<debugfs>/dynamic_debug/control. For example, if you want to enable
+printing from source file 'svcsock.c', line 1603 you simply do:
 
 nullarbor:~ # echo 'file svcsock.c line 1603 +p' >
 				<debugfs>/dynamic_debug/control
@@ -44,15 +46,15 @@
 Viewing Dynamic Debug Behaviour
 ===========================
 
-You can view the currently configured behaviour of all the debug statements
-via:
+You can view the currently configured behaviour of all the debug
+statements via:
 
 nullarbor:~ # cat <debugfs>/dynamic_debug/control
 # filename:lineno [module]function flags format
-/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup - "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
-/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init - "\011max_inline       : %d\012"
-/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init - "\011sq_depth         : %d\012"
-/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init - "\011max_requests     : %d\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup =_ "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline       : %d\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth         : %d\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests     : %d\012"
 ...
 
 
@@ -65,12 +67,12 @@
 nullarbor:~ # grep -i tcp <debugfs>/dynamic_debug/control | wc -l
 42
 
-Note in particular that the third column shows the enabled behaviour
-flags for each debug statement callsite (see below for definitions of the
-flags).  The default value, no extra behaviour enabled, is "-".  So
-you can view all the debug statement callsites with any non-default flags:
+The third column shows the currently enabled flags for each debug
+statement callsite (see below for definitions of the flags).  The
+default value, with no flags enabled, is "=_".  So you can view all
+the debug statement callsites with any non-default flags:
 
-nullarbor:~ # awk '$3 != "-"' <debugfs>/dynamic_debug/control
+nullarbor:~ # awk '$3 != "=_"' <debugfs>/dynamic_debug/control
 # filename:lineno [module]function flags format
 /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012"
 
@@ -103,15 +105,14 @@
 
 command ::= match-spec* flags-spec
 
-The match-spec's are used to choose a subset of the known dprintk()
+The match-spec's are used to choose a subset of the known pr_debug()
 callsites to which to apply the flags-spec.  Think of them as a query
 with implicit ANDs between each pair.  Note that an empty list of
-match-specs is possible, but is not very useful because it will not
-match any debug statement callsites.
+match-specs will select all debug statement callsites.
 
-A match specification comprises a keyword, which controls the attribute
-of the callsite to be compared, and a value to compare against.  Possible
-keywords are:
+A match specification comprises a keyword, which controls the
+attribute of the callsite to be compared, and a value to compare
+against.  Possible keywords are:
 
 match-spec ::= 'func' string |
 	       'file' string |
@@ -164,15 +165,15 @@
     characters (") or single quote characters (').
     Examples:
 
-    format svcrdma:	    // many of the NFS/RDMA server dprintks
-    format readahead	    // some dprintks in the readahead cache
+    format svcrdma:	    // many of the NFS/RDMA server pr_debugs
+    format readahead	    // some pr_debugs in the readahead cache
     format nfsd:\040SETATTR // one way to match a format with whitespace
     format "nfsd: SETATTR"  // a neater way to match a format with whitespace
     format 'nfsd: SETATTR'  // yet another way to match a format with whitespace
 
 line
     The given line number or range of line numbers is compared
-    against the line number of each dprintk() callsite.  A single
+    against the line number of each pr_debug() callsite.  A single
     line number matches the callsite line number exactly.  A
     range of line numbers matches any callsite between the first
     and last line number inclusive.  An empty first number means
@@ -188,51 +189,93 @@
 by one or more flag characters.  The change operation is one
 of the characters:
 
--
-    remove the given flags
-
-+
-    add the given flags
-
-=
-    set the flags to the given flags
+  -    remove the given flags
+  +    add the given flags
+  =    set the flags to the given flags
 
 The flags are:
 
-f
-    Include the function name in the printed message
-l
-    Include line number in the printed message
-m
-    Include module name in the printed message
-p
-    Causes a printk() message to be emitted to dmesg
-t
-    Include thread ID in messages not generated from interrupt context
+  p    enables the pr_debug() callsite.
+  f    Include the function name in the printed message
+  l    Include line number in the printed message
+  m    Include module name in the printed message
+  t    Include thread ID in messages not generated from interrupt context
+  _    No flags are set. (Or'd with others on input)
 
-Note the regexp ^[-+=][flmpt]+$ matches a flags specification.
-Note also that there is no convenient syntax to remove all
-the flags at once, you need to use "-flmpt".
+For display, the flags are preceded by '='
+(mnemonic: what the flags are currently equal to).
+
+Note the regexp ^[-+=][flmpt_]+$ matches a flags specification.
+To clear all flags at once, use "=_" or "-flmpt".
 
 
-Debug messages during boot process
+Debug messages during Boot Process
 ==================================
 
-To be able to activate debug messages during the boot process,
-even before userspace and debugfs exists, use the boot parameter:
-ddebug_query="QUERY"
+To activate debug messages for core code and built-in modules during
+the boot process, even before userspace and debugfs exists, use
+dyndbg="QUERY", module.dyndbg="QUERY", or ddebug_query="QUERY"
+(ddebug_query is obsoleted by dyndbg, and deprecated).  QUERY follows
+the syntax described above, but must not exceed 1023 characters.  Your
+bootloader may impose lower limits.
 
-QUERY follows the syntax described above, but must not exceed 1023
-characters. The enablement of debug messages is done as an arch_initcall.
-Thus you can enable debug messages in all code processed after this
-arch_initcall via this boot parameter.
+These dyndbg params are processed just after the ddebug tables are
+processed, as part of the arch_initcall.  Thus you can enable debug
+messages in all code run after this arch_initcall via this boot
+parameter.
+
 On an x86 system for example ACPI enablement is a subsys_initcall and
-ddebug_query="file ec.c +p"
+   dyndbg="file ec.c +p"
 will show early Embedded Controller transactions during ACPI setup if
 your machine (typically a laptop) has an Embedded Controller.
 PCI (or other devices) initialization also is a hot candidate for using
 this boot parameter for debugging purposes.
 
+If foo module is not built-in, foo.dyndbg will still be processed at
+boot time, without effect, but will be reprocessed when module is
+loaded later.  dyndbg_query= and bare dyndbg= are only processed at
+boot.
+
+
+Debug Messages at Module Initialization Time
+============================================
+
+When "modprobe foo" is called, modprobe scans /proc/cmdline for
+foo.params, strips "foo.", and passes them to the kernel along with
+params given in modprobe args or /etc/modprob.d/*.conf files,
+in the following order:
+
+1. # parameters given via /etc/modprobe.d/*.conf
+   options foo dyndbg=+pt
+   options foo dyndbg # defaults to +p
+
+2. # foo.dyndbg as given in boot args, "foo." is stripped and passed
+   foo.dyndbg=" func bar +p; func buz +mp"
+
+3. # args to modprobe
+   modprobe foo dyndbg==pmf # override previous settings
+
+These dyndbg queries are applied in order, with last having final say.
+This allows boot args to override or modify those from /etc/modprobe.d
+(sensible, since 1 is system wide, 2 is kernel or boot specific), and
+modprobe args to override both.
+
+In the foo.dyndbg="QUERY" form, the query must exclude "module foo".
+"foo" is extracted from the param-name, and applied to each query in
+"QUERY", and only 1 match-spec of each type is allowed.
+
+The dyndbg option is a "fake" module parameter, which means:
+
+- modules do not need to define it explicitly
+- every module gets it tacitly, whether they use pr_debug or not
+- it doesnt appear in /sys/module/$module/parameters/
+  To see it, grep the control file, or inspect /proc/cmdline.
+
+For CONFIG_DYNAMIC_DEBUG kernels, any settings given at boot-time (or
+enabled by -DDEBUG flag during compilation) can be disabled later via
+the sysfs interface if the debug messages are no longer needed:
+
+   echo "module module_name -p" > <debugfs>/dynamic_debug/control
 
 Examples
 ========
@@ -260,3 +303,18 @@
 // enable messages for NFS calls READ, READLINK, READDIR and READDIR+.
 nullarbor:~ # echo -n 'format "nfsd: READ" +p' >
 				<debugfs>/dynamic_debug/control
+
+// enable all messages
+nullarbor:~ # echo -n '+p' > <debugfs>/dynamic_debug/control
+
+// add module, function to all enabled messages
+nullarbor:~ # echo -n '+mf' > <debugfs>/dynamic_debug/control
+
+// boot-args example, with newlines and comments for readability
+Kernel command line: ...
+  // see whats going on in dyndbg=value processing
+  dynamic_debug.verbose=1
+  // enable pr_debugs in 2 builtins, #cmt is stripped
+  dyndbg="module params +p #cmt ; module sys +p"
+  // enable pr_debugs in 2 functions in a module loaded later
+  pc87360.dyndbg="func pc87360_init_device +p; func pc87360_find +p"
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index fdcc49f..03df2b0 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -734,7 +734,7 @@
    associated with a physical CPU socket.
 
    Each MC have 3 physical read channels, 3 physical write channels and
-   3 logic channels. The driver currenty sees it as just 3 channels.
+   3 logic channels. The driver currently sees it as just 3 channels.
    Each channel can have up to 3 DIMMs.
 
    The minimum known unity is DIMMs. There are no information about csrows.
diff --git a/Documentation/eisa.txt b/Documentation/eisa.txt
index 38cf0c7..a55e491 100644
--- a/Documentation/eisa.txt
+++ b/Documentation/eisa.txt
@@ -179,7 +179,7 @@
 
 Converting an EISA driver to the new API mostly involves *deleting*
 code (since probing is now in the core EISA code). Unfortunately, most
-drivers share their probing routine between ISA, MCA and EISA. Special
+drivers share their probing routine between ISA, and EISA. Special
 care must be taken when ripping out the EISA code, so other busses
 won't suffer from these surgical strikes...
 
diff --git a/Documentation/extcon/porting-android-switch-class b/Documentation/extcon/porting-android-switch-class
new file mode 100644
index 0000000..eb0fa5f
--- /dev/null
+++ b/Documentation/extcon/porting-android-switch-class
@@ -0,0 +1,124 @@
+
+	Staging/Android Switch Class Porting Guide
+	(linux/drivers/staging/android/switch)
+	(c) Copyright 2012 Samsung Electronics
+
+AUTHORS
+MyungJoo Ham <myungjoo.ham@samsung.com>
+
+/*****************************************************************
+ * CHAPTER 1.                                                    *
+ * PORTING SWITCH CLASS DEVICE DRIVERS                           *
+ *****************************************************************/
+
+****** STEP 1. Basic Functionality
+	No extcon extended feature, but switch features only.
+
+- struct switch_dev (fed to switch_dev_register/unregister)
+    @name: no change
+    @dev: no change
+    @index: drop (not used in switch device driver side anyway)
+    @state: no change
+	If you have used @state with magic numbers, keep it
+	at this step.
+    @print_name: no change but type change (switch_dev->extcon_dev)
+    @print_state: no change but type change (switch_dev->extcon_dev)
+
+- switch_dev_register(sdev, dev)
+	=> extcon_dev_register(edev, dev)
+	: no change but type change (sdev->edev)
+- switch_dev_unregister(sdev)
+	=> extcon_dev_unregister(edev)
+	: no change but type change (sdev->edev)
+- switch_get_state(sdev)
+	=> extcon_get_state(edev)
+	: no change but type change (sdev->edev) and (return: int->u32)
+- switch_set_state(sdev, state)
+	=> extcon_set_state(edev, state)
+	: no change but type change (sdev->edev) and (state: int->u32)
+
+With this changes, the ex-switch extcon class device works as it once
+worked as switch class device. However, it will now have additional
+interfaces (both ABI and in-kernel API) and different ABI locations.
+However, if CONFIG_ANDROID is enabled without CONFIG_ANDROID_SWITCH,
+/sys/class/switch/* will be symbolically linked to /sys/class/extcon/
+so that they are still compatible with legacy userspace processes.
+
+****** STEP 2. Multistate (no more magic numbers in state value)
+	Extcon's extended features for switch device drivers with
+	complex features usually required magic numbers in state
+	value of switch_dev. With extcon, such magic numbers that
+	support multiple cables (
+
+  1. Define cable names at edev->supported_cable.
+  2. (Recommended) remove print_state callback.
+  3. Use extcon_get_cable_state_(edev, index) or
+   extcon_get_cable_state(edev, cable_name) instead of
+   extcon_get_state(edev) if you intend to get a state of a specific
+   cable. Same for set_state. This way, you can remove the usage of
+   magic numbers in state value.
+  4. Use extcon_update_state() if you are updating specific bits of
+   the state value.
+
+Example: a switch device driver w/ magic numbers for two cables.
+	"0x00": no cables connected.
+	"0x01": cable 1 connected
+	"0x02": cable 2 connected
+	"0x03": cable 1 and 2 connected
+  1. edev->supported_cable = {"1", "2", NULL};
+  2. edev->print_state = NULL;
+  3. extcon_get_cable_state_(edev, 0) shows cable 1's state.
+     extcon_get_cable_state(edev, "1") shows cable 1's state.
+     extcon_set_cable_state_(edev, 1) sets cable 2's state.
+     extcon_set_cable_state(edev, "2") sets cable 2's state
+  4. extcon_update_state(edev, 0x01, 0) sets the least bit's 0.
+
+****** STEP 3. Notify other device drivers
+
+  You can notify others of the cable attach/detach events with
+notifier chains.
+
+  At the side of other device drivers (the extcon device itself
+does not need to get notified of its own events), there are two
+methods to register notifier_block for cable events:
+(a) for a specific cable or (b) for every cable.
+
+  (a) extcon_register_interest(obj, extcon_name, cable_name, nb)
+	Example: want to get news of "MAX8997_MUIC"'s "USB" cable
+
+	obj = kzalloc(sizeof(struct extcon_specific_cable_nb),
+		      GFP_KERNEL);
+	nb->notifier_call = the_callback_to_handle_usb;
+
+	extcon_register_intereset(obj, "MAX8997_MUIC", "USB", nb);
+
+  (b) extcon_register_notifier(edev, nb)
+	Call nb for any changes in edev.
+
+  Please note that in order to properly behave with method (a),
+the extcon device driver should support multistate feature (STEP 2).
+
+****** STEP 4. Inter-cable relation (mutually exclusive)
+
+  You can provide inter-cable mutually exclusiveness information
+for an extcon device. When cables A and B are declared to be mutually
+exclusive, the two cables cannot be in ATTACHED state simulteneously.
+
+
+/*****************************************************************
+ * CHAPTER 2.                                                    *
+ * PORTING USERSPACE w/ SWITCH CLASS DEVICE SUPPORT              *
+ *****************************************************************/
+
+****** ABI Location
+
+  If "CONFIG_ANDROID" is enabled and "CONFIG_ANDROID_SWITCH" is
+disabled, /sys/class/switch/* are created as symbolic links to
+/sys/class/extcon/*. Because CONFIG_ANDROID_SWITCH creates
+/sys/class/switch directory, we disable symboling linking if
+CONFIG_ANDROID_SWITCH is enabled.
+
+  The two files of switch class, name and state, are provided with
+extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is
+not enabled or print_state callback is supplied, the output of
+state ABI is same with switch class.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 04d81d2..50d82ae 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -2,7 +2,14 @@
 removed in the kernel source tree.  Every entry should contain what
 exactly is going away, why it is happening, and who is going to be doing
 the work.  When the feature is removed from the kernel, it should also
-be removed from this file.
+be removed from this file.  The suggested deprecation period is 3 releases.
+
+---------------------------
+
+What:	ddebug_query="query" boot cmdline param
+When:	v3.8
+Why:	obsoleted by dyndbg="query" and module.dyndbg="query"
+Who:	Jim Cromie <jim.cromie@gmail.com>, Jason Baron <jbaron@redhat.com>
 
 ---------------------------
 
@@ -554,6 +561,15 @@
 
 ----------------------------
 
+What:	remove bogus DV presets V4L2_DV_1080I29_97, V4L2_DV_1080I30 and
+	V4L2_DV_1080I25
+When:	3.6
+Why:	These HDTV formats do not exist and were added by a confused mind
+	(that was me, to be precise...)
+Who:	Hans Verkuil <hans.verkuil@cisco.com>
+
+----------------------------
+
 What:	V4L2_CID_HCENTER, V4L2_CID_VCENTER V4L2 controls
 When:	3.7
 Why:	The V4L2_CID_VCENTER, V4L2_CID_HCENTER controls have been deprecated
@@ -561,3 +577,14 @@
 	There are newer controls (V4L2_CID_PAN*, V4L2_CID_TILT*) that provide
 	similar	functionality.
 Who:	Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
+
+----------------------------
+
+What:	cgroup option updates via remount
+When:	March 2013
+Why:	Remount currently allows changing bound subsystems and
+	release_agent.  Rebinding is hardly useful as it only works
+	when the hierarchy is empty and release_agent itself should be
+	replaced with conventional fsnotify.
+
+----------------------------
diff --git a/Documentation/filesystems/nfs/pnfs.txt b/Documentation/filesystems/nfs/pnfs.txt
index c7919c6..52ae07f 100644
--- a/Documentation/filesystems/nfs/pnfs.txt
+++ b/Documentation/filesystems/nfs/pnfs.txt
@@ -93,7 +93,7 @@
 				(allways exists)
 				(More protocols can be defined in the future.
 				 The client does not interpret this string it is
-				 passed unchanged as recieved from the Server)
+				 passed unchanged as received from the Server)
 		-o		osdname of the requested target OSD
 				(Might be empty)
 				(A string which denotes the OSD name, there is a
diff --git a/Documentation/filesystems/qnx6.txt b/Documentation/filesystems/qnx6.txt
index 050223e..e59f2f0 100644
--- a/Documentation/filesystems/qnx6.txt
+++ b/Documentation/filesystems/qnx6.txt
@@ -17,7 +17,7 @@
 On QNX it is possible to create little endian and big endian qnx6 filesystems.
 This feature makes it possible to create and use a different endianness fs
 for the target (QNX is used on quite a range of embedded systems) plattform
-running on a different endianess.
+running on a different endianness.
 The Linux driver handles endianness transparently. (LE and BE)
 
 Blocks
@@ -26,7 +26,7 @@
 The space in the device or file is split up into blocks. These are a fixed
 size of 512, 1024, 2048 or 4096, which is decided when the filesystem is
 created.
-Blockpointers are 32bit, so the maximum space that can be adressed is
+Blockpointers are 32bit, so the maximum space that can be addressed is
 2^32 * 4096 bytes or 16TB
 
 The superblocks
@@ -47,16 +47,16 @@
 Each superblock holds a set of root inodes for the different filesystem
 parts. (Inode, Bitmap and Longfilenames)
 Each of these root nodes holds information like total size of the stored
-data and the adressing levels in that specific tree.
-If the level value is 0, up to 16 direct blocks can be adressed by each
+data and the addressing levels in that specific tree.
+If the level value is 0, up to 16 direct blocks can be addressed by each
 node.
-Level 1 adds an additional indirect adressing level where each indirect
-adressing block holds up to blocksize / 4 bytes pointers to data blocks.
-Level 2 adds an additional indirect adressig block level (so, already up
-to 16 * 256 * 256 = 1048576 blocks that can be adressed by such a tree)a
+Level 1 adds an additional indirect addressing level where each indirect
+addressing block holds up to blocksize / 4 bytes pointers to data blocks.
+Level 2 adds an additional indirect addressing block level (so, already up
+to 16 * 256 * 256 = 1048576 blocks that can be addressed by such a tree).
 
 Unused block pointers are always set to ~0 - regardless of root node,
-indirect adressing blocks or inodes.
+indirect addressing blocks or inodes.
 Data leaves are always on the lowest level. So no data is stored on upper
 tree levels.
 
@@ -64,7 +64,7 @@
 The Audi MMI 3G first superblock directly starts at byte 0.
 Second superblock position can either be calculated from the superblock
 information (total number of filesystem blocks) or by taking the highest
-device address, zeroing the last 3 bytes and then substracting 0x1000 from
+device address, zeroing the last 3 bytes and then subtracting 0x1000 from
 that address.
 
 0x1000 is the size reserved for each superblock - regardless of the
@@ -83,8 +83,8 @@
 Object mode field is POSIX format. (which makes things easier)
 
 There are also pointers to the first 16 blocks, if the object data can be
-adressed with 16 direct blocks.
-For more than 16 blocks an indirect adressing in form of another tree is
+addressed with 16 direct blocks.
+For more than 16 blocks an indirect addressing in form of another tree is
 used. (scheme is the same as the one used for the superblock root nodes)
 
 The filesize is stored 64bit. Inode counting starts with 1. (whilst long
@@ -118,13 +118,13 @@
 inode.
 
 Character and block special devices do not exist in QNX as those files
-are handled by the QNX kernel/drivers and created in /dev independant of the
+are handled by the QNX kernel/drivers and created in /dev independent of the
 underlaying filesystem.
 
 Long filenames
 --------------
 
-Long filenames are stored in a seperate adressing tree. The staring point
+Long filenames are stored in a separate addressing tree. The staring point
 is the longfilename root node in the active superblock.
 Each data block (tree leaves) holds one long filename. That filename is
 limited to 510 bytes. The first two starting bytes are used as length field
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
new file mode 100644
index 0000000..f50a6cc
--- /dev/null
+++ b/Documentation/hwmon/ina2xx
@@ -0,0 +1,29 @@
+Kernel driver ina2xx
+====================
+
+Supported chips:
+  * Texas Instruments INA219
+    Prefix: 'ina219'
+    Addresses: I2C 0x40 - 0x4f
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/
+
+  * Texas Instruments INA226
+    Prefix: 'ina226'
+    Addresses: I2C 0x40 - 0x4f
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/
+
+Author: Lothar Felten <l-felten@ti.com>
+
+Description
+-----------
+
+The INA219 is a high-side current shunt and power monitor with an I2C
+interface. The INA219 monitors both shunt drop and supply voltage, with
+programmable conversion times and filtering.
+
+The INA226 is a current shunt and power monitor with an I2C interface.
+The INA226 monitors both a shunt voltage drop and bus supply voltage.
+
+The shunt value in micro-ohms can be set via platform data.
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
index 23b7def2..87850d8 100644
--- a/Documentation/hwmon/it87
+++ b/Documentation/hwmon/it87
@@ -30,6 +30,14 @@
     Prefix: 'it8728'
     Addresses scanned: from Super I/O config space (8 I/O ports)
     Datasheet: Not publicly available
+  * IT8782F
+    Prefix: 'it8782'
+    Addresses scanned: from Super I/O config space (8 I/O ports)
+    Datasheet: Not publicly available
+  * IT8783E/F
+    Prefix: 'it8783'
+    Addresses scanned: from Super I/O config space (8 I/O ports)
+    Datasheet: Not publicly available
   * SiS950   [clone of IT8705F]
     Prefix: 'it87'
     Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -63,7 +71,7 @@
 Hardware Interfaces
 -------------------
 
-All the chips suported by this driver are LPC Super-I/O chips, accessed
+All the chips supported by this driver are LPC Super-I/O chips, accessed
 through the LPC bus (ISA-like I/O ports). The IT8712F additionally has an
 SMBus interface to the hardware monitoring functions. This driver no
 longer supports this interface though, as it is slower and less reliable
@@ -75,7 +83,8 @@
 -----------
 
 This driver implements support for the IT8705F, IT8712F, IT8716F,
-IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E and SiS950 chips.
+IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8781F, IT8782F,
+IT8783E/F, and SiS950 chips.
 
 These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
 joysticks and other miscellaneous stuff. For hardware monitoring, they
@@ -99,11 +108,11 @@
 have support for 2 additional fans. The additional fans are supported by the
 driver.
 
-The IT8716F, IT8718F, IT8720F and IT8721F/IT8758E, and late IT8712F and
-IT8705F also have optional 16-bit tachometer counters for fans 1 to 3. This
-is better (no more fan clock divider mess) but not compatible with the older
-chips and revisions. The 16-bit tachometer mode is enabled by the driver when
-one of the above chips is detected.
+The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8782F, IT8783E/F, and late
+IT8712F and IT8705F also have optional 16-bit tachometer counters for fans 1 to
+3. This is better (no more fan clock divider mess) but not compatible with the
+older chips and revisions. The 16-bit tachometer mode is enabled by the driver
+when one of the above chips is detected.
 
 The IT8726F is just bit enhanced IT8716F with additional hardware
 for AMD power sequencing. Therefore the chip will appear as IT8716F
@@ -131,9 +140,10 @@
 0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery
 voltage in8 does not have limit registers.
 
-On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside
-the chip (in7, in8 and optionally in3). The driver handles this transparently
-so user-space doesn't have to care.
+On the IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs are
+internal and scaled inside the chip (in7 (optional for IT8782F and IT8783E/F),
+in8 and optionally in3). The driver handles this transparently so user-space
+doesn't have to care.
 
 The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value:
 the voltage level your processor should work with. This is hardcoded by
diff --git a/Documentation/hwmon/wm831x b/Documentation/hwmon/wm831x
index 24f47d8..1144675 100644
--- a/Documentation/hwmon/wm831x
+++ b/Documentation/hwmon/wm831x
@@ -22,7 +22,7 @@
 Voltage Monitoring
 ------------------
 
-Voltages are sampled by a 12 bit ADC.  Voltages in milivolts are 1.465
+Voltages are sampled by a 12 bit ADC.  Voltages in millivolts are 1.465
 times the ADC value.
 
 Temperature Monitoring
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index e34b531d..915f28c 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -120,6 +120,7 @@
 'G'	00-0F	linux/gigaset_dev.h	conflict!
 'H'	00-7F	linux/hiddev.h		conflict!
 'H'	00-0F	linux/hidraw.h		conflict!
+'H'	01	linux/mei.h		conflict!
 'H'	00-0F	sound/asound.h		conflict!
 'H'	20-40	sound/asound_fm.h	conflict!
 'H'	80-8F	sound/sfnt_info.h	conflict!
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index e275432..5b6e584 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -70,7 +70,6 @@
 	M68k	M68k architecture is enabled.
 			These options have more detailed description inside of
 			Documentation/m68k/kernel-options.txt.
-	MCA	MCA bus support is enabled.
 	MDA	MDA console support is enabled.
 	MIPS	MIPS architecture is enabled.
 	MOUSE	Appropriate mouse support is enabled.
@@ -611,7 +610,7 @@
 
 	ddebug_query=   [KNL,DYNAMIC_DEBUG] Enable debug messages at early boot
 			time. See Documentation/dynamic-debug-howto.txt for
-			details.
+			details.  Deprecated, see dyndbg.
 
 	debug		[KNL] Enable kernel debugging (events log level).
 
@@ -731,6 +730,11 @@
 
 	dscc4.setup=	[NET]
 
+	dyndbg[="val"]		[KNL,DYNAMIC_DEBUG]
+	module.dyndbg[="val"]
+			Enable debug messages at boot time.  See
+			Documentation/dynamic-debug-howto.txt for details.
+
 	earlycon=	[KNL] Output early console device and options.
 		uart[8250],io,<addr>[,options]
 		uart[8250],mmio,<addr>[,options]
@@ -2458,6 +2462,8 @@
 
 	resume=		[SWSUSP]
 			Specify the partition device for software suspend
+			Format:
+			{/dev/<dev> | PARTUUID=<uuid> | <int>:<int> | <hex>}
 
 	resume_offset=	[SWSUSP]
 			Specify the offset from the beginning of the partition
diff --git a/Documentation/mca.txt b/Documentation/mca.txt
deleted file mode 100644
index dfd130c..0000000
--- a/Documentation/mca.txt
+++ /dev/null
@@ -1,313 +0,0 @@
-i386 Micro Channel Architecture Support
-=======================================
-
-MCA support is enabled using the CONFIG_MCA define.  A machine with a MCA
-bus will have the kernel variable MCA_bus set, assuming the BIOS feature
-bits are set properly (see arch/i386/boot/setup.S for information on
-how this detection is done).
-
-Adapter Detection
-=================
-
-The ideal MCA adapter detection is done through the use of the
-Programmable Option Select registers.  Generic functions for doing
-this have been added in include/linux/mca.h and arch/x86/kernel/mca_32.c.
-Everything needed to detect adapters and read (and write) configuration
-information is there.  A number of MCA-specific drivers already use
-this.  The typical probe code looks like the following:
-
-	#include <linux/mca.h>
-
-	unsigned char pos2, pos3, pos4, pos5;
-	struct net_device* dev;
-	int slot;
-
-	if( MCA_bus ) {
-		slot = mca_find_adapter( ADAPTER_ID, 0 );
-		if( slot == MCA_NOTFOUND ) {
-			return -ENODEV;
-		}
-		/* optional - see below */
-		mca_set_adapter_name( slot, "adapter name & description" );
-		mca_set_adapter_procfn( slot, dev_getinfo, dev );
-
-		/* read the POS registers.  Most devices only use 2 and 3 */
-		pos2 = mca_read_stored_pos( slot, 2 );
-		pos3 = mca_read_stored_pos( slot, 3 );
-		pos4 = mca_read_stored_pos( slot, 4 );
-		pos5 = mca_read_stored_pos( slot, 5 );
-	} else {
-		return -ENODEV;
-	}
-
-	/* extract configuration from pos[2345] and set everything up */
-
-Loadable modules should modify this to test that the specified IRQ and
-IO ports (plus whatever other stuff) match.  See 3c523.c for example
-code (actually, smc-mca.c has a slightly more complex example that can
-handle a list of adapter ids).
-
-Keep in mind that devices should never directly access the POS registers
-(via inb(), outb(), etc).  While it's generally safe, there is a small
-potential for blowing up hardware when it's done at the wrong time.
-Furthermore, accessing a POS register disables a device temporarily.
-This is usually okay during startup, but do _you_ want to rely on it?
-During initial configuration, mca_init() reads all the POS registers
-into memory.  mca_read_stored_pos() accesses that data.  mca_read_pos()
-and mca_write_pos() are also available for (safer) direct POS access,
-but their use is _highly_ discouraged.  mca_write_pos() is particularly
-dangerous, as it is possible for adapters to be put in inconsistent
-states (i.e. sharing IO address, etc) and may result in crashes, toasted
-hardware, and blindness.
-
-User level drivers (such as the AGX X server) can use /proc/mca/pos to
-find adapters (see below).
-
-Some MCA adapters can also be detected via the usual ISA-style device
-probing (many SCSI adapters, for example).  This sort of thing is highly
-discouraged.  Perfectly good information is available telling you what's
-there, so there's no excuse for messing with random IO ports.  However,
-we MCA people still appreciate any ISA-style driver that will work with
-our hardware.  You take what you can get...
-
-Level-Triggered Interrupts
-==========================
-
-Because MCA uses level-triggered interrupts, a few problems arise with
-what might best be described as the ISA mindset and its effects on
-drivers.  These sorts of problems are expected to become less common as
-more people use shared IRQs on PCI machines.
-
-In general, an interrupt must be acknowledged not only at the ICU (which
-is done automagically by the kernel), but at the device level.  In
-particular, IRQ 0 must be reset after a timer interrupt (now done in
-arch/x86/kernel/time.c) or the first timer interrupt hangs the system.
-There were also problems with the 1.3.x floppy drivers, but that seems
-to have been fixed.
-
-IRQs are also shareable, and most MCA-specific devices should be coded
-with shared IRQs in mind.
-
-/proc/mca
-=========
-
-/proc/mca is a directory containing various files for adapters and
-other stuff.
-
-	/proc/mca/pos		Straight listing of POS registers
-	/proc/mca/slot[1-8]	Information on adapter in specific slot
-	/proc/mca/video		Same for integrated video
-	/proc/mca/scsi		Same for integrated SCSI
-	/proc/mca/machine	Machine information
-
-See Appendix A for a sample.
-
-Device drivers can easily add their own information function for
-specific slots (including integrated ones) via the
-mca_set_adapter_procfn() call.  Drivers that support this are ESDI, IBM
-SCSI, and 3c523.  If a device is also a module, make sure that the proc
-function is removed in the module cleanup.  This will require storing
-the slot information in a private structure somewhere.  See the 3c523
-driver for details.
-
-Your typical proc function will look something like this:
-
-	static int
-	dev_getinfo( char* buf, int slot, void* d ) {
-		struct net_device* dev = (struct net_device*) d;
-		int len = 0;
-
-		len += sprintf( buf+len, "Device: %s\n", dev->name );
-		len += sprintf( buf+len, "IRQ: %d\n", dev->irq );
-		len += sprintf( buf+len, "IO Port: %#lx-%#lx\n", ... );
-		...
-
-		return len;
-	}
-
-Some of the standard MCA information will already be printed, so don't
-bother repeating it.  Don't try putting in more than 3K of information.
-
-Enable this function with:
-	mca_set_adapter_procfn( slot, dev_getinfo, dev );
-
-Disable it with:
-	mca_set_adapter_procfn( slot, NULL, NULL );
-
-It is also recommended that, even if you don't write a proc function, to
-set the name of the adapter (i.e. "PS/2 ESDI Controller") via
-mca_set_adapter_name( int slot, char* name ).
-
-MCA Device Drivers
-==================
-
-Currently, there are a number of MCA-specific device drivers.
-
-1) PS/2 SCSI
-	drivers/scsi/ibmmca.c
-	drivers/scsi/ibmmca.h
-   The driver for the IBM SCSI subsystem.  Includes both integrated
-   controllers and adapter cards.  May require command-line arg
-   "ibmmcascsi=io_port" to force detection of an adapter.  If you have a
-   machine with a front-panel display (i.e. model 95), you can use
-   "ibmmcascsi=display" to enable a drive activity indicator.
-
-2) 3c523
-	drivers/net/3c523.c
-	drivers/net/3c523.h
-   3Com 3c523 Etherlink/MC ethernet driver.
-
-3) SMC Ultra/MCA and IBM Adapter/A
-	drivers/net/smc-mca.c
-	drivers/net/smc-mca.h
-	Driver for the MCA version of the SMC Ultra and various other
-	OEM'ed and work-alike cards (Elite, Adapter/A, etc).
-
-4) NE/2
-	driver/net/ne2.c
-	driver/net/ne2.h
-	The NE/2 is the MCA version of the NE2000.  This may not work
-	with clones that have a different adapter id than the original
-	NE/2.
-
-5) Future Domain MCS-600/700, OEM'd IBM Fast SCSI Adapter/A and
-   Reply Sound Blaster/SCSI (SCSI part)
-	Better support for these cards than the driver for ISA.
-   Supports multiple cards with IRQ sharing.
-
-Also added boot time option of scsi-probe, which can do reordering of
-SCSI host adapters. This will direct the kernel on the order which
-SCSI adapter should be detected. Example:
-  scsi-probe=ibmmca,fd_mcs,adaptec1542,buslogic
-
-The serial drivers were modified to support the extended IO port range
-of the typical MCA system (also #ifdef CONFIG_MCA).
-
-The following devices work with existing drivers:
-1) Token-ring
-2) Future Domain SCSI (MCS-600, MCS-700, not MCS-350, OEM'ed IBM SCSI)
-3) Adaptec 1640 SCSI (using the aha1542 driver)
-4) Bustek/Buslogic SCSI (various)
-5) Probably all Arcnet cards.
-6) Some, possibly all, MCA IDE controllers.
-7) 3Com 3c529 (MCA version of 3c509) (patched)
-
-8) Intel EtherExpressMC  (patched version)
-   You need to have CONFIG_MCA defined to have EtherExpressMC support.
-9) Reply Sound Blaster/SCSI (SB part) (patched version)
-
-Bugs & Other Weirdness
-======================
-
-NMIs tend to occur with MCA machines because of various hardware
-weirdness, bus timeouts, and many other non-critical things.  Some basic
-code to handle them (inspired by the NetBSD MCA code) has been added to
-detect the guilty device, but it's pretty incomplete.  If NMIs are a
-persistent problem (on some model 70 or 80s, they occur every couple
-shell commands), the CONFIG_IGNORE_NMI flag will take care of that.
-
-Various Pentium machines have had serious problems with the FPU test in
-bugs.h.  Basically, the machine hangs after the HLT test.  This occurs,
-as far as we know, on the Pentium-equipped 85s, 95s, and some PC Servers.
-The PCI/MCA PC 750s are fine as far as I can tell.  The ``mca-pentium''
-boot-prompt flag will disable the FPU bug check if this is a problem
-with your machine.
-
-The model 80 has a raft of problems that are just too weird and unique
-to get into here.  Some people have no trouble while others have nothing
-but problems.  I'd suspect some problems are related to the age of the
-average 80 and accompanying hardware deterioration, although others
-are definitely design problems with the hardware.  Among the problems
-include SCSI controller problems, ESDI controller problems, and serious
-screw-ups in the floppy controller.  Oh, and the parallel port is also
-pretty flaky.  There were about 5 or 6 different model 80 motherboards
-produced to fix various obscure problems.  As far as I know, it's pretty
-much impossible to tell which bugs a particular model 80 has (other than
-triggering them, that is).
-
-Drivers are required for some MCA memory adapters.  If you're suddenly
-short a few megs of RAM, this might be the reason.  The (I think) Enhanced
-Memory Adapter commonly found on the model 70 is one.  There's a very
-alpha driver floating around, but it's pretty ugly (disassembled from
-the DOS driver, actually).  See the MCA Linux web page (URL below)
-for more current memory info.
-
-The Thinkpad 700 and 720 will work, but various components are either
-non-functional, flaky, or we don't know anything about them.  The
-graphics controller is supposed to be some WD, but we can't get things
-working properly.  The PCMCIA slots don't seem to work.  Ditto for APM.
-The serial ports work, but detection seems to be flaky.
-
-Credits
-=======
-A whole pile of people have contributed to the MCA code.  I'd include
-their names here, but I don't have a list handy.  Check the MCA Linux
-home page (URL below) for a perpetually out-of-date list.
-
-=====================================================================
-MCA Linux Home Page: http://www.dgmicro.com/mca/
-
-Christophe Beauregard
-chrisb@truespectra.com
-cpbeaure@calum.csclub.uwaterloo.ca
-
-=====================================================================
-Appendix A: Sample /proc/mca
-
-This is from my model 8595.  Slot 1 contains the standard IBM SCSI
-adapter, slot 3 is an Adaptec AHA-1640, slot 5 is a XGA-1 video adapter,
-and slot 7 is the 3c523 Etherlink/MC.
-
-/proc/mca/machine:
-Model Id: 0xf8
-Submodel Id: 0x14
-BIOS Revision: 0x5
-
-/proc/mca/pos:
-Slot 1: ff 8e f1 fc a0 ff ff ff  IBM SCSI Adapter w/Cache
-Slot 2: ff ff ff ff ff ff ff ff  
-Slot 3: 1f 0f 81 3b bf b6 ff ff  
-Slot 4: ff ff ff ff ff ff ff ff  
-Slot 5: db 8f 1d 5e fd c0 00 00  
-Slot 6: ff ff ff ff ff ff ff ff  
-Slot 7: 42 60 ff 08 ff ff ff ff  3Com 3c523 Etherlink/MC
-Slot 8: ff ff ff ff ff ff ff ff  
-Video : ff ff ff ff ff ff ff ff  
-SCSI  : ff ff ff ff ff ff ff ff  
-
-/proc/mca/slot1:
-Slot: 1
-Adapter Name: IBM SCSI Adapter w/Cache
-Id: 8eff
-Enabled: Yes
-POS: ff 8e f1 fc a0 ff ff ff 
-Subsystem PUN: 7
-Detected at boot: Yes
-
-/proc/mca/slot3:
-Slot: 3
-Adapter Name: Unknown
-Id: 0f1f
-Enabled: Yes
-POS: 1f 0f 81 3b bf b6 ff ff 
-
-/proc/mca/slot5:
-Slot: 5
-Adapter Name: Unknown
-Id: 8fdb
-Enabled: Yes
-POS: db 8f 1d 5e fd c0 00 00 
-
-/proc/mca/slot7:
-Slot: 7
-Adapter Name: 3Com 3c523 Etherlink/MC
-Id: 6042
-Enabled: Yes
-POS: 42 60 ff 08 ff ff ff ff 
-Revision: 0xe
-IRQ: 9
-IO Address: 0x3300-0x3308
-Memory: 0xd8000-0xdbfff
-Transceiver: External
-Device: eth0
-Hardware Address: 02 60 8c 45 c4 2a
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 3a0f879..8028754 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -335,6 +335,9 @@
 Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must
 be identical for all nested calls to the function.
 
+media_entity_pipeline_start() may return an error. In that case, it will
+clean up any the changes it did by itself.
+
 When stopping the stream, drivers must notify the entities with
 
 	media_entity_pipeline_stop(struct media_entity *entity);
@@ -351,3 +354,19 @@
 changing entities configuration parameters) drivers can explicitly check the
 media_entity stream_count field to find out if an entity is streaming. This
 operation must be done with the media_device graph_mutex held.
+
+
+Link validation
+---------------
+
+Link validation is performed by media_entity_pipeline_start() for any
+entity which has sink pads in the pipeline. The
+media_entity::link_validate() callback is used for that purpose. In
+link_validate() callback, entity driver should check that the properties of
+the source pad of the connected entity and its own sink pad match. It is up
+to the type of the entity (and in the end, the properties of the hardware)
+what matching actually means.
+
+Subsystems should facilitate link validation by providing subsystem specific
+helper functions to provide easy access for commonly needed information, and
+in the end provide a way to use driver-specific callbacks.
diff --git a/Documentation/memory-devices/ti-emif.txt b/Documentation/memory-devices/ti-emif.txt
new file mode 100644
index 0000000..f4ad9a7
--- /dev/null
+++ b/Documentation/memory-devices/ti-emif.txt
@@ -0,0 +1,57 @@
+TI EMIF SDRAM Controller Driver:
+
+Author
+========
+Aneesh V <aneesh@ti.com>
+
+Location
+============
+driver/memory/emif.c
+
+Supported SoCs:
+===================
+TI OMAP44xx
+TI OMAP54xx
+
+Menuconfig option:
+==========================
+Device Drivers
+	Memory devices
+		Texas Instruments EMIF driver
+
+Description
+===========
+This driver is for the EMIF module available in Texas Instruments
+SoCs. EMIF is an SDRAM controller that, based on its revision,
+supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols.
+This driver takes care of only LPDDR2 memories presently. The
+functions of the driver includes re-configuring AC timing
+parameters and other settings during frequency, voltage and
+temperature changes
+
+Platform Data (see include/linux/platform_data/emif_plat.h):
+=====================================================================
+DDR device details and other board dependent and SoC dependent
+information can be passed through platform data (struct emif_platform_data)
+- DDR device details: 'struct ddr_device_info'
+- Device AC timings: 'struct lpddr2_timings' and 'struct lpddr2_min_tck'
+- Custom configurations: customizable policy options through
+  'struct emif_custom_configs'
+- IP revision
+- PHY type
+
+Interface to the external world:
+================================
+EMIF driver registers notifiers for voltage and frequency changes
+affecting EMIF and takes appropriate actions when these are invoked.
+- freq_pre_notify_handling()
+- freq_post_notify_handling()
+- volt_notify_handling()
+
+Debugfs
+========
+The driver creates two debugfs entries per device.
+- regcache_dump : dump of register values calculated and saved for all
+  frequencies used so far.
+- mr4 : last polled value of MR4 register in the LPDDR2 device. MR4
+  indicates the current temperature level of the device.
diff --git a/Documentation/memory-hotplug.txt b/Documentation/memory-hotplug.txt
index 8f485d7..6d0c251 100644
--- a/Documentation/memory-hotplug.txt
+++ b/Documentation/memory-hotplug.txt
@@ -341,7 +341,7 @@
 --------------------------------
 8. Memory hotplug event notifier
 --------------------------------
-Memory hotplug has event notifer. There are 6 types of notification.
+Memory hotplug has event notifier. There are 6 types of notification.
 
 MEMORY_GOING_ONLINE
   Generated before new memory becomes available in order to be able to
diff --git a/Documentation/misc-devices/mei/.gitignore b/Documentation/misc-devices/mei/.gitignore
new file mode 100644
index 0000000..f356b81
--- /dev/null
+++ b/Documentation/misc-devices/mei/.gitignore
@@ -0,0 +1 @@
+mei-amt-version
diff --git a/Documentation/misc-devices/mei/Makefile b/Documentation/misc-devices/mei/Makefile
new file mode 100644
index 0000000..00e8c3e
--- /dev/null
+++ b/Documentation/misc-devices/mei/Makefile
@@ -0,0 +1,8 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := mei-amt-version
+HOSTCFLAGS_mei-amt-version.o += -I$(objtree)/usr/include
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
diff --git a/Documentation/misc-devices/mei/TODO b/Documentation/misc-devices/mei/TODO
new file mode 100644
index 0000000..6b3625d
--- /dev/null
+++ b/Documentation/misc-devices/mei/TODO
@@ -0,0 +1,2 @@
+TODO:
+	- Cleanup and split the timer function
diff --git a/Documentation/misc-devices/mei/mei-amt-version.c b/Documentation/misc-devices/mei/mei-amt-version.c
new file mode 100644
index 0000000..01804f2
--- /dev/null
+++ b/Documentation/misc-devices/mei/mei-amt-version.c
@@ -0,0 +1,481 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *	Intel Corporation.
+ *	linux-mei@linux.intel.com
+ *	http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <bits/wordsize.h>
+#include <linux/mei.h>
+
+/*****************************************************************************
+ * Intel Management Engine Interface
+ *****************************************************************************/
+
+#define mei_msg(_me, fmt, ARGS...) do {         \
+	if (_me->verbose)                       \
+		fprintf(stderr, fmt, ##ARGS);	\
+} while (0)
+
+#define mei_err(_me, fmt, ARGS...) do {         \
+	fprintf(stderr, "Error: " fmt, ##ARGS); \
+} while (0)
+
+struct mei {
+	uuid_le guid;
+	bool initialized;
+	bool verbose;
+	unsigned int buf_size;
+	unsigned char prot_ver;
+	int fd;
+};
+
+static void mei_deinit(struct mei *cl)
+{
+	if (cl->fd != -1)
+		close(cl->fd);
+	cl->fd = -1;
+	cl->buf_size = 0;
+	cl->prot_ver = 0;
+	cl->initialized = false;
+}
+
+static bool mei_init(struct mei *me, const uuid_le *guid,
+		unsigned char req_protocol_version, bool verbose)
+{
+	int result;
+	struct mei_client *cl;
+	struct mei_connect_client_data data;
+
+	mei_deinit(me);
+
+	me->verbose = verbose;
+
+	me->fd = open("/dev/mei", O_RDWR);
+	if (me->fd == -1) {
+		mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
+		goto err;
+	}
+	memcpy(&me->guid, guid, sizeof(*guid));
+	memset(&data, 0, sizeof(data));
+	me->initialized = true;
+
+	memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
+	result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
+	if (result) {
+		mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
+		goto err;
+	}
+	cl = &data.out_client_properties;
+	mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
+	mei_msg(me, "protocol_version %d\n", cl->protocol_version);
+
+	if ((req_protocol_version > 0) &&
+	     (cl->protocol_version != req_protocol_version)) {
+		mei_err(me, "Intel MEI protocol version not supported\n");
+		goto err;
+	}
+
+	me->buf_size = cl->max_msg_length;
+	me->prot_ver = cl->protocol_version;
+
+	return true;
+err:
+	mei_deinit(me);
+	return false;
+}
+
+static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
+			ssize_t len, unsigned long timeout)
+{
+	ssize_t rc;
+
+	mei_msg(me, "call read length = %zd\n", len);
+
+	rc = read(me->fd, buffer, len);
+	if (rc < 0) {
+		mei_err(me, "read failed with status %zd %s\n",
+				rc, strerror(errno));
+		mei_deinit(me);
+	} else {
+		mei_msg(me, "read succeeded with result %zd\n", rc);
+	}
+	return rc;
+}
+
+static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
+			ssize_t len, unsigned long timeout)
+{
+	struct timeval tv;
+	ssize_t written;
+	ssize_t rc;
+	fd_set set;
+
+	tv.tv_sec = timeout / 1000;
+	tv.tv_usec = (timeout % 1000) * 1000000;
+
+	mei_msg(me, "call write length = %zd\n", len);
+
+	written = write(me->fd, buffer, len);
+	if (written < 0) {
+		rc = -errno;
+		mei_err(me, "write failed with status %zd %s\n",
+			written, strerror(errno));
+		goto out;
+	}
+
+	FD_ZERO(&set);
+	FD_SET(me->fd, &set);
+	rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
+	if (rc > 0 && FD_ISSET(me->fd, &set)) {
+		mei_msg(me, "write success\n");
+	} else if (rc == 0) {
+		mei_err(me, "write failed on timeout with status\n");
+		goto out;
+	} else { /* rc < 0 */
+		mei_err(me, "write failed on select with status %zd\n", rc);
+		goto out;
+	}
+
+	rc = written;
+out:
+	if (rc < 0)
+		mei_deinit(me);
+
+	return rc;
+}
+
+/***************************************************************************
+ * Intel Advanced Management Technolgy ME Client
+ ***************************************************************************/
+
+#define AMT_MAJOR_VERSION 1
+#define AMT_MINOR_VERSION 1
+
+#define AMT_STATUS_SUCCESS                0x0
+#define AMT_STATUS_INTERNAL_ERROR         0x1
+#define AMT_STATUS_NOT_READY              0x2
+#define AMT_STATUS_INVALID_AMT_MODE       0x3
+#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
+
+#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE  0x4000
+#define AMT_STATUS_SDK_RESOURCES      0x1004
+
+
+#define AMT_BIOS_VERSION_LEN   65
+#define AMT_VERSIONS_NUMBER    50
+#define AMT_UNICODE_STRING_LEN 20
+
+struct amt_unicode_string {
+	uint16_t length;
+	char string[AMT_UNICODE_STRING_LEN];
+} __attribute__((packed));
+
+struct amt_version_type {
+	struct amt_unicode_string description;
+	struct amt_unicode_string version;
+} __attribute__((packed));
+
+struct amt_version {
+	uint8_t major;
+	uint8_t minor;
+} __attribute__((packed));
+
+struct amt_code_versions {
+	uint8_t bios[AMT_BIOS_VERSION_LEN];
+	uint32_t count;
+	struct amt_version_type versions[AMT_VERSIONS_NUMBER];
+} __attribute__((packed));
+
+/***************************************************************************
+ * Intel Advanced Management Technolgy Host Interface
+ ***************************************************************************/
+
+struct amt_host_if_msg_header {
+	struct amt_version version;
+	uint16_t _reserved;
+	uint32_t command;
+	uint32_t length;
+} __attribute__((packed));
+
+struct amt_host_if_resp_header {
+	struct amt_host_if_msg_header header;
+	uint32_t status;
+	unsigned char data[0];
+} __attribute__((packed));
+
+const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,  \
+				0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
+
+#define AMT_HOST_IF_CODE_VERSIONS_REQUEST  0x0400001A
+#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
+
+const struct amt_host_if_msg_header CODE_VERSION_REQ = {
+	.version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
+	._reserved = 0,
+	.command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
+	.length = 0
+};
+
+
+struct amt_host_if {
+	struct mei mei_cl;
+	unsigned long send_timeout;
+	bool initialized;
+};
+
+
+static bool amt_host_if_init(struct amt_host_if *acmd,
+		      unsigned long send_timeout, bool verbose)
+{
+	acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
+	acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
+	return acmd->initialized;
+}
+
+static void amt_host_if_deinit(struct amt_host_if *acmd)
+{
+	mei_deinit(&acmd->mei_cl);
+	acmd->initialized = false;
+}
+
+static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
+{
+	uint32_t status = AMT_STATUS_SUCCESS;
+	struct amt_code_versions *code_ver;
+	size_t code_ver_len;
+	uint32_t ver_type_cnt;
+	uint32_t len;
+	uint32_t i;
+
+	code_ver = (struct amt_code_versions *)resp->data;
+	/* length - sizeof(status) */
+	code_ver_len = resp->header.length - sizeof(uint32_t);
+	ver_type_cnt = code_ver_len -
+			sizeof(code_ver->bios) -
+			sizeof(code_ver->count);
+	if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
+		status = AMT_STATUS_INTERNAL_ERROR;
+		goto out;
+	}
+
+	for (i = 0; i < code_ver->count; i++) {
+		len = code_ver->versions[i].description.length;
+
+		if (len > AMT_UNICODE_STRING_LEN) {
+			status = AMT_STATUS_INTERNAL_ERROR;
+			goto out;
+		}
+
+		len = code_ver->versions[i].version.length;
+		if (code_ver->versions[i].version.string[len] != '\0' ||
+		    len != strlen(code_ver->versions[i].version.string)) {
+			status = AMT_STATUS_INTERNAL_ERROR;
+			goto out;
+		}
+	}
+out:
+	return status;
+}
+
+static uint32_t amt_verify_response_header(uint32_t command,
+				const struct amt_host_if_msg_header *resp_hdr,
+				uint32_t response_size)
+{
+	if (response_size < sizeof(struct amt_host_if_resp_header)) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	} else if (response_size != (resp_hdr->length +
+				sizeof(struct amt_host_if_msg_header))) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	} else if (resp_hdr->command != command) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	} else if (resp_hdr->_reserved != 0) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	} else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
+		   resp_hdr->version.minor < AMT_MINOR_VERSION) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	}
+	return AMT_STATUS_SUCCESS;
+}
+
+static uint32_t amt_host_if_call(struct amt_host_if *acmd,
+			const unsigned char *command, ssize_t command_sz,
+			uint8_t **read_buf, uint32_t rcmd,
+			unsigned int expected_sz)
+{
+	uint32_t in_buf_sz;
+	uint32_t out_buf_sz;
+	ssize_t written;
+	uint32_t status;
+	struct amt_host_if_resp_header *msg_hdr;
+
+	in_buf_sz = acmd->mei_cl.buf_size;
+	*read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
+	if (*read_buf == NULL)
+		return AMT_STATUS_SDK_RESOURCES;
+	memset(*read_buf, 0, in_buf_sz);
+	msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
+
+	written = mei_send_msg(&acmd->mei_cl,
+				command, command_sz, acmd->send_timeout);
+	if (written != command_sz)
+		return AMT_STATUS_INTERNAL_ERROR;
+
+	out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
+	if (out_buf_sz <= 0)
+		return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
+
+	status = msg_hdr->status;
+	if (status != AMT_STATUS_SUCCESS)
+		return status;
+
+	status = amt_verify_response_header(rcmd,
+				&msg_hdr->header, out_buf_sz);
+	if (status != AMT_STATUS_SUCCESS)
+		return status;
+
+	if (expected_sz && expected_sz != out_buf_sz)
+		return AMT_STATUS_INTERNAL_ERROR;
+
+	return AMT_STATUS_SUCCESS;
+}
+
+
+static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
+			       struct amt_code_versions *versions)
+{
+	struct amt_host_if_resp_header *response = NULL;
+	uint32_t status;
+
+	status = amt_host_if_call(cmd,
+			(const unsigned char *)&CODE_VERSION_REQ,
+			sizeof(CODE_VERSION_REQ),
+			(uint8_t **)&response,
+			AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
+
+	if (status != AMT_STATUS_SUCCESS)
+		goto out;
+
+	status = amt_verify_code_versions(response);
+	if (status != AMT_STATUS_SUCCESS)
+		goto out;
+
+	memcpy(versions, response->data, sizeof(struct amt_code_versions));
+out:
+	if (response != NULL)
+		free(response);
+
+	return status;
+}
+
+/************************** end of amt_host_if_command ***********************/
+int main(int argc, char **argv)
+{
+	struct amt_code_versions ver;
+	struct amt_host_if acmd;
+	unsigned int i;
+	uint32_t status;
+	int ret;
+	bool verbose;
+
+	verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
+
+	if (!amt_host_if_init(&acmd, 5000, verbose)) {
+		ret = 1;
+		goto out;
+	}
+
+	status = amt_get_code_versions(&acmd, &ver);
+
+	amt_host_if_deinit(&acmd);
+
+	switch (status) {
+	case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
+		printf("Intel AMT: DISABLED\n");
+		ret = 0;
+		break;
+	case AMT_STATUS_SUCCESS:
+		printf("Intel AMT: ENABLED\n");
+		for (i = 0; i < ver.count; i++) {
+			printf("%s:\t%s\n", ver.versions[i].description.string,
+				ver.versions[i].version.string);
+		}
+		ret = 0;
+		break;
+	default:
+		printf("An error has occurred\n");
+		ret = 1;
+		break;
+	}
+
+out:
+	return ret;
+}
diff --git a/drivers/staging/mei/mei.txt b/Documentation/misc-devices/mei/mei.txt
similarity index 100%
rename from drivers/staging/mei/mei.txt
rename to Documentation/misc-devices/mei/mei.txt
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index 56ca3b7..ac29539 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -649,7 +649,7 @@
   The CAN device must be configured via netlink interface. The supported
   netlink message types are defined and briefly described in
   "include/linux/can/netlink.h". CAN link support for the program "ip"
-  of the IPROUTE2 utility suite is avaiable and it can be used as shown
+  of the IPROUTE2 utility suite is available and it can be used as shown
   below:
 
   - Setting CAN device properties:
diff --git a/Documentation/parisc/debugging b/Documentation/parisc/debugging
index d728594..7d75223 100644
--- a/Documentation/parisc/debugging
+++ b/Documentation/parisc/debugging
@@ -34,6 +34,6 @@
 was interrupted - so if you get an interruption between the instruction
 that clears the Q bit and the RFI that sets it again you don't know
 where exactly it happened.  If you're lucky the IAOQ will point to the
-instrucion that cleared the Q bit, if you're not it points anywhere
+instruction that cleared the Q bit, if you're not it points anywhere
 at all.  Usually Q bit problems will show themselves in unexplainable
 system hangs or running off the end of physical memory.
diff --git a/Documentation/power/suspend-and-cpuhotplug.txt b/Documentation/power/suspend-and-cpuhotplug.txt
index f28f9a6..e13dafc 100644
--- a/Documentation/power/suspend-and-cpuhotplug.txt
+++ b/Documentation/power/suspend-and-cpuhotplug.txt
@@ -29,7 +29,7 @@
 
                                   Write 'mem' to
                                 /sys/power/state
-                                    syfs file
+                                    sysfs file
                                         |
                                         v
                                Acquire pm_mutex lock
diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
index 8fb1ba7..4ba7db2 100644
--- a/Documentation/ramoops.txt
+++ b/Documentation/ramoops.txt
@@ -3,7 +3,7 @@
 
 Sergiu Iordache <sergiu@chromium.org>
 
-Updated: 8 August 2011
+Updated: 17 November 2011
 
 0. Introduction
 
@@ -30,6 +30,11 @@
 The module uses a counter to record multiple dumps but the counter gets reset
 on restart (i.e. new dumps after the restart will overwrite old ones).
 
+Ramoops also supports software ECC protection of persistent memory regions.
+This might be useful when a hardware reset was used to bring the machine back
+to life (i.e. a watchdog triggered). In such cases, RAM may be somewhat
+corrupt, but usually it is restorable.
+
 2. Setting the parameters
 
 Setting the ramoops parameters can be done in 2 different manners:
@@ -38,7 +43,7 @@
  2. Use a platform device and set the platform data. The parameters can then
  be set through that platform data. An example of doing that is:
 
-#include <linux/ramoops.h>
+#include <linux/pstore_ram.h>
 [...]
 
 static struct ramoops_platform_data ramoops_data = {
@@ -46,6 +51,7 @@
         .mem_address            = <...>,
         .record_size            = <...>,
         .dump_oops              = <...>,
+        .ecc                    = <...>,
 };
 
 static struct platform_device ramoops_dev = {
@@ -71,6 +77,6 @@
 
 4. Reading the data
 
-The dump data can be read from memory (through /dev/mem or other means).
-Getting the module parameters, which are needed in order to parse the data, can
-be done through /sys/module/ramoops/parameters/* .
+The dump data can be read from the pstore filesystem. The format for these
+files is "dmesg-ramoops-N", where N is the record number in memory. To delete
+a stored record from RAM, simply unlink the respective pstore file.
diff --git a/Documentation/scheduler/sched-design-CFS.txt b/Documentation/scheduler/sched-design-CFS.txt
index 91ecff0..d529e02d 100644
--- a/Documentation/scheduler/sched-design-CFS.txt
+++ b/Documentation/scheduler/sched-design-CFS.txt
@@ -130,7 +130,7 @@
     idle timer scheduler in order to avoid to get into priority
     inversion problems which would deadlock the machine.
 
-SCHED_FIFO/_RR are implemented in sched_rt.c and are as specified by
+SCHED_FIFO/_RR are implemented in sched/rt.c and are as specified by
 POSIX.
 
 The command chrt from util-linux-ng 2.13.1.1 can set all of these except
@@ -145,9 +145,9 @@
 encapsulate scheduling policy details and are handled by the scheduler core
 without the core code assuming too much about them.
 
-sched_fair.c implements the CFS scheduler described above.
+sched/fair.c implements the CFS scheduler described above.
 
-sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler way than
+sched/rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler way than
 the previous vanilla scheduler did.  It uses 100 runqueues (for all 100 RT
 priority levels, instead of 140 in the previous scheduler) and it needs no
 expired array.
diff --git a/Documentation/scheduler/sched-domains.txt b/Documentation/scheduler/sched-domains.txt
index b7ee379..443f0c7 100644
--- a/Documentation/scheduler/sched-domains.txt
+++ b/Documentation/scheduler/sched-domains.txt
@@ -61,10 +61,6 @@
 struct sched_domain fields, SD_FLAG_*, SD_*_INIT to get an idea of
 the specifics and what to tune.
 
-For SMT, the architecture must define CONFIG_SCHED_SMT and provide a
-cpumask_t cpu_sibling_map[NR_CPUS], where cpu_sibling_map[i] is the mask of
-all "i"'s siblings as well as "i" itself.
-
 Architectures may retain the regular override the default SD_*_INIT flags
 while using the generic domain builder in kernel/sched.c if they wish to
 retain the traditional SMT->SMP->NUMA topology (or some subset of that). This
diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX
index b7dd650..9b0787f 100644
--- a/Documentation/scsi/00-INDEX
+++ b/Documentation/scsi/00-INDEX
@@ -56,8 +56,6 @@
 	- info on driver for NCR5380 and NCR53c400 based adapters
 hptiop.txt
 	- HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
-ibmmca.txt
-	- info on driver for IBM adapters with MCA bus
 in2000.txt
 	- info on in2000 driver
 libsas.txt
diff --git a/Documentation/scsi/ibmmca.txt b/Documentation/scsi/ibmmca.txt
deleted file mode 100644
index ac41a9f..0000000
--- a/Documentation/scsi/ibmmca.txt
+++ /dev/null
@@ -1,1402 +0,0 @@
-
-               -=< The IBM Microchannel SCSI-Subsystem >=-
-	       
-	                 for the IBM PS/2 series
-		 
-	  	   Low Level Software-Driver for Linux
-		 
-     Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU 
-  General Public License. Originally written by Martin Kolinek, December 1995.
-   Officially modified and maintained by Michael Lang since January 1999.
-	   
- 	                       Version 4.0a
-	
-   Last update: January 3, 2001
-   
-   Before you Start
-   ----------------
-   This is the common README.ibmmca file for all driver releases of the 
-   IBM MCA SCSI driver for Linux. Please note, that driver releases 4.0
-   or newer do not work with kernel versions older than 2.4.0, while driver
-   versions older than 4.0 do not work with kernels 2.4.0 or later! If you
-   try to compile your kernel with the wrong driver source, the 
-   compilation is aborted and you get a corresponding error message. This is
-   no bug in the driver; it prevents you from using the wrong source code
-   with the wrong kernel version.
-
-   Authors of this Driver
-   ----------------------
-    - Chris Beauregard (improvement of the SCSI-device mapping by the driver)
-    - Martin Kolinek (origin, first release of this driver)
-    - Klaus Kudielka (multiple SCSI-host management/detection, adaption to
-                      Linux Kernel 2.1.x, module support)
-    - Michael Lang (assigning original pun/lun mapping, dynamical ldn
-                    assignment, rewritten adapter detection, this file, 
-		    patches, official driver maintenance and subsequent 
-		    debugging, related with the driver)
-
-   Table of Contents
-   -----------------
-   1 Abstract
-   2 Driver Description
-     2.1  IBM SCSI-Subsystem Detection
-     2.2  Physical Units, Logical Units, and Logical Devices
-     2.3  SCSI-Device Recognition and dynamical ldn Assignment
-     2.4  SCSI-Device Order
-     2.5  Regular SCSI-Command-Processing
-     2.6  Abort & Reset Commands
-     2.7  Disk Geometry
-     2.8  Kernel Boot Option
-     2.9  Driver Module Support
-     2.10 Multiple Hostadapter Support
-     2.11 /proc/scsi-Filesystem Information
-     2.12 /proc/mca-Filesystem Information
-     2.13 Supported IBM SCSI-Subsystems
-     2.14 Linux Kernel Versions
-   3 Code History
-   4 To do
-   5 Users' Manual
-     5.1 Commandline Parameters
-     5.2 Troubleshooting
-     5.3 Bug reports
-     5.4 Support WWW-page
-   6 References
-   7 Credits to
-     7.1 People
-     7.2 Sponsors & Supporters
-   8 Trademarks
-   9 Disclaimer
-
-                              * * *
-
-   1 Abstract
-   ----------
-   This README-file describes the IBM SCSI-subsystem low level driver for
-   Linux. The descriptions which were formerly kept in the source code have
-   been taken out of this file to simplify the codes readability. The driver
-   description has been updated, as most of the former description was already
-   quite outdated. The history of the driver development is also kept inside
-   here. Multiple historical developments have been summarized to shorten the
-   text size a bit. At the end of this file you can find a small manual for
-   this driver and hints to get it running on your machine.
-
-   2 Driver Description
-   --------------------
-   2.1 IBM SCSI-Subsystem Detection
-   --------------------------------
-   This is done in the ibmmca_detect() function. It first checks, if the
-   Microchannel-bus support is enabled, as the IBM SCSI-subsystem needs the
-   Microchannel. In a next step, a free interrupt is chosen and the main
-   interrupt handler is connected to it to handle answers of the SCSI-
-   subsystem(s). If the F/W SCSI-adapter is forced by the BIOS to use IRQ11
-   instead of IRQ14, IRQ11 is used for the IBM SCSI-2 F/W adapter. In a 
-   further step it is checked, if the adapter gets detected by force from
-   the kernel commandline, where the I/O port and the SCSI-subsystem id can 
-   be specified. The next step checks if there is an integrated SCSI-subsystem
-   installed. This register area is fixed through all IBM PS/2 MCA-machines 
-   and appears as something like a virtual slot 10 of the MCA-bus. On most
-   PS/2 machines, the POS registers of slot 10 are set to 0xff or 0x00 if not
-   integrated SCSI-controller is available. But on certain PS/2s, like model 
-   9595, this slot 10 is used to store other information which at earlier
-   stage confused the driver and resulted in the detection of some ghost-SCSI. 
-   If POS-register 2 and 3 are not 0x00 and not 0xff, but all other POS
-   registers are either 0xff or 0x00, there must be an integrated SCSI-
-   subsystem present and it will be registered as IBM Integrated SCSI-
-   Subsystem. The next step checks, if there is a slot-adapter installed on 
-   the MCA-bus. To get this, the first two POS-registers, that represent the 
-   adapter ID are checked. If they fit to one of the ids, stored in the 
-   adapter list, a SCSI-subsystem is assumed to be found in a slot and will be 
-   registered. This check is done through all possible MCA-bus slots to allow 
-   more than one SCSI-adapter to be present in the PS/2-system and this is 
-   already the first point of problems. Looking into the technical reference 
-   manual for the IBM PS/2 common interfaces, the POS2 register must have 
-   different interpretation of its single bits to avoid overlapping I/O
-   regions. While one can assume, that the integrated subsystem has a fix 
-   I/O-address at 0x3540 - 0x3547, further installed IBM SCSI-adapters must 
-   use a different I/O-address. This is expressed by bit 1 to 3 of POS2 
-   (multiplied by 8 + 0x3540). Bits 2 and 3 are reserved for the integrated 
-   subsystem, but not for the adapters! The following list shows, how the 
-   bits of POS2 and POS3 should be interpreted.
-   
-   The POS2-register of all PS/2 models' integrated SCSI-subsystems has the 
-   following interpretation of bits:
-                           Bit 7 - 4 : Chip Revision ID (Release)
-                           Bit 3 - 2 : Reserved
-                           Bit 1     : 8k NVRAM Disabled
-                           Bit 0     : Chip Enable (EN-Signal)
-   The POS3-register is interpreted as follows (for most IBM SCSI-subsys.):
-                           Bit 7 - 5 : SCSI ID
-                           Bit 4 - 0 : Reserved = 0
-   The slot-adapters have different interpretation of these bits. The IBM SCSI
-   adapter (w/Cache) and the IBM SCSI-2 F/W adapter use the following
-   interpretation of the POS2 register:
-                           Bit 7 - 4 : ROM Segment Address Select
-			   Bit 3 - 1 : Adapter I/O Address Select (*8+0x3540)
-			   Bit 0     : Adapter Enable (EN-Signal)
-   and for the POS3 register:
-                           Bit 7 - 5 : SCSI ID 
-			   Bit 4     : Fairness Enable (SCSI ID3 f. F/W)
-			   Bit 3 - 0 : Arbitration Level
-   The most modern product of the series is the IBM SCSI-2 F/W adapter, it 
-   allows dual-bus SCSI and SCSI-wide addressing, which means, PUNs may be
-   between 0 and 15. Here, Bit 4 is the high-order bit of the 4-bit wide
-   adapter PUN expression. In short words, this means, that IBM PS/2 machines 
-   can only support 1 single integrated subsystem by default. Additional
-   slot-adapters get ports assigned by the automatic configuration tool.
-
-   One day I found a patch in ibmmca_detect(), forcing the I/O-address to be 
-   0x3540 for integrated SCSI-subsystems, there was a remark placed, that on 
-   integrated IBM SCSI-subsystems of model 56, the POS2 register was showing 5.
-   This means, that really for these models, POS2 has to be interpreted
-   sticking to the technical reference guide. In this case, the bit 2 (4) is 
-   a reserved bit and may not be interpreted. These differences between the 
-   adapters and the integrated controllers are taken into account by the 
-   detection routine of the driver on from version >3.0g. 
-
-   Every time, a SCSI-subsystem is discovered, the ibmmca_register() function
-   is called. This function checks first, if the requested area for the I/O-
-   address of this SCSI-subsystem is still available and assigns this I/O-
-   area to the SCSI-subsystem. There are always 8 sequential I/O-addresses
-   taken for each individual SCSI-subsystem found, which are:
-   
-     Offset            Type                  Permissions
-       0     Command Interface Register 1    Read/Write
-       1     Command Interface Register 2    Read/Write
-       2     Command Interface Register 3    Read/Write
-       3     Command Interface Register 4    Read/Write
-       4     Attention Register              Read/Write
-       5     Basic Control Register          Read/Write
-       6     Interrupt Status Register       Read
-       7     Basic Status Register           Read
-   
-   After the I/O-address range is assigned, the host-adapter is assigned
-   to a local structure which keeps all adapter information needed for the
-   driver itself and the mid- and higher-level SCSI-drivers. The SCSI pun/lun
-   and the adapters' ldn tables are initialized and get probed afterwards by
-   the check_devices() function. If no further adapters are found, 
-   ibmmca_detect() quits.
-   
-   2.2 Physical Units, Logical Units, and Logical Devices
-   ------------------------------------------------------
-   There can be up to 56 devices on the SCSI bus (besides the adapter):
-   there are up to 7 "physical units" (each identified by physical unit 
-   number or pun, also called the scsi id, this is the number you select
-   with hardware jumpers), and each physical unit can have up to 8 
-   "logical units" (each identified by logical unit number, or lun, 
-   between 0 and 7). The IBM SCSI-2 F/W adapter offers this on up to two
-   busses and provides support for 30 logical devices at the same time, where
-   in wide-addressing mode you can have 16 puns with 32 luns on each device.
-   This section describes the handling of devices on non-F/W adapters.
-   Just imagine, that you can have 16 * 32 = 512 devices on a F/W adapter
-   which means a lot of possible devices for such a small machine.
-
-   Typically the adapter has pun=7, so puns of other physical units
-   are between 0 and 6(15). On a wide-adapter a pun higher than 7 is
-   possible, but is normally not used. Almost all physical units have only 
-   one logical unit, with lun=0. A CD-ROM jukebox would be an example of a 
-   physical unit with more than one logical unit.
-
-   The embedded microprocessor of the IBM SCSI-subsystem hides the complex
-   two-dimensional (pun,lun) organization from the operating system.
-   When the machine is powered-up (or rebooted), the embedded microprocessor 
-   checks, on its own, all 56 possible (pun,lun) combinations, and the first 
-   15 devices found are assigned into a one-dimensional array of so-called 
-   "logical devices", identified by "logical device numbers" or ldn. The last 
-   ldn=15 is reserved for the subsystem itself. Wide adapters may have 
-   to check up to 15 * 8 = 120 pun/lun combinations.
-   
-   2.3 SCSI-Device Recognition and Dynamical ldn Assignment
-   --------------------------------------------------------
-   One consequence of information hiding is that the real (pun,lun)    
-   numbers are also hidden. The two possibilities to get around this problem
-   are to offer fake pun/lun combinations to the operating system or to 
-   delete the whole mapping of the adapter and to reassign the ldns, using
-   the immediate assign command of the SCSI-subsystem for probing through
-   all possible pun/lun combinations.  An ldn is a "logical device number"
-   which is used by IBM SCSI-subsystems to access some valid SCSI-device.
-   At the beginning of the development of this driver, the following approach 
-   was used:
-   
-   First, the driver checked the ldn's (0 to 6) to find out which ldn's
-   have devices assigned. This was done by the functions check_devices() and
-   device_exists(). The interrupt handler has a special paragraph of code
-   (see local_checking_phase_flag) to assist in the checking. Assume, for
-   example, that three logical devices were found assigned at ldn 0, 1, 2.
-   These are presented to the upper layer of Linux SCSI driver
-   as devices with bogus (pun, lun) equal to (0,0), (1,0), (2,0). 
-   On the other hand, if the upper layer issues a command to device
-   say (4,0), this driver returns DID_NO_CONNECT error.
-
-   In a second step of the driver development, the following improvement has
-   been applied: The first approach limited the number of devices to 7, far
-   fewer than the 15 that it could use, then it just mapped ldn -> 
-   (ldn/8,ldn%8) for pun,lun.  We ended up with a real mishmash of puns
-   and luns, but it all seemed to work.
-
-   The latest development, which is implemented from the driver version 3.0
-   and later, realizes the device recognition in the following way:
-   The physical SCSI-devices on the SCSI-bus are probed via immediate_assign- 
-   and device_inquiry-commands, that is all implemented in a completely new
-   made check_devices() subroutine. This delivers an exact map of the physical
-   SCSI-world that is now stored in the get_scsi[][]-array. This means,
-   that the once hidden pun,lun assignment is now known to this driver.
-   It no longer believes in default-settings of the subsystem and maps all
-   ldns to existing pun,lun "by foot". This assures full control of the ldn
-   mapping and allows dynamical remapping of ldns to different pun,lun, if
-   there are more SCSI-devices installed than ldns available (n>15). The
-   ldns from 0 to 6 get 'hardwired' by this driver to puns 0 to 7 at lun=0,
-   excluding the pun of the subsystem. This assures, that at least simple 
-   SCSI-installations have optimum access-speed and are not touched by
-   dynamical remapping. The ldns 7 to 14 are put to existing devices with 
-   lun>0 or to non-existing devices, in order to satisfy the subsystem, if 
-   there are less than 15 SCSI-devices connected. In the case of more than 15 
-   devices, the dynamical mapping goes active. If the get_scsi[][] reports a 
-   device to be existent, but it has no ldn assigned, it gets an ldn out of 7
-   to 14. The numbers are assigned in cyclic order, therefore it takes 8 
-   dynamical reassignments on the SCSI-devices until a certain device 
-   loses its ldn again. This assures that dynamical remapping is avoided 
-   during intense I/O between up to 15 SCSI-devices (means pun,lun 
-   combinations). A further advantage of this method is that people who
-   build their kernel without probing on all luns will get what they expect,
-   because the driver just won't assign everything with lun>0 when 
-   multiple lun probing is inactive.
- 
-   2.4 SCSI-Device Order
-   ---------------------
-   Because of the now correct recognition of physical pun,lun, and 
-   their report to mid-level- and higher-level-drivers, the new reported puns
-   can be different from the old, faked puns. Therefore, Linux will eventually
-   change /dev/sdXXX assignments and prompt you for corrupted superblock
-   repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!!
-   You have to reboot (CTRL-D) with an old kernel and set the /etc/fstab-file
-   entries right. After that, the system should come up as errorfree as before.
-   If your boot-partition is not coming up, also edit the /etc/lilo.conf-file
-   in a Linux session booted on old kernel and run lilo before reboot. Check
-   lilo.conf anyway to get boot on other partitions with foreign OSes right
-   again. But there exists a feature of this driver that allows you to change
-   the assignment order of the SCSI-devices by flipping the PUN-assignment.
-   See the next paragraph for a description.
- 
-   The problem for this is, that Linux does not assign the SCSI-devices in the
-   way as described in the ANSI-SCSI-standard. Linux assigns /dev/sda to 
-   the device with at minimum id 0. But the first drive should be at id 6,
-   because for historical reasons, drive at id 6 has, by hardware, the highest
-   priority and a drive at id 0 the lowest. IBM was one of the rare producers,
-   where the BIOS assigns drives belonging to the ANSI-SCSI-standard. Most 
-   other producers' BIOS does not (I think even Adaptec-BIOS). The 
-   IBMMCA_SCSI_ORDER_STANDARD flag, which you set while configuring the
-   kernel enables to choose the preferred way of SCSI-device-assignment. 
-   Defining this flag would result in Linux determining the devices in the 
-   same order as DOS and OS/2 does on your MCA-machine. This is also standard 
-   on most industrial computers and OSes, like e.g. OS-9. Leaving this flag 
-   undefined will get your devices ordered in the default way of Linux. See 
-   also the remarks of Chris Beauregard from Dec 15, 1997 and the followups 
-   in section 3.
-   
-   2.5 Regular SCSI-Command-Processing
-   -----------------------------------
-   Only three functions get involved: ibmmca_queuecommand(), issue_cmd(),
-   and interrupt_handler().
-
-   The upper layer issues a scsi command by calling function 
-   ibmmca_queuecommand(). This function fills a "subsystem control block"
-   (scb) and calls a local function issue_cmd(), which writes a scb 
-   command into subsystem I/O ports. Once the scb command is carried out, 
-   the interrupt_handler() is invoked. If a device is determined to be 
-   existent and it has not assigned any ldn, it gets one dynamically.
-   For this, the whole stuff is done in ibmmca_queuecommand().
-
-   2.6 Abort & Reset Commands
-   --------------------------
-   These are implemented with busy waiting for interrupt to arrive.
-   ibmmca_reset() and ibmmca_abort() do not work sufficiently well
-   up to now and need still a lot of development work. This seems
-   to be a problem with other low-level SCSI drivers too, however
-   this should be no excuse.
-
-   2.7 Disk Geometry
-   -----------------
-   The ibmmca_biosparams() function should return the same disk geometry 
-   as the bios. This is needed for fdisk, etc. The returned geometry is 
-   certainly correct for disks smaller than 1 gigabyte. In the meantime,
-   it has been proved, that this works fine even with disks larger than
-   1 gigabyte.
-
-   2.8 Kernel Boot Option
-   ----------------------
-   The function ibmmca_scsi_setup() is called if option ibmmcascsi=n 
-   is passed to the kernel. See file linux/init/main.c for details.
-   
-   2.9 Driver Module Support
-   -------------------------
-   Is implemented and tested by K. Kudielka. This could probably not work
-   on kernels <2.1.0.
-  
-   2.10 Multiple Hostadapter Support
-   ---------------------------------
-   This driver supports up to eight interfaces of type IBM-SCSI-Subsystem. 
-   Integrated-, and MCA-adapters are automatically recognized. Unrecognizable
-   IBM-SCSI-Subsystem interfaces can be specified as kernel-parameters.
- 
-   2.11 /proc/scsi-Filesystem Information
-   --------------------------------------
-   Information about the driver condition is given in 
-   /proc/scsi/ibmmca/<host_no>. ibmmca_proc_info() provides this information.
-   
-   This table is quite informative for interested users. It shows the load
-   of commands on the subsystem and whether you are running the bypassed
-   (software) or integrated (hardware) SCSI-command set (see below). The
-   amount of accesses is shown. Read, write, modeselect is shown separately
-   in order to help debugging problems with CD-ROMs or tapedrives.
-   
-   The following table shows the list of 15 logical device numbers, that are
-   used by the SCSI-subsystem. The load on each ldn is shown in the table,
-   again, read and write commands are split. The last column shows the amount
-   of reassignments, that have been applied to the ldns, if you have more than
-   15 pun/lun combinations available on the SCSI-bus.
-   
-   The last two tables show the pun/lun map and the positions of the ldns
-   on this pun/lun map. This may change during operation, when a ldn is
-   reassigned to another pun/lun combination. If the necessity for dynamical
-   assignments is set to 'no', the ldn structure keeps static.
-   
-   2.12 /proc/mca-Filesystem Information
-   -------------------------------------
-   The slot-file contains all default entries and in addition chip and I/O-
-   address information of the SCSI-subsystem. This information is provided
-   by ibmmca_getinfo().
-   
-   2.13 Supported IBM SCSI-Subsystems
-   ----------------------------------
-   The following IBM SCSI-subsystems are supported by this driver:
-   
-     - IBM Fast/Wide SCSI-2 Adapter
-     - IBM 7568 Industrial Computer SCSI Adapter w/Cache
-     - IBM Expansion Unit SCSI Controller
-     - IBM SCSI Adapter w/Cache
-     - IBM SCSI Adapter
-     - IBM Integrated SCSI Controller
-     - All clones, 100% compatible with the chipset and subsystem command
-       system of IBM SCSI-adapters (forced detection)
-     
-   2.14 Linux Kernel Versions
-   --------------------------
-   The IBM SCSI-subsystem low level driver is prepared to be used with
-   all versions of Linux between 2.0.x and 2.4.x. The compatibility checks
-   are fully implemented up from version 3.1e of the driver. This means, that
-   you just need the latest ibmmca.h and ibmmca.c file and copy it in the
-   linux/drivers/scsi directory. The code is automatically adapted during 
-   kernel compilation. This is different from kernel 2.4.0! Here version 
-   4.0 or later of the driver must be used for kernel 2.4.0 or later. Version
-   4.0 or later does not work together with older kernels! Driver versions
-   older than 4.0 do not work together with kernel 2.4.0 or later. They work
-   on all older kernels.
-
-   3 Code History
-   --------------
-   Jan 15 1996:  First public release.
-   - Martin Kolinek
-
-   Jan 23 1996:  Scrapped code which reassigned scsi devices to logical
-   device numbers. Instead, the existing assignment (created
-   when the machine is powered-up or rebooted) is used. 
-   A side effect is that the upper layer of Linux SCSI 
-   device driver gets bogus scsi ids (this is benign), 
-   and also the hard disks are ordered under Linux the 
-   same way as they are under dos (i.e., C: disk is sda, 
-   D: disk is sdb, etc.).
-   - Martin Kolinek
-
-   I think that the CD-ROM is now detected only if a CD is 
-   inside CD_ROM while Linux boots. This can be fixed later,
-   once the driver works on all types of PS/2's.
-   - Martin Kolinek
-
-   Feb 7 1996:   Modified biosparam function. Fixed the CD-ROM detection. 
-   For now, devices other than harddisk and CD_ROM are 
-   ignored. Temporarily modified abort() function 
-   to behave like reset().
-   - Martin Kolinek
-
-   Mar 31 1996:  The integrated scsi subsystem is correctly found
-   in PS/2 models 56,57, but not in model 76. Therefore
-   the ibmmca_scsi_setup() function has been added today.
-   This function allows the user to force detection of
-   scsi subsystem. The kernel option has format
-   ibmmcascsi=n
-   where n is the scsi_id (pun) of the subsystem. Most likely, n is 7.
-   - Martin Kolinek
-
-   Aug 21 1996:  Modified the code which maps ldns to (pun,0).  It was
-   insufficient for those of us with CD-ROM changers.
-   - Chris Beauregard
- 
-   Dec 14 1996: More improvements to the ldn mapping.  See check_devices
-   for details.  Did more fiddling with the integrated SCSI detection,
-   but I think it's ultimately hopeless without actually testing the
-   model of the machine.  The 56, 57, 76 and 95 (ultimedia) all have
-   different integrated SCSI register configurations.  However, the 56
-   and 57 are the only ones that have problems with forced detection.
-   - Chris Beauregard
- 
-   Mar 8-16 1997: Modified driver to run as a module and to support 
-   multiple adapters. A structure, called ibmmca_hostdata, is now
-   present, containing all the variables, that were once only
-   available for one single adapter. The find_subsystem-routine has vanished.
-   The hardware recognition is now done in ibmmca_detect directly.
-   This routine checks for presence of MCA-bus, checks the interrupt
-   level and continues with checking the installed hardware.
-   Certain PS/2-models do not recognize a SCSI-subsystem automatically.
-   Hence, the setup defined by command-line-parameters is checked first.
-   Thereafter, the routine probes for an integrated SCSI-subsystem.
-   Finally, adapters are checked. This method has the advantage to cover all
-   possible combinations of multiple SCSI-subsystems on one MCA-board. Up to
-   eight SCSI-subsystems can be recognized and announced to the upper-level
-   drivers with this improvement. A set of defines made changes to other
-   routines as small as possible.
-   - Klaus Kudielka
-   
-   May 30 1997: (v1.5b)
-   1) SCSI-command capability enlarged by the recognition of MODE_SELECT.
-      This needs the RD-Bit to be disabled on IM_OTHER_SCSI_CMD_CMD which 
-      allows data to be written from the system to the device. It is a
-      necessary step to be allowed to set blocksize of SCSI-tape-drives and 
-      the tape-speed, without confusing the SCSI-Subsystem.
-   2) The recognition of a tape is included in the check_devices routine.
-      This is done by checking for TYPE_TAPE, that is already defined in
-      the kernel-scsi-environment. The markup of a tape is done in the 
-      global ldn_is_tape[] array. If the entry on index ldn 
-      is 1, there is a tapedrive connected.
-   3) The ldn_is_tape[] array is necessary to distinguish between tape- and 
-      other devices. Fixed blocklength devices should not cause a problem
-      with the SCB-command for read and write in the ibmmca_queuecommand
-      subroutine. Therefore, I only derivate the READ_XX, WRITE_XX for
-      the tape-devices, as recommended by IBM in this Technical Reference,
-      mentioned below. (IBM recommends to avoid using the read/write of the
-      subsystem, but the fact was, that read/write causes a command error from
-      the subsystem and this causes kernel-panic.)
-   4) In addition, I propose to use the ldn instead of a fix char for the
-      display of PS2_DISK_LED_ON(). On 95, one can distinguish between the
-      devices that are accessed. It shows activity and easyfies debugging.   
-   The tape-support has been tested with a SONY SDT-5200 and a HP DDS-2
-   (I do not know yet the type). Optimization and CD-ROM audio-support, 
-   I am working on ...
-   - Michael Lang
-   
-   June 19 1997: (v1.6b)
-   1) Submitting the extra-array ldn_is_tape[] -> to the local ld[]
-      device-array. 
-   2) CD-ROM Audio-Play seems to work now.
-   3) When using DDS-2 (120M) DAT-Tapes, mtst shows still density-code
-      0x13 for ordinary DDS (61000 BPM) instead 0x24 for DDS-2. This appears 
-      also on Adaptec 2940 adaptor in a PCI-System. Therefore, I assume that 
-      the problem is independent of the low-level-driver/bus-architecture.
-   4) Hexadecimal ldn on PS/2-95 LED-display.
-   5) Fixing of the PS/2-LED on/off that it works right with tapedrives and
-      does not confuse the disk_rw_in_progress counter.
-   - Michael Lang
-  
-   June 21 1997: (v1.7b)
-   1) Adding of a proc_info routine to inform in /proc/scsi/ibmmca/<host> the
-      outer-world about operational load statistics on the different ldns,
-      seen by the driver. Everybody that has more than one IBM-SCSI should
-      test this, because I only have one and cannot see what happens with more
-      than one IBM-SCSI hosts.
-   2) Definition of a driver version-number to have a better recognition of 
-      the source when there are existing too much releases that may confuse
-      the user, when reading about release-specific problems. Up to know,
-      I calculated the version-number to be 1.7. Because we are in BETA-test
-      yet, it is today 1.7b.
-   3) Sorry for the heavy bug I programmed on June 19 1997! After that, the
-      CD-ROM did not work any more! The C7-command was a fake impression
-      I got while programming. Now, the READ and WRITE commands for CD-ROM are
-      no longer running over the subsystem, but just over 
-      IM_OTHER_SCSI_CMD_CMD. On my observations (PS/2-95), now CD-ROM mounts
-      much faster(!) and hopefully all fancy multimedia-functions, like direct
-      digital recording from audio-CDs also work. (I tried it with cdda2wav
-      from the cdwtools-package and it filled up the harddisk immediately :-).)
-      To easify boolean logics, a further local device-type in ld[], called
-      is_cdrom has been included.
-   4) If one uses a SCSI-device of unsupported type/commands, one
-      immediately runs into a kernel-panic caused by Command Error. To better
-      understand which SCSI-command caused the problem, I extended this
-      specific panic-message slightly.
-   - Michael Lang
- 
-   June 25 1997: (v1.8b)
-   1) Some cosmetic changes for the handling of SCSI-device-types.
-      Now, also CD-Burners / WORMs and SCSI-scanners should work. For
-      MO-drives I have no experience, therefore not yet supported.
-      In logical_devices I changed from different type-variables to one
-      called 'device_type' where the values, corresponding to scsi.h,
-      of a SCSI-device are stored.
-   2) There existed a small bug, that maps a device, coming after a SCSI-tape
-      wrong. Therefore, e.g. a CD-ROM changer would have been mapped wrong
-      -> problem removed.
-   3) Extension of the logical_device structure. Now it contains also device,
-      vendor and revision-level of a SCSI-device for internal usage.
-   - Michael Lang
-
-   June 26-29 1997: (v2.0b)
-   1) The release number 2.0b is necessary because of the completely new done
-      recognition and handling of SCSI-devices with the adapter. As I got
-      from Chris the hint, that the subsystem can reassign ldns dynamically,
-      I remembered this immediate_assign-command, I found once in the handbook.
-      Now, the driver first kills all ldn assignments that are set by default
-      on the SCSI-subsystem. After that, it probes on all puns and luns for
-      devices by going through all combinations with immediate_assign and
-      probing for devices, using device_inquiry. The found physical(!) pun,lun
-      structure is stored in get_scsi[][] as device types. This is followed
-      by the assignment of all ldns to existing SCSI-devices. If more ldns
-      than devices are available, they are assigned to non existing pun,lun
-      combinations to satisfy the adapter. With this, the dynamical mapping
-      was possible to implement. (For further info see the text in the 
-      source code and in the description below. Read the description
-      below BEFORE installing this driver on your system!)
-   2) Changed the name IBMMCA_DRIVER_VERSION to IBMMCA_SCSI_DRIVER_VERSION.
-   3) The LED-display shows on PS/2-95 no longer the ldn, but the SCSI-ID
-      (pun) of the accessed SCSI-device. This is now senseful, because the 
-      pun known within the driver is exactly the pun of the physical device
-      and no longer a fake one.
-   4) The /proc/scsi/ibmmca/<host_no> consists now of the first part, where
-      hit-statistics of ldns is shown and a second part, where the maps of 
-      physical and logical SCSI-devices are displayed. This could be very 
-      interesting, when one is using more than 15 SCSI-devices in order to 
-      follow the dynamical remapping of ldns.
-   - Michael Lang
- 
-   June 26-29 1997: (v2.0b-1)
-   1) I forgot to switch the local_checking_phase_flag to 1 and back to 0
-      in the dynamical remapping part in ibmmca_queuecommand for the 
-      device_exist routine. Sorry.
-   - Michael Lang
- 
-   July 1-13 1997: (v3.0b,c)
-   1) Merging of the driver-developments of Klaus Kudielka and Michael Lang 
-      in order to get a optimum and unified driver-release for the 
-      IBM-SCSI-Subsystem-Adapter(s).
-         For people, using the Kernel-release >=2.1.0, module-support should 
-      be no problem. For users, running under <2.1.0, module-support may not 
-      work, because the methods have changed between 2.0.x and 2.1.x.
-   2) Added some more effective statistics for /proc-output.
-   3) Change typecasting at necessary points from (unsigned long) to
-      virt_to_bus().
-   4) Included #if... at special points to have specific adaption of the
-      driver to kernel 2.0.x and 2.1.x. It should therefore also run with 
-      later releases.
-   5) Magneto-Optical drives and medium-changers are also recognized, now.
-      Therefore, we have a completely gapfree recognition of all SCSI-
-      device-types, that are known by Linux up to kernel 2.1.31.
-   6) The flag SCSI_IBMMCA_DEV_RESET has been inserted. If it is set within
-      the configuration, each connected SCSI-device will get a reset command
-      during boottime. This can be necessary for some special SCSI-devices.
-      This flag should be included in Config.in.
-      (See also the new Config.in file.)
-   Probable next improvement: bad disk handler.
-   - Michael Lang
- 
-   Sept 14 1997: (v3.0c)
-   1) Some debugging and speed optimization applied.
-   - Michael Lang
-
-   Dec 15, 1997
-    - chrisb@truespectra.com
-    - made the front panel display thingy optional, specified from the
-    command-line via ibmmcascsi=display.  Along the lines of the /LED
-    option for the OS/2 driver.
-    - fixed small bug in the LED display that would hang some machines.
-    - reversed ordering of the drives (using the
-    IBMMCA_SCSI_ORDER_STANDARD define).  This is necessary for two main
-    reasons:
-	- users who've already installed Linux won't be screwed.  Keep
-	in mind that not everyone is a kernel hacker.
-	- be consistent with the BIOS ordering of the drives.  In the
-	BIOS, id 6 is C:, id 0 might be D:.  With this scheme, they'd be
-	backwards.  This confuses the crap out of those heathens who've
-	got a impure Linux installation (which, <wince>, I'm one of).
-    This whole problem arises because IBM is actually non-standard with
-    the id to BIOS mappings.  You'll find, in fdomain.c, a similar
-    comment about a few FD BIOS revisions.  The Linux (and apparently
-    industry) standard is that C: maps to scsi id (0,0).  Let's stick
-    with that standard.
-    - Since this is technically a branch of my own, I changed the
-    version number to 3.0e-cpb.
-
-   Jan 17, 1998: (v3.0f)
-   1) Addition of some statistical info for /proc in proc_info.
-   2) Taking care of the SCSI-assignment problem, dealed by Chris at Dec 15
-      1997. In fact, IBM is right, concerning the assignment of SCSI-devices 
-      to driveletters. It is conform to the ANSI-definition of the SCSI-
-      standard to assign drive C: to SCSI-id 6, because it is the highest
-      hardware priority after the hostadapter (that has still today by
-      default everywhere id 7). Also realtime-operating systems that I use, 
-      like LynxOS and OS9, which are quite industrial systems use top-down
-      numbering of the harddisks, that is also starting at id 6. Now, one
-      sits a bit between two chairs. On one hand side, using the define
-      IBMMCA_SCSI_ORDER_STANDARD makes Linux assigning disks conform to
-      the IBM- and ANSI-SCSI-standard and keeps this driver downward
-      compatible to older releases, on the other hand side, people is quite
-      habituated in believing that C: is assigned to (0,0) and much other
-      SCSI-BIOS do so. Therefore, I moved the IBMMCA_SCSI_ORDER_STANDARD 
-      define out of the driver and put it into Config.in as subitem of 
-      'IBM SCSI support'. A help, added to Documentation/Configure.help 
-      explains the differences between saying 'y' or 'n' to the user, when 
-      IBMMCA_SCSI_ORDER_STANDARD prompts, so the ordinary user is enabled to 
-      choose the way of assignment, depending on his own situation and gusto.
-   3) Adapted SCSI_IBMMCA_DEV_RESET to the local naming convention, so it is
-      now called IBMMCA_SCSI_DEV_RESET.
-   4) Optimization of proc_info and its subroutines.
-   5) Added more in-source-comments and extended the driver description by
-      some explanation about the SCSI-device-assignment problem.
-   - Michael Lang
-   
-   Jan 18, 1998: (v3.0g)
-   1) Correcting names to be absolutely conform to the later 2.1.x releases.
-      This is necessary for 
-            IBMMCA_SCSI_DEV_RESET -> CONFIG_IBMMCA_SCSI_DEV_RESET
-            IBMMCA_SCSI_ORDER_STANDARD -> CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-   - Michael Lang
- 
-   Jan 18, 1999: (v3.1 MCA-team internal)
-   1) The multiple hosts structure is accessed from every subroutine, so there
-      is no longer the address of the device structure passed from function
-      to function, but only the hostindex. A call by value, nothing more. This
-      should really be understood by the compiler and the subsystem should get
-      the right values and addresses.
-   2) The SCSI-subsystem detection was not complete and quite hugely buggy up
-      to now, compared to the technical manual. The interpretation of the pos2
-      register is not as assumed by people before, therefore, I dropped a note
-      in the ibmmca_detect function to show the registers' interpretation.
-      The pos-registers of integrated SCSI-subsystems do not contain any 
-      information concerning the IO-port offset, really. Instead, they contain
-      some info about the adapter, the chip, the NVRAM .... The I/O-port is
-      fixed to 0x3540 - 0x3547. There can be more than one adapters in the 
-      slots and they get an offset for the I/O area in order to get their own
-      I/O-address area. See chapter 2 for detailed description. At least, the 
-      detection should now work right, even on models other than 95. The 95ers
-      came happily around the bug, as their pos2 register contains always 0 
-      in the critical area. Reserved bits are not allowed to be interpreted, 
-      therefore, IBM is allowed to set those bits as they like and they may 
-      really vary between different PS/2 models. So, now, no interpretation 
-      of reserved bits - hopefully no trouble here anymore.
-   3) The command error, which you may get on models 55, 56, 57, 70, 77 and
-      P70 may have been caused by the fact, that adapters of older design do
-      not like sending commands to non-existing SCSI-devices and will react
-      with a command error as a sign of protest. While this error is not
-      present on IBM SCSI Adapter w/cache, it appears on IBM Integrated SCSI
-      Adapters. Therefore, I implemented a workaround to forgive those 
-      adapters their protests, but it is marked up in the statistics, so
-      after a successful boot, you can see in /proc/scsi/ibmmca/<host_number>
-      how often the command errors have been forgiven to the SCSI-subsystem.
-      If the number is bigger than 0, you have a SCSI subsystem of older
-      design, what should no longer matter.
-   4) ibmmca_getinfo() has been adapted very carefully, so it shows in the 
-      slotn file really, what is senseful to be presented.
-   5) ibmmca_register() has been extended in its parameter list in order to
-      pass the right name of the SCSI-adapter to Linux.
-   - Michael Lang
-
-   Feb 6, 1999: (v3.1)
-   1) Finally, after some 3.1Beta-releases, the 3.1 release. Sorry, for 
-      the delayed release, but it was not finished with the release of 
-      Kernel 2.2.0.
-   - Michael Lang
-   
-   Feb 10, 1999 (v3.1)
-   1) Added a new commandline parameter called 'bypass' in order to bypass
-      every integrated subsystem SCSI-command consequently in case of
-      troubles.
-   2) Concatenated read_capacity requests to the harddisks. It gave a lot
-      of troubles with some controllers and after I wanted to apply some
-      extensions, it jumped out in the same situation, on my w/cache, as like 
-      on D. Weinehalls' Model 56, having integrated SCSI. This gave me the 
-      decisive hint to move the code-part out and declare it global. Now
-      it seems to work far better and more stable. Let us see what
-      the world thinks of it...
-   3) By the way, only Sony DAT-drives seem to show density code 0x13. A
-      test with a HP drive gave right results, so the problem is vendor-
-      specific and not a problem of the OS or the driver.
-   - Michael Lang
-   
-   Feb 18, 1999 (v3.1d)
-   1) The abort command and the reset function have been checked for 
-      inconsistencies. From the logical point of thinking, they work
-      at their optimum, now, but as the subsystem does not answer with an
-      interrupt, abort never finishes, sigh...
-   2) Everything, that is accessed by a busmaster request from the adapter
-      is now declared as global variable, even the return-buffer in the
-      local checking phase. This assures, that no accesses to undefined memory
-      areas are performed.
-   3) In ibmmca.h, the line unchecked_isa_dma is added with 1 in order to
-      avoid memory-pointers for the areas higher than 16MByte in order to
-      be sure, it also works on 16-Bit Microchannel bus systems.
-   4) A lot of small things have been found, but nothing that endangered the
-      driver operations. Just it should be more stable, now.
-   - Michael Lang
-      
-   Feb 20, 1999 (v3.1e)
-   1) I took the warning from the Linux Kernel Hackers Guide serious and 
-      checked the cmd->result return value to the done-function very carefully.
-      It is obvious, that the IBM SCSI only delivers the tsb.dev_status, if
-      some error appeared, else it is undefined. Now, this is fixed. Before
-      any SCB command gets queued, the tsb.dev_status is set to 0, so the 
-      cmd->result won't screw up Linux higher level drivers.
-   2) The reset-function has slightly improved. This is still planned for 
-      abort. During the abort and the reset function, no interrupts are 
-      allowed. This is however quite hard to cope with, so the INT-status
-      register is read. When the interrupt gets queued, one can find its
-      status immediately on that register and is enabled to continue in the
-      reset function. I had no chance to test this really, only in a bogus 
-      situation, I got this function running, but the situation was too much
-      worse for Linux :-(, so tests will continue.
-   3) Buffers got now consistent. No open address mapping, as before and
-      therefore no further troubles with the unassigned memory segmentation
-      faults that scrambled probes on 95XX series and even on 85XX series,
-      when the kernel is done in a not so perfectly fitting way.
-   4) Spontaneous interrupts from the subsystem, appearing without any
-      command previously queued are answered with a DID_BAD_INTR result.
-   5) Taken into account ZP Gus' proposals to reverse the SCSI-device
-      scan order. As it does not work on Kernel 2.1.x or 2.2.x, as proposed
-      by him, I implemented it in a slightly derived way, which offers in 
-      addition more flexibility.
-   - Michael Lang
-
-   Apr 23, 2000 (v3.2pre1)
-   1) During a very long time, I collected a huge amount of bug reports from
-      various people, trying really quite different things on their SCSI-
-      PS/2s. Today, all these bug reports are taken into account and should be
-      mostly solved. The major topics were:
-      - Driver crashes during boottime by no obvious reason.
-      - Driver panics while the midlevel-SCSI-driver is trying to inquire
-        the SCSI-device properties, even though hardware is in perfect state.
-      - Displayed info for the various slot-cards is interpreted wrong.
-      The main reasons for the crashes were two:
-      1) The commands to check for device information like INQUIRY, 
-         TEST_UNIT_READY, REQUEST_SENSE and MODE_SENSE cause the devices
-	 to deliver information of up to 255 bytes. Midlevel drivers offer
-	 1024 bytes of space for the answer, but the IBM-SCSI-adapters do
-	 not accept this, as they stick quite near to ANSI-SCSI and report
-	 a COMMAND_ERROR message which causes the driver to panic. The main
-	 problem was located around the INQUIRY command. Now, for all the
-	 mentioned commands, the buffersize sent to the adapter is at 
-	 maximum 255 which seems to be a quite reasonable solution. 
-	 TEST_UNIT_READY gets a buffersize of 0 to make sure that no 
-	 data is transferred in order to avoid any possible command failure.
-      2) On unsuccessful TEST_UNIT_READY, the mid-level driver has to send
-         a REQUEST_SENSE in order to see where the problem is located. This
-	 REQUEST_SENSE may have various length in its answer-buffer. IBM
-	 SCSI-subsystems report a command failure if the returned buffersize
-	 is different from the sent buffersize, but this can be suppressed by
-	 a special bit, which is now done and problems seem to be solved.
-   2) Code adaption to all kernel-releases. Now, the 3.2 code compiles on 
-      2.0.x, 2.1.x, 2.2.x and 2.3.x kernel releases without any code-changes.
-   3) Commandline-parameters are recognized again, even under Kernel 2.3.x or
-      higher.
-   - Michael Lang   
-
-   April 27, 2000 (v3.2pre2)
-   1) Bypassed commands get read by the adapter by one cycle instead of two.
-      This increases SCSI-performance.
-   2) Synchronous datatransfer is provided for sure to be 5 MHz on older
-      SCSI and 10 MHz on internal F/W SCSI-adapter.
-   3) New commandline parameters allow to force the adapter to slow down while
-      in synchronous transfer. Could be helpful for very old devices.
-   - Michael Lang
-   
-   June 2, 2000 (v3.2pre5)
-   1) Added Jim Shorney's contribution to make the activity indicator
-      flashing in addition to the LED-alphanumeric display-panel on
-      models 95A. To be enabled to choose this feature freely, a new
-      commandline parameter is added, called 'activity'.
-   2) Added the READ_CONTROL bit for test_unit_ready SCSI-command.
-   3) Added some suppress_exception bits to read_device_capacity and
-      all device_inquiry occurrences in the driver code.
-   4) Complaints about the various KERNEL_VERSION implementations are
-      taken into account. Every local_LinuxKernelVersion occurrence is
-      now replaced by KERNEL_VERSION, defined in linux/version.h. 
-      Corresponding changes were applied to ibmmca.h, too. This was a
-      contribution to all kernel-parts by Philipp Hahn.
-   - Michael Lang
-   
-   July 17, 2000 (v3.2pre8)
-   A long period of collecting bug reports from all corners of the world
-   now lead to the following corrections to the code:
-   1) SCSI-2 F/W support crashed with a COMMAND ERROR. The reason for this 
-      was that it is possible to disable Fast-SCSI for the external bus.
-      The feature-control command, where this crash appeared regularly, tried
-      to set the maximum speed of 10MHz synchronous transfer speed and that
-      reports a COMMAND ERROR if external bus Fast-SCSI is disabled. Now,
-      the feature-command probes down from maximum speed until the adapter 
-      stops to complain, which is at the same time the maximum possible
-      speed selected in the reference program. So, F/W external can run at
-      5 MHz (slow-) or 10 MHz (fast-SCSI). During feature probing, the 
-      COMMAND ERROR message is used to detect if the adapter does not complain.
-   2) Up to now, only combined busmode is supported, if you use external
-      SCSI-devices, attached to the F/W-controller. If dual bus is selected,
-      only the internal SCSI-devices get accessed by Linux. For most 
-      applications, this should do fine. 
-   3) Wide-SCSI-addressing (16-Bit) is now possible for the internal F/W
-      bus on the F/W adapter. If F/W adapter is detected, the driver
-      automatically uses the extended PUN/LUN <-> LDN mapping tables, which
-      are now new from 3.2pre8. This allows PUNs between 0 and 15 and should
-      provide more fun with the F/W adapter.
-   4) Several machines use the SCSI: POS registers for internal/undocumented
-      storage of system relevant info. This confused the driver, mainly on
-      models 9595, as it expected no onboard SCSI only, if all POS in
-      the integrated SCSI-area are set to 0x00 or 0xff. Now, the mechanism
-      to check for integrated SCSI is much more restrictive and these problems
-      should be history.
-   - Michael Lang          
-
-   July 18, 2000 (v3.2pre9)
-   This develop rather quickly at the moment. Two major things were still
-   missing in 3.2pre8:
-   1) The adapter PUN for F/W adapters has 4-bits, while all other adapters
-      have 3-bits. This is now taken into account for F/W.
-   2) When you select CONFIG_IBMMCA_SCSI_ORDER_STANDARD, you should 
-      normally get the inverse probing order of your devices on the SCSI-bus.
-      The ANSI device order gets scrambled in version 3.2pre8!! Now, a new
-      and tested algorithm inverts the device-order on the SCSI-bus and
-      automatically avoids accidental access to whatever SCSI PUN the adapter 
-      is set and works with SCSI- and Wide-SCSI-addressing.
-   - Michael Lang
-
-   July 23, 2000 (v3.2pre10 unpublished) 
-   1) LED panel display supports wide-addressing in ibmmca=display mode.
-   2) Adapter-information and autoadaption to address-space is done.
-   3) Auto-probing for maximum synchronous SCSI transfer rate is working.
-   4) Optimization to some embedded function calls is applied.
-   5) Added some comment for the user to wait for SCSI-devices being probed.
-   6) Finished version 3.2 for Kernel 2.4.0. It least, I thought it is but...
-   - Michael Lang
-   
-   July 26, 2000 (v3.2pre11)
-   1) I passed a horrible weekend getting mad with NMIs on kernel 2.2.14 and
-      a model 9595. Asking around in the community, nobody except of me has
-      seen such errors. Weird, but I am trying to recompile everything on
-      the model 9595. Maybe, as I use a specially modified gcc, that could
-      cause problems. But, it was not the reason. The true background was,
-      that the kernel was compiled for i386 and the 9595 has a 486DX-2. 
-      Normally, no troubles should appear, but for this special machine,
-      only the right processor support is working fine!
-   2) Previous problems with synchronous speed, slowing down from one adapter 
-      to the next during probing are corrected. Now, local variables store
-      the synchronous bitmask for every single adapter found on the MCA bus.
-   3) LED alphanumeric panel support for XX95 systems is now showing some
-      alive rotator during boottime. This makes sense, when no monitor is 
-      connected to the system. You can get rid of all display activity, if
-      you do not use any parameter or just ibmmcascsi=activity, for the 
-      harddrive activity LED, existent on all PS/2, except models 8595-XXX.
-      If no monitor is available, please use ibmmcascsi=display, which works
-      fine together with the linuxinfo utility for the LED-panel.
-   - Michael Lang
-   
-   July 29, 2000 (v3.2)
-   1) Submission of this driver for kernel 2.4test-XX and 2.2.17.
-   - Michael Lang
-   
-   December 28, 2000 (v3.2d / v4.0)
-   1) The interrupt handler had some wrong statement to wait for. This
-      was done due to experimental reasons during 3.2 development but it
-      has shown that this is not stable enough. Going back to wait for the
-      adapter to be not busy is best.
-   2) Inquiry requests can be shorter than 255 bytes of return buffer. Due
-      to a bug in the ibmmca_queuecommand routine, this buffer was forced
-      to 255 at minimum. If the memory address, this return buffer is pointing
-      to does not offer more space, invalid memory accesses destabilized the
-      kernel.
-   3) version 4.0 is only valid for kernel 2.4.0 or later. This is necessary
-      to remove old kernel version dependent waste from the driver. 3.2d is
-      only distributed with older kernels but keeps compatibility with older
-      kernel versions. 4.0 and higher versions cannot be used with older 
-      kernels anymore!! You must have at least kernel 2.4.0!!
-   4) The commandline argument 'bypass' and all its functionality got removed
-      in version 4.0. This was never really necessary, as all troubles were
-      based on non-command related reasons up to now, so bypassing commands
-      did not help to avoid any bugs. It is kept in 3.2X for debugging reasons.
-   5) Dynamic reassignment of ldns was again verified and analyzed to be
-      completely inoperational. This is corrected and should work now.
-   6) All commands that get sent to the SCSI adapter were verified and
-      completed in such a way, that they are now completely conform to the
-      demands in the technical description of IBM. Main candidates were the
-      DEVICE_INQUIRY, REQUEST_SENSE and DEVICE_CAPACITY commands. They must
-      be transferred by bypassing the internal command buffer of the adapter
-      or else the response can be a random result. GET_POS_INFO would be more
-      safe in usage, if one could use the SUPRESS_EXCEPTION_SHORT, but this
-      is not allowed by the technical references of IBM. (Sorry, folks, the
-      model 80 problem is still a task to be solved in a different way.)
-   7) v3.2d is still hold back for some days for testing, while 4.0 is 
-      released.
-   - Michael Lang
-   
-   January 3, 2001 (v4.0a)
-   1) A lot of complains after the 2.4.0-prerelease kernel came in about
-      the impossibility to compile the driver as a module. This problem is
-      solved. In combination with that problem, some unprecise declaration
-      of the function option_setup() gave some warnings during compilation.
-      This is solved, too by a forward declaration in ibmmca.c.
-   2) #ifdef argument concerning CONFIG_SCSI_IBMMCA is no longer needed and
-      was entirely removed.
-   3) Some switch statements got optimized in code, as some minor variables
-      in internal SCSI-command handlers.
-   - Michael Lang
-
-   4 To do
-   -------
-        - IBM SCSI-2 F/W external SCSI bus support in separate mode!
-	- It seems that the handling of bad disks is really bad -
-	  non-existent, in fact. However, a low-level driver cannot help
-	  much, if such things happen.
-
-   5 Users' Manual
-   ---------------
-   5.1 Commandline Parameters
-   --------------------------
-   There exist several features for the IBM SCSI-subsystem driver.
-   The commandline parameter format is:
-   
-         ibmmcascsi=<command1>,<command2>,<command3>,...
-	 
-   where commandN can be one of the following:
-   
-         display    Owners of a model 95 or other PS/2 systems with an
-	            alphanumeric LED display may set this to have their
-		    display showing the following output of the 8 digits:
-		      
-		                ------DA
-				
-		    where '-' stays dark, 'D' shows the SCSI-device id
-		    and 'A' shows the SCSI hostindex, being currently 
-		    accessed. During boottime, this will give the message
-		    
-		                SCSIini*
-				
-                    on the LED-panel, where the * represents a rotator, 
-		    showing the activity during the probing phase of the
-		    driver which can take up to two minutes per SCSI-adapter.
-	 adisplay   This works like display, but gives more optical overview 
-	            of the activities on the SCSI-bus. The display will have
-		    the following output:
-		    
-		                6543210A
-				
-		    where the numbers 0 to 6 light up at the shown position,
-		    when the SCSI-device is accessed. 'A' shows again the SCSI
-		    hostindex. If display nor adisplay is set, the internal
-		    PS/2 harddisk LED is used for media-activities. So, if
-		    you really do not have a system with a LED-display, you
-		    should not set display or adisplay. Keep in mind, that
-		    display and adisplay can only be used alternatively. It
-		    is not recommended to use this option, if you have some
-		    wide-addressed devices e.g. at the SCSI-2 F/W adapter in
-		    your system. In addition, the usage of the display for
-		    other tasks in parallel, like the linuxinfo-utility makes 
-		    no sense with this option.
-	 activity   This enables the PS/2 harddisk LED activity indicator.
-	            Most PS/2 have no alphanumeric LED display, but some
-		    indicator. So you should use this parameter to activate it.
-		    If you own model 9595 (Server95), you can have both, the 
-		    LED panel and the activity indicator in parallel. However,
-		    some PS/2s, like the 8595 do not have any harddisk LED 
-		    activity indicator, which means, that you must use the
-		    alphanumeric LED display if you want to monitor SCSI-
-		    activity.
-	 bypass     This is obsolete from driver version 4.0, as the adapters
-	            got that far understood, that the selection between 
-		    integrated and bypassed commands should now work completely
-		    correct! For historical reasons, the old description is
-		    kept here:
-	            This commandline parameter forces the driver never to use
-	            SCSI-subsystems' integrated SCSI-command set. Except of
-		    the immediate assign, which is of vital importance for
-		    every IBM SCSI-subsystem to set its ldns right. Instead,
-		    the ordinary ANSI-SCSI-commands are used and passed by the
-		    controller to the SCSI-devices, therefore 'bypass'. The
-		    effort, done by the subsystem is quite bogus and at a
-		    minimum and therefore it should work everywhere. This
-		    could maybe solve troubles with old or integrated SCSI-
-		    controllers and nasty harddisks. Keep in mind, that using 
-		    this flag will slow-down SCSI-accesses slightly, as the 
-		    software generated commands are always slower than the 
-		    hardware. Non-harddisk devices always get read/write-
-		    commands in bypass mode. On the most recent releases of 
-		    the Linux IBM-SCSI-driver, the bypass command should be
-		    no longer a necessary thing, if you are sure about your
-		    SCSI-hardware!
-	 normal     This is the parameter, introduced on the 2.0.x development
-	            rail by ZP Gu. This parameter defines the SCSI-device
-		    scan order in the new industry standard. This means, that
-		    the first SCSI-device is the one with the lowest pun.
-		    E.g. harddisk at pun=0 is scanned before harddisk at
-		    pun=6, which means, that harddisk at pun=0 gets sda
-		    and the one at pun=6 gets sdb.
-	 ansi       The ANSI-standard for the right scan order, as done by
-	            IBM, Microware and Microsoft, scans SCSI-devices starting
-		    at the highest pun, which means, that e.g. harddisk at
-		    pun=6 gets sda and a harddisk at pun=0 gets sdb. If you
-		    like to have the same SCSI-device order, as in DOS, OS-9
-		    or OS/2, just use this parameter.
-         fast       SCSI-I/O in synchronous mode is done at 5 MHz for IBM-
-                    SCSI-devices. SCSI-2 Fast/Wide Adapter/A external bus
-                    should then run at 10 MHz if Fast-SCSI is enabled,
-                    and at 5 MHz if Fast-SCSI is disabled on the external
-                    bus. This is the default setting when nothing is 
-                    specified here.
-         medium     Synchronous rate is at 50% approximately, which means
-                    2.5 MHz for IBM SCSI-adapters and 5.0 MHz for F/W ext.
-                    SCSI-bus (when Fast-SCSI speed enabled on external bus).
-         slow       The slowest possible synchronous transfer rate is set. 
-                    This means 1.82 MHz for IBM SCSI-adapters and 2.0 MHz
-                    for F/W external bus at Fast-SCSI speed on the external
-		    bus.
-		    
-   A further option is that you can force the SCSI-driver to accept a SCSI-
-   subsystem at a certain I/O-address with a predefined adapter PUN. This
-   is done by entering 
-
-                  commandN   = I/O-base
-		  commandN+1 = adapter PUN
-		  
-   e.g. ibmmcascsi=0x3540,7 will force the driver to detect a SCSI-subsystem 
-   at I/O-address 0x3540 with adapter PUN 7. Please only use this method, if
-   the driver does really not recognize your SCSI-adapter! With driver version
-   3.2, this recognition of various adapters was hugely improved and you
-   should try first to remove your commandline arguments of such type with a 
-   newer driver. I bet, it will be recognized correctly. Even multiple and 
-   different types of IBM SCSI-adapters should be recognized correctly, too.
-   Use the forced detection method only as last solution!
-   
-   Examples:
-   
-        ibmmcascsi=adisplay
-	
-   This will use the advanced display mode for the model 95 LED alphanumeric
-   display.
-   
-        ibmmcascsi=display,0x3558,7
-	
-   This will activate the default display mode for the model 95 LED display
-   and will force the driver to accept a SCSI-subsystem at I/O-base 0x3558
-   with adapter PUN 7.
-   
-   5.2 Troubleshooting
-   -------------------
-   The following FAQs should help you to solve some major problems with this
-   driver.
-   
-     Q: "Reset SCSI-devices at boottime" halts the system at boottime, why?
-     A: This is only tested with the IBM SCSI Adapter w/cache. It is not
-        yet proven to run on other adapters, however you may be lucky.
-	In version 3.1d this has been hugely improved and should work better,
-	now. Normally you really won't need to activate this flag in the
-	kernel configuration, as all post 1989 SCSI-devices should accept
-	the reset-signal, when the computer is switched on. The SCSI-
-	subsystem generates this reset while being initialized. This flag
-	is really reserved for users with very old, very strange or self-made
-	SCSI-devices.
-     Q: Why is the SCSI-order of my drives mirrored to the device-order
-        seen from OS/2 or DOS ?
-     A: It depends on the operating system, if it looks at the devices in
-        ANSI-SCSI-standard (starting from pun 6 and going down to pun 0) or
-	if it just starts at pun 0 and counts up. If you want to be conform
-	with OS/2 and DOS, you have to activate this flag in the kernel
-	configuration or you should set 'ansi' as parameter for the kernel.
-	The parameter 'normal' sets the new industry standard, starting
-	from pun 0, scanning up to pun 6. This allows you to change your 
-	opinion still after having already compiled the kernel.
-     Q: Why can't I find IBM MCA SCSI support in the config menu?
-     A: You have to activate MCA bus support, first.
-     Q: Where can I find the latest info about this driver?
-     A: See the file MAINTAINERS for the current WWW-address, which offers
-        updates, info and Q/A lists. At this file's origin, the webaddress
-	was: http://www.staff.uni-mainz.de/mlang/linux.html
-     Q: My SCSI-adapter is not recognized by the driver, what can I do?
-     A: Just force it to be recognized by kernel parameters. See section 5.1.
-        If this really happens, do also send e-mail to the maintainer, as
-	forced detection should be never necessary. Forced detection is in
-	principal some flaw of the driver adapter detection and goes into 
-	bug reports.
-     Q: The driver screws up, if it starts to probe SCSI-devices, is there
-        some way out of it?
-     A: Yes, that was some recognition problem of the correct SCSI-adapter
-        and its I/O base addresses. Upgrade your driver to the latest release
-	and it should be fine again.
-     Q: I get a message: panic IBM MCA SCSI: command error .... , what can
-        I do against this?
-     A: Previously, I followed the way by ignoring command errors by using
-        ibmmcascsi=forgiveall, but this command no longer exists and is
-	obsolete. If such a problem appears, it is caused by some segmentation
-	fault of the driver, which maps to some unallowed area. The latest 
-	version of the driver should be ok, as most bugs have been solved.
-     Q: There are still kernel panics, even after having set 
-        ibmmcascsi=forgiveall. Are there other possibilities to prevent
-	such panics?
-     A: No, get just the latest release of the driver and it should work 
-        better and better with increasing version number. Forget about this
-	ibmmcascsi=forgiveall, as also ignorecmd are obsolete.!
-     Q: Linux panics or stops without any comment, but it is probable, that my
-        harddisk(s) have bad blocks.
-     A: Sorry, the bad-block handling is still a feeble point of this driver,
-        but is on the schedule for development in the near future.
-     Q: Linux panics while dynamically assigning SCSI-ids or ldns.
-     A: If you disconnect a SCSI-device from the machine, while Linux is up
-        and the driver uses dynamical reassignment of logical device numbers
-	(ldn), it really gets "angry" if it won't find devices, that were still
-	present at boottime and stops Linux.
-     Q: The system does not recover after an abort-command has been generated.
-     A: This is regrettably true, as it is not yet understood, why the 
-        SCSI-adapter does really NOT generate any interrupt at the end of
-	the abort-command. As no interrupt is generated, the abort command
-	cannot get finished and the system hangs, sorry, but checks are 
-	running to hunt down this problem. If there is a real pending command,
-	the interrupt MUST get generated after abort. In this case, it
-	should finish well.
-     Q: The system gets in bad shape after a SCSI-reset, is this known?
-     A: Yes, as there are a lot of prescriptions (see the Linux Hackers'
-        Guide) what has to be done for reset, we still share the bad shape of
-	the reset functions with all other low level SCSI-drivers. 
-	Astonishingly, reset works in most cases quite ok, but the harddisks
-	won't run in synchronous mode anymore after a reset, until you reboot.
-     Q: Why does my XXX w/Cache adapter not use read-prefetch?
-     A: Ok, that is not completely possible. If a cache is present, the 
-        adapter tries to use it internally. Explicitly, one can use the cache
-	with a read prefetch command, maybe in future, but this requires
-	some major overhead of SCSI-commands that risks the performance to
-	go down more than it gets improved. Tests with that are running.
-     Q: I have a IBM SCSI-2 Fast/Wide adapter, it boots in some way and hangs.
-     A: Yes, that is understood, as for sure, your SCSI-2 Fast/Wide adapter
-        was in such a case recognized as integrated SCSI-adapter or something 
-	else, but not as the correct adapter. As the I/O-ports get assigned 
-	wrongly by that reason, the system should crash in most cases. You 
-	should upgrade to the latest release of the SCSI-driver. The 
-	recommended version is 3.2 or later. Here, the F/W support is in
-	a stable and reliable condition. Wide-addressing is in addition 
-	supported.
-     Q: I get an Oops message and something like "killing interrupt".
-     A: The reason for this is that the IBM SCSI-subsystem only sends a 
-        termination status back, if some error appeared. In former releases
-	of the driver, it was not checked, if the termination status block
-	is NULL. From version 3.2, it is taken care of this.
-     Q: I have a F/W adapter and the driver sees my internal SCSI-devices,
-        but ignores the external ones.
-     A: Select combined busmode in the IBM config-program and check for that
-        no SCSI-id on the external devices appears on internal devices.
-        Reboot afterwards. Dual busmode is supported, but works only for the
-	internal bus, yet. External bus is still ignored. Take care for your
-	SCSI-ids. If combined bus-mode is activated, on some adapters, 
-	the wide-addressing is not possible, so devices with ids between 8 
-	and 15 get ignored by the driver & adapter!
-     Q: I have a 9595 and I get a NMI during heavy SCSI I/O e.g. during fsck.
-        A COMMAND ERROR is reported and characters on the screen are missing.
-	Warm reboot is not possible. Things look like quite weird.
-     A: Check the processor type of your 9595. If you have an 80486 or 486DX-2
-        processor complex on your mainboard and you compiled a kernel that
-	supports 80386 processors, it is possible, that the kernel cannot
-	keep track of the PS/2 interrupt handling and stops on an NMI. Just
-	compile a kernel for the correct processor type of your PS/2 and
-	everything should be fine. This is necessary even if one assumes,
-	that some 80486 system should be downward compatible to 80386
-	software.
-     Q: Some commands hang and interrupts block the machine. After some
-        timeout, the syslog reports that it tries to call abort, but the
-	machine is frozen.
-     A: This can be a busy wait bug in the interrupt handler of driver 
-        version 3.2. You should at least upgrade to 3.2c if you use 
-	kernel < 2.4.0 and driver version 4.0 if you use kernel 2.4.0 or 
-	later (including all test releases).
-     Q: I have a PS/2 model 80 and more than 16 MBytes of RAM. The driver
-        completely refuses to work, reports NMIs, COMMAND ERRORs or other
-	ambiguous stuff. When reducing the RAM size down below 16 MB, 
-	everything is running smoothly.
-     A: No real answer, yet. In any case, one should force the kernel to
-        present SCBs only below the 16 MBytes barrier. Maybe this solves the
-	problem. Not yet tried, but guessing that it could work. To get this,
-	set unchecked_isa_dma argument of ibmmca.h from 0 to 1.
-
-   5.3 Bug reports
-   --------------
-   If you really find bugs in the source code or the driver will successfully
-   refuse to work on your machine, you should send a bug report to me. The
-   best for this is to follow the instructions on the WWW-page for this
-   driver. Fill out the bug-report form, placed on the WWW-page and ship it,
-   so the bugs can be taken into account with maximum efforts. But, please
-   do not send bug reports about this driver to Linus Torvalds or Leonard
-   Zubkoff, as Linus is buried in E-Mail and Leonard is supervising all
-   SCSI-drivers and won't have the time left to look inside every single
-   driver to fix a bug and especially DO NOT send modified code to Linus
-   Torvalds or Alan J. Cox which has not been checked here!!! They are both
-   quite buried in E-mail (as me, sometimes, too) and one should first check
-   for problems on my local teststand. Recently, I got a lot of 
-   bug reports for errors in the ibmmca.c code, which I could not imagine, but
-   a look inside some Linux-distribution showed me quite often some modified
-   code, which did no longer work on most other machines than the one of the
-   modifier. Ok, so now that there is maintenance service available for this
-   driver, please use this address first in order to keep the level of
-   confusion low. Thank you!
-   
-   When you get a SCSI-error message that panics your system, a list of
-   register-entries of the SCSI-subsystem is shown (from Version 3.1d). With 
-   this list, it is very easy for the maintainer to localize the problem in 
-   the driver or in the configuration of the user. Please write down all the 
-   values from this report and send them to the maintainer. This would really 
-   help a lot and makes life easier concerning misunderstandings.
-   
-   Use the bug-report form (see 5.4 for its address) to send all the bug-
-   stuff to the maintainer or write e-mail with the values from the table. 
-   
-   5.4 Support WWW-page
-   --------------------
-   The address of the IBM SCSI-subsystem supporting WWW-page is:
-   
-        http://www.staff.uni-mainz.de/mlang/linux.html
-	
-   Here you can find info about the background of this driver, patches,
-   troubleshooting support, news and a bugreport form. Please check that
-   WWW-page regularly for latest hints. If ever this URL changes, please 
-   refer to the MAINTAINERS file in order to get the latest address.
-   
-   For the bugreport, please fill out the formular on the corresponding
-   WWW-page. Read the dedicated instructions and write as much as you
-   know about your problem. If you do not like such formulars, please send
-   some e-mail directly, but at least with the same information as required by
-   the formular.
-   
-   If you have extensive bug reports, including Oops messages and
-   screen-shots, please feel free to send it directly to the address
-   of the maintainer, too. The current address of the maintainer is:
-   
-            Michael Lang <langa2@kph.uni-mainz.de>
-   
-   6 References
-   ------------
-   IBM Corp., "Update for the PS/2 Hardware Interface Technical Reference, 
-   Common Interfaces", Armonk, September 1991, PN 04G3281, 
-   (available in the U.S. for $21.75 at 1-800-IBM-PCTB or in Germany for
-   around 40,-DM at "Hallo IBM").
-  
-   IBM Corp., "Personal System/2 Micro Channel SCSI
-   Adapter with Cache Technical Reference", Armonk, March 1990, PN 68X2365.
-
-   IBM Corp., "Personal System/2 Micro Channel SCSI
-   Adapter Technical Reference", Armonk, March 1990, PN 68X2397.
-
-   IBM Corp., "SCSI-2 Fast/Wide Adapter/A Technical Reference - Dual Bus",
-   Armonk, March 1994, PN 83G7545.
- 
-   Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie-
-   Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl.
-   Addison Wesley, 1996.
-   
-   Michael K. Johnson, "The Linux Kernel Hackers' Guide", Version 0.6, Chapel
-   Hill - North Carolina, 1995
-   
-   Andreas Kaiser, "SCSI TAPE BACKUP for OS/2 2.0", Version 2.12, Stuttgart
-   1993
-   
-   Helmut Rompel, "IBM Computerwelt GUIDE", What is what bei IBM., Systeme *
-   Programme * Begriffe, IWT-Verlag GmbH - Muenchen, 1988
-   
-   7 Credits to
-   ------------
-   7.1 People
-   ----------
-   Klaus Grimm
-                who already a long time ago gave me the old code from the
-		SCSI-driver in order to get it running for some old machine
-		in our institute.
-   Martin Kolinek
-                who wrote the first release of the IBM SCSI-subsystem driver.
-   Chris Beauregard
-                who for a long time maintained MCA-Linux and the SCSI-driver
-		in the beginning. Chris, wherever you are: Cheers to you!
-   Klaus Kudielka
-                with whom in the 2.1.x times, I had a quite fruitful
-                cooperation to get the driver running as a module and to get
-		it running with multiple SCSI-adapters.
-   David Weinehall
-                for his excellent maintenance of the MCA-stuff and the quite 
-		detailed bug reports and ideas for this driver (and his 
-		patience ;-)).
-   Alan J. Cox  
-                for his bug reports and his bold activities in cross-checking
-		the driver-code with his teststand.
-		
-   7.2 Sponsors & Supporters
-   -------------------------
-   "Hallo IBM",
-   IBM-Deutschland GmbH
-                the service of IBM-Deutschland for customers. Their E-Mail
-		service is unbeatable. Whatever old stuff I asked for, I 
-		always got some helpful answers.
-   Karl-Otto Reimers,
-   IBM Klub - Sparte IBM Geschichte, Sindelfingen
-                for sending me a copy of the w/Cache manual from the 
-		IBM-Deutschland archives.
-   Harald Staiger
-                for his extensive hardware donations which allows me today
-		still to test the driver in various constellations.
-   Erich Fritscher
-                for his very kind sponsoring.
-   Louis Ohland,
-   Charles Lasitter
-                for support by shipping me an IBM SCSI-2 Fast/Wide manual.
-                In addition, the contribution of various hardware is quite 
-                decessive and will make it possible to add FWSR (RAID)
-                adapter support to the driver in the near future! So,
-                complaints about no RAID support won't remain forever.
-                Yes, folks, that is no joke, RAID support is going to rise!
-   Erik Weber
-                for the great deal we made about a model 9595 and the nice
-                surrounding equipment and the cool trip to Mannheim
-                second-hand computer market. In addition, I would like
-		to thank him for his exhaustive SCSI-driver testing on his 
-		95er PS/2 park.
-   Anthony Hogbin
-                for his direct shipment of a SCSI F/W adapter, which allowed
-                me immediately on the first stage to try it on model 8557
-                together with onboard SCSI adapter and some SCSI w/Cache.
-   Andreas Hotz
-                for his support by memory and an IBM SCSI-adapter. Collecting
-                all this together now allows me to try really things with
-                the driver at maximum load and variety on various models in
-                a very quick and efficient way.
-   Peter Jennewein
-                for his model 30, which serves me as part of my teststand
-		and his cool remark about how you make an ordinary diskette
-		drive working and how to connect it to an IBM-diskette port.
-   Johannes Gutenberg-Universitaet, Mainz &
-   Institut fuer Kernphysik, Mainz Microtron (MAMI)
-                for the offered space, the link, placed on the central
-                homepage and the space to store and offer the driver and 
-		related material and the free working times, which allow
-                me to answer all your e-mail.
-                   
-   8 Trademarks
-   ------------
-   IBM, PS/2, OS/2, Microchannel are registered trademarks of International 
-   Business Machines Corporation
-   
-   MS-DOS is a registered trademark of Microsoft Corporation
-   
-   Microware, OS-9 are registered trademarks of Microware Systems
-   
-   9 Disclaimer
-   ------------
-   Beside the GNU General Public License and the dependent disclaimers and disclaimers
-   concerning the Linux-kernel in special, this SCSI-driver comes without any
-   warranty. Its functionality is tested as good as possible on certain 
-   machines and combinations of computer hardware, which does not exclude,
-   that data loss or severe damage of hardware is possible while using this
-   part of software on some arbitrary computer hardware or in combination 
-   with other software packages. It is highly recommended to make backup
-   copies of your data before using this software. Furthermore, personal
-   injuries by hardware defects, that could be caused by this SCSI-driver are
-   not excluded and it is highly recommended to handle this driver with a
-   maximum of carefulness.
-   
-   This driver supports hardware, produced by International Business Machines
-   Corporation (IBM).
-   
-------
-Michael Lang 
-(langa2@kph.uni-mainz.de)
diff --git a/Documentation/scsi/scsi-parameters.txt b/Documentation/scsi/scsi-parameters.txt
index 21e5798..2bfd6f6 100644
--- a/Documentation/scsi/scsi-parameters.txt
+++ b/Documentation/scsi/scsi-parameters.txt
@@ -37,9 +37,6 @@
 
 	eata=		[HW,SCSI]
 
-	fd_mcs=		[HW,SCSI]
-			See header of drivers/scsi/fd_mcs.c.
-
 	fdomain=	[HW,SCSI]
 			See header of drivers/scsi/fdomain.c.
 
@@ -48,9 +45,6 @@
 
 	gvp11=		[HW,SCSI]
 
-	ibmmcascsi=	[HW,MCA,SCSI] IBM MicroChannel SCSI adapter
-			See Documentation/mca.txt.
-
 	in2000=		[HW,SCSI]
 			See header of drivers/scsi/in2000.c.
 
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
index a340b18..2b06aba 100644
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -30,7 +30,7 @@
 and thus represent two hosts. Like most modern HBAs, each aic7xxx host
 has its own PCI device address. [The one-to-one correspondence between
 a SCSI host and a PCI device is common but not required (e.g. with
-ISA or MCA adapters).]
+ISA adapters).]
 
 The SCSI mid level isolates an LLD from other layers such as the SCSI
 upper layer drivers and the block layer.
diff --git a/Documentation/serial/stallion.txt b/Documentation/serial/stallion.txt
index 5509091..4d798c0 100644
--- a/Documentation/serial/stallion.txt
+++ b/Documentation/serial/stallion.txt
@@ -20,10 +20,10 @@
 multiport serial boards. One is for the Stallion smart boards - that is
 EasyIO, EasyConnection 8/32 and EasyConnection 8/64-PCI, the other for
 the true Stallion intelligent multiport boards - EasyConnection 8/64
-(ISA, EISA, MCA), EasyConnection/RA-PCI, ONboard and Brumby.
+(ISA, EISA), EasyConnection/RA-PCI, ONboard and Brumby.
 
 If you are using any of the Stallion intelligent multiport boards (Brumby,
-ONboard, EasyConnection 8/64 (ISA, EISA, MCA), EasyConnection/RA-PCI) with
+ONboard, EasyConnection 8/64 (ISA, EISA), EasyConnection/RA-PCI) with
 Linux you will need to get the driver utility package.  This contains a
 firmware loader and the firmware images necessary to make the devices operate.
 
@@ -40,7 +40,7 @@
 boards then you don't need this package, although it does have a serial stats
 display program.
 
-If you require DIP switch settings, EISA or MCA configuration files, or any
+If you require DIP switch settings, or EISA configuration files, or any
 other information related to Stallion boards then have a look at Stallion's
 web pages at http://www.stallion.com.
 
@@ -51,13 +51,13 @@
 The drivers can be used as loadable modules or compiled into the kernel.
 You can choose which when doing a "config" on the kernel.
 
-All ISA, EISA and MCA boards that you want to use need to be configured into
+All ISA, and EISA boards that you want to use need to be configured into
 the driver(s). All PCI boards will be automatically detected when you load
 the driver - so they do not need to be entered into the driver(s)
 configuration structure. Note that kernel PCI support is required to use PCI
 boards.
 
-There are two methods of configuring ISA, EISA and MCA boards into the drivers.
+There are two methods of configuring ISA and EISA boards into the drivers.
 If using the driver as a loadable module then the simplest method is to pass
 the driver configuration as module arguments. The other method is to modify
 the driver source to add configuration lines for each board in use.
@@ -71,12 +71,12 @@
 2.1 MODULE DRIVER CONFIGURATION:
 
 The simplest configuration for modules is to use the module load arguments
-to configure any ISA, EISA or MCA boards. PCI boards are automatically
+to configure any ISA or EISA boards. PCI boards are automatically
 detected, so do not need any additional configuration at all.
 
-If using EasyIO, EasyConnection 8/32 ISA or MCA, or EasyConnection 8/63-PCI
+If using EasyIO, EasyConnection 8/32 ISA, or EasyConnection 8/63-PCI
 boards then use the "stallion" driver module, Otherwise if you are using
-an EasyConnection 8/64 ISA, EISA or MCA, EasyConnection/RA-PCI, ONboard,
+an EasyConnection 8/64 ISA or EISA, EasyConnection/RA-PCI, ONboard,
 Brumby or original Stallion board then use the "istallion" driver module.
 
 Typically to load up the smart board driver use:
@@ -146,7 +146,7 @@
 2.2 STATIC DRIVER CONFIGURATION:
 
 For static driver configuration you need to modify the driver source code.
-Entering ISA, EISA and MCA boards into the driver(s) configuration structure
+Entering ISA and EISA boards into the driver(s) configuration structure
 involves editing the driver(s) source file. It's pretty easy if you follow
 the instructions below. Both drivers can support up to 4 boards. The smart
 card driver (the stallion.c driver) supports any combination of EasyIO and
@@ -157,7 +157,7 @@
 To set up the driver(s) for the boards that you want to use you need to
 edit the appropriate driver file and add configuration entries.
 
-If using EasyIO or EasyConnection 8/32 ISA or MCA boards,
+If using EasyIO or EasyConnection 8/32 ISA boards,
    In drivers/char/stallion.c:
       - find the definition of the stl_brdconf array (of structures)
         near the top of the file
@@ -243,7 +243,7 @@
 On EasyIO and EasyConnection 8/32 boards the IRQ is software programmable, so
 if there is a conflict you may need to change the IRQ used for a board. There
 are no interrupts to worry about for ONboard, Brumby or EasyConnection 8/64
-(ISA, EISA and MCA) boards. The memory region on EasyConnection 8/64 and
+(ISA and EISA) boards. The memory region on EasyConnection 8/64 and
 ONboard boards is software programmable, but not on the Brumby boards.
 
 
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 8c16d50..221b810 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -1545,7 +1545,7 @@
 
     Module for sound cards based on the C-Media CMI8786/8787/8788 chip:
     * Asound A-8788
-    * Asus Xonar DG
+    * Asus Xonar DG/DGX
     * AuzenTech X-Meridian
     * AuzenTech X-Meridian 2G
     * Bgears b-Enspirer
diff --git a/Documentation/sound/alsa/compress_offload.txt b/Documentation/sound/alsa/compress_offload.txt
index c83a835..90e9b3a 100644
--- a/Documentation/sound/alsa/compress_offload.txt
+++ b/Documentation/sound/alsa/compress_offload.txt
@@ -18,7 +18,7 @@
 mostly because of a lack of a generic API available in the mainline
 kernel.
 
-Rather than requiring a compability break with an API change of the
+Rather than requiring a compatibility break with an API change of the
 ALSA PCM interface, a new 'Compressed Data' API is introduced to
 provide a control and data-streaming interface for audio DSPs.
 
diff --git a/Documentation/sound/oss/ALS b/Documentation/sound/oss/ALS
index d01ffbf..bf10bed 100644
--- a/Documentation/sound/oss/ALS
+++ b/Documentation/sound/oss/ALS
@@ -57,10 +57,10 @@
     DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono).
 
 Jonathan Woithe
-jwoithe@physics.adelaide.edu.au
+jwoithe@just42.net
 30 March 1998
 
 Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200
 Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info.
-Modified 2000-11-19 by Jonathan Woithe, jwoithe@physics.adelaide.edu.au
+Modified 2000-11-19 by Jonathan Woithe, jwoithe@just42.net
  - updated information for kernel 2.4.x.
diff --git a/Documentation/static-keys.txt b/Documentation/static-keys.txt
index d93f3c0..9f5263d 100644
--- a/Documentation/static-keys.txt
+++ b/Documentation/static-keys.txt
@@ -235,7 +235,7 @@
 6 (mov) + 2 (test) + 2 (jne) = 10 - 5 (5 byte jump 0) = 5 addition bytes.
 
 If we then include the padding bytes, the jump label code saves, 16 total bytes
-of instruction memory for this small fucntion. In this case the non-jump label
+of instruction memory for this small function. In this case the non-jump label
 function is 80 bytes long. Thus, we have have saved 20% of the instruction
 footprint. We can in fact improve this even further, since the 5-byte no-op
 really can be a 2-byte no-op since we can reach the branch with a 2-byte jmp.
diff --git a/Documentation/trace/uprobetracer.txt b/Documentation/trace/uprobetracer.txt
new file mode 100644
index 0000000..24ce682
--- /dev/null
+++ b/Documentation/trace/uprobetracer.txt
@@ -0,0 +1,113 @@
+		Uprobe-tracer: Uprobe-based Event Tracing
+		=========================================
+                 Documentation written by Srikar Dronamraju
+
+Overview
+--------
+Uprobe based trace events are similar to kprobe based trace events.
+To enable this feature, build your kernel with CONFIG_UPROBE_EVENT=y.
+
+Similar to the kprobe-event tracer, this doesn't need to be activated via
+current_tracer. Instead of that, add probe points via
+/sys/kernel/debug/tracing/uprobe_events, and enable it via
+/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled.
+
+However unlike kprobe-event tracer, the uprobe event interface expects the
+user to calculate the offset of the probepoint in the object
+
+Synopsis of uprobe_tracer
+-------------------------
+  p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS]	: Set a probe
+
+ GRP		: Group name. If omitted, use "uprobes" for it.
+ EVENT		: Event name. If omitted, the event name is generated
+		  based on SYMBOL+offs.
+ PATH		: path to an executable or a library.
+ SYMBOL[+offs]	: Symbol+offset where the probe is inserted.
+
+ FETCHARGS	: Arguments. Each probe can have up to 128 args.
+  %REG		: Fetch register REG
+
+Event Profiling
+---------------
+ You can check the total number of probe hits and probe miss-hits via
+/sys/kernel/debug/tracing/uprobe_profile.
+ The first column is event name, the second is the number of probe hits,
+the third is the number of probe miss-hits.
+
+Usage examples
+--------------
+To add a probe as a new event, write a new definition to uprobe_events
+as below.
+
+  echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events
+
+ This sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash
+
+  echo > /sys/kernel/debug/tracing/uprobe_events
+
+ This clears all probe points.
+
+The following example shows how to dump the instruction pointer and %ax
+a register at the probed text address.  Here we are trying to probe
+function zfree in /bin/zsh
+
+    # cd /sys/kernel/debug/tracing/
+    # cat /proc/`pgrep  zsh`/maps | grep /bin/zsh | grep r-xp
+    00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh
+    # objdump -T /bin/zsh | grep -w zfree
+    0000000000446420 g    DF .text  0000000000000012  Base        zfree
+
+0x46420 is the offset of zfree in object /bin/zsh that is loaded at
+0x00400000. Hence the command to probe would be :
+
+    # echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events
+
+Please note: User has to explicitly calculate the offset of the probepoint
+in the object. We can see the events that are registered by looking at the
+uprobe_events file.
+
+    # cat uprobe_events
+    p:uprobes/p_zsh_0x46420 /bin/zsh:0x00046420 arg1=%ip arg2=%ax
+
+The format of events can be seen by viewing the file events/uprobes/p_zsh_0x46420/format
+
+    # cat events/uprobes/p_zsh_0x46420/format
+    name: p_zsh_0x46420
+    ID: 922
+    format:
+	field:unsigned short common_type;	offset:0;	size:2;	signed:0;
+	field:unsigned char common_flags;	offset:2;	size:1;	signed:0;
+	field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0;
+	field:int common_pid;	offset:4;	size:4;	signed:1;
+	field:int common_padding;	offset:8;	size:4;	signed:1;
+
+	field:unsigned long __probe_ip;	offset:12;	size:4;	signed:0;
+	field:u32 arg1;	offset:16;	size:4;	signed:0;
+	field:u32 arg2;	offset:20;	size:4;	signed:0;
+
+    print fmt: "(%lx) arg1=%lx arg2=%lx", REC->__probe_ip, REC->arg1, REC->arg2
+
+Right after definition, each event is disabled by default. For tracing these
+events, you need to enable it by:
+
+    # echo 1 > events/uprobes/enable
+
+Lets disable the event after sleeping for some time.
+    # sleep 20
+    # echo 0 > events/uprobes/enable
+
+And you can see the traced information via /sys/kernel/debug/tracing/trace.
+
+    # cat trace
+    # tracer: nop
+    #
+    #           TASK-PID    CPU#    TIMESTAMP  FUNCTION
+    #              | |       |          |         |
+                 zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
+                 zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
+                 zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
+                 zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
+
+Each line shows us probes were triggered for a pid 24842 with ip being
+0x446421 and contents of ax register being 79.
diff --git a/Documentation/usb/dwc3.txt b/Documentation/usb/dwc3.txt
index 7b590ed..1d02c01 100644
--- a/Documentation/usb/dwc3.txt
+++ b/Documentation/usb/dwc3.txt
@@ -28,7 +28,7 @@
       none
 
     - primary handler of the EP-interrupt
-      reads the event and tries to process it. Everything that requries
+      reads the event and tries to process it. Everything that requires
       sleeping is handed over to the Thread. The event is saved in an
       per-endpoint data-structure.
       We probably have to pay attention not to process events once we
diff --git a/Documentation/usb/functionfs.txt b/Documentation/usb/functionfs.txt
new file mode 100644
index 0000000..eaaaea0
--- /dev/null
+++ b/Documentation/usb/functionfs.txt
@@ -0,0 +1,67 @@
+*How FunctionFS works*
+
+From kernel point of view it is just a composite function with some
+unique behaviour.  It may be added to an USB configuration only after
+the user space driver has registered by writing descriptors and
+strings (the user space program has to provide the same information
+that kernel level composite functions provide when they are added to
+the configuration).
+
+This in particular means that the composite initialisation functions
+may not be in init section (ie. may not use the __init tag).
+
+From user space point of view it is a file system which when
+mounted provides an "ep0" file.  User space driver need to
+write descriptors and strings to that file.  It does not need
+to worry about endpoints, interfaces or strings numbers but
+simply provide descriptors such as if the function was the
+only one (endpoints and strings numbers starting from one and
+interface numbers starting from zero).  The FunctionFS changes
+them as needed also handling situation when numbers differ in
+different configurations.
+
+When descriptors and strings are written "ep#" files appear
+(one for each declared endpoint) which handle communication on
+a single endpoint.  Again, FunctionFS takes care of the real
+numbers and changing of the configuration (which means that
+"ep1" file may be really mapped to (say) endpoint 3 (and when
+configuration changes to (say) endpoint 2)).  "ep0" is used
+for receiving events and handling setup requests.
+
+When all files are closed the function disables itself.
+
+What I also want to mention is that the FunctionFS is designed in such
+a way that it is possible to mount it several times so in the end
+a gadget could use several FunctionFS functions. The idea is that
+each FunctionFS instance is identified by the device name used
+when mounting.
+
+One can imagine a gadget that has an Ethernet, MTP and HID interfaces
+where the last two are implemented via FunctionFS.  On user space
+level it would look like this:
+
+$ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid
+$ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp
+$ ( cd /dev/ffs-mtp && mtp-daemon ) &
+$ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid
+$ ( cd /dev/ffs-hid && hid-daemon ) &
+
+On kernel level the gadget checks ffs_data->dev_name to identify
+whether it's FunctionFS designed for MTP ("mtp") or HID ("hid").
+
+If no "functions" module parameters is supplied, the driver accepts
+just one function with any name.
+
+When "functions" module parameter is supplied, only functions
+with listed names are accepted. In particular, if the "functions"
+parameter's value is just a one-element list, then the behaviour
+is similar to when there is no "functions" at all; however,
+only a function with the specified name is accepted.
+
+The gadget is registered only after all the declared function
+filesystems have been mounted and USB descriptors of all functions
+have been written to their ep0's.
+
+Conversely, the gadget is unregistered after the first USB function
+closes its endpoints.
+
diff --git a/Documentation/usb/wusb-cbaf b/Documentation/usb/wusb-cbaf
index 426ddaa..8b3d43e 100644
--- a/Documentation/usb/wusb-cbaf
+++ b/Documentation/usb/wusb-cbaf
@@ -36,7 +36,7 @@
 
  get-cdid DEVICE
 
-   Get the device ID associated to the HOST-CHDI we sent with
+   Get the device ID associated to the HOST-CHID we sent with
    'set-chid'. We might not know about it.
 
  set-cc DEVICE
diff --git a/Documentation/video4linux/4CCs.txt b/Documentation/video4linux/4CCs.txt
new file mode 100644
index 0000000..41241af
--- /dev/null
+++ b/Documentation/video4linux/4CCs.txt
@@ -0,0 +1,32 @@
+Guidelines for Linux4Linux pixel format 4CCs
+============================================
+
+Guidelines for Video4Linux 4CC codes defined using v4l2_fourcc() are
+specified in this document. First of the characters defines the nature of
+the pixel format, compression and colour space. The interpretation of the
+other three characters depends on the first one.
+
+Existing 4CCs may not obey these guidelines.
+
+Formats
+=======
+
+Raw bayer
+---------
+
+The following first characters are used by raw bayer formats:
+
+	B: raw bayer, uncompressed
+	b: raw bayer, DPCM compressed
+	a: A-law compressed
+	u: u-law compressed
+
+2nd character: pixel order
+	B: BGGR
+	G: GBRG
+	g: GRBG
+	R: RGGB
+
+3rd character: uncompressed bits-per-pixel 0--9, A--
+
+4th character: compressed bits-per-pixel 0--9, A--
diff --git a/Documentation/video4linux/README.cpia2 b/Documentation/video4linux/README.cpia2
index ce8213d..38e742f 100644
--- a/Documentation/video4linux/README.cpia2
+++ b/Documentation/video4linux/README.cpia2
@@ -12,7 +12,7 @@
 	The driver is implemented as two kernel modules. The cpia2 module
 contains the camera functions and the V4L interface.  The cpia2_usb module
 contains usb specific functions.  The main reason for this was the size of the
-module was getting out of hand, so I separted them.  It is not likely that
+module was getting out of hand, so I separated them.  It is not likely that
 there will be a parallel port version.
 
 FEATURES:
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index e6c2842..1e6b653 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -276,6 +276,7 @@
 pac7302		093a:2624	PAC7302
 pac7302		093a:2625	Genius iSlim 310
 pac7302		093a:2626	Labtec 2200
+pac7302		093a:2627	Genius FaceCam 300
 pac7302		093a:2628	Genius iLook 300
 pac7302		093a:2629	Genious iSlim 300
 pac7302		093a:262a	Webcam 300k
diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index e2492a9..43da22b 100644
--- a/Documentation/video4linux/v4l2-controls.txt
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -130,8 +130,18 @@
 			const struct v4l2_ctrl_ops *ops,
 			u32 id, s32 max, s32 skip_mask, s32 def);
 
+Or alternatively for integer menu controls, by calling v4l2_ctrl_new_int_menu:
+
+	struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
+			const struct v4l2_ctrl_ops *ops,
+			u32 id, s32 max, s32 def, const s64 *qmenu_int);
+
 These functions are typically called right after the v4l2_ctrl_handler_init:
 
+	static const s64 exp_bias_qmenu[] = {
+	       -2, -1, 0, 1, 2
+	};
+
 	v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
 	v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
@@ -141,6 +151,11 @@
 			V4L2_CID_POWER_LINE_FREQUENCY,
 			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
 			V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
+	v4l2_ctrl_new_int_menu(&foo->ctrl_handler, &foo_ctrl_ops,
+			V4L2_CID_EXPOSURE_BIAS,
+			ARRAY_SIZE(exp_bias_qmenu) - 1,
+			ARRAY_SIZE(exp_bias_qmenu) / 2 - 1,
+			exp_bias_qmenu);
 	...
 	if (foo->ctrl_handler.error) {
 		int err = foo->ctrl_handler.error;
@@ -164,6 +179,12 @@
 and instead of a step there is a skip_mask argument: if bit X is 1, then menu
 item X is skipped.
 
+The v4l2_ctrl_new_int_menu function creates a new standard integer menu
+control with driver-specific items in the menu. It differs from
+v4l2_ctrl_new_std_menu in that it doesn't have the mask argument and takes
+as the last argument an array of signed 64-bit integers that form an exact
+menu item list.
+
 Note that if something fails, the function will return NULL or an error and
 set ctrl_handler->error to the error code. If ctrl_handler->error was already
 set, then it will just return and do nothing. This is also true for
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 659b2ba..1f59052 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -182,11 +182,11 @@
 }
 
 If you have multiple device nodes then it can be difficult to know when it is
-safe to unregister v4l2_device. For this purpose v4l2_device has refcounting
-support. The refcount is increased whenever video_register_device is called and
-it is decreased whenever that device node is released. When the refcount reaches
-zero, then the v4l2_device release() callback is called. You can do your final
-cleanup there.
+safe to unregister v4l2_device for hotpluggable devices. For this purpose
+v4l2_device has refcounting support. The refcount is increased whenever
+video_register_device is called and it is decreased whenever that device node
+is released. When the refcount reaches zero, then the v4l2_device release()
+callback is called. You can do your final cleanup there.
 
 If other device nodes (e.g. ALSA) are created, then you can increase and
 decrease the refcount manually as well by calling:
@@ -197,6 +197,10 @@
 
 int v4l2_device_put(struct v4l2_device *v4l2_dev);
 
+Since the initial refcount is 1 you also need to call v4l2_device_put in the
+disconnect() callback (for USB devices) or in the remove() callback (for e.g.
+PCI devices), otherwise the refcount will never reach 0.
+
 struct v4l2_subdev
 ------------------
 
@@ -262,11 +266,16 @@
 	...
 };
 
+struct v4l2_subdev_pad_ops {
+	...
+};
+
 struct v4l2_subdev_ops {
 	const struct v4l2_subdev_core_ops  *core;
 	const struct v4l2_subdev_tuner_ops *tuner;
 	const struct v4l2_subdev_audio_ops *audio;
 	const struct v4l2_subdev_video_ops *video;
+	const struct v4l2_subdev_pad_ops *video;
 };
 
 The core ops are common to all subdevs, the other categories are implemented
@@ -303,6 +312,22 @@
 
 	media_entity_cleanup(&sd->entity);
 
+If the subdev driver intends to process video and integrate with the media
+framework, it must implement format related functionality using
+v4l2_subdev_pad_ops instead of v4l2_subdev_video_ops.
+
+In that case, the subdev driver may set the link_validate field to provide
+its own link validation function. The link validation function is called for
+every link in the pipeline where both of the ends of the links are V4L2
+sub-devices. The driver is still responsible for validating the correctness
+of the format configuration between sub-devices and video nodes.
+
+If link_validate op is not set, the default function
+v4l2_subdev_link_validate_default() is used instead. This function ensures
+that width, height and the media bus pixel code are equal on both source and
+sink of the link. Subdev drivers are also free to use this function to
+perform the checks mentioned above in addition to their own checks.
+
 A device (bridge) driver needs to register the v4l2_subdev with the
 v4l2_device:
 
@@ -555,19 +580,25 @@
 You should also set these fields:
 
 - v4l2_dev: set to the v4l2_device parent device.
+
 - name: set to something descriptive and unique.
+
 - fops: set to the v4l2_file_operations struct.
+
 - ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
   (highly recommended to use this and it might become compulsory in the
   future!), then set this to your v4l2_ioctl_ops struct.
+
 - lock: leave to NULL if you want to do all the locking in the driver.
-  Otherwise you give it a pointer to a struct mutex_lock and before any
-  of the v4l2_file_operations is called this lock will be taken by the
-  core and released afterwards.
+  Otherwise you give it a pointer to a struct mutex_lock and before the
+  unlocked_ioctl file operation is called this lock will be taken by the
+  core and released afterwards. See the next section for more details.
+
 - prio: keeps track of the priorities. Used to implement VIDIOC_G/S_PRIORITY.
   If left to NULL, then it will use the struct v4l2_prio_state in v4l2_device.
   If you want to have a separate priority state per (group of) device node(s),
   then you can point it to your own struct v4l2_prio_state.
+
 - parent: you only set this if v4l2_device was registered with NULL as
   the parent device struct. This only happens in cases where one hardware
   device has multiple PCI devices that all share the same v4l2_device core.
@@ -577,6 +608,7 @@
   (cx8802). Since the v4l2_device cannot be associated with a particular
   PCI device it is setup without a parent device. But when the struct
   video_device is setup you do know which parent PCI device to use.
+
 - flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the framework
   handle the VIDIOC_G/S_PRIORITY ioctls. This requires that you use struct
   v4l2_fh. Eventually this flag will disappear once all drivers use the core
@@ -587,6 +619,16 @@
 
 Do not use .ioctl! This is deprecated and will go away in the future.
 
+In some cases you want to tell the core that a function you had specified in
+your v4l2_ioctl_ops should be ignored. You can mark such ioctls by calling this
+function before video_device_register is called:
+
+void v4l2_disable_ioctl(struct video_device *vdev, unsigned int cmd);
+
+This tends to be needed if based on external factors (e.g. which card is
+being used) you want to turns off certain features in v4l2_ioctl_ops without
+having to make a new struct.
+
 The v4l2_file_operations struct is a subset of file_operations. The main
 difference is that the inode argument is omitted since it is never used.
 
@@ -609,8 +651,22 @@
 --------------------------------
 
 You can set a pointer to a mutex_lock in struct video_device. Usually this
-will be either a top-level mutex or a mutex per device node. If you want
-finer-grained locking then you have to set it to NULL and do you own locking.
+will be either a top-level mutex or a mutex per device node. By default this
+lock will be used for unlocked_ioctl, but you can disable locking for
+selected ioctls by calling:
+
+	void v4l2_disable_ioctl_locking(struct video_device *vdev, unsigned int cmd);
+
+E.g.: v4l2_disable_ioctl_locking(vdev, VIDIOC_DQBUF);
+
+You have to call this before you register the video_device.
+
+Particularly with USB drivers where certain commands such as setting controls
+can take a long time you may want to do your own locking for the buffer queuing
+ioctls.
+
+If you want still finer-grained locking then you have to set mutex_lock to NULL
+and do you own locking completely.
 
 It is up to the driver developer to decide which method to use. However, if
 your driver has high-latency operations (for example, changing the exposure
@@ -618,7 +674,7 @@
 doing your own locking if you want to allow the user to do other things with
 the device while waiting for the high-latency command to finish.
 
-If a lock is specified then all file operations will be serialized on that
+If a lock is specified then all ioctl commands will be serialized on that
 lock. If you use videobuf then you must pass the same lock to the videobuf
 queue initialize function: if videobuf has to wait for a frame to arrive, then
 it will temporarily unlock the lock and relock it afterwards. If your driver
@@ -941,21 +997,35 @@
 
 Useful functions:
 
-- v4l2_event_queue()
+void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
 
   Queue events to video device. The driver's only responsibility is to fill
   in the type and the data fields. The other fields will be filled in by
   V4L2.
 
-- v4l2_event_subscribe()
+int v4l2_event_subscribe(struct v4l2_fh *fh,
+			 struct v4l2_event_subscription *sub, unsigned elems,
+			 const struct v4l2_subscribed_event_ops *ops)
 
   The video_device->ioctl_ops->vidioc_subscribe_event must check the driver
   is able to produce events with specified event id. Then it calls
-  v4l2_event_subscribe() to subscribe the event. The last argument is the
-  size of the event queue for this event. If it is 0, then the framework
-  will fill in a default value (this depends on the event type).
+  v4l2_event_subscribe() to subscribe the event.
 
-- v4l2_event_unsubscribe()
+  The elems argument is the size of the event queue for this event. If it is 0,
+  then the framework will fill in a default value (this depends on the event
+  type).
+
+  The ops argument allows the driver to specify a number of callbacks:
+  * add:     called when a new listener gets added (subscribing to the same
+             event twice will only cause this callback to get called once)
+  * del:     called when a listener stops listening
+  * replace: replace event 'old' with event 'new'.
+  * merge:   merge event 'old' into event 'new'.
+  All 4 callbacks are optional, if you don't want to specify any callbacks
+  the ops argument itself maybe NULL.
+
+int v4l2_event_unsubscribe(struct v4l2_fh *fh,
+			   struct v4l2_event_subscription *sub)
 
   vidioc_unsubscribe_event in struct v4l2_ioctl_ops. A driver may use
   v4l2_event_unsubscribe() directly unless it wants to be involved in
@@ -964,7 +1034,7 @@
   The special type V4L2_EVENT_ALL may be used to unsubscribe all events. The
   drivers may want to handle this in a special way.
 
-- v4l2_event_pending()
+int v4l2_event_pending(struct v4l2_fh *fh)
 
   Returns the number of pending events. Useful when implementing poll.
 
diff --git a/drivers/staging/vme/vme_api.txt b/Documentation/vme_api.txt
similarity index 100%
rename from drivers/staging/vme/vme_api.txt
rename to Documentation/vme_api.txt
diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c
index 63fdc34..73ff5cc 100644
--- a/Documentation/watchdog/src/watchdog-test.c
+++ b/Documentation/watchdog/src/watchdog-test.c
@@ -7,6 +7,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <sys/ioctl.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
@@ -29,6 +30,14 @@
  * The main program.  Run the program with "-d" to disable the card,
  * or "-e" to enable the card.
  */
+
+void term(int sig)
+{
+    close(fd);
+    fprintf(stderr, "Stopping watchdog ticks...\n");
+    exit(0);
+}
+
 int main(int argc, char *argv[])
 {
     int flags;
@@ -47,26 +56,31 @@
 	    ioctl(fd, WDIOC_SETOPTIONS, &flags);
 	    fprintf(stderr, "Watchdog card disabled.\n");
 	    fflush(stderr);
-	    exit(0);
+	    goto end;
 	} else if (!strncasecmp(argv[1], "-e", 2)) {
 	    flags = WDIOS_ENABLECARD;
 	    ioctl(fd, WDIOC_SETOPTIONS, &flags);
 	    fprintf(stderr, "Watchdog card enabled.\n");
 	    fflush(stderr);
-	    exit(0);
+	    goto end;
 	} else {
 	    fprintf(stderr, "-d to disable, -e to enable.\n");
 	    fprintf(stderr, "run by itself to tick the card.\n");
 	    fflush(stderr);
-	    exit(0);
+	    goto end;
 	}
     } else {
 	fprintf(stderr, "Watchdog Ticking Away!\n");
 	fflush(stderr);
     }
 
+    signal(SIGINT, term);
+
     while(1) {
 	keep_alive();
 	sleep(1);
     }
+end:
+    close(fd);
+    return 0;
 }
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
index 227f6cd..25fe430 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -59,7 +59,7 @@
 * bootstatus: status of the device after booting (reported with watchdog
   WDIOF_* status bits).
 * driver_data: a pointer to the drivers private data of a watchdog device.
-  This data should only be accessed via the watchdog_set_drvadata and
+  This data should only be accessed via the watchdog_set_drvdata and
   watchdog_get_drvdata routines.
 * status: this field contains a number of status bits that give extra
   information about the status of the device (Like: is the watchdog timer
diff --git a/Documentation/zh_CN/magic-number.txt b/Documentation/zh_CN/magic-number.txt
index f606ba8..4263022 100644
--- a/Documentation/zh_CN/magic-number.txt
+++ b/Documentation/zh_CN/magic-number.txt
@@ -160,7 +160,7 @@
 HTB_CMAGIC            0xFEFAFEF1  htb_class         net/sched/sch_htb.c
 NMI_MAGIC             0x48414d4d455201 nmi_s        arch/mips/include/asm/sn/nmi.h
 
-请注意,在声音记忆管理中仍然有每一些被定义的驱动魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。
+请注意,在声音记忆管理中仍然有一些特殊的为每个驱动定义的魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。
 
 IrDA子系统也使用了大量的自己的魔术值,查看include/net/irda/irda.h来获取他们完整的信息。
 
diff --git a/MAINTAINERS b/MAINTAINERS
index d4abe75..62b0cf4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -640,13 +640,6 @@
 F:	drivers/amba/
 F:	include/linux/amba/bus.h
 
-ARM/ADI ROADRUNNER MACHINE SUPPORT
-M:	Lennert Buytenhek <kernel@wantstofly.org>
-L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:	Maintained
-F:	arch/arm/mach-ixp23xx/
-F:	arch/arm/mach-ixp23xx/include/mach/
-
 ARM/ADS SPHERE MACHINE SUPPORT
 M:	Lennert Buytenhek <kernel@wantstofly.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -746,7 +739,10 @@
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	arch/arm/mach-prima2/
-F:	drivers/dma/sirf-dma*
+F:	drivers/dma/sirf-dma.c
+F:	drivers/i2c/busses/i2c-sirf.c
+F:	drivers/pinctrl/pinctrl-sirf.c
+F:	drivers/spi/spi-sirf.c
 
 ARM/EBSA110 MACHINE SUPPORT
 M:	Russell King <linux@arm.linux.org.uk>
@@ -859,21 +855,11 @@
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 
-ARM/INTEL IXP2000 ARM ARCHITECTURE
-M:	Lennert Buytenhek <kernel@wantstofly.org>
-L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:	Maintained
-
 ARM/INTEL IXDP2850 MACHINE SUPPORT
 M:	Lennert Buytenhek <kernel@wantstofly.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 
-ARM/INTEL IXP23XX ARM ARCHITECTURE
-M:	Lennert Buytenhek <kernel@wantstofly.org>
-L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:	Maintained
-
 ARM/INTEL IXP4XX ARM ARCHITECTURE
 M:	Imre Kaloz <kaloz@openwrt.org>
 M:	Krzysztof Halasa <khc@pm.waw.pl>
@@ -908,11 +894,12 @@
 M:	Philipp Zabel <philipp.zabel@gmail.com>
 S:	Maintained
 
-ARM/Marvell Loki/Kirkwood/MV78xx0/Orion SOC support
-M:	Lennert Buytenhek <kernel@wantstofly.org>
-M:	Nicolas Pitre <nico@fluxnic.net>
+ARM/Marvell Dove/Kirkwood/MV78xx0/Orion SOC support
+M:	Jason Cooper <jason@lakedaemon.net>
+M:	Andrew Lunn <andrew@lunn.ch>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:	Odd Fixes
+S:	Maintained
+F:	arch/arm/mach-dove/
 F:	arch/arm/mach-kirkwood/
 F:	arch/arm/mach-mv78xx0/
 F:	arch/arm/mach-orion5x/
@@ -1331,6 +1318,21 @@
 S:	Supported
 F:	drivers/tty/serial/atmel_serial.c
 
+ATMEL DMA DRIVER
+M:	Nicolas Ferre <nicolas.ferre@atmel.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Supported
+F:	drivers/dma/at_hdmac.c
+F:	drivers/dma/at_hdmac_regs.h
+F:	arch/arm/mach-at91/include/mach/at_hdmac.h
+
+ATMEL ISI DRIVER
+M:	Josh Wu <josh.wu@atmel.com>
+L:	linux-media@vger.kernel.org
+S:	Supported
+F:	drivers/media/video/atmel-isi.c
+F:	include/media/atmel-isi.h
+
 ATMEL LCDFB DRIVER
 M:	Nicolas Ferre <nicolas.ferre@atmel.com>
 L:	linux-fbdev@vger.kernel.org
@@ -1348,10 +1350,22 @@
 S:	Supported
 F:	drivers/spi/spi-atmel.*
 
+ATMEL Timer Counter (TC) AND CLOCKSOURCE DRIVERS
+M:	Nicolas Ferre <nicolas.ferre@atmel.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Supported
+F:	drivers/misc/atmel_tclib.c
+F:	drivers/clocksource/tcb_clksrc.c
+
+ATMEL TSADCC DRIVER
+M:	Josh Wu <josh.wu@atmel.com>
+L:	linux-input@vger.kernel.org
+S:	Supported
+F:	drivers/input/touchscreen/atmel_tsadcc.c
+
 ATMEL USBA UDC DRIVER
 M:	Nicolas Ferre <nicolas.ferre@atmel.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:	http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
 S:	Supported
 F:	drivers/usb/gadget/atmel_usba_udc.*
 
@@ -1812,6 +1826,12 @@
 S:	Maintained
 F:	Documentation/zh_CN/
 
+CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
+M:	Alexander Shishkin <alexander.shishkin@linux.intel.com>
+L:	linux-usb@vger.kernel.org
+S:	Maintained
+F:	drivers/usb/chipidea/
+
 CISCO VIC ETHERNET NIC DRIVER
 M:	Christian Benvenuti <benve@cisco.com>
 M:	Roopa Prabhu <roprabhu@cisco.com>
@@ -2698,6 +2718,13 @@
 F:	Documentation/hwmon/f71805f
 F:	drivers/hwmon/f71805f.c
 
+FC0011 TUNER DRIVER
+M:	Michael Buesch <m@bues.ch>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	drivers/media/common/tuners/fc0011.h
+F:	drivers/media/common/tuners/fc0011.c
+
 FANOTIFY
 M:	Eric Paris <eparis@redhat.com>
 S:	Maintained
@@ -2756,6 +2783,15 @@
 S:	Maintained
 F:	sound/firewire/
 
+FIREWIRE SBP-2 TARGET
+M:	Chris Boot <bootc@bootc.net>
+L:	linux-scsi@vger.kernel.org
+L:	target-devel@vger.kernel.org
+L:	linux1394-devel@lists.sourceforge.net
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
+S:	Maintained
+F:	drivers/target/sbp/
+
 FIREWIRE SUBSYSTEM
 M:	Stefan Richter <stefanr@s5r6.in-berlin.de>
 L:	linux1394-devel@lists.sourceforge.net
@@ -2892,7 +2928,7 @@
 F:	arch/frv/
 
 FUJITSU LAPTOP EXTRAS
-M:	Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+M:	Jonathan Woithe <jwoithe@just42.net>
 L:	platform-driver-x86@vger.kernel.org
 S:	Maintained
 F:	drivers/platform/x86/fujitsu-laptop.c
@@ -3318,12 +3354,6 @@
 S:	Maintained
 F:	arch/ia64/
 
-IBM MCA SCSI SUBSYSTEM DRIVER
-M:	Michael Lang <langa2@kph.uni-mainz.de>
-W:	http://www.uni-mainz.de/~langm000/linux.html
-S:	Maintained
-F:	drivers/scsi/ibmmca.c
-
 IBM Power Linux RAID adapter
 M:	Brian King <brking@us.ibm.com>
 S:	Supported
@@ -3386,6 +3416,7 @@
 M:	Jonathan Cameron <jic23@cam.ac.uk>
 L:	linux-iio@vger.kernel.org
 S:	Maintained
+F:	drivers/iio/
 F:	drivers/staging/iio/
 
 IKANOS/ADI EAGLE ADSL USB DRIVER
@@ -3434,6 +3465,8 @@
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
 S:	Maintained
 F:	drivers/input/
+F:	include/linux/input.h
+F:	include/linux/input/
 
 INPUT MULTITOUCH (MT) PROTOCOL
 M:	Henrik Rydberg <rydberg@euromail.se>
@@ -3605,6 +3638,14 @@
 W:	http://wireless.kernel.org/en/users/Drivers/iwmc3200wifi
 F:	drivers/net/wireless/iwmc3200wifi/
 
+INTEL MANAGEMENT ENGINE (mei)
+M:	Tomas Winkler <tomas.winkler@intel.com>
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+F:	include/linux/mei.h
+F:	drivers/misc/mei/*
+F:	Documentation/mei/*
+
 IOC3 ETHERNET DRIVER
 M:	Ralf Baechle <ralf@linux-mips.org>
 L:	linux-mips@linux-mips.org
@@ -4420,13 +4461,6 @@
 S:	Supported
 F:	arch/microblaze/
 
-MICROCHANNEL ARCHITECTURE (MCA)
-M:	James Bottomley <James.Bottomley@HansenPartnership.com>
-S:	Maintained
-F:	Documentation/mca.txt
-F:	drivers/mca/
-F:	include/linux/mca*
-
 MICROTEK X6 SCANNER
 M:	Oliver Neukum <oliver@neukum.name>
 S:	Maintained
@@ -5226,6 +5260,14 @@
 S:	Maintained
 F:	drivers/pinctrl/
 
+PIN CONTROLLER - ST SPEAR
+M:	Viresh Kumar <viresh.kumar@st.com>
+L:	spear-devel@list.st.com
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+W:	http://www.st.com/spear
+S:	Maintained
+F:	driver/pinctrl/spear/
+
 PKTCDVD DRIVER
 M:	Peter Osterlund <petero2@telia.com>
 S:	Maintained
@@ -6330,21 +6372,6 @@
 F:	arch/arm/plat-spear/clock.c
 F:	arch/arm/plat-spear/include/plat/clock.h
 
-SPEAR PAD MULTIPLEXING SUPPORT
-M:	Viresh Kumar <viresh.kumar@st.com>
-L:	spear-devel@list.st.com
-L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:	http://www.st.com/spear
-S:	Maintained
-F:	arch/arm/plat-spear/include/plat/padmux.h
-F:	arch/arm/plat-spear/padmux.c
-F:	arch/arm/mach-spear*/spear*xx.c
-F:	arch/arm/mach-spear*/include/mach/generic.h
-F:	arch/arm/mach-spear3xx/spear3*0.c
-F:	arch/arm/mach-spear3xx/spear3*0_evb.c
-F:	arch/arm/mach-spear6xx/spear600.c
-F:	arch/arm/mach-spear6xx/spear600_evb.c
-
 SPI SUBSYSTEM
 M:	Grant Likely <grant.likely@secretlab.ca>
 L:	spi-devel-general@lists.sourceforge.net
@@ -6551,7 +6578,7 @@
 L:	linux-sh@vger.kernel.org
 W:	http://www.linux-sh.org
 Q:	http://patchwork.kernel.org/project/linux-sh/list/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git sh-latest
+T:	git git://github.com/pmundt/linux-sh.git sh-latest
 S:	Supported
 F:	Documentation/sh/
 F:	arch/sh/
@@ -6669,6 +6696,12 @@
 F:	drivers/mmc/host/tifm_sd.c
 F:	include/linux/tifm.h
 
+TI LM49xxx FAMILY ASoC CODEC DRIVERS
+M:	M R Swami Reddy <mr.swami.reddy@ti.com>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:	Maintained
+F:	sound/soc/codecs/lm49453*
+
 TI TWL4030 SERIES SOC CODEC DRIVER
 M:	Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -7046,6 +7079,14 @@
 S:	Maintained
 F:	drivers/net/usb/pegasus.*
 
+USB PHY LAYER
+M:	Felipe Balbi <balbi@ti.com>
+L:	linux-usb@vger.kernel.org
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
+S:	Maintained
+F:	drivers/usb/phy/
+F:	drivers/usb/otg/
+
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <zaitcev@redhat.com>
 L:	linux-usb@vger.kernel.org
@@ -7159,7 +7200,7 @@
 
 USB VIDEO CLASS
 M:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-L:	linux-uvc-devel@lists.berlios.de (subscribers-only)
+L:	linux-uvc-devel@lists.sourceforge.net (subscribers-only)
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://www.ideasonboard.org/uvc/
@@ -7329,6 +7370,18 @@
 F:	drivers/vlynq/vlynq.c
 F:	include/linux/vlynq.h
 
+VME SUBSYSTEM
+M:	Martyn Welch <martyn.welch@ge.com>
+M:	Manohar Vanga <manohar.vanga@cern.ch>
+M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+L:	devel@driverdev.osuosl.org
+S:	Maintained
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
+F:	Documentation/vme_api.txt
+F:	drivers/staging/vme/
+F:	drivers/vme/
+F:	include/linux/vme*
+
 VMWARE VMXNET3 ETHERNET DRIVER
 M:	Shreyas Bhatewara <sbhatewara@vmware.com>
 M:	"VMware, Inc." <pv-drivers@vmware.com>
diff --git a/Makefile b/Makefile
index a687963..b62c1e0 100644
--- a/Makefile
+++ b/Makefile
@@ -400,8 +400,10 @@
 
 # Files to ignore in find ... statements
 
-RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o
-export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git
+RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \
+		   -o -name .pc -o -name .hg -o -name .git \) -prune -o
+export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \
+			 --exclude CVS --exclude .pc --exclude .hg --exclude .git
 
 # ===========================================================================
 # Rules shared between *config targets and build targets
@@ -564,6 +566,16 @@
 KBUILD_CFLAGS	+= -O2
 endif
 
+ifdef CONFIG_READABLE_ASM
+# Disable optimizations that make assembler listings hard to read.
+# reorder blocks reorders the control in the function
+# ipa clone creates specialized cloned functions
+# partial inlining inlines only parts of functions
+KBUILD_CFLAGS += $(call cc-option,-fno-reorder-blocks,) \
+                 $(call cc-option,-fno-ipa-cp-clone,) \
+                 $(call cc-option,-fno-partial-inlining)
+endif
+
 include $(srctree)/arch/$(SRCARCH)/Makefile
 
 ifneq ($(CONFIG_FRAME_WARN),0)
@@ -784,6 +796,10 @@
 quiet_cmd_sysmap = SYSMAP
       cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap
 
+# Sort exception table at build time
+quiet_cmd_sortextable = SORTEX
+      cmd_sortextable = $(objtree)/scripts/sortextable
+
 # Link of vmlinux
 # If CONFIG_KALLSYMS is set .version is already updated
 # Generate System.map and verify that the content is consistent
@@ -796,6 +812,12 @@
 	$(call cmd,vmlinux__)
 	$(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
 
+	$(if $(CONFIG_BUILDTIME_EXTABLE_SORT),				\
+	  $(Q)$(if $($(quiet)cmd_sortextable),				\
+	    echo '  $($(quiet)cmd_sortextable)  vmlinux' &&)		\
+	  $(cmd_sortextable)  vmlinux)
+
+
 	$(Q)$(if $($(quiet)cmd_sysmap),                                      \
 	  echo '  $($(quiet)cmd_sysmap)  System.map' &&)                     \
 	$(cmd_sysmap) $@ System.map;                                         \
@@ -966,7 +988,7 @@
 ifneq ($(KBUILD_SRC),)
 	@$(kecho) '  Using $(srctree) as source for kernel'
 	$(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \
-		echo "  $(srctree) is not clean, please run 'make mrproper'";\
+		echo "  $(srctree) is not clean, please run 'make mrproper'"; \
 		echo "  in the '$(srctree)' directory.";\
 		/bin/false; \
 	fi;
@@ -1003,8 +1025,8 @@
 endef
 
 define filechk_version.h
-	(echo \#define LINUX_VERSION_CODE $(shell                             \
-	expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL));    \
+	(echo \#define LINUX_VERSION_CODE $(shell                         \
+	expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
 	echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
 endef
 
@@ -1471,6 +1493,13 @@
 kernelversion:
 	@echo $(KERNELVERSION)
 
+# Clear a bunch of variables before executing the submake
+tools/: FORCE
+	$(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/
+
+tools/%: FORCE
+	$(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/ $*
+
 # Single targets
 # ---------------------------------------------------------------------------
 # Single targets are compatible with:
diff --git a/README b/README
index 0d5a7dd..9beaed0 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-	Linux kernel release 3.x <http://kernel.org/>
+        Linux kernel release 3.x <http://kernel.org/>
 
 These are the release notes for Linux version 3.  Read them carefully,
 as they tell you what this is all about, explain how to install the
@@ -62,13 +62,13 @@
    directory where you have permissions (eg. your home directory) and
    unpack it:
 
-		gzip -cd linux-3.X.tar.gz | tar xvf -
+     gzip -cd linux-3.X.tar.gz | tar xvf -
 
    or
-		bzip2 -dc linux-3.X.tar.bz2 | tar xvf -
 
+     bzip2 -dc linux-3.X.tar.bz2 | tar xvf -
 
-   Replace "XX" with the version number of the latest kernel.
+   Replace "X" with the version number of the latest kernel.
 
    Do NOT use the /usr/src/linux area! This area has a (usually
    incomplete) set of kernel headers that are used by the library header
@@ -78,49 +78,43 @@
  - You can also upgrade between 3.x releases by patching.  Patches are
    distributed in the traditional gzip and the newer bzip2 format.  To
    install by patching, get all the newer patch files, enter the
-   top level directory of the kernel source (linux-3.x) and execute:
+   top level directory of the kernel source (linux-3.X) and execute:
 
-		gzip -cd ../patch-3.x.gz | patch -p1
+     gzip -cd ../patch-3.x.gz | patch -p1
 
    or
-		bzip2 -dc ../patch-3.x.bz2 | patch -p1
 
-   (repeat xx for all versions bigger than the version of your current
-   source tree, _in_order_) and you should be ok.  You may want to remove
-   the backup files (xxx~ or xxx.orig), and make sure that there are no
-   failed patches (xxx# or xxx.rej). If there are, either you or me has
-   made a mistake.
+     bzip2 -dc ../patch-3.x.bz2 | patch -p1
+
+   Replace "x" for all versions bigger than the version "X" of your current
+   source tree, _in_order_, and you should be ok.  You may want to remove
+   the backup files (some-file-name~ or some-file-name.orig), and make sure
+   that there are no failed patches (some-file-name# or some-file-name.rej).
+   If there are, either you or I have made a mistake.
 
    Unlike patches for the 3.x kernels, patches for the 3.x.y kernels
    (also known as the -stable kernels) are not incremental but instead apply
-   directly to the base 3.x kernel.  Please read
-   Documentation/applying-patches.txt for more information.
+   directly to the base 3.x kernel.  For example, if your base kernel is 3.0
+   and you want to apply the 3.0.3 patch, you must not first apply the 3.0.1
+   and 3.0.2 patches. Similarly, if you are running kernel version 3.0.2 and
+   want to jump to 3.0.3, you must first reverse the 3.0.2 patch (that is,
+   patch -R) _before_ applying the 3.0.3 patch. You can read more on this in
+   Documentation/applying-patches.txt
 
    Alternatively, the script patch-kernel can be used to automate this
    process.  It determines the current kernel version and applies any
    patches found.
 
-		linux/scripts/patch-kernel linux
+     linux/scripts/patch-kernel linux
 
    The first argument in the command above is the location of the
    kernel source.  Patches are applied from the current directory, but
    an alternative directory can be specified as the second argument.
 
- - If you are upgrading between releases using the stable series patches
-   (for example, patch-3.x.y), note that these "dot-releases" are
-   not incremental and must be applied to the 3.x base tree. For
-   example, if your base kernel is 3.0 and you want to apply the
-   3.0.3 patch, you do not and indeed must not first apply the
-   3.0.1 and 3.0.2 patches. Similarly, if you are running kernel
-   version 3.0.2 and want to jump to 3.0.3, you must first
-   reverse the 3.0.2 patch (that is, patch -R) _before_ applying
-   the 3.0.3 patch.
-   You can read more on this in Documentation/applying-patches.txt
-
  - Make sure you have no stale .o files and dependencies lying around:
 
-		cd linux
-		make mrproper
+     cd linux
+     make mrproper
 
    You should now have the sources correctly installed.
 
@@ -137,21 +131,23 @@
 
 BUILD directory for the kernel:
 
-   When compiling the kernel all output files will per default be
+   When compiling the kernel, all output files will per default be
    stored together with the kernel source code.
    Using the option "make O=output/dir" allow you to specify an alternate
    place for the output files (including .config).
    Example:
-     kernel source code:	/usr/src/linux-3.N
-     build directory:		/home/name/build/kernel
 
-   To configure and build the kernel use:
-   cd /usr/src/linux-3.N
-   make O=/home/name/build/kernel menuconfig
-   make O=/home/name/build/kernel
-   sudo make O=/home/name/build/kernel modules_install install
+     kernel source code: /usr/src/linux-3.X
+     build directory:    /home/name/build/kernel
 
-   Please note: If the 'O=output/dir' option is used then it must be
+   To configure and build the kernel, use:
+
+     cd /usr/src/linux-3.X
+     make O=/home/name/build/kernel menuconfig
+     make O=/home/name/build/kernel
+     sudo make O=/home/name/build/kernel modules_install install
+
+   Please note: If the 'O=output/dir' option is used, then it must be
    used for all invocations of make.
 
 CONFIGURING the kernel:
@@ -163,61 +159,78 @@
    new version with minimal work, use "make oldconfig", which will
    only ask you for the answers to new questions.
 
- - Alternate configuration commands are:
-	"make config"      Plain text interface.
-	"make menuconfig"  Text based color menus, radiolists & dialogs.
-	"make nconfig"     Enhanced text based color menus.
-	"make xconfig"     X windows (Qt) based configuration tool.
-	"make gconfig"     X windows (Gtk) based configuration tool.
-	"make oldconfig"   Default all questions based on the contents of
-			   your existing ./.config file and asking about
-			   new config symbols.
-	"make silentoldconfig"
-			   Like above, but avoids cluttering the screen
-			   with questions already answered.
-			   Additionally updates the dependencies.
-	"make defconfig"   Create a ./.config file by using the default
-			   symbol values from either arch/$ARCH/defconfig
-			   or arch/$ARCH/configs/${PLATFORM}_defconfig,
-			   depending on the architecture.
-	"make ${PLATFORM}_defconfig"
-			  Create a ./.config file by using the default
-			  symbol values from
-			  arch/$ARCH/configs/${PLATFORM}_defconfig.
-			  Use "make help" to get a list of all available
-			  platforms of your architecture.
-	"make allyesconfig"
-			   Create a ./.config file by setting symbol
-			   values to 'y' as much as possible.
-	"make allmodconfig"
-			   Create a ./.config file by setting symbol
-			   values to 'm' as much as possible.
-	"make allnoconfig" Create a ./.config file by setting symbol
-			   values to 'n' as much as possible.
-	"make randconfig"  Create a ./.config file by setting symbol
-			   values to random values.
+ - Alternative configuration commands are:
+
+     "make config"      Plain text interface.
+
+     "make menuconfig"  Text based color menus, radiolists & dialogs.
+
+     "make nconfig"     Enhanced text based color menus.
+
+     "make xconfig"     X windows (Qt) based configuration tool.
+
+     "make gconfig"     X windows (Gtk) based configuration tool.
+
+     "make oldconfig"   Default all questions based on the contents of
+                        your existing ./.config file and asking about
+                        new config symbols.
+
+     "make silentoldconfig"
+                        Like above, but avoids cluttering the screen
+                        with questions already answered.
+                        Additionally updates the dependencies.
+
+     "make defconfig"   Create a ./.config file by using the default
+                        symbol values from either arch/$ARCH/defconfig
+                        or arch/$ARCH/configs/${PLATFORM}_defconfig,
+                        depending on the architecture.
+
+     "make ${PLATFORM}_defconfig"
+                        Create a ./.config file by using the default
+                        symbol values from
+                        arch/$ARCH/configs/${PLATFORM}_defconfig.
+                        Use "make help" to get a list of all available
+                        platforms of your architecture.
+
+     "make allyesconfig"
+                        Create a ./.config file by setting symbol
+                        values to 'y' as much as possible.
+
+     "make allmodconfig"
+                        Create a ./.config file by setting symbol
+                        values to 'm' as much as possible.
+
+     "make allnoconfig" Create a ./.config file by setting symbol
+                        values to 'n' as much as possible.
+
+     "make randconfig"  Create a ./.config file by setting symbol
+                        values to random values.
 
    You can find more information on using the Linux kernel config tools
    in Documentation/kbuild/kconfig.txt.
 
-	NOTES on "make config":
-	- having unnecessary drivers will make the kernel bigger, and can
-	  under some circumstances lead to problems: probing for a
-	  nonexistent controller card may confuse your other controllers
-	- compiling the kernel with "Processor type" set higher than 386
-	  will result in a kernel that does NOT work on a 386.  The
-	  kernel will detect this on bootup, and give up.
-	- A kernel with math-emulation compiled in will still use the
-	  coprocessor if one is present: the math emulation will just
-	  never get used in that case.  The kernel will be slightly larger,
-	  but will work on different machines regardless of whether they
-	  have a math coprocessor or not. 
-	- the "kernel hacking" configuration details usually result in a
-	  bigger or slower kernel (or both), and can even make the kernel
-	  less stable by configuring some routines to actively try to
-	  break bad code to find kernel problems (kmalloc()).  Thus you
-	  should probably answer 'n' to the questions for
-          "development", "experimental", or "debugging" features.
+ - NOTES on "make config":
+
+    - Having unnecessary drivers will make the kernel bigger, and can
+      under some circumstances lead to problems: probing for a
+      nonexistent controller card may confuse your other controllers
+
+    - Compiling the kernel with "Processor type" set higher than 386
+      will result in a kernel that does NOT work on a 386.  The
+      kernel will detect this on bootup, and give up.
+
+    - A kernel with math-emulation compiled in will still use the
+      coprocessor if one is present: the math emulation will just
+      never get used in that case.  The kernel will be slightly larger,
+      but will work on different machines regardless of whether they
+      have a math coprocessor or not.
+
+    - The "kernel hacking" configuration details usually result in a
+      bigger or slower kernel (or both), and can even make the kernel
+      less stable by configuring some routines to actively try to
+      break bad code to find kernel problems (kmalloc()).  Thus you
+      should probably answer 'n' to the questions for "development",
+      "experimental", or "debugging" features.
 
 COMPILING the kernel:
 
@@ -230,7 +243,7 @@
    possible to do "make install" if you have lilo installed to suit the
    kernel makefiles, but you may want to check your particular lilo setup first.
 
-   To do the actual install you have to be root, but none of the normal
+   To do the actual install, you have to be root, but none of the normal
    build should require that. Don't take the name of root in vain.
 
  - If you configured any of the parts of the kernel as `modules', you
@@ -238,13 +251,13 @@
 
  - Verbose kernel compile/build output:
 
-   Normally the kernel build system runs in a fairly quiet mode (but not
+   Normally, the kernel build system runs in a fairly quiet mode (but not
    totally silent).  However, sometimes you or other kernel developers need
    to see compile, link, or other commands exactly as they are executed.
    For this, use "verbose" build mode.  This is done by inserting
    "V=1" in the "make" command.  E.g.:
 
-	make V=1 all
+     make V=1 all
 
    To have the build system also tell the reason for the rebuild of each
    target, use "V=2".  The default is "V=0".
@@ -256,6 +269,7 @@
    are installing a new kernel with the same version number as your
    working kernel, make a backup of your modules directory before you
    do a "make modules_install".
+
    Alternatively, before compiling, use the kernel config option
    "LOCALVERSION" to append a unique suffix to the regular kernel version.
    LOCALVERSION can be set in the "General Setup" menu.
@@ -267,7 +281,7 @@
  - Booting a kernel directly from a floppy without the assistance of a
    bootloader such as LILO, is no longer supported.
 
-   If you boot Linux from the hard drive, chances are you use LILO which
+   If you boot Linux from the hard drive, chances are you use LILO, which
    uses the kernel image as specified in the file /etc/lilo.conf.  The
    kernel image file is usually /vmlinuz, /boot/vmlinuz, /bzImage or
    /boot/bzImage.  To use the new kernel, save a copy of the old image
@@ -306,21 +320,21 @@
 
  - If the bug results in a message like
 
-	unable to handle kernel paging request at address C0000010
-	Oops: 0002
-	EIP:   0010:XXXXXXXX
-	eax: xxxxxxxx   ebx: xxxxxxxx   ecx: xxxxxxxx   edx: xxxxxxxx
-	esi: xxxxxxxx   edi: xxxxxxxx   ebp: xxxxxxxx
-	ds: xxxx  es: xxxx  fs: xxxx  gs: xxxx
-	Pid: xx, process nr: xx
-	xx xx xx xx xx xx xx xx xx xx
+     unable to handle kernel paging request at address C0000010
+     Oops: 0002
+     EIP:   0010:XXXXXXXX
+     eax: xxxxxxxx   ebx: xxxxxxxx   ecx: xxxxxxxx   edx: xxxxxxxx
+     esi: xxxxxxxx   edi: xxxxxxxx   ebp: xxxxxxxx
+     ds: xxxx  es: xxxx  fs: xxxx  gs: xxxx
+     Pid: xx, process nr: xx
+     xx xx xx xx xx xx xx xx xx xx
 
    or similar kernel debugging information on your screen or in your
    system log, please duplicate it *exactly*.  The dump may look
    incomprehensible to you, but it does contain information that may
    help debugging the problem.  The text above the dump is also
    important: it tells something about why the kernel dumped code (in
-   the above example it's due to a bad kernel pointer). More information
+   the above example, it's due to a bad kernel pointer). More information
    on making sense of the dump is in Documentation/oops-tracing.txt
 
  - If you compiled the kernel with CONFIG_KALLSYMS you can send the dump
@@ -328,7 +342,7 @@
    sense of the dump (but compiling with CONFIG_KALLSYMS is usually preferred).
    This utility can be downloaded from
    ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops/ .
-   Alternately you can do the dump lookup by hand:
+   Alternatively, you can do the dump lookup by hand:
 
  - In debugging dumps like the above, it helps enormously if you can
    look up what the EIP value means.  The hex value as such doesn't help
@@ -342,7 +356,7 @@
    the file 'linux/vmlinux'.  To extract the namelist and match it against
    the EIP from the kernel crash, do:
 
-		nm vmlinux | sort | less
+     nm vmlinux | sort | less
 
    This will give you a list of kernel addresses sorted in ascending
    order, from which it is simple to find the function that contains the
@@ -361,7 +375,7 @@
    kernel image or similar), telling me as much about your setup as
    possible will help.  Please read the REPORTING-BUGS document for details.
 
- - Alternately, you can use gdb on a running kernel. (read-only; i.e. you
+ - Alternatively, you can use gdb on a running kernel. (read-only; i.e. you
    cannot change values or set break points.) To do this, first compile the
    kernel with -g; edit arch/i386/Makefile appropriately, then do a "make
    clean". You'll also need to enable CONFIG_PROC_FS (via "make config").
diff --git a/arch/Kconfig b/arch/Kconfig
index 1f9461b..e9a9108 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -76,6 +76,23 @@
 	depends on KPROBES && HAVE_OPTPROBES
 	depends on !PREEMPT
 
+config UPROBES
+	bool "Transparent user-space probes (EXPERIMENTAL)"
+	depends on UPROBE_EVENT && PERF_EVENTS
+	default n
+	help
+	  Uprobes is the user-space counterpart to kprobes: they
+	  enable instrumentation applications (such as 'perf probe')
+	  to establish unintrusive probes in user-space binaries and
+	  libraries, by executing handler functions when the probes
+	  are hit by user-space applications.
+
+	  ( These probes come in the form of single-byte breakpoints,
+	    managed by the kernel and kept transparent to the probed
+	    application. )
+
+	  If in doubt, say "N".
+
 config HAVE_EFFICIENT_UNALIGNED_ACCESS
 	bool
 	help
diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h
index 94afe58..e37b887b 100644
--- a/arch/alpha/include/asm/processor.h
+++ b/arch/alpha/include/asm/processor.h
@@ -49,9 +49,6 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 /* Create a kernel thread without removing it from tasklists.  */
 extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index cd63479..3f844d2 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -236,7 +236,7 @@
 		ok = 0;
 
 	/* If both conditions above are met, we are fine. */
-	DBGA("pci_dac_dma_supported %s from %p\n",
+	DBGA("pci_dac_dma_supported %s from %pf\n",
 	     ok ? "yes" : "no", __builtin_return_address(0));
 
 	return ok;
@@ -268,7 +268,7 @@
 	    && paddr + size <= __direct_map_size) {
 		ret = paddr + __direct_map_base;
 
-		DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %p\n",
+		DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %pf\n",
 		      cpu_addr, size, ret, __builtin_return_address(0));
 
 		return ret;
@@ -279,7 +279,7 @@
 	if (dac_allowed) {
 		ret = paddr + alpha_mv.pci_dac_offset;
 
-		DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %p\n",
+		DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %pf\n",
 		      cpu_addr, size, ret, __builtin_return_address(0));
 
 		return ret;
@@ -316,7 +316,7 @@
 	ret = arena->dma_base + dma_ofs * PAGE_SIZE;
 	ret += (unsigned long)cpu_addr & ~PAGE_MASK;
 
-	DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %p\n",
+	DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %pf\n",
 	      cpu_addr, size, npages, ret, __builtin_return_address(0));
 
 	return ret;
@@ -385,14 +385,14 @@
 	    && dma_addr < __direct_map_base + __direct_map_size) {
 		/* Nothing to do.  */
 
-		DBGA2("pci_unmap_single: direct [%llx,%zx] from %p\n",
+		DBGA2("pci_unmap_single: direct [%llx,%zx] from %pf\n",
 		      dma_addr, size, __builtin_return_address(0));
 
 		return;
 	}
 
 	if (dma_addr > 0xffffffff) {
-		DBGA2("pci64_unmap_single: DAC [%llx,%zx] from %p\n",
+		DBGA2("pci64_unmap_single: DAC [%llx,%zx] from %pf\n",
 		      dma_addr, size, __builtin_return_address(0));
 		return;
 	}
@@ -424,7 +424,7 @@
 
 	spin_unlock_irqrestore(&arena->lock, flags);
 
-	DBGA2("pci_unmap_single: sg [%llx,%zx] np %ld from %p\n",
+	DBGA2("pci_unmap_single: sg [%llx,%zx] np %ld from %pf\n",
 	      dma_addr, size, npages, __builtin_return_address(0));
 }
 
@@ -447,7 +447,7 @@
 	cpu_addr = (void *)__get_free_pages(gfp, order);
 	if (! cpu_addr) {
 		printk(KERN_INFO "pci_alloc_consistent: "
-		       "get_free_pages failed from %p\n",
+		       "get_free_pages failed from %pf\n",
 			__builtin_return_address(0));
 		/* ??? Really atomic allocation?  Otherwise we could play
 		   with vmalloc and sg if we can't find contiguous memory.  */
@@ -466,7 +466,7 @@
 		goto try_again;
 	}
 
-	DBGA2("pci_alloc_consistent: %zx -> [%p,%llx] from %p\n",
+	DBGA2("pci_alloc_consistent: %zx -> [%p,%llx] from %pf\n",
 	      size, cpu_addr, *dma_addrp, __builtin_return_address(0));
 
 	return cpu_addr;
@@ -486,7 +486,7 @@
 	pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
 	free_pages((unsigned long)cpu_addr, get_order(size));
 
-	DBGA2("pci_free_consistent: [%llx,%zx] from %p\n",
+	DBGA2("pci_free_consistent: [%llx,%zx] from %pf\n",
 	      dma_addr, size, __builtin_return_address(0));
 }
 
diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
index 0dae252..d821b17 100644
--- a/arch/alpha/kernel/perf_event.c
+++ b/arch/alpha/kernel/perf_event.c
@@ -824,7 +824,6 @@
 
 	idx = la_ptr;
 
-	perf_sample_data_init(&data, 0);
 	for (j = 0; j < cpuc->n_events; j++) {
 		if (cpuc->current_idx[j] == idx)
 			break;
@@ -848,7 +847,7 @@
 
 	hwc = &event->hw;
 	alpha_perf_event_update(event, hwc, idx, alpha_pmu->pmc_max_period[idx]+1);
-	data.period = event->hw.last_period;
+	perf_sample_data_init(&data, 0, hwc->last_period);
 
 	if (alpha_perf_event_set_period(event, hwc, idx)) {
 		if (perf_event_overflow(event, &data, regs)) {
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 35f2ef4..10ab2d7 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -34,9 +34,6 @@
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 asmlinkage void ret_from_sys_call(void);
-static void do_signal(struct pt_regs *, struct switch_stack *,
-		      unsigned long, unsigned long);
-
 
 /*
  * The OSF/1 sigprocmask calling sequence is different from the
@@ -121,17 +118,8 @@
 SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
 {
 	sigset_t blocked;
-
-	current->saved_sigmask = current->blocked;
-
-	mask &= _BLOCKABLE;
 	siginitset(&blocked, mask);
-	set_current_blocked(&blocked);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 asmlinkage int
@@ -376,11 +364,11 @@
 	oldsp = rdusp();
 	frame = get_sigframe(ka, oldsp, sizeof(*frame));
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
+		return -EFAULT;
 
 	err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
@@ -396,7 +384,7 @@
 
 	/* Check that everything was written properly.  */
 	if (err)
-		goto give_sigsegv;
+		return err;
 
 	/* "Return" to the handler */
 	regs->r26 = r26;
@@ -410,12 +398,7 @@
 	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
 		current->comm, current->pid, frame, regs->pc, regs->r26);
 #endif
-
 	return 0;
-
-give_sigsegv:
-	force_sigsegv(sig, current);
-	return -EFAULT;
 }
 
 static int
@@ -428,7 +411,7 @@
 	oldsp = rdusp();
 	frame = get_sigframe(ka, oldsp, sizeof(*frame));
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
+		return -EFAULT;
 
 	err |= copy_siginfo_to_user(&frame->info, info);
 
@@ -443,7 +426,7 @@
 				set->sig[0], oldsp);
 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
@@ -459,7 +442,7 @@
 	}
 
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* "Return" to the handler */
 	regs->r26 = r26;
@@ -475,31 +458,37 @@
 #endif
 
 	return 0;
-
-give_sigsegv:
-	force_sigsegv(sig, current);
-	return -EFAULT;
 }
 
 
 /*
  * OK, we're invoking a handler.
  */
-static inline int
+static inline void
 handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
-	      sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw)
+	      struct pt_regs * regs, struct switch_stack *sw)
 {
+	sigset_t *oldset = &current->blocked;
 	int ret;
 
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		ret = setup_rt_frame(sig, ka, info, oldset, regs, sw);
 	else
 		ret = setup_frame(sig, ka, oldset, regs, sw);
 
-	if (ret == 0)
-		block_sigmask(ka, sig);
-
-	return ret;
+	if (ret) {
+		force_sigsegv(sig, current);
+		return;
+	}
+	block_sigmask(ka, sig);
+	/* A signal was successfully delivered, and the
+	   saved sigmask was stored on the signal frame,
+	   and will be restored by sigreturn.  So we can
+	   simply clear the restore sigmask flag.  */
+	clear_thread_flag(TIF_RESTORE_SIGMASK);
 }
 
 static inline void
@@ -547,12 +536,6 @@
 	int signr;
 	unsigned long single_stepping = ptrace_cancel_bpt(current);
 	struct k_sigaction ka;
-	sigset_t *oldset;
-
-	if (test_thread_flag(TIF_RESTORE_SIGMASK))
-		oldset = &current->saved_sigmask;
-	else
-		oldset = &current->blocked;
 
 	/* This lets the debugger run, ... */
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -564,14 +547,7 @@
 		/* Whee!  Actually deliver the signal.  */
 		if (r0)
 			syscall_restart(r0, r19, regs, &ka);
-		if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) {
-			/* A signal was successfully delivered, and the
-			   saved sigmask was stored on the signal frame,
-			   and will be restored by sigreturn.  So we can
-			   simply clear the restore sigmask flag.  */
-			if (test_thread_flag(TIF_RESTORE_SIGMASK))
-				clear_thread_flag(TIF_RESTORE_SIGMASK);
-		}
+		handle_signal(signr, &ka, &info, regs, sw);
 		if (single_stepping) 
 			ptrace_set_bpt(current); /* re-set bpt */
 		return;
@@ -596,10 +572,8 @@
 	}
 
 	/* If there's no signal to deliver, we just restore the saved mask.  */
-	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-		clear_thread_flag(TIF_RESTORE_SIGMASK);
-		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
-	}
+	if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+		set_current_blocked(&current->saved_sigmask);
 
 	if (single_stepping)
 		ptrace_set_bpt(current);	/* re-set breakpoint */
@@ -610,7 +584,7 @@
 		 unsigned long thread_info_flags,
 		 unsigned long r0, unsigned long r19)
 {
-	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+	if (thread_info_flags & _TIF_SIGPENDING)
 		do_signal(regs, sw, r0, r19);
 
 	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 002b1c8..4f4c811 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -107,14 +107,6 @@
 config SBUS
 	bool
 
-config MCA
-	bool
-	help
-	  MicroChannel Architecture is found in some IBM PS/2 machines and
-	  laptops.  It is a bus system similar to PCI or ISA. See
-	  <file:Documentation/mca.txt> (and especially the web page given
-	  there) before attempting to build an MCA bus kernel.
-
 config STACKTRACE_SUPPORT
 	bool
 	default y
@@ -336,8 +328,8 @@
 	select IRQ_DOMAIN
 	select NEED_MACH_IO_H if PCCARD
 	help
-	  This enables support for systems based on the Atmel AT91RM9200,
-	  AT91SAM9 processors.
+	  This enables support for systems based on Atmel
+	  AT91RM9200 and AT91SAM9* processors.
 
 config ARCH_BCMRING
 	bool "Broadcom BCMRING"
@@ -369,12 +361,12 @@
 	  Support for the Calxeda Highbank SoC based boards.
 
 config ARCH_CLPS711X
-	bool "Cirrus Logic CLPS711x/EP721x-based"
+	bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
 	select CPU_ARM720T
 	select ARCH_USES_GETTIMEOFFSET
 	select NEED_MACH_MEMORY_H
 	help
-	  Support for Cirrus Logic 711x/721x based boards.
+	  Support for Cirrus Logic 711x/721x/731x based boards.
 
 config ARCH_CNS3XXX
 	bool "Cavium Networks CNS3XXX family"
@@ -403,6 +395,8 @@
 	select CLKDEV_LOOKUP
 	select GENERIC_IRQ_CHIP
 	select MIGHT_HAVE_CACHE_L2X0
+	select PINCTRL
+	select PINCTRL_SIRF
 	select USE_OF
 	select ZONE_DMA
 	help
@@ -465,6 +459,7 @@
 	select CLKDEV_LOOKUP
 	select CLKSRC_MMIO
 	select HAVE_CLK_PREPARE
+	select PINCTRL
 	help
 	  Support for Freescale MXS-based family of processors
 
@@ -524,28 +519,6 @@
 	help
 	  Support for Intel's IOP33X (XScale) family of processors.
 
-config ARCH_IXP23XX
- 	bool "IXP23XX-based"
-	depends on MMU
-	select CPU_XSC3
- 	select PCI
-	select ARCH_USES_GETTIMEOFFSET
-	select NEED_MACH_IO_H
-	select NEED_MACH_MEMORY_H
-	help
-	  Support for Intel's IXP23xx (XScale) family of processors.
-
-config ARCH_IXP2000
-	bool "IXP2400/2800-based"
-	depends on MMU
-	select CPU_XSCALE
-	select PCI
-	select ARCH_USES_GETTIMEOFFSET
-	select NEED_MACH_IO_H
-	select NEED_MACH_MEMORY_H
-	help
-	  Support for Intel's IXP2400/2800 (XScale) family of processors.
-
 config ARCH_IXP4XX
 	bool "IXP4xx-based"
 	depends on MMU
@@ -593,6 +566,7 @@
 	select USB_ARCH_HAS_OHCI
 	select CLKDEV_LOOKUP
 	select GENERIC_CLOCKEVENTS
+	select USE_OF
 	help
 	  Support for the NXP LPC32XX family of processors
 
@@ -628,6 +602,7 @@
 	select CLKDEV_LOOKUP
 	select GENERIC_CLOCKEVENTS
 	select GPIO_PXA
+	select IRQ_DOMAIN
 	select PLAT_PXA
 	select SPARSE_IRQ
 	select GENERIC_ALLOCATOR
@@ -939,6 +914,7 @@
 	select CPU_ARM926T
 	select CLKDEV_LOOKUP
 	select GENERIC_CLOCKEVENTS
+	select PINCTRL
 	select MIGHT_HAVE_CACHE_L2X0
 	select ARCH_REQUIRE_GPIOLIB
 	help
@@ -1039,10 +1015,6 @@
 
 source "arch/arm/mach-ixp4xx/Kconfig"
 
-source "arch/arm/mach-ixp2000/Kconfig"
-
-source "arch/arm/mach-ixp23xx/Kconfig"
-
 source "arch/arm/mach-kirkwood/Kconfig"
 
 source "arch/arm/mach-ks8695/Kconfig"
@@ -1934,10 +1906,10 @@
 	default ZBOOT_ROM_NONE
 	help
 	  Include experimental SD/MMC loading code in the ROM-able zImage.
-	  With this enabled it is possible to write the the ROM-able zImage
+	  With this enabled it is possible to write the ROM-able zImage
 	  kernel image to an MMC or SD card and boot the kernel straight
 	  from the reset vector. At reset the processor Mask ROM will load
-	  the first part of the the ROM-able zImage which in turn loads the
+	  the first part of the ROM-able zImage which in turn loads the
 	  rest the kernel image to RAM.
 
 config ZBOOT_ROM_NONE
@@ -2279,9 +2251,9 @@
 source "kernel/power/Kconfig"
 
 config ARCH_SUSPEND_POSSIBLE
-	depends on !ARCH_S5PC100
+	depends on !ARCH_S5PC100 && !ARCH_TEGRA
 	depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
-		CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
+		CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK
 	def_bool y
 
 config ARM_CPU_SUSPEND
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 3b18ef7..157900d 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -147,8 +147,6 @@
 machine-$(CONFIG_ARCH_IOP13XX)		:= iop13xx
 machine-$(CONFIG_ARCH_IOP32X)		:= iop32x
 machine-$(CONFIG_ARCH_IOP33X)		:= iop33x
-machine-$(CONFIG_ARCH_IXP2000)		:= ixp2000
-machine-$(CONFIG_ARCH_IXP23XX)		:= ixp23xx
 machine-$(CONFIG_ARCH_IXP4XX)		:= ixp4xx
 machine-$(CONFIG_ARCH_KIRKWOOD)		:= kirkwood
 machine-$(CONFIG_ARCH_KS8695)		:= ks8695
diff --git a/arch/arm/boot/compressed/head-xscale.S b/arch/arm/boot/compressed/head-xscale.S
index aa5ee49..6ab0599 100644
--- a/arch/arm/boot/compressed/head-xscale.S
+++ b/arch/arm/boot/compressed/head-xscale.S
@@ -32,10 +32,3 @@
 		bic	r0, r0, #0x1000		@ clear Icache
 		mcr	p15, 0, r0, c1, c0, 0
 
-#ifdef CONFIG_ARCH_IXP2000
-		mov	r1, #-1
-		mov	r0, #0xd6000000
-		str	r1, [r0, #0x14]
-		str	r1, [r0, #0x18]
-#endif
-
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
new file mode 100644
index 0000000..f449efc
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -0,0 +1,273 @@
+/*
+ * at91sam9260.dtsi - Device Tree Include file for AT91SAM9260 family SoC
+ *
+ *  Copyright (C) 2011 Atmel,
+ *                2011 Nicolas Ferre <nicolas.ferre@atmel.com>,
+ *                2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Atmel AT91SAM9260 family SoC";
+	compatible = "atmel,at91sam9260";
+	interrupt-parent = <&aic>;
+
+	aliases {
+		serial0 = &dbgu;
+		serial1 = &usart0;
+		serial2 = &usart1;
+		serial3 = &usart2;
+		serial4 = &usart3;
+		serial5 = &usart4;
+		serial6 = &usart5;
+		gpio0 = &pioA;
+		gpio1 = &pioB;
+		gpio2 = &pioC;
+		tcb0 = &tcb0;
+		tcb1 = &tcb1;
+	};
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926ejs";
+		};
+	};
+
+	memory {
+		reg = <0x20000000 0x04000000>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		apb {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			aic: interrupt-controller@fffff000 {
+				#interrupt-cells = <2>;
+				compatible = "atmel,at91rm9200-aic";
+				interrupt-controller;
+				reg = <0xfffff000 0x200>;
+			};
+
+			ramc0: ramc@ffffea00 {
+				compatible = "atmel,at91sam9260-sdramc";
+				reg = <0xffffea00 0x200>;
+			};
+
+			pmc: pmc@fffffc00 {
+				compatible = "atmel,at91rm9200-pmc";
+				reg = <0xfffffc00 0x100>;
+			};
+
+			rstc@fffffd00 {
+				compatible = "atmel,at91sam9260-rstc";
+				reg = <0xfffffd00 0x10>;
+			};
+
+			shdwc@fffffd10 {
+				compatible = "atmel,at91sam9260-shdwc";
+				reg = <0xfffffd10 0x10>;
+			};
+
+			pit: timer@fffffd30 {
+				compatible = "atmel,at91sam9260-pit";
+				reg = <0xfffffd30 0xf>;
+				interrupts = <1 4>;
+			};
+
+			tcb0: timer@fffa0000 {
+				compatible = "atmel,at91rm9200-tcb";
+				reg = <0xfffa0000 0x100>;
+				interrupts = <17 4 18 4 19 4>;
+			};
+
+			tcb1: timer@fffdc000 {
+				compatible = "atmel,at91rm9200-tcb";
+				reg = <0xfffdc000 0x100>;
+				interrupts = <26 4 27 4 28 4>;
+			};
+
+			pioA: gpio@fffff400 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff400 0x100>;
+				interrupts = <2 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioB: gpio@fffff600 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff600 0x100>;
+				interrupts = <3 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioC: gpio@fffff800 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff800 0x100>;
+				interrupts = <4 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			dbgu: serial@fffff200 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfffff200 0x200>;
+				interrupts = <1 4>;
+				status = "disabled";
+			};
+
+			usart0: serial@fffb0000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfffb0000 0x200>;
+				interrupts = <6 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart1: serial@fffb4000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfffb4000 0x200>;
+				interrupts = <7 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart2: serial@fffb8000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfffb8000 0x200>;
+				interrupts = <8 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart3: serial@fffd0000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfffd0000 0x200>;
+				interrupts = <23 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart4: serial@fffd4000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfffd4000 0x200>;
+				interrupts = <24 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart5: serial@fffd8000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfffd8000 0x200>;
+				interrupts = <25 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			macb0: ethernet@fffc4000 {
+				compatible = "cdns,at32ap7000-macb", "cdns,macb";
+				reg = <0xfffc4000 0x100>;
+				interrupts = <21 4>;
+				status = "disabled";
+			};
+
+			usb1: gadget@fffa4000 {
+				compatible = "atmel,at91rm9200-udc";
+				reg = <0xfffa4000 0x4000>;
+				interrupts = <10 4>;
+				status = "disabled";
+			};
+
+			adc0: adc@fffe0000 {
+				compatible = "atmel,at91sam9260-adc";
+				reg = <0xfffe0000 0x100>;
+				interrupts = <5 4>;
+				atmel,adc-use-external-triggers;
+				atmel,adc-channels-used = <0xf>;
+				atmel,adc-vref = <3300>;
+				atmel,adc-num-channels = <4>;
+				atmel,adc-startup-time = <15>;
+				atmel,adc-channel-base = <0x30>;
+				atmel,adc-drdy-mask = <0x10000>;
+				atmel,adc-status-register = <0x1c>;
+				atmel,adc-trigger-register = <0x04>;
+
+				trigger@0 {
+					trigger-name = "timer-counter-0";
+					trigger-value = <0x1>;
+				};
+				trigger@1 {
+					trigger-name = "timer-counter-1";
+					trigger-value = <0x3>;
+				};
+
+				trigger@2 {
+					trigger-name = "timer-counter-2";
+					trigger-value = <0x5>;
+				};
+
+				trigger@3 {
+					trigger-name = "external";
+					trigger-value = <0x13>;
+					trigger-external;
+				};
+			};
+		};
+
+		nand0: nand@40000000 {
+			compatible = "atmel,at91rm9200-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x40000000 0x10000000
+			       0xffffe800 0x200
+			      >;
+			atmel,nand-addr-offset = <21>;
+			atmel,nand-cmd-offset = <22>;
+			gpios = <&pioC 13 0
+				 &pioC 14 0
+				 0
+				>;
+			status = "disabled";
+		};
+
+		usb0: ohci@00500000 {
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+			reg = <0x00500000 0x100000>;
+			interrupts = <20 4>;
+			status = "disabled";
+		};
+	};
+
+	i2c@0 {
+		compatible = "i2c-gpio";
+		gpios = <&pioA 23 0 /* sda */
+			 &pioA 24 0 /* scl */
+			>;
+		i2c-gpio,sda-open-drain;
+		i2c-gpio,scl-open-drain;
+		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
new file mode 100644
index 0000000..0209913
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -0,0 +1,220 @@
+/*
+ * at91sam9263.dtsi - Device Tree Include file for AT91SAM9263 family SoC
+ *
+ *  Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 only.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Atmel AT91SAM9263 family SoC";
+	compatible = "atmel,at91sam9263";
+	interrupt-parent = <&aic>;
+
+	aliases {
+		serial0 = &dbgu;
+		serial1 = &usart0;
+		serial2 = &usart1;
+		serial3 = &usart2;
+		gpio0 = &pioA;
+		gpio1 = &pioB;
+		gpio2 = &pioC;
+		gpio3 = &pioD;
+		gpio4 = &pioE;
+		tcb0 = &tcb0;
+	};
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926ejs";
+		};
+	};
+
+	memory {
+		reg = <0x20000000 0x08000000>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		apb {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			aic: interrupt-controller@fffff000 {
+				#interrupt-cells = <2>;
+				compatible = "atmel,at91rm9200-aic";
+				interrupt-controller;
+				reg = <0xfffff000 0x200>;
+			};
+
+			pmc: pmc@fffffc00 {
+				compatible = "atmel,at91rm9200-pmc";
+				reg = <0xfffffc00 0x100>;
+			};
+
+			ramc: ramc@ffffe200 {
+				compatible = "atmel,at91sam9260-sdramc";
+				reg = <0xffffe200 0x200
+				       0xffffe800 0x200>;
+			};
+
+			pit: timer@fffffd30 {
+				compatible = "atmel,at91sam9260-pit";
+				reg = <0xfffffd30 0xf>;
+				interrupts = <1 4>;
+			};
+
+			tcb0: timer@fff7c000 {
+				compatible = "atmel,at91rm9200-tcb";
+				reg = <0xfff7c000 0x100>;
+				interrupts = <19 4>;
+			};
+
+			rstc@fffffd00 {
+				compatible = "atmel,at91sam9260-rstc";
+				reg = <0xfffffd00 0x10>;
+			};
+
+			shdwc@fffffd10 {
+				compatible = "atmel,at91sam9260-shdwc";
+				reg = <0xfffffd10 0x10>;
+			};
+
+			pioA: gpio@fffff200 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff200 0x100>;
+				interrupts = <2 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioB: gpio@fffff400 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff400 0x100>;
+				interrupts = <3 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioC: gpio@fffff600 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff600 0x100>;
+				interrupts = <4 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioD: gpio@fffff800 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff800 0x100>;
+				interrupts = <4 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioE: gpio@fffffa00 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffffa00 0x100>;
+				interrupts = <4 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			dbgu: serial@ffffee00 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xffffee00 0x200>;
+				interrupts = <1 4>;
+				status = "disabled";
+			};
+
+			usart0: serial@fff8c000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfff8c000 0x200>;
+				interrupts = <7 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart1: serial@fff90000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfff90000 0x200>;
+				interrupts = <8 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart2: serial@fff94000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfff94000 0x200>;
+				interrupts = <9 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			macb0: ethernet@fffbc000 {
+				compatible = "cdns,at32ap7000-macb", "cdns,macb";
+				reg = <0xfffbc000 0x100>;
+				interrupts = <21 4>;
+				status = "disabled";
+			};
+
+			usb1: gadget@fff78000 {
+				compatible = "atmel,at91rm9200-udc";
+				reg = <0xfff78000 0x4000>;
+				interrupts = <24 4>;
+				status = "disabled";
+			};
+		};
+
+		nand0: nand@40000000 {
+			compatible = "atmel,at91rm9200-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x40000000 0x10000000
+			       0xffffe000 0x200
+			      >;
+			atmel,nand-addr-offset = <21>;
+			atmel,nand-cmd-offset = <22>;
+			gpios = <&pioA 22 0
+				 &pioD 15 0
+				 0
+				>;
+			status = "disabled";
+		};
+
+		usb0: ohci@00a00000 {
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+			reg = <0x00a00000 0x100000>;
+			interrupts = <29 4>;
+			status = "disabled";
+		};
+	};
+
+	i2c@0 {
+		compatible = "i2c-gpio";
+		gpios = <&pioB 4 0 /* sda */
+			 &pioB 5 0 /* scl */
+			>;
+		i2c-gpio,sda-open-drain;
+		i2c-gpio,scl-open-drain;
+		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
new file mode 100644
index 0000000..f86ac4b
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9263ek.dts
@@ -0,0 +1,156 @@
+/*
+ * at91sam9263ek.dts - Device Tree file for Atmel at91sam9263 reference board
+ *
+ *  Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 only
+ */
+/dts-v1/;
+/include/ "at91sam9263.dtsi"
+
+/ {
+	model = "Atmel at91sam9263ek";
+	compatible = "atmel,at91sam9263ek", "atmel,at91sam9263", "atmel,at91sam9";
+
+	chosen {
+		bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+	};
+
+	memory {
+		reg = <0x20000000 0x4000000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <16367660>;
+		};
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@ffffee00 {
+				status = "okay";
+			};
+
+			usart0: serial@fff8c000 {
+				status = "okay";
+			};
+
+			macb0: ethernet@fffbc000 {
+				phy-mode = "rmii";
+				status = "okay";
+			};
+
+			usb1: gadget@fff78000 {
+				atmel,vbus-gpio = <&pioA 25 0>;
+				status = "okay";
+			};
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt = <1>;
+			status = "okay";
+
+			at91bootstrap@0 {
+				label = "at91bootstrap";
+				reg = <0x0 0x20000>;
+			};
+
+			barebox@20000 {
+				label = "barebox";
+				reg = <0x20000 0x40000>;
+			};
+
+			bareboxenv@60000 {
+				label = "bareboxenv";
+				reg = <0x60000 0x20000>;
+			};
+
+			bareboxenv2@80000 {
+				label = "bareboxenv2";
+				reg = <0x80000 0x20000>;
+			};
+
+			oftree@80000 {
+				label = "oftree";
+				reg = <0xa0000 0x20000>;
+			};
+
+			kernel@a0000 {
+				label = "kernel";
+				reg = <0xc0000 0x400000>;
+			};
+
+			rootfs@4a0000 {
+				label = "rootfs";
+				reg = <0x4c0000 0x7800000>;
+			};
+
+			data@7ca0000 {
+				label = "data";
+				reg = <0x7cc0000 0x8340000>;
+			};
+		};
+
+		usb0: ohci@00a00000 {
+			num-ports = <2>;
+			status = "okay";
+			atmel,vbus-gpio = <&pioA 24 0
+					   &pioA 21 0
+					  >;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		d3 {
+			label = "d3";
+			gpios = <&pioB 7 0>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		d2 {
+			label = "d2";
+			gpios = <&pioC 29 1>;
+			linux,default-trigger = "nand-disk";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		left_click {
+			label = "left_click";
+			gpios = <&pioC 5 1>;
+			linux,code = <272>;
+			gpio-key,wakeup;
+		};
+
+		right_click {
+			label = "right_click";
+			gpios = <&pioC 4 1>;
+			linux,code = <273>;
+			gpio-key,wakeup;
+		};
+	};
+
+	i2c@0 {
+		status = "okay";
+
+		24c512@50 {
+			compatible = "24c512";
+			reg = <0x50>;
+			pagesize = <128>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
index 773ef48..2a1d1ca 100644
--- a/arch/arm/boot/dts/at91sam9g20.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20.dtsi
@@ -1,238 +1,26 @@
 /*
  * at91sam9g20.dtsi - Device Tree Include file for AT91SAM9G20 family SoC
  *
- *  Copyright (C) 2011 Atmel,
- *                2011 Nicolas Ferre <nicolas.ferre@atmel.com>,
- *                2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *  Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
  *
- * Licensed under GPLv2 or later.
+ * Licensed under GPLv2.
  */
 
-/include/ "skeleton.dtsi"
+/include/ "at91sam9260.dtsi"
 
 / {
 	model = "Atmel AT91SAM9G20 family SoC";
 	compatible = "atmel,at91sam9g20";
-	interrupt-parent = <&aic>;
-
-	aliases {
-		serial0 = &dbgu;
-		serial1 = &usart0;
-		serial2 = &usart1;
-		serial3 = &usart2;
-		serial4 = &usart3;
-		serial5 = &usart4;
-		serial6 = &usart5;
-		gpio0 = &pioA;
-		gpio1 = &pioB;
-		gpio2 = &pioC;
-		tcb0 = &tcb0;
-		tcb1 = &tcb1;
-	};
-	cpus {
-		cpu@0 {
-			compatible = "arm,arm926ejs";
-		};
-	};
 
 	memory {
 		reg = <0x20000000 0x08000000>;
 	};
 
 	ahb {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
 		apb {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges;
-
-			aic: interrupt-controller@fffff000 {
-				#interrupt-cells = <2>;
-				compatible = "atmel,at91rm9200-aic";
-				interrupt-controller;
-				reg = <0xfffff000 0x200>;
-			};
-
-			ramc0: ramc@ffffea00 {
-				compatible = "atmel,at91sam9260-sdramc";
-				reg = <0xffffea00 0x200>;
-			};
-
-			pmc: pmc@fffffc00 {
-				compatible = "atmel,at91rm9200-pmc";
-				reg = <0xfffffc00 0x100>;
-			};
-
-			rstc@fffffd00 {
-				compatible = "atmel,at91sam9260-rstc";
-				reg = <0xfffffd00 0x10>;
-			};
-
-			shdwc@fffffd10 {
-				compatible = "atmel,at91sam9260-shdwc";
-				reg = <0xfffffd10 0x10>;
-			};
-
-			pit: timer@fffffd30 {
-				compatible = "atmel,at91sam9260-pit";
-				reg = <0xfffffd30 0xf>;
-				interrupts = <1 4>;
-			};
-
-			tcb0: timer@fffa0000 {
-				compatible = "atmel,at91rm9200-tcb";
-				reg = <0xfffa0000 0x100>;
-				interrupts = <17 4 18 4 19 4>;
-			};
-
-			tcb1: timer@fffdc000 {
-				compatible = "atmel,at91rm9200-tcb";
-				reg = <0xfffdc000 0x100>;
-				interrupts = <26 4 27 4 28 4>;
-			};
-
-			pioA: gpio@fffff400 {
-				compatible = "atmel,at91rm9200-gpio";
-				reg = <0xfffff400 0x100>;
-				interrupts = <2 4>;
-				#gpio-cells = <2>;
-				gpio-controller;
-				interrupt-controller;
-			};
-
-			pioB: gpio@fffff600 {
-				compatible = "atmel,at91rm9200-gpio";
-				reg = <0xfffff600 0x100>;
-				interrupts = <3 4>;
-				#gpio-cells = <2>;
-				gpio-controller;
-				interrupt-controller;
-			};
-
-			pioC: gpio@fffff800 {
-				compatible = "atmel,at91rm9200-gpio";
-				reg = <0xfffff800 0x100>;
-				interrupts = <4 4>;
-				#gpio-cells = <2>;
-				gpio-controller;
-				interrupt-controller;
-			};
-
-			dbgu: serial@fffff200 {
-				compatible = "atmel,at91sam9260-usart";
-				reg = <0xfffff200 0x200>;
-				interrupts = <1 4>;
-				status = "disabled";
-			};
-
-			usart0: serial@fffb0000 {
-				compatible = "atmel,at91sam9260-usart";
-				reg = <0xfffb0000 0x200>;
-				interrupts = <6 4>;
-				atmel,use-dma-rx;
-				atmel,use-dma-tx;
-				status = "disabled";
-			};
-
-			usart1: serial@fffb4000 {
-				compatible = "atmel,at91sam9260-usart";
-				reg = <0xfffb4000 0x200>;
-				interrupts = <7 4>;
-				atmel,use-dma-rx;
-				atmel,use-dma-tx;
-				status = "disabled";
-			};
-
-			usart2: serial@fffb8000 {
-				compatible = "atmel,at91sam9260-usart";
-				reg = <0xfffb8000 0x200>;
-				interrupts = <8 4>;
-				atmel,use-dma-rx;
-				atmel,use-dma-tx;
-				status = "disabled";
-			};
-
-			usart3: serial@fffd0000 {
-				compatible = "atmel,at91sam9260-usart";
-				reg = <0xfffd0000 0x200>;
-				interrupts = <23 4>;
-				atmel,use-dma-rx;
-				atmel,use-dma-tx;
-				status = "disabled";
-			};
-
-			usart4: serial@fffd4000 {
-				compatible = "atmel,at91sam9260-usart";
-				reg = <0xfffd4000 0x200>;
-				interrupts = <24 4>;
-				atmel,use-dma-rx;
-				atmel,use-dma-tx;
-				status = "disabled";
-			};
-
-			usart5: serial@fffd8000 {
-				compatible = "atmel,at91sam9260-usart";
-				reg = <0xfffd8000 0x200>;
-				interrupts = <25 4>;
-				atmel,use-dma-rx;
-				atmel,use-dma-tx;
-				status = "disabled";
-			};
-
-			macb0: ethernet@fffc4000 {
-				compatible = "cdns,at32ap7000-macb", "cdns,macb";
-				reg = <0xfffc4000 0x100>;
-				interrupts = <21 4>;
-				status = "disabled";
-			};
-
-			usb1: gadget@fffa4000 {
-				compatible = "atmel,at91rm9200-udc";
-				reg = <0xfffa4000 0x4000>;
-				interrupts = <10 4>;
-				status = "disabled";
+			adc0: adc@fffe0000 {
+				atmel,adc-startup-time = <40>;
 			};
 		};
-
-		nand0: nand@40000000 {
-			compatible = "atmel,at91rm9200-nand";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			reg = <0x40000000 0x10000000
-			       0xffffe800 0x200
-			      >;
-			atmel,nand-addr-offset = <21>;
-			atmel,nand-cmd-offset = <22>;
-			gpios = <&pioC 13 0
-				 &pioC 14 0
-				 0
-				>;
-			status = "disabled";
-		};
-
-		usb0: ohci@00500000 {
-			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
-			reg = <0x00500000 0x100000>;
-			interrupts = <20 4>;
-			status = "disabled";
-		};
-	};
-
-	i2c@0 {
-		compatible = "i2c-gpio";
-		gpios = <&pioA 23 0 /* sda */
-			 &pioA 24 0 /* scl */
-			>;
-		i2c-gpio,sda-open-drain;
-		i2c-gpio,scl-open-drain;
-		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
 	};
 };
diff --git a/arch/arm/boot/dts/at91sam9g20ek.dts b/arch/arm/boot/dts/at91sam9g20ek.dts
new file mode 100644
index 0000000..e5324bf
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g20ek.dts
@@ -0,0 +1,29 @@
+/*
+ * at91sam9g20ek.dts - Device Tree file for Atmel at91sam9g20ek board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9g20ek_common.dtsi"
+
+/ {
+	model = "Atmel at91sam9g20ek";
+	compatible = "atmel,at91sam9g20ek", "atmel,at91sam9g20", "atmel,at91sam9";
+
+	leds {
+		compatible = "gpio-leds";
+
+		ds1 {
+			label = "ds1";
+			gpios = <&pioA 9 0>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		ds5 {
+			label = "ds5";
+			gpios = <&pioA 6 1>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
new file mode 100644
index 0000000..f1b2e14
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
@@ -0,0 +1,29 @@
+/*
+ * at91sam9g20ek_2mmc.dts - Device Tree file for Atmel at91sam9g20ek 2 MMC board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9g20ek_common.dtsi"
+
+/ {
+	model = "Atmel at91sam9g20ek 2 mmc";
+	compatible = "atmel,at91sam9g20ek_2mmc", "atmel,at91sam9g20", "atmel,at91sam9";
+
+	leds {
+		compatible = "gpio-leds";
+
+		ds1 {
+			label = "ds1";
+			gpios = <&pioB 9 0>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		ds5 {
+			label = "ds5";
+			gpios = <&pioB 8 1>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
new file mode 100644
index 0000000..b06c0db
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -0,0 +1,142 @@
+/*
+ * at91sam9g20ek_common.dtsi - Device Tree file for Atmel at91sam9g20ek board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/include/ "at91sam9g20.dtsi"
+
+/ {
+
+	chosen {
+		bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+	};
+
+	memory {
+		reg = <0x20000000 0x4000000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <18432000>;
+		};
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@fffff200 {
+				status = "okay";
+			};
+
+			usart0: serial@fffb0000 {
+				status = "okay";
+			};
+
+			usart1: serial@fffb4000 {
+				status = "okay";
+			};
+
+			macb0: ethernet@fffc4000 {
+				phy-mode = "rmii";
+				status = "okay";
+			};
+
+			usb1: gadget@fffa4000 {
+				atmel,vbus-gpio = <&pioC 5 0>;
+				status = "okay";
+			};
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+
+			at91bootstrap@0 {
+				label = "at91bootstrap";
+				reg = <0x0 0x20000>;
+			};
+
+			barebox@20000 {
+				label = "barebox";
+				reg = <0x20000 0x40000>;
+			};
+
+			bareboxenv@60000 {
+				label = "bareboxenv";
+				reg = <0x60000 0x20000>;
+			};
+
+			bareboxenv2@80000 {
+				label = "bareboxenv2";
+				reg = <0x80000 0x20000>;
+			};
+
+			oftree@80000 {
+				label = "oftree";
+				reg = <0xa0000 0x20000>;
+			};
+
+			kernel@a0000 {
+				label = "kernel";
+				reg = <0xc0000 0x400000>;
+			};
+
+			rootfs@4a0000 {
+				label = "rootfs";
+				reg = <0x4c0000 0x7800000>;
+			};
+
+			data@7ca0000 {
+				label = "data";
+				reg = <0x7cc0000 0x8340000>;
+			};
+		};
+
+		usb0: ohci@00500000 {
+			num-ports = <2>;
+			status = "okay";
+		};
+	};
+
+	i2c@0 {
+		status = "okay";
+
+		24c512@50 {
+			compatible = "24c512";
+			reg = <0x50>;
+		};
+
+		wm8731@1b {
+			compatible = "wm8731";
+			reg = <0x1b>;
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		btn3 {
+			label = "Buttin 3";
+			gpios = <&pioA 30 1>;
+			linux,code = <0x103>;
+			gpio-key,wakeup;
+		};
+
+		btn4 {
+			label = "Buttin 4";
+			gpios = <&pioA 31 1>;
+			linux,code = <0x104>;
+			gpio-key,wakeup;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index c804214..7dbccaf 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -199,6 +199,43 @@
 				interrupts = <25 4>;
 				status = "disabled";
 			};
+
+			adc0: adc@fffb0000 {
+				compatible = "atmel,at91sam9260-adc";
+				reg = <0xfffb0000 0x100>;
+				interrupts = <20 4>;
+				atmel,adc-use-external-triggers;
+				atmel,adc-channels-used = <0xff>;
+				atmel,adc-vref = <3300>;
+				atmel,adc-num-channels = <8>;
+				atmel,adc-startup-time = <40>;
+				atmel,adc-channel-base = <0x30>;
+				atmel,adc-drdy-mask = <0x10000>;
+				atmel,adc-status-register = <0x1c>;
+				atmel,adc-trigger-register = <0x08>;
+
+				trigger@0 {
+					trigger-name = "external-rising";
+					trigger-value = <0x1>;
+					trigger-external;
+				};
+				trigger@1 {
+					trigger-name = "external-falling";
+					trigger-value = <0x2>;
+					trigger-external;
+				};
+
+				trigger@2 {
+					trigger-name = "external-any";
+					trigger-value = <0x3>;
+					trigger-external;
+				};
+
+				trigger@3 {
+					trigger-name = "continuous";
+					trigger-value = <0x6>;
+				};
+			};
 		};
 
 		nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
new file mode 100644
index 0000000..cb84de7
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -0,0 +1,221 @@
+/*
+ * at91sam9n12.dtsi - Device Tree include file for AT91SAM9N12 SoC
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Hong Xu <hong.xu@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Atmel AT91SAM9N12 SoC";
+	compatible = "atmel,at91sam9n12";
+	interrupt-parent = <&aic>;
+
+	aliases {
+		serial0 = &dbgu;
+		serial1 = &usart0;
+		serial2 = &usart1;
+		serial3 = &usart2;
+		serial4 = &usart3;
+		gpio0 = &pioA;
+		gpio1 = &pioB;
+		gpio2 = &pioC;
+		gpio3 = &pioD;
+		tcb0 = &tcb0;
+		tcb1 = &tcb1;
+	};
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926ejs";
+		};
+	};
+
+	memory {
+		reg = <0x20000000 0x10000000>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		apb {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			aic: interrupt-controller@fffff000 {
+				#interrupt-cells = <2>;
+				compatible = "atmel,at91rm9200-aic";
+				interrupt-controller;
+				reg = <0xfffff000 0x200>;
+			};
+
+			ramc0: ramc@ffffe800 {
+				compatible = "atmel,at91sam9g45-ddramc";
+				reg = <0xffffe800 0x200>;
+			};
+
+			pmc: pmc@fffffc00 {
+				compatible = "atmel,at91rm9200-pmc";
+				reg = <0xfffffc00 0x100>;
+			};
+
+			rstc@fffffe00 {
+				compatible = "atmel,at91sam9g45-rstc";
+				reg = <0xfffffe00 0x10>;
+			};
+
+			pit: timer@fffffe30 {
+				compatible = "atmel,at91sam9260-pit";
+				reg = <0xfffffe30 0xf>;
+				interrupts = <1 4>;
+			};
+
+			shdwc@fffffe10 {
+				compatible = "atmel,at91sam9x5-shdwc";
+				reg = <0xfffffe10 0x10>;
+			};
+
+			tcb0: timer@f8008000 {
+				compatible = "atmel,at91sam9x5-tcb";
+				reg = <0xf8008000 0x100>;
+				interrupts = <17 4>;
+			};
+
+			tcb1: timer@f800c000 {
+				compatible = "atmel,at91sam9x5-tcb";
+				reg = <0xf800c000 0x100>;
+				interrupts = <17 4>;
+			};
+
+			dma: dma-controller@ffffec00 {
+				compatible = "atmel,at91sam9g45-dma";
+				reg = <0xffffec00 0x200>;
+				interrupts = <20 4>;
+			};
+
+			pioA: gpio@fffff400 {
+				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+				reg = <0xfffff400 0x100>;
+				interrupts = <2 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioB: gpio@fffff600 {
+				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+				reg = <0xfffff600 0x100>;
+				interrupts = <2 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioC: gpio@fffff800 {
+				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+				reg = <0xfffff800 0x100>;
+				interrupts = <3 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioD: gpio@fffffa00 {
+				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+				reg = <0xfffffa00 0x100>;
+				interrupts = <3 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			dbgu: serial@fffff200 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfffff200 0x200>;
+				interrupts = <1 4>;
+				status = "disabled";
+			};
+
+			usart0: serial@f801c000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xf801c000 0x4000>;
+				interrupts = <5 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart1: serial@f8020000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xf8020000 0x4000>;
+				interrupts = <6 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart2: serial@f8024000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xf8024000 0x4000>;
+				interrupts = <7 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart3: serial@f8028000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xf8028000 0x4000>;
+				interrupts = <8 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+		};
+
+		nand0: nand@40000000 {
+			compatible = "atmel,at91rm9200-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = < 0x40000000 0x10000000
+				0xffffe000 0x00000600
+				0xffffe600 0x00000200
+				0x00100000 0x00100000
+			       >;
+			atmel,nand-addr-offset = <21>;
+			atmel,nand-cmd-offset = <22>;
+			gpios = <&pioD 5 0
+				 &pioD 4 0
+				 0
+				>;
+			status = "disabled";
+		};
+
+		usb0: ohci@00500000 {
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+			reg = <0x00500000 0x00100000>;
+			interrupts = <22 4>;
+			status = "disabled";
+		};
+	};
+
+	i2c@0 {
+		compatible = "i2c-gpio";
+		gpios = <&pioA 30 0 /* sda */
+			 &pioA 31 0 /* scl */
+			>;
+		i2c-gpio,sda-open-drain;
+		i2c-gpio,scl-open-drain;
+		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
new file mode 100644
index 0000000..f4e43e3
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -0,0 +1,84 @@
+/*
+ * at91sam9n12ek.dts - Device Tree file for AT91SAM9N12-EK board
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Hong Xu <hong.xu@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9n12.dtsi"
+
+/ {
+	model = "Atmel AT91SAM9N12-EK";
+	compatible = "atmel,at91sam9n12ek", "atmel,at91sam9n12", "atmel,at91sam9";
+
+	chosen {
+		bootargs = "mem=128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
+	};
+
+	memory {
+		reg = <0x20000000 0x10000000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <16000000>;
+		};
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@fffff200 {
+				status = "okay";
+			};
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		d8 {
+			label = "d8";
+			gpios = <&pioB 4 1>;
+			linux,default-trigger = "mmc0";
+		};
+
+		d9 {
+			label = "d6";
+			gpios = <&pioB 5 1>;
+			linux,default-trigger = "nand-disk";
+		};
+
+		d10 {
+			label = "d7";
+			gpios = <&pioB 6 0>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		enter {
+			label = "Enter";
+			gpios = <&pioB 4 1>;
+			linux,code = <28>;
+			gpio-key,wakeup;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index dd4ed74..6b3ef43 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -190,6 +190,44 @@
 				interrupts = <27 4>;
 				status = "disabled";
 			};
+
+			adc0: adc@f804c000 {
+				compatible = "atmel,at91sam9260-adc";
+				reg = <0xf804c000 0x100>;
+				interrupts = <19 4>;
+				atmel,adc-use-external;
+				atmel,adc-channels-used = <0xffff>;
+				atmel,adc-vref = <3300>;
+				atmel,adc-num-channels = <12>;
+				atmel,adc-startup-time = <40>;
+				atmel,adc-channel-base = <0x50>;
+				atmel,adc-drdy-mask = <0x1000000>;
+				atmel,adc-status-register = <0x30>;
+				atmel,adc-trigger-register = <0xc0>;
+
+				trigger@0 {
+					trigger-name = "external-rising";
+					trigger-value = <0x1>;
+					trigger-external;
+				};
+
+				trigger@1 {
+					trigger-name = "external-falling";
+					trigger-value = <0x2>;
+					trigger-external;
+				};
+
+				trigger@2 {
+					trigger-name = "external-any";
+					trigger-value = <0x3>;
+					trigger-external;
+				};
+
+				trigger@3 {
+					trigger-name = "continuous";
+					trigger-value = <0x6>;
+				};
+			};
 		};
 
 		nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/db8500.dtsi b/arch/arm/boot/dts/db8500.dtsi
index 14bc307..881bc39 100644
--- a/arch/arm/boot/dts/db8500.dtsi
+++ b/arch/arm/boot/dts/db8500.dtsi
@@ -55,83 +55,101 @@
 
 		gpio0: gpio@8012e000 {
 			compatible = "stericsson,db8500-gpio",
-				"stmicroelectronics,nomadik-gpio";
+				"st,nomadik-gpio";
 			reg =  <0x8012e000 0x80>;
 			interrupts = <0 119 0x4>;
 			supports-sleepmode;
 			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-bank = <0>;
 		};
 
 		gpio1: gpio@8012e080 {
 			compatible = "stericsson,db8500-gpio",
-				"stmicroelectronics,nomadik-gpio";
+				"st,nomadik-gpio";
 			reg =  <0x8012e080 0x80>;
 			interrupts = <0 120 0x4>;
 			supports-sleepmode;
 			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-bank = <1>;
 		};
 
 		gpio2: gpio@8000e000 {
 			compatible = "stericsson,db8500-gpio",
-				"stmicroelectronics,nomadik-gpio";
+				"st,nomadik-gpio";
 			reg =  <0x8000e000 0x80>;
 			interrupts = <0 121 0x4>;
 			supports-sleepmode;
 			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-bank = <2>;
 		};
 
 		gpio3: gpio@8000e080 {
 			compatible = "stericsson,db8500-gpio",
-				"stmicroelectronics,nomadik-gpio";
+				"st,nomadik-gpio";
 			reg =  <0x8000e080 0x80>;
 			interrupts = <0 122 0x4>;
 			supports-sleepmode;
 			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-bank = <3>;
 		};
 
 		gpio4: gpio@8000e100 {
 			compatible = "stericsson,db8500-gpio",
-				"stmicroelectronics,nomadik-gpio";
+				"st,nomadik-gpio";
 			reg =  <0x8000e100 0x80>;
 			interrupts = <0 123 0x4>;
 			supports-sleepmode;
 			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-bank = <4>;
 		};
 
 		gpio5: gpio@8000e180 {
 			compatible = "stericsson,db8500-gpio",
-				"stmicroelectronics,nomadik-gpio";
+				"st,nomadik-gpio";
 			reg =  <0x8000e180 0x80>;
 			interrupts = <0 124 0x4>;
 			supports-sleepmode;
 			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-bank = <5>;
 		};
 
 		gpio6: gpio@8011e000 {
 			compatible = "stericsson,db8500-gpio",
-				"stmicroelectronics,nomadik-gpio";
+				"st,nomadik-gpio";
 			reg =  <0x8011e000 0x80>;
 			interrupts = <0 125 0x4>;
 			supports-sleepmode;
 			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-bank = <6>;
 		};
 
 		gpio7: gpio@8011e080 {
 			compatible = "stericsson,db8500-gpio",
-				"stmicroelectronics,nomadik-gpio";
+				"st,nomadik-gpio";
 			reg =  <0x8011e080 0x80>;
 			interrupts = <0 126 0x4>;
 			supports-sleepmode;
 			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-bank = <7>;
 		};
 
 		gpio8: gpio@a03fe000 {
 			compatible = "stericsson,db8500-gpio",
-				"stmicroelectronics,nomadik-gpio";
+				"st,nomadik-gpio";
 			reg =  <0xa03fe000 0x80>;
 			interrupts = <0 127 0x4>;
 			supports-sleepmode;
 			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-bank = <8>;
 		};
 
 		usb@a03e0000 {
@@ -153,7 +171,13 @@
 			reg = <0x80157000 0x1000>;
 			interrupts = <46 47>;
 			#address-cells = <1>;
-			#size-cells = <0>;
+			#size-cells = <1>;
+			ranges;
+
+				prcmu-timer-4@80157450 {
+				compatible = "stericsson,db8500-prcmu-timer-4";
+				reg = <0x80157450 0xC>;
+			};
 
 			ab8500@5 {
 				compatible = "stericsson,ab8500";
@@ -163,7 +187,7 @@
 		};
 
 		i2c@80004000 {
-			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
 			reg = <0x80004000 0x1000>;
 			interrupts = <0 21 0x4>;
 			#address-cells = <1>;
@@ -171,7 +195,7 @@
 		};
 
 		i2c@80122000 {
-			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
 			reg = <0x80122000 0x1000>;
 			interrupts = <0 22 0x4>;
 			#address-cells = <1>;
@@ -179,7 +203,7 @@
 		};
 
 		i2c@80128000 {
-			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
 			reg = <0x80128000 0x1000>;
 			interrupts = <0 55 0x4>;
 			#address-cells = <1>;
@@ -187,7 +211,7 @@
 		};
 
 		i2c@80110000 {
-			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
 			reg = <0x80110000 0x1000>;
 			interrupts = <0 12 0x4>;
 			#address-cells = <1>;
@@ -195,7 +219,7 @@
 		};
 
 		i2c@8012a000 {
-			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
 			reg = <0x8012a000 0x1000>;
 			interrupts = <0 51 0x4>;
 			#address-cells = <1>;
@@ -270,5 +294,14 @@
 			interrupts = <0 100 0x4>;
 			status = "disabled";
 		};
+
+		external-bus@50000000 {
+			compatible = "simple-bus";
+			reg = <0x50000000 0x4000000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x50000000 0x4000000>;
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/emev2-kzm9d.dts b/arch/arm/boot/dts/emev2-kzm9d.dts
new file mode 100644
index 0000000..297e3ba
--- /dev/null
+++ b/arch/arm/boot/dts/emev2-kzm9d.dts
@@ -0,0 +1,26 @@
+/*
+ * Device Tree Source for the KZM9D board
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * 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.
+ */
+/dts-v1/;
+
+/include/ "emev2.dtsi"
+
+/ {
+	model = "EMEV2 KZM9D Board";
+	compatible = "renesas,kzm9d", "renesas,emev2";
+
+	memory {
+		device_type = "memory";
+		reg = <0x40000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS1,115200n81";
+	};
+};
diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi
new file mode 100644
index 0000000..eb504a6
--- /dev/null
+++ b/arch/arm/boot/dts/emev2.dtsi
@@ -0,0 +1,63 @@
+/*
+ * Device Tree Source for the EMEV2 SoC
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+	compatible = "renesas,emev2";
+	interrupt-parent = <&gic>;
+
+	cpus {
+		cpu@0 {
+			compatible = "arm,cortex-a9";
+		};
+		cpu@1 {
+			compatible = "arm,cortex-a9";
+		};
+	};
+
+	gic: interrupt-controller@e0020000 {
+		compatible = "arm,cortex-a9-gic";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xe0028000 0x1000>,
+		      <0xe0020000 0x0100>;
+	};
+
+	sti@e0180000 {
+		compatible = "renesas,em-sti";
+		reg = <0xe0180000 0x54>;
+		interrupts = <0 125 0>;
+	};
+
+	uart@e1020000 {
+		compatible = "renesas,em-uart";
+		reg = <0xe1020000 0x38>;
+		interrupts = <0 8 0>;
+	};
+
+	uart@e1030000 {
+		compatible = "renesas,em-uart";
+		reg = <0xe1030000 0x38>;
+		interrupts = <0 9 0>;
+	};
+
+	uart@e1040000 {
+		compatible = "renesas,em-uart";
+		reg = <0xe1040000 0x38>;
+		interrupts = <0 10 0>;
+	};
+
+	uart@e1050000 {
+		compatible = "renesas,em-uart";
+		reg = <0xe1050000 0x38>;
+		interrupts = <0 11 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/ethernut5.dts b/arch/arm/boot/dts/ethernut5.dts
new file mode 100644
index 0000000..1ea9d34
--- /dev/null
+++ b/arch/arm/boot/dts/ethernut5.dts
@@ -0,0 +1,84 @@
+/*
+ * ethernut5.dts - Device Tree file for Ethernut 5 board
+ *
+ * Copyright (C) 2012 egnite GmbH <info@egnite.de>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9260.dtsi"
+
+/ {
+	model = "Ethernut 5";
+	compatible = "egnite,ethernut5", "atmel,at91sam9260", "atmel,at91sam9";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 root=/dev/mtdblock0 rw rootfstype=jffs2";
+	};
+
+	memory {
+		reg = <0x20000000 0x08000000>;
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@fffff200 {
+				status = "okay";
+			};
+
+			usart0: serial@fffb0000 {
+				status = "okay";
+			};
+
+			usart1: serial@fffb4000 {
+				status = "okay";
+			};
+
+			macb0: ethernet@fffc4000 {
+				phy-mode = "rmii";
+				status = "okay";
+			};
+
+			usb1: gadget@fffa4000 {
+				atmel,vbus-gpio = <&pioC 5 0>;
+				status = "okay";
+			};
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+
+			gpios = <0
+				 &pioC 14 0
+				 0
+				>;
+
+			root@0 {
+				label = "root";
+				reg = <0x0 0x08000000>;
+			};
+
+			data@20000 {
+				label = "data";
+				reg = <0x08000000 0x38000000>;
+			};
+		};
+
+		usb0: ohci@00500000 {
+			num-ports = <2>;
+			status = "okay";
+		};
+	};
+
+	i2c@0 {
+		status = "okay";
+
+		pcf8563@50 {
+			compatible = "nxp,pcf8563";
+			reg = <0x51>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/kirkwood-dns320.dts b/arch/arm/boot/dts/kirkwood-dns320.dts
new file mode 100644
index 0000000..dc09a73
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-dns320.dts
@@ -0,0 +1,64 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+	model = "D-Link DNS-320 NAS (Rev A1)";
+	compatible = "dlink,dns-320-a1", "dlink,dns-320", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8 earlyprintk";
+	};
+
+	ocp@f1000000 {
+		serial@12000 {
+			clock-frequency = <166666667>;
+			status = "okay";
+		};
+
+		serial@12100 {
+			clock-frequency = <166666667>;
+			status = "okay";
+		};
+
+		nand@3000000 {
+			status = "okay";
+
+			partition@0 {
+				label = "u-boot";
+				reg = <0x0000000 0x100000>;
+				read-only;
+			};
+
+			partition@100000 {
+				label = "uImage";
+				reg = <0x0100000 0x500000>;
+			};
+
+			partition@600000 {
+				label = "ramdisk";
+				reg = <0x0600000 0x500000>;
+			};
+
+			partition@b00000 {
+				label = "image";
+				reg = <0x0b00000 0x6600000>;
+			};
+
+			partition@7100000 {
+				label = "mini firmware";
+				reg = <0x7100000 0xa00000>;
+			};
+
+			partition@7b00000 {
+				label = "config";
+				reg = <0x7b00000 0x500000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/kirkwood-dns325.dts b/arch/arm/boot/dts/kirkwood-dns325.dts
new file mode 100644
index 0000000..c2a5562
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-dns325.dts
@@ -0,0 +1,59 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+	model = "D-Link DNS-325 NAS (Rev A1)";
+	compatible = "dlink,dns-325-a1", "dlink,dns-325", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x10000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8 earlyprintk";
+	};
+
+	ocp@f1000000 {
+		serial@12000 {
+			clock-frequency = <200000000>;
+			status = "okay";
+		};
+
+		nand@3000000 {
+			status = "okay";
+
+			partition@0 {
+				label = "u-boot";
+				reg = <0x0000000 0x100000>;
+				read-only;
+			};
+
+			partition@100000 {
+				label = "uImage";
+				reg = <0x0100000 0x500000>;
+			};
+
+			partition@600000 {
+				label = "ramdisk";
+				reg = <0x0600000 0x500000>;
+			};
+
+			partition@b00000 {
+				label = "image";
+				reg = <0x0b00000 0x6600000>;
+			};
+
+			partition@7100000 {
+				label = "mini firmware";
+				reg = <0x7100000 0xa00000>;
+			};
+
+			partition@7b00000 {
+				label = "config";
+				reg = <0x7b00000 0x500000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/kirkwood-ib62x0.dts b/arch/arm/boot/dts/kirkwood-ib62x0.dts
new file mode 100644
index 0000000..ada0f0c
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ib62x0.dts
@@ -0,0 +1,44 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+	model = "RaidSonic ICY BOX IB-NAS62x0 (Rev B)";
+	compatible = "raidsonic,ib-nas6210-b", "raidsonic,ib-nas6220-b", "raidsonic,ib-nas6210", "raidsonic,ib-nas6220", "raidsonic,ib-nas62x0",  "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x10000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8 earlyprintk";
+	};
+
+	ocp@f1000000 {
+		serial@12000 {
+			clock-frequency = <200000000>;
+			status = "okay";
+		};
+
+		nand@3000000 {
+			status = "okay";
+
+			partition@0 {
+				label = "u-boot";
+				reg = <0x0000000 0x100000>;
+			};
+
+			partition@100000 {
+				label = "uImage";
+				reg = <0x0100000 0x600000>;
+			};
+
+			partition@700000 {
+				label = "root";
+				reg = <0x0700000 0xf900000>;
+			};
+
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/kirkwood-iconnect.dts b/arch/arm/boot/dts/kirkwood-iconnect.dts
new file mode 100644
index 0000000..1ba75d4
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-iconnect.dts
@@ -0,0 +1,26 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+	model = "Iomega Iconnect";
+	compatible = "iom,iconnect-1.1", "iom,iconnect", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x10000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8 earlyprintk mtdparts=orion_nand:0xc0000@0x0(uboot),0x20000@0xa0000(env),0x300000@0x100000(zImage),0x300000@0x540000(initrd),0x1f400000@0x980000(boot)";
+		linux,initrd-start = <0x4500040>;
+		linux,initrd-end   = <0x4800000>;
+	};
+
+	ocp@f1000000 {
+		serial@12000 {
+			clock-frequency = <200000000>;
+			status = "ok";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
index 3474ef89..926528b 100644
--- a/arch/arm/boot/dts/kirkwood.dtsi
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -5,7 +5,7 @@
 
 	ocp@f1000000 {
 		compatible = "simple-bus";
-		ranges = <0 0xf1000000 0x1000000>;
+		ranges = <0 0xf1000000 0x4000000>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
@@ -32,5 +32,18 @@
 			reg = <0x10300 0x20>;
 			interrupts = <53>;
 		};
+
+		nand@3000000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			cle = <0>;
+			ale = <1>;
+			bank-width = <1>;
+			compatible = "mrvl,orion-nand";
+			reg = <0x3000000 0x400>;
+			chip-delay = <25>;
+			/* set partition map and/or chip-delay in board dts */
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/kizbox.dts b/arch/arm/boot/dts/kizbox.dts
new file mode 100644
index 0000000..e8814fe
--- /dev/null
+++ b/arch/arm/boot/dts/kizbox.dts
@@ -0,0 +1,138 @@
+/*
+ * kizbox.dts - Device Tree file for Overkiz Kizbox board
+ *
+ * Copyright (C) 2012 Boris BREZILLON <linux-arm@overkiz.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9g20.dtsi"
+
+/ {
+
+	model = "Overkiz kizbox";
+	compatible = "overkiz,kizbox", "atmel,at91sam9g20", "atmel,at91sam9";
+
+	chosen {
+		bootargs = "panic=5 ubi.mtd=1 rootfstype=ubifs root=ubi0:root";
+	};
+
+	memory {
+		reg = <0x20000000 0x2000000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <18432000>;
+		};
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@fffff200 {
+				status = "okay";
+			};
+
+			usart0: serial@fffb0000 {
+				status = "okay";
+			};
+
+			usart1: serial@fffb4000 {
+				status = "okay";
+			};
+
+			macb0: ethernet@fffc4000 {
+				phy-mode = "mii";
+				status = "okay";
+			};
+
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			status = "okay";
+
+			bootloaderkernel@0 {
+				label = "bootloader-kernel";
+				reg = <0x0 0xc0000>;
+			};
+
+			ubi@c0000 {
+				label = "ubi";
+				reg = <0xc0000 0x7f40000>;
+			};
+
+		};
+
+		usb0: ohci@00500000 {
+			num-ports = <1>;
+			status = "okay";
+		};
+	};
+
+	i2c@0 {
+		status = "okay";
+
+		pcf8563@51 {
+			/* nxp pcf8563 rtc */
+			compatible = "nxp,pcf8563";
+			reg = <0x51>;
+		};
+
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led1g {
+			label = "led1:green";
+			gpios = <&pioB 0 1>;
+			linux,default-trigger = "none";
+		};
+
+		led1r {
+			label = "led1:red";
+			gpios = <&pioB 1 1>;
+			linux,default-trigger = "none";
+		};
+
+		led2g {
+			label = "led2:green";
+			gpios = <&pioB 2 1>;
+			linux,default-trigger = "none";
+			default-state = "on";
+		};
+
+		led2r {
+			label = "led2:red";
+			gpios = <&pioB 3 1>;
+			linux,default-trigger = "none";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reset {
+			label = "reset";
+			gpios = <&pioB 30 1>;
+			linux,code = <0x100>;
+			gpio-key,wakeup;
+		};
+
+		mode {
+			label = "mode";
+			gpios = <&pioB 31 1>;
+			linux,code = <0x101>;
+			gpio-key,wakeup;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi
new file mode 100644
index 0000000..2d69686
--- /dev/null
+++ b/arch/arm/boot/dts/lpc32xx.dtsi
@@ -0,0 +1,292 @@
+/*
+ * NXP LPC32xx SoC
+ *
+ * Copyright 2012 Roland Stigge <stigge@antcom.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	compatible = "nxp,lpc3220";
+	interrupt-parent = <&mic>;
+
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926ejs";
+		};
+	};
+
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges = <0x20000000 0x20000000 0x30000000>;
+
+		/*
+		 * Enable either SLC or MLC
+		 */
+		slc: flash@20020000 {
+			compatible = "nxp,lpc3220-slc";
+			reg = <0x20020000 0x1000>;
+			status = "disable";
+		};
+
+		mlc: flash@200B0000 {
+			compatible = "nxp,lpc3220-mlc";
+			reg = <0x200B0000 0x1000>;
+			status = "disable";
+		};
+
+		dma@31000000 {
+			compatible = "arm,pl080", "arm,primecell";
+			reg = <0x31000000 0x1000>;
+			interrupts = <0x1c 0>;
+		};
+
+		/*
+		 * Enable either ohci or usbd (gadget)!
+		 */
+		ohci@31020000 {
+			compatible = "nxp,ohci-nxp", "usb-ohci";
+			reg = <0x31020000 0x300>;
+			interrupts = <0x3b 0>;
+			status = "disable";
+		};
+
+		usbd@31020000 {
+			compatible = "nxp,lpc3220-udc";
+			reg = <0x31020000 0x300>;
+			interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
+			status = "disable";
+		};
+
+		clcd@31040000 {
+			compatible = "arm,pl110", "arm,primecell";
+			reg = <0x31040000 0x1000>;
+			interrupts = <0x0e 0>;
+			status = "disable";
+		};
+
+		mac: ethernet@31060000 {
+			compatible = "nxp,lpc-eth";
+			reg = <0x31060000 0x1000>;
+			interrupts = <0x1d 0>;
+		};
+
+		apb {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "simple-bus";
+			ranges = <0x20000000 0x20000000 0x30000000>;
+
+			ssp0: ssp@20084000 {
+				compatible = "arm,pl022", "arm,primecell";
+				reg = <0x20084000 0x1000>;
+				interrupts = <0x14 0>;
+			};
+
+			spi1: spi@20088000 {
+				compatible = "nxp,lpc3220-spi";
+				reg = <0x20088000 0x1000>;
+			};
+
+			ssp1: ssp@2008c000 {
+				compatible = "arm,pl022", "arm,primecell";
+				reg = <0x2008c000 0x1000>;
+				interrupts = <0x15 0>;
+			};
+
+			spi2: spi@20090000 {
+				compatible = "nxp,lpc3220-spi";
+				reg = <0x20090000 0x1000>;
+			};
+
+			i2s0: i2s@20094000 {
+				compatible = "nxp,lpc3220-i2s";
+				reg = <0x20094000 0x1000>;
+			};
+
+			sd@20098000 {
+				compatible = "arm,pl180", "arm,primecell";
+				reg = <0x20098000 0x1000>;
+				interrupts = <0x0f 0>, <0x0d 0>;
+			};
+
+			i2s1: i2s@2009C000 {
+				compatible = "nxp,lpc3220-i2s";
+				reg = <0x2009C000 0x1000>;
+			};
+
+			uart3: serial@40080000 {
+				compatible = "nxp,serial";
+				reg = <0x40080000 0x1000>;
+			};
+
+			uart4: serial@40088000 {
+				compatible = "nxp,serial";
+				reg = <0x40088000 0x1000>;
+			};
+
+			uart5: serial@40090000 {
+				compatible = "nxp,serial";
+				reg = <0x40090000 0x1000>;
+			};
+
+			uart6: serial@40098000 {
+				compatible = "nxp,serial";
+				reg = <0x40098000 0x1000>;
+			};
+
+			i2c1: i2c@400A0000 {
+				compatible = "nxp,pnx-i2c";
+				reg = <0x400A0000 0x100>;
+				interrupts = <0x33 0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				pnx,timeout = <0x64>;
+			};
+
+			i2c2: i2c@400A8000 {
+				compatible = "nxp,pnx-i2c";
+				reg = <0x400A8000 0x100>;
+				interrupts = <0x32 0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				pnx,timeout = <0x64>;
+			};
+
+			i2cusb: i2c@31020300 {
+				compatible = "nxp,pnx-i2c";
+				reg = <0x31020300 0x100>;
+				interrupts = <0x3f 0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				pnx,timeout = <0x64>;
+			};
+		};
+
+		fab {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "simple-bus";
+			ranges = <0x20000000 0x20000000 0x30000000>;
+
+			/*
+			 * MIC Interrupt controller includes:
+			 *   MIC @40008000
+			 *   SIC1 @4000C000
+			 *   SIC2 @40010000
+			 */
+			mic: interrupt-controller@40008000 {
+				compatible = "nxp,lpc3220-mic";
+				interrupt-controller;
+				reg = <0x40008000 0xC000>;
+				#interrupt-cells = <2>;
+			};
+
+			uart1: serial@40014000 {
+				compatible = "nxp,serial";
+				reg = <0x40014000 0x1000>;
+			};
+
+			uart2: serial@40018000 {
+				compatible = "nxp,serial";
+				reg = <0x40018000 0x1000>;
+			};
+
+			uart7: serial@4001C000 {
+				compatible = "nxp,serial";
+				reg = <0x4001C000 0x1000>;
+			};
+
+			rtc@40024000 {
+				compatible = "nxp,lpc3220-rtc";
+				reg = <0x40024000 0x1000>;
+				interrupts = <0x34 0>;
+			};
+
+			gpio: gpio@40028000 {
+				compatible = "nxp,lpc3220-gpio";
+				reg = <0x40028000 0x1000>;
+				/* create a private address space for enumeration */
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				gpio_p0: gpio-bank@0 {
+					gpio-controller;
+					#gpio-cells = <2>;
+					reg = <0>;
+				};
+
+				gpio_p1: gpio-bank@1 {
+					gpio-controller;
+					#gpio-cells = <2>;
+					reg = <1>;
+				};
+
+				gpio_p2: gpio-bank@2 {
+					gpio-controller;
+					#gpio-cells = <2>;
+					reg = <2>;
+				};
+
+				gpio_p3: gpio-bank@3 {
+					gpio-controller;
+					#gpio-cells = <2>;
+					reg = <3>;
+				};
+
+				gpi_p3: gpio-bank@4 {
+					gpio-controller;
+					#gpio-cells = <2>;
+					reg = <4>;
+				};
+
+				gpo_p3: gpio-bank@5 {
+					gpio-controller;
+					#gpio-cells = <2>;
+					reg = <5>;
+				};
+			};
+
+			watchdog@4003C000 {
+				compatible = "nxp,pnx4008-wdt";
+				reg = <0x4003C000 0x1000>;
+			};
+
+			/*
+			 * TSC vs. ADC: Since those two share the same
+			 * hardware, you need to choose from one of the
+			 * following two and do 'status = "okay";' for one of
+			 * them
+			 */
+
+			adc@40048000 {
+				compatible = "nxp,lpc3220-adc";
+				reg = <0x40048000 0x1000>;
+				interrupts = <0x27 0>;
+				status = "disable";
+			};
+
+			tsc@40048000 {
+				compatible = "nxp,lpc3220-tsc";
+				reg = <0x40048000 0x1000>;
+				interrupts = <0x27 0>;
+				status = "disable";
+			};
+
+			key@40050000 {
+				compatible = "nxp,lpc3220-key";
+				reg = <0x40050000 0x1000>;
+			};
+
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
new file mode 100644
index 0000000..153a4b2
--- /dev/null
+++ b/arch/arm/boot/dts/mmp2-brownstone.dts
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (C) 2012 Marvell Technology Group 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
+ *  publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "mmp2.dtsi"
+
+/ {
+	model = "Marvell MMP2 Aspenite Development Board";
+	compatible = "mrvl,mmp2-brownstone", "mrvl,mmp2";
+
+	chosen {
+		bootargs = "console=ttyS2,38400 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on";
+	};
+
+	memory {
+		reg = <0x00000000 0x04000000>;
+	};
+
+	soc {
+		apb@d4000000 {
+			uart3: uart@d4018000 {
+				status = "okay";
+			};
+			twsi1: i2c@d4011000 {
+				status = "okay";
+			};
+			rtc: rtc@d4010000 {
+				status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/mmp2.dtsi b/arch/arm/boot/dts/mmp2.dtsi
new file mode 100644
index 0000000..80f74e2
--- /dev/null
+++ b/arch/arm/boot/dts/mmp2.dtsi
@@ -0,0 +1,220 @@
+/*
+ *  Copyright (C) 2012 Marvell Technology Group 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
+ *  publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+		serial3 = &uart4;
+		i2c0 = &twsi1;
+		i2c1 = &twsi2;
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		interrupt-parent = <&intc>;
+		ranges;
+
+		axi@d4200000 {	/* AXI */
+			compatible = "mrvl,axi-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4200000 0x00200000>;
+			ranges;
+
+			intc: interrupt-controller@d4282000 {
+				compatible = "mrvl,mmp2-intc";
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0xd4282000 0x1000>;
+				mrvl,intc-nr-irqs = <64>;
+			};
+
+			intcmux4@d4282150 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <4>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x150 0x4>, <0x168 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <2>;
+			};
+
+			intcmux5: interrupt-controller@d4282154 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <5>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x154 0x4>, <0x16c 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <2>;
+				mrvl,clr-mfp-irq = <1>;
+			};
+
+			intcmux9: interrupt-controller@d4282180 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <9>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x180 0x4>, <0x17c 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <3>;
+			};
+
+			intcmux17: interrupt-controller@d4282158 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <17>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x158 0x4>, <0x170 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <5>;
+			};
+
+			intcmux35: interrupt-controller@d428215c {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <35>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x15c 0x4>, <0x174 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <15>;
+			};
+
+			intcmux51: interrupt-controller@d4282160 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <51>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x160 0x4>, <0x178 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <2>;
+			};
+
+			intcmux55: interrupt-controller@d4282188 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <55>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x188 0x4>, <0x184 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <2>;
+			};
+		};
+
+		apb@d4000000 {	/* APB */
+			compatible = "mrvl,apb-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4000000 0x00200000>;
+			ranges;
+
+			timer0: timer@d4014000 {
+				compatible = "mrvl,mmp-timer";
+				reg = <0xd4014000 0x100>;
+				interrupts = <13>;
+			};
+
+			uart1: uart@d4030000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4030000 0x1000>;
+				interrupts = <27>;
+				status = "disabled";
+			};
+
+			uart2: uart@d4017000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4017000 0x1000>;
+				interrupts = <28>;
+				status = "disabled";
+			};
+
+			uart3: uart@d4018000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4018000 0x1000>;
+				interrupts = <24>;
+				status = "disabled";
+			};
+
+			uart4: uart@d4016000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4016000 0x1000>;
+				interrupts = <46>;
+				status = "disabled";
+			};
+
+			gpio@d4019000 {
+				compatible = "mrvl,mmp-gpio";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0xd4019000 0x1000>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupts = <49>;
+				interrupt-names = "gpio_mux";
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				ranges;
+
+				gcb0: gpio@d4019000 {
+					reg = <0xd4019000 0x4>;
+				};
+
+				gcb1: gpio@d4019004 {
+					reg = <0xd4019004 0x4>;
+				};
+
+				gcb2: gpio@d4019008 {
+					reg = <0xd4019008 0x4>;
+				};
+
+				gcb3: gpio@d4019100 {
+					reg = <0xd4019100 0x4>;
+				};
+
+				gcb4: gpio@d4019104 {
+					reg = <0xd4019104 0x4>;
+				};
+
+				gcb5: gpio@d4019108 {
+					reg = <0xd4019108 0x4>;
+				};
+			};
+
+			twsi1: i2c@d4011000 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4011000 0x1000>;
+				interrupts = <7>;
+				mrvl,i2c-fast-mode;
+				status = "disabled";
+			};
+
+			twsi2: i2c@d4025000 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4025000 0x1000>;
+				interrupts = <58>;
+				status = "disabled";
+			};
+
+			rtc: rtc@d4010000 {
+				compatible = "mrvl,mmp-rtc";
+				reg = <0xd4010000 0x1000>;
+				interrupts = <1 0>;
+				interrupt-names = "rtc 1Hz", "rtc alarm";
+				interrupt-parent = <&intcmux5>;
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 9f72cd4..8c756be 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -18,3 +18,52 @@
 		reg = <0x80000000 0x20000000>; /* 512 MB */
 	};
 };
+
+&i2c1 {
+	clock-frequency = <2600000>;
+
+	twl: twl@48 {
+		reg = <0x48>;
+		interrupts = <7>; /* SYS_NIRQ cascaded to intc */
+		interrupt-parent = <&intc>;
+
+		vsim: regulator@10 {
+			compatible = "ti,twl4030-vsim";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <3000000>;
+		};
+	};
+};
+
+/include/ "twl4030.dtsi"
+
+&i2c2 {
+	clock-frequency = <400000>;
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+
+	/*
+	 * Display monitor features are burnt in the EEPROM
+	 * as EDID data.
+	 */
+	eeprom@50 {
+		compatible = "ti,eeprom";
+		reg = <0x50>;
+	};
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmc1>;
+	vmmc_aux-supply = <&vsim>;
+	ti,bus-width = <8>;
+};
+
+&mmc2 {
+	status = "disable";
+};
+
+&mmc3 {
+	status = "disable";
+};
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index c612135..99474fa 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -69,6 +69,60 @@
 			reg = <0x48200000 0x1000>;
 		};
 
+		gpio1: gpio@48310000 {
+			compatible = "ti,omap3-gpio";
+			ti,hwmods = "gpio1";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio2: gpio@49050000 {
+			compatible = "ti,omap3-gpio";
+			ti,hwmods = "gpio2";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio3: gpio@49052000 {
+			compatible = "ti,omap3-gpio";
+			ti,hwmods = "gpio3";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio4: gpio@49054000 {
+			compatible = "ti,omap3-gpio";
+			ti,hwmods = "gpio4";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio5: gpio@49056000 {
+			compatible = "ti,omap3-gpio";
+			ti,hwmods = "gpio5";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio6: gpio@49058000 {
+			compatible = "ti,omap3-gpio";
+			ti,hwmods = "gpio6";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
 		uart1: serial@4806a000 {
 			compatible = "ti,omap3-uart";
 			ti,hwmods = "uart1";
@@ -113,5 +167,53 @@
 			#size-cells = <0>;
 			ti,hwmods = "i2c3";
 		};
+
+		mcspi1: spi@48098000 {
+			compatible = "ti,omap2-mcspi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "mcspi1";
+			ti,spi-num-cs = <4>;
+		};
+
+		mcspi2: spi@4809a000 {
+			compatible = "ti,omap2-mcspi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "mcspi2";
+			ti,spi-num-cs = <2>;
+		};
+
+		mcspi3: spi@480b8000 {
+			compatible = "ti,omap2-mcspi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "mcspi3";
+			ti,spi-num-cs = <2>;
+		};
+
+		mcspi4: spi@480ba000 {
+			compatible = "ti,omap2-mcspi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "mcspi4";
+			ti,spi-num-cs = <1>;
+		};
+
+		mmc1: mmc@4809c000 {
+			compatible = "ti,omap3-hsmmc";
+			ti,hwmods = "mmc1";
+			ti,dual-volt;
+		};
+
+		mmc2: mmc@480b4000 {
+			compatible = "ti,omap3-hsmmc";
+			ti,hwmods = "mmc2";
+		};
+
+		mmc3: mmc@480ad000 {
+			compatible = "ti,omap3-hsmmc";
+			ti,hwmods = "mmc3";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts
index 9755ad5..e671361 100644
--- a/arch/arm/boot/dts/omap4-panda.dts
+++ b/arch/arm/boot/dts/omap4-panda.dts
@@ -17,4 +17,75 @@
 		device_type = "memory";
 		reg = <0x80000000 0x40000000>; /* 1 GB */
 	};
+
+	leds {
+		compatible = "gpio-leds";
+		heartbeat {
+			label = "pandaboard::status1";
+			gpios = <&gpio1 7 0>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		mmc {
+			label = "pandaboard::status2";
+			gpios = <&gpio1 8 0>;
+			linux,default-trigger = "mmc0";
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+
+	twl: twl@48 {
+		reg = <0x48>;
+		/* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */
+		interrupts = <0 7 4>; /* IRQ_SYS_1N cascaded to gic */
+		interrupt-parent = <&gic>;
+	};
+};
+
+/include/ "twl6030.dtsi"
+
+&i2c2 {
+	clock-frequency = <400000>;
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+
+	/*
+	 * Display monitor features are burnt in their EEPROM as EDID data.
+	 * The EEPROM is connected as I2C slave device.
+	 */
+	eeprom@50 {
+		compatible = "ti,eeprom";
+		reg = <0x50>;
+	};
+};
+
+&i2c4 {
+	clock-frequency = <400000>;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmc>;
+	ti,bus-width = <8>;
+};
+
+&mmc2 {
+	status = "disable";
+};
+
+&mmc3 {
+	status = "disable";
+};
+
+&mmc4 {
+	status = "disable";
+};
+
+&mmc5 {
+	ti,non-removable;
+	ti,bus-width = <4>;
 };
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index 63c6b2b..e5eeb6f 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -17,4 +17,144 @@
 		device_type = "memory";
 		reg = <0x80000000 0x40000000>; /* 1 GB */
 	};
+
+	vdd_eth: fixedregulator@0 {
+		compatible = "regulator-fixed";
+		regulator-name = "VDD_ETH";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 16 0>;  /* gpio line 48 */
+		enable-active-high;
+		regulator-boot-on;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		debug0 {
+			label = "omap4:green:debug0";
+			gpios = <&gpio2 29 0>; /* 61 */
+		};
+
+		debug1 {
+			label = "omap4:green:debug1";
+			gpios = <&gpio1 30 0>; /* 30 */
+		};
+
+		debug2 {
+			label = "omap4:green:debug2";
+			gpios = <&gpio1 7 0>; /* 7 */
+		};
+
+		debug3 {
+			label = "omap4:green:debug3";
+			gpios = <&gpio1 8 0>; /* 8 */
+		};
+
+		debug4 {
+			label = "omap4:green:debug4";
+			gpios = <&gpio2 18 0>; /* 50 */
+		};
+
+		user1 {
+			label = "omap4:blue:user";
+			gpios = <&gpio6 9 0>; /* 169 */
+		};
+
+		user2 {
+			label = "omap4:red:user";
+			gpios = <&gpio6 10 0>; /* 170 */
+		};
+
+		user3 {
+			label = "omap4:green:user";
+			gpios = <&gpio5 11 0>; /* 139 */
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+
+	twl: twl@48 {
+		reg = <0x48>;
+		/* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */
+		interrupts = <0 7 4>; /* IRQ_SYS_1N cascaded to gic */
+		interrupt-parent = <&gic>;
+	};
+};
+
+/include/ "twl6030.dtsi"
+
+&i2c2 {
+	clock-frequency = <400000>;
+};
+
+&i2c3 {
+	clock-frequency = <400000>;
+
+	/*
+	 * Temperature Sensor
+	 * http://www.ti.com/lit/ds/symlink/tmp105.pdf
+	 */
+	tmp105@48 {
+		compatible = "ti,tmp105";
+		reg = <0x48>;
+	};
+
+	/*
+	 * Ambient Light Sensor
+	 * http://www.rohm.com/products/databook/sensor/pdf/bh1780gli-e.pdf
+	 */
+	bh1780@29 {
+		compatible = "rohm,bh1780";
+		reg = <0x29>;
+	};
+};
+
+&i2c4 {
+	clock-frequency = <400000>;
+
+	/*
+	 * 3-Axis Digital Compass
+	 * http://www.sparkfun.com/datasheets/Sensors/Magneto/HMC5843.pdf
+	 */
+	hmc5843@1e {
+		compatible = "honeywell,hmc5843";
+		reg = <0x1e>;
+	};
+};
+
+&mcspi1 {
+	eth@0 {
+		compatible = "ks8851";
+		spi-max-frequency = <24000000>;
+		reg = <0>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <2>; /* gpio line 34 */
+		vdd-supply = <&vdd_eth>;
+	};
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmc>;
+	ti,bus-width = <8>;
+};
+
+&mmc2 {
+	vmmc-supply = <&vaux1>;
+	ti,bus-width = <8>;
+	ti,non-removable;
+};
+
+&mmc3 {
+	status = "disable";
+};
+
+&mmc4 {
+	status = "disable";
+};
+
+&mmc5 {
+	ti,bus-width = <4>;
+	ti,non-removable;
 };
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 3d35559..359c497 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -104,6 +104,60 @@
 			      <0x48240100 0x0100>;
 		};
 
+		gpio1: gpio@4a310000 {
+			compatible = "ti,omap4-gpio";
+			ti,hwmods = "gpio1";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio2: gpio@48055000 {
+			compatible = "ti,omap4-gpio";
+			ti,hwmods = "gpio2";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio3: gpio@48057000 {
+			compatible = "ti,omap4-gpio";
+			ti,hwmods = "gpio3";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio4: gpio@48059000 {
+			compatible = "ti,omap4-gpio";
+			ti,hwmods = "gpio4";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio5: gpio@4805b000 {
+			compatible = "ti,omap4-gpio";
+			ti,hwmods = "gpio5";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		gpio6: gpio@4805d000 {
+			compatible = "ti,omap4-gpio";
+			ti,hwmods = "gpio6";
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
 		uart1: serial@4806a000 {
 			compatible = "ti,omap4-uart";
 			ti,hwmods = "uart1";
@@ -155,5 +209,68 @@
 			#size-cells = <0>;
 			ti,hwmods = "i2c4";
 		};
+
+		mcspi1: spi@48098000 {
+			compatible = "ti,omap4-mcspi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "mcspi1";
+			ti,spi-num-cs = <4>;
+		};
+
+		mcspi2: spi@4809a000 {
+			compatible = "ti,omap4-mcspi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "mcspi2";
+			ti,spi-num-cs = <2>;
+		};
+
+		mcspi3: spi@480b8000 {
+			compatible = "ti,omap4-mcspi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "mcspi3";
+			ti,spi-num-cs = <2>;
+		};
+
+		mcspi4: spi@480ba000 {
+			compatible = "ti,omap4-mcspi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "mcspi4";
+			ti,spi-num-cs = <1>;
+		};
+
+		mmc1: mmc@4809c000 {
+			compatible = "ti,omap4-hsmmc";
+			ti,hwmods = "mmc1";
+			ti,dual-volt;
+			ti,needs-special-reset;
+		};
+
+		mmc2: mmc@480b4000 {
+			compatible = "ti,omap4-hsmmc";
+			ti,hwmods = "mmc2";
+			ti,needs-special-reset;
+		};
+
+		mmc3: mmc@480ad000 {
+			compatible = "ti,omap4-hsmmc";
+			ti,hwmods = "mmc3";
+			ti,needs-special-reset;
+		};
+
+		mmc4: mmc@480d1000 {
+			compatible = "ti,omap4-hsmmc";
+			ti,hwmods = "mmc4";
+			ti,needs-special-reset;
+		};
+
+		mmc5: mmc@480d5000 {
+			compatible = "ti,omap4-hsmmc";
+			ti,hwmods = "mmc5";
+			ti,needs-special-reset;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/phy3250.dts b/arch/arm/boot/dts/phy3250.dts
new file mode 100644
index 0000000..0167e86
--- /dev/null
+++ b/arch/arm/boot/dts/phy3250.dts
@@ -0,0 +1,145 @@
+/*
+ * PHYTEC phyCORE-LPC3250 board
+ *
+ * Copyright 2012 Roland Stigge <stigge@antcom.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "lpc32xx.dtsi"
+
+/ {
+	model = "PHYTEC phyCORE-LPC3250 board based on NXP LPC3250";
+	compatible = "phytec,phy3250", "nxp,lpc3250";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	memory {
+		device_type = "memory";
+		reg = <0 0x4000000>;
+	};
+
+	ahb {
+		mac: ethernet@31060000 {
+			phy-mode = "rmii";
+			use-iram;
+		};
+
+		/* Here, choose exactly one from: ohci, usbd */
+		ohci@31020000 {
+			transceiver = <&isp1301>;
+			status = "okay";
+		};
+
+/*
+		usbd@31020000 {
+			transceiver = <&isp1301>;
+			status = "okay";
+		};
+*/
+
+		clcd@31040000 {
+			status = "okay";
+		};
+
+		/* 64MB Flash via SLC NAND controller */
+		slc: flash@20020000 {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			mtd0@00000000 {
+				label = "phy3250-boot";
+				reg = <0x00000000 0x00064000>;
+				read-only;
+			};
+
+			mtd1@00064000 {
+				label = "phy3250-uboot";
+				reg = <0x00064000 0x00190000>;
+				read-only;
+			};
+
+			mtd2@001f4000 {
+				label = "phy3250-ubt-prms";
+				reg = <0x001f4000 0x00010000>;
+			};
+
+			mtd3@00204000 {
+				label = "phy3250-kernel";
+				reg = <0x00204000 0x00400000>;
+			};
+
+			mtd4@00604000 {
+				label = "phy3250-rootfs";
+				reg = <0x00604000 0x039fc000>;
+			};
+		};
+
+		apb {
+			i2c1: i2c@400A0000 {
+				clock-frequency = <100000>;
+
+				pcf8563: rtc@51 {
+					compatible = "nxp,pcf8563";
+					reg = <0x51>;
+				};
+
+				uda1380: uda1380@18 {
+					compatible = "nxp,uda1380";
+					reg = <0x18>;
+					power-gpio = <&gpio 0x59 0>;
+					reset-gpio = <&gpio 0x51 0>;
+					dac-clk = "wspll";
+				};
+			};
+
+			i2c2: i2c@400A8000 {
+				clock-frequency = <100000>;
+			};
+
+			i2cusb: i2c@31020300 {
+				clock-frequency = <100000>;
+
+				isp1301: usb-transceiver@2c {
+					compatible = "nxp,isp1301";
+					reg = <0x2c>;
+				};
+			};
+
+			ssp0: ssp@20084000 {
+				eeprom: at25@0 {
+					compatible = "atmel,at25";
+				};
+			};
+		};
+
+		fab {
+			tsc@40048000 {
+				status = "okay";
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led0 {
+			gpios = <&gpo_p3 1 1>; /* GPO_P3 1, GPIO 80, active low */
+			linux,default-trigger = "heartbeat";
+			default-state = "off";
+		};
+
+		led1 {
+			gpios = <&gpo_p3 14 1>; /* GPO_P3 14, GPIO 93, active low */
+			linux,default-trigger = "timer";
+			default-state = "off";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
index d32d512..31a7186 100644
--- a/arch/arm/boot/dts/pxa168.dtsi
+++ b/arch/arm/boot/dts/pxa168.dtsi
@@ -18,13 +18,6 @@
 		i2c1 = &twsi2;
 	};
 
-	intc: intc-interrupt-controller@d4282000 {
-		compatible = "mrvl,mmp-intc", "mrvl,intc";
-		interrupt-controller;
-		#interrupt-cells = <1>;
-		reg = <0xd4282000 0x1000>;
-	};
-
 	soc {
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -32,6 +25,23 @@
 		interrupt-parent = <&intc>;
 		ranges;
 
+		axi@d4200000 {	/* AXI */
+			compatible = "mrvl,axi-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4200000 0x00200000>;
+			ranges;
+
+			intc: interrupt-controller@d4282000 {
+				compatible = "mrvl,mmp-intc";
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0xd4282000 0x1000>;
+				mrvl,intc-nr-irqs = <64>;
+			};
+
+		};
+
 		apb@d4000000 {	/* APB */
 			compatible = "mrvl,apb-bus", "simple-bus";
 			#address-cells = <1>;
@@ -39,40 +49,65 @@
 			reg = <0xd4000000 0x00200000>;
 			ranges;
 
+			timer0: timer@d4014000 {
+				compatible = "mrvl,mmp-timer";
+				reg = <0xd4014000 0x100>;
+				interrupts = <13>;
+			};
+
 			uart1: uart@d4017000 {
-				compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+				compatible = "mrvl,mmp-uart";
 				reg = <0xd4017000 0x1000>;
 				interrupts = <27>;
 				status = "disabled";
 			};
 
 			uart2: uart@d4018000 {
-				compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+				compatible = "mrvl,mmp-uart";
 				reg = <0xd4018000 0x1000>;
 				interrupts = <28>;
 				status = "disabled";
 			};
 
 			uart3: uart@d4026000 {
-				compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+				compatible = "mrvl,mmp-uart";
 				reg = <0xd4026000 0x1000>;
 				interrupts = <29>;
 				status = "disabled";
 			};
 
-			gpio: gpio@d4019000 {
-				compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+			gpio@d4019000 {
+				compatible = "mrvl,mmp-gpio";
+				#address-cells = <1>;
+				#size-cells = <1>;
 				reg = <0xd4019000 0x1000>;
+				gpio-controller;
+				#gpio-cells = <2>;
 				interrupts = <49>;
 				interrupt-names = "gpio_mux";
-				gpio-controller;
-				#gpio-cells = <1>;
 				interrupt-controller;
 				#interrupt-cells = <1>;
+				ranges;
+
+				gcb0: gpio@d4019000 {
+					reg = <0xd4019000 0x4>;
+				};
+
+				gcb1: gpio@d4019004 {
+					reg = <0xd4019004 0x4>;
+				};
+
+				gcb2: gpio@d4019008 {
+					reg = <0xd4019008 0x4>;
+				};
+
+				gcb3: gpio@d4019100 {
+					reg = <0xd4019100 0x4>;
+				};
 			};
 
 			twsi1: i2c@d4011000 {
-				compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+				compatible = "mrvl,mmp-twsi";
 				reg = <0xd4011000 0x1000>;
 				interrupts = <7>;
 				mrvl,i2c-fast-mode;
@@ -80,7 +115,7 @@
 			};
 
 			twsi2: i2c@d4025000 {
-				compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+				compatible = "mrvl,mmp-twsi";
 				reg = <0xd4025000 0x1000>;
 				interrupts = <58>;
 				status = "disabled";
diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
new file mode 100644
index 0000000..e92be5a
--- /dev/null
+++ b/arch/arm/boot/dts/pxa910-dkb.dts
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (C) 2012 Marvell Technology Group 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
+ *  publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "pxa910.dtsi"
+
+/ {
+	model = "Marvell PXA910 DKB Development Board";
+	compatible = "mrvl,pxa910-dkb", "mrvl,pxa910";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on";
+	};
+
+	memory {
+		reg = <0x00000000 0x10000000>;
+	};
+
+	soc {
+		apb@d4000000 {
+			uart1: uart@d4017000 {
+				status = "okay";
+			};
+			twsi1: i2c@d4011000 {
+				status = "okay";
+			};
+			rtc: rtc@d4010000 {
+				status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
new file mode 100644
index 0000000..aebf32d
--- /dev/null
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -0,0 +1,140 @@
+/*
+ *  Copyright (C) 2012 Marvell Technology Group 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
+ *  publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+		i2c0 = &twsi1;
+		i2c1 = &twsi2;
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		interrupt-parent = <&intc>;
+		ranges;
+
+		axi@d4200000 {	/* AXI */
+			compatible = "mrvl,axi-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4200000 0x00200000>;
+			ranges;
+
+			intc: interrupt-controller@d4282000 {
+				compatible = "mrvl,mmp-intc";
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0xd4282000 0x1000>;
+				mrvl,intc-nr-irqs = <64>;
+			};
+
+		};
+
+		apb@d4000000 {	/* APB */
+			compatible = "mrvl,apb-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4000000 0x00200000>;
+			ranges;
+
+			timer0: timer@d4014000 {
+				compatible = "mrvl,mmp-timer";
+				reg = <0xd4014000 0x100>;
+				interrupts = <13>;
+			};
+
+			timer1: timer@d4016000 {
+				compatible = "mrvl,mmp-timer";
+				reg = <0xd4016000 0x100>;
+				interrupts = <29>;
+				status = "disabled";
+			};
+
+			uart1: uart@d4017000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4017000 0x1000>;
+				interrupts = <27>;
+				status = "disabled";
+			};
+
+			uart2: uart@d4018000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4018000 0x1000>;
+				interrupts = <28>;
+				status = "disabled";
+			};
+
+			uart3: uart@d4036000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4036000 0x1000>;
+				interrupts = <59>;
+				status = "disabled";
+			};
+
+			gpio@d4019000 {
+				compatible = "mrvl,mmp-gpio";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0xd4019000 0x1000>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupts = <49>;
+				interrupt-names = "gpio_mux";
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				ranges;
+
+				gcb0: gpio@d4019000 {
+					reg = <0xd4019000 0x4>;
+				};
+
+				gcb1: gpio@d4019004 {
+					reg = <0xd4019004 0x4>;
+				};
+
+				gcb2: gpio@d4019008 {
+					reg = <0xd4019008 0x4>;
+				};
+
+				gcb3: gpio@d4019100 {
+					reg = <0xd4019100 0x4>;
+				};
+			};
+
+			twsi1: i2c@d4011000 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4011000 0x1000>;
+				interrupts = <7>;
+				mrvl,i2c-fast-mode;
+				status = "disabled";
+			};
+
+			twsi2: i2c@d4037000 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4037000 0x1000>;
+				interrupts = <54>;
+				status = "disabled";
+			};
+
+			rtc: rtc@d4010000 {
+				compatible = "mrvl,mmp-rtc";
+				reg = <0xd4010000 0x1000>;
+				interrupts = <5 6>;
+				interrupt-names = "rtc 1Hz", "rtc alarm";
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
new file mode 100644
index 0000000..a7505a9
--- /dev/null
+++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -0,0 +1,22 @@
+/*
+ * Device Tree Source for the armadillo 800 eva board
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "armadillo 800 eva";
+	compatible = "renesas,armadillo800eva";
+
+	memory {
+		device_type = "memory";
+		reg = <0x40000000 0x20000000>;
+	};
+};
diff --git a/arch/arm/boot/dts/sh7372.dtsi b/arch/arm/boot/dts/sh7372.dtsi
new file mode 100644
index 0000000..677fc60
--- /dev/null
+++ b/arch/arm/boot/dts/sh7372.dtsi
@@ -0,0 +1,21 @@
+/*
+ * Device Tree Source for the sh7372 SoC
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+	compatible = "renesas,sh7372";
+
+	cpus {
+		cpu@0 {
+			compatible = "arm,cortex-a8";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/sh73a0-kzm9g.dts b/arch/arm/boot/dts/sh73a0-kzm9g.dts
new file mode 100644
index 0000000..bcb9119
--- /dev/null
+++ b/arch/arm/boot/dts/sh73a0-kzm9g.dts
@@ -0,0 +1,22 @@
+/*
+ * Device Tree Source for the KZM-A9-GT board
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "KZM-A9-GT";
+	compatible = "renesas,kzm9g", "renesas,sh73a0";
+
+	memory {
+		device_type = "memory";
+		reg = <0x41000000 0x1e800000>;
+	};
+};
diff --git a/arch/arm/boot/dts/snowball.dts b/arch/arm/boot/dts/snowball.dts
index 359c6d6..d99dc04 100644
--- a/arch/arm/boot/dts/snowball.dts
+++ b/arch/arm/boot/dts/snowball.dts
@@ -30,35 +30,35 @@
 			wakeup = <1>;
 			linux,code = <2>;
 			label = "userpb";
-			gpios = <&gpio1 0>;
+			gpios = <&gpio1 0 0>;
 		};
 		button@2 {
 			debounce_interval = <50>;
 			wakeup = <1>;
 			linux,code = <3>;
-			label = "userpb";
-			gpios = <&gpio4 23>;
+			label = "extkb1";
+			gpios = <&gpio4 23 0>;
 		};
 		button@3 {
 			debounce_interval = <50>;
 			wakeup = <1>;
 			linux,code = <4>;
-			label = "userpb";
-			gpios = <&gpio4 23>;
+			label = "extkb2";
+			gpios = <&gpio4 24 0>;
 		};
 		button@4 {
 			debounce_interval = <50>;
 			wakeup = <1>;
 			linux,code = <5>;
-			label = "userpb";
-			gpios = <&gpio5 1>;
+			label = "extkb3";
+			gpios = <&gpio5 1 0>;
 		};
 		button@5 {
 			debounce_interval = <50>;
 			wakeup = <1>;
 			linux,code = <6>;
-			label = "userpb";
-			gpios = <&gpio5 2>;
+			label = "extkb4";
+			gpios = <&gpio5 2 0>;
 		};
 	};
 
@@ -73,17 +73,19 @@
 	soc-u9500 {
 
 		external-bus@50000000 {
-			compatible = "simple-bus";
-			reg = <0x50000000 0x10000000>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges;
+			status = "okay";
 
-			ethernet@50000000 {
-				compatible = "smsc,9111";
-				reg = <0x50000000 0x10000>;
-				interrupts = <12>;
+			ethernet@0 {
+				compatible = "smsc,lan9115";
+				reg = <0 0x10000>;
+				interrupts = <12 0x1>;
 				interrupt-parent = <&gpio4>;
+
+				reg-shift = <1>;
+				reg-io-width = <2>;
+				smsc,force-internal-phy;
+				smsc,irq-active-high;
+				smsc,irq-push-pull;
 			};
 		};
 
diff --git a/arch/arm/boot/dts/spear300-evb.dts b/arch/arm/boot/dts/spear300-evb.dts
new file mode 100644
index 0000000..910e264
--- /dev/null
+++ b/arch/arm/boot/dts/spear300-evb.dts
@@ -0,0 +1,221 @@
+/*
+ * DTS file for SPEAr300 Evaluation Baord
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "spear300.dtsi"
+
+/ {
+	model = "ST SPEAr300 Evaluation Board";
+	compatible = "st,spear300-evb", "st,spear300";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	memory {
+		reg = <0 0x40000000>;
+	};
+
+	ahb {
+		pinmux@99000000 {
+			st,pinmux-mode = <2>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&state_default>;
+
+			state_default: pinmux {
+				i2c0 {
+					st,pins = "i2c0_grp";
+					st,function = "i2c0";
+				};
+				ssp0 {
+					st,pins = "ssp0_grp";
+					st,function = "ssp0";
+				};
+				mii0 {
+					st,pins = "mii0_grp";
+					st,function = "mii0";
+				};
+				uart0 {
+					st,pins = "uart0_grp";
+					st,function = "uart0";
+				};
+				clcd {
+					st,pins = "clcd_pfmode_grp";
+					st,function = "clcd";
+				};
+				sdhci {
+					st,pins = "sdhci_4bit_grp";
+					st,function = "sdhci";
+				};
+				gpio1 {
+					st,pins = "gpio1_4_to_7_grp",
+						"gpio1_0_to_3_grp";
+					st,function = "gpio1";
+				};
+			};
+		};
+
+		clcd@60000000 {
+			status = "okay";
+		};
+
+		dma@fc400000 {
+			status = "okay";
+		};
+
+		fsmc: flash@94000000 {
+			status = "okay";
+		};
+
+		gmac: eth@e0800000 {
+			status = "okay";
+		};
+
+		sdhci@70000000 {
+			int-gpio = <&gpio1 0 0>;
+			power-gpio = <&gpio1 2 1>;
+			status = "okay";
+		};
+
+		smi: flash@fc000000 {
+			status = "okay";
+		};
+
+		spi0: spi@d0100000 {
+			status = "okay";
+		};
+
+		ehci@e1800000 {
+			status = "okay";
+		};
+
+		ohci@e1900000 {
+			status = "okay";
+		};
+
+		ohci@e2100000 {
+			status = "okay";
+		};
+
+		apb {
+			gpio0: gpio@fc980000 {
+			       status = "okay";
+			};
+
+			gpio1: gpio@a9000000 {
+			       status = "okay";
+			};
+
+			i2c0: i2c@d0180000 {
+			       status = "okay";
+			};
+
+			kbd@a0000000 {
+				linux,keymap = < 0x00000001
+						 0x00010002
+						 0x00020003
+						 0x00030004
+						 0x00040005
+						 0x00050006
+						 0x00060007
+						 0x00070008
+						 0x00080009
+						 0x0100000a
+						 0x0101000c
+						 0x0102000d
+						 0x0103000e
+						 0x0104000f
+						 0x01050010
+						 0x01060011
+						 0x01070012
+						 0x01080013
+						 0x02000014
+						 0x02010015
+						 0x02020016
+						 0x02030017
+						 0x02040018
+						 0x02050019
+						 0x0206001a
+						 0x0207001b
+						 0x0208001c
+						 0x0300001d
+						 0x0301001e
+						 0x0302001f
+						 0x03030020
+						 0x03040021
+						 0x03050022
+						 0x03060023
+						 0x03070024
+						 0x03080025
+						 0x04000026
+						 0x04010027
+						 0x04020028
+						 0x04030029
+						 0x0404002a
+						 0x0405002b
+						 0x0406002c
+						 0x0407002d
+						 0x0408002e
+						 0x0500002f
+						 0x05010030
+						 0x05020031
+						 0x05030032
+						 0x05040033
+						 0x05050034
+						 0x05060035
+						 0x05070036
+						 0x05080037
+						 0x06000038
+						 0x06010039
+						 0x0602003a
+						 0x0603003b
+						 0x0604003c
+						 0x0605003d
+						 0x0606003e
+						 0x0607003f
+						 0x06080040
+						 0x07000041
+						 0x07010042
+						 0x07020043
+						 0x07030044
+						 0x07040045
+						 0x07050046
+						 0x07060047
+						 0x07070048
+						 0x07080049
+						 0x0800004a
+						 0x0801004b
+						 0x0802004c
+						 0x0803004d
+						 0x0804004e
+						 0x0805004f
+						 0x08060050
+						 0x08070051
+						 0x08080052 >;
+			       autorepeat;
+			       st,mode = <0>;
+			       status = "okay";
+			};
+
+			rtc@fc900000 {
+			       status = "okay";
+			};
+
+			serial@d0000000 {
+			       status = "okay";
+			};
+
+			wdt@fc880000 {
+			       status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/spear300.dtsi b/arch/arm/boot/dts/spear300.dtsi
new file mode 100644
index 0000000..01c5e35
--- /dev/null
+++ b/arch/arm/boot/dts/spear300.dtsi
@@ -0,0 +1,77 @@
+/*
+ * DTS file for SPEAr300 SoC
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "spear3xx.dtsi"
+
+/ {
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges = <0x60000000 0x60000000 0x50000000
+			  0xd0000000 0xd0000000 0x30000000>;
+
+		pinmux@99000000 {
+			compatible = "st,spear300-pinmux";
+			reg = <0x99000000 0x1000>;
+		};
+
+		clcd@60000000 {
+			compatible = "arm,clcd-pl110", "arm,primecell";
+			reg = <0x60000000 0x1000>;
+			interrupts = <30>;
+			status = "disabled";
+		};
+
+		fsmc: flash@94000000 {
+			compatible = "st,spear600-fsmc-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x94000000 0x1000	/* FSMC Register */
+			       0x80000000 0x0010>;	/* NAND Base */
+			reg-names = "fsmc_regs", "nand_data";
+			st,ale-off = <0x20000>;
+			st,cle-off = <0x10000>;
+			status = "disabled";
+		};
+
+		sdhci@70000000 {
+			compatible = "st,sdhci-spear";
+			reg = <0x70000000 0x100>;
+			interrupts = <1>;
+			status = "disabled";
+		};
+
+		apb {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "simple-bus";
+			ranges = <0xa0000000 0xa0000000 0x10000000
+				  0xd0000000 0xd0000000 0x30000000>;
+
+			gpio1: gpio@a9000000 {
+				#gpio-cells = <2>;
+				compatible = "arm,pl061", "arm,primecell";
+				gpio-controller;
+				reg = <0xa9000000 0x1000>;
+				status = "disabled";
+			};
+
+			kbd@a0000000 {
+				compatible = "st,spear300-kbd";
+				reg = <0xa0000000 0x1000>;
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/spear310-evb.dts b/arch/arm/boot/dts/spear310-evb.dts
new file mode 100644
index 0000000..6d95317
--- /dev/null
+++ b/arch/arm/boot/dts/spear310-evb.dts
@@ -0,0 +1,172 @@
+/*
+ * DTS file for SPEAr310 Evaluation Baord
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "spear310.dtsi"
+
+/ {
+	model = "ST SPEAr310 Evaluation Board";
+	compatible = "st,spear310-evb", "st,spear310";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	memory {
+		reg = <0 0x40000000>;
+	};
+
+	ahb {
+		pinmux@b4000000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&state_default>;
+
+			state_default: pinmux {
+				gpio0 {
+					st,pins = "gpio0_pin0_grp",
+						"gpio0_pin1_grp",
+						"gpio0_pin2_grp",
+						"gpio0_pin3_grp",
+						"gpio0_pin4_grp",
+						"gpio0_pin5_grp";
+					st,function = "gpio0";
+				};
+				i2c0 {
+					st,pins = "i2c0_grp";
+					st,function = "i2c0";
+				};
+				mii0 {
+					st,pins = "mii0_grp";
+					st,function = "mii0";
+				};
+				ssp0 {
+					st,pins = "ssp0_grp";
+					st,function = "ssp0";
+				};
+				uart0 {
+					st,pins = "uart0_grp";
+					st,function = "uart0";
+				};
+				emi {
+					st,pins = "emi_cs_0_to_5_grp";
+					st,function = "emi";
+				};
+				fsmc {
+					st,pins = "fsmc_grp";
+					st,function = "fsmc";
+				};
+				uart1 {
+					st,pins = "uart1_grp";
+					st,function = "uart1";
+				};
+				uart2 {
+					st,pins = "uart2_grp";
+					st,function = "uart2";
+				};
+				uart3 {
+					st,pins = "uart3_grp";
+					st,function = "uart3";
+				};
+				uart4 {
+					st,pins = "uart4_grp";
+					st,function = "uart4";
+				};
+				uart5 {
+					st,pins = "uart5_grp";
+					st,function = "uart5";
+				};
+			};
+		};
+
+		dma@fc400000 {
+			status = "okay";
+		};
+
+		fsmc: flash@44000000 {
+			status = "okay";
+		};
+
+		gmac: eth@e0800000 {
+			status = "okay";
+		};
+
+		smi: flash@fc000000 {
+			status = "okay";
+			clock-rate=<50000000>;
+
+			flash@f8000000 {
+				label = "m25p64";
+				reg = <0xf8000000 0x800000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				st,smi-fast-mode;
+			};
+		};
+
+		spi0: spi@d0100000 {
+			status = "okay";
+		};
+
+		ehci@e1800000 {
+			status = "okay";
+		};
+
+		ohci@e1900000 {
+			status = "okay";
+		};
+
+		ohci@e2100000 {
+			status = "okay";
+		};
+
+		apb {
+			gpio0: gpio@fc980000 {
+			       status = "okay";
+			};
+
+			i2c0: i2c@d0180000 {
+			       status = "okay";
+			};
+
+			rtc@fc900000 {
+			       status = "okay";
+			};
+
+			serial@d0000000 {
+			       status = "okay";
+			};
+
+			serial@b2000000 {
+			       status = "okay";
+			};
+
+			serial@b2080000 {
+			       status = "okay";
+			};
+
+			serial@b2100000 {
+			       status = "okay";
+			};
+
+			serial@b2180000 {
+			       status = "okay";
+			};
+
+			serial@b2200000 {
+			       status = "okay";
+			};
+
+			wdt@fc880000 {
+			       status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/spear310.dtsi b/arch/arm/boot/dts/spear310.dtsi
new file mode 100644
index 0000000..e47081c
--- /dev/null
+++ b/arch/arm/boot/dts/spear310.dtsi
@@ -0,0 +1,80 @@
+/*
+ * DTS file for SPEAr310 SoC
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "spear3xx.dtsi"
+
+/ {
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges = <0x40000000 0x40000000 0x10000000
+			  0xb0000000 0xb0000000 0x10000000
+			  0xd0000000 0xd0000000 0x30000000>;
+
+		pinmux@b4000000 {
+			compatible = "st,spear310-pinmux";
+			reg = <0xb4000000 0x1000>;
+		};
+
+		fsmc: flash@44000000 {
+			compatible = "st,spear600-fsmc-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x44000000 0x1000	/* FSMC Register */
+			       0x40000000 0x0010>;	/* NAND Base */
+			reg-names = "fsmc_regs", "nand_data";
+			st,ale-off = <0x10000>;
+			st,cle-off = <0x20000>;
+			status = "disabled";
+		};
+
+		apb {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "simple-bus";
+			ranges = <0xb0000000 0xb0000000 0x10000000
+				  0xd0000000 0xd0000000 0x30000000>;
+
+			serial@b2000000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xb2000000 0x1000>;
+				status = "disabled";
+			};
+
+			serial@b2080000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xb2080000 0x1000>;
+				status = "disabled";
+			};
+
+			serial@b2100000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xb2100000 0x1000>;
+				status = "disabled";
+			};
+
+			serial@b2180000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xb2180000 0x1000>;
+				status = "disabled";
+			};
+
+			serial@b2200000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xb2200000 0x1000>;
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts
new file mode 100644
index 0000000..0c6463b
--- /dev/null
+++ b/arch/arm/boot/dts/spear320-evb.dts
@@ -0,0 +1,173 @@
+/*
+ * DTS file for SPEAr320 Evaluation Baord
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "spear320.dtsi"
+
+/ {
+	model = "ST SPEAr300 Evaluation Board";
+	compatible = "st,spear300-evb", "st,spear300";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	memory {
+		reg = <0 0x40000000>;
+	};
+
+	ahb {
+		pinmux@b3000000 {
+			st,pinmux-mode = <3>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&state_default>;
+
+			state_default: pinmux {
+				i2c0 {
+					st,pins = "i2c0_grp";
+					st,function = "i2c0";
+				};
+				mii0 {
+					st,pins = "mii0_grp";
+					st,function = "mii0";
+				};
+				ssp0 {
+					st,pins = "ssp0_grp";
+					st,function = "ssp0";
+				};
+				uart0 {
+					st,pins = "uart0_grp";
+					st,function = "uart0";
+				};
+				sdhci {
+					st,pins = "sdhci_cd_51_grp";
+					st,function = "sdhci";
+				};
+				i2s {
+					st,pins = "i2s_grp";
+					st,function = "i2s";
+				};
+				uart1 {
+					st,pins = "uart1_grp";
+					st,function = "uart1";
+				};
+				uart2 {
+					st,pins = "uart2_grp";
+					st,function = "uart2";
+				};
+				can0 {
+					st,pins = "can0_grp";
+					st,function = "can0";
+				};
+				can1 {
+					st,pins = "can1_grp";
+					st,function = "can1";
+				};
+				mii2 {
+					st,pins = "mii2_grp";
+					st,function = "mii2";
+				};
+				pwm0_1 {
+					st,pins = "pwm0_1_pin_14_15_grp";
+					st,function = "pwm0_1";
+				};
+				pwm2 {
+					st,pins = "pwm2_pin_13_grp";
+					st,function = "pwm2";
+				};
+			};
+		};
+
+		clcd@90000000 {
+			status = "okay";
+		};
+
+		dma@fc400000 {
+			status = "okay";
+		};
+
+		fsmc: flash@4c000000 {
+			status = "okay";
+		};
+
+		gmac: eth@e0800000 {
+			status = "okay";
+		};
+
+		sdhci@70000000 {
+			power-gpio = <&gpio0 2 1>;
+			power_always_enb;
+			status = "okay";
+		};
+
+		smi: flash@fc000000 {
+			status = "okay";
+		};
+
+		spi0: spi@d0100000 {
+			status = "okay";
+		};
+
+		spi1: spi@a5000000 {
+			status = "okay";
+		};
+
+		spi2: spi@a6000000 {
+			status = "okay";
+		};
+
+		ehci@e1800000 {
+			status = "okay";
+		};
+
+		ohci@e1900000 {
+			status = "okay";
+		};
+
+		ohci@e2100000 {
+			status = "okay";
+		};
+
+		apb {
+			gpio0: gpio@fc980000 {
+			       status = "okay";
+			};
+
+			i2c0: i2c@d0180000 {
+			       status = "okay";
+			};
+
+			i2c1: i2c@a7000000 {
+			       status = "okay";
+			};
+
+			rtc@fc900000 {
+			       status = "okay";
+			};
+
+			serial@d0000000 {
+			       status = "okay";
+			};
+
+			serial@a3000000 {
+			       status = "okay";
+			};
+
+			serial@a4000000 {
+			       status = "okay";
+			};
+
+			wdt@fc880000 {
+			       status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi
new file mode 100644
index 0000000..5372ca3
--- /dev/null
+++ b/arch/arm/boot/dts/spear320.dtsi
@@ -0,0 +1,95 @@
+/*
+ * DTS file for SPEAr320 SoC
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "spear3xx.dtsi"
+
+/ {
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges = <0x40000000 0x40000000 0x80000000
+			  0xd0000000 0xd0000000 0x30000000>;
+
+		pinmux@b3000000 {
+			compatible = "st,spear320-pinmux";
+			reg = <0xb3000000 0x1000>;
+		};
+
+		clcd@90000000 {
+			compatible = "arm,clcd-pl110", "arm,primecell";
+			reg = <0x90000000 0x1000>;
+			interrupts = <33>;
+			status = "disabled";
+		};
+
+		fsmc: flash@4c000000 {
+			compatible = "st,spear600-fsmc-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x4c000000 0x1000	/* FSMC Register */
+			       0x50000000 0x0010>;	/* NAND Base */
+			reg-names = "fsmc_regs", "nand_data";
+			st,ale-off = <0x20000>;
+			st,cle-off = <0x10000>;
+			status = "disabled";
+		};
+
+		sdhci@70000000 {
+			compatible = "st,sdhci-spear";
+			reg = <0x70000000 0x100>;
+			interrupts = <29>;
+			status = "disabled";
+		};
+
+		spi1: spi@a5000000 {
+			compatible = "arm,pl022", "arm,primecell";
+			reg = <0xa5000000 0x1000>;
+			status = "disabled";
+		};
+
+		spi2: spi@a6000000 {
+			compatible = "arm,pl022", "arm,primecell";
+			reg = <0xa6000000 0x1000>;
+			status = "disabled";
+		};
+
+		apb {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "simple-bus";
+			ranges = <0xa0000000 0xa0000000 0x10000000
+				  0xd0000000 0xd0000000 0x30000000>;
+
+			i2c1: i2c@a7000000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "snps,designware-i2c";
+				reg = <0xa7000000 0x1000>;
+				status = "disabled";
+			};
+
+			serial@a3000000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xa3000000 0x1000>;
+				status = "disabled";
+			};
+
+			serial@a4000000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xa4000000 0x1000>;
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/spear3xx.dtsi b/arch/arm/boot/dts/spear3xx.dtsi
new file mode 100644
index 0000000..0ae7c8e
--- /dev/null
+++ b/arch/arm/boot/dts/spear3xx.dtsi
@@ -0,0 +1,144 @@
+/*
+ * DTS file for all SPEAr3xx SoCs
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	interrupt-parent = <&vic>;
+
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926ejs";
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0 0x40000000>;
+	};
+
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges = <0xd0000000 0xd0000000 0x30000000>;
+
+		vic: interrupt-controller@f1100000 {
+			compatible = "arm,pl190-vic";
+			interrupt-controller;
+			reg = <0xf1100000 0x1000>;
+			#interrupt-cells = <1>;
+		};
+
+		dma@fc400000 {
+			compatible = "arm,pl080", "arm,primecell";
+			reg = <0xfc400000 0x1000>;
+			interrupt-parent = <&vic>;
+			interrupts = <8>;
+			status = "disabled";
+		};
+
+		gmac: eth@e0800000 {
+			compatible = "st,spear600-gmac";
+			reg = <0xe0800000 0x8000>;
+			interrupts = <23 22>;
+			interrupt-names = "macirq", "eth_wake_irq";
+			status = "disabled";
+		};
+
+		smi: flash@fc000000 {
+			compatible = "st,spear600-smi";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xfc000000 0x1000>;
+			interrupts = <9>;
+			status = "disabled";
+		};
+
+		spi0: spi@d0100000 {
+			compatible = "arm,pl022", "arm,primecell";
+			reg = <0xd0100000 0x1000>;
+			interrupts = <20>;
+			status = "disabled";
+		};
+
+		ehci@e1800000 {
+			compatible = "st,spear600-ehci", "usb-ehci";
+			reg = <0xe1800000 0x1000>;
+			interrupts = <26>;
+			status = "disabled";
+		};
+
+		ohci@e1900000 {
+			compatible = "st,spear600-ohci", "usb-ohci";
+			reg = <0xe1900000 0x1000>;
+			interrupts = <25>;
+			status = "disabled";
+		};
+
+		ohci@e2100000 {
+			compatible = "st,spear600-ohci", "usb-ohci";
+			reg = <0xe2100000 0x1000>;
+			interrupts = <27>;
+			status = "disabled";
+		};
+
+		apb {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "simple-bus";
+			ranges = <0xd0000000 0xd0000000 0x30000000>;
+
+			gpio0: gpio@fc980000 {
+				compatible = "arm,pl061", "arm,primecell";
+				reg = <0xfc980000 0x1000>;
+				interrupts = <11>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				status = "disabled";
+			};
+
+			i2c0: i2c@d0180000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "snps,designware-i2c";
+				reg = <0xd0180000 0x1000>;
+				interrupts = <21>;
+				status = "disabled";
+			};
+
+			rtc@fc900000 {
+				compatible = "st,spear-rtc";
+				reg = <0xfc900000 0x1000>;
+				interrupts = <10>;
+				status = "disabled";
+			};
+
+			serial@d0000000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xd0000000 0x1000>;
+				interrupts = <19>;
+				status = "disabled";
+			};
+
+			wdt@fc880000 {
+				compatible = "arm,sp805", "arm,primecell";
+				reg = <0xfc880000 0x1000>;
+				interrupts = <12>;
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts
index 636292e..790a7a8 100644
--- a/arch/arm/boot/dts/spear600-evb.dts
+++ b/arch/arm/boot/dts/spear600-evb.dts
@@ -24,6 +24,10 @@
 	};
 
 	ahb {
+		dma@fc400000 {
+			status = "okay";
+		};
+
 		gmac: ethernet@e0800000 {
 			phy-mode = "gmii";
 			status = "okay";
diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi
index ebe0885..d777e3a 100644
--- a/arch/arm/boot/dts/spear600.dtsi
+++ b/arch/arm/boot/dts/spear600.dtsi
@@ -45,6 +45,14 @@
 			#interrupt-cells = <1>;
 		};
 
+		dma@fc400000 {
+			compatible = "arm,pl080", "arm,primecell";
+			reg = <0xfc400000 0x1000>;
+			interrupt-parent = <&vic1>;
+			interrupts = <10>;
+			status = "disabled";
+		};
+
 		gmac: ethernet@e0800000 {
 			compatible = "st,spear600-gmac";
 			reg = <0xe0800000 0x8000>;
diff --git a/arch/arm/boot/dts/tegra-cardhu.dts b/arch/arm/boot/dts/tegra-cardhu.dts
index ac3fb75..0a9f34a 100644
--- a/arch/arm/boot/dts/tegra-cardhu.dts
+++ b/arch/arm/boot/dts/tegra-cardhu.dts
@@ -10,6 +10,50 @@
 		reg = < 0x80000000 0x40000000 >;
 	};
 
+	pinmux@70000000 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			sdmmc1_clk_pz0 {
+				nvidia,pins = "sdmmc1_clk_pz0";
+				nvidia,function = "sdmmc1";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			sdmmc1_cmd_pz1 {
+				nvidia,pins =	"sdmmc1_cmd_pz1",
+						"sdmmc1_dat0_py7",
+						"sdmmc1_dat1_py6",
+						"sdmmc1_dat2_py5",
+						"sdmmc1_dat3_py4";
+				nvidia,function = "sdmmc1";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			sdmmc4_clk_pcc4 {
+				nvidia,pins =	"sdmmc4_clk_pcc4",
+						"sdmmc4_rst_n_pcc3";
+				nvidia,function = "sdmmc4";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			sdmmc4_dat0_paa0 {
+				nvidia,pins =	"sdmmc4_dat0_paa0",
+						"sdmmc4_dat1_paa1",
+						"sdmmc4_dat2_paa2",
+						"sdmmc4_dat3_paa3",
+						"sdmmc4_dat4_paa4",
+						"sdmmc4_dat5_paa5",
+						"sdmmc4_dat6_paa6",
+						"sdmmc4_dat7_paa7";
+				nvidia,function = "sdmmc4";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+		};
+	};
+
 	serial@70006000 {
 		clock-frequency = < 408000000 >;
 	};
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
index 6e8447d..1a0b1f1 100644
--- a/arch/arm/boot/dts/tegra-harmony.dts
+++ b/arch/arm/boot/dts/tegra-harmony.dts
@@ -10,6 +10,230 @@
 		reg = < 0x00000000 0x40000000 >;
 	};
 
+	pinmux@70000000 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata";
+				nvidia,function = "ide";
+			};
+			atb {
+				nvidia,pins = "atb", "gma", "gme";
+				nvidia,function = "sdio4";
+			};
+			atc {
+				nvidia,pins = "atc";
+				nvidia,function = "nand";
+			};
+			atd {
+				nvidia,pins = "atd", "ate", "gmb", "gmd", "gpu",
+					"spia", "spib", "spic";
+				nvidia,function = "gmi";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap2 {
+				nvidia,pins = "dap2";
+				nvidia,function = "dap2";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "i2c2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtd";
+				nvidia,function = "sdio2";
+			};
+			dtb {
+				nvidia,pins = "dtb", "dtc", "dte";
+				nvidia,function = "rsvd1";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gmc {
+				nvidia,pins = "gmc";
+				nvidia,function = "uartd";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint", "pta";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uarta";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
+					"ld3", "ld4", "ld5", "ld6", "ld7",
+					"ld8", "ld9", "ld10", "ld11", "ld12",
+					"ld13", "ld14", "ld15", "ld16", "ld17",
+					"ldc", "ldi", "lhp0", "lhp1", "lhp2",
+					"lhs", "lm0", "lm1", "lpp", "lpw0",
+					"lpw1", "lpw2", "lsc0", "lsc1", "lsck",
+					"lsda", "lsdi", "lspi", "lvp0", "lvp1",
+					"lvs";
+				nvidia,function = "displaya";
+			};
+			owc {
+				nvidia,pins = "owc", "spdi", "spdo", "uac";
+				nvidia,function = "rsvd2";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdb {
+				nvidia,pins = "sdb", "sdc", "sdd";
+				nvidia,function = "pwm";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxc {
+				nvidia,pins = "slxc", "slxd";
+				nvidia,function = "spdif";
+			};
+			spid {
+				nvidia,pins = "spid", "spie", "spif";
+				nvidia,function = "spi1";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atb", "atc", "atd", "ate",
+					"cdev1", "dap1", "dtb", "gma", "gmb",
+					"gmc", "gmd", "gme", "gpu7", "gpv",
+					"i2cp", "pta", "rm", "slxa", "slxk",
+					"spia", "spib";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_cdev2 {
+				nvidia,pins = "cdev2", "csus", "spid", "spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_crtp {
+				nvidia,pins = "crtp", "dap2", "dap3", "dap4",
+					"dtc", "dte", "dtf", "gpu", "sdio1",
+					"slxc", "slxd", "spdi", "spdo", "spig",
+					"uac", "uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_ddc {
+				nvidia,pins = "ddc", "dta", "dtd", "kbca",
+					"kbcb", "kbcc", "kbcd", "kbce", "kbcf",
+					"sdc";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+					"lpw1", "lsc1", "lsck", "lsda", "lsdi",
+					"lvp0", "owc", "sdb";
+				nvidia,tristate = <1>;
+			};
+			conf_irrx {
+				nvidia,pins = "irrx", "irtx", "sdd", "spic",
+					"spie", "spih", "uaa", "uab", "uad",
+					"uca", "ucb";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lm0", "lpp",
+					"lpw0", "lpw2", "lsc0", "lspi", "lvp1",
+					"lvs", "pmc";
+				nvidia,tristate = <0>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+		};
+	};
+
 	pmc@7000f400 {
 		nvidia,invert-interrupt;
 	};
diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts
index 6c02abb..10943fb 100644
--- a/arch/arm/boot/dts/tegra-paz00.dts
+++ b/arch/arm/boot/dts/tegra-paz00.dts
@@ -10,6 +10,226 @@
 		reg = <0x00000000 0x20000000>;
 	};
 
+	pinmux@70000000 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata", "atc", "atd", "ate",
+					"dap2", "gmb", "gmc", "gmd", "spia",
+					"spib", "spic", "spid", "spie";
+				nvidia,function = "gmi";
+			};
+			atb {
+				nvidia,pins = "atb", "gma", "gme";
+				nvidia,function = "sdio4";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "pllc_out1";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "i2c2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+				nvidia,function = "rsvd1";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gpu {
+				nvidia,pins = "gpu", "sdb", "sdd";
+				nvidia,function = "pwm";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint", "pta";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uarta";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcc", "kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			kbcb {
+				nvidia,pins = "kbcb", "kbcd";
+				nvidia,function = "sdio2";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
+					"ld3", "ld4", "ld5", "ld6", "ld7",
+					"ld8", "ld9", "ld10", "ld11", "ld12",
+					"ld13", "ld14", "ld15", "ld16", "ld17",
+					"ldc", "ldi", "lhp0", "lhp1", "lhp2",
+					"lhs", "lm0", "lm1", "lpp", "lpw0",
+					"lpw1", "lpw2", "lsc0", "lsc1", "lsck",
+					"lsda", "lsdi", "lspi", "lvp0", "lvp1",
+					"lvs";
+				nvidia,function = "displaya";
+			};
+			owc {
+				nvidia,pins = "owc";
+				nvidia,function = "owr";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdc {
+				nvidia,pins = "sdc";
+				nvidia,function = "twc";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxc {
+				nvidia,pins = "slxc", "slxd";
+				nvidia,function = "spi4";
+			};
+			spdi {
+				nvidia,pins = "spdi", "spdo";
+				nvidia,function = "rsvd2";
+			};
+			spif {
+				nvidia,pins = "spif", "uac";
+				nvidia,function = "rsvd4";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "spdif";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atb", "atc", "atd", "ate",
+					"cdev1", "dap1", "dap2", "dtf", "gma",
+					"gmb", "gmc", "gmd", "gme", "gpu",
+					"gpu7", "gpv", "i2cp", "pta", "rm",
+					"sdio1", "slxk", "spdo", "uac", "uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,pull = <1>;
+				nvidia,tristate = <0>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_crtp {
+				nvidia,pins = "crtp", "dap3", "dap4", "dtb",
+					"dtc", "dte", "slxa", "slxc", "slxd",
+					"spdi";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_csus {
+				nvidia,pins = "csus", "spia", "spib", "spid",
+					"spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_ddc {
+				nvidia,pins = "ddc", "irrx", "irtx", "kbca",
+					"kbcb", "kbcc", "kbcd", "kbce", "kbcf",
+					"spic", "spig", "uaa", "uab";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_dta {
+				nvidia,pins = "dta", "dtd", "owc", "sdc", "sdd",
+					"spie", "spih", "uad", "uca", "ucb";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "ld0", "ld1", "ld2",
+					"ld3", "ld4", "ld5", "ld6", "ld7",
+					"ld8", "ld9", "ld10", "ld11", "ld12",
+					"ld13", "ld14", "ld15", "ld16", "ld17",
+					"ldc", "ldi", "lhs", "lsc0", "lspi",
+					"lvs", "pmc";
+				nvidia,tristate = <0>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_lcsn {
+				nvidia,pins = "lcsn", "lhp0", "lhp1", "lhp2",
+					"lm0", "lm1", "lpp", "lpw0", "lpw1",
+					"lpw2", "lsc1", "lsck", "lsda", "lsdi",
+					"lvp0", "lvp1", "sdb";
+				nvidia,tristate = <1>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+		};
+	};
+
 	i2c@7000c000 {
 		clock-frequency = <400000>;
 
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts
index dbf1c5a..ec33116f 100644
--- a/arch/arm/boot/dts/tegra-seaboard.dts
+++ b/arch/arm/boot/dts/tegra-seaboard.dts
@@ -11,6 +11,249 @@
 		reg = < 0x00000000 0x40000000 >;
 	};
 
+	pinmux@70000000 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata";
+				nvidia,function = "ide";
+			};
+			atb {
+				nvidia,pins = "atb", "gma", "gme";
+				nvidia,function = "sdio4";
+			};
+			atc {
+				nvidia,pins = "atc";
+				nvidia,function = "nand";
+			};
+			atd {
+				nvidia,pins = "atd", "ate", "gmb", "spia",
+					"spib", "spic";
+				nvidia,function = "gmi";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp", "lm1";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap2 {
+				nvidia,pins = "dap2";
+				nvidia,function = "dap2";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc", "owc", "spdi", "spdo",
+					"uac";
+				nvidia,function = "rsvd2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+				nvidia,function = "vi";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gmc {
+				nvidia,pins = "gmc";
+				nvidia,function = "uartd";
+			};
+			gmd {
+				nvidia,pins = "gmd";
+				nvidia,function = "sflash";
+			};
+			gpu {
+				nvidia,pins = "gpu";
+				nvidia,function = "pwm";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint", "lpw0", "lpw2", "lsc1",
+					"lsck", "lsda", "pta";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uartb";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ldc", "lm0", "lpw1",
+					"lsdi", "lvp0";
+				nvidia,function = "rsvd4";
+			};
+			ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lpp", "lsc0",
+					"lspi", "lvp1", "lvs";
+				nvidia,function = "displaya";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdb {
+				nvidia,pins = "sdb", "sdc", "sdd";
+				nvidia,function = "sdio3";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxc {
+				nvidia,pins = "slxc", "slxd";
+				nvidia,function = "spdif";
+			};
+			spid {
+				nvidia,pins = "spid", "spie", "spif";
+				nvidia,function = "spi1";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atb", "atc", "atd",
+					"cdev1", "cdev2", "dap1", "dap2",
+					"dap4", "dtf", "gma", "gmc", "gmd",
+					"gme", "gpu", "gpu7", "i2cp", "irrx",
+					"irtx", "pta", "rm", "sdc", "sdd",
+					"slxd", "slxk", "spdi", "spdo", "uac",
+					"uad", "uca", "ucb", "uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_ate {
+				nvidia,pins = "ate", "csus", "dap3", "ddc",
+					"gpv", "owc", "slxc", "spib", "spid",
+					"spie";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_crtp {
+				nvidia,pins = "crtp", "gmb", "slxa", "spia",
+					"spig", "spih";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd";
+				nvidia,pull = <1>;
+				nvidia,tristate = <0>;
+			};
+			conf_dte {
+				nvidia,pins = "dte", "spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+					"lpw1", "lsc1", "lsck", "lsda", "lsdi",
+					"lvp0";
+				nvidia,tristate = <1>;
+			};
+			conf_kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf", "sdio1", "spic", "uaa",
+					"uab";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lm0", "lpp",
+					"lpw0", "lpw2", "lsc0", "lspi", "lvp1",
+					"lvs", "pmc", "sdb";
+				nvidia,tristate = <0>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+			drive_sdio1 {
+				nvidia,pins = "drive_sdio1";
+				nvidia,high-speed-mode = <0>;
+				nvidia,schmitt = <0>;
+				nvidia,low-power-mode = <3>;
+				nvidia,pull-down-strength = <31>;
+				nvidia,pull-up-strength = <31>;
+				nvidia,slew-rate-rising = <3>;
+				nvidia,slew-rate-falling = <3>;
+			};
+		};
+	};
+
 	i2c@7000c000 {
 		clock-frequency = <400000>;
 
diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts
index 2524768..98efd5b 100644
--- a/arch/arm/boot/dts/tegra-trimslice.dts
+++ b/arch/arm/boot/dts/tegra-trimslice.dts
@@ -10,6 +10,236 @@
 		reg = < 0x00000000 0x40000000 >;
 	};
 
+	pinmux@70000000 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata";
+				nvidia,function = "ide";
+			};
+			atb {
+				nvidia,pins = "atb", "gma";
+				nvidia,function = "sdio4";
+			};
+			atc {
+				nvidia,pins = "atc", "gmb";
+				nvidia,function = "nand";
+			};
+			atd {
+				nvidia,pins = "atd", "ate", "gme", "pta";
+				nvidia,function = "gmi";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap2 {
+				nvidia,pins = "dap2";
+				nvidia,function = "dap2";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "i2c2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+				nvidia,function = "vi";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gmc {
+				nvidia,pins = "gmc", "gmd";
+				nvidia,function = "sflash";
+			};
+			gpu {
+				nvidia,pins = "gpu";
+				nvidia,function = "uarta";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uartb";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
+					"ld3", "ld4", "ld5", "ld6", "ld7",
+					"ld8", "ld9", "ld10", "ld11", "ld12",
+					"ld13", "ld14", "ld15", "ld16", "ld17",
+					"ldc", "ldi", "lhp0", "lhp1", "lhp2",
+					"lhs", "lm0", "lm1", "lpp", "lpw0",
+					"lpw1", "lpw2", "lsc0", "lsc1", "lsck",
+					"lsda", "lsdi", "lspi", "lvp0", "lvp1",
+					"lvs";
+				nvidia,function = "displaya";
+			};
+			owc {
+				nvidia,pins = "owc", "uac";
+				nvidia,function = "rsvd2";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdb {
+				nvidia,pins = "sdb", "sdc", "sdd";
+				nvidia,function = "pwm";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxc {
+				nvidia,pins = "slxc", "slxd";
+				nvidia,function = "sdio3";
+			};
+			spdi {
+				nvidia,pins = "spdi", "spdo";
+				nvidia,function = "spdif";
+			};
+			spia {
+				nvidia,pins = "spia", "spib", "spic";
+				nvidia,function = "spi2";
+			};
+			spid {
+				nvidia,pins = "spid", "spie", "spif";
+				nvidia,function = "spi1";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atc", "atd", "ate",
+					"crtp", "dap2", "dap3", "dap4", "dta",
+					"dtb", "dtc", "dtd", "dte", "gmb",
+					"gme", "i2cp", "pta", "slxc", "slxd",
+					"spdi", "spdo", "uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_atb {
+				nvidia,pins = "atb", "cdev1", "dap1", "gma",
+					"gmc", "gmd", "gpu", "gpu7", "gpv",
+					"sdio1", "slxa", "slxk", "uac";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_cdev2 {
+				nvidia,pins = "cdev2", "csus", "spia", "spib",
+					"spid", "spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_ddc {
+				nvidia,pins = "ddc", "dtf", "rm", "sdc", "sdd";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+					"lpw1", "lsc1", "lsck", "lsda", "lsdi",
+					"lvp0", "pmc";
+				nvidia,tristate = <1>;
+			};
+			conf_irrx {
+				nvidia,pins = "irrx", "irtx", "kbca", "kbcb",
+					"kbcc", "kbcd", "kbce", "kbcf", "owc",
+					"spic", "spie", "spig", "spih", "uaa",
+					"uab", "uad", "uca", "ucb";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lm0", "lpp",
+					"lpw0", "lpw2", "lsc0", "lspi", "lvp1",
+					"lvs", "sdb";
+				nvidia,tristate = <0>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+		};
+	};
+
 	i2c@7000c000 {
 		clock-frequency = <400000>;
 	};
diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts
index 2dcff87..71eb2e5 100644
--- a/arch/arm/boot/dts/tegra-ventana.dts
+++ b/arch/arm/boot/dts/tegra-ventana.dts
@@ -10,6 +10,236 @@
 		reg = < 0x00000000 0x40000000 >;
 	};
 
+	pinmux@70000000 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata";
+				nvidia,function = "ide";
+			};
+			atb {
+				nvidia,pins = "atb", "gma", "gme";
+				nvidia,function = "sdio4";
+			};
+			atc {
+				nvidia,pins = "atc";
+				nvidia,function = "nand";
+			};
+			atd {
+				nvidia,pins = "atd", "ate", "gmb", "spia",
+					"spib", "spic";
+				nvidia,function = "gmi";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp", "lm1";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap2 {
+				nvidia,pins = "dap2";
+				nvidia,function = "dap2";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc", "owc", "spdi", "spdo",
+					"uac";
+				nvidia,function = "rsvd2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+				nvidia,function = "vi";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gmc {
+				nvidia,pins = "gmc";
+				nvidia,function = "uartd";
+			};
+			gmd {
+				nvidia,pins = "gmd";
+				nvidia,function = "sflash";
+			};
+			gpu {
+				nvidia,pins = "gpu";
+				nvidia,function = "pwm";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint", "pta";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uartb";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ldc", "lm0", "lpw1",
+					"lsdi", "lvp0";
+				nvidia,function = "rsvd4";
+			};
+			ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lpp", "lpw0",
+					"lpw2", "lsc0", "lsc1", "lsck", "lsda",
+					"lspi", "lvp1", "lvs";
+				nvidia,function = "displaya";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdb {
+				nvidia,pins = "sdb", "sdc", "sdd", "slxc";
+				nvidia,function = "sdio3";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxd {
+				nvidia,pins = "slxd";
+				nvidia,function = "spdif";
+			};
+			spid {
+				nvidia,pins = "spid", "spie", "spif";
+				nvidia,function = "spi1";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atb", "atc", "atd",
+					"cdev1", "cdev2", "dap1", "dap2",
+					"dap4", "ddc", "dtf", "gma", "gmc",
+					"gme", "gpu", "gpu7", "i2cp", "irrx",
+					"irtx", "pta", "rm", "sdc", "sdd",
+					"slxc", "slxd", "slxk", "spdi", "spdo",
+					"uac", "uad", "uca", "ucb", "uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_ate {
+				nvidia,pins = "ate", "csus", "dap3", "gmd",
+					"gpv", "owc", "spia", "spib", "spic",
+					"spid", "spie", "spig";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_crtp {
+				nvidia,pins = "crtp", "gmb", "slxa", "spih";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd";
+				nvidia,pull = <1>;
+				nvidia,tristate = <0>;
+			};
+			conf_dte {
+				nvidia,pins = "dte", "spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+					"lpw1", "lsck", "lsda", "lsdi", "lvp0";
+				nvidia,tristate = <1>;
+			};
+			conf_kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf", "sdio1", "uaa", "uab";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lm0", "lpp",
+					"lpw0", "lpw2", "lsc0", "lsc1", "lspi",
+					"lvp1", "lvs", "pmc", "sdb";
+				nvidia,tristate = <0>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+		};
+	};
+
 	i2c@7000c000 {
 		clock-frequency = <400000>;
 
diff --git a/arch/arm/boot/dts/tny_a9260.dts b/arch/arm/boot/dts/tny_a9260.dts
new file mode 100644
index 0000000..367a16d
--- /dev/null
+++ b/arch/arm/boot/dts/tny_a9260.dts
@@ -0,0 +1,15 @@
+/*
+ * tny_a9260.dts - Device Tree file for Caloa TNY A9260 board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9260.dtsi"
+/include/ "tny_a9260_common.dtsi"
+
+/ {
+	model = "Calao TNY A9260";
+	compatible = "calao,tny-a9260", "atmel,at91sam9260", "atmel,at91sam9";
+};
diff --git a/arch/arm/boot/dts/tny_a9260_common.dtsi b/arch/arm/boot/dts/tny_a9260_common.dtsi
new file mode 100644
index 0000000..0e6d3de
--- /dev/null
+++ b/arch/arm/boot/dts/tny_a9260_common.dtsi
@@ -0,0 +1,83 @@
+/*
+ * tny_a9260_common.dtsi - Device Tree file for Caloa TNY A926x board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/ {
+	chosen {
+		bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock6 rw rootfstype=ubifs";
+	};
+
+	memory {
+		reg = <0x20000000 0x4000000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <12000000>;
+		};
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@fffff200 {
+				status = "okay";
+			};
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+
+			at91bootstrap@0 {
+				label = "at91bootstrap";
+				reg = <0x0 0x20000>;
+			};
+
+			barebox@20000 {
+				label = "barebox";
+				reg = <0x20000 0x40000>;
+			};
+
+			bareboxenv@60000 {
+				label = "bareboxenv";
+				reg = <0x60000 0x20000>;
+			};
+
+			bareboxenv2@80000 {
+				label = "bareboxenv2";
+				reg = <0x80000 0x20000>;
+			};
+
+			oftree@80000 {
+				label = "oftree";
+				reg = <0xa0000 0x20000>;
+			};
+
+			kernel@a0000 {
+				label = "kernel";
+				reg = <0xc0000 0x400000>;
+			};
+
+			rootfs@4a0000 {
+				label = "rootfs";
+				reg = <0x4c0000 0x7800000>;
+			};
+
+			data@7ca0000 {
+				label = "data";
+				reg = <0x7cc0000 0x8340000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/tny_a9263.dts b/arch/arm/boot/dts/tny_a9263.dts
new file mode 100644
index 0000000..dee9c57
--- /dev/null
+++ b/arch/arm/boot/dts/tny_a9263.dts
@@ -0,0 +1,97 @@
+/*
+ * usb_a9263.dts - Device Tree file for Caloa USB A9293 board
+ *
+ *  Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 only
+ */
+/dts-v1/;
+/include/ "at91sam9263.dtsi"
+
+/ {
+	model = "Calao TNY A9263";
+	compatible = "atmel,tny-a9263", "atmel,at91sam9263", "atmel,at91sam9";
+
+	chosen {
+		bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+	};
+
+	memory {
+		reg = <0x20000000 0x4000000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <12000000>;
+		};
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@ffffee00 {
+				status = "okay";
+			};
+
+			usb1: gadget@fff78000 {
+				atmel,vbus-gpio = <&pioB 11 0>;
+				status = "okay";
+			};
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+
+			at91bootstrap@0 {
+				label = "at91bootstrap";
+				reg = <0x0 0x20000>;
+			};
+
+			barebox@20000 {
+				label = "barebox";
+				reg = <0x20000 0x40000>;
+			};
+
+			bareboxenv@60000 {
+				label = "bareboxenv";
+				reg = <0x60000 0x20000>;
+			};
+
+			bareboxenv2@80000 {
+				label = "bareboxenv2";
+				reg = <0x80000 0x20000>;
+			};
+
+			oftree@80000 {
+				label = "oftree";
+				reg = <0xa0000 0x20000>;
+			};
+
+			kernel@a0000 {
+				label = "kernel";
+				reg = <0xc0000 0x400000>;
+			};
+
+			rootfs@4a0000 {
+				label = "rootfs";
+				reg = <0x4c0000 0x7800000>;
+			};
+
+			data@7ca0000 {
+				label = "data";
+				reg = <0x7cc0000 0x8340000>;
+			};
+		};
+	};
+
+	i2c@0 {
+		status = "okay";
+	};
+};
diff --git a/arch/arm/boot/dts/tny_a9g20.dts b/arch/arm/boot/dts/tny_a9g20.dts
new file mode 100644
index 0000000..e1ab64c
--- /dev/null
+++ b/arch/arm/boot/dts/tny_a9g20.dts
@@ -0,0 +1,15 @@
+/*
+ * tny_a9g20.dts - Device Tree file for Caloa TNY A9G20 board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9g20.dtsi"
+/include/ "tny_a9260_common.dtsi"
+
+/ {
+	model = "Calao TNY A9G20";
+	compatible = "calao,tny-a9g20", "atmel,at91sam9g20", "atmel,at91sam9";
+};
diff --git a/arch/arm/boot/dts/twl4030.dtsi b/arch/arm/boot/dts/twl4030.dtsi
new file mode 100644
index 0000000..22f4d13
--- /dev/null
+++ b/arch/arm/boot/dts/twl4030.dtsi
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.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.
+ */
+
+/*
+ * Integrated Power Management Chip
+ */
+&twl {
+	compatible = "ti,twl4030";
+	interrupt-controller;
+	#interrupt-cells = <1>;
+
+	rtc {
+		compatible = "ti,twl4030-rtc";
+		interrupts = <11>;
+	};
+
+	vdac: regulator@0 {
+		compatible = "ti,twl4030-vdac";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	vpll2: regulator@1 {
+		compatible = "ti,twl4030-vpll2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	vmmc1: regulator@2 {
+		compatible = "ti,twl4030-vmmc1";
+		regulator-min-microvolt = <1850000>;
+		regulator-max-microvolt = <3150000>;
+	};
+
+	twl_gpio: gpio {
+		compatible = "ti,twl4030-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <1>;
+	};
+};
diff --git a/arch/arm/boot/dts/twl6030.dtsi b/arch/arm/boot/dts/twl6030.dtsi
new file mode 100644
index 0000000..3b2f351
--- /dev/null
+++ b/arch/arm/boot/dts/twl6030.dtsi
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.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.
+ */
+
+/*
+ * Integrated Power Management Chip
+ * http://www.ti.com/lit/ds/symlink/twl6030.pdf
+ */
+&twl {
+	compatible = "ti,twl6030";
+	interrupt-controller;
+	#interrupt-cells = <1>;
+
+	rtc {
+		compatible = "ti,twl4030-rtc";
+		interrupts = <11>;
+	};
+
+	vaux1: regulator@0 {
+		compatible = "ti,twl6030-vaux1";
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <3000000>;
+	};
+
+	vaux2: regulator@1 {
+		compatible = "ti,twl6030-vaux2";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <2800000>;
+	};
+
+	vaux3: regulator@2 {
+		compatible = "ti,twl6030-vaux3";
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <3000000>;
+	};
+
+	vmmc: regulator@3 {
+		compatible = "ti,twl6030-vmmc";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <3000000>;
+	};
+
+	vpp: regulator@4 {
+		compatible = "ti,twl6030-vpp";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2500000>;
+	};
+
+	vusim: regulator@5 {
+		compatible = "ti,twl6030-vusim";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <2900000>;
+	};
+
+	vdac: regulator@6 {
+		compatible = "ti,twl6030-vdac";
+	};
+
+	vana: regulator@7 {
+		compatible = "ti,twl6030-vana";
+	};
+
+	vcxio: regulator@8 {
+		compatible = "ti,twl6030-vcxio";
+	};
+
+	vusb: regulator@9 {
+		compatible = "ti,twl6030-vusb";
+	};
+
+	v1v8: regulator@10 {
+		compatible = "ti,twl6030-v1v8";
+	};
+
+	v2v1: regulator@11 {
+		compatible = "ti,twl6030-v2v1";
+	};
+
+	clk32kg: regulator@12 {
+		compatible = "ti,twl6030-clk32kg";
+	};
+};
diff --git a/arch/arm/boot/dts/usb_a9260.dts b/arch/arm/boot/dts/usb_a9260.dts
new file mode 100644
index 0000000..2962160
--- /dev/null
+++ b/arch/arm/boot/dts/usb_a9260.dts
@@ -0,0 +1,23 @@
+/*
+ * usb_a9260.dts - Device Tree file for Caloa USB A9260 board
+ *
+ *  Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9260.dtsi"
+/include/ "usb_a9260_common.dtsi"
+
+/ {
+	model = "Calao USB A9260";
+	compatible = "calao,usb-a9260", "atmel,at91sam9260", "atmel,at91sam9";
+
+	chosen {
+		bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+	};
+
+	memory {
+		reg = <0x20000000 0x4000000>;
+	};
+};
diff --git a/arch/arm/boot/dts/usb_a9260_common.dtsi b/arch/arm/boot/dts/usb_a9260_common.dtsi
new file mode 100644
index 0000000..e70d229
--- /dev/null
+++ b/arch/arm/boot/dts/usb_a9260_common.dtsi
@@ -0,0 +1,117 @@
+/*
+ * usb_a926x.dts - Device Tree file for Caloa USB A926x board
+ *
+ *  Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/ {
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <12000000>;
+		};
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@fffff200 {
+				status = "okay";
+			};
+
+			macb0: ethernet@fffc4000 {
+				phy-mode = "rmii";
+				status = "okay";
+			};
+
+			usb1: gadget@fffa4000 {
+				atmel,vbus-gpio = <&pioC 5 0>;
+				status = "okay";
+			};
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+
+			at91bootstrap@0 {
+				label = "at91bootstrap";
+				reg = <0x0 0x20000>;
+			};
+
+			barebox@20000 {
+				label = "barebox";
+				reg = <0x20000 0x40000>;
+			};
+
+			bareboxenv@60000 {
+				label = "bareboxenv";
+				reg = <0x60000 0x20000>;
+			};
+
+			bareboxenv2@80000 {
+				label = "bareboxenv2";
+				reg = <0x80000 0x20000>;
+			};
+
+			oftree@80000 {
+				label = "oftree";
+				reg = <0xa0000 0x20000>;
+			};
+
+			kernel@a0000 {
+				label = "kernel";
+				reg = <0xc0000 0x400000>;
+			};
+
+			rootfs@4a0000 {
+				label = "rootfs";
+				reg = <0x4c0000 0x7800000>;
+			};
+
+			data@7ca0000 {
+				label = "data";
+				reg = <0x7cc0000 0x8340000>;
+			};
+		};
+
+		usb0: ohci@00500000 {
+			num-ports = <2>;
+			status = "okay";
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		user_led {
+			label = "user_led";
+			gpios = <&pioB 21 1>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		user_pb {
+			label = "user_pb";
+			gpios = <&pioB 10 1>;
+			linux,code = <28>;
+			gpio-key,wakeup;
+		};
+	};
+
+	i2c@0 {
+		status = "okay";
+	};
+};
diff --git a/arch/arm/boot/dts/usb_a9263.dts b/arch/arm/boot/dts/usb_a9263.dts
new file mode 100644
index 0000000..6fe05cc
--- /dev/null
+++ b/arch/arm/boot/dts/usb_a9263.dts
@@ -0,0 +1,131 @@
+/*
+ * usb_a9263.dts - Device Tree file for Caloa USB A9293 board
+ *
+ *  Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 only
+ */
+/dts-v1/;
+/include/ "at91sam9263.dtsi"
+
+/ {
+	model = "Calao USB A9263";
+	compatible = "atmel,usb-a9263", "atmel,at91sam9263", "atmel,at91sam9";
+
+	chosen {
+		bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+	};
+
+	memory {
+		reg = <0x20000000 0x4000000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <12000000>;
+		};
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@ffffee00 {
+				status = "okay";
+			};
+
+			macb0: ethernet@fffbc000 {
+				phy-mode = "rmii";
+				status = "okay";
+			};
+
+			usb1: gadget@fff78000 {
+				atmel,vbus-gpio = <&pioB 11 0>;
+				status = "okay";
+			};
+
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+
+			at91bootstrap@0 {
+				label = "at91bootstrap";
+				reg = <0x0 0x20000>;
+			};
+
+			barebox@20000 {
+				label = "barebox";
+				reg = <0x20000 0x40000>;
+			};
+
+			bareboxenv@60000 {
+				label = "bareboxenv";
+				reg = <0x60000 0x20000>;
+			};
+
+			bareboxenv2@80000 {
+				label = "bareboxenv2";
+				reg = <0x80000 0x20000>;
+			};
+
+			oftree@80000 {
+				label = "oftree";
+				reg = <0xa0000 0x20000>;
+			};
+
+			kernel@a0000 {
+				label = "kernel";
+				reg = <0xc0000 0x400000>;
+			};
+
+			rootfs@4a0000 {
+				label = "rootfs";
+				reg = <0x4c0000 0x7800000>;
+			};
+
+			data@7ca0000 {
+				label = "data";
+				reg = <0x7cc0000 0x8340000>;
+			};
+		};
+
+		usb0: ohci@00a00000 {
+			num-ports = <2>;
+			status = "okay";
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		user_led {
+			label = "user_led";
+			gpios = <&pioB 21 0>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		user_pb {
+			label = "user_pb";
+			gpios = <&pioB 10 1>;
+			linux,code = <28>;
+			gpio-key,wakeup;
+		};
+	};
+
+	i2c@0 {
+		status = "okay";
+	};
+};
diff --git a/arch/arm/boot/dts/usb_a9g20.dts b/arch/arm/boot/dts/usb_a9g20.dts
index 7c2399c..2dacb16 100644
--- a/arch/arm/boot/dts/usb_a9g20.dts
+++ b/arch/arm/boot/dts/usb_a9g20.dts
@@ -7,6 +7,7 @@
  */
 /dts-v1/;
 /include/ "at91sam9g20.dtsi"
+/include/ "usb_a9260_common.dtsi"
 
 / {
 	model = "Calao USB A9G20";
@@ -20,108 +21,7 @@
 		reg = <0x20000000 0x4000000>;
 	};
 
-	clocks {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		main_clock: clock@0 {
-			compatible = "atmel,osc", "fixed-clock";
-			clock-frequency = <12000000>;
-		};
-	};
-
-	ahb {
-		apb {
-			dbgu: serial@fffff200 {
-				status = "okay";
-			};
-
-			macb0: ethernet@fffc4000 {
-				phy-mode = "rmii";
-				status = "okay";
-			};
-
-			usb1: gadget@fffa4000 {
-				atmel,vbus-gpio = <&pioC 5 0>;
-				status = "okay";
-			};
-		};
-
-		nand0: nand@40000000 {
-			nand-bus-width = <8>;
-			nand-ecc-mode = "soft";
-			nand-on-flash-bbt;
-			status = "okay";
-
-			at91bootstrap@0 {
-				label = "at91bootstrap";
-				reg = <0x0 0x20000>;
-			};
-
-			barebox@20000 {
-				label = "barebox";
-				reg = <0x20000 0x40000>;
-			};
-
-			bareboxenv@60000 {
-				label = "bareboxenv";
-				reg = <0x60000 0x20000>;
-			};
-
-			bareboxenv2@80000 {
-				label = "bareboxenv2";
-				reg = <0x80000 0x20000>;
-			};
-
-			kernel@a0000 {
-				label = "kernel";
-				reg = <0xa0000 0x400000>;
-			};
-
-			rootfs@4a0000 {
-				label = "rootfs";
-				reg = <0x4a0000 0x7800000>;
-			};
-
-			data@7ca0000 {
-				label = "data";
-				reg = <0x7ca0000 0x8360000>;
-			};
-		};
-
-		usb0: ohci@00500000 {
-			num-ports = <2>;
-			status = "okay";
-		};
-	};
-
-	leds {
-		compatible = "gpio-leds";
-
-		user_led {
-			label = "user_led";
-			gpios = <&pioB 21 1>;
-			linux,default-trigger = "heartbeat";
-		};
-	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		user_pb {
-			label = "user_pb";
-			gpios = <&pioB 10 1>;
-			linux,code = <28>;
-			gpio-key,wakeup;
-		};
-	};
-
 	i2c@0 {
-		status = "okay";
-
 		rv3029c2@56 {
 			compatible = "rv3029c2";
 			reg = <0x56>;
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 215816f..e8a4e58 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -11,7 +11,5 @@
 obj-$(CONFIG_SHARP_LOCOMO)	+= locomo.o
 obj-$(CONFIG_SHARP_PARAM)	+= sharpsl_param.o
 obj-$(CONFIG_SHARP_SCOOP)	+= scoop.o
-obj-$(CONFIG_ARCH_IXP2000)	+= uengine.o
-obj-$(CONFIG_ARCH_IXP23XX)	+= uengine.o
 obj-$(CONFIG_PCI_HOST_ITE8152)  += it8152.o
 obj-$(CONFIG_ARM_TIMER_SP804)	+= timer-sp.o
diff --git a/arch/arm/common/uengine.c b/arch/arm/common/uengine.c
deleted file mode 100644
index bef408f..0000000
--- a/arch/arm/common/uengine.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Generic library functions for the microengines found on the Intel
- * IXP2000 series of network processors.
- *
- * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
- * Dedicated to Marija Kulikova.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <asm/hardware/uengine.h>
-
-#if defined(CONFIG_ARCH_IXP2000)
-#define IXP_UENGINE_CSR_VIRT_BASE	IXP2000_UENGINE_CSR_VIRT_BASE
-#define IXP_PRODUCT_ID			IXP2000_PRODUCT_ID
-#define IXP_MISC_CONTROL		IXP2000_MISC_CONTROL
-#define IXP_RESET1			IXP2000_RESET1
-#else
-#if defined(CONFIG_ARCH_IXP23XX)
-#define IXP_UENGINE_CSR_VIRT_BASE	IXP23XX_UENGINE_CSR_VIRT_BASE
-#define IXP_PRODUCT_ID			IXP23XX_PRODUCT_ID
-#define IXP_MISC_CONTROL		IXP23XX_MISC_CONTROL
-#define IXP_RESET1			IXP23XX_RESET1
-#else
-#error unknown platform
-#endif
-#endif
-
-#define USTORE_ADDRESS			0x000
-#define USTORE_DATA_LOWER		0x004
-#define USTORE_DATA_UPPER		0x008
-#define CTX_ENABLES			0x018
-#define CC_ENABLE			0x01c
-#define CSR_CTX_POINTER			0x020
-#define INDIRECT_CTX_STS		0x040
-#define ACTIVE_CTX_STS			0x044
-#define INDIRECT_CTX_SIG_EVENTS		0x048
-#define INDIRECT_CTX_WAKEUP_EVENTS	0x050
-#define NN_PUT				0x080
-#define NN_GET				0x084
-#define TIMESTAMP_LOW			0x0c0
-#define TIMESTAMP_HIGH			0x0c4
-#define T_INDEX_BYTE_INDEX		0x0f4
-#define LOCAL_CSR_STATUS		0x180
-
-u32 ixp2000_uengine_mask;
-
-static void *ixp2000_uengine_csr_area(int uengine)
-{
-	return ((void *)IXP_UENGINE_CSR_VIRT_BASE) + (uengine << 10);
-}
-
-/*
- * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR
- * space means that the microengine we tried to access was also trying
- * to access its own CSR space on the same clock cycle as we did.  When
- * this happens, we lose the arbitration process by default, and the
- * read or write we tried to do was not actually performed, so we try
- * again until it succeeds.
- */
-u32 ixp2000_uengine_csr_read(int uengine, int offset)
-{
-	void *uebase;
-	u32 *local_csr_status;
-	u32 *reg;
-	u32 value;
-
-	uebase = ixp2000_uengine_csr_area(uengine);
-
-	local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
-	reg = (u32 *)(uebase + offset);
-	do {
-		value = ixp2000_reg_read(reg);
-	} while (ixp2000_reg_read(local_csr_status) & 1);
-
-	return value;
-}
-EXPORT_SYMBOL(ixp2000_uengine_csr_read);
-
-void ixp2000_uengine_csr_write(int uengine, int offset, u32 value)
-{
-	void *uebase;
-	u32 *local_csr_status;
-	u32 *reg;
-
-	uebase = ixp2000_uengine_csr_area(uengine);
-
-	local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
-	reg = (u32 *)(uebase + offset);
-	do {
-		ixp2000_reg_write(reg, value);
-	} while (ixp2000_reg_read(local_csr_status) & 1);
-}
-EXPORT_SYMBOL(ixp2000_uengine_csr_write);
-
-void ixp2000_uengine_reset(u32 uengine_mask)
-{
-	u32 value;
-
-	value = ixp2000_reg_read(IXP_RESET1) & ~ixp2000_uengine_mask;
-
-	uengine_mask &= ixp2000_uengine_mask;
-	ixp2000_reg_wrb(IXP_RESET1, value | uengine_mask);
-	ixp2000_reg_wrb(IXP_RESET1, value);
-}
-EXPORT_SYMBOL(ixp2000_uengine_reset);
-
-void ixp2000_uengine_set_mode(int uengine, u32 mode)
-{
-	/*
-	 * CTL_STR_PAR_EN: unconditionally enable parity checking on
-	 * control store.
-	 */
-	mode |= 0x10000000;
-	ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mode);
-
-	/*
-	 * Enable updating of condition codes.
-	 */
-	ixp2000_uengine_csr_write(uengine, CC_ENABLE, 0x00002000);
-
-	/*
-	 * Initialise other per-microengine registers.
-	 */
-	ixp2000_uengine_csr_write(uengine, NN_PUT, 0x00);
-	ixp2000_uengine_csr_write(uengine, NN_GET, 0x00);
-	ixp2000_uengine_csr_write(uengine, T_INDEX_BYTE_INDEX, 0);
-}
-EXPORT_SYMBOL(ixp2000_uengine_set_mode);
-
-static int make_even_parity(u32 x)
-{
-	return hweight32(x) & 1;
-}
-
-static void ustore_write(int uengine, u64 insn)
-{
-	/*
-	 * Generate even parity for top and bottom 20 bits.
-	 */
-	insn |= (u64)make_even_parity((insn >> 20) & 0x000fffff) << 41;
-	insn |= (u64)make_even_parity(insn & 0x000fffff) << 40;
-
-	/*
-	 * Write to microstore.  The second write auto-increments
-	 * the USTORE_ADDRESS index register.
-	 */
-	ixp2000_uengine_csr_write(uengine, USTORE_DATA_LOWER, (u32)insn);
-	ixp2000_uengine_csr_write(uengine, USTORE_DATA_UPPER, (u32)(insn >> 32));
-}
-
-void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns)
-{
-	int i;
-
-	/*
-	 * Start writing to microstore at address 0.
-	 */
-	ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x80000000);
-	for (i = 0; i < insns; i++) {
-		u64 insn;
-
-		insn = (((u64)ucode[0]) << 32) |
-			(((u64)ucode[1]) << 24) |
-			(((u64)ucode[2]) << 16) |
-			(((u64)ucode[3]) << 8) |
-			((u64)ucode[4]);
-		ucode += 5;
-
-		ustore_write(uengine, insn);
-	}
-
-	/*
- 	 * Pad with a few NOPs at the end (to avoid the microengine
-	 * aborting as it prefetches beyond the last instruction), unless
-	 * we run off the end of the instruction store first, at which
-	 * point the address register will wrap back to zero.
-	 */
-	for (i = 0; i < 4; i++) {
-		u32 addr;
-
-		addr = ixp2000_uengine_csr_read(uengine, USTORE_ADDRESS);
-		if (addr == 0x80000000)
-			break;
-		ustore_write(uengine, 0xf0000c0300ULL);
-	}
-
-	/*
-	 * End programming.
-	 */
-	ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x00000000);
-}
-EXPORT_SYMBOL(ixp2000_uengine_load_microcode);
-
-void ixp2000_uengine_init_context(int uengine, int context, int pc)
-{
-	/*
-	 * Select the right context for indirect access.
-	 */
-	ixp2000_uengine_csr_write(uengine, CSR_CTX_POINTER, context);
-
-	/*
-	 * Initialise signal masks to immediately go to Ready state.
-	 */
-	ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_SIG_EVENTS, 1);
-	ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_WAKEUP_EVENTS, 1);
-
-	/*
-	 * Set program counter.
-	 */
-	ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_STS, pc);
-}
-EXPORT_SYMBOL(ixp2000_uengine_init_context);
-
-void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask)
-{
-	u32 mask;
-
-	/*
-	 * Enable the specified context to go to Executing state.
-	 */
-	mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
-	mask |= ctx_mask << 8;
-	ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
-}
-EXPORT_SYMBOL(ixp2000_uengine_start_contexts);
-
-void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask)
-{
-	u32 mask;
-
-	/*
-	 * Disable the Ready->Executing transition.  Note that this
-	 * does not stop the context until it voluntarily yields.
-	 */
-	mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
-	mask &= ~(ctx_mask << 8);
-	ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
-}
-EXPORT_SYMBOL(ixp2000_uengine_stop_contexts);
-
-static int check_ixp_type(struct ixp2000_uengine_code *c)
-{
-	u32 product_id;
-	u32 rev;
-
-	product_id = ixp2000_reg_read(IXP_PRODUCT_ID);
-	if (((product_id >> 16) & 0x1f) != 0)
-		return 0;
-
-	switch ((product_id >> 8) & 0xff) {
-#ifdef CONFIG_ARCH_IXP2000
-	case 0:		/* IXP2800 */
-		if (!(c->cpu_model_bitmask & 4))
-			return 0;
-		break;
-
-	case 1:		/* IXP2850 */
-		if (!(c->cpu_model_bitmask & 8))
-			return 0;
-		break;
-
-	case 2:		/* IXP2400 */
-		if (!(c->cpu_model_bitmask & 2))
-			return 0;
-		break;
-#endif
-
-#ifdef CONFIG_ARCH_IXP23XX
-	case 4:		/* IXP23xx */
-		if (!(c->cpu_model_bitmask & 0x3f0))
-			return 0;
-		break;
-#endif
-
-	default:
-		return 0;
-	}
-
-	rev = product_id & 0xff;
-	if (rev < c->cpu_min_revision || rev > c->cpu_max_revision)
-		return 0;
-
-	return 1;
-}
-
-static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b)
-{
-	int offset;
-	int i;
-
-	offset = 0;
-
-	for (i = 0; i < 128; i++) {
-		u8 b3;
-		u8 b2;
-		u8 b1;
-		u8 b0;
-
-		b3 = (gpr_a[i] >> 24) & 0xff;
-		b2 = (gpr_a[i] >> 16) & 0xff;
-		b1 = (gpr_a[i] >> 8) & 0xff;
-		b0 = gpr_a[i] & 0xff;
-
-		/* immed[@ai, (b1 << 8) | b0] */
-		/* 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII */
-		ucode[offset++] = 0xf0;
-		ucode[offset++] = (b1 >> 4);
-		ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6);
-		ucode[offset++] = (b0 << 2);
-		ucode[offset++] = 0x80 | i;
-
-		/* immed_w1[@ai, (b3 << 8) | b2] */
-		/* 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII */
-		ucode[offset++] = 0xf4;
-		ucode[offset++] = 0x40 | (b3 >> 4);
-		ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6);
-		ucode[offset++] = (b2 << 2);
-		ucode[offset++] = 0x80 | i;
-	}
-
-	for (i = 0; i < 128; i++) {
-		u8 b3;
-		u8 b2;
-		u8 b1;
-		u8 b0;
-
-		b3 = (gpr_b[i] >> 24) & 0xff;
-		b2 = (gpr_b[i] >> 16) & 0xff;
-		b1 = (gpr_b[i] >> 8) & 0xff;
-		b0 = gpr_b[i] & 0xff;
-
-		/* immed[@bi, (b1 << 8) | b0] */
-		/* 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV */
-		ucode[offset++] = 0xf0;
-		ucode[offset++] = (b1 >> 4);
-		ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6);
-		ucode[offset++] = (i << 2) | 0x03;
-		ucode[offset++] = b0;
-
-		/* immed_w1[@bi, (b3 << 8) | b2] */
-		/* 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV */
-		ucode[offset++] = 0xf4;
-		ucode[offset++] = 0x40 | (b3 >> 4);
-		ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6);
-		ucode[offset++] = (i << 2) | 0x03;
-		ucode[offset++] = b2;
-	}
-
-	/* ctx_arb[kill] */
-	ucode[offset++] = 0xe0;
-	ucode[offset++] = 0x00;
-	ucode[offset++] = 0x01;
-	ucode[offset++] = 0x00;
-	ucode[offset++] = 0x00;
-}
-
-static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c)
-{
-	int per_ctx_regs;
-	u32 *gpr_a;
-	u32 *gpr_b;
-	u8 *ucode;
-	int i;
-
-	gpr_a = kzalloc(128 * sizeof(u32), GFP_KERNEL);
-	gpr_b = kzalloc(128 * sizeof(u32), GFP_KERNEL);
-	ucode = kmalloc(513 * 5, GFP_KERNEL);
-	if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) {
-		kfree(ucode);
-		kfree(gpr_b);
-		kfree(gpr_a);
-		return 1;
-	}
-
-	per_ctx_regs = 16;
-	if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS)
-		per_ctx_regs = 32;
-
-	for (i = 0; i < 256; i++) {
-		struct ixp2000_reg_value *r = c->initial_reg_values + i;
-		u32 *bank;
-		int inc;
-		int j;
-
-		if (r->reg == -1)
-			break;
-
-		bank = (r->reg & 0x400) ? gpr_b : gpr_a;
-		inc = (r->reg & 0x80) ? 128 : per_ctx_regs;
-
-		j = r->reg & 0x7f;
-		while (j < 128) {
-			bank[j] = r->value;
-			j += inc;
-		}
-	}
-
-	generate_ucode(ucode, gpr_a, gpr_b);
-	ixp2000_uengine_load_microcode(uengine, ucode, 513);
-	ixp2000_uengine_init_context(uengine, 0, 0);
-	ixp2000_uengine_start_contexts(uengine, 0x01);
-	for (i = 0; i < 100; i++) {
-		u32 status;
-
-		status = ixp2000_uengine_csr_read(uengine, ACTIVE_CTX_STS);
-		if (!(status & 0x80000000))
-			break;
-	}
-	ixp2000_uengine_stop_contexts(uengine, 0x01);
-
-	kfree(ucode);
-	kfree(gpr_b);
-	kfree(gpr_a);
-
-	return !!(i == 100);
-}
-
-int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c)
-{
-	int ctx;
-
-	if (!check_ixp_type(c))
-		return 1;
-
-	if (!(ixp2000_uengine_mask & (1 << uengine)))
-		return 1;
-
-	ixp2000_uengine_reset(1 << uengine);
-	ixp2000_uengine_set_mode(uengine, c->uengine_parameters);
-	if (set_initial_registers(uengine, c))
-		return 1;
-	ixp2000_uengine_load_microcode(uengine, c->insns, c->num_insns);
-
-	for (ctx = 0; ctx < 8; ctx++)
-		ixp2000_uengine_init_context(uengine, ctx, 0);
-
-	return 0;
-}
-EXPORT_SYMBOL(ixp2000_uengine_load);
-
-
-static int __init ixp2000_uengine_init(void)
-{
-	int uengine;
-	u32 value;
-
-	/*
-	 * Determine number of microengines present.
-	 */
-	switch ((ixp2000_reg_read(IXP_PRODUCT_ID) >> 8) & 0x1fff) {
-#ifdef CONFIG_ARCH_IXP2000
-	case 0:		/* IXP2800 */
-	case 1:		/* IXP2850 */
-		ixp2000_uengine_mask = 0x00ff00ff;
-		break;
-
-	case 2:		/* IXP2400 */
-		ixp2000_uengine_mask = 0x000f000f;
-		break;
-#endif
-
-#ifdef CONFIG_ARCH_IXP23XX
-	case 4:		/* IXP23xx */
-		ixp2000_uengine_mask = (*IXP23XX_EXP_CFG_FUSE >> 8) & 0xf;
-		break;
-#endif
-
-	default:
-		printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n",
-			(unsigned int)ixp2000_reg_read(IXP_PRODUCT_ID));
-		ixp2000_uengine_mask = 0x00000000;
-		break;
-	}
-
-	/*
-	 * Reset microengines.
-	 */
-	ixp2000_uengine_reset(ixp2000_uengine_mask);
-
-	/*
-	 * Synchronise timestamp counters across all microengines.
-	 */
-	value = ixp2000_reg_read(IXP_MISC_CONTROL);
-	ixp2000_reg_wrb(IXP_MISC_CONTROL, value & ~0x80);
-	for (uengine = 0; uengine < 32; uengine++) {
-		if (ixp2000_uengine_mask & (1 << uengine)) {
-			ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0);
-			ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0);
-		}
-	}
-	ixp2000_reg_wrb(IXP_MISC_CONTROL, value | 0x80);
-
-	return 0;
-}
-
-subsys_initcall(ixp2000_uengine_init);
diff --git a/arch/arm/configs/armadillo800eva_defconfig b/arch/arm/configs/armadillo800eva_defconfig
new file mode 100644
index 0000000..ddc9fe6
--- /dev/null
+++ b/arch/arm/configs/armadillo800eva_defconfig
@@ -0,0 +1,142 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_SHMOBILE=y
+CONFIG_ARCH_R8A7740=y
+CONFIG_MACH_ARMADILLO800EVA=y
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_ARM_THUMB is not set
+CONFIG_CPU_BPREDICT_DISABLE=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_458693=y
+CONFIG_ARM_ERRATA_460075=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096"
+CONFIG_CMDLINE_FORCE=y
+CONFIG_KEXEC=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+CONFIG_SH_ETH=y
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ST1232=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=8
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_SH_MOBILE=y
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_SH_MOBILE_LCDC=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SH4_FSI=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_RENESAS_USBHS=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_RENESAS_USBHS_UDC=y
+CONFIG_USB_ETH=m
+CONFIG_MMC=y
+CONFIG_MMC_SDHI=y
+CONFIG_MMC_SH_MMCIF=y
+CONFIG_UIO=y
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_DNOTIFY is not set
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_ARM_UNWIND is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_XZ_DEC=y
diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
new file mode 100644
index 0000000..67bc571
--- /dev/null
+++ b/arch/arm/configs/at91_dt_defconfig
@@ -0,0 +1,196 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_AT91=y
+CONFIG_SOC_AT91SAM9260=y
+CONFIG_SOC_AT91SAM9263=y
+CONFIG_SOC_AT91SAM9G45=y
+CONFIG_SOC_AT91SAM9X5=y
+CONFIG_MACH_AT91SAM_DT=y
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_AT91_TIMER_HZ=128
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_CPU=y
+CONFIG_UACCESS_WITH_MEMCPY=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw"
+CONFIG_KEXEC=y
+CONFIG_AUTO_ZRELADDR=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+CONFIG_IPV6_SIT_6RD=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_GLUEBI=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_ATMEL_PWM=y
+CONFIG_ATMEL_TCLIB=y
+CONFIG_EEPROM_93CX6=m
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_MACB=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+CONFIG_DAVICOM_PHY=y
+CONFIG_MICREL_PHY=y
+# CONFIG_WLAN is not set
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=480
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=272
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_SERIO is not set
+CONFIG_LEGACY_PTY_COUNT=4
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_GPIO=y
+CONFIG_SPI=y
+CONFIG_SPI_ATMEL=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
+CONFIG_SSB=m
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_ATMEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_ATMEL_LCDC=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_ACORN_8x8=y
+CONFIG_FONT_MINI_4x6=y
+CONFIG_LOGO=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_AT91=m
+CONFIG_USB_ATMEL_USBA=m
+CONFIG_USB_ETH=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_ACM_MS=m
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_MULTI_CDC=y
+CONFIG_MMC=y
+CONFIG_MMC_ATMELMCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_AT91RM9200=y
+CONFIG_RTC_DRV_AT91SAM9=y
+CONFIG_DMADEVICES=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_FANOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC7=m
+CONFIG_AVERAGE=y
diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig
index bbe4e1a..d54e2ac 100644
--- a/arch/arm/configs/at91rm9200_defconfig
+++ b/arch/arm/configs/at91rm9200_defconfig
@@ -14,6 +14,7 @@
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARCH_AT91=y
+CONFIG_ARCH_AT91RM9200=y
 CONFIG_MACH_ONEARM=y
 CONFIG_ARCH_AT91RM9200DK=y
 CONFIG_MACH_AT91RM9200EK=y
diff --git a/arch/arm/configs/bcmring_defconfig b/arch/arm/configs/bcmring_defconfig
index 795374d..9e6a8fe1 100644
--- a/arch/arm/configs/bcmring_defconfig
+++ b/arch/arm/configs/bcmring_defconfig
@@ -11,7 +11,7 @@
 # CONFIG_TIMERFD is not set
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig
index 6b31cb6..09a0296 100644
--- a/arch/arm/configs/imx_v4_v5_defconfig
+++ b/arch/arm/configs/imx_v4_v5_defconfig
@@ -92,6 +92,7 @@
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_MC13783=m
 # CONFIG_SERIO is not set
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=m
@@ -107,7 +108,8 @@
 CONFIG_W1=y
 CONFIG_W1_MASTER_MXC=y
 CONFIG_W1_SLAVE_THERM=y
-# CONFIG_HWMON is not set
+CONFIG_HWMON=m
+CONFIG_SENSORS_MC13783_ADC=m
 CONFIG_WATCHDOG=y
 CONFIG_IMX2_WDT=y
 CONFIG_MFD_MC13XXX=y
diff --git a/arch/arm/configs/ixp2000_defconfig b/arch/arm/configs/ixp2000_defconfig
deleted file mode 100644
index 8405ade..0000000
--- a/arch/arm/configs/ixp2000_defconfig
+++ /dev/null
@@ -1,99 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_ARCH_IXP2000=y
-CONFIG_ARCH_ENP2611=y
-CONFIG_ARCH_IXDP2400=y
-CONFIG_ARCH_IXDP2800=y
-CONFIG_ARCH_IXDP2401=y
-CONFIG_ARCH_IXDP2801=y
-# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
-# CONFIG_ARM_THUMB is not set
-CONFIG_CPU_BIG_ENDIAN=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0"
-CONFIG_FPE_NWFPE=y
-CONFIG_FPE_NWFPE_XP=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_SYN_COOKIES=y
-CONFIG_IPV6=y
-# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET6_XFRM_MODE_BEET is not set
-# CONFIG_IPV6_SIT is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_IXP2000=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_EEPROM_LEGACY=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_CS89x0=y
-CONFIG_E100=y
-CONFIG_ENP2611_MSF_NET=y
-CONFIG_WAN=y
-CONFIG_HDLC=y
-CONFIG_HDLC_RAW=y
-CONFIG_HDLC_CISCO=y
-CONFIG_HDLC_FR=y
-CONFIG_HDLC_PPP=y
-CONFIG_DLCI=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=3
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_IXP2000=y
-CONFIG_WATCHDOG=y
-CONFIG_IXP2000_WATCHDOG=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
diff --git a/arch/arm/configs/ixp23xx_defconfig b/arch/arm/configs/ixp23xx_defconfig
deleted file mode 100644
index 6887176..0000000
--- a/arch/arm/configs/ixp23xx_defconfig
+++ /dev/null
@@ -1,105 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_ARCH_IXP23XX=y
-CONFIG_MACH_ESPRESSO=y
-CONFIG_MACH_IXDP2351=y
-CONFIG_MACH_ROADRUNNER=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_CPU_BIG_ENDIAN=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp"
-CONFIG_FPE_NWFPE=y
-CONFIG_FPE_NWFPE_XP=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_SYN_COOKIES=y
-CONFIG_IPV6=y
-# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET6_XFRM_MODE_BEET is not set
-# CONFIG_IPV6_SIT is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_FW_LOADER is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_EEPROM_LEGACY=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_SIIMAGE=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_E100=y
-CONFIG_E1000=y
-CONFIG_WAN=y
-CONFIG_HDLC=y
-CONFIG_HDLC_RAW=y
-CONFIG_HDLC_CISCO=y
-CONFIG_HDLC_FR=y
-CONFIG_HDLC_PPP=y
-CONFIG_DLCI=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_WATCHDOG=y
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_MON=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_UHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_INOTIFY=y
-CONFIG_MSDOS_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig
new file mode 100644
index 0000000..e3ebc20
--- /dev/null
+++ b/arch/arm/configs/kzm9g_defconfig
@@ -0,0 +1,139 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_SHMOBILE=y
+CONFIG_KEYBOARD_GPIO_POLLED=y
+CONFIG_ARCH_SH73A0=y
+CONFIG_MACH_KZM9G=y
+CONFIG_MEMORY_START=0x41000000
+CONFIG_MEMORY_SIZE=0x1f000000
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel earlyprintk=sh-sci.4,115200"
+CONFIG_KEXEC=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_IRDA=y
+CONFIG_SH_IRDA=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC911X=y
+# CONFIG_WLAN is not set
+CONFIG_INPUT_SPARSEKMAP=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ST1232=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=9
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_SH_MOBILE=y
+CONFIG_GPIO_PCF857X=y
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+CONFIG_FB_SH_MOBILE_LCDC=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_FB_SH_MOBILE_MERAM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SH4_FSI=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_R8A66597_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_SDHI=y
+CONFIG_MMC_SH_MMCIF=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_SH_DMAE=y
+CONFIG_ASYNC_TX_DMA=y
+CONFIG_STAGING=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+# CONFIG_ARM_UNWIND is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRC16=y
diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
index fb20881..4fa6054 100644
--- a/arch/arm/configs/lpc32xx_defconfig
+++ b/arch/arm/configs/lpc32xx_defconfig
@@ -2,7 +2,7 @@
 CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
+CONFIG_LOG_BUF_SHIFT=16
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
@@ -10,6 +10,7 @@
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
+CONFIG_JUMP_LABEL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
@@ -21,6 +22,8 @@
 CONFIG_AEABI=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CMDLINE="console=ttyS0,115200n81 root=/dev/ram0"
 CONFIG_CPU_IDLE=y
 CONFIG_FPE_NWFPE=y
@@ -40,7 +43,8 @@
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
 # CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
@@ -55,13 +59,24 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=1
 CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_MISC_DEVICES=y
 CONFIG_EEPROM_AT25=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_NETDEVICES=y
 CONFIG_MII=y
-CONFIG_PHYLIB=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+CONFIG_LPC_ENET=y
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 CONFIG_SMSC_PHY=y
 # CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
@@ -97,16 +112,22 @@
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
+CONFIG_SND_DEBUG=y
+CONFIG_SND_DEBUG_VERBOSE=y
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_ARM is not set
 # CONFIG_SND_SPI is not set
 CONFIG_SND_SOC=y
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
+CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_STORAGE=y
-CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_LPC32XX=y
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_ARMMMCI=y
@@ -114,10 +135,21 @@
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_RTC_DRV_DS1374=y
+CONFIG_RTC_DRV_PCF8563=y
 CONFIG_RTC_DRV_LPC32XX=y
+CONFIG_DMADEVICES=y
+CONFIG_AMBA_PL08X=y
+CONFIG_STAGING=y
+CONFIG_IIO=y
+CONFIG_LPC32XX_ADC=y
 CONFIG_EXT2_FS=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_MSDOS_FS=y
diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig
index 37207d1..bf123c5 100644
--- a/arch/arm/configs/nhk8815_defconfig
+++ b/arch/arm/configs/nhk8815_defconfig
@@ -97,6 +97,7 @@
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_GPIO=y
 CONFIG_DEBUG_GPIO=y
+CONFIG_PINCTRL_NOMADIK=y
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_RTC_CLASS=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index d5f00d7..9854ff4 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -98,6 +98,7 @@
 CONFIG_LIBERTAS_SDIO=m
 CONFIG_LIBERTAS_DEBUG=y
 CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC95XX=y
 CONFIG_USB_ALI_M5632=y
 CONFIG_USB_AN2720=y
 CONFIG_USB_EPSON2888=y
@@ -175,6 +176,7 @@
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_WDM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_LIBUSUAL=y
diff --git a/arch/arm/configs/spear3xx_defconfig b/arch/arm/configs/spear3xx_defconfig
index fea7e1f..7ed4291 100644
--- a/arch/arm/configs/spear3xx_defconfig
+++ b/arch/arm/configs/spear3xx_defconfig
@@ -2,33 +2,67 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_PLAT_SPEAR=y
-CONFIG_BOARD_SPEAR300_EVB=y
-CONFIG_BOARD_SPEAR310_EVB=y
-CONFIG_BOARD_SPEAR320_EVB=y
+CONFIG_MACH_SPEAR300=y
+CONFIG_MACH_SPEAR310=y
+CONFIG_MACH_SPEAR320=y
 CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_FSMC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_STMMAC_ETH=y
+# CONFIG_WLAN is not set
 CONFIG_INPUT_FF_MEMLESS=y
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_SPEAR=y
 # CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=8192
+CONFIG_I2C=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_PL061=y
 # CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
 # CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_SPEAR=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_AMBA_PL08X=y
+CONFIG_DMATEST=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_SECURITY=y
@@ -39,8 +73,6 @@
 CONFIG_VFAT_FS=m
 CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
 CONFIG_TMPFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=m
@@ -48,6 +80,4 @@
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_CRC32 is not set
diff --git a/arch/arm/configs/spear6xx_defconfig b/arch/arm/configs/spear6xx_defconfig
index cef2e83..cf94bc7 100644
--- a/arch/arm/configs/spear6xx_defconfig
+++ b/arch/arm/configs/spear6xx_defconfig
@@ -2,29 +2,58 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_PLAT_SPEAR=y
 CONFIG_ARCH_SPEAR6XX=y
-CONFIG_BOARD_SPEAR600_EVB=y
+CONFIG_BOARD_SPEAR600_DT=y
 CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_FSMC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_STMMAC_ETH=y
+# CONFIG_WLAN is not set
 CONFIG_INPUT_FF_MEMLESS=y
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=8192
+CONFIG_I2C=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_PL061=y
 # CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
 # CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_AMBA_PL08X=y
+CONFIG_DMATEST=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_SECURITY=y
@@ -35,8 +64,6 @@
 CONFIG_VFAT_FS=m
 CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
 CONFIG_TMPFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=m
@@ -44,6 +71,4 @@
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_CRC32 is not set
diff --git a/arch/arm/include/asm/hardware/clps7111.h b/arch/arm/include/asm/hardware/clps7111.h
deleted file mode 100644
index 4447722..0000000
--- a/arch/arm/include/asm/hardware/clps7111.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- *  arch/arm/include/asm/hardware/clps7111.h
- *
- *  This file contains the hardware definitions of the CLPS7111 internal
- *  registers.
- *
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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 __ASM_HARDWARE_CLPS7111_H
-#define __ASM_HARDWARE_CLPS7111_H
-
-#define CLPS7111_PHYS_BASE	(0x80000000)
-
-#ifndef __ASSEMBLY__
-#define clps_readb(off)		__raw_readb(CLPS7111_BASE + (off))
-#define clps_readw(off)		__raw_readw(CLPS7111_BASE + (off))
-#define clps_readl(off)		__raw_readl(CLPS7111_BASE + (off))
-#define clps_writeb(val,off)	__raw_writeb(val, CLPS7111_BASE + (off))
-#define clps_writew(val,off)	__raw_writew(val, CLPS7111_BASE + (off))
-#define clps_writel(val,off)	__raw_writel(val, CLPS7111_BASE + (off))
-#endif
-
-#define PADR		(0x0000)
-#define PBDR		(0x0001)
-#define PDDR		(0x0003)
-#define PADDR		(0x0040)
-#define PBDDR		(0x0041)
-#define PDDDR		(0x0043)
-#define PEDR		(0x0080)
-#define PEDDR		(0x00c0)
-#define SYSCON1		(0x0100)
-#define SYSFLG1		(0x0140)
-#define MEMCFG1		(0x0180)
-#define MEMCFG2		(0x01c0)
-#define DRFPR		(0x0200)
-#define INTSR1		(0x0240)
-#define INTMR1		(0x0280)
-#define LCDCON		(0x02c0)
-#define TC1D            (0x0300)
-#define TC2D		(0x0340)
-#define RTCDR		(0x0380)
-#define RTCMR		(0x03c0)
-#define PMPCON		(0x0400)
-#define CODR		(0x0440)
-#define UARTDR1		(0x0480)
-#define UBRLCR1		(0x04c0)
-#define SYNCIO		(0x0500)
-#define PALLSW		(0x0540)
-#define PALMSW		(0x0580)
-#define STFCLR		(0x05c0)
-#define BLEOI		(0x0600)
-#define MCEOI		(0x0640)
-#define TEOI		(0x0680)
-#define TC1EOI		(0x06c0)
-#define TC2EOI		(0x0700)
-#define RTCEOI		(0x0740)
-#define UMSEOI		(0x0780)
-#define COEOI		(0x07c0)
-#define HALT		(0x0800)
-#define STDBY		(0x0840)
-
-#define FBADDR		(0x1000)
-#define SYSCON2		(0x1100)
-#define SYSFLG2		(0x1140)
-#define INTSR2		(0x1240)
-#define INTMR2		(0x1280)
-#define UARTDR2		(0x1480)
-#define UBRLCR2		(0x14c0)
-#define SS2DR		(0x1500)
-#define SRXEOF		(0x1600)
-#define SS2POP		(0x16c0)
-#define KBDEOI		(0x1700)
-
-/* common bits: SYSCON1 / SYSCON2 */
-#define SYSCON_UARTEN		(1 << 8)
-
-#define SYSCON1_KBDSCAN(x)	((x) & 15)
-#define SYSCON1_KBDSCANMASK	(15)
-#define SYSCON1_TC1M		(1 << 4)
-#define SYSCON1_TC1S		(1 << 5)
-#define SYSCON1_TC2M		(1 << 6)
-#define SYSCON1_TC2S		(1 << 7)
-#define SYSCON1_UART1EN		SYSCON_UARTEN
-#define SYSCON1_BZTOG		(1 << 9)
-#define SYSCON1_BZMOD		(1 << 10)
-#define SYSCON1_DBGEN		(1 << 11)
-#define SYSCON1_LCDEN		(1 << 12)
-#define SYSCON1_CDENTX		(1 << 13)
-#define SYSCON1_CDENRX		(1 << 14)
-#define SYSCON1_SIREN		(1 << 15)
-#define SYSCON1_ADCKSEL(x)	(((x) & 3) << 16)
-#define SYSCON1_ADCKSEL_MASK	(3 << 16)
-#define SYSCON1_EXCKEN		(1 << 18)
-#define SYSCON1_WAKEDIS		(1 << 19)
-#define SYSCON1_IRTXM		(1 << 20)
-
-/* common bits: SYSFLG1 / SYSFLG2 */
-#define SYSFLG_UBUSY		(1 << 11)
-#define SYSFLG_URXFE		(1 << 22)
-#define SYSFLG_UTXFF		(1 << 23)
-
-#define SYSFLG1_MCDR		(1 << 0)
-#define SYSFLG1_DCDET		(1 << 1)
-#define SYSFLG1_WUDR		(1 << 2)
-#define SYSFLG1_WUON		(1 << 3)
-#define SYSFLG1_CTS		(1 << 8)
-#define SYSFLG1_DSR		(1 << 9)
-#define SYSFLG1_DCD		(1 << 10)
-#define SYSFLG1_UBUSY		SYSFLG_UBUSY
-#define SYSFLG1_NBFLG		(1 << 12)
-#define SYSFLG1_RSTFLG		(1 << 13)
-#define SYSFLG1_PFFLG		(1 << 14)
-#define SYSFLG1_CLDFLG		(1 << 15)
-#define SYSFLG1_URXFE		SYSFLG_URXFE
-#define SYSFLG1_UTXFF		SYSFLG_UTXFF
-#define SYSFLG1_CRXFE		(1 << 24)
-#define SYSFLG1_CTXFF		(1 << 25)
-#define SYSFLG1_SSIBUSY		(1 << 26)
-#define SYSFLG1_ID		(1 << 29)
-
-#define SYSFLG2_SSRXOF		(1 << 0)
-#define SYSFLG2_RESVAL		(1 << 1)
-#define SYSFLG2_RESFRM		(1 << 2)
-#define SYSFLG2_SS2RXFE		(1 << 3)
-#define SYSFLG2_SS2TXFF		(1 << 4)
-#define SYSFLG2_SS2TXUF		(1 << 5)
-#define SYSFLG2_CKMODE		(1 << 6)
-#define SYSFLG2_UBUSY		SYSFLG_UBUSY
-#define SYSFLG2_URXFE		SYSFLG_URXFE
-#define SYSFLG2_UTXFF		SYSFLG_UTXFF
-
-#define LCDCON_GSEN		(1 << 30)
-#define LCDCON_GSMD		(1 << 31)
-
-#define SYSCON2_SERSEL		(1 << 0)
-#define SYSCON2_KBD6		(1 << 1)
-#define SYSCON2_DRAMZ		(1 << 2)
-#define SYSCON2_KBWEN		(1 << 3)
-#define SYSCON2_SS2TXEN		(1 << 4)
-#define SYSCON2_PCCARD1		(1 << 5)
-#define SYSCON2_PCCARD2		(1 << 6)
-#define SYSCON2_SS2RXEN		(1 << 7)
-#define SYSCON2_UART2EN		SYSCON_UARTEN
-#define SYSCON2_SS2MAEN		(1 << 9)
-#define SYSCON2_OSTB		(1 << 12)
-#define SYSCON2_CLKENSL		(1 << 13)
-#define SYSCON2_BUZFREQ		(1 << 14)
-
-/* common bits: UARTDR1 / UARTDR2 */
-#define UARTDR_FRMERR		(1 << 8)
-#define UARTDR_PARERR		(1 << 9)
-#define UARTDR_OVERR		(1 << 10)
-
-/* common bits: UBRLCR1 / UBRLCR2 */
-#define UBRLCR_BAUD_MASK	((1 << 12) - 1)
-#define UBRLCR_BREAK		(1 << 12)
-#define UBRLCR_PRTEN		(1 << 13)
-#define UBRLCR_EVENPRT		(1 << 14)
-#define UBRLCR_XSTOP		(1 << 15)
-#define UBRLCR_FIFOEN		(1 << 16)
-#define UBRLCR_WRDLEN5		(0 << 17)
-#define UBRLCR_WRDLEN6		(1 << 17)
-#define UBRLCR_WRDLEN7		(2 << 17)
-#define UBRLCR_WRDLEN8		(3 << 17)
-#define UBRLCR_WRDLEN_MASK	(3 << 17)
-
-#define SYNCIO_SMCKEN		(1 << 13)
-#define SYNCIO_TXFRMEN		(1 << 14)
-
-#endif /* __ASM_HARDWARE_CLPS7111_H */
diff --git a/arch/arm/include/asm/hardware/cs89712.h b/arch/arm/include/asm/hardware/cs89712.h
deleted file mode 100644
index f756269..0000000
--- a/arch/arm/include/asm/hardware/cs89712.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *  arch/arm/include/asm/hardware/cs89712.h
- *
- *  This file contains the hardware definitions of the CS89712
- *  additional internal registers.
- *
- *  Copyright (C) 2001 Thomas Gleixner autronix automation <gleixner@autronix.de>
- *			
- *
- * 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 __ASM_HARDWARE_CS89712_H
-#define __ASM_HARDWARE_CS89712_H
-
-/*
-*	CS89712 additional registers
-*/
-                                  
-#define PCDR			0x0002	/* Port C Data register ---------------------------- */
-#define PCDDR			0x0042	/* Port C Data Direction register ------------------ */
-#define SDCONF			0x2300  /* SDRAM Configuration register ---------------------*/
-#define SDRFPR			0x2340  /* SDRAM Refresh period register --------------------*/
-
-#define SDCONF_ACTIVE		(1 << 10)
-#define SDCONF_CLKCTL		(1 << 9)
-#define SDCONF_WIDTH_4		(0 << 7)
-#define SDCONF_WIDTH_8		(1 << 7)
-#define SDCONF_WIDTH_16		(2 << 7)
-#define SDCONF_WIDTH_32		(3 << 7)
-#define SDCONF_SIZE_16		(0 << 5)
-#define SDCONF_SIZE_64		(1 << 5)
-#define SDCONF_SIZE_128		(2 << 5)
-#define SDCONF_SIZE_256		(3 << 5)
-#define SDCONF_CASLAT_2		(2)
-#define SDCONF_CASLAT_3		(3)
-
-#endif /* __ASM_HARDWARE_CS89712_H */
diff --git a/arch/arm/include/asm/hardware/ep7211.h b/arch/arm/include/asm/hardware/ep7211.h
deleted file mode 100644
index 654d5f6..0000000
--- a/arch/arm/include/asm/hardware/ep7211.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *  arch/arm/include/asm/hardware/ep7211.h
- *
- *  This file contains the hardware definitions of the EP7211 internal
- *  registers.
- *
- *  Copyright (C) 2001 Blue Mug, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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 __ASM_HARDWARE_EP7211_H
-#define __ASM_HARDWARE_EP7211_H
-
-#include <asm/hardware/clps7111.h>
-
-/*
- * define EP7211_BASE to be the base address of the region
- * you want to access.
- */
-
-#define EP7211_PHYS_BASE	(0x80000000)
-
-/*
- * XXX miket@bluemug.com: need to introduce EP7211 registers (those not
- * present in 7212) here.
- */
-
-#endif /* __ASM_HARDWARE_EP7211_H */
diff --git a/arch/arm/include/asm/hardware/ep7212.h b/arch/arm/include/asm/hardware/ep7212.h
deleted file mode 100644
index 3b43bbe..0000000
--- a/arch/arm/include/asm/hardware/ep7212.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *  arch/arm/include/asm/hardware/ep7212.h
- *
- *  This file contains the hardware definitions of the EP7212 internal
- *  registers.
- *
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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 __ASM_HARDWARE_EP7212_H
-#define __ASM_HARDWARE_EP7212_H
-
-/*
- * define EP7212_BASE to be the base address of the region
- * you want to access.
- */
-
-#define EP7212_PHYS_BASE	(0x80000000)
-
-#ifndef __ASSEMBLY__
-#define ep_readl(off)		__raw_readl(EP7212_BASE + (off))
-#define ep_writel(val,off)	__raw_writel(val, EP7212_BASE + (off))
-#endif
-
-/*
- * These registers are specific to the EP7212 only
- */
-#define DAIR			0x2000
-#define DAIR0			0x2040
-#define DAIDR1			0x2080
-#define DAIDR2			0x20c0
-#define DAISR			0x2100
-#define SYSCON3			0x2200
-#define INTSR3			0x2240
-#define INTMR3			0x2280
-#define LEDFLSH			0x22c0
-
-#define DAIR_DAIEN		(1 << 16)
-#define DAIR_ECS		(1 << 17)
-#define DAIR_LCTM		(1 << 19)
-#define DAIR_LCRM		(1 << 20)
-#define DAIR_RCTM		(1 << 21)
-#define DAIR_RCRM		(1 << 22)
-#define DAIR_LBM		(1 << 23)
-
-#define DAIDR2_FIFOEN		(1 << 15)
-#define DAIDR2_FIFOLEFT		(0x0d << 16)
-#define DAIDR2_FIFORIGHT	(0x11 << 16)
-
-#define DAISR_RCTS		(1 << 0)
-#define DAISR_RCRS		(1 << 1)
-#define DAISR_LCTS		(1 << 2)
-#define DAISR_LCRS		(1 << 3)
-#define DAISR_RCTU		(1 << 4)
-#define DAISR_RCRO		(1 << 5)
-#define DAISR_LCTU		(1 << 6)
-#define DAISR_LCRO		(1 << 7)
-#define DAISR_RCNF		(1 << 8)
-#define DAISR_RCNE		(1 << 9)
-#define DAISR_LCNF		(1 << 10)
-#define DAISR_LCNE		(1 << 11)
-#define DAISR_FIFO		(1 << 12)
-
-#define SYSCON3_ADCCON		(1 << 0)
-#define SYSCON3_DAISEL		(1 << 3)
-#define SYSCON3_ADCCKNSEN	(1 << 4)
-#define SYSCON3_FASTWAKE	(1 << 8)
-#define SYSCON3_DAIEN		(1 << 9)
-
-#endif /* __ASM_HARDWARE_EP7212_H */
diff --git a/arch/arm/include/asm/hardware/uengine.h b/arch/arm/include/asm/hardware/uengine.h
deleted file mode 100644
index b442d65..0000000
--- a/arch/arm/include/asm/hardware/uengine.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Generic library functions for the microengines found on the Intel
- * IXP2000 series of network processors.
- *
- * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
- * Dedicated to Marija Kulikova.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version.
- */
-
-#ifndef __IXP2000_UENGINE_H
-#define __IXP2000_UENGINE_H
-
-extern u32 ixp2000_uengine_mask;
-
-struct ixp2000_uengine_code
-{
-	u32	cpu_model_bitmask;
-	u8	cpu_min_revision;
-	u8	cpu_max_revision;
-
-	u32	uengine_parameters;
-
-	struct ixp2000_reg_value {
-		int	reg;
-		u32	value;
-	} *initial_reg_values;
-
-	int	num_insns;
-	u8	*insns;
-};
-
-u32 ixp2000_uengine_csr_read(int uengine, int offset);
-void ixp2000_uengine_csr_write(int uengine, int offset, u32 value);
-void ixp2000_uengine_reset(u32 uengine_mask);
-void ixp2000_uengine_set_mode(int uengine, u32 mode);
-void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns);
-void ixp2000_uengine_init_context(int uengine, int context, int pc);
-void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask);
-void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask);
-int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c);
-
-#define IXP2000_UENGINE_8_CONTEXTS		0x00000000
-#define IXP2000_UENGINE_4_CONTEXTS		0x80000000
-#define IXP2000_UENGINE_PRN_UPDATE_EVERY	0x40000000
-#define IXP2000_UENGINE_PRN_UPDATE_ON_ACCESS	0x00000000
-#define IXP2000_UENGINE_NN_FROM_SELF		0x00100000
-#define IXP2000_UENGINE_NN_FROM_PREVIOUS	0x00000000
-#define IXP2000_UENGINE_ASSERT_EMPTY_AT_3	0x000c0000
-#define IXP2000_UENGINE_ASSERT_EMPTY_AT_2	0x00080000
-#define IXP2000_UENGINE_ASSERT_EMPTY_AT_1	0x00040000
-#define IXP2000_UENGINE_ASSERT_EMPTY_AT_0	0x00000000
-#define IXP2000_UENGINE_LM_ADDR1_GLOBAL		0x00020000
-#define IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT	0x00000000
-#define IXP2000_UENGINE_LM_ADDR0_GLOBAL		0x00010000
-#define IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT	0x00000000
-
-
-#endif
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index d7038fa..99afa74 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -77,9 +77,6 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 unsigned long get_wchan(struct task_struct *p);
 
 #if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327)
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index b78af0c..ab627a7 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -489,8 +489,6 @@
 	 */
 	armv6_pmcr_write(pmcr);
 
-	perf_sample_data_init(&data, 0);
-
 	cpuc = &__get_cpu_var(cpu_hw_events);
 	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
 		struct perf_event *event = cpuc->events[idx];
@@ -509,7 +507,7 @@
 
 		hwc = &event->hw;
 		armpmu_event_update(event, hwc, idx);
-		data.period = event->hw.last_period;
+		perf_sample_data_init(&data, 0, hwc->last_period);
 		if (!armpmu_event_set_period(event, hwc, idx))
 			continue;
 
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 00755d8..d3c5360 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1077,8 +1077,6 @@
 	 */
 	regs = get_irq_regs();
 
-	perf_sample_data_init(&data, 0);
-
 	cpuc = &__get_cpu_var(cpu_hw_events);
 	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
 		struct perf_event *event = cpuc->events[idx];
@@ -1097,7 +1095,7 @@
 
 		hwc = &event->hw;
 		armpmu_event_update(event, hwc, idx);
-		data.period = event->hw.last_period;
+		perf_sample_data_init(&data, 0, hwc->last_period);
 		if (!armpmu_event_set_period(event, hwc, idx))
 			continue;
 
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 71a21e6..e34e725 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -248,8 +248,6 @@
 
 	regs = get_irq_regs();
 
-	perf_sample_data_init(&data, 0);
-
 	cpuc = &__get_cpu_var(cpu_hw_events);
 	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
 		struct perf_event *event = cpuc->events[idx];
@@ -263,7 +261,7 @@
 
 		hwc = &event->hw;
 		armpmu_event_update(event, hwc, idx);
-		data.period = event->hw.last_period;
+		perf_sample_data_init(&data, 0, hwc->last_period);
 		if (!armpmu_event_set_period(event, hwc, idx))
 			continue;
 
@@ -588,8 +586,6 @@
 
 	regs = get_irq_regs();
 
-	perf_sample_data_init(&data, 0);
-
 	cpuc = &__get_cpu_var(cpu_hw_events);
 	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
 		struct perf_event *event = cpuc->events[idx];
@@ -603,7 +599,7 @@
 
 		hwc = &event->hw;
 		armpmu_event_update(event, hwc, idx);
-		data.period = event->hw.last_period;
+		perf_sample_data_init(&data, 0, hwc->last_period);
 		if (!armpmu_event_set_period(event, hwc, idx))
 			continue;
 
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 73d9a42..4e5fdd9 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -67,17 +67,8 @@
 asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
 {
 	sigset_t blocked;
-
-	current->saved_sigmask = current->blocked;
-
-	mask &= _BLOCKABLE;
 	siginitset(&blocked, mask);
-	set_current_blocked(&blocked);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_restore_sigmask();
-	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 asmlinkage int 
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
index af0aaeb..3e94811 100644
--- a/arch/arm/kernel/sys_oabi-compat.c
+++ b/arch/arm/kernel/sys_oabi-compat.c
@@ -124,8 +124,8 @@
 	tmp.__st_ino = stat->ino;
 	tmp.st_mode = stat->mode;
 	tmp.st_nlink = stat->nlink;
-	tmp.st_uid = stat->uid;
-	tmp.st_gid = stat->gid;
+	tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
+	tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
 	tmp.st_rdev = huge_encode_dev(stat->rdev);
 	tmp.st_size = stat->size;
 	tmp.st_blocks = stat->blocks;
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 45db05d..19505c0 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -9,15 +9,6 @@
 config HAVE_AT91_DBGU1
 	bool
 
-config HAVE_AT91_USART3
-	bool
-
-config HAVE_AT91_USART4
-	bool
-
-config HAVE_AT91_USART5
-	bool
-
 config AT91_SAM9_ALT_RESET
 	bool
 	default !ARCH_AT91X40
@@ -26,87 +17,129 @@
 	bool
 	default !ARCH_AT91X40
 
+config SOC_AT91SAM9
+	bool
+	select GENERIC_CLOCKEVENTS
+	select CPU_ARM926T
+
 menu "Atmel AT91 System-on-Chip"
 
-choice
-	prompt "Atmel AT91 Processor"
+comment "Atmel AT91 Processor"
 
-config ARCH_AT91RM9200
+config SOC_AT91SAM9
+	bool
+	select CPU_ARM926T
+	select AT91_SAM9_TIME
+	select AT91_SAM9_SMC
+
+config SOC_AT91RM9200
 	bool "AT91RM9200"
 	select CPU_ARM920T
 	select GENERIC_CLOCKEVENTS
 	select HAVE_AT91_DBGU0
-	select HAVE_AT91_USART3
+
+config SOC_AT91SAM9260
+	bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
+	select SOC_AT91SAM9
+	select HAVE_AT91_DBGU0
+	select HAVE_NET_MACB
+	help
+	  Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE
+	  or AT91SAM9G20 SoC.
+
+config SOC_AT91SAM9261
+	bool "AT91SAM9261 or AT91SAM9G10"
+	select SOC_AT91SAM9
+	select HAVE_AT91_DBGU0
+	select HAVE_FB_ATMEL
+	help
+	  Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC.
+
+config SOC_AT91SAM9263
+	bool "AT91SAM9263"
+	select SOC_AT91SAM9
+	select HAVE_AT91_DBGU1
+	select HAVE_FB_ATMEL
+	select HAVE_NET_MACB
+
+config SOC_AT91SAM9RL
+	bool "AT91SAM9RL"
+	select SOC_AT91SAM9
+	select HAVE_AT91_DBGU0
+	select HAVE_FB_ATMEL
+
+config SOC_AT91SAM9G45
+	bool "AT91SAM9G45 or AT91SAM9M10 families"
+	select SOC_AT91SAM9
+	select HAVE_AT91_DBGU1
+	select HAVE_FB_ATMEL
+	select HAVE_NET_MACB
+	help
+	  Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
+	  This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
+
+config SOC_AT91SAM9X5
+	bool "AT91SAM9x5 family"
+	select SOC_AT91SAM9
+	select HAVE_AT91_DBGU0
+	select HAVE_FB_ATMEL
+	select HAVE_NET_MACB
+	help
+	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
+	  This means that your SAM9 name finishes with a '5' (except if it is
+	  AT91SAM9G45!).
+	  This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35
+	  and AT91SAM9X35.
+
+config SOC_AT91SAM9N12
+	bool "AT91SAM9N12 family"
+	select SOC_AT91SAM9
+	select HAVE_AT91_DBGU0
+	select HAVE_FB_ATMEL
+	help
+	  Select this if you are using Atmel's AT91SAM9N12 SoC.
+
+choice
+	prompt "Atmel AT91 Processor Devices for non DT boards"
+
+config ARCH_AT91_NONE
+	bool "None"
+
+config ARCH_AT91RM9200
+	bool "AT91RM9200"
+	select SOC_AT91RM9200
 
 config ARCH_AT91SAM9260
 	bool "AT91SAM9260 or AT91SAM9XE"
-	select CPU_ARM926T
-	select GENERIC_CLOCKEVENTS
-	select HAVE_AT91_DBGU0
-	select HAVE_AT91_USART3
-	select HAVE_AT91_USART4
-	select HAVE_AT91_USART5
-	select HAVE_NET_MACB
+	select SOC_AT91SAM9260
 
 config ARCH_AT91SAM9261
 	bool "AT91SAM9261"
-	select CPU_ARM926T
-	select GENERIC_CLOCKEVENTS
-	select HAVE_FB_ATMEL
-	select HAVE_AT91_DBGU0
+	select SOC_AT91SAM9261
 
 config ARCH_AT91SAM9G10
 	bool "AT91SAM9G10"
-	select CPU_ARM926T
-	select GENERIC_CLOCKEVENTS
-	select HAVE_AT91_DBGU0
-	select HAVE_FB_ATMEL
+	select SOC_AT91SAM9261
 
 config ARCH_AT91SAM9263
 	bool "AT91SAM9263"
-	select CPU_ARM926T
-	select GENERIC_CLOCKEVENTS
-	select HAVE_FB_ATMEL
-	select HAVE_NET_MACB
-	select HAVE_AT91_DBGU1
+	select SOC_AT91SAM9263
 
 config ARCH_AT91SAM9RL
 	bool "AT91SAM9RL"
-	select CPU_ARM926T
-	select GENERIC_CLOCKEVENTS
-	select HAVE_AT91_USART3
-	select HAVE_FB_ATMEL
-	select HAVE_AT91_DBGU0
+	select SOC_AT91SAM9RL
 
 config ARCH_AT91SAM9G20
 	bool "AT91SAM9G20"
-	select CPU_ARM926T
-	select GENERIC_CLOCKEVENTS
-	select HAVE_AT91_DBGU0
-	select HAVE_AT91_USART3
-	select HAVE_AT91_USART4
-	select HAVE_AT91_USART5
-	select HAVE_NET_MACB
+	select SOC_AT91SAM9260
 
 config ARCH_AT91SAM9G45
 	bool "AT91SAM9G45"
-	select CPU_ARM926T
-	select GENERIC_CLOCKEVENTS
-	select HAVE_AT91_USART3
-	select HAVE_FB_ATMEL
-	select HAVE_NET_MACB
-	select HAVE_AT91_DBGU1
-
-config ARCH_AT91SAM9X5
-	bool "AT91SAM9x5 family"
-	select CPU_ARM926T
-	select GENERIC_CLOCKEVENTS
-	select HAVE_FB_ATMEL
-	select HAVE_NET_MACB
-	select HAVE_AT91_DBGU0
+	select SOC_AT91SAM9G45
 
 config ARCH_AT91X40
 	bool "AT91x40"
+	depends on !MMU
 	select ARCH_USES_GETTIMEOFFSET
 
 endchoice
@@ -364,6 +397,7 @@
 	  Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
 	  with 2 SD/MMC Slots. This is the case for AT91SAM9G20-EK rev. C and
 	  onwards.
+	  <http://www.atmel.com/tools/SAM9G20-EK.aspx>
 
 config MACH_CPU9G20
 	bool "Eukrea CPU9G20 board"
@@ -433,9 +467,10 @@
 config MACH_AT91SAM9M10G45EK
 	bool "Atmel AT91SAM9M10G45-EK Evaluation Kits"
 	help
-	  Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit.
-	  "ES" at the end of the name means that this board is an
-	  Engineering Sample.
+	  Select this if you are using Atmel's AT91SAM9M10G45-EK Evaluation Kit.
+	  Those boards can be populated with any SoC of AT91SAM9G45 or AT91SAM9M10
+	  families: AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
+	  <http://www.atmel.com/tools/SAM9M10-G45-EK.aspx>
 
 endif
 
@@ -515,41 +550,6 @@
 	  system clock (of at least several MHz), rounding is less of a
 	  problem so it can be safer to use a decimal values like 100.
 
-choice
-	prompt "Select a UART for early kernel messages"
-
-config AT91_EARLY_DBGU0
-	bool "DBGU on rm9200, 9260/9g20, 9261/9g10 and 9rl"
-	depends on HAVE_AT91_DBGU0
-
-config AT91_EARLY_DBGU1
-	bool "DBGU on 9263 and 9g45"
-	depends on HAVE_AT91_DBGU1
-
-config AT91_EARLY_USART0
-	bool "USART0"
-
-config AT91_EARLY_USART1
-	bool "USART1"
-
-config AT91_EARLY_USART2
-	bool "USART2"
-	depends on ! ARCH_AT91X40
-
-config AT91_EARLY_USART3
-	bool "USART3"
-	depends on HAVE_AT91_USART3
-
-config AT91_EARLY_USART4
-	bool "USART4"
-	depends on HAVE_AT91_USART4
-
-config AT91_EARLY_USART5
-	bool "USART5"
-	depends on HAVE_AT91_USART5
-
-endchoice
-
 endmenu
 
 endif
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 8512e53..3bb7a51 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -10,17 +10,26 @@
 obj-$(CONFIG_AT91_PMC_UNIT)	+= clock.o
 obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
 obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
+obj-$(CONFIG_SOC_AT91SAM9)	+= at91sam926x_time.o sam9_smc.o
 
 # CPU-specific support
-obj-$(CONFIG_ARCH_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9260)	+= at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9261)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G10)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9263)	+= at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9RL)	+= at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G20)	+= at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G45)	+= at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9X5)	+= at91sam9x5.o at91sam926x_time.o sam9_smc.o
+obj-$(CONFIG_SOC_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o
+obj-$(CONFIG_SOC_AT91SAM9260)	+= at91sam9260.o
+obj-$(CONFIG_SOC_AT91SAM9261)	+= at91sam9261.o
+obj-$(CONFIG_SOC_AT91SAM9263)	+= at91sam9263.o
+obj-$(CONFIG_SOC_AT91SAM9G45)	+= at91sam9g45.o
+obj-$(CONFIG_SOC_AT91SAM9N12)	+= at91sam9n12.o
+obj-$(CONFIG_SOC_AT91SAM9X5)	+= at91sam9x5.o
+obj-$(CONFIG_SOC_AT91SAM9RL)	+= at91sam9rl.o
+
+obj-$(CONFIG_ARCH_AT91RM9200)	+= at91rm9200_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9260)	+= at91sam9260_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9261)	+= at91sam9261_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9G10)	+= at91sam9261_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9263)	+= at91sam9263_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9RL)	+= at91sam9rl_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9G20)	+= at91sam9260_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9G45)	+= at91sam9g45_devices.o
 obj-$(CONFIG_ARCH_AT91X40)	+= at91x40.o at91x40_time.o
 
 # AT91RM9200 board-specific support
diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
index 0da66ca..9e84fe4 100644
--- a/arch/arm/mach-at91/Makefile.boot
+++ b/arch/arm/mach-at91/Makefile.boot
@@ -14,9 +14,23 @@
 endif
 
 # Keep dtb files sorted alphabetically for each SoC
+# sam9260
+dtb-$(CONFIG_MACH_AT91SAM_DT) += ethernut5.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb
+# sam9263
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9263ek.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9263.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9263.dtb
 # sam9g20
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += kizbox.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb
 dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
 # sam9g45
 dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+# sam9n12
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
 # sam9x5
 dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 8910679..2691768 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -249,18 +249,6 @@
 	clk_register(&pck3);
 }
 
-static struct clk_lookup console_clock_lookup;
-
-void __init at91rm9200_set_console_clock(int id)
-{
-	if (id >= ARRAY_SIZE(usart_clocks_lookups))
-		return;
-
-	console_clock_lookup.con_id = "usart";
-	console_clock_lookup.clk = usart_clocks_lookups[id].clk;
-	clkdev_add(&console_clock_lookup);
-}
-
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 60c4728..e6b7d05 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -1152,14 +1152,6 @@
 		at91_uarts[portnr] = pdev;
 }
 
-void __init at91_set_serial_console(unsigned portnr)
-{
-	if (portnr < ATMEL_MAX_UART) {
-		atmel_default_console_device = at91_uarts[portnr];
-		at91rm9200_set_console_clock(at91_uarts[portnr]->id);
-	}
-}
-
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -1168,13 +1160,9 @@
 		if (at91_uarts[i])
 			platform_device_register(at91_uarts[i]);
 	}
-
-	if (!atmel_default_console_device)
-		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 #else
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 46f7742..2b1e438 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -55,6 +55,13 @@
 	.pmc_mask	= 1 << AT91SAM9260_ID_ADC,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+
+static struct clk adc_op_clk = {
+	.name		= "adc_op_clk",
+	.type		= CLK_TYPE_PERIPHERAL,
+	.rate_hz	= 5000000,
+};
+
 static struct clk usart0_clk = {
 	.name		= "usart0_clk",
 	.pmc_mask	= 1 << AT91SAM9260_ID_US0,
@@ -166,6 +173,7 @@
 	&pioB_clk,
 	&pioC_clk,
 	&adc_clk,
+	&adc_op_clk,
 	&usart0_clk,
 	&usart1_clk,
 	&usart2_clk,
@@ -268,18 +276,6 @@
 	clk_register(&pck1);
 }
 
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9260_set_console_clock(int id)
-{
-	if (id >= ARRAY_SIZE(usart_clocks_lookups))
-		return;
-
-	console_clock_lookup.con_id = "usart";
-	console_clock_lookup.clk = usart_clocks_lookups[id].clk;
-	clkdev_add(&console_clock_lookup);
-}
-
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 5652dde..0ded951 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -17,12 +17,15 @@
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <mach/board.h>
 #include <mach/cpu.h>
 #include <mach/at91sam9260.h>
 #include <mach/at91sam9260_matrix.h>
 #include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
+#include <mach/at91_adc.h>
 
 #include "generic.h"
 
@@ -702,25 +705,8 @@
 	.num_resources	= ARRAY_SIZE(tcb1_resources),
 };
 
-#if defined(CONFIG_OF)
-static struct of_device_id tcb_ids[] = {
-	{ .compatible = "atmel,at91rm9200-tcb" },
-	{ /*sentinel*/ }
-};
-#endif
-
 static void __init at91_add_device_tc(void)
 {
-#if defined(CONFIG_OF)
-	struct device_node *np;
-
-	np = of_find_matching_node(NULL, tcb_ids);
-	if (np) {
-		of_node_put(np);
-		return;
-	}
-#endif
-
 	platform_device_register(&at91sam9260_tcb0_device);
 	platform_device_register(&at91sam9260_tcb1_device);
 }
@@ -1229,14 +1215,6 @@
 		at91_uarts[portnr] = pdev;
 }
 
-void __init at91_set_serial_console(unsigned portnr)
-{
-	if (portnr < ATMEL_MAX_UART) {
-		atmel_default_console_device = at91_uarts[portnr];
-		at91sam9260_set_console_clock(at91_uarts[portnr]->id);
-	}
-}
-
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -1245,13 +1223,9 @@
 		if (at91_uarts[i])
 			platform_device_register(at91_uarts[i]);
 	}
-
-	if (!atmel_default_console_device)
-		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 #else
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
@@ -1369,6 +1343,93 @@
 void __init at91_add_device_cf(struct at91_cf_data * data) {}
 #endif
 
+/* --------------------------------------------------------------------
+ *  ADCs
+ * -------------------------------------------------------------------- */
+
+#if IS_ENABLED(CONFIG_AT91_ADC)
+static struct at91_adc_data adc_data;
+
+static struct resource adc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9260_BASE_ADC,
+		.end	= AT91SAM9260_BASE_ADC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9260_ID_ADC,
+		.end	= AT91SAM9260_ID_ADC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_adc_device = {
+	.name		= "at91_adc",
+	.id		= -1,
+	.dev		= {
+				.platform_data		= &adc_data,
+	},
+	.resource	= adc_resources,
+	.num_resources	= ARRAY_SIZE(adc_resources),
+};
+
+static struct at91_adc_trigger at91_adc_triggers[] = {
+	[0] = {
+		.name = "timer-counter-0",
+		.value = AT91_ADC_TRGSEL_TC0 | AT91_ADC_TRGEN,
+	},
+	[1] = {
+		.name = "timer-counter-1",
+		.value = AT91_ADC_TRGSEL_TC1 | AT91_ADC_TRGEN,
+	},
+	[2] = {
+		.name = "timer-counter-2",
+		.value = AT91_ADC_TRGSEL_TC2 | AT91_ADC_TRGEN,
+	},
+	[3] = {
+		.name = "external",
+		.value = AT91_ADC_TRGSEL_EXTERNAL | AT91_ADC_TRGEN,
+		.is_external = true,
+	},
+};
+
+static struct at91_adc_reg_desc at91_adc_register_g20 = {
+	.channel_base = AT91_ADC_CHR(0),
+	.drdy_mask = AT91_ADC_DRDY,
+	.status_register = AT91_ADC_SR,
+	.trigger_register = AT91_ADC_MR,
+};
+
+void __init at91_add_device_adc(struct at91_adc_data *data)
+{
+	if (!data)
+		return;
+
+	if (test_bit(0, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC0, 0);
+	if (test_bit(1, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC1, 0);
+	if (test_bit(2, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC2, 0);
+	if (test_bit(3, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC3, 0);
+
+	if (data->use_external_triggers)
+		at91_set_A_periph(AT91_PIN_PA22, 0);
+
+	data->num_channels = 4;
+	data->startup_time = 10;
+	data->registers = &at91_adc_register_g20;
+	data->trigger_number = 4;
+	data->trigger_list = at91_adc_triggers;
+
+	adc_data = *data;
+	platform_device_register(&at91_adc_device);
+}
+#else
+void __init at91_add_device_adc(struct at91_adc_data *data) {}
+#endif
+
 /* -------------------------------------------------------------------- */
 /*
  * These devices are always present and don't need any board-specific
@@ -1376,6 +1437,9 @@
  */
 static int __init at91_add_standard_devices(void)
 {
+	if (of_have_populated_dt())
+		return 0;
+
 	at91_add_device_rtt();
 	at91_add_device_watchdog();
 	at91_add_device_tc();
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 7de81e6..c77d503d0 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -239,18 +239,6 @@
 	clk_register(&hck1);
 }
 
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9261_set_console_clock(int id)
-{
-	if (id >= ARRAY_SIZE(usart_clocks_lookups))
-		return;
-
-	console_clock_lookup.con_id = "usart";
-	console_clock_lookup.clk = usart_clocks_lookups[id].clk;
-	clkdev_add(&console_clock_lookup);
-}
-
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 4db961a..9295e90 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -1051,14 +1051,6 @@
 		at91_uarts[portnr] = pdev;
 }
 
-void __init at91_set_serial_console(unsigned portnr)
-{
-	if (portnr < ATMEL_MAX_UART) {
-		atmel_default_console_device = at91_uarts[portnr];
-		at91sam9261_set_console_clock(at91_uarts[portnr]->id);
-	}
-}
-
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -1067,13 +1059,9 @@
 		if (at91_uarts[i])
 			platform_device_register(at91_uarts[i]);
 	}
-
-	if (!atmel_default_console_device)
-		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 #else
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index ef301be..ed91c7e 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -199,6 +199,16 @@
 	CLKDEV_CON_ID("pioC", &pioCDE_clk),
 	CLKDEV_CON_ID("pioD", &pioCDE_clk),
 	CLKDEV_CON_ID("pioE", &pioCDE_clk),
+	/* more usart lookup table for DT entries */
+	CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
+	CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk),
+	CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
+	CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
+	/* more tc lookup table for DT entries */
+	CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb_clk),
+	CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
+	CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
+	CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
@@ -255,18 +265,6 @@
 	clk_register(&pck3);
 }
 
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9263_set_console_clock(int id)
-{
-	if (id >= ARRAY_SIZE(usart_clocks_lookups))
-		return;
-
-	console_clock_lookup.con_id = "usart";
-	console_clock_lookup.clk = usart_clocks_lookups[id].clk;
-	clkdev_add(&console_clock_lookup);
-}
-
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index fe99206..175e000 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -953,8 +953,25 @@
 	.num_resources	= ARRAY_SIZE(tcb_resources),
 };
 
+#if defined(CONFIG_OF)
+static struct of_device_id tcb_ids[] = {
+	{ .compatible = "atmel,at91rm9200-tcb" },
+	{ /*sentinel*/ }
+};
+#endif
+
 static void __init at91_add_device_tc(void)
 {
+#if defined(CONFIG_OF)
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, tcb_ids);
+	if (np) {
+		of_node_put(np);
+		return;
+	}
+#endif
+
 	platform_device_register(&at91sam9263_tcb_device);
 }
 #else
@@ -1461,14 +1478,6 @@
 		at91_uarts[portnr] = pdev;
 }
 
-void __init at91_set_serial_console(unsigned portnr)
-{
-	if (portnr < ATMEL_MAX_UART) {
-		atmel_default_console_device = at91_uarts[portnr];
-		at91sam9263_set_console_clock(at91_uarts[portnr]->id);
-	}
-}
-
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -1477,13 +1486,9 @@
 		if (at91_uarts[i])
 			platform_device_register(at91_uarts[i]);
 	}
-
-	if (!atmel_default_console_device)
-		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 #else
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
@@ -1495,6 +1500,9 @@
  */
 static int __init at91_add_standard_devices(void)
 {
+	if (of_have_populated_dt())
+		return 0;
+
 	at91_add_device_rtt();
 	at91_add_device_watchdog();
 	at91_add_device_tc();
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index d222f83..4792682 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -176,6 +176,12 @@
 	.type		= CLK_TYPE_PERIPHERAL,
 };
 
+static struct clk adc_op_clk = {
+	.name		= "adc_op_clk",
+	.type		= CLK_TYPE_PERIPHERAL,
+	.rate_hz	= 13200000,
+};
+
 static struct clk *periph_clocks[] __initdata = {
 	&pioA_clk,
 	&pioB_clk,
@@ -204,6 +210,7 @@
 	&isi_clk,
 	&udphs_clk,
 	&mmc1_clk,
+	&adc_op_clk,
 	// irq0
 };
 
@@ -242,6 +249,8 @@
 	CLKDEV_CON_ID("pioC", &pioC_clk),
 	CLKDEV_CON_ID("pioD", &pioDE_clk),
 	CLKDEV_CON_ID("pioE", &pioDE_clk),
+	/* Fake adc clock */
+	CLKDEV_CON_ID("adc_clk", &tsc_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
@@ -288,18 +297,6 @@
 	clk_register(&pck1);
 }
 
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9g45_set_console_clock(int id)
-{
-	if (id >= ARRAY_SIZE(usart_clocks_lookups))
-		return;
-
-	console_clock_lookup.con_id = "usart";
-	console_clock_lookup.clk = usart_clocks_lookups[id].clk;
-	clkdev_add(&console_clock_lookup);
-}
-
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 6b008ae..f674724 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -19,9 +19,12 @@
 #include <linux/i2c-gpio.h>
 #include <linux/atmel-mci.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <linux/fb.h>
 #include <video/atmel_lcdc.h>
 
+#include <mach/at91_adc.h>
 #include <mach/board.h>
 #include <mach/at91sam9g45.h>
 #include <mach/at91sam9g45_matrix.h>
@@ -69,15 +72,7 @@
 
 void __init at91_add_device_hdmac(void)
 {
-#if defined(CONFIG_OF)
-	struct device_node *of_node =
-		of_find_node_by_name(NULL, "dma-controller");
-
-	if (of_node)
-		of_node_put(of_node);
-	else
-#endif
-		platform_device_register(&at_hdmac_device);
+	platform_device_register(&at_hdmac_device);
 }
 #else
 void __init at91_add_device_hdmac(void) {}
@@ -1094,25 +1089,8 @@
 	.num_resources	= ARRAY_SIZE(tcb1_resources),
 };
 
-#if defined(CONFIG_OF)
-static struct of_device_id tcb_ids[] = {
-	{ .compatible = "atmel,at91rm9200-tcb" },
-	{ /*sentinel*/ }
-};
-#endif
-
 static void __init at91_add_device_tc(void)
 {
-#if defined(CONFIG_OF)
-	struct device_node *np;
-
-	np = of_find_matching_node(NULL, tcb_ids);
-	if (np) {
-		of_node_put(np);
-		return;
-	}
-#endif
-
 	platform_device_register(&at91sam9g45_tcb0_device);
 	platform_device_register(&at91sam9g45_tcb1_device);
 }
@@ -1207,6 +1185,104 @@
 
 
 /* --------------------------------------------------------------------
+ *  ADC
+ * -------------------------------------------------------------------- */
+
+#if IS_ENABLED(CONFIG_AT91_ADC)
+static struct at91_adc_data adc_data;
+
+static struct resource adc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9G45_BASE_TSC,
+		.end	= AT91SAM9G45_BASE_TSC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9G45_ID_TSC,
+		.end	= AT91SAM9G45_ID_TSC,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device at91_adc_device = {
+	.name		= "at91_adc",
+	.id		= -1,
+	.dev		= {
+				.platform_data	= &adc_data,
+	},
+	.resource	= adc_resources,
+	.num_resources	= ARRAY_SIZE(adc_resources),
+};
+
+static struct at91_adc_trigger at91_adc_triggers[] = {
+	[0] = {
+		.name = "external-rising",
+		.value = 1,
+		.is_external = true,
+	},
+	[1] = {
+		.name = "external-falling",
+		.value = 2,
+		.is_external = true,
+	},
+	[2] = {
+		.name = "external-any",
+		.value = 3,
+		.is_external = true,
+	},
+	[3] = {
+		.name = "continuous",
+		.value = 6,
+		.is_external = false,
+	},
+};
+
+static struct at91_adc_reg_desc at91_adc_register_g45 = {
+	.channel_base = AT91_ADC_CHR(0),
+	.drdy_mask = AT91_ADC_DRDY,
+	.status_register = AT91_ADC_SR,
+	.trigger_register = 0x08,
+};
+
+void __init at91_add_device_adc(struct at91_adc_data *data)
+{
+	if (!data)
+		return;
+
+	if (test_bit(0, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD20, 0);
+	if (test_bit(1, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD21, 0);
+	if (test_bit(2, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD22, 0);
+	if (test_bit(3, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD23, 0);
+	if (test_bit(4, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD24, 0);
+	if (test_bit(5, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD25, 0);
+	if (test_bit(6, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD26, 0);
+	if (test_bit(7, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD27, 0);
+
+	if (data->use_external_triggers)
+		at91_set_A_periph(AT91_PIN_PD28, 0);
+
+	data->num_channels = 8;
+	data->startup_time = 40;
+	data->registers = &at91_adc_register_g45;
+	data->trigger_number = 4;
+	data->trigger_list = at91_adc_triggers;
+
+	adc_data = *data;
+	platform_device_register(&at91_adc_device);
+}
+#else
+void __init at91_add_device_adc(struct at91_adc_data *data) {}
+#endif
+
+/* --------------------------------------------------------------------
  *  RTT
  * -------------------------------------------------------------------- */
 
@@ -1741,14 +1817,6 @@
 		at91_uarts[portnr] = pdev;
 }
 
-void __init at91_set_serial_console(unsigned portnr)
-{
-	if (portnr < ATMEL_MAX_UART) {
-		atmel_default_console_device = at91_uarts[portnr];
-		at91sam9g45_set_console_clock(at91_uarts[portnr]->id);
-	}
-}
-
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -1757,13 +1825,9 @@
 		if (at91_uarts[i])
 			platform_device_register(at91_uarts[i]);
 	}
-
-	if (!atmel_default_console_device)
-		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 #else
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
@@ -1775,6 +1839,9 @@
  */
 static int __init at91_add_standard_devices(void)
 {
+	if (of_have_populated_dt())
+		return 0;
+
 	at91_add_device_hdmac();
 	at91_add_device_rtc();
 	at91_add_device_rtt();
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
new file mode 100644
index 0000000..0849466
--- /dev/null
+++ b/arch/arm/mach-at91/at91sam9n12.c
@@ -0,0 +1,233 @@
+/*
+ * SoC specific setup code for the AT91SAM9N12
+ *
+ * Copyright (C) 2012 Atmel Corporation.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/at91sam9n12.h>
+#include <mach/at91_pmc.h>
+#include <mach/cpu.h>
+#include <mach/board.h>
+
+#include "soc.h"
+#include "generic.h"
+#include "clock.h"
+#include "sam9_smc.h"
+
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioAB_clk = {
+	.name		= "pioAB_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_PIOAB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioCD_clk = {
+	.name		= "pioCD_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_PIOCD,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+	.name		= "usart0_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_USART0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+	.name		= "usart1_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_USART1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+	.name		= "usart2_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_USART2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart3_clk = {
+	.name		= "usart3_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_USART3,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi0_clk = {
+	.name		= "twi0_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_TWI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi1_clk = {
+	.name		= "twi1_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_TWI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc_clk = {
+	.name		= "mci_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_MCI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+	.name		= "spi0_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_SPI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+	.name		= "spi1_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_SPI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart0_clk = {
+	.name		= "uart0_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_UART0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart1_clk = {
+	.name		= "uart1_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_UART1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb_clk = {
+	.name		= "tcb_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_TCB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pwm_clk = {
+	.name		= "pwm_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_PWM,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk adc_clk = {
+	.name		= "adc_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_ADC,
+	.type	= CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma_clk = {
+	.name		= "dma_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_DMA,
+	.type	= CLK_TYPE_PERIPHERAL,
+};
+static struct clk uhp_clk = {
+	.name		= "uhp",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_UHP,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk udp_clk = {
+	.name		= "udp_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_UDP,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk lcdc_clk = {
+	.name		= "lcdc_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_LCDC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc_clk = {
+	.name		= "ssc_clk",
+	.pmc_mask	= 1 << AT91SAM9N12_ID_SSC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+	&pioAB_clk,
+	&pioCD_clk,
+	&usart0_clk,
+	&usart1_clk,
+	&usart2_clk,
+	&usart3_clk,
+	&twi0_clk,
+	&twi1_clk,
+	&mmc_clk,
+	&spi0_clk,
+	&spi1_clk,
+	&lcdc_clk,
+	&uart0_clk,
+	&uart1_clk,
+	&tcb_clk,
+	&pwm_clk,
+	&adc_clk,
+	&dma_clk,
+	&uhp_clk,
+	&udp_clk,
+	&ssc_clk,
+};
+
+static struct clk_lookup periph_clocks_lookups[] = {
+	/* lookup table for DT entries */
+	CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+	CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk),
+	CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk),
+	CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk),
+	CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
+	CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
+	CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
+	CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
+	CLKDEV_CON_ID("pioA", &pioAB_clk),
+	CLKDEV_CON_ID("pioB", &pioAB_clk),
+	CLKDEV_CON_ID("pioC", &pioCD_clk),
+	CLKDEV_CON_ID("pioD", &pioCD_clk),
+	/* additional fake clock for macb_hclk */
+	CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
+	CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
+};
+
+/*
+ * The two programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+	.name		= "pck0",
+	.pmc_mask	= AT91_PMC_PCK0,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 0,
+};
+static struct clk pck1 = {
+	.name		= "pck1",
+	.pmc_mask	= AT91_PMC_PCK1,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 1,
+};
+
+static void __init at91sam9n12_register_clocks(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+		clk_register(periph_clocks[i]);
+	clk_register(&pck0);
+	clk_register(&pck1);
+
+	clkdev_add_table(periph_clocks_lookups,
+			 ARRAY_SIZE(periph_clocks_lookups));
+
+}
+
+/* --------------------------------------------------------------------
+ *  AT91SAM9N12 processor initialization
+ * -------------------------------------------------------------------- */
+
+static void __init at91sam9n12_map_io(void)
+{
+	at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
+}
+
+void __init at91sam9n12_initialize(void)
+{
+	at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
+
+	/* Register GPIO subsystem (using DT) */
+	at91_gpio_init(NULL, 0);
+}
+
+struct at91_init_soc __initdata at91sam9n12_soc = {
+	.map_io = at91sam9n12_map_io,
+	.register_clocks = at91sam9n12_register_clocks,
+	.init = at91sam9n12_initialize,
+};
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index d9f2774..e420085 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -232,18 +232,6 @@
 	clk_register(&pck1);
 }
 
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9rl_set_console_clock(int id)
-{
-	if (id >= ARRAY_SIZE(usart_clocks_lookups))
-		return;
-
-	console_clock_lookup.con_id = "usart";
-	console_clock_lookup.clk = usart_clocks_lookups[id].clk;
-	clkdev_add(&console_clock_lookup);
-}
-
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index fe4ae22..9c0b148 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -1192,14 +1192,6 @@
 		at91_uarts[portnr] = pdev;
 }
 
-void __init at91_set_serial_console(unsigned portnr)
-{
-	if (portnr < ATMEL_MAX_UART) {
-		atmel_default_console_device = at91_uarts[portnr];
-		at91sam9rl_set_console_clock(at91_uarts[portnr]->id);
-	}
-}
-
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -1208,13 +1200,9 @@
 		if (at91_uarts[i])
 			platform_device_register(at91_uarts[i]);
 	}
-
-	if (!atmel_default_console_device)
-		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 #else
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 13c8cae..1b144b4 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -120,6 +120,11 @@
 	.pmc_mask	= 1 << AT91SAM9X5_ID_ADC,
 	.type	= CLK_TYPE_PERIPHERAL,
 };
+static struct clk adc_op_clk = {
+	.name		= "adc_op_clk",
+	.type		= CLK_TYPE_PERIPHERAL,
+	.rate_hz	= 5000000,
+};
 static struct clk dma0_clk = {
 	.name		= "dma0_clk",
 	.pmc_mask	= 1 << AT91SAM9X5_ID_DMA0,
@@ -205,6 +210,7 @@
 	&tcb0_clk,
 	&pwm_clk,
 	&adc_clk,
+	&adc_op_clk,
 	&dma0_clk,
 	&dma1_clk,
 	&uhphs_clk,
diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c
index 2628384..271f994 100644
--- a/arch/arm/mach-at91/board-1arm.c
+++ b/arch/arm/mach-at91/board-1arm.c
@@ -47,20 +47,6 @@
 
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata onearm_eth_data = {
@@ -82,6 +68,16 @@
 static void __init onearm_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+	/* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&onearm_eth_data);
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
index 161efba..b7d8aa7 100644
--- a/arch/arm/mach-at91/board-afeb-9260v1.c
+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
@@ -52,22 +52,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1,
-			     ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR
-			   | ATMEL_UART_DCD | ATMEL_UART_RI);
-
-	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9260_ID_US1, 2,
-			ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -183,6 +167,18 @@
 static void __init afeb9260_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1,
+			     ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR
+			   | ATMEL_UART_DCD | ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2,
+			ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&afeb9260_usbh_data);
diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
index c6d44ee..29d3ef0 100644
--- a/arch/arm/mach-at91/board-cam60.c
+++ b/arch/arm/mach-at91/board-cam60.c
@@ -49,12 +49,6 @@
 {
 	/* Initialize processor: 10 MHz crystal */
 	at91_initialize(10000000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -175,6 +169,8 @@
 static void __init cam60_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
 	/* SPI */
 	at91_add_device_spi(cam60_spi_devices, ARRAY_SIZE(cam60_spi_devices));
diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
index 59d9cf9..44328a6 100644
--- a/arch/arm/mach-at91/board-carmeva.c
+++ b/arch/arm/mach-at91/board-carmeva.c
@@ -44,17 +44,6 @@
 {
 	/* Initialize processor: 20.000 MHz crystal */
 	at91_initialize(20000000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata carmeva_eth_data = {
@@ -139,6 +128,13 @@
 static void __init carmeva_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&carmeva_eth_data);
diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
index 5f3680e..69951ec 100644
--- a/arch/arm/mach-at91/board-cpu9krea.c
+++ b/arch/arm/mach-at91/board-cpu9krea.c
@@ -52,34 +52,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DGBU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS |
-		ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
-		ATMEL_UART_DCD | ATMEL_UART_RI);
-
-	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS |
-		ATMEL_UART_RTS);
-
-	/* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS |
-		ATMEL_UART_RTS);
-
-	/* USART3 on ttyS4. (Rx, Tx) */
-	at91_register_uart(AT91SAM9260_ID_US3, 4, 0);
-
-	/* USART4 on ttyS5. (Rx, Tx) */
-	at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
-
-	/* USART5 on ttyS6. (Rx, Tx) */
-	at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -352,6 +324,30 @@
 	/* NOR */
 	cpu9krea_add_device_nor();
 	/* Serial */
+	/* DGBU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS |
+		ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
+		ATMEL_UART_DCD | ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS |
+		ATMEL_UART_RTS);
+
+	/* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS |
+		ATMEL_UART_RTS);
+
+	/* USART3 on ttyS4. (Rx, Tx) */
+	at91_register_uart(AT91SAM9260_ID_US3, 4, 0);
+
+	/* USART4 on ttyS5. (Rx, Tx) */
+	at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+
+	/* USART5 on ttyS6. (Rx, Tx) */
+	at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&cpu9krea_usbh_data);
diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
index e094cc8..895cf2d 100644
--- a/arch/arm/mach-at91/board-cpuat91.c
+++ b/arch/arm/mach-at91/board-cpuat91.c
@@ -59,28 +59,6 @@
 
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS |
-		ATMEL_UART_RTS);
-
-	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS |
-		ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
-		ATMEL_UART_DCD | ATMEL_UART_RI);
-
-	/* USART2 on ttyS3 (Rx, Tx) */
-	at91_register_uart(AT91RM9200_ID_US2, 3, 0);
-
-	/* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS |
-		ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata cpuat91_eth_data = {
@@ -161,6 +139,24 @@
 static void __init cpuat91_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS |
+		ATMEL_UART_RTS);
+
+	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS |
+		ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
+		ATMEL_UART_DCD | ATMEL_UART_RI);
+
+	/* USART2 on ttyS3 (Rx, Tx) */
+	at91_register_uart(AT91RM9200_ID_US2, 3, 0);
+
+	/* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS |
+		ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* LEDs. */
 	at91_gpio_leds(cpuat91_leds, ARRAY_SIZE(cpuat91_leds));
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index 1a1547b..cd81336 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -47,15 +47,6 @@
 {
 	/* Initialize processor: 3.6864 MHz crystal */
 	at91_initialize(3686400);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
-
-	/* DBGU on ttyS0 */
-	at91_register_uart(0, 0, 0);
-
-	/* make console=ttyS0 the default */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata csb337_eth_data = {
@@ -228,7 +219,11 @@
 
 static void __init csb337_board_init(void)
 {
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
 	/* Serial */
+	/* DBGU on ttyS0 */
+	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&csb337_eth_data);
diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
index f650bf3..7c8b05a 100644
--- a/arch/arm/mach-at91/board-csb637.c
+++ b/arch/arm/mach-at91/board-csb637.c
@@ -44,12 +44,6 @@
 {
 	/* Initialize processor: 3.6864 MHz crystal */
 	at91_initialize(3686400);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* make console=ttyS0 (ie, DBGU) the default */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata csb637_eth_data = {
@@ -118,6 +112,8 @@
 	/* LED(s) */
 	at91_gpio_leds(csb_leds, ARRAY_SIZE(csb_leds));
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&csb637_eth_data);
diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
index c18d4d30..a1fce05 100644
--- a/arch/arm/mach-at91/board-dt.c
+++ b/arch/arm/mach-at91/board-dt.c
@@ -1,10 +1,6 @@
 /*
  *  Setup code for AT91SAM Evaluation Kits with Device Tree support
  *
- *  Covers: * AT91SAM9G45-EKES  board
- *          * AT91SAM9M10-EKES  board
- *          * AT91SAM9M10G45-EK board
- *
  *  Copyright (C) 2011 Atmel,
  *                2011 Nicolas Ferre <nicolas.ferre@atmel.com>
  *
@@ -49,9 +45,7 @@
 }
 
 static const char *at91_dt_board_compat[] __initdata = {
-	"atmel,at91sam9m10g45ek",
-	"atmel,at91sam9x5ek",
-	"calao,usb-a9g20",
+	"atmel,at91sam9",
 	NULL
 };
 
diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
index d302ca3..bd10172 100644
--- a/arch/arm/mach-at91/board-eb9200.c
+++ b/arch/arm/mach-at91/board-eb9200.c
@@ -44,20 +44,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			| ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			| ATMEL_UART_RI);
-
-	/* USART2 on ttyS2. (Rx, Tx) - IRDA */
-	at91_register_uart(AT91RM9200_ID_US2, 2, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata eb9200_eth_data = {
@@ -101,6 +87,16 @@
 static void __init eb9200_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			| ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			| ATMEL_UART_RI);
+
+	/* USART2 on ttyS2. (Rx, Tx) - IRDA */
+	at91_register_uart(AT91RM9200_ID_US2, 2, 0);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&eb9200_eth_data);
diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
index 69966ce..89cc372 100644
--- a/arch/arm/mach-at91/board-ecbat91.c
+++ b/arch/arm/mach-at91/board-ecbat91.c
@@ -50,18 +50,6 @@
 
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx & Tx only) */
-	at91_register_uart(AT91RM9200_ID_US0, 1, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata ecb_at91eth_data = {
@@ -151,7 +139,15 @@
 
 static void __init ecb_at91board_init(void)
 {
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
+
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx & Tx only) */
+	at91_register_uart(AT91RM9200_ID_US0, 1, 0);
 	at91_add_device_serial();
 
 	/* Ethernet */
diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
index f23aabe..558546c 100644
--- a/arch/arm/mach-at91/board-eco920.c
+++ b/arch/arm/mach-at91/board-eco920.c
@@ -37,15 +37,6 @@
 	at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
 	at91_initialize(18432000);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
-
-	/* DBGU on ttyS0. (Rx & Tx only */
-	at91_register_uart(0, 0, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata eco920_eth_data = {
@@ -103,6 +94,10 @@
 
 static void __init eco920_board_init(void)
 {
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+	/* DBGU on ttyS0. (Rx & Tx only */
+	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
 	at91_add_device_eth(&eco920_eth_data);
 	at91_add_device_usbh(&eco920_usbh_data);
diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
index 1815152..47658f7 100644
--- a/arch/arm/mach-at91/board-flexibity.c
+++ b/arch/arm/mach-at91/board-flexibity.c
@@ -41,12 +41,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /* USB Host port */
@@ -143,6 +137,8 @@
 static void __init flexibity_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&flexibity_usbh_data);
diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
index caf017f..33411e6 100644
--- a/arch/arm/mach-at91/board-foxg20.c
+++ b/arch/arm/mach-at91/board-foxg20.c
@@ -61,44 +61,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1,
-				ATMEL_UART_CTS
-				| ATMEL_UART_RTS
-				| ATMEL_UART_DTR
-				| ATMEL_UART_DSR
-				| ATMEL_UART_DCD
-				| ATMEL_UART_RI);
-
-	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9260_ID_US1, 2,
-		ATMEL_UART_CTS
-		| ATMEL_UART_RTS);
-
-	/* USART2 on ttyS3. (Rx & Tx only) */
-	at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
-
-	/* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9260_ID_US3, 4,
-		ATMEL_UART_CTS
-		| ATMEL_UART_RTS);
-
-	/* USART4 on ttyS5. (Rx & Tx only) */
-	at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
-
-	/* USART5 on ttyS6. (Rx & Tx only) */
-	at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
-
-	/* Set the internal pull-up resistor on DRXD */
-	at91_set_A_periph(AT91_PIN_PB14, 1);
-
 }
 
 /*
@@ -241,6 +203,39 @@
 static void __init foxg20_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1,
+				ATMEL_UART_CTS
+				| ATMEL_UART_RTS
+				| ATMEL_UART_DTR
+				| ATMEL_UART_DSR
+				| ATMEL_UART_DCD
+				| ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2,
+		ATMEL_UART_CTS
+		| ATMEL_UART_RTS);
+
+	/* USART2 on ttyS3. (Rx & Tx only) */
+	at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
+
+	/* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9260_ID_US3, 4,
+		ATMEL_UART_CTS
+		| ATMEL_UART_RTS);
+
+	/* USART4 on ttyS5. (Rx & Tx only) */
+	at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+
+	/* USART5 on ttyS6. (Rx & Tx only) */
+	at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+
+	/* Set the internal pull-up resistor on DRXD */
+	at91_set_A_periph(AT91_PIN_PB14, 1);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&foxg20_usbh_data);
diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
index 230e719..3e0dfa6 100644
--- a/arch/arm/mach-at91/board-gsia18s.c
+++ b/arch/arm/mach-at91/board-gsia18s.c
@@ -41,38 +41,6 @@
 static void __init gsia18s_init_early(void)
 {
 	stamp9g20_init_early();
-
-	/*
-	 * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
-	 * Used for Internal Analog Modem.
-	 */
-	at91_register_uart(AT91SAM9260_ID_US0, 1,
-				ATMEL_UART_CTS | ATMEL_UART_RTS |
-				ATMEL_UART_DTR | ATMEL_UART_DSR |
-				ATMEL_UART_DCD | ATMEL_UART_RI);
-	/*
-	 * USART1 on ttyS2 (Rx, Tx, CTS, RTS).
-	 * Used for GPS or WiFi or Data stream.
-	 */
-	at91_register_uart(AT91SAM9260_ID_US1, 2,
-				ATMEL_UART_CTS | ATMEL_UART_RTS);
-	/*
-	 * USART2 on ttyS3 (Rx, Tx, CTS, RTS).
-	 * Used for External Modem.
-	 */
-	at91_register_uart(AT91SAM9260_ID_US2, 3,
-				ATMEL_UART_CTS | ATMEL_UART_RTS);
-	/*
-	 * USART3 on ttyS4 (Rx, Tx, RTS).
-	 * Used for RS-485.
-	 */
-	at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS);
-
-	/*
-	 * USART4 on ttyS5 (Rx, Tx).
-	 * Used for TRX433 Radio Module.
-	 */
-	at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
 }
 
 /*
@@ -558,6 +526,37 @@
 
 static void __init gsia18s_board_init(void)
 {
+	/*
+	 * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
+	 * Used for Internal Analog Modem.
+	 */
+	at91_register_uart(AT91SAM9260_ID_US0, 1,
+				ATMEL_UART_CTS | ATMEL_UART_RTS |
+				ATMEL_UART_DTR | ATMEL_UART_DSR |
+				ATMEL_UART_DCD | ATMEL_UART_RI);
+	/*
+	 * USART1 on ttyS2 (Rx, Tx, CTS, RTS).
+	 * Used for GPS or WiFi or Data stream.
+	 */
+	at91_register_uart(AT91SAM9260_ID_US1, 2,
+				ATMEL_UART_CTS | ATMEL_UART_RTS);
+	/*
+	 * USART2 on ttyS3 (Rx, Tx, CTS, RTS).
+	 * Used for External Modem.
+	 */
+	at91_register_uart(AT91SAM9260_ID_US2, 3,
+				ATMEL_UART_CTS | ATMEL_UART_RTS);
+	/*
+	 * USART3 on ttyS4 (Rx, Tx, RTS).
+	 * Used for RS-485.
+	 */
+	at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS);
+
+	/*
+	 * USART4 on ttyS5 (Rx, Tx).
+	 * Used for TRX433 Radio Module.
+	 */
+	at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
 	stamp9g20_board_init();
 	at91_add_device_usbh(&usbh_data);
 	at91_add_device_udc(&udc_data);
diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
index efde1b2..f260657 100644
--- a/arch/arm/mach-at91/board-kafa.c
+++ b/arch/arm/mach-at91/board-kafa.c
@@ -47,18 +47,6 @@
 
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* Set up the LEDs */
-	at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata kafa_eth_data = {
@@ -79,7 +67,15 @@
 
 static void __init kafa_board_init(void)
 {
+	/* Set up the LEDs */
+	at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
+
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&kafa_eth_data);
diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
index 59b92aa..ba39db5 100644
--- a/arch/arm/mach-at91/board-kb9202.c
+++ b/arch/arm/mach-at91/board-kb9202.c
@@ -50,24 +50,6 @@
 
 	/* Initialize processor: 10 MHz crystal */
 	at91_initialize(10000000);
-
-	/* Set up the LEDs */
-	at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1 (Rx & Tx only) */
-	at91_register_uart(AT91RM9200_ID_US0, 1, 0);
-
-	/* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */
-	at91_register_uart(AT91RM9200_ID_US1, 2, 0);
-
-	/* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */
-	at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata kb9202_eth_data = {
@@ -115,7 +97,21 @@
 
 static void __init kb9202_board_init(void)
 {
+	/* Set up the LEDs */
+	at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
+
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1 (Rx & Tx only) */
+	at91_register_uart(AT91RM9200_ID_US0, 1, 0);
+
+	/* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */
+	at91_register_uart(AT91RM9200_ID_US1, 2, 0);
+
+	/* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */
+	at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&kb9202_eth_data);
diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
index 57d5f6a..d2f4cc1 100644
--- a/arch/arm/mach-at91/board-neocore926.c
+++ b/arch/arm/mach-at91/board-neocore926.c
@@ -55,15 +55,6 @@
 {
 	/* Initialize processor: 20 MHz crystal */
 	at91_initialize(20000000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -341,6 +332,11 @@
 static void __init neocore926_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 
 	/* USB Host */
diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
index b4a12fc..7fe6383 100644
--- a/arch/arm/mach-at91/board-pcontrol-g20.c
+++ b/arch/arm/mach-at91/board-pcontrol-g20.c
@@ -40,17 +40,6 @@
 static void __init pcontrol_g20_init_early(void)
 {
 	stamp9g20_init_early();
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback  A2 */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
-						| ATMEL_UART_RTS);
-
-	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485  X5 */
-	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
-						| ATMEL_UART_RTS);
-
-	/* USART2 on ttyS3. (Rx, Tx)  9bit-Bus  Multidrop-mode  X4 */
-	at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
 }
 
 static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
@@ -199,6 +188,16 @@
 
 static void __init pcontrol_g20_board_init(void)
 {
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback  A2 */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
+						| ATMEL_UART_RTS);
+
+	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485  X5 */
+	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
+						| ATMEL_UART_RTS);
+
+	/* USART2 on ttyS3. (Rx, Tx)  9bit-Bus  Multidrop-mode  X4 */
+	at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
 	stamp9g20_board_init();
 	at91_add_device_usbh(&usbh_data);
 	at91_add_device_eth(&macb_data);
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
index 59e35dd..b45c0a5 100644
--- a/arch/arm/mach-at91/board-picotux200.c
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -48,17 +48,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			  | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			  | ATMEL_UART_RI);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata picotux200_eth_data = {
@@ -106,6 +95,13 @@
 static void __init picotux200_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			  | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			  | ATMEL_UART_RI);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&picotux200_eth_data);
diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
index b6ed5ed..0c61bf0d 100644
--- a/arch/arm/mach-at91/board-qil-a9260.c
+++ b/arch/arm/mach-at91/board-qil-a9260.c
@@ -52,24 +52,6 @@
 {
 	/* Initialize processor: 12.000 MHz crystal */
 	at91_initialize(12000000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS1 (ie, USART0) */
-	at91_set_serial_console(1);
-
 }
 
 /*
@@ -235,6 +217,19 @@
 static void __init ek_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+	/* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
index 01332aa..afd7a47 100644
--- a/arch/arm/mach-at91/board-rm9200dk.c
+++ b/arch/arm/mach-at91/board-rm9200dk.c
@@ -50,20 +50,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata dk_eth_data = {
@@ -190,7 +176,17 @@
 
 static void __init dk_board_init(void)
 {
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&dk_eth_data);
diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
index b2e4fe2..2b15b8a 100644
--- a/arch/arm/mach-at91/board-rm9200ek.c
+++ b/arch/arm/mach-at91/board-rm9200ek.c
@@ -50,20 +50,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static struct macb_platform_data __initdata ek_eth_data = {
@@ -161,7 +147,17 @@
 
 static void __init ek_board_init(void)
 {
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
+
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&ek_eth_data);
diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
index af0750f..24ab9be 100644
--- a/arch/arm/mach-at91/board-rsi-ews.c
+++ b/arch/arm/mach-at91/board-rsi-ews.c
@@ -35,26 +35,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	/* This one is for debugging */
-	at91_register_uart(0, 0, 0);
-
-	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	/* Dialin/-out modem interface */
-	at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* USART3 on ttyS4. (Rx, Tx, RTS) */
-	/* RS485 communication */
-	at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -204,7 +184,23 @@
  */
 static void __init rsi_ews_board_init(void)
 {
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
+
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	/* This one is for debugging */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	/* Dialin/-out modem interface */
+	at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
+
+	/* USART3 on ttyS4. (Rx, Tx, RTS) */
+	/* RS485 communication */
+	at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS);
 	at91_add_device_serial();
 	at91_set_gpio_output(AT91_PIN_PA21, 0);
 	/* Ethernet */
diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
index e8b116b..cdd21f2 100644
--- a/arch/arm/mach-at91/board-sam9-l9260.c
+++ b/arch/arm/mach-at91/board-sam9-l9260.c
@@ -48,23 +48,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -184,7 +167,20 @@
 
 static void __init ek_board_init(void)
 {
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
+
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index d5aec55..7b3c391 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -54,20 +54,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -320,6 +306,16 @@
 static void __init ek_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 065fed3..2736453 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -58,15 +58,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -577,7 +568,12 @@
 
 static void __init ek_board_init(void)
 {
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
+
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 2ffe50f..983cb98 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -57,15 +57,6 @@
 {
 	/* Initialize processor: 16.367 MHz crystal */
 	at91_initialize(16367660);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -412,6 +403,11 @@
 static void __init ek_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 8923ec9..6860d34 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -32,6 +32,8 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/consumer.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -65,20 +67,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -318,6 +306,16 @@
 static void __init ek_add_device_buttons(void) {}
 #endif
 
+/*
+ * ADCs
+ */
+
+static struct at91_adc_data ek_adc_data = {
+	.channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3),
+	.use_external_triggers = true,
+	.vref = 3300,
+};
+
 #if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
 static struct regulator_consumer_supply ek_audio_consumer_supplies[] = {
 	REGULATOR_SUPPLY("AVDD", "0-001b"),
@@ -372,6 +370,16 @@
 static void __init ek_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&ek_usbh_data);
@@ -393,6 +401,8 @@
 	ek_add_device_gpio_leds();
 	/* Push Buttons */
 	ek_add_device_buttons();
+	/* ADCs */
+	at91_add_device_adc(&ek_adc_data);
 	/* PCK0 provides MCLK to the WM8731 */
 	at91_set_B_periph(AT91_PIN_PC1, 0);
 	/* SSC (for WM8731) */
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index c88e908..63163dc 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -27,6 +27,8 @@
 #include <linux/atmel-mci.h>
 #include <linux/delay.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <mach/hardware.h>
 #include <video/atmel_lcdc.h>
 #include <media/soc_camera.h>
@@ -53,16 +55,6 @@
 {
 	/* Initialize processor: 12.000 MHz crystal */
 	at91_initialize(12000000);
-
-	/* DGBU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 not connected on the -EK board */
-	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -315,6 +307,14 @@
 	.ts_sample_hold_time	= 0x0a,
 };
 
+/*
+ * ADCs
+ */
+static struct at91_adc_data ek_adc_data = {
+	.channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7),
+	.use_external_triggers = true,
+	.vref = 3300,
+};
 
 /*
  * GPIO Buttons
@@ -457,6 +457,12 @@
 static void __init ek_board_init(void)
 {
 	/* Serial */
+	/* DGBU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 not connected on the -EK board */
+	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* USB HS Host */
 	at91_add_device_usbh_ohci(&ek_usbh_hs_data);
@@ -480,6 +486,8 @@
 	at91_add_device_lcdc(&ek_lcdc_data);
 	/* Touch Screen */
 	at91_add_device_tsadcc(&ek_tsadcc_data);
+	/* ADC */
+	at91_add_device_adc(&ek_adc_data);
 	/* Push Buttons */
 	ek_add_device_buttons();
 	/* AC97 */
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
index b109ce2..be3239f 100644
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ b/arch/arm/mach-at91/board-sam9rlek.c
@@ -42,15 +42,6 @@
 {
 	/* Initialize processor: 12.000 MHz crystal */
 	at91_initialize(12000000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -296,6 +287,11 @@
 static void __init ek_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* USB HS */
 	at91_add_device_usba(&ek_usba_udc_data);
diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
index ebc9d01..9d446f1b 100644
--- a/arch/arm/mach-at91/board-snapper9260.c
+++ b/arch/arm/mach-at91/board-snapper9260.c
@@ -43,16 +43,6 @@
 static void __init snapper9260_init_early(void)
 {
 	at91_initialize(18432000);
-
-	/* Debug on ttyS0 */
-	at91_register_uart(0, 0, 0);
-	at91_set_serial_console(0);
-
-	at91_register_uart(AT91SAM9260_ID_US0, 1,
-			   ATMEL_UART_CTS | ATMEL_UART_RTS);
-	at91_register_uart(AT91SAM9260_ID_US1, 2,
-			   ATMEL_UART_CTS | ATMEL_UART_RTS);
-	at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
 }
 
 static struct at91_usbh_data __initdata snapper9260_usbh_data = {
@@ -168,6 +158,14 @@
 	snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31);
 	i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1);
 
+	/* Debug on ttyS0 */
+	at91_register_uart(0, 0, 0);
+
+	at91_register_uart(AT91SAM9260_ID_US0, 1,
+			   ATMEL_UART_CTS | ATMEL_UART_RTS);
+	at91_register_uart(AT91SAM9260_ID_US1, 2,
+			   ATMEL_UART_CTS | ATMEL_UART_RTS);
+	at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
 	at91_add_device_serial();
 	at91_add_device_usbh(&snapper9260_usbh_data);
 	at91_add_device_udc(&snapper9260_udc_data);
diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
index 7640049..ee86f9d 100644
--- a/arch/arm/mach-at91/board-stamp9g20.c
+++ b/arch/arm/mach-at91/board-stamp9g20.c
@@ -36,44 +36,6 @@
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* DGBU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
-}
-
-static void __init stamp9g20evb_init_early(void)
-{
-	stamp9g20_init_early();
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-						| ATMEL_UART_DTR | ATMEL_UART_DSR
-						| ATMEL_UART_DCD | ATMEL_UART_RI);
-}
-
-static void __init portuxg20_init_early(void)
-{
-	stamp9g20_init_early();
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-						| ATMEL_UART_DTR | ATMEL_UART_DSR
-						| ATMEL_UART_DCD | ATMEL_UART_RI);
-
-	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
-	at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* USART4 on ttyS5. (Rx, Tx only) */
-	at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
-
-	/* USART5 on ttyS6. (Rx, Tx only) */
-	at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
 }
 
 /*
@@ -254,6 +216,8 @@
 void __init stamp9g20_board_init(void)
 {
 	/* Serial */
+	/* DGBU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
 	/* NAND */
 	add_device_nand();
@@ -269,6 +233,22 @@
 
 static void __init portuxg20_board_init(void)
 {
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+						| ATMEL_UART_DTR | ATMEL_UART_DSR
+						| ATMEL_UART_DCD | ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+	/* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+	/* USART4 on ttyS5. (Rx, Tx only) */
+	at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+
+	/* USART5 on ttyS6. (Rx, Tx only) */
+	at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
 	stamp9g20_board_init();
 	/* USB Host */
 	at91_add_device_usbh(&usbh_data);
@@ -286,6 +266,10 @@
 
 static void __init stamp9g20evb_board_init(void)
 {
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+						| ATMEL_UART_DTR | ATMEL_UART_DSR
+						| ATMEL_UART_DCD | ATMEL_UART_RI);
 	stamp9g20_board_init();
 	/* USB Host */
 	at91_add_device_usbh(&usbh_data);
@@ -303,7 +287,7 @@
 	/* Maintainer: taskit GmbH */
 	.timer		= &at91sam926x_timer,
 	.map_io		= at91_map_io,
-	.init_early	= portuxg20_init_early,
+	.init_early	= stamp9g20_init_early,
 	.init_irq	= at91_init_irq_default,
 	.init_machine	= portuxg20_board_init,
 MACHINE_END
@@ -312,7 +296,7 @@
 	/* Maintainer: taskit GmbH */
 	.timer		= &at91sam926x_timer,
 	.map_io		= at91_map_io,
-	.init_early	= stamp9g20evb_init_early,
+	.init_early	= stamp9g20_init_early,
 	.init_irq	= at91_init_irq_default,
 	.init_machine	= stamp9g20evb_board_init,
 MACHINE_END
diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
index b7483a3..95393fc 100644
--- a/arch/arm/mach-at91/board-usb-a926x.c
+++ b/arch/arm/mach-at91/board-usb-a926x.c
@@ -53,12 +53,6 @@
 {
 	/* Initialize processor: 12.00 MHz crystal */
 	at91_initialize(12000000);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -178,6 +172,10 @@
 		.offset	= MTDPART_OFS_NXTBLK,
 		.size	= SZ_128K,
 	}, {
+		.name	= "oftree",
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= SZ_128K,
+	}, {
 		.name	= "kernel",
 		.offset	= MTDPART_OFS_NXTBLK,
 		.size	= 4 * SZ_1M,
@@ -325,6 +323,8 @@
 static void __init ek_board_init(void)
 {
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
 	/* USB Host */
 	at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
index 38dd279..d56665e 100644
--- a/arch/arm/mach-at91/board-yl-9200.c
+++ b/arch/arm/mach-at91/board-yl-9200.c
@@ -58,26 +58,6 @@
 
 	/* Initialize processor: 18.432 MHz crystal */
 	at91_initialize(18432000);
-
-	/* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
-	at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			| ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			| ATMEL_UART_RI);
-
-	/* USART0 on ttyS2. (Rx & Tx only to JP3) */
-	at91_register_uart(AT91RM9200_ID_US0, 2, 0);
-
-	/* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */
-	at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 /*
@@ -560,7 +540,23 @@
 
 static void __init yl9200_board_init(void)
 {
+	/* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
+	at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
+
 	/* Serial */
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			| ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			| ATMEL_UART_RI);
+
+	/* USART0 on ttyS2. (Rx & Tx only to JP3) */
+	at91_register_uart(AT91RM9200_ID_US0, 2, 0);
+
+	/* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */
+	at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS);
 	at91_add_device_serial();
 	/* Ethernet */
 	at91_add_device_eth(&yl9200_eth_data);
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index 6b69282..de2ec6b 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -58,13 +58,15 @@
 
 #define cpu_has_800M_plla()	(  cpu_is_at91sam9g20() \
 				|| cpu_is_at91sam9g45() \
-				|| cpu_is_at91sam9x5())
+				|| cpu_is_at91sam9x5() \
+				|| cpu_is_at91sam9n12())
 
 #define cpu_has_300M_plla()	(cpu_is_at91sam9g10())
 
 #define cpu_has_pllb()		(!(cpu_is_at91sam9rl() \
 				|| cpu_is_at91sam9g45() \
-				|| cpu_is_at91sam9x5()))
+				|| cpu_is_at91sam9x5() \
+				|| cpu_is_at91sam9n12()))
 
 #define cpu_has_upll()		(cpu_is_at91sam9g45() \
 				|| cpu_is_at91sam9x5())
@@ -78,12 +80,15 @@
 				|| cpu_is_at91sam9x5()))
 
 #define cpu_has_plladiv2()	(cpu_is_at91sam9g45() \
-				|| cpu_is_at91sam9x5())
+				|| cpu_is_at91sam9x5() \
+				|| cpu_is_at91sam9n12())
 
 #define cpu_has_mdiv3()		(cpu_is_at91sam9g45() \
-				|| cpu_is_at91sam9x5())
+				|| cpu_is_at91sam9x5() \
+				|| cpu_is_at91sam9n12())
 
-#define cpu_has_alt_prescaler()	(cpu_is_at91sam9x5())
+#define cpu_has_alt_prescaler()	(cpu_is_at91sam9x5() \
+				|| cpu_is_at91sam9n12())
 
 static LIST_HEAD(clocks);
 static DEFINE_SPINLOCK(clk_lock);
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index ece1f9a..0c63815 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -21,6 +21,7 @@
 #include <linux/export.h>
 #include <asm/proc-fns.h>
 #include <asm/cpuidle.h>
+#include <mach/cpu.h>
 
 #include "pm.h"
 
@@ -33,7 +34,12 @@
 			struct cpuidle_driver *drv,
 			       int index)
 {
-	at91_standby();
+	if (cpu_is_at91rm9200())
+		at91rm9200_standby();
+	else if (cpu_is_at91sam9g45())
+		at91sam9g45_standby();
+	else
+		at91sam9_standby();
 
 	return index;
 }
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index dd9b346..0a60bf8 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -40,17 +40,6 @@
 extern struct sys_timer at91x40_timer;
 
  /* Clocks */
-/*
- * function to specify the clock of the default console. As we do not
- * use the device/driver bus, the dev_name is not intialize. So we need
- * to link the clock to a specific con_id only "usart"
- */
-extern void __init at91rm9200_set_console_clock(int id);
-extern void __init at91sam9260_set_console_clock(int id);
-extern void __init at91sam9261_set_console_clock(int id);
-extern void __init at91sam9263_set_console_clock(int id);
-extern void __init at91sam9rl_set_console_clock(int id);
-extern void __init at91sam9g45_set_console_clock(int id);
 #ifdef CONFIG_AT91_PMC_UNIT
 extern int __init at91_clock_init(unsigned long main_clock);
 extern int __init at91_dt_clock_init(void);
diff --git a/arch/arm/mach-at91/include/mach/at91rm9200.h b/arch/arm/mach-at91/include/mach/at91rm9200.h
index 603e6aa..e67317c 100644
--- a/arch/arm/mach-at91/include/mach/at91rm9200.h
+++ b/arch/arm/mach-at91/include/mach/at91rm9200.h
@@ -88,11 +88,6 @@
 #define AT91RM9200_BASE_RTC	0xfffffe00	/* Real-Time Clock */
 #define AT91RM9200_BASE_MC	0xffffff00	/* Memory Controllers */
 
-#define AT91_USART0	AT91RM9200_BASE_US0
-#define AT91_USART1	AT91RM9200_BASE_US1
-#define AT91_USART2	AT91RM9200_BASE_US2
-#define AT91_USART3	AT91RM9200_BASE_US3
-
 /*
  * Internal Memory.
  */
diff --git a/arch/arm/mach-at91/include/mach/at91sam9260.h b/arch/arm/mach-at91/include/mach/at91sam9260.h
index 08ae9af..416c7b6 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9260.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9260.h
@@ -95,13 +95,6 @@
 #define AT91SAM9260_BASE_WDT	0xfffffd40
 #define AT91SAM9260_BASE_GPBR	0xfffffd50
 
-#define AT91_USART0	AT91SAM9260_BASE_US0
-#define AT91_USART1	AT91SAM9260_BASE_US1
-#define AT91_USART2	AT91SAM9260_BASE_US2
-#define AT91_USART3	AT91SAM9260_BASE_US3
-#define AT91_USART4	AT91SAM9260_BASE_US4
-#define AT91_USART5	AT91SAM9260_BASE_US5
-
 
 /*
  * Internal Memory.
diff --git a/arch/arm/mach-at91/include/mach/at91sam9261.h b/arch/arm/mach-at91/include/mach/at91sam9261.h
index 44fbdc1..a041406 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9261.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9261.h
@@ -79,10 +79,6 @@
 #define AT91SAM9261_BASE_WDT	0xfffffd40
 #define AT91SAM9261_BASE_GPBR	0xfffffd50
 
-#define AT91_USART0	AT91SAM9261_BASE_US0
-#define AT91_USART1	AT91SAM9261_BASE_US1
-#define AT91_USART2	AT91SAM9261_BASE_US2
-
 
 /*
  * Internal Memory.
diff --git a/arch/arm/mach-at91/include/mach/at91sam9263.h b/arch/arm/mach-at91/include/mach/at91sam9263.h
index d96cbb2..d201029 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9263.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9263.h
@@ -95,10 +95,6 @@
 #define AT91SAM9263_BASE_RTT1	0xfffffd50
 #define AT91SAM9263_BASE_GPBR	0xfffffd60
 
-#define AT91_USART0	AT91SAM9263_BASE_US0
-#define AT91_USART1	AT91SAM9263_BASE_US1
-#define AT91_USART2	AT91SAM9263_BASE_US2
-
 #define AT91_SMC	AT91_SMC0
 
 /*
diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h
index d052abc..3a4da24 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9g45.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h
@@ -106,11 +106,6 @@
 #define AT91SAM9G45_BASE_RTC	0xfffffdb0
 #define AT91SAM9G45_BASE_GPBR	0xfffffd60
 
-#define AT91_USART0	AT91SAM9G45_BASE_US0
-#define AT91_USART1	AT91SAM9G45_BASE_US1
-#define AT91_USART2	AT91SAM9G45_BASE_US2
-#define AT91_USART3	AT91SAM9G45_BASE_US3
-
 /*
  * Internal Memory.
  */
diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h
new file mode 100644
index 0000000..d374b87
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h
@@ -0,0 +1,60 @@
+/*
+ * SoC specific header file for the AT91SAM9N12
+ *
+ * Copyright (C) 2012 Atmel Corporation
+ *
+ * Common definitions, based on AT91SAM9N12 SoC datasheet
+ *
+ * Licensed under GPLv2 or later
+ */
+
+#ifndef _AT91SAM9N12_H_
+#define _AT91SAM9N12_H_
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91SAM9N12_ID_PIOAB	2	/* Parallel I/O Controller A and B */
+#define AT91SAM9N12_ID_PIOCD	3	/* Parallel I/O Controller C and D */
+#define AT91SAM9N12_ID_FUSE	4	/* FUSE Controller */
+#define AT91SAM9N12_ID_USART0	5	/* USART 0 */
+#define AT91SAM9N12_ID_USART1	6	/* USART 1 */
+#define AT91SAM9N12_ID_USART2	7	/* USART 2 */
+#define AT91SAM9N12_ID_USART3	8	/* USART 3 */
+#define AT91SAM9N12_ID_TWI0	9	/* Two-Wire Interface 0 */
+#define AT91SAM9N12_ID_TWI1	10	/* Two-Wire Interface 1 */
+#define AT91SAM9N12_ID_MCI	12	/* High Speed Multimedia Card Interface */
+#define AT91SAM9N12_ID_SPI0	13	/* Serial Peripheral Interface 0 */
+#define AT91SAM9N12_ID_SPI1	14	/* Serial Peripheral Interface 1 */
+#define AT91SAM9N12_ID_UART0	15	/* UART 0 */
+#define AT91SAM9N12_ID_UART1	16	/* UART 1 */
+#define AT91SAM9N12_ID_TCB	17	/* Timer Counter 0, 1, 2, 3, 4 and 5 */
+#define AT91SAM9N12_ID_PWM	18	/* Pulse Width Modulation Controller */
+#define AT91SAM9N12_ID_ADC	19	/* ADC Controller */
+#define AT91SAM9N12_ID_DMA	20	/* DMA Controller */
+#define AT91SAM9N12_ID_UHP	22	/* USB Host High Speed */
+#define AT91SAM9N12_ID_UDP	23	/* USB Device High Speed */
+#define AT91SAM9N12_ID_LCDC	25	/* LCD Controller */
+#define AT91SAM9N12_ID_ISI	25	/* Image Sensor Interface */
+#define AT91SAM9N12_ID_SSC	28	/* Synchronous Serial Controller */
+#define AT91SAM9N12_ID_TRNG	30	/* TRNG */
+#define AT91SAM9N12_ID_IRQ0	31	/* Advanced Interrupt Controller */
+
+/*
+ * User Peripheral physical base addresses.
+ */
+#define AT91SAM9N12_BASE_USART0	0xf801c000
+#define AT91SAM9N12_BASE_USART1	0xf8020000
+#define AT91SAM9N12_BASE_USART2	0xf8024000
+#define AT91SAM9N12_BASE_USART3	0xf8028000
+
+/*
+ * Internal Memory.
+ */
+#define AT91SAM9N12_SRAM_BASE	0x00300000	/* Internal SRAM base address */
+#define AT91SAM9N12_SRAM_SIZE	SZ_32K		/* Internal SRAM size (32Kb) */
+
+#define AT91SAM9N12_ROM_BASE	0x00100000	/* Internal ROM base address */
+#define AT91SAM9N12_ROM_SIZE	SZ_128K		/* Internal ROM size (128Kb) */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h
new file mode 100644
index 0000000..40060cd
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h
@@ -0,0 +1,53 @@
+/*
+ * Matrix-centric header file for the AT91SAM9N12
+ *
+ * Copyright (C) 2012 Atmel Corporation.
+ *
+ * Only EBI related registers.
+ * Write Protect register definitions may be useful.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef _AT91SAM9N12_MATRIX_H_
+#define _AT91SAM9N12_MATRIX_H_
+
+#define AT91_MATRIX_EBICSA	(AT91_MATRIX + 0x118)	/* EBI Chip Select Assignment Register */
+#define		AT91_MATRIX_EBI_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
+#define			AT91_MATRIX_EBI_CS1A_SMC		(0 << 1)
+#define			AT91_MATRIX_EBI_CS1A_SDRAMC		(1 << 1)
+#define		AT91_MATRIX_EBI_CS3A		(1 << 3)	/* Chip Select 3 Assignment */
+#define			AT91_MATRIX_EBI_CS3A_SMC		(0 << 3)
+#define			AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH	(1 << 3)
+#define		AT91_MATRIX_EBI_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
+#define			AT91_MATRIX_EBI_DBPU_ON			(0 << 8)
+#define			AT91_MATRIX_EBI_DBPU_OFF		(1 << 8)
+#define		AT91_MATRIX_EBI_VDDIOMSEL	(1 << 16)	/* Memory voltage selection */
+#define			AT91_MATRIX_EBI_VDDIOMSEL_1_8V		(0 << 16)
+#define			AT91_MATRIX_EBI_VDDIOMSEL_3_3V		(1 << 16)
+#define		AT91_MATRIX_EBI_EBI_IOSR	(1 << 17)	/* EBI I/O slew rate selection */
+#define			AT91_MATRIX_EBI_EBI_IOSR_REDUCED	(0 << 17)
+#define			AT91_MATRIX_EBI_EBI_IOSR_NORMAL		(1 << 17)
+#define		AT91_MATRIX_EBI_DDR_IOSR	(1 << 18)	/* DDR2 dedicated port I/O slew rate selection */
+#define			AT91_MATRIX_EBI_DDR_IOSR_REDUCED	(0 << 18)
+#define			AT91_MATRIX_EBI_DDR_IOSR_NORMAL		(1 << 18)
+#define		AT91_MATRIX_NFD0_SELECT		(1 << 24)	/* NAND Flash Data Bus Selection */
+#define			AT91_MATRIX_NFD0_ON_D0			(0 << 24)
+#define			AT91_MATRIX_NFD0_ON_D16			(1 << 24)
+#define		AT91_MATRIX_DDR_MP_EN		(1 << 25)	/* DDR Multi-port Enable */
+#define			AT91_MATRIX_MP_OFF			(0 << 25)
+#define			AT91_MATRIX_MP_ON			(1 << 25)
+
+#define AT91_MATRIX_WPMR	(AT91_MATRIX + 0x1E4)	/* Write Protect Mode Register */
+#define		AT91_MATRIX_WPMR_WPEN		(1 << 0)	/* Write Protect ENable */
+#define			AT91_MATRIX_WPMR_WP_WPDIS		(0 << 0)
+#define			AT91_MATRIX_WPMR_WP_WPEN		(1 << 0)
+#define		AT91_MATRIX_WPMR_WPKEY		(0xFFFFFF << 8)	/* Write Protect KEY */
+
+#define AT91_MATRIX_WPSR	(AT91_MATRIX + 0x1E8)	/* Write Protect Status Register */
+#define		AT91_MATRIX_WPSR_WPVS		(1 << 0)	/* Write Protect Violation Status */
+#define			AT91_MATRIX_WPSR_NO_WPV		(0 << 0)
+#define			AT91_MATRIX_WPSR_WPV		(1 << 0)
+#define		AT91_MATRIX_WPSR_WPVSRC		(0xFFFF << 8)	/* Write Protect Violation Source */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9rl.h b/arch/arm/mach-at91/include/mach/at91sam9rl.h
index e0073eb..a15db56 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9rl.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9rl.h
@@ -89,11 +89,6 @@
 #define AT91SAM9RL_BASE_GPBR	0xfffffd60
 #define AT91SAM9RL_BASE_RTC	0xfffffe00
 
-#define AT91_USART0	AT91SAM9RL_BASE_US0
-#define AT91_USART1	AT91SAM9RL_BASE_US1
-#define AT91_USART2	AT91SAM9RL_BASE_US2
-#define AT91_USART3	AT91SAM9RL_BASE_US3
-
 
 /*
  * Internal Memory.
diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h
index 88e43d5..c75ee19 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
@@ -55,14 +55,6 @@
 #define AT91SAM9X5_BASE_USART2	0xf8024000
 
 /*
- * Base addresses for early serial code (uncompress.h)
- */
-#define AT91_DBGU	AT91_BASE_DBGU0
-#define AT91_USART0	AT91SAM9X5_BASE_USART0
-#define AT91_USART1	AT91SAM9X5_BASE_USART1
-#define AT91_USART2	AT91SAM9X5_BASE_USART2
-
-/*
  * Internal Memory.
  */
 #define AT91SAM9X5_SRAM_BASE	0x00300000	/* Internal SRAM base address */
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 49a8211..369afc2 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -121,7 +121,6 @@
 #define ATMEL_UART_RI	0x20
 
 extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins);
-extern void __init at91_set_serial_console(unsigned portnr);
 
 extern struct platform_device *atmel_default_console_device;
 
diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h
index 0118c33..b6504c1 100644
--- a/arch/arm/mach-at91/include/mach/cpu.h
+++ b/arch/arm/mach-at91/include/mach/cpu.h
@@ -25,6 +25,7 @@
 #define ARCH_ID_AT91SAM9G45MRL	0x819b05a2	/* aka 9G45-ES2 & non ES lots */
 #define ARCH_ID_AT91SAM9G45ES	0x819b05a1	/* 9G45-ES (Engineering Sample) */
 #define ARCH_ID_AT91SAM9X5	0x819a05a0
+#define ARCH_ID_AT91SAM9N12	0x819a07a0
 
 #define ARCH_ID_AT91SAM9XE128	0x329973a0
 #define ARCH_ID_AT91SAM9XE256	0x329a93a0
@@ -54,6 +55,7 @@
 #define ARCH_REVISON_9200_BGA	(0 << 0)
 #define ARCH_REVISON_9200_PQFP	(1 << 0)
 
+#ifndef __ASSEMBLY__
 enum at91_soc_type {
 	/* 920T */
 	AT91_SOC_RM9200,
@@ -70,6 +72,9 @@
 	/* SAM9X5 */
 	AT91_SOC_SAM9X5,
 
+	/* SAM9N12 */
+	AT91_SOC_SAM9N12,
+
 	/* Unknown type */
 	AT91_SOC_NONE
 };
@@ -106,7 +111,7 @@
 	return at91_soc_initdata.type != AT91_SOC_NONE;
 }
 
-#ifdef CONFIG_ARCH_AT91RM9200
+#ifdef CONFIG_SOC_AT91RM9200
 #define cpu_is_at91rm9200()	(at91_soc_initdata.type == AT91_SOC_RM9200)
 #define cpu_is_at91rm9200_bga()	(at91_soc_initdata.subtype == AT91_SOC_RM9200_BGA)
 #define cpu_is_at91rm9200_pqfp() (at91_soc_initdata.subtype == AT91_SOC_RM9200_PQFP)
@@ -116,45 +121,37 @@
 #define cpu_is_at91rm9200_pqfp() (0)
 #endif
 
-#ifdef CONFIG_ARCH_AT91SAM9260
+#ifdef CONFIG_SOC_AT91SAM9260
 #define cpu_is_at91sam9xe()	(at91_soc_initdata.subtype == AT91_SOC_SAM9XE)
 #define cpu_is_at91sam9260()	(at91_soc_initdata.type == AT91_SOC_SAM9260)
+#define cpu_is_at91sam9g20()	(at91_soc_initdata.type == AT91_SOC_SAM9G20)
 #else
 #define cpu_is_at91sam9xe()	(0)
 #define cpu_is_at91sam9260()	(0)
-#endif
-
-#ifdef CONFIG_ARCH_AT91SAM9G20
-#define cpu_is_at91sam9g20()	(at91_soc_initdata.type == AT91_SOC_SAM9G20)
-#else
 #define cpu_is_at91sam9g20()	(0)
 #endif
 
-#ifdef CONFIG_ARCH_AT91SAM9261
+#ifdef CONFIG_SOC_AT91SAM9261
 #define cpu_is_at91sam9261()	(at91_soc_initdata.type == AT91_SOC_SAM9261)
-#else
-#define cpu_is_at91sam9261()	(0)
-#endif
-
-#ifdef CONFIG_ARCH_AT91SAM9G10
 #define cpu_is_at91sam9g10()	(at91_soc_initdata.type == AT91_SOC_SAM9G10)
 #else
+#define cpu_is_at91sam9261()	(0)
 #define cpu_is_at91sam9g10()	(0)
 #endif
 
-#ifdef CONFIG_ARCH_AT91SAM9263
+#ifdef CONFIG_SOC_AT91SAM9263
 #define cpu_is_at91sam9263()	(at91_soc_initdata.type == AT91_SOC_SAM9263)
 #else
 #define cpu_is_at91sam9263()	(0)
 #endif
 
-#ifdef CONFIG_ARCH_AT91SAM9RL
+#ifdef CONFIG_SOC_AT91SAM9RL
 #define cpu_is_at91sam9rl()	(at91_soc_initdata.type == AT91_SOC_SAM9RL)
 #else
 #define cpu_is_at91sam9rl()	(0)
 #endif
 
-#ifdef CONFIG_ARCH_AT91SAM9G45
+#ifdef CONFIG_SOC_AT91SAM9G45
 #define cpu_is_at91sam9g45()	(at91_soc_initdata.type == AT91_SOC_SAM9G45)
 #define cpu_is_at91sam9g45es()	(at91_soc_initdata.subtype == AT91_SOC_SAM9G45ES)
 #define cpu_is_at91sam9m10()	(at91_soc_initdata.subtype == AT91_SOC_SAM9M10)
@@ -168,7 +165,7 @@
 #define cpu_is_at91sam9m11()	(0)
 #endif
 
-#ifdef CONFIG_ARCH_AT91SAM9X5
+#ifdef CONFIG_SOC_AT91SAM9X5
 #define cpu_is_at91sam9x5()	(at91_soc_initdata.type == AT91_SOC_SAM9X5)
 #define cpu_is_at91sam9g15()	(at91_soc_initdata.subtype == AT91_SOC_SAM9G15)
 #define cpu_is_at91sam9g35()	(at91_soc_initdata.subtype == AT91_SOC_SAM9G35)
@@ -184,10 +181,17 @@
 #define cpu_is_at91sam9x25()	(0)
 #endif
 
+#ifdef CONFIG_SOC_AT91SAM9N12
+#define cpu_is_at91sam9n12()	(at91_soc_initdata.type == AT91_SOC_SAM9N12)
+#else
+#define cpu_is_at91sam9n12()	(0)
+#endif
+
 /*
  * Since this is ARM, we will never run on any AVR32 CPU. But these
  * definitions may reduce clutter in common drivers.
  */
 #define cpu_is_at32ap7000()	(0)
+#endif /* __ASSEMBLY__ */
 
 #endif /* __MACH_CPU_H__ */
diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
index 01db372..09242b6 100644
--- a/arch/arm/mach-at91/include/mach/hardware.h
+++ b/arch/arm/mach-at91/include/mach/hardware.h
@@ -22,27 +22,18 @@
 /* 9263, 9g45 */
 #define AT91_BASE_DBGU1	0xffffee00
 
-#if defined(CONFIG_ARCH_AT91RM9200)
-#include <mach/at91rm9200.h>
-#elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
-#include <mach/at91sam9260.h>
-#elif defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10)
-#include <mach/at91sam9261.h>
-#elif defined(CONFIG_ARCH_AT91SAM9263)
-#include <mach/at91sam9263.h>
-#elif defined(CONFIG_ARCH_AT91SAM9RL)
-#include <mach/at91sam9rl.h>
-#elif defined(CONFIG_ARCH_AT91SAM9G45)
-#include <mach/at91sam9g45.h>
-#elif defined(CONFIG_ARCH_AT91SAM9X5)
-#include <mach/at91sam9x5.h>
-#elif defined(CONFIG_ARCH_AT91X40)
+#if defined(CONFIG_ARCH_AT91X40)
 #include <mach/at91x40.h>
 #else
-#error "Unsupported AT91 processor"
-#endif
+#include <mach/at91rm9200.h>
+#include <mach/at91sam9260.h>
+#include <mach/at91sam9261.h>
+#include <mach/at91sam9263.h>
+#include <mach/at91sam9rl.h>
+#include <mach/at91sam9g45.h>
+#include <mach/at91sam9x5.h>
+#include <mach/at91sam9n12.h>
 
-#if !defined(CONFIG_ARCH_AT91X40)
 /*
  * On all at91 except rm9200 and x40 have the System Controller starts
  * at address 0xffffc000 and has a size of 16KiB.
diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h
index 4218647..6f6118d 100644
--- a/arch/arm/mach-at91/include/mach/uncompress.h
+++ b/arch/arm/mach-at91/include/mach/uncompress.h
@@ -1,7 +1,8 @@
 /*
  * arch/arm/mach-at91/include/mach/uncompress.h
  *
- *  Copyright (C) 2003 SAN People
+ * Copyright (C) 2003 SAN People
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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
@@ -25,22 +26,147 @@
 #include <linux/atmel_serial.h>
 #include <mach/hardware.h>
 
-#if defined(CONFIG_AT91_EARLY_DBGU0)
-#define UART_OFFSET AT91_BASE_DBGU0
-#elif defined(CONFIG_AT91_EARLY_DBGU1)
-#define UART_OFFSET AT91_BASE_DBGU1
-#elif defined(CONFIG_AT91_EARLY_USART0)
-#define UART_OFFSET AT91_USART0
-#elif defined(CONFIG_AT91_EARLY_USART1)
-#define UART_OFFSET AT91_USART1
-#elif defined(CONFIG_AT91_EARLY_USART2)
-#define UART_OFFSET AT91_USART2
-#elif defined(CONFIG_AT91_EARLY_USART3)
-#define UART_OFFSET AT91_USART3
-#elif defined(CONFIG_AT91_EARLY_USART4)
-#define UART_OFFSET AT91_USART4
-#elif defined(CONFIG_AT91_EARLY_USART5)
-#define UART_OFFSET AT91_USART5
+#include <mach/at91_dbgu.h>
+#include <mach/cpu.h>
+
+void __iomem *at91_uart;
+
+#if !defined(CONFIG_ARCH_AT91X40)
+static const u32 uarts_rm9200[] = {
+	AT91_BASE_DBGU0,
+	AT91RM9200_BASE_US0,
+	AT91RM9200_BASE_US1,
+	AT91RM9200_BASE_US2,
+	AT91RM9200_BASE_US3,
+	0,
+};
+
+static const u32 uarts_sam9260[] = {
+	AT91_BASE_DBGU0,
+	AT91SAM9260_BASE_US0,
+	AT91SAM9260_BASE_US1,
+	AT91SAM9260_BASE_US2,
+	AT91SAM9260_BASE_US3,
+	AT91SAM9260_BASE_US4,
+	AT91SAM9260_BASE_US5,
+	0,
+};
+
+static const u32 uarts_sam9261[] = {
+	AT91_BASE_DBGU0,
+	AT91SAM9261_BASE_US0,
+	AT91SAM9261_BASE_US1,
+	AT91SAM9261_BASE_US2,
+	0,
+};
+
+static const u32 uarts_sam9263[] = {
+	AT91_BASE_DBGU1,
+	AT91SAM9263_BASE_US0,
+	AT91SAM9263_BASE_US1,
+	AT91SAM9263_BASE_US2,
+	0,
+};
+
+static const u32 uarts_sam9g45[] = {
+	AT91_BASE_DBGU1,
+	AT91SAM9G45_BASE_US0,
+	AT91SAM9G45_BASE_US1,
+	AT91SAM9G45_BASE_US2,
+	AT91SAM9G45_BASE_US3,
+	0,
+};
+
+static const u32 uarts_sam9rl[] = {
+	AT91_BASE_DBGU0,
+	AT91SAM9RL_BASE_US0,
+	AT91SAM9RL_BASE_US1,
+	AT91SAM9RL_BASE_US2,
+	AT91SAM9RL_BASE_US3,
+	0,
+};
+
+static const u32 uarts_sam9x5[] = {
+	AT91_BASE_DBGU0,
+	AT91SAM9X5_BASE_USART0,
+	AT91SAM9X5_BASE_USART1,
+	AT91SAM9X5_BASE_USART2,
+	0,
+};
+
+static inline const u32* decomp_soc_detect(u32 dbgu_base)
+{
+	u32 cidr, socid;
+
+	cidr = __raw_readl(dbgu_base + AT91_DBGU_CIDR);
+	socid = cidr & ~AT91_CIDR_VERSION;
+
+	switch (socid) {
+	case ARCH_ID_AT91RM9200:
+		return uarts_rm9200;
+
+	case ARCH_ID_AT91SAM9G20:
+	case ARCH_ID_AT91SAM9260:
+		return uarts_sam9260;
+
+	case ARCH_ID_AT91SAM9261:
+		return uarts_sam9261;
+
+	case ARCH_ID_AT91SAM9263:
+		return uarts_sam9263;
+
+	case ARCH_ID_AT91SAM9G45:
+		return uarts_sam9g45;
+
+	case ARCH_ID_AT91SAM9RL64:
+		return uarts_sam9rl;
+
+	case ARCH_ID_AT91SAM9X5:
+		return uarts_sam9x5;
+	}
+
+	/* at91sam9g10 */
+	if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
+		return uarts_sam9261;
+	}
+	/* at91sam9xe */
+	else if ((cidr & AT91_CIDR_ARCH) == ARCH_FAMILY_AT91SAM9XE) {
+		return uarts_sam9260;
+	}
+
+	return NULL;
+}
+
+static inline void arch_decomp_setup(void)
+{
+	int i = 0;
+	const u32* usarts;
+
+	usarts = decomp_soc_detect(AT91_BASE_DBGU0);
+
+	if (!usarts)
+		usarts = decomp_soc_detect(AT91_BASE_DBGU1);
+	if (!usarts) {
+		at91_uart = NULL;
+		return;
+	}
+
+	do {
+		/* physical address */
+		at91_uart = (void __iomem *)usarts[i];
+
+		if (__raw_readl(at91_uart + ATMEL_US_BRGR))
+			return;
+		i++;
+	} while (usarts[i]);
+
+	at91_uart = NULL;
+}
+#else
+static inline void arch_decomp_setup(void)
+{
+	at91_uart = NULL;
+}
 #endif
 
 /*
@@ -52,28 +178,24 @@
  */
 static void putc(int c)
 {
-#ifdef UART_OFFSET
-	void __iomem *sys = (void __iomem *) UART_OFFSET;	/* physical address */
+	if (!at91_uart)
+		return;
 
-	while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXRDY))
+	while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXRDY))
 		barrier();
-	__raw_writel(c, sys + ATMEL_US_THR);
-#endif
+	__raw_writel(c, at91_uart + ATMEL_US_THR);
 }
 
 static inline void flush(void)
 {
-#ifdef UART_OFFSET
-	void __iomem *sys = (void __iomem *) UART_OFFSET;	/* physical address */
+	if (!at91_uart)
+		return;
 
 	/* wait for transmission to complete */
-	while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXEMPTY))
+	while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXEMPTY))
 		barrier();
-#endif
 }
 
-#define arch_decomp_setup()
-
 #define arch_decomp_wdog()
 
 #endif
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index f630250..1bfaad6 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -261,7 +261,12 @@
 			 * For ARM 926 based chips, this requirement is weaker
 			 * as at91sam9 can access a RAM in self-refresh mode.
 			 */
-			at91_standby();
+			if (cpu_is_at91rm9200())
+				at91rm9200_standby();
+			else if (cpu_is_at91sam9g45())
+				at91sam9g45_standby();
+			else
+				at91sam9_standby();
 			break;
 
 		case PM_SUSPEND_ON:
@@ -307,10 +312,9 @@
 
 	pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : ""));
 
-#ifdef CONFIG_ARCH_AT91RM9200
 	/* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */
-	at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
-#endif
+	if (cpu_is_at91rm9200())
+		at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
 
 	suspend_set_ops(&at91_pm_ops);
 
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
index 89f56f3..38f467c 100644
--- a/arch/arm/mach-at91/pm.h
+++ b/arch/arm/mach-at91/pm.h
@@ -12,7 +12,6 @@
 #define __ARCH_ARM_MACH_AT91_PM
 
 #include <mach/at91_ramc.h>
-#ifdef CONFIG_ARCH_AT91RM9200
 #include <mach/at91rm9200_sdramc.h>
 
 /*
@@ -43,10 +42,6 @@
 		  "r" (lpr));
 }
 
-#define at91_standby at91rm9200_standby
-
-#elif defined(CONFIG_ARCH_AT91SAM9G45)
-
 /* We manage both DDRAM/SDRAM controllers, we need more than one value to
  * remember.
  */
@@ -75,11 +70,7 @@
 	at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
 }
 
-#define at91_standby at91sam9g45_standby
-
-#else
-
-#ifdef CONFIG_ARCH_AT91SAM9263
+#ifdef CONFIG_SOC_AT91SAM9263
 /*
  * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
  * handle those cases both here and in the Suspend-To-RAM support.
@@ -102,8 +93,4 @@
 	at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr);
 }
 
-#define at91_standby at91sam9_standby
-
-#endif
-
 #endif
diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
index db54521..098c28d 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -18,7 +18,7 @@
 #include <mach/at91_ramc.h>
 
 
-#ifdef CONFIG_ARCH_AT91SAM9263
+#ifdef CONFIG_SOC_AT91SAM9263
 /*
  * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
  * handle those cases both here and in the Suspend-To-RAM support.
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index f44a2e7..944bffb 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -143,6 +143,11 @@
 		at91_soc_initdata.type = AT91_SOC_SAM9X5;
 		at91_boot_soc = at91sam9x5_soc;
 		break;
+
+	case ARCH_ID_AT91SAM9N12:
+		at91_soc_initdata.type = AT91_SOC_SAM9N12;
+		at91_boot_soc = at91sam9n12_soc;
+		break;
 	}
 
 	/* at91sam9g10 */
@@ -210,6 +215,7 @@
 	[AT91_SOC_SAM9G45]	= "at91sam9g45",
 	[AT91_SOC_SAM9RL]	= "at91sam9rl",
 	[AT91_SOC_SAM9X5]	= "at91sam9x5",
+	[AT91_SOC_SAM9N12]	= "at91sam9n12",
 	[AT91_SOC_NONE]		= "Unknown"
 };
 
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
index 5db4aa4..a9cfeb1 100644
--- a/arch/arm/mach-at91/soc.h
+++ b/arch/arm/mach-at91/soc.h
@@ -20,36 +20,41 @@
 extern struct at91_init_soc at91sam9g45_soc;
 extern struct at91_init_soc at91sam9rl_soc;
 extern struct at91_init_soc at91sam9x5_soc;
+extern struct at91_init_soc at91sam9n12_soc;
 
 static inline int at91_soc_is_enabled(void)
 {
 	return at91_boot_soc.init != NULL;
 }
 
-#if !defined(CONFIG_ARCH_AT91RM9200)
+#if !defined(CONFIG_SOC_AT91RM9200)
 #define at91rm9200_soc	at91_boot_soc
 #endif
 
-#if !(defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20))
+#if !defined(CONFIG_SOC_AT91SAM9260)
 #define at91sam9260_soc	at91_boot_soc
 #endif
 
-#if !(defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10))
+#if !defined(CONFIG_SOC_AT91SAM9261)
 #define at91sam9261_soc	at91_boot_soc
 #endif
 
-#if !defined(CONFIG_ARCH_AT91SAM9263)
+#if !defined(CONFIG_SOC_AT91SAM9263)
 #define at91sam9263_soc	at91_boot_soc
 #endif
 
-#if !defined(CONFIG_ARCH_AT91SAM9G45)
+#if !defined(CONFIG_SOC_AT91SAM9G45)
 #define at91sam9g45_soc	at91_boot_soc
 #endif
 
-#if !defined(CONFIG_ARCH_AT91SAM9RL)
+#if !defined(CONFIG_SOC_AT91SAM9RL)
 #define at91sam9rl_soc	at91_boot_soc
 #endif
 
-#if !defined(CONFIG_ARCH_AT91SAM9X5)
+#if !defined(CONFIG_SOC_AT91SAM9X5)
 #define at91sam9x5_soc	at91_boot_soc
 #endif
+
+#if !defined(CONFIG_SOC_AT91SAM9N12)
+#define at91sam9n12_soc	at91_boot_soc
+#endif
diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig
index eb34bd12..ea036d6 100644
--- a/arch/arm/mach-clps711x/Kconfig
+++ b/arch/arm/mach-clps711x/Kconfig
@@ -1,6 +1,6 @@
 if ARCH_CLPS711X
 
-menu "CLPS711X/EP721X Implementations"
+menu "CLPS711X/EP721X/EP731X Implementations"
 
 config ARCH_AUTCPU12
 	bool "AUTCPU12"
@@ -45,26 +45,13 @@
 config ARCH_FORTUNET
 	bool "FORTUNET"
 
-# XXX Maybe these should indicate register compatibility
-# instead of being mutually exclusive.
-config ARCH_EP7211
-	bool
-	depends on ARCH_EDB7211
-	default y
-
-config ARCH_EP7212
-	bool
-	depends on ARCH_P720T || ARCH_CEIVA
-	default y
-
 config EP72XX_ROM_BOOT
-	bool "EP72xx ROM boot"
-	depends on ARCH_EP7211 || ARCH_EP7212
-	---help---
+	bool "EP721x/EP731x ROM boot"
+	help
 	  If you say Y here, your CLPS711x-based kernel will use the bootstrap
 	  mode memory map instead of the normal memory map.
 
-	  Processors derived from the Cirrus CLPS-711X core support two boot
+	  Processors derived from the Cirrus CLPS711X core support two boot
 	  modes.  Normal mode boots from the external memory device at CS0.
 	  Bootstrap mode rearranges parts of the memory map, placing an
 	  internal 128 byte bootstrap ROM at CS0.  This option performs the
diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c
index 3c5b5bb..c965fd8 100644
--- a/arch/arm/mach-clps711x/common.c
+++ b/arch/arm/mach-clps711x/common.c
@@ -36,7 +36,6 @@
 #include <asm/page.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
-#include <asm/hardware/clps7111.h>
 #include <asm/system_misc.h>
 
 /*
@@ -44,8 +43,8 @@
  */
 static struct map_desc clps711x_io_desc[] __initdata = {
 	{
-		.virtual	= CLPS7111_VIRT_BASE,
-		.pfn		= __phys_to_pfn(CLPS7111_PHYS_BASE),
+		.virtual	= (unsigned long)CLPS711X_VIRT_BASE,
+		.pfn		= __phys_to_pfn(CLPS711X_PHYS_BASE),
 		.length		= SZ_1M,
 		.type		= MT_DEVICE
 	}
@@ -67,12 +66,6 @@
 
 static void int1_ack(struct irq_data *d)
 {
-	u32 intmr1;
-
-	intmr1 = clps_readl(INTMR1);
-	intmr1 &= ~(1 << d->irq);
-	clps_writel(intmr1, INTMR1);
-
 	switch (d->irq) {
 	case IRQ_CSINT:  clps_writel(0, COEOI);  break;
 	case IRQ_TC1OI:  clps_writel(0, TC1EOI); break;
@@ -109,12 +102,6 @@
 
 static void int2_ack(struct irq_data *d)
 {
-	u32 intmr2;
-
-	intmr2 = clps_readl(INTMR2);
-	intmr2 &= ~(1 << (d->irq - 16));
-	clps_writel(intmr2, INTMR2);
-
 	switch (d->irq) {
 	case IRQ_KBDINT: clps_writel(0, KBDEOI); break;
 	}
diff --git a/arch/arm/mach-clps711x/include/mach/clps711x.h b/arch/arm/mach-clps711x/include/mach/clps711x.h
new file mode 100644
index 0000000..1dd806f
--- /dev/null
+++ b/arch/arm/mach-clps711x/include/mach/clps711x.h
@@ -0,0 +1,278 @@
+/*
+ *  This file contains the hardware definitions of the Cirrus Logic
+ *  ARM7 CLPS711X internal registers.
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions 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.
+ *
+ * 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 __MACH_CLPS711X_H
+#define __MACH_CLPS711X_H
+
+#define CLPS711X_PHYS_BASE	(0x80000000)
+
+#define PADR		(0x0000)
+#define PBDR		(0x0001)
+#define PCDR		(0x0002)
+#define PDDR		(0x0003)
+#define PADDR		(0x0040)
+#define PBDDR		(0x0041)
+#define PCDDR		(0x0042)
+#define PDDDR		(0x0043)
+#define PEDR		(0x0080)
+#define PEDDR		(0x00c0)
+#define SYSCON1		(0x0100)
+#define SYSFLG1		(0x0140)
+#define MEMCFG1		(0x0180)
+#define MEMCFG2		(0x01c0)
+#define DRFPR		(0x0200)
+#define INTSR1		(0x0240)
+#define INTMR1		(0x0280)
+#define LCDCON		(0x02c0)
+#define TC1D		(0x0300)
+#define TC2D		(0x0340)
+#define RTCDR		(0x0380)
+#define RTCMR		(0x03c0)
+#define PMPCON		(0x0400)
+#define CODR		(0x0440)
+#define UARTDR1		(0x0480)
+#define UBRLCR1		(0x04c0)
+#define SYNCIO		(0x0500)
+#define PALLSW		(0x0540)
+#define PALMSW		(0x0580)
+#define STFCLR		(0x05c0)
+#define BLEOI		(0x0600)
+#define MCEOI		(0x0640)
+#define TEOI		(0x0680)
+#define TC1EOI		(0x06c0)
+#define TC2EOI		(0x0700)
+#define RTCEOI		(0x0740)
+#define UMSEOI		(0x0780)
+#define COEOI		(0x07c0)
+#define HALT		(0x0800)
+#define STDBY		(0x0840)
+
+#define FBADDR		(0x1000)
+#define SYSCON2		(0x1100)
+#define SYSFLG2		(0x1140)
+#define INTSR2		(0x1240)
+#define INTMR2		(0x1280)
+#define UARTDR2		(0x1480)
+#define UBRLCR2		(0x14c0)
+#define SS2DR		(0x1500)
+#define SRXEOF		(0x1600)
+#define SS2POP		(0x16c0)
+#define KBDEOI		(0x1700)
+
+#define DAIR		(0x2000)
+#define DAIR0		(0x2040)
+#define DAIDR1		(0x2080)
+#define DAIDR2		(0x20c0)
+#define DAISR		(0x2100)
+#define SYSCON3		(0x2200)
+#define INTSR3		(0x2240)
+#define INTMR3		(0x2280)
+#define LEDFLSH		(0x22c0)
+#define SDCONF		(0x2300)
+#define SDRFPR		(0x2340)
+#define UNIQID		(0x2440)
+#define DAI64FS		(0x2600)
+#define PLLW		(0x2610)
+#define PLLR		(0xa5a8)
+#define RANDID0		(0x2700)
+#define RANDID1		(0x2704)
+#define RANDID2		(0x2708)
+#define RANDID3		(0x270c)
+
+/* common bits: SYSCON1 / SYSCON2 */
+#define SYSCON_UARTEN		(1 << 8)
+
+#define SYSCON1_KBDSCAN(x)	((x) & 15)
+#define SYSCON1_KBDSCANMASK	(15)
+#define SYSCON1_TC1M		(1 << 4)
+#define SYSCON1_TC1S		(1 << 5)
+#define SYSCON1_TC2M		(1 << 6)
+#define SYSCON1_TC2S		(1 << 7)
+#define SYSCON1_UART1EN		SYSCON_UARTEN
+#define SYSCON1_BZTOG		(1 << 9)
+#define SYSCON1_BZMOD		(1 << 10)
+#define SYSCON1_DBGEN		(1 << 11)
+#define SYSCON1_LCDEN		(1 << 12)
+#define SYSCON1_CDENTX		(1 << 13)
+#define SYSCON1_CDENRX		(1 << 14)
+#define SYSCON1_SIREN		(1 << 15)
+#define SYSCON1_ADCKSEL(x)	(((x) & 3) << 16)
+#define SYSCON1_ADCKSEL_MASK	(3 << 16)
+#define SYSCON1_EXCKEN		(1 << 18)
+#define SYSCON1_WAKEDIS		(1 << 19)
+#define SYSCON1_IRTXM		(1 << 20)
+
+/* common bits: SYSFLG1 / SYSFLG2 */
+#define SYSFLG_UBUSY		(1 << 11)
+#define SYSFLG_URXFE		(1 << 22)
+#define SYSFLG_UTXFF		(1 << 23)
+
+#define SYSFLG1_MCDR		(1 << 0)
+#define SYSFLG1_DCDET		(1 << 1)
+#define SYSFLG1_WUDR		(1 << 2)
+#define SYSFLG1_WUON		(1 << 3)
+#define SYSFLG1_CTS		(1 << 8)
+#define SYSFLG1_DSR		(1 << 9)
+#define SYSFLG1_DCD		(1 << 10)
+#define SYSFLG1_UBUSY		SYSFLG_UBUSY
+#define SYSFLG1_NBFLG		(1 << 12)
+#define SYSFLG1_RSTFLG		(1 << 13)
+#define SYSFLG1_PFFLG		(1 << 14)
+#define SYSFLG1_CLDFLG		(1 << 15)
+#define SYSFLG1_URXFE		SYSFLG_URXFE
+#define SYSFLG1_UTXFF		SYSFLG_UTXFF
+#define SYSFLG1_CRXFE		(1 << 24)
+#define SYSFLG1_CTXFF		(1 << 25)
+#define SYSFLG1_SSIBUSY		(1 << 26)
+#define SYSFLG1_ID		(1 << 29)
+#define SYSFLG1_VERID(x)	(((x) >> 30) & 3)
+#define SYSFLG1_VERID_MASK	(3 << 30)
+
+#define SYSFLG2_SSRXOF		(1 << 0)
+#define SYSFLG2_RESVAL		(1 << 1)
+#define SYSFLG2_RESFRM		(1 << 2)
+#define SYSFLG2_SS2RXFE		(1 << 3)
+#define SYSFLG2_SS2TXFF		(1 << 4)
+#define SYSFLG2_SS2TXUF		(1 << 5)
+#define SYSFLG2_CKMODE		(1 << 6)
+#define SYSFLG2_UBUSY		SYSFLG_UBUSY
+#define SYSFLG2_URXFE		SYSFLG_URXFE
+#define SYSFLG2_UTXFF		SYSFLG_UTXFF
+
+#define LCDCON_GSEN		(1 << 30)
+#define LCDCON_GSMD		(1 << 31)
+
+#define SYSCON2_SERSEL		(1 << 0)
+#define SYSCON2_KBD6		(1 << 1)
+#define SYSCON2_DRAMZ		(1 << 2)
+#define SYSCON2_KBWEN		(1 << 3)
+#define SYSCON2_SS2TXEN		(1 << 4)
+#define SYSCON2_PCCARD1		(1 << 5)
+#define SYSCON2_PCCARD2		(1 << 6)
+#define SYSCON2_SS2RXEN		(1 << 7)
+#define SYSCON2_UART2EN		SYSCON_UARTEN
+#define SYSCON2_SS2MAEN		(1 << 9)
+#define SYSCON2_OSTB		(1 << 12)
+#define SYSCON2_CLKENSL		(1 << 13)
+#define SYSCON2_BUZFREQ		(1 << 14)
+
+/* common bits: UARTDR1 / UARTDR2 */
+#define UARTDR_FRMERR		(1 << 8)
+#define UARTDR_PARERR		(1 << 9)
+#define UARTDR_OVERR		(1 << 10)
+
+/* common bits: UBRLCR1 / UBRLCR2 */
+#define UBRLCR_BAUD_MASK	((1 << 12) - 1)
+#define UBRLCR_BREAK		(1 << 12)
+#define UBRLCR_PRTEN		(1 << 13)
+#define UBRLCR_EVENPRT		(1 << 14)
+#define UBRLCR_XSTOP		(1 << 15)
+#define UBRLCR_FIFOEN		(1 << 16)
+#define UBRLCR_WRDLEN5		(0 << 17)
+#define UBRLCR_WRDLEN6		(1 << 17)
+#define UBRLCR_WRDLEN7		(2 << 17)
+#define UBRLCR_WRDLEN8		(3 << 17)
+#define UBRLCR_WRDLEN_MASK	(3 << 17)
+
+#define SYNCIO_FRMLEN(x)	(((x) & 0x3f) << 7)
+#define SYNCIO_CFGLEN(x)	((x) & 0x7f)
+#define SYNCIO_SMCKEN		(1 << 13)
+#define SYNCIO_TXFRMEN		(1 << 14)
+
+#define DAIR_RESERVED		(0x0404)
+#define DAIR_DAIEN		(1 << 16)
+#define DAIR_ECS		(1 << 17)
+#define DAIR_LCTM		(1 << 19)
+#define DAIR_LCRM		(1 << 20)
+#define DAIR_RCTM		(1 << 21)
+#define DAIR_RCRM		(1 << 22)
+#define DAIR_LBM		(1 << 23)
+
+#define DAIDR2_FIFOEN		(1 << 15)
+#define DAIDR2_FIFOLEFT		(0x0d << 16)
+#define DAIDR2_FIFORIGHT	(0x11 << 16)
+
+#define DAISR_RCTS		(1 << 0)
+#define DAISR_RCRS		(1 << 1)
+#define DAISR_LCTS		(1 << 2)
+#define DAISR_LCRS		(1 << 3)
+#define DAISR_RCTU		(1 << 4)
+#define DAISR_RCRO		(1 << 5)
+#define DAISR_LCTU		(1 << 6)
+#define DAISR_LCRO		(1 << 7)
+#define DAISR_RCNF		(1 << 8)
+#define DAISR_RCNE		(1 << 9)
+#define DAISR_LCNF		(1 << 10)
+#define DAISR_LCNE		(1 << 11)
+#define DAISR_FIFO		(1 << 12)
+
+#define DAI64FS_I2SF64		(1 << 0)
+#define DAI64FS_AUDIOCLKEN	(1 << 1)
+#define DAI64FS_AUDIOCLKSRC	(1 << 2)
+#define DAI64FS_MCLK256EN	(1 << 3)
+#define DAI64FS_LOOPBACK	(1 << 5)
+
+#define SYSCON3_ADCCON		(1 << 0)
+#define SYSCON3_CLKCTL0		(1 << 1)
+#define SYSCON3_CLKCTL1		(1 << 2)
+#define SYSCON3_DAISEL		(1 << 3)
+#define SYSCON3_ADCCKNSEN	(1 << 4)
+#define SYSCON3_VERSN(x)	(((x) >> 5) & 7)
+#define SYSCON3_VERSN_MASK	(7 << 5)
+#define SYSCON3_FASTWAKE	(1 << 8)
+#define SYSCON3_DAIEN		(1 << 9)
+#define SYSCON3_128FS		SYSCON3_DAIEN
+#define SYSCON3_ENPD67		(1 << 10)
+
+#define SDCONF_ACTIVE		(1 << 10)
+#define SDCONF_CLKCTL		(1 << 9)
+#define SDCONF_WIDTH_4		(0 << 7)
+#define SDCONF_WIDTH_8		(1 << 7)
+#define SDCONF_WIDTH_16		(2 << 7)
+#define SDCONF_WIDTH_32		(3 << 7)
+#define SDCONF_SIZE_16		(0 << 5)
+#define SDCONF_SIZE_64		(1 << 5)
+#define SDCONF_SIZE_128		(2 << 5)
+#define SDCONF_SIZE_256		(3 << 5)
+#define SDCONF_CASLAT_2		(2)
+#define SDCONF_CASLAT_3		(3)
+
+#define MEMCFG_BUS_WIDTH_32	(1)
+#define MEMCFG_BUS_WIDTH_16	(0)
+#define MEMCFG_BUS_WIDTH_8	(3)
+
+#define MEMCFG_WAITSTATE_8_3	(0 << 2)
+#define MEMCFG_WAITSTATE_7_3	(1 << 2)
+#define MEMCFG_WAITSTATE_6_3	(2 << 2)
+#define MEMCFG_WAITSTATE_5_3	(3 << 2)
+#define MEMCFG_WAITSTATE_4_2	(4 << 2)
+#define MEMCFG_WAITSTATE_3_2	(5 << 2)
+#define MEMCFG_WAITSTATE_2_2	(6 << 2)
+#define MEMCFG_WAITSTATE_1_2	(7 << 2)
+#define MEMCFG_WAITSTATE_8_1	(8 << 2)
+#define MEMCFG_WAITSTATE_7_1	(9 << 2)
+#define MEMCFG_WAITSTATE_6_1	(10 << 2)
+#define MEMCFG_WAITSTATE_5_1	(11 << 2)
+#define MEMCFG_WAITSTATE_4_0	(12 << 2)
+#define MEMCFG_WAITSTATE_3_0	(13 << 2)
+#define MEMCFG_WAITSTATE_2_0	(14 << 2)
+#define MEMCFG_WAITSTATE_1_0	(15 << 2)
+
+#endif /* __MACH_CLPS711X_H */
diff --git a/arch/arm/mach-clps711x/include/mach/debug-macro.S b/arch/arm/mach-clps711x/include/mach/debug-macro.S
index b802e8a..118b3d9 100644
--- a/arch/arm/mach-clps711x/include/mach/debug-macro.S
+++ b/arch/arm/mach-clps711x/include/mach/debug-macro.S
@@ -12,7 +12,6 @@
 */
 
 #include <mach/hardware.h>
-#include <asm/hardware/clps7111.h>
 
 		.macro	addruart, rp, rv, tmp
 #ifndef CONFIG_DEBUG_CLPS711X_UART2
@@ -20,8 +19,8 @@
 #else
 		mov	\rp, #0x1000	@ UART2
 #endif
-		orr	\rv, \rp, #CLPS7111_VIRT_BASE
-		orr	\rp, \rp, #CLPS7111_PHYS_BASE
+		orr	\rv, \rp, #CLPS711X_VIRT_BASE
+		orr	\rp, \rp, #CLPS711X_PHYS_BASE
 		.endm
 
 		.macro	senduart,rd,rx
diff --git a/arch/arm/mach-clps711x/include/mach/entry-macro.S b/arch/arm/mach-clps711x/include/mach/entry-macro.S
index 125af59..56e5c2c 100644
--- a/arch/arm/mach-clps711x/include/mach/entry-macro.S
+++ b/arch/arm/mach-clps711x/include/mach/entry-macro.S
@@ -8,7 +8,6 @@
  * warranty of any kind, whether express or implied.
  */
 #include <mach/hardware.h>
-#include <asm/hardware/clps7111.h>
 
 		.macro	get_irqnr_preamble, base, tmp
 		.endm
@@ -18,7 +17,7 @@
 #endif
 
 		.macro	get_irqnr_and_base, irqnr, stat, base, mask
-		mov	\base, #CLPS7111_BASE
+		mov	\base, #CLPS711X_VIRT_BASE
 		ldr	\stat, [\base, #INTSR1]
 		ldr	\mask, [\base, #INTMR1]
 		mov	\irqnr, #4
diff --git a/arch/arm/mach-clps711x/include/mach/hardware.h b/arch/arm/mach-clps711x/include/mach/hardware.h
index d0b7d87..13a64fc 100644
--- a/arch/arm/mach-clps711x/include/mach/hardware.h
+++ b/arch/arm/mach-clps711x/include/mach/hardware.h
@@ -19,12 +19,21 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
+#ifndef __MACH_HARDWARE_H
+#define __MACH_HARDWARE_H
 
+#include <mach/clps711x.h>
 
-#define CLPS7111_VIRT_BASE	0xff000000
-#define CLPS7111_BASE		CLPS7111_VIRT_BASE
+#define CLPS711X_VIRT_BASE	IOMEM(0xff000000)
+
+#ifndef __ASSEMBLY__
+#define clps_readb(off)		readb(CLPS711X_VIRT_BASE + (off))
+#define clps_readw(off)		readw(CLPS711X_VIRT_BASE + (off))
+#define clps_readl(off)		readl(CLPS711X_VIRT_BASE + (off))
+#define clps_writeb(val,off)	writeb(val, CLPS711X_VIRT_BASE + (off))
+#define clps_writew(val,off)	writew(val, CLPS711X_VIRT_BASE + (off))
+#define clps_writel(val,off)	writel(val, CLPS711X_VIRT_BASE + (off))
+#endif
 
 /*
  * The physical addresses that the external chip select signals map to is
@@ -52,46 +61,11 @@
 #define CS7_PHYS_BASE		(0x00000000)
 #endif
 
-#if defined (CONFIG_ARCH_EP7211)
-
-#define EP7211_VIRT_BASE	CLPS7111_VIRT_BASE
-#define EP7211_BASE		CLPS7111_VIRT_BASE
-#include <asm/hardware/ep7211.h>
-
-#elif defined (CONFIG_ARCH_EP7212)
-
-#define EP7212_VIRT_BASE	CLPS7111_VIRT_BASE
-#define EP7212_BASE		CLPS7111_VIRT_BASE
-#include <asm/hardware/ep7212.h>
-
-#endif
-
 #define SYSPLD_VIRT_BASE	0xfe000000
 #define SYSPLD_BASE		SYSPLD_VIRT_BASE
 
-#if  defined (CONFIG_ARCH_AUTCPU12)
-
-#define  CS89712_VIRT_BASE	CLPS7111_VIRT_BASE
-#define  CS89712_BASE		CLPS7111_VIRT_BASE
-
-#include <asm/hardware/clps7111.h>
-#include <asm/hardware/ep7212.h>
-#include <asm/hardware/cs89712.h>
-
-#endif
-
-
 #if defined (CONFIG_ARCH_CDB89712)
 
-#include <asm/hardware/clps7111.h>
-#include <asm/hardware/ep7212.h>
-#include <asm/hardware/cs89712.h>
-
-/* static cdb89712_map_io() areas */
-#define REGISTER_START   0x80000000
-#define REGISTER_SIZE    0x4000
-#define REGISTER_BASE    0xff000000
-
 #define ETHER_START      0x20000000
 #define ETHER_SIZE       0x1000
 #define ETHER_BASE       0xfe000000
@@ -154,13 +128,6 @@
 
 #if defined (CONFIG_ARCH_CEIVA)
 
-#define  CEIVA_VIRT_BASE	CLPS7111_VIRT_BASE
-#define  CEIVA_BASE		CLPS7111_VIRT_BASE
-
-#include <asm/hardware/clps7111.h>
-#include <asm/hardware/ep7212.h>
-
-
 /*
  * The two flash banks are wired to chip selects 0 and 1. This is the mapping
  * for them.
diff --git a/arch/arm/mach-clps711x/include/mach/irqs.h b/arch/arm/mach-clps711x/include/mach/irqs.h
index 30b7e97..14d215f 100644
--- a/arch/arm/mach-clps711x/include/mach/irqs.h
+++ b/arch/arm/mach-clps711x/include/mach/irqs.h
@@ -35,7 +35,6 @@
 #define IRQ_SSEOTI			15
 
 #define INT1_IRQS			(0x0000fff0)
-#define INT1_ACK_IRQS			(0x00004f10)
 
 /*
  * Interrupts from INTSR2
@@ -47,7 +46,5 @@
 #define IRQ_URXINT2			(16+13)	/* bit 13 */
 
 #define INT2_IRQS			(0x30070000)
-#define INT2_ACK_IRQS			(0x00010000)
 
-#define NR_IRQS                         30
-
+#define NR_IRQS				30
diff --git a/arch/arm/mach-clps711x/include/mach/time.h b/arch/arm/mach-clps711x/include/mach/time.h
deleted file mode 100644
index 61fef91..0000000
--- a/arch/arm/mach-clps711x/include/mach/time.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *  arch/arm/mach-clps711x/include/mach/time.h
- *
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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 <asm/leds.h>
-#include <asm/hardware/clps7111.h>
-
-extern void clps711x_setup_timer(void);
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t
-p720t_timer_interrupt(int irq, void *dev_id)
-{
-	struct pt_regs *regs = get_irq_regs();
-	do_leds();
-	xtime_update(1);
-#ifndef CONFIG_SMP
-	update_process_times(user_mode(regs));
-#endif
-	do_profile(regs);
-	return IRQ_HANDLED;
-}
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-void __init time_init(void)
-{
-	clps711x_setup_timer();
-	timer_irq.handler = p720t_timer_interrupt;
-	setup_irq(IRQ_TC2OI, &timer_irq);
-}
diff --git a/arch/arm/mach-clps711x/include/mach/uncompress.h b/arch/arm/mach-clps711x/include/mach/uncompress.h
index 35ed731..7b28d6a 100644
--- a/arch/arm/mach-clps711x/include/mach/uncompress.h
+++ b/arch/arm/mach-clps711x/include/mach/uncompress.h
@@ -17,14 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <mach/hardware.h>
-#include <asm/hardware/clps7111.h>
-
-#undef CLPS7111_BASE
-#define CLPS7111_BASE CLPS7111_PHYS_BASE
-
-#define __raw_readl(p)		(*(unsigned long *)(p))
-#define __raw_writel(v,p)	(*(unsigned long *)(p) = (v))
+#include <mach/clps711x.h>
 
 #ifdef CONFIG_DEBUG_CLPS711X_UART2
 #define SYSFLGx	SYSFLG2
@@ -34,19 +27,25 @@
 #define UARTDRx	UARTDR1
 #endif
 
+#define phys_reg(x)	(*(volatile u32 *)(CLPS711X_PHYS_BASE + (x)))
+
 /*
+ * The following code assumes the serial port has already been
+ * initialized by the bootloader.  If you didn't setup a port in
+ * your bootloader then nothing will appear (which might be desired).
+ *
  * This does not append a newline
  */
 static inline void putc(int c)
 {
-	while (clps_readl(SYSFLGx) & SYSFLG_UTXFF)
+	while (phys_reg(SYSFLGx) & SYSFLG_UTXFF)
 		barrier();
-	clps_writel(c, UARTDRx);
+	phys_reg(UARTDRx) = c;
 }
 
 static inline void flush(void)
 {
-	while (clps_readl(SYSFLGx) & SYSFLG_UBUSY)
+	while (phys_reg(SYSFLGx) & SYSFLG_UBUSY)
 		barrier();
 }
 
diff --git a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c
index dd9a6cd..bbc449f 100644
--- a/arch/arm/mach-clps711x/p720t-leds.c
+++ b/arch/arm/mach-clps711x/p720t-leds.c
@@ -27,9 +27,6 @@
 #include <asm/leds.h>
 #include <asm/mach-types.h>
 
-#include <asm/hardware/clps7111.h>
-#include <asm/hardware/ep7212.h>
-
 static void p720t_leds_event(led_event_t ledevt)
 {
 	unsigned long flags;
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index a70de24..09f6107 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -284,7 +284,7 @@
 	.resource	= da850_evm_nandflash_resource,
 };
 
-static struct platform_device *da850_evm_devices[] __initdata = {
+static struct platform_device *da850_evm_devices[] = {
 	&da850_evm_nandflash_device,
 	&da850_evm_norflash_device,
 };
diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h
index 3e519da..8db0fc6 100644
--- a/arch/arm/mach-davinci/davinci.h
+++ b/arch/arm/mach-davinci/davinci.h
@@ -72,7 +72,7 @@
 /* DM355 function declarations */
 void __init dm355_init(void);
 void dm355_init_spi0(unsigned chipselect_mask,
-		struct spi_board_info *info, unsigned len);
+		const struct spi_board_info *info, unsigned len);
 void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata);
 void dm355_set_vpfe_config(struct vpfe_config *cfg);
 
@@ -83,7 +83,7 @@
 void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
 void __init dm365_init_rtc(void);
 void dm365_init_spi0(unsigned chipselect_mask,
-			struct spi_board_info *info, unsigned len);
+			const struct spi_board_info *info, unsigned len);
 void dm365_set_vpfe_config(struct vpfe_config *cfg);
 
 /* DM644x function declarations */
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 42dbf3d..d1624a3 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -831,7 +831,7 @@
 	},
 };
 
-int __init da8xx_register_spi(int instance, struct spi_board_info *info,
+int __init da8xx_register_spi(int instance, const struct spi_board_info *info,
 			      unsigned len)
 {
 	int ret;
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index fd3d09a..678cd99 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -424,7 +424,7 @@
 };
 
 void __init dm355_init_spi0(unsigned chipselect_mask,
-		struct spi_board_info *info, unsigned len)
+		const struct spi_board_info *info, unsigned len)
 {
 	/* for now, assume we need MISO */
 	davinci_cfg_reg(DM355_SPI0_SDI);
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 1a2e953..a50d49de 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -676,7 +676,7 @@
 };
 
 void __init dm365_init_spi0(unsigned chipselect_mask,
-		struct spi_board_info *info, unsigned len)
+		const struct spi_board_info *info, unsigned len)
 {
 	davinci_cfg_reg(DM365_SPI0_SCLK);
 	davinci_cfg_reg(DM365_SPI0_SDI);
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index fd33919..95ce019 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -557,9 +557,9 @@
 	if (i == edma_cc[ctlr]->num_slots)
 		stop_slot = i;
 
-	for (j = start_slot; j < stop_slot; j++)
-		if (test_bit(j, tmp_inuse))
-			clear_bit(j, edma_cc[ctlr]->edma_inuse);
+	j = start_slot;
+	for_each_set_bit_from(j, tmp_inuse, stop_slot)
+		clear_bit(j, edma_cc[ctlr]->edma_inuse);
 
 	if (count)
 		return -EBUSY;
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index ee3461d..a2f1f27 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -76,7 +76,8 @@
 int da830_register_edma(struct edma_rsv_info *rsv);
 int da850_register_edma(struct edma_rsv_info *rsv[2]);
 int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata);
-int da8xx_register_spi(int instance, struct spi_board_info *info, unsigned len);
+int da8xx_register_spi(int instance,
+		const struct spi_board_info *info, unsigned len);
 int da8xx_register_watchdog(void);
 int da8xx_register_usb20(unsigned mA, unsigned potpgt);
 int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index 8bc3fc2..405318e 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -246,7 +246,7 @@
 #define MDSTAT_STATE_MASK	0x3f
 #define PDSTAT_STATE_MASK	0x1f
 #define MDCTL_FORCE		BIT(31)
-#define PDCTL_NEXT		BIT(1)
+#define PDCTL_NEXT		BIT(0)
 #define PDCTL_EPCGOOD		BIT(8)
 
 #ifndef __ASSEMBLER__
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index bda7aca..42ab1e7 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -181,7 +181,7 @@
 	return 166666667;
 }
 
-static void dove_timer_init(void)
+static void __init dove_timer_init(void)
 {
 	orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
 			IRQ_DOVE_BRIDGE, get_tclk());
diff --git a/arch/arm/mach-dove/mpp.c b/arch/arm/mach-dove/mpp.c
index 51e0e41..7f70afc 100644
--- a/arch/arm/mach-dove/mpp.c
+++ b/arch/arm/mach-dove/mpp.c
@@ -56,7 +56,7 @@
 
 /* Dump all the extra MPP registers. The platform code will dump the
    registers for pins 0-23. */
-static void dove_mpp_dump_regs(void)
+static void __init dove_mpp_dump_regs(void)
 {
 	pr_debug("PMU_CTRL4_CTRL: %08x\n",
 		 readl(DOVE_MPP_CTRL4_VIRT_BASE));
@@ -67,7 +67,7 @@
 	pr_debug("MPP_GENERAL: %08x\n", readl(DOVE_MPP_GENERAL_VIRT_BASE));
 }
 
-static void dove_mpp_cfg_nfc(int sel)
+static void __init dove_mpp_cfg_nfc(int sel)
 {
 	u32 mpp_gen_cfg = readl(DOVE_MPP_GENERAL_VIRT_BASE);
 
@@ -78,7 +78,7 @@
 	dove_mpp_gpio_mode(64, 71, GPIO_OUTPUT_OK);
 }
 
-static void dove_mpp_cfg_au1(int sel)
+static void __init dove_mpp_cfg_au1(int sel)
 {
 	u32 mpp_ctrl4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
 	u32 ssp_ctrl1 = readl(DOVE_SSP_CTRL_STATUS_1);
@@ -118,7 +118,7 @@
 
 /* Configure the group registers, enabling GPIO if sel indicates the
    pin is to be used for GPIO */
-static void dove_mpp_conf_grp(unsigned int *mpp_grp_list)
+static void __init dove_mpp_conf_grp(unsigned int *mpp_grp_list)
 {
 	u32 mpp_ctrl4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
 	int gpio_mode;
diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig
index 97a2493..fe3c1fa 100644
--- a/arch/arm/mach-ep93xx/Kconfig
+++ b/arch/arm/mach-ep93xx/Kconfig
@@ -2,6 +2,11 @@
 
 menu "Cirrus EP93xx Implementation Options"
 
+config EP93XX_SOC_COMMON
+	bool
+	default y
+	select LEDS_GPIO_REGISTER
+
 config CRUNCH
 	bool "Support for MaverickCrunch"
 	help
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 8d25895..66b1494 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -241,11 +241,7 @@
  * EP93xx GPIO
  *************************************************************************/
 static struct resource ep93xx_gpio_resource[] = {
-	{
-		.start		= EP93XX_GPIO_PHYS_BASE,
-		.end		= EP93XX_GPIO_PHYS_BASE + 0xcc - 1,
-		.flags		= IORESOURCE_MEM,
-	},
+	DEFINE_RES_MEM(EP93XX_GPIO_PHYS_BASE, 0xcc),
 };
 
 static struct platform_device ep93xx_gpio_device = {
@@ -288,11 +284,7 @@
 	{ IRQ_EP93XX_UART3 }, &ep93xx_uart_data);
 
 static struct resource ep93xx_rtc_resource[] = {
-	{
-		.start		= EP93XX_RTC_PHYS_BASE,
-		.end		= EP93XX_RTC_PHYS_BASE + 0x10c - 1,
-		.flags		= IORESOURCE_MEM,
-	},
+	DEFINE_RES_MEM(EP93XX_RTC_PHYS_BASE, 0x10c),
 };
 
 static struct platform_device ep93xx_rtc_device = {
@@ -304,16 +296,8 @@
 
 
 static struct resource ep93xx_ohci_resources[] = {
-	[0] = {
-		.start	= EP93XX_USB_PHYS_BASE,
-		.end	= EP93XX_USB_PHYS_BASE + 0x0fff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_EP93XX_USB,
-		.end	= IRQ_EP93XX_USB,
-		.flags	= IORESOURCE_IRQ,
-	},
+	DEFINE_RES_MEM(EP93XX_USB_PHYS_BASE, 0x1000),
+	DEFINE_RES_IRQ(IRQ_EP93XX_USB),
 };
 
 
@@ -372,15 +356,8 @@
 static struct ep93xx_eth_data ep93xx_eth_data;
 
 static struct resource ep93xx_eth_resource[] = {
-	{
-		.start	= EP93XX_ETHERNET_PHYS_BASE,
-		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_EP93XX_ETHERNET,
-		.end	= IRQ_EP93XX_ETHERNET,
-		.flags	= IORESOURCE_IRQ,
-	}
+	DEFINE_RES_MEM(EP93XX_ETHERNET_PHYS_BASE, 0x10000),
+	DEFINE_RES_IRQ(IRQ_EP93XX_ETHERNET),
 };
 
 static u64 ep93xx_eth_dma_mask = DMA_BIT_MASK(32);
@@ -461,16 +438,8 @@
 static struct ep93xx_spi_info ep93xx_spi_master_data;
 
 static struct resource ep93xx_spi_resources[] = {
-	{
-		.start	= EP93XX_SPI_PHYS_BASE,
-		.end	= EP93XX_SPI_PHYS_BASE + 0x18 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.start	= IRQ_EP93XX_SSP,
-		.end	= IRQ_EP93XX_SSP,
-		.flags	= IORESOURCE_IRQ,
-	},
+	DEFINE_RES_MEM(EP93XX_SPI_PHYS_BASE, 0x18),
+	DEFINE_RES_IRQ(IRQ_EP93XX_SSP),
 };
 
 static u64 ep93xx_spi_dma_mask = DMA_BIT_MASK(32);
@@ -513,7 +482,7 @@
 /*************************************************************************
  * EP93xx LEDs
  *************************************************************************/
-static struct gpio_led ep93xx_led_pins[] = {
+static const struct gpio_led ep93xx_led_pins[] __initconst = {
 	{
 		.name	= "platform:grled",
 		.gpio	= EP93XX_GPIO_LINE_GRLED,
@@ -523,29 +492,16 @@
 	},
 };
 
-static struct gpio_led_platform_data ep93xx_led_data = {
+static const struct gpio_led_platform_data ep93xx_led_data __initconst = {
 	.num_leds	= ARRAY_SIZE(ep93xx_led_pins),
 	.leds		= ep93xx_led_pins,
 };
 
-static struct platform_device ep93xx_leds = {
-	.name		= "leds-gpio",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &ep93xx_led_data,
-	},
-};
-
-
 /*************************************************************************
  * EP93xx pwm peripheral handling
  *************************************************************************/
 static struct resource ep93xx_pwm0_resource[] = {
-	{
-		.start	= EP93XX_PWM_PHYS_BASE,
-		.end	= EP93XX_PWM_PHYS_BASE + 0x10 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
+	DEFINE_RES_MEM(EP93XX_PWM_PHYS_BASE, 0x10),
 };
 
 static struct platform_device ep93xx_pwm0_device = {
@@ -556,11 +512,7 @@
 };
 
 static struct resource ep93xx_pwm1_resource[] = {
-	{
-		.start	= EP93XX_PWM_PHYS_BASE + 0x20,
-		.end	= EP93XX_PWM_PHYS_BASE + 0x30 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
+	DEFINE_RES_MEM(EP93XX_PWM_PHYS_BASE + 0x20, 0x10),
 };
 
 static struct platform_device ep93xx_pwm1_device = {
@@ -628,11 +580,7 @@
 static struct ep93xxfb_mach_info ep93xxfb_data;
 
 static struct resource ep93xx_fb_resource[] = {
-	{
-		.start		= EP93XX_RASTER_PHYS_BASE,
-		.end		= EP93XX_RASTER_PHYS_BASE + 0x800 - 1,
-		.flags		= IORESOURCE_MEM,
-	},
+	DEFINE_RES_MEM(EP93XX_RASTER_PHYS_BASE, 0x800),
 };
 
 static struct platform_device ep93xx_fb_device = {
@@ -680,15 +628,8 @@
 static struct ep93xx_keypad_platform_data ep93xx_keypad_data;
 
 static struct resource ep93xx_keypad_resource[] = {
-	{
-		.start	= EP93XX_KEY_MATRIX_PHYS_BASE,
-		.end	= EP93XX_KEY_MATRIX_PHYS_BASE + 0x0c - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_EP93XX_KEY,
-		.end	= IRQ_EP93XX_KEY,
-		.flags	= IORESOURCE_IRQ,
-	},
+	DEFINE_RES_MEM(EP93XX_KEY_MATRIX_PHYS_BASE, 0x0c),
+	DEFINE_RES_IRQ(IRQ_EP93XX_KEY),
 };
 
 static struct platform_device ep93xx_keypad_device = {
@@ -761,11 +702,7 @@
  * EP93xx I2S audio peripheral handling
  *************************************************************************/
 static struct resource ep93xx_i2s_resource[] = {
-	{
-		.start	= EP93XX_I2S_PHYS_BASE,
-		.end	= EP93XX_I2S_PHYS_BASE + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
+	DEFINE_RES_MEM(EP93XX_I2S_PHYS_BASE, 0x100),
 };
 
 static struct platform_device ep93xx_i2s_device = {
@@ -824,16 +761,8 @@
  * EP93xx AC97 audio peripheral handling
  *************************************************************************/
 static struct resource ep93xx_ac97_resources[] = {
-	{
-		.start	= EP93XX_AAC_PHYS_BASE,
-		.end	= EP93XX_AAC_PHYS_BASE + 0xac - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.start	= IRQ_EP93XX_AACINTR,
-		.end	= IRQ_EP93XX_AACINTR,
-		.flags	= IORESOURCE_IRQ,
-	},
+	DEFINE_RES_MEM(EP93XX_AAC_PHYS_BASE, 0xac),
+	DEFINE_RES_IRQ(IRQ_EP93XX_AACINTR),
 };
 
 static struct platform_device ep93xx_ac97_device = {
@@ -889,8 +818,9 @@
 
 	platform_device_register(&ep93xx_rtc_device);
 	platform_device_register(&ep93xx_ohci_device);
-	platform_device_register(&ep93xx_leds);
 	platform_device_register(&ep93xx_wdt_device);
+
+	gpio_led_register_device(-1, &ep93xx_led_data);
 }
 
 void ep93xx_restart(char mode, const char *cmd)
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index b8df521..15b05b8 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -200,6 +200,7 @@
 	select S3C_DEV_HSMMC2
 	select S3C_DEV_HSMMC3
 	select SAMSUNG_DEV_BACKLIGHT
+	select EXYNOS_DEV_DRM
 	select EXYNOS4_DEV_AHCI
 	select SAMSUNG_DEV_KEYPAD
 	select EXYNOS4_DEV_DMA
@@ -250,11 +251,13 @@
 	select S3C_DEV_I2C1
 	select S3C_DEV_I2C3
 	select S3C_DEV_I2C5
+	select S3C_DEV_USB_HSOTG
 	select S5P_DEV_I2C_HDMIPHY
 	select S5P_DEV_MFC
 	select S5P_DEV_ONENAND
 	select S5P_DEV_TV
 	select EXYNOS4_DEV_DMA
+	select EXYNOS_DEV_DRM
 	select EXYNOS4_SETUP_FIMD0
 	select EXYNOS4_SETUP_I2C1
 	select EXYNOS4_SETUP_I2C3
@@ -262,6 +265,7 @@
 	select EXYNOS4_SETUP_SDHCI
 	select EXYNOS4_SETUP_FIMC
 	select S5P_SETUP_MIPIPHY
+	select EXYNOS4_SETUP_USB_PHY
 	help
 	  Machine support for Samsung Mobile Universal S5PC210 Reference
 	  Board.
@@ -280,6 +284,7 @@
 	select S3C_DEV_I2C3
 	select S3C_DEV_I2C5
 	select S3C_DEV_I2C6
+	select S3C_DEV_USB_HSOTG
 	select S5P_DEV_CSIS0
 	select S5P_DEV_JPEG
 	select S5P_DEV_FIMC0
@@ -291,6 +296,7 @@
 	select S5P_DEV_USB_EHCI
 	select S5P_SETUP_MIPIPHY
 	select EXYNOS4_DEV_DMA
+	select EXYNOS_DEV_DRM
 	select EXYNOS4_SETUP_FIMC
 	select EXYNOS4_SETUP_FIMD0
 	select EXYNOS4_SETUP_I2C1
@@ -325,6 +331,7 @@
 	select S5P_DEV_USB_EHCI
 	select SAMSUNG_DEV_BACKLIGHT
 	select SAMSUNG_DEV_PWM
+	select EXYNOS_DEV_DRM
 	select EXYNOS4_DEV_DMA
 	select EXYNOS4_DEV_USB_OHCI
 	select EXYNOS4_SETUP_FIMD0
@@ -345,6 +352,11 @@
 	select S3C_DEV_I2C7
 	select S3C_DEV_RTC
 	select S3C_DEV_WDT
+	select S5P_DEV_FIMC0
+	select S5P_DEV_FIMC1
+	select S5P_DEV_FIMC2
+	select S5P_DEV_FIMC3
+	select S5P_DEV_MFC
 	select SAMSUNG_DEV_BACKLIGHT
 	select SAMSUNG_DEV_KEYPAD
 	select SAMSUNG_DEV_PWM
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
index 33ab4e7..26dac28 100644
--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -20,6 +20,7 @@
 #include <asm/smp_scu.h>
 #include <asm/suspend.h>
 #include <asm/unified.h>
+#include <asm/cpuidle.h>
 #include <mach/regs-pmu.h>
 #include <mach/pmu.h>
 
@@ -34,22 +35,12 @@
 
 #define S5P_CHECK_AFTR		0xFCBA0D10
 
-static int exynos4_enter_idle(struct cpuidle_device *dev,
-			struct cpuidle_driver *drv,
-			      int index);
 static int exynos4_enter_lowpower(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv,
 				int index);
 
 static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
-	[0] = {
-		.enter			= exynos4_enter_idle,
-		.exit_latency		= 1,
-		.target_residency	= 100000,
-		.flags			= CPUIDLE_FLAG_TIME_VALID,
-		.name			= "C0",
-		.desc			= "ARM clock gating(WFI)",
-	},
+	[0] = ARM_CPUIDLE_WFI_STATE,
 	[1] = {
 		.enter			= exynos4_enter_lowpower,
 		.exit_latency		= 300,
@@ -63,8 +54,9 @@
 static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
 
 static struct cpuidle_driver exynos4_idle_driver = {
-	.name		= "exynos4_idle",
-	.owner		= THIS_MODULE,
+	.name			= "exynos4_idle",
+	.owner			= THIS_MODULE,
+	.en_core_tk_irqen	= 1,
 };
 
 /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
@@ -103,13 +95,8 @@
 				struct cpuidle_driver *drv,
 				int index)
 {
-	struct timeval before, after;
-	int idle_time;
 	unsigned long tmp;
 
-	local_irq_disable();
-	do_gettimeofday(&before);
-
 	exynos4_set_wakeupmask();
 
 	/* Set value of power down register for aftr mode */
@@ -150,34 +137,6 @@
 	/* Clear wakeup state register */
 	__raw_writel(0x0, S5P_WAKEUP_STAT);
 
-	do_gettimeofday(&after);
-
-	local_irq_enable();
-	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
-		    (after.tv_usec - before.tv_usec);
-
-	dev->last_residency = idle_time;
-	return index;
-}
-
-static int exynos4_enter_idle(struct cpuidle_device *dev,
-				struct cpuidle_driver *drv,
-				int index)
-{
-	struct timeval before, after;
-	int idle_time;
-
-	local_irq_disable();
-	do_gettimeofday(&before);
-
-	cpu_do_idle();
-
-	do_gettimeofday(&after);
-	local_irq_enable();
-	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
-		    (after.tv_usec - before.tv_usec);
-
-	dev->last_residency = idle_time;
 	return index;
 }
 
@@ -192,7 +151,7 @@
 		new_index = drv->safe_state_index;
 
 	if (new_index == 0)
-		return exynos4_enter_idle(dev, drv, new_index);
+		return arm_cpuidle_simple_enter(dev, drv, new_index);
 	else
 		return exynos4_enter_core0_aftr(dev, drv, new_index);
 }
diff --git a/arch/arm/mach-exynos/dev-ahci.c b/arch/arm/mach-exynos/dev-ahci.c
index 50ce5b0..ce1aad3 100644
--- a/arch/arm/mach-exynos/dev-ahci.c
+++ b/arch/arm/mach-exynos/dev-ahci.c
@@ -236,16 +236,8 @@
 };
 
 static struct resource exynos4_ahci_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_SATA,
-		.end	= EXYNOS4_PA_SATA + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= EXYNOS4_IRQ_SATA,
-		.end	= EXYNOS4_IRQ_SATA,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_SATA, SZ_64K),
+	[1] = DEFINE_RES_IRQ(EXYNOS4_IRQ_SATA),
 };
 
 static u64 exynos4_ahci_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-exynos/dev-audio.c b/arch/arm/mach-exynos/dev-audio.c
index 7199e1a..b33a5b6 100644
--- a/arch/arm/mach-exynos/dev-audio.c
+++ b/arch/arm/mach-exynos/dev-audio.c
@@ -62,26 +62,10 @@
 };
 
 static struct resource exynos4_i2s0_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_I2S0,
-		.end	= EXYNOS4_PA_I2S0 + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_I2S0_TX,
-		.end	= DMACH_I2S0_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_I2S0_RX,
-		.end	= DMACH_I2S0_RX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[3] = {
-		.start	= DMACH_I2S0S_TX,
-		.end	= DMACH_I2S0S_TX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_I2S0, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
+	[3] = DEFINE_RES_DMA(DMACH_I2S0S_TX),
 };
 
 struct platform_device exynos4_device_i2s0 = {
@@ -110,21 +94,9 @@
 };
 
 static struct resource exynos4_i2s1_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_I2S1,
-		.end	= EXYNOS4_PA_I2S1 + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_I2S1_TX,
-		.end	= DMACH_I2S1_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_I2S1_RX,
-		.end	= DMACH_I2S1_RX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_I2S1, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
 };
 
 struct platform_device exynos4_device_i2s1 = {
@@ -138,21 +110,9 @@
 };
 
 static struct resource exynos4_i2s2_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_I2S2,
-		.end	= EXYNOS4_PA_I2S2 + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_I2S2_TX,
-		.end	= DMACH_I2S2_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_I2S2_RX,
-		.end	= DMACH_I2S2_RX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_I2S2, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
 };
 
 struct platform_device exynos4_device_i2s2 = {
@@ -192,21 +152,9 @@
 };
 
 static struct resource exynos4_pcm0_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_PCM0,
-		.end	= EXYNOS4_PA_PCM0 + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_PCM0_TX,
-		.end	= DMACH_PCM0_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_PCM0_RX,
-		.end	= DMACH_PCM0_RX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_PCM0, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
 };
 
 struct platform_device exynos4_device_pcm0 = {
@@ -220,21 +168,9 @@
 };
 
 static struct resource exynos4_pcm1_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_PCM1,
-		.end	= EXYNOS4_PA_PCM1 + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_PCM1_TX,
-		.end	= DMACH_PCM1_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_PCM1_RX,
-		.end	= DMACH_PCM1_RX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_PCM1, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
 };
 
 struct platform_device exynos4_device_pcm1 = {
@@ -248,21 +184,9 @@
 };
 
 static struct resource exynos4_pcm2_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_PCM2,
-		.end	= EXYNOS4_PA_PCM2 + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_PCM2_TX,
-		.end	= DMACH_PCM2_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_PCM2_RX,
-		.end	= DMACH_PCM2_RX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_PCM2, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM2_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM2_RX),
 };
 
 struct platform_device exynos4_device_pcm2 = {
@@ -283,31 +207,11 @@
 }
 
 static struct resource exynos4_ac97_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_AC97,
-		.end	= EXYNOS4_PA_AC97 + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_AC97_PCMOUT,
-		.end	= DMACH_AC97_PCMOUT,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_AC97_PCMIN,
-		.end	= DMACH_AC97_PCMIN,
-		.flags	= IORESOURCE_DMA,
-	},
-	[3] = {
-		.start	= DMACH_AC97_MICIN,
-		.end	= DMACH_AC97_MICIN,
-		.flags	= IORESOURCE_DMA,
-	},
-	[4] = {
-		.start	= EXYNOS4_IRQ_AC97,
-		.end	= EXYNOS4_IRQ_AC97,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_AC97, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
+	[2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
+	[3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
+	[4] = DEFINE_RES_IRQ(EXYNOS4_IRQ_AC97),
 };
 
 static struct s3c_audio_pdata s3c_ac97_pdata = {
@@ -338,16 +242,8 @@
 }
 
 static struct resource exynos4_spdif_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_SPDIF,
-		.end	= EXYNOS4_PA_SPDIF + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_SPDIF,
-		.end	= DMACH_SPDIF,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_SPDIF, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_SPDIF),
 };
 
 static struct s3c_audio_pdata samsung_spdif_pdata = {
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index 591e785..c02dae7 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -189,6 +189,7 @@
 #define IRQ_IIC7			EXYNOS4_IRQ_IIC7
 
 #define IRQ_USB_HOST			EXYNOS4_IRQ_USB_HOST
+#define IRQ_OTG				EXYNOS4_IRQ_USB_HSOTG
 
 #define IRQ_HSMMC0			EXYNOS4_IRQ_HSMMC0
 #define IRQ_HSMMC1			EXYNOS4_IRQ_HSMMC1
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index 6e6d11f..e009a66 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -130,6 +130,9 @@
 #define EXYNOS4_PA_HSMMC(x)		(0x12510000 + ((x) * 0x10000))
 #define EXYNOS4_PA_DWMCI		0x12550000
 
+#define EXYNOS4_PA_HSOTG		0x12480000
+#define EXYNOS4_PA_USB_HSPHY		0x125B0000
+
 #define EXYNOS4_PA_SATA			0x12560000
 #define EXYNOS4_PA_SATAPHY		0x125D0000
 #define EXYNOS4_PA_SATAPHY_CTRL		0x126B0000
@@ -186,6 +189,7 @@
 #define S3C_PA_SPI0			EXYNOS4_PA_SPI0
 #define S3C_PA_SPI1			EXYNOS4_PA_SPI1
 #define S3C_PA_SPI2			EXYNOS4_PA_SPI2
+#define S3C_PA_USB_HSOTG		EXYNOS4_PA_HSOTG
 
 #define S5P_PA_EHCI			EXYNOS4_PA_EHCI
 #define S5P_PA_FIMC0			EXYNOS4_PA_FIMC0
diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h
index 4c53f38..d457d05 100644
--- a/arch/arm/mach-exynos/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h
@@ -163,6 +163,9 @@
 #define S5P_CHECK_SLEEP				0x00000BAD
 
 /* Only for EXYNOS4210 */
+#define S5P_USBDEVICE_PHY_CONTROL	S5P_PMUREG(0x0704)
+#define S5P_USBDEVICE_PHY_ENABLE	(1 << 0)
+
 #define S5P_USBHOST_PHY_CONTROL		S5P_PMUREG(0x0708)
 #define S5P_USBHOST_PHY_ENABLE		(1 << 0)
 
diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c
index d726fcd..fed7116 100644
--- a/arch/arm/mach-exynos/mach-armlex4210.c
+++ b/arch/arm/mach-exynos/mach-armlex4210.c
@@ -77,7 +77,6 @@
 
 static struct s3c_sdhci_platdata armlex4210_hsmmc0_pdata __initdata = {
 	.cd_type		= S3C_SDHCI_CD_PERMANENT,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 #ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT
 	.max_width		= 8,
 	.host_caps		= MMC_CAP_8_BIT_DATA,
@@ -88,13 +87,11 @@
 	.cd_type		= S3C_SDHCI_CD_GPIO,
 	.ext_cd_gpio		= EXYNOS4_GPX2(5),
 	.ext_cd_gpio_invert	= 1,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 	.max_width		= 4,
 };
 
 static struct s3c_sdhci_platdata armlex4210_hsmmc3_pdata __initdata = {
 	.cd_type		= S3C_SDHCI_CD_PERMANENT,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 	.max_width		= 4,
 };
 
@@ -121,16 +118,9 @@
 }
 
 static struct resource armlex4210_smsc911x_resources[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_SROM_BANK(3),
-		.end	= EXYNOS4_PA_SROM_BANK(3) + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_EINT(27),
-		.end	= IRQ_EINT(27),
-		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_SROM_BANK(3), SZ_64K),
+	[1] = DEFINE_RES_NAMED(IRQ_EINT(27), 1, NULL, IORESOURCE_IRQ \
+					| IRQF_TRIGGER_HIGH),
 };
 
 static struct smsc911x_platform_config smsc9215_config = {
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index ed90aef..6c31f2a 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -25,6 +25,8 @@
 #include <linux/mmc/host.h>
 #include <linux/fb.h>
 #include <linux/pwm_backlight.h>
+#include <linux/platform_data/s3c-hsotg.h>
+#include <drm/exynos_drm.h>
 
 #include <video/platform_lcd.h>
 #include <media/m5mols.h>
@@ -114,7 +116,6 @@
 				MMC_CAP_ERASE),
 	.host_caps2		= MMC_CAP2_BROKEN_VOLTAGE,
 	.cd_type		= S3C_SDHCI_CD_PERMANENT,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 static struct regulator_consumer_supply emmc_supplies[] = {
@@ -155,7 +156,6 @@
 	.ext_cd_gpio		= EXYNOS4_GPX3(3),	/* XEINT_27 */
 	.ext_cd_gpio_invert	= 1,
 	.cd_type		= S3C_SDHCI_CD_GPIO,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 /* WLAN */
@@ -164,7 +164,6 @@
 	.host_caps		= MMC_CAP_4_BIT_DATA |
 				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
 	.cd_type		= S3C_SDHCI_CD_EXTERNAL,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 static void __init nuri_sdhci_init(void)
@@ -213,6 +212,29 @@
 	},
 };
 
+#ifdef CONFIG_DRM_EXYNOS
+static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
+	.panel = {
+		.timing	= {
+			.xres		= 1024,
+			.yres		= 600,
+			.hsync_len	= 40,
+			.left_margin	= 79,
+			.right_margin	= 200,
+			.vsync_len	= 10,
+			.upper_margin	= 10,
+			.lower_margin	= 11,
+			.refresh	= 60,
+		},
+	},
+	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
+			  VIDCON0_CLKSEL_LCD,
+	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+	.default_win	= 3,
+	.bpp		= 32,
+};
+
+#else
 /* Frame Buffer */
 static struct s3c_fb_pd_win nuri_fb_win0 = {
 	.win_mode = {
@@ -239,6 +261,7 @@
 	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
 	.setup_gpio	= exynos4_fimd0_gpio_setup_24bpp,
 };
+#endif
 
 static void nuri_lcd_power_on(struct plat_lcd_data *pd, unsigned int power)
 {
@@ -351,6 +374,7 @@
 	REGULATOR_SUPPLY("vdd", "s5p-adc"), /* Used by CPU's ADC drv */
 };
 static struct regulator_consumer_supply __initdata max8997_ldo3_[] = {
+	REGULATOR_SUPPLY("vusb_d", "s3c-hsotg"), /* USB */
 	REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), /* MIPI */
 };
 static struct regulator_consumer_supply __initdata max8997_ldo4_[] = {
@@ -366,7 +390,7 @@
 	REGULATOR_SUPPLY("dig_18", "0-001f"), /* HCD803 */
 };
 static struct regulator_consumer_supply __initdata max8997_ldo8_[] = {
-	REGULATOR_SUPPLY("vusb_d", NULL), /* Used by CPU */
+	REGULATOR_SUPPLY("vusb_a", "s3c-hsotg"), /* USB */
 	REGULATOR_SUPPLY("vdac", NULL), /* Used by CPU */
 };
 static struct regulator_consumer_supply __initdata max8997_ldo11_[] = {
@@ -822,6 +846,7 @@
 	.constraints	= {
 		.name		= "SAFEOUT1",
 		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
+		.always_on	= 1,
 		.state_mem	= {
 			.disabled	= 1,
 		},
@@ -1079,6 +1104,9 @@
 	s5p_ehci_set_platdata(pdata);
 }
 
+/* USB OTG */
+static struct s3c_hsotg_plat nuri_hsotg_pdata;
+
 /* CAMERA */
 static struct regulator_consumer_supply cam_vt_cam15_supply =
 	REGULATOR_SUPPLY("vdd_core", "6-003c");
@@ -1291,6 +1319,7 @@
 	&s5p_device_mfc_l,
 	&s5p_device_mfc_r,
 	&s5p_device_fimc_md,
+	&s3c_device_usb_hsotg,
 
 	/* NURI Devices */
 	&nuri_gpio_keys,
@@ -1302,6 +1331,9 @@
 	&cam_vdda_fixed_rdev,
 	&cam_8m_12v_fixed_rdev,
 	&exynos4_bus_devfreq,
+#ifdef CONFIG_DRM_EXYNOS
+	&exynos_device_drm,
+#endif
 };
 
 static void __init nuri_map_io(void)
@@ -1334,11 +1366,17 @@
 	i2c_register_board_info(9, i2c9_devs, ARRAY_SIZE(i2c9_devs));
 	s3c_i2c6_set_platdata(&nuri_i2c6_platdata);
 
+#ifdef CONFIG_DRM_EXYNOS
+	s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
+	exynos4_fimd0_gpio_setup_24bpp();
+#else
 	s5p_fimd0_set_platdata(&nuri_fb_pdata);
+#endif
 
 	nuri_camera_init();
 
 	nuri_ehci_init();
+	s3c_hsotg_set_platdata(&nuri_hsotg_pdata);
 
 	/* Last */
 	platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices));
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 878d4c9..26124a3 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -45,6 +45,7 @@
 #include <mach/ohci.h>
 #include <mach/map.h>
 
+#include <drm/exynos_drm.h>
 #include "common.h"
 
 /* Following are default values for UCON, ULCON and UFCON UART registers */
@@ -472,12 +473,10 @@
 
 static struct s3c_sdhci_platdata origen_hsmmc0_pdata __initdata = {
 	.cd_type		= S3C_SDHCI_CD_INTERNAL,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 static struct s3c_sdhci_platdata origen_hsmmc2_pdata __initdata = {
 	.cd_type		= S3C_SDHCI_CD_INTERNAL,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 /* USB EHCI */
@@ -583,6 +582,27 @@
 	.dev.platform_data	= &origen_lcd_hv070wsa_data,
 };
 
+#ifdef CONFIG_DRM_EXYNOS
+static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
+	.panel	= {
+		.timing	= {
+			.left_margin	= 64,
+			.right_margin	= 16,
+			.upper_margin	= 64,
+			.lower_margin	= 16,
+			.hsync_len	= 48,
+			.vsync_len	= 3,
+			.xres		= 1024,
+			.yres		= 600,
+		},
+	},
+	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
+				VIDCON1_INV_VCLK,
+	.default_win	= 0,
+	.bpp		= 32,
+};
+#else
 static struct s3c_fb_pd_win origen_fb_win0 = {
 	.win_mode = {
 		.left_margin	= 64,
@@ -596,6 +616,8 @@
 	},
 	.max_bpp		= 32,
 	.default_bpp		= 24,
+	.virtual_x		= 1024,
+	.virtual_y		= 2 * 600,
 };
 
 static struct s3c_fb_platdata origen_lcd_pdata __initdata = {
@@ -605,9 +627,10 @@
 				VIDCON1_INV_VCLK,
 	.setup_gpio	= exynos4_fimd0_gpio_setup_24bpp,
 };
+#endif
 
 /* Bluetooth rfkill gpio platform data */
-struct rfkill_gpio_platform_data origen_bt_pdata = {
+static struct rfkill_gpio_platform_data origen_bt_pdata = {
 	.reset_gpio	= EXYNOS4_GPX2(2),
 	.shutdown_gpio	= -1,
 	.type		= RFKILL_TYPE_BLUETOOTH,
@@ -644,6 +667,9 @@
 	&s5p_device_mfc_l,
 	&s5p_device_mfc_r,
 	&s5p_device_mixer,
+#ifdef CONFIG_DRM_EXYNOS
+	&exynos_device_drm,
+#endif
 	&exynos4_device_ohci,
 	&origen_device_gpiokeys,
 	&origen_lcd_hv070wsa,
@@ -719,7 +745,12 @@
 	s5p_tv_setup();
 	s5p_i2c_hdmiphy_set_platdata(NULL);
 
+#ifdef CONFIG_DRM_EXYNOS
+	s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
+	exynos4_fimd0_gpio_setup_24bpp();
+#else
 	s5p_fimd0_set_platdata(&origen_lcd_pdata);
+#endif
 
 	platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices));
 
diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c
index d00e4f0..fe772d8 100644
--- a/arch/arm/mach-exynos/mach-smdk4x12.c
+++ b/arch/arm/mach-exynos/mach-smdk4x12.c
@@ -31,6 +31,7 @@
 #include <plat/gpio-cfg.h>
 #include <plat/iic.h>
 #include <plat/keypad.h>
+#include <plat/mfc.h>
 #include <plat/regs-serial.h>
 #include <plat/sdhci.h>
 
@@ -85,7 +86,6 @@
 
 static struct s3c_sdhci_platdata smdk4x12_hsmmc2_pdata __initdata = {
 	.cd_type		= S3C_SDHCI_CD_INTERNAL,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 #ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT
 	.max_width		= 8,
 	.host_caps		= MMC_CAP_8_BIT_DATA,
@@ -94,7 +94,6 @@
 
 static struct s3c_sdhci_platdata smdk4x12_hsmmc3_pdata __initdata = {
 	.cd_type		= S3C_SDHCI_CD_INTERNAL,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 static struct regulator_consumer_supply max8997_buck1 =
@@ -244,6 +243,14 @@
 	&s3c_device_i2c7,
 	&s3c_device_rtc,
 	&s3c_device_wdt,
+	&s5p_device_fimc0,
+	&s5p_device_fimc1,
+	&s5p_device_fimc2,
+	&s5p_device_fimc3,
+	&s5p_device_fimc_md,
+	&s5p_device_mfc,
+	&s5p_device_mfc_l,
+	&s5p_device_mfc_r,
 	&samsung_device_keypad,
 };
 
@@ -256,6 +263,11 @@
 	s3c24xx_init_uarts(smdk4x12_uartcfgs, ARRAY_SIZE(smdk4x12_uartcfgs));
 }
 
+static void __init smdk4x12_reserve(void)
+{
+	s5p_mfc_reserve_mem(0x43000000, 8 << 20, 0x51000000, 8 << 20);
+}
+
 static void __init smdk4x12_machine_init(void)
 {
 	s3c_i2c0_set_platdata(NULL);
@@ -293,6 +305,7 @@
 	.init_machine	= smdk4x12_machine_init,
 	.timer		= &exynos4_timer,
 	.restart	= exynos4_restart,
+	.reserve	= &smdk4x12_reserve,
 MACHINE_END
 
 MACHINE_START(SMDK4412, "SMDK4412")
@@ -305,4 +318,5 @@
 	.init_machine	= smdk4x12_machine_init,
 	.timer		= &exynos4_timer,
 	.restart	= exynos4_restart,
+	.reserve	= &smdk4x12_reserve,
 MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index 83b91fa..5af9606 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -44,6 +44,7 @@
 #include <mach/map.h>
 #include <mach/ohci.h>
 
+#include <drm/exynos_drm.h>
 #include "common.h"
 
 /* Following are default values for UCON, ULCON and UFCON UART registers */
@@ -93,7 +94,6 @@
 
 static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = {
 	.cd_type		= S3C_SDHCI_CD_INTERNAL,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 #ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT
 	.max_width		= 8,
 	.host_caps		= MMC_CAP_8_BIT_DATA,
@@ -104,12 +104,10 @@
 	.cd_type		= S3C_SDHCI_CD_GPIO,
 	.ext_cd_gpio		= EXYNOS4_GPK0(2),
 	.ext_cd_gpio_invert	= 1,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = {
 	.cd_type		= S3C_SDHCI_CD_INTERNAL,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 #ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT
 	.max_width		= 8,
 	.host_caps		= MMC_CAP_8_BIT_DATA,
@@ -120,7 +118,6 @@
 	.cd_type		= S3C_SDHCI_CD_GPIO,
 	.ext_cd_gpio		= EXYNOS4_GPK2(2),
 	.ext_cd_gpio_invert	= 1,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 static void lcd_lte480wv_set_power(struct plat_lcd_data *pd,
@@ -160,6 +157,26 @@
 	.dev.platform_data	= &smdkv310_lcd_lte480wv_data,
 };
 
+#ifdef CONFIG_DRM_EXYNOS
+static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
+	.panel	= {
+		.timing	= {
+			.left_margin	= 13,
+			.right_margin	= 8,
+			.upper_margin	= 7,
+			.lower_margin	= 5,
+			.hsync_len	= 3,
+			.vsync_len	= 1,
+			.xres		= 800,
+			.yres		= 480,
+		},
+	},
+	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+	.default_win	= 0,
+	.bpp		= 32,
+};
+#else
 static struct s3c_fb_pd_win smdkv310_fb_win0 = {
 	.win_mode = {
 		.left_margin	= 13,
@@ -181,18 +198,12 @@
 	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
 	.setup_gpio	= exynos4_fimd0_gpio_setup_24bpp,
 };
+#endif
 
 static struct resource smdkv310_smsc911x_resources[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_SROM_BANK(1),
-		.end	= EXYNOS4_PA_SROM_BANK(1) + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_EINT(5),
-		.end	= IRQ_EINT(5),
-		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
-	},
+	[0] = DEFINE_RES_MEM(EXYNOS4_PA_SROM_BANK(1), SZ_64K),
+	[1] = DEFINE_RES_NAMED(IRQ_EINT(5), 1, NULL, IORESOURCE_IRQ \
+						| IRQF_TRIGGER_LOW),
 };
 
 static struct smsc911x_platform_config smsc9215_config = {
@@ -273,6 +284,9 @@
 	&s5p_device_fimc_md,
 	&s5p_device_g2d,
 	&s5p_device_jpeg,
+#ifdef CONFIG_DRM_EXYNOS
+	&exynos_device_drm,
+#endif
 	&exynos4_device_ac97,
 	&exynos4_device_i2s0,
 	&exynos4_device_ohci,
@@ -364,7 +378,12 @@
 	samsung_keypad_set_platdata(&smdkv310_keypad_data);
 
 	samsung_bl_set(&smdkv310_bl_gpio_info, &smdkv310_bl_data);
+#ifdef CONFIG_DRM_EXYNOS
+	s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
+	exynos4_fimd0_gpio_setup_24bpp();
+#else
 	s5p_fimd0_set_platdata(&smdkv310_lcd0_pdata);
+#endif
 
 	smdkv310_ehci_init();
 	smdkv310_ohci_init();
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index a34036e..6b731b8 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -23,6 +23,8 @@
 #include <linux/i2c-gpio.h>
 #include <linux/i2c/mcs.h>
 #include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/platform_data/s3c-hsotg.h>
+#include <drm/exynos_drm.h>
 
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -205,6 +207,7 @@
 };
 
 static struct regulator_consumer_supply lp3974_ldo3_consumer[] = {
+	REGULATOR_SUPPLY("vusb_a", "s3c-hsotg"),
 	REGULATOR_SUPPLY("vdd", "exynos4-hdmi"),
 	REGULATOR_SUPPLY("vdd_pll", "exynos4-hdmi"),
 	REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"),
@@ -290,6 +293,7 @@
 };
 
 static struct regulator_consumer_supply lp3974_ldo8_consumer[] = {
+	REGULATOR_SUPPLY("vusb_d", "s3c-hsotg"),
 	REGULATOR_SUPPLY("vdd33a_dac", "s5p-sdo"),
 };
 
@@ -486,7 +490,10 @@
 static struct regulator_init_data lp3974_esafeout1_data = {
 	.constraints	= {
 		.name		= "SAFEOUT1",
+		.min_uV		= 4800000,
+		.max_uV		= 4800000,
 		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
+		.always_on	= 1,
 		.state_mem	= {
 			.enabled	= 1,
 		},
@@ -750,7 +757,6 @@
 				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
 	.host_caps2		= MMC_CAP2_BROKEN_VOLTAGE,
 	.cd_type		= S3C_SDHCI_CD_PERMANENT,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 static struct regulator_consumer_supply mmc0_supplies[] = {
@@ -790,7 +796,6 @@
 	.ext_cd_gpio		= EXYNOS4_GPX3(4),      /* XEINT_28 */
 	.ext_cd_gpio_invert	= 1,
 	.cd_type		= S3C_SDHCI_CD_GPIO,
-	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 /* WiFi */
@@ -813,6 +818,29 @@
 	/* Gyro, To be updated */
 };
 
+#ifdef CONFIG_DRM_EXYNOS
+static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
+	.panel = {
+		.timing	= {
+			.left_margin	= 16,
+			.right_margin	= 16,
+			.upper_margin	= 2,
+			.lower_margin	= 28,
+			.hsync_len	= 2,
+			.vsync_len	= 1,
+			.xres		= 480,
+			.yres		= 800,
+			.refresh	= 55,
+		},
+	},
+	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
+			  VIDCON0_CLKSEL_LCD,
+	.vidcon1	= VIDCON1_INV_VCLK | VIDCON1_INV_VDEN
+			  | VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+	.default_win	= 3,
+	.bpp		= 32,
+};
+#else
 /* Frame Buffer */
 static struct s3c_fb_pd_win universal_fb_win0 = {
 	.win_mode = {
@@ -840,6 +868,7 @@
 			  | VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
 	.setup_gpio	= exynos4_fimd0_gpio_setup_24bpp,
 };
+#endif
 
 static struct regulator_consumer_supply cam_vt_dio_supply =
 	REGULATOR_SUPPLY("vdd_core", "0-003c");
@@ -994,6 +1023,9 @@
 	{ GPIO_CAM_VGA_NSTBY,	GPIOF_OUT_INIT_LOW,  "CAM_VGA_NSTBY" },
 };
 
+/* USB OTG */
+static struct s3c_hsotg_plat universal_hsotg_pdata;
+
 static void __init universal_camera_init(void)
 {
 	s3c_set_platdata(&mipi_csis_platdata, sizeof(mipi_csis_platdata),
@@ -1049,6 +1081,10 @@
 	&s5p_device_onenand,
 	&s5p_device_fimd0,
 	&s5p_device_jpeg,
+#ifdef CONFIG_DRM_EXYNOS
+	&exynos_device_drm,
+#endif
+	&s3c_device_usb_hsotg,
 	&s5p_device_mfc,
 	&s5p_device_mfc_l,
 	&s5p_device_mfc_r,
@@ -1096,12 +1132,18 @@
 	s5p_i2c_hdmiphy_set_platdata(NULL);
 	i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
 
+#ifdef CONFIG_DRM_EXYNOS
+	s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
+	exynos4_fimd0_gpio_setup_24bpp();
+#else
 	s5p_fimd0_set_platdata(&universal_lcd_pdata);
+#endif
 
 	universal_touchkey_init();
 	i2c_register_board_info(I2C_GPIO_BUS_12, i2c_gpio12_devs,
 			ARRAY_SIZE(i2c_gpio12_devs));
 
+	s3c_hsotg_set_platdata(&universal_hsotg_pdata);
 	universal_camera_init();
 
 	/* Last */
diff --git a/arch/arm/mach-exynos/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c
index 41743d2..1af0a7f 100644
--- a/arch/arm/mach-exynos/setup-usb-phy.c
+++ b/arch/arm/mach-exynos/setup-usb-phy.c
@@ -26,11 +26,71 @@
 	return (readl(EXYNOS4_PHYPWR) & PHY1_STD_ANALOG_POWERDOWN) ? 0 : 1;
 }
 
-static int exynos4_usb_phy1_init(struct platform_device *pdev)
+static void exynos4210_usb_phy_clkset(struct platform_device *pdev)
 {
-	struct clk *otg_clk;
 	struct clk *xusbxti_clk;
 	u32 phyclk;
+
+	/* set clock frequency for PLL */
+	phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
+
+	xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
+	if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
+		switch (clk_get_rate(xusbxti_clk)) {
+		case 12 * MHZ:
+			phyclk |= CLKSEL_12M;
+			break;
+		case 24 * MHZ:
+			phyclk |= CLKSEL_24M;
+			break;
+		default:
+		case 48 * MHZ:
+			/* default reference clock */
+			break;
+		}
+		clk_put(xusbxti_clk);
+	}
+
+	writel(phyclk, EXYNOS4_PHYCLK);
+}
+
+static int exynos4210_usb_phy0_init(struct platform_device *pdev)
+{
+	u32 rstcon;
+
+	writel(readl(S5P_USBDEVICE_PHY_CONTROL) | S5P_USBDEVICE_PHY_ENABLE,
+			S5P_USBDEVICE_PHY_CONTROL);
+
+	exynos4210_usb_phy_clkset(pdev);
+
+	/* set to normal PHY0 */
+	writel((readl(EXYNOS4_PHYPWR) & ~PHY0_NORMAL_MASK), EXYNOS4_PHYPWR);
+
+	/* reset PHY0 and Link */
+	rstcon = readl(EXYNOS4_RSTCON) | PHY0_SWRST_MASK;
+	writel(rstcon, EXYNOS4_RSTCON);
+	udelay(10);
+
+	rstcon &= ~PHY0_SWRST_MASK;
+	writel(rstcon, EXYNOS4_RSTCON);
+
+	return 0;
+}
+
+static int exynos4210_usb_phy0_exit(struct platform_device *pdev)
+{
+	writel((readl(EXYNOS4_PHYPWR) | PHY0_ANALOG_POWERDOWN |
+				PHY0_OTG_DISABLE), EXYNOS4_PHYPWR);
+
+	writel(readl(S5P_USBDEVICE_PHY_CONTROL) & ~S5P_USBDEVICE_PHY_ENABLE,
+			S5P_USBDEVICE_PHY_CONTROL);
+
+	return 0;
+}
+
+static int exynos4210_usb_phy1_init(struct platform_device *pdev)
+{
+	struct clk *otg_clk;
 	u32 rstcon;
 	int err;
 
@@ -54,27 +114,7 @@
 	writel(readl(S5P_USBHOST_PHY_CONTROL) | S5P_USBHOST_PHY_ENABLE,
 			S5P_USBHOST_PHY_CONTROL);
 
-	/* set clock frequency for PLL */
-	phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
-
-	xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
-	if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
-		switch (clk_get_rate(xusbxti_clk)) {
-		case 12 * MHZ:
-			phyclk |= CLKSEL_12M;
-			break;
-		case 24 * MHZ:
-			phyclk |= CLKSEL_24M;
-			break;
-		default:
-		case 48 * MHZ:
-			/* default reference clock */
-			break;
-		}
-		clk_put(xusbxti_clk);
-	}
-
-	writel(phyclk, EXYNOS4_PHYCLK);
+	exynos4210_usb_phy_clkset(pdev);
 
 	/* floating prevention logic: disable */
 	writel((readl(EXYNOS4_PHY1CON) | FPENABLEN), EXYNOS4_PHY1CON);
@@ -102,7 +142,7 @@
 	return 0;
 }
 
-static int exynos4_usb_phy1_exit(struct platform_device *pdev)
+static int exynos4210_usb_phy1_exit(struct platform_device *pdev)
 {
 	struct clk *otg_clk;
 	int err;
@@ -136,16 +176,20 @@
 
 int s5p_usb_phy_init(struct platform_device *pdev, int type)
 {
-	if (type == S5P_USB_PHY_HOST)
-		return exynos4_usb_phy1_init(pdev);
+	if (type == S5P_USB_PHY_DEVICE)
+		return exynos4210_usb_phy0_init(pdev);
+	else if (type == S5P_USB_PHY_HOST)
+		return exynos4210_usb_phy1_init(pdev);
 
 	return -EINVAL;
 }
 
 int s5p_usb_phy_exit(struct platform_device *pdev, int type)
 {
-	if (type == S5P_USB_PHY_HOST)
-		return exynos4_usb_phy1_exit(pdev);
+	if (type == S5P_USB_PHY_DEVICE)
+		return exynos4210_usb_phy0_exit(pdev);
+	else if (type == S5P_USB_PHY_HOST)
+		return exynos4210_usb_phy1_exit(pdev);
 
 	return -EINVAL;
 }
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 7561eca..cca8c0c 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -151,6 +151,7 @@
 	select IMX_HAVE_PLATFORM_IMX2_WDT
 	select IMX_HAVE_PLATFORM_IMXDI_RTC
 	select IMX_HAVE_PLATFORM_IMX_I2C
+	select IMX_HAVE_PLATFORM_IMX_SSI
 	select IMX_HAVE_PLATFORM_IMX_FB
 	select IMX_HAVE_PLATFORM_IMX_KEYPAD
 	select IMX_HAVE_PLATFORM_IMX_UART
@@ -163,6 +164,7 @@
 	select SOC_IMX25
 	select IMX_HAVE_PLATFORM_FLEXCAN
 	select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+	select IMX_HAVE_PLATFORM_IMX2_WDT
 	select IMX_HAVE_PLATFORM_IMXDI_RTC
 	select IMX_HAVE_PLATFORM_IMX_FB
 	select IMX_HAVE_PLATFORM_IMX_I2C
@@ -181,6 +183,7 @@
 	bool "Eukrea MBIMXSD development board"
 	select IMX_HAVE_PLATFORM_GPIO_KEYS
 	select IMX_HAVE_PLATFORM_IMX_SSI
+	select IMX_HAVE_PLATFORM_SPI_IMX
 	select LEDS_GPIO_REGISTER
 	help
 	  This adds board specific devices that can be found on Eukrea's
@@ -493,6 +496,7 @@
 	select IMX_HAVE_PLATFORM_FSL_USB2_UDC
 	select IMX_HAVE_PLATFORM_IMX2_WDT
 	select IMX_HAVE_PLATFORM_IMX_I2C
+	select IMX_HAVE_PLATFORM_IMX_SSI
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_IPU_CORE
 	select IMX_HAVE_PLATFORM_MXC_EHCI
@@ -571,8 +575,10 @@
 	select MXC_DEBUG_BOARD
 	select IMX_HAVE_PLATFORM_FSL_USB2_UDC
 	select IMX_HAVE_PLATFORM_IMX2_WDT
+	select IMX_HAVE_PLATFORM_IMX_FB
 	select IMX_HAVE_PLATFORM_IMX_I2C
 	select IMX_HAVE_PLATFORM_IMX_UART
+	select IMX_HAVE_PLATFORM_IPU_CORE
 	select IMX_HAVE_PLATFORM_MXC_EHCI
 	select IMX_HAVE_PLATFORM_MXC_NAND
 	select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
@@ -606,6 +612,7 @@
 	select IMX_HAVE_PLATFORM_GPIO_KEYS
 	select IMX_HAVE_PLATFORM_IMX_SSI
 	select IMX_HAVE_PLATFORM_IPU_CORE
+	select IMX_HAVE_PLATFORM_SPI_IMX
 	select LEDS_GPIO_REGISTER
 	help
 	  This adds board specific devices that can be found on Eukrea's
@@ -682,42 +689,13 @@
 	  Include support for MX51PDK (3DS) platform. This includes specific
 	  configurations for the board and its peripherals.
 
-config MACH_EUKREA_CPUIMX51
-	bool "Support Eukrea CPUIMX51 module"
-	select SOC_IMX51
-	select IMX_HAVE_PLATFORM_FSL_USB2_UDC
-	select IMX_HAVE_PLATFORM_IMX_I2C
-	select IMX_HAVE_PLATFORM_IMX_UART
-	select IMX_HAVE_PLATFORM_MXC_EHCI
-	select IMX_HAVE_PLATFORM_MXC_NAND
-	select IMX_HAVE_PLATFORM_SPI_IMX
-	help
-	  Include support for Eukrea CPUIMX51 platform. This includes
-	  specific configurations for the module and its peripherals.
-
-choice
-	prompt "Baseboard"
-	depends on MACH_EUKREA_CPUIMX51
-	default MACH_EUKREA_MBIMX51_BASEBOARD
-
-config MACH_EUKREA_MBIMX51_BASEBOARD
-	prompt "Eukrea MBIMX51 development board"
-	bool
-	select IMX_HAVE_PLATFORM_IMX_KEYPAD
-	select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
-	select LEDS_GPIO_REGISTER
-	help
-	  This adds board specific devices that can be found on Eukrea's
-	  MBIMX51 evaluation board.
-
-endchoice
-
 config MACH_EUKREA_CPUIMX51SD
 	bool "Support Eukrea CPUIMX51SD module"
 	select SOC_IMX51
 	select IMX_HAVE_PLATFORM_FSL_USB2_UDC
 	select IMX_HAVE_PLATFORM_IMX_I2C
 	select IMX_HAVE_PLATFORM_IMX_UART
+	select IMX_HAVE_PLATFORM_IMX2_WDT
 	select IMX_HAVE_PLATFORM_MXC_EHCI
 	select IMX_HAVE_PLATFORM_MXC_NAND
 	select IMX_HAVE_PLATFORM_SPI_IMX
@@ -733,6 +711,7 @@
 config MACH_EUKREA_MBIMXSD51_BASEBOARD
 	prompt "Eukrea MBIMXSD development board"
 	bool
+	select IMX_HAVE_PLATFORM_IMX_SSI
 	select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
 	select LEDS_GPIO_REGISTER
 	help
@@ -842,6 +821,8 @@
 	select HAVE_IMX_MMDC
 	select HAVE_IMX_SRC
 	select HAVE_SMP
+	select PINCTRL
+	select PINCTRL_IMX6Q
 	select USE_OF
 
 	help
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index ab939c5..4937c07 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -83,10 +83,8 @@
 obj-$(CONFIG_MACH_MX53_SMD) += mach-mx53_smd.o
 obj-$(CONFIG_MACH_MX53_LOCO) += mach-mx53_loco.o
 obj-$(CONFIG_MACH_MX53_ARD) += mach-mx53_ard.o
-obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += mach-cpuimx51.o
-obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o
 obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += mach-cpuimx51sd.o
-obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd-baseboard.o
+obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd51-baseboard.o
 obj-$(CONFIG_MX51_EFIKA_COMMON) += mx51_efika.o
 obj-$(CONFIG_MACH_MX51_EFIKAMX) += mach-mx51_efikamx.o
 obj-$(CONFIG_MACH_MX51_EFIKASB) += mach-mx51_efikasb.o
diff --git a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
index 5f2f91d..b46cab0 100644
--- a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
@@ -243,7 +243,7 @@
 static void __maybe_unused ads7846_dev_init(void)
 {
 	if (gpio_request(ADS7846_PENDOWN, "ADS7846 pendown") < 0) {
-		printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+		printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
 		return;
 	}
 	gpio_direction_input(ADS7846_PENDOWN);
diff --git a/arch/arm/mach-imx/eukrea_mbimx51-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx51-baseboard.c
deleted file mode 100644
index a6a3ab8..0000000
--- a/arch/arm/mach-imx/eukrea_mbimx51-baseboard.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- *
- * Copyright (C) 2010 Eric Bénard <eric@eukrea.com>
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/i2c/tsc2007.h>
-#include <linux/leds.h>
-
-#include <mach/common.h>
-#include <mach/hardware.h>
-#include <mach/iomux-mx51.h>
-
-#include <asm/mach/arch.h>
-
-#include "devices-imx51.h"
-
-#define MBIMX51_TSC2007_GPIO	IMX_GPIO_NR(3, 30)
-#define MBIMX51_LED0		IMX_GPIO_NR(3, 5)
-#define MBIMX51_LED1		IMX_GPIO_NR(3, 6)
-#define MBIMX51_LED2		IMX_GPIO_NR(3, 7)
-#define MBIMX51_LED3		IMX_GPIO_NR(3, 8)
-
-static const struct gpio_led mbimx51_leds[] __initconst = {
-	{
-		.name			= "led0",
-		.default_trigger	= "heartbeat",
-		.active_low		= 1,
-		.gpio			= MBIMX51_LED0,
-	},
-	{
-		.name			= "led1",
-		.default_trigger	= "nand-disk",
-		.active_low		= 1,
-		.gpio			= MBIMX51_LED1,
-	},
-	{
-		.name			= "led2",
-		.default_trigger	= "mmc0",
-		.active_low		= 1,
-		.gpio			= MBIMX51_LED2,
-	},
-	{
-		.name			= "led3",
-		.default_trigger	= "default-on",
-		.active_low		= 1,
-		.gpio			= MBIMX51_LED3,
-	},
-};
-
-static const struct gpio_led_platform_data mbimx51_leds_info __initconst = {
-	.leds		= mbimx51_leds,
-	.num_leds	= ARRAY_SIZE(mbimx51_leds),
-};
-
-static iomux_v3_cfg_t mbimx51_pads[] = {
-	/* UART2 */
-	MX51_PAD_UART2_RXD__UART2_RXD,
-	MX51_PAD_UART2_TXD__UART2_TXD,
-
-	/* UART3 */
-	MX51_PAD_UART3_RXD__UART3_RXD,
-	MX51_PAD_UART3_TXD__UART3_TXD,
-	MX51_PAD_KEY_COL4__UART3_RTS,
-	MX51_PAD_KEY_COL5__UART3_CTS,
-
-	/* TSC2007 IRQ */
-	MX51_PAD_NANDF_D10__GPIO3_30,
-
-	/* LEDS */
-	MX51_PAD_DISPB2_SER_DIN__GPIO3_5,
-	MX51_PAD_DISPB2_SER_DIO__GPIO3_6,
-	MX51_PAD_DISPB2_SER_CLK__GPIO3_7,
-	MX51_PAD_DISPB2_SER_RS__GPIO3_8,
-
-	/* KPP */
-	MX51_PAD_KEY_ROW0__KEY_ROW0,
-	MX51_PAD_KEY_ROW1__KEY_ROW1,
-	MX51_PAD_KEY_ROW2__KEY_ROW2,
-	MX51_PAD_KEY_ROW3__KEY_ROW3,
-	MX51_PAD_KEY_COL0__KEY_COL0,
-	MX51_PAD_KEY_COL1__KEY_COL1,
-	MX51_PAD_KEY_COL2__KEY_COL2,
-	MX51_PAD_KEY_COL3__KEY_COL3,
-
-	/* SD 1 */
-	MX51_PAD_SD1_CMD__SD1_CMD,
-	MX51_PAD_SD1_CLK__SD1_CLK,
-	MX51_PAD_SD1_DATA0__SD1_DATA0,
-	MX51_PAD_SD1_DATA1__SD1_DATA1,
-	MX51_PAD_SD1_DATA2__SD1_DATA2,
-	MX51_PAD_SD1_DATA3__SD1_DATA3,
-
-	/* SD 2 */
-	MX51_PAD_SD2_CMD__SD2_CMD,
-	MX51_PAD_SD2_CLK__SD2_CLK,
-	MX51_PAD_SD2_DATA0__SD2_DATA0,
-	MX51_PAD_SD2_DATA1__SD2_DATA1,
-	MX51_PAD_SD2_DATA2__SD2_DATA2,
-	MX51_PAD_SD2_DATA3__SD2_DATA3,
-};
-
-static const struct imxuart_platform_data uart_pdata __initconst = {
-	.flags = IMXUART_HAVE_RTSCTS,
-};
-
-static int mbimx51_keymap[] = {
-	KEY(0, 0, KEY_1),
-	KEY(0, 1, KEY_2),
-	KEY(0, 2, KEY_3),
-	KEY(0, 3, KEY_UP),
-
-	KEY(1, 0, KEY_4),
-	KEY(1, 1, KEY_5),
-	KEY(1, 2, KEY_6),
-	KEY(1, 3, KEY_LEFT),
-
-	KEY(2, 0, KEY_7),
-	KEY(2, 1, KEY_8),
-	KEY(2, 2, KEY_9),
-	KEY(2, 3, KEY_RIGHT),
-
-	KEY(3, 0, KEY_0),
-	KEY(3, 1, KEY_DOWN),
-	KEY(3, 2, KEY_ESC),
-	KEY(3, 3, KEY_ENTER),
-};
-
-static const struct matrix_keymap_data mbimx51_map_data __initconst = {
-	.keymap		= mbimx51_keymap,
-	.keymap_size	= ARRAY_SIZE(mbimx51_keymap),
-};
-
-static int tsc2007_get_pendown_state(void)
-{
-	return !gpio_get_value(MBIMX51_TSC2007_GPIO);
-}
-
-struct tsc2007_platform_data tsc2007_data = {
-	.model = 2007,
-	.x_plate_ohms = 180,
-	.get_pendown_state = tsc2007_get_pendown_state,
-};
-
-static struct i2c_board_info mbimx51_i2c_devices[] = {
-	{
-		I2C_BOARD_INFO("tsc2007", 0x49),
-		.irq  = IMX_GPIO_TO_IRQ(MBIMX51_TSC2007_GPIO),
-		.platform_data = &tsc2007_data,
-	}, {
-		I2C_BOARD_INFO("tlv320aic23", 0x1a),
-	},
-};
-
-/*
- * baseboard initialization.
- */
-void __init eukrea_mbimx51_baseboard_init(void)
-{
-	mxc_iomux_v3_setup_multiple_pads(mbimx51_pads,
-					ARRAY_SIZE(mbimx51_pads));
-
-	imx51_add_imx_uart(1, NULL);
-	imx51_add_imx_uart(2, &uart_pdata);
-
-	gpio_request(MBIMX51_LED0, "LED0");
-	gpio_direction_output(MBIMX51_LED0, 1);
-	gpio_free(MBIMX51_LED0);
-	gpio_request(MBIMX51_LED1, "LED1");
-	gpio_direction_output(MBIMX51_LED1, 1);
-	gpio_free(MBIMX51_LED1);
-	gpio_request(MBIMX51_LED2, "LED2");
-	gpio_direction_output(MBIMX51_LED2, 1);
-	gpio_free(MBIMX51_LED2);
-	gpio_request(MBIMX51_LED3, "LED3");
-	gpio_direction_output(MBIMX51_LED3, 1);
-	gpio_free(MBIMX51_LED3);
-
-	gpio_led_register_device(-1, &mbimx51_leds_info);
-
-	imx51_add_imx_keypad(&mbimx51_map_data);
-
-	gpio_request(MBIMX51_TSC2007_GPIO, "tsc2007_irq");
-	gpio_direction_input(MBIMX51_TSC2007_GPIO);
-	irq_set_irq_type(gpio_to_irq(MBIMX51_TSC2007_GPIO),
-					IRQF_TRIGGER_FALLING);
-	i2c_register_board_info(1, mbimx51_i2c_devices,
-				ARRAY_SIZE(mbimx51_i2c_devices));
-
-	imx51_add_sdhci_esdhc_imx(0, NULL);
-	imx51_add_sdhci_esdhc_imx(1, NULL);
-}
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c
deleted file mode 100644
index aaa592fd..0000000
--- a/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2010 Eric Benard - eric@eukrea.com
- *
- * Based on pcm970-baseboard.c which is :
- * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/leds.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-#include <linux/i2c.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-#include <mach/common.h>
-#include <mach/iomux-mx51.h>
-
-#include "devices-imx51.h"
-
-static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = {
-	/* LED */
-	MX51_PAD_NANDF_D10__GPIO3_30,
-	/* SWITCH */
-	NEW_PAD_CTRL(MX51_PAD_NANDF_D9__GPIO3_31, PAD_CTL_PUS_22K_UP |
-			PAD_CTL_PKE | PAD_CTL_SRE_FAST |
-			PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
-	/* UART2 */
-	MX51_PAD_UART2_RXD__UART2_RXD,
-	MX51_PAD_UART2_TXD__UART2_TXD,
-	/* UART 3 */
-	MX51_PAD_UART3_RXD__UART3_RXD,
-	MX51_PAD_UART3_TXD__UART3_TXD,
-	MX51_PAD_KEY_COL4__UART3_RTS,
-	MX51_PAD_KEY_COL5__UART3_CTS,
-	/* SD */
-	MX51_PAD_SD1_CMD__SD1_CMD,
-	MX51_PAD_SD1_CLK__SD1_CLK,
-	MX51_PAD_SD1_DATA0__SD1_DATA0,
-	MX51_PAD_SD1_DATA1__SD1_DATA1,
-	MX51_PAD_SD1_DATA2__SD1_DATA2,
-	MX51_PAD_SD1_DATA3__SD1_DATA3,
-	/* SD1 CD */
-	NEW_PAD_CTRL(MX51_PAD_GPIO1_0__SD1_CD, PAD_CTL_PUS_22K_UP |
-			PAD_CTL_PKE | PAD_CTL_SRE_FAST |
-			PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
-};
-
-#define GPIO_LED1	IMX_GPIO_NR(3, 30)
-#define GPIO_SWITCH1	IMX_GPIO_NR(3, 31)
-
-static const struct gpio_led eukrea_mbimxsd_leds[] __initconst = {
-	{
-		.name			= "led1",
-		.default_trigger	= "heartbeat",
-		.active_low		= 1,
-		.gpio			= GPIO_LED1,
-	},
-};
-
-static const struct gpio_led_platform_data
-		eukrea_mbimxsd_led_info __initconst = {
-	.leds		= eukrea_mbimxsd_leds,
-	.num_leds	= ARRAY_SIZE(eukrea_mbimxsd_leds),
-};
-
-static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
-	{
-		.gpio		= GPIO_SWITCH1,
-		.code		= BTN_0,
-		.desc		= "BP1",
-		.active_low	= 1,
-		.wakeup		= 1,
-	},
-};
-
-static const struct gpio_keys_platform_data
-		eukrea_mbimxsd_button_data __initconst = {
-	.buttons	= eukrea_mbimxsd_gpio_buttons,
-	.nbuttons	= ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
-};
-
-static const struct imxuart_platform_data uart_pdata __initconst = {
-	.flags = IMXUART_HAVE_RTSCTS,
-};
-
-static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
-	{
-		I2C_BOARD_INFO("tlv320aic23", 0x1a),
-	},
-};
-
-/*
- * system init for baseboard usage. Will be called by cpuimx51sd init.
- *
- * Add platform devices present on this baseboard and init
- * them from CPU side as far as required to use them later on
- */
-void __init eukrea_mbimxsd51_baseboard_init(void)
-{
-	if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads,
-			ARRAY_SIZE(eukrea_mbimxsd_pads)))
-		printk(KERN_ERR "error setting mbimxsd pads !\n");
-
-	imx51_add_imx_uart(1, NULL);
-	imx51_add_imx_uart(2, &uart_pdata);
-
-	imx51_add_sdhci_esdhc_imx(0, NULL);
-
-	gpio_request(GPIO_LED1, "LED1");
-	gpio_direction_output(GPIO_LED1, 1);
-	gpio_free(GPIO_LED1);
-
-	gpio_request(GPIO_SWITCH1, "SWITCH1");
-	gpio_direction_input(GPIO_SWITCH1);
-	gpio_free(GPIO_SWITCH1);
-
-	i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
-				ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
-
-	gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
-	imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
-}
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
index 2cf603e..dfd2da8 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
@@ -23,6 +23,7 @@
 #include <linux/leds.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
+#include <linux/spi/spi.h>
 #include <video/platform_lcd.h>
 
 #include <mach/hardware.h>
@@ -87,12 +88,22 @@
 	/* CAN */
 	MX25_PAD_GPIO_D__CAN2_RX,
 	MX25_PAD_GPIO_C__CAN2_TX,
+	/* SPI1 */
+	MX25_PAD_CSPI1_MOSI__CSPI1_MOSI,
+	MX25_PAD_CSPI1_MISO__CSPI1_MISO,
+	MX25_PAD_CSPI1_SS0__GPIO_1_16,
+	MX25_PAD_CSPI1_SS1__GPIO_1_17,
+	MX25_PAD_CSPI1_SCLK__CSPI1_SCLK,
+	MX25_PAD_CSPI1_RDY__GPIO_2_22,
 };
 
-#define GPIO_LED1	83
-#define GPIO_SWITCH1	82
-#define GPIO_SD1CD	52
-#define GPIO_LCDPWR	26
+#define GPIO_LED1		IMX_GPIO_NR(3, 19)
+#define GPIO_SWITCH1	IMX_GPIO_NR(3, 18)
+#define GPIO_SD1CD		IMX_GPIO_NR(2, 20)
+#define GPIO_LCDPWR		IMX_GPIO_NR(1, 26)
+#define	GPIO_SPI1_SS0	IMX_GPIO_NR(1, 16)
+#define	GPIO_SPI1_SS1	IMX_GPIO_NR(1, 17)
+#define	GPIO_SPI1_IRQ	IMX_GPIO_NR(2, 22)
 
 static struct imx_fb_videomode eukrea_mximxsd_modes[] = {
 	{
@@ -228,6 +239,30 @@
 	.wp_type = ESDHC_WP_NONE,
 };
 
+static struct spi_board_info eukrea_mbimxsd25_spi_board_info[] __initdata = {
+	{
+		.modalias = "spidev",
+		.max_speed_hz = 20000000,
+		.bus_num = 0,
+		.chip_select = 0,
+		.mode = SPI_MODE_0,
+	},
+	{
+		.modalias = "spidev",
+		.max_speed_hz = 20000000,
+		.bus_num = 0,
+		.chip_select = 1,
+		.mode = SPI_MODE_0,
+	},
+};
+
+static int eukrea_mbimxsd25_spi_cs[] = {GPIO_SPI1_SS0, GPIO_SPI1_SS1};
+
+static const struct spi_imx_master eukrea_mbimxsd25_spi0_data __initconst = {
+	.chipselect     = eukrea_mbimxsd25_spi_cs,
+	.num_chipselect = ARRAY_SIZE(eukrea_mbimxsd25_spi_cs),
+};
+
 /*
  * system init for baseboard usage. Will be called by cpuimx25 init.
  *
@@ -257,11 +292,17 @@
 
 	gpio_request(GPIO_LCDPWR, "LCDPWR");
 	gpio_direction_output(GPIO_LCDPWR, 1);
-	gpio_free(GPIO_SWITCH1);
 
 	i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
 				ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
 
+	gpio_request(GPIO_SPI1_IRQ, "SPI1_IRQ");
+	gpio_direction_input(GPIO_SPI1_IRQ);
+	gpio_free(GPIO_SPI1_IRQ);
+	imx25_add_spi_imx0(&eukrea_mbimxsd25_spi0_data);
+	spi_register_board_info(eukrea_mbimxsd25_spi_board_info,
+		ARRAY_SIZE(eukrea_mbimxsd25_spi_board_info));
+
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 	gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
 	imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
index fd8bf8a..557f6c48 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
@@ -27,6 +27,7 @@
 #include <linux/leds.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
+#include <linux/spi/spi.h>
 #include <video/platform_lcd.h>
 #include <linux/i2c.h>
 
@@ -158,12 +159,22 @@
 	MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
 	/* SD1 CD */
 	MX35_PAD_LD18__GPIO3_24,
+	/* SPI */
+	MX35_PAD_CSPI1_MOSI__CSPI1_MOSI,
+	MX35_PAD_CSPI1_MISO__CSPI1_MISO,
+	MX35_PAD_CSPI1_SS0__GPIO1_18,
+	MX35_PAD_CSPI1_SS1__GPIO1_19,
+	MX35_PAD_CSPI1_SCLK__CSPI1_SCLK,
+	MX35_PAD_CSPI1_SPI_RDY__GPIO3_5,
 };
 
 #define GPIO_LED1	IMX_GPIO_NR(3, 29)
 #define GPIO_SWITCH1	IMX_GPIO_NR(3, 25)
 #define GPIO_LCDPWR	IMX_GPIO_NR(1, 4)
 #define GPIO_SD1CD	IMX_GPIO_NR(3, 24)
+#define	GPIO_SPI1_SS0	IMX_GPIO_NR(1, 18)
+#define	GPIO_SPI1_SS1	IMX_GPIO_NR(1, 19)
+#define	GPIO_SPI1_IRQ	IMX_GPIO_NR(3, 5)
 
 static void eukrea_mbimxsd_lcd_power_set(struct plat_lcd_data *pd,
 				   unsigned int power)
@@ -239,6 +250,30 @@
 	.wp_type = ESDHC_WP_NONE,
 };
 
+static struct spi_board_info eukrea_mbimxsd35_spi_board_info[] __initdata = {
+	{
+		.modalias = "spidev",
+		.max_speed_hz = 20000000,
+		.bus_num = 0,
+		.chip_select = 0,
+		.mode = SPI_MODE_0,
+	},
+	{
+		.modalias = "spidev",
+		.max_speed_hz = 20000000,
+		.bus_num = 0,
+		.chip_select = 1,
+		.mode = SPI_MODE_0,
+	},
+};
+
+static int eukrea_mbimxsd35_spi_cs[] = {GPIO_SPI1_SS0, GPIO_SPI1_SS1};
+
+static const struct spi_imx_master eukrea_mbimxsd35_spi0_data __initconst = {
+	.chipselect     = eukrea_mbimxsd35_spi_cs,
+	.num_chipselect = ARRAY_SIZE(eukrea_mbimxsd35_spi_cs),
+};
+
 /*
  * system init for baseboard usage. Will be called by cpuimx35 init.
  *
@@ -274,6 +309,13 @@
 	i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
 				ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
 
+	gpio_request(GPIO_SPI1_IRQ, "SPI1_IRQ");
+	gpio_direction_input(GPIO_SPI1_IRQ);
+	gpio_free(GPIO_SPI1_IRQ);
+	imx35_add_spi_imx0(&eukrea_mbimxsd35_spi0_data);
+	spi_register_board_info(eukrea_mbimxsd35_spi_board_info,
+		ARRAY_SIZE(eukrea_mbimxsd35_spi_board_info));
+
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 	gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
 	imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c
new file mode 100644
index 0000000..96a24b7
--- /dev/null
+++ b/arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2010 Eric Benard - eric@eukrea.com
+ *
+ * Based on pcm970-baseboard.c which is :
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <video/platform_lcd.h>
+#include <linux/backlight.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/iomux-mx51.h>
+
+#include "devices-imx51.h"
+
+static iomux_v3_cfg_t eukrea_mbimxsd51_pads[] = {
+	/* LED */
+	MX51_PAD_NANDF_D10__GPIO3_30,
+	/* SWITCH */
+	NEW_PAD_CTRL(MX51_PAD_NANDF_D9__GPIO3_31, PAD_CTL_PUS_22K_UP |
+			PAD_CTL_PKE | PAD_CTL_SRE_FAST |
+			PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
+	/* UART2 */
+	MX51_PAD_UART2_RXD__UART2_RXD,
+	MX51_PAD_UART2_TXD__UART2_TXD,
+	/* UART 3 */
+	MX51_PAD_UART3_RXD__UART3_RXD,
+	MX51_PAD_UART3_TXD__UART3_TXD,
+	MX51_PAD_KEY_COL4__UART3_RTS,
+	MX51_PAD_KEY_COL5__UART3_CTS,
+	/* SD */
+	MX51_PAD_SD1_CMD__SD1_CMD,
+	MX51_PAD_SD1_CLK__SD1_CLK,
+	MX51_PAD_SD1_DATA0__SD1_DATA0,
+	MX51_PAD_SD1_DATA1__SD1_DATA1,
+	MX51_PAD_SD1_DATA2__SD1_DATA2,
+	MX51_PAD_SD1_DATA3__SD1_DATA3,
+	/* SD1 CD */
+	NEW_PAD_CTRL(MX51_PAD_GPIO1_0__SD1_CD, PAD_CTL_PUS_22K_UP |
+			PAD_CTL_PKE | PAD_CTL_SRE_FAST |
+			PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
+	/* SSI */
+	MX51_PAD_AUD3_BB_TXD__AUD3_TXD,
+	MX51_PAD_AUD3_BB_RXD__AUD3_RXD,
+	MX51_PAD_AUD3_BB_CK__AUD3_TXC,
+	MX51_PAD_AUD3_BB_FS__AUD3_TXFS,
+	/* LCD Backlight */
+	MX51_PAD_DI1_D1_CS__GPIO3_4,
+	/* LCD RST */
+	MX51_PAD_CSI1_D9__GPIO3_13,
+};
+
+#define GPIO_LED1	IMX_GPIO_NR(3, 30)
+#define GPIO_SWITCH1	IMX_GPIO_NR(3, 31)
+#define GPIO_LCDRST	IMX_GPIO_NR(3, 13)
+#define GPIO_LCDBL	IMX_GPIO_NR(3, 4)
+
+static void eukrea_mbimxsd51_lcd_power_set(struct plat_lcd_data *pd,
+				   unsigned int power)
+{
+	if (power)
+		gpio_direction_output(GPIO_LCDRST, 1);
+	else
+		gpio_direction_output(GPIO_LCDRST, 0);
+}
+
+static struct plat_lcd_data eukrea_mbimxsd51_lcd_power_data = {
+	.set_power		= eukrea_mbimxsd51_lcd_power_set,
+};
+
+static struct platform_device eukrea_mbimxsd51_lcd_powerdev = {
+	.name			= "platform-lcd",
+	.dev.platform_data	= &eukrea_mbimxsd51_lcd_power_data,
+};
+
+static void eukrea_mbimxsd51_bl_set_intensity(int intensity)
+{
+	if (intensity)
+		gpio_direction_output(GPIO_LCDBL, 1);
+	else
+		gpio_direction_output(GPIO_LCDBL, 0);
+}
+
+static struct generic_bl_info eukrea_mbimxsd51_bl_info = {
+	.name			= "eukrea_mbimxsd51-bl",
+	.max_intensity		= 0xff,
+	.default_intensity	= 0xff,
+	.set_bl_intensity	= eukrea_mbimxsd51_bl_set_intensity,
+};
+
+static struct platform_device eukrea_mbimxsd51_bl_dev = {
+	.name			= "generic-bl",
+	.id			= 1,
+	.dev = {
+		.platform_data	= &eukrea_mbimxsd51_bl_info,
+	},
+};
+
+static const struct gpio_led eukrea_mbimxsd51_leds[] __initconst = {
+	{
+		.name			= "led1",
+		.default_trigger	= "heartbeat",
+		.active_low		= 1,
+		.gpio			= GPIO_LED1,
+	},
+};
+
+static const struct gpio_led_platform_data
+		eukrea_mbimxsd51_led_info __initconst = {
+	.leds		= eukrea_mbimxsd51_leds,
+	.num_leds	= ARRAY_SIZE(eukrea_mbimxsd51_leds),
+};
+
+static struct gpio_keys_button eukrea_mbimxsd51_gpio_buttons[] = {
+	{
+		.gpio		= GPIO_SWITCH1,
+		.code		= BTN_0,
+		.desc		= "BP1",
+		.active_low	= 1,
+		.wakeup		= 1,
+	},
+};
+
+static const struct gpio_keys_platform_data
+		eukrea_mbimxsd51_button_data __initconst = {
+	.buttons	= eukrea_mbimxsd51_gpio_buttons,
+	.nbuttons	= ARRAY_SIZE(eukrea_mbimxsd51_gpio_buttons),
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct i2c_board_info eukrea_mbimxsd51_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("tlv320aic23", 0x1a),
+	},
+};
+
+static const
+struct imx_ssi_platform_data eukrea_mbimxsd51_ssi_pdata __initconst = {
+	.flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
+};
+
+static int screen_type;
+
+static int __init eukrea_mbimxsd51_screen_type(char *options)
+{
+	if (!strcmp(options, "dvi"))
+		screen_type = 1;
+	else if (!strcmp(options, "tft"))
+		screen_type = 0;
+
+	return 0;
+}
+__setup("screen_type=", eukrea_mbimxsd51_screen_type);
+
+/*
+ * system init for baseboard usage. Will be called by cpuimx51sd init.
+ *
+ * Add platform devices present on this baseboard and init
+ * them from CPU side as far as required to use them later on
+ */
+void __init eukrea_mbimxsd51_baseboard_init(void)
+{
+	if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd51_pads,
+			ARRAY_SIZE(eukrea_mbimxsd51_pads)))
+		printk(KERN_ERR "error setting mbimxsd pads !\n");
+
+	imx51_add_imx_uart(1, NULL);
+	imx51_add_imx_uart(2, &uart_pdata);
+
+	imx51_add_sdhci_esdhc_imx(0, NULL);
+
+	imx51_add_imx_ssi(0, &eukrea_mbimxsd51_ssi_pdata);
+
+	gpio_request(GPIO_LED1, "LED1");
+	gpio_direction_output(GPIO_LED1, 1);
+	gpio_free(GPIO_LED1);
+
+	gpio_request(GPIO_SWITCH1, "SWITCH1");
+	gpio_direction_input(GPIO_SWITCH1);
+	gpio_free(GPIO_SWITCH1);
+
+	gpio_request(GPIO_LCDRST, "LCDRST");
+	gpio_direction_output(GPIO_LCDRST, 0);
+	gpio_request(GPIO_LCDBL, "LCDBL");
+	gpio_direction_output(GPIO_LCDBL, 0);
+	if (!screen_type) {
+		platform_device_register(&eukrea_mbimxsd51_bl_dev);
+		platform_device_register(&eukrea_mbimxsd51_lcd_powerdev);
+	} else {
+		gpio_free(GPIO_LCDRST);
+		gpio_free(GPIO_LCDBL);
+	}
+
+	i2c_register_board_info(0, eukrea_mbimxsd51_i2c_devices,
+				ARRAY_SIZE(eukrea_mbimxsd51_i2c_devices));
+
+	gpio_led_register_device(-1, &eukrea_mbimxsd51_led_info);
+	imx_add_gpio_keys(&eukrea_mbimxsd51_button_data);
+}
diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c
index 5cca573..5f577fb 100644
--- a/arch/arm/mach-imx/imx51-dt.c
+++ b/arch/arm/mach-imx/imx51-dt.c
@@ -14,6 +14,7 @@
 #include <linux/irqdomain.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <linux/pinctrl/machine.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <mach/common.h>
@@ -81,6 +82,8 @@
 
 	of_irq_init(imx51_irq_match);
 
+	pinctrl_provide_dummies();
+
 	node = of_find_matching_node(NULL, imx51_iomuxc_of_match);
 	if (node) {
 		of_id = of_match_node(imx51_iomuxc_of_match, node);
diff --git a/arch/arm/mach-imx/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c
index 4172279..574eca4 100644
--- a/arch/arm/mach-imx/imx53-dt.c
+++ b/arch/arm/mach-imx/imx53-dt.c
@@ -15,6 +15,7 @@
 #include <linux/irqdomain.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <linux/pinctrl/machine.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <mach/common.h>
@@ -88,6 +89,8 @@
 
 	of_irq_init(imx53_irq_match);
 
+	pinctrl_provide_dummies();
+
 	node = of_find_matching_node(NULL, imx53_iomuxc_of_match);
 	if (node) {
 		of_id = of_match_node(imx53_iomuxc_of_match, node);
diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c
index 8ecc872..c515f8e 100644
--- a/arch/arm/mach-imx/mach-cpuimx35.c
+++ b/arch/arm/mach-imx/mach-cpuimx35.c
@@ -194,7 +194,7 @@
 	mx35_clocks_init();
 }
 
-struct sys_timer eukrea_cpuimx35_timer = {
+static struct sys_timer eukrea_cpuimx35_timer = {
 	.init	= eukrea_cpuimx35_timer_init,
 };
 
diff --git a/arch/arm/mach-imx/mach-cpuimx51.c b/arch/arm/mach-imx/mach-cpuimx51.c
deleted file mode 100644
index 944025d..0000000
--- a/arch/arm/mach-imx/mach-cpuimx51.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- *
- * Copyright (C) 2010 Eric Bénard <eric@eukrea.com>
- *
- * based on board-mx51_babbage.c which is
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-
-#include <mach/eukrea-baseboards.h>
-#include <mach/common.h>
-#include <mach/hardware.h>
-#include <mach/iomux-mx51.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-
-#include "devices-imx51.h"
-
-#define CPUIMX51_USBH1_STP	IMX_GPIO_NR(1, 27)
-#define CPUIMX51_QUARTA_GPIO	IMX_GPIO_NR(3, 28)
-#define CPUIMX51_QUARTB_GPIO	IMX_GPIO_NR(3, 25)
-#define CPUIMX51_QUARTC_GPIO	IMX_GPIO_NR(3, 26)
-#define CPUIMX51_QUARTD_GPIO	IMX_GPIO_NR(3, 27)
-#define CPUIMX51_QUART_XTAL	14745600
-#define CPUIMX51_QUART_REGSHIFT	17
-
-/* USB_CTRL_1 */
-#define MX51_USB_CTRL_1_OFFSET		0x10
-#define MX51_USB_CTRL_UH1_EXT_CLK_EN	(1 << 25)
-
-#define	MX51_USB_PLLDIV_12_MHZ		0x00
-#define	MX51_USB_PLL_DIV_19_2_MHZ	0x01
-#define	MX51_USB_PLL_DIV_24_MHZ		0x02
-
-static struct plat_serial8250_port serial_platform_data[] = {
-	{
-		.mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x400000),
-		.irq = IMX_GPIO_TO_IRQ(CPUIMX51_QUARTA_GPIO),
-		.irqflags = IRQF_TRIGGER_HIGH,
-		.uartclk = CPUIMX51_QUART_XTAL,
-		.regshift = CPUIMX51_QUART_REGSHIFT,
-		.iotype = UPIO_MEM,
-		.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
-	}, {
-		.mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x800000),
-		.irq = IMX_GPIO_TO_IRQ(CPUIMX51_QUARTB_GPIO),
-		.irqflags = IRQF_TRIGGER_HIGH,
-		.uartclk = CPUIMX51_QUART_XTAL,
-		.regshift = CPUIMX51_QUART_REGSHIFT,
-		.iotype = UPIO_MEM,
-		.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
-	}, {
-		.mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x1000000),
-		.irq = IMX_GPIO_TO_IRQ(CPUIMX51_QUARTC_GPIO),
-		.irqflags = IRQF_TRIGGER_HIGH,
-		.uartclk = CPUIMX51_QUART_XTAL,
-		.regshift = CPUIMX51_QUART_REGSHIFT,
-		.iotype = UPIO_MEM,
-		.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
-	}, {
-		.mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x2000000),
-		.irq = IMX_GPIO_TO_IRQ(CPUIMX51_QUARTD_GPIO),
-		.irqflags = IRQF_TRIGGER_HIGH,
-		.uartclk = CPUIMX51_QUART_XTAL,
-		.regshift = CPUIMX51_QUART_REGSHIFT,
-		.iotype = UPIO_MEM,
-		.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
-	}, {
-	}
-};
-
-static struct platform_device serial_device = {
-	.name = "serial8250",
-	.id = 0,
-	.dev = {
-		.platform_data = serial_platform_data,
-	},
-};
-
-static struct platform_device *devices[] __initdata = {
-	&serial_device,
-};
-
-static iomux_v3_cfg_t eukrea_cpuimx51_pads[] = {
-	/* UART1 */
-	MX51_PAD_UART1_RXD__UART1_RXD,
-	MX51_PAD_UART1_TXD__UART1_TXD,
-	MX51_PAD_UART1_RTS__UART1_RTS,
-	MX51_PAD_UART1_CTS__UART1_CTS,
-
-	/* I2C2 */
-	MX51_PAD_GPIO1_2__I2C2_SCL,
-	MX51_PAD_GPIO1_3__I2C2_SDA,
-	MX51_PAD_NANDF_D10__GPIO3_30,
-
-	/* QUART IRQ */
-	MX51_PAD_NANDF_D15__GPIO3_25,
-	MX51_PAD_NANDF_D14__GPIO3_26,
-	MX51_PAD_NANDF_D13__GPIO3_27,
-	MX51_PAD_NANDF_D12__GPIO3_28,
-
-	/* USB HOST1 */
-	MX51_PAD_USBH1_CLK__USBH1_CLK,
-	MX51_PAD_USBH1_DIR__USBH1_DIR,
-	MX51_PAD_USBH1_NXT__USBH1_NXT,
-	MX51_PAD_USBH1_DATA0__USBH1_DATA0,
-	MX51_PAD_USBH1_DATA1__USBH1_DATA1,
-	MX51_PAD_USBH1_DATA2__USBH1_DATA2,
-	MX51_PAD_USBH1_DATA3__USBH1_DATA3,
-	MX51_PAD_USBH1_DATA4__USBH1_DATA4,
-	MX51_PAD_USBH1_DATA5__USBH1_DATA5,
-	MX51_PAD_USBH1_DATA6__USBH1_DATA6,
-	MX51_PAD_USBH1_DATA7__USBH1_DATA7,
-	MX51_PAD_USBH1_STP__USBH1_STP,
-};
-
-static const struct mxc_nand_platform_data
-		eukrea_cpuimx51_nand_board_info __initconst = {
-	.width		= 1,
-	.hw_ecc		= 1,
-	.flash_bbt	= 1,
-};
-
-static const struct imxuart_platform_data uart_pdata __initconst = {
-	.flags = IMXUART_HAVE_RTSCTS,
-};
-
-static const
-struct imxi2c_platform_data eukrea_cpuimx51_i2c_data __initconst = {
-	.bitrate = 100000,
-};
-
-static struct i2c_board_info eukrea_cpuimx51_i2c_devices[] = {
-	{
-		I2C_BOARD_INFO("pcf8563", 0x51),
-	},
-};
-
-/* This function is board specific as the bit mask for the plldiv will also
-be different for other Freescale SoCs, thus a common bitmask is not
-possible and cannot get place in /plat-mxc/ehci.c.*/
-static int initialize_otg_port(struct platform_device *pdev)
-{
-	u32 v;
-	void __iomem *usb_base;
-	void __iomem *usbother_base;
-
-	usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K);
-	if (!usb_base)
-		return -ENOMEM;
-	usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
-
-	/* Set the PHY clock to 19.2MHz */
-	v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
-	v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
-	v |= MX51_USB_PLL_DIV_19_2_MHZ;
-	__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
-	iounmap(usb_base);
-
-	mdelay(10);
-
-	return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY);
-}
-
-static int initialize_usbh1_port(struct platform_device *pdev)
-{
-	u32 v;
-	void __iomem *usb_base;
-	void __iomem *usbother_base;
-
-	usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K);
-	if (!usb_base)
-		return -ENOMEM;
-	usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
-
-	/* The clock for the USBH1 ULPI port will come externally from the PHY. */
-	v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET);
-	__raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET);
-	iounmap(usb_base);
-
-	mdelay(10);
-
-	return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED |
-			MXC_EHCI_ITC_NO_THRESHOLD);
-}
-
-static const struct mxc_usbh_platform_data dr_utmi_config __initconst = {
-	.init		= initialize_otg_port,
-	.portsc	= MXC_EHCI_UTMI_16BIT,
-};
-
-static const struct fsl_usb2_platform_data usb_pdata __initconst = {
-	.operating_mode	= FSL_USB2_DR_DEVICE,
-	.phy_mode	= FSL_USB2_PHY_UTMI_WIDE,
-};
-
-static const struct mxc_usbh_platform_data usbh1_config __initconst = {
-	.init		= initialize_usbh1_port,
-	.portsc	= MXC_EHCI_MODE_ULPI,
-};
-
-static int otg_mode_host;
-
-static int __init eukrea_cpuimx51_otg_mode(char *options)
-{
-	if (!strcmp(options, "host"))
-		otg_mode_host = 1;
-	else if (!strcmp(options, "device"))
-		otg_mode_host = 0;
-	else
-		pr_info("otg_mode neither \"host\" nor \"device\". "
-			"Defaulting to device\n");
-	return 0;
-}
-__setup("otg_mode=", eukrea_cpuimx51_otg_mode);
-
-/*
- * Board specific initialization.
- */
-static void __init eukrea_cpuimx51_init(void)
-{
-	imx51_soc_init();
-
-	mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51_pads,
-					ARRAY_SIZE(eukrea_cpuimx51_pads));
-
-	imx51_add_imx_uart(0, &uart_pdata);
-	imx51_add_mxc_nand(&eukrea_cpuimx51_nand_board_info);
-
-	gpio_request(CPUIMX51_QUARTA_GPIO, "quarta_irq");
-	gpio_direction_input(CPUIMX51_QUARTA_GPIO);
-	gpio_free(CPUIMX51_QUARTA_GPIO);
-	gpio_request(CPUIMX51_QUARTB_GPIO, "quartb_irq");
-	gpio_direction_input(CPUIMX51_QUARTB_GPIO);
-	gpio_free(CPUIMX51_QUARTB_GPIO);
-	gpio_request(CPUIMX51_QUARTC_GPIO, "quartc_irq");
-	gpio_direction_input(CPUIMX51_QUARTC_GPIO);
-	gpio_free(CPUIMX51_QUARTC_GPIO);
-	gpio_request(CPUIMX51_QUARTD_GPIO, "quartd_irq");
-	gpio_direction_input(CPUIMX51_QUARTD_GPIO);
-	gpio_free(CPUIMX51_QUARTD_GPIO);
-
-	imx51_add_fec(NULL);
-	platform_add_devices(devices, ARRAY_SIZE(devices));
-
-	imx51_add_imx_i2c(1, &eukrea_cpuimx51_i2c_data);
-	i2c_register_board_info(1, eukrea_cpuimx51_i2c_devices,
-				ARRAY_SIZE(eukrea_cpuimx51_i2c_devices));
-
-	if (otg_mode_host)
-		imx51_add_mxc_ehci_otg(&dr_utmi_config);
-	else {
-		initialize_otg_port(NULL);
-		imx51_add_fsl_usb2_udc(&usb_pdata);
-	}
-	imx51_add_mxc_ehci_hs(1, &usbh1_config);
-
-#ifdef CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD
-	eukrea_mbimx51_baseboard_init();
-#endif
-}
-
-static void __init eukrea_cpuimx51_timer_init(void)
-{
-	mx51_clocks_init(32768, 24000000, 22579200, 0);
-}
-
-static struct sys_timer mxc_timer = {
-	.init	= eukrea_cpuimx51_timer_init,
-};
-
-MACHINE_START(EUKREA_CPUIMX51, "Eukrea CPUIMX51 Module")
-	/* Maintainer: Eric Bénard <eric@eukrea.com> */
-	.atag_offset = 0x100,
-	.map_io = mx51_map_io,
-	.init_early = imx51_init_early,
-	.init_irq = mx51_init_irq,
-	.handle_irq = imx51_handle_irq,
-	.timer = &mxc_timer,
-	.init_machine = eukrea_cpuimx51_init,
-	.restart	= mxc_restart,
-MACHINE_END
diff --git a/arch/arm/mach-imx/mach-cpuimx51sd.c b/arch/arm/mach-imx/mach-cpuimx51sd.c
index 9fbe923..ce341a6 100644
--- a/arch/arm/mach-imx/mach-cpuimx51sd.c
+++ b/arch/arm/mach-imx/mach-cpuimx51sd.c
@@ -41,11 +41,13 @@
 
 #define USBH1_RST		IMX_GPIO_NR(2, 28)
 #define ETH_RST			IMX_GPIO_NR(2, 31)
-#define TSC2007_IRQGPIO		IMX_GPIO_NR(3, 12)
+#define TSC2007_IRQGPIO_REV2	IMX_GPIO_NR(3, 12)
+#define TSC2007_IRQGPIO_REV3	IMX_GPIO_NR(4, 0)
 #define CAN_IRQGPIO		IMX_GPIO_NR(1, 1)
 #define CAN_RST			IMX_GPIO_NR(4, 15)
 #define CAN_NCS			IMX_GPIO_NR(4, 24)
-#define CAN_RXOBF		IMX_GPIO_NR(1, 4)
+#define CAN_RXOBF_REV2		IMX_GPIO_NR(1, 4)
+#define CAN_RXOBF_REV3		IMX_GPIO_NR(3, 12)
 #define CAN_RX1BF		IMX_GPIO_NR(1, 6)
 #define CAN_TXORTS		IMX_GPIO_NR(1, 7)
 #define CAN_TX1RTS		IMX_GPIO_NR(1, 8)
@@ -90,6 +92,10 @@
 	MX51_PAD_I2C1_CLK__GPIO4_16,
 	MX51_PAD_I2C1_DAT__GPIO4_17,
 
+	/* I2C1 */
+	MX51_PAD_SD2_CMD__I2C1_SCL,
+	MX51_PAD_SD2_CLK__I2C1_SDA,
+
 	/* CAN */
 	MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI,
 	MX51_PAD_CSPI1_MISO__ECSPI1_MISO,
@@ -108,15 +114,27 @@
 	NEW_PAD_CTRL(MX51_PAD_GPIO_NAND__GPIO_NAND, PAD_CTL_PUS_22K_UP |
 			PAD_CTL_PKE | PAD_CTL_SRE_FAST |
 			PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
+	NEW_PAD_CTRL(MX51_PAD_NANDF_D8__GPIO4_0, PAD_CTL_PUS_22K_UP |
+			PAD_CTL_PKE | PAD_CTL_SRE_FAST |
+			PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
 };
 
 static const struct imxuart_platform_data uart_pdata __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
+static int tsc2007_get_pendown_state(void)
+{
+	if (mx51_revision() < IMX_CHIP_REVISION_3_0)
+		return !gpio_get_value(TSC2007_IRQGPIO_REV2);
+	else
+		return !gpio_get_value(TSC2007_IRQGPIO_REV3);
+}
+
 static struct tsc2007_platform_data tsc2007_info = {
 	.model			= 2007,
 	.x_plate_ohms		= 180,
+	.get_pendown_state	= tsc2007_get_pendown_state,
 };
 
 static struct i2c_board_info eukrea_cpuimx51sd_i2c_devices[] = {
@@ -126,7 +144,6 @@
 		I2C_BOARD_INFO("tsc2007", 0x49),
 		.type		= "tsc2007",
 		.platform_data	= &tsc2007_info,
-		.irq		= IMX_GPIO_TO_IRQ(TSC2007_IRQGPIO),
 	},
 };
 
@@ -255,10 +272,14 @@
 	.num_chipselect	= ARRAY_SIZE(cpuimx51sd_spi1_cs),
 };
 
-static struct platform_device *platform_devices[] __initdata = {
+static struct platform_device *rev2_platform_devices[] __initdata = {
 	&hsi2c_gpio_device,
 };
 
+static const struct imxi2c_platform_data cpuimx51sd_i2c_data __initconst = {
+	.bitrate = 100000,
+};
+
 static void __init eukrea_cpuimx51sd_init(void)
 {
 	imx51_soc_init();
@@ -272,6 +293,7 @@
 
 	imx51_add_imx_uart(0, &uart_pdata);
 	imx51_add_mxc_nand(&eukrea_cpuimx51sd_nand_board_info);
+	imx51_add_imx2_wdt(0, NULL);
 
 	gpio_request(ETH_RST, "eth_rst");
 	gpio_set_value(ETH_RST, 1);
@@ -291,13 +313,25 @@
 	spi_register_board_info(cpuimx51sd_spi_device,
 				ARRAY_SIZE(cpuimx51sd_spi_device));
 
-	gpio_request(TSC2007_IRQGPIO, "tsc2007_irq");
-	gpio_direction_input(TSC2007_IRQGPIO);
-	gpio_free(TSC2007_IRQGPIO);
+	if (mx51_revision() < IMX_CHIP_REVISION_3_0) {
+		eukrea_cpuimx51sd_i2c_devices[1].irq =
+			gpio_to_irq(TSC2007_IRQGPIO_REV2),
+		platform_add_devices(rev2_platform_devices,
+			ARRAY_SIZE(rev2_platform_devices));
+		gpio_request(TSC2007_IRQGPIO_REV2, "tsc2007_irq");
+		gpio_direction_input(TSC2007_IRQGPIO_REV2);
+		gpio_free(TSC2007_IRQGPIO_REV2);
+	} else {
+		eukrea_cpuimx51sd_i2c_devices[1].irq =
+			gpio_to_irq(TSC2007_IRQGPIO_REV3),
+		imx51_add_imx_i2c(0, &cpuimx51sd_i2c_data);
+		gpio_request(TSC2007_IRQGPIO_REV3, "tsc2007_irq");
+		gpio_direction_input(TSC2007_IRQGPIO_REV3);
+		gpio_free(TSC2007_IRQGPIO_REV3);
+	}
 
 	i2c_register_board_info(0, eukrea_cpuimx51sd_i2c_devices,
 			ARRAY_SIZE(eukrea_cpuimx51sd_i2c_devices));
-	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
 	if (otg_mode_host)
 		imx51_add_mxc_ehci_otg(&dr_utmi_config);
diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
index 76a97a5..d1e04e6 100644
--- a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
+++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
@@ -106,6 +106,7 @@
 static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
 	.operating_mode = FSL_USB2_DR_DEVICE,
 	.phy_mode       = FSL_USB2_PHY_UTMI,
+	.workaround     = FLS_USB2_WORKAROUND_ENGCM09152,
 };
 
 static int otg_mode_host;
@@ -135,6 +136,7 @@
 	imx25_add_mxc_nand(&eukrea_cpuimx25_nand_board_info);
 	imx25_add_imxdi_rtc(NULL);
 	imx25_add_fec(&mx25_fec_pdata);
+	imx25_add_imx2_wdt(NULL);
 
 	i2c_register_board_info(0, eukrea_cpuimx25_i2c_devices,
 				ARRAY_SIZE(eukrea_cpuimx25_i2c_devices));
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index f7b074f..dff82eb 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -38,6 +38,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
+#include <asm/system.h>
 #include <mach/common.h>
 #include <mach/iomux-mx27.h>
 
@@ -48,6 +49,14 @@
 #define OTG_PHY_CS_GPIO (GPIO_PORTF + 17)
 #define SDHC1_IRQ IRQ_GPIOB(25)
 
+#define MOTHERBOARD_BIT2	(GPIO_PORTD + 31)
+#define MOTHERBOARD_BIT1	(GPIO_PORTD + 30)
+#define MOTHERBOARD_BIT0	(GPIO_PORTD + 29)
+
+#define EXPBOARD_BIT2		(GPIO_PORTD + 25)
+#define EXPBOARD_BIT1		(GPIO_PORTD + 27)
+#define EXPBOARD_BIT0		(GPIO_PORTD + 28)
+
 static const int visstrim_m10_pins[] __initconst = {
 	/* UART1 (console) */
 	PE12_PF_UART1_TXD,
@@ -119,6 +128,23 @@
 	PB19_PF_CSI_D7,
 	PB20_PF_CSI_VSYNC,
 	PB21_PF_CSI_HSYNC,
+	/* mother board version */
+	MOTHERBOARD_BIT2 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+	MOTHERBOARD_BIT1 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+	MOTHERBOARD_BIT0 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+	/* expansion board version */
+	EXPBOARD_BIT2 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+	EXPBOARD_BIT1 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+	EXPBOARD_BIT0 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+};
+
+static struct gpio visstrim_m10_version_gpios[] = {
+	{ EXPBOARD_BIT0, GPIOF_IN, "exp-version-0" },
+	{ EXPBOARD_BIT1, GPIOF_IN, "exp-version-1" },
+	{ EXPBOARD_BIT2, GPIOF_IN, "exp-version-2" },
+	{ MOTHERBOARD_BIT0, GPIOF_IN, "mother-version-0" },
+	{ MOTHERBOARD_BIT1, GPIOF_IN, "mother-version-1" },
+	{ MOTHERBOARD_BIT2, GPIOF_IN, "mother-version-2" },
 };
 
 /* Camera */
@@ -152,7 +178,7 @@
 
 static struct mx2_camera_platform_data visstrim_camera = {
 	.flags = MX2_CAMERA_CCIR | MX2_CAMERA_CCIR_INTERLACE |
-			MX2_CAMERA_SWAP16 | MX2_CAMERA_PCLK_SAMPLE_RISING,
+		 MX2_CAMERA_PCLK_SAMPLE_RISING,
 	.clk = 100000,
 };
 
@@ -369,11 +395,40 @@
 	.flags			= IMX_SSI_DMA | IMX_SSI_SYN,
 };
 
+static void __init visstrim_m10_revision(void)
+{
+	int exp_version = 0;
+	int mo_version = 0;
+	int ret;
+
+	ret = gpio_request_array(visstrim_m10_version_gpios,
+				 ARRAY_SIZE(visstrim_m10_version_gpios));
+	if (ret) {
+		pr_err("Failed to request version gpios");
+		return;
+	}
+
+	/* Get expansion board version (negative logic) */
+	exp_version |= !gpio_get_value(EXPBOARD_BIT2) << 2;
+	exp_version |= !gpio_get_value(EXPBOARD_BIT1) << 1;
+	exp_version |= !gpio_get_value(EXPBOARD_BIT0);
+
+	/* Get mother board version (negative logic) */
+	mo_version |= !gpio_get_value(MOTHERBOARD_BIT2) << 2;
+	mo_version |= !gpio_get_value(MOTHERBOARD_BIT1) << 1;
+	mo_version |= !gpio_get_value(MOTHERBOARD_BIT0);
+
+	system_rev = 0x27000;
+	system_rev |= (mo_version << 4);
+	system_rev |= exp_version;
+}
+
 static void __init visstrim_m10_board_init(void)
 {
 	int ret;
 
 	imx27_soc_init();
+	visstrim_m10_revision();
 
 	ret = mxc_gpio_setup_multiple_pins(visstrim_m10_pins,
 			ARRAY_SIZE(visstrim_m10_pins), "VISSTRIM_M10");
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index da6c1d9..3df360a 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -19,6 +19,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <linux/pinctrl/machine.h>
 #include <linux/phy.h>
 #include <linux/micrel_phy.h>
 #include <asm/smp_twd.h>
@@ -77,6 +78,12 @@
 
 static void __init imx6q_init_machine(void)
 {
+	/*
+	 * This should be removed when all imx6q boards have pinctrl
+	 * states for devices defined in device tree.
+	 */
+	pinctrl_provide_dummies();
+
 	if (of_machine_is_compatible("fsl,imx6q-sabrelite"))
 		phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
 					   ksz9021rn_phy_fixup);
diff --git a/arch/arm/mach-imx/mach-mx1ads.c b/arch/arm/mach-imx/mach-mx1ads.c
index 9704608..7274e79 100644
--- a/arch/arm/mach-imx/mach-mx1ads.c
+++ b/arch/arm/mach-imx/mach-mx1ads.c
@@ -134,7 +134,7 @@
 	mx1_clocks_init(32000);
 }
 
-struct sys_timer mx1ads_timer = {
+static struct sys_timer mx1ads_timer = {
 	.init	= mx1ads_timer_init,
 };
 
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index e432d4a..d14bbe9 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -304,8 +304,7 @@
 	imx21_add_mxc_nand(&mx21ads_nand_board_info);
 
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
-	platform_device_register_full(
-			(struct platform_device_info *)&mx21ads_cs8900_devinfo);
+	platform_device_register_full(&mx21ads_cs8900_devinfo);
 }
 
 static void __init mx21ads_timer_init(void)
diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c
index 4d1aab1..4eafdf2 100644
--- a/arch/arm/mach-imx/mach-mx31_3ds.c
+++ b/arch/arm/mach-imx/mach-mx31_3ds.c
@@ -156,6 +156,11 @@
 	MX31_PIN_CSI_VSYNC__CSI_VSYNC,
 	MX31_PIN_CSI_D5__GPIO3_5, /* CMOS PWDN */
 	IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_GPIO), /* CMOS reset */
+	/* SSI */
+	MX31_PIN_STXD4__STXD4,
+	MX31_PIN_SRXD4__SRXD4,
+	MX31_PIN_SCK4__SCK4,
+	MX31_PIN_SFS4__SFS4,
 };
 
 /*
@@ -488,12 +493,23 @@
 };
 
 /* MC13783 */
+static struct mc13xxx_codec_platform_data mx31_3ds_codec = {
+	.dac_ssi_port = MC13783_SSI1_PORT,
+	.adc_ssi_port = MC13783_SSI1_PORT,
+};
+
 static struct mc13xxx_platform_data mc13783_pdata = {
 	.regulators = {
 		.regulators = mx31_3ds_regulators,
 		.num_regulators = ARRAY_SIZE(mx31_3ds_regulators),
 	},
-	.flags  = MC13XXX_USE_TOUCHSCREEN | MC13XXX_USE_RTC,
+	.codec = &mx31_3ds_codec,
+	.flags  = MC13XXX_USE_TOUCHSCREEN | MC13XXX_USE_RTC | MC13XXX_USE_CODEC,
+
+};
+
+static struct imx_ssi_platform_data mx31_3ds_ssi_pdata = {
+	.flags = IMX_SSI_DMA | IMX_SSI_NET,
 };
 
 /* SPI */
@@ -741,6 +757,10 @@
 	}
 
 	mx31_3ds_init_camera();
+
+	imx31_add_imx_ssi(0, &mx31_3ds_ssi_pdata);
+
+	imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
 }
 
 static void __init mx31_3ds_timer_init(void)
diff --git a/arch/arm/mach-imx/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c
index 0abef5f..686c605 100644
--- a/arch/arm/mach-imx/mach-mx31lite.c
+++ b/arch/arm/mach-imx/mach-mx31lite.c
@@ -283,7 +283,7 @@
 	mx31_clocks_init(26000000);
 }
 
-struct sys_timer mx31lite_timer = {
+static struct sys_timer mx31lite_timer = {
 	.init	= mx31lite_timer_init,
 };
 
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index f17a15f..016791f 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -47,6 +47,7 @@
 #include <mach/hardware.h>
 #include <mach/iomux-mx3.h>
 #include <mach/ulpi.h>
+#include <mach/ssi.h>
 
 #include "devices-imx31.h"
 
@@ -102,6 +103,9 @@
 	MX31_PIN_CSPI3_MOSI__MOSI, MX31_PIN_CSPI3_MISO__MISO,
 	MX31_PIN_CSPI3_SCLK__SCLK, MX31_PIN_CSPI3_SPI_RDY__SPI_RDY,
 	MX31_PIN_CSPI2_SS1__CSPI3_SS1,
+	/* SSI */
+	MX31_PIN_STXD4__STXD4, MX31_PIN_SRXD4__SRXD4,
+	MX31_PIN_SCK4__SCK4, MX31_PIN_SFS4__SFS4,
 };
 
 static struct physmap_flash_data mx31moboard_flash_data = {
@@ -276,6 +280,11 @@
 	.b1on_key = KEY_POWER,
 };
 
+static struct mc13xxx_codec_platform_data moboard_codec = {
+	.dac_ssi_port = MC13783_SSI1_PORT,
+	.adc_ssi_port = MC13783_SSI1_PORT,
+};
+
 static struct mc13xxx_platform_data moboard_pmic = {
 	.regulators = {
 		.regulators = moboard_regulators,
@@ -283,7 +292,12 @@
 	},
 	.leds = &moboard_leds,
 	.buttons = &moboard_buttons,
-	.flags = MC13XXX_USE_RTC | MC13XXX_USE_ADC,
+	.codec = &moboard_codec,
+	.flags = MC13XXX_USE_RTC | MC13XXX_USE_ADC | MC13XXX_USE_CODEC,
+};
+
+static struct imx_ssi_platform_data moboard_ssi_pdata = {
+	.flags = IMX_SSI_DMA | IMX_SSI_NET,
 };
 
 static struct spi_board_info moboard_spi_board_info[] __initdata = {
@@ -554,6 +568,10 @@
 
 	moboard_usbh2_init();
 
+	imx31_add_imx_ssi(0, &moboard_ssi_pdata);
+
+	imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
+
 	pm_power_off = mx31moboard_poweroff;
 
 	switch (mx31moboard_baseboard) {
@@ -580,7 +598,7 @@
 	mx31_clocks_init(26000000);
 }
 
-struct sys_timer mx31moboard_timer = {
+static struct sys_timer mx31moboard_timer = {
 	.init	= mx31moboard_timer_init,
 };
 
diff --git a/arch/arm/mach-imx/mach-mx35_3ds.c b/arch/arm/mach-imx/mach-mx35_3ds.c
index 6ae51c6..86284bb 100644
--- a/arch/arm/mach-imx/mach-mx35_3ds.c
+++ b/arch/arm/mach-imx/mach-mx35_3ds.c
@@ -34,6 +34,8 @@
 #include <linux/usb/otg.h>
 
 #include <linux/mtd/physmap.h>
+#include <linux/mfd/mc13892.h>
+#include <linux/regulator/machine.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -253,6 +255,8 @@
 	MX35_PAD_CSI_MCLK__IPU_CSI_MCLK,
 	MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK,
 	MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC,
+	/*PMIC IRQ*/
+	MX35_PAD_GPIO2_0__GPIO2_0,
 };
 
 /*
@@ -317,6 +321,193 @@
 	},
 };
 
+static struct regulator_consumer_supply sw1_consumers[] = {
+	{
+		.supply = "cpu_vcc",
+	}
+};
+
+static struct regulator_consumer_supply vcam_consumers[] = {
+	/* sgtl5000 */
+	REGULATOR_SUPPLY("VDDA", "0-000a"),
+};
+
+static struct regulator_consumer_supply vaudio_consumers[] = {
+	REGULATOR_SUPPLY("cmos_vio", "soc-camera-pdrv.0"),
+};
+
+static struct regulator_init_data sw1_init = {
+	.constraints = {
+		.name = "SW1",
+		.min_uV = 600000,
+		.max_uV = 1375000,
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+		.valid_modes_mask = 0,
+		.always_on = 1,
+		.boot_on = 1,
+	},
+	.num_consumer_supplies = ARRAY_SIZE(sw1_consumers),
+	.consumer_supplies = sw1_consumers,
+};
+
+static struct regulator_init_data sw2_init = {
+	.constraints = {
+		.name = "SW2",
+		.always_on = 1,
+		.boot_on = 1,
+	}
+};
+
+static struct regulator_init_data sw3_init = {
+	.constraints = {
+		.name = "SW3",
+		.always_on = 1,
+		.boot_on = 1,
+	}
+};
+
+static struct regulator_init_data sw4_init = {
+	.constraints = {
+		.name = "SW4",
+		.always_on = 1,
+		.boot_on = 1,
+	}
+};
+
+static struct regulator_init_data viohi_init = {
+	.constraints = {
+		.name = "VIOHI",
+		.boot_on = 1,
+	}
+};
+
+static struct regulator_init_data vusb_init = {
+	.constraints = {
+		.name = "VUSB",
+		.boot_on = 1,
+	}
+};
+
+static struct regulator_init_data vdig_init = {
+	.constraints = {
+		.name = "VDIG",
+		.boot_on = 1,
+	}
+};
+
+static struct regulator_init_data vpll_init = {
+	.constraints = {
+		.name = "VPLL",
+		.boot_on = 1,
+	}
+};
+
+static struct regulator_init_data vusb2_init = {
+	.constraints = {
+		.name = "VUSB2",
+		.boot_on = 1,
+	}
+};
+
+static struct regulator_init_data vvideo_init = {
+	.constraints = {
+		.name = "VVIDEO",
+		.boot_on = 1
+	}
+};
+
+static struct regulator_init_data vaudio_init = {
+	.constraints = {
+		.name = "VAUDIO",
+		.min_uV = 2300000,
+		.max_uV = 3000000,
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+		.boot_on = 1
+	},
+	.num_consumer_supplies = ARRAY_SIZE(vaudio_consumers),
+	.consumer_supplies = vaudio_consumers,
+};
+
+static struct regulator_init_data vcam_init = {
+	.constraints = {
+		.name = "VCAM",
+		.min_uV = 2500000,
+		.max_uV = 3000000,
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+					REGULATOR_CHANGE_MODE,
+		.valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL,
+		.boot_on = 1
+	},
+	.num_consumer_supplies = ARRAY_SIZE(vcam_consumers),
+	.consumer_supplies = vcam_consumers,
+};
+
+static struct regulator_init_data vgen1_init = {
+	.constraints = {
+		.name = "VGEN1",
+	}
+};
+
+static struct regulator_init_data vgen2_init = {
+	.constraints = {
+		.name = "VGEN2",
+		.boot_on = 1,
+	}
+};
+
+static struct regulator_init_data vgen3_init = {
+	.constraints = {
+		.name = "VGEN3",
+	}
+};
+
+static struct mc13xxx_regulator_init_data mx35_3ds_regulators[] = {
+	{ .id = MC13892_SW1, .init_data = &sw1_init },
+	{ .id = MC13892_SW2, .init_data = &sw2_init },
+	{ .id = MC13892_SW3, .init_data = &sw3_init },
+	{ .id = MC13892_SW4, .init_data = &sw4_init },
+	{ .id = MC13892_VIOHI, .init_data = &viohi_init },
+	{ .id = MC13892_VPLL, .init_data = &vpll_init },
+	{ .id = MC13892_VDIG, .init_data = &vdig_init },
+	{ .id = MC13892_VUSB2, .init_data = &vusb2_init },
+	{ .id = MC13892_VVIDEO, .init_data = &vvideo_init },
+	{ .id = MC13892_VAUDIO, .init_data = &vaudio_init },
+	{ .id = MC13892_VCAM, .init_data = &vcam_init },
+	{ .id = MC13892_VGEN1, .init_data = &vgen1_init },
+	{ .id = MC13892_VGEN2, .init_data = &vgen2_init },
+	{ .id = MC13892_VGEN3, .init_data = &vgen3_init },
+	{ .id = MC13892_VUSB, .init_data = &vusb_init },
+};
+
+static struct mc13xxx_platform_data mx35_3ds_mc13892_data = {
+	.flags = MC13XXX_USE_RTC | MC13XXX_USE_TOUCHSCREEN,
+	.regulators = {
+		.num_regulators = ARRAY_SIZE(mx35_3ds_regulators),
+		.regulators = mx35_3ds_regulators,
+	},
+};
+
+#define GPIO_PMIC_INT IMX_GPIO_NR(2, 0)
+
+static struct i2c_board_info mx35_3ds_i2c_mc13892 = {
+
+	I2C_BOARD_INFO("mc13892", 0x08),
+	.platform_data = &mx35_3ds_mc13892_data,
+	.irq = IMX_GPIO_TO_IRQ(GPIO_PMIC_INT),
+};
+
+static void __init imx35_3ds_init_mc13892(void)
+{
+	int ret = gpio_request_one(GPIO_PMIC_INT, GPIOF_DIR_IN, "pmic irq");
+
+	if (ret) {
+		pr_err("failed to get pmic irq: %d\n", ret);
+		return;
+	}
+
+	i2c_register_board_info(0, &mx35_3ds_i2c_mc13892, 1);
+}
+
 static int mx35_3ds_otg_init(struct platform_device *pdev)
 {
 	return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERNAL_PHY);
@@ -412,6 +603,8 @@
 	imx35_fb_pdev = imx35_add_mx3_sdc_fb(&mx3fb_pdata);
 	mx35_3ds_lcd.dev.parent = &imx35_fb_pdev->dev;
 	platform_device_register(&mx35_3ds_lcd);
+
+	imx35_3ds_init_mc13892();
 }
 
 static void __init mx35pdk_timer_init(void)
@@ -419,7 +612,7 @@
 	mx35_clocks_init();
 }
 
-struct sys_timer mx35pdk_timer = {
+static struct sys_timer mx35pdk_timer = {
 	.init	= mx35pdk_timer_init,
 };
 
diff --git a/arch/arm/mach-imx/mach-mx51_efikamx.c b/arch/arm/mach-imx/mach-mx51_efikamx.c
index 586e9f8..86e96ef 100644
--- a/arch/arm/mach-imx/mach-mx51_efikamx.c
+++ b/arch/arm/mach-imx/mach-mx51_efikamx.c
@@ -284,8 +284,7 @@
 	.init = mx51_efikamx_timer_init,
 };
 
-MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop")
-	/* Maintainer: Amit Kucheria <amit.kucheria@linaro.org> */
+MACHINE_START(MX51_EFIKAMX, "Genesi Efika MX (Smarttop)")
 	.atag_offset = 0x100,
 	.map_io = mx51_map_io,
 	.init_early = imx51_init_early,
diff --git a/arch/arm/mach-imx/mach-mx51_efikasb.c b/arch/arm/mach-imx/mach-mx51_efikasb.c
index 24aded9..88f837a 100644
--- a/arch/arm/mach-imx/mach-mx51_efikasb.c
+++ b/arch/arm/mach-imx/mach-mx51_efikasb.c
@@ -280,7 +280,7 @@
 	.init	= mx51_efikasb_timer_init,
 };
 
-MACHINE_START(MX51_EFIKASB, "Genesi Efika Smartbook")
+MACHINE_START(MX51_EFIKASB, "Genesi Efika MX (Smartbook)")
 	.atag_offset = 0x100,
 	.map_io = mx51_map_io,
 	.init_early = imx51_init_early,
diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c
index 5fddf94..10c9795 100644
--- a/arch/arm/mach-imx/mach-pcm037.c
+++ b/arch/arm/mach-imx/mach-pcm037.c
@@ -683,7 +683,7 @@
 	mx31_clocks_init(26000000);
 }
 
-struct sys_timer pcm037_timer = {
+static struct sys_timer pcm037_timer = {
 	.init	= pcm037_timer_init,
 };
 
diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c
index 237474f..73585f5 100644
--- a/arch/arm/mach-imx/mach-pcm043.c
+++ b/arch/arm/mach-imx/mach-pcm043.c
@@ -399,7 +399,7 @@
 	mx35_clocks_init();
 }
 
-struct sys_timer pcm043_timer = {
+static struct sys_timer pcm043_timer = {
 	.init	= pcm043_timer_init,
 };
 
diff --git a/arch/arm/mach-imx/mach-vpr200.c b/arch/arm/mach-imx/mach-vpr200.c
index 033257e..add8c69 100644
--- a/arch/arm/mach-imx/mach-vpr200.c
+++ b/arch/arm/mach-imx/mach-vpr200.c
@@ -310,7 +310,7 @@
 	mx35_clocks_init();
 }
 
-struct sys_timer vpr200_timer = {
+static struct sys_timer vpr200_timer = {
 	.init	= vpr200_timer_init,
 };
 
diff --git a/arch/arm/mach-imx/mm-imx1.c b/arch/arm/mach-imx/mm-imx1.c
index 2bded59..fcafd3d 100644
--- a/arch/arm/mach-imx/mm-imx1.c
+++ b/arch/arm/mach-imx/mm-imx1.c
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/pinctrl/machine.h>
 
 #include <asm/mach/map.h>
 
@@ -58,4 +59,5 @@
 						MX1_GPIO_INT_PORTC, 0);
 	mxc_register_gpio("imx1-gpio", 3, MX1_GPIO4_BASE_ADDR, SZ_256,
 						MX1_GPIO_INT_PORTD, 0);
+	pinctrl_provide_dummies();
 }
diff --git a/arch/arm/mach-imx/mm-imx21.c b/arch/arm/mach-imx/mm-imx21.c
index 14d540e..5f43905 100644
--- a/arch/arm/mach-imx/mm-imx21.c
+++ b/arch/arm/mach-imx/mm-imx21.c
@@ -20,6 +20,7 @@
 
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/pinctrl/machine.h>
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/devices-common.h>
@@ -88,6 +89,7 @@
 	mxc_register_gpio("imx21-gpio", 4, MX21_GPIO5_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0);
 	mxc_register_gpio("imx21-gpio", 5, MX21_GPIO6_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0);
 
+	pinctrl_provide_dummies();
 	imx_add_imx_dma();
 	platform_device_register_simple("imx21-audmux", 0, imx21_audmux_res,
 					ARRAY_SIZE(imx21_audmux_res));
diff --git a/arch/arm/mach-imx/mm-imx25.c b/arch/arm/mach-imx/mm-imx25.c
index 153b457..6ff3714 100644
--- a/arch/arm/mach-imx/mm-imx25.c
+++ b/arch/arm/mach-imx/mm-imx25.c
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/pinctrl/machine.h>
 
 #include <asm/pgtable.h>
 #include <asm/mach/map.h>
@@ -95,6 +96,7 @@
 	mxc_register_gpio("imx31-gpio", 2, MX25_GPIO3_BASE_ADDR, SZ_16K, MX25_INT_GPIO3, 0);
 	mxc_register_gpio("imx31-gpio", 3, MX25_GPIO4_BASE_ADDR, SZ_16K, MX25_INT_GPIO4, 0);
 
+	pinctrl_provide_dummies();
 	/* i.mx25 has the i.mx35 type sdma */
 	imx_add_imx_sdma("imx35-sdma", MX25_SDMA_BASE_ADDR, MX25_INT_SDMA, &imx25_sdma_pdata);
 	/* i.mx25 has the i.mx31 type audmux */
diff --git a/arch/arm/mach-imx/mm-imx27.c b/arch/arm/mach-imx/mm-imx27.c
index 8cb3f5e..2566255 100644
--- a/arch/arm/mach-imx/mm-imx27.c
+++ b/arch/arm/mach-imx/mm-imx27.c
@@ -20,6 +20,7 @@
 
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/pinctrl/machine.h>
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/devices-common.h>
@@ -89,6 +90,7 @@
 	mxc_register_gpio("imx21-gpio", 4, MX27_GPIO5_BASE_ADDR, SZ_256, MX27_INT_GPIO, 0);
 	mxc_register_gpio("imx21-gpio", 5, MX27_GPIO6_BASE_ADDR, SZ_256, MX27_INT_GPIO, 0);
 
+	pinctrl_provide_dummies();
 	imx_add_imx_dma();
 	/* imx27 has the imx21 type audmux */
 	platform_device_register_simple("imx21-audmux", 0, imx27_audmux_res,
diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c
index 7412738..9128d15 100644
--- a/arch/arm/mach-imx/mm-imx3.c
+++ b/arch/arm/mach-imx/mm-imx3.c
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/pinctrl/machine.h>
 
 #include <asm/pgtable.h>
 #include <asm/system_misc.h>
@@ -267,6 +268,7 @@
 	mxc_register_gpio("imx31-gpio", 1, MX35_GPIO2_BASE_ADDR, SZ_16K, MX35_INT_GPIO2, 0);
 	mxc_register_gpio("imx31-gpio", 2, MX35_GPIO3_BASE_ADDR, SZ_16K, MX35_INT_GPIO3, 0);
 
+	pinctrl_provide_dummies();
 	if (to_version == 1) {
 		strncpy(imx35_sdma_pdata.fw_name, "sdma-imx35-to1.bin",
 			strlen(imx35_sdma_pdata.fw_name));
diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c
index e10f391..ba91e6b 100644
--- a/arch/arm/mach-imx/mm-imx5.c
+++ b/arch/arm/mach-imx/mm-imx5.c
@@ -14,6 +14,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/clk.h>
+#include <linux/pinctrl/machine.h>
 
 #include <asm/system_misc.h>
 #include <asm/mach/map.h>
@@ -223,6 +224,7 @@
 	mxc_register_gpio("imx31-gpio", 5, MX53_GPIO6_BASE_ADDR, SZ_16K, MX53_INT_GPIO6_LOW, MX53_INT_GPIO6_HIGH);
 	mxc_register_gpio("imx31-gpio", 6, MX53_GPIO7_BASE_ADDR, SZ_16K, MX53_INT_GPIO7_LOW, MX53_INT_GPIO7_HIGH);
 
+	pinctrl_provide_dummies();
 	/* i.mx53 has the i.mx35 type sdma */
 	imx_add_imx_sdma("imx35-sdma", MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata);
 
diff --git a/arch/arm/mach-ixp2000/Kconfig b/arch/arm/mach-ixp2000/Kconfig
deleted file mode 100644
index 08d2707..0000000
--- a/arch/arm/mach-ixp2000/Kconfig
+++ /dev/null
@@ -1,72 +0,0 @@
-
-if ARCH_IXP2000
-
-config ARCH_SUPPORTS_BIG_ENDIAN
-	bool
-	default y
-
-menu "Intel IXP2400/2800 Implementation Options"
-
-comment "IXP2400/2800 Platforms"
-
-config ARCH_ENP2611
-	bool "Support Radisys ENP-2611"
-	help
-	  Say 'Y' here if you want your kernel to support the Radisys
-	  ENP2611 PCI network processing card. For more information on
-	  this card, see <file:Documentation/arm/IXP2000>.
-
-config ARCH_IXDP2400
-	bool "Support Intel IXDP2400"
-	help
-	  Say 'Y' here if you want your kernel to support the Intel
-	  IXDP2400 reference platform. For more information on
-	  this platform, see <file:Documentation/arm/IXP2000>.
-
-config ARCH_IXDP2800
-	bool "Support Intel IXDP2800"
-	help
-	  Say 'Y' here if you want your kernel to support the Intel
-	  IXDP2800 reference platform. For more information on
-	  this platform, see <file:Documentation/arm/IXP2000>.
-
-config ARCH_IXDP2X00
-	bool
-	depends on ARCH_IXDP2400 || ARCH_IXDP2800
-	default y	
-
-config ARCH_IXDP2401
-	bool "Support Intel IXDP2401"
-	help
-	  Say 'Y' here if you want your kernel to support the Intel
-	  IXDP2401 reference platform. For more information on
-	  this platform, see <file:Documentation/arm/IXP2000>.
-
-config ARCH_IXDP2801
-	bool "Support Intel IXDP2801 and IXDP28x5"
-	help
-	  Say 'Y' here if you want your kernel to support the Intel
-	  IXDP2801/2805/2855 reference platforms. For more information on
-	  this platform, see <file:Documentation/arm/IXP2000>.
-
-config MACH_IXDP28X5
-	bool
-	depends on ARCH_IXDP2801
-	default y
-
-config ARCH_IXDP2X01
-	bool
-	depends on ARCH_IXDP2401 || ARCH_IXDP2801
-	default y	
-
-config IXP2000_SUPPORT_BROKEN_PCI_IO
-	bool "Support broken PCI I/O on older IXP2000s"
-	default y
-	help
-	  Say 'N' here if you only intend to run your kernel on an
-	  IXP2000 B0 or later model and do not need the PCI I/O
-	  byteswap workaround.  Say 'Y' otherwise.
-
-endmenu
-
-endif
diff --git a/arch/arm/mach-ixp2000/Makefile b/arch/arm/mach-ixp2000/Makefile
deleted file mode 100644
index 1e6139d..0000000
--- a/arch/arm/mach-ixp2000/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-obj-y			:= core.o pci.o
-obj-m			:=
-obj-n			:=
-obj-			:=
-
-obj-$(CONFIG_ARCH_ENP2611)	+= enp2611.o
-obj-$(CONFIG_ARCH_IXDP2400)	+= ixdp2400.o
-obj-$(CONFIG_ARCH_IXDP2800)	+= ixdp2800.o
-obj-$(CONFIG_ARCH_IXDP2X00)	+= ixdp2x00.o
-obj-$(CONFIG_ARCH_IXDP2X01)	+= ixdp2x01.o
-
diff --git a/arch/arm/mach-ixp2000/Makefile.boot b/arch/arm/mach-ixp2000/Makefile.boot
deleted file mode 100644
index 9c7af91..0000000
--- a/arch/arm/mach-ixp2000/Makefile.boot
+++ /dev/null
@@ -1,3 +0,0 @@
-   zreladdr-y	+= 0x00008000
-params_phys-y	:= 0x00000100
-
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
deleted file mode 100644
index f214cdf..0000000
--- a/arch/arm/mach-ixp2000/core.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/core.c
- *
- * Common routines used by all IXP2400/2800 based platforms.
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2004 (C) MontaVista Software, Inc. 
- *
- * Based on work Copyright (C) 2002-2003 Intel Corporation
- * 
- * 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/gpio.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/serial_8250.h>
-#include <linux/mm.h>
-#include <linux/export.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
-
-#include <mach/gpio-ixp2000.h>
-
-static DEFINE_SPINLOCK(ixp2000_slowport_lock);
-static unsigned long ixp2000_slowport_irq_flags;
-
-/*************************************************************************
- * Slowport access routines
- *************************************************************************/
-void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg)
-{
-	spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags);
-
-	old_cfg->CCR = *IXP2000_SLOWPORT_CCR;
-	old_cfg->WTC = *IXP2000_SLOWPORT_WTC2;
-	old_cfg->RTC = *IXP2000_SLOWPORT_RTC2;
-	old_cfg->PCR = *IXP2000_SLOWPORT_PCR;
-	old_cfg->ADC = *IXP2000_SLOWPORT_ADC;
-
-	ixp2000_reg_write(IXP2000_SLOWPORT_CCR, new_cfg->CCR);
-	ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC);
-	ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC);
-	ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR);
-	ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, new_cfg->ADC);
-}
-
-void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
-{
-	ixp2000_reg_write(IXP2000_SLOWPORT_CCR, old_cfg->CCR);
-	ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC);
-	ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC);
-	ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR);
-	ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, old_cfg->ADC);
-
-	spin_unlock_irqrestore(&ixp2000_slowport_lock, 
-					ixp2000_slowport_irq_flags);
-}
-
-/*************************************************************************
- * Chip specific mappings shared by all IXP2000 systems
- *************************************************************************/
-static struct map_desc ixp2000_io_desc[] __initdata = {
-	{
-		.virtual	= IXP2000_CAP_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_CAP_PHYS_BASE),
-		.length		= IXP2000_CAP_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= IXP2000_INTCTL_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE),
-		.length		= IXP2000_INTCTL_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= IXP2000_PCI_CREG_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE),
-		.length		= IXP2000_PCI_CREG_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= IXP2000_PCI_CSR_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE),
-		.length		= IXP2000_PCI_CSR_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= IXP2000_MSF_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_MSF_PHYS_BASE),
-		.length		= IXP2000_MSF_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= IXP2000_SCRATCH_RING_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE),
-		.length		= IXP2000_SCRATCH_RING_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= IXP2000_SRAM0_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE),
-		.length		= IXP2000_SRAM0_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= IXP2000_PCI_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE),
-		.length		= IXP2000_PCI_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= IXP2000_PCI_CFG0_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE),
-		.length		= IXP2000_PCI_CFG0_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= IXP2000_PCI_CFG1_VIRT_BASE,
-		.pfn		= __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE),
-		.length		= IXP2000_PCI_CFG1_SIZE,
-		.type		= MT_DEVICE,
-	}
-};
-
-void __init ixp2000_map_io(void)
-{
-	iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
-
-	/* Set slowport to 8-bit mode.  */
-	ixp2000_reg_wrb(IXP2000_SLOWPORT_FRM, 1);
-}
-
-
-/*************************************************************************
- * Serial port support for IXP2000
- *************************************************************************/
-static struct plat_serial8250_port ixp2000_serial_port[] = {
-	{
-		.mapbase	= IXP2000_UART_PHYS_BASE,
-		.membase	= (char *)(IXP2000_UART_VIRT_BASE + 3),
-		.irq		= IRQ_IXP2000_UART,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= 50000000,
-	},
-	{ },
-};
-
-static struct resource ixp2000_uart_resource = {
-	.start		= IXP2000_UART_PHYS_BASE,
-	.end		= IXP2000_UART_PHYS_BASE + 0x1f,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device ixp2000_serial_device = {
-	.name		= "serial8250",
-	.id		= PLAT8250_DEV_PLATFORM,
-	.dev		= {
-		.platform_data		= ixp2000_serial_port,
-	},
-	.num_resources	= 1,
-	.resource	= &ixp2000_uart_resource,
-};
-
-void __init ixp2000_uart_init(void)
-{
-	platform_device_register(&ixp2000_serial_device);
-}
-
-
-/*************************************************************************
- * Timer-tick functions for IXP2000
- *************************************************************************/
-static unsigned ticks_per_jiffy;
-static unsigned ticks_per_usec;
-static unsigned next_jiffy_time;
-static volatile unsigned long *missing_jiffy_timer_csr;
-
-unsigned long ixp2000_gettimeoffset (void)
-{
- 	unsigned long offset;
-
-	offset = next_jiffy_time - *missing_jiffy_timer_csr;
-
-	return offset / ticks_per_usec;
-}
-
-static irqreturn_t ixp2000_timer_interrupt(int irq, void *dev_id)
-{
-	/* clear timer 1 */
-	ixp2000_reg_wrb(IXP2000_T1_CLR, 1);
-
-	while ((signed long)(next_jiffy_time - *missing_jiffy_timer_csr)
-							>= ticks_per_jiffy) {
-		timer_tick();
-		next_jiffy_time -= ticks_per_jiffy;
-	}
-
-	return IRQ_HANDLED;
-}
-
-static struct irqaction ixp2000_timer_irq = {
-	.name		= "IXP2000 Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-	.handler	= ixp2000_timer_interrupt,
-};
-
-void __init ixp2000_init_time(unsigned long tick_rate)
-{
-	ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
-	ticks_per_usec = tick_rate / 1000000;
-
-	/*
-	 * We use timer 1 as our timer interrupt.
-	 */
-	ixp2000_reg_write(IXP2000_T1_CLR, 0);
-	ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1);
-	ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7));
-
-	/*
-	 * We use a second timer as a monotonic counter for tracking
-	 * missed jiffies.  The IXP2000 has four timers, but if we're
-	 * on an A-step IXP2800, timer 2 and 3 don't work, so on those
-	 * chips we use timer 4.  Timer 4 is the only timer that can
-	 * be used for the watchdog, so we use timer 2 if we're on a
-	 * non-buggy chip.
-	 */
-	if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
-		printk(KERN_INFO "Enabling IXP2800 erratum #25 workaround\n");
-
-		ixp2000_reg_write(IXP2000_T4_CLR, 0);
-		ixp2000_reg_write(IXP2000_T4_CLD, -1);
-		ixp2000_reg_wrb(IXP2000_T4_CTL, (1 << 7));
-		missing_jiffy_timer_csr = IXP2000_T4_CSR;
-	} else {
-		ixp2000_reg_write(IXP2000_T2_CLR, 0);
-		ixp2000_reg_write(IXP2000_T2_CLD, -1);
-		ixp2000_reg_wrb(IXP2000_T2_CTL, (1 << 7));
-		missing_jiffy_timer_csr = IXP2000_T2_CSR;
-	}
- 	next_jiffy_time = 0xffffffff;
-
-	/* register for interrupt */
-	setup_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq);
-}
-
-/*************************************************************************
- * GPIO helpers
- *************************************************************************/
-static unsigned long GPIO_IRQ_falling_edge;
-static unsigned long GPIO_IRQ_rising_edge;
-static unsigned long GPIO_IRQ_level_low;
-static unsigned long GPIO_IRQ_level_high;
-
-static void update_gpio_int_csrs(void)
-{
-	ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
-	ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
-	ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
-	ixp2000_reg_wrb(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
-}
-
-void gpio_line_config(int line, int direction)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	if (direction == GPIO_OUT) {
-		/* if it's an output, it ain't an interrupt anymore */
-		GPIO_IRQ_falling_edge &= ~(1 << line);
-		GPIO_IRQ_rising_edge &= ~(1 << line);
-		GPIO_IRQ_level_low &= ~(1 << line);
-		GPIO_IRQ_level_high &= ~(1 << line);
-		update_gpio_int_csrs();
-
-		ixp2000_reg_wrb(IXP2000_GPIO_PDSR, 1 << line);
-	} else if (direction == GPIO_IN) {
-		ixp2000_reg_wrb(IXP2000_GPIO_PDCR, 1 << line);
-	}
-	local_irq_restore(flags);
-}
-EXPORT_SYMBOL(gpio_line_config);
-
-
-/*************************************************************************
- * IRQ handling IXP2000
- *************************************************************************/
-static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irq_desc *desc)
-{                               
-	int i;
-	unsigned long status = *IXP2000_GPIO_INST;
-		   
-	for (i = 0; i <= 7; i++) {
-		if (status & (1<<i)) {
-			generic_handle_irq(i + IRQ_IXP2000_GPIO0);
-		}
-	}
-}
-
-static int ixp2000_GPIO_irq_type(struct irq_data *d, unsigned int type)
-{
-	int line = d->irq - IRQ_IXP2000_GPIO0;
-
-	/*
-	 * First, configure this GPIO line as an input.
-	 */
-	ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
-
-	/*
-	 * Then, set the proper trigger type.
-	 */
-	if (type & IRQ_TYPE_EDGE_FALLING)
-		GPIO_IRQ_falling_edge |= 1 << line;
-	else
-		GPIO_IRQ_falling_edge &= ~(1 << line);
-	if (type & IRQ_TYPE_EDGE_RISING)
-		GPIO_IRQ_rising_edge |= 1 << line;
-	else
-		GPIO_IRQ_rising_edge &= ~(1 << line);
-	if (type & IRQ_TYPE_LEVEL_LOW)
-		GPIO_IRQ_level_low |= 1 << line;
-	else
-		GPIO_IRQ_level_low &= ~(1 << line);
-	if (type & IRQ_TYPE_LEVEL_HIGH)
-		GPIO_IRQ_level_high |= 1 << line;
-	else
-		GPIO_IRQ_level_high &= ~(1 << line);
-	update_gpio_int_csrs();
-
-	return 0;
-}
-
-static void ixp2000_GPIO_irq_mask_ack(struct irq_data *d)
-{
-	unsigned int irq = d->irq;
-
-	ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
-
-	ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
-	ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
-	ixp2000_reg_wrb(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
-}
-
-static void ixp2000_GPIO_irq_mask(struct irq_data *d)
-{
-	unsigned int irq = d->irq;
-
-	ixp2000_reg_wrb(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
-}
-
-static void ixp2000_GPIO_irq_unmask(struct irq_data *d)
-{
-	unsigned int irq = d->irq;
-
-	ixp2000_reg_write(IXP2000_GPIO_INSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
-}
-
-static struct irq_chip ixp2000_GPIO_irq_chip = {
-	.irq_ack	= ixp2000_GPIO_irq_mask_ack,
-	.irq_mask	= ixp2000_GPIO_irq_mask,
-	.irq_unmask	= ixp2000_GPIO_irq_unmask,
-	.irq_set_type	= ixp2000_GPIO_irq_type,
-};
-
-static void ixp2000_pci_irq_mask(struct irq_data *d)
-{
-	unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
-	if (d->irq == IRQ_IXP2000_PCIA)
-		ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26)));
-	else if (d->irq == IRQ_IXP2000_PCIB)
-		ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27)));
-}
-
-static void ixp2000_pci_irq_unmask(struct irq_data *d)
-{
-	unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
-	if (d->irq == IRQ_IXP2000_PCIA)
-		ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 26)));
-	else if (d->irq == IRQ_IXP2000_PCIB)
-		ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 27)));
-}
-
-/*
- * Error interrupts. These are used extensively by the microengine drivers
- */
-static void ixp2000_err_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-	int i;
-	unsigned long status = *IXP2000_IRQ_ERR_STATUS;
-
-	for(i = 31; i >= 0; i--) {
-		if(status & (1 << i)) {
-			generic_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i);
-		}
-	}
-}
-
-static void ixp2000_err_irq_mask(struct irq_data *d)
-{
-	ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_CLR,
-			(1 << (d->irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
-}
-
-static void ixp2000_err_irq_unmask(struct irq_data *d)
-{
-	ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_SET,
-			(1 << (d->irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
-}
-
-static struct irq_chip ixp2000_err_irq_chip = {
-	.irq_ack	= ixp2000_err_irq_mask,
-	.irq_mask	= ixp2000_err_irq_mask,
-	.irq_unmask	= ixp2000_err_irq_unmask
-};
-
-static struct irq_chip ixp2000_pci_irq_chip = {
-	.irq_ack	= ixp2000_pci_irq_mask,
-	.irq_mask	= ixp2000_pci_irq_mask,
-	.irq_unmask	= ixp2000_pci_irq_unmask
-};
-
-static void ixp2000_irq_mask(struct irq_data *d)
-{
-	ixp2000_reg_wrb(IXP2000_IRQ_ENABLE_CLR, (1 << d->irq));
-}
-
-static void ixp2000_irq_unmask(struct irq_data *d)
-{
-	ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << d->irq));
-}
-
-static struct irq_chip ixp2000_irq_chip = {
-	.irq_ack	= ixp2000_irq_mask,
-	.irq_mask	= ixp2000_irq_mask,
-	.irq_unmask	= ixp2000_irq_unmask
-};
-
-void __init ixp2000_init_irq(void)
-{
-	int irq;
-
-	/*
-	 * Mask all sources
-	 */
-	ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, 0xffffffff);
-	ixp2000_reg_write(IXP2000_FIQ_ENABLE_CLR, 0xffffffff);
-
-	/* clear all GPIO edge/level detects */
-	ixp2000_reg_write(IXP2000_GPIO_REDR, 0);
-	ixp2000_reg_write(IXP2000_GPIO_FEDR, 0);
-	ixp2000_reg_write(IXP2000_GPIO_LSHR, 0);
-	ixp2000_reg_write(IXP2000_GPIO_LSLR, 0);
-	ixp2000_reg_write(IXP2000_GPIO_INCR, -1);
-
-	/* clear PCI interrupt sources */
-	ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, 0);
-
-	/*
-	 * Certain bits in the IRQ status register of the 
-	 * IXP2000 are reserved. Instead of trying to map
-	 * things non 1:1 from bit position to IRQ number,
-	 * we mark the reserved IRQs as invalid. This makes
-	 * our mask/unmask code much simpler.
-	 */
-	for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) {
-		if ((1 << irq) & IXP2000_VALID_IRQ_MASK) {
-			irq_set_chip_and_handler(irq, &ixp2000_irq_chip,
-						 handle_level_irq);
-			set_irq_flags(irq, IRQF_VALID);
-		} else set_irq_flags(irq, 0);
-	}
-
-	for (irq = IRQ_IXP2000_DRAM0_MIN_ERR; irq <= IRQ_IXP2000_SP_INT; irq++) {
-		if((1 << (irq - IRQ_IXP2000_DRAM0_MIN_ERR)) &
-				IXP2000_VALID_ERR_IRQ_MASK) {
-			irq_set_chip_and_handler(irq, &ixp2000_err_irq_chip,
-						 handle_level_irq);
-			set_irq_flags(irq, IRQF_VALID);
-		}
-		else
-			set_irq_flags(irq, 0);
-	}
-	irq_set_chained_handler(IRQ_IXP2000_ERRSUM, ixp2000_err_irq_handler);
-
-	for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) {
-		irq_set_chip_and_handler(irq, &ixp2000_GPIO_irq_chip,
-					 handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-	irq_set_chained_handler(IRQ_IXP2000_GPIO, ixp2000_GPIO_irq_handler);
-
-	/*
-	 * Enable PCI irqs.  The actual PCI[AB] decoding is done in
-	 * entry-macro.S, so we don't need a chained handler for the
-	 * PCI interrupt source.
-	 */
-	ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << IRQ_IXP2000_PCI));
-	for (irq = IRQ_IXP2000_PCIA; irq <= IRQ_IXP2000_PCIB; irq++) {
-		irq_set_chip_and_handler(irq, &ixp2000_pci_irq_chip,
-					 handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-}
-
-void ixp2000_restart(char mode, const char *cmd)
-{
-	ixp2000_reg_wrb(IXP2000_RESET0, RSTALL);
-}
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
deleted file mode 100644
index 73df2f6..0000000
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/enp2611.c
- *
- * Radisys ENP-2611 support.
- *
- * Created 2004 by Lennert Buytenhek from the ixdp2x01 code.  The
- * original version carries the following notices:
- *
- * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002-2003 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-
-/*************************************************************************
- * ENP-2611 timer tick configuration
- *************************************************************************/
-static void __init enp2611_timer_init(void)
-{
-	ixp2000_init_time(50 * 1000 * 1000);
-}
-
-static struct sys_timer enp2611_timer = {
-	.init		= enp2611_timer_init,
-	.offset		= ixp2000_gettimeoffset,
-};
-
-
-/*************************************************************************
- * ENP-2611 I/O
- *************************************************************************/
-static struct map_desc enp2611_io_desc[] __initdata = {
-	{
-		.virtual	= ENP2611_CALEB_VIRT_BASE,
-		.pfn		= __phys_to_pfn(ENP2611_CALEB_PHYS_BASE),
-		.length		= ENP2611_CALEB_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= ENP2611_PM3386_0_VIRT_BASE,
-		.pfn		= __phys_to_pfn(ENP2611_PM3386_0_PHYS_BASE),
-		.length		= ENP2611_PM3386_0_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= ENP2611_PM3386_1_VIRT_BASE,
-		.pfn		= __phys_to_pfn(ENP2611_PM3386_1_PHYS_BASE),
-		.length		= ENP2611_PM3386_1_SIZE,
-		.type		= MT_DEVICE,
-	}
-};
-
-void __init enp2611_map_io(void)
-{
-	ixp2000_map_io();
-	iotable_init(enp2611_io_desc, ARRAY_SIZE(enp2611_io_desc));
-}
-
-
-/*************************************************************************
- * ENP-2611 PCI
- *************************************************************************/
-static int enp2611_pci_setup(int nr, struct pci_sys_data *sys)
-{
-	sys->mem_offset = 0xe0000000;
-	ixp2000_pci_setup(nr, sys);
-	return 1;
-}
-
-static void __init enp2611_pci_preinit(void)
-{
-	ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00100000);
-	ixp2000_pci_preinit();
-	pcibios_setup("firmware");
-}
-
-static inline int enp2611_pci_valid_device(struct pci_bus *bus,
-						unsigned int devfn)
-{
-	/* The 82559 ethernet controller appears at both PCI:1:0:0 and
-	 * PCI:1:2:0, so let's pretend the second one isn't there.
-	 */
-	if (bus->number == 0x01 && devfn == 0x10)
-		return 0;
-
-	return 1;
-}
-
-static int enp2611_pci_read_config(struct pci_bus *bus, unsigned int devfn,
-					int where, int size, u32 *value)
-{
-	if (enp2611_pci_valid_device(bus, devfn))
-		return ixp2000_pci_read_config(bus, devfn, where, size, value);
-
-	return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-static int enp2611_pci_write_config(struct pci_bus *bus, unsigned int devfn,
-					int where, int size, u32 value)
-{
-	if (enp2611_pci_valid_device(bus, devfn))
-		return ixp2000_pci_write_config(bus, devfn, where, size, value);
-
-	return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-static struct pci_ops enp2611_pci_ops = {
-	.read   = enp2611_pci_read_config,
-	.write  = enp2611_pci_write_config
-};
-
-static int __init enp2611_pci_map_irq(const struct pci_dev *dev, u8 slot,
-	u8 pin)
-{
-	int irq;
-
-	if (dev->bus->number == 0 && PCI_SLOT(dev->devfn) == 0) {
-		/* IXP2400. */
-		irq = IRQ_IXP2000_PCIA;
-	} else if (dev->bus->number == 0 && PCI_SLOT(dev->devfn) == 1) {
-		/* 21555 non-transparent bridge.  */
-		irq = IRQ_IXP2000_PCIB;
-	} else if (dev->bus->number == 0 && PCI_SLOT(dev->devfn) == 4) {
-		/* PCI2050B transparent bridge.  */
-		irq = -1;
-	} else if (dev->bus->number == 1 && PCI_SLOT(dev->devfn) == 0) {
-		/* 82559 ethernet.  */
-		irq = IRQ_IXP2000_PCIA;
-	} else if (dev->bus->number == 1 && PCI_SLOT(dev->devfn) == 1) {
-		/* SPI-3 option board.  */
-		irq = IRQ_IXP2000_PCIB;
-	} else {
-		printk(KERN_ERR "enp2611_pci_map_irq() called for unknown "
-				"device PCI:%d:%d:%d\n", dev->bus->number,
-				PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-		irq = -1;
-	}
-
-	return irq;
-}
-
-struct hw_pci enp2611_pci __initdata = {
-	.nr_controllers	= 1,
-	.ops		= &enp2611_pci_ops,
-	.setup		= enp2611_pci_setup,
-	.preinit	= enp2611_pci_preinit,
-	.map_irq	= enp2611_pci_map_irq,
-};
-
-int __init enp2611_pci_init(void)
-{
-	if (machine_is_enp2611())
-		pci_common_init(&enp2611_pci);
-
-	return 0;
-}
-
-subsys_initcall(enp2611_pci_init);
-
-
-/*************************************************************************
- * ENP-2611 Machine Initialization
- *************************************************************************/
-static struct flash_platform_data enp2611_flash_platform_data = {
-	.map_name	= "cfi_probe",
-	.width		= 1,
-};
-
-static struct ixp2000_flash_data enp2611_flash_data = {
-	.platform_data	= &enp2611_flash_platform_data,
-	.nr_banks	= 1
-};
-
-static struct resource enp2611_flash_resource = {
-	.start		= 0xc4000000,
-	.end		= 0xc4000000 + 0x00ffffff,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device enp2611_flash = {
-	.name		= "IXP2000-Flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data = &enp2611_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &enp2611_flash_resource,
-};
-
-static struct ixp2000_i2c_pins enp2611_i2c_gpio_pins = {
-	.sda_pin	= ENP2611_GPIO_SDA,
-	.scl_pin	= ENP2611_GPIO_SCL,
-};
-
-static struct platform_device enp2611_i2c_controller = {
-	.name		= "IXP2000-I2C",
-	.id		= 0,
-	.dev		= {
-		.platform_data = &enp2611_i2c_gpio_pins
-	},
-	.num_resources	= 0
-};
-
-static struct platform_device *enp2611_devices[] __initdata = {
-	&enp2611_flash,
-	&enp2611_i2c_controller
-};
-
-static void __init enp2611_init_machine(void)
-{
-	platform_add_devices(enp2611_devices, ARRAY_SIZE(enp2611_devices));
-	ixp2000_uart_init();
-}
-
-
-MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
-	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.atag_offset	= 0x100,
-	.map_io		= enp2611_map_io,
-	.init_irq	= ixp2000_init_irq,
-	.timer		= &enp2611_timer,
-	.init_machine	= enp2611_init_machine,
-	.restart	= ixp2000_restart,
-MACHINE_END
-
-
diff --git a/arch/arm/mach-ixp2000/include/mach/debug-macro.S b/arch/arm/mach-ixp2000/include/mach/debug-macro.S
deleted file mode 100644
index bdd3ccd..0000000
--- a/arch/arm/mach-ixp2000/include/mach/debug-macro.S
+++ /dev/null
@@ -1,25 +0,0 @@
-/* arch/arm/mach-ixp2000/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * 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.
- *
-*/
-
-		.macro  addruart, rp, rv, tmp
-		mov	\rp, #0x00030000
-#ifdef	__ARMEB__
-		orr	\rp, \rp, #0x00000003
-#endif
-		orr	\rv, \rp, #0xfe000000	@ virtual base
-		orr	\rv, \rv, #0x00f00000
-		orr	\rp, \rp, #0xc0000000	@ Physical base
-		.endm
-
-#define UART_SHIFT	2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-ixp2000/include/mach/enp2611.h b/arch/arm/mach-ixp2000/include/mach/enp2611.h
deleted file mode 100644
index 9ce3690..0000000
--- a/arch/arm/mach-ixp2000/include/mach/enp2611.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/enp2611.h
- *
- * Register and other defines for Radisys ENP-2611
- *
- * Created 2004 by Lennert Buytenhek from the ixdp2x01 code.  The
- * original version carries the following notices:
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#ifndef __ENP2611_H
-#define __ENP2611_H
-
-#define ENP2611_CALEB_PHYS_BASE		0xc5000000
-#define ENP2611_CALEB_VIRT_BASE		0xfe000000
-#define ENP2611_CALEB_SIZE		0x00100000
-
-#define ENP2611_PM3386_0_PHYS_BASE	0xc6000000
-#define ENP2611_PM3386_0_VIRT_BASE	0xfe100000
-#define ENP2611_PM3386_0_SIZE		0x00100000
-
-#define ENP2611_PM3386_1_PHYS_BASE	0xc6400000
-#define ENP2611_PM3386_1_VIRT_BASE	0xfe200000
-#define ENP2611_PM3386_1_SIZE		0x00100000
-
-#define ENP2611_GPIO_SCL		7
-#define ENP2611_GPIO_SDA		6
-
-#define IRQ_ENP2611_THERMAL		IRQ_IXP2000_GPIO4
-#define IRQ_ENP2611_OPTION_BOARD	IRQ_IXP2000_GPIO3
-#define IRQ_ENP2611_CALEB		IRQ_IXP2000_GPIO2
-#define IRQ_ENP2611_PM3386_1		IRQ_IXP2000_GPIO1
-#define IRQ_ENP2611_PM3386_0		IRQ_IXP2000_GPIO0
-
-
-#endif
diff --git a/arch/arm/mach-ixp2000/include/mach/entry-macro.S b/arch/arm/mach-ixp2000/include/mach/entry-macro.S
deleted file mode 100644
index c4444df..0000000
--- a/arch/arm/mach-ixp2000/include/mach/entry-macro.S
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for IXP2000-based platforms
- *
- * 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 <mach/irqs.h>
-
-		.macro  get_irqnr_preamble, base, tmp
-		.endm
-
-		.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-
-		mov	\irqnr, #0x0              @clear out irqnr as default
-                mov	\base, #0xfe000000
-		orr	\base, \base, #0x00e00000
-		orr	\base, \base, #0x08
-		ldr	\irqstat, [\base]         @ get interrupts
-
-		cmp	\irqstat, #0
-		beq	1001f
-
-		clz     \irqnr, \irqstat
-		mov     \base, #31
-		subs    \irqnr, \base, \irqnr
-
-		/*
-		 * We handle PCIA and PCIB here so we don't have an
-		 * extra layer of code just to check these two bits.
-		 */
-		cmp	\irqnr, #IRQ_IXP2000_PCI
-		bne	1001f
-
-		mov	\base, #0xfe000000
-		orr	\base, \base, #0x00c00000
-		orr	\base, \base, #0x00000100
-		orr	\base, \base, #0x00000058
-		ldr	\irqstat, [\base]
-
-		mov	\tmp, #(1<<26)
-		tst	\irqstat, \tmp
-		movne	\irqnr, #IRQ_IXP2000_PCIA
-		bne	1001f
-
-		mov	\tmp, #(1<<27)
-		tst	\irqstat, \tmp
-		movne	\irqnr, #IRQ_IXP2000_PCIB
-
-1001:
-		.endm
-
diff --git a/arch/arm/mach-ixp2000/include/mach/gpio-ixp2000.h b/arch/arm/mach-ixp2000/include/mach/gpio-ixp2000.h
deleted file mode 100644
index af836c7..0000000
--- a/arch/arm/mach-ixp2000/include/mach/gpio-ixp2000.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/gpio.h
- *
- * Copyright (C) 2002 Intel 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.
- */
-
-/*
- * IXP2000 GPIO in/out, edge/level detection for IRQs:
- * IRQs are generated on Falling-edge, Rising-Edge, Level-low, Level-High
- * or both Falling-edge and Rising-edge.
- * This must be called *before* the corresponding IRQ is registerd.
- * Use this instead of directly setting the GPIO registers.
- * GPIOs may also be used as GPIOs (e.g. for emulating i2c/smb)
- */
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H
-
-#ifndef __ASSEMBLY__
-
-#define GPIO_IN				0
-#define GPIO_OUT			1
-
-#define IXP2000_GPIO_LOW		0
-#define IXP2000_GPIO_HIGH		1
-
-extern void gpio_line_config(int line, int direction);
-
-static inline int gpio_line_get(int line)
-{
-	return (((*IXP2000_GPIO_PLR) >> line) & 1);
-}
-
-static inline void gpio_line_set(int line, int value)
-{
-	if (value == IXP2000_GPIO_HIGH) {
-		ixp2000_reg_write(IXP2000_GPIO_POSR, 1 << line);
-	} else if (value == IXP2000_GPIO_LOW) {
-		ixp2000_reg_write(IXP2000_GPIO_POCR, 1 << line);
-	}
-}
-
-#endif /* !__ASSEMBLY__ */
-
-#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
diff --git a/arch/arm/mach-ixp2000/include/mach/hardware.h b/arch/arm/mach-ixp2000/include/mach/hardware.h
deleted file mode 100644
index cdaf1db..0000000
--- a/arch/arm/mach-ixp2000/include/mach/hardware.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/hardware.h
- *
- * Hardware definitions for IXP2400/2800 based systems
- *
- * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
- *
- * Maintainer: Deepak Saxena <dsaxena@mvista.com>
- *
- * Copyright (C) 2001-2002 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H__
-#define __ASM_ARCH_HARDWARE_H__
-
-#include "ixp2000-regs.h"	/* Chipset Registers */
-
-/*
- * Platform helper functions
- */
-#include "platform.h"
-
-/*
- * Platform-specific bits
- */
-#include "enp2611.h"		/* ENP-2611 */
-#include "ixdp2x00.h"		/* IXDP2400/2800 */
-#include "ixdp2x01.h"		/* IXDP2401/2801 */
-
-#endif  /* _ASM_ARCH_HARDWARE_H__ */
diff --git a/arch/arm/mach-ixp2000/include/mach/io.h b/arch/arm/mach-ixp2000/include/mach/io.h
deleted file mode 100644
index f6552d6..0000000
--- a/arch/arm/mach-ixp2000/include/mach/io.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/io.h
- *
- * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002  Intel Corp.
- * Copyrgiht (C) 2003-2004 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 __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#include <mach/hardware.h>
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-/*
- * The A? revisions of the IXP2000s assert byte lanes for PCI I/O
- * transactions the other way round (MEM transactions don't have this
- * issue), so if we want to support those models, we need to override
- * the standard I/O functions.
- *
- * B0 and later have a bit that can be set to 1 to get the proper
- * behavior for I/O transactions, which then allows us to use the
- * standard I/O functions.  This is what we do if the user does not
- * explicitly ask for support for pre-B0.
- */
-#ifdef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
-#define ___io(p)		((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
-
-#define alignb(addr)		(void __iomem *)((unsigned long)(addr) ^ 3)
-#define alignw(addr)		(void __iomem *)((unsigned long)(addr) ^ 2)
-
-#define outb(v,p)		__raw_writeb((v),alignb(___io(p)))
-#define outw(v,p)		__raw_writew((v),alignw(___io(p)))
-#define outl(v,p)		__raw_writel((v),___io(p))
-
-#define inb(p)		({ unsigned int __v = __raw_readb(alignb(___io(p))); __v; })
-#define inw(p)		\
-	({ unsigned int __v = (__raw_readw(alignw(___io(p)))); __v; })
-#define inl(p)		\
-	({ unsigned int __v = (__raw_readl(___io(p))); __v; })
-
-#define outsb(p,d,l)		__raw_writesb(alignb(___io(p)),d,l)
-#define outsw(p,d,l)		__raw_writesw(alignw(___io(p)),d,l)
-#define outsl(p,d,l)		__raw_writesl(___io(p),d,l)
-
-#define insb(p,d,l)		__raw_readsb(alignb(___io(p)),d,l)
-#define insw(p,d,l)		__raw_readsw(alignw(___io(p)),d,l)
-#define insl(p,d,l)		__raw_readsl(___io(p),d,l)
-
-#define __is_io_address(p)	((((unsigned long)(p)) & ~(IXP2000_PCI_IO_SIZE - 1)) == IXP2000_PCI_IO_VIRT_BASE)
-
-#define ioread8(p)						\
-	({							\
-		unsigned int __v;				\
-								\
-		if (__is_io_address(p)) {			\
-			__v = __raw_readb(alignb(p));		\
-		} else {					\
-			__v = __raw_readb(p);			\
-		}						\
-								\
-		__v;						\
-	})							\
-
-#define ioread16(p)						\
-	({							\
-		unsigned int __v;				\
-								\
-		if (__is_io_address(p)) {			\
-			__v = __raw_readw(alignw(p));		\
-		} else {					\
-			__v = le16_to_cpu(__raw_readw(p));	\
-		}						\
-								\
-		__v;						\
-	})
-
-#define ioread32(p)						\
-	({							\
-		unsigned int __v;				\
-								\
-		if (__is_io_address(p)) {			\
-			__v = __raw_readl(p);			\
-		} else {					\
-			__v = le32_to_cpu(__raw_readl(p));	\
-		}						\
-								\
-		 __v;						\
-	})
-
-#define iowrite8(v,p)						\
-	({							\
-		if (__is_io_address(p)) {			\
-			__raw_writeb((v), alignb(p));		\
-		} else {					\
-			__raw_writeb((v), p);			\
-		}						\
-	})
-
-#define iowrite16(v,p)						\
-	({							\
-		if (__is_io_address(p)) {			\
-			__raw_writew((v), alignw(p));		\
-		} else {					\
-			__raw_writew(cpu_to_le16(v), p);	\
-		}						\
-	})
-
-#define iowrite32(v,p)						\
-	({							\
-		if (__is_io_address(p)) {			\
-			__raw_writel((v), p);			\
-		} else {					\
-			__raw_writel(cpu_to_le32(v), p);	\
-		}						\
-	})
-
-#define ioport_map(port, nr)	___io(port)
-
-#define ioport_unmap(addr)
-#else
-#define __io(p)			((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
-#endif
-
-
-#endif
diff --git a/arch/arm/mach-ixp2000/include/mach/irqs.h b/arch/arm/mach-ixp2000/include/mach/irqs.h
deleted file mode 100644
index bee96bc..0000000
--- a/arch/arm/mach-ixp2000/include/mach/irqs.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/irqs.h
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 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 _IRQS_H
-#define _IRQS_H
-
-/*
- * Do NOT add #ifdef MACHINE_FOO in here.
- * Simpy add your machine IRQs here and increase NR_IRQS if needed to
- * hold your machine's IRQ table.
- */
-
-/*
- * Some interrupt numbers go unused b/c the IRQ mask/ummask/status
- * register has those bit reserved. We just mark those interrupts
- * as invalid and this allows us to do mask/unmask with a single
- * shift operation instead of having to map the IRQ number to
- * a HW IRQ number.
- */
-#define	IRQ_IXP2000_SOFT_INT		0 /* soft interrupt */
-#define	IRQ_IXP2000_ERRSUM		1 /* OR of all bits in ErrorStatus reg*/
-#define	IRQ_IXP2000_UART		2
-#define	IRQ_IXP2000_GPIO		3
-#define	IRQ_IXP2000_TIMER1     		4
-#define	IRQ_IXP2000_TIMER2     		5
-#define	IRQ_IXP2000_TIMER3     		6
-#define	IRQ_IXP2000_TIMER4     		7
-#define	IRQ_IXP2000_PMU        		8               
-#define	IRQ_IXP2000_SPF        		9  /* Slow port framer IRQ */
-#define	IRQ_IXP2000_DMA1      		10
-#define	IRQ_IXP2000_DMA2      		11
-#define	IRQ_IXP2000_DMA3      		12
-#define	IRQ_IXP2000_PCI_DOORBELL	13
-#define	IRQ_IXP2000_ME_ATTN       	14 
-#define	IRQ_IXP2000_PCI   		15 /* PCI INTA or INTB */
-#define	IRQ_IXP2000_THDA0   		16 /* thread 0-31A */
-#define	IRQ_IXP2000_THDA1  		17 /* thread 32-63A, IXP2800 only */
-#define	IRQ_IXP2000_THDA2		18 /* thread 64-95A */
-#define	IRQ_IXP2000_THDA3 		19 /* thread 96-127A, IXP2800 only */
-#define	IRQ_IXP2000_THDB0		24 /* thread 0-31B */
-#define	IRQ_IXP2000_THDB1		25 /* thread 32-63B, IXP2800 only */
-#define	IRQ_IXP2000_THDB2		26 /* thread 64-95B */
-#define	IRQ_IXP2000_THDB3		27 /* thread 96-127B, IXP2800 only */
-
-/* define generic GPIOs */
-#define IRQ_IXP2000_GPIO0		32
-#define IRQ_IXP2000_GPIO1		33
-#define IRQ_IXP2000_GPIO2		34
-#define IRQ_IXP2000_GPIO3		35
-#define IRQ_IXP2000_GPIO4		36
-#define IRQ_IXP2000_GPIO5		37
-#define IRQ_IXP2000_GPIO6		38
-#define IRQ_IXP2000_GPIO7		39
-
-/* split off the 2 PCI sources */
-#define IRQ_IXP2000_PCIA		40
-#define IRQ_IXP2000_PCIB		41
-
-/* Int sources from IRQ_ERROR_STATUS */
-#define IRQ_IXP2000_DRAM0_MIN_ERR	42
-#define IRQ_IXP2000_DRAM0_MAJ_ERR	43
-#define IRQ_IXP2000_DRAM1_MIN_ERR	44
-#define IRQ_IXP2000_DRAM1_MAJ_ERR	45
-#define IRQ_IXP2000_DRAM2_MIN_ERR	46
-#define IRQ_IXP2000_DRAM2_MAJ_ERR	47
-/* 48-57 reserved */
-#define IRQ_IXP2000_SRAM0_ERR		58
-#define IRQ_IXP2000_SRAM1_ERR		59
-#define IRQ_IXP2000_SRAM2_ERR		60
-#define IRQ_IXP2000_SRAM3_ERR		61
-/* 62-65 reserved */
-#define IRQ_IXP2000_MEDIA_ERR		66
-#define IRQ_IXP2000_PCI_ERR			67
-#define IRQ_IXP2000_SP_INT			68
-
-#define NR_IXP2000_IRQS				69
-
-#define	IXP2000_BOARD_IRQ(x)		(NR_IXP2000_IRQS + (x))
-
-#define	IXP2000_BOARD_IRQ_MASK(irq)	(1 << (irq - NR_IXP2000_IRQS))	
-
-#define IXP2000_ERR_IRQ_MASK(irq) ( 1 << (irq - IRQ_IXP2000_DRAM0_MIN_ERR))
-#define IXP2000_VALID_ERR_IRQ_MASK (\
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM0_MIN_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM0_MAJ_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM1_MIN_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM1_MAJ_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM2_MIN_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM2_MAJ_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SRAM0_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SRAM1_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SRAM2_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SRAM3_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_MEDIA_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_PCI_ERR) | \
-		IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SP_INT)	)
-
-/*
- * This allows for all the on-chip sources plus up to 32 CPLD based
- * IRQs. Should be more than enough.
- */
-#define	IXP2000_BOARD_IRQS		32
-#define NR_IRQS				(NR_IXP2000_IRQS + IXP2000_BOARD_IRQS)
-
-
-/* 
- * IXDP2400 specific IRQs
- */
-#define	IRQ_IXDP2400_INGRESS_NPU	IXP2000_BOARD_IRQ(0) 
-#define	IRQ_IXDP2400_ENET		IXP2000_BOARD_IRQ(1) 
-#define	IRQ_IXDP2400_MEDIA_PCI		IXP2000_BOARD_IRQ(2) 
-#define	IRQ_IXDP2400_MEDIA_SP		IXP2000_BOARD_IRQ(3) 
-#define	IRQ_IXDP2400_SF_PCI		IXP2000_BOARD_IRQ(4) 
-#define	IRQ_IXDP2400_SF_SP		IXP2000_BOARD_IRQ(5) 
-#define	IRQ_IXDP2400_PMC		IXP2000_BOARD_IRQ(6) 
-#define	IRQ_IXDP2400_TVM		IXP2000_BOARD_IRQ(7) 
-
-#define	NR_IXDP2400_IRQS		((IRQ_IXDP2400_TVM)+1)  
-#define	IXDP2400_NR_IRQS		NR_IXDP2400_IRQS - NR_IXP2000_IRQS
-
-/* IXDP2800 specific IRQs */
-#define IRQ_IXDP2800_EGRESS_ENET	IXP2000_BOARD_IRQ(0)
-#define IRQ_IXDP2800_INGRESS_NPU	IXP2000_BOARD_IRQ(1)
-#define IRQ_IXDP2800_PMC		IXP2000_BOARD_IRQ(2)
-#define IRQ_IXDP2800_FABRIC_PCI		IXP2000_BOARD_IRQ(3)
-#define IRQ_IXDP2800_FABRIC		IXP2000_BOARD_IRQ(4)
-#define IRQ_IXDP2800_MEDIA		IXP2000_BOARD_IRQ(5)
-
-#define	NR_IXDP2800_IRQS		((IRQ_IXDP2800_MEDIA)+1)
-#define	IXDP2800_NR_IRQS		NR_IXDP2800_IRQS - NR_IXP2000_IRQS
-
-/* 
- * IRQs on both IXDP2x01 boards
- */
-#define IRQ_IXDP2X01_SPCI_DB_0		IXP2000_BOARD_IRQ(2)
-#define IRQ_IXDP2X01_SPCI_DB_1		IXP2000_BOARD_IRQ(3)
-#define IRQ_IXDP2X01_SPCI_PMC_INTA	IXP2000_BOARD_IRQ(4)
-#define IRQ_IXDP2X01_SPCI_PMC_INTB	IXP2000_BOARD_IRQ(5)
-#define IRQ_IXDP2X01_SPCI_PMC_INTC	IXP2000_BOARD_IRQ(6)
-#define IRQ_IXDP2X01_SPCI_PMC_INTD	IXP2000_BOARD_IRQ(7)
-#define IRQ_IXDP2X01_SPCI_FIC_INT	IXP2000_BOARD_IRQ(8)
-#define IRQ_IXDP2X01_IPMI_FROM		IXP2000_BOARD_IRQ(16)
-#define IRQ_IXDP2X01_125US		IXP2000_BOARD_IRQ(17)
-#define IRQ_IXDP2X01_DB_0_ADD		IXP2000_BOARD_IRQ(18)
-#define IRQ_IXDP2X01_DB_1_ADD		IXP2000_BOARD_IRQ(19)
-#define IRQ_IXDP2X01_UART1		IXP2000_BOARD_IRQ(21)
-#define IRQ_IXDP2X01_UART2		IXP2000_BOARD_IRQ(22)
-#define IRQ_IXDP2X01_FIC_ADD_INT	IXP2000_BOARD_IRQ(24)
-#define IRQ_IXDP2X01_CS8900		IXP2000_BOARD_IRQ(25)
-#define IRQ_IXDP2X01_BBSRAM		IXP2000_BOARD_IRQ(26)
-
-#define IXDP2X01_VALID_IRQ_MASK ( \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_DB_0) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_DB_1) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTA) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTB) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTC) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTD) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_FIC_INT) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_IPMI_FROM) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_125US) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_DB_0_ADD) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_DB_1_ADD) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_UART1) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_UART2) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_FIC_ADD_INT) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_CS8900) | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_BBSRAM) )
-
-/* 
- * IXDP2401 specific IRQs
- */
-#define IRQ_IXDP2401_INTA_82546		IXP2000_BOARD_IRQ(0)
-#define IRQ_IXDP2401_INTB_82546		IXP2000_BOARD_IRQ(1)
-
-#define	IXDP2401_VALID_IRQ_MASK ( \
-		IXDP2X01_VALID_IRQ_MASK | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2401_INTA_82546) |\
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2401_INTB_82546))
-
-/*
- * IXDP2801-specific IRQs
- */
-#define IRQ_IXDP2801_RIV		IXP2000_BOARD_IRQ(0)
-#define IRQ_IXDP2801_CNFG_MEDIA		IXP2000_BOARD_IRQ(27)
-#define IRQ_IXDP2801_CLOCK_REF		IXP2000_BOARD_IRQ(28)
-
-#define	IXDP2801_VALID_IRQ_MASK ( \
-		IXDP2X01_VALID_IRQ_MASK | \
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2801_RIV) |\
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2801_CNFG_MEDIA) |\
-		IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2801_CLOCK_REF))
-
-#define	NR_IXDP2X01_IRQS		((IRQ_IXDP2801_CLOCK_REF) + 1)
-
-#endif /*_IRQS_H*/
diff --git a/arch/arm/mach-ixp2000/include/mach/ixdp2x00.h b/arch/arm/mach-ixp2000/include/mach/ixdp2x00.h
deleted file mode 100644
index 5df8479..0000000
--- a/arch/arm/mach-ixp2000/include/mach/ixdp2x00.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/ixdp2x00.h
- *
- * Register and other defines for IXDP2[48]00 platforms
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-#ifndef _IXDP2X00_H_
-#define _IXDP2X00_H_
-
-/*
- * On board CPLD memory map
- */
-#define IXDP2X00_PHYS_CPLD_BASE		0xc7000000
-#define IXDP2X00_VIRT_CPLD_BASE		0xfe000000
-#define IXDP2X00_CPLD_SIZE		0x00100000
-
-
-#define IXDP2X00_CPLD_REG(x)  	\
-	(volatile unsigned long *)(IXDP2X00_VIRT_CPLD_BASE | x)
-
-/*
- * IXDP2400 CPLD registers
- */
-#define IXDP2400_CPLD_SYSLED		IXDP2X00_CPLD_REG(0x0)  
-#define IXDP2400_CPLD_DISP_DATA		IXDP2X00_CPLD_REG(0x4)
-#define IXDP2400_CPLD_CLOCK_SPEED	IXDP2X00_CPLD_REG(0x8)
-#define IXDP2400_CPLD_INT_STAT		IXDP2X00_CPLD_REG(0xc)
-#define IXDP2400_CPLD_REV		IXDP2X00_CPLD_REG(0x10)
-#define IXDP2400_CPLD_SYS_CLK_M		IXDP2X00_CPLD_REG(0x14)
-#define IXDP2400_CPLD_SYS_CLK_N		IXDP2X00_CPLD_REG(0x18)
-#define IXDP2400_CPLD_INT_MASK		IXDP2X00_CPLD_REG(0x48)
-
-/*
- * IXDP2800 CPLD registers
- */
-#define IXDP2800_CPLD_INT_STAT		IXDP2X00_CPLD_REG(0x0)
-#define IXDP2800_CPLD_INT_MASK		IXDP2X00_CPLD_REG(0x140)
-
-
-#define	IXDP2X00_GPIO_I2C_ENABLE	0x02
-#define	IXDP2X00_GPIO_SCL		0x07
-#define	IXDP2X00_GPIO_SDA		0x06
-
-/*
- * PCI devfns for on-board devices. We need these to be able to
- * properly translate IRQs and for device removal.
- */
-#define	IXDP2400_SLAVE_ENET_DEVFN	0x18	/* Bus 1 */
-#define	IXDP2400_MASTER_ENET_DEVFN	0x20	/* Bus 1 */
-#define	IXDP2400_MEDIA_DEVFN		0x28	/* Bus 1 */
-#define	IXDP2400_SWITCH_FABRIC_DEVFN	0x30	/* Bus 1 */
-
-#define	IXDP2800_SLAVE_ENET_DEVFN	0x20	/* Bus 1 */
-#define	IXDP2800_MASTER_ENET_DEVFN	0x18	/* Bus 1 */
-#define	IXDP2800_SWITCH_FABRIC_DEVFN	0x30	/* Bus 1 */
-
-#define	IXDP2X00_P2P_DEVFN		0x20	/* Bus 0 */
-#define	IXDP2X00_21555_DEVFN		0x30	/* Bus 0 */
-#define IXDP2X00_SLAVE_NPU_DEVFN	0x28	/* Bus 1 */
-#define	IXDP2X00_PMC_DEVFN		0x38	/* Bus 1 */
-#define IXDP2X00_MASTER_NPU_DEVFN	0x38	/* Bus 1 */
-
-#ifndef __ASSEMBLY__
-/*
- * The master NPU is always PCI master.
- */
-static inline unsigned int ixdp2x00_master_npu(void)
-{
-	return !!ixp2000_is_pcimaster();
-}
-
-/*
- * Helper functions used by ixdp2400 and ixdp2800 specific code
- */
-void ixdp2x00_init_irq(volatile unsigned long*, volatile unsigned long *, unsigned long);
-void ixdp2x00_slave_pci_postinit(void);
-void ixdp2x00_init_machine(void);
-void ixdp2x00_map_io(void);
-
-#endif
-
-#endif /*_IXDP2X00_H_ */
diff --git a/arch/arm/mach-ixp2000/include/mach/ixdp2x01.h b/arch/arm/mach-ixp2000/include/mach/ixdp2x01.h
deleted file mode 100644
index 4c1f040..0000000
--- a/arch/arm/mach-ixp2000/include/mach/ixdp2x01.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/ixdp2x01.h
- *
- * Platform definitions for IXDP2X01 && IXDP2801 systems
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2004 (c) MontaVista Software, Inc. 
- *
- * Based on original code Copyright (c) 2002-2003 Intel Corporation
- * 
- * 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 __IXDP2X01_H__
-#define __IXDP2X01_H__
-
-#define	IXDP2X01_PHYS_CPLD_BASE		0xc6024000
-#define	IXDP2X01_VIRT_CPLD_BASE		0xfe000000
-#define	IXDP2X01_CPLD_REGION_SIZE	0x00100000
-
-#define IXDP2X01_CPLD_VIRT_REG(reg) (volatile unsigned long*)(IXDP2X01_VIRT_CPLD_BASE | reg)
-#define IXDP2X01_CPLD_PHYS_REG(reg) (IXDP2X01_PHYS_CPLD_BASE | reg)
-
-#define IXDP2X01_UART1_VIRT_BASE	IXDP2X01_CPLD_VIRT_REG(0x40)
-#define IXDP2X01_UART1_PHYS_BASE	IXDP2X01_CPLD_PHYS_REG(0x40)
-
-#define IXDP2X01_UART2_VIRT_BASE	IXDP2X01_CPLD_VIRT_REG(0x60)
-#define IXDP2X01_UART2_PHYS_BASE	IXDP2X01_CPLD_PHYS_REG(0x60)
-
-#define IXDP2X01_CS8900_VIRT_BASE	IXDP2X01_CPLD_VIRT_REG(0x80)
-#define IXDP2X01_CS8900_VIRT_END	(IXDP2X01_CS8900_VIRT_BASE + 16)
-
-#define IXDP2X01_CPLD_RESET_REG         IXDP2X01_CPLD_VIRT_REG(0x00)
-#define IXDP2X01_INT_MASK_SET_REG	IXDP2X01_CPLD_VIRT_REG(0x08)
-#define IXDP2X01_INT_STAT_REG		IXDP2X01_CPLD_VIRT_REG(0x0C)
-#define IXDP2X01_INT_RAW_REG		IXDP2X01_CPLD_VIRT_REG(0x10) 
-#define IXDP2X01_INT_MASK_CLR_REG	IXDP2X01_INT_RAW_REG
-#define IXDP2X01_INT_SIM_REG		IXDP2X01_CPLD_VIRT_REG(0x14)
-
-#define IXDP2X01_CPLD_FLASH_REG		IXDP2X01_CPLD_VIRT_REG(0x20)
-
-#define IXDP2X01_CPLD_FLASH_INTERN 	0x8000
-#define IXDP2X01_CPLD_FLASH_BANK_MASK 	0xF
-#define IXDP2X01_FLASH_WINDOW_BITS 	25
-#define IXDP2X01_FLASH_WINDOW_SIZE 	(1 << IXDP2X01_FLASH_WINDOW_BITS)
-#define IXDP2X01_FLASH_WINDOW_MASK 	(IXDP2X01_FLASH_WINDOW_SIZE - 1)
-
-#define	IXDP2X01_UART_CLK		1843200
-
-#define	IXDP2X01_GPIO_I2C_ENABLE	0x02
-#define	IXDP2X01_GPIO_SCL		0x07
-#define	IXDP2X01_GPIO_SDA		0x06
-
-#endif /* __IXDP2x01_H__ */
diff --git a/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h b/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h
deleted file mode 100644
index 822f63f..0000000
--- a/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h
- *
- * Chipset register definitions for IXP2400/2800 based systems.
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- *
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-#ifndef _IXP2000_REGS_H_
-#define _IXP2000_REGS_H_
-
-/*
- * IXP2000 linux memory map:
- *
- * virt		phys		size
- * fb000000	db000000	16M		PCI CFG1
- * fc000000	da000000	16M		PCI CFG0
- * fd000000	d8000000	16M		PCI I/O
- * fe[0-7]00000			8M		per-platform mappings
- * fe900000	80000000	1M		SRAM #0 (first MB)
- * fea00000	cb400000	1M		SCRATCH ring get/put
- * feb00000	c8000000	1M		MSF
- * fec00000	df000000	1M		PCI CSRs
- * fed00000	de000000	1M		PCI CREG
- * fee00000	d6000000	1M		INTCTL
- * fef00000	c0000000	1M		CAP
- */
-
-/* 
- * Static I/O regions.
- *
- * Most of the registers are clumped in 4K regions spread throughout
- * the 0xc0000000 -> 0xc0100000 address range, but we just map in
- * the whole range using a single 1 MB section instead of small
- * 4K pages.
- *
- * CAP stands for CSR Access Proxy.
- *
- * If you change the virtual address of this mapping, please propagate
- * the change to arch/arm/kernel/debug.S, which hardcodes the virtual
- * address of the UART located in this region.
- */
-
-#define	IXP2000_CAP_PHYS_BASE		0xc0000000
-#define	IXP2000_CAP_VIRT_BASE		0xfef00000
-#define	IXP2000_CAP_SIZE		0x00100000
-
-/*
- * Addresses for specific on-chip peripherals.
- */
-#define	IXP2000_SLOWPORT_CSR_VIRT_BASE	0xfef80000
-#define	IXP2000_GLOBAL_REG_VIRT_BASE	0xfef04000
-#define	IXP2000_UART_PHYS_BASE		0xc0030000
-#define	IXP2000_UART_VIRT_BASE		0xfef30000
-#define	IXP2000_TIMER_VIRT_BASE		0xfef20000
-#define	IXP2000_UENGINE_CSR_VIRT_BASE	0xfef18000
-#define	IXP2000_GPIO_VIRT_BASE		0xfef10000
-
-/*
- * Devices outside of the 0xc0000000 -> 0xc0100000 range.  The virtual
- * addresses of the INTCTL and PCI_CSR mappings are hardcoded in
- * entry-macro.S, so if you ever change these please propagate
- * the change.
- */
-#define IXP2000_INTCTL_PHYS_BASE	0xd6000000
-#define	IXP2000_INTCTL_VIRT_BASE	0xfee00000
-#define	IXP2000_INTCTL_SIZE		0x00100000
-
-#define IXP2000_PCI_CREG_PHYS_BASE	0xde000000
-#define	IXP2000_PCI_CREG_VIRT_BASE	0xfed00000
-#define	IXP2000_PCI_CREG_SIZE		0x00100000
-
-#define IXP2000_PCI_CSR_PHYS_BASE	0xdf000000
-#define	IXP2000_PCI_CSR_VIRT_BASE	0xfec00000
-#define	IXP2000_PCI_CSR_SIZE		0x00100000
-
-#define IXP2000_MSF_PHYS_BASE		0xc8000000
-#define IXP2000_MSF_VIRT_BASE		0xfeb00000
-#define IXP2000_MSF_SIZE		0x00100000
-
-#define IXP2000_SCRATCH_RING_PHYS_BASE	0xcb400000
-#define IXP2000_SCRATCH_RING_VIRT_BASE	0xfea00000
-#define IXP2000_SCRATCH_RING_SIZE	0x00100000
-
-#define IXP2000_SRAM0_PHYS_BASE		0x80000000
-#define IXP2000_SRAM0_VIRT_BASE		0xfe900000
-#define IXP2000_SRAM0_SIZE		0x00100000
-
-#define IXP2000_PCI_IO_PHYS_BASE	0xd8000000
-#define	IXP2000_PCI_IO_VIRT_BASE	0xfd000000
-#define IXP2000_PCI_IO_SIZE     	0x01000000
-
-#define IXP2000_PCI_CFG0_PHYS_BASE	0xda000000
-#define IXP2000_PCI_CFG0_VIRT_BASE	0xfc000000
-#define IXP2000_PCI_CFG0_SIZE   	0x01000000
-
-#define IXP2000_PCI_CFG1_PHYS_BASE	0xdb000000
-#define IXP2000_PCI_CFG1_VIRT_BASE	0xfb000000
-#define IXP2000_PCI_CFG1_SIZE		0x01000000
-
-/* 
- * Timers
- */
-#define	IXP2000_TIMER_REG(x)		((volatile unsigned long*)(IXP2000_TIMER_VIRT_BASE | (x)))
-/* Timer control */
-#define	IXP2000_T1_CTL			IXP2000_TIMER_REG(0x00)
-#define	IXP2000_T2_CTL			IXP2000_TIMER_REG(0x04)
-#define	IXP2000_T3_CTL			IXP2000_TIMER_REG(0x08)
-#define	IXP2000_T4_CTL			IXP2000_TIMER_REG(0x0c)
-/* Store initial value */
-#define	IXP2000_T1_CLD			IXP2000_TIMER_REG(0x10)
-#define	IXP2000_T2_CLD			IXP2000_TIMER_REG(0x14)
-#define	IXP2000_T3_CLD			IXP2000_TIMER_REG(0x18)
-#define	IXP2000_T4_CLD			IXP2000_TIMER_REG(0x1c)
-/* Read current value */
-#define	IXP2000_T1_CSR			IXP2000_TIMER_REG(0x20)
-#define	IXP2000_T2_CSR			IXP2000_TIMER_REG(0x24)
-#define	IXP2000_T3_CSR			IXP2000_TIMER_REG(0x28)
-#define	IXP2000_T4_CSR			IXP2000_TIMER_REG(0x2c)
-/* Clear associated timer interrupt */
-#define	IXP2000_T1_CLR			IXP2000_TIMER_REG(0x30)
-#define	IXP2000_T2_CLR			IXP2000_TIMER_REG(0x34)
-#define	IXP2000_T3_CLR			IXP2000_TIMER_REG(0x38)
-#define	IXP2000_T4_CLR			IXP2000_TIMER_REG(0x3c)
-/* Timer watchdog enable for T4 */
-#define	IXP2000_TWDE			IXP2000_TIMER_REG(0x40)
-
-#define	WDT_ENABLE			0x00000001
-#define	TIMER_DIVIDER_256		0x00000008
-#define	TIMER_ENABLE			0x00000080
-#define	IRQ_MASK_TIMER1         	(1 << 4)
-
-/*
- * Interrupt controller registers
- */
-#define IXP2000_INTCTL_REG(x)		(volatile unsigned long*)(IXP2000_INTCTL_VIRT_BASE | (x))
-#define IXP2000_IRQ_STATUS		IXP2000_INTCTL_REG(0x08)
-#define IXP2000_IRQ_ENABLE		IXP2000_INTCTL_REG(0x10)
-#define IXP2000_IRQ_ENABLE_SET		IXP2000_INTCTL_REG(0x10)
-#define IXP2000_IRQ_ENABLE_CLR		IXP2000_INTCTL_REG(0x18)
-#define IXP2000_FIQ_ENABLE_CLR		IXP2000_INTCTL_REG(0x14)
-#define IXP2000_IRQ_ERR_STATUS		IXP2000_INTCTL_REG(0x24)
-#define IXP2000_IRQ_ERR_ENABLE_SET	IXP2000_INTCTL_REG(0x2c)
-#define IXP2000_FIQ_ERR_ENABLE_CLR	IXP2000_INTCTL_REG(0x30)
-#define IXP2000_IRQ_ERR_ENABLE_CLR	IXP2000_INTCTL_REG(0x34)
-#define IXP2000_IRQ_THD_RAW_STATUS_A_0	IXP2000_INTCTL_REG(0x60)
-#define IXP2000_IRQ_THD_RAW_STATUS_A_1	IXP2000_INTCTL_REG(0x64)
-#define IXP2000_IRQ_THD_RAW_STATUS_A_2	IXP2000_INTCTL_REG(0x68)
-#define IXP2000_IRQ_THD_RAW_STATUS_A_3	IXP2000_INTCTL_REG(0x6c)
-#define IXP2000_IRQ_THD_RAW_STATUS_B_0	IXP2000_INTCTL_REG(0x80)
-#define IXP2000_IRQ_THD_RAW_STATUS_B_1	IXP2000_INTCTL_REG(0x84)
-#define IXP2000_IRQ_THD_RAW_STATUS_B_2	IXP2000_INTCTL_REG(0x88)
-#define IXP2000_IRQ_THD_RAW_STATUS_B_3	IXP2000_INTCTL_REG(0x8c)
-#define IXP2000_IRQ_THD_STATUS_A_0	IXP2000_INTCTL_REG(0xe0)
-#define IXP2000_IRQ_THD_STATUS_A_1	IXP2000_INTCTL_REG(0xe4)
-#define IXP2000_IRQ_THD_STATUS_A_2	IXP2000_INTCTL_REG(0xe8)
-#define IXP2000_IRQ_THD_STATUS_A_3	IXP2000_INTCTL_REG(0xec)
-#define IXP2000_IRQ_THD_STATUS_B_0	IXP2000_INTCTL_REG(0x100)
-#define IXP2000_IRQ_THD_STATUS_B_1	IXP2000_INTCTL_REG(0x104)
-#define IXP2000_IRQ_THD_STATUS_B_2	IXP2000_INTCTL_REG(0x108)
-#define IXP2000_IRQ_THD_STATUS_B_3	IXP2000_INTCTL_REG(0x10c)
-#define IXP2000_IRQ_THD_ENABLE_SET_A_0	IXP2000_INTCTL_REG(0x160)
-#define IXP2000_IRQ_THD_ENABLE_SET_A_1	IXP2000_INTCTL_REG(0x164)
-#define IXP2000_IRQ_THD_ENABLE_SET_A_2	IXP2000_INTCTL_REG(0x168)
-#define IXP2000_IRQ_THD_ENABLE_SET_A_3	IXP2000_INTCTL_REG(0x16c)
-#define IXP2000_IRQ_THD_ENABLE_SET_B_0	IXP2000_INTCTL_REG(0x180)
-#define IXP2000_IRQ_THD_ENABLE_SET_B_1	IXP2000_INTCTL_REG(0x184)
-#define IXP2000_IRQ_THD_ENABLE_SET_B_2	IXP2000_INTCTL_REG(0x188)
-#define IXP2000_IRQ_THD_ENABLE_SET_B_3	IXP2000_INTCTL_REG(0x18c)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_0	IXP2000_INTCTL_REG(0x1e0)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_1	IXP2000_INTCTL_REG(0x1e4)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_2	IXP2000_INTCTL_REG(0x1e8)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_3	IXP2000_INTCTL_REG(0x1ec)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_0	IXP2000_INTCTL_REG(0x200)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_1	IXP2000_INTCTL_REG(0x204)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_2	IXP2000_INTCTL_REG(0x208)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_3	IXP2000_INTCTL_REG(0x20c)
-
-/*
- * Mask of valid IRQs in the 32-bit IRQ register. We use
- * this to mark certain IRQs as being invalid.
- */
-#define	IXP2000_VALID_IRQ_MASK	0x0f0fffff
-
-/*
- * PCI config register access from core
- */
-#define IXP2000_PCI_CREG(x)		(volatile unsigned long*)(IXP2000_PCI_CREG_VIRT_BASE | (x))
-#define IXP2000_PCI_CMDSTAT 		IXP2000_PCI_CREG(0x04)
-#define IXP2000_PCI_CSR_BAR		IXP2000_PCI_CREG(0x10)
-#define IXP2000_PCI_SRAM_BAR		IXP2000_PCI_CREG(0x14)
-#define IXP2000_PCI_SDRAM_BAR		IXP2000_PCI_CREG(0x18)
-
-/*
- * PCI CSRs
- */
-#define IXP2000_PCI_CSR(x)		(volatile unsigned long*)(IXP2000_PCI_CSR_VIRT_BASE | (x))
-
-/*
- * PCI outbound interrupts
- */
-#define IXP2000_PCI_OUT_INT_STATUS	IXP2000_PCI_CSR(0x30)
-#define IXP2000_PCI_OUT_INT_MASK	IXP2000_PCI_CSR(0x34)
-/*
- * PCI communications
- */
-#define IXP2000_PCI_MAILBOX0		IXP2000_PCI_CSR(0x50)
-#define IXP2000_PCI_MAILBOX1		IXP2000_PCI_CSR(0x54)
-#define IXP2000_PCI_MAILBOX2		IXP2000_PCI_CSR(0x58)
-#define IXP2000_PCI_MAILBOX3		IXP2000_PCI_CSR(0x5C)
-#define IXP2000_XSCALE_DOORBELL		IXP2000_PCI_CSR(0x60)
-#define IXP2000_XSCALE_DOORBELL_SETUP	IXP2000_PCI_CSR(0x64)
-#define IXP2000_PCI_DOORBELL		IXP2000_PCI_CSR(0x70)
-#define IXP2000_PCI_DOORBELL_SETUP	IXP2000_PCI_CSR(0x74)
-
-/*
- * DMA engines
- */
-#define IXP2000_PCI_CH1_BYTE_CNT	IXP2000_PCI_CSR(0x80)
-#define IXP2000_PCI_CH1_ADDR		IXP2000_PCI_CSR(0x84)
-#define IXP2000_PCI_CH1_DRAM_ADDR	IXP2000_PCI_CSR(0x88)
-#define IXP2000_PCI_CH1_DESC_PTR	IXP2000_PCI_CSR(0x8C)
-#define IXP2000_PCI_CH1_CNTRL		IXP2000_PCI_CSR(0x90)
-#define IXP2000_PCI_CH1_ME_PARAM	IXP2000_PCI_CSR(0x94)
-#define IXP2000_PCI_CH2_BYTE_CNT	IXP2000_PCI_CSR(0xA0)
-#define IXP2000_PCI_CH2_ADDR		IXP2000_PCI_CSR(0xA4)
-#define IXP2000_PCI_CH2_DRAM_ADDR	IXP2000_PCI_CSR(0xA8)
-#define IXP2000_PCI_CH2_DESC_PTR	IXP2000_PCI_CSR(0xAC)
-#define IXP2000_PCI_CH2_CNTRL		IXP2000_PCI_CSR(0xB0)
-#define IXP2000_PCI_CH2_ME_PARAM	IXP2000_PCI_CSR(0xB4)
-#define IXP2000_PCI_CH3_BYTE_CNT	IXP2000_PCI_CSR(0xC0)
-#define IXP2000_PCI_CH3_ADDR		IXP2000_PCI_CSR(0xC4)
-#define IXP2000_PCI_CH3_DRAM_ADDR	IXP2000_PCI_CSR(0xC8)
-#define IXP2000_PCI_CH3_DESC_PTR	IXP2000_PCI_CSR(0xCC)
-#define IXP2000_PCI_CH3_CNTRL		IXP2000_PCI_CSR(0xD0)
-#define IXP2000_PCI_CH3_ME_PARAM	IXP2000_PCI_CSR(0xD4)
-#define IXP2000_DMA_INF_MODE		IXP2000_PCI_CSR(0xE0)
-/*
- * Size masks for BARs
- */
-#define IXP2000_PCI_SRAM_BASE_ADDR_MASK	IXP2000_PCI_CSR(0xFC)
-#define IXP2000_PCI_DRAM_BASE_ADDR_MASK	IXP2000_PCI_CSR(0x100)
-/*
- * Control and uEngine related
- */
-#define IXP2000_PCI_CONTROL		IXP2000_PCI_CSR(0x13C)
-#define IXP2000_PCI_ADDR_EXT		IXP2000_PCI_CSR(0x140)
-#define IXP2000_PCI_ME_PUSH_STATUS	IXP2000_PCI_CSR(0x148)
-#define IXP2000_PCI_ME_PUSH_EN		IXP2000_PCI_CSR(0x14C)
-#define IXP2000_PCI_ERR_STATUS		IXP2000_PCI_CSR(0x150)
-#define IXP2000_PCI_ERR_ENABLE		IXP2000_PCI_CSR(0x154)
-/*
- * Inbound PCI interrupt control
- */
-#define IXP2000_PCI_XSCALE_INT_STATUS	IXP2000_PCI_CSR(0x158)
-#define IXP2000_PCI_XSCALE_INT_ENABLE	IXP2000_PCI_CSR(0x15C)
-
-#define IXP2000_PCICNTL_PNR		(1<<17)	/* PCI not Reset bit of PCI_CONTROL */
-#define IXP2000_PCICNTL_PCF		(1<<28)	/* PCI Central function bit */
-#define IXP2000_XSCALE_INT		(1<<1)	/* Interrupt from XScale to PCI */
-
-/* These are from the IRQ register in the PCI ISR register */
-#define PCI_CONTROL_BE_DEO		(1 << 22)	/* Big Endian Data Enable Out */
-#define PCI_CONTROL_BE_DEI		(1 << 21)	/* Big Endian Data Enable In  */
-#define PCI_CONTROL_BE_BEO		(1 << 20)	/* Big Endian Byte Enable Out */
-#define PCI_CONTROL_BE_BEI		(1 << 19)	/* Big Endian Byte Enable In  */
-#define PCI_CONTROL_IEE			(1 << 17)	/* I/O cycle Endian swap Enable */
-
-#define IXP2000_PCI_RST_REL		(1 << 2)
-#define CFG_RST_DIR			(*IXP2000_PCI_CONTROL & IXP2000_PCICNTL_PCF)
-#define CFG_PCI_BOOT_HOST		(1 << 2)
-#define CFG_BOOT_PROM			(1 << 1)
-
-/*
- * SlowPort CSRs
- *
- * The slowport is used to access things like flash, SONET framer control
- * ports, slave microprocessors, CPLDs, and others of chip memory mapped
- * peripherals.
- */
-#define	SLOWPORT_CSR(x)		(volatile unsigned long*)(IXP2000_SLOWPORT_CSR_VIRT_BASE | (x))
-
-#define	IXP2000_SLOWPORT_CCR		SLOWPORT_CSR(0x00)
-#define	IXP2000_SLOWPORT_WTC1		SLOWPORT_CSR(0x04)
-#define	IXP2000_SLOWPORT_WTC2		SLOWPORT_CSR(0x08)
-#define	IXP2000_SLOWPORT_RTC1		SLOWPORT_CSR(0x0c)
-#define	IXP2000_SLOWPORT_RTC2		SLOWPORT_CSR(0x10)
-#define	IXP2000_SLOWPORT_FSR		SLOWPORT_CSR(0x14)
-#define	IXP2000_SLOWPORT_PCR		SLOWPORT_CSR(0x18)
-#define	IXP2000_SLOWPORT_ADC		SLOWPORT_CSR(0x1C)
-#define	IXP2000_SLOWPORT_FAC		SLOWPORT_CSR(0x20)
-#define	IXP2000_SLOWPORT_FRM		SLOWPORT_CSR(0x24)
-#define	IXP2000_SLOWPORT_FIN		SLOWPORT_CSR(0x28)
-
-/*
- * CCR values.  
- * The CCR configures the clock division for the slowport interface.
- */
-#define	SLOWPORT_CCR_DIV_1		0x00
-#define	SLOWPORT_CCR_DIV_2		0x01
-#define	SLOWPORT_CCR_DIV_4		0x02
-#define	SLOWPORT_CCR_DIV_6		0x03
-#define	SLOWPORT_CCR_DIV_8		0x04
-#define	SLOWPORT_CCR_DIV_10		0x05
-#define	SLOWPORT_CCR_DIV_12		0x06
-#define	SLOWPORT_CCR_DIV_14		0x07
-#define	SLOWPORT_CCR_DIV_16		0x08
-#define	SLOWPORT_CCR_DIV_18		0x09
-#define	SLOWPORT_CCR_DIV_20		0x0a
-#define	SLOWPORT_CCR_DIV_22		0x0b
-#define	SLOWPORT_CCR_DIV_24		0x0c
-#define	SLOWPORT_CCR_DIV_26		0x0d
-#define	SLOWPORT_CCR_DIV_28		0x0e
-#define	SLOWPORT_CCR_DIV_30		0x0f
-
-/*
- * PCR values.  PCR configure the mode of the interface.
- */
-#define	SLOWPORT_MODE_FLASH		0x00
-#define	SLOWPORT_MODE_LUCENT		0x01
-#define	SLOWPORT_MODE_PMC_SIERRA	0x02
-#define	SLOWPORT_MODE_INTEL_UP		0x03
-#define	SLOWPORT_MODE_MOTOROLA_UP	0x04
-
-/*
- * ADC values.  Defines data and address bus widths.
- */
-#define	SLOWPORT_ADDR_WIDTH_8		0x00
-#define	SLOWPORT_ADDR_WIDTH_16		0x01
-#define	SLOWPORT_ADDR_WIDTH_24		0x02
-#define	SLOWPORT_ADDR_WIDTH_32		0x03
-#define	SLOWPORT_DATA_WIDTH_8		0x00
-#define	SLOWPORT_DATA_WIDTH_16		0x10
-#define	SLOWPORT_DATA_WIDTH_24		0x20
-#define	SLOWPORT_DATA_WIDTH_32		0x30
-
-/*
- * Masks and shifts for various fields in the WTC and RTC registers.
- */
-#define	SLOWPORT_WRTC_MASK_HD		0x0003
-#define	SLOWPORT_WRTC_MASK_PW		0x003c
-#define	SLOWPORT_WRTC_MASK_SU		0x03c0
-
-#define	SLOWPORT_WRTC_SHIFT_HD		0x00
-#define	SLOWPORT_WRTC_SHIFT_SU		0x02
-#define	SLOWPORT_WRTC_SHFIT_PW		0x06
-
-
-/*
- * GPIO registers & GPIO interface.
- */
-#define IXP2000_GPIO_REG(x)		((volatile unsigned long*)(IXP2000_GPIO_VIRT_BASE+(x)))
-#define IXP2000_GPIO_PLR		IXP2000_GPIO_REG(0x00)
-#define IXP2000_GPIO_PDPR		IXP2000_GPIO_REG(0x04)
-#define IXP2000_GPIO_PDSR		IXP2000_GPIO_REG(0x08)
-#define IXP2000_GPIO_PDCR		IXP2000_GPIO_REG(0x0c)
-#define IXP2000_GPIO_POPR		IXP2000_GPIO_REG(0x10)
-#define IXP2000_GPIO_POSR		IXP2000_GPIO_REG(0x14)
-#define IXP2000_GPIO_POCR		IXP2000_GPIO_REG(0x18)
-#define IXP2000_GPIO_REDR		IXP2000_GPIO_REG(0x1c)
-#define IXP2000_GPIO_FEDR		IXP2000_GPIO_REG(0x20)
-#define IXP2000_GPIO_EDSR		IXP2000_GPIO_REG(0x24)
-#define IXP2000_GPIO_LSHR		IXP2000_GPIO_REG(0x28)
-#define IXP2000_GPIO_LSLR		IXP2000_GPIO_REG(0x2c)
-#define IXP2000_GPIO_LDSR		IXP2000_GPIO_REG(0x30)
-#define IXP2000_GPIO_INER		IXP2000_GPIO_REG(0x34)
-#define IXP2000_GPIO_INSR		IXP2000_GPIO_REG(0x38)
-#define IXP2000_GPIO_INCR		IXP2000_GPIO_REG(0x3c)
-#define IXP2000_GPIO_INST		IXP2000_GPIO_REG(0x40)
-
-/*
- * "Global" registers...whatever that's supposed to mean.
- */
-#define GLOBAL_REG_BASE			(IXP2000_GLOBAL_REG_VIRT_BASE + 0x0a00)
-#define GLOBAL_REG(x)			(volatile unsigned long*)(GLOBAL_REG_BASE | (x))
-
-#define IXP2000_MAJ_PROD_TYPE_MASK	0x001F0000
-#define IXP2000_MAJ_PROD_TYPE_IXP2000	0x00000000
-#define IXP2000_MIN_PROD_TYPE_MASK 	0x0000FF00
-#define IXP2000_MIN_PROD_TYPE_IXP2400	0x00000200
-#define IXP2000_MIN_PROD_TYPE_IXP2850	0x00000100
-#define IXP2000_MIN_PROD_TYPE_IXP2800	0x00000000
-#define IXP2000_MAJ_REV_MASK	      	0x000000F0
-#define IXP2000_MIN_REV_MASK	      	0x0000000F
-#define IXP2000_PROD_ID_MASK		0xFFFFFFFF
-
-#define IXP2000_PRODUCT_ID		GLOBAL_REG(0x00)
-#define IXP2000_MISC_CONTROL		GLOBAL_REG(0x04)
-#define IXP2000_MSF_CLK_CNTRL  		GLOBAL_REG(0x08)
-#define IXP2000_RESET0      		GLOBAL_REG(0x0c)
-#define IXP2000_RESET1      		GLOBAL_REG(0x10)
-#define IXP2000_CCR            		GLOBAL_REG(0x14)
-#define	IXP2000_STRAP_OPTIONS  		GLOBAL_REG(0x18)
-
-#define	RSTALL				(1 << 16)
-#define	WDT_RESET_ENABLE		0x01000000
-
-
-/*
- * MSF registers.  The IXP2400 and IXP2800 have somewhat different MSF
- * units, but the registers that differ between the two don't overlap,
- * so we can have one register list for both.
- */
-#define IXP2000_MSF_REG(x)			((volatile unsigned long*)(IXP2000_MSF_VIRT_BASE + (x)))
-#define IXP2000_MSF_RX_CONTROL			IXP2000_MSF_REG(0x0000)
-#define IXP2000_MSF_TX_CONTROL			IXP2000_MSF_REG(0x0004)
-#define IXP2000_MSF_INTERRUPT_STATUS		IXP2000_MSF_REG(0x0008)
-#define IXP2000_MSF_INTERRUPT_ENABLE		IXP2000_MSF_REG(0x000c)
-#define IXP2000_MSF_CSIX_TYPE_MAP		IXP2000_MSF_REG(0x0010)
-#define IXP2000_MSF_FC_EGRESS_STATUS		IXP2000_MSF_REG(0x0014)
-#define IXP2000_MSF_FC_INGRESS_STATUS		IXP2000_MSF_REG(0x0018)
-#define IXP2000_MSF_HWM_CONTROL			IXP2000_MSF_REG(0x0024)
-#define IXP2000_MSF_FC_STATUS_OVERRIDE		IXP2000_MSF_REG(0x0028)
-#define IXP2000_MSF_CLOCK_CONTROL		IXP2000_MSF_REG(0x002c)
-#define IXP2000_MSF_RX_PORT_MAP			IXP2000_MSF_REG(0x0040)
-#define IXP2000_MSF_RBUF_ELEMENT_DONE		IXP2000_MSF_REG(0x0044)
-#define IXP2000_MSF_RX_MPHY_POLL_LIMIT		IXP2000_MSF_REG(0x0048)
-#define IXP2000_MSF_RX_CALENDAR_LENGTH		IXP2000_MSF_REG(0x0048)
-#define IXP2000_MSF_RX_THREAD_FREELIST_TIMEOUT_0	IXP2000_MSF_REG(0x0050)
-#define IXP2000_MSF_RX_THREAD_FREELIST_TIMEOUT_1	IXP2000_MSF_REG(0x0054)
-#define IXP2000_MSF_RX_THREAD_FREELIST_TIMEOUT_2	IXP2000_MSF_REG(0x0058)
-#define IXP2000_MSF_TX_SEQUENCE_0		IXP2000_MSF_REG(0x0060)
-#define IXP2000_MSF_TX_SEQUENCE_1		IXP2000_MSF_REG(0x0064)
-#define IXP2000_MSF_TX_SEQUENCE_2		IXP2000_MSF_REG(0x0068)
-#define IXP2000_MSF_TX_MPHY_POLL_LIMIT		IXP2000_MSF_REG(0x0070)
-#define IXP2000_MSF_TX_CALENDAR_LENGTH		IXP2000_MSF_REG(0x0070)
-#define IXP2000_MSF_RX_UP_CONTROL_0		IXP2000_MSF_REG(0x0080)
-#define IXP2000_MSF_RX_UP_CONTROL_1		IXP2000_MSF_REG(0x0084)
-#define IXP2000_MSF_RX_UP_CONTROL_2		IXP2000_MSF_REG(0x0088)
-#define IXP2000_MSF_RX_UP_CONTROL_3		IXP2000_MSF_REG(0x008c)
-#define IXP2000_MSF_TX_UP_CONTROL_0		IXP2000_MSF_REG(0x0090)
-#define IXP2000_MSF_TX_UP_CONTROL_1		IXP2000_MSF_REG(0x0094)
-#define IXP2000_MSF_TX_UP_CONTROL_2		IXP2000_MSF_REG(0x0098)
-#define IXP2000_MSF_TX_UP_CONTROL_3		IXP2000_MSF_REG(0x009c)
-#define IXP2000_MSF_TRAIN_DATA			IXP2000_MSF_REG(0x00a0)
-#define IXP2000_MSF_TRAIN_CALENDAR		IXP2000_MSF_REG(0x00a4)
-#define IXP2000_MSF_TRAIN_FLOW_CONTROL		IXP2000_MSF_REG(0x00a8)
-#define IXP2000_MSF_TX_CALENDAR_0		IXP2000_MSF_REG(0x1000)
-#define IXP2000_MSF_RX_PORT_CALENDAR_STATUS	IXP2000_MSF_REG(0x1400)
-
-
-#endif				/* _IXP2000_H_ */
diff --git a/arch/arm/mach-ixp2000/include/mach/memory.h b/arch/arm/mach-ixp2000/include/mach/memory.h
deleted file mode 100644
index 5f0c4fd..0000000
--- a/arch/arm/mach-ixp2000/include/mach/memory.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/memory.h
- *
- * Copyright (c) 2002 Intel Corp.
- * Copyright (c) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#define PLAT_PHYS_OFFSET	UL(0x00000000)
-
-#include <mach/ixp2000-regs.h>
-
-#define IXP2000_PCI_SDRAM_OFFSET	(*IXP2000_PCI_SDRAM_BAR & 0xfffffff0)
-
-#define __phys_to_bus(x)	((x) + (IXP2000_PCI_SDRAM_OFFSET - PHYS_OFFSET))
-#define __bus_to_phys(x)	((x) - (IXP2000_PCI_SDRAM_OFFSET - PHYS_OFFSET))
-
-#define __virt_to_bus(v)	__phys_to_bus(__virt_to_phys(v))
-#define __bus_to_virt(b)	__phys_to_virt(__bus_to_phys(b))
-#define __pfn_to_bus(p)		__phys_to_bus(__pfn_to_phys(p))
-#define __bus_to_pfn(b)		__phys_to_pfn(__bus_to_phys(b))
-
-#endif
-
diff --git a/arch/arm/mach-ixp2000/include/mach/platform.h b/arch/arm/mach-ixp2000/include/mach/platform.h
deleted file mode 100644
index 6b500c0..0000000
--- a/arch/arm/mach-ixp2000/include/mach/platform.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/platform.h
- *
- * Various bits of code used by platform-level code.
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2004 (c) MontaVista Software, 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 __ASSEMBLY__
-
-static inline unsigned long ixp2000_reg_read(volatile void *reg)
-{
-	return *((volatile unsigned long *)reg);
-}
-
-static inline void ixp2000_reg_write(volatile void *reg, unsigned long val)
-{
-	*((volatile unsigned long *)reg) = val;
-}
-
-/*
- * On the IXP2400, we can't use XCB=000 due to chip bugs.  We use
- * XCB=101 instead, but that makes all I/O accesses bufferable.  This
- * is not a problem in general, but we do have to be slightly more
- * careful because I/O writes are no longer automatically flushed out
- * of the write buffer.
- *
- * In cases where we want to make sure that a write has been flushed
- * out of the write buffer before we proceed, for example when masking
- * a device interrupt before re-enabling IRQs in CPSR, we can use this
- * function, ixp2000_reg_wrb, which performs a write, a readback, and
- * issues a dummy instruction dependent on the value of the readback
- * (mov rX, rX) to make sure that the readback has completed before we
- * continue.
- */
-static inline void ixp2000_reg_wrb(volatile void *reg, unsigned long val)
-{
-	unsigned long dummy;
-
-	*((volatile unsigned long *)reg) = val;
-
-	dummy = *((volatile unsigned long *)reg);
-	__asm__ __volatile__("mov %0, %0" : "+r" (dummy));
-}
-
-/*
- * Boards may multiplex different devices on the 2nd channel of 
- * the slowport interface that each need different configuration 
- * settings.  For example, the IXDP2400 uses channel 2 on the interface 
- * to access the CPLD, the switch fabric card, and the media card.  Each
- * one needs a different mode so drivers must save/restore the mode 
- * before and after each operation.  
- *
- * acquire_slowport(&your_config);
- * ...
- * do slowport operations
- * ...
- * release_slowport();
- *
- * Note that while you have the slowport, you are holding a spinlock,
- * so your code should be written as if you explicitly acquired a lock.
- *
- * The configuration only affects device 2 on the slowport, so the
- * MTD map driver does not acquire/release the slowport.  
- */
-struct slowport_cfg {
-	unsigned long CCR;	/* Clock divide */
-	unsigned long WTC;	/* Write Timing Control */
-	unsigned long RTC;	/* Read Timing Control */
-	unsigned long PCR;	/* Protocol Control Register */
-	unsigned long ADC;	/* Address/Data Width Control */
-};
-
-
-void ixp2000_acquire_slowport(struct slowport_cfg *, struct slowport_cfg *);
-void ixp2000_release_slowport(struct slowport_cfg *);
-
-/*
- * IXP2400 A0/A1 and  IXP2800 A0/A1/A2 have broken slowport that requires
- * tweaking of addresses in the MTD driver.
- */
-static inline unsigned ixp2000_has_broken_slowport(void)
-{
-	unsigned long id = *IXP2000_PRODUCT_ID;
-	unsigned long id_prod = id & (IXP2000_MAJ_PROD_TYPE_MASK |
-				      IXP2000_MIN_PROD_TYPE_MASK);
-	return (((id_prod ==
-		  /* fixed in IXP2400-B0 */
-		  (IXP2000_MAJ_PROD_TYPE_IXP2000 |
-		   IXP2000_MIN_PROD_TYPE_IXP2400)) &&
-		 ((id & IXP2000_MAJ_REV_MASK) == 0)) ||
-		((id_prod ==
-		  /* fixed in IXP2800-B0 */
-		  (IXP2000_MAJ_PROD_TYPE_IXP2000 |
-		   IXP2000_MIN_PROD_TYPE_IXP2800)) &&
-		 ((id & IXP2000_MAJ_REV_MASK) == 0)) ||
-		((id_prod ==
-		  /* fixed in IXP2850-B0 */
-		  (IXP2000_MAJ_PROD_TYPE_IXP2000 |
-		   IXP2000_MIN_PROD_TYPE_IXP2850)) &&
-		 ((id & IXP2000_MAJ_REV_MASK) == 0)));
-}
-
-static inline unsigned int ixp2000_has_flash(void)
-{
-	return ((*IXP2000_STRAP_OPTIONS) & (CFG_BOOT_PROM));
-}
-
-static inline unsigned int ixp2000_is_pcimaster(void)
-{
-	return ((*IXP2000_STRAP_OPTIONS) & (CFG_PCI_BOOT_HOST));
-}
-
-void ixp2000_map_io(void);
-void ixp2000_uart_init(void);
-void ixp2000_init_irq(void);
-void ixp2000_init_time(unsigned long);
-void ixp2000_restart(char, const char *);
-unsigned long ixp2000_gettimeoffset(void);
-
-struct pci_sys_data;
-
-extern struct pci_ops ixp2000_pci_ops;
-u32 *ixp2000_pci_config_addr(unsigned int bus, unsigned int devfn, int where);
-void ixp2000_pci_preinit(void);
-int ixp2000_pci_setup(int, struct pci_sys_data*);
-int ixp2000_pci_read_config(struct pci_bus*, unsigned int, int, int, u32 *);
-int ixp2000_pci_write_config(struct pci_bus*, unsigned int, int, int, u32);
-
-/*
- * Several of the IXP2000 systems have banked flash so we need to extend the
- * flash_platform_data structure with some private pointers
- */
-struct ixp2000_flash_data {
-	struct flash_platform_data *platform_data;
-	int nr_banks;
-	unsigned long (*bank_setup)(unsigned long);
-};
-
-struct ixp2000_i2c_pins {
-	unsigned long sda_pin;
-	unsigned long scl_pin;
-};
-
-
-#endif /*  !__ASSEMBLY__ */
diff --git a/arch/arm/mach-ixp2000/include/mach/timex.h b/arch/arm/mach-ixp2000/include/mach/timex.h
deleted file mode 100644
index 835e659..0000000
--- a/arch/arm/mach-ixp2000/include/mach/timex.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/timex.h
- *
- * IXP2000 architecture timex specifications
- */
-
-
-/*
- * Default clock is 50MHz APB, but platform code can override this
- */
-#define CLOCK_TICK_RATE	50000000
-
-
diff --git a/arch/arm/mach-ixp2000/include/mach/uncompress.h b/arch/arm/mach-ixp2000/include/mach/uncompress.h
deleted file mode 100644
index ce36308..0000000
--- a/arch/arm/mach-ixp2000/include/mach/uncompress.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/uncompress.h
- *
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2002 Intel Corp.
- *
- *  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/serial_reg.h>
-
-#define UART_BASE	0xc0030000
-
-#define PHYS(x)          ((volatile unsigned long *)(UART_BASE + x))
-
-#define UARTDR          PHYS(0x00)      /* Transmit reg dlab=0 */
-#define UARTDLL         PHYS(0x00)      /* Divisor Latch reg dlab=1*/
-#define UARTDLM         PHYS(0x04)      /* Divisor Latch reg dlab=1*/
-#define UARTIER         PHYS(0x04)      /* Interrupt enable reg */
-#define UARTFCR         PHYS(0x08)      /* FIFO control reg dlab =0*/
-#define UARTLCR         PHYS(0x0c)      /* Control reg */
-#define UARTSR          PHYS(0x14)      /* Status reg */
-
-
-static inline void putc(int c)
-{
-	int j = 0x1000;
-
-	while (--j && !(*UARTSR & UART_LSR_THRE))
-		barrier();
-
-	*UARTDR = c;
-}
-
-static inline void flush(void)
-{
-}
-
-#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
deleted file mode 100644
index 4ec4480..0000000
--- a/arch/arm/mach-ixp2000/ixdp2400.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/ixdp2400.c
- *
- * IXDP2400 platform support
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/arch.h>
-
-/*************************************************************************
- * IXDP2400 timer tick
- *************************************************************************/
-static void __init ixdp2400_timer_init(void)
-{
-	int numerator, denominator;
-	int denom_array[] = {2, 4, 8, 16, 1, 2, 4, 8};
-
-	numerator = (*(IXDP2400_CPLD_SYS_CLK_M) & 0xFF) *2;
-	denominator = denom_array[(*(IXDP2400_CPLD_SYS_CLK_N) & 0x7)];
-
-	ixp2000_init_time(((3125000 * numerator) / (denominator)) / 2);
-}
-
-static struct sys_timer ixdp2400_timer = {
-	.init		= ixdp2400_timer_init,
-	.offset		= ixp2000_gettimeoffset,
-};
-
-/*************************************************************************
- * IXDP2400 PCI
- *************************************************************************/
-void __init ixdp2400_pci_preinit(void)
-{
-	ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00100000);
-	ixp2000_pci_preinit();
-	pcibios_setup("firmware");
-}
-
-int ixdp2400_pci_setup(int nr, struct pci_sys_data *sys)
-{
-	sys->mem_offset = 0xe0000000;
-
-	ixp2000_pci_setup(nr, sys);
-
-	return 1;
-}
-
-static int __init ixdp2400_pci_map_irq(const struct pci_dev *dev, u8 slot,
-	u8 pin)
-{
-	if (ixdp2x00_master_npu()) {
-
-		/*
-		 * Root bus devices.  Slave NPU is only one with interrupt.
-		 * Everything else, we just return -1 b/c nothing else
-		 * on the root bus has interrupts.
-		 */
-		if(!dev->bus->self) {
-			if(dev->devfn == IXDP2X00_SLAVE_NPU_DEVFN )
-				return IRQ_IXDP2400_INGRESS_NPU;
-
-			return -1;
-		}
-
-		/*
-		 * Bridge behind the PMC slot.
-		 * NOTE: Only INTA from the PMC slot is routed. VERY BAD.
-		 */
-		if(dev->bus->self->devfn == IXDP2X00_PMC_DEVFN &&
-			dev->bus->parent->self->devfn == IXDP2X00_P2P_DEVFN &&
-			!dev->bus->parent->self->bus->parent)
-				  return IRQ_IXDP2400_PMC;
-
-		/*
-		 * Device behind the first bridge
-		 */
-		if(dev->bus->self->devfn == IXDP2X00_P2P_DEVFN) {
-			switch(dev->devfn) {
-				case IXDP2400_MASTER_ENET_DEVFN:	
-					return IRQ_IXDP2400_ENET;	
-			
-				case IXDP2400_MEDIA_DEVFN:
-					return IRQ_IXDP2400_MEDIA_PCI;
-
-				case IXDP2400_SWITCH_FABRIC_DEVFN:
-					return IRQ_IXDP2400_SF_PCI;
-
-				case IXDP2X00_PMC_DEVFN:
-					return IRQ_IXDP2400_PMC;
-			}
-		}
-
-		return -1;
-	} else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
-}
-
-
-static void ixdp2400_pci_postinit(void)
-{
-	struct pci_dev *dev;
-
-	if (ixdp2x00_master_npu()) {
-		dev = pci_get_bus_and_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
-		pci_stop_and_remove_bus_device(dev);
-		pci_dev_put(dev);
-	} else {
-		dev = pci_get_bus_and_slot(1, IXDP2400_MASTER_ENET_DEVFN);
-		pci_stop_and_remove_bus_device(dev);
-		pci_dev_put(dev);
-
-		ixdp2x00_slave_pci_postinit();
-	}
-}
-
-static struct hw_pci ixdp2400_pci __initdata = {
-	.nr_controllers	= 1,
-	.ops		= &ixp2000_pci_ops,
-	.setup		= ixdp2400_pci_setup,
-	.preinit	= ixdp2400_pci_preinit,
-	.postinit	= ixdp2400_pci_postinit,
-	.map_irq	= ixdp2400_pci_map_irq,
-};
-
-int __init ixdp2400_pci_init(void)
-{
-	if (machine_is_ixdp2400())
-		pci_common_init(&ixdp2400_pci);
-
-	return 0;
-}
-
-subsys_initcall(ixdp2400_pci_init);
-
-void __init ixdp2400_init_irq(void)
-{
-	ixdp2x00_init_irq(IXDP2400_CPLD_INT_STAT, IXDP2400_CPLD_INT_MASK, IXDP2400_NR_IRQS);
-}
-
-MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
-	/* Maintainer: MontaVista Software, Inc. */
-	.atag_offset	= 0x100,
-	.map_io		= ixdp2x00_map_io,
-	.init_irq	= ixdp2400_init_irq,
-	.timer		= &ixdp2400_timer,
-	.init_machine	= ixdp2x00_init_machine,
-	.restart	= ixp2000_restart,
-MACHINE_END
-
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
deleted file mode 100644
index 44378c3..0000000
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/ixdp2800.c
- *
- * IXDP2800 platform support
- *
- * Original Author: Jeffrey Daly <jeffrey.daly@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/arch.h>
-
-/*************************************************************************
- * IXDP2800 timer tick
- *************************************************************************/
-
-static void __init ixdp2800_timer_init(void)
-{
-	ixp2000_init_time(50000000);
-}
-
-static struct sys_timer ixdp2800_timer = {
-	.init		= ixdp2800_timer_init,
-	.offset		= ixp2000_gettimeoffset,
-};
-
-/*************************************************************************
- * IXDP2800 PCI
- *************************************************************************/
-static void __init ixdp2800_slave_disable_pci_master(void)
-{
-	*IXP2000_PCI_CMDSTAT &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
-}
-
-static void __init ixdp2800_master_wait_for_slave(void)
-{
-	volatile u32 *addr;
-
-	printk(KERN_INFO "IXDP2800: waiting for slave NPU to configure "
-			 "its BAR sizes\n");
-
-	addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
-					PCI_BASE_ADDRESS_1);
-	do {
-		*addr = 0xffffffff;
-		cpu_relax();
-	} while (*addr != 0xfe000008);
-
-	addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
-					PCI_BASE_ADDRESS_2);
-	do {
-		*addr = 0xffffffff;
-		cpu_relax();
-	} while (*addr != 0xc0000008);
-
-	/*
-	 * Configure the slave's SDRAM BAR by hand.
-	 */
-	*addr = 0x40000008;
-}
-
-static void __init ixdp2800_slave_wait_for_master_enable(void)
-{
-	printk(KERN_INFO "IXDP2800: waiting for master NPU to enable us\n");
-
-	while ((*IXP2000_PCI_CMDSTAT & PCI_COMMAND_MASTER) == 0)
-		cpu_relax();
-}
-
-void __init ixdp2800_pci_preinit(void)
-{
-	printk("ixdp2x00_pci_preinit called\n");
-
-	*IXP2000_PCI_ADDR_EXT = 0x0001e000;
-
-	if (!ixdp2x00_master_npu())
-		ixdp2800_slave_disable_pci_master();
-
-	*IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff;
-	*IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
-
-	ixp2000_pci_preinit();
-
-	if (ixdp2x00_master_npu()) {
-		/*
-		 * Wait until the slave set its SRAM/SDRAM BAR sizes
-		 * correctly before we proceed to scan and enumerate
-		 * the bus.
-		 */
-		ixdp2800_master_wait_for_slave();
-
-		/*
-		 * We configure the SDRAM BARs by hand because they
-		 * are 1G and fall outside of the regular allocated
-		 * PCI address space.
-		 */
-		*IXP2000_PCI_SDRAM_BAR = 0x00000008;
-	} else {
-		/*
-		 * Wait for the master to complete scanning the bus
-		 * and assigning resources before we proceed to scan
-		 * the bus ourselves.  Set pci=firmware to honor the
-		 * master's resource assignment.
-		 */
-		ixdp2800_slave_wait_for_master_enable();
-		pcibios_setup("firmware");
-	}
-}
-
-/*
- * We assign the SDRAM BARs for the two IXP2800 CPUs by hand, outside
- * of the regular PCI window, because there's only 512M of outbound PCI
- * memory window on each IXP, while we need 1G for each of the BARs.
- */
-static void __devinit ixp2800_pci_fixup(struct pci_dev *dev)
-{
-	if (machine_is_ixdp2800()) {
-		dev->resource[2].start = 0;
-		dev->resource[2].end   = 0;
-		dev->resource[2].flags = 0;
-	}
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IXP2800, ixp2800_pci_fixup);
-
-static int __init ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
-{
-	sys->mem_offset = 0x00000000;
-
-	ixp2000_pci_setup(nr, sys);
-
-	return 1;
-}
-
-static int __init ixdp2800_pci_map_irq(const struct pci_dev *dev, u8 slot,
-	u8 pin)
-{
-	if (ixdp2x00_master_npu()) {
-
-		/*
-		 * Root bus devices.  Slave NPU is only one with interrupt.
-		 * Everything else, we just return -1 which is invalid.
-		 */
-		if(!dev->bus->self) {
-			if(dev->devfn == IXDP2X00_SLAVE_NPU_DEVFN )
-				return IRQ_IXDP2800_INGRESS_NPU;
-
-			return -1;
-		}
-
-		/*
-		 * Bridge behind the PMC slot.
-		 */
-		if(dev->bus->self->devfn == IXDP2X00_PMC_DEVFN &&
-			dev->bus->parent->self->devfn == IXDP2X00_P2P_DEVFN &&
-			!dev->bus->parent->self->bus->parent)
-				  return IRQ_IXDP2800_PMC;
-
-		/*
-		 * Device behind the first bridge
-		 */
-		if(dev->bus->self->devfn == IXDP2X00_P2P_DEVFN) {
-			switch(dev->devfn) {
-				case IXDP2X00_PMC_DEVFN:
-					return IRQ_IXDP2800_PMC;	
-			
-				case IXDP2800_MASTER_ENET_DEVFN:
-					return IRQ_IXDP2800_EGRESS_ENET;
-
-				case IXDP2800_SWITCH_FABRIC_DEVFN:
-					return IRQ_IXDP2800_FABRIC;
-			}
-		}
-
-		return -1;
-	} else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
-}
-
-static void __init ixdp2800_master_enable_slave(void)
-{
-	volatile u32 *addr;
-
-	printk(KERN_INFO "IXDP2800: enabling slave NPU\n");
-
-	addr = (volatile u32 *)ixp2000_pci_config_addr(0,
-					IXDP2X00_SLAVE_NPU_DEVFN,
-					PCI_COMMAND);
-
-	*addr |= PCI_COMMAND_MASTER;
-}
-
-static void __init ixdp2800_master_wait_for_slave_bus_scan(void)
-{
-	volatile u32 *addr;
-
-	printk(KERN_INFO "IXDP2800: waiting for slave to finish bus scan\n");
-
-	addr = (volatile u32 *)ixp2000_pci_config_addr(0,
-					IXDP2X00_SLAVE_NPU_DEVFN,
-					PCI_COMMAND);
-	while ((*addr & PCI_COMMAND_MEMORY) == 0)
-		cpu_relax();
-}
-
-static void __init ixdp2800_slave_signal_bus_scan_completion(void)
-{
-	printk(KERN_INFO "IXDP2800: bus scan done, signaling master\n");
-	*IXP2000_PCI_CMDSTAT |= PCI_COMMAND_MEMORY;
-}
-
-static void __init ixdp2800_pci_postinit(void)
-{
-	if (!ixdp2x00_master_npu()) {
-		ixdp2x00_slave_pci_postinit();
-		ixdp2800_slave_signal_bus_scan_completion();
-	}
-}
-
-struct __initdata hw_pci ixdp2800_pci __initdata = {
-	.nr_controllers	= 1,
-	.ops		= &ixp2000_pci_ops,
-	.setup		= ixdp2800_pci_setup,
-	.preinit	= ixdp2800_pci_preinit,
-	.postinit	= ixdp2800_pci_postinit,
-	.map_irq	= ixdp2800_pci_map_irq,
-};
-
-int __init ixdp2800_pci_init(void)
-{
-	if (machine_is_ixdp2800()) {
-		struct pci_dev *dev;
-
-		pci_common_init(&ixdp2800_pci);
-		if (ixdp2x00_master_npu()) {
-			dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
-			pci_stop_and_remove_bus_device(dev);
-			pci_dev_put(dev);
-
-			ixdp2800_master_enable_slave();
-			ixdp2800_master_wait_for_slave_bus_scan();
-		} else {
-			dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN);
-			pci_stop_and_remove_bus_device(dev);
-			pci_dev_put(dev);
-		}
-	}
-
-	return 0;
-}
-
-subsys_initcall(ixdp2800_pci_init);
-
-void __init ixdp2800_init_irq(void)
-{
-	ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2800_NR_IRQS);
-}
-
-MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
-	/* Maintainer: MontaVista Software, Inc. */
-	.atag_offset	= 0x100,
-	.map_io		= ixdp2x00_map_io,
-	.init_irq	= ixdp2800_init_irq,
-	.timer		= &ixdp2800_timer,
-	.init_machine	= ixdp2x00_init_machine,
-	.restart	= ixp2000_restart,
-MACHINE_END
-
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
deleted file mode 100644
index 421e38d..0000000
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/ixdp2x00.c
- *
- * Code common to IXDP2400 and IXDP2800 platforms.
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/arch.h>
-
-#include <mach/gpio-ixp2000.h>
-
-/*************************************************************************
- * IXDP2x00 IRQ Initialization
- *************************************************************************/
-static volatile unsigned long *board_irq_mask;
-static volatile unsigned long *board_irq_stat;
-static unsigned long board_irq_count;
-
-#ifdef CONFIG_ARCH_IXDP2400
-/*
- * Slowport configuration for accessing CPLD registers on IXDP2x00
- */
-static struct slowport_cfg slowport_cpld_cfg = {
-	.CCR =	SLOWPORT_CCR_DIV_2,
-	.WTC = 0x00000070,
-	.RTC = 0x00000070,
-	.PCR = SLOWPORT_MODE_FLASH,
-	.ADC = SLOWPORT_ADDR_WIDTH_24 | SLOWPORT_DATA_WIDTH_8
-};
-#endif
-
-static void ixdp2x00_irq_mask(struct irq_data *d)
-{
-	unsigned long dummy;
-	static struct slowport_cfg old_cfg;
-
-	/*
-	 * This is ugly in common code but really don't know
-	 * of a better way to handle it. :(
-	 */
-#ifdef CONFIG_ARCH_IXDP2400
-	if (machine_is_ixdp2400())
-		ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
-#endif
-
-	dummy = *board_irq_mask;
-	dummy |=  IXP2000_BOARD_IRQ_MASK(d->irq);
-	ixp2000_reg_wrb(board_irq_mask, dummy);
-
-#ifdef CONFIG_ARCH_IXDP2400
-	if (machine_is_ixdp2400())
-		ixp2000_release_slowport(&old_cfg);
-#endif
-}
-
-static void ixdp2x00_irq_unmask(struct irq_data *d)
-{
-	unsigned long dummy;
-	static struct slowport_cfg old_cfg;
-
-#ifdef CONFIG_ARCH_IXDP2400
-	if (machine_is_ixdp2400())
-		ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
-#endif
-
-	dummy = *board_irq_mask;
-	dummy &=  ~IXP2000_BOARD_IRQ_MASK(d->irq);
-	ixp2000_reg_wrb(board_irq_mask, dummy);
-
-	if (machine_is_ixdp2400()) 
-		ixp2000_release_slowport(&old_cfg);
-}
-
-static void ixdp2x00_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-        volatile u32 ex_interrupt = 0;
-	static struct slowport_cfg old_cfg;
-	int i;
-
-	desc->irq_data.chip->irq_mask(&desc->irq_data);
-
-#ifdef CONFIG_ARCH_IXDP2400
-	if (machine_is_ixdp2400())
-		ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
-#endif
-        ex_interrupt = *board_irq_stat & 0xff;
-	if (machine_is_ixdp2400())
-		ixp2000_release_slowport(&old_cfg);
-
-	if(!ex_interrupt) {
-		printk(KERN_ERR "Spurious IXDP2x00 CPLD interrupt!\n");
-		return;
-	}
-
-	for(i = 0; i < board_irq_count; i++) {
-		if(ex_interrupt & (1 << i))  {
-			int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
-			generic_handle_irq(cpld_irq);
-		}
-	}
-
-	desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixdp2x00_cpld_irq_chip = {
-	.irq_ack	= ixdp2x00_irq_mask,
-	.irq_mask	= ixdp2x00_irq_mask,
-	.irq_unmask	= ixdp2x00_irq_unmask
-};
-
-void __init ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_of_irqs)
-{
-	unsigned int irq;
-
-	ixp2000_init_irq();
-	
-	if (!ixdp2x00_master_npu())
-		return;
-
-	board_irq_stat = stat_reg;
-	board_irq_mask = mask_reg;
-	board_irq_count = nr_of_irqs;
-
-	*board_irq_mask = 0xffffffff;
-
-	for(irq = IXP2000_BOARD_IRQ(0); irq < IXP2000_BOARD_IRQ(board_irq_count); irq++) {
-		irq_set_chip_and_handler(irq, &ixdp2x00_cpld_irq_chip,
-					 handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-
-	/* Hook into PCI interrupt */
-	irq_set_chained_handler(IRQ_IXP2000_PCIB, ixdp2x00_irq_handler);
-}
-
-/*************************************************************************
- * IXDP2x00 memory map
- *************************************************************************/
-static struct map_desc ixdp2x00_io_desc __initdata = {
-	.virtual	= IXDP2X00_VIRT_CPLD_BASE, 
-	.pfn		= __phys_to_pfn(IXDP2X00_PHYS_CPLD_BASE),
-	.length		= IXDP2X00_CPLD_SIZE,
-	.type		= MT_DEVICE
-};
-
-void __init ixdp2x00_map_io(void)
-{
-	ixp2000_map_io();	
-
-	iotable_init(&ixdp2x00_io_desc, 1);
-}
-
-/*************************************************************************
- * IXDP2x00-common PCI init
- *
- * The IXDP2[48]00 has a horrid PCI bus layout. Basically the board 
- * contains two NPUs (ingress and egress) connected over PCI,  both running 
- * instances  of the kernel. So far so good. Peers on the PCI bus running 
- * Linux is a common design in telecom systems. The problem is that instead 
- * of all the devices being controlled by a single host, different
- * devices are controlled by different NPUs on the same bus, leading to
- * multiple hosts on the bus. The exact bus layout looks like:
- *
- *                   Bus 0
- *    Master NPU <-------------------+-------------------> Slave NPU
- *                                   |
- *                                   |
- *                                  P2P 
- *                                   |
- *
- *                  Bus 1            |
- *               <--+------+---------+---------+------+-->
- *                  |      |         |         |      |
- *                  |      |         |         |      |
- *             ... Dev    PMC       Media     Eth0   Eth1 ...
- *
- * The master controls all but Eth1, which is controlled by the
- * slave. What this means is that the both the master and the slave
- * have to scan the bus, but only one of them can enumerate the bus.
- * In addition, after the bus is scanned, each kernel must remove
- * the device(s) it does not control from the PCI dev list otherwise
- * a driver on each NPU will try to manage it and we will have horrible
- * conflicts. Oh..and the slave NPU needs to see the master NPU
- * for Intel's drivers to work properly. Closed source drivers...
- *
- * The way we deal with this is fairly simple but ugly:
- *
- * 1) Let master scan and enumerate the bus completely.
- * 2) Master deletes Eth1 from device list.
- * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave)
- *    from device list.
- * 4) Find HW designers and LART them.
- *
- * The boards also do not do normal PCI IRQ routing, or any sort of 
- * sensical  swizzling, so we just need to check where on the  bus a
- * device sits and figure out to which CPLD pin the interrupt is routed.
- * See ixdp2[48]00.c files.
- *
- *************************************************************************/
-void ixdp2x00_slave_pci_postinit(void)
-{
-	struct pci_dev *dev;
-
-	/*
-	 * Remove PMC device is there is one
-	 */
-	if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) {
-		pci_stop_and_remove_bus_device(dev);
-		pci_dev_put(dev);
-	}
-
-	dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN);
-	pci_stop_and_remove_bus_device(dev);
-	pci_dev_put(dev);
-}
-
-/**************************************************************************
- * IXDP2x00 Machine Setup
- *************************************************************************/
-static struct flash_platform_data ixdp2x00_platform_data = {
-	.map_name	= "cfi_probe",
-	.width		= 1,
-};
-
-static struct ixp2000_flash_data ixdp2x00_flash_data = {
-	.platform_data	= &ixdp2x00_platform_data,
-	.nr_banks	= 1
-};
-
-static struct resource ixdp2x00_flash_resource = {
-	.start		= 0xc4000000,
-	.end		= 0xc4000000 + 0x00ffffff,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2x00_flash = {
-	.name		= "IXP2000-Flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data = &ixdp2x00_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &ixdp2x00_flash_resource,
-};
-
-static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = {
-	.sda_pin	= IXDP2X00_GPIO_SDA,
-	.scl_pin	= IXDP2X00_GPIO_SCL,
-};
-
-static struct platform_device ixdp2x00_i2c_controller = {
-	.name		= "IXP2000-I2C",
-	.id		= 0,
-	.dev		= {
-		.platform_data = &ixdp2x00_i2c_gpio_pins,
-	},
-	.num_resources	= 0
-};
-
-static struct platform_device *ixdp2x00_devices[] __initdata = {
-	&ixdp2x00_flash,
-	&ixdp2x00_i2c_controller
-};
-
-void __init ixdp2x00_init_machine(void)
-{
-	gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1);
-	gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT);
-
-	platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices));
-	ixp2000_uart_init();
-}
-
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
deleted file mode 100644
index af8b801..0000000
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/ixdp2x01.c
- *
- * Code common to Intel IXDP2401 and IXDP2801 platforms
- *
- * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002-2003 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-
-/*************************************************************************
- * IXDP2x01 IRQ Handling
- *************************************************************************/
-static void ixdp2x01_irq_mask(struct irq_data *d)
-{
-	ixp2000_reg_wrb(IXDP2X01_INT_MASK_SET_REG,
-				IXP2000_BOARD_IRQ_MASK(d->irq));
-}
-
-static void ixdp2x01_irq_unmask(struct irq_data *d)
-{
-	ixp2000_reg_write(IXDP2X01_INT_MASK_CLR_REG,
-				IXP2000_BOARD_IRQ_MASK(d->irq));
-}
-
-static u32 valid_irq_mask;
-
-static void ixdp2x01_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-	u32 ex_interrupt;
-	int i;
-
-	desc->irq_data.chip->irq_mask(&desc->irq_data);
-
-	ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask;
-
-	if (!ex_interrupt) {
-		printk(KERN_ERR "Spurious IXDP2X01 CPLD interrupt!\n");
-		return;
-	}
-
-	for (i = 0; i < IXP2000_BOARD_IRQS; i++) {
-		if (ex_interrupt & (1 << i)) {
-			int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
-			generic_handle_irq(cpld_irq);
-		}
-	}
-
-	desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixdp2x01_irq_chip = {
-	.irq_mask	= ixdp2x01_irq_mask,
-	.irq_ack	= ixdp2x01_irq_mask,
-	.irq_unmask	= ixdp2x01_irq_unmask
-};
-
-/*
- * We only do anything if we are the master NPU on the board.
- * The slave NPU only has the ethernet chip going directly to
- * the PCIB interrupt input.
- */
-void __init ixdp2x01_init_irq(void)
-{
-	int irq = 0;
-
-	/* initialize chip specific interrupts */
-	ixp2000_init_irq();
-
-	if (machine_is_ixdp2401())
-		valid_irq_mask = IXDP2401_VALID_IRQ_MASK;
-	else
-		valid_irq_mask = IXDP2801_VALID_IRQ_MASK;
-
-	/* Mask all interrupts from CPLD, disable simulation */
-	ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff);
-	ixp2000_reg_wrb(IXDP2X01_INT_SIM_REG, 0);
-
-	for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) {
-		if (irq & valid_irq_mask) {
-			irq_set_chip_and_handler(irq, &ixdp2x01_irq_chip,
-						 handle_level_irq);
-			set_irq_flags(irq, IRQF_VALID);
-		} else {
-			set_irq_flags(irq, 0);
-		}
-	}
-
-	/* Hook into PCI interrupts */
-	irq_set_chained_handler(IRQ_IXP2000_PCIB, ixdp2x01_irq_handler);
-}
-
-
-/*************************************************************************
- * IXDP2x01 memory map
- *************************************************************************/
-static struct map_desc ixdp2x01_io_desc __initdata = {
-	.virtual	= IXDP2X01_VIRT_CPLD_BASE, 
-	.pfn		= __phys_to_pfn(IXDP2X01_PHYS_CPLD_BASE),
-	.length		= IXDP2X01_CPLD_REGION_SIZE,
-	.type		= MT_DEVICE
-};
-
-static void __init ixdp2x01_map_io(void)
-{
-	ixp2000_map_io();
-	iotable_init(&ixdp2x01_io_desc, 1);
-}
-
-
-/*************************************************************************
- * IXDP2x01 serial ports
- *************************************************************************/
-static struct plat_serial8250_port ixdp2x01_serial_port1[] = {
-	{
-		.mapbase	= (unsigned long)IXDP2X01_UART1_PHYS_BASE,
-		.membase	= (char *)IXDP2X01_UART1_VIRT_BASE,
-		.irq		= IRQ_IXDP2X01_UART1,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
-		.iotype		= UPIO_MEM32,
-		.regshift	= 2,
-		.uartclk	= IXDP2X01_UART_CLK,
-	},
-	{ }
-};
-
-static struct resource ixdp2x01_uart_resource1 = {
-	.start		= IXDP2X01_UART1_PHYS_BASE,
-	.end		= IXDP2X01_UART1_PHYS_BASE + 0xffff,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2x01_serial_device1 = {
-	.name		= "serial8250",
-	.id		= PLAT8250_DEV_PLATFORM1,
-	.dev		= {
-		.platform_data		= ixdp2x01_serial_port1,
-	},
-	.num_resources	= 1,
-	.resource	= &ixdp2x01_uart_resource1,
-};
-
-static struct plat_serial8250_port ixdp2x01_serial_port2[] = {
-	{
-		.mapbase	= (unsigned long)IXDP2X01_UART2_PHYS_BASE,
-		.membase	= (char *)IXDP2X01_UART2_VIRT_BASE,
-		.irq		= IRQ_IXDP2X01_UART2,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
-		.iotype		= UPIO_MEM32,
-		.regshift	= 2,
-		.uartclk	= IXDP2X01_UART_CLK,
-	}, 
-	{ }
-};
-
-static struct resource ixdp2x01_uart_resource2 = {
-	.start		= IXDP2X01_UART2_PHYS_BASE,
-	.end		= IXDP2X01_UART2_PHYS_BASE + 0xffff,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2x01_serial_device2 = {
-	.name		= "serial8250",
-	.id		= PLAT8250_DEV_PLATFORM2,
-	.dev		= {
-		.platform_data		= ixdp2x01_serial_port2,
-	},
-	.num_resources	= 1,
-	.resource	= &ixdp2x01_uart_resource2,
-};
-
-static void ixdp2x01_uart_init(void)
-{
-	platform_device_register(&ixdp2x01_serial_device1);
-	platform_device_register(&ixdp2x01_serial_device2);
-}
-
-
-/*************************************************************************
- * IXDP2x01 timer tick configuration
- *************************************************************************/
-static unsigned int ixdp2x01_clock;
-
-static int __init ixdp2x01_clock_setup(char *str)
-{
-	ixdp2x01_clock = simple_strtoul(str, NULL, 10);
-
-	return 1;
-}
-
-__setup("ixdp2x01_clock=", ixdp2x01_clock_setup);
-
-static void __init ixdp2x01_timer_init(void)
-{
-	if (!ixdp2x01_clock)
-		ixdp2x01_clock = 50000000;
-
-	ixp2000_init_time(ixdp2x01_clock);
-}
-
-static struct sys_timer ixdp2x01_timer = {
-	.init		= ixdp2x01_timer_init,
-	.offset		= ixp2000_gettimeoffset,
-};
-
-/*************************************************************************
- * IXDP2x01 PCI
- *************************************************************************/
-void __init ixdp2x01_pci_preinit(void)
-{
-	ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00000000);
-	ixp2000_pci_preinit();
-	pcibios_setup("firmware");
-}
-
-#define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
-
-static int __init ixdp2x01_pci_map_irq(const struct pci_dev *dev, u8 slot,
-	u8 pin)
-{
-	u8 bus = dev->bus->number;
-	u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
-	struct pci_bus *tmp_bus = dev->bus;
-
-	/* Primary bus, no interrupts here */
-	if (bus == 0) {
-		return -1;
-	}
-
-	/* Lookup first leaf in bus tree */
-	while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) {
-		tmp_bus = tmp_bus->parent;
-	}
-
-	/* Select between known bridges */
-	switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) {
-	/* Device is located after first MB bridge */
-	case 0x0008:
-		if (tmp_bus == dev->bus) {
-			/* Device is located directly after first MB bridge */
-			switch (devpin) {
-			case DEVPIN(1, 1):	/* Onboard 82546 ch 0 */
-				if (machine_is_ixdp2401())
-					return IRQ_IXDP2401_INTA_82546;
-				return -1;
-			case DEVPIN(1, 2):	/* Onboard 82546 ch 1 */
-				if (machine_is_ixdp2401())
-					return IRQ_IXDP2401_INTB_82546;
-				return -1;
-			case DEVPIN(0, 1):	/* PMC INTA# */
-				return IRQ_IXDP2X01_SPCI_PMC_INTA;
-			case DEVPIN(0, 2):	/* PMC INTB# */
-				return IRQ_IXDP2X01_SPCI_PMC_INTB;
-			case DEVPIN(0, 3):	/* PMC INTC# */
-				return IRQ_IXDP2X01_SPCI_PMC_INTC;
-			case DEVPIN(0, 4):	/* PMC INTD# */
-				return IRQ_IXDP2X01_SPCI_PMC_INTD;
-			}
-		}
-		break;
-	case 0x0010:
-		if (tmp_bus == dev->bus) {
-			/* Device is located directly after second MB bridge */
-			/* Secondary bus of second bridge */
-			switch (devpin) {
-			case DEVPIN(0, 1):	/* DB#0 */
-				return IRQ_IXDP2X01_SPCI_DB_0;
-			case DEVPIN(1, 1):	/* DB#1 */
-				return IRQ_IXDP2X01_SPCI_DB_1;
-			}
-		} else {
-			/* Device is located indirectly after second MB bridge */
-			/* Not supported now */
-		}
-		break;
-	}
-
-	return -1;
-}
-
-
-static int ixdp2x01_pci_setup(int nr, struct pci_sys_data *sys)
-{
-	sys->mem_offset = 0xe0000000;
-
-	if (machine_is_ixdp2801() || machine_is_ixdp28x5())
-		sys->mem_offset -= ((*IXP2000_PCI_ADDR_EXT & 0xE000) << 16);
-
-	return ixp2000_pci_setup(nr, sys);
-}
-
-struct hw_pci ixdp2x01_pci __initdata = {
-	.nr_controllers	= 1,
-	.ops		= &ixp2000_pci_ops,
-	.setup		= ixdp2x01_pci_setup,
-	.preinit	= ixdp2x01_pci_preinit,
-	.map_irq	= ixdp2x01_pci_map_irq,
-};
-
-int __init ixdp2x01_pci_init(void)
-{
-	if (machine_is_ixdp2401() || machine_is_ixdp2801() ||\
-		machine_is_ixdp28x5())
-		pci_common_init(&ixdp2x01_pci);
-
-	return 0;
-}
-
-subsys_initcall(ixdp2x01_pci_init);
-
-/*************************************************************************
- * IXDP2x01 Machine Initialization
- *************************************************************************/
-static struct flash_platform_data ixdp2x01_flash_platform_data = {
-	.map_name	= "cfi_probe",
-	.width		= 1,
-};
-
-static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs)
-{
-	ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG,
-		((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN));
-	return (ofs & IXDP2X01_FLASH_WINDOW_MASK);
-}
-
-static struct ixp2000_flash_data ixdp2x01_flash_data = {
-	.platform_data	= &ixdp2x01_flash_platform_data,
-	.bank_setup	= ixdp2x01_flash_bank_setup
-};
-
-static struct resource ixdp2x01_flash_resource = {
-	.start		= 0xc4000000,
-	.end		= 0xc4000000 + 0x01ffffff,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2x01_flash = {
-	.name		= "IXP2000-Flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data = &ixdp2x01_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &ixdp2x01_flash_resource,
-};
-
-static struct ixp2000_i2c_pins ixdp2x01_i2c_gpio_pins = {
-	.sda_pin	= IXDP2X01_GPIO_SDA,
-	.scl_pin	= IXDP2X01_GPIO_SCL,
-};
-
-static struct platform_device ixdp2x01_i2c_controller = {
-	.name		= "IXP2000-I2C",
-	.id		= 0,
-	.dev		= {
-		.platform_data = &ixdp2x01_i2c_gpio_pins,
-	},
-	.num_resources	= 0
-};
-
-static struct platform_device *ixdp2x01_devices[] __initdata = {
-	&ixdp2x01_flash,
-	&ixdp2x01_i2c_controller
-};
-
-static void __init ixdp2x01_init_machine(void)
-{
-	ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG,
-		(IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN));
-	
-	ixdp2x01_flash_data.nr_banks =
-		((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1);
-
-	platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices));
-	ixp2000_uart_init();
-	ixdp2x01_uart_init();
-}
-
-static void ixdp2401_restart(char mode, const char *cmd)
-{
-	/*
-	 * Reset flash banking register so that we are pointing at
-	 * RedBoot bank.
-	 */
-	ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG,
-				((0 >> IXDP2X01_FLASH_WINDOW_BITS)
-					| IXDP2X01_CPLD_FLASH_INTERN));
-	ixp2000_reg_wrb(IXDP2X01_CPLD_RESET_REG, 0xffffffff);
-
-	ixp2000_restart(mode, cmd);
-}
-
-static void ixdp280x_restart(char mode, const char *cmd)
-{
-	/*
-	 * On IXDP2801 we need to write this magic sequence to the CPLD
-	 * to cause a complete reset of the CPU and all external devices
-	 * and move the flash bank register back to 0.
-	 */
-	unsigned long reset_reg = *IXDP2X01_CPLD_RESET_REG;
-
-	reset_reg = 0x55AA0000 | (reset_reg & 0x0000FFFF);
-	ixp2000_reg_write(IXDP2X01_CPLD_RESET_REG, reset_reg);
-	ixp2000_reg_wrb(IXDP2X01_CPLD_RESET_REG, 0x80000000);
-
-	ixp2000_restart(mode, cmd);
-}
-
-#ifdef CONFIG_ARCH_IXDP2401
-MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
-	/* Maintainer: MontaVista Software, Inc. */
-	.atag_offset	= 0x100,
-	.map_io		= ixdp2x01_map_io,
-	.init_irq	= ixdp2x01_init_irq,
-	.timer		= &ixdp2x01_timer,
-	.init_machine	= ixdp2x01_init_machine,
-	.restart	= ixdp2401_restart,
-MACHINE_END
-#endif
-
-#ifdef CONFIG_ARCH_IXDP2801
-MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
-	/* Maintainer: MontaVista Software, Inc. */
-	.atag_offset	= 0x100,
-	.map_io		= ixdp2x01_map_io,
-	.init_irq	= ixdp2x01_init_irq,
-	.timer		= &ixdp2x01_timer,
-	.init_machine	= ixdp2x01_init_machine,
-	.restart	= ixdp280x_restart,
-MACHINE_END
-
-/*
- * IXDP28x5 is basically an IXDP2801 with a different CPU but Intel
- * changed the machine ID in the bootloader
- */
-MACHINE_START(IXDP28X5, "Intel IXDP2805/2855 Development Platform")
-	/* Maintainer: MontaVista Software, Inc. */
-	.atag_offset	= 0x100,
-	.map_io		= ixdp2x01_map_io,
-	.init_irq	= ixdp2x01_init_irq,
-	.timer		= &ixdp2x01_timer,
-	.init_machine	= ixdp2x01_init_machine,
-	.restart	= ixdp280x_restart,
-MACHINE_END
-#endif
-
-
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
deleted file mode 100644
index d706838..0000000
--- a/arch/arm/mach-ixp2000/pci.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/pci.c
- *
- * PCI routines for IXDP2400/IXDP2800 boards
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintained by: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2002 Intel Corp.
- * Copyright (C) 2003-2004 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <asm/mach/pci.h>
-
-static volatile int pci_master_aborts = 0;
-
-static int clear_master_aborts(void);
-
-u32 *
-ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
-{
-	u32 *paddress;
-
-	if (PCI_SLOT(devfn) > 7)
-		return 0;
-
-	/* Must be dword aligned */
-	where &= ~3;
-
-	/*
-	 * For top bus, generate type 0, else type 1
-	 */
-	if (!bus_nr) {
-		/* only bits[23:16] are used for IDSEL */
-		paddress = (u32 *) (IXP2000_PCI_CFG0_VIRT_BASE
-				    | (1 << (PCI_SLOT(devfn) + 16))
-				    | (PCI_FUNC(devfn) << 8) | where);
-	} else {
-		paddress = (u32 *) (IXP2000_PCI_CFG1_VIRT_BASE 
-				    | (bus_nr << 16)
-				    | (PCI_SLOT(devfn) << 11)
-				    | (PCI_FUNC(devfn) << 8) | where);
-	}
-
-	return paddress;
-}
-
-/*
- * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
- * 0 and 3 are not valid indexes...
- */
-static u32 bytemask[] = {
-	/*0*/	0,
-	/*1*/	0xff,
-	/*2*/	0xffff,
-	/*3*/	0,
-	/*4*/	0xffffffff,
-};
-
-
-int ixp2000_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where,
-				int size, u32 *value)
-{
-	u32 n;
-	u32 *addr;
-
-	n = where % 4;
-
-	addr = ixp2000_pci_config_addr(bus->number, devfn, where);
-	if (!addr)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	pci_master_aborts = 0;
-	*value = (*addr >> (8*n)) & bytemask[size];
-	if (pci_master_aborts) {
-		pci_master_aborts = 0;
-		*value = 0xffffffff;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	}
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-/*
- * We don't do error checks by calling clear_master_aborts() b/c the
- * assumption is that the caller did a read first to make sure a device
- * exists.
- */
-int ixp2000_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where,
-				int size, u32 value)
-{
-	u32 mask;
-	u32 *addr;
-	u32 temp;
-
-	mask = ~(bytemask[size] << ((where % 0x4) * 8));
-	addr = ixp2000_pci_config_addr(bus->number, devfn, where);
-	if (!addr)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	temp = (u32) (value) << ((where % 0x4) * 8);
-	*addr = (*addr & mask) | temp;
-
-	clear_master_aborts();
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-
-struct pci_ops ixp2000_pci_ops = {
-	.read	= ixp2000_pci_read_config,
-	.write	= ixp2000_pci_write_config
-};
-
-
-int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
-{
-
-	volatile u32 temp;
-	unsigned long flags;
-
-	pci_master_aborts = 1;
-
-	local_irq_save(flags);
-	temp = *(IXP2000_PCI_CONTROL);
-	if (temp & ((1 << 8) | (1 << 5))) {
-		ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
-	}
-
-	temp = *(IXP2000_PCI_CMDSTAT);
-	if (temp & (1 << 29)) {
-		while (temp & (1 << 29)) {	
-			ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
-			temp = *(IXP2000_PCI_CMDSTAT);
-		}
-	}
-	local_irq_restore(flags);
-
-	/*
-	 * If it was an imprecise abort, then we need to correct the
-	 * return address to be _after_ the instruction.
-	 */
-	if (fsr & (1 << 10))
-		regs->ARM_pc += 4;
-
-	return 0;
-}
-
-int
-clear_master_aborts(void)
-{
-	volatile u32 temp;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	temp = *(IXP2000_PCI_CONTROL);
-	if (temp & ((1 << 8) | (1 << 5))) {
-		ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
-	}
-
-	temp = *(IXP2000_PCI_CMDSTAT);
-	if (temp & (1 << 29)) {
-		while (temp & (1 << 29)) {
-			ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
-			temp = *(IXP2000_PCI_CMDSTAT);
-		}
-	}
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-void __init
-ixp2000_pci_preinit(void)
-{
-	pci_set_flags(0);
-
-	pcibios_min_io = 0;
-	pcibios_min_mem = 0;
-
-#ifndef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
-	/*
-	 * Configure the PCI unit to properly byteswap I/O transactions,
-	 * and verify that it worked.
-	 */
-	ixp2000_reg_write(IXP2000_PCI_CONTROL,
-			  (*IXP2000_PCI_CONTROL | PCI_CONTROL_IEE));
-
-	if ((*IXP2000_PCI_CONTROL & PCI_CONTROL_IEE) == 0)
-		panic("IXP2000: PCI I/O is broken on this ixp model, and "
-			"the needed workaround has not been configured in");
-#endif
-
-	hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS, 0,
-				"PCI config cycle to non-existent device");
-}
-
-
-/*
- * IXP2000 systems often have large resource requirements, so we just
- * use our own resource space.
- */
-static struct resource ixp2000_pci_mem_space = {
-	.start	= 0xe0000000,
-	.end	= 0xffffffff,
-	.flags	= IORESOURCE_MEM,
-	.name	= "PCI Mem Space"
-};
-
-static struct resource ixp2000_pci_io_space = {
-	.start	= 0x00010000,
-	.end	= 0x0001ffff,
-	.flags	= IORESOURCE_IO,
-	.name	= "PCI I/O Space"
-};
-
-int ixp2000_pci_setup(int nr, struct pci_sys_data *sys)
-{
-	if (nr >= 1)
-		return 0;
-
-	pci_add_resource_offset(&sys->resources,
-				&ixp2000_pci_io_space, sys->io_offset);
-	pci_add_resource_offset(&sys->resources,
-				&ixp2000_pci_mem_space, sys->mem_offset);
-
-	return 1;
-}
-
diff --git a/arch/arm/mach-ixp23xx/Kconfig b/arch/arm/mach-ixp23xx/Kconfig
deleted file mode 100644
index 982670e..0000000
--- a/arch/arm/mach-ixp23xx/Kconfig
+++ /dev/null
@@ -1,25 +0,0 @@
-if ARCH_IXP23XX
-
-config ARCH_SUPPORTS_BIG_ENDIAN
-	bool
-	default y
-
-menu "Intel IXP23xx Implementation Options"
-
-comment "IXP23xx Platforms"
-
-config MACH_ESPRESSO
-	bool "Support IP Fabrics Double Espresso platform"
-	help
-
-config MACH_IXDP2351
-	bool "Support Intel IXDP2351 platform"
-	help
-
-config MACH_ROADRUNNER
-	bool "Support ADI RoadRunner platform"
-	help
-
-endmenu
-
-endif
diff --git a/arch/arm/mach-ixp23xx/Makefile b/arch/arm/mach-ixp23xx/Makefile
deleted file mode 100644
index 288b371..0000000
--- a/arch/arm/mach-ixp23xx/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-obj-y			:= core.o pci.o
-obj-m			:=
-obj-n			:=
-obj-			:=
-
-obj-$(CONFIG_MACH_ESPRESSO)	+= espresso.o
-obj-$(CONFIG_MACH_IXDP2351)	+= ixdp2351.o
-obj-$(CONFIG_MACH_ROADRUNNER)	+= roadrunner.o
diff --git a/arch/arm/mach-ixp23xx/Makefile.boot b/arch/arm/mach-ixp23xx/Makefile.boot
deleted file mode 100644
index 44fb4a71..0000000
--- a/arch/arm/mach-ixp23xx/Makefile.boot
+++ /dev/null
@@ -1,2 +0,0 @@
-   zreladdr-y	+= 0x00008000
-params_phys-y	:= 0x00000100
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
deleted file mode 100644
index d345424..0000000
--- a/arch/arm/mach-ixp23xx/core.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/core.c
- *
- * Core routines for IXP23xx chips
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2005 (c) MontaVista Software, Inc.
- *
- * Based on 2.4 code Copyright 2004 (c) Intel Corporation
- *
- * 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/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-#include <asm/system_misc.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-
-
-/*************************************************************************
- * Chip specific mappings shared by all IXP23xx systems
- *************************************************************************/
-static struct map_desc ixp23xx_io_desc[] __initdata = {
-	{ /* XSI-CPP CSRs */
-	 	.virtual	= IXP23XX_XSI2CPP_CSR_VIRT,
-	 	.pfn		= __phys_to_pfn(IXP23XX_XSI2CPP_CSR_PHYS),
-	 	.length		= IXP23XX_XSI2CPP_CSR_SIZE,
-		.type		= MT_DEVICE,
-	}, { /* Expansion Bus Config */
-	 	.virtual	= IXP23XX_EXP_CFG_VIRT,
-	 	.pfn		= __phys_to_pfn(IXP23XX_EXP_CFG_PHYS),
-	 	.length		= IXP23XX_EXP_CFG_SIZE,
-		.type		= MT_DEVICE,
-	}, { /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACS,.... */
-	 	.virtual	= IXP23XX_PERIPHERAL_VIRT,
-	 	.pfn		= __phys_to_pfn(IXP23XX_PERIPHERAL_PHYS),
-	 	.length		= IXP23XX_PERIPHERAL_SIZE,
-		.type		= MT_DEVICE,
-	}, { /* CAP CSRs */
-	 	.virtual	= IXP23XX_CAP_CSR_VIRT,
-	 	.pfn		= __phys_to_pfn(IXP23XX_CAP_CSR_PHYS),
-	 	.length		= IXP23XX_CAP_CSR_SIZE,
-		.type		= MT_DEVICE,
-	}, { /* MSF CSRs */
-	 	.virtual	= IXP23XX_MSF_CSR_VIRT,
-	 	.pfn		= __phys_to_pfn(IXP23XX_MSF_CSR_PHYS),
-	 	.length		= IXP23XX_MSF_CSR_SIZE,
-		.type		= MT_DEVICE,
-	}, { /* PCI I/O Space */
-	 	.virtual	= IXP23XX_PCI_IO_VIRT,
-	 	.pfn		= __phys_to_pfn(IXP23XX_PCI_IO_PHYS),
-	 	.length		= IXP23XX_PCI_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, { /* PCI Config Space */
-	 	.virtual	= IXP23XX_PCI_CFG_VIRT,
-	 	.pfn		= __phys_to_pfn(IXP23XX_PCI_CFG_PHYS),
-	 	.length		= IXP23XX_PCI_CFG_SIZE,
-		.type		= MT_DEVICE,
-	}, { /* PCI local CFG CSRs */
-	 	.virtual	= IXP23XX_PCI_CREG_VIRT,
-	 	.pfn		= __phys_to_pfn(IXP23XX_PCI_CREG_PHYS),
-	 	.length		= IXP23XX_PCI_CREG_SIZE,
-		.type		= MT_DEVICE,
-	}, { /* PCI MEM Space */
-	 	.virtual	= IXP23XX_PCI_MEM_VIRT,
-	 	.pfn		= __phys_to_pfn(IXP23XX_PCI_MEM_PHYS),
-	 	.length		= IXP23XX_PCI_MEM_SIZE,
-		.type		= MT_DEVICE,
-	}
-};
-
-void __init ixp23xx_map_io(void)
-{
-	iotable_init(ixp23xx_io_desc, ARRAY_SIZE(ixp23xx_io_desc));
-}
-
-
-/***************************************************************************
- * IXP23xx Interrupt Handling
- ***************************************************************************/
-enum ixp23xx_irq_type {
-	IXP23XX_IRQ_LEVEL, IXP23XX_IRQ_EDGE
-};
-
-static void ixp23xx_config_irq(unsigned int, enum ixp23xx_irq_type);
-
-static int ixp23xx_irq_set_type(struct irq_data *d, unsigned int type)
-{
-	int line = d->irq - IRQ_IXP23XX_GPIO6 + 6;
-	u32 int_style;
-	enum ixp23xx_irq_type irq_type;
-	volatile u32 *int_reg;
-
-	/*
-	 * Only GPIOs 6-15 are wired to interrupts on IXP23xx
-	 */
-	if (line < 6 || line > 15)
-		return -EINVAL;
-
-	switch (type) {
-	case IRQ_TYPE_EDGE_BOTH:
-		int_style = IXP23XX_GPIO_STYLE_TRANSITIONAL;
-		irq_type = IXP23XX_IRQ_EDGE;
-		break;
-	case IRQ_TYPE_EDGE_RISING:
-		int_style = IXP23XX_GPIO_STYLE_RISING_EDGE;
-		irq_type = IXP23XX_IRQ_EDGE;
-		break;
-	case IRQ_TYPE_EDGE_FALLING:
-		int_style = IXP23XX_GPIO_STYLE_FALLING_EDGE;
-		irq_type = IXP23XX_IRQ_EDGE;
-		break;
-	case IRQ_TYPE_LEVEL_HIGH:
-		int_style = IXP23XX_GPIO_STYLE_ACTIVE_HIGH;
-		irq_type = IXP23XX_IRQ_LEVEL;
-		break;
-	case IRQ_TYPE_LEVEL_LOW:
-		int_style = IXP23XX_GPIO_STYLE_ACTIVE_LOW;
-		irq_type = IXP23XX_IRQ_LEVEL;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ixp23xx_config_irq(d->irq, irq_type);
-
-	if (line >= 8) {	/* pins 8-15 */
-		line -= 8;
-		int_reg = (volatile u32 *)IXP23XX_GPIO_GPIT2R;
-	} else {		/* pins 0-7 */
-		int_reg = (volatile u32 *)IXP23XX_GPIO_GPIT1R;
-	}
-
-	/*
-	 * Clear pending interrupts
-	 */
-	*IXP23XX_GPIO_GPISR = (1 << line);
-
-	/* Clear the style for the appropriate pin */
-	*int_reg &= ~(IXP23XX_GPIO_STYLE_MASK <<
-			(line * IXP23XX_GPIO_STYLE_SIZE));
-
-	/* Set the new style */
-	*int_reg |= (int_style << (line * IXP23XX_GPIO_STYLE_SIZE));
-
-	return 0;
-}
-
-static void ixp23xx_irq_mask(struct irq_data *d)
-{
-	volatile unsigned long *intr_reg;
-	unsigned int irq = d->irq;
-
-	if (irq >= 56)
-		irq += 8;
-
-	intr_reg = IXP23XX_INTR_EN1 + (irq / 32);
-	*intr_reg &= ~(1 << (irq % 32));
-}
-
-static void ixp23xx_irq_ack(struct irq_data *d)
-{
-	int line = d->irq - IRQ_IXP23XX_GPIO6 + 6;
-
-	if ((line < 6) || (line > 15))
-		return;
-
-	*IXP23XX_GPIO_GPISR = (1 << line);
-}
-
-/*
- * Level triggered interrupts on GPIO lines can only be cleared when the
- * interrupt condition disappears.
- */
-static void ixp23xx_irq_level_unmask(struct irq_data *d)
-{
-	volatile unsigned long *intr_reg;
-	unsigned int irq = d->irq;
-
-	ixp23xx_irq_ack(d);
-
-	if (irq >= 56)
-		irq += 8;
-
-	intr_reg = IXP23XX_INTR_EN1 + (irq / 32);
-	*intr_reg |= (1 << (irq % 32));
-}
-
-static void ixp23xx_irq_edge_unmask(struct irq_data *d)
-{
-	volatile unsigned long *intr_reg;
-	unsigned int irq = d->irq;
-
-	if (irq >= 56)
-		irq += 8;
-
-	intr_reg = IXP23XX_INTR_EN1 + (irq / 32);
-	*intr_reg |= (1 << (irq % 32));
-}
-
-static struct irq_chip ixp23xx_irq_level_chip = {
-	.irq_ack	= ixp23xx_irq_mask,
-	.irq_mask	= ixp23xx_irq_mask,
-	.irq_unmask	= ixp23xx_irq_level_unmask,
-	.irq_set_type	= ixp23xx_irq_set_type
-};
-
-static struct irq_chip ixp23xx_irq_edge_chip = {
-	.irq_ack	= ixp23xx_irq_ack,
-	.irq_mask	= ixp23xx_irq_mask,
-	.irq_unmask	= ixp23xx_irq_edge_unmask,
-	.irq_set_type	= ixp23xx_irq_set_type
-};
-
-static void ixp23xx_pci_irq_mask(struct irq_data *d)
-{
-	unsigned int irq = d->irq;
-
-	*IXP23XX_PCI_XSCALE_INT_ENABLE &= ~(1 << (IRQ_IXP23XX_INTA + 27 - irq));
-}
-
-static void ixp23xx_pci_irq_unmask(struct irq_data *d)
-{
-	unsigned int irq = d->irq;
-
-	*IXP23XX_PCI_XSCALE_INT_ENABLE |= (1 << (IRQ_IXP23XX_INTA + 27 - irq));
-}
-
-/*
- * TODO: Should this just be done at ASM level?
- */
-static void pci_handler(unsigned int irq, struct irq_desc *desc)
-{
-	u32 pci_interrupt;
-	unsigned int irqno;
-
-	pci_interrupt = *IXP23XX_PCI_XSCALE_INT_STATUS;
-
-	desc->irq_data.chip->irq_ack(&desc->irq_data);
-
-	/* See which PCI_INTA, or PCI_INTB interrupted */
-	if (pci_interrupt & (1 << 26)) {
-		irqno = IRQ_IXP23XX_INTB;
-	} else if (pci_interrupt & (1 << 27)) {
-		irqno = IRQ_IXP23XX_INTA;
-	} else {
-		BUG();
-	}
-
-	generic_handle_irq(irqno);
-
-	desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixp23xx_pci_irq_chip = {
-	.irq_ack	= ixp23xx_pci_irq_mask,
-	.irq_mask	= ixp23xx_pci_irq_mask,
-	.irq_unmask	= ixp23xx_pci_irq_unmask
-};
-
-static void ixp23xx_config_irq(unsigned int irq, enum ixp23xx_irq_type type)
-{
-	switch (type) {
-	case IXP23XX_IRQ_LEVEL:
-		irq_set_chip_and_handler(irq, &ixp23xx_irq_level_chip,
-					 handle_level_irq);
-		break;
-	case IXP23XX_IRQ_EDGE:
-		irq_set_chip_and_handler(irq, &ixp23xx_irq_edge_chip,
-					 handle_edge_irq);
-		break;
-	}
-	set_irq_flags(irq, IRQF_VALID);
-}
-
-void __init ixp23xx_init_irq(void)
-{
-	int irq;
-
-	/* Route everything to IRQ */
-	*IXP23XX_INTR_SEL1 = 0x0;
-	*IXP23XX_INTR_SEL2 = 0x0;
-	*IXP23XX_INTR_SEL3 = 0x0;
-	*IXP23XX_INTR_SEL4 = 0x0;
-
-	/* Mask all sources */
-	*IXP23XX_INTR_EN1 = 0x0;
-	*IXP23XX_INTR_EN2 = 0x0;
-	*IXP23XX_INTR_EN3 = 0x0;
-	*IXP23XX_INTR_EN4 = 0x0;
-
-	/*
-	 * Configure all IRQs for level-sensitive operation
-	 */
-	for (irq = 0; irq <= NUM_IXP23XX_RAW_IRQS; irq++) {
-		ixp23xx_config_irq(irq, IXP23XX_IRQ_LEVEL);
-	}
-
-	for (irq = IRQ_IXP23XX_INTA; irq <= IRQ_IXP23XX_INTB; irq++) {
-		irq_set_chip_and_handler(irq, &ixp23xx_pci_irq_chip,
-					 handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-
-	irq_set_chained_handler(IRQ_IXP23XX_PCI_INT_RPH, pci_handler);
-}
-
-
-/*************************************************************************
- * Timer-tick functions for IXP23xx
- *************************************************************************/
-#define CLOCK_TICKS_PER_USEC	(CLOCK_TICK_RATE / USEC_PER_SEC)
-
-static unsigned long next_jiffy_time;
-
-static unsigned long
-ixp23xx_gettimeoffset(void)
-{
-	unsigned long elapsed;
-
-	elapsed = *IXP23XX_TIMER_CONT - (next_jiffy_time - LATCH);
-
-	return elapsed / CLOCK_TICKS_PER_USEC;
-}
-
-static irqreturn_t
-ixp23xx_timer_interrupt(int irq, void *dev_id)
-{
-	/* Clear Pending Interrupt by writing '1' to it */
-	*IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND;
-	while ((signed long)(*IXP23XX_TIMER_CONT - next_jiffy_time) >= LATCH) {
-		timer_tick();
-		next_jiffy_time += LATCH;
-	}
-
-	return IRQ_HANDLED;
-}
-
-static struct irqaction ixp23xx_timer_irq = {
-	.name		= "IXP23xx Timer Tick",
-	.handler	= ixp23xx_timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-};
-
-void __init ixp23xx_init_timer(void)
-{
-	/* Clear Pending Interrupt by writing '1' to it */
-	*IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND;
-
-	/* Setup the Timer counter value */
-	*IXP23XX_TIMER1_RELOAD =
-		(LATCH & ~IXP23XX_TIMER_RELOAD_MASK) | IXP23XX_TIMER_ENABLE;
-
-	*IXP23XX_TIMER_CONT = 0;
-	next_jiffy_time = LATCH;
-
-	/* Connect the interrupt handler and enable the interrupt */
-	setup_irq(IRQ_IXP23XX_TIMER1, &ixp23xx_timer_irq);
-}
-
-struct sys_timer ixp23xx_timer = {
-	.init		= ixp23xx_init_timer,
-	.offset		= ixp23xx_gettimeoffset,
-};
-
-
-/*************************************************************************
- * IXP23xx Platform Initialization
- *************************************************************************/
-static struct resource ixp23xx_uart_resources[] = {
-	{
-		.start		= IXP23XX_UART1_PHYS,
-		.end		= IXP23XX_UART1_PHYS + 0x0fff,
-		.flags		= IORESOURCE_MEM
-	}, {
-		.start		= IXP23XX_UART2_PHYS,
-		.end		= IXP23XX_UART2_PHYS + 0x0fff,
-		.flags		= IORESOURCE_MEM
-	}
-};
-
-static struct plat_serial8250_port ixp23xx_uart_data[] = {
-	{
-		.mapbase	= IXP23XX_UART1_PHYS,
-		.membase	= (char *)(IXP23XX_UART1_VIRT + 3),
-		.irq		= IRQ_IXP23XX_UART1,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= IXP23XX_UART_XTAL,
-	}, {
-		.mapbase	= IXP23XX_UART2_PHYS,
-		.membase	= (char *)(IXP23XX_UART2_VIRT + 3),
-		.irq		= IRQ_IXP23XX_UART2,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= IXP23XX_UART_XTAL,
-	},
-	{ },
-};
-
-static struct platform_device ixp23xx_uart = {
-	.name			= "serial8250",
-	.id			= 0,
-	.dev.platform_data	= ixp23xx_uart_data,
-	.num_resources		= 2,
-	.resource		= ixp23xx_uart_resources,
-};
-
-static struct platform_device *ixp23xx_devices[] __initdata = {
-	&ixp23xx_uart,
-};
-
-void __init ixp23xx_sys_init(void)
-{
-	/* by default, the idle code is disabled */
-	disable_hlt();
-
-	*IXP23XX_EXP_UNIT_FUSE |= 0xf;
-	platform_add_devices(ixp23xx_devices, ARRAY_SIZE(ixp23xx_devices));
-}
-
-void ixp23xx_restart(char mode, const char *cmd)
-{
-	/* Use on-chip reset capability */
-	*IXP23XX_RESET0 |= IXP23XX_RST_ALL;
-}
diff --git a/arch/arm/mach-ixp23xx/espresso.c b/arch/arm/mach-ixp23xx/espresso.c
deleted file mode 100644
index d142d45..0000000
--- a/arch/arm/mach-ixp23xx/espresso.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/espresso.c
- *
- * Double Espresso-specific routines
- *
- * Author: Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * 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/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/pci.h>
-
-static int __init espresso_pci_init(void)
-{
-	if (machine_is_espresso())
-		ixp23xx_pci_slave_init();
-
-	return 0;
-};
-subsys_initcall(espresso_pci_init);
-
-static struct physmap_flash_data espresso_flash_data = {
-	.width		= 2,
-};
-
-static struct resource espresso_flash_resource = {
-	.start		= 0x90000000,
-	.end		= 0x91ffffff,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device espresso_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &espresso_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &espresso_flash_resource,
-};
-
-static void __init espresso_init(void)
-{
-	platform_device_register(&espresso_flash);
-
-	/*
-	 * Mark flash as writeable.
-	 */
-	IXP23XX_EXP_CS0[0] |= IXP23XX_FLASH_WRITABLE;
-	IXP23XX_EXP_CS0[1] |= IXP23XX_FLASH_WRITABLE;
-
-	ixp23xx_sys_init();
-}
-
-MACHINE_START(ESPRESSO, "IP Fabrics Double Espresso")
-	/* Maintainer: Lennert Buytenhek */
-	.map_io		= ixp23xx_map_io,
-	.init_irq	= ixp23xx_init_irq,
-	.timer		= &ixp23xx_timer,
-	.atag_offset	= 0x100,
-	.init_machine	= espresso_init,
-	.restart	= ixp23xx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-ixp23xx/include/mach/debug-macro.S b/arch/arm/mach-ixp23xx/include/mach/debug-macro.S
deleted file mode 100644
index 5ff524c..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/debug-macro.S
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * 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 <mach/ixp23xx.h>
-
-		.macro	addruart, rp, rv, tmp
-		ldr	\rp, =IXP23XX_PERIPHERAL_PHYS 	@ physical
-		ldr	\rv, =IXP23XX_PERIPHERAL_VIRT	@ virtual
-#ifdef __ARMEB__
-		orr	\rp, \rp, #0x00000003
-		orr	\rv, \rv, #0x00000003
-#endif
-		.endm
-
-#define UART_SHIFT	2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-ixp23xx/include/mach/entry-macro.S b/arch/arm/mach-ixp23xx/include/mach/entry-macro.S
deleted file mode 100644
index 3fd2cb9..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/entry-macro.S
- */
-
-		.macro  get_irqnr_preamble, base, tmp
-		.endm
-
-		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-		ldr	\irqnr, =(IXP23XX_INTC_VIRT + IXP23XX_INTR_IRQ_ENC_ST_OFFSET)
-		ldr	\irqnr, [\irqnr]	@ get interrupt number
-		cmp	\irqnr, #0x0		@ spurious interrupt ?
-		movne	\irqnr, \irqnr, lsr #2	@ skip unwanted low order bits
-		subne	\irqnr, \irqnr, #1	@ convert to 0 based
-
-#if 0
-		cmp	\irqnr, #IRQ_IXP23XX_PCI_INT_RPH
-		bne	1001f
-		mov	\irqnr, #IRQ_IXP23XX_INTA
-
-		ldr	\irqnr, =0xf5000030
-
-		mov	\tmp, #(1<<26)
-		tst	\irqnr, \tmp
-		movne	\irqnr, #IRQ_IXP23XX_INTB
-
-		mov	\tmp, #(1<<27)
-		tst	\irqnr, \tmp
-		movne	\irqnr, #IRQ_IXP23XX_INTA
-1001:
-#endif
-		.endm
diff --git a/arch/arm/mach-ixp23xx/include/mach/hardware.h b/arch/arm/mach-ixp23xx/include/mach/hardware.h
deleted file mode 100644
index 60e55fa..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/hardware.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/hardware.h
- *
- * Copyright (C) 2002-2004 Intel Corporation.
- * Copyricht (C) 2005 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.
- *
- * Hardware definitions for IXP23XX based systems
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/* PCI IO info */
-
-#include "ixp23xx.h"
-
-/*
- * Platform helper functions
- */
-#include "platform.h"
-
-/*
- * Platform-specific headers
- */
-#include "ixdp2351.h"
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/io.h b/arch/arm/mach-ixp23xx/include/mach/io.h
deleted file mode 100644
index a7aceb5..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/io.h
- *
- * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2003-2005 Intel Corp.
- * Copyright (C) 2005 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 __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(p)		((void __iomem*)((p) + IXP23XX_PCI_IO_VIRT))
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/irqs.h b/arch/arm/mach-ixp23xx/include/mach/irqs.h
deleted file mode 100644
index 3af33a0..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/irqs.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/irqs.h
- *
- * IRQ definitions for IXP23XX based systems
- *
- * Author: Naeem Afzal <naeem.m.afzal@intel.com>
- *
- * Copyright (C) 2003-2004 Intel 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.
- */
-
-#ifndef __ASM_ARCH_IRQS_H
-#define __ASM_ARCH_IRQS_H
-
-#define NR_IXP23XX_IRQS			IRQ_IXP23XX_INTB+1
-#define IRQ_IXP23XX_EXTIRQS		NR_IXP23XX_IRQS
-
-
-#define IRQ_IXP23XX_DBG0		0	/* Debug/Execution/MBox */
-#define IRQ_IXP23XX_DBG1		1	/* Debug/Execution/MBox */
-#define IRQ_IXP23XX_NPE_TRG		2	/* npe_trigger */
-#define IRQ_IXP23XX_TIMER1		3	/* Timer[0] */
-#define IRQ_IXP23XX_TIMER2		4	/* Timer[1] */
-#define IRQ_IXP23XX_TIMESTAMP		5	/* Timer[2], Time-stamp */
-#define IRQ_IXP23XX_WDOG		6	/* Time[3], Watchdog Timer */
-#define IRQ_IXP23XX_PCI_DBELL		7	/* PCI Doorbell */
-#define IRQ_IXP23XX_PCI_DMA1		8	/* PCI DMA Channel 1 */
-#define IRQ_IXP23XX_PCI_DMA2		9	/* PCI DMA Channel 2 */
-#define IRQ_IXP23XX_PCI_DMA3		10	/* PCI DMA Channel 3 */
-#define IRQ_IXP23XX_PCI_INT_RPH		11	/* pcxg_pci_int_rph */
-#define IRQ_IXP23XX_CPP_PMU		12	/* xpxg_pm_int_rpl */
-#define IRQ_IXP23XX_SWINT0		13	/* S/W Interrupt0 */
-#define IRQ_IXP23XX_SWINT1		14	/* S/W Interrupt1 */
-#define IRQ_IXP23XX_UART2		15	/* UART1 Interrupt */
-#define IRQ_IXP23XX_UART1		16	/* UART0 Interrupt */
-#define IRQ_IXP23XX_XSI_PMU_ROLLOVER	17	/* AHB Performance M. Unit counter rollover */
-#define IRQ_IXP23XX_XSI_AHB_PM0		18	/* intr_pm_o */
-#define IRQ_IXP23XX_XSI_AHB_ECE0	19	/* intr_ece_o */
-#define IRQ_IXP23XX_XSI_AHB_GASKET	20	/* gas_intr_o */
-#define IRQ_IXP23XX_XSI_CPP		21	/* xsi2cpp_int */
-#define IRQ_IXP23XX_CPP_XSI		22	/* cpp2xsi_int */
-#define IRQ_IXP23XX_ME_ATTN0		23	/* ME_ATTN */
-#define IRQ_IXP23XX_ME_ATTN1		24	/* ME_ATTN */
-#define IRQ_IXP23XX_ME_ATTN2		25	/* ME_ATTN */
-#define IRQ_IXP23XX_ME_ATTN3		26	/* ME_ATTN */
-#define IRQ_IXP23XX_PCI_ERR_RPH		27	/* PCXG_PCI_ERR_RPH */
-#define IRQ_IXP23XX_D0XG_ECC_CORR	28	/* D0XG_DRAM_ECC_CORR */
-#define IRQ_IXP23XX_D0XG_ECC_UNCORR	29	/* D0XG_DRAM_ECC_UNCORR */
-#define IRQ_IXP23XX_SRAM_ERR1		30	/* SRAM1_ERR */
-#define IRQ_IXP23XX_SRAM_ERR0		31	/* SRAM0_ERR */
-#define IRQ_IXP23XX_MEDIA_ERR		32	/* MEDIA_ERR */
-#define IRQ_IXP23XX_STH_DRAM_ECC_MAJ	33	/* STH_DRAM0_ECC_MAJ */
-#define IRQ_IXP23XX_GPIO6		34	/* GPIO0 interrupts */
-#define IRQ_IXP23XX_GPIO7		35	/* GPIO1 interrupts */
-#define IRQ_IXP23XX_GPIO8		36	/* GPIO2 interrupts */
-#define IRQ_IXP23XX_GPIO9		37	/* GPIO3 interrupts */
-#define IRQ_IXP23XX_GPIO10		38	/* GPIO4 interrupts */
-#define IRQ_IXP23XX_GPIO11		39	/* GPIO5 interrupts */
-#define IRQ_IXP23XX_GPIO12		40	/* GPIO6 interrupts */
-#define IRQ_IXP23XX_GPIO13		41	/* GPIO7 interrupts */
-#define IRQ_IXP23XX_GPIO14		42	/* GPIO8 interrupts */
-#define IRQ_IXP23XX_GPIO15		43	/* GPIO9 interrupts */
-#define IRQ_IXP23XX_SHAC_RING0		44	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING1		45	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING2		46	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING3		47	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING4		48	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING5		49	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING6		50	/* SHAC RING Full */
-#define IRQ_IXP23XX_SHAC_RING7		51	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING8		52	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING9		53	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING10		54	/* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING11		55	/* SHAC Ring Full */
-#define IRQ_IXP23XX_ME_THREAD_A0_ME0	56	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A1_ME0	57	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A2_ME0	58	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A3_ME0	59	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A4_ME0	60	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A5_ME0	61	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A6_ME0	62	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A7_ME0	63	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A8_ME1	64	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A9_ME1	65	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A10_ME1	66	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A11_ME1	67	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A12_ME1	68	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A13_ME1	69	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A14_ME1	70	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A15_ME1	71	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A16_ME2	72	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A17_ME2	73	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A18_ME2	74	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A19_ME2	75	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A20_ME2	76	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A21_ME2	77	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A22_ME2	78	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A23_ME2	79	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A24_ME3	80	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A25_ME3	81	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A26_ME3	82	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A27_ME3	83	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A28_ME3	84	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A29_ME3	85	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A30_ME3	86	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A31_ME3	87	/* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_B0_ME0	88	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B1_ME0	89	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B2_ME0	90	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B3_ME0	91	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B4_ME0	92	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B5_ME0	93	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B6_ME0	94	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B7_ME0	95	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B8_ME1	96	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B9_ME1	97	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B10_ME1	98	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B11_ME1	99	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B12_ME1	100	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B13_ME1	101	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B14_ME1	102	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B15_ME1	103	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B16_ME2	104	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B17_ME2	105	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B18_ME2	106	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B19_ME2	107	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B20_ME2	108	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B21_ME2	109	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B22_ME2	110	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B23_ME2	111	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B24_ME3	112	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B25_ME3	113	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B26_ME3	114	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B27_ME3	115	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B28_ME3	116	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B29_ME3	117	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B30_ME3	118	/* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B31_ME3	119	/* ME_THREAD_B */
-
-#define NUM_IXP23XX_RAW_IRQS		120
-
-#define IRQ_IXP23XX_INTA		120	/* Indirect pcxg_pci_int_rph */
-#define IRQ_IXP23XX_INTB		121	/* Indirect pcxg_pci_int_rph */
-
-#define NR_IXP23XX_IRQ			(IRQ_IXP23XX_INTB + 1)
-
-/*
- * We default to 32 per-board IRQs. Increase this number if you need
- * more, but keep it realistic.
- */
-#define NR_IXP23XX_MACH_IRQS 		32
-
-#define NR_IRQS				(NR_IXP23XX_IRQS + NR_IXP23XX_MACH_IRQS)
-
-#define IXP23XX_MACH_IRQ(irq) 		(NR_IXP23XX_IRQ + (irq))
-
-
-/*
- * IXDP2351-specific interrupts
- */
-
-/*
- * External PCI interrupts signaled through INTB
- *
- */
-#define IXDP2351_INTB_IRQ_BASE 		0
-#define IRQ_IXDP2351_INTA_82546		IXP23XX_MACH_IRQ(0)
-#define IRQ_IXDP2351_INTB_82546		IXP23XX_MACH_IRQ(1)
-#define IRQ_IXDP2351_SPCI_DB_0		IXP23XX_MACH_IRQ(2)
-#define IRQ_IXDP2351_SPCI_DB_1		IXP23XX_MACH_IRQ(3)
-#define IRQ_IXDP2351_SPCI_PMC_INTA	IXP23XX_MACH_IRQ(4)
-#define IRQ_IXDP2351_SPCI_PMC_INTB	IXP23XX_MACH_IRQ(5)
-#define IRQ_IXDP2351_SPCI_PMC_INTC	IXP23XX_MACH_IRQ(6)
-#define IRQ_IXDP2351_SPCI_PMC_INTD	IXP23XX_MACH_IRQ(7)
-#define IRQ_IXDP2351_SPCI_FIC		IXP23XX_MACH_IRQ(8)
-
-#define IXDP2351_INTB_IRQ_BIT(irq)	(irq - IXP23XX_MACH_IRQ(0))
-#define IXDP2351_INTB_IRQ_MASK(irq)	(1 << IXDP2351_INTB_IRQ_BIT(irq))
-#define IXDP2351_INTB_IRQ_VALID		0x01FF
-#define IXDP2351_INTB_IRQ_NUM 		16
-
-/*
- * Other external interrupts signaled through INTA
- */
-#define IXDP2351_INTA_IRQ_BASE 		16
-#define IRQ_IXDP2351_IPMI_FROM		IXP23XX_MACH_IRQ(16)
-#define IRQ_IXDP2351_125US		IXP23XX_MACH_IRQ(17)
-#define IRQ_IXDP2351_DB_0_ADD		IXP23XX_MACH_IRQ(18)
-#define IRQ_IXDP2351_DB_1_ADD		IXP23XX_MACH_IRQ(19)
-#define IRQ_IXDP2351_DEBUG1		IXP23XX_MACH_IRQ(20)
-#define IRQ_IXDP2351_ADD_UART		IXP23XX_MACH_IRQ(21)
-#define IRQ_IXDP2351_FIC_ADD		IXP23XX_MACH_IRQ(24)
-#define IRQ_IXDP2351_CS8900		IXP23XX_MACH_IRQ(25)
-#define IRQ_IXDP2351_BBSRAM		IXP23XX_MACH_IRQ(26)
-#define IRQ_IXDP2351_CONFIG_MEDIA	IXP23XX_MACH_IRQ(27)
-#define IRQ_IXDP2351_CLOCK_REF		IXP23XX_MACH_IRQ(28)
-#define IRQ_IXDP2351_A10_NP		IXP23XX_MACH_IRQ(29)
-#define IRQ_IXDP2351_A11_NP		IXP23XX_MACH_IRQ(30)
-#define IRQ_IXDP2351_DEBUG_NP		IXP23XX_MACH_IRQ(31)
-
-#define IXDP2351_INTA_IRQ_BIT(irq) 	(irq - IXP23XX_MACH_IRQ(16))
-#define IXDP2351_INTA_IRQ_MASK(irq) 	(1 << IXDP2351_INTA_IRQ_BIT(irq))
-#define IXDP2351_INTA_IRQ_VALID 	0xFF3F
-#define IXDP2351_INTA_IRQ_NUM 		16
-
-
-/*
- * ADI RoadRunner IRQs
- */
-#define IRQ_ROADRUNNER_PCI_INTA 	IRQ_IXP23XX_INTA
-#define IRQ_ROADRUNNER_PCI_INTB 	IRQ_IXP23XX_INTB
-#define IRQ_ROADRUNNER_PCI_INTC 	IRQ_IXP23XX_GPIO11
-#define IRQ_ROADRUNNER_PCI_INTD 	IRQ_IXP23XX_GPIO12
-
-/*
- * Put new board definitions here
- */
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/ixdp2351.h b/arch/arm/mach-ixp23xx/include/mach/ixdp2351.h
deleted file mode 100644
index 6639510..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/ixdp2351.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/ixdp2351.h
- *
- * Register and other defines for IXDP2351
- *
- * Copyright (c) 2002-2004 Intel Corp.
- * Copytight (c) 2005 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 as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef __ASM_ARCH_IXDP2351_H
-#define __ASM_ARCH_IXDP2351_H
-
-/*
- * NP module memory map
- */
-#define IXDP2351_NP_PHYS_BASE		(IXP23XX_EXP_BUS_CS4_BASE)
-#define IXDP2351_NP_PHYS_SIZE		0x00100000
-#define IXDP2351_NP_VIRT_BASE		0xeff00000
-
-#define IXDP2351_VIRT_CS8900_BASE	(IXDP2351_NP_VIRT_BASE)
-#define IXDP2351_VIRT_CS8900_END	(IXDP2351_VIRT_CS8900_BASE + 16)
-
-#define IXDP2351_VIRT_NP_CPLD_BASE 	(IXP23XX_EXP_BUS_CS4_BASE_VIRT + 0x00010000)
-
-#define IXDP2351_NP_CPLD_REG(reg) ((volatile u16 *)(IXDP2351_VIRT_NP_CPLD_BASE + reg))
-
-#define IXDP2351_NP_CPLD_RESET1_REG	IXDP2351_NP_CPLD_REG(0x00)
-#define IXDP2351_NP_CPLD_LED_REG	IXDP2351_NP_CPLD_REG(0x02)
-#define IXDP2351_NP_CPLD_VERSION_REG	IXDP2351_NP_CPLD_REG(0x04)
-
-/*
- * Base board module memory map
- */
-
-#define IXDP2351_BB_BASE_PHYS		(IXP23XX_EXP_BUS_CS5_BASE)
-#define IXDP2351_BB_SIZE		0x01000000
-#define IXDP2351_BB_BASE_VIRT		(0xee000000)
-
-#define IXDP2351_BB_AREA_BASE(offset)	(IXDP2351_BB_BASE_VIRT + offset)
-
-#define IXDP2351_VIRT_NVRAM_BASE	IXDP2351_BB_AREA_BASE(0x0)
-#define IXDP2351_NVRAM_SIZE		(0x20000)
-
-#define IXDP2351_VIRT_MB_IXF1104_BASE	IXDP2351_BB_AREA_BASE(0x00020000)
-#define IXDP2351_VIRT_ADD_UART_BASE	IXDP2351_BB_AREA_BASE(0x000240C0)
-#define IXDP2351_VIRT_FIC_BASE		IXDP2351_BB_AREA_BASE(0x00200000)
-#define IXDP2351_VIRT_DB0_BASE		IXDP2351_BB_AREA_BASE(0x00400000)
-#define IXDP2351_VIRT_DB1_BASE		IXDP2351_BB_AREA_BASE(0x00600000)
-#define IXDP2351_VIRT_CPLD_BASE		IXDP2351_BB_AREA_BASE(0x00024000)
-
-/*
- * On board CPLD registers
- */
-#define IXDP2351_CPLD_BB_REG(reg) ((volatile u16 *)(IXDP2351_VIRT_CPLD_BASE + reg))
-
-#define IXDP2351_CPLD_RESET0_REG	IXDP2351_CPLD_BB_REG(0x00)
-#define IXDP2351_CPLD_RESET1_REG	IXDP2351_CPLD_BB_REG(0x04)
-
-#define IXDP2351_CPLD_RESET1_MAGIC 	0x55AA
-#define IXDP2351_CPLD_RESET1_ENABLE 	0x8000
-
-#define IXDP2351_CPLD_FPGA_CONFIG_REG	IXDP2351_CPLD_BB_REG(0x08)
-#define IXDP2351_CPLD_INTB_MASK_SET_REG	IXDP2351_CPLD_BB_REG(0x10)
-#define IXDP2351_CPLD_INTA_MASK_SET_REG	IXDP2351_CPLD_BB_REG(0x14)
-#define IXDP2351_CPLD_INTB_STAT_REG	IXDP2351_CPLD_BB_REG(0x18)
-#define IXDP2351_CPLD_INTA_STAT_REG	IXDP2351_CPLD_BB_REG(0x1C)
-#define IXDP2351_CPLD_INTB_RAW_REG	IXDP2351_CPLD_BB_REG(0x20)	/* read */
-#define IXDP2351_CPLD_INTA_RAW_REG	IXDP2351_CPLD_BB_REG(0x24)	/* read */
-#define IXDP2351_CPLD_INTB_MASK_CLR_REG	IXDP2351_CPLD_INTB_RAW_REG	/* write */
-#define IXDP2351_CPLD_INTA_MASK_CLR_REG	IXDP2351_CPLD_INTA_RAW_REG	/* write */
-#define IXDP2351_CPLD_INTB_SIM_REG	IXDP2351_CPLD_BB_REG(0x28)
-#define IXDP2351_CPLD_INTA_SIM_REG	IXDP2351_CPLD_BB_REG(0x2C)
-	/* Interrupt bits are defined in irqs.h */
-#define IXDP2351_CPLD_BB_GBE0_REG	IXDP2351_CPLD_BB_REG(0x30)
-#define IXDP2351_CPLD_BB_GBE1_REG	IXDP2351_CPLD_BB_REG(0x34)
-
-/* #define IXDP2351_CPLD_BB_MISC_REG	IXDP2351_CPLD_REG(0x1C) */
-/* #define IXDP2351_CPLD_BB_MISC_REV_MASK	0xFF		*/
-/* #define IXDP2351_CPLD_BB_GDXCS0_REG	IXDP2351_CPLD_REG(0x24) */
-/* #define IXDP2351_CPLD_BB_GDXCS1_REG	IXDP2351_CPLD_REG(0x28) */
-/* #define IXDP2351_CPLD_BB_CLOCK_REG	IXDP2351_CPLD_REG(0x04) */
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/ixp23xx.h b/arch/arm/mach-ixp23xx/include/mach/ixp23xx.h
deleted file mode 100644
index 6d02481..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/ixp23xx.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/ixp23xx.h
- *
- * Register definitions for IXP23XX
- *
- * Copyright (C) 2003-2005 Intel Corporation.
- * Copyright (C) 2005 MontaVista Software, Inc.
- *
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * 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 __ASM_ARCH_IXP23XX_H
-#define __ASM_ARCH_IXP23XX_H
-
-/*
- * IXP2300 linux memory map:
- *
- * virt		phys		size
- * fffd0000	a0000000	64K		XSI2CPP_CSR
- * fffc0000	c4000000	4K		EXP_CFG
- * fff00000	c8000000	64K		PERIPHERAL
- * fe000000	1c0000000	16M		CAP_CSR
- * fd000000	1c8000000	16M		MSF_CSR
- * fb000000			16M		---
- * fa000000	1d8000000	32M		PCI_IO
- * f8000000	1da000000	32M		PCI_CFG
- * f6000000	1de000000	32M		PCI_CREG
- * f4000000			32M		---
- * f0000000	1e0000000	64M		PCI_MEM
- * e[c-f]000000					per-platform mappings
- */
-
-
-/****************************************************************************
- * Static mappings.
- ****************************************************************************/
-#define IXP23XX_XSI2CPP_CSR_PHYS	0xa0000000
-#define IXP23XX_XSI2CPP_CSR_VIRT	0xfffd0000
-#define IXP23XX_XSI2CPP_CSR_SIZE	0x00010000
-
-#define IXP23XX_EXP_CFG_PHYS		0xc4000000
-#define IXP23XX_EXP_CFG_VIRT		0xfffc0000
-#define IXP23XX_EXP_CFG_SIZE		0x00001000
-
-#define IXP23XX_PERIPHERAL_PHYS		0xc8000000
-#define IXP23XX_PERIPHERAL_VIRT		0xfff00000
-#define IXP23XX_PERIPHERAL_SIZE		0x00010000
-
-#define IXP23XX_CAP_CSR_PHYS		0x1c0000000ULL
-#define IXP23XX_CAP_CSR_VIRT		0xfe000000
-#define IXP23XX_CAP_CSR_SIZE		0x01000000
-
-#define IXP23XX_MSF_CSR_PHYS		0x1c8000000ULL
-#define IXP23XX_MSF_CSR_VIRT		0xfd000000
-#define IXP23XX_MSF_CSR_SIZE		0x01000000
-
-#define IXP23XX_PCI_IO_PHYS		0x1d8000000ULL
-#define IXP23XX_PCI_IO_VIRT		0xfa000000
-#define IXP23XX_PCI_IO_SIZE		0x02000000
-
-#define IXP23XX_PCI_CFG_PHYS		0x1da000000ULL
-#define IXP23XX_PCI_CFG_VIRT		0xf8000000
-#define IXP23XX_PCI_CFG_SIZE		0x02000000
-#define IXP23XX_PCI_CFG0_VIRT		IXP23XX_PCI_CFG_VIRT
-#define IXP23XX_PCI_CFG1_VIRT		(IXP23XX_PCI_CFG_VIRT + 0x01000000)
-
-#define IXP23XX_PCI_CREG_PHYS		0x1de000000ULL
-#define IXP23XX_PCI_CREG_VIRT		0xf6000000
-#define IXP23XX_PCI_CREG_SIZE		0x02000000
-#define IXP23XX_PCI_CSR_VIRT		(IXP23XX_PCI_CREG_VIRT + 0x01000000)
-
-#define IXP23XX_PCI_MEM_START		0xe0000000
-#define IXP23XX_PCI_MEM_PHYS		0x1e0000000ULL
-#define IXP23XX_PCI_MEM_VIRT		0xf0000000
-#define IXP23XX_PCI_MEM_SIZE		0x04000000
-
-
-/****************************************************************************
- * XSI2CPP CSRs.
- ****************************************************************************/
-#define IXP23XX_XSI2CPP_REG(x)		((volatile unsigned long *)(IXP23XX_XSI2CPP_CSR_VIRT + (x)))
-#define IXP23XX_CPP2XSI_CURR_XFER_REG3	IXP23XX_XSI2CPP_REG(0xf8)
-#define IXP23XX_CPP2XSI_ADDR_31		(1 << 19)
-#define IXP23XX_CPP2XSI_PSH_OFF		(1 << 20)
-#define IXP23XX_CPP2XSI_COH_OFF		(1 << 21)
-
-
-/****************************************************************************
- * Expansion Bus Config.
- ****************************************************************************/
-#define IXP23XX_EXP_CFG_REG(x)		((volatile unsigned long *)(IXP23XX_EXP_CFG_VIRT + (x)))
-#define IXP23XX_EXP_CS0			IXP23XX_EXP_CFG_REG(0x00)
-#define IXP23XX_EXP_CS1			IXP23XX_EXP_CFG_REG(0x04)
-#define IXP23XX_EXP_CS2			IXP23XX_EXP_CFG_REG(0x08)
-#define IXP23XX_EXP_CS3			IXP23XX_EXP_CFG_REG(0x0c)
-#define IXP23XX_EXP_CS4			IXP23XX_EXP_CFG_REG(0x10)
-#define IXP23XX_EXP_CS5			IXP23XX_EXP_CFG_REG(0x14)
-#define IXP23XX_EXP_CS6			IXP23XX_EXP_CFG_REG(0x18)
-#define IXP23XX_EXP_CS7			IXP23XX_EXP_CFG_REG(0x1c)
-#define IXP23XX_FLASH_WRITABLE		(0x2)
-#define IXP23XX_FLASH_BUS8		(0x1)
-
-#define IXP23XX_EXP_CFG0		IXP23XX_EXP_CFG_REG(0x20)
-#define IXP23XX_EXP_CFG1		IXP23XX_EXP_CFG_REG(0x24)
-#define IXP23XX_EXP_CFG0_MEM_MAP		(1 << 31)
-#define IXP23XX_EXP_CFG0_XSCALE_SPEED_SEL 	(3 << 22)
-#define IXP23XX_EXP_CFG0_XSCALE_SPEED_EN	(1 << 21)
-#define IXP23XX_EXP_CFG0_CPP_SPEED_SEL		(3 << 19)
-#define IXP23XX_EXP_CFG0_CPP_SPEED_EN		(1 << 18)
-#define IXP23XX_EXP_CFG0_PCI_SWIN		(3 << 16)
-#define IXP23XX_EXP_CFG0_PCI_DWIN		(3 << 14)
-#define IXP23XX_EXP_CFG0_PCI33_MODE		(1 << 13)
-#define IXP23XX_EXP_CFG0_QDR_SPEED_SEL		(1 << 12)
-#define IXP23XX_EXP_CFG0_CPP_DIV_SEL		(1 << 5)
-#define IXP23XX_EXP_CFG0_XSI_NOT_PRES		(1 << 4)
-#define IXP23XX_EXP_CFG0_PROM_BOOT		(1 << 3)
-#define IXP23XX_EXP_CFG0_PCI_ARB		(1 << 2)
-#define IXP23XX_EXP_CFG0_PCI_HOST		(1 << 1)
-#define IXP23XX_EXP_CFG0_FLASH_WIDTH		(1 << 0)
-
-#define IXP23XX_EXP_UNIT_FUSE		IXP23XX_EXP_CFG_REG(0x28)
-#define IXP23XX_EXP_MSF_MUX		IXP23XX_EXP_CFG_REG(0x30)
-#define IXP23XX_EXP_CFG_FUSE		IXP23XX_EXP_CFG_REG(0x34)
-
-#define IXP23XX_EXP_BUS_PHYS		0x90000000
-#define IXP23XX_EXP_BUS_WINDOW_SIZE	0x01000000
-
-#define IXP23XX_EXP_BUS_CS0_BASE	(IXP23XX_EXP_BUS_PHYS + 0x00000000)
-#define IXP23XX_EXP_BUS_CS1_BASE	(IXP23XX_EXP_BUS_PHYS + 0x01000000)
-#define IXP23XX_EXP_BUS_CS2_BASE	(IXP23XX_EXP_BUS_PHYS + 0x02000000)
-#define IXP23XX_EXP_BUS_CS3_BASE	(IXP23XX_EXP_BUS_PHYS + 0x03000000)
-#define IXP23XX_EXP_BUS_CS4_BASE	(IXP23XX_EXP_BUS_PHYS + 0x04000000)
-#define IXP23XX_EXP_BUS_CS5_BASE	(IXP23XX_EXP_BUS_PHYS + 0x05000000)
-#define IXP23XX_EXP_BUS_CS6_BASE	(IXP23XX_EXP_BUS_PHYS + 0x06000000)
-#define IXP23XX_EXP_BUS_CS7_BASE	(IXP23XX_EXP_BUS_PHYS + 0x07000000)
-
-
-/****************************************************************************
- * Peripherals.
- ****************************************************************************/
-#define IXP23XX_UART1_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x0000)
-#define IXP23XX_UART2_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x1000)
-#define IXP23XX_PMU_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x2000)
-#define IXP23XX_INTC_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x3000)
-#define IXP23XX_GPIO_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x4000)
-#define IXP23XX_TIMER_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x5000)
-#define IXP23XX_NPE0_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x6000)
-#define IXP23XX_DSR_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x7000)
-#define IXP23XX_NPE1_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x8000)
-#define IXP23XX_ETH0_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0x9000)
-#define IXP23XX_ETH1_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0xA000)
-#define IXP23XX_GIG0_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0xB000)
-#define IXP23XX_GIG1_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0xC000)
-#define IXP23XX_DDRS_VIRT		(IXP23XX_PERIPHERAL_VIRT + 0xD000)
-
-#define IXP23XX_UART1_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x0000)
-#define IXP23XX_UART2_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x1000)
-#define IXP23XX_PMU_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x2000)
-#define IXP23XX_INTC_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x3000)
-#define IXP23XX_GPIO_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x4000)
-#define IXP23XX_TIMER_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x5000)
-#define IXP23XX_NPE0_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x6000)
-#define IXP23XX_DSR_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x7000)
-#define IXP23XX_NPE1_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x8000)
-#define IXP23XX_ETH0_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0x9000)
-#define IXP23XX_ETH1_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0xA000)
-#define IXP23XX_GIG0_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0xB000)
-#define IXP23XX_GIG1_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0xC000)
-#define IXP23XX_DDRS_PHYS		(IXP23XX_PERIPHERAL_PHYS + 0xD000)
-
-
-/****************************************************************************
- * Interrupt controller.
- ****************************************************************************/
-#define IXP23XX_INTC_REG(x)		 ((volatile unsigned long *)(IXP23XX_INTC_VIRT + (x)))
-#define IXP23XX_INTR_ST1		IXP23XX_INTC_REG(0x00)
-#define IXP23XX_INTR_ST2		IXP23XX_INTC_REG(0x04)
-#define IXP23XX_INTR_ST3		IXP23XX_INTC_REG(0x08)
-#define IXP23XX_INTR_ST4		IXP23XX_INTC_REG(0x0c)
-#define IXP23XX_INTR_EN1		IXP23XX_INTC_REG(0x10)
-#define IXP23XX_INTR_EN2		IXP23XX_INTC_REG(0x14)
-#define IXP23XX_INTR_EN3		IXP23XX_INTC_REG(0x18)
-#define IXP23XX_INTR_EN4		IXP23XX_INTC_REG(0x1c)
-#define IXP23XX_INTR_SEL1		IXP23XX_INTC_REG(0x20)
-#define IXP23XX_INTR_SEL2		IXP23XX_INTC_REG(0x24)
-#define IXP23XX_INTR_SEL3		IXP23XX_INTC_REG(0x28)
-#define IXP23XX_INTR_SEL4		IXP23XX_INTC_REG(0x2c)
-#define IXP23XX_INTR_IRQ_ST1		IXP23XX_INTC_REG(0x30)
-#define IXP23XX_INTR_IRQ_ST2		IXP23XX_INTC_REG(0x34)
-#define IXP23XX_INTR_IRQ_ST3		IXP23XX_INTC_REG(0x38)
-#define IXP23XX_INTR_IRQ_ST4		IXP23XX_INTC_REG(0x3c)
-#define IXP23XX_INTR_IRQ_ENC_ST_OFFSET	0x54
-
-
-/****************************************************************************
- * GPIO.
- ****************************************************************************/
-#define IXP23XX_GPIO_REG(x)		((volatile unsigned long *)(IXP23XX_GPIO_VIRT + (x)))
-#define IXP23XX_GPIO_GPOUTR		IXP23XX_GPIO_REG(0x00)
-#define IXP23XX_GPIO_GPOER		IXP23XX_GPIO_REG(0x04)
-#define IXP23XX_GPIO_GPINR		IXP23XX_GPIO_REG(0x08)
-#define IXP23XX_GPIO_GPISR		IXP23XX_GPIO_REG(0x0c)
-#define IXP23XX_GPIO_GPIT1R		IXP23XX_GPIO_REG(0x10)
-#define IXP23XX_GPIO_GPIT2R		IXP23XX_GPIO_REG(0x14)
-#define IXP23XX_GPIO_GPCLKR		IXP23XX_GPIO_REG(0x18)
-#define IXP23XX_GPIO_GPDBSELR 		IXP23XX_GPIO_REG(0x1c)
-
-#define IXP23XX_GPIO_STYLE_MASK		0x7
-#define IXP23XX_GPIO_STYLE_ACTIVE_HIGH	0x0
-#define IXP23XX_GPIO_STYLE_ACTIVE_LOW	0x1
-#define IXP23XX_GPIO_STYLE_RISING_EDGE	0x2
-#define IXP23XX_GPIO_STYLE_FALLING_EDGE	0x3
-#define IXP23XX_GPIO_STYLE_TRANSITIONAL	0x4
-
-#define IXP23XX_GPIO_STYLE_SIZE		3
-
-
-/****************************************************************************
- * Timer.
- ****************************************************************************/
-#define IXP23XX_TIMER_REG(x)		((volatile unsigned long *)(IXP23XX_TIMER_VIRT + (x)))
-#define IXP23XX_TIMER_CONT		IXP23XX_TIMER_REG(0x00)
-#define IXP23XX_TIMER1_TIMESTAMP	IXP23XX_TIMER_REG(0x04)
-#define IXP23XX_TIMER1_RELOAD		IXP23XX_TIMER_REG(0x08)
-#define IXP23XX_TIMER2_TIMESTAMP	IXP23XX_TIMER_REG(0x0c)
-#define IXP23XX_TIMER2_RELOAD		IXP23XX_TIMER_REG(0x10)
-#define IXP23XX_TIMER_WDOG		IXP23XX_TIMER_REG(0x14)
-#define IXP23XX_TIMER_WDOG_EN		IXP23XX_TIMER_REG(0x18)
-#define IXP23XX_TIMER_WDOG_KEY		IXP23XX_TIMER_REG(0x1c)
-#define IXP23XX_TIMER_WDOG_KEY_MAGIC	0x482e
-#define IXP23XX_TIMER_STATUS		IXP23XX_TIMER_REG(0x20)
-#define IXP23XX_TIMER_SOFT_RESET	IXP23XX_TIMER_REG(0x24)
-#define IXP23XX_TIMER_SOFT_RESET_EN	IXP23XX_TIMER_REG(0x28)
-
-#define IXP23XX_TIMER_ENABLE		(1 << 0)
-#define IXP23XX_TIMER_ONE_SHOT		(1 << 1)
-/* Low order bits of reload value ignored */
-#define IXP23XX_TIMER_RELOAD_MASK	(0x3)
-#define IXP23XX_TIMER_DISABLED		(0x0)
-#define IXP23XX_TIMER1_INT_PEND		(1 << 0)
-#define IXP23XX_TIMER2_INT_PEND		(1 << 1)
-#define IXP23XX_TIMER_STATUS_TS_PEND	(1 << 2)
-#define IXP23XX_TIMER_STATUS_WDOG_PEND	(1 << 3)
-#define IXP23XX_TIMER_STATUS_WARM_RESET	(1 << 4)
-
-
-/****************************************************************************
- * CAP CSRs.
- ****************************************************************************/
-#define IXP23XX_GLOBAL_REG(x)		((volatile unsigned long *)(IXP23XX_CAP_CSR_VIRT + 0x4a00 + (x)))
-#define IXP23XX_PRODUCT_ID		IXP23XX_GLOBAL_REG(0x00)
-#define IXP23XX_MISC_CONTROL		IXP23XX_GLOBAL_REG(0x04)
-#define IXP23XX_MSF_CLK_CNTRL		IXP23XX_GLOBAL_REG(0x08)
-#define IXP23XX_RESET0			IXP23XX_GLOBAL_REG(0x0c)
-#define IXP23XX_RESET1			IXP23XX_GLOBAL_REG(0x10)
-#define IXP23XX_STRAP_OPTIONS		IXP23XX_GLOBAL_REG(0x18)
-
-#define IXP23XX_ENABLE_WATCHDOG		(1 << 24)
-#define IXP23XX_SHPC_INIT_COMP		(1 << 21)
-#define IXP23XX_RST_ALL			(1 << 16)
-#define IXP23XX_RESET_PCI		(1 << 2)
-#define IXP23XX_PCI_UNIT_RESET		(1 << 1)
-#define IXP23XX_XSCALE_RESET		(1 << 0)
-
-#define IXP23XX_UENGINE_CSR_VIRT_BASE	(IXP23XX_CAP_CSR_VIRT + 0x18000)
-
-
-/****************************************************************************
- * PCI CSRs.
- ****************************************************************************/
-#define IXP23XX_PCI_CREG(x)		((volatile unsigned long *)(IXP23XX_PCI_CREG_VIRT + (x)))
-#define IXP23XX_PCI_CMDSTAT		IXP23XX_PCI_CREG(0x04)
-#define IXP23XX_PCI_SRAM_BAR		IXP23XX_PCI_CREG(0x14)
-#define IXP23XX_PCI_SDRAM_BAR		IXP23XX_PCI_CREG(0x18)
-
-
-#define IXP23XX_PCI_CSR(x)		((volatile unsigned long *)(IXP23XX_PCI_CREG_VIRT + 0x01000000 + (x)))
-#define IXP23XX_PCI_OUT_INT_STATUS	IXP23XX_PCI_CSR(0x0030)
-#define IXP23XX_PCI_OUT_INT_MASK	IXP23XX_PCI_CSR(0x0034)
-#define IXP23XX_PCI_SRAM_BASE_ADDR_MASK IXP23XX_PCI_CSR(0x00fc)
-#define IXP23XX_PCI_DRAM_BASE_ADDR_MASK IXP23XX_PCI_CSR(0x0100)
-#define IXP23XX_PCI_CONTROL		IXP23XX_PCI_CSR(0x013c)
-#define IXP23XX_PCI_ADDR_EXT		IXP23XX_PCI_CSR(0x0140)
-#define IXP23XX_PCI_ME_PUSH_STATUS	IXP23XX_PCI_CSR(0x0148)
-#define IXP23XX_PCI_ME_PUSH_EN		IXP23XX_PCI_CSR(0x014c)
-#define IXP23XX_PCI_ERR_STATUS		IXP23XX_PCI_CSR(0x0150)
-#define IXP23XX_PCI_ERROR_STATUS	IXP23XX_PCI_CSR(0x0150)
-#define IXP23XX_PCI_ERR_ENABLE		IXP23XX_PCI_CSR(0x0154)
-#define IXP23XX_PCI_XSCALE_INT_STATUS	IXP23XX_PCI_CSR(0x0158)
-#define IXP23XX_PCI_XSCALE_INT_ENABLE	IXP23XX_PCI_CSR(0x015c)
-#define IXP23XX_PCI_CPP_ADDR_BITS	IXP23XX_PCI_CSR(0x0160)
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/memory.h b/arch/arm/mach-ixp23xx/include/mach/memory.h
deleted file mode 100644
index 6cf0704..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/memory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/memory.h
- *
- * Copyright (c) 2003-2004 Intel Corp.
- *
- * 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 __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#include <mach/hardware.h>
-
-/*
- * Physical DRAM offset.
- */
-#define PLAT_PHYS_OFFSET		(0x00000000)
-
-#define IXP23XX_PCI_SDRAM_OFFSET (*((volatile int *)IXP23XX_PCI_SDRAM_BAR) & 0xfffffff0)
-
-#define __phys_to_bus(x)	((x) + (IXP23XX_PCI_SDRAM_OFFSET - PHYS_OFFSET))
-#define __bus_to_phys(x)	((x) - (IXP23XX_PCI_SDRAM_OFFSET - PHYS_OFFSET))
-
-#define __virt_to_bus(v)	__phys_to_bus(__virt_to_phys(v))
-#define __bus_to_virt(b)	__phys_to_virt(__bus_to_phys(b))
-#define __pfn_to_bus(p)		__phys_to_bus(__pfn_to_phys(p))
-#define __bus_to_pfn(b)		__phys_to_pfn(__bus_to_phys(b))
-
-#define arch_is_coherent()	1
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/platform.h b/arch/arm/mach-ixp23xx/include/mach/platform.h
deleted file mode 100644
index 798d8b4..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/platform.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/platform.h
- *
- * Various bits of code used by platform-level code.
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2005 (c) MontaVista Software, 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 __ASSEMBLY__
-
-static inline unsigned long ixp2000_reg_read(volatile void *reg)
-{
-	return *((volatile unsigned long *)reg);
-}
-
-static inline void ixp2000_reg_write(volatile void *reg, unsigned long val)
-{
-	*((volatile unsigned long *)reg) = val;
-}
-
-static inline void ixp2000_reg_wrb(volatile void *reg, unsigned long val)
-{
-	*((volatile unsigned long *)reg) = val;
-}
-
-struct pci_sys_data;
-
-void ixp23xx_map_io(void);
-void ixp23xx_init_irq(void);
-void ixp23xx_sys_init(void);
-void ixp23xx_restart(char, const char *);
-int ixp23xx_pci_setup(int, struct pci_sys_data *);
-void ixp23xx_pci_preinit(void);
-extern struct pci_ops ixp23xx_pci_ops;
-void ixp23xx_pci_slave_init(void);
-
-extern struct sys_timer ixp23xx_timer;
-
-#define IXP23XX_UART_XTAL		14745600
-
-#ifndef __ASSEMBLY__
-/*
- * Is system memory on the XSI or CPP bus?
- */
-static inline unsigned ixp23xx_cpp_boot(void)
-{
-	return (*IXP23XX_EXP_CFG0 & IXP23XX_EXP_CFG0_XSI_NOT_PRES);
-}
-#endif
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/time.h b/arch/arm/mach-ixp23xx/include/mach/time.h
deleted file mode 100644
index b61dafc..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/time.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/time.h
- */
diff --git a/arch/arm/mach-ixp23xx/include/mach/timex.h b/arch/arm/mach-ixp23xx/include/mach/timex.h
deleted file mode 100644
index e341e9c..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/timex.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/timex.h
- *
- * XScale architecture timex specifications
- */
-
-#define CLOCK_TICK_RATE 75000000
diff --git a/arch/arm/mach-ixp23xx/include/mach/uncompress.h b/arch/arm/mach-ixp23xx/include/mach/uncompress.h
deleted file mode 100644
index 8b4c358..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/uncompress.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/uncompress.h
- *
- * Copyright (C) 2002-2004 Intel 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.
- */
-
-#ifndef __ASM_ARCH_UNCOMPRESS_H
-#define __ASM_ARCH_UNCOMPRESS_H
-
-#include <mach/ixp23xx.h>
-#include <linux/serial_reg.h>
-
-#define UART_BASE	((volatile u32 *)IXP23XX_UART1_PHYS)
-
-static inline void putc(char c)
-{
-	int j;
-
-	for (j = 0; j < 0x1000; j++) {
-		if (UART_BASE[UART_LSR] & UART_LSR_THRE)
-			break;
-		barrier();
-	}
-
-	UART_BASE[UART_TX] = c;
-}
-
-static inline void flush(void)
-{
-}
-
-#define arch_decomp_setup()
-#define arch_decomp_wdog()
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
deleted file mode 100644
index 8b48e32..0000000
--- a/arch/arm/mach-ixp23xx/ixdp2351.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/ixdp2351.c
- *
- * IXDP2351 board-specific routines
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2005 (c) MontaVista Software, Inc.
- *
- * Based on 2.4 code Copyright 2004 (c) Intel Corporation
- *
- * 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/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/pci.h>
-
-/*
- * IXDP2351 Interrupt Handling
- */
-static void ixdp2351_inta_mask(struct irq_data *d)
-{
-	*IXDP2351_CPLD_INTA_MASK_SET_REG = IXDP2351_INTA_IRQ_MASK(d->irq);
-}
-
-static void ixdp2351_inta_unmask(struct irq_data *d)
-{
-	*IXDP2351_CPLD_INTA_MASK_CLR_REG = IXDP2351_INTA_IRQ_MASK(d->irq);
-}
-
-static void ixdp2351_inta_handler(unsigned int irq, struct irq_desc *desc)
-{
-	u16 ex_interrupt =
-		*IXDP2351_CPLD_INTA_STAT_REG & IXDP2351_INTA_IRQ_VALID;
-	int i;
-
-	desc->irq_data.chip->irq_mask(&desc->irq_data);
-
-	for (i = 0; i < IXDP2351_INTA_IRQ_NUM; i++) {
-		if (ex_interrupt & (1 << i)) {
-			int cpld_irq =
-				IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + i);
-			generic_handle_irq(cpld_irq);
-		}
-	}
-
-	desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixdp2351_inta_chip = {
-	.irq_ack	= ixdp2351_inta_mask,
-	.irq_mask	= ixdp2351_inta_mask,
-	.irq_unmask	= ixdp2351_inta_unmask
-};
-
-static void ixdp2351_intb_mask(struct irq_data *d)
-{
-	*IXDP2351_CPLD_INTB_MASK_SET_REG = IXDP2351_INTB_IRQ_MASK(d->irq);
-}
-
-static void ixdp2351_intb_unmask(struct irq_data *d)
-{
-	*IXDP2351_CPLD_INTB_MASK_CLR_REG = IXDP2351_INTB_IRQ_MASK(d->irq);
-}
-
-static void ixdp2351_intb_handler(unsigned int irq, struct irq_desc *desc)
-{
-	u16 ex_interrupt =
-		*IXDP2351_CPLD_INTB_STAT_REG & IXDP2351_INTB_IRQ_VALID;
-	int i;
-
-	desc->irq_data.chip->irq_ack(&desc->irq_data);
-
-	for (i = 0; i < IXDP2351_INTB_IRQ_NUM; i++) {
-		if (ex_interrupt & (1 << i)) {
-			int cpld_irq =
-				IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + i);
-			generic_handle_irq(cpld_irq);
-		}
-	}
-
-	desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixdp2351_intb_chip = {
-	.irq_ack	= ixdp2351_intb_mask,
-	.irq_mask	= ixdp2351_intb_mask,
-	.irq_unmask	= ixdp2351_intb_unmask
-};
-
-void __init ixdp2351_init_irq(void)
-{
-	int irq;
-
-	/* Mask all interrupts from CPLD, disable simulation */
-	*IXDP2351_CPLD_INTA_MASK_SET_REG = (u16) -1;
-	*IXDP2351_CPLD_INTB_MASK_SET_REG = (u16) -1;
-	*IXDP2351_CPLD_INTA_SIM_REG = 0;
-	*IXDP2351_CPLD_INTB_SIM_REG = 0;
-
-	ixp23xx_init_irq();
-
-	for (irq = IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE);
-	     irq <
-	     IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + IXDP2351_INTA_IRQ_NUM);
-	     irq++) {
-		if (IXDP2351_INTA_IRQ_MASK(irq) & IXDP2351_INTA_IRQ_VALID) {
-			set_irq_flags(irq, IRQF_VALID);
-			irq_set_chip_and_handler(irq, &ixdp2351_inta_chip,
-						 handle_level_irq);
-		}
-	}
-
-	for (irq = IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE);
-	     irq <
-	     IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + IXDP2351_INTB_IRQ_NUM);
-	     irq++) {
-		if (IXDP2351_INTB_IRQ_MASK(irq) & IXDP2351_INTB_IRQ_VALID) {
-			set_irq_flags(irq, IRQF_VALID);
-			irq_set_chip_and_handler(irq, &ixdp2351_intb_chip,
-						 handle_level_irq);
-		}
-	}
-
-	irq_set_chained_handler(IRQ_IXP23XX_INTA, ixdp2351_inta_handler);
-	irq_set_chained_handler(IRQ_IXP23XX_INTB, ixdp2351_intb_handler);
-}
-
-/*
- * IXDP2351 PCI
- */
-
-/*
- * This board does not do normal PCI IRQ routing, or any
- * sort of swizzling, so we just need to check where on the
- * bus the device is and figure out what CPLD pin it is
- * being routed to.
- */
-#define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
-
-static int __init ixdp2351_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-	u8 bus = dev->bus->number;
-	u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
-	struct pci_bus *tmp_bus = dev->bus;
-
-	/* Primary bus, no interrupts here */
-	if (!bus)
-		return -1;
-
-	/* Lookup first leaf in bus tree */
-	while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL))
-		tmp_bus = tmp_bus->parent;
-
-	/* Select between known bridges */
-	switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) {
-		/* Device is located after first bridge */
-	case 0x0008:
-		if (tmp_bus == dev->bus) {
-			/* Device is located directy after first bridge */
-			switch (devpin) {
-				/* Onboard 82546 */
-			case DEVPIN(1, 1):	/* Onboard 82546 ch 0 */
-				return IRQ_IXDP2351_INTA_82546;
-			case DEVPIN(1, 2):	/* Onboard 82546 ch 1 */
-				return IRQ_IXDP2351_INTB_82546;
-				/* PMC SLOT */
-			case DEVPIN(0, 1):	/* PMCP INTA# */
-			case DEVPIN(2, 4):	/* PMCS INTD# */
-				return IRQ_IXDP2351_SPCI_PMC_INTA;
-			case DEVPIN(0, 2):	/* PMCP INTB# */
-			case DEVPIN(2, 1):	/* PMCS INTA# */
-				return IRQ_IXDP2351_SPCI_PMC_INTB;
-			case DEVPIN(0, 3):	/* PMCP INTC# */
-			case DEVPIN(2, 2):	/* PMCS INTB# */
-				return IRQ_IXDP2351_SPCI_PMC_INTC;
-			case DEVPIN(0, 4):	/* PMCP INTD# */
-			case DEVPIN(2, 3):	/* PMCS INTC# */
-				return IRQ_IXDP2351_SPCI_PMC_INTD;
-			}
-		} else {
-			/* Device is located indirectly after first bridge */
-			/* Not supported now */
-			return -1;
-		}
-		break;
-	case 0x0010:
-		if (tmp_bus == dev->bus) {
-			/* Device is located directy after second bridge */
-			/* Secondary bus of second bridge */
-			switch (devpin) {
-			case DEVPIN(0, 1):	/* DB#0 */
-			case DEVPIN(0, 2):
-			case DEVPIN(0, 3):
-			case DEVPIN(0, 4):
-				return IRQ_IXDP2351_SPCI_DB_0;
-			case DEVPIN(1, 1):	/* DB#1 */
-			case DEVPIN(1, 2):
-			case DEVPIN(1, 3):
-			case DEVPIN(1, 4):
-				return IRQ_IXDP2351_SPCI_DB_1;
-			case DEVPIN(2, 1):	/* FIC1 */
-			case DEVPIN(2, 2):
-			case DEVPIN(2, 3):
-			case DEVPIN(2, 4):
-			case DEVPIN(3, 1):	/* FIC2 */
-			case DEVPIN(3, 2):
-			case DEVPIN(3, 3):
-			case DEVPIN(3, 4):
-				return IRQ_IXDP2351_SPCI_FIC;
-			}
-		} else {
-			/* Device is located indirectly after second bridge */
-			/* Not supported now */
-			return -1;
-		}
-		break;
-	}
-
-	return -1;
-}
-
-struct hw_pci ixdp2351_pci __initdata = {
-	.nr_controllers	= 1,
-	.ops		= &ixp23xx_pci_ops,
-	.preinit	= ixp23xx_pci_preinit,
-	.setup		= ixp23xx_pci_setup,
-	.map_irq	= ixdp2351_map_irq,
-};
-
-int __init ixdp2351_pci_init(void)
-{
-	if (machine_is_ixdp2351())
-		pci_common_init(&ixdp2351_pci);
-
-	return 0;
-}
-
-subsys_initcall(ixdp2351_pci_init);
-
-/*
- * IXDP2351 Static Mapped I/O
- */
-static struct map_desc ixdp2351_io_desc[] __initdata = {
-	{
-		.virtual	= IXDP2351_NP_VIRT_BASE,
-		.pfn		= __phys_to_pfn((u64)IXDP2351_NP_PHYS_BASE),
-		.length		= IXDP2351_NP_PHYS_SIZE,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= IXDP2351_BB_BASE_VIRT,
-		.pfn		= __phys_to_pfn((u64)IXDP2351_BB_BASE_PHYS),
-		.length		= IXDP2351_BB_SIZE,
-		.type		= MT_DEVICE
-	}
-};
-
-static void __init ixdp2351_map_io(void)
-{
-	ixp23xx_map_io();
-	iotable_init(ixdp2351_io_desc, ARRAY_SIZE(ixdp2351_io_desc));
-}
-
-static struct physmap_flash_data ixdp2351_flash_data = {
-	.width		= 1,
-};
-
-static struct resource ixdp2351_flash_resource = {
-	.start		= 0x90000000,
-	.end		= 0x93ffffff,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2351_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &ixdp2351_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &ixdp2351_flash_resource,
-};
-
-static void __init ixdp2351_init(void)
-{
-	platform_device_register(&ixdp2351_flash);
-
-	/*
-	 * Mark flash as writeable
-	 */
-	IXP23XX_EXP_CS0[0] |= IXP23XX_FLASH_WRITABLE;
-	IXP23XX_EXP_CS0[1] |= IXP23XX_FLASH_WRITABLE;
-	IXP23XX_EXP_CS0[2] |= IXP23XX_FLASH_WRITABLE;
-	IXP23XX_EXP_CS0[3] |= IXP23XX_FLASH_WRITABLE;
-
-	ixp23xx_sys_init();
-}
-
-static void ixdp2351_restart(char mode, const char *cmd)
-{
-	/* First try machine specific support */
-
-	*IXDP2351_CPLD_RESET1_REG = IXDP2351_CPLD_RESET1_MAGIC;
-	(void) *IXDP2351_CPLD_RESET1_REG;
-	*IXDP2351_CPLD_RESET1_REG = IXDP2351_CPLD_RESET1_ENABLE;
-
-	ixp23xx_restart(mode, cmd);
-}
-
-MACHINE_START(IXDP2351, "Intel IXDP2351 Development Platform")
-	/* Maintainer: MontaVista Software, Inc. */
-	.map_io		= ixdp2351_map_io,
-	.init_irq	= ixdp2351_init_irq,
-	.timer		= &ixp23xx_timer,
-	.atag_offset	= 0x100,
-	.init_machine	= ixdp2351_init,
-	.restart	= ixdp2351_restart,
-MACHINE_END
diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c
deleted file mode 100644
index 9211506..0000000
--- a/arch/arm/mach-ixp23xx/pci.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/pci.c
- *
- * PCI routines for IXP23XX based systems
- *
- * Copyright (c) 2005 MontaVista Software, Inc.
- *
- * based on original code:
- *
- * Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Copyright 2002-2005 Intel Corp.
- *
- * 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/sched.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/sizes.h>
-#include <asm/mach/pci.h>
-#include <mach/hardware.h>
-
-extern int (*external_fault) (unsigned long, struct pt_regs *);
-
-static volatile int pci_master_aborts = 0;
-
-#ifdef DEBUG
-#define DBG(x...)	printk(x)
-#else
-#define DBG(x...)
-#endif
-
-int clear_master_aborts(void);
-
-static u32
-*ixp23xx_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
-{
-	u32 *paddress;
-
-	/*
-	 * Must be dword aligned
-	 */
-	where &= ~3;
-
-	/*
-	 * For top bus, generate type 0, else type 1
-	 */
-	if (!bus_nr) {
-		if (PCI_SLOT(devfn) >= 8)
-			return 0;
-
-		paddress = (u32 *) (IXP23XX_PCI_CFG0_VIRT
-				    | (1 << (PCI_SLOT(devfn) + 16))
-				    | (PCI_FUNC(devfn) << 8) | where);
-	} else {
-		paddress = (u32 *) (IXP23XX_PCI_CFG1_VIRT
-				    | (bus_nr << 16)
-				    | (PCI_SLOT(devfn) << 11)
-				    | (PCI_FUNC(devfn) << 8) | where);
-	}
-
-	return paddress;
-}
-
-/*
- * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
- * 0 and 3 are not valid indexes...
- */
-static u32 bytemask[] = {
-	/*0*/	0,
-	/*1*/	0xff,
-	/*2*/	0xffff,
-	/*3*/	0,
-	/*4*/	0xffffffff,
-};
-
-static int ixp23xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
-				int where, int size, u32 *value)
-{
-	u32 n;
-	u32 *addr;
-
-	n = where % 4;
-
-	DBG("In config_read(%d) %d from dev %d:%d:%d\n", size, where,
-		bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
-
-	addr = ixp23xx_pci_config_addr(bus->number, devfn, where);
-	if (!addr)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	pci_master_aborts = 0;
-	*value = (*addr >> (8*n)) & bytemask[size];
-	if (pci_master_aborts) {
-			pci_master_aborts = 0;
-			*value = 0xffffffff;
-			return PCIBIOS_DEVICE_NOT_FOUND;
-		}
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-/*
- * We don't do error checking on the address for writes.
- * It's assumed that the user checked for the device existing first
- * by doing a read first.
- */
-static int ixp23xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
-					int where, int size, u32 value)
-{
-	u32 mask;
-	u32 *addr;
-	u32 temp;
-
-	mask = ~(bytemask[size] << ((where % 0x4) * 8));
-	addr = ixp23xx_pci_config_addr(bus->number, devfn, where);
-	if (!addr)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	temp = (u32) (value) << ((where % 0x4) * 8);
-	*addr = (*addr & mask) | temp;
-
-	clear_master_aborts();
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-struct pci_ops ixp23xx_pci_ops = {
-	.read	= ixp23xx_pci_read_config,
-	.write	= ixp23xx_pci_write_config,
-};
-
-int ixp23xx_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
-{
-	volatile unsigned long temp;
-	unsigned long flags;
-
-	pci_master_aborts = 1;
-
-	local_irq_save(flags);
-	temp = *IXP23XX_PCI_CONTROL;
-
-	/*
-	 * master abort and cmd tgt err
-	 */
-	if (temp & ((1 << 8) | (1 << 5)))
-		*IXP23XX_PCI_CONTROL = temp;
-
-	temp = *IXP23XX_PCI_CMDSTAT;
-
-	if (temp & (1 << 29))
-		*IXP23XX_PCI_CMDSTAT = temp;
-	local_irq_restore(flags);
-
-	/*
-	 * If it was an imprecise abort, then we need to correct the
-	 * return address to be _after_ the instruction.
-	 */
-	if (fsr & (1 << 10))
-		regs->ARM_pc += 4;
-
-	return 0;
-}
-
-int clear_master_aborts(void)
-{
-	volatile u32 temp;
-
-	temp = *IXP23XX_PCI_CONTROL;
-
-	/*
-	 * master abort and cmd tgt err
-	 */
-	if (temp & ((1 << 8) | (1 << 5)))
-		*IXP23XX_PCI_CONTROL = temp;
-
-	temp = *IXP23XX_PCI_CMDSTAT;
-
-	if (temp & (1 << 29))
-		*IXP23XX_PCI_CMDSTAT = temp;
-
-	return 0;
-}
-
-static void __init ixp23xx_pci_common_init(void)
-{
-#ifdef __ARMEB__
-	*IXP23XX_PCI_CONTROL |= 0x20000;	/* set I/O swapping */
-#endif
-	/*
-	 * ADDR_31 needs to be clear for PCI memory access to CPP memory
-	 */
-	*IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_ADDR_31;
-	*IXP23XX_CPP2XSI_CURR_XFER_REG3 |= IXP23XX_CPP2XSI_PSH_OFF;
-
-	/*
-	 * Select correct memory for PCI inbound transactions
-	 */
-	if (ixp23xx_cpp_boot()) {
-		*IXP23XX_PCI_CPP_ADDR_BITS &= ~(1 << 1);
-	} else {
-		*IXP23XX_PCI_CPP_ADDR_BITS |= (1 << 1);
-
-		/*
-		 * Enable coherency on A2 silicon.
-		 */
-		if (arch_is_coherent())
-			*IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_COH_OFF;
-	}
-}
-
-void __init ixp23xx_pci_preinit(void)
-{
-	pcibios_min_io = 0;
-	pcibios_min_mem = 0xe0000000;
-
-	pci_set_flags(0);
-
-	ixp23xx_pci_common_init();
-
-	hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS, 0,
-			"PCI config cycle to non-existent device");
-
-	*IXP23XX_PCI_ADDR_EXT = 0x0000e000;
-}
-
-/*
- * Prevent PCI layer from seeing the inbound host-bridge resources
- */
-static void __devinit pci_fixup_ixp23xx(struct pci_dev *dev)
-{
-	int i;
-
-	dev->class &= 0xff;
-	dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		dev->resource[i].start = 0;
-		dev->resource[i].end   = 0;
-		dev->resource[i].flags = 0;
-	}
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9002, pci_fixup_ixp23xx);
-
-/*
- * IXP2300 systems often have large resource requirements, so we just
- * use our own resource space.
- */
-static struct resource ixp23xx_pci_mem_space = {
-	.start	= IXP23XX_PCI_MEM_START,
-	.end	= IXP23XX_PCI_MEM_START + IXP23XX_PCI_MEM_SIZE - 1,
-	.flags	= IORESOURCE_MEM,
-	.name	= "PCI Mem Space"
-};
-
-static struct resource ixp23xx_pci_io_space = {
-	.start	= 0x00000100,
-	.end	= 0x01ffffff,
-	.flags	= IORESOURCE_IO,
-	.name	= "PCI I/O Space"
-};
-
-int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys)
-{
-	if (nr >= 1)
-		return 0;
-
-	pci_add_resource_offset(&sys->resources,
-				&ixp23xx_pci_io_space, sys->io_offset);
-	pci_add_resource_offset(&sys->resources,
-				&ixp23xx_pci_mem_space, sys->mem_offset);
-
-	return 1;
-}
-
-void __init ixp23xx_pci_slave_init(void)
-{
-	ixp23xx_pci_common_init();
-}
diff --git a/arch/arm/mach-ixp23xx/roadrunner.c b/arch/arm/mach-ixp23xx/roadrunner.c
deleted file mode 100644
index 8c0e5de..0000000
--- a/arch/arm/mach-ixp23xx/roadrunner.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/roadrunner.c
- *
- * RoadRunner board-specific routines
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2005 (c) MontaVista Software, Inc.
- *
- * Based on 2.4 code Copyright 2005 (c) ADI Engineering Corporation
- *
- * 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/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/pci.h>
-
-/*
- * Interrupt mapping
- */
-#define INTA		IRQ_ROADRUNNER_PCI_INTA
-#define INTB		IRQ_ROADRUNNER_PCI_INTB
-#define INTC		IRQ_ROADRUNNER_PCI_INTC
-#define INTD		IRQ_ROADRUNNER_PCI_INTD
-
-#define INTC_PIN	IXP23XX_GPIO_PIN_11
-#define INTD_PIN	IXP23XX_GPIO_PIN_12
-
-static int __init roadrunner_map_irq(const struct pci_dev *dev, u8 idsel,
-	u8 pin)
-{
-	static int pci_card_slot_irq[] = {INTB, INTC, INTD, INTA};
-	static int pmc_card_slot_irq[] = {INTA, INTB, INTC, INTD};
-	static int usb_irq[] = {INTB, INTC, INTD, -1};
-	static int mini_pci_1_irq[] = {INTB, INTC, -1, -1};
-	static int mini_pci_2_irq[] = {INTC, INTD, -1, -1};
-
-	switch(dev->bus->number) {
-		case 0:
-			switch(dev->devfn) {
-			case 0x0: // PCI-PCI bridge
-				break;
-			case 0x8: // PCI Card Slot
-				return pci_card_slot_irq[pin - 1];
-			case 0x10: // PMC Slot
-				return pmc_card_slot_irq[pin - 1];
-			case 0x18: // PMC Slot Secondary Agent
-				break;
-			case 0x20: // IXP Processor
-				break;
-			default:
-				return NO_IRQ;
-			}
-			break;
-
-		case 1:
-			switch(dev->devfn) {
-			case 0x0: // IDE Controller
-				return (pin == 1) ? INTC : -1;
-			case 0x8: // USB fun 0
-			case 0x9: // USB fun 1
-			case 0xa: // USB fun 2
-				return usb_irq[pin - 1];
-			case 0x10: // Mini PCI 1
-				return mini_pci_1_irq[pin-1];
-			case 0x18: // Mini PCI 2
-				return mini_pci_2_irq[pin-1];
-			case 0x20: // MEM slot
-				return (pin == 1) ? INTA : -1;
-			default:
-				return NO_IRQ;
-			}
-			break;
-
-		default:
-			return NO_IRQ;
-	}
-
-	return NO_IRQ;
-}
-
-static void __init roadrunner_pci_preinit(void)
-{
-	irq_set_irq_type(IRQ_ROADRUNNER_PCI_INTC, IRQ_TYPE_LEVEL_LOW);
-	irq_set_irq_type(IRQ_ROADRUNNER_PCI_INTD, IRQ_TYPE_LEVEL_LOW);
-
-	ixp23xx_pci_preinit();
-}
-
-static struct hw_pci roadrunner_pci __initdata = {
-	.nr_controllers	= 1,
-	.ops		= &ixp23xx_pci_ops,
-	.preinit	= roadrunner_pci_preinit,
-	.setup		= ixp23xx_pci_setup,
-	.map_irq	= roadrunner_map_irq,
-};
-
-static int __init roadrunner_pci_init(void)
-{
-	if (machine_is_roadrunner())
-		pci_common_init(&roadrunner_pci);
-
-	return 0;
-};
-
-subsys_initcall(roadrunner_pci_init);
-
-static struct physmap_flash_data roadrunner_flash_data = {
-	.width		= 2,
-};
-
-static struct resource roadrunner_flash_resource = {
-	.start		= 0x90000000,
-	.end		= 0x93ffffff,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device roadrunner_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &roadrunner_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &roadrunner_flash_resource,
-};
-
-static void __init roadrunner_init(void)
-{
-	platform_device_register(&roadrunner_flash);
-
-	/*
-	 * Mark flash as writeable
-	 */
-	IXP23XX_EXP_CS0[0] |= IXP23XX_FLASH_WRITABLE;
-	IXP23XX_EXP_CS0[1] |= IXP23XX_FLASH_WRITABLE;
-	IXP23XX_EXP_CS0[2] |= IXP23XX_FLASH_WRITABLE;
-	IXP23XX_EXP_CS0[3] |= IXP23XX_FLASH_WRITABLE;
-
-	ixp23xx_sys_init();
-}
-
-MACHINE_START(ROADRUNNER, "ADI Engineering RoadRunner Development Platform")
-	/* Maintainer: Deepak Saxena */
-	.map_io		= ixp23xx_map_io,
-	.init_irq	= ixp23xx_init_irq,
-	.timer		= &ixp23xx_timer,
-	.atag_offset	= 0x100,
-	.init_machine	= roadrunner_init,
-	.restart	= ixp23xx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig
index 90ceab7..199764f 100644
--- a/arch/arm/mach-kirkwood/Kconfig
+++ b/arch/arm/mach-kirkwood/Kconfig
@@ -58,6 +58,28 @@
 	  Say 'Y' here if you want your kernel to support the
 	  Marvell DreamPlug (Flattened Device Tree).
 
+config MACH_ICONNECT_DT
+	bool "Iomega Iconnect (Flattened Device Tree)"
+	select ARCH_KIRKWOOD_DT
+	help
+	  Say 'Y' here to enable Iomega Iconnect support.
+
+config MACH_DLINK_KIRKWOOD_DT
+	bool "D-Link Kirkwood-based NAS (Flattened Device Tree)"
+	select ARCH_KIRKWOOD_DT
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Kirkwood-based D-Link NASes such as DNS-320 & DNS-325,
+	  using Flattened Device Tree.
+
+config MACH_IB62X0_DT
+	bool "RaidSonic IB-NAS6210, IB-NAS6220 (Flattened Device Tree)"
+	select ARCH_KIRKWOOD_DT
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  RaidSonic IB-NAS6210 & IB-NAS6220 devices, using
+	  Flattened Device Tree.
+
 config MACH_TS219
 	bool "QNAP TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and TS-219P+ Turbo NAS"
 	help
diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile
index e299a95..d2b0590 100644
--- a/arch/arm/mach-kirkwood/Makefile
+++ b/arch/arm/mach-kirkwood/Makefile
@@ -22,3 +22,6 @@
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_ARCH_KIRKWOOD_DT)		+= board-dt.o
 obj-$(CONFIG_MACH_DREAMPLUG_DT)		+= board-dreamplug.o
+obj-$(CONFIG_MACH_ICONNECT_DT)		+= board-iconnect.o
+obj-$(CONFIG_MACH_DLINK_KIRKWOOD_DT)	+= board-dnskw.o
+obj-$(CONFIG_MACH_IB62X0_DT)		+= board-ib62x0.o
diff --git a/arch/arm/mach-kirkwood/Makefile.boot b/arch/arm/mach-kirkwood/Makefile.boot
index 16f9385..02edbdf 100644
--- a/arch/arm/mach-kirkwood/Makefile.boot
+++ b/arch/arm/mach-kirkwood/Makefile.boot
@@ -3,3 +3,7 @@
 initrd_phys-y	:= 0x00800000
 
 dtb-$(CONFIG_MACH_DREAMPLUG_DT) += kirkwood-dreamplug.dtb
+dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns320.dtb
+dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns325.dtb
+dtb-$(CONFIG_MACH_ICONNECT_DT) += kirkwood-iconnect.dtb
+dtb-$(CONFIG_MACH_IB62X0_DT) += kirkwood-ib62x0.dtb
diff --git a/arch/arm/mach-kirkwood/board-dnskw.c b/arch/arm/mach-kirkwood/board-dnskw.c
new file mode 100644
index 0000000..58c2d68
--- /dev/null
+++ b/arch/arm/mach-kirkwood/board-dnskw.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2012 (C), Jamie Lentin <jm@lentin.co.uk>
+ *
+ * arch/arm/mach-kirkwood/board-dnskw.c
+ *
+ * D-link DNS-320 & DNS-325 NAS Init for drivers not converted to
+ * flattened device tree yet.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio-fan.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/kirkwood.h>
+#include <mach/bridge-regs.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mv643xx_eth_platform_data dnskw_ge00_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
+};
+
+static struct mv_sata_platform_data dnskw_sata_data = {
+	.n_ports	= 2,
+};
+
+static unsigned int dnskw_mpp_config[] __initdata = {
+	MPP13_UART1_TXD,	/* Custom ... */
+	MPP14_UART1_RXD,	/* ... Controller (DNS-320 only) */
+	MPP20_SATA1_ACTn,	/* LED: White Right HDD */
+	MPP21_SATA0_ACTn,	/* LED: White Left HDD */
+	MPP24_GPIO,
+	MPP25_GPIO,
+	MPP26_GPIO,	/* LED: Power */
+	MPP27_GPIO,	/* LED: Red Right HDD */
+	MPP28_GPIO,	/* LED: Red Left HDD */
+	MPP29_GPIO,	/* LED: Red USB (DNS-325 only) */
+	MPP30_GPIO,
+	MPP31_GPIO,
+	MPP32_GPIO,
+	MPP33_GPO,
+	MPP34_GPIO,	/* Button: Front power */
+	MPP35_GPIO,	/* LED: Red USB (DNS-320 only) */
+	MPP36_GPIO,	/* Power: Turn off board */
+	MPP37_GPIO,	/* Power: Turn back on after power failure */
+	MPP38_GPIO,
+	MPP39_GPIO,	/* Power: SATA0 */
+	MPP40_GPIO,	/* Power: SATA1 */
+	MPP41_GPIO,	/* SATA0 present */
+	MPP42_GPIO,	/* SATA1 present */
+	MPP43_GPIO,	/* LED: White USB */
+	MPP44_GPIO,	/* Fan: Tachometer Pin */
+	MPP45_GPIO,	/* Fan: high speed */
+	MPP46_GPIO,	/* Fan: low speed */
+	MPP47_GPIO,	/* Button: Back unmount */
+	MPP48_GPIO,	/* Button: Back reset */
+	MPP49_GPIO,	/* Temp Alarm (DNS-325) Pin of U5 (DNS-320) */
+	0
+};
+
+static struct gpio_led dns325_led_pins[] = {
+	{
+		.name	= "dns325:white:power",
+		.gpio	= 26,
+		.active_low = 1,
+		.default_trigger = "default-on",
+	},
+	{
+		.name	= "dns325:white:usb",
+		.gpio	= 43,
+		.active_low = 1,
+	},
+	{
+		.name	= "dns325:red:l_hdd",
+		.gpio	= 28,
+		.active_low = 1,
+	},
+	{
+		.name	= "dns325:red:r_hdd",
+		.gpio	= 27,
+		.active_low = 1,
+	},
+	{
+		.name	= "dns325:red:usb",
+		.gpio	= 29,
+		.active_low = 1,
+	},
+};
+
+static struct gpio_led_platform_data dns325_led_data = {
+	.num_leds	= ARRAY_SIZE(dns325_led_pins),
+	.leds		= dns325_led_pins,
+};
+
+static struct platform_device dns325_led_device = {
+	.name		= "leds-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &dns325_led_data,
+	},
+};
+
+static struct gpio_led dns320_led_pins[] = {
+	{
+		.name	= "dns320:blue:power",
+		.gpio	= 26,
+		.active_low = 1,
+		.default_trigger = "default-on",
+	},
+	{
+		.name	= "dns320:blue:usb",
+		.gpio	= 43,
+		.active_low = 1,
+	},
+	{
+		.name	= "dns320:orange:l_hdd",
+		.gpio	= 28,
+		.active_low = 1,
+	},
+	{
+		.name	= "dns320:orange:r_hdd",
+		.gpio	= 27,
+		.active_low = 1,
+	},
+	{
+		.name	= "dns320:orange:usb",
+		.gpio	= 35,
+		.active_low = 1,
+	},
+};
+
+static struct gpio_led_platform_data dns320_led_data = {
+	.num_leds	= ARRAY_SIZE(dns320_led_pins),
+	.leds		= dns320_led_pins,
+};
+
+static struct platform_device dns320_led_device = {
+	.name		= "leds-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &dns320_led_data,
+	},
+};
+
+static struct i2c_board_info dns325_i2c_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("lm75", 0x48),
+	},
+	/* Something at 0x0c also */
+};
+
+static struct gpio_keys_button dnskw_button_pins[] = {
+	{
+		.code		= KEY_POWER,
+		.gpio		= 34,
+		.desc		= "Power button",
+		.active_low	= 1,
+	},
+	{
+		.code		= KEY_EJECTCD,
+		.gpio		= 47,
+		.desc		= "USB unmount button",
+		.active_low	= 1,
+	},
+	{
+		.code		= KEY_RESTART,
+		.gpio		= 48,
+		.desc		= "Reset button",
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_platform_data dnskw_button_data = {
+	.buttons	= dnskw_button_pins,
+	.nbuttons	= ARRAY_SIZE(dnskw_button_pins),
+};
+
+static struct platform_device dnskw_button_device = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.num_resources	= 0,
+	.dev		= {
+		.platform_data	= &dnskw_button_data,
+	}
+};
+
+/* Fan: ADDA AD045HB-G73 40mm 6000rpm@5v */
+static struct gpio_fan_speed dnskw_fan_speed[] = {
+	{    0,  0 },
+	{ 3000,	 1 },
+	{ 6000,	 2 },
+};
+static unsigned dnskw_fan_pins[] = {46, 45};
+
+static struct gpio_fan_platform_data dnskw_fan_data = {
+	.num_ctrl	= ARRAY_SIZE(dnskw_fan_pins),
+	.ctrl		= dnskw_fan_pins,
+	.num_speed	= ARRAY_SIZE(dnskw_fan_speed),
+	.speed		= dnskw_fan_speed,
+};
+
+static struct platform_device dnskw_fan_device = {
+	.name	= "gpio-fan",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &dnskw_fan_data,
+	},
+};
+
+static void dnskw_power_off(void)
+{
+	gpio_set_value(36, 1);
+}
+
+/* Register any GPIO for output and set the value */
+static void __init dnskw_gpio_register(unsigned gpio, char *name, int def)
+{
+	if (gpio_request(gpio, name) == 0 &&
+	    gpio_direction_output(gpio, 0) == 0) {
+		gpio_set_value(gpio, def);
+		if (gpio_export(gpio, 0) != 0)
+			pr_err("dnskw: Failed to export GPIO %s\n", name);
+	} else
+		pr_err("dnskw: Failed to register %s\n", name);
+}
+
+void __init dnskw_init(void)
+{
+	kirkwood_mpp_conf(dnskw_mpp_config);
+
+	kirkwood_ehci_init();
+	kirkwood_ge00_init(&dnskw_ge00_data);
+	kirkwood_sata_init(&dnskw_sata_data);
+	kirkwood_i2c_init();
+
+	platform_device_register(&dnskw_button_device);
+	platform_device_register(&dnskw_fan_device);
+
+	if (of_machine_is_compatible("dlink,dns-325")) {
+		i2c_register_board_info(0, dns325_i2c_board_info,
+					ARRAY_SIZE(dns325_i2c_board_info));
+		platform_device_register(&dns325_led_device);
+
+	} else if (of_machine_is_compatible("dlink,dns-320"))
+		platform_device_register(&dns320_led_device);
+
+	/* Register power-off GPIO. */
+	if (gpio_request(36, "dnskw:power:off") == 0
+	    && gpio_direction_output(36, 0) == 0)
+		pm_power_off = dnskw_power_off;
+	else
+		pr_err("dnskw: failed to configure power-off GPIO\n");
+
+	/* Ensure power is supplied to both HDDs */
+	dnskw_gpio_register(39, "dnskw:power:sata0", 1);
+	dnskw_gpio_register(40, "dnskw:power:sata1", 1);
+
+	/* Set NAS to turn back on after a power failure */
+	dnskw_gpio_register(37, "dnskw:power:recover", 1);
+}
diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c
index f7fe1b9..10d1969 100644
--- a/arch/arm/mach-kirkwood/board-dt.c
+++ b/arch/arm/mach-kirkwood/board-dt.c
@@ -56,11 +56,24 @@
 	if (of_machine_is_compatible("globalscale,dreamplug"))
 		dreamplug_init();
 
+	if (of_machine_is_compatible("dlink,dns-kirkwood"))
+		dnskw_init();
+
+	if (of_machine_is_compatible("iom,iconnect"))
+		iconnect_init();
+
+	if (of_machine_is_compatible("raidsonic,ib-nas62x0"))
+		ib62x0_init();
+
 	of_platform_populate(NULL, kirkwood_dt_match_table, NULL, NULL);
 }
 
 static const char *kirkwood_dt_board_compat[] = {
 	"globalscale,dreamplug",
+	"dlink,dns-320",
+	"dlink,dns-325",
+	"iom,iconnect",
+	"raidsonic,ib-nas62x0",
 	NULL
 };
 
diff --git a/arch/arm/mach-kirkwood/board-ib62x0.c b/arch/arm/mach-kirkwood/board-ib62x0.c
new file mode 100644
index 0000000..eddf1df
--- /dev/null
+++ b/arch/arm/mach-kirkwood/board-ib62x0.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2012 (C), Simon Baatz <gmbnomis@gmail.com>
+ *
+ * arch/arm/mach-kirkwood/board-ib62x0.c
+ *
+ * RaidSonic ICY BOX IB-NAS6210 & IB-NAS6220 init for drivers not
+ * converted to flattened device tree yet.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include "common.h"
+#include "mpp.h"
+
+#define IB62X0_GPIO_POWER_OFF	24
+
+static struct mv643xx_eth_platform_data ib62x0_ge00_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
+};
+
+static struct mv_sata_platform_data ib62x0_sata_data = {
+	.n_ports	= 2,
+};
+
+static unsigned int ib62x0_mpp_config[] __initdata = {
+	MPP0_NF_IO2,
+	MPP1_NF_IO3,
+	MPP2_NF_IO4,
+	MPP3_NF_IO5,
+	MPP4_NF_IO6,
+	MPP5_NF_IO7,
+	MPP18_NF_IO0,
+	MPP19_NF_IO1,
+	MPP22_GPIO,	/* OS LED red */
+	MPP24_GPIO,	/* Power off device */
+	MPP25_GPIO,	/* OS LED green */
+	MPP27_GPIO,	/* USB transfer LED */
+	MPP28_GPIO,	/* Reset button */
+	MPP29_GPIO,	/* USB Copy button */
+	0
+};
+
+static struct gpio_led ib62x0_led_pins[] = {
+	{
+		.name			= "ib62x0:green:os",
+		.default_trigger	= "default-on",
+		.gpio			= 25,
+		.active_low		= 0,
+	},
+	{
+		.name			= "ib62x0:red:os",
+		.default_trigger	= "none",
+		.gpio			= 22,
+		.active_low		= 0,
+	},
+	{
+		.name			= "ib62x0:red:usb_copy",
+		.default_trigger	= "none",
+		.gpio			= 27,
+		.active_low		= 0,
+	},
+};
+
+static struct gpio_led_platform_data ib62x0_led_data = {
+	.leds		= ib62x0_led_pins,
+	.num_leds	= ARRAY_SIZE(ib62x0_led_pins),
+};
+
+static struct platform_device ib62x0_led_device = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &ib62x0_led_data,
+	}
+};
+
+static struct gpio_keys_button ib62x0_button_pins[] = {
+	{
+		.code		= KEY_COPY,
+		.gpio		= 29,
+		.desc		= "USB Copy",
+		.active_low	= 1,
+	},
+	{
+		.code		= KEY_RESTART,
+		.gpio		= 28,
+		.desc		= "Reset",
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_platform_data ib62x0_button_data = {
+	.buttons	= ib62x0_button_pins,
+	.nbuttons	= ARRAY_SIZE(ib62x0_button_pins),
+};
+
+static struct platform_device ib62x0_button_device = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.num_resources	= 0,
+	.dev		= {
+		.platform_data	= &ib62x0_button_data,
+	}
+};
+
+static void ib62x0_power_off(void)
+{
+	gpio_set_value(IB62X0_GPIO_POWER_OFF, 1);
+}
+
+void __init ib62x0_init(void)
+{
+	/*
+	 * Basic setup. Needs to be called early.
+	 */
+	kirkwood_mpp_conf(ib62x0_mpp_config);
+
+	kirkwood_ehci_init();
+	kirkwood_ge00_init(&ib62x0_ge00_data);
+	kirkwood_sata_init(&ib62x0_sata_data);
+	platform_device_register(&ib62x0_led_device);
+	platform_device_register(&ib62x0_button_device);
+	if (gpio_request(IB62X0_GPIO_POWER_OFF, "ib62x0:power:off") == 0 &&
+	    gpio_direction_output(IB62X0_GPIO_POWER_OFF, 0) == 0)
+		pm_power_off = ib62x0_power_off;
+	else
+		pr_err("board-ib62x0: failed to configure power-off GPIO\n");
+}
diff --git a/arch/arm/mach-kirkwood/board-iconnect.c b/arch/arm/mach-kirkwood/board-iconnect.c
new file mode 100644
index 0000000..2222c57
--- /dev/null
+++ b/arch/arm/mach-kirkwood/board-iconnect.c
@@ -0,0 +1,165 @@
+/*
+ * arch/arm/mach-kirkwood/board-iconnect.c
+ *
+ * Iomega i-connect Board Setup
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mv643xx_eth_platform_data iconnect_ge00_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(11),
+};
+
+static struct gpio_led iconnect_led_pins[] = {
+	{
+		.name		= "led_level",
+		.gpio		= 41,
+		.default_trigger = "default-on",
+	}, {
+		.name		= "power:blue",
+		.gpio		= 42,
+		.default_trigger = "timer",
+	}, {
+		.name		= "power:red",
+		.gpio		= 43,
+	}, {
+		.name		= "usb1:blue",
+		.gpio		= 44,
+	}, {
+		.name		= "usb2:blue",
+		.gpio		= 45,
+	}, {
+		.name		= "usb3:blue",
+		.gpio		= 46,
+	}, {
+		.name		= "usb4:blue",
+		.gpio		= 47,
+	}, {
+		.name		= "otb:blue",
+		.gpio		= 48,
+	},
+};
+
+static struct gpio_led_platform_data iconnect_led_data = {
+	.leds		= iconnect_led_pins,
+	.num_leds	= ARRAY_SIZE(iconnect_led_pins),
+	.gpio_blink_set	= orion_gpio_led_blink_set,
+};
+
+static struct platform_device iconnect_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &iconnect_led_data,
+	}
+};
+
+static unsigned int iconnect_mpp_config[] __initdata = {
+	MPP12_GPIO,
+	MPP35_GPIO,
+	MPP41_GPIO,
+	MPP42_GPIO,
+	MPP43_GPIO,
+	MPP44_GPIO,
+	MPP45_GPIO,
+	MPP46_GPIO,
+	MPP47_GPIO,
+	MPP48_GPIO,
+	0
+};
+
+static struct i2c_board_info __initdata iconnect_board_info[] = {
+	{
+		I2C_BOARD_INFO("lm63", 0x4c),
+	},
+};
+
+static struct mtd_partition iconnect_nand_parts[] = {
+	{
+		.name = "flash",
+		.offset = 0,
+		.size = MTDPART_SIZ_FULL,
+	},
+};
+
+/* yikes... theses are the original input buttons */
+/* but I'm not convinced by the sw event choices  */
+static struct gpio_keys_button iconnect_buttons[] = {
+	{
+		.type		= EV_SW,
+		.code		= SW_LID,
+		.gpio		= 12,
+		.desc		= "Reset Button",
+		.active_low	= 1,
+		.debounce_interval = 100,
+	}, {
+		.type		= EV_SW,
+		.code		= SW_TABLET_MODE,
+		.gpio		= 35,
+		.desc		= "OTB Button",
+		.active_low	= 1,
+		.debounce_interval = 100,
+	},
+};
+
+static struct gpio_keys_platform_data iconnect_button_data = {
+	.buttons	= iconnect_buttons,
+	.nbuttons	= ARRAY_SIZE(iconnect_buttons),
+};
+
+static struct platform_device iconnect_button_device = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.num_resources	= 0,
+	.dev        = {
+		.platform_data  = &iconnect_button_data,
+	},
+};
+
+void __init iconnect_init(void)
+{
+	kirkwood_mpp_conf(iconnect_mpp_config);
+	kirkwood_nand_init(ARRAY_AND_SIZE(iconnect_nand_parts), 25);
+	kirkwood_i2c_init();
+	i2c_register_board_info(0, iconnect_board_info,
+		ARRAY_SIZE(iconnect_board_info));
+
+	kirkwood_ehci_init();
+	kirkwood_ge00_init(&iconnect_ge00_data);
+
+	platform_device_register(&iconnect_button_device);
+	platform_device_register(&iconnect_leds);
+}
+
+static int __init iconnect_pci_init(void)
+{
+	if (of_machine_is_compatible("iom,iconnect"))
+		kirkwood_pcie_init(KW_PCIE0);
+	return 0;
+}
+subsys_initcall(iconnect_pci_init);
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index a02cae8..3ad0373 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -15,6 +15,7 @@
 #include <linux/ata_platform.h>
 #include <linux/mtd/nand.h>
 #include <linux/dma-mapping.h>
+#include <linux/of.h>
 #include <net/dsa.h>
 #include <asm/page.h>
 #include <asm/timex.h>
@@ -482,6 +483,9 @@
 	unsigned int curr = readl(CLOCK_GATING_CTRL);
 	u32 dev, rev;
 
+#ifdef CONFIG_OF
+	struct device_node *np;
+#endif
 	kirkwood_pcie_id(&dev, &rev);
 	printk(KERN_DEBUG "Gating clock of unused units\n");
 	printk(KERN_DEBUG "before: 0x%08x\n", curr);
@@ -489,6 +493,14 @@
 	/* Make sure those units are accessible */
 	writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0 | CGC_PEX1, CLOCK_GATING_CTRL);
 
+#ifdef CONFIG_OF
+	np = of_find_compatible_node(NULL, NULL, "mrvl,orion-nand");
+	if (np && of_device_is_available(np)) {
+		kirkwood_clk_ctrl |= CGC_RUNIT;
+		of_node_put(np);
+	}
+#endif
+
 	/* For SATA: first shutdown the phy */
 	if (!(kirkwood_clk_ctrl & CGC_SATA0)) {
 		/* Disable PLL and IVREF */
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index fa8e768..a34c41a 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -58,6 +58,24 @@
 static inline void dreamplug_init(void) {};
 #endif
 
+#ifdef CONFIG_MACH_DLINK_KIRKWOOD_DT
+void dnskw_init(void);
+#else
+static inline void dnskw_init(void) {};
+#endif
+
+#ifdef CONFIG_MACH_ICONNECT_DT
+void iconnect_init(void);
+#else
+static inline void iconnect_init(void) {};
+#endif
+
+#ifdef CONFIG_MACH_IB62X0_DT
+void ib62x0_init(void);
+#else
+static inline void ib62x0_init(void) {};
+#endif
+
 /* early init functions not converted to fdt yet */
 char *kirkwood_id(void);
 void kirkwood_l2_init(void);
diff --git a/arch/arm/mach-lpc32xx/Kconfig b/arch/arm/mach-lpc32xx/Kconfig
index 75946ac..e0b3eee 100644
--- a/arch/arm/mach-lpc32xx/Kconfig
+++ b/arch/arm/mach-lpc32xx/Kconfig
@@ -29,30 +29,4 @@
 
 endmenu
 
-menu "LPC32XX chip components"
-
-config ARCH_LPC32XX_IRAM_FOR_NET
-	bool "Use IRAM for network buffers"
-	default y
-	help
-	  Say Y here to use the LPC internal fast IRAM (i.e. 256KB SRAM) as
-	  network buffer.  If the total combined required buffer sizes is
-	  larger than the size of IRAM, then SDRAM will be used instead.
-
-	  This can be enabled safely if the IRAM is not intended for other
-	  uses.
-
-config ARCH_LPC32XX_MII_SUPPORT
-	bool "Check to enable MII support or leave disabled for RMII support"
-	help
-	  Say Y here to enable MII support, or N for RMII support. Regardless of
-	  which support is selected, the ethernet interface driver needs to be
-	  selected in the device driver networking section.
-
-	  The PHY3250 reference board uses RMII, so users of this board should
-	  say N.
-
-endmenu
-
 endif
-
diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c
index 2fc24ca..f6a3ffe 100644
--- a/arch/arm/mach-lpc32xx/clock.c
+++ b/arch/arm/mach-lpc32xx/clock.c
@@ -1095,49 +1095,42 @@
 }
 EXPORT_SYMBOL(clk_get_parent);
 
-#define _REGISTER_CLOCK(d, n, c) \
-	{ \
-		.dev_id = (d), \
-		.con_id = (n), \
-		.clk = &(c), \
-	},
-
 static struct clk_lookup lookups[] = {
-	_REGISTER_CLOCK(NULL, "osc_32KHz", osc_32KHz)
-	_REGISTER_CLOCK(NULL, "osc_pll397", osc_pll397)
-	_REGISTER_CLOCK(NULL, "osc_main", osc_main)
-	_REGISTER_CLOCK(NULL, "sys_ck", clk_sys)
-	_REGISTER_CLOCK(NULL, "arm_pll_ck", clk_armpll)
-	_REGISTER_CLOCK(NULL, "ck_pll5", clk_usbpll)
-	_REGISTER_CLOCK(NULL, "hclk_ck", clk_hclk)
-	_REGISTER_CLOCK(NULL, "pclk_ck", clk_pclk)
-	_REGISTER_CLOCK(NULL, "timer0_ck", clk_timer0)
-	_REGISTER_CLOCK(NULL, "timer1_ck", clk_timer1)
-	_REGISTER_CLOCK(NULL, "timer2_ck", clk_timer2)
-	_REGISTER_CLOCK(NULL, "timer3_ck", clk_timer3)
-	_REGISTER_CLOCK(NULL, "vfp9_ck", clk_vfp9)
-	_REGISTER_CLOCK(NULL, "clk_dmac", clk_dma)
-	_REGISTER_CLOCK("pnx4008-watchdog", NULL, clk_wdt)
-	_REGISTER_CLOCK(NULL, "uart3_ck", clk_uart3)
-	_REGISTER_CLOCK(NULL, "uart4_ck", clk_uart4)
-	_REGISTER_CLOCK(NULL, "uart5_ck", clk_uart5)
-	_REGISTER_CLOCK(NULL, "uart6_ck", clk_uart6)
-	_REGISTER_CLOCK("pnx-i2c.0", NULL, clk_i2c0)
-	_REGISTER_CLOCK("pnx-i2c.1", NULL, clk_i2c1)
-	_REGISTER_CLOCK("pnx-i2c.2", NULL, clk_i2c2)
-	_REGISTER_CLOCK("dev:ssp0", NULL, clk_ssp0)
-	_REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1)
-	_REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan)
-	_REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand)
-	_REGISTER_CLOCK("lpc32xx-adc", NULL, clk_adc)
-	_REGISTER_CLOCK(NULL, "i2s0_ck", clk_i2s0)
-	_REGISTER_CLOCK(NULL, "i2s1_ck", clk_i2s1)
-	_REGISTER_CLOCK("ts-lpc32xx", NULL, clk_tsc)
-	_REGISTER_CLOCK("dev:mmc0", NULL, clk_mmc)
-	_REGISTER_CLOCK("lpc-eth.0", NULL, clk_net)
-	_REGISTER_CLOCK("dev:clcd", NULL, clk_lcd)
-	_REGISTER_CLOCK("lpc32xx_udc", "ck_usbd", clk_usbd)
-	_REGISTER_CLOCK("lpc32xx_rtc", NULL, clk_rtc)
+	CLKDEV_INIT(NULL, "osc_32KHz", &osc_32KHz),
+	CLKDEV_INIT(NULL, "osc_pll397", &osc_pll397),
+	CLKDEV_INIT(NULL, "osc_main", &osc_main),
+	CLKDEV_INIT(NULL, "sys_ck", &clk_sys),
+	CLKDEV_INIT(NULL, "arm_pll_ck", &clk_armpll),
+	CLKDEV_INIT(NULL, "ck_pll5", &clk_usbpll),
+	CLKDEV_INIT(NULL, "hclk_ck", &clk_hclk),
+	CLKDEV_INIT(NULL, "pclk_ck", &clk_pclk),
+	CLKDEV_INIT(NULL, "timer0_ck", &clk_timer0),
+	CLKDEV_INIT(NULL, "timer1_ck", &clk_timer1),
+	CLKDEV_INIT(NULL, "timer2_ck", &clk_timer2),
+	CLKDEV_INIT(NULL, "timer3_ck", &clk_timer3),
+	CLKDEV_INIT(NULL, "vfp9_ck", &clk_vfp9),
+	CLKDEV_INIT("pl08xdmac", NULL, &clk_dma),
+	CLKDEV_INIT("4003c000.watchdog", NULL, &clk_wdt),
+	CLKDEV_INIT(NULL, "uart3_ck", &clk_uart3),
+	CLKDEV_INIT(NULL, "uart4_ck", &clk_uart4),
+	CLKDEV_INIT(NULL, "uart5_ck", &clk_uart5),
+	CLKDEV_INIT(NULL, "uart6_ck", &clk_uart6),
+	CLKDEV_INIT("400a0000.i2c", NULL, &clk_i2c0),
+	CLKDEV_INIT("400a8000.i2c", NULL, &clk_i2c1),
+	CLKDEV_INIT("31020300.i2c", NULL, &clk_i2c2),
+	CLKDEV_INIT("dev:ssp0", NULL, &clk_ssp0),
+	CLKDEV_INIT("dev:ssp1", NULL, &clk_ssp1),
+	CLKDEV_INIT("lpc32xx_keys.0", NULL, &clk_kscan),
+	CLKDEV_INIT("lpc32xx-nand.0", "nand_ck", &clk_nand),
+	CLKDEV_INIT("40048000.adc", NULL, &clk_adc),
+	CLKDEV_INIT(NULL, "i2s0_ck", &clk_i2s0),
+	CLKDEV_INIT(NULL, "i2s1_ck", &clk_i2s1),
+	CLKDEV_INIT("40048000.tsc", NULL, &clk_tsc),
+	CLKDEV_INIT("20098000.sd", NULL, &clk_mmc),
+	CLKDEV_INIT("31060000.ethernet", NULL, &clk_net),
+	CLKDEV_INIT("dev:clcd", NULL, &clk_lcd),
+	CLKDEV_INIT("31020000.usbd", "ck_usbd", &clk_usbd),
+	CLKDEV_INIT("lpc32xx_rtc", NULL, &clk_rtc),
 };
 
 static int __init clk_init(void)
diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c
index bbbf063..5c96057 100644
--- a/arch/arm/mach-lpc32xx/common.c
+++ b/arch/arm/mach-lpc32xx/common.c
@@ -27,186 +27,11 @@
 
 #include <asm/mach/map.h>
 
-#include <mach/i2c.h>
 #include <mach/hardware.h>
 #include <mach/platform.h>
 #include "common.h"
 
 /*
- * Watchdog timer
- */
-static struct resource watchdog_resources[] = {
-	[0] = {
-		.start = LPC32XX_WDTIM_BASE,
-		.end = LPC32XX_WDTIM_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-struct platform_device lpc32xx_watchdog_device = {
-	.name = "pnx4008-watchdog",
-	.id = -1,
-	.num_resources = ARRAY_SIZE(watchdog_resources),
-	.resource = watchdog_resources,
-};
-
-/*
- * I2C busses
- */
-static struct i2c_pnx_data i2c0_data = {
-	.name = I2C_CHIP_NAME "1",
-	.base = LPC32XX_I2C1_BASE,
-	.irq = IRQ_LPC32XX_I2C_1,
-};
-
-static struct i2c_pnx_data i2c1_data = {
-	.name = I2C_CHIP_NAME "2",
-	.base = LPC32XX_I2C2_BASE,
-	.irq = IRQ_LPC32XX_I2C_2,
-};
-
-static struct i2c_pnx_data i2c2_data = {
-	.name = "USB-I2C",
-	.base = LPC32XX_OTG_I2C_BASE,
-	.irq = IRQ_LPC32XX_USB_I2C,
-};
-
-struct platform_device lpc32xx_i2c0_device = {
-	.name = "pnx-i2c",
-	.id = 0,
-	.dev = {
-		.platform_data = &i2c0_data,
-	},
-};
-
-struct platform_device lpc32xx_i2c1_device = {
-	.name = "pnx-i2c",
-	.id = 1,
-	.dev = {
-		.platform_data = &i2c1_data,
-	},
-};
-
-struct platform_device lpc32xx_i2c2_device = {
-	.name = "pnx-i2c",
-	.id = 2,
-	.dev = {
-		.platform_data = &i2c2_data,
-	},
-};
-
-/* TSC (Touch Screen Controller) */
-
-static struct resource lpc32xx_tsc_resources[] = {
-	{
-		.start = LPC32XX_ADC_BASE,
-		.end = LPC32XX_ADC_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = IRQ_LPC32XX_TS_IRQ,
-		.end = IRQ_LPC32XX_TS_IRQ,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device lpc32xx_tsc_device = {
-	.name =  "ts-lpc32xx",
-	.id = -1,
-	.num_resources = ARRAY_SIZE(lpc32xx_tsc_resources),
-	.resource = lpc32xx_tsc_resources,
-};
-
-/* RTC */
-
-static struct resource lpc32xx_rtc_resources[] = {
-	{
-		.start = LPC32XX_RTC_BASE,
-		.end = LPC32XX_RTC_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},{
-		.start = IRQ_LPC32XX_RTC,
-		.end = IRQ_LPC32XX_RTC,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device lpc32xx_rtc_device = {
-	.name =  "rtc-lpc32xx",
-	.id = -1,
-	.num_resources = ARRAY_SIZE(lpc32xx_rtc_resources),
-	.resource = lpc32xx_rtc_resources,
-};
-
-/*
- * ADC support
- */
-static struct resource adc_resources[] = {
-	{
-		.start = LPC32XX_ADC_BASE,
-		.end = LPC32XX_ADC_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = IRQ_LPC32XX_TS_IRQ,
-		.end = IRQ_LPC32XX_TS_IRQ,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device lpc32xx_adc_device = {
-	.name =  "lpc32xx-adc",
-	.id = -1,
-	.num_resources = ARRAY_SIZE(adc_resources),
-	.resource = adc_resources,
-};
-
-/*
- * USB support
- */
-/* The dmamask must be set for OHCI to work */
-static u64 ohci_dmamask = ~(u32) 0;
-static struct resource ohci_resources[] = {
-	{
-		.start = IO_ADDRESS(LPC32XX_USB_BASE),
-		.end = IO_ADDRESS(LPC32XX_USB_BASE + 0x100 - 1),
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = IRQ_LPC32XX_USB_HOST,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-struct platform_device lpc32xx_ohci_device = {
-	.name = "usb-ohci",
-	.id = -1,
-	.dev = {
-		.dma_mask = &ohci_dmamask,
-		.coherent_dma_mask = 0xFFFFFFFF,
-	},
-	.num_resources = ARRAY_SIZE(ohci_resources),
-	.resource = ohci_resources,
-};
-
-/*
- * Network Support
- */
-static struct resource net_resources[] = {
-	[0] = DEFINE_RES_MEM(LPC32XX_ETHERNET_BASE, SZ_4K),
-	[1] = DEFINE_RES_MEM(LPC32XX_IRAM_BASE, SZ_128K),
-	[2] = DEFINE_RES_IRQ(IRQ_LPC32XX_ETHERNET),
-};
-
-static u64 lpc32xx_mac_dma_mask = 0xffffffffUL;
-struct platform_device lpc32xx_net_device = {
-	.name = "lpc-eth",
-	.id = 0,
-	.dev = {
-		.dma_mask = &lpc32xx_mac_dma_mask,
-		.coherent_dma_mask = 0xffffffffUL,
-	},
-	.num_resources = ARRAY_SIZE(net_resources),
-	.resource = net_resources,
-};
-
-/*
  * Returns the unique ID for the device
  */
 void lpc32xx_get_uid(u32 devid[4])
@@ -398,3 +223,16 @@
 	while (1)
 		;
 }
+
+static int __init lpc32xx_display_uid(void)
+{
+	u32 uid[4];
+
+	lpc32xx_get_uid(uid);
+
+	printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n",
+		uid[3], uid[2], uid[1], uid[0]);
+
+	return 1;
+}
+arch_initcall(lpc32xx_display_uid);
diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h
index 68e45e8..afeac3b 100644
--- a/arch/arm/mach-lpc32xx/common.h
+++ b/arch/arm/mach-lpc32xx/common.h
@@ -23,26 +23,12 @@
 #include <linux/platform_device.h>
 
 /*
- * Arch specific platform device structures
- */
-extern struct platform_device lpc32xx_watchdog_device;
-extern struct platform_device lpc32xx_i2c0_device;
-extern struct platform_device lpc32xx_i2c1_device;
-extern struct platform_device lpc32xx_i2c2_device;
-extern struct platform_device lpc32xx_tsc_device;
-extern struct platform_device lpc32xx_adc_device;
-extern struct platform_device lpc32xx_rtc_device;
-extern struct platform_device lpc32xx_ohci_device;
-extern struct platform_device lpc32xx_net_device;
-
-/*
  * Other arch specific structures and functions
  */
 extern struct sys_timer lpc32xx_timer;
 extern void __init lpc32xx_init_irq(void);
 extern void __init lpc32xx_map_io(void);
 extern void __init lpc32xx_serial_init(void);
-extern void __init lpc32xx_gpio_init(void);
 extern void lpc23xx_restart(char, const char *);
 
 
diff --git a/arch/arm/mach-lpc32xx/include/mach/i2c.h b/arch/arm/mach-lpc32xx/include/mach/i2c.h
deleted file mode 100644
index 034dc92..0000000
--- a/arch/arm/mach-lpc32xx/include/mach/i2c.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * PNX4008-specific tweaks for I2C IP3204 block
- *
- * Author: Vitaly Wool <vwool@ru.mvista.com>
- *
- * 2005 (c) MontaVista Software, 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 __ASM_ARCH_I2C_H
-#define __ASM_ARCH_I2C_H
-
-enum {
-	mstatus_tdi = 0x00000001,
-	mstatus_afi = 0x00000002,
-	mstatus_nai = 0x00000004,
-	mstatus_drmi = 0x00000008,
-	mstatus_active = 0x00000020,
-	mstatus_scl = 0x00000040,
-	mstatus_sda = 0x00000080,
-	mstatus_rff = 0x00000100,
-	mstatus_rfe = 0x00000200,
-	mstatus_tff = 0x00000400,
-	mstatus_tfe = 0x00000800,
-};
-
-enum {
-	mcntrl_tdie = 0x00000001,
-	mcntrl_afie = 0x00000002,
-	mcntrl_naie = 0x00000004,
-	mcntrl_drmie = 0x00000008,
-	mcntrl_daie = 0x00000020,
-	mcntrl_rffie = 0x00000040,
-	mcntrl_tffie = 0x00000080,
-	mcntrl_reset = 0x00000100,
-	mcntrl_cdbmode = 0x00000400,
-};
-
-enum {
-	rw_bit = 1 << 0,
-	start_bit = 1 << 8,
-	stop_bit = 1 << 9,
-};
-
-#define I2C_REG_RX(a)	((a)->ioaddr)		/* Rx FIFO reg (RO) */
-#define I2C_REG_TX(a)	((a)->ioaddr)		/* Tx FIFO reg (WO) */
-#define I2C_REG_STS(a)	((a)->ioaddr + 0x04)	/* Status reg (RO) */
-#define I2C_REG_CTL(a)	((a)->ioaddr + 0x08)	/* Ctl reg */
-#define I2C_REG_CKL(a)	((a)->ioaddr + 0x0c)	/* Clock divider low */
-#define I2C_REG_CKH(a)	((a)->ioaddr + 0x10)	/* Clock divider high */
-#define I2C_REG_ADR(a)	((a)->ioaddr + 0x14)	/* I2C address */
-#define I2C_REG_RFL(a)	((a)->ioaddr + 0x18)	/* Rx FIFO level (RO) */
-#define I2C_REG_TFL(a)	((a)->ioaddr + 0x1c)	/* Tx FIFO level (RO) */
-#define I2C_REG_RXB(a)	((a)->ioaddr + 0x20)	/* Num of bytes Rx-ed (RO) */
-#define I2C_REG_TXB(a)	((a)->ioaddr + 0x24)	/* Num of bytes Tx-ed (RO) */
-#define I2C_REG_TXS(a)	((a)->ioaddr + 0x28)	/* Tx slave FIFO (RO) */
-#define I2C_REG_STFL(a)	((a)->ioaddr + 0x2c)	/* Tx slave FIFO level (RO) */
-
-#define I2C_CHIP_NAME		"PNX4008-I2C"
-
-#endif				/* __ASM_ARCH_I2C_H */
diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c
index d080cb1..5b1cc35 100644
--- a/arch/arm/mach-lpc32xx/irq.c
+++ b/arch/arm/mach-lpc32xx/irq.c
@@ -22,6 +22,11 @@
 #include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
 
 #include <mach/irqs.h>
 #include <mach/hardware.h>
@@ -44,6 +49,9 @@
 #define SIC1_ATR_DEFAULT	0x00026000
 #define SIC2_ATR_DEFAULT	0x00000000
 
+static struct irq_domain *lpc32xx_mic_domain;
+static struct device_node *lpc32xx_mic_np;
+
 struct lpc32xx_event_group_regs {
 	void __iomem *enab_reg;
 	void __iomem *edge_reg;
@@ -203,7 +211,7 @@
 {
 	unsigned int reg, ctrl, mask;
 
-	get_controller(d->irq, &ctrl, &mask);
+	get_controller(d->hwirq, &ctrl, &mask);
 
 	reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) & ~mask;
 	__raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
@@ -213,7 +221,7 @@
 {
 	unsigned int reg, ctrl, mask;
 
-	get_controller(d->irq, &ctrl, &mask);
+	get_controller(d->hwirq, &ctrl, &mask);
 
 	reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) | mask;
 	__raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
@@ -223,14 +231,14 @@
 {
 	unsigned int ctrl, mask;
 
-	get_controller(d->irq, &ctrl, &mask);
+	get_controller(d->hwirq, &ctrl, &mask);
 
 	__raw_writel(mask, LPC32XX_INTC_RAW_STAT(ctrl));
 
 	/* Also need to clear pending wake event */
-	if (lpc32xx_events[d->irq].mask != 0)
-		__raw_writel(lpc32xx_events[d->irq].mask,
-			lpc32xx_events[d->irq].event_group->rawstat_reg);
+	if (lpc32xx_events[d->hwirq].mask != 0)
+		__raw_writel(lpc32xx_events[d->hwirq].mask,
+			lpc32xx_events[d->hwirq].event_group->rawstat_reg);
 }
 
 static void __lpc32xx_set_irq_type(unsigned int irq, int use_high_level,
@@ -274,22 +282,22 @@
 	switch (type) {
 	case IRQ_TYPE_EDGE_RISING:
 		/* Rising edge sensitive */
-		__lpc32xx_set_irq_type(d->irq, 1, 1);
+		__lpc32xx_set_irq_type(d->hwirq, 1, 1);
 		break;
 
 	case IRQ_TYPE_EDGE_FALLING:
 		/* Falling edge sensitive */
-		__lpc32xx_set_irq_type(d->irq, 0, 1);
+		__lpc32xx_set_irq_type(d->hwirq, 0, 1);
 		break;
 
 	case IRQ_TYPE_LEVEL_LOW:
 		/* Low level sensitive */
-		__lpc32xx_set_irq_type(d->irq, 0, 0);
+		__lpc32xx_set_irq_type(d->hwirq, 0, 0);
 		break;
 
 	case IRQ_TYPE_LEVEL_HIGH:
 		/* High level sensitive */
-		__lpc32xx_set_irq_type(d->irq, 1, 0);
+		__lpc32xx_set_irq_type(d->hwirq, 1, 0);
 		break;
 
 	/* Other modes are not supported */
@@ -298,7 +306,7 @@
 	}
 
 	/* Ok to use the level handler for all types */
-	irq_set_handler(d->irq, handle_level_irq);
+	irq_set_handler(d->hwirq, handle_level_irq);
 
 	return 0;
 }
@@ -307,33 +315,33 @@
 {
 	unsigned long eventreg;
 
-	if (lpc32xx_events[d->irq].mask != 0) {
-		eventreg = __raw_readl(lpc32xx_events[d->irq].
+	if (lpc32xx_events[d->hwirq].mask != 0) {
+		eventreg = __raw_readl(lpc32xx_events[d->hwirq].
 			event_group->enab_reg);
 
 		if (state)
-			eventreg |= lpc32xx_events[d->irq].mask;
+			eventreg |= lpc32xx_events[d->hwirq].mask;
 		else {
-			eventreg &= ~lpc32xx_events[d->irq].mask;
+			eventreg &= ~lpc32xx_events[d->hwirq].mask;
 
 			/*
 			 * When disabling the wakeup, clear the latched
 			 * event
 			 */
-			__raw_writel(lpc32xx_events[d->irq].mask,
-				lpc32xx_events[d->irq].
+			__raw_writel(lpc32xx_events[d->hwirq].mask,
+				lpc32xx_events[d->hwirq].
 				event_group->rawstat_reg);
 		}
 
 		__raw_writel(eventreg,
-			lpc32xx_events[d->irq].event_group->enab_reg);
+			lpc32xx_events[d->hwirq].event_group->enab_reg);
 
 		return 0;
 	}
 
 	/* Clear event */
-	__raw_writel(lpc32xx_events[d->irq].mask,
-		lpc32xx_events[d->irq].event_group->rawstat_reg);
+	__raw_writel(lpc32xx_events[d->hwirq].mask,
+		lpc32xx_events[d->hwirq].event_group->rawstat_reg);
 
 	return -ENODEV;
 }
@@ -353,6 +361,7 @@
 }
 
 static struct irq_chip lpc32xx_irq_chip = {
+	.name = "MIC",
 	.irq_ack = lpc32xx_ack_irq,
 	.irq_mask = lpc32xx_mask_irq,
 	.irq_unmask = lpc32xx_unmask_irq,
@@ -386,9 +395,23 @@
 	}
 }
 
+static int __init __lpc32xx_mic_of_init(struct device_node *node,
+					struct device_node *parent)
+{
+	lpc32xx_mic_np = node;
+
+	return 0;
+}
+
+static const struct of_device_id mic_of_match[] __initconst = {
+	{ .compatible = "nxp,lpc3220-mic", .data = __lpc32xx_mic_of_init },
+	{ }
+};
+
 void __init lpc32xx_init_irq(void)
 {
 	unsigned int i;
+	int irq_base;
 
 	/* Setup MIC */
 	__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_MIC_BASE));
@@ -448,4 +471,19 @@
 		LPC32XX_CLKPWR_PIN_RS);
 	__raw_writel(__raw_readl(LPC32XX_CLKPWR_INT_RS),
 		LPC32XX_CLKPWR_INT_RS);
+
+	of_irq_init(mic_of_match);
+
+	irq_base = irq_alloc_descs(-1, 0, NR_IRQS, 0);
+	if (irq_base < 0) {
+		pr_warn("Cannot allocate irq_descs, assuming pre-allocated\n");
+		irq_base = 0;
+	}
+
+	lpc32xx_mic_domain = irq_domain_add_legacy(lpc32xx_mic_np, NR_IRQS,
+						   irq_base, 0,
+						   &irq_domain_simple_ops,
+						   NULL);
+	if (!lpc32xx_mic_domain)
+		panic("Unable to add MIC irq domain\n");
 }
diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c
index 7f7401e..540106c 100644
--- a/arch/arm/mach-lpc32xx/phy3250.c
+++ b/arch/arm/mach-lpc32xx/phy3250.c
@@ -1,8 +1,9 @@
 /*
- * arch/arm/mach-lpc32xx/phy3250.c
+ * Platform support for LPC32xx SoC
  *
  * Author: Kevin Wells <kevin.wells@nxp.com>
  *
+ * Copyright (C) 2012 Roland Stigge <stigge@antcom.de>
  * Copyright (C) 2010 NXP Semiconductors
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,11 +26,16 @@
 #include <linux/device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/eeprom.h>
-#include <linux/leds.h>
 #include <linux/gpio.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
 #include <linux/amba/pl022.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/amba/pl08x.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -47,7 +53,6 @@
 #define SPI0_CS_GPIO	LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5)
 #define LCD_POWER_GPIO	LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 0)
 #define BKL_POWER_GPIO	LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 4)
-#define LED_GPIO	LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 1)
 
 /*
  * AMBA LCD controller
@@ -150,9 +155,6 @@
 	.remove		= lpc32xx_clcd_remove,
 };
 
-static AMBA_AHB_DEVICE(lpc32xx_clcd, "dev:clcd", 0,
-	LPC32XX_LCD_BASE, { IRQ_LPC32XX_LCD }, &lpc32xx_clcd_data);
-
 /*
  * AMBA SSP (SPI)
  */
@@ -180,8 +182,11 @@
 	.enable_dma		= 0,
 };
 
-static AMBA_APB_DEVICE(lpc32xx_ssp0, "dev:ssp0", 0,
-	LPC32XX_SSP0_BASE, { IRQ_LPC32XX_SSP0 }, &lpc32xx_ssp0_data);
+static struct pl022_ssp_controller lpc32xx_ssp1_data = {
+	.bus_id			= 1,
+	.num_chipselect		= 1,
+	.enable_dma		= 0,
+};
 
 /* AT25 driver registration */
 static int __init phy3250_spi_board_register(void)
@@ -221,73 +226,20 @@
 }
 arch_initcall(phy3250_spi_board_register);
 
-static struct i2c_board_info __initdata phy3250_i2c_board_info[] = {
-	{
-		I2C_BOARD_INFO("pcf8563", 0x51),
-	},
+static struct pl08x_platform_data pl08x_pd = {
 };
 
-static struct gpio_led phy_leds[] = {
-	{
-		.name			= "led0",
-		.gpio			= LED_GPIO,
-		.active_low		= 1,
-		.default_trigger	= "heartbeat",
-	},
+static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = {
+	OF_DEV_AUXDATA("arm,pl022", 0x20084000, "dev:ssp0", &lpc32xx_ssp0_data),
+	OF_DEV_AUXDATA("arm,pl022", 0x2008C000, "dev:ssp1", &lpc32xx_ssp1_data),
+	OF_DEV_AUXDATA("arm,pl110", 0x31040000, "dev:clcd", &lpc32xx_clcd_data),
+	OF_DEV_AUXDATA("arm,pl080", 0x31000000, "pl08xdmac", &pl08x_pd),
+	{ }
 };
 
-static struct gpio_led_platform_data led_data = {
-	.leds = phy_leds,
-	.num_leds = ARRAY_SIZE(phy_leds),
-};
-
-static struct platform_device lpc32xx_gpio_led_device = {
-	.name			= "leds-gpio",
-	.id			= -1,
-	.dev.platform_data	= &led_data,
-};
-
-static struct platform_device *phy3250_devs[] __initdata = {
-	&lpc32xx_rtc_device,
-	&lpc32xx_tsc_device,
-	&lpc32xx_i2c0_device,
-	&lpc32xx_i2c1_device,
-	&lpc32xx_i2c2_device,
-	&lpc32xx_watchdog_device,
-	&lpc32xx_gpio_led_device,
-	&lpc32xx_adc_device,
-	&lpc32xx_ohci_device,
-	&lpc32xx_net_device,
-};
-
-static struct amba_device *amba_devs[] __initdata = {
-	&lpc32xx_clcd_device,
-	&lpc32xx_ssp0_device,
-};
-
-/*
- * Board specific functions
- */
-static void __init phy3250_board_init(void)
+static void __init lpc3250_machine_init(void)
 {
 	u32 tmp;
-	int i;
-
-	lpc32xx_gpio_init();
-
-	/* Register GPIOs used on this board */
-	if (gpio_request(SPI0_CS_GPIO, "spi0 cs"))
-		printk(KERN_ERR "Error requesting gpio %u",
-			SPI0_CS_GPIO);
-	else if (gpio_direction_output(SPI0_CS_GPIO, 1))
-		printk(KERN_ERR "Error setting gpio %u to output",
-			SPI0_CS_GPIO);
-
-	/* Setup network interface for RMII mode */
-	tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL);
-	tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK;
-	tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS;
-	__raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL);
 
 	/* Setup SLC NAND controller muxing */
 	__raw_writel(LPC32XX_CLKPWR_NANDCLK_SEL_SLC,
@@ -300,6 +252,12 @@
 	tmp |= LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16;
 	__raw_writel(tmp, LPC32XX_CLKPWR_LCDCLK_CTRL);
 
+	/* Set up USB power */
+	tmp = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+	tmp |= LPC32XX_CLKPWR_USBCTRL_HCLK_EN |
+		LPC32XX_CLKPWR_USBCTRL_USBI2C_EN;
+	__raw_writel(tmp, LPC32XX_CLKPWR_USB_CTRL);
+
 	/* Set up I2C pull levels */
 	tmp = __raw_readl(LPC32XX_CLKPWR_I2C_CLK_CTRL);
 	tmp |= LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE |
@@ -321,54 +279,51 @@
 	/*
 	 * AMBA peripheral clocks need to be enabled prior to AMBA device
 	 * detection or a data fault will occur, so enable the clocks
-	 * here. However, we don't want to enable them if the peripheral
-	 * isn't included in the image
+	 * here.
 	 */
-#ifdef CONFIG_FB_ARMCLCD
 	tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
 	__raw_writel((tmp | LPC32XX_CLKPWR_LCDCTRL_CLK_EN),
 		LPC32XX_CLKPWR_LCDCLK_CTRL);
-#endif
-#ifdef CONFIG_SPI_PL022
+
 	tmp = __raw_readl(LPC32XX_CLKPWR_SSP_CLK_CTRL);
 	__raw_writel((tmp | LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN),
 		LPC32XX_CLKPWR_SSP_CLK_CTRL);
-#endif
 
-	platform_add_devices(phy3250_devs, ARRAY_SIZE(phy3250_devs));
-	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
-		struct amba_device *d = amba_devs[i];
-		amba_device_register(d, &iomem_resource);
-	}
+	tmp = __raw_readl(LPC32XX_CLKPWR_DMA_CLK_CTRL);
+	__raw_writel((tmp | LPC32XX_CLKPWR_DMACLKCTRL_CLK_EN),
+		     LPC32XX_CLKPWR_DMA_CLK_CTRL);
 
 	/* Test clock needed for UDA1380 initial init */
 	__raw_writel(LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC |
 		LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN,
 		LPC32XX_CLKPWR_TEST_CLK_SEL);
 
-	i2c_register_board_info(0, phy3250_i2c_board_info,
-		ARRAY_SIZE(phy3250_i2c_board_info));
+	of_platform_populate(NULL, of_default_bus_match_table,
+			     lpc32xx_auxdata_lookup, NULL);
+
+	/* Register GPIOs used on this board */
+	if (gpio_request(SPI0_CS_GPIO, "spi0 cs"))
+		printk(KERN_ERR "Error requesting gpio %u",
+			SPI0_CS_GPIO);
+	else if (gpio_direction_output(SPI0_CS_GPIO, 1))
+		printk(KERN_ERR "Error setting gpio %u to output",
+			SPI0_CS_GPIO);
 }
 
-static int __init lpc32xx_display_uid(void)
-{
-	u32 uid[4];
+static char const *lpc32xx_dt_compat[] __initdata = {
+	"nxp,lpc3220",
+	"nxp,lpc3230",
+	"nxp,lpc3240",
+	"nxp,lpc3250",
+	NULL
+};
 
-	lpc32xx_get_uid(uid);
-
-	printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n",
-		uid[3], uid[2], uid[1], uid[0]);
-
-	return 1;
-}
-arch_initcall(lpc32xx_display_uid);
-
-MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller")
-	/* Maintainer: Kevin Wells, NXP Semiconductors */
+DT_MACHINE_START(LPC32XX_DT, "LPC32XX SoC (Flattened Device Tree)")
 	.atag_offset	= 0x100,
 	.map_io		= lpc32xx_map_io,
 	.init_irq	= lpc32xx_init_irq,
 	.timer		= &lpc32xx_timer,
-	.init_machine	= phy3250_board_init,
+	.init_machine	= lpc3250_machine_init,
+	.dt_compat	= lpc32xx_dt_compat,
 	.restart	= lpc23xx_restart,
 MACHINE_END
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index 5a90b9a..7fddd01 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -2,16 +2,6 @@
 
 menu "Marvell PXA168/910/MMP2 Implmentations"
 
-config MACH_MMP_DT
-	bool "Support MMP2 platforms from device tree"
-	select CPU_PXA168
-	select CPU_PXA910
-	select USE_OF
-	help
-	  Include support for Marvell MMP2 based platforms using
-	  the device tree. Needn't select any other machine while
-	  MACH_MMP_DT is enabled.
-
 config MACH_ASPENITE
 	bool "Marvell's PXA168 Aspenite Development Board"
 	select CPU_PXA168
@@ -94,6 +84,25 @@
 	  Say 'Y' here if you want to support the Marvell PXA168-based
 	  GuruPlug Display (gplugD) Board
 
+config MACH_MMP_DT
+	bool "Support MMP (ARMv5) platforms from device tree"
+	select CPU_PXA168
+	select CPU_PXA910
+	select USE_OF
+	help
+	  Include support for Marvell MMP2 based platforms using
+	  the device tree. Needn't select any other machine while
+	  MACH_MMP_DT is enabled.
+
+config MACH_MMP2_DT
+	bool "Support MMP2 (ARMv7) platforms from device tree"
+	depends on !CPU_MOHAWK
+	select CPU_MMP2
+	select USE_OF
+	help
+	  Include support for Marvell MMP2 based platforms using
+	  the device tree.
+
 endmenu
 
 config CPU_PXA168
@@ -113,4 +122,11 @@
 	select CPU_PJ4
 	help
 	  Select code specific to MMP2. MMP2 is ARMv7 compatible.
+
+config USB_EHCI_MV_U2O
+        bool "EHCI support for PXA USB OTG controller"
+	depends on USB_EHCI_MV
+	help
+	  Enables support for OTG controller which can be switched to host mode.
+
 endif
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 4fc0ff5..b786f7e 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -2,12 +2,17 @@
 # Makefile for Marvell's PXA168 processors line
 #
 
-obj-y				+= common.o clock.o devices.o time.o
+obj-y				+= common.o clock.o devices.o time.o irq.o
 
 # SoC support
-obj-$(CONFIG_CPU_PXA168)	+= pxa168.o irq-pxa168.o
-obj-$(CONFIG_CPU_PXA910)	+= pxa910.o irq-pxa168.o
-obj-$(CONFIG_CPU_MMP2)		+= mmp2.o irq-mmp2.o sram.o
+obj-$(CONFIG_CPU_PXA168)	+= pxa168.o
+obj-$(CONFIG_CPU_PXA910)	+= pxa910.o
+obj-$(CONFIG_CPU_MMP2)		+= mmp2.o sram.o
+
+ifeq ($(CONFIG_PM),y)
+obj-$(CONFIG_CPU_PXA910)	+= pm-pxa910.o
+obj-$(CONFIG_CPU_MMP2)		+= pm-mmp2.o
+endif
 
 # board support
 obj-$(CONFIG_MACH_ASPENITE)	+= aspenite.o
@@ -19,5 +24,6 @@
 obj-$(CONFIG_MACH_FLINT)	+= flint.o
 obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
 obj-$(CONFIG_MACH_MMP_DT)	+= mmp-dt.o
+obj-$(CONFIG_MACH_MMP2_DT)	+= mmp2-dt.o
 obj-$(CONFIG_MACH_TETON_BGA)	+= teton_bga.o
 obj-$(CONFIG_MACH_GPLUGD)	+= gplugd.o
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index bf5d8e1..223090b 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -17,6 +17,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 #include <linux/interrupt.h>
+#include <linux/platform_data/mv_usb.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -221,6 +222,21 @@
 	.debounce_interval	= 30,
 };
 
+#if defined(CONFIG_USB_EHCI_MV)
+static char *pxa168_sph_clock_name[] = {
+	[0] = "PXA168-USBCLK",
+};
+
+static struct mv_usb_platform_data pxa168_sph_pdata = {
+	.clknum         = 1,
+	.clkname        = pxa168_sph_clock_name,
+	.mode           = MV_USB_MODE_HOST,
+	.phy_init	= pxa_usb_phy_init,
+	.phy_deinit	= pxa_usb_phy_deinit,
+	.set_vbus	= NULL,
+};
+#endif
+
 static void __init common_init(void)
 {
 	mfp_config(ARRAY_AND_SIZE(common_pin_config));
@@ -236,6 +252,10 @@
 
 	/* off-chip devices */
 	platform_device_register(&smc91x_device);
+
+#if defined(CONFIG_USB_EHCI_MV)
+	pxa168_add_usb_host(&pxa168_sph_pdata);
+#endif
 }
 
 MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform")
diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c
index 191d9de..dd2d8b1 100644
--- a/arch/arm/mach-mmp/devices.c
+++ b/arch/arm/mach-mmp/devices.c
@@ -9,9 +9,13 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/delay.h>
 
 #include <asm/irq.h>
+#include <mach/irqs.h>
 #include <mach/devices.h>
+#include <mach/cputype.h>
+#include <mach/regs-usb.h>
 
 int __init pxa_register_device(struct pxa_device_desc *desc,
 				void *data, size_t size)
@@ -67,3 +71,281 @@
 
 	return platform_device_add(pdev);
 }
+
+#if defined(CONFIG_USB) || defined(CONFIG_USB_GADGET)
+
+/*****************************************************************************
+ * The registers read/write routines
+ *****************************************************************************/
+
+static unsigned int u2o_get(void __iomem *base, unsigned int offset)
+{
+	return readl_relaxed(base + offset);
+}
+
+static void u2o_set(void __iomem *base, unsigned int offset,
+		unsigned int value)
+{
+	u32 reg;
+
+	reg = readl_relaxed(base + offset);
+	reg |= value;
+	writel_relaxed(reg, base + offset);
+	readl_relaxed(base + offset);
+}
+
+static void u2o_clear(void __iomem *base, unsigned int offset,
+		unsigned int value)
+{
+	u32 reg;
+
+	reg = readl_relaxed(base + offset);
+	reg &= ~value;
+	writel_relaxed(reg, base + offset);
+	readl_relaxed(base + offset);
+}
+
+static void u2o_write(void __iomem *base, unsigned int offset,
+		unsigned int value)
+{
+	writel_relaxed(value, base + offset);
+	readl_relaxed(base + offset);
+}
+
+#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV)
+
+#if defined(CONFIG_CPU_PXA910) || defined(CONFIG_CPU_PXA168)
+
+static DEFINE_MUTEX(phy_lock);
+static int phy_init_cnt;
+
+static int usb_phy_init_internal(void __iomem *base)
+{
+	int loops;
+
+	pr_info("Init usb phy!!!\n");
+
+	/* Initialize the USB PHY power */
+	if (cpu_is_pxa910()) {
+		u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
+			| (1<<UTMI_CTRL_PU_REF_SHIFT));
+	}
+
+	u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
+	u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
+
+	/* UTMI_PLL settings */
+	u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
+		| UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
+		| UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
+		| UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
+
+	u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
+		| 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
+		| 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
+		| 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
+
+	/* UTMI_TX */
+	u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
+		| UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
+		| UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
+		| UTMI_TX_AMP_MASK);
+	u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
+		| 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT
+		| 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT);
+
+	/* UTMI_RX */
+	u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
+		| UTMI_REG_SQ_LENGTH_MASK);
+	u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
+		| 2<<UTMI_REG_SQ_LENGTH_SHIFT);
+
+	/* UTMI_IVREF */
+	if (cpu_is_pxa168())
+		/* fixing Microsoft Altair board interface with NEC hub issue -
+		 * Set UTMI_IVREF from 0x4a3 to 0x4bf */
+		u2o_write(base, UTMI_IVREF, 0x4bf);
+
+	/* toggle VCOCAL_START bit of UTMI_PLL */
+	udelay(200);
+	u2o_set(base, UTMI_PLL, VCOCAL_START);
+	udelay(40);
+	u2o_clear(base, UTMI_PLL, VCOCAL_START);
+
+	/* toggle REG_RCAL_START bit of UTMI_TX */
+	udelay(400);
+	u2o_set(base, UTMI_TX, REG_RCAL_START);
+	udelay(40);
+	u2o_clear(base, UTMI_TX, REG_RCAL_START);
+	udelay(400);
+
+	/* Make sure PHY PLL is ready */
+	loops = 0;
+	while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
+		mdelay(1);
+		loops++;
+		if (loops > 100) {
+			printk(KERN_WARNING "calibrate timeout, UTMI_PLL %x\n",
+				u2o_get(base, UTMI_PLL));
+			break;
+		}
+	}
+
+	if (cpu_is_pxa168()) {
+		u2o_set(base, UTMI_RESERVE, 1 << 5);
+		/* Turn on UTMI PHY OTG extension */
+		u2o_write(base, UTMI_OTG_ADDON, 1);
+	}
+
+	return 0;
+}
+
+static int usb_phy_deinit_internal(void __iomem *base)
+{
+	pr_info("Deinit usb phy!!!\n");
+
+	if (cpu_is_pxa168())
+		u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
+
+	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
+	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
+	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
+	u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
+	u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
+
+	return 0;
+}
+
+int pxa_usb_phy_init(void __iomem *phy_reg)
+{
+	mutex_lock(&phy_lock);
+	if (phy_init_cnt++ == 0)
+		usb_phy_init_internal(phy_reg);
+	mutex_unlock(&phy_lock);
+	return 0;
+}
+
+void pxa_usb_phy_deinit(void __iomem *phy_reg)
+{
+	WARN_ON(phy_init_cnt == 0);
+
+	mutex_lock(&phy_lock);
+	if (--phy_init_cnt == 0)
+		usb_phy_deinit_internal(phy_reg);
+	mutex_unlock(&phy_lock);
+}
+#endif
+#endif
+#endif
+
+#ifdef CONFIG_USB_SUPPORT
+static u64 usb_dma_mask = ~(u32)0;
+
+#ifdef CONFIG_USB_MV_UDC
+struct resource pxa168_u2o_resources[] = {
+	/* regbase */
+	[0] = {
+		.start	= PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
+		.end	= PXA168_U2O_REGBASE + USB_REG_RANGE,
+		.flags	= IORESOURCE_MEM,
+		.name	= "capregs",
+	},
+	/* phybase */
+	[1] = {
+		.start	= PXA168_U2O_PHYBASE,
+		.end	= PXA168_U2O_PHYBASE + USB_PHY_RANGE,
+		.flags	= IORESOURCE_MEM,
+		.name	= "phyregs",
+	},
+	[2] = {
+		.start	= IRQ_PXA168_USB1,
+		.end	= IRQ_PXA168_USB1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device pxa168_device_u2o = {
+	.name		= "mv-udc",
+	.id		= -1,
+	.resource	= pxa168_u2o_resources,
+	.num_resources	= ARRAY_SIZE(pxa168_u2o_resources),
+	.dev		=  {
+		.dma_mask	= &usb_dma_mask,
+		.coherent_dma_mask = 0xffffffff,
+	}
+};
+#endif /* CONFIG_USB_MV_UDC */
+
+#ifdef CONFIG_USB_EHCI_MV_U2O
+struct resource pxa168_u2oehci_resources[] = {
+	/* regbase */
+	[0] = {
+		.start	= PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
+		.end	= PXA168_U2O_REGBASE + USB_REG_RANGE,
+		.flags	= IORESOURCE_MEM,
+		.name	= "capregs",
+	},
+	/* phybase */
+	[1] = {
+		.start	= PXA168_U2O_PHYBASE,
+		.end	= PXA168_U2O_PHYBASE + USB_PHY_RANGE,
+		.flags	= IORESOURCE_MEM,
+		.name	= "phyregs",
+	},
+	[2] = {
+		.start	= IRQ_PXA168_USB1,
+		.end	= IRQ_PXA168_USB1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device pxa168_device_u2oehci = {
+	.name		= "pxa-u2oehci",
+	.id		= -1,
+	.dev		= {
+		.dma_mask		= &usb_dma_mask,
+		.coherent_dma_mask	= 0xffffffff,
+	},
+
+	.num_resources	= ARRAY_SIZE(pxa168_u2oehci_resources),
+	.resource	= pxa168_u2oehci_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_MV_OTG)
+struct resource pxa168_u2ootg_resources[] = {
+	/* regbase */
+	[0] = {
+		.start	= PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
+		.end	= PXA168_U2O_REGBASE + USB_REG_RANGE,
+		.flags	= IORESOURCE_MEM,
+		.name	= "capregs",
+	},
+	/* phybase */
+	[1] = {
+		.start	= PXA168_U2O_PHYBASE,
+		.end	= PXA168_U2O_PHYBASE + USB_PHY_RANGE,
+		.flags	= IORESOURCE_MEM,
+		.name	= "phyregs",
+	},
+	[2] = {
+		.start	= IRQ_PXA168_USB1,
+		.end	= IRQ_PXA168_USB1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device pxa168_device_u2ootg = {
+	.name		= "mv-otg",
+	.id		= -1,
+	.dev  = {
+		.dma_mask          = &usb_dma_mask,
+		.coherent_dma_mask = 0xffffffff,
+	},
+
+	.num_resources	= ARRAY_SIZE(pxa168_u2ootg_resources),
+	.resource      = pxa168_u2ootg_resources,
+};
+#endif /* CONFIG_USB_MV_OTG */
+
+#endif
diff --git a/arch/arm/mach-mmp/include/mach/addr-map.h b/arch/arm/mach-mmp/include/mach/addr-map.h
index b1ece08..f88a44c 100644
--- a/arch/arm/mach-mmp/include/mach/addr-map.h
+++ b/arch/arm/mach-mmp/include/mach/addr-map.h
@@ -31,4 +31,16 @@
 #define SMC_CS1_PHYS_BASE	0x90000000
 #define SMC_CS1_PHYS_SIZE	0x10000000
 
+#define APMU_VIRT_BASE		(AXI_VIRT_BASE + 0x82800)
+#define APMU_REG(x)		(APMU_VIRT_BASE + (x))
+
+#define APBC_VIRT_BASE		(APB_VIRT_BASE + 0x015000)
+#define APBC_REG(x)		(APBC_VIRT_BASE + (x))
+
+#define MPMU_VIRT_BASE		(APB_VIRT_BASE + 0x50000)
+#define MPMU_REG(x)		(MPMU_VIRT_BASE + (x))
+
+#define CIU_VIRT_BASE		(AXI_VIRT_BASE + 0x82c00)
+#define CIU_REG(x)		(CIU_VIRT_BASE + (x))
+
 #endif /* __ASM_MACH_ADDR_MAP_H */
diff --git a/arch/arm/mach-mmp/include/mach/devices.h b/arch/arm/mach-mmp/include/mach/devices.h
index d0ec7da..21217ef 100644
--- a/arch/arm/mach-mmp/include/mach/devices.h
+++ b/arch/arm/mach-mmp/include/mach/devices.h
@@ -50,4 +50,7 @@
 }
 
 extern int pxa_register_device(struct pxa_device_desc *, void *, size_t);
+extern int pxa_usb_phy_init(void __iomem *phy_reg);
+extern void pxa_usb_phy_deinit(void __iomem *phy_reg);
+
 #endif /* __MACH_DEVICE_H */
diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S
index 9cff9e7..bd152e2 100644
--- a/arch/arm/mach-mmp/include/mach/entry-macro.S
+++ b/arch/arm/mach-mmp/include/mach/entry-macro.S
@@ -6,13 +6,15 @@
  * published by the Free Software Foundation.
  */
 
+#include <asm/irq.h>
 #include <mach/regs-icu.h>
 
 	.macro	get_irqnr_preamble, base, tmp
 	mrc	p15, 0, \tmp, c0, c0, 0		@ CPUID
 	and	\tmp, \tmp, #0xff00
 	cmp	\tmp, #0x5800
-	ldr	\base, =ICU_VIRT_BASE
+	ldr	\base, =mmp_icu_base
+	ldr	\base, [\base, #0]
 	addne	\base, \base, #0x10c		@ PJ1 AP INT SEL register
 	addeq	\base, \base, #0x104		@ PJ4 IRQ SEL register
 	.endm
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h
index d0e7466..fb492a5 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/include/mach/irqs.h
@@ -125,7 +125,7 @@
 #define IRQ_MMP2_RTC_MUX		5
 #define IRQ_MMP2_TWSI1			7
 #define IRQ_MMP2_GPU			8
-#define IRQ_MMP2_KEYPAD			9
+#define IRQ_MMP2_KEYPAD_MUX		9
 #define IRQ_MMP2_ROTARY			10
 #define IRQ_MMP2_TRACKBALL		11
 #define IRQ_MMP2_ONEWIRE		12
@@ -163,11 +163,11 @@
 #define IRQ_MMP2_DMA_FIQ		47
 #define IRQ_MMP2_DMA_RIQ		48
 #define IRQ_MMP2_GPIO			49
-#define IRQ_MMP2_SSP_MUX		51
+#define IRQ_MMP2_MIPI_HSI1_MUX		51
 #define IRQ_MMP2_MMC2			52
 #define IRQ_MMP2_MMC3			53
 #define IRQ_MMP2_MMC4			54
-#define IRQ_MMP2_MIPI_HSI		55
+#define IRQ_MMP2_MIPI_HSI0_MUX		55
 #define IRQ_MMP2_MSP			58
 #define IRQ_MMP2_MIPI_SLIM_DMA		59
 #define IRQ_MMP2_PJ4_FREQ_CHG		60
@@ -186,8 +186,14 @@
 #define IRQ_MMP2_RTC_ALARM		(IRQ_MMP2_RTC_BASE + 0)
 #define IRQ_MMP2_RTC			(IRQ_MMP2_RTC_BASE + 1)
 
+/* secondary interrupt of INT #9 */
+#define IRQ_MMP2_KEYPAD_BASE		(IRQ_MMP2_RTC_BASE + 2)
+#define IRQ_MMP2_KPC			(IRQ_MMP2_KEYPAD_BASE + 0)
+#define IRQ_MMP2_ROTORY			(IRQ_MMP2_KEYPAD_BASE + 1)
+#define IRQ_MMP2_TBALL			(IRQ_MMP2_KEYPAD_BASE + 2)
+
 /* secondary interrupt of INT #17 */
-#define IRQ_MMP2_TWSI_BASE		(IRQ_MMP2_RTC_BASE + 2)
+#define IRQ_MMP2_TWSI_BASE		(IRQ_MMP2_KEYPAD_BASE + 3)
 #define IRQ_MMP2_TWSI2			(IRQ_MMP2_TWSI_BASE + 0)
 #define IRQ_MMP2_TWSI3			(IRQ_MMP2_TWSI_BASE + 1)
 #define IRQ_MMP2_TWSI4			(IRQ_MMP2_TWSI_BASE + 2)
@@ -212,11 +218,16 @@
 #define IRQ_MMP2_COMMRX			(IRQ_MMP2_MISC_BASE + 14)
 
 /* secondary interrupt of INT #51 */
-#define IRQ_MMP2_SSP_BASE		(IRQ_MMP2_MISC_BASE + 15)
-#define IRQ_MMP2_SSP1_SRDY		(IRQ_MMP2_SSP_BASE + 0)
-#define IRQ_MMP2_SSP3_SRDY		(IRQ_MMP2_SSP_BASE + 1)
+#define IRQ_MMP2_MIPI_HSI1_BASE		(IRQ_MMP2_MISC_BASE + 15)
+#define IRQ_MMP2_HSI1_CAWAKE		(IRQ_MMP2_MIPI_HSI1_BASE + 0)
+#define IRQ_MMP2_MIPI_HSI_INT1		(IRQ_MMP2_MIPI_HSI1_BASE + 1)
 
-#define IRQ_MMP2_MUX_END		(IRQ_MMP2_SSP_BASE + 2)
+/* secondary interrupt of INT #55 */
+#define IRQ_MMP2_MIPI_HSI0_BASE		(IRQ_MMP2_MIPI_HSI1_BASE + 2)
+#define IRQ_MMP2_HSI0_CAWAKE		(IRQ_MMP2_MIPI_HSI0_BASE + 0)
+#define IRQ_MMP2_MIPI_HSI_INT0		(IRQ_MMP2_MIPI_HSI0_BASE + 1)
+
+#define IRQ_MMP2_MUX_END		(IRQ_MMP2_MIPI_HSI0_BASE + 2)
 
 #define IRQ_GPIO_START			128
 #define MMP_NR_BUILTIN_GPIO		192
diff --git a/arch/arm/mach-mmp/include/mach/pm-mmp2.h b/arch/arm/mach-mmp/include/mach/pm-mmp2.h
new file mode 100644
index 0000000..98bd66c
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/pm-mmp2.h
@@ -0,0 +1,61 @@
+/*
+ * MMP2 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2010 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#ifndef __MMP2_PM_H__
+#define __MMP2_PM_H__
+
+#include <mach/addr-map.h>
+
+#define APMU_PJ_IDLE_CFG			APMU_REG(0x018)
+#define APMU_PJ_IDLE_CFG_PJ_IDLE		(1 << 1)
+#define APMU_PJ_IDLE_CFG_PJ_PWRDWN		(1 << 5)
+#define APMU_PJ_IDLE_CFG_PWR_SW(x)		((x) << 16)
+#define APMU_PJ_IDLE_CFG_L2_PWR_SW		(1 << 19)
+#define APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK	(3 << 28)
+
+#define APMU_SRAM_PWR_DWN			APMU_REG(0x08c)
+
+#define MPMU_SCCR				MPMU_REG(0x038)
+#define MPMU_PCR_PJ				MPMU_REG(0x1000)
+#define MPMU_PCR_PJ_AXISD			(1 << 31)
+#define MPMU_PCR_PJ_SLPEN			(1 << 29)
+#define MPMU_PCR_PJ_SPSD			(1 << 28)
+#define MPMU_PCR_PJ_DDRCORSD			(1 << 27)
+#define MPMU_PCR_PJ_APBSD			(1 << 26)
+#define MPMU_PCR_PJ_INTCLR			(1 << 24)
+#define MPMU_PCR_PJ_SLPWP0			(1 << 23)
+#define MPMU_PCR_PJ_SLPWP1			(1 << 22)
+#define MPMU_PCR_PJ_SLPWP2			(1 << 21)
+#define MPMU_PCR_PJ_SLPWP3			(1 << 20)
+#define MPMU_PCR_PJ_VCTCXOSD			(1 << 19)
+#define MPMU_PCR_PJ_SLPWP4			(1 << 18)
+#define MPMU_PCR_PJ_SLPWP5			(1 << 17)
+#define MPMU_PCR_PJ_SLPWP6			(1 << 16)
+#define MPMU_PCR_PJ_SLPWP7			(1 << 15)
+
+#define MPMU_PLL2_CTRL1				MPMU_REG(0x0414)
+#define MPMU_CGR_PJ				MPMU_REG(0x1024)
+#define MPMU_WUCRM_PJ				MPMU_REG(0x104c)
+#define MPMU_WUCRM_PJ_WAKEUP(x)			(1 << (x))
+#define MPMU_WUCRM_PJ_RTC_ALARM			(1 << 17)
+
+enum {
+	POWER_MODE_ACTIVE = 0,
+	POWER_MODE_CORE_INTIDLE,
+	POWER_MODE_CORE_EXTIDLE,
+	POWER_MODE_APPS_IDLE,
+	POWER_MODE_APPS_SLEEP,
+	POWER_MODE_CHIP_SLEEP,
+	POWER_MODE_SYS_SLEEP,
+};
+
+extern void mmp2_pm_enter_lowpower_mode(int state);
+extern int mmp2_set_wake(struct irq_data *d, unsigned int on);
+#endif
diff --git a/arch/arm/mach-mmp/include/mach/pm-pxa910.h b/arch/arm/mach-mmp/include/mach/pm-pxa910.h
new file mode 100644
index 0000000..8cac8ab
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/pm-pxa910.h
@@ -0,0 +1,77 @@
+/*
+ * PXA910 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2009 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#ifndef __PXA910_PM_H__
+#define __PXA910_PM_H__
+
+#define APMU_MOH_IDLE_CFG			APMU_REG(0x0018)
+#define APMU_MOH_IDLE_CFG_MOH_IDLE		(1 << 1)
+#define APMU_MOH_IDLE_CFG_MOH_PWRDWN		(1 << 5)
+#define APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN	(1 << 6)
+#define APMU_MOH_IDLE_CFG_MOH_PWR_SW(x)		(((x) & 0x3) << 16)
+#define APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(x)	(((x) & 0x3) << 18)
+#define APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ	(1 << 21)
+#define APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN	(1 << 20)
+
+#define APMU_SQU_CLK_GATE_CTRL			APMU_REG(0x001c)
+#define APMU_MC_HW_SLP_TYPE			APMU_REG(0x00b0)
+
+#define MPMU_FCCR				MPMU_REG(0x0008)
+#define MPMU_APCR				MPMU_REG(0x1000)
+#define MPMU_APCR_AXISD				(1 << 31)
+#define MPMU_APCR_DSPSD				(1 << 30)
+#define MPMU_APCR_SLPEN				(1 << 29)
+#define MPMU_APCR_DTCMSD			(1 << 28)
+#define MPMU_APCR_DDRCORSD			(1 << 27)
+#define MPMU_APCR_APBSD				(1 << 26)
+#define MPMU_APCR_BBSD				(1 << 25)
+#define MPMU_APCR_SLPWP0			(1 << 23)
+#define MPMU_APCR_SLPWP1			(1 << 22)
+#define MPMU_APCR_SLPWP2			(1 << 21)
+#define MPMU_APCR_SLPWP3			(1 << 20)
+#define MPMU_APCR_VCTCXOSD			(1 << 19)
+#define MPMU_APCR_SLPWP4			(1 << 18)
+#define MPMU_APCR_SLPWP5			(1 << 17)
+#define MPMU_APCR_SLPWP6			(1 << 16)
+#define MPMU_APCR_SLPWP7			(1 << 15)
+#define MPMU_APCR_MSASLPEN			(1 << 14)
+#define MPMU_APCR_STBYEN			(1 << 13)
+
+#define MPMU_AWUCRM				MPMU_REG(0x104c)
+#define MPMU_AWUCRM_AP_ASYNC_INT		(1 << 25)
+#define MPMU_AWUCRM_AP_FULL_IDLE		(1 << 24)
+#define MPMU_AWUCRM_SDH1			(1 << 23)
+#define MPMU_AWUCRM_SDH2			(1 << 22)
+#define MPMU_AWUCRM_KEYPRESS			(1 << 21)
+#define MPMU_AWUCRM_TRACKBALL			(1 << 20)
+#define MPMU_AWUCRM_NEWROTARY			(1 << 19)
+#define MPMU_AWUCRM_RTC_ALARM			(1 << 17)
+#define MPMU_AWUCRM_AP2_TIMER_3			(1 << 13)
+#define MPMU_AWUCRM_AP2_TIMER_2			(1 << 12)
+#define MPMU_AWUCRM_AP2_TIMER_1			(1 << 11)
+#define MPMU_AWUCRM_AP1_TIMER_3			(1 << 10)
+#define MPMU_AWUCRM_AP1_TIMER_2			(1 << 9)
+#define MPMU_AWUCRM_AP1_TIMER_1			(1 << 8)
+#define MPMU_AWUCRM_WAKEUP(x)			(1 << ((x) & 0x7))
+
+enum {
+	POWER_MODE_ACTIVE = 0,
+	POWER_MODE_CORE_INTIDLE,
+	POWER_MODE_CORE_EXTIDLE,
+	POWER_MODE_APPS_IDLE,
+	POWER_MODE_APPS_SLEEP,
+	POWER_MODE_SYS_SLEEP,
+	POWER_MODE_HIBERNATE,
+	POWER_MODE_UDR,
+};
+
+extern int pxa910_set_wake(struct irq_data *data, unsigned int on);
+
+#endif
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h
index dc03d58..09dcd6e 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -16,6 +16,7 @@
 #include <plat/pxa27x_keypad.h>
 #include <mach/cputype.h>
 #include <linux/pxa168_eth.h>
+#include <linux/platform_data/mv_usb.h>
 
 extern struct pxa_device_desc pxa168_device_uart1;
 extern struct pxa_device_desc pxa168_device_uart2;
@@ -36,12 +37,9 @@
 extern struct pxa_device_desc pxa168_device_keypad;
 extern struct pxa_device_desc pxa168_device_eth;
 
-struct pxa168_usb_pdata {
-	/* If NULL, default phy init routine for PXA168 would be called */
-	int (*phy_init)(void __iomem *usb_phy_reg_base);
-};
 /* pdata can be NULL */
-int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata);
+extern int __init pxa168_add_usb_host(struct mv_usb_platform_data *pdata);
+
 
 extern struct platform_device pxa168_device_gpio;
 
diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h
index e2e1f1e..793634c 100644
--- a/arch/arm/mach-mmp/include/mach/pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/pxa910.h
@@ -20,6 +20,9 @@
 extern struct pxa_device_desc pxa910_device_pwm3;
 extern struct pxa_device_desc pxa910_device_pwm4;
 extern struct pxa_device_desc pxa910_device_nand;
+extern struct platform_device pxa168_device_u2o;
+extern struct platform_device pxa168_device_u2ootg;
+extern struct platform_device pxa168_device_u2oehci;
 
 extern struct platform_device pxa910_device_gpio;
 extern struct platform_device pxa910_device_rtc;
diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h
index 8a37fb0..68b0c93 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apbc.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h
@@ -13,9 +13,6 @@
 
 #include <mach/addr-map.h>
 
-#define APBC_VIRT_BASE	(APB_VIRT_BASE + 0x015000)
-#define APBC_REG(x)	(APBC_VIRT_BASE + (x))
-
 /*
  * APB clock register offsets for PXA168
  */
diff --git a/arch/arm/mach-mmp/include/mach/regs-apmu.h b/arch/arm/mach-mmp/include/mach/regs-apmu.h
index 8447ac6..7af8deb 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apmu.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apmu.h
@@ -13,9 +13,6 @@
 
 #include <mach/addr-map.h>
 
-#define APMU_VIRT_BASE	(AXI_VIRT_BASE + 0x82800)
-#define APMU_REG(x)	(APMU_VIRT_BASE + (x))
-
 /* Clock Reset Control */
 #define APMU_IRE	APMU_REG(0x048)
 #define APMU_LCD	APMU_REG(0x04c)
diff --git a/arch/arm/mach-mmp/include/mach/regs-usb.h b/arch/arm/mach-mmp/include/mach/regs-usb.h
new file mode 100644
index 0000000..b047bf4
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/regs-usb.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_ARCH_REGS_USB_H
+#define __ASM_ARCH_REGS_USB_H
+
+#define PXA168_U2O_REGBASE	(0xd4208000)
+#define PXA168_U2O_PHYBASE	(0xd4207000)
+
+#define PXA168_U2H_REGBASE      (0xd4209000)
+#define PXA168_U2H_PHYBASE      (0xd4206000)
+
+#define MMP3_HSIC1_REGBASE	(0xf0001000)
+#define MMP3_HSIC1_PHYBASE	(0xf0001800)
+
+#define MMP3_HSIC2_REGBASE	(0xf0002000)
+#define MMP3_HSIC2_PHYBASE	(0xf0002800)
+
+#define MMP3_FSIC_REGBASE	(0xf0003000)
+#define MMP3_FSIC_PHYBASE	(0xf0003800)
+
+
+#define USB_REG_RANGE		(0x1ff)
+#define USB_PHY_RANGE		(0xff)
+
+/* registers */
+#define U2x_CAPREGS_OFFSET       0x100
+
+/* phy regs */
+#define UTMI_REVISION		0x0
+#define UTMI_CTRL		0x4
+#define UTMI_PLL		0x8
+#define UTMI_TX			0xc
+#define UTMI_RX			0x10
+#define UTMI_IVREF		0x14
+#define UTMI_T0			0x18
+#define UTMI_T1			0x1c
+#define UTMI_T2			0x20
+#define UTMI_T3			0x24
+#define UTMI_T4			0x28
+#define UTMI_T5			0x2c
+#define UTMI_RESERVE		0x30
+#define UTMI_USB_INT		0x34
+#define UTMI_DBG_CTL		0x38
+#define UTMI_OTG_ADDON		0x3c
+
+/* For UTMICTRL Register */
+#define UTMI_CTRL_USB_CLK_EN                    (1 << 31)
+/* pxa168 */
+#define UTMI_CTRL_SUSPEND_SET1                  (1 << 30)
+#define UTMI_CTRL_SUSPEND_SET2                  (1 << 29)
+#define UTMI_CTRL_RXBUF_PDWN                    (1 << 24)
+#define UTMI_CTRL_TXBUF_PDWN                    (1 << 11)
+
+#define UTMI_CTRL_INPKT_DELAY_SHIFT             30
+#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT		28
+#define UTMI_CTRL_PU_REF_SHIFT			20
+#define UTMI_CTRL_ARC_PULLDN_SHIFT              12
+#define UTMI_CTRL_PLL_PWR_UP_SHIFT              1
+#define UTMI_CTRL_PWR_UP_SHIFT                  0
+
+/* For UTMI_PLL Register */
+#define UTMI_PLL_PLLCALI12_SHIFT		29
+#define UTMI_PLL_PLLCALI12_MASK			(0x3 << 29)
+
+#define UTMI_PLL_PLLVDD18_SHIFT			27
+#define UTMI_PLL_PLLVDD18_MASK			(0x3 << 27)
+
+#define UTMI_PLL_PLLVDD12_SHIFT			25
+#define UTMI_PLL_PLLVDD12_MASK			(0x3 << 25)
+
+#define UTMI_PLL_CLK_BLK_EN_SHIFT               24
+#define CLK_BLK_EN                              (0x1 << 24)
+#define PLL_READY                               (0x1 << 23)
+#define KVCO_EXT                                (0x1 << 22)
+#define VCOCAL_START                            (0x1 << 21)
+
+#define UTMI_PLL_KVCO_SHIFT			15
+#define UTMI_PLL_KVCO_MASK                      (0x7 << 15)
+
+#define UTMI_PLL_ICP_SHIFT			12
+#define UTMI_PLL_ICP_MASK                       (0x7 << 12)
+
+#define UTMI_PLL_FBDIV_SHIFT                    4
+#define UTMI_PLL_FBDIV_MASK                     (0xFF << 4)
+
+#define UTMI_PLL_REFDIV_SHIFT                   0
+#define UTMI_PLL_REFDIV_MASK                    (0xF << 0)
+
+/* For UTMI_TX Register */
+#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT		27
+#define UTMI_TX_REG_EXT_FS_RCAL_MASK		(0xf << 27)
+
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT	26
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK		(0x1 << 26)
+
+#define UTMI_TX_TXVDD12_SHIFT                   22
+#define UTMI_TX_TXVDD12_MASK                    (0x3 << 22)
+
+#define UTMI_TX_CK60_PHSEL_SHIFT                17
+#define UTMI_TX_CK60_PHSEL_MASK                 (0xf << 17)
+
+#define UTMI_TX_IMPCAL_VTH_SHIFT                14
+#define UTMI_TX_IMPCAL_VTH_MASK                 (0x7 << 14)
+
+#define REG_RCAL_START                          (0x1 << 12)
+
+#define UTMI_TX_LOW_VDD_EN_SHIFT                11
+
+#define UTMI_TX_AMP_SHIFT			0
+#define UTMI_TX_AMP_MASK			(0x7 << 0)
+
+/* For UTMI_RX Register */
+#define UTMI_REG_SQ_LENGTH_SHIFT                15
+#define UTMI_REG_SQ_LENGTH_MASK                 (0x3 << 15)
+
+#define UTMI_RX_SQ_THRESH_SHIFT                 4
+#define UTMI_RX_SQ_THRESH_MASK                  (0xf << 4)
+
+#define UTMI_OTG_ADDON_OTG_ON			(1 << 0)
+
+/* For MMP3 USB Phy */
+#define USB2_PLL_REG0		0x4
+#define USB2_PLL_REG1		0x8
+#define USB2_TX_REG0		0x10
+#define USB2_TX_REG1		0x14
+#define USB2_TX_REG2		0x18
+#define USB2_RX_REG0		0x20
+#define USB2_RX_REG1		0x24
+#define USB2_RX_REG2		0x28
+#define USB2_ANA_REG0		0x30
+#define USB2_ANA_REG1		0x34
+#define USB2_ANA_REG2		0x38
+#define USB2_DIG_REG0		0x3C
+#define USB2_DIG_REG1		0x40
+#define USB2_DIG_REG2		0x44
+#define USB2_DIG_REG3		0x48
+#define USB2_TEST_REG0		0x4C
+#define USB2_TEST_REG1		0x50
+#define USB2_TEST_REG2		0x54
+#define USB2_CHARGER_REG0	0x58
+#define USB2_OTG_REG0		0x5C
+#define USB2_PHY_MON0		0x60
+#define USB2_RESETVE_REG0	0x64
+#define USB2_ICID_REG0		0x78
+#define USB2_ICID_REG1		0x7C
+
+/* USB2_PLL_REG0 */
+/* This is for Ax stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3		0
+#define USB2_PLL_FBDIV_MASK_MMP3		(0xFF << 0)
+
+#define USB2_PLL_REFDIV_SHIFT_MMP3		8
+#define USB2_PLL_REFDIV_MASK_MMP3		(0xF << 8)
+
+#define USB2_PLL_VDD12_SHIFT_MMP3		12
+#define USB2_PLL_VDD18_SHIFT_MMP3		14
+
+/* This is for B0 stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3_B0		0
+#define USB2_PLL_REFDIV_SHIFT_MMP3_B0		9
+#define USB2_PLL_VDD18_SHIFT_MMP3_B0		14
+#define USB2_PLL_FBDIV_MASK_MMP3_B0		0x01FF
+#define USB2_PLL_REFDIV_MASK_MMP3_B0		0x3E00
+
+#define USB2_PLL_CAL12_SHIFT_MMP3		0
+#define USB2_PLL_CALI12_MASK_MMP3		(0x3 << 0)
+
+#define USB2_PLL_VCOCAL_START_SHIFT_MMP3	2
+
+#define USB2_PLL_KVCO_SHIFT_MMP3		4
+#define USB2_PLL_KVCO_MASK_MMP3			(0x7<<4)
+
+#define USB2_PLL_ICP_SHIFT_MMP3			8
+#define USB2_PLL_ICP_MASK_MMP3			(0x7<<8)
+
+#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3		12
+
+#define USB2_PLL_PU_PLL_SHIFT_MMP3		13
+#define USB2_PLL_PU_PLL_MASK			(0x1 << 13)
+
+#define USB2_PLL_READY_MASK_MMP3		(0x1 << 15)
+
+/* USB2_TX_REG0 */
+#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3		8
+#define USB2_TX_IMPCAL_VTH_MASK_MMP3		(0x7 << 8)
+
+#define USB2_TX_RCAL_START_SHIFT_MMP3		13
+
+/* USB2_TX_REG1 */
+#define USB2_TX_CK60_PHSEL_SHIFT_MMP3		0
+#define USB2_TX_CK60_PHSEL_MASK_MMP3		(0xf << 0)
+
+#define USB2_TX_AMP_SHIFT_MMP3			4
+#define USB2_TX_AMP_MASK_MMP3			(0x7 << 4)
+
+#define USB2_TX_VDD12_SHIFT_MMP3		8
+#define USB2_TX_VDD12_MASK_MMP3			(0x3 << 8)
+
+/* USB2_TX_REG2 */
+#define USB2_TX_DRV_SLEWRATE_SHIFT		10
+
+/* USB2_RX_REG0 */
+#define USB2_RX_SQ_THRESH_SHIFT_MMP3		4
+#define USB2_RX_SQ_THRESH_MASK_MMP3		(0xf << 4)
+
+#define USB2_RX_SQ_LENGTH_SHIFT_MMP3		10
+#define USB2_RX_SQ_LENGTH_MASK_MMP3		(0x3 << 10)
+
+/* USB2_ANA_REG1*/
+#define USB2_ANA_PU_ANA_SHIFT_MMP3		14
+
+/* USB2_OTG_REG0 */
+#define USB2_OTG_PU_OTG_SHIFT_MMP3		3
+
+/* fsic registers */
+#define FSIC_MISC			0x4
+#define FSIC_INT			0x28
+#define FSIC_CTRL			0x30
+
+/* HSIC registers */
+#define HSIC_PAD_CTRL			0x4
+
+#define HSIC_CTRL			0x8
+#define HSIC_CTRL_HSIC_ENABLE		(1<<7)
+#define HSIC_CTRL_PLL_BYPASS		(1<<4)
+
+#define TEST_GRP_0			0xc
+#define TEST_GRP_1			0x10
+
+#define HSIC_INT			0x14
+#define HSIC_INT_READY_INT_EN		(1<<10)
+#define HSIC_INT_CONNECT_INT_EN		(1<<9)
+#define HSIC_INT_CORE_INT_EN		(1<<8)
+#define HSIC_INT_HS_READY		(1<<2)
+#define HSIC_INT_CONNECT		(1<<1)
+#define HSIC_INT_CORE			(1<<0)
+
+#define HSIC_CONFIG			0x18
+#define USBHSIC_CTRL			0x20
+
+#define HSIC_USB_CTRL			0x28
+#define HSIC_USB_CTRL_CLKEN		1
+#define	HSIC_USB_CLK_PHY		0x0
+#define HSIC_USB_CLK_PMU		0x1
+
+#endif /* __ASM_ARCH_PXA_U2O_H */
diff --git a/arch/arm/mach-mmp/irq-mmp2.c b/arch/arm/mach-mmp/irq-mmp2.c
deleted file mode 100644
index 7895d27..0000000
--- a/arch/arm/mach-mmp/irq-mmp2.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- *  linux/arch/arm/mach-mmp/irq-mmp2.c
- *
- *  Generic IRQ handling, GPIO IRQ demultiplexing, etc.
- *
- *  Author:	Haojian Zhuang <haojian.zhuang@marvell.com>
- *  Copyright:	Marvell International Ltd.
- *
- *  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/irq.h>
-#include <linux/io.h>
-
-#include <mach/irqs.h>
-#include <mach/regs-icu.h>
-#include <mach/mmp2.h>
-
-#include "common.h"
-
-static void icu_mask_irq(struct irq_data *d)
-{
-	uint32_t r = __raw_readl(ICU_INT_CONF(d->irq));
-
-	r &= ~ICU_INT_ROUTE_PJ4_IRQ;
-	__raw_writel(r, ICU_INT_CONF(d->irq));
-}
-
-static void icu_unmask_irq(struct irq_data *d)
-{
-	uint32_t r = __raw_readl(ICU_INT_CONF(d->irq));
-
-	r |= ICU_INT_ROUTE_PJ4_IRQ;
-	__raw_writel(r, ICU_INT_CONF(d->irq));
-}
-
-static struct irq_chip icu_irq_chip = {
-	.name		= "icu_irq",
-	.irq_mask	= icu_mask_irq,
-	.irq_mask_ack	= icu_mask_irq,
-	.irq_unmask	= icu_unmask_irq,
-};
-
-static void pmic_irq_ack(struct irq_data *d)
-{
-	if (d->irq == IRQ_MMP2_PMIC)
-		mmp2_clear_pmic_int();
-}
-
-#define SECOND_IRQ_MASK(_name_, irq_base, prefix)			\
-static void _name_##_mask_irq(struct irq_data *d)			\
-{									\
-	uint32_t r;							\
-	r = __raw_readl(prefix##_MASK) | (1 << (d->irq - irq_base));	\
-	__raw_writel(r, prefix##_MASK);					\
-}
-
-#define SECOND_IRQ_UNMASK(_name_, irq_base, prefix)			\
-static void _name_##_unmask_irq(struct irq_data *d)			\
-{									\
-	uint32_t r;							\
-	r = __raw_readl(prefix##_MASK) & ~(1 << (d->irq - irq_base));	\
-	__raw_writel(r, prefix##_MASK);					\
-}
-
-#define SECOND_IRQ_DEMUX(_name_, irq_base, prefix)			\
-static void _name_##_irq_demux(unsigned int irq, struct irq_desc *desc)	\
-{									\
-	unsigned long status, mask, n;					\
-	mask = __raw_readl(prefix##_MASK);				\
-	while (1) {							\
-		status = __raw_readl(prefix##_STATUS) & ~mask;		\
-		if (status == 0)					\
-			break;						\
-		n = find_first_bit(&status, BITS_PER_LONG);		\
-		while (n < BITS_PER_LONG) {				\
-			generic_handle_irq(irq_base + n);		\
-			n = find_next_bit(&status, BITS_PER_LONG, n+1);	\
-		}							\
-	}								\
-}
-
-#define SECOND_IRQ_CHIP(_name_, irq_base, prefix)			\
-SECOND_IRQ_MASK(_name_, irq_base, prefix)				\
-SECOND_IRQ_UNMASK(_name_, irq_base, prefix)				\
-SECOND_IRQ_DEMUX(_name_, irq_base, prefix)				\
-static struct irq_chip _name_##_irq_chip = {				\
-	.name		= #_name_,					\
-	.irq_mask	= _name_##_mask_irq,				\
-	.irq_unmask	= _name_##_unmask_irq,				\
-}
-
-SECOND_IRQ_CHIP(pmic, IRQ_MMP2_PMIC_BASE, MMP2_ICU_INT4);
-SECOND_IRQ_CHIP(rtc,  IRQ_MMP2_RTC_BASE,  MMP2_ICU_INT5);
-SECOND_IRQ_CHIP(twsi, IRQ_MMP2_TWSI_BASE, MMP2_ICU_INT17);
-SECOND_IRQ_CHIP(misc, IRQ_MMP2_MISC_BASE, MMP2_ICU_INT35);
-SECOND_IRQ_CHIP(ssp,  IRQ_MMP2_SSP_BASE,  MMP2_ICU_INT51);
-
-static void init_mux_irq(struct irq_chip *chip, int start, int num)
-{
-	int irq;
-
-	for (irq = start; num > 0; irq++, num--) {
-		struct irq_data *d = irq_get_irq_data(irq);
-
-		/* mask and clear the IRQ */
-		chip->irq_mask(d);
-		if (chip->irq_ack)
-			chip->irq_ack(d);
-
-		irq_set_chip(irq, chip);
-		set_irq_flags(irq, IRQF_VALID);
-		irq_set_handler(irq, handle_level_irq);
-	}
-}
-
-void __init mmp2_init_icu(void)
-{
-	int irq;
-
-	for (irq = 0; irq < IRQ_MMP2_MUX_BASE; irq++) {
-		icu_mask_irq(irq_get_irq_data(irq));
-		irq_set_chip(irq, &icu_irq_chip);
-		set_irq_flags(irq, IRQF_VALID);
-
-		switch (irq) {
-		case IRQ_MMP2_PMIC_MUX:
-		case IRQ_MMP2_RTC_MUX:
-		case IRQ_MMP2_TWSI_MUX:
-		case IRQ_MMP2_MISC_MUX:
-		case IRQ_MMP2_SSP_MUX:
-			break;
-		default:
-			irq_set_handler(irq, handle_level_irq);
-			break;
-		}
-	}
-
-	/* NOTE: IRQ_MMP2_PMIC requires the PMIC MFPR register
-	 * to be written to clear the interrupt
-	 */
-	pmic_irq_chip.irq_ack = pmic_irq_ack;
-
-	init_mux_irq(&pmic_irq_chip, IRQ_MMP2_PMIC_BASE, 2);
-	init_mux_irq(&rtc_irq_chip, IRQ_MMP2_RTC_BASE, 2);
-	init_mux_irq(&twsi_irq_chip, IRQ_MMP2_TWSI_BASE, 5);
-	init_mux_irq(&misc_irq_chip, IRQ_MMP2_MISC_BASE, 15);
-	init_mux_irq(&ssp_irq_chip, IRQ_MMP2_SSP_BASE, 2);
-
-	irq_set_chained_handler(IRQ_MMP2_PMIC_MUX, pmic_irq_demux);
-	irq_set_chained_handler(IRQ_MMP2_RTC_MUX, rtc_irq_demux);
-	irq_set_chained_handler(IRQ_MMP2_TWSI_MUX, twsi_irq_demux);
-	irq_set_chained_handler(IRQ_MMP2_MISC_MUX, misc_irq_demux);
-	irq_set_chained_handler(IRQ_MMP2_SSP_MUX, ssp_irq_demux);
-}
diff --git a/arch/arm/mach-mmp/irq-pxa168.c b/arch/arm/mach-mmp/irq-pxa168.c
deleted file mode 100644
index 89706a0..0000000
--- a/arch/arm/mach-mmp/irq-pxa168.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *  linux/arch/arm/mach-mmp/irq.c
- *
- *  Generic IRQ handling, GPIO IRQ demultiplexing, etc.
- *
- *  Author:	Bin Yang <bin.yang@marvell.com>
- *  Created:	Sep 30, 2008
- *  Copyright:	Marvell International Ltd.
- *
- *  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/irq.h>
-#include <linux/io.h>
-
-#include <mach/regs-icu.h>
-
-#include "common.h"
-
-#define IRQ_ROUTE_TO_AP		(ICU_INT_CONF_AP_INT | ICU_INT_CONF_IRQ)
-
-#define PRIORITY_DEFAULT	0x1
-#define PRIORITY_NONE		0x0	/* means IRQ disabled */
-
-static void icu_mask_irq(struct irq_data *d)
-{
-	__raw_writel(PRIORITY_NONE, ICU_INT_CONF(d->irq));
-}
-
-static void icu_unmask_irq(struct irq_data *d)
-{
-	__raw_writel(IRQ_ROUTE_TO_AP | PRIORITY_DEFAULT, ICU_INT_CONF(d->irq));
-}
-
-static struct irq_chip icu_irq_chip = {
-	.name		= "icu_irq",
-	.irq_ack	= icu_mask_irq,
-	.irq_mask	= icu_mask_irq,
-	.irq_unmask	= icu_unmask_irq,
-};
-
-void __init icu_init_irq(void)
-{
-	int irq;
-
-	for (irq = 0; irq < 64; irq++) {
-		icu_mask_irq(irq_get_irq_data(irq));
-		irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-}
diff --git a/arch/arm/mach-mmp/irq.c b/arch/arm/mach-mmp/irq.c
new file mode 100644
index 0000000..fcfe0e3
--- /dev/null
+++ b/arch/arm/mach-mmp/irq.c
@@ -0,0 +1,458 @@
+/*
+ *  linux/arch/arm/mach-mmp/irq.c
+ *
+ *  Generic IRQ handling, GPIO IRQ demultiplexing, etc.
+ *  Copyright (C) 2008 - 2012 Marvell Technology Group Ltd.
+ *
+ *  Author:	Bin Yang <bin.yang@marvell.com>
+ *              Haojian Zhuang <haojian.zhuang@gmail.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/init.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <mach/irqs.h>
+
+#ifdef CONFIG_CPU_MMP2
+#include <mach/pm-mmp2.h>
+#endif
+#ifdef CONFIG_CPU_PXA910
+#include <mach/pm-pxa910.h>
+#endif
+
+#include "common.h"
+
+#define MAX_ICU_NR		16
+
+struct icu_chip_data {
+	int			nr_irqs;
+	unsigned int		virq_base;
+	unsigned int		cascade_irq;
+	void __iomem		*reg_status;
+	void __iomem		*reg_mask;
+	unsigned int		conf_enable;
+	unsigned int		conf_disable;
+	unsigned int		conf_mask;
+	unsigned int		clr_mfp_irq_base;
+	unsigned int		clr_mfp_hwirq;
+	struct irq_domain	*domain;
+};
+
+struct mmp_intc_conf {
+	unsigned int	conf_enable;
+	unsigned int	conf_disable;
+	unsigned int	conf_mask;
+};
+
+void __iomem *mmp_icu_base;
+static struct icu_chip_data icu_data[MAX_ICU_NR];
+static int max_icu_nr;
+
+extern void mmp2_clear_pmic_int(void);
+
+static void icu_mask_ack_irq(struct irq_data *d)
+{
+	struct irq_domain *domain = d->domain;
+	struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+	int hwirq;
+	u32 r;
+
+	hwirq = d->irq - data->virq_base;
+	if (data == &icu_data[0]) {
+		r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+		r &= ~data->conf_mask;
+		r |= data->conf_disable;
+		writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+	} else {
+#ifdef CONFIG_CPU_MMP2
+		if ((data->virq_base == data->clr_mfp_irq_base)
+			&& (hwirq == data->clr_mfp_hwirq))
+			mmp2_clear_pmic_int();
+#endif
+		r = readl_relaxed(data->reg_mask) | (1 << hwirq);
+		writel_relaxed(r, data->reg_mask);
+	}
+}
+
+static void icu_mask_irq(struct irq_data *d)
+{
+	struct irq_domain *domain = d->domain;
+	struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+	int hwirq;
+	u32 r;
+
+	hwirq = d->irq - data->virq_base;
+	if (data == &icu_data[0]) {
+		r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+		r &= ~data->conf_mask;
+		r |= data->conf_disable;
+		writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+	} else {
+		r = readl_relaxed(data->reg_mask) | (1 << hwirq);
+		writel_relaxed(r, data->reg_mask);
+	}
+}
+
+static void icu_unmask_irq(struct irq_data *d)
+{
+	struct irq_domain *domain = d->domain;
+	struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+	int hwirq;
+	u32 r;
+
+	hwirq = d->irq - data->virq_base;
+	if (data == &icu_data[0]) {
+		r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+		r &= ~data->conf_mask;
+		r |= data->conf_enable;
+		writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+	} else {
+		r = readl_relaxed(data->reg_mask) & ~(1 << hwirq);
+		writel_relaxed(r, data->reg_mask);
+	}
+}
+
+static struct irq_chip icu_irq_chip = {
+	.name		= "icu_irq",
+	.irq_mask	= icu_mask_irq,
+	.irq_mask_ack	= icu_mask_ack_irq,
+	.irq_unmask	= icu_unmask_irq,
+};
+
+static void icu_mux_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+	struct irq_domain *domain;
+	struct icu_chip_data *data;
+	int i;
+	unsigned long mask, status, n;
+
+	for (i = 1; i < max_icu_nr; i++) {
+		if (irq == icu_data[i].cascade_irq) {
+			domain = icu_data[i].domain;
+			data = (struct icu_chip_data *)domain->host_data;
+			break;
+		}
+	}
+	if (i >= max_icu_nr) {
+		pr_err("Spurious irq %d in MMP INTC\n", irq);
+		return;
+	}
+
+	mask = readl_relaxed(data->reg_mask);
+	while (1) {
+		status = readl_relaxed(data->reg_status) & ~mask;
+		if (status == 0)
+			break;
+		n = find_first_bit(&status, BITS_PER_LONG);
+		while (n < BITS_PER_LONG) {
+			generic_handle_irq(icu_data[i].virq_base + n);
+			n = find_next_bit(&status, BITS_PER_LONG, n + 1);
+		}
+	}
+}
+
+static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
+			      irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
+	set_irq_flags(irq, IRQF_VALID);
+	return 0;
+}
+
+static int mmp_irq_domain_xlate(struct irq_domain *d, struct device_node *node,
+				const u32 *intspec, unsigned int intsize,
+				unsigned long *out_hwirq,
+				unsigned int *out_type)
+{
+	*out_hwirq = intspec[0];
+	return 0;
+}
+
+const struct irq_domain_ops mmp_irq_domain_ops = {
+	.map		= mmp_irq_domain_map,
+	.xlate		= mmp_irq_domain_xlate,
+};
+
+static struct mmp_intc_conf mmp_conf = {
+	.conf_enable	= 0x51,
+	.conf_disable	= 0x0,
+	.conf_mask	= 0x7f,
+};
+
+static struct mmp_intc_conf mmp2_conf = {
+	.conf_enable	= 0x20,
+	.conf_disable	= 0x0,
+	.conf_mask	= 0x7f,
+};
+
+/* MMP (ARMv5) */
+void __init icu_init_irq(void)
+{
+	int irq;
+
+	max_icu_nr = 1;
+	mmp_icu_base = ioremap(0xd4282000, 0x1000);
+	icu_data[0].conf_enable = mmp_conf.conf_enable;
+	icu_data[0].conf_disable = mmp_conf.conf_disable;
+	icu_data[0].conf_mask = mmp_conf.conf_mask;
+	icu_data[0].nr_irqs = 64;
+	icu_data[0].virq_base = 0;
+	icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
+						   &irq_domain_simple_ops,
+						   &icu_data[0]);
+	for (irq = 0; irq < 64; irq++) {
+		icu_mask_irq(irq_get_irq_data(irq));
+		irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
+		set_irq_flags(irq, IRQF_VALID);
+	}
+	irq_set_default_host(icu_data[0].domain);
+#ifdef CONFIG_CPU_PXA910
+	icu_irq_chip.irq_set_wake = pxa910_set_wake;
+#endif
+}
+
+/* MMP2 (ARMv7) */
+void __init mmp2_init_icu(void)
+{
+	int irq;
+
+	max_icu_nr = 8;
+	mmp_icu_base = ioremap(0xd4282000, 0x1000);
+	icu_data[0].conf_enable = mmp2_conf.conf_enable;
+	icu_data[0].conf_disable = mmp2_conf.conf_disable;
+	icu_data[0].conf_mask = mmp2_conf.conf_mask;
+	icu_data[0].nr_irqs = 64;
+	icu_data[0].virq_base = 0;
+	icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
+						   &irq_domain_simple_ops,
+						   &icu_data[0]);
+	icu_data[1].reg_status = mmp_icu_base + 0x150;
+	icu_data[1].reg_mask = mmp_icu_base + 0x168;
+	icu_data[1].clr_mfp_irq_base = IRQ_MMP2_PMIC_BASE;
+	icu_data[1].clr_mfp_hwirq = IRQ_MMP2_PMIC - IRQ_MMP2_PMIC_BASE;
+	icu_data[1].nr_irqs = 2;
+	icu_data[1].virq_base = IRQ_MMP2_PMIC_BASE;
+	icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs,
+						   icu_data[1].virq_base, 0,
+						   &irq_domain_simple_ops,
+						   &icu_data[1]);
+	icu_data[2].reg_status = mmp_icu_base + 0x154;
+	icu_data[2].reg_mask = mmp_icu_base + 0x16c;
+	icu_data[2].nr_irqs = 2;
+	icu_data[2].virq_base = IRQ_MMP2_RTC_BASE;
+	icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs,
+						   icu_data[2].virq_base, 0,
+						   &irq_domain_simple_ops,
+						   &icu_data[2]);
+	icu_data[3].reg_status = mmp_icu_base + 0x180;
+	icu_data[3].reg_mask = mmp_icu_base + 0x17c;
+	icu_data[3].nr_irqs = 3;
+	icu_data[3].virq_base = IRQ_MMP2_KEYPAD_BASE;
+	icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs,
+						   icu_data[3].virq_base, 0,
+						   &irq_domain_simple_ops,
+						   &icu_data[3]);
+	icu_data[4].reg_status = mmp_icu_base + 0x158;
+	icu_data[4].reg_mask = mmp_icu_base + 0x170;
+	icu_data[4].nr_irqs = 5;
+	icu_data[4].virq_base = IRQ_MMP2_TWSI_BASE;
+	icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs,
+						   icu_data[4].virq_base, 0,
+						   &irq_domain_simple_ops,
+						   &icu_data[4]);
+	icu_data[5].reg_status = mmp_icu_base + 0x15c;
+	icu_data[5].reg_mask = mmp_icu_base + 0x174;
+	icu_data[5].nr_irqs = 15;
+	icu_data[5].virq_base = IRQ_MMP2_MISC_BASE;
+	icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs,
+						   icu_data[5].virq_base, 0,
+						   &irq_domain_simple_ops,
+						   &icu_data[5]);
+	icu_data[6].reg_status = mmp_icu_base + 0x160;
+	icu_data[6].reg_mask = mmp_icu_base + 0x178;
+	icu_data[6].nr_irqs = 2;
+	icu_data[6].virq_base = IRQ_MMP2_MIPI_HSI1_BASE;
+	icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs,
+						   icu_data[6].virq_base, 0,
+						   &irq_domain_simple_ops,
+						   &icu_data[6]);
+	icu_data[7].reg_status = mmp_icu_base + 0x188;
+	icu_data[7].reg_mask = mmp_icu_base + 0x184;
+	icu_data[7].nr_irqs = 2;
+	icu_data[7].virq_base = IRQ_MMP2_MIPI_HSI0_BASE;
+	icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs,
+						   icu_data[7].virq_base, 0,
+						   &irq_domain_simple_ops,
+						   &icu_data[7]);
+	for (irq = 0; irq < IRQ_MMP2_MUX_END; irq++) {
+		icu_mask_irq(irq_get_irq_data(irq));
+		switch (irq) {
+		case IRQ_MMP2_PMIC_MUX:
+		case IRQ_MMP2_RTC_MUX:
+		case IRQ_MMP2_KEYPAD_MUX:
+		case IRQ_MMP2_TWSI_MUX:
+		case IRQ_MMP2_MISC_MUX:
+		case IRQ_MMP2_MIPI_HSI1_MUX:
+		case IRQ_MMP2_MIPI_HSI0_MUX:
+			irq_set_chip(irq, &icu_irq_chip);
+			irq_set_chained_handler(irq, icu_mux_irq_demux);
+			break;
+		default:
+			irq_set_chip_and_handler(irq, &icu_irq_chip,
+						 handle_level_irq);
+			break;
+		}
+		set_irq_flags(irq, IRQF_VALID);
+	}
+	irq_set_default_host(icu_data[0].domain);
+#ifdef CONFIG_CPU_MMP2
+	icu_irq_chip.irq_set_wake = mmp2_set_wake;
+#endif
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id intc_ids[] __initconst = {
+	{ .compatible = "mrvl,mmp-intc", .data = &mmp_conf },
+	{ .compatible = "mrvl,mmp2-intc", .data = &mmp2_conf },
+	{}
+};
+
+static const struct of_device_id mmp_mux_irq_match[] __initconst = {
+	{ .compatible = "mrvl,mmp2-mux-intc" },
+	{}
+};
+
+int __init mmp2_mux_init(struct device_node *parent)
+{
+	struct device_node *node;
+	const struct of_device_id *of_id;
+	struct resource res;
+	int i, irq_base, ret, irq;
+	u32 nr_irqs, mfp_irq;
+
+	node = parent;
+	max_icu_nr = 1;
+	for (i = 1; i < MAX_ICU_NR; i++) {
+		node = of_find_matching_node(node, mmp_mux_irq_match);
+		if (!node)
+			break;
+		of_id = of_match_node(&mmp_mux_irq_match[0], node);
+		ret = of_property_read_u32(node, "mrvl,intc-nr-irqs",
+					   &nr_irqs);
+		if (ret) {
+			pr_err("Not found mrvl,intc-nr-irqs property\n");
+			ret = -EINVAL;
+			goto err;
+		}
+		ret = of_address_to_resource(node, 0, &res);
+		if (ret < 0) {
+			pr_err("Not found reg property\n");
+			ret = -EINVAL;
+			goto err;
+		}
+		icu_data[i].reg_status = mmp_icu_base + res.start;
+		ret = of_address_to_resource(node, 1, &res);
+		if (ret < 0) {
+			pr_err("Not found reg property\n");
+			ret = -EINVAL;
+			goto err;
+		}
+		icu_data[i].reg_mask = mmp_icu_base + res.start;
+		icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
+		if (!icu_data[i].cascade_irq) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+		if (irq_base < 0) {
+			pr_err("Failed to allocate IRQ numbers for mux intc\n");
+			ret = irq_base;
+			goto err;
+		}
+		if (!of_property_read_u32(node, "mrvl,clr-mfp-irq",
+					  &mfp_irq)) {
+			icu_data[i].clr_mfp_irq_base = irq_base;
+			icu_data[i].clr_mfp_hwirq = mfp_irq;
+		}
+		irq_set_chained_handler(icu_data[i].cascade_irq,
+					icu_mux_irq_demux);
+		icu_data[i].nr_irqs = nr_irqs;
+		icu_data[i].virq_base = irq_base;
+		icu_data[i].domain = irq_domain_add_legacy(node, nr_irqs,
+							   irq_base, 0,
+							   &mmp_irq_domain_ops,
+							   &icu_data[i]);
+		for (irq = irq_base; irq < irq_base + nr_irqs; irq++)
+			icu_mask_irq(irq_get_irq_data(irq));
+	}
+	max_icu_nr = i;
+	return 0;
+err:
+	of_node_put(node);
+	max_icu_nr = i;
+	return ret;
+}
+
+void __init mmp_dt_irq_init(void)
+{
+	struct device_node *node;
+	const struct of_device_id *of_id;
+	struct mmp_intc_conf *conf;
+	int nr_irqs, irq_base, ret, irq;
+
+	node = of_find_matching_node(NULL, intc_ids);
+	if (!node) {
+		pr_err("Failed to find interrupt controller in arch-mmp\n");
+		return;
+	}
+	of_id = of_match_node(intc_ids, node);
+	conf = of_id->data;
+
+	ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs);
+	if (ret) {
+		pr_err("Not found mrvl,intc-nr-irqs property\n");
+		return;
+	}
+
+	mmp_icu_base = of_iomap(node, 0);
+	if (!mmp_icu_base) {
+		pr_err("Failed to get interrupt controller register\n");
+		return;
+	}
+
+	irq_base = irq_alloc_descs(-1, 0, nr_irqs - NR_IRQS_LEGACY, 0);
+	if (irq_base < 0) {
+		pr_err("Failed to allocate IRQ numbers\n");
+		goto err;
+	} else if (irq_base != NR_IRQS_LEGACY) {
+		pr_err("ICU's irqbase should be started from 0\n");
+		goto err;
+	}
+	icu_data[0].conf_enable = conf->conf_enable;
+	icu_data[0].conf_disable = conf->conf_disable;
+	icu_data[0].conf_mask = conf->conf_mask;
+	icu_data[0].nr_irqs = nr_irqs;
+	icu_data[0].virq_base = 0;
+	icu_data[0].domain = irq_domain_add_legacy(node, nr_irqs, 0, 0,
+						   &mmp_irq_domain_ops,
+						   &icu_data[0]);
+	irq_set_default_host(icu_data[0].domain);
+	for (irq = 0; irq < nr_irqs; irq++)
+		icu_mask_irq(irq_get_irq_data(irq));
+	mmp2_mux_init(node);
+	return;
+err:
+	iounmap(mmp_icu_base);
+}
+#endif
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index 6707539..033cc31 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -14,14 +14,19 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
 #include <mach/irqs.h>
 
 #include "common.h"
 
-extern struct sys_timer pxa168_timer;
-extern void __init icu_init_irq(void);
+extern void __init mmp_dt_irq_init(void);
+extern void __init mmp_dt_init_timer(void);
 
-static const struct of_dev_auxdata mmp_auxdata_lookup[] __initconst = {
+static struct sys_timer mmp_dt_timer = {
+	.init	= mmp_dt_init_timer,
+};
+
+static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = {
 	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
 	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
 	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4026000, "pxa2xx-uart.2", NULL),
@@ -32,44 +37,47 @@
 	{}
 };
 
-static int __init mmp_intc_add_irq_domain(struct device_node *np,
-					   struct device_node *parent)
-{
-	irq_domain_add_simple(np, 0);
-	return 0;
-}
-
-static int __init mmp_gpio_add_irq_domain(struct device_node *np,
-					   struct device_node *parent)
-{
-	irq_domain_add_simple(np, IRQ_GPIO_START);
-	return 0;
-}
-
-static const struct of_device_id mmp_irq_match[] __initconst = {
-	{ .compatible = "mrvl,mmp-intc", .data = mmp_intc_add_irq_domain, },
-	{ .compatible = "mrvl,mmp-gpio", .data = mmp_gpio_add_irq_domain, },
+static const struct of_dev_auxdata pxa910_auxdata_lookup[] __initconst = {
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4036000, "pxa2xx-uart.2", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4037000, "pxa2xx-i2c.1", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
 	{}
 };
 
-static void __init mmp_dt_init(void)
+static void __init pxa168_dt_init(void)
 {
-
-	of_irq_init(mmp_irq_match);
-
 	of_platform_populate(NULL, of_default_bus_match_table,
-			     mmp_auxdata_lookup, NULL);
+			     pxa168_auxdata_lookup, NULL);
 }
 
-static const char *pxa168_dt_board_compat[] __initdata = {
+static void __init pxa910_dt_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+			     pxa910_auxdata_lookup, NULL);
+}
+
+static const char *mmp_dt_board_compat[] __initdata = {
 	"mrvl,pxa168-aspenite",
+	"mrvl,pxa910-dkb",
 	NULL,
 };
 
 DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
 	.map_io		= mmp_map_io,
-	.init_irq	= icu_init_irq,
-	.timer		= &pxa168_timer,
-	.init_machine	= mmp_dt_init,
-	.dt_compat	= pxa168_dt_board_compat,
+	.init_irq	= mmp_dt_irq_init,
+	.timer		= &mmp_dt_timer,
+	.init_machine	= pxa168_dt_init,
+	.dt_compat	= mmp_dt_board_compat,
+MACHINE_END
+
+DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)")
+	.map_io		= mmp_map_io,
+	.init_irq	= mmp_dt_irq_init,
+	.timer		= &mmp_dt_timer,
+	.init_machine	= pxa910_dt_init,
+	.dt_compat	= mmp_dt_board_compat,
 MACHINE_END
diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c
new file mode 100644
index 0000000..535a5ed
--- /dev/null
+++ b/arch/arm/mach-mmp/mmp2-dt.c
@@ -0,0 +1,60 @@
+/*
+ *  linux/arch/arm/mach-mmp/mmp2-dt.c
+ *
+ *  Copyright (C) 2012 Marvell Technology Group 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
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/irqs.h>
+#include <mach/regs-apbc.h>
+
+#include "common.h"
+
+extern void __init mmp_dt_irq_init(void);
+extern void __init mmp_dt_init_timer(void);
+
+static struct sys_timer mmp_dt_timer = {
+	.init	= mmp_dt_init_timer,
+};
+
+static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = {
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4030000, "pxa2xx-uart.0", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.1", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.2", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4016000, "pxa2xx-uart.3", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
+	{}
+};
+
+static void __init mmp2_dt_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+			     mmp2_auxdata_lookup, NULL);
+}
+
+static const char *mmp2_dt_board_compat[] __initdata = {
+	"mrvl,mmp2-brownstone",
+	NULL,
+};
+
+DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
+	.map_io		= mmp_map_io,
+	.init_irq	= mmp_dt_irq_init,
+	.timer		= &mmp_dt_timer,
+	.init_machine	= mmp2_dt_init,
+	.dt_compat	= mmp2_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-mmp/pm-mmp2.c b/arch/arm/mach-mmp/pm-mmp2.c
new file mode 100644
index 0000000..461a191
--- /dev/null
+++ b/arch/arm/mach-mmp/pm-mmp2.c
@@ -0,0 +1,264 @@
+/*
+ * MMP2 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2012 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/cputype.h>
+#include <mach/addr-map.h>
+#include <mach/pm-mmp2.h>
+#include <mach/regs-icu.h>
+#include <mach/irqs.h>
+
+int mmp2_set_wake(struct irq_data *d, unsigned int on)
+{
+	int irq = d->irq;
+	struct irq_desc *desc = irq_to_desc(irq);
+	unsigned long data = 0;
+
+	if (unlikely(irq >= nr_irqs)) {
+		pr_err("IRQ nubmers are out of boundary!\n");
+		return -EINVAL;
+	}
+
+	if (on) {
+		if (desc->action)
+			desc->action->flags |= IRQF_NO_SUSPEND;
+	} else {
+		if (desc->action)
+			desc->action->flags &= ~IRQF_NO_SUSPEND;
+	}
+
+	/* enable wakeup sources */
+	switch (irq) {
+	case IRQ_MMP2_RTC:
+	case IRQ_MMP2_RTC_ALARM:
+		data = MPMU_WUCRM_PJ_WAKEUP(4) | MPMU_WUCRM_PJ_RTC_ALARM;
+		break;
+	case IRQ_MMP2_PMIC:
+		data = MPMU_WUCRM_PJ_WAKEUP(7);
+		break;
+	case IRQ_MMP2_MMC2:
+		/* mmc use WAKEUP2, same as GPIO wakeup source */
+		data = MPMU_WUCRM_PJ_WAKEUP(2);
+		break;
+	}
+	if (on) {
+		if (data) {
+			data |= __raw_readl(MPMU_WUCRM_PJ);
+			__raw_writel(data, MPMU_WUCRM_PJ);
+		}
+	} else {
+		if (data) {
+			data = ~data & __raw_readl(MPMU_WUCRM_PJ);
+			__raw_writel(data, MPMU_WUCRM_PJ);
+		}
+	}
+	return 0;
+}
+
+static void pm_scu_clk_disable(void)
+{
+	unsigned int val;
+
+	/* close AXI fabric clock gate */
+	__raw_writel(0x0, CIU_REG(0x64));
+	__raw_writel(0x0, CIU_REG(0x68));
+
+	/* close MCB master clock gate */
+	val = __raw_readl(CIU_REG(0x1c));
+	val |= 0xf0;
+	__raw_writel(val, CIU_REG(0x1c));
+
+	return ;
+}
+
+static void pm_scu_clk_enable(void)
+{
+	unsigned int val;
+
+	/* open AXI fabric clock gate */
+	__raw_writel(0x03003003, CIU_REG(0x64));
+	__raw_writel(0x00303030, CIU_REG(0x68));
+
+	/* open MCB master clock gate */
+	val = __raw_readl(CIU_REG(0x1c));
+	val &= ~(0xf0);
+	__raw_writel(val, CIU_REG(0x1c));
+
+	return ;
+}
+
+static void pm_mpmu_clk_disable(void)
+{
+	/*
+	 * disable clocks in MPMU_CGR_PJ register
+	 * except clock for APMU_PLL1, APMU_PLL1_2 and AP_26M
+	 */
+	__raw_writel(0x0000a010, MPMU_CGR_PJ);
+}
+
+static void pm_mpmu_clk_enable(void)
+{
+	unsigned int val;
+
+	__raw_writel(0xdffefffe, MPMU_CGR_PJ);
+	val = __raw_readl(MPMU_PLL2_CTRL1);
+	val |= (1 << 29);
+	__raw_writel(val, MPMU_PLL2_CTRL1);
+
+	return ;
+}
+
+void mmp2_pm_enter_lowpower_mode(int state)
+{
+	uint32_t idle_cfg, apcr;
+
+	idle_cfg = __raw_readl(APMU_PJ_IDLE_CFG);
+	apcr = __raw_readl(MPMU_PCR_PJ);
+	apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD | MPMU_PCR_PJ_APBSD
+		 | MPMU_PCR_PJ_AXISD | MPMU_PCR_PJ_VCTCXOSD | (1 << 13));
+	idle_cfg &= ~APMU_PJ_IDLE_CFG_PJ_IDLE;
+
+	switch (state) {
+	case POWER_MODE_SYS_SLEEP:
+		apcr |= MPMU_PCR_PJ_SLPEN;		/* set the SLPEN bit */
+		apcr |= MPMU_PCR_PJ_VCTCXOSD;		/* set VCTCXOSD */
+		/* fall through */
+	case POWER_MODE_CHIP_SLEEP:
+		apcr |= MPMU_PCR_PJ_SLPEN;
+		/* fall through */
+	case POWER_MODE_APPS_SLEEP:
+		apcr |= MPMU_PCR_PJ_APBSD;		/* set APBSD */
+		/* fall through */
+	case POWER_MODE_APPS_IDLE:
+		apcr |= MPMU_PCR_PJ_AXISD;		/* set AXISDD bit */
+		apcr |= MPMU_PCR_PJ_DDRCORSD;		/* set DDRCORSD bit */
+		idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN;	/* PJ power down */
+		apcr |= MPMU_PCR_PJ_SPSD;
+		/* fall through */
+	case POWER_MODE_CORE_EXTIDLE:
+		idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE;	/* set the IDLE bit */
+		idle_cfg &= ~APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK;
+		idle_cfg |= APMU_PJ_IDLE_CFG_PWR_SW(3)
+			| APMU_PJ_IDLE_CFG_L2_PWR_SW;
+		break;
+	case POWER_MODE_CORE_INTIDLE:
+		apcr &= ~MPMU_PCR_PJ_SPSD;
+		break;
+	}
+
+	/* set reserve bits */
+	apcr |= (1 << 30) | (1 << 25);
+
+	/* finally write the registers back */
+	__raw_writel(idle_cfg, APMU_PJ_IDLE_CFG);
+	__raw_writel(apcr, MPMU_PCR_PJ);	/* 0xfe086000 */
+}
+
+static int mmp2_pm_enter(suspend_state_t state)
+{
+	int temp;
+
+	temp = __raw_readl(MMP2_ICU_INT4_MASK);
+	if (temp & (1 << 1)) {
+		printk(KERN_ERR "%s: PMIC interrupt is handling\n", __func__);
+		return -EAGAIN;
+	}
+
+	temp = __raw_readl(APMU_SRAM_PWR_DWN);
+	temp |= ((1 << 19) | (1 << 18));
+	__raw_writel(temp, APMU_SRAM_PWR_DWN);
+	pm_mpmu_clk_disable();
+	pm_scu_clk_disable();
+
+	printk(KERN_INFO "%s: before suspend\n", __func__);
+	cpu_do_idle();
+	printk(KERN_INFO "%s: after suspend\n", __func__);
+
+	pm_mpmu_clk_enable();		/* enable clocks in MPMU */
+	pm_scu_clk_enable();		/* enable clocks in SCU */
+
+	return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int mmp2_pm_prepare(void)
+{
+	mmp2_pm_enter_lowpower_mode(POWER_MODE_SYS_SLEEP);
+
+	return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static void mmp2_pm_finish(void)
+{
+	mmp2_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
+}
+
+static int mmp2_pm_valid(suspend_state_t state)
+{
+	return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
+}
+
+/*
+ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
+ */
+static const struct platform_suspend_ops mmp2_pm_ops = {
+	.valid		= mmp2_pm_valid,
+	.prepare	= mmp2_pm_prepare,
+	.enter		= mmp2_pm_enter,
+	.finish		= mmp2_pm_finish,
+};
+
+static int __init mmp2_pm_init(void)
+{
+	uint32_t apcr;
+
+	if (!cpu_is_mmp2())
+		return -EIO;
+
+	suspend_set_ops(&mmp2_pm_ops);
+
+	/*
+	 * Set bit 0, Slow clock Select 32K clock input instead of VCXO
+	 * VCXO is chosen by default, which would be disabled in suspend
+	 */
+	__raw_writel(0x5, MPMU_SCCR);
+
+	/*
+	 * Clear bit 23 of CIU_CPU_CONF
+	 * direct PJ4 to DDR access through Memory Controller slow queue
+	 * fast queue has issue and cause lcd will flick
+	 */
+	__raw_writel(__raw_readl(CIU_REG(0x8)) & ~(0x1 << 23), CIU_REG(0x8));
+
+	/* Clear default low power control bit */
+	apcr = __raw_readl(MPMU_PCR_PJ);
+	apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD
+			| MPMU_PCR_PJ_APBSD | MPMU_PCR_PJ_AXISD | 1 << 13);
+	__raw_writel(apcr, MPMU_PCR_PJ);
+
+	return 0;
+}
+
+late_initcall(mmp2_pm_init);
diff --git a/arch/arm/mach-mmp/pm-pxa910.c b/arch/arm/mach-mmp/pm-pxa910.c
new file mode 100644
index 0000000..48981ca
--- /dev/null
+++ b/arch/arm/mach-mmp/pm-pxa910.c
@@ -0,0 +1,285 @@
+/*
+ * PXA910 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2009 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/cputype.h>
+#include <mach/addr-map.h>
+#include <mach/pm-pxa910.h>
+#include <mach/regs-icu.h>
+#include <mach/irqs.h>
+
+int pxa910_set_wake(struct irq_data *data, unsigned int on)
+{
+	int irq = data->irq;
+	struct irq_desc *desc = irq_to_desc(data->irq);
+	uint32_t awucrm = 0, apcr = 0;
+
+	if (unlikely(irq >= nr_irqs)) {
+		pr_err("IRQ nubmers are out of boundary!\n");
+		return -EINVAL;
+	}
+
+	if (on) {
+		if (desc->action)
+			desc->action->flags |= IRQF_NO_SUSPEND;
+	} else {
+		if (desc->action)
+			desc->action->flags &= ~IRQF_NO_SUSPEND;
+	}
+
+	/* setting wakeup sources */
+	switch (irq) {
+	/* wakeup line 2 */
+	case IRQ_PXA910_AP_GPIO:
+		awucrm = MPMU_AWUCRM_WAKEUP(2);
+		apcr |= MPMU_APCR_SLPWP2;
+		break;
+	/* wakeup line 3 */
+	case IRQ_PXA910_KEYPAD:
+		awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_KEYPRESS;
+		apcr |= MPMU_APCR_SLPWP3;
+		break;
+	case IRQ_PXA910_ROTARY:
+		awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_NEWROTARY;
+		apcr |= MPMU_APCR_SLPWP3;
+		break;
+	case IRQ_PXA910_TRACKBALL:
+		awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_TRACKBALL;
+		apcr |= MPMU_APCR_SLPWP3;
+		break;
+	/* wakeup line 4 */
+	case IRQ_PXA910_AP1_TIMER1:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_1;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP1_TIMER2:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_2;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP1_TIMER3:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_3;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP2_TIMER1:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_1;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP2_TIMER2:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_2;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP2_TIMER3:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_3;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_RTC_ALARM:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_RTC_ALARM;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	/* wakeup line 5 */
+	case IRQ_PXA910_USB1:
+	case IRQ_PXA910_USB2:
+		awucrm = MPMU_AWUCRM_WAKEUP(5);
+		apcr |= MPMU_APCR_SLPWP5;
+		break;
+	/* wakeup line 6 */
+	case IRQ_PXA910_MMC:
+		awucrm = MPMU_AWUCRM_WAKEUP(6)
+			| MPMU_AWUCRM_SDH1
+			| MPMU_AWUCRM_SDH2;
+		apcr |= MPMU_APCR_SLPWP6;
+		break;
+	/* wakeup line 7 */
+	case IRQ_PXA910_PMIC_INT:
+		awucrm = MPMU_AWUCRM_WAKEUP(7);
+		apcr |= MPMU_APCR_SLPWP7;
+		break;
+	default:
+		if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
+			awucrm = MPMU_AWUCRM_WAKEUP(2);
+			apcr |= MPMU_APCR_SLPWP2;
+		} else
+			printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
+				irq);
+	}
+
+	if (on) {
+		if (awucrm) {
+			awucrm |= __raw_readl(MPMU_AWUCRM);
+			__raw_writel(awucrm, MPMU_AWUCRM);
+		}
+		if (apcr) {
+			apcr = ~apcr & __raw_readl(MPMU_APCR);
+			__raw_writel(apcr, MPMU_APCR);
+		}
+	} else {
+		if (awucrm) {
+			awucrm = ~awucrm & __raw_readl(MPMU_AWUCRM);
+			__raw_writel(awucrm, MPMU_AWUCRM);
+		}
+		if (apcr) {
+			apcr |= __raw_readl(MPMU_APCR);
+			__raw_writel(apcr, MPMU_APCR);
+		}
+	}
+	return 0;
+}
+
+void pxa910_pm_enter_lowpower_mode(int state)
+{
+	uint32_t idle_cfg, apcr;
+
+	idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
+	apcr = __raw_readl(MPMU_APCR);
+
+	apcr &= ~(MPMU_APCR_DDRCORSD | MPMU_APCR_APBSD | MPMU_APCR_AXISD
+		| MPMU_APCR_VCTCXOSD | MPMU_APCR_STBYEN);
+	idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_IDLE
+		| APMU_MOH_IDLE_CFG_MOH_PWRDWN);
+
+	switch (state) {
+	case POWER_MODE_UDR:
+		/* only shutdown APB in UDR */
+		apcr |= MPMU_APCR_STBYEN | MPMU_APCR_APBSD;
+		/* fall through */
+	case POWER_MODE_SYS_SLEEP:
+		apcr |= MPMU_APCR_SLPEN;		/* set the SLPEN bit */
+		apcr |= MPMU_APCR_VCTCXOSD;		/* set VCTCXOSD */
+		/* fall through */
+	case POWER_MODE_APPS_SLEEP:
+		apcr |= MPMU_APCR_DDRCORSD;		/* set DDRCORSD */
+		/* fall through */
+	case POWER_MODE_APPS_IDLE:
+		apcr |= MPMU_APCR_AXISD;		/* set AXISDD bit */
+		/* fall through */
+	case POWER_MODE_CORE_EXTIDLE:
+		idle_cfg |= APMU_MOH_IDLE_CFG_MOH_IDLE;
+		idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN;
+		idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWR_SW(3)
+			| APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(3);
+		/* fall through */
+	case POWER_MODE_CORE_INTIDLE:
+		break;
+	}
+
+	/* program the memory controller hardware sleep type and auto wakeup */
+	idle_cfg |= APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ;
+	idle_cfg |= APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN;
+	__raw_writel(0x0, APMU_MC_HW_SLP_TYPE);		/* auto refresh */
+
+	/* set DSPSD, DTCMSD, BBSD, MSASLPEN */
+	apcr |= MPMU_APCR_DSPSD | MPMU_APCR_DTCMSD | MPMU_APCR_BBSD
+		| MPMU_APCR_MSASLPEN;
+
+	/*always set SLEPEN bit mainly for MSA*/
+	apcr |= MPMU_APCR_SLPEN;
+
+	/* finally write the registers back */
+	__raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
+	__raw_writel(apcr, MPMU_APCR);
+
+}
+
+static int pxa910_pm_enter(suspend_state_t state)
+{
+	unsigned int idle_cfg, reg = 0;
+
+	/*pmic thread not completed,exit;otherwise system can't be waked up*/
+	reg = __raw_readl(ICU_INT_CONF(IRQ_PXA910_PMIC_INT));
+	if ((reg & 0x3) == 0)
+		return -EAGAIN;
+
+	idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
+	idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN
+		| APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN;
+	__raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
+
+	/* disable L2 */
+	outer_disable();
+	/* wait for l2 idle */
+	while (!(readl(CIU_REG(0x8)) & (1 << 16)))
+		udelay(1);
+
+	cpu_do_idle();
+
+	/* enable L2 */
+	outer_resume();
+	/* wait for l2 idle */
+	while (!(readl(CIU_REG(0x8)) & (1 << 16)))
+		udelay(1);
+
+	idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
+	idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_PWRDWN
+		| APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN);
+	__raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
+
+	return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int pxa910_pm_prepare(void)
+{
+	pxa910_pm_enter_lowpower_mode(POWER_MODE_UDR);
+	return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static void pxa910_pm_finish(void)
+{
+	pxa910_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
+}
+
+static int pxa910_pm_valid(suspend_state_t state)
+{
+	return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
+}
+
+static const struct platform_suspend_ops pxa910_pm_ops = {
+	.valid		= pxa910_pm_valid,
+	.prepare	= pxa910_pm_prepare,
+	.enter		= pxa910_pm_enter,
+	.finish		= pxa910_pm_finish,
+};
+
+static int __init pxa910_pm_init(void)
+{
+	uint32_t awucrm = 0;
+
+	if (!cpu_is_pxa910())
+		return -EIO;
+
+	suspend_set_ops(&pxa910_pm_ops);
+
+	/* Set the following bits for MMP3 playback with VCTXO on */
+	__raw_writel(__raw_readl(APMU_SQU_CLK_GATE_CTRL) | (1 << 30),
+		APMU_SQU_CLK_GATE_CTRL);
+	__raw_writel(__raw_readl(MPMU_FCCR) | (1 << 28), MPMU_FCCR);
+
+	awucrm |= MPMU_AWUCRM_AP_ASYNC_INT | MPMU_AWUCRM_AP_FULL_IDLE;
+	__raw_writel(awucrm, MPMU_AWUCRM);
+
+	return 0;
+}
+
+late_initcall(pxa910_pm_init);
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index b24d2c3..62d787c 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/platform_data/mv_usb.h>
 
 #include <asm/mach/time.h>
 #include <asm/system_misc.h>
@@ -27,6 +28,7 @@
 #include <mach/mfp.h>
 #include <linux/dma-mapping.h>
 #include <mach/pxa168.h>
+#include <mach/regs-usb.h>
 
 #include "common.h"
 #include "clock.h"
@@ -93,7 +95,7 @@
 	INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
 	INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
 	INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
-	INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"),
+	INIT_CLKREG(&clk_usb, NULL, "PXA168-USBCLK"),
 	INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
 };
 
@@ -184,17 +186,17 @@
 struct resource pxa168_usb_host_resources[] = {
 	/* USB Host conroller register base */
 	[0] = {
-		.start	= 0xd4209000,
-		.end	= 0xd4209000 + 0x200,
+		.start	= PXA168_U2H_REGBASE + U2x_CAPREGS_OFFSET,
+		.end	= PXA168_U2H_REGBASE + USB_REG_RANGE,
 		.flags	= IORESOURCE_MEM,
-		.name	= "pxa168-usb-host",
+		.name	= "capregs",
 	},
 	/* USB PHY register base */
 	[1] = {
-		.start	= 0xd4206000,
-		.end	= 0xd4206000 + 0xff,
+		.start	= PXA168_U2H_PHYBASE,
+		.end	= PXA168_U2H_PHYBASE + USB_PHY_RANGE,
 		.flags	= IORESOURCE_MEM,
-		.name	= "pxa168-usb-phy",
+		.name	= "phyregs",
 	},
 	[2] = {
 		.start	= IRQ_PXA168_USB2,
@@ -205,7 +207,7 @@
 
 static u64 pxa168_usb_host_dmamask = DMA_BIT_MASK(32);
 struct platform_device pxa168_device_usb_host = {
-	.name = "pxa168-ehci",
+	.name = "pxa-sph",
 	.id   = -1,
 	.dev  = {
 		.dma_mask = &pxa168_usb_host_dmamask,
@@ -216,7 +218,7 @@
 	.resource      = pxa168_usb_host_resources,
 };
 
-int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata)
+int __init pxa168_add_usb_host(struct mv_usb_platform_data *pdata)
 {
 	pxa168_device_usb_host.dev.platform_data = pdata;
 	return platform_device_register(&pxa168_device_usb_host);
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 43f8bcc..6da52e9 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -109,7 +109,7 @@
 	INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL),
 	INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
 	INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
-	INIT_CLKREG(&clk_u2o, "pxa-u2o", "U2OCLK"),
+	INIT_CLKREG(&clk_u2o, NULL, "U2OCLK"),
 	INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
 };
 
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 71fc4ee..936447c 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -25,6 +25,9 @@
 
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <asm/sched_clock.h>
 #include <mach/addr-map.h>
@@ -41,6 +44,8 @@
 #define MAX_DELTA		(0xfffffffe)
 #define MIN_DELTA		(16)
 
+static void __iomem *mmp_timer_base = TIMERS_VIRT_BASE;
+
 /*
  * FIXME: the timer needs some delay to stablize the counter capture
  */
@@ -48,12 +53,12 @@
 {
 	int delay = 100;
 
-	__raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(1));
+	__raw_writel(1, mmp_timer_base + TMR_CVWR(1));
 
 	while (delay--)
 		cpu_relax();
 
-	return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(1));
+	return __raw_readl(mmp_timer_base + TMR_CVWR(1));
 }
 
 static u32 notrace mmp_read_sched_clock(void)
@@ -68,12 +73,12 @@
 	/*
 	 * Clear pending interrupt status.
 	 */
-	__raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
+	__raw_writel(0x01, mmp_timer_base + TMR_ICR(0));
 
 	/*
 	 * Disable timer 0.
 	 */
-	__raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+	__raw_writel(0x02, mmp_timer_base + TMR_CER);
 
 	c->event_handler(c);
 
@@ -90,23 +95,23 @@
 	/*
 	 * Disable timer 0.
 	 */
-	__raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+	__raw_writel(0x02, mmp_timer_base + TMR_CER);
 
 	/*
 	 * Clear and enable timer match 0 interrupt.
 	 */
-	__raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
-	__raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0));
+	__raw_writel(0x01, mmp_timer_base + TMR_ICR(0));
+	__raw_writel(0x01, mmp_timer_base + TMR_IER(0));
 
 	/*
 	 * Setup new clockevent timer value.
 	 */
-	__raw_writel(delta - 1, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0));
+	__raw_writel(delta - 1, mmp_timer_base + TMR_TN_MM(0, 0));
 
 	/*
 	 * Enable timer 0.
 	 */
-	__raw_writel(0x03, TIMERS_VIRT_BASE + TMR_CER);
+	__raw_writel(0x03, mmp_timer_base + TMR_CER);
 
 	local_irq_restore(flags);
 
@@ -124,7 +129,7 @@
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
 		/* disable the matching interrupt */
-		__raw_writel(0x00, TIMERS_VIRT_BASE + TMR_IER(0));
+		__raw_writel(0x00, mmp_timer_base + TMR_IER(0));
 		break;
 	case CLOCK_EVT_MODE_RESUME:
 	case CLOCK_EVT_MODE_PERIODIC:
@@ -157,27 +162,27 @@
 
 static void __init timer_config(void)
 {
-	uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR);
+	uint32_t ccr = __raw_readl(mmp_timer_base + TMR_CCR);
 
-	__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_CER); /* disable */
+	__raw_writel(0x0, mmp_timer_base + TMR_CER); /* disable */
 
 	ccr &= (cpu_is_mmp2()) ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
 		(TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3));
-	__raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR);
+	__raw_writel(ccr, mmp_timer_base + TMR_CCR);
 
 	/* set timer 0 to periodic mode, and timer 1 to free-running mode */
-	__raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CMR);
+	__raw_writel(0x2, mmp_timer_base + TMR_CMR);
 
-	__raw_writel(0x1, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* periodic */
-	__raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0));  /* clear status */
-	__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
+	__raw_writel(0x1, mmp_timer_base + TMR_PLCR(0)); /* periodic */
+	__raw_writel(0x7, mmp_timer_base + TMR_ICR(0));  /* clear status */
+	__raw_writel(0x0, mmp_timer_base + TMR_IER(0));
 
-	__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(1)); /* free-running */
-	__raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(1));  /* clear status */
-	__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(1));
+	__raw_writel(0x0, mmp_timer_base + TMR_PLCR(1)); /* free-running */
+	__raw_writel(0x7, mmp_timer_base + TMR_ICR(1));  /* clear status */
+	__raw_writel(0x0, mmp_timer_base + TMR_IER(1));
 
 	/* enable timer 1 counter */
-	__raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CER);
+	__raw_writel(0x2, mmp_timer_base + TMR_CER);
 }
 
 static struct irqaction timer_irq = {
@@ -203,3 +208,37 @@
 	clocksource_register_hz(&cksrc, CLOCK_TICK_RATE);
 	clockevents_register_device(&ckevt);
 }
+
+#ifdef CONFIG_OF
+static struct of_device_id mmp_timer_dt_ids[] = {
+	{ .compatible = "mrvl,mmp-timer", },
+	{}
+};
+
+void __init mmp_dt_init_timer(void)
+{
+	struct device_node *np;
+	int irq, ret;
+
+	np = of_find_matching_node(NULL, mmp_timer_dt_ids);
+	if (!np) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq) {
+		ret = -EINVAL;
+		goto out;
+	}
+	mmp_timer_base = of_iomap(np, 0);
+	if (!mmp_timer_base) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	timer_init(irq);
+	return;
+out:
+	pr_err("Failed to get timer from device tree with error:%d\n", ret);
+}
+#endif
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index 3fc9ed2..7a7de2b 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -17,6 +17,8 @@
 #include <linux/interrupt.h>
 #include <linux/i2c/pca953x.h>
 #include <linux/gpio.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/platform_data/mv_usb.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -25,6 +27,7 @@
 #include <mach/mfp-pxa910.h>
 #include <mach/pxa910.h>
 #include <mach/irqs.h>
+#include <mach/regs-usb.h>
 
 #include "common.h"
 
@@ -135,8 +138,18 @@
 	},
 };
 
+static struct pm860x_platform_data ttc_dkb_pm8607_info = {
+	.irq_base       = IRQ_BOARD_START,
+};
+
 static struct i2c_board_info ttc_dkb_i2c_info[] = {
 	{
+		.type           = "88PM860x",
+		.addr           = 0x34,
+		.platform_data  = &ttc_dkb_pm8607_info,
+		.irq            = IRQ_PXA910_PMIC_INT,
+	},
+	{
 		.type		= "max7312",
 		.addr		= 0x23,
 		.irq		= MMP_GPIO_TO_IRQ(80),
@@ -144,6 +157,26 @@
 	},
 };
 
+#ifdef CONFIG_USB_SUPPORT
+#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O)
+
+static char *pxa910_usb_clock_name[] = {
+	[0] = "U2OCLK",
+};
+
+static struct mv_usb_platform_data ttc_usb_pdata = {
+	.clknum		= 1,
+	.clkname	= pxa910_usb_clock_name,
+	.vbus		= NULL,
+	.mode		= MV_USB_MODE_OTG,
+	.otg_force_a_bus_req = 1,
+	.phy_init	= pxa_usb_phy_init,
+	.phy_deinit	= pxa_usb_phy_deinit,
+	.set_vbus	= NULL,
+};
+#endif
+#endif
+
 static void __init ttc_dkb_init(void)
 {
 	mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
@@ -154,6 +187,21 @@
 	/* off-chip devices */
 	pxa910_add_twsi(0, NULL, ARRAY_AND_SIZE(ttc_dkb_i2c_info));
 	platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices));
+
+#ifdef CONFIG_USB_MV_UDC
+	pxa168_device_u2o.dev.platform_data = &ttc_usb_pdata;
+	platform_device_register(&pxa168_device_u2o);
+#endif
+
+#ifdef CONFIG_USB_EHCI_MV_U2O
+	pxa168_device_u2oehci.dev.platform_data = &ttc_usb_pdata;
+	platform_device_register(&pxa168_device_u2oehci);
+#endif
+
+#ifdef CONFIG_USB_MV_OTG
+	pxa168_device_u2ootg.dev.platform_data = &ttc_usb_pdata;
+	platform_device_register(&pxa168_device_u2ootg);
+#endif
 }
 
 MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index db81ed53..75b3cfc 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -17,7 +17,6 @@
 #include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/irq.h>
-#include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/io.h>
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 7e8909c..fbaa4ed 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -17,7 +17,6 @@
 #include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/irq.h>
-#include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/usb/msm_hsusb.h>
diff --git a/arch/arm/mach-msm/include/mach/debug-macro.S b/arch/arm/mach-msm/include/mach/debug-macro.S
index 3ffd866..0e05f88 100644
--- a/arch/arm/mach-msm/include/mach/debug-macro.S
+++ b/arch/arm/mach-msm/include/mach/debug-macro.S
@@ -30,8 +30,7 @@
 	@ Write the 1 character to UARTDM_TF
 	str	\rd, [\rx, #0x70]
 #else
-	teq	\rx, #0
-	strne	\rd, [\rx, #0x0C]
+	str	\rd, [\rx, #0x0C]
 #endif
 	.endm
 
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index bafabb5..c536fd6 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -282,6 +282,9 @@
 			__asmeq("%1", "r1")
 			__asmeq("%2", "r0")
 			__asmeq("%3", "r1")
+#ifdef REQUIRES_SEC
+			".arch_extension sec\n"
+#endif
 			"smc	#0	@ switch to secure world\n"
 			: "=r" (r0), "=r" (r1)
 			: "r" (r0), "r" (r1)
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index c57f996..07d5383 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -9,11 +9,13 @@
 	bool
 	select CPU_ARM926T
 	select HAVE_PWM
+	select PINCTRL_IMX23
 
 config SOC_IMX28
 	bool
 	select CPU_ARM926T
 	select HAVE_PWM
+	select PINCTRL_IMX28
 
 comment "MXS platforms:"
 
diff --git a/arch/arm/mach-mxs/include/mach/common.h b/arch/arm/mach-mxs/include/mach/common.h
index c50c3ea..8d88399 100644
--- a/arch/arm/mach-mxs/include/mach/common.h
+++ b/arch/arm/mach-mxs/include/mach/common.h
@@ -19,11 +19,13 @@
 extern void mxs_restart(char, const char *);
 extern int mxs_saif_clkmux_select(unsigned int clkmux);
 
+extern void mx23_soc_init(void);
 extern int mx23_register_gpios(void);
 extern int mx23_clocks_init(void);
 extern void mx23_map_io(void);
 extern void mx23_init_irq(void);
 
+extern void mx28_soc_init(void);
 extern int mx28_register_gpios(void);
 extern int mx28_clocks_init(void);
 extern void mx28_map_io(void);
diff --git a/arch/arm/mach-mxs/mach-apx4devkit.c b/arch/arm/mach-mxs/mach-apx4devkit.c
index 48a7fab..5e90b9d 100644
--- a/arch/arm/mach-mxs/mach-apx4devkit.c
+++ b/arch/arm/mach-mxs/mach-apx4devkit.c
@@ -207,6 +207,8 @@
 
 static void __init apx4devkit_init(void)
 {
+	mx28_soc_init();
+
 	mxs_iomux_setup_multiple_pads(apx4devkit_pads,
 			ARRAY_SIZE(apx4devkit_pads));
 
diff --git a/arch/arm/mach-mxs/mach-m28evk.c b/arch/arm/mach-mxs/mach-m28evk.c
index 06d7996..4c00c87 100644
--- a/arch/arm/mach-mxs/mach-m28evk.c
+++ b/arch/arm/mach-mxs/mach-m28evk.c
@@ -319,6 +319,8 @@
 
 static void __init m28evk_init(void)
 {
+	mx28_soc_init();
+
 	mxs_iomux_setup_multiple_pads(m28evk_pads, ARRAY_SIZE(m28evk_pads));
 
 	mx28_add_duart();
diff --git a/arch/arm/mach-mxs/mach-mx23evk.c b/arch/arm/mach-mxs/mach-mx23evk.c
index 5ea1c57..e7272a4 100644
--- a/arch/arm/mach-mxs/mach-mx23evk.c
+++ b/arch/arm/mach-mxs/mach-mx23evk.c
@@ -141,6 +141,8 @@
 {
 	int ret;
 
+	mx23_soc_init();
+
 	mxs_iomux_setup_multiple_pads(mx23evk_pads, ARRAY_SIZE(mx23evk_pads));
 
 	mx23_add_duart();
diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index e386c14..da4610e 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -413,6 +413,8 @@
 {
 	int ret;
 
+	mx28_soc_init();
+
 	mxs_iomux_setup_multiple_pads(mx28evk_pads, ARRAY_SIZE(mx28evk_pads));
 
 	mx28_add_duart();
diff --git a/arch/arm/mach-mxs/mach-stmp378x_devb.c b/arch/arm/mach-mxs/mach-stmp378x_devb.c
index a626c07..6548965 100644
--- a/arch/arm/mach-mxs/mach-stmp378x_devb.c
+++ b/arch/arm/mach-mxs/mach-stmp378x_devb.c
@@ -85,6 +85,8 @@
 {
 	int ret;
 
+	mx23_soc_init();
+
 	mxs_iomux_setup_multiple_pads(stmp378x_dvb_pads,
 			ARRAY_SIZE(stmp378x_dvb_pads));
 
diff --git a/arch/arm/mach-mxs/mach-tx28.c b/arch/arm/mach-mxs/mach-tx28.c
index 2c0862e..8837029 100644
--- a/arch/arm/mach-mxs/mach-tx28.c
+++ b/arch/arm/mach-mxs/mach-tx28.c
@@ -146,6 +146,8 @@
 
 static void __init tx28_stk5v3_init(void)
 {
+	mx28_soc_init();
+
 	mxs_iomux_setup_multiple_pads(tx28_stk5v3_pads,
 			ARRAY_SIZE(tx28_stk5v3_pads));
 
diff --git a/arch/arm/mach-mxs/mm.c b/arch/arm/mach-mxs/mm.c
index 50af5ce..67a384e 100644
--- a/arch/arm/mach-mxs/mm.c
+++ b/arch/arm/mach-mxs/mm.c
@@ -13,6 +13,7 @@
 
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/pinctrl/machine.h>
 
 #include <asm/mach/map.h>
 
@@ -61,3 +62,13 @@
 {
 	icoll_init_irq();
 }
+
+void __init mx23_soc_init(void)
+{
+	pinctrl_provide_dummies();
+}
+
+void __init mx28_soc_init(void)
+{
+	pinctrl_provide_dummies();
+}
diff --git a/arch/arm/mach-nomadik/Kconfig b/arch/arm/mach-nomadik/Kconfig
index 3c5e0f5..365879b 100644
--- a/arch/arm/mach-nomadik/Kconfig
+++ b/arch/arm/mach-nomadik/Kconfig
@@ -15,6 +15,7 @@
 config I2C_BITBANG_8815NHK
 	tristate "Driver for bit-bang busses found on the 8815 NHK"
 	depends on I2C && MACH_NOMADIK_8815NHK
+	depends on PINCTRL_NOMADIK
 	select I2C_ALGOBIT
 	default y
 
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index dfab466..cba3f71 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -132,6 +132,7 @@
 
 config MACH_SX1
 	bool "Siemens SX1"
+	select I2C
 	depends on ARCH_OMAP1 && ARCH_OMAP15XX
 	help
 	  Support for the Siemens SX1 phone. To boot the kernel,
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 9923f92..398e9e5 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -12,6 +12,9 @@
 
 obj-$(CONFIG_OMAP_32K_TIMER)	+= timer32k.o
 
+# OCPI interconnect support for 1710, 1610 and 5912
+obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
+
 # Power Management
 obj-$(CONFIG_PM) += pm.o sleep.o
 
@@ -28,13 +31,15 @@
 obj-y					+= $(usb-fs-m) $(usb-fs-y)
 
 # Specific board support
-obj-$(CONFIG_MACH_OMAP_H2)		+= board-h2.o board-h2-mmc.o
+obj-$(CONFIG_MACH_OMAP_H2)		+= board-h2.o board-h2-mmc.o \
+					   board-nand.o
 obj-$(CONFIG_MACH_OMAP_INNOVATOR)	+= board-innovator.o
 obj-$(CONFIG_MACH_OMAP_GENERIC)		+= board-generic.o
-obj-$(CONFIG_MACH_OMAP_PERSEUS2)	+= board-perseus2.o
-obj-$(CONFIG_MACH_OMAP_FSAMPLE)		+= board-fsample.o
+obj-$(CONFIG_MACH_OMAP_PERSEUS2)	+= board-perseus2.o board-nand.o
+obj-$(CONFIG_MACH_OMAP_FSAMPLE)		+= board-fsample.o board-nand.o
 obj-$(CONFIG_MACH_OMAP_OSK)		+= board-osk.o
-obj-$(CONFIG_MACH_OMAP_H3)		+= board-h3.o board-h3-mmc.o
+obj-$(CONFIG_MACH_OMAP_H3)		+= board-h3.o board-h3-mmc.o \
+					   board-nand.o
 obj-$(CONFIG_MACH_VOICEBLUE)		+= board-voiceblue.o
 obj-$(CONFIG_MACH_OMAP_PALMTE)		+= board-palmte.o
 obj-$(CONFIG_MACH_OMAP_PALMZ71)		+= board-palmz71.o
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
index cfd98b1..68e8e56 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -102,7 +102,7 @@
 	}
 
 	retval = request_irq(INT_DEFERRED_FIQ, deferred_fiq,
-			IRQ_TYPE_EDGE_RISING, "deferred_fiq", 0);
+			IRQ_TYPE_EDGE_RISING, "deferred_fiq", NULL);
 	if (retval < 0) {
 		pr_err("Failed to get deferred_fiq IRQ, ret=%d\n", retval);
 		release_fiq(&fh);
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 80bd43c..4a4afb3 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -185,20 +185,6 @@
 	.resource	= &nor_resource,
 };
 
-static void nand_cmd_ctl(struct mtd_info *mtd, int cmd,	unsigned int ctrl)
-{
-	struct nand_chip *this = mtd->priv;
-	unsigned long mask;
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	mask = (ctrl & NAND_CLE) ? 0x02 : 0;
-	if (ctrl & NAND_ALE)
-		mask |= 0x04;
-	writeb(cmd, (unsigned long)this->IO_ADDR_W | mask);
-}
-
 #define FSAMPLE_NAND_RB_GPIO_PIN	62
 
 static int nand_dev_ready(struct mtd_info *mtd)
@@ -216,7 +202,7 @@
 		.part_probe_types	= part_probes,
 	},
 	.ctrl	= {
-		.cmd_ctrl	= nand_cmd_ctl,
+		.cmd_ctrl	= omap1_nand_cmd_ctl,
 		.dev_ready	= nand_dev_ready,
 	},
 };
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 553a2e5..057ec13 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -179,20 +179,6 @@
 	},
 };
 
-static void h2_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-	struct nand_chip *this = mtd->priv;
-	unsigned long mask;
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	mask = (ctrl & NAND_CLE) ? 0x02 : 0;
-	if (ctrl & NAND_ALE)
-		mask |= 0x04;
-	writeb(cmd, (unsigned long)this->IO_ADDR_W | mask);
-}
-
 #define H2_NAND_RB_GPIO_PIN	62
 
 static int h2_nand_dev_ready(struct mtd_info *mtd)
@@ -212,9 +198,8 @@
 		.part_probe_types	= h2_part_probes,
 	},
 	.ctrl	= {
-		.cmd_ctrl	= h2_nand_cmd_ctl,
+		.cmd_ctrl	= omap1_nand_cmd_ctl,
 		.dev_ready	= h2_nand_dev_ready,
-
 	},
 };
 
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 4c19f4c..f6ddf87 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -181,20 +181,6 @@
 	},
 };
 
-static void nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-	struct nand_chip *this = mtd->priv;
-	unsigned long mask;
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	mask = (ctrl & NAND_CLE) ? 0x02 : 0;
-	if (ctrl & NAND_ALE)
-		mask |= 0x04;
-	writeb(cmd, (unsigned long)this->IO_ADDR_W | mask);
-}
-
 #define H3_NAND_RB_GPIO_PIN	10
 
 static int nand_dev_ready(struct mtd_info *mtd)
@@ -214,7 +200,7 @@
 		.part_probe_types	= part_probes,
 	},
 	.ctrl	= {
-		.cmd_ctrl	= nand_cmd_ctl,
+		.cmd_ctrl	= omap1_nand_cmd_ctl,
 		.dev_ready	= nand_dev_ready,
 
 	},
diff --git a/arch/arm/mach-omap1/board-nand.c b/arch/arm/mach-omap1/board-nand.c
new file mode 100644
index 0000000..4d08353
--- /dev/null
+++ b/arch/arm/mach-omap1/board-nand.c
@@ -0,0 +1,37 @@
+/*
+ * linux/arch/arm/mach-omap1/board-nand.c
+ *
+ * Common OMAP1 board NAND code
+ *
+ * Copyright (C) 2004, 2012 Texas Instruments, Inc.
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *         Greg Lonnon (glonnon@ridgerun.com) or info@ridgerun.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/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+
+#include "common.h"
+
+void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *this = mtd->priv;
+	unsigned long mask;
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	mask = (ctrl & NAND_CLE) ? 0x02 : 0;
+	if (ctrl & NAND_ALE)
+		mask |= 0x04;
+
+	writeb(cmd, this->IO_ADDR_W + mask);
+}
+
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index a2c5abc..61ed4f0 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -289,10 +289,10 @@
 		gpio_direction_input(PALMZ71_USBDETECT_GPIO);
 		if (request_irq(gpio_to_irq(PALMZ71_USBDETECT_GPIO),
 				palmz71_powercable, IRQF_SAMPLE_RANDOM,
-				"palmz71-cable", 0))
+				"palmz71-cable", NULL))
 			printk(KERN_ERR
 					"IRQ request for power cable failed!\n");
-		palmz71_powercable(gpio_to_irq(PALMZ71_USBDETECT_GPIO), 0);
+		palmz71_powercable(gpio_to_irq(PALMZ71_USBDETECT_GPIO), NULL);
 	}
 }
 
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 76d4ee0..a2c8889 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -143,20 +143,6 @@
 	.resource	= &nor_resource,
 };
 
-static void nand_cmd_ctl(struct mtd_info *mtd, int cmd,	unsigned int ctrl)
-{
-	struct nand_chip *this = mtd->priv;
-	unsigned long mask;
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	mask = (ctrl & NAND_CLE) ? 0x02 : 0;
-	if (ctrl & NAND_ALE)
-		mask |= 0x04;
-	writeb(cmd, (unsigned long)this->IO_ADDR_W | mask);
-}
-
 #define P2_NAND_RB_GPIO_PIN	62
 
 static int nand_dev_ready(struct mtd_info *mtd)
@@ -174,7 +160,7 @@
 		.part_probe_types	= part_probes,
 	},
 	.ctrl	= {
-		.cmd_ctrl	= nand_cmd_ctl,
+		.cmd_ctrl	= omap1_nand_cmd_ctl,
 		.dev_ready	= nand_dev_ready,
 	},
 };
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index 67382dd..a9ee06b 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -194,9 +194,8 @@
 {
 	/* Find the highest supported frequency <= rate and switch to it */
 	struct mpu_rate * ptr;
-	unsigned long dpll1_rate, ref_rate;
+	unsigned long ref_rate;
 
-	dpll1_rate = ck_dpll1_p->rate;
 	ref_rate = ck_ref_p->rate;
 
 	for (ptr = omap1_rate_table; ptr->rate; ptr++) {
diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h
index af658ad..bb7779b 100644
--- a/arch/arm/mach-omap1/common.h
+++ b/arch/arm/mach-omap1/common.h
@@ -27,6 +27,7 @@
 #define __ARCH_ARM_MACH_OMAP1_COMMON_H
 
 #include <plat/common.h>
+#include <linux/mtd/mtd.h>
 
 #if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
 void omap7xx_map_io(void);
@@ -56,8 +57,20 @@
 void omap1_init_irq(void);
 void omap1_restart(char, const char *);
 
+extern void __init omap_check_revision(void);
+
+extern void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
+			       unsigned int ctrl);
+
 extern struct sys_timer omap1_timer;
 extern bool omap_32k_timer_init(void);
-extern void __init omap_init_consistent_dma_size(void);
+
+extern u32 omap_irq_flags;
+
+#ifdef CONFIG_ARCH_OMAP16XX
+extern int ocpi_enable(void);
+#else
+static inline int ocpi_enable(void) { return 0; }
+#endif
 
 #endif /* __ARCH_ARM_MACH_OMAP1_COMMON_H */
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index 76c67b3..29ec50f 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -87,7 +87,7 @@
 	fpga_ack_irq(d);
 }
 
-void innovator_fpga_IRQ_demux(unsigned int irq, struct irq_desc *desc)
+static void innovator_fpga_IRQ_demux(unsigned int irq, struct irq_desc *desc)
 {
 	u32 stat;
 	int fpga_irq;
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c
index 2b28e1d..a1b846a 100644
--- a/arch/arm/mach-omap1/id.c
+++ b/arch/arm/mach-omap1/id.c
@@ -21,6 +21,8 @@
 
 #include <mach/hardware.h>
 
+#include "common.h"
+
 #define OMAP_DIE_ID_0		0xfffe1800
 #define OMAP_DIE_ID_1		0xfffe1804
 #define OMAP_PRODUCTION_ID_0	0xfffe2000
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index d969a72..71ce017 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -18,13 +18,12 @@
 
 #include <plat/mux.h>
 #include <plat/tc.h>
+#include <plat/dma.h>
 
 #include "iomap.h"
 #include "common.h"
 #include "clock.h"
 
-extern void omap_check_revision(void);
-
 /*
  * The machine specific code may provide the extra mapping besides the
  * default mapping provided here.
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index 4448114..6995fb6 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -49,6 +49,8 @@
 
 #include <mach/hardware.h>
 
+#include "common.h"
+
 #define IRQ_BANK(irq) ((irq) >> 5)
 #define IRQ_BIT(irq)  ((irq) & 0x1f)
 
diff --git a/arch/arm/mach-omap1/lcd_dma.c b/arch/arm/mach-omap1/lcd_dma.c
index 86ace9a..5769c71 100644
--- a/arch/arm/mach-omap1/lcd_dma.c
+++ b/arch/arm/mach-omap1/lcd_dma.c
@@ -57,7 +57,7 @@
 	void *cb_data;
 
 	int active;
-	unsigned long addr, size;
+	unsigned long addr;
 	int rotate, data_type, xres, yres;
 	int vxres;
 	int mirror;
@@ -77,11 +77,6 @@
 }
 EXPORT_SYMBOL(omap_set_lcd_dma_b1);
 
-void omap_set_lcd_dma_src_port(int port)
-{
-	lcd_dma.src_port = port;
-}
-
 void omap_set_lcd_dma_ext_controller(int external)
 {
 	lcd_dma.ext_ctrl = external;
diff --git a/arch/arm/mach-omap1/ocpi.c b/arch/arm/mach-omap1/ocpi.c
new file mode 100644
index 0000000..238170c
--- /dev/null
+++ b/arch/arm/mach-omap1/ocpi.c
@@ -0,0 +1,112 @@
+/*
+ * linux/arch/arm/plat-omap/ocpi.c
+ *
+ * Minimal OCP bus support for omap16xx
+ *
+ * Copyright (C) 2003 - 2005 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * Modified for clock framework by Paul Mundt <paul.mundt@nokia.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
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#include "common.h"
+
+#define OCPI_BASE		0xfffec320
+#define OCPI_FAULT		(OCPI_BASE + 0x00)
+#define OCPI_CMD_FAULT		(OCPI_BASE + 0x04)
+#define OCPI_SINT0		(OCPI_BASE + 0x08)
+#define OCPI_TABORT		(OCPI_BASE + 0x0c)
+#define OCPI_SINT1		(OCPI_BASE + 0x10)
+#define OCPI_PROT		(OCPI_BASE + 0x14)
+#define OCPI_SEC		(OCPI_BASE + 0x18)
+
+/* USB OHCI OCPI access error registers */
+#define HOSTUEADDR	0xfffba0e0
+#define HOSTUESTATUS	0xfffba0e4
+
+static struct clk *ocpi_ck;
+
+/*
+ * Enables device access to OMAP buses via the OCPI bridge
+ * FIXME: Add locking
+ */
+int ocpi_enable(void)
+{
+	unsigned int val;
+
+	if (!cpu_is_omap16xx())
+		return -ENODEV;
+
+	/* Enable access for OHCI in OCPI */
+	val = omap_readl(OCPI_PROT);
+	val &= ~0xff;
+	/* val &= (1 << 0);	 Allow access only to EMIFS */
+	omap_writel(val, OCPI_PROT);
+
+	val = omap_readl(OCPI_SEC);
+	val &= ~0xff;
+	omap_writel(val, OCPI_SEC);
+
+	return 0;
+}
+EXPORT_SYMBOL(ocpi_enable);
+
+static int __init omap_ocpi_init(void)
+{
+	if (!cpu_is_omap16xx())
+		return -ENODEV;
+
+	ocpi_ck = clk_get(NULL, "l3_ocpi_ck");
+	if (IS_ERR(ocpi_ck))
+		return PTR_ERR(ocpi_ck);
+
+	clk_enable(ocpi_ck);
+	ocpi_enable();
+	pr_info("OMAP OCPI interconnect driver loaded\n");
+
+	return 0;
+}
+
+static void __exit omap_ocpi_exit(void)
+{
+	/* REVISIT: Disable OCPI */
+
+	if (!cpu_is_omap16xx())
+		return;
+
+	clk_disable(ocpi_ck);
+	clk_put(ocpi_ck);
+}
+
+MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
+MODULE_DESCRIPTION("OMAP OCPI bus controller module");
+MODULE_LICENSE("GPL");
+module_init(omap_ocpi_init);
+module_exit(omap_ocpi_exit);
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index f66c329..b2560d3 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -569,11 +569,10 @@
 
 static void omap_pm_init_proc(void)
 {
-	struct proc_dir_entry *entry;
-
-	entry = create_proc_read_entry("driver/omap_pm",
-				       S_IWUSR | S_IRUGO, NULL,
-				       omap_pm_read_proc, NULL);
+	/* XXX Appears to leak memory */
+	create_proc_read_entry("driver/omap_pm",
+			       S_IWUSR | S_IRUGO, NULL,
+			       omap_pm_read_proc, NULL);
 }
 
 #endif /* DEBUG && CONFIG_PROC_FS */
diff --git a/arch/arm/mach-omap1/reset.c b/arch/arm/mach-omap1/reset.c
index f255b15..b177091 100644
--- a/arch/arm/mach-omap1/reset.c
+++ b/arch/arm/mach-omap1/reset.c
@@ -8,6 +8,8 @@
 
 #include <mach/hardware.h>
 
+#include "common.h"
+
 void omap1_restart(char mode, const char *cmd)
 {
 	/*
diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c
index fb202af..64c65bc 100644
--- a/arch/arm/mach-omap1/timer.c
+++ b/arch/arm/mach-omap1/timer.c
@@ -54,8 +54,7 @@
 	return 0;
 }
 
-
-int __init omap1_dm_timer_init(void)
+static int __init omap1_dm_timer_init(void)
 {
 	int i;
 	int ret;
diff --git a/arch/arm/mach-omap1/usb.c b/arch/arm/mach-omap1/usb.c
index 19de03b..e61afd9 100644
--- a/arch/arm/mach-omap1/usb.c
+++ b/arch/arm/mach-omap1/usb.c
@@ -29,6 +29,8 @@
 #include <plat/mux.h>
 #include <plat/usb.h>
 
+#include "common.h"
+
 /* These routines should handle the standard chip-specific modes
  * for usb0/1/2 ports, covering basic mux and transceiver setup.
  *
@@ -138,6 +140,7 @@
 	if (cpu_is_omap7xx())
 		ohci_resources[1].start = INT_7XX_USB_HHC_1;
 	pdata->ohci_device = &ohci_device;
+	pdata->ocpi_enable = &ocpi_enable;
 }
 
 #else
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 8141b76..964ee67 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -17,6 +17,7 @@
 	select MENELAUS if ARCH_OMAP2
 	select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4
 	select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4
+	select HIGHMEM
 	help
 	  Compile a kernel suitable for booting most boards
 
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 49f92bc..385c083 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer.o pm.o \
-	 common.o gpio.o dma.o wd_timer.o display.o i2c.o
+	 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o
 
 omap-2-3-common				= irq.o sdrc.o
 hwmod-common				= omap_hwmod.o \
@@ -118,16 +118,18 @@
 					   powerdomains44xx_data.o
 
 # PRCM clockdomain control
-obj-$(CONFIG_ARCH_OMAP2)		+= clockdomain.o \
+clockdomain-common			+= clockdomain.o \
+					   clockdomains_common_data.o
+obj-$(CONFIG_ARCH_OMAP2)		+= $(clockdomain-common) \
 					   clockdomain2xxx_3xxx.o \
 					   clockdomains2xxx_3xxx_data.o
 obj-$(CONFIG_SOC_OMAP2420)		+= clockdomains2420_data.o
 obj-$(CONFIG_SOC_OMAP2430)		+= clockdomains2430_data.o
-obj-$(CONFIG_ARCH_OMAP3)		+= clockdomain.o \
+obj-$(CONFIG_ARCH_OMAP3)		+= $(clockdomain-common) \
 					   clockdomain2xxx_3xxx.o \
 					   clockdomains2xxx_3xxx_data.o \
 					   clockdomains3xxx_data.o
-obj-$(CONFIG_ARCH_OMAP4)		+= clockdomain.o \
+obj-$(CONFIG_ARCH_OMAP4)		+= $(clockdomain-common) \
 					   clockdomain44xx.o \
 					   clockdomains44xx_data.o
 
@@ -187,6 +189,9 @@
 obj-y					+= dsp.o
 endif
 
+# OMAP2420 MSDI controller integration support ("MMC")
+obj-$(CONFIG_SOC_OMAP2420)		+= msdi.o
+
 # Specific board support
 obj-$(CONFIG_MACH_OMAP_GENERIC)		+= board-generic.o
 obj-$(CONFIG_MACH_OMAP_H4)		+= board-h4.o
diff --git a/arch/arm/mach-omap2/am35xx-emac.c b/arch/arm/mach-omap2/am35xx-emac.c
index 1f97e74..447682c 100644
--- a/arch/arm/mach-omap2/am35xx-emac.c
+++ b/arch/arm/mach-omap2/am35xx-emac.c
@@ -39,26 +39,23 @@
 
 static void am35xx_enable_emac_int(void)
 {
-	u32 regval;
+	u32 v;
 
-	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-	regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
-		  AM35XX_CPGMAC_C0_TX_PULSE_CLR |
-		  AM35XX_CPGMAC_C0_MISC_PULSE_CLR |
-		  AM35XX_CPGMAC_C0_RX_THRESH_CLR);
-	omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
-	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+	v = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+	v |= (AM35XX_CPGMAC_C0_RX_PULSE_CLR | AM35XX_CPGMAC_C0_TX_PULSE_CLR |
+	      AM35XX_CPGMAC_C0_MISC_PULSE_CLR | AM35XX_CPGMAC_C0_RX_THRESH_CLR);
+	omap_ctrl_writel(v, AM35XX_CONTROL_LVL_INTR_CLEAR);
+	omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); /* OCP barrier */
 }
 
 static void am35xx_disable_emac_int(void)
 {
-	u32 regval;
+	u32 v;
 
-	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-	regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
-		  AM35XX_CPGMAC_C0_TX_PULSE_CLR);
-	omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
-	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+	v = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+	v |= (AM35XX_CPGMAC_C0_RX_PULSE_CLR | AM35XX_CPGMAC_C0_TX_PULSE_CLR);
+	omap_ctrl_writel(v, AM35XX_CONTROL_LVL_INTR_CLEAR);
+	omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); /* OCP barrier */
 }
 
 static struct emac_platform_data am35xx_emac_pdata = {
@@ -92,7 +89,7 @@
 
 void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
 {
-	unsigned int regval;
+	u32 v;
 	int err;
 
 	am35xx_emac_pdata.rmii_en = rmii_en;
@@ -110,8 +107,8 @@
 		return;
 	}
 
-	regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
-	regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
-	omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
-	regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+	v = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+	v &= ~AM35XX_CPGMACSS_SW_RST;
+	omap_ctrl_writel(v, AM35XX_CONTROL_IP_SW_RESET);
+	omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); /* OCP barrier */
 }
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index da75f23..37abb0d 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -37,7 +37,7 @@
 #include <plat/dma.h>
 #include <plat/gpmc.h>
 #include <video/omapdss.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 
 #include <plat/gpmc-smc91x.h>
 
@@ -113,9 +113,6 @@
 	{SDP3430_LCD_PANEL_BACKLIGHT_GPIO, GPIOF_OUT_INIT_LOW, "LCD Backlight"},
 };
 
-static int lcd_enabled;
-static int dvi_enabled;
-
 static void __init sdp3430_display_init(void)
 {
 	int r;
@@ -129,44 +126,18 @@
 
 static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
 {
-	if (dvi_enabled) {
-		printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
-		return -EINVAL;
-	}
-
 	gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 1);
 	gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 1);
 
-	lcd_enabled = 1;
-
 	return 0;
 }
 
 static void sdp3430_panel_disable_lcd(struct omap_dss_device *dssdev)
 {
-	lcd_enabled = 0;
-
 	gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 0);
 	gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 0);
 }
 
-static int sdp3430_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
-	if (lcd_enabled) {
-		printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
-		return -EINVAL;
-	}
-
-	dvi_enabled = 1;
-
-	return 0;
-}
-
-static void sdp3430_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
-	dvi_enabled = 0;
-}
-
 static int sdp3430_panel_enable_tv(struct omap_dss_device *dssdev)
 {
 	return 0;
@@ -186,15 +157,14 @@
 	.platform_disable	= sdp3430_panel_disable_lcd,
 };
 
-static struct panel_dvi_platform_data dvi_panel = {
-	.platform_enable	= sdp3430_panel_enable_dvi,
-	.platform_disable	= sdp3430_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+	.power_down_gpio	= -1,
 };
 
 static struct omap_dss_device sdp3430_dvi_device = {
 	.name			= "dvi",
 	.type			= OMAP_DISPLAY_TYPE_DPI,
-	.driver_name		= "dvi",
+	.driver_name		= "tfp410",
 	.data			= &dvi_panel,
 	.phy.dpi.data_lines	= 24,
 };
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 130ab00..94af6cd 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -384,6 +384,11 @@
 	.id	= -1,
 };
 
+static struct platform_device sdp4430_hdmi_audio_codec = {
+	.name	= "hdmi-audio-codec",
+	.id	= -1,
+};
+
 static struct omap_abe_twl6040_data sdp4430_abe_audio_data = {
 	.card_name = "SDP4430",
 	.has_hs		= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
@@ -418,6 +423,7 @@
 	&sdp4430_vbat,
 	&sdp4430_dmic_codec,
 	&sdp4430_abe_audio,
+	&sdp4430_hdmi_audio_codec,
 };
 
 static struct omap_musb_board_data musb_board_data = {
@@ -489,50 +495,6 @@
 	},
 };
 
-static int omap4_twl6030_hsmmc_late_init(struct device *dev)
-{
-	int irq = 0;
-	struct platform_device *pdev = container_of(dev,
-				struct platform_device, dev);
-	struct omap_mmc_platform_data *pdata = dev->platform_data;
-
-	/* Setting MMC1 Card detect Irq */
-	if (pdev->id == 0) {
-		irq = twl6030_mmc_card_detect_config();
-		if (irq < 0) {
-			pr_err("Failed configuring MMC1 card detect\n");
-			return irq;
-		}
-		pdata->slots[0].card_detect_irq = irq;
-		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
-	}
-	return 0;
-}
-
-static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
-{
-	struct omap_mmc_platform_data *pdata;
-
-	/* dev can be null if CONFIG_MMC_OMAP_HS is not set */
-	if (!dev) {
-		pr_err("Failed %s\n", __func__);
-		return;
-	}
-	pdata = dev->platform_data;
-	pdata->init =	omap4_twl6030_hsmmc_late_init;
-}
-
-static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
-{
-	struct omap2_hsmmc_info *c;
-
-	omap_hsmmc_init(controllers);
-	for (c = controllers; c->mmc; c++)
-		omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
-
-	return 0;
-}
-
 static struct regulator_init_data sdp4430_vaux1 = {
 	.constraints = {
 		.min_uV			= 1000000,
@@ -615,7 +577,9 @@
 			TWL_COMMON_REGULATOR_VANA |
 			TWL_COMMON_REGULATOR_VCXIO |
 			TWL_COMMON_REGULATOR_VUSB |
-			TWL_COMMON_REGULATOR_CLK32KG);
+			TWL_COMMON_REGULATOR_CLK32KG |
+			TWL_COMMON_REGULATOR_V1V8 |
+			TWL_COMMON_REGULATOR_V2V1);
 	omap4_pmic_init("twl6030", &sdp4430_twldata,
 			&twl6040_data, OMAP44XX_IRQ_SYS_2N);
 	omap_register_i2c_bus(2, 400, NULL, 0);
@@ -666,6 +630,10 @@
 		.use_ext_te	= false,
 		.ext_te_gpio	= 101,
 		.esd_interval	= 0,
+		.pin_config = {
+			.num_pins	= 6,
+			.pins		= { 0, 1, 2, 3, 4, 5 },
+		},
 };
 
 static struct omap_dss_device sdp4430_lcd_device = {
@@ -674,13 +642,6 @@
 	.type			= OMAP_DISPLAY_TYPE_DSI,
 	.data			= &dsi1_panel,
 	.phy.dsi		= {
-		.clk_lane	= 1,
-		.clk_pol	= 0,
-		.data1_lane	= 2,
-		.data1_pol	= 0,
-		.data2_lane	= 3,
-		.data2_pol	= 0,
-
 		.module		= 0,
 	},
 
@@ -715,6 +676,10 @@
 		.use_ext_te	= false,
 		.ext_te_gpio	= 103,
 		.esd_interval	= 0,
+		.pin_config = {
+			.num_pins	= 6,
+			.pins		= { 0, 1, 2, 3, 4, 5 },
+		},
 };
 
 static struct omap_dss_device sdp4430_lcd2_device = {
@@ -723,12 +688,6 @@
 	.type			= OMAP_DISPLAY_TYPE_DSI,
 	.data			= &dsi2_panel,
 	.phy.dsi		= {
-		.clk_lane	= 1,
-		.clk_pol	= 0,
-		.data1_lane	= 2,
-		.data1_pol	= 0,
-		.data2_lane	= 3,
-		.data2_pol	= 0,
 
 		.module		= 1,
 	},
@@ -758,21 +717,6 @@
 	.channel		= OMAP_DSS_CHANNEL_LCD2,
 };
 
-static void sdp4430_lcd_init(void)
-{
-	int r;
-
-	r = gpio_request_one(dsi1_panel.reset_gpio, GPIOF_DIR_OUT,
-		"lcd1_reset_gpio");
-	if (r)
-		pr_err("%s: Could not get lcd1_reset_gpio\n", __func__);
-
-	r = gpio_request_one(dsi2_panel.reset_gpio, GPIOF_DIR_OUT,
-		"lcd2_reset_gpio");
-	if (r)
-		pr_err("%s: Could not get lcd2_reset_gpio\n", __func__);
-}
-
 static struct omap_dss_hdmi_data sdp4430_hdmi_data = {
 	.hpd_gpio = HDMI_GPIO_HPD,
 };
@@ -858,7 +802,6 @@
 	if (r)
 		pr_err("%s: Could not get display_sel GPIO\n", __func__);
 
-	sdp4430_lcd_init();
 	sdp4430_picodlp_init();
 	omap_display_init(&sdp4430_dss_data);
 	/*
diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c
index c3851e8..3b8a53c 100644
--- a/arch/arm/mach-omap2/board-am3517crane.c
+++ b/arch/arm/mach-omap2/board-am3517crane.c
@@ -30,6 +30,7 @@
 #include "common.h"
 #include <plat/usb.h>
 
+#include "am35xx-emac.h"
 #include "mux.h"
 #include "control.h"
 
@@ -90,6 +91,7 @@
 	}
 
 	usbhs_init(&usbhs_bdata);
+	am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
 }
 
 MACHINE_START(CRANEBOARD, "AM3517/05 CRANEBOARD")
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index 3645285..99790eb 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -37,7 +37,7 @@
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 
 #include "am35xx-emac.h"
 #include "mux.h"
@@ -207,31 +207,14 @@
 	.platform_disable	= am3517_evm_panel_disable_tv,
 };
 
-static int am3517_evm_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
-	if (lcd_enabled) {
-		printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
-		return -EINVAL;
-	}
-	dvi_enabled = 1;
-
-	return 0;
-}
-
-static void am3517_evm_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
-	dvi_enabled = 0;
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
-	.platform_enable	= am3517_evm_panel_enable_dvi,
-	.platform_disable	= am3517_evm_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+	.power_down_gpio	= -1,
 };
 
 static struct omap_dss_device am3517_evm_dvi_device = {
 	.type			= OMAP_DISPLAY_TYPE_DPI,
 	.name			= "dvi",
-	.driver_name		= "dvi",
+	.driver_name		= "tfp410",
 	.data			= &dvi_panel,
 	.phy.dpi.data_lines	= 24,
 };
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index 909a8b9..c03df14 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -44,7 +44,7 @@
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 #include <plat/mcspi.h>
 
 #include <mach/hardware.h>
@@ -218,25 +218,6 @@
 	gpio_set_value(CM_T35_LCD_EN_GPIO, 0);
 }
 
-static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
-	if (lcd_enabled) {
-		printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
-		return -EINVAL;
-	}
-
-	gpio_set_value(CM_T35_DVI_EN_GPIO, 0);
-	dvi_enabled = 1;
-
-	return 0;
-}
-
-static void cm_t35_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
-	gpio_set_value(CM_T35_DVI_EN_GPIO, 1);
-	dvi_enabled = 0;
-}
-
 static int cm_t35_panel_enable_tv(struct omap_dss_device *dssdev)
 {
 	return 0;
@@ -260,15 +241,14 @@
 	.phy.dpi.data_lines	= 18,
 };
 
-static struct panel_dvi_platform_data dvi_panel = {
-	.platform_enable	= cm_t35_panel_enable_dvi,
-	.platform_disable	= cm_t35_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+	.power_down_gpio	= CM_T35_DVI_EN_GPIO,
 };
 
 static struct omap_dss_device cm_t35_dvi_device = {
 	.name			= "dvi",
 	.type			= OMAP_DISPLAY_TYPE_DPI,
-	.driver_name		= "dvi",
+	.driver_name		= "tfp410",
 	.data			= &dvi_panel,
 	.phy.dpi.data_lines	= 24,
 };
@@ -316,7 +296,6 @@
 static struct gpio cm_t35_dss_gpios[] __initdata = {
 	{ CM_T35_LCD_EN_GPIO, GPIOF_OUT_INIT_LOW,  "lcd enable"    },
 	{ CM_T35_LCD_BL_GPIO, GPIOF_OUT_INIT_LOW,  "lcd bl enable" },
-	{ CM_T35_DVI_EN_GPIO, GPIOF_OUT_INIT_HIGH, "dvi enable"    },
 };
 
 static void __init cm_t35_init_display(void)
@@ -335,7 +314,6 @@
 
 	gpio_export(CM_T35_LCD_EN_GPIO, 0);
 	gpio_export(CM_T35_LCD_BL_GPIO, 0);
-	gpio_export(CM_T35_DVI_EN_GPIO, 0);
 
 	msleep(50);
 	gpio_set_value(CM_T35_LCD_EN_GPIO, 1);
@@ -498,6 +476,10 @@
 	.setup          = cm_t35_twl_gpio_setup,
 };
 
+static struct twl4030_power_data cm_t35_power_data = {
+	.use_poweroff	= true,
+};
+
 static struct twl4030_platform_data cm_t35_twldata = {
 	/* platform_data for children goes here */
 	.keypad		= &cm_t35_kp_data,
@@ -505,6 +487,7 @@
 	.vmmc1		= &cm_t35_vmmc1,
 	.vsim		= &cm_t35_vsim,
 	.vio		= &cm_t35_vio,
+	.power		= &cm_t35_power_data,
 };
 
 static void __init cm_t35_init_i2c(void)
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index a2010f0..b063f0d 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -47,7 +47,7 @@
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
@@ -118,19 +118,6 @@
 		gpio_set_value_cansleep(dssdev->reset_gpio, 0);
 }
 
-static int devkit8000_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
-	if (gpio_is_valid(dssdev->reset_gpio))
-		gpio_set_value_cansleep(dssdev->reset_gpio, 1);
-	return 0;
-}
-
-static void devkit8000_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
-	if (gpio_is_valid(dssdev->reset_gpio))
-		gpio_set_value_cansleep(dssdev->reset_gpio, 0);
-}
-
 static struct regulator_consumer_supply devkit8000_vmmc1_supply[] = {
 	REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
 };
@@ -154,15 +141,14 @@
 	.phy.dpi.data_lines     = 24,
 };
 
-static struct panel_dvi_platform_data dvi_panel = {
-	.platform_enable        = devkit8000_panel_enable_dvi,
-	.platform_disable       = devkit8000_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+	.power_down_gpio	= -1,
 };
 
 static struct omap_dss_device devkit8000_dvi_device = {
 	.name                   = "dvi",
 	.type                   = OMAP_DISPLAY_TYPE_DPI,
-	.driver_name            = "dvi",
+	.driver_name            = "tfp410",
 	.data			= &dvi_panel,
 	.phy.dpi.data_lines     = 24,
 };
@@ -244,13 +230,7 @@
 	}
 
 	/* gpio + 7 is "DVI_PD" (out, active low) */
-	devkit8000_dvi_device.reset_gpio = gpio + 7;
-	ret = gpio_request_one(devkit8000_dvi_device.reset_gpio,
-			       GPIOF_OUT_INIT_LOW, "DVI PowerDown");
-	if (ret < 0) {
-		devkit8000_dvi_device.reset_gpio = -EINVAL;
-		printk(KERN_ERR "Failed to request GPIO for DVI PowerDown\n");
-	}
+	dvi_panel.power_down_gpio = gpio + 7;
 
 	return 0;
 }
diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index 0349fd2..70a81f9 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -87,7 +87,7 @@
 	.dma_channel	= -1,   /* disable DMA in OMAP OneNAND driver */
 };
 
-static void
+void
 __init board_onenand_init(struct mtd_partition *onenand_parts,
 				u8 nr_parts, u8 cs)
 {
@@ -98,7 +98,7 @@
 	gpmc_onenand_init(&board_onenand_data);
 }
 #else
-static void
+void
 __init board_onenand_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs)
 {
 }
diff --git a/arch/arm/mach-omap2/board-flash.h b/arch/arm/mach-omap2/board-flash.h
index d25503a..c44b70d 100644
--- a/arch/arm/mach-omap2/board-flash.h
+++ b/arch/arm/mach-omap2/board-flash.h
@@ -47,3 +47,14 @@
 {
 }
 #endif
+
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+		defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+extern void board_onenand_init(struct mtd_partition *nand_parts,
+					u8 nr_parts, u8 cs);
+#else
+static inline void board_onenand_init(struct mtd_partition *nand_parts,
+					u8 nr_parts, u8 cs)
+{
+}
+#endif
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index 098d183..7302ba7 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -15,7 +15,6 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/irqdomain.h>
-#include <linux/i2c/twl.h>
 
 #include <mach/hardware.h>
 #include <asm/hardware/gic.h>
@@ -95,22 +94,6 @@
 #endif
 
 #ifdef CONFIG_ARCH_OMAP3
-static struct twl4030_platform_data beagle_twldata = {
-	.irq_base	= TWL4030_IRQ_BASE,
-	.irq_end	= TWL4030_IRQ_END,
-};
-
-static void __init omap3_i2c_init(void)
-{
-	omap3_pmic_init("twl4030", &beagle_twldata);
-}
-
-static void __init omap3_init(void)
-{
-	omap3_i2c_init();
-	omap_generic_init();
-}
-
 static const char *omap3_boards_compat[] __initdata = {
 	"ti,omap3",
 	NULL,
@@ -122,7 +105,7 @@
 	.init_early	= omap3430_init_early,
 	.init_irq	= omap_init_irq,
 	.handle_irq	= omap3_intc_handle_irq,
-	.init_machine	= omap3_init,
+	.init_machine	= omap_generic_init,
 	.timer		= &omap3_timer,
 	.dt_compat	= omap3_boards_compat,
 	.restart	= omap_prcm_restart,
@@ -130,22 +113,6 @@
 #endif
 
 #ifdef CONFIG_ARCH_OMAP4
-static struct twl4030_platform_data sdp4430_twldata = {
-	.irq_base	= TWL6030_IRQ_BASE,
-	.irq_end	= TWL6030_IRQ_END,
-};
-
-static void __init omap4_i2c_init(void)
-{
-	omap4_pmic_init("twl6030", &sdp4430_twldata, NULL, 0);
-}
-
-static void __init omap4_init(void)
-{
-	omap4_i2c_init();
-	omap_generic_init();
-}
-
 static const char *omap4_boards_compat[] __initdata = {
 	"ti,omap4",
 	NULL,
@@ -157,7 +124,7 @@
 	.init_early	= omap4430_init_early,
 	.init_irq	= omap_init_irq,
 	.handle_irq	= gic_handle_irq,
-	.init_machine	= omap4_init,
+	.init_machine	= omap_generic_init,
 	.timer		= &omap4_timer,
 	.dt_compat	= omap4_boards_compat,
 	.restart	= omap_prcm_restart,
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index 740cee9..7a27409 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -24,6 +24,8 @@
 #include <linux/i2c/twl.h>
 #include <linux/mmc/host.h>
 
+#include <linux/mtd/nand.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
@@ -32,13 +34,15 @@
 #include <plat/gpmc.h>
 #include <plat/usb.h>
 #include <video/omapdss.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 #include <plat/onenand.h>
 
 #include "mux.h"
 #include "hsmmc.h"
 #include "sdram-numonyx-m65kxxxxam.h"
 #include "common-board-devices.h"
+#include "board-flash.h"
+#include "control.h"
 
 #define IGEP2_SMSC911X_CS       5
 #define IGEP2_SMSC911X_GPIO     176
@@ -60,6 +64,10 @@
 #define IGEP3_GPIO_LED1_RED	16
 #define IGEP3_GPIO_USBH_NRESET  183
 
+#define IGEP_SYSBOOT_MASK           0x1f
+#define IGEP_SYSBOOT_NAND           0x0f
+#define IGEP_SYSBOOT_ONENAND        0x10
+
 /*
  * IGEP2 Hardware Revision Table
  *
@@ -110,8 +118,10 @@
 	gpio_free(IGEP2_GPIO_LED1_RED);
 }
 
-#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
-	defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+#if defined(CONFIG_MTD_ONENAND_OMAP2) ||		\
+	defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) ||	\
+	defined(CONFIG_MTD_NAND_OMAP2) ||		\
+	defined(CONFIG_MTD_NAND_OMAP2_MODULE)
 
 #define ONENAND_MAP             0x20000000
 
@@ -123,7 +133,7 @@
  * So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
  */
 
-static struct mtd_partition igep_onenand_partitions[] = {
+static struct mtd_partition igep_flash_partitions[] = {
 	{
 		.name           = "X-Loader",
 		.offset         = 0,
@@ -151,50 +161,28 @@
 	},
 };
 
-static struct omap_onenand_platform_data igep_onenand_data = {
-	.parts = igep_onenand_partitions,
-	.nr_parts = ARRAY_SIZE(igep_onenand_partitions),
-	.dma_channel	= -1,	/* disable DMA in OMAP OneNAND driver */
-};
-
-static struct platform_device igep_onenand_device = {
-	.name		= "omap2-onenand",
-	.id		= -1,
-	.dev = {
-		.platform_data = &igep_onenand_data,
-	},
-};
+static inline u32 igep_get_sysboot_value(void)
+{
+	return omap_ctrl_readl(OMAP343X_CONTROL_STATUS) & IGEP_SYSBOOT_MASK;
+}
 
 static void __init igep_flash_init(void)
 {
-	u8 cs = 0;
-	u8 onenandcs = GPMC_CS_NUM + 1;
+	u32 mux;
+	mux = igep_get_sysboot_value();
 
-	for (cs = 0; cs < GPMC_CS_NUM; cs++) {
-		u32 ret;
-		ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
-		/* Check if NAND/oneNAND is configured */
-		if ((ret & 0xC00) == 0x800)
-			/* NAND found */
-			pr_err("IGEP: Unsupported NAND found\n");
-		else {
-			ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-			if ((ret & 0x3F) == (ONENAND_MAP >> 24))
-				/* ONENAND found */
-				onenandcs = cs;
-		}
+	if (mux == IGEP_SYSBOOT_NAND) {
+		pr_info("IGEP: initializing NAND memory device\n");
+		board_nand_init(igep_flash_partitions,
+				ARRAY_SIZE(igep_flash_partitions),
+				0, NAND_BUSWIDTH_16);
+	} else if (mux == IGEP_SYSBOOT_ONENAND) {
+		pr_info("IGEP: initializing OneNAND memory device\n");
+		board_onenand_init(igep_flash_partitions,
+				   ARRAY_SIZE(igep_flash_partitions), 0);
+	} else {
+		pr_err("IGEP: Flash: unsupported sysboot sequence found\n");
 	}
-
-	if (onenandcs > GPMC_CS_NUM) {
-		pr_err("IGEP: Unable to find configuration in GPMC\n");
-		return;
-	}
-
-	igep_onenand_data.cs = onenandcs;
-
-	if (platform_device_register(&igep_onenand_device) < 0)
-		pr_err("IGEP: Unable to register OneNAND device\n");
 }
 
 #else
@@ -444,28 +432,15 @@
 	.setup		= igep_twl_gpio_setup,
 };
 
-static int igep2_enable_dvi(struct omap_dss_device *dssdev)
-{
-	gpio_direction_output(IGEP2_GPIO_DVI_PUP, 1);
-
-	return 0;
-}
-
-static void igep2_disable_dvi(struct omap_dss_device *dssdev)
-{
-	gpio_direction_output(IGEP2_GPIO_DVI_PUP, 0);
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
-	.platform_enable	= igep2_enable_dvi,
-	.platform_disable	= igep2_disable_dvi,
-	.i2c_bus_num = 3,
+static struct tfp410_platform_data dvi_panel = {
+	.i2c_bus_num		= 3,
+	.power_down_gpio	= IGEP2_GPIO_DVI_PUP,
 };
 
 static struct omap_dss_device igep2_dvi_device = {
 	.type			= OMAP_DISPLAY_TYPE_DPI,
 	.name			= "dvi",
-	.driver_name		= "dvi",
+	.driver_name		= "tfp410",
 	.data			= &dvi_panel,
 	.phy.dpi.data_lines	= 24,
 };
@@ -480,14 +455,6 @@
 	.default_device	= &igep2_dvi_device,
 };
 
-static void __init igep2_display_init(void)
-{
-	int err = gpio_request_one(IGEP2_GPIO_DVI_PUP, GPIOF_OUT_INIT_HIGH,
-				   "GPIO_DVI_PUP");
-	if (err)
-		pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n");
-}
-
 static struct platform_device *igep_devices[] __initdata = {
 	&igep_vwlan_device,
 };
@@ -540,7 +507,10 @@
 {
 	int ret;
 
-	omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_USB, 0);
+	omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_USB,
+			      TWL_COMMON_REGULATOR_VPLL2);
+	igep_twldata.vpll2->constraints.apply_uV = true;
+	igep_twldata.vpll2->constraints.name = "VDVI";
 
 	if (machine_is_igep0020()) {
 		/*
@@ -554,10 +524,7 @@
 
 		igep_twldata.keypad	= &igep2_keypad_pdata;
 		/* Get common pmic data */
-		omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_AUDIO,
-				      TWL_COMMON_REGULATOR_VPLL2);
-		igep_twldata.vpll2->constraints.apply_uV = true;
-		igep_twldata.vpll2->constraints.name = "VDVI";
+		omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_AUDIO, 0);
 	}
 
 	omap3_pmic_init("twl4030", &igep_twldata);
@@ -668,7 +635,6 @@
 
 	if (machine_is_igep0020()) {
 		omap_display_init(&igep2_dss_data);
-		igep2_display_init();
 		igep2_init_smsc911x();
 		usbhs_init(&igep2_usbhs_bdata);
 	} else {
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 7be8d65..2a7b9a9 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -42,7 +42,7 @@
 #include <plat/board.h>
 #include "common.h"
 #include <video/omapdss.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
@@ -83,11 +83,13 @@
 	int usb_pwr_level;
 	int reset_gpio;
 	int usr_button_gpio;
+	int mmc_caps;
 } beagle_config = {
 	.mmc1_gpio_wp = -EINVAL,
 	.usb_pwr_level = GPIOF_OUT_INIT_LOW,
 	.reset_gpio = 129,
 	.usr_button_gpio = 4,
+	.mmc_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 };
 
 static struct gpio omap3_beagle_rev_gpios[] __initdata = {
@@ -145,10 +147,12 @@
 		printk(KERN_INFO "OMAP3 Beagle Rev: xM Ax/Bx\n");
 		omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
 		beagle_config.usb_pwr_level = GPIOF_OUT_INIT_HIGH;
+		beagle_config.mmc_caps &= ~MMC_CAP_8_BIT_DATA;
 		break;
 	case 2:
 		printk(KERN_INFO "OMAP3 Beagle Rev: xM C\n");
 		omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
+		beagle_config.mmc_caps &= ~MMC_CAP_8_BIT_DATA;
 		break;
 	default:
 		printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
@@ -189,33 +193,17 @@
 
 /* DSS */
 
-static int beagle_enable_dvi(struct omap_dss_device *dssdev)
-{
-	if (gpio_is_valid(dssdev->reset_gpio))
-		gpio_set_value(dssdev->reset_gpio, 1);
-
-	return 0;
-}
-
-static void beagle_disable_dvi(struct omap_dss_device *dssdev)
-{
-	if (gpio_is_valid(dssdev->reset_gpio))
-		gpio_set_value(dssdev->reset_gpio, 0);
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
-	.platform_enable = beagle_enable_dvi,
-	.platform_disable = beagle_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
 	.i2c_bus_num = 3,
+	.power_down_gpio = -1,
 };
 
 static struct omap_dss_device beagle_dvi_device = {
 	.type = OMAP_DISPLAY_TYPE_DPI,
 	.name = "dvi",
-	.driver_name = "dvi",
+	.driver_name = "tfp410",
 	.data = &dvi_panel,
 	.phy.dpi.data_lines = 24,
-	.reset_gpio = -EINVAL,
 };
 
 static struct omap_dss_device beagle_tv_device = {
@@ -236,22 +224,12 @@
 	.default_device = &beagle_dvi_device,
 };
 
-static void __init beagle_display_init(void)
-{
-	int r;
-
-	r = gpio_request_one(beagle_dvi_device.reset_gpio, GPIOF_OUT_INIT_LOW,
-			     "DVI reset");
-	if (r < 0)
-		printk(KERN_ERR "Unable to get DVI reset GPIO\n");
-}
-
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_wp	= -EINVAL,
 		.deferred	= true,
 	},
@@ -309,7 +287,7 @@
 		if (gpio_request_one(gpio + 1, GPIOF_IN, "EHCI_nOC"))
 			pr_err("%s: unable to configure EHCI_nOC\n", __func__);
 	}
-	beagle_dvi_device.reset_gpio = beagle_config.reset_gpio;
+	dvi_panel.power_down_gpio = beagle_config.reset_gpio;
 
 	gpio_request_one(gpio + TWL4030_GPIO_MAX, beagle_config.usb_pwr_level,
 			"nEN_USB_PWR");
@@ -523,6 +501,7 @@
 
 	if (beagle_config.mmc1_gpio_wp != -EINVAL)
 		omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
+	mmc[0].caps = beagle_config.mmc_caps;
 	omap_hsmmc_init(mmc);
 
 	omap3_beagle_i2c_init();
@@ -552,7 +531,6 @@
 	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
 	omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
 
-	beagle_display_init();
 	beagle_opp_init();
 }
 
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 49df127..ace3c67 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -46,7 +46,7 @@
 #include "common.h"
 #include <plat/mcspi.h>
 #include <video/omapdss.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
@@ -219,35 +219,14 @@
 	.platform_disable	= omap3_evm_disable_tv,
 };
 
-static int omap3_evm_enable_dvi(struct omap_dss_device *dssdev)
-{
-	if (lcd_enabled) {
-		printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
-		return -EINVAL;
-	}
-
-	gpio_set_value_cansleep(OMAP3EVM_DVI_PANEL_EN_GPIO, 1);
-
-	dvi_enabled = 1;
-	return 0;
-}
-
-static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev)
-{
-	gpio_set_value_cansleep(OMAP3EVM_DVI_PANEL_EN_GPIO, 0);
-
-	dvi_enabled = 0;
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
-	.platform_enable	= omap3_evm_enable_dvi,
-	.platform_disable	= omap3_evm_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+	.power_down_gpio	= OMAP3EVM_DVI_PANEL_EN_GPIO,
 };
 
 static struct omap_dss_device omap3_evm_dvi_device = {
 	.name			= "dvi",
 	.type			= OMAP_DISPLAY_TYPE_DPI,
-	.driver_name		= "dvi",
+	.driver_name		= "tfp410",
 	.data			= &dvi_panel,
 	.phy.dpi.data_lines	= 24,
 };
@@ -630,13 +609,13 @@
 
 static void __init omap3_evm_init(void)
 {
+	struct omap_board_mux *obm;
+
 	omap3_evm_get_revision();
 	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
 
-	if (cpu_is_omap3630())
-		omap3_mux_init(omap36x_board_mux, OMAP_PACKAGE_CBB);
-	else
-		omap3_mux_init(omap35x_board_mux, OMAP_PACKAGE_CBB);
+	obm = (cpu_is_omap3630()) ? omap36x_board_mux : omap35x_board_mux;
+	omap3_mux_init(obm, OMAP_PACKAGE_CBB);
 
 	omap_board_config = omap3_evm_config;
 	omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
index 9b3c141..c008bf8 100644
--- a/arch/arm/mach-omap2/board-omap3logic.c
+++ b/arch/arm/mach-omap2/board-omap3logic.c
@@ -4,8 +4,9 @@
  * Copyright (C) 2010 Li-Pro.Net
  * Stephan Linz <linz@li-pro.net>
  *
- * Copyright (C) 2010 Logic Product Development, Inc.
+ * Copyright (C) 2010-2012 Logic Product Development, Inc.
  * Peter Barada <peter.barada@logicpd.com>
+ * Ashwin BIhari <ashwin.bihari@logicpd.com>
  *
  * Modified from Beagle, EVM, and RX51
  *
@@ -45,6 +46,7 @@
 #include <plat/gpmc-smsc911x.h>
 #include <plat/gpmc.h>
 #include <plat/sdrc.h>
+#include <plat/usb.h>
 
 #define OMAP3LOGIC_SMSC911X_CS			1
 
@@ -85,6 +87,11 @@
 			| BIT(13) | BIT(15) | BIT(16) | BIT(17),
 };
 
+static struct twl4030_usb_data omap3logic_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
+
 static struct twl4030_platform_data omap3logic_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
@@ -92,6 +99,7 @@
 	/* platform_data for children goes here */
 	.gpio		= &omap3logic_gpio_data,
 	.vmmc1		= &omap3logic_vmmc1,
+	.usb		= &omap3logic_usb_data,
 };
 
 static int __init omap3logic_i2c_init(void)
@@ -185,6 +193,20 @@
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+	/* mUSB */
+	OMAP3_MUX(HSUSB0_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_STP, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+	OMAP3_MUX(HSUSB0_DIR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_NXT, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(HSUSB0_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #endif
@@ -205,6 +227,8 @@
 	board_mmc_init();
 	board_smsc911x_init();
 
+	usb_musb_init(NULL);
+
 	/* Ensure SDRC pins are mux'd for self-refresh */
 	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
 	omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index 4dffc95..4396bae 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -42,7 +42,7 @@
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
@@ -92,9 +92,6 @@
 #define LCD_PANEL_BKLIGHT_GPIO	210
 #define ENABLE_VPLL2_DEV_GRP	0xE0
 
-static int lcd_enabled;
-static int dvi_enabled;
-
 static void __init omap3_stalker_display_init(void)
 {
 	return;
@@ -122,32 +119,14 @@
 	.platform_disable	= omap3_stalker_disable_tv,
 };
 
-static int omap3_stalker_enable_dvi(struct omap_dss_device *dssdev)
-{
-	if (lcd_enabled) {
-		printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
-		return -EINVAL;
-	}
-	gpio_set_value(DSS_ENABLE_GPIO, 1);
-	dvi_enabled = 1;
-	return 0;
-}
-
-static void omap3_stalker_disable_dvi(struct omap_dss_device *dssdev)
-{
-	gpio_set_value(DSS_ENABLE_GPIO, 0);
-	dvi_enabled = 0;
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
-	.platform_enable	= omap3_stalker_enable_dvi,
-	.platform_disable	= omap3_stalker_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+	.power_down_gpio	= DSS_ENABLE_GPIO,
 };
 
 static struct omap_dss_device omap3_stalker_dvi_device = {
 	.name			= "dvi",
 	.type			= OMAP_DISPLAY_TYPE_DPI,
-	.driver_name		= "dvi",
+	.driver_name		= "tfp410",
 	.data			= &dvi_panel,
 	.phy.dpi.data_lines	= 24,
 };
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 1b782ba..68b8fc9 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -28,6 +28,7 @@
 #include <linux/mfd/twl6040.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
+#include <linux/ti_wilink_st.h>
 #include <linux/wl12xx.h>
 #include <linux/platform_data/omap-abe-twl6040.h>
 
@@ -42,7 +43,7 @@
 #include "common.h"
 #include <plat/usb.h>
 #include <plat/mmc.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 
 #include "hsmmc.h"
 #include "control.h"
@@ -58,12 +59,21 @@
 #define HDMI_GPIO_HPD  63 /* Hotplug detect */
 
 /* wl127x BT, FM, GPS connectivity chip */
-static int wl1271_gpios[] = {46, -1, -1};
+static struct ti_st_plat_data wilink_platform_data = {
+	.nshutdown_gpio	= 46,
+	.dev_name	= "/dev/ttyO1",
+	.flow_cntrl	= 1,
+	.baud_rate	= 3000000,
+	.chip_enable	= NULL,
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+
 static struct platform_device wl1271_device = {
 	.name	= "kim",
 	.id	= -1,
 	.dev	= {
-		.platform_data	= &wl1271_gpios,
+		.platform_data	= &wilink_platform_data,
 	},
 };
 
@@ -117,6 +127,11 @@
 	},
 };
 
+static struct platform_device panda_hdmi_audio_codec = {
+	.name	= "hdmi-audio-codec",
+	.id	= -1,
+};
+
 static struct platform_device btwilink_device = {
 	.name	= "btwilink",
 	.id	= -1,
@@ -126,6 +141,7 @@
 	&leds_gpio,
 	&wl1271_device,
 	&panda_abe_audio,
+	&panda_hdmi_audio_codec,
 	&btwilink_device,
 };
 
@@ -231,60 +247,11 @@
 	},
 };
 
-struct wl12xx_platform_data omap_panda_wlan_data  __initdata = {
+static struct wl12xx_platform_data omap_panda_wlan_data  __initdata = {
 	/* PANDA ref clock is 38.4 MHz */
 	.board_ref_clock = 2,
 };
 
-static int omap4_twl6030_hsmmc_late_init(struct device *dev)
-{
-	int irq = 0;
-	struct platform_device *pdev = container_of(dev,
-				struct platform_device, dev);
-	struct omap_mmc_platform_data *pdata = dev->platform_data;
-
-	if (!pdata) {
-		dev_err(dev, "%s: NULL platform data\n", __func__);
-		return -EINVAL;
-	}
-	/* Setting MMC1 Card detect Irq */
-	if (pdev->id == 0) {
-		irq = twl6030_mmc_card_detect_config();
-		if (irq < 0) {
-			dev_err(dev, "%s: Error card detect config(%d)\n",
-				__func__, irq);
-			return irq;
-		}
-		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
-	}
-	return 0;
-}
-
-static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
-{
-	struct omap_mmc_platform_data *pdata;
-
-	/* dev can be null if CONFIG_MMC_OMAP_HS is not set */
-	if (!dev) {
-		pr_err("Failed omap4_twl6030_hsmmc_set_late_init\n");
-		return;
-	}
-	pdata = dev->platform_data;
-
-	pdata->init =	omap4_twl6030_hsmmc_late_init;
-}
-
-static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
-{
-	struct omap2_hsmmc_info *c;
-
-	omap_hsmmc_init(controllers);
-	for (c = controllers; c->mmc; c++)
-		omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
-
-	return 0;
-}
-
 static struct twl6040_codec_data twl6040_codec = {
 	/* single-step ramp for headset and handsfree */
 	.hs_left_step	= 0x0f,
@@ -323,7 +290,9 @@
 			TWL_COMMON_REGULATOR_VANA |
 			TWL_COMMON_REGULATOR_VCXIO |
 			TWL_COMMON_REGULATOR_VUSB |
-			TWL_COMMON_REGULATOR_CLK32KG);
+			TWL_COMMON_REGULATOR_CLK32KG |
+			TWL_COMMON_REGULATOR_V1V8 |
+			TWL_COMMON_REGULATOR_V2V1);
 	omap4_pmic_init("twl6030", &omap4_panda_twldata,
 			&twl6040_data, OMAP44XX_IRQ_SYS_2N);
 	omap_register_i2c_bus(2, 400, NULL, 0);
@@ -420,47 +389,22 @@
 /* Display DVI */
 #define PANDA_DVI_TFP410_POWER_DOWN_GPIO	0
 
-static int omap4_panda_enable_dvi(struct omap_dss_device *dssdev)
-{
-	gpio_set_value(dssdev->reset_gpio, 1);
-	return 0;
-}
-
-static void omap4_panda_disable_dvi(struct omap_dss_device *dssdev)
-{
-	gpio_set_value(dssdev->reset_gpio, 0);
-}
-
 /* Using generic display panel */
-static struct panel_dvi_platform_data omap4_dvi_panel = {
-	.platform_enable	= omap4_panda_enable_dvi,
-	.platform_disable	= omap4_panda_disable_dvi,
-	.i2c_bus_num = 3,
+static struct tfp410_platform_data omap4_dvi_panel = {
+	.i2c_bus_num		= 3,
+	.power_down_gpio	= PANDA_DVI_TFP410_POWER_DOWN_GPIO,
 };
 
-struct omap_dss_device omap4_panda_dvi_device = {
+static struct omap_dss_device omap4_panda_dvi_device = {
 	.type			= OMAP_DISPLAY_TYPE_DPI,
 	.name			= "dvi",
-	.driver_name		= "dvi",
+	.driver_name		= "tfp410",
 	.data			= &omap4_dvi_panel,
 	.phy.dpi.data_lines	= 24,
 	.reset_gpio		= PANDA_DVI_TFP410_POWER_DOWN_GPIO,
 	.channel		= OMAP_DSS_CHANNEL_LCD2,
 };
 
-int __init omap4_panda_dvi_init(void)
-{
-	int r;
-
-	/* Requesting TFP410 DVI GPIO and disabling it, at bootup */
-	r = gpio_request_one(omap4_panda_dvi_device.reset_gpio,
-				GPIOF_OUT_INIT_LOW, "DVI PD");
-	if (r)
-		pr_err("Failed to get DVI powerdown GPIO\n");
-
-	return r;
-}
-
 static struct gpio panda_hdmi_gpios[] = {
 	{ HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
 	{ HDMI_GPIO_LS_OE,	GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
@@ -509,13 +453,8 @@
 	.default_device	= &omap4_panda_dvi_device,
 };
 
-void __init omap4_panda_display_init(void)
+static void __init omap4_panda_display_init(void)
 {
-	int r;
-
-	r = omap4_panda_dvi_init();
-	if (r)
-		pr_err("error initializing panda DVI\n");
 
 	omap_display_init(&omap4_panda_dss_data);
 
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 33aa391..5527c19 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -46,7 +46,7 @@
 #include "common.h"
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
 #include <plat/gpmc.h>
 #include <mach/hardware.h>
 #include <plat/nand.h>
@@ -167,32 +167,15 @@
 	gpio_export(OVERO_GPIO_LCD_BL, 0);
 }
 
-static int overo_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
-	if (lcd_enabled) {
-		printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
-		return -EINVAL;
-	}
-	dvi_enabled = 1;
-
-	return 0;
-}
-
-static void overo_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
-	dvi_enabled = 0;
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
-	.platform_enable	= overo_panel_enable_dvi,
-	.platform_disable	= overo_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
 	.i2c_bus_num		= 3,
+	.power_down_gpio	= -1,
 };
 
 static struct omap_dss_device overo_dvi_device = {
 	.name			= "dvi",
 	.type			= OMAP_DISPLAY_TYPE_DPI,
-	.driver_name		= "dvi",
+	.driver_name		= "tfp410",
 	.data			= &dvi_panel,
 	.phy.dpi.data_lines	= 24,
 };
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index d87ee06..ff53dec 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -44,6 +44,7 @@
 #include <linux/leds-lp5523.h>
 
 #include <../drivers/staging/iio/light/tsl2563.h>
+#include <linux/lis3lv02d.h>
 
 #include "mux.h"
 #include "hsmmc.h"
@@ -63,6 +64,9 @@
 #define RX51_TSC2005_RESET_GPIO         104
 #define RX51_TSC2005_IRQ_GPIO           100
 
+#define LIS302_IRQ1_GPIO 181
+#define LIS302_IRQ2_GPIO 180  /* Not yet in use */
+
 /* list all spi devices here */
 enum {
 	RX51_SPI_WL1251,
@@ -73,6 +77,77 @@
 static struct wl12xx_platform_data wl1251_pdata;
 static struct tsc2005_platform_data tsc2005_pdata;
 
+#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
+static int lis302_setup(void)
+{
+	int err;
+	int irq1 = LIS302_IRQ1_GPIO;
+	int irq2 = LIS302_IRQ2_GPIO;
+
+	/* gpio for interrupt pin 1 */
+	err = gpio_request(irq1, "lis3lv02dl_irq1");
+	if (err) {
+		printk(KERN_ERR "lis3lv02dl: gpio request failed\n");
+		goto out;
+	}
+
+	/* gpio for interrupt pin 2 */
+	err = gpio_request(irq2, "lis3lv02dl_irq2");
+	if (err) {
+		gpio_free(irq1);
+		printk(KERN_ERR "lis3lv02dl: gpio request failed\n");
+		goto out;
+	}
+
+	gpio_direction_input(irq1);
+	gpio_direction_input(irq2);
+
+out:
+	return err;
+}
+
+static int lis302_release(void)
+{
+	gpio_free(LIS302_IRQ1_GPIO);
+	gpio_free(LIS302_IRQ2_GPIO);
+
+	return 0;
+}
+
+static struct lis3lv02d_platform_data rx51_lis3lv02d_data = {
+	.click_flags    = LIS3_CLICK_SINGLE_X | LIS3_CLICK_SINGLE_Y |
+			  LIS3_CLICK_SINGLE_Z,
+	/* Limits are 0.5g * value */
+	.click_thresh_x = 8,
+	.click_thresh_y = 8,
+	.click_thresh_z = 10,
+	/* Click must be longer than time limit */
+	.click_time_limit = 9,
+	/* Kind of debounce filter */
+	.click_latency    = 50,
+
+	/* Limits for all axis. millig-value / 18 to get HW values */
+	.wakeup_flags = LIS3_WAKEUP_X_HI | LIS3_WAKEUP_Y_HI,
+	.wakeup_thresh = 800 / 18,
+	.wakeup_flags2 = LIS3_WAKEUP_Z_HI ,
+	.wakeup_thresh2 = 900 / 18,
+
+	.hipass_ctrl = LIS3_HIPASS1_DISABLE | LIS3_HIPASS2_DISABLE,
+
+	/* Interrupt line 2 for click detection, line 1 for thresholds */
+	.irq_cfg = LIS3_IRQ2_CLICK | LIS3_IRQ1_FF_WU_12,
+
+	.axis_x = LIS3_DEV_X,
+	.axis_y = LIS3_INV_DEV_Y,
+	.axis_z = LIS3_INV_DEV_Z,
+	.setup_resources = lis302_setup,
+	.release_resources = lis302_release,
+	.st_min_limits = {-32, 3, 3},
+	.st_max_limits = {-3, 32, 32},
+	.irq2 = OMAP_GPIO_IRQ(LIS302_IRQ2_GPIO),
+};
+#endif
+
 #if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE)
 static struct tsl2563_platform_data rx51_tsl2563_platform_data = {
 	.cover_comp_gain = 16,
@@ -872,11 +947,11 @@
 	.resource_config = twl4030_rconfig,
 };
 
-struct twl4030_vibra_data rx51_vibra_data __initdata = {
+static struct twl4030_vibra_data rx51_vibra_data __initdata = {
 	.coexist	= 0,
 };
 
-struct twl4030_audio_data rx51_audio_data __initdata = {
+static struct twl4030_audio_data rx51_audio_data __initdata = {
 	.audio_mclk	= 26000000,
 	.vibra		= &rx51_vibra_data,
 };
@@ -950,6 +1025,16 @@
 	}
 };
 
+static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_3[] = {
+#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
+	{
+		I2C_BOARD_INFO("lis3lv02d", 0x1d),
+		.platform_data = &rx51_lis3lv02d_data,
+		.irq = OMAP_GPIO_IRQ(LIS302_IRQ1_GPIO),
+	},
+#endif
+};
+
 static int __init rx51_i2c_init(void)
 {
 	if ((system_rev >= SYSTEM_REV_S_USES_VAUX3 && system_rev < 0x100) ||
@@ -971,7 +1056,8 @@
 	omap_pmic_init(1, 2200, "twl5030", INT_34XX_SYS_NIRQ, &rx51_twldata);
 	omap_register_i2c_bus(2, 100, rx51_peripherals_i2c_board_info_2,
 			      ARRAY_SIZE(rx51_peripherals_i2c_board_info_2));
-	omap_register_i2c_bus(3, 400, NULL, 0);
+	omap_register_i2c_bus(3, 400, rx51_peripherals_i2c_board_info_3,
+			      ARRAY_SIZE(rx51_peripherals_i2c_board_info_3));
 	return 0;
 }
 
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index 27f01f0..2da92a6 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -59,25 +59,24 @@
 };
 
 /*
- * cpuidle C-states definition override from the default values.
- * The 'exit_latency' field is the sum of sleep and wake-up latencies.
- */
-static struct cpuidle_params rx51_cpuidle_params[] = {
-	/* C1 */
-	{110 + 162, 5 , 1},
-	/* C2 */
-	{106 + 180, 309, 1},
-	/* C3 */
-	{107 + 410, 46057, 0},
-	/* C4 */
-	{121 + 3374, 46057, 0},
-	/* C5 */
-	{855 + 1146, 46057, 1},
-	/* C6 */
-	{7580 + 4134, 484329, 0},
-	/* C7 */
-	{7505 + 15274, 484329, 1},
-};
+ * cpuidle C-states definition for rx51.
+ *
+ * The 'exit_latency' field is the sum of sleep
+ * and wake-up latencies.
+
+    ---------------------------------------------
+   | state |  exit_latency  |  target_residency  |
+    ---------------------------------------------
+   |  C1   |    110 + 162   |            5       |
+   |  C2   |    106 + 180   |          309       |
+   |  C3   |    107 + 410   |        46057       |
+   |  C4   |    121 + 3374  |        46057       |
+   |  C5   |    855 + 1146  |        46057       |
+   |  C6   |   7580 + 4134  |       484329       |
+   |  C7   |   7505 + 15274 |       484329       |
+    ---------------------------------------------
+
+*/
 
 extern void __init rx51_peripherals_init(void);
 
@@ -98,7 +97,6 @@
 	struct omap_sdrc_params *sdrc_params;
 
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-	omap3_pm_init_cpuidle(rx51_cpuidle_params);
 	omap_serial_init();
 
 	sdrc_params = nokia_get_sdram_timings();
diff --git a/arch/arm/mach-omap2/board-zoom-display.c b/arch/arm/mach-omap2/board-zoom-display.c
index a43a765..28187f1 100644
--- a/arch/arm/mach-omap2/board-zoom-display.c
+++ b/arch/arm/mach-omap2/board-zoom-display.c
@@ -16,6 +16,7 @@
 #include <linux/spi/spi.h>
 #include <plat/mcspi.h>
 #include <video/omapdss.h>
+#include <mach/board-zoom.h>
 
 #define LCD_PANEL_RESET_GPIO_PROD	96
 #define LCD_PANEL_RESET_GPIO_PILOT	55
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index d9f4931..5c4e665 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -439,7 +439,7 @@
 		clk->ops->disable(clk);
 	}
 	if (clk->clkdm != NULL)
-		pwrdm_clkdm_state_switch(clk->clkdm);
+		pwrdm_state_switch(clk->clkdm->pwrdm.ptr);
 }
 #endif
 
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index f4a626f7..4e1a3b0 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -1,7 +1,7 @@
 /*
  * OMAP3 clock data
  *
- * Copyright (C) 2007-2010 Texas Instruments, Inc.
+ * Copyright (C) 2007-2010, 2012 Texas Instruments, Inc.
  * Copyright (C) 2007-2011 Nokia Corporation
  *
  * Written by Paul Walmsley
@@ -1640,6 +1640,7 @@
 	.name		= "hdq_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &core_12m_fck,
+	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP3430_EN_HDQ_SHIFT,
 	.recalc		= &followparent_recalc,
@@ -3294,8 +3295,8 @@
 	CLK(NULL,	"gfx_l3_ick",	&gfx_l3_ick,	CK_3430ES1),
 	CLK(NULL,	"gfx_cg1_ck",	&gfx_cg1_ck,	CK_3430ES1),
 	CLK(NULL,	"gfx_cg2_ck",	&gfx_cg2_ck,	CK_3430ES1),
-	CLK(NULL,	"sgx_fck",	&sgx_fck,	CK_3430ES2PLUS | CK_3517 | CK_36XX),
-	CLK(NULL,	"sgx_ick",	&sgx_ick,	CK_3430ES2PLUS | CK_3517 | CK_36XX),
+	CLK(NULL,	"sgx_fck",	&sgx_fck,	CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+	CLK(NULL,	"sgx_ick",	&sgx_ick,	CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
 	CLK(NULL,	"d2d_26m_fck",	&d2d_26m_fck,	CK_3430ES1),
 	CLK(NULL,	"modem_fck",	&modem_fck,	CK_34XX | CK_36XX),
 	CLK(NULL,	"sad2d_ick",	&sad2d_ick,	CK_34XX | CK_36XX),
@@ -3419,7 +3420,7 @@
 	CLK(NULL,	"per_48m_fck",	&per_48m_fck,	CK_3XXX),
 	CLK(NULL,	"uart3_fck",	&uart3_fck,	CK_3XXX),
 	CLK(NULL,	"uart4_fck",	&uart4_fck,	CK_36XX),
-	CLK(NULL,	"uart4_fck",	&uart4_fck_am35xx, CK_3505 | CK_3517),
+	CLK(NULL,	"uart4_fck",	&uart4_fck_am35xx, CK_AM35XX),
 	CLK(NULL,	"gpt2_fck",	&gpt2_fck,	CK_3XXX),
 	CLK(NULL,	"gpt3_fck",	&gpt3_fck,	CK_3XXX),
 	CLK(NULL,	"gpt4_fck",	&gpt4_fck,	CK_3XXX),
@@ -3513,21 +3514,9 @@
 	struct omap_clk *c;
 	u32 cpu_clkflg = 0;
 
-	/*
-	 * 3505 must be tested before 3517, since 3517 returns true
-	 * for both AM3517 chips and AM3517 family chips, which
-	 * includes 3505.  Unfortunately there's no obvious family
-	 * test for 3517/3505 :-(
-	 */
-	if (cpu_is_omap3505()) {
+	if (cpu_is_omap3517()) {
 		cpu_mask = RATE_IN_34XX;
-		cpu_clkflg = CK_3505;
-	} else if (cpu_is_omap3517()) {
-		cpu_mask = RATE_IN_34XX;
-		cpu_clkflg = CK_3517;
-	} else if (cpu_is_omap3505()) {
-		cpu_mask = RATE_IN_34XX;
-		cpu_clkflg = CK_3505;
+		cpu_clkflg = CK_AM35XX;
 	} else if (cpu_is_omap3630()) {
 		cpu_mask = (RATE_IN_34XX | RATE_IN_36XX);
 		cpu_clkflg = CK_36XX;
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index fa6ea65..2172f66 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3355,17 +3355,6 @@
 	CLK(NULL,	"auxclk5_ck",			&auxclk5_ck,	CK_443X),
 	CLK(NULL,	"auxclkreq5_ck",		&auxclkreq5_ck,	CK_443X),
 	CLK(NULL,	"gpmc_ck",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt1_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt2_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt3_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt4_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt5_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt6_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt7_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt8_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt9_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt10_ick",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpt11_ick",			&dummy_ck,	CK_443X),
 	CLK("omap_i2c.1",	"ick",				&dummy_ck,	CK_443X),
 	CLK("omap_i2c.2",	"ick",				&dummy_ck,	CK_443X),
 	CLK("omap_i2c.3",	"ick",				&dummy_ck,	CK_443X),
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index ad07689..8664f5a 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -840,7 +840,7 @@
 	spin_lock_irqsave(&clkdm->lock, flags);
 	clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
 	arch_clkdm->clkdm_allow_idle(clkdm);
-	pwrdm_clkdm_state_switch(clkdm);
+	pwrdm_state_switch(clkdm->pwrdm.ptr);
 	spin_unlock_irqrestore(&clkdm->lock, flags);
 }
 
@@ -924,8 +924,7 @@
 
 	spin_lock_irqsave(&clkdm->lock, flags);
 	arch_clkdm->clkdm_clk_enable(clkdm);
-	pwrdm_wait_transition(clkdm->pwrdm.ptr);
-	pwrdm_clkdm_state_switch(clkdm);
+	pwrdm_state_switch(clkdm->pwrdm.ptr);
 	spin_unlock_irqrestore(&clkdm->lock, flags);
 
 	pr_debug("clockdomain: clkdm %s: enabled\n", clkdm->name);
@@ -950,7 +949,7 @@
 
 	spin_lock_irqsave(&clkdm->lock, flags);
 	arch_clkdm->clkdm_clk_disable(clkdm);
-	pwrdm_clkdm_state_switch(clkdm);
+	pwrdm_state_switch(clkdm->pwrdm.ptr);
 	spin_unlock_irqrestore(&clkdm->lock, flags);
 
 	pr_debug("clockdomain: clkdm %s: disabled\n", clkdm->name);
diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c
index 935c7f0..4f04dd1 100644
--- a/arch/arm/mach-omap2/clockdomain44xx.c
+++ b/arch/arm/mach-omap2/clockdomain44xx.c
@@ -51,6 +51,9 @@
 	struct clkdm_dep *cd;
 	u32 mask = 0;
 
+	if (!clkdm->prcm_partition)
+		return 0;
+
 	for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
 		if (!cd->clkdm)
 			continue; /* only happens if data is erroneous */
@@ -103,6 +106,9 @@
 {
 	bool hwsup = false;
 
+	if (!clkdm->prcm_partition)
+		return 0;
+
 	hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
 					clkdm->cm_inst, clkdm->clkdm_offs);
 
diff --git a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
index 0a6a048..839145e1 100644
--- a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
+++ b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
@@ -89,13 +89,3 @@
 	.pwrdm		= { .name = "wkup_pwrdm" },
 	.dep_bit	= OMAP_EN_WKUP_SHIFT,
 };
-
-struct clockdomain prm_common_clkdm = {
-	.name		= "prm_clkdm",
-	.pwrdm		= { .name = "wkup_pwrdm" },
-};
-
-struct clockdomain cm_common_clkdm = {
-	.name		= "cm_clkdm",
-	.pwrdm		= { .name = "core_pwrdm" },
-};
diff --git a/arch/arm/mach-omap2/clockdomains3xxx_data.c b/arch/arm/mach-omap2/clockdomains3xxx_data.c
index b84e138..6038adb 100644
--- a/arch/arm/mach-omap2/clockdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/clockdomains3xxx_data.c
@@ -53,9 +53,9 @@
  * 3430ES2 PM_WKDEP_SGX: adds IVA2, removes CORE
  */
 static struct clkdm_dep gfx_sgx_3xxx_wkdeps[] = {
-	{ .clkdm_name = "iva2_clkdm", },
-	{ .clkdm_name = "mpu_clkdm", },
-	{ .clkdm_name = "wkup_clkdm", },
+	{ .clkdm_name = "iva2_clkdm" },
+	{ .clkdm_name = "mpu_clkdm" },
+	{ .clkdm_name = "wkup_clkdm" },
 	{ NULL },
 };
 
diff --git a/arch/arm/mach-omap2/clockdomains44xx_data.c b/arch/arm/mach-omap2/clockdomains44xx_data.c
index bd7ed13..c534258 100644
--- a/arch/arm/mach-omap2/clockdomains44xx_data.c
+++ b/arch/arm/mach-omap2/clockdomains44xx_data.c
@@ -430,6 +430,8 @@
 	&l4_wkup_44xx_clkdm,
 	&emu_sys_44xx_clkdm,
 	&l3_dma_44xx_clkdm,
+	&prm_common_clkdm,
+	&cm_common_clkdm,
 	NULL
 };
 
diff --git a/arch/arm/mach-omap2/clockdomains_common_data.c b/arch/arm/mach-omap2/clockdomains_common_data.c
new file mode 100644
index 0000000..615b1f0
--- /dev/null
+++ b/arch/arm/mach-omap2/clockdomains_common_data.c
@@ -0,0 +1,24 @@
+/*
+ * OMAP2+-common clockdomain data
+ *
+ * Copyright (C) 2008-2012 Texas Instruments, Inc.
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Paul Walmsley, Jouni Högander
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include "clockdomain.h"
+
+/* These are implicit clockdomains - they are never defined as such in TRM */
+struct clockdomain prm_common_clkdm = {
+	.name		= "prm_clkdm",
+	.pwrdm		= { .name = "wkup_pwrdm" },
+};
+
+struct clockdomain cm_common_clkdm = {
+	.name		= "cm_clkdm",
+	.pwrdm		= { .name = "core_pwrdm" },
+};
diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index b912759..8083a8c 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -79,7 +79,7 @@
 
 /* CM_CLKSEL1_PLL_IVA2 */
 #define OMAP3430_IVA2_CLK_SRC_SHIFT			19
-#define OMAP3430_IVA2_CLK_SRC_MASK			(0x3 << 19)
+#define OMAP3430_IVA2_CLK_SRC_MASK			(0x7 << 19)
 #define OMAP3430_IVA2_DPLL_MULT_SHIFT			8
 #define OMAP3430_IVA2_DPLL_MULT_MASK			(0x7ff << 8)
 #define OMAP3430_IVA2_DPLL_DIV_SHIFT			0
@@ -124,7 +124,7 @@
 
 /* CM_CLKSEL1_PLL_MPU */
 #define OMAP3430_MPU_CLK_SRC_SHIFT			19
-#define OMAP3430_MPU_CLK_SRC_MASK			(0x3 << 19)
+#define OMAP3430_MPU_CLK_SRC_MASK			(0x7 << 19)
 #define OMAP3430_MPU_DPLL_MULT_SHIFT			8
 #define OMAP3430_MPU_DPLL_MULT_MASK			(0x7ff << 8)
 #define OMAP3430_MPU_DPLL_DIV_SHIFT			0
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
index bd8810c..8c86d29 100644
--- a/arch/arm/mach-omap2/cminst44xx.c
+++ b/arch/arm/mach-omap2/cminst44xx.c
@@ -32,6 +32,7 @@
 #include "prcm44xx.h"
 #include "prm44xx.h"
 #include "prcm_mpu44xx.h"
+#include "prcm-common.h"
 
 /*
  * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
@@ -49,14 +50,21 @@
 #define CLKCTRL_IDLEST_INTERFACE_IDLE		0x2
 #define CLKCTRL_IDLEST_DISABLED			0x3
 
-static u32 _cm_bases[OMAP4_MAX_PRCM_PARTITIONS] = {
-	[OMAP4430_INVALID_PRCM_PARTITION]	= 0,
-	[OMAP4430_PRM_PARTITION]		= OMAP4430_PRM_BASE,
-	[OMAP4430_CM1_PARTITION]		= OMAP4430_CM1_BASE,
-	[OMAP4430_CM2_PARTITION]		= OMAP4430_CM2_BASE,
-	[OMAP4430_SCRM_PARTITION]		= 0,
-	[OMAP4430_PRCM_MPU_PARTITION]		= OMAP4430_PRCM_MPU_BASE,
-};
+static void __iomem *_cm_bases[OMAP4_MAX_PRCM_PARTITIONS];
+
+/**
+ * omap_cm_base_init - Populates the cm partitions
+ *
+ * Populates the base addresses of the _cm_bases
+ * array used for read/write of cm module registers.
+ */
+void omap_cm_base_init(void)
+{
+	_cm_bases[OMAP4430_PRM_PARTITION] = prm_base;
+	_cm_bases[OMAP4430_CM1_PARTITION] = cm_base;
+	_cm_bases[OMAP4430_CM2_PARTITION] = cm2_base;
+	_cm_bases[OMAP4430_PRCM_MPU_PARTITION] = prcm_mpu_base;
+}
 
 /* Private functions */
 
@@ -106,7 +114,7 @@
 	BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
 	       part == OMAP4430_INVALID_PRCM_PARTITION ||
 	       !_cm_bases[part]);
-	return __raw_readl(OMAP2_L4_IO_ADDRESS(_cm_bases[part] + inst + idx));
+	return __raw_readl(_cm_bases[part] + inst + idx);
 }
 
 /* Write into a register in a CM instance */
@@ -115,7 +123,7 @@
 	BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
 	       part == OMAP4430_INVALID_PRCM_PARTITION ||
 	       !_cm_bases[part]);
-	__raw_writel(val, OMAP2_L4_IO_ADDRESS(_cm_bases[part] + inst + idx));
+	__raw_writel(val, _cm_bases[part] + inst + idx);
 }
 
 /* Read-modify-write a register in CM1. Caller must lock */
diff --git a/arch/arm/mach-omap2/common.c b/arch/arm/mach-omap2/common.c
index 1549c11..8a6953a 100644
--- a/arch/arm/mach-omap2/common.c
+++ b/arch/arm/mach-omap2/common.c
@@ -166,6 +166,7 @@
 	.prm	= OMAP2_L4_IO_ADDRESS(OMAP4430_PRM_BASE),
 	.cm	= OMAP2_L4_IO_ADDRESS(OMAP4430_CM_BASE),
 	.cm2	= OMAP2_L4_IO_ADDRESS(OMAP4430_CM2_BASE),
+	.prcm_mpu	= OMAP2_L4_IO_ADDRESS(OMAP4430_PRCM_MPU_BASE),
 };
 
 void __init omap2_set_globals_443x(void)
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 57da7f4..d6c9e61 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -27,6 +27,7 @@
 #ifndef __ASSEMBLER__
 
 #include <linux/delay.h>
+#include <linux/i2c/twl.h>
 #include <plat/common.h>
 #include <asm/proc-fns.h>
 
@@ -111,6 +112,7 @@
 	void __iomem	*prm;            /* Power and Reset Management */
 	void __iomem	*cm;             /* Clock Management */
 	void __iomem	*cm2;
+	void __iomem	*prcm_mpu;
 };
 
 void omap2_set_globals_242x(void);
@@ -134,8 +136,6 @@
 void ti81xx_map_io(void);
 void omap_barriers_init(void);
 
-extern void __init omap_init_consistent_dma_size(void);
-
 /**
  * omap_test_timeout - busy-loop, testing a condition
  * @cond: condition to test until it evaluates to true
@@ -254,6 +254,8 @@
 struct omap_sdrc_params;
 extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
 				      struct omap_sdrc_params *sdrc_cs1);
+struct omap2_hsmmc_info;
+extern int omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers);
 
 #endif /* __ASSEMBLER__ */
 #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 5358664..207bc1c 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -38,40 +38,44 @@
 
 #ifdef CONFIG_CPU_IDLE
 
-/*
- * The latencies/thresholds for various C states have
- * to be configured from the respective board files.
- * These are some default values (which might not provide
- * the best power savings) used on boards which do not
- * pass these details from the board file.
- */
-static struct cpuidle_params cpuidle_params_table[] = {
-	/* C1 */
-	{2 + 2, 5, 1},
-	/* C2 */
-	{10 + 10, 30, 1},
-	/* C3 */
-	{50 + 50, 300, 1},
-	/* C4 */
-	{1500 + 1800, 4000, 1},
-	/* C5 */
-	{2500 + 7500, 12000, 1},
-	/* C6 */
-	{3000 + 8500, 15000, 1},
-	/* C7 */
-	{10000 + 30000, 300000, 1},
-};
-#define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
-
 /* Mach specific information to be recorded in the C-state driver_data */
 struct omap3_idle_statedata {
 	u32 mpu_state;
 	u32 core_state;
-	u8 valid;
 };
-struct omap3_idle_statedata omap3_idle_data[OMAP3_NUM_STATES];
 
-struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
+static struct omap3_idle_statedata omap3_idle_data[] = {
+	{
+		.mpu_state = PWRDM_POWER_ON,
+		.core_state = PWRDM_POWER_ON,
+	},
+	{
+		.mpu_state = PWRDM_POWER_ON,
+		.core_state = PWRDM_POWER_ON,
+	},
+	{
+		.mpu_state = PWRDM_POWER_RET,
+		.core_state = PWRDM_POWER_ON,
+	},
+	{
+		.mpu_state = PWRDM_POWER_OFF,
+		.core_state = PWRDM_POWER_ON,
+	},
+	{
+		.mpu_state = PWRDM_POWER_RET,
+		.core_state = PWRDM_POWER_RET,
+	},
+	{
+		.mpu_state = PWRDM_POWER_OFF,
+		.core_state = PWRDM_POWER_RET,
+	},
+	{
+		.mpu_state = PWRDM_POWER_OFF,
+		.core_state = PWRDM_POWER_OFF,
+	},
+};
+
+static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
 
 static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
 				struct clockdomain *clkdm)
@@ -91,8 +95,7 @@
 				struct cpuidle_driver *drv,
 				int index)
 {
-	struct omap3_idle_statedata *cx =
-			cpuidle_get_statedata(&dev->states_usage[index]);
+	struct omap3_idle_statedata *cx = &omap3_idle_data[index];
 	u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
 
 	local_fiq_disable();
@@ -169,14 +172,12 @@
  * if it satisfies the enable_off_mode condition.
  */
 static int next_valid_state(struct cpuidle_device *dev,
-			struct cpuidle_driver *drv,
-				int index)
+			    struct cpuidle_driver *drv, int index)
 {
-	struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
-	struct cpuidle_state *curr = &drv->states[index];
-	struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
+	struct omap3_idle_statedata *cx = &omap3_idle_data[index];
 	u32 mpu_deepest_state = PWRDM_POWER_RET;
 	u32 core_deepest_state = PWRDM_POWER_RET;
+	int idx;
 	int next_index = -1;
 
 	if (enable_off_mode) {
@@ -191,45 +192,29 @@
 	}
 
 	/* Check if current state is valid */
-	if ((cx->valid) &&
-	    (cx->mpu_state >= mpu_deepest_state) &&
-	    (cx->core_state >= core_deepest_state)) {
+	if ((cx->mpu_state >= mpu_deepest_state) &&
+	    (cx->core_state >= core_deepest_state))
 		return index;
-	} else {
-		int idx = OMAP3_NUM_STATES - 1;
 
-		/* Reach the current state starting at highest C-state */
-		for (; idx >= 0; idx--) {
-			if (&drv->states[idx] == curr) {
-				next_index = idx;
-				break;
-			}
+	/*
+	 * Drop to next valid state.
+	 * Start search from the next (lower) state.
+	 */
+	for (idx = index - 1; idx >= 0; idx--) {
+		cx =  &omap3_idle_data[idx];
+		if ((cx->mpu_state >= mpu_deepest_state) &&
+		    (cx->core_state >= core_deepest_state)) {
+			next_index = idx;
+			break;
 		}
-
-		/* Should never hit this condition */
-		WARN_ON(next_index == -1);
-
-		/*
-		 * Drop to next valid state.
-		 * Start search from the next (lower) state.
-		 */
-		idx--;
-		for (; idx >= 0; idx--) {
-			cx = cpuidle_get_statedata(&dev->states_usage[idx]);
-			if ((cx->valid) &&
-			    (cx->mpu_state >= mpu_deepest_state) &&
-			    (cx->core_state >= core_deepest_state)) {
-				next_index = idx;
-				break;
-			}
-		}
-		/*
-		 * C1 is always valid.
-		 * So, no need to check for 'next_index == -1' outside
-		 * this loop.
-		 */
 	}
 
+	/*
+	 * C1 is always valid.
+	 * So, no need to check for 'next_index == -1' outside
+	 * this loop.
+	 */
+
 	return next_index;
 }
 
@@ -273,7 +258,7 @@
 	 * Prevent PER off if CORE is not in retention or off as this
 	 * would disable PER wakeups completely.
 	 */
-	cx = cpuidle_get_statedata(&dev->states_usage[index]);
+	cx = &omap3_idle_data[index];
 	core_next_state = cx->core_state;
 	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
 	if ((per_next_state == PWRDM_POWER_OFF) &&
@@ -298,57 +283,71 @@
 
 DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
 
-void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params)
-{
-	int i;
-
-	if (!cpuidle_board_params)
-		return;
-
-	for (i = 0; i < OMAP3_NUM_STATES; i++) {
-		cpuidle_params_table[i].valid =	cpuidle_board_params[i].valid;
-		cpuidle_params_table[i].exit_latency =
-			cpuidle_board_params[i].exit_latency;
-		cpuidle_params_table[i].target_residency =
-			cpuidle_board_params[i].target_residency;
-	}
-	return;
-}
-
 struct cpuidle_driver omap3_idle_driver = {
 	.name = 	"omap3_idle",
 	.owner = 	THIS_MODULE,
+	.states = {
+		{
+			.enter		  = omap3_enter_idle,
+			.exit_latency	  = 2 + 2,
+			.target_residency = 5,
+			.flags		  = CPUIDLE_FLAG_TIME_VALID,
+			.name		  = "C1",
+			.desc		  = "MPU ON + CORE ON",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 10 + 10,
+			.target_residency = 30,
+			.flags		  = CPUIDLE_FLAG_TIME_VALID,
+			.name		  = "C2",
+			.desc		  = "MPU ON + CORE ON",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 50 + 50,
+			.target_residency = 300,
+			.flags		  = CPUIDLE_FLAG_TIME_VALID,
+			.name		  = "C3",
+			.desc		  = "MPU RET + CORE ON",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 1500 + 1800,
+			.target_residency = 4000,
+			.flags		  = CPUIDLE_FLAG_TIME_VALID,
+			.name		  = "C4",
+			.desc		  = "MPU OFF + CORE ON",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 2500 + 7500,
+			.target_residency = 12000,
+			.flags		  = CPUIDLE_FLAG_TIME_VALID,
+			.name		  = "C5",
+			.desc		  = "MPU RET + CORE RET",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 3000 + 8500,
+			.target_residency = 15000,
+			.flags		  = CPUIDLE_FLAG_TIME_VALID,
+			.name		  = "C6",
+			.desc		  = "MPU OFF + CORE RET",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 10000 + 30000,
+			.target_residency = 30000,
+			.flags		  = CPUIDLE_FLAG_TIME_VALID,
+			.name		  = "C7",
+			.desc		  = "MPU OFF + CORE OFF",
+		},
+	},
+	.state_count = ARRAY_SIZE(omap3_idle_data),
+	.safe_state_index = 0,
 };
 
-/* Helper to fill the C-state common data*/
-static inline void _fill_cstate(struct cpuidle_driver *drv,
-					int idx, const char *descr)
-{
-	struct cpuidle_state *state = &drv->states[idx];
-
-	state->exit_latency	= cpuidle_params_table[idx].exit_latency;
-	state->target_residency	= cpuidle_params_table[idx].target_residency;
-	state->flags		= CPUIDLE_FLAG_TIME_VALID;
-	state->enter		= omap3_enter_idle_bm;
-	sprintf(state->name, "C%d", idx + 1);
-	strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
-
-}
-
-/* Helper to register the driver_data */
-static inline struct omap3_idle_statedata *_fill_cstate_usage(
-					struct cpuidle_device *dev,
-					int idx)
-{
-	struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
-
-	cx->valid		= cpuidle_params_table[idx].valid;
-	cpuidle_set_statedata(state_usage, cx);
-
-	return cx;
-}
-
 /**
  * omap3_idle_init - Init routine for OMAP3 idle
  *
@@ -358,77 +357,20 @@
 int __init omap3_idle_init(void)
 {
 	struct cpuidle_device *dev;
-	struct cpuidle_driver *drv = &omap3_idle_driver;
-	struct omap3_idle_statedata *cx;
 
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
 	core_pd = pwrdm_lookup("core_pwrdm");
 	per_pd = pwrdm_lookup("per_pwrdm");
 	cam_pd = pwrdm_lookup("cam_pwrdm");
 
+	if (!mpu_pd || !core_pd || !per_pd || !cam_pd)
+		return -ENODEV;
 
-	drv->safe_state_index = -1;
-	dev = &per_cpu(omap3_idle_dev, smp_processor_id());
-
-	/* C1 . MPU WFI + Core active */
-	_fill_cstate(drv, 0, "MPU ON + CORE ON");
-	(&drv->states[0])->enter = omap3_enter_idle;
-	drv->safe_state_index = 0;
-	cx = _fill_cstate_usage(dev, 0);
-	cx->valid = 1;	/* C1 is always valid */
-	cx->mpu_state = PWRDM_POWER_ON;
-	cx->core_state = PWRDM_POWER_ON;
-
-	/* C2 . MPU WFI + Core inactive */
-	_fill_cstate(drv, 1, "MPU ON + CORE ON");
-	cx = _fill_cstate_usage(dev, 1);
-	cx->mpu_state = PWRDM_POWER_ON;
-	cx->core_state = PWRDM_POWER_ON;
-
-	/* C3 . MPU CSWR + Core inactive */
-	_fill_cstate(drv, 2, "MPU RET + CORE ON");
-	cx = _fill_cstate_usage(dev, 2);
-	cx->mpu_state = PWRDM_POWER_RET;
-	cx->core_state = PWRDM_POWER_ON;
-
-	/* C4 . MPU OFF + Core inactive */
-	_fill_cstate(drv, 3, "MPU OFF + CORE ON");
-	cx = _fill_cstate_usage(dev, 3);
-	cx->mpu_state = PWRDM_POWER_OFF;
-	cx->core_state = PWRDM_POWER_ON;
-
-	/* C5 . MPU RET + Core RET */
-	_fill_cstate(drv, 4, "MPU RET + CORE RET");
-	cx = _fill_cstate_usage(dev, 4);
-	cx->mpu_state = PWRDM_POWER_RET;
-	cx->core_state = PWRDM_POWER_RET;
-
-	/* C6 . MPU OFF + Core RET */
-	_fill_cstate(drv, 5, "MPU OFF + CORE RET");
-	cx = _fill_cstate_usage(dev, 5);
-	cx->mpu_state = PWRDM_POWER_OFF;
-	cx->core_state = PWRDM_POWER_RET;
-
-	/* C7 . MPU OFF + Core OFF */
-	_fill_cstate(drv, 6, "MPU OFF + CORE OFF");
-	cx = _fill_cstate_usage(dev, 6);
-	/*
-	 * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
-	 * enable OFF mode in a stable form for previous revisions.
-	 * We disable C7 state as a result.
-	 */
-	if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) {
-		cx->valid = 0;
-		pr_warn("%s: core off state C7 disabled due to i583\n",
-			__func__);
-	}
-	cx->mpu_state = PWRDM_POWER_OFF;
-	cx->core_state = PWRDM_POWER_OFF;
-
-	drv->state_count = OMAP3_NUM_STATES;
 	cpuidle_register_driver(&omap3_idle_driver);
 
-	dev->state_count = OMAP3_NUM_STATES;
+	dev = &per_cpu(omap3_idle_dev, smp_processor_id());
+	dev->cpu = 0;
+
 	if (cpuidle_register_device(dev)) {
 		printk(KERN_ERR "%s: CPUidle register device failed\n",
 		       __func__);
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index f386cbe..be1617c 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -24,26 +24,31 @@
 
 #ifdef CONFIG_CPU_IDLE
 
-/* Machine specific information to be recorded in the C-state driver_data */
+/* Machine specific information */
 struct omap4_idle_statedata {
 	u32 cpu_state;
 	u32 mpu_logic_state;
 	u32 mpu_state;
-	u8 valid;
 };
 
-static struct cpuidle_params cpuidle_params_table[] = {
-	/* C1 - CPU0 ON + CPU1 ON + MPU ON */
-	{.exit_latency = 2 + 2 , .target_residency = 5, .valid = 1},
-	/* C2- CPU0 OFF + CPU1 OFF + MPU CSWR */
-	{.exit_latency = 328 + 440 , .target_residency = 960, .valid = 1},
-	/* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
-	{.exit_latency = 460 + 518 , .target_residency = 1100, .valid = 1},
+static struct omap4_idle_statedata omap4_idle_data[] = {
+	{
+		.cpu_state = PWRDM_POWER_ON,
+		.mpu_state = PWRDM_POWER_ON,
+		.mpu_logic_state = PWRDM_POWER_RET,
+	},
+	{
+		.cpu_state = PWRDM_POWER_OFF,
+		.mpu_state = PWRDM_POWER_RET,
+		.mpu_logic_state = PWRDM_POWER_RET,
+	},
+	{
+		.cpu_state = PWRDM_POWER_OFF,
+		.mpu_state = PWRDM_POWER_RET,
+		.mpu_logic_state = PWRDM_POWER_OFF,
+	},
 };
 
-#define OMAP4_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
-
-struct omap4_idle_statedata omap4_idle_data[OMAP4_NUM_STATES];
 static struct powerdomain *mpu_pd, *cpu0_pd, *cpu1_pd;
 
 /**
@@ -60,8 +65,7 @@
 			struct cpuidle_driver *drv,
 			int index)
 {
-	struct omap4_idle_statedata *cx =
-			cpuidle_get_statedata(&dev->states_usage[index]);
+	struct omap4_idle_statedata *cx = &omap4_idle_data[index];
 	u32 cpu1_state;
 	int cpu_id = smp_processor_id();
 
@@ -78,7 +82,7 @@
 	cpu1_state = pwrdm_read_pwrst(cpu1_pd);
 	if (cpu1_state != PWRDM_POWER_OFF) {
 		index = drv->safe_state_index;
-		cx = cpuidle_get_statedata(&dev->states_usage[index]);
+		cx = &omap4_idle_data[index];
 	}
 
 	if (index > 0)
@@ -133,36 +137,39 @@
 	.name				= "omap4_idle",
 	.owner				= THIS_MODULE,
 	.en_core_tk_irqen		= 1,
+	.states = {
+		{
+			/* C1 - CPU0 ON + CPU1 ON + MPU ON */
+			.exit_latency = 2 + 2,
+			.target_residency = 5,
+			.flags = CPUIDLE_FLAG_TIME_VALID,
+			.enter = omap4_enter_idle,
+			.name = "C1",
+			.desc = "MPUSS ON"
+		},
+		{
+                        /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
+			.exit_latency = 328 + 440,
+			.target_residency = 960,
+			.flags = CPUIDLE_FLAG_TIME_VALID,
+			.enter = omap4_enter_idle,
+			.name = "C2",
+			.desc = "MPUSS CSWR",
+		},
+		{
+			/* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
+			.exit_latency = 460 + 518,
+			.target_residency = 1100,
+			.flags = CPUIDLE_FLAG_TIME_VALID,
+			.enter = omap4_enter_idle,
+			.name = "C3",
+			.desc = "MPUSS OSWR",
+		},
+	},
+	.state_count = ARRAY_SIZE(omap4_idle_data),
+	.safe_state_index = 0,
 };
 
-static inline void _fill_cstate(struct cpuidle_driver *drv,
-					int idx, const char *descr)
-{
-	struct cpuidle_state *state = &drv->states[idx];
-
-	state->exit_latency	= cpuidle_params_table[idx].exit_latency;
-	state->target_residency	= cpuidle_params_table[idx].target_residency;
-	state->flags		= CPUIDLE_FLAG_TIME_VALID;
-	state->enter		= omap4_enter_idle;
-	sprintf(state->name, "C%d", idx + 1);
-	strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
-}
-
-static inline struct omap4_idle_statedata *_fill_cstate_usage(
-					struct cpuidle_device *dev,
-					int idx)
-{
-	struct omap4_idle_statedata *cx = &omap4_idle_data[idx];
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
-
-	cx->valid		= cpuidle_params_table[idx].valid;
-	cpuidle_set_statedata(state_usage, cx);
-
-	return cx;
-}
-
-
-
 /**
  * omap4_idle_init - Init routine for OMAP4 idle
  *
@@ -171,9 +178,7 @@
  */
 int __init omap4_idle_init(void)
 {
-	struct omap4_idle_statedata *cx;
 	struct cpuidle_device *dev;
-	struct cpuidle_driver *drv = &omap4_idle_driver;
 	unsigned int cpu_id = 0;
 
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
@@ -182,42 +187,15 @@
 	if ((!mpu_pd) || (!cpu0_pd) || (!cpu1_pd))
 		return -ENODEV;
 
-
-	drv->safe_state_index = -1;
 	dev = &per_cpu(omap4_idle_dev, cpu_id);
 	dev->cpu = cpu_id;
 
-	/* C1 - CPU0 ON + CPU1 ON + MPU ON */
-	_fill_cstate(drv, 0, "MPUSS ON");
-	drv->safe_state_index = 0;
-	cx = _fill_cstate_usage(dev, 0);
-	cx->valid = 1;	/* C1 is always valid */
-	cx->cpu_state = PWRDM_POWER_ON;
-	cx->mpu_state = PWRDM_POWER_ON;
-	cx->mpu_logic_state = PWRDM_POWER_RET;
-
-	/* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
-	_fill_cstate(drv, 1, "MPUSS CSWR");
-	cx = _fill_cstate_usage(dev, 1);
-	cx->cpu_state = PWRDM_POWER_OFF;
-	cx->mpu_state = PWRDM_POWER_RET;
-	cx->mpu_logic_state = PWRDM_POWER_RET;
-
-	/* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
-	_fill_cstate(drv, 2, "MPUSS OSWR");
-	cx = _fill_cstate_usage(dev, 2);
-	cx->cpu_state = PWRDM_POWER_OFF;
-	cx->mpu_state = PWRDM_POWER_RET;
-	cx->mpu_logic_state = PWRDM_POWER_OFF;
-
-	drv->state_count = OMAP4_NUM_STATES;
 	cpuidle_register_driver(&omap4_idle_driver);
 
-	dev->state_count = OMAP4_NUM_STATES;
 	if (cpuidle_register_device(dev)) {
 		pr_err("%s: CPUidle register device failed\n", __func__);
-			return -EIO;
-		}
+		return -EIO;
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index e433603..ae62ece 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -42,7 +42,6 @@
 
 static int __init omap3_l3_init(void)
 {
-	int l;
 	struct omap_hwmod *oh;
 	struct platform_device *pdev;
 	char oh_name[L3_MODULES_MAX_LEN];
@@ -54,7 +53,7 @@
 	if (!(cpu_is_omap34xx()))
 		return -ENODEV;
 
-	l = snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main");
+	snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main");
 
 	oh = omap_hwmod_lookup(oh_name);
 
@@ -72,7 +71,7 @@
 
 static int __init omap4_l3_init(void)
 {
-	int l, i;
+	int i;
 	struct omap_hwmod *oh[3];
 	struct platform_device *pdev;
 	char oh_name[L3_MODULES_MAX_LEN];
@@ -89,7 +88,7 @@
 		return -ENODEV;
 
 	for (i = 0; i < L3_MODULES; i++) {
-		l = snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main_%d", i+1);
+		snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main_%d", i+1);
 
 		oh[i] = omap_hwmod_lookup(oh_name);
 		if (!(oh[i]))
@@ -355,6 +354,36 @@
 static inline void omap_init_dmic(void) {}
 #endif
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP_HDMI) || \
+		defined(CONFIG_SND_OMAP_SOC_OMAP_HDMI_MODULE)
+
+static struct platform_device omap_hdmi_audio = {
+	.name	= "omap-hdmi-audio",
+	.id	= -1,
+};
+
+static void __init omap_init_hdmi_audio(void)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+
+	oh = omap_hwmod_lookup("dss_hdmi");
+	if (!oh) {
+		printk(KERN_ERR "Could not look up dss_hdmi hw_mod\n");
+		return;
+	}
+
+	pdev = omap_device_build("omap-hdmi-audio-dai",
+		-1, oh, NULL, 0, NULL, 0, 0);
+	WARN(IS_ERR(pdev),
+	     "Can't build omap_device for omap-hdmi-audio-dai.\n");
+
+	platform_device_register(&omap_hdmi_audio);
+}
+#else
+static inline void omap_init_hdmi_audio(void) {}
+#endif
+
 #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 
 #include <plat/mcspi.h>
@@ -701,11 +730,15 @@
 	 * in alphabetical order so they're easier to sort through.
 	 */
 	omap_init_audio();
-	omap_init_mcpdm();
-	omap_init_dmic();
 	omap_init_camera();
+	omap_init_hdmi_audio();
 	omap_init_mbox();
-	omap_init_mcspi();
+	/* If dtb is there, the devices will be created dynamically */
+	if (!of_have_populated_dt()) {
+		omap_init_dmic();
+		omap_init_mcpdm();
+		omap_init_mcspi();
+	}
 	omap_init_pmu();
 	omap_hdq_init();
 	omap_init_sti();
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index fc56745..f0f10be 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -142,7 +142,8 @@
 
 	ai = omap3_dpll_autoidle_read(clk);
 
-	omap3_dpll_deny_idle(clk);
+	if (ai)
+		omap3_dpll_deny_idle(clk);
 
 	_omap3_dpll_write_clken(clk, DPLL_LOCKED);
 
@@ -186,8 +187,6 @@
 
 	if (ai)
 		omap3_dpll_allow_idle(clk);
-	else
-		omap3_dpll_deny_idle(clk);
 
 	return r;
 }
@@ -216,8 +215,6 @@
 
 	if (ai)
 		omap3_dpll_allow_idle(clk);
-	else
-		omap3_dpll_deny_idle(clk);
 
 	return 0;
 }
@@ -519,6 +516,9 @@
 
 	dd = clk->dpll_data;
 
+	if (!dd->autoidle_reg)
+		return -EINVAL;
+
 	v = __raw_readl(dd->autoidle_reg);
 	v &= dd->autoidle_mask;
 	v >>= __ffs(dd->autoidle_mask);
@@ -545,6 +545,12 @@
 
 	dd = clk->dpll_data;
 
+	if (!dd->autoidle_reg) {
+		pr_debug("clock: DPLL %s: autoidle not supported\n",
+			clk->name);
+		return;
+	}
+
 	/*
 	 * REVISIT: CORE DPLL can optionally enter low-power bypass
 	 * by writing 0x5 instead of 0x1.  Add some mechanism to
@@ -554,6 +560,7 @@
 	v &= ~dd->autoidle_mask;
 	v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
 	__raw_writel(v, dd->autoidle_reg);
+
 }
 
 /**
@@ -572,6 +579,12 @@
 
 	dd = clk->dpll_data;
 
+	if (!dd->autoidle_reg) {
+		pr_debug("clock: DPLL %s: autoidle not supported\n",
+			clk->name);
+		return;
+	}
+
 	v = __raw_readl(dd->autoidle_reg);
 	v &= ~dd->autoidle_mask;
 	v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
diff --git a/arch/arm/mach-omap2/dsp.c b/arch/arm/mach-omap2/dsp.c
index 74f18f2..3376388 100644
--- a/arch/arm/mach-omap2/dsp.c
+++ b/arch/arm/mach-omap2/dsp.c
@@ -57,8 +57,9 @@
 
 	if (pdata->phys_mempool_base) {
 		pdata->phys_mempool_size = CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE;
-		pr_info("%s: %x bytes @ %x\n", __func__,
-			pdata->phys_mempool_size, pdata->phys_mempool_base);
+		pr_info("%s: %llx bytes @ %llx\n", __func__,
+			(unsigned long long)pdata->phys_mempool_size,
+			(unsigned long long)pdata->phys_mempool_base);
 	}
 
 	pdev = platform_device_alloc("omap-dsp", -1);
diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c
index 2f994e5..a80e093 100644
--- a/arch/arm/mach-omap2/gpio.c
+++ b/arch/arm/mach-omap2/gpio.c
@@ -20,6 +20,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
 
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
@@ -58,7 +59,7 @@
 	pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1);
 	pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
 	pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);
-	if (!pdata) {
+	if (!pdata->regs) {
 		pr_err("gpio%d: Memory allocation failed\n", id);
 		return -ENOMEM;
 	}
@@ -146,7 +147,10 @@
  */
 static int __init omap2_gpio_init(void)
 {
-	return omap_hwmod_for_each_by_class("gpio", omap2_gpio_dev_init,
-						NULL);
+	/* If dtb is there, the devices will be created dynamically */
+	if (of_have_populated_dt())
+		return -ENODEV;
+
+	return omap_hwmod_for_each_by_class("gpio", omap2_gpio_dev_init, NULL);
 }
 postcore_initcall(omap2_gpio_init);
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 385b3e0..a0fa9bb 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -176,7 +176,7 @@
 	const int t_wpl  = 40;
 	const int t_wph  = 30;
 	int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
-	int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
+	int div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
 	int first_time = 0, hf = 0, vhf = 0, sync_read = 0, sync_write = 0;
 	int err, ticks_cez;
 	int cs = cfg->cs, freq = *freq_ptr;
@@ -240,7 +240,6 @@
 		break;
 	}
 
-	tick_ns = gpmc_ticks_to_ns(1);
 	div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
 	gpmc_clk_ns = gpmc_ticks_to_ns(div);
 	if (gpmc_clk_ns < 15) /* >66Mhz */
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 00d5108..580e684 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -755,8 +755,7 @@
 		irq++;
 	}
 
-	ret = request_irq(gpmc_irq,
-			gpmc_handle_irq, IRQF_SHARED, "gpmc", gpmc_base);
+	ret = request_irq(gpmc_irq, gpmc_handle_irq, IRQF_SHARED, "gpmc", NULL);
 	if (ret)
 		pr_err("gpmc: irq-%d could not claim: err %d\n",
 						gpmc_irq, ret);
diff --git a/arch/arm/mach-omap2/hdq1w.c b/arch/arm/mach-omap2/hdq1w.c
new file mode 100644
index 0000000..297ebe0
--- /dev/null
+++ b/arch/arm/mach-omap2/hdq1w.c
@@ -0,0 +1,72 @@
+/*
+ * IP block integration code for the HDQ1W/1-wire IP block
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Paul Walmsley
+ *
+ * Based on the I2C reset code in arch/arm/mach-omap2/i2c.c by
+ *     Avinash.H.M <avinashhm@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
+ */
+
+#include <plat/omap_hwmod.h>
+#include <plat/hdq1w.h>
+
+#include "common.h"
+
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT	10000
+
+/**
+ * omap_hdq1w_reset - reset the OMAP HDQ1W module
+ * @oh: struct omap_hwmod *
+ *
+ * OCP soft reset the HDQ1W IP block.  Section 20.6.1.4 "HDQ1W/1-Wire
+ * Software Reset" of the OMAP34xx Technical Reference Manual Revision
+ * ZR (SWPU223R) does not include the rather important fact that, for
+ * the reset to succeed, the HDQ1W module's internal clock gate must be
+ * programmed to allow the clock to propagate to the rest of the
+ * module.  In this sense, it's rather similar to the I2C custom reset
+ * function.  Returns 0.
+ */
+int omap_hdq1w_reset(struct omap_hwmod *oh)
+{
+	u32 v;
+	int c = 0;
+
+	/* Write to the SOFTRESET bit */
+	omap_hwmod_softreset(oh);
+
+	/* Enable the module's internal clocks */
+	v = omap_hwmod_read(oh, HDQ_CTRL_STATUS_OFFSET);
+	v |= 1 << HDQ_CTRL_STATUS_CLOCKENABLE_SHIFT;
+	omap_hwmod_write(v, oh, HDQ_CTRL_STATUS_OFFSET);
+
+	/* Poll on RESETDONE bit */
+	omap_test_timeout((omap_hwmod_read(oh,
+					   oh->class->sysc->syss_offs)
+			   & SYSS_RESETDONE_MASK),
+			  MAX_MODULE_SOFTRESET_WAIT, c);
+
+	if (c == MAX_MODULE_SOFTRESET_WAIT)
+		pr_warning("%s: %s: softreset failed (waited %d usec)\n",
+			   __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT);
+	else
+		pr_debug("%s: %s: softreset in %d usec\n", __func__,
+			 oh->name, c);
+
+	return 0;
+}
diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c
index 454dfce..8763c85 100644
--- a/arch/arm/mach-omap2/hwspinlock.c
+++ b/arch/arm/mach-omap2/hwspinlock.c
@@ -28,7 +28,7 @@
 	.base_id = 0,
 };
 
-int __init hwspinlocks_init(void)
+static int __init hwspinlocks_init(void)
 {
 	int retval = 0;
 	struct omap_hwmod *oh;
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 0e79b7b..f139817 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -478,9 +478,12 @@
 	case 0xb94e:
 		switch (rev) {
 		case 0:
-		default:
 			omap_revision = OMAP4460_REV_ES1_0;
 			break;
+		case 2:
+		default:
+			omap_revision = OMAP4460_REV_ES1_1;
+			break;
 		}
 		break;
 	case 0xb975:
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 065bd76..4b9491a 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -31,6 +31,7 @@
 #include <plat/omap-pm.h>
 #include <plat/omap_hwmod.h>
 #include <plat/multi.h>
+#include <plat/dma.h>
 
 #include "iomap.h"
 #include "voltage.h"
@@ -363,24 +364,6 @@
 #endif
 	omap_hwmod_for_each(_set_hwmod_postsetup_state, &postsetup_state);
 
-	/*
-	 * Set the default postsetup state for unusual modules (like
-	 * MPU WDT).
-	 *
-	 * The postsetup_state is not actually used until
-	 * omap_hwmod_late_init(), so boards that desire full watchdog
-	 * coverage of kernel initialization can reprogram the
-	 * postsetup_state between the calls to
-	 * omap2_init_common_infra() and omap_sdrc_init().
-	 *
-	 * XXX ideally we could detect whether the MPU WDT was currently
-	 * enabled here and make this conditional
-	 */
-	postsetup_state = _HWMOD_STATE_DISABLED;
-	omap_hwmod_for_each_by_class("wd_timer",
-				     _set_hwmod_postsetup_state,
-				     &postsetup_state);
-
 	omap_pm_if_early_init();
 }
 
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 65f0d257..1ecf545 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -25,6 +25,7 @@
 #include <mach/hardware.h>
 
 #include "iomap.h"
+#include "common.h"
 
 /* selected INTC register offsets */
 
@@ -149,7 +150,6 @@
 	ct->chip.irq_mask = irq_gc_mask_disable_reg;
 	ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
 
-	ct->regs.ack = INTC_CONTROL;
 	ct->regs.enable = INTC_MIR_CLEAR0;
 	ct->regs.disable = INTC_MIR_SET0;
 	irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
@@ -231,7 +231,7 @@
 			goto out;
 
 		irqnr = readl_relaxed(base_addr + 0xd8);
-#ifdef CONFIG_SOC_OMAPTI816X
+#ifdef CONFIG_SOC_OMAPTI81XX
 		if (irqnr)
 			goto out;
 		irqnr = readl_relaxed(base_addr + 0xf8);
@@ -334,7 +334,7 @@
 void omap3_intc_suspend(void)
 {
 	/* A pending interrupt would prevent OMAP from entering suspend */
-	omap_ack_irq(0);
+	omap_ack_irq(NULL);
 }
 
 void omap3_intc_prepare_idle(void)
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index 415a6f1..19b8b67 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -26,9 +26,9 @@
 #define MAILBOX_IRQSTATUS(u)		(0x100 + 8 * (u))
 #define MAILBOX_IRQENABLE(u)		(0x104 + 8 * (u))
 
-#define OMAP4_MAILBOX_IRQSTATUS(u)	(0x104 + 10 * (u))
-#define OMAP4_MAILBOX_IRQENABLE(u)	(0x108 + 10 * (u))
-#define OMAP4_MAILBOX_IRQENABLE_CLR(u)	(0x10c + 10 * (u))
+#define OMAP4_MAILBOX_IRQSTATUS(u)	(0x104 + 0x10 * (u))
+#define OMAP4_MAILBOX_IRQENABLE(u)	(0x108 + 0x10 * (u))
+#define OMAP4_MAILBOX_IRQENABLE_CLR(u)	(0x10c + 0x10 * (u))
 
 #define MAILBOX_IRQ_NEWMSG(m)		(1 << (2 * (m)))
 #define MAILBOX_IRQ_NOTFULL(m)		(1 << (2 * (m) + 1))
diff --git a/arch/arm/mach-omap2/msdi.c b/arch/arm/mach-omap2/msdi.c
new file mode 100644
index 0000000..ef2a692
--- /dev/null
+++ b/arch/arm/mach-omap2/msdi.c
@@ -0,0 +1,88 @@
+/*
+ * MSDI IP block reset
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Paul Walmsley
+ *
+ * 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
+ *
+ * XXX What about pad muxing?
+ */
+
+#include <linux/kernel.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/mmc.h>
+
+#include "common.h"
+
+/*
+ * MSDI_CON_OFFSET: offset in bytes of the MSDI IP block's CON register
+ *     from the IP block's base address
+ */
+#define MSDI_CON_OFFSET				0x0c
+
+/* Register bitfields in the CON register */
+#define MSDI_CON_POW_MASK			BIT(11)
+#define MSDI_CON_CLKD_MASK			(0x3f << 0)
+#define MSDI_CON_CLKD_SHIFT			0
+
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT	10000
+
+/* MSDI_TARGET_RESET_CLKD: clock divisor to use throughout the reset */
+#define MSDI_TARGET_RESET_CLKD		0x3ff
+
+/**
+ * omap_msdi_reset - reset the MSDI IP block
+ * @oh: struct omap_hwmod *
+ *
+ * The MSDI IP block on OMAP2420 has to have both the POW and CLKD
+ * fields set inside its CON register for a reset to complete
+ * successfully.  This is not documented in the TRM.  For CLKD, we use
+ * the value that results in the lowest possible clock rate, to attempt
+ * to avoid disturbing any cards.
+ */
+int omap_msdi_reset(struct omap_hwmod *oh)
+{
+	u16 v = 0;
+	int c = 0;
+
+	/* Write to the SOFTRESET bit */
+	omap_hwmod_softreset(oh);
+
+	/* Enable the MSDI core and internal clock */
+	v |= MSDI_CON_POW_MASK;
+	v |= MSDI_TARGET_RESET_CLKD << MSDI_CON_CLKD_SHIFT;
+	omap_hwmod_write(v, oh, MSDI_CON_OFFSET);
+
+	/* Poll on RESETDONE bit */
+	omap_test_timeout((omap_hwmod_read(oh, oh->class->sysc->syss_offs)
+			   & SYSS_RESETDONE_MASK),
+			  MAX_MODULE_SOFTRESET_WAIT, c);
+
+	if (c == MAX_MODULE_SOFTRESET_WAIT)
+		pr_warning("%s: %s: softreset failed (waited %d usec)\n",
+			   __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT);
+	else
+		pr_debug("%s: %s: softreset in %d usec\n", __func__,
+			 oh->name, c);
+
+	/* Disable the MSDI internal clock */
+	v &= ~MSDI_CON_CLKD_MASK;
+	omap_hwmod_write(v, oh, MSDI_CON_OFFSET);
+
+	return 0;
+}
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 65c3391..3268ee2 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -247,7 +247,7 @@
 	int mux_mode;
 
 	mux_mode = omap_mux_get_by_name(muxname, &partition, &mux);
-	if (mux_mode < 0)
+	if (mux_mode < 0 || !mux)
 		return mux_mode;
 
 	old_mode = omap_mux_read(partition, mux->reg_offset);
diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c
index d8f8ef4..d9ae4a5 100644
--- a/arch/arm/mach-omap2/omap-secure.c
+++ b/arch/arm/mach-omap2/omap-secure.c
@@ -18,6 +18,7 @@
 #include <asm/cacheflush.h>
 #include <asm/memblock.h>
 
+#include <plat/omap-secure.h>
 #include <mach/omap-secure.h>
 
 static phys_addr_t omap_secure_memblock_base;
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index 42cd7fb..d811c77 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -259,7 +259,7 @@
 /*
  * Clear WakeupGen SAR backup status.
  */
-void irq_sar_clear(void)
+static void irq_sar_clear(void)
 {
 	u32 val;
 	val = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET);
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 70de277..a8161e5 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -25,11 +25,13 @@
 #include <plat/irqs.h>
 #include <plat/sram.h>
 #include <plat/omap-secure.h>
+#include <plat/mmc.h>
 
 #include <mach/hardware.h>
 #include <mach/omap-wakeupgen.h>
 
 #include "common.h"
+#include "hsmmc.h"
 #include "omap4-sar-layout.h"
 #include <linux/export.h>
 
@@ -207,3 +209,59 @@
 	return 0;
 }
 early_initcall(omap4_sar_ram_init);
+
+#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+static int omap4_twl6030_hsmmc_late_init(struct device *dev)
+{
+	int irq = 0;
+	struct platform_device *pdev = container_of(dev,
+				struct platform_device, dev);
+	struct omap_mmc_platform_data *pdata = dev->platform_data;
+
+	/* Setting MMC1 Card detect Irq */
+	if (pdev->id == 0) {
+		irq = twl6030_mmc_card_detect_config();
+		if (irq < 0) {
+			dev_err(dev, "%s: Error card detect config(%d)\n",
+				__func__, irq);
+			return irq;
+		}
+		pdata->slots[0].card_detect_irq = irq;
+		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+	}
+	return 0;
+}
+
+static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
+{
+	struct omap_mmc_platform_data *pdata;
+
+	/* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+	if (!dev) {
+		pr_err("Failed %s\n", __func__);
+		return;
+	}
+	pdata = dev->platform_data;
+	pdata->init =	omap4_twl6030_hsmmc_late_init;
+}
+
+int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
+{
+	struct omap2_hsmmc_info *c;
+
+	omap_hsmmc_init(controllers);
+	for (c = controllers; c->mmc; c++) {
+		/* pdev can be null if CONFIG_MMC_OMAP_HS is not set */
+		if (!c->pdev)
+			continue;
+		omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
+	}
+
+	return 0;
+}
+#else
+int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
+{
+	return 0;
+}
+#endif
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 7144ae6..bf86f7e 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2,7 +2,7 @@
  * omap_hwmod implementation for OMAP2/3/4
  *
  * Copyright (C) 2009-2011 Nokia Corporation
- * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011-2012 Texas Instruments, Inc.
  *
  * Paul Walmsley, Benoît Cousson, Kevin Hilman
  *
@@ -137,6 +137,7 @@
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
+#include <linux/bootmem.h>
 
 #include "common.h"
 #include <plat/cpu.h>
@@ -159,16 +160,58 @@
 /* Name of the OMAP hwmod for the MPU */
 #define MPU_INITIATOR_NAME		"mpu"
 
+/*
+ * Number of struct omap_hwmod_link records per struct
+ * omap_hwmod_ocp_if record (master->slave and slave->master)
+ */
+#define LINKS_PER_OCP_IF		2
+
 /* omap_hwmod_list contains all registered struct omap_hwmods */
 static LIST_HEAD(omap_hwmod_list);
 
 /* mpu_oh: used to add/remove MPU initiator from sleepdep list */
 static struct omap_hwmod *mpu_oh;
 
+/*
+ * linkspace: ptr to a buffer that struct omap_hwmod_link records are
+ * allocated from - used to reduce the number of small memory
+ * allocations, which has a significant impact on performance
+ */
+static struct omap_hwmod_link *linkspace;
+
+/*
+ * free_ls, max_ls: array indexes into linkspace; representing the
+ * next free struct omap_hwmod_link index, and the maximum number of
+ * struct omap_hwmod_link records allocated (respectively)
+ */
+static unsigned short free_ls, max_ls, ls_supp;
 
 /* Private functions */
 
 /**
+ * _fetch_next_ocp_if - return the next OCP interface in a list
+ * @p: ptr to a ptr to the list_head inside the ocp_if to return
+ * @i: pointer to the index of the element pointed to by @p in the list
+ *
+ * Return a pointer to the struct omap_hwmod_ocp_if record
+ * containing the struct list_head pointed to by @p, and increment
+ * @p such that a future call to this routine will return the next
+ * record.
+ */
+static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p,
+						    int *i)
+{
+	struct omap_hwmod_ocp_if *oi;
+
+	oi = list_entry(*p, struct omap_hwmod_link, node)->ocp_if;
+	*p = (*p)->next;
+
+	*i = *i + 1;
+
+	return oi;
+}
+
+/**
  * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy
  * @oh: struct omap_hwmod *
  *
@@ -582,16 +625,16 @@
  */
 static int _init_interface_clks(struct omap_hwmod *oh)
 {
+	struct omap_hwmod_ocp_if *os;
+	struct list_head *p;
 	struct clk *c;
-	int i;
+	int i = 0;
 	int ret = 0;
 
-	if (oh->slaves_cnt == 0)
-		return 0;
+	p = oh->slave_ports.next;
 
-	for (i = 0; i < oh->slaves_cnt; i++) {
-		struct omap_hwmod_ocp_if *os = oh->slaves[i];
-
+	while (i < oh->slaves_cnt) {
+		os = _fetch_next_ocp_if(&p, &i);
 		if (!os->clk)
 			continue;
 
@@ -643,21 +686,22 @@
  */
 static int _enable_clocks(struct omap_hwmod *oh)
 {
-	int i;
+	struct omap_hwmod_ocp_if *os;
+	struct list_head *p;
+	int i = 0;
 
 	pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name);
 
 	if (oh->_clk)
 		clk_enable(oh->_clk);
 
-	if (oh->slaves_cnt > 0) {
-		for (i = 0; i < oh->slaves_cnt; i++) {
-			struct omap_hwmod_ocp_if *os = oh->slaves[i];
-			struct clk *c = os->_clk;
+	p = oh->slave_ports.next;
 
-			if (c && (os->flags & OCPIF_SWSUP_IDLE))
-				clk_enable(c);
-		}
+	while (i < oh->slaves_cnt) {
+		os = _fetch_next_ocp_if(&p, &i);
+
+		if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
+			clk_enable(os->_clk);
 	}
 
 	/* The opt clocks are controlled by the device driver. */
@@ -673,21 +717,22 @@
  */
 static int _disable_clocks(struct omap_hwmod *oh)
 {
-	int i;
+	struct omap_hwmod_ocp_if *os;
+	struct list_head *p;
+	int i = 0;
 
 	pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name);
 
 	if (oh->_clk)
 		clk_disable(oh->_clk);
 
-	if (oh->slaves_cnt > 0) {
-		for (i = 0; i < oh->slaves_cnt; i++) {
-			struct omap_hwmod_ocp_if *os = oh->slaves[i];
-			struct clk *c = os->_clk;
+	p = oh->slave_ports.next;
 
-			if (c && (os->flags & OCPIF_SWSUP_IDLE))
-				clk_disable(c);
-		}
+	while (i < oh->slaves_cnt) {
+		os = _fetch_next_ocp_if(&p, &i);
+
+		if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
+			clk_disable(os->_clk);
 	}
 
 	/* The opt clocks are controlled by the device driver. */
@@ -781,39 +826,6 @@
 }
 
 /**
- * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
- * @oh: struct omap_hwmod *
- *
- * Disable the PRCM module mode related to the hwmod @oh.
- * Return EINVAL if the modulemode is not supported and 0 in case of success.
- */
-static int _omap4_disable_module(struct omap_hwmod *oh)
-{
-	int v;
-
-	/* The module mode does not exist prior OMAP4 */
-	if (!cpu_is_omap44xx())
-		return -EINVAL;
-
-	if (!oh->clkdm || !oh->prcm.omap4.modulemode)
-		return -EINVAL;
-
-	pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
-
-	omap4_cminst_module_disable(oh->clkdm->prcm_partition,
-				    oh->clkdm->cm_inst,
-				    oh->clkdm->clkdm_offs,
-				    oh->prcm.omap4.clkctrl_offs);
-
-	v = _omap4_wait_target_disable(oh);
-	if (v)
-		pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
-			oh->name);
-
-	return 0;
-}
-
-/**
  * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
  * @oh: struct omap_hwmod *oh
  *
@@ -883,59 +895,220 @@
 }
 
 /**
- * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use
- * @oh: struct omap_hwmod *
+ * _get_mpu_irq_by_name - fetch MPU interrupt line number by name
+ * @oh: struct omap_hwmod * to operate on
+ * @name: pointer to the name of the MPU interrupt number to fetch (optional)
+ * @irq: pointer to an unsigned int to store the MPU IRQ number to
  *
- * Returns the array index of the OCP slave port that the MPU
- * addresses the device on, or -EINVAL upon error or not found.
+ * Retrieve a MPU hardware IRQ line number named by @name associated
+ * with the IP block pointed to by @oh.  The IRQ number will be filled
+ * into the address pointed to by @dma.  When @name is non-null, the
+ * IRQ line number associated with the named entry will be returned.
+ * If @name is null, the first matching entry will be returned.  Data
+ * order is not meaningful in hwmod data, so callers are strongly
+ * encouraged to use a non-null @name whenever possible to avoid
+ * unpredictable effects if hwmod data is later added that causes data
+ * ordering to change.  Returns 0 upon success or a negative error
+ * code upon error.
  */
-static int __init _find_mpu_port_index(struct omap_hwmod *oh)
+static int _get_mpu_irq_by_name(struct omap_hwmod *oh, const char *name,
+				unsigned int *irq)
 {
 	int i;
-	int found = 0;
+	bool found = false;
 
-	if (!oh || oh->slaves_cnt == 0)
-		return -EINVAL;
+	if (!oh->mpu_irqs)
+		return -ENOENT;
 
-	for (i = 0; i < oh->slaves_cnt; i++) {
-		struct omap_hwmod_ocp_if *os = oh->slaves[i];
+	i = 0;
+	while (oh->mpu_irqs[i].irq != -1) {
+		if (name == oh->mpu_irqs[i].name ||
+		    !strcmp(name, oh->mpu_irqs[i].name)) {
+			found = true;
+			break;
+		}
+		i++;
+	}
 
+	if (!found)
+		return -ENOENT;
+
+	*irq = oh->mpu_irqs[i].irq;
+
+	return 0;
+}
+
+/**
+ * _get_sdma_req_by_name - fetch SDMA request line ID by name
+ * @oh: struct omap_hwmod * to operate on
+ * @name: pointer to the name of the SDMA request line to fetch (optional)
+ * @dma: pointer to an unsigned int to store the request line ID to
+ *
+ * Retrieve an SDMA request line ID named by @name on the IP block
+ * pointed to by @oh.  The ID will be filled into the address pointed
+ * to by @dma.  When @name is non-null, the request line ID associated
+ * with the named entry will be returned.  If @name is null, the first
+ * matching entry will be returned.  Data order is not meaningful in
+ * hwmod data, so callers are strongly encouraged to use a non-null
+ * @name whenever possible to avoid unpredictable effects if hwmod
+ * data is later added that causes data ordering to change.  Returns 0
+ * upon success or a negative error code upon error.
+ */
+static int _get_sdma_req_by_name(struct omap_hwmod *oh, const char *name,
+				 unsigned int *dma)
+{
+	int i;
+	bool found = false;
+
+	if (!oh->sdma_reqs)
+		return -ENOENT;
+
+	i = 0;
+	while (oh->sdma_reqs[i].dma_req != -1) {
+		if (name == oh->sdma_reqs[i].name ||
+		    !strcmp(name, oh->sdma_reqs[i].name)) {
+			found = true;
+			break;
+		}
+		i++;
+	}
+
+	if (!found)
+		return -ENOENT;
+
+	*dma = oh->sdma_reqs[i].dma_req;
+
+	return 0;
+}
+
+/**
+ * _get_addr_space_by_name - fetch address space start & end by name
+ * @oh: struct omap_hwmod * to operate on
+ * @name: pointer to the name of the address space to fetch (optional)
+ * @pa_start: pointer to a u32 to store the starting address to
+ * @pa_end: pointer to a u32 to store the ending address to
+ *
+ * Retrieve address space start and end addresses for the IP block
+ * pointed to by @oh.  The data will be filled into the addresses
+ * pointed to by @pa_start and @pa_end.  When @name is non-null, the
+ * address space data associated with the named entry will be
+ * returned.  If @name is null, the first matching entry will be
+ * returned.  Data order is not meaningful in hwmod data, so callers
+ * are strongly encouraged to use a non-null @name whenever possible
+ * to avoid unpredictable effects if hwmod data is later added that
+ * causes data ordering to change.  Returns 0 upon success or a
+ * negative error code upon error.
+ */
+static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name,
+				   u32 *pa_start, u32 *pa_end)
+{
+	int i, j;
+	struct omap_hwmod_ocp_if *os;
+	struct list_head *p = NULL;
+	bool found = false;
+
+	p = oh->slave_ports.next;
+
+	i = 0;
+	while (i < oh->slaves_cnt) {
+		os = _fetch_next_ocp_if(&p, &i);
+
+		if (!os->addr)
+			return -ENOENT;
+
+		j = 0;
+		while (os->addr[j].pa_start != os->addr[j].pa_end) {
+			if (name == os->addr[j].name ||
+			    !strcmp(name, os->addr[j].name)) {
+				found = true;
+				break;
+			}
+			j++;
+		}
+
+		if (found)
+			break;
+	}
+
+	if (!found)
+		return -ENOENT;
+
+	*pa_start = os->addr[j].pa_start;
+	*pa_end = os->addr[j].pa_end;
+
+	return 0;
+}
+
+/**
+ * _save_mpu_port_index - find and save the index to @oh's MPU port
+ * @oh: struct omap_hwmod *
+ *
+ * Determines the array index of the OCP slave port that the MPU uses
+ * to address the device, and saves it into the struct omap_hwmod.
+ * Intended to be called during hwmod registration only. No return
+ * value.
+ */
+static void __init _save_mpu_port_index(struct omap_hwmod *oh)
+{
+	struct omap_hwmod_ocp_if *os = NULL;
+	struct list_head *p;
+	int i = 0;
+
+	if (!oh)
+		return;
+
+	oh->_int_flags |= _HWMOD_NO_MPU_PORT;
+
+	p = oh->slave_ports.next;
+
+	while (i < oh->slaves_cnt) {
+		os = _fetch_next_ocp_if(&p, &i);
 		if (os->user & OCP_USER_MPU) {
-			found = 1;
+			oh->_mpu_port = os;
+			oh->_int_flags &= ~_HWMOD_NO_MPU_PORT;
 			break;
 		}
 	}
 
-	if (found)
-		pr_debug("omap_hwmod: %s: MPU OCP slave port ID  %d\n",
-			 oh->name, i);
-	else
-		pr_debug("omap_hwmod: %s: no MPU OCP slave port found\n",
-			 oh->name);
-
-	return (found) ? i : -EINVAL;
+	return;
 }
 
 /**
- * _find_mpu_rt_base - find hwmod register target base addr accessible by MPU
+ * _find_mpu_rt_port - return omap_hwmod_ocp_if accessible by the MPU
  * @oh: struct omap_hwmod *
  *
- * Return the virtual address of the base of the register target of
- * device @oh, or NULL on error.
+ * Given a pointer to a struct omap_hwmod record @oh, return a pointer
+ * to the struct omap_hwmod_ocp_if record that is used by the MPU to
+ * communicate with the IP block.  This interface need not be directly
+ * connected to the MPU (and almost certainly is not), but is directly
+ * connected to the IP block represented by @oh.  Returns a pointer
+ * to the struct omap_hwmod_ocp_if * upon success, or returns NULL upon
+ * error or if there does not appear to be a path from the MPU to this
+ * IP block.
  */
-static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
+static struct omap_hwmod_ocp_if *_find_mpu_rt_port(struct omap_hwmod *oh)
+{
+	if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0)
+		return NULL;
+
+	return oh->_mpu_port;
+};
+
+/**
+ * _find_mpu_rt_addr_space - return MPU register target address space for @oh
+ * @oh: struct omap_hwmod *
+ *
+ * Returns a pointer to the struct omap_hwmod_addr_space record representing
+ * the register target MPU address space; or returns NULL upon error.
+ */
+static struct omap_hwmod_addr_space * __init _find_mpu_rt_addr_space(struct omap_hwmod *oh)
 {
 	struct omap_hwmod_ocp_if *os;
 	struct omap_hwmod_addr_space *mem;
-	int i = 0, found = 0;
-	void __iomem *va_start;
+	int found = 0, i = 0;
 
-	if (!oh || oh->slaves_cnt == 0)
-		return NULL;
-
-	os = oh->slaves[index];
-
-	if (!os->addr)
+	os = _find_mpu_rt_port(oh);
+	if (!os || !os->addr)
 		return NULL;
 
 	do {
@@ -944,20 +1117,7 @@
 			found = 1;
 	} while (!found && mem->pa_start != mem->pa_end);
 
-	if (found) {
-		va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
-		if (!va_start) {
-			pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name);
-			return NULL;
-		}
-		pr_debug("omap_hwmod: %s: MPU register target at va %p\n",
-			 oh->name, va_start);
-	} else {
-		pr_debug("omap_hwmod: %s: no MPU register target found\n",
-			 oh->name);
-	}
-
-	return (found) ? va_start : NULL;
+	return (found) ? mem : NULL;
 }
 
 /**
@@ -1205,12 +1365,11 @@
 	if (!oh)
 		return -EINVAL;
 
-	if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+	if (oh->flags & HWMOD_NO_IDLEST)
 		return 0;
 
-	os = oh->slaves[oh->_mpu_port_index];
-
-	if (oh->flags & HWMOD_NO_IDLEST)
+	os = _find_mpu_rt_port(oh);
+	if (!os)
 		return 0;
 
 	/* XXX check module SIDLEMODE */
@@ -1378,13 +1537,73 @@
 }
 
 /**
+ * _are_any_hardreset_lines_asserted - return true if part of @oh is hard-reset
+ * @oh: struct omap_hwmod *
+ *
+ * If any hardreset line associated with @oh is asserted, then return true.
+ * Otherwise, if @oh has no hardreset lines associated with it, or if
+ * no hardreset lines associated with @oh are asserted, then return false.
+ * This function is used to avoid executing some parts of the IP block
+ * enable/disable sequence if a hardreset line is set.
+ */
+static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh)
+{
+	int i;
+
+	if (oh->rst_lines_cnt == 0)
+		return false;
+
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
+			return true;
+
+	return false;
+}
+
+/**
+ * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
+ * @oh: struct omap_hwmod *
+ *
+ * Disable the PRCM module mode related to the hwmod @oh.
+ * Return EINVAL if the modulemode is not supported and 0 in case of success.
+ */
+static int _omap4_disable_module(struct omap_hwmod *oh)
+{
+	int v;
+
+	/* The module mode does not exist prior OMAP4 */
+	if (!cpu_is_omap44xx())
+		return -EINVAL;
+
+	if (!oh->clkdm || !oh->prcm.omap4.modulemode)
+		return -EINVAL;
+
+	pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
+
+	omap4_cminst_module_disable(oh->clkdm->prcm_partition,
+				    oh->clkdm->cm_inst,
+				    oh->clkdm->clkdm_offs,
+				    oh->prcm.omap4.clkctrl_offs);
+
+	if (_are_any_hardreset_lines_asserted(oh))
+		return 0;
+
+	v = _omap4_wait_target_disable(oh);
+	if (v)
+		pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
+			oh->name);
+
+	return 0;
+}
+
+/**
  * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
  * @oh: struct omap_hwmod *
  *
  * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit.  hwmod must be
- * enabled for this to work.  Returns -EINVAL if the hwmod cannot be
- * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if
- * the module did not reset in time, or 0 upon success.
+ * enabled for this to work.  Returns -ENOENT if the hwmod cannot be
+ * reset this way, -EINVAL if the hwmod is in the wrong state,
+ * -ETIMEDOUT if the module did not reset in time, or 0 upon success.
  *
  * In OMAP3 a specific SYSSTATUS register is used to get the reset status.
  * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead
@@ -1401,7 +1620,7 @@
 
 	if (!oh->class->sysc ||
 	    !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
-		return -EINVAL;
+		return -ENOENT;
 
 	/* clocks must be on for this operation */
 	if (oh->_state != _HWMOD_STATE_ENABLED) {
@@ -1462,32 +1681,60 @@
  * _reset - reset an omap_hwmod
  * @oh: struct omap_hwmod *
  *
- * Resets an omap_hwmod @oh.  The default software reset mechanism for
- * most OMAP IP blocks is triggered via the OCP_SYSCONFIG.SOFTRESET
- * bit.  However, some hwmods cannot be reset via this method: some
- * are not targets and therefore have no OCP header registers to
- * access; others (like the IVA) have idiosyncratic reset sequences.
- * So for these relatively rare cases, custom reset code can be
- * supplied in the struct omap_hwmod_class .reset function pointer.
- * Passes along the return value from either _reset() or the custom
- * reset function - these must return -EINVAL if the hwmod cannot be
- * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if
- * the module did not reset in time, or 0 upon success.
+ * Resets an omap_hwmod @oh.  If the module has a custom reset
+ * function pointer defined, then call it to reset the IP block, and
+ * pass along its return value to the caller.  Otherwise, if the IP
+ * block has an OCP_SYSCONFIG register with a SOFTRESET bitfield
+ * associated with it, call a function to reset the IP block via that
+ * method, and pass along the return value to the caller.  Finally, if
+ * the IP block has some hardreset lines associated with it, assert
+ * all of those, but do _not_ deassert them. (This is because driver
+ * authors have expressed an apparent requirement to control the
+ * deassertion of the hardreset lines themselves.)
+ *
+ * The default software reset mechanism for most OMAP IP blocks is
+ * triggered via the OCP_SYSCONFIG.SOFTRESET bit.  However, some
+ * hwmods cannot be reset via this method.  Some are not targets and
+ * therefore have no OCP header registers to access.  Others (like the
+ * IVA) have idiosyncratic reset sequences.  So for these relatively
+ * rare cases, custom reset code can be supplied in the struct
+ * omap_hwmod_class .reset function pointer.  Passes along the return
+ * value from either _ocp_softreset() or the custom reset function -
+ * these must return -EINVAL if the hwmod cannot be reset this way or
+ * if the hwmod is in the wrong state, -ETIMEDOUT if the module did
+ * not reset in time, or 0 upon success.
  */
 static int _reset(struct omap_hwmod *oh)
 {
-	int ret;
+	int i, r;
 
 	pr_debug("omap_hwmod: %s: resetting\n", oh->name);
 
-	ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh);
+	if (oh->class->reset) {
+		r = oh->class->reset(oh);
+	} else {
+		if (oh->rst_lines_cnt > 0) {
+			for (i = 0; i < oh->rst_lines_cnt; i++)
+				_assert_hardreset(oh, oh->rst_lines[i].name);
+			return 0;
+		} else {
+			r = _ocp_softreset(oh);
+			if (r == -ENOENT)
+				r = 0;
+		}
+	}
 
+	/*
+	 * OCP_SYSCONFIG bits need to be reprogrammed after a
+	 * softreset.  The _enable() function should be split to avoid
+	 * the rewrite of the OCP_SYSCONFIG register.
+	 */
 	if (oh->class->sysc) {
 		_update_sysc_cache(oh);
 		_enable_sysc(oh);
 	}
 
-	return ret;
+	return r;
 }
 
 /**
@@ -1506,10 +1753,9 @@
 	pr_debug("omap_hwmod: %s: enabling\n", oh->name);
 
 	/*
-	 * hwmods with HWMOD_INIT_NO_IDLE flag set are left
-	 * in enabled state at init.
-	 * Now that someone is really trying to enable them,
-	 * just ensure that the hwmod mux is set.
+	 * hwmods with HWMOD_INIT_NO_IDLE flag set are left in enabled
+	 * state at init.  Now that someone is really trying to enable
+	 * them, just ensure that the hwmod mux is set.
 	 */
 	if (oh->_int_flags & _HWMOD_SKIP_ENABLE) {
 		/*
@@ -1532,15 +1778,17 @@
 		return -EINVAL;
 	}
 
-
 	/*
-	 * If an IP contains only one HW reset line, then de-assert it in order
-	 * to allow the module state transition. Otherwise the PRCM will return
-	 * Intransition status, and the init will failed.
+	 * If an IP block contains HW reset lines and any of them are
+	 * asserted, we let integration code associated with that
+	 * block handle the enable.  We've received very little
+	 * information on what those driver authors need, and until
+	 * detailed information is provided and the driver code is
+	 * posted to the public lists, this is probably the best we
+	 * can do.
 	 */
-	if ((oh->_state == _HWMOD_STATE_INITIALIZED ||
-	     oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
-		_deassert_hardreset(oh, oh->rst_lines[0].name);
+	if (_are_any_hardreset_lines_asserted(oh))
+		return 0;
 
 	/* Mux pins for device runtime if populated */
 	if (oh->mux && (!oh->mux->enabled ||
@@ -1615,6 +1863,9 @@
 		return -EINVAL;
 	}
 
+	if (_are_any_hardreset_lines_asserted(oh))
+		return 0;
+
 	if (oh->class->sysc)
 		_idle_sysc(oh);
 	_del_initiator_dep(oh, mpu_oh);
@@ -1687,7 +1938,7 @@
  */
 static int _shutdown(struct omap_hwmod *oh)
 {
-	int ret;
+	int ret, i;
 	u8 prev_state;
 
 	if (oh->_state != _HWMOD_STATE_IDLE &&
@@ -1697,6 +1948,9 @@
 		return -EINVAL;
 	}
 
+	if (_are_any_hardreset_lines_asserted(oh))
+		return 0;
+
 	pr_debug("omap_hwmod: %s: disabling\n", oh->name);
 
 	if (oh->class->pre_shutdown) {
@@ -1728,12 +1982,8 @@
 	}
 	/* XXX Should this code also force-disable the optional clocks? */
 
-	/*
-	 * If an IP contains only one HW reset line, then assert it
-	 * after disabling the clocks and before shutting down the IP.
-	 */
-	if (oh->rst_lines_cnt == 1)
-		_assert_hardreset(oh, oh->rst_lines[0].name);
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		_assert_hardreset(oh, oh->rst_lines[i].name);
 
 	/* Mux pins to safe mode or use populated off mode values */
 	if (oh->mux)
@@ -1745,59 +1995,186 @@
 }
 
 /**
- * _setup - do initial configuration of omap_hwmod
- * @oh: struct omap_hwmod *
+ * _init_mpu_rt_base - populate the virtual address for a hwmod
+ * @oh: struct omap_hwmod * to locate the virtual address
  *
- * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh
- * OCP_SYSCONFIG register.  Returns 0.
+ * Cache the virtual address used by the MPU to access this IP block's
+ * registers.  This address is needed early so the OCP registers that
+ * are part of the device's address space can be ioremapped properly.
+ * No return value.
  */
-static int _setup(struct omap_hwmod *oh, void *data)
+static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data)
 {
-	int i, r;
-	u8 postsetup_state;
+	struct omap_hwmod_addr_space *mem;
+	void __iomem *va_start;
 
-	if (oh->_state != _HWMOD_STATE_CLKS_INITED)
+	if (!oh)
+		return;
+
+	_save_mpu_port_index(oh);
+
+	if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+		return;
+
+	mem = _find_mpu_rt_addr_space(oh);
+	if (!mem) {
+		pr_debug("omap_hwmod: %s: no MPU register target found\n",
+			 oh->name);
+		return;
+	}
+
+	va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
+	if (!va_start) {
+		pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name);
+		return;
+	}
+
+	pr_debug("omap_hwmod: %s: MPU register target at va %p\n",
+		 oh->name, va_start);
+
+	oh->_mpu_rt_va = va_start;
+}
+
+/**
+ * _init - initialize internal data for the hwmod @oh
+ * @oh: struct omap_hwmod *
+ * @n: (unused)
+ *
+ * Look up the clocks and the address space used by the MPU to access
+ * registers belonging to the hwmod @oh.  @oh must already be
+ * registered at this point.  This is the first of two phases for
+ * hwmod initialization.  Code called here does not touch any hardware
+ * registers, it simply prepares internal data structures.  Returns 0
+ * upon success or if the hwmod isn't registered, or -EINVAL upon
+ * failure.
+ */
+static int __init _init(struct omap_hwmod *oh, void *data)
+{
+	int r;
+
+	if (oh->_state != _HWMOD_STATE_REGISTERED)
 		return 0;
 
-	/* Set iclk autoidle mode */
-	if (oh->slaves_cnt > 0) {
-		for (i = 0; i < oh->slaves_cnt; i++) {
-			struct omap_hwmod_ocp_if *os = oh->slaves[i];
-			struct clk *c = os->_clk;
+	_init_mpu_rt_base(oh, NULL);
 
-			if (!c)
-				continue;
-
-			if (os->flags & OCPIF_SWSUP_IDLE) {
-				/* XXX omap_iclk_deny_idle(c); */
-			} else {
-				/* XXX omap_iclk_allow_idle(c); */
-				clk_enable(c);
-			}
-		}
+	r = _init_clocks(oh, NULL);
+	if (IS_ERR_VALUE(r)) {
+		WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name);
+		return -EINVAL;
 	}
 
 	oh->_state = _HWMOD_STATE_INITIALIZED;
 
-	/*
-	 * In the case of hwmod with hardreset that should not be
-	 * de-assert at boot time, we have to keep the module
-	 * initialized, because we cannot enable it properly with the
-	 * reset asserted. Exit without warning because that behavior is
-	 * expected.
-	 */
-	if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1)
-		return 0;
+	return 0;
+}
 
-	r = _enable(oh);
-	if (r) {
-		pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",
-			   oh->name, oh->_state);
-		return 0;
+/**
+ * _setup_iclk_autoidle - configure an IP block's interface clocks
+ * @oh: struct omap_hwmod *
+ *
+ * Set up the module's interface clocks.  XXX This function is still mostly
+ * a stub; implementing this properly requires iclk autoidle usecounting in
+ * the clock code.   No return value.
+ */
+static void __init _setup_iclk_autoidle(struct omap_hwmod *oh)
+{
+	struct omap_hwmod_ocp_if *os;
+	struct list_head *p;
+	int i = 0;
+	if (oh->_state != _HWMOD_STATE_INITIALIZED)
+		return;
+
+	p = oh->slave_ports.next;
+
+	while (i < oh->slaves_cnt) {
+		os = _fetch_next_ocp_if(&p, &i);
+		if (!os->_clk)
+			continue;
+
+		if (os->flags & OCPIF_SWSUP_IDLE) {
+			/* XXX omap_iclk_deny_idle(c); */
+		} else {
+			/* XXX omap_iclk_allow_idle(c); */
+			clk_enable(os->_clk);
+		}
+	}
+
+	return;
+}
+
+/**
+ * _setup_reset - reset an IP block during the setup process
+ * @oh: struct omap_hwmod *
+ *
+ * Reset the IP block corresponding to the hwmod @oh during the setup
+ * process.  The IP block is first enabled so it can be successfully
+ * reset.  Returns 0 upon success or a negative error code upon
+ * failure.
+ */
+static int __init _setup_reset(struct omap_hwmod *oh)
+{
+	int r;
+
+	if (oh->_state != _HWMOD_STATE_INITIALIZED)
+		return -EINVAL;
+
+	if (oh->rst_lines_cnt == 0) {
+		r = _enable(oh);
+		if (r) {
+			pr_warning("omap_hwmod: %s: cannot be enabled for reset (%d)\n",
+				   oh->name, oh->_state);
+			return -EINVAL;
+		}
 	}
 
 	if (!(oh->flags & HWMOD_INIT_NO_RESET))
-		_reset(oh);
+		r = _reset(oh);
+
+	return r;
+}
+
+/**
+ * _setup_postsetup - transition to the appropriate state after _setup
+ * @oh: struct omap_hwmod *
+ *
+ * Place an IP block represented by @oh into a "post-setup" state --
+ * either IDLE, ENABLED, or DISABLED.  ("post-setup" simply means that
+ * this function is called at the end of _setup().)  The postsetup
+ * state for an IP block can be changed by calling
+ * omap_hwmod_enter_postsetup_state() early in the boot process,
+ * before one of the omap_hwmod_setup*() functions are called for the
+ * IP block.
+ *
+ * The IP block stays in this state until a PM runtime-based driver is
+ * loaded for that IP block.  A post-setup state of IDLE is
+ * appropriate for almost all IP blocks with runtime PM-enabled
+ * drivers, since those drivers are able to enable the IP block.  A
+ * post-setup state of ENABLED is appropriate for kernels with PM
+ * runtime disabled.  The DISABLED state is appropriate for unusual IP
+ * blocks such as the MPU WDTIMER on kernels without WDTIMER drivers
+ * included, since the WDTIMER starts running on reset and will reset
+ * the MPU if left active.
+ *
+ * This post-setup mechanism is deprecated.  Once all of the OMAP
+ * drivers have been converted to use PM runtime, and all of the IP
+ * block data and interconnect data is available to the hwmod code, it
+ * should be possible to replace this mechanism with a "lazy reset"
+ * arrangement.  In a "lazy reset" setup, each IP block is enabled
+ * when the driver first probes, then all remaining IP blocks without
+ * drivers are either shut down or enabled after the drivers have
+ * loaded.  However, this cannot take place until the above
+ * preconditions have been met, since otherwise the late reset code
+ * has no way of knowing which IP blocks are in use by drivers, and
+ * which ones are unused.
+ *
+ * No return value.
+ */
+static void __init _setup_postsetup(struct omap_hwmod *oh)
+{
+	u8 postsetup_state;
+
+	if (oh->rst_lines_cnt > 0)
+		return;
 
 	postsetup_state = oh->_postsetup_state;
 	if (postsetup_state == _HWMOD_STATE_UNKNOWN)
@@ -1821,6 +2198,35 @@
 		WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n",
 		     oh->name, postsetup_state);
 
+	return;
+}
+
+/**
+ * _setup - prepare IP block hardware for use
+ * @oh: struct omap_hwmod *
+ * @n: (unused, pass NULL)
+ *
+ * Configure the IP block represented by @oh.  This may include
+ * enabling the IP block, resetting it, and placing it into a
+ * post-setup state, depending on the type of IP block and applicable
+ * flags.  IP blocks are reset to prevent any previous configuration
+ * by the bootloader or previous operating system from interfering
+ * with power management or other parts of the system.  The reset can
+ * be avoided; see omap_hwmod_no_setup_reset().  This is the second of
+ * two phases for hwmod initialization.  Code called here generally
+ * affects the IP block hardware, or system integration hardware
+ * associated with the IP block.  Returns 0.
+ */
+static int __init _setup(struct omap_hwmod *oh, void *data)
+{
+	if (oh->_state != _HWMOD_STATE_INITIALIZED)
+		return 0;
+
+	_setup_iclk_autoidle(oh);
+
+	if (!_setup_reset(oh))
+		_setup_postsetup(oh);
+
 	return 0;
 }
 
@@ -1843,8 +2249,6 @@
  */
 static int __init _register(struct omap_hwmod *oh)
 {
-	int ms_id;
-
 	if (!oh || !oh->name || !oh->class || !oh->class->name ||
 	    (oh->_state != _HWMOD_STATE_UNKNOWN))
 		return -EINVAL;
@@ -1854,14 +2258,10 @@
 	if (_lookup(oh->name))
 		return -EEXIST;
 
-	ms_id = _find_mpu_port_index(oh);
-	if (!IS_ERR_VALUE(ms_id))
-		oh->_mpu_port_index = ms_id;
-	else
-		oh->_int_flags |= _HWMOD_NO_MPU_PORT;
-
 	list_add_tail(&oh->node, &omap_hwmod_list);
 
+	INIT_LIST_HEAD(&oh->master_ports);
+	INIT_LIST_HEAD(&oh->slave_ports);
 	spin_lock_init(&oh->_lock);
 
 	oh->_state = _HWMOD_STATE_REGISTERED;
@@ -1876,6 +2276,160 @@
 	return 0;
 }
 
+/**
+ * _alloc_links - return allocated memory for hwmod links
+ * @ml: pointer to a struct omap_hwmod_link * for the master link
+ * @sl: pointer to a struct omap_hwmod_link * for the slave link
+ *
+ * Return pointers to two struct omap_hwmod_link records, via the
+ * addresses pointed to by @ml and @sl.  Will first attempt to return
+ * memory allocated as part of a large initial block, but if that has
+ * been exhausted, will allocate memory itself.  Since ideally this
+ * second allocation path will never occur, the number of these
+ * 'supplemental' allocations will be logged when debugging is
+ * enabled.  Returns 0.
+ */
+static int __init _alloc_links(struct omap_hwmod_link **ml,
+			       struct omap_hwmod_link **sl)
+{
+	unsigned int sz;
+
+	if ((free_ls + LINKS_PER_OCP_IF) <= max_ls) {
+		*ml = &linkspace[free_ls++];
+		*sl = &linkspace[free_ls++];
+		return 0;
+	}
+
+	sz = sizeof(struct omap_hwmod_link) * LINKS_PER_OCP_IF;
+
+	*sl = NULL;
+	*ml = alloc_bootmem(sz);
+
+	memset(*ml, 0, sz);
+
+	*sl = (void *)(*ml) + sizeof(struct omap_hwmod_link);
+
+	ls_supp++;
+	pr_debug("omap_hwmod: supplemental link allocations needed: %d\n",
+		 ls_supp * LINKS_PER_OCP_IF);
+
+	return 0;
+};
+
+/**
+ * _add_link - add an interconnect between two IP blocks
+ * @oi: pointer to a struct omap_hwmod_ocp_if record
+ *
+ * Add struct omap_hwmod_link records connecting the master IP block
+ * specified in @oi->master to @oi, and connecting the slave IP block
+ * specified in @oi->slave to @oi.  This code is assumed to run before
+ * preemption or SMP has been enabled, thus avoiding the need for
+ * locking in this code.  Changes to this assumption will require
+ * additional locking.  Returns 0.
+ */
+static int __init _add_link(struct omap_hwmod_ocp_if *oi)
+{
+	struct omap_hwmod_link *ml, *sl;
+
+	pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name,
+		 oi->slave->name);
+
+	_alloc_links(&ml, &sl);
+
+	ml->ocp_if = oi;
+	INIT_LIST_HEAD(&ml->node);
+	list_add(&ml->node, &oi->master->master_ports);
+	oi->master->masters_cnt++;
+
+	sl->ocp_if = oi;
+	INIT_LIST_HEAD(&sl->node);
+	list_add(&sl->node, &oi->slave->slave_ports);
+	oi->slave->slaves_cnt++;
+
+	return 0;
+}
+
+/**
+ * _register_link - register a struct omap_hwmod_ocp_if
+ * @oi: struct omap_hwmod_ocp_if *
+ *
+ * Registers the omap_hwmod_ocp_if record @oi.  Returns -EEXIST if it
+ * has already been registered; -EINVAL if @oi is NULL or if the
+ * record pointed to by @oi is missing required fields; or 0 upon
+ * success.
+ *
+ * XXX The data should be copied into bootmem, so the original data
+ * should be marked __initdata and freed after init.  This would allow
+ * unneeded omap_hwmods to be freed on multi-OMAP configurations.
+ */
+static int __init _register_link(struct omap_hwmod_ocp_if *oi)
+{
+	if (!oi || !oi->master || !oi->slave || !oi->user)
+		return -EINVAL;
+
+	if (oi->_int_flags & _OCPIF_INT_FLAGS_REGISTERED)
+		return -EEXIST;
+
+	pr_debug("omap_hwmod: registering link from %s to %s\n",
+		 oi->master->name, oi->slave->name);
+
+	/*
+	 * Register the connected hwmods, if they haven't been
+	 * registered already
+	 */
+	if (oi->master->_state != _HWMOD_STATE_REGISTERED)
+		_register(oi->master);
+
+	if (oi->slave->_state != _HWMOD_STATE_REGISTERED)
+		_register(oi->slave);
+
+	_add_link(oi);
+
+	oi->_int_flags |= _OCPIF_INT_FLAGS_REGISTERED;
+
+	return 0;
+}
+
+/**
+ * _alloc_linkspace - allocate large block of hwmod links
+ * @ois: pointer to an array of struct omap_hwmod_ocp_if records to count
+ *
+ * Allocate a large block of struct omap_hwmod_link records.  This
+ * improves boot time significantly by avoiding the need to allocate
+ * individual records one by one.  If the number of records to
+ * allocate in the block hasn't been manually specified, this function
+ * will count the number of struct omap_hwmod_ocp_if records in @ois
+ * and use that to determine the allocation size.  For SoC families
+ * that require multiple list registrations, such as OMAP3xxx, this
+ * estimation process isn't optimal, so manual estimation is advised
+ * in those cases.  Returns -EEXIST if the allocation has already occurred
+ * or 0 upon success.
+ */
+static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois)
+{
+	unsigned int i = 0;
+	unsigned int sz;
+
+	if (linkspace) {
+		WARN(1, "linkspace already allocated\n");
+		return -EEXIST;
+	}
+
+	if (max_ls == 0)
+		while (ois[i++])
+			max_ls += LINKS_PER_OCP_IF;
+
+	sz = sizeof(struct omap_hwmod_link) * max_ls;
+
+	pr_debug("omap_hwmod: %s: allocating %d byte linkspace (%d links)\n",
+		 __func__, sz, max_ls);
+
+	linkspace = alloc_bootmem(sz);
+
+	memset(linkspace, 0, sz);
+
+	return 0;
+}
 
 /* Public functions */
 
@@ -2004,120 +2558,101 @@
 }
 
 /**
- * omap_hwmod_register - register an array of hwmods
- * @ohs: pointer to an array of omap_hwmods to register
+ * omap_hwmod_register_links - register an array of hwmod links
+ * @ois: pointer to an array of omap_hwmod_ocp_if to register
  *
  * Intended to be called early in boot before the clock framework is
- * initialized.  If @ohs is not null, will register all omap_hwmods
- * listed in @ohs that are valid for this chip.  Returns 0.
+ * initialized.  If @ois is not null, will register all omap_hwmods
+ * listed in @ois that are valid for this chip.  Returns 0.
  */
-int __init omap_hwmod_register(struct omap_hwmod **ohs)
+int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois)
 {
 	int r, i;
 
-	if (!ohs)
+	if (!ois)
 		return 0;
 
+	if (!linkspace) {
+		if (_alloc_linkspace(ois)) {
+			pr_err("omap_hwmod: could not allocate link space\n");
+			return -ENOMEM;
+		}
+	}
+
 	i = 0;
 	do {
-		r = _register(ohs[i]);
-		WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name,
-		     r);
-	} while (ohs[++i]);
+		r = _register_link(ois[i]);
+		WARN(r && r != -EEXIST,
+		     "omap_hwmod: _register_link(%s -> %s) returned %d\n",
+		     ois[i]->master->name, ois[i]->slave->name, r);
+	} while (ois[++i]);
 
 	return 0;
 }
 
-/*
- * _populate_mpu_rt_base - populate the virtual address for a hwmod
+/**
+ * _ensure_mpu_hwmod_is_setup - ensure the MPU SS hwmod is init'ed and set up
+ * @oh: pointer to the hwmod currently being set up (usually not the MPU)
  *
- * Must be called only from omap_hwmod_setup_*() so ioremap works properly.
- * Assumes the caller takes care of locking if needed.
+ * If the hwmod data corresponding to the MPU subsystem IP block
+ * hasn't been initialized and set up yet, do so now.  This must be
+ * done first since sleep dependencies may be added from other hwmods
+ * to the MPU.  Intended to be called only by omap_hwmod_setup*().  No
+ * return value.
  */
-static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data)
+static void __init _ensure_mpu_hwmod_is_setup(struct omap_hwmod *oh)
 {
-	if (oh->_state != _HWMOD_STATE_REGISTERED)
-		return 0;
-
-	if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
-		return 0;
-
-	oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index);
-
-	return 0;
+	if (!mpu_oh || mpu_oh->_state == _HWMOD_STATE_UNKNOWN)
+		pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n",
+		       __func__, MPU_INITIATOR_NAME);
+	else if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh)
+		omap_hwmod_setup_one(MPU_INITIATOR_NAME);
 }
 
 /**
  * omap_hwmod_setup_one - set up a single hwmod
  * @oh_name: const char * name of the already-registered hwmod to set up
  *
- * Must be called after omap2_clk_init().  Resolves the struct clk
- * names to struct clk pointers for each registered omap_hwmod.  Also
- * calls _setup() on each hwmod.  Returns -EINVAL upon error or 0 upon
- * success.
+ * Initialize and set up a single hwmod.  Intended to be used for a
+ * small number of early devices, such as the timer IP blocks used for
+ * the scheduler clock.  Must be called after omap2_clk_init().
+ * Resolves the struct clk names to struct clk pointers for each
+ * registered omap_hwmod.  Also calls _setup() on each hwmod.  Returns
+ * -EINVAL upon error or 0 upon success.
  */
 int __init omap_hwmod_setup_one(const char *oh_name)
 {
 	struct omap_hwmod *oh;
-	int r;
 
 	pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__);
 
-	if (!mpu_oh) {
-		pr_err("omap_hwmod: %s: cannot setup_one: MPU initiator hwmod %s not yet registered\n",
-		       oh_name, MPU_INITIATOR_NAME);
-		return -EINVAL;
-	}
-
 	oh = _lookup(oh_name);
 	if (!oh) {
 		WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name);
 		return -EINVAL;
 	}
 
-	if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh)
-		omap_hwmod_setup_one(MPU_INITIATOR_NAME);
+	_ensure_mpu_hwmod_is_setup(oh);
 
-	r = _populate_mpu_rt_base(oh, NULL);
-	if (IS_ERR_VALUE(r)) {
-		WARN(1, "omap_hwmod: %s: couldn't set mpu_rt_base\n", oh_name);
-		return -EINVAL;
-	}
-
-	r = _init_clocks(oh, NULL);
-	if (IS_ERR_VALUE(r)) {
-		WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh_name);
-		return -EINVAL;
-	}
-
+	_init(oh, NULL);
 	_setup(oh, NULL);
 
 	return 0;
 }
 
 /**
- * omap_hwmod_setup - do some post-clock framework initialization
+ * omap_hwmod_setup_all - set up all registered IP blocks
  *
- * Must be called after omap2_clk_init().  Resolves the struct clk names
- * to struct clk pointers for each registered omap_hwmod.  Also calls
- * _setup() on each hwmod.  Returns 0 upon success.
+ * Initialize and set up all IP blocks registered with the hwmod code.
+ * Must be called after omap2_clk_init().  Resolves the struct clk
+ * names to struct clk pointers for each registered omap_hwmod.  Also
+ * calls _setup() on each hwmod.  Returns 0 upon success.
  */
 static int __init omap_hwmod_setup_all(void)
 {
-	int r;
+	_ensure_mpu_hwmod_is_setup(NULL);
 
-	if (!mpu_oh) {
-		pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n",
-		       __func__, MPU_INITIATOR_NAME);
-		return -EINVAL;
-	}
-
-	r = omap_hwmod_for_each(_populate_mpu_rt_base, NULL);
-
-	r = omap_hwmod_for_each(_init_clocks, NULL);
-	WARN(IS_ERR_VALUE(r),
-	     "omap_hwmod: %s: _init_clocks failed\n", __func__);
-
+	omap_hwmod_for_each(_init, NULL);
 	omap_hwmod_for_each(_setup, NULL);
 
 	return 0;
@@ -2274,6 +2809,10 @@
 	return r;
 }
 
+/*
+ * IP block data retrieval functions
+ */
+
 /**
  * omap_hwmod_count_resources - count number of struct resources needed by hwmod
  * @oh: struct omap_hwmod *
@@ -2292,12 +2831,19 @@
  */
 int omap_hwmod_count_resources(struct omap_hwmod *oh)
 {
-	int ret, i;
+	struct omap_hwmod_ocp_if *os;
+	struct list_head *p;
+	int ret;
+	int i = 0;
 
 	ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh);
 
-	for (i = 0; i < oh->slaves_cnt; i++)
-		ret += _count_ocp_if_addr_spaces(oh->slaves[i]);
+	p = oh->slave_ports.next;
+
+	while (i < oh->slaves_cnt) {
+		os = _fetch_next_ocp_if(&p, &i);
+		ret += _count_ocp_if_addr_spaces(os);
+	}
 
 	return ret;
 }
@@ -2314,7 +2860,9 @@
  */
 int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
 {
-	int i, j, mpu_irqs_cnt, sdma_reqs_cnt;
+	struct omap_hwmod_ocp_if *os;
+	struct list_head *p;
+	int i, j, mpu_irqs_cnt, sdma_reqs_cnt, addr_cnt;
 	int r = 0;
 
 	/* For each IRQ, DMA, memory area, fill in array.*/
@@ -2337,11 +2885,11 @@
 		r++;
 	}
 
-	for (i = 0; i < oh->slaves_cnt; i++) {
-		struct omap_hwmod_ocp_if *os;
-		int addr_cnt;
+	p = oh->slave_ports.next;
 
-		os = oh->slaves[i];
+	i = 0;
+	while (i < oh->slaves_cnt) {
+		os = _fetch_next_ocp_if(&p, &i);
 		addr_cnt = _count_ocp_if_addr_spaces(os);
 
 		for (j = 0; j < addr_cnt; j++) {
@@ -2357,6 +2905,69 @@
 }
 
 /**
+ * omap_hwmod_get_resource_byname - fetch IP block integration data by name
+ * @oh: struct omap_hwmod * to operate on
+ * @type: one of the IORESOURCE_* constants from include/linux/ioport.h
+ * @name: pointer to the name of the data to fetch (optional)
+ * @rsrc: pointer to a struct resource, allocated by the caller
+ *
+ * Retrieve MPU IRQ, SDMA request line, or address space start/end
+ * data for the IP block pointed to by @oh.  The data will be filled
+ * into a struct resource record pointed to by @rsrc.  The struct
+ * resource must be allocated by the caller.  When @name is non-null,
+ * the data associated with the matching entry in the IRQ/SDMA/address
+ * space hwmod data arrays will be returned.  If @name is null, the
+ * first array entry will be returned.  Data order is not meaningful
+ * in hwmod data, so callers are strongly encouraged to use a non-null
+ * @name whenever possible to avoid unpredictable effects if hwmod
+ * data is later added that causes data ordering to change.  This
+ * function is only intended for use by OMAP core code.  Device
+ * drivers should not call this function - the appropriate bus-related
+ * data accessor functions should be used instead.  Returns 0 upon
+ * success or a negative error code upon error.
+ */
+int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type,
+				   const char *name, struct resource *rsrc)
+{
+	int r;
+	unsigned int irq, dma;
+	u32 pa_start, pa_end;
+
+	if (!oh || !rsrc)
+		return -EINVAL;
+
+	if (type == IORESOURCE_IRQ) {
+		r = _get_mpu_irq_by_name(oh, name, &irq);
+		if (r)
+			return r;
+
+		rsrc->start = irq;
+		rsrc->end = irq;
+	} else if (type == IORESOURCE_DMA) {
+		r = _get_sdma_req_by_name(oh, name, &dma);
+		if (r)
+			return r;
+
+		rsrc->start = dma;
+		rsrc->end = dma;
+	} else if (type == IORESOURCE_MEM) {
+		r = _get_addr_space_by_name(oh, name, &pa_start, &pa_end);
+		if (r)
+			return r;
+
+		rsrc->start = pa_start;
+		rsrc->end = pa_end;
+	} else {
+		return -EINVAL;
+	}
+
+	rsrc->flags = type;
+	rsrc->name = name;
+
+	return 0;
+}
+
+/**
  * omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain
  * @oh: struct omap_hwmod *
  *
@@ -2370,6 +2981,7 @@
 struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh)
 {
 	struct clk *c;
+	struct omap_hwmod_ocp_if *oi;
 
 	if (!oh)
 		return NULL;
@@ -2377,9 +2989,10 @@
 	if (oh->_clk) {
 		c = oh->_clk;
 	} else {
-		if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+		oi = _find_mpu_rt_port(oh);
+		if (!oi)
 			return NULL;
-		c = oh->slaves[oh->_mpu_port_index]->_clk;
+		c = oi->_clk;
 	}
 
 	if (!c->clkdm)
@@ -2653,10 +3266,10 @@
  * @state: state that _setup() should leave the hwmod in
  *
  * Sets the hwmod state that @oh will enter at the end of _setup()
- * (called by omap_hwmod_setup_*()).  Only valid to call between
- * calling omap_hwmod_register() and omap_hwmod_setup_*().  Returns
- * 0 upon success or -EINVAL if there is a problem with the arguments
- * or if the hwmod is in the wrong state.
+ * (called by omap_hwmod_setup_*()).  See also the documentation
+ * for _setup_postsetup(), above.  Returns 0 upon success or
+ * -EINVAL if there is a problem with the arguments or if the hwmod is
+ * in the wrong state.
  */
 int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
 {
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index a6bde34..a7640d1 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -2,6 +2,7 @@
  * omap_hwmod_2420_data.c - hardware modules present on the OMAP2420 chips
  *
  * Copyright (C) 2009-2011 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
  * Paul Walmsley
  *
  * This program is free software; you can redistribute it and/or modify
@@ -22,6 +23,7 @@
 #include <plat/dmtimer.h>
 #include <plat/l3_2xxx.h>
 #include <plat/l4_2xxx.h>
+#include <plat/mmc.h>
 
 #include "omap_hwmod_common_data.h"
 
@@ -32,996 +34,51 @@
 /*
  * OMAP2420 hardware module integration data
  *
- * ALl of the data in this section should be autogeneratable from the
+ * All of the data in this section should be autogeneratable from the
  * TI hardware database or other technical documentation.  Data that
  * is driver-specific or driver-kernel integration-specific belongs
  * elsewhere.
  */
 
-static struct omap_hwmod omap2420_mpu_hwmod;
-static struct omap_hwmod omap2420_iva_hwmod;
-static struct omap_hwmod omap2420_l3_main_hwmod;
-static struct omap_hwmod omap2420_l4_core_hwmod;
-static struct omap_hwmod omap2420_dss_core_hwmod;
-static struct omap_hwmod omap2420_dss_dispc_hwmod;
-static struct omap_hwmod omap2420_dss_rfbi_hwmod;
-static struct omap_hwmod omap2420_dss_venc_hwmod;
-static struct omap_hwmod omap2420_wd_timer2_hwmod;
-static struct omap_hwmod omap2420_gpio1_hwmod;
-static struct omap_hwmod omap2420_gpio2_hwmod;
-static struct omap_hwmod omap2420_gpio3_hwmod;
-static struct omap_hwmod omap2420_gpio4_hwmod;
-static struct omap_hwmod omap2420_dma_system_hwmod;
-static struct omap_hwmod omap2420_mcspi1_hwmod;
-static struct omap_hwmod omap2420_mcspi2_hwmod;
-
-/* L3 -> L4_CORE interface */
-static struct omap_hwmod_ocp_if omap2420_l3_main__l4_core = {
-	.master	= &omap2420_l3_main_hwmod,
-	.slave	= &omap2420_l4_core_hwmod,
-	.user	= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* MPU -> L3 interface */
-static struct omap_hwmod_ocp_if omap2420_mpu__l3_main = {
-	.master = &omap2420_mpu_hwmod,
-	.slave	= &omap2420_l3_main_hwmod,
-	.user	= OCP_USER_MPU,
-};
-
-/* Slave interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l3_main_slaves[] = {
-	&omap2420_mpu__l3_main,
-};
-
-/* DSS -> l3 */
-static struct omap_hwmod_ocp_if omap2420_dss__l3 = {
-	.master		= &omap2420_dss_core_hwmod,
-	.slave		= &omap2420_l3_main_hwmod,
-	.fw = {
-		.omap2 = {
-			.l3_perm_bit  = OMAP2_L3_CORE_FW_CONNID_DSS,
-			.flags	= OMAP_FIREWALL_L3,
-		}
-	},
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* Master interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l3_main_masters[] = {
-	&omap2420_l3_main__l4_core,
-};
-
-/* L3 */
-static struct omap_hwmod omap2420_l3_main_hwmod = {
-	.name		= "l3_main",
-	.class		= &l3_hwmod_class,
-	.masters	= omap2420_l3_main_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2420_l3_main_masters),
-	.slaves		= omap2420_l3_main_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_l3_main_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-static struct omap_hwmod omap2420_l4_wkup_hwmod;
-static struct omap_hwmod omap2420_uart1_hwmod;
-static struct omap_hwmod omap2420_uart2_hwmod;
-static struct omap_hwmod omap2420_uart3_hwmod;
-static struct omap_hwmod omap2420_i2c1_hwmod;
-static struct omap_hwmod omap2420_i2c2_hwmod;
-static struct omap_hwmod omap2420_mcbsp1_hwmod;
-static struct omap_hwmod omap2420_mcbsp2_hwmod;
-
-/* l4 core -> mcspi1 interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__mcspi1 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_mcspi1_hwmod,
-	.clk		= "mcspi1_ick",
-	.addr		= omap2_mcspi1_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 core -> mcspi2 interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__mcspi2 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_mcspi2_hwmod,
-	.clk		= "mcspi2_ick",
-	.addr		= omap2_mcspi2_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4_CORE -> L4_WKUP interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
-	.master	= &omap2420_l4_core_hwmod,
-	.slave	= &omap2420_l4_wkup_hwmod,
-	.user	= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> UART1 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_uart1_hwmod,
-	.clk		= "uart1_ick",
-	.addr		= omap2xxx_uart1_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> UART2 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_uart2_hwmod,
-	.clk		= "uart2_ick",
-	.addr		= omap2xxx_uart2_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 PER -> UART3 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_uart3_hwmod,
-	.clk		= "uart3_ick",
-	.addr		= omap2xxx_uart3_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> I2C1 interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__i2c1 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_i2c1_hwmod,
-	.clk		= "i2c1_ick",
-	.addr		= omap2_i2c1_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> I2C2 interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__i2c2 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_i2c2_hwmod,
-	.clk		= "i2c2_ick",
-	.addr		= omap2_i2c2_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* Slave interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = {
-	&omap2420_l3_main__l4_core,
-};
-
-/* Master interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = {
-	&omap2420_l4_core__l4_wkup,
-	&omap2_l4_core__uart1,
-	&omap2_l4_core__uart2,
-	&omap2_l4_core__uart3,
-	&omap2420_l4_core__i2c1,
-	&omap2420_l4_core__i2c2
-};
-
-/* L4 CORE */
-static struct omap_hwmod omap2420_l4_core_hwmod = {
-	.name		= "l4_core",
-	.class		= &l4_hwmod_class,
-	.masters	= omap2420_l4_core_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2420_l4_core_masters),
-	.slaves		= omap2420_l4_core_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_l4_core_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* Slave interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l4_wkup_slaves[] = {
-	&omap2420_l4_core__l4_wkup,
-};
-
-/* Master interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l4_wkup_masters[] = {
-};
-
-/* L4 WKUP */
-static struct omap_hwmod omap2420_l4_wkup_hwmod = {
-	.name		= "l4_wkup",
-	.class		= &l4_hwmod_class,
-	.masters	= omap2420_l4_wkup_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2420_l4_wkup_masters),
-	.slaves		= omap2420_l4_wkup_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_l4_wkup_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* Master interfaces on the MPU device */
-static struct omap_hwmod_ocp_if *omap2420_mpu_masters[] = {
-	&omap2420_mpu__l3_main,
-};
-
-/* MPU */
-static struct omap_hwmod omap2420_mpu_hwmod = {
-	.name		= "mpu",
-	.class		= &mpu_hwmod_class,
-	.main_clk	= "mpu_ck",
-	.masters	= omap2420_mpu_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2420_mpu_masters),
-};
-
 /*
- * IVA1 interface data
+ * IP blocks
  */
 
-/* IVA <- L3 interface */
-static struct omap_hwmod_ocp_if omap2420_l3__iva = {
-	.master		= &omap2420_l3_main_hwmod,
-	.slave		= &omap2420_iva_hwmod,
-	.clk		= "iva1_ifck",
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+/* IVA1 (IVA1) */
+static struct omap_hwmod_class iva1_hwmod_class = {
+	.name		= "iva1",
 };
 
-static struct omap_hwmod_ocp_if *omap2420_iva_masters[] = {
-	&omap2420_l3__iva,
+static struct omap_hwmod_rst_info omap2420_iva_resets[] = {
+	{ .name = "iva", .rst_shift = 8 },
 };
 
-/*
- * IVA2 (IVA2)
- */
-
 static struct omap_hwmod omap2420_iva_hwmod = {
 	.name		= "iva",
-	.class		= &iva_hwmod_class,
-	.masters	= omap2420_iva_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2420_iva_masters),
+	.class		= &iva1_hwmod_class,
+	.clkdm_name	= "iva1_clkdm",
+	.rst_lines	= omap2420_iva_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap2420_iva_resets),
+	.main_clk	= "iva1_ifck",
 };
 
-/* always-on timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
-	.timer_capability       = OMAP_TIMER_ALWON,
+/* DSP */
+static struct omap_hwmod_class dsp_hwmod_class = {
+	.name		= "dsp",
 };
 
-/* pwm timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
-	.timer_capability       = OMAP_TIMER_HAS_PWM,
+static struct omap_hwmod_rst_info omap2420_dsp_resets[] = {
+	{ .name = "logic", .rst_shift = 0 },
+	{ .name = "mmu", .rst_shift = 1 },
 };
 
-/* timer1 */
-static struct omap_hwmod omap2420_timer1_hwmod;
-
-static struct omap_hwmod_addr_space omap2420_timer1_addrs[] = {
-	{
-		.pa_start	= 0x48028000,
-		.pa_end		= 0x48028000 + SZ_1K - 1,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-/* l4_wkup -> timer1 */
-static struct omap_hwmod_ocp_if omap2420_l4_wkup__timer1 = {
-	.master		= &omap2420_l4_wkup_hwmod,
-	.slave		= &omap2420_timer1_hwmod,
-	.clk		= "gpt1_ick",
-	.addr		= omap2420_timer1_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer1 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer1_slaves[] = {
-	&omap2420_l4_wkup__timer1,
-};
-
-/* timer1 hwmod */
-static struct omap_hwmod omap2420_timer1_hwmod = {
-	.name		= "timer1",
-	.mpu_irqs	= omap2_timer1_mpu_irqs,
-	.main_clk	= "gpt1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT1_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2420_timer1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer1_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer2 */
-static struct omap_hwmod omap2420_timer2_hwmod;
-
-/* l4_core -> timer2 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer2 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer2_hwmod,
-	.clk		= "gpt2_ick",
-	.addr		= omap2xxx_timer2_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer2 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer2_slaves[] = {
-	&omap2420_l4_core__timer2,
-};
-
-/* timer2 hwmod */
-static struct omap_hwmod omap2420_timer2_hwmod = {
-	.name		= "timer2",
-	.mpu_irqs	= omap2_timer2_mpu_irqs,
-	.main_clk	= "gpt2_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT2_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2420_timer2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer2_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer3 */
-static struct omap_hwmod omap2420_timer3_hwmod;
-
-/* l4_core -> timer3 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer3 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer3_hwmod,
-	.clk		= "gpt3_ick",
-	.addr		= omap2xxx_timer3_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer3 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer3_slaves[] = {
-	&omap2420_l4_core__timer3,
-};
-
-/* timer3 hwmod */
-static struct omap_hwmod omap2420_timer3_hwmod = {
-	.name		= "timer3",
-	.mpu_irqs	= omap2_timer3_mpu_irqs,
-	.main_clk	= "gpt3_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT3_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2420_timer3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer3_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer4 */
-static struct omap_hwmod omap2420_timer4_hwmod;
-
-/* l4_core -> timer4 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer4 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer4_hwmod,
-	.clk		= "gpt4_ick",
-	.addr		= omap2xxx_timer4_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer4 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer4_slaves[] = {
-	&omap2420_l4_core__timer4,
-};
-
-/* timer4 hwmod */
-static struct omap_hwmod omap2420_timer4_hwmod = {
-	.name		= "timer4",
-	.mpu_irqs	= omap2_timer4_mpu_irqs,
-	.main_clk	= "gpt4_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT4_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2420_timer4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer4_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer5 */
-static struct omap_hwmod omap2420_timer5_hwmod;
-
-/* l4_core -> timer5 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer5 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer5_hwmod,
-	.clk		= "gpt5_ick",
-	.addr		= omap2xxx_timer5_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer5 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer5_slaves[] = {
-	&omap2420_l4_core__timer5,
-};
-
-/* timer5 hwmod */
-static struct omap_hwmod omap2420_timer5_hwmod = {
-	.name		= "timer5",
-	.mpu_irqs	= omap2_timer5_mpu_irqs,
-	.main_clk	= "gpt5_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT5_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2420_timer5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer5_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-
-/* timer6 */
-static struct omap_hwmod omap2420_timer6_hwmod;
-
-/* l4_core -> timer6 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer6 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer6_hwmod,
-	.clk		= "gpt6_ick",
-	.addr		= omap2xxx_timer6_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer6 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer6_slaves[] = {
-	&omap2420_l4_core__timer6,
-};
-
-/* timer6 hwmod */
-static struct omap_hwmod omap2420_timer6_hwmod = {
-	.name		= "timer6",
-	.mpu_irqs	= omap2_timer6_mpu_irqs,
-	.main_clk	= "gpt6_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT6_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2420_timer6_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer6_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer7 */
-static struct omap_hwmod omap2420_timer7_hwmod;
-
-/* l4_core -> timer7 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer7 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer7_hwmod,
-	.clk		= "gpt7_ick",
-	.addr		= omap2xxx_timer7_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer7 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer7_slaves[] = {
-	&omap2420_l4_core__timer7,
-};
-
-/* timer7 hwmod */
-static struct omap_hwmod omap2420_timer7_hwmod = {
-	.name		= "timer7",
-	.mpu_irqs	= omap2_timer7_mpu_irqs,
-	.main_clk	= "gpt7_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT7_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2420_timer7_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer7_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer8 */
-static struct omap_hwmod omap2420_timer8_hwmod;
-
-/* l4_core -> timer8 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer8 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer8_hwmod,
-	.clk		= "gpt8_ick",
-	.addr		= omap2xxx_timer8_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer8 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer8_slaves[] = {
-	&omap2420_l4_core__timer8,
-};
-
-/* timer8 hwmod */
-static struct omap_hwmod omap2420_timer8_hwmod = {
-	.name		= "timer8",
-	.mpu_irqs	= omap2_timer8_mpu_irqs,
-	.main_clk	= "gpt8_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT8_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2420_timer8_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer8_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer9 */
-static struct omap_hwmod omap2420_timer9_hwmod;
-
-/* l4_core -> timer9 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer9 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer9_hwmod,
-	.clk		= "gpt9_ick",
-	.addr		= omap2xxx_timer9_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer9 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer9_slaves[] = {
-	&omap2420_l4_core__timer9,
-};
-
-/* timer9 hwmod */
-static struct omap_hwmod omap2420_timer9_hwmod = {
-	.name		= "timer9",
-	.mpu_irqs	= omap2_timer9_mpu_irqs,
-	.main_clk	= "gpt9_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT9_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap2420_timer9_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer9_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer10 */
-static struct omap_hwmod omap2420_timer10_hwmod;
-
-/* l4_core -> timer10 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer10 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer10_hwmod,
-	.clk		= "gpt10_ick",
-	.addr		= omap2_timer10_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer10 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer10_slaves[] = {
-	&omap2420_l4_core__timer10,
-};
-
-/* timer10 hwmod */
-static struct omap_hwmod omap2420_timer10_hwmod = {
-	.name		= "timer10",
-	.mpu_irqs	= omap2_timer10_mpu_irqs,
-	.main_clk	= "gpt10_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT10_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap2420_timer10_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer10_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer11 */
-static struct omap_hwmod omap2420_timer11_hwmod;
-
-/* l4_core -> timer11 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer11 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer11_hwmod,
-	.clk		= "gpt11_ick",
-	.addr		= omap2_timer11_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer11 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer11_slaves[] = {
-	&omap2420_l4_core__timer11,
-};
-
-/* timer11 hwmod */
-static struct omap_hwmod omap2420_timer11_hwmod = {
-	.name		= "timer11",
-	.mpu_irqs	= omap2_timer11_mpu_irqs,
-	.main_clk	= "gpt11_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT11_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap2420_timer11_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer11_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer12 */
-static struct omap_hwmod omap2420_timer12_hwmod;
-
-/* l4_core -> timer12 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer12 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_timer12_hwmod,
-	.clk		= "gpt12_ick",
-	.addr		= omap2xxx_timer12_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer12 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer12_slaves[] = {
-	&omap2420_l4_core__timer12,
-};
-
-/* timer12 hwmod */
-static struct omap_hwmod omap2420_timer12_hwmod = {
-	.name		= "timer12",
-	.mpu_irqs	= omap2xxx_timer12_mpu_irqs,
-	.main_clk	= "gpt12_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT12_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap2420_timer12_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_timer12_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* l4_wkup -> wd_timer2 */
-static struct omap_hwmod_addr_space omap2420_wd_timer2_addrs[] = {
-	{
-		.pa_start	= 0x48022000,
-		.pa_end		= 0x4802207f,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2420_l4_wkup__wd_timer2 = {
-	.master		= &omap2420_l4_wkup_hwmod,
-	.slave		= &omap2420_wd_timer2_hwmod,
-	.clk		= "mpu_wdt_ick",
-	.addr		= omap2420_wd_timer2_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* wd_timer2 */
-static struct omap_hwmod_ocp_if *omap2420_wd_timer2_slaves[] = {
-	&omap2420_l4_wkup__wd_timer2,
-};
-
-static struct omap_hwmod omap2420_wd_timer2_hwmod = {
-	.name		= "wd_timer2",
-	.class		= &omap2xxx_wd_timer_hwmod_class,
-	.main_clk	= "mpu_wdt_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
-		},
-	},
-	.slaves		= omap2420_wd_timer2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_wd_timer2_slaves),
-};
-
-/* UART1 */
-
-static struct omap_hwmod_ocp_if *omap2420_uart1_slaves[] = {
-	&omap2_l4_core__uart1,
-};
-
-static struct omap_hwmod omap2420_uart1_hwmod = {
-	.name		= "uart1",
-	.mpu_irqs	= omap2_uart1_mpu_irqs,
-	.sdma_reqs	= omap2_uart1_sdma_reqs,
-	.main_clk	= "uart1_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_UART1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
-		},
-	},
-	.slaves		= omap2420_uart1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_uart1_slaves),
-	.class		= &omap2_uart_class,
-};
-
-/* UART2 */
-
-static struct omap_hwmod_ocp_if *omap2420_uart2_slaves[] = {
-	&omap2_l4_core__uart2,
-};
-
-static struct omap_hwmod omap2420_uart2_hwmod = {
-	.name		= "uart2",
-	.mpu_irqs	= omap2_uart2_mpu_irqs,
-	.sdma_reqs	= omap2_uart2_sdma_reqs,
-	.main_clk	= "uart2_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_UART2_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
-		},
-	},
-	.slaves		= omap2420_uart2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_uart2_slaves),
-	.class		= &omap2_uart_class,
-};
-
-/* UART3 */
-
-static struct omap_hwmod_ocp_if *omap2420_uart3_slaves[] = {
-	&omap2_l4_core__uart3,
-};
-
-static struct omap_hwmod omap2420_uart3_hwmod = {
-	.name		= "uart3",
-	.mpu_irqs	= omap2_uart3_mpu_irqs,
-	.sdma_reqs	= omap2_uart3_sdma_reqs,
-	.main_clk	= "uart3_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 2,
-			.module_bit = OMAP24XX_EN_UART3_SHIFT,
-			.idlest_reg_id = 2,
-			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
-		},
-	},
-	.slaves		= omap2420_uart3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_uart3_slaves),
-	.class		= &omap2_uart_class,
-};
-
-/* dss */
-/* dss master ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_masters[] = {
-	&omap2420_dss__l3,
-};
-
-/* l4_core -> dss */
-static struct omap_hwmod_ocp_if omap2420_l4_core__dss = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_dss_core_hwmod,
-	.clk		= "dss_ick",
-	.addr		= omap2_dss_addrs,
-	.fw = {
-		.omap2 = {
-			.l4_fw_region  = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
-			.flags	= OMAP_FIREWALL_L4,
-		}
-	},
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_slaves[] = {
-	&omap2420_l4_core__dss,
-};
-
-static struct omap_hwmod_opt_clk dss_opt_clks[] = {
-	/*
-	 * The DSS HW needs all DSS clocks enabled during reset. The dss_core
-	 * driver does not use these clocks.
-	 */
-	{ .role = "tv_clk", .clk = "dss_54m_fck" },
-	{ .role = "sys_clk", .clk = "dss2_fck" },
-};
-
-static struct omap_hwmod omap2420_dss_core_hwmod = {
-	.name		= "dss_core",
-	.class		= &omap2_dss_hwmod_class,
-	.main_clk	= "dss1_fck", /* instead of dss_fck */
-	.sdma_reqs	= omap2xxx_dss_sdma_chs,
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
-		},
-	},
-	.opt_clks	= dss_opt_clks,
-	.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
-	.slaves		= omap2420_dss_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_dss_slaves),
-	.masters	= omap2420_dss_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2420_dss_masters),
-	.flags		= HWMOD_NO_IDLEST | HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-};
-
-/* l4_core -> dss_dispc */
-static struct omap_hwmod_ocp_if omap2420_l4_core__dss_dispc = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_dss_dispc_hwmod,
-	.clk		= "dss_ick",
-	.addr		= omap2_dss_dispc_addrs,
-	.fw = {
-		.omap2 = {
-			.l4_fw_region  = OMAP2420_L4_CORE_FW_DSS_DISPC_REGION,
-			.flags	= OMAP_FIREWALL_L4,
-		}
-	},
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_dispc slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_dispc_slaves[] = {
-	&omap2420_l4_core__dss_dispc,
-};
-
-static struct omap_hwmod omap2420_dss_dispc_hwmod = {
-	.name		= "dss_dispc",
-	.class		= &omap2_dispc_hwmod_class,
-	.mpu_irqs	= omap2_dispc_irqs,
-	.main_clk	= "dss1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
-		},
-	},
-	.slaves		= omap2420_dss_dispc_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_dss_dispc_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-	.dev_attr	= &omap2_3_dss_dispc_dev_attr
-};
-
-/* l4_core -> dss_rfbi */
-static struct omap_hwmod_ocp_if omap2420_l4_core__dss_rfbi = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_dss_rfbi_hwmod,
-	.clk		= "dss_ick",
-	.addr		= omap2_dss_rfbi_addrs,
-	.fw = {
-		.omap2 = {
-			.l4_fw_region  = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
-			.flags	= OMAP_FIREWALL_L4,
-		}
-	},
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_rfbi slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_rfbi_slaves[] = {
-	&omap2420_l4_core__dss_rfbi,
-};
-
-static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
-	{ .role = "ick", .clk = "dss_ick" },
-};
-
-static struct omap_hwmod omap2420_dss_rfbi_hwmod = {
-	.name		= "dss_rfbi",
-	.class		= &omap2_rfbi_hwmod_class,
-	.main_clk	= "dss1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
-			.module_offs = CORE_MOD,
-		},
-	},
-	.opt_clks	= dss_rfbi_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_rfbi_opt_clks),
-	.slaves		= omap2420_dss_rfbi_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_dss_rfbi_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* l4_core -> dss_venc */
-static struct omap_hwmod_ocp_if omap2420_l4_core__dss_venc = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_dss_venc_hwmod,
-	.clk		= "dss_ick",
-	.addr		= omap2_dss_venc_addrs,
-	.fw = {
-		.omap2 = {
-			.l4_fw_region  = OMAP2420_L4_CORE_FW_DSS_VENC_REGION,
-			.flags	= OMAP_FIREWALL_L4,
-		}
-	},
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_venc slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_venc_slaves[] = {
-	&omap2420_l4_core__dss_venc,
-};
-
-static struct omap_hwmod omap2420_dss_venc_hwmod = {
-	.name		= "dss_venc",
-	.class		= &omap2_venc_hwmod_class,
-	.main_clk	= "dss_54m_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
-			.module_offs = CORE_MOD,
-		},
-	},
-	.slaves		= omap2420_dss_venc_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_dss_venc_slaves),
-	.flags		= HWMOD_NO_IDLEST,
+static struct omap_hwmod omap2420_dsp_hwmod = {
+	.name		= "dsp",
+	.class		= &dsp_hwmod_class,
+	.clkdm_name	= "dsp_clkdm",
+	.rst_lines	= omap2420_dsp_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap2420_dsp_resets),
+	.main_clk	= "dsp_fck",
 };
 
 /* I2C common */
@@ -1048,11 +105,6 @@
 };
 
 /* I2C1 */
-
-static struct omap_hwmod_ocp_if *omap2420_i2c1_slaves[] = {
-	&omap2420_l4_core__i2c1,
-};
-
 static struct omap_hwmod omap2420_i2c1_hwmod = {
 	.name		= "i2c1",
 	.mpu_irqs	= omap2_i2c1_mpu_irqs,
@@ -1067,19 +119,12 @@
 			.idlest_idle_bit = OMAP2420_ST_I2C1_SHIFT,
 		},
 	},
-	.slaves		= omap2420_i2c1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_i2c1_slaves),
 	.class		= &i2c_class,
 	.dev_attr	= &i2c_dev_attr,
 	.flags		= HWMOD_16BIT_REG,
 };
 
 /* I2C2 */
-
-static struct omap_hwmod_ocp_if *omap2420_i2c2_slaves[] = {
-	&omap2420_l4_core__i2c2,
-};
-
 static struct omap_hwmod omap2420_i2c2_hwmod = {
 	.name		= "i2c2",
 	.mpu_irqs	= omap2_i2c2_mpu_irqs,
@@ -1094,191 +139,11 @@
 			.idlest_idle_bit = OMAP2420_ST_I2C2_SHIFT,
 		},
 	},
-	.slaves		= omap2420_i2c2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_i2c2_slaves),
 	.class		= &i2c_class,
 	.dev_attr	= &i2c_dev_attr,
 	.flags		= HWMOD_16BIT_REG,
 };
 
-/* l4_wkup -> gpio1 */
-static struct omap_hwmod_addr_space omap2420_gpio1_addr_space[] = {
-	{
-		.pa_start	= 0x48018000,
-		.pa_end		= 0x480181ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio1 = {
-	.master		= &omap2420_l4_wkup_hwmod,
-	.slave		= &omap2420_gpio1_hwmod,
-	.clk		= "gpios_ick",
-	.addr		= omap2420_gpio1_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> gpio2 */
-static struct omap_hwmod_addr_space omap2420_gpio2_addr_space[] = {
-	{
-		.pa_start	= 0x4801a000,
-		.pa_end		= 0x4801a1ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio2 = {
-	.master		= &omap2420_l4_wkup_hwmod,
-	.slave		= &omap2420_gpio2_hwmod,
-	.clk		= "gpios_ick",
-	.addr		= omap2420_gpio2_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> gpio3 */
-static struct omap_hwmod_addr_space omap2420_gpio3_addr_space[] = {
-	{
-		.pa_start	= 0x4801c000,
-		.pa_end		= 0x4801c1ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio3 = {
-	.master		= &omap2420_l4_wkup_hwmod,
-	.slave		= &omap2420_gpio3_hwmod,
-	.clk		= "gpios_ick",
-	.addr		= omap2420_gpio3_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> gpio4 */
-static struct omap_hwmod_addr_space omap2420_gpio4_addr_space[] = {
-	{
-		.pa_start	= 0x4801e000,
-		.pa_end		= 0x4801e1ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio4 = {
-	.master		= &omap2420_l4_wkup_hwmod,
-	.slave		= &omap2420_gpio4_hwmod,
-	.clk		= "gpios_ick",
-	.addr		= omap2420_gpio4_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* gpio dev_attr */
-static struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width = 32,
-	.dbck_flag = false,
-};
-
-/* gpio1 */
-static struct omap_hwmod_ocp_if *omap2420_gpio1_slaves[] = {
-	&omap2420_l4_wkup__gpio1,
-};
-
-static struct omap_hwmod omap2420_gpio1_hwmod = {
-	.name		= "gpio1",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio1_irqs,
-	.main_clk	= "gpios_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
-		},
-	},
-	.slaves		= omap2420_gpio1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_gpio1_slaves),
-	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio2 */
-static struct omap_hwmod_ocp_if *omap2420_gpio2_slaves[] = {
-	&omap2420_l4_wkup__gpio2,
-};
-
-static struct omap_hwmod omap2420_gpio2_hwmod = {
-	.name		= "gpio2",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio2_irqs,
-	.main_clk	= "gpios_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
-		},
-	},
-	.slaves		= omap2420_gpio2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_gpio2_slaves),
-	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio3 */
-static struct omap_hwmod_ocp_if *omap2420_gpio3_slaves[] = {
-	&omap2420_l4_wkup__gpio3,
-};
-
-static struct omap_hwmod omap2420_gpio3_hwmod = {
-	.name		= "gpio3",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio3_irqs,
-	.main_clk	= "gpios_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
-		},
-	},
-	.slaves		= omap2420_gpio3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_gpio3_slaves),
-	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio4 */
-static struct omap_hwmod_ocp_if *omap2420_gpio4_slaves[] = {
-	&omap2420_l4_wkup__gpio4,
-};
-
-static struct omap_hwmod omap2420_gpio4_hwmod = {
-	.name		= "gpio4",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio4_irqs,
-	.main_clk	= "gpios_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
-		},
-	},
-	.slaves		= omap2420_gpio4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_gpio4_slaves),
-	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
 /* dma attributes */
 static struct omap_dma_dev_attr dma_dev_attr = {
 	.dev_caps  = RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY |
@@ -1286,67 +151,22 @@
 	.lch_count = 32,
 };
 
-/* dma_system -> L3 */
-static struct omap_hwmod_ocp_if omap2420_dma_system__l3 = {
-	.master		= &omap2420_dma_system_hwmod,
-	.slave		= &omap2420_l3_main_hwmod,
-	.clk		= "core_l3_ck",
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dma_system master ports */
-static struct omap_hwmod_ocp_if *omap2420_dma_system_masters[] = {
-	&omap2420_dma_system__l3,
-};
-
-/* l4_core -> dma_system */
-static struct omap_hwmod_ocp_if omap2420_l4_core__dma_system = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_dma_system_hwmod,
-	.clk		= "sdma_ick",
-	.addr		= omap2_dma_system_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dma_system slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dma_system_slaves[] = {
-	&omap2420_l4_core__dma_system,
-};
-
 static struct omap_hwmod omap2420_dma_system_hwmod = {
 	.name		= "dma",
 	.class		= &omap2xxx_dma_hwmod_class,
 	.mpu_irqs	= omap2_dma_system_irqs,
 	.main_clk	= "core_l3_ck",
-	.slaves		= omap2420_dma_system_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_dma_system_slaves),
-	.masters	= omap2420_dma_system_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2420_dma_system_masters),
 	.dev_attr	= &dma_dev_attr,
 	.flags		= HWMOD_NO_IDLEST,
 };
 
 /* mailbox */
-static struct omap_hwmod omap2420_mailbox_hwmod;
 static struct omap_hwmod_irq_info omap2420_mailbox_irqs[] = {
 	{ .name = "dsp", .irq = 26 },
 	{ .name = "iva", .irq = 34 },
 	{ .irq = -1 }
 };
 
-/* l4_core -> mailbox */
-static struct omap_hwmod_ocp_if omap2420_l4_core__mailbox = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_mailbox_hwmod,
-	.addr		= omap2_mailbox_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mailbox slave ports */
-static struct omap_hwmod_ocp_if *omap2420_mailbox_slaves[] = {
-	&omap2420_l4_core__mailbox,
-};
-
 static struct omap_hwmod omap2420_mailbox_hwmod = {
 	.name		= "mailbox",
 	.class		= &omap2xxx_mailbox_hwmod_class,
@@ -1361,66 +181,6 @@
 			.idlest_idle_bit = OMAP24XX_ST_MAILBOXES_SHIFT,
 		},
 	},
-	.slaves		= omap2420_mailbox_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_mailbox_slaves),
-};
-
-/* mcspi1 */
-static struct omap_hwmod_ocp_if *omap2420_mcspi1_slaves[] = {
-	&omap2420_l4_core__mcspi1,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
-	.num_chipselect = 4,
-};
-
-static struct omap_hwmod omap2420_mcspi1_hwmod = {
-	.name		= "mcspi1_hwmod",
-	.mpu_irqs	= omap2_mcspi1_mpu_irqs,
-	.sdma_reqs	= omap2_mcspi1_sdma_reqs,
-	.main_clk	= "mcspi1_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_MCSPI1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_MCSPI1_SHIFT,
-		},
-	},
-	.slaves		= omap2420_mcspi1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_mcspi1_slaves),
-	.class		= &omap2xxx_mcspi_class,
-	.dev_attr	= &omap_mcspi1_dev_attr,
-};
-
-/* mcspi2 */
-static struct omap_hwmod_ocp_if *omap2420_mcspi2_slaves[] = {
-	&omap2420_l4_core__mcspi2,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
-	.num_chipselect = 2,
-};
-
-static struct omap_hwmod omap2420_mcspi2_hwmod = {
-	.name		= "mcspi2_hwmod",
-	.mpu_irqs	= omap2_mcspi2_mpu_irqs,
-	.sdma_reqs	= omap2_mcspi2_sdma_reqs,
-	.main_clk	= "mcspi2_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_MCSPI2_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_MCSPI2_SHIFT,
-		},
-	},
-	.slaves		= omap2420_mcspi2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_mcspi2_slaves),
-	.class		= &omap2xxx_mcspi_class,
-	.dev_attr	= &omap_mcspi2_dev_attr,
 };
 
 /*
@@ -1439,20 +199,6 @@
 	{ .irq = -1 }
 };
 
-/* l4_core -> mcbsp1 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp1 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_mcbsp1_hwmod,
-	.clk		= "mcbsp1_ick",
-	.addr		= omap2_mcbsp1_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp1 slave ports */
-static struct omap_hwmod_ocp_if *omap2420_mcbsp1_slaves[] = {
-	&omap2420_l4_core__mcbsp1,
-};
-
 static struct omap_hwmod omap2420_mcbsp1_hwmod = {
 	.name		= "mcbsp1",
 	.class		= &omap2420_mcbsp_hwmod_class,
@@ -1468,8 +214,6 @@
 			.idlest_idle_bit = OMAP24XX_ST_MCBSP1_SHIFT,
 		},
 	},
-	.slaves		= omap2420_mcbsp1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_mcbsp1_slaves),
 };
 
 /* mcbsp2 */
@@ -1479,20 +223,6 @@
 	{ .irq = -1 }
 };
 
-/* l4_core -> mcbsp2 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp2 = {
-	.master		= &omap2420_l4_core_hwmod,
-	.slave		= &omap2420_mcbsp2_hwmod,
-	.clk		= "mcbsp2_ick",
-	.addr		= omap2xxx_mcbsp2_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp2 slave ports */
-static struct omap_hwmod_ocp_if *omap2420_mcbsp2_slaves[] = {
-	&omap2420_l4_core__mcbsp2,
-};
-
 static struct omap_hwmod omap2420_mcbsp2_hwmod = {
 	.name		= "mcbsp2",
 	.class		= &omap2420_mcbsp_hwmod_class,
@@ -1508,66 +238,352 @@
 			.idlest_idle_bit = OMAP24XX_ST_MCBSP2_SHIFT,
 		},
 	},
-	.slaves		= omap2420_mcbsp2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2420_mcbsp2_slaves),
 };
 
-static __initdata struct omap_hwmod *omap2420_hwmods[] = {
-	&omap2420_l3_main_hwmod,
-	&omap2420_l4_core_hwmod,
-	&omap2420_l4_wkup_hwmod,
-	&omap2420_mpu_hwmod,
-	&omap2420_iva_hwmod,
+static struct omap_hwmod_class_sysconfig omap2420_msdi_sysc = {
+	.rev_offs	= 0x3c,
+	.sysc_offs	= 0x64,
+	.syss_offs	= 0x68,
+	.sysc_flags	= (SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
 
-	&omap2420_timer1_hwmod,
-	&omap2420_timer2_hwmod,
-	&omap2420_timer3_hwmod,
-	&omap2420_timer4_hwmod,
-	&omap2420_timer5_hwmod,
-	&omap2420_timer6_hwmod,
-	&omap2420_timer7_hwmod,
-	&omap2420_timer8_hwmod,
-	&omap2420_timer9_hwmod,
-	&omap2420_timer10_hwmod,
-	&omap2420_timer11_hwmod,
-	&omap2420_timer12_hwmod,
+static struct omap_hwmod_class omap2420_msdi_hwmod_class = {
+	.name	= "msdi",
+	.sysc	= &omap2420_msdi_sysc,
+	.reset	= &omap_msdi_reset,
+};
 
-	&omap2420_wd_timer2_hwmod,
-	&omap2420_uart1_hwmod,
-	&omap2420_uart2_hwmod,
-	&omap2420_uart3_hwmod,
-	/* dss class */
-	&omap2420_dss_core_hwmod,
-	&omap2420_dss_dispc_hwmod,
-	&omap2420_dss_rfbi_hwmod,
-	&omap2420_dss_venc_hwmod,
-	/* i2c class */
-	&omap2420_i2c1_hwmod,
-	&omap2420_i2c2_hwmod,
+/* msdi1 */
+static struct omap_hwmod_irq_info omap2420_msdi1_irqs[] = {
+	{ .irq = 83 },
+	{ .irq = -1 }
+};
 
-	/* gpio class */
-	&omap2420_gpio1_hwmod,
-	&omap2420_gpio2_hwmod,
-	&omap2420_gpio3_hwmod,
-	&omap2420_gpio4_hwmod,
+static struct omap_hwmod_dma_info omap2420_msdi1_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 61 }, /* OMAP24XX_DMA_MMC1_TX */
+	{ .name = "rx", .dma_req = 62 }, /* OMAP24XX_DMA_MMC1_RX */
+	{ .dma_req = -1 }
+};
 
-	/* dma_system class*/
-	&omap2420_dma_system_hwmod,
+static struct omap_hwmod omap2420_msdi1_hwmod = {
+	.name		= "msdi1",
+	.class		= &omap2420_msdi_hwmod_class,
+	.mpu_irqs	= omap2420_msdi1_irqs,
+	.sdma_reqs	= omap2420_msdi1_sdma_reqs,
+	.main_clk	= "mmc_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP2420_EN_MMC_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP2420_ST_MMC_SHIFT,
+		},
+	},
+	.flags		= HWMOD_16BIT_REG,
+};
 
-	/* mailbox class */
-	&omap2420_mailbox_hwmod,
+/* HDQ1W/1-wire */
+static struct omap_hwmod omap2420_hdq1w_hwmod = {
+	.name		= "hdq1w",
+	.mpu_irqs	= omap2_hdq1w_mpu_irqs,
+	.main_clk	= "hdq_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_HDQ_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_HDQ_SHIFT,
+		},
+	},
+	.class		= &omap2_hdq1w_class,
+};
 
-	/* mcbsp class */
-	&omap2420_mcbsp1_hwmod,
-	&omap2420_mcbsp2_hwmod,
+/*
+ * interfaces
+ */
 
-	/* mcspi class */
-	&omap2420_mcspi1_hwmod,
-	&omap2420_mcspi2_hwmod,
+/* L4 CORE -> I2C1 interface */
+static struct omap_hwmod_ocp_if omap2420_l4_core__i2c1 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2420_i2c1_hwmod,
+	.clk		= "i2c1_ick",
+	.addr		= omap2_i2c1_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> I2C2 interface */
+static struct omap_hwmod_ocp_if omap2420_l4_core__i2c2 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2420_i2c2_hwmod,
+	.clk		= "i2c2_ick",
+	.addr		= omap2_i2c2_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* IVA <- L3 interface */
+static struct omap_hwmod_ocp_if omap2420_l3__iva = {
+	.master		= &omap2xxx_l3_main_hwmod,
+	.slave		= &omap2420_iva_hwmod,
+	.clk		= "core_l3_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* DSP <- L3 interface */
+static struct omap_hwmod_ocp_if omap2420_l3__dsp = {
+	.master		= &omap2xxx_l3_main_hwmod,
+	.slave		= &omap2420_dsp_hwmod,
+	.clk		= "dsp_ick",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2420_timer1_addrs[] = {
+	{
+		.pa_start	= 0x48028000,
+		.pa_end		= 0x48028000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__timer1 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_timer1_hwmod,
+	.clk		= "gpt1_ick",
+	.addr		= omap2420_timer1_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2420_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x48022000,
+		.pa_end		= 0x4802207f,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__wd_timer2 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_wd_timer2_hwmod,
+	.clk		= "mpu_wdt_ick",
+	.addr		= omap2420_wd_timer2_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio1 */
+static struct omap_hwmod_addr_space omap2420_gpio1_addr_space[] = {
+	{
+		.pa_start	= 0x48018000,
+		.pa_end		= 0x480181ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio1 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_gpio1_hwmod,
+	.clk		= "gpios_ick",
+	.addr		= omap2420_gpio1_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio2 */
+static struct omap_hwmod_addr_space omap2420_gpio2_addr_space[] = {
+	{
+		.pa_start	= 0x4801a000,
+		.pa_end		= 0x4801a1ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio2 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_gpio2_hwmod,
+	.clk		= "gpios_ick",
+	.addr		= omap2420_gpio2_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio3 */
+static struct omap_hwmod_addr_space omap2420_gpio3_addr_space[] = {
+	{
+		.pa_start	= 0x4801c000,
+		.pa_end		= 0x4801c1ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio3 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_gpio3_hwmod,
+	.clk		= "gpios_ick",
+	.addr		= omap2420_gpio3_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio4 */
+static struct omap_hwmod_addr_space omap2420_gpio4_addr_space[] = {
+	{
+		.pa_start	= 0x4801e000,
+		.pa_end		= 0x4801e1ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio4 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_gpio4_hwmod,
+	.clk		= "gpios_ick",
+	.addr		= omap2420_gpio4_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dma_system -> L3 */
+static struct omap_hwmod_ocp_if omap2420_dma_system__l3 = {
+	.master		= &omap2420_dma_system_hwmod,
+	.slave		= &omap2xxx_l3_main_hwmod,
+	.clk		= "core_l3_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dma_system */
+static struct omap_hwmod_ocp_if omap2420_l4_core__dma_system = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2420_dma_system_hwmod,
+	.clk		= "sdma_ick",
+	.addr		= omap2_dma_system_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> mailbox */
+static struct omap_hwmod_ocp_if omap2420_l4_core__mailbox = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2420_mailbox_hwmod,
+	.addr		= omap2_mailbox_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> mcbsp1 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp1 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2420_mcbsp1_hwmod,
+	.clk		= "mcbsp1_ick",
+	.addr		= omap2_mcbsp1_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> mcbsp2 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp2 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2420_mcbsp2_hwmod,
+	.clk		= "mcbsp2_ick",
+	.addr		= omap2xxx_mcbsp2_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2420_msdi1_addrs[] = {
+	{
+		.pa_start	= 0x4809c000,
+		.pa_end		= 0x4809c000 + SZ_128 - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+/* l4_core -> msdi1 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__msdi1 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2420_msdi1_hwmod,
+	.clk		= "mmc_ick",
+	.addr		= omap2420_msdi1_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> hdq1w interface */
+static struct omap_hwmod_ocp_if omap2420_l4_core__hdq1w = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2420_hdq1w_hwmod,
+	.clk		= "hdq_ick",
+	.addr		= omap2_hdq1w_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+	.flags		= OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE,
+};
+
+
+/* l4_wkup -> 32ksync_counter */
+static struct omap_hwmod_addr_space omap2420_counter_32k_addrs[] = {
+	{
+		.pa_start	= 0x48004000,
+		.pa_end		= 0x4800401f,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__counter_32k = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_counter_32k_hwmod,
+	.clk		= "sync_32k_ick",
+	.addr		= omap2420_counter_32k_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = {
+	&omap2xxx_l3_main__l4_core,
+	&omap2xxx_mpu__l3_main,
+	&omap2xxx_dss__l3,
+	&omap2xxx_l4_core__mcspi1,
+	&omap2xxx_l4_core__mcspi2,
+	&omap2xxx_l4_core__l4_wkup,
+	&omap2_l4_core__uart1,
+	&omap2_l4_core__uart2,
+	&omap2_l4_core__uart3,
+	&omap2420_l4_core__i2c1,
+	&omap2420_l4_core__i2c2,
+	&omap2420_l3__iva,
+	&omap2420_l3__dsp,
+	&omap2420_l4_wkup__timer1,
+	&omap2xxx_l4_core__timer2,
+	&omap2xxx_l4_core__timer3,
+	&omap2xxx_l4_core__timer4,
+	&omap2xxx_l4_core__timer5,
+	&omap2xxx_l4_core__timer6,
+	&omap2xxx_l4_core__timer7,
+	&omap2xxx_l4_core__timer8,
+	&omap2xxx_l4_core__timer9,
+	&omap2xxx_l4_core__timer10,
+	&omap2xxx_l4_core__timer11,
+	&omap2xxx_l4_core__timer12,
+	&omap2420_l4_wkup__wd_timer2,
+	&omap2xxx_l4_core__dss,
+	&omap2xxx_l4_core__dss_dispc,
+	&omap2xxx_l4_core__dss_rfbi,
+	&omap2xxx_l4_core__dss_venc,
+	&omap2420_l4_wkup__gpio1,
+	&omap2420_l4_wkup__gpio2,
+	&omap2420_l4_wkup__gpio3,
+	&omap2420_l4_wkup__gpio4,
+	&omap2420_dma_system__l3,
+	&omap2420_l4_core__dma_system,
+	&omap2420_l4_core__mailbox,
+	&omap2420_l4_core__mcbsp1,
+	&omap2420_l4_core__mcbsp2,
+	&omap2420_l4_core__msdi1,
+	&omap2420_l4_core__hdq1w,
+	&omap2420_l4_wkup__counter_32k,
 	NULL,
 };
 
 int __init omap2420_hwmod_init(void)
 {
-	return omap_hwmod_register(omap2420_hwmods);
+	return omap_hwmod_register_links(omap2420_hwmod_ocp_ifs);
 }
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 04a3885..4d72649 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -2,6 +2,7 @@
  * omap_hwmod_2430_data.c - hardware modules present on the OMAP2430 chips
  *
  * Copyright (C) 2009-2011 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
  * Paul Walmsley
  *
  * This program is free software; you can redistribute it and/or modify
@@ -33,1044 +34,29 @@
 /*
  * OMAP2430 hardware module integration data
  *
- * ALl of the data in this section should be autogeneratable from the
+ * All of the data in this section should be autogeneratable from the
  * TI hardware database or other technical documentation.  Data that
  * is driver-specific or driver-kernel integration-specific belongs
  * elsewhere.
  */
 
-static struct omap_hwmod omap2430_mpu_hwmod;
-static struct omap_hwmod omap2430_iva_hwmod;
-static struct omap_hwmod omap2430_l3_main_hwmod;
-static struct omap_hwmod omap2430_l4_core_hwmod;
-static struct omap_hwmod omap2430_dss_core_hwmod;
-static struct omap_hwmod omap2430_dss_dispc_hwmod;
-static struct omap_hwmod omap2430_dss_rfbi_hwmod;
-static struct omap_hwmod omap2430_dss_venc_hwmod;
-static struct omap_hwmod omap2430_wd_timer2_hwmod;
-static struct omap_hwmod omap2430_gpio1_hwmod;
-static struct omap_hwmod omap2430_gpio2_hwmod;
-static struct omap_hwmod omap2430_gpio3_hwmod;
-static struct omap_hwmod omap2430_gpio4_hwmod;
-static struct omap_hwmod omap2430_gpio5_hwmod;
-static struct omap_hwmod omap2430_dma_system_hwmod;
-static struct omap_hwmod omap2430_mcbsp1_hwmod;
-static struct omap_hwmod omap2430_mcbsp2_hwmod;
-static struct omap_hwmod omap2430_mcbsp3_hwmod;
-static struct omap_hwmod omap2430_mcbsp4_hwmod;
-static struct omap_hwmod omap2430_mcbsp5_hwmod;
-static struct omap_hwmod omap2430_mcspi1_hwmod;
-static struct omap_hwmod omap2430_mcspi2_hwmod;
-static struct omap_hwmod omap2430_mcspi3_hwmod;
-static struct omap_hwmod omap2430_mmc1_hwmod;
-static struct omap_hwmod omap2430_mmc2_hwmod;
-
-/* L3 -> L4_CORE interface */
-static struct omap_hwmod_ocp_if omap2430_l3_main__l4_core = {
-	.master	= &omap2430_l3_main_hwmod,
-	.slave	= &omap2430_l4_core_hwmod,
-	.user	= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* MPU -> L3 interface */
-static struct omap_hwmod_ocp_if omap2430_mpu__l3_main = {
-	.master = &omap2430_mpu_hwmod,
-	.slave	= &omap2430_l3_main_hwmod,
-	.user	= OCP_USER_MPU,
-};
-
-/* Slave interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l3_main_slaves[] = {
-	&omap2430_mpu__l3_main,
-};
-
-/* DSS -> l3 */
-static struct omap_hwmod_ocp_if omap2430_dss__l3 = {
-	.master		= &omap2430_dss_core_hwmod,
-	.slave		= &omap2430_l3_main_hwmod,
-	.fw = {
-		.omap2 = {
-			.l3_perm_bit  = OMAP2_L3_CORE_FW_CONNID_DSS,
-			.flags	= OMAP_FIREWALL_L3,
-		}
-	},
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* Master interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l3_main_masters[] = {
-	&omap2430_l3_main__l4_core,
-};
-
-/* L3 */
-static struct omap_hwmod omap2430_l3_main_hwmod = {
-	.name		= "l3_main",
-	.class		= &l3_hwmod_class,
-	.masters	= omap2430_l3_main_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2430_l3_main_masters),
-	.slaves		= omap2430_l3_main_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_l3_main_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-static struct omap_hwmod omap2430_l4_wkup_hwmod;
-static struct omap_hwmod omap2430_uart1_hwmod;
-static struct omap_hwmod omap2430_uart2_hwmod;
-static struct omap_hwmod omap2430_uart3_hwmod;
-static struct omap_hwmod omap2430_i2c1_hwmod;
-static struct omap_hwmod omap2430_i2c2_hwmod;
-
-static struct omap_hwmod omap2430_usbhsotg_hwmod;
-
-/* l3_core -> usbhsotg  interface */
-static struct omap_hwmod_ocp_if omap2430_usbhsotg__l3 = {
-	.master		= &omap2430_usbhsotg_hwmod,
-	.slave		= &omap2430_l3_main_hwmod,
-	.clk		= "core_l3_ck",
-	.user		= OCP_USER_MPU,
-};
-
-/* L4 CORE -> I2C1 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__i2c1 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_i2c1_hwmod,
-	.clk		= "i2c1_ick",
-	.addr		= omap2_i2c1_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> I2C2 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__i2c2 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_i2c2_hwmod,
-	.clk		= "i2c2_ick",
-	.addr		= omap2_i2c2_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4_CORE -> L4_WKUP interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = {
-	.master	= &omap2430_l4_core_hwmod,
-	.slave	= &omap2430_l4_wkup_hwmod,
-	.user	= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> UART1 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_uart1_hwmod,
-	.clk		= "uart1_ick",
-	.addr		= omap2xxx_uart1_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> UART2 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_uart2_hwmod,
-	.clk		= "uart2_ick",
-	.addr		= omap2xxx_uart2_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 PER -> UART3 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_uart3_hwmod,
-	.clk		= "uart3_ick",
-	.addr		= omap2xxx_uart3_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /*
-* usbhsotg interface data
-*/
-static struct omap_hwmod_addr_space omap2430_usbhsotg_addrs[] = {
-	{
-		.pa_start	= OMAP243X_HS_BASE,
-		.pa_end		= OMAP243X_HS_BASE + SZ_4K - 1,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-/*  l4_core ->usbhsotg  interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__usbhsotg = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_usbhsotg_hwmod,
-	.clk		= "usb_l4_ick",
-	.addr		= omap2430_usbhsotg_addrs,
-	.user		= OCP_USER_MPU,
-};
-
-static struct omap_hwmod_ocp_if *omap2430_usbhsotg_masters[] = {
-	&omap2430_usbhsotg__l3,
-};
-
-static struct omap_hwmod_ocp_if *omap2430_usbhsotg_slaves[] = {
-	&omap2430_l4_core__usbhsotg,
-};
-
-/* L4 CORE -> MMC1 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mmc1 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mmc1_hwmod,
-	.clk		= "mmchs1_ick",
-	.addr		= omap2430_mmc1_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> MMC2 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mmc2 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mmc2_hwmod,
-	.clk		= "mmchs2_ick",
-	.addr		= omap2430_mmc2_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* Slave interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l4_core_slaves[] = {
-	&omap2430_l3_main__l4_core,
-};
-
-/* Master interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l4_core_masters[] = {
-	&omap2430_l4_core__l4_wkup,
-	&omap2430_l4_core__mmc1,
-	&omap2430_l4_core__mmc2,
-};
-
-/* L4 CORE */
-static struct omap_hwmod omap2430_l4_core_hwmod = {
-	.name		= "l4_core",
-	.class		= &l4_hwmod_class,
-	.masters	= omap2430_l4_core_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2430_l4_core_masters),
-	.slaves		= omap2430_l4_core_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_l4_core_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* Slave interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l4_wkup_slaves[] = {
-	&omap2430_l4_core__l4_wkup,
-	&omap2_l4_core__uart1,
-	&omap2_l4_core__uart2,
-	&omap2_l4_core__uart3,
-};
-
-/* Master interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l4_wkup_masters[] = {
-};
-
-/* l4 core -> mcspi1 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi1 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mcspi1_hwmod,
-	.clk		= "mcspi1_ick",
-	.addr		= omap2_mcspi1_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 core -> mcspi2 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi2 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mcspi2_hwmod,
-	.clk		= "mcspi2_ick",
-	.addr		= omap2_mcspi2_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 core -> mcspi3 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi3 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mcspi3_hwmod,
-	.clk		= "mcspi3_ick",
-	.addr		= omap2430_mcspi3_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 WKUP */
-static struct omap_hwmod omap2430_l4_wkup_hwmod = {
-	.name		= "l4_wkup",
-	.class		= &l4_hwmod_class,
-	.masters	= omap2430_l4_wkup_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2430_l4_wkup_masters),
-	.slaves		= omap2430_l4_wkup_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_l4_wkup_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* Master interfaces on the MPU device */
-static struct omap_hwmod_ocp_if *omap2430_mpu_masters[] = {
-	&omap2430_mpu__l3_main,
-};
-
-/* MPU */
-static struct omap_hwmod omap2430_mpu_hwmod = {
-	.name		= "mpu",
-	.class		= &mpu_hwmod_class,
-	.main_clk	= "mpu_ck",
-	.masters	= omap2430_mpu_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2430_mpu_masters),
-};
-
-/*
- * IVA2_1 interface data
+ * IP blocks
  */
 
-/* IVA2 <- L3 interface */
-static struct omap_hwmod_ocp_if omap2430_l3__iva = {
-	.master		= &omap2430_l3_main_hwmod,
-	.slave		= &omap2430_iva_hwmod,
-	.clk		= "dsp_fck",
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+/* IVA2 (IVA2) */
+static struct omap_hwmod_rst_info omap2430_iva_resets[] = {
+	{ .name = "logic", .rst_shift = 0 },
+	{ .name = "mmu", .rst_shift = 1 },
 };
 
-static struct omap_hwmod_ocp_if *omap2430_iva_masters[] = {
-	&omap2430_l3__iva,
-};
-
-/*
- * IVA2 (IVA2)
- */
-
 static struct omap_hwmod omap2430_iva_hwmod = {
 	.name		= "iva",
 	.class		= &iva_hwmod_class,
-	.masters	= omap2430_iva_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2430_iva_masters),
-};
-
-/* always-on timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
-	.timer_capability       = OMAP_TIMER_ALWON,
-};
-
-/* pwm timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
-	.timer_capability       = OMAP_TIMER_HAS_PWM,
-};
-
-/* timer1 */
-static struct omap_hwmod omap2430_timer1_hwmod;
-
-static struct omap_hwmod_addr_space omap2430_timer1_addrs[] = {
-	{
-		.pa_start	= 0x49018000,
-		.pa_end		= 0x49018000 + SZ_1K - 1,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-/* l4_wkup -> timer1 */
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__timer1 = {
-	.master		= &omap2430_l4_wkup_hwmod,
-	.slave		= &omap2430_timer1_hwmod,
-	.clk		= "gpt1_ick",
-	.addr		= omap2430_timer1_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer1 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer1_slaves[] = {
-	&omap2430_l4_wkup__timer1,
-};
-
-/* timer1 hwmod */
-static struct omap_hwmod omap2430_timer1_hwmod = {
-	.name		= "timer1",
-	.mpu_irqs	= omap2_timer1_mpu_irqs,
-	.main_clk	= "gpt1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT1_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2430_timer1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer1_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer2 */
-static struct omap_hwmod omap2430_timer2_hwmod;
-
-/* l4_core -> timer2 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer2 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer2_hwmod,
-	.clk		= "gpt2_ick",
-	.addr		= omap2xxx_timer2_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer2 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer2_slaves[] = {
-	&omap2430_l4_core__timer2,
-};
-
-/* timer2 hwmod */
-static struct omap_hwmod omap2430_timer2_hwmod = {
-	.name		= "timer2",
-	.mpu_irqs	= omap2_timer2_mpu_irqs,
-	.main_clk	= "gpt2_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT2_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2430_timer2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer2_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer3 */
-static struct omap_hwmod omap2430_timer3_hwmod;
-
-/* l4_core -> timer3 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer3 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer3_hwmod,
-	.clk		= "gpt3_ick",
-	.addr		= omap2xxx_timer3_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer3 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer3_slaves[] = {
-	&omap2430_l4_core__timer3,
-};
-
-/* timer3 hwmod */
-static struct omap_hwmod omap2430_timer3_hwmod = {
-	.name		= "timer3",
-	.mpu_irqs	= omap2_timer3_mpu_irqs,
-	.main_clk	= "gpt3_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT3_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2430_timer3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer3_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer4 */
-static struct omap_hwmod omap2430_timer4_hwmod;
-
-/* l4_core -> timer4 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer4 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer4_hwmod,
-	.clk		= "gpt4_ick",
-	.addr		= omap2xxx_timer4_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer4 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer4_slaves[] = {
-	&omap2430_l4_core__timer4,
-};
-
-/* timer4 hwmod */
-static struct omap_hwmod omap2430_timer4_hwmod = {
-	.name		= "timer4",
-	.mpu_irqs	= omap2_timer4_mpu_irqs,
-	.main_clk	= "gpt4_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT4_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2430_timer4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer4_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer5 */
-static struct omap_hwmod omap2430_timer5_hwmod;
-
-/* l4_core -> timer5 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer5 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer5_hwmod,
-	.clk		= "gpt5_ick",
-	.addr		= omap2xxx_timer5_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer5 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer5_slaves[] = {
-	&omap2430_l4_core__timer5,
-};
-
-/* timer5 hwmod */
-static struct omap_hwmod omap2430_timer5_hwmod = {
-	.name		= "timer5",
-	.mpu_irqs	= omap2_timer5_mpu_irqs,
-	.main_clk	= "gpt5_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT5_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2430_timer5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer5_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer6 */
-static struct omap_hwmod omap2430_timer6_hwmod;
-
-/* l4_core -> timer6 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer6 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer6_hwmod,
-	.clk		= "gpt6_ick",
-	.addr		= omap2xxx_timer6_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer6 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer6_slaves[] = {
-	&omap2430_l4_core__timer6,
-};
-
-/* timer6 hwmod */
-static struct omap_hwmod omap2430_timer6_hwmod = {
-	.name		= "timer6",
-	.mpu_irqs	= omap2_timer6_mpu_irqs,
-	.main_clk	= "gpt6_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT6_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2430_timer6_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer6_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer7 */
-static struct omap_hwmod omap2430_timer7_hwmod;
-
-/* l4_core -> timer7 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer7 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer7_hwmod,
-	.clk		= "gpt7_ick",
-	.addr		= omap2xxx_timer7_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer7 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer7_slaves[] = {
-	&omap2430_l4_core__timer7,
-};
-
-/* timer7 hwmod */
-static struct omap_hwmod omap2430_timer7_hwmod = {
-	.name		= "timer7",
-	.mpu_irqs	= omap2_timer7_mpu_irqs,
-	.main_clk	= "gpt7_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT7_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2430_timer7_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer7_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer8 */
-static struct omap_hwmod omap2430_timer8_hwmod;
-
-/* l4_core -> timer8 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer8 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer8_hwmod,
-	.clk		= "gpt8_ick",
-	.addr		= omap2xxx_timer8_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer8 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer8_slaves[] = {
-	&omap2430_l4_core__timer8,
-};
-
-/* timer8 hwmod */
-static struct omap_hwmod omap2430_timer8_hwmod = {
-	.name		= "timer8",
-	.mpu_irqs	= omap2_timer8_mpu_irqs,
-	.main_clk	= "gpt8_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT8_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap2430_timer8_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer8_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer9 */
-static struct omap_hwmod omap2430_timer9_hwmod;
-
-/* l4_core -> timer9 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer9 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer9_hwmod,
-	.clk		= "gpt9_ick",
-	.addr		= omap2xxx_timer9_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer9 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer9_slaves[] = {
-	&omap2430_l4_core__timer9,
-};
-
-/* timer9 hwmod */
-static struct omap_hwmod omap2430_timer9_hwmod = {
-	.name		= "timer9",
-	.mpu_irqs	= omap2_timer9_mpu_irqs,
-	.main_clk	= "gpt9_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT9_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap2430_timer9_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer9_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer10 */
-static struct omap_hwmod omap2430_timer10_hwmod;
-
-/* l4_core -> timer10 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer10 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer10_hwmod,
-	.clk		= "gpt10_ick",
-	.addr		= omap2_timer10_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer10 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer10_slaves[] = {
-	&omap2430_l4_core__timer10,
-};
-
-/* timer10 hwmod */
-static struct omap_hwmod omap2430_timer10_hwmod = {
-	.name		= "timer10",
-	.mpu_irqs	= omap2_timer10_mpu_irqs,
-	.main_clk	= "gpt10_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT10_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap2430_timer10_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer10_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer11 */
-static struct omap_hwmod omap2430_timer11_hwmod;
-
-/* l4_core -> timer11 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer11 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer11_hwmod,
-	.clk		= "gpt11_ick",
-	.addr		= omap2_timer11_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer11 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer11_slaves[] = {
-	&omap2430_l4_core__timer11,
-};
-
-/* timer11 hwmod */
-static struct omap_hwmod omap2430_timer11_hwmod = {
-	.name		= "timer11",
-	.mpu_irqs	= omap2_timer11_mpu_irqs,
-	.main_clk	= "gpt11_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT11_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap2430_timer11_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer11_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* timer12 */
-static struct omap_hwmod omap2430_timer12_hwmod;
-
-/* l4_core -> timer12 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer12 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_timer12_hwmod,
-	.clk		= "gpt12_ick",
-	.addr		= omap2xxx_timer12_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer12 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer12_slaves[] = {
-	&omap2430_l4_core__timer12,
-};
-
-/* timer12 hwmod */
-static struct omap_hwmod omap2430_timer12_hwmod = {
-	.name		= "timer12",
-	.mpu_irqs	= omap2xxx_timer12_mpu_irqs,
-	.main_clk	= "gpt12_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPT12_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap2430_timer12_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_timer12_slaves),
-	.class		= &omap2xxx_timer_hwmod_class,
-};
-
-/* l4_wkup -> wd_timer2 */
-static struct omap_hwmod_addr_space omap2430_wd_timer2_addrs[] = {
-	{
-		.pa_start	= 0x49016000,
-		.pa_end		= 0x4901607f,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__wd_timer2 = {
-	.master		= &omap2430_l4_wkup_hwmod,
-	.slave		= &omap2430_wd_timer2_hwmod,
-	.clk		= "mpu_wdt_ick",
-	.addr		= omap2430_wd_timer2_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* wd_timer2 */
-static struct omap_hwmod_ocp_if *omap2430_wd_timer2_slaves[] = {
-	&omap2430_l4_wkup__wd_timer2,
-};
-
-static struct omap_hwmod omap2430_wd_timer2_hwmod = {
-	.name		= "wd_timer2",
-	.class		= &omap2xxx_wd_timer_hwmod_class,
-	.main_clk	= "mpu_wdt_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
-		},
-	},
-	.slaves		= omap2430_wd_timer2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_wd_timer2_slaves),
-};
-
-/* UART1 */
-
-static struct omap_hwmod_ocp_if *omap2430_uart1_slaves[] = {
-	&omap2_l4_core__uart1,
-};
-
-static struct omap_hwmod omap2430_uart1_hwmod = {
-	.name		= "uart1",
-	.mpu_irqs	= omap2_uart1_mpu_irqs,
-	.sdma_reqs	= omap2_uart1_sdma_reqs,
-	.main_clk	= "uart1_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_UART1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
-		},
-	},
-	.slaves		= omap2430_uart1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_uart1_slaves),
-	.class		= &omap2_uart_class,
-};
-
-/* UART2 */
-
-static struct omap_hwmod_ocp_if *omap2430_uart2_slaves[] = {
-	&omap2_l4_core__uart2,
-};
-
-static struct omap_hwmod omap2430_uart2_hwmod = {
-	.name		= "uart2",
-	.mpu_irqs	= omap2_uart2_mpu_irqs,
-	.sdma_reqs	= omap2_uart2_sdma_reqs,
-	.main_clk	= "uart2_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_UART2_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
-		},
-	},
-	.slaves		= omap2430_uart2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_uart2_slaves),
-	.class		= &omap2_uart_class,
-};
-
-/* UART3 */
-
-static struct omap_hwmod_ocp_if *omap2430_uart3_slaves[] = {
-	&omap2_l4_core__uart3,
-};
-
-static struct omap_hwmod omap2430_uart3_hwmod = {
-	.name		= "uart3",
-	.mpu_irqs	= omap2_uart3_mpu_irqs,
-	.sdma_reqs	= omap2_uart3_sdma_reqs,
-	.main_clk	= "uart3_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 2,
-			.module_bit = OMAP24XX_EN_UART3_SHIFT,
-			.idlest_reg_id = 2,
-			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
-		},
-	},
-	.slaves		= omap2430_uart3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_uart3_slaves),
-	.class		= &omap2_uart_class,
-};
-
-/* dss */
-/* dss master ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_masters[] = {
-	&omap2430_dss__l3,
-};
-
-/* l4_core -> dss */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dss = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_dss_core_hwmod,
-	.clk		= "dss_ick",
-	.addr		= omap2_dss_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_slaves[] = {
-	&omap2430_l4_core__dss,
-};
-
-static struct omap_hwmod_opt_clk dss_opt_clks[] = {
-	/*
-	 * The DSS HW needs all DSS clocks enabled during reset. The dss_core
-	 * driver does not use these clocks.
-	 */
-	{ .role = "tv_clk", .clk = "dss_54m_fck" },
-	{ .role = "sys_clk", .clk = "dss2_fck" },
-};
-
-static struct omap_hwmod omap2430_dss_core_hwmod = {
-	.name		= "dss_core",
-	.class		= &omap2_dss_hwmod_class,
-	.main_clk	= "dss1_fck", /* instead of dss_fck */
-	.sdma_reqs	= omap2xxx_dss_sdma_chs,
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
-		},
-	},
-	.opt_clks	= dss_opt_clks,
-	.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
-	.slaves		= omap2430_dss_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_dss_slaves),
-	.masters	= omap2430_dss_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2430_dss_masters),
-	.flags		= HWMOD_NO_IDLEST | HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-};
-
-/* l4_core -> dss_dispc */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dss_dispc = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_dss_dispc_hwmod,
-	.clk		= "dss_ick",
-	.addr		= omap2_dss_dispc_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_dispc slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_dispc_slaves[] = {
-	&omap2430_l4_core__dss_dispc,
-};
-
-static struct omap_hwmod omap2430_dss_dispc_hwmod = {
-	.name		= "dss_dispc",
-	.class		= &omap2_dispc_hwmod_class,
-	.mpu_irqs	= omap2_dispc_irqs,
-	.main_clk	= "dss1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
-		},
-	},
-	.slaves		= omap2430_dss_dispc_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_dss_dispc_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-	.dev_attr	= &omap2_3_dss_dispc_dev_attr
-};
-
-/* l4_core -> dss_rfbi */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dss_rfbi = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_dss_rfbi_hwmod,
-	.clk		= "dss_ick",
-	.addr		= omap2_dss_rfbi_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_rfbi slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_rfbi_slaves[] = {
-	&omap2430_l4_core__dss_rfbi,
-};
-
-static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
-	{ .role = "ick", .clk = "dss_ick" },
-};
-
-static struct omap_hwmod omap2430_dss_rfbi_hwmod = {
-	.name		= "dss_rfbi",
-	.class		= &omap2_rfbi_hwmod_class,
-	.main_clk	= "dss1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
-			.module_offs = CORE_MOD,
-		},
-	},
-	.opt_clks	= dss_rfbi_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_rfbi_opt_clks),
-	.slaves		= omap2430_dss_rfbi_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_dss_rfbi_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* l4_core -> dss_venc */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dss_venc = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_dss_venc_hwmod,
-	.clk		= "dss_ick",
-	.addr		= omap2_dss_venc_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_venc slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_venc_slaves[] = {
-	&omap2430_l4_core__dss_venc,
-};
-
-static struct omap_hwmod omap2430_dss_venc_hwmod = {
-	.name		= "dss_venc",
-	.class		= &omap2_venc_hwmod_class,
-	.main_clk	= "dss_54m_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
-			.module_offs = CORE_MOD,
-		},
-	},
-	.slaves		= omap2430_dss_venc_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_dss_venc_slaves),
-	.flags		= HWMOD_NO_IDLEST,
+	.clkdm_name	= "dsp_clkdm",
+	.rst_lines	= omap2430_iva_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap2430_iva_resets),
+	.main_clk	= "dsp_fck",
 };
 
 /* I2C common */
@@ -1098,11 +84,6 @@
 };
 
 /* I2C1 */
-
-static struct omap_hwmod_ocp_if *omap2430_i2c1_slaves[] = {
-	&omap2430_l4_core__i2c1,
-};
-
 static struct omap_hwmod omap2430_i2c1_hwmod = {
 	.name		= "i2c1",
 	.flags		= HWMOD_16BIT_REG,
@@ -1126,18 +107,11 @@
 			.idlest_idle_bit = OMAP2430_ST_I2CHS1_SHIFT,
 		},
 	},
-	.slaves		= omap2430_i2c1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_i2c1_slaves),
 	.class		= &i2c_class,
 	.dev_attr	= &i2c_dev_attr,
 };
 
 /* I2C2 */
-
-static struct omap_hwmod_ocp_if *omap2430_i2c2_slaves[] = {
-	&omap2430_l4_core__i2c2,
-};
-
 static struct omap_hwmod omap2430_i2c2_hwmod = {
 	.name		= "i2c2",
 	.flags		= HWMOD_16BIT_REG,
@@ -1153,218 +127,16 @@
 			.idlest_idle_bit = OMAP2430_ST_I2CHS2_SHIFT,
 		},
 	},
-	.slaves		= omap2430_i2c2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_i2c2_slaves),
 	.class		= &i2c_class,
 	.dev_attr	= &i2c_dev_attr,
 };
 
-/* l4_wkup -> gpio1 */
-static struct omap_hwmod_addr_space omap2430_gpio1_addr_space[] = {
-	{
-		.pa_start	= 0x4900C000,
-		.pa_end		= 0x4900C1ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio1 = {
-	.master		= &omap2430_l4_wkup_hwmod,
-	.slave		= &omap2430_gpio1_hwmod,
-	.clk		= "gpios_ick",
-	.addr		= omap2430_gpio1_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> gpio2 */
-static struct omap_hwmod_addr_space omap2430_gpio2_addr_space[] = {
-	{
-		.pa_start	= 0x4900E000,
-		.pa_end		= 0x4900E1ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio2 = {
-	.master		= &omap2430_l4_wkup_hwmod,
-	.slave		= &omap2430_gpio2_hwmod,
-	.clk		= "gpios_ick",
-	.addr		= omap2430_gpio2_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> gpio3 */
-static struct omap_hwmod_addr_space omap2430_gpio3_addr_space[] = {
-	{
-		.pa_start	= 0x49010000,
-		.pa_end		= 0x490101ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio3 = {
-	.master		= &omap2430_l4_wkup_hwmod,
-	.slave		= &omap2430_gpio3_hwmod,
-	.clk		= "gpios_ick",
-	.addr		= omap2430_gpio3_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> gpio4 */
-static struct omap_hwmod_addr_space omap2430_gpio4_addr_space[] = {
-	{
-		.pa_start	= 0x49012000,
-		.pa_end		= 0x490121ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio4 = {
-	.master		= &omap2430_l4_wkup_hwmod,
-	.slave		= &omap2430_gpio4_hwmod,
-	.clk		= "gpios_ick",
-	.addr		= omap2430_gpio4_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_core -> gpio5 */
-static struct omap_hwmod_addr_space omap2430_gpio5_addr_space[] = {
-	{
-		.pa_start	= 0x480B6000,
-		.pa_end		= 0x480B61ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_core__gpio5 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_gpio5_hwmod,
-	.clk		= "gpio5_ick",
-	.addr		= omap2430_gpio5_addr_space,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* gpio dev_attr */
-static struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width = 32,
-	.dbck_flag = false,
-};
-
-/* gpio1 */
-static struct omap_hwmod_ocp_if *omap2430_gpio1_slaves[] = {
-	&omap2430_l4_wkup__gpio1,
-};
-
-static struct omap_hwmod omap2430_gpio1_hwmod = {
-	.name		= "gpio1",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio1_irqs,
-	.main_clk	= "gpios_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_EN_GPIOS_SHIFT,
-		},
-	},
-	.slaves		= omap2430_gpio1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_gpio1_slaves),
-	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio2 */
-static struct omap_hwmod_ocp_if *omap2430_gpio2_slaves[] = {
-	&omap2430_l4_wkup__gpio2,
-};
-
-static struct omap_hwmod omap2430_gpio2_hwmod = {
-	.name		= "gpio2",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio2_irqs,
-	.main_clk	= "gpios_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
-		},
-	},
-	.slaves		= omap2430_gpio2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_gpio2_slaves),
-	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio3 */
-static struct omap_hwmod_ocp_if *omap2430_gpio3_slaves[] = {
-	&omap2430_l4_wkup__gpio3,
-};
-
-static struct omap_hwmod omap2430_gpio3_hwmod = {
-	.name		= "gpio3",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio3_irqs,
-	.main_clk	= "gpios_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
-		},
-	},
-	.slaves		= omap2430_gpio3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_gpio3_slaves),
-	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio4 */
-static struct omap_hwmod_ocp_if *omap2430_gpio4_slaves[] = {
-	&omap2430_l4_wkup__gpio4,
-};
-
-static struct omap_hwmod omap2430_gpio4_hwmod = {
-	.name		= "gpio4",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio4_irqs,
-	.main_clk	= "gpios_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
-		},
-	},
-	.slaves		= omap2430_gpio4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_gpio4_slaves),
-	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
 /* gpio5 */
 static struct omap_hwmod_irq_info omap243x_gpio5_irqs[] = {
 	{ .irq = 33 }, /* INT_24XX_GPIO_BANK5 */
 	{ .irq = -1 }
 };
 
-static struct omap_hwmod_ocp_if *omap2430_gpio5_slaves[] = {
-	&omap2430_l4_core__gpio5,
-};
-
 static struct omap_hwmod omap2430_gpio5_hwmod = {
 	.name		= "gpio5",
 	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -1379,10 +151,8 @@
 			.idlest_idle_bit = OMAP2430_ST_GPIO5_SHIFT,
 		},
 	},
-	.slaves		= omap2430_gpio5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_gpio5_slaves),
 	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
+	.dev_attr	= &omap2xxx_gpio_dev_attr,
 };
 
 /* dma attributes */
@@ -1392,66 +162,21 @@
 	.lch_count = 32,
 };
 
-/* dma_system -> L3 */
-static struct omap_hwmod_ocp_if omap2430_dma_system__l3 = {
-	.master		= &omap2430_dma_system_hwmod,
-	.slave		= &omap2430_l3_main_hwmod,
-	.clk		= "core_l3_ck",
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dma_system master ports */
-static struct omap_hwmod_ocp_if *omap2430_dma_system_masters[] = {
-	&omap2430_dma_system__l3,
-};
-
-/* l4_core -> dma_system */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dma_system = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_dma_system_hwmod,
-	.clk		= "sdma_ick",
-	.addr		= omap2_dma_system_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dma_system slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dma_system_slaves[] = {
-	&omap2430_l4_core__dma_system,
-};
-
 static struct omap_hwmod omap2430_dma_system_hwmod = {
 	.name		= "dma",
 	.class		= &omap2xxx_dma_hwmod_class,
 	.mpu_irqs	= omap2_dma_system_irqs,
 	.main_clk	= "core_l3_ck",
-	.slaves		= omap2430_dma_system_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_dma_system_slaves),
-	.masters	= omap2430_dma_system_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2430_dma_system_masters),
 	.dev_attr	= &dma_dev_attr,
 	.flags		= HWMOD_NO_IDLEST,
 };
 
 /* mailbox */
-static struct omap_hwmod omap2430_mailbox_hwmod;
 static struct omap_hwmod_irq_info omap2430_mailbox_irqs[] = {
 	{ .irq = 26 },
 	{ .irq = -1 }
 };
 
-/* l4_core -> mailbox */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mailbox = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mailbox_hwmod,
-	.addr		= omap2_mailbox_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mailbox slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mailbox_slaves[] = {
-	&omap2430_l4_core__mailbox,
-};
-
 static struct omap_hwmod omap2430_mailbox_hwmod = {
 	.name		= "mailbox",
 	.class		= &omap2xxx_mailbox_hwmod_class,
@@ -1466,66 +191,6 @@
 			.idlest_idle_bit = OMAP24XX_ST_MAILBOXES_SHIFT,
 		},
 	},
-	.slaves		= omap2430_mailbox_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mailbox_slaves),
-};
-
-/* mcspi1 */
-static struct omap_hwmod_ocp_if *omap2430_mcspi1_slaves[] = {
-	&omap2430_l4_core__mcspi1,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
-	.num_chipselect = 4,
-};
-
-static struct omap_hwmod omap2430_mcspi1_hwmod = {
-	.name		= "mcspi1_hwmod",
-	.mpu_irqs	= omap2_mcspi1_mpu_irqs,
-	.sdma_reqs	= omap2_mcspi1_sdma_reqs,
-	.main_clk	= "mcspi1_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_MCSPI1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_MCSPI1_SHIFT,
-		},
-	},
-	.slaves		= omap2430_mcspi1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mcspi1_slaves),
-	.class		= &omap2xxx_mcspi_class,
-	.dev_attr	= &omap_mcspi1_dev_attr,
-};
-
-/* mcspi2 */
-static struct omap_hwmod_ocp_if *omap2430_mcspi2_slaves[] = {
-	&omap2430_l4_core__mcspi2,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
-	.num_chipselect = 2,
-};
-
-static struct omap_hwmod omap2430_mcspi2_hwmod = {
-	.name		= "mcspi2_hwmod",
-	.mpu_irqs	= omap2_mcspi2_mpu_irqs,
-	.sdma_reqs	= omap2_mcspi2_sdma_reqs,
-	.main_clk	= "mcspi2_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP24XX_EN_MCSPI2_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP24XX_ST_MCSPI2_SHIFT,
-		},
-	},
-	.slaves		= omap2430_mcspi2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mcspi2_slaves),
-	.class		= &omap2xxx_mcspi_class,
-	.dev_attr	= &omap_mcspi2_dev_attr,
 };
 
 /* mcspi3 */
@@ -1542,16 +207,12 @@
 	{ .dma_req = -1 }
 };
 
-static struct omap_hwmod_ocp_if *omap2430_mcspi3_slaves[] = {
-	&omap2430_l4_core__mcspi3,
-};
-
 static struct omap2_mcspi_dev_attr omap_mcspi3_dev_attr = {
 	.num_chipselect = 2,
 };
 
 static struct omap_hwmod omap2430_mcspi3_hwmod = {
-	.name		= "mcspi3_hwmod",
+	.name		= "mcspi3",
 	.mpu_irqs	= omap2430_mcspi3_mpu_irqs,
 	.sdma_reqs	= omap2430_mcspi3_sdma_reqs,
 	.main_clk	= "mcspi3_fck",
@@ -1564,15 +225,11 @@
 			.idlest_idle_bit = OMAP2430_ST_MCSPI3_SHIFT,
 		},
 	},
-	.slaves		= omap2430_mcspi3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mcspi3_slaves),
 	.class		= &omap2xxx_mcspi_class,
 	.dev_attr	= &omap_mcspi3_dev_attr,
 };
 
-/*
- * usbhsotg
- */
+/* usbhsotg */
 static struct omap_hwmod_class_sysconfig omap2430_usbhsotg_sysc = {
 	.rev_offs	= 0x0400,
 	.sysc_offs	= 0x0404,
@@ -1611,10 +268,6 @@
 			.idlest_idle_bit = OMAP2430_ST_USBHS_SHIFT,
 		},
 	},
-	.masters	= omap2430_usbhsotg_masters,
-	.masters_cnt	= ARRAY_SIZE(omap2430_usbhsotg_masters),
-	.slaves		= omap2430_usbhsotg_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_usbhsotg_slaves),
 	.class		= &usbotg_class,
 	/*
 	 * Erratum ID: i479  idle_req / idle_ack mechanism potentially
@@ -1652,20 +305,6 @@
 	{ .irq = -1 }
 };
 
-/* l4_core -> mcbsp1 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp1 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mcbsp1_hwmod,
-	.clk		= "mcbsp1_ick",
-	.addr		= omap2_mcbsp1_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp1 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp1_slaves[] = {
-	&omap2430_l4_core__mcbsp1,
-};
-
 static struct omap_hwmod omap2430_mcbsp1_hwmod = {
 	.name		= "mcbsp1",
 	.class		= &omap2430_mcbsp_hwmod_class,
@@ -1681,8 +320,6 @@
 			.idlest_idle_bit = OMAP24XX_ST_MCBSP1_SHIFT,
 		},
 	},
-	.slaves		= omap2430_mcbsp1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mcbsp1_slaves),
 };
 
 /* mcbsp2 */
@@ -1693,20 +330,6 @@
 	{ .irq = -1 }
 };
 
-/* l4_core -> mcbsp2 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp2 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mcbsp2_hwmod,
-	.clk		= "mcbsp2_ick",
-	.addr		= omap2xxx_mcbsp2_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp2 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp2_slaves[] = {
-	&omap2430_l4_core__mcbsp2,
-};
-
 static struct omap_hwmod omap2430_mcbsp2_hwmod = {
 	.name		= "mcbsp2",
 	.class		= &omap2430_mcbsp_hwmod_class,
@@ -1722,8 +345,6 @@
 			.idlest_idle_bit = OMAP24XX_ST_MCBSP2_SHIFT,
 		},
 	},
-	.slaves		= omap2430_mcbsp2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mcbsp2_slaves),
 };
 
 /* mcbsp3 */
@@ -1734,30 +355,6 @@
 	{ .irq = -1 }
 };
 
-static struct omap_hwmod_addr_space omap2430_mcbsp3_addrs[] = {
-	{
-		.name		= "mpu",
-		.pa_start	= 0x4808C000,
-		.pa_end		= 0x4808C0ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-/* l4_core -> mcbsp3 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp3 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mcbsp3_hwmod,
-	.clk		= "mcbsp3_ick",
-	.addr		= omap2430_mcbsp3_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp3 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp3_slaves[] = {
-	&omap2430_l4_core__mcbsp3,
-};
-
 static struct omap_hwmod omap2430_mcbsp3_hwmod = {
 	.name		= "mcbsp3",
 	.class		= &omap2430_mcbsp_hwmod_class,
@@ -1773,8 +370,6 @@
 			.idlest_idle_bit = OMAP2430_ST_MCBSP3_SHIFT,
 		},
 	},
-	.slaves		= omap2430_mcbsp3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mcbsp3_slaves),
 };
 
 /* mcbsp4 */
@@ -1791,30 +386,6 @@
 	{ .dma_req = -1 }
 };
 
-static struct omap_hwmod_addr_space omap2430_mcbsp4_addrs[] = {
-	{
-		.name		= "mpu",
-		.pa_start	= 0x4808E000,
-		.pa_end		= 0x4808E0ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-/* l4_core -> mcbsp4 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp4 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mcbsp4_hwmod,
-	.clk		= "mcbsp4_ick",
-	.addr		= omap2430_mcbsp4_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp4 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp4_slaves[] = {
-	&omap2430_l4_core__mcbsp4,
-};
-
 static struct omap_hwmod omap2430_mcbsp4_hwmod = {
 	.name		= "mcbsp4",
 	.class		= &omap2430_mcbsp_hwmod_class,
@@ -1830,8 +401,6 @@
 			.idlest_idle_bit = OMAP2430_ST_MCBSP4_SHIFT,
 		},
 	},
-	.slaves		= omap2430_mcbsp4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mcbsp4_slaves),
 };
 
 /* mcbsp5 */
@@ -1848,30 +417,6 @@
 	{ .dma_req = -1 }
 };
 
-static struct omap_hwmod_addr_space omap2430_mcbsp5_addrs[] = {
-	{
-		.name		= "mpu",
-		.pa_start	= 0x48096000,
-		.pa_end		= 0x480960ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{ }
-};
-
-/* l4_core -> mcbsp5 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp5 = {
-	.master		= &omap2430_l4_core_hwmod,
-	.slave		= &omap2430_mcbsp5_hwmod,
-	.clk		= "mcbsp5_ick",
-	.addr		= omap2430_mcbsp5_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp5 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp5_slaves[] = {
-	&omap2430_l4_core__mcbsp5,
-};
-
 static struct omap_hwmod omap2430_mcbsp5_hwmod = {
 	.name		= "mcbsp5",
 	.class		= &omap2430_mcbsp_hwmod_class,
@@ -1887,12 +432,9 @@
 			.idlest_idle_bit = OMAP2430_ST_MCBSP5_SHIFT,
 		},
 	},
-	.slaves		= omap2430_mcbsp5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mcbsp5_slaves),
 };
 
 /* MMC/SD/SDIO common */
-
 static struct omap_hwmod_class_sysconfig omap2430_mmc_sysc = {
 	.rev_offs	= 0x1fc,
 	.sysc_offs	= 0x10,
@@ -1910,7 +452,6 @@
 };
 
 /* MMC/SD/SDIO1 */
-
 static struct omap_hwmod_irq_info omap2430_mmc1_mpu_irqs[] = {
 	{ .irq = 83 },
 	{ .irq = -1 }
@@ -1926,10 +467,6 @@
 	{ .role = "dbck", .clk = "mmchsdb1_fck" },
 };
 
-static struct omap_hwmod_ocp_if *omap2430_mmc1_slaves[] = {
-	&omap2430_l4_core__mmc1,
-};
-
 static struct omap_mmc_dev_attr mmc1_dev_attr = {
 	.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
 };
@@ -1952,13 +489,10 @@
 		},
 	},
 	.dev_attr	= &mmc1_dev_attr,
-	.slaves		= omap2430_mmc1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mmc1_slaves),
 	.class		= &omap2430_mmc_class,
 };
 
 /* MMC/SD/SDIO2 */
-
 static struct omap_hwmod_irq_info omap2430_mmc2_mpu_irqs[] = {
 	{ .irq = 86 },
 	{ .irq = -1 }
@@ -1974,10 +508,6 @@
 	{ .role = "dbck", .clk = "mmchsdb2_fck" },
 };
 
-static struct omap_hwmod_ocp_if *omap2430_mmc2_slaves[] = {
-	&omap2430_l4_core__mmc2,
-};
-
 static struct omap_hwmod omap2430_mmc2_hwmod = {
 	.name		= "mmc2",
 	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -1995,78 +525,418 @@
 			.idlest_idle_bit = OMAP2430_ST_MMCHS2_SHIFT,
 		},
 	},
-	.slaves		= omap2430_mmc2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap2430_mmc2_slaves),
 	.class		= &omap2430_mmc_class,
 };
 
-static __initdata struct omap_hwmod *omap2430_hwmods[] = {
-	&omap2430_l3_main_hwmod,
-	&omap2430_l4_core_hwmod,
-	&omap2430_l4_wkup_hwmod,
-	&omap2430_mpu_hwmod,
-	&omap2430_iva_hwmod,
+/* HDQ1W/1-wire */
+static struct omap_hwmod omap2430_hdq1w_hwmod = {
+	.name		= "hdq1w",
+	.mpu_irqs	= omap2_hdq1w_mpu_irqs,
+	.main_clk	= "hdq_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_HDQ_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_HDQ_SHIFT,
+		},
+	},
+	.class		= &omap2_hdq1w_class,
+};
 
-	&omap2430_timer1_hwmod,
-	&omap2430_timer2_hwmod,
-	&omap2430_timer3_hwmod,
-	&omap2430_timer4_hwmod,
-	&omap2430_timer5_hwmod,
-	&omap2430_timer6_hwmod,
-	&omap2430_timer7_hwmod,
-	&omap2430_timer8_hwmod,
-	&omap2430_timer9_hwmod,
-	&omap2430_timer10_hwmod,
-	&omap2430_timer11_hwmod,
-	&omap2430_timer12_hwmod,
+/*
+ * interfaces
+ */
 
-	&omap2430_wd_timer2_hwmod,
-	&omap2430_uart1_hwmod,
-	&omap2430_uart2_hwmod,
-	&omap2430_uart3_hwmod,
-	/* dss class */
-	&omap2430_dss_core_hwmod,
-	&omap2430_dss_dispc_hwmod,
-	&omap2430_dss_rfbi_hwmod,
-	&omap2430_dss_venc_hwmod,
-	/* i2c class */
-	&omap2430_i2c1_hwmod,
-	&omap2430_i2c2_hwmod,
-	&omap2430_mmc1_hwmod,
-	&omap2430_mmc2_hwmod,
+/* L3 -> L4_CORE interface */
+/* l3_core -> usbhsotg  interface */
+static struct omap_hwmod_ocp_if omap2430_usbhsotg__l3 = {
+	.master		= &omap2430_usbhsotg_hwmod,
+	.slave		= &omap2xxx_l3_main_hwmod,
+	.clk		= "core_l3_ck",
+	.user		= OCP_USER_MPU,
+};
 
-	/* gpio class */
-	&omap2430_gpio1_hwmod,
-	&omap2430_gpio2_hwmod,
-	&omap2430_gpio3_hwmod,
-	&omap2430_gpio4_hwmod,
-	&omap2430_gpio5_hwmod,
+/* L4 CORE -> I2C1 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__i2c1 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_i2c1_hwmod,
+	.clk		= "i2c1_ick",
+	.addr		= omap2_i2c1_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
 
-	/* dma_system class*/
-	&omap2430_dma_system_hwmod,
+/* L4 CORE -> I2C2 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__i2c2 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_i2c2_hwmod,
+	.clk		= "i2c2_ick",
+	.addr		= omap2_i2c2_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
 
-	/* mcbsp class */
-	&omap2430_mcbsp1_hwmod,
-	&omap2430_mcbsp2_hwmod,
-	&omap2430_mcbsp3_hwmod,
-	&omap2430_mcbsp4_hwmod,
-	&omap2430_mcbsp5_hwmod,
+static struct omap_hwmod_addr_space omap2430_usbhsotg_addrs[] = {
+	{
+		.pa_start	= OMAP243X_HS_BASE,
+		.pa_end		= OMAP243X_HS_BASE + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
 
-	/* mailbox class */
-	&omap2430_mailbox_hwmod,
+/*  l4_core ->usbhsotg  interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__usbhsotg = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_usbhsotg_hwmod,
+	.clk		= "usb_l4_ick",
+	.addr		= omap2430_usbhsotg_addrs,
+	.user		= OCP_USER_MPU,
+};
 
-	/* mcspi class */
-	&omap2430_mcspi1_hwmod,
-	&omap2430_mcspi2_hwmod,
-	&omap2430_mcspi3_hwmod,
+/* L4 CORE -> MMC1 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mmc1 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_mmc1_hwmod,
+	.clk		= "mmchs1_ick",
+	.addr		= omap2430_mmc1_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
 
-	/* usbotg class*/
-	&omap2430_usbhsotg_hwmod,
+/* L4 CORE -> MMC2 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mmc2 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_mmc2_hwmod,
+	.clk		= "mmchs2_ick",
+	.addr		= omap2430_mmc2_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
 
+/* l4 core -> mcspi3 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi3 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_mcspi3_hwmod,
+	.clk		= "mcspi3_ick",
+	.addr		= omap2430_mcspi3_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* IVA2 <- L3 interface */
+static struct omap_hwmod_ocp_if omap2430_l3__iva = {
+	.master		= &omap2xxx_l3_main_hwmod,
+	.slave		= &omap2430_iva_hwmod,
+	.clk		= "core_l3_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2430_timer1_addrs[] = {
+	{
+		.pa_start	= 0x49018000,
+		.pa_end		= 0x49018000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__timer1 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_timer1_hwmod,
+	.clk		= "gpt1_ick",
+	.addr		= omap2430_timer1_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2430_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x49016000,
+		.pa_end		= 0x4901607f,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__wd_timer2 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_wd_timer2_hwmod,
+	.clk		= "mpu_wdt_ick",
+	.addr		= omap2430_wd_timer2_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio1 */
+static struct omap_hwmod_addr_space omap2430_gpio1_addr_space[] = {
+	{
+		.pa_start	= 0x4900C000,
+		.pa_end		= 0x4900C1ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio1 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_gpio1_hwmod,
+	.clk		= "gpios_ick",
+	.addr		= omap2430_gpio1_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio2 */
+static struct omap_hwmod_addr_space omap2430_gpio2_addr_space[] = {
+	{
+		.pa_start	= 0x4900E000,
+		.pa_end		= 0x4900E1ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio2 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_gpio2_hwmod,
+	.clk		= "gpios_ick",
+	.addr		= omap2430_gpio2_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio3 */
+static struct omap_hwmod_addr_space omap2430_gpio3_addr_space[] = {
+	{
+		.pa_start	= 0x49010000,
+		.pa_end		= 0x490101ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio3 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_gpio3_hwmod,
+	.clk		= "gpios_ick",
+	.addr		= omap2430_gpio3_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio4 */
+static struct omap_hwmod_addr_space omap2430_gpio4_addr_space[] = {
+	{
+		.pa_start	= 0x49012000,
+		.pa_end		= 0x490121ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio4 = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_gpio4_hwmod,
+	.clk		= "gpios_ick",
+	.addr		= omap2430_gpio4_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> gpio5 */
+static struct omap_hwmod_addr_space omap2430_gpio5_addr_space[] = {
+	{
+		.pa_start	= 0x480B6000,
+		.pa_end		= 0x480B61ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_core__gpio5 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_gpio5_hwmod,
+	.clk		= "gpio5_ick",
+	.addr		= omap2430_gpio5_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dma_system -> L3 */
+static struct omap_hwmod_ocp_if omap2430_dma_system__l3 = {
+	.master		= &omap2430_dma_system_hwmod,
+	.slave		= &omap2xxx_l3_main_hwmod,
+	.clk		= "core_l3_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dma_system */
+static struct omap_hwmod_ocp_if omap2430_l4_core__dma_system = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_dma_system_hwmod,
+	.clk		= "sdma_ick",
+	.addr		= omap2_dma_system_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> mailbox */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mailbox = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_mailbox_hwmod,
+	.addr		= omap2_mailbox_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> mcbsp1 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp1 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_mcbsp1_hwmod,
+	.clk		= "mcbsp1_ick",
+	.addr		= omap2_mcbsp1_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> mcbsp2 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp2 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_mcbsp2_hwmod,
+	.clk		= "mcbsp2_ick",
+	.addr		= omap2xxx_mcbsp2_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp3_addrs[] = {
+	{
+		.name		= "mpu",
+		.pa_start	= 0x4808C000,
+		.pa_end		= 0x4808C0ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_core -> mcbsp3 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp3 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_mcbsp3_hwmod,
+	.clk		= "mcbsp3_ick",
+	.addr		= omap2430_mcbsp3_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp4_addrs[] = {
+	{
+		.name		= "mpu",
+		.pa_start	= 0x4808E000,
+		.pa_end		= 0x4808E0ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_core -> mcbsp4 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp4 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_mcbsp4_hwmod,
+	.clk		= "mcbsp4_ick",
+	.addr		= omap2430_mcbsp4_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp5_addrs[] = {
+	{
+		.name		= "mpu",
+		.pa_start	= 0x48096000,
+		.pa_end		= 0x480960ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_core -> mcbsp5 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp5 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_mcbsp5_hwmod,
+	.clk		= "mcbsp5_ick",
+	.addr		= omap2430_mcbsp5_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> hdq1w */
+static struct omap_hwmod_ocp_if omap2430_l4_core__hdq1w = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2430_hdq1w_hwmod,
+	.clk		= "hdq_ick",
+	.addr		= omap2_hdq1w_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+	.flags		= OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE,
+};
+
+/* l4_wkup -> 32ksync_counter */
+static struct omap_hwmod_addr_space omap2430_counter_32k_addrs[] = {
+	{
+		.pa_start	= 0x49020000,
+		.pa_end		= 0x4902001f,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__counter_32k = {
+	.master		= &omap2xxx_l4_wkup_hwmod,
+	.slave		= &omap2xxx_counter_32k_hwmod,
+	.clk		= "sync_32k_ick",
+	.addr		= omap2430_counter_32k_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = {
+	&omap2xxx_l3_main__l4_core,
+	&omap2xxx_mpu__l3_main,
+	&omap2xxx_dss__l3,
+	&omap2430_usbhsotg__l3,
+	&omap2430_l4_core__i2c1,
+	&omap2430_l4_core__i2c2,
+	&omap2xxx_l4_core__l4_wkup,
+	&omap2_l4_core__uart1,
+	&omap2_l4_core__uart2,
+	&omap2_l4_core__uart3,
+	&omap2430_l4_core__usbhsotg,
+	&omap2430_l4_core__mmc1,
+	&omap2430_l4_core__mmc2,
+	&omap2xxx_l4_core__mcspi1,
+	&omap2xxx_l4_core__mcspi2,
+	&omap2430_l4_core__mcspi3,
+	&omap2430_l3__iva,
+	&omap2430_l4_wkup__timer1,
+	&omap2xxx_l4_core__timer2,
+	&omap2xxx_l4_core__timer3,
+	&omap2xxx_l4_core__timer4,
+	&omap2xxx_l4_core__timer5,
+	&omap2xxx_l4_core__timer6,
+	&omap2xxx_l4_core__timer7,
+	&omap2xxx_l4_core__timer8,
+	&omap2xxx_l4_core__timer9,
+	&omap2xxx_l4_core__timer10,
+	&omap2xxx_l4_core__timer11,
+	&omap2xxx_l4_core__timer12,
+	&omap2430_l4_wkup__wd_timer2,
+	&omap2xxx_l4_core__dss,
+	&omap2xxx_l4_core__dss_dispc,
+	&omap2xxx_l4_core__dss_rfbi,
+	&omap2xxx_l4_core__dss_venc,
+	&omap2430_l4_wkup__gpio1,
+	&omap2430_l4_wkup__gpio2,
+	&omap2430_l4_wkup__gpio3,
+	&omap2430_l4_wkup__gpio4,
+	&omap2430_l4_core__gpio5,
+	&omap2430_dma_system__l3,
+	&omap2430_l4_core__dma_system,
+	&omap2430_l4_core__mailbox,
+	&omap2430_l4_core__mcbsp1,
+	&omap2430_l4_core__mcbsp2,
+	&omap2430_l4_core__mcbsp3,
+	&omap2430_l4_core__mcbsp4,
+	&omap2430_l4_core__mcbsp5,
+	&omap2430_l4_core__hdq1w,
+	&omap2430_l4_wkup__counter_32k,
 	NULL,
 };
 
 int __init omap2430_hwmod_init(void)
 {
-	return omap_hwmod_register(omap2430_hwmods);
+	return omap_hwmod_register_links(omap2430_hwmod_ocp_ifs);
 }
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c
index 04637fa..cbb4ef6 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c
@@ -171,3 +171,12 @@
 	},
 	{ }
 };
+
+struct omap_hwmod_addr_space omap2_hdq1w_addr_space[] = {
+	{
+		.pa_start       = 0x480b2000,
+		.pa_end         = 0x480b2fff,
+		.flags          = ADDR_TYPE_RT,
+	},
+	{ }
+};
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c
index f08e442..102d76e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c
@@ -2,6 +2,7 @@
  * omap_hwmod_2xxx_3xxx_ipblock_data.c - common IP block data for OMAP2/3
  *
  * Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
  * Paul Walmsley
  *
  * This program is free software; you can redistribute it and/or modify
@@ -12,6 +13,7 @@
 #include <plat/serial.h>
 #include <plat/dma.h>
 #include <plat/common.h>
+#include <plat/hdq1w.h>
 
 #include <mach/irqs.h>
 
@@ -302,3 +304,23 @@
 	{ .irq = -1 }
 };
 
+struct omap_hwmod_class_sysconfig omap2_hdq1w_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x14,
+	.syss_offs	= 0x18,
+	.sysc_flags	= (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+			   SYSS_HAS_RESET_STATUS),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+struct omap_hwmod_class omap2_hdq1w_class = {
+	.name	= "hdq1w",
+	.sysc	= &omap2_hdq1w_sysc,
+	.reset	= &omap_hdq1w_reset,
+};
+
+struct omap_hwmod_irq_info omap2_hdq1w_mpu_irqs[] = {
+	{ .irq = 58, },
+	{ .irq = -1 }
+};
+
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
index 4f3547c..5178e40 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
@@ -15,10 +15,12 @@
 
 #include <plat/omap_hwmod.h>
 #include <plat/serial.h>
+#include <plat/l3_2xxx.h>
+#include <plat/l4_2xxx.h>
 
 #include "omap_hwmod_common_data.h"
 
-struct omap_hwmod_addr_space omap2xxx_uart1_addr_space[] = {
+static struct omap_hwmod_addr_space omap2xxx_uart1_addr_space[] = {
 	{
 		.pa_start	= OMAP2_UART1_BASE,
 		.pa_end		= OMAP2_UART1_BASE + SZ_8K - 1,
@@ -27,7 +29,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_uart2_addr_space[] = {
+static struct omap_hwmod_addr_space omap2xxx_uart2_addr_space[] = {
 	{
 		.pa_start	= OMAP2_UART2_BASE,
 		.pa_end		= OMAP2_UART2_BASE + SZ_1K - 1,
@@ -36,7 +38,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_uart3_addr_space[] = {
+static struct omap_hwmod_addr_space omap2xxx_uart3_addr_space[] = {
 	{
 		.pa_start	= OMAP2_UART3_BASE,
 		.pa_end		= OMAP2_UART3_BASE + SZ_1K - 1,
@@ -45,7 +47,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_timer2_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer2_addrs[] = {
 	{
 		.pa_start	= 0x4802a000,
 		.pa_end		= 0x4802a000 + SZ_1K - 1,
@@ -54,7 +56,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_timer3_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer3_addrs[] = {
 	{
 		.pa_start	= 0x48078000,
 		.pa_end		= 0x48078000 + SZ_1K - 1,
@@ -63,7 +65,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_timer4_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer4_addrs[] = {
 	{
 		.pa_start	= 0x4807a000,
 		.pa_end		= 0x4807a000 + SZ_1K - 1,
@@ -72,7 +74,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_timer5_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer5_addrs[] = {
 	{
 		.pa_start	= 0x4807c000,
 		.pa_end		= 0x4807c000 + SZ_1K - 1,
@@ -81,7 +83,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_timer6_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer6_addrs[] = {
 	{
 		.pa_start	= 0x4807e000,
 		.pa_end		= 0x4807e000 + SZ_1K - 1,
@@ -90,7 +92,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_timer7_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer7_addrs[] = {
 	{
 		.pa_start	= 0x48080000,
 		.pa_end		= 0x48080000 + SZ_1K - 1,
@@ -99,7 +101,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_timer8_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer8_addrs[] = {
 	{
 		.pa_start	= 0x48082000,
 		.pa_end		= 0x48082000 + SZ_1K - 1,
@@ -108,7 +110,7 @@
 	{ }
 };
 
-struct omap_hwmod_addr_space omap2xxx_timer9_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer9_addrs[] = {
 	{
 		.pa_start	= 0x48084000,
 		.pa_end		= 0x48084000 + SZ_1K - 1,
@@ -127,4 +129,246 @@
 	{ }
 };
 
+/*
+ * Common interconnect data
+ */
+
+/* L3 -> L4_CORE interface */
+struct omap_hwmod_ocp_if omap2xxx_l3_main__l4_core = {
+	.master	= &omap2xxx_l3_main_hwmod,
+	.slave	= &omap2xxx_l4_core_hwmod,
+	.user	= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* MPU -> L3 interface */
+struct omap_hwmod_ocp_if omap2xxx_mpu__l3_main = {
+	.master = &omap2xxx_mpu_hwmod,
+	.slave	= &omap2xxx_l3_main_hwmod,
+	.user	= OCP_USER_MPU,
+};
+
+/* DSS -> l3 */
+struct omap_hwmod_ocp_if omap2xxx_dss__l3 = {
+	.master		= &omap2xxx_dss_core_hwmod,
+	.slave		= &omap2xxx_l3_main_hwmod,
+	.fw = {
+		.omap2 = {
+			.l3_perm_bit  = OMAP2_L3_CORE_FW_CONNID_DSS,
+			.flags	= OMAP_FIREWALL_L3,
+		}
+	},
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4_CORE -> L4_WKUP interface */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__l4_wkup = {
+	.master	= &omap2xxx_l4_core_hwmod,
+	.slave	= &omap2xxx_l4_wkup_hwmod,
+	.user	= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART1 interface */
+struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_uart1_hwmod,
+	.clk		= "uart1_ick",
+	.addr		= omap2xxx_uart1_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_uart2_hwmod,
+	.clk		= "uart2_ick",
+	.addr		= omap2xxx_uart2_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_uart3_hwmod,
+	.clk		= "uart3_ick",
+	.addr		= omap2xxx_uart3_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi1 interface */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__mcspi1 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_mcspi1_hwmod,
+	.clk		= "mcspi1_ick",
+	.addr		= omap2_mcspi1_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi2 interface */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__mcspi2 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_mcspi2_hwmod,
+	.clk		= "mcspi2_ick",
+	.addr		= omap2_mcspi2_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer2 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer2 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer2_hwmod,
+	.clk		= "gpt2_ick",
+	.addr		= omap2xxx_timer2_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer3 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer3 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer3_hwmod,
+	.clk		= "gpt3_ick",
+	.addr		= omap2xxx_timer3_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer4 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer4 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer4_hwmod,
+	.clk		= "gpt4_ick",
+	.addr		= omap2xxx_timer4_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer5 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer5 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer5_hwmod,
+	.clk		= "gpt5_ick",
+	.addr		= omap2xxx_timer5_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer6 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer6 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer6_hwmod,
+	.clk		= "gpt6_ick",
+	.addr		= omap2xxx_timer6_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer7 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer7 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer7_hwmod,
+	.clk		= "gpt7_ick",
+	.addr		= omap2xxx_timer7_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer8 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer8 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer8_hwmod,
+	.clk		= "gpt8_ick",
+	.addr		= omap2xxx_timer8_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer9 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer9 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer9_hwmod,
+	.clk		= "gpt9_ick",
+	.addr		= omap2xxx_timer9_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer10 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer10 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer10_hwmod,
+	.clk		= "gpt10_ick",
+	.addr		= omap2_timer10_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer11 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer11 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer11_hwmod,
+	.clk		= "gpt11_ick",
+	.addr		= omap2_timer11_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer12 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer12 = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_timer12_hwmod,
+	.clk		= "gpt12_ick",
+	.addr		= omap2xxx_timer12_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__dss = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_dss_core_hwmod,
+	.clk		= "dss_ick",
+	.addr		= omap2_dss_addrs,
+	.fw = {
+		.omap2 = {
+			.l4_fw_region  = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
+			.flags	= OMAP_FIREWALL_L4,
+		}
+	},
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss_dispc */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_dispc = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_dss_dispc_hwmod,
+	.clk		= "dss_ick",
+	.addr		= omap2_dss_dispc_addrs,
+	.fw = {
+		.omap2 = {
+			.l4_fw_region  = OMAP2420_L4_CORE_FW_DSS_DISPC_REGION,
+			.flags	= OMAP_FIREWALL_L4,
+		}
+	},
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss_rfbi */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_rfbi = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_dss_rfbi_hwmod,
+	.clk		= "dss_ick",
+	.addr		= omap2_dss_rfbi_addrs,
+	.fw = {
+		.omap2 = {
+			.l4_fw_region  = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
+			.flags	= OMAP_FIREWALL_L4,
+		}
+	},
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss_venc */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_venc = {
+	.master		= &omap2xxx_l4_core_hwmod,
+	.slave		= &omap2xxx_dss_venc_hwmod,
+	.clk		= "dss_ick",
+	.addr		= omap2_dss_venc_addrs,
+	.fw = {
+		.omap2 = {
+			.l4_fw_region  = OMAP2420_L4_CORE_FW_DSS_VENC_REGION,
+			.flags	= OMAP_FIREWALL_L4,
+		}
+	},
+	.flags		= OCPIF_SWSUP_IDLE,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index 2a67297..83eafd9 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -10,6 +10,7 @@
  */
 #include <plat/omap_hwmod.h>
 #include <plat/serial.h>
+#include <plat/gpio.h>
 #include <plat/dma.h>
 #include <plat/dmtimer.h>
 #include <plat/mcspi.h>
@@ -17,6 +18,8 @@
 #include <mach/irqs.h>
 
 #include "omap_hwmod_common_data.h"
+#include "cm-regbits-24xx.h"
+#include "prm-regbits-24xx.h"
 #include "wd_timer.h"
 
 struct omap_hwmod_irq_info omap2xxx_timer12_mpu_irqs[] = {
@@ -86,7 +89,8 @@
 struct omap_hwmod_class omap2xxx_wd_timer_hwmod_class = {
 	.name		= "wd_timer",
 	.sysc		= &omap2xxx_wd_timer_sysc,
-	.pre_shutdown	= &omap2_wd_timer_disable
+	.pre_shutdown	= &omap2_wd_timer_disable,
+	.reset		= &omap2_wd_timer_reset,
 };
 
 /*
@@ -170,3 +174,582 @@
 	.sysc	= &omap2xxx_mcspi_sysc,
 	.rev	= OMAP2_MCSPI_REV,
 };
+
+/*
+ * IP blocks
+ */
+
+/* L3 */
+struct omap_hwmod omap2xxx_l3_main_hwmod = {
+	.name		= "l3_main",
+	.class		= &l3_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* L4 CORE */
+struct omap_hwmod omap2xxx_l4_core_hwmod = {
+	.name		= "l4_core",
+	.class		= &l4_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* L4 WKUP */
+struct omap_hwmod omap2xxx_l4_wkup_hwmod = {
+	.name		= "l4_wkup",
+	.class		= &l4_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* MPU */
+struct omap_hwmod omap2xxx_mpu_hwmod = {
+	.name		= "mpu",
+	.class		= &mpu_hwmod_class,
+	.main_clk	= "mpu_ck",
+};
+
+/* IVA2 */
+struct omap_hwmod omap2xxx_iva_hwmod = {
+	.name		= "iva",
+	.class		= &iva_hwmod_class,
+};
+
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+	.timer_capability       = OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+	.timer_capability       = OMAP_TIMER_HAS_PWM,
+};
+
+/* timer1 */
+
+struct omap_hwmod omap2xxx_timer1_hwmod = {
+	.name		= "timer1",
+	.mpu_irqs	= omap2_timer1_mpu_irqs,
+	.main_clk	= "gpt1_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT1_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer2 */
+
+struct omap_hwmod omap2xxx_timer2_hwmod = {
+	.name		= "timer2",
+	.mpu_irqs	= omap2_timer2_mpu_irqs,
+	.main_clk	= "gpt2_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT2_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer3 */
+
+struct omap_hwmod omap2xxx_timer3_hwmod = {
+	.name		= "timer3",
+	.mpu_irqs	= omap2_timer3_mpu_irqs,
+	.main_clk	= "gpt3_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT3_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer4 */
+
+struct omap_hwmod omap2xxx_timer4_hwmod = {
+	.name		= "timer4",
+	.mpu_irqs	= omap2_timer4_mpu_irqs,
+	.main_clk	= "gpt4_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT4_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer5 */
+
+struct omap_hwmod omap2xxx_timer5_hwmod = {
+	.name		= "timer5",
+	.mpu_irqs	= omap2_timer5_mpu_irqs,
+	.main_clk	= "gpt5_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT5_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer6 */
+
+struct omap_hwmod omap2xxx_timer6_hwmod = {
+	.name		= "timer6",
+	.mpu_irqs	= omap2_timer6_mpu_irqs,
+	.main_clk	= "gpt6_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT6_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer7 */
+
+struct omap_hwmod omap2xxx_timer7_hwmod = {
+	.name		= "timer7",
+	.mpu_irqs	= omap2_timer7_mpu_irqs,
+	.main_clk	= "gpt7_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT7_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer8 */
+
+struct omap_hwmod omap2xxx_timer8_hwmod = {
+	.name		= "timer8",
+	.mpu_irqs	= omap2_timer8_mpu_irqs,
+	.main_clk	= "gpt8_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT8_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer9 */
+
+struct omap_hwmod omap2xxx_timer9_hwmod = {
+	.name		= "timer9",
+	.mpu_irqs	= omap2_timer9_mpu_irqs,
+	.main_clk	= "gpt9_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT9_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer10 */
+
+struct omap_hwmod omap2xxx_timer10_hwmod = {
+	.name		= "timer10",
+	.mpu_irqs	= omap2_timer10_mpu_irqs,
+	.main_clk	= "gpt10_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT10_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer11 */
+
+struct omap_hwmod omap2xxx_timer11_hwmod = {
+	.name		= "timer11",
+	.mpu_irqs	= omap2_timer11_mpu_irqs,
+	.main_clk	= "gpt11_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT11_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* timer12 */
+
+struct omap_hwmod omap2xxx_timer12_hwmod = {
+	.name		= "timer12",
+	.mpu_irqs	= omap2xxx_timer12_mpu_irqs,
+	.main_clk	= "gpt12_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPT12_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+	.class		= &omap2xxx_timer_hwmod_class,
+};
+
+/* wd_timer2 */
+struct omap_hwmod omap2xxx_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap2xxx_wd_timer_hwmod_class,
+	.main_clk	= "mpu_wdt_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+		},
+	},
+};
+
+/* UART1 */
+
+struct omap_hwmod omap2xxx_uart1_hwmod = {
+	.name		= "uart1",
+	.mpu_irqs	= omap2_uart1_mpu_irqs,
+	.sdma_reqs	= omap2_uart1_sdma_reqs,
+	.main_clk	= "uart1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+		},
+	},
+	.class		= &omap2_uart_class,
+};
+
+/* UART2 */
+
+struct omap_hwmod omap2xxx_uart2_hwmod = {
+	.name		= "uart2",
+	.mpu_irqs	= omap2_uart2_mpu_irqs,
+	.sdma_reqs	= omap2_uart2_sdma_reqs,
+	.main_clk	= "uart2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+		},
+	},
+	.class		= &omap2_uart_class,
+};
+
+/* UART3 */
+
+struct omap_hwmod omap2xxx_uart3_hwmod = {
+	.name		= "uart3",
+	.mpu_irqs	= omap2_uart3_mpu_irqs,
+	.sdma_reqs	= omap2_uart3_sdma_reqs,
+	.main_clk	= "uart3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 2,
+			.module_bit = OMAP24XX_EN_UART3_SHIFT,
+			.idlest_reg_id = 2,
+			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+		},
+	},
+	.class		= &omap2_uart_class,
+};
+
+/* dss */
+
+static struct omap_hwmod_opt_clk dss_opt_clks[] = {
+	/*
+	 * The DSS HW needs all DSS clocks enabled during reset. The dss_core
+	 * driver does not use these clocks.
+	 */
+	{ .role = "tv_clk", .clk = "dss_54m_fck" },
+	{ .role = "sys_clk", .clk = "dss2_fck" },
+};
+
+struct omap_hwmod omap2xxx_dss_core_hwmod = {
+	.name		= "dss_core",
+	.class		= &omap2_dss_hwmod_class,
+	.main_clk	= "dss1_fck", /* instead of dss_fck */
+	.sdma_reqs	= omap2xxx_dss_sdma_chs,
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
+		},
+	},
+	.opt_clks	= dss_opt_clks,
+	.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
+	.flags		= HWMOD_NO_IDLEST | HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+};
+
+struct omap_hwmod omap2xxx_dss_dispc_hwmod = {
+	.name		= "dss_dispc",
+	.class		= &omap2_dispc_hwmod_class,
+	.mpu_irqs	= omap2_dispc_irqs,
+	.main_clk	= "dss1_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
+		},
+	},
+	.flags		= HWMOD_NO_IDLEST,
+	.dev_attr	= &omap2_3_dss_dispc_dev_attr
+};
+
+static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
+	{ .role = "ick", .clk = "dss_ick" },
+};
+
+struct omap_hwmod omap2xxx_dss_rfbi_hwmod = {
+	.name		= "dss_rfbi",
+	.class		= &omap2_rfbi_hwmod_class,
+	.main_clk	= "dss1_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
+			.module_offs = CORE_MOD,
+		},
+	},
+	.opt_clks	= dss_rfbi_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dss_rfbi_opt_clks),
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+struct omap_hwmod omap2xxx_dss_venc_hwmod = {
+	.name		= "dss_venc",
+	.class		= &omap2_venc_hwmod_class,
+	.main_clk	= "dss_54m_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_DSS1_SHIFT,
+			.module_offs = CORE_MOD,
+		},
+	},
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* gpio dev_attr */
+struct omap_gpio_dev_attr omap2xxx_gpio_dev_attr = {
+	.bank_width = 32,
+	.dbck_flag = false,
+};
+
+/* gpio1 */
+struct omap_hwmod omap2xxx_gpio1_hwmod = {
+	.name		= "gpio1",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap2_gpio1_irqs,
+	.main_clk	= "gpios_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
+		},
+	},
+	.class		= &omap2xxx_gpio_hwmod_class,
+	.dev_attr	= &omap2xxx_gpio_dev_attr,
+};
+
+/* gpio2 */
+struct omap_hwmod omap2xxx_gpio2_hwmod = {
+	.name		= "gpio2",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap2_gpio2_irqs,
+	.main_clk	= "gpios_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
+		},
+	},
+	.class		= &omap2xxx_gpio_hwmod_class,
+	.dev_attr	= &omap2xxx_gpio_dev_attr,
+};
+
+/* gpio3 */
+struct omap_hwmod omap2xxx_gpio3_hwmod = {
+	.name		= "gpio3",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap2_gpio3_irqs,
+	.main_clk	= "gpios_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
+		},
+	},
+	.class		= &omap2xxx_gpio_hwmod_class,
+	.dev_attr	= &omap2xxx_gpio_dev_attr,
+};
+
+/* gpio4 */
+struct omap_hwmod omap2xxx_gpio4_hwmod = {
+	.name		= "gpio4",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap2_gpio4_irqs,
+	.main_clk	= "gpios_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_GPIOS_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
+		},
+	},
+	.class		= &omap2xxx_gpio_hwmod_class,
+	.dev_attr	= &omap2xxx_gpio_dev_attr,
+};
+
+/* mcspi1 */
+static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
+	.num_chipselect = 4,
+};
+
+struct omap_hwmod omap2xxx_mcspi1_hwmod = {
+	.name		= "mcspi1",
+	.mpu_irqs	= omap2_mcspi1_mpu_irqs,
+	.sdma_reqs	= omap2_mcspi1_sdma_reqs,
+	.main_clk	= "mcspi1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_MCSPI1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_MCSPI1_SHIFT,
+		},
+	},
+	.class		= &omap2xxx_mcspi_class,
+	.dev_attr	= &omap_mcspi1_dev_attr,
+};
+
+/* mcspi2 */
+static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
+	.num_chipselect = 2,
+};
+
+struct omap_hwmod omap2xxx_mcspi2_hwmod = {
+	.name		= "mcspi2",
+	.mpu_irqs	= omap2_mcspi2_mpu_irqs,
+	.sdma_reqs	= omap2_mcspi2_sdma_reqs,
+	.main_clk	= "mcspi2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_MCSPI2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_MCSPI2_SHIFT,
+		},
+	},
+	.class		= &omap2xxx_mcspi_class,
+	.dev_attr	= &omap_mcspi2_dev_attr,
+};
+
+
+static struct omap_hwmod_class omap2xxx_counter_hwmod_class = {
+	.name	= "counter",
+};
+
+struct omap_hwmod omap2xxx_counter_32k_hwmod = {
+	.name		= "counter_32k",
+	.main_clk	= "func_32k_ck",
+	.prcm		= {
+		.omap2	= {
+			.module_offs = WKUP_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_ST_32KSYNC_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_32KSYNC_SHIFT,
+		},
+	},
+	.class		= &omap2xxx_counter_hwmod_class,
+};
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index db86ce9..fd48797 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -2,6 +2,7 @@
  * omap_hwmod_3xxx_data.c - hardware modules present on the OMAP3xxx chips
  *
  * Copyright (C) 2009-2011 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
  * Paul Walmsley
  *
  * This program is free software; you can redistribute it and/or modify
@@ -38,55 +39,2001 @@
 /*
  * OMAP3xxx hardware module integration data
  *
- * ALl of the data in this section should be autogeneratable from the
+ * All of the data in this section should be autogeneratable from the
  * TI hardware database or other technical documentation.  Data that
  * is driver-specific or driver-kernel integration-specific belongs
  * elsewhere.
  */
 
-static struct omap_hwmod omap3xxx_mpu_hwmod;
-static struct omap_hwmod omap3xxx_iva_hwmod;
-static struct omap_hwmod omap3xxx_l3_main_hwmod;
-static struct omap_hwmod omap3xxx_l4_core_hwmod;
-static struct omap_hwmod omap3xxx_l4_per_hwmod;
-static struct omap_hwmod omap3xxx_wd_timer2_hwmod;
-static struct omap_hwmod omap3430es1_dss_core_hwmod;
-static struct omap_hwmod omap3xxx_dss_core_hwmod;
-static struct omap_hwmod omap3xxx_dss_dispc_hwmod;
-static struct omap_hwmod omap3xxx_dss_dsi1_hwmod;
-static struct omap_hwmod omap3xxx_dss_rfbi_hwmod;
-static struct omap_hwmod omap3xxx_dss_venc_hwmod;
-static struct omap_hwmod omap3xxx_i2c1_hwmod;
-static struct omap_hwmod omap3xxx_i2c2_hwmod;
-static struct omap_hwmod omap3xxx_i2c3_hwmod;
-static struct omap_hwmod omap3xxx_gpio1_hwmod;
-static struct omap_hwmod omap3xxx_gpio2_hwmod;
-static struct omap_hwmod omap3xxx_gpio3_hwmod;
-static struct omap_hwmod omap3xxx_gpio4_hwmod;
-static struct omap_hwmod omap3xxx_gpio5_hwmod;
-static struct omap_hwmod omap3xxx_gpio6_hwmod;
-static struct omap_hwmod omap34xx_sr1_hwmod;
-static struct omap_hwmod omap34xx_sr2_hwmod;
-static struct omap_hwmod omap34xx_mcspi1;
-static struct omap_hwmod omap34xx_mcspi2;
-static struct omap_hwmod omap34xx_mcspi3;
-static struct omap_hwmod omap34xx_mcspi4;
-static struct omap_hwmod omap3xxx_mmc1_hwmod;
-static struct omap_hwmod omap3xxx_mmc2_hwmod;
-static struct omap_hwmod omap3xxx_mmc3_hwmod;
-static struct omap_hwmod am35xx_usbhsotg_hwmod;
+/*
+ * IP blocks
+ */
 
-static struct omap_hwmod omap3xxx_dma_system_hwmod;
+/* L3 */
+static struct omap_hwmod_irq_info omap3xxx_l3_main_irqs[] = {
+	{ .irq = INT_34XX_L3_DBG_IRQ },
+	{ .irq = INT_34XX_L3_APP_IRQ },
+	{ .irq = -1 }
+};
 
-static struct omap_hwmod omap3xxx_mcbsp1_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp2_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp3_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp4_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp5_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod;
-static struct omap_hwmod omap3xxx_usb_host_hs_hwmod;
-static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod;
+static struct omap_hwmod omap3xxx_l3_main_hwmod = {
+	.name		= "l3_main",
+	.class		= &l3_hwmod_class,
+	.mpu_irqs	= omap3xxx_l3_main_irqs,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* L4 CORE */
+static struct omap_hwmod omap3xxx_l4_core_hwmod = {
+	.name		= "l4_core",
+	.class		= &l4_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* L4 PER */
+static struct omap_hwmod omap3xxx_l4_per_hwmod = {
+	.name		= "l4_per",
+	.class		= &l4_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* L4 WKUP */
+static struct omap_hwmod omap3xxx_l4_wkup_hwmod = {
+	.name		= "l4_wkup",
+	.class		= &l4_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* L4 SEC */
+static struct omap_hwmod omap3xxx_l4_sec_hwmod = {
+	.name		= "l4_sec",
+	.class		= &l4_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* MPU */
+static struct omap_hwmod omap3xxx_mpu_hwmod = {
+	.name		= "mpu",
+	.class		= &mpu_hwmod_class,
+	.main_clk	= "arm_fck",
+};
+
+/* IVA2 (IVA2) */
+static struct omap_hwmod_rst_info omap3xxx_iva_resets[] = {
+	{ .name = "logic", .rst_shift = 0 },
+	{ .name = "seq0", .rst_shift = 1 },
+	{ .name = "seq1", .rst_shift = 2 },
+};
+
+static struct omap_hwmod omap3xxx_iva_hwmod = {
+	.name		= "iva",
+	.class		= &iva_hwmod_class,
+	.clkdm_name	= "iva2_clkdm",
+	.rst_lines	= omap3xxx_iva_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap3xxx_iva_resets),
+	.main_clk	= "iva2_ck",
+};
+
+/* timer class */
+static struct omap_hwmod_class_sysconfig omap3xxx_timer_1ms_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
+				SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+				SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_timer_1ms_hwmod_class = {
+	.name = "timer",
+	.sysc = &omap3xxx_timer_1ms_sysc,
+	.rev = OMAP_TIMER_IP_VERSION_1,
+};
+
+static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
+			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
+	.name = "timer",
+	.sysc = &omap3xxx_timer_sysc,
+	.rev =  OMAP_TIMER_IP_VERSION_1,
+};
+
+/* secure timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_secure_dev_attr = {
+	.timer_capability	= OMAP_TIMER_SECURE,
+};
+
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+	.timer_capability	= OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+	.timer_capability	= OMAP_TIMER_HAS_PWM,
+};
+
+/* timer1 */
+static struct omap_hwmod omap3xxx_timer1_hwmod = {
+	.name		= "timer1",
+	.mpu_irqs	= omap2_timer1_mpu_irqs,
+	.main_clk	= "gpt1_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT1_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT1_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap3xxx_timer_1ms_hwmod_class,
+};
+
+/* timer2 */
+static struct omap_hwmod omap3xxx_timer2_hwmod = {
+	.name		= "timer2",
+	.mpu_irqs	= omap2_timer2_mpu_irqs,
+	.main_clk	= "gpt2_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT2_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT2_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap3xxx_timer_1ms_hwmod_class,
+};
+
+/* timer3 */
+static struct omap_hwmod omap3xxx_timer3_hwmod = {
+	.name		= "timer3",
+	.mpu_irqs	= omap2_timer3_mpu_irqs,
+	.main_clk	= "gpt3_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT3_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT3_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap3xxx_timer_hwmod_class,
+};
+
+/* timer4 */
+static struct omap_hwmod omap3xxx_timer4_hwmod = {
+	.name		= "timer4",
+	.mpu_irqs	= omap2_timer4_mpu_irqs,
+	.main_clk	= "gpt4_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT4_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT4_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap3xxx_timer_hwmod_class,
+};
+
+/* timer5 */
+static struct omap_hwmod omap3xxx_timer5_hwmod = {
+	.name		= "timer5",
+	.mpu_irqs	= omap2_timer5_mpu_irqs,
+	.main_clk	= "gpt5_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT5_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT5_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap3xxx_timer_hwmod_class,
+};
+
+/* timer6 */
+static struct omap_hwmod omap3xxx_timer6_hwmod = {
+	.name		= "timer6",
+	.mpu_irqs	= omap2_timer6_mpu_irqs,
+	.main_clk	= "gpt6_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT6_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT6_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap3xxx_timer_hwmod_class,
+};
+
+/* timer7 */
+static struct omap_hwmod omap3xxx_timer7_hwmod = {
+	.name		= "timer7",
+	.mpu_irqs	= omap2_timer7_mpu_irqs,
+	.main_clk	= "gpt7_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT7_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT7_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &omap3xxx_timer_hwmod_class,
+};
+
+/* timer8 */
+static struct omap_hwmod omap3xxx_timer8_hwmod = {
+	.name		= "timer8",
+	.mpu_irqs	= omap2_timer8_mpu_irqs,
+	.main_clk	= "gpt8_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT8_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT8_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+	.class		= &omap3xxx_timer_hwmod_class,
+};
+
+/* timer9 */
+static struct omap_hwmod omap3xxx_timer9_hwmod = {
+	.name		= "timer9",
+	.mpu_irqs	= omap2_timer9_mpu_irqs,
+	.main_clk	= "gpt9_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT9_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT9_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+	.class		= &omap3xxx_timer_hwmod_class,
+};
+
+/* timer10 */
+static struct omap_hwmod omap3xxx_timer10_hwmod = {
+	.name		= "timer10",
+	.mpu_irqs	= omap2_timer10_mpu_irqs,
+	.main_clk	= "gpt10_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT10_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT10_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+	.class		= &omap3xxx_timer_1ms_hwmod_class,
+};
+
+/* timer11 */
+static struct omap_hwmod omap3xxx_timer11_hwmod = {
+	.name		= "timer11",
+	.mpu_irqs	= omap2_timer11_mpu_irqs,
+	.main_clk	= "gpt11_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT11_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT11_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+	.class		= &omap3xxx_timer_hwmod_class,
+};
+
+/* timer12 */
+static struct omap_hwmod_irq_info omap3xxx_timer12_mpu_irqs[] = {
+	{ .irq = 95, },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap3xxx_timer12_hwmod = {
+	.name		= "timer12",
+	.mpu_irqs	= omap3xxx_timer12_mpu_irqs,
+	.main_clk	= "gpt12_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPT12_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPT12_SHIFT,
+		},
+	},
+	.dev_attr	= &capability_secure_dev_attr,
+	.class		= &omap3xxx_timer_hwmod_class,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_wd_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+/* I2C common */
+static struct omap_hwmod_class_sysconfig i2c_sysc = {
+	.rev_offs	= 0x00,
+	.sysc_offs	= 0x20,
+	.syss_offs	= 0x10,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.clockact	= CLOCKACT_TEST_ICLK,
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_wd_timer_hwmod_class = {
+	.name		= "wd_timer",
+	.sysc		= &omap3xxx_wd_timer_sysc,
+	.pre_shutdown	= &omap2_wd_timer_disable,
+	.reset		= &omap2_wd_timer_reset,
+};
+
+static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap3xxx_wd_timer_hwmod_class,
+	.main_clk	= "wdt2_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_WDT2_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_WDT2_SHIFT,
+		},
+	},
+	/*
+	 * XXX: Use software supervised mode, HW supervised smartidle seems to
+	 * block CORE power domain idle transitions. Maybe a HW bug in wdt2?
+	 */
+	.flags		= HWMOD_SWSUP_SIDLE,
+};
+
+/* UART1 */
+static struct omap_hwmod omap3xxx_uart1_hwmod = {
+	.name		= "uart1",
+	.mpu_irqs	= omap2_uart1_mpu_irqs,
+	.sdma_reqs	= omap2_uart1_sdma_reqs,
+	.main_clk	= "uart1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART1_SHIFT,
+		},
+	},
+	.class		= &omap2_uart_class,
+};
+
+/* UART2 */
+static struct omap_hwmod omap3xxx_uart2_hwmod = {
+	.name		= "uart2",
+	.mpu_irqs	= omap2_uart2_mpu_irqs,
+	.sdma_reqs	= omap2_uart2_sdma_reqs,
+	.main_clk	= "uart2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART2_SHIFT,
+		},
+	},
+	.class		= &omap2_uart_class,
+};
+
+/* UART3 */
+static struct omap_hwmod omap3xxx_uart3_hwmod = {
+	.name		= "uart3",
+	.mpu_irqs	= omap2_uart3_mpu_irqs,
+	.sdma_reqs	= omap2_uart3_sdma_reqs,
+	.main_clk	= "uart3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = OMAP3430_PER_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART3_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART3_SHIFT,
+		},
+	},
+	.class		= &omap2_uart_class,
+};
+
+/* UART4 */
+static struct omap_hwmod_irq_info uart4_mpu_irqs[] = {
+	{ .irq = INT_36XX_UART4_IRQ, },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info uart4_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP36XX_DMA_UART4_RX, },
+	{ .name = "tx",	.dma_req = OMAP36XX_DMA_UART4_TX, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap36xx_uart4_hwmod = {
+	.name		= "uart4",
+	.mpu_irqs	= uart4_mpu_irqs,
+	.sdma_reqs	= uart4_sdma_reqs,
+	.main_clk	= "uart4_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = OMAP3430_PER_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3630_EN_UART4_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3630_EN_UART4_SHIFT,
+		},
+	},
+	.class		= &omap2_uart_class,
+};
+
+static struct omap_hwmod_irq_info am35xx_uart4_mpu_irqs[] = {
+	{ .irq = INT_35XX_UART4_IRQ, },
+};
+
+static struct omap_hwmod_dma_info am35xx_uart4_sdma_reqs[] = {
+	{ .name = "rx", .dma_req = AM35XX_DMA_UART4_RX, },
+	{ .name = "tx", .dma_req = AM35XX_DMA_UART4_TX, },
+};
+
+static struct omap_hwmod am35xx_uart4_hwmod = {
+	.name		= "uart4",
+	.mpu_irqs	= am35xx_uart4_mpu_irqs,
+	.sdma_reqs	= am35xx_uart4_sdma_reqs,
+	.main_clk	= "uart4_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART4_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART4_SHIFT,
+		},
+	},
+	.class		= &omap2_uart_class,
+};
+
+static struct omap_hwmod_class i2c_class = {
+	.name	= "i2c",
+	.sysc	= &i2c_sysc,
+	.rev	= OMAP_I2C_IP_VERSION_1,
+	.reset	= &omap_i2c_reset,
+};
+
+static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = {
+	{ .name = "dispc", .dma_req = 5 },
+	{ .name = "dsi1", .dma_req = 74 },
+	{ .dma_req = -1 }
+};
+
+/* dss */
+static struct omap_hwmod_opt_clk dss_opt_clks[] = {
+	/*
+	 * The DSS HW needs all DSS clocks enabled during reset. The dss_core
+	 * driver does not use these clocks.
+	 */
+	{ .role = "sys_clk", .clk = "dss2_alwon_fck" },
+	{ .role = "tv_clk", .clk = "dss_tv_fck" },
+	/* required only on OMAP3430 */
+	{ .role = "tv_dac_clk", .clk = "dss_96m_fck" },
+};
+
+static struct omap_hwmod omap3430es1_dss_core_hwmod = {
+	.name		= "dss_core",
+	.class		= &omap2_dss_hwmod_class,
+	.main_clk	= "dss1_alwon_fck", /* instead of dss_fck */
+	.sdma_reqs	= omap3xxx_dss_sdma_chs,
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_DSS1_SHIFT,
+			.module_offs = OMAP3430_DSS_MOD,
+			.idlest_reg_id = 1,
+			.idlest_stdby_bit = OMAP3430ES1_ST_DSS_SHIFT,
+		},
+	},
+	.opt_clks	= dss_opt_clks,
+	.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
+	.flags		= HWMOD_NO_IDLEST | HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+};
+
+static struct omap_hwmod omap3xxx_dss_core_hwmod = {
+	.name		= "dss_core",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.class		= &omap2_dss_hwmod_class,
+	.main_clk	= "dss1_alwon_fck", /* instead of dss_fck */
+	.sdma_reqs	= omap3xxx_dss_sdma_chs,
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_DSS1_SHIFT,
+			.module_offs = OMAP3430_DSS_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT,
+			.idlest_stdby_bit = OMAP3430ES2_ST_DSS_STDBY_SHIFT,
+		},
+	},
+	.opt_clks	= dss_opt_clks,
+	.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
+};
+
+/*
+ * 'dispc' class
+ * display controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap3_dispc_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+			   SYSC_HAS_ENAWAKEUP),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3_dispc_hwmod_class = {
+	.name	= "dispc",
+	.sysc	= &omap3_dispc_sysc,
+};
+
+static struct omap_hwmod omap3xxx_dss_dispc_hwmod = {
+	.name		= "dss_dispc",
+	.class		= &omap3_dispc_hwmod_class,
+	.mpu_irqs	= omap2_dispc_irqs,
+	.main_clk	= "dss1_alwon_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_DSS1_SHIFT,
+			.module_offs = OMAP3430_DSS_MOD,
+		},
+	},
+	.flags		= HWMOD_NO_IDLEST,
+	.dev_attr	= &omap2_3_dss_dispc_dev_attr
+};
+
+/*
+ * 'dsi' class
+ * display serial interface controller
+ */
+
+static struct omap_hwmod_class omap3xxx_dsi_hwmod_class = {
+	.name = "dsi",
+};
+
+static struct omap_hwmod_irq_info omap3xxx_dsi1_irqs[] = {
+	{ .irq = 25 },
+	{ .irq = -1 }
+};
+
+/* dss_dsi1 */
+static struct omap_hwmod_opt_clk dss_dsi1_opt_clks[] = {
+	{ .role = "sys_clk", .clk = "dss2_alwon_fck" },
+};
+
+static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = {
+	.name		= "dss_dsi1",
+	.class		= &omap3xxx_dsi_hwmod_class,
+	.mpu_irqs	= omap3xxx_dsi1_irqs,
+	.main_clk	= "dss1_alwon_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_DSS1_SHIFT,
+			.module_offs = OMAP3430_DSS_MOD,
+		},
+	},
+	.opt_clks	= dss_dsi1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dss_dsi1_opt_clks),
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
+	{ .role = "ick", .clk = "dss_ick" },
+};
+
+static struct omap_hwmod omap3xxx_dss_rfbi_hwmod = {
+	.name		= "dss_rfbi",
+	.class		= &omap2_rfbi_hwmod_class,
+	.main_clk	= "dss1_alwon_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_DSS1_SHIFT,
+			.module_offs = OMAP3430_DSS_MOD,
+		},
+	},
+	.opt_clks	= dss_rfbi_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dss_rfbi_opt_clks),
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+static struct omap_hwmod_opt_clk dss_venc_opt_clks[] = {
+	/* required only on OMAP3430 */
+	{ .role = "tv_dac_clk", .clk = "dss_96m_fck" },
+};
+
+static struct omap_hwmod omap3xxx_dss_venc_hwmod = {
+	.name		= "dss_venc",
+	.class		= &omap2_venc_hwmod_class,
+	.main_clk	= "dss_tv_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_DSS1_SHIFT,
+			.module_offs = OMAP3430_DSS_MOD,
+		},
+	},
+	.opt_clks	= dss_venc_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dss_venc_opt_clks),
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/* I2C1 */
+static struct omap_i2c_dev_attr i2c1_dev_attr = {
+	.fifo_depth	= 8, /* bytes */
+	.flags		= OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
+			  OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
+			  OMAP_I2C_FLAG_BUS_SHIFT_2,
+};
+
+static struct omap_hwmod omap3xxx_i2c1_hwmod = {
+	.name		= "i2c1",
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.mpu_irqs	= omap2_i2c1_mpu_irqs,
+	.sdma_reqs	= omap2_i2c1_sdma_reqs,
+	.main_clk	= "i2c1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_I2C1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_I2C1_SHIFT,
+		},
+	},
+	.class		= &i2c_class,
+	.dev_attr	= &i2c1_dev_attr,
+};
+
+/* I2C2 */
+static struct omap_i2c_dev_attr i2c2_dev_attr = {
+	.fifo_depth	= 8, /* bytes */
+	.flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
+		 OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
+		 OMAP_I2C_FLAG_BUS_SHIFT_2,
+};
+
+static struct omap_hwmod omap3xxx_i2c2_hwmod = {
+	.name		= "i2c2",
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.mpu_irqs	= omap2_i2c2_mpu_irqs,
+	.sdma_reqs	= omap2_i2c2_sdma_reqs,
+	.main_clk	= "i2c2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_I2C2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_I2C2_SHIFT,
+		},
+	},
+	.class		= &i2c_class,
+	.dev_attr	= &i2c2_dev_attr,
+};
+
+/* I2C3 */
+static struct omap_i2c_dev_attr i2c3_dev_attr = {
+	.fifo_depth	= 64, /* bytes */
+	.flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
+		 OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
+		 OMAP_I2C_FLAG_BUS_SHIFT_2,
+};
+
+static struct omap_hwmod_irq_info i2c3_mpu_irqs[] = {
+	{ .irq = INT_34XX_I2C3_IRQ, },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info i2c3_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = OMAP34XX_DMA_I2C3_TX },
+	{ .name = "rx", .dma_req = OMAP34XX_DMA_I2C3_RX },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap3xxx_i2c3_hwmod = {
+	.name		= "i2c3",
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.mpu_irqs	= i2c3_mpu_irqs,
+	.sdma_reqs	= i2c3_sdma_reqs,
+	.main_clk	= "i2c3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_I2C3_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_I2C3_SHIFT,
+		},
+	},
+	.class		= &i2c_class,
+	.dev_attr	= &i2c3_dev_attr,
+};
+
+/*
+ * 'gpio' class
+ * general purpose io module
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_gpio_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_gpio_hwmod_class = {
+	.name = "gpio",
+	.sysc = &omap3xxx_gpio_sysc,
+	.rev = 1,
+};
+
+/* gpio_dev_attr */
+static struct omap_gpio_dev_attr gpio_dev_attr = {
+	.bank_width = 32,
+	.dbck_flag = true,
+};
+
+/* gpio1 */
+static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio1_dbck", },
+};
+
+static struct omap_hwmod omap3xxx_gpio1_hwmod = {
+	.name		= "gpio1",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap2_gpio1_irqs,
+	.main_clk	= "gpio1_ick",
+	.opt_clks	= gpio1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPIO1_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPIO1_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_gpio_hwmod_class,
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio2 */
+static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio2_dbck", },
+};
+
+static struct omap_hwmod omap3xxx_gpio2_hwmod = {
+	.name		= "gpio2",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap2_gpio2_irqs,
+	.main_clk	= "gpio2_ick",
+	.opt_clks	= gpio2_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPIO2_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPIO2_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_gpio_hwmod_class,
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio3 */
+static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio3_dbck", },
+};
+
+static struct omap_hwmod omap3xxx_gpio3_hwmod = {
+	.name		= "gpio3",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap2_gpio3_irqs,
+	.main_clk	= "gpio3_ick",
+	.opt_clks	= gpio3_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio3_opt_clks),
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPIO3_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPIO3_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_gpio_hwmod_class,
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio4 */
+static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio4_dbck", },
+};
+
+static struct omap_hwmod omap3xxx_gpio4_hwmod = {
+	.name		= "gpio4",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap2_gpio4_irqs,
+	.main_clk	= "gpio4_ick",
+	.opt_clks	= gpio4_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio4_opt_clks),
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPIO4_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPIO4_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_gpio_hwmod_class,
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio5 */
+static struct omap_hwmod_irq_info omap3xxx_gpio5_irqs[] = {
+	{ .irq = 33 }, /* INT_34XX_GPIO_BANK5 */
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio5_dbck", },
+};
+
+static struct omap_hwmod omap3xxx_gpio5_hwmod = {
+	.name		= "gpio5",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap3xxx_gpio5_irqs,
+	.main_clk	= "gpio5_ick",
+	.opt_clks	= gpio5_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio5_opt_clks),
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPIO5_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPIO5_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_gpio_hwmod_class,
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio6 */
+static struct omap_hwmod_irq_info omap3xxx_gpio6_irqs[] = {
+	{ .irq = 34 }, /* INT_34XX_GPIO_BANK6 */
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio6_dbck", },
+};
+
+static struct omap_hwmod omap3xxx_gpio6_hwmod = {
+	.name		= "gpio6",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap3xxx_gpio6_irqs,
+	.main_clk	= "gpio6_ick",
+	.opt_clks	= gpio6_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio6_opt_clks),
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_GPIO6_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_GPIO6_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_gpio_hwmod_class,
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* dma attributes */
+static struct omap_dma_dev_attr dma_dev_attr = {
+	.dev_caps  = RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY |
+				IS_CSSA_32 | IS_CDSA_32 | IS_RW_PRIORITY,
+	.lch_count = 32,
+};
+
+static struct omap_hwmod_class_sysconfig omap3xxx_dma_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x002c,
+	.syss_offs	= 0x0028,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_MIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_dma_hwmod_class = {
+	.name = "dma",
+	.sysc = &omap3xxx_dma_sysc,
+};
+
+/* dma_system */
+static struct omap_hwmod omap3xxx_dma_system_hwmod = {
+	.name		= "dma",
+	.class		= &omap3xxx_dma_hwmod_class,
+	.mpu_irqs	= omap2_dma_system_irqs,
+	.main_clk	= "core_l3_ick",
+	.prcm = {
+		.omap2 = {
+			.module_offs		= CORE_MOD,
+			.prcm_reg_id		= 1,
+			.module_bit		= OMAP3430_ST_SDMA_SHIFT,
+			.idlest_reg_id		= 1,
+			.idlest_idle_bit	= OMAP3430_ST_SDMA_SHIFT,
+		},
+	},
+	.dev_attr	= &dma_dev_attr,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'mcbsp' class
+ * multi channel buffered serial port controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_mcbsp_sysc = {
+	.sysc_offs	= 0x008c,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_ENAWAKEUP |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+	.clockact	= 0x2,
+};
+
+static struct omap_hwmod_class omap3xxx_mcbsp_hwmod_class = {
+	.name = "mcbsp",
+	.sysc = &omap3xxx_mcbsp_sysc,
+	.rev  = MCBSP_CONFIG_TYPE3,
+};
+
+/* mcbsp1 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp1_irqs[] = {
+	{ .name = "common", .irq = 16 },
+	{ .name = "tx", .irq = 59 },
+	{ .name = "rx", .irq = 60 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap3xxx_mcbsp1_hwmod = {
+	.name		= "mcbsp1",
+	.class		= &omap3xxx_mcbsp_hwmod_class,
+	.mpu_irqs	= omap3xxx_mcbsp1_irqs,
+	.sdma_reqs	= omap2_mcbsp1_sdma_reqs,
+	.main_clk	= "mcbsp1_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCBSP1_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCBSP1_SHIFT,
+		},
+	},
+};
+
+/* mcbsp2 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp2_irqs[] = {
+	{ .name = "common", .irq = 17 },
+	{ .name = "tx", .irq = 62 },
+	{ .name = "rx", .irq = 63 },
+	{ .irq = -1 }
+};
+
+static struct omap_mcbsp_dev_attr omap34xx_mcbsp2_dev_attr = {
+	.sidetone	= "mcbsp2_sidetone",
+};
+
+static struct omap_hwmod omap3xxx_mcbsp2_hwmod = {
+	.name		= "mcbsp2",
+	.class		= &omap3xxx_mcbsp_hwmod_class,
+	.mpu_irqs	= omap3xxx_mcbsp2_irqs,
+	.sdma_reqs	= omap2_mcbsp2_sdma_reqs,
+	.main_clk	= "mcbsp2_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCBSP2_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCBSP2_SHIFT,
+		},
+	},
+	.dev_attr	= &omap34xx_mcbsp2_dev_attr,
+};
+
+/* mcbsp3 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp3_irqs[] = {
+	{ .name = "common", .irq = 22 },
+	{ .name = "tx", .irq = 89 },
+	{ .name = "rx", .irq = 90 },
+	{ .irq = -1 }
+};
+
+static struct omap_mcbsp_dev_attr omap34xx_mcbsp3_dev_attr = {
+	.sidetone	= "mcbsp3_sidetone",
+};
+
+static struct omap_hwmod omap3xxx_mcbsp3_hwmod = {
+	.name		= "mcbsp3",
+	.class		= &omap3xxx_mcbsp_hwmod_class,
+	.mpu_irqs	= omap3xxx_mcbsp3_irqs,
+	.sdma_reqs	= omap2_mcbsp3_sdma_reqs,
+	.main_clk	= "mcbsp3_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCBSP3_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCBSP3_SHIFT,
+		},
+	},
+	.dev_attr	= &omap34xx_mcbsp3_dev_attr,
+};
+
+/* mcbsp4 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp4_irqs[] = {
+	{ .name = "common", .irq = 23 },
+	{ .name = "tx", .irq = 54 },
+	{ .name = "rx", .irq = 55 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap3xxx_mcbsp4_sdma_chs[] = {
+	{ .name = "rx", .dma_req = 20 },
+	{ .name = "tx", .dma_req = 19 },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap3xxx_mcbsp4_hwmod = {
+	.name		= "mcbsp4",
+	.class		= &omap3xxx_mcbsp_hwmod_class,
+	.mpu_irqs	= omap3xxx_mcbsp4_irqs,
+	.sdma_reqs	= omap3xxx_mcbsp4_sdma_chs,
+	.main_clk	= "mcbsp4_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCBSP4_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCBSP4_SHIFT,
+		},
+	},
+};
+
+/* mcbsp5 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp5_irqs[] = {
+	{ .name = "common", .irq = 27 },
+	{ .name = "tx", .irq = 81 },
+	{ .name = "rx", .irq = 82 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap3xxx_mcbsp5_sdma_chs[] = {
+	{ .name = "rx", .dma_req = 22 },
+	{ .name = "tx", .dma_req = 21 },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap3xxx_mcbsp5_hwmod = {
+	.name		= "mcbsp5",
+	.class		= &omap3xxx_mcbsp_hwmod_class,
+	.mpu_irqs	= omap3xxx_mcbsp5_irqs,
+	.sdma_reqs	= omap3xxx_mcbsp5_sdma_chs,
+	.main_clk	= "mcbsp5_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCBSP5_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCBSP5_SHIFT,
+		},
+	},
+};
+
+/* 'mcbsp sidetone' class */
+static struct omap_hwmod_class_sysconfig omap3xxx_mcbsp_sidetone_sysc = {
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= SYSC_HAS_AUTOIDLE,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_mcbsp_sidetone_hwmod_class = {
+	.name = "mcbsp_sidetone",
+	.sysc = &omap3xxx_mcbsp_sidetone_sysc,
+};
+
+/* mcbsp2_sidetone */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp2_sidetone_irqs[] = {
+	{ .name = "irq", .irq = 4 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod = {
+	.name		= "mcbsp2_sidetone",
+	.class		= &omap3xxx_mcbsp_sidetone_hwmod_class,
+	.mpu_irqs	= omap3xxx_mcbsp2_sidetone_irqs,
+	.main_clk	= "mcbsp2_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			 .module_bit = OMAP3430_EN_MCBSP2_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCBSP2_SHIFT,
+		},
+	},
+};
+
+/* mcbsp3_sidetone */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp3_sidetone_irqs[] = {
+	{ .name = "irq", .irq = 5 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod = {
+	.name		= "mcbsp3_sidetone",
+	.class		= &omap3xxx_mcbsp_sidetone_hwmod_class,
+	.mpu_irqs	= omap3xxx_mcbsp3_sidetone_irqs,
+	.main_clk	= "mcbsp3_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCBSP3_SHIFT,
+			.module_offs = OMAP3430_PER_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCBSP3_SHIFT,
+		},
+	},
+};
+
+/* SR common */
+static struct omap_hwmod_sysc_fields omap34xx_sr_sysc_fields = {
+	.clkact_shift	= 20,
+};
+
+static struct omap_hwmod_class_sysconfig omap34xx_sr_sysc = {
+	.sysc_offs	= 0x24,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_NO_CACHE),
+	.clockact	= CLOCKACT_TEST_ICLK,
+	.sysc_fields	= &omap34xx_sr_sysc_fields,
+};
+
+static struct omap_hwmod_class omap34xx_smartreflex_hwmod_class = {
+	.name = "smartreflex",
+	.sysc = &omap34xx_sr_sysc,
+	.rev  = 1,
+};
+
+static struct omap_hwmod_sysc_fields omap36xx_sr_sysc_fields = {
+	.sidle_shift	= 24,
+	.enwkup_shift	= 26,
+};
+
+static struct omap_hwmod_class_sysconfig omap36xx_sr_sysc = {
+	.sysc_offs	= 0x38,
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
+			SYSC_NO_CACHE),
+	.sysc_fields	= &omap36xx_sr_sysc_fields,
+};
+
+static struct omap_hwmod_class omap36xx_smartreflex_hwmod_class = {
+	.name = "smartreflex",
+	.sysc = &omap36xx_sr_sysc,
+	.rev  = 2,
+};
+
+/* SR1 */
+static struct omap_smartreflex_dev_attr sr1_dev_attr = {
+	.sensor_voltdm_name   = "mpu_iva",
+};
+
+static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
+	{ .irq = 18 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap34xx_sr1_hwmod = {
+	.name		= "sr1",
+	.class		= &omap34xx_smartreflex_hwmod_class,
+	.main_clk	= "sr1_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SR1_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_SR1_SHIFT,
+		},
+	},
+	.dev_attr	= &sr1_dev_attr,
+	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
+	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
+};
+
+static struct omap_hwmod omap36xx_sr1_hwmod = {
+	.name		= "sr1",
+	.class		= &omap36xx_smartreflex_hwmod_class,
+	.main_clk	= "sr1_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SR1_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_SR1_SHIFT,
+		},
+	},
+	.dev_attr	= &sr1_dev_attr,
+	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
+};
+
+/* SR2 */
+static struct omap_smartreflex_dev_attr sr2_dev_attr = {
+	.sensor_voltdm_name	= "core",
+};
+
+static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
+	{ .irq = 19 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap34xx_sr2_hwmod = {
+	.name		= "sr2",
+	.class		= &omap34xx_smartreflex_hwmod_class,
+	.main_clk	= "sr2_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SR2_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_SR2_SHIFT,
+		},
+	},
+	.dev_attr	= &sr2_dev_attr,
+	.mpu_irqs	= omap3_smartreflex_core_irqs,
+	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
+};
+
+static struct omap_hwmod omap36xx_sr2_hwmod = {
+	.name		= "sr2",
+	.class		= &omap36xx_smartreflex_hwmod_class,
+	.main_clk	= "sr2_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SR2_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_SR2_SHIFT,
+		},
+	},
+	.dev_attr	= &sr2_dev_attr,
+	.mpu_irqs	= omap3_smartreflex_core_irqs,
+};
+
+/*
+ * 'mailbox' class
+ * mailbox module allowing communication between the on-chip processors
+ * using a queued mailbox-interrupt mechanism.
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_mailbox_sysc = {
+	.rev_offs	= 0x000,
+	.sysc_offs	= 0x010,
+	.syss_offs	= 0x014,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+				SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_mailbox_hwmod_class = {
+	.name = "mailbox",
+	.sysc = &omap3xxx_mailbox_sysc,
+};
+
+static struct omap_hwmod_irq_info omap3xxx_mailbox_irqs[] = {
+	{ .irq = 26 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap3xxx_mailbox_hwmod = {
+	.name		= "mailbox",
+	.class		= &omap3xxx_mailbox_hwmod_class,
+	.mpu_irqs	= omap3xxx_mailbox_irqs,
+	.main_clk	= "mailboxes_ick",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MAILBOXES_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MAILBOXES_SHIFT,
+		},
+	},
+};
+
+/*
+ * 'mcspi' class
+ * multichannel serial port interface (mcspi) / master/slave synchronous serial
+ * bus
+ */
+
+static struct omap_hwmod_class_sysconfig omap34xx_mcspi_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+				SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+				SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap34xx_mcspi_class = {
+	.name = "mcspi",
+	.sysc = &omap34xx_mcspi_sysc,
+	.rev = OMAP3_MCSPI_REV,
+};
+
+/* mcspi1 */
+static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
+	.num_chipselect = 4,
+};
+
+static struct omap_hwmod omap34xx_mcspi1 = {
+	.name		= "mcspi1",
+	.mpu_irqs	= omap2_mcspi1_mpu_irqs,
+	.sdma_reqs	= omap2_mcspi1_sdma_reqs,
+	.main_clk	= "mcspi1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCSPI1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCSPI1_SHIFT,
+		},
+	},
+	.class		= &omap34xx_mcspi_class,
+	.dev_attr       = &omap_mcspi1_dev_attr,
+};
+
+/* mcspi2 */
+static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
+	.num_chipselect = 2,
+};
+
+static struct omap_hwmod omap34xx_mcspi2 = {
+	.name		= "mcspi2",
+	.mpu_irqs	= omap2_mcspi2_mpu_irqs,
+	.sdma_reqs	= omap2_mcspi2_sdma_reqs,
+	.main_clk	= "mcspi2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCSPI2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCSPI2_SHIFT,
+		},
+	},
+	.class		= &omap34xx_mcspi_class,
+	.dev_attr       = &omap_mcspi2_dev_attr,
+};
+
+/* mcspi3 */
+static struct omap_hwmod_irq_info omap34xx_mcspi3_mpu_irqs[] = {
+	{ .name = "irq", .irq = 91 }, /* 91 */
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap34xx_mcspi3_sdma_reqs[] = {
+	{ .name = "tx0", .dma_req = 15 },
+	{ .name = "rx0", .dma_req = 16 },
+	{ .name = "tx1", .dma_req = 23 },
+	{ .name = "rx1", .dma_req = 24 },
+	{ .dma_req = -1 }
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi3_dev_attr = {
+	.num_chipselect = 2,
+};
+
+static struct omap_hwmod omap34xx_mcspi3 = {
+	.name		= "mcspi3",
+	.mpu_irqs	= omap34xx_mcspi3_mpu_irqs,
+	.sdma_reqs	= omap34xx_mcspi3_sdma_reqs,
+	.main_clk	= "mcspi3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCSPI3_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCSPI3_SHIFT,
+		},
+	},
+	.class		= &omap34xx_mcspi_class,
+	.dev_attr       = &omap_mcspi3_dev_attr,
+};
+
+/* mcspi4 */
+static struct omap_hwmod_irq_info omap34xx_mcspi4_mpu_irqs[] = {
+	{ .name = "irq", .irq = INT_34XX_SPI4_IRQ }, /* 48 */
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap34xx_mcspi4_sdma_reqs[] = {
+	{ .name = "tx0", .dma_req = 70 }, /* DMA_SPI4_TX0 */
+	{ .name = "rx0", .dma_req = 71 }, /* DMA_SPI4_RX0 */
+	{ .dma_req = -1 }
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi4_dev_attr = {
+	.num_chipselect = 1,
+};
+
+static struct omap_hwmod omap34xx_mcspi4 = {
+	.name		= "mcspi4",
+	.mpu_irqs	= omap34xx_mcspi4_mpu_irqs,
+	.sdma_reqs	= omap34xx_mcspi4_sdma_reqs,
+	.main_clk	= "mcspi4_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MCSPI4_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MCSPI4_SHIFT,
+		},
+	},
+	.class		= &omap34xx_mcspi_class,
+	.dev_attr       = &omap_mcspi4_dev_attr,
+};
+
+/* usbhsotg */
+static struct omap_hwmod_class_sysconfig omap3xxx_usbhsotg_sysc = {
+	.rev_offs	= 0x0400,
+	.sysc_offs	= 0x0404,
+	.syss_offs	= 0x0408,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE|
+			  SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			  SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			  MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class usbotg_class = {
+	.name = "usbotg",
+	.sysc = &omap3xxx_usbhsotg_sysc,
+};
+
+/* usb_otg_hs */
+static struct omap_hwmod_irq_info omap3xxx_usbhsotg_mpu_irqs[] = {
+
+	{ .name = "mc", .irq = 92 },
+	{ .name = "dma", .irq = 93 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap3xxx_usbhsotg_hwmod = {
+	.name		= "usb_otg_hs",
+	.mpu_irqs	= omap3xxx_usbhsotg_mpu_irqs,
+	.main_clk	= "hsotgusb_ick",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
+			.module_offs = CORE_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT,
+			.idlest_stdby_bit = OMAP3430ES2_ST_HSOTGUSB_STDBY_SHIFT
+		},
+	},
+	.class		= &usbotg_class,
+
+	/*
+	 * Erratum ID: i479  idle_req / idle_ack mechanism potentially
+	 * broken when autoidle is enabled
+	 * workaround is to disable the autoidle bit at module level.
+	 */
+	.flags		= HWMOD_NO_OCP_AUTOIDLE | HWMOD_SWSUP_SIDLE
+				| HWMOD_SWSUP_MSTANDBY,
+};
+
+/* usb_otg_hs */
+static struct omap_hwmod_irq_info am35xx_usbhsotg_mpu_irqs[] = {
+
+	{ .name = "mc", .irq = 71 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_class am35xx_usbotg_class = {
+	.name = "am35xx_usbotg",
+	.sysc = NULL,
+};
+
+static struct omap_hwmod am35xx_usbhsotg_hwmod = {
+	.name		= "am35x_otg_hs",
+	.mpu_irqs	= am35xx_usbhsotg_mpu_irqs,
+	.main_clk	= NULL,
+	.prcm = {
+		.omap2 = {
+		},
+	},
+	.class		= &am35xx_usbotg_class,
+};
+
+/* MMC/SD/SDIO common */
+static struct omap_hwmod_class_sysconfig omap34xx_mmc_sysc = {
+	.rev_offs	= 0x1fc,
+	.sysc_offs	= 0x10,
+	.syss_offs	= 0x14,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap34xx_mmc_class = {
+	.name = "mmc",
+	.sysc = &omap34xx_mmc_sysc,
+};
+
+/* MMC/SD/SDIO1 */
+
+static struct omap_hwmod_irq_info omap34xx_mmc1_mpu_irqs[] = {
+	{ .irq = 83, },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap34xx_mmc1_sdma_reqs[] = {
+	{ .name = "tx",	.dma_req = 61, },
+	{ .name = "rx",	.dma_req = 62, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk omap34xx_mmc1_opt_clks[] = {
+	{ .role = "dbck", .clk = "omap_32k_fck", },
+};
+
+static struct omap_mmc_dev_attr mmc1_dev_attr = {
+	.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+/* See 35xx errata 2.1.1.128 in SPRZ278F */
+static struct omap_mmc_dev_attr mmc1_pre_es3_dev_attr = {
+	.flags = (OMAP_HSMMC_SUPPORTS_DUAL_VOLT |
+		  OMAP_HSMMC_BROKEN_MULTIBLOCK_READ),
+};
+
+static struct omap_hwmod omap3xxx_pre_es3_mmc1_hwmod = {
+	.name		= "mmc1",
+	.mpu_irqs	= omap34xx_mmc1_mpu_irqs,
+	.sdma_reqs	= omap34xx_mmc1_sdma_reqs,
+	.opt_clks	= omap34xx_mmc1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc1_opt_clks),
+	.main_clk	= "mmchs1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MMC1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MMC1_SHIFT,
+		},
+	},
+	.dev_attr	= &mmc1_pre_es3_dev_attr,
+	.class		= &omap34xx_mmc_class,
+};
+
+static struct omap_hwmod omap3xxx_es3plus_mmc1_hwmod = {
+	.name		= "mmc1",
+	.mpu_irqs	= omap34xx_mmc1_mpu_irqs,
+	.sdma_reqs	= omap34xx_mmc1_sdma_reqs,
+	.opt_clks	= omap34xx_mmc1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc1_opt_clks),
+	.main_clk	= "mmchs1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MMC1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MMC1_SHIFT,
+		},
+	},
+	.dev_attr	= &mmc1_dev_attr,
+	.class		= &omap34xx_mmc_class,
+};
+
+/* MMC/SD/SDIO2 */
+
+static struct omap_hwmod_irq_info omap34xx_mmc2_mpu_irqs[] = {
+	{ .irq = INT_24XX_MMC2_IRQ, },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap34xx_mmc2_sdma_reqs[] = {
+	{ .name = "tx",	.dma_req = 47, },
+	{ .name = "rx",	.dma_req = 48, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk omap34xx_mmc2_opt_clks[] = {
+	{ .role = "dbck", .clk = "omap_32k_fck", },
+};
+
+/* See 35xx errata 2.1.1.128 in SPRZ278F */
+static struct omap_mmc_dev_attr mmc2_pre_es3_dev_attr = {
+	.flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
+};
+
+static struct omap_hwmod omap3xxx_pre_es3_mmc2_hwmod = {
+	.name		= "mmc2",
+	.mpu_irqs	= omap34xx_mmc2_mpu_irqs,
+	.sdma_reqs	= omap34xx_mmc2_sdma_reqs,
+	.opt_clks	= omap34xx_mmc2_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc2_opt_clks),
+	.main_clk	= "mmchs2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MMC2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MMC2_SHIFT,
+		},
+	},
+	.dev_attr	= &mmc2_pre_es3_dev_attr,
+	.class		= &omap34xx_mmc_class,
+};
+
+static struct omap_hwmod omap3xxx_es3plus_mmc2_hwmod = {
+	.name		= "mmc2",
+	.mpu_irqs	= omap34xx_mmc2_mpu_irqs,
+	.sdma_reqs	= omap34xx_mmc2_sdma_reqs,
+	.opt_clks	= omap34xx_mmc2_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc2_opt_clks),
+	.main_clk	= "mmchs2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MMC2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MMC2_SHIFT,
+		},
+	},
+	.class		= &omap34xx_mmc_class,
+};
+
+/* MMC/SD/SDIO3 */
+
+static struct omap_hwmod_irq_info omap34xx_mmc3_mpu_irqs[] = {
+	{ .irq = 94, },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap34xx_mmc3_sdma_reqs[] = {
+	{ .name = "tx",	.dma_req = 77, },
+	{ .name = "rx",	.dma_req = 78, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk omap34xx_mmc3_opt_clks[] = {
+	{ .role = "dbck", .clk = "omap_32k_fck", },
+};
+
+static struct omap_hwmod omap3xxx_mmc3_hwmod = {
+	.name		= "mmc3",
+	.mpu_irqs	= omap34xx_mmc3_mpu_irqs,
+	.sdma_reqs	= omap34xx_mmc3_sdma_reqs,
+	.opt_clks	= omap34xx_mmc3_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc3_opt_clks),
+	.main_clk	= "mmchs3_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_MMC3_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_MMC3_SHIFT,
+		},
+	},
+	.class		= &omap34xx_mmc_class,
+};
+
+/*
+ * 'usb_host_hs' class
+ * high-speed multi-port usb host controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_usb_host_hs_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
+			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_usb_host_hs_hwmod_class = {
+	.name = "usb_host_hs",
+	.sysc = &omap3xxx_usb_host_hs_sysc,
+};
+
+static struct omap_hwmod_opt_clk omap3xxx_usb_host_hs_opt_clks[] = {
+	  { .role = "ehci_logic_fck", .clk = "usbhost_120m_fck", },
+};
+
+static struct omap_hwmod_irq_info omap3xxx_usb_host_hs_irqs[] = {
+	{ .name = "ohci-irq", .irq = 76 },
+	{ .name = "ehci-irq", .irq = 77 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap3xxx_usb_host_hs_hwmod = {
+	.name		= "usb_host_hs",
+	.class		= &omap3xxx_usb_host_hs_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.mpu_irqs	= omap3xxx_usb_host_hs_irqs,
+	.main_clk	= "usbhost_48m_fck",
+	.prcm = {
+		.omap2 = {
+			.module_offs = OMAP3430ES2_USBHOST_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430ES2_EN_USBHOST1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430ES2_ST_USBHOST_IDLE_SHIFT,
+			.idlest_stdby_bit = OMAP3430ES2_ST_USBHOST_STDBY_SHIFT,
+		},
+	},
+	.opt_clks	= omap3xxx_usb_host_hs_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(omap3xxx_usb_host_hs_opt_clks),
+
+	/*
+	 * Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
+	 * id: i660
+	 *
+	 * Description:
+	 * In the following configuration :
+	 * - USBHOST module is set to smart-idle mode
+	 * - PRCM asserts idle_req to the USBHOST module ( This typically
+	 *   happens when the system is going to a low power mode : all ports
+	 *   have been suspended, the master part of the USBHOST module has
+	 *   entered the standby state, and SW has cut the functional clocks)
+	 * - an USBHOST interrupt occurs before the module is able to answer
+	 *   idle_ack, typically a remote wakeup IRQ.
+	 * Then the USB HOST module will enter a deadlock situation where it
+	 * is no more accessible nor functional.
+	 *
+	 * Workaround:
+	 * Don't use smart idle; use only force idle, hence HWMOD_SWSUP_SIDLE
+	 */
+
+	/*
+	 * Errata: USB host EHCI may stall when entering smart-standby mode
+	 * Id: i571
+	 *
+	 * Description:
+	 * When the USBHOST module is set to smart-standby mode, and when it is
+	 * ready to enter the standby state (i.e. all ports are suspended and
+	 * all attached devices are in suspend mode), then it can wrongly assert
+	 * the Mstandby signal too early while there are still some residual OCP
+	 * transactions ongoing. If this condition occurs, the internal state
+	 * machine may go to an undefined state and the USB link may be stuck
+	 * upon the next resume.
+	 *
+	 * Workaround:
+	 * Don't use smart standby; use only force standby,
+	 * hence HWMOD_SWSUP_MSTANDBY
+	 */
+
+	/*
+	 * During system boot; If the hwmod framework resets the module
+	 * the module will have smart idle settings; which can lead to deadlock
+	 * (above Errata Id:i660); so, dont reset the module during boot;
+	 * Use HWMOD_INIT_NO_RESET.
+	 */
+
+	.flags		= HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
+			  HWMOD_INIT_NO_RESET,
+};
+
+/*
+ * 'usb_tll_hs' class
+ * usb_tll_hs module is the adapter on the usb_host_hs ports
+ */
+static struct omap_hwmod_class_sysconfig omap3xxx_usb_tll_hs_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_usb_tll_hs_hwmod_class = {
+	.name = "usb_tll_hs",
+	.sysc = &omap3xxx_usb_tll_hs_sysc,
+};
+
+static struct omap_hwmod_irq_info omap3xxx_usb_tll_hs_irqs[] = {
+	{ .name = "tll-irq", .irq = 78 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod = {
+	.name		= "usb_tll_hs",
+	.class		= &omap3xxx_usb_tll_hs_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.mpu_irqs	= omap3xxx_usb_tll_hs_irqs,
+	.main_clk	= "usbtll_fck",
+	.prcm = {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 3,
+			.module_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
+			.idlest_reg_id = 3,
+			.idlest_idle_bit = OMAP3430ES2_ST_USBTLL_SHIFT,
+		},
+	},
+};
+
+static struct omap_hwmod omap3xxx_hdq1w_hwmod = {
+	.name		= "hdq1w",
+	.mpu_irqs	= omap2_hdq1w_mpu_irqs,
+	.main_clk	= "hdq_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_HDQ_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_HDQ_SHIFT,
+		},
+	},
+	.class		= &omap2_hdq1w_class,
+};
+
+/*
+ * '32K sync counter' class
+ * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock
+ */
+static struct omap_hwmod_class_sysconfig omap3xxx_counter_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0004,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE,
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_counter_hwmod_class = {
+	.name	= "counter",
+	.sysc	= &omap3xxx_counter_sysc,
+};
+
+static struct omap_hwmod omap3xxx_counter_32k_hwmod = {
+	.name		= "counter_32k",
+	.class		= &omap3xxx_counter_hwmod_class,
+	.clkdm_name	= "wkup_clkdm",
+	.flags		= HWMOD_SWSUP_SIDLE,
+	.main_clk	= "wkup_32k_fck",
+	.prcm		= {
+		.omap2	= {
+			.module_offs = WKUP_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_ST_32KSYNC_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_32KSYNC_SHIFT,
+		},
+	},
+};
+
+/*
+ * interfaces
+ */
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
@@ -102,18 +2049,11 @@
 	.user	= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* L3 taret configuration and error log registers */
-static struct omap_hwmod_irq_info omap3xxx_l3_main_irqs[] = {
-	{ .irq = INT_34XX_L3_DBG_IRQ },
-	{ .irq = INT_34XX_L3_APP_IRQ },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_l3_main_addrs[] = {
 	{
-		.pa_start       = 0x68000000,
-		.pa_end         = 0x6800ffff,
-		.flags          = ADDR_TYPE_RT,
+		.pa_start	= 0x68000000,
+		.pa_end		= 0x6800ffff,
+		.flags		= ADDR_TYPE_RT,
 	},
 	{ }
 };
@@ -126,12 +2066,13 @@
 	.user	= OCP_USER_MPU,
 };
 
-/* Slave interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l3_main_slaves[] = {
-	&omap3xxx_mpu__l3_main,
+/* DSS -> l3 */
+static struct omap_hwmod_ocp_if omap3430es1_dss__l3 = {
+	.master		= &omap3430es1_dss_core_hwmod,
+	.slave		= &omap3xxx_l3_main_hwmod,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* DSS -> l3 */
 static struct omap_hwmod_ocp_if omap3xxx_dss__l3 = {
 	.master		= &omap3xxx_dss_core_hwmod,
 	.slave		= &omap3xxx_l3_main_hwmod,
@@ -144,32 +2085,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* Master interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l3_main_masters[] = {
-	&omap3xxx_l3_main__l4_core,
-	&omap3xxx_l3_main__l4_per,
-};
-
-/* L3 */
-static struct omap_hwmod omap3xxx_l3_main_hwmod = {
-	.name		= "l3_main",
-	.class		= &l3_hwmod_class,
-	.mpu_irqs	= omap3xxx_l3_main_irqs,
-	.masters	= omap3xxx_l3_main_masters,
-	.masters_cnt	= ARRAY_SIZE(omap3xxx_l3_main_masters),
-	.slaves		= omap3xxx_l3_main_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_l3_main_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-static struct omap_hwmod omap3xxx_l4_wkup_hwmod;
-static struct omap_hwmod omap3xxx_uart1_hwmod;
-static struct omap_hwmod omap3xxx_uart2_hwmod;
-static struct omap_hwmod omap3xxx_uart3_hwmod;
-static struct omap_hwmod omap3xxx_uart4_hwmod;
-static struct omap_hwmod am35xx_uart4_hwmod;
-static struct omap_hwmod omap3xxx_usbhsotg_hwmod;
-
 /* l3_core -> usbhsotg interface */
 static struct omap_hwmod_ocp_if omap3xxx_usbhsotg__l3 = {
 	.master		= &omap3xxx_usbhsotg_hwmod,
@@ -193,9 +2108,18 @@
 };
 
 /* L4 CORE -> MMC1 interface */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmc1 = {
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__pre_es3_mmc1 = {
 	.master		= &omap3xxx_l4_core_hwmod,
-	.slave		= &omap3xxx_mmc1_hwmod,
+	.slave		= &omap3xxx_pre_es3_mmc1_hwmod,
+	.clk		= "mmchs1_ick",
+	.addr		= omap2430_mmc1_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+	.flags		= OMAP_FIREWALL_L4
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__es3plus_mmc1 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap3xxx_es3plus_mmc1_hwmod,
 	.clk		= "mmchs1_ick",
 	.addr		= omap2430_mmc1_addr_space,
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
@@ -203,9 +2127,18 @@
 };
 
 /* L4 CORE -> MMC2 interface */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmc2 = {
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__pre_es3_mmc2 = {
 	.master		= &omap3xxx_l4_core_hwmod,
-	.slave		= &omap3xxx_mmc2_hwmod,
+	.slave		= &omap3xxx_pre_es3_mmc2_hwmod,
+	.clk		= "mmchs2_ick",
+	.addr		= omap2430_mmc2_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+	.flags		= OMAP_FIREWALL_L4
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__es3plus_mmc2 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap3xxx_es3plus_mmc2_hwmod,
 	.clk		= "mmchs2_ick",
 	.addr		= omap2430_mmc2_addr_space,
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
@@ -286,7 +2219,7 @@
 };
 
 /* L4 PER -> UART4 interface */
-static struct omap_hwmod_addr_space omap3xxx_uart4_addr_space[] = {
+static struct omap_hwmod_addr_space omap36xx_uart4_addr_space[] = {
 	{
 		.pa_start	= OMAP3_UART4_BASE,
 		.pa_end		= OMAP3_UART4_BASE + SZ_1K - 1,
@@ -295,29 +2228,29 @@
 	{ }
 };
 
-static struct omap_hwmod_ocp_if omap3_l4_per__uart4 = {
+static struct omap_hwmod_ocp_if omap36xx_l4_per__uart4 = {
 	.master		= &omap3xxx_l4_per_hwmod,
-	.slave		= &omap3xxx_uart4_hwmod,
+	.slave		= &omap36xx_uart4_hwmod,
 	.clk		= "uart4_ick",
-	.addr		= omap3xxx_uart4_addr_space,
+	.addr		= omap36xx_uart4_addr_space,
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 /* AM35xx: L4 CORE -> UART4 interface */
 static struct omap_hwmod_addr_space am35xx_uart4_addr_space[] = {
 	{
-		.pa_start       = OMAP3_UART4_AM35XX_BASE,
-		.pa_end         = OMAP3_UART4_AM35XX_BASE + SZ_1K - 1,
-		.flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+		.pa_start	= OMAP3_UART4_AM35XX_BASE,
+		.pa_end		= OMAP3_UART4_AM35XX_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
 	},
 };
 
 static struct omap_hwmod_ocp_if am35xx_l4_core__uart4 = {
-	.master         = &omap3xxx_l4_core_hwmod,
-	.slave          = &am35xx_uart4_hwmod,
-	.clk            = "uart4_ick",
-	.addr           = am35xx_uart4_addr_space,
-	.user           = OCP_USER_MPU | OCP_USER_SDMA,
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &am35xx_uart4_hwmod,
+	.clk		= "uart4_ick",
+	.addr		= am35xx_uart4_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 /* L4 CORE -> I2C1 interface */
@@ -377,16 +2310,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
-	{ .irq = 18},
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
-	{ .irq = 19},
-	{ .irq = -1 }
-};
-
 /* L4 CORE -> SR1 interface */
 static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = {
 	{
@@ -397,7 +2320,7 @@
 	{ }
 };
 
-static struct omap_hwmod_ocp_if omap3_l4_core__sr1 = {
+static struct omap_hwmod_ocp_if omap34xx_l4_core__sr1 = {
 	.master		= &omap3xxx_l4_core_hwmod,
 	.slave		= &omap34xx_sr1_hwmod,
 	.clk		= "sr_l4_ick",
@@ -405,6 +2328,14 @@
 	.user		= OCP_USER_MPU,
 };
 
+static struct omap_hwmod_ocp_if omap36xx_l4_core__sr1 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap36xx_sr1_hwmod,
+	.clk		= "sr_l4_ick",
+	.addr		= omap3_sr1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
 /* L4 CORE -> SR1 interface */
 static struct omap_hwmod_addr_space omap3_sr2_addr_space[] = {
 	{
@@ -415,7 +2346,7 @@
 	{ }
 };
 
-static struct omap_hwmod_ocp_if omap3_l4_core__sr2 = {
+static struct omap_hwmod_ocp_if omap34xx_l4_core__sr2 = {
 	.master		= &omap3xxx_l4_core_hwmod,
 	.slave		= &omap34xx_sr2_hwmod,
 	.clk		= "sr_l4_ick",
@@ -423,9 +2354,13 @@
 	.user		= OCP_USER_MPU,
 };
 
-/*
-* usbhsotg interface data
-*/
+static struct omap_hwmod_ocp_if omap36xx_l4_core__sr2 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap36xx_sr2_hwmod,
+	.clk		= "sr_l4_ick",
+	.addr		= omap3_sr2_addr_space,
+	.user		= OCP_USER_MPU,
+};
 
 static struct omap_hwmod_addr_space omap3xxx_usbhsotg_addrs[] = {
 	{
@@ -445,14 +2380,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-static struct omap_hwmod_ocp_if *omap3xxx_usbhsotg_masters[] = {
-	&omap3xxx_usbhsotg__l3,
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_usbhsotg_slaves[] = {
-	&omap3xxx_l4_core__usbhsotg,
-};
-
 static struct omap_hwmod_addr_space am35xx_usbhsotg_addrs[] = {
 	{
 		.pa_start	= AM35XX_IPSS_USBOTGSS_BASE,
@@ -471,148 +2398,21 @@
 	.user		= OCP_USER_MPU,
 };
 
-static struct omap_hwmod_ocp_if *am35xx_usbhsotg_masters[] = {
-	&am35xx_usbhsotg__l3,
+/* L4_WKUP -> L4_SEC interface */
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__l4_sec = {
+	.master = &omap3xxx_l4_wkup_hwmod,
+	.slave	= &omap3xxx_l4_sec_hwmod,
+	.user	= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_ocp_if *am35xx_usbhsotg_slaves[] = {
-	&am35xx_l4_core__usbhsotg,
-};
-/* Slave interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
-	&omap3xxx_l3_main__l4_core,
-};
-
-/* L4 CORE */
-static struct omap_hwmod omap3xxx_l4_core_hwmod = {
-	.name		= "l4_core",
-	.class		= &l4_hwmod_class,
-	.slaves		= omap3xxx_l4_core_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_l4_core_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* Slave interfaces on the L4_PER interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l4_per_slaves[] = {
-	&omap3xxx_l3_main__l4_per,
-};
-
-/* L4 PER */
-static struct omap_hwmod omap3xxx_l4_per_hwmod = {
-	.name		= "l4_per",
-	.class		= &l4_hwmod_class,
-	.slaves		= omap3xxx_l4_per_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_l4_per_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* Slave interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_slaves[] = {
-	&omap3xxx_l4_core__l4_wkup,
-};
-
-/* L4 WKUP */
-static struct omap_hwmod omap3xxx_l4_wkup_hwmod = {
-	.name		= "l4_wkup",
-	.class		= &l4_hwmod_class,
-	.slaves		= omap3xxx_l4_wkup_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_l4_wkup_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* Master interfaces on the MPU device */
-static struct omap_hwmod_ocp_if *omap3xxx_mpu_masters[] = {
-	&omap3xxx_mpu__l3_main,
-};
-
-/* MPU */
-static struct omap_hwmod omap3xxx_mpu_hwmod = {
-	.name		= "mpu",
-	.class		= &mpu_hwmod_class,
-	.main_clk	= "arm_fck",
-	.masters	= omap3xxx_mpu_masters,
-	.masters_cnt	= ARRAY_SIZE(omap3xxx_mpu_masters),
-};
-
-/*
- * IVA2_2 interface data
- */
-
 /* IVA2 <- L3 interface */
 static struct omap_hwmod_ocp_if omap3xxx_l3__iva = {
 	.master		= &omap3xxx_l3_main_hwmod,
 	.slave		= &omap3xxx_iva_hwmod,
-	.clk		= "iva2_ck",
+	.clk		= "core_l3_ick",
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_ocp_if *omap3xxx_iva_masters[] = {
-	&omap3xxx_l3__iva,
-};
-
-/*
- * IVA2 (IVA2)
- */
-
-static struct omap_hwmod omap3xxx_iva_hwmod = {
-	.name		= "iva",
-	.class		= &iva_hwmod_class,
-	.masters	= omap3xxx_iva_masters,
-	.masters_cnt	= ARRAY_SIZE(omap3xxx_iva_masters),
-};
-
-/* timer class */
-static struct omap_hwmod_class_sysconfig omap3xxx_timer_1ms_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
-				SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
-				SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_timer_1ms_hwmod_class = {
-	.name = "timer",
-	.sysc = &omap3xxx_timer_1ms_sysc,
-	.rev = OMAP_TIMER_IP_VERSION_1,
-};
-
-static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
-			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
-	.name = "timer",
-	.sysc = &omap3xxx_timer_sysc,
-	.rev =  OMAP_TIMER_IP_VERSION_1,
-};
-
-/* secure timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_secure_dev_attr = {
-	.timer_capability       = OMAP_TIMER_SECURE,
-};
-
-/* always-on timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
-	.timer_capability       = OMAP_TIMER_ALWON,
-};
-
-/* pwm timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
-	.timer_capability       = OMAP_TIMER_HAS_PWM,
-};
-
-/* timer1 */
-static struct omap_hwmod omap3xxx_timer1_hwmod;
-
 static struct omap_hwmod_addr_space omap3xxx_timer1_addrs[] = {
 	{
 		.pa_start	= 0x48318000,
@@ -631,34 +2431,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer1 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer1_slaves[] = {
-	&omap3xxx_l4_wkup__timer1,
-};
-
-/* timer1 hwmod */
-static struct omap_hwmod omap3xxx_timer1_hwmod = {
-	.name		= "timer1",
-	.mpu_irqs	= omap2_timer1_mpu_irqs,
-	.main_clk	= "gpt1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT1_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT1_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap3xxx_timer1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer1_slaves),
-	.class		= &omap3xxx_timer_1ms_hwmod_class,
-};
-
-/* timer2 */
-static struct omap_hwmod omap3xxx_timer2_hwmod;
-
 static struct omap_hwmod_addr_space omap3xxx_timer2_addrs[] = {
 	{
 		.pa_start	= 0x49032000,
@@ -677,34 +2449,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer2 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer2_slaves[] = {
-	&omap3xxx_l4_per__timer2,
-};
-
-/* timer2 hwmod */
-static struct omap_hwmod omap3xxx_timer2_hwmod = {
-	.name		= "timer2",
-	.mpu_irqs	= omap2_timer2_mpu_irqs,
-	.main_clk	= "gpt2_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT2_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT2_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap3xxx_timer2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer2_slaves),
-	.class		= &omap3xxx_timer_1ms_hwmod_class,
-};
-
-/* timer3 */
-static struct omap_hwmod omap3xxx_timer3_hwmod;
-
 static struct omap_hwmod_addr_space omap3xxx_timer3_addrs[] = {
 	{
 		.pa_start	= 0x49034000,
@@ -723,34 +2467,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer3 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer3_slaves[] = {
-	&omap3xxx_l4_per__timer3,
-};
-
-/* timer3 hwmod */
-static struct omap_hwmod omap3xxx_timer3_hwmod = {
-	.name		= "timer3",
-	.mpu_irqs	= omap2_timer3_mpu_irqs,
-	.main_clk	= "gpt3_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT3_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT3_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap3xxx_timer3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer3_slaves),
-	.class		= &omap3xxx_timer_hwmod_class,
-};
-
-/* timer4 */
-static struct omap_hwmod omap3xxx_timer4_hwmod;
-
 static struct omap_hwmod_addr_space omap3xxx_timer4_addrs[] = {
 	{
 		.pa_start	= 0x49036000,
@@ -769,34 +2485,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer4 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer4_slaves[] = {
-	&omap3xxx_l4_per__timer4,
-};
-
-/* timer4 hwmod */
-static struct omap_hwmod omap3xxx_timer4_hwmod = {
-	.name		= "timer4",
-	.mpu_irqs	= omap2_timer4_mpu_irqs,
-	.main_clk	= "gpt4_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT4_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT4_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap3xxx_timer4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer4_slaves),
-	.class		= &omap3xxx_timer_hwmod_class,
-};
-
-/* timer5 */
-static struct omap_hwmod omap3xxx_timer5_hwmod;
-
 static struct omap_hwmod_addr_space omap3xxx_timer5_addrs[] = {
 	{
 		.pa_start	= 0x49038000,
@@ -815,34 +2503,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer5 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer5_slaves[] = {
-	&omap3xxx_l4_per__timer5,
-};
-
-/* timer5 hwmod */
-static struct omap_hwmod omap3xxx_timer5_hwmod = {
-	.name		= "timer5",
-	.mpu_irqs	= omap2_timer5_mpu_irqs,
-	.main_clk	= "gpt5_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT5_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT5_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap3xxx_timer5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer5_slaves),
-	.class		= &omap3xxx_timer_hwmod_class,
-};
-
-/* timer6 */
-static struct omap_hwmod omap3xxx_timer6_hwmod;
-
 static struct omap_hwmod_addr_space omap3xxx_timer6_addrs[] = {
 	{
 		.pa_start	= 0x4903A000,
@@ -861,34 +2521,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer6 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer6_slaves[] = {
-	&omap3xxx_l4_per__timer6,
-};
-
-/* timer6 hwmod */
-static struct omap_hwmod omap3xxx_timer6_hwmod = {
-	.name		= "timer6",
-	.mpu_irqs	= omap2_timer6_mpu_irqs,
-	.main_clk	= "gpt6_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT6_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT6_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap3xxx_timer6_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer6_slaves),
-	.class		= &omap3xxx_timer_hwmod_class,
-};
-
-/* timer7 */
-static struct omap_hwmod omap3xxx_timer7_hwmod;
-
 static struct omap_hwmod_addr_space omap3xxx_timer7_addrs[] = {
 	{
 		.pa_start	= 0x4903C000,
@@ -907,34 +2539,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer7 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer7_slaves[] = {
-	&omap3xxx_l4_per__timer7,
-};
-
-/* timer7 hwmod */
-static struct omap_hwmod omap3xxx_timer7_hwmod = {
-	.name		= "timer7",
-	.mpu_irqs	= omap2_timer7_mpu_irqs,
-	.main_clk	= "gpt7_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT7_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT7_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap3xxx_timer7_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer7_slaves),
-	.class		= &omap3xxx_timer_hwmod_class,
-};
-
-/* timer8 */
-static struct omap_hwmod omap3xxx_timer8_hwmod;
-
 static struct omap_hwmod_addr_space omap3xxx_timer8_addrs[] = {
 	{
 		.pa_start	= 0x4903E000,
@@ -953,34 +2557,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer8 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer8_slaves[] = {
-	&omap3xxx_l4_per__timer8,
-};
-
-/* timer8 hwmod */
-static struct omap_hwmod omap3xxx_timer8_hwmod = {
-	.name		= "timer8",
-	.mpu_irqs	= omap2_timer8_mpu_irqs,
-	.main_clk	= "gpt8_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT8_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT8_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap3xxx_timer8_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer8_slaves),
-	.class		= &omap3xxx_timer_hwmod_class,
-};
-
-/* timer9 */
-static struct omap_hwmod omap3xxx_timer9_hwmod;
-
 static struct omap_hwmod_addr_space omap3xxx_timer9_addrs[] = {
 	{
 		.pa_start	= 0x49040000,
@@ -999,34 +2575,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer9 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer9_slaves[] = {
-	&omap3xxx_l4_per__timer9,
-};
-
-/* timer9 hwmod */
-static struct omap_hwmod omap3xxx_timer9_hwmod = {
-	.name		= "timer9",
-	.mpu_irqs	= omap2_timer9_mpu_irqs,
-	.main_clk	= "gpt9_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT9_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT9_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap3xxx_timer9_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer9_slaves),
-	.class		= &omap3xxx_timer_hwmod_class,
-};
-
-/* timer10 */
-static struct omap_hwmod omap3xxx_timer10_hwmod;
-
 /* l4_core -> timer10 */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer10 = {
 	.master		= &omap3xxx_l4_core_hwmod,
@@ -1036,34 +2584,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer10 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer10_slaves[] = {
-	&omap3xxx_l4_core__timer10,
-};
-
-/* timer10 hwmod */
-static struct omap_hwmod omap3xxx_timer10_hwmod = {
-	.name		= "timer10",
-	.mpu_irqs	= omap2_timer10_mpu_irqs,
-	.main_clk	= "gpt10_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT10_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT10_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap3xxx_timer10_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer10_slaves),
-	.class		= &omap3xxx_timer_1ms_hwmod_class,
-};
-
-/* timer11 */
-static struct omap_hwmod omap3xxx_timer11_hwmod;
-
 /* l4_core -> timer11 */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer11 = {
 	.master		= &omap3xxx_l4_core_hwmod,
@@ -1073,38 +2593,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer11 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer11_slaves[] = {
-	&omap3xxx_l4_core__timer11,
-};
-
-/* timer11 hwmod */
-static struct omap_hwmod omap3xxx_timer11_hwmod = {
-	.name		= "timer11",
-	.mpu_irqs	= omap2_timer11_mpu_irqs,
-	.main_clk	= "gpt11_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT11_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT11_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap3xxx_timer11_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer11_slaves),
-	.class		= &omap3xxx_timer_hwmod_class,
-};
-
-/* timer12*/
-static struct omap_hwmod omap3xxx_timer12_hwmod;
-static struct omap_hwmod_irq_info omap3xxx_timer12_mpu_irqs[] = {
-	{ .irq = 95, },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_timer12_addrs[] = {
 	{
 		.pa_start	= 0x48304000,
@@ -1115,39 +2603,14 @@
 };
 
 /* l4_core -> timer12 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer12 = {
-	.master		= &omap3xxx_l4_core_hwmod,
+static struct omap_hwmod_ocp_if omap3xxx_l4_sec__timer12 = {
+	.master		= &omap3xxx_l4_sec_hwmod,
 	.slave		= &omap3xxx_timer12_hwmod,
 	.clk		= "gpt12_ick",
 	.addr		= omap3xxx_timer12_addrs,
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer12 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer12_slaves[] = {
-	&omap3xxx_l4_core__timer12,
-};
-
-/* timer12 hwmod */
-static struct omap_hwmod omap3xxx_timer12_hwmod = {
-	.name		= "timer12",
-	.mpu_irqs	= omap3xxx_timer12_mpu_irqs,
-	.main_clk	= "gpt12_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPT12_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPT12_SHIFT,
-		},
-	},
-	.dev_attr	= &capability_secure_dev_attr,
-	.slaves		= omap3xxx_timer12_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer12_slaves),
-	.class		= &omap3xxx_timer_hwmod_class,
-};
-
 /* l4_wkup -> wd_timer2 */
 static struct omap_hwmod_addr_space omap3xxx_wd_timer2_addrs[] = {
 	{
@@ -1166,233 +2629,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/*
- * 'wd_timer' class
- * 32-bit watchdog upward counter that generates a pulse on the reset pin on
- * overflow condition
- */
-
-static struct omap_hwmod_class_sysconfig omap3xxx_wd_timer_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
-			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
-			   SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-/* I2C common */
-static struct omap_hwmod_class_sysconfig i2c_sysc = {
-	.rev_offs	= 0x00,
-	.sysc_offs	= 0x20,
-	.syss_offs	= 0x10,
-	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
-			   SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.clockact	= CLOCKACT_TEST_ICLK,
-	.sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_wd_timer_hwmod_class = {
-	.name		= "wd_timer",
-	.sysc		= &omap3xxx_wd_timer_sysc,
-	.pre_shutdown	= &omap2_wd_timer_disable
-};
-
-/* wd_timer2 */
-static struct omap_hwmod_ocp_if *omap3xxx_wd_timer2_slaves[] = {
-	&omap3xxx_l4_wkup__wd_timer2,
-};
-
-static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
-	.name		= "wd_timer2",
-	.class		= &omap3xxx_wd_timer_hwmod_class,
-	.main_clk	= "wdt2_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_WDT2_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_WDT2_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_wd_timer2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_wd_timer2_slaves),
-	/*
-	 * XXX: Use software supervised mode, HW supervised smartidle seems to
-	 * block CORE power domain idle transitions. Maybe a HW bug in wdt2?
-	 */
-	.flags		= HWMOD_SWSUP_SIDLE,
-};
-
-/* UART1 */
-
-static struct omap_hwmod_ocp_if *omap3xxx_uart1_slaves[] = {
-	&omap3_l4_core__uart1,
-};
-
-static struct omap_hwmod omap3xxx_uart1_hwmod = {
-	.name		= "uart1",
-	.mpu_irqs	= omap2_uart1_mpu_irqs,
-	.sdma_reqs	= omap2_uart1_sdma_reqs,
-	.main_clk	= "uart1_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_UART1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_EN_UART1_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_uart1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart1_slaves),
-	.class		= &omap2_uart_class,
-};
-
-/* UART2 */
-
-static struct omap_hwmod_ocp_if *omap3xxx_uart2_slaves[] = {
-	&omap3_l4_core__uart2,
-};
-
-static struct omap_hwmod omap3xxx_uart2_hwmod = {
-	.name		= "uart2",
-	.mpu_irqs	= omap2_uart2_mpu_irqs,
-	.sdma_reqs	= omap2_uart2_sdma_reqs,
-	.main_clk	= "uart2_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_UART2_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_EN_UART2_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_uart2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart2_slaves),
-	.class		= &omap2_uart_class,
-};
-
-/* UART3 */
-
-static struct omap_hwmod_ocp_if *omap3xxx_uart3_slaves[] = {
-	&omap3_l4_per__uart3,
-};
-
-static struct omap_hwmod omap3xxx_uart3_hwmod = {
-	.name		= "uart3",
-	.mpu_irqs	= omap2_uart3_mpu_irqs,
-	.sdma_reqs	= omap2_uart3_sdma_reqs,
-	.main_clk	= "uart3_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = OMAP3430_PER_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_UART3_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_EN_UART3_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_uart3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart3_slaves),
-	.class		= &omap2_uart_class,
-};
-
-/* UART4 */
-
-static struct omap_hwmod_irq_info uart4_mpu_irqs[] = {
-	{ .irq = INT_36XX_UART4_IRQ, },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info uart4_sdma_reqs[] = {
-	{ .name = "rx",	.dma_req = OMAP36XX_DMA_UART4_RX, },
-	{ .name = "tx",	.dma_req = OMAP36XX_DMA_UART4_TX, },
-	{ .dma_req = -1 }
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_uart4_slaves[] = {
-	&omap3_l4_per__uart4,
-};
-
-static struct omap_hwmod omap3xxx_uart4_hwmod = {
-	.name		= "uart4",
-	.mpu_irqs	= uart4_mpu_irqs,
-	.sdma_reqs	= uart4_sdma_reqs,
-	.main_clk	= "uart4_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = OMAP3430_PER_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3630_EN_UART4_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3630_EN_UART4_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_uart4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart4_slaves),
-	.class		= &omap2_uart_class,
-};
-
-static struct omap_hwmod_irq_info am35xx_uart4_mpu_irqs[] = {
-	{ .irq = INT_35XX_UART4_IRQ, },
-};
-
-static struct omap_hwmod_dma_info am35xx_uart4_sdma_reqs[] = {
-	{ .name = "rx", .dma_req = AM35XX_DMA_UART4_RX, },
-	{ .name = "tx", .dma_req = AM35XX_DMA_UART4_TX, },
-};
-
-static struct omap_hwmod_ocp_if *am35xx_uart4_slaves[] = {
-	&am35xx_l4_core__uart4,
-};
-
-static struct omap_hwmod am35xx_uart4_hwmod = {
-	.name           = "uart4",
-	.mpu_irqs       = am35xx_uart4_mpu_irqs,
-	.sdma_reqs      = am35xx_uart4_sdma_reqs,
-	.main_clk       = "uart4_fck",
-	.prcm           = {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_UART4_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_EN_UART4_SHIFT,
-		},
-	},
-	.slaves         = am35xx_uart4_slaves,
-	.slaves_cnt     = ARRAY_SIZE(am35xx_uart4_slaves),
-	.class          = &omap2_uart_class,
-};
-
-
-static struct omap_hwmod_class i2c_class = {
-	.name	= "i2c",
-	.sysc	= &i2c_sysc,
-	.rev	= OMAP_I2C_IP_VERSION_1,
-	.reset	= &omap_i2c_reset,
-};
-
-static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = {
-	{ .name = "dispc", .dma_req = 5 },
-	{ .name = "dsi1", .dma_req = 74 },
-	{ .dma_req = -1 }
-};
-
-/* dss */
-/* dss master ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_masters[] = {
-	&omap3xxx_dss__l3,
-};
-
 /* l4_core -> dss */
 static struct omap_hwmod_ocp_if omap3430es1_l4_core__dss = {
 	.master		= &omap3xxx_l4_core_hwmod,
@@ -1424,95 +2660,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dss slave ports */
-static struct omap_hwmod_ocp_if *omap3430es1_dss_slaves[] = {
-	&omap3430es1_l4_core__dss,
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_dss_slaves[] = {
-	&omap3xxx_l4_core__dss,
-};
-
-static struct omap_hwmod_opt_clk dss_opt_clks[] = {
-	/*
-	 * The DSS HW needs all DSS clocks enabled during reset. The dss_core
-	 * driver does not use these clocks.
-	 */
-	{ .role = "sys_clk", .clk = "dss2_alwon_fck" },
-	{ .role = "tv_clk", .clk = "dss_tv_fck" },
-	/* required only on OMAP3430 */
-	{ .role = "tv_dac_clk", .clk = "dss_96m_fck" },
-};
-
-static struct omap_hwmod omap3430es1_dss_core_hwmod = {
-	.name		= "dss_core",
-	.class		= &omap2_dss_hwmod_class,
-	.main_clk	= "dss1_alwon_fck", /* instead of dss_fck */
-	.sdma_reqs	= omap3xxx_dss_sdma_chs,
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_DSS1_SHIFT,
-			.module_offs = OMAP3430_DSS_MOD,
-			.idlest_reg_id = 1,
-			.idlest_stdby_bit = OMAP3430ES1_ST_DSS_SHIFT,
-		},
-	},
-	.opt_clks	= dss_opt_clks,
-	.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
-	.slaves		= omap3430es1_dss_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3430es1_dss_slaves),
-	.masters	= omap3xxx_dss_masters,
-	.masters_cnt	= ARRAY_SIZE(omap3xxx_dss_masters),
-	.flags		= HWMOD_NO_IDLEST | HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-};
-
-static struct omap_hwmod omap3xxx_dss_core_hwmod = {
-	.name		= "dss_core",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.class		= &omap2_dss_hwmod_class,
-	.main_clk	= "dss1_alwon_fck", /* instead of dss_fck */
-	.sdma_reqs	= omap3xxx_dss_sdma_chs,
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_DSS1_SHIFT,
-			.module_offs = OMAP3430_DSS_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT,
-			.idlest_stdby_bit = OMAP3430ES2_ST_DSS_STDBY_SHIFT,
-		},
-	},
-	.opt_clks	= dss_opt_clks,
-	.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
-	.slaves		= omap3xxx_dss_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_dss_slaves),
-	.masters	= omap3xxx_dss_masters,
-	.masters_cnt	= ARRAY_SIZE(omap3xxx_dss_masters),
-};
-
-/*
- * 'dispc' class
- * display controller
- */
-
-static struct omap_hwmod_class_sysconfig omap3_dispc_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE |
-			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
-			   SYSC_HAS_ENAWAKEUP),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3_dispc_hwmod_class = {
-	.name	= "dispc",
-	.sysc	= &omap3_dispc_sysc,
-};
-
 /* l4_core -> dss_dispc */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_dispc = {
 	.master		= &omap3xxx_l4_core_hwmod,
@@ -1529,44 +2676,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dss_dispc slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_dispc_slaves[] = {
-	&omap3xxx_l4_core__dss_dispc,
-};
-
-static struct omap_hwmod omap3xxx_dss_dispc_hwmod = {
-	.name		= "dss_dispc",
-	.class		= &omap3_dispc_hwmod_class,
-	.mpu_irqs	= omap2_dispc_irqs,
-	.main_clk	= "dss1_alwon_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_DSS1_SHIFT,
-			.module_offs = OMAP3430_DSS_MOD,
-		},
-	},
-	.slaves		= omap3xxx_dss_dispc_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_dss_dispc_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-	.dev_attr	= &omap2_3_dss_dispc_dev_attr
-};
-
-/*
- * 'dsi' class
- * display serial interface controller
- */
-
-static struct omap_hwmod_class omap3xxx_dsi_hwmod_class = {
-	.name = "dsi",
-};
-
-static struct omap_hwmod_irq_info omap3xxx_dsi1_irqs[] = {
-	{ .irq = 25 },
-	{ .irq = -1 }
-};
-
-/* dss_dsi1 */
 static struct omap_hwmod_addr_space omap3xxx_dss_dsi1_addrs[] = {
 	{
 		.pa_start	= 0x4804FC00,
@@ -1592,34 +2701,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dss_dsi1 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_dsi1_slaves[] = {
-	&omap3xxx_l4_core__dss_dsi1,
-};
-
-static struct omap_hwmod_opt_clk dss_dsi1_opt_clks[] = {
-	{ .role = "sys_clk", .clk = "dss2_alwon_fck" },
-};
-
-static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = {
-	.name		= "dss_dsi1",
-	.class		= &omap3xxx_dsi_hwmod_class,
-	.mpu_irqs	= omap3xxx_dsi1_irqs,
-	.main_clk	= "dss1_alwon_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_DSS1_SHIFT,
-			.module_offs = OMAP3430_DSS_MOD,
-		},
-	},
-	.opt_clks	= dss_dsi1_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_dsi1_opt_clks),
-	.slaves		= omap3xxx_dss_dsi1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_dss_dsi1_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
 /* l4_core -> dss_rfbi */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_rfbi = {
 	.master		= &omap3xxx_l4_core_hwmod,
@@ -1636,33 +2717,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dss_rfbi slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_rfbi_slaves[] = {
-	&omap3xxx_l4_core__dss_rfbi,
-};
-
-static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
-	{ .role = "ick", .clk = "dss_ick" },
-};
-
-static struct omap_hwmod omap3xxx_dss_rfbi_hwmod = {
-	.name		= "dss_rfbi",
-	.class		= &omap2_rfbi_hwmod_class,
-	.main_clk	= "dss1_alwon_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_DSS1_SHIFT,
-			.module_offs = OMAP3430_DSS_MOD,
-		},
-	},
-	.opt_clks	= dss_rfbi_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_rfbi_opt_clks),
-	.slaves		= omap3xxx_dss_rfbi_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_dss_rfbi_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
 /* l4_core -> dss_venc */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_venc = {
 	.master		= &omap3xxx_l4_core_hwmod,
@@ -1676,150 +2730,10 @@
 			.flags	= OMAP_FIREWALL_L4,
 		}
 	},
+	.flags		= OCPIF_SWSUP_IDLE,
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dss_venc slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_venc_slaves[] = {
-	&omap3xxx_l4_core__dss_venc,
-};
-
-static struct omap_hwmod_opt_clk dss_venc_opt_clks[] = {
-	/* required only on OMAP3430 */
-	{ .role = "tv_dac_clk", .clk = "dss_96m_fck" },
-};
-
-static struct omap_hwmod omap3xxx_dss_venc_hwmod = {
-	.name		= "dss_venc",
-	.class		= &omap2_venc_hwmod_class,
-	.main_clk	= "dss_tv_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_DSS1_SHIFT,
-			.module_offs = OMAP3430_DSS_MOD,
-		},
-	},
-	.opt_clks	= dss_venc_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_venc_opt_clks),
-	.slaves		= omap3xxx_dss_venc_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_dss_venc_slaves),
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/* I2C1 */
-
-static struct omap_i2c_dev_attr i2c1_dev_attr = {
-	.fifo_depth	= 8, /* bytes */
-	.flags		= OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
-			  OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
-			  OMAP_I2C_FLAG_BUS_SHIFT_2,
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_i2c1_slaves[] = {
-	&omap3_l4_core__i2c1,
-};
-
-static struct omap_hwmod omap3xxx_i2c1_hwmod = {
-	.name		= "i2c1",
-	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-	.mpu_irqs	= omap2_i2c1_mpu_irqs,
-	.sdma_reqs	= omap2_i2c1_sdma_reqs,
-	.main_clk	= "i2c1_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_I2C1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_I2C1_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_i2c1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_i2c1_slaves),
-	.class		= &i2c_class,
-	.dev_attr	= &i2c1_dev_attr,
-};
-
-/* I2C2 */
-
-static struct omap_i2c_dev_attr i2c2_dev_attr = {
-	.fifo_depth	= 8, /* bytes */
-	.flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
-		 OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
-		 OMAP_I2C_FLAG_BUS_SHIFT_2,
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_i2c2_slaves[] = {
-	&omap3_l4_core__i2c2,
-};
-
-static struct omap_hwmod omap3xxx_i2c2_hwmod = {
-	.name		= "i2c2",
-	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-	.mpu_irqs	= omap2_i2c2_mpu_irqs,
-	.sdma_reqs	= omap2_i2c2_sdma_reqs,
-	.main_clk	= "i2c2_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_I2C2_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_I2C2_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_i2c2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_i2c2_slaves),
-	.class		= &i2c_class,
-	.dev_attr	= &i2c2_dev_attr,
-};
-
-/* I2C3 */
-
-static struct omap_i2c_dev_attr i2c3_dev_attr = {
-	.fifo_depth	= 64, /* bytes */
-	.flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
-		 OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
-		 OMAP_I2C_FLAG_BUS_SHIFT_2,
-};
-
-static struct omap_hwmod_irq_info i2c3_mpu_irqs[] = {
-	{ .irq = INT_34XX_I2C3_IRQ, },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info i2c3_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = OMAP34XX_DMA_I2C3_TX },
-	{ .name = "rx", .dma_req = OMAP34XX_DMA_I2C3_RX },
-	{ .dma_req = -1 }
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_i2c3_slaves[] = {
-	&omap3_l4_core__i2c3,
-};
-
-static struct omap_hwmod omap3xxx_i2c3_hwmod = {
-	.name		= "i2c3",
-	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-	.mpu_irqs	= i2c3_mpu_irqs,
-	.sdma_reqs	= i2c3_sdma_reqs,
-	.main_clk	= "i2c3_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_I2C3_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_I2C3_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_i2c3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_i2c3_slaves),
-	.class		= &i2c_class,
-	.dev_attr	= &i2c3_dev_attr,
-};
-
 /* l4_wkup -> gpio1 */
 static struct omap_hwmod_addr_space omap3xxx_gpio1_addrs[] = {
 	{
@@ -1922,230 +2836,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/*
- * 'gpio' class
- * general purpose io module
- */
-
-static struct omap_hwmod_class_sysconfig omap3xxx_gpio_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
-			   SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_gpio_hwmod_class = {
-	.name = "gpio",
-	.sysc = &omap3xxx_gpio_sysc,
-	.rev = 1,
-};
-
-/* gpio_dev_attr*/
-static struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width = 32,
-	.dbck_flag = true,
-};
-
-/* gpio1 */
-static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio1_dbck", },
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_gpio1_slaves[] = {
-	&omap3xxx_l4_wkup__gpio1,
-};
-
-static struct omap_hwmod omap3xxx_gpio1_hwmod = {
-	.name		= "gpio1",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio1_irqs,
-	.main_clk	= "gpio1_ick",
-	.opt_clks	= gpio1_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPIO1_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPIO1_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_gpio1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_gpio1_slaves),
-	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio2 */
-static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio2_dbck", },
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_gpio2_slaves[] = {
-	&omap3xxx_l4_per__gpio2,
-};
-
-static struct omap_hwmod omap3xxx_gpio2_hwmod = {
-	.name		= "gpio2",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio2_irqs,
-	.main_clk	= "gpio2_ick",
-	.opt_clks	= gpio2_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPIO2_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPIO2_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_gpio2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_gpio2_slaves),
-	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio3 */
-static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio3_dbck", },
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_gpio3_slaves[] = {
-	&omap3xxx_l4_per__gpio3,
-};
-
-static struct omap_hwmod omap3xxx_gpio3_hwmod = {
-	.name		= "gpio3",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio3_irqs,
-	.main_clk	= "gpio3_ick",
-	.opt_clks	= gpio3_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio3_opt_clks),
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPIO3_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPIO3_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_gpio3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_gpio3_slaves),
-	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio4 */
-static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio4_dbck", },
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_gpio4_slaves[] = {
-	&omap3xxx_l4_per__gpio4,
-};
-
-static struct omap_hwmod omap3xxx_gpio4_hwmod = {
-	.name		= "gpio4",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap2_gpio4_irqs,
-	.main_clk	= "gpio4_ick",
-	.opt_clks	= gpio4_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio4_opt_clks),
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPIO4_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPIO4_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_gpio4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_gpio4_slaves),
-	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio5 */
-static struct omap_hwmod_irq_info omap3xxx_gpio5_irqs[] = {
-	{ .irq = 33 }, /* INT_34XX_GPIO_BANK5 */
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio5_dbck", },
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_gpio5_slaves[] = {
-	&omap3xxx_l4_per__gpio5,
-};
-
-static struct omap_hwmod omap3xxx_gpio5_hwmod = {
-	.name		= "gpio5",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap3xxx_gpio5_irqs,
-	.main_clk	= "gpio5_ick",
-	.opt_clks	= gpio5_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio5_opt_clks),
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPIO5_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPIO5_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_gpio5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_gpio5_slaves),
-	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
-/* gpio6 */
-static struct omap_hwmod_irq_info omap3xxx_gpio6_irqs[] = {
-	{ .irq = 34 }, /* INT_34XX_GPIO_BANK6 */
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio6_dbck", },
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_gpio6_slaves[] = {
-	&omap3xxx_l4_per__gpio6,
-};
-
-static struct omap_hwmod omap3xxx_gpio6_hwmod = {
-	.name		= "gpio6",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap3xxx_gpio6_irqs,
-	.main_clk	= "gpio6_ick",
-	.opt_clks	= gpio6_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio6_opt_clks),
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_GPIO6_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_GPIO6_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_gpio6_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_gpio6_slaves),
-	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
-};
-
 /* dma_system -> L3 */
 static struct omap_hwmod_ocp_if omap3xxx_dma_system__l3 = {
 	.master		= &omap3xxx_dma_system_hwmod,
@@ -2154,32 +2844,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dma attributes */
-static struct omap_dma_dev_attr dma_dev_attr = {
-	.dev_caps  = RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY |
-				IS_CSSA_32 | IS_CDSA_32 | IS_RW_PRIORITY,
-	.lch_count = 32,
-};
-
-static struct omap_hwmod_class_sysconfig omap3xxx_dma_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x002c,
-	.syss_offs	= 0x0028,
-	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-			   SYSC_HAS_MIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE |
-			   SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_dma_hwmod_class = {
-	.name = "dma",
-	.sysc = &omap3xxx_dma_sysc,
-};
-
-/* dma_system */
 static struct omap_hwmod_addr_space omap3xxx_dma_system_addrs[] = {
 	{
 		.pa_start	= 0x48056000,
@@ -2189,11 +2853,6 @@
 	{ }
 };
 
-/* dma_system master ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dma_system_masters[] = {
-	&omap3xxx_dma_system__l3,
-};
-
 /* l4_cfg -> dma_system */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__dma_system = {
 	.master		= &omap3xxx_l4_core_hwmod,
@@ -2203,61 +2862,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dma_system slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dma_system_slaves[] = {
-	&omap3xxx_l4_core__dma_system,
-};
-
-static struct omap_hwmod omap3xxx_dma_system_hwmod = {
-	.name		= "dma",
-	.class		= &omap3xxx_dma_hwmod_class,
-	.mpu_irqs	= omap2_dma_system_irqs,
-	.main_clk	= "core_l3_ick",
-	.prcm = {
-		.omap2 = {
-			.module_offs		= CORE_MOD,
-			.prcm_reg_id		= 1,
-			.module_bit		= OMAP3430_ST_SDMA_SHIFT,
-			.idlest_reg_id		= 1,
-			.idlest_idle_bit	= OMAP3430_ST_SDMA_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_dma_system_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_dma_system_slaves),
-	.masters	= omap3xxx_dma_system_masters,
-	.masters_cnt	= ARRAY_SIZE(omap3xxx_dma_system_masters),
-	.dev_attr	= &dma_dev_attr,
-	.flags		= HWMOD_NO_IDLEST,
-};
-
-/*
- * 'mcbsp' class
- * multi channel buffered serial port controller
- */
-
-static struct omap_hwmod_class_sysconfig omap3xxx_mcbsp_sysc = {
-	.sysc_offs	= 0x008c,
-	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_ENAWAKEUP |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-	.clockact	= 0x2,
-};
-
-static struct omap_hwmod_class omap3xxx_mcbsp_hwmod_class = {
-	.name = "mcbsp",
-	.sysc = &omap3xxx_mcbsp_sysc,
-	.rev  = MCBSP_CONFIG_TYPE3,
-};
-
-/* mcbsp1 */
-static struct omap_hwmod_irq_info omap3xxx_mcbsp1_irqs[] = {
-	{ .name = "irq", .irq = 16 },
-	{ .name = "tx", .irq = 59 },
-	{ .name = "rx", .irq = 60 },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_mcbsp1_addrs[] = {
 	{
 		.name		= "mpu",
@@ -2277,38 +2881,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcbsp1 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp1_slaves[] = {
-	&omap3xxx_l4_core__mcbsp1,
-};
-
-static struct omap_hwmod omap3xxx_mcbsp1_hwmod = {
-	.name		= "mcbsp1",
-	.class		= &omap3xxx_mcbsp_hwmod_class,
-	.mpu_irqs	= omap3xxx_mcbsp1_irqs,
-	.sdma_reqs	= omap2_mcbsp1_sdma_reqs,
-	.main_clk	= "mcbsp1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCBSP1_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCBSP1_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mcbsp1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mcbsp1_slaves),
-};
-
-/* mcbsp2 */
-static struct omap_hwmod_irq_info omap3xxx_mcbsp2_irqs[] = {
-	{ .name = "irq", .irq = 17 },
-	{ .name = "tx", .irq = 62 },
-	{ .name = "rx", .irq = 63 },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_mcbsp2_addrs[] = {
 	{
 		.name		= "mpu",
@@ -2328,43 +2900,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcbsp2 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp2_slaves[] = {
-	&omap3xxx_l4_per__mcbsp2,
-};
-
-static struct omap_mcbsp_dev_attr omap34xx_mcbsp2_dev_attr = {
-	.sidetone	= "mcbsp2_sidetone",
-};
-
-static struct omap_hwmod omap3xxx_mcbsp2_hwmod = {
-	.name		= "mcbsp2",
-	.class		= &omap3xxx_mcbsp_hwmod_class,
-	.mpu_irqs	= omap3xxx_mcbsp2_irqs,
-	.sdma_reqs	= omap2_mcbsp2_sdma_reqs,
-	.main_clk	= "mcbsp2_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCBSP2_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCBSP2_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mcbsp2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mcbsp2_slaves),
-	.dev_attr	= &omap34xx_mcbsp2_dev_attr,
-};
-
-/* mcbsp3 */
-static struct omap_hwmod_irq_info omap3xxx_mcbsp3_irqs[] = {
-	{ .name = "irq", .irq = 22 },
-	{ .name = "tx", .irq = 89 },
-	{ .name = "rx", .irq = 90 },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_mcbsp3_addrs[] = {
 	{
 		.name		= "mpu",
@@ -2384,49 +2919,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcbsp3 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp3_slaves[] = {
-	&omap3xxx_l4_per__mcbsp3,
-};
-
-static struct omap_mcbsp_dev_attr omap34xx_mcbsp3_dev_attr = {
-	.sidetone       = "mcbsp3_sidetone",
-};
-
-static struct omap_hwmod omap3xxx_mcbsp3_hwmod = {
-	.name		= "mcbsp3",
-	.class		= &omap3xxx_mcbsp_hwmod_class,
-	.mpu_irqs	= omap3xxx_mcbsp3_irqs,
-	.sdma_reqs	= omap2_mcbsp3_sdma_reqs,
-	.main_clk	= "mcbsp3_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCBSP3_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCBSP3_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mcbsp3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mcbsp3_slaves),
-	.dev_attr	= &omap34xx_mcbsp3_dev_attr,
-};
-
-/* mcbsp4 */
-static struct omap_hwmod_irq_info omap3xxx_mcbsp4_irqs[] = {
-	{ .name = "irq", .irq = 23 },
-	{ .name = "tx", .irq = 54 },
-	{ .name = "rx", .irq = 55 },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap3xxx_mcbsp4_sdma_chs[] = {
-	{ .name = "rx", .dma_req = 20 },
-	{ .name = "tx", .dma_req = 19 },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_mcbsp4_addrs[] = {
 	{
 		.name		= "mpu",
@@ -2446,44 +2938,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcbsp4 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp4_slaves[] = {
-	&omap3xxx_l4_per__mcbsp4,
-};
-
-static struct omap_hwmod omap3xxx_mcbsp4_hwmod = {
-	.name		= "mcbsp4",
-	.class		= &omap3xxx_mcbsp_hwmod_class,
-	.mpu_irqs	= omap3xxx_mcbsp4_irqs,
-	.sdma_reqs	= omap3xxx_mcbsp4_sdma_chs,
-	.main_clk	= "mcbsp4_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCBSP4_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCBSP4_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mcbsp4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mcbsp4_slaves),
-};
-
-/* mcbsp5 */
-static struct omap_hwmod_irq_info omap3xxx_mcbsp5_irqs[] = {
-	{ .name = "irq", .irq = 27 },
-	{ .name = "tx", .irq = 81 },
-	{ .name = "rx", .irq = 82 },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap3xxx_mcbsp5_sdma_chs[] = {
-	{ .name = "rx", .dma_req = 22 },
-	{ .name = "tx", .dma_req = 21 },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_mcbsp5_addrs[] = {
 	{
 		.name		= "mpu",
@@ -2503,48 +2957,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcbsp5 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp5_slaves[] = {
-	&omap3xxx_l4_core__mcbsp5,
-};
-
-static struct omap_hwmod omap3xxx_mcbsp5_hwmod = {
-	.name		= "mcbsp5",
-	.class		= &omap3xxx_mcbsp_hwmod_class,
-	.mpu_irqs	= omap3xxx_mcbsp5_irqs,
-	.sdma_reqs	= omap3xxx_mcbsp5_sdma_chs,
-	.main_clk	= "mcbsp5_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCBSP5_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCBSP5_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mcbsp5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mcbsp5_slaves),
-};
-/* 'mcbsp sidetone' class */
-
-static struct omap_hwmod_class_sysconfig omap3xxx_mcbsp_sidetone_sysc = {
-	.sysc_offs	= 0x0010,
-	.sysc_flags	= SYSC_HAS_AUTOIDLE,
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_mcbsp_sidetone_hwmod_class = {
-	.name = "mcbsp_sidetone",
-	.sysc = &omap3xxx_mcbsp_sidetone_sysc,
-};
-
-/* mcbsp2_sidetone */
-static struct omap_hwmod_irq_info omap3xxx_mcbsp2_sidetone_irqs[] = {
-	{ .name = "irq", .irq = 4 },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_mcbsp2_sidetone_addrs[] = {
 	{
 		.name		= "sidetone",
@@ -2564,35 +2976,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* mcbsp2_sidetone slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp2_sidetone_slaves[] = {
-	&omap3xxx_l4_per__mcbsp2_sidetone,
-};
-
-static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod = {
-	.name		= "mcbsp2_sidetone",
-	.class		= &omap3xxx_mcbsp_sidetone_hwmod_class,
-	.mpu_irqs	= omap3xxx_mcbsp2_sidetone_irqs,
-	.main_clk	= "mcbsp2_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			 .module_bit = OMAP3430_EN_MCBSP2_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCBSP2_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mcbsp2_sidetone_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mcbsp2_sidetone_slaves),
-};
-
-/* mcbsp3_sidetone */
-static struct omap_hwmod_irq_info omap3xxx_mcbsp3_sidetone_irqs[] = {
-	{ .name = "irq", .irq = 5 },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_mcbsp3_sidetone_addrs[] = {
 	{
 		.name		= "sidetone",
@@ -2612,190 +2995,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* mcbsp3_sidetone slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp3_sidetone_slaves[] = {
-	&omap3xxx_l4_per__mcbsp3_sidetone,
-};
-
-static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod = {
-	.name		= "mcbsp3_sidetone",
-	.class		= &omap3xxx_mcbsp_sidetone_hwmod_class,
-	.mpu_irqs	= omap3xxx_mcbsp3_sidetone_irqs,
-	.main_clk	= "mcbsp3_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCBSP3_SHIFT,
-			.module_offs = OMAP3430_PER_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCBSP3_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mcbsp3_sidetone_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mcbsp3_sidetone_slaves),
-};
-
-
-/* SR common */
-static struct omap_hwmod_sysc_fields omap34xx_sr_sysc_fields = {
-	.clkact_shift	= 20,
-};
-
-static struct omap_hwmod_class_sysconfig omap34xx_sr_sysc = {
-	.sysc_offs	= 0x24,
-	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_NO_CACHE),
-	.clockact	= CLOCKACT_TEST_ICLK,
-	.sysc_fields	= &omap34xx_sr_sysc_fields,
-};
-
-static struct omap_hwmod_class omap34xx_smartreflex_hwmod_class = {
-	.name = "smartreflex",
-	.sysc = &omap34xx_sr_sysc,
-	.rev  = 1,
-};
-
-static struct omap_hwmod_sysc_fields omap36xx_sr_sysc_fields = {
-	.sidle_shift	= 24,
-	.enwkup_shift	= 26
-};
-
-static struct omap_hwmod_class_sysconfig omap36xx_sr_sysc = {
-	.sysc_offs	= 0x38,
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
-			SYSC_NO_CACHE),
-	.sysc_fields	= &omap36xx_sr_sysc_fields,
-};
-
-static struct omap_hwmod_class omap36xx_smartreflex_hwmod_class = {
-	.name = "smartreflex",
-	.sysc = &omap36xx_sr_sysc,
-	.rev  = 2,
-};
-
-/* SR1 */
-static struct omap_smartreflex_dev_attr sr1_dev_attr = {
-	.sensor_voltdm_name   = "mpu_iva",
-};
-
-static struct omap_hwmod_ocp_if *omap3_sr1_slaves[] = {
-	&omap3_l4_core__sr1,
-};
-
-static struct omap_hwmod omap34xx_sr1_hwmod = {
-	.name		= "sr1_hwmod",
-	.class		= &omap34xx_smartreflex_hwmod_class,
-	.main_clk	= "sr1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_SR1_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_EN_SR1_SHIFT,
-		},
-	},
-	.slaves		= omap3_sr1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
-	.dev_attr	= &sr1_dev_attr,
-	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
-	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
-};
-
-static struct omap_hwmod omap36xx_sr1_hwmod = {
-	.name		= "sr1_hwmod",
-	.class		= &omap36xx_smartreflex_hwmod_class,
-	.main_clk	= "sr1_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_SR1_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_EN_SR1_SHIFT,
-		},
-	},
-	.slaves		= omap3_sr1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
-	.dev_attr	= &sr1_dev_attr,
-	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
-};
-
-/* SR2 */
-static struct omap_smartreflex_dev_attr sr2_dev_attr = {
-	.sensor_voltdm_name	= "core",
-};
-
-static struct omap_hwmod_ocp_if *omap3_sr2_slaves[] = {
-	&omap3_l4_core__sr2,
-};
-
-static struct omap_hwmod omap34xx_sr2_hwmod = {
-	.name		= "sr2_hwmod",
-	.class		= &omap34xx_smartreflex_hwmod_class,
-	.main_clk	= "sr2_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_SR2_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_EN_SR2_SHIFT,
-		},
-	},
-	.slaves		= omap3_sr2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
-	.dev_attr	= &sr2_dev_attr,
-	.mpu_irqs	= omap3_smartreflex_core_irqs,
-	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
-};
-
-static struct omap_hwmod omap36xx_sr2_hwmod = {
-	.name		= "sr2_hwmod",
-	.class		= &omap36xx_smartreflex_hwmod_class,
-	.main_clk	= "sr2_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_SR2_SHIFT,
-			.module_offs = WKUP_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_EN_SR2_SHIFT,
-		},
-	},
-	.slaves		= omap3_sr2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
-	.dev_attr	= &sr2_dev_attr,
-	.mpu_irqs	= omap3_smartreflex_core_irqs,
-};
-
-/*
- * 'mailbox' class
- * mailbox module allowing communication between the on-chip processors
- * using a queued mailbox-interrupt mechanism.
- */
-
-static struct omap_hwmod_class_sysconfig omap3xxx_mailbox_sysc = {
-	.rev_offs	= 0x000,
-	.sysc_offs	= 0x010,
-	.syss_offs	= 0x014,
-	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
-				SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_mailbox_hwmod_class = {
-	.name = "mailbox",
-	.sysc = &omap3xxx_mailbox_sysc,
-};
-
-static struct omap_hwmod omap3xxx_mailbox_hwmod;
-static struct omap_hwmod_irq_info omap3xxx_mailbox_irqs[] = {
-	{ .irq = 26 },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_mailbox_addrs[] = {
 	{
 		.pa_start	= 0x48094000,
@@ -2813,29 +3012,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mailbox slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mailbox_slaves[] = {
-	&omap3xxx_l4_core__mailbox,
-};
-
-static struct omap_hwmod omap3xxx_mailbox_hwmod = {
-	.name		= "mailbox",
-	.class		= &omap3xxx_mailbox_hwmod_class,
-	.mpu_irqs	= omap3xxx_mailbox_irqs,
-	.main_clk	= "mailboxes_ick",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MAILBOXES_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MAILBOXES_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mailbox_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mailbox_slaves),
-};
-
 /* l4 core -> mcspi1 interface */
 static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi1 = {
 	.master		= &omap3xxx_l4_core_hwmod,
@@ -2881,459 +3057,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/*
- * 'mcspi' class
- * multichannel serial port interface (mcspi) / master/slave synchronous serial
- * bus
- */
-
-static struct omap_hwmod_class_sysconfig omap34xx_mcspi_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
-				SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
-				SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap34xx_mcspi_class = {
-	.name = "mcspi",
-	.sysc = &omap34xx_mcspi_sysc,
-	.rev = OMAP3_MCSPI_REV,
-};
-
-/* mcspi1 */
-static struct omap_hwmod_ocp_if *omap34xx_mcspi1_slaves[] = {
-	&omap34xx_l4_core__mcspi1,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
-	.num_chipselect = 4,
-};
-
-static struct omap_hwmod omap34xx_mcspi1 = {
-	.name		= "mcspi1",
-	.mpu_irqs	= omap2_mcspi1_mpu_irqs,
-	.sdma_reqs	= omap2_mcspi1_sdma_reqs,
-	.main_clk	= "mcspi1_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCSPI1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCSPI1_SHIFT,
-		},
-	},
-	.slaves		= omap34xx_mcspi1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap34xx_mcspi1_slaves),
-	.class		= &omap34xx_mcspi_class,
-	.dev_attr       = &omap_mcspi1_dev_attr,
-};
-
-/* mcspi2 */
-static struct omap_hwmod_ocp_if *omap34xx_mcspi2_slaves[] = {
-	&omap34xx_l4_core__mcspi2,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
-	.num_chipselect = 2,
-};
-
-static struct omap_hwmod omap34xx_mcspi2 = {
-	.name		= "mcspi2",
-	.mpu_irqs	= omap2_mcspi2_mpu_irqs,
-	.sdma_reqs	= omap2_mcspi2_sdma_reqs,
-	.main_clk	= "mcspi2_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCSPI2_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCSPI2_SHIFT,
-		},
-	},
-	.slaves		= omap34xx_mcspi2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap34xx_mcspi2_slaves),
-	.class		= &omap34xx_mcspi_class,
-	.dev_attr       = &omap_mcspi2_dev_attr,
-};
-
-/* mcspi3 */
-static struct omap_hwmod_irq_info omap34xx_mcspi3_mpu_irqs[] = {
-	{ .name = "irq", .irq = 91 }, /* 91 */
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap34xx_mcspi3_sdma_reqs[] = {
-	{ .name = "tx0", .dma_req = 15 },
-	{ .name = "rx0", .dma_req = 16 },
-	{ .name = "tx1", .dma_req = 23 },
-	{ .name = "rx1", .dma_req = 24 },
-	{ .dma_req = -1 }
-};
-
-static struct omap_hwmod_ocp_if *omap34xx_mcspi3_slaves[] = {
-	&omap34xx_l4_core__mcspi3,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi3_dev_attr = {
-	.num_chipselect = 2,
-};
-
-static struct omap_hwmod omap34xx_mcspi3 = {
-	.name		= "mcspi3",
-	.mpu_irqs	= omap34xx_mcspi3_mpu_irqs,
-	.sdma_reqs	= omap34xx_mcspi3_sdma_reqs,
-	.main_clk	= "mcspi3_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCSPI3_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCSPI3_SHIFT,
-		},
-	},
-	.slaves		= omap34xx_mcspi3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap34xx_mcspi3_slaves),
-	.class		= &omap34xx_mcspi_class,
-	.dev_attr       = &omap_mcspi3_dev_attr,
-};
-
-/* SPI4 */
-static struct omap_hwmod_irq_info omap34xx_mcspi4_mpu_irqs[] = {
-	{ .name = "irq", .irq = INT_34XX_SPI4_IRQ }, /* 48 */
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap34xx_mcspi4_sdma_reqs[] = {
-	{ .name = "tx0", .dma_req = 70 }, /* DMA_SPI4_TX0 */
-	{ .name = "rx0", .dma_req = 71 }, /* DMA_SPI4_RX0 */
-	{ .dma_req = -1 }
-};
-
-static struct omap_hwmod_ocp_if *omap34xx_mcspi4_slaves[] = {
-	&omap34xx_l4_core__mcspi4,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi4_dev_attr = {
-	.num_chipselect = 1,
-};
-
-static struct omap_hwmod omap34xx_mcspi4 = {
-	.name		= "mcspi4",
-	.mpu_irqs	= omap34xx_mcspi4_mpu_irqs,
-	.sdma_reqs	= omap34xx_mcspi4_sdma_reqs,
-	.main_clk	= "mcspi4_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MCSPI4_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MCSPI4_SHIFT,
-		},
-	},
-	.slaves		= omap34xx_mcspi4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap34xx_mcspi4_slaves),
-	.class		= &omap34xx_mcspi_class,
-	.dev_attr       = &omap_mcspi4_dev_attr,
-};
-
-/*
- * usbhsotg
- */
-static struct omap_hwmod_class_sysconfig omap3xxx_usbhsotg_sysc = {
-	.rev_offs	= 0x0400,
-	.sysc_offs	= 0x0404,
-	.syss_offs	= 0x0408,
-	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE|
-			  SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
-			  SYSC_HAS_AUTOIDLE),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			  MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class usbotg_class = {
-	.name = "usbotg",
-	.sysc = &omap3xxx_usbhsotg_sysc,
-};
-/* usb_otg_hs */
-static struct omap_hwmod_irq_info omap3xxx_usbhsotg_mpu_irqs[] = {
-
-	{ .name = "mc", .irq = 92 },
-	{ .name = "dma", .irq = 93 },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod omap3xxx_usbhsotg_hwmod = {
-	.name		= "usb_otg_hs",
-	.mpu_irqs	= omap3xxx_usbhsotg_mpu_irqs,
-	.main_clk	= "hsotgusb_ick",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
-			.module_offs = CORE_MOD,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT,
-			.idlest_stdby_bit = OMAP3430ES2_ST_HSOTGUSB_STDBY_SHIFT
-		},
-	},
-	.masters	= omap3xxx_usbhsotg_masters,
-	.masters_cnt	= ARRAY_SIZE(omap3xxx_usbhsotg_masters),
-	.slaves		= omap3xxx_usbhsotg_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_usbhsotg_slaves),
-	.class		= &usbotg_class,
-
-	/*
-	 * Erratum ID: i479  idle_req / idle_ack mechanism potentially
-	 * broken when autoidle is enabled
-	 * workaround is to disable the autoidle bit at module level.
-	 */
-	.flags		= HWMOD_NO_OCP_AUTOIDLE | HWMOD_SWSUP_SIDLE
-				| HWMOD_SWSUP_MSTANDBY,
-};
-
-/* usb_otg_hs */
-static struct omap_hwmod_irq_info am35xx_usbhsotg_mpu_irqs[] = {
-
-	{ .name = "mc", .irq = 71 },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_class am35xx_usbotg_class = {
-	.name = "am35xx_usbotg",
-	.sysc = NULL,
-};
-
-static struct omap_hwmod am35xx_usbhsotg_hwmod = {
-	.name		= "am35x_otg_hs",
-	.mpu_irqs	= am35xx_usbhsotg_mpu_irqs,
-	.main_clk	= NULL,
-	.prcm = {
-		.omap2 = {
-		},
-	},
-	.masters	= am35xx_usbhsotg_masters,
-	.masters_cnt	= ARRAY_SIZE(am35xx_usbhsotg_masters),
-	.slaves		= am35xx_usbhsotg_slaves,
-	.slaves_cnt	= ARRAY_SIZE(am35xx_usbhsotg_slaves),
-	.class		= &am35xx_usbotg_class,
-};
-
-/* MMC/SD/SDIO common */
-
-static struct omap_hwmod_class_sysconfig omap34xx_mmc_sysc = {
-	.rev_offs	= 0x1fc,
-	.sysc_offs	= 0x10,
-	.syss_offs	= 0x14,
-	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
-			   SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap34xx_mmc_class = {
-	.name = "mmc",
-	.sysc = &omap34xx_mmc_sysc,
-};
-
-/* MMC/SD/SDIO1 */
-
-static struct omap_hwmod_irq_info omap34xx_mmc1_mpu_irqs[] = {
-	{ .irq = 83, },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap34xx_mmc1_sdma_reqs[] = {
-	{ .name = "tx",	.dma_req = 61, },
-	{ .name = "rx",	.dma_req = 62, },
-	{ .dma_req = -1 }
-};
-
-static struct omap_hwmod_opt_clk omap34xx_mmc1_opt_clks[] = {
-	{ .role = "dbck", .clk = "omap_32k_fck", },
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_mmc1_slaves[] = {
-	&omap3xxx_l4_core__mmc1,
-};
-
-static struct omap_mmc_dev_attr mmc1_dev_attr = {
-	.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
-};
-
-/* See 35xx errata 2.1.1.128 in SPRZ278F */
-static struct omap_mmc_dev_attr mmc1_pre_es3_dev_attr = {
-	.flags = (OMAP_HSMMC_SUPPORTS_DUAL_VOLT |
-		  OMAP_HSMMC_BROKEN_MULTIBLOCK_READ),
-};
-
-static struct omap_hwmod omap3xxx_pre_es3_mmc1_hwmod = {
-	.name		= "mmc1",
-	.mpu_irqs	= omap34xx_mmc1_mpu_irqs,
-	.sdma_reqs	= omap34xx_mmc1_sdma_reqs,
-	.opt_clks	= omap34xx_mmc1_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc1_opt_clks),
-	.main_clk	= "mmchs1_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MMC1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MMC1_SHIFT,
-		},
-	},
-	.dev_attr	= &mmc1_pre_es3_dev_attr,
-	.slaves		= omap3xxx_mmc1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mmc1_slaves),
-	.class		= &omap34xx_mmc_class,
-};
-
-static struct omap_hwmod omap3xxx_es3plus_mmc1_hwmod = {
-	.name		= "mmc1",
-	.mpu_irqs	= omap34xx_mmc1_mpu_irqs,
-	.sdma_reqs	= omap34xx_mmc1_sdma_reqs,
-	.opt_clks	= omap34xx_mmc1_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc1_opt_clks),
-	.main_clk	= "mmchs1_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MMC1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MMC1_SHIFT,
-		},
-	},
-	.dev_attr	= &mmc1_dev_attr,
-	.slaves		= omap3xxx_mmc1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mmc1_slaves),
-	.class		= &omap34xx_mmc_class,
-};
-
-/* MMC/SD/SDIO2 */
-
-static struct omap_hwmod_irq_info omap34xx_mmc2_mpu_irqs[] = {
-	{ .irq = INT_24XX_MMC2_IRQ, },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap34xx_mmc2_sdma_reqs[] = {
-	{ .name = "tx",	.dma_req = 47, },
-	{ .name = "rx",	.dma_req = 48, },
-	{ .dma_req = -1 }
-};
-
-static struct omap_hwmod_opt_clk omap34xx_mmc2_opt_clks[] = {
-	{ .role = "dbck", .clk = "omap_32k_fck", },
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_mmc2_slaves[] = {
-	&omap3xxx_l4_core__mmc2,
-};
-
-/* See 35xx errata 2.1.1.128 in SPRZ278F */
-static struct omap_mmc_dev_attr mmc2_pre_es3_dev_attr = {
-	.flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
-};
-
-static struct omap_hwmod omap3xxx_pre_es3_mmc2_hwmod = {
-	.name		= "mmc2",
-	.mpu_irqs	= omap34xx_mmc2_mpu_irqs,
-	.sdma_reqs	= omap34xx_mmc2_sdma_reqs,
-	.opt_clks	= omap34xx_mmc2_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc2_opt_clks),
-	.main_clk	= "mmchs2_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MMC2_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MMC2_SHIFT,
-		},
-	},
-	.dev_attr	= &mmc2_pre_es3_dev_attr,
-	.slaves		= omap3xxx_mmc2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mmc2_slaves),
-	.class		= &omap34xx_mmc_class,
-};
-
-static struct omap_hwmod omap3xxx_es3plus_mmc2_hwmod = {
-	.name		= "mmc2",
-	.mpu_irqs	= omap34xx_mmc2_mpu_irqs,
-	.sdma_reqs	= omap34xx_mmc2_sdma_reqs,
-	.opt_clks	= omap34xx_mmc2_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc2_opt_clks),
-	.main_clk	= "mmchs2_fck",
-	.prcm		= {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MMC2_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MMC2_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mmc2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mmc2_slaves),
-	.class		= &omap34xx_mmc_class,
-};
-
-/* MMC/SD/SDIO3 */
-
-static struct omap_hwmod_irq_info omap34xx_mmc3_mpu_irqs[] = {
-	{ .irq = 94, },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap34xx_mmc3_sdma_reqs[] = {
-	{ .name = "tx",	.dma_req = 77, },
-	{ .name = "rx",	.dma_req = 78, },
-	{ .dma_req = -1 }
-};
-
-static struct omap_hwmod_opt_clk omap34xx_mmc3_opt_clks[] = {
-	{ .role = "dbck", .clk = "omap_32k_fck", },
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_mmc3_slaves[] = {
-	&omap3xxx_l4_core__mmc3,
-};
-
-static struct omap_hwmod omap3xxx_mmc3_hwmod = {
-	.name		= "mmc3",
-	.mpu_irqs	= omap34xx_mmc3_mpu_irqs,
-	.sdma_reqs	= omap34xx_mmc3_sdma_reqs,
-	.opt_clks	= omap34xx_mmc3_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(omap34xx_mmc3_opt_clks),
-	.main_clk	= "mmchs3_fck",
-	.prcm		= {
-		.omap2 = {
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430_EN_MMC3_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430_ST_MMC3_SHIFT,
-		},
-	},
-	.slaves		= omap3xxx_mmc3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_mmc3_slaves),
-	.class		= &omap34xx_mmc_class,
-};
-
-/*
- * 'usb_host_hs' class
- * high-speed multi-port usb host controller
- */
 static struct omap_hwmod_ocp_if omap3xxx_usb_host_hs__l3_main_2 = {
 	.master		= &omap3xxx_usb_host_hs_hwmod,
 	.slave		= &omap3xxx_l3_main_hwmod,
@@ -3341,27 +3064,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-static struct omap_hwmod_class_sysconfig omap3xxx_usb_host_hs_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
-			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_usb_host_hs_hwmod_class = {
-	.name = "usb_host_hs",
-	.sysc = &omap3xxx_usb_host_hs_sysc,
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_usb_host_hs_masters[] = {
-	&omap3xxx_usb_host_hs__l3_main_2,
-};
-
 static struct omap_hwmod_addr_space omap3xxx_usb_host_hs_addrs[] = {
 	{
 		.name		= "uhh",
@@ -3390,117 +3092,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_ocp_if *omap3xxx_usb_host_hs_slaves[] = {
-	&omap3xxx_l4_core__usb_host_hs,
-};
-
-static struct omap_hwmod_opt_clk omap3xxx_usb_host_hs_opt_clks[] = {
-	  { .role = "ehci_logic_fck", .clk = "usbhost_120m_fck", },
-};
-
-static struct omap_hwmod_irq_info omap3xxx_usb_host_hs_irqs[] = {
-	{ .name = "ohci-irq", .irq = 76 },
-	{ .name = "ehci-irq", .irq = 77 },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod omap3xxx_usb_host_hs_hwmod = {
-	.name		= "usb_host_hs",
-	.class		= &omap3xxx_usb_host_hs_hwmod_class,
-	.clkdm_name	= "l3_init_clkdm",
-	.mpu_irqs	= omap3xxx_usb_host_hs_irqs,
-	.main_clk	= "usbhost_48m_fck",
-	.prcm = {
-		.omap2 = {
-			.module_offs = OMAP3430ES2_USBHOST_MOD,
-			.prcm_reg_id = 1,
-			.module_bit = OMAP3430ES2_EN_USBHOST1_SHIFT,
-			.idlest_reg_id = 1,
-			.idlest_idle_bit = OMAP3430ES2_ST_USBHOST_IDLE_SHIFT,
-			.idlest_stdby_bit = OMAP3430ES2_ST_USBHOST_STDBY_SHIFT,
-		},
-	},
-	.opt_clks	= omap3xxx_usb_host_hs_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(omap3xxx_usb_host_hs_opt_clks),
-	.slaves		= omap3xxx_usb_host_hs_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_usb_host_hs_slaves),
-	.masters	= omap3xxx_usb_host_hs_masters,
-	.masters_cnt	= ARRAY_SIZE(omap3xxx_usb_host_hs_masters),
-
-	/*
-	 * Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
-	 * id: i660
-	 *
-	 * Description:
-	 * In the following configuration :
-	 * - USBHOST module is set to smart-idle mode
-	 * - PRCM asserts idle_req to the USBHOST module ( This typically
-	 *   happens when the system is going to a low power mode : all ports
-	 *   have been suspended, the master part of the USBHOST module has
-	 *   entered the standby state, and SW has cut the functional clocks)
-	 * - an USBHOST interrupt occurs before the module is able to answer
-	 *   idle_ack, typically a remote wakeup IRQ.
-	 * Then the USB HOST module will enter a deadlock situation where it
-	 * is no more accessible nor functional.
-	 *
-	 * Workaround:
-	 * Don't use smart idle; use only force idle, hence HWMOD_SWSUP_SIDLE
-	 */
-
-	/*
-	 * Errata: USB host EHCI may stall when entering smart-standby mode
-	 * Id: i571
-	 *
-	 * Description:
-	 * When the USBHOST module is set to smart-standby mode, and when it is
-	 * ready to enter the standby state (i.e. all ports are suspended and
-	 * all attached devices are in suspend mode), then it can wrongly assert
-	 * the Mstandby signal too early while there are still some residual OCP
-	 * transactions ongoing. If this condition occurs, the internal state
-	 * machine may go to an undefined state and the USB link may be stuck
-	 * upon the next resume.
-	 *
-	 * Workaround:
-	 * Don't use smart standby; use only force standby,
-	 * hence HWMOD_SWSUP_MSTANDBY
-	 */
-
-	/*
-	 * During system boot; If the hwmod framework resets the module
-	 * the module will have smart idle settings; which can lead to deadlock
-	 * (above Errata Id:i660); so, dont reset the module during boot;
-	 * Use HWMOD_INIT_NO_RESET.
-	 */
-
-	.flags		= HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
-			  HWMOD_INIT_NO_RESET,
-};
-
-/*
- * 'usb_tll_hs' class
- * usb_tll_hs module is the adapter on the usb_host_hs ports
- */
-static struct omap_hwmod_class_sysconfig omap3xxx_usb_tll_hs_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
-			   SYSC_HAS_AUTOIDLE),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_usb_tll_hs_hwmod_class = {
-	.name = "usb_tll_hs",
-	.sysc = &omap3xxx_usb_tll_hs_sysc,
-};
-
-static struct omap_hwmod_irq_info omap3xxx_usb_tll_hs_irqs[] = {
-	{ .name = "tll-irq", .irq = 78 },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap3xxx_usb_tll_hs_addrs[] = {
 	{
 		.name		= "tll",
@@ -3519,183 +3110,187 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_ocp_if *omap3xxx_usb_tll_hs_slaves[] = {
-	&omap3xxx_l4_core__usb_tll_hs,
+/* l4_core -> hdq1w interface */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__hdq1w = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap3xxx_hdq1w_hwmod,
+	.clk		= "hdq_ick",
+	.addr		= omap2_hdq1w_addr_space,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+	.flags		= OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE,
 };
 
-static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod = {
-	.name		= "usb_tll_hs",
-	.class		= &omap3xxx_usb_tll_hs_hwmod_class,
-	.clkdm_name	= "l3_init_clkdm",
-	.mpu_irqs	= omap3xxx_usb_tll_hs_irqs,
-	.main_clk	= "usbtll_fck",
-	.prcm = {
-		.omap2 = {
-			.module_offs = CORE_MOD,
-			.prcm_reg_id = 3,
-			.module_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
-			.idlest_reg_id = 3,
-			.idlest_idle_bit = OMAP3430ES2_ST_USBTLL_SHIFT,
-		},
+/* l4_wkup -> 32ksync_counter */
+static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
+	{
+		.pa_start	= 0x48320000,
+		.pa_end		= 0x4832001f,
+		.flags		= ADDR_TYPE_RT
 	},
-	.slaves		= omap3xxx_usb_tll_hs_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap3xxx_usb_tll_hs_slaves),
+	{ }
 };
 
-static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
-	&omap3xxx_l3_main_hwmod,
-	&omap3xxx_l4_core_hwmod,
-	&omap3xxx_l4_per_hwmod,
-	&omap3xxx_l4_wkup_hwmod,
-	&omap3xxx_mmc3_hwmod,
-	&omap3xxx_mpu_hwmod,
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__counter_32k = {
+	.master		= &omap3xxx_l4_wkup_hwmod,
+	.slave		= &omap3xxx_counter_32k_hwmod,
+	.clk		= "omap_32ksync_ick",
+	.addr		= omap3xxx_counter_32k_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
 
-	&omap3xxx_timer1_hwmod,
-	&omap3xxx_timer2_hwmod,
-	&omap3xxx_timer3_hwmod,
-	&omap3xxx_timer4_hwmod,
-	&omap3xxx_timer5_hwmod,
-	&omap3xxx_timer6_hwmod,
-	&omap3xxx_timer7_hwmod,
-	&omap3xxx_timer8_hwmod,
-	&omap3xxx_timer9_hwmod,
-	&omap3xxx_timer10_hwmod,
-	&omap3xxx_timer11_hwmod,
-
-	&omap3xxx_wd_timer2_hwmod,
-	&omap3xxx_uart1_hwmod,
-	&omap3xxx_uart2_hwmod,
-	&omap3xxx_uart3_hwmod,
-
-	/* i2c class */
-	&omap3xxx_i2c1_hwmod,
-	&omap3xxx_i2c2_hwmod,
-	&omap3xxx_i2c3_hwmod,
-
-	/* gpio class */
-	&omap3xxx_gpio1_hwmod,
-	&omap3xxx_gpio2_hwmod,
-	&omap3xxx_gpio3_hwmod,
-	&omap3xxx_gpio4_hwmod,
-	&omap3xxx_gpio5_hwmod,
-	&omap3xxx_gpio6_hwmod,
-
-	/* dma_system class*/
-	&omap3xxx_dma_system_hwmod,
-
-	/* mcbsp class */
-	&omap3xxx_mcbsp1_hwmod,
-	&omap3xxx_mcbsp2_hwmod,
-	&omap3xxx_mcbsp3_hwmod,
-	&omap3xxx_mcbsp4_hwmod,
-	&omap3xxx_mcbsp5_hwmod,
-	&omap3xxx_mcbsp2_sidetone_hwmod,
-	&omap3xxx_mcbsp3_sidetone_hwmod,
-
-
-	/* mcspi class */
-	&omap34xx_mcspi1,
-	&omap34xx_mcspi2,
-	&omap34xx_mcspi3,
-	&omap34xx_mcspi4,
-
+static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
+	&omap3xxx_l3_main__l4_core,
+	&omap3xxx_l3_main__l4_per,
+	&omap3xxx_mpu__l3_main,
+	&omap3xxx_l4_core__l4_wkup,
+	&omap3xxx_l4_core__mmc3,
+	&omap3_l4_core__uart1,
+	&omap3_l4_core__uart2,
+	&omap3_l4_per__uart3,
+	&omap3_l4_core__i2c1,
+	&omap3_l4_core__i2c2,
+	&omap3_l4_core__i2c3,
+	&omap3xxx_l4_wkup__l4_sec,
+	&omap3xxx_l4_wkup__timer1,
+	&omap3xxx_l4_per__timer2,
+	&omap3xxx_l4_per__timer3,
+	&omap3xxx_l4_per__timer4,
+	&omap3xxx_l4_per__timer5,
+	&omap3xxx_l4_per__timer6,
+	&omap3xxx_l4_per__timer7,
+	&omap3xxx_l4_per__timer8,
+	&omap3xxx_l4_per__timer9,
+	&omap3xxx_l4_core__timer10,
+	&omap3xxx_l4_core__timer11,
+	&omap3xxx_l4_wkup__wd_timer2,
+	&omap3xxx_l4_wkup__gpio1,
+	&omap3xxx_l4_per__gpio2,
+	&omap3xxx_l4_per__gpio3,
+	&omap3xxx_l4_per__gpio4,
+	&omap3xxx_l4_per__gpio5,
+	&omap3xxx_l4_per__gpio6,
+	&omap3xxx_dma_system__l3,
+	&omap3xxx_l4_core__dma_system,
+	&omap3xxx_l4_core__mcbsp1,
+	&omap3xxx_l4_per__mcbsp2,
+	&omap3xxx_l4_per__mcbsp3,
+	&omap3xxx_l4_per__mcbsp4,
+	&omap3xxx_l4_core__mcbsp5,
+	&omap3xxx_l4_per__mcbsp2_sidetone,
+	&omap3xxx_l4_per__mcbsp3_sidetone,
+	&omap34xx_l4_core__mcspi1,
+	&omap34xx_l4_core__mcspi2,
+	&omap34xx_l4_core__mcspi3,
+	&omap34xx_l4_core__mcspi4,
+	&omap3xxx_l4_wkup__counter_32k,
 	NULL,
 };
 
-/* GP-only hwmods */
-static __initdata struct omap_hwmod *omap3xxx_gp_hwmods[] = {
-	&omap3xxx_timer12_hwmod,
+/* GP-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3xxx_gp_hwmod_ocp_ifs[] __initdata = {
+	&omap3xxx_l4_sec__timer12,
 	NULL
 };
 
-/* 3430ES1-only hwmods */
-static __initdata struct omap_hwmod *omap3430es1_hwmods[] = {
-	&omap3430es1_dss_core_hwmod,
+/* 3430ES1-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3430es1_hwmod_ocp_ifs[] __initdata = {
+	&omap3430es1_dss__l3,
+	&omap3430es1_l4_core__dss,
 	NULL
 };
 
-/* 3430ES2+-only hwmods */
-static __initdata struct omap_hwmod *omap3430es2plus_hwmods[] = {
-	&omap3xxx_dss_core_hwmod,
-	&omap3xxx_usbhsotg_hwmod,
-	&omap3xxx_usb_host_hs_hwmod,
-	&omap3xxx_usb_tll_hs_hwmod,
+/* 3430ES2+-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3430es2plus_hwmod_ocp_ifs[] __initdata = {
+	&omap3xxx_dss__l3,
+	&omap3xxx_l4_core__dss,
+	&omap3xxx_usbhsotg__l3,
+	&omap3xxx_l4_core__usbhsotg,
+	&omap3xxx_usb_host_hs__l3_main_2,
+	&omap3xxx_l4_core__usb_host_hs,
+	&omap3xxx_l4_core__usb_tll_hs,
 	NULL
 };
 
-/* <= 3430ES3-only hwmods */
-static struct omap_hwmod *omap3430_pre_es3_hwmods[] __initdata = {
-	&omap3xxx_pre_es3_mmc1_hwmod,
-	&omap3xxx_pre_es3_mmc2_hwmod,
+/* <= 3430ES3-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3430_pre_es3_hwmod_ocp_ifs[] __initdata = {
+	&omap3xxx_l4_core__pre_es3_mmc1,
+	&omap3xxx_l4_core__pre_es3_mmc2,
 	NULL
 };
 
-/* 3430ES3+-only hwmods */
-static struct omap_hwmod *omap3430_es3plus_hwmods[] __initdata = {
-	&omap3xxx_es3plus_mmc1_hwmod,
-	&omap3xxx_es3plus_mmc2_hwmod,
+/* 3430ES3+-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3430_es3plus_hwmod_ocp_ifs[] __initdata = {
+	&omap3xxx_l4_core__es3plus_mmc1,
+	&omap3xxx_l4_core__es3plus_mmc2,
 	NULL
 };
 
-/* 34xx-only hwmods (all ES revisions) */
-static __initdata struct omap_hwmod *omap34xx_hwmods[] = {
-	&omap3xxx_iva_hwmod,
-	&omap34xx_sr1_hwmod,
-	&omap34xx_sr2_hwmod,
-	&omap3xxx_mailbox_hwmod,
+/* 34xx-only hwmod links (all ES revisions) */
+static struct omap_hwmod_ocp_if *omap34xx_hwmod_ocp_ifs[] __initdata = {
+	&omap3xxx_l3__iva,
+	&omap34xx_l4_core__sr1,
+	&omap34xx_l4_core__sr2,
+	&omap3xxx_l4_core__mailbox,
+	&omap3xxx_l4_core__hdq1w,
 	NULL
 };
 
-/* 36xx-only hwmods (all ES revisions) */
-static __initdata struct omap_hwmod *omap36xx_hwmods[] = {
-	&omap3xxx_iva_hwmod,
-	&omap3xxx_uart4_hwmod,
-	&omap3xxx_dss_core_hwmod,
-	&omap36xx_sr1_hwmod,
-	&omap36xx_sr2_hwmod,
-	&omap3xxx_usbhsotg_hwmod,
-	&omap3xxx_mailbox_hwmod,
-	&omap3xxx_usb_host_hs_hwmod,
-	&omap3xxx_usb_tll_hs_hwmod,
-	&omap3xxx_es3plus_mmc1_hwmod,
-	&omap3xxx_es3plus_mmc2_hwmod,
+/* 36xx-only hwmod links (all ES revisions) */
+static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = {
+	&omap3xxx_l3__iva,
+	&omap36xx_l4_per__uart4,
+	&omap3xxx_dss__l3,
+	&omap3xxx_l4_core__dss,
+	&omap36xx_l4_core__sr1,
+	&omap36xx_l4_core__sr2,
+	&omap3xxx_usbhsotg__l3,
+	&omap3xxx_l4_core__usbhsotg,
+	&omap3xxx_l4_core__mailbox,
+	&omap3xxx_usb_host_hs__l3_main_2,
+	&omap3xxx_l4_core__usb_host_hs,
+	&omap3xxx_l4_core__usb_tll_hs,
+	&omap3xxx_l4_core__es3plus_mmc1,
+	&omap3xxx_l4_core__es3plus_mmc2,
+	&omap3xxx_l4_core__hdq1w,
 	NULL
 };
 
-static __initdata struct omap_hwmod *am35xx_hwmods[] = {
-	&omap3xxx_dss_core_hwmod, /* XXX ??? */
-	&am35xx_usbhsotg_hwmod,
-	&am35xx_uart4_hwmod,
-	&omap3xxx_usb_host_hs_hwmod,
-	&omap3xxx_usb_tll_hs_hwmod,
-	&omap3xxx_es3plus_mmc1_hwmod,
-	&omap3xxx_es3plus_mmc2_hwmod,
+static struct omap_hwmod_ocp_if *am35xx_hwmod_ocp_ifs[] __initdata = {
+	&omap3xxx_dss__l3,
+	&omap3xxx_l4_core__dss,
+	&am35xx_usbhsotg__l3,
+	&am35xx_l4_core__usbhsotg,
+	&am35xx_l4_core__uart4,
+	&omap3xxx_usb_host_hs__l3_main_2,
+	&omap3xxx_l4_core__usb_host_hs,
+	&omap3xxx_l4_core__usb_tll_hs,
+	&omap3xxx_l4_core__es3plus_mmc1,
+	&omap3xxx_l4_core__es3plus_mmc2,
 	NULL
 };
 
-static __initdata struct omap_hwmod *omap3xxx_dss_hwmods[] = {
-	/* dss class */
-	&omap3xxx_dss_dispc_hwmod,
-	&omap3xxx_dss_dsi1_hwmod,
-	&omap3xxx_dss_rfbi_hwmod,
-	&omap3xxx_dss_venc_hwmod,
+static struct omap_hwmod_ocp_if *omap3xxx_dss_hwmod_ocp_ifs[] __initdata = {
+	&omap3xxx_l4_core__dss_dispc,
+	&omap3xxx_l4_core__dss_dsi1,
+	&omap3xxx_l4_core__dss_rfbi,
+	&omap3xxx_l4_core__dss_venc,
 	NULL
 };
 
 int __init omap3xxx_hwmod_init(void)
 {
 	int r;
-	struct omap_hwmod **h = NULL;
+	struct omap_hwmod_ocp_if **h = NULL;
 	unsigned int rev;
 
-	/* Register hwmods common to all OMAP3 */
-	r = omap_hwmod_register(omap3xxx_hwmods);
+	/* Register hwmod links common to all OMAP3 */
+	r = omap_hwmod_register_links(omap3xxx_hwmod_ocp_ifs);
 	if (r < 0)
 		return r;
 
-	/* Register GP-only hwmods. */
+	/* Register GP-only hwmod links. */
 	if (omap_type() == OMAP2_DEVICE_TYPE_GP) {
-		r = omap_hwmod_register(omap3xxx_gp_hwmods);
+		r = omap_hwmod_register_links(omap3xxx_gp_hwmod_ocp_ifs);
 		if (r < 0)
 			return r;
 	}
@@ -3703,43 +3298,43 @@
 	rev = omap_rev();
 
 	/*
-	 * Register hwmods common to individual OMAP3 families, all
+	 * Register hwmod links common to individual OMAP3 families, all
 	 * silicon revisions (e.g., 34xx, or AM3505/3517, or 36xx)
 	 * All possible revisions should be included in this conditional.
 	 */
 	if (rev == OMAP3430_REV_ES1_0 || rev == OMAP3430_REV_ES2_0 ||
 	    rev == OMAP3430_REV_ES2_1 || rev == OMAP3430_REV_ES3_0 ||
 	    rev == OMAP3430_REV_ES3_1 || rev == OMAP3430_REV_ES3_1_2) {
-		h = omap34xx_hwmods;
+		h = omap34xx_hwmod_ocp_ifs;
 	} else if (rev == OMAP3517_REV_ES1_0 || rev == OMAP3517_REV_ES1_1) {
-		h = am35xx_hwmods;
+		h = am35xx_hwmod_ocp_ifs;
 	} else if (rev == OMAP3630_REV_ES1_0 || rev == OMAP3630_REV_ES1_1 ||
 		   rev == OMAP3630_REV_ES1_2) {
-		h = omap36xx_hwmods;
+		h = omap36xx_hwmod_ocp_ifs;
 	} else {
 		WARN(1, "OMAP3 hwmod family init: unknown chip type\n");
 		return -EINVAL;
 	};
 
-	r = omap_hwmod_register(h);
+	r = omap_hwmod_register_links(h);
 	if (r < 0)
 		return r;
 
 	/*
-	 * Register hwmods specific to certain ES levels of a
+	 * Register hwmod links specific to certain ES levels of a
 	 * particular family of silicon (e.g., 34xx ES1.0)
 	 */
 	h = NULL;
 	if (rev == OMAP3430_REV_ES1_0) {
-		h = omap3430es1_hwmods;
+		h = omap3430es1_hwmod_ocp_ifs;
 	} else if (rev == OMAP3430_REV_ES2_0 || rev == OMAP3430_REV_ES2_1 ||
 		   rev == OMAP3430_REV_ES3_0 || rev == OMAP3430_REV_ES3_1 ||
 		   rev == OMAP3430_REV_ES3_1_2) {
-		h = omap3430es2plus_hwmods;
+		h = omap3430es2plus_hwmod_ocp_ifs;
 	};
 
 	if (h) {
-		r = omap_hwmod_register(h);
+		r = omap_hwmod_register_links(h);
 		if (r < 0)
 			return r;
 	}
@@ -3747,29 +3342,29 @@
 	h = NULL;
 	if (rev == OMAP3430_REV_ES1_0 || rev == OMAP3430_REV_ES2_0 ||
 	    rev == OMAP3430_REV_ES2_1) {
-		h = omap3430_pre_es3_hwmods;
+		h = omap3430_pre_es3_hwmod_ocp_ifs;
 	} else if (rev == OMAP3430_REV_ES3_0 || rev == OMAP3430_REV_ES3_1 ||
 		   rev == OMAP3430_REV_ES3_1_2) {
-		h = omap3430_es3plus_hwmods;
+		h = omap3430_es3plus_hwmod_ocp_ifs;
 	};
 
 	if (h)
-		r = omap_hwmod_register(h);
+		r = omap_hwmod_register_links(h);
 	if (r < 0)
 		return r;
 
 	/*
 	 * DSS code presumes that dss_core hwmod is handled first,
 	 * _before_ any other DSS related hwmods so register common
-	 * DSS hwmods last to ensure that dss_core is already registered.
-	 * Otherwise some change things may happen, for ex. if dispc
-	 * is handled before dss_core and DSS is enabled in bootloader
-	 * DIPSC will be reset with outputs enabled which sometimes leads
-	 * to unrecoverable L3 error.
-	 * XXX The long-term fix to this is to ensure modules are set up
-	 * in dependency order in the hwmod core code.
+	 * DSS hwmod links last to ensure that dss_core is already
+	 * registered.  Otherwise some change things may happen, for
+	 * ex. if dispc is handled before dss_core and DSS is enabled
+	 * in bootloader DISPC will be reset with outputs enabled
+	 * which sometimes leads to unrecoverable L3 error.  XXX The
+	 * long-term fix to this is to ensure hwmods are set up in
+	 * dependency order in the hwmod core code.
 	 */
-	r = omap_hwmod_register(omap3xxx_dss_hwmods);
+	r = omap_hwmod_register_links(omap3xxx_dss_hwmod_ocp_ifs);
 
 	return r;
 }
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 6abc757..950454a 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -1,7 +1,7 @@
 /*
  * Hardware modules present on the OMAP44xx chips
  *
- * Copyright (C) 2009-2011 Texas Instruments, Inc.
+ * Copyright (C) 2009-2012 Texas Instruments, Inc.
  * Copyright (C) 2009-2010 Nokia Corporation
  *
  * Paul Walmsley
@@ -44,41 +44,34 @@
 #define OMAP44XX_IRQ_GIC_START	32
 
 /* Base offset for all OMAP4 dma requests */
-#define OMAP44XX_DMA_REQ_START  1
-
-/* Backward references (IPs with Bus Master capability) */
-static struct omap_hwmod omap44xx_aess_hwmod;
-static struct omap_hwmod omap44xx_dma_system_hwmod;
-static struct omap_hwmod omap44xx_dmm_hwmod;
-static struct omap_hwmod omap44xx_dsp_hwmod;
-static struct omap_hwmod omap44xx_dss_hwmod;
-static struct omap_hwmod omap44xx_emif_fw_hwmod;
-static struct omap_hwmod omap44xx_hsi_hwmod;
-static struct omap_hwmod omap44xx_ipu_hwmod;
-static struct omap_hwmod omap44xx_iss_hwmod;
-static struct omap_hwmod omap44xx_iva_hwmod;
-static struct omap_hwmod omap44xx_l3_instr_hwmod;
-static struct omap_hwmod omap44xx_l3_main_1_hwmod;
-static struct omap_hwmod omap44xx_l3_main_2_hwmod;
-static struct omap_hwmod omap44xx_l3_main_3_hwmod;
-static struct omap_hwmod omap44xx_l4_abe_hwmod;
-static struct omap_hwmod omap44xx_l4_cfg_hwmod;
-static struct omap_hwmod omap44xx_l4_per_hwmod;
-static struct omap_hwmod omap44xx_l4_wkup_hwmod;
-static struct omap_hwmod omap44xx_mmc1_hwmod;
-static struct omap_hwmod omap44xx_mmc2_hwmod;
-static struct omap_hwmod omap44xx_mpu_hwmod;
-static struct omap_hwmod omap44xx_mpu_private_hwmod;
-static struct omap_hwmod omap44xx_usb_otg_hs_hwmod;
-static struct omap_hwmod omap44xx_usb_host_hs_hwmod;
-static struct omap_hwmod omap44xx_usb_tll_hs_hwmod;
+#define OMAP44XX_DMA_REQ_START	1
 
 /*
- * Interconnects omap_hwmod structures
- * hwmods that compose the global OMAP interconnect
+ * IP blocks
  */
 
 /*
+ * 'c2c_target_fw' class
+ * instance(s): c2c_target_fw
+ */
+static struct omap_hwmod_class omap44xx_c2c_target_fw_hwmod_class = {
+	.name	= "c2c_target_fw",
+};
+
+/* c2c_target_fw */
+static struct omap_hwmod omap44xx_c2c_target_fw_hwmod = {
+	.name		= "c2c_target_fw",
+	.class		= &omap44xx_c2c_target_fw_hwmod_class,
+	.clkdm_name	= "d2d_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_D2D_SAD2D_FW_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_D2D_SAD2D_FW_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
  * 'dmm' class
  * instance(s): dmm
  */
@@ -92,6 +85,3532 @@
 	{ .irq = -1 }
 };
 
+static struct omap_hwmod omap44xx_dmm_hwmod = {
+	.name		= "dmm",
+	.class		= &omap44xx_dmm_hwmod_class,
+	.clkdm_name	= "l3_emif_clkdm",
+	.mpu_irqs	= omap44xx_dmm_irqs,
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_MEMIF_DMM_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_MEMIF_DMM_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'emif_fw' class
+ * instance(s): emif_fw
+ */
+static struct omap_hwmod_class omap44xx_emif_fw_hwmod_class = {
+	.name	= "emif_fw",
+};
+
+/* emif_fw */
+static struct omap_hwmod omap44xx_emif_fw_hwmod = {
+	.name		= "emif_fw",
+	.class		= &omap44xx_emif_fw_hwmod_class,
+	.clkdm_name	= "l3_emif_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_MEMIF_EMIF_FW_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_MEMIF_EMIF_FW_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'l3' class
+ * instance(s): l3_instr, l3_main_1, l3_main_2, l3_main_3
+ */
+static struct omap_hwmod_class omap44xx_l3_hwmod_class = {
+	.name	= "l3",
+};
+
+/* l3_instr */
+static struct omap_hwmod omap44xx_l3_instr_hwmod = {
+	.name		= "l3_instr",
+	.class		= &omap44xx_l3_hwmod_class,
+	.clkdm_name	= "l3_instr_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INSTR_L3_INSTR_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/* l3_main_1 */
+static struct omap_hwmod_irq_info omap44xx_l3_main_1_irqs[] = {
+	{ .name = "dbg_err", .irq = 9 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "app_err", .irq = 10 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
+	.name		= "l3_main_1",
+	.class		= &omap44xx_l3_hwmod_class,
+	.clkdm_name	= "l3_1_clkdm",
+	.mpu_irqs	= omap44xx_l3_main_1_irqs,
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3_1_L3_1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/* l3_main_2 */
+static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
+	.name		= "l3_main_2",
+	.class		= &omap44xx_l3_hwmod_class,
+	.clkdm_name	= "l3_2_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3_2_L3_2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3_2_L3_2_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/* l3_main_3 */
+static struct omap_hwmod omap44xx_l3_main_3_hwmod = {
+	.name		= "l3_main_3",
+	.class		= &omap44xx_l3_hwmod_class,
+	.clkdm_name	= "l3_instr_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INSTR_L3_3_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INSTR_L3_3_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * 'l4' class
+ * instance(s): l4_abe, l4_cfg, l4_per, l4_wkup
+ */
+static struct omap_hwmod_class omap44xx_l4_hwmod_class = {
+	.name	= "l4",
+};
+
+/* l4_abe */
+static struct omap_hwmod omap44xx_l4_abe_hwmod = {
+	.name		= "l4_abe",
+	.class		= &omap44xx_l4_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_L4ABE_CLKCTRL_OFFSET,
+		},
+	},
+};
+
+/* l4_cfg */
+static struct omap_hwmod omap44xx_l4_cfg_hwmod = {
+	.name		= "l4_cfg",
+	.class		= &omap44xx_l4_hwmod_class,
+	.clkdm_name	= "l4_cfg_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4CFG_L4_CFG_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/* l4_per */
+static struct omap_hwmod omap44xx_l4_per_hwmod = {
+	.name		= "l4_per",
+	.class		= &omap44xx_l4_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_L4PER_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_L4_PER_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/* l4_wkup */
+static struct omap_hwmod omap44xx_l4_wkup_hwmod = {
+	.name		= "l4_wkup",
+	.class		= &omap44xx_l4_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_WKUP_L4WKUP_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_WKUP_L4WKUP_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'mpu_bus' class
+ * instance(s): mpu_private
+ */
+static struct omap_hwmod_class omap44xx_mpu_bus_hwmod_class = {
+	.name	= "mpu_bus",
+};
+
+/* mpu_private */
+static struct omap_hwmod omap44xx_mpu_private_hwmod = {
+	.name		= "mpu_private",
+	.class		= &omap44xx_mpu_bus_hwmod_class,
+	.clkdm_name	= "mpuss_clkdm",
+};
+
+/*
+ * 'ocp_wp_noc' class
+ * instance(s): ocp_wp_noc
+ */
+static struct omap_hwmod_class omap44xx_ocp_wp_noc_hwmod_class = {
+	.name	= "ocp_wp_noc",
+};
+
+/* ocp_wp_noc */
+static struct omap_hwmod omap44xx_ocp_wp_noc_hwmod = {
+	.name		= "ocp_wp_noc",
+	.class		= &omap44xx_ocp_wp_noc_hwmod_class,
+	.clkdm_name	= "l3_instr_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INSTR_OCP_WP1_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * Modules omap_hwmod structures
+ *
+ * The following IPs are excluded for the moment because:
+ * - They do not need an explicit SW control using omap_hwmod API.
+ * - They still need to be validated with the driver
+ *   properly adapted to omap_hwmod / omap_device
+ *
+ * usim
+ */
+
+/*
+ * 'aess' class
+ * audio engine sub system
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_aess_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART |
+			   MSTANDBY_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_aess_hwmod_class = {
+	.name	= "aess",
+	.sysc	= &omap44xx_aess_sysc,
+};
+
+/* aess */
+static struct omap_hwmod_irq_info omap44xx_aess_irqs[] = {
+	{ .irq = 99 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_aess_sdma_reqs[] = {
+	{ .name = "fifo0", .dma_req = 100 + OMAP44XX_DMA_REQ_START },
+	{ .name = "fifo1", .dma_req = 101 + OMAP44XX_DMA_REQ_START },
+	{ .name = "fifo2", .dma_req = 102 + OMAP44XX_DMA_REQ_START },
+	{ .name = "fifo3", .dma_req = 103 + OMAP44XX_DMA_REQ_START },
+	{ .name = "fifo4", .dma_req = 104 + OMAP44XX_DMA_REQ_START },
+	{ .name = "fifo5", .dma_req = 105 + OMAP44XX_DMA_REQ_START },
+	{ .name = "fifo6", .dma_req = 106 + OMAP44XX_DMA_REQ_START },
+	{ .name = "fifo7", .dma_req = 107 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_aess_hwmod = {
+	.name		= "aess",
+	.class		= &omap44xx_aess_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_aess_irqs,
+	.sdma_reqs	= omap44xx_aess_sdma_reqs,
+	.main_clk	= "aess_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_AESS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_AESS_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'c2c' class
+ * chip 2 chip interface used to plug the ape soc (omap) with an external modem
+ * soc
+ */
+
+static struct omap_hwmod_class omap44xx_c2c_hwmod_class = {
+	.name	= "c2c",
+};
+
+/* c2c */
+static struct omap_hwmod_irq_info omap44xx_c2c_irqs[] = {
+	{ .irq = 88 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_c2c_sdma_reqs[] = {
+	{ .dma_req = 68 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_c2c_hwmod = {
+	.name		= "c2c",
+	.class		= &omap44xx_c2c_hwmod_class,
+	.clkdm_name	= "d2d_clkdm",
+	.mpu_irqs	= omap44xx_c2c_irqs,
+	.sdma_reqs	= omap44xx_c2c_sdma_reqs,
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_D2D_SAD2D_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_D2D_SAD2D_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'counter' class
+ * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_counter_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0004,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE,
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_counter_hwmod_class = {
+	.name	= "counter",
+	.sysc	= &omap44xx_counter_sysc,
+};
+
+/* counter_32k */
+static struct omap_hwmod omap44xx_counter_32k_hwmod = {
+	.name		= "counter_32k",
+	.class		= &omap44xx_counter_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.flags		= HWMOD_SWSUP_SIDLE,
+	.main_clk	= "sys_32k_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_WKUP_SYNCTIMER_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_WKUP_SYNCTIMER_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'ctrl_module' class
+ * attila core control module + core pad control module + wkup pad control
+ * module + attila wkup control module
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_ctrl_module_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE,
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_ctrl_module_hwmod_class = {
+	.name	= "ctrl_module",
+	.sysc	= &omap44xx_ctrl_module_sysc,
+};
+
+/* ctrl_module_core */
+static struct omap_hwmod_irq_info omap44xx_ctrl_module_core_irqs[] = {
+	{ .irq = 8 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_ctrl_module_core_hwmod = {
+	.name		= "ctrl_module_core",
+	.class		= &omap44xx_ctrl_module_hwmod_class,
+	.clkdm_name	= "l4_cfg_clkdm",
+	.mpu_irqs	= omap44xx_ctrl_module_core_irqs,
+};
+
+/* ctrl_module_pad_core */
+static struct omap_hwmod omap44xx_ctrl_module_pad_core_hwmod = {
+	.name		= "ctrl_module_pad_core",
+	.class		= &omap44xx_ctrl_module_hwmod_class,
+	.clkdm_name	= "l4_cfg_clkdm",
+};
+
+/* ctrl_module_wkup */
+static struct omap_hwmod omap44xx_ctrl_module_wkup_hwmod = {
+	.name		= "ctrl_module_wkup",
+	.class		= &omap44xx_ctrl_module_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+};
+
+/* ctrl_module_pad_wkup */
+static struct omap_hwmod omap44xx_ctrl_module_pad_wkup_hwmod = {
+	.name		= "ctrl_module_pad_wkup",
+	.class		= &omap44xx_ctrl_module_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+};
+
+/*
+ * 'debugss' class
+ * debug and emulation sub system
+ */
+
+static struct omap_hwmod_class omap44xx_debugss_hwmod_class = {
+	.name	= "debugss",
+};
+
+/* debugss */
+static struct omap_hwmod omap44xx_debugss_hwmod = {
+	.name		= "debugss",
+	.class		= &omap44xx_debugss_hwmod_class,
+	.clkdm_name	= "emu_sys_clkdm",
+	.main_clk	= "trace_clk_div_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_EMU_DEBUGSS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_EMU_DEBUGSS_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'dma' class
+ * dma controller for data exchange between memory to memory (i.e. internal or
+ * external memory) and gp peripherals to memory or memory to gp peripherals
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_dma_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x002c,
+	.syss_offs	= 0x0028,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_dma_hwmod_class = {
+	.name	= "dma",
+	.sysc	= &omap44xx_dma_sysc,
+};
+
+/* dma dev_attr */
+static struct omap_dma_dev_attr dma_dev_attr = {
+	.dev_caps	= RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY |
+			  IS_CSSA_32 | IS_CDSA_32 | IS_RW_PRIORITY,
+	.lch_count	= 32,
+};
+
+/* dma_system */
+static struct omap_hwmod_irq_info omap44xx_dma_system_irqs[] = {
+	{ .name = "0", .irq = 12 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "1", .irq = 13 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "2", .irq = 14 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "3", .irq = 15 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_dma_system_hwmod = {
+	.name		= "dma_system",
+	.class		= &omap44xx_dma_hwmod_class,
+	.clkdm_name	= "l3_dma_clkdm",
+	.mpu_irqs	= omap44xx_dma_system_irqs,
+	.main_clk	= "l3_div_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_SDMA_SDMA_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_SDMA_SDMA_CONTEXT_OFFSET,
+		},
+	},
+	.dev_attr	= &dma_dev_attr,
+};
+
+/*
+ * 'dmic' class
+ * digital microphone controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_dmic_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_dmic_hwmod_class = {
+	.name	= "dmic",
+	.sysc	= &omap44xx_dmic_sysc,
+};
+
+/* dmic */
+static struct omap_hwmod_irq_info omap44xx_dmic_irqs[] = {
+	{ .irq = 114 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_dmic_sdma_reqs[] = {
+	{ .dma_req = 66 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_dmic_hwmod = {
+	.name		= "dmic",
+	.class		= &omap44xx_dmic_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_dmic_irqs,
+	.sdma_reqs	= omap44xx_dmic_sdma_reqs,
+	.main_clk	= "dmic_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_DMIC_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_DMIC_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'dsp' class
+ * dsp sub-system
+ */
+
+static struct omap_hwmod_class omap44xx_dsp_hwmod_class = {
+	.name	= "dsp",
+};
+
+/* dsp */
+static struct omap_hwmod_irq_info omap44xx_dsp_irqs[] = {
+	{ .irq = 28 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_rst_info omap44xx_dsp_resets[] = {
+	{ .name = "dsp", .rst_shift = 0 },
+	{ .name = "mmu_cache", .rst_shift = 1 },
+};
+
+static struct omap_hwmod omap44xx_dsp_hwmod = {
+	.name		= "dsp",
+	.class		= &omap44xx_dsp_hwmod_class,
+	.clkdm_name	= "tesla_clkdm",
+	.mpu_irqs	= omap44xx_dsp_irqs,
+	.rst_lines	= omap44xx_dsp_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_dsp_resets),
+	.main_clk	= "dsp_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_TESLA_TESLA_CLKCTRL_OFFSET,
+			.rstctrl_offs = OMAP4_RM_TESLA_RSTCTRL_OFFSET,
+			.context_offs = OMAP4_RM_TESLA_TESLA_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * 'dss' class
+ * display sub-system
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_dss_sysc = {
+	.rev_offs	= 0x0000,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= SYSS_HAS_RESET_STATUS,
+};
+
+static struct omap_hwmod_class omap44xx_dss_hwmod_class = {
+	.name	= "dss",
+	.sysc	= &omap44xx_dss_sysc,
+	.reset	= omap_dss_reset,
+};
+
+/* dss */
+static struct omap_hwmod_opt_clk dss_opt_clks[] = {
+	{ .role = "sys_clk", .clk = "dss_sys_clk" },
+	{ .role = "tv_clk", .clk = "dss_tv_clk" },
+	{ .role = "hdmi_clk", .clk = "dss_48mhz_clk" },
+};
+
+static struct omap_hwmod omap44xx_dss_hwmod = {
+	.name		= "dss_core",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.class		= &omap44xx_dss_hwmod_class,
+	.clkdm_name	= "l3_dss_clkdm",
+	.main_clk	= "dss_dss_clk",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+		},
+	},
+	.opt_clks	= dss_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dss_opt_clks),
+};
+
+/*
+ * 'dispc' class
+ * display controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_dispc_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_MIDLEMODE |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_dispc_hwmod_class = {
+	.name	= "dispc",
+	.sysc	= &omap44xx_dispc_sysc,
+};
+
+/* dss_dispc */
+static struct omap_hwmod_irq_info omap44xx_dss_dispc_irqs[] = {
+	{ .irq = 25 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_dss_dispc_sdma_reqs[] = {
+	{ .dma_req = 5 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_dss_dispc_dev_attr omap44xx_dss_dispc_dev_attr = {
+	.manager_count		= 3,
+	.has_framedonetv_irq	= 1
+};
+
+static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
+	.name		= "dss_dispc",
+	.class		= &omap44xx_dispc_hwmod_class,
+	.clkdm_name	= "l3_dss_clkdm",
+	.mpu_irqs	= omap44xx_dss_dispc_irqs,
+	.sdma_reqs	= omap44xx_dss_dispc_sdma_reqs,
+	.main_clk	= "dss_dss_clk",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+		},
+	},
+	.dev_attr	= &omap44xx_dss_dispc_dev_attr
+};
+
+/*
+ * 'dsi' class
+ * display serial interface controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_dsi_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_dsi_hwmod_class = {
+	.name	= "dsi",
+	.sysc	= &omap44xx_dsi_sysc,
+};
+
+/* dss_dsi1 */
+static struct omap_hwmod_irq_info omap44xx_dss_dsi1_irqs[] = {
+	{ .irq = 53 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_dss_dsi1_sdma_reqs[] = {
+	{ .dma_req = 74 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk dss_dsi1_opt_clks[] = {
+	{ .role = "sys_clk", .clk = "dss_sys_clk" },
+};
+
+static struct omap_hwmod omap44xx_dss_dsi1_hwmod = {
+	.name		= "dss_dsi1",
+	.class		= &omap44xx_dsi_hwmod_class,
+	.clkdm_name	= "l3_dss_clkdm",
+	.mpu_irqs	= omap44xx_dss_dsi1_irqs,
+	.sdma_reqs	= omap44xx_dss_dsi1_sdma_reqs,
+	.main_clk	= "dss_dss_clk",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+		},
+	},
+	.opt_clks	= dss_dsi1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dss_dsi1_opt_clks),
+};
+
+/* dss_dsi2 */
+static struct omap_hwmod_irq_info omap44xx_dss_dsi2_irqs[] = {
+	{ .irq = 84 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_dss_dsi2_sdma_reqs[] = {
+	{ .dma_req = 83 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk dss_dsi2_opt_clks[] = {
+	{ .role = "sys_clk", .clk = "dss_sys_clk" },
+};
+
+static struct omap_hwmod omap44xx_dss_dsi2_hwmod = {
+	.name		= "dss_dsi2",
+	.class		= &omap44xx_dsi_hwmod_class,
+	.clkdm_name	= "l3_dss_clkdm",
+	.mpu_irqs	= omap44xx_dss_dsi2_irqs,
+	.sdma_reqs	= omap44xx_dss_dsi2_sdma_reqs,
+	.main_clk	= "dss_dss_clk",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+		},
+	},
+	.opt_clks	= dss_dsi2_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dss_dsi2_opt_clks),
+};
+
+/*
+ * 'hdmi' class
+ * hdmi controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_hdmi_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_hdmi_hwmod_class = {
+	.name	= "hdmi",
+	.sysc	= &omap44xx_hdmi_sysc,
+};
+
+/* dss_hdmi */
+static struct omap_hwmod_irq_info omap44xx_dss_hdmi_irqs[] = {
+	{ .irq = 101 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_dss_hdmi_sdma_reqs[] = {
+	{ .dma_req = 75 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk dss_hdmi_opt_clks[] = {
+	{ .role = "sys_clk", .clk = "dss_sys_clk" },
+};
+
+static struct omap_hwmod omap44xx_dss_hdmi_hwmod = {
+	.name		= "dss_hdmi",
+	.class		= &omap44xx_hdmi_hwmod_class,
+	.clkdm_name	= "l3_dss_clkdm",
+	.mpu_irqs	= omap44xx_dss_hdmi_irqs,
+	.sdma_reqs	= omap44xx_dss_hdmi_sdma_reqs,
+	.main_clk	= "dss_48mhz_clk",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+		},
+	},
+	.opt_clks	= dss_hdmi_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dss_hdmi_opt_clks),
+};
+
+/*
+ * 'rfbi' class
+ * remote frame buffer interface
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_rfbi_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_rfbi_hwmod_class = {
+	.name	= "rfbi",
+	.sysc	= &omap44xx_rfbi_sysc,
+};
+
+/* dss_rfbi */
+static struct omap_hwmod_dma_info omap44xx_dss_rfbi_sdma_reqs[] = {
+	{ .dma_req = 13 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
+	{ .role = "ick", .clk = "dss_fck" },
+};
+
+static struct omap_hwmod omap44xx_dss_rfbi_hwmod = {
+	.name		= "dss_rfbi",
+	.class		= &omap44xx_rfbi_hwmod_class,
+	.clkdm_name	= "l3_dss_clkdm",
+	.sdma_reqs	= omap44xx_dss_rfbi_sdma_reqs,
+	.main_clk	= "dss_dss_clk",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+		},
+	},
+	.opt_clks	= dss_rfbi_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dss_rfbi_opt_clks),
+};
+
+/*
+ * 'venc' class
+ * video encoder
+ */
+
+static struct omap_hwmod_class omap44xx_venc_hwmod_class = {
+	.name	= "venc",
+};
+
+/* dss_venc */
+static struct omap_hwmod omap44xx_dss_venc_hwmod = {
+	.name		= "dss_venc",
+	.class		= &omap44xx_venc_hwmod_class,
+	.clkdm_name	= "l3_dss_clkdm",
+	.main_clk	= "dss_tv_clk",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'elm' class
+ * bch error location module
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_elm_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_elm_hwmod_class = {
+	.name	= "elm",
+	.sysc	= &omap44xx_elm_sysc,
+};
+
+/* elm */
+static struct omap_hwmod_irq_info omap44xx_elm_irqs[] = {
+	{ .irq = 4 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_elm_hwmod = {
+	.name		= "elm",
+	.class		= &omap44xx_elm_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_elm_irqs,
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_ELM_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_ELM_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'emif' class
+ * external memory interface no1
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_emif_sysc = {
+	.rev_offs	= 0x0000,
+};
+
+static struct omap_hwmod_class omap44xx_emif_hwmod_class = {
+	.name	= "emif",
+	.sysc	= &omap44xx_emif_sysc,
+};
+
+/* emif1 */
+static struct omap_hwmod_irq_info omap44xx_emif1_irqs[] = {
+	{ .irq = 110 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_emif1_hwmod = {
+	.name		= "emif1",
+	.class		= &omap44xx_emif_hwmod_class,
+	.clkdm_name	= "l3_emif_clkdm",
+	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+	.mpu_irqs	= omap44xx_emif1_irqs,
+	.main_clk	= "ddrphy_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_MEMIF_EMIF_1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_MEMIF_EMIF_1_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/* emif2 */
+static struct omap_hwmod_irq_info omap44xx_emif2_irqs[] = {
+	{ .irq = 111 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_emif2_hwmod = {
+	.name		= "emif2",
+	.class		= &omap44xx_emif_hwmod_class,
+	.clkdm_name	= "l3_emif_clkdm",
+	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+	.mpu_irqs	= omap44xx_emif2_irqs,
+	.main_clk	= "ddrphy_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_MEMIF_EMIF_2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_MEMIF_EMIF_2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * 'fdif' class
+ * face detection hw accelerator module
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_fdif_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	/*
+	 * FDIF needs 100 OCP clk cycles delay after a softreset before
+	 * accessing sysconfig again.
+	 * The lowest frequency at the moment for L3 bus is 100 MHz, so
+	 * 1usec delay is needed. Add an x2 margin to be safe (2 usecs).
+	 *
+	 * TODO: Indicate errata when available.
+	 */
+	.srst_udelay	= 2,
+	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_fdif_hwmod_class = {
+	.name	= "fdif",
+	.sysc	= &omap44xx_fdif_sysc,
+};
+
+/* fdif */
+static struct omap_hwmod_irq_info omap44xx_fdif_irqs[] = {
+	{ .irq = 69 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_fdif_hwmod = {
+	.name		= "fdif",
+	.class		= &omap44xx_fdif_hwmod_class,
+	.clkdm_name	= "iss_clkdm",
+	.mpu_irqs	= omap44xx_fdif_irqs,
+	.main_clk	= "fdif_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_CAM_FDIF_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_CAM_FDIF_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'gpio' class
+ * general purpose io module
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_gpio_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0114,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_gpio_hwmod_class = {
+	.name	= "gpio",
+	.sysc	= &omap44xx_gpio_sysc,
+	.rev	= 2,
+};
+
+/* gpio dev_attr */
+static struct omap_gpio_dev_attr gpio_dev_attr = {
+	.bank_width	= 32,
+	.dbck_flag	= true,
+};
+
+/* gpio1 */
+static struct omap_hwmod_irq_info omap44xx_gpio1_irqs[] = {
+	{ .irq = 29 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio1_dbclk" },
+};
+
+static struct omap_hwmod omap44xx_gpio1_hwmod = {
+	.name		= "gpio1",
+	.class		= &omap44xx_gpio_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= omap44xx_gpio1_irqs,
+	.main_clk	= "gpio1_ick",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_WKUP_GPIO1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_WKUP_GPIO1_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+	.opt_clks	= gpio1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio2 */
+static struct omap_hwmod_irq_info omap44xx_gpio2_irqs[] = {
+	{ .irq = 30 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio2_dbclk" },
+};
+
+static struct omap_hwmod omap44xx_gpio2_hwmod = {
+	.name		= "gpio2",
+	.class		= &omap44xx_gpio_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap44xx_gpio2_irqs,
+	.main_clk	= "gpio2_ick",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_GPIO2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+	.opt_clks	= gpio2_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio3 */
+static struct omap_hwmod_irq_info omap44xx_gpio3_irqs[] = {
+	{ .irq = 31 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio3_dbclk" },
+};
+
+static struct omap_hwmod omap44xx_gpio3_hwmod = {
+	.name		= "gpio3",
+	.class		= &omap44xx_gpio_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap44xx_gpio3_irqs,
+	.main_clk	= "gpio3_ick",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_GPIO3_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+	.opt_clks	= gpio3_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio3_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio4 */
+static struct omap_hwmod_irq_info omap44xx_gpio4_irqs[] = {
+	{ .irq = 32 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio4_dbclk" },
+};
+
+static struct omap_hwmod omap44xx_gpio4_hwmod = {
+	.name		= "gpio4",
+	.class		= &omap44xx_gpio_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap44xx_gpio4_irqs,
+	.main_clk	= "gpio4_ick",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_GPIO4_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+	.opt_clks	= gpio4_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio4_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio5 */
+static struct omap_hwmod_irq_info omap44xx_gpio5_irqs[] = {
+	{ .irq = 33 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio5_dbclk" },
+};
+
+static struct omap_hwmod omap44xx_gpio5_hwmod = {
+	.name		= "gpio5",
+	.class		= &omap44xx_gpio_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap44xx_gpio5_irqs,
+	.main_clk	= "gpio5_ick",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_GPIO5_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+	.opt_clks	= gpio5_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio5_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio6 */
+static struct omap_hwmod_irq_info omap44xx_gpio6_irqs[] = {
+	{ .irq = 34 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio6_dbclk" },
+};
+
+static struct omap_hwmod omap44xx_gpio6_hwmod = {
+	.name		= "gpio6",
+	.class		= &omap44xx_gpio_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= omap44xx_gpio6_irqs,
+	.main_clk	= "gpio6_ick",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_GPIO6_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+	.opt_clks	= gpio6_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio6_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/*
+ * 'gpmc' class
+ * general purpose memory controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_gpmc_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_gpmc_hwmod_class = {
+	.name	= "gpmc",
+	.sysc	= &omap44xx_gpmc_sysc,
+};
+
+/* gpmc */
+static struct omap_hwmod_irq_info omap44xx_gpmc_irqs[] = {
+	{ .irq = 20 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_gpmc_sdma_reqs[] = {
+	{ .dma_req = 3 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_gpmc_hwmod = {
+	.name		= "gpmc",
+	.class		= &omap44xx_gpmc_hwmod_class,
+	.clkdm_name	= "l3_2_clkdm",
+	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+	.mpu_irqs	= omap44xx_gpmc_irqs,
+	.sdma_reqs	= omap44xx_gpmc_sdma_reqs,
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3_2_GPMC_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3_2_GPMC_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * 'gpu' class
+ * 2d/3d graphics accelerator
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_gpu_sysc = {
+	.rev_offs	= 0x1fc00,
+	.sysc_offs	= 0x1fc10,
+	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+			   MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_gpu_hwmod_class = {
+	.name	= "gpu",
+	.sysc	= &omap44xx_gpu_sysc,
+};
+
+/* gpu */
+static struct omap_hwmod_irq_info omap44xx_gpu_irqs[] = {
+	{ .irq = 21 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_gpu_hwmod = {
+	.name		= "gpu",
+	.class		= &omap44xx_gpu_hwmod_class,
+	.clkdm_name	= "l3_gfx_clkdm",
+	.mpu_irqs	= omap44xx_gpu_irqs,
+	.main_clk	= "gpu_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_GFX_GFX_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_GFX_GFX_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'hdq1w' class
+ * hdq / 1-wire serial interface controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_hdq1w_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0014,
+	.syss_offs	= 0x0018,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_SOFTRESET |
+			   SYSS_HAS_RESET_STATUS),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_hdq1w_hwmod_class = {
+	.name	= "hdq1w",
+	.sysc	= &omap44xx_hdq1w_sysc,
+};
+
+/* hdq1w */
+static struct omap_hwmod_irq_info omap44xx_hdq1w_irqs[] = {
+	{ .irq = 58 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_hdq1w_hwmod = {
+	.name		= "hdq1w",
+	.class		= &omap44xx_hdq1w_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_INIT_NO_RESET, /* XXX temporary */
+	.mpu_irqs	= omap44xx_hdq1w_irqs,
+	.main_clk	= "hdq1w_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_HDQ1W_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_HDQ1W_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'hsi' class
+ * mipi high-speed synchronous serial interface (multichannel and full-duplex
+ * serial if)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_hsi_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_EMUFREE |
+			   SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+			   MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_hsi_hwmod_class = {
+	.name	= "hsi",
+	.sysc	= &omap44xx_hsi_sysc,
+};
+
+/* hsi */
+static struct omap_hwmod_irq_info omap44xx_hsi_irqs[] = {
+	{ .name = "mpu_p1", .irq = 67 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "mpu_p2", .irq = 68 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "mpu_dma", .irq = 71 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_hsi_hwmod = {
+	.name		= "hsi",
+	.class		= &omap44xx_hsi_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.mpu_irqs	= omap44xx_hsi_irqs,
+	.main_clk	= "hsi_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INIT_HSI_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INIT_HSI_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * 'i2c' class
+ * multimaster high-speed i2c controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_i2c_sysc = {
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0090,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.clockact	= CLOCKACT_TEST_ICLK,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_i2c_hwmod_class = {
+	.name	= "i2c",
+	.sysc	= &omap44xx_i2c_sysc,
+	.rev	= OMAP_I2C_IP_VERSION_2,
+	.reset	= &omap_i2c_reset,
+};
+
+static struct omap_i2c_dev_attr i2c_dev_attr = {
+	.flags	= OMAP_I2C_FLAG_BUS_SHIFT_NONE |
+			OMAP_I2C_FLAG_RESET_REGS_POSTIDLE,
+};
+
+/* i2c1 */
+static struct omap_hwmod_irq_info omap44xx_i2c1_irqs[] = {
+	{ .irq = 56 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_i2c1_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 26 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 27 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_i2c1_hwmod = {
+	.name		= "i2c1",
+	.class		= &omap44xx_i2c_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.mpu_irqs	= omap44xx_i2c1_irqs,
+	.sdma_reqs	= omap44xx_i2c1_sdma_reqs,
+	.main_clk	= "i2c1_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_I2C1_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &i2c_dev_attr,
+};
+
+/* i2c2 */
+static struct omap_hwmod_irq_info omap44xx_i2c2_irqs[] = {
+	{ .irq = 57 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_i2c2_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 28 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 29 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_i2c2_hwmod = {
+	.name		= "i2c2",
+	.class		= &omap44xx_i2c_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.mpu_irqs	= omap44xx_i2c2_irqs,
+	.sdma_reqs	= omap44xx_i2c2_sdma_reqs,
+	.main_clk	= "i2c2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_I2C2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &i2c_dev_attr,
+};
+
+/* i2c3 */
+static struct omap_hwmod_irq_info omap44xx_i2c3_irqs[] = {
+	{ .irq = 61 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_i2c3_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 24 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 25 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_i2c3_hwmod = {
+	.name		= "i2c3",
+	.class		= &omap44xx_i2c_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.mpu_irqs	= omap44xx_i2c3_irqs,
+	.sdma_reqs	= omap44xx_i2c3_sdma_reqs,
+	.main_clk	= "i2c3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_I2C3_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &i2c_dev_attr,
+};
+
+/* i2c4 */
+static struct omap_hwmod_irq_info omap44xx_i2c4_irqs[] = {
+	{ .irq = 62 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_i2c4_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 123 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 124 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_i2c4_hwmod = {
+	.name		= "i2c4",
+	.class		= &omap44xx_i2c_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.mpu_irqs	= omap44xx_i2c4_irqs,
+	.sdma_reqs	= omap44xx_i2c4_sdma_reqs,
+	.main_clk	= "i2c4_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_I2C4_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &i2c_dev_attr,
+};
+
+/*
+ * 'ipu' class
+ * imaging processor unit
+ */
+
+static struct omap_hwmod_class omap44xx_ipu_hwmod_class = {
+	.name	= "ipu",
+};
+
+/* ipu */
+static struct omap_hwmod_irq_info omap44xx_ipu_irqs[] = {
+	{ .irq = 100 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_rst_info omap44xx_ipu_resets[] = {
+	{ .name = "cpu0", .rst_shift = 0 },
+	{ .name = "cpu1", .rst_shift = 1 },
+	{ .name = "mmu_cache", .rst_shift = 2 },
+};
+
+static struct omap_hwmod omap44xx_ipu_hwmod = {
+	.name		= "ipu",
+	.class		= &omap44xx_ipu_hwmod_class,
+	.clkdm_name	= "ducati_clkdm",
+	.mpu_irqs	= omap44xx_ipu_irqs,
+	.rst_lines	= omap44xx_ipu_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_ipu_resets),
+	.main_clk	= "ipu_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET,
+			.rstctrl_offs = OMAP4_RM_DUCATI_RSTCTRL_OFFSET,
+			.context_offs = OMAP4_RM_DUCATI_DUCATI_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * 'iss' class
+ * external images sensor pixel data processor
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_iss_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	/*
+	 * ISS needs 100 OCP clk cycles delay after a softreset before
+	 * accessing sysconfig again.
+	 * The lowest frequency at the moment for L3 bus is 100 MHz, so
+	 * 1usec delay is needed. Add an x2 margin to be safe (2 usecs).
+	 *
+	 * TODO: Indicate errata when available.
+	 */
+	.srst_udelay	= 2,
+	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+			   MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_iss_hwmod_class = {
+	.name	= "iss",
+	.sysc	= &omap44xx_iss_sysc,
+};
+
+/* iss */
+static struct omap_hwmod_irq_info omap44xx_iss_irqs[] = {
+	{ .irq = 24 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_iss_sdma_reqs[] = {
+	{ .name = "1", .dma_req = 8 + OMAP44XX_DMA_REQ_START },
+	{ .name = "2", .dma_req = 9 + OMAP44XX_DMA_REQ_START },
+	{ .name = "3", .dma_req = 11 + OMAP44XX_DMA_REQ_START },
+	{ .name = "4", .dma_req = 12 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk iss_opt_clks[] = {
+	{ .role = "ctrlclk", .clk = "iss_ctrlclk" },
+};
+
+static struct omap_hwmod omap44xx_iss_hwmod = {
+	.name		= "iss",
+	.class		= &omap44xx_iss_hwmod_class,
+	.clkdm_name	= "iss_clkdm",
+	.mpu_irqs	= omap44xx_iss_irqs,
+	.sdma_reqs	= omap44xx_iss_sdma_reqs,
+	.main_clk	= "iss_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_CAM_ISS_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= iss_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(iss_opt_clks),
+};
+
+/*
+ * 'iva' class
+ * multi-standard video encoder/decoder hardware accelerator
+ */
+
+static struct omap_hwmod_class omap44xx_iva_hwmod_class = {
+	.name	= "iva",
+};
+
+/* iva */
+static struct omap_hwmod_irq_info omap44xx_iva_irqs[] = {
+	{ .name = "sync_1", .irq = 103 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "sync_0", .irq = 104 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "mailbox_0", .irq = 107 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_rst_info omap44xx_iva_resets[] = {
+	{ .name = "seq0", .rst_shift = 0 },
+	{ .name = "seq1", .rst_shift = 1 },
+	{ .name = "logic", .rst_shift = 2 },
+};
+
+static struct omap_hwmod omap44xx_iva_hwmod = {
+	.name		= "iva",
+	.class		= &omap44xx_iva_hwmod_class,
+	.clkdm_name	= "ivahd_clkdm",
+	.mpu_irqs	= omap44xx_iva_irqs,
+	.rst_lines	= omap44xx_iva_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_iva_resets),
+	.main_clk	= "iva_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_IVAHD_IVAHD_CLKCTRL_OFFSET,
+			.rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET,
+			.context_offs = OMAP4_RM_IVAHD_IVAHD_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * 'kbd' class
+ * keyboard controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_kbd_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_EMUFREE | SYSC_HAS_ENAWAKEUP |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_kbd_hwmod_class = {
+	.name	= "kbd",
+	.sysc	= &omap44xx_kbd_sysc,
+};
+
+/* kbd */
+static struct omap_hwmod_irq_info omap44xx_kbd_irqs[] = {
+	{ .irq = 120 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_kbd_hwmod = {
+	.name		= "kbd",
+	.class		= &omap44xx_kbd_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= omap44xx_kbd_irqs,
+	.main_clk	= "kbd_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_WKUP_KEYBOARD_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_WKUP_KEYBOARD_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'mailbox' class
+ * mailbox module allowing communication between the on-chip processors using a
+ * queued mailbox-interrupt mechanism.
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mailbox_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_mailbox_hwmod_class = {
+	.name	= "mailbox",
+	.sysc	= &omap44xx_mailbox_sysc,
+};
+
+/* mailbox */
+static struct omap_hwmod_irq_info omap44xx_mailbox_irqs[] = {
+	{ .irq = 26 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_mailbox_hwmod = {
+	.name		= "mailbox",
+	.class		= &omap44xx_mailbox_hwmod_class,
+	.clkdm_name	= "l4_cfg_clkdm",
+	.mpu_irqs	= omap44xx_mailbox_irqs,
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4CFG_MAILBOX_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4CFG_MAILBOX_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'mcasp' class
+ * multi-channel audio serial port controller
+ */
+
+/* The IP is not compliant to type1 / type2 scheme */
+static struct omap_hwmod_sysc_fields omap_hwmod_sysc_type_mcasp = {
+	.sidle_shift	= 0,
+};
+
+static struct omap_hwmod_class_sysconfig omap44xx_mcasp_sysc = {
+	.sysc_offs	= 0x0004,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE,
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type_mcasp,
+};
+
+static struct omap_hwmod_class omap44xx_mcasp_hwmod_class = {
+	.name	= "mcasp",
+	.sysc	= &omap44xx_mcasp_sysc,
+};
+
+/* mcasp */
+static struct omap_hwmod_irq_info omap44xx_mcasp_irqs[] = {
+	{ .name = "arevt", .irq = 108 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "axevt", .irq = 109 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcasp_sdma_reqs[] = {
+	{ .name = "axevt", .dma_req = 7 + OMAP44XX_DMA_REQ_START },
+	{ .name = "arevt", .dma_req = 10 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_mcasp_hwmod = {
+	.name		= "mcasp",
+	.class		= &omap44xx_mcasp_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_mcasp_irqs,
+	.sdma_reqs	= omap44xx_mcasp_sdma_reqs,
+	.main_clk	= "mcasp_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_MCASP_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_MCASP_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'mcbsp' class
+ * multi channel buffered serial port controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mcbsp_sysc = {
+	.sysc_offs	= 0x008c,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_ENAWAKEUP |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_mcbsp_hwmod_class = {
+	.name	= "mcbsp",
+	.sysc	= &omap44xx_mcbsp_sysc,
+	.rev	= MCBSP_CONFIG_TYPE4,
+};
+
+/* mcbsp1 */
+static struct omap_hwmod_irq_info omap44xx_mcbsp1_irqs[] = {
+	{ .name = "common", .irq = 17 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcbsp1_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 32 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 33 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk mcbsp1_opt_clks[] = {
+	{ .role = "pad_fck", .clk = "pad_clks_ck" },
+	{ .role = "prcm_clk", .clk = "mcbsp1_sync_mux_ck" },
+};
+
+static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
+	.name		= "mcbsp1",
+	.class		= &omap44xx_mcbsp_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_mcbsp1_irqs,
+	.sdma_reqs	= omap44xx_mcbsp1_sdma_reqs,
+	.main_clk	= "mcbsp1_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_MCBSP1_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= mcbsp1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(mcbsp1_opt_clks),
+};
+
+/* mcbsp2 */
+static struct omap_hwmod_irq_info omap44xx_mcbsp2_irqs[] = {
+	{ .name = "common", .irq = 22 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcbsp2_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 16 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 17 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk mcbsp2_opt_clks[] = {
+	{ .role = "pad_fck", .clk = "pad_clks_ck" },
+	{ .role = "prcm_clk", .clk = "mcbsp2_sync_mux_ck" },
+};
+
+static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
+	.name		= "mcbsp2",
+	.class		= &omap44xx_mcbsp_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_mcbsp2_irqs,
+	.sdma_reqs	= omap44xx_mcbsp2_sdma_reqs,
+	.main_clk	= "mcbsp2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_MCBSP2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= mcbsp2_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(mcbsp2_opt_clks),
+};
+
+/* mcbsp3 */
+static struct omap_hwmod_irq_info omap44xx_mcbsp3_irqs[] = {
+	{ .name = "common", .irq = 23 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcbsp3_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 18 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 19 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk mcbsp3_opt_clks[] = {
+	{ .role = "pad_fck", .clk = "pad_clks_ck" },
+	{ .role = "prcm_clk", .clk = "mcbsp3_sync_mux_ck" },
+};
+
+static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
+	.name		= "mcbsp3",
+	.class		= &omap44xx_mcbsp_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_mcbsp3_irqs,
+	.sdma_reqs	= omap44xx_mcbsp3_sdma_reqs,
+	.main_clk	= "mcbsp3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_MCBSP3_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= mcbsp3_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(mcbsp3_opt_clks),
+};
+
+/* mcbsp4 */
+static struct omap_hwmod_irq_info omap44xx_mcbsp4_irqs[] = {
+	{ .name = "common", .irq = 16 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcbsp4_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 30 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 31 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk mcbsp4_opt_clks[] = {
+	{ .role = "pad_fck", .clk = "pad_clks_ck" },
+	{ .role = "prcm_clk", .clk = "mcbsp4_sync_mux_ck" },
+};
+
+static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
+	.name		= "mcbsp4",
+	.class		= &omap44xx_mcbsp_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_mcbsp4_irqs,
+	.sdma_reqs	= omap44xx_mcbsp4_sdma_reqs,
+	.main_clk	= "mcbsp4_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_MCBSP4_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= mcbsp4_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(mcbsp4_opt_clks),
+};
+
+/*
+ * 'mcpdm' class
+ * multi channel pdm controller (proprietary interface with phoenix power
+ * ic)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mcpdm_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_mcpdm_hwmod_class = {
+	.name	= "mcpdm",
+	.sysc	= &omap44xx_mcpdm_sysc,
+};
+
+/* mcpdm */
+static struct omap_hwmod_irq_info omap44xx_mcpdm_irqs[] = {
+	{ .irq = 112 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcpdm_sdma_reqs[] = {
+	{ .name = "up_link", .dma_req = 64 + OMAP44XX_DMA_REQ_START },
+	{ .name = "dn_link", .dma_req = 65 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_mcpdm_hwmod = {
+	.name		= "mcpdm",
+	.class		= &omap44xx_mcpdm_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_mcpdm_irqs,
+	.sdma_reqs	= omap44xx_mcpdm_sdma_reqs,
+	.main_clk	= "mcpdm_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_PDM_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_PDM_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'mcspi' class
+ * multichannel serial port interface (mcspi) / master/slave synchronous serial
+ * bus
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mcspi_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_mcspi_hwmod_class = {
+	.name	= "mcspi",
+	.sysc	= &omap44xx_mcspi_sysc,
+	.rev	= OMAP4_MCSPI_REV,
+};
+
+/* mcspi1 */
+static struct omap_hwmod_irq_info omap44xx_mcspi1_irqs[] = {
+	{ .irq = 65 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcspi1_sdma_reqs[] = {
+	{ .name = "tx0", .dma_req = 34 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx0", .dma_req = 35 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx1", .dma_req = 36 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx1", .dma_req = 37 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx2", .dma_req = 38 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx2", .dma_req = 39 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx3", .dma_req = 40 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx3", .dma_req = 41 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+/* mcspi1 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi1_dev_attr = {
+	.num_chipselect	= 4,
+};
+
+static struct omap_hwmod omap44xx_mcspi1_hwmod = {
+	.name		= "mcspi1",
+	.class		= &omap44xx_mcspi_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_mcspi1_irqs,
+	.sdma_reqs	= omap44xx_mcspi1_sdma_reqs,
+	.main_clk	= "mcspi1_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_MCSPI1_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &mcspi1_dev_attr,
+};
+
+/* mcspi2 */
+static struct omap_hwmod_irq_info omap44xx_mcspi2_irqs[] = {
+	{ .irq = 66 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcspi2_sdma_reqs[] = {
+	{ .name = "tx0", .dma_req = 42 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx0", .dma_req = 43 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx1", .dma_req = 44 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx1", .dma_req = 45 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+/* mcspi2 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi2_dev_attr = {
+	.num_chipselect	= 2,
+};
+
+static struct omap_hwmod omap44xx_mcspi2_hwmod = {
+	.name		= "mcspi2",
+	.class		= &omap44xx_mcspi_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_mcspi2_irqs,
+	.sdma_reqs	= omap44xx_mcspi2_sdma_reqs,
+	.main_clk	= "mcspi2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_MCSPI2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &mcspi2_dev_attr,
+};
+
+/* mcspi3 */
+static struct omap_hwmod_irq_info omap44xx_mcspi3_irqs[] = {
+	{ .irq = 91 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcspi3_sdma_reqs[] = {
+	{ .name = "tx0", .dma_req = 14 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx0", .dma_req = 15 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx1", .dma_req = 22 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx1", .dma_req = 23 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+/* mcspi3 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi3_dev_attr = {
+	.num_chipselect	= 2,
+};
+
+static struct omap_hwmod omap44xx_mcspi3_hwmod = {
+	.name		= "mcspi3",
+	.class		= &omap44xx_mcspi_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_mcspi3_irqs,
+	.sdma_reqs	= omap44xx_mcspi3_sdma_reqs,
+	.main_clk	= "mcspi3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_MCSPI3_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &mcspi3_dev_attr,
+};
+
+/* mcspi4 */
+static struct omap_hwmod_irq_info omap44xx_mcspi4_irqs[] = {
+	{ .irq = 48 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcspi4_sdma_reqs[] = {
+	{ .name = "tx0", .dma_req = 69 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx0", .dma_req = 70 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+/* mcspi4 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi4_dev_attr = {
+	.num_chipselect	= 1,
+};
+
+static struct omap_hwmod omap44xx_mcspi4_hwmod = {
+	.name		= "mcspi4",
+	.class		= &omap44xx_mcspi_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_mcspi4_irqs,
+	.sdma_reqs	= omap44xx_mcspi4_sdma_reqs,
+	.main_clk	= "mcspi4_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_MCSPI4_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &mcspi4_dev_attr,
+};
+
+/*
+ * 'mmc' class
+ * multimedia card high-speed/sd/sdio (mmc/sd/sdio) host controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mmc_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
+			   SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+			   MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_mmc_hwmod_class = {
+	.name	= "mmc",
+	.sysc	= &omap44xx_mmc_sysc,
+};
+
+/* mmc1 */
+static struct omap_hwmod_irq_info omap44xx_mmc1_irqs[] = {
+	{ .irq = 83 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc1_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 60 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 61 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+/* mmc1 dev_attr */
+static struct omap_mmc_dev_attr mmc1_dev_attr = {
+	.flags	= OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+static struct omap_hwmod omap44xx_mmc1_hwmod = {
+	.name		= "mmc1",
+	.class		= &omap44xx_mmc_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.mpu_irqs	= omap44xx_mmc1_irqs,
+	.sdma_reqs	= omap44xx_mmc1_sdma_reqs,
+	.main_clk	= "mmc1_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INIT_MMC1_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &mmc1_dev_attr,
+};
+
+/* mmc2 */
+static struct omap_hwmod_irq_info omap44xx_mmc2_irqs[] = {
+	{ .irq = 86 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc2_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 46 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 47 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_mmc2_hwmod = {
+	.name		= "mmc2",
+	.class		= &omap44xx_mmc_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.mpu_irqs	= omap44xx_mmc2_irqs,
+	.sdma_reqs	= omap44xx_mmc2_sdma_reqs,
+	.main_clk	= "mmc2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INIT_MMC2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* mmc3 */
+static struct omap_hwmod_irq_info omap44xx_mmc3_irqs[] = {
+	{ .irq = 94 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc3_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 76 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 77 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_mmc3_hwmod = {
+	.name		= "mmc3",
+	.class		= &omap44xx_mmc_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_mmc3_irqs,
+	.sdma_reqs	= omap44xx_mmc3_sdma_reqs,
+	.main_clk	= "mmc3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_MMCSD3_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* mmc4 */
+static struct omap_hwmod_irq_info omap44xx_mmc4_irqs[] = {
+	{ .irq = 96 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc4_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 56 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 57 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_mmc4_hwmod = {
+	.name		= "mmc4",
+	.class		= &omap44xx_mmc_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_mmc4_irqs,
+	.sdma_reqs	= omap44xx_mmc4_sdma_reqs,
+	.main_clk	= "mmc4_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_MMCSD4_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* mmc5 */
+static struct omap_hwmod_irq_info omap44xx_mmc5_irqs[] = {
+	{ .irq = 59 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc5_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 58 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 59 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_mmc5_hwmod = {
+	.name		= "mmc5",
+	.class		= &omap44xx_mmc_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_mmc5_irqs,
+	.sdma_reqs	= omap44xx_mmc5_sdma_reqs,
+	.main_clk	= "mmc5_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_MMCSD5_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'mpu' class
+ * mpu sub-system
+ */
+
+static struct omap_hwmod_class omap44xx_mpu_hwmod_class = {
+	.name	= "mpu",
+};
+
+/* mpu */
+static struct omap_hwmod_irq_info omap44xx_mpu_irqs[] = {
+	{ .name = "pl310", .irq = 0 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "cti0", .irq = 1 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "cti1", .irq = 2 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_mpu_hwmod = {
+	.name		= "mpu",
+	.class		= &omap44xx_mpu_hwmod_class,
+	.clkdm_name	= "mpuss_clkdm",
+	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+	.mpu_irqs	= omap44xx_mpu_irqs,
+	.main_clk	= "dpll_mpu_m2_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_MPU_MPU_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_MPU_MPU_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'ocmc_ram' class
+ * top-level core on-chip ram
+ */
+
+static struct omap_hwmod_class omap44xx_ocmc_ram_hwmod_class = {
+	.name	= "ocmc_ram",
+};
+
+/* ocmc_ram */
+static struct omap_hwmod omap44xx_ocmc_ram_hwmod = {
+	.name		= "ocmc_ram",
+	.class		= &omap44xx_ocmc_ram_hwmod_class,
+	.clkdm_name	= "l3_2_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3_2_OCMC_RAM_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3_2_OCMC_RAM_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'ocp2scp' class
+ * bridge to transform ocp interface protocol to scp (serial control port)
+ * protocol
+ */
+
+static struct omap_hwmod_class omap44xx_ocp2scp_hwmod_class = {
+	.name	= "ocp2scp",
+};
+
+/* ocp2scp_usb_phy */
+static struct omap_hwmod_opt_clk ocp2scp_usb_phy_opt_clks[] = {
+	{ .role = "phy_48m", .clk = "ocp2scp_usb_phy_phy_48m" },
+};
+
+static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
+	.name		= "ocp2scp_usb_phy",
+	.class		= &omap44xx_ocp2scp_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INIT_USBPHYOCP2SCP_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+	.opt_clks	= ocp2scp_usb_phy_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(ocp2scp_usb_phy_opt_clks),
+};
+
+/*
+ * 'prcm' class
+ * power and reset manager (part of the prcm infrastructure) + clock manager 2
+ * + clock manager 1 (in always on power domain) + local prm in mpu
+ */
+
+static struct omap_hwmod_class omap44xx_prcm_hwmod_class = {
+	.name	= "prcm",
+};
+
+/* prcm_mpu */
+static struct omap_hwmod omap44xx_prcm_mpu_hwmod = {
+	.name		= "prcm_mpu",
+	.class		= &omap44xx_prcm_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+};
+
+/* cm_core_aon */
+static struct omap_hwmod omap44xx_cm_core_aon_hwmod = {
+	.name		= "cm_core_aon",
+	.class		= &omap44xx_prcm_hwmod_class,
+	.clkdm_name	= "cm_clkdm",
+};
+
+/* cm_core */
+static struct omap_hwmod omap44xx_cm_core_hwmod = {
+	.name		= "cm_core",
+	.class		= &omap44xx_prcm_hwmod_class,
+	.clkdm_name	= "cm_clkdm",
+};
+
+/* prm */
+static struct omap_hwmod_irq_info omap44xx_prm_irqs[] = {
+	{ .irq = 11 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_rst_info omap44xx_prm_resets[] = {
+	{ .name = "rst_global_warm_sw", .rst_shift = 0 },
+	{ .name = "rst_global_cold_sw", .rst_shift = 1 },
+};
+
+static struct omap_hwmod omap44xx_prm_hwmod = {
+	.name		= "prm",
+	.class		= &omap44xx_prcm_hwmod_class,
+	.clkdm_name	= "prm_clkdm",
+	.mpu_irqs	= omap44xx_prm_irqs,
+	.rst_lines	= omap44xx_prm_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_prm_resets),
+};
+
+/*
+ * 'scrm' class
+ * system clock and reset manager
+ */
+
+static struct omap_hwmod_class omap44xx_scrm_hwmod_class = {
+	.name	= "scrm",
+};
+
+/* scrm */
+static struct omap_hwmod omap44xx_scrm_hwmod = {
+	.name		= "scrm",
+	.class		= &omap44xx_scrm_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+};
+
+/*
+ * 'sl2if' class
+ * shared level 2 memory interface
+ */
+
+static struct omap_hwmod_class omap44xx_sl2if_hwmod_class = {
+	.name	= "sl2if",
+};
+
+/* sl2if */
+static struct omap_hwmod omap44xx_sl2if_hwmod = {
+	.name		= "sl2if",
+	.class		= &omap44xx_sl2if_hwmod_class,
+	.clkdm_name	= "ivahd_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_IVAHD_SL2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_IVAHD_SL2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * 'slimbus' class
+ * bidirectional, multi-drop, multi-channel two-line serial interface between
+ * the device and external components
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_slimbus_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_slimbus_hwmod_class = {
+	.name	= "slimbus",
+	.sysc	= &omap44xx_slimbus_sysc,
+};
+
+/* slimbus1 */
+static struct omap_hwmod_irq_info omap44xx_slimbus1_irqs[] = {
+	{ .irq = 97 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_slimbus1_sdma_reqs[] = {
+	{ .name = "tx0", .dma_req = 84 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx1", .dma_req = 85 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx2", .dma_req = 86 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx3", .dma_req = 87 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx0", .dma_req = 88 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx1", .dma_req = 89 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx2", .dma_req = 90 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx3", .dma_req = 91 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk slimbus1_opt_clks[] = {
+	{ .role = "fclk_1", .clk = "slimbus1_fclk_1" },
+	{ .role = "fclk_0", .clk = "slimbus1_fclk_0" },
+	{ .role = "fclk_2", .clk = "slimbus1_fclk_2" },
+	{ .role = "slimbus_clk", .clk = "slimbus1_slimbus_clk" },
+};
+
+static struct omap_hwmod omap44xx_slimbus1_hwmod = {
+	.name		= "slimbus1",
+	.class		= &omap44xx_slimbus_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_slimbus1_irqs,
+	.sdma_reqs	= omap44xx_slimbus1_sdma_reqs,
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_SLIMBUS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_SLIMBUS_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= slimbus1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(slimbus1_opt_clks),
+};
+
+/* slimbus2 */
+static struct omap_hwmod_irq_info omap44xx_slimbus2_irqs[] = {
+	{ .irq = 98 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_slimbus2_sdma_reqs[] = {
+	{ .name = "tx0", .dma_req = 92 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx1", .dma_req = 93 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx2", .dma_req = 94 + OMAP44XX_DMA_REQ_START },
+	{ .name = "tx3", .dma_req = 95 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx0", .dma_req = 96 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx1", .dma_req = 97 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx2", .dma_req = 98 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx3", .dma_req = 99 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk slimbus2_opt_clks[] = {
+	{ .role = "fclk_1", .clk = "slimbus2_fclk_1" },
+	{ .role = "fclk_0", .clk = "slimbus2_fclk_0" },
+	{ .role = "slimbus_clk", .clk = "slimbus2_slimbus_clk" },
+};
+
+static struct omap_hwmod omap44xx_slimbus2_hwmod = {
+	.name		= "slimbus2",
+	.class		= &omap44xx_slimbus_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_slimbus2_irqs,
+	.sdma_reqs	= omap44xx_slimbus2_sdma_reqs,
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_SLIMBUS2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_SLIMBUS2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= slimbus2_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(slimbus2_opt_clks),
+};
+
+/*
+ * 'smartreflex' class
+ * smartreflex module (monitor silicon performance and outputs a measure of
+ * performance error)
+ */
+
+/* The IP is not compliant to type1 / type2 scheme */
+static struct omap_hwmod_sysc_fields omap_hwmod_sysc_type_smartreflex = {
+	.sidle_shift	= 24,
+	.enwkup_shift	= 26,
+};
+
+static struct omap_hwmod_class_sysconfig omap44xx_smartreflex_sysc = {
+	.sysc_offs	= 0x0038,
+	.sysc_flags	= (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type_smartreflex,
+};
+
+static struct omap_hwmod_class omap44xx_smartreflex_hwmod_class = {
+	.name	= "smartreflex",
+	.sysc	= &omap44xx_smartreflex_sysc,
+	.rev	= 2,
+};
+
+/* smartreflex_core */
+static struct omap_smartreflex_dev_attr smartreflex_core_dev_attr = {
+	.sensor_voltdm_name   = "core",
+};
+
+static struct omap_hwmod_irq_info omap44xx_smartreflex_core_irqs[] = {
+	{ .irq = 19 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_smartreflex_core_hwmod = {
+	.name		= "smartreflex_core",
+	.class		= &omap44xx_smartreflex_hwmod_class,
+	.clkdm_name	= "l4_ao_clkdm",
+	.mpu_irqs	= omap44xx_smartreflex_core_irqs,
+
+	.main_clk	= "smartreflex_core_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ALWON_SR_CORE_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &smartreflex_core_dev_attr,
+};
+
+/* smartreflex_iva */
+static struct omap_smartreflex_dev_attr smartreflex_iva_dev_attr = {
+	.sensor_voltdm_name	= "iva",
+};
+
+static struct omap_hwmod_irq_info omap44xx_smartreflex_iva_irqs[] = {
+	{ .irq = 102 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = {
+	.name		= "smartreflex_iva",
+	.class		= &omap44xx_smartreflex_hwmod_class,
+	.clkdm_name	= "l4_ao_clkdm",
+	.mpu_irqs	= omap44xx_smartreflex_iva_irqs,
+	.main_clk	= "smartreflex_iva_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_ALWON_SR_IVA_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ALWON_SR_IVA_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &smartreflex_iva_dev_attr,
+};
+
+/* smartreflex_mpu */
+static struct omap_smartreflex_dev_attr smartreflex_mpu_dev_attr = {
+	.sensor_voltdm_name	= "mpu",
+};
+
+static struct omap_hwmod_irq_info omap44xx_smartreflex_mpu_irqs[] = {
+	{ .irq = 18 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = {
+	.name		= "smartreflex_mpu",
+	.class		= &omap44xx_smartreflex_hwmod_class,
+	.clkdm_name	= "l4_ao_clkdm",
+	.mpu_irqs	= omap44xx_smartreflex_mpu_irqs,
+	.main_clk	= "smartreflex_mpu_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_ALWON_SR_MPU_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ALWON_SR_MPU_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &smartreflex_mpu_dev_attr,
+};
+
+/*
+ * 'spinlock' class
+ * spinlock provides hardware assistance for synchronizing the processes
+ * running on multiple processors
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_spinlock_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_spinlock_hwmod_class = {
+	.name	= "spinlock",
+	.sysc	= &omap44xx_spinlock_sysc,
+};
+
+/* spinlock */
+static struct omap_hwmod omap44xx_spinlock_hwmod = {
+	.name		= "spinlock",
+	.class		= &omap44xx_spinlock_hwmod_class,
+	.clkdm_name	= "l4_cfg_clkdm",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4CFG_HW_SEM_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4CFG_HW_SEM_CONTEXT_OFFSET,
+		},
+	},
+};
+
+/*
+ * 'timer' class
+ * general purpose timer module with accurate 1ms tick
+ * This class contains several variants: ['timer_1ms', 'timer']
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_timer_1ms_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_EMUFREE | SYSC_HAS_ENAWAKEUP |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_timer_1ms_hwmod_class = {
+	.name	= "timer",
+	.sysc	= &omap44xx_timer_1ms_sysc,
+};
+
+static struct omap_hwmod_class_sysconfig omap44xx_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
+	.name	= "timer",
+	.sysc	= &omap44xx_timer_sysc,
+};
+
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+	.timer_capability	= OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+	.timer_capability	= OMAP_TIMER_HAS_PWM,
+};
+
+/* timer1 */
+static struct omap_hwmod_irq_info omap44xx_timer1_irqs[] = {
+	{ .irq = 37 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer1_hwmod = {
+	.name		= "timer1",
+	.class		= &omap44xx_timer_1ms_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= omap44xx_timer1_irqs,
+	.main_clk	= "timer1_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_WKUP_TIMER1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_WKUP_TIMER1_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+};
+
+/* timer2 */
+static struct omap_hwmod_irq_info omap44xx_timer2_irqs[] = {
+	{ .irq = 38 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer2_hwmod = {
+	.name		= "timer2",
+	.class		= &omap44xx_timer_1ms_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_timer2_irqs,
+	.main_clk	= "timer2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_DMTIMER2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+};
+
+/* timer3 */
+static struct omap_hwmod_irq_info omap44xx_timer3_irqs[] = {
+	{ .irq = 39 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer3_hwmod = {
+	.name		= "timer3",
+	.class		= &omap44xx_timer_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_timer3_irqs,
+	.main_clk	= "timer3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER3_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_DMTIMER3_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+};
+
+/* timer4 */
+static struct omap_hwmod_irq_info omap44xx_timer4_irqs[] = {
+	{ .irq = 40 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer4_hwmod = {
+	.name		= "timer4",
+	.class		= &omap44xx_timer_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_timer4_irqs,
+	.main_clk	= "timer4_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER4_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_DMTIMER4_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+};
+
+/* timer5 */
+static struct omap_hwmod_irq_info omap44xx_timer5_irqs[] = {
+	{ .irq = 41 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer5_hwmod = {
+	.name		= "timer5",
+	.class		= &omap44xx_timer_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_timer5_irqs,
+	.main_clk	= "timer5_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_TIMER5_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_TIMER5_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+};
+
+/* timer6 */
+static struct omap_hwmod_irq_info omap44xx_timer6_irqs[] = {
+	{ .irq = 42 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer6_hwmod = {
+	.name		= "timer6",
+	.class		= &omap44xx_timer_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_timer6_irqs,
+
+	.main_clk	= "timer6_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_TIMER6_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_TIMER6_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+};
+
+/* timer7 */
+static struct omap_hwmod_irq_info omap44xx_timer7_irqs[] = {
+	{ .irq = 43 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer7_hwmod = {
+	.name		= "timer7",
+	.class		= &omap44xx_timer_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_timer7_irqs,
+	.main_clk	= "timer7_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_TIMER7_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_TIMER7_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+};
+
+/* timer8 */
+static struct omap_hwmod_irq_info omap44xx_timer8_irqs[] = {
+	{ .irq = 44 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer8_hwmod = {
+	.name		= "timer8",
+	.class		= &omap44xx_timer_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_timer8_irqs,
+	.main_clk	= "timer8_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_TIMER8_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_TIMER8_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+};
+
+/* timer9 */
+static struct omap_hwmod_irq_info omap44xx_timer9_irqs[] = {
+	{ .irq = 45 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer9_hwmod = {
+	.name		= "timer9",
+	.class		= &omap44xx_timer_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_timer9_irqs,
+	.main_clk	= "timer9_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER9_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_DMTIMER9_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+};
+
+/* timer10 */
+static struct omap_hwmod_irq_info omap44xx_timer10_irqs[] = {
+	{ .irq = 46 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer10_hwmod = {
+	.name		= "timer10",
+	.class		= &omap44xx_timer_1ms_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_timer10_irqs,
+	.main_clk	= "timer10_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER10_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_DMTIMER10_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+};
+
+/* timer11 */
+static struct omap_hwmod_irq_info omap44xx_timer11_irqs[] = {
+	{ .irq = 47 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_timer11_hwmod = {
+	.name		= "timer11",
+	.class		= &omap44xx_timer_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_timer11_irqs,
+	.main_clk	= "timer11_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER11_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_DMTIMER11_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_pwm_dev_attr,
+};
+
+/*
+ * 'uart' class
+ * universal asynchronous receiver/transmitter (uart)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_uart_sysc = {
+	.rev_offs	= 0x0050,
+	.sysc_offs	= 0x0054,
+	.syss_offs	= 0x0058,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_uart_hwmod_class = {
+	.name	= "uart",
+	.sysc	= &omap44xx_uart_sysc,
+};
+
+/* uart1 */
+static struct omap_hwmod_irq_info omap44xx_uart1_irqs[] = {
+	{ .irq = 72 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart1_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 48 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 49 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_uart1_hwmod = {
+	.name		= "uart1",
+	.class		= &omap44xx_uart_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_uart1_irqs,
+	.sdma_reqs	= omap44xx_uart1_sdma_reqs,
+	.main_clk	= "uart1_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_UART1_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* uart2 */
+static struct omap_hwmod_irq_info omap44xx_uart2_irqs[] = {
+	{ .irq = 73 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart2_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 50 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 51 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_uart2_hwmod = {
+	.name		= "uart2",
+	.class		= &omap44xx_uart_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_uart2_irqs,
+	.sdma_reqs	= omap44xx_uart2_sdma_reqs,
+	.main_clk	= "uart2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_UART2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* uart3 */
+static struct omap_hwmod_irq_info omap44xx_uart3_irqs[] = {
+	{ .irq = 74 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart3_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 52 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 53 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_uart3_hwmod = {
+	.name		= "uart3",
+	.class		= &omap44xx_uart_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+	.mpu_irqs	= omap44xx_uart3_irqs,
+	.sdma_reqs	= omap44xx_uart3_sdma_reqs,
+	.main_clk	= "uart3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_UART3_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* uart4 */
+static struct omap_hwmod_irq_info omap44xx_uart4_irqs[] = {
+	{ .irq = 70 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart4_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 54 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 55 + OMAP44XX_DMA_REQ_START },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_uart4_hwmod = {
+	.name		= "uart4",
+	.class		= &omap44xx_uart_hwmod_class,
+	.clkdm_name	= "l4_per_clkdm",
+	.mpu_irqs	= omap44xx_uart4_irqs,
+	.sdma_reqs	= omap44xx_uart4_sdma_reqs,
+	.main_clk	= "uart4_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4PER_UART4_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'usb_host_fs' class
+ * full-speed usb host controller
+ */
+
+/* The IP is not compliant to type1 / type2 scheme */
+static struct omap_hwmod_sysc_fields omap_hwmod_sysc_type_usb_host_fs = {
+	.midle_shift	= 4,
+	.sidle_shift	= 2,
+	.srst_shift	= 1,
+};
+
+static struct omap_hwmod_class_sysconfig omap44xx_usb_host_fs_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0210,
+	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type_usb_host_fs,
+};
+
+static struct omap_hwmod_class omap44xx_usb_host_fs_hwmod_class = {
+	.name	= "usb_host_fs",
+	.sysc	= &omap44xx_usb_host_fs_sysc,
+};
+
+/* usb_host_fs */
+static struct omap_hwmod_irq_info omap44xx_usb_host_fs_irqs[] = {
+	{ .name = "std", .irq = 89 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "smi", .irq = 90 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_usb_host_fs_hwmod = {
+	.name		= "usb_host_fs",
+	.class		= &omap44xx_usb_host_fs_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.mpu_irqs	= omap44xx_usb_host_fs_irqs,
+	.main_clk	= "usb_host_fs_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INIT_USB_HOST_FS_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INIT_USB_HOST_FS_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'usb_host_hs' class
+ * high-speed multi-port usb host controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_usb_host_hs_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+			   MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_usb_host_hs_hwmod_class = {
+	.name	= "usb_host_hs",
+	.sysc	= &omap44xx_usb_host_hs_sysc,
+};
+
+/* usb_host_hs */
+static struct omap_hwmod_irq_info omap44xx_usb_host_hs_irqs[] = {
+	{ .name = "ohci-irq", .irq = 76 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "ehci-irq", .irq = 77 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_usb_host_hs_hwmod = {
+	.name		= "usb_host_hs",
+	.class		= &omap44xx_usb_host_hs_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.main_clk	= "usb_host_hs_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INIT_USB_HOST_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.mpu_irqs	= omap44xx_usb_host_hs_irqs,
+
+	/*
+	 * Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
+	 * id: i660
+	 *
+	 * Description:
+	 * In the following configuration :
+	 * - USBHOST module is set to smart-idle mode
+	 * - PRCM asserts idle_req to the USBHOST module ( This typically
+	 *   happens when the system is going to a low power mode : all ports
+	 *   have been suspended, the master part of the USBHOST module has
+	 *   entered the standby state, and SW has cut the functional clocks)
+	 * - an USBHOST interrupt occurs before the module is able to answer
+	 *   idle_ack, typically a remote wakeup IRQ.
+	 * Then the USB HOST module will enter a deadlock situation where it
+	 * is no more accessible nor functional.
+	 *
+	 * Workaround:
+	 * Don't use smart idle; use only force idle, hence HWMOD_SWSUP_SIDLE
+	 */
+
+	/*
+	 * Errata: USB host EHCI may stall when entering smart-standby mode
+	 * Id: i571
+	 *
+	 * Description:
+	 * When the USBHOST module is set to smart-standby mode, and when it is
+	 * ready to enter the standby state (i.e. all ports are suspended and
+	 * all attached devices are in suspend mode), then it can wrongly assert
+	 * the Mstandby signal too early while there are still some residual OCP
+	 * transactions ongoing. If this condition occurs, the internal state
+	 * machine may go to an undefined state and the USB link may be stuck
+	 * upon the next resume.
+	 *
+	 * Workaround:
+	 * Don't use smart standby; use only force standby,
+	 * hence HWMOD_SWSUP_MSTANDBY
+	 */
+
+	/*
+	 * During system boot; If the hwmod framework resets the module
+	 * the module will have smart idle settings; which can lead to deadlock
+	 * (above Errata Id:i660); so, dont reset the module during boot;
+	 * Use HWMOD_INIT_NO_RESET.
+	 */
+
+	.flags		= HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
+			  HWMOD_INIT_NO_RESET,
+};
+
+/*
+ * 'usb_otg_hs' class
+ * high-speed on-the-go universal serial bus (usb_otg_hs) controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_usb_otg_hs_sysc = {
+	.rev_offs	= 0x0400,
+	.sysc_offs	= 0x0404,
+	.syss_offs	= 0x0408,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+			   SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+			   MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_usb_otg_hs_hwmod_class = {
+	.name	= "usb_otg_hs",
+	.sysc	= &omap44xx_usb_otg_hs_sysc,
+};
+
+/* usb_otg_hs */
+static struct omap_hwmod_irq_info omap44xx_usb_otg_hs_irqs[] = {
+	{ .name = "mc", .irq = 92 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "dma", .irq = 93 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_opt_clk usb_otg_hs_opt_clks[] = {
+	{ .role = "xclk", .clk = "usb_otg_hs_xclk" },
+};
+
+static struct omap_hwmod omap44xx_usb_otg_hs_hwmod = {
+	.name		= "usb_otg_hs",
+	.class		= &omap44xx_usb_otg_hs_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.flags		= HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+	.mpu_irqs	= omap44xx_usb_otg_hs_irqs,
+	.main_clk	= "usb_otg_hs_ick",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INIT_USB_OTG_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INIT_USB_OTG_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+	.opt_clks	= usb_otg_hs_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(usb_otg_hs_opt_clks),
+};
+
+/*
+ * 'usb_tll_hs' class
+ * usb_tll_hs module is the adapter on the usb_host_hs ports
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_usb_tll_hs_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_usb_tll_hs_hwmod_class = {
+	.name	= "usb_tll_hs",
+	.sysc	= &omap44xx_usb_tll_hs_sysc,
+};
+
+static struct omap_hwmod_irq_info omap44xx_usb_tll_hs_irqs[] = {
+	{ .name = "tll-irq", .irq = 78 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_usb_tll_hs_hwmod = {
+	.name		= "usb_tll_hs",
+	.class		= &omap44xx_usb_tll_hs_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.mpu_irqs	= omap44xx_usb_tll_hs_irqs,
+	.main_clk	= "usb_tll_hs_ick",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L3INIT_USB_TLL_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_HWCTRL,
+		},
+	},
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_wd_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_wd_timer_hwmod_class = {
+	.name		= "wd_timer",
+	.sysc		= &omap44xx_wd_timer_sysc,
+	.pre_shutdown	= &omap2_wd_timer_disable,
+	.reset		= &omap2_wd_timer_reset,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_irq_info omap44xx_wd_timer2_irqs[] = {
+	{ .irq = 80 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap44xx_wd_timer_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= omap44xx_wd_timer2_irqs,
+	.main_clk	= "wd_timer2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_WKUP_WDT2_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_WKUP_WDT2_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* wd_timer3 */
+static struct omap_hwmod_irq_info omap44xx_wd_timer3_irqs[] = {
+	{ .irq = 36 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
+	.name		= "wd_timer3",
+	.class		= &omap44xx_wd_timer_hwmod_class,
+	.clkdm_name	= "abe_clkdm",
+	.mpu_irqs	= omap44xx_wd_timer3_irqs,
+	.main_clk	= "wd_timer3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_ABE_WDT3_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+
+/*
+ * interfaces
+ */
+
+static struct omap_hwmod_addr_space omap44xx_c2c_target_fw_addrs[] = {
+	{
+		.pa_start	= 0x4a204000,
+		.pa_end		= 0x4a2040ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* c2c -> c2c_target_fw */
+static struct omap_hwmod_ocp_if omap44xx_c2c__c2c_target_fw = {
+	.master		= &omap44xx_c2c_hwmod,
+	.slave		= &omap44xx_c2c_target_fw_hwmod,
+	.clk		= "div_core_ck",
+	.addr		= omap44xx_c2c_target_fw_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4_cfg -> c2c_target_fw */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__c2c_target_fw = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_c2c_target_fw_hwmod,
+	.clk		= "l4_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* l3_main_1 -> dmm */
 static struct omap_hwmod_ocp_if omap44xx_l3_main_1__dmm = {
 	.master		= &omap44xx_l3_main_1_hwmod,
@@ -118,36 +3637,14 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* dmm slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dmm_slaves[] = {
-	&omap44xx_l3_main_1__dmm,
-	&omap44xx_mpu__dmm,
+/* c2c -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_c2c__emif_fw = {
+	.master		= &omap44xx_c2c_hwmod,
+	.slave		= &omap44xx_emif_fw_hwmod,
+	.clk		= "div_core_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod omap44xx_dmm_hwmod = {
-	.name		= "dmm",
-	.class		= &omap44xx_dmm_hwmod_class,
-	.clkdm_name	= "l3_emif_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_MEMIF_DMM_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_MEMIF_DMM_CONTEXT_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_dmm_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dmm_slaves),
-	.mpu_irqs	= omap44xx_dmm_irqs,
-};
-
-/*
- * 'emif_fw' class
- * instance(s): emif_fw
- */
-static struct omap_hwmod_class omap44xx_emif_fw_hwmod_class = {
-	.name	= "emif_fw",
-};
-
-/* emif_fw */
 /* dmm -> emif_fw */
 static struct omap_hwmod_ocp_if omap44xx_dmm__emif_fw = {
 	.master		= &omap44xx_dmm_hwmod,
@@ -174,35 +3671,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* emif_fw slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_emif_fw_slaves[] = {
-	&omap44xx_dmm__emif_fw,
-	&omap44xx_l4_cfg__emif_fw,
-};
-
-static struct omap_hwmod omap44xx_emif_fw_hwmod = {
-	.name		= "emif_fw",
-	.class		= &omap44xx_emif_fw_hwmod_class,
-	.clkdm_name	= "l3_emif_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_MEMIF_EMIF_FW_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_MEMIF_EMIF_FW_CONTEXT_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_emif_fw_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_emif_fw_slaves),
-};
-
-/*
- * 'l3' class
- * instance(s): l3_instr, l3_main_1, l3_main_2, l3_main_3
- */
-static struct omap_hwmod_class omap44xx_l3_hwmod_class = {
-	.name	= "l3",
-};
-
-/* l3_instr */
 /* iva -> l3_instr */
 static struct omap_hwmod_ocp_if omap44xx_iva__l3_instr = {
 	.master		= &omap44xx_iva_hwmod,
@@ -219,32 +3687,12 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_instr slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l3_instr_slaves[] = {
-	&omap44xx_iva__l3_instr,
-	&omap44xx_l3_main_3__l3_instr,
-};
-
-static struct omap_hwmod omap44xx_l3_instr_hwmod = {
-	.name		= "l3_instr",
-	.class		= &omap44xx_l3_hwmod_class,
-	.clkdm_name	= "l3_instr_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3INSTR_L3_INSTR_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.slaves		= omap44xx_l3_instr_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_l3_instr_slaves),
-};
-
-/* l3_main_1 */
-static struct omap_hwmod_irq_info omap44xx_l3_main_1_irqs[] = {
-	{ .name = "dbg_err", .irq = 9 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "app_err", .irq = 10 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
+/* ocp_wp_noc -> l3_instr */
+static struct omap_hwmod_ocp_if omap44xx_ocp_wp_noc__l3_instr = {
+	.master		= &omap44xx_ocp_wp_noc_hwmod,
+	.slave		= &omap44xx_l3_instr_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 /* dsp -> l3_main_1 */
@@ -313,33 +3761,22 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* l3_main_1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l3_main_1_slaves[] = {
-	&omap44xx_dsp__l3_main_1,
-	&omap44xx_dss__l3_main_1,
-	&omap44xx_l3_main_2__l3_main_1,
-	&omap44xx_l4_cfg__l3_main_1,
-	&omap44xx_mmc1__l3_main_1,
-	&omap44xx_mmc2__l3_main_1,
-	&omap44xx_mpu__l3_main_1,
+/* c2c_target_fw -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_c2c_target_fw__l3_main_2 = {
+	.master		= &omap44xx_c2c_target_fw_hwmod,
+	.slave		= &omap44xx_l3_main_2_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
-	.name		= "l3_main_1",
-	.class		= &omap44xx_l3_hwmod_class,
-	.clkdm_name	= "l3_1_clkdm",
-	.mpu_irqs	= omap44xx_l3_main_1_irqs,
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3_1_L3_1_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_l3_main_1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_l3_main_1_slaves),
+/* debugss -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_debugss__l3_main_2 = {
+	.master		= &omap44xx_debugss_hwmod,
+	.slave		= &omap44xx_l3_main_2_hwmod,
+	.clk		= "dbgclk_mux_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_main_2 */
 /* dma_system -> l3_main_2 */
 static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = {
 	.master		= &omap44xx_dma_system_hwmod,
@@ -348,6 +3785,22 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* fdif -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_fdif__l3_main_2 = {
+	.master		= &omap44xx_fdif_hwmod,
+	.slave		= &omap44xx_l3_main_2_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* gpu -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_gpu__l3_main_2 = {
+	.master		= &omap44xx_gpu_hwmod,
+	.slave		= &omap44xx_l3_main_2_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* hsi -> l3_main_2 */
 static struct omap_hwmod_ocp_if omap44xx_hsi__l3_main_2 = {
 	.master		= &omap44xx_hsi_hwmod,
@@ -406,6 +3859,22 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* usb_host_fs -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_usb_host_fs__l3_main_2 = {
+	.master		= &omap44xx_usb_host_fs_hwmod,
+	.slave		= &omap44xx_l3_main_2_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* usb_host_hs -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_usb_host_hs__l3_main_2 = {
+	.master		= &omap44xx_usb_host_hs_hwmod,
+	.slave		= &omap44xx_l3_main_2_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* usb_otg_hs -> l3_main_2 */
 static struct omap_hwmod_ocp_if omap44xx_usb_otg_hs__l3_main_2 = {
 	.master		= &omap44xx_usb_otg_hs_hwmod,
@@ -414,33 +3883,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_main_2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = {
-	&omap44xx_dma_system__l3_main_2,
-	&omap44xx_hsi__l3_main_2,
-	&omap44xx_ipu__l3_main_2,
-	&omap44xx_iss__l3_main_2,
-	&omap44xx_iva__l3_main_2,
-	&omap44xx_l3_main_1__l3_main_2,
-	&omap44xx_l4_cfg__l3_main_2,
-	&omap44xx_usb_otg_hs__l3_main_2,
-};
-
-static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
-	.name		= "l3_main_2",
-	.class		= &omap44xx_l3_hwmod_class,
-	.clkdm_name	= "l3_2_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3_2_L3_2_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3_2_L3_2_CONTEXT_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_l3_main_2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_l3_main_2_slaves),
-};
-
-/* l3_main_3 */
 static struct omap_hwmod_addr_space omap44xx_l3_main_3_addrs[] = {
 	{
 		.pa_start	= 0x45000000,
@@ -475,37 +3917,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_main_3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l3_main_3_slaves[] = {
-	&omap44xx_l3_main_1__l3_main_3,
-	&omap44xx_l3_main_2__l3_main_3,
-	&omap44xx_l4_cfg__l3_main_3,
-};
-
-static struct omap_hwmod omap44xx_l3_main_3_hwmod = {
-	.name		= "l3_main_3",
-	.class		= &omap44xx_l3_hwmod_class,
-	.clkdm_name	= "l3_instr_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3INSTR_L3_3_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3INSTR_L3_3_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.slaves		= omap44xx_l3_main_3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_l3_main_3_slaves),
-};
-
-/*
- * 'l4' class
- * instance(s): l4_abe, l4_cfg, l4_per, l4_wkup
- */
-static struct omap_hwmod_class omap44xx_l4_hwmod_class = {
-	.name	= "l4",
-};
-
-/* l4_abe */
 /* aess -> l4_abe */
 static struct omap_hwmod_ocp_if omap44xx_aess__l4_abe = {
 	.master		= &omap44xx_aess_hwmod,
@@ -538,28 +3949,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_abe slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l4_abe_slaves[] = {
-	&omap44xx_aess__l4_abe,
-	&omap44xx_dsp__l4_abe,
-	&omap44xx_l3_main_1__l4_abe,
-	&omap44xx_mpu__l4_abe,
-};
-
-static struct omap_hwmod omap44xx_l4_abe_hwmod = {
-	.name		= "l4_abe",
-	.class		= &omap44xx_l4_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_L4ABE_CLKCTRL_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_l4_abe_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_l4_abe_slaves),
-};
-
-/* l4_cfg */
 /* l3_main_1 -> l4_cfg */
 static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_cfg = {
 	.master		= &omap44xx_l3_main_1_hwmod,
@@ -568,26 +3957,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l4_cfg_slaves[] = {
-	&omap44xx_l3_main_1__l4_cfg,
-};
-
-static struct omap_hwmod omap44xx_l4_cfg_hwmod = {
-	.name		= "l4_cfg",
-	.class		= &omap44xx_l4_hwmod_class,
-	.clkdm_name	= "l4_cfg_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4CFG_L4_CFG_CONTEXT_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_l4_cfg_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_l4_cfg_slaves),
-};
-
-/* l4_per */
 /* l3_main_2 -> l4_per */
 static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l4_per = {
 	.master		= &omap44xx_l3_main_2_hwmod,
@@ -596,26 +3965,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l4_per_slaves[] = {
-	&omap44xx_l3_main_2__l4_per,
-};
-
-static struct omap_hwmod omap44xx_l4_per_hwmod = {
-	.name		= "l4_per",
-	.class		= &omap44xx_l4_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_L4PER_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_L4_PER_CONTEXT_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_l4_per_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_l4_per_slaves),
-};
-
-/* l4_wkup */
 /* l4_cfg -> l4_wkup */
 static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l4_wkup = {
 	.master		= &omap44xx_l4_cfg_hwmod,
@@ -624,34 +3973,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_wkup slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l4_wkup_slaves[] = {
-	&omap44xx_l4_cfg__l4_wkup,
-};
-
-static struct omap_hwmod omap44xx_l4_wkup_hwmod = {
-	.name		= "l4_wkup",
-	.class		= &omap44xx_l4_hwmod_class,
-	.clkdm_name	= "l4_wkup_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_WKUP_L4WKUP_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_WKUP_L4WKUP_CONTEXT_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_l4_wkup_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_l4_wkup_slaves),
-};
-
-/*
- * 'mpu_bus' class
- * instance(s): mpu_private
- */
-static struct omap_hwmod_class omap44xx_mpu_bus_hwmod_class = {
-	.name	= "mpu_bus",
-};
-
-/* mpu_private */
 /* mpu -> mpu_private */
 static struct omap_hwmod_ocp_if omap44xx_mpu__mpu_private = {
 	.master		= &omap44xx_mpu_hwmod,
@@ -660,105 +3981,22 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mpu_private slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mpu_private_slaves[] = {
-	&omap44xx_mpu__mpu_private,
+static struct omap_hwmod_addr_space omap44xx_ocp_wp_noc_addrs[] = {
+	{
+		.pa_start	= 0x4a102000,
+		.pa_end		= 0x4a10207f,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
 };
 
-static struct omap_hwmod omap44xx_mpu_private_hwmod = {
-	.name		= "mpu_private",
-	.class		= &omap44xx_mpu_bus_hwmod_class,
-	.clkdm_name	= "mpuss_clkdm",
-	.slaves		= omap44xx_mpu_private_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mpu_private_slaves),
-};
-
-/*
- * Modules omap_hwmod structures
- *
- * The following IPs are excluded for the moment because:
- * - They do not need an explicit SW control using omap_hwmod API.
- * - They still need to be validated with the driver
- *   properly adapted to omap_hwmod / omap_device
- *
- *  c2c
- *  c2c_target_fw
- *  cm_core
- *  cm_core_aon
- *  ctrl_module_core
- *  ctrl_module_pad_core
- *  ctrl_module_pad_wkup
- *  ctrl_module_wkup
- *  debugss
- *  efuse_ctrl_cust
- *  efuse_ctrl_std
- *  elm
- *  emif1
- *  emif2
- *  fdif
- *  gpmc
- *  gpu
- *  hdq1w
- *  mcasp
- *  mpu_c0
- *  mpu_c1
- *  ocmc_ram
- *  ocp2scp_usb_phy
- *  ocp_wp_noc
- *  prcm_mpu
- *  prm
- *  scrm
- *  sl2if
- *  slimbus1
- *  slimbus2
- *  usb_host_fs
- *  usb_host_hs
- *  usb_phy_cm
- *  usb_tll_hs
- *  usim
- */
-
-/*
- * 'aess' class
- * audio engine sub system
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_aess_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART |
-			   MSTANDBY_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_aess_hwmod_class = {
-	.name	= "aess",
-	.sysc	= &omap44xx_aess_sysc,
-};
-
-/* aess */
-static struct omap_hwmod_irq_info omap44xx_aess_irqs[] = {
-	{ .irq = 99 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_aess_sdma_reqs[] = {
-	{ .name = "fifo0", .dma_req = 100 + OMAP44XX_DMA_REQ_START },
-	{ .name = "fifo1", .dma_req = 101 + OMAP44XX_DMA_REQ_START },
-	{ .name = "fifo2", .dma_req = 102 + OMAP44XX_DMA_REQ_START },
-	{ .name = "fifo3", .dma_req = 103 + OMAP44XX_DMA_REQ_START },
-	{ .name = "fifo4", .dma_req = 104 + OMAP44XX_DMA_REQ_START },
-	{ .name = "fifo5", .dma_req = 105 + OMAP44XX_DMA_REQ_START },
-	{ .name = "fifo6", .dma_req = 106 + OMAP44XX_DMA_REQ_START },
-	{ .name = "fifo7", .dma_req = 107 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
-/* aess master ports */
-static struct omap_hwmod_ocp_if *omap44xx_aess_masters[] = {
-	&omap44xx_aess__l4_abe,
+/* l4_cfg -> ocp_wp_noc */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ocp_wp_noc = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_ocp_wp_noc_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_ocp_wp_noc_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = {
@@ -797,80 +4035,14 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* aess slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_aess_slaves[] = {
-	&omap44xx_l4_abe__aess,
-	&omap44xx_l4_abe__aess_dma,
+/* l3_main_2 -> c2c */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__c2c = {
+	.master		= &omap44xx_l3_main_2_hwmod,
+	.slave		= &omap44xx_c2c_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod omap44xx_aess_hwmod = {
-	.name		= "aess",
-	.class		= &omap44xx_aess_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_aess_irqs,
-	.sdma_reqs	= omap44xx_aess_sdma_reqs,
-	.main_clk	= "aess_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_AESS_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_AESS_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_aess_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_aess_slaves),
-	.masters	= omap44xx_aess_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_aess_masters),
-};
-
-/*
- * 'bandgap' class
- * bangap reference for ldo regulators
- */
-
-static struct omap_hwmod_class omap44xx_bandgap_hwmod_class = {
-	.name	= "bandgap",
-};
-
-/* bandgap */
-static struct omap_hwmod_opt_clk bandgap_opt_clks[] = {
-	{ .role = "fclk", .clk = "bandgap_fclk" },
-};
-
-static struct omap_hwmod omap44xx_bandgap_hwmod = {
-	.name		= "bandgap",
-	.class		= &omap44xx_bandgap_hwmod_class,
-	.clkdm_name	= "l4_wkup_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_WKUP_BANDGAP_CLKCTRL_OFFSET,
-		},
-	},
-	.opt_clks	= bandgap_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(bandgap_opt_clks),
-};
-
-/*
- * 'counter' class
- * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_counter_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0004,
-	.sysc_flags	= SYSC_HAS_SIDLEMODE,
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_counter_hwmod_class = {
-	.name	= "counter",
-	.sysc	= &omap44xx_counter_sysc,
-};
-
-/* counter_32k */
-static struct omap_hwmod omap44xx_counter_32k_hwmod;
 static struct omap_hwmod_addr_space omap44xx_counter_32k_addrs[] = {
 	{
 		.pa_start	= 0x4a304000,
@@ -889,70 +4061,94 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* counter_32k slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_counter_32k_slaves[] = {
-	&omap44xx_l4_wkup__counter_32k,
-};
-
-static struct omap_hwmod omap44xx_counter_32k_hwmod = {
-	.name		= "counter_32k",
-	.class		= &omap44xx_counter_hwmod_class,
-	.clkdm_name	= "l4_wkup_clkdm",
-	.flags		= HWMOD_SWSUP_SIDLE,
-	.main_clk	= "sys_32k_ck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_WKUP_SYNCTIMER_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_WKUP_SYNCTIMER_CONTEXT_OFFSET,
-		},
+static struct omap_hwmod_addr_space omap44xx_ctrl_module_core_addrs[] = {
+	{
+		.pa_start	= 0x4a002000,
+		.pa_end		= 0x4a0027ff,
+		.flags		= ADDR_TYPE_RT
 	},
-	.slaves		= omap44xx_counter_32k_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_counter_32k_slaves),
+	{ }
 };
 
-/*
- * 'dma' class
- * dma controller for data exchange between memory to memory (i.e. internal or
- * external memory) and gp peripherals to memory or memory to gp peripherals
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_dma_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x002c,
-	.syss_offs	= 0x0028,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-			   SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
+/* l4_cfg -> ctrl_module_core */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ctrl_module_core = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_ctrl_module_core_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_ctrl_module_core_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_class omap44xx_dma_hwmod_class = {
-	.name	= "dma",
-	.sysc	= &omap44xx_dma_sysc,
+static struct omap_hwmod_addr_space omap44xx_ctrl_module_pad_core_addrs[] = {
+	{
+		.pa_start	= 0x4a100000,
+		.pa_end		= 0x4a1007ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
 };
 
-/* dma dev_attr */
-static struct omap_dma_dev_attr dma_dev_attr = {
-	.dev_caps	= RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY |
-			  IS_CSSA_32 | IS_CDSA_32 | IS_RW_PRIORITY,
-	.lch_count	= 32,
+/* l4_cfg -> ctrl_module_pad_core */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ctrl_module_pad_core = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_ctrl_module_pad_core_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_ctrl_module_pad_core_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dma_system */
-static struct omap_hwmod_irq_info omap44xx_dma_system_irqs[] = {
-	{ .name = "0", .irq = 12 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "1", .irq = 13 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "2", .irq = 14 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "3", .irq = 15 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
+static struct omap_hwmod_addr_space omap44xx_ctrl_module_wkup_addrs[] = {
+	{
+		.pa_start	= 0x4a30c000,
+		.pa_end		= 0x4a30c7ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
 };
 
-/* dma_system master ports */
-static struct omap_hwmod_ocp_if *omap44xx_dma_system_masters[] = {
-	&omap44xx_dma_system__l3_main_2,
+/* l4_wkup -> ctrl_module_wkup */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__ctrl_module_wkup = {
+	.master		= &omap44xx_l4_wkup_hwmod,
+	.slave		= &omap44xx_ctrl_module_wkup_hwmod,
+	.clk		= "l4_wkup_clk_mux_ck",
+	.addr		= omap44xx_ctrl_module_wkup_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_ctrl_module_pad_wkup_addrs[] = {
+	{
+		.pa_start	= 0x4a31e000,
+		.pa_end		= 0x4a31e7ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_wkup -> ctrl_module_pad_wkup */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__ctrl_module_pad_wkup = {
+	.master		= &omap44xx_l4_wkup_hwmod,
+	.slave		= &omap44xx_ctrl_module_pad_wkup_hwmod,
+	.clk		= "l4_wkup_clk_mux_ck",
+	.addr		= omap44xx_ctrl_module_pad_wkup_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_debugss_addrs[] = {
+	{
+		.pa_start	= 0x54160000,
+		.pa_end		= 0x54167fff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l3_instr -> debugss */
+static struct omap_hwmod_ocp_if omap44xx_l3_instr__debugss = {
+	.master		= &omap44xx_l3_instr_hwmod,
+	.slave		= &omap44xx_debugss_hwmod,
+	.clk		= "l3_div_ck",
+	.addr		= omap44xx_debugss_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 static struct omap_hwmod_addr_space omap44xx_dma_system_addrs[] = {
@@ -973,62 +4169,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dma_system slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dma_system_slaves[] = {
-	&omap44xx_l4_cfg__dma_system,
-};
-
-static struct omap_hwmod omap44xx_dma_system_hwmod = {
-	.name		= "dma_system",
-	.class		= &omap44xx_dma_hwmod_class,
-	.clkdm_name	= "l3_dma_clkdm",
-	.mpu_irqs	= omap44xx_dma_system_irqs,
-	.main_clk	= "l3_div_ck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_SDMA_SDMA_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_SDMA_SDMA_CONTEXT_OFFSET,
-		},
-	},
-	.dev_attr	= &dma_dev_attr,
-	.slaves		= omap44xx_dma_system_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dma_system_slaves),
-	.masters	= omap44xx_dma_system_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_dma_system_masters),
-};
-
-/*
- * 'dmic' class
- * digital microphone controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_dmic_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_dmic_hwmod_class = {
-	.name	= "dmic",
-	.sysc	= &omap44xx_dmic_sysc,
-};
-
-/* dmic */
-static struct omap_hwmod omap44xx_dmic_hwmod;
-static struct omap_hwmod_irq_info omap44xx_dmic_irqs[] = {
-	{ .irq = 114 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_dmic_sdma_reqs[] = {
-	{ .dma_req = 66 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_dmic_addrs[] = {
 	{
 		.name		= "mpu",
@@ -1067,65 +4207,20 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* dmic slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dmic_slaves[] = {
-	&omap44xx_l4_abe__dmic,
-	&omap44xx_l4_abe__dmic_dma,
-};
-
-static struct omap_hwmod omap44xx_dmic_hwmod = {
-	.name		= "dmic",
-	.class		= &omap44xx_dmic_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_dmic_irqs,
-	.sdma_reqs	= omap44xx_dmic_sdma_reqs,
-	.main_clk	= "dmic_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_DMIC_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_DMIC_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_dmic_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dmic_slaves),
-};
-
-/*
- * 'dsp' class
- * dsp sub-system
- */
-
-static struct omap_hwmod_class omap44xx_dsp_hwmod_class = {
-	.name	= "dsp",
-};
-
-/* dsp */
-static struct omap_hwmod_irq_info omap44xx_dsp_irqs[] = {
-	{ .irq = 28 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_rst_info omap44xx_dsp_resets[] = {
-	{ .name = "mmu_cache", .rst_shift = 1 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_dsp_c0_resets[] = {
-	{ .name = "dsp", .rst_shift = 0 },
-};
-
 /* dsp -> iva */
 static struct omap_hwmod_ocp_if omap44xx_dsp__iva = {
 	.master		= &omap44xx_dsp_hwmod,
 	.slave		= &omap44xx_iva_hwmod,
 	.clk		= "dpll_iva_m5x2_ck",
+	.user		= OCP_USER_DSP,
 };
 
-/* dsp master ports */
-static struct omap_hwmod_ocp_if *omap44xx_dsp_masters[] = {
-	&omap44xx_dsp__l3_main_1,
-	&omap44xx_dsp__l4_abe,
-	&omap44xx_dsp__iva,
+/* dsp -> sl2if */
+static struct omap_hwmod_ocp_if omap44xx_dsp__sl2if = {
+	.master		= &omap44xx_dsp_hwmod,
+	.slave		= &omap44xx_sl2if_hwmod,
+	.clk		= "dpll_iva_m5x2_ck",
+	.user		= OCP_USER_DSP,
 };
 
 /* l4_cfg -> dsp */
@@ -1136,71 +4231,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* dsp slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dsp_slaves[] = {
-	&omap44xx_l4_cfg__dsp,
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_dsp_c0_hwmod = {
-	.name		= "dsp_c0",
-	.class		= &omap44xx_dsp_hwmod_class,
-	.clkdm_name	= "tesla_clkdm",
-	.flags		= HWMOD_INIT_NO_RESET,
-	.rst_lines	= omap44xx_dsp_c0_resets,
-	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_dsp_c0_resets),
-	.prcm = {
-		.omap4 = {
-			.rstctrl_offs = OMAP4_RM_TESLA_RSTCTRL_OFFSET,
-		},
-	},
-};
-
-static struct omap_hwmod omap44xx_dsp_hwmod = {
-	.name		= "dsp",
-	.class		= &omap44xx_dsp_hwmod_class,
-	.clkdm_name	= "tesla_clkdm",
-	.mpu_irqs	= omap44xx_dsp_irqs,
-	.rst_lines	= omap44xx_dsp_resets,
-	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_dsp_resets),
-	.main_clk	= "dsp_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_TESLA_TESLA_CLKCTRL_OFFSET,
-			.rstctrl_offs = OMAP4_RM_TESLA_RSTCTRL_OFFSET,
-			.context_offs = OMAP4_RM_TESLA_TESLA_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.slaves		= omap44xx_dsp_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dsp_slaves),
-	.masters	= omap44xx_dsp_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_dsp_masters),
-};
-
-/*
- * 'dss' class
- * display sub-system
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_dss_sysc = {
-	.rev_offs	= 0x0000,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= SYSS_HAS_RESET_STATUS,
-};
-
-static struct omap_hwmod_class omap44xx_dss_hwmod_class = {
-	.name	= "dss",
-	.sysc	= &omap44xx_dss_sysc,
-	.reset	= omap_dss_reset,
-};
-
-/* dss */
-/* dss master ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_masters[] = {
-	&omap44xx_dss__l3_main_1,
-};
-
 static struct omap_hwmod_addr_space omap44xx_dss_dma_addrs[] = {
 	{
 		.pa_start	= 0x58000000,
@@ -1237,73 +4267,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* dss slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_slaves[] = {
-	&omap44xx_l3_main_2__dss,
-	&omap44xx_l4_per__dss,
-};
-
-static struct omap_hwmod_opt_clk dss_opt_clks[] = {
-	{ .role = "sys_clk", .clk = "dss_sys_clk" },
-	{ .role = "tv_clk", .clk = "dss_tv_clk" },
-	{ .role = "hdmi_clk", .clk = "dss_48mhz_clk" },
-};
-
-static struct omap_hwmod omap44xx_dss_hwmod = {
-	.name		= "dss_core",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.class		= &omap44xx_dss_hwmod_class,
-	.clkdm_name	= "l3_dss_clkdm",
-	.main_clk	= "dss_dss_clk",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
-		},
-	},
-	.opt_clks	= dss_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_opt_clks),
-	.slaves		= omap44xx_dss_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dss_slaves),
-	.masters	= omap44xx_dss_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_dss_masters),
-};
-
-/*
- * 'dispc' class
- * display controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_dispc_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_MIDLEMODE |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-			   SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_dispc_hwmod_class = {
-	.name	= "dispc",
-	.sysc	= &omap44xx_dispc_sysc,
-};
-
-/* dss_dispc */
-static struct omap_hwmod omap44xx_dss_dispc_hwmod;
-static struct omap_hwmod_irq_info omap44xx_dss_dispc_irqs[] = {
-	{ .irq = 25 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_dss_dispc_sdma_reqs[] = {
-	{ .dma_req = 5 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_dss_dispc_dma_addrs[] = {
 	{
 		.pa_start	= 0x58001000,
@@ -1331,11 +4294,6 @@
 	{ }
 };
 
-static struct omap_dss_dispc_dev_attr omap44xx_dss_dispc_dev_attr = {
-	.manager_count		= 3,
-	.has_framedonetv_irq	= 1
-};
-
 /* l4_per -> dss_dispc */
 static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dispc = {
 	.master		= &omap44xx_l4_per_hwmod,
@@ -1345,63 +4303,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* dss_dispc slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_dispc_slaves[] = {
-	&omap44xx_l3_main_2__dss_dispc,
-	&omap44xx_l4_per__dss_dispc,
-};
-
-static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
-	.name		= "dss_dispc",
-	.class		= &omap44xx_dispc_hwmod_class,
-	.clkdm_name	= "l3_dss_clkdm",
-	.mpu_irqs	= omap44xx_dss_dispc_irqs,
-	.sdma_reqs	= omap44xx_dss_dispc_sdma_reqs,
-	.main_clk	= "dss_dss_clk",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_dss_dispc_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dss_dispc_slaves),
-	.dev_attr	= &omap44xx_dss_dispc_dev_attr
-};
-
-/*
- * 'dsi' class
- * display serial interface controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_dsi_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_dsi_hwmod_class = {
-	.name	= "dsi",
-	.sysc	= &omap44xx_dsi_sysc,
-};
-
-/* dss_dsi1 */
-static struct omap_hwmod omap44xx_dss_dsi1_hwmod;
-static struct omap_hwmod_irq_info omap44xx_dss_dsi1_irqs[] = {
-	{ .irq = 53 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_dss_dsi1_sdma_reqs[] = {
-	{ .dma_req = 74 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_dss_dsi1_dma_addrs[] = {
 	{
 		.pa_start	= 0x58004000,
@@ -1438,47 +4339,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* dss_dsi1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_dsi1_slaves[] = {
-	&omap44xx_l3_main_2__dss_dsi1,
-	&omap44xx_l4_per__dss_dsi1,
-};
-
-static struct omap_hwmod_opt_clk dss_dsi1_opt_clks[] = {
-	{ .role = "sys_clk", .clk = "dss_sys_clk" },
-};
-
-static struct omap_hwmod omap44xx_dss_dsi1_hwmod = {
-	.name		= "dss_dsi1",
-	.class		= &omap44xx_dsi_hwmod_class,
-	.clkdm_name	= "l3_dss_clkdm",
-	.mpu_irqs	= omap44xx_dss_dsi1_irqs,
-	.sdma_reqs	= omap44xx_dss_dsi1_sdma_reqs,
-	.main_clk	= "dss_dss_clk",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
-		},
-	},
-	.opt_clks	= dss_dsi1_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_dsi1_opt_clks),
-	.slaves		= omap44xx_dss_dsi1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dss_dsi1_slaves),
-};
-
-/* dss_dsi2 */
-static struct omap_hwmod omap44xx_dss_dsi2_hwmod;
-static struct omap_hwmod_irq_info omap44xx_dss_dsi2_irqs[] = {
-	{ .irq = 84 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_dss_dsi2_sdma_reqs[] = {
-	{ .dma_req = 83 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_dss_dsi2_dma_addrs[] = {
 	{
 		.pa_start	= 0x58005000,
@@ -1515,67 +4375,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* dss_dsi2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_dsi2_slaves[] = {
-	&omap44xx_l3_main_2__dss_dsi2,
-	&omap44xx_l4_per__dss_dsi2,
-};
-
-static struct omap_hwmod_opt_clk dss_dsi2_opt_clks[] = {
-	{ .role = "sys_clk", .clk = "dss_sys_clk" },
-};
-
-static struct omap_hwmod omap44xx_dss_dsi2_hwmod = {
-	.name		= "dss_dsi2",
-	.class		= &omap44xx_dsi_hwmod_class,
-	.clkdm_name	= "l3_dss_clkdm",
-	.mpu_irqs	= omap44xx_dss_dsi2_irqs,
-	.sdma_reqs	= omap44xx_dss_dsi2_sdma_reqs,
-	.main_clk	= "dss_dss_clk",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
-		},
-	},
-	.opt_clks	= dss_dsi2_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_dsi2_opt_clks),
-	.slaves		= omap44xx_dss_dsi2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dss_dsi2_slaves),
-};
-
-/*
- * 'hdmi' class
- * hdmi controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_hdmi_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.sysc_flags	= (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_hdmi_hwmod_class = {
-	.name	= "hdmi",
-	.sysc	= &omap44xx_hdmi_sysc,
-};
-
-/* dss_hdmi */
-static struct omap_hwmod omap44xx_dss_hdmi_hwmod;
-static struct omap_hwmod_irq_info omap44xx_dss_hdmi_irqs[] = {
-	{ .irq = 101 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_dss_hdmi_sdma_reqs[] = {
-	{ .dma_req = 75 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_dss_hdmi_dma_addrs[] = {
 	{
 		.pa_start	= 0x58006000,
@@ -1612,62 +4411,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* dss_hdmi slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_hdmi_slaves[] = {
-	&omap44xx_l3_main_2__dss_hdmi,
-	&omap44xx_l4_per__dss_hdmi,
-};
-
-static struct omap_hwmod_opt_clk dss_hdmi_opt_clks[] = {
-	{ .role = "sys_clk", .clk = "dss_sys_clk" },
-};
-
-static struct omap_hwmod omap44xx_dss_hdmi_hwmod = {
-	.name		= "dss_hdmi",
-	.class		= &omap44xx_hdmi_hwmod_class,
-	.clkdm_name	= "l3_dss_clkdm",
-	.mpu_irqs	= omap44xx_dss_hdmi_irqs,
-	.sdma_reqs	= omap44xx_dss_hdmi_sdma_reqs,
-	.main_clk	= "dss_48mhz_clk",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
-		},
-	},
-	.opt_clks	= dss_hdmi_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_hdmi_opt_clks),
-	.slaves		= omap44xx_dss_hdmi_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dss_hdmi_slaves),
-};
-
-/*
- * 'rfbi' class
- * remote frame buffer interface
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_rfbi_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_rfbi_hwmod_class = {
-	.name	= "rfbi",
-	.sysc	= &omap44xx_rfbi_sysc,
-};
-
-/* dss_rfbi */
-static struct omap_hwmod omap44xx_dss_rfbi_hwmod;
-static struct omap_hwmod_dma_info omap44xx_dss_rfbi_sdma_reqs[] = {
-	{ .dma_req = 13 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_dss_rfbi_dma_addrs[] = {
 	{
 		.pa_start	= 0x58002000,
@@ -1704,45 +4447,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* dss_rfbi slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_rfbi_slaves[] = {
-	&omap44xx_l3_main_2__dss_rfbi,
-	&omap44xx_l4_per__dss_rfbi,
-};
-
-static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
-	{ .role = "ick", .clk = "dss_fck" },
-};
-
-static struct omap_hwmod omap44xx_dss_rfbi_hwmod = {
-	.name		= "dss_rfbi",
-	.class		= &omap44xx_rfbi_hwmod_class,
-	.clkdm_name	= "l3_dss_clkdm",
-	.sdma_reqs	= omap44xx_dss_rfbi_sdma_reqs,
-	.main_clk	= "dss_dss_clk",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
-		},
-	},
-	.opt_clks	= dss_rfbi_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(dss_rfbi_opt_clks),
-	.slaves		= omap44xx_dss_rfbi_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dss_rfbi_slaves),
-};
-
-/*
- * 'venc' class
- * video encoder
- */
-
-static struct omap_hwmod_class omap44xx_venc_hwmod_class = {
-	.name	= "venc",
-};
-
-/* dss_venc */
-static struct omap_hwmod omap44xx_dss_venc_hwmod;
 static struct omap_hwmod_addr_space omap44xx_dss_venc_dma_addrs[] = {
 	{
 		.pa_start	= 0x58003000,
@@ -1779,61 +4483,76 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* dss_venc slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_venc_slaves[] = {
-	&omap44xx_l3_main_2__dss_venc,
-	&omap44xx_l4_per__dss_venc,
-};
-
-static struct omap_hwmod omap44xx_dss_venc_hwmod = {
-	.name		= "dss_venc",
-	.class		= &omap44xx_venc_hwmod_class,
-	.clkdm_name	= "l3_dss_clkdm",
-	.main_clk	= "dss_tv_clk",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
-		},
+static struct omap_hwmod_addr_space omap44xx_elm_addrs[] = {
+	{
+		.pa_start	= 0x48078000,
+		.pa_end		= 0x48078fff,
+		.flags		= ADDR_TYPE_RT
 	},
-	.slaves		= omap44xx_dss_venc_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_dss_venc_slaves),
+	{ }
 };
 
-/*
- * 'gpio' class
- * general purpose io module
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_gpio_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0114,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-			   SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
+/* l4_per -> elm */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__elm = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_elm_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_elm_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_class omap44xx_gpio_hwmod_class = {
-	.name	= "gpio",
-	.sysc	= &omap44xx_gpio_sysc,
-	.rev	= 2,
+static struct omap_hwmod_addr_space omap44xx_emif1_addrs[] = {
+	{
+		.pa_start	= 0x4c000000,
+		.pa_end		= 0x4c0000ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
 };
 
-/* gpio dev_attr */
-static struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width	= 32,
-	.dbck_flag	= true,
+/* emif_fw -> emif1 */
+static struct omap_hwmod_ocp_if omap44xx_emif_fw__emif1 = {
+	.master		= &omap44xx_emif_fw_hwmod,
+	.slave		= &omap44xx_emif1_hwmod,
+	.clk		= "l3_div_ck",
+	.addr		= omap44xx_emif1_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* gpio1 */
-static struct omap_hwmod omap44xx_gpio1_hwmod;
-static struct omap_hwmod_irq_info omap44xx_gpio1_irqs[] = {
-	{ .irq = 29 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
+static struct omap_hwmod_addr_space omap44xx_emif2_addrs[] = {
+	{
+		.pa_start	= 0x4d000000,
+		.pa_end		= 0x4d0000ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* emif_fw -> emif2 */
+static struct omap_hwmod_ocp_if omap44xx_emif_fw__emif2 = {
+	.master		= &omap44xx_emif_fw_hwmod,
+	.slave		= &omap44xx_emif2_hwmod,
+	.clk		= "l3_div_ck",
+	.addr		= omap44xx_emif2_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_fdif_addrs[] = {
+	{
+		.pa_start	= 0x4a10a000,
+		.pa_end		= 0x4a10a1ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_cfg -> fdif */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__fdif = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_fdif_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_fdif_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 static struct omap_hwmod_addr_space omap44xx_gpio1_addrs[] = {
@@ -1854,42 +4573,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* gpio1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio1_slaves[] = {
-	&omap44xx_l4_wkup__gpio1,
-};
-
-static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio1_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio1_hwmod = {
-	.name		= "gpio1",
-	.class		= &omap44xx_gpio_hwmod_class,
-	.clkdm_name	= "l4_wkup_clkdm",
-	.mpu_irqs	= omap44xx_gpio1_irqs,
-	.main_clk	= "gpio1_ick",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_WKUP_GPIO1_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_WKUP_GPIO1_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.opt_clks	= gpio1_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
-	.slaves		= omap44xx_gpio1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_gpio1_slaves),
-};
-
-/* gpio2 */
-static struct omap_hwmod omap44xx_gpio2_hwmod;
-static struct omap_hwmod_irq_info omap44xx_gpio2_irqs[] = {
-	{ .irq = 30 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_gpio2_addrs[] = {
 	{
 		.pa_start	= 0x48055000,
@@ -1908,43 +4591,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* gpio2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio2_slaves[] = {
-	&omap44xx_l4_per__gpio2,
-};
-
-static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio2_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio2_hwmod = {
-	.name		= "gpio2",
-	.class		= &omap44xx_gpio_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap44xx_gpio2_irqs,
-	.main_clk	= "gpio2_ick",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_GPIO2_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.opt_clks	= gpio2_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
-	.slaves		= omap44xx_gpio2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_gpio2_slaves),
-};
-
-/* gpio3 */
-static struct omap_hwmod omap44xx_gpio3_hwmod;
-static struct omap_hwmod_irq_info omap44xx_gpio3_irqs[] = {
-	{ .irq = 31 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_gpio3_addrs[] = {
 	{
 		.pa_start	= 0x48057000,
@@ -1963,43 +4609,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* gpio3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio3_slaves[] = {
-	&omap44xx_l4_per__gpio3,
-};
-
-static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio3_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio3_hwmod = {
-	.name		= "gpio3",
-	.class		= &omap44xx_gpio_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap44xx_gpio3_irqs,
-	.main_clk	= "gpio3_ick",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_GPIO3_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.opt_clks	= gpio3_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio3_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
-	.slaves		= omap44xx_gpio3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_gpio3_slaves),
-};
-
-/* gpio4 */
-static struct omap_hwmod omap44xx_gpio4_hwmod;
-static struct omap_hwmod_irq_info omap44xx_gpio4_irqs[] = {
-	{ .irq = 32 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_gpio4_addrs[] = {
 	{
 		.pa_start	= 0x48059000,
@@ -2018,43 +4627,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* gpio4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio4_slaves[] = {
-	&omap44xx_l4_per__gpio4,
-};
-
-static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio4_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio4_hwmod = {
-	.name		= "gpio4",
-	.class		= &omap44xx_gpio_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap44xx_gpio4_irqs,
-	.main_clk	= "gpio4_ick",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_GPIO4_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.opt_clks	= gpio4_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio4_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
-	.slaves		= omap44xx_gpio4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_gpio4_slaves),
-};
-
-/* gpio5 */
-static struct omap_hwmod omap44xx_gpio5_hwmod;
-static struct omap_hwmod_irq_info omap44xx_gpio5_irqs[] = {
-	{ .irq = 33 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_gpio5_addrs[] = {
 	{
 		.pa_start	= 0x4805b000,
@@ -2073,43 +4645,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* gpio5 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio5_slaves[] = {
-	&omap44xx_l4_per__gpio5,
-};
-
-static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio5_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio5_hwmod = {
-	.name		= "gpio5",
-	.class		= &omap44xx_gpio_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap44xx_gpio5_irqs,
-	.main_clk	= "gpio5_ick",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_GPIO5_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.opt_clks	= gpio5_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio5_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
-	.slaves		= omap44xx_gpio5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_gpio5_slaves),
-};
-
-/* gpio6 */
-static struct omap_hwmod omap44xx_gpio6_hwmod;
-static struct omap_hwmod_irq_info omap44xx_gpio6_irqs[] = {
-	{ .irq = 34 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_gpio6_addrs[] = {
 	{
 		.pa_start	= 0x4805d000,
@@ -2128,71 +4663,58 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* gpio6 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio6_slaves[] = {
-	&omap44xx_l4_per__gpio6,
-};
-
-static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
-	{ .role = "dbclk", .clk = "gpio6_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio6_hwmod = {
-	.name		= "gpio6",
-	.class		= &omap44xx_gpio_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-	.mpu_irqs	= omap44xx_gpio6_irqs,
-	.main_clk	= "gpio6_ick",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_GPIO6_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
+static struct omap_hwmod_addr_space omap44xx_gpmc_addrs[] = {
+	{
+		.pa_start	= 0x50000000,
+		.pa_end		= 0x500003ff,
+		.flags		= ADDR_TYPE_RT
 	},
-	.opt_clks	= gpio6_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(gpio6_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
-	.slaves		= omap44xx_gpio6_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_gpio6_slaves),
+	{ }
 };
 
-/*
- * 'hsi' class
- * mipi high-speed synchronous serial interface (multichannel and full-duplex
- * serial if)
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_hsi_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_EMUFREE |
-			   SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
-			   MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
+/* l3_main_2 -> gpmc */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__gpmc = {
+	.master		= &omap44xx_l3_main_2_hwmod,
+	.slave		= &omap44xx_gpmc_hwmod,
+	.clk		= "l3_div_ck",
+	.addr		= omap44xx_gpmc_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_class omap44xx_hsi_hwmod_class = {
-	.name	= "hsi",
-	.sysc	= &omap44xx_hsi_sysc,
+static struct omap_hwmod_addr_space omap44xx_gpu_addrs[] = {
+	{
+		.pa_start	= 0x56000000,
+		.pa_end		= 0x5600ffff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
 };
 
-/* hsi */
-static struct omap_hwmod_irq_info omap44xx_hsi_irqs[] = {
-	{ .name = "mpu_p1", .irq = 67 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "mpu_p2", .irq = 68 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "mpu_dma", .irq = 71 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
+/* l3_main_2 -> gpu */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__gpu = {
+	.master		= &omap44xx_l3_main_2_hwmod,
+	.slave		= &omap44xx_gpu_hwmod,
+	.clk		= "l3_div_ck",
+	.addr		= omap44xx_gpu_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* hsi master ports */
-static struct omap_hwmod_ocp_if *omap44xx_hsi_masters[] = {
-	&omap44xx_hsi__l3_main_2,
+static struct omap_hwmod_addr_space omap44xx_hdq1w_addrs[] = {
+	{
+		.pa_start	= 0x480b2000,
+		.pa_end		= 0x480b201f,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_per -> hdq1w */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__hdq1w = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_hdq1w_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_hdq1w_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 static struct omap_hwmod_addr_space omap44xx_hsi_addrs[] = {
@@ -2213,71 +4735,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* hsi slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_hsi_slaves[] = {
-	&omap44xx_l4_cfg__hsi,
-};
-
-static struct omap_hwmod omap44xx_hsi_hwmod = {
-	.name		= "hsi",
-	.class		= &omap44xx_hsi_hwmod_class,
-	.clkdm_name	= "l3_init_clkdm",
-	.mpu_irqs	= omap44xx_hsi_irqs,
-	.main_clk	= "hsi_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3INIT_HSI_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3INIT_HSI_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.slaves		= omap44xx_hsi_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_hsi_slaves),
-	.masters	= omap44xx_hsi_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_hsi_masters),
-};
-
-/*
- * 'i2c' class
- * multimaster high-speed i2c controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_i2c_sysc = {
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0090,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.clockact	= CLOCKACT_TEST_ICLK,
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_i2c_hwmod_class = {
-	.name	= "i2c",
-	.sysc	= &omap44xx_i2c_sysc,
-	.rev	= OMAP_I2C_IP_VERSION_2,
-	.reset	= &omap_i2c_reset,
-};
-
-static struct omap_i2c_dev_attr i2c_dev_attr = {
-	.flags	= OMAP_I2C_FLAG_BUS_SHIFT_NONE,
-};
-
-/* i2c1 */
-static struct omap_hwmod omap44xx_i2c1_hwmod;
-static struct omap_hwmod_irq_info omap44xx_i2c1_irqs[] = {
-	{ .irq = 56 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_i2c1_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 26 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 27 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_i2c1_addrs[] = {
 	{
 		.pa_start	= 0x48070000,
@@ -2296,44 +4753,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* i2c1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_i2c1_slaves[] = {
-	&omap44xx_l4_per__i2c1,
-};
-
-static struct omap_hwmod omap44xx_i2c1_hwmod = {
-	.name		= "i2c1",
-	.class		= &omap44xx_i2c_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-	.mpu_irqs	= omap44xx_i2c1_irqs,
-	.sdma_reqs	= omap44xx_i2c1_sdma_reqs,
-	.main_clk	= "i2c1_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_I2C1_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_i2c1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_i2c1_slaves),
-	.dev_attr	= &i2c_dev_attr,
-};
-
-/* i2c2 */
-static struct omap_hwmod omap44xx_i2c2_hwmod;
-static struct omap_hwmod_irq_info omap44xx_i2c2_irqs[] = {
-	{ .irq = 57 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_i2c2_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 28 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 29 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_i2c2_addrs[] = {
 	{
 		.pa_start	= 0x48072000,
@@ -2352,44 +4771,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* i2c2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_i2c2_slaves[] = {
-	&omap44xx_l4_per__i2c2,
-};
-
-static struct omap_hwmod omap44xx_i2c2_hwmod = {
-	.name		= "i2c2",
-	.class		= &omap44xx_i2c_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-	.mpu_irqs	= omap44xx_i2c2_irqs,
-	.sdma_reqs	= omap44xx_i2c2_sdma_reqs,
-	.main_clk	= "i2c2_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_I2C2_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_i2c2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_i2c2_slaves),
-	.dev_attr	= &i2c_dev_attr,
-};
-
-/* i2c3 */
-static struct omap_hwmod omap44xx_i2c3_hwmod;
-static struct omap_hwmod_irq_info omap44xx_i2c3_irqs[] = {
-	{ .irq = 61 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_i2c3_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 24 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 25 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_i2c3_addrs[] = {
 	{
 		.pa_start	= 0x48060000,
@@ -2408,44 +4789,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* i2c3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_i2c3_slaves[] = {
-	&omap44xx_l4_per__i2c3,
-};
-
-static struct omap_hwmod omap44xx_i2c3_hwmod = {
-	.name		= "i2c3",
-	.class		= &omap44xx_i2c_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-	.mpu_irqs	= omap44xx_i2c3_irqs,
-	.sdma_reqs	= omap44xx_i2c3_sdma_reqs,
-	.main_clk	= "i2c3_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_I2C3_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_i2c3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_i2c3_slaves),
-	.dev_attr	= &i2c_dev_attr,
-};
-
-/* i2c4 */
-static struct omap_hwmod omap44xx_i2c4_hwmod;
-static struct omap_hwmod_irq_info omap44xx_i2c4_irqs[] = {
-	{ .irq = 62 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_i2c4_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 123 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 124 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_i2c4_addrs[] = {
 	{
 		.pa_start	= 0x48350000,
@@ -2464,63 +4807,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* i2c4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_i2c4_slaves[] = {
-	&omap44xx_l4_per__i2c4,
-};
-
-static struct omap_hwmod omap44xx_i2c4_hwmod = {
-	.name		= "i2c4",
-	.class		= &omap44xx_i2c_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-	.mpu_irqs	= omap44xx_i2c4_irqs,
-	.sdma_reqs	= omap44xx_i2c4_sdma_reqs,
-	.main_clk	= "i2c4_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_I2C4_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_i2c4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_i2c4_slaves),
-	.dev_attr	= &i2c_dev_attr,
-};
-
-/*
- * 'ipu' class
- * imaging processor unit
- */
-
-static struct omap_hwmod_class omap44xx_ipu_hwmod_class = {
-	.name	= "ipu",
-};
-
-/* ipu */
-static struct omap_hwmod_irq_info omap44xx_ipu_irqs[] = {
-	{ .irq = 100 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_rst_info omap44xx_ipu_c0_resets[] = {
-	{ .name = "cpu0", .rst_shift = 0 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_ipu_c1_resets[] = {
-	{ .name = "cpu1", .rst_shift = 1 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_ipu_resets[] = {
-	{ .name = "mmu_cache", .rst_shift = 2 },
-};
-
-/* ipu master ports */
-static struct omap_hwmod_ocp_if *omap44xx_ipu_masters[] = {
-	&omap44xx_ipu__l3_main_2,
-};
-
 /* l3_main_2 -> ipu */
 static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ipu = {
 	.master		= &omap44xx_l3_main_2_hwmod,
@@ -2529,112 +4815,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* ipu slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_ipu_slaves[] = {
-	&omap44xx_l3_main_2__ipu,
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_ipu_c0_hwmod = {
-	.name		= "ipu_c0",
-	.class		= &omap44xx_ipu_hwmod_class,
-	.clkdm_name	= "ducati_clkdm",
-	.flags		= HWMOD_INIT_NO_RESET,
-	.rst_lines	= omap44xx_ipu_c0_resets,
-	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_ipu_c0_resets),
-	.prcm = {
-		.omap4 = {
-			.rstctrl_offs = OMAP4_RM_DUCATI_RSTCTRL_OFFSET,
-		},
-	},
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_ipu_c1_hwmod = {
-	.name		= "ipu_c1",
-	.class		= &omap44xx_ipu_hwmod_class,
-	.clkdm_name	= "ducati_clkdm",
-	.flags		= HWMOD_INIT_NO_RESET,
-	.rst_lines	= omap44xx_ipu_c1_resets,
-	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_ipu_c1_resets),
-	.prcm = {
-		.omap4 = {
-			.rstctrl_offs = OMAP4_RM_DUCATI_RSTCTRL_OFFSET,
-		},
-	},
-};
-
-static struct omap_hwmod omap44xx_ipu_hwmod = {
-	.name		= "ipu",
-	.class		= &omap44xx_ipu_hwmod_class,
-	.clkdm_name	= "ducati_clkdm",
-	.mpu_irqs	= omap44xx_ipu_irqs,
-	.rst_lines	= omap44xx_ipu_resets,
-	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_ipu_resets),
-	.main_clk	= "ipu_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET,
-			.rstctrl_offs = OMAP4_RM_DUCATI_RSTCTRL_OFFSET,
-			.context_offs = OMAP4_RM_DUCATI_DUCATI_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.slaves		= omap44xx_ipu_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_ipu_slaves),
-	.masters	= omap44xx_ipu_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_ipu_masters),
-};
-
-/*
- * 'iss' class
- * external images sensor pixel data processor
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_iss_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	/*
-	 * ISS needs 100 OCP clk cycles delay after a softreset before
-	 * accessing sysconfig again.
-	 * The lowest frequency at the moment for L3 bus is 100 MHz, so
-	 * 1usec delay is needed. Add an x2 margin to be safe (2 usecs).
-	 *
-	 * TODO: Indicate errata when available.
-	 */
-	.srst_udelay	= 2,
-	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
-			   MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_iss_hwmod_class = {
-	.name	= "iss",
-	.sysc	= &omap44xx_iss_sysc,
-};
-
-/* iss */
-static struct omap_hwmod_irq_info omap44xx_iss_irqs[] = {
-	{ .irq = 24 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_iss_sdma_reqs[] = {
-	{ .name = "1", .dma_req = 8 + OMAP44XX_DMA_REQ_START },
-	{ .name = "2", .dma_req = 9 + OMAP44XX_DMA_REQ_START },
-	{ .name = "3", .dma_req = 11 + OMAP44XX_DMA_REQ_START },
-	{ .name = "4", .dma_req = 12 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
-/* iss master ports */
-static struct omap_hwmod_ocp_if *omap44xx_iss_masters[] = {
-	&omap44xx_iss__l3_main_2,
-};
-
 static struct omap_hwmod_addr_space omap44xx_iss_addrs[] = {
 	{
 		.pa_start	= 0x52000000,
@@ -2653,70 +4833,12 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* iss slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_iss_slaves[] = {
-	&omap44xx_l3_main_2__iss,
-};
-
-static struct omap_hwmod_opt_clk iss_opt_clks[] = {
-	{ .role = "ctrlclk", .clk = "iss_ctrlclk" },
-};
-
-static struct omap_hwmod omap44xx_iss_hwmod = {
-	.name		= "iss",
-	.class		= &omap44xx_iss_hwmod_class,
-	.clkdm_name	= "iss_clkdm",
-	.mpu_irqs	= omap44xx_iss_irqs,
-	.sdma_reqs	= omap44xx_iss_sdma_reqs,
-	.main_clk	= "iss_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_CAM_ISS_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.opt_clks	= iss_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(iss_opt_clks),
-	.slaves		= omap44xx_iss_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_iss_slaves),
-	.masters	= omap44xx_iss_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_iss_masters),
-};
-
-/*
- * 'iva' class
- * multi-standard video encoder/decoder hardware accelerator
- */
-
-static struct omap_hwmod_class omap44xx_iva_hwmod_class = {
-	.name	= "iva",
-};
-
-/* iva */
-static struct omap_hwmod_irq_info omap44xx_iva_irqs[] = {
-	{ .name = "sync_1", .irq = 103 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "sync_0", .irq = 104 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "mailbox_0", .irq = 107 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_rst_info omap44xx_iva_resets[] = {
-	{ .name = "logic", .rst_shift = 2 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_iva_seq0_resets[] = {
-	{ .name = "seq0", .rst_shift = 0 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_iva_seq1_resets[] = {
-	{ .name = "seq1", .rst_shift = 1 },
-};
-
-/* iva master ports */
-static struct omap_hwmod_ocp_if *omap44xx_iva_masters[] = {
-	&omap44xx_iva__l3_main_2,
-	&omap44xx_iva__l3_instr,
+/* iva -> sl2if */
+static struct omap_hwmod_ocp_if omap44xx_iva__sl2if = {
+	.master		= &omap44xx_iva_hwmod,
+	.slave		= &omap44xx_sl2if_hwmod,
+	.clk		= "dpll_iva_m5x2_ck",
+	.user		= OCP_USER_IVA,
 };
 
 static struct omap_hwmod_addr_space omap44xx_iva_addrs[] = {
@@ -2737,93 +4859,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-/* iva slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_iva_slaves[] = {
-	&omap44xx_dsp__iva,
-	&omap44xx_l3_main_2__iva,
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_iva_seq0_hwmod = {
-	.name		= "iva_seq0",
-	.class		= &omap44xx_iva_hwmod_class,
-	.clkdm_name	= "ivahd_clkdm",
-	.flags		= HWMOD_INIT_NO_RESET,
-	.rst_lines	= omap44xx_iva_seq0_resets,
-	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_iva_seq0_resets),
-	.prcm = {
-		.omap4 = {
-			.rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET,
-		},
-	},
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_iva_seq1_hwmod = {
-	.name		= "iva_seq1",
-	.class		= &omap44xx_iva_hwmod_class,
-	.clkdm_name	= "ivahd_clkdm",
-	.flags		= HWMOD_INIT_NO_RESET,
-	.rst_lines	= omap44xx_iva_seq1_resets,
-	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_iva_seq1_resets),
-	.prcm = {
-		.omap4 = {
-			.rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET,
-		},
-	},
-};
-
-static struct omap_hwmod omap44xx_iva_hwmod = {
-	.name		= "iva",
-	.class		= &omap44xx_iva_hwmod_class,
-	.clkdm_name	= "ivahd_clkdm",
-	.mpu_irqs	= omap44xx_iva_irqs,
-	.rst_lines	= omap44xx_iva_resets,
-	.rst_lines_cnt	= ARRAY_SIZE(omap44xx_iva_resets),
-	.main_clk	= "iva_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_IVAHD_IVAHD_CLKCTRL_OFFSET,
-			.rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET,
-			.context_offs = OMAP4_RM_IVAHD_IVAHD_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.slaves		= omap44xx_iva_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_iva_slaves),
-	.masters	= omap44xx_iva_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_iva_masters),
-};
-
-/*
- * 'kbd' class
- * keyboard controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_kbd_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSC_HAS_EMUFREE | SYSC_HAS_ENAWAKEUP |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-			   SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_kbd_hwmod_class = {
-	.name	= "kbd",
-	.sysc	= &omap44xx_kbd_sysc,
-};
-
-/* kbd */
-static struct omap_hwmod omap44xx_kbd_hwmod;
-static struct omap_hwmod_irq_info omap44xx_kbd_irqs[] = {
-	{ .irq = 120 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_kbd_addrs[] = {
 	{
 		.pa_start	= 0x4a31c000,
@@ -2842,55 +4877,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* kbd slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_kbd_slaves[] = {
-	&omap44xx_l4_wkup__kbd,
-};
-
-static struct omap_hwmod omap44xx_kbd_hwmod = {
-	.name		= "kbd",
-	.class		= &omap44xx_kbd_hwmod_class,
-	.clkdm_name	= "l4_wkup_clkdm",
-	.mpu_irqs	= omap44xx_kbd_irqs,
-	.main_clk	= "kbd_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_WKUP_KEYBOARD_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_WKUP_KEYBOARD_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_kbd_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_kbd_slaves),
-};
-
-/*
- * 'mailbox' class
- * mailbox module allowing communication between the on-chip processors using a
- * queued mailbox-interrupt mechanism.
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mailbox_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.sysc_flags	= (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_mailbox_hwmod_class = {
-	.name	= "mailbox",
-	.sysc	= &omap44xx_mailbox_sysc,
-};
-
-/* mailbox */
-static struct omap_hwmod omap44xx_mailbox_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mailbox_irqs[] = {
-	{ .irq = 26 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mailbox_addrs[] = {
 	{
 		.pa_start	= 0x4a0f4000,
@@ -2909,56 +4895,40 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mailbox slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mailbox_slaves[] = {
-	&omap44xx_l4_cfg__mailbox,
-};
-
-static struct omap_hwmod omap44xx_mailbox_hwmod = {
-	.name		= "mailbox",
-	.class		= &omap44xx_mailbox_hwmod_class,
-	.clkdm_name	= "l4_cfg_clkdm",
-	.mpu_irqs	= omap44xx_mailbox_irqs,
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4CFG_MAILBOX_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4CFG_MAILBOX_CONTEXT_OFFSET,
-		},
+static struct omap_hwmod_addr_space omap44xx_mcasp_addrs[] = {
+	{
+		.pa_start	= 0x40128000,
+		.pa_end		= 0x401283ff,
+		.flags		= ADDR_TYPE_RT
 	},
-	.slaves		= omap44xx_mailbox_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mailbox_slaves),
+	{ }
 };
 
-/*
- * 'mcbsp' class
- * multi channel buffered serial port controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mcbsp_sysc = {
-	.sysc_offs	= 0x008c,
-	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_ENAWAKEUP |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
+/* l4_abe -> mcasp */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcasp = {
+	.master		= &omap44xx_l4_abe_hwmod,
+	.slave		= &omap44xx_mcasp_hwmod,
+	.clk		= "ocp_abe_iclk",
+	.addr		= omap44xx_mcasp_addrs,
+	.user		= OCP_USER_MPU,
 };
 
-static struct omap_hwmod_class omap44xx_mcbsp_hwmod_class = {
-	.name	= "mcbsp",
-	.sysc	= &omap44xx_mcbsp_sysc,
-	.rev	= MCBSP_CONFIG_TYPE4,
+static struct omap_hwmod_addr_space omap44xx_mcasp_dma_addrs[] = {
+	{
+		.pa_start	= 0x49028000,
+		.pa_end		= 0x490283ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
 };
 
-/* mcbsp1 */
-static struct omap_hwmod omap44xx_mcbsp1_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcbsp1_irqs[] = {
-	{ .irq = 17 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcbsp1_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 32 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 33 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
+/* l4_abe -> mcasp (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcasp_dma = {
+	.master		= &omap44xx_l4_abe_hwmod,
+	.slave		= &omap44xx_mcasp_hwmod,
+	.clk		= "ocp_abe_iclk",
+	.addr		= omap44xx_mcasp_dma_addrs,
+	.user		= OCP_USER_SDMA,
 };
 
 static struct omap_hwmod_addr_space omap44xx_mcbsp1_addrs[] = {
@@ -2999,50 +4969,6 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* mcbsp1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcbsp1_slaves[] = {
-	&omap44xx_l4_abe__mcbsp1,
-	&omap44xx_l4_abe__mcbsp1_dma,
-};
-
-static struct omap_hwmod_opt_clk mcbsp1_opt_clks[] = {
-	{ .role = "pad_fck", .clk = "pad_clks_ck" },
-	{ .role = "prcm_clk", .clk = "mcbsp1_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
-	.name		= "mcbsp1",
-	.class		= &omap44xx_mcbsp_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_mcbsp1_irqs,
-	.sdma_reqs	= omap44xx_mcbsp1_sdma_reqs,
-	.main_clk	= "mcbsp1_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_MCBSP1_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_mcbsp1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcbsp1_slaves),
-	.opt_clks	= mcbsp1_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(mcbsp1_opt_clks),
-};
-
-/* mcbsp2 */
-static struct omap_hwmod omap44xx_mcbsp2_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcbsp2_irqs[] = {
-	{ .irq = 22 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcbsp2_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 16 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 17 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mcbsp2_addrs[] = {
 	{
 		.name		= "mpu",
@@ -3081,50 +5007,6 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* mcbsp2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcbsp2_slaves[] = {
-	&omap44xx_l4_abe__mcbsp2,
-	&omap44xx_l4_abe__mcbsp2_dma,
-};
-
-static struct omap_hwmod_opt_clk mcbsp2_opt_clks[] = {
-	{ .role = "pad_fck", .clk = "pad_clks_ck" },
-	{ .role = "prcm_clk", .clk = "mcbsp2_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
-	.name		= "mcbsp2",
-	.class		= &omap44xx_mcbsp_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_mcbsp2_irqs,
-	.sdma_reqs	= omap44xx_mcbsp2_sdma_reqs,
-	.main_clk	= "mcbsp2_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_MCBSP2_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_mcbsp2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcbsp2_slaves),
-	.opt_clks	= mcbsp2_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(mcbsp2_opt_clks),
-};
-
-/* mcbsp3 */
-static struct omap_hwmod omap44xx_mcbsp3_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcbsp3_irqs[] = {
-	{ .irq = 23 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcbsp3_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 18 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 19 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mcbsp3_addrs[] = {
 	{
 		.name		= "mpu",
@@ -3163,50 +5045,6 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* mcbsp3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcbsp3_slaves[] = {
-	&omap44xx_l4_abe__mcbsp3,
-	&omap44xx_l4_abe__mcbsp3_dma,
-};
-
-static struct omap_hwmod_opt_clk mcbsp3_opt_clks[] = {
-	{ .role = "pad_fck", .clk = "pad_clks_ck" },
-	{ .role = "prcm_clk", .clk = "mcbsp3_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
-	.name		= "mcbsp3",
-	.class		= &omap44xx_mcbsp_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_mcbsp3_irqs,
-	.sdma_reqs	= omap44xx_mcbsp3_sdma_reqs,
-	.main_clk	= "mcbsp3_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_MCBSP3_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_mcbsp3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcbsp3_slaves),
-	.opt_clks	= mcbsp3_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(mcbsp3_opt_clks),
-};
-
-/* mcbsp4 */
-static struct omap_hwmod omap44xx_mcbsp4_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcbsp4_irqs[] = {
-	{ .irq = 16 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcbsp4_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 30 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 31 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mcbsp4_addrs[] = {
 	{
 		.pa_start	= 0x48096000,
@@ -3225,70 +5063,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcbsp4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcbsp4_slaves[] = {
-	&omap44xx_l4_per__mcbsp4,
-};
-
-static struct omap_hwmod_opt_clk mcbsp4_opt_clks[] = {
-	{ .role = "pad_fck", .clk = "pad_clks_ck" },
-	{ .role = "prcm_clk", .clk = "mcbsp4_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
-	.name		= "mcbsp4",
-	.class		= &omap44xx_mcbsp_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_mcbsp4_irqs,
-	.sdma_reqs	= omap44xx_mcbsp4_sdma_reqs,
-	.main_clk	= "mcbsp4_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_MCBSP4_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_mcbsp4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcbsp4_slaves),
-	.opt_clks	= mcbsp4_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(mcbsp4_opt_clks),
-};
-
-/*
- * 'mcpdm' class
- * multi channel pdm controller (proprietary interface with phoenix power
- * ic)
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mcpdm_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_mcpdm_hwmod_class = {
-	.name	= "mcpdm",
-	.sysc	= &omap44xx_mcpdm_sysc,
-};
-
-/* mcpdm */
-static struct omap_hwmod omap44xx_mcpdm_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcpdm_irqs[] = {
-	{ .irq = 112 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcpdm_sdma_reqs[] = {
-	{ .name = "up_link", .dma_req = 64 + OMAP44XX_DMA_REQ_START },
-	{ .name = "dn_link", .dma_req = 65 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mcpdm_addrs[] = {
 	{
 		.pa_start	= 0x40132000,
@@ -3325,71 +5099,6 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* mcpdm slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcpdm_slaves[] = {
-	&omap44xx_l4_abe__mcpdm,
-	&omap44xx_l4_abe__mcpdm_dma,
-};
-
-static struct omap_hwmod omap44xx_mcpdm_hwmod = {
-	.name		= "mcpdm",
-	.class		= &omap44xx_mcpdm_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_mcpdm_irqs,
-	.sdma_reqs	= omap44xx_mcpdm_sdma_reqs,
-	.main_clk	= "mcpdm_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_PDM_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_PDM_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_mcpdm_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcpdm_slaves),
-};
-
-/*
- * 'mcspi' class
- * multichannel serial port interface (mcspi) / master/slave synchronous serial
- * bus
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mcspi_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_mcspi_hwmod_class = {
-	.name	= "mcspi",
-	.sysc	= &omap44xx_mcspi_sysc,
-	.rev	= OMAP4_MCSPI_REV,
-};
-
-/* mcspi1 */
-static struct omap_hwmod omap44xx_mcspi1_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcspi1_irqs[] = {
-	{ .irq = 65 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcspi1_sdma_reqs[] = {
-	{ .name = "tx0", .dma_req = 34 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx0", .dma_req = 35 + OMAP44XX_DMA_REQ_START },
-	{ .name = "tx1", .dma_req = 36 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx1", .dma_req = 37 + OMAP44XX_DMA_REQ_START },
-	{ .name = "tx2", .dma_req = 38 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx2", .dma_req = 39 + OMAP44XX_DMA_REQ_START },
-	{ .name = "tx3", .dma_req = 40 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx3", .dma_req = 41 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mcspi1_addrs[] = {
 	{
 		.pa_start	= 0x48098000,
@@ -3408,50 +5117,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcspi1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcspi1_slaves[] = {
-	&omap44xx_l4_per__mcspi1,
-};
-
-/* mcspi1 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi1_dev_attr = {
-	.num_chipselect	= 4,
-};
-
-static struct omap_hwmod omap44xx_mcspi1_hwmod = {
-	.name		= "mcspi1",
-	.class		= &omap44xx_mcspi_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_mcspi1_irqs,
-	.sdma_reqs	= omap44xx_mcspi1_sdma_reqs,
-	.main_clk	= "mcspi1_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_MCSPI1_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &mcspi1_dev_attr,
-	.slaves		= omap44xx_mcspi1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcspi1_slaves),
-};
-
-/* mcspi2 */
-static struct omap_hwmod omap44xx_mcspi2_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcspi2_irqs[] = {
-	{ .irq = 66 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcspi2_sdma_reqs[] = {
-	{ .name = "tx0", .dma_req = 42 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx0", .dma_req = 43 + OMAP44XX_DMA_REQ_START },
-	{ .name = "tx1", .dma_req = 44 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx1", .dma_req = 45 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mcspi2_addrs[] = {
 	{
 		.pa_start	= 0x4809a000,
@@ -3470,50 +5135,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcspi2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcspi2_slaves[] = {
-	&omap44xx_l4_per__mcspi2,
-};
-
-/* mcspi2 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi2_dev_attr = {
-	.num_chipselect	= 2,
-};
-
-static struct omap_hwmod omap44xx_mcspi2_hwmod = {
-	.name		= "mcspi2",
-	.class		= &omap44xx_mcspi_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_mcspi2_irqs,
-	.sdma_reqs	= omap44xx_mcspi2_sdma_reqs,
-	.main_clk	= "mcspi2_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_MCSPI2_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &mcspi2_dev_attr,
-	.slaves		= omap44xx_mcspi2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcspi2_slaves),
-};
-
-/* mcspi3 */
-static struct omap_hwmod omap44xx_mcspi3_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcspi3_irqs[] = {
-	{ .irq = 91 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcspi3_sdma_reqs[] = {
-	{ .name = "tx0", .dma_req = 14 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx0", .dma_req = 15 + OMAP44XX_DMA_REQ_START },
-	{ .name = "tx1", .dma_req = 22 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx1", .dma_req = 23 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mcspi3_addrs[] = {
 	{
 		.pa_start	= 0x480b8000,
@@ -3532,48 +5153,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcspi3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcspi3_slaves[] = {
-	&omap44xx_l4_per__mcspi3,
-};
-
-/* mcspi3 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi3_dev_attr = {
-	.num_chipselect	= 2,
-};
-
-static struct omap_hwmod omap44xx_mcspi3_hwmod = {
-	.name		= "mcspi3",
-	.class		= &omap44xx_mcspi_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_mcspi3_irqs,
-	.sdma_reqs	= omap44xx_mcspi3_sdma_reqs,
-	.main_clk	= "mcspi3_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_MCSPI3_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &mcspi3_dev_attr,
-	.slaves		= omap44xx_mcspi3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcspi3_slaves),
-};
-
-/* mcspi4 */
-static struct omap_hwmod omap44xx_mcspi4_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcspi4_irqs[] = {
-	{ .irq = 48 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcspi4_sdma_reqs[] = {
-	{ .name = "tx0", .dma_req = 69 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx0", .dma_req = 70 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mcspi4_addrs[] = {
 	{
 		.pa_start	= 0x480ba000,
@@ -3592,74 +5171,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mcspi4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcspi4_slaves[] = {
-	&omap44xx_l4_per__mcspi4,
-};
-
-/* mcspi4 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi4_dev_attr = {
-	.num_chipselect	= 1,
-};
-
-static struct omap_hwmod omap44xx_mcspi4_hwmod = {
-	.name		= "mcspi4",
-	.class		= &omap44xx_mcspi_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_mcspi4_irqs,
-	.sdma_reqs	= omap44xx_mcspi4_sdma_reqs,
-	.main_clk	= "mcspi4_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_MCSPI4_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &mcspi4_dev_attr,
-	.slaves		= omap44xx_mcspi4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcspi4_slaves),
-};
-
-/*
- * 'mmc' class
- * multimedia card high-speed/sd/sdio (mmc/sd/sdio) host controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mmc_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
-			   SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
-			   MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_mmc_hwmod_class = {
-	.name	= "mmc",
-	.sysc	= &omap44xx_mmc_sysc,
-};
-
-/* mmc1 */
-static struct omap_hwmod_irq_info omap44xx_mmc1_irqs[] = {
-	{ .irq = 83 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mmc1_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 60 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 61 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
-/* mmc1 master ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc1_masters[] = {
-	&omap44xx_mmc1__l3_main_1,
-};
-
 static struct omap_hwmod_addr_space omap44xx_mmc1_addrs[] = {
 	{
 		.pa_start	= 0x4809c000,
@@ -3678,54 +5189,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mmc1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc1_slaves[] = {
-	&omap44xx_l4_per__mmc1,
-};
-
-/* mmc1 dev_attr */
-static struct omap_mmc_dev_attr mmc1_dev_attr = {
-	.flags	= OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
-};
-
-static struct omap_hwmod omap44xx_mmc1_hwmod = {
-	.name		= "mmc1",
-	.class		= &omap44xx_mmc_hwmod_class,
-	.clkdm_name	= "l3_init_clkdm",
-	.mpu_irqs	= omap44xx_mmc1_irqs,
-	.sdma_reqs	= omap44xx_mmc1_sdma_reqs,
-	.main_clk	= "mmc1_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3INIT_MMC1_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &mmc1_dev_attr,
-	.slaves		= omap44xx_mmc1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mmc1_slaves),
-	.masters	= omap44xx_mmc1_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_mmc1_masters),
-};
-
-/* mmc2 */
-static struct omap_hwmod_irq_info omap44xx_mmc2_irqs[] = {
-	{ .irq = 86 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mmc2_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 46 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 47 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
-/* mmc2 master ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc2_masters[] = {
-	&omap44xx_mmc2__l3_main_1,
-};
-
 static struct omap_hwmod_addr_space omap44xx_mmc2_addrs[] = {
 	{
 		.pa_start	= 0x480b4000,
@@ -3744,44 +5207,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mmc2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc2_slaves[] = {
-	&omap44xx_l4_per__mmc2,
-};
-
-static struct omap_hwmod omap44xx_mmc2_hwmod = {
-	.name		= "mmc2",
-	.class		= &omap44xx_mmc_hwmod_class,
-	.clkdm_name	= "l3_init_clkdm",
-	.mpu_irqs	= omap44xx_mmc2_irqs,
-	.sdma_reqs	= omap44xx_mmc2_sdma_reqs,
-	.main_clk	= "mmc2_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3INIT_MMC2_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_mmc2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mmc2_slaves),
-	.masters	= omap44xx_mmc2_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_mmc2_masters),
-};
-
-/* mmc3 */
-static struct omap_hwmod omap44xx_mmc3_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mmc3_irqs[] = {
-	{ .irq = 94 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mmc3_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 76 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 77 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mmc3_addrs[] = {
 	{
 		.pa_start	= 0x480ad000,
@@ -3800,42 +5225,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mmc3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc3_slaves[] = {
-	&omap44xx_l4_per__mmc3,
-};
-
-static struct omap_hwmod omap44xx_mmc3_hwmod = {
-	.name		= "mmc3",
-	.class		= &omap44xx_mmc_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_mmc3_irqs,
-	.sdma_reqs	= omap44xx_mmc3_sdma_reqs,
-	.main_clk	= "mmc3_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_MMCSD3_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_mmc3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mmc3_slaves),
-};
-
-/* mmc4 */
-static struct omap_hwmod omap44xx_mmc4_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mmc4_irqs[] = {
-	{ .irq = 96 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mmc4_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 56 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 57 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mmc4_addrs[] = {
 	{
 		.pa_start	= 0x480d1000,
@@ -3854,43 +5243,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mmc4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc4_slaves[] = {
-	&omap44xx_l4_per__mmc4,
-};
-
-static struct omap_hwmod omap44xx_mmc4_hwmod = {
-	.name		= "mmc4",
-	.class		= &omap44xx_mmc_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_mmc4_irqs,
-
-	.sdma_reqs	= omap44xx_mmc4_sdma_reqs,
-	.main_clk	= "mmc4_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_MMCSD4_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_mmc4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mmc4_slaves),
-};
-
-/* mmc5 */
-static struct omap_hwmod omap44xx_mmc5_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mmc5_irqs[] = {
-	{ .irq = 59 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_mmc5_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 58 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 59 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_mmc5_addrs[] = {
 	{
 		.pa_start	= 0x480d5000,
@@ -3909,105 +5261,172 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mmc5 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc5_slaves[] = {
-	&omap44xx_l4_per__mmc5,
+/* l3_main_2 -> ocmc_ram */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ocmc_ram = {
+	.master		= &omap44xx_l3_main_2_hwmod,
+	.slave		= &omap44xx_ocmc_ram_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod omap44xx_mmc5_hwmod = {
-	.name		= "mmc5",
-	.class		= &omap44xx_mmc_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_mmc5_irqs,
-	.sdma_reqs	= omap44xx_mmc5_sdma_reqs,
-	.main_clk	= "mmc5_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_MMCSD5_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
+/* l4_cfg -> ocp2scp_usb_phy */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ocp2scp_usb_phy = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_ocp2scp_usb_phy_hwmod,
+	.clk		= "l4_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_prcm_mpu_addrs[] = {
+	{
+		.pa_start	= 0x48243000,
+		.pa_end		= 0x48243fff,
+		.flags		= ADDR_TYPE_RT
 	},
-	.slaves		= omap44xx_mmc5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_mmc5_slaves),
+	{ }
 };
 
-/*
- * 'mpu' class
- * mpu sub-system
- */
-
-static struct omap_hwmod_class omap44xx_mpu_hwmod_class = {
-	.name	= "mpu",
+/* mpu_private -> prcm_mpu */
+static struct omap_hwmod_ocp_if omap44xx_mpu_private__prcm_mpu = {
+	.master		= &omap44xx_mpu_private_hwmod,
+	.slave		= &omap44xx_prcm_mpu_hwmod,
+	.clk		= "l3_div_ck",
+	.addr		= omap44xx_prcm_mpu_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mpu */
-static struct omap_hwmod_irq_info omap44xx_mpu_irqs[] = {
-	{ .name = "pl310", .irq = 0 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "cti0", .irq = 1 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "cti1", .irq = 2 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-/* mpu master ports */
-static struct omap_hwmod_ocp_if *omap44xx_mpu_masters[] = {
-	&omap44xx_mpu__l3_main_1,
-	&omap44xx_mpu__l4_abe,
-	&omap44xx_mpu__dmm,
-};
-
-static struct omap_hwmod omap44xx_mpu_hwmod = {
-	.name		= "mpu",
-	.class		= &omap44xx_mpu_hwmod_class,
-	.clkdm_name	= "mpuss_clkdm",
-	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
-	.mpu_irqs	= omap44xx_mpu_irqs,
-	.main_clk	= "dpll_mpu_m2_ck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_MPU_MPU_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_MPU_MPU_CONTEXT_OFFSET,
-		},
+static struct omap_hwmod_addr_space omap44xx_cm_core_aon_addrs[] = {
+	{
+		.pa_start	= 0x4a004000,
+		.pa_end		= 0x4a004fff,
+		.flags		= ADDR_TYPE_RT
 	},
-	.masters	= omap44xx_mpu_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_mpu_masters),
+	{ }
 };
 
-/*
- * 'smartreflex' class
- * smartreflex module (monitor silicon performance and outputs a measure of
- * performance error)
- */
-
-/* The IP is not compliant to type1 / type2 scheme */
-static struct omap_hwmod_sysc_fields omap_hwmod_sysc_type_smartreflex = {
-	.sidle_shift	= 24,
-	.enwkup_shift	= 26,
+/* l4_wkup -> cm_core_aon */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__cm_core_aon = {
+	.master		= &omap44xx_l4_wkup_hwmod,
+	.slave		= &omap44xx_cm_core_aon_hwmod,
+	.clk		= "l4_wkup_clk_mux_ck",
+	.addr		= omap44xx_cm_core_aon_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_class_sysconfig omap44xx_smartreflex_sysc = {
-	.sysc_offs	= 0x0038,
-	.sysc_flags	= (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type_smartreflex,
+static struct omap_hwmod_addr_space omap44xx_cm_core_addrs[] = {
+	{
+		.pa_start	= 0x4a008000,
+		.pa_end		= 0x4a009fff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
 };
 
-static struct omap_hwmod_class omap44xx_smartreflex_hwmod_class = {
-	.name	= "smartreflex",
-	.sysc	= &omap44xx_smartreflex_sysc,
-	.rev	= 2,
+/* l4_cfg -> cm_core */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__cm_core = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_cm_core_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_cm_core_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* smartreflex_core */
-static struct omap_smartreflex_dev_attr smartreflex_core_dev_attr = {
-	.sensor_voltdm_name   = "core",
+static struct omap_hwmod_addr_space omap44xx_prm_addrs[] = {
+	{
+		.pa_start	= 0x4a306000,
+		.pa_end		= 0x4a307fff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
 };
 
-static struct omap_hwmod omap44xx_smartreflex_core_hwmod;
-static struct omap_hwmod_irq_info omap44xx_smartreflex_core_irqs[] = {
-	{ .irq = 19 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
+/* l4_wkup -> prm */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__prm = {
+	.master		= &omap44xx_l4_wkup_hwmod,
+	.slave		= &omap44xx_prm_hwmod,
+	.clk		= "l4_wkup_clk_mux_ck",
+	.addr		= omap44xx_prm_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_scrm_addrs[] = {
+	{
+		.pa_start	= 0x4a30a000,
+		.pa_end		= 0x4a30a7ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_wkup -> scrm */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__scrm = {
+	.master		= &omap44xx_l4_wkup_hwmod,
+	.slave		= &omap44xx_scrm_hwmod,
+	.clk		= "l4_wkup_clk_mux_ck",
+	.addr		= omap44xx_scrm_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 -> sl2if */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__sl2if = {
+	.master		= &omap44xx_l3_main_2_hwmod,
+	.slave		= &omap44xx_sl2if_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_slimbus1_addrs[] = {
+	{
+		.pa_start	= 0x4012c000,
+		.pa_end		= 0x4012c3ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_abe -> slimbus1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__slimbus1 = {
+	.master		= &omap44xx_l4_abe_hwmod,
+	.slave		= &omap44xx_slimbus1_hwmod,
+	.clk		= "ocp_abe_iclk",
+	.addr		= omap44xx_slimbus1_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_slimbus1_dma_addrs[] = {
+	{
+		.pa_start	= 0x4902c000,
+		.pa_end		= 0x4902c3ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_abe -> slimbus1 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__slimbus1_dma = {
+	.master		= &omap44xx_l4_abe_hwmod,
+	.slave		= &omap44xx_slimbus1_hwmod,
+	.clk		= "ocp_abe_iclk",
+	.addr		= omap44xx_slimbus1_dma_addrs,
+	.user		= OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_slimbus2_addrs[] = {
+	{
+		.pa_start	= 0x48076000,
+		.pa_end		= 0x480763ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_per -> slimbus2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__slimbus2 = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_slimbus2_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_slimbus2_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 static struct omap_hwmod_addr_space omap44xx_smartreflex_core_addrs[] = {
@@ -4028,41 +5447,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* smartreflex_core slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_smartreflex_core_slaves[] = {
-	&omap44xx_l4_cfg__smartreflex_core,
-};
-
-static struct omap_hwmod omap44xx_smartreflex_core_hwmod = {
-	.name		= "smartreflex_core",
-	.class		= &omap44xx_smartreflex_hwmod_class,
-	.clkdm_name	= "l4_ao_clkdm",
-	.mpu_irqs	= omap44xx_smartreflex_core_irqs,
-
-	.main_clk	= "smartreflex_core_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ALWON_SR_CORE_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_smartreflex_core_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_smartreflex_core_slaves),
-	.dev_attr	= &smartreflex_core_dev_attr,
-};
-
-/* smartreflex_iva */
-static struct omap_smartreflex_dev_attr smartreflex_iva_dev_attr = {
-	.sensor_voltdm_name	= "iva",
-};
-
-static struct omap_hwmod omap44xx_smartreflex_iva_hwmod;
-static struct omap_hwmod_irq_info omap44xx_smartreflex_iva_irqs[] = {
-	{ .irq = 102 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_smartreflex_iva_addrs[] = {
 	{
 		.pa_start	= 0x4a0db000,
@@ -4081,40 +5465,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* smartreflex_iva slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_smartreflex_iva_slaves[] = {
-	&omap44xx_l4_cfg__smartreflex_iva,
-};
-
-static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = {
-	.name		= "smartreflex_iva",
-	.class		= &omap44xx_smartreflex_hwmod_class,
-	.clkdm_name	= "l4_ao_clkdm",
-	.mpu_irqs	= omap44xx_smartreflex_iva_irqs,
-	.main_clk	= "smartreflex_iva_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_ALWON_SR_IVA_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ALWON_SR_IVA_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_smartreflex_iva_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_smartreflex_iva_slaves),
-	.dev_attr	= &smartreflex_iva_dev_attr,
-};
-
-/* smartreflex_mpu */
-static struct omap_smartreflex_dev_attr smartreflex_mpu_dev_attr = {
-	.sensor_voltdm_name	= "mpu",
-};
-
-static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod;
-static struct omap_hwmod_irq_info omap44xx_smartreflex_mpu_irqs[] = {
-	{ .irq = 18 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_smartreflex_mpu_addrs[] = {
 	{
 		.pa_start	= 0x4a0d9000,
@@ -4133,54 +5483,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* smartreflex_mpu slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_smartreflex_mpu_slaves[] = {
-	&omap44xx_l4_cfg__smartreflex_mpu,
-};
-
-static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = {
-	.name		= "smartreflex_mpu",
-	.class		= &omap44xx_smartreflex_hwmod_class,
-	.clkdm_name	= "l4_ao_clkdm",
-	.mpu_irqs	= omap44xx_smartreflex_mpu_irqs,
-	.main_clk	= "smartreflex_mpu_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_ALWON_SR_MPU_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ALWON_SR_MPU_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_smartreflex_mpu_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_smartreflex_mpu_slaves),
-	.dev_attr	= &smartreflex_mpu_dev_attr,
-};
-
-/*
- * 'spinlock' class
- * spinlock provides hardware assistance for synchronizing the processes
- * running on multiple processors
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_spinlock_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_spinlock_hwmod_class = {
-	.name	= "spinlock",
-	.sysc	= &omap44xx_spinlock_sysc,
-};
-
-/* spinlock */
-static struct omap_hwmod omap44xx_spinlock_hwmod;
 static struct omap_hwmod_addr_space omap44xx_spinlock_addrs[] = {
 	{
 		.pa_start	= 0x4a0f6000,
@@ -4199,80 +5501,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* spinlock slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_spinlock_slaves[] = {
-	&omap44xx_l4_cfg__spinlock,
-};
-
-static struct omap_hwmod omap44xx_spinlock_hwmod = {
-	.name		= "spinlock",
-	.class		= &omap44xx_spinlock_hwmod_class,
-	.clkdm_name	= "l4_cfg_clkdm",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4CFG_HW_SEM_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4CFG_HW_SEM_CONTEXT_OFFSET,
-		},
-	},
-	.slaves		= omap44xx_spinlock_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_spinlock_slaves),
-};
-
-/*
- * 'timer' class
- * general purpose timer module with accurate 1ms tick
- * This class contains several variants: ['timer_1ms', 'timer']
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_timer_1ms_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-			   SYSC_HAS_EMUFREE | SYSC_HAS_ENAWAKEUP |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-			   SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_timer_1ms_hwmod_class = {
-	.name	= "timer",
-	.sysc	= &omap44xx_timer_1ms_sysc,
-};
-
-static struct omap_hwmod_class_sysconfig omap44xx_timer_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
-	.name	= "timer",
-	.sysc	= &omap44xx_timer_sysc,
-};
-
-/* always-on timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
-	.timer_capability	= OMAP_TIMER_ALWON,
-};
-
-/* pwm timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
-	.timer_capability	= OMAP_TIMER_HAS_PWM,
-};
-
-/* timer1 */
-static struct omap_hwmod omap44xx_timer1_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer1_irqs[] = {
-	{ .irq = 37 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer1_addrs[] = {
 	{
 		.pa_start	= 0x4a318000,
@@ -4291,36 +5519,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer1_slaves[] = {
-	&omap44xx_l4_wkup__timer1,
-};
-
-static struct omap_hwmod omap44xx_timer1_hwmod = {
-	.name		= "timer1",
-	.class		= &omap44xx_timer_1ms_hwmod_class,
-	.clkdm_name	= "l4_wkup_clkdm",
-	.mpu_irqs	= omap44xx_timer1_irqs,
-	.main_clk	= "timer1_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_WKUP_TIMER1_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_WKUP_TIMER1_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap44xx_timer1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer1_slaves),
-};
-
-/* timer2 */
-static struct omap_hwmod omap44xx_timer2_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer2_irqs[] = {
-	{ .irq = 38 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer2_addrs[] = {
 	{
 		.pa_start	= 0x48032000,
@@ -4339,36 +5537,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer2_slaves[] = {
-	&omap44xx_l4_per__timer2,
-};
-
-static struct omap_hwmod omap44xx_timer2_hwmod = {
-	.name		= "timer2",
-	.class		= &omap44xx_timer_1ms_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_timer2_irqs,
-	.main_clk	= "timer2_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER2_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_DMTIMER2_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap44xx_timer2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer2_slaves),
-};
-
-/* timer3 */
-static struct omap_hwmod omap44xx_timer3_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer3_irqs[] = {
-	{ .irq = 39 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer3_addrs[] = {
 	{
 		.pa_start	= 0x48034000,
@@ -4387,36 +5555,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer3_slaves[] = {
-	&omap44xx_l4_per__timer3,
-};
-
-static struct omap_hwmod omap44xx_timer3_hwmod = {
-	.name		= "timer3",
-	.class		= &omap44xx_timer_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_timer3_irqs,
-	.main_clk	= "timer3_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER3_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_DMTIMER3_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap44xx_timer3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer3_slaves),
-};
-
-/* timer4 */
-static struct omap_hwmod omap44xx_timer4_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer4_irqs[] = {
-	{ .irq = 40 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer4_addrs[] = {
 	{
 		.pa_start	= 0x48036000,
@@ -4435,36 +5573,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer4_slaves[] = {
-	&omap44xx_l4_per__timer4,
-};
-
-static struct omap_hwmod omap44xx_timer4_hwmod = {
-	.name		= "timer4",
-	.class		= &omap44xx_timer_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_timer4_irqs,
-	.main_clk	= "timer4_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER4_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_DMTIMER4_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap44xx_timer4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer4_slaves),
-};
-
-/* timer5 */
-static struct omap_hwmod omap44xx_timer5_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer5_irqs[] = {
-	{ .irq = 41 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer5_addrs[] = {
 	{
 		.pa_start	= 0x40138000,
@@ -4501,37 +5609,6 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* timer5 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer5_slaves[] = {
-	&omap44xx_l4_abe__timer5,
-	&omap44xx_l4_abe__timer5_dma,
-};
-
-static struct omap_hwmod omap44xx_timer5_hwmod = {
-	.name		= "timer5",
-	.class		= &omap44xx_timer_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_timer5_irqs,
-	.main_clk	= "timer5_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_TIMER5_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_TIMER5_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap44xx_timer5_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer5_slaves),
-};
-
-/* timer6 */
-static struct omap_hwmod omap44xx_timer6_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer6_irqs[] = {
-	{ .irq = 42 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer6_addrs[] = {
 	{
 		.pa_start	= 0x4013a000,
@@ -4568,38 +5645,6 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* timer6 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer6_slaves[] = {
-	&omap44xx_l4_abe__timer6,
-	&omap44xx_l4_abe__timer6_dma,
-};
-
-static struct omap_hwmod omap44xx_timer6_hwmod = {
-	.name		= "timer6",
-	.class		= &omap44xx_timer_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_timer6_irqs,
-
-	.main_clk	= "timer6_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_TIMER6_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_TIMER6_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap44xx_timer6_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer6_slaves),
-};
-
-/* timer7 */
-static struct omap_hwmod omap44xx_timer7_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer7_irqs[] = {
-	{ .irq = 43 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer7_addrs[] = {
 	{
 		.pa_start	= 0x4013c000,
@@ -4636,37 +5681,6 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* timer7 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer7_slaves[] = {
-	&omap44xx_l4_abe__timer7,
-	&omap44xx_l4_abe__timer7_dma,
-};
-
-static struct omap_hwmod omap44xx_timer7_hwmod = {
-	.name		= "timer7",
-	.class		= &omap44xx_timer_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_timer7_irqs,
-	.main_clk	= "timer7_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_TIMER7_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_TIMER7_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_alwon_dev_attr,
-	.slaves		= omap44xx_timer7_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer7_slaves),
-};
-
-/* timer8 */
-static struct omap_hwmod omap44xx_timer8_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer8_irqs[] = {
-	{ .irq = 44 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer8_addrs[] = {
 	{
 		.pa_start	= 0x4013e000,
@@ -4703,37 +5717,6 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* timer8 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer8_slaves[] = {
-	&omap44xx_l4_abe__timer8,
-	&omap44xx_l4_abe__timer8_dma,
-};
-
-static struct omap_hwmod omap44xx_timer8_hwmod = {
-	.name		= "timer8",
-	.class		= &omap44xx_timer_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_timer8_irqs,
-	.main_clk	= "timer8_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_TIMER8_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_TIMER8_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap44xx_timer8_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer8_slaves),
-};
-
-/* timer9 */
-static struct omap_hwmod omap44xx_timer9_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer9_irqs[] = {
-	{ .irq = 45 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer9_addrs[] = {
 	{
 		.pa_start	= 0x4803e000,
@@ -4752,36 +5735,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer9 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer9_slaves[] = {
-	&omap44xx_l4_per__timer9,
-};
-
-static struct omap_hwmod omap44xx_timer9_hwmod = {
-	.name		= "timer9",
-	.class		= &omap44xx_timer_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_timer9_irqs,
-	.main_clk	= "timer9_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER9_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_DMTIMER9_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap44xx_timer9_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer9_slaves),
-};
-
-/* timer10 */
-static struct omap_hwmod omap44xx_timer10_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer10_irqs[] = {
-	{ .irq = 46 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer10_addrs[] = {
 	{
 		.pa_start	= 0x48086000,
@@ -4800,36 +5753,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer10 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer10_slaves[] = {
-	&omap44xx_l4_per__timer10,
-};
-
-static struct omap_hwmod omap44xx_timer10_hwmod = {
-	.name		= "timer10",
-	.class		= &omap44xx_timer_1ms_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_timer10_irqs,
-	.main_clk	= "timer10_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER10_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_DMTIMER10_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap44xx_timer10_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer10_slaves),
-};
-
-/* timer11 */
-static struct omap_hwmod omap44xx_timer11_hwmod;
-static struct omap_hwmod_irq_info omap44xx_timer11_irqs[] = {
-	{ .irq = 47 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_timer11_addrs[] = {
 	{
 		.pa_start	= 0x48088000,
@@ -4848,64 +5771,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* timer11 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer11_slaves[] = {
-	&omap44xx_l4_per__timer11,
-};
-
-static struct omap_hwmod omap44xx_timer11_hwmod = {
-	.name		= "timer11",
-	.class		= &omap44xx_timer_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_timer11_irqs,
-	.main_clk	= "timer11_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER11_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_DMTIMER11_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.dev_attr	= &capability_pwm_dev_attr,
-	.slaves		= omap44xx_timer11_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer11_slaves),
-};
-
-/*
- * 'uart' class
- * universal asynchronous receiver/transmitter (uart)
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_uart_sysc = {
-	.rev_offs	= 0x0050,
-	.sysc_offs	= 0x0054,
-	.syss_offs	= 0x0058,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-			   SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_uart_hwmod_class = {
-	.name	= "uart",
-	.sysc	= &omap44xx_uart_sysc,
-};
-
-/* uart1 */
-static struct omap_hwmod omap44xx_uart1_hwmod;
-static struct omap_hwmod_irq_info omap44xx_uart1_irqs[] = {
-	{ .irq = 72 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_uart1_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 48 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 49 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_uart1_addrs[] = {
 	{
 		.pa_start	= 0x4806a000,
@@ -4924,42 +5789,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* uart1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_uart1_slaves[] = {
-	&omap44xx_l4_per__uart1,
-};
-
-static struct omap_hwmod omap44xx_uart1_hwmod = {
-	.name		= "uart1",
-	.class		= &omap44xx_uart_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_uart1_irqs,
-	.sdma_reqs	= omap44xx_uart1_sdma_reqs,
-	.main_clk	= "uart1_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_UART1_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_uart1_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart1_slaves),
-};
-
-/* uart2 */
-static struct omap_hwmod omap44xx_uart2_hwmod;
-static struct omap_hwmod_irq_info omap44xx_uart2_irqs[] = {
-	{ .irq = 73 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_uart2_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 50 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 51 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_uart2_addrs[] = {
 	{
 		.pa_start	= 0x4806c000,
@@ -4978,42 +5807,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* uart2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_uart2_slaves[] = {
-	&omap44xx_l4_per__uart2,
-};
-
-static struct omap_hwmod omap44xx_uart2_hwmod = {
-	.name		= "uart2",
-	.class		= &omap44xx_uart_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_uart2_irqs,
-	.sdma_reqs	= omap44xx_uart2_sdma_reqs,
-	.main_clk	= "uart2_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_UART2_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_uart2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart2_slaves),
-};
-
-/* uart3 */
-static struct omap_hwmod omap44xx_uart3_hwmod;
-static struct omap_hwmod_irq_info omap44xx_uart3_irqs[] = {
-	{ .irq = 74 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_uart3_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 52 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 53 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_uart3_addrs[] = {
 	{
 		.pa_start	= 0x48020000,
@@ -5032,43 +5825,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* uart3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_uart3_slaves[] = {
-	&omap44xx_l4_per__uart3,
-};
-
-static struct omap_hwmod omap44xx_uart3_hwmod = {
-	.name		= "uart3",
-	.class		= &omap44xx_uart_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
-	.mpu_irqs	= omap44xx_uart3_irqs,
-	.sdma_reqs	= omap44xx_uart3_sdma_reqs,
-	.main_clk	= "uart3_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_UART3_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_uart3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart3_slaves),
-};
-
-/* uart4 */
-static struct omap_hwmod omap44xx_uart4_hwmod;
-static struct omap_hwmod_irq_info omap44xx_uart4_irqs[] = {
-	{ .irq = 70 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_dma_info omap44xx_uart4_sdma_reqs[] = {
-	{ .name = "tx", .dma_req = 54 + OMAP44XX_DMA_REQ_START },
-	{ .name = "rx", .dma_req = 55 + OMAP44XX_DMA_REQ_START },
-	{ .dma_req = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_uart4_addrs[] = {
 	{
 		.pa_start	= 0x4806e000,
@@ -5087,62 +5843,51 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* uart4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_uart4_slaves[] = {
-	&omap44xx_l4_per__uart4,
-};
-
-static struct omap_hwmod omap44xx_uart4_hwmod = {
-	.name		= "uart4",
-	.class		= &omap44xx_uart_hwmod_class,
-	.clkdm_name	= "l4_per_clkdm",
-	.mpu_irqs	= omap44xx_uart4_irqs,
-	.sdma_reqs	= omap44xx_uart4_sdma_reqs,
-	.main_clk	= "uart4_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L4PER_UART4_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
+static struct omap_hwmod_addr_space omap44xx_usb_host_fs_addrs[] = {
+	{
+		.pa_start	= 0x4a0a9000,
+		.pa_end		= 0x4a0a93ff,
+		.flags		= ADDR_TYPE_RT
 	},
-	.slaves		= omap44xx_uart4_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart4_slaves),
+	{ }
 };
 
-/*
- * 'usb_otg_hs' class
- * high-speed on-the-go universal serial bus (usb_otg_hs) controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_usb_otg_hs_sysc = {
-	.rev_offs	= 0x0400,
-	.sysc_offs	= 0x0404,
-	.syss_offs	= 0x0408,
-	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-			   SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
-			   MSTANDBY_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
+/* l4_cfg -> usb_host_fs */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_fs = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_usb_host_fs_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_usb_host_fs_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_class omap44xx_usb_otg_hs_hwmod_class = {
-	.name	= "usb_otg_hs",
-	.sysc	= &omap44xx_usb_otg_hs_sysc,
+static struct omap_hwmod_addr_space omap44xx_usb_host_hs_addrs[] = {
+	{
+		.name		= "uhh",
+		.pa_start	= 0x4a064000,
+		.pa_end		= 0x4a0647ff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.name		= "ohci",
+		.pa_start	= 0x4a064800,
+		.pa_end		= 0x4a064bff,
+	},
+	{
+		.name		= "ehci",
+		.pa_start	= 0x4a064c00,
+		.pa_end		= 0x4a064fff,
+	},
+	{}
 };
 
-/* usb_otg_hs */
-static struct omap_hwmod_irq_info omap44xx_usb_otg_hs_irqs[] = {
-	{ .name = "mc", .irq = 92 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "dma", .irq = 93 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-/* usb_otg_hs master ports */
-static struct omap_hwmod_ocp_if *omap44xx_usb_otg_hs_masters[] = {
-	&omap44xx_usb_otg_hs__l3_main_2,
+/* l4_cfg -> usb_host_hs */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_hs = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_usb_host_hs_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_usb_host_hs_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 static struct omap_hwmod_addr_space omap44xx_usb_otg_hs_addrs[] = {
@@ -5163,65 +5908,23 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* usb_otg_hs slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_usb_otg_hs_slaves[] = {
-	&omap44xx_l4_cfg__usb_otg_hs,
-};
-
-static struct omap_hwmod_opt_clk usb_otg_hs_opt_clks[] = {
-	{ .role = "xclk", .clk = "usb_otg_hs_xclk" },
-};
-
-static struct omap_hwmod omap44xx_usb_otg_hs_hwmod = {
-	.name		= "usb_otg_hs",
-	.class		= &omap44xx_usb_otg_hs_hwmod_class,
-	.clkdm_name	= "l3_init_clkdm",
-	.flags		= HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
-	.mpu_irqs	= omap44xx_usb_otg_hs_irqs,
-	.main_clk	= "usb_otg_hs_ick",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3INIT_USB_OTG_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3INIT_USB_OTG_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
+static struct omap_hwmod_addr_space omap44xx_usb_tll_hs_addrs[] = {
+	{
+		.name		= "tll",
+		.pa_start	= 0x4a062000,
+		.pa_end		= 0x4a063fff,
+		.flags		= ADDR_TYPE_RT
 	},
-	.opt_clks	= usb_otg_hs_opt_clks,
-	.opt_clks_cnt	= ARRAY_SIZE(usb_otg_hs_opt_clks),
-	.slaves		= omap44xx_usb_otg_hs_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_usb_otg_hs_slaves),
-	.masters	= omap44xx_usb_otg_hs_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_usb_otg_hs_masters),
+	{}
 };
 
-/*
- * 'wd_timer' class
- * 32-bit watchdog upward counter that generates a pulse on the reset pin on
- * overflow condition
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_wd_timer_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_wd_timer_hwmod_class = {
-	.name		= "wd_timer",
-	.sysc		= &omap44xx_wd_timer_sysc,
-	.pre_shutdown	= &omap2_wd_timer_disable,
-};
-
-/* wd_timer2 */
-static struct omap_hwmod omap44xx_wd_timer2_hwmod;
-static struct omap_hwmod_irq_info omap44xx_wd_timer2_irqs[] = {
-	{ .irq = 80 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
+/* l4_cfg -> usb_tll_hs */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_tll_hs = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_usb_tll_hs_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_usb_tll_hs_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
 static struct omap_hwmod_addr_space omap44xx_wd_timer2_addrs[] = {
@@ -5242,35 +5945,6 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* wd_timer2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_wd_timer2_slaves[] = {
-	&omap44xx_l4_wkup__wd_timer2,
-};
-
-static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
-	.name		= "wd_timer2",
-	.class		= &omap44xx_wd_timer_hwmod_class,
-	.clkdm_name	= "l4_wkup_clkdm",
-	.mpu_irqs	= omap44xx_wd_timer2_irqs,
-	.main_clk	= "wd_timer2_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_WKUP_WDT2_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_WKUP_WDT2_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_wd_timer2_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_wd_timer2_slaves),
-};
-
-/* wd_timer3 */
-static struct omap_hwmod omap44xx_wd_timer3_hwmod;
-static struct omap_hwmod_irq_info omap44xx_wd_timer3_irqs[] = {
-	{ .irq = 36 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
 static struct omap_hwmod_addr_space omap44xx_wd_timer3_addrs[] = {
 	{
 		.pa_start	= 0x40130000,
@@ -5307,384 +5981,169 @@
 	.user		= OCP_USER_SDMA,
 };
 
-/* wd_timer3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_wd_timer3_slaves[] = {
+static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
+	&omap44xx_c2c__c2c_target_fw,
+	&omap44xx_l4_cfg__c2c_target_fw,
+	&omap44xx_l3_main_1__dmm,
+	&omap44xx_mpu__dmm,
+	&omap44xx_c2c__emif_fw,
+	&omap44xx_dmm__emif_fw,
+	&omap44xx_l4_cfg__emif_fw,
+	&omap44xx_iva__l3_instr,
+	&omap44xx_l3_main_3__l3_instr,
+	&omap44xx_ocp_wp_noc__l3_instr,
+	&omap44xx_dsp__l3_main_1,
+	&omap44xx_dss__l3_main_1,
+	&omap44xx_l3_main_2__l3_main_1,
+	&omap44xx_l4_cfg__l3_main_1,
+	&omap44xx_mmc1__l3_main_1,
+	&omap44xx_mmc2__l3_main_1,
+	&omap44xx_mpu__l3_main_1,
+	&omap44xx_c2c_target_fw__l3_main_2,
+	&omap44xx_debugss__l3_main_2,
+	&omap44xx_dma_system__l3_main_2,
+	&omap44xx_fdif__l3_main_2,
+	&omap44xx_gpu__l3_main_2,
+	&omap44xx_hsi__l3_main_2,
+	&omap44xx_ipu__l3_main_2,
+	&omap44xx_iss__l3_main_2,
+	&omap44xx_iva__l3_main_2,
+	&omap44xx_l3_main_1__l3_main_2,
+	&omap44xx_l4_cfg__l3_main_2,
+	&omap44xx_usb_host_fs__l3_main_2,
+	&omap44xx_usb_host_hs__l3_main_2,
+	&omap44xx_usb_otg_hs__l3_main_2,
+	&omap44xx_l3_main_1__l3_main_3,
+	&omap44xx_l3_main_2__l3_main_3,
+	&omap44xx_l4_cfg__l3_main_3,
+	&omap44xx_aess__l4_abe,
+	&omap44xx_dsp__l4_abe,
+	&omap44xx_l3_main_1__l4_abe,
+	&omap44xx_mpu__l4_abe,
+	&omap44xx_l3_main_1__l4_cfg,
+	&omap44xx_l3_main_2__l4_per,
+	&omap44xx_l4_cfg__l4_wkup,
+	&omap44xx_mpu__mpu_private,
+	&omap44xx_l4_cfg__ocp_wp_noc,
+	&omap44xx_l4_abe__aess,
+	&omap44xx_l4_abe__aess_dma,
+	&omap44xx_l3_main_2__c2c,
+	&omap44xx_l4_wkup__counter_32k,
+	&omap44xx_l4_cfg__ctrl_module_core,
+	&omap44xx_l4_cfg__ctrl_module_pad_core,
+	&omap44xx_l4_wkup__ctrl_module_wkup,
+	&omap44xx_l4_wkup__ctrl_module_pad_wkup,
+	&omap44xx_l3_instr__debugss,
+	&omap44xx_l4_cfg__dma_system,
+	&omap44xx_l4_abe__dmic,
+	&omap44xx_l4_abe__dmic_dma,
+	&omap44xx_dsp__iva,
+	&omap44xx_dsp__sl2if,
+	&omap44xx_l4_cfg__dsp,
+	&omap44xx_l3_main_2__dss,
+	&omap44xx_l4_per__dss,
+	&omap44xx_l3_main_2__dss_dispc,
+	&omap44xx_l4_per__dss_dispc,
+	&omap44xx_l3_main_2__dss_dsi1,
+	&omap44xx_l4_per__dss_dsi1,
+	&omap44xx_l3_main_2__dss_dsi2,
+	&omap44xx_l4_per__dss_dsi2,
+	&omap44xx_l3_main_2__dss_hdmi,
+	&omap44xx_l4_per__dss_hdmi,
+	&omap44xx_l3_main_2__dss_rfbi,
+	&omap44xx_l4_per__dss_rfbi,
+	&omap44xx_l3_main_2__dss_venc,
+	&omap44xx_l4_per__dss_venc,
+	&omap44xx_l4_per__elm,
+	&omap44xx_emif_fw__emif1,
+	&omap44xx_emif_fw__emif2,
+	&omap44xx_l4_cfg__fdif,
+	&omap44xx_l4_wkup__gpio1,
+	&omap44xx_l4_per__gpio2,
+	&omap44xx_l4_per__gpio3,
+	&omap44xx_l4_per__gpio4,
+	&omap44xx_l4_per__gpio5,
+	&omap44xx_l4_per__gpio6,
+	&omap44xx_l3_main_2__gpmc,
+	&omap44xx_l3_main_2__gpu,
+	&omap44xx_l4_per__hdq1w,
+	&omap44xx_l4_cfg__hsi,
+	&omap44xx_l4_per__i2c1,
+	&omap44xx_l4_per__i2c2,
+	&omap44xx_l4_per__i2c3,
+	&omap44xx_l4_per__i2c4,
+	&omap44xx_l3_main_2__ipu,
+	&omap44xx_l3_main_2__iss,
+	&omap44xx_iva__sl2if,
+	&omap44xx_l3_main_2__iva,
+	&omap44xx_l4_wkup__kbd,
+	&omap44xx_l4_cfg__mailbox,
+	&omap44xx_l4_abe__mcasp,
+	&omap44xx_l4_abe__mcasp_dma,
+	&omap44xx_l4_abe__mcbsp1,
+	&omap44xx_l4_abe__mcbsp1_dma,
+	&omap44xx_l4_abe__mcbsp2,
+	&omap44xx_l4_abe__mcbsp2_dma,
+	&omap44xx_l4_abe__mcbsp3,
+	&omap44xx_l4_abe__mcbsp3_dma,
+	&omap44xx_l4_per__mcbsp4,
+	&omap44xx_l4_abe__mcpdm,
+	&omap44xx_l4_abe__mcpdm_dma,
+	&omap44xx_l4_per__mcspi1,
+	&omap44xx_l4_per__mcspi2,
+	&omap44xx_l4_per__mcspi3,
+	&omap44xx_l4_per__mcspi4,
+	&omap44xx_l4_per__mmc1,
+	&omap44xx_l4_per__mmc2,
+	&omap44xx_l4_per__mmc3,
+	&omap44xx_l4_per__mmc4,
+	&omap44xx_l4_per__mmc5,
+	&omap44xx_l3_main_2__ocmc_ram,
+	&omap44xx_l4_cfg__ocp2scp_usb_phy,
+	&omap44xx_mpu_private__prcm_mpu,
+	&omap44xx_l4_wkup__cm_core_aon,
+	&omap44xx_l4_cfg__cm_core,
+	&omap44xx_l4_wkup__prm,
+	&omap44xx_l4_wkup__scrm,
+	&omap44xx_l3_main_2__sl2if,
+	&omap44xx_l4_abe__slimbus1,
+	&omap44xx_l4_abe__slimbus1_dma,
+	&omap44xx_l4_per__slimbus2,
+	&omap44xx_l4_cfg__smartreflex_core,
+	&omap44xx_l4_cfg__smartreflex_iva,
+	&omap44xx_l4_cfg__smartreflex_mpu,
+	&omap44xx_l4_cfg__spinlock,
+	&omap44xx_l4_wkup__timer1,
+	&omap44xx_l4_per__timer2,
+	&omap44xx_l4_per__timer3,
+	&omap44xx_l4_per__timer4,
+	&omap44xx_l4_abe__timer5,
+	&omap44xx_l4_abe__timer5_dma,
+	&omap44xx_l4_abe__timer6,
+	&omap44xx_l4_abe__timer6_dma,
+	&omap44xx_l4_abe__timer7,
+	&omap44xx_l4_abe__timer7_dma,
+	&omap44xx_l4_abe__timer8,
+	&omap44xx_l4_abe__timer8_dma,
+	&omap44xx_l4_per__timer9,
+	&omap44xx_l4_per__timer10,
+	&omap44xx_l4_per__timer11,
+	&omap44xx_l4_per__uart1,
+	&omap44xx_l4_per__uart2,
+	&omap44xx_l4_per__uart3,
+	&omap44xx_l4_per__uart4,
+	&omap44xx_l4_cfg__usb_host_fs,
+	&omap44xx_l4_cfg__usb_host_hs,
+	&omap44xx_l4_cfg__usb_otg_hs,
+	&omap44xx_l4_cfg__usb_tll_hs,
+	&omap44xx_l4_wkup__wd_timer2,
 	&omap44xx_l4_abe__wd_timer3,
 	&omap44xx_l4_abe__wd_timer3_dma,
-};
-
-static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
-	.name		= "wd_timer3",
-	.class		= &omap44xx_wd_timer_hwmod_class,
-	.clkdm_name	= "abe_clkdm",
-	.mpu_irqs	= omap44xx_wd_timer3_irqs,
-	.main_clk	= "wd_timer3_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_ABE_WDT3_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.slaves		= omap44xx_wd_timer3_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_slaves),
-};
-
-/*
- * 'usb_host_hs' class
- * high-speed multi-port usb host controller
- */
-static struct omap_hwmod_ocp_if omap44xx_usb_host_hs__l3_main_2 = {
-	.master		= &omap44xx_usb_host_hs_hwmod,
-	.slave		= &omap44xx_l3_main_2_hwmod,
-	.clk		= "l3_div_ck",
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_class_sysconfig omap44xx_usb_host_hs_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_SOFTRESET),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-			   SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
-			   MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
-	.sysc_fields	= &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_usb_host_hs_hwmod_class = {
-	.name = "usb_host_hs",
-	.sysc = &omap44xx_usb_host_hs_sysc,
-};
-
-static struct omap_hwmod_ocp_if *omap44xx_usb_host_hs_masters[] = {
-	&omap44xx_usb_host_hs__l3_main_2,
-};
-
-static struct omap_hwmod_addr_space omap44xx_usb_host_hs_addrs[] = {
-	{
-		.name		= "uhh",
-		.pa_start	= 0x4a064000,
-		.pa_end		= 0x4a0647ff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{
-		.name		= "ohci",
-		.pa_start	= 0x4a064800,
-		.pa_end		= 0x4a064bff,
-	},
-	{
-		.name		= "ehci",
-		.pa_start	= 0x4a064c00,
-		.pa_end		= 0x4a064fff,
-	},
-	{}
-};
-
-static struct omap_hwmod_irq_info omap44xx_usb_host_hs_irqs[] = {
-	{ .name = "ohci-irq", .irq = 76 + OMAP44XX_IRQ_GIC_START },
-	{ .name = "ehci-irq", .irq = 77 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_hs = {
-	.master		= &omap44xx_l4_cfg_hwmod,
-	.slave		= &omap44xx_usb_host_hs_hwmod,
-	.clk		= "l4_div_ck",
-	.addr		= omap44xx_usb_host_hs_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_ocp_if *omap44xx_usb_host_hs_slaves[] = {
-	&omap44xx_l4_cfg__usb_host_hs,
-};
-
-static struct omap_hwmod omap44xx_usb_host_hs_hwmod = {
-	.name		= "usb_host_hs",
-	.class		= &omap44xx_usb_host_hs_hwmod_class,
-	.clkdm_name	= "l3_init_clkdm",
-	.main_clk	= "usb_host_hs_fck",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3INIT_USB_HOST_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_SWCTRL,
-		},
-	},
-	.mpu_irqs	= omap44xx_usb_host_hs_irqs,
-	.slaves		= omap44xx_usb_host_hs_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_usb_host_hs_slaves),
-	.masters	= omap44xx_usb_host_hs_masters,
-	.masters_cnt	= ARRAY_SIZE(omap44xx_usb_host_hs_masters),
-
-	/*
-	 * Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
-	 * id: i660
-	 *
-	 * Description:
-	 * In the following configuration :
-	 * - USBHOST module is set to smart-idle mode
-	 * - PRCM asserts idle_req to the USBHOST module ( This typically
-	 *   happens when the system is going to a low power mode : all ports
-	 *   have been suspended, the master part of the USBHOST module has
-	 *   entered the standby state, and SW has cut the functional clocks)
-	 * - an USBHOST interrupt occurs before the module is able to answer
-	 *   idle_ack, typically a remote wakeup IRQ.
-	 * Then the USB HOST module will enter a deadlock situation where it
-	 * is no more accessible nor functional.
-	 *
-	 * Workaround:
-	 * Don't use smart idle; use only force idle, hence HWMOD_SWSUP_SIDLE
-	 */
-
-	/*
-	 * Errata: USB host EHCI may stall when entering smart-standby mode
-	 * Id: i571
-	 *
-	 * Description:
-	 * When the USBHOST module is set to smart-standby mode, and when it is
-	 * ready to enter the standby state (i.e. all ports are suspended and
-	 * all attached devices are in suspend mode), then it can wrongly assert
-	 * the Mstandby signal too early while there are still some residual OCP
-	 * transactions ongoing. If this condition occurs, the internal state
-	 * machine may go to an undefined state and the USB link may be stuck
-	 * upon the next resume.
-	 *
-	 * Workaround:
-	 * Don't use smart standby; use only force standby,
-	 * hence HWMOD_SWSUP_MSTANDBY
-	 */
-
-	/*
-	 * During system boot; If the hwmod framework resets the module
-	 * the module will have smart idle settings; which can lead to deadlock
-	 * (above Errata Id:i660); so, dont reset the module during boot;
-	 * Use HWMOD_INIT_NO_RESET.
-	 */
-
-	.flags		= HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
-			  HWMOD_INIT_NO_RESET,
-};
-
-/*
- * 'usb_tll_hs' class
- * usb_tll_hs module is the adapter on the usb_host_hs ports
- */
-static struct omap_hwmod_class_sysconfig omap44xx_usb_tll_hs_sysc = {
-	.rev_offs	= 0x0000,
-	.sysc_offs	= 0x0010,
-	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
-			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
-			   SYSC_HAS_AUTOIDLE),
-	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-	.sysc_fields	= &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_usb_tll_hs_hwmod_class = {
-	.name = "usb_tll_hs",
-	.sysc = &omap44xx_usb_tll_hs_sysc,
-};
-
-static struct omap_hwmod_irq_info omap44xx_usb_tll_hs_irqs[] = {
-	{ .name = "tll-irq", .irq = 78 + OMAP44XX_IRQ_GIC_START },
-	{ .irq = -1 }
-};
-
-static struct omap_hwmod_addr_space omap44xx_usb_tll_hs_addrs[] = {
-	{
-		.name		= "tll",
-		.pa_start	= 0x4a062000,
-		.pa_end		= 0x4a063fff,
-		.flags		= ADDR_TYPE_RT
-	},
-	{}
-};
-
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_tll_hs = {
-	.master		= &omap44xx_l4_cfg_hwmod,
-	.slave		= &omap44xx_usb_tll_hs_hwmod,
-	.clk		= "l4_div_ck",
-	.addr		= omap44xx_usb_tll_hs_addrs,
-	.user		= OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_ocp_if *omap44xx_usb_tll_hs_slaves[] = {
-	&omap44xx_l4_cfg__usb_tll_hs,
-};
-
-static struct omap_hwmod omap44xx_usb_tll_hs_hwmod = {
-	.name		= "usb_tll_hs",
-	.class		= &omap44xx_usb_tll_hs_hwmod_class,
-	.clkdm_name	= "l3_init_clkdm",
-	.main_clk	= "usb_tll_hs_ick",
-	.prcm = {
-		.omap4 = {
-			.clkctrl_offs = OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET,
-			.context_offs = OMAP4_RM_L3INIT_USB_TLL_CONTEXT_OFFSET,
-			.modulemode   = MODULEMODE_HWCTRL,
-		},
-	},
-	.mpu_irqs	= omap44xx_usb_tll_hs_irqs,
-	.slaves		= omap44xx_usb_tll_hs_slaves,
-	.slaves_cnt	= ARRAY_SIZE(omap44xx_usb_tll_hs_slaves),
-};
-
-static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
-
-	/* dmm class */
-	&omap44xx_dmm_hwmod,
-
-	/* emif_fw class */
-	&omap44xx_emif_fw_hwmod,
-
-	/* l3 class */
-	&omap44xx_l3_instr_hwmod,
-	&omap44xx_l3_main_1_hwmod,
-	&omap44xx_l3_main_2_hwmod,
-	&omap44xx_l3_main_3_hwmod,
-
-	/* l4 class */
-	&omap44xx_l4_abe_hwmod,
-	&omap44xx_l4_cfg_hwmod,
-	&omap44xx_l4_per_hwmod,
-	&omap44xx_l4_wkup_hwmod,
-
-	/* mpu_bus class */
-	&omap44xx_mpu_private_hwmod,
-
-	/* aess class */
-/*	&omap44xx_aess_hwmod, */
-
-	/* bandgap class */
-	&omap44xx_bandgap_hwmod,
-
-	/* counter class */
-/*	&omap44xx_counter_32k_hwmod, */
-
-	/* dma class */
-	&omap44xx_dma_system_hwmod,
-
-	/* dmic class */
-	&omap44xx_dmic_hwmod,
-
-	/* dsp class */
-	&omap44xx_dsp_hwmod,
-	&omap44xx_dsp_c0_hwmod,
-
-	/* dss class */
-	&omap44xx_dss_hwmod,
-	&omap44xx_dss_dispc_hwmod,
-	&omap44xx_dss_dsi1_hwmod,
-	&omap44xx_dss_dsi2_hwmod,
-	&omap44xx_dss_hdmi_hwmod,
-	&omap44xx_dss_rfbi_hwmod,
-	&omap44xx_dss_venc_hwmod,
-
-	/* gpio class */
-	&omap44xx_gpio1_hwmod,
-	&omap44xx_gpio2_hwmod,
-	&omap44xx_gpio3_hwmod,
-	&omap44xx_gpio4_hwmod,
-	&omap44xx_gpio5_hwmod,
-	&omap44xx_gpio6_hwmod,
-
-	/* hsi class */
-/*	&omap44xx_hsi_hwmod, */
-
-	/* i2c class */
-	&omap44xx_i2c1_hwmod,
-	&omap44xx_i2c2_hwmod,
-	&omap44xx_i2c3_hwmod,
-	&omap44xx_i2c4_hwmod,
-
-	/* ipu class */
-	&omap44xx_ipu_hwmod,
-	&omap44xx_ipu_c0_hwmod,
-	&omap44xx_ipu_c1_hwmod,
-
-	/* iss class */
-/*	&omap44xx_iss_hwmod, */
-
-	/* iva class */
-	&omap44xx_iva_hwmod,
-	&omap44xx_iva_seq0_hwmod,
-	&omap44xx_iva_seq1_hwmod,
-
-	/* kbd class */
-	&omap44xx_kbd_hwmod,
-
-	/* mailbox class */
-	&omap44xx_mailbox_hwmod,
-
-	/* mcbsp class */
-	&omap44xx_mcbsp1_hwmod,
-	&omap44xx_mcbsp2_hwmod,
-	&omap44xx_mcbsp3_hwmod,
-	&omap44xx_mcbsp4_hwmod,
-
-	/* mcpdm class */
-	&omap44xx_mcpdm_hwmod,
-
-	/* mcspi class */
-	&omap44xx_mcspi1_hwmod,
-	&omap44xx_mcspi2_hwmod,
-	&omap44xx_mcspi3_hwmod,
-	&omap44xx_mcspi4_hwmod,
-
-	/* mmc class */
-	&omap44xx_mmc1_hwmod,
-	&omap44xx_mmc2_hwmod,
-	&omap44xx_mmc3_hwmod,
-	&omap44xx_mmc4_hwmod,
-	&omap44xx_mmc5_hwmod,
-
-	/* mpu class */
-	&omap44xx_mpu_hwmod,
-
-	/* smartreflex class */
-	&omap44xx_smartreflex_core_hwmod,
-	&omap44xx_smartreflex_iva_hwmod,
-	&omap44xx_smartreflex_mpu_hwmod,
-
-	/* spinlock class */
-	&omap44xx_spinlock_hwmod,
-
-	/* timer class */
-	&omap44xx_timer1_hwmod,
-	&omap44xx_timer2_hwmod,
-	&omap44xx_timer3_hwmod,
-	&omap44xx_timer4_hwmod,
-	&omap44xx_timer5_hwmod,
-	&omap44xx_timer6_hwmod,
-	&omap44xx_timer7_hwmod,
-	&omap44xx_timer8_hwmod,
-	&omap44xx_timer9_hwmod,
-	&omap44xx_timer10_hwmod,
-	&omap44xx_timer11_hwmod,
-
-	/* uart class */
-	&omap44xx_uart1_hwmod,
-	&omap44xx_uart2_hwmod,
-	&omap44xx_uart3_hwmod,
-	&omap44xx_uart4_hwmod,
-
-	/* usb host class */
-	&omap44xx_usb_host_hs_hwmod,
-	&omap44xx_usb_tll_hs_hwmod,
-
-	/* usb_otg_hs class */
-	&omap44xx_usb_otg_hs_hwmod,
-
-	/* wd_timer class */
-	&omap44xx_wd_timer2_hwmod,
-	&omap44xx_wd_timer3_hwmod,
 	NULL,
 };
 
 int __init omap44xx_hwmod_init(void)
 {
-	return omap_hwmod_register(omap44xx_hwmods);
+	return omap_hwmod_register_links(omap44xx_hwmod_ocp_ifs);
 }
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_common_data.h b/arch/arm/mach-omap2/omap_hwmod_common_data.h
index ad5d8f0..e7e8eea 100644
--- a/arch/arm/mach-omap2/omap_hwmod_common_data.h
+++ b/arch/arm/mach-omap2/omap_hwmod_common_data.h
@@ -19,18 +19,6 @@
 #include "display.h"
 
 /* Common address space across OMAP2xxx */
-extern struct omap_hwmod_addr_space omap2xxx_uart1_addr_space[];
-extern struct omap_hwmod_addr_space omap2xxx_uart2_addr_space[];
-extern struct omap_hwmod_addr_space omap2xxx_uart3_addr_space[];
-extern struct omap_hwmod_addr_space omap2xxx_timer2_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer3_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer4_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer5_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer6_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer7_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer8_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer9_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer12_addrs[];
 extern struct omap_hwmod_addr_space omap2xxx_mcbsp2_addrs[];
 
 /* Common address space across OMAP2xxx/3xxx */
@@ -50,10 +38,70 @@
 extern struct omap_hwmod_addr_space omap2_dma_system_addrs[];
 extern struct omap_hwmod_addr_space omap2_mailbox_addrs[];
 extern struct omap_hwmod_addr_space omap2_mcbsp1_addrs[];
+extern struct omap_hwmod_addr_space omap2_hdq1w_addr_space[];
 
 /* Common IP block data across OMAP2xxx */
 extern struct omap_hwmod_irq_info omap2xxx_timer12_mpu_irqs[];
 extern struct omap_hwmod_dma_info omap2xxx_dss_sdma_chs[];
+extern struct omap_gpio_dev_attr omap2xxx_gpio_dev_attr;
+extern struct omap_hwmod omap2xxx_l3_main_hwmod;
+extern struct omap_hwmod omap2xxx_l4_core_hwmod;
+extern struct omap_hwmod omap2xxx_l4_wkup_hwmod;
+extern struct omap_hwmod omap2xxx_mpu_hwmod;
+extern struct omap_hwmod omap2xxx_iva_hwmod;
+extern struct omap_hwmod omap2xxx_timer1_hwmod;
+extern struct omap_hwmod omap2xxx_timer2_hwmod;
+extern struct omap_hwmod omap2xxx_timer3_hwmod;
+extern struct omap_hwmod omap2xxx_timer4_hwmod;
+extern struct omap_hwmod omap2xxx_timer5_hwmod;
+extern struct omap_hwmod omap2xxx_timer6_hwmod;
+extern struct omap_hwmod omap2xxx_timer7_hwmod;
+extern struct omap_hwmod omap2xxx_timer8_hwmod;
+extern struct omap_hwmod omap2xxx_timer9_hwmod;
+extern struct omap_hwmod omap2xxx_timer10_hwmod;
+extern struct omap_hwmod omap2xxx_timer11_hwmod;
+extern struct omap_hwmod omap2xxx_timer12_hwmod;
+extern struct omap_hwmod omap2xxx_wd_timer2_hwmod;
+extern struct omap_hwmod omap2xxx_uart1_hwmod;
+extern struct omap_hwmod omap2xxx_uart2_hwmod;
+extern struct omap_hwmod omap2xxx_uart3_hwmod;
+extern struct omap_hwmod omap2xxx_dss_core_hwmod;
+extern struct omap_hwmod omap2xxx_dss_dispc_hwmod;
+extern struct omap_hwmod omap2xxx_dss_rfbi_hwmod;
+extern struct omap_hwmod omap2xxx_dss_venc_hwmod;
+extern struct omap_hwmod omap2xxx_gpio1_hwmod;
+extern struct omap_hwmod omap2xxx_gpio2_hwmod;
+extern struct omap_hwmod omap2xxx_gpio3_hwmod;
+extern struct omap_hwmod omap2xxx_gpio4_hwmod;
+extern struct omap_hwmod omap2xxx_mcspi1_hwmod;
+extern struct omap_hwmod omap2xxx_mcspi2_hwmod;
+extern struct omap_hwmod omap2xxx_counter_32k_hwmod;
+
+/* Common interface data across OMAP2xxx */
+extern struct omap_hwmod_ocp_if omap2xxx_l3_main__l4_core;
+extern struct omap_hwmod_ocp_if omap2xxx_mpu__l3_main;
+extern struct omap_hwmod_ocp_if omap2xxx_dss__l3;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__l4_wkup;
+extern struct omap_hwmod_ocp_if omap2_l4_core__uart1;
+extern struct omap_hwmod_ocp_if omap2_l4_core__uart2;
+extern struct omap_hwmod_ocp_if omap2_l4_core__uart3;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__mcspi1;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__mcspi2;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer2;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer3;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer4;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer5;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer6;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer7;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer8;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer9;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer10;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer11;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer12;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__dss;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_dispc;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_rfbi;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_venc;
 
 /* Common IP block data */
 extern struct omap_hwmod_dma_info omap2_uart1_sdma_reqs[];
@@ -94,6 +142,8 @@
 extern struct omap_hwmod_irq_info omap2_dma_system_irqs[];
 extern struct omap_hwmod_irq_info omap2_mcspi1_mpu_irqs[];
 extern struct omap_hwmod_irq_info omap2_mcspi2_mpu_irqs[];
+extern struct omap_hwmod_addr_space omap2xxx_timer12_addrs[];
+extern struct omap_hwmod_irq_info omap2_hdq1w_mpu_irqs[];
 
 /* OMAP hwmod classes - forward declarations */
 extern struct omap_hwmod_class l3_hwmod_class;
@@ -105,6 +155,8 @@
 extern struct omap_hwmod_class omap2_dispc_hwmod_class;
 extern struct omap_hwmod_class omap2_rfbi_hwmod_class;
 extern struct omap_hwmod_class omap2_venc_hwmod_class;
+extern struct omap_hwmod_class_sysconfig omap2_hdq1w_sysc;
+extern struct omap_hwmod_class omap2_hdq1w_class;
 
 extern struct omap_hwmod_class omap2xxx_timer_hwmod_class;
 extern struct omap_hwmod_class omap2xxx_wd_timer_hwmod_class;
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 36fa90b..7856489 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -38,27 +38,6 @@
 }
 #endif
 
-/*
- * cpuidle mach specific parameters
- *
- * The board code can override the default C-states definition using
- * omap3_pm_init_cpuidle
- */
-struct cpuidle_params {
-	u32 exit_latency;	/* exit_latency = sleep + wake-up latencies */
-	u32 target_residency;
-	u8 valid;		/* validates the C-state */
-};
-
-#if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE)
-extern void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params);
-#else
-static
-inline void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params)
-{
-}
-#endif
-
 extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm);
 extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state);
 
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 95442b6..facfffc 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -171,8 +171,6 @@
 
 static void omap2_enter_mpu_retention(void)
 {
-	int only_idle = 0;
-
 	/* Putting MPU into the WFI state while a transfer is active
 	 * seems to cause the I2C block to timeout. Why? Good question. */
 	if (omap2_i2c_active())
@@ -195,7 +193,6 @@
 
 		omap2_prm_write_mod_reg(OMAP_LOGICRETSTATE_MASK, MPU_MOD,
 						 OMAP2_PM_PWSTCTRL);
-		only_idle = 1;
 	}
 
 	omap2_sram_idle();
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 703bd10..8b43aef 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -273,7 +273,7 @@
 	int per_next_state = PWRDM_POWER_ON;
 	int core_next_state = PWRDM_POWER_ON;
 	int per_going_off;
-	int core_prev_state, per_prev_state;
+	int core_prev_state;
 	u32 sdrc_pwr = 0;
 
 	mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
@@ -375,10 +375,8 @@
 	pwrdm_post_transition();
 
 	/* PER */
-	if (per_next_state < PWRDM_POWER_ON) {
-		per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
+	if (per_next_state < PWRDM_POWER_ON)
 		omap2_gpio_resume_after_idle();
-	}
 
 	/* Disable IO-PAD and IO-CHAIN wakeup */
 	if (omap3_has_io_wakeup() &&
@@ -702,7 +700,7 @@
 static int __init omap3_pm_init(void)
 {
 	struct power_state *pwrst, *tmp;
-	struct clockdomain *neon_clkdm, *per_clkdm, *mpu_clkdm, *core_clkdm;
+	struct clockdomain *neon_clkdm, *mpu_clkdm;
 	int ret;
 
 	if (!cpu_is_omap34xx())
@@ -757,8 +755,6 @@
 
 	neon_clkdm = clkdm_lookup("neon_clkdm");
 	mpu_clkdm = clkdm_lookup("mpu_clkdm");
-	per_clkdm = clkdm_lookup("per_clkdm");
-	core_clkdm = clkdm_lookup("core_clkdm");
 
 #ifdef CONFIG_SUSPEND
 	omap_pm_suspend = omap3_pm_suspend;
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 96ad3dbe..9611490 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -981,16 +981,6 @@
 	return ret;
 }
 
-int pwrdm_clkdm_state_switch(struct clockdomain *clkdm)
-{
-	if (clkdm != NULL && clkdm->pwrdm.ptr != NULL) {
-		pwrdm_wait_transition(clkdm->pwrdm.ptr);
-		return pwrdm_state_switch(clkdm->pwrdm.ptr);
-	}
-
-	return -EINVAL;
-}
-
 int pwrdm_pre_transition(void)
 {
 	pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 0d72a8a..8f88d65 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -213,7 +213,6 @@
 int pwrdm_wait_transition(struct powerdomain *pwrdm);
 
 int pwrdm_state_switch(struct powerdomain *pwrdm);
-int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);
 int pwrdm_pre_transition(void);
 int pwrdm_post_transition(void);
 int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 5aa5435..6da3ba4 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -177,6 +177,8 @@
 /* PM_WKST_WKUP, CM_IDLEST_WKUP shared bits */
 #define OMAP24XX_ST_GPIOS_SHIFT				2
 #define OMAP24XX_ST_GPIOS_MASK				(1 << 2)
+#define OMAP24XX_ST_32KSYNC_SHIFT			1
+#define OMAP24XX_ST_32KSYNC_MASK			(1 << 1)
 #define OMAP24XX_ST_GPT1_SHIFT				0
 #define OMAP24XX_ST_GPT1_MASK				(1 << 0)
 
@@ -307,6 +309,8 @@
 #define OMAP3430_ST_SR1_MASK				(1 << 6)
 #define OMAP3430_ST_GPIO1_SHIFT				3
 #define OMAP3430_ST_GPIO1_MASK				(1 << 3)
+#define OMAP3430_ST_32KSYNC_SHIFT			2
+#define OMAP3430_ST_32KSYNC_MASK			(1 << 2)
 #define OMAP3430_ST_GPT12_SHIFT				1
 #define OMAP3430_ST_GPT12_MASK				(1 << 1)
 #define OMAP3430_ST_GPT1_SHIFT				0
@@ -410,6 +414,19 @@
 extern void __iomem *prm_base;
 extern void __iomem *cm_base;
 extern void __iomem *cm2_base;
+extern void __iomem *prcm_mpu_base;
+
+#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_OMAP5)
+extern void omap_prm_base_init(void);
+extern void omap_cm_base_init(void);
+#else
+static inline void omap_prm_base_init(void)
+{
+}
+static inline void omap_cm_base_init(void)
+{
+}
+#endif
 
 /**
  * struct omap_prcm_irq - describes a PRCM interrupt bit
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 626acfa..480f40a 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -42,6 +42,7 @@
 void __iomem *prm_base;
 void __iomem *cm_base;
 void __iomem *cm2_base;
+void __iomem *prcm_mpu_base;
 
 #define MAX_MODULE_ENABLE_WAIT		100000
 
@@ -155,4 +156,11 @@
 		cm_base = omap2_globals->cm;
 	if (omap2_globals->cm2)
 		cm2_base = omap2_globals->cm2;
+	if (omap2_globals->prcm_mpu)
+		prcm_mpu_base = omap2_globals->prcm_mpu;
+
+	if (cpu_is_omap44xx()) {
+		omap_prm_base_init();
+		omap_cm_base_init();
+	}
 }
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index d28f848..dfe00dd 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -237,7 +237,7 @@
  */
 int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
 {
-	int nr_regs = irq_setup->nr_regs;
+	int nr_regs;
 	u32 mask[OMAP_PRCM_MAX_NR_PENDING_REG];
 	int offset, i;
 	struct irq_chip_generic *gc;
@@ -246,6 +246,8 @@
 	if (!irq_setup)
 		return -EINVAL;
 
+	nr_regs = irq_setup->nr_regs;
+
 	if (prcm_irq_setup) {
 		pr_err("PRCM: already initialized; won't reinitialize\n");
 		return -EINVAL;
diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c
index 9b3898a..c12320c0 100644
--- a/arch/arm/mach-omap2/prminst44xx.c
+++ b/arch/arm/mach-omap2/prminst44xx.c
@@ -18,20 +18,26 @@
 
 #include "iomap.h"
 #include "common.h"
+#include "prcm-common.h"
 #include "prm44xx.h"
 #include "prminst44xx.h"
 #include "prm-regbits-44xx.h"
 #include "prcm44xx.h"
 #include "prcm_mpu44xx.h"
 
-static u32 _prm_bases[OMAP4_MAX_PRCM_PARTITIONS] = {
-	[OMAP4430_INVALID_PRCM_PARTITION]	= 0,
-	[OMAP4430_PRM_PARTITION]		= OMAP4430_PRM_BASE,
-	[OMAP4430_CM1_PARTITION]		= 0,
-	[OMAP4430_CM2_PARTITION]		= 0,
-	[OMAP4430_SCRM_PARTITION]		= 0,
-	[OMAP4430_PRCM_MPU_PARTITION]		= OMAP4430_PRCM_MPU_BASE,
-};
+static void __iomem *_prm_bases[OMAP4_MAX_PRCM_PARTITIONS];
+
+/**
+ * omap_prm_base_init - Populates the prm partitions
+ *
+ * Populates the base addresses of the _prm_bases
+ * array used for read/write of prm module registers.
+ */
+void omap_prm_base_init(void)
+{
+	_prm_bases[OMAP4430_PRM_PARTITION] = prm_base;
+	_prm_bases[OMAP4430_PRCM_MPU_PARTITION] = prcm_mpu_base;
+}
 
 /* Read a register in a PRM instance */
 u32 omap4_prminst_read_inst_reg(u8 part, s16 inst, u16 idx)
@@ -39,8 +45,7 @@
 	BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
 	       part == OMAP4430_INVALID_PRCM_PARTITION ||
 	       !_prm_bases[part]);
-	return __raw_readl(OMAP2_L4_IO_ADDRESS(_prm_bases[part] + inst +
-					       idx));
+	return __raw_readl(_prm_bases[part] + inst + idx);
 }
 
 /* Write into a register in a PRM instance */
@@ -49,7 +54,7 @@
 	BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
 	       part == OMAP4430_INVALID_PRCM_PARTITION ||
 	       !_prm_bases[part]);
-	__raw_writel(val, OMAP2_L4_IO_ADDRESS(_prm_bases[part] + inst + idx));
+	__raw_writel(val, _prm_bases[part] + inst + idx);
 }
 
 /* Read-modify-write a register in PRM. Caller must lock */
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 9fc2f44..292d4aa 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -133,7 +133,7 @@
 static void omap_serial_fill_default_pads(struct omap_board_data *bdata) {}
 #endif
 
-char *cmdline_find_option(char *str)
+static char *cmdline_find_option(char *str)
 {
 	extern char *saved_command_line;
 
@@ -245,14 +245,6 @@
 	omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
 	omap_up.autosuspend_timeout = info->autosuspend_timeout;
 
-	/* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */
-	if (!cpu_is_omap2420() && !cpu_is_ti816x())
-		omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS;
-
-	/* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */
-	if (cpu_is_omap34xx() || cpu_is_omap3630())
-		omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE;
-
 	pdata = &omap_up;
 	pdata_size = sizeof(struct omap_uart_port_info);
 
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index c512bac..1b78358 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -145,8 +145,10 @@
 {
 	char name[10]; /* 10 = sizeof("gptXX_Xck0") */
 	struct omap_hwmod *oh;
+	struct resource irq_rsrc, mem_rsrc;
 	size_t size;
 	int res = 0;
+	int r;
 
 	sprintf(name, "timer%d", gptimer_id);
 	omap_hwmod_setup_one(name);
@@ -154,9 +156,16 @@
 	if (!oh)
 		return -ENODEV;
 
-	timer->irq = oh->mpu_irqs[0].irq;
-	timer->phys_base = oh->slaves[0]->addr->pa_start;
-	size = oh->slaves[0]->addr->pa_end - timer->phys_base;
+	r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, &irq_rsrc);
+	if (r)
+		return -ENXIO;
+	timer->irq = irq_rsrc.start;
+
+	r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, &mem_rsrc);
+	if (r)
+		return -ENXIO;
+	timer->phys_base = mem_rsrc.start;
+	size = mem_rsrc.end - mem_rsrc.start;
 
 	/* Static mapping, never released */
 	timer->io_base = ioremap(timer->phys_base, size);
@@ -169,13 +178,6 @@
 	if (IS_ERR(timer->fclk))
 		return -ENODEV;
 
-	sprintf(name, "gpt%d_ick", gptimer_id);
-	timer->iclk = clk_get(NULL, name);
-	if (IS_ERR(timer->iclk)) {
-		clk_put(timer->fclk);
-		return -ENODEV;
-	}
-
 	omap_hwmod_enable(oh);
 
 	sys_timer_reserved |= (1 << (gptimer_id - 1));
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index 7a7b893..119d5a9 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -31,6 +31,7 @@
 
 #include "twl-common.h"
 #include "pm.h"
+#include "voltage.h"
 
 static struct i2c_board_info __initdata pmic_i2c_board_info = {
 	.addr		= 0x48,
@@ -47,6 +48,18 @@
 	},
 };
 
+static int twl_set_voltage(void *data, int target_uV)
+{
+	struct voltagedomain *voltdm = (struct voltagedomain *)data;
+	return voltdm_scale(voltdm, target_uV);
+}
+
+static int twl_get_voltage(void *data)
+{
+	struct voltagedomain *voltdm = (struct voltagedomain *)data;
+	return voltdm_get_voltage(voltdm);
+}
+
 void __init omap_pmic_init(int bus, u32 clkrate,
 			   const char *pmic_type, int pmic_irq,
 			   struct twl4030_platform_data *pmic_data)
@@ -153,6 +166,48 @@
 	.consumer_supplies		= omap3_vpll2_supplies,
 };
 
+static struct regulator_consumer_supply omap3_vdd1_supply[] = {
+	REGULATOR_SUPPLY("vcc", "mpu.0"),
+};
+
+static struct regulator_consumer_supply omap3_vdd2_supply[] = {
+	REGULATOR_SUPPLY("vcc", "l3_main.0"),
+};
+
+static struct regulator_init_data omap3_vdd1 = {
+	.constraints = {
+		.name			= "vdd_mpu_iva",
+		.min_uV			= 600000,
+		.max_uV			= 1450000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE,
+	},
+	.num_consumer_supplies		= ARRAY_SIZE(omap3_vdd1_supply),
+	.consumer_supplies		= omap3_vdd1_supply,
+};
+
+static struct regulator_init_data omap3_vdd2 = {
+	.constraints = {
+		.name			= "vdd_core",
+		.min_uV			= 600000,
+		.max_uV			= 1450000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE,
+	},
+	.num_consumer_supplies		= ARRAY_SIZE(omap3_vdd2_supply),
+	.consumer_supplies		= omap3_vdd2_supply,
+};
+
+static struct twl_regulator_driver_data omap3_vdd1_drvdata = {
+	.get_voltage = twl_get_voltage,
+	.set_voltage = twl_set_voltage,
+};
+
+static struct twl_regulator_driver_data omap3_vdd2_drvdata = {
+	.get_voltage = twl_get_voltage,
+	.set_voltage = twl_set_voltage,
+};
+
 void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
 				  u32 pdata_flags, u32 regulators_flags)
 {
@@ -160,6 +215,16 @@
 		pmic_data->irq_base = TWL4030_IRQ_BASE;
 	if (!pmic_data->irq_end)
 		pmic_data->irq_end = TWL4030_IRQ_END;
+	if (!pmic_data->vdd1) {
+		omap3_vdd1.driver_data = &omap3_vdd1_drvdata;
+		omap3_vdd1_drvdata.data = voltdm_lookup("mpu_iva");
+		pmic_data->vdd1 = &omap3_vdd1;
+	}
+	if (!pmic_data->vdd2) {
+		omap3_vdd2.driver_data = &omap3_vdd2_drvdata;
+		omap3_vdd2_drvdata.data = voltdm_lookup("core");
+		pmic_data->vdd2 = &omap3_vdd2;
+	}
 
 	/* Common platform data configurations */
 	if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
@@ -201,6 +266,7 @@
 		.valid_ops_mask		= REGULATOR_CHANGE_MODE
 					| REGULATOR_CHANGE_STATUS,
 	},
+	.supply_regulator	= "V2V1",
 };
 
 static struct regulator_init_data omap4_vaux2_idata = {
@@ -291,6 +357,7 @@
 	},
 	.num_consumer_supplies	= ARRAY_SIZE(omap4_vcxio_supply),
 	.consumer_supplies	= omap4_vcxio_supply,
+	.supply_regulator	= "V2V1",
 };
 
 static struct regulator_init_data omap4_vusb_idata = {
@@ -310,6 +377,105 @@
 	},
 };
 
+static struct regulator_consumer_supply omap4_vdd1_supply[] = {
+	REGULATOR_SUPPLY("vcc", "mpu.0"),
+};
+
+static struct regulator_consumer_supply omap4_vdd2_supply[] = {
+	REGULATOR_SUPPLY("vcc", "iva.0"),
+};
+
+static struct regulator_consumer_supply omap4_vdd3_supply[] = {
+	REGULATOR_SUPPLY("vcc", "l3_main.0"),
+};
+
+static struct regulator_init_data omap4_vdd1 = {
+	.constraints = {
+		.name			= "vdd_mpu",
+		.min_uV			= 500000,
+		.max_uV			= 1500000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE,
+	},
+	.num_consumer_supplies		= ARRAY_SIZE(omap4_vdd1_supply),
+	.consumer_supplies		= omap4_vdd1_supply,
+};
+
+static struct regulator_init_data omap4_vdd2 = {
+	.constraints = {
+		.name			= "vdd_iva",
+		.min_uV			= 500000,
+		.max_uV			= 1500000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE,
+	},
+	.num_consumer_supplies		= ARRAY_SIZE(omap4_vdd2_supply),
+	.consumer_supplies		= omap4_vdd2_supply,
+};
+
+static struct regulator_init_data omap4_vdd3 = {
+	.constraints = {
+		.name			= "vdd_core",
+		.min_uV			= 500000,
+		.max_uV			= 1500000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE,
+	},
+	.num_consumer_supplies		= ARRAY_SIZE(omap4_vdd3_supply),
+	.consumer_supplies		= omap4_vdd3_supply,
+};
+
+
+static struct twl_regulator_driver_data omap4_vdd1_drvdata = {
+	.get_voltage = twl_get_voltage,
+	.set_voltage = twl_set_voltage,
+};
+
+static struct twl_regulator_driver_data omap4_vdd2_drvdata = {
+	.get_voltage = twl_get_voltage,
+	.set_voltage = twl_set_voltage,
+};
+
+static struct twl_regulator_driver_data omap4_vdd3_drvdata = {
+	.get_voltage = twl_get_voltage,
+	.set_voltage = twl_set_voltage,
+};
+
+static struct regulator_consumer_supply omap4_v1v8_supply[] = {
+	REGULATOR_SUPPLY("vio", "1-004b"),
+};
+
+static struct regulator_init_data omap4_v1v8_idata = {
+	.constraints = {
+		.min_uV			= 1800000,
+		.max_uV			= 1800000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+		.always_on		= true,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(omap4_v1v8_supply),
+	.consumer_supplies	= omap4_v1v8_supply,
+};
+
+static struct regulator_consumer_supply omap4_v2v1_supply[] = {
+	REGULATOR_SUPPLY("v2v1", "1-004b"),
+};
+
+static struct regulator_init_data omap4_v2v1_idata = {
+	.constraints = {
+		.min_uV			= 2100000,
+		.max_uV			= 2100000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(omap4_v2v1_supply),
+	.consumer_supplies	= omap4_v2v1_supply,
+};
+
 void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
 				  u32 pdata_flags, u32 regulators_flags)
 {
@@ -318,6 +484,24 @@
 	if (!pmic_data->irq_end)
 		pmic_data->irq_end = TWL6030_IRQ_END;
 
+	if (!pmic_data->vdd1) {
+		omap4_vdd1.driver_data = &omap4_vdd1_drvdata;
+		omap4_vdd1_drvdata.data = voltdm_lookup("mpu");
+		pmic_data->vdd1 = &omap4_vdd1;
+	}
+
+	if (!pmic_data->vdd2) {
+		omap4_vdd2.driver_data = &omap4_vdd2_drvdata;
+		omap4_vdd2_drvdata.data = voltdm_lookup("iva");
+		pmic_data->vdd2 = &omap4_vdd2;
+	}
+
+	if (!pmic_data->vdd3) {
+		omap4_vdd3.driver_data = &omap4_vdd3_drvdata;
+		omap4_vdd3_drvdata.data = voltdm_lookup("core");
+		pmic_data->vdd3 = &omap4_vdd3;
+	}
+
 	/* Common platform data configurations */
 	if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
 		pmic_data->usb = &omap4_usb_pdata;
@@ -350,5 +534,11 @@
 	if (regulators_flags & TWL_COMMON_REGULATOR_CLK32KG &&
 	    !pmic_data->clk32kg)
 		pmic_data->clk32kg = &omap4_clk32kg_idata;
+
+	if (regulators_flags & TWL_COMMON_REGULATOR_V1V8 && !pmic_data->v1v8)
+		pmic_data->v1v8 = &omap4_v1v8_idata;
+
+	if (regulators_flags & TWL_COMMON_REGULATOR_V2V1 && !pmic_data->v2v1)
+		pmic_data->v2v1 = &omap4_v2v1_idata;
 }
 #endif /* CONFIG_ARCH_OMAP4 */
diff --git a/arch/arm/mach-omap2/twl-common.h b/arch/arm/mach-omap2/twl-common.h
index 0962748..8fe71cf 100644
--- a/arch/arm/mach-omap2/twl-common.h
+++ b/arch/arm/mach-omap2/twl-common.h
@@ -22,6 +22,8 @@
 #define TWL_COMMON_REGULATOR_VCXIO	(1 << 8)
 #define TWL_COMMON_REGULATOR_VUSB	(1 << 9)
 #define TWL_COMMON_REGULATOR_CLK32KG	(1 << 10)
+#define TWL_COMMON_REGULATOR_V1V8	(1 << 11)
+#define TWL_COMMON_REGULATOR_V2V1	(1 << 12)
 
 /* TWL4030 LDO regulators */
 #define TWL_COMMON_REGULATOR_VPLL1	(1 << 4)
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index 994d8f5..db84a46 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -126,7 +126,7 @@
 	tmp = (t.sync_clk + fclk_ps - 1) / fclk_ps;
 	if (tmp > 4)
 		return -ERANGE;
-	if (tmp <= 0)
+	if (tmp == 0)
 		tmp = 1;
 	t.page_burst_access = (fclk_ps * tmp) / 1000;
 
diff --git a/arch/arm/mach-omap2/vc3xxx_data.c b/arch/arm/mach-omap2/vc3xxx_data.c
index a5ec7f8f..5d8eaf3 100644
--- a/arch/arm/mach-omap2/vc3xxx_data.c
+++ b/arch/arm/mach-omap2/vc3xxx_data.c
@@ -46,6 +46,7 @@
 };
 
 struct omap_vc_channel omap3_vc_mpu = {
+	.flags = OMAP_VC_CHANNEL_DEFAULT,
 	.common = &omap3_vc_common,
 	.smps_sa_reg	 = OMAP3_PRM_VC_SMPS_SA_OFFSET,
 	.smps_volra_reg	 = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET,
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 8a36342..4dc60e8 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -73,7 +73,8 @@
 int voltdm_scale(struct voltagedomain *voltdm,
 		 unsigned long target_volt)
 {
-	int ret;
+	int ret, i;
+	unsigned long volt = 0;
 
 	if (!voltdm || IS_ERR(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
@@ -86,9 +87,23 @@
 		return -ENODATA;
 	}
 
-	ret = voltdm->scale(voltdm, target_volt);
+	/* Adjust voltage to the exact voltage from the OPP table */
+	for (i = 0; voltdm->volt_data[i].volt_nominal != 0; i++) {
+		if (voltdm->volt_data[i].volt_nominal >= target_volt) {
+			volt = voltdm->volt_data[i].volt_nominal;
+			break;
+		}
+	}
+
+	if (!volt) {
+		pr_warning("%s: not scaling. OPP voltage for %lu, not found.\n",
+			   __func__, target_volt);
+		return -EINVAL;
+	}
+
+	ret = voltdm->scale(voltdm, volt);
 	if (!ret)
-		voltdm->nominal_volt = target_volt;
+		voltdm->nominal_volt = volt;
 
 	return ret;
 }
diff --git a/arch/arm/mach-omap2/wd_timer.c b/arch/arm/mach-omap2/wd_timer.c
index 4067669..b2f1c67 100644
--- a/arch/arm/mach-omap2/wd_timer.c
+++ b/arch/arm/mach-omap2/wd_timer.c
@@ -14,6 +14,7 @@
 #include <plat/omap_hwmod.h>
 
 #include "wd_timer.h"
+#include "common.h"
 
 /*
  * In order to avoid any assumptions from bootloader regarding WDT
@@ -25,6 +26,8 @@
 #define OMAP_WDT_WPS		0x34
 #define OMAP_WDT_SPR		0x48
 
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT	10000
 
 int omap2_wd_timer_disable(struct omap_hwmod *oh)
 {
@@ -54,3 +57,45 @@
 	return 0;
 }
 
+/**
+ * omap2_wdtimer_reset - reset and disable the WDTIMER IP block
+ * @oh: struct omap_hwmod *
+ *
+ * After the WDTIMER IP blocks are reset on OMAP2/3, we must also take
+ * care to execute the special watchdog disable sequence.  This is
+ * because the watchdog is re-armed upon OCP softreset.  (On OMAP4,
+ * this behavior was apparently changed and the watchdog is no longer
+ * re-armed after an OCP soft-reset.)  Returns -ETIMEDOUT if the reset
+ * did not complete, or 0 upon success.
+ *
+ * XXX Most of this code should be moved to the omap_hwmod.c layer
+ * during a normal merge window.  omap_hwmod_softreset() should be
+ * renamed to omap_hwmod_set_ocp_softreset(), and omap_hwmod_softreset()
+ * should call the hwmod _ocp_softreset() code.
+ */
+int omap2_wd_timer_reset(struct omap_hwmod *oh)
+{
+	int c = 0;
+
+	/* Write to the SOFTRESET bit */
+	omap_hwmod_softreset(oh);
+
+	/* Poll on RESETDONE bit */
+	omap_test_timeout((omap_hwmod_read(oh,
+					   oh->class->sysc->syss_offs)
+			   & SYSS_RESETDONE_MASK),
+			  MAX_MODULE_SOFTRESET_WAIT, c);
+
+	if (oh->class->sysc->srst_udelay)
+		udelay(oh->class->sysc->srst_udelay);
+
+	if (c == MAX_MODULE_SOFTRESET_WAIT)
+		pr_warning("%s: %s: softreset failed (waited %d usec)\n",
+			   __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT);
+	else
+		pr_debug("%s: %s: softreset in %d usec\n", __func__,
+			 oh->name, c);
+
+	return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT :
+		omap2_wd_timer_disable(oh);
+}
diff --git a/arch/arm/mach-omap2/wd_timer.h b/arch/arm/mach-omap2/wd_timer.h
index e0054a2..f6bbba7 100644
--- a/arch/arm/mach-omap2/wd_timer.h
+++ b/arch/arm/mach-omap2/wd_timer.h
@@ -13,5 +13,6 @@
 #include <plat/omap_hwmod.h>
 
 extern int omap2_wd_timer_disable(struct omap_hwmod *oh);
+extern int omap2_wd_timer_reset(struct omap_hwmod *oh);
 
 #endif
diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig
index 6604fc6..0673f0c 100644
--- a/arch/arm/mach-orion5x/Kconfig
+++ b/arch/arm/mach-orion5x/Kconfig
@@ -86,7 +86,6 @@
 
 config MACH_TS78XX
 	bool "Technologic Systems TS-78xx"
-	select PM
 	help
 	  Say 'Y' here if you want your kernel to support the
 	  Technologic Systems TS-78xx platform.
diff --git a/arch/arm/mach-orion5x/addr-map.c b/arch/arm/mach-orion5x/addr-map.c
index 3638e5c..eaac83d 100644
--- a/arch/arm/mach-orion5x/addr-map.c
+++ b/arch/arm/mach-orion5x/addr-map.c
@@ -76,7 +76,7 @@
 /*
  * Description of the windows needed by the platform code
  */
-static struct __initdata orion_addr_map_cfg addr_map_cfg = {
+static struct orion_addr_map_cfg addr_map_cfg __initdata = {
 	.num_wins = 8,
 	.cpu_win_can_remap = cpu_win_can_remap,
 	.bridge_virt_base = ORION5X_BRIDGE_VIRT_BASE,
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 2448166..e2e9db4 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -205,7 +205,7 @@
 	return 166666667;
 }
 
-static void orion5x_timer_init(void)
+static void __init orion5x_timer_init(void)
 {
 	orion5x_tclk = orion5x_find_tclk();
 
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index 2e6454c..31bab92 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -45,6 +45,7 @@
  */
 struct pci_bus;
 struct pci_sys_data;
+struct pci_dev;
 
 void orion5x_pcie_id(u32 *dev, u32 *rev);
 void orion5x_pci_disable(void);
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index 8c06cca..d470864 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -252,27 +252,6 @@
  * GPIO LEDs (simple - doesn't use hardware blinking support)
  */
 
-#define ORION_BLINK_HALF_PERIOD 100 /* ms */
-
-static int dns323_gpio_blink_set(unsigned gpio, int state,
-	unsigned long *delay_on, unsigned long *delay_off)
-{
-
-	if (delay_on && delay_off && !*delay_on && !*delay_off)
-		*delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
-
-	switch(state) {
-	case GPIO_LED_NO_BLINK_LOW:
-	case GPIO_LED_NO_BLINK_HIGH:
-		orion_gpio_set_blink(gpio, 0);
-		gpio_set_value(gpio, state);
-		break;
-	case GPIO_LED_BLINK:
-		orion_gpio_set_blink(gpio, 1);
-	}
-	return 0;
-}
-
 static struct gpio_led dns323ab_leds[] = {
 	{
 		.name = "power:blue",
@@ -311,13 +290,13 @@
 static struct gpio_led_platform_data dns323ab_led_data = {
 	.num_leds	= ARRAY_SIZE(dns323ab_leds),
 	.leds		= dns323ab_leds,
-	.gpio_blink_set = dns323_gpio_blink_set,
+	.gpio_blink_set = orion_gpio_led_blink_set,
 };
 
 static struct gpio_led_platform_data dns323c_led_data = {
 	.num_leds	= ARRAY_SIZE(dns323c_leds),
 	.leds		= dns323c_leds,
-	.gpio_blink_set = dns323_gpio_blink_set,
+	.gpio_blink_set = orion_gpio_led_blink_set,
 };
 
 static struct platform_device dns323_gpio_leds = {
diff --git a/arch/arm/mach-orion5x/ts78xx-fpga.h b/arch/arm/mach-orion5x/ts78xx-fpga.h
index 151e89e..97c393d 100644
--- a/arch/arm/mach-orion5x/ts78xx-fpga.h
+++ b/arch/arm/mach-orion5x/ts78xx-fpga.h
@@ -28,9 +28,9 @@
 
 struct fpga_devices {
 	/* Technologic Systems */
-	struct fpga_device 	ts_rtc;
-	struct fpga_device 	ts_nand;
-	struct fpga_device 	ts_rng;
+	struct fpga_device	ts_rtc;
+	struct fpga_device	ts_nand;
+	struct fpga_device	ts_rng;
 };
 
 struct ts78xx_fpga_data {
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index c96f374..a74f3cf 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -8,6 +8,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sysfs.h>
@@ -115,7 +117,7 @@
  * I've used the method TS use in their rtc7800.c example for the detection
  *
  * TODO: track down a guinea pig without an RTC to see if we can work out a
- * 		better RTC detection routine
+ *		better RTC detection routine
  */
 static int ts78xx_ts_rtc_load(void)
 {
@@ -141,10 +143,14 @@
 			} else
 				rc = platform_device_add(&ts78xx_ts_rtc_device);
 
+			if (rc)
+				pr_info("RTC could not be registered: %d\n",
+					rc);
 			return rc;
 		}
 	}
 
+	pr_info("RTC not found\n");
 	return -ENODEV;
 };
 
@@ -292,11 +298,8 @@
 	},
 };
 
-static struct resource ts78xx_ts_nand_resources = {
-	.start		= TS_NAND_DATA,
-	.end		= TS_NAND_DATA + 4,
-	.flags		= IORESOURCE_MEM,
-};
+static struct resource ts78xx_ts_nand_resources
+			= DEFINE_RES_MEM(TS_NAND_DATA, 4);
 
 static struct platform_device ts78xx_ts_nand_device = {
 	.name		= "gen_nand",
@@ -319,6 +322,8 @@
 	} else
 		rc = platform_device_add(&ts78xx_ts_nand_device);
 
+	if (rc)
+		pr_info("NAND could not be registered: %d\n", rc);
 	return rc;
 };
 
@@ -332,11 +337,8 @@
  ****************************************************************************/
 #define TS_RNG_DATA	(TS78XX_FPGA_REGS_PHYS_BASE | 0x044)
 
-static struct resource ts78xx_ts_rng_resource = {
-	.flags		= IORESOURCE_MEM,
-	.start		= TS_RNG_DATA,
-	.end		= TS_RNG_DATA + 4 - 1,
-};
+static struct resource ts78xx_ts_rng_resource
+			= DEFINE_RES_MEM(TS_RNG_DATA, 4);
 
 static struct timeriomem_rng_data ts78xx_ts_rng_data = {
 	.period		= 1000000, /* one second */
@@ -363,6 +365,8 @@
 	} else
 		rc = platform_device_add(&ts78xx_ts_rng_device);
 
+	if (rc)
+		pr_info("RNG could not be registered: %d\n", rc);
 	return rc;
 };
 
@@ -402,7 +406,7 @@
 		/* enable devices if magic matches */
 		switch ((ts78xx_fpga.id >> 8) & 0xffffff) {
 		case TS7800_FPGA_MAGIC:
-			pr_warning("TS-7800 FPGA: unrecognized revision 0x%.2x\n",
+			pr_warning("unrecognised FPGA revision 0x%.2x\n",
 					ts78xx_fpga.id & 0xff);
 			ts78xx_fpga.supports.ts_rtc.present = 1;
 			ts78xx_fpga.supports.ts_nand.present = 1;
@@ -422,26 +426,20 @@
 
 	if (ts78xx_fpga.supports.ts_rtc.present == 1) {
 		tmp = ts78xx_ts_rtc_load();
-		if (tmp) {
-			pr_info("TS-78xx: RTC not registered\n");
+		if (tmp)
 			ts78xx_fpga.supports.ts_rtc.present = 0;
-		}
 		ret |= tmp;
 	}
 	if (ts78xx_fpga.supports.ts_nand.present == 1) {
 		tmp = ts78xx_ts_nand_load();
-		if (tmp) {
-			pr_info("TS-78xx: NAND not registered\n");
+		if (tmp)
 			ts78xx_fpga.supports.ts_nand.present = 0;
-		}
 		ret |= tmp;
 	}
 	if (ts78xx_fpga.supports.ts_rng.present == 1) {
 		tmp = ts78xx_ts_rng_load();
-		if (tmp) {
-			pr_info("TS-78xx: RNG not registered\n");
+		if (tmp)
 			ts78xx_fpga.supports.ts_rng.present = 0;
-		}
 		ret |= tmp;
 	}
 
@@ -466,7 +464,7 @@
 {
 	ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
 
-	pr_info("TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",
+	pr_info("FPGA magic=0x%.6x, rev=0x%.2x\n",
 			(ts78xx_fpga.id >> 8) & 0xffffff,
 			ts78xx_fpga.id & 0xff);
 
@@ -494,7 +492,7 @@
 	 * UrJTAG SVN since r1381 can be used to reprogram the FPGA
 	 */
 	if (ts78xx_fpga.id != fpga_id) {
-		pr_err("TS-78xx FPGA: magic/rev mismatch\n"
+		pr_err("FPGA magic/rev mismatch\n"
 			"TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
 			(ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
 			(fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
@@ -525,7 +523,7 @@
 	int value, ret;
 
 	if (ts78xx_fpga.state < 0) {
-		pr_err("TS-78xx FPGA: borked, you must powercycle asap\n");
+		pr_err("FPGA borked, you must powercycle ASAP\n");
 		return -EBUSY;
 	}
 
@@ -533,10 +531,8 @@
 		value = 1;
 	else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
 		value = 0;
-	else {
-		pr_err("ts78xx_fpga_store: Invalid value\n");
+	else
 		return -EINVAL;
-	}
 
 	if (ts78xx_fpga.state == value)
 		return n;
@@ -614,7 +610,7 @@
 	/* FPGA init */
 	ts78xx_fpga_devices_zero_init();
 	ret = ts78xx_fpga_load();
-	ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
+	ret = sysfs_create_file(firmware_kobj, &ts78xx_fpga_attr.attr);
 	if (ret)
 		pr_err("sysfs_create_file failed: %d\n", ret);
 }
diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c
index 8103f96..550cfc2 100644
--- a/arch/arm/mach-pnx4008/i2c.c
+++ b/arch/arm/mach-pnx4008/i2c.c
@@ -16,48 +16,62 @@
 #include <linux/err.h>
 #include <mach/platform.h>
 #include <mach/irqs.h>
-#include <mach/i2c.h>
 
-static struct i2c_pnx_data i2c0_data = {
-	.name = I2C_CHIP_NAME "0",
-	.base = PNX4008_I2C1_BASE,
-	.irq = I2C_1_INT,
+static struct resource i2c0_resources[] = {
+	{
+		.start = PNX4008_I2C1_BASE,
+		.end = PNX4008_I2C1_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = I2C_1_INT,
+		.end = I2C_1_INT,
+		.flags = IORESOURCE_IRQ,
+	},
 };
 
-static struct i2c_pnx_data i2c1_data = {
-	.name = I2C_CHIP_NAME "1",
-	.base = PNX4008_I2C2_BASE,
-	.irq = I2C_2_INT,
+static struct resource i2c1_resources[] = {
+	{
+		.start = PNX4008_I2C2_BASE,
+		.end = PNX4008_I2C2_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = I2C_2_INT,
+		.end = I2C_2_INT,
+		.flags = IORESOURCE_IRQ,
+	},
 };
 
-static struct i2c_pnx_data i2c2_data = {
-	.name = "USB-I2C",
-	.base = (PNX4008_USB_CONFIG_BASE + 0x300),
-	.irq = USB_I2C_INT,
+static struct resource i2c2_resources[] = {
+	{
+		.start = PNX4008_USB_CONFIG_BASE + 0x300,
+		.end = PNX4008_USB_CONFIG_BASE + 0x300 + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = USB_I2C_INT,
+		.end = USB_I2C_INT,
+		.flags = IORESOURCE_IRQ,
+	},
 };
 
 static struct platform_device i2c0_device = {
-	.name = "pnx-i2c",
+	.name = "pnx-i2c.0",
 	.id = 0,
-	.dev = {
-		.platform_data = &i2c0_data,
-	},
+	.resource = i2c0_resources,
+	.num_resources = ARRAY_SIZE(i2c0_resources),
 };
 
 static struct platform_device i2c1_device = {
-	.name = "pnx-i2c",
+	.name = "pnx-i2c.1",
 	.id = 1,
-	.dev = {
-		.platform_data = &i2c1_data,
-	},
+	.resource = i2c1_resources,
+	.num_resources = ARRAY_SIZE(i2c1_resources),
 };
 
 static struct platform_device i2c2_device = {
-	.name = "pnx-i2c",
+	.name = "pnx-i2c.2",
 	.id = 2,
-	.dev = {
-		.platform_data = &i2c2_data,
-	},
+	.resource = i2c2_resources,
+	.num_resources = ARRAY_SIZE(i2c2_resources),
 };
 
 static struct platform_device *devices[] __initdata = {
diff --git a/arch/arm/mach-pnx4008/include/mach/i2c.h b/arch/arm/mach-pnx4008/include/mach/i2c.h
deleted file mode 100644
index 259ac53..0000000
--- a/arch/arm/mach-pnx4008/include/mach/i2c.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * PNX4008-specific tweaks for I2C IP3204 block
- *
- * Author: Vitaly Wool <vwool@ru.mvista.com>
- *
- * 2005 (c) MontaVista Software, 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 __ASM_ARCH_I2C_H__
-#define __ASM_ARCH_I2C_H__
-
-enum {
-	mstatus_tdi = 0x00000001,
-	mstatus_afi = 0x00000002,
-	mstatus_nai = 0x00000004,
-	mstatus_drmi = 0x00000008,
-	mstatus_active = 0x00000020,
-	mstatus_scl = 0x00000040,
-	mstatus_sda = 0x00000080,
-	mstatus_rff = 0x00000100,
-	mstatus_rfe = 0x00000200,
-	mstatus_tff = 0x00000400,
-	mstatus_tfe = 0x00000800,
-};
-
-enum {
-	mcntrl_tdie = 0x00000001,
-	mcntrl_afie = 0x00000002,
-	mcntrl_naie = 0x00000004,
-	mcntrl_drmie = 0x00000008,
-	mcntrl_daie = 0x00000020,
-	mcntrl_rffie = 0x00000040,
-	mcntrl_tffie = 0x00000080,
-	mcntrl_reset = 0x00000100,
-	mcntrl_cdbmode = 0x00000400,
-};
-
-enum {
-	rw_bit = 1 << 0,
-	start_bit = 1 << 8,
-	stop_bit = 1 << 9,
-};
-
-#define I2C_REG_RX(a)	((a)->ioaddr)		/* Rx FIFO reg (RO) */
-#define I2C_REG_TX(a)	((a)->ioaddr)		/* Tx FIFO reg (WO) */
-#define I2C_REG_STS(a)	((a)->ioaddr + 0x04)	/* Status reg (RO) */
-#define I2C_REG_CTL(a)	((a)->ioaddr + 0x08)	/* Ctl reg */
-#define I2C_REG_CKL(a)	((a)->ioaddr + 0x0c)	/* Clock divider low */
-#define I2C_REG_CKH(a)	((a)->ioaddr + 0x10)	/* Clock divider high */
-#define I2C_REG_ADR(a)	((a)->ioaddr + 0x14)	/* I2C address */
-#define I2C_REG_RFL(a)	((a)->ioaddr + 0x18)	/* Rx FIFO level (RO) */
-#define I2C_REG_TFL(a)	((a)->ioaddr + 0x1c)	/* Tx FIFO level (RO) */
-#define I2C_REG_RXB(a)	((a)->ioaddr + 0x20)	/* Num of bytes Rx-ed (RO) */
-#define I2C_REG_TXB(a)	((a)->ioaddr + 0x24)	/* Num of bytes Tx-ed (RO) */
-#define I2C_REG_TXS(a)	((a)->ioaddr + 0x28)	/* Tx slave FIFO (RO) */
-#define I2C_REG_STFL(a)	((a)->ioaddr + 0x2c)	/* Tx slave FIFO level (RO) */
-
-#define HCLK_MHZ		13
-#define I2C_CHIP_NAME		"PNX4008-I2C"
-
-#endif				/* __ASM_ARCH_I2C_H___ */
diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c
index c35456f..56e8ceb 100644
--- a/arch/arm/mach-pxa/balloon3.c
+++ b/arch/arm/mach-pxa/balloon3.c
@@ -732,9 +732,7 @@
 #if defined(CONFIG_REGULATOR_MAX1586) || \
     defined(CONFIG_REGULATOR_MAX1586_MODULE)
 static struct regulator_consumer_supply balloon3_max1587a_consumers[] = {
-	{
-		.supply	= "vcc_core",
-	}
+	REGULATOR_SUPPLY("vcc_core", NULL),
 };
 
 static struct regulator_init_data balloon3_max1587a_v3_info = {
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index 3132740..3e4e9fe 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -713,9 +713,7 @@
 };
 
 static struct regulator_consumer_supply buck2_consumers[] = {
-	{
-		.supply = "vcc_core",
-	},
+	REGULATOR_SUPPLY("vcc_core", NULL),
 };
 
 static struct regulator_init_data buck2_data = {
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 16ec557..a3a4a38 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -1085,10 +1085,7 @@
 /* DA9030 related initializations */
 #define REGULATOR_CONSUMER(_name, _dev_name, _supply)		        \
 	static struct regulator_consumer_supply _name##_consumers[] = {	\
-		{							\
-			.dev_name = _dev_name,				\
-			.supply = _supply,				\
-		},							\
+		REGULATOR_SUPPLY(_supply, _dev_name),			\
 	}
 
 REGULATOR_CONSUMER(ldo3, "reg-userspace-consumer.0", "vcc gps");
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index b83b95a..d09da6a 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -22,6 +22,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
+#include <linux/input/navpoint.h>
 #include <linux/lcd.h>
 #include <linux/mfd/htc-egpio.h>
 #include <linux/mfd/asic3.h>
@@ -102,6 +103,10 @@
 	GPIO44_BTUART_CTS,
 	GPIO45_BTUART_RTS_LPM_LOW,
 
+	/* STUART (IRDA) */
+	GPIO46_STUART_RXD,
+	GPIO47_STUART_TXD,
+
 	/* PWM 1 (Backlight) */
 	GPIO17_PWM1_OUT,
 
@@ -113,7 +118,7 @@
 	GPIO113_I2S_SYSCLK,
 
 	/* SSP 1 (NavPoint) */
-	GPIO23_SSP1_SCLK,
+	GPIO23_SSP1_SCLK_IN,
 	GPIO24_SSP1_SFRM,
 	GPIO25_SSP1_TXD,
 	GPIO26_SSP1_RXD,
@@ -125,10 +130,13 @@
 	GPIO88_GPIO,
 
 	/* HX4700 specific input GPIOs */
-	GPIO12_GPIO,	/* ASIC3_IRQ */
+	GPIO12_GPIO | WAKEUP_ON_EDGE_RISE,	/* ASIC3_IRQ */
 	GPIO13_GPIO,	/* W3220_IRQ */
 	GPIO14_GPIO,	/* nWLAN_IRQ */
 
+	/* HX4700 specific output GPIOs */
+	GPIO102_GPIO | MFP_LPM_DRIVE_LOW,	/* SYNAPTICS_POWER_ON */
+
 	GPIO10_GPIO,	/* GSM_IRQ */
 	GPIO13_GPIO,	/* CPLD_IRQ */
 	GPIO107_GPIO,	/* DS1WM_IRQ */
@@ -183,6 +191,23 @@
 };
 
 /*
+ * Synaptics NavPoint connected to SSP1
+ */
+
+static struct navpoint_platform_data navpoint_platform_data = {
+	.port	= 1,
+	.gpio	= GPIO102_HX4700_SYNAPTICS_POWER_ON,
+};
+
+static struct platform_device navpoint = {
+	.name	= "navpoint",
+	.id	= -1,
+	.dev = {
+		.platform_data = &navpoint_platform_data,
+	},
+};
+
+/*
  * ASIC3
  */
 
@@ -227,7 +252,6 @@
 	ASIC3_GPIOC0_LED0,		/* red */
 	ASIC3_GPIOC1_LED1,		/* green */
 	ASIC3_GPIOC2_LED2,		/* blue */
-	ASIC3_GPIOC4_CF_nCD,
 	ASIC3_GPIOC5_nCIOW,
 	ASIC3_GPIOC6_nCIOR,
 	ASIC3_GPIOC7_nPCE_1,
@@ -241,6 +265,7 @@
 	ASIC3_GPIOC15_nPIOR,
 
 	/* GPIOD: input GPIOs, CF */
+	ASIC3_GPIOD4_CF_nCD,
 	ASIC3_GPIOD11_nCIOIS16,
 	ASIC3_GPIOD12_nCWAIT,
 	ASIC3_GPIOD15_nPIOW,
@@ -291,6 +316,7 @@
 	.gpio_config_num = ARRAY_SIZE(asic3_gpio_config),
 	.irq_base        = IRQ_BOARD_START,
 	.gpio_base       = HX4700_ASIC3_GPIO_BASE,
+	.clock_rate      = 4000000,
 	.leds            = asic3_leds,
 };
 
@@ -680,12 +706,8 @@
  */
 
 static struct regulator_consumer_supply bq24022_consumers[] = {
-	{
-		.supply = "vbus_draw",
-	},
-	{
-		.supply = "ac_draw",
-	},
+	REGULATOR_SUPPLY("vbus_draw", NULL),
+	REGULATOR_SUPPLY("ac_draw", NULL),
 };
 
 static struct regulator_init_data bq24022_init_data = {
@@ -764,9 +786,8 @@
  * Maxim MAX1587A on PI2C
  */
 
-static struct regulator_consumer_supply max1587a_consumer = {
-	.supply = "vcc_core",
-};
+static struct regulator_consumer_supply max1587a_consumer =
+	REGULATOR_SUPPLY("vcc_core", NULL);
 
 static struct regulator_init_data max1587a_v3_info = {
 	.constraints = {
@@ -828,6 +849,7 @@
 static struct platform_device *devices[] __initdata = {
 	&asic3,
 	&gpio_keys,
+	&navpoint,
 	&backlight,
 	&w3220,
 	&hx4700_lcd,
@@ -859,6 +881,7 @@
 	int ret;
 
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(hx4700_pin_config));
+	gpio_set_wake(GPIO12_HX4700_ASIC3_IRQ, 1);
 	ret = gpio_request_array(ARRAY_AND_SIZE(global_gpios));
 	if (ret)
 		pr_err ("hx4700: Failed to request GPIOs.\n");
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
index a658672..a611ad3 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
@@ -208,6 +208,7 @@
 #define GPIO113_I2S_SYSCLK	MFP_CFG_OUT(GPIO113, AF1, DRIVE_LOW)
 
 /* SSP 1 */
+#define GPIO23_SSP1_SCLK_IN	MFP_CFG_IN(GPIO23, AF2)
 #define GPIO23_SSP1_SCLK	MFP_CFG_OUT(GPIO23, AF2, DRIVE_LOW)
 #define GPIO29_SSP1_SCLK	MFP_CFG_IN(GPIO29, AF3)
 #define GPIO27_SSP1_SYSCLK	MFP_CFG_OUT(GPIO27, AF1, DRIVE_LOW)
diff --git a/arch/arm/mach-pxa/include/mach/mioa701.h b/arch/arm/mach-pxa/include/mach/mioa701.h
index 0286844..e57f5c7 100644
--- a/arch/arm/mach-pxa/include/mach/mioa701.h
+++ b/arch/arm/mach-pxa/include/mach/mioa701.h
@@ -61,6 +61,9 @@
 #define GPIO93_KEY_VOLUME_UP			93
 #define GPIO94_KEY_VOLUME_DOWN			94
 
+/* Camera */
+#define GPIO56_MT9M111_nOE			56
+
 extern struct input_dev *mioa701_evdev;
 extern void mioa701_gpio_lpm_set(unsigned long mfp_pin);
 
diff --git a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
index d727916..0260aaa 100644
--- a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
+++ b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
@@ -31,7 +31,6 @@
 #define PCM990_CTRL_INT_IRQ		PXA_GPIO_TO_IRQ(PCM990_CTRL_INT_IRQ_GPIO)
 #define PCM990_CTRL_INT_IRQ_EDGE	IRQ_TYPE_EDGE_RISING
 #define PCM990_CTRL_PHYS		PXA_CS1_PHYS	/* 16-Bit */
-#define PCM990_CTRL_BASE		0xea000000
 #define PCM990_CTRL_SIZE		(1*1024*1024)
 
 #define PCM990_CTRL_PWR_IRQ_GPIO	14
@@ -69,13 +68,13 @@
 #define PCM990_CTRL_MMC2DE	0x0004	/* R MMC2 Card detect */
 #define PCM990_CTRL_MMC2WP	0x0008	/* R MMC2 Card write protect */
 
-#define PCM990_CTRL_REG6	0x000C	/* Interrupt Clear REGISTER */
+#define PCM990_CTRL_INTSETCLR	0x000C	/* Interrupt Clear REGISTER */
 #define PCM990_CTRL_INTC0	0x0001	/* Clear Reg BT Detect */
 #define PCM990_CTRL_INTC1	0x0002	/* Clear Reg FR RI */
 #define PCM990_CTRL_INTC2	0x0004	/* Clear Reg MMC1 Detect */
 #define PCM990_CTRL_INTC3	0x0008	/* Clear Reg PM_5V off */
 
-#define PCM990_CTRL_REG7	0x000E	/* Interrupt Enable REGISTER */
+#define PCM990_CTRL_INTMSKENA	0x000E	/* Interrupt Enable REGISTER */
 #define PCM990_CTRL_ENAINT0	0x0001	/* Enable Int BT Detect */
 #define PCM990_CTRL_ENAINT1	0x0002	/* Enable Int FR RI */
 #define PCM990_CTRL_ENAINT2	0x0004	/* Enable Int MMC1 Detect */
@@ -102,32 +101,6 @@
 #define PCM990_CTRL_ACPRES	0x0004	/* DC Present */
 #define PCM990_CTRL_ACALARM	0x0008	/* Error Akku */
 
-#define PCM990_CTRL_P2V(x)	((x) - PCM990_CTRL_PHYS + PCM990_CTRL_BASE)
-#define PCM990_CTRL_V2P(x)	((x) - PCM990_CTRL_BASE + PCM990_CTRL_PHYS)
-
-#ifndef __ASSEMBLY__
-#  define __PCM990_CTRL_REG(x) \
-		(*((volatile unsigned char *)PCM990_CTRL_P2V(x)))
-#else
-#  define __PCM990_CTRL_REG(x)	PCM990_CTRL_P2V(x)
-#endif
-
-#define PCM990_INTMSKENA __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG7)
-#define PCM990_INTSETCLR __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG6)
-#define PCM990_CTRL0	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG0)
-#define PCM990_CTRL1	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG1)
-#define PCM990_CTRL2	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG2)
-#define PCM990_CTRL3	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG3)
-#define PCM990_CTRL4	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG4)
-#define PCM990_CTRL5	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5)
-#define PCM990_CTRL6	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG6)
-#define PCM990_CTRL7	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG7)
-#define PCM990_CTRL8	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG8)
-#define PCM990_CTRL9	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG9)
-#define PCM990_CTRL10	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG10)
-#define PCM990_CTRL11	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG11)
-
-
 /*
  * IDE
  */
@@ -166,24 +139,6 @@
 #define PCM990_IDE_PLD_P2V(x) ((x) - PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_BASE)
 #define PCM990_IDE_PLD_V2P(x) ((x) - PCM990_IDE_PLD_BASE + PCM990_IDE_PLD_PHYS)
 
-#ifndef __ASSEMBLY__
-# define  __PCM990_IDE_PLD_REG(x) \
-	(*((volatile unsigned char *)PCM990_IDE_PLD_P2V(x)))
-#else
-# define  __PCM990_IDE_PLD_REG(x)	PCM990_IDE_PLD_P2V(x)
-#endif
-
-#define PCM990_IDE0 \
-	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG0)
-#define PCM990_IDE1 \
-	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG1)
-#define PCM990_IDE2 \
-	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG2)
-#define PCM990_IDE3 \
-	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG3)
-#define PCM990_IDE4 \
-	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG4)
-
 /*
  * Compact Flash
  */
@@ -196,10 +151,6 @@
 #define PCM990_CF_CD_EDGE	IRQ_TYPE_EDGE_RISING
 
 #define PCM990_CF_PLD_PHYS	0x30000000	/* 16 bit wide */
-#define PCM990_CF_PLD_BASE	0xef000000
-#define PCM990_CF_PLD_SIZE	(1*1024*1024)
-#define PCM990_CF_PLD_P2V(x)	((x) - PCM990_CF_PLD_PHYS + PCM990_CF_PLD_BASE)
-#define PCM990_CF_PLD_V2P(x)	((x) - PCM990_CF_PLD_BASE + PCM990_CF_PLD_PHYS)
 
 /* visible CPLD (U6) registers */
 #define PCM990_CF_PLD_REG0	0x1000	/* OFFSET CF REGISTER 0 */
@@ -239,21 +190,6 @@
 #define PCM990_CF_REG6_CD1	0x0001	/* R CF Card_Detect1 */
 #define PCM990_CF_REG6_CD2	0x0002	/* R CF Card_Detect2 */
 
-#ifndef __ASSEMBLY__
-#  define  __PCM990_CF_PLD_REG(x) \
-	(*((volatile unsigned char *)PCM990_CF_PLD_P2V(x)))
-#else
-#  define  __PCM990_CF_PLD_REG(x)	PCM990_CF_PLD_P2V(x)
-#endif
-
-#define PCM990_CF0 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG0)
-#define PCM990_CF1 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG1)
-#define PCM990_CF2 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG2)
-#define PCM990_CF3 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG3)
-#define PCM990_CF4 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG4)
-#define PCM990_CF5 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG5)
-#define PCM990_CF6 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG6)
-
 /*
  * Wolfson AC97 Touch
  */
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index 8de0651..2db697c 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -579,12 +579,8 @@
  */
 
 static struct regulator_consumer_supply bq24022_consumers[] = {
-	{
-		.supply = "vbus_draw",
-	},
-	{
-		.supply = "ac_draw",
-	},
+	REGULATOR_SUPPLY("vbus_draw", NULL),
+	REGULATOR_SUPPLY("ac_draw", NULL),
 };
 
 static struct regulator_init_data bq24022_init_data = {
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index 061d570..bf99022 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -103,6 +103,7 @@
 	GPIO82_CIF_DD_5,
 	GPIO84_CIF_FV,
 	GPIO85_CIF_LV,
+	MIO_CFG_OUT(GPIO56_MT9M111_nOE, AF0, DRIVE_LOW),
 
 	/* Bluetooth */
 	MIO_CFG_IN(GPIO14_BT_nACTIVITY, AF0),
@@ -581,9 +582,7 @@
  * Voltage regulation
  */
 static struct regulator_consumer_supply max1586_consumers[] = {
-	{
-		.supply = "vcc_core",
-	}
+	REGULATOR_SUPPLY("vcc_core", NULL),
 };
 
 static struct regulator_init_data max1586_v3_info = {
@@ -705,6 +704,7 @@
 	{ GPIO9_CHARGE_EN, GPIOF_OUT_INIT_HIGH, "Charger enable" },
 	{ GPIO18_POWEROFF, GPIOF_OUT_INIT_LOW, "Power Off" },
 	{ GPIO87_LCD_POWER, GPIOF_OUT_INIT_LOW, "LCD Power" },
+	{ GPIO56_MT9M111_nOE, GPIOF_OUT_INIT_LOW, "Camera nOE" },
 };
 
 static void __init mioa701_machine_init(void)
diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c
index fbc10d7..dad71cf 100644
--- a/arch/arm/mach-pxa/palm27x.c
+++ b/arch/arm/mach-pxa/palm27x.c
@@ -429,9 +429,7 @@
 #if defined(CONFIG_REGULATOR_MAX1586) || \
     defined(CONFIG_REGULATOR_MAX1586_MODULE)
 static struct regulator_consumer_supply palm27x_max1587a_consumers[] = {
-	{
-		.supply	= "vcc_core",
-	}
+	REGULATOR_SUPPLY("vcc_core", NULL),
 };
 
 static struct regulator_init_data palm27x_max1587a_v3_info = {
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index abab4e2..cb723e8 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -65,6 +65,18 @@
 	GPIO31_AC97_SYNC,
 };
 
+static void __iomem *pcm990_cpld_base;
+
+static u8 pcm990_cpld_readb(unsigned int reg)
+{
+	return readb(pcm990_cpld_base + reg);
+}
+
+static void pcm990_cpld_writeb(u8 value, unsigned int reg)
+{
+	writeb(value, pcm990_cpld_base + reg);
+}
+
 /*
  * pcm990_lcd_power - control power supply to the LCD
  * @on: 0 = switch off, 1 = switch on
@@ -78,13 +90,13 @@
 		/* enable LCD-Latches
 		 * power on LCD
 		 */
-		__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG3) =
-			PCM990_CTRL_LCDPWR + PCM990_CTRL_LCDON;
+		pcm990_cpld_writeb(PCM990_CTRL_LCDPWR + PCM990_CTRL_LCDON,
+				PCM990_CTRL_REG3);
 	} else {
 		/* disable LCD-Latches
 		 * power off LCD
 		 */
-		__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG3) = 0x00;
+		pcm990_cpld_writeb(0, PCM990_CTRL_REG3);
 	}
 }
 #endif
@@ -243,15 +255,26 @@
 static void pcm990_mask_ack_irq(struct irq_data *d)
 {
 	int pcm990_irq = (d->irq - PCM027_IRQ(0));
-	PCM990_INTMSKENA = (pcm990_irq_enabled &= ~(1 << pcm990_irq));
+
+	pcm990_irq_enabled &= ~(1 << pcm990_irq);
+
+	pcm990_cpld_writeb(pcm990_irq_enabled, PCM990_CTRL_INTMSKENA);
 }
 
 static void pcm990_unmask_irq(struct irq_data *d)
 {
 	int pcm990_irq = (d->irq - PCM027_IRQ(0));
+	u8 val;
+
 	/* the irq can be acknowledged only if deasserted, so it's done here */
-	PCM990_INTSETCLR |= 1 << pcm990_irq;
-	PCM990_INTMSKENA  = (pcm990_irq_enabled |= (1 << pcm990_irq));
+
+	pcm990_irq_enabled |= (1 << pcm990_irq);
+
+	val = pcm990_cpld_readb(PCM990_CTRL_INTSETCLR);
+	val |= 1 << pcm990_irq;
+	pcm990_cpld_writeb(val, PCM990_CTRL_INTSETCLR);
+
+	pcm990_cpld_writeb(pcm990_irq_enabled, PCM990_CTRL_INTMSKENA);
 }
 
 static struct irq_chip pcm990_irq_chip = {
@@ -261,7 +284,10 @@
 
 static void pcm990_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-	unsigned long pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled;
+	unsigned long pending;
+
+	pending = ~pcm990_cpld_readb(PCM990_CTRL_INTSETCLR);
+	pending &= pcm990_irq_enabled;
 
 	do {
 		/* clear our parent IRQ */
@@ -270,7 +296,8 @@
 			irq = PCM027_IRQ(0) + __ffs(pending);
 			generic_handle_irq(irq);
 		}
-		pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled;
+		pending = ~pcm990_cpld_readb(PCM990_CTRL_INTSETCLR);
+		pending &= pcm990_irq_enabled;
 	} while (pending);
 }
 
@@ -285,8 +312,9 @@
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 
-	PCM990_INTMSKENA = 0x00;	/* disable all Interrupts */
-	PCM990_INTSETCLR = 0xFF;
+	/* disable all Interrupts */
+	pcm990_cpld_writeb(0x0, PCM990_CTRL_INTMSKENA);
+	pcm990_cpld_writeb(0xff, PCM990_CTRL_INTSETCLR);
 
 	irq_set_chained_handler(PCM990_CTRL_INT_IRQ, pcm990_irq_handler);
 	irq_set_irq_type(PCM990_CTRL_INT_IRQ, PCM990_CTRL_INT_IRQ_EDGE);
@@ -309,13 +337,16 @@
 static void pcm990_mci_setpower(struct device *dev, unsigned int vdd)
 {
 	struct pxamci_platform_data *p_d = dev->platform_data;
+	u8 val;
+
+	val = pcm990_cpld_readb(PCM990_CTRL_REG5);
 
 	if ((1 << vdd) & p_d->ocr_mask)
-		__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5) =
-						PCM990_CTRL_MMC2PWR;
+		val |= PCM990_CTRL_MMC2PWR;
 	else
-		__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5) =
-						~PCM990_CTRL_MMC2PWR;
+		val &= ~PCM990_CTRL_MMC2PWR;
+
+	pcm990_cpld_writeb(PCM990_CTRL_MMC2PWR, PCM990_CTRL_REG5);
 }
 
 static void pcm990_mci_exit(struct device *dev, void *data)
@@ -481,23 +512,6 @@
 #endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
 
 /*
- * enable generic access to the base board control CPLDs U6 and U7
- */
-static struct map_desc pcm990_io_desc[] __initdata = {
-	{
-		.virtual	= PCM990_CTRL_BASE,
-		.pfn		= __phys_to_pfn(PCM990_CTRL_PHYS),
-		.length		= PCM990_CTRL_SIZE,
-		.type		= MT_DEVICE	/* CPLD */
-	}, {
-		.virtual	= PCM990_CF_PLD_BASE,
-		.pfn		= __phys_to_pfn(PCM990_CF_PLD_PHYS),
-		.length		= PCM990_CF_PLD_SIZE,
-		.type		= MT_DEVICE	/* CPLD */
-	}
-};
-
-/*
  * system init for baseboard usage. Will be called by pcm027 init.
  *
  * Add platform devices present on this baseboard and init
@@ -507,8 +521,11 @@
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(pcm990_pin_config));
 
-	/* register CPLD access */
-	iotable_init(ARRAY_AND_SIZE(pcm990_io_desc));
+	pcm990_cpld_base = ioremap(PCM990_CTRL_PHYS, PCM990_CTRL_SIZE);
+	if (!pcm990_cpld_base) {
+		pr_err("pcm990: failed to ioremap cpld\n");
+		return;
+	}
 
 	/* register CPLD's IRQ controller */
 	pcm990_init_irq();
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index df2ab0f..363d91b 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -877,9 +877,7 @@
 };
 
 static struct regulator_consumer_supply isl6271a_consumers[] = {
-	{
-		.supply	= "vcc_core",
-	}
+	REGULATOR_SUPPLY("vcc_core", NULL),
 };
 
 static struct regulator_init_data isl6271a_info[] = {
diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c
index 4cd645e..30b1b0b 100644
--- a/arch/arm/mach-pxa/stargate2.c
+++ b/arch/arm/mach-pxa/stargate2.c
@@ -151,10 +151,7 @@
 };
 
 static struct regulator_consumer_supply stargate2_sensor_3_con[] = {
-	{
-		.dev_name = "sht15",
-		.supply = "vcc",
-	},
+	REGULATOR_SUPPLY("vcc", "sht15"),
 };
 
 enum stargate2_ldos{
diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c
index c57ab63..e1740ac 100644
--- a/arch/arm/mach-pxa/vpac270.c
+++ b/arch/arm/mach-pxa/vpac270.c
@@ -640,9 +640,7 @@
 #if defined(CONFIG_REGULATOR_MAX1586) || \
     defined(CONFIG_REGULATOR_MAX1586_MODULE)
 static struct regulator_consumer_supply vpac270_max1587a_consumers[] = {
-	{
-		.supply	= "vcc_core",
-	}
+	REGULATOR_SUPPLY("vcc_core", NULL),
 };
 
 static struct regulator_init_data vpac270_max1587a_v3_info = {
diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c
index fa86199..b9320cb 100644
--- a/arch/arm/mach-pxa/z2.c
+++ b/arch/arm/mach-pxa/z2.c
@@ -615,9 +615,7 @@
 #if defined(CONFIG_REGULATOR_TPS65023) || \
 	defined(CONFIG_REGULATOR_TPS65023_MODULE)
 static struct regulator_consumer_supply z2_tps65021_consumers[] = {
-	{
-		.supply	= "vcc_core",
-	}
+	REGULATOR_SUPPLY("vcc_core", NULL),
 };
 
 static struct regulator_init_data z2_tps65021_info[] = {
diff --git a/arch/arm/mach-s3c24xx/bast-ide.c b/arch/arm/mach-s3c24xx/bast-ide.c
index 298ecec..ba02cf8 100644
--- a/arch/arm/mach-s3c24xx/bast-ide.c
+++ b/arch/arm/mach-s3c24xx/bast-ide.c
@@ -37,21 +37,9 @@
 #define IDE_CS	S3C2410_CS5
 
 static struct resource bast_ide0_resource[] = {
-	[0]	= {
-		.start	= IDE_CS + BAST_PA_IDEPRI,
-		.end	= IDE_CS + BAST_PA_IDEPRI + (8 * 0x20) - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1]	= {
-		.start	= IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20) ,
-		.end	= IDE_CS + BAST_PA_IDEPRIAUX + (7 * 0x20) - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[2]	= {
-		.start	= IRQ_IDE0,
-		.end	= IRQ_IDE0,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDEPRI, 8 * 0x20),
+	[1] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20), 0x20),
+	[2] = DEFINE_RES_IRQ(IRQ_IDE0),
 };
 
 static struct platform_device bast_device_ide0 = {
@@ -67,21 +55,9 @@
 };
 
 static struct resource bast_ide1_resource[] = {
-	[0]	= {
-		.start	= IDE_CS + BAST_PA_IDESEC,
-		.end	= IDE_CS + BAST_PA_IDESEC + (8 * 0x20) - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1]	= {
-		.start	= IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20),
-		.end	= IDE_CS + BAST_PA_IDESECAUX + (7 * 0x20) - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[2]	= {
-		.start	= IRQ_IDE1,
-		.end	= IRQ_IDE1,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDESEC, 8 * 0x20),
+	[1] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20), 0x20),
+	[2] = DEFINE_RES_IRQ(IRQ_IDE1),
 };
 
 static struct platform_device bast_device_ide1 = {
diff --git a/arch/arm/mach-s3c24xx/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c
index 4220cc6..ea2c4b0 100644
--- a/arch/arm/mach-s3c24xx/mach-amlm5900.c
+++ b/arch/arm/mach-s3c24xx/mach-amlm5900.c
@@ -65,13 +65,8 @@
 
 #include "common.h"
 
-static struct resource amlm5900_nor_resource = {
-		.start = 0x00000000,
-		.end   = 0x01000000 - 1,
-		.flags = IORESOURCE_MEM,
-};
-
-
+static struct resource amlm5900_nor_resource =
+			DEFINE_RES_MEM(0x00000000, SZ_16M);
 
 static struct mtd_partition amlm5900_mtd_partitions[] = {
 	{
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index 60c72c5..5a7d0c0 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -235,19 +235,9 @@
 };
 
 static struct resource anubis_ide0_resource[] = {
-	{
-		.start	= S3C2410_CS3,
-		.end	= S3C2410_CS3 + (8*32) - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= S3C2410_CS3 + (1<<26) + (6*32),
-		.end	= S3C2410_CS3 + (1<<26) + (7*32) - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_IDE0,
-		.end	= IRQ_IDE0,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S3C2410_CS3, 8 * 32),
+	[2] = DEFINE_RES_MEM(S3C2410_CS3 + (1 << 26) + (6 * 32), 32),
+	[3] = DEFINE_RES_IRQ(IRQ_IDE0),
 };
 
 static struct platform_device anubis_device_ide0 = {
@@ -262,19 +252,9 @@
 };
 
 static struct resource anubis_ide1_resource[] = {
-	{
-		.start	= S3C2410_CS4,
-		.end	= S3C2410_CS4 + (8*32) - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= S3C2410_CS4 + (1<<26) + (6*32),
-		.end	= S3C2410_CS4 + (1<<26) + (7*32) - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_IDE0,
-		.end	= IRQ_IDE0,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S3C2410_CS4, 8 * 32),
+	[1] = DEFINE_RES_MEM(S3C2410_CS4 + (1 << 26) + (6 * 32), 32),
+	[2] = DEFINE_RES_IRQ(IRQ_IDE0),
 };
 
 static struct platform_device anubis_device_ide1 = {
@@ -298,16 +278,8 @@
 };
 
 static struct resource anubis_asix_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5,
-		.end   = S3C2410_CS5 + (0x20 * 0x20) -1,
-		.flags = IORESOURCE_MEM
-	},
-	[1] = {
-		.start = IRQ_ASIX,
-		.end   = IRQ_ASIX,
-		.flags = IORESOURCE_IRQ
-	}
+	[0] = DEFINE_RES_MEM(S3C2410_CS5, 0x20 * 0x20),
+	[1] = DEFINE_RES_IRQ(IRQ_ASIX),
 };
 
 static struct platform_device anubis_device_asix = {
@@ -323,21 +295,9 @@
 /* SM501 */
 
 static struct resource anubis_sm501_resource[] = {
-	[0] = {
-		.start	= S3C2410_CS2,
-		.end	= S3C2410_CS2 + SZ_8M,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= S3C2410_CS2 + SZ_64M - SZ_2M,
-		.end	= S3C2410_CS2 + SZ_64M - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[2] = {
-		.start	= IRQ_EINT0,
-		.end	= IRQ_EINT0,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S3C2410_CS2, SZ_8M),
+	[1] = DEFINE_RES_MEM(S3C2410_CS2 + SZ_64M - SZ_2M, SZ_2M),
+	[2] = DEFINE_RES_IRQ(IRQ_EINT0),
 };
 
 static struct sm501_initdata anubis_sm501_initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
index d7ae49c..7a05abf 100644
--- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -118,21 +118,10 @@
 /* DM9000AEP 10/100 ethernet controller */
 
 static struct resource at2440evb_dm9k_resource[] = {
-	[0] = {
-		.start = S3C2410_CS3,
-		.end   = S3C2410_CS3 + 3,
-		.flags = IORESOURCE_MEM
-	},
-	[1] = {
-		.start = S3C2410_CS3 + 4,
-		.end   = S3C2410_CS3 + 7,
-		.flags = IORESOURCE_MEM
-	},
-	[2] = {
-		.start = IRQ_EINT7,
-		.end   = IRQ_EINT7,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
-	}
+	[0] = DEFINE_RES_MEM(S3C2410_CS3, 4),
+	[1] = DEFINE_RES_MEM(S3C2410_CS3 + 4, 4),
+	[2] = DEFINE_RES_NAMED(IRQ_EINT7, 1, NULL, IORESOURCE_IRQ \
+					| IORESOURCE_IRQ_HIGHEDGE),
 };
 
 static struct dm9000_plat_data at2440evb_dm9k_pdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index 53219c0..1cf1720 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -310,22 +310,10 @@
 /* DM9000 */
 
 static struct resource bast_dm9k_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + BAST_PA_DM9000,
-		.end   = S3C2410_CS5 + BAST_PA_DM9000 + 3,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = S3C2410_CS5 + BAST_PA_DM9000 + 0x40,
-		.end   = S3C2410_CS5 + BAST_PA_DM9000 + 0x40 + 0x3f,
-		.flags = IORESOURCE_MEM,
-	},
-	[2] = {
-		.start = IRQ_DM9000,
-		.end   = IRQ_DM9000,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-	}
-
+	[0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000, 4),
+	[1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000 + 0x40, 0x40),
+	[2] = DEFINE_RES_NAMED(IRQ_DM9000 , 1, NULL, IORESOURCE_IRQ \
+					| IORESOURCE_IRQ_HIGHLEVEL),
 };
 
 /* for the moment we limit ourselves to 16bit IO until some
@@ -400,21 +388,9 @@
 };
 
 static struct resource bast_asix_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + BAST_PA_ASIXNET,
-		.end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20) - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
-		.end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
-		.flags = IORESOURCE_MEM,
-	},
-	[2] = {
-		.start = IRQ_ASIX,
-		.end   = IRQ_ASIX,
-		.flags = IORESOURCE_IRQ
-	}
+	[0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET, 0x18 * 0x20),
+	[1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20), 1),
+	[2] = DEFINE_RES_IRQ(IRQ_ASIX),
 };
 
 static struct platform_device bast_device_asix = {
@@ -430,11 +406,8 @@
 /* Asix AX88796 10/100 ethernet controller parallel port */
 
 static struct resource bast_asixpp_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20),
-		.end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1b * 0x20) - 1,
-		.flags = IORESOURCE_MEM,
-	}
+	[0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20), \
+					0x30 * 0x20),
 };
 
 static struct platform_device bast_device_axpp = {
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
index ba5d853..0f29f64 100644
--- a/arch/arm/mach-s3c24xx/mach-gta02.c
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -387,11 +387,8 @@
 	.width		= 2,
 };
 
-static struct resource gta02_nor_flash_resource = {
-	.start		= GTA02_FLASH_BASE,
-	.end		= GTA02_FLASH_BASE + GTA02_FLASH_SIZE - 1,
-	.flags		= IORESOURCE_MEM,
-};
+static struct resource gta02_nor_flash_resource =
+	DEFINE_RES_MEM(GTA02_FLASH_BASE, GTA02_FLASH_SIZE);
 
 static struct platform_device gta02_nor_flash = {
 	.name		= "physmap-flash",
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
index 6b21ba1..bb8d008 100644
--- a/arch/arm/mach-s3c24xx/mach-h1940.c
+++ b/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -253,13 +253,8 @@
 };
 
 static struct resource power_supply_resources[] = {
-	[0] = {
-			.name	= "ac",
-			.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
-					  IORESOURCE_IRQ_HIGHEDGE,
-			.start	= IRQ_EINT2,
-			.end	= IRQ_EINT2,
-	},
+	[0] = DEFINE_RES_NAMED(IRQ_EINT2, 1, "ac", IORESOURCE_IRQ \
+			| IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE),
 };
 
 static struct platform_device power_supply = {
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index 5d66fb2..f092b18 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -292,21 +292,10 @@
 /* DM9000AEP 10/100 ethernet controller */
 
 static struct resource mini2440_dm9k_resource[] = {
-	[0] = {
-		.start = MACH_MINI2440_DM9K_BASE,
-		.end   = MACH_MINI2440_DM9K_BASE + 3,
-		.flags = IORESOURCE_MEM
-	},
-	[1] = {
-		.start = MACH_MINI2440_DM9K_BASE + 4,
-		.end   = MACH_MINI2440_DM9K_BASE + 7,
-		.flags = IORESOURCE_MEM
-	},
-	[2] = {
-		.start = IRQ_EINT7,
-		.end   = IRQ_EINT7,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
-	}
+	[0] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE, 4),
+	[1] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE + 4, 4),
+	[2] = DEFINE_RES_NAMED(IRQ_EINT7, 1, NULL, IORESOURCE_IRQ \
+						| IORESOURCE_IRQ_HIGHEDGE),
 };
 
 /*
diff --git a/arch/arm/mach-s3c24xx/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c
index 5198e3e..5c05ba1 100644
--- a/arch/arm/mach-s3c24xx/mach-nexcoder.c
+++ b/arch/arm/mach-s3c24xx/mach-nexcoder.c
@@ -84,11 +84,7 @@
 /* NOR Flash on NexVision NexCoder 2440 board */
 
 static struct resource nexcoder_nor_resource[] = {
-	[0] = {
-		.start = S3C2410_CS0,
-		.end   = S3C2410_CS0 + (8*1024*1024) - 1,
-		.flags = IORESOURCE_MEM,
-	}
+	[0] = DEFINE_RES_MEM(S3C2410_CS0, SZ_8M),
 };
 
 static struct map_info nexcoder_nor_map = {
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index c5daeb6..95d0772 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -244,16 +244,8 @@
 /* PCMCIA control and configuration */
 
 static struct resource osiris_pcmcia_resource[] = {
-	[0] = {
-		.start	= 0x0f000000,
-		.end	= 0x0f100000,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= 0x0c000000,
-		.end	= 0x0c100000,
-		.flags	= IORESOURCE_MEM,
-	}
+	[0] = DEFINE_RES_MEM(0x0f000000, SZ_1M),
+	[1] = DEFINE_RES_MEM(0x0c000000, SZ_1M),
 };
 
 static struct platform_device osiris_pcmcia = {
diff --git a/arch/arm/mach-s3c24xx/mach-otom.c b/arch/arm/mach-s3c24xx/mach-otom.c
index 5f1e0ee..bc4b6ef 100644
--- a/arch/arm/mach-s3c24xx/mach-otom.c
+++ b/arch/arm/mach-s3c24xx/mach-otom.c
@@ -77,11 +77,7 @@
 /* NOR Flash on NexVision OTOM board */
 
 static struct resource otom_nor_resource[] = {
-	[0] = {
-		.start = S3C2410_CS0,
-		.end   = S3C2410_CS0 + (4*1024*1024) - 1,
-		.flags = IORESOURCE_MEM,
-	}
+	[0] = DEFINE_RES_MEM(S3C2410_CS0, SZ_4M),
 };
 
 static struct platform_device otom_device_nor = {
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 91c16d9..b868ddd 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -180,16 +180,8 @@
 /* CS8900 */
 
 static struct resource qt2410_cs89x0_resources[] = {
-	[0] = {
-		.start	= 0x19000000,
-		.end	= 0x19000000 + 16,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_EINT9,
-		.end	= IRQ_EINT9,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(0x19000000, 17),
+	[1] = DEFINE_RES_IRQ(IRQ_EINT9),
 };
 
 static struct platform_device qt2410_cs89x0 = {
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index 200debb..a6762aa 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -152,13 +152,8 @@
 };
 
 static struct resource power_supply_resources[] = {
-	[0] = {
-			.name	= "ac",
-			.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
-					  IORESOURCE_IRQ_HIGHEDGE,
-			.start	= IRQ_EINT2,
-			.end	= IRQ_EINT2,
-	},
+	[0] = DEFINE_RES_NAMED(IRQ_EINT2, 1, "ac", IORESOURCE_IRQ \
+			| IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE),
 };
 
 static struct platform_device power_supply = {
diff --git a/arch/arm/mach-s3c24xx/mach-tct_hammer.c b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
index 1114666f..fe99028 100644
--- a/arch/arm/mach-s3c24xx/mach-tct_hammer.c
+++ b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
@@ -56,11 +56,8 @@
 
 #include "common.h"
 
-static struct resource tct_hammer_nor_resource = {
-		.start = 0x00000000,
-		.end   = 0x01000000 - 1,
-		.flags = IORESOURCE_MEM,
-};
+static struct resource tct_hammer_nor_resource =
+			DEFINE_RES_MEM(0x00000000, SZ_16M);
 
 static struct mtd_partition tct_hammer_mtd_partitions[] = {
 	{
diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c
index 87608d4..bd5f189 100644
--- a/arch/arm/mach-s3c24xx/mach-vr1000.c
+++ b/arch/arm/mach-s3c24xx/mach-vr1000.c
@@ -187,40 +187,17 @@
 /* DM9000 ethernet devices */
 
 static struct resource vr1000_dm9k0_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + VR1000_PA_DM9000,
-		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 3,
-		.flags = IORESOURCE_MEM
-	},
-	[1] = {
-		.start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x40,
-		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x7f,
-		.flags = IORESOURCE_MEM
-	},
-	[2] = {
-		.start = IRQ_VR1000_DM9000A,
-		.end   = IRQ_VR1000_DM9000A,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-	}
-
+	[0] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000, 4),
+	[1] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0x40, 0x40),
+	[2] = DEFINE_RES_NAMED(IRQ_VR1000_DM9000A, 1, NULL, IORESOURCE_IRQ \
+						| IORESOURCE_IRQ_HIGHLEVEL),
 };
 
 static struct resource vr1000_dm9k1_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x80,
-		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x83,
-		.flags = IORESOURCE_MEM
-	},
-	[1] = {
-		.start = S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0,
-		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0xFF,
-		.flags = IORESOURCE_MEM
-	},
-	[2] = {
-		.start = IRQ_VR1000_DM9000N,
-		.end   = IRQ_VR1000_DM9000N,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-	}
+	[0] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0x80, 4),
+	[1] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0, 0x40),
+	[2] = DEFINE_RES_NAMED(IRQ_VR1000_DM9000N, 1, NULL, IORESOURCE_IRQ \
+						| IORESOURCE_IRQ_HIGHLEVEL),
 };
 
 /* for the moment we limit ourselves to 16bit IO until some
diff --git a/arch/arm/mach-s3c24xx/simtec-nor.c b/arch/arm/mach-s3c24xx/simtec-nor.c
index b9d6d4f..029744fc 100644
--- a/arch/arm/mach-s3c24xx/simtec-nor.c
+++ b/arch/arm/mach-s3c24xx/simtec-nor.c
@@ -55,11 +55,7 @@
 };
 
 static struct resource simtec_nor_resource[] = {
-	[0] = {
-		.start = S3C2410_CS1 + 0x4000000,
-		.end   = S3C2410_CS1 + 0x4000000 + SZ_8M - 1,
-		.flags = IORESOURCE_MEM,
-	}
+	[0] = DEFINE_RES_MEM(S3C2410_CS1 + 0x4000000, SZ_8M),
 };
 
 static struct platform_device simtec_device_nor = {
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index 82c0915..06ca1cd 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -210,7 +210,7 @@
 	  and audio daughtercard for the Samsung SMDK6410 reference
 	  platform.  Enabling this option will build support for this
 	  module into the kernel.  The presence of the module will be
-	  detected at runtime so the the resulting kernel can be used
+	  detected at runtime so the resulting kernel can be used
 	  with or without the 1190-EV1 fitted.
 
 config SMDK6410_WM1192_EV1
@@ -226,7 +226,7 @@
 	  daughtercard for the Samsung SMDK6410 reference platform.
 	  Enabling this option will build support for this module into
 	  the kernel.  The presence of the daughtercard will be
-	  detected at runtime so the the resulting kernel can be used
+	  detected at runtime so the resulting kernel can be used
 	  with or without the 1192-EV1 fitted.
 
 config MACH_NCP
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index 93470b1..124fd5d 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -57,21 +57,9 @@
 }
 
 static struct resource s3c64xx_iis0_resource[] = {
-	[0] = {
-		.start = S3C64XX_PA_IIS0,
-		.end   = S3C64XX_PA_IIS0 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_I2S0_OUT,
-		.end   = DMACH_I2S0_OUT,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_I2S0_IN,
-		.end   = DMACH_I2S0_IN,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S0_OUT),
+	[2] = DEFINE_RES_DMA(DMACH_I2S0_IN),
 };
 
 static struct s3c_audio_pdata i2sv3_pdata = {
@@ -95,21 +83,9 @@
 EXPORT_SYMBOL(s3c64xx_device_iis0);
 
 static struct resource s3c64xx_iis1_resource[] = {
-	[0] = {
-		.start = S3C64XX_PA_IIS1,
-		.end   = S3C64XX_PA_IIS1 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_I2S1_OUT,
-		.end   = DMACH_I2S1_OUT,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_I2S1_IN,
-		.end   = DMACH_I2S1_IN,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S1_OUT),
+	[2] = DEFINE_RES_DMA(DMACH_I2S1_IN),
 };
 
 struct platform_device s3c64xx_device_iis1 = {
@@ -124,21 +100,9 @@
 EXPORT_SYMBOL(s3c64xx_device_iis1);
 
 static struct resource s3c64xx_iisv4_resource[] = {
-	[0] = {
-		.start = S3C64XX_PA_IISV4,
-		.end   = S3C64XX_PA_IISV4 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_HSI_I2SV40_TX,
-		.end   = DMACH_HSI_I2SV40_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_HSI_I2SV40_RX,
-		.end   = DMACH_HSI_I2SV40_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_TX),
+	[2] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_RX),
 };
 
 static struct s3c_audio_pdata i2sv4_pdata = {
@@ -187,21 +151,9 @@
 }
 
 static struct resource s3c64xx_pcm0_resource[] = {
-	[0] = {
-		.start = S3C64XX_PA_PCM0,
-		.end   = S3C64XX_PA_PCM0 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_PCM0_TX,
-		.end   = DMACH_PCM0_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_PCM0_RX,
-		.end   = DMACH_PCM0_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm0_pdata = {
@@ -220,21 +172,9 @@
 EXPORT_SYMBOL(s3c64xx_device_pcm0);
 
 static struct resource s3c64xx_pcm1_resource[] = {
-	[0] = {
-		.start = S3C64XX_PA_PCM1,
-		.end   = S3C64XX_PA_PCM1 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_PCM1_TX,
-		.end   = DMACH_PCM1_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_PCM1_RX,
-		.end   = DMACH_PCM1_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm1_pdata = {
@@ -265,31 +205,11 @@
 }
 
 static struct resource s3c64xx_ac97_resource[] = {
-	[0] = {
-		.start = S3C64XX_PA_AC97,
-		.end   = S3C64XX_PA_AC97 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_AC97_PCMOUT,
-		.end   = DMACH_AC97_PCMOUT,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_AC97_PCMIN,
-		.end   = DMACH_AC97_PCMIN,
-		.flags = IORESOURCE_DMA,
-	},
-	[3] = {
-		.start = DMACH_AC97_MICIN,
-		.end   = DMACH_AC97_MICIN,
-		.flags = IORESOURCE_DMA,
-	},
-	[4] = {
-		.start = IRQ_AC97,
-		.end   = IRQ_AC97,
-		.flags = IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
+	[2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
+	[3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
+	[4] = DEFINE_RES_IRQ(IRQ_AC97),
 };
 
 static struct s3c_audio_pdata s3c_ac97_pdata;
diff --git a/arch/arm/mach-s3c64xx/dev-uart.c b/arch/arm/mach-s3c64xx/dev-uart.c
index c681b99..46e18d7 100644
--- a/arch/arm/mach-s3c64xx/dev-uart.c
+++ b/arch/arm/mach-s3c64xx/dev-uart.c
@@ -31,55 +31,23 @@
 /* 64xx uarts are closer together */
 
 static struct resource s3c64xx_uart0_resource[] = {
-	[0] = {
-		.start	= S3C_PA_UART0,
-		.end	= S3C_PA_UART0 + 0x100,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_UART0,
-		.end	= IRQ_UART0,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S3C_PA_UART0, SZ_256),
+	[1] = DEFINE_RES_IRQ(IRQ_UART0),
 };
 
 static struct resource s3c64xx_uart1_resource[] = {
-	[0] = {
-		.start = S3C_PA_UART1,
-		.end   = S3C_PA_UART1 + 0x100,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_UART1,
-		.end	= IRQ_UART1,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S3C_PA_UART1, SZ_256),
+	[1] = DEFINE_RES_IRQ(IRQ_UART1),
 };
 
 static struct resource s3c6xx_uart2_resource[] = {
-	[0] = {
-		.start = S3C_PA_UART2,
-		.end   = S3C_PA_UART2 + 0x100,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_UART2,
-		.end	= IRQ_UART2,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S3C_PA_UART2, SZ_256),
+	[1] = DEFINE_RES_IRQ(IRQ_UART2),
 };
 
 static struct resource s3c64xx_uart3_resource[] = {
-	[0] = {
-		.start = S3C_PA_UART3,
-		.end   = S3C_PA_UART3 + 0x100,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_UART3,
-		.end	= IRQ_UART3,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S3C_PA_UART3, SZ_256),
+	[1] = DEFINE_RES_IRQ(IRQ_UART3),
 };
 
 
diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c
index b86f277..f252691 100644
--- a/arch/arm/mach-s3c64xx/mach-anw6410.c
+++ b/arch/arm/mach-s3c64xx/mach-anw6410.c
@@ -165,21 +165,10 @@
 }
 
 static struct resource anw6410_dm9000_resource[] = {
-	[0] = {
-		.start = ANW6410_PA_DM9000,
-		.end   = ANW6410_PA_DM9000 + 3,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = ANW6410_PA_DM9000 + 4,
-		.end   = ANW6410_PA_DM9000 + 4 + 500,
-		.flags = IORESOURCE_MEM,
-	},
-	[2] = {
-		.start = IRQ_EINT(15),
-		.end   = IRQ_EINT(15),
-		.flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
-	},
+	[0] = DEFINE_RES_MEM(ANW6410_PA_DM9000, 4),
+	[1] = DEFINE_RES_MEM(ANW6410_PA_DM9000 + 4, 501),
+	[2] = DEFINE_RES_NAMED(IRQ_EINT(15), 1, NULL, IORESOURCE_IRQ \
+					| IRQF_TRIGGER_HIGH),
 };
 
 static struct dm9000_plat_data anw6410_dm9000_pdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index e20bf58..aa1137f 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -31,6 +31,7 @@
 #include <linux/spi/spi.h>
 
 #include <linux/i2c/pca953x.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #include <video/platform_lcd.h>
 
@@ -61,7 +62,6 @@
 #include <plat/sdhci.h>
 #include <plat/gpio-cfg.h>
 #include <plat/s3c64xx-spi.h>
-#include <plat/udc-hs.h>
 
 #include <plat/keypad.h>
 #include <plat/clock.h>
@@ -232,21 +232,10 @@
 };
 
 static struct resource crag6410_dm9k_resource[] = {
-	[0] = {
-		.start	= S3C64XX_PA_XM0CSN5,
-		.end	= S3C64XX_PA_XM0CSN5 + 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= S3C64XX_PA_XM0CSN5 + (1 << 8),
-		.end	= S3C64XX_PA_XM0CSN5 + (1 << 8) + 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[2] = {
-		.start	= S3C_EINT(17),
-		.end	= S3C_EINT(17),
-		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-	},
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN5, 2),
+	[1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN5 + (1 << 8), 2),
+	[2] = DEFINE_RES_NAMED(S3C_EINT(17), 1, NULL, IORESOURCE_IRQ \
+				| IORESOURCE_IRQ_HIGHLEVEL),
 };
 
 static struct dm9000_plat_data mini6410_dm9k_pdata = {
@@ -262,12 +251,7 @@
 };
 
 static struct resource crag6410_mmgpio_resource[] = {
-	[0] = {
-		.name	= "dat",
-		.start	= S3C64XX_PA_XM0CSN4 + 1,
-		.end	= S3C64XX_PA_XM0CSN4 + 1,
-		.flags	= IORESOURCE_MEM,
-	},
+	[0] = DEFINE_RES_MEM_NAMED(S3C64XX_PA_XM0CSN4, 1, "dat"),
 };
 
 static struct platform_device crag6410_mmgpio = {
@@ -306,6 +290,24 @@
 	REGULATOR_SUPPLY("SPKVDD2", "1-001a"),
 	REGULATOR_SUPPLY("SPKVDDL", "1-001a"),
 	REGULATOR_SUPPLY("SPKVDDR", "1-001a"),
+
+	REGULATOR_SUPPLY("DC1VDD", "0-0034"),
+	REGULATOR_SUPPLY("DC2VDD", "0-0034"),
+	REGULATOR_SUPPLY("DC3VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO1VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO2VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO4VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO5VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO6VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO7VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO8VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO9VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO10VDD", "0-0034"),
+	REGULATOR_SUPPLY("LDO11VDD", "0-0034"),
+
+	REGULATOR_SUPPLY("DC1VDD", "1-0034"),
+	REGULATOR_SUPPLY("DC2VDD", "1-0034"),
+	REGULATOR_SUPPLY("DC3VDD", "1-0034"),
 };
 
 static struct regulator_init_data wallvdd_data = {
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index c34c2ab..b2166d4 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -85,21 +85,10 @@
 /* DM9000AEP 10/100 ethernet controller */
 
 static struct resource mini6410_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 | IORESOURCE_IRQ_HIGHLEVEL
-	}
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, 2),
+	[1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1 + 4, 2),
+	[2] = DEFINE_RES_NAMED(S3C_EINT(7), 1, NULL, IORESOURCE_IRQ \
+					| IORESOURCE_IRQ_HIGHLEVEL),
 };
 
 static struct dm9000_plat_data mini6410_dm9k_pdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index be2a9a2..5c08266 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -86,21 +86,10 @@
 /* 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 | IORESOURCE_IRQ_HIGHLEVEL
-	}
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, 2),
+	[1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1 + 4, 2),
+	[2] = DEFINE_RES_NAMED(S3C_EINT(7), 1, NULL, IORESOURCE_IRQ \
+					| IORESOURCE_IRQ_HIGHLEVEL),
 };
 
 static struct dm9000_plat_data real6410_dm9k_pdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index ce745e1..ceeb1de 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -18,6 +18,7 @@
 #include <linux/serial_core.h>
 #include <linux/spi/spi_gpio.h>
 #include <linux/usb/gpio_vbus.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
@@ -33,7 +34,6 @@
 #include <plat/gpio-cfg.h>
 #include <plat/hwmon.h>
 #include <plat/regs-serial.h>
-#include <plat/udc-hs.h>
 #include <plat/usb-control.h>
 #include <plat/sdhci.h>
 #include <plat/ts.h>
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index d55bc96..7da044f 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -30,6 +30,7 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/pwm_backlight.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #ifdef CONFIG_SMDK6410_WM1190_EV1
 #include <linux/mfd/wm8350/core.h>
@@ -72,7 +73,6 @@
 #include <plat/keypad.h>
 #include <plat/backlight.h>
 #include <plat/regs-fb-v4.h>
-#include <plat/udc-hs.h>
 
 #include "common.h"
 
@@ -182,16 +182,9 @@
  */
 
 static struct resource smdk6410_smsc911x_resources[] = {
-	[0] = {
-		.start = S3C64XX_PA_XM0CSN1,
-		.end   = S3C64XX_PA_XM0CSN1 + SZ_64K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = S3C_EINT(10),
-		.end   = S3C_EINT(10),
-		.flags = IORESOURCE_IRQ | IRQ_TYPE_LEVEL_LOW,
-	},
+	[0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, SZ_64K),
+	[1] = DEFINE_RES_NAMED(S3C_EINT(10), 1, NULL, IORESOURCE_IRQ \
+					| IRQ_TYPE_LEVEL_LOW),
 };
 
 static struct smsc911x_platform_config smdk6410_smsc911x_pdata = {
diff --git a/arch/arm/mach-s5p64x0/dev-audio.c b/arch/arm/mach-s5p64x0/dev-audio.c
index 35f1f22..91113dd 100644
--- a/arch/arm/mach-s5p64x0/dev-audio.c
+++ b/arch/arm/mach-s5p64x0/dev-audio.c
@@ -51,21 +51,9 @@
 };
 
 static struct resource s5p64x0_i2s0_resource[] = {
-	[0] = {
-		.start	= S5P64X0_PA_I2S,
-		.end	= S5P64X0_PA_I2S + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_I2S0_TX,
-		.end	= DMACH_I2S0_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_I2S0_RX,
-		.end	= DMACH_I2S0_RX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5P64X0_PA_I2S, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
 };
 
 struct platform_device s5p6440_device_iis = {
@@ -130,21 +118,9 @@
 };
 
 static struct resource s5p6450_i2s1_resource[] = {
-	[0] = {
-		.start	= S5P6450_PA_I2S1,
-		.end	= S5P6450_PA_I2S1 + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_I2S1_TX,
-		.end	= DMACH_I2S1_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_I2S1_RX,
-		.end	= DMACH_I2S1_RX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5P6450_PA_I2S1, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
 };
 
 struct platform_device s5p6450_device_iis1 = {
@@ -158,21 +134,9 @@
 };
 
 static struct resource s5p6450_i2s2_resource[] = {
-	[0] = {
-		.start	= S5P6450_PA_I2S2,
-		.end	= S5P6450_PA_I2S2 + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_I2S2_TX,
-		.end	= DMACH_I2S2_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_I2S2_RX,
-		.end	= DMACH_I2S2_RX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5P6450_PA_I2S2, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
 };
 
 struct platform_device s5p6450_device_iis2 = {
@@ -208,21 +172,9 @@
 };
 
 static struct resource s5p6440_pcm0_resource[] = {
-	[0] = {
-		.start	= S5P64X0_PA_PCM,
-		.end	= S5P64X0_PA_PCM + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_PCM0_TX,
-		.end	= DMACH_PCM0_TX,
-		.flags	= IORESOURCE_DMA,
-	},
-	[2] = {
-		.start	= DMACH_PCM0_RX,
-		.end	= DMACH_PCM0_RX,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5P64X0_PA_PCM, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
 };
 
 struct platform_device s5p6440_device_pcm = {
diff --git a/arch/arm/mach-s5pc100/dev-audio.c b/arch/arm/mach-s5pc100/dev-audio.c
index ab2d271..9d4bde3 100644
--- a/arch/arm/mach-s5pc100/dev-audio.c
+++ b/arch/arm/mach-s5pc100/dev-audio.c
@@ -56,26 +56,10 @@
 };
 
 static struct resource s5pc100_iis0_resource[] = {
-	[0] = {
-		.start = S5PC100_PA_I2S0,
-		.end   = S5PC100_PA_I2S0 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_I2S0_TX,
-		.end   = DMACH_I2S0_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_I2S0_RX,
-		.end   = DMACH_I2S0_RX,
-		.flags = IORESOURCE_DMA,
-	},
-	[3] = {
-		.start = DMACH_I2S0S_TX,
-		.end = DMACH_I2S0S_TX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PC100_PA_I2S0, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
+	[3] = DEFINE_RES_DMA(DMACH_I2S0S_TX),
 };
 
 struct platform_device s5pc100_device_iis0 = {
@@ -103,21 +87,9 @@
 };
 
 static struct resource s5pc100_iis1_resource[] = {
-	[0] = {
-		.start = S5PC100_PA_I2S1,
-		.end   = S5PC100_PA_I2S1 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_I2S1_TX,
-		.end   = DMACH_I2S1_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_I2S1_RX,
-		.end   = DMACH_I2S1_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PC100_PA_I2S1, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
 };
 
 struct platform_device s5pc100_device_iis1 = {
@@ -131,21 +103,9 @@
 };
 
 static struct resource s5pc100_iis2_resource[] = {
-	[0] = {
-		.start = S5PC100_PA_I2S2,
-		.end   = S5PC100_PA_I2S2 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_I2S2_TX,
-		.end   = DMACH_I2S2_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_I2S2_RX,
-		.end   = DMACH_I2S2_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PC100_PA_I2S2, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
 };
 
 struct platform_device s5pc100_device_iis2 = {
@@ -184,21 +144,9 @@
 };
 
 static struct resource s5pc100_pcm0_resource[] = {
-	[0] = {
-		.start = S5PC100_PA_PCM0,
-		.end   = S5PC100_PA_PCM0 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_PCM0_TX,
-		.end   = DMACH_PCM0_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_PCM0_RX,
-		.end   = DMACH_PCM0_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PC100_PA_PCM0, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
 };
 
 struct platform_device s5pc100_device_pcm0 = {
@@ -212,21 +160,9 @@
 };
 
 static struct resource s5pc100_pcm1_resource[] = {
-	[0] = {
-		.start = S5PC100_PA_PCM1,
-		.end   = S5PC100_PA_PCM1 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_PCM1_TX,
-		.end   = DMACH_PCM1_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_PCM1_RX,
-		.end   = DMACH_PCM1_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PC100_PA_PCM1, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
 };
 
 struct platform_device s5pc100_device_pcm1 = {
@@ -247,31 +183,11 @@
 }
 
 static struct resource s5pc100_ac97_resource[] = {
-	[0] = {
-		.start = S5PC100_PA_AC97,
-		.end   = S5PC100_PA_AC97 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_AC97_PCMOUT,
-		.end   = DMACH_AC97_PCMOUT,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_AC97_PCMIN,
-		.end   = DMACH_AC97_PCMIN,
-		.flags = IORESOURCE_DMA,
-	},
-	[3] = {
-		.start = DMACH_AC97_MICIN,
-		.end   = DMACH_AC97_MICIN,
-		.flags = IORESOURCE_DMA,
-	},
-	[4] = {
-		.start = IRQ_AC97,
-		.end   = IRQ_AC97,
-		.flags = IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S5PC100_PA_AC97, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
+	[2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
+	[3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
+	[4] = DEFINE_RES_IRQ(IRQ_AC97),
 };
 
 static struct s3c_audio_pdata s3c_ac97_pdata = {
@@ -308,16 +224,8 @@
 }
 
 static struct resource s5pc100_spdif_resource[] = {
-	[0] = {
-		.start	= S5PC100_PA_SPDIF,
-		.end	= S5PC100_PA_SPDIF + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_SPDIF,
-		.end	= DMACH_SPDIF,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PC100_PA_SPDIF, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_SPDIF),
 };
 
 static struct s3c_audio_pdata s5p_spdif_pdata = {
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 29594fc..88e983b 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -85,6 +85,7 @@
 	select S5P_DEV_ONENAND
 	select S5PV210_SETUP_FB_24BPP
 	select S5PV210_SETUP_SDHCI
+	select S5PV210_SETUP_USB_PHY
 	help
 	  Machine support for the Samsung Aquila target based on S5PC110 SoC
 
diff --git a/arch/arm/mach-s5pv210/dev-audio.c b/arch/arm/mach-s5pv210/dev-audio.c
index 63f5d82..8367749 100644
--- a/arch/arm/mach-s5pv210/dev-audio.c
+++ b/arch/arm/mach-s5pv210/dev-audio.c
@@ -59,26 +59,10 @@
 };
 
 static struct resource s5pv210_iis0_resource[] = {
-	[0] = {
-		.start = S5PV210_PA_IIS0,
-		.end   = S5PV210_PA_IIS0 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_I2S0_TX,
-		.end   = DMACH_I2S0_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_I2S0_RX,
-		.end   = DMACH_I2S0_RX,
-		.flags = IORESOURCE_DMA,
-	},
-	[3] = {
-		.start = DMACH_I2S0S_TX,
-		.end = DMACH_I2S0S_TX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PV210_PA_IIS0, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
+	[3] = DEFINE_RES_DMA(DMACH_I2S0S_TX),
 };
 
 struct platform_device s5pv210_device_iis0 = {
@@ -106,21 +90,9 @@
 };
 
 static struct resource s5pv210_iis1_resource[] = {
-	[0] = {
-		.start = S5PV210_PA_IIS1,
-		.end   = S5PV210_PA_IIS1 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_I2S1_TX,
-		.end   = DMACH_I2S1_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_I2S1_RX,
-		.end   = DMACH_I2S1_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PV210_PA_IIS1, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
 };
 
 struct platform_device s5pv210_device_iis1 = {
@@ -134,21 +106,9 @@
 };
 
 static struct resource s5pv210_iis2_resource[] = {
-	[0] = {
-		.start = S5PV210_PA_IIS2,
-		.end   = S5PV210_PA_IIS2 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_I2S2_TX,
-		.end   = DMACH_I2S2_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_I2S2_RX,
-		.end   = DMACH_I2S2_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PV210_PA_IIS2, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+	[2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
 };
 
 struct platform_device s5pv210_device_iis2 = {
@@ -188,21 +148,9 @@
 };
 
 static struct resource s5pv210_pcm0_resource[] = {
-	[0] = {
-		.start = S5PV210_PA_PCM0,
-		.end   = S5PV210_PA_PCM0 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_PCM0_TX,
-		.end   = DMACH_PCM0_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_PCM0_RX,
-		.end   = DMACH_PCM0_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PV210_PA_PCM0, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
 };
 
 struct platform_device s5pv210_device_pcm0 = {
@@ -216,21 +164,9 @@
 };
 
 static struct resource s5pv210_pcm1_resource[] = {
-	[0] = {
-		.start = S5PV210_PA_PCM1,
-		.end   = S5PV210_PA_PCM1 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_PCM1_TX,
-		.end   = DMACH_PCM1_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_PCM1_RX,
-		.end   = DMACH_PCM1_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PV210_PA_PCM1, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
 };
 
 struct platform_device s5pv210_device_pcm1 = {
@@ -244,21 +180,9 @@
 };
 
 static struct resource s5pv210_pcm2_resource[] = {
-	[0] = {
-		.start = S5PV210_PA_PCM2,
-		.end   = S5PV210_PA_PCM2 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_PCM2_TX,
-		.end   = DMACH_PCM2_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_PCM2_RX,
-		.end   = DMACH_PCM2_RX,
-		.flags = IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PV210_PA_PCM2, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_PCM2_TX),
+	[2] = DEFINE_RES_DMA(DMACH_PCM2_RX),
 };
 
 struct platform_device s5pv210_device_pcm2 = {
@@ -279,31 +203,11 @@
 }
 
 static struct resource s5pv210_ac97_resource[] = {
-	[0] = {
-		.start = S5PV210_PA_AC97,
-		.end   = S5PV210_PA_AC97 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_AC97_PCMOUT,
-		.end   = DMACH_AC97_PCMOUT,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_AC97_PCMIN,
-		.end   = DMACH_AC97_PCMIN,
-		.flags = IORESOURCE_DMA,
-	},
-	[3] = {
-		.start = DMACH_AC97_MICIN,
-		.end   = DMACH_AC97_MICIN,
-		.flags = IORESOURCE_DMA,
-	},
-	[4] = {
-		.start = IRQ_AC97,
-		.end   = IRQ_AC97,
-		.flags = IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S5PV210_PA_AC97, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
+	[2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
+	[3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
+	[4] = DEFINE_RES_IRQ(IRQ_AC97),
 };
 
 static struct s3c_audio_pdata s3c_ac97_pdata = {
@@ -334,16 +238,8 @@
 }
 
 static struct resource s5pv210_spdif_resource[] = {
-	[0] = {
-		.start	= S5PV210_PA_SPDIF,
-		.end	= S5PV210_PA_SPDIF + 0x100 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= DMACH_SPDIF,
-		.end	= DMACH_SPDIF,
-		.flags	= IORESOURCE_DMA,
-	},
+	[0] = DEFINE_RES_MEM(S5PV210_PA_SPDIF, SZ_256),
+	[1] = DEFINE_RES_DMA(DMACH_SPDIF),
 };
 
 static struct s3c_audio_pdata samsung_spdif_pdata = {
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 3239566..f20a97c 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -27,6 +27,7 @@
 #include <linux/gpio.h>
 #include <linux/mmc/host.h>
 #include <linux/interrupt.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #include <asm/hardware/vic.h>
 #include <asm/mach/arch.h>
@@ -278,6 +279,9 @@
 	i2c2_devs[0].irq = gpio_to_irq(gpio);
 }
 
+/* USB OTG */
+static struct s3c_hsotg_plat goni_hsotg_pdata;
+
 static void goni_camera_init(void)
 {
 	s5pv210_fimc_setup_gpio(S5P_CAMPORT_A);
@@ -941,6 +945,8 @@
 	s3c_set_platdata(&goni_fimc_md_platdata, sizeof(goni_fimc_md_platdata),
 			 &s5p_device_fimc_md);
 
+	s3c_hsotg_set_platdata(&goni_hsotg_pdata);
+
 	goni_camera_init();
 
 	/* SPI */
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index 91d4ad8..fa1b612 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -119,21 +119,10 @@
 };
 
 static struct resource smdkv210_dm9000_resources[] = {
-	[0] = {
-		.start	= S5PV210_PA_SROM_BANK5,
-		.end	= S5PV210_PA_SROM_BANK5,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= S5PV210_PA_SROM_BANK5 + 2,
-		.end	= S5PV210_PA_SROM_BANK5 + 2,
-		.flags	= IORESOURCE_MEM,
-	},
-	[2] = {
-		.start	= IRQ_EINT(9),
-		.end	= IRQ_EINT(9),
-		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-	},
+	[0] = DEFINE_RES_MEM(S5PV210_PA_SROM_BANK5, 1),
+	[1] = DEFINE_RES_MEM(S5PV210_PA_SROM_BANK5 + 2, 1),
+	[2] = DEFINE_RES_NAMED(IRQ_EINT(9), 1, NULL, IORESOURCE_IRQ \
+				| IORESOURCE_IRQ_HIGHLEVEL),
 };
 
 static struct dm9000_plat_data smdkv210_dm9000_platdata = {
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 34560ca..f31383c 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -41,6 +41,12 @@
 	select ARM_GIC
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 
+config ARCH_EMEV2
+	bool "Emma Mobile EV2"
+	select CPU_V7
+	select ARM_GIC
+	select ARCH_WANT_OPTIONAL_GPIOLIB
+
 comment "SH-Mobile Board Type"
 
 config MACH_G3EVM
@@ -58,6 +64,7 @@
 	depends on ARCH_SH7372
 	select ARCH_REQUIRE_GPIOLIB
 	select SH_LCD_MIPI_DSI
+	select SND_SOC_AK4642 if SND_SIMPLE_CARD
 
 choice
 	prompt "AP4EVB LCD panel selection"
@@ -82,6 +89,7 @@
 	bool "mackerel board"
 	depends on ARCH_SH7372
 	select ARCH_REQUIRE_GPIOLIB
+	select SND_SOC_AK4642 if SND_SIMPLE_CARD
 
 config MACH_KOTA2
 	bool "KOTA2 board"
@@ -93,11 +101,28 @@
 	select ARCH_REQUIRE_GPIOLIB
 	depends on ARCH_R8A7740
 
+config MACH_ARMADILLO800EVA
+	bool "Armadillo-800 EVA board"
+	depends on ARCH_R8A7740
+	select ARCH_REQUIRE_GPIOLIB
+	select USE_OF
+
 config MACH_MARZEN
 	bool "MARZEN board"
 	depends on ARCH_R8A7779
 	select ARCH_REQUIRE_GPIOLIB
 
+config MACH_KZM9D
+	bool "KZM9D board"
+	depends on ARCH_EMEV2
+	select USE_OF
+
+config MACH_KZM9G
+	bool "KZM-A9-GT board"
+	depends on ARCH_SH73A0
+	select ARCH_REQUIRE_GPIOLIB
+	select USE_OF
+
 comment "SH-Mobile System Configuration"
 
 config CPU_HAS_INTEVT
@@ -110,7 +135,8 @@
 	hex "Physical memory start address"
 	default "0x50000000" if MACH_G3EVM
 	default "0x40000000" if MACH_G4EVM || MACH_AP4EVB || MACH_AG5EVM || \
-				MACH_MACKEREL || MACH_BONITO
+				MACH_MACKEREL || MACH_BONITO || \
+				MACH_ARMADILLO800EVA
 	default "0x41000000" if MACH_KOTA2
 	default "0x00000000"
 	---help---
@@ -122,7 +148,8 @@
 	hex "Physical memory size"
 	default "0x08000000" if MACH_G3EVM
 	default "0x08000000" if MACH_G4EVM
-	default "0x20000000" if MACH_AG5EVM || MACH_BONITO
+	default "0x20000000" if MACH_AG5EVM || MACH_BONITO || \
+				MACH_ARMADILLO800EVA
 	default "0x1e000000" if MACH_KOTA2
 	default "0x10000000" if MACH_AP4EVB || MACH_MACKEREL
 	default "0x04000000"
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index e7c2590..e6b177b 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -12,12 +12,14 @@
 obj-$(CONFIG_ARCH_SH73A0)	+= setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o
 obj-$(CONFIG_ARCH_R8A7740)	+= setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o
 obj-$(CONFIG_ARCH_R8A7779)	+= setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o
+obj-$(CONFIG_ARCH_EMEV2)	+= setup-emev2.o clock-emev2.o
 
 # SMP objects
 smp-y				:= platsmp.o headsmp.o
 smp-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
 smp-$(CONFIG_ARCH_SH73A0)	+= smp-sh73a0.o
 smp-$(CONFIG_ARCH_R8A7779)	+= smp-r8a7779.o
+smp-$(CONFIG_ARCH_EMEV2)	+= smp-emev2.o
 
 # Pinmux setup
 pfc-y				:=
@@ -49,6 +51,9 @@
 obj-$(CONFIG_MACH_KOTA2)	+= board-kota2.o
 obj-$(CONFIG_MACH_BONITO)	+= board-bonito.o
 obj-$(CONFIG_MACH_MARZEN)	+= board-marzen.o
+obj-$(CONFIG_MACH_ARMADILLO800EVA)	+= board-armadillo800eva.o
+obj-$(CONFIG_MACH_KZM9D)	+= board-kzm9d.o
+obj-$(CONFIG_MACH_KZM9G)	+= board-kzm9g.o
 
 # Framework support
 obj-$(CONFIG_SMP)		+= $(smp-y)
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index b56dde2..b540b8e 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -50,6 +50,7 @@
 #include <media/soc_camera.h>
 
 #include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 
 #include <video/sh_mobile_hdmi.h>
 #include <video/sh_mobile_lcdc.h>
@@ -785,17 +786,25 @@
 	},
 };
 
-static struct fsi_ak4642_info fsi2_ak4643_info = {
+static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
+	.fmt		= SND_SOC_DAIFMT_LEFT_J,
+	.codec_daifmt	= SND_SOC_DAIFMT_CBM_CFM,
+	.cpu_daifmt	= SND_SOC_DAIFMT_CBS_CFS,
+	.sysclk		= 11289600,
+};
+
+static struct asoc_simple_card_info fsi2_ak4643_info = {
 	.name		= "AK4643",
 	.card		= "FSI2A-AK4643",
 	.cpu_dai	= "fsia-dai",
 	.codec		= "ak4642-codec.0-0013",
 	.platform	= "sh_fsi2",
-	.id		= FSI_PORT_A,
+	.codec_dai	= "ak4642-hifi",
+	.init		= &fsi2_ak4643_init_info,
 };
 
 static struct platform_device fsi_ak4643_device = {
-	.name	= "fsi-ak4642-audio",
+	.name	= "asoc-simple-card",
 	.dev	= {
 		.platform_data	= &fsi2_ak4643_info,
 	},
@@ -900,8 +909,26 @@
 	},
 };
 
+static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
+	.cpu_daifmt	= SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static struct asoc_simple_card_info fsi2_hdmi_info = {
+	.name		= "HDMI",
+	.card		= "FSI2B-HDMI",
+	.cpu_dai	= "fsib-dai",
+	.codec		= "sh-mobile-hdmi",
+	.platform	= "sh_fsi2",
+	.codec_dai	= "sh_mobile_hdmi-hifi",
+	.init		= &fsi2_hdmi_init_info,
+};
+
 static struct platform_device fsi_hdmi_device = {
-	.name		= "sh_fsi2_b_hdmi",
+	.name	= "asoc-simple-card",
+	.id	= 1,
+	.dev	= {
+		.platform_data	= &fsi2_hdmi_info,
+	},
 };
 
 static struct gpio_led ap4evb_leds[] = {
@@ -997,6 +1024,8 @@
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
 	.flags = SH_CEU_FLAG_USE_8BIT_BUS,
+	.max_width = 8188,
+	.max_height = 8188,
 	.csi2 = &csi2,
 };
 
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
new file mode 100644
index 0000000..9e37026
--- /dev/null
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -0,0 +1,784 @@
+/*
+ * armadillo 800 eva board support
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/sh_eth.h>
+#include <linux/videodev2.h>
+#include <linux/usb/renesas_usbhs.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
+#include <mach/common.h>
+#include <mach/irqs.h>
+#include <asm/page.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <mach/r8a7740.h>
+#include <video/sh_mobile_lcdc.h>
+
+/*
+ * CON1		Camera Module
+ * CON2		Extension Bus
+ * CON3		HDMI Output
+ * CON4		Composite Video Output
+ * CON5		H-UDI JTAG
+ * CON6		ARM JTAG
+ * CON7		SD1
+ * CON8		SD2
+ * CON9		RTC BackUp
+ * CON10	Monaural Mic Input
+ * CON11	Stereo Headphone Output
+ * CON12	Audio Line Output(L)
+ * CON13	Audio Line Output(R)
+ * CON14	AWL13 Module
+ * CON15	Extension
+ * CON16	LCD1
+ * CON17	LCD2
+ * CON19	Power Input
+ * CON20	USB1
+ * CON21	USB2
+ * CON22	Serial
+ * CON23	LAN
+ * CON24	USB3
+ * LED1		Camera LED(Yellow)
+ * LED2		Power LED (Green)
+ * ED3-LED6	User LED(Yellow)
+ * LED7		LAN link LED(Green)
+ * LED8		LAN activity LED(Yellow)
+ */
+
+/*
+ * DipSwitch
+ *
+ *                    SW1
+ *
+ * -12345678-+---------------+----------------------------
+ *  1        | boot          | hermit
+ *  0        | boot          | OS auto boot
+ * -12345678-+---------------+----------------------------
+ *   00      | boot device   | eMMC
+ *   10      | boot device   | SDHI0 (CON7)
+ *   01      | boot device   | -
+ *   11      | boot device   | Extension Buss (CS0)
+ * -12345678-+---------------+----------------------------
+ *     0     | Extension Bus | D8-D15 disable, eMMC enable
+ *     1     | Extension Bus | D8-D15 enable,  eMMC disable
+ * -12345678-+---------------+----------------------------
+ *      0    | SDHI1         | COM8 disable, COM14 enable
+ *      1    | SDHI1         | COM8 enable,  COM14 disable
+ * -12345678-+---------------+----------------------------
+ *       0   | USB0          | COM20 enable,  COM24 disable
+ *       1   | USB0          | COM20 disable, COM24 enable
+ * -12345678-+---------------+----------------------------
+ *        00 | JTAG          | SH-X2
+ *        10 | JTAG          | ARM
+ *        01 | JTAG          | -
+ *        11 | JTAG          | Boundary Scan
+ *-----------+---------------+----------------------------
+ */
+
+/*
+ * USB function
+ *
+ * When you use USB Function,
+ * set SW1.6 ON, and connect cable to CN24.
+ *
+ * USBF needs workaround on R8A7740 chip.
+ * These are a little bit complex.
+ * see
+ *	usbhsf_power_ctrl()
+ *
+ * CAUTION
+ *
+ * It uses autonomy mode for USB hotplug at this point
+ * (= usbhs_private.platform_callback.get_vbus is NULL),
+ * since we don't know what's happen on PM control
+ * on this workaround.
+ */
+#define USBCR1		0xe605810a
+#define USBH		0xC6700000
+#define USBH_USBCTR	0x10834
+
+struct usbhsf_private {
+	struct clk *phy;
+	struct clk *usb24;
+	struct clk *pci;
+	struct clk *func;
+	struct clk *host;
+	void __iomem *usbh_base;
+	struct renesas_usbhs_platform_info info;
+};
+
+#define usbhsf_get_priv(pdev)				\
+	container_of(renesas_usbhs_get_info(pdev),	\
+		     struct usbhsf_private, info)
+
+static int usbhsf_get_id(struct platform_device *pdev)
+{
+	return USBHS_GADGET;
+}
+
+static void usbhsf_power_ctrl(struct platform_device *pdev,
+			      void __iomem *base, int enable)
+{
+	struct usbhsf_private *priv = usbhsf_get_priv(pdev);
+
+	/*
+	 * Work around for USB Function.
+	 * It needs USB host clock, and settings
+	 */
+	if (enable) {
+		/*
+		 * enable all the related usb clocks
+		 * for usb workaround
+		 */
+		clk_enable(priv->usb24);
+		clk_enable(priv->pci);
+		clk_enable(priv->host);
+		clk_enable(priv->func);
+		clk_enable(priv->phy);
+
+		/*
+		 * set USBCR1
+		 *
+		 * Port1 is driven by USB function,
+		 * Port2 is driven by USB HOST
+		 * One HOST (Port1 or Port2 is HOST)
+		 * USB PLL input clock = 24MHz
+		 */
+		__raw_writew(0xd750, USBCR1);
+		mdelay(1);
+
+		/*
+		 * start USB Host
+		 */
+		__raw_writel(0x0000000c, priv->usbh_base + USBH_USBCTR);
+		__raw_writel(0x00000008, priv->usbh_base + USBH_USBCTR);
+		mdelay(10);
+
+		/*
+		 * USB PHY Power ON
+		 */
+		__raw_writew(0xd770, USBCR1);
+		__raw_writew(0x4000, base + 0x102); /* USBF :: SUSPMODE */
+
+	} else {
+		__raw_writel(0x0000010f, priv->usbh_base + USBH_USBCTR);
+		__raw_writew(0xd7c0, USBCR1); /* GPIO */
+
+		clk_disable(priv->phy);
+		clk_disable(priv->func);	/* usb work around */
+		clk_disable(priv->host);	/* usb work around */
+		clk_disable(priv->pci);		/* usb work around */
+		clk_disable(priv->usb24);	/* usb work around */
+	}
+}
+
+static void usbhsf_hardware_exit(struct platform_device *pdev)
+{
+	struct usbhsf_private *priv = usbhsf_get_priv(pdev);
+
+	if (!IS_ERR(priv->phy))
+		clk_put(priv->phy);
+	if (!IS_ERR(priv->usb24))
+		clk_put(priv->usb24);
+	if (!IS_ERR(priv->pci))
+		clk_put(priv->pci);
+	if (!IS_ERR(priv->host))
+		clk_put(priv->host);
+	if (!IS_ERR(priv->func))
+		clk_put(priv->func);
+	if (priv->usbh_base)
+		iounmap(priv->usbh_base);
+
+	priv->phy	= NULL;
+	priv->usb24	= NULL;
+	priv->pci	= NULL;
+	priv->host	= NULL;
+	priv->func	= NULL;
+	priv->usbh_base	= NULL;
+}
+
+static int usbhsf_hardware_init(struct platform_device *pdev)
+{
+	struct usbhsf_private *priv = usbhsf_get_priv(pdev);
+
+	priv->phy	= clk_get(&pdev->dev, "phy");
+	priv->usb24	= clk_get(&pdev->dev, "usb24");
+	priv->pci	= clk_get(&pdev->dev, "pci");
+	priv->func	= clk_get(&pdev->dev, "func");
+	priv->host	= clk_get(&pdev->dev, "host");
+	priv->usbh_base	= ioremap_nocache(USBH, 0x20000);
+
+	if (IS_ERR(priv->phy)		||
+	    IS_ERR(priv->usb24)		||
+	    IS_ERR(priv->pci)		||
+	    IS_ERR(priv->host)		||
+	    IS_ERR(priv->func)		||
+	    !priv->usbh_base) {
+		dev_err(&pdev->dev, "USB clock setting failed\n");
+		usbhsf_hardware_exit(pdev);
+		return -EIO;
+	}
+
+	/* usb24 use 1/1 of parent clock (= usb24s = 24MHz) */
+	clk_set_rate(priv->usb24,
+		     clk_get_rate(clk_get_parent(priv->usb24)));
+
+	return 0;
+}
+
+static struct usbhsf_private usbhsf_private = {
+	.info = {
+		.platform_callback = {
+			.get_id		= usbhsf_get_id,
+			.hardware_init	= usbhsf_hardware_init,
+			.hardware_exit	= usbhsf_hardware_exit,
+			.power_ctrl	= usbhsf_power_ctrl,
+		},
+		.driver_param = {
+			.buswait_bwait		= 5,
+			.detection_delay	= 5,
+		},
+	}
+};
+
+static struct resource usbhsf_resources[] = {
+	{
+		.name	= "USBHS",
+		.start	= 0xe6890000,
+		.end	= 0xe6890104 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= evt2irq(0x0A20),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device usbhsf_device = {
+	.name	= "renesas_usbhs",
+	.dev = {
+		.platform_data = &usbhsf_private.info,
+	},
+	.id = -1,
+	.num_resources	= ARRAY_SIZE(usbhsf_resources),
+	.resource	= usbhsf_resources,
+};
+
+/* Ether */
+static struct sh_eth_plat_data sh_eth_platdata = {
+	.phy			= 0x00, /* LAN8710A */
+	.edmac_endian		= EDMAC_LITTLE_ENDIAN,
+	.register_type		= SH_ETH_REG_GIGABIT,
+	.phy_interface		= PHY_INTERFACE_MODE_MII,
+};
+
+static struct resource sh_eth_resources[] = {
+	{
+		.start	= 0xe9a00000,
+		.end	= 0xe9a00800 - 1,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= 0xe9a01800,
+		.end	= 0xe9a02000 - 1,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= evt2irq(0x0500),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device sh_eth_device = {
+	.name = "sh-eth",
+	.id = -1,
+	.dev = {
+		.platform_data = &sh_eth_platdata,
+	},
+	.resource = sh_eth_resources,
+	.num_resources = ARRAY_SIZE(sh_eth_resources),
+};
+
+/* LCDC */
+static struct fb_videomode lcdc0_mode = {
+	.name		= "AMPIER/AM-800480",
+	.xres		= 800,
+	.yres		= 480,
+	.left_margin	= 88,
+	.right_margin	= 40,
+	.hsync_len	= 128,
+	.upper_margin	= 20,
+	.lower_margin	= 5,
+	.vsync_len	= 5,
+	.sync		= 0,
+};
+
+static struct sh_mobile_lcdc_info lcdc0_info = {
+	.clock_source	= LCDC_CLK_BUS,
+	.ch[0] = {
+		.chan		= LCDC_CHAN_MAINLCD,
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.interface_type	= RGB24,
+		.clock_divider	= 5,
+		.flags		= 0,
+		.lcd_modes	= &lcdc0_mode,
+		.num_modes	= 1,
+		.panel_cfg = {
+			.width	= 111,
+			.height = 68,
+		},
+	},
+};
+
+static struct resource lcdc0_resources[] = {
+	[0] = {
+		.name	= "LCD0",
+		.start	= 0xfe940000,
+		.end	= 0xfe943fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x580),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device lcdc0_device = {
+	.name		= "sh_mobile_lcdc_fb",
+	.num_resources	= ARRAY_SIZE(lcdc0_resources),
+	.resource	= lcdc0_resources,
+	.id		= 0,
+	.dev	= {
+		.platform_data	= &lcdc0_info,
+		.coherent_dma_mask = ~0,
+	},
+};
+
+/* GPIO KEY */
+#define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
+
+static struct gpio_keys_button gpio_buttons[] = {
+	GPIO_KEY(KEY_POWER,	GPIO_PORT99,	"SW1"),
+	GPIO_KEY(KEY_BACK,	GPIO_PORT100,	"SW2"),
+	GPIO_KEY(KEY_MENU,	GPIO_PORT97,	"SW3"),
+	GPIO_KEY(KEY_HOME,	GPIO_PORT98,	"SW4"),
+};
+
+static struct gpio_keys_platform_data gpio_key_info = {
+	.buttons	= gpio_buttons,
+	.nbuttons	= ARRAY_SIZE(gpio_buttons),
+};
+
+static struct platform_device gpio_keys_device = {
+	.name   = "gpio-keys",
+	.id     = -1,
+	.dev    = {
+		.platform_data  = &gpio_key_info,
+	},
+};
+
+/* SDHI0 */
+/*
+ * FIXME
+ *
+ * It use polling mode here, since
+ * CD (= Card Detect) pin is not connected to SDHI0_CD.
+ * We can use IRQ31 as card detect irq,
+ * but it needs chattering removal operation
+ */
+#define IRQ31	evt2irq(0x33E0)
+static struct sh_mobile_sdhi_info sdhi0_info = {
+	.tmio_caps	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |\
+			  MMC_CAP_NEEDS_POLL,
+	.tmio_ocr_mask	= MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
+	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT,
+};
+
+static struct resource sdhi0_resources[] = {
+	{
+		.name	= "SDHI0",
+		.start	= 0xe6850000,
+		.end	= 0xe6850100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	/*
+	 * no SH_MOBILE_SDHI_IRQ_CARD_DETECT here
+	 */
+	{
+		.name	= SH_MOBILE_SDHI_IRQ_SDCARD,
+		.start	= evt2irq(0x0E20),
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= SH_MOBILE_SDHI_IRQ_SDIO,
+		.start	= evt2irq(0x0E40),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device sdhi0_device = {
+	.name		= "sh_mobile_sdhi",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &sdhi0_info,
+	},
+	.num_resources	= ARRAY_SIZE(sdhi0_resources),
+	.resource	= sdhi0_resources,
+};
+
+/* SDHI1 */
+static struct sh_mobile_sdhi_info sdhi1_info = {
+	.tmio_caps	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+	.tmio_ocr_mask	= MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
+	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT,
+};
+
+static struct resource sdhi1_resources[] = {
+	[0] = {
+		.name	= "SDHI1",
+		.start	= 0xe6860000,
+		.end	= 0xe6860100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x0E80),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= evt2irq(0x0EA0),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		.start	= evt2irq(0x0EC0),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device sdhi1_device = {
+	.name		= "sh_mobile_sdhi",
+	.id		= 1,
+	.dev		= {
+		.platform_data	= &sdhi1_info,
+	},
+	.num_resources	= ARRAY_SIZE(sdhi1_resources),
+	.resource	= sdhi1_resources,
+};
+
+/* MMCIF */
+static struct sh_mmcif_plat_data sh_mmcif_plat = {
+	.sup_pclk	= 0,
+	.ocr		= MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
+	.caps		= MMC_CAP_4_BIT_DATA |
+			  MMC_CAP_8_BIT_DATA |
+			  MMC_CAP_NONREMOVABLE,
+};
+
+static struct resource sh_mmcif_resources[] = {
+	[0] = {
+		.name	= "MMCIF",
+		.start	= 0xe6bd0000,
+		.end	= 0xe6bd0100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		/* MMC ERR */
+		.start	= evt2irq(0x1AC0),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		/* MMC NOR */
+		.start	= evt2irq(0x1AE0),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device sh_mmcif_device = {
+	.name		= "sh_mmcif",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &sh_mmcif_plat,
+	},
+	.num_resources	= ARRAY_SIZE(sh_mmcif_resources),
+	.resource	= sh_mmcif_resources,
+};
+
+/* I2C */
+static struct i2c_board_info i2c0_devices[] = {
+	{
+		I2C_BOARD_INFO("st1232-ts", 0x55),
+		.irq = evt2irq(0x0340),
+	},
+};
+
+/*
+ * board devices
+ */
+static struct platform_device *eva_devices[] __initdata = {
+	&lcdc0_device,
+	&gpio_keys_device,
+	&sh_eth_device,
+	&sdhi0_device,
+	&sh_mmcif_device,
+};
+
+static void __init eva_clock_init(void)
+{
+	struct clk *system	= clk_get(NULL, "system_clk");
+	struct clk *xtal1	= clk_get(NULL, "extal1");
+	struct clk *usb24s	= clk_get(NULL, "usb24s");
+
+	if (IS_ERR(system)	||
+	    IS_ERR(xtal1)	||
+	    IS_ERR(usb24s)) {
+		pr_err("armadillo800eva board clock init failed\n");
+		goto clock_error;
+	}
+
+	/* armadillo 800 eva extal1 is 24MHz */
+	clk_set_rate(xtal1, 24000000);
+
+	/* usb24s use extal1 (= system) clock (= 24MHz) */
+	clk_set_parent(usb24s, system);
+
+clock_error:
+	if (!IS_ERR(system))
+		clk_put(system);
+	if (!IS_ERR(xtal1))
+		clk_put(xtal1);
+	if (!IS_ERR(usb24s))
+		clk_put(usb24s);
+}
+
+/*
+ * board init
+ */
+static void __init eva_init(void)
+{
+	eva_clock_init();
+
+	r8a7740_pinmux_init();
+
+	/* SCIFA1 */
+	gpio_request(GPIO_FN_SCIFA1_RXD, NULL);
+	gpio_request(GPIO_FN_SCIFA1_TXD, NULL);
+
+	/* LCDC0 */
+	gpio_request(GPIO_FN_LCDC0_SELECT,	NULL);
+	gpio_request(GPIO_FN_LCD0_D0,		NULL);
+	gpio_request(GPIO_FN_LCD0_D1,		NULL);
+	gpio_request(GPIO_FN_LCD0_D2,		NULL);
+	gpio_request(GPIO_FN_LCD0_D3,		NULL);
+	gpio_request(GPIO_FN_LCD0_D4,		NULL);
+	gpio_request(GPIO_FN_LCD0_D5,		NULL);
+	gpio_request(GPIO_FN_LCD0_D6,		NULL);
+	gpio_request(GPIO_FN_LCD0_D7,		NULL);
+	gpio_request(GPIO_FN_LCD0_D8,		NULL);
+	gpio_request(GPIO_FN_LCD0_D9,		NULL);
+	gpio_request(GPIO_FN_LCD0_D10,		NULL);
+	gpio_request(GPIO_FN_LCD0_D11,		NULL);
+	gpio_request(GPIO_FN_LCD0_D12,		NULL);
+	gpio_request(GPIO_FN_LCD0_D13,		NULL);
+	gpio_request(GPIO_FN_LCD0_D14,		NULL);
+	gpio_request(GPIO_FN_LCD0_D15,		NULL);
+	gpio_request(GPIO_FN_LCD0_D16,		NULL);
+	gpio_request(GPIO_FN_LCD0_D17,		NULL);
+	gpio_request(GPIO_FN_LCD0_D18_PORT40,	NULL);
+	gpio_request(GPIO_FN_LCD0_D19_PORT4,	NULL);
+	gpio_request(GPIO_FN_LCD0_D20_PORT3,	NULL);
+	gpio_request(GPIO_FN_LCD0_D21_PORT2,	NULL);
+	gpio_request(GPIO_FN_LCD0_D22_PORT0,	NULL);
+	gpio_request(GPIO_FN_LCD0_D23_PORT1,	NULL);
+	gpio_request(GPIO_FN_LCD0_DCK,		NULL);
+	gpio_request(GPIO_FN_LCD0_VSYN,		NULL);
+	gpio_request(GPIO_FN_LCD0_HSYN,		NULL);
+	gpio_request(GPIO_FN_LCD0_DISP,		NULL);
+	gpio_request(GPIO_FN_LCD0_LCLK_PORT165,	NULL);
+
+	gpio_request(GPIO_PORT61, NULL); /* LCDDON */
+	gpio_direction_output(GPIO_PORT61, 1);
+
+	gpio_request(GPIO_PORT202, NULL); /* LCD0_LED_CONT */
+	gpio_direction_output(GPIO_PORT202, 0);
+
+	/* Touchscreen */
+	gpio_request(GPIO_FN_IRQ10,	NULL); /* TP_INT */
+	gpio_request(GPIO_PORT166,	NULL); /* TP_RST_B */
+	gpio_direction_output(GPIO_PORT166, 1);
+
+	/* GETHER */
+	gpio_request(GPIO_FN_ET_CRS,		NULL);
+	gpio_request(GPIO_FN_ET_MDC,		NULL);
+	gpio_request(GPIO_FN_ET_MDIO,		NULL);
+	gpio_request(GPIO_FN_ET_TX_ER,		NULL);
+	gpio_request(GPIO_FN_ET_RX_ER,		NULL);
+	gpio_request(GPIO_FN_ET_ERXD0,		NULL);
+	gpio_request(GPIO_FN_ET_ERXD1,		NULL);
+	gpio_request(GPIO_FN_ET_ERXD2,		NULL);
+	gpio_request(GPIO_FN_ET_ERXD3,		NULL);
+	gpio_request(GPIO_FN_ET_TX_CLK,		NULL);
+	gpio_request(GPIO_FN_ET_TX_EN,		NULL);
+	gpio_request(GPIO_FN_ET_ETXD0,		NULL);
+	gpio_request(GPIO_FN_ET_ETXD1,		NULL);
+	gpio_request(GPIO_FN_ET_ETXD2,		NULL);
+	gpio_request(GPIO_FN_ET_ETXD3,		NULL);
+	gpio_request(GPIO_FN_ET_PHY_INT,	NULL);
+	gpio_request(GPIO_FN_ET_COL,		NULL);
+	gpio_request(GPIO_FN_ET_RX_DV,		NULL);
+	gpio_request(GPIO_FN_ET_RX_CLK,		NULL);
+
+	gpio_request(GPIO_PORT18, NULL); /* PHY_RST */
+	gpio_direction_output(GPIO_PORT18, 1);
+
+	/* USB */
+	gpio_request(GPIO_PORT159, NULL); /* USB_DEVICE_MODE */
+	gpio_direction_input(GPIO_PORT159);
+
+	if (gpio_get_value(GPIO_PORT159)) {
+		/* USB Host */
+	} else {
+		/* USB Func */
+		gpio_request(GPIO_FN_VBUS, NULL);
+		platform_device_register(&usbhsf_device);
+	}
+
+	/* SDHI0 */
+	gpio_request(GPIO_FN_SDHI0_CMD, NULL);
+	gpio_request(GPIO_FN_SDHI0_CLK, NULL);
+	gpio_request(GPIO_FN_SDHI0_D0, NULL);
+	gpio_request(GPIO_FN_SDHI0_D1, NULL);
+	gpio_request(GPIO_FN_SDHI0_D2, NULL);
+	gpio_request(GPIO_FN_SDHI0_D3, NULL);
+	gpio_request(GPIO_FN_SDHI0_WP, NULL);
+
+	gpio_request(GPIO_PORT17, NULL);	/* SDHI0_18/33_B */
+	gpio_request(GPIO_PORT74, NULL);	/* SDHI0_PON */
+	gpio_request(GPIO_PORT75, NULL);	/* SDSLOT1_PON */
+	gpio_direction_output(GPIO_PORT17, 0);
+	gpio_direction_output(GPIO_PORT74, 1);
+	gpio_direction_output(GPIO_PORT75, 1);
+
+	/* we can use GPIO_FN_IRQ31_PORT167 here for SDHI0 CD irq */
+
+	/*
+	 * MMCIF
+	 *
+	 * Here doesn't care SW1.4 status,
+	 * since CON2 is not mounted.
+	 */
+	gpio_request(GPIO_FN_MMC1_CLK_PORT103,	NULL);
+	gpio_request(GPIO_FN_MMC1_CMD_PORT104,	NULL);
+	gpio_request(GPIO_FN_MMC1_D0_PORT149,	NULL);
+	gpio_request(GPIO_FN_MMC1_D1_PORT148,	NULL);
+	gpio_request(GPIO_FN_MMC1_D2_PORT147,	NULL);
+	gpio_request(GPIO_FN_MMC1_D3_PORT146,	NULL);
+	gpio_request(GPIO_FN_MMC1_D4_PORT145,	NULL);
+	gpio_request(GPIO_FN_MMC1_D5_PORT144,	NULL);
+	gpio_request(GPIO_FN_MMC1_D6_PORT143,	NULL);
+	gpio_request(GPIO_FN_MMC1_D7_PORT142,	NULL);
+
+	/*
+	 * CAUTION
+	 *
+	 * DBGMD/LCDC0/FSIA MUX
+	 * DBGMD_SELECT_B should be set after setting PFC Function.
+	 */
+	gpio_request(GPIO_PORT176, NULL);
+	gpio_direction_output(GPIO_PORT176, 1);
+
+	/*
+	 * We can switch CON8/CON14 by SW1.5,
+	 * but it needs after DBGMD_SELECT_B
+	 */
+	gpio_request(GPIO_PORT6, NULL);
+	gpio_direction_input(GPIO_PORT6);
+	if (gpio_get_value(GPIO_PORT6)) {
+		/* CON14 enable */
+	} else {
+		/* CON8 (SDHI1) enable */
+		gpio_request(GPIO_FN_SDHI1_CLK,	NULL);
+		gpio_request(GPIO_FN_SDHI1_CMD,	NULL);
+		gpio_request(GPIO_FN_SDHI1_D0,	NULL);
+		gpio_request(GPIO_FN_SDHI1_D1,	NULL);
+		gpio_request(GPIO_FN_SDHI1_D2,	NULL);
+		gpio_request(GPIO_FN_SDHI1_D3,	NULL);
+		gpio_request(GPIO_FN_SDHI1_CD,	NULL);
+		gpio_request(GPIO_FN_SDHI1_WP,	NULL);
+
+		gpio_request(GPIO_PORT16, NULL); /* SDSLOT2_PON */
+		gpio_direction_output(GPIO_PORT16, 1);
+
+		platform_device_register(&sdhi1_device);
+	}
+
+
+#ifdef CONFIG_CACHE_L2X0
+	/* Early BRESP enable, Shared attribute override enable, 32K*8way */
+	l2x0_init(__io(0xf0002000), 0x40440000, 0x82000fff);
+#endif
+
+	i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices));
+
+	r8a7740_add_standard_devices();
+
+	platform_add_devices(eva_devices,
+			     ARRAY_SIZE(eva_devices));
+}
+
+static void __init eva_earlytimer_init(void)
+{
+	r8a7740_clock_init(MD_CK0 | MD_CK2);
+	shmobile_earlytimer_init();
+}
+
+static void __init eva_add_early_devices(void)
+{
+	r8a7740_add_early_devices();
+
+	/* override timer setup with board-specific code */
+	shmobile_timer.init = eva_earlytimer_init;
+}
+
+static const char *eva_boards_compat_dt[] __initdata = {
+	"renesas,armadillo800eva",
+	NULL,
+};
+
+DT_MACHINE_START(ARMADILLO800EVA_DT, "armadillo800eva")
+	.map_io		= r8a7740_map_io,
+	.init_early	= eva_add_early_devices,
+	.init_irq	= r8a7740_init_irq,
+	.handle_irq	= shmobile_handle_irq_intc,
+	.init_machine	= eva_init,
+	.timer		= &shmobile_timer,
+	.dt_compat	= eva_boards_compat_dt,
+MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index 81fd95f..63ab706 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -486,7 +486,7 @@
 	shmobile_earlytimer_init();
 }
 
-void __init bonito_add_early_devices(void)
+static void __init bonito_add_early_devices(void)
 {
 	r8a7740_add_early_devices();
 
diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c
new file mode 100644
index 0000000..7bc5e7d
--- /dev/null
+++ b/arch/arm/mach-shmobile/board-kzm9d.c
@@ -0,0 +1,85 @@
+/*
+ * kzm9d board support
+ *
+ * Copyright (C) 2012  Renesas Solutions Corp.
+ * Copyright (C) 2012  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/smsc911x.h>
+#include <mach/common.h>
+#include <mach/emev2.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+
+/* Ether */
+static struct resource smsc911x_resources[] = {
+	[0] = {
+		.start	= 0x20000000,
+		.end	= 0x2000ffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= EMEV2_GPIO_IRQ(1),
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
+	},
+};
+
+static struct smsc911x_platform_config smsc911x_platdata = {
+	.flags		= SMSC911X_USE_32BIT,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
+};
+
+static struct platform_device smsc91x_device = {
+	.name	= "smsc911x",
+	.id	= 0,
+	.dev	= {
+		  .platform_data = &smsc911x_platdata,
+		},
+	.num_resources	= ARRAY_SIZE(smsc911x_resources),
+	.resource	= smsc911x_resources,
+};
+
+static struct platform_device *kzm9d_devices[] __initdata = {
+	&smsc91x_device,
+};
+
+void __init kzm9d_add_standard_devices(void)
+{
+	emev2_add_standard_devices();
+
+	platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices));
+}
+
+static const char *kzm9d_boards_compat_dt[] __initdata = {
+	"renesas,kzm9d",
+	NULL,
+};
+
+DT_MACHINE_START(KZM9D_DT, "kzm9d")
+	.map_io		= emev2_map_io,
+	.init_early	= emev2_add_early_devices,
+	.nr_irqs	= NR_IRQS_LEGACY,
+	.init_irq	= emev2_init_irq,
+	.handle_irq	= gic_handle_irq,
+	.init_machine	= kzm9d_add_standard_devices,
+	.timer		= &shmobile_timer,
+	.dt_compat	= kzm9d_boards_compat_dt,
+MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
new file mode 100644
index 0000000..d8e33b6
--- /dev/null
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -0,0 +1,460 @@
+/*
+ * KZM-A9-GT board support
+ *
+ * Copyright (C) 2012	Kuninori Morimoto <kuninori.morimoto.gx@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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
+#include <linux/input.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
+#include <linux/mfd/tmio.h>
+#include <linux/platform_device.h>
+#include <linux/smsc911x.h>
+#include <linux/usb/r8a66597.h>
+#include <linux/videodev2.h>
+#include <mach/irqs.h>
+#include <mach/sh73a0.h>
+#include <mach/common.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <video/sh_mobile_lcdc.h>
+
+/*
+ * external GPIO
+ */
+#define GPIO_PCF8575_BASE	(GPIO_NR)
+#define GPIO_PCF8575_PORT10	(GPIO_NR + 8)
+#define GPIO_PCF8575_PORT11	(GPIO_NR + 9)
+#define GPIO_PCF8575_PORT12	(GPIO_NR + 10)
+#define GPIO_PCF8575_PORT13	(GPIO_NR + 11)
+#define GPIO_PCF8575_PORT14	(GPIO_NR + 12)
+#define GPIO_PCF8575_PORT15	(GPIO_NR + 13)
+#define GPIO_PCF8575_PORT16	(GPIO_NR + 14)
+
+/* SMSC 9221 */
+static struct resource smsc9221_resources[] = {
+	[0] = {
+		.start	= 0x10000000, /* CS4 */
+		.end	= 0x100000ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x260), /* IRQ3 */
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct smsc911x_platform_config smsc9221_platdata = {
+	.flags		= SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct platform_device smsc_device = {
+	.name		= "smsc911x",
+	.dev  = {
+		.platform_data = &smsc9221_platdata,
+	},
+	.resource	= smsc9221_resources,
+	.num_resources	= ARRAY_SIZE(smsc9221_resources),
+};
+
+/* USB external chip */
+static struct r8a66597_platdata usb_host_data = {
+	.on_chip	= 0,
+	.xtal		= R8A66597_PLATDATA_XTAL_48MHZ,
+};
+
+static struct resource usb_resources[] = {
+	[0] = {
+		.start	= 0x10010000,
+		.end	= 0x1001ffff - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x220), /* IRQ1 */
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device usb_host_device = {
+	.name	= "r8a66597_hcd",
+	.dev = {
+		.platform_data		= &usb_host_data,
+		.dma_mask		= NULL,
+		.coherent_dma_mask	= 0xffffffff,
+	},
+	.num_resources	= ARRAY_SIZE(usb_resources),
+	.resource	= usb_resources,
+};
+
+/* LCDC */
+static struct fb_videomode kzm_lcdc_mode = {
+	.name		= "WVGA Panel",
+	.xres		= 800,
+	.yres		= 480,
+	.left_margin	= 220,
+	.right_margin	= 110,
+	.hsync_len	= 70,
+	.upper_margin	= 20,
+	.lower_margin	= 5,
+	.vsync_len	= 5,
+	.sync		= 0,
+};
+
+static struct sh_mobile_lcdc_info lcdc_info = {
+	.clock_source = LCDC_CLK_BUS,
+	.ch[0] = {
+		.chan		= LCDC_CHAN_MAINLCD,
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.interface_type	= RGB24,
+		.lcd_modes	= &kzm_lcdc_mode,
+		.num_modes	= 1,
+		.clock_divider	= 5,
+		.flags		= 0,
+		.panel_cfg = {
+			.width	= 152,
+			.height	= 91,
+		},
+	}
+};
+
+static struct resource lcdc_resources[] = {
+	[0] = {
+		.name	= "LCDC",
+		.start	= 0xfe940000,
+		.end	= 0xfe943fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x580),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device lcdc_device = {
+	.name		= "sh_mobile_lcdc_fb",
+	.num_resources	= ARRAY_SIZE(lcdc_resources),
+	.resource	= lcdc_resources,
+	.dev	= {
+		.platform_data	= &lcdc_info,
+		.coherent_dma_mask = ~0,
+	},
+};
+
+/* MMCIF */
+static struct resource sh_mmcif_resources[] = {
+	[0] = {
+		.name	= "MMCIF",
+		.start	= 0xe6bd0000,
+		.end	= 0xe6bd00ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= gic_spi(141),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= gic_spi(140),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct sh_mmcif_plat_data sh_mmcif_platdata = {
+	.ocr		= MMC_VDD_165_195,
+	.caps		= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+};
+
+static struct platform_device mmc_device = {
+	.name		= "sh_mmcif",
+	.dev		= {
+		.dma_mask		= NULL,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &sh_mmcif_platdata,
+	},
+	.num_resources	= ARRAY_SIZE(sh_mmcif_resources),
+	.resource	= sh_mmcif_resources,
+};
+
+/* SDHI */
+static struct sh_mobile_sdhi_info sdhi0_info = {
+	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT,
+	.tmio_caps	= MMC_CAP_SD_HIGHSPEED,
+	.tmio_ocr_mask	= MMC_VDD_27_28 | MMC_VDD_28_29,
+};
+
+static struct resource sdhi0_resources[] = {
+	[0] = {
+		.name	= "SDHI0",
+		.start	= 0xee100000,
+		.end	= 0xee1000ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= SH_MOBILE_SDHI_IRQ_CARD_DETECT,
+		.start	= gic_spi(83),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDCARD,
+		.start	= gic_spi(84),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDIO,
+		.start	= gic_spi(85),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device sdhi0_device = {
+	.name		= "sh_mobile_sdhi",
+	.num_resources	= ARRAY_SIZE(sdhi0_resources),
+	.resource	= sdhi0_resources,
+	.dev	= {
+		.platform_data	= &sdhi0_info,
+	},
+};
+
+/* KEY */
+#define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
+
+static struct gpio_keys_button gpio_buttons[] = {
+	GPIO_KEY(KEY_BACK,	GPIO_PCF8575_PORT10,	"SW3"),
+	GPIO_KEY(KEY_RIGHT,	GPIO_PCF8575_PORT11,	"SW2-R"),
+	GPIO_KEY(KEY_LEFT,	GPIO_PCF8575_PORT12,	"SW2-L"),
+	GPIO_KEY(KEY_ENTER,	GPIO_PCF8575_PORT13,	"SW2-P"),
+	GPIO_KEY(KEY_UP,	GPIO_PCF8575_PORT14,	"SW2-U"),
+	GPIO_KEY(KEY_DOWN,	GPIO_PCF8575_PORT15,	"SW2-D"),
+	GPIO_KEY(KEY_HOME,	GPIO_PCF8575_PORT16,	"SW1"),
+};
+
+static struct gpio_keys_platform_data gpio_key_info = {
+	.buttons	= gpio_buttons,
+	.nbuttons	= ARRAY_SIZE(gpio_buttons),
+	.poll_interval	= 250, /* poling at this point */
+};
+
+static struct platform_device gpio_keys_device = {
+	/* gpio-pcf857x.c driver doesn't support gpio_to_irq() */
+	.name	= "gpio-keys-polled",
+	.dev	= {
+		.platform_data  = &gpio_key_info,
+	},
+};
+
+/* I2C */
+static struct pcf857x_platform_data pcf8575_pdata = {
+	.gpio_base	= GPIO_PCF8575_BASE,
+};
+
+static struct i2c_board_info i2c1_devices[] = {
+	{
+		I2C_BOARD_INFO("st1232-ts", 0x55),
+		.irq = intcs_evt2irq(0x300), /* IRQ8 */
+	},
+};
+
+static struct i2c_board_info i2c3_devices[] = {
+	{
+		I2C_BOARD_INFO("pcf8575", 0x20),
+		.platform_data = &pcf8575_pdata,
+	},
+};
+
+static struct platform_device *kzm_devices[] __initdata = {
+	&smsc_device,
+	&usb_host_device,
+	&lcdc_device,
+	&mmc_device,
+	&sdhi0_device,
+	&gpio_keys_device,
+};
+
+/*
+ * FIXME
+ *
+ * This is quick hack for enabling LCDC backlight
+ */
+static int __init as3711_enable_lcdc_backlight(void)
+{
+	struct i2c_adapter *a = i2c_get_adapter(0);
+	struct i2c_msg msg;
+	int i, ret;
+	__u8 magic[] = {
+		0x40, 0x2a,
+		0x43, 0x3c,
+		0x44, 0x3c,
+		0x45, 0x3c,
+		0x54, 0x03,
+		0x51, 0x00,
+		0x51, 0x01,
+		0xff, 0x00, /* wait */
+		0x43, 0xf0,
+		0x44, 0xf0,
+		0x45, 0xf0,
+	};
+
+	if (!machine_is_kzm9g())
+		return 0;
+
+	if (!a)
+		return 0;
+
+	msg.addr	= 0x40;
+	msg.len		= 2;
+	msg.flags	= 0;
+
+	for (i = 0; i < ARRAY_SIZE(magic); i += 2) {
+		msg.buf = magic + i;
+
+		if (0xff == msg.buf[0]) {
+			udelay(500);
+			continue;
+		}
+
+		ret = i2c_transfer(a, &msg, 1);
+		if (ret < 0) {
+			pr_err("i2c transfer fail\n");
+			break;
+		}
+	}
+
+	return 0;
+}
+device_initcall(as3711_enable_lcdc_backlight);
+
+static void __init kzm_init(void)
+{
+	sh73a0_pinmux_init();
+
+	/* enable SCIFA4 */
+	gpio_request(GPIO_FN_SCIFA4_TXD, NULL);
+	gpio_request(GPIO_FN_SCIFA4_RXD, NULL);
+	gpio_request(GPIO_FN_SCIFA4_RTS_, NULL);
+	gpio_request(GPIO_FN_SCIFA4_CTS_, NULL);
+
+	/* CS4 for SMSC/USB */
+	gpio_request(GPIO_FN_CS4_, NULL); /* CS4 */
+
+	/* SMSC */
+	gpio_request(GPIO_PORT224, NULL); /* IRQ3 */
+	gpio_direction_input(GPIO_PORT224);
+
+	/* LCDC */
+	gpio_request(GPIO_FN_LCDD23,	NULL);
+	gpio_request(GPIO_FN_LCDD22,	NULL);
+	gpio_request(GPIO_FN_LCDD21,	NULL);
+	gpio_request(GPIO_FN_LCDD20,	NULL);
+	gpio_request(GPIO_FN_LCDD19,	NULL);
+	gpio_request(GPIO_FN_LCDD18,	NULL);
+	gpio_request(GPIO_FN_LCDD17,	NULL);
+	gpio_request(GPIO_FN_LCDD16,	NULL);
+	gpio_request(GPIO_FN_LCDD15,	NULL);
+	gpio_request(GPIO_FN_LCDD14,	NULL);
+	gpio_request(GPIO_FN_LCDD13,	NULL);
+	gpio_request(GPIO_FN_LCDD12,	NULL);
+	gpio_request(GPIO_FN_LCDD11,	NULL);
+	gpio_request(GPIO_FN_LCDD10,	NULL);
+	gpio_request(GPIO_FN_LCDD9,	NULL);
+	gpio_request(GPIO_FN_LCDD8,	NULL);
+	gpio_request(GPIO_FN_LCDD7,	NULL);
+	gpio_request(GPIO_FN_LCDD6,	NULL);
+	gpio_request(GPIO_FN_LCDD5,	NULL);
+	gpio_request(GPIO_FN_LCDD4,	NULL);
+	gpio_request(GPIO_FN_LCDD3,	NULL);
+	gpio_request(GPIO_FN_LCDD2,	NULL);
+	gpio_request(GPIO_FN_LCDD1,	NULL);
+	gpio_request(GPIO_FN_LCDD0,	NULL);
+	gpio_request(GPIO_FN_LCDDISP,	NULL);
+	gpio_request(GPIO_FN_LCDDCK,	NULL);
+
+	gpio_request(GPIO_PORT222,	NULL); /* LCDCDON */
+	gpio_request(GPIO_PORT226,	NULL); /* SC */
+	gpio_direction_output(GPIO_PORT222, 1);
+	gpio_direction_output(GPIO_PORT226, 1);
+
+	/* Touchscreen */
+	gpio_request(GPIO_PORT223, NULL); /* IRQ8 */
+	gpio_direction_input(GPIO_PORT223);
+
+	/* enable MMCIF */
+	gpio_request(GPIO_FN_MMCCLK0,		NULL);
+	gpio_request(GPIO_FN_MMCCMD0_PU,	NULL);
+	gpio_request(GPIO_FN_MMCD0_0_PU,	NULL);
+	gpio_request(GPIO_FN_MMCD0_1_PU,	NULL);
+	gpio_request(GPIO_FN_MMCD0_2_PU,	NULL);
+	gpio_request(GPIO_FN_MMCD0_3_PU,	NULL);
+	gpio_request(GPIO_FN_MMCD0_4_PU,	NULL);
+	gpio_request(GPIO_FN_MMCD0_5_PU,	NULL);
+	gpio_request(GPIO_FN_MMCD0_6_PU,	NULL);
+	gpio_request(GPIO_FN_MMCD0_7_PU,	NULL);
+
+	/* enable SD */
+	gpio_request(GPIO_FN_SDHIWP0,		NULL);
+	gpio_request(GPIO_FN_SDHICD0,		NULL);
+	gpio_request(GPIO_FN_SDHICMD0,		NULL);
+	gpio_request(GPIO_FN_SDHICLK0,		NULL);
+	gpio_request(GPIO_FN_SDHID0_3,		NULL);
+	gpio_request(GPIO_FN_SDHID0_2,		NULL);
+	gpio_request(GPIO_FN_SDHID0_1,		NULL);
+	gpio_request(GPIO_FN_SDHID0_0,		NULL);
+	gpio_request(GPIO_FN_SDHI0_VCCQ_MC0_ON,	NULL);
+	gpio_request(GPIO_PORT15, NULL);
+	gpio_direction_output(GPIO_PORT15, 1); /* power */
+
+	/* I2C 3 */
+	gpio_request(GPIO_FN_PORT27_I2C_SCL3, NULL);
+	gpio_request(GPIO_FN_PORT28_I2C_SDA3, NULL);
+
+#ifdef CONFIG_CACHE_L2X0
+	/* Early BRESP enable, Shared attribute override enable, 64K*8way */
+	l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff);
+#endif
+
+	i2c_register_board_info(1, i2c1_devices, ARRAY_SIZE(i2c1_devices));
+	i2c_register_board_info(3, i2c3_devices, ARRAY_SIZE(i2c3_devices));
+
+	sh73a0_add_standard_devices();
+	platform_add_devices(kzm_devices, ARRAY_SIZE(kzm_devices));
+}
+
+static const char *kzm9g_boards_compat_dt[] __initdata = {
+	"renesas,kzm9g",
+	NULL,
+};
+
+DT_MACHINE_START(KZM9G_DT, "kzm9g")
+	.map_io		= sh73a0_map_io,
+	.init_early	= sh73a0_add_early_devices,
+	.nr_irqs	= NR_IRQS_LEGACY,
+	.init_irq	= sh73a0_init_irq,
+	.handle_irq	= gic_handle_irq,
+	.init_machine	= kzm_init,
+	.timer		= &shmobile_timer,
+	.dt_compat	= kzm9g_boards_compat_dt,
+MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 8c6202b..50c67b2 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -53,6 +53,7 @@
 #include <media/soc_camera.h>
 #include <media/soc_camera_platform.h>
 #include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 
 #include <mach/common.h>
 #include <mach/irqs.h>
@@ -502,8 +503,26 @@
 	},
 };
 
+static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
+	.cpu_daifmt	= SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static struct asoc_simple_card_info fsi2_hdmi_info = {
+	.name		= "HDMI",
+	.card		= "FSI2B-HDMI",
+	.cpu_dai	= "fsib-dai",
+	.codec		= "sh-mobile-hdmi",
+	.platform	= "sh_fsi2",
+	.codec_dai	= "sh_mobile_hdmi-hifi",
+	.init		= &fsi2_hdmi_init_info,
+};
+
 static struct platform_device fsi_hdmi_device = {
-	.name		= "sh_fsi2_b_hdmi",
+	.name	= "asoc-simple-card",
+	.id	= 1,
+	.dev	= {
+		.platform_data	= &fsi2_hdmi_info,
+	},
 };
 
 static void __init hdmi_init_pm_clock(void)
@@ -908,6 +927,8 @@
 static struct sh_fsi_platform_info fsi_info = {
 	.port_a = {
 		.flags = SH_FSI_BRS_INV,
+		.tx_id = SHDMA_SLAVE_FSIA_TX,
+		.rx_id = SHDMA_SLAVE_FSIA_RX,
 	},
 	.port_b = {
 		.flags = SH_FSI_BRS_INV	|
@@ -920,9 +941,11 @@
 
 static struct resource fsi_resources[] = {
 	[0] = {
+		/* we need 0xFE1F0000 to access DMA
+		 * instead of 0xFE3C0000 */
 		.name	= "FSI",
-		.start	= 0xFE3C0000,
-		.end	= 0xFE3C0400 - 1,
+		.start  = 0xFE1F0000,
+		.end    = 0xFE1F0400 - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -941,17 +964,25 @@
 	},
 };
 
-static struct fsi_ak4642_info fsi2_ak4643_info = {
+static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
+	.fmt		= SND_SOC_DAIFMT_LEFT_J,
+	.codec_daifmt	= SND_SOC_DAIFMT_CBM_CFM,
+	.cpu_daifmt	= SND_SOC_DAIFMT_CBS_CFS,
+	.sysclk		= 11289600,
+};
+
+static struct asoc_simple_card_info fsi2_ak4643_info = {
 	.name		= "AK4643",
 	.card		= "FSI2A-AK4643",
 	.cpu_dai	= "fsia-dai",
 	.codec		= "ak4642-codec.0-0013",
 	.platform	= "sh_fsi2",
-	.id		= FSI_PORT_A,
+	.codec_dai	= "ak4642-hifi",
+	.init		= &fsi2_ak4643_init_info,
 };
 
 static struct platform_device fsi_ak4643_device = {
-	.name	= "fsi-ak4642-audio",
+	.name	= "asoc-simple-card",
 	.dev	= {
 		.platform_data	= &fsi2_ak4643_info,
 	},
@@ -1248,6 +1279,8 @@
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
 	.flags = SH_CEU_FLAG_USE_8BIT_BUS,
+	.max_width = 8188,
+	.max_height = 8188,
 };
 
 static struct resource ceu_resources[] = {
diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c
new file mode 100644
index 0000000..4710f18
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock-emev2.c
@@ -0,0 +1,249 @@
+/*
+ * Emma Mobile EV2 clock framework support
+ *
+ * Copyright (C) 2012  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/sh_clk.h>
+#include <linux/clkdev.h>
+#include <mach/common.h>
+
+#define EMEV2_SMU_BASE 0xe0110000
+
+/* EMEV2 SMU registers */
+#define USIAU0_RSTCTRL 0x094
+#define USIBU1_RSTCTRL 0x0ac
+#define USIBU2_RSTCTRL 0x0b0
+#define USIBU3_RSTCTRL 0x0b4
+#define STI_RSTCTRL 0x124
+#define USIAU0GCLKCTRL 0x4a0
+#define USIBU1GCLKCTRL 0x4b8
+#define USIBU2GCLKCTRL 0x4bc
+#define USIBU3GCLKCTRL 0x04c0
+#define STIGCLKCTRL 0x528
+#define USIAU0SCLKDIV 0x61c
+#define USIB2SCLKDIV 0x65c
+#define USIB3SCLKDIV 0x660
+#define STI_CLKSEL 0x688
+#define SMU_GENERAL_REG0 0x7c0
+
+/* not pretty, but hey */
+static void __iomem *smu_base;
+
+static void emev2_smu_write(unsigned long value, int offs)
+{
+	BUG_ON(!smu_base || (offs >= PAGE_SIZE));
+	iowrite32(value, smu_base + offs);
+}
+
+void emev2_set_boot_vector(unsigned long value)
+{
+	emev2_smu_write(value, SMU_GENERAL_REG0);
+}
+
+static struct clk_mapping smu_mapping = {
+	.phys	= EMEV2_SMU_BASE,
+	.len	= PAGE_SIZE,
+};
+
+/* Fixed 32 KHz root clock from C32K pin */
+static struct clk c32k_clk = {
+	.rate           = 32768,
+	.mapping	= &smu_mapping,
+};
+
+/* PLL3 multiplies C32K with 7000 */
+static unsigned long pll3_recalc(struct clk *clk)
+{
+	return clk->parent->rate * 7000;
+}
+
+static struct sh_clk_ops pll3_clk_ops = {
+	.recalc		= pll3_recalc,
+};
+
+static struct clk pll3_clk = {
+	.ops		= &pll3_clk_ops,
+	.parent		= &c32k_clk,
+};
+
+static struct clk *main_clks[] = {
+	&c32k_clk,
+	&pll3_clk,
+};
+
+enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3,
+	SCLKDIV_NR };
+
+#define SCLKDIV(_reg, _shift)			\
+{								\
+	.parent		= &pll3_clk,				\
+	.enable_reg	= IOMEM(EMEV2_SMU_BASE + (_reg)),	\
+	.enable_bit	= _shift,				\
+}
+
+static struct clk sclkdiv_clks[SCLKDIV_NR] = {
+	[SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0),
+	[SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16),
+	[SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0),
+	[SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0),
+};
+
+enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK,
+	GCLK_STI_SCLK,
+	GCLK_NR };
+
+#define GCLK_SCLK(_parent, _reg) \
+{								\
+	.parent		= _parent,				\
+	.enable_reg	= IOMEM(EMEV2_SMU_BASE + (_reg)),	\
+	.enable_bit	= 1, /* SCLK_GCC */			\
+}
+
+static struct clk gclk_clks[GCLK_NR] = {
+	[GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0],
+				       USIAU0GCLKCTRL),
+	[GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1],
+				       USIBU1GCLKCTRL),
+	[GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2],
+				       USIBU2GCLKCTRL),
+	[GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3],
+				       USIBU3GCLKCTRL),
+	[GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL),
+};
+
+static int emev2_gclk_enable(struct clk *clk)
+{
+	iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
+		  clk->mapped_reg);
+	return 0;
+}
+
+static void emev2_gclk_disable(struct clk *clk)
+{
+	iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
+		  clk->mapped_reg);
+}
+
+static struct sh_clk_ops emev2_gclk_clk_ops = {
+	.enable		= emev2_gclk_enable,
+	.disable	= emev2_gclk_disable,
+	.recalc		= followparent_recalc,
+};
+
+static int __init emev2_gclk_register(struct clk *clks, int nr)
+{
+	struct clk *clkp;
+	int ret = 0;
+	int k;
+
+	for (k = 0; !ret && (k < nr); k++) {
+		clkp = clks + k;
+		clkp->ops = &emev2_gclk_clk_ops;
+		ret |= clk_register(clkp);
+	}
+
+	return ret;
+}
+
+static unsigned long emev2_sclkdiv_recalc(struct clk *clk)
+{
+	unsigned int sclk_div;
+
+	sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff;
+
+	return clk->parent->rate / (sclk_div + 1);
+}
+
+static struct sh_clk_ops emev2_sclkdiv_clk_ops = {
+	.recalc		= emev2_sclkdiv_recalc,
+};
+
+static int __init emev2_sclkdiv_register(struct clk *clks, int nr)
+{
+	struct clk *clkp;
+	int ret = 0;
+	int k;
+
+	for (k = 0; !ret && (k < nr); k++) {
+		clkp = clks + k;
+		clkp->ops = &emev2_sclkdiv_clk_ops;
+		ret |= clk_register(clkp);
+	}
+
+	return ret;
+}
+
+static struct clk_lookup lookups[] = {
+	CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]),
+	CLKDEV_DEV_ID("e1020000.uart", &gclk_clks[GCLK_USIAU0_SCLK]),
+	CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]),
+	CLKDEV_DEV_ID("e1030000.uart", &gclk_clks[GCLK_USIBU1_SCLK]),
+	CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]),
+	CLKDEV_DEV_ID("e1040000.uart", &gclk_clks[GCLK_USIBU2_SCLK]),
+	CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]),
+	CLKDEV_DEV_ID("e1050000.uart", &gclk_clks[GCLK_USIBU3_SCLK]),
+	CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]),
+	CLKDEV_DEV_ID("e0180000.sti", &gclk_clks[GCLK_STI_SCLK]),
+};
+
+void __init emev2_clock_init(void)
+{
+	int k, ret = 0;
+	static int is_setup;
+
+	/* yuck, this is ugly as hell, but the non-smp case of clocks
+	 * code is now designed to rely on ioremap() instead of static
+	 * entity maps. in the case of smp we need access to the SMU
+	 * register earlier than ioremap() is actually working without
+	 * any static maps. to enable SMP in ugly but with dynamic
+	 * mappings we have to call emev2_clock_init() from different
+	 * places depending on UP and SMP...
+	 */
+	if (is_setup++)
+		return;
+
+	smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
+	BUG_ON(!smu_base);
+
+	/* setup STI timer to run on 37.768 kHz and deassert reset */
+	emev2_smu_write(0, STI_CLKSEL);
+	emev2_smu_write(1, STI_RSTCTRL);
+
+	/* deassert reset for UART0->UART3 */
+	emev2_smu_write(2, USIAU0_RSTCTRL);
+	emev2_smu_write(2, USIBU1_RSTCTRL);
+	emev2_smu_write(2, USIBU2_RSTCTRL);
+	emev2_smu_write(2, USIBU3_RSTCTRL);
+
+	for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+		ret = clk_register(main_clks[k]);
+
+	if (!ret)
+		ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR);
+
+	if (!ret)
+		ret = emev2_gclk_register(gclk_clks, GCLK_NR);
+
+	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+	if (!ret)
+		shmobile_clk_init();
+	else
+		panic("failed to setup emev2 clocks\n");
+}
diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
index 99c4d74..26eea5f 100644
--- a/arch/arm/mach-shmobile/clock-r8a7740.c
+++ b/arch/arm/mach-shmobile/clock-r8a7740.c
@@ -47,6 +47,7 @@
 #define PLLC01CR	0xe6150028
 
 #define SUBCKCR		0xe6150080
+#define USBCKCR		0xe615008c
 
 #define MSTPSR0		0xe6150030
 #define MSTPSR1		0xe6150038
@@ -181,6 +182,95 @@
 	.parent		= &pllc1_clk,
 };
 
+/* USB clock */
+static struct clk *usb24s_parents[] = {
+	[0] = &system_clk,
+	[1] = &extal2_clk
+};
+
+static int usb24s_enable(struct clk *clk)
+{
+	__raw_writel(__raw_readl(USBCKCR) & ~(1 << 8), USBCKCR);
+
+	return 0;
+}
+
+static void usb24s_disable(struct clk *clk)
+{
+	__raw_writel(__raw_readl(USBCKCR) | (1 << 8), USBCKCR);
+}
+
+static int usb24s_set_parent(struct clk *clk, struct clk *parent)
+{
+	int i, ret;
+	u32 val;
+
+	if (!clk->parent_table || !clk->parent_num)
+		return -EINVAL;
+
+	/* Search the parent */
+	for (i = 0; i < clk->parent_num; i++)
+		if (clk->parent_table[i] == parent)
+			break;
+
+	if (i == clk->parent_num)
+		return -ENODEV;
+
+	ret = clk_reparent(clk, parent);
+	if (ret < 0)
+		return ret;
+
+	val = __raw_readl(USBCKCR);
+	val &= ~(1 << 7);
+	val |= i << 7;
+	__raw_writel(val, USBCKCR);
+
+	return 0;
+}
+
+static struct sh_clk_ops usb24s_clk_ops = {
+	.recalc		= followparent_recalc,
+	.enable		= usb24s_enable,
+	.disable	= usb24s_disable,
+	.set_parent	= usb24s_set_parent,
+};
+
+static struct clk usb24s_clk = {
+	.ops		= &usb24s_clk_ops,
+	.parent_table	= usb24s_parents,
+	.parent_num	= ARRAY_SIZE(usb24s_parents),
+	.parent		= &system_clk,
+};
+
+static unsigned long usb24_recalc(struct clk *clk)
+{
+	return clk->parent->rate /
+		((__raw_readl(USBCKCR) & (1 << 6)) ? 1 : 2);
+};
+
+static int usb24_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 val;
+
+	/* closer to which ? parent->rate or parent->rate/2 */
+	val = __raw_readl(USBCKCR);
+	val &= ~(1 << 6);
+	val |= (rate > (clk->parent->rate / 4) * 3) << 6;
+	__raw_writel(val, USBCKCR);
+
+	return 0;
+}
+
+static struct sh_clk_ops usb24_clk_ops = {
+	.recalc		= usb24_recalc,
+	.set_rate	= usb24_set_rate,
+};
+
+static struct clk usb24_clk = {
+	.ops		= &usb24_clk_ops,
+	.parent		= &usb24s_clk,
+};
+
 struct clk *main_clks[] = {
 	&extalr_clk,
 	&extal1_clk,
@@ -196,6 +286,8 @@
 	&pllc0_clk,
 	&pllc1_clk,
 	&pllc1_div2_clk,
+	&usb24s_clk,
+	&usb24_clk,
 };
 
 static void div4_kick(struct clk *clk)
@@ -223,7 +315,7 @@
 
 enum {
 	DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP,
-	DIV4_HPP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
+	DIV4_HPP, DIV4_USBP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
 	DIV4_NR
 };
 
@@ -234,6 +326,7 @@
 	[DIV4_M1]	= SH_CLK_DIV4(&pllc1_clk, FRQCRA,  4, 0x6fff, CLK_ENABLE_ON_INIT),
 	[DIV4_HP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRB,  4, 0x6fff, 0),
 	[DIV4_HPP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC, 20, 0x6fff, 0),
+	[DIV4_USBP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC, 16, 0x6fff, 0),
 	[DIV4_S]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC, 12, 0x6fff, 0),
 	[DIV4_ZB]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC,  8, 0x6fff, 0),
 	[DIV4_M3]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC,  4, 0x6fff, 0),
@@ -257,7 +350,11 @@
 	MSTP222,
 	MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
 
-	MSTP329, MSTP323,
+	MSTP329, MSTP328, MSTP323, MSTP320,
+	MSTP314, MSTP313, MSTP312,
+	MSTP309,
+
+	MSTP416, MSTP415, MSTP407, MSTP406,
 
 	MSTP_NR
 };
@@ -280,7 +377,18 @@
 	[MSTP200] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2,  0, 0), /* SCIFA4 */
 
 	[MSTP329] = SH_CLK_MSTP32(&r_clk,		SMSTPCR3, 29, 0), /* CMT10 */
+	[MSTP328] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 28, 0), /* FSI */
 	[MSTP323] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR3, 23, 0), /* IIC1 */
+	[MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 20, 0), /* USBF */
+	[MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 14, 0), /* SDHI0 */
+	[MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 13, 0), /* SDHI1 */
+	[MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 12, 0), /* MMC */
+	[MSTP309] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3,  9, 0), /* GEther */
+
+	[MSTP416] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4, 16, 0), /* USBHOST */
+	[MSTP415] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4, 15, 0), /* SDHI2 */
+	[MSTP407] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4,  7, 0), /* USB-Func */
+	[MSTP406] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4,  6, 0), /* USB Phy */
 };
 
 static struct clk_lookup lookups[] = {
@@ -299,6 +407,7 @@
 	CLKDEV_CON_ID("pllc0_clk",		&pllc0_clk),
 	CLKDEV_CON_ID("pllc1_clk",		&pllc1_clk),
 	CLKDEV_CON_ID("pllc1_div2_clk",		&pllc1_div2_clk),
+	CLKDEV_CON_ID("usb24s",			&usb24s_clk),
 
 	/* DIV4 clocks */
 	CLKDEV_CON_ID("i_clk",			&div4_clks[DIV4_I]),
@@ -334,7 +443,22 @@
 	CLKDEV_DEV_ID("sh-sci.6",		&mstp_clks[MSTP230]),
 
 	CLKDEV_DEV_ID("sh_cmt.10",		&mstp_clks[MSTP329]),
+	CLKDEV_DEV_ID("sh_fsi2",		&mstp_clks[MSTP328]),
 	CLKDEV_DEV_ID("i2c-sh_mobile.1",	&mstp_clks[MSTP323]),
+	CLKDEV_DEV_ID("renesas_usbhs",		&mstp_clks[MSTP320]),
+	CLKDEV_DEV_ID("sh_mobile_sdhi.0",	&mstp_clks[MSTP314]),
+	CLKDEV_DEV_ID("sh_mobile_sdhi.1",	&mstp_clks[MSTP313]),
+	CLKDEV_DEV_ID("sh_mmcif",		&mstp_clks[MSTP312]),
+	CLKDEV_DEV_ID("sh-eth",			&mstp_clks[MSTP309]),
+
+	CLKDEV_DEV_ID("sh_mobile_sdhi.2",	&mstp_clks[MSTP415]),
+
+	/* ICK */
+	CLKDEV_ICK_ID("host",	"renesas_usbhs",	&mstp_clks[MSTP416]),
+	CLKDEV_ICK_ID("func",	"renesas_usbhs",	&mstp_clks[MSTP407]),
+	CLKDEV_ICK_ID("phy",	"renesas_usbhs",	&mstp_clks[MSTP406]),
+	CLKDEV_ICK_ID("pci",	"renesas_usbhs",	&div4_clks[DIV4_USBP]),
+	CLKDEV_ICK_ID("usb24",	"renesas_usbhs",	&usb24_clk),
 };
 
 void __init r8a7740_clock_init(u8 md_ck)
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index c85e6ec..ff5f12f 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -3,6 +3,8 @@
 
 extern void shmobile_earlytimer_init(void);
 extern struct sys_timer shmobile_timer;
+extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz,
+				 unsigned int mult, unsigned int div);
 struct twd_local_timer;
 extern void shmobile_setup_console(void);
 extern void shmobile_secondary_vector(void);
diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h
new file mode 100644
index 0000000..e6b0c1b
--- /dev/null
+++ b/arch/arm/mach-shmobile/include/mach/emev2.h
@@ -0,0 +1,19 @@
+#ifndef __ASM_EMEV2_H__
+#define __ASM_EMEV2_H__
+
+extern void emev2_map_io(void);
+extern void emev2_init_irq(void);
+extern void emev2_add_early_devices(void);
+extern void emev2_add_standard_devices(void);
+extern void emev2_clock_init(void);
+extern void emev2_set_boot_vector(unsigned long value);
+extern unsigned int emev2_get_core_count(void);
+extern int emev2_platform_cpu_kill(unsigned int cpu);
+extern void emev2_secondary_init(unsigned int cpu);
+extern int emev2_boot_secondary(unsigned int cpu);
+extern void emev2_smp_prepare_cpus(void);
+
+#define EMEV2_GPIO_BASE 200
+#define EMEV2_GPIO_IRQ(n) (EMEV2_GPIO_BASE + (n))
+
+#endif /* __ASM_EMEV2_H__ */
diff --git a/arch/arm/mach-shmobile/include/mach/intc.h b/arch/arm/mach-shmobile/include/mach/intc.h
index 8b22258..a5603c7 100644
--- a/arch/arm/mach-shmobile/include/mach/intc.h
+++ b/arch/arm/mach-shmobile/include/mach/intc.h
@@ -142,6 +142,50 @@
 			     p ## _sense_registers, p ## _ack_registers) \
 }
 
+#define INTC_IRQ_PINS_16H(p, base, vect, str)				\
+									\
+static struct resource p ## _resources[] __initdata = {			\
+	[0] = {								\
+		.start	= base,						\
+		.end	= base + 0x64,					\
+		.flags	= IORESOURCE_MEM,				\
+	},								\
+};									\
+									\
+enum {									\
+	p ## _UNUSED = 0,						\
+	INTC_IRQ_PINS_ENUM_16H(p),					\
+};									\
+									\
+static struct intc_vect p ## _vectors[] __initdata = {			\
+	INTC_IRQ_PINS_VECT_16H(p, vect),				\
+};									\
+									\
+static struct intc_mask_reg p ## _mask_registers[] __initdata = {	\
+	INTC_IRQ_PINS_MASK_16H(p, base),				\
+};									\
+									\
+static struct intc_prio_reg p ## _prio_registers[] __initdata = {	\
+	INTC_IRQ_PINS_PRIO_16H(p, base),				\
+};									\
+									\
+static struct intc_sense_reg p ## _sense_registers[] __initdata = {	\
+	INTC_IRQ_PINS_SENSE_16H(p, base),				\
+};									\
+									\
+static struct intc_mask_reg p ## _ack_registers[] __initdata = {	\
+	INTC_IRQ_PINS_ACK_16H(p, base),					\
+};									\
+									\
+static struct intc_desc p ## _desc __initdata = {			\
+	.name = str,							\
+	.resource = p ## _resources,					\
+	.num_resources = ARRAY_SIZE(p ## _resources),			\
+	.hw = INTC_HW_DESC(p ## _vectors, NULL,				\
+			     p ## _mask_registers, p ## _prio_registers, \
+			     p ## _sense_registers, p ## _ack_registers) \
+}
+
 #define INTC_IRQ_PINS_32(p, base, vect, str)				\
 									\
 static struct resource p ## _resources[] __initdata = {			\
diff --git a/arch/arm/mach-shmobile/include/mach/irqs.h b/arch/arm/mach-shmobile/include/mach/irqs.h
index 4e686cc2..06a5da3 100644
--- a/arch/arm/mach-shmobile/include/mach/irqs.h
+++ b/arch/arm/mach-shmobile/include/mach/irqs.h
@@ -7,7 +7,7 @@
 #define gic_spi(nr)		((nr) + 32)
 
 /* INTCS */
-#define INTCS_VECT_BASE		0x2200
+#define INTCS_VECT_BASE		0x3400
 #define INTCS_VECT(n, vect)	INTC_VECT((n), INTCS_VECT_BASE + (vect))
 #define intcs_evt2irq(evt)	evt2irq(INTCS_VECT_BASE + (evt))
 
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index 8254ab8..915d009 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -457,6 +457,8 @@
 	SHDMA_SLAVE_SDHI1_TX,
 	SHDMA_SLAVE_SDHI2_RX,
 	SHDMA_SLAVE_SDHI2_TX,
+	SHDMA_SLAVE_FSIA_RX,
+	SHDMA_SLAVE_FSIA_TX,
 	SHDMA_SLAVE_MMCIF_RX,
 	SHDMA_SLAVE_MMCIF_TX,
 	SHDMA_SLAVE_USB0_TX,
diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h
index cad5757..398e2c1 100644
--- a/arch/arm/mach-shmobile/include/mach/sh73a0.h
+++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h
@@ -482,6 +482,9 @@
 	GPIO_FN_FSIAILR_PU,
 	GPIO_FN_FSIAIBT_PU,
 	GPIO_FN_FSIAISLD_PU,
+
+	/* end of GPIO */
+	GPIO_NR,
 };
 
 /* DMA slave IDs */
@@ -515,8 +518,36 @@
 	SHDMA_SLAVE_MMCIF_RX,
 };
 
-/* PINT interrupts are located at Linux IRQ 800 and up */
-#define SH73A0_PINT0_IRQ(irq) ((irq) + 800)
-#define SH73A0_PINT1_IRQ(irq) ((irq) + 832)
+/*
+ *		SH73A0 IRQ LOCATION TABLE
+ *
+ * 416	-----------------------------------------
+ *		IRQ0-IRQ15
+ * 431	-----------------------------------------
+ * ...
+ * 448	-----------------------------------------
+ *		sh73a0-intcs
+ *		sh73a0-intca-irq-pins
+ * 680	-----------------------------------------
+ * ...
+ * 700	-----------------------------------------
+ *		sh73a0-pint0
+ * 731	-----------------------------------------
+ * 732	-----------------------------------------
+ *		sh73a0-pint1
+ * 739	-----------------------------------------
+ * ...
+ * 800	-----------------------------------------
+ *		IRQ16-IRQ31
+ * 815	-----------------------------------------
+ * ...
+ * 928	-----------------------------------------
+ *		sh73a0-intca-irq-pins
+ * 943	-----------------------------------------
+ */
+
+/* PINT interrupts are located at Linux IRQ 700 and up */
+#define SH73A0_PINT0_IRQ(irq) ((irq) + 700)
+#define SH73A0_PINT1_IRQ(irq) ((irq) + 732)
 
 #endif /* __ASM_SH73A0_H__ */
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 6447e0a..2587a22 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/sh_intc.h>
@@ -305,14 +306,16 @@
 			 intca_mask_registers, intca_prio_registers,
 			 NULL);
 
-INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000,
-		 INTC_VECT, "sh7372-intca-irq-pins");
+INTC_IRQ_PINS_16(intca_irq_pins_lo, 0xe6900000,
+		 INTC_VECT, "sh7372-intca-irq-lo");
+
+INTC_IRQ_PINS_16H(intca_irq_pins_hi, 0xe6900000,
+		 INTC_VECT, "sh7372-intca-irq-hi");
+
 enum {
 	UNUSED_INTCS = 0,
 	ENABLED_INTCS,
 
-	INTCS,
-
 	/* interrupt sources INTCS */
 
 	/* IRQ0S - IRQ31S */
@@ -426,8 +429,6 @@
 	INTCS_VECT(CPORTS2R, 0x1a20),
 	/* CEC */
 	INTCS_VECT(JPU6E, 0x1a80),
-
-	INTC_VECT(INTCS, 0xf80),
 };
 
 static struct intc_group intcs_groups[] __initdata = {
@@ -490,9 +491,6 @@
 	{ 0xffd5019c, 0xffd501dc, 8, /* IMR7SA3 / IMCR7SA3 */
 	  { MFIS2_INTCS, CPORTS2R, 0, 0,
 	    JPU6E, 0, 0, 0 } },
-	{ 0xffd20104, 0, 16, /* INTAMASK */
-	  { 0, 0, 0, 0, 0, 0, 0, 0,
-	    0, 0, 0, 0, 0, 0, 0, INTCS } },
 };
 
 /* Priority is needed for INTCA to receive the INTCS interrupt */
@@ -557,18 +555,30 @@
 void __init sh7372_init_irq(void)
 {
 	void __iomem *intevtsa;
+	int n;
 
 	intcs_ffd2 = ioremap_nocache(0xffd20000, PAGE_SIZE);
 	intevtsa = intcs_ffd2 + 0x100;
 	intcs_ffd5 = ioremap_nocache(0xffd50000, PAGE_SIZE);
 
 	register_intc_controller(&intca_desc);
-	register_intc_controller(&intca_irq_pins_desc);
+	register_intc_controller(&intca_irq_pins_lo_desc);
+	register_intc_controller(&intca_irq_pins_hi_desc);
 	register_intc_controller(&intcs_desc);
 
+	/* setup dummy cascade chip for INTCS */
+	n = evt2irq(0xf80);
+	irq_alloc_desc_at(n, numa_node_id());
+	irq_set_chip_and_handler_name(n, &dummy_irq_chip,
+				      handle_level_irq, "level");
+	set_irq_flags(n, IRQF_VALID); /* yuck */
+
 	/* demux using INTEVTSA */
-	irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa);
-	irq_set_chained_handler(evt2irq(0xf80), intcs_demux);
+	irq_set_handler_data(n, (void *)intevtsa);
+	irq_set_chained_handler(n, intcs_demux);
+
+	/* unmask INTCS in INTAMASK */
+	iowrite16(0, intcs_ffd2 + 0x104);
 }
 
 static unsigned short ffd2[0x200];
diff --git a/arch/arm/mach-shmobile/pfc-r8a7740.c b/arch/arm/mach-shmobile/pfc-r8a7740.c
index a4fff69..670fe18 100644
--- a/arch/arm/mach-shmobile/pfc-r8a7740.c
+++ b/arch/arm/mach-shmobile/pfc-r8a7740.c
@@ -22,6 +22,7 @@
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 #include <mach/r8a7740.h>
+#include <mach/irqs.h>
 
 #define CPU_ALL_PORT(fn, pfx, sfx)					\
 	PORT_10(fn, pfx, sfx),		PORT_90(fn, pfx, sfx),		\
@@ -2527,6 +2528,41 @@
 	{ },
 };
 
+static struct pinmux_irq pinmux_irqs[] = {
+	PINMUX_IRQ(evt2irq(0x0200), PORT2_FN0,	 PORT13_FN0),	/* IRQ0A */
+	PINMUX_IRQ(evt2irq(0x0220), PORT20_FN0),		/* IRQ1A */
+	PINMUX_IRQ(evt2irq(0x0240), PORT11_FN0,	 PORT12_FN0),	/* IRQ2A */
+	PINMUX_IRQ(evt2irq(0x0260), PORT10_FN0,	 PORT14_FN0),	/* IRQ3A */
+	PINMUX_IRQ(evt2irq(0x0280), PORT15_FN0,	 PORT172_FN0),	/* IRQ4A */
+	PINMUX_IRQ(evt2irq(0x02A0), PORT0_FN0,	 PORT1_FN0),	/* IRQ5A */
+	PINMUX_IRQ(evt2irq(0x02C0), PORT121_FN0, PORT173_FN0),	/* IRQ6A */
+	PINMUX_IRQ(evt2irq(0x02E0), PORT120_FN0, PORT209_FN0),	/* IRQ7A */
+	PINMUX_IRQ(evt2irq(0x0300), PORT119_FN0),		/* IRQ8A */
+	PINMUX_IRQ(evt2irq(0x0320), PORT118_FN0, PORT210_FN0),	/* IRQ9A */
+	PINMUX_IRQ(evt2irq(0x0340), PORT19_FN0),		/* IRQ10A */
+	PINMUX_IRQ(evt2irq(0x0360), PORT104_FN0),		/* IRQ11A */
+	PINMUX_IRQ(evt2irq(0x0380), PORT42_FN0,	 PORT97_FN0),	/* IRQ12A */
+	PINMUX_IRQ(evt2irq(0x03A0), PORT64_FN0,	 PORT98_FN0),	/* IRQ13A */
+	PINMUX_IRQ(evt2irq(0x03C0), PORT63_FN0,	 PORT99_FN0),	/* IRQ14A */
+	PINMUX_IRQ(evt2irq(0x03E0), PORT62_FN0,	 PORT100_FN0),	/* IRQ15A */
+	PINMUX_IRQ(evt2irq(0x3200), PORT68_FN0,	 PORT211_FN0),	/* IRQ16A */
+	PINMUX_IRQ(evt2irq(0x3220), PORT69_FN0),		/* IRQ17A */
+	PINMUX_IRQ(evt2irq(0x3240), PORT70_FN0),		/* IRQ18A */
+	PINMUX_IRQ(evt2irq(0x3260), PORT71_FN0),		/* IRQ19A */
+	PINMUX_IRQ(evt2irq(0x3280), PORT67_FN0),		/* IRQ20A */
+	PINMUX_IRQ(evt2irq(0x32A0), PORT202_FN0),		/* IRQ21A */
+	PINMUX_IRQ(evt2irq(0x32C0), PORT95_FN0),		/* IRQ22A */
+	PINMUX_IRQ(evt2irq(0x32E0), PORT96_FN0),		/* IRQ23A */
+	PINMUX_IRQ(evt2irq(0x3300), PORT180_FN0),		/* IRQ24A */
+	PINMUX_IRQ(evt2irq(0x3320), PORT38_FN0),		/* IRQ25A */
+	PINMUX_IRQ(evt2irq(0x3340), PORT58_FN0,	 PORT81_FN0),	/* IRQ26A */
+	PINMUX_IRQ(evt2irq(0x3360), PORT57_FN0,	 PORT168_FN0),	/* IRQ27A */
+	PINMUX_IRQ(evt2irq(0x3380), PORT56_FN0,	 PORT169_FN0),	/* IRQ28A */
+	PINMUX_IRQ(evt2irq(0x33A0), PORT50_FN0,	 PORT170_FN0),	/* IRQ29A */
+	PINMUX_IRQ(evt2irq(0x33C0), PORT49_FN0,	 PORT171_FN0),	/* IRQ30A */
+	PINMUX_IRQ(evt2irq(0x33E0), PORT41_FN0,	 PORT167_FN0),	/* IRQ31A */
+};
+
 static struct pinmux_info r8a7740_pinmux_info = {
 	.name		= "r8a7740_pfc",
 	.reserved_id	= PINMUX_RESERVED,
@@ -2554,6 +2590,9 @@
 
 	.gpio_data	= pinmux_data,
 	.gpio_data_size	= ARRAY_SIZE(pinmux_data),
+
+	.gpio_irq	= pinmux_irqs,
+	.gpio_irq_size	= ARRAY_SIZE(pinmux_irqs),
 };
 
 void r8a7740_pinmux_init(void)
diff --git a/arch/arm/mach-shmobile/pfc-sh73a0.c b/arch/arm/mach-shmobile/pfc-sh73a0.c
index e05634c..4a547b8 100644
--- a/arch/arm/mach-shmobile/pfc-sh73a0.c
+++ b/arch/arm/mach-shmobile/pfc-sh73a0.c
@@ -829,14 +829,14 @@
 	PINMUX_DATA(PORT27_I2C_SCL2_MARK, PORT27_FN2, MSEL2CR_MSEL17_0,
 		MSEL2CR_MSEL16_1), \
 	PINMUX_DATA(PORT27_I2C_SCL3_MARK, PORT27_FN3, MSEL2CR_MSEL19_0,
-		MSEL2CR_MSEL18_0), \
+		MSEL2CR_MSEL18_1), \
 	PINMUX_DATA(MFG0_OUT1_MARK, PORT27_FN4), \
 	PINMUX_DATA(PORT27_IROUT_MARK, PORT27_FN7),
 	PINMUX_DATA(XDVFS2_MARK, PORT28_FN1), \
 	PINMUX_DATA(PORT28_I2C_SDA2_MARK, PORT28_FN2, MSEL2CR_MSEL17_0,
 		MSEL2CR_MSEL16_1), \
 	PINMUX_DATA(PORT28_I2C_SDA3_MARK, PORT28_FN3, MSEL2CR_MSEL19_0,
-		MSEL2CR_MSEL18_0), \
+		MSEL2CR_MSEL18_1), \
 	PINMUX_DATA(PORT28_TPU1TO1_MARK, PORT28_FN7),
 	PINMUX_DATA(SIM_RST_MARK, PORT29_FN1), \
 	PINMUX_DATA(PORT29_TPU1TO1_MARK, PORT29_FN4),
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index 45fa392..bacdd66 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -16,12 +16,16 @@
 #include <linux/device.h>
 #include <linux/smp.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
 #include <mach/common.h>
+#include <mach/emev2.h>
 
-#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2())
+#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2() || \
+			of_machine_is_compatible("renesas,sh73a0"))
 #define is_r8a7779() machine_is_marzen()
+#define is_emev2() of_machine_is_compatible("renesas,emev2")
 
 static unsigned int __init shmobile_smp_get_core_count(void)
 {
@@ -31,6 +35,9 @@
 	if (is_r8a7779())
 		return r8a7779_get_core_count();
 
+	if (is_emev2())
+		return emev2_get_core_count();
+
 	return 1;
 }
 
@@ -41,6 +48,9 @@
 
 	if (is_r8a7779())
 		r8a7779_smp_prepare_cpus();
+
+	if (is_emev2())
+		emev2_smp_prepare_cpus();
 }
 
 int shmobile_platform_cpu_kill(unsigned int cpu)
@@ -48,6 +58,9 @@
 	if (is_r8a7779())
 		return r8a7779_platform_cpu_kill(cpu);
 
+	if (is_emev2())
+		return emev2_platform_cpu_kill(cpu);
+
 	return 1;
 }
 
@@ -60,6 +73,9 @@
 
 	if (is_r8a7779())
 		r8a7779_secondary_init(cpu);
+
+	if (is_emev2())
+		emev2_secondary_init(cpu);
 }
 
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -70,6 +86,9 @@
 	if (is_r8a7779())
 		return r8a7779_boot_secondary(cpu);
 
+	if (is_emev2())
+		return emev2_boot_secondary(cpu);
+
 	return -ENOSYS;
 }
 
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c
new file mode 100644
index 0000000..dae9aa6
--- /dev/null
+++ b/arch/arm/mach-shmobile/setup-emev2.c
@@ -0,0 +1,452 @@
+/*
+ * Emma Mobile EV2 processor support
+ *
+ * Copyright (C) 2012  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/gpio-em.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/of_irq.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/emev2.h>
+#include <mach/irqs.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/hardware/gic.h>
+
+static struct map_desc emev2_io_desc[] __initdata = {
+#ifdef CONFIG_SMP
+	/* 128K entity map for 0xe0100000 (SMU) */
+	{
+		.virtual	= 0xe0100000,
+		.pfn		= __phys_to_pfn(0xe0100000),
+		.length		= SZ_128K,
+		.type		= MT_DEVICE
+	},
+	/* 2M mapping for SCU + L2 controller */
+	{
+		.virtual	= 0xf0000000,
+		.pfn		= __phys_to_pfn(0x1e000000),
+		.length		= SZ_2M,
+		.type		= MT_DEVICE
+	},
+#endif
+};
+
+void __init emev2_map_io(void)
+{
+	iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc));
+}
+
+/* UART */
+static struct resource uart0_resources[] = {
+	[0]	= {
+		.start	= 0xe1020000,
+		.end	= 0xe1020037,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1]	= {
+		.start	= 40,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device uart0_device = {
+	.name		= "serial8250-em",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(uart0_resources),
+	.resource	= uart0_resources,
+};
+
+static struct resource uart1_resources[] = {
+	[0]	= {
+		.start	= 0xe1030000,
+		.end	= 0xe1030037,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1]	= {
+		.start	= 41,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device uart1_device = {
+	.name		= "serial8250-em",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(uart1_resources),
+	.resource	= uart1_resources,
+};
+
+static struct resource uart2_resources[] = {
+	[0]	= {
+		.start	= 0xe1040000,
+		.end	= 0xe1040037,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1]	= {
+		.start	= 42,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device uart2_device = {
+	.name		= "serial8250-em",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(uart2_resources),
+	.resource	= uart2_resources,
+};
+
+static struct resource uart3_resources[] = {
+	[0]	= {
+		.start	= 0xe1050000,
+		.end	= 0xe1050037,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1]	= {
+		.start	= 43,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device uart3_device = {
+	.name		= "serial8250-em",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(uart3_resources),
+	.resource	= uart3_resources,
+};
+
+/* STI */
+static struct resource sti_resources[] = {
+	[0] = {
+		.name	= "STI",
+		.start	= 0xe0180000,
+		.end	= 0xe0180053,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 157,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device sti_device = {
+	.name		= "em_sti",
+	.id		= 0,
+	.resource	= sti_resources,
+	.num_resources	= ARRAY_SIZE(sti_resources),
+};
+
+
+/* GIO */
+static struct gpio_em_config gio0_config = {
+	.gpio_base = 0,
+	.irq_base = EMEV2_GPIO_IRQ(0),
+	.number_of_pins = 32,
+};
+
+static struct resource gio0_resources[] = {
+	[0] = {
+		.name	= "GIO_000",
+		.start	= 0xe0050000,
+		.end	= 0xe005002b,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "GIO_000",
+		.start	= 0xe0050040,
+		.end	= 0xe005005f,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= 99,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		.start	= 100,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device gio0_device = {
+	.name		= "em_gio",
+	.id		= 0,
+	.resource	= gio0_resources,
+	.num_resources	= ARRAY_SIZE(gio0_resources),
+	.dev		= {
+		.platform_data	= &gio0_config,
+	},
+};
+
+static struct gpio_em_config gio1_config = {
+	.gpio_base = 32,
+	.irq_base = EMEV2_GPIO_IRQ(32),
+	.number_of_pins = 32,
+};
+
+static struct resource gio1_resources[] = {
+	[0] = {
+		.name	= "GIO_032",
+		.start	= 0xe0050080,
+		.end	= 0xe00500ab,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "GIO_032",
+		.start	= 0xe00500c0,
+		.end	= 0xe00500df,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= 101,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		.start	= 102,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device gio1_device = {
+	.name		= "em_gio",
+	.id		= 1,
+	.resource	= gio1_resources,
+	.num_resources	= ARRAY_SIZE(gio1_resources),
+	.dev		= {
+		.platform_data	= &gio1_config,
+	},
+};
+
+static struct gpio_em_config gio2_config = {
+	.gpio_base = 64,
+	.irq_base = EMEV2_GPIO_IRQ(64),
+	.number_of_pins = 32,
+};
+
+static struct resource gio2_resources[] = {
+	[0] = {
+		.name	= "GIO_064",
+		.start	= 0xe0050100,
+		.end	= 0xe005012b,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "GIO_064",
+		.start	= 0xe0050140,
+		.end	= 0xe005015f,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= 103,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		.start	= 104,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device gio2_device = {
+	.name		= "em_gio",
+	.id		= 2,
+	.resource	= gio2_resources,
+	.num_resources	= ARRAY_SIZE(gio2_resources),
+	.dev		= {
+		.platform_data	= &gio2_config,
+	},
+};
+
+static struct gpio_em_config gio3_config = {
+	.gpio_base = 96,
+	.irq_base = EMEV2_GPIO_IRQ(96),
+	.number_of_pins = 32,
+};
+
+static struct resource gio3_resources[] = {
+	[0] = {
+		.name	= "GIO_096",
+		.start	= 0xe0050100,
+		.end	= 0xe005012b,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "GIO_096",
+		.start	= 0xe0050140,
+		.end	= 0xe005015f,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= 105,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		.start	= 106,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device gio3_device = {
+	.name		= "em_gio",
+	.id		= 3,
+	.resource	= gio3_resources,
+	.num_resources	= ARRAY_SIZE(gio3_resources),
+	.dev		= {
+		.platform_data	= &gio3_config,
+	},
+};
+
+static struct gpio_em_config gio4_config = {
+	.gpio_base = 128,
+	.irq_base = EMEV2_GPIO_IRQ(128),
+	.number_of_pins = 31,
+};
+
+static struct resource gio4_resources[] = {
+	[0] = {
+		.name	= "GIO_128",
+		.start	= 0xe0050200,
+		.end	= 0xe005022b,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "GIO_128",
+		.start	= 0xe0050240,
+		.end	= 0xe005025f,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= 107,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		.start	= 108,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device gio4_device = {
+	.name		= "em_gio",
+	.id		= 4,
+	.resource	= gio4_resources,
+	.num_resources	= ARRAY_SIZE(gio4_resources),
+	.dev		= {
+		.platform_data	= &gio4_config,
+	},
+};
+
+static struct platform_device *emev2_early_devices[] __initdata = {
+	&uart0_device,
+	&uart1_device,
+	&uart2_device,
+	&uart3_device,
+};
+
+static struct platform_device *emev2_late_devices[] __initdata = {
+	&sti_device,
+	&gio0_device,
+	&gio1_device,
+	&gio2_device,
+	&gio3_device,
+	&gio4_device,
+};
+
+void __init emev2_add_standard_devices(void)
+{
+	emev2_clock_init();
+
+	platform_add_devices(emev2_early_devices,
+			     ARRAY_SIZE(emev2_early_devices));
+
+	platform_add_devices(emev2_late_devices,
+			     ARRAY_SIZE(emev2_late_devices));
+}
+
+void __init emev2_init_delay(void)
+{
+	shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */
+}
+
+void __init emev2_add_early_devices(void)
+{
+	emev2_init_delay();
+
+	early_platform_add_devices(emev2_early_devices,
+				   ARRAY_SIZE(emev2_early_devices));
+
+	/* setup early console here as well */
+	shmobile_setup_console();
+}
+
+void __init emev2_init_irq(void)
+{
+	void __iomem *gic_dist_base;
+	void __iomem *gic_cpu_base;
+
+	/* Static mappings, never released */
+	gic_dist_base = ioremap(0xe0028000, PAGE_SIZE);
+	gic_cpu_base = ioremap(0xe0020000, PAGE_SIZE);
+	BUG_ON(!gic_dist_base || !gic_cpu_base);
+
+	/* Use GIC to handle interrupts */
+	gic_init(0, 29, gic_dist_base, gic_cpu_base);
+}
+
+#ifdef CONFIG_USE_OF
+static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = {
+	{ }
+};
+
+void __init emev2_add_standard_devices_dt(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+			     emev2_auxdata_lookup, NULL);
+}
+
+static const struct of_device_id emev2_dt_irq_match[] = {
+	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{},
+};
+
+static const char *emev2_boards_compat_dt[] __initdata = {
+	"renesas,emev2",
+	NULL,
+};
+
+void __init emev2_init_irq_dt(void)
+{
+	of_irq_init(emev2_dt_irq_match);
+}
+
+DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
+	.init_early	= emev2_init_delay,
+	.nr_irqs	= NR_IRQS_LEGACY,
+	.init_irq	= emev2_init_irq_dt,
+	.handle_irq	= gic_handle_irq,
+	.init_machine	= emev2_add_standard_devices_dt,
+	.timer		= &shmobile_timer,
+	.dt_compat	= emev2_boards_compat_dt,
+MACHINE_END
+
+#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index 14edb5c..ec4eb49 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -18,6 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -60,6 +61,12 @@
 void __init r8a7740_map_io(void)
 {
 	iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc));
+
+	/*
+	 * DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't
+	 * enough to allocate the frame buffer memory.
+	 */
+	init_consistent_dma_size(12 << 20);
 }
 
 /* SCIFA0 */
@@ -350,19 +357,19 @@
 	i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10);
 	i2c_read(reg, ICSTART); /* dummy read */
 
-	mdelay(100);
+	udelay(10);
 
 	i2c_write(reg, ICCR, 0x01);
-	i2c_read(reg, ICCR);
 	i2c_write(reg, ICSTART, 0x00);
-	i2c_read(reg, ICSTART);
+
+	udelay(10);
 
 	i2c_write(reg, ICCR, 0x10);
-	mdelay(100);
+	udelay(10);
 	i2c_write(reg, ICCR, 0x00);
-	mdelay(100);
+	udelay(10);
 	i2c_write(reg, ICCR, 0x10);
-	mdelay(100);
+	udelay(10);
 
 	iounmap(reg);
 }
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 2fe8f83..6a4bd58 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
 #include <linux/uio_driver.h>
 #include <linux/delay.h>
 #include <linux/input.h>
@@ -461,6 +462,16 @@
 		.chcr		= DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
 		.mid_rid	= 0xce,
 	}, {
+		.slave_id	= SHDMA_SLAVE_FSIA_TX,
+		.addr		= 0xfe1f0024,
+		.chcr		= DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+		.mid_rid	= 0xb1,
+	}, {
+		.slave_id	= SHDMA_SLAVE_FSIA_RX,
+		.addr		= 0xfe1f0020,
+		.chcr		= DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+		.mid_rid	= 0xb2,
+	}, {
 		.slave_id	= SHDMA_SLAVE_MMCIF_TX,
 		.addr		= 0xe6bd0034,
 		.chcr		= DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
@@ -1092,3 +1103,50 @@
 	/* override timer setup with soc-specific code */
 	shmobile_timer.init = sh7372_earlytimer_init;
 }
+
+#ifdef CONFIG_USE_OF
+
+void __init sh7372_add_early_devices_dt(void)
+{
+	shmobile_setup_delay(800, 1, 3); /* Cortex-A8 @ 800MHz */
+
+	early_platform_add_devices(sh7372_early_devices,
+				   ARRAY_SIZE(sh7372_early_devices));
+
+	/* setup early console here as well */
+	shmobile_setup_console();
+}
+
+static const struct of_dev_auxdata sh7372_auxdata_lookup[] __initconst = {
+	{ }
+};
+
+void __init sh7372_add_standard_devices_dt(void)
+{
+	/* clocks are setup late during boot in the case of DT */
+	sh7372_clock_init();
+
+	platform_add_devices(sh7372_early_devices,
+			    ARRAY_SIZE(sh7372_early_devices));
+
+	of_platform_populate(NULL, of_default_bus_match_table,
+			     sh7372_auxdata_lookup, NULL);
+}
+
+static const char *sh7372_boards_compat_dt[] __initdata = {
+	"renesas,sh7372",
+	NULL,
+};
+
+DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)")
+	.map_io		= sh7372_map_io,
+	.init_early	= sh7372_add_early_devices_dt,
+	.nr_irqs	= NR_IRQS_LEGACY,
+	.init_irq	= sh7372_init_irq,
+	.handle_irq	= shmobile_handle_irq_intc,
+	.init_machine	= sh7372_add_standard_devices_dt,
+	.timer		= &shmobile_timer,
+	.dt_compat	= sh7372_boards_compat_dt,
+MACHINE_END
+
+#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c
new file mode 100644
index 0000000..6a35c4a
--- /dev/null
+++ b/arch/arm/mach-shmobile/smp-emev2.c
@@ -0,0 +1,97 @@
+/*
+ * SMP support for Emma Mobile EV2
+ *
+ * Copyright (C) 2012  Renesas Solutions Corp.
+ * Copyright (C) 2012  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <mach/common.h>
+#include <mach/emev2.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+#include <asm/hardware/gic.h>
+#include <asm/cacheflush.h>
+
+#define EMEV2_SCU_BASE 0x1e000000
+
+static DEFINE_SPINLOCK(scu_lock);
+static void __iomem *scu_base;
+
+static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
+{
+	unsigned long tmp;
+
+	/* we assume this code is running on a different cpu
+	 * than the one that is changing coherency setting */
+	spin_lock(&scu_lock);
+	tmp = readl(scu_base + 8);
+	tmp &= ~clr;
+	tmp |= set;
+	writel(tmp, scu_base + 8);
+	spin_unlock(&scu_lock);
+
+}
+
+unsigned int __init emev2_get_core_count(void)
+{
+	if (!scu_base) {
+		scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE);
+		emev2_clock_init(); /* need ioremapped SMU */
+	}
+
+	WARN_ON_ONCE(!scu_base);
+
+	return scu_base ? scu_get_core_count(scu_base) : 1;
+}
+
+int emev2_platform_cpu_kill(unsigned int cpu)
+{
+	return 0; /* not supported yet */
+}
+
+void __cpuinit emev2_secondary_init(unsigned int cpu)
+{
+	gic_secondary_init(0);
+}
+
+int __cpuinit emev2_boot_secondary(unsigned int cpu)
+{
+	cpu = cpu_logical_map(cpu);
+
+	/* enable cache coherency */
+	modify_scu_cpu_psr(0, 3 << (cpu * 8));
+
+	/* Tell ROM loader about our vector (in headsmp.S) */
+	emev2_set_boot_vector(__pa(shmobile_secondary_vector));
+
+	gic_raise_softirq(cpumask_of(cpu), 1);
+	return 0;
+}
+
+void __init emev2_smp_prepare_cpus(void)
+{
+	int cpu = cpu_logical_map(0);
+
+	scu_enable(scu_base);
+
+	/* enable cache coherency on CPU0 */
+	modify_scu_cpu_psr(0, 3 << (cpu * 8));
+}
diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c
index 8b79e79..a689197 100644
--- a/arch/arm/mach-shmobile/timer.c
+++ b/arch/arm/mach-shmobile/timer.c
@@ -19,9 +19,27 @@
  *
  */
 #include <linux/platform_device.h>
+#include <linux/delay.h>
 #include <asm/mach/time.h>
 #include <asm/smp_twd.h>
 
+void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz,
+				 unsigned int mult, unsigned int div)
+{
+	/* calculate a worst-case loops-per-jiffy value
+	 * based on maximum cpu core mhz setting and the
+	 * __delay() implementation in arch/arm/lib/delay.S
+	 *
+	 * this will result in a longer delay than expected
+	 * when the cpu core runs on lower frequencies.
+	 */
+
+	unsigned int value = (1000000 * mult) / (HZ * div);
+
+	if (!preset_lpj)
+		preset_lpj = max_cpu_core_mhz * value;
+}
+
 static void __init shmobile_late_time_init(void)
 {
 	/*
diff --git a/arch/arm/mach-spear3xx/Kconfig b/arch/arm/mach-spear3xx/Kconfig
index 2cee6b0..8bd3729 100644
--- a/arch/arm/mach-spear3xx/Kconfig
+++ b/arch/arm/mach-spear3xx/Kconfig
@@ -5,39 +5,22 @@
 if ARCH_SPEAR3XX
 
 menu "SPEAr3xx Implementations"
-config BOARD_SPEAR300_EVB
-	bool "SPEAr300 Evaluation Board"
-	select MACH_SPEAR300
-	help
-	  Supports ST SPEAr300 Evaluation Board
-
-config BOARD_SPEAR310_EVB
-	bool "SPEAr310 Evaluation Board"
-	select MACH_SPEAR310
-	help
-	  Supports ST SPEAr310 Evaluation Board
-
-config BOARD_SPEAR320_EVB
-	bool "SPEAr320 Evaluation Board"
-	select MACH_SPEAR320
-	help
-	  Supports ST SPEAr320 Evaluation Board
-
-endmenu
-
 config MACH_SPEAR300
-	bool "SPEAr300"
+	bool "SPEAr300 Machine support with Device Tree"
+	select PINCTRL_SPEAR300
 	help
-	  Supports ST SPEAr300 Machine
+	  Supports ST SPEAr300 machine configured via the device-tree
 
 config MACH_SPEAR310
-	bool "SPEAr310"
+	bool "SPEAr310 Machine support with Device Tree"
+	select PINCTRL_SPEAR310
 	help
-	  Supports ST SPEAr310 Machine
+	  Supports ST SPEAr310 machine configured via the device-tree
 
 config MACH_SPEAR320
-	bool "SPEAr320"
+	bool "SPEAr320 Machine support with Device Tree"
+	select PINCTRL_SPEAR320
 	help
-	  Supports ST SPEAr320 Machine
-
+	  Supports ST SPEAr320 machine configured via the device-tree
+endmenu
 endif #ARCH_SPEAR3XX
diff --git a/arch/arm/mach-spear3xx/Makefile b/arch/arm/mach-spear3xx/Makefile
index b248624..17b5d83 100644
--- a/arch/arm/mach-spear3xx/Makefile
+++ b/arch/arm/mach-spear3xx/Makefile
@@ -3,24 +3,13 @@
 #
 
 # common files
-obj-y	+= spear3xx.o clock.o
+obj-$(CONFIG_ARCH_SPEAR3XX)	+= spear3xx.o clock.o
 
 # spear300 specific files
 obj-$(CONFIG_MACH_SPEAR300) += spear300.o
 
-# spear300 boards files
-obj-$(CONFIG_BOARD_SPEAR300_EVB) += spear300_evb.o
-
-
 # spear310 specific files
 obj-$(CONFIG_MACH_SPEAR310) += spear310.o
 
-# spear310 boards files
-obj-$(CONFIG_BOARD_SPEAR310_EVB) += spear310_evb.o
-
-
 # spear320 specific files
 obj-$(CONFIG_MACH_SPEAR320) += spear320.o
-
-# spear320 boards files
-obj-$(CONFIG_BOARD_SPEAR320_EVB) += spear320_evb.o
diff --git a/arch/arm/mach-spear3xx/Makefile.boot b/arch/arm/mach-spear3xx/Makefile.boot
index 4674a4c..d93e217 100644
--- a/arch/arm/mach-spear3xx/Makefile.boot
+++ b/arch/arm/mach-spear3xx/Makefile.boot
@@ -1,3 +1,7 @@
 zreladdr-y	+= 0x00008000
 params_phys-y	:= 0x00000100
 initrd_phys-y	:= 0x00800000
+
+dtb-$(CONFIG_MACH_SPEAR300)	+= spear300-evb.dtb
+dtb-$(CONFIG_MACH_SPEAR310)	+= spear310-evb.dtb
+dtb-$(CONFIG_MACH_SPEAR320)	+= spear320-evb.dtb
diff --git a/arch/arm/mach-spear3xx/clock.c b/arch/arm/mach-spear3xx/clock.c
index 6c4841f..cd6c110 100644
--- a/arch/arm/mach-spear3xx/clock.c
+++ b/arch/arm/mach-spear3xx/clock.c
@@ -11,12 +11,112 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/clkdev.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/of_platform.h>
 #include <asm/mach-types.h>
 #include <plat/clock.h>
 #include <mach/misc_regs.h>
+#include <mach/spear.h>
+
+#define PLL1_CTR		(MISC_BASE + 0x008)
+#define PLL1_FRQ		(MISC_BASE + 0x00C)
+#define PLL1_MOD		(MISC_BASE + 0x010)
+#define PLL2_CTR		(MISC_BASE + 0x014)
+/* PLL_CTR register masks */
+#define PLL_ENABLE		2
+#define PLL_MODE_SHIFT		4
+#define PLL_MODE_MASK		0x3
+#define PLL_MODE_NORMAL		0
+#define PLL_MODE_FRACTION	1
+#define PLL_MODE_DITH_DSB	2
+#define PLL_MODE_DITH_SSB	3
+
+#define PLL2_FRQ		(MISC_BASE + 0x018)
+/* PLL FRQ register masks */
+#define PLL_DIV_N_SHIFT		0
+#define PLL_DIV_N_MASK		0xFF
+#define PLL_DIV_P_SHIFT		8
+#define PLL_DIV_P_MASK		0x7
+#define PLL_NORM_FDBK_M_SHIFT	24
+#define PLL_NORM_FDBK_M_MASK	0xFF
+#define PLL_DITH_FDBK_M_SHIFT	16
+#define PLL_DITH_FDBK_M_MASK	0xFFFF
+
+#define PLL2_MOD		(MISC_BASE + 0x01C)
+#define PLL_CLK_CFG		(MISC_BASE + 0x020)
+#define CORE_CLK_CFG		(MISC_BASE + 0x024)
+/* CORE CLK CFG register masks */
+#define PLL_HCLK_RATIO_SHIFT	10
+#define PLL_HCLK_RATIO_MASK	0x3
+#define HCLK_PCLK_RATIO_SHIFT	8
+#define HCLK_PCLK_RATIO_MASK	0x3
+
+#define PERIP_CLK_CFG		(MISC_BASE + 0x028)
+/* PERIP_CLK_CFG register masks */
+#define UART_CLK_SHIFT		4
+#define UART_CLK_MASK		0x1
+#define FIRDA_CLK_SHIFT		5
+#define FIRDA_CLK_MASK		0x3
+#define GPT0_CLK_SHIFT		8
+#define GPT1_CLK_SHIFT		11
+#define GPT2_CLK_SHIFT		12
+#define GPT_CLK_MASK		0x1
+#define AUX_CLK_PLL3_VAL	0
+#define AUX_CLK_PLL1_VAL	1
+
+#define PERIP1_CLK_ENB		(MISC_BASE + 0x02C)
+/* PERIP1_CLK_ENB register masks */
+#define UART_CLK_ENB		3
+#define SSP_CLK_ENB		5
+#define I2C_CLK_ENB		7
+#define JPEG_CLK_ENB		8
+#define FIRDA_CLK_ENB		10
+#define GPT1_CLK_ENB		11
+#define GPT2_CLK_ENB		12
+#define ADC_CLK_ENB		15
+#define RTC_CLK_ENB		17
+#define GPIO_CLK_ENB		18
+#define DMA_CLK_ENB		19
+#define SMI_CLK_ENB		21
+#define GMAC_CLK_ENB		23
+#define USBD_CLK_ENB		24
+#define USBH_CLK_ENB		25
+#define C3_CLK_ENB		31
+
+#define RAS_CLK_ENB		(MISC_BASE + 0x034)
+
+#define PRSC1_CLK_CFG		(MISC_BASE + 0x044)
+#define PRSC2_CLK_CFG		(MISC_BASE + 0x048)
+#define PRSC3_CLK_CFG		(MISC_BASE + 0x04C)
+/* gpt synthesizer register masks */
+#define GPT_MSCALE_SHIFT	0
+#define GPT_MSCALE_MASK		0xFFF
+#define GPT_NSCALE_SHIFT	12
+#define GPT_NSCALE_MASK		0xF
+
+#define AMEM_CLK_CFG		(MISC_BASE + 0x050)
+#define EXPI_CLK_CFG		(MISC_BASE + 0x054)
+#define CLCD_CLK_SYNT		(MISC_BASE + 0x05C)
+#define FIRDA_CLK_SYNT		(MISC_BASE + 0x060)
+#define UART_CLK_SYNT		(MISC_BASE + 0x064)
+#define GMAC_CLK_SYNT		(MISC_BASE + 0x068)
+#define RAS1_CLK_SYNT		(MISC_BASE + 0x06C)
+#define RAS2_CLK_SYNT		(MISC_BASE + 0x070)
+#define RAS3_CLK_SYNT		(MISC_BASE + 0x074)
+#define RAS4_CLK_SYNT		(MISC_BASE + 0x078)
+/* aux clk synthesiser register masks for irda to ras4 */
+#define AUX_SYNT_ENB		31
+#define AUX_EQ_SEL_SHIFT	30
+#define AUX_EQ_SEL_MASK		1
+#define AUX_EQ1_SEL		0
+#define AUX_EQ2_SEL		1
+#define AUX_XSCALE_SHIFT	16
+#define AUX_XSCALE_MASK		0xFFF
+#define AUX_YSCALE_SHIFT	0
+#define AUX_YSCALE_MASK		0xFFF
 
 /* root clks */
 /* 32 KHz oscillator clock */
@@ -411,6 +511,21 @@
 	.recalc = &follow_parent,
 };
 
+/* clock derived from usbh clk */
+/* usbh0 clock */
+static struct clk usbh0_clk = {
+	.flags = ALWAYS_ENABLED,
+	.pclk = &usbh_clk,
+	.recalc = &follow_parent,
+};
+
+/* usbh1 clock */
+static struct clk usbh1_clk = {
+	.flags = ALWAYS_ENABLED,
+	.pclk = &usbh_clk,
+	.recalc = &follow_parent,
+};
+
 /* clock derived from ahb clk */
 /* apb masks structure */
 static struct bus_clk_masks apb_masks = {
@@ -652,109 +767,126 @@
 
 /* array of all spear 3xx clock lookups */
 static struct clk_lookup spear_clk_lookups[] = {
-	{ .con_id = "apb_pclk",		.clk = &dummy_apb_pclk},
+	CLKDEV_INIT(NULL, "apb_pclk", &dummy_apb_pclk),
 	/* root clks */
-	{ .con_id = "osc_32k_clk",	.clk = &osc_32k_clk},
-	{ .con_id = "osc_24m_clk",	.clk = &osc_24m_clk},
+	CLKDEV_INIT(NULL, "osc_32k_clk", &osc_32k_clk),
+	CLKDEV_INIT(NULL, "osc_24m_clk", &osc_24m_clk),
 	/* clock derived from 32 KHz osc clk */
-	{ .dev_id = "rtc-spear",	.clk = &rtc_clk},
+	CLKDEV_INIT("fc900000.rtc", NULL, &rtc_clk),
 	/* clock derived from 24 MHz osc clk */
-	{ .con_id = "pll1_clk",		.clk = &pll1_clk},
-	{ .con_id = "pll3_48m_clk",	.clk = &pll3_48m_clk},
-	{ .dev_id = "wdt",		.clk = &wdt_clk},
+	CLKDEV_INIT(NULL, "pll1_clk", &pll1_clk),
+	CLKDEV_INIT(NULL, "pll3_48m_clk", &pll3_48m_clk),
+	CLKDEV_INIT("fc880000.wdt", NULL, &wdt_clk),
 	/* clock derived from pll1 clk */
-	{ .con_id = "cpu_clk",		.clk = &cpu_clk},
-	{ .con_id = "ahb_clk",		.clk = &ahb_clk},
-	{ .con_id = "uart_synth_clk",	.clk = &uart_synth_clk},
-	{ .con_id = "firda_synth_clk",	.clk = &firda_synth_clk},
-	{ .con_id = "gpt0_synth_clk",	.clk = &gpt0_synth_clk},
-	{ .con_id = "gpt1_synth_clk",	.clk = &gpt1_synth_clk},
-	{ .con_id = "gpt2_synth_clk",	.clk = &gpt2_synth_clk},
-	{ .dev_id = "uart",		.clk = &uart_clk},
-	{ .dev_id = "firda",		.clk = &firda_clk},
-	{ .dev_id = "gpt0",		.clk = &gpt0_clk},
-	{ .dev_id = "gpt1",		.clk = &gpt1_clk},
-	{ .dev_id = "gpt2",		.clk = &gpt2_clk},
+	CLKDEV_INIT(NULL, "cpu_clk", &cpu_clk),
+	CLKDEV_INIT(NULL, "ahb_clk", &ahb_clk),
+	CLKDEV_INIT(NULL, "uart_synth_clk", &uart_synth_clk),
+	CLKDEV_INIT(NULL, "firda_synth_clk", &firda_synth_clk),
+	CLKDEV_INIT(NULL, "gpt0_synth_clk", &gpt0_synth_clk),
+	CLKDEV_INIT(NULL, "gpt1_synth_clk", &gpt1_synth_clk),
+	CLKDEV_INIT(NULL, "gpt2_synth_clk", &gpt2_synth_clk),
+	CLKDEV_INIT("d0000000.serial", NULL, &uart_clk),
+	CLKDEV_INIT("firda", NULL, &firda_clk),
+	CLKDEV_INIT("gpt0", NULL, &gpt0_clk),
+	CLKDEV_INIT("gpt1", NULL, &gpt1_clk),
+	CLKDEV_INIT("gpt2", NULL, &gpt2_clk),
 	/* clock derived from pll3 clk */
-	{ .dev_id = "designware_udc",   .clk = &usbd_clk},
-	{ .con_id = "usbh_clk",		.clk = &usbh_clk},
+	CLKDEV_INIT("designware_udc", NULL, &usbd_clk),
+	CLKDEV_INIT(NULL, "usbh_clk", &usbh_clk),
+	/* clock derived from usbh clk */
+	CLKDEV_INIT(NULL, "usbh.0_clk", &usbh0_clk),
+	CLKDEV_INIT(NULL, "usbh.1_clk", &usbh1_clk),
 	/* clock derived from ahb clk */
-	{ .con_id = "apb_clk",		.clk = &apb_clk},
-	{ .dev_id = "i2c_designware.0",	.clk = &i2c_clk},
-	{ .dev_id = "dma",		.clk = &dma_clk},
-	{ .dev_id = "jpeg",		.clk = &jpeg_clk},
-	{ .dev_id = "gmac",		.clk = &gmac_clk},
-	{ .dev_id = "smi",		.clk = &smi_clk},
-	{ .dev_id = "c3",		.clk = &c3_clk},
+	CLKDEV_INIT(NULL, "apb_clk", &apb_clk),
+	CLKDEV_INIT("d0180000.i2c", NULL, &i2c_clk),
+	CLKDEV_INIT("fc400000.dma", NULL, &dma_clk),
+	CLKDEV_INIT("jpeg", NULL, &jpeg_clk),
+	CLKDEV_INIT("e0800000.eth", NULL, &gmac_clk),
+	CLKDEV_INIT("fc000000.flash", NULL, &smi_clk),
+	CLKDEV_INIT("c3", NULL, &c3_clk),
 	/* clock derived from apb clk */
-	{ .dev_id = "adc",		.clk = &adc_clk},
-	{ .dev_id = "ssp-pl022.0",	.clk = &ssp0_clk},
-	{ .dev_id = "gpio",		.clk = &gpio_clk},
+	CLKDEV_INIT("adc", NULL, &adc_clk),
+	CLKDEV_INIT("d0100000.spi", NULL, &ssp0_clk),
+	CLKDEV_INIT("fc980000.gpio", NULL, &gpio_clk),
 };
 
 /* array of all spear 300 clock lookups */
 #ifdef CONFIG_MACH_SPEAR300
 static struct clk_lookup spear300_clk_lookups[] = {
-	{ .dev_id = "clcd",		.clk = &clcd_clk},
-	{ .con_id = "fsmc",		.clk = &fsmc_clk},
-	{ .dev_id = "gpio1",		.clk = &gpio1_clk},
-	{ .dev_id = "keyboard",		.clk = &kbd_clk},
-	{ .dev_id = "sdhci",		.clk = &sdhci_clk},
+	CLKDEV_INIT("60000000.clcd", NULL, &clcd_clk),
+	CLKDEV_INIT("94000000.flash", NULL, &fsmc_clk),
+	CLKDEV_INIT("a9000000.gpio", NULL, &gpio1_clk),
+	CLKDEV_INIT("a0000000.kbd", NULL, &kbd_clk),
+	CLKDEV_INIT("70000000.sdhci", NULL, &sdhci_clk),
 };
+
+void __init spear300_clk_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++)
+		clk_register(&spear_clk_lookups[i]);
+
+	for (i = 0; i < ARRAY_SIZE(spear300_clk_lookups); i++)
+		clk_register(&spear300_clk_lookups[i]);
+
+	clk_init();
+}
 #endif
 
 /* array of all spear 310 clock lookups */
 #ifdef CONFIG_MACH_SPEAR310
 static struct clk_lookup spear310_clk_lookups[] = {
-	{ .con_id = "fsmc",		.clk = &fsmc_clk},
-	{ .con_id = "emi",		.clk = &emi_clk},
-	{ .dev_id = "uart1",		.clk = &uart1_clk},
-	{ .dev_id = "uart2",		.clk = &uart2_clk},
-	{ .dev_id = "uart3",		.clk = &uart3_clk},
-	{ .dev_id = "uart4",		.clk = &uart4_clk},
-	{ .dev_id = "uart5",		.clk = &uart5_clk},
+	CLKDEV_INIT("44000000.flash", NULL, &fsmc_clk),
+	CLKDEV_INIT(NULL, "emi", &emi_clk),
+	CLKDEV_INIT("b2000000.serial", NULL, &uart1_clk),
+	CLKDEV_INIT("b2080000.serial", NULL, &uart2_clk),
+	CLKDEV_INIT("b2100000.serial", NULL, &uart3_clk),
+	CLKDEV_INIT("b2180000.serial", NULL, &uart4_clk),
+	CLKDEV_INIT("b2200000.serial", NULL, &uart5_clk),
 };
+
+void __init spear310_clk_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++)
+		clk_register(&spear_clk_lookups[i]);
+
+	for (i = 0; i < ARRAY_SIZE(spear310_clk_lookups); i++)
+		clk_register(&spear310_clk_lookups[i]);
+
+	clk_init();
+}
 #endif
 
 /* array of all spear 320 clock lookups */
 #ifdef CONFIG_MACH_SPEAR320
 static struct clk_lookup spear320_clk_lookups[] = {
-	{ .dev_id = "clcd",		.clk = &clcd_clk},
-	{ .con_id = "fsmc",		.clk = &fsmc_clk},
-	{ .dev_id = "i2c_designware.1",	.clk = &i2c1_clk},
-	{ .con_id = "emi",		.clk = &emi_clk},
-	{ .dev_id = "pwm",		.clk = &pwm_clk},
-	{ .dev_id = "sdhci",		.clk = &sdhci_clk},
-	{ .dev_id = "c_can_platform.0",	.clk = &can0_clk},
-	{ .dev_id = "c_can_platform.1",	.clk = &can1_clk},
-	{ .dev_id = "ssp-pl022.1",	.clk = &ssp1_clk},
-	{ .dev_id = "ssp-pl022.2",	.clk = &ssp2_clk},
-	{ .dev_id = "uart1",		.clk = &uart1_clk},
-	{ .dev_id = "uart2",		.clk = &uart2_clk},
+	CLKDEV_INIT("90000000.clcd", NULL, &clcd_clk),
+	CLKDEV_INIT("4c000000.flash", NULL, &fsmc_clk),
+	CLKDEV_INIT("a7000000.i2c", NULL, &i2c1_clk),
+	CLKDEV_INIT(NULL, "emi", &emi_clk),
+	CLKDEV_INIT("pwm", NULL, &pwm_clk),
+	CLKDEV_INIT("70000000.sdhci", NULL, &sdhci_clk),
+	CLKDEV_INIT("c_can_platform.0", NULL, &can0_clk),
+	CLKDEV_INIT("c_can_platform.1", NULL, &can1_clk),
+	CLKDEV_INIT("a5000000.spi", NULL, &ssp1_clk),
+	CLKDEV_INIT("a6000000.spi", NULL, &ssp2_clk),
+	CLKDEV_INIT("a3000000.serial", NULL, &uart1_clk),
+	CLKDEV_INIT("a4000000.serial", NULL, &uart2_clk),
 };
-#endif
 
-void __init spear3xx_clk_init(void)
+void __init spear320_clk_init(void)
 {
-	int i, cnt;
-	struct clk_lookup *lookups;
-
-	if (machine_is_spear300()) {
-		cnt = ARRAY_SIZE(spear300_clk_lookups);
-		lookups = spear300_clk_lookups;
-	} else if (machine_is_spear310()) {
-		cnt = ARRAY_SIZE(spear310_clk_lookups);
-		lookups = spear310_clk_lookups;
-	} else {
-		cnt = ARRAY_SIZE(spear320_clk_lookups);
-		lookups = spear320_clk_lookups;
-	}
+	int i;
 
 	for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++)
 		clk_register(&spear_clk_lookups[i]);
 
-	for (i = 0; i < cnt; i++)
-		clk_register(&lookups[i]);
+	for (i = 0; i < ARRAY_SIZE(spear320_clk_lookups); i++)
+		clk_register(&spear320_clk_lookups[i]);
 
 	clk_init();
 }
+#endif
diff --git a/arch/arm/mach-spear3xx/include/mach/generic.h b/arch/arm/mach-spear3xx/include/mach/generic.h
index 14276e5..bdb3045 100644
--- a/arch/arm/mach-spear3xx/include/mach/generic.h
+++ b/arch/arm/mach-spear3xx/include/mach/generic.h
@@ -14,188 +14,40 @@
 #ifndef __MACH_GENERIC_H
 #define __MACH_GENERIC_H
 
+#include <linux/amba/pl08x.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/amba/bus.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
-#include <plat/padmux.h>
-
-/* spear3xx declarations */
-/*
- * Each GPT has 2 timer channels
- * Following GPT channels will be used as clock source and clockevent
- */
-#define SPEAR_GPT0_BASE		SPEAR3XX_ML1_TMR_BASE
-#define SPEAR_GPT0_CHAN0_IRQ	SPEAR3XX_IRQ_CPU_GPT1_1
-#define SPEAR_GPT0_CHAN1_IRQ	SPEAR3XX_IRQ_CPU_GPT1_2
 
 /* Add spear3xx family device structure declarations here */
-extern struct amba_device spear3xx_gpio_device;
-extern struct amba_device spear3xx_uart_device;
 extern struct sys_timer spear3xx_timer;
+extern struct pl022_ssp_controller pl022_plat_data;
+extern struct pl08x_platform_data pl080_plat_data;
 
 /* Add spear3xx family function declarations here */
-void __init spear3xx_clk_init(void);
-void __init spear_setup_timer(void);
+void __init spear_setup_timer(resource_size_t base, int irq);
 void __init spear3xx_map_io(void);
-void __init spear3xx_init_irq(void);
-void __init spear3xx_init(void);
+void __init spear3xx_dt_init_irq(void);
 
 void spear_restart(char, const char *);
 
-/* pad mux declarations */
-#define PMX_FIRDA_MASK		(1 << 14)
-#define PMX_I2C_MASK		(1 << 13)
-#define PMX_SSP_CS_MASK		(1 << 12)
-#define PMX_SSP_MASK		(1 << 11)
-#define PMX_MII_MASK		(1 << 10)
-#define PMX_GPIO_PIN0_MASK	(1 << 9)
-#define PMX_GPIO_PIN1_MASK	(1 << 8)
-#define PMX_GPIO_PIN2_MASK	(1 << 7)
-#define PMX_GPIO_PIN3_MASK	(1 << 6)
-#define PMX_GPIO_PIN4_MASK	(1 << 5)
-#define PMX_GPIO_PIN5_MASK	(1 << 4)
-#define PMX_UART0_MODEM_MASK	(1 << 3)
-#define PMX_UART0_MASK		(1 << 2)
-#define PMX_TIMER_3_4_MASK	(1 << 1)
-#define PMX_TIMER_1_2_MASK	(1 << 0)
-
-/* pad mux devices */
-extern struct pmx_dev spear3xx_pmx_firda;
-extern struct pmx_dev spear3xx_pmx_i2c;
-extern struct pmx_dev spear3xx_pmx_ssp_cs;
-extern struct pmx_dev spear3xx_pmx_ssp;
-extern struct pmx_dev spear3xx_pmx_mii;
-extern struct pmx_dev spear3xx_pmx_gpio_pin0;
-extern struct pmx_dev spear3xx_pmx_gpio_pin1;
-extern struct pmx_dev spear3xx_pmx_gpio_pin2;
-extern struct pmx_dev spear3xx_pmx_gpio_pin3;
-extern struct pmx_dev spear3xx_pmx_gpio_pin4;
-extern struct pmx_dev spear3xx_pmx_gpio_pin5;
-extern struct pmx_dev spear3xx_pmx_uart0_modem;
-extern struct pmx_dev spear3xx_pmx_uart0;
-extern struct pmx_dev spear3xx_pmx_timer_3_4;
-extern struct pmx_dev spear3xx_pmx_timer_1_2;
-
-#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
-/* padmux plgpio devices */
-extern struct pmx_dev spear3xx_pmx_plgpio_0_1;
-extern struct pmx_dev spear3xx_pmx_plgpio_2_3;
-extern struct pmx_dev spear3xx_pmx_plgpio_4_5;
-extern struct pmx_dev spear3xx_pmx_plgpio_6_9;
-extern struct pmx_dev spear3xx_pmx_plgpio_10_27;
-extern struct pmx_dev spear3xx_pmx_plgpio_28;
-extern struct pmx_dev spear3xx_pmx_plgpio_29;
-extern struct pmx_dev spear3xx_pmx_plgpio_30;
-extern struct pmx_dev spear3xx_pmx_plgpio_31;
-extern struct pmx_dev spear3xx_pmx_plgpio_32;
-extern struct pmx_dev spear3xx_pmx_plgpio_33;
-extern struct pmx_dev spear3xx_pmx_plgpio_34_36;
-extern struct pmx_dev spear3xx_pmx_plgpio_37_42;
-extern struct pmx_dev spear3xx_pmx_plgpio_43_44_47_48;
-extern struct pmx_dev spear3xx_pmx_plgpio_45_46_49_50;
-#endif
-
 /* spear300 declarations */
 #ifdef CONFIG_MACH_SPEAR300
-/* Add spear300 machine device structure declarations here */
-extern struct amba_device spear300_gpio1_device;
-
-/* pad mux modes */
-extern struct pmx_mode spear300_nand_mode;
-extern struct pmx_mode spear300_nor_mode;
-extern struct pmx_mode spear300_photo_frame_mode;
-extern struct pmx_mode spear300_lend_ip_phone_mode;
-extern struct pmx_mode spear300_hend_ip_phone_mode;
-extern struct pmx_mode spear300_lend_wifi_phone_mode;
-extern struct pmx_mode spear300_hend_wifi_phone_mode;
-extern struct pmx_mode spear300_ata_pabx_wi2s_mode;
-extern struct pmx_mode spear300_ata_pabx_i2s_mode;
-extern struct pmx_mode spear300_caml_lcdw_mode;
-extern struct pmx_mode spear300_camu_lcd_mode;
-extern struct pmx_mode spear300_camu_wlcd_mode;
-extern struct pmx_mode spear300_caml_lcd_mode;
-
-/* pad mux devices */
-extern struct pmx_dev spear300_pmx_fsmc_2_chips;
-extern struct pmx_dev spear300_pmx_fsmc_4_chips;
-extern struct pmx_dev spear300_pmx_keyboard;
-extern struct pmx_dev spear300_pmx_clcd;
-extern struct pmx_dev spear300_pmx_telecom_gpio;
-extern struct pmx_dev spear300_pmx_telecom_tdm;
-extern struct pmx_dev spear300_pmx_telecom_spi_cs_i2c_clk;
-extern struct pmx_dev spear300_pmx_telecom_camera;
-extern struct pmx_dev spear300_pmx_telecom_dac;
-extern struct pmx_dev spear300_pmx_telecom_i2s;
-extern struct pmx_dev spear300_pmx_telecom_boot_pins;
-extern struct pmx_dev spear300_pmx_telecom_sdhci_4bit;
-extern struct pmx_dev spear300_pmx_telecom_sdhci_8bit;
-extern struct pmx_dev spear300_pmx_gpio1;
-
-/* Add spear300 machine function declarations here */
-void __init spear300_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
-		u8 pmx_dev_count);
+void __init spear300_clk_init(void);
 
 #endif /* CONFIG_MACH_SPEAR300 */
 
 /* spear310 declarations */
 #ifdef CONFIG_MACH_SPEAR310
-/* Add spear310 machine device structure declarations here */
-
-/* pad mux devices */
-extern struct pmx_dev spear310_pmx_emi_cs_0_1_4_5;
-extern struct pmx_dev spear310_pmx_emi_cs_2_3;
-extern struct pmx_dev spear310_pmx_uart1;
-extern struct pmx_dev spear310_pmx_uart2;
-extern struct pmx_dev spear310_pmx_uart3_4_5;
-extern struct pmx_dev spear310_pmx_fsmc;
-extern struct pmx_dev spear310_pmx_rs485_0_1;
-extern struct pmx_dev spear310_pmx_tdm0;
-
-/* Add spear310 machine function declarations here */
-void __init spear310_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
-		u8 pmx_dev_count);
+void __init spear310_clk_init(void);
 
 #endif /* CONFIG_MACH_SPEAR310 */
 
 /* spear320 declarations */
 #ifdef CONFIG_MACH_SPEAR320
-/* Add spear320 machine device structure declarations here */
-
-/* pad mux modes */
-extern struct pmx_mode spear320_auto_net_smii_mode;
-extern struct pmx_mode spear320_auto_net_mii_mode;
-extern struct pmx_mode spear320_auto_exp_mode;
-extern struct pmx_mode spear320_small_printers_mode;
-
-/* pad mux devices */
-extern struct pmx_dev spear320_pmx_clcd;
-extern struct pmx_dev spear320_pmx_emi;
-extern struct pmx_dev spear320_pmx_fsmc;
-extern struct pmx_dev spear320_pmx_spp;
-extern struct pmx_dev spear320_pmx_sdhci;
-extern struct pmx_dev spear320_pmx_i2s;
-extern struct pmx_dev spear320_pmx_uart1;
-extern struct pmx_dev spear320_pmx_uart1_modem;
-extern struct pmx_dev spear320_pmx_uart2;
-extern struct pmx_dev spear320_pmx_touchscreen;
-extern struct pmx_dev spear320_pmx_can;
-extern struct pmx_dev spear320_pmx_sdhci_led;
-extern struct pmx_dev spear320_pmx_pwm0;
-extern struct pmx_dev spear320_pmx_pwm1;
-extern struct pmx_dev spear320_pmx_pwm2;
-extern struct pmx_dev spear320_pmx_pwm3;
-extern struct pmx_dev spear320_pmx_ssp1;
-extern struct pmx_dev spear320_pmx_ssp2;
-extern struct pmx_dev spear320_pmx_mii1;
-extern struct pmx_dev spear320_pmx_smii0;
-extern struct pmx_dev spear320_pmx_smii1;
-extern struct pmx_dev spear320_pmx_i2c1;
-
-/* Add spear320 machine function declarations here */
-void __init spear320_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
-		u8 pmx_dev_count);
+void __init spear320_clk_init(void);
 
 #endif /* CONFIG_MACH_SPEAR320 */
 
diff --git a/arch/arm/mach-spear3xx/include/mach/hardware.h b/arch/arm/mach-spear3xx/include/mach/hardware.h
index 4660c0d..40a8c17 100644
--- a/arch/arm/mach-spear3xx/include/mach/hardware.h
+++ b/arch/arm/mach-spear3xx/include/mach/hardware.h
@@ -1,23 +1 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/hardware.h
- *
- * Hardware definitions for SPEAr3xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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 __MACH_HARDWARE_H
-#define __MACH_HARDWARE_H
-
-#include <plat/hardware.h>
-#include <mach/spear.h>
-
-/* Vitual to physical translation of statically mapped space */
-#define IO_ADDRESS(x)		(x | 0xF0000000)
-
-#endif /* __MACH_HARDWARE_H */
+/* empty */
diff --git a/arch/arm/mach-spear3xx/include/mach/irqs.h b/arch/arm/mach-spear3xx/include/mach/irqs.h
index 6e26544..319620a 100644
--- a/arch/arm/mach-spear3xx/include/mach/irqs.h
+++ b/arch/arm/mach-spear3xx/include/mach/irqs.h
@@ -14,141 +14,15 @@
 #ifndef __MACH_IRQS_H
 #define __MACH_IRQS_H
 
-/* SPEAr3xx IRQ definitions */
-#define SPEAR3XX_IRQ_HW_ACCEL_MOD_0		0
+/* FIXME: probe all these from DT */
 #define SPEAR3XX_IRQ_INTRCOMM_RAS_ARM		1
 #define SPEAR3XX_IRQ_CPU_GPT1_1			2
-#define SPEAR3XX_IRQ_CPU_GPT1_2			3
-#define SPEAR3XX_IRQ_BASIC_GPT1_1		4
-#define SPEAR3XX_IRQ_BASIC_GPT1_2		5
-#define SPEAR3XX_IRQ_BASIC_GPT2_1		6
-#define SPEAR3XX_IRQ_BASIC_GPT2_2		7
-#define SPEAR3XX_IRQ_BASIC_DMA			8
-#define SPEAR3XX_IRQ_BASIC_SMI			9
-#define SPEAR3XX_IRQ_BASIC_RTC			10
-#define SPEAR3XX_IRQ_BASIC_GPIO			11
-#define SPEAR3XX_IRQ_BASIC_WDT			12
-#define SPEAR3XX_IRQ_DDR_CONTROLLER		13
-#define SPEAR3XX_IRQ_SYS_ERROR			14
-#define SPEAR3XX_IRQ_WAKEUP_RCV			15
-#define SPEAR3XX_IRQ_JPEG			16
-#define SPEAR3XX_IRQ_IRDA			17
-#define SPEAR3XX_IRQ_ADC			18
-#define SPEAR3XX_IRQ_UART			19
-#define SPEAR3XX_IRQ_SSP			20
-#define SPEAR3XX_IRQ_I2C			21
-#define SPEAR3XX_IRQ_MAC_1			22
-#define SPEAR3XX_IRQ_MAC_2			23
-#define SPEAR3XX_IRQ_USB_DEV			24
-#define SPEAR3XX_IRQ_USB_H_OHCI_0		25
-#define SPEAR3XX_IRQ_USB_H_EHCI_0		26
-#define SPEAR3XX_IRQ_USB_H_EHCI_1		SPEAR3XX_IRQ_USB_H_EHCI_0
-#define SPEAR3XX_IRQ_USB_H_OHCI_1		27
 #define SPEAR3XX_IRQ_GEN_RAS_1			28
 #define SPEAR3XX_IRQ_GEN_RAS_2			29
 #define SPEAR3XX_IRQ_GEN_RAS_3			30
-#define SPEAR3XX_IRQ_HW_ACCEL_MOD_1		31
 #define SPEAR3XX_IRQ_VIC_END			32
-
 #define SPEAR3XX_VIRQ_START			SPEAR3XX_IRQ_VIC_END
 
-/* SPEAr300 Virtual irq definitions */
-/* IRQs sharing IRQ_GEN_RAS_1 */
-#define SPEAR300_VIRQ_IT_PERS_S			(SPEAR3XX_VIRQ_START + 0)
-#define SPEAR300_VIRQ_IT_CHANGE_S		(SPEAR3XX_VIRQ_START + 1)
-#define SPEAR300_VIRQ_I2S			(SPEAR3XX_VIRQ_START + 2)
-#define SPEAR300_VIRQ_TDM			(SPEAR3XX_VIRQ_START + 3)
-#define SPEAR300_VIRQ_CAMERA_L			(SPEAR3XX_VIRQ_START + 4)
-#define SPEAR300_VIRQ_CAMERA_F			(SPEAR3XX_VIRQ_START + 5)
-#define SPEAR300_VIRQ_CAMERA_V			(SPEAR3XX_VIRQ_START + 6)
-#define SPEAR300_VIRQ_KEYBOARD			(SPEAR3XX_VIRQ_START + 7)
-#define SPEAR300_VIRQ_GPIO1			(SPEAR3XX_VIRQ_START + 8)
-
-/* IRQs sharing IRQ_GEN_RAS_3 */
-#define SPEAR300_IRQ_CLCD			SPEAR3XX_IRQ_GEN_RAS_3
-
-/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
-#define SPEAR300_IRQ_SDHCI			SPEAR3XX_IRQ_INTRCOMM_RAS_ARM
-
-/* SPEAr310 Virtual irq definitions */
-/* IRQs sharing IRQ_GEN_RAS_1 */
-#define SPEAR310_VIRQ_SMII0			(SPEAR3XX_VIRQ_START + 0)
-#define SPEAR310_VIRQ_SMII1			(SPEAR3XX_VIRQ_START + 1)
-#define SPEAR310_VIRQ_SMII2			(SPEAR3XX_VIRQ_START + 2)
-#define SPEAR310_VIRQ_SMII3			(SPEAR3XX_VIRQ_START + 3)
-#define SPEAR310_VIRQ_WAKEUP_SMII0		(SPEAR3XX_VIRQ_START + 4)
-#define SPEAR310_VIRQ_WAKEUP_SMII1		(SPEAR3XX_VIRQ_START + 5)
-#define SPEAR310_VIRQ_WAKEUP_SMII2		(SPEAR3XX_VIRQ_START + 6)
-#define SPEAR310_VIRQ_WAKEUP_SMII3		(SPEAR3XX_VIRQ_START + 7)
-
-/* IRQs sharing IRQ_GEN_RAS_2 */
-#define SPEAR310_VIRQ_UART1			(SPEAR3XX_VIRQ_START + 8)
-#define SPEAR310_VIRQ_UART2			(SPEAR3XX_VIRQ_START + 9)
-#define SPEAR310_VIRQ_UART3			(SPEAR3XX_VIRQ_START + 10)
-#define SPEAR310_VIRQ_UART4			(SPEAR3XX_VIRQ_START + 11)
-#define SPEAR310_VIRQ_UART5			(SPEAR3XX_VIRQ_START + 12)
-
-/* IRQs sharing IRQ_GEN_RAS_3 */
-#define SPEAR310_VIRQ_EMI			(SPEAR3XX_VIRQ_START + 13)
-#define SPEAR310_VIRQ_PLGPIO			(SPEAR3XX_VIRQ_START + 14)
-
-/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
-#define SPEAR310_VIRQ_TDM_HDLC			(SPEAR3XX_VIRQ_START + 15)
-#define SPEAR310_VIRQ_RS485_0			(SPEAR3XX_VIRQ_START + 16)
-#define SPEAR310_VIRQ_RS485_1			(SPEAR3XX_VIRQ_START + 17)
-
-/* SPEAr320 Virtual irq definitions */
-/* IRQs sharing IRQ_GEN_RAS_1 */
-#define SPEAR320_VIRQ_EMI			(SPEAR3XX_VIRQ_START + 0)
-#define SPEAR320_VIRQ_CLCD			(SPEAR3XX_VIRQ_START + 1)
-#define SPEAR320_VIRQ_SPP			(SPEAR3XX_VIRQ_START + 2)
-
-/* IRQs sharing IRQ_GEN_RAS_2 */
-#define SPEAR320_IRQ_SDHCI			SPEAR3XX_IRQ_GEN_RAS_2
-
-/* IRQs sharing IRQ_GEN_RAS_3 */
-#define SPEAR320_VIRQ_PLGPIO			(SPEAR3XX_VIRQ_START + 3)
-#define SPEAR320_VIRQ_I2S_PLAY			(SPEAR3XX_VIRQ_START + 4)
-#define SPEAR320_VIRQ_I2S_REC			(SPEAR3XX_VIRQ_START + 5)
-
-/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
-#define SPEAR320_VIRQ_CANU			(SPEAR3XX_VIRQ_START + 6)
-#define SPEAR320_VIRQ_CANL			(SPEAR3XX_VIRQ_START + 7)
-#define SPEAR320_VIRQ_UART1			(SPEAR3XX_VIRQ_START + 8)
-#define SPEAR320_VIRQ_UART2			(SPEAR3XX_VIRQ_START + 9)
-#define SPEAR320_VIRQ_SSP1			(SPEAR3XX_VIRQ_START + 10)
-#define SPEAR320_VIRQ_SSP2			(SPEAR3XX_VIRQ_START + 11)
-#define SPEAR320_VIRQ_SMII0			(SPEAR3XX_VIRQ_START + 12)
-#define SPEAR320_VIRQ_MII1_SMII1		(SPEAR3XX_VIRQ_START + 13)
-#define SPEAR320_VIRQ_WAKEUP_SMII0		(SPEAR3XX_VIRQ_START + 14)
-#define SPEAR320_VIRQ_WAKEUP_MII1_SMII1		(SPEAR3XX_VIRQ_START + 15)
-#define SPEAR320_VIRQ_I2C1			(SPEAR3XX_VIRQ_START + 16)
-
-/*
- * GPIO pins virtual irqs
- * Use the lowest number for the GPIO virtual IRQs base on which subarchs
- * we have compiled in
- */
-#if defined(CONFIG_MACH_SPEAR310)
-#define SPEAR3XX_GPIO_INT_BASE			(SPEAR3XX_VIRQ_START + 18)
-#elif defined(CONFIG_MACH_SPEAR320)
-#define SPEAR3XX_GPIO_INT_BASE			(SPEAR3XX_VIRQ_START + 17)
-#else
-#define SPEAR3XX_GPIO_INT_BASE			(SPEAR3XX_VIRQ_START + 9)
-#endif
-
-#define SPEAR300_GPIO1_INT_BASE			(SPEAR3XX_GPIO_INT_BASE + 8)
-#define SPEAR3XX_PLGPIO_COUNT	102
-
-#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
-#define SPEAR3XX_PLGPIO_INT_BASE		(SPEAR3XX_GPIO_INT_BASE + 8)
-#define SPEAR3XX_GPIO_INT_END			(SPEAR3XX_PLGPIO_INT_BASE + \
-							SPEAR3XX_PLGPIO_COUNT)
-#else
-#define SPEAR3XX_GPIO_INT_END	(SPEAR300_GPIO1_INT_BASE + 8)
-#endif
-
-#define SPEAR3XX_VIRQ_END	SPEAR3XX_GPIO_INT_END
-#define NR_IRQS			SPEAR3XX_VIRQ_END
+#define NR_IRQS			160
 
 #endif /* __MACH_IRQS_H */
diff --git a/arch/arm/mach-spear3xx/include/mach/misc_regs.h b/arch/arm/mach-spear3xx/include/mach/misc_regs.h
index 5bd8cd8..e0ab72e 100644
--- a/arch/arm/mach-spear3xx/include/mach/misc_regs.h
+++ b/arch/arm/mach-spear3xx/include/mach/misc_regs.h
@@ -14,151 +14,7 @@
 #ifndef __MACH_MISC_REGS_H
 #define __MACH_MISC_REGS_H
 
-#include <mach/hardware.h>
-
 #define MISC_BASE		IOMEM(VA_SPEAR3XX_ICM3_MISC_REG_BASE)
-
-#define SOC_CFG_CTR		(MISC_BASE + 0x000)
-#define DIAG_CFG_CTR		(MISC_BASE + 0x004)
-#define PLL1_CTR		(MISC_BASE + 0x008)
-#define PLL1_FRQ		(MISC_BASE + 0x00C)
-#define PLL1_MOD		(MISC_BASE + 0x010)
-#define PLL2_CTR		(MISC_BASE + 0x014)
-/* PLL_CTR register masks */
-#define PLL_ENABLE		2
-#define PLL_MODE_SHIFT		4
-#define PLL_MODE_MASK		0x3
-#define PLL_MODE_NORMAL		0
-#define PLL_MODE_FRACTION	1
-#define PLL_MODE_DITH_DSB	2
-#define PLL_MODE_DITH_SSB	3
-
-#define PLL2_FRQ		(MISC_BASE + 0x018)
-/* PLL FRQ register masks */
-#define PLL_DIV_N_SHIFT		0
-#define PLL_DIV_N_MASK		0xFF
-#define PLL_DIV_P_SHIFT		8
-#define PLL_DIV_P_MASK		0x7
-#define PLL_NORM_FDBK_M_SHIFT	24
-#define PLL_NORM_FDBK_M_MASK	0xFF
-#define PLL_DITH_FDBK_M_SHIFT	16
-#define PLL_DITH_FDBK_M_MASK	0xFFFF
-
-#define PLL2_MOD		(MISC_BASE + 0x01C)
-#define PLL_CLK_CFG		(MISC_BASE + 0x020)
-#define CORE_CLK_CFG		(MISC_BASE + 0x024)
-/* CORE CLK CFG register masks */
-#define PLL_HCLK_RATIO_SHIFT	10
-#define PLL_HCLK_RATIO_MASK	0x3
-#define HCLK_PCLK_RATIO_SHIFT	8
-#define HCLK_PCLK_RATIO_MASK	0x3
-
-#define PERIP_CLK_CFG		(MISC_BASE + 0x028)
-/* PERIP_CLK_CFG register masks */
-#define UART_CLK_SHIFT		4
-#define UART_CLK_MASK		0x1
-#define FIRDA_CLK_SHIFT		5
-#define FIRDA_CLK_MASK		0x3
-#define GPT0_CLK_SHIFT		8
-#define GPT1_CLK_SHIFT		11
-#define GPT2_CLK_SHIFT		12
-#define GPT_CLK_MASK		0x1
-#define AUX_CLK_PLL3_VAL	0
-#define AUX_CLK_PLL1_VAL	1
-
-#define PERIP1_CLK_ENB		(MISC_BASE + 0x02C)
-/* PERIP1_CLK_ENB register masks */
-#define UART_CLK_ENB		3
-#define SSP_CLK_ENB		5
-#define I2C_CLK_ENB		7
-#define JPEG_CLK_ENB		8
-#define FIRDA_CLK_ENB		10
-#define GPT1_CLK_ENB		11
-#define GPT2_CLK_ENB		12
-#define ADC_CLK_ENB		15
-#define RTC_CLK_ENB		17
-#define GPIO_CLK_ENB		18
-#define DMA_CLK_ENB		19
-#define SMI_CLK_ENB		21
-#define GMAC_CLK_ENB		23
-#define USBD_CLK_ENB		24
-#define USBH_CLK_ENB		25
-#define C3_CLK_ENB		31
-
-#define SOC_CORE_ID		(MISC_BASE + 0x030)
-#define RAS_CLK_ENB		(MISC_BASE + 0x034)
-#define PERIP1_SOF_RST		(MISC_BASE + 0x038)
-/* PERIP1_SOF_RST register masks */
-#define JPEG_SOF_RST		8
-
-#define SOC_USER_ID		(MISC_BASE + 0x03C)
-#define RAS_SOF_RST		(MISC_BASE + 0x040)
-#define PRSC1_CLK_CFG		(MISC_BASE + 0x044)
-#define PRSC2_CLK_CFG		(MISC_BASE + 0x048)
-#define PRSC3_CLK_CFG		(MISC_BASE + 0x04C)
-/* gpt synthesizer register masks */
-#define GPT_MSCALE_SHIFT	0
-#define GPT_MSCALE_MASK		0xFFF
-#define GPT_NSCALE_SHIFT	12
-#define GPT_NSCALE_MASK		0xF
-
-#define AMEM_CLK_CFG		(MISC_BASE + 0x050)
-#define EXPI_CLK_CFG		(MISC_BASE + 0x054)
-#define CLCD_CLK_SYNT		(MISC_BASE + 0x05C)
-#define FIRDA_CLK_SYNT		(MISC_BASE + 0x060)
-#define UART_CLK_SYNT		(MISC_BASE + 0x064)
-#define GMAC_CLK_SYNT		(MISC_BASE + 0x068)
-#define RAS1_CLK_SYNT		(MISC_BASE + 0x06C)
-#define RAS2_CLK_SYNT		(MISC_BASE + 0x070)
-#define RAS3_CLK_SYNT		(MISC_BASE + 0x074)
-#define RAS4_CLK_SYNT		(MISC_BASE + 0x078)
-/* aux clk synthesiser register masks for irda to ras4 */
-#define AUX_SYNT_ENB		31
-#define AUX_EQ_SEL_SHIFT	30
-#define AUX_EQ_SEL_MASK		1
-#define AUX_EQ1_SEL		0
-#define AUX_EQ2_SEL		1
-#define AUX_XSCALE_SHIFT	16
-#define AUX_XSCALE_MASK		0xFFF
-#define AUX_YSCALE_SHIFT	0
-#define AUX_YSCALE_MASK		0xFFF
-
-#define ICM1_ARB_CFG		(MISC_BASE + 0x07C)
-#define ICM2_ARB_CFG		(MISC_BASE + 0x080)
-#define ICM3_ARB_CFG		(MISC_BASE + 0x084)
-#define ICM4_ARB_CFG		(MISC_BASE + 0x088)
-#define ICM5_ARB_CFG		(MISC_BASE + 0x08C)
-#define ICM6_ARB_CFG		(MISC_BASE + 0x090)
-#define ICM7_ARB_CFG		(MISC_BASE + 0x094)
-#define ICM8_ARB_CFG		(MISC_BASE + 0x098)
-#define ICM9_ARB_CFG		(MISC_BASE + 0x09C)
 #define DMA_CHN_CFG		(MISC_BASE + 0x0A0)
-#define USB2_PHY_CFG		(MISC_BASE + 0x0A4)
-#define GMAC_CFG_CTR		(MISC_BASE + 0x0A8)
-#define EXPI_CFG_CTR		(MISC_BASE + 0x0AC)
-#define PRC1_LOCK_CTR		(MISC_BASE + 0x0C0)
-#define PRC2_LOCK_CTR		(MISC_BASE + 0x0C4)
-#define PRC3_LOCK_CTR		(MISC_BASE + 0x0C8)
-#define PRC4_LOCK_CTR		(MISC_BASE + 0x0CC)
-#define PRC1_IRQ_CTR		(MISC_BASE + 0x0D0)
-#define PRC2_IRQ_CTR		(MISC_BASE + 0x0D4)
-#define PRC3_IRQ_CTR		(MISC_BASE + 0x0D8)
-#define PRC4_IRQ_CTR		(MISC_BASE + 0x0DC)
-#define PWRDOWN_CFG_CTR		(MISC_BASE + 0x0E0)
-#define COMPSSTL_1V8_CFG	(MISC_BASE + 0x0E4)
-#define COMPSSTL_2V5_CFG	(MISC_BASE + 0x0E8)
-#define COMPCOR_3V3_CFG		(MISC_BASE + 0x0EC)
-#define SSTLPAD_CFG_CTR		(MISC_BASE + 0x0F0)
-#define BIST1_CFG_CTR		(MISC_BASE + 0x0F4)
-#define BIST2_CFG_CTR		(MISC_BASE + 0x0F8)
-#define BIST3_CFG_CTR		(MISC_BASE + 0x0FC)
-#define BIST4_CFG_CTR		(MISC_BASE + 0x100)
-#define BIST5_CFG_CTR		(MISC_BASE + 0x104)
-#define BIST1_STS_RES		(MISC_BASE + 0x108)
-#define BIST2_STS_RES		(MISC_BASE + 0x10C)
-#define BIST3_STS_RES		(MISC_BASE + 0x110)
-#define BIST4_STS_RES		(MISC_BASE + 0x114)
-#define BIST5_STS_RES		(MISC_BASE + 0x118)
-#define SYSERR_CFG_CTR		(MISC_BASE + 0x11C)
 
 #endif /* __MACH_MISC_REGS_H */
diff --git a/arch/arm/mach-spear3xx/include/mach/spear.h b/arch/arm/mach-spear3xx/include/mach/spear.h
index 63fd983..6d4dadc 100644
--- a/arch/arm/mach-spear3xx/include/mach/spear.h
+++ b/arch/arm/mach-spear3xx/include/mach/spear.h
@@ -15,60 +15,27 @@
 #define __MACH_SPEAR3XX_H
 
 #include <asm/memory.h>
-#include <mach/spear300.h>
-#include <mach/spear310.h>
-#include <mach/spear320.h>
-
-#define SPEAR3XX_ML_SDRAM_BASE		UL(0x00000000)
-
-#define SPEAR3XX_ICM9_BASE		UL(0xC0000000)
 
 /* ICM1 - Low speed connection */
 #define SPEAR3XX_ICM1_2_BASE		UL(0xD0000000)
+#define VA_SPEAR3XX_ICM1_2_BASE		UL(0xFD000000)
 #define SPEAR3XX_ICM1_UART_BASE		UL(0xD0000000)
-#define VA_SPEAR3XX_ICM1_UART_BASE	IO_ADDRESS(SPEAR3XX_ICM1_UART_BASE)
-#define SPEAR3XX_ICM1_ADC_BASE		UL(0xD0080000)
+#define VA_SPEAR3XX_ICM1_UART_BASE	(VA_SPEAR3XX_ICM1_2_BASE | SPEAR3XX_ICM1_UART_BASE)
 #define SPEAR3XX_ICM1_SSP_BASE		UL(0xD0100000)
-#define SPEAR3XX_ICM1_I2C_BASE		UL(0xD0180000)
-#define SPEAR3XX_ICM1_JPEG_BASE		UL(0xD0800000)
-#define SPEAR3XX_ICM1_IRDA_BASE		UL(0xD1000000)
-#define SPEAR3XX_ICM1_SRAM_BASE		UL(0xD2800000)
-
-/* ICM2 - Application Subsystem */
-#define SPEAR3XX_ICM2_HWACCEL0_BASE	UL(0xD8800000)
-#define SPEAR3XX_ICM2_HWACCEL1_BASE	UL(0xD9000000)
-
-/* ICM4 - High Speed Connection */
-#define SPEAR3XX_ICM4_BASE		UL(0xE0000000)
-#define SPEAR3XX_ICM4_MII_BASE		UL(0xE0800000)
-#define SPEAR3XX_ICM4_USBD_FIFO_BASE	UL(0xE1000000)
-#define SPEAR3XX_ICM4_USBD_CSR_BASE	UL(0xE1100000)
-#define SPEAR3XX_ICM4_USBD_PLDT_BASE	UL(0xE1200000)
-#define SPEAR3XX_ICM4_USB_EHCI0_1_BASE	UL(0xE1800000)
-#define SPEAR3XX_ICM4_USB_OHCI0_BASE	UL(0xE1900000)
-#define SPEAR3XX_ICM4_USB_OHCI1_BASE	UL(0xE2100000)
-#define SPEAR3XX_ICM4_USB_ARB_BASE	UL(0xE2800000)
 
 /* ML1 - Multi Layer CPU Subsystem */
 #define SPEAR3XX_ICM3_ML1_2_BASE	UL(0xF0000000)
-#define SPEAR3XX_ML1_TMR_BASE		UL(0xF0000000)
-#define SPEAR3XX_ML1_VIC_BASE		UL(0xF1100000)
-#define VA_SPEAR3XX_ML1_VIC_BASE	IO_ADDRESS(SPEAR3XX_ML1_VIC_BASE)
+#define VA_SPEAR6XX_ML_CPU_BASE		UL(0xF0000000)
+#define SPEAR3XX_CPU_TMR_BASE		UL(0xF0000000)
 
 /* ICM3 - Basic Subsystem */
-#define SPEAR3XX_ICM3_SMEM_BASE		UL(0xF8000000)
 #define SPEAR3XX_ICM3_SMI_CTRL_BASE	UL(0xFC000000)
+#define VA_SPEAR3XX_ICM3_SMI_CTRL_BASE	UL(0xFC000000)
 #define SPEAR3XX_ICM3_DMA_BASE		UL(0xFC400000)
-#define SPEAR3XX_ICM3_SDRAM_CTRL_BASE	UL(0xFC600000)
-#define SPEAR3XX_ICM3_TMR0_BASE		UL(0xFC800000)
-#define SPEAR3XX_ICM3_WDT_BASE		UL(0xFC880000)
-#define SPEAR3XX_ICM3_RTC_BASE		UL(0xFC900000)
-#define SPEAR3XX_ICM3_GPIO_BASE		UL(0xFC980000)
 #define SPEAR3XX_ICM3_SYS_CTRL_BASE	UL(0xFCA00000)
-#define VA_SPEAR3XX_ICM3_SYS_CTRL_BASE	IO_ADDRESS(SPEAR3XX_ICM3_SYS_CTRL_BASE)
+#define VA_SPEAR3XX_ICM3_SYS_CTRL_BASE	(VA_SPEAR3XX_ICM3_SMI_CTRL_BASE | SPEAR3XX_ICM3_SYS_CTRL_BASE)
 #define SPEAR3XX_ICM3_MISC_REG_BASE	UL(0xFCA80000)
-#define VA_SPEAR3XX_ICM3_MISC_REG_BASE	IO_ADDRESS(SPEAR3XX_ICM3_MISC_REG_BASE)
-#define SPEAR3XX_ICM3_TMR1_BASE		UL(0xFCB00000)
+#define VA_SPEAR3XX_ICM3_MISC_REG_BASE	(VA_SPEAR3XX_ICM3_SMI_CTRL_BASE | SPEAR3XX_ICM3_MISC_REG_BASE)
 
 /* Debug uart for linux, will be used for debug and uncompress messages */
 #define SPEAR_DBG_UART_BASE		SPEAR3XX_ICM1_UART_BASE
diff --git a/arch/arm/mach-spear3xx/include/mach/spear300.h b/arch/arm/mach-spear3xx/include/mach/spear300.h
deleted file mode 100644
index 3b6ea07..0000000
--- a/arch/arm/mach-spear3xx/include/mach/spear300.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/spear300.h
- *
- * SPEAr300 Machine specific definition
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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.
- */
-
-#ifdef	CONFIG_MACH_SPEAR300
-
-#ifndef __MACH_SPEAR300_H
-#define __MACH_SPEAR300_H
-
-/* Base address of various IPs */
-#define SPEAR300_TELECOM_BASE		UL(0x50000000)
-
-/* Interrupt registers offsets and masks */
-#define SPEAR300_INT_ENB_MASK_REG	0x54
-#define SPEAR300_INT_STS_MASK_REG	0x58
-#define SPEAR300_IT_PERS_S_IRQ_MASK	(1 << 0)
-#define SPEAR300_IT_CHANGE_S_IRQ_MASK	(1 << 1)
-#define SPEAR300_I2S_IRQ_MASK		(1 << 2)
-#define SPEAR300_TDM_IRQ_MASK		(1 << 3)
-#define SPEAR300_CAMERA_L_IRQ_MASK	(1 << 4)
-#define SPEAR300_CAMERA_F_IRQ_MASK	(1 << 5)
-#define SPEAR300_CAMERA_V_IRQ_MASK	(1 << 6)
-#define SPEAR300_KEYBOARD_IRQ_MASK	(1 << 7)
-#define SPEAR300_GPIO1_IRQ_MASK		(1 << 8)
-
-#define SPEAR300_SHIRQ_RAS1_MASK	0x1FF
-
-#define SPEAR300_CLCD_BASE		UL(0x60000000)
-#define SPEAR300_SDHCI_BASE		UL(0x70000000)
-#define SPEAR300_NAND_0_BASE		UL(0x80000000)
-#define SPEAR300_NAND_1_BASE		UL(0x84000000)
-#define SPEAR300_NAND_2_BASE		UL(0x88000000)
-#define SPEAR300_NAND_3_BASE		UL(0x8c000000)
-#define SPEAR300_NOR_0_BASE		UL(0x90000000)
-#define SPEAR300_NOR_1_BASE		UL(0x91000000)
-#define SPEAR300_NOR_2_BASE		UL(0x92000000)
-#define SPEAR300_NOR_3_BASE		UL(0x93000000)
-#define SPEAR300_FSMC_BASE		UL(0x94000000)
-#define SPEAR300_SOC_CONFIG_BASE	UL(0x99000000)
-#define SPEAR300_KEYBOARD_BASE		UL(0xA0000000)
-#define SPEAR300_GPIO_BASE		UL(0xA9000000)
-
-#endif /* __MACH_SPEAR300_H */
-
-#endif /* CONFIG_MACH_SPEAR300 */
diff --git a/arch/arm/mach-spear3xx/include/mach/spear310.h b/arch/arm/mach-spear3xx/include/mach/spear310.h
deleted file mode 100644
index 1567d0da..0000000
--- a/arch/arm/mach-spear3xx/include/mach/spear310.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/spear310.h
- *
- * SPEAr310 Machine specific definition
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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.
- */
-
-#ifdef	CONFIG_MACH_SPEAR310
-
-#ifndef __MACH_SPEAR310_H
-#define __MACH_SPEAR310_H
-
-#define SPEAR310_NAND_BASE		UL(0x40000000)
-#define SPEAR310_FSMC_BASE		UL(0x44000000)
-#define SPEAR310_UART1_BASE		UL(0xB2000000)
-#define SPEAR310_UART2_BASE		UL(0xB2080000)
-#define SPEAR310_UART3_BASE		UL(0xB2100000)
-#define SPEAR310_UART4_BASE		UL(0xB2180000)
-#define SPEAR310_UART5_BASE		UL(0xB2200000)
-#define SPEAR310_HDLC_BASE		UL(0xB2800000)
-#define SPEAR310_RS485_0_BASE		UL(0xB3000000)
-#define SPEAR310_RS485_1_BASE		UL(0xB3800000)
-#define SPEAR310_SOC_CONFIG_BASE	UL(0xB4000000)
-
-/* Interrupt registers offsets and masks */
-#define SPEAR310_INT_STS_MASK_REG	0x04
-#define SPEAR310_SMII0_IRQ_MASK		(1 << 0)
-#define SPEAR310_SMII1_IRQ_MASK		(1 << 1)
-#define SPEAR310_SMII2_IRQ_MASK		(1 << 2)
-#define SPEAR310_SMII3_IRQ_MASK		(1 << 3)
-#define SPEAR310_WAKEUP_SMII0_IRQ_MASK	(1 << 4)
-#define SPEAR310_WAKEUP_SMII1_IRQ_MASK	(1 << 5)
-#define SPEAR310_WAKEUP_SMII2_IRQ_MASK	(1 << 6)
-#define SPEAR310_WAKEUP_SMII3_IRQ_MASK	(1 << 7)
-#define SPEAR310_UART1_IRQ_MASK		(1 << 8)
-#define SPEAR310_UART2_IRQ_MASK		(1 << 9)
-#define SPEAR310_UART3_IRQ_MASK		(1 << 10)
-#define SPEAR310_UART4_IRQ_MASK		(1 << 11)
-#define SPEAR310_UART5_IRQ_MASK		(1 << 12)
-#define SPEAR310_EMI_IRQ_MASK		(1 << 13)
-#define SPEAR310_TDM_HDLC_IRQ_MASK	(1 << 14)
-#define SPEAR310_RS485_0_IRQ_MASK	(1 << 15)
-#define SPEAR310_RS485_1_IRQ_MASK	(1 << 16)
-
-#define SPEAR310_SHIRQ_RAS1_MASK	0x000FF
-#define SPEAR310_SHIRQ_RAS2_MASK	0x01F00
-#define SPEAR310_SHIRQ_RAS3_MASK	0x02000
-#define SPEAR310_SHIRQ_INTRCOMM_RAS_MASK	0x1C000
-
-#endif /* __MACH_SPEAR310_H */
-
-#endif /* CONFIG_MACH_SPEAR310 */
diff --git a/arch/arm/mach-spear3xx/include/mach/spear320.h b/arch/arm/mach-spear3xx/include/mach/spear320.h
deleted file mode 100644
index 8cfa83f..0000000
--- a/arch/arm/mach-spear3xx/include/mach/spear320.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/spear320.h
- *
- * SPEAr320 Machine specific definition
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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.
- */
-
-#ifdef	CONFIG_MACH_SPEAR320
-
-#ifndef __MACH_SPEAR320_H
-#define __MACH_SPEAR320_H
-
-#define SPEAR320_EMI_CTRL_BASE		UL(0x40000000)
-#define SPEAR320_FSMC_BASE		UL(0x4C000000)
-#define SPEAR320_NAND_BASE		UL(0x50000000)
-#define SPEAR320_I2S_BASE		UL(0x60000000)
-#define SPEAR320_SDHCI_BASE		UL(0x70000000)
-#define SPEAR320_CLCD_BASE		UL(0x90000000)
-#define SPEAR320_PAR_PORT_BASE		UL(0xA0000000)
-#define SPEAR320_CAN0_BASE		UL(0xA1000000)
-#define SPEAR320_CAN1_BASE		UL(0xA2000000)
-#define SPEAR320_UART1_BASE		UL(0xA3000000)
-#define SPEAR320_UART2_BASE		UL(0xA4000000)
-#define SPEAR320_SSP0_BASE		UL(0xA5000000)
-#define SPEAR320_SSP1_BASE		UL(0xA6000000)
-#define SPEAR320_I2C_BASE		UL(0xA7000000)
-#define SPEAR320_PWM_BASE		UL(0xA8000000)
-#define SPEAR320_SMII0_BASE		UL(0xAA000000)
-#define SPEAR320_SMII1_BASE		UL(0xAB000000)
-#define SPEAR320_SOC_CONFIG_BASE	UL(0xB3000000)
-
-/* Interrupt registers offsets and masks */
-#define SPEAR320_INT_STS_MASK_REG		0x04
-#define SPEAR320_INT_CLR_MASK_REG		0x04
-#define SPEAR320_INT_ENB_MASK_REG		0x08
-#define SPEAR320_GPIO_IRQ_MASK			(1 << 0)
-#define SPEAR320_I2S_PLAY_IRQ_MASK		(1 << 1)
-#define SPEAR320_I2S_REC_IRQ_MASK		(1 << 2)
-#define SPEAR320_EMI_IRQ_MASK			(1 << 7)
-#define SPEAR320_CLCD_IRQ_MASK			(1 << 8)
-#define SPEAR320_SPP_IRQ_MASK			(1 << 9)
-#define SPEAR320_SDHCI_IRQ_MASK			(1 << 10)
-#define SPEAR320_CAN_U_IRQ_MASK			(1 << 11)
-#define SPEAR320_CAN_L_IRQ_MASK			(1 << 12)
-#define SPEAR320_UART1_IRQ_MASK			(1 << 13)
-#define SPEAR320_UART2_IRQ_MASK			(1 << 14)
-#define SPEAR320_SSP1_IRQ_MASK			(1 << 15)
-#define SPEAR320_SSP2_IRQ_MASK			(1 << 16)
-#define SPEAR320_SMII0_IRQ_MASK			(1 << 17)
-#define SPEAR320_MII1_SMII1_IRQ_MASK		(1 << 18)
-#define SPEAR320_WAKEUP_SMII0_IRQ_MASK		(1 << 19)
-#define SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK	(1 << 20)
-#define SPEAR320_I2C1_IRQ_MASK			(1 << 21)
-
-#define SPEAR320_SHIRQ_RAS1_MASK		0x000380
-#define SPEAR320_SHIRQ_RAS3_MASK		0x000007
-#define SPEAR320_SHIRQ_INTRCOMM_RAS_MASK	0x3FF800
-
-#endif /* __MACH_SPEAR320_H */
-
-#endif /* CONFIG_MACH_SPEAR320 */
diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c
index f7db668..f75fe25 100644
--- a/arch/arm/mach-spear3xx/spear300.c
+++ b/arch/arm/mach-spear3xx/spear300.c
@@ -3,372 +3,62 @@
  *
  * SPEAr300 machine source file
  *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
  *
  * 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/types.h>
-#include <linux/amba/pl061.h>
-#include <linux/ptrace.h>
-#include <asm/irq.h>
+#define pr_fmt(fmt) "SPEAr300: " fmt
+
+#include <linux/amba/pl08x.h>
+#include <linux/of_platform.h>
+#include <asm/hardware/vic.h>
+#include <asm/mach/arch.h>
 #include <plat/shirq.h>
 #include <mach/generic.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
 
-/* pad multiplexing support */
-/* muxing registers */
-#define PAD_MUX_CONFIG_REG	0x00
-#define MODE_CONFIG_REG		0x04
+/* Base address of various IPs */
+#define SPEAR300_TELECOM_BASE		UL(0x50000000)
 
-/* modes */
-#define NAND_MODE			(1 << 0)
-#define NOR_MODE			(1 << 1)
-#define PHOTO_FRAME_MODE		(1 << 2)
-#define LEND_IP_PHONE_MODE		(1 << 3)
-#define HEND_IP_PHONE_MODE		(1 << 4)
-#define LEND_WIFI_PHONE_MODE		(1 << 5)
-#define HEND_WIFI_PHONE_MODE		(1 << 6)
-#define ATA_PABX_WI2S_MODE		(1 << 7)
-#define ATA_PABX_I2S_MODE		(1 << 8)
-#define CAML_LCDW_MODE			(1 << 9)
-#define CAMU_LCD_MODE			(1 << 10)
-#define CAMU_WLCD_MODE			(1 << 11)
-#define CAML_LCD_MODE			(1 << 12)
-#define ALL_MODES			0x1FFF
+/* Interrupt registers offsets and masks */
+#define SPEAR300_INT_ENB_MASK_REG	0x54
+#define SPEAR300_INT_STS_MASK_REG	0x58
+#define SPEAR300_IT_PERS_S_IRQ_MASK	(1 << 0)
+#define SPEAR300_IT_CHANGE_S_IRQ_MASK	(1 << 1)
+#define SPEAR300_I2S_IRQ_MASK		(1 << 2)
+#define SPEAR300_TDM_IRQ_MASK		(1 << 3)
+#define SPEAR300_CAMERA_L_IRQ_MASK	(1 << 4)
+#define SPEAR300_CAMERA_F_IRQ_MASK	(1 << 5)
+#define SPEAR300_CAMERA_V_IRQ_MASK	(1 << 6)
+#define SPEAR300_KEYBOARD_IRQ_MASK	(1 << 7)
+#define SPEAR300_GPIO1_IRQ_MASK		(1 << 8)
 
-struct pmx_mode spear300_nand_mode = {
-	.id = NAND_MODE,
-	.name = "nand mode",
-	.mask = 0x00,
-};
+#define SPEAR300_SHIRQ_RAS1_MASK	0x1FF
 
-struct pmx_mode spear300_nor_mode = {
-	.id = NOR_MODE,
-	.name = "nor mode",
-	.mask = 0x01,
-};
+#define SPEAR300_SOC_CONFIG_BASE	UL(0x99000000)
 
-struct pmx_mode spear300_photo_frame_mode = {
-	.id = PHOTO_FRAME_MODE,
-	.name = "photo frame mode",
-	.mask = 0x02,
-};
 
-struct pmx_mode spear300_lend_ip_phone_mode = {
-	.id = LEND_IP_PHONE_MODE,
-	.name = "lend ip phone mode",
-	.mask = 0x03,
-};
+/* SPEAr300 Virtual irq definitions */
+/* IRQs sharing IRQ_GEN_RAS_1 */
+#define SPEAR300_VIRQ_IT_PERS_S			(SPEAR3XX_VIRQ_START + 0)
+#define SPEAR300_VIRQ_IT_CHANGE_S		(SPEAR3XX_VIRQ_START + 1)
+#define SPEAR300_VIRQ_I2S			(SPEAR3XX_VIRQ_START + 2)
+#define SPEAR300_VIRQ_TDM			(SPEAR3XX_VIRQ_START + 3)
+#define SPEAR300_VIRQ_CAMERA_L			(SPEAR3XX_VIRQ_START + 4)
+#define SPEAR300_VIRQ_CAMERA_F			(SPEAR3XX_VIRQ_START + 5)
+#define SPEAR300_VIRQ_CAMERA_V			(SPEAR3XX_VIRQ_START + 6)
+#define SPEAR300_VIRQ_KEYBOARD			(SPEAR3XX_VIRQ_START + 7)
+#define SPEAR300_VIRQ_GPIO1			(SPEAR3XX_VIRQ_START + 8)
 
-struct pmx_mode spear300_hend_ip_phone_mode = {
-	.id = HEND_IP_PHONE_MODE,
-	.name = "hend ip phone mode",
-	.mask = 0x04,
-};
+/* IRQs sharing IRQ_GEN_RAS_3 */
+#define SPEAR300_IRQ_CLCD			SPEAR3XX_IRQ_GEN_RAS_3
 
-struct pmx_mode spear300_lend_wifi_phone_mode = {
-	.id = LEND_WIFI_PHONE_MODE,
-	.name = "lend wifi phone mode",
-	.mask = 0x05,
-};
-
-struct pmx_mode spear300_hend_wifi_phone_mode = {
-	.id = HEND_WIFI_PHONE_MODE,
-	.name = "hend wifi phone mode",
-	.mask = 0x06,
-};
-
-struct pmx_mode spear300_ata_pabx_wi2s_mode = {
-	.id = ATA_PABX_WI2S_MODE,
-	.name = "ata pabx wi2s mode",
-	.mask = 0x07,
-};
-
-struct pmx_mode spear300_ata_pabx_i2s_mode = {
-	.id = ATA_PABX_I2S_MODE,
-	.name = "ata pabx i2s mode",
-	.mask = 0x08,
-};
-
-struct pmx_mode spear300_caml_lcdw_mode = {
-	.id = CAML_LCDW_MODE,
-	.name = "caml lcdw mode",
-	.mask = 0x0C,
-};
-
-struct pmx_mode spear300_camu_lcd_mode = {
-	.id = CAMU_LCD_MODE,
-	.name = "camu lcd mode",
-	.mask = 0x0D,
-};
-
-struct pmx_mode spear300_camu_wlcd_mode = {
-	.id = CAMU_WLCD_MODE,
-	.name = "camu wlcd mode",
-	.mask = 0x0E,
-};
-
-struct pmx_mode spear300_caml_lcd_mode = {
-	.id = CAML_LCD_MODE,
-	.name = "caml lcd mode",
-	.mask = 0x0F,
-};
-
-/* devices */
-static struct pmx_dev_mode pmx_fsmc_2_chips_modes[] = {
-	{
-		.ids = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
-			ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
-		.mask = PMX_FIRDA_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_fsmc_2_chips = {
-	.name = "fsmc_2_chips",
-	.modes = pmx_fsmc_2_chips_modes,
-	.mode_count = ARRAY_SIZE(pmx_fsmc_2_chips_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_fsmc_4_chips_modes[] = {
-	{
-		.ids = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
-			ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
-		.mask = PMX_FIRDA_MASK | PMX_UART0_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_fsmc_4_chips = {
-	.name = "fsmc_4_chips",
-	.modes = pmx_fsmc_4_chips_modes,
-	.mode_count = ARRAY_SIZE(pmx_fsmc_4_chips_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_keyboard_modes[] = {
-	{
-		.ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE |
-			LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
-			CAML_LCDW_MODE | CAMU_LCD_MODE | CAMU_WLCD_MODE |
-			CAML_LCD_MODE,
-		.mask = 0x0,
-	},
-};
-
-struct pmx_dev spear300_pmx_keyboard = {
-	.name = "keyboard",
-	.modes = pmx_keyboard_modes,
-	.mode_count = ARRAY_SIZE(pmx_keyboard_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_clcd_modes[] = {
-	{
-		.ids = PHOTO_FRAME_MODE,
-		.mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK ,
-	}, {
-		.ids = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE |
-			CAMU_LCD_MODE | CAML_LCD_MODE,
-		.mask = PMX_TIMER_3_4_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_clcd = {
-	.name = "clcd",
-	.modes = pmx_clcd_modes,
-	.mode_count = ARRAY_SIZE(pmx_clcd_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_gpio_modes[] = {
-	{
-		.ids = PHOTO_FRAME_MODE | CAMU_LCD_MODE | CAML_LCD_MODE,
-		.mask = PMX_MII_MASK,
-	}, {
-		.ids = LEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE,
-		.mask = PMX_MII_MASK | PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK,
-	}, {
-		.ids = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_WLCD_MODE,
-		.mask = PMX_MII_MASK | PMX_TIMER_3_4_MASK,
-	}, {
-		.ids = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE,
-		.mask = PMX_MII_MASK | PMX_TIMER_1_2_MASK,
-	}, {
-		.ids = ATA_PABX_WI2S_MODE,
-		.mask = PMX_MII_MASK | PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK
-			| PMX_UART0_MODEM_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_telecom_gpio = {
-	.name = "telecom_gpio",
-	.modes = pmx_telecom_gpio_modes,
-	.mode_count = ARRAY_SIZE(pmx_telecom_gpio_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_tdm_modes[] = {
-	{
-		.ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
-			HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE
-			| HEND_WIFI_PHONE_MODE | ATA_PABX_WI2S_MODE
-			| ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
-			| CAMU_WLCD_MODE | CAML_LCD_MODE,
-		.mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_telecom_tdm = {
-	.name = "telecom_tdm",
-	.modes = pmx_telecom_tdm_modes,
-	.mode_count = ARRAY_SIZE(pmx_telecom_tdm_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_spi_cs_i2c_clk_modes[] = {
-	{
-		.ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE |
-			LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE
-			| ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE |
-			CAML_LCDW_MODE | CAML_LCD_MODE,
-		.mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_telecom_spi_cs_i2c_clk = {
-	.name = "telecom_spi_cs_i2c_clk",
-	.modes = pmx_telecom_spi_cs_i2c_clk_modes,
-	.mode_count = ARRAY_SIZE(pmx_telecom_spi_cs_i2c_clk_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_camera_modes[] = {
-	{
-		.ids = CAML_LCDW_MODE | CAML_LCD_MODE,
-		.mask = PMX_MII_MASK,
-	}, {
-		.ids = CAMU_LCD_MODE | CAMU_WLCD_MODE,
-		.mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK | PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_telecom_camera = {
-	.name = "telecom_camera",
-	.modes = pmx_telecom_camera_modes,
-	.mode_count = ARRAY_SIZE(pmx_telecom_camera_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_dac_modes[] = {
-	{
-		.ids = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
-			| CAMU_WLCD_MODE | CAML_LCD_MODE,
-		.mask = PMX_TIMER_1_2_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_telecom_dac = {
-	.name = "telecom_dac",
-	.modes = pmx_telecom_dac_modes,
-	.mode_count = ARRAY_SIZE(pmx_telecom_dac_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_i2s_modes[] = {
-	{
-		.ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE
-			| LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
-			ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
-			| CAMU_WLCD_MODE | CAML_LCD_MODE,
-		.mask = PMX_UART0_MODEM_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_telecom_i2s = {
-	.name = "telecom_i2s",
-	.modes = pmx_telecom_i2s_modes,
-	.mode_count = ARRAY_SIZE(pmx_telecom_i2s_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_boot_pins_modes[] = {
-	{
-		.ids = NAND_MODE | NOR_MODE,
-		.mask = PMX_UART0_MODEM_MASK | PMX_TIMER_1_2_MASK |
-			PMX_TIMER_3_4_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_telecom_boot_pins = {
-	.name = "telecom_boot_pins",
-	.modes = pmx_telecom_boot_pins_modes,
-	.mode_count = ARRAY_SIZE(pmx_telecom_boot_pins_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_sdhci_4bit_modes[] = {
-	{
-		.ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
-			HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
-			HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
-			CAMU_WLCD_MODE | CAML_LCD_MODE | ATA_PABX_WI2S_MODE |
-			ATA_PABX_I2S_MODE,
-		.mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
-			PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
-			PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_telecom_sdhci_4bit = {
-	.name = "telecom_sdhci_4bit",
-	.modes = pmx_telecom_sdhci_4bit_modes,
-	.mode_count = ARRAY_SIZE(pmx_telecom_sdhci_4bit_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_sdhci_8bit_modes[] = {
-	{
-		.ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
-			HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
-			HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
-			CAMU_WLCD_MODE | CAML_LCD_MODE,
-		.mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
-			PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
-			PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK | PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_telecom_sdhci_8bit = {
-	.name = "telecom_sdhci_8bit",
-	.modes = pmx_telecom_sdhci_8bit_modes,
-	.mode_count = ARRAY_SIZE(pmx_telecom_sdhci_8bit_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_gpio1_modes[] = {
-	{
-		.ids = PHOTO_FRAME_MODE,
-		.mask = PMX_UART0_MODEM_MASK | PMX_TIMER_1_2_MASK |
-			PMX_TIMER_3_4_MASK,
-	},
-};
-
-struct pmx_dev spear300_pmx_gpio1 = {
-	.name = "arm gpio1",
-	.modes = pmx_gpio1_modes,
-	.mode_count = ARRAY_SIZE(pmx_gpio1_modes),
-	.enb_on_reset = 1,
-};
-
-/* pmx driver structure */
-static struct pmx_driver pmx_driver = {
-	.mode_reg = {.offset = MODE_CONFIG_REG, .mask = 0x0000000f},
-	.mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff},
-};
+/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
+#define SPEAR300_IRQ_SDHCI			SPEAR3XX_IRQ_INTRCOMM_RAS_ARM
 
 /* spear3xx shared irq */
 static struct shirq_dev_config shirq_ras1_config[] = {
@@ -423,45 +113,239 @@
 	},
 };
 
-/* Add spear300 specific devices here */
-/* arm gpio1 device registration */
-static struct pl061_platform_data gpio1_plat_data = {
-	.gpio_base	= 8,
-	.irq_base	= SPEAR300_GPIO1_INT_BASE,
+/* DMAC platform data's slave info */
+struct pl08x_channel_data spear300_dma_info[] = {
+	{
+		.bus_id = "uart0_rx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart0_tx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp0_rx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp0_tx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "i2c_rx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "i2c_tx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "irda",
+		.min_signal = 12,
+		.max_signal = 12,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "adc",
+		.min_signal = 13,
+		.max_signal = 13,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "to_jpeg",
+		.min_signal = 14,
+		.max_signal = 14,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "from_jpeg",
+		.min_signal = 15,
+		.max_signal = 15,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras0_rx",
+		.min_signal = 0,
+		.max_signal = 0,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras0_tx",
+		.min_signal = 1,
+		.max_signal = 1,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras1_rx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras1_tx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras2_rx",
+		.min_signal = 4,
+		.max_signal = 4,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras2_tx",
+		.min_signal = 5,
+		.max_signal = 5,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras3_rx",
+		.min_signal = 6,
+		.max_signal = 6,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras3_tx",
+		.min_signal = 7,
+		.max_signal = 7,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras4_rx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras4_tx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras5_rx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras5_tx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras6_rx",
+		.min_signal = 12,
+		.max_signal = 12,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras6_tx",
+		.min_signal = 13,
+		.max_signal = 13,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras7_rx",
+		.min_signal = 14,
+		.max_signal = 14,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras7_tx",
+		.min_signal = 15,
+		.max_signal = 15,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	},
 };
 
-AMBA_APB_DEVICE(spear300_gpio1, "gpio1", 0, SPEAR300_GPIO_BASE,
-	{SPEAR300_VIRQ_GPIO1}, &gpio1_plat_data);
+/* Add SPEAr300 auxdata to pass platform data */
+static struct of_dev_auxdata spear300_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("arm,pl022", SPEAR3XX_ICM1_SSP_BASE, NULL,
+			&pl022_plat_data),
+	OF_DEV_AUXDATA("arm,pl080", SPEAR3XX_ICM3_DMA_BASE, NULL,
+			&pl080_plat_data),
+	{}
+};
 
-/* spear300 routines */
-void __init spear300_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
-		u8 pmx_dev_count)
+static void __init spear300_dt_init(void)
 {
-	int ret = 0;
+	int ret;
 
-	/* call spear3xx family common init function */
-	spear3xx_init();
+	pl080_plat_data.slave_channels = spear300_dma_info;
+	pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear300_dma_info);
+
+	of_platform_populate(NULL, of_default_bus_match_table,
+			spear300_auxdata_lookup, NULL);
 
 	/* shared irq registration */
 	shirq_ras1.regs.base = ioremap(SPEAR300_TELECOM_BASE, SZ_4K);
 	if (shirq_ras1.regs.base) {
 		ret = spear_shirq_register(&shirq_ras1);
 		if (ret)
-			printk(KERN_ERR "Error registering Shared IRQ\n");
-	}
-
-	/* pmx initialization */
-	pmx_driver.mode = pmx_mode;
-	pmx_driver.devs = pmx_devs;
-	pmx_driver.devs_count = pmx_dev_count;
-
-	pmx_driver.base = ioremap(SPEAR300_SOC_CONFIG_BASE, SZ_4K);
-	if (pmx_driver.base) {
-		ret = pmx_register(&pmx_driver);
-		if (ret)
-			printk(KERN_ERR "padmux: registration failed. err no"
-					": %d\n", ret);
-		/* Free Mapping, device selection already done */
-		iounmap(pmx_driver.base);
+			pr_err("Error registering Shared IRQ\n");
 	}
 }
+
+static const char * const spear300_dt_board_compat[] = {
+	"st,spear300",
+	"st,spear300-evb",
+	NULL,
+};
+
+static void __init spear300_map_io(void)
+{
+	spear3xx_map_io();
+	spear300_clk_init();
+}
+
+DT_MACHINE_START(SPEAR300_DT, "ST SPEAr300 SoC with Flattened Device Tree")
+	.map_io		=	spear300_map_io,
+	.init_irq	=	spear3xx_dt_init_irq,
+	.handle_irq	=	vic_handle_irq,
+	.timer		=	&spear3xx_timer,
+	.init_machine	=	spear300_dt_init,
+	.restart	=	spear_restart,
+	.dt_compat	=	spear300_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear300_evb.c b/arch/arm/mach-spear3xx/spear300_evb.c
deleted file mode 100644
index 3462ab9..0000000
--- a/arch/arm/mach-spear3xx/spear300_evb.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/spear300_evb.c
- *
- * SPEAr300 evaluation board source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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 <asm/hardware/vic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* padmux devices to enable */
-static struct pmx_dev *pmx_devs[] = {
-	/* spear3xx specific devices */
-	&spear3xx_pmx_i2c,
-	&spear3xx_pmx_ssp_cs,
-	&spear3xx_pmx_ssp,
-	&spear3xx_pmx_mii,
-	&spear3xx_pmx_uart0,
-
-	/* spear300 specific devices */
-	&spear300_pmx_fsmc_2_chips,
-	&spear300_pmx_clcd,
-	&spear300_pmx_telecom_sdhci_4bit,
-	&spear300_pmx_gpio1,
-};
-
-static struct amba_device *amba_devs[] __initdata = {
-	/* spear3xx specific devices */
-	&spear3xx_gpio_device,
-	&spear3xx_uart_device,
-
-	/* spear300 specific devices */
-	&spear300_gpio1_device,
-};
-
-static struct platform_device *plat_devs[] __initdata = {
-	/* spear3xx specific devices */
-
-	/* spear300 specific devices */
-};
-
-static void __init spear300_evb_init(void)
-{
-	unsigned int i;
-
-	/* call spear300 machine init function */
-	spear300_init(&spear300_photo_frame_mode, pmx_devs,
-			ARRAY_SIZE(pmx_devs));
-
-	/* Add Platform Devices */
-	platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
-
-	/* Add Amba Devices */
-	for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
-		amba_device_register(amba_devs[i], &iomem_resource);
-}
-
-MACHINE_START(SPEAR300, "ST-SPEAR300-EVB")
-	.atag_offset	=	0x100,
-	.map_io		=	spear3xx_map_io,
-	.init_irq	=	spear3xx_init_irq,
-	.handle_irq	=	vic_handle_irq,
-	.timer		=	&spear3xx_timer,
-	.init_machine	=	spear300_evb_init,
-	.restart	=	spear_restart,
-MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c
index febaa6f..f0842a5 100644
--- a/arch/arm/mach-spear3xx/spear310.c
+++ b/arch/arm/mach-spear3xx/spear310.c
@@ -3,141 +3,84 @@
  *
  * SPEAr310 machine source file
  *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
  *
  * 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/ptrace.h>
-#include <asm/irq.h>
+#define pr_fmt(fmt) "SPEAr310: " fmt
+
+#include <linux/amba/pl08x.h>
+#include <linux/amba/serial.h>
+#include <linux/of_platform.h>
+#include <asm/hardware/vic.h>
+#include <asm/mach/arch.h>
 #include <plat/shirq.h>
 #include <mach/generic.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
 
-/* pad multiplexing support */
-/* muxing registers */
-#define PAD_MUX_CONFIG_REG	0x08
+#define SPEAR310_UART1_BASE		UL(0xB2000000)
+#define SPEAR310_UART2_BASE		UL(0xB2080000)
+#define SPEAR310_UART3_BASE		UL(0xB2100000)
+#define SPEAR310_UART4_BASE		UL(0xB2180000)
+#define SPEAR310_UART5_BASE		UL(0xB2200000)
+#define SPEAR310_SOC_CONFIG_BASE	UL(0xB4000000)
 
-/* devices */
-static struct pmx_dev_mode pmx_emi_cs_0_1_4_5_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_TIMER_3_4_MASK,
-	},
-};
+/* Interrupt registers offsets and masks */
+#define SPEAR310_INT_STS_MASK_REG	0x04
+#define SPEAR310_SMII0_IRQ_MASK		(1 << 0)
+#define SPEAR310_SMII1_IRQ_MASK		(1 << 1)
+#define SPEAR310_SMII2_IRQ_MASK		(1 << 2)
+#define SPEAR310_SMII3_IRQ_MASK		(1 << 3)
+#define SPEAR310_WAKEUP_SMII0_IRQ_MASK	(1 << 4)
+#define SPEAR310_WAKEUP_SMII1_IRQ_MASK	(1 << 5)
+#define SPEAR310_WAKEUP_SMII2_IRQ_MASK	(1 << 6)
+#define SPEAR310_WAKEUP_SMII3_IRQ_MASK	(1 << 7)
+#define SPEAR310_UART1_IRQ_MASK		(1 << 8)
+#define SPEAR310_UART2_IRQ_MASK		(1 << 9)
+#define SPEAR310_UART3_IRQ_MASK		(1 << 10)
+#define SPEAR310_UART4_IRQ_MASK		(1 << 11)
+#define SPEAR310_UART5_IRQ_MASK		(1 << 12)
+#define SPEAR310_EMI_IRQ_MASK		(1 << 13)
+#define SPEAR310_TDM_HDLC_IRQ_MASK	(1 << 14)
+#define SPEAR310_RS485_0_IRQ_MASK	(1 << 15)
+#define SPEAR310_RS485_1_IRQ_MASK	(1 << 16)
 
-struct pmx_dev spear310_pmx_emi_cs_0_1_4_5 = {
-	.name = "emi_cs_0_1_4_5",
-	.modes = pmx_emi_cs_0_1_4_5_modes,
-	.mode_count = ARRAY_SIZE(pmx_emi_cs_0_1_4_5_modes),
-	.enb_on_reset = 1,
-};
+#define SPEAR310_SHIRQ_RAS1_MASK	0x000FF
+#define SPEAR310_SHIRQ_RAS2_MASK	0x01F00
+#define SPEAR310_SHIRQ_RAS3_MASK	0x02000
+#define SPEAR310_SHIRQ_INTRCOMM_RAS_MASK	0x1C000
 
-static struct pmx_dev_mode pmx_emi_cs_2_3_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_TIMER_1_2_MASK,
-	},
-};
+/* SPEAr310 Virtual irq definitions */
+/* IRQs sharing IRQ_GEN_RAS_1 */
+#define SPEAR310_VIRQ_SMII0			(SPEAR3XX_VIRQ_START + 0)
+#define SPEAR310_VIRQ_SMII1			(SPEAR3XX_VIRQ_START + 1)
+#define SPEAR310_VIRQ_SMII2			(SPEAR3XX_VIRQ_START + 2)
+#define SPEAR310_VIRQ_SMII3			(SPEAR3XX_VIRQ_START + 3)
+#define SPEAR310_VIRQ_WAKEUP_SMII0		(SPEAR3XX_VIRQ_START + 4)
+#define SPEAR310_VIRQ_WAKEUP_SMII1		(SPEAR3XX_VIRQ_START + 5)
+#define SPEAR310_VIRQ_WAKEUP_SMII2		(SPEAR3XX_VIRQ_START + 6)
+#define SPEAR310_VIRQ_WAKEUP_SMII3		(SPEAR3XX_VIRQ_START + 7)
 
-struct pmx_dev spear310_pmx_emi_cs_2_3 = {
-	.name = "emi_cs_2_3",
-	.modes = pmx_emi_cs_2_3_modes,
-	.mode_count = ARRAY_SIZE(pmx_emi_cs_2_3_modes),
-	.enb_on_reset = 1,
-};
+/* IRQs sharing IRQ_GEN_RAS_2 */
+#define SPEAR310_VIRQ_UART1			(SPEAR3XX_VIRQ_START + 8)
+#define SPEAR310_VIRQ_UART2			(SPEAR3XX_VIRQ_START + 9)
+#define SPEAR310_VIRQ_UART3			(SPEAR3XX_VIRQ_START + 10)
+#define SPEAR310_VIRQ_UART4			(SPEAR3XX_VIRQ_START + 11)
+#define SPEAR310_VIRQ_UART5			(SPEAR3XX_VIRQ_START + 12)
 
-static struct pmx_dev_mode pmx_uart1_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_FIRDA_MASK,
-	},
-};
+/* IRQs sharing IRQ_GEN_RAS_3 */
+#define SPEAR310_VIRQ_EMI			(SPEAR3XX_VIRQ_START + 13)
+#define SPEAR310_VIRQ_PLGPIO			(SPEAR3XX_VIRQ_START + 14)
 
-struct pmx_dev spear310_pmx_uart1 = {
-	.name = "uart1",
-	.modes = pmx_uart1_modes,
-	.mode_count = ARRAY_SIZE(pmx_uart1_modes),
-	.enb_on_reset = 1,
-};
+/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
+#define SPEAR310_VIRQ_TDM_HDLC			(SPEAR3XX_VIRQ_START + 15)
+#define SPEAR310_VIRQ_RS485_0			(SPEAR3XX_VIRQ_START + 16)
+#define SPEAR310_VIRQ_RS485_1			(SPEAR3XX_VIRQ_START + 17)
 
-static struct pmx_dev_mode pmx_uart2_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_TIMER_1_2_MASK,
-	},
-};
-
-struct pmx_dev spear310_pmx_uart2 = {
-	.name = "uart2",
-	.modes = pmx_uart2_modes,
-	.mode_count = ARRAY_SIZE(pmx_uart2_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart3_4_5_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_UART0_MODEM_MASK,
-	},
-};
-
-struct pmx_dev spear310_pmx_uart3_4_5 = {
-	.name = "uart3_4_5",
-	.modes = pmx_uart3_4_5_modes,
-	.mode_count = ARRAY_SIZE(pmx_uart3_4_5_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_fsmc_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_SSP_CS_MASK,
-	},
-};
-
-struct pmx_dev spear310_pmx_fsmc = {
-	.name = "fsmc",
-	.modes = pmx_fsmc_modes,
-	.mode_count = ARRAY_SIZE(pmx_fsmc_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_rs485_0_1_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear310_pmx_rs485_0_1 = {
-	.name = "rs485_0_1",
-	.modes = pmx_rs485_0_1_modes,
-	.mode_count = ARRAY_SIZE(pmx_rs485_0_1_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_tdm0_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear310_pmx_tdm0 = {
-	.name = "tdm0",
-	.modes = pmx_tdm0_modes,
-	.mode_count = ARRAY_SIZE(pmx_tdm0_modes),
-	.enb_on_reset = 1,
-};
-
-/* pmx driver structure */
-static struct pmx_driver pmx_driver = {
-	.mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff},
-};
 
 /* spear3xx shared irq */
 static struct shirq_dev_config shirq_ras1_config[] = {
@@ -255,17 +198,247 @@
 	},
 };
 
-/* Add spear310 specific devices here */
+/* DMAC platform data's slave info */
+struct pl08x_channel_data spear310_dma_info[] = {
+	{
+		.bus_id = "uart0_rx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart0_tx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp0_rx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp0_tx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "i2c_rx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "i2c_tx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "irda",
+		.min_signal = 12,
+		.max_signal = 12,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "adc",
+		.min_signal = 13,
+		.max_signal = 13,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "to_jpeg",
+		.min_signal = 14,
+		.max_signal = 14,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "from_jpeg",
+		.min_signal = 15,
+		.max_signal = 15,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart1_rx",
+		.min_signal = 0,
+		.max_signal = 0,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart1_tx",
+		.min_signal = 1,
+		.max_signal = 1,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart2_rx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart2_tx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart3_rx",
+		.min_signal = 4,
+		.max_signal = 4,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart3_tx",
+		.min_signal = 5,
+		.max_signal = 5,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart4_rx",
+		.min_signal = 6,
+		.max_signal = 6,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart4_tx",
+		.min_signal = 7,
+		.max_signal = 7,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart5_rx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart5_tx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras5_rx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras5_tx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras6_rx",
+		.min_signal = 12,
+		.max_signal = 12,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras6_tx",
+		.min_signal = 13,
+		.max_signal = 13,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras7_rx",
+		.min_signal = 14,
+		.max_signal = 14,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras7_tx",
+		.min_signal = 15,
+		.max_signal = 15,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	},
+};
 
-/* spear310 routines */
-void __init spear310_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
-		u8 pmx_dev_count)
+/* uart devices plat data */
+static struct amba_pl011_data spear310_uart_data[] = {
+	{
+		.dma_filter = pl08x_filter_id,
+		.dma_tx_param = "uart1_tx",
+		.dma_rx_param = "uart1_rx",
+	}, {
+		.dma_filter = pl08x_filter_id,
+		.dma_tx_param = "uart2_tx",
+		.dma_rx_param = "uart2_rx",
+	}, {
+		.dma_filter = pl08x_filter_id,
+		.dma_tx_param = "uart3_tx",
+		.dma_rx_param = "uart3_rx",
+	}, {
+		.dma_filter = pl08x_filter_id,
+		.dma_tx_param = "uart4_tx",
+		.dma_rx_param = "uart4_rx",
+	}, {
+		.dma_filter = pl08x_filter_id,
+		.dma_tx_param = "uart5_tx",
+		.dma_rx_param = "uart5_rx",
+	},
+};
+
+/* Add SPEAr310 auxdata to pass platform data */
+static struct of_dev_auxdata spear310_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("arm,pl022", SPEAR3XX_ICM1_SSP_BASE, NULL,
+			&pl022_plat_data),
+	OF_DEV_AUXDATA("arm,pl080", SPEAR3XX_ICM3_DMA_BASE, NULL,
+			&pl080_plat_data),
+	OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART1_BASE, NULL,
+			&spear310_uart_data[0]),
+	OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART2_BASE, NULL,
+			&spear310_uart_data[1]),
+	OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART3_BASE, NULL,
+			&spear310_uart_data[2]),
+	OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART4_BASE, NULL,
+			&spear310_uart_data[3]),
+	OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART5_BASE, NULL,
+			&spear310_uart_data[4]),
+	{}
+};
+
+static void __init spear310_dt_init(void)
 {
 	void __iomem *base;
-	int ret = 0;
+	int ret;
 
-	/* call spear3xx family common init function */
-	spear3xx_init();
+	pl080_plat_data.slave_channels = spear310_dma_info;
+	pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear310_dma_info);
+
+	of_platform_populate(NULL, of_default_bus_match_table,
+			spear310_auxdata_lookup, NULL);
 
 	/* shared irq registration */
 	base = ioremap(SPEAR310_SOC_CONFIG_BASE, SZ_4K);
@@ -274,35 +447,46 @@
 		shirq_ras1.regs.base = base;
 		ret = spear_shirq_register(&shirq_ras1);
 		if (ret)
-			printk(KERN_ERR "Error registering Shared IRQ 1\n");
+			pr_err("Error registering Shared IRQ 1\n");
 
 		/* shirq 2 */
 		shirq_ras2.regs.base = base;
 		ret = spear_shirq_register(&shirq_ras2);
 		if (ret)
-			printk(KERN_ERR "Error registering Shared IRQ 2\n");
+			pr_err("Error registering Shared IRQ 2\n");
 
 		/* shirq 3 */
 		shirq_ras3.regs.base = base;
 		ret = spear_shirq_register(&shirq_ras3);
 		if (ret)
-			printk(KERN_ERR "Error registering Shared IRQ 3\n");
+			pr_err("Error registering Shared IRQ 3\n");
 
 		/* shirq 4 */
 		shirq_intrcomm_ras.regs.base = base;
 		ret = spear_shirq_register(&shirq_intrcomm_ras);
 		if (ret)
-			printk(KERN_ERR "Error registering Shared IRQ 4\n");
+			pr_err("Error registering Shared IRQ 4\n");
 	}
-
-	/* pmx initialization */
-	pmx_driver.base = base;
-	pmx_driver.mode = pmx_mode;
-	pmx_driver.devs = pmx_devs;
-	pmx_driver.devs_count = pmx_dev_count;
-
-	ret = pmx_register(&pmx_driver);
-	if (ret)
-		printk(KERN_ERR "padmux: registration failed. err no: %d\n",
-				ret);
 }
+
+static const char * const spear310_dt_board_compat[] = {
+	"st,spear310",
+	"st,spear310-evb",
+	NULL,
+};
+
+static void __init spear310_map_io(void)
+{
+	spear3xx_map_io();
+	spear310_clk_init();
+}
+
+DT_MACHINE_START(SPEAR310_DT, "ST SPEAr310 SoC with Flattened Device Tree")
+	.map_io		=	spear310_map_io,
+	.init_irq	=	spear3xx_dt_init_irq,
+	.handle_irq	=	vic_handle_irq,
+	.timer		=	&spear3xx_timer,
+	.init_machine	=	spear310_dt_init,
+	.restart	=	spear_restart,
+	.dt_compat	=	spear310_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear310_evb.c b/arch/arm/mach-spear3xx/spear310_evb.c
deleted file mode 100644
index f92c499..0000000
--- a/arch/arm/mach-spear3xx/spear310_evb.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/spear310_evb.c
- *
- * SPEAr310 evaluation board source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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 <asm/hardware/vic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* padmux devices to enable */
-static struct pmx_dev *pmx_devs[] = {
-	/* spear3xx specific devices */
-	&spear3xx_pmx_i2c,
-	&spear3xx_pmx_ssp,
-	&spear3xx_pmx_gpio_pin0,
-	&spear3xx_pmx_gpio_pin1,
-	&spear3xx_pmx_gpio_pin2,
-	&spear3xx_pmx_gpio_pin3,
-	&spear3xx_pmx_gpio_pin4,
-	&spear3xx_pmx_gpio_pin5,
-	&spear3xx_pmx_uart0,
-
-	/* spear310 specific devices */
-	&spear310_pmx_emi_cs_0_1_4_5,
-	&spear310_pmx_emi_cs_2_3,
-	&spear310_pmx_uart1,
-	&spear310_pmx_uart2,
-	&spear310_pmx_uart3_4_5,
-	&spear310_pmx_fsmc,
-	&spear310_pmx_rs485_0_1,
-	&spear310_pmx_tdm0,
-};
-
-static struct amba_device *amba_devs[] __initdata = {
-	/* spear3xx specific devices */
-	&spear3xx_gpio_device,
-	&spear3xx_uart_device,
-
-	/* spear310 specific devices */
-};
-
-static struct platform_device *plat_devs[] __initdata = {
-	/* spear3xx specific devices */
-
-	/* spear310 specific devices */
-};
-
-static void __init spear310_evb_init(void)
-{
-	unsigned int i;
-
-	/* call spear310 machine init function */
-	spear310_init(NULL, pmx_devs, ARRAY_SIZE(pmx_devs));
-
-	/* Add Platform Devices */
-	platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
-
-	/* Add Amba Devices */
-	for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
-		amba_device_register(amba_devs[i], &iomem_resource);
-}
-
-MACHINE_START(SPEAR310, "ST-SPEAR310-EVB")
-	.atag_offset	=	0x100,
-	.map_io		=	spear3xx_map_io,
-	.init_irq	=	spear3xx_init_irq,
-	.handle_irq	=	vic_handle_irq,
-	.timer		=	&spear3xx_timer,
-	.init_machine	=	spear310_evb_init,
-	.restart	=	spear_restart,
-MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c
index deaaf19..e8caeef 100644
--- a/arch/arm/mach-spear3xx/spear320.c
+++ b/arch/arm/mach-spear3xx/spear320.c
@@ -3,386 +3,85 @@
  *
  * SPEAr320 machine source file
  *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
  *
  * 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/ptrace.h>
-#include <asm/irq.h>
+#define pr_fmt(fmt) "SPEAr320: " fmt
+
+#include <linux/amba/pl022.h>
+#include <linux/amba/pl08x.h>
+#include <linux/amba/serial.h>
+#include <linux/of_platform.h>
+#include <asm/hardware/vic.h>
+#include <asm/mach/arch.h>
 #include <plat/shirq.h>
 #include <mach/generic.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
 
-/* pad multiplexing support */
-/* muxing registers */
-#define PAD_MUX_CONFIG_REG	0x0C
-#define MODE_CONFIG_REG		0x10
+#define SPEAR320_UART1_BASE		UL(0xA3000000)
+#define SPEAR320_UART2_BASE		UL(0xA4000000)
+#define SPEAR320_SSP0_BASE		UL(0xA5000000)
+#define SPEAR320_SSP1_BASE		UL(0xA6000000)
+#define SPEAR320_SOC_CONFIG_BASE	UL(0xB3000000)
 
-/* modes */
-#define AUTO_NET_SMII_MODE	(1 << 0)
-#define AUTO_NET_MII_MODE	(1 << 1)
-#define AUTO_EXP_MODE		(1 << 2)
-#define SMALL_PRINTERS_MODE	(1 << 3)
-#define ALL_MODES		0xF
+/* Interrupt registers offsets and masks */
+#define SPEAR320_INT_STS_MASK_REG		0x04
+#define SPEAR320_INT_CLR_MASK_REG		0x04
+#define SPEAR320_INT_ENB_MASK_REG		0x08
+#define SPEAR320_GPIO_IRQ_MASK			(1 << 0)
+#define SPEAR320_I2S_PLAY_IRQ_MASK		(1 << 1)
+#define SPEAR320_I2S_REC_IRQ_MASK		(1 << 2)
+#define SPEAR320_EMI_IRQ_MASK			(1 << 7)
+#define SPEAR320_CLCD_IRQ_MASK			(1 << 8)
+#define SPEAR320_SPP_IRQ_MASK			(1 << 9)
+#define SPEAR320_SDHCI_IRQ_MASK			(1 << 10)
+#define SPEAR320_CAN_U_IRQ_MASK			(1 << 11)
+#define SPEAR320_CAN_L_IRQ_MASK			(1 << 12)
+#define SPEAR320_UART1_IRQ_MASK			(1 << 13)
+#define SPEAR320_UART2_IRQ_MASK			(1 << 14)
+#define SPEAR320_SSP1_IRQ_MASK			(1 << 15)
+#define SPEAR320_SSP2_IRQ_MASK			(1 << 16)
+#define SPEAR320_SMII0_IRQ_MASK			(1 << 17)
+#define SPEAR320_MII1_SMII1_IRQ_MASK		(1 << 18)
+#define SPEAR320_WAKEUP_SMII0_IRQ_MASK		(1 << 19)
+#define SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK	(1 << 20)
+#define SPEAR320_I2C1_IRQ_MASK			(1 << 21)
 
-struct pmx_mode spear320_auto_net_smii_mode = {
-	.id = AUTO_NET_SMII_MODE,
-	.name = "Automation Networking SMII Mode",
-	.mask = 0x00,
-};
+#define SPEAR320_SHIRQ_RAS1_MASK		0x000380
+#define SPEAR320_SHIRQ_RAS3_MASK		0x000007
+#define SPEAR320_SHIRQ_INTRCOMM_RAS_MASK	0x3FF800
 
-struct pmx_mode spear320_auto_net_mii_mode = {
-	.id = AUTO_NET_MII_MODE,
-	.name = "Automation Networking MII Mode",
-	.mask = 0x01,
-};
+/* SPEAr320 Virtual irq definitions */
+/* IRQs sharing IRQ_GEN_RAS_1 */
+#define SPEAR320_VIRQ_EMI			(SPEAR3XX_VIRQ_START + 0)
+#define SPEAR320_VIRQ_CLCD			(SPEAR3XX_VIRQ_START + 1)
+#define SPEAR320_VIRQ_SPP			(SPEAR3XX_VIRQ_START + 2)
 
-struct pmx_mode spear320_auto_exp_mode = {
-	.id = AUTO_EXP_MODE,
-	.name = "Automation Expanded Mode",
-	.mask = 0x02,
-};
+/* IRQs sharing IRQ_GEN_RAS_2 */
+#define SPEAR320_IRQ_SDHCI			SPEAR3XX_IRQ_GEN_RAS_2
 
-struct pmx_mode spear320_small_printers_mode = {
-	.id = SMALL_PRINTERS_MODE,
-	.name = "Small Printers Mode",
-	.mask = 0x03,
-};
+/* IRQs sharing IRQ_GEN_RAS_3 */
+#define SPEAR320_VIRQ_PLGPIO			(SPEAR3XX_VIRQ_START + 3)
+#define SPEAR320_VIRQ_I2S_PLAY			(SPEAR3XX_VIRQ_START + 4)
+#define SPEAR320_VIRQ_I2S_REC			(SPEAR3XX_VIRQ_START + 5)
 
-/* devices */
-static struct pmx_dev_mode pmx_clcd_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE,
-		.mask = 0x0,
-	},
-};
-
-struct pmx_dev spear320_pmx_clcd = {
-	.name = "clcd",
-	.modes = pmx_clcd_modes,
-	.mode_count = ARRAY_SIZE(pmx_clcd_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_emi_modes[] = {
-	{
-		.ids = AUTO_EXP_MODE,
-		.mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_emi = {
-	.name = "emi",
-	.modes = pmx_emi_modes,
-	.mode_count = ARRAY_SIZE(pmx_emi_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_fsmc_modes[] = {
-	{
-		.ids = ALL_MODES,
-		.mask = 0x0,
-	},
-};
-
-struct pmx_dev spear320_pmx_fsmc = {
-	.name = "fsmc",
-	.modes = pmx_fsmc_modes,
-	.mode_count = ARRAY_SIZE(pmx_fsmc_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_spp_modes[] = {
-	{
-		.ids = SMALL_PRINTERS_MODE,
-		.mask = 0x0,
-	},
-};
-
-struct pmx_dev spear320_pmx_spp = {
-	.name = "spp",
-	.modes = pmx_spp_modes,
-	.mode_count = ARRAY_SIZE(pmx_spp_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_sdhci_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE |
-			SMALL_PRINTERS_MODE,
-		.mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_sdhci = {
-	.name = "sdhci",
-	.modes = pmx_sdhci_modes,
-	.mode_count = ARRAY_SIZE(pmx_sdhci_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_i2s_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
-		.mask = PMX_UART0_MODEM_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_i2s = {
-	.name = "i2s",
-	.modes = pmx_i2s_modes,
-	.mode_count = ARRAY_SIZE(pmx_i2s_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart1_modes[] = {
-	{
-		.ids = ALL_MODES,
-		.mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_uart1 = {
-	.name = "uart1",
-	.modes = pmx_uart1_modes,
-	.mode_count = ARRAY_SIZE(pmx_uart1_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart1_modem_modes[] = {
-	{
-		.ids = AUTO_EXP_MODE,
-		.mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK |
-			PMX_SSP_CS_MASK,
-	}, {
-		.ids = SMALL_PRINTERS_MODE,
-		.mask = PMX_GPIO_PIN3_MASK | PMX_GPIO_PIN4_MASK |
-			PMX_GPIO_PIN5_MASK | PMX_SSP_CS_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_uart1_modem = {
-	.name = "uart1_modem",
-	.modes = pmx_uart1_modem_modes,
-	.mode_count = ARRAY_SIZE(pmx_uart1_modem_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart2_modes[] = {
-	{
-		.ids = ALL_MODES,
-		.mask = PMX_FIRDA_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_uart2 = {
-	.name = "uart2",
-	.modes = pmx_uart2_modes,
-	.mode_count = ARRAY_SIZE(pmx_uart2_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_touchscreen_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE,
-		.mask = PMX_SSP_CS_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_touchscreen = {
-	.name = "touchscreen",
-	.modes = pmx_touchscreen_modes,
-	.mode_count = ARRAY_SIZE(pmx_touchscreen_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_can_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE,
-		.mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
-			PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_can = {
-	.name = "can",
-	.modes = pmx_can_modes,
-	.mode_count = ARRAY_SIZE(pmx_can_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_sdhci_led_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
-		.mask = PMX_SSP_CS_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_sdhci_led = {
-	.name = "sdhci_led",
-	.modes = pmx_sdhci_led_modes,
-	.mode_count = ARRAY_SIZE(pmx_sdhci_led_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_pwm0_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
-		.mask = PMX_UART0_MODEM_MASK,
-	}, {
-		.ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_pwm0 = {
-	.name = "pwm0",
-	.modes = pmx_pwm0_modes,
-	.mode_count = ARRAY_SIZE(pmx_pwm0_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_pwm1_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
-		.mask = PMX_UART0_MODEM_MASK,
-	}, {
-		.ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_pwm1 = {
-	.name = "pwm1",
-	.modes = pmx_pwm1_modes,
-	.mode_count = ARRAY_SIZE(pmx_pwm1_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_pwm2_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
-		.mask = PMX_SSP_CS_MASK,
-	}, {
-		.ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_pwm2 = {
-	.name = "pwm2",
-	.modes = pmx_pwm2_modes,
-	.mode_count = ARRAY_SIZE(pmx_pwm2_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_pwm3_modes[] = {
-	{
-		.ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_pwm3 = {
-	.name = "pwm3",
-	.modes = pmx_pwm3_modes,
-	.mode_count = ARRAY_SIZE(pmx_pwm3_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_ssp1_modes[] = {
-	{
-		.ids = SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_ssp1 = {
-	.name = "ssp1",
-	.modes = pmx_ssp1_modes,
-	.mode_count = ARRAY_SIZE(pmx_ssp1_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_ssp2_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_ssp2 = {
-	.name = "ssp2",
-	.modes = pmx_ssp2_modes,
-	.mode_count = ARRAY_SIZE(pmx_ssp2_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_mii1_modes[] = {
-	{
-		.ids = AUTO_NET_MII_MODE,
-		.mask = 0x0,
-	},
-};
-
-struct pmx_dev spear320_pmx_mii1 = {
-	.name = "mii1",
-	.modes = pmx_mii1_modes,
-	.mode_count = ARRAY_SIZE(pmx_mii1_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_smii0_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE | AUTO_EXP_MODE | SMALL_PRINTERS_MODE,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_smii0 = {
-	.name = "smii0",
-	.modes = pmx_smii0_modes,
-	.mode_count = ARRAY_SIZE(pmx_smii0_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_smii1_modes[] = {
-	{
-		.ids = AUTO_NET_SMII_MODE | SMALL_PRINTERS_MODE,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear320_pmx_smii1 = {
-	.name = "smii1",
-	.modes = pmx_smii1_modes,
-	.mode_count = ARRAY_SIZE(pmx_smii1_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_i2c1_modes[] = {
-	{
-		.ids = AUTO_EXP_MODE,
-		.mask = 0x0,
-	},
-};
-
-struct pmx_dev spear320_pmx_i2c1 = {
-	.name = "i2c1",
-	.modes = pmx_i2c1_modes,
-	.mode_count = ARRAY_SIZE(pmx_i2c1_modes),
-	.enb_on_reset = 1,
-};
-
-/* pmx driver structure */
-static struct pmx_driver pmx_driver = {
-	.mode_reg = {.offset = MODE_CONFIG_REG, .mask = 0x00000007},
-	.mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff},
-};
+/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
+#define SPEAR320_VIRQ_CANU			(SPEAR3XX_VIRQ_START + 6)
+#define SPEAR320_VIRQ_CANL			(SPEAR3XX_VIRQ_START + 7)
+#define SPEAR320_VIRQ_UART1			(SPEAR3XX_VIRQ_START + 8)
+#define SPEAR320_VIRQ_UART2			(SPEAR3XX_VIRQ_START + 9)
+#define SPEAR320_VIRQ_SSP1			(SPEAR3XX_VIRQ_START + 10)
+#define SPEAR320_VIRQ_SSP2			(SPEAR3XX_VIRQ_START + 11)
+#define SPEAR320_VIRQ_SMII0			(SPEAR3XX_VIRQ_START + 12)
+#define SPEAR320_VIRQ_MII1_SMII1		(SPEAR3XX_VIRQ_START + 13)
+#define SPEAR320_VIRQ_WAKEUP_SMII0		(SPEAR3XX_VIRQ_START + 14)
+#define SPEAR320_VIRQ_WAKEUP_MII1_SMII1		(SPEAR3XX_VIRQ_START + 15)
+#define SPEAR320_VIRQ_I2C1			(SPEAR3XX_VIRQ_START + 16)
 
 /* spear3xx shared irq */
 static struct shirq_dev_config shirq_ras1_config[] = {
@@ -508,17 +207,250 @@
 	},
 };
 
-/* Add spear320 specific devices here */
+/* DMAC platform data's slave info */
+struct pl08x_channel_data spear320_dma_info[] = {
+	{
+		.bus_id = "uart0_rx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart0_tx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp0_rx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp0_tx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "i2c0_rx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "i2c0_tx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "irda",
+		.min_signal = 12,
+		.max_signal = 12,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "adc",
+		.min_signal = 13,
+		.max_signal = 13,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "to_jpeg",
+		.min_signal = 14,
+		.max_signal = 14,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "from_jpeg",
+		.min_signal = 15,
+		.max_signal = 15,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp1_rx",
+		.min_signal = 0,
+		.max_signal = 0,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ssp1_tx",
+		.min_signal = 1,
+		.max_signal = 1,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ssp2_rx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ssp2_tx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart1_rx",
+		.min_signal = 4,
+		.max_signal = 4,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart1_tx",
+		.min_signal = 5,
+		.max_signal = 5,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart2_rx",
+		.min_signal = 6,
+		.max_signal = 6,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart2_tx",
+		.min_signal = 7,
+		.max_signal = 7,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2c1_rx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2c1_tx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2c2_rx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2c2_tx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2s_rx",
+		.min_signal = 12,
+		.max_signal = 12,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2s_tx",
+		.min_signal = 13,
+		.max_signal = 13,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "rs485_rx",
+		.min_signal = 14,
+		.max_signal = 14,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "rs485_tx",
+		.min_signal = 15,
+		.max_signal = 15,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	},
+};
 
-/* spear320 routines */
-void __init spear320_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
-		u8 pmx_dev_count)
+static struct pl022_ssp_controller spear320_ssp_data[] = {
+	{
+		.bus_id = 1,
+		.enable_dma = 1,
+		.dma_filter = pl08x_filter_id,
+		.dma_tx_param = "ssp1_tx",
+		.dma_rx_param = "ssp1_rx",
+		.num_chipselect = 2,
+	}, {
+		.bus_id = 2,
+		.enable_dma = 1,
+		.dma_filter = pl08x_filter_id,
+		.dma_tx_param = "ssp2_tx",
+		.dma_rx_param = "ssp2_rx",
+		.num_chipselect = 2,
+	}
+};
+
+static struct amba_pl011_data spear320_uart_data[] = {
+	{
+		.dma_filter = pl08x_filter_id,
+		.dma_tx_param = "uart1_tx",
+		.dma_rx_param = "uart1_rx",
+	}, {
+		.dma_filter = pl08x_filter_id,
+		.dma_tx_param = "uart2_tx",
+		.dma_rx_param = "uart2_rx",
+	},
+};
+
+/* Add SPEAr310 auxdata to pass platform data */
+static struct of_dev_auxdata spear320_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("arm,pl022", SPEAR3XX_ICM1_SSP_BASE, NULL,
+			&pl022_plat_data),
+	OF_DEV_AUXDATA("arm,pl080", SPEAR3XX_ICM3_DMA_BASE, NULL,
+			&pl080_plat_data),
+	OF_DEV_AUXDATA("arm,pl022", SPEAR320_SSP0_BASE, NULL,
+			&spear320_ssp_data[0]),
+	OF_DEV_AUXDATA("arm,pl022", SPEAR320_SSP1_BASE, NULL,
+			&spear320_ssp_data[1]),
+	OF_DEV_AUXDATA("arm,pl011", SPEAR320_UART1_BASE, NULL,
+			&spear320_uart_data[0]),
+	OF_DEV_AUXDATA("arm,pl011", SPEAR320_UART2_BASE, NULL,
+			&spear320_uart_data[1]),
+	{}
+};
+
+static void __init spear320_dt_init(void)
 {
 	void __iomem *base;
-	int ret = 0;
+	int ret;
 
-	/* call spear3xx family common init function */
-	spear3xx_init();
+	pl080_plat_data.slave_channels = spear320_dma_info;
+	pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear320_dma_info);
+
+	of_platform_populate(NULL, of_default_bus_match_table,
+			spear320_auxdata_lookup, NULL);
 
 	/* shared irq registration */
 	base = ioremap(SPEAR320_SOC_CONFIG_BASE, SZ_4K);
@@ -527,29 +459,40 @@
 		shirq_ras1.regs.base = base;
 		ret = spear_shirq_register(&shirq_ras1);
 		if (ret)
-			printk(KERN_ERR "Error registering Shared IRQ 1\n");
+			pr_err("Error registering Shared IRQ 1\n");
 
 		/* shirq 3 */
 		shirq_ras3.regs.base = base;
 		ret = spear_shirq_register(&shirq_ras3);
 		if (ret)
-			printk(KERN_ERR "Error registering Shared IRQ 3\n");
+			pr_err("Error registering Shared IRQ 3\n");
 
 		/* shirq 4 */
 		shirq_intrcomm_ras.regs.base = base;
 		ret = spear_shirq_register(&shirq_intrcomm_ras);
 		if (ret)
-			printk(KERN_ERR "Error registering Shared IRQ 4\n");
+			pr_err("Error registering Shared IRQ 4\n");
 	}
-
-	/* pmx initialization */
-	pmx_driver.base = base;
-	pmx_driver.mode = pmx_mode;
-	pmx_driver.devs = pmx_devs;
-	pmx_driver.devs_count = pmx_dev_count;
-
-	ret = pmx_register(&pmx_driver);
-	if (ret)
-		printk(KERN_ERR "padmux: registration failed. err no: %d\n",
-				ret);
 }
+
+static const char * const spear320_dt_board_compat[] = {
+	"st,spear320",
+	"st,spear320-evb",
+	NULL,
+};
+
+static void __init spear320_map_io(void)
+{
+	spear3xx_map_io();
+	spear320_clk_init();
+}
+
+DT_MACHINE_START(SPEAR320_DT, "ST SPEAr320 SoC with Flattened Device Tree")
+	.map_io		=	spear320_map_io,
+	.init_irq	=	spear3xx_dt_init_irq,
+	.handle_irq	=	vic_handle_irq,
+	.timer		=	&spear3xx_timer,
+	.init_machine	=	spear320_dt_init,
+	.restart	=	spear_restart,
+	.dt_compat	=	spear320_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear320_evb.c b/arch/arm/mach-spear3xx/spear320_evb.c
deleted file mode 100644
index 105334a..0000000
--- a/arch/arm/mach-spear3xx/spear320_evb.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/spear320_evb.c
- *
- * SPEAr320 evaluation board source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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 <asm/hardware/vic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* padmux devices to enable */
-static struct pmx_dev *pmx_devs[] = {
-	/* spear3xx specific devices */
-	&spear3xx_pmx_i2c,
-	&spear3xx_pmx_ssp,
-	&spear3xx_pmx_mii,
-	&spear3xx_pmx_uart0,
-
-	/* spear320 specific devices */
-	&spear320_pmx_fsmc,
-	&spear320_pmx_sdhci,
-	&spear320_pmx_i2s,
-	&spear320_pmx_uart1,
-	&spear320_pmx_uart2,
-	&spear320_pmx_can,
-	&spear320_pmx_pwm0,
-	&spear320_pmx_pwm1,
-	&spear320_pmx_pwm2,
-	&spear320_pmx_mii1,
-};
-
-static struct amba_device *amba_devs[] __initdata = {
-	/* spear3xx specific devices */
-	&spear3xx_gpio_device,
-	&spear3xx_uart_device,
-
-	/* spear320 specific devices */
-};
-
-static struct platform_device *plat_devs[] __initdata = {
-	/* spear3xx specific devices */
-
-	/* spear320 specific devices */
-};
-
-static void __init spear320_evb_init(void)
-{
-	unsigned int i;
-
-	/* call spear320 machine init function */
-	spear320_init(&spear320_auto_net_mii_mode, pmx_devs,
-			ARRAY_SIZE(pmx_devs));
-
-	/* Add Platform Devices */
-	platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
-
-	/* Add Amba Devices */
-	for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
-		amba_device_register(amba_devs[i], &iomem_resource);
-}
-
-MACHINE_START(SPEAR320, "ST-SPEAR320-EVB")
-	.atag_offset	=	0x100,
-	.map_io		=	spear3xx_map_io,
-	.init_irq	=	spear3xx_init_irq,
-	.handle_irq	=	vic_handle_irq,
-	.timer		=	&spear3xx_timer,
-	.init_machine	=	spear320_evb_init,
-	.restart	=	spear_restart,
-MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c
index b1733c3..826ac20 100644
--- a/arch/arm/mach-spear3xx/spear3xx.c
+++ b/arch/arm/mach-spear3xx/spear3xx.c
@@ -3,71 +3,78 @@
  *
  * SPEAr3XX machines common source file
  *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
  *
  * 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/types.h>
-#include <linux/amba/pl061.h>
-#include <linux/ptrace.h>
-#include <linux/io.h>
-#include <asm/hardware/vic.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
+#define pr_fmt(fmt) "SPEAr3xx: " fmt
 
-/* Add spear3xx machines common devices here */
-/* gpio device registration */
-static struct pl061_platform_data gpio_plat_data = {
-	.gpio_base	= 0,
-	.irq_base	= SPEAR3XX_GPIO_INT_BASE,
+#include <linux/amba/pl022.h>
+#include <linux/amba/pl08x.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <asm/hardware/pl080.h>
+#include <asm/hardware/vic.h>
+#include <plat/pl080.h>
+#include <mach/generic.h>
+#include <mach/spear.h>
+
+/* ssp device registration */
+struct pl022_ssp_controller pl022_plat_data = {
+	.bus_id = 0,
+	.enable_dma = 1,
+	.dma_filter = pl08x_filter_id,
+	.dma_tx_param = "ssp0_tx",
+	.dma_rx_param = "ssp0_rx",
+	/*
+	 * This is number of spi devices that can be connected to spi. There are
+	 * two type of chipselects on which slave devices can work. One is chip
+	 * select provided by spi masters other is controlled through external
+	 * gpio's. We can't use chipselect provided from spi master (because as
+	 * soon as FIFO becomes empty, CS is disabled and transfer ends). So
+	 * this number now depends on number of gpios available for spi. each
+	 * slave on each master requires a separate gpio pin.
+	 */
+	.num_chipselect = 2,
 };
 
-AMBA_APB_DEVICE(spear3xx_gpio, "gpio", 0, SPEAR3XX_ICM3_GPIO_BASE,
-	{SPEAR3XX_IRQ_BASIC_GPIO}, &gpio_plat_data);
+/* dmac device registration */
+struct pl08x_platform_data pl080_plat_data = {
+	.memcpy_channel = {
+		.bus_id = "memcpy",
+		.cctl = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT | \
+			PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT | \
+			PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | \
+			PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | \
+			PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE | \
+			PL080_CONTROL_PROT_SYS),
+	},
+	.lli_buses = PL08X_AHB1,
+	.mem_buses = PL08X_AHB1,
+	.get_signal = pl080_get_signal,
+	.put_signal = pl080_put_signal,
+};
 
-/* uart device registration */
-AMBA_APB_DEVICE(spear3xx_uart, "uart", 0, SPEAR3XX_ICM1_UART_BASE,
-	{SPEAR3XX_IRQ_UART}, NULL);
-
-/* Do spear3xx familiy common initialization part here */
-void __init spear3xx_init(void)
-{
-	/* nothing to do for now */
-}
-
-/* This will initialize vic */
-void __init spear3xx_init_irq(void)
-{
-	vic_init((void __iomem *)VA_SPEAR3XX_ML1_VIC_BASE, 0, ~0, 0);
-}
-
-/* Following will create static virtual/physical mappings */
+/*
+ * Following will create 16MB static virtual/physical mappings
+ * PHYSICAL		VIRTUAL
+ * 0xD0000000		0xFD000000
+ * 0xFC000000		0xFC000000
+ */
 struct map_desc spear3xx_io_desc[] __initdata = {
 	{
-		.virtual	= VA_SPEAR3XX_ICM1_UART_BASE,
-		.pfn		= __phys_to_pfn(SPEAR3XX_ICM1_UART_BASE),
-		.length		= SZ_4K,
+		.virtual	= VA_SPEAR3XX_ICM1_2_BASE,
+		.pfn		= __phys_to_pfn(SPEAR3XX_ICM1_2_BASE),
+		.length		= SZ_16M,
 		.type		= MT_DEVICE
 	}, {
-		.virtual	= VA_SPEAR3XX_ML1_VIC_BASE,
-		.pfn		= __phys_to_pfn(SPEAR3XX_ML1_VIC_BASE),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= VA_SPEAR3XX_ICM3_SYS_CTRL_BASE,
-		.pfn		= __phys_to_pfn(SPEAR3XX_ICM3_SYS_CTRL_BASE),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= VA_SPEAR3XX_ICM3_MISC_REG_BASE,
-		.pfn		= __phys_to_pfn(SPEAR3XX_ICM3_MISC_REG_BASE),
-		.length		= SZ_4K,
+		.virtual	= VA_SPEAR3XX_ICM3_SMI_CTRL_BASE,
+		.pfn		= __phys_to_pfn(SPEAR3XX_ICM3_SMI_CTRL_BASE),
+		.length		= SZ_16M,
 		.type		= MT_DEVICE
 	},
 };
@@ -76,436 +83,8 @@
 void __init spear3xx_map_io(void)
 {
 	iotable_init(spear3xx_io_desc, ARRAY_SIZE(spear3xx_io_desc));
-
-	/* This will initialize clock framework */
-	spear3xx_clk_init();
 }
 
-/* pad multiplexing support */
-/* devices */
-static struct pmx_dev_mode pmx_firda_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_FIRDA_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_firda = {
-	.name = "firda",
-	.modes = pmx_firda_modes,
-	.mode_count = ARRAY_SIZE(pmx_firda_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_i2c_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_I2C_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_i2c = {
-	.name = "i2c",
-	.modes = pmx_i2c_modes,
-	.mode_count = ARRAY_SIZE(pmx_i2c_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_ssp_cs_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_SSP_CS_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_ssp_cs = {
-	.name = "ssp_chip_selects",
-	.modes = pmx_ssp_cs_modes,
-	.mode_count = ARRAY_SIZE(pmx_ssp_cs_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_ssp_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_SSP_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_ssp = {
-	.name = "ssp",
-	.modes = pmx_ssp_modes,
-	.mode_count = ARRAY_SIZE(pmx_ssp_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_mii_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_mii = {
-	.name = "mii",
-	.modes = pmx_mii_modes,
-	.mode_count = ARRAY_SIZE(pmx_mii_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin0_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_GPIO_PIN0_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin0 = {
-	.name = "gpio_pin0",
-	.modes = pmx_gpio_pin0_modes,
-	.mode_count = ARRAY_SIZE(pmx_gpio_pin0_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin1_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_GPIO_PIN1_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin1 = {
-	.name = "gpio_pin1",
-	.modes = pmx_gpio_pin1_modes,
-	.mode_count = ARRAY_SIZE(pmx_gpio_pin1_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin2_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_GPIO_PIN2_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin2 = {
-	.name = "gpio_pin2",
-	.modes = pmx_gpio_pin2_modes,
-	.mode_count = ARRAY_SIZE(pmx_gpio_pin2_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin3_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_GPIO_PIN3_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin3 = {
-	.name = "gpio_pin3",
-	.modes = pmx_gpio_pin3_modes,
-	.mode_count = ARRAY_SIZE(pmx_gpio_pin3_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin4_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_GPIO_PIN4_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin4 = {
-	.name = "gpio_pin4",
-	.modes = pmx_gpio_pin4_modes,
-	.mode_count = ARRAY_SIZE(pmx_gpio_pin4_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin5_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_GPIO_PIN5_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin5 = {
-	.name = "gpio_pin5",
-	.modes = pmx_gpio_pin5_modes,
-	.mode_count = ARRAY_SIZE(pmx_gpio_pin5_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_uart0_modem_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_UART0_MODEM_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_uart0_modem = {
-	.name = "uart0_modem",
-	.modes = pmx_uart0_modem_modes,
-	.mode_count = ARRAY_SIZE(pmx_uart0_modem_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_uart0_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_UART0_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_uart0 = {
-	.name = "uart0",
-	.modes = pmx_uart0_modes,
-	.mode_count = ARRAY_SIZE(pmx_uart0_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_timer_3_4_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_TIMER_3_4_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_timer_3_4 = {
-	.name = "timer_3_4",
-	.modes = pmx_timer_3_4_modes,
-	.mode_count = ARRAY_SIZE(pmx_timer_3_4_modes),
-	.enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_timer_1_2_modes[] = {
-	{
-		.ids = 0xffffffff,
-		.mask = PMX_TIMER_1_2_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_timer_1_2 = {
-	.name = "timer_1_2",
-	.modes = pmx_timer_1_2_modes,
-	.mode_count = ARRAY_SIZE(pmx_timer_1_2_modes),
-	.enb_on_reset = 0,
-};
-
-#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
-/* plgpios devices */
-static struct pmx_dev_mode pmx_plgpio_0_1_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_FIRDA_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_0_1 = {
-	.name = "plgpio 0 and 1",
-	.modes = pmx_plgpio_0_1_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_0_1_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_2_3_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_UART0_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_2_3 = {
-	.name = "plgpio 2 and 3",
-	.modes = pmx_plgpio_2_3_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_2_3_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_4_5_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_I2C_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_4_5 = {
-	.name = "plgpio 4 and 5",
-	.modes = pmx_plgpio_4_5_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_4_5_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_6_9_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_SSP_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_6_9 = {
-	.name = "plgpio 6 to 9",
-	.modes = pmx_plgpio_6_9_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_6_9_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_10_27_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_MII_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_10_27 = {
-	.name = "plgpio 10 to 27",
-	.modes = pmx_plgpio_10_27_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_10_27_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_28_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_GPIO_PIN0_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_28 = {
-	.name = "plgpio 28",
-	.modes = pmx_plgpio_28_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_28_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_29_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_GPIO_PIN1_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_29 = {
-	.name = "plgpio 29",
-	.modes = pmx_plgpio_29_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_29_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_30_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_GPIO_PIN2_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_30 = {
-	.name = "plgpio 30",
-	.modes = pmx_plgpio_30_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_30_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_31_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_GPIO_PIN3_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_31 = {
-	.name = "plgpio 31",
-	.modes = pmx_plgpio_31_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_31_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_32_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_GPIO_PIN4_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_32 = {
-	.name = "plgpio 32",
-	.modes = pmx_plgpio_32_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_32_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_33_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_GPIO_PIN5_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_33 = {
-	.name = "plgpio 33",
-	.modes = pmx_plgpio_33_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_33_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_34_36_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_SSP_CS_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_34_36 = {
-	.name = "plgpio 34 to 36",
-	.modes = pmx_plgpio_34_36_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_34_36_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_37_42_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_UART0_MODEM_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_37_42 = {
-	.name = "plgpio 37 to 42",
-	.modes = pmx_plgpio_37_42_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_37_42_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_43_44_47_48_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_TIMER_1_2_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_43_44_47_48 = {
-	.name = "plgpio 43, 44, 47 and 48",
-	.modes = pmx_plgpio_43_44_47_48_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_43_44_47_48_modes),
-	.enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_45_46_49_50_modes[] = {
-	{
-		.ids = 0x00,
-		.mask = PMX_TIMER_3_4_MASK,
-	},
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_45_46_49_50 = {
-	.name = "plgpio 45, 46, 49 and 50",
-	.modes = pmx_plgpio_45_46_49_50_modes,
-	.mode_count = ARRAY_SIZE(pmx_plgpio_45_46_49_50_modes),
-	.enb_on_reset = 1,
-};
-#endif /* CONFIG_MACH_SPEAR310 || CONFIG_MACH_SPEAR320 */
-
 static void __init spear3xx_timer_init(void)
 {
 	char pclk_name[] = "pll3_48m_clk";
@@ -530,9 +109,19 @@
 	clk_put(gpt_clk);
 	clk_put(pclk);
 
-	spear_setup_timer();
+	spear_setup_timer(SPEAR3XX_CPU_TMR_BASE, SPEAR3XX_IRQ_CPU_GPT1_1);
 }
 
 struct sys_timer spear3xx_timer = {
 	.init = spear3xx_timer_init,
 };
+
+static const struct of_device_id vic_of_match[] __initconst = {
+	{ .compatible = "arm,pl190-vic", .data = vic_of_init, },
+	{ /* Sentinel */ }
+};
+
+void __init spear3xx_dt_init_irq(void)
+{
+	of_irq_init(vic_of_match);
+}
diff --git a/arch/arm/mach-spear6xx/Kconfig b/arch/arm/mach-spear6xx/Kconfig
index fbe298b..339f397 100644
--- a/arch/arm/mach-spear6xx/Kconfig
+++ b/arch/arm/mach-spear6xx/Kconfig
@@ -2,21 +2,9 @@
 # SPEAr6XX Machine configuration file
 #
 
-if ARCH_SPEAR6XX
-
-menu "SPEAr6xx Implementations"
-config BOARD_SPEAR600_DT
-	bool "SPEAr600 generic board configured via device-tree"
-	select MACH_SPEAR600
+config MACH_SPEAR600
+	def_bool y
+	depends on ARCH_SPEAR6XX
 	select USE_OF
 	help
 	  Supports ST SPEAr600 boards configured via the device-tree
-
-endmenu
-
-config MACH_SPEAR600
-	bool "SPEAr600"
-	help
-	  Supports ST SPEAr600 Machine
-
-endif #ARCH_SPEAR6XX
diff --git a/arch/arm/mach-spear6xx/Makefile.boot b/arch/arm/mach-spear6xx/Makefile.boot
index 4674a4c..af493da 100644
--- a/arch/arm/mach-spear6xx/Makefile.boot
+++ b/arch/arm/mach-spear6xx/Makefile.boot
@@ -1,3 +1,5 @@
 zreladdr-y	+= 0x00008000
 params_phys-y	:= 0x00000100
 initrd_phys-y	:= 0x00800000
+
+dtb-$(CONFIG_BOARD_SPEAR600_DT)	+= spear600-evb.dtb
diff --git a/arch/arm/mach-spear6xx/clock.c b/arch/arm/mach-spear6xx/clock.c
index a86499a..bef77d4 100644
--- a/arch/arm/mach-spear6xx/clock.c
+++ b/arch/arm/mach-spear6xx/clock.c
@@ -16,6 +16,112 @@
 #include <linux/kernel.h>
 #include <plat/clock.h>
 #include <mach/misc_regs.h>
+#include <mach/spear.h>
+
+#define PLL1_CTR		(MISC_BASE + 0x008)
+#define PLL1_FRQ		(MISC_BASE + 0x00C)
+#define PLL1_MOD		(MISC_BASE + 0x010)
+#define PLL2_CTR		(MISC_BASE + 0x014)
+/* PLL_CTR register masks */
+#define PLL_ENABLE		2
+#define PLL_MODE_SHIFT		4
+#define PLL_MODE_MASK		0x3
+#define PLL_MODE_NORMAL		0
+#define PLL_MODE_FRACTION	1
+#define PLL_MODE_DITH_DSB	2
+#define PLL_MODE_DITH_SSB	3
+
+#define PLL2_FRQ		(MISC_BASE + 0x018)
+/* PLL FRQ register masks */
+#define PLL_DIV_N_SHIFT		0
+#define PLL_DIV_N_MASK		0xFF
+#define PLL_DIV_P_SHIFT		8
+#define PLL_DIV_P_MASK		0x7
+#define PLL_NORM_FDBK_M_SHIFT	24
+#define PLL_NORM_FDBK_M_MASK	0xFF
+#define PLL_DITH_FDBK_M_SHIFT	16
+#define PLL_DITH_FDBK_M_MASK	0xFFFF
+
+#define PLL2_MOD		(MISC_BASE + 0x01C)
+#define PLL_CLK_CFG		(MISC_BASE + 0x020)
+#define CORE_CLK_CFG		(MISC_BASE + 0x024)
+/* CORE CLK CFG register masks */
+#define PLL_HCLK_RATIO_SHIFT	10
+#define PLL_HCLK_RATIO_MASK	0x3
+#define HCLK_PCLK_RATIO_SHIFT	8
+#define HCLK_PCLK_RATIO_MASK	0x3
+
+#define PERIP_CLK_CFG		(MISC_BASE + 0x028)
+/* PERIP_CLK_CFG register masks */
+#define CLCD_CLK_SHIFT		2
+#define CLCD_CLK_MASK		0x3
+#define UART_CLK_SHIFT		4
+#define UART_CLK_MASK		0x1
+#define FIRDA_CLK_SHIFT		5
+#define FIRDA_CLK_MASK		0x3
+#define GPT0_CLK_SHIFT		8
+#define GPT1_CLK_SHIFT		10
+#define GPT2_CLK_SHIFT		11
+#define GPT3_CLK_SHIFT		12
+#define GPT_CLK_MASK		0x1
+#define AUX_CLK_PLL3_VAL	0
+#define AUX_CLK_PLL1_VAL	1
+
+#define PERIP1_CLK_ENB		(MISC_BASE + 0x02C)
+/* PERIP1_CLK_ENB register masks */
+#define UART0_CLK_ENB		3
+#define UART1_CLK_ENB		4
+#define SSP0_CLK_ENB		5
+#define SSP1_CLK_ENB		6
+#define I2C_CLK_ENB		7
+#define JPEG_CLK_ENB		8
+#define FSMC_CLK_ENB		9
+#define FIRDA_CLK_ENB		10
+#define GPT2_CLK_ENB		11
+#define GPT3_CLK_ENB		12
+#define GPIO2_CLK_ENB		13
+#define SSP2_CLK_ENB		14
+#define ADC_CLK_ENB		15
+#define GPT1_CLK_ENB		11
+#define RTC_CLK_ENB		17
+#define GPIO1_CLK_ENB		18
+#define DMA_CLK_ENB		19
+#define SMI_CLK_ENB		21
+#define CLCD_CLK_ENB		22
+#define GMAC_CLK_ENB		23
+#define USBD_CLK_ENB		24
+#define USBH0_CLK_ENB		25
+#define USBH1_CLK_ENB		26
+
+#define PRSC1_CLK_CFG		(MISC_BASE + 0x044)
+#define PRSC2_CLK_CFG		(MISC_BASE + 0x048)
+#define PRSC3_CLK_CFG		(MISC_BASE + 0x04C)
+/* gpt synthesizer register masks */
+#define GPT_MSCALE_SHIFT	0
+#define GPT_MSCALE_MASK		0xFFF
+#define GPT_NSCALE_SHIFT	12
+#define GPT_NSCALE_MASK		0xF
+
+#define AMEM_CLK_CFG		(MISC_BASE + 0x050)
+#define EXPI_CLK_CFG		(MISC_BASE + 0x054)
+#define CLCD_CLK_SYNT		(MISC_BASE + 0x05C)
+#define FIRDA_CLK_SYNT		(MISC_BASE + 0x060)
+#define UART_CLK_SYNT		(MISC_BASE + 0x064)
+#define GMAC_CLK_SYNT		(MISC_BASE + 0x068)
+#define RAS1_CLK_SYNT		(MISC_BASE + 0x06C)
+#define RAS2_CLK_SYNT		(MISC_BASE + 0x070)
+#define RAS3_CLK_SYNT		(MISC_BASE + 0x074)
+#define RAS4_CLK_SYNT		(MISC_BASE + 0x078)
+/* aux clk synthesiser register masks for irda to ras4 */
+#define AUX_SYNT_ENB		31
+#define AUX_EQ_SEL_SHIFT	30
+#define AUX_EQ_SEL_MASK		1
+#define AUX_EQ1_SEL		0
+#define AUX_EQ2_SEL		1
+#define AUX_XSCALE_SHIFT	16
+#define AUX_XSCALE_MASK		0xFFF
+#define AUX_YSCALE_SHIFT	0
+#define AUX_YSCALE_MASK		0xFFF
 
 /* root clks */
 /* 32 KHz oscillator clock */
@@ -623,53 +729,53 @@
 
 /* array of all spear 6xx clock lookups */
 static struct clk_lookup spear_clk_lookups[] = {
-	{ .con_id = "apb_pclk",		.clk = &dummy_apb_pclk},
+	CLKDEV_INIT(NULL, "apb_pclk", &dummy_apb_pclk),
 	/* root clks */
-	{ .con_id = "osc_32k_clk",	.clk = &osc_32k_clk},
-	{ .con_id = "osc_30m_clk",	.clk = &osc_30m_clk},
+	CLKDEV_INIT(NULL, "osc_32k_clk", &osc_32k_clk),
+	CLKDEV_INIT(NULL, "osc_30m_clk", &osc_30m_clk),
 	/* clock derived from 32 KHz os		 clk */
-	{ .dev_id = "rtc-spear",	.clk = &rtc_clk},
+	CLKDEV_INIT("rtc-spear", NULL, &rtc_clk),
 	/* clock derived from 30 MHz os		 clk */
-	{ .con_id = "pll1_clk",		.clk = &pll1_clk},
-	{ .con_id = "pll3_48m_clk",	.clk = &pll3_48m_clk},
-	{ .dev_id = "wdt",		.clk = &wdt_clk},
+	CLKDEV_INIT(NULL, "pll1_clk", &pll1_clk),
+	CLKDEV_INIT(NULL, "pll3_48m_clk", &pll3_48m_clk),
+	CLKDEV_INIT("wdt", NULL, &wdt_clk),
 	/* clock derived from pll1 clk */
-	{ .con_id = "cpu_clk",		.clk = &cpu_clk},
-	{ .con_id = "ahb_clk",		.clk = &ahb_clk},
-	{ .con_id = "uart_synth_clk",	.clk = &uart_synth_clk},
-	{ .con_id = "firda_synth_clk",	.clk = &firda_synth_clk},
-	{ .con_id = "clcd_synth_clk",	.clk = &clcd_synth_clk},
-	{ .con_id = "gpt0_synth_clk",	.clk = &gpt0_synth_clk},
-	{ .con_id = "gpt2_synth_clk",	.clk = &gpt2_synth_clk},
-	{ .con_id = "gpt3_synth_clk",	.clk = &gpt3_synth_clk},
-	{ .dev_id = "d0000000.serial",	.clk = &uart0_clk},
-	{ .dev_id = "d0080000.serial",	.clk = &uart1_clk},
-	{ .dev_id = "firda",		.clk = &firda_clk},
-	{ .dev_id = "clcd",		.clk = &clcd_clk},
-	{ .dev_id = "gpt0",		.clk = &gpt0_clk},
-	{ .dev_id = "gpt1",		.clk = &gpt1_clk},
-	{ .dev_id = "gpt2",		.clk = &gpt2_clk},
-	{ .dev_id = "gpt3",		.clk = &gpt3_clk},
+	CLKDEV_INIT(NULL, "cpu_clk", &cpu_clk),
+	CLKDEV_INIT(NULL, "ahb_clk", &ahb_clk),
+	CLKDEV_INIT(NULL, "uart_synth_clk", &uart_synth_clk),
+	CLKDEV_INIT(NULL, "firda_synth_clk", &firda_synth_clk),
+	CLKDEV_INIT(NULL, "clcd_synth_clk", &clcd_synth_clk),
+	CLKDEV_INIT(NULL, "gpt0_synth_clk", &gpt0_synth_clk),
+	CLKDEV_INIT(NULL, "gpt2_synth_clk", &gpt2_synth_clk),
+	CLKDEV_INIT(NULL, "gpt3_synth_clk", &gpt3_synth_clk),
+	CLKDEV_INIT("d0000000.serial", NULL, &uart0_clk),
+	CLKDEV_INIT("d0080000.serial", NULL, &uart1_clk),
+	CLKDEV_INIT("firda", NULL, &firda_clk),
+	CLKDEV_INIT("clcd", NULL, &clcd_clk),
+	CLKDEV_INIT("gpt0", NULL, &gpt0_clk),
+	CLKDEV_INIT("gpt1", NULL, &gpt1_clk),
+	CLKDEV_INIT("gpt2", NULL, &gpt2_clk),
+	CLKDEV_INIT("gpt3", NULL, &gpt3_clk),
 	/* clock derived from pll3 clk */
-	{ .dev_id = "designware_udc",	.clk = &usbd_clk},
-	{ .con_id = "usbh.0_clk",	.clk = &usbh0_clk},
-	{ .con_id = "usbh.1_clk",	.clk = &usbh1_clk},
+	CLKDEV_INIT("designware_udc", NULL, &usbd_clk),
+	CLKDEV_INIT(NULL, "usbh.0_clk", &usbh0_clk),
+	CLKDEV_INIT(NULL, "usbh.1_clk", &usbh1_clk),
 	/* clock derived from ahb clk */
-	{ .con_id = "apb_clk",		.clk = &apb_clk},
-	{ .dev_id = "d0200000.i2c",	.clk = &i2c_clk},
-	{ .dev_id = "dma",		.clk = &dma_clk},
-	{ .dev_id = "jpeg",		.clk = &jpeg_clk},
-	{ .dev_id = "gmac",		.clk = &gmac_clk},
-	{ .dev_id = "smi",		.clk = &smi_clk},
-	{ .dev_id = "fsmc-nand",	.clk = &fsmc_clk},
+	CLKDEV_INIT(NULL, "apb_clk", &apb_clk),
+	CLKDEV_INIT("d0200000.i2c", NULL, &i2c_clk),
+	CLKDEV_INIT("fc400000.dma", NULL, &dma_clk),
+	CLKDEV_INIT("jpeg", NULL, &jpeg_clk),
+	CLKDEV_INIT("gmac", NULL, &gmac_clk),
+	CLKDEV_INIT("fc000000.flash", NULL, &smi_clk),
+	CLKDEV_INIT("d1800000.flash", NULL, &fsmc_clk),
 	/* clock derived from apb clk */
-	{ .dev_id = "adc",		.clk = &adc_clk},
-	{ .dev_id = "ssp-pl022.0",	.clk = &ssp0_clk},
-	{ .dev_id = "ssp-pl022.1",	.clk = &ssp1_clk},
-	{ .dev_id = "ssp-pl022.2",	.clk = &ssp2_clk},
-	{ .dev_id = "f0100000.gpio",	.clk = &gpio0_clk},
-	{ .dev_id = "fc980000.gpio",	.clk = &gpio1_clk},
-	{ .dev_id = "d8100000.gpio",	.clk = &gpio2_clk},
+	CLKDEV_INIT("adc", NULL, &adc_clk),
+	CLKDEV_INIT("ssp-pl022.0", NULL, &ssp0_clk),
+	CLKDEV_INIT("ssp-pl022.1", NULL, &ssp1_clk),
+	CLKDEV_INIT("ssp-pl022.2", NULL, &ssp2_clk),
+	CLKDEV_INIT("f0100000.gpio", NULL, &gpio0_clk),
+	CLKDEV_INIT("fc980000.gpio", NULL, &gpio1_clk),
+	CLKDEV_INIT("d8100000.gpio", NULL, &gpio2_clk),
 };
 
 void __init spear6xx_clk_init(void)
diff --git a/arch/arm/mach-spear6xx/include/mach/generic.h b/arch/arm/mach-spear6xx/include/mach/generic.h
index 116b993..7167fd3 100644
--- a/arch/arm/mach-spear6xx/include/mach/generic.h
+++ b/arch/arm/mach-spear6xx/include/mach/generic.h
@@ -15,34 +15,9 @@
 #define __MACH_GENERIC_H
 
 #include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <asm/mach/time.h>
-#include <asm/mach/map.h>
 
-/*
- * Each GPT has 2 timer channels
- * Following GPT channels will be used as clock source and clockevent
- */
-#define SPEAR_GPT0_BASE		SPEAR6XX_CPU_TMR_BASE
-#define SPEAR_GPT0_CHAN0_IRQ	IRQ_CPU_GPT1_1
-#define SPEAR_GPT0_CHAN1_IRQ	IRQ_CPU_GPT1_2
-
-/* Add spear6xx family device structure declarations here */
-extern struct amba_device gpio_device[];
-extern struct amba_device uart_device[];
-extern struct sys_timer spear6xx_timer;
-
-/* Add spear6xx family function declarations here */
-void __init spear_setup_timer(void);
-void __init spear6xx_map_io(void);
-void __init spear6xx_init_irq(void);
-void __init spear6xx_init(void);
-void __init spear600_init(void);
-void __init spear6xx_clk_init(void);
-
+void __init spear_setup_timer(resource_size_t base, int irq);
 void spear_restart(char, const char *);
-
-/* Add spear600 machine device structure declarations here */
+void __init spear6xx_clk_init(void);
 
 #endif /* __MACH_GENERIC_H */
diff --git a/arch/arm/mach-spear6xx/include/mach/hardware.h b/arch/arm/mach-spear6xx/include/mach/hardware.h
index 0b3f96a..40a8c17 100644
--- a/arch/arm/mach-spear6xx/include/mach/hardware.h
+++ b/arch/arm/mach-spear6xx/include/mach/hardware.h
@@ -1,23 +1 @@
-/*
- * arch/arm/mach-spear6xx/include/mach/hardware.h
- *
- * Hardware definitions for SPEAr6xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
- *
- * 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 __MACH_HARDWARE_H
-#define __MACH_HARDWARE_H
-
-#include <plat/hardware.h>
-#include <mach/spear.h>
-
-/* Vitual to physical translation of statically mapped space */
-#define IO_ADDRESS(x)		(x | 0xF0000000)
-
-#endif /* __MACH_HARDWARE_H */
+/* empty */
diff --git a/arch/arm/mach-spear6xx/include/mach/irqs.h b/arch/arm/mach-spear6xx/include/mach/irqs.h
index 8f214b0..2b73538 100644
--- a/arch/arm/mach-spear6xx/include/mach/irqs.h
+++ b/arch/arm/mach-spear6xx/include/mach/irqs.h
@@ -16,82 +16,13 @@
 
 /* IRQ definitions */
 /* VIC 1 */
-#define IRQ_INTRCOMM_SW_IRQ			0
-#define IRQ_INTRCOMM_CPU_1			1
-#define IRQ_INTRCOMM_CPU_2			2
-#define IRQ_INTRCOMM_RAS2A11_1			3
-#define IRQ_INTRCOMM_RAS2A11_2			4
-#define IRQ_INTRCOMM_RAS2A12_1			5
-#define IRQ_INTRCOMM_RAS2A12_2			6
-#define IRQ_GEN_RAS_0				7
-#define IRQ_GEN_RAS_1				8
-#define IRQ_GEN_RAS_2				9
-#define IRQ_GEN_RAS_3				10
-#define IRQ_GEN_RAS_4				11
-#define IRQ_GEN_RAS_5				12
-#define IRQ_GEN_RAS_6				13
-#define IRQ_GEN_RAS_7				14
-#define IRQ_GEN_RAS_8				15
+/* FIXME: probe this from DT */
 #define IRQ_CPU_GPT1_1				16
-#define IRQ_CPU_GPT1_2				17
-#define IRQ_LOCAL_GPIO				18
-#define IRQ_PLL_UNLOCK				19
-#define IRQ_JPEG				20
-#define IRQ_FSMC				21
-#define IRQ_IRDA				22
-#define IRQ_RESERVED				23
-#define IRQ_UART_0				24
-#define IRQ_UART_1				25
-#define IRQ_SSP_1				26
-#define IRQ_SSP_2				27
-#define IRQ_I2C					28
-#define IRQ_GEN_RAS_9				29
-#define IRQ_GEN_RAS_10				30
-#define IRQ_GEN_RAS_11				31
-
-/* VIC 2 */
-#define IRQ_APPL_GPT1_1				32
-#define IRQ_APPL_GPT1_2				33
-#define IRQ_APPL_GPT2_1				34
-#define IRQ_APPL_GPT2_2				35
-#define IRQ_APPL_GPIO				36
-#define IRQ_APPL_SSP				37
-#define IRQ_APPL_ADC				38
-#define IRQ_APPL_RESERVED			39
-#define IRQ_AHB_EXP_MASTER			40
-#define IRQ_DDR_CONTROLLER			41
-#define IRQ_BASIC_DMA				42
-#define IRQ_BASIC_RESERVED1			43
-#define IRQ_BASIC_SMI				44
-#define IRQ_BASIC_CLCD				45
-#define IRQ_EXP_AHB_1				46
-#define IRQ_EXP_AHB_2				47
-#define IRQ_BASIC_GPT1_1			48
-#define IRQ_BASIC_GPT1_2			49
-#define IRQ_BASIC_RTC				50
-#define IRQ_BASIC_GPIO				51
-#define IRQ_BASIC_WDT				52
-#define IRQ_BASIC_RESERVED			53
-#define IRQ_AHB_EXP_SLAVE			54
-#define IRQ_GMAC_1				55
-#define IRQ_GMAC_2				56
-#define IRQ_USB_DEV				57
-#define IRQ_USB_H_OHCI_0			58
-#define IRQ_USB_H_EHCI_0			59
-#define IRQ_USB_H_OHCI_1			60
-#define IRQ_USB_H_EHCI_1			61
-#define IRQ_EXP_AHB_3				62
-#define IRQ_EXP_AHB_4				63
 
 #define IRQ_VIC_END				64
 
 /* GPIO pins virtual irqs */
-#define SPEAR_GPIO_INT_BASE	IRQ_VIC_END
-#define SPEAR_GPIO0_INT_BASE	SPEAR_GPIO_INT_BASE
-#define SPEAR_GPIO1_INT_BASE	(SPEAR_GPIO0_INT_BASE + 8)
-#define SPEAR_GPIO2_INT_BASE	(SPEAR_GPIO1_INT_BASE + 8)
-#define SPEAR_GPIO_INT_END	(SPEAR_GPIO2_INT_BASE + 8)
-#define VIRTUAL_IRQS		(SPEAR_GPIO_INT_END - IRQ_VIC_END)
-#define NR_IRQS			(IRQ_VIC_END + VIRTUAL_IRQS)
+#define VIRTUAL_IRQS				24
+#define NR_IRQS					(IRQ_VIC_END + VIRTUAL_IRQS)
 
 #endif	/* __MACH_IRQS_H */
diff --git a/arch/arm/mach-spear6xx/include/mach/misc_regs.h b/arch/arm/mach-spear6xx/include/mach/misc_regs.h
index 68c20a0..2b9aaa6 100644
--- a/arch/arm/mach-spear6xx/include/mach/misc_regs.h
+++ b/arch/arm/mach-spear6xx/include/mach/misc_regs.h
@@ -14,161 +14,7 @@
 #ifndef __MACH_MISC_REGS_H
 #define __MACH_MISC_REGS_H
 
-#include <mach/hardware.h>
-
 #define MISC_BASE		IOMEM(VA_SPEAR6XX_ICM3_MISC_REG_BASE)
-
-#define SOC_CFG_CTR		(MISC_BASE + 0x000)
-#define DIAG_CFG_CTR		(MISC_BASE + 0x004)
-#define PLL1_CTR		(MISC_BASE + 0x008)
-#define PLL1_FRQ		(MISC_BASE + 0x00C)
-#define PLL1_MOD		(MISC_BASE + 0x010)
-#define PLL2_CTR		(MISC_BASE + 0x014)
-/* PLL_CTR register masks */
-#define PLL_ENABLE		2
-#define PLL_MODE_SHIFT		4
-#define PLL_MODE_MASK		0x3
-#define PLL_MODE_NORMAL		0
-#define PLL_MODE_FRACTION	1
-#define PLL_MODE_DITH_DSB	2
-#define PLL_MODE_DITH_SSB	3
-
-#define PLL2_FRQ		(MISC_BASE + 0x018)
-/* PLL FRQ register masks */
-#define PLL_DIV_N_SHIFT		0
-#define PLL_DIV_N_MASK		0xFF
-#define PLL_DIV_P_SHIFT		8
-#define PLL_DIV_P_MASK		0x7
-#define PLL_NORM_FDBK_M_SHIFT	24
-#define PLL_NORM_FDBK_M_MASK	0xFF
-#define PLL_DITH_FDBK_M_SHIFT	16
-#define PLL_DITH_FDBK_M_MASK	0xFFFF
-
-#define PLL2_MOD		(MISC_BASE + 0x01C)
-#define PLL_CLK_CFG		(MISC_BASE + 0x020)
-#define CORE_CLK_CFG		(MISC_BASE + 0x024)
-/* CORE CLK CFG register masks */
-#define PLL_HCLK_RATIO_SHIFT	10
-#define PLL_HCLK_RATIO_MASK	0x3
-#define HCLK_PCLK_RATIO_SHIFT	8
-#define HCLK_PCLK_RATIO_MASK	0x3
-
-#define PERIP_CLK_CFG		(MISC_BASE + 0x028)
-/* PERIP_CLK_CFG register masks */
-#define CLCD_CLK_SHIFT		2
-#define CLCD_CLK_MASK		0x3
-#define UART_CLK_SHIFT		4
-#define UART_CLK_MASK		0x1
-#define FIRDA_CLK_SHIFT		5
-#define FIRDA_CLK_MASK		0x3
-#define GPT0_CLK_SHIFT		8
-#define GPT1_CLK_SHIFT		10
-#define GPT2_CLK_SHIFT		11
-#define GPT3_CLK_SHIFT		12
-#define GPT_CLK_MASK		0x1
-#define AUX_CLK_PLL3_VAL	0
-#define AUX_CLK_PLL1_VAL	1
-
-#define PERIP1_CLK_ENB		(MISC_BASE + 0x02C)
-/* PERIP1_CLK_ENB register masks */
-#define UART0_CLK_ENB		3
-#define UART1_CLK_ENB		4
-#define SSP0_CLK_ENB		5
-#define SSP1_CLK_ENB		6
-#define I2C_CLK_ENB		7
-#define JPEG_CLK_ENB		8
-#define FSMC_CLK_ENB		9
-#define FIRDA_CLK_ENB		10
-#define GPT2_CLK_ENB		11
-#define GPT3_CLK_ENB		12
-#define GPIO2_CLK_ENB		13
-#define SSP2_CLK_ENB		14
-#define ADC_CLK_ENB		15
-#define GPT1_CLK_ENB		11
-#define RTC_CLK_ENB		17
-#define GPIO1_CLK_ENB		18
-#define DMA_CLK_ENB		19
-#define SMI_CLK_ENB		21
-#define CLCD_CLK_ENB		22
-#define GMAC_CLK_ENB		23
-#define USBD_CLK_ENB		24
-#define USBH0_CLK_ENB		25
-#define USBH1_CLK_ENB		26
-
-#define SOC_CORE_ID		(MISC_BASE + 0x030)
-#define RAS_CLK_ENB		(MISC_BASE + 0x034)
-#define PERIP1_SOF_RST		(MISC_BASE + 0x038)
-/* PERIP1_SOF_RST register masks */
-#define JPEG_SOF_RST		8
-
-#define SOC_USER_ID		(MISC_BASE + 0x03C)
-#define RAS_SOF_RST		(MISC_BASE + 0x040)
-#define PRSC1_CLK_CFG		(MISC_BASE + 0x044)
-#define PRSC2_CLK_CFG		(MISC_BASE + 0x048)
-#define PRSC3_CLK_CFG		(MISC_BASE + 0x04C)
-/* gpt synthesizer register masks */
-#define GPT_MSCALE_SHIFT	0
-#define GPT_MSCALE_MASK		0xFFF
-#define GPT_NSCALE_SHIFT	12
-#define GPT_NSCALE_MASK		0xF
-
-#define AMEM_CLK_CFG		(MISC_BASE + 0x050)
-#define EXPI_CLK_CFG		(MISC_BASE + 0x054)
-#define CLCD_CLK_SYNT		(MISC_BASE + 0x05C)
-#define FIRDA_CLK_SYNT		(MISC_BASE + 0x060)
-#define UART_CLK_SYNT		(MISC_BASE + 0x064)
-#define GMAC_CLK_SYNT		(MISC_BASE + 0x068)
-#define RAS1_CLK_SYNT		(MISC_BASE + 0x06C)
-#define RAS2_CLK_SYNT		(MISC_BASE + 0x070)
-#define RAS3_CLK_SYNT		(MISC_BASE + 0x074)
-#define RAS4_CLK_SYNT		(MISC_BASE + 0x078)
-/* aux clk synthesiser register masks for irda to ras4 */
-#define AUX_SYNT_ENB		31
-#define AUX_EQ_SEL_SHIFT	30
-#define AUX_EQ_SEL_MASK		1
-#define AUX_EQ1_SEL		0
-#define AUX_EQ2_SEL		1
-#define AUX_XSCALE_SHIFT	16
-#define AUX_XSCALE_MASK		0xFFF
-#define AUX_YSCALE_SHIFT	0
-#define AUX_YSCALE_MASK		0xFFF
-
-#define ICM1_ARB_CFG		(MISC_BASE + 0x07C)
-#define ICM2_ARB_CFG		(MISC_BASE + 0x080)
-#define ICM3_ARB_CFG		(MISC_BASE + 0x084)
-#define ICM4_ARB_CFG		(MISC_BASE + 0x088)
-#define ICM5_ARB_CFG		(MISC_BASE + 0x08C)
-#define ICM6_ARB_CFG		(MISC_BASE + 0x090)
-#define ICM7_ARB_CFG		(MISC_BASE + 0x094)
-#define ICM8_ARB_CFG		(MISC_BASE + 0x098)
-#define ICM9_ARB_CFG		(MISC_BASE + 0x09C)
 #define DMA_CHN_CFG		(MISC_BASE + 0x0A0)
-#define USB2_PHY_CFG		(MISC_BASE + 0x0A4)
-#define GMAC_CFG_CTR		(MISC_BASE + 0x0A8)
-#define EXPI_CFG_CTR		(MISC_BASE + 0x0AC)
-#define PRC1_LOCK_CTR		(MISC_BASE + 0x0C0)
-#define PRC2_LOCK_CTR		(MISC_BASE + 0x0C4)
-#define PRC3_LOCK_CTR		(MISC_BASE + 0x0C8)
-#define PRC4_LOCK_CTR		(MISC_BASE + 0x0CC)
-#define PRC1_IRQ_CTR		(MISC_BASE + 0x0D0)
-#define PRC2_IRQ_CTR		(MISC_BASE + 0x0D4)
-#define PRC3_IRQ_CTR		(MISC_BASE + 0x0D8)
-#define PRC4_IRQ_CTR		(MISC_BASE + 0x0DC)
-#define PWRDOWN_CFG_CTR		(MISC_BASE + 0x0E0)
-#define COMPSSTL_1V8_CFG	(MISC_BASE + 0x0E4)
-#define COMPSSTL_2V5_CFG	(MISC_BASE + 0x0E8)
-#define COMPCOR_3V3_CFG		(MISC_BASE + 0x0EC)
-#define SSTLPAD_CFG_CTR		(MISC_BASE + 0x0F0)
-#define BIST1_CFG_CTR		(MISC_BASE + 0x0F4)
-#define BIST2_CFG_CTR		(MISC_BASE + 0x0F8)
-#define BIST3_CFG_CTR		(MISC_BASE + 0x0FC)
-#define BIST4_CFG_CTR		(MISC_BASE + 0x100)
-#define BIST5_CFG_CTR		(MISC_BASE + 0x104)
-#define BIST1_STS_RES		(MISC_BASE + 0x108)
-#define BIST2_STS_RES		(MISC_BASE + 0x10C)
-#define BIST3_STS_RES		(MISC_BASE + 0x110)
-#define BIST4_STS_RES		(MISC_BASE + 0x114)
-#define BIST5_STS_RES		(MISC_BASE + 0x118)
-#define SYSERR_CFG_CTR		(MISC_BASE + 0x11C)
 
 #endif /* __MACH_MISC_REGS_H */
diff --git a/arch/arm/mach-spear6xx/include/mach/spear.h b/arch/arm/mach-spear6xx/include/mach/spear.h
index 7fd6215..d278ed0 100644
--- a/arch/arm/mach-spear6xx/include/mach/spear.h
+++ b/arch/arm/mach-spear6xx/include/mach/spear.h
@@ -15,69 +15,26 @@
 #define __MACH_SPEAR6XX_H
 
 #include <asm/memory.h>
-#include <mach/spear600.h>
 
-#define SPEAR6XX_ML_SDRAM_BASE		UL(0x00000000)
 /* ICM1 - Low speed connection */
 #define SPEAR6XX_ICM1_BASE		UL(0xD0000000)
-
+#define VA_SPEAR6XX_ICM1_BASE		UL(0xFD000000)
 #define SPEAR6XX_ICM1_UART0_BASE	UL(0xD0000000)
-#define VA_SPEAR6XX_ICM1_UART0_BASE	IO_ADDRESS(SPEAR6XX_ICM1_UART0_BASE)
-
-#define SPEAR6XX_ICM1_UART1_BASE	UL(0xD0080000)
-#define SPEAR6XX_ICM1_SSP0_BASE		UL(0xD0100000)
-#define SPEAR6XX_ICM1_SSP1_BASE		UL(0xD0180000)
-#define SPEAR6XX_ICM1_I2C_BASE		UL(0xD0200000)
-#define SPEAR6XX_ICM1_JPEG_BASE		UL(0xD0800000)
-#define SPEAR6XX_ICM1_IRDA_BASE		UL(0xD1000000)
-#define SPEAR6XX_ICM1_FSMC_BASE		UL(0xD1800000)
-#define SPEAR6XX_ICM1_NAND_BASE		UL(0xD2000000)
-#define SPEAR6XX_ICM1_SRAM_BASE		UL(0xD2800000)
-
-/* ICM2 - Application Subsystem */
-#define SPEAR6XX_ICM2_BASE		UL(0xD8000000)
-#define SPEAR6XX_ICM2_TMR0_BASE		UL(0xD8000000)
-#define SPEAR6XX_ICM2_TMR1_BASE		UL(0xD8080000)
-#define SPEAR6XX_ICM2_GPIO_BASE		UL(0xD8100000)
-#define SPEAR6XX_ICM2_SSP2_BASE		UL(0xD8180000)
-#define SPEAR6XX_ICM2_ADC_BASE		UL(0xD8200000)
+#define VA_SPEAR6XX_ICM1_UART0_BASE	(VA_SPEAR6XX_ICM1_2_BASE | SPEAR6XX_ICM1_UART0_BASE)
 
 /* ML-1, 2 - Multi Layer CPU Subsystem */
 #define SPEAR6XX_ML_CPU_BASE		UL(0xF0000000)
+#define VA_SPEAR6XX_ML_CPU_BASE		UL(0xF0000000)
 #define SPEAR6XX_CPU_TMR_BASE		UL(0xF0000000)
-#define SPEAR6XX_CPU_GPIO_BASE		UL(0xF0100000)
-#define SPEAR6XX_CPU_VIC_SEC_BASE	UL(0xF1000000)
-#define VA_SPEAR6XX_CPU_VIC_SEC_BASE	IO_ADDRESS(SPEAR6XX_CPU_VIC_SEC_BASE)
-#define SPEAR6XX_CPU_VIC_PRI_BASE	UL(0xF1100000)
-#define VA_SPEAR6XX_CPU_VIC_PRI_BASE	IO_ADDRESS(SPEAR6XX_CPU_VIC_PRI_BASE)
 
 /* ICM3 - Basic Subsystem */
-#define SPEAR6XX_ICM3_BASE		UL(0xF8000000)
-#define SPEAR6XX_ICM3_SMEM_BASE		UL(0xF8000000)
 #define SPEAR6XX_ICM3_SMI_CTRL_BASE	UL(0xFC000000)
-#define SPEAR6XX_ICM3_CLCD_BASE		UL(0xFC200000)
+#define VA_SPEAR6XX_ICM3_SMI_CTRL_BASE	UL(0xFC000000)
 #define SPEAR6XX_ICM3_DMA_BASE		UL(0xFC400000)
-#define SPEAR6XX_ICM3_SDRAM_CTRL_BASE	UL(0xFC600000)
-#define SPEAR6XX_ICM3_TMR_BASE		UL(0xFC800000)
-#define SPEAR6XX_ICM3_WDT_BASE		UL(0xFC880000)
-#define SPEAR6XX_ICM3_RTC_BASE		UL(0xFC900000)
-#define SPEAR6XX_ICM3_GPIO_BASE		UL(0xFC980000)
 #define SPEAR6XX_ICM3_SYS_CTRL_BASE	UL(0xFCA00000)
-#define VA_SPEAR6XX_ICM3_SYS_CTRL_BASE	IO_ADDRESS(SPEAR6XX_ICM3_SYS_CTRL_BASE)
+#define VA_SPEAR6XX_ICM3_SYS_CTRL_BASE	(VA_SPEAR6XX_ICM3_SMI_CTRL_BASE | SPEAR6XX_ICM3_SYS_CTRL_BASE)
 #define SPEAR6XX_ICM3_MISC_REG_BASE	UL(0xFCA80000)
-#define VA_SPEAR6XX_ICM3_MISC_REG_BASE	IO_ADDRESS(SPEAR6XX_ICM3_MISC_REG_BASE)
-
-/* ICM4 - High Speed Connection */
-#define SPEAR6XX_ICM4_BASE		UL(0xE0000000)
-#define SPEAR6XX_ICM4_GMAC_BASE		UL(0xE0800000)
-#define SPEAR6XX_ICM4_USBD_FIFO_BASE	UL(0xE1000000)
-#define SPEAR6XX_ICM4_USBD_CSR_BASE	UL(0xE1100000)
-#define SPEAR6XX_ICM4_USBD_PLDT_BASE	UL(0xE1200000)
-#define SPEAR6XX_ICM4_USB_EHCI0_BASE	UL(0xE1800000)
-#define SPEAR6XX_ICM4_USB_OHCI0_BASE	UL(0xE1900000)
-#define SPEAR6XX_ICM4_USB_EHCI1_BASE	UL(0xE2000000)
-#define SPEAR6XX_ICM4_USB_OHCI1_BASE	UL(0xE2100000)
-#define SPEAR6XX_ICM4_USB_ARB_BASE	UL(0xE2800000)
+#define VA_SPEAR6XX_ICM3_MISC_REG_BASE	(VA_SPEAR6XX_ICM3_SMI_CTRL_BASE | SPEAR6XX_ICM3_MISC_REG_BASE)
 
 /* Debug uart for linux, will be used for debug and uncompress messages */
 #define SPEAR_DBG_UART_BASE		SPEAR6XX_ICM1_UART0_BASE
diff --git a/arch/arm/mach-spear6xx/include/mach/spear600.h b/arch/arm/mach-spear6xx/include/mach/spear600.h
deleted file mode 100644
index c068cc5..0000000
--- a/arch/arm/mach-spear6xx/include/mach/spear600.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-spear66xx/include/mach/spear600.h
- *
- * SPEAr600 Machine specific definition
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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.
- */
-
-#ifdef	CONFIG_MACH_SPEAR600
-
-#ifndef __MACH_SPEAR600_H
-#define __MACH_SPEAR600_H
-
-#endif /* __MACH_SPEAR600_H */
-
-#endif /* CONFIG_MACH_SPEAR600 */
diff --git a/arch/arm/mach-spear6xx/spear6xx.c b/arch/arm/mach-spear6xx/spear6xx.c
index 2ed8b14..de194db 100644
--- a/arch/arm/mach-spear6xx/spear6xx.c
+++ b/arch/arm/mach-spear6xx/spear6xx.c
@@ -13,41 +13,404 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/amba/pl08x.h>
+#include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <asm/hardware/pl080.h>
 #include <asm/hardware/vic.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <plat/pl080.h>
 #include <mach/generic.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
 
-/* Following will create static virtual/physical mappings */
-static struct map_desc spear6xx_io_desc[] __initdata = {
+/* dmac device registration */
+static struct pl08x_channel_data spear600_dma_info[] = {
 	{
-		.virtual	= VA_SPEAR6XX_ICM1_UART0_BASE,
-		.pfn		= __phys_to_pfn(SPEAR6XX_ICM1_UART0_BASE),
-		.length		= SZ_4K,
+		.bus_id = "ssp1_rx",
+		.min_signal = 0,
+		.max_signal = 0,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp1_tx",
+		.min_signal = 1,
+		.max_signal = 1,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart0_rx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart0_tx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart1_rx",
+		.min_signal = 4,
+		.max_signal = 4,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "uart1_tx",
+		.min_signal = 5,
+		.max_signal = 5,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp2_rx",
+		.min_signal = 6,
+		.max_signal = 6,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ssp2_tx",
+		.min_signal = 7,
+		.max_signal = 7,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ssp0_rx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ssp0_tx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "i2c_rx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "i2c_tx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "irda",
+		.min_signal = 12,
+		.max_signal = 12,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "adc",
+		.min_signal = 13,
+		.max_signal = 13,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "to_jpeg",
+		.min_signal = 14,
+		.max_signal = 14,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "from_jpeg",
+		.min_signal = 15,
+		.max_signal = 15,
+		.muxval = 0,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras0_rx",
+		.min_signal = 0,
+		.max_signal = 0,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras0_tx",
+		.min_signal = 1,
+		.max_signal = 1,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras1_rx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras1_tx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras2_rx",
+		.min_signal = 4,
+		.max_signal = 4,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras2_tx",
+		.min_signal = 5,
+		.max_signal = 5,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras3_rx",
+		.min_signal = 6,
+		.max_signal = 6,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras3_tx",
+		.min_signal = 7,
+		.max_signal = 7,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras4_rx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras4_tx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras5_rx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras5_tx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras6_rx",
+		.min_signal = 12,
+		.max_signal = 12,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras6_tx",
+		.min_signal = 13,
+		.max_signal = 13,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras7_rx",
+		.min_signal = 14,
+		.max_signal = 14,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ras7_tx",
+		.min_signal = 15,
+		.max_signal = 15,
+		.muxval = 1,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB1,
+	}, {
+		.bus_id = "ext0_rx",
+		.min_signal = 0,
+		.max_signal = 0,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext0_tx",
+		.min_signal = 1,
+		.max_signal = 1,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext1_rx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext1_tx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext2_rx",
+		.min_signal = 4,
+		.max_signal = 4,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext2_tx",
+		.min_signal = 5,
+		.max_signal = 5,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext3_rx",
+		.min_signal = 6,
+		.max_signal = 6,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext3_tx",
+		.min_signal = 7,
+		.max_signal = 7,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext4_rx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext4_tx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext5_rx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext5_tx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext6_rx",
+		.min_signal = 12,
+		.max_signal = 12,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext6_tx",
+		.min_signal = 13,
+		.max_signal = 13,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext7_rx",
+		.min_signal = 14,
+		.max_signal = 14,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ext7_tx",
+		.min_signal = 15,
+		.max_signal = 15,
+		.muxval = 2,
+		.cctl = 0,
+		.periph_buses = PL08X_AHB2,
+	},
+};
+
+struct pl08x_platform_data pl080_plat_data = {
+	.memcpy_channel = {
+		.bus_id = "memcpy",
+		.cctl = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT | \
+			PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT | \
+			PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | \
+			PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | \
+			PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE | \
+			PL080_CONTROL_PROT_SYS),
+	},
+	.lli_buses = PL08X_AHB1,
+	.mem_buses = PL08X_AHB1,
+	.get_signal = pl080_get_signal,
+	.put_signal = pl080_put_signal,
+	.slave_channels = spear600_dma_info,
+	.num_slave_channels = ARRAY_SIZE(spear600_dma_info),
+};
+
+/*
+ * Following will create 16MB static virtual/physical mappings
+ * PHYSICAL		VIRTUAL
+ * 0xF0000000		0xF0000000
+ * 0xF1000000		0xF1000000
+ * 0xD0000000		0xFD000000
+ * 0xFC000000		0xFC000000
+ */
+struct map_desc spear6xx_io_desc[] __initdata = {
+	{
+		.virtual	= VA_SPEAR6XX_ML_CPU_BASE,
+		.pfn		= __phys_to_pfn(SPEAR6XX_ML_CPU_BASE),
+		.length		= 2 * SZ_16M,
+		.type		= MT_DEVICE
+	},	{
+		.virtual	= VA_SPEAR6XX_ICM1_BASE,
+		.pfn		= __phys_to_pfn(SPEAR6XX_ICM1_BASE),
+		.length		= SZ_16M,
 		.type		= MT_DEVICE
 	}, {
-		.virtual	= VA_SPEAR6XX_CPU_VIC_PRI_BASE,
-		.pfn		= __phys_to_pfn(SPEAR6XX_CPU_VIC_PRI_BASE),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= VA_SPEAR6XX_CPU_VIC_SEC_BASE,
-		.pfn		= __phys_to_pfn(SPEAR6XX_CPU_VIC_SEC_BASE),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= VA_SPEAR6XX_ICM3_SYS_CTRL_BASE,
-		.pfn		= __phys_to_pfn(SPEAR6XX_ICM3_SYS_CTRL_BASE),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= VA_SPEAR6XX_ICM3_MISC_REG_BASE,
-		.pfn		= __phys_to_pfn(SPEAR6XX_ICM3_MISC_REG_BASE),
-		.length		= SZ_4K,
+		.virtual	= VA_SPEAR6XX_ICM3_SMI_CTRL_BASE,
+		.pfn		= __phys_to_pfn(SPEAR6XX_ICM3_SMI_CTRL_BASE),
+		.length		= SZ_16M,
 		.type		= MT_DEVICE
 	},
 };
@@ -85,16 +448,24 @@
 	clk_put(gpt_clk);
 	clk_put(pclk);
 
-	spear_setup_timer();
+	spear_setup_timer(SPEAR6XX_CPU_TMR_BASE, IRQ_CPU_GPT1_1);
 }
 
 struct sys_timer spear6xx_timer = {
 	.init = spear6xx_timer_init,
 };
 
+/* Add auxdata to pass platform data */
+struct of_dev_auxdata spear6xx_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("arm,pl080", SPEAR6XX_ICM3_DMA_BASE, NULL,
+			&pl080_plat_data),
+	{}
+};
+
 static void __init spear600_dt_init(void)
 {
-	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+	of_platform_populate(NULL, of_default_bus_match_table,
+			spear6xx_auxdata_lookup, NULL);
 }
 
 static const char *spear600_dt_board_compat[] = {
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index d87d968..2eb4445 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -5,7 +5,6 @@
 obj-y                                   += irq.o
 obj-y                                   += clock.o
 obj-y                                   += timer.o
-obj-y                                   += pinmux.o
 obj-y					+= fuse.o
 obj-y					+= pmc.o
 obj-y					+= flowctrl.o
@@ -14,8 +13,6 @@
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= powergate.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_clocks.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pinmux-tegra20-tables.o
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= pinmux-tegra30-tables.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= board-dt-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.o
 obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index 0952494..fac3eb1 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -37,7 +37,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/setup.h>
-#include <asm/hardware/gic.h>
 
 #include <mach/iomap.h>
 #include <mach/irqs.h>
@@ -47,15 +46,7 @@
 #include "clock.h"
 #include "devices.h"
 
-void harmony_pinmux_init(void);
-void paz00_pinmux_init(void);
-void seaboard_pinmux_init(void);
-void trimslice_pinmux_init(void);
-void ventana_pinmux_init(void);
-
 struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
-	OF_DEV_AUXDATA("nvidia,tegra20-pinmux", TEGRA_APB_MISC_BASE + 0x14, "tegra-pinmux", NULL),
-	OF_DEV_AUXDATA("nvidia,tegra20-gpio", TEGRA_GPIO_BASE, "tegra-gpio", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL),
@@ -64,9 +55,9 @@
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c-dvc", TEGRA_DVC_BASE, "tegra-i2c.3", NULL),
-	OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
-	OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL),
-	OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra20-i2s.0", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra20-i2s.1", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra20-das", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
 		       &tegra_ehci1_pdata),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
@@ -95,33 +86,10 @@
 	{}
 };
 
-static struct {
-	char *machine;
-	void (*init)(void);
-} pinmux_configs[] = {
-	{ "compulab,trimslice", trimslice_pinmux_init },
-	{ "nvidia,harmony", harmony_pinmux_init },
-	{ "compal,paz00", paz00_pinmux_init },
-	{ "nvidia,seaboard", seaboard_pinmux_init },
-	{ "nvidia,ventana", ventana_pinmux_init },
-};
-
 static void __init tegra_dt_init(void)
 {
-	int i;
-
 	tegra_clk_init_from_table(tegra_dt_clk_init_table);
 
-	for (i = 0; i < ARRAY_SIZE(pinmux_configs); i++) {
-		if (of_machine_is_compatible(pinmux_configs[i].machine)) {
-			pinmux_configs[i].init();
-			break;
-		}
-	}
-
-	WARN(i == ARRAY_SIZE(pinmux_configs),
-		"Unknown platform! Pinmuxing not initialized\n");
-
 	/*
 	 * Finished with the static registrations now; fill in the missing
 	 * devices
diff --git a/arch/arm/mach-tegra/board-harmony-pinmux.c b/arch/arm/mach-tegra/board-harmony-pinmux.c
index 1af85bccc..83d420f 100644
--- a/arch/arm/mach-tegra/board-harmony-pinmux.c
+++ b/arch/arm/mach-tegra/board-harmony-pinmux.c
@@ -2,6 +2,7 @@
  * arch/arm/mach-tegra/board-harmony-pinmux.c
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -15,153 +16,138 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
 
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-
-#include "gpio-names.h"
 #include "board-harmony.h"
 #include "board-pinmux.h"
 
-static struct tegra_pingroup_config harmony_pinmux[] = {
-	{TEGRA_PINGROUP_ATA,   TEGRA_MUX_IDE,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATB,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATC,   TEGRA_MUX_NAND,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATE,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4,     TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CRTP,  TEGRA_MUX_CRT,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CSUS,  TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP1,  TEGRA_MUX_DAP1,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DAP2,  TEGRA_MUX_DAP2,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP3,  TEGRA_MUX_DAP3,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP4,  TEGRA_MUX_DAP4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DDC,   TEGRA_MUX_I2C2,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTA,   TEGRA_MUX_SDIO2,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTB,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTC,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTD,   TEGRA_MUX_SDIO2,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTE,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTF,   TEGRA_MUX_I2C3,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_GMA,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMB,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMC,   TEGRA_MUX_UARTD,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GME,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPU,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_GPU7,  TEGRA_MUX_RTCK,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_I2CP,  TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_IRRX,  TEGRA_MUX_UARTA,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_IRTX,  TEGRA_MUX_UARTA,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_KBCA,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCB,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCC,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCD,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCE,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCF,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LCSN,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LD0,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD1,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD10,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD11,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD12,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD13,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD14,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD15,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD16,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD17,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD2,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD3,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD4,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD5,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD6,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD7,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD8,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD9,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LDC,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LDI,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP2,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LM0,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LM1,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPP,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LPW0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LPW1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPW2,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LSC0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LSC1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSCK,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSDA,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSDI,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSPI,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LVP0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LVP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LVS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_OWC,   TEGRA_MUX_RSVD2,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_PMC,   TEGRA_MUX_PWR_ON,        TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PTA,   TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_RM,    TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDB,   TEGRA_MUX_PWM,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SDC,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDD,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SLXC,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXD,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPDI,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPDO,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIA,  TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPIB,  TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPIC,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPID,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIE,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIF,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIG,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIH,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UAA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UAB,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UAC,   TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UAD,   TEGRA_MUX_IRDA,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UCA,   TEGRA_MUX_UARTC,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UCB,   TEGRA_MUX_UARTC,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UDA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CK32,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DDRC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCA,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCB,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCD,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCE,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_XM2C,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_XM2D,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-};
-
-static struct tegra_gpio_table gpio_table[] = {
-	{ .gpio = TEGRA_GPIO_SD2_CD,		.enable = true	},
-	{ .gpio = TEGRA_GPIO_SD2_WP,		.enable = true	},
-	{ .gpio = TEGRA_GPIO_SD2_POWER,		.enable = true	},
-	{ .gpio = TEGRA_GPIO_SD4_CD,		.enable = true	},
-	{ .gpio = TEGRA_GPIO_SD4_WP,		.enable = true	},
-	{ .gpio = TEGRA_GPIO_SD4_POWER,		.enable = true	},
-	{ .gpio = TEGRA_GPIO_CDC_IRQ,		.enable = true	},
-	{ .gpio = TEGRA_GPIO_HP_DET,		.enable = true	},
-	{ .gpio = TEGRA_GPIO_INT_MIC_EN,	.enable = true	},
-	{ .gpio = TEGRA_GPIO_EXT_MIC_EN,	.enable = true	},
+static struct pinctrl_map harmony_map[] = {
+	TEGRA_MAP_MUXCONF("ata",   "ide",           none, driven),
+	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("atc",   "nand",          none, driven),
+	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
+	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     down, tristate),
+	TEGRA_MAP_MUXCONF("crtp",  "crt",           none, tristate),
+	TEGRA_MAP_MUXCONF("csus",  "vi_sensor_clk", down, tristate),
+	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
+	TEGRA_MAP_MUXCONF("dap2",  "dap2",          none, tristate),
+	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
+	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, tristate),
+	TEGRA_MAP_MUXCONF("ddc",   "i2c2",          up,   driven),
+	TEGRA_MAP_MUXCONF("dta",   "sdio2",         up,   driven),
+	TEGRA_MAP_MUXCONF("dtb",   "rsvd1",         none, driven),
+	TEGRA_MAP_MUXCONF("dtc",   "rsvd1",         none, tristate),
+	TEGRA_MAP_MUXCONF("dtd",   "sdio2",         up,   driven),
+	TEGRA_MAP_MUXCONF("dte",   "rsvd1",         none, tristate),
+	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          none, tristate),
+	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("gmb",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("gmc",   "uartd",         none, driven),
+	TEGRA_MAP_MUXCONF("gmd",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("gme",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("gpu",   "gmi",           none, tristate),
+	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
+	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, driven),
+	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   tristate),
+	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, driven),
+	TEGRA_MAP_MUXCONF("irrx",  "uarta",         up,   tristate),
+	TEGRA_MAP_MUXCONF("irtx",  "uarta",         up,   tristate),
+	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcb",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcd",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("lcsn",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ldc",   "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lm0",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lm1",   "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lpw1",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsdi",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lvp0",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("owc",   "rsvd2",         na,   tristate),
+	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   driven),
+	TEGRA_MAP_MUXCONF("pta",   "hdmi",          none, driven),
+	TEGRA_MAP_MUXCONF("rm",    "i2c1",          none, driven),
+	TEGRA_MAP_MUXCONF("sdb",   "pwm",           na,   tristate),
+	TEGRA_MAP_MUXCONF("sdc",   "pwm",           up,   driven),
+	TEGRA_MAP_MUXCONF("sdd",   "pwm",           up,   tristate),
+	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         none, tristate),
+	TEGRA_MAP_MUXCONF("slxa",  "pcie",          none, driven),
+	TEGRA_MAP_MUXCONF("slxc",  "spdif",         none, tristate),
+	TEGRA_MAP_MUXCONF("slxd",  "spdif",         none, tristate),
+	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
+	TEGRA_MAP_MUXCONF("spdi",  "rsvd2",         none, tristate),
+	TEGRA_MAP_MUXCONF("spdo",  "rsvd2",         none, tristate),
+	TEGRA_MAP_MUXCONF("spia",  "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("spib",  "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("spic",  "gmi",           up,   tristate),
+	TEGRA_MAP_MUXCONF("spid",  "spi1",          down, tristate),
+	TEGRA_MAP_MUXCONF("spie",  "spi1",          up,   tristate),
+	TEGRA_MAP_MUXCONF("spif",  "spi1",          down, tristate),
+	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      none, tristate),
+	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
+	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   tristate),
+	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   tristate),
+	TEGRA_MAP_MUXCONF("uac",   "rsvd2",         none, tristate),
+	TEGRA_MAP_MUXCONF("uad",   "irda",          up,   tristate),
+	TEGRA_MAP_MUXCONF("uca",   "uartc",         up,   tristate),
+	TEGRA_MAP_MUXCONF("ucb",   "uartc",         up,   tristate),
+	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, tristate),
+	TEGRA_MAP_CONF("ck32",    none, na),
+	TEGRA_MAP_CONF("ddrc",    none, na),
+	TEGRA_MAP_CONF("pmca",    none, na),
+	TEGRA_MAP_CONF("pmcb",    none, na),
+	TEGRA_MAP_CONF("pmcc",    none, na),
+	TEGRA_MAP_CONF("pmcd",    none, na),
+	TEGRA_MAP_CONF("pmce",    none, na),
+	TEGRA_MAP_CONF("xm2c",    none, na),
+	TEGRA_MAP_CONF("xm2d",    none, na),
+	TEGRA_MAP_CONF("ls",      up,   na),
+	TEGRA_MAP_CONF("lc",      up,   na),
+	TEGRA_MAP_CONF("ld17_0",  down, na),
+	TEGRA_MAP_CONF("ld19_18", down, na),
+	TEGRA_MAP_CONF("ld21_20", down, na),
+	TEGRA_MAP_CONF("ld23_22", down, na),
 };
 
 static struct tegra_board_pinmux_conf conf = {
-	.pgs = harmony_pinmux,
-	.pg_count = ARRAY_SIZE(harmony_pinmux),
-	.gpios = gpio_table,
-	.gpio_count = ARRAY_SIZE(gpio_table),
+	.maps = harmony_map,
+	.map_count = ARRAY_SIZE(harmony_map),
 };
 
 void harmony_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index c00aadb..b906b3b 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/pda_power.h>
@@ -52,6 +53,7 @@
 		.irq		= INT_UARTD,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= 216000000,
@@ -122,7 +124,6 @@
 	&tegra_ehci3_device,
 	&tegra_i2s_device1,
 	&tegra_das_device,
-	&tegra_pcm_device,
 	&harmony_audio_device,
 };
 
diff --git a/arch/arm/mach-tegra/board-paz00-pinmux.c b/arch/arm/mach-tegra/board-paz00-pinmux.c
index c775572..6f1111b 100644
--- a/arch/arm/mach-tegra/board-paz00-pinmux.c
+++ b/arch/arm/mach-tegra/board-paz00-pinmux.c
@@ -2,6 +2,7 @@
  * arch/arm/mach-tegra/board-paz00-pinmux.c
  *
  * Copyright (C) 2010 Marc Dietrich <marvin24@gmx.de>
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -15,150 +16,138 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
 
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-
-#include "gpio-names.h"
 #include "board-paz00.h"
 #include "board-pinmux.h"
 
-static struct tegra_pingroup_config paz00_pinmux[] = {
-	{TEGRA_PINGROUP_ATA,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATB,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATC,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATE,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4,     TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CRTP,  TEGRA_MUX_CRT,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CSUS,  TEGRA_MUX_PLLC_OUT1,     TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP1,  TEGRA_MUX_DAP1,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DAP2,  TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DAP3,  TEGRA_MUX_DAP3,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP4,  TEGRA_MUX_DAP4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DDC,   TEGRA_MUX_I2C2,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTA,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTB,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTC,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTD,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTE,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTF,   TEGRA_MUX_I2C3,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMA,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMB,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMC,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GME,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPU,   TEGRA_MUX_PWM,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPU7,  TEGRA_MUX_RTCK,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_I2CP,  TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_IRRX,  TEGRA_MUX_UARTA,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_IRTX,  TEGRA_MUX_UARTA,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCA,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCB,  TEGRA_MUX_SDIO2,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCC,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCD,  TEGRA_MUX_SDIO2,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCE,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCF,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LCSN,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LD0,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD1,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD10,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD11,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD12,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD13,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD14,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD15,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD16,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD17,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD2,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD3,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD4,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD5,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD6,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD7,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD8,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD9,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LDC,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LDI,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LHP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LHP2,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LHS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LM0,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LM1,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPP,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPW0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPW1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPW2,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSC0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LSC1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSCK,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSDA,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSDI,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSPI,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LVP0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LVP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LVS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_OWC,   TEGRA_MUX_OWR,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_PMC,   TEGRA_MUX_PWR_ON,        TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PTA,   TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_RM,    TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDB,   TEGRA_MUX_PWM,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SDC,   TEGRA_MUX_TWC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SDD,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXC,  TEGRA_MUX_SPI4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXD,  TEGRA_MUX_SPI4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPDI,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPDO,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPIA,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIB,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIC,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPID,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIE,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIF,  TEGRA_MUX_RSVD4,         TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIG,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPIH,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UAA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UAB,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UAC,   TEGRA_MUX_RSVD4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UAD,   TEGRA_MUX_SPDIF,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UCA,   TEGRA_MUX_UARTC,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UCB,   TEGRA_MUX_UARTC,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UDA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CK32,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DDRC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCA,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCB,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCD,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCE,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_XM2C,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_XM2D,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-};
-
-static struct tegra_gpio_table gpio_table[] = {
-	{ .gpio = TEGRA_GPIO_SD1_CD,	.enable = true },
-	{ .gpio = TEGRA_GPIO_SD1_WP,	.enable = true },
-	{ .gpio = TEGRA_GPIO_SD1_POWER,	.enable = true },
-	{ .gpio = TEGRA_ULPI_RST,	.enable = true },
-	{ .gpio = TEGRA_WIFI_PWRN,	.enable = true },
-	{ .gpio = TEGRA_WIFI_RST,	.enable = true },
-	{ .gpio = TEGRA_WIFI_LED,	.enable = true },
+static struct pinctrl_map paz00_map[] = {
+	TEGRA_MAP_MUXCONF("ata",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("atc",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
+	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     down, driven),
+	TEGRA_MAP_MUXCONF("crtp",  "crt",           none, tristate),
+	TEGRA_MAP_MUXCONF("csus",  "pllc_out1",     down, tristate),
+	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
+	TEGRA_MAP_MUXCONF("dap2",  "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
+	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, tristate),
+	TEGRA_MAP_MUXCONF("ddc",   "i2c2",          up,   driven),
+	TEGRA_MAP_MUXCONF("dta",   "rsvd1",         up,   tristate),
+	TEGRA_MAP_MUXCONF("dtb",   "rsvd1",         none, tristate),
+	TEGRA_MAP_MUXCONF("dtc",   "rsvd1",         none, tristate),
+	TEGRA_MAP_MUXCONF("dtd",   "rsvd1",         up,   tristate),
+	TEGRA_MAP_MUXCONF("dte",   "rsvd1",         none, tristate),
+	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          none, driven),
+	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("gmb",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("gmc",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("gmd",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("gme",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("gpu",   "pwm",           none, driven),
+	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
+	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, driven),
+	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   driven),
+	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, driven),
+	TEGRA_MAP_MUXCONF("irrx",  "uarta",         up,   driven),
+	TEGRA_MAP_MUXCONF("irtx",  "uarta",         up,   driven),
+	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcb",  "sdio2",         up,   driven),
+	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcd",  "sdio2",         up,   driven),
+	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("lcsn",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ldc",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lm0",   "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lm1",   "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lpw1",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsdi",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lvp0",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("owc",   "owr",           up,   tristate),
+	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   driven),
+	TEGRA_MAP_MUXCONF("pta",   "hdmi",          none, driven),
+	TEGRA_MAP_MUXCONF("rm",    "i2c1",          none, driven),
+	TEGRA_MAP_MUXCONF("sdb",   "pwm",           na,   tristate),
+	TEGRA_MAP_MUXCONF("sdc",   "twc",           up,   tristate),
+	TEGRA_MAP_MUXCONF("sdd",   "pwm",           up,   tristate),
+	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         none, driven),
+	TEGRA_MAP_MUXCONF("slxa",  "pcie",          none, tristate),
+	TEGRA_MAP_MUXCONF("slxc",  "spi4",          none, tristate),
+	TEGRA_MAP_MUXCONF("slxd",  "spi4",          none, tristate),
+	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
+	TEGRA_MAP_MUXCONF("spdi",  "rsvd2",         none, tristate),
+	TEGRA_MAP_MUXCONF("spdo",  "rsvd2",         none, driven),
+	TEGRA_MAP_MUXCONF("spia",  "gmi",           down, tristate),
+	TEGRA_MAP_MUXCONF("spib",  "gmi",           down, tristate),
+	TEGRA_MAP_MUXCONF("spic",  "gmi",           up,   driven),
+	TEGRA_MAP_MUXCONF("spid",  "gmi",           down, tristate),
+	TEGRA_MAP_MUXCONF("spie",  "gmi",           up,   tristate),
+	TEGRA_MAP_MUXCONF("spif",  "rsvd4",         down, tristate),
+	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      up,   driven),
+	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
+	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   driven),
+	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   driven),
+	TEGRA_MAP_MUXCONF("uac",   "rsvd4",         none, driven),
+	TEGRA_MAP_MUXCONF("uad",   "spdif",         up,   tristate),
+	TEGRA_MAP_MUXCONF("uca",   "uartc",         up,   tristate),
+	TEGRA_MAP_MUXCONF("ucb",   "uartc",         up,   tristate),
+	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, driven),
+	TEGRA_MAP_CONF("ck32",    none, na),
+	TEGRA_MAP_CONF("ddrc",    none, na),
+	TEGRA_MAP_CONF("pmca",    none, na),
+	TEGRA_MAP_CONF("pmcb",    none, na),
+	TEGRA_MAP_CONF("pmcc",    none, na),
+	TEGRA_MAP_CONF("pmcd",    none, na),
+	TEGRA_MAP_CONF("pmce",    none, na),
+	TEGRA_MAP_CONF("xm2c",    none, na),
+	TEGRA_MAP_CONF("xm2d",    none, na),
+	TEGRA_MAP_CONF("ls",      up,   na),
+	TEGRA_MAP_CONF("lc",      up,   na),
+	TEGRA_MAP_CONF("ld17_0",  down, na),
+	TEGRA_MAP_CONF("ld19_18", down, na),
+	TEGRA_MAP_CONF("ld21_20", down, na),
+	TEGRA_MAP_CONF("ld23_22", down, na),
 };
 
 static struct tegra_board_pinmux_conf conf = {
-	.pgs = paz00_pinmux,
-	.pg_count = ARRAY_SIZE(paz00_pinmux),
-	.gpios = gpio_table,
-	.gpio_count = ARRAY_SIZE(gpio_table),
+	.maps = paz00_map,
+	.map_count = ARRAY_SIZE(paz00_map),
 };
 
 void paz00_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
index 330afdf..d0735c7 100644
--- a/arch/arm/mach-tegra/board-paz00.c
+++ b/arch/arm/mach-tegra/board-paz00.c
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio_keys.h>
@@ -55,6 +56,7 @@
 		.irq		= INT_UARTA,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= 216000000,
@@ -65,6 +67,7 @@
 		.irq		= INT_UARTC,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= 216000000,
diff --git a/arch/arm/mach-tegra/board-pinmux.c b/arch/arm/mach-tegra/board-pinmux.c
index adc3efe..a5574c7 100644
--- a/arch/arm/mach-tegra/board-pinmux.c
+++ b/arch/arm/mach-tegra/board-pinmux.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -15,75 +15,59 @@
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/notifier.h>
-#include <linux/of.h>
 #include <linux/string.h>
 
-#include <mach/gpio-tegra.h>
-#include <mach/pinmux.h>
-
 #include "board-pinmux.h"
 #include "devices.h"
 
-struct tegra_board_pinmux_conf *confs[2];
+unsigned long tegra_pincfg_pullnone_driven[2] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_NONE),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_DRIVEN),
+};
 
-static void tegra_board_pinmux_setup_gpios(void)
-{
-	int i;
+unsigned long tegra_pincfg_pullnone_tristate[2] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_NONE),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_TRISTATE),
+};
 
-	for (i = 0; i < ARRAY_SIZE(confs); i++) {
-		if (!confs[i])
-			continue;
+unsigned long tegra_pincfg_pullnone_na[1] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_NONE),
+};
 
-		tegra_gpio_config(confs[i]->gpios, confs[i]->gpio_count);
-	}
-}
+unsigned long tegra_pincfg_pullup_driven[2] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_UP),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_DRIVEN),
+};
 
-static void tegra_board_pinmux_setup_pinmux(void)
-{
-	int i;
+unsigned long tegra_pincfg_pullup_tristate[2] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_UP),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_TRISTATE),
+};
 
-	for (i = 0; i < ARRAY_SIZE(confs); i++) {
-		if (!confs[i])
-			continue;
+unsigned long tegra_pincfg_pullup_na[1] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_UP),
+};
 
-		tegra_pinmux_config_table(confs[i]->pgs, confs[i]->pg_count);
+unsigned long tegra_pincfg_pulldown_driven[2] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_DOWN),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_DRIVEN),
+};
 
-		if (confs[i]->drives)
-			tegra_drive_pinmux_config_table(confs[i]->drives,
-							confs[i]->drive_count);
-	}
-}
+unsigned long tegra_pincfg_pulldown_tristate[2] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_DOWN),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_TRISTATE),
+};
 
-static int tegra_board_pinmux_bus_notify(struct notifier_block *nb,
-					 unsigned long event, void *vdev)
-{
-	static bool had_gpio;
-	static bool had_pinmux;
+unsigned long tegra_pincfg_pulldown_na[1] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_DOWN),
+};
 
-	struct device *dev = vdev;
-	const char *devname;
+unsigned long tegra_pincfg_pullna_driven[1] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_DRIVEN),
+};
 
-	if (event != BUS_NOTIFY_BOUND_DRIVER)
-		return NOTIFY_DONE;
-
-	devname = dev_name(dev);
-
-	if (!had_gpio && !strcmp(devname, GPIO_DEV)) {
-		tegra_board_pinmux_setup_gpios();
-		had_gpio = true;
-	} else if (!had_pinmux && !strcmp(devname, PINMUX_DEV)) {
-		tegra_board_pinmux_setup_pinmux();
-		had_pinmux = true;
-	}
-
-	if (had_gpio && had_pinmux)
-		return NOTIFY_STOP_MASK;
-	else
-		return NOTIFY_DONE;
-}
-
-static struct notifier_block nb = {
-	.notifier_call = tegra_board_pinmux_bus_notify,
+unsigned long tegra_pincfg_pullna_tristate[1] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_TRISTATE),
 };
 
 static struct platform_device *devices[] = {
@@ -94,11 +78,10 @@
 void tegra_board_pinmux_init(struct tegra_board_pinmux_conf *conf_a,
 			     struct tegra_board_pinmux_conf *conf_b)
 {
-	confs[0] = conf_a;
-	confs[1] = conf_b;
+	if (conf_a)
+		pinctrl_register_mappings(conf_a->maps, conf_a->map_count);
+	if (conf_b)
+		pinctrl_register_mappings(conf_b->maps, conf_b->map_count);
 
-	bus_register_notifier(&platform_bus_type, &nb);
-
-	if (!of_machine_is_compatible("nvidia,tegra20"))
-		platform_add_devices(devices, ARRAY_SIZE(devices));
+	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
diff --git a/arch/arm/mach-tegra/board-pinmux.h b/arch/arm/mach-tegra/board-pinmux.h
index 4aac735..c5f3f33 100644
--- a/arch/arm/mach-tegra/board-pinmux.h
+++ b/arch/arm/mach-tegra/board-pinmux.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -15,21 +15,37 @@
 #ifndef __MACH_TEGRA_BOARD_PINMUX_H
 #define __MACH_TEGRA_BOARD_PINMUX_H
 
-#define GPIO_DEV "tegra-gpio"
-#define PINMUX_DEV "tegra-pinmux"
+#include <linux/pinctrl/machine.h>
 
-struct tegra_pingroup_config;
-struct tegra_gpio_table;
+#include <mach/pinconf-tegra.h>
+
+#define PINMUX_DEV "tegra20-pinctrl"
+
+#define TEGRA_MAP_MUX(_group_, _function_) \
+	PIN_MAP_MUX_GROUP_HOG_DEFAULT(PINMUX_DEV, _group_, _function_)
+
+#define TEGRA_MAP_CONF(_group_, _pull_, _drive_) \
+	PIN_MAP_CONFIGS_GROUP_HOG_DEFAULT(PINMUX_DEV, _group_, tegra_pincfg_pull##_pull_##_##_drive_)
+
+#define TEGRA_MAP_MUXCONF(_group_, _function_, _pull_, _drive_) \
+	TEGRA_MAP_MUX(_group_, _function_), \
+	TEGRA_MAP_CONF(_group_, _pull_, _drive_)
+
+extern unsigned long tegra_pincfg_pullnone_driven[2];
+extern unsigned long tegra_pincfg_pullnone_tristate[2];
+extern unsigned long tegra_pincfg_pullnone_na[1];
+extern unsigned long tegra_pincfg_pullup_driven[2];
+extern unsigned long tegra_pincfg_pullup_tristate[2];
+extern unsigned long tegra_pincfg_pullup_na[1];
+extern unsigned long tegra_pincfg_pulldown_driven[2];
+extern unsigned long tegra_pincfg_pulldown_tristate[2];
+extern unsigned long tegra_pincfg_pulldown_na[1];
+extern unsigned long tegra_pincfg_pullna_driven[1];
+extern unsigned long tegra_pincfg_pullna_tristate[1];
 
 struct tegra_board_pinmux_conf {
-	struct tegra_pingroup_config *pgs;
-	int pg_count;
-
-	struct tegra_drive_pingroup_config *drives;
-	int drive_count;
-
-	struct tegra_gpio_table *gpios;
-	int gpio_count;
+	struct pinctrl_map *maps;
+	int map_count;
 };
 
 void tegra_board_pinmux_init(struct tegra_board_pinmux_conf *conf_a,
diff --git a/arch/arm/mach-tegra/board-seaboard-pinmux.c b/arch/arm/mach-tegra/board-seaboard-pinmux.c
index 55e7e43..11fc8a5 100644
--- a/arch/arm/mach-tegra/board-seaboard-pinmux.c
+++ b/arch/arm/mach-tegra/board-seaboard-pinmux.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010,2011 NVIDIA Corporation
+ * Copyright (C) 2010-2012 NVIDIA Corporation
  * Copyright (C) 2011 Google, Inc.
  *
  * This software is licensed under the terms of the GNU General Public
@@ -14,216 +14,176 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
 
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-
-#include "gpio-names.h"
-#include "board-pinmux.h"
 #include "board-seaboard.h"
+#include "board-pinmux.h"
 
-#define DEFAULT_DRIVE(_name)					\
-	{							\
-		.pingroup = TEGRA_DRIVE_PINGROUP_##_name,	\
-		.hsm = TEGRA_HSM_DISABLE,			\
-		.schmitt = TEGRA_SCHMITT_ENABLE,		\
-		.drive = TEGRA_DRIVE_DIV_1,			\
-		.pull_down = TEGRA_PULL_31,			\
-		.pull_up = TEGRA_PULL_31,			\
-		.slew_rising = TEGRA_SLEW_SLOWEST,		\
-		.slew_falling = TEGRA_SLEW_SLOWEST,		\
-	}
-
-static struct tegra_drive_pingroup_config seaboard_drive_pinmux[] = {
-	DEFAULT_DRIVE(SDIO1),
+static unsigned long seaboard_pincfg_drive_sdio1[] = {
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE, 0),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_SCHMITT, 0),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_LOW_POWER_MODE, 3),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH, 31),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH, 31),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING, 3),
+	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_SLEW_RATE_RISING, 3),
 };
 
-static struct tegra_pingroup_config common_pinmux[] = {
-	{TEGRA_PINGROUP_ATA,   TEGRA_MUX_IDE,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATB,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATC,   TEGRA_MUX_NAND,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATE,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4,     TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CRTP,  TEGRA_MUX_CRT,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CSUS,  TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP1,  TEGRA_MUX_DAP1,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DAP2,  TEGRA_MUX_DAP2,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DAP3,  TEGRA_MUX_DAP3,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP4,  TEGRA_MUX_DAP4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTA,   TEGRA_MUX_VI,            TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTB,   TEGRA_MUX_VI,            TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTC,   TEGRA_MUX_VI,            TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTD,   TEGRA_MUX_VI,            TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTE,   TEGRA_MUX_VI,            TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTF,   TEGRA_MUX_I2C3,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMA,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMB,   TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_GMC,   TEGRA_MUX_UARTD,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GME,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPU,   TEGRA_MUX_PWM,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPU7,  TEGRA_MUX_RTCK,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_I2CP,  TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_IRRX,  TEGRA_MUX_UARTB,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_IRTX,  TEGRA_MUX_UARTB,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCA,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCB,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCC,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCD,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCE,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_KBCF,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LCSN,  TEGRA_MUX_RSVD4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LD0,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD1,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD10,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD11,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD12,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD13,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD14,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD15,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD16,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD17,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD2,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD3,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD4,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD5,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD6,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD7,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD8,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD9,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LDC,   TEGRA_MUX_RSVD4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LDI,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP2,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LM0,   TEGRA_MUX_RSVD4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LM1,   TEGRA_MUX_CRT,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPP,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LPW1,  TEGRA_MUX_RSVD4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSC0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LSDI,  TEGRA_MUX_RSVD4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSPI,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LVP0,  TEGRA_MUX_RSVD4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LVP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LVS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_OWC,   TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_PMC,   TEGRA_MUX_PWR_ON,        TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_RM,    TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDB,   TEGRA_MUX_SDIO3,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDC,   TEGRA_MUX_SDIO3,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDD,   TEGRA_MUX_SDIO3,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXD,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPDI,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPDO,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPIB,  TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPID,  TEGRA_MUX_SPI1,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIE,  TEGRA_MUX_SPI1,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIF,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIH,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UAA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UAB,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UAC,   TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UAD,   TEGRA_MUX_IRDA,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UCA,   TEGRA_MUX_UARTC,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UCB,   TEGRA_MUX_UARTC,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UDA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CK32,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DDRC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCA,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCB,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCD,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCE,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_XM2C,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_XM2D,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+static struct pinctrl_map common_map[] = {
+	TEGRA_MAP_MUXCONF("ata",   "ide",           none, driven),
+	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("atc",   "nand",          none, driven),
+	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, driven),
+	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, tristate),
+	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
+	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     none, driven),
+	TEGRA_MAP_MUXCONF("crtp",  "crt",           up,   tristate),
+	TEGRA_MAP_MUXCONF("csus",  "vi_sensor_clk", none, tristate),
+	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
+	TEGRA_MAP_MUXCONF("dap2",  "dap2",          none, driven),
+	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
+	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, driven),
+	TEGRA_MAP_MUXCONF("dta",   "vi",            down, driven),
+	TEGRA_MAP_MUXCONF("dtb",   "vi",            down, driven),
+	TEGRA_MAP_MUXCONF("dtc",   "vi",            down, driven),
+	TEGRA_MAP_MUXCONF("dtd",   "vi",            down, driven),
+	TEGRA_MAP_MUXCONF("dte",   "vi",            down, tristate),
+	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          none, driven),
+	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("gmb",   "gmi",           up,   tristate),
+	TEGRA_MAP_MUXCONF("gmc",   "uartd",         none, driven),
+	TEGRA_MAP_MUXCONF("gme",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("gpu",   "pwm",           none, driven),
+	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
+	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, tristate),
+	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   tristate),
+	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, driven),
+	TEGRA_MAP_MUXCONF("irrx",  "uartb",         none, driven),
+	TEGRA_MAP_MUXCONF("irtx",  "uartb",         none, driven),
+	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcb",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcd",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   driven),
+	TEGRA_MAP_MUXCONF("lcsn",  "rsvd4",         na,   tristate),
+	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ldc",   "rsvd4",         na,   tristate),
+	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lm0",   "rsvd4",         na,   driven),
+	TEGRA_MAP_MUXCONF("lm1",   "crt",           na,   tristate),
+	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lpw1",  "rsvd4",         na,   tristate),
+	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lsdi",  "rsvd4",         na,   tristate),
+	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lvp0",  "rsvd4",         na,   tristate),
+	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("owc",   "rsvd2",         none, tristate),
+	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   driven),
+	TEGRA_MAP_MUXCONF("pta",   "hdmi",          none, driven),
+	TEGRA_MAP_MUXCONF("rm",    "i2c1",          none, driven),
+	TEGRA_MAP_MUXCONF("sdb",   "sdio3",         na,   driven),
+	TEGRA_MAP_MUXCONF("sdc",   "sdio3",         none, driven),
+	TEGRA_MAP_MUXCONF("sdd",   "sdio3",         none, driven),
+	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         up,   driven),
+	TEGRA_MAP_MUXCONF("slxa",  "pcie",          up,   tristate),
+	TEGRA_MAP_MUXCONF("slxd",  "spdif",         none, driven),
+	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
+	TEGRA_MAP_MUXCONF("spdi",  "rsvd2",         none, driven),
+	TEGRA_MAP_MUXCONF("spdo",  "rsvd2",         none, driven),
+	TEGRA_MAP_MUXCONF("spib",  "gmi",           none, tristate),
+	TEGRA_MAP_MUXCONF("spid",  "spi1",          none, tristate),
+	TEGRA_MAP_MUXCONF("spie",  "spi1",          none, tristate),
+	TEGRA_MAP_MUXCONF("spif",  "spi1",          down, tristate),
+	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
+	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   driven),
+	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   driven),
+	TEGRA_MAP_MUXCONF("uac",   "rsvd2",         none, driven),
+	TEGRA_MAP_MUXCONF("uad",   "irda",          none, driven),
+	TEGRA_MAP_MUXCONF("uca",   "uartc",         none, driven),
+	TEGRA_MAP_MUXCONF("ucb",   "uartc",         none, driven),
+	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, driven),
+	TEGRA_MAP_CONF("ck32",    none, na),
+	TEGRA_MAP_CONF("ddrc",    none, na),
+	TEGRA_MAP_CONF("pmca",    none, na),
+	TEGRA_MAP_CONF("pmcb",    none, na),
+	TEGRA_MAP_CONF("pmcc",    none, na),
+	TEGRA_MAP_CONF("pmcd",    none, na),
+	TEGRA_MAP_CONF("pmce",    none, na),
+	TEGRA_MAP_CONF("xm2c",    none, na),
+	TEGRA_MAP_CONF("xm2d",    none, na),
+	TEGRA_MAP_CONF("ls",      up,   na),
+	TEGRA_MAP_CONF("lc",      up,   na),
+	TEGRA_MAP_CONF("ld17_0",  down, na),
+	TEGRA_MAP_CONF("ld19_18", down, na),
+	TEGRA_MAP_CONF("ld21_20", down, na),
+	TEGRA_MAP_CONF("ld23_22", down, na),
 };
 
-static struct tegra_pingroup_config seaboard_pinmux[] = {
-	{TEGRA_PINGROUP_DDC,   TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_GMD,   TEGRA_MUX_SFLASH,        TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LPW0,  TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LPW2,  TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LSC1,  TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSCK,  TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSDA,  TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_PTA,   TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SLXC,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPIA,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIC,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPIG,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+static struct pinctrl_map seaboard_map[] = {
+	TEGRA_MAP_MUXCONF("ddc",   "rsvd2",         none, tristate),
+	TEGRA_MAP_MUXCONF("gmd",   "sflash",        none, driven),
+	TEGRA_MAP_MUXCONF("lpw0",  "hdmi",          na,   driven),
+	TEGRA_MAP_MUXCONF("lpw2",  "hdmi",          na,   driven),
+	TEGRA_MAP_MUXCONF("lsc1",  "hdmi",          na,   tristate),
+	TEGRA_MAP_MUXCONF("lsck",  "hdmi",          na,   tristate),
+	TEGRA_MAP_MUXCONF("lsda",  "hdmi",          na,   tristate),
+	TEGRA_MAP_MUXCONF("slxc",  "spdif",         none, tristate),
+	TEGRA_MAP_MUXCONF("spia",  "gmi",           up,   tristate),
+	TEGRA_MAP_MUXCONF("spic",  "gmi",           up,   driven),
+	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      up,   tristate),
+	PIN_MAP_CONFIGS_GROUP_HOG_DEFAULT(PINMUX_DEV, "drive_sdio1", seaboard_pincfg_drive_sdio1),
 };
 
-static struct tegra_pingroup_config ventana_pinmux[] = {
-	{TEGRA_PINGROUP_DDC,  TEGRA_MUX_RSVD2,    TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMD,  TEGRA_MUX_SFLASH,   TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPW0, TEGRA_MUX_RSVD4,    TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LPW2, TEGRA_MUX_RSVD4,    TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LSC1, TEGRA_MUX_RSVD4,    TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LSCK, TEGRA_MUX_RSVD4,    TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSDA, TEGRA_MUX_RSVD4,    TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_PTA,  TEGRA_MUX_RSVD2,    TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SLXC, TEGRA_MUX_SDIO3,    TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SLXK, TEGRA_MUX_SDIO3,    TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-};
-
-static struct tegra_gpio_table common_gpio_table[] = {
-	{ .gpio = TEGRA_GPIO_SD2_CD,		.enable = true },
-	{ .gpio = TEGRA_GPIO_SD2_WP,		.enable = true },
-	{ .gpio = TEGRA_GPIO_SD2_POWER,		.enable = true },
-	{ .gpio = TEGRA_GPIO_CDC_IRQ,		.enable = true },
-};
-
-static struct tegra_gpio_table seaboard_gpio_table[] = {
-	{ .gpio = TEGRA_GPIO_LIDSWITCH,		.enable = true },
-	{ .gpio = TEGRA_GPIO_POWERKEY,		.enable = true },
-	{ .gpio = TEGRA_GPIO_HP_DET,		.enable = true },
-	{ .gpio = TEGRA_GPIO_ISL29018_IRQ,	.enable = true },
-	{ .gpio = TEGRA_GPIO_USB1,		.enable = true },
-};
-
-static struct tegra_gpio_table ventana_gpio_table[] = {
-	/* hp_det */
-	{ .gpio = TEGRA_GPIO_PW2,		.enable = true },
-	/* int_mic_en */
-	{ .gpio = TEGRA_GPIO_PX0,		.enable = true },
-	/* ext_mic_en */
-	{ .gpio = TEGRA_GPIO_PX1,		.enable = true },
+static struct pinctrl_map ventana_map[] = {
+	TEGRA_MAP_MUXCONF("ddc",   "rsvd2",         none, driven),
+	TEGRA_MAP_MUXCONF("gmd",   "sflash",        none, tristate),
+	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("slxc",  "sdio3",         none, driven),
+	TEGRA_MAP_MUXCONF("spia",  "gmi",           none, tristate),
+	TEGRA_MAP_MUXCONF("spic",  "gmi",           none, tristate),
+	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      none, tristate),
 };
 
 static struct tegra_board_pinmux_conf common_conf = {
-	.pgs = common_pinmux,
-	.pg_count = ARRAY_SIZE(common_pinmux),
-	.gpios = common_gpio_table,
-	.gpio_count = ARRAY_SIZE(common_gpio_table),
+	.maps = common_map,
+	.map_count = ARRAY_SIZE(common_map),
 };
 
 static struct tegra_board_pinmux_conf seaboard_conf = {
-	.pgs = seaboard_pinmux,
-	.pg_count = ARRAY_SIZE(seaboard_pinmux),
-	.drives = seaboard_drive_pinmux,
-	.drive_count = ARRAY_SIZE(seaboard_drive_pinmux),
-	.gpios = seaboard_gpio_table,
-	.gpio_count = ARRAY_SIZE(seaboard_gpio_table),
+	.maps = seaboard_map,
+	.map_count = ARRAY_SIZE(seaboard_map),
 };
 
 static struct tegra_board_pinmux_conf ventana_conf = {
-	.pgs = ventana_pinmux,
-	.pg_count = ARRAY_SIZE(ventana_pinmux),
-	.gpios = ventana_gpio_table,
-	.gpio_count = ARRAY_SIZE(ventana_gpio_table),
+	.maps = ventana_map,
+	.map_count = ARRAY_SIZE(ventana_map),
 };
 
 void seaboard_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c
index d669847..79064c7 100644
--- a/arch/arm/mach-tegra/board-seaboard.c
+++ b/arch/arm/mach-tegra/board-seaboard.c
@@ -18,12 +18,14 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
+#include <linux/platform_data/tegra_usb.h>
 
 #include <sound/wm8903.h>
 
@@ -47,6 +49,7 @@
 		/* Memory and IRQ filled in before registration */
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= 216000000,
@@ -153,7 +156,6 @@
 	&seaboard_gpio_keys_device,
 	&tegra_i2s_device1,
 	&tegra_das_device,
-	&tegra_pcm_device,
 	&seaboard_audio_device,
 };
 
@@ -186,20 +188,10 @@
 
 static int seaboard_ehci_init(void)
 {
-	int gpio_status;
+	struct tegra_ehci_platform_data *pdata;
 
-	gpio_status = gpio_request(TEGRA_GPIO_USB1, "VBUS_USB1");
-	if (gpio_status < 0) {
-		pr_err("VBUS_USB1 request GPIO FAILED\n");
-		WARN_ON(1);
-	}
-
-	gpio_status = gpio_direction_output(TEGRA_GPIO_USB1, 1);
-	if (gpio_status < 0) {
-		pr_err("VBUS_USB1 request GPIO DIRECTION FAILED\n");
-		WARN_ON(1);
-	}
-	gpio_set_value(TEGRA_GPIO_USB1, 1);
+	pdata = tegra_ehci1_device.dev.platform_data;
+	pdata->vbus_gpio = TEGRA_GPIO_USB1;
 
 	platform_device_register(&tegra_ehci1_device);
 	platform_device_register(&tegra_ehci3_device);
@@ -209,9 +201,6 @@
 
 static void __init seaboard_i2c_init(void)
 {
-	gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018");
-	gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ);
-
 	isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ);
 	i2c_register_board_info(0, &isl29018_device, 1);
 
@@ -261,7 +250,6 @@
 	debug_uart_platform_data[0].irq = INT_UARTB;
 
 	seaboard_audio_pdata.gpio_hp_mute = TEGRA_GPIO_KAEN_HP_MUTE;
-	tegra_gpio_enable(TEGRA_GPIO_KAEN_HP_MUTE);
 
 	seaboard_common_init();
 
diff --git a/arch/arm/mach-tegra/board-trimslice-pinmux.c b/arch/arm/mach-tegra/board-trimslice-pinmux.c
index a21a2be..7b39511 100644
--- a/arch/arm/mach-tegra/board-trimslice-pinmux.c
+++ b/arch/arm/mach-tegra/board-trimslice-pinmux.c
@@ -2,6 +2,7 @@
  * arch/arm/mach-tegra/board-trimslice-pinmux.c
  *
  * Copyright (C) 2011 CompuLab, Ltd.
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -13,150 +14,139 @@
  * GNU General Public License for more details.
  *
  */
-#include <linux/gpio.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/of.h>
 
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-
-#include "gpio-names.h"
-#include "board-pinmux.h"
 #include "board-trimslice.h"
+#include "board-pinmux.h"
 
-static struct tegra_pingroup_config trimslice_pinmux[] = {
-	{TEGRA_PINGROUP_ATA,   TEGRA_MUX_IDE,           TEGRA_PUPD_NORMAL,	TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_ATB,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,	TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_ATC,   TEGRA_MUX_NAND,          TEGRA_PUPD_NORMAL,	TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_ATD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,	TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_ATE,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,	TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT,      TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4,     TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CRTP,  TEGRA_MUX_CRT,           TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CSUS,  TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP1,  TEGRA_MUX_DAP1,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DAP2,  TEGRA_MUX_DAP2,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP3,  TEGRA_MUX_DAP3,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DAP4,  TEGRA_MUX_DAP4,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DDC,   TEGRA_MUX_I2C2,          TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DTA,   TEGRA_MUX_VI,            TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTB,   TEGRA_MUX_VI,            TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTC,   TEGRA_MUX_VI,            TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTD,   TEGRA_MUX_VI,            TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTE,   TEGRA_MUX_VI,            TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_DTF,   TEGRA_MUX_I2C3,          TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMA,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMB,   TEGRA_MUX_NAND,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_GMC,   TEGRA_MUX_SFLASH,        TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GMD,   TEGRA_MUX_SFLASH,        TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GME,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_GPU,   TEGRA_MUX_UARTA,         TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPU7,  TEGRA_MUX_RTCK,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI,          TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_I2CP,  TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_IRRX,  TEGRA_MUX_UARTB,         TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_IRTX,  TEGRA_MUX_UARTB,         TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_KBCA,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_KBCB,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_KBCC,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_KBCD,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_KBCE,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_KBCF,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LCSN,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LD0,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD1,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD2,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD3,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD4,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD5,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD6,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD7,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD8,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD9,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD10,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD11,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD12,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD13,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD14,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD15,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD16,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LD17,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LDC,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LDI,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHP2,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LHS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LM0,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LM1,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPP,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LPW0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LPW1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LPW2,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LSC0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LSC1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSCK,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSDA,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSDI,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LSPI,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LVP0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_LVP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_LVS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_OWC,   TEGRA_MUX_RSVD2,         TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_PMC,   TEGRA_MUX_PWR_ON,        TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_PTA,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_RM,    TEGRA_MUX_I2C,           TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDB,   TEGRA_MUX_PWM,           TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDC,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDD,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,     TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1,         TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SLXC,  TEGRA_MUX_SDIO3,         TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXD,  TEGRA_MUX_SDIO3,         TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_SPDI,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPDO,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIA,  TEGRA_MUX_SPI2,          TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIB,  TEGRA_MUX_SPI2,          TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIC,  TEGRA_MUX_SPI2,          TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPID,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIE,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIF,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_DOWN,   TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIG,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SPIH,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UAA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UAB,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UAC,   TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_UAD,   TEGRA_MUX_IRDA,          TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UCA,   TEGRA_MUX_UARTC,         TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UCB,   TEGRA_MUX_UARTC,         TEGRA_PUPD_PULL_UP,     TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_UDA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_CK32,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_DDRC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCA,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCB,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCD,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_PMCE,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_XM2C,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_XM2D,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
-};
-
-static struct tegra_gpio_table gpio_table[] = {
-	{ .gpio = TRIMSLICE_GPIO_SD4_CD, .enable = true	}, /* mmc4 cd */
-	{ .gpio = TRIMSLICE_GPIO_SD4_WP, .enable = true	}, /* mmc4 wp */
-
-	{ .gpio = TRIMSLICE_GPIO_USB1_MODE, .enable = true }, /* USB1 mode */
-	{ .gpio = TRIMSLICE_GPIO_USB2_RST,  .enable = true }, /* USB2 PHY rst */
+static struct pinctrl_map trimslice_map[] = {
+	TEGRA_MAP_MUXCONF("ata",   "ide",           none, tristate),
+	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("atc",   "nand",          none, tristate),
+	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, tristate),
+	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, tristate),
+	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
+	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     down, tristate),
+	TEGRA_MAP_MUXCONF("crtp",  "crt",           none, tristate),
+	TEGRA_MAP_MUXCONF("csus",  "vi_sensor_clk", down, tristate),
+	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
+	TEGRA_MAP_MUXCONF("dap2",  "dap2",          none, tristate),
+	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
+	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, tristate),
+	TEGRA_MAP_MUXCONF("ddc",   "i2c2",          up,   driven),
+	TEGRA_MAP_MUXCONF("dta",   "vi",            none, tristate),
+	TEGRA_MAP_MUXCONF("dtb",   "vi",            none, tristate),
+	TEGRA_MAP_MUXCONF("dtc",   "vi",            none, tristate),
+	TEGRA_MAP_MUXCONF("dtd",   "vi",            none, tristate),
+	TEGRA_MAP_MUXCONF("dte",   "vi",            none, tristate),
+	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          up,   driven),
+	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
+	TEGRA_MAP_MUXCONF("gmb",   "nand",          none, tristate),
+	TEGRA_MAP_MUXCONF("gmc",   "sflash",        none, driven),
+	TEGRA_MAP_MUXCONF("gmd",   "sflash",        none, driven),
+	TEGRA_MAP_MUXCONF("gme",   "gmi",           none, tristate),
+	TEGRA_MAP_MUXCONF("gpu",   "uarta",         none, driven),
+	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
+	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, driven),
+	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   tristate),
+	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, tristate),
+	TEGRA_MAP_MUXCONF("irrx",  "uartb",         up,   tristate),
+	TEGRA_MAP_MUXCONF("irtx",  "uartb",         up,   tristate),
+	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   tristate),
+	TEGRA_MAP_MUXCONF("kbcb",  "kbc",           up,   tristate),
+	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   tristate),
+	TEGRA_MAP_MUXCONF("kbcd",  "kbc",           up,   tristate),
+	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   tristate),
+	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   tristate),
+	TEGRA_MAP_MUXCONF("lcsn",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("ldc",   "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lm0",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lm1",   "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lpw1",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lsdi",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lvp0",  "displaya",      na,   tristate),
+	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
+	TEGRA_MAP_MUXCONF("owc",   "rsvd2",         up,   tristate),
+	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   tristate),
+	TEGRA_MAP_MUXCONF("pta",   "gmi",           none, tristate),
+	TEGRA_MAP_MUXCONF("rm",    "i2c1",          up,   driven),
+	TEGRA_MAP_MUXCONF("sdb",   "pwm",           na,   driven),
+	TEGRA_MAP_MUXCONF("sdc",   "pwm",           up,   driven),
+	TEGRA_MAP_MUXCONF("sdd",   "pwm",           up,   driven),
+	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         none, driven),
+	TEGRA_MAP_MUXCONF("slxa",  "pcie",          none, driven),
+	TEGRA_MAP_MUXCONF("slxc",  "sdio3",         none, tristate),
+	TEGRA_MAP_MUXCONF("slxd",  "sdio3",         none, tristate),
+	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
+	TEGRA_MAP_MUXCONF("spdi",  "spdif",         none, tristate),
+	TEGRA_MAP_MUXCONF("spdo",  "spdif",         none, tristate),
+	TEGRA_MAP_MUXCONF("spia",  "spi2",          down, tristate),
+	TEGRA_MAP_MUXCONF("spib",  "spi2",          down, tristate),
+	TEGRA_MAP_MUXCONF("spic",  "spi2",          up,   tristate),
+	TEGRA_MAP_MUXCONF("spid",  "spi1",          down, tristate),
+	TEGRA_MAP_MUXCONF("spie",  "spi1",          up,   tristate),
+	TEGRA_MAP_MUXCONF("spif",  "spi1",          down, tristate),
+	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      up,   tristate),
+	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
+	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   tristate),
+	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   tristate),
+	TEGRA_MAP_MUXCONF("uac",   "rsvd2",         none, driven),
+	TEGRA_MAP_MUXCONF("uad",   "irda",          up,   tristate),
+	TEGRA_MAP_MUXCONF("uca",   "uartc",         up,   tristate),
+	TEGRA_MAP_MUXCONF("ucb",   "uartc",         up,   tristate),
+	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, tristate),
+	TEGRA_MAP_CONF("ck32",    none, na),
+	TEGRA_MAP_CONF("ddrc",    none, na),
+	TEGRA_MAP_CONF("pmca",    none, na),
+	TEGRA_MAP_CONF("pmcb",    none, na),
+	TEGRA_MAP_CONF("pmcc",    none, na),
+	TEGRA_MAP_CONF("pmcd",    none, na),
+	TEGRA_MAP_CONF("pmce",    none, na),
+	TEGRA_MAP_CONF("xm2c",    none, na),
+	TEGRA_MAP_CONF("xm2d",    none, na),
+	TEGRA_MAP_CONF("ls",      up,   na),
+	TEGRA_MAP_CONF("lc",      up,   na),
+	TEGRA_MAP_CONF("ld17_0",  down, na),
+	TEGRA_MAP_CONF("ld19_18", down, na),
+	TEGRA_MAP_CONF("ld21_20", down, na),
+	TEGRA_MAP_CONF("ld23_22", down, na),
 };
 
 static struct tegra_board_pinmux_conf conf = {
-	.pgs = trimslice_pinmux,
-	.pg_count = ARRAY_SIZE(trimslice_pinmux),
-	.gpios = gpio_table,
-	.gpio_count = ARRAY_SIZE(gpio_table),
+	.maps = trimslice_map,
+	.map_count = ARRAY_SIZE(trimslice_map),
 };
 
 void trimslice_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c
index cd52820a..bc59b37 100644
--- a/arch/arm/mach-tegra/board-trimslice.c
+++ b/arch/arm/mach-tegra/board-trimslice.c
@@ -22,9 +22,11 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
+#include <linux/platform_data/tegra_usb.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
@@ -48,6 +50,7 @@
 		.irq		= INT_UARTA,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= 216000000,
@@ -86,7 +89,6 @@
 	&tegra_sdhci_device4,
 	&tegra_i2s_device1,
 	&tegra_das_device,
-	&tegra_pcm_device,
 	&trimslice_audio_device,
 };
 
@@ -111,19 +113,13 @@
 
 static void trimslice_usb_init(void)
 {
-	int err;
+	struct tegra_ehci_platform_data *pdata;
+
+	pdata = tegra_ehci1_device.dev.platform_data;
+	pdata->vbus_gpio = TRIMSLICE_GPIO_USB1_MODE;
 
 	platform_device_register(&tegra_ehci3_device);
-
 	platform_device_register(&tegra_ehci2_device);
-
-	err = gpio_request_one(TRIMSLICE_GPIO_USB1_MODE, GPIOF_OUT_INIT_HIGH,
-			       "usb1mode");
-	if (err) {
-		pr_err("TrimSlice: failed to obtain USB1 mode gpio: %d\n", err);
-		return;
-	}
-
 	platform_device_register(&tegra_ehci1_device);
 }
 
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 5f6b867..2d8dfa2 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -110,7 +110,7 @@
 };
 
 struct platform_device tegra_pinmux_device = {
-	.name		= "tegra-pinmux",
+	.name		= "tegra20-pinctrl",
 	.id		= -1,
 	.resource	= pinmux_resource,
 	.num_resources	= ARRAY_SIZE(pinmux_resource),
@@ -448,17 +448,20 @@
 struct tegra_ehci_platform_data tegra_ehci1_pdata = {
 	.operating_mode = TEGRA_USB_OTG,
 	.power_down_on_bus_suspend = 1,
+	.vbus_gpio = -1,
 };
 
 struct tegra_ehci_platform_data tegra_ehci2_pdata = {
 	.phy_config = &tegra_ehci2_ulpi_phy_config,
 	.operating_mode = TEGRA_USB_HOST,
 	.power_down_on_bus_suspend = 1,
+	.vbus_gpio = -1,
 };
 
 struct tegra_ehci_platform_data tegra_ehci3_pdata = {
 	.operating_mode = TEGRA_USB_HOST,
 	.power_down_on_bus_suspend = 1,
+	.vbus_gpio = -1,
 };
 
 static u64 tegra_ehci_dmamask = DMA_BIT_MASK(32);
@@ -671,14 +674,14 @@
 };
 
 struct platform_device tegra_i2s_device1 = {
-	.name		= "tegra-i2s",
+	.name		= "tegra20-i2s",
 	.id		= 0,
 	.resource	= i2s_resource1,
 	.num_resources	= ARRAY_SIZE(i2s_resource1),
 };
 
 struct platform_device tegra_i2s_device2 = {
-	.name		= "tegra-i2s",
+	.name		= "tegra20-i2s",
 	.id		= 1,
 	.resource	= i2s_resource2,
 	.num_resources	= ARRAY_SIZE(i2s_resource2),
@@ -693,13 +696,8 @@
 };
 
 struct platform_device tegra_das_device = {
-	.name		= "tegra-das",
+	.name		= "tegra20-das",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(tegra_das_resources),
 	.resource	= tegra_das_resources,
 };
-
-struct platform_device tegra_pcm_device = {
-	.name = "tegra-pcm-audio",
-	.id = -1,
-};
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index ec45567..138c642 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -52,6 +52,5 @@
 extern struct platform_device tegra_i2s_device1;
 extern struct platform_device tegra_i2s_device2;
 extern struct platform_device tegra_das_device;
-extern struct platform_device tegra_pcm_device;
 
 #endif
diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h
index 3c9339058..9077092 100644
--- a/arch/arm/mach-tegra/include/mach/dma.h
+++ b/arch/arm/mach-tegra/include/mach/dma.h
@@ -51,8 +51,6 @@
 #define TEGRA_DMA_REQ_SEL_OWR			25
 #define TEGRA_DMA_REQ_SEL_INVALID		31
 
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-
 struct tegra_dma_req;
 struct tegra_dma_channel;
 
@@ -151,5 +149,3 @@
 int __init tegra_dma_init(void);
 
 #endif
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/gpio-tegra.h b/arch/arm/mach-tegra/include/mach/gpio-tegra.h
index 6140820..a978b3c 100644
--- a/arch/arm/mach-tegra/include/mach/gpio-tegra.h
+++ b/arch/arm/mach-tegra/include/mach/gpio-tegra.h
@@ -25,13 +25,4 @@
 
 #define TEGRA_NR_GPIOS		INT_GPIO_NR
 
-struct tegra_gpio_table {
-	int	gpio;	/* GPIO number */
-	bool	enable;	/* Enable for GPIO at init? */
-};
-
-void tegra_gpio_config(struct tegra_gpio_table *table, int num);
-void tegra_gpio_enable(int gpio);
-void tegra_gpio_disable(int gpio);
-
 #endif
diff --git a/arch/arm/mach-tegra/include/mach/pinmux-tegra20.h b/arch/arm/mach-tegra/include/mach/pinmux-tegra20.h
deleted file mode 100644
index 6a40c1d..0000000
--- a/arch/arm/mach-tegra/include/mach/pinmux-tegra20.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/include/mach/pinmux-tegra20.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __MACH_TEGRA_PINMUX_TEGRA20_H
-#define __MACH_TEGRA_PINMUX_TEGRA20_H
-
-enum tegra_pingroup {
-	TEGRA_PINGROUP_ATA = 0,
-	TEGRA_PINGROUP_ATB,
-	TEGRA_PINGROUP_ATC,
-	TEGRA_PINGROUP_ATD,
-	TEGRA_PINGROUP_ATE,
-	TEGRA_PINGROUP_CDEV1,
-	TEGRA_PINGROUP_CDEV2,
-	TEGRA_PINGROUP_CRTP,
-	TEGRA_PINGROUP_CSUS,
-	TEGRA_PINGROUP_DAP1,
-	TEGRA_PINGROUP_DAP2,
-	TEGRA_PINGROUP_DAP3,
-	TEGRA_PINGROUP_DAP4,
-	TEGRA_PINGROUP_DDC,
-	TEGRA_PINGROUP_DTA,
-	TEGRA_PINGROUP_DTB,
-	TEGRA_PINGROUP_DTC,
-	TEGRA_PINGROUP_DTD,
-	TEGRA_PINGROUP_DTE,
-	TEGRA_PINGROUP_DTF,
-	TEGRA_PINGROUP_GMA,
-	TEGRA_PINGROUP_GMB,
-	TEGRA_PINGROUP_GMC,
-	TEGRA_PINGROUP_GMD,
-	TEGRA_PINGROUP_GME,
-	TEGRA_PINGROUP_GPU,
-	TEGRA_PINGROUP_GPU7,
-	TEGRA_PINGROUP_GPV,
-	TEGRA_PINGROUP_HDINT,
-	TEGRA_PINGROUP_I2CP,
-	TEGRA_PINGROUP_IRRX,
-	TEGRA_PINGROUP_IRTX,
-	TEGRA_PINGROUP_KBCA,
-	TEGRA_PINGROUP_KBCB,
-	TEGRA_PINGROUP_KBCC,
-	TEGRA_PINGROUP_KBCD,
-	TEGRA_PINGROUP_KBCE,
-	TEGRA_PINGROUP_KBCF,
-	TEGRA_PINGROUP_LCSN,
-	TEGRA_PINGROUP_LD0,
-	TEGRA_PINGROUP_LD1,
-	TEGRA_PINGROUP_LD10,
-	TEGRA_PINGROUP_LD11,
-	TEGRA_PINGROUP_LD12,
-	TEGRA_PINGROUP_LD13,
-	TEGRA_PINGROUP_LD14,
-	TEGRA_PINGROUP_LD15,
-	TEGRA_PINGROUP_LD16,
-	TEGRA_PINGROUP_LD17,
-	TEGRA_PINGROUP_LD2,
-	TEGRA_PINGROUP_LD3,
-	TEGRA_PINGROUP_LD4,
-	TEGRA_PINGROUP_LD5,
-	TEGRA_PINGROUP_LD6,
-	TEGRA_PINGROUP_LD7,
-	TEGRA_PINGROUP_LD8,
-	TEGRA_PINGROUP_LD9,
-	TEGRA_PINGROUP_LDC,
-	TEGRA_PINGROUP_LDI,
-	TEGRA_PINGROUP_LHP0,
-	TEGRA_PINGROUP_LHP1,
-	TEGRA_PINGROUP_LHP2,
-	TEGRA_PINGROUP_LHS,
-	TEGRA_PINGROUP_LM0,
-	TEGRA_PINGROUP_LM1,
-	TEGRA_PINGROUP_LPP,
-	TEGRA_PINGROUP_LPW0,
-	TEGRA_PINGROUP_LPW1,
-	TEGRA_PINGROUP_LPW2,
-	TEGRA_PINGROUP_LSC0,
-	TEGRA_PINGROUP_LSC1,
-	TEGRA_PINGROUP_LSCK,
-	TEGRA_PINGROUP_LSDA,
-	TEGRA_PINGROUP_LSDI,
-	TEGRA_PINGROUP_LSPI,
-	TEGRA_PINGROUP_LVP0,
-	TEGRA_PINGROUP_LVP1,
-	TEGRA_PINGROUP_LVS,
-	TEGRA_PINGROUP_OWC,
-	TEGRA_PINGROUP_PMC,
-	TEGRA_PINGROUP_PTA,
-	TEGRA_PINGROUP_RM,
-	TEGRA_PINGROUP_SDB,
-	TEGRA_PINGROUP_SDC,
-	TEGRA_PINGROUP_SDD,
-	TEGRA_PINGROUP_SDIO1,
-	TEGRA_PINGROUP_SLXA,
-	TEGRA_PINGROUP_SLXC,
-	TEGRA_PINGROUP_SLXD,
-	TEGRA_PINGROUP_SLXK,
-	TEGRA_PINGROUP_SPDI,
-	TEGRA_PINGROUP_SPDO,
-	TEGRA_PINGROUP_SPIA,
-	TEGRA_PINGROUP_SPIB,
-	TEGRA_PINGROUP_SPIC,
-	TEGRA_PINGROUP_SPID,
-	TEGRA_PINGROUP_SPIE,
-	TEGRA_PINGROUP_SPIF,
-	TEGRA_PINGROUP_SPIG,
-	TEGRA_PINGROUP_SPIH,
-	TEGRA_PINGROUP_UAA,
-	TEGRA_PINGROUP_UAB,
-	TEGRA_PINGROUP_UAC,
-	TEGRA_PINGROUP_UAD,
-	TEGRA_PINGROUP_UCA,
-	TEGRA_PINGROUP_UCB,
-	TEGRA_PINGROUP_UDA,
-	/* these pin groups only have pullup and pull down control */
-	TEGRA_PINGROUP_CK32,
-	TEGRA_PINGROUP_DDRC,
-	TEGRA_PINGROUP_PMCA,
-	TEGRA_PINGROUP_PMCB,
-	TEGRA_PINGROUP_PMCC,
-	TEGRA_PINGROUP_PMCD,
-	TEGRA_PINGROUP_PMCE,
-	TEGRA_PINGROUP_XM2C,
-	TEGRA_PINGROUP_XM2D,
-	TEGRA_MAX_PINGROUP,
-};
-
-enum tegra_drive_pingroup {
-	TEGRA_DRIVE_PINGROUP_AO1 = 0,
-	TEGRA_DRIVE_PINGROUP_AO2,
-	TEGRA_DRIVE_PINGROUP_AT1,
-	TEGRA_DRIVE_PINGROUP_AT2,
-	TEGRA_DRIVE_PINGROUP_CDEV1,
-	TEGRA_DRIVE_PINGROUP_CDEV2,
-	TEGRA_DRIVE_PINGROUP_CSUS,
-	TEGRA_DRIVE_PINGROUP_DAP1,
-	TEGRA_DRIVE_PINGROUP_DAP2,
-	TEGRA_DRIVE_PINGROUP_DAP3,
-	TEGRA_DRIVE_PINGROUP_DAP4,
-	TEGRA_DRIVE_PINGROUP_DBG,
-	TEGRA_DRIVE_PINGROUP_LCD1,
-	TEGRA_DRIVE_PINGROUP_LCD2,
-	TEGRA_DRIVE_PINGROUP_SDMMC2,
-	TEGRA_DRIVE_PINGROUP_SDMMC3,
-	TEGRA_DRIVE_PINGROUP_SPI,
-	TEGRA_DRIVE_PINGROUP_UAA,
-	TEGRA_DRIVE_PINGROUP_UAB,
-	TEGRA_DRIVE_PINGROUP_UART2,
-	TEGRA_DRIVE_PINGROUP_UART3,
-	TEGRA_DRIVE_PINGROUP_VI1,
-	TEGRA_DRIVE_PINGROUP_VI2,
-	TEGRA_DRIVE_PINGROUP_XM2A,
-	TEGRA_DRIVE_PINGROUP_XM2C,
-	TEGRA_DRIVE_PINGROUP_XM2D,
-	TEGRA_DRIVE_PINGROUP_XM2CLK,
-	TEGRA_DRIVE_PINGROUP_MEMCOMP,
-	TEGRA_DRIVE_PINGROUP_SDIO1,
-	TEGRA_DRIVE_PINGROUP_CRT,
-	TEGRA_DRIVE_PINGROUP_DDC,
-	TEGRA_DRIVE_PINGROUP_GMA,
-	TEGRA_DRIVE_PINGROUP_GMB,
-	TEGRA_DRIVE_PINGROUP_GMC,
-	TEGRA_DRIVE_PINGROUP_GMD,
-	TEGRA_DRIVE_PINGROUP_GME,
-	TEGRA_DRIVE_PINGROUP_OWR,
-	TEGRA_DRIVE_PINGROUP_UAD,
-	TEGRA_MAX_DRIVE_PINGROUP,
-};
-
-#endif
-
diff --git a/arch/arm/mach-tegra/include/mach/pinmux-tegra30.h b/arch/arm/mach-tegra/include/mach/pinmux-tegra30.h
deleted file mode 100644
index c1aee3e..0000000
--- a/arch/arm/mach-tegra/include/mach/pinmux-tegra30.h
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/include/mach/pinmux-tegra30.h
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2010,2011 Nvidia, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __MACH_TEGRA_PINMUX_TEGRA30_H
-#define __MACH_TEGRA_PINMUX_TEGRA30_H
-
-enum tegra_pingroup {
-	TEGRA_PINGROUP_ULPI_DATA0 = 0,
-	TEGRA_PINGROUP_ULPI_DATA1,
-	TEGRA_PINGROUP_ULPI_DATA2,
-	TEGRA_PINGROUP_ULPI_DATA3,
-	TEGRA_PINGROUP_ULPI_DATA4,
-	TEGRA_PINGROUP_ULPI_DATA5,
-	TEGRA_PINGROUP_ULPI_DATA6,
-	TEGRA_PINGROUP_ULPI_DATA7,
-	TEGRA_PINGROUP_ULPI_CLK,
-	TEGRA_PINGROUP_ULPI_DIR,
-	TEGRA_PINGROUP_ULPI_NXT,
-	TEGRA_PINGROUP_ULPI_STP,
-	TEGRA_PINGROUP_DAP3_FS,
-	TEGRA_PINGROUP_DAP3_DIN,
-	TEGRA_PINGROUP_DAP3_DOUT,
-	TEGRA_PINGROUP_DAP3_SCLK,
-	TEGRA_PINGROUP_GPIO_PV0,
-	TEGRA_PINGROUP_GPIO_PV1,
-	TEGRA_PINGROUP_SDMMC1_CLK,
-	TEGRA_PINGROUP_SDMMC1_CMD,
-	TEGRA_PINGROUP_SDMMC1_DAT3,
-	TEGRA_PINGROUP_SDMMC1_DAT2,
-	TEGRA_PINGROUP_SDMMC1_DAT1,
-	TEGRA_PINGROUP_SDMMC1_DAT0,
-	TEGRA_PINGROUP_GPIO_PV2,
-	TEGRA_PINGROUP_GPIO_PV3,
-	TEGRA_PINGROUP_CLK2_OUT,
-	TEGRA_PINGROUP_CLK2_REQ,
-	TEGRA_PINGROUP_LCD_PWR1,
-	TEGRA_PINGROUP_LCD_PWR2,
-	TEGRA_PINGROUP_LCD_SDIN,
-	TEGRA_PINGROUP_LCD_SDOUT,
-	TEGRA_PINGROUP_LCD_WR_N,
-	TEGRA_PINGROUP_LCD_CS0_N,
-	TEGRA_PINGROUP_LCD_DC0,
-	TEGRA_PINGROUP_LCD_SCK,
-	TEGRA_PINGROUP_LCD_PWR0,
-	TEGRA_PINGROUP_LCD_PCLK,
-	TEGRA_PINGROUP_LCD_DE,
-	TEGRA_PINGROUP_LCD_HSYNC,
-	TEGRA_PINGROUP_LCD_VSYNC,
-	TEGRA_PINGROUP_LCD_D0,
-	TEGRA_PINGROUP_LCD_D1,
-	TEGRA_PINGROUP_LCD_D2,
-	TEGRA_PINGROUP_LCD_D3,
-	TEGRA_PINGROUP_LCD_D4,
-	TEGRA_PINGROUP_LCD_D5,
-	TEGRA_PINGROUP_LCD_D6,
-	TEGRA_PINGROUP_LCD_D7,
-	TEGRA_PINGROUP_LCD_D8,
-	TEGRA_PINGROUP_LCD_D9,
-	TEGRA_PINGROUP_LCD_D10,
-	TEGRA_PINGROUP_LCD_D11,
-	TEGRA_PINGROUP_LCD_D12,
-	TEGRA_PINGROUP_LCD_D13,
-	TEGRA_PINGROUP_LCD_D14,
-	TEGRA_PINGROUP_LCD_D15,
-	TEGRA_PINGROUP_LCD_D16,
-	TEGRA_PINGROUP_LCD_D17,
-	TEGRA_PINGROUP_LCD_D18,
-	TEGRA_PINGROUP_LCD_D19,
-	TEGRA_PINGROUP_LCD_D20,
-	TEGRA_PINGROUP_LCD_D21,
-	TEGRA_PINGROUP_LCD_D22,
-	TEGRA_PINGROUP_LCD_D23,
-	TEGRA_PINGROUP_LCD_CS1_N,
-	TEGRA_PINGROUP_LCD_M1,
-	TEGRA_PINGROUP_LCD_DC1,
-	TEGRA_PINGROUP_HDMI_INT,
-	TEGRA_PINGROUP_DDC_SCL,
-	TEGRA_PINGROUP_DDC_SDA,
-	TEGRA_PINGROUP_CRT_HSYNC,
-	TEGRA_PINGROUP_CRT_VSYNC,
-	TEGRA_PINGROUP_VI_D0,
-	TEGRA_PINGROUP_VI_D1,
-	TEGRA_PINGROUP_VI_D2,
-	TEGRA_PINGROUP_VI_D3,
-	TEGRA_PINGROUP_VI_D4,
-	TEGRA_PINGROUP_VI_D5,
-	TEGRA_PINGROUP_VI_D6,
-	TEGRA_PINGROUP_VI_D7,
-	TEGRA_PINGROUP_VI_D8,
-	TEGRA_PINGROUP_VI_D9,
-	TEGRA_PINGROUP_VI_D10,
-	TEGRA_PINGROUP_VI_D11,
-	TEGRA_PINGROUP_VI_PCLK,
-	TEGRA_PINGROUP_VI_MCLK,
-	TEGRA_PINGROUP_VI_VSYNC,
-	TEGRA_PINGROUP_VI_HSYNC,
-	TEGRA_PINGROUP_UART2_RXD,
-	TEGRA_PINGROUP_UART2_TXD,
-	TEGRA_PINGROUP_UART2_RTS_N,
-	TEGRA_PINGROUP_UART2_CTS_N,
-	TEGRA_PINGROUP_UART3_TXD,
-	TEGRA_PINGROUP_UART3_RXD,
-	TEGRA_PINGROUP_UART3_CTS_N,
-	TEGRA_PINGROUP_UART3_RTS_N,
-	TEGRA_PINGROUP_GPIO_PU0,
-	TEGRA_PINGROUP_GPIO_PU1,
-	TEGRA_PINGROUP_GPIO_PU2,
-	TEGRA_PINGROUP_GPIO_PU3,
-	TEGRA_PINGROUP_GPIO_PU4,
-	TEGRA_PINGROUP_GPIO_PU5,
-	TEGRA_PINGROUP_GPIO_PU6,
-	TEGRA_PINGROUP_GEN1_I2C_SDA,
-	TEGRA_PINGROUP_GEN1_I2C_SCL,
-	TEGRA_PINGROUP_DAP4_FS,
-	TEGRA_PINGROUP_DAP4_DIN,
-	TEGRA_PINGROUP_DAP4_DOUT,
-	TEGRA_PINGROUP_DAP4_SCLK,
-	TEGRA_PINGROUP_CLK3_OUT,
-	TEGRA_PINGROUP_CLK3_REQ,
-	TEGRA_PINGROUP_GMI_WP_N,
-	TEGRA_PINGROUP_GMI_IORDY,
-	TEGRA_PINGROUP_GMI_WAIT,
-	TEGRA_PINGROUP_GMI_ADV_N,
-	TEGRA_PINGROUP_GMI_CLK,
-	TEGRA_PINGROUP_GMI_CS0_N,
-	TEGRA_PINGROUP_GMI_CS1_N,
-	TEGRA_PINGROUP_GMI_CS2_N,
-	TEGRA_PINGROUP_GMI_CS3_N,
-	TEGRA_PINGROUP_GMI_CS4_N,
-	TEGRA_PINGROUP_GMI_CS6_N,
-	TEGRA_PINGROUP_GMI_CS7_N,
-	TEGRA_PINGROUP_GMI_AD0,
-	TEGRA_PINGROUP_GMI_AD1,
-	TEGRA_PINGROUP_GMI_AD2,
-	TEGRA_PINGROUP_GMI_AD3,
-	TEGRA_PINGROUP_GMI_AD4,
-	TEGRA_PINGROUP_GMI_AD5,
-	TEGRA_PINGROUP_GMI_AD6,
-	TEGRA_PINGROUP_GMI_AD7,
-	TEGRA_PINGROUP_GMI_AD8,
-	TEGRA_PINGROUP_GMI_AD9,
-	TEGRA_PINGROUP_GMI_AD10,
-	TEGRA_PINGROUP_GMI_AD11,
-	TEGRA_PINGROUP_GMI_AD12,
-	TEGRA_PINGROUP_GMI_AD13,
-	TEGRA_PINGROUP_GMI_AD14,
-	TEGRA_PINGROUP_GMI_AD15,
-	TEGRA_PINGROUP_GMI_A16,
-	TEGRA_PINGROUP_GMI_A17,
-	TEGRA_PINGROUP_GMI_A18,
-	TEGRA_PINGROUP_GMI_A19,
-	TEGRA_PINGROUP_GMI_WR_N,
-	TEGRA_PINGROUP_GMI_OE_N,
-	TEGRA_PINGROUP_GMI_DQS,
-	TEGRA_PINGROUP_GMI_RST_N,
-	TEGRA_PINGROUP_GEN2_I2C_SCL,
-	TEGRA_PINGROUP_GEN2_I2C_SDA,
-	TEGRA_PINGROUP_SDMMC4_CLK,
-	TEGRA_PINGROUP_SDMMC4_CMD,
-	TEGRA_PINGROUP_SDMMC4_DAT0,
-	TEGRA_PINGROUP_SDMMC4_DAT1,
-	TEGRA_PINGROUP_SDMMC4_DAT2,
-	TEGRA_PINGROUP_SDMMC4_DAT3,
-	TEGRA_PINGROUP_SDMMC4_DAT4,
-	TEGRA_PINGROUP_SDMMC4_DAT5,
-	TEGRA_PINGROUP_SDMMC4_DAT6,
-	TEGRA_PINGROUP_SDMMC4_DAT7,
-	TEGRA_PINGROUP_SDMMC4_RST_N,
-	TEGRA_PINGROUP_CAM_MCLK,
-	TEGRA_PINGROUP_GPIO_PCC1,
-	TEGRA_PINGROUP_GPIO_PBB0,
-	TEGRA_PINGROUP_CAM_I2C_SCL,
-	TEGRA_PINGROUP_CAM_I2C_SDA,
-	TEGRA_PINGROUP_GPIO_PBB3,
-	TEGRA_PINGROUP_GPIO_PBB4,
-	TEGRA_PINGROUP_GPIO_PBB5,
-	TEGRA_PINGROUP_GPIO_PBB6,
-	TEGRA_PINGROUP_GPIO_PBB7,
-	TEGRA_PINGROUP_GPIO_PCC2,
-	TEGRA_PINGROUP_JTAG_RTCK,
-	TEGRA_PINGROUP_PWR_I2C_SCL,
-	TEGRA_PINGROUP_PWR_I2C_SDA,
-	TEGRA_PINGROUP_KB_ROW0,
-	TEGRA_PINGROUP_KB_ROW1,
-	TEGRA_PINGROUP_KB_ROW2,
-	TEGRA_PINGROUP_KB_ROW3,
-	TEGRA_PINGROUP_KB_ROW4,
-	TEGRA_PINGROUP_KB_ROW5,
-	TEGRA_PINGROUP_KB_ROW6,
-	TEGRA_PINGROUP_KB_ROW7,
-	TEGRA_PINGROUP_KB_ROW8,
-	TEGRA_PINGROUP_KB_ROW9,
-	TEGRA_PINGROUP_KB_ROW10,
-	TEGRA_PINGROUP_KB_ROW11,
-	TEGRA_PINGROUP_KB_ROW12,
-	TEGRA_PINGROUP_KB_ROW13,
-	TEGRA_PINGROUP_KB_ROW14,
-	TEGRA_PINGROUP_KB_ROW15,
-	TEGRA_PINGROUP_KB_COL0,
-	TEGRA_PINGROUP_KB_COL1,
-	TEGRA_PINGROUP_KB_COL2,
-	TEGRA_PINGROUP_KB_COL3,
-	TEGRA_PINGROUP_KB_COL4,
-	TEGRA_PINGROUP_KB_COL5,
-	TEGRA_PINGROUP_KB_COL6,
-	TEGRA_PINGROUP_KB_COL7,
-	TEGRA_PINGROUP_CLK_32K_OUT,
-	TEGRA_PINGROUP_SYS_CLK_REQ,
-	TEGRA_PINGROUP_CORE_PWR_REQ,
-	TEGRA_PINGROUP_CPU_PWR_REQ,
-	TEGRA_PINGROUP_PWR_INT_N,
-	TEGRA_PINGROUP_CLK_32K_IN,
-	TEGRA_PINGROUP_OWR,
-	TEGRA_PINGROUP_DAP1_FS,
-	TEGRA_PINGROUP_DAP1_DIN,
-	TEGRA_PINGROUP_DAP1_DOUT,
-	TEGRA_PINGROUP_DAP1_SCLK,
-	TEGRA_PINGROUP_CLK1_REQ,
-	TEGRA_PINGROUP_CLK1_OUT,
-	TEGRA_PINGROUP_SPDIF_IN,
-	TEGRA_PINGROUP_SPDIF_OUT,
-	TEGRA_PINGROUP_DAP2_FS,
-	TEGRA_PINGROUP_DAP2_DIN,
-	TEGRA_PINGROUP_DAP2_DOUT,
-	TEGRA_PINGROUP_DAP2_SCLK,
-	TEGRA_PINGROUP_SPI2_MOSI,
-	TEGRA_PINGROUP_SPI2_MISO,
-	TEGRA_PINGROUP_SPI2_CS0_N,
-	TEGRA_PINGROUP_SPI2_SCK,
-	TEGRA_PINGROUP_SPI1_MOSI,
-	TEGRA_PINGROUP_SPI1_SCK,
-	TEGRA_PINGROUP_SPI1_CS0_N,
-	TEGRA_PINGROUP_SPI1_MISO,
-	TEGRA_PINGROUP_SPI2_CS1_N,
-	TEGRA_PINGROUP_SPI2_CS2_N,
-	TEGRA_PINGROUP_SDMMC3_CLK,
-	TEGRA_PINGROUP_SDMMC3_CMD,
-	TEGRA_PINGROUP_SDMMC3_DAT0,
-	TEGRA_PINGROUP_SDMMC3_DAT1,
-	TEGRA_PINGROUP_SDMMC3_DAT2,
-	TEGRA_PINGROUP_SDMMC3_DAT3,
-	TEGRA_PINGROUP_SDMMC3_DAT4,
-	TEGRA_PINGROUP_SDMMC3_DAT5,
-	TEGRA_PINGROUP_SDMMC3_DAT6,
-	TEGRA_PINGROUP_SDMMC3_DAT7,
-	TEGRA_PINGROUP_PEX_L0_PRSNT_N,
-	TEGRA_PINGROUP_PEX_L0_RST_N,
-	TEGRA_PINGROUP_PEX_L0_CLKREQ_N,
-	TEGRA_PINGROUP_PEX_WAKE_N,
-	TEGRA_PINGROUP_PEX_L1_PRSNT_N,
-	TEGRA_PINGROUP_PEX_L1_RST_N,
-	TEGRA_PINGROUP_PEX_L1_CLKREQ_N,
-	TEGRA_PINGROUP_PEX_L2_PRSNT_N,
-	TEGRA_PINGROUP_PEX_L2_RST_N,
-	TEGRA_PINGROUP_PEX_L2_CLKREQ_N,
-	TEGRA_PINGROUP_HDMI_CEC,
-	TEGRA_MAX_PINGROUP,
-};
-
-enum tegra_drive_pingroup {
-	TEGRA_DRIVE_PINGROUP_AO1 = 0,
-	TEGRA_DRIVE_PINGROUP_AO2,
-	TEGRA_DRIVE_PINGROUP_AT1,
-	TEGRA_DRIVE_PINGROUP_AT2,
-	TEGRA_DRIVE_PINGROUP_AT3,
-	TEGRA_DRIVE_PINGROUP_AT4,
-	TEGRA_DRIVE_PINGROUP_AT5,
-	TEGRA_DRIVE_PINGROUP_CDEV1,
-	TEGRA_DRIVE_PINGROUP_CDEV2,
-	TEGRA_DRIVE_PINGROUP_CSUS,
-	TEGRA_DRIVE_PINGROUP_DAP1,
-	TEGRA_DRIVE_PINGROUP_DAP2,
-	TEGRA_DRIVE_PINGROUP_DAP3,
-	TEGRA_DRIVE_PINGROUP_DAP4,
-	TEGRA_DRIVE_PINGROUP_DBG,
-	TEGRA_DRIVE_PINGROUP_LCD1,
-	TEGRA_DRIVE_PINGROUP_LCD2,
-	TEGRA_DRIVE_PINGROUP_SDIO2,
-	TEGRA_DRIVE_PINGROUP_SDIO3,
-	TEGRA_DRIVE_PINGROUP_SPI,
-	TEGRA_DRIVE_PINGROUP_UAA,
-	TEGRA_DRIVE_PINGROUP_UAB,
-	TEGRA_DRIVE_PINGROUP_UART2,
-	TEGRA_DRIVE_PINGROUP_UART3,
-	TEGRA_DRIVE_PINGROUP_VI1,
-	TEGRA_DRIVE_PINGROUP_SDIO1,
-	TEGRA_DRIVE_PINGROUP_CRT,
-	TEGRA_DRIVE_PINGROUP_DDC,
-	TEGRA_DRIVE_PINGROUP_GMA,
-	TEGRA_DRIVE_PINGROUP_GMB,
-	TEGRA_DRIVE_PINGROUP_GMC,
-	TEGRA_DRIVE_PINGROUP_GMD,
-	TEGRA_DRIVE_PINGROUP_GME,
-	TEGRA_DRIVE_PINGROUP_GMF,
-	TEGRA_DRIVE_PINGROUP_GMG,
-	TEGRA_DRIVE_PINGROUP_GMH,
-	TEGRA_DRIVE_PINGROUP_OWR,
-	TEGRA_DRIVE_PINGROUP_UAD,
-	TEGRA_DRIVE_PINGROUP_GPV,
-	TEGRA_DRIVE_PINGROUP_DEV3,
-	TEGRA_DRIVE_PINGROUP_CEC,
-	TEGRA_MAX_DRIVE_PINGROUP,
-};
-
-#endif
-
diff --git a/arch/arm/mach-tegra/include/mach/pinmux.h b/arch/arm/mach-tegra/include/mach/pinmux.h
deleted file mode 100644
index 055f179..0000000
--- a/arch/arm/mach-tegra/include/mach/pinmux.h
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/include/mach/pinmux.h
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2010,2011 Nvidia, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __MACH_TEGRA_PINMUX_H
-#define __MACH_TEGRA_PINMUX_H
-
-enum tegra_mux_func {
-	TEGRA_MUX_RSVD = 0x8000,
-	TEGRA_MUX_RSVD1 = 0x8000,
-	TEGRA_MUX_RSVD2 = 0x8001,
-	TEGRA_MUX_RSVD3 = 0x8002,
-	TEGRA_MUX_RSVD4 = 0x8003,
-	TEGRA_MUX_INVALID = 0x4000,
-	TEGRA_MUX_NONE = -1,
-	TEGRA_MUX_AHB_CLK,
-	TEGRA_MUX_APB_CLK,
-	TEGRA_MUX_AUDIO_SYNC,
-	TEGRA_MUX_CRT,
-	TEGRA_MUX_DAP1,
-	TEGRA_MUX_DAP2,
-	TEGRA_MUX_DAP3,
-	TEGRA_MUX_DAP4,
-	TEGRA_MUX_DAP5,
-	TEGRA_MUX_DISPLAYA,
-	TEGRA_MUX_DISPLAYB,
-	TEGRA_MUX_EMC_TEST0_DLL,
-	TEGRA_MUX_EMC_TEST1_DLL,
-	TEGRA_MUX_GMI,
-	TEGRA_MUX_GMI_INT,
-	TEGRA_MUX_HDMI,
-	TEGRA_MUX_I2C,
-	TEGRA_MUX_I2C2,
-	TEGRA_MUX_I2C3,
-	TEGRA_MUX_IDE,
-	TEGRA_MUX_IRDA,
-	TEGRA_MUX_KBC,
-	TEGRA_MUX_MIO,
-	TEGRA_MUX_MIPI_HS,
-	TEGRA_MUX_NAND,
-	TEGRA_MUX_OSC,
-	TEGRA_MUX_OWR,
-	TEGRA_MUX_PCIE,
-	TEGRA_MUX_PLLA_OUT,
-	TEGRA_MUX_PLLC_OUT1,
-	TEGRA_MUX_PLLM_OUT1,
-	TEGRA_MUX_PLLP_OUT2,
-	TEGRA_MUX_PLLP_OUT3,
-	TEGRA_MUX_PLLP_OUT4,
-	TEGRA_MUX_PWM,
-	TEGRA_MUX_PWR_INTR,
-	TEGRA_MUX_PWR_ON,
-	TEGRA_MUX_RTCK,
-	TEGRA_MUX_SDIO1,
-	TEGRA_MUX_SDIO2,
-	TEGRA_MUX_SDIO3,
-	TEGRA_MUX_SDIO4,
-	TEGRA_MUX_SFLASH,
-	TEGRA_MUX_SPDIF,
-	TEGRA_MUX_SPI1,
-	TEGRA_MUX_SPI2,
-	TEGRA_MUX_SPI2_ALT,
-	TEGRA_MUX_SPI3,
-	TEGRA_MUX_SPI4,
-	TEGRA_MUX_TRACE,
-	TEGRA_MUX_TWC,
-	TEGRA_MUX_UARTA,
-	TEGRA_MUX_UARTB,
-	TEGRA_MUX_UARTC,
-	TEGRA_MUX_UARTD,
-	TEGRA_MUX_UARTE,
-	TEGRA_MUX_ULPI,
-	TEGRA_MUX_VI,
-	TEGRA_MUX_VI_SENSOR_CLK,
-	TEGRA_MUX_XIO,
-	TEGRA_MUX_BLINK,
-	TEGRA_MUX_CEC,
-	TEGRA_MUX_CLK12,
-	TEGRA_MUX_DAP,
-	TEGRA_MUX_DAPSDMMC2,
-	TEGRA_MUX_DDR,
-	TEGRA_MUX_DEV3,
-	TEGRA_MUX_DTV,
-	TEGRA_MUX_VI_ALT1,
-	TEGRA_MUX_VI_ALT2,
-	TEGRA_MUX_VI_ALT3,
-	TEGRA_MUX_EMC_DLL,
-	TEGRA_MUX_EXTPERIPH1,
-	TEGRA_MUX_EXTPERIPH2,
-	TEGRA_MUX_EXTPERIPH3,
-	TEGRA_MUX_GMI_ALT,
-	TEGRA_MUX_HDA,
-	TEGRA_MUX_HSI,
-	TEGRA_MUX_I2C4,
-	TEGRA_MUX_I2C5,
-	TEGRA_MUX_I2CPWR,
-	TEGRA_MUX_I2S0,
-	TEGRA_MUX_I2S1,
-	TEGRA_MUX_I2S2,
-	TEGRA_MUX_I2S3,
-	TEGRA_MUX_I2S4,
-	TEGRA_MUX_NAND_ALT,
-	TEGRA_MUX_POPSDIO4,
-	TEGRA_MUX_POPSDMMC4,
-	TEGRA_MUX_PWM0,
-	TEGRA_MUX_PWM1,
-	TEGRA_MUX_PWM2,
-	TEGRA_MUX_PWM3,
-	TEGRA_MUX_SATA,
-	TEGRA_MUX_SPI5,
-	TEGRA_MUX_SPI6,
-	TEGRA_MUX_SYSCLK,
-	TEGRA_MUX_VGP1,
-	TEGRA_MUX_VGP2,
-	TEGRA_MUX_VGP3,
-	TEGRA_MUX_VGP4,
-	TEGRA_MUX_VGP5,
-	TEGRA_MUX_VGP6,
-	TEGRA_MUX_SAFE,
-	TEGRA_MAX_MUX,
-};
-
-enum tegra_pullupdown {
-	TEGRA_PUPD_NORMAL = 0,
-	TEGRA_PUPD_PULL_DOWN,
-	TEGRA_PUPD_PULL_UP,
-};
-
-enum tegra_tristate {
-	TEGRA_TRI_NORMAL = 0,
-	TEGRA_TRI_TRISTATE = 1,
-};
-
-enum tegra_pin_io {
-	TEGRA_PIN_OUTPUT = 0,
-	TEGRA_PIN_INPUT = 1,
-};
-
-enum tegra_vddio {
-	TEGRA_VDDIO_BB = 0,
-	TEGRA_VDDIO_LCD,
-	TEGRA_VDDIO_VI,
-	TEGRA_VDDIO_UART,
-	TEGRA_VDDIO_DDR,
-	TEGRA_VDDIO_NAND,
-	TEGRA_VDDIO_SYS,
-	TEGRA_VDDIO_AUDIO,
-	TEGRA_VDDIO_SD,
-	TEGRA_VDDIO_CAM,
-	TEGRA_VDDIO_GMI,
-	TEGRA_VDDIO_PEXCTL,
-	TEGRA_VDDIO_SDMMC1,
-	TEGRA_VDDIO_SDMMC3,
-	TEGRA_VDDIO_SDMMC4,
-};
-
-struct tegra_pingroup_config {
-	int pingroup;
-	enum tegra_mux_func	func;
-	enum tegra_pullupdown	pupd;
-	enum tegra_tristate	tristate;
-};
-
-enum tegra_slew {
-	TEGRA_SLEW_FASTEST = 0,
-	TEGRA_SLEW_FAST,
-	TEGRA_SLEW_SLOW,
-	TEGRA_SLEW_SLOWEST,
-	TEGRA_MAX_SLEW,
-};
-
-enum tegra_pull_strength {
-	TEGRA_PULL_0 = 0,
-	TEGRA_PULL_1,
-	TEGRA_PULL_2,
-	TEGRA_PULL_3,
-	TEGRA_PULL_4,
-	TEGRA_PULL_5,
-	TEGRA_PULL_6,
-	TEGRA_PULL_7,
-	TEGRA_PULL_8,
-	TEGRA_PULL_9,
-	TEGRA_PULL_10,
-	TEGRA_PULL_11,
-	TEGRA_PULL_12,
-	TEGRA_PULL_13,
-	TEGRA_PULL_14,
-	TEGRA_PULL_15,
-	TEGRA_PULL_16,
-	TEGRA_PULL_17,
-	TEGRA_PULL_18,
-	TEGRA_PULL_19,
-	TEGRA_PULL_20,
-	TEGRA_PULL_21,
-	TEGRA_PULL_22,
-	TEGRA_PULL_23,
-	TEGRA_PULL_24,
-	TEGRA_PULL_25,
-	TEGRA_PULL_26,
-	TEGRA_PULL_27,
-	TEGRA_PULL_28,
-	TEGRA_PULL_29,
-	TEGRA_PULL_30,
-	TEGRA_PULL_31,
-	TEGRA_MAX_PULL,
-};
-
-enum tegra_drive {
-	TEGRA_DRIVE_DIV_8 = 0,
-	TEGRA_DRIVE_DIV_4,
-	TEGRA_DRIVE_DIV_2,
-	TEGRA_DRIVE_DIV_1,
-	TEGRA_MAX_DRIVE,
-};
-
-enum tegra_hsm {
-	TEGRA_HSM_DISABLE = 0,
-	TEGRA_HSM_ENABLE,
-};
-
-enum tegra_schmitt {
-	TEGRA_SCHMITT_DISABLE = 0,
-	TEGRA_SCHMITT_ENABLE,
-};
-
-struct tegra_drive_pingroup_config {
-	int pingroup;
-	enum tegra_hsm hsm;
-	enum tegra_schmitt schmitt;
-	enum tegra_drive drive;
-	enum tegra_pull_strength pull_down;
-	enum tegra_pull_strength pull_up;
-	enum tegra_slew slew_rising;
-	enum tegra_slew slew_falling;
-};
-
-struct tegra_drive_pingroup_desc {
-	const char *name;
-	s16 reg_bank;
-	s16 reg;
-};
-
-struct tegra_pingroup_desc {
-	const char *name;
-	int funcs[4];
-	int func_safe;
-	int vddio;
-	enum tegra_pin_io io_default;
-	s16 tri_bank;	/* Register bank the tri_reg exists within */
-	s16 mux_bank;	/* Register bank the mux_reg exists within */
-	s16 pupd_bank;	/* Register bank the pupd_reg exists within */
-	s16 tri_reg; 	/* offset into the TRISTATE_REG_* register bank */
-	s16 mux_reg;	/* offset into the PIN_MUX_CTL_* register bank */
-	s16 pupd_reg;	/* offset into the PULL_UPDOWN_REG_* register bank */
-	s8 tri_bit; 	/* offset into the TRISTATE_REG_* register bit */
-	s8 mux_bit;	/* offset into the PIN_MUX_CTL_* register bit */
-	s8 pupd_bit;	/* offset into the PULL_UPDOWN_REG_* register bit */
-	s8 lock_bit;	/* offset of the LOCK bit into mux register bit */
-	s8 od_bit;	/* offset of the OD bit into mux register bit */
-	s8 ioreset_bit;	/* offset of the IO_RESET bit into mux register bit */
-};
-
-typedef void (*pinmux_init) (const struct tegra_pingroup_desc **pg,
-	int *pg_max, const struct tegra_drive_pingroup_desc **pgdrive,
-	int *pgdrive_max);
-
-void tegra20_pinmux_init(const struct tegra_pingroup_desc **pg, int *pg_max,
-	const struct tegra_drive_pingroup_desc **pgdrive, int *pgdrive_max);
-
-void tegra30_pinmux_init(const struct tegra_pingroup_desc **pg, int *pg_max,
-	const struct tegra_drive_pingroup_desc **pgdrive, int *pgdrive_max);
-
-int tegra_pinmux_set_tristate(int pg, enum tegra_tristate tristate);
-int tegra_pinmux_set_pullupdown(int pg, enum tegra_pullupdown pupd);
-
-void tegra_pinmux_config_table(const struct tegra_pingroup_config *config,
-	int len);
-
-void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
-	int len);
-void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
-	int len);
-void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
-	int len);
-void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
-	int len, enum tegra_tristate tristate);
-void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
-	int len, enum tegra_pullupdown pupd);
-#endif
diff --git a/arch/arm/mach-tegra/pinmux-tegra20-tables.c b/arch/arm/mach-tegra/pinmux-tegra20-tables.c
deleted file mode 100644
index 734add1..0000000
--- a/arch/arm/mach-tegra/pinmux-tegra20-tables.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/pinmux-tegra20-tables.c
- *
- * Common pinmux configurations for Tegra20 SoCs
- *
- * Copyright (C) 2010 NVIDIA Corporation
- *
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/string.h>
-
-#include <mach/iomap.h>
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-#include <mach/suspend.h>
-
-#define TRISTATE_REG_A		0x14
-#define PIN_MUX_CTL_REG_A	0x80
-#define PULLUPDOWN_REG_A	0xa0
-#define PINGROUP_REG_A		0x868
-
-#define DRIVE_PINGROUP(pg_name, r)				\
-	[TEGRA_DRIVE_PINGROUP_ ## pg_name] = {			\
-		.name = #pg_name,				\
-		.reg_bank = 3,					\
-		.reg = ((r) - PINGROUP_REG_A)			\
-	}
-
-static const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE_PINGROUP] = {
-	DRIVE_PINGROUP(AO1,		0x868),
-	DRIVE_PINGROUP(AO2,		0x86c),
-	DRIVE_PINGROUP(AT1,		0x870),
-	DRIVE_PINGROUP(AT2,		0x874),
-	DRIVE_PINGROUP(CDEV1,		0x878),
-	DRIVE_PINGROUP(CDEV2,		0x87c),
-	DRIVE_PINGROUP(CSUS,		0x880),
-	DRIVE_PINGROUP(DAP1,		0x884),
-	DRIVE_PINGROUP(DAP2,		0x888),
-	DRIVE_PINGROUP(DAP3,		0x88c),
-	DRIVE_PINGROUP(DAP4,		0x890),
-	DRIVE_PINGROUP(DBG,		0x894),
-	DRIVE_PINGROUP(LCD1,		0x898),
-	DRIVE_PINGROUP(LCD2,		0x89c),
-	DRIVE_PINGROUP(SDMMC2,		0x8a0),
-	DRIVE_PINGROUP(SDMMC3,		0x8a4),
-	DRIVE_PINGROUP(SPI,		0x8a8),
-	DRIVE_PINGROUP(UAA,		0x8ac),
-	DRIVE_PINGROUP(UAB,		0x8b0),
-	DRIVE_PINGROUP(UART2,		0x8b4),
-	DRIVE_PINGROUP(UART3,		0x8b8),
-	DRIVE_PINGROUP(VI1,		0x8bc),
-	DRIVE_PINGROUP(VI2,		0x8c0),
-	DRIVE_PINGROUP(XM2A,		0x8c4),
-	DRIVE_PINGROUP(XM2C,		0x8c8),
-	DRIVE_PINGROUP(XM2D,		0x8cc),
-	DRIVE_PINGROUP(XM2CLK,		0x8d0),
-	DRIVE_PINGROUP(MEMCOMP,		0x8d4),
-	DRIVE_PINGROUP(SDIO1,		0x8e0),
-	DRIVE_PINGROUP(CRT,		0x8ec),
-	DRIVE_PINGROUP(DDC,		0x8f0),
-	DRIVE_PINGROUP(GMA,		0x8f4),
-	DRIVE_PINGROUP(GMB,		0x8f8),
-	DRIVE_PINGROUP(GMC,		0x8fc),
-	DRIVE_PINGROUP(GMD,		0x900),
-	DRIVE_PINGROUP(GME,		0x904),
-	DRIVE_PINGROUP(OWR,		0x908),
-	DRIVE_PINGROUP(UAD,		0x90c),
-};
-
-#define PINGROUP(pg_name, vdd, f0, f1, f2, f3, f_safe,		\
-		 tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b)	\
-	[TEGRA_PINGROUP_ ## pg_name] = {			\
-		.name = #pg_name,				\
-		.vddio = TEGRA_VDDIO_ ## vdd,			\
-		.funcs = {					\
-			TEGRA_MUX_ ## f0,			\
-			TEGRA_MUX_ ## f1,			\
-			TEGRA_MUX_ ## f2,			\
-			TEGRA_MUX_ ## f3,			\
-		},						\
-		.func_safe = TEGRA_MUX_ ## f_safe,		\
-		.tri_bank = 0,					\
-		.tri_reg = ((tri_r) - TRISTATE_REG_A),		\
-		.tri_bit = tri_b,				\
-		.mux_bank = 1,					\
-		.mux_reg = ((mux_r) - PIN_MUX_CTL_REG_A),	\
-		.mux_bit = mux_b,				\
-		.pupd_bank = 2,				\
-		.pupd_reg = ((pupd_r) - PULLUPDOWN_REG_A),	\
-		.pupd_bit = pupd_b,				\
-		.lock_bit = -1,					\
-		.od_bit = -1,					\
-		.ioreset_bit = -1,				\
-		.io_default = -1,				\
-	}
-
-static const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP] = {
-	PINGROUP(ATA,   NAND,  IDE,       NAND,      GMI,       RSVD,          IDE,       0x14, 0,  0x80, 24, 0xA0, 0),
-	PINGROUP(ATB,   NAND,  IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 1,  0x80, 16, 0xA0, 2),
-	PINGROUP(ATC,   NAND,  IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 2,  0x80, 22, 0xA0, 4),
-	PINGROUP(ATD,   NAND,  IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 3,  0x80, 20, 0xA0, 6),
-	PINGROUP(ATE,   NAND,  IDE,       NAND,      GMI,       RSVD,          IDE,       0x18, 25, 0x80, 12, 0xA0, 8),
-	PINGROUP(CDEV1, AUDIO, OSC,       PLLA_OUT,  PLLM_OUT1, AUDIO_SYNC,    OSC,       0x14, 4,  0x88, 2,  0xA8, 0),
-	PINGROUP(CDEV2, AUDIO, OSC,       AHB_CLK,   APB_CLK,   PLLP_OUT4,     OSC,       0x14, 5,  0x88, 4,  0xA8, 2),
-	PINGROUP(CRTP,  LCD,   CRT,       RSVD,      RSVD,      RSVD,          RSVD,      0x20, 14, 0x98, 20, 0xA4, 24),
-	PINGROUP(CSUS,  VI,    PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, PLLC_OUT1, 0x14, 6,  0x88, 6,  0xAC, 24),
-	PINGROUP(DAP1,  AUDIO, DAP1,      RSVD,      GMI,       SDIO2,         DAP1,      0x14, 7,  0x88, 20, 0xA0, 10),
-	PINGROUP(DAP2,  AUDIO, DAP2,      TWC,       RSVD,      GMI,           DAP2,      0x14, 8,  0x88, 22, 0xA0, 12),
-	PINGROUP(DAP3,  BB,    DAP3,      RSVD,      RSVD,      RSVD,          DAP3,      0x14, 9,  0x88, 24, 0xA0, 14),
-	PINGROUP(DAP4,  UART,  DAP4,      RSVD,      GMI,       RSVD,          DAP4,      0x14, 10, 0x88, 26, 0xA0, 16),
-	PINGROUP(DDC,   LCD,   I2C2,      RSVD,      RSVD,      RSVD,          RSVD4,     0x18, 31, 0x88, 0,  0xB0, 28),
-	PINGROUP(DTA,   VI,    RSVD,      SDIO2,     VI,        RSVD,          RSVD4,     0x14, 11, 0x84, 20, 0xA0, 18),
-	PINGROUP(DTB,   VI,    RSVD,      RSVD,      VI,        SPI1,          RSVD1,     0x14, 12, 0x84, 22, 0xA0, 20),
-	PINGROUP(DTC,   VI,    RSVD,      RSVD,      VI,        RSVD,          RSVD1,     0x14, 13, 0x84, 26, 0xA0, 22),
-	PINGROUP(DTD,   VI,    RSVD,      SDIO2,     VI,        RSVD,          RSVD1,     0x14, 14, 0x84, 28, 0xA0, 24),
-	PINGROUP(DTE,   VI,    RSVD,      RSVD,      VI,        SPI1,          RSVD1,     0x14, 15, 0x84, 30, 0xA0, 26),
-	PINGROUP(DTF,   VI,    I2C3,      RSVD,      VI,        RSVD,          RSVD4,     0x20, 12, 0x98, 30, 0xA0, 28),
-	PINGROUP(GMA,   NAND,  UARTE,     SPI3,      GMI,       SDIO4,         SPI3,      0x14, 28, 0x84, 0,  0xB0, 20),
-	PINGROUP(GMB,   NAND,  IDE,       NAND,      GMI,       GMI_INT,       GMI,       0x18, 29, 0x88, 28, 0xB0, 22),
-	PINGROUP(GMC,   NAND,  UARTD,     SPI4,      GMI,       SFLASH,        SPI4,      0x14, 29, 0x84, 2,  0xB0, 24),
-	PINGROUP(GMD,   NAND,  RSVD,      NAND,      GMI,       SFLASH,        GMI,       0x18, 30, 0x88, 30, 0xB0, 26),
-	PINGROUP(GME,   NAND,  RSVD,      DAP5,      GMI,       SDIO4,         GMI,       0x18, 0,  0x8C, 0,  0xA8, 24),
-	PINGROUP(GPU,   UART,  PWM,       UARTA,     GMI,       RSVD,          RSVD4,     0x14, 16, 0x8C, 4,  0xA4, 20),
-	PINGROUP(GPU7,  SYS,   RTCK,      RSVD,      RSVD,      RSVD,          RTCK,      0x20, 11, 0x98, 28, 0xA4, 6),
-	PINGROUP(GPV,   SD,    PCIE,      RSVD,      RSVD,      RSVD,          PCIE,      0x14, 17, 0x8C, 2,  0xA0, 30),
-	PINGROUP(HDINT, LCD,   HDMI,      RSVD,      RSVD,      RSVD,          HDMI,      0x1C, 23, 0x84, 4,  0xAC, 22),
-	PINGROUP(I2CP,  SYS,   I2C,       RSVD,      RSVD,      RSVD,          RSVD4,     0x14, 18, 0x88, 8,  0xA4, 2),
-	PINGROUP(IRRX,  UART,  UARTA,     UARTB,     GMI,       SPI4,          UARTB,     0x14, 20, 0x88, 18, 0xA8, 22),
-	PINGROUP(IRTX,  UART,  UARTA,     UARTB,     GMI,       SPI4,          UARTB,     0x14, 19, 0x88, 16, 0xA8, 20),
-	PINGROUP(KBCA,  SYS,   KBC,       NAND,      SDIO2,     EMC_TEST0_DLL, KBC,       0x14, 22, 0x88, 10, 0xA4, 8),
-	PINGROUP(KBCB,  SYS,   KBC,       NAND,      SDIO2,     MIO,           KBC,       0x14, 21, 0x88, 12, 0xA4, 10),
-	PINGROUP(KBCC,  SYS,   KBC,       NAND,      TRACE,     EMC_TEST1_DLL, KBC,       0x18, 26, 0x88, 14, 0xA4, 12),
-	PINGROUP(KBCD,  SYS,   KBC,       NAND,      SDIO2,     MIO,           KBC,       0x20, 10, 0x98, 26, 0xA4, 14),
-	PINGROUP(KBCE,  SYS,   KBC,       NAND,      OWR,       RSVD,          KBC,       0x14, 26, 0x80, 28, 0xB0, 2),
-	PINGROUP(KBCF,  SYS,   KBC,       NAND,      TRACE,     MIO,           KBC,       0x14, 27, 0x80, 26, 0xB0, 0),
-	PINGROUP(LCSN,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          RSVD4,     0x1C, 31, 0x90, 12, 0xAC, 20),
-	PINGROUP(LD0,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 0,  0x94, 0,  0xAC, 12),
-	PINGROUP(LD1,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 1,  0x94, 2,  0xAC, 12),
-	PINGROUP(LD10,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 10, 0x94, 20, 0xAC, 12),
-	PINGROUP(LD11,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 11, 0x94, 22, 0xAC, 12),
-	PINGROUP(LD12,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 12, 0x94, 24, 0xAC, 12),
-	PINGROUP(LD13,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 13, 0x94, 26, 0xAC, 12),
-	PINGROUP(LD14,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 14, 0x94, 28, 0xAC, 12),
-	PINGROUP(LD15,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 15, 0x94, 30, 0xAC, 12),
-	PINGROUP(LD16,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 16, 0x98, 0,  0xAC, 12),
-	PINGROUP(LD17,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 17, 0x98, 2,  0xAC, 12),
-	PINGROUP(LD2,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 2,  0x94, 4,  0xAC, 12),
-	PINGROUP(LD3,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 3,  0x94, 6,  0xAC, 12),
-	PINGROUP(LD4,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 4,  0x94, 8,  0xAC, 12),
-	PINGROUP(LD5,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 5,  0x94, 10, 0xAC, 12),
-	PINGROUP(LD6,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 6,  0x94, 12, 0xAC, 12),
-	PINGROUP(LD7,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 7,  0x94, 14, 0xAC, 12),
-	PINGROUP(LD8,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 8,  0x94, 16, 0xAC, 12),
-	PINGROUP(LD9,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 9,  0x94, 18, 0xAC, 12),
-	PINGROUP(LDC,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 30, 0x90, 14, 0xAC, 20),
-	PINGROUP(LDI,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x20, 6,  0x98, 16, 0xAC, 18),
-	PINGROUP(LHP0,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 18, 0x98, 10, 0xAC, 16),
-	PINGROUP(LHP1,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 19, 0x98, 4,  0xAC, 14),
-	PINGROUP(LHP2,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 20, 0x98, 6,  0xAC, 14),
-	PINGROUP(LHS,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x20, 7,  0x90, 22, 0xAC, 22),
-	PINGROUP(LM0,   LCD,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          RSVD4,     0x1C, 24, 0x90, 26, 0xAC, 22),
-	PINGROUP(LM1,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      CRT,           RSVD3,     0x1C, 25, 0x90, 28, 0xAC, 22),
-	PINGROUP(LPP,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x20, 8,  0x98, 14, 0xAC, 18),
-	PINGROUP(LPW0,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 3,  0x90, 0,  0xAC, 20),
-	PINGROUP(LPW1,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x20, 4,  0x90, 2,  0xAC, 20),
-	PINGROUP(LPW2,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 5,  0x90, 4,  0xAC, 20),
-	PINGROUP(LSC0,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 27, 0x90, 18, 0xAC, 22),
-	PINGROUP(LSC1,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x1C, 28, 0x90, 20, 0xAC, 20),
-	PINGROUP(LSCK,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x1C, 29, 0x90, 16, 0xAC, 20),
-	PINGROUP(LSDA,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 1,  0x90, 8,  0xAC, 20),
-	PINGROUP(LSDI,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          DISPLAYA,  0x20, 2,  0x90, 6,  0xAC, 20),
-	PINGROUP(LSPI,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       HDMI,          DISPLAYA,  0x20, 0,  0x90, 10, 0xAC, 22),
-	PINGROUP(LVP0,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 21, 0x90, 30, 0xAC, 22),
-	PINGROUP(LVP1,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 22, 0x98, 8,  0xAC, 16),
-	PINGROUP(LVS,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 26, 0x90, 24, 0xAC, 22),
-	PINGROUP(OWC,   SYS,   OWR,       RSVD,      RSVD,      RSVD,          OWR,       0x14, 31, 0x84, 8,  0xB0, 30),
-	PINGROUP(PMC,   SYS,   PWR_ON,    PWR_INTR,  RSVD,      RSVD,          PWR_ON,    0x14, 23, 0x98, 18, -1,   -1),
-	PINGROUP(PTA,   NAND,  I2C2,      HDMI,      GMI,       RSVD,          RSVD4,     0x14, 24, 0x98, 22, 0xA4, 4),
-	PINGROUP(RM,    UART,  I2C,       RSVD,      RSVD,      RSVD,          RSVD4,     0x14, 25, 0x80, 14, 0xA4, 0),
-	PINGROUP(SDB,   SD,    UARTA,     PWM,       SDIO3,     SPI2,          PWM,       0x20, 15, 0x8C, 10, -1,   -1),
-	PINGROUP(SDC,   SD,    PWM,       TWC,       SDIO3,     SPI3,          TWC,       0x18, 1,  0x8C, 12, 0xAC, 28),
-	PINGROUP(SDD,   SD,    UARTA,     PWM,       SDIO3,     SPI3,          PWM,       0x18, 2,  0x8C, 14, 0xAC, 30),
-	PINGROUP(SDIO1, BB,    SDIO1,     RSVD,      UARTE,     UARTA,         RSVD2,     0x14, 30, 0x80, 30, 0xB0, 18),
-	PINGROUP(SLXA,  SD,    PCIE,      SPI4,      SDIO3,     SPI2,          PCIE,      0x18, 3,  0x84, 6,  0xA4, 22),
-	PINGROUP(SLXC,  SD,    SPDIF,     SPI4,      SDIO3,     SPI2,          SPI4,      0x18, 5,  0x84, 10, 0xA4, 26),
-	PINGROUP(SLXD,  SD,    SPDIF,     SPI4,      SDIO3,     SPI2,          SPI4,      0x18, 6,  0x84, 12, 0xA4, 28),
-	PINGROUP(SLXK,  SD,    PCIE,      SPI4,      SDIO3,     SPI2,          PCIE,      0x18, 7,  0x84, 14, 0xA4, 30),
-	PINGROUP(SPDI,  AUDIO, SPDIF,     RSVD,      I2C,       SDIO2,         RSVD2,     0x18, 8,  0x8C, 8,  0xA4, 16),
-	PINGROUP(SPDO,  AUDIO, SPDIF,     RSVD,      I2C,       SDIO2,         RSVD2,     0x18, 9,  0x8C, 6,  0xA4, 18),
-	PINGROUP(SPIA,  AUDIO, SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 10, 0x8C, 30, 0xA8, 4),
-	PINGROUP(SPIB,  AUDIO, SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 11, 0x8C, 28, 0xA8, 6),
-	PINGROUP(SPIC,  AUDIO, SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 12, 0x8C, 26, 0xA8, 8),
-	PINGROUP(SPID,  AUDIO, SPI2,      SPI1,      SPI2_ALT,  GMI,           GMI,       0x18, 13, 0x8C, 24, 0xA8, 10),
-	PINGROUP(SPIE,  AUDIO, SPI2,      SPI1,      SPI2_ALT,  GMI,           GMI,       0x18, 14, 0x8C, 22, 0xA8, 12),
-	PINGROUP(SPIF,  AUDIO, SPI3,      SPI1,      SPI2,      RSVD,          RSVD4,     0x18, 15, 0x8C, 20, 0xA8, 14),
-	PINGROUP(SPIG,  AUDIO, SPI3,      SPI2,      SPI2_ALT,  I2C,           SPI2_ALT,  0x18, 16, 0x8C, 18, 0xA8, 16),
-	PINGROUP(SPIH,  AUDIO, SPI3,      SPI2,      SPI2_ALT,  I2C,           SPI2_ALT,  0x18, 17, 0x8C, 16, 0xA8, 18),
-	PINGROUP(UAA,   BB,    SPI3,      MIPI_HS,   UARTA,     ULPI,          MIPI_HS,   0x18, 18, 0x80, 0,  0xAC, 0),
-	PINGROUP(UAB,   BB,    SPI2,      MIPI_HS,   UARTA,     ULPI,          MIPI_HS,   0x18, 19, 0x80, 2,  0xAC, 2),
-	PINGROUP(UAC,   BB,    OWR,       RSVD,      RSVD,      RSVD,          RSVD4,     0x18, 20, 0x80, 4,  0xAC, 4),
-	PINGROUP(UAD,   UART,  IRDA,      SPDIF,     UARTA,     SPI4,          SPDIF,     0x18, 21, 0x80, 6,  0xAC, 6),
-	PINGROUP(UCA,   UART,  UARTC,     RSVD,      GMI,       RSVD,          RSVD4,     0x18, 22, 0x84, 16, 0xAC, 8),
-	PINGROUP(UCB,   UART,  UARTC,     PWM,       GMI,       RSVD,          RSVD4,     0x18, 23, 0x84, 18, 0xAC, 10),
-	PINGROUP(UDA,   BB,    SPI1,      RSVD,      UARTD,     ULPI,          RSVD2,     0x20, 13, 0x80, 8,  0xB0, 16),
-	/* these pin groups only have pullup and pull down control */
-	PINGROUP(CK32,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 14),
-	PINGROUP(DDRC,  DDR,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xAC, 26),
-	PINGROUP(PMCA,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 4),
-	PINGROUP(PMCB,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 6),
-	PINGROUP(PMCC,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 8),
-	PINGROUP(PMCD,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 10),
-	PINGROUP(PMCE,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 12),
-	PINGROUP(XM2C,  DDR,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xA8, 30),
-	PINGROUP(XM2D,  DDR,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xA8, 28),
-};
-
-void __devinit tegra20_pinmux_init(const struct tegra_pingroup_desc **pg,
-		int *pg_max, const struct tegra_drive_pingroup_desc **pgdrive,
-		int *pgdrive_max)
-{
-	*pg = tegra_soc_pingroups;
-	*pg_max = TEGRA_MAX_PINGROUP;
-	*pgdrive = tegra_soc_drive_pingroups;
-	*pgdrive_max = TEGRA_MAX_DRIVE_PINGROUP;
-}
-
diff --git a/arch/arm/mach-tegra/pinmux-tegra30-tables.c b/arch/arm/mach-tegra/pinmux-tegra30-tables.c
deleted file mode 100644
index 14fc0e4..0000000
--- a/arch/arm/mach-tegra/pinmux-tegra30-tables.c
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/pinmux-tegra30-tables.c
- *
- * Common pinmux configurations for Tegra30 SoCs
- *
- * Copyright (C) 2010,2011 NVIDIA Corporation
- *
- * 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.
- *
- * 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/string.h>
-
-#include <mach/iomap.h>
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra30.h>
-#include <mach/suspend.h>
-
-#define PINGROUP_REG_A	0x868
-#define MUXCTL_REG_A	0x3000
-
-#define DRIVE_PINGROUP(pg_name, r)		\
-	[TEGRA_DRIVE_PINGROUP_ ## pg_name] = {	\
-		.name = #pg_name,		\
-		.reg_bank = 0,			\
-		.reg = ((r) - PINGROUP_REG_A)	\
-	}
-
-static const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE_PINGROUP] = {
-	DRIVE_PINGROUP(AO1,		0x868),
-	DRIVE_PINGROUP(AO2,		0x86c),
-	DRIVE_PINGROUP(AT1,		0x870),
-	DRIVE_PINGROUP(AT2,		0x874),
-	DRIVE_PINGROUP(AT3,		0x878),
-	DRIVE_PINGROUP(AT4,		0x87c),
-	DRIVE_PINGROUP(AT5,		0x880),
-	DRIVE_PINGROUP(CDEV1,		0x884),
-	DRIVE_PINGROUP(CDEV2,		0x888),
-	DRIVE_PINGROUP(CSUS,		0x88c),
-	DRIVE_PINGROUP(DAP1,		0x890),
-	DRIVE_PINGROUP(DAP2,		0x894),
-	DRIVE_PINGROUP(DAP3,		0x898),
-	DRIVE_PINGROUP(DAP4,		0x89c),
-	DRIVE_PINGROUP(DBG,		0x8a0),
-	DRIVE_PINGROUP(LCD1,		0x8a4),
-	DRIVE_PINGROUP(LCD2,		0x8a8),
-	DRIVE_PINGROUP(SDIO2,		0x8ac),
-	DRIVE_PINGROUP(SDIO3,		0x8b0),
-	DRIVE_PINGROUP(SPI,		0x8b4),
-	DRIVE_PINGROUP(UAA,		0x8b8),
-	DRIVE_PINGROUP(UAB,		0x8bc),
-	DRIVE_PINGROUP(UART2,		0x8c0),
-	DRIVE_PINGROUP(UART3,		0x8c4),
-	DRIVE_PINGROUP(VI1,		0x8c8),
-	DRIVE_PINGROUP(SDIO1,		0x8ec),
-	DRIVE_PINGROUP(CRT,		0x8f8),
-	DRIVE_PINGROUP(DDC,		0x8fc),
-	DRIVE_PINGROUP(GMA,		0x900),
-	DRIVE_PINGROUP(GMB,		0x904),
-	DRIVE_PINGROUP(GMC,		0x908),
-	DRIVE_PINGROUP(GMD,		0x90c),
-	DRIVE_PINGROUP(GME,		0x910),
-	DRIVE_PINGROUP(GMF,		0x914),
-	DRIVE_PINGROUP(GMG,		0x918),
-	DRIVE_PINGROUP(GMH,		0x91c),
-	DRIVE_PINGROUP(OWR,		0x920),
-	DRIVE_PINGROUP(UAD,		0x924),
-	DRIVE_PINGROUP(GPV,		0x928),
-	DRIVE_PINGROUP(DEV3,		0x92c),
-	DRIVE_PINGROUP(CEC,		0x938),
-};
-
-#define PINGROUP(pg_name, vdd, f0, f1, f2, f3, fs, iod, reg)	\
-	[TEGRA_PINGROUP_ ## pg_name] = {			\
-		.name = #pg_name,				\
-		.vddio = TEGRA_VDDIO_ ## vdd,			\
-		.funcs = {					\
-			TEGRA_MUX_ ## f0,			\
-			TEGRA_MUX_ ## f1,			\
-			TEGRA_MUX_ ## f2,			\
-			TEGRA_MUX_ ## f3,			\
-		},						\
-		.func_safe = TEGRA_MUX_ ## fs,			\
-		.tri_bank = 1,					\
-		.tri_reg = ((reg) - MUXCTL_REG_A),		\
-		.tri_bit = 4,					\
-		.mux_bank = 1,					\
-		.mux_reg = ((reg) - MUXCTL_REG_A),		\
-		.mux_bit = 0,					\
-		.pupd_bank = 1,					\
-		.pupd_reg = ((reg) - MUXCTL_REG_A),		\
-		.pupd_bit = 2,					\
-		.io_default = TEGRA_PIN_ ## iod,		\
-		.od_bit = 6,					\
-		.lock_bit = 7,					\
-		.ioreset_bit = 8,				\
-	}
-
-static const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP] = {
-	/*       NAME		  VDD	    f0		f1          f2          f3          fSafe       io	reg */
-	PINGROUP(ULPI_DATA0,	  BB,	    SPI3,	HSI,	    UARTA,	ULPI,	    RSVD,	INPUT,	0x3000),
-	PINGROUP(ULPI_DATA1,	  BB,	    SPI3,	HSI,	    UARTA,	ULPI,	    RSVD,	INPUT,	0x3004),
-	PINGROUP(ULPI_DATA2,	  BB,	    SPI3,	HSI,	    UARTA,	ULPI,	    RSVD,	INPUT,	0x3008),
-	PINGROUP(ULPI_DATA3,	  BB,	    SPI3,	HSI,	    UARTA,	ULPI,	    RSVD,	INPUT,	0x300c),
-	PINGROUP(ULPI_DATA4,	  BB,	    SPI2,	HSI,	    UARTA,	ULPI,	    RSVD,	INPUT,	0x3010),
-	PINGROUP(ULPI_DATA5,	  BB,	    SPI2,	HSI,	    UARTA,	ULPI,	    RSVD,	INPUT,	0x3014),
-	PINGROUP(ULPI_DATA6,	  BB,	    SPI2,	HSI,	    UARTA,	ULPI,	    RSVD,	INPUT,	0x3018),
-	PINGROUP(ULPI_DATA7,	  BB,	    SPI2,	HSI,	    UARTA,	ULPI,	    RSVD,	INPUT,	0x301c),
-	PINGROUP(ULPI_CLK,	  BB,	    SPI1,	RSVD,	    UARTD,	ULPI,	    RSVD,	INPUT,	0x3020),
-	PINGROUP(ULPI_DIR,	  BB,	    SPI1,	RSVD,	    UARTD,	ULPI,	    RSVD,	INPUT,	0x3024),
-	PINGROUP(ULPI_NXT,	  BB,	    SPI1,	RSVD,	    UARTD,	ULPI,	    RSVD,	INPUT,	0x3028),
-	PINGROUP(ULPI_STP,	  BB,	    SPI1,	RSVD,	    UARTD,	ULPI,	    RSVD,	INPUT,	0x302c),
-	PINGROUP(DAP3_FS,	  BB,	    I2S2,	RSVD1,	    DISPLAYA,	DISPLAYB,   RSVD,	INPUT,	0x3030),
-	PINGROUP(DAP3_DIN,	  BB,	    I2S2,	RSVD1,	    DISPLAYA,	DISPLAYB,   RSVD,	INPUT,	0x3034),
-	PINGROUP(DAP3_DOUT,	  BB,	    I2S2,	RSVD1,	    DISPLAYA,	DISPLAYB,   RSVD,	INPUT,	0x3038),
-	PINGROUP(DAP3_SCLK,	  BB,	    I2S2,	RSVD1,	    DISPLAYA,	DISPLAYB,   RSVD,	INPUT,	0x303c),
-	PINGROUP(GPIO_PV0,	  BB,	    RSVD,	RSVD,	    RSVD,	RSVD,	    RSVD,	INPUT,	0x3040),
-	PINGROUP(GPIO_PV1,	  BB,	    RSVD,	RSVD,	    RSVD,	RSVD,	    RSVD,	INPUT,	0x3044),
-	PINGROUP(SDMMC1_CLK,	  SDMMC1,   SDIO1,	RSVD1,	    RSVD2,	INVALID,    RSVD,	INPUT,	0x3048),
-	PINGROUP(SDMMC1_CMD,	  SDMMC1,   SDIO1,	RSVD1,	    RSVD2,	INVALID,    RSVD,	INPUT,	0x304c),
-	PINGROUP(SDMMC1_DAT3,	  SDMMC1,   SDIO1,	RSVD1,	    UARTE,	INVALID,    RSVD,	INPUT,	0x3050),
-	PINGROUP(SDMMC1_DAT2,	  SDMMC1,   SDIO1,	RSVD1,	    UARTE,	INVALID,    RSVD,	INPUT,	0x3054),
-	PINGROUP(SDMMC1_DAT1,	  SDMMC1,   SDIO1,	RSVD1,	    UARTE,	INVALID,    RSVD,	INPUT,	0x3058),
-	PINGROUP(SDMMC1_DAT0,	  SDMMC1,   SDIO1,	RSVD1,	    UARTE,	INVALID,    RSVD,	INPUT,	0x305c),
-	PINGROUP(GPIO_PV2,	  SDMMC1,   OWR,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x3060),
-	PINGROUP(GPIO_PV3,	  SDMMC1,   INVALID,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x3064),
-	PINGROUP(CLK2_OUT,	  SDMMC1,   EXTPERIPH2,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x3068),
-	PINGROUP(CLK2_REQ,	  SDMMC1,   DAP,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x306c),
-	PINGROUP(LCD_PWR1,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x3070),
-	PINGROUP(LCD_PWR2,	  LCD,	    DISPLAYA,	DISPLAYB,   SPI5,	INVALID,    RSVD,	OUTPUT,	0x3074),
-	PINGROUP(LCD_SDIN,	  LCD,	    DISPLAYA,	DISPLAYB,   SPI5,	RSVD,	    RSVD,	OUTPUT,	0x3078),
-	PINGROUP(LCD_SDOUT,	  LCD,	    DISPLAYA,	DISPLAYB,   SPI5,	INVALID,    RSVD,	OUTPUT,	0x307c),
-	PINGROUP(LCD_WR_N,	  LCD,	    DISPLAYA,	DISPLAYB,   SPI5,	INVALID,    RSVD,	OUTPUT,	0x3080),
-	PINGROUP(LCD_CS0_N,	  LCD,	    DISPLAYA,	DISPLAYB,   SPI5,	RSVD,	    RSVD,	OUTPUT,	0x3084),
-	PINGROUP(LCD_DC0,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x3088),
-	PINGROUP(LCD_SCK,	  LCD,	    DISPLAYA,	DISPLAYB,   SPI5,	INVALID,    RSVD,	OUTPUT,	0x308c),
-	PINGROUP(LCD_PWR0,	  LCD,	    DISPLAYA,	DISPLAYB,   SPI5,	INVALID,    RSVD,	OUTPUT,	0x3090),
-	PINGROUP(LCD_PCLK,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x3094),
-	PINGROUP(LCD_DE,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x3098),
-	PINGROUP(LCD_HSYNC,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x309c),
-	PINGROUP(LCD_VSYNC,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30a0),
-	PINGROUP(LCD_D0,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30a4),
-	PINGROUP(LCD_D1,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30a8),
-	PINGROUP(LCD_D2,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30ac),
-	PINGROUP(LCD_D3,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30b0),
-	PINGROUP(LCD_D4,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30b4),
-	PINGROUP(LCD_D5,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30b8),
-	PINGROUP(LCD_D6,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30bc),
-	PINGROUP(LCD_D7,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30c0),
-	PINGROUP(LCD_D8,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30c4),
-	PINGROUP(LCD_D9,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30c8),
-	PINGROUP(LCD_D10,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30cc),
-	PINGROUP(LCD_D11,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30d0),
-	PINGROUP(LCD_D12,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30d4),
-	PINGROUP(LCD_D13,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30d8),
-	PINGROUP(LCD_D14,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30dc),
-	PINGROUP(LCD_D15,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30e0),
-	PINGROUP(LCD_D16,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30e4),
-	PINGROUP(LCD_D17,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30e8),
-	PINGROUP(LCD_D18,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30ec),
-	PINGROUP(LCD_D19,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30f0),
-	PINGROUP(LCD_D20,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30f4),
-	PINGROUP(LCD_D21,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30f8),
-	PINGROUP(LCD_D22,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x30fc),
-	PINGROUP(LCD_D23,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x3100),
-	PINGROUP(LCD_CS1_N,	  LCD,	    DISPLAYA,	DISPLAYB,   SPI5,	RSVD2,	    RSVD,	OUTPUT,	0x3104),
-	PINGROUP(LCD_M1,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x3108),
-	PINGROUP(LCD_DC1,	  LCD,	    DISPLAYA,	DISPLAYB,   RSVD1,	RSVD2,	    RSVD,	OUTPUT,	0x310c),
-	PINGROUP(HDMI_INT,	  LCD,	    RSVD,	RSVD,	    RSVD,	RSVD,	    RSVD,	INPUT,	0x3110),
-	PINGROUP(DDC_SCL,	  LCD,	    I2C4,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x3114),
-	PINGROUP(DDC_SDA,	  LCD,	    I2C4,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x3118),
-	PINGROUP(CRT_HSYNC,	  LCD,	    CRT,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x311c),
-	PINGROUP(CRT_VSYNC,	  LCD,	    CRT,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x3120),
-	PINGROUP(VI_D0,		  VI,	    INVALID,	RSVD1,	    VI,		RSVD2,	    RSVD,	INPUT,	0x3124),
-	PINGROUP(VI_D1,		  VI,	    INVALID,	SDIO2,	    VI,		RSVD1,	    RSVD,	INPUT,	0x3128),
-	PINGROUP(VI_D2,		  VI,	    INVALID,	SDIO2,	    VI,		RSVD1,	    RSVD,	INPUT,	0x312c),
-	PINGROUP(VI_D3,		  VI,	    INVALID,	SDIO2,	    VI,		RSVD1,	    RSVD,	INPUT,	0x3130),
-	PINGROUP(VI_D4,		  VI,	    INVALID,	SDIO2,	    VI,		RSVD1,	    RSVD,	INPUT,	0x3134),
-	PINGROUP(VI_D5,		  VI,	    INVALID,	SDIO2,	    VI,		RSVD1,	    RSVD,	INPUT,	0x3138),
-	PINGROUP(VI_D6,		  VI,	    INVALID,	SDIO2,	    VI,		RSVD1,	    RSVD,	INPUT,	0x313c),
-	PINGROUP(VI_D7,		  VI,	    INVALID,	SDIO2,	    VI,		RSVD1,	    RSVD,	INPUT,	0x3140),
-	PINGROUP(VI_D8,		  VI,	    INVALID,	SDIO2,	    VI,		RSVD1,	    RSVD,	INPUT,	0x3144),
-	PINGROUP(VI_D9,		  VI,	    INVALID,	SDIO2,	    VI,		RSVD1,	    RSVD,	INPUT,	0x3148),
-	PINGROUP(VI_D10,	  VI,	    INVALID,	RSVD1,	    VI,		RSVD2,	    RSVD,	INPUT,	0x314c),
-	PINGROUP(VI_D11,	  VI,	    INVALID,	RSVD1,	    VI,		RSVD2,	    RSVD,	INPUT,	0x3150),
-	PINGROUP(VI_PCLK,	  VI,	    RSVD1,	SDIO2,	    VI,		RSVD2,	    RSVD,	INPUT,	0x3154),
-	PINGROUP(VI_MCLK,	  VI,	    VI,		INVALID,    INVALID,	INVALID,    RSVD,	INPUT,	0x3158),
-	PINGROUP(VI_VSYNC,	  VI,	    INVALID,	RSVD1,	    VI,		RSVD2,	    RSVD,	INPUT,	0x315c),
-	PINGROUP(VI_HSYNC,	  VI,	    INVALID,	RSVD1,	    VI,		RSVD2,	    RSVD,	INPUT,	0x3160),
-	PINGROUP(UART2_RXD,	  UART,	    IRDA,	SPDIF,	    UARTA,	SPI4,	    RSVD,	INPUT,	0x3164),
-	PINGROUP(UART2_TXD,	  UART,	    IRDA,	SPDIF,	    UARTA,	SPI4,	    RSVD,	INPUT,	0x3168),
-	PINGROUP(UART2_RTS_N,	  UART,	    UARTA,	UARTB,	    GMI,	SPI4,	    RSVD,	INPUT,	0x316c),
-	PINGROUP(UART2_CTS_N,	  UART,	    UARTA,	UARTB,	    GMI,	SPI4,	    RSVD,	INPUT,	0x3170),
-	PINGROUP(UART3_TXD,	  UART,	    UARTC,	RSVD1,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3174),
-	PINGROUP(UART3_RXD,	  UART,	    UARTC,	RSVD1,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3178),
-	PINGROUP(UART3_CTS_N,	  UART,	    UARTC,	RSVD1,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x317c),
-	PINGROUP(UART3_RTS_N,	  UART,	    UARTC,	PWM0,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3180),
-	PINGROUP(GPIO_PU0,	  UART,	    OWR,	UARTA,	    GMI,	RSVD1,	    RSVD,	INPUT,	0x3184),
-	PINGROUP(GPIO_PU1,	  UART,	    RSVD1,	UARTA,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3188),
-	PINGROUP(GPIO_PU2,	  UART,	    RSVD1,	UARTA,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x318c),
-	PINGROUP(GPIO_PU3,	  UART,	    PWM0,	UARTA,	    GMI,	RSVD1,	    RSVD,	INPUT,	0x3190),
-	PINGROUP(GPIO_PU4,	  UART,	    PWM1,	UARTA,	    GMI,	RSVD1,	    RSVD,	INPUT,	0x3194),
-	PINGROUP(GPIO_PU5,	  UART,	    PWM2,	UARTA,	    GMI,	RSVD1,	    RSVD,	INPUT,	0x3198),
-	PINGROUP(GPIO_PU6,	  UART,	    PWM3,	UARTA,	    GMI,	RSVD1,	    RSVD,	INPUT,	0x319c),
-	PINGROUP(GEN1_I2C_SDA,	  UART,	    I2C,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x31a0),
-	PINGROUP(GEN1_I2C_SCL,	  UART,	    I2C,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x31a4),
-	PINGROUP(DAP4_FS,	  UART,	    I2S3,	RSVD1,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31a8),
-	PINGROUP(DAP4_DIN,	  UART,	    I2S3,	RSVD1,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31ac),
-	PINGROUP(DAP4_DOUT,	  UART,	    I2S3,	RSVD1,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31b0),
-	PINGROUP(DAP4_SCLK,	  UART,	    I2S3,	RSVD1,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31b4),
-	PINGROUP(CLK3_OUT,	  UART,	    EXTPERIPH3,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x31b8),
-	PINGROUP(CLK3_REQ,	  UART,	    DEV3,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x31bc),
-	PINGROUP(GMI_WP_N,	  GMI,	    RSVD1,	NAND,	    GMI,	GMI_ALT,    RSVD,	INPUT,	0x31c0),
-	PINGROUP(GMI_IORDY,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31c4),
-	PINGROUP(GMI_WAIT,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31c8),
-	PINGROUP(GMI_ADV_N,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31cc),
-	PINGROUP(GMI_CLK,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31d0),
-	PINGROUP(GMI_CS0_N,	  GMI,	    RSVD1,	NAND,	    GMI,	INVALID,    RSVD,	INPUT,	0x31d4),
-	PINGROUP(GMI_CS1_N,	  GMI,	    RSVD1,	NAND,	    GMI,	DTV,	    RSVD,	INPUT,	0x31d8),
-	PINGROUP(GMI_CS2_N,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31dc),
-	PINGROUP(GMI_CS3_N,	  GMI,	    RSVD1,	NAND,	    GMI,	GMI_ALT,    RSVD,	INPUT,	0x31e0),
-	PINGROUP(GMI_CS4_N,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31e4),
-	PINGROUP(GMI_CS6_N,	  GMI,	    NAND,	NAND_ALT,   GMI,	SATA,	    RSVD,	INPUT,	0x31e8),
-	PINGROUP(GMI_CS7_N,	  GMI,	    NAND,	NAND_ALT,   GMI,	GMI_ALT,    RSVD,	INPUT,	0x31ec),
-	PINGROUP(GMI_AD0,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31f0),
-	PINGROUP(GMI_AD1,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31f4),
-	PINGROUP(GMI_AD2,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31f8),
-	PINGROUP(GMI_AD3,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x31fc),
-	PINGROUP(GMI_AD4,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3200),
-	PINGROUP(GMI_AD5,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3204),
-	PINGROUP(GMI_AD6,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3208),
-	PINGROUP(GMI_AD7,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x320c),
-	PINGROUP(GMI_AD8,	  GMI,	    PWM0,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3210),
-	PINGROUP(GMI_AD9,	  GMI,	    PWM1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3214),
-	PINGROUP(GMI_AD10,	  GMI,	    PWM2,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3218),
-	PINGROUP(GMI_AD11,	  GMI,	    PWM3,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x321c),
-	PINGROUP(GMI_AD12,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3220),
-	PINGROUP(GMI_AD13,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3224),
-	PINGROUP(GMI_AD14,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x3228),
-	PINGROUP(GMI_AD15,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD2,	    RSVD,	INPUT,	0x322c),
-	PINGROUP(GMI_A16,	  GMI,	    UARTD,	SPI4,	    GMI,	GMI_ALT,    RSVD,	INPUT,	0x3230),
-	PINGROUP(GMI_A17,	  GMI,	    UARTD,	SPI4,	    GMI,	INVALID,    RSVD,	INPUT,	0x3234),
-	PINGROUP(GMI_A18,	  GMI,	    UARTD,	SPI4,	    GMI,	INVALID,    RSVD,	INPUT,	0x3238),
-	PINGROUP(GMI_A19,	  GMI,	    UARTD,	SPI4,	    GMI,	RSVD3,	    RSVD,	INPUT,	0x323c),
-	PINGROUP(GMI_WR_N,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD3,	    RSVD,	INPUT,	0x3240),
-	PINGROUP(GMI_OE_N,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD3,	    RSVD,	INPUT,	0x3244),
-	PINGROUP(GMI_DQS,	  GMI,	    RSVD1,	NAND,	    GMI,	RSVD3,	    RSVD,	INPUT,	0x3248),
-	PINGROUP(GMI_RST_N,	  GMI,	    NAND,	NAND_ALT,   GMI,	RSVD3,	    RSVD,	INPUT,	0x324c),
-	PINGROUP(GEN2_I2C_SCL,	  GMI,	    I2C2,	INVALID,    GMI,	RSVD3,	    RSVD,	INPUT,	0x3250),
-	PINGROUP(GEN2_I2C_SDA,	  GMI,	    I2C2,	INVALID,    GMI,	RSVD3,	    RSVD,	INPUT,	0x3254),
-	PINGROUP(SDMMC4_CLK,	  SDMMC4,   INVALID,	NAND,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x3258),
-	PINGROUP(SDMMC4_CMD,	  SDMMC4,   I2C3,	NAND,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x325c),
-	PINGROUP(SDMMC4_DAT0,	  SDMMC4,   UARTE,	SPI3,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x3260),
-	PINGROUP(SDMMC4_DAT1,	  SDMMC4,   UARTE,	SPI3,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x3264),
-	PINGROUP(SDMMC4_DAT2,	  SDMMC4,   UARTE,	SPI3,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x3268),
-	PINGROUP(SDMMC4_DAT3,	  SDMMC4,   UARTE,	SPI3,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x326c),
-	PINGROUP(SDMMC4_DAT4,	  SDMMC4,   I2C3,	I2S4,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x3270),
-	PINGROUP(SDMMC4_DAT5,	  SDMMC4,   VGP3,	I2S4,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x3274),
-	PINGROUP(SDMMC4_DAT6,	  SDMMC4,   VGP4,	I2S4,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x3278),
-	PINGROUP(SDMMC4_DAT7,	  SDMMC4,   VGP5,	I2S4,	    GMI,	SDIO4,	    RSVD,	INPUT,	0x327c),
-	PINGROUP(SDMMC4_RST_N,	  SDMMC4,   VGP6,	RSVD1,	    RSVD2,	POPSDMMC4,  RSVD,	INPUT,	0x3280),
-	PINGROUP(CAM_MCLK,	  CAM,	    VI,		INVALID,    VI_ALT2,	POPSDMMC4,  RSVD,	INPUT,	0x3284),
-	PINGROUP(GPIO_PCC1,	  CAM,	    I2S4,	RSVD1,	    RSVD2,	POPSDMMC4,  RSVD,	INPUT,	0x3288),
-	PINGROUP(GPIO_PBB0,	  CAM,	    I2S4,	RSVD1,	    RSVD2,	POPSDMMC4,  RSVD,	INPUT,	0x328c),
-	PINGROUP(CAM_I2C_SCL,	  CAM,	    INVALID,	I2C3,	    RSVD2,	POPSDMMC4,  RSVD,	INPUT,	0x3290),
-	PINGROUP(CAM_I2C_SDA,	  CAM,	    INVALID,	I2C3,	    RSVD2,	POPSDMMC4,  RSVD,	INPUT,	0x3294),
-	PINGROUP(GPIO_PBB3,	  CAM,	    VGP3,	DISPLAYA,   DISPLAYB,	POPSDMMC4,  RSVD,	INPUT,	0x3298),
-	PINGROUP(GPIO_PBB4,	  CAM,	    VGP4,	DISPLAYA,   DISPLAYB,	POPSDMMC4,  RSVD,	INPUT,	0x329c),
-	PINGROUP(GPIO_PBB5,	  CAM,	    VGP5,	DISPLAYA,   DISPLAYB,	POPSDMMC4,  RSVD,	INPUT,	0x32a0),
-	PINGROUP(GPIO_PBB6,	  CAM,	    VGP6,	DISPLAYA,   DISPLAYB,	POPSDMMC4,  RSVD,	INPUT,	0x32a4),
-	PINGROUP(GPIO_PBB7,	  CAM,	    I2S4,	RSVD1,	    RSVD2,	POPSDMMC4,  RSVD,	INPUT,	0x32a8),
-	PINGROUP(GPIO_PCC2,	  CAM,	    I2S4,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x32ac),
-	PINGROUP(JTAG_RTCK,	  SYS,	    RTCK,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x32b0),
-	PINGROUP(PWR_I2C_SCL,	  SYS,	    I2CPWR,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x32b4),
-	PINGROUP(PWR_I2C_SDA,	  SYS,	    I2CPWR,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x32b8),
-	PINGROUP(KB_ROW0,	  SYS,	    KBC,	INVALID,    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x32bc),
-	PINGROUP(KB_ROW1,	  SYS,	    KBC,	INVALID,    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x32c0),
-	PINGROUP(KB_ROW2,	  SYS,	    KBC,	INVALID,    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x32c4),
-	PINGROUP(KB_ROW3,	  SYS,	    KBC,	INVALID,    RSVD2,	INVALID,    RSVD,	INPUT,	0x32c8),
-	PINGROUP(KB_ROW4,	  SYS,	    KBC,	INVALID,    TRACE,	RSVD3,	    RSVD,	INPUT,	0x32cc),
-	PINGROUP(KB_ROW5,	  SYS,	    KBC,	INVALID,    TRACE,	OWR,	    RSVD,	INPUT,	0x32d0),
-	PINGROUP(KB_ROW6,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32d4),
-	PINGROUP(KB_ROW7,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32d8),
-	PINGROUP(KB_ROW8,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32dc),
-	PINGROUP(KB_ROW9,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32e0),
-	PINGROUP(KB_ROW10,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32e4),
-	PINGROUP(KB_ROW11,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32e8),
-	PINGROUP(KB_ROW12,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32ec),
-	PINGROUP(KB_ROW13,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32f0),
-	PINGROUP(KB_ROW14,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32f4),
-	PINGROUP(KB_ROW15,	  SYS,	    KBC,	INVALID,    SDIO2,	INVALID,    RSVD,	INPUT,	0x32f8),
-	PINGROUP(KB_COL0,	  SYS,	    KBC,	INVALID,    TRACE,	INVALID,    RSVD,	INPUT,	0x32fc),
-	PINGROUP(KB_COL1,	  SYS,	    KBC,	INVALID,    TRACE,	INVALID,    RSVD,	INPUT,	0x3300),
-	PINGROUP(KB_COL2,	  SYS,	    KBC,	INVALID,    TRACE,	RSVD,	    RSVD,	INPUT,	0x3304),
-	PINGROUP(KB_COL3,	  SYS,	    KBC,	INVALID,    TRACE,	RSVD,	    RSVD,	INPUT,	0x3308),
-	PINGROUP(KB_COL4,	  SYS,	    KBC,	INVALID,    TRACE,	RSVD,	    RSVD,	INPUT,	0x330c),
-	PINGROUP(KB_COL5,	  SYS,	    KBC,	INVALID,    TRACE,	RSVD,	    RSVD,	INPUT,	0x3310),
-	PINGROUP(KB_COL6,	  SYS,	    KBC,	INVALID,    TRACE,	INVALID,    RSVD,	INPUT,	0x3314),
-	PINGROUP(KB_COL7,	  SYS,	    KBC,	INVALID,    TRACE,	INVALID,    RSVD,	INPUT,	0x3318),
-	PINGROUP(CLK_32K_OUT,	  SYS,	    BLINK,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x331c),
-	PINGROUP(SYS_CLK_REQ,	  SYS,	    SYSCLK,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x3320),
-	PINGROUP(CORE_PWR_REQ,	  SYS,	    RSVD,	RSVD,	    RSVD,	RSVD,	    RSVD,	INPUT,	0x3324),
-	PINGROUP(CPU_PWR_REQ,	  SYS,	    RSVD,	RSVD,	    RSVD,	RSVD,	    RSVD,	INPUT,	0x3328),
-	PINGROUP(PWR_INT_N,	  SYS,	    RSVD,	RSVD,	    RSVD,	RSVD,	    RSVD,	INPUT,	0x332c),
-	PINGROUP(CLK_32K_IN,	  SYS,	    RSVD,	RSVD,	    RSVD,	RSVD,	    RSVD,	INPUT,	0x3330),
-	PINGROUP(OWR,		  SYS,	    OWR,	RSVD,	    RSVD,	RSVD,	    RSVD,	INPUT,	0x3334),
-	PINGROUP(DAP1_FS,	  AUDIO,    I2S0,	HDA,	    GMI,	SDIO2,	    RSVD,	INPUT,	0x3338),
-	PINGROUP(DAP1_DIN,	  AUDIO,    I2S0,	HDA,	    GMI,	SDIO2,	    RSVD,	INPUT,	0x333c),
-	PINGROUP(DAP1_DOUT,	  AUDIO,    I2S0,	HDA,	    GMI,	SDIO2,	    RSVD,	INPUT,	0x3340),
-	PINGROUP(DAP1_SCLK,	  AUDIO,    I2S0,	HDA,	    GMI,	SDIO2,	    RSVD,	INPUT,	0x3344),
-	PINGROUP(CLK1_REQ,	  AUDIO,    DAP,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x3348),
-	PINGROUP(CLK1_OUT,	  AUDIO,    EXTPERIPH1,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x334c),
-	PINGROUP(SPDIF_IN,	  AUDIO,    SPDIF,	HDA,	    INVALID,	DAPSDMMC2,  RSVD,	INPUT,	0x3350),
-	PINGROUP(SPDIF_OUT,	  AUDIO,    SPDIF,	RSVD1,	    INVALID,	DAPSDMMC2,  RSVD,	INPUT,	0x3354),
-	PINGROUP(DAP2_FS,	  AUDIO,    I2S1,	HDA,	    RSVD2,	GMI,	    RSVD,	INPUT,	0x3358),
-	PINGROUP(DAP2_DIN,	  AUDIO,    I2S1,	HDA,	    RSVD2,	GMI,	    RSVD,	INPUT,	0x335c),
-	PINGROUP(DAP2_DOUT,	  AUDIO,    I2S1,	HDA,	    RSVD2,	GMI,	    RSVD,	INPUT,	0x3360),
-	PINGROUP(DAP2_SCLK,	  AUDIO,    I2S1,	HDA,	    RSVD2,	GMI,	    RSVD,	INPUT,	0x3364),
-	PINGROUP(SPI2_MOSI,	  AUDIO,    SPI6,	SPI2,	    INVALID,	GMI,	    RSVD,	INPUT,	0x3368),
-	PINGROUP(SPI2_MISO,	  AUDIO,    SPI6,	SPI2,	    INVALID,	GMI,	    RSVD,	INPUT,	0x336c),
-	PINGROUP(SPI2_CS0_N,	  AUDIO,    SPI6,	SPI2,	    INVALID,	GMI,	    RSVD,	INPUT,	0x3370),
-	PINGROUP(SPI2_SCK,	  AUDIO,    SPI6,	SPI2,	    INVALID,	GMI,	    RSVD,	INPUT,	0x3374),
-	PINGROUP(SPI1_MOSI,	  AUDIO,    SPI2,	SPI1,	    INVALID,	GMI,	    RSVD,	INPUT,	0x3378),
-	PINGROUP(SPI1_SCK,	  AUDIO,    SPI2,	SPI1,	    INVALID,	GMI,	    RSVD,	INPUT,	0x337c),
-	PINGROUP(SPI1_CS0_N,	  AUDIO,    SPI2,	SPI1,	    INVALID,	GMI,	    RSVD,	INPUT,	0x3380),
-	PINGROUP(SPI1_MISO,	  AUDIO,    INVALID,	SPI1,	    INVALID,	RSVD3,	    RSVD,	INPUT,	0x3384),
-	PINGROUP(SPI2_CS1_N,	  AUDIO,    INVALID,	SPI2,	    INVALID,	INVALID,    RSVD,	INPUT,	0x3388),
-	PINGROUP(SPI2_CS2_N,	  AUDIO,    INVALID,	SPI2,	    INVALID,	INVALID,    RSVD,	INPUT,	0x338c),
-	PINGROUP(SDMMC3_CLK,	  SDMMC3,   UARTA,	PWM2,	    SDIO3,	INVALID,    RSVD,	INPUT,	0x3390),
-	PINGROUP(SDMMC3_CMD,	  SDMMC3,   UARTA,	PWM3,	    SDIO3,	INVALID,    RSVD,	INPUT,	0x3394),
-	PINGROUP(SDMMC3_DAT0,	  SDMMC3,   RSVD,	RSVD1,	    SDIO3,	INVALID,    RSVD,	INPUT,	0x3398),
-	PINGROUP(SDMMC3_DAT1,	  SDMMC3,   RSVD,	RSVD1,	    SDIO3,	INVALID,    RSVD,	INPUT,	0x339c),
-	PINGROUP(SDMMC3_DAT2,	  SDMMC3,   RSVD,	PWM1,	    SDIO3,	INVALID,    RSVD,	INPUT,	0x33a0),
-	PINGROUP(SDMMC3_DAT3,	  SDMMC3,   RSVD,	PWM0,	    SDIO3,	INVALID,    RSVD,	INPUT,	0x33a4),
-	PINGROUP(SDMMC3_DAT4,	  SDMMC3,   PWM1,	INVALID,    SDIO3,	INVALID,    RSVD,	INPUT,	0x33a8),
-	PINGROUP(SDMMC3_DAT5,	  SDMMC3,   PWM0,	INVALID,    SDIO3,	INVALID,    RSVD,	INPUT,	0x33ac),
-	PINGROUP(SDMMC3_DAT6,	  SDMMC3,   SPDIF,	INVALID,    SDIO3,	INVALID,    RSVD,	INPUT,	0x33b0),
-	PINGROUP(SDMMC3_DAT7,	  SDMMC3,   SPDIF,	INVALID,    SDIO3,	INVALID,    RSVD,	INPUT,	0x33b4),
-	PINGROUP(PEX_L0_PRSNT_N,  PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33b8),
-	PINGROUP(PEX_L0_RST_N,	  PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33bc),
-	PINGROUP(PEX_L0_CLKREQ_N, PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33c0),
-	PINGROUP(PEX_WAKE_N,	  PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33c4),
-	PINGROUP(PEX_L1_PRSNT_N,  PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33c8),
-	PINGROUP(PEX_L1_RST_N,	  PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33cc),
-	PINGROUP(PEX_L1_CLKREQ_N, PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33d0),
-	PINGROUP(PEX_L2_PRSNT_N,  PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33d4),
-	PINGROUP(PEX_L2_RST_N,	  PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33d8),
-	PINGROUP(PEX_L2_CLKREQ_N, PEXCTL,   PCIE,	HDA,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33dc),
-	PINGROUP(HDMI_CEC,	  SYS,      CEC,	RSVD1,	    RSVD2,	RSVD3,	    RSVD,	INPUT,	0x33e0),
-};
-
-void __devinit tegra30_pinmux_init(const struct tegra_pingroup_desc **pg,
-		int *pg_max, const struct tegra_drive_pingroup_desc **pgdrive,
-		int *pgdrive_max)
-{
-	*pg = tegra_soc_pingroups;
-	*pg_max = TEGRA_MAX_PINGROUP;
-	*pgdrive = tegra_soc_drive_pingroups;
-	*pgdrive_max = TEGRA_MAX_DRIVE_PINGROUP;
-}
-
diff --git a/arch/arm/mach-tegra/pinmux.c b/arch/arm/mach-tegra/pinmux.c
deleted file mode 100644
index ac35d2b..0000000
--- a/arch/arm/mach-tegra/pinmux.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/pinmux.c
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/of_device.h>
-
-#include <mach/iomap.h>
-#include <mach/pinmux.h>
-
-#define HSM_EN(reg)	(((reg) >> 2) & 0x1)
-#define SCHMT_EN(reg)	(((reg) >> 3) & 0x1)
-#define LPMD(reg)	(((reg) >> 4) & 0x3)
-#define DRVDN(reg)	(((reg) >> 12) & 0x1f)
-#define DRVUP(reg)	(((reg) >> 20) & 0x1f)
-#define SLWR(reg)	(((reg) >> 28) & 0x3)
-#define SLWF(reg)	(((reg) >> 30) & 0x3)
-
-static const struct tegra_pingroup_desc *pingroups;
-static const struct tegra_drive_pingroup_desc *drive_pingroups;
-static int pingroup_max;
-static int drive_max;
-
-static char *tegra_mux_names[TEGRA_MAX_MUX] = {
-	[TEGRA_MUX_AHB_CLK] = "AHB_CLK",
-	[TEGRA_MUX_APB_CLK] = "APB_CLK",
-	[TEGRA_MUX_AUDIO_SYNC] = "AUDIO_SYNC",
-	[TEGRA_MUX_CRT] = "CRT",
-	[TEGRA_MUX_DAP1] = "DAP1",
-	[TEGRA_MUX_DAP2] = "DAP2",
-	[TEGRA_MUX_DAP3] = "DAP3",
-	[TEGRA_MUX_DAP4] = "DAP4",
-	[TEGRA_MUX_DAP5] = "DAP5",
-	[TEGRA_MUX_DISPLAYA] = "DISPLAYA",
-	[TEGRA_MUX_DISPLAYB] = "DISPLAYB",
-	[TEGRA_MUX_EMC_TEST0_DLL] = "EMC_TEST0_DLL",
-	[TEGRA_MUX_EMC_TEST1_DLL] = "EMC_TEST1_DLL",
-	[TEGRA_MUX_GMI] = "GMI",
-	[TEGRA_MUX_GMI_INT] = "GMI_INT",
-	[TEGRA_MUX_HDMI] = "HDMI",
-	[TEGRA_MUX_I2C] = "I2C",
-	[TEGRA_MUX_I2C2] = "I2C2",
-	[TEGRA_MUX_I2C3] = "I2C3",
-	[TEGRA_MUX_IDE] = "IDE",
-	[TEGRA_MUX_IRDA] = "IRDA",
-	[TEGRA_MUX_KBC] = "KBC",
-	[TEGRA_MUX_MIO] = "MIO",
-	[TEGRA_MUX_MIPI_HS] = "MIPI_HS",
-	[TEGRA_MUX_NAND] = "NAND",
-	[TEGRA_MUX_OSC] = "OSC",
-	[TEGRA_MUX_OWR] = "OWR",
-	[TEGRA_MUX_PCIE] = "PCIE",
-	[TEGRA_MUX_PLLA_OUT] = "PLLA_OUT",
-	[TEGRA_MUX_PLLC_OUT1] = "PLLC_OUT1",
-	[TEGRA_MUX_PLLM_OUT1] = "PLLM_OUT1",
-	[TEGRA_MUX_PLLP_OUT2] = "PLLP_OUT2",
-	[TEGRA_MUX_PLLP_OUT3] = "PLLP_OUT3",
-	[TEGRA_MUX_PLLP_OUT4] = "PLLP_OUT4",
-	[TEGRA_MUX_PWM] = "PWM",
-	[TEGRA_MUX_PWR_INTR] = "PWR_INTR",
-	[TEGRA_MUX_PWR_ON] = "PWR_ON",
-	[TEGRA_MUX_RTCK] = "RTCK",
-	[TEGRA_MUX_SDIO1] = "SDIO1",
-	[TEGRA_MUX_SDIO2] = "SDIO2",
-	[TEGRA_MUX_SDIO3] = "SDIO3",
-	[TEGRA_MUX_SDIO4] = "SDIO4",
-	[TEGRA_MUX_SFLASH] = "SFLASH",
-	[TEGRA_MUX_SPDIF] = "SPDIF",
-	[TEGRA_MUX_SPI1] = "SPI1",
-	[TEGRA_MUX_SPI2] = "SPI2",
-	[TEGRA_MUX_SPI2_ALT] = "SPI2_ALT",
-	[TEGRA_MUX_SPI3] = "SPI3",
-	[TEGRA_MUX_SPI4] = "SPI4",
-	[TEGRA_MUX_TRACE] = "TRACE",
-	[TEGRA_MUX_TWC] = "TWC",
-	[TEGRA_MUX_UARTA] = "UARTA",
-	[TEGRA_MUX_UARTB] = "UARTB",
-	[TEGRA_MUX_UARTC] = "UARTC",
-	[TEGRA_MUX_UARTD] = "UARTD",
-	[TEGRA_MUX_UARTE] = "UARTE",
-	[TEGRA_MUX_ULPI] = "ULPI",
-	[TEGRA_MUX_VI] = "VI",
-	[TEGRA_MUX_VI_SENSOR_CLK] = "VI_SENSOR_CLK",
-	[TEGRA_MUX_XIO] = "XIO",
-	[TEGRA_MUX_BLINK] = "BLINK",
-	[TEGRA_MUX_CEC] = "CEC",
-	[TEGRA_MUX_CLK12] = "CLK12",
-	[TEGRA_MUX_DAP] = "DAP",
-	[TEGRA_MUX_DAPSDMMC2] = "DAPSDMMC2",
-	[TEGRA_MUX_DDR] = "DDR",
-	[TEGRA_MUX_DEV3] = "DEV3",
-	[TEGRA_MUX_DTV] = "DTV",
-	[TEGRA_MUX_VI_ALT1] = "VI_ALT1",
-	[TEGRA_MUX_VI_ALT2] = "VI_ALT2",
-	[TEGRA_MUX_VI_ALT3] = "VI_ALT3",
-	[TEGRA_MUX_EMC_DLL] = "EMC_DLL",
-	[TEGRA_MUX_EXTPERIPH1] = "EXTPERIPH1",
-	[TEGRA_MUX_EXTPERIPH2] = "EXTPERIPH2",
-	[TEGRA_MUX_EXTPERIPH3] = "EXTPERIPH3",
-	[TEGRA_MUX_GMI_ALT] = "GMI_ALT",
-	[TEGRA_MUX_HDA] = "HDA",
-	[TEGRA_MUX_HSI] = "HSI",
-	[TEGRA_MUX_I2C4] = "I2C4",
-	[TEGRA_MUX_I2C5] = "I2C5",
-	[TEGRA_MUX_I2CPWR] = "I2CPWR",
-	[TEGRA_MUX_I2S0] = "I2S0",
-	[TEGRA_MUX_I2S1] = "I2S1",
-	[TEGRA_MUX_I2S2] = "I2S2",
-	[TEGRA_MUX_I2S3] = "I2S3",
-	[TEGRA_MUX_I2S4] = "I2S4",
-	[TEGRA_MUX_NAND_ALT] = "NAND_ALT",
-	[TEGRA_MUX_POPSDIO4] = "POPSDIO4",
-	[TEGRA_MUX_POPSDMMC4] = "POPSDMMC4",
-	[TEGRA_MUX_PWM0] = "PWM0",
-	[TEGRA_MUX_PWM1] = "PWM2",
-	[TEGRA_MUX_PWM2] = "PWM2",
-	[TEGRA_MUX_PWM3] = "PWM3",
-	[TEGRA_MUX_SATA] = "SATA",
-	[TEGRA_MUX_SPI5] = "SPI5",
-	[TEGRA_MUX_SPI6] = "SPI6",
-	[TEGRA_MUX_SYSCLK] = "SYSCLK",
-	[TEGRA_MUX_VGP1] = "VGP1",
-	[TEGRA_MUX_VGP2] = "VGP2",
-	[TEGRA_MUX_VGP3] = "VGP3",
-	[TEGRA_MUX_VGP4] = "VGP4",
-	[TEGRA_MUX_VGP5] = "VGP5",
-	[TEGRA_MUX_VGP6] = "VGP6",
-	[TEGRA_MUX_SAFE] = "<safe>",
-};
-
-static const char *tegra_drive_names[TEGRA_MAX_DRIVE] = {
-	[TEGRA_DRIVE_DIV_8] = "DIV_8",
-	[TEGRA_DRIVE_DIV_4] = "DIV_4",
-	[TEGRA_DRIVE_DIV_2] = "DIV_2",
-	[TEGRA_DRIVE_DIV_1] = "DIV_1",
-};
-
-static const char *tegra_slew_names[TEGRA_MAX_SLEW] = {
-	[TEGRA_SLEW_FASTEST] = "FASTEST",
-	[TEGRA_SLEW_FAST] = "FAST",
-	[TEGRA_SLEW_SLOW] = "SLOW",
-	[TEGRA_SLEW_SLOWEST] = "SLOWEST",
-};
-
-static DEFINE_SPINLOCK(mux_lock);
-
-static const char *pingroup_name(int pg)
-{
-	if (pg < 0 || pg >=  pingroup_max)
-		return "<UNKNOWN>";
-
-	return pingroups[pg].name;
-}
-
-static const char *func_name(enum tegra_mux_func func)
-{
-	if (func == TEGRA_MUX_RSVD1)
-		return "RSVD1";
-
-	if (func == TEGRA_MUX_RSVD2)
-		return "RSVD2";
-
-	if (func == TEGRA_MUX_RSVD3)
-		return "RSVD3";
-
-	if (func == TEGRA_MUX_RSVD4)
-		return "RSVD4";
-
-	if (func == TEGRA_MUX_NONE)
-		return "NONE";
-
-	if (func < 0 || func >=  TEGRA_MAX_MUX)
-		return "<UNKNOWN>";
-
-	return tegra_mux_names[func];
-}
-
-
-static const char *tri_name(unsigned long val)
-{
-	return val ? "TRISTATE" : "NORMAL";
-}
-
-static const char *pupd_name(unsigned long val)
-{
-	switch (val) {
-	case 0:
-		return "NORMAL";
-
-	case 1:
-		return "PULL_DOWN";
-
-	case 2:
-		return "PULL_UP";
-
-	default:
-		return "RSVD";
-	}
-}
-
-static int nbanks;
-static void __iomem **regs;
-
-static inline u32 pg_readl(u32 bank, u32 reg)
-{
-	return readl(regs[bank] + reg);
-}
-
-static inline void pg_writel(u32 val, u32 bank, u32 reg)
-{
-	writel(val, regs[bank] + reg);
-}
-
-static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config)
-{
-	int mux = -1;
-	int i;
-	unsigned long reg;
-	unsigned long flags;
-	int pg = config->pingroup;
-	enum tegra_mux_func func = config->func;
-
-	if (pg < 0 || pg >=  pingroup_max)
-		return -ERANGE;
-
-	if (pingroups[pg].mux_reg < 0)
-		return -EINVAL;
-
-	if (func < 0)
-		return -ERANGE;
-
-	if (func == TEGRA_MUX_SAFE)
-		func = pingroups[pg].func_safe;
-
-	if (func & TEGRA_MUX_RSVD) {
-		mux = func & 0x3;
-	} else {
-		for (i = 0; i < 4; i++) {
-			if (pingroups[pg].funcs[i] == func) {
-				mux = i;
-				break;
-			}
-		}
-	}
-
-	if (mux < 0)
-		return -EINVAL;
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(pingroups[pg].mux_bank, pingroups[pg].mux_reg);
-	reg &= ~(0x3 << pingroups[pg].mux_bit);
-	reg |= mux << pingroups[pg].mux_bit;
-	pg_writel(reg, pingroups[pg].mux_bank, pingroups[pg].mux_reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-int tegra_pinmux_set_tristate(int pg, enum tegra_tristate tristate)
-{
-	unsigned long reg;
-	unsigned long flags;
-
-	if (pg < 0 || pg >=  pingroup_max)
-		return -ERANGE;
-
-	if (pingroups[pg].tri_reg < 0)
-		return -EINVAL;
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(pingroups[pg].tri_bank, pingroups[pg].tri_reg);
-	reg &= ~(0x1 << pingroups[pg].tri_bit);
-	if (tristate)
-		reg |= 1 << pingroups[pg].tri_bit;
-	pg_writel(reg, pingroups[pg].tri_bank, pingroups[pg].tri_reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-int tegra_pinmux_set_pullupdown(int pg, enum tegra_pullupdown pupd)
-{
-	unsigned long reg;
-	unsigned long flags;
-
-	if (pg < 0 || pg >=  pingroup_max)
-		return -ERANGE;
-
-	if (pingroups[pg].pupd_reg < 0)
-		return -EINVAL;
-
-	if (pupd != TEGRA_PUPD_NORMAL &&
-	    pupd != TEGRA_PUPD_PULL_DOWN &&
-	    pupd != TEGRA_PUPD_PULL_UP)
-		return -EINVAL;
-
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(pingroups[pg].pupd_bank, pingroups[pg].pupd_reg);
-	reg &= ~(0x3 << pingroups[pg].pupd_bit);
-	reg |= pupd << pingroups[pg].pupd_bit;
-	pg_writel(reg, pingroups[pg].pupd_bank, pingroups[pg].pupd_reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-static void tegra_pinmux_config_pingroup(const struct tegra_pingroup_config *config)
-{
-	int pingroup = config->pingroup;
-	enum tegra_mux_func func     = config->func;
-	enum tegra_pullupdown pupd   = config->pupd;
-	enum tegra_tristate tristate = config->tristate;
-	int err;
-
-	if (pingroups[pingroup].mux_reg >= 0) {
-		err = tegra_pinmux_set_func(config);
-		if (err < 0)
-			pr_err("pinmux: can't set pingroup %s func to %s: %d\n",
-			       pingroup_name(pingroup), func_name(func), err);
-	}
-
-	if (pingroups[pingroup].pupd_reg >= 0) {
-		err = tegra_pinmux_set_pullupdown(pingroup, pupd);
-		if (err < 0)
-			pr_err("pinmux: can't set pingroup %s pullupdown to %s: %d\n",
-			       pingroup_name(pingroup), pupd_name(pupd), err);
-	}
-
-	if (pingroups[pingroup].tri_reg >= 0) {
-		err = tegra_pinmux_set_tristate(pingroup, tristate);
-		if (err < 0)
-			pr_err("pinmux: can't set pingroup %s tristate to %s: %d\n",
-			       pingroup_name(pingroup), tri_name(func), err);
-	}
-}
-
-void tegra_pinmux_config_table(const struct tegra_pingroup_config *config, int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++)
-		tegra_pinmux_config_pingroup(&config[i]);
-}
-
-static const char *drive_pinmux_name(int pg)
-{
-	if (pg < 0 || pg >=  drive_max)
-		return "<UNKNOWN>";
-
-	return drive_pingroups[pg].name;
-}
-
-static const char *enable_name(unsigned long val)
-{
-	return val ? "ENABLE" : "DISABLE";
-}
-
-static const char *drive_name(unsigned long val)
-{
-	if (val >= TEGRA_MAX_DRIVE)
-		return "<UNKNOWN>";
-
-	return tegra_drive_names[val];
-}
-
-static const char *slew_name(unsigned long val)
-{
-	if (val >= TEGRA_MAX_SLEW)
-		return "<UNKNOWN>";
-
-	return tegra_slew_names[val];
-}
-
-static int tegra_drive_pinmux_set_hsm(int pg, enum tegra_hsm hsm)
-{
-	unsigned long flags;
-	u32 reg;
-	if (pg < 0 || pg >=  drive_max)
-		return -ERANGE;
-
-	if (hsm != TEGRA_HSM_ENABLE && hsm != TEGRA_HSM_DISABLE)
-		return -EINVAL;
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-	if (hsm == TEGRA_HSM_ENABLE)
-		reg |= (1 << 2);
-	else
-		reg &= ~(1 << 2);
-	pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-static int tegra_drive_pinmux_set_schmitt(int pg, enum tegra_schmitt schmitt)
-{
-	unsigned long flags;
-	u32 reg;
-	if (pg < 0 || pg >=  drive_max)
-		return -ERANGE;
-
-	if (schmitt != TEGRA_SCHMITT_ENABLE && schmitt != TEGRA_SCHMITT_DISABLE)
-		return -EINVAL;
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-	if (schmitt == TEGRA_SCHMITT_ENABLE)
-		reg |= (1 << 3);
-	else
-		reg &= ~(1 << 3);
-	pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-static int tegra_drive_pinmux_set_drive(int pg, enum tegra_drive drive)
-{
-	unsigned long flags;
-	u32 reg;
-	if (pg < 0 || pg >=  drive_max)
-		return -ERANGE;
-
-	if (drive < 0 || drive >= TEGRA_MAX_DRIVE)
-		return -EINVAL;
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-	reg &= ~(0x3 << 4);
-	reg |= drive << 4;
-	pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-static int tegra_drive_pinmux_set_pull_down(int pg,
-	enum tegra_pull_strength pull_down)
-{
-	unsigned long flags;
-	u32 reg;
-	if (pg < 0 || pg >=  drive_max)
-		return -ERANGE;
-
-	if (pull_down < 0 || pull_down >= TEGRA_MAX_PULL)
-		return -EINVAL;
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-	reg &= ~(0x1f << 12);
-	reg |= pull_down << 12;
-	pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-static int tegra_drive_pinmux_set_pull_up(int pg,
-	enum tegra_pull_strength pull_up)
-{
-	unsigned long flags;
-	u32 reg;
-	if (pg < 0 || pg >=  drive_max)
-		return -ERANGE;
-
-	if (pull_up < 0 || pull_up >= TEGRA_MAX_PULL)
-		return -EINVAL;
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-	reg &= ~(0x1f << 12);
-	reg |= pull_up << 12;
-	pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-static int tegra_drive_pinmux_set_slew_rising(int pg,
-	enum tegra_slew slew_rising)
-{
-	unsigned long flags;
-	u32 reg;
-	if (pg < 0 || pg >=  drive_max)
-		return -ERANGE;
-
-	if (slew_rising < 0 || slew_rising >= TEGRA_MAX_SLEW)
-		return -EINVAL;
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-	reg &= ~(0x3 << 28);
-	reg |= slew_rising << 28;
-	pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-static int tegra_drive_pinmux_set_slew_falling(int pg,
-	enum tegra_slew slew_falling)
-{
-	unsigned long flags;
-	u32 reg;
-	if (pg < 0 || pg >=  drive_max)
-		return -ERANGE;
-
-	if (slew_falling < 0 || slew_falling >= TEGRA_MAX_SLEW)
-		return -EINVAL;
-
-	spin_lock_irqsave(&mux_lock, flags);
-
-	reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-	reg &= ~(0x3 << 30);
-	reg |= slew_falling << 30;
-	pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
-	spin_unlock_irqrestore(&mux_lock, flags);
-
-	return 0;
-}
-
-static void tegra_drive_pinmux_config_pingroup(int pingroup,
-					  enum tegra_hsm hsm,
-					  enum tegra_schmitt schmitt,
-					  enum tegra_drive drive,
-					  enum tegra_pull_strength pull_down,
-					  enum tegra_pull_strength pull_up,
-					  enum tegra_slew slew_rising,
-					  enum tegra_slew slew_falling)
-{
-	int err;
-
-	err = tegra_drive_pinmux_set_hsm(pingroup, hsm);
-	if (err < 0)
-		pr_err("pinmux: can't set pingroup %s hsm to %s: %d\n",
-			drive_pinmux_name(pingroup),
-			enable_name(hsm), err);
-
-	err = tegra_drive_pinmux_set_schmitt(pingroup, schmitt);
-	if (err < 0)
-		pr_err("pinmux: can't set pingroup %s schmitt to %s: %d\n",
-			drive_pinmux_name(pingroup),
-			enable_name(schmitt), err);
-
-	err = tegra_drive_pinmux_set_drive(pingroup, drive);
-	if (err < 0)
-		pr_err("pinmux: can't set pingroup %s drive to %s: %d\n",
-			drive_pinmux_name(pingroup),
-			drive_name(drive), err);
-
-	err = tegra_drive_pinmux_set_pull_down(pingroup, pull_down);
-	if (err < 0)
-		pr_err("pinmux: can't set pingroup %s pull down to %d: %d\n",
-			drive_pinmux_name(pingroup),
-			pull_down, err);
-
-	err = tegra_drive_pinmux_set_pull_up(pingroup, pull_up);
-	if (err < 0)
-		pr_err("pinmux: can't set pingroup %s pull up to %d: %d\n",
-			drive_pinmux_name(pingroup),
-			pull_up, err);
-
-	err = tegra_drive_pinmux_set_slew_rising(pingroup, slew_rising);
-	if (err < 0)
-		pr_err("pinmux: can't set pingroup %s rising slew to %s: %d\n",
-			drive_pinmux_name(pingroup),
-			slew_name(slew_rising), err);
-
-	err = tegra_drive_pinmux_set_slew_falling(pingroup, slew_falling);
-	if (err < 0)
-		pr_err("pinmux: can't set pingroup %s falling slew to %s: %d\n",
-			drive_pinmux_name(pingroup),
-			slew_name(slew_falling), err);
-}
-
-void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
-	int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++)
-		tegra_drive_pinmux_config_pingroup(config[i].pingroup,
-						     config[i].hsm,
-						     config[i].schmitt,
-						     config[i].drive,
-						     config[i].pull_down,
-						     config[i].pull_up,
-						     config[i].slew_rising,
-						     config[i].slew_falling);
-}
-
-void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
-	int len)
-{
-	int i;
-	struct tegra_pingroup_config c;
-
-	for (i = 0; i < len; i++) {
-		int err;
-		c = config[i];
-		if (c.pingroup < 0 || c.pingroup >= pingroup_max) {
-			WARN_ON(1);
-			continue;
-		}
-		c.func = pingroups[c.pingroup].func_safe;
-		err = tegra_pinmux_set_func(&c);
-		if (err < 0)
-			pr_err("%s: tegra_pinmux_set_func returned %d setting "
-			       "%s to %s\n", __func__, err,
-			       pingroup_name(c.pingroup), func_name(c.func));
-	}
-}
-
-void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
-	int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++) {
-		int err;
-		if (config[i].pingroup < 0 ||
-		    config[i].pingroup >= pingroup_max) {
-			WARN_ON(1);
-			continue;
-		}
-		err = tegra_pinmux_set_func(&config[i]);
-		if (err < 0)
-			pr_err("%s: tegra_pinmux_set_func returned %d setting "
-			       "%s to %s\n", __func__, err,
-			       pingroup_name(config[i].pingroup),
-			       func_name(config[i].func));
-	}
-}
-
-void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
-	int len, enum tegra_tristate tristate)
-{
-	int i;
-	int err;
-	int pingroup;
-
-	for (i = 0; i < len; i++) {
-		pingroup = config[i].pingroup;
-		if (pingroups[pingroup].tri_reg >= 0) {
-			err = tegra_pinmux_set_tristate(pingroup, tristate);
-			if (err < 0)
-				pr_err("pinmux: can't set pingroup %s tristate"
-					" to %s: %d\n",	pingroup_name(pingroup),
-					tri_name(tristate), err);
-		}
-	}
-}
-
-void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
-	int len, enum tegra_pullupdown pupd)
-{
-	int i;
-	int err;
-	int pingroup;
-
-	for (i = 0; i < len; i++) {
-		pingroup = config[i].pingroup;
-		if (pingroups[pingroup].pupd_reg >= 0) {
-			err = tegra_pinmux_set_pullupdown(pingroup, pupd);
-			if (err < 0)
-				pr_err("pinmux: can't set pingroup %s pullupdown"
-					" to %s: %d\n",	pingroup_name(pingroup),
-					pupd_name(pupd), err);
-		}
-	}
-}
-
-static struct of_device_id tegra_pinmux_of_match[] __devinitdata = {
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-	{ .compatible = "nvidia,tegra20-pinmux", tegra20_pinmux_init },
-#endif
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-	{ .compatible = "nvidia,tegra30-pinmux", tegra30_pinmux_init },
-#endif
-	{ },
-};
-
-static int __devinit tegra_pinmux_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	int i;
-	int config_bad = 0;
-	const struct of_device_id *match;
-
-	match = of_match_device(tegra_pinmux_of_match, &pdev->dev);
-
-	if (match)
-		((pinmux_init)(match->data))(&pingroups, &pingroup_max,
-			&drive_pingroups, &drive_max);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-	else
-		/* no device tree available, so we must be on tegra20 */
-		tegra20_pinmux_init(&pingroups, &pingroup_max,
-					&drive_pingroups, &drive_max);
-#else
-	pr_warn("non Tegra20 platform requires pinmux devicetree node\n");
-#endif
-
-	for (i = 0; ; i++) {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-		if (!res)
-			break;
-	}
-	nbanks = i;
-
-	for (i = 0; i < pingroup_max; i++) {
-		if (pingroups[i].tri_bank >= nbanks) {
-			dev_err(&pdev->dev, "pingroup %d: bad tri_bank\n", i);
-			config_bad = 1;
-		}
-
-		if (pingroups[i].mux_bank >= nbanks) {
-			dev_err(&pdev->dev, "pingroup %d: bad mux_bank\n", i);
-			config_bad = 1;
-		}
-
-		if (pingroups[i].pupd_bank >= nbanks) {
-			dev_err(&pdev->dev, "pingroup %d: bad pupd_bank\n", i);
-			config_bad = 1;
-		}
-	}
-
-	for (i = 0; i < drive_max; i++) {
-		if (drive_pingroups[i].reg_bank >= nbanks) {
-			dev_err(&pdev->dev,
-				"drive pingroup %d: bad reg_bank\n", i);
-			config_bad = 1;
-		}
-	}
-
-	if (config_bad)
-		return -ENODEV;
-
-	regs = devm_kzalloc(&pdev->dev, nbanks * sizeof(*regs), GFP_KERNEL);
-	if (!regs) {
-		dev_err(&pdev->dev, "Can't alloc regs pointer\n");
-		return -ENODEV;
-	}
-
-	for (i = 0; i < nbanks; i++) {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-		if (!res) {
-			dev_err(&pdev->dev, "Missing MEM resource\n");
-			return -ENODEV;
-		}
-
-		if (!devm_request_mem_region(&pdev->dev, res->start,
-					    resource_size(res),
-					    dev_name(&pdev->dev))) {
-			dev_err(&pdev->dev,
-				"Couldn't request MEM resource %d\n", i);
-			return -ENODEV;
-		}
-
-		regs[i] = devm_ioremap(&pdev->dev, res->start,
-					resource_size(res));
-		if (!regs) {
-			dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i);
-			return -ENODEV;
-		}
-	}
-
-	return 0;
-}
-
-static struct platform_driver tegra_pinmux_driver = {
-	.driver		= {
-		.name	= "tegra-pinmux",
-		.owner	= THIS_MODULE,
-		.of_match_table = tegra_pinmux_of_match,
-	},
-	.probe		= tegra_pinmux_probe,
-};
-
-static int __init tegra_pinmux_init(void)
-{
-	return platform_driver_register(&tegra_pinmux_driver);
-}
-postcore_initcall(tegra_pinmux_init);
-
-#ifdef	CONFIG_DEBUG_FS
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-static void dbg_pad_field(struct seq_file *s, int len)
-{
-	seq_putc(s, ',');
-
-	while (len-- > -1)
-		seq_putc(s, ' ');
-}
-
-static int dbg_pinmux_show(struct seq_file *s, void *unused)
-{
-	int i;
-	int len;
-
-	for (i = 0; i < pingroup_max; i++) {
-		unsigned long reg;
-		unsigned long tri;
-		unsigned long mux;
-		unsigned long pupd;
-
-		seq_printf(s, "\t{TEGRA_PINGROUP_%s", pingroups[i].name);
-		len = strlen(pingroups[i].name);
-		dbg_pad_field(s, 5 - len);
-
-		if (pingroups[i].mux_reg < 0) {
-			seq_printf(s, "TEGRA_MUX_NONE");
-			len = strlen("NONE");
-		} else {
-			reg = pg_readl(pingroups[i].mux_bank,
-					pingroups[i].mux_reg);
-			mux = (reg >> pingroups[i].mux_bit) & 0x3;
-			if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) {
-				seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1);
-				len = 5;
-			} else {
-				seq_printf(s, "TEGRA_MUX_%s",
-					   tegra_mux_names[pingroups[i].funcs[mux]]);
-				len = strlen(tegra_mux_names[pingroups[i].funcs[mux]]);
-			}
-		}
-		dbg_pad_field(s, 13-len);
-
-		if (pingroups[i].pupd_reg < 0) {
-			seq_printf(s, "TEGRA_PUPD_NORMAL");
-			len = strlen("NORMAL");
-		} else {
-			reg = pg_readl(pingroups[i].pupd_bank,
-					pingroups[i].pupd_reg);
-			pupd = (reg >> pingroups[i].pupd_bit) & 0x3;
-			seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd));
-			len = strlen(pupd_name(pupd));
-		}
-		dbg_pad_field(s, 9 - len);
-
-		if (pingroups[i].tri_reg < 0) {
-			seq_printf(s, "TEGRA_TRI_NORMAL");
-		} else {
-			reg = pg_readl(pingroups[i].tri_bank,
-					pingroups[i].tri_reg);
-			tri = (reg >> pingroups[i].tri_bit) & 0x1;
-
-			seq_printf(s, "TEGRA_TRI_%s", tri_name(tri));
-		}
-		seq_printf(s, "},\n");
-	}
-	return 0;
-}
-
-static int dbg_pinmux_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, dbg_pinmux_show, &inode->i_private);
-}
-
-static const struct file_operations debug_fops = {
-	.open		= dbg_pinmux_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int dbg_drive_pinmux_show(struct seq_file *s, void *unused)
-{
-	int i;
-	int len;
-
-	for (i = 0; i < drive_max; i++) {
-		u32 reg;
-
-		seq_printf(s, "\t{TEGRA_DRIVE_PINGROUP_%s",
-			drive_pingroups[i].name);
-		len = strlen(drive_pingroups[i].name);
-		dbg_pad_field(s, 7 - len);
-
-
-		reg = pg_readl(drive_pingroups[i].reg_bank,
-				drive_pingroups[i].reg);
-		if (HSM_EN(reg)) {
-			seq_printf(s, "TEGRA_HSM_ENABLE");
-			len = 16;
-		} else {
-			seq_printf(s, "TEGRA_HSM_DISABLE");
-			len = 17;
-		}
-		dbg_pad_field(s, 17 - len);
-
-		if (SCHMT_EN(reg)) {
-			seq_printf(s, "TEGRA_SCHMITT_ENABLE");
-			len = 21;
-		} else {
-			seq_printf(s, "TEGRA_SCHMITT_DISABLE");
-			len = 22;
-		}
-		dbg_pad_field(s, 22 - len);
-
-		seq_printf(s, "TEGRA_DRIVE_%s", drive_name(LPMD(reg)));
-		len = strlen(drive_name(LPMD(reg)));
-		dbg_pad_field(s, 5 - len);
-
-		seq_printf(s, "TEGRA_PULL_%d", DRVDN(reg));
-		len = DRVDN(reg) < 10 ? 1 : 2;
-		dbg_pad_field(s, 2 - len);
-
-		seq_printf(s, "TEGRA_PULL_%d", DRVUP(reg));
-		len = DRVUP(reg) < 10 ? 1 : 2;
-		dbg_pad_field(s, 2 - len);
-
-		seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWR(reg)));
-		len = strlen(slew_name(SLWR(reg)));
-		dbg_pad_field(s, 7 - len);
-
-		seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWF(reg)));
-
-		seq_printf(s, "},\n");
-	}
-	return 0;
-}
-
-static int dbg_drive_pinmux_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, dbg_drive_pinmux_show, &inode->i_private);
-}
-
-static const struct file_operations debug_drive_fops = {
-	.open		= dbg_drive_pinmux_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init tegra_pinmux_debuginit(void)
-{
-	(void) debugfs_create_file("tegra_pinmux", S_IRUGO,
-					NULL, NULL, &debug_fops);
-	(void) debugfs_create_file("tegra_pinmux_drive", S_IRUGO,
-					NULL, NULL, &debug_drive_fops);
-	return 0;
-}
-late_initcall(tegra_pinmux_debuginit);
-#endif
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 592a4ee..bae09b8 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -1764,6 +1764,12 @@
 	{ 19200000, 760000000,  950,  24, 1, 8},
 	{ 26000000, 760000000,  760,  26, 1, 12},
 
+	/* 750 MHz */
+	{ 12000000, 750000000,  750,  12, 1, 12},
+	{ 13000000, 750000000,  750,  13, 1, 12},
+	{ 19200000, 750000000,  625,  16, 1, 8},
+	{ 26000000, 750000000,  750,  26, 1, 12},
+
 	/* 608 MHz */
 	{ 12000000, 608000000,  608,  12, 1, 12},
 	{ 13000000, 608000000,  608,  13, 1, 12},
@@ -2142,8 +2148,8 @@
 	PERIPH_CLK("apbdma",	"tegra-dma",		NULL,	34,	0,	108000000, mux_pclk,			0),
 	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET),
 	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("i2s1",	"tegra-i2s.0",		NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("i2s2",	"tegra-i2s.1",		NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("i2s1",	"tegra20-i2s.0",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("i2s2",	"tegra20-i2s.1",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("spdif_out",	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("spdif_in",	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71),
 	PERIPH_CLK("pwm",	"pwm",			NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71),
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index c5b2ac0..d71d2fe 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -711,7 +711,6 @@
 			err = -ENXIO;
 			goto err1;
 		}
-		tegra_gpio_enable(ulpi_config->reset_gpio);
 		gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
 		gpio_direction_output(ulpi_config->reset_gpio, 0);
 		phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index ef7099e..53d3d46 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -9,10 +9,8 @@
 	select ARM_ERRATA_754322
 	select ARM_ERRATA_764369
 	select CACHE_L2X0
-
-config UX500_SOC_DB5500
-	bool
-	select MFD_DB5500_PRCMU
+	select PINCTRL
+	select PINCTRL_NOMADIK
 
 config UX500_SOC_DB8500
 	bool
@@ -20,6 +18,7 @@
 	select REGULATOR
 	select REGULATOR_DB8500_PRCMU
 	select CPU_FREQ_TABLE if CPU_FREQ
+	select PINCTRL_DB8500
 
 menu "Ux500 target platform (boards)"
 
@@ -45,15 +44,8 @@
 	help
 	  Include support for the snowball development platform.
 
-config MACH_U5500
-	bool "U5500 Development platform"
-	select UX500_SOC_DB5500
-	help
-	  Include support for the U5500 development platform.
-
 config UX500_AUTO_PLATFORM
 	def_bool y
-	depends on !MACH_U5500
 	select MACH_MOP500
 	help
 	  At least one platform needs to be selected in order to build
@@ -74,18 +66,4 @@
 	  Choose the UART on which kernel low-level debug messages should be
 	  output.
 
-config U5500_MODEM_IRQ
-	bool "Modem IRQ support"
-	depends on UX500_SOC_DB5500
-	default y
-	help
-	  Add support for handling IRQ:s from modem side
-
-config U5500_MBOX
-	bool "Mailbox support"
-	depends on U5500_MODEM_IRQ
-	default y
-	help
-	  Add support for U5500 mailbox communication with modem side
-
 endif
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 465b9ec..026086f 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -4,17 +4,14 @@
 
 obj-y				:= clock.o cpu.o devices.o devices-common.o \
 				   id.o usb.o timer.o
+obj-$(CONFIG_CPU_IDLE)          += cpuidle.o
 obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
-obj-$(CONFIG_UX500_SOC_DB5500)	+= cpu-db5500.o dma-db5500.o
 obj-$(CONFIG_UX500_SOC_DB8500)	+= cpu-db8500.o devices-db8500.o
 obj-$(CONFIG_MACH_MOP500)	+= board-mop500.o board-mop500-sdi.o \
 				board-mop500-regulators.o \
 				board-mop500-uib.o board-mop500-stuib.o \
 				board-mop500-u8500uib.o \
-				board-mop500-pins.o
-obj-$(CONFIG_MACH_U5500)	+= board-u5500.o board-u5500-sdi.o
+				board-mop500-pins.o \
+				board-mop500-msp.o
 obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
-obj-$(CONFIG_U5500_MODEM_IRQ)	+= modem-irq-db5500.o
-obj-$(CONFIG_U5500_MBOX)	+= mbox-db5500.o
-
diff --git a/arch/arm/mach-ux500/board-mop500-msp.c b/arch/arm/mach-ux500/board-mop500-msp.c
new file mode 100644
index 0000000..9960480
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-msp.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <plat/gpio-nomadik.h>
+#include <plat/pincfg.h>
+#include <plat/ste_dma40.h>
+
+#include <mach/devices.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/msp.h>
+
+#include "ste-dma40-db8500.h"
+#include "board-mop500.h"
+#include "devices-db8500.h"
+#include "pins-db8500.h"
+
+/* MSP1/3 Tx/Rx usage protection */
+static DEFINE_SPINLOCK(msp_rxtx_lock);
+
+/* Reference Count */
+static int msp_rxtx_ref;
+
+/* Pin modes */
+struct pinctrl *msp1_p;
+struct pinctrl_state *msp1_def;
+struct pinctrl_state *msp1_sleep;
+
+int msp13_i2s_init(void)
+{
+	int retval = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msp_rxtx_lock, flags);
+	if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_def))) {
+		retval = pinctrl_select_state(msp1_p, msp1_def);
+		if (retval)
+			pr_err("could not set MSP1 defstate\n");
+	}
+	if (!retval)
+		msp_rxtx_ref++;
+	spin_unlock_irqrestore(&msp_rxtx_lock, flags);
+
+	return retval;
+}
+
+int msp13_i2s_exit(void)
+{
+	int retval = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msp_rxtx_lock, flags);
+	WARN_ON(!msp_rxtx_ref);
+	msp_rxtx_ref--;
+	if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_sleep))) {
+		retval = pinctrl_select_state(msp1_p, msp1_sleep);
+		if (retval)
+			pr_err("could not set MSP1 sleepstate\n");
+	}
+	spin_unlock_irqrestore(&msp_rxtx_lock, flags);
+
+	return retval;
+}
+
+static struct stedma40_chan_cfg msp0_dma_rx = {
+	.high_priority = true,
+	.dir = STEDMA40_PERIPH_TO_MEM,
+
+	.src_dev_type = DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX,
+	.dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+
+	.src_info.psize = STEDMA40_PSIZE_LOG_4,
+	.dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+	/* data_width is set during configuration */
+};
+
+static struct stedma40_chan_cfg msp0_dma_tx = {
+	.high_priority = true,
+	.dir = STEDMA40_MEM_TO_PERIPH,
+
+	.src_dev_type = STEDMA40_DEV_DST_MEMORY,
+	.dst_dev_type = DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX,
+
+	.src_info.psize = STEDMA40_PSIZE_LOG_4,
+	.dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+	/* data_width is set during configuration */
+};
+
+static struct msp_i2s_platform_data msp0_platform_data = {
+	.id = MSP_I2S_0,
+	.msp_i2s_dma_rx = &msp0_dma_rx,
+	.msp_i2s_dma_tx = &msp0_dma_tx,
+};
+
+static struct stedma40_chan_cfg msp1_dma_rx = {
+	.high_priority = true,
+	.dir = STEDMA40_PERIPH_TO_MEM,
+
+	.src_dev_type = DB8500_DMA_DEV30_MSP3_RX,
+	.dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+
+	.src_info.psize = STEDMA40_PSIZE_LOG_4,
+	.dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+	/* data_width is set during configuration */
+};
+
+static struct stedma40_chan_cfg msp1_dma_tx = {
+	.high_priority = true,
+	.dir = STEDMA40_MEM_TO_PERIPH,
+
+	.src_dev_type = STEDMA40_DEV_DST_MEMORY,
+	.dst_dev_type = DB8500_DMA_DEV30_MSP1_TX,
+
+	.src_info.psize = STEDMA40_PSIZE_LOG_4,
+	.dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+	/* data_width is set during configuration */
+};
+
+static struct msp_i2s_platform_data msp1_platform_data = {
+	.id = MSP_I2S_1,
+	.msp_i2s_dma_rx = NULL,
+	.msp_i2s_dma_tx = &msp1_dma_tx,
+	.msp_i2s_init = msp13_i2s_init,
+	.msp_i2s_exit = msp13_i2s_exit,
+};
+
+static struct stedma40_chan_cfg msp2_dma_rx = {
+	.high_priority = true,
+	.dir = STEDMA40_PERIPH_TO_MEM,
+
+	.src_dev_type = DB8500_DMA_DEV14_MSP2_RX,
+	.dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+
+	/* MSP2 DMA doesn't work with PSIZE == 4 on DB8500v2 */
+	.src_info.psize = STEDMA40_PSIZE_LOG_1,
+	.dst_info.psize = STEDMA40_PSIZE_LOG_1,
+
+	/* data_width is set during configuration */
+};
+
+static struct stedma40_chan_cfg msp2_dma_tx = {
+	.high_priority = true,
+	.dir = STEDMA40_MEM_TO_PERIPH,
+
+	.src_dev_type = STEDMA40_DEV_DST_MEMORY,
+	.dst_dev_type = DB8500_DMA_DEV14_MSP2_TX,
+
+	.src_info.psize = STEDMA40_PSIZE_LOG_4,
+	.dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+	.use_fixed_channel = true,
+	.phy_channel = 1,
+
+	/* data_width is set during configuration */
+};
+
+static struct platform_device *db8500_add_msp_i2s(struct device *parent,
+			int id,
+			resource_size_t base, int irq,
+			struct msp_i2s_platform_data *pdata)
+{
+	struct platform_device *pdev;
+	struct resource res[] = {
+		DEFINE_RES_MEM(base, SZ_4K),
+		DEFINE_RES_IRQ(irq),
+	};
+
+	pr_info("Register platform-device 'ux500-msp-i2s', id %d, irq %d\n",
+		id, irq);
+	pdev = platform_device_register_resndata(parent, "ux500-msp-i2s", id,
+						res, ARRAY_SIZE(res),
+						pdata, sizeof(*pdata));
+	if (!pdev) {
+		pr_err("Failed to register platform-device 'ux500-msp-i2s.%d'!\n",
+			id);
+		return NULL;
+	}
+
+	return pdev;
+}
+
+/* Platform device for ASoC U8500 machine */
+static struct platform_device snd_soc_u8500 = {
+		.name = "snd-soc-u8500",
+		.id = 0,
+		.dev = {
+			.platform_data = NULL,
+		},
+};
+
+/* Platform device for Ux500-PCM */
+static struct platform_device ux500_pcm = {
+		.name = "ux500-pcm",
+		.id = 0,
+		.dev = {
+			.platform_data = NULL,
+		},
+};
+
+static struct msp_i2s_platform_data msp2_platform_data = {
+	.id = MSP_I2S_2,
+	.msp_i2s_dma_rx = &msp2_dma_rx,
+	.msp_i2s_dma_tx = &msp2_dma_tx,
+};
+
+static struct msp_i2s_platform_data msp3_platform_data = {
+	.id		= MSP_I2S_3,
+	.msp_i2s_dma_rx	= &msp1_dma_rx,
+	.msp_i2s_dma_tx	= NULL,
+	.msp_i2s_init = msp13_i2s_init,
+	.msp_i2s_exit = msp13_i2s_exit,
+};
+
+int mop500_msp_init(struct device *parent)
+{
+	struct platform_device *msp1;
+
+	pr_info("%s: Register platform-device 'snd-soc-u8500'.\n", __func__);
+	platform_device_register(&snd_soc_u8500);
+
+	pr_info("Initialize MSP I2S-devices.\n");
+	db8500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0,
+			   &msp0_platform_data);
+	msp1 = db8500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1,
+			   &msp1_platform_data);
+	db8500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2,
+			   &msp2_platform_data);
+	db8500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1,
+			   &msp3_platform_data);
+
+	/* Get the pinctrl handle for MSP1 */
+	if (msp1) {
+		msp1_p = pinctrl_get(&msp1->dev);
+		if (IS_ERR(msp1_p))
+			dev_err(&msp1->dev, "could not get MSP1 pinctrl\n");
+		else {
+			msp1_def = pinctrl_lookup_state(msp1_p,
+							PINCTRL_STATE_DEFAULT);
+			if (IS_ERR(msp1_def)) {
+				dev_err(&msp1->dev,
+					"could not get MSP1 defstate\n");
+			}
+			msp1_sleep = pinctrl_lookup_state(msp1_p,
+							  PINCTRL_STATE_SLEEP);
+			if (IS_ERR(msp1_sleep))
+				dev_err(&msp1->dev,
+					"could not get MSP1 idlestate\n");
+		}
+	}
+
+	pr_info("%s: Register platform-device 'ux500-pcm'\n", __func__);
+	platform_device_register(&ux500_pcm);
+
+	return 0;
+}
diff --git a/arch/arm/mach-ux500/board-mop500-msp.h b/arch/arm/mach-ux500/board-mop500-msp.h
new file mode 100644
index 0000000..6fcfb5e
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-msp.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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.
+ */
+
+void mop500_msp_init(struct device *parent);
diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c
index f5413dc..32fd992 100644
--- a/arch/arm/mach-ux500/board-mop500-pins.c
+++ b/arch/arm/mach-ux500/board-mop500-pins.c
@@ -7,299 +7,508 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/bug.h>
+#include <linux/string.h>
+#include <linux/pinctrl/machine.h>
 
 #include <asm/mach-types.h>
 #include <plat/pincfg.h>
 #include <plat/gpio-nomadik.h>
+
 #include <mach/hardware.h>
 
 #include "pins-db8500.h"
+#include "board-mop500.h"
 
-static pin_cfg_t mop500_pins_common[] = {
-	/* I2C */
-	GPIO147_I2C0_SCL,
-	GPIO148_I2C0_SDA,
-	GPIO16_I2C1_SCL,
-	GPIO17_I2C1_SDA,
-	GPIO10_I2C2_SDA,
-	GPIO11_I2C2_SCL,
-	GPIO229_I2C3_SDA,
-	GPIO230_I2C3_SCL,
+enum custom_pin_cfg_t {
+	PINS_FOR_DEFAULT,
+	PINS_FOR_U9500,
+};
 
-	/* MSP0 */
-	GPIO12_MSP0_TXD,
-	GPIO13_MSP0_TFS,
-	GPIO14_MSP0_TCK,
-	GPIO15_MSP0_RXD,
+static enum custom_pin_cfg_t pinsfor;
 
-	/* MSP2: HDMI */
-	GPIO193_MSP2_TXD,
-	GPIO194_MSP2_TCK,
-	GPIO195_MSP2_TFS,
-	GPIO196_MSP2_RXD | PIN_OUTPUT_LOW,
+/* These simply sets bias for pins */
+#define BIAS(a,b) static unsigned long a[] = { b }
 
-	/* Touch screen INTERFACE */
-	GPIO84_GPIO	| PIN_INPUT_PULLUP, /* TOUCH_INT1 */
+BIAS(pd, PIN_PULL_DOWN);
+BIAS(slpm_gpio_nopull, PIN_SLPM_GPIO|PIN_SLPM_INPUT_NOPULL);
+BIAS(in_nopull, PIN_INPUT_NOPULL);
+BIAS(in_nopull_sleep_nowkup, PIN_INPUT_NOPULL|PIN_SLPM_WAKEUP_DISABLE);
+BIAS(in_pu, PIN_INPUT_PULLUP);
+BIAS(in_pd, PIN_INPUT_PULLDOWN);
+BIAS(in_pd_slpm_in_pu, PIN_INPUT_PULLDOWN|PIN_SLPM_INPUT_PULLUP);
+BIAS(in_pu_slpm_out_lo, PIN_INPUT_PULLUP|PIN_SLPM_OUTPUT_LOW);
+BIAS(out_hi, PIN_OUTPUT_HIGH);
+BIAS(out_lo, PIN_OUTPUT_LOW);
+BIAS(out_lo_sleep_nowkup, PIN_OUTPUT_LOW|PIN_SLPM_WAKEUP_DISABLE);
+/* These also force them into GPIO mode */
+BIAS(gpio_in_pu, PIN_INPUT_PULLUP|PIN_GPIOMODE_ENABLED);
+BIAS(gpio_in_pd, PIN_INPUT_PULLDOWN|PIN_GPIOMODE_ENABLED);
+BIAS(gpio_in_pu_slpm_gpio_nopull, PIN_INPUT_PULLUP|PIN_GPIOMODE_ENABLED|PIN_SLPM_GPIO|PIN_SLPM_INPUT_NOPULL);
+BIAS(gpio_in_pd_slpm_gpio_nopull, PIN_INPUT_PULLDOWN|PIN_GPIOMODE_ENABLED|PIN_SLPM_GPIO|PIN_SLPM_INPUT_NOPULL);
+BIAS(gpio_out_hi, PIN_OUTPUT_HIGH|PIN_GPIOMODE_ENABLED);
+BIAS(gpio_out_lo, PIN_OUTPUT_LOW|PIN_GPIOMODE_ENABLED);
+/* Sleep modes */
+BIAS(sleep_in_wkup_pdis, PIN_SLPM_DIR_INPUT|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(sleep_in_nopull_wkup, PIN_INPUT_NOPULL|PIN_SLPM_WAKEUP_ENABLE);
+BIAS(sleep_out_hi_wkup_pdis, PIN_SLPM_OUTPUT_HIGH|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(sleep_out_lo_wkup, PIN_OUTPUT_LOW|PIN_SLPM_WAKEUP_ENABLE);
+BIAS(sleep_out_wkup_pdis, PIN_SLPM_DIR_OUTPUT|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
 
-	/* STMPE1601/tc35893 keypad  IRQ */
-	GPIO218_GPIO	| PIN_INPUT_PULLUP,
+/* We use these to define hog settings that are always done on boot */
+#define DB8500_MUX_HOG(group,func) \
+	PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-db8500", group, func)
+#define DB8500_PIN_HOG(pin,conf) \
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-db8500", pin, conf)
 
-	/* MMC0 (MicroSD card) */
-	GPIO18_MC0_CMDDIR	| PIN_OUTPUT_HIGH,
-	GPIO19_MC0_DAT0DIR	| PIN_OUTPUT_HIGH,
-	GPIO20_MC0_DAT2DIR	| PIN_OUTPUT_HIGH,
+/* These are default states associated with device and changed runtime */
+#define DB8500_MUX(group,func,dev) \
+	PIN_MAP_MUX_GROUP_DEFAULT(dev, "pinctrl-db8500", group, func)
+#define DB8500_PIN(pin,conf,dev) \
+	PIN_MAP_CONFIGS_PIN_DEFAULT(dev, "pinctrl-db8500", pin, conf)
 
-	GPIO22_MC0_FBCLK	| PIN_INPUT_NOPULL,
-	GPIO23_MC0_CLK		| PIN_OUTPUT_LOW,
-	GPIO24_MC0_CMD		| PIN_INPUT_PULLUP,
-	GPIO25_MC0_DAT0		| PIN_INPUT_PULLUP,
-	GPIO26_MC0_DAT1		| PIN_INPUT_PULLUP,
-	GPIO27_MC0_DAT2		| PIN_INPUT_PULLUP,
-	GPIO28_MC0_DAT3		| PIN_INPUT_PULLUP,
+#define DB8500_PIN_SLEEP(pin,conf,dev) \
+	PIN_MAP_CONFIGS_PIN(dev, PINCTRL_STATE_SLEEP, "pinctrl-db8500",	\
+			    pin, conf)
 
-	/* SDI1 (SDIO) */
-	GPIO208_MC1_CLK		| PIN_OUTPUT_LOW,
-	GPIO209_MC1_FBCLK	| PIN_INPUT_NOPULL,
-	GPIO210_MC1_CMD		| PIN_INPUT_PULLUP,
-	GPIO211_MC1_DAT0	| PIN_INPUT_PULLUP,
-	GPIO212_MC1_DAT1	| PIN_INPUT_PULLUP,
-	GPIO213_MC1_DAT2	| PIN_INPUT_PULLUP,
-	GPIO214_MC1_DAT3	| PIN_INPUT_PULLUP,
-
-	/* MMC2 (On-board DATA INTERFACE eMMC) */
-	GPIO128_MC2_CLK		| PIN_OUTPUT_LOW,
-	GPIO129_MC2_CMD		| PIN_INPUT_PULLUP,
-	GPIO130_MC2_FBCLK	| PIN_INPUT_NOPULL,
-	GPIO131_MC2_DAT0	| PIN_INPUT_PULLUP,
-	GPIO132_MC2_DAT1	| PIN_INPUT_PULLUP,
-	GPIO133_MC2_DAT2	| PIN_INPUT_PULLUP,
-	GPIO134_MC2_DAT3	| PIN_INPUT_PULLUP,
-	GPIO135_MC2_DAT4	| PIN_INPUT_PULLUP,
-	GPIO136_MC2_DAT5	| PIN_INPUT_PULLUP,
-	GPIO137_MC2_DAT6	| PIN_INPUT_PULLUP,
-	GPIO138_MC2_DAT7	| PIN_INPUT_PULLUP,
-
-	/* MMC4 (On-board STORAGE INTERFACE eMMC) */
-	GPIO197_MC4_DAT3	| PIN_INPUT_PULLUP,
-	GPIO198_MC4_DAT2	| PIN_INPUT_PULLUP,
-	GPIO199_MC4_DAT1	| PIN_INPUT_PULLUP,
-	GPIO200_MC4_DAT0	| PIN_INPUT_PULLUP,
-	GPIO201_MC4_CMD		| PIN_INPUT_PULLUP,
-	GPIO202_MC4_FBCLK	| PIN_INPUT_NOPULL,
-	GPIO203_MC4_CLK		| PIN_OUTPUT_LOW,
-	GPIO204_MC4_DAT7	| PIN_INPUT_PULLUP,
-	GPIO205_MC4_DAT6	| PIN_INPUT_PULLUP,
-	GPIO206_MC4_DAT5	| PIN_INPUT_PULLUP,
-	GPIO207_MC4_DAT4	| PIN_INPUT_PULLUP,
-
-	/* SKE keypad */
-	GPIO153_KP_I7,
-	GPIO154_KP_I6,
-	GPIO155_KP_I5,
-	GPIO156_KP_I4,
-	GPIO157_KP_O7,
-	GPIO158_KP_O6,
-	GPIO159_KP_O5,
-	GPIO160_KP_O4,
-	GPIO161_KP_I3,
-	GPIO162_KP_I2,
-	GPIO163_KP_I1,
-	GPIO164_KP_I0,
-	GPIO165_KP_O3,
-	GPIO166_KP_O2,
-	GPIO167_KP_O1,
-	GPIO168_KP_O0,
-
-	/* UART */
-	/* uart-0 pins gpio configuration should be
-	 * kept intact to prevent glitch in tx line
-	 * when tty dev is opened. Later these pins
-	 * are configured to uart mop500_pins_uart0
-	 *
-	 * It will be replaced with uart configuration
-	 * once the issue is solved.
+/* Pin control settings */
+static struct pinctrl_map __initdata mop500_family_pinmap[] = {
+	/*
+	 * uMSP0, mux in 4 pins, regular placement of RX/TX
+	 * explicitly set the pins to no pull
 	 */
-	GPIO0_GPIO	| PIN_INPUT_PULLUP,
-	GPIO1_GPIO	| PIN_OUTPUT_HIGH,
-	GPIO2_GPIO	| PIN_INPUT_PULLUP,
-	GPIO3_GPIO	| PIN_OUTPUT_HIGH,
-
-	GPIO29_U2_RXD	| PIN_INPUT_PULLUP,
-	GPIO30_U2_TXD	| PIN_OUTPUT_HIGH,
-	GPIO31_U2_CTSn	| PIN_INPUT_PULLUP,
-	GPIO32_U2_RTSn	| PIN_OUTPUT_HIGH,
-
-	/* Display & HDMI HW sync */
-	GPIO68_LCD_VSI0	| PIN_INPUT_PULLUP,
-	GPIO69_LCD_VSI1	| PIN_INPUT_PULLUP,
+	DB8500_MUX_HOG("msp0txrx_a_1", "msp0"),
+	DB8500_MUX_HOG("msp0tfstck_a_1", "msp0"),
+	DB8500_PIN_HOG("GPIO12_AC4", in_nopull), /* TXD */
+	DB8500_PIN_HOG("GPIO15_AC3", in_nopull), /* RXD */
+	DB8500_PIN_HOG("GPIO13_AF3", in_nopull), /* TFS */
+	DB8500_PIN_HOG("GPIO14_AE3", in_nopull), /* TCK */
+	/* MSP2 for HDMI, pull down TXD, TCK, TFS  */
+	DB8500_MUX_HOG("msp2_a_1", "msp2"),
+	DB8500_PIN_HOG("GPIO193_AH27", in_pd), /* TXD */
+	DB8500_PIN_HOG("GPIO194_AF27", in_pd), /* TCK */
+	DB8500_PIN_HOG("GPIO195_AG28", in_pd), /* TFS */
+	DB8500_PIN_HOG("GPIO196_AG26", out_lo), /* RXD */
+	/*
+	 * LCD, set TE0 (using LCD VSI0) and D14 (touch screen interrupt) to
+	 * pull-up
+	 * TODO: is this really correct? Snowball doesn't have a LCD.
+	 */
+	DB8500_MUX_HOG("lcdvsi0_a_1", "lcd"),
+	DB8500_PIN_HOG("GPIO68_E1", in_pu),
+	DB8500_PIN_HOG("GPIO84_C2", gpio_in_pu),
+	/*
+	 * STMPE1601/tc35893 keypad IRQ GPIO 218
+	 * TODO: set for snowball and HREF really??
+	 */
+	DB8500_PIN_HOG("GPIO218_AH11", gpio_in_pu),
+	/*
+	 * UART0, we do not mux in u0 here.
+	 * uart-0 pins gpio configuration should be kept intact to prevent
+	 * a glitch in tx line when the tty dev is opened. Later these pins
+	 * are configured to uart mop500_pins_uart0
+	 */
+	DB8500_PIN_HOG("GPIO0_AJ5", in_pu), /* CTS */
+	DB8500_PIN_HOG("GPIO1_AJ3", out_hi), /* RTS */
+	DB8500_PIN_HOG("GPIO2_AH4", in_pu), /* RXD */
+	DB8500_PIN_HOG("GPIO3_AH3", out_hi), /* TXD */
+	/*
+	 * Mux in UART2 on altfunction C and set pull-ups.
+	 * TODO: is this used on U8500 variants and Snowball really?
+	 * The setting on GPIO31 conflicts with magnetometer use on hrefv60
+	 */
+	DB8500_MUX_HOG("u2rxtx_c_1", "u2"),
+	DB8500_MUX_HOG("u2ctsrts_c_1", "u2"),
+	DB8500_PIN_HOG("GPIO29_W2", in_pu), /* RXD */
+	DB8500_PIN_HOG("GPIO30_W3", out_hi), /* TXD */
+	DB8500_PIN_HOG("GPIO31_V3", in_pu), /* CTS */
+	DB8500_PIN_HOG("GPIO32_V2", out_hi), /* RTS */
+	/*
+	 * The following pin sets were known as "runtime pins" before being
+	 * converted to the pinctrl model. Here we model them as "default"
+	 * states.
+	 */
+	/* Mux in UART0 after initialization */
+	DB8500_MUX("u0_a_1", "u0", "uart0"),
+	DB8500_PIN("GPIO0_AJ5", in_pu, "uart0"), /* CTS */
+	DB8500_PIN("GPIO1_AJ3", out_hi, "uart0"), /* RTS */
+	DB8500_PIN("GPIO2_AH4", in_pu, "uart0"), /* RXD */
+	DB8500_PIN("GPIO3_AH3", out_hi, "uart0"), /* TXD */
+	/* UART0 sleep state */
+	DB8500_PIN_SLEEP("GPIO0_AJ5", sleep_in_wkup_pdis, "uart0"),
+	DB8500_PIN_SLEEP("GPIO1_AJ3", sleep_out_hi_wkup_pdis, "uart0"),
+	DB8500_PIN_SLEEP("GPIO2_AH4", sleep_in_wkup_pdis, "uart0"),
+	DB8500_PIN_SLEEP("GPIO3_AH3", sleep_out_wkup_pdis, "uart0"),
+	/* MSP1 for ALSA codec */
+	DB8500_MUX("msp1txrx_a_1", "msp1", "ux500-msp-i2s.1"),
+	DB8500_MUX("msp1_a_1", "msp1", "ux500-msp-i2s.1"),
+	DB8500_PIN("GPIO33_AF2", out_lo_sleep_nowkup, "ux500-msp-i2s.1"),
+	DB8500_PIN("GPIO34_AE1", in_nopull_sleep_nowkup, "ux500-msp-i2s.1"),
+	DB8500_PIN("GPIO35_AE2", in_nopull_sleep_nowkup, "ux500-msp-i2s.1"),
+	DB8500_PIN("GPIO36_AG2", in_nopull_sleep_nowkup, "ux500-msp-i2s.1"),
+	/* MSP1 sleep state */
+	DB8500_PIN_SLEEP("GPIO33_AF2", sleep_out_lo_wkup, "ux500-msp-i2s.1"),
+	DB8500_PIN_SLEEP("GPIO34_AE1", sleep_in_nopull_wkup, "ux500-msp-i2s.1"),
+	DB8500_PIN_SLEEP("GPIO35_AE2", sleep_in_nopull_wkup, "ux500-msp-i2s.1"),
+	DB8500_PIN_SLEEP("GPIO36_AG2", sleep_in_nopull_wkup, "ux500-msp-i2s.1"),
+	/* Mux in LCD data lines 8 thru 11 and LCDA CLK for MCDE TVOUT */
+	DB8500_MUX("lcd_d8_d11_a_1", "lcd", "mcde-tvout"),
+	DB8500_MUX("lcdaclk_b_1", "lcda", "mcde-tvout"),
+	/* Mux in LCD VSI1 and pull it up for MCDE HDMI output */
+	DB8500_MUX("lcdvsi1_a_1", "lcd", "av8100-hdmi"),
+	/* Mux in I2C blocks, put pins into GPIO in sleepmode no pull-up */
+	DB8500_MUX("i2c0_a_1", "i2c0", "nmk-i2c.0"),
+	DB8500_PIN("GPIO147_C15", slpm_gpio_nopull, "nmk-i2c.0"),
+	DB8500_PIN("GPIO148_B16", slpm_gpio_nopull, "nmk-i2c.0"),
+	DB8500_MUX("i2c1_b_2", "i2c1", "nmk-i2c.1"),
+	DB8500_PIN("GPIO16_AD3", slpm_gpio_nopull, "nmk-i2c.1"),
+	DB8500_PIN("GPIO17_AD4", slpm_gpio_nopull, "nmk-i2c.1"),
+	DB8500_MUX("i2c2_b_2", "i2c2", "nmk-i2c.2"),
+	DB8500_PIN("GPIO10_AF5", slpm_gpio_nopull, "nmk-i2c.2"),
+	DB8500_PIN("GPIO11_AG4", slpm_gpio_nopull, "nmk-i2c.2"),
+	DB8500_MUX("i2c3_c_2", "i2c3", "nmk-i2c.3"),
+	DB8500_PIN("GPIO229_AG7", slpm_gpio_nopull, "nmk-i2c.3"),
+	DB8500_PIN("GPIO230_AF7", slpm_gpio_nopull, "nmk-i2c.3"),
+	/* Mux in SDI0 (here called MC0) used for removable MMC/SD/SDIO cards */
+	DB8500_MUX("mc0_a_1", "mc0", "sdi0"),
+	DB8500_PIN("GPIO18_AC2", out_hi, "sdi0"), /* CMDDIR */
+	DB8500_PIN("GPIO19_AC1", out_hi, "sdi0"), /* DAT0DIR */
+	DB8500_PIN("GPIO20_AB4", out_hi, "sdi0"), /* DAT2DIR */
+	DB8500_PIN("GPIO22_AA3", in_nopull, "sdi0"), /* FBCLK */
+	DB8500_PIN("GPIO23_AA4", out_lo, "sdi0"), /* CLK */
+	DB8500_PIN("GPIO24_AB2", in_pu, "sdi0"), /* CMD */
+	DB8500_PIN("GPIO25_Y4", in_pu, "sdi0"), /* DAT0 */
+	DB8500_PIN("GPIO26_Y2", in_pu, "sdi0"), /* DAT1 */
+	DB8500_PIN("GPIO27_AA2", in_pu, "sdi0"), /* DAT2 */
+	DB8500_PIN("GPIO28_AA1", in_pu, "sdi0"), /* DAT3 */
+	/* Mux in SDI1 (here called MC1) used for SDIO for CW1200 WLAN */
+	DB8500_MUX("mc1_a_1", "mc1", "sdi1"),
+	DB8500_PIN("GPIO208_AH16", out_lo, "sdi1"), /* CLK */
+	DB8500_PIN("GPIO209_AG15", in_nopull, "sdi1"), /* FBCLK */
+	DB8500_PIN("GPIO210_AJ15", in_pu, "sdi1"), /* CMD */
+	DB8500_PIN("GPIO211_AG14", in_pu, "sdi1"), /* DAT0 */
+	DB8500_PIN("GPIO212_AF13", in_pu, "sdi1"), /* DAT1 */
+	DB8500_PIN("GPIO213_AG13", in_pu, "sdi1"), /* DAT2 */
+	DB8500_PIN("GPIO214_AH15", in_pu, "sdi1"), /* DAT3 */
+	/* Mux in SDI2 (here called MC2) used for for PoP eMMC */
+	DB8500_MUX("mc2_a_1", "mc2", "sdi2"),
+	DB8500_PIN("GPIO128_A5", out_lo, "sdi2"), /* CLK */
+	DB8500_PIN("GPIO129_B4", in_pu, "sdi2"), /* CMD */
+	DB8500_PIN("GPIO130_C8", in_nopull, "sdi2"), /* FBCLK */
+	DB8500_PIN("GPIO131_A12", in_pu, "sdi2"), /* DAT0 */
+	DB8500_PIN("GPIO132_C10", in_pu, "sdi2"), /* DAT1 */
+	DB8500_PIN("GPIO133_B10", in_pu, "sdi2"), /* DAT2 */
+	DB8500_PIN("GPIO134_B9", in_pu, "sdi2"), /* DAT3 */
+	DB8500_PIN("GPIO135_A9", in_pu, "sdi2"), /* DAT4 */
+	DB8500_PIN("GPIO136_C7", in_pu, "sdi2"), /* DAT5 */
+	DB8500_PIN("GPIO137_A7", in_pu, "sdi2"), /* DAT6 */
+	DB8500_PIN("GPIO138_C5", in_pu, "sdi2"), /* DAT7 */
+	/* Mux in SDI4 (here called MC4) used for for PCB-mounted eMMC */
+	DB8500_MUX("mc4_a_1", "mc4", "sdi4"),
+	DB8500_PIN("GPIO197_AH24", in_pu, "sdi4"), /* DAT3 */
+	DB8500_PIN("GPIO198_AG25", in_pu, "sdi4"), /* DAT2 */
+	DB8500_PIN("GPIO199_AH23", in_pu, "sdi4"), /* DAT1 */
+	DB8500_PIN("GPIO200_AH26", in_pu, "sdi4"), /* DAT0 */
+	DB8500_PIN("GPIO201_AF24", in_pu, "sdi4"), /* CMD */
+	DB8500_PIN("GPIO202_AF25", in_nopull, "sdi4"), /* FBCLK */
+	DB8500_PIN("GPIO203_AE23", out_lo, "sdi4"), /* CLK */
+	DB8500_PIN("GPIO204_AF23", in_pu, "sdi4"), /* DAT7 */
+	DB8500_PIN("GPIO205_AG23", in_pu, "sdi4"), /* DAT6 */
+	DB8500_PIN("GPIO206_AG24", in_pu, "sdi4"), /* DAT5 */
+	DB8500_PIN("GPIO207_AJ23", in_pu, "sdi4"), /* DAT4 */
+	/* Mux in USB pins, drive STP high */
+	DB8500_MUX("usb_a_1", "usb", "musb-ux500.0"),
+	DB8500_PIN("GPIO257_AE29", out_hi, "musb-ux500.0"), /* STP */
+	/* Mux in SPI2 pins on the "other C1" altfunction */
+	DB8500_MUX("spi2_oc1_1", "spi2", "spi2"),
+	DB8500_PIN("GPIO216_AG12", gpio_out_hi, "spi2"), /* FRM */
+	DB8500_PIN("GPIO218_AH11", in_pd, "spi2"), /* RXD */
+	DB8500_PIN("GPIO215_AH13", out_lo, "spi2"), /* TXD */
+	DB8500_PIN("GPIO217_AH12", out_lo, "spi2"), /* CLK */
 };
 
-static pin_cfg_t mop500_pins_default[] = {
-	/* SSP0 */
-	GPIO143_SSP0_CLK,
-	GPIO144_SSP0_FRM,
-	GPIO145_SSP0_RXD | PIN_PULL_DOWN,
-	GPIO146_SSP0_TXD,
-
-
-	GPIO217_GPIO	| PIN_INPUT_PULLUP, /* TC35892 IRQ */
-
-	/* SDI0 (MicroSD card) */
-	GPIO21_MC0_DAT31DIR	| PIN_OUTPUT_HIGH,
-
-	/* UART */
-	GPIO4_U1_RXD	| PIN_INPUT_PULLUP,
-	GPIO5_U1_TXD	| PIN_OUTPUT_HIGH,
-	GPIO6_U1_CTSn	| PIN_INPUT_PULLUP,
-	GPIO7_U1_RTSn	| PIN_OUTPUT_HIGH,
+/*
+ * These are specifically for the MOP500 and HREFP (pre-v60) version of the
+ * board, which utilized a TC35892 GPIO expander instead of using a lot of
+ * on-chip pins as the HREFv60 and later does.
+ */
+static struct pinctrl_map __initdata mop500_pinmap[] = {
+	/* Mux in SSP0, pull down RXD pin */
+	DB8500_MUX_HOG("ssp0_a_1", "ssp0"),
+	DB8500_PIN_HOG("GPIO145_C13", pd),
+	/*
+	 * XENON Flashgun on image processor GPIO (controlled from image
+	 * processor firmware), mux in these image processor GPIO lines 0
+	 * (XENON_FLASH_ID) and 1 (XENON_READY) on altfunction C and pull up
+	 * the pins.
+	 */
+	DB8500_MUX_HOG("ipgpio0_c_1", "ipgpio"),
+	DB8500_MUX_HOG("ipgpio1_c_1", "ipgpio"),
+	DB8500_PIN_HOG("GPIO6_AF6", in_pu),
+	DB8500_PIN_HOG("GPIO7_AG5", in_pu),
+	/* TC35892 IRQ, pull up the line, let the driver mux in the pin */
+	DB8500_PIN_HOG("GPIO217_AH12", gpio_in_pu),
+	/* Mux in UART1 and set the pull-ups */
+	DB8500_MUX_HOG("u1rxtx_a_1", "u1"),
+	DB8500_MUX_HOG("u1ctsrts_a_1", "u1"),
+	DB8500_PIN_HOG("GPIO4_AH6", in_pu), /* RXD */
+	DB8500_PIN_HOG("GPIO5_AG6", out_hi), /* TXD */
+	DB8500_PIN_HOG("GPIO6_AF6", in_pu), /* CTS */
+	DB8500_PIN_HOG("GPIO7_AG5", out_hi), /* RTS */
+	/*
+	 * Runtime stuff: make it possible to mux in the SKE keypad
+	 * and bias the pins
+	 */
+	DB8500_MUX("kp_a_2", "kp", "ske"),
+	DB8500_PIN("GPIO153_B17", in_pd_slpm_in_pu, "ske"), /* I7 */
+	DB8500_PIN("GPIO154_C16", in_pd_slpm_in_pu, "ske"), /* I6 */
+	DB8500_PIN("GPIO155_C19", in_pd_slpm_in_pu, "ske"), /* I5 */
+	DB8500_PIN("GPIO156_C17", in_pd_slpm_in_pu, "ske"), /* I4 */
+	DB8500_PIN("GPIO161_D21", in_pd_slpm_in_pu, "ske"), /* I3 */
+	DB8500_PIN("GPIO162_D20", in_pd_slpm_in_pu, "ske"), /* I2 */
+	DB8500_PIN("GPIO163_C20", in_pd_slpm_in_pu, "ske"), /* I1 */
+	DB8500_PIN("GPIO164_B21", in_pd_slpm_in_pu, "ske"), /* I0 */
+	DB8500_PIN("GPIO157_A18", in_pu_slpm_out_lo, "ske"), /* O7 */
+	DB8500_PIN("GPIO158_C18", in_pu_slpm_out_lo, "ske"), /* O6 */
+	DB8500_PIN("GPIO159_B19", in_pu_slpm_out_lo, "ske"), /* O5 */
+	DB8500_PIN("GPIO160_B20", in_pu_slpm_out_lo, "ske"), /* O4 */
+	DB8500_PIN("GPIO165_C21", in_pu_slpm_out_lo, "ske"), /* O3 */
+	DB8500_PIN("GPIO166_A22", in_pu_slpm_out_lo, "ske"), /* O2 */
+	DB8500_PIN("GPIO167_B24", in_pu_slpm_out_lo, "ske"), /* O1 */
+	DB8500_PIN("GPIO168_C22", in_pu_slpm_out_lo, "ske"), /* O0 */
+	/* Mux in and drive the SDI0 DAT31DIR line high at runtime */
+	DB8500_MUX("mc0dat31dir_a_1", "mc0", "sdi0"),
+	DB8500_PIN("GPIO21_AB3", out_hi, "sdi0"),
 };
 
-static pin_cfg_t hrefv60_pins[] = {
-	/* WLAN */
-	GPIO4_GPIO		| PIN_INPUT_PULLUP,/* WLAN_IRQ */
-	GPIO85_GPIO		| PIN_OUTPUT_LOW,/* WLAN_ENA */
-
-	/* XENON Flashgun INTERFACE */
-	GPIO6_IP_GPIO0	| PIN_INPUT_PULLUP,/* XENON_FLASH_ID */
-	GPIO7_IP_GPIO1	| PIN_INPUT_PULLUP,/* XENON_READY */
-	GPIO170_GPIO	| PIN_OUTPUT_LOW, /* XENON_CHARGE */
-
-	/* Assistant LED INTERFACE */
-	GPIO21_GPIO | PIN_OUTPUT_LOW,  /* XENON_EN1 */
-	GPIO64_IP_GPIO4 | PIN_OUTPUT_LOW,  /* XENON_EN2 */
-
-	/* Magnetometer */
-	GPIO31_GPIO | PIN_INPUT_PULLUP,  /* magnetometer_INT */
-	GPIO32_GPIO | PIN_INPUT_PULLDOWN, /* Magnetometer DRDY */
-
-	/* Display Interface */
-	GPIO65_GPIO		| PIN_OUTPUT_LOW, /* DISP1 RST */
-	GPIO66_GPIO		| PIN_OUTPUT_LOW, /* DISP2 RST */
-
-	/* Touch screen INTERFACE */
-	GPIO143_GPIO	| PIN_OUTPUT_LOW,/*TOUCH_RST1 */
-
-	/* Touch screen INTERFACE 2 */
-	GPIO67_GPIO	| PIN_INPUT_PULLUP, /* TOUCH_INT2 */
-	GPIO146_GPIO	| PIN_OUTPUT_LOW,/*TOUCH_RST2 */
-
-	/* ETM_PTM_TRACE INTERFACE */
-	GPIO70_GPIO	| PIN_OUTPUT_LOW,/* ETM_PTM_DATA23 */
-	GPIO71_GPIO	| PIN_OUTPUT_LOW,/* ETM_PTM_DATA22 */
-	GPIO72_GPIO	| PIN_OUTPUT_LOW,/* ETM_PTM_DATA21 */
-	GPIO73_GPIO	| PIN_OUTPUT_LOW,/* ETM_PTM_DATA20 */
-	GPIO74_GPIO	| PIN_OUTPUT_LOW,/* ETM_PTM_DATA19 */
-
-	/* NAHJ INTERFACE */
-	GPIO76_GPIO	| PIN_OUTPUT_LOW,/* NAHJ_CTRL */
-	GPIO216_GPIO	| PIN_OUTPUT_HIGH,/* NAHJ_CTRL_INV */
-
-	/* NFC INTERFACE */
-	GPIO77_GPIO	| PIN_OUTPUT_LOW, /* NFC_ENA */
-	GPIO144_GPIO	| PIN_INPUT_PULLDOWN, /* NFC_IRQ */
-	GPIO142_GPIO	| PIN_OUTPUT_LOW, /* NFC_RESET */
-
-	/* Keyboard MATRIX INTERFACE */
-	GPIO90_MC5_CMD	| PIN_OUTPUT_LOW, /* KP_O_1 */
-	GPIO87_MC5_DAT1	| PIN_OUTPUT_LOW, /* KP_O_2 */
-	GPIO86_MC5_DAT0	| PIN_OUTPUT_LOW, /* KP_O_3 */
-	GPIO96_KP_O6	| PIN_OUTPUT_LOW, /* KP_O_6 */
-	GPIO94_KP_O7	| PIN_OUTPUT_LOW, /* KP_O_7 */
-	GPIO93_MC5_DAT4	| PIN_INPUT_PULLUP, /* KP_I_0 */
-	GPIO89_MC5_DAT3	| PIN_INPUT_PULLUP, /* KP_I_2 */
-	GPIO88_MC5_DAT2	| PIN_INPUT_PULLUP, /* KP_I_3 */
-	GPIO91_GPIO	| PIN_INPUT_PULLUP, /* FORCE_SENSING_INT */
-	GPIO92_GPIO	| PIN_OUTPUT_LOW, /* FORCE_SENSING_RST */
-	GPIO97_GPIO	| PIN_OUTPUT_LOW, /* FORCE_SENSING_WU */
-
-	/* DiPro Sensor Interface */
-	GPIO139_GPIO	| PIN_INPUT_PULLUP, /* DIPRO_INT */
-
-	/* HAL SWITCH INTERFACE */
-	GPIO145_GPIO	| PIN_INPUT_PULLDOWN,/* HAL_SW */
-
-	/* Audio Amplifier Interface */
-	GPIO149_GPIO	| PIN_OUTPUT_LOW, /* VAUDIO_HF_EN */
-
-	/* GBF INTERFACE */
-	GPIO171_GPIO	| PIN_OUTPUT_LOW, /* GBF_ENA_RESET */
-
-	/* MSP : HDTV INTERFACE */
-	GPIO192_GPIO	| PIN_INPUT_PULLDOWN,
-
-	/* ACCELEROMETER_INTERFACE */
-	GPIO82_GPIO		| PIN_INPUT_PULLUP, /* ACC_INT1 */
-	GPIO83_GPIO		| PIN_INPUT_PULLUP, /* ACC_INT2 */
-
-	/* Proximity Sensor */
-	GPIO217_GPIO		| PIN_INPUT_PULLUP,
-
-
+/*
+ * The HREFv60 series of platforms is using available pins on the DB8500
+ * insteaf of the Toshiba I2C GPIO expander, reusing some pins like the SSP0
+ * and SSP1 ports (previously connected to the AB8500) as generic GPIO lines.
+ */
+static struct pinctrl_map __initdata hrefv60_pinmap[] = {
+	/* Drive WLAN_ENA low */
+	DB8500_PIN_HOG("GPIO85_D5", gpio_out_lo), /* WLAN_ENA */
+	/*
+	 * XENON Flashgun on image processor GPIO (controlled from image
+	 * processor firmware), mux in these image processor GPIO lines 0
+	 * (XENON_FLASH_ID), 1 (XENON_READY) and there is an assistant
+	 * LED on IP GPIO 4 (XENON_EN2) on altfunction C, that need bias
+	 * from GPIO21 so pull up 0, 1 and drive 4 and GPIO21 low as output.
+	 */
+	DB8500_MUX_HOG("ipgpio0_c_1", "ipgpio"),
+	DB8500_MUX_HOG("ipgpio1_c_1", "ipgpio"),
+	DB8500_MUX_HOG("ipgpio4_c_1", "ipgpio"),
+	DB8500_PIN_HOG("GPIO6_AF6", in_pu), /* XENON_FLASH_ID */
+	DB8500_PIN_HOG("GPIO7_AG5", in_pu), /* XENON_READY */
+	DB8500_PIN_HOG("GPIO21_AB3", gpio_out_lo), /* XENON_EN1 */
+	DB8500_PIN_HOG("GPIO64_F3", out_lo), /* XENON_EN2 */
+	/* Magnetometer uses GPIO 31 and 32, pull these up/down respectively */
+	DB8500_PIN_HOG("GPIO31_V3", gpio_in_pu), /* EN1 */
+	DB8500_PIN_HOG("GPIO32_V2", gpio_in_pd), /* DRDY */
+	/*
+	 * Display Interface 1 uses GPIO 65 for RST (reset).
+	 * Display Interface 2 uses GPIO 66 for RST (reset).
+	 * Drive DISP1 reset high (not reset), driver DISP2 reset low (reset)
+	 */
+	DB8500_PIN_HOG("GPIO65_F1", gpio_out_hi), /* DISP1 NO RST */
+	DB8500_PIN_HOG("GPIO66_G3", gpio_out_lo), /* DISP2 RST */
+	/*
+	 * Touch screen uses GPIO 143 for RST1, GPIO 146 for RST2 and
+	 * GPIO 67 for interrupts. Pull-up the IRQ line and drive both
+	 * reset signals low.
+	 */
+	DB8500_PIN_HOG("GPIO143_D12", gpio_out_lo), /* TOUCH_RST1 */
+	DB8500_PIN_HOG("GPIO67_G2", gpio_in_pu), /* TOUCH_INT2 */
+	DB8500_PIN_HOG("GPIO146_D13", gpio_out_lo), /* TOUCH_RST2 */
+	/*
+	 * Drive D19-D23 for the ETM PTM trace interface low,
+	 * (presumably pins are unconnected therefore grounded here,
+	 * the "other alt C1" setting enables these pins)
+	 */
+	DB8500_PIN_HOG("GPIO70_G5", gpio_out_lo),
+	DB8500_PIN_HOG("GPIO71_G4", gpio_out_lo),
+	DB8500_PIN_HOG("GPIO72_H4", gpio_out_lo),
+	DB8500_PIN_HOG("GPIO73_H3", gpio_out_lo),
+	DB8500_PIN_HOG("GPIO74_J3", gpio_out_lo),
+	/* NAHJ CTRL on GPIO 76 to low, CTRL_INV on GPIO216 to high */
+	DB8500_PIN_HOG("GPIO76_J2", gpio_out_lo), /* CTRL */
+	DB8500_PIN_HOG("GPIO216_AG12", gpio_out_hi), /* CTRL_INV */
+	/* NFC ENA and RESET to low, pulldown IRQ line */
+	DB8500_PIN_HOG("GPIO77_H1", gpio_out_lo), /* NFC_ENA */
+	DB8500_PIN_HOG("GPIO144_B13", gpio_in_pd), /* NFC_IRQ */
+	DB8500_PIN_HOG("GPIO142_C11", gpio_out_lo), /* NFC_RESET */
+	/*
+	 * SKE keyboard partly on alt A and partly on "Other alt C1"
+	 * Driver KP_O1,2,3,6,7 low and pull up KP_I 0,2,3 for three
+	 * rows of 6 keys, then pull up force sensing interrup and
+	 * drive reset and force sensing WU low.
+	 */
+	DB8500_MUX_HOG("kp_a_1", "kp"),
+	DB8500_MUX_HOG("kp_oc1_1", "kp"),
+	DB8500_PIN_HOG("GPIO90_A3", out_lo), /* KP_O1 */
+	DB8500_PIN_HOG("GPIO87_B3", out_lo), /* KP_O2 */
+	DB8500_PIN_HOG("GPIO86_C6", out_lo), /* KP_O3 */
+	DB8500_PIN_HOG("GPIO96_D8", out_lo), /* KP_O6 */
+	DB8500_PIN_HOG("GPIO94_D7", out_lo), /* KP_O7 */
+	DB8500_PIN_HOG("GPIO93_B7", in_pu), /* KP_I0 */
+	DB8500_PIN_HOG("GPIO89_E6", in_pu), /* KP_I2 */
+	DB8500_PIN_HOG("GPIO88_C4", in_pu), /* KP_I3 */
+	DB8500_PIN_HOG("GPIO91_B6", gpio_in_pu), /* FORCE_SENSING_INT */
+	DB8500_PIN_HOG("GPIO92_D6", gpio_out_lo), /* FORCE_SENSING_RST */
+	DB8500_PIN_HOG("GPIO97_D9", gpio_out_lo), /* FORCE_SENSING_WU */
+	/* DiPro Sensor interrupt */
+	DB8500_PIN_HOG("GPIO139_C9", gpio_in_pu), /* DIPRO_INT */
+	/* Audio Amplifier HF enable */
+	DB8500_PIN_HOG("GPIO149_B14", gpio_out_hi), /* VAUDIO_HF_EN, enable MAX8968 */
+	/* GBF interface, pull low to reset state */
+	DB8500_PIN_HOG("GPIO171_D23", gpio_out_lo), /* GBF_ENA_RESET */
+	/* MSP : HDTV INTERFACE GPIO line */
+	DB8500_PIN_HOG("GPIO192_AJ27", gpio_in_pd),
+	/* Accelerometer interrupt lines */
+	DB8500_PIN_HOG("GPIO82_C1", gpio_in_pu), /* ACC_INT1 */
+	DB8500_PIN_HOG("GPIO83_D3", gpio_in_pu), /* ACC_INT2 */
+	/* SD card detect GPIO pin */
+	DB8500_PIN_HOG("GPIO95_E8", gpio_in_pu),
+	/*
+	 * Runtime stuff
+	 * Pull up/down of some sensor GPIO pins, for proximity, HAL sensor
+	 * etc.
+	 */
+	DB8500_PIN("GPIO217_AH12", gpio_in_pu_slpm_gpio_nopull, "gpio-keys.0"),
+	DB8500_PIN("GPIO145_C13", gpio_in_pd_slpm_gpio_nopull, "gpio-keys.0"),
+	DB8500_PIN("GPIO139_C9", gpio_in_pu_slpm_gpio_nopull, "gpio-keys.0"),
+	/*
+	 * Make it possible to mux in the SKE keypad and bias the pins
+	 * FIXME: what's the point with this on HREFv60? KP/SKE is already
+	 * muxed in at another place! Enabling this will bork.
+	 */
+	DB8500_MUX("kp_a_2", "kp", "ske"),
+	DB8500_PIN("GPIO153_B17", in_pd_slpm_in_pu, "ske"), /* I7 */
+	DB8500_PIN("GPIO154_C16", in_pd_slpm_in_pu, "ske"), /* I6 */
+	DB8500_PIN("GPIO155_C19", in_pd_slpm_in_pu, "ske"), /* I5 */
+	DB8500_PIN("GPIO156_C17", in_pd_slpm_in_pu, "ske"), /* I4 */
+	DB8500_PIN("GPIO161_D21", in_pd_slpm_in_pu, "ske"), /* I3 */
+	DB8500_PIN("GPIO162_D20", in_pd_slpm_in_pu, "ske"), /* I2 */
+	DB8500_PIN("GPIO163_C20", in_pd_slpm_in_pu, "ske"), /* I1 */
+	DB8500_PIN("GPIO164_B21", in_pd_slpm_in_pu, "ske"), /* I0 */
+	DB8500_PIN("GPIO157_A18", in_pu_slpm_out_lo, "ske"), /* O7 */
+	DB8500_PIN("GPIO158_C18", in_pu_slpm_out_lo, "ske"), /* O6 */
+	DB8500_PIN("GPIO159_B19", in_pu_slpm_out_lo, "ske"), /* O5 */
+	DB8500_PIN("GPIO160_B20", in_pu_slpm_out_lo, "ske"), /* O4 */
+	DB8500_PIN("GPIO165_C21", in_pu_slpm_out_lo, "ske"), /* O3 */
+	DB8500_PIN("GPIO166_A22", in_pu_slpm_out_lo, "ske"), /* O2 */
+	DB8500_PIN("GPIO167_B24", in_pu_slpm_out_lo, "ske"), /* O1 */
+	DB8500_PIN("GPIO168_C22", in_pu_slpm_out_lo, "ske"), /* O0 */
 };
 
-static pin_cfg_t snowball_pins[] = {
-	/* SSP0, to AB8500 */
-	GPIO143_SSP0_CLK,
-	GPIO144_SSP0_FRM,
-	GPIO145_SSP0_RXD	| PIN_PULL_DOWN,
-	GPIO146_SSP0_TXD,
-
-	/* MMC0: MicroSD card */
-	GPIO21_MC0_DAT31DIR     | PIN_OUTPUT_HIGH,
-
-	/* MMC2: LAN */
-	GPIO86_SM_ADQ0,
-	GPIO87_SM_ADQ1,
-	GPIO88_SM_ADQ2,
-	GPIO89_SM_ADQ3,
-	GPIO90_SM_ADQ4,
-	GPIO91_SM_ADQ5,
-	GPIO92_SM_ADQ6,
-	GPIO93_SM_ADQ7,
-
-	GPIO94_SM_ADVn,
-	GPIO95_SM_CS0n,
-	GPIO96_SM_OEn,
-	GPIO97_SM_WEn,
-
-	GPIO128_SM_CKO,
-	GPIO130_SM_FBCLK,
-	GPIO131_SM_ADQ8,
-	GPIO132_SM_ADQ9,
-	GPIO133_SM_ADQ10,
-	GPIO134_SM_ADQ11,
-	GPIO135_SM_ADQ12,
-	GPIO136_SM_ADQ13,
-	GPIO137_SM_ADQ14,
-	GPIO138_SM_ADQ15,
-
-	/* RSTn_LAN */
-	GPIO141_GPIO		| PIN_OUTPUT_HIGH,
+static struct pinctrl_map __initdata u9500_pinmap[] = {
+	/* Mux in UART1 (just RX/TX) and set the pull-ups */
+	DB8500_MUX_HOG("u1rxtx_a_1", "u1"),
+	DB8500_PIN_HOG("GPIO4_AH6", in_pu),
+	DB8500_PIN_HOG("GPIO5_AG6", out_hi),
+	/* WLAN_IRQ line */
+	DB8500_PIN_HOG("GPIO144_B13", gpio_in_pu),
+	/* HSI */
+	DB8500_MUX_HOG("hsir_a_1", "hsi"),
+	DB8500_MUX_HOG("hsit_a_1", "hsi"),
+	DB8500_PIN_HOG("GPIO219_AG10", in_pd), /* RX FLA0 */
+	DB8500_PIN_HOG("GPIO220_AH10", in_pd), /* RX DAT0 */
+	DB8500_PIN_HOG("GPIO221_AJ11", out_lo), /* RX RDY0 */
+	DB8500_PIN_HOG("GPIO222_AJ9", out_lo), /* TX FLA0 */
+	DB8500_PIN_HOG("GPIO223_AH9", out_lo), /* TX DAT0 */
+	DB8500_PIN_HOG("GPIO224_AG9", in_pd), /* TX RDY0 */
+	DB8500_PIN_HOG("GPIO225_AG8", in_pd), /* CAWAKE0 */
+	DB8500_PIN_HOG("GPIO226_AF8", out_hi), /* ACWAKE0 */
 };
 
-void __init mop500_pins_init(void)
+static struct pinctrl_map __initdata u8500_pinmap[] = {
+	DB8500_PIN_HOG("GPIO226_AF8", gpio_out_lo), /* WLAN_PMU_EN */
+	DB8500_PIN_HOG("GPIO4_AH6", gpio_in_pu), /* WLAN_IRQ */
+};
+
+static struct pinctrl_map __initdata snowball_pinmap[] = {
+	/* Mux in SSP0 connected to AB8500, pull down RXD pin */
+	DB8500_MUX_HOG("ssp0_a_1", "ssp0"),
+	DB8500_PIN_HOG("GPIO145_C13", pd),
+	/* Always drive the MC0 DAT31DIR line high on these boards */
+	DB8500_PIN_HOG("GPIO21_AB3", out_hi),
+	/* Mux in "SM" which is used for the SMSC911x Ethernet adapter */
+	DB8500_MUX_HOG("sm_b_1", "sm"),
+	/* Drive RSTn_LAN high */
+	DB8500_PIN_HOG("GPIO141_C12", gpio_out_hi),
+	/*  Accelerometer/Magnetometer */
+	DB8500_PIN_HOG("GPIO163_C20", gpio_in_pu), /* ACCEL_IRQ1 */
+	DB8500_PIN_HOG("GPIO164_B21", gpio_in_pu), /* ACCEL_IRQ2 */
+	DB8500_PIN_HOG("GPIO165_C21", gpio_in_pu), /* MAG_DRDY */
+	/* WLAN/GBF */
+	DB8500_PIN_HOG("GPIO161_D21", gpio_out_lo), /* WLAN_PMU_EN */
+	DB8500_PIN_HOG("GPIO171_D23", gpio_out_hi), /* GBF_ENA */
+	DB8500_PIN_HOG("GPIO215_AH13", gpio_out_lo), /* WLAN_ENA */
+	DB8500_PIN_HOG("GPIO216_AG12", gpio_in_pu), /* WLAN_IRQ */
+};
+
+/*
+ * passing "pinsfor=" in kernel cmdline allows for custom
+ * configuration of GPIOs on u8500 derived boards.
+ */
+static int __init early_pinsfor(char *p)
 {
-	nmk_config_pins(mop500_pins_common,
-			ARRAY_SIZE(mop500_pins_common));
+	pinsfor = PINS_FOR_DEFAULT;
 
-	nmk_config_pins(mop500_pins_default,
-			ARRAY_SIZE(mop500_pins_default));
+	if (strcmp(p, "u9500-21") == 0)
+		pinsfor = PINS_FOR_U9500;
+
+	return 0;
+}
+early_param("pinsfor", early_pinsfor);
+
+int pins_for_u9500(void)
+{
+	if (pinsfor == PINS_FOR_U9500)
+		return 1;
+
+	return 0;
 }
 
-void __init snowball_pins_init(void)
+static void __init mop500_href_family_pinmaps_init(void)
 {
-	nmk_config_pins(mop500_pins_common,
-			ARRAY_SIZE(mop500_pins_common));
-
-	nmk_config_pins(snowball_pins,
-			ARRAY_SIZE(snowball_pins));
+	switch (pinsfor) {
+	case PINS_FOR_U9500:
+		pinctrl_register_mappings(u9500_pinmap,
+					  ARRAY_SIZE(u9500_pinmap));
+		break;
+	case PINS_FOR_DEFAULT:
+		pinctrl_register_mappings(u8500_pinmap,
+					  ARRAY_SIZE(u8500_pinmap));
+	default:
+		break;
+	}
 }
 
-void __init hrefv60_pins_init(void)
+void __init mop500_pinmaps_init(void)
 {
-	nmk_config_pins(mop500_pins_common,
-			ARRAY_SIZE(mop500_pins_common));
+	pinctrl_register_mappings(mop500_family_pinmap,
+				  ARRAY_SIZE(mop500_family_pinmap));
+	pinctrl_register_mappings(mop500_pinmap,
+				  ARRAY_SIZE(mop500_pinmap));
+	mop500_href_family_pinmaps_init();
+}
 
-	nmk_config_pins(hrefv60_pins,
-			ARRAY_SIZE(hrefv60_pins));
+void __init snowball_pinmaps_init(void)
+{
+	pinctrl_register_mappings(mop500_family_pinmap,
+				  ARRAY_SIZE(mop500_family_pinmap));
+	pinctrl_register_mappings(snowball_pinmap,
+				  ARRAY_SIZE(snowball_pinmap));
+	pinctrl_register_mappings(u8500_pinmap,
+				  ARRAY_SIZE(u8500_pinmap));
+}
+
+void __init hrefv60_pinmaps_init(void)
+{
+	pinctrl_register_mappings(mop500_family_pinmap,
+				  ARRAY_SIZE(mop500_family_pinmap));
+	pinctrl_register_mappings(hrefv60_pinmap,
+				  ARRAY_SIZE(hrefv60_pinmap));
+	mop500_href_family_pinmaps_init();
 }
diff --git a/arch/arm/mach-ux500/board-mop500-uib.c b/arch/arm/mach-ux500/board-mop500-uib.c
index 5af36aa..b29a788 100644
--- a/arch/arm/mach-ux500/board-mop500-uib.c
+++ b/arch/arm/mach-ux500/board-mop500-uib.c
@@ -102,7 +102,7 @@
 	struct i2c_adapter *i2c0;
 	int ret;
 
-	if (!cpu_is_u8500())
+	if (!cpu_is_u8500_family())
 		return -ENODEV;
 
 	if (uib) {
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 77d03c1..f943687 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2008-2009 ST-Ericsson
  *
@@ -29,30 +30,30 @@
 #include <linux/smsc911x.h>
 #include <linux/gpio_keys.h>
 #include <linux/delay.h>
-
 #include <linux/of.h>
 #include <linux/of_platform.h>
-
 #include <linux/leds.h>
+#include <linux/pinctrl/consumer.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
 
 #include <plat/i2c.h>
 #include <plat/ste_dma40.h>
-#include <plat/pincfg.h>
 #include <plat/gpio-nomadik.h>
 
 #include <mach/hardware.h>
 #include <mach/setup.h>
 #include <mach/devices.h>
 #include <mach/irqs.h>
+#include <mach/crypto-ux500.h>
 
-#include "pins-db8500.h"
 #include "ste-dma40-db8500.h"
 #include "devices-db8500.h"
 #include "board-mop500.h"
 #include "board-mop500-regulators.h"
+#include "board-mop500-msp.h"
 
 static struct gpio_led snowball_led_array[] = {
 	{
@@ -417,6 +418,45 @@
 	regulator_put(prox_regulator);
 }
 
+static struct cryp_platform_data u8500_cryp1_platform_data = {
+		.mem_to_engine = {
+				.dir = STEDMA40_MEM_TO_PERIPH,
+				.src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+				.dst_dev_type = DB8500_DMA_DEV48_CAC1_TX,
+				.src_info.data_width = STEDMA40_WORD_WIDTH,
+				.dst_info.data_width = STEDMA40_WORD_WIDTH,
+				.mode = STEDMA40_MODE_LOGICAL,
+				.src_info.psize = STEDMA40_PSIZE_LOG_4,
+				.dst_info.psize = STEDMA40_PSIZE_LOG_4,
+		},
+		.engine_to_mem = {
+				.dir = STEDMA40_PERIPH_TO_MEM,
+				.src_dev_type = DB8500_DMA_DEV48_CAC1_RX,
+				.dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+				.src_info.data_width = STEDMA40_WORD_WIDTH,
+				.dst_info.data_width = STEDMA40_WORD_WIDTH,
+				.mode = STEDMA40_MODE_LOGICAL,
+				.src_info.psize = STEDMA40_PSIZE_LOG_4,
+				.dst_info.psize = STEDMA40_PSIZE_LOG_4,
+		}
+};
+
+static struct stedma40_chan_cfg u8500_hash_dma_cfg_tx = {
+		.dir = STEDMA40_MEM_TO_PERIPH,
+		.src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+		.dst_dev_type = DB8500_DMA_DEV50_HAC1_TX,
+		.src_info.data_width = STEDMA40_WORD_WIDTH,
+		.dst_info.data_width = STEDMA40_WORD_WIDTH,
+		.mode = STEDMA40_MODE_LOGICAL,
+		.src_info.psize = STEDMA40_PSIZE_LOG_16,
+		.dst_info.psize = STEDMA40_PSIZE_LOG_16,
+};
+
+static struct hash_platform_data u8500_hash1_platform_data = {
+		.mem_to_engine = &u8500_hash_dma_cfg_tx,
+		.dma_filter = stedma40_filter,
+};
+
 /* add any platform devices here - TODO */
 static struct platform_device *mop500_platform_devs[] __initdata = {
 	&mop500_gpio_keys_device,
@@ -520,14 +560,6 @@
 };
 #endif
 
-
-static pin_cfg_t mop500_pins_uart0[] = {
-	GPIO0_U0_CTSn   | PIN_INPUT_PULLUP,
-	GPIO1_U0_RTSn   | PIN_OUTPUT_HIGH,
-	GPIO2_U0_RXD    | PIN_INPUT_PULLUP,
-	GPIO3_U0_TXD    | PIN_OUTPUT_HIGH,
-};
-
 #define PRCC_K_SOFTRST_SET      0x18
 #define PRCC_K_SOFTRST_CLEAR    0x1C
 static void ux500_uart0_reset(void)
@@ -548,24 +580,33 @@
 	udelay(1);
 }
 
+/* This needs to be referenced by callbacks */
+struct pinctrl *u0_p;
+struct pinctrl_state *u0_def;
+struct pinctrl_state *u0_sleep;
+
 static void ux500_uart0_init(void)
 {
 	int ret;
 
-	ret = nmk_config_pins(mop500_pins_uart0,
-			ARRAY_SIZE(mop500_pins_uart0));
-	if (ret < 0)
-		pr_err("pl011: uart pins_enable failed\n");
+	if (IS_ERR(u0_p) || IS_ERR(u0_def))
+		return;
+
+	ret = pinctrl_select_state(u0_p, u0_def);
+	if (ret)
+		pr_err("could not set UART0 defstate\n");
 }
 
 static void ux500_uart0_exit(void)
 {
 	int ret;
 
-	ret = nmk_config_pins_sleep(mop500_pins_uart0,
-			ARRAY_SIZE(mop500_pins_uart0));
-	if (ret < 0)
-		pr_err("pl011: uart pins_disable failed\n");
+	if (IS_ERR(u0_p) || IS_ERR(u0_sleep))
+		return;
+
+	ret = pinctrl_select_state(u0_p, u0_sleep);
+	if (ret)
+		pr_err("could not set UART0 idlestate\n");
 }
 
 static struct amba_pl011_data uart0_plat = {
@@ -597,15 +638,41 @@
 
 static void __init mop500_uart_init(struct device *parent)
 {
-	db8500_add_uart0(parent, &uart0_plat);
+	struct amba_device *uart0_device;
+
+	uart0_device = db8500_add_uart0(parent, &uart0_plat);
+	if (uart0_device) {
+		u0_p = pinctrl_get(&uart0_device->dev);
+		if (IS_ERR(u0_p))
+			dev_err(&uart0_device->dev,
+				"could not get UART0 pinctrl\n");
+		else {
+			u0_def = pinctrl_lookup_state(u0_p,
+						      PINCTRL_STATE_DEFAULT);
+			if (IS_ERR(u0_def)) {
+				dev_err(&uart0_device->dev,
+					"could not get UART0 defstate\n");
+			}
+			u0_sleep = pinctrl_lookup_state(u0_p,
+							PINCTRL_STATE_SLEEP);
+			if (IS_ERR(u0_sleep))
+				dev_err(&uart0_device->dev,
+					"could not get UART0 idlestate\n");
+		}
+	}
 	db8500_add_uart1(parent, &uart1_plat);
 	db8500_add_uart2(parent, &uart2_plat);
 }
 
+static void __init u8500_cryp1_hash1_init(struct device *parent)
+{
+	db8500_add_cryp1(parent, &u8500_cryp1_platform_data);
+	db8500_add_hash1(parent, &u8500_hash1_platform_data);
+}
+
 static struct platform_device *snowball_platform_devs[] __initdata = {
 	&snowball_led_dev,
 	&snowball_key_dev,
-	&snowball_sbnet_dev,
 	&ab8500_device,
 };
 
@@ -617,10 +684,9 @@
 
 	mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
 
+	mop500_pinmaps_init();
 	parent = u8500_init_devices();
 
-	mop500_pins_init();
-
 	/* FIXME: parent of ab8500 should be prcmu */
 	for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
 		mop500_platform_devs[i]->dev.parent = parent;
@@ -631,8 +697,11 @@
 	mop500_i2c_init(parent);
 	mop500_sdi_init(parent);
 	mop500_spi_init(parent);
+	mop500_msp_init(parent);
 	mop500_uart_init(parent);
 
+	u8500_cryp1_hash1_init(parent);
+
 	i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
 
 	i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
@@ -646,13 +715,11 @@
 static void __init snowball_init_machine(void)
 {
 	struct device *parent = NULL;
-	int i2c0_devs;
 	int i;
 
+	snowball_pinmaps_init();
 	parent = u8500_init_devices();
 
-	snowball_pins_init();
-
 	for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++)
 		snowball_platform_devs[i]->dev.parent = parent;
 
@@ -662,13 +729,9 @@
 	mop500_i2c_init(parent);
 	snowball_sdi_init(parent);
 	mop500_spi_init(parent);
+	mop500_msp_init(parent);
 	mop500_uart_init(parent);
 
-	i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
-	i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
-	i2c_register_board_info(2, mop500_i2c2_devices,
-				ARRAY_SIZE(mop500_i2c2_devices));
-
 	/* This board has full regulator constraints */
 	regulator_has_full_constraints();
 }
@@ -686,10 +749,9 @@
 	 */
 	mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
 
+	hrefv60_pinmaps_init();
 	parent = u8500_init_devices();
 
-	hrefv60_pins_init();
-
 	for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
 		mop500_platform_devs[i]->dev.parent = parent;
 
@@ -699,6 +761,7 @@
 	mop500_i2c_init(parent);
 	hrefv60_sdi_init(parent);
 	mop500_spi_init(parent);
+	mop500_msp_init(parent);
 	mop500_uart_init(parent);
 
 	i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
@@ -746,16 +809,29 @@
 #ifdef CONFIG_MACH_UX500_DT
 
 struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
+	/* Requires DMA and call-back bindings. */
 	OF_DEV_AUXDATA("arm,pl011", 0x80120000, "uart0", &uart0_plat),
 	OF_DEV_AUXDATA("arm,pl011", 0x80121000, "uart1", &uart1_plat),
 	OF_DEV_AUXDATA("arm,pl011", 0x80007000, "uart2", &uart2_plat),
+	/* Requires DMA bindings. */
 	OF_DEV_AUXDATA("arm,pl022", 0x80002000, "ssp0",  &ssp0_plat),
+	/* Requires clock name bindings. */
+	OF_DEV_AUXDATA("st,nomadik-gpio", 0x8012e000, "gpio.0", NULL),
+	OF_DEV_AUXDATA("st,nomadik-gpio", 0x8012e080, "gpio.1", NULL),
+	OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e000, "gpio.2", NULL),
+	OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e080, "gpio.3", NULL),
+	OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e100, "gpio.4", NULL),
+	OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e180, "gpio.5", NULL),
+	OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e000, "gpio.6", NULL),
+	OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e080, "gpio.7", NULL),
+	OF_DEV_AUXDATA("st,nomadik-gpio", 0xa03fe000, "gpio.8", NULL),
 	{},
 };
 
-static const struct of_device_id u8500_soc_node[] = {
+static const struct of_device_id u8500_local_bus_nodes[] = {
 	/* only create devices below soc node */
 	{ .compatible = "stericsson,db8500", },
+	{ .compatible = "simple-bus"},
 	{ },
 };
 
@@ -765,8 +841,15 @@
 	int i2c0_devs;
 	int i;
 
+	/* Pinmaps must be in place before devices register */
+	if (of_machine_is_compatible("st-ericsson,mop500"))
+		mop500_pinmaps_init();
+	else if (of_machine_is_compatible("calaosystems,snowball-a9500"))
+		snowball_pinmaps_init();
+	else if (of_machine_is_compatible("st-ericsson,hrefv60+"))
+		hrefv60_pinmaps_init();
+
 	parent = u8500_init_devices();
-	i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
 
 	for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
 		mop500_platform_devs[i]->dev.parent = parent;
@@ -774,18 +857,22 @@
 		snowball_platform_devs[i]->dev.parent = parent;
 
 	/* automatically probe child nodes of db8500 device */
-	of_platform_populate(NULL, u8500_soc_node, u8500_auxdata_lookup, parent);
+	of_platform_populate(NULL, u8500_local_bus_nodes, u8500_auxdata_lookup, parent);
 
 	if (of_machine_is_compatible("st-ericsson,mop500")) {
 		mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
-		mop500_pins_init();
 
 		platform_add_devices(mop500_platform_devs,
 				ARRAY_SIZE(mop500_platform_devs));
 
 		mop500_sdi_init(parent);
+
+		i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
+		i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
+		i2c_register_board_info(2, mop500_i2c2_devices,
+					ARRAY_SIZE(mop500_i2c2_devices));
+
 	} else if (of_machine_is_compatible("calaosystems,snowball-a9500")) {
-		snowball_pins_init();
 		platform_add_devices(snowball_platform_devs,
 				ARRAY_SIZE(snowball_platform_devs));
 
@@ -797,19 +884,20 @@
 		 * instead.
 		 */
 		mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
-		i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES;
-		hrefv60_pins_init();
 		platform_add_devices(mop500_platform_devs,
 				ARRAY_SIZE(mop500_platform_devs));
 
 		hrefv60_sdi_init(parent);
+
+		i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
+		i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES;
+
+		i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
+		i2c_register_board_info(2, mop500_i2c2_devices,
+					ARRAY_SIZE(mop500_i2c2_devices));
 	}
 	mop500_i2c_init(parent);
 
-	i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
-	i2c_register_board_info(2, mop500_i2c2_devices,
-				ARRAY_SIZE(mop500_i2c2_devices));
-
 	/* This board has full regulator constraints */
 	regulator_has_full_constraints();
 }
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h
index fdcfa87..bc44c07 100644
--- a/arch/arm/mach-ux500/board-mop500.h
+++ b/arch/arm/mach-ux500/board-mop500.h
@@ -7,6 +7,9 @@
 #ifndef __BOARD_MOP500_H
 #define __BOARD_MOP500_H
 
+/* For NOMADIK_NR_GPIO */
+#include <mach/irqs.h>
+
 /* Snowball specific GPIO assignments, this board has no GPIO expander */
 #define SNOWBALL_ACCEL_INT1_GPIO	163
 #define SNOWBALL_ACCEL_INT2_GPIO	164
@@ -73,6 +76,7 @@
 #define SNOWBALL_PME_ETH_GPIO		MOP500_AB8500_PIN_GPIO(24)	/* SYSCLKREQ7/GPIO24 */
 #define SNOWBALL_EN_3V3_ETH_GPIO	MOP500_AB8500_PIN_GPIO(26)	/* GPIO26 */
 
+struct device;
 struct i2c_board_info;
 
 extern void mop500_sdi_init(struct device *parent);
@@ -81,9 +85,9 @@
 extern void mop500_sdi_tc35892_init(struct device *parent);
 void __init mop500_u8500uib_init(void);
 void __init mop500_stuib_init(void);
-void __init mop500_pins_init(void);
-void __init hrefv60_pins_init(void);
-void __init snowball_pins_init(void);
+void __init mop500_pinmaps_init(void);
+void __init snowball_pinmaps_init(void);
+void __init hrefv60_pinmaps_init(void);
 
 void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info,
 		unsigned n);
diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c
deleted file mode 100644
index 836112e..0000000
--- a/arch/arm/mach-ux500/board-u5500-sdi.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Hanumath Prasad <ulf.hansson@stericsson.com>
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/amba/mmci.h>
-#include <linux/mmc/host.h>
-
-#include <plat/pincfg.h>
-#include <plat/gpio-nomadik.h>
-#include <mach/db5500-regs.h>
-#include <plat/ste_dma40.h>
-
-#include "pins-db5500.h"
-#include "devices-db5500.h"
-#include "ste-dma40-db5500.h"
-
-static pin_cfg_t u5500_sdi_pins[] = {
-	/* SDI0 (POP eMMC) */
-	GPIO5_MC0_DAT0		| PIN_DIR_INPUT | PIN_PULL_UP,
-	GPIO6_MC0_DAT1		| PIN_DIR_INPUT | PIN_PULL_UP,
-	GPIO7_MC0_DAT2		| PIN_DIR_INPUT | PIN_PULL_UP,
-	GPIO8_MC0_DAT3		| PIN_DIR_INPUT | PIN_PULL_UP,
-	GPIO9_MC0_DAT4		| PIN_DIR_INPUT | PIN_PULL_UP,
-	GPIO10_MC0_DAT5		| PIN_DIR_INPUT | PIN_PULL_UP,
-	GPIO11_MC0_DAT6		| PIN_DIR_INPUT | PIN_PULL_UP,
-	GPIO12_MC0_DAT7		| PIN_DIR_INPUT | PIN_PULL_UP,
-	GPIO13_MC0_CMD		| PIN_DIR_INPUT | PIN_PULL_UP,
-	GPIO14_MC0_CLK		| PIN_DIR_OUTPUT | PIN_VAL_LOW,
-};
-
-#ifdef CONFIG_STE_DMA40
-struct stedma40_chan_cfg u5500_sdi0_dma_cfg_rx = {
-	.mode = STEDMA40_MODE_LOGICAL,
-	.dir = STEDMA40_PERIPH_TO_MEM,
-	.src_dev_type = DB5500_DMA_DEV24_SDMMC0_RX,
-	.dst_dev_type = STEDMA40_DEV_DST_MEMORY,
-	.src_info.data_width = STEDMA40_WORD_WIDTH,
-	.dst_info.data_width = STEDMA40_WORD_WIDTH,
-};
-
-static struct stedma40_chan_cfg u5500_sdi0_dma_cfg_tx = {
-	.mode = STEDMA40_MODE_LOGICAL,
-	.dir = STEDMA40_MEM_TO_PERIPH,
-	.src_dev_type = STEDMA40_DEV_SRC_MEMORY,
-	.dst_dev_type = DB5500_DMA_DEV24_SDMMC0_TX,
-	.src_info.data_width = STEDMA40_WORD_WIDTH,
-	.dst_info.data_width = STEDMA40_WORD_WIDTH,
-};
-#endif
-
-static struct mmci_platform_data u5500_sdi0_data = {
-	.ocr_mask	= MMC_VDD_165_195,
-	.f_max		= 50000000,
-	.capabilities	= MMC_CAP_4_BIT_DATA |
-				MMC_CAP_8_BIT_DATA |
-				MMC_CAP_MMC_HIGHSPEED,
-	.gpio_cd	= -1,
-	.gpio_wp	= -1,
-#ifdef CONFIG_STE_DMA40
-	.dma_filter	= stedma40_filter,
-	.dma_rx_param	= &u5500_sdi0_dma_cfg_rx,
-	.dma_tx_param	= &u5500_sdi0_dma_cfg_tx,
-#endif
-};
-
-void __init u5500_sdi_init(struct device *parent)
-{
-	nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins));
-
-	db5500_add_sdi0(parent, &u5500_sdi0_data);
-}
diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c
deleted file mode 100644
index 0ff4be7..0000000
--- a/arch/arm/mach-ux500/board-u5500.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <linux/irq.h>
-#include <linux/i2c.h>
-#include <linux/mfd/abx500/ab5500.h>
-
-#include <asm/hardware/gic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-
-#include <plat/pincfg.h>
-#include <plat/i2c.h>
-#include <plat/gpio-nomadik.h>
-
-#include <mach/hardware.h>
-#include <mach/devices.h>
-#include <mach/setup.h>
-
-#include "pins-db5500.h"
-#include "devices-db5500.h"
-#include <linux/led-lm3530.h>
-
-/*
- * GPIO
- */
-
-static pin_cfg_t u5500_pins[] = {
-	/* I2C */
-	GPIO218_I2C2_SCL        | PIN_INPUT_PULLUP,
-	GPIO219_I2C2_SDA        | PIN_INPUT_PULLUP,
-
-	/* DISPLAY_ENABLE */
-	GPIO226_GPIO        | PIN_OUTPUT_LOW,
-
-	/* Backlight Enbale */
-	GPIO224_GPIO        | PIN_OUTPUT_HIGH,
-};
-/*
- * I2C
- */
-
-#define U5500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
-static struct nmk_i2c_controller u5500_i2c##id##_data = { \
-	/*				\
-	 * slave data setup time, which is	\
-	 * 250 ns,100ns,10ns which is 14,6,2	\
-	 * respectively for a 48 Mhz	\
-	 * i2c clock			\
-	 */				\
-	.slsu		= _slsu,	\
-	/* Tx FIFO threshold */		\
-	.tft		= _tft,		\
-	/* Rx FIFO threshold */		\
-	.rft		= _rft,		\
-	/* std. mode operation */	\
-	.clk_freq	= clk,		\
-	.sm		= _sm,		\
-}
-/*
- * The board uses TODO <3> i2c controllers, initialize all of
- * them with slave data setup time of 250 ns,
- * Tx & Rx FIFO threshold values as 1 and standard
- * mode of operation
- */
-
-U5500_I2C_CONTROLLER(2,	0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
-
-static struct lm3530_platform_data u5500_als_platform_data = {
-	.mode = LM3530_BL_MODE_MANUAL,
-	.als_input_mode = LM3530_INPUT_ALS1,
-	.max_current = LM3530_FS_CURR_26mA,
-	.pwm_pol_hi = true,
-	.als_avrg_time = LM3530_ALS_AVRG_TIME_512ms,
-	.brt_ramp_law = 1,      /* Linear */
-	.brt_ramp_fall = LM3530_RAMP_TIME_8s,
-	.brt_ramp_rise = LM3530_RAMP_TIME_8s,
-	.als1_resistor_sel = LM3530_ALS_IMPD_13_53kOhm,
-	.als2_resistor_sel = LM3530_ALS_IMPD_Z,
-	.als_vmin = 730,	/* mV */
-	.als_vmax = 1020,	/* mV */
-	.brt_val = 0x7F,	/* Max brightness */
-};
-
-static struct i2c_board_info __initdata u5500_i2c2_devices[] = {
-	{
-		/* Backlight */
-		I2C_BOARD_INFO("lm3530-led", 0x36),
-		.platform_data = &u5500_als_platform_data,
-	},
-};
-
-static void __init u5500_i2c_init(struct device *parent)
-{
-	db5500_add_i2c2(parent, &u5500_i2c2_data);
-	i2c_register_board_info(2, ARRAY_AND_SIZE(u5500_i2c2_devices));
-}
-
-static struct ab5500_platform_data ab5500_plf_data = {
-	.irq = {
-		.base = 0,
-		.count = 0,
-	},
-	.init_settings = NULL,
-	.init_settings_sz = 0,
-	.pm_power_off = false,
-};
-
-static struct platform_device ab5500_device = {
-	.name = "ab5500-core",
-	.id = 0,
-	.dev = {
-		.platform_data = &ab5500_plf_data,
-	},
-	.num_resources = 0,
-};
-
-static struct platform_device *u5500_platform_devices[] __initdata = {
-	&ab5500_device,
-};
-
-static void __init u5500_uart_init(struct device *parent)
-{
-	db5500_add_uart0(parent, NULL);
-	db5500_add_uart1(parent, NULL);
-	db5500_add_uart2(parent, NULL);
-}
-
-static void __init u5500_init_machine(void)
-{
-	struct device *parent = NULL;
-	int i;
-
-	parent = u5500_init_devices();
-	nmk_config_pins(u5500_pins, ARRAY_SIZE(u5500_pins));
-
-	u5500_i2c_init(parent);
-	u5500_sdi_init(parent);
-	u5500_uart_init(parent);
-
-	for (i = 0; i < ARRAY_SIZE(u5500_platform_devices); i++)
-		u5500_platform_devices[i]->dev.parent = parent;
-
-	platform_add_devices(u5500_platform_devices,
-		ARRAY_SIZE(u5500_platform_devices));
-}
-
-MACHINE_START(U5500, "ST-Ericsson U5500 Platform")
-	.atag_offset	= 0x100,
-	.map_io		= u5500_map_io,
-	.init_irq	= ux500_init_irq,
-	.timer		= &ux500_timer,
-	.handle_irq	= gic_handle_irq,
-	.init_machine	= u5500_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index 77a75ed..dc12394 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -36,9 +36,9 @@
 
 static int __init ux500_l2x0_init(void)
 {
-	if (cpu_is_u5500())
-		l2x0_base = __io_address(U5500_L2CC_BASE);
-	else if (cpu_is_u8500())
+	u32 aux_val = 0x3e000000;
+
+	if (cpu_is_u8500_family())
 		l2x0_base = __io_address(U8500_L2CC_BASE);
 	else
 		ux500_unknown_soc();
@@ -46,11 +46,19 @@
 	/* Unlock before init */
 	ux500_l2x0_unlock();
 
+	/* DB9540's L2 has 128KB way size */
+	if (cpu_is_u9540())
+		/* 128KB way size */
+		aux_val |= (0x4 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+	else
+		/* 64KB way size */
+		aux_val |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+
 	/* 64KB way size, 8 way associativity, force WA */
 	if (of_have_populated_dt())
-		l2x0_of_init(0x3e060000, 0xc0000fff);
+		l2x0_of_init(aux_val, 0xc0000fff);
 	else
-		l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
+		l2x0_init(l2x0_base, aux_val, 0xc0000fff);
 
 	/*
 	 * We can't disable l2 as we are in non secure mode, currently
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index ec35f0a..1762c47 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -149,9 +149,7 @@
 	unsigned long mturate;
 	unsigned long retclk;
 
-	if (cpu_is_u5500())
-		addr = __io_address(U5500_PRCMU_BASE);
-	else if (cpu_is_u8500())
+	if (cpu_is_u8500_family())
 		addr = __io_address(U8500_PRCMU_BASE);
 	else
 		ux500_unknown_soc();
@@ -336,6 +334,7 @@
  */
 
 /* Peripheral Cluster #1 */
+static DEFINE_PRCC_CLK(1, msp3,		11, 10, &clk_msp1clk);
 static DEFINE_PRCC_CLK(1, i2c4,		10, 9, &clk_i2cclk);
 static DEFINE_PRCC_CLK(1, gpio0,	9, -1, NULL);
 static DEFINE_PRCC_CLK(1, slimbus0,	8,  8, &clk_slimclk);
@@ -382,14 +381,15 @@
 /* Peripheral Cluster #6 */
 
 /* MTU ID in data */
-static DEFINE_PRCC_CLK_CUSTOM(6, mtu1, 8, -1, NULL, clk_mtu_get_rate, 1);
-static DEFINE_PRCC_CLK_CUSTOM(6, mtu0, 7, -1, NULL, clk_mtu_get_rate, 0);
-static DEFINE_PRCC_CLK(6, cfgreg,	6,  6, NULL);
-static DEFINE_PRCC_CLK(6, hash1,	5, -1, NULL);
-static DEFINE_PRCC_CLK(6, unipro,	4,  1, &clk_uniproclk);
-static DEFINE_PRCC_CLK(6, pka,		3, -1, NULL);
-static DEFINE_PRCC_CLK(6, hash0,	2, -1, NULL);
-static DEFINE_PRCC_CLK(6, cryp0,	1, -1, NULL);
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu1, 9, -1, NULL, clk_mtu_get_rate, 1);
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu0, 8, -1, NULL, clk_mtu_get_rate, 0);
+static DEFINE_PRCC_CLK(6, cfgreg,	7,  7, NULL);
+static DEFINE_PRCC_CLK(6, hash1,	6, -1, NULL);
+static DEFINE_PRCC_CLK(6, unipro,	5,  1, &clk_uniproclk);
+static DEFINE_PRCC_CLK(6, pka,		4, -1, NULL);
+static DEFINE_PRCC_CLK(6, hash0,	3, -1, NULL);
+static DEFINE_PRCC_CLK(6, cryp0,	2, -1, NULL);
+static DEFINE_PRCC_CLK(6, cryp1,    1, -1, NULL);
 static DEFINE_PRCC_CLK(6, rng,	0,  0, &clk_rngclk);
 
 static struct clk clk_dummy_apb_pclk = {
@@ -405,7 +405,7 @@
 	CLK(slimbus0,	"slimbus0",	NULL),
 	CLK(i2c2,	"nmk-i2c.2",	NULL),
 	CLK(sdi0,	"sdi0",		NULL),
-	CLK(msp0,	"msp0",		NULL),
+	CLK(msp0,	"ux500-msp-i2s.0",	NULL),
 	CLK(i2c1,	"nmk-i2c.1",	NULL),
 	CLK(uart1,	"uart1",	NULL),
 	CLK(uart0,	"uart0",	NULL),
@@ -431,6 +431,7 @@
 	CLK(pka,	"pka",		NULL),
 	CLK(hash0,	"hash0",	NULL),
 	CLK(cryp0,	"cryp0",	NULL),
+	CLK(cryp1,  "cryp1",    NULL),
 
 	/* PRCMU level clock gating */
 
@@ -455,7 +456,8 @@
 	/* Peripheral Cluster #1 */
 	CLK(i2c4,	"nmk-i2c.4",	NULL),
 	CLK(spi3,	"spi3",		NULL),
-	CLK(msp1,	"msp1",		NULL),
+	CLK(msp1,	"ux500-msp-i2s.1",	NULL),
+	CLK(msp3,	"ux500-msp-i2s.3",	NULL),
 
 	/* Peripheral Cluster #2 */
 	CLK(gpio1,	"gpio.6",	NULL),
@@ -465,7 +467,7 @@
 	CLK(spi0,	"spi0",		NULL),
 	CLK(sdi3,	"sdi3",		NULL),
 	CLK(sdi1,	"sdi1",		NULL),
-	CLK(msp2,	"msp2",		NULL),
+	CLK(msp2,	"ux500-msp-i2s.2",	NULL),
 	CLK(sdi4,	"sdi4",		NULL),
 	CLK(pwl,	"pwl",		NULL),
 	CLK(spi1,	"spi1",		NULL),
@@ -705,14 +707,6 @@
 
 int __init clk_init(void)
 {
-	if (cpu_is_u5500()) {
-		/* Clock tree for U5500 not implemented yet */
-		clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
-		clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
-		clk_uartclk.rate = 36360000;
-		clk_sdmmcclk.rate = 99900000;
-	}
-
 	clkdev_add_table(u8500_clks, ARRAY_SIZE(u8500_clks));
 	clkdev_add(&clk_smp_twd_lookup);
 
diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c
deleted file mode 100644
index bca47f3..0000000
--- a/arch/arm/mach-ux500/cpu-db5500.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#include <asm/mach/map.h>
-#include <asm/pmu.h>
-
-#include <plat/gpio-nomadik.h>
-
-#include <mach/hardware.h>
-#include <mach/devices.h>
-#include <mach/setup.h>
-#include <mach/irqs.h>
-#include <mach/usb.h>
-
-#include "devices-db5500.h"
-#include "ste-dma40-db5500.h"
-
-static struct map_desc u5500_uart_io_desc[] __initdata = {
-	__IO_DEV_DESC(U5500_UART0_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_UART2_BASE, SZ_4K),
-};
-
-static struct map_desc u5500_io_desc[] __initdata = {
-	/* SCU base also covers GIC CPU BASE and TWD with its 4K page */
-	__IO_DEV_DESC(U5500_SCU_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_GIC_DIST_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_L2CC_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_MTU0_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_BACKUPRAM0_BASE, SZ_8K),
-
-	__IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_GPIO2_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_GPIO3_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_GPIO4_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K),
-	__IO_DEV_DESC(U5500_PRCMU_TCDM_BASE, SZ_4K),
-};
-
-static struct resource mbox0_resources[] = {
-	{
-		.name = "mbox_peer",
-		.start = U5500_MBOX0_PEER_START,
-		.end = U5500_MBOX0_PEER_END,
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.name = "mbox_local",
-		.start = U5500_MBOX0_LOCAL_START,
-		.end = U5500_MBOX0_LOCAL_END,
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.name = "mbox_irq",
-		.start = MBOX_PAIR0_VIRT_IRQ,
-		.end = MBOX_PAIR0_VIRT_IRQ,
-		.flags = IORESOURCE_IRQ,
-	}
-};
-
-static struct resource mbox1_resources[] = {
-	{
-		.name = "mbox_peer",
-		.start = U5500_MBOX1_PEER_START,
-		.end = U5500_MBOX1_PEER_END,
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.name = "mbox_local",
-		.start = U5500_MBOX1_LOCAL_START,
-		.end = U5500_MBOX1_LOCAL_END,
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.name = "mbox_irq",
-		.start = MBOX_PAIR1_VIRT_IRQ,
-		.end = MBOX_PAIR1_VIRT_IRQ,
-		.flags = IORESOURCE_IRQ,
-	}
-};
-
-static struct resource mbox2_resources[] = {
-	{
-		.name = "mbox_peer",
-		.start = U5500_MBOX2_PEER_START,
-		.end = U5500_MBOX2_PEER_END,
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.name = "mbox_local",
-		.start = U5500_MBOX2_LOCAL_START,
-		.end = U5500_MBOX2_LOCAL_END,
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.name = "mbox_irq",
-		.start = MBOX_PAIR2_VIRT_IRQ,
-		.end = MBOX_PAIR2_VIRT_IRQ,
-		.flags = IORESOURCE_IRQ,
-	}
-};
-
-static struct platform_device mbox0_device = {
-	.id = 0,
-	.name = "mbox",
-	.resource = mbox0_resources,
-	.num_resources = ARRAY_SIZE(mbox0_resources),
-};
-
-static struct platform_device mbox1_device = {
-	.id = 1,
-	.name = "mbox",
-	.resource = mbox1_resources,
-	.num_resources = ARRAY_SIZE(mbox1_resources),
-};
-
-static struct platform_device mbox2_device = {
-	.id = 2,
-	.name = "mbox",
-	.resource = mbox2_resources,
-	.num_resources = ARRAY_SIZE(mbox2_resources),
-};
-
-static struct platform_device *db5500_platform_devs[] __initdata = {
-	&mbox0_device,
-	&mbox1_device,
-	&mbox2_device,
-};
-
-static resource_size_t __initdata db5500_gpio_base[] = {
-	U5500_GPIOBANK0_BASE,
-	U5500_GPIOBANK1_BASE,
-	U5500_GPIOBANK2_BASE,
-	U5500_GPIOBANK3_BASE,
-	U5500_GPIOBANK4_BASE,
-	U5500_GPIOBANK5_BASE,
-	U5500_GPIOBANK6_BASE,
-	U5500_GPIOBANK7_BASE,
-};
-
-static void __init db5500_add_gpios(struct device *parent)
-{
-	struct nmk_gpio_platform_data pdata = {
-		/* No custom data yet */
-	};
-
-	dbx500_add_gpios(parent, ARRAY_AND_SIZE(db5500_gpio_base),
-			 IRQ_DB5500_GPIO0, &pdata);
-}
-
-void __init u5500_map_io(void)
-{
-	/*
-	 * Map the UARTs early so that the DEBUG_LL stuff continues to work.
-	 */
-	iotable_init(u5500_uart_io_desc, ARRAY_SIZE(u5500_uart_io_desc));
-
-	ux500_map_io();
-
-	iotable_init(u5500_io_desc, ARRAY_SIZE(u5500_io_desc));
-
-	_PRCMU_BASE = __io_address(U5500_PRCMU_BASE);
-}
-
-static void __init db5500_pmu_init(void)
-{
-	struct resource res[] = {
-		[0] = {
-			.start		= IRQ_DB5500_PMU0,
-			.end		= IRQ_DB5500_PMU0,
-			.flags		= IORESOURCE_IRQ,
-		},
-		[1] = {
-			.start		= IRQ_DB5500_PMU1,
-			.end		= IRQ_DB5500_PMU1,
-			.flags		= IORESOURCE_IRQ,
-		},
-	};
-
-	platform_device_register_simple("arm-pmu", ARM_PMU_DEVICE_CPU,
-					res, ARRAY_SIZE(res));
-}
-
-static int usb_db5500_rx_dma_cfg[] = {
-	DB5500_DMA_DEV4_USB_OTG_IEP_1_9,
-	DB5500_DMA_DEV5_USB_OTG_IEP_2_10,
-	DB5500_DMA_DEV6_USB_OTG_IEP_3_11,
-	DB5500_DMA_DEV20_USB_OTG_IEP_4_12,
-	DB5500_DMA_DEV21_USB_OTG_IEP_5_13,
-	DB5500_DMA_DEV22_USB_OTG_IEP_6_14,
-	DB5500_DMA_DEV23_USB_OTG_IEP_7_15,
-	DB5500_DMA_DEV38_USB_OTG_IEP_8
-};
-
-static int usb_db5500_tx_dma_cfg[] = {
-	DB5500_DMA_DEV4_USB_OTG_OEP_1_9,
-	DB5500_DMA_DEV5_USB_OTG_OEP_2_10,
-	DB5500_DMA_DEV6_USB_OTG_OEP_3_11,
-	DB5500_DMA_DEV20_USB_OTG_OEP_4_12,
-	DB5500_DMA_DEV21_USB_OTG_OEP_5_13,
-	DB5500_DMA_DEV22_USB_OTG_OEP_6_14,
-	DB5500_DMA_DEV23_USB_OTG_OEP_7_15,
-	DB5500_DMA_DEV38_USB_OTG_OEP_8
-};
-
-static const char *db5500_read_soc_id(void)
-{
-	return kasprintf(GFP_KERNEL, "u5500 currently unsupported\n");
-}
-
-static struct device * __init db5500_soc_device_init(void)
-{
-	const char *soc_id = db5500_read_soc_id();
-
-	return ux500_soc_device_init(soc_id);
-}
-
-struct device * __init u5500_init_devices(void)
-{
-	struct device *parent;
-	int i;
-
-	parent = db5500_soc_device_init();
-
-	db5500_add_gpios(parent);
-	db5500_pmu_init();
-	db5500_dma_init(parent);
-	db5500_add_rtc(parent);
-	db5500_add_usb(parent, usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
-
-	for (i = 0; i < ARRAY_SIZE(db5500_platform_devs); i++)
-		db5500_platform_devs[i]->dev.parent = parent;
-
-	platform_add_devices(db5500_platform_devs,
-			     ARRAY_SIZE(db5500_platform_devs));
-
-	return parent;
-}
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 9bd8163..16169c4 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -34,8 +34,8 @@
 	__IO_DEV_DESC(U8500_UART0_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_UART2_BASE, SZ_4K),
 };
-
-static struct map_desc u8500_io_desc[] __initdata = {
+/*  U8500 and U9540 common io_desc */
+static struct map_desc u8500_common_io_desc[] __initdata = {
 	/* SCU base also covers GIC CPU BASE and TWD with its 4K page */
 	__IO_DEV_DESC(U8500_SCU_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K),
@@ -49,12 +49,23 @@
 	__IO_DEV_DESC(U8500_CLKRST5_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_CLKRST6_BASE, SZ_4K),
 
-	__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K),
+};
+
+/* U8500 IO map specific description */
+static struct map_desc u8500_io_desc[] __initdata = {
+	__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
+
+};
+
+/* U9540 IO map specific description */
+static struct map_desc u9540_io_desc[] __initdata = {
+	__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K + SZ_8K),
+	__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K + SZ_8K),
 };
 
 void __init u8500_map_io(void)
@@ -66,7 +77,12 @@
 
 	ux500_map_io();
 
-	iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
+	iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc));
+
+	if (cpu_is_u9540())
+		iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc));
+	else
+		iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
 
 	_PRCMU_BASE = __io_address(U8500_PRCMU_BASE);
 }
@@ -121,6 +137,12 @@
 	&db8500_prcmu_device,
 };
 
+static struct platform_device *of_platform_devs[] __initdata = {
+	&u8500_dma40_device,
+	&db8500_pmu_device,
+	&db8500_prcmu_device,
+};
+
 static resource_size_t __initdata db8500_gpio_base[] = {
 	U8500_GPIOBANK0_BASE,
 	U8500_GPIOBANK1_BASE,
@@ -141,6 +163,7 @@
 
 	dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base),
 			 IRQ_DB8500_GPIO0, &pdata);
+	dbx500_add_pinctrl(parent, "pinctrl-db8500");
 }
 
 static int usb_db8500_rx_dma_cfg[] = {
@@ -199,10 +222,16 @@
 	platform_device_register_data(parent,
 		"cpufreq-u8500", -1, NULL, 0);
 
-	for (i = 0; i < ARRAY_SIZE(platform_devs); i++)
-		platform_devs[i]->dev.parent = parent;
+	for (i = 0; i < ARRAY_SIZE(of_platform_devs); i++)
+		of_platform_devs[i]->dev.parent = parent;
 
-	platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+	/*
+	 * Devices to be DT:ed:
+	 *   u8500_dma40_device  = todo
+	 *   db8500_pmu_device   = todo
+	 *   db8500_prcmu_device = todo
+	 */
+	platform_add_devices(of_platform_devs, ARRAY_SIZE(of_platform_devs));
 
 	return parent;
 }
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index d11f389..a29a0e3 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -10,7 +10,6 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/mfd/db8500-prcmu.h>
-#include <linux/mfd/db5500-prcmu.h>
 #include <linux/clksrc-dbx500-prcmu.h>
 #include <linux/sys_soc.h>
 #include <linux/err.h>
@@ -30,6 +29,18 @@
 
 void __iomem *_PRCMU_BASE;
 
+/*
+ * FIXME: Should we set up the GPIO domain here?
+ *
+ * The problem is that we cannot put the interrupt resources into the platform
+ * device until the irqdomain has been added. Right now, we set the GIC interrupt
+ * domain from init_irq(), then load the gpio driver from
+ * core_initcall(nmk_gpio_init) and add the platform devices from
+ * arch_initcall(customize_machine).
+ *
+ * This feels fragile because it depends on the gpio device getting probed
+ * _before_ any device uses the gpio interrupts.
+*/
 static const struct of_device_id ux500_dt_irq_match[] = {
 	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
 	{},
@@ -40,10 +51,7 @@
 	void __iomem *dist_base;
 	void __iomem *cpu_base;
 
-	if (cpu_is_u5500()) {
-		dist_base = __io_address(U5500_GIC_DIST_BASE);
-		cpu_base = __io_address(U5500_GIC_CPU_BASE);
-	} else if (cpu_is_u8500()) {
+	if (cpu_is_u8500_family()) {
 		dist_base = __io_address(U8500_GIC_DIST_BASE);
 		cpu_base = __io_address(U8500_GIC_CPU_BASE);
 	} else
@@ -60,9 +68,7 @@
 	 * Init clocks here so that they are available for system timer
 	 * initialization.
 	 */
-	if (cpu_is_u5500())
-		db5500_prcmu_early_init();
-	if (cpu_is_u8500())
+	if (cpu_is_u8500_family())
 		db8500_prcmu_early_init();
 	clk_init();
 }
diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c
new file mode 100644
index 0000000..b54884bd
--- /dev/null
+++ b/arch/arm/mach-ux500/cpuidle.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2012 Linaro : Daniel Lezcano <daniel.lezcano@linaro.org> (IBM)
+ *
+ * Based on the work of Rickard Andersson <rickard.andersson@stericsson.com>
+ * and Jonas Aaberg <jonas.aberg@stericsson.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/cpuidle.h>
+#include <linux/clockchips.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/smp.h>
+#include <linux/mfd/dbx500-prcmu.h>
+
+#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+
+static atomic_t master = ATOMIC_INIT(0);
+static DEFINE_SPINLOCK(master_lock);
+static DEFINE_PER_CPU(struct cpuidle_device, ux500_cpuidle_device);
+
+static inline int ux500_enter_idle(struct cpuidle_device *dev,
+				   struct cpuidle_driver *drv, int index)
+{
+	int this_cpu = smp_processor_id();
+	bool recouple = false;
+
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu);
+
+	if (atomic_inc_return(&master) == num_online_cpus()) {
+
+		/* With this lock, we prevent the other cpu to exit and enter
+		 * this function again and become the master */
+		if (!spin_trylock(&master_lock))
+			goto wfi;
+
+		/* decouple the gic from the A9 cores */
+		if (prcmu_gic_decouple())
+			goto out;
+
+		/* If an error occur, we will have to recouple the gic
+		 * manually */
+		recouple = true;
+
+		/* At this state, as the gic is decoupled, if the other
+		 * cpu is in WFI, we have the guarantee it won't be wake
+		 * up, so we can safely go to retention */
+		if (!prcmu_is_cpu_in_wfi(this_cpu ? 0 : 1))
+			goto out;
+
+		/* The prcmu will be in charge of watching the interrupts
+		 * and wake up the cpus */
+		if (prcmu_copy_gic_settings())
+			goto out;
+
+		/* Check in the meantime an interrupt did
+		 * not occur on the gic ... */
+		if (prcmu_gic_pending_irq())
+			goto out;
+
+		/* ... and the prcmu */
+		if (prcmu_pending_irq())
+			goto out;
+
+		/* Go to the retention state, the prcmu will wait for the
+		 * cpu to go WFI and this is what happens after exiting this
+		 * 'master' critical section */
+		if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true))
+			goto out;
+
+		/* When we switch to retention, the prcmu is in charge
+		 * of recoupling the gic automatically */
+		recouple = false;
+
+		spin_unlock(&master_lock);
+	}
+wfi:
+	cpu_do_idle();
+out:
+	atomic_dec(&master);
+
+	if (recouple) {
+		prcmu_gic_recouple();
+		spin_unlock(&master_lock);
+	}
+
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &this_cpu);
+
+	return index;
+}
+
+static struct cpuidle_driver ux500_idle_driver = {
+	.name = "ux500_idle",
+	.owner = THIS_MODULE,
+	.en_core_tk_irqen = 1,
+	.states = {
+		ARM_CPUIDLE_WFI_STATE,
+		{
+			.enter		  = ux500_enter_idle,
+			.exit_latency	  = 70,
+			.target_residency = 260,
+			.flags		  = CPUIDLE_FLAG_TIME_VALID,
+			.name		  = "ApIdle",
+			.desc		  = "ARM Retention",
+		},
+	},
+	.safe_state_index = 0,
+	.state_count = 2,
+};
+
+/*
+ * For each cpu, setup the broadcast timer because we will
+ * need to migrate the timers for the states >= ApIdle.
+ */
+static void ux500_setup_broadcast_timer(void *arg)
+{
+	int cpu = smp_processor_id();
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
+}
+
+int __init ux500_idle_init(void)
+{
+	int ret, cpu;
+	struct cpuidle_device *device;
+
+        /* Configure wake up reasons */
+	prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
+			     PRCMU_WAKEUP(ABB));
+
+	/*
+	 * Configure the timer broadcast for each cpu, that must
+	 * be done from the cpu context, so we use a smp cross
+	 * call with 'on_each_cpu'.
+	 */
+	on_each_cpu(ux500_setup_broadcast_timer, NULL, 1);
+
+	ret = cpuidle_register_driver(&ux500_idle_driver);
+	if (ret) {
+		printk(KERN_ERR "failed to register ux500 idle driver\n");
+		return ret;
+	}
+
+	for_each_online_cpu(cpu) {
+		device = &per_cpu(ux500_cpuidle_device, cpu);
+		device->cpu = cpu;
+		ret = cpuidle_register_device(device);
+		if (ret) {
+			printk(KERN_ERR "Failed to register cpuidle "
+			       "device for cpu%d\n", cpu);
+			goto out_unregister;
+		}
+	}
+out:
+	return ret;
+
+out_unregister:
+	for_each_online_cpu(cpu) {
+		device = &per_cpu(ux500_cpuidle_device, cpu);
+		cpuidle_unregister_device(device);
+	}
+
+	cpuidle_unregister_driver(&ux500_idle_driver);
+	goto out;
+}
+
+device_initcall(ux500_idle_init);
diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h
index f75bcb2..6e47065 100644
--- a/arch/arm/mach-ux500/devices-common.h
+++ b/arch/arm/mach-ux500/devices-common.h
@@ -13,6 +13,7 @@
 #include <linux/sys_soc.h>
 #include <linux/amba/bus.h>
 #include <plat/i2c.h>
+#include <mach/crypto-ux500.h>
 
 struct spi_master_cntlr;
 
@@ -85,9 +86,70 @@
 				0, NULL, 0);
 }
 
+struct cryp_platform_data;
+
+static inline struct platform_device *
+dbx500_add_cryp1(struct device *parent, int id, resource_size_t base, int irq,
+		struct cryp_platform_data *pdata)
+{
+	struct resource res[] = {
+			DEFINE_RES_MEM(base, SZ_4K),
+			DEFINE_RES_IRQ(irq),
+	};
+
+	struct platform_device_info pdevinfo = {
+			.parent = parent,
+			.name = "cryp1",
+			.id = id,
+			.res = res,
+			.num_res = ARRAY_SIZE(res),
+			.data = pdata,
+			.size_data = sizeof(*pdata),
+			.dma_mask = DMA_BIT_MASK(32),
+	};
+
+	return platform_device_register_full(&pdevinfo);
+}
+
+struct hash_platform_data;
+
+static inline struct platform_device *
+dbx500_add_hash1(struct device *parent, int id, resource_size_t base,
+		struct hash_platform_data *pdata)
+{
+	struct resource res[] = {
+			DEFINE_RES_MEM(base, SZ_4K),
+	};
+
+	struct platform_device_info pdevinfo = {
+			.parent = parent,
+			.name = "hash1",
+			.id = id,
+			.res = res,
+			.num_res = ARRAY_SIZE(res),
+			.data = pdata,
+			.size_data = sizeof(*pdata),
+			.dma_mask = DMA_BIT_MASK(32),
+	};
+
+	return platform_device_register_full(&pdevinfo);
+}
+
 struct nmk_gpio_platform_data;
 
 void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num,
 		      int irq, struct nmk_gpio_platform_data *pdata);
 
+static inline void
+dbx500_add_pinctrl(struct device *parent, const char *name)
+{
+	struct platform_device_info pdevinfo = {
+		.parent = parent,
+		.name = name,
+		.id = -1,
+	};
+
+	platform_device_register_full(&pdevinfo);
+}
+
 #endif
diff --git a/arch/arm/mach-ux500/devices-db5500.h b/arch/arm/mach-ux500/devices-db5500.h
deleted file mode 100644
index e709555..0000000
--- a/arch/arm/mach-ux500/devices-db5500.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL), version 2.
- */
-
-#ifndef __DEVICES_DB5500_H
-#define __DEVICES_DB5500_H
-
-#include "devices-common.h"
-
-#define db5500_add_i2c1(parent, pdata) \
-	dbx500_add_i2c(parent, 1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
-#define db5500_add_i2c2(parent, pdata) \
-	dbx500_add_i2c(parent, 2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
-#define db5500_add_i2c3(parent, pdata) \
-	dbx500_add_i2c(parent, 3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
-
-#define db5500_add_msp0_spi(parent, pdata) \
-	dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
-			   IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_spi(parent, pdata) \
-	dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
-			   IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_spi(parent, pdata) \
-	dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
-			   IRQ_DB5500_MSP2, pdata)
-
-#define db5500_add_msp0_spi(parent, pdata) \
-	dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
-			  IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_spi(parent, pdata) \
-	dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
-			  IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_spi(parent, pdata) \
-	dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
-			  IRQ_DB5500_MSP2, pdata)
-
-#define db5500_add_rtc(parent) \
-	dbx500_add_rtc(parent, U5500_RTC_BASE, IRQ_DB5500_RTC);
-
-#define db5500_add_usb(parent, rx_cfg, tx_cfg) \
-	ux500_add_usb(parent, U5500_USBOTG_BASE, \
-		      IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
-
-#define db5500_add_sdi0(parent, pdata) \
-	dbx500_add_sdi(parent, "sdi0", U5500_SDI0_BASE, \
-		       IRQ_DB5500_SDMMC0, pdata,	\
-		       0x10480180)
-#define db5500_add_sdi1(parent, pdata) \
-	dbx500_add_sdi(parent, "sdi1", U5500_SDI1_BASE, \
-		       IRQ_DB5500_SDMMC1, pdata,	\
-		       0x10480180)
-#define db5500_add_sdi2(parent, pdata) \
-	dbx500_add_sdi(parent, "sdi2", U5500_SDI2_BASE, \
-		       IRQ_DB5500_SDMMC2, pdata		\
-		       0x10480180)
-#define db5500_add_sdi3(parent, pdata) \
-	dbx500_add_sdi(parent, "sdi3", U5500_SDI3_BASE, \
-		       IRQ_DB5500_SDMMC3, pdata		\
-		       0x10480180)
-#define db5500_add_sdi4(parent, pdata) \
-	dbx500_add_sdi(parent, "sdi4", U5500_SDI4_BASE, \
-		       IRQ_DB5500_SDMMC4, pdata		\
-		       0x10480180)
-
-/* This one has a bad peripheral ID in the U5500 silicon */
-#define db5500_add_spi0(parent, pdata) \
-	dbx500_add_spi(parent, "spi0", U5500_SPI0_BASE, \
-		       IRQ_DB5500_SPI0, pdata,		\
-		       0x10080023)
-#define db5500_add_spi1(parent, pdata) \
-	dbx500_add_spi(parent, "spi1", U5500_SPI1_BASE, \
-		       IRQ_DB5500_SPI1, pdata,		\
-		       0x10080023)
-#define db5500_add_spi2(parent, pdata) \
-	dbx500_add_spi(parent, "spi2", U5500_SPI2_BASE, \
-		       IRQ_DB5500_SPI2, pdata		\
-		       0x10080023)
-#define db5500_add_spi3(parent, pdata) \
-	dbx500_add_spi(parent, "spi3", U5500_SPI3_BASE, \
-		       IRQ_DB5500_SPI3, pdata		\
-		       0x10080023)
-
-#define db5500_add_uart0(parent, plat) \
-	dbx500_add_uart(parent, "uart0", U5500_UART0_BASE, \
-			IRQ_DB5500_UART0, plat)
-#define db5500_add_uart1(parent, plat) \
-	dbx500_add_uart(parent, "uart1", U5500_UART1_BASE, \
-			IRQ_DB5500_UART1, plat)
-#define db5500_add_uart2(parent, plat) \
-	dbx500_add_uart(parent, "uart2", U5500_UART2_BASE, \
-			IRQ_DB5500_UART2, plat)
-#define db5500_add_uart3(parent, plat) \
-	dbx500_add_uart(parent, "uart3", U5500_UART3_BASE, \
-			IRQ_DB5500_UART3, plat)
-
-#endif
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c
index 6e66d37..91754a8 100644
--- a/arch/arm/mach-ux500/devices-db8500.c
+++ b/arch/arm/mach-ux500/devices-db8500.c
@@ -104,6 +104,8 @@
 	[DB8500_DMA_DEV14_MSP2_TX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
 	[DB8500_DMA_DEV30_MSP1_TX] = U8500_MSP1_BASE + MSP_TX_RX_REG_OFFSET,
 	[DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
+	[DB8500_DMA_DEV48_CAC1_TX] = U8500_CRYP1_BASE + CRYP1_TX_REG_OFFSET,
+	[DB8500_DMA_DEV50_HAC1_TX] = U8500_HASH1_BASE + HASH1_TX_REG_OFFSET,
 };
 
 /* Mapping between source event lines and physical device address */
@@ -139,6 +141,7 @@
 	[DB8500_DMA_DEV14_MSP2_RX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
 	[DB8500_DMA_DEV30_MSP3_RX] = U8500_MSP3_BASE + MSP_TX_RX_REG_OFFSET,
 	[DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
+	[DB8500_DMA_DEV48_CAC1_RX] = U8500_CRYP1_BASE + CRYP1_RX_REG_OFFSET,
 };
 
 /* Reserved event lines for memcpy only */
diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h
index 6fc7eb2..3c8010f 100644
--- a/arch/arm/mach-ux500/devices-db8500.h
+++ b/arch/arm/mach-ux500/devices-db8500.h
@@ -34,7 +34,6 @@
 	return amba_ahb_device_add(parent, name, base, SZ_4K, irq, 0, pdata, 0);
 }
 
-
 #define db8500_add_i2c0(parent, pdata) \
 	dbx500_add_i2c(parent, 0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
 #define db8500_add_i2c1(parent, pdata) \
@@ -46,15 +45,6 @@
 #define db8500_add_i2c4(parent, pdata) \
 	dbx500_add_i2c(parent, 4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
 
-#define db8500_add_msp0_i2s(parent, pdata) \
-	dbx500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
-#define db8500_add_msp1_i2s(parent, pdata) \
-	dbx500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
-#define db8500_add_msp2_i2s(parent, pdata) \
-	dbx500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
-#define db8500_add_msp3_i2s(parent, pdata) \
-	dbx500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
-
 #define db8500_add_msp0_spi(parent, pdata) \
 	dbx500_add_msp_spi(parent, "msp0", U8500_MSP0_BASE, \
 			   IRQ_DB8500_MSP0, pdata)
@@ -124,4 +114,8 @@
 	dbx500_add_uart(parent, "uart2", U8500_UART2_BASE, \
 			IRQ_DB8500_UART2, pdata)
 
+#define db8500_add_cryp1(parent, pdata) \
+	dbx500_add_cryp1(parent, -1, U8500_CRYP1_BASE, IRQ_DB8500_CRYP1, pdata)
+#define db8500_add_hash1(parent, pdata) \
+	dbx500_add_hash1(parent, -1, U8500_HASH1_BASE, pdata)
 #endif
diff --git a/arch/arm/mach-ux500/dma-db5500.c b/arch/arm/mach-ux500/dma-db5500.c
deleted file mode 100644
index 41e9470..0000000
--- a/arch/arm/mach-ux500/dma-db5500.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
- * Author: Rabin Vincent <rabinv.vincent@stericsson.com> for ST-Ericsson
- *
- * License terms: GNU General Public License (GPL), version 2
- */
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-#include <plat/ste_dma40.h>
-#include <mach/setup.h>
-#include <mach/hardware.h>
-
-#include "ste-dma40-db5500.h"
-
-static struct resource dma40_resources[] = {
-	[0] = {
-		.start = U5500_DMA_BASE,
-		.end   = U5500_DMA_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-		.name  = "base",
-	},
-	[1] = {
-		.start = U5500_DMA_LCPA_BASE,
-		.end   = U5500_DMA_LCPA_BASE + 2 * SZ_1K - 1,
-		.flags = IORESOURCE_MEM,
-		.name  = "lcpa",
-	},
-	[2] = {
-		.start = IRQ_DB5500_DMA,
-		.end   = IRQ_DB5500_DMA,
-		.flags = IORESOURCE_IRQ
-	}
-};
-
-/* Default configuration for physical memcpy */
-static struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
-	.mode = STEDMA40_MODE_PHYSICAL,
-	.dir = STEDMA40_MEM_TO_MEM,
-
-	.src_info.data_width = STEDMA40_BYTE_WIDTH,
-	.src_info.psize = STEDMA40_PSIZE_PHY_1,
-	.src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
-
-	.dst_info.data_width = STEDMA40_BYTE_WIDTH,
-	.dst_info.psize = STEDMA40_PSIZE_PHY_1,
-	.dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
-};
-
-/* Default configuration for logical memcpy */
-static struct stedma40_chan_cfg dma40_memcpy_conf_log = {
-	.dir = STEDMA40_MEM_TO_MEM,
-
-	.src_info.data_width = STEDMA40_BYTE_WIDTH,
-	.src_info.psize = STEDMA40_PSIZE_LOG_1,
-	.src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
-
-	.dst_info.data_width = STEDMA40_BYTE_WIDTH,
-	.dst_info.psize = STEDMA40_PSIZE_LOG_1,
-	.dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
-};
-
-/*
- * Mapping between soruce event lines and physical device address This was
- * created assuming that the event line is tied to a device and therefore the
- * address is constant, however this is not true for at least USB, and the
- * values are just placeholders for USB.  This table is preserved and used for
- * now.
- */
-static const dma_addr_t dma40_rx_map[DB5500_DMA_NR_DEV] = {
-	[DB5500_DMA_DEV24_SDMMC0_RX] = -1,
-	[DB5500_DMA_DEV38_USB_OTG_IEP_8] = -1,
-	[DB5500_DMA_DEV23_USB_OTG_IEP_7_15] = -1,
-	[DB5500_DMA_DEV22_USB_OTG_IEP_6_14] = -1,
-	[DB5500_DMA_DEV21_USB_OTG_IEP_5_13] = -1,
-	[DB5500_DMA_DEV20_USB_OTG_IEP_4_12] = -1,
-	[DB5500_DMA_DEV6_USB_OTG_IEP_3_11] = -1,
-	[DB5500_DMA_DEV5_USB_OTG_IEP_2_10] = -1,
-	[DB5500_DMA_DEV4_USB_OTG_IEP_1_9] = -1,
-};
-
-/* Mapping between destination event lines and physical device address */
-static const dma_addr_t dma40_tx_map[DB5500_DMA_NR_DEV] = {
-	[DB5500_DMA_DEV24_SDMMC0_TX] = -1,
-	[DB5500_DMA_DEV38_USB_OTG_OEP_8] = -1,
-	[DB5500_DMA_DEV23_USB_OTG_OEP_7_15] = -1,
-	[DB5500_DMA_DEV22_USB_OTG_OEP_6_14] = -1,
-	[DB5500_DMA_DEV21_USB_OTG_OEP_5_13] = -1,
-	[DB5500_DMA_DEV20_USB_OTG_OEP_4_12] = -1,
-	[DB5500_DMA_DEV6_USB_OTG_OEP_3_11] = -1,
-	[DB5500_DMA_DEV5_USB_OTG_OEP_2_10] = -1,
-	[DB5500_DMA_DEV4_USB_OTG_OEP_1_9] = -1,
-};
-
-static int dma40_memcpy_event[] = {
-	DB5500_DMA_MEMCPY_TX_1,
-	DB5500_DMA_MEMCPY_TX_2,
-	DB5500_DMA_MEMCPY_TX_3,
-	DB5500_DMA_MEMCPY_TX_4,
-	DB5500_DMA_MEMCPY_TX_5,
-};
-
-static struct stedma40_platform_data dma40_plat_data = {
-	.dev_len		= ARRAY_SIZE(dma40_rx_map),
-	.dev_rx			= dma40_rx_map,
-	.dev_tx			= dma40_tx_map,
-	.memcpy			= dma40_memcpy_event,
-	.memcpy_len		= ARRAY_SIZE(dma40_memcpy_event),
-	.memcpy_conf_phy	= &dma40_memcpy_conf_phy,
-	.memcpy_conf_log	= &dma40_memcpy_conf_log,
-	.disabled_channels	= {-1},
-};
-
-static struct platform_device dma40_device = {
-	.dev = {
-		.platform_data = &dma40_plat_data,
-	},
-	.name		= "dma40",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(dma40_resources),
-	.resource	= dma40_resources
-};
-
-void __init db5500_dma_init(struct device *parent)
-{
-	int ret;
-
-	dma40_device.dev.parent = parent;
-	ret = platform_device_register(&dma40_device);
-	if (ret)
-		dev_err(&dma40_device.dev, "unable to register device: %d\n", ret);
-
-}
diff --git a/arch/arm/mach-ux500/id.c b/arch/arm/mach-ux500/id.c
index 15a0f63..d157992 100644
--- a/arch/arm/mach-ux500/id.c
+++ b/arch/arm/mach-ux500/id.c
@@ -23,7 +23,7 @@
 {
 	phys_addr_t base = addr & ~0xfff;
 	struct map_desc desc = {
-		.virtual	= IO_ADDRESS(base),
+		.virtual	= UX500_VIRT_ROM,
 		.pfn		= __phys_to_pfn(base),
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
@@ -35,7 +35,7 @@
 	local_flush_tlb_all();
 	flush_cache_all();
 
-	return readl(__io_address(addr));
+	return readl(IOMEM(UX500_VIRT_ROM + (addr & 0xfff)));
 }
 
 static void ux500_print_soc_info(unsigned int asicid)
@@ -67,6 +67,7 @@
  * DB8500v2	0x412fc091	0x9001DBF4		0x008500B0
  * DB8520v2.2	0x412fc091	0x9001DBF4		0x008500B2
  * DB5500v1	0x412fc091	0x9001FFF4		0x005500A0
+ * DB9540	0x413fc090	0xFFFFDBF4		0x009540xx
  */
 
 void __init ux500_map_io(void)
@@ -91,6 +92,10 @@
 		/* DB5500v1 */
 		addr = 0x9001FFF4;
 		break;
+
+	case 0x413fc090: /* DB9540 */
+		addr = 0xFFFFDBF4;
+		break;
 	}
 
 	if (addr)
diff --git a/arch/arm/mach-ux500/include/mach/crypto-ux500.h b/arch/arm/mach-ux500/include/mach/crypto-ux500.h
new file mode 100644
index 0000000..5b2d081
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/crypto-ux500.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef _CRYPTO_UX500_H
+#define _CRYPTO_UX500_H
+#include <linux/dmaengine.h>
+#include <plat/ste_dma40.h>
+
+struct hash_platform_data {
+	void *mem_to_engine;
+	bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+};
+
+struct cryp_platform_data {
+	struct stedma40_chan_cfg mem_to_engine;
+	struct stedma40_chan_cfg engine_to_mem;
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/db5500-regs.h b/arch/arm/mach-ux500/include/mach/db5500-regs.h
deleted file mode 100644
index 8e714bc..0000000
--- a/arch/arm/mach-ux500/include/mach/db5500-regs.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef __MACH_DB5500_REGS_H
-#define __MACH_DB5500_REGS_H
-
-#define U5500_PER1_BASE		0xA0020000
-#define U5500_PER2_BASE		0xA0010000
-#define U5500_PER3_BASE		0x80140000
-#define U5500_PER4_BASE		0x80150000
-#define U5500_PER5_BASE		0x80100000
-#define U5500_PER6_BASE		0x80120000
-
-#define U5500_GIC_DIST_BASE	0xA0411000
-#define U5500_GIC_CPU_BASE	0xA0410100
-#define U5500_DMA_BASE		0x90030000
-#define U5500_STM_BASE		0x90020000
-#define U5500_STM_REG_BASE	(U5500_STM_BASE + 0xF000)
-#define U5500_MCDE_BASE		0xA0400000
-#define U5500_MODEM_BASE	0xB0000000
-#define U5500_L2CC_BASE		0xA0412000
-#define U5500_SCU_BASE		0xA0410000
-#define U5500_DSI1_BASE		0xA0401000
-#define U5500_DSI2_BASE		0xA0402000
-#define U5500_SIA_BASE		0xA0100000
-#define U5500_SVA_BASE		0x80200000
-#define U5500_HSEM_BASE		0xA0000000
-#define U5500_NAND0_BASE	0x60000000
-#define U5500_NAND1_BASE	0x70000000
-#define U5500_TWD_BASE		0xa0410600
-#define U5500_ICN_BASE		0xA0040000
-#define U5500_B2R2_BASE		0xa0200000
-#define U5500_BOOT_ROM_BASE	0x90000000
-
-#define U5500_FSMC_BASE		(U5500_PER1_BASE + 0x0000)
-#define U5500_SDI0_BASE		(U5500_PER1_BASE + 0x1000)
-#define U5500_SDI2_BASE		(U5500_PER1_BASE + 0x2000)
-#define U5500_UART0_BASE	(U5500_PER1_BASE + 0x3000)
-#define U5500_I2C1_BASE		(U5500_PER1_BASE + 0x4000)
-#define U5500_MSP0_BASE		(U5500_PER1_BASE + 0x5000)
-#define U5500_GPIO0_BASE	(U5500_PER1_BASE + 0xE000)
-#define U5500_CLKRST1_BASE	(U5500_PER1_BASE + 0xF000)
-
-#define U5500_USBOTG_BASE	(U5500_PER2_BASE + 0x0000)
-#define U5500_GPIO1_BASE	(U5500_PER2_BASE + 0xE000)
-#define U5500_CLKRST2_BASE	(U5500_PER2_BASE + 0xF000)
-
-#define U5500_KEYPAD_BASE	(U5500_PER3_BASE + 0x0000)
-#define U5500_PWM_BASE		(U5500_PER3_BASE + 0x1000)
-#define U5500_GPIO3_BASE	(U5500_PER3_BASE + 0xE000)
-#define U5500_CLKRST3_BASE	(U5500_PER3_BASE + 0xF000)
-
-#define U5500_BACKUPRAM0_BASE	(U5500_PER4_BASE + 0x0000)
-#define U5500_BACKUPRAM1_BASE	(U5500_PER4_BASE + 0x1000)
-#define U5500_RTT0_BASE		(U5500_PER4_BASE + 0x2000)
-#define U5500_RTT1_BASE		(U5500_PER4_BASE + 0x3000)
-#define U5500_RTC_BASE		(U5500_PER4_BASE + 0x4000)
-#define U5500_SCR_BASE		(U5500_PER4_BASE + 0x5000)
-#define U5500_DMC_BASE		(U5500_PER4_BASE + 0x6000)
-#define U5500_PRCMU_BASE	(U5500_PER4_BASE + 0x7000)
-#define U5500_PRCMU_TIMER_3_BASE (U5500_PER4_BASE + 0x07338)
-#define U5500_PRCMU_TIMER_4_BASE (U5500_PER4_BASE + 0x07450)
-#define U5500_MSP1_BASE		(U5500_PER4_BASE + 0x9000)
-#define U5500_GPIO2_BASE	(U5500_PER4_BASE + 0xA000)
-#define U5500_MTIMER_BASE	(U5500_PER4_BASE + 0xC000)
-#define U5500_CDETECT_BASE	(U5500_PER4_BASE + 0xF000)
-#define U5500_PRCMU_TCDM_BASE	(U5500_PER4_BASE + 0x18000)
-#define U5500_PRCMU_TCPM_BASE	(U5500_PER4_BASE + 0x10000)
-#define U5500_TPIU_BASE		(U5500_PER4_BASE + 0x50000)
-
-#define U5500_SPI0_BASE		(U5500_PER5_BASE + 0x0000)
-#define U5500_SPI1_BASE		(U5500_PER5_BASE + 0x1000)
-#define U5500_SPI2_BASE		(U5500_PER5_BASE + 0x2000)
-#define U5500_SPI3_BASE		(U5500_PER5_BASE + 0x3000)
-#define U5500_UART1_BASE	(U5500_PER5_BASE + 0x4000)
-#define U5500_UART2_BASE	(U5500_PER5_BASE + 0x5000)
-#define U5500_UART3_BASE	(U5500_PER5_BASE + 0x6000)
-#define U5500_SDI1_BASE		(U5500_PER5_BASE + 0x7000)
-#define U5500_SDI3_BASE		(U5500_PER5_BASE + 0x8000)
-#define U5500_SDI4_BASE		(U5500_PER5_BASE + 0x9000)
-#define U5500_I2C2_BASE		(U5500_PER5_BASE + 0xA000)
-#define U5500_I2C3_BASE		(U5500_PER5_BASE + 0xB000)
-#define U5500_MSP2_BASE		(U5500_PER5_BASE + 0xC000)
-#define U5500_IRDA_BASE		(U5500_PER5_BASE + 0xD000)
-#define U5500_IRRC_BASE		(U5500_PER5_BASE + 0x10000)
-#define U5500_GPIO4_BASE	(U5500_PER5_BASE + 0x1E000)
-#define U5500_CLKRST5_BASE	(U5500_PER5_BASE + 0x1F000)
-
-#define U5500_RNG_BASE		(U5500_PER6_BASE + 0x0000)
-#define U5500_HASH0_BASE	(U5500_PER6_BASE + 0x1000)
-#define U5500_HASH1_BASE	(U5500_PER6_BASE + 0x2000)
-#define U5500_PKA_BASE		(U5500_PER6_BASE + 0x4000)
-#define U5500_PKAM_BASE		(U5500_PER6_BASE + 0x5100)
-#define U5500_MTU0_BASE		(U5500_PER6_BASE + 0x6000)
-#define U5500_MTU1_BASE		(U5500_PER6_BASE + 0x7000)
-#define U5500_CR_BASE		(U5500_PER6_BASE + 0x8000)
-#define U5500_CRYP0_BASE	(U5500_PER6_BASE + 0xA000)
-#define U5500_CRYP1_BASE	(U5500_PER6_BASE + 0xB000)
-#define U5500_CLKRST6_BASE	(U5500_PER6_BASE + 0xF000)
-
-#define U5500_GPIOBANK0_BASE	U5500_GPIO0_BASE
-#define U5500_GPIOBANK1_BASE	(U5500_GPIO0_BASE + 0x80)
-#define U5500_GPIOBANK2_BASE	U5500_GPIO1_BASE
-#define U5500_GPIOBANK3_BASE	U5500_GPIO2_BASE
-#define U5500_GPIOBANK4_BASE	U5500_GPIO3_BASE
-#define U5500_GPIOBANK5_BASE	U5500_GPIO4_BASE
-#define U5500_GPIOBANK6_BASE	(U5500_GPIO4_BASE + 0x80)
-#define U5500_GPIOBANK7_BASE	(U5500_GPIO4_BASE + 0x100)
-
-#define U5500_MBOX_BASE		(U5500_MODEM_BASE + 0xFFD1000)
-#define U5500_MBOX0_PEER_START	(U5500_MBOX_BASE + 0x40)
-#define U5500_MBOX0_PEER_END	(U5500_MBOX_BASE + 0x5F)
-#define U5500_MBOX0_LOCAL_START	(U5500_MBOX_BASE + 0x60)
-#define U5500_MBOX0_LOCAL_END	(U5500_MBOX_BASE + 0x7F)
-#define U5500_MBOX1_PEER_START	(U5500_MBOX_BASE + 0x80)
-#define U5500_MBOX1_PEER_END	(U5500_MBOX_BASE + 0x9F)
-#define U5500_MBOX1_LOCAL_START	(U5500_MBOX_BASE + 0xA0)
-#define U5500_MBOX1_LOCAL_END	(U5500_MBOX_BASE + 0xBF)
-#define U5500_MBOX2_PEER_START	(U5500_MBOX_BASE + 0x00)
-#define U5500_MBOX2_PEER_END	(U5500_MBOX_BASE + 0x1F)
-#define U5500_MBOX2_LOCAL_START	(U5500_MBOX_BASE + 0x20)
-#define U5500_MBOX2_LOCAL_END	(U5500_MBOX_BASE + 0x3F)
-
-#define U5500_ACCCON_BASE_SEC	(0xBFFF0000)
-#define U5500_ACCCON_BASE		(0xBFFF1000)
-#define U5500_ACCCON_CPUVEC_RESET_ADDR_OFFSET (0x00000020)
-#define U5500_ACCCON_ACC_CPU_CTRL_OFFSET (0x000000BC)
-#define U5500_INTCON_MBOX1_INT_RESET_ADDR	(0xBFFD31A4)
-
-#define U5500_ESRAM_BASE	        0x40000000
-#define U5500_ESRAM_DMA_LCPA_OFFSET	0x10000
-#define U5500_DMA_LCPA_BASE    (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET)
-
-#define U5500_MCDE_SIZE		0x1000
-#define U5500_DSI_LINK_SIZE	0x1000
-#define U5500_DSI_LINK_COUNT	0x2
-#define U5500_DSI_LINK1_BASE	(U5500_MCDE_BASE + U5500_MCDE_SIZE)
-#define U5500_DSI_LINK2_BASE	(U5500_DSI_LINK1_BASE + U5500_DSI_LINK_SIZE)
-
-#endif
diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h
index 9ec20b9..1530d49 100644
--- a/arch/arm/mach-ux500/include/mach/db8500-regs.h
+++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h
@@ -41,6 +41,10 @@
 /* ASIC ID is at 0xbf4 offset within this region */
 #define U8500_ASIC_ID_BASE	0x9001D000
 
+#define U9540_BOOT_ROM_BASE	0xFFFE0000
+/* ASIC ID is at 0xbf4 offset within this region */
+#define U9540_ASIC_ID_BASE	0xFFFFD000
+
 #define U8500_PER6_BASE		0xa03c0000
 #define U8500_PER7_BASE		0xa03d0000
 #define U8500_PER5_BASE		0xa03e0000
@@ -96,7 +100,9 @@
 #define U8500_SCR_BASE		(U8500_PER4_BASE + 0x05000)
 #define U8500_DMC_BASE		(U8500_PER4_BASE + 0x06000)
 #define U8500_PRCMU_BASE	(U8500_PER4_BASE + 0x07000)
+#define U9540_DMC1_BASE		(U8500_PER4_BASE + 0x0A000)
 #define U8500_PRCMU_TCDM_BASE	(U8500_PER4_BASE + 0x68000)
+#define U9540_PRCMU_TCDM_BASE	(U8500_PER4_BASE + 0x6A000)
 #define U8500_PRCMU_TCPM_BASE   (U8500_PER4_BASE + 0x60000)
 #define U8500_PRCMU_TIMER_3_BASE (U8500_PER4_BASE + 0x07338)
 #define U8500_PRCMU_TIMER_4_BASE (U8500_PER4_BASE + 0x07450)
diff --git a/arch/arm/mach-ux500/include/mach/debug-macro.S b/arch/arm/mach-ux500/include/mach/debug-macro.S
index 8d74d92..6703522 100644
--- a/arch/arm/mach-ux500/include/mach/debug-macro.S
+++ b/arch/arm/mach-ux500/include/mach/debug-macro.S
@@ -20,10 +20,6 @@
  * built, so that there's some hint during the build that something is wrong.
  */
 
-#ifdef CONFIG_UX500_SOC_DB5500
-#define __UX500_UART(n)	U5500_UART##n##_BASE
-#endif
-
 #ifdef CONFIG_UX500_SOC_DB8500
 #define __UX500_UART(n)	U8500_UART##n##_BASE
 #endif
diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h
index 5f6cb71..cbc6f1e 100644
--- a/arch/arm/mach-ux500/include/mach/devices.h
+++ b/arch/arm/mach-ux500/include/mach/devices.h
@@ -10,11 +10,13 @@
 struct platform_device;
 struct amba_device;
 
-extern struct platform_device u5500_gpio_devs[];
 extern struct platform_device u8500_gpio_devs[];
 
 extern struct amba_device ux500_pl031_device;
 
+extern struct platform_device ux500_hash1_device;
+extern struct platform_device ux500_cryp1_device;
+
 extern struct platform_device u8500_dma40_device;
 extern struct platform_device ux500_ske_keypad_device;
 
diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h
index f846989..28d16e7 100644
--- a/arch/arm/mach-ux500/include/mach/hardware.h
+++ b/arch/arm/mach-ux500/include/mach/hardware.h
@@ -17,6 +17,8 @@
  */
 #define U8500_IO_VIRTUAL	0xf0000000
 #define U8500_IO_PHYSICAL	0xa0000000
+/* This is where we map in the ROM to check ASIC IDs */
+#define UX500_VIRT_ROM		0xf0000000
 
 /* This macro is used in assembly, so no cast */
 #define IO_ADDRESS(x)           \
@@ -24,13 +26,16 @@
 
 /* typesafe io address */
 #define __io_address(n)		IOMEM(IO_ADDRESS(n))
+
 /* Used by some plat-nomadik code */
 #define io_p2v(n)		__io_address(n)
 
 #include <mach/db8500-regs.h>
-#include <mach/db5500-regs.h>
 
 #define MSP_TX_RX_REG_OFFSET	0
+#define CRYP1_RX_REG_OFFSET	0x10
+#define CRYP1_TX_REG_OFFSET	0x8
+#define HASH1_TX_REG_OFFSET	0x4
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/arm/mach-ux500/include/mach/id.h b/arch/arm/mach-ux500/include/mach/id.h
index 833d6a6..c6e2db9 100644
--- a/arch/arm/mach-ux500/include/mach/id.h
+++ b/arch/arm/mach-ux500/include/mach/id.h
@@ -41,6 +41,16 @@
 	return dbx500_partnumber() == 0x8500;
 }
 
+static inline bool __attribute_const__ cpu_is_u9540(void)
+{
+	return dbx500_partnumber() == 0x9540;
+}
+
+static inline bool cpu_is_u8500_family(void)
+{
+	return cpu_is_u8500() || cpu_is_u9540();
+}
+
 static inline bool __attribute_const__ cpu_is_u5500(void)
 {
 	return dbx500_partnumber() == 0x5500;
@@ -111,7 +121,12 @@
 
 static inline bool cpu_is_u8500v20_or_later(void)
 {
-	return cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11();
+	/*
+	 * U9540 has so much in common with U8500 that is is considered a
+	 * U8500 variant.
+	 */
+	return cpu_is_u9540() ||
+		(cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
 }
 
 static inline bool ux500_is_svp(void)
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
deleted file mode 100644
index 29d972c..0000000
--- a/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef __MACH_IRQS_BOARD_U5500_H
-#define __MACH_IRQS_BOARD_U5500_H
-
-#define AB5500_NR_IRQS		5
-#define IRQ_AB5500_BASE		IRQ_BOARD_START
-#define IRQ_AB5500_END		(IRQ_AB5500_BASE + AB5500_NR_IRQS)
-
-#define U5500_IRQ_END		IRQ_AB5500_END
-
-#if IRQ_BOARD_END < U5500_IRQ_END
-#undef IRQ_BOARD_END
-#define IRQ_BOARD_END		U5500_IRQ_END
-#endif
-
-#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-db5500.h b/arch/arm/mach-ux500/include/mach/irqs-db5500.h
deleted file mode 100644
index 7723977..0000000
--- a/arch/arm/mach-ux500/include/mach/irqs-db5500.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com>
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef __MACH_IRQS_DB5500_H
-#define __MACH_IRQS_DB5500_H
-
-#define IRQ_DB5500_MTU0			(IRQ_SHPI_START + 4)
-#define IRQ_DB5500_SPI2			(IRQ_SHPI_START + 6)
-#define IRQ_DB5500_PMU0			(IRQ_SHPI_START + 7)
-#define IRQ_DB5500_SPI0			(IRQ_SHPI_START + 8)
-#define IRQ_DB5500_RTT			(IRQ_SHPI_START + 9)
-#define IRQ_DB5500_PKA			(IRQ_SHPI_START + 10)
-#define IRQ_DB5500_UART0		(IRQ_SHPI_START + 11)
-#define IRQ_DB5500_I2C3			(IRQ_SHPI_START + 12)
-#define IRQ_DB5500_L2CC			(IRQ_SHPI_START + 13)
-#define IRQ_DB5500_MSP0			(IRQ_SHPI_START + 14)
-#define IRQ_DB5500_CRYP1		(IRQ_SHPI_START + 15)
-#define IRQ_DB5500_PMU1			(IRQ_SHPI_START + 16)
-#define IRQ_DB5500_MTU1			(IRQ_SHPI_START + 17)
-#define IRQ_DB5500_RTC			(IRQ_SHPI_START + 18)
-#define IRQ_DB5500_UART1		(IRQ_SHPI_START + 19)
-#define IRQ_DB5500_USB_WAKEUP		(IRQ_SHPI_START + 20)
-#define IRQ_DB5500_I2C0			(IRQ_SHPI_START + 21)
-#define IRQ_DB5500_I2C1			(IRQ_SHPI_START + 22)
-#define IRQ_DB5500_USBOTG		(IRQ_SHPI_START + 23)
-#define IRQ_DB5500_DMA_SECURE		(IRQ_SHPI_START + 24)
-#define IRQ_DB5500_DMA			(IRQ_SHPI_START + 25)
-#define IRQ_DB5500_UART2		(IRQ_SHPI_START + 26)
-#define IRQ_DB5500_ICN_PMU1		(IRQ_SHPI_START + 27)
-#define IRQ_DB5500_ICN_PMU2		(IRQ_SHPI_START + 28)
-#define IRQ_DB5500_UART3		(IRQ_SHPI_START + 29)
-#define IRQ_DB5500_SPI3			(IRQ_SHPI_START + 30)
-#define IRQ_DB5500_SDMMC4		(IRQ_SHPI_START + 31)
-#define IRQ_DB5500_IRRC			(IRQ_SHPI_START + 33)
-#define IRQ_DB5500_IRDA_FT		(IRQ_SHPI_START + 34)
-#define IRQ_DB5500_IRDA_SD		(IRQ_SHPI_START + 35)
-#define IRQ_DB5500_IRDA_FI		(IRQ_SHPI_START + 36)
-#define IRQ_DB5500_IRDA_FD		(IRQ_SHPI_START + 37)
-#define IRQ_DB5500_FSMC_CODEREADY	(IRQ_SHPI_START + 38)
-#define IRQ_DB5500_FSMC_NANDWAIT	(IRQ_SHPI_START + 39)
-#define IRQ_DB5500_AB5500		(IRQ_SHPI_START + 40)
-#define IRQ_DB5500_SDMMC2		(IRQ_SHPI_START + 41)
-#define IRQ_DB5500_SIA			(IRQ_SHPI_START + 42)
-#define IRQ_DB5500_SIA2			(IRQ_SHPI_START + 43)
-#define IRQ_DB5500_HVA			(IRQ_SHPI_START + 44)
-#define IRQ_DB5500_HVA2			(IRQ_SHPI_START + 45)
-#define IRQ_DB5500_PRCMU0		(IRQ_SHPI_START + 46)
-#define IRQ_DB5500_PRCMU1		(IRQ_SHPI_START + 47)
-#define IRQ_DB5500_DISP			(IRQ_SHPI_START + 48)
-#define IRQ_DB5500_SDMMC1		(IRQ_SHPI_START + 50)
-#define IRQ_DB5500_MSP1			(IRQ_SHPI_START + 52)
-#define IRQ_DB5500_KBD			(IRQ_SHPI_START + 53)
-#define IRQ_DB5500_I2C2			(IRQ_SHPI_START + 55)
-#define IRQ_DB5500_B2R2			(IRQ_SHPI_START + 56)
-#define IRQ_DB5500_CRYP0		(IRQ_SHPI_START + 57)
-#define IRQ_DB5500_SDMMC3		(IRQ_SHPI_START + 59)
-#define IRQ_DB5500_SDMMC0		(IRQ_SHPI_START + 60)
-#define IRQ_DB5500_HSEM			(IRQ_SHPI_START + 61)
-#define IRQ_DB5500_SBAG			(IRQ_SHPI_START + 63)
-#define IRQ_DB5500_MODEM		(IRQ_SHPI_START + 65)
-#define IRQ_DB5500_SPI1			(IRQ_SHPI_START + 96)
-#define IRQ_DB5500_MSP2			(IRQ_SHPI_START + 98)
-#define IRQ_DB5500_SRPTIMER		(IRQ_SHPI_START + 101)
-#define IRQ_DB5500_CTI0			(IRQ_SHPI_START + 108)
-#define IRQ_DB5500_CTI1			(IRQ_SHPI_START + 109)
-#define IRQ_DB5500_ICN_ERR		(IRQ_SHPI_START + 110)
-#define IRQ_DB5500_MALI_PPMMU		(IRQ_SHPI_START + 112)
-#define IRQ_DB5500_MALI_PP		(IRQ_SHPI_START + 113)
-#define IRQ_DB5500_MALI_GPMMU		(IRQ_SHPI_START + 114)
-#define IRQ_DB5500_MALI_GP		(IRQ_SHPI_START + 115)
-#define IRQ_DB5500_MALI			(IRQ_SHPI_START + 116)
-#define IRQ_DB5500_PRCMU_SEM		(IRQ_SHPI_START + 118)
-#define IRQ_DB5500_GPIO0		(IRQ_SHPI_START + 119)
-#define IRQ_DB5500_GPIO1		(IRQ_SHPI_START + 120)
-#define IRQ_DB5500_GPIO2		(IRQ_SHPI_START + 121)
-#define IRQ_DB5500_GPIO3		(IRQ_SHPI_START + 122)
-#define IRQ_DB5500_GPIO4		(IRQ_SHPI_START + 123)
-#define IRQ_DB5500_GPIO5		(IRQ_SHPI_START + 124)
-#define IRQ_DB5500_GPIO6		(IRQ_SHPI_START + 125)
-#define IRQ_DB5500_GPIO7		(IRQ_SHPI_START + 126)
-
-#ifdef CONFIG_UX500_SOC_DB5500
-
-/*
- * After the GPIO ones we reserve a range of IRQ:s in which virtual
- * IRQ:s representing modem IRQ:s can be allocated
- */
-#define IRQ_MODEM_EVENTS_BASE	IRQ_SOC_START
-#define IRQ_MODEM_EVENTS_NBR	72
-#define IRQ_MODEM_EVENTS_END	(IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
-
-/* List of virtual IRQ:s that are allocated from the range above */
-#define MBOX_PAIR0_VIRT_IRQ	(IRQ_MODEM_EVENTS_BASE + 43)
-#define MBOX_PAIR1_VIRT_IRQ	(IRQ_MODEM_EVENTS_BASE + 45)
-#define MBOX_PAIR2_VIRT_IRQ	(IRQ_MODEM_EVENTS_BASE + 41)
-
-/*
- * We may have several SoCs, but only one will run at a
- * time, so the one with most IRQs will bump this ahead,
- * but the IRQ_SOC_START remains the same for either SoC.
- */
-#if IRQ_SOC_END < IRQ_MODEM_EVENTS_END
-#undef IRQ_SOC_END
-#define IRQ_SOC_END		IRQ_MODEM_EVENTS_END
-#endif
-
-#endif /* CONFIG_UX500_SOC_DB5500 */
-
-#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h
index c23a6b5..e892854 100644
--- a/arch/arm/mach-ux500/include/mach/irqs.h
+++ b/arch/arm/mach-ux500/include/mach/irqs.h
@@ -24,7 +24,7 @@
  */
 #define IRQ_MTU0		(IRQ_SHPI_START + 4)
 
-#define DBX500_NR_INTERNAL_IRQS		160
+#define DBX500_NR_INTERNAL_IRQS		166
 
 /* After chip-specific IRQ numbers we have the GPIO ones */
 #define NOMADIK_NR_GPIO			288
@@ -36,7 +36,6 @@
 /* This will be overridden by SoC-specific irq headers */
 #define IRQ_SOC_END		IRQ_SOC_START
 
-#include <mach/irqs-db5500.h>
 #include <mach/irqs-db8500.h>
 
 #define IRQ_BOARD_START		IRQ_SOC_END
@@ -47,10 +46,6 @@
 #include <mach/irqs-board-mop500.h>
 #endif
 
-#ifdef CONFIG_MACH_U5500
-#include <mach/irqs-board-u5500.h>
-#endif
-
 #define NR_IRQS			IRQ_BOARD_END
 
 #endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-ux500/include/mach/mbox-db5500.h b/arch/arm/mach-ux500/include/mach/mbox-db5500.h
deleted file mode 100644
index 7f9da4d..0000000
--- a/arch/arm/mach-ux500/include/mach/mbox-db5500.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
- * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
- * License terms: GNU General Public License (GPL), version 2.
- */
-
-#ifndef __INC_STE_MBOX_H
-#define __INC_STE_MBOX_H
-
-#define MBOX_BUF_SIZE 16
-#define MBOX_NAME_SIZE 8
-
-/**
-  * mbox_recv_cb_t - Definition of the mailbox callback.
-  * @mbox_msg:	The mailbox message.
-  * @priv:	The clients private data as specified in the call to mbox_setup.
-  *
-  * This function will be called upon reception of new mailbox messages.
-  */
-typedef void mbox_recv_cb_t (u32 mbox_msg, void *priv);
-
-/**
-  * struct mbox - Mailbox instance struct
-  * @list:		Linked list head.
-  * @pdev:		Pointer to device struct.
-  * @cb:		Callback function. Will be called
-  *			when new data is received.
-  * @client_data:	Clients private data. Will be sent back
-  *			in the callback function.
-  * @virtbase_peer:	Virtual address for outgoing mailbox.
-  * @virtbase_local:	Virtual address for incoming mailbox.
-  * @buffer:		Then internal queue for outgoing messages.
-  * @name:		Name of this mailbox.
-  * @buffer_available:	Completion variable to achieve "blocking send".
-  *			This variable will be signaled when there is
-  *			internal buffer space available.
-  * @client_blocked:	To keep track if any client is currently
-  *			blocked.
-  * @lock:		Spinlock to protect this mailbox instance.
-  * @write_index:	Index in internal buffer to write to.
-  * @read_index:	Index in internal buffer to read from.
-  * @allocated:		Indicates whether this particular mailbox
-  *			id has been allocated by someone.
-  */
-struct mbox {
-	struct list_head list;
-	struct platform_device *pdev;
-	mbox_recv_cb_t *cb;
-	void *client_data;
-	void __iomem *virtbase_peer;
-	void __iomem *virtbase_local;
-	u32 buffer[MBOX_BUF_SIZE];
-	char name[MBOX_NAME_SIZE];
-	struct completion buffer_available;
-	u8 client_blocked;
-	spinlock_t lock;
-	u8 write_index;
-	u8 read_index;
-	bool allocated;
-};
-
-/**
-  * mbox_setup - Set up a mailbox and return its instance.
-  * @mbox_id:	The ID number of the mailbox. 0 or 1 for modem CPU,
-  *		2 for modem DSP.
-  * @mbox_cb:	Pointer to the callback function to be called when a new message
-  *		is received.
-  * @priv:	Client user data which will be returned in the callback.
-  *
-  * Returns a mailbox instance to be specified in subsequent calls to mbox_send.
-  */
-struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv);
-
-/**
-  * mbox_send - Send a mailbox message.
-  * @mbox:	Mailbox instance (returned by mbox_setup)
-  * @mbox_msg:	The mailbox message to send.
-  * @block:	Specifies whether this call will block until send is possible,
-  *		or return an error if the mailbox buffer is full.
-  *
-  * Returns 0 on success or a negative error code on error. -ENOMEM indicates
-  * that the internal buffer is full and you have to try again later (or
-  * specify "block" in order to block until send is possible).
-  */
-int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block);
-
-#endif /*INC_STE_MBOX_H*/
diff --git a/arch/arm/mach-ux500/include/mach/msp.h b/arch/arm/mach-ux500/include/mach/msp.h
new file mode 100644
index 0000000..798be19
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/msp.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __MSP_H
+#define __MSP_H
+
+#include <plat/ste_dma40.h>
+
+enum msp_i2s_id {
+	MSP_I2S_0 = 0,
+	MSP_I2S_1,
+	MSP_I2S_2,
+	MSP_I2S_3,
+};
+
+/* Platform data structure for a MSP I2S-device */
+struct msp_i2s_platform_data {
+	enum msp_i2s_id id;
+	struct stedma40_chan_cfg *msp_i2s_dma_rx;
+	struct stedma40_chan_cfg *msp_i2s_dma_tx;
+	int (*msp_i2s_init) (void);
+	int (*msp_i2s_exit) (void);
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h
index 3dc00ff..4e369f1 100644
--- a/arch/arm/mach-ux500/include/mach/setup.h
+++ b/arch/arm/mach-ux500/include/mach/setup.h
@@ -15,18 +15,12 @@
 #include <linux/init.h>
 
 void __init ux500_map_io(void);
-extern void __init u5500_map_io(void);
 extern void __init u8500_map_io(void);
 
-extern struct device * __init u5500_init_devices(void);
 extern struct device * __init u8500_init_devices(void);
 
 extern void __init ux500_init_irq(void);
 
-extern void __init u5500_sdi_init(struct device *parent);
-
-extern void __init db5500_dma_init(struct device *parent);
-
 extern struct device *ux500_soc_device_init(const char *soc_id);
 
 struct amba_device;
diff --git a/arch/arm/mach-ux500/include/mach/uncompress.h b/arch/arm/mach-ux500/include/mach/uncompress.h
index 6fb3c4b..34775ba 100644
--- a/arch/arm/mach-ux500/include/mach/uncompress.h
+++ b/arch/arm/mach-ux500/include/mach/uncompress.h
@@ -50,11 +50,8 @@
 
 static inline void arch_decomp_setup(void)
 {
-	/* Check in run time if we run on an U8500 or U5500 */
-	if (machine_is_u5500())
-		ux500_uart_base = U5500_UART0_BASE;
-	else
-		ux500_uart_base = U8500_UART2_BASE;
+	/* Use machine_is_foo() macro if you need to switch base someday */
+	ux500_uart_base = U8500_UART2_BASE;
 }
 
 #define arch_decomp_wdog() /* nothing to do here */
diff --git a/arch/arm/mach-ux500/mbox-db5500.c b/arch/arm/mach-ux500/mbox-db5500.c
deleted file mode 100644
index 0127490..0000000
--- a/arch/arm/mach-ux500/mbox-db5500.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
- * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
- * License terms: GNU General Public License (GPL), version 2.
- */
-
-/*
- * Mailbox nomenclature:
- *
- *       APE           MODEM
- *           mbox pairX
- *   ..........................
- *   .                       .
- *   .           peer        .
- *   .     send  ----        .
- *   .      -->  |  |        .
- *   .           |  |        .
- *   .           ----        .
- *   .                       .
- *   .           local       .
- *   .     rec   ----        .
- *   .           |  | <--    .
- *   .           |  |        .
- *   .           ----        .
- *   .........................
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/completion.h>
-#include <mach/mbox-db5500.h>
-
-#define MBOX_NAME "mbox"
-
-#define MBOX_FIFO_DATA        0x000
-#define MBOX_FIFO_ADD         0x004
-#define MBOX_FIFO_REMOVE      0x008
-#define MBOX_FIFO_THRES_FREE  0x00C
-#define MBOX_FIFO_THRES_OCCUP 0x010
-#define MBOX_FIFO_STATUS      0x014
-
-#define MBOX_DISABLE_IRQ 0x4
-#define MBOX_ENABLE_IRQ  0x0
-#define MBOX_LATCH 1
-
-/* Global list of all mailboxes */
-static struct list_head mboxs = LIST_HEAD_INIT(mboxs);
-
-static struct mbox *get_mbox_with_id(u8 id)
-{
-	u8 i;
-	struct list_head *pos = &mboxs;
-	for (i = 0; i <= id; i++)
-		pos = pos->next;
-
-	return (struct mbox *) list_entry(pos, struct mbox, list);
-}
-
-int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block)
-{
-	int res = 0;
-
-	spin_lock(&mbox->lock);
-
-	dev_dbg(&(mbox->pdev->dev),
-		"About to buffer 0x%X to mailbox 0x%X."
-		" ri = %d, wi = %d\n",
-		mbox_msg, (u32)mbox, mbox->read_index,
-		mbox->write_index);
-
-	/* Check if write buffer is full */
-	while (((mbox->write_index + 1) % MBOX_BUF_SIZE) == mbox->read_index) {
-		if (!block) {
-			dev_dbg(&(mbox->pdev->dev),
-			"Buffer full in non-blocking call! "
-			"Returning -ENOMEM!\n");
-			res = -ENOMEM;
-			goto exit;
-		}
-		spin_unlock(&mbox->lock);
-		dev_dbg(&(mbox->pdev->dev),
-			"Buffer full in blocking call! Sleeping...\n");
-		mbox->client_blocked = 1;
-		wait_for_completion(&mbox->buffer_available);
-		dev_dbg(&(mbox->pdev->dev),
-			"Blocking send was woken up! Trying again...\n");
-		spin_lock(&mbox->lock);
-	}
-
-	mbox->buffer[mbox->write_index] = mbox_msg;
-	mbox->write_index = (mbox->write_index + 1) % MBOX_BUF_SIZE;
-
-	/*
-	 * Indicate that we want an IRQ as soon as there is a slot
-	 * in the FIFO
-	 */
-	writel(MBOX_ENABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
-
-exit:
-	spin_unlock(&mbox->lock);
-	return res;
-}
-EXPORT_SYMBOL(mbox_send);
-
-#if defined(CONFIG_DEBUG_FS)
-/*
- * Expected input: <value> <nbr sends>
- * Example: "echo 0xdeadbeef 4 > mbox-node" sends 0xdeadbeef 4 times
- */
-static ssize_t mbox_write_fifo(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf,
-			       size_t count)
-{
-	unsigned long mbox_mess;
-	unsigned long nbr_sends;
-	unsigned long i;
-	char int_buf[16];
-	char *token;
-	char *val;
-
-	struct mbox *mbox = (struct mbox *) dev->platform_data;
-
-	strncpy((char *) &int_buf, buf, sizeof(int_buf));
-	token = (char *) &int_buf;
-
-	/* Parse message */
-	val = strsep(&token, " ");
-	if ((val == NULL) || (strict_strtoul(val, 16, &mbox_mess) != 0))
-		mbox_mess = 0xDEADBEEF;
-
-	val = strsep(&token, " ");
-	if ((val == NULL) || (strict_strtoul(val, 10, &nbr_sends) != 0))
-		nbr_sends = 1;
-
-	dev_dbg(dev, "Will write 0x%lX %ld times using data struct at 0x%X\n",
-		mbox_mess, nbr_sends, (u32) mbox);
-
-	for (i = 0; i < nbr_sends; i++)
-		mbox_send(mbox, mbox_mess, true);
-
-	return count;
-}
-
-static ssize_t mbox_read_fifo(struct device *dev,
-			      struct device_attribute *attr,
-			      char *buf)
-{
-	int mbox_value;
-	struct mbox *mbox = (struct mbox *) dev->platform_data;
-
-	if ((readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7) <= 0)
-		return sprintf(buf, "Mailbox is empty\n");
-
-	mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
-	writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
-
-	return sprintf(buf, "0x%X\n", mbox_value);
-}
-
-static DEVICE_ATTR(fifo, S_IWUSR | S_IRUGO, mbox_read_fifo, mbox_write_fifo);
-
-static int mbox_show(struct seq_file *s, void *data)
-{
-	struct list_head *pos;
-	u8 mbox_index = 0;
-
-	list_for_each(pos, &mboxs) {
-		struct mbox *m =
-			(struct mbox *) list_entry(pos, struct mbox, list);
-		if (m == NULL) {
-			seq_printf(s,
-				   "Unable to retrieve mailbox %d\n",
-				   mbox_index);
-			continue;
-		}
-
-		spin_lock(&m->lock);
-		if ((m->virtbase_peer == NULL) || (m->virtbase_local == NULL)) {
-			seq_printf(s, "MAILBOX %d not setup or corrupt\n",
-				   mbox_index);
-			spin_unlock(&m->lock);
-			continue;
-		}
-
-		seq_printf(s,
-		"===========================\n"
-		" MAILBOX %d\n"
-		" PEER MAILBOX DUMP\n"
-		"---------------------------\n"
-		"FIFO:                 0x%X (%d)\n"
-		"Free     Threshold:   0x%.2X (%d)\n"
-		"Occupied Threshold:   0x%.2X (%d)\n"
-		"Status:               0x%.2X (%d)\n"
-		"   Free spaces  (ot):    %d (%d)\n"
-		"   Occup spaces (ot):    %d (%d)\n"
-		"===========================\n"
-		" LOCAL MAILBOX DUMP\n"
-		"---------------------------\n"
-		"FIFO:                 0x%.X (%d)\n"
-		"Free     Threshold:   0x%.2X (%d)\n"
-		"Occupied Threshold:   0x%.2X (%d)\n"
-		"Status:               0x%.2X (%d)\n"
-		"   Free spaces  (ot):    %d (%d)\n"
-		"   Occup spaces (ot):    %d (%d)\n"
-		"===========================\n"
-		"write_index: %d\n"
-		"read_index : %d\n"
-		"===========================\n"
-		"\n",
-		mbox_index,
-		readl(m->virtbase_peer + MBOX_FIFO_DATA),
-		readl(m->virtbase_peer + MBOX_FIFO_DATA),
-		readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
-		readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
-		readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
-		readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
-		readl(m->virtbase_peer + MBOX_FIFO_STATUS),
-		readl(m->virtbase_peer + MBOX_FIFO_STATUS),
-		(readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 4) & 0x7,
-		(readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 7) & 0x1,
-		(readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 0) & 0x7,
-		(readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 3) & 0x1,
-		readl(m->virtbase_local + MBOX_FIFO_DATA),
-		readl(m->virtbase_local + MBOX_FIFO_DATA),
-		readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
-		readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
-		readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
-		readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
-		readl(m->virtbase_local + MBOX_FIFO_STATUS),
-		readl(m->virtbase_local + MBOX_FIFO_STATUS),
-		(readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 4) & 0x7,
-		(readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 7) & 0x1,
-		(readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 0) & 0x7,
-		(readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 3) & 0x1,
-		m->write_index, m->read_index);
-		mbox_index++;
-		spin_unlock(&m->lock);
-	}
-
-	return 0;
-}
-
-static int mbox_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, mbox_show, NULL);
-}
-
-static const struct file_operations mbox_operations = {
-	.owner = THIS_MODULE,
-	.open = mbox_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-#endif
-
-static irqreturn_t mbox_irq(int irq, void *arg)
-{
-	u32 mbox_value;
-	int nbr_occup;
-	int nbr_free;
-	struct mbox *mbox = (struct mbox *) arg;
-
-	spin_lock(&mbox->lock);
-
-	dev_dbg(&(mbox->pdev->dev),
-		"mbox IRQ [%d] received. ri = %d, wi = %d\n",
-		irq, mbox->read_index, mbox->write_index);
-
-	/*
-	 * Check if we have any outgoing messages, and if there is space for
-	 * them in the FIFO.
-	 */
-	if (mbox->read_index != mbox->write_index) {
-		/*
-		 * Check by reading FREE for LOCAL since that indicates
-		 * OCCUP for PEER
-		 */
-		nbr_free = (readl(mbox->virtbase_local + MBOX_FIFO_STATUS)
-			    >> 4) & 0x7;
-		dev_dbg(&(mbox->pdev->dev),
-			"Status indicates %d empty spaces in the FIFO!\n",
-			nbr_free);
-
-		while ((nbr_free > 0) &&
-		       (mbox->read_index != mbox->write_index)) {
-			/* Write the message and latch it into the FIFO */
-			writel(mbox->buffer[mbox->read_index],
-			       (mbox->virtbase_peer + MBOX_FIFO_DATA));
-			writel(MBOX_LATCH,
-			       (mbox->virtbase_peer + MBOX_FIFO_ADD));
-			dev_dbg(&(mbox->pdev->dev),
-				"Wrote message 0x%X to addr 0x%X\n",
-				mbox->buffer[mbox->read_index],
-				(u32) (mbox->virtbase_peer + MBOX_FIFO_DATA));
-
-			nbr_free--;
-			mbox->read_index =
-				(mbox->read_index + 1) % MBOX_BUF_SIZE;
-		}
-
-		/*
-		 * Check if we still want IRQ:s when there is free
-		 * space to send
-		 */
-		if (mbox->read_index != mbox->write_index) {
-			dev_dbg(&(mbox->pdev->dev),
-				"Still have messages to send, but FIFO full. "
-				"Request IRQ again!\n");
-			writel(MBOX_ENABLE_IRQ,
-			       mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
-		} else {
-			dev_dbg(&(mbox->pdev->dev),
-				"No more messages to send. "
-				"Do not request IRQ again!\n");
-			writel(MBOX_DISABLE_IRQ,
-			       mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
-		}
-
-		/*
-		 * Check if we can signal any blocked clients that it is OK to
-		 * start buffering again
-		 */
-		if (mbox->client_blocked &&
-		    (((mbox->write_index + 1) % MBOX_BUF_SIZE)
-		     != mbox->read_index)) {
-			dev_dbg(&(mbox->pdev->dev),
-				"Waking up blocked client\n");
-			complete(&mbox->buffer_available);
-			mbox->client_blocked = 0;
-		}
-	}
-
-	/* Check if we have any incoming messages */
-	nbr_occup = readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7;
-	if (nbr_occup == 0)
-		goto exit;
-
-	if (mbox->cb == NULL) {
-		dev_dbg(&(mbox->pdev->dev), "No receive callback registered, "
-			"leaving %d incoming messages in fifo!\n", nbr_occup);
-		goto exit;
-	}
-
-	/* Read and acknowledge the message */
-	mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
-	writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
-
-	/* Notify consumer of new mailbox message */
-	dev_dbg(&(mbox->pdev->dev), "Calling callback for message 0x%X!\n",
-		mbox_value);
-	mbox->cb(mbox_value, mbox->client_data);
-
-exit:
-	dev_dbg(&(mbox->pdev->dev), "Exit mbox IRQ. ri = %d, wi = %d\n",
-		mbox->read_index, mbox->write_index);
-	spin_unlock(&mbox->lock);
-
-	return IRQ_HANDLED;
-}
-
-/* Setup is executed once for each mbox pair */
-struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
-{
-	struct resource *resource;
-	int irq;
-	int res;
-	struct mbox *mbox;
-
-	mbox = get_mbox_with_id(mbox_id);
-	if (mbox == NULL) {
-		dev_err(&(mbox->pdev->dev), "Incorrect mailbox id: %d!\n",
-			mbox_id);
-		goto exit;
-	}
-
-	/*
-	 * Check if mailbox has been allocated to someone else,
-	 * otherwise allocate it
-	 */
-	if (mbox->allocated) {
-		dev_err(&(mbox->pdev->dev), "Mailbox number %d is busy!\n",
-			mbox_id);
-		mbox = NULL;
-		goto exit;
-	}
-	mbox->allocated = true;
-
-	dev_dbg(&(mbox->pdev->dev), "Initiating mailbox number %d: 0x%X...\n",
-		mbox_id, (u32)mbox);
-
-	mbox->client_data = priv;
-	mbox->cb = mbox_cb;
-
-	/* Get addr for peer mailbox and ioremap it */
-	resource = platform_get_resource_byname(mbox->pdev,
-						IORESOURCE_MEM,
-						"mbox_peer");
-	if (resource == NULL) {
-		dev_err(&(mbox->pdev->dev),
-			"Unable to retrieve mbox peer resource\n");
-		mbox = NULL;
-		goto exit;
-	}
-	dev_dbg(&(mbox->pdev->dev),
-		"Resource name: %s start: 0x%X, end: 0x%X\n",
-		resource->name, resource->start, resource->end);
-	mbox->virtbase_peer = ioremap(resource->start, resource_size(resource));
-	if (!mbox->virtbase_peer) {
-		dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n");
-		mbox = NULL;
-		goto exit;
-	}
-	dev_dbg(&(mbox->pdev->dev),
-		"ioremapped peer physical: (0x%X-0x%X) to virtual: 0x%X\n",
-		resource->start, resource->end, (u32) mbox->virtbase_peer);
-
-	/* Get addr for local mailbox and ioremap it */
-	resource = platform_get_resource_byname(mbox->pdev,
-						IORESOURCE_MEM,
-						"mbox_local");
-	if (resource == NULL) {
-		dev_err(&(mbox->pdev->dev),
-			"Unable to retrieve mbox local resource\n");
-		mbox = NULL;
-		goto exit;
-	}
-	dev_dbg(&(mbox->pdev->dev),
-		"Resource name: %s start: 0x%X, end: 0x%X\n",
-		resource->name, resource->start, resource->end);
-	mbox->virtbase_local = ioremap(resource->start, resource_size(resource));
-	if (!mbox->virtbase_local) {
-		dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n");
-		mbox = NULL;
-		goto exit;
-	}
-	dev_dbg(&(mbox->pdev->dev),
-		"ioremapped local physical: (0x%X-0x%X) to virtual: 0x%X\n",
-		resource->start, resource->end, (u32) mbox->virtbase_peer);
-
-	init_completion(&mbox->buffer_available);
-	mbox->client_blocked = 0;
-
-	/* Get IRQ for mailbox and allocate it */
-	irq = platform_get_irq_byname(mbox->pdev, "mbox_irq");
-	if (irq < 0) {
-		dev_err(&(mbox->pdev->dev),
-			"Unable to retrieve mbox irq resource\n");
-		mbox = NULL;
-		goto exit;
-	}
-
-	dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", irq);
-	res = request_irq(irq, mbox_irq, 0, mbox->name, (void *) mbox);
-	if (res < 0) {
-		dev_err(&(mbox->pdev->dev),
-			"Unable to allocate mbox irq %d\n", irq);
-		mbox = NULL;
-		goto exit;
-	}
-
-	/* Set up mailbox to not launch IRQ on free space in mailbox */
-	writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
-
-	/*
-	 * Set up mailbox to launch IRQ on new message if we have
-	 * a callback set. If not, do not raise IRQ, but keep message
-	 * in FIFO for manual retrieval
-	 */
-	if (mbox_cb != NULL)
-		writel(MBOX_ENABLE_IRQ,
-		       mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
-	else
-		writel(MBOX_DISABLE_IRQ,
-		       mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
-
-#if defined(CONFIG_DEBUG_FS)
-	res = device_create_file(&(mbox->pdev->dev), &dev_attr_fifo);
-	if (res != 0)
-		dev_warn(&(mbox->pdev->dev),
-			 "Unable to create mbox sysfs entry");
-
-	(void) debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL,
-				   NULL, &mbox_operations);
-#endif
-
-	dev_info(&(mbox->pdev->dev),
-		 "Mailbox driver with index %d initiated!\n", mbox_id);
-
-exit:
-	return mbox;
-}
-EXPORT_SYMBOL(mbox_setup);
-
-
-int __init mbox_probe(struct platform_device *pdev)
-{
-	struct mbox local_mbox;
-	struct mbox *mbox;
-	int res = 0;
-	dev_dbg(&(pdev->dev), "Probing mailbox (pdev = 0x%X)...\n", (u32) pdev);
-
-	memset(&local_mbox, 0x0, sizeof(struct mbox));
-
-	/* Associate our mbox data with the platform device */
-	res = platform_device_add_data(pdev,
-				       (void *) &local_mbox,
-				       sizeof(struct mbox));
-	if (res != 0) {
-		dev_err(&(pdev->dev),
-			"Unable to allocate driver platform data!\n");
-		goto exit;
-	}
-
-	mbox = (struct mbox *) pdev->dev.platform_data;
-	mbox->pdev = pdev;
-	mbox->write_index = 0;
-	mbox->read_index = 0;
-
-	INIT_LIST_HEAD(&(mbox->list));
-	list_add_tail(&(mbox->list), &mboxs);
-
-	sprintf(mbox->name, "%s", MBOX_NAME);
-	spin_lock_init(&mbox->lock);
-
-	dev_info(&(pdev->dev), "Mailbox driver loaded\n");
-
-exit:
-	return res;
-}
-
-static struct platform_driver mbox_driver = {
-	.driver = {
-		.name = MBOX_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init mbox_init(void)
-{
-	return platform_driver_probe(&mbox_driver, mbox_probe);
-}
-
-module_init(mbox_init);
-
-void __exit mbox_exit(void)
-{
-	platform_driver_unregister(&mbox_driver);
-}
-
-module_exit(mbox_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MBOX driver");
diff --git a/arch/arm/mach-ux500/modem-irq-db5500.c b/arch/arm/mach-ux500/modem-irq-db5500.c
deleted file mode 100644
index 6b86416..0000000
--- a/arch/arm/mach-ux500/modem-irq-db5500.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
- * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
- * License terms: GNU General Public License (GPL), version 2.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <mach/id.h>
-
-#define MODEM_INTCON_BASE_ADDR 0xBFFD3000
-#define MODEM_INTCON_SIZE 0xFFF
-
-#define DEST_IRQ41_OFFSET 0x2A4
-#define DEST_IRQ43_OFFSET 0x2AC
-#define DEST_IRQ45_OFFSET 0x2B4
-
-#define PRIO_IRQ41_OFFSET 0x6A4
-#define PRIO_IRQ43_OFFSET 0x6AC
-#define PRIO_IRQ45_OFFSET 0x6B4
-
-#define ALLOW_IRQ_OFFSET 0x104
-
-#define MODEM_INTCON_CPU_NBR 0x1
-#define MODEM_INTCON_PRIO_HIGH 0x0
-
-#define MODEM_INTCON_ALLOW_IRQ41 0x0200
-#define MODEM_INTCON_ALLOW_IRQ43 0x0800
-#define MODEM_INTCON_ALLOW_IRQ45 0x2000
-
-#define MODEM_IRQ_REG_OFFSET 0x4
-
-struct modem_irq {
-	void __iomem *modem_intcon_base;
-};
-
-
-static void setup_modem_intcon(void __iomem *modem_intcon_base)
-{
-	/* IC_DESTINATION_BASE_ARRAY - Which CPU to receive the IRQ */
-	writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ41_OFFSET);
-	writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ43_OFFSET);
-	writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ45_OFFSET);
-
-	/* IC_PRIORITY_BASE_ARRAY - IRQ priority in modem IRQ controller */
-	writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ41_OFFSET);
-	writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ43_OFFSET);
-	writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ45_OFFSET);
-
-	/* IC_ALLOW_ARRAY - IRQ enable */
-	writel(MODEM_INTCON_ALLOW_IRQ41 |
-		   MODEM_INTCON_ALLOW_IRQ43 |
-		   MODEM_INTCON_ALLOW_IRQ45,
-		   modem_intcon_base + ALLOW_IRQ_OFFSET);
-}
-
-static irqreturn_t modem_cpu_irq_handler(int irq, void *data)
-{
-	int real_irq;
-	int virt_irq;
-	struct modem_irq *mi = (struct modem_irq *)data;
-
-	/* Read modem side IRQ number from modem IRQ controller */
-	real_irq = readl(mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET) & 0xFF;
-	virt_irq = IRQ_MODEM_EVENTS_BASE + real_irq;
-
-	pr_debug("modem_irq: Worker read addr 0x%X and got value 0x%X "
-		 "which will be 0x%X (%d) which translates to "
-		 "virtual IRQ 0x%X (%d)!\n",
-		   (u32)mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET,
-		   real_irq,
-		   real_irq & 0xFF,
-		   real_irq & 0xFF,
-		   virt_irq,
-		   virt_irq);
-
-	if (virt_irq != 0)
-		generic_handle_irq(virt_irq);
-
-	pr_debug("modem_irq: Done handling virtual IRQ %d!\n", virt_irq);
-
-	return IRQ_HANDLED;
-}
-
-static void create_virtual_irq(int irq, struct irq_chip *modem_irq_chip)
-{
-	irq_set_chip_and_handler(irq, modem_irq_chip, handle_simple_irq);
-	set_irq_flags(irq, IRQF_VALID);
-
-	pr_debug("modem_irq: Created virtual IRQ %d\n", irq);
-}
-
-static int modem_irq_init(void)
-{
-	int err;
-	static struct irq_chip  modem_irq_chip;
-	struct modem_irq *mi;
-
-	if (!cpu_is_u5500())
-		return -ENODEV;
-
-	pr_info("modem_irq: Set up IRQ handler for incoming modem IRQ %d\n",
-		   IRQ_DB5500_MODEM);
-
-	mi = kmalloc(sizeof(struct modem_irq), GFP_KERNEL);
-	if (!mi) {
-		pr_err("modem_irq: Could not allocate device\n");
-		return -ENOMEM;
-	}
-
-	mi->modem_intcon_base =
-		ioremap(MODEM_INTCON_BASE_ADDR, MODEM_INTCON_SIZE);
-	pr_debug("modem_irq: ioremapped modem_intcon_base from "
-		 "phy 0x%x to virt 0x%x\n", MODEM_INTCON_BASE_ADDR,
-		 (u32)mi->modem_intcon_base);
-
-	setup_modem_intcon(mi->modem_intcon_base);
-
-	modem_irq_chip = dummy_irq_chip;
-	modem_irq_chip.name = "modem_irq";
-
-	/* Create the virtual IRQ:s needed */
-	create_virtual_irq(MBOX_PAIR0_VIRT_IRQ, &modem_irq_chip);
-	create_virtual_irq(MBOX_PAIR1_VIRT_IRQ, &modem_irq_chip);
-	create_virtual_irq(MBOX_PAIR2_VIRT_IRQ, &modem_irq_chip);
-
-	err = request_threaded_irq(IRQ_DB5500_MODEM, NULL,
-				   modem_cpu_irq_handler, IRQF_ONESHOT,
-				   "modem_irq", mi);
-	if (err)
-		pr_err("modem_irq: Could not register IRQ %d\n",
-		       IRQ_DB5500_MODEM);
-
-	return 0;
-}
-
-arch_initcall(modem_irq_init);
diff --git a/arch/arm/mach-ux500/pins-db5500.h b/arch/arm/mach-ux500/pins-db5500.h
deleted file mode 100644
index bf50c21..0000000
--- a/arch/arm/mach-ux500/pins-db5500.h
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License terms: GNU General Public License, version 2
- * Author: Rabin Vincent <rabin.vincent@stericsson.com>
- */
-
-#ifndef __MACH_DB5500_PINS_H
-#define __MACH_DB5500_PINS_H
-
-#define GPIO0_GPIO		PIN_CFG(0, GPIO)
-#define GPIO0_SM_CS3n		PIN_CFG(0, ALT_A)
-
-#define GPIO1_GPIO		PIN_CFG(1, GPIO)
-#define GPIO1_SM_A3		PIN_CFG(1, ALT_A)
-
-#define GPIO2_GPIO		PIN_CFG(2, GPIO)
-#define GPIO2_SM_A4		PIN_CFG(2, ALT_A)
-#define GPIO2_SM_AVD		PIN_CFG(2, ALT_B)
-
-#define GPIO3_GPIO		PIN_CFG(3, GPIO)
-#define GPIO3_I2C1_SCL		PIN_CFG(3, ALT_A)
-
-#define GPIO4_GPIO		PIN_CFG(4, GPIO)
-#define GPIO4_I2C1_SDA		PIN_CFG(4, ALT_A)
-
-#define GPIO5_GPIO		PIN_CFG(5, GPIO)
-#define GPIO5_MC0_DAT0		PIN_CFG(5, ALT_A)
-#define GPIO5_SM_ADQ8		PIN_CFG(5, ALT_B)
-
-#define GPIO6_GPIO		PIN_CFG(6, GPIO)
-#define GPIO6_MC0_DAT1		PIN_CFG(6, ALT_A)
-#define GPIO6_SM_ADQ0		PIN_CFG(6, ALT_B)
-
-#define GPIO7_GPIO		PIN_CFG(7, GPIO)
-#define GPIO7_MC0_DAT2		PIN_CFG(7, ALT_A)
-#define GPIO7_SM_ADQ9		PIN_CFG(7, ALT_B)
-
-#define GPIO8_GPIO		PIN_CFG(8, GPIO)
-#define GPIO8_MC0_DAT3		PIN_CFG(8, ALT_A)
-#define GPIO8_SM_ADQ1		PIN_CFG(8, ALT_B)
-
-#define GPIO9_GPIO		PIN_CFG(9, GPIO)
-#define GPIO9_MC0_DAT4		PIN_CFG(9, ALT_A)
-#define GPIO9_SM_ADQ10		PIN_CFG(9, ALT_B)
-
-#define GPIO10_GPIO		PIN_CFG(10, GPIO)
-#define GPIO10_MC0_DAT5		PIN_CFG(10, ALT_A)
-#define GPIO10_SM_ADQ2		PIN_CFG(10, ALT_B)
-
-#define GPIO11_GPIO		PIN_CFG(11, GPIO)
-#define GPIO11_MC0_DAT6		PIN_CFG(11, ALT_A)
-#define GPIO11_SM_ADQ11		PIN_CFG(11, ALT_B)
-
-#define GPIO12_GPIO		PIN_CFG(12, GPIO)
-#define GPIO12_MC0_DAT7		PIN_CFG(12, ALT_A)
-#define GPIO12_SM_ADQ3		PIN_CFG(12, ALT_B)
-
-#define GPIO13_GPIO		PIN_CFG(13, GPIO)
-#define GPIO13_MC0_CMD		PIN_CFG(13, ALT_A)
-#define GPIO13_SM_BUSY0n	PIN_CFG(13, ALT_B)
-#define GPIO13_SM_WAIT0n	PIN_CFG(13, ALT_C)
-
-#define GPIO14_GPIO		PIN_CFG(14, GPIO)
-#define GPIO14_MC0_CLK		PIN_CFG(14, ALT_A)
-#define GPIO14_SM_CS1n		PIN_CFG(14, ALT_B)
-#define GPIO14_SM_CKO		PIN_CFG(14, ALT_C)
-
-#define GPIO15_GPIO		PIN_CFG(15, GPIO)
-#define GPIO15_SM_A5		PIN_CFG(15, ALT_A)
-#define GPIO15_SM_CLE		PIN_CFG(15, ALT_B)
-
-#define GPIO16_GPIO		PIN_CFG(16, GPIO)
-#define GPIO16_MC2_CMD		PIN_CFG(16, ALT_A)
-#define GPIO16_SM_OEn		PIN_CFG(16, ALT_B)
-
-#define GPIO17_GPIO		PIN_CFG(17, GPIO)
-#define GPIO17_MC2_CLK		PIN_CFG(17, ALT_A)
-#define GPIO17_SM_WEn		PIN_CFG(17, ALT_B)
-
-#define GPIO18_GPIO		PIN_CFG(18, GPIO)
-#define GPIO18_SM_A6		PIN_CFG(18, ALT_A)
-#define GPIO18_SM_ALE		PIN_CFG(18, ALT_B)
-#define GPIO18_SM_AVDn		PIN_CFG(18, ALT_C)
-
-#define GPIO19_GPIO		PIN_CFG(19, GPIO)
-#define GPIO19_MC2_DAT1		PIN_CFG(19, ALT_A)
-#define GPIO19_SM_ADQ4		PIN_CFG(19, ALT_B)
-
-#define GPIO20_GPIO		PIN_CFG(20, GPIO)
-#define GPIO20_MC2_DAT3		PIN_CFG(20, ALT_A)
-#define GPIO20_SM_ADQ5		PIN_CFG(20, ALT_B)
-
-#define GPIO21_GPIO		PIN_CFG(21, GPIO)
-#define GPIO21_MC2_DAT5		PIN_CFG(21, ALT_A)
-#define GPIO21_SM_ADQ6		PIN_CFG(21, ALT_B)
-
-#define GPIO22_GPIO		PIN_CFG(22, GPIO)
-#define GPIO22_MC2_DAT7		PIN_CFG(22, ALT_A)
-#define GPIO22_SM_ADQ7		PIN_CFG(22, ALT_B)
-
-#define GPIO23_GPIO		PIN_CFG(23, GPIO)
-#define GPIO23_MC2_DAT0		PIN_CFG(23, ALT_A)
-#define GPIO23_SM_ADQ12		PIN_CFG(23, ALT_B)
-#define GPIO23_MC0_DAT1		PIN_CFG(23, ALT_C)
-
-#define GPIO24_GPIO		PIN_CFG(24, GPIO)
-#define GPIO24_MC2_DAT2		PIN_CFG(24, ALT_A)
-#define GPIO24_SM_ADQ13		PIN_CFG(24, ALT_B)
-#define GPIO24_MC0_DAT3		PIN_CFG(24, ALT_C)
-
-#define GPIO25_GPIO		PIN_CFG(25, GPIO)
-#define GPIO25_MC2_DAT4		PIN_CFG(25, ALT_A)
-#define GPIO25_SM_ADQ14		PIN_CFG(25, ALT_B)
-#define GPIO25_MC0_CMD		PIN_CFG(25, ALT_C)
-
-#define GPIO26_GPIO		PIN_CFG(26, GPIO)
-#define GPIO26_MC2_DAT6		PIN_CFG(26, ALT_A)
-#define GPIO26_SM_ADQ15		PIN_CFG(26, ALT_B)
-
-#define GPIO27_GPIO		PIN_CFG(27, GPIO)
-#define GPIO27_SM_CS0n		PIN_CFG(27, ALT_A)
-#define GPIO27_SM_PS0n		PIN_CFG(27, ALT_B)
-
-#define GPIO28_GPIO		PIN_CFG(28, GPIO)
-#define GPIO28_U0_TXD		PIN_CFG(28, ALT_A)
-#define GPIO28_SM_A0		PIN_CFG(28, ALT_B)
-
-#define GPIO29_GPIO		PIN_CFG(29, GPIO)
-#define GPIO29_U0_RXD		PIN_CFG(29, ALT_A)
-#define GPIO29_SM_A1		PIN_CFG(29, ALT_B)
-#define GPIO29_PWM_0		PIN_CFG(29, ALT_C)
-
-#define GPIO30_GPIO		PIN_CFG(30, GPIO)
-#define GPIO30_MC0_DAT5		PIN_CFG(30, ALT_A)
-#define GPIO30_SM_A2		PIN_CFG(30, ALT_B)
-#define GPIO30_PWM_1		PIN_CFG(30, ALT_C)
-
-#define GPIO31_GPIO		PIN_CFG(31, GPIO)
-#define GPIO31_MC0_DAT7		PIN_CFG(31, ALT_A)
-#define GPIO31_SM_CS2n		PIN_CFG(31, ALT_B)
-#define GPIO31_PWM_2		PIN_CFG(31, ALT_C)
-
-#define GPIO32_GPIO		PIN_CFG(32, GPIO)
-#define GPIO32_MSP0_TCK		PIN_CFG(32, ALT_A)
-#define GPIO32_ACCI2S0_SCK	PIN_CFG(32, ALT_B)
-
-#define GPIO33_GPIO		PIN_CFG(33, GPIO)
-#define GPIO33_MSP0_TFS		PIN_CFG(33, ALT_A)
-#define GPIO33_ACCI2S0_WS	PIN_CFG(33, ALT_B)
-
-#define GPIO34_GPIO		PIN_CFG(34, GPIO)
-#define GPIO34_MSP0_TXD		PIN_CFG(34, ALT_A)
-#define GPIO34_ACCI2S0_DLD	PIN_CFG(34, ALT_B)
-
-#define GPIO35_GPIO		PIN_CFG(35, GPIO)
-#define GPIO35_MSP0_RXD		PIN_CFG(35, ALT_A)
-#define GPIO35_ACCI2S0_ULD	PIN_CFG(35, ALT_B)
-
-#define GPIO64_GPIO		PIN_CFG(64, GPIO)
-#define GPIO64_USB_DAT0		PIN_CFG(64, ALT_A)
-#define GPIO64_U0_TXD		PIN_CFG(64, ALT_B)
-
-#define GPIO65_GPIO		PIN_CFG(65, GPIO)
-#define GPIO65_USB_DAT1		PIN_CFG(65, ALT_A)
-#define GPIO65_U0_RXD		PIN_CFG(65, ALT_B)
-
-#define GPIO66_GPIO		PIN_CFG(66, GPIO)
-#define GPIO66_USB_DAT2		PIN_CFG(66, ALT_A)
-
-#define GPIO67_GPIO		PIN_CFG(67, GPIO)
-#define GPIO67_USB_DAT3		PIN_CFG(67, ALT_A)
-
-#define GPIO68_GPIO		PIN_CFG(68, GPIO)
-#define GPIO68_USB_DAT4		PIN_CFG(68, ALT_A)
-
-#define GPIO69_GPIO		PIN_CFG(69, GPIO)
-#define GPIO69_USB_DAT5		PIN_CFG(69, ALT_A)
-
-#define GPIO70_GPIO		PIN_CFG(70, GPIO)
-#define GPIO70_USB_DAT6		PIN_CFG(70, ALT_A)
-
-#define GPIO71_GPIO		PIN_CFG(71, GPIO)
-#define GPIO71_USB_DAT7		PIN_CFG(71, ALT_A)
-
-#define GPIO72_GPIO		PIN_CFG(72, GPIO)
-#define GPIO72_USB_STP		PIN_CFG(72, ALT_A)
-
-#define GPIO73_GPIO		PIN_CFG(73, GPIO)
-#define GPIO73_USB_DIR		PIN_CFG(73, ALT_A)
-
-#define GPIO74_GPIO		PIN_CFG(74, GPIO)
-#define GPIO74_USB_NXT		PIN_CFG(74, ALT_A)
-
-#define GPIO75_GPIO		PIN_CFG(75, GPIO)
-#define GPIO75_USB_XCLK		PIN_CFG(75, ALT_A)
-
-#define GPIO76_GPIO		PIN_CFG(76, GPIO)
-
-#define GPIO77_GPIO		PIN_CFG(77, GPIO)
-#define GPIO77_ACCTX_ON		PIN_CFG(77, ALT_A)
-
-#define GPIO78_GPIO		PIN_CFG(78, GPIO)
-#define GPIO78_IRQn		PIN_CFG(78, ALT_A)
-
-#define GPIO79_GPIO		PIN_CFG(79, GPIO)
-#define GPIO79_ACCSIM_Clk	PIN_CFG(79, ALT_A)
-
-#define GPIO80_GPIO		PIN_CFG(80, GPIO)
-#define GPIO80_ACCSIM_Da	PIN_CFG(80, ALT_A)
-
-#define GPIO81_GPIO		PIN_CFG(81, GPIO)
-#define GPIO81_ACCSIM_Reset	PIN_CFG(81, ALT_A)
-
-#define GPIO82_GPIO		PIN_CFG(82, GPIO)
-#define GPIO82_ACCSIM_DDir	PIN_CFG(82, ALT_A)
-
-#define GPIO96_GPIO		PIN_CFG(96, GPIO)
-#define GPIO96_MSP1_TCK		PIN_CFG(96, ALT_A)
-#define GPIO96_PRCMU_DEBUG3	PIN_CFG(96, ALT_B)
-#define GPIO96_PRCMU_DEBUG7	PIN_CFG(96, ALT_C)
-
-#define GPIO97_GPIO		PIN_CFG(97, GPIO)
-#define GPIO97_MSP1_TFS		PIN_CFG(97, ALT_A)
-#define GPIO97_PRCMU_DEBUG2	PIN_CFG(97, ALT_B)
-#define GPIO97_PRCMU_DEBUG6	PIN_CFG(97, ALT_C)
-
-#define GPIO98_GPIO		PIN_CFG(98, GPIO)
-#define GPIO98_MSP1_TXD		PIN_CFG(98, ALT_A)
-#define GPIO98_PRCMU_DEBUG1	PIN_CFG(98, ALT_B)
-#define GPIO98_PRCMU_DEBUG5	PIN_CFG(98, ALT_C)
-
-#define GPIO99_GPIO		PIN_CFG(99, GPIO)
-#define GPIO99_MSP1_RXD		PIN_CFG(99, ALT_A)
-#define GPIO99_PRCMU_DEBUG0	PIN_CFG(99, ALT_B)
-#define GPIO99_PRCMU_DEBUG4	PIN_CFG(99, ALT_C)
-
-#define GPIO100_GPIO		PIN_CFG(100, GPIO)
-#define GPIO100_I2C0_SCL	PIN_CFG(100, ALT_A)
-
-#define GPIO101_GPIO		PIN_CFG(101, GPIO)
-#define GPIO101_I2C0_SDA	PIN_CFG(101, ALT_A)
-
-#define GPIO128_GPIO		PIN_CFG(128, GPIO)
-#define GPIO128_KP_I0		PIN_CFG(128, ALT_A)
-#define GPIO128_BUSMON_D0	PIN_CFG(128, ALT_B)
-
-#define GPIO129_GPIO		PIN_CFG(129, GPIO)
-#define GPIO129_KP_O0		PIN_CFG(129, ALT_A)
-#define GPIO129_BUSMON_D1	PIN_CFG(129, ALT_B)
-
-#define GPIO130_GPIO		PIN_CFG(130, GPIO)
-#define GPIO130_KP_I1		PIN_CFG(130, ALT_A)
-#define GPIO130_BUSMON_D2	PIN_CFG(130, ALT_B)
-
-#define GPIO131_GPIO		PIN_CFG(131, GPIO)
-#define GPIO131_KP_O1		PIN_CFG(131, ALT_A)
-#define GPIO131_BUSMON_D3	PIN_CFG(131, ALT_B)
-
-#define GPIO132_GPIO		PIN_CFG(132, GPIO)
-#define GPIO132_KP_I2		PIN_CFG(132, ALT_A)
-#define GPIO132_ETM_D15		PIN_CFG(132, ALT_B)
-#define GPIO132_STMAPE_CLK	PIN_CFG(132, ALT_C)
-
-#define GPIO133_GPIO		PIN_CFG(133, GPIO)
-#define GPIO133_KP_O2		PIN_CFG(133, ALT_A)
-#define GPIO133_ETM_D14		PIN_CFG(133, ALT_B)
-#define GPIO133_U0_RXD		PIN_CFG(133, ALT_C)
-
-#define GPIO134_GPIO		PIN_CFG(134, GPIO)
-#define GPIO134_KP_I3		PIN_CFG(134, ALT_A)
-#define GPIO134_ETM_D13		PIN_CFG(134, ALT_B)
-#define GPIO134_STMAPE_DAT0	PIN_CFG(134, ALT_C)
-
-#define GPIO135_GPIO		PIN_CFG(135, GPIO)
-#define GPIO135_KP_O3		PIN_CFG(135, ALT_A)
-#define GPIO135_ETM_D12		PIN_CFG(135, ALT_B)
-#define GPIO135_STMAPE_DAT1	PIN_CFG(135, ALT_C)
-
-#define GPIO136_GPIO		PIN_CFG(136, GPIO)
-#define GPIO136_KP_I4		PIN_CFG(136, ALT_A)
-#define GPIO136_ETM_D11		PIN_CFG(136, ALT_B)
-#define GPIO136_STMAPE_DAT2	PIN_CFG(136, ALT_C)
-
-#define GPIO137_GPIO		PIN_CFG(137, GPIO)
-#define GPIO137_KP_O4		PIN_CFG(137, ALT_A)
-#define GPIO137_ETM_D10		PIN_CFG(137, ALT_B)
-#define GPIO137_STMAPE_DAT3	PIN_CFG(137, ALT_C)
-
-#define GPIO138_GPIO		PIN_CFG(138, GPIO)
-#define GPIO138_KP_I5		PIN_CFG(138, ALT_A)
-#define GPIO138_ETM_D9		PIN_CFG(138, ALT_B)
-#define GPIO138_U0_TXD		PIN_CFG(138, ALT_C)
-
-#define GPIO139_GPIO		PIN_CFG(139, GPIO)
-#define GPIO139_KP_O5		PIN_CFG(139, ALT_A)
-#define GPIO139_ETM_D8		PIN_CFG(139, ALT_B)
-#define GPIO139_BUSMON_D11	PIN_CFG(139, ALT_C)
-
-#define GPIO140_GPIO		PIN_CFG(140, GPIO)
-#define GPIO140_KP_I6		PIN_CFG(140, ALT_A)
-#define GPIO140_ETM_D7		PIN_CFG(140, ALT_B)
-#define GPIO140_STMAPE_CLK	PIN_CFG(140, ALT_C)
-
-#define GPIO141_GPIO		PIN_CFG(141, GPIO)
-#define GPIO141_KP_O6		PIN_CFG(141, ALT_A)
-#define GPIO141_ETM_D6		PIN_CFG(141, ALT_B)
-#define GPIO141_U0_RXD		PIN_CFG(141, ALT_C)
-
-#define GPIO142_GPIO		PIN_CFG(142, GPIO)
-#define GPIO142_KP_I7		PIN_CFG(142, ALT_A)
-#define GPIO142_ETM_D5		PIN_CFG(142, ALT_B)
-#define GPIO142_STMAPE_DAT0	PIN_CFG(142, ALT_C)
-
-#define GPIO143_GPIO		PIN_CFG(143, GPIO)
-#define GPIO143_KP_O7		PIN_CFG(143, ALT_A)
-#define GPIO143_ETM_D4		PIN_CFG(143, ALT_B)
-#define GPIO143_STMAPE_DAT1	PIN_CFG(143, ALT_C)
-
-#define GPIO144_GPIO		PIN_CFG(144, GPIO)
-#define GPIO144_I2C3_SCL	PIN_CFG(144, ALT_A)
-#define GPIO144_ETM_D3		PIN_CFG(144, ALT_B)
-#define GPIO144_STMAPE_DAT2	PIN_CFG(144, ALT_C)
-
-#define GPIO145_GPIO		PIN_CFG(145, GPIO)
-#define GPIO145_I2C3_SDA	PIN_CFG(145, ALT_A)
-#define GPIO145_ETM_D2		PIN_CFG(145, ALT_B)
-#define GPIO145_STMAPE_DAT3	PIN_CFG(145, ALT_C)
-
-#define GPIO146_GPIO		PIN_CFG(146, GPIO)
-#define GPIO146_PWM_0		PIN_CFG(146, ALT_A)
-#define GPIO146_ETM_D1		PIN_CFG(146, ALT_B)
-
-#define GPIO147_GPIO		PIN_CFG(147, GPIO)
-#define GPIO147_PWM_1		PIN_CFG(147, ALT_A)
-#define GPIO147_ETM_D0		PIN_CFG(147, ALT_B)
-
-#define GPIO148_GPIO		PIN_CFG(148, GPIO)
-#define GPIO148_PWM_2		PIN_CFG(148, ALT_A)
-#define GPIO148_ETM_CLK		PIN_CFG(148, ALT_B)
-
-#define GPIO160_GPIO		PIN_CFG(160, GPIO)
-#define GPIO160_CLKOUT_REQn	PIN_CFG(160, ALT_A)
-
-#define GPIO161_GPIO		PIN_CFG(161, GPIO)
-#define GPIO161_CLKOUT_0	PIN_CFG(161, ALT_A)
-
-#define GPIO162_GPIO		PIN_CFG(162, GPIO)
-#define GPIO162_CLKOUT_1	PIN_CFG(162, ALT_A)
-
-#define GPIO163_GPIO		PIN_CFG(163, GPIO)
-
-#define GPIO164_GPIO		PIN_CFG(164, GPIO)
-#define GPIO164_GPS_START	PIN_CFG(164, ALT_A)
-
-#define GPIO165_GPIO		PIN_CFG(165, GPIO)
-#define GPIO165_SPI1_CS2n	PIN_CFG(165, ALT_A)
-#define GPIO165_U3_RXD		PIN_CFG(165, ALT_B)
-#define GPIO165_BUSMON_D20	PIN_CFG(165, ALT_C)
-
-#define GPIO166_GPIO		PIN_CFG(166, GPIO)
-#define GPIO166_SPI1_CS1n	PIN_CFG(166, ALT_A)
-#define GPIO166_U3_TXD		PIN_CFG(166, ALT_B)
-#define GPIO166_BUSMON_D21	PIN_CFG(166, ALT_C)
-
-#define GPIO167_GPIO		PIN_CFG(167, GPIO)
-#define GPIO167_SPI1_CS0n	PIN_CFG(167, ALT_A)
-#define GPIO167_U3_RTSn		PIN_CFG(167, ALT_B)
-#define GPIO167_BUSMON_D22	PIN_CFG(167, ALT_C)
-
-#define GPIO168_GPIO		PIN_CFG(168, GPIO)
-#define GPIO168_SPI1_RXD	PIN_CFG(168, ALT_A)
-#define GPIO168_U3_CTSn		PIN_CFG(168, ALT_B)
-#define GPIO168_BUSMON_D23	PIN_CFG(168, ALT_C)
-
-#define GPIO169_GPIO		PIN_CFG(169, GPIO)
-#define GPIO169_SPI1_TXD	PIN_CFG(169, ALT_A)
-#define GPIO169_DDR_RC		PIN_CFG(169, ALT_B)
-#define GPIO169_BUSMON_D24	PIN_CFG(169, ALT_C)
-
-#define GPIO170_GPIO		PIN_CFG(170, GPIO)
-#define GPIO170_SPI1_CLK	PIN_CFG(170, ALT_A)
-
-#define GPIO171_GPIO		PIN_CFG(171, GPIO)
-#define GPIO171_MC3_DAT0	PIN_CFG(171, ALT_A)
-#define GPIO171_SPI3_RXD	PIN_CFG(171, ALT_B)
-#define GPIO171_BUSMON_D25	PIN_CFG(171, ALT_C)
-
-#define GPIO172_GPIO		PIN_CFG(172, GPIO)
-#define GPIO172_MC3_DAT1	PIN_CFG(172, ALT_A)
-#define GPIO172_SPI3_CS1n	PIN_CFG(172, ALT_B)
-#define GPIO172_BUSMON_D26	PIN_CFG(172, ALT_C)
-
-#define GPIO173_GPIO		PIN_CFG(173, GPIO)
-#define GPIO173_MC3_DAT2	PIN_CFG(173, ALT_A)
-#define GPIO173_SPI3_CS2n	PIN_CFG(173, ALT_B)
-#define GPIO173_BUSMON_D27	PIN_CFG(173, ALT_C)
-
-#define GPIO174_GPIO		PIN_CFG(174, GPIO)
-#define GPIO174_MC3_DAT3	PIN_CFG(174, ALT_A)
-#define GPIO174_SPI3_CS0n	PIN_CFG(174, ALT_B)
-#define GPIO174_BUSMON_D28	PIN_CFG(174, ALT_C)
-
-#define GPIO175_GPIO		PIN_CFG(175, GPIO)
-#define GPIO175_MC3_CMD		PIN_CFG(175, ALT_A)
-#define GPIO175_SPI3_TXD	PIN_CFG(175, ALT_B)
-#define GPIO175_BUSMON_D29	PIN_CFG(175, ALT_C)
-
-#define GPIO176_GPIO		PIN_CFG(176, GPIO)
-#define GPIO176_MC3_CLK		PIN_CFG(176, ALT_A)
-#define GPIO176_SPI3_CLK	PIN_CFG(176, ALT_B)
-
-#define GPIO177_GPIO		PIN_CFG(177, GPIO)
-#define GPIO177_U2_RXD		PIN_CFG(177, ALT_A)
-#define GPIO177_I2C3_SCL	PIN_CFG(177, ALT_B)
-#define GPIO177_BUSMON_D30	PIN_CFG(177, ALT_C)
-
-#define GPIO178_GPIO		PIN_CFG(178, GPIO)
-#define GPIO178_U2_TXD		PIN_CFG(178, ALT_A)
-#define GPIO178_I2C3_SDA	PIN_CFG(178, ALT_B)
-#define GPIO178_BUSMON_D31	PIN_CFG(178, ALT_C)
-
-#define GPIO179_GPIO		PIN_CFG(179, GPIO)
-#define GPIO179_U2_CTSn		PIN_CFG(179, ALT_A)
-#define GPIO179_U3_RXD		PIN_CFG(179, ALT_B)
-#define GPIO179_BUSMON_D32	PIN_CFG(179, ALT_C)
-
-#define GPIO180_GPIO		PIN_CFG(180, GPIO)
-#define GPIO180_U2_RTSn		PIN_CFG(180, ALT_A)
-#define GPIO180_U3_TXD		PIN_CFG(180, ALT_B)
-#define GPIO180_BUSMON_D33	PIN_CFG(180, ALT_C)
-
-#define GPIO185_GPIO		PIN_CFG(185, GPIO)
-#define GPIO185_SPI3_CS2n	PIN_CFG(185, ALT_A)
-#define GPIO185_MC4_DAT0	PIN_CFG(185, ALT_B)
-
-#define GPIO186_GPIO		PIN_CFG(186, GPIO)
-#define GPIO186_SPI3_CS1n	PIN_CFG(186, ALT_A)
-#define GPIO186_MC4_DAT1	PIN_CFG(186, ALT_B)
-
-#define GPIO187_GPIO		PIN_CFG(187, GPIO)
-#define GPIO187_SPI3_CS0n	PIN_CFG(187, ALT_A)
-#define GPIO187_MC4_DAT2	PIN_CFG(187, ALT_B)
-
-#define GPIO188_GPIO		PIN_CFG(188, GPIO)
-#define GPIO188_SPI3_RXD	PIN_CFG(188, ALT_A)
-#define GPIO188_MC4_DAT3	PIN_CFG(188, ALT_B)
-
-#define GPIO189_GPIO		PIN_CFG(189, GPIO)
-#define GPIO189_SPI3_TXD	PIN_CFG(189, ALT_A)
-#define GPIO189_MC4_CMD		PIN_CFG(189, ALT_B)
-
-#define GPIO190_GPIO		PIN_CFG(190, GPIO)
-#define GPIO190_SPI3_CLK	PIN_CFG(190, ALT_A)
-#define GPIO190_MC4_CLK		PIN_CFG(190, ALT_B)
-
-#define GPIO191_GPIO		PIN_CFG(191, GPIO)
-#define GPIO191_MC1_DAT0	PIN_CFG(191, ALT_A)
-#define GPIO191_MC4_DAT4	PIN_CFG(191, ALT_B)
-#define GPIO191_STMAPE_DAT0	PIN_CFG(191, ALT_C)
-
-#define GPIO192_GPIO		PIN_CFG(192, GPIO)
-#define GPIO192_MC1_DAT1	PIN_CFG(192, ALT_A)
-#define GPIO192_MC4_DAT5	PIN_CFG(192, ALT_B)
-#define GPIO192_STMAPE_DAT1	PIN_CFG(192, ALT_C)
-
-#define GPIO193_GPIO		PIN_CFG(193, GPIO)
-#define GPIO193_MC1_DAT2	PIN_CFG(193, ALT_A)
-#define GPIO193_MC4_DAT6	PIN_CFG(193, ALT_B)
-#define GPIO193_STMAPE_DAT2	PIN_CFG(193, ALT_C)
-
-#define GPIO194_GPIO		PIN_CFG(194, GPIO)
-#define GPIO194_MC1_DAT3	PIN_CFG(194, ALT_A)
-#define GPIO194_MC4_DAT7	PIN_CFG(194, ALT_B)
-#define GPIO194_STMAPE_DAT3	PIN_CFG(194, ALT_C)
-
-#define GPIO195_GPIO		PIN_CFG(195, GPIO)
-#define GPIO195_MC1_CLK		PIN_CFG(195, ALT_A)
-#define GPIO195_STMAPE_CLK	PIN_CFG(195, ALT_B)
-#define GPIO195_BUSMON_CLK	PIN_CFG(195, ALT_C)
-
-#define GPIO196_GPIO		PIN_CFG(196, GPIO)
-#define GPIO196_MC1_CMD		PIN_CFG(196, ALT_A)
-#define GPIO196_U0_RXD		PIN_CFG(196, ALT_B)
-#define GPIO196_BUSMON_D38	PIN_CFG(196, ALT_C)
-
-#define GPIO197_GPIO		PIN_CFG(197, GPIO)
-#define GPIO197_MC1_CMDDIR	PIN_CFG(197, ALT_A)
-#define GPIO197_BUSMON_D39	PIN_CFG(197, ALT_B)
-
-#define GPIO198_GPIO		PIN_CFG(198, GPIO)
-#define GPIO198_MC1_FBCLK	PIN_CFG(198, ALT_A)
-
-#define GPIO199_GPIO		PIN_CFG(199, GPIO)
-#define GPIO199_MC1_DAT0DIR	PIN_CFG(199, ALT_A)
-#define GPIO199_BUSMON_D40	PIN_CFG(199, ALT_B)
-
-#define GPIO200_GPIO		PIN_CFG(200, GPIO)
-#define GPIO200_U1_TXD		PIN_CFG(200, ALT_A)
-#define GPIO200_ACCU0_RTSn	PIN_CFG(200, ALT_B)
-
-#define GPIO201_GPIO		PIN_CFG(201, GPIO)
-#define GPIO201_U1_RXD		PIN_CFG(201, ALT_A)
-#define GPIO201_ACCU0_CTSn	PIN_CFG(201, ALT_B)
-
-#define GPIO202_GPIO		PIN_CFG(202, GPIO)
-#define GPIO202_U1_CTSn		PIN_CFG(202, ALT_A)
-#define GPIO202_ACCU0_RXD	PIN_CFG(202, ALT_B)
-
-#define GPIO203_GPIO		PIN_CFG(203, GPIO)
-#define GPIO203_U1_RTSn		PIN_CFG(203, ALT_A)
-#define GPIO203_ACCU0_TXD	PIN_CFG(203, ALT_B)
-
-#define GPIO204_GPIO		PIN_CFG(204, GPIO)
-#define GPIO204_SPI0_CS2n	PIN_CFG(204, ALT_A)
-#define GPIO204_ACCGPIO_000	PIN_CFG(204, ALT_B)
-#define GPIO204_LCD_VSI1	PIN_CFG(204, ALT_C)
-
-#define GPIO205_GPIO		PIN_CFG(205, GPIO)
-#define GPIO205_SPI0_CS1n	PIN_CFG(205, ALT_A)
-#define GPIO205_ACCGPIO_001	PIN_CFG(205, ALT_B)
-#define GPIO205_LCD_D3		PIN_CFG(205, ALT_C)
-
-#define GPIO206_GPIO		PIN_CFG(206, GPIO)
-#define GPIO206_SPI0_CS0n	PIN_CFG(206, ALT_A)
-#define GPIO206_ACCGPIO_002	PIN_CFG(206, ALT_B)
-#define GPIO206_LCD_D2		PIN_CFG(206, ALT_C)
-
-#define GPIO207_GPIO		PIN_CFG(207, GPIO)
-#define GPIO207_SPI0_RXD	PIN_CFG(207, ALT_A)
-#define GPIO207_ACCGPIO_003	PIN_CFG(207, ALT_B)
-#define GPIO207_LCD_D1		PIN_CFG(207, ALT_C)
-
-#define GPIO208_GPIO		PIN_CFG(208, GPIO)
-#define GPIO208_SPI0_TXD	PIN_CFG(208, ALT_A)
-#define GPIO208_ACCGPIO_004	PIN_CFG(208, ALT_B)
-#define GPIO208_LCD_D0		PIN_CFG(208, ALT_C)
-
-#define GPIO209_GPIO		PIN_CFG(209, GPIO)
-#define GPIO209_SPI0_CLK	PIN_CFG(209, ALT_A)
-#define GPIO209_ACCGPIO_005	PIN_CFG(209, ALT_B)
-#define GPIO209_LCD_CLK		PIN_CFG(209, ALT_C)
-
-#define GPIO210_GPIO		PIN_CFG(210, GPIO)
-#define GPIO210_LCD_VSO		PIN_CFG(210, ALT_A)
-#define GPIO210_PRCMU_PWRCTRL1	PIN_CFG(210, ALT_B)
-
-#define GPIO211_GPIO		PIN_CFG(211, GPIO)
-#define GPIO211_LCD_VSI0	PIN_CFG(211, ALT_A)
-#define GPIO211_PRCMU_PWRCTRL2	PIN_CFG(211, ALT_B)
-
-#define GPIO212_GPIO		PIN_CFG(212, GPIO)
-#define GPIO212_SPI2_CS2n	PIN_CFG(212, ALT_A)
-#define GPIO212_LCD_HSO		PIN_CFG(212, ALT_B)
-
-#define GPIO213_GPIO		PIN_CFG(213, GPIO)
-#define GPIO213_SPI2_CS1n	PIN_CFG(213, ALT_A)
-#define GPIO213_LCD_DE		PIN_CFG(213, ALT_B)
-#define GPIO213_BUSMON_D16	PIN_CFG(213, ALT_C)
-
-#define GPIO214_GPIO		PIN_CFG(214, GPIO)
-#define GPIO214_SPI2_CS0n	PIN_CFG(214, ALT_A)
-#define GPIO214_LCD_D7		PIN_CFG(214, ALT_B)
-#define GPIO214_BUSMON_D17	PIN_CFG(214, ALT_C)
-
-#define GPIO215_GPIO		PIN_CFG(215, GPIO)
-#define GPIO215_SPI2_RXD	PIN_CFG(215, ALT_A)
-#define GPIO215_LCD_D6		PIN_CFG(215, ALT_B)
-#define GPIO215_BUSMON_D18	PIN_CFG(215, ALT_C)
-
-#define GPIO216_GPIO		PIN_CFG(216, GPIO)
-#define GPIO216_SPI2_CLK	PIN_CFG(216, ALT_A)
-#define GPIO216_LCD_D5		PIN_CFG(216, ALT_B)
-
-#define GPIO217_GPIO		PIN_CFG(217, GPIO)
-#define GPIO217_SPI2_TXD	PIN_CFG(217, ALT_A)
-#define GPIO217_LCD_D4		PIN_CFG(217, ALT_B)
-#define GPIO217_BUSMON_D19	PIN_CFG(217, ALT_C)
-
-#define GPIO218_GPIO		PIN_CFG(218, GPIO)
-#define GPIO218_I2C2_SCL	PIN_CFG(218, ALT_A)
-#define GPIO218_LCD_VSO		PIN_CFG(218, ALT_B)
-
-#define GPIO219_GPIO		PIN_CFG(219, GPIO)
-#define GPIO219_I2C2_SDA	PIN_CFG(219, ALT_A)
-#define GPIO219_LCD_D3		PIN_CFG(219, ALT_B)
-
-#define GPIO220_GPIO		PIN_CFG(220, GPIO)
-#define GPIO220_MSP2_TCK	PIN_CFG(220, ALT_A)
-#define GPIO220_LCD_D2		PIN_CFG(220, ALT_B)
-
-#define GPIO221_GPIO		PIN_CFG(221, GPIO)
-#define GPIO221_MSP2_TFS	PIN_CFG(221, ALT_A)
-#define GPIO221_LCD_D1		PIN_CFG(221, ALT_B)
-
-#define GPIO222_GPIO		PIN_CFG(222, GPIO)
-#define GPIO222_MSP2_TXD	PIN_CFG(222, ALT_A)
-#define GPIO222_LCD_D0		PIN_CFG(222, ALT_B)
-
-#define GPIO223_GPIO		PIN_CFG(223, GPIO)
-#define GPIO223_MSP2_RXD	PIN_CFG(223, ALT_A)
-#define GPIO223_LCD_CLK		PIN_CFG(223, ALT_B)
-
-#define GPIO224_GPIO		PIN_CFG(224, GPIO)
-#define GPIO224_PRCMU_PWRCTRL0	PIN_CFG(224, ALT_A)
-#define GPIO224_LCD_VSI1	PIN_CFG(224, ALT_B)
-
-#define GPIO225_GPIO		PIN_CFG(225, GPIO)
-#define GPIO225_PRCMU_PWRCTRL1	PIN_CFG(225, ALT_A)
-#define GPIO225_IRDA_RXD	PIN_CFG(225, ALT_B)
-
-#define GPIO226_GPIO		PIN_CFG(226, GPIO)
-#define GPIO226_PRCMU_PWRCTRL2	PIN_CFG(226, ALT_A)
-#define GPIO226_IRRC_DAT	PIN_CFG(226, ALT_B)
-
-#define GPIO227_GPIO		PIN_CFG(227, GPIO)
-#define GPIO227_IRRC_DAT	PIN_CFG(227, ALT_A)
-#define GPIO227_IRDA_TXD	PIN_CFG(227, ALT_B)
-
-#endif
diff --git a/arch/arm/mach-ux500/pins-db8500.h b/arch/arm/mach-ux500/pins-db8500.h
index 8b1d1a7..062c7ac 100644
--- a/arch/arm/mach-ux500/pins-db8500.h
+++ b/arch/arm/mach-ux500/pins-db8500.h
@@ -35,40 +35,40 @@
 
 #define GPIO4_GPIO		PIN_CFG(4, GPIO)
 #define GPIO4_U1_RXD		PIN_CFG(4, ALT_A)
-#define GPIO4_I2C4_SCL		PIN_CFG_INPUT(4, ALT_B, PULLUP)
+#define GPIO4_I2C4_SCL		PIN_CFG(4, ALT_B)
 #define GPIO4_IP_TRSTn		PIN_CFG(4, ALT_C)
 
 #define GPIO5_GPIO		PIN_CFG(5, GPIO)
 #define GPIO5_U1_TXD		PIN_CFG(5, ALT_A)
-#define GPIO5_I2C4_SDA		PIN_CFG_INPUT(5, ALT_B, PULLUP)
+#define GPIO5_I2C4_SDA		PIN_CFG(5, ALT_B)
 #define GPIO5_IP_GPIO6		PIN_CFG(5, ALT_C)
 
 #define GPIO6_GPIO		PIN_CFG(6, GPIO)
 #define GPIO6_U1_CTSn		PIN_CFG(6, ALT_A)
-#define GPIO6_I2C1_SCL		PIN_CFG_INPUT(6, ALT_B, PULLUP)
+#define GPIO6_I2C1_SCL		PIN_CFG(6, ALT_B)
 #define GPIO6_IP_GPIO0		PIN_CFG(6, ALT_C)
 
 #define GPIO7_GPIO		PIN_CFG(7, GPIO)
 #define GPIO7_U1_RTSn		PIN_CFG(7, ALT_A)
-#define GPIO7_I2C1_SDA		PIN_CFG_INPUT(7, ALT_B, PULLUP)
+#define GPIO7_I2C1_SDA		PIN_CFG(7, ALT_B)
 #define GPIO7_IP_GPIO1		PIN_CFG(7, ALT_C)
 
 #define GPIO8_GPIO		PIN_CFG(8, GPIO)
-#define GPIO8_IPI2C_SDA		PIN_CFG_INPUT(8, ALT_A, PULLUP)
-#define GPIO8_I2C2_SDA		PIN_CFG_INPUT(8, ALT_B, PULLUP)
+#define GPIO8_IPI2C_SDA		PIN_CFG(8, ALT_A)
+#define GPIO8_I2C2_SDA		PIN_CFG(8, ALT_B)
 
 #define GPIO9_GPIO		PIN_CFG(9, GPIO)
-#define GPIO9_IPI2C_SCL		PIN_CFG_INPUT(9, ALT_A, PULLUP)
-#define GPIO9_I2C2_SCL		PIN_CFG_INPUT(9, ALT_B, PULLUP)
+#define GPIO9_IPI2C_SCL		PIN_CFG(9, ALT_A)
+#define GPIO9_I2C2_SCL		PIN_CFG(9, ALT_B)
 
 #define GPIO10_GPIO		PIN_CFG(10, GPIO)
-#define GPIO10_IPI2C_SDA	PIN_CFG_INPUT(10, ALT_A, PULLUP)
-#define GPIO10_I2C2_SDA		PIN_CFG_INPUT(10, ALT_B, PULLUP)
+#define GPIO10_IPI2C_SDA	PIN_CFG(10, ALT_A)
+#define GPIO10_I2C2_SDA		PIN_CFG(10, ALT_B)
 #define GPIO10_IP_GPIO3		PIN_CFG(10, ALT_C)
 
 #define GPIO11_GPIO		PIN_CFG(11, GPIO)
-#define GPIO11_IPI2C_SCL	PIN_CFG_INPUT(11, ALT_A, PULLUP)
-#define GPIO11_I2C2_SCL		PIN_CFG_INPUT(11, ALT_B, PULLUP)
+#define GPIO11_IPI2C_SCL	PIN_CFG(11, ALT_A)
+#define GPIO11_I2C2_SCL		PIN_CFG(11, ALT_B)
 #define GPIO11_IP_GPIO2		PIN_CFG(11, ALT_C)
 
 #define GPIO12_GPIO		PIN_CFG(12, GPIO)
@@ -87,12 +87,12 @@
 
 #define GPIO16_GPIO		PIN_CFG(16, GPIO)
 #define GPIO16_MSP0_RFS		PIN_CFG(16, ALT_A)
-#define GPIO16_I2C1_SCL		PIN_CFG_INPUT(16, ALT_B, PULLUP)
+#define GPIO16_I2C1_SCL		PIN_CFG(16, ALT_B)
 #define GPIO16_SLIM0_DAT	PIN_CFG(16, ALT_C)
 
 #define GPIO17_GPIO		PIN_CFG(17, GPIO)
 #define GPIO17_MSP0_RCK		PIN_CFG(17, ALT_A)
-#define GPIO17_I2C1_SDA		PIN_CFG_INPUT(17, ALT_B, PULLUP)
+#define GPIO17_I2C1_SDA		PIN_CFG(17, ALT_B)
 #define GPIO17_SLIM0_CLK	PIN_CFG(17, ALT_C)
 
 #define GPIO18_GPIO		PIN_CFG(18, GPIO)
@@ -434,10 +434,10 @@
 #define GPIO146_SSP0_TXD	PIN_CFG(146, ALT_A)
 
 #define GPIO147_GPIO		PIN_CFG(147, GPIO)
-#define GPIO147_I2C0_SCL	PIN_CFG_INPUT(147, ALT_A, PULLUP)
+#define GPIO147_I2C0_SCL	PIN_CFG(147, ALT_A)
 
 #define GPIO148_GPIO		PIN_CFG(148, GPIO)
-#define GPIO148_I2C0_SDA	PIN_CFG_INPUT(148, ALT_A, PULLUP)
+#define GPIO148_I2C0_SDA	PIN_CFG(148, ALT_A)
 
 #define GPIO149_GPIO		PIN_CFG(149, GPIO)
 #define GPIO149_IP_GPIO0	PIN_CFG(149, ALT_A)
@@ -459,82 +459,82 @@
 #define GPIO152_KP_O9		PIN_CFG(152, ALT_C)
 
 #define GPIO153_GPIO		PIN_CFG(153, GPIO)
-#define GPIO153_KP_I7		PIN_CFG_INPUT(153, ALT_A, PULLDOWN)
+#define GPIO153_KP_I7		PIN_CFG(153, ALT_A)
 #define GPIO153_LCD_D24		PIN_CFG(153, ALT_B)
 #define GPIO153_U2_RXD		PIN_CFG(153, ALT_C)
 
 #define GPIO154_GPIO		PIN_CFG(154, GPIO)
-#define GPIO154_KP_I6		PIN_CFG_INPUT(154, ALT_A, PULLDOWN)
+#define GPIO154_KP_I6		PIN_CFG(154, ALT_A)
 #define GPIO154_LCD_D25		PIN_CFG(154, ALT_B)
 #define GPIO154_U2_TXD		PIN_CFG(154, ALT_C)
 
 #define GPIO155_GPIO		PIN_CFG(155, GPIO)
-#define GPIO155_KP_I5		PIN_CFG_INPUT(155, ALT_A, PULLDOWN)
+#define GPIO155_KP_I5		PIN_CFG(155, ALT_A)
 #define GPIO155_LCD_D26		PIN_CFG(155, ALT_B)
 #define GPIO155_STMAPE_CLK	PIN_CFG(155, ALT_C)
 
 #define GPIO156_GPIO		PIN_CFG(156, GPIO)
-#define GPIO156_KP_I4		PIN_CFG_INPUT(156, ALT_A, PULLDOWN)
+#define GPIO156_KP_I4		PIN_CFG(156, ALT_A)
 #define GPIO156_LCD_D27		PIN_CFG(156, ALT_B)
 #define GPIO156_STMAPE_DAT3	PIN_CFG(156, ALT_C)
 
 #define GPIO157_GPIO		PIN_CFG(157, GPIO)
-#define GPIO157_KP_O7		PIN_CFG_INPUT(157, ALT_A, PULLUP)
+#define GPIO157_KP_O7		PIN_CFG(157, ALT_A)
 #define GPIO157_LCD_D28		PIN_CFG(157, ALT_B)
 #define GPIO157_STMAPE_DAT2	PIN_CFG(157, ALT_C)
 
 #define GPIO158_GPIO		PIN_CFG(158, GPIO)
-#define GPIO158_KP_O6		PIN_CFG_INPUT(158, ALT_A, PULLUP)
+#define GPIO158_KP_O6		PIN_CFG(158, ALT_A)
 #define GPIO158_LCD_D29		PIN_CFG(158, ALT_B)
 #define GPIO158_STMAPE_DAT1	PIN_CFG(158, ALT_C)
 
 #define GPIO159_GPIO		PIN_CFG(159, GPIO)
-#define GPIO159_KP_O5		PIN_CFG_INPUT(159, ALT_A, PULLUP)
+#define GPIO159_KP_O5		PIN_CFG(159, ALT_A)
 #define GPIO159_LCD_D30		PIN_CFG(159, ALT_B)
 #define GPIO159_STMAPE_DAT0	PIN_CFG(159, ALT_C)
 
 #define GPIO160_GPIO		PIN_CFG(160, GPIO)
-#define GPIO160_KP_O4		PIN_CFG_INPUT(160, ALT_A, PULLUP)
+#define GPIO160_KP_O4		PIN_CFG(160, ALT_A)
 #define GPIO160_LCD_D31		PIN_CFG(160, ALT_B)
 #define GPIO160_NONE		PIN_CFG(160, ALT_C)
 
 #define GPIO161_GPIO		PIN_CFG(161, GPIO)
-#define GPIO161_KP_I3		PIN_CFG_INPUT(161, ALT_A, PULLDOWN)
+#define GPIO161_KP_I3		PIN_CFG(161, ALT_A)
 #define GPIO161_LCD_D32		PIN_CFG(161, ALT_B)
 #define GPIO161_UARTMOD_RXD	PIN_CFG(161, ALT_C)
 
 #define GPIO162_GPIO		PIN_CFG(162, GPIO)
-#define GPIO162_KP_I2		PIN_CFG_INPUT(162, ALT_A, PULLDOWN)
+#define GPIO162_KP_I2		PIN_CFG(162, ALT_A)
 #define GPIO162_LCD_D33		PIN_CFG(162, ALT_B)
 #define GPIO162_UARTMOD_TXD	PIN_CFG(162, ALT_C)
 
 #define GPIO163_GPIO		PIN_CFG(163, GPIO)
-#define GPIO163_KP_I1		PIN_CFG_INPUT(163, ALT_A, PULLDOWN)
+#define GPIO163_KP_I1		PIN_CFG(163, ALT_A)
 #define GPIO163_LCD_D34		PIN_CFG(163, ALT_B)
 #define GPIO163_STMMOD_CLK	PIN_CFG(163, ALT_C)
 
 #define GPIO164_GPIO		PIN_CFG(164, GPIO)
-#define GPIO164_KP_I0		PIN_CFG_INPUT(164, ALT_A, PULLUP)
+#define GPIO164_KP_I0		PIN_CFG(164, ALT_A)
 #define GPIO164_LCD_D35		PIN_CFG(164, ALT_B)
 #define GPIO164_STMMOD_DAT3	PIN_CFG(164, ALT_C)
 
 #define GPIO165_GPIO		PIN_CFG(165, GPIO)
-#define GPIO165_KP_O3		PIN_CFG_INPUT(165, ALT_A, PULLUP)
+#define GPIO165_KP_O3		PIN_CFG(165, ALT_A)
 #define GPIO165_LCD_D36		PIN_CFG(165, ALT_B)
 #define GPIO165_STMMOD_DAT2	PIN_CFG(165, ALT_C)
 
 #define GPIO166_GPIO		PIN_CFG(166, GPIO)
-#define GPIO166_KP_O2		PIN_CFG_INPUT(166, ALT_A, PULLUP)
+#define GPIO166_KP_O2		PIN_CFG(166, ALT_A)
 #define GPIO166_LCD_D37		PIN_CFG(166, ALT_B)
 #define GPIO166_STMMOD_DAT1	PIN_CFG(166, ALT_C)
 
 #define GPIO167_GPIO		PIN_CFG(167, GPIO)
-#define GPIO167_KP_O1		PIN_CFG_INPUT(167, ALT_A, PULLUP)
+#define GPIO167_KP_O1		PIN_CFG(167, ALT_A)
 #define GPIO167_LCD_D38		PIN_CFG(167, ALT_B)
 #define GPIO167_STMMOD_DAT0	PIN_CFG(167, ALT_C)
 
 #define GPIO168_GPIO		PIN_CFG(168, GPIO)
-#define GPIO168_KP_O0		PIN_CFG_INPUT(168, ALT_A, PULLUP)
+#define GPIO168_KP_O0		PIN_CFG(168, ALT_A)
 #define GPIO168_LCD_D39		PIN_CFG(168, ALT_B)
 #define GPIO168_NONE		PIN_CFG(168, ALT_C)
 
@@ -637,7 +637,7 @@
 #define GPIO216_GPIO		PIN_CFG(216, GPIO)
 #define GPIO216_MC1_DAT2DIR	PIN_CFG(216, ALT_A)
 #define GPIO216_MC3_CMDDIR	PIN_CFG(216, ALT_B)
-#define GPIO216_I2C3_SDA	PIN_CFG_INPUT(216, ALT_C, PULLUP)
+#define GPIO216_I2C3_SDA	PIN_CFG(216, ALT_C)
 #define GPIO216_SPI2_FRM	PIN_CFG(216, ALT_C)
 
 #define GPIO217_GPIO		PIN_CFG(217, GPIO)
@@ -649,7 +649,7 @@
 #define GPIO218_GPIO		PIN_CFG(218, GPIO)
 #define GPIO218_MC1_DAT31DIR	PIN_CFG(218, ALT_A)
 #define GPIO218_MC3_DAT0DIR	PIN_CFG(218, ALT_B)
-#define GPIO218_I2C3_SCL	PIN_CFG_INPUT(218, ALT_C, PULLUP)
+#define GPIO218_I2C3_SCL	PIN_CFG(218, ALT_C)
 #define GPIO218_SPI2_RXD	PIN_CFG(218, ALT_C)
 
 #define GPIO219_GPIO		PIN_CFG(219, GPIO)
@@ -698,12 +698,12 @@
 #define GPIO229_GPIO		PIN_CFG(229, GPIO)
 #define GPIO229_CLKOUT1		PIN_CFG(229, ALT_A)
 #define GPIO229_PWL		PIN_CFG(229, ALT_B)
-#define GPIO229_I2C3_SDA	PIN_CFG_INPUT(229, ALT_C, PULLUP)
+#define GPIO229_I2C3_SDA	PIN_CFG(229, ALT_C)
 
 #define GPIO230_GPIO		PIN_CFG(230, GPIO)
 #define GPIO230_CLKOUT2		PIN_CFG(230, ALT_A)
 #define GPIO230_PWL		PIN_CFG(230, ALT_B)
-#define GPIO230_I2C3_SCL	PIN_CFG_INPUT(230, ALT_C, PULLUP)
+#define GPIO230_I2C3_SCL	PIN_CFG(230, ALT_C)
 
 #define GPIO256_GPIO		PIN_CFG(256, GPIO)
 #define GPIO256_USB_NXT		PIN_CFG(256, ALT_A)
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index eff5842..da1d5ad 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -48,9 +48,7 @@
 
 static void __iomem *scu_base_addr(void)
 {
-	if (cpu_is_u5500())
-		return __io_address(U5500_SCU_BASE);
-	else if (cpu_is_u8500())
+	if (cpu_is_u8500_family())
 		return __io_address(U8500_SCU_BASE);
 	else
 		ux500_unknown_soc();
@@ -120,9 +118,7 @@
 {
 	void __iomem *backupram;
 
-	if (cpu_is_u5500())
-		backupram = __io_address(U5500_BACKUPRAM0_BASE);
-	else if (cpu_is_u8500())
+	if (cpu_is_u8500_family())
 		backupram = __io_address(U8500_BACKUPRAM0_BASE);
 	else
 		ux500_unknown_soc();
diff --git a/arch/arm/mach-ux500/ste-dma40-db5500.h b/arch/arm/mach-ux500/ste-dma40-db5500.h
deleted file mode 100644
index cb2110c..0000000
--- a/arch/arm/mach-ux500/ste-dma40-db5500.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- *
- * DB5500-SoC-specific configuration for DMA40
- */
-
-#ifndef STE_DMA40_DB5500_H
-#define STE_DMA40_DB5500_H
-
-#define DB5500_DMA_NR_DEV 64
-
-enum dma_src_dev_type {
-	DB5500_DMA_DEV0_SPI0_RX = 0,
-	DB5500_DMA_DEV1_SPI1_RX = 1,
-	DB5500_DMA_DEV2_SPI2_RX = 2,
-	DB5500_DMA_DEV3_SPI3_RX = 3,
-	DB5500_DMA_DEV4_USB_OTG_IEP_1_9 = 4,
-	DB5500_DMA_DEV5_USB_OTG_IEP_2_10 = 5,
-	DB5500_DMA_DEV6_USB_OTG_IEP_3_11 = 6,
-	DB5500_DMA_DEV7_IRDA_RFS = 7,
-	DB5500_DMA_DEV8_IRDA_FIFO_RX = 8,
-	DB5500_DMA_DEV9_MSP0_RX = 9,
-	DB5500_DMA_DEV10_MSP1_RX = 10,
-	DB5500_DMA_DEV11_MSP2_RX = 11,
-	DB5500_DMA_DEV12_UART0_RX = 12,
-	DB5500_DMA_DEV13_UART1_RX = 13,
-	DB5500_DMA_DEV14_UART2_RX = 14,
-	DB5500_DMA_DEV15_UART3_RX = 15,
-	DB5500_DMA_DEV16_USB_OTG_IEP_8 = 16,
-	DB5500_DMA_DEV17_USB_OTG_IEP_1_9 = 17,
-	DB5500_DMA_DEV18_USB_OTG_IEP_2_10 = 18,
-	DB5500_DMA_DEV19_USB_OTG_IEP_3_11 = 19,
-	DB5500_DMA_DEV20_USB_OTG_IEP_4_12 = 20,
-	DB5500_DMA_DEV21_USB_OTG_IEP_5_13 = 21,
-	DB5500_DMA_DEV22_USB_OTG_IEP_6_14 = 22,
-	DB5500_DMA_DEV23_USB_OTG_IEP_7_15 = 23,
-	DB5500_DMA_DEV24_SDMMC0_RX = 24,
-	DB5500_DMA_DEV25_SDMMC1_RX = 25,
-	DB5500_DMA_DEV26_SDMMC2_RX = 26,
-	DB5500_DMA_DEV27_SDMMC3_RX = 27,
-	DB5500_DMA_DEV28_SDMMC4_RX = 28,
-	/* 29 - 32 not used */
-	DB5500_DMA_DEV33_SDMMC0_RX = 33,
-	DB5500_DMA_DEV34_SDMMC1_RX = 34,
-	DB5500_DMA_DEV35_SDMMC2_RX = 35,
-	DB5500_DMA_DEV36_SDMMC3_RX = 36,
-	DB5500_DMA_DEV37_SDMMC4_RX = 37,
-	DB5500_DMA_DEV38_USB_OTG_IEP_8 = 38,
-	DB5500_DMA_DEV39_USB_OTG_IEP_1_9 = 39,
-	DB5500_DMA_DEV40_USB_OTG_IEP_2_10 = 40,
-	DB5500_DMA_DEV41_USB_OTG_IEP_3_11 = 41,
-	DB5500_DMA_DEV42_USB_OTG_IEP_4_12 = 42,
-	DB5500_DMA_DEV43_USB_OTG_IEP_5_13 = 43,
-	DB5500_DMA_DEV44_USB_OTG_IEP_6_14 = 44,
-	DB5500_DMA_DEV45_USB_OTG_IEP_7_15 = 45,
-	/* 46 not used */
-	DB5500_DMA_DEV47_MCDE_RX = 47,
-	DB5500_DMA_DEV48_CRYPTO1_RX = 48,
-	/* 49, 50 not used */
-	DB5500_DMA_DEV49_I2C1_RX = 51,
-	DB5500_DMA_DEV50_I2C3_RX = 52,
-	DB5500_DMA_DEV51_I2C2_RX = 53,
-	/* 54 - 60 not used */
-	DB5500_DMA_DEV61_CRYPTO0_RX = 61,
-	/* 62, 63 not used */
-};
-
-enum dma_dest_dev_type {
-	DB5500_DMA_DEV0_SPI0_TX = 0,
-	DB5500_DMA_DEV1_SPI1_TX = 1,
-	DB5500_DMA_DEV2_SPI2_TX = 2,
-	DB5500_DMA_DEV3_SPI3_TX = 3,
-	DB5500_DMA_DEV4_USB_OTG_OEP_1_9 = 4,
-	DB5500_DMA_DEV5_USB_OTG_OEP_2_10 = 5,
-	DB5500_DMA_DEV6_USB_OTG_OEP_3_11 = 6,
-	DB5500_DMA_DEV7_IRRC_TX = 7,
-	DB5500_DMA_DEV8_IRDA_FIFO_TX = 8,
-	DB5500_DMA_DEV9_MSP0_TX = 9,
-	DB5500_DMA_DEV10_MSP1_TX = 10,
-	DB5500_DMA_DEV11_MSP2_TX = 11,
-	DB5500_DMA_DEV12_UART0_TX = 12,
-	DB5500_DMA_DEV13_UART1_TX = 13,
-	DB5500_DMA_DEV14_UART2_TX = 14,
-	DB5500_DMA_DEV15_UART3_TX = 15,
-	DB5500_DMA_DEV16_USB_OTG_OEP_8 = 16,
-	DB5500_DMA_DEV17_USB_OTG_OEP_1_9 = 17,
-	DB5500_DMA_DEV18_USB_OTG_OEP_2_10 = 18,
-	DB5500_DMA_DEV19_USB_OTG_OEP_3_11 = 19,
-	DB5500_DMA_DEV20_USB_OTG_OEP_4_12 = 20,
-	DB5500_DMA_DEV21_USB_OTG_OEP_5_13 = 21,
-	DB5500_DMA_DEV22_USB_OTG_OEP_6_14 = 22,
-	DB5500_DMA_DEV23_USB_OTG_OEP_7_15 = 23,
-	DB5500_DMA_DEV24_SDMMC0_TX = 24,
-	DB5500_DMA_DEV25_SDMMC1_TX = 25,
-	DB5500_DMA_DEV26_SDMMC2_TX = 26,
-	DB5500_DMA_DEV27_SDMMC3_TX = 27,
-	DB5500_DMA_DEV28_SDMMC4_TX = 28,
-	/* 29 - 31 not used */
-	DB5500_DMA_DEV32_FSMC_TX = 32,
-	DB5500_DMA_DEV33_SDMMC0_TX = 33,
-	DB5500_DMA_DEV34_SDMMC1_TX = 34,
-	DB5500_DMA_DEV35_SDMMC2_TX = 35,
-	DB5500_DMA_DEV36_SDMMC3_TX = 36,
-	DB5500_DMA_DEV37_SDMMC4_TX = 37,
-	DB5500_DMA_DEV38_USB_OTG_OEP_8 = 38,
-	DB5500_DMA_DEV39_USB_OTG_OEP_1_9 = 39,
-	DB5500_DMA_DEV40_USB_OTG_OEP_2_10 = 40,
-	DB5500_DMA_DEV41_USB_OTG_OEP_3_11 = 41,
-	DB5500_DMA_DEV42_USB_OTG_OEP_4_12 = 42,
-	DB5500_DMA_DEV43_USB_OTG_OEP_5_13 = 43,
-	DB5500_DMA_DEV44_USB_OTG_OEP_6_14 = 44,
-	DB5500_DMA_DEV45_USB_OTG_OEP_7_15 = 45,
-	/* 46 not used */
-	DB5500_DMA_DEV47_STM_TX = 47,
-	DB5500_DMA_DEV48_CRYPTO1_TX = 48,
-	DB5500_DMA_DEV49_CRYPTO1_TX_HASH1_TX = 49,
-	DB5500_DMA_DEV50_HASH1_TX = 50,
-	DB5500_DMA_DEV51_I2C1_TX = 51,
-	DB5500_DMA_DEV52_I2C3_TX = 52,
-	DB5500_DMA_DEV53_I2C2_TX = 53,
-	/* 54, 55 not used */
-	DB5500_DMA_MEMCPY_TX_1 = 56,
-	DB5500_DMA_MEMCPY_TX_2 = 57,
-	DB5500_DMA_MEMCPY_TX_3 = 58,
-	DB5500_DMA_MEMCPY_TX_4 = 59,
-	DB5500_DMA_MEMCPY_TX_5 = 60,
-	DB5500_DMA_DEV61_CRYPTO0_TX = 61,
-	DB5500_DMA_DEV62_CRYPTO0_TX_HASH0_TX = 62,
-	DB5500_DMA_DEV63_HASH0_TX = 63,
-};
-
-#endif
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
index d37df98..741e71f 100644
--- a/arch/arm/mach-ux500/timer.c
+++ b/arch/arm/mach-ux500/timer.c
@@ -8,6 +8,7 @@
 #include <linux/errno.h>
 #include <linux/clksrc-dbx500-prcmu.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 
 #include <asm/smp_twd.h>
 
@@ -18,8 +19,6 @@
 #include <mach/irqs.h>
 
 #ifdef CONFIG_HAVE_ARM_TWD
-static DEFINE_TWD_LOCAL_TIMER(u5500_twd_local_timer,
-			      U5500_TWD_BASE, IRQ_LOCALTIMER);
 static DEFINE_TWD_LOCAL_TIMER(u8500_twd_local_timer,
 			      U8500_TWD_BASE, IRQ_LOCALTIMER);
 
@@ -28,8 +27,8 @@
 	struct twd_local_timer *twd_local_timer;
 	int err;
 
-	twd_local_timer = cpu_is_u5500() ? &u5500_twd_local_timer :
-					   &u8500_twd_local_timer;
+	/* Use this to switch local timer base if changed in new ASICs */
+	twd_local_timer = &u8500_twd_local_timer;
 
 	if (of_have_populated_dt())
 		twd_local_timer_of_register();
@@ -43,21 +42,41 @@
 #define ux500_twd_init()	do { } while(0)
 #endif
 
+const static struct of_device_id prcmu_timer_of_match[] __initconst = {
+	{ .compatible = "stericsson,db8500-prcmu-timer-4", },
+	{ },
+};
+
 static void __init ux500_timer_init(void)
 {
 	void __iomem *mtu_timer_base;
 	void __iomem *prcmu_timer_base;
+	void __iomem *tmp_base;
+	struct device_node *np;
 
-	if (cpu_is_u5500()) {
-		mtu_timer_base = __io_address(U5500_MTU0_BASE);
-		prcmu_timer_base = __io_address(U5500_PRCMU_TIMER_3_BASE);
-	} else if (cpu_is_u8500()) {
+	if (cpu_is_u8500_family()) {
 		mtu_timer_base = __io_address(U8500_MTU0_BASE);
 		prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
 	} else {
 		ux500_unknown_soc();
 	}
 
+	/* TODO: Once MTU has been DT:ed place code above into else. */
+	if (of_have_populated_dt()) {
+		np = of_find_matching_node(NULL, prcmu_timer_of_match);
+		if (!np)
+			goto dt_fail;
+
+		tmp_base = of_iomap(np, 0);
+		if (!tmp_base)
+			goto dt_fail;
+
+		prcmu_timer_base = tmp_base;
+	}
+
+dt_fail:
+	/* Doing it the old fashioned way. */
+
 	/*
 	 * Here we register the timerblocks active in the system.
 	 * Localtimers (twd) is started when both cpu is up and running.
@@ -70,7 +89,7 @@
 	 * depending on delay which is not yet calibrated. RTC-RTT is in the
 	 * always-on powerdomain and is used as clockevent instead of twd when
 	 * sleeping.
-	 * The PRCMU timer 4(3 for DB5500) register a clocksource and
+	 * The PRCMU timer 4 register a clocksource and
 	 * sched_clock with higher rating then MTU since is always-on.
 	 *
 	 */
diff --git a/arch/arm/mm/cache-tauros2.c b/arch/arm/mm/cache-tauros2.c
index 1fbca05..23a7643 100644
--- a/arch/arm/mm/cache-tauros2.c
+++ b/arch/arm/mm/cache-tauros2.c
@@ -108,6 +108,26 @@
 
 	dsb();
 }
+
+static void tauros2_disable(void)
+{
+	__asm__ __volatile__ (
+	"mcr	p15, 1, %0, c7, c11, 0 @L2 Cache Clean All\n\t"
+	"mrc	p15, 0, %0, c1, c0, 0\n\t"
+	"bic	%0, %0, #(1 << 26)\n\t"
+	"mcr	p15, 0, %0, c1, c0, 0  @Disable L2 Cache\n\t"
+	: : "r" (0x0));
+}
+
+static void tauros2_resume(void)
+{
+	__asm__ __volatile__ (
+	"mcr	p15, 1, %0, c7, c7, 0 @L2 Cache Invalidate All\n\t"
+	"mrc	p15, 0, %0, c1, c0, 0\n\t"
+	"orr	%0, %0, #(1 << 26)\n\t"
+	"mcr	p15, 0, %0, c1, c0, 0 @Enable L2 Cache\n\t"
+	: : "r" (0x0));
+}
 #endif
 
 static inline u32 __init read_extra_features(void)
@@ -194,6 +214,8 @@
 		outer_cache.inv_range = tauros2_inv_range;
 		outer_cache.clean_range = tauros2_clean_range;
 		outer_cache.flush_range = tauros2_flush_range;
+		outer_cache.disable = tauros2_disable;
+		outer_cache.resume = tauros2_resume;
 	}
 #endif
 
@@ -219,6 +241,8 @@
 		outer_cache.inv_range = tauros2_inv_range;
 		outer_cache.clean_range = tauros2_clean_range;
 		outer_cache.flush_range = tauros2_flush_range;
+		outer_cache.disable = tauros2_disable;
+		outer_cache.resume = tauros2_resume;
 	}
 #endif
 
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index b047546..fbb2124 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -345,6 +345,41 @@
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
 	mov	pc, lr
 
+.globl	cpu_mohawk_suspend_size
+.equ	cpu_mohawk_suspend_size, 4 * 6
+#ifdef CONFIG_PM_SLEEP
+ENTRY(cpu_mohawk_do_suspend)
+	stmfd	sp!, {r4 - r9, lr}
+	mrc	p14, 0, r4, c6, c0, 0	@ clock configuration, for turbo mode
+	mrc	p15, 0, r5, c15, c1, 0	@ CP access reg
+	mrc	p15, 0, r6, c13, c0, 0	@ PID
+	mrc 	p15, 0, r7, c3, c0, 0	@ domain ID
+	mrc	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
+	mrc 	p15, 0, r9, c1, c0, 0	@ control reg
+	bic	r4, r4, #2		@ clear frequency change bit
+	stmia	r0, {r4 - r9}		@ store cp regs
+	ldmia	sp!, {r4 - r9, pc}
+ENDPROC(cpu_mohawk_do_suspend)
+
+ENTRY(cpu_mohawk_do_resume)
+	ldmia	r0, {r4 - r9}		@ load cp regs
+	mov	ip, #0
+	mcr	p15, 0, ip, c7, c7, 0	@ invalidate I & D caches, BTB
+	mcr	p15, 0, ip, c7, c10, 4	@ drain write (&fill) buffer
+	mcr	p15, 0, ip, c7, c5, 4	@ flush prefetch buffer
+	mcr	p15, 0, ip, c8, c7, 0	@ invalidate I & D TLBs
+	mcr	p14, 0, r4, c6, c0, 0	@ clock configuration, turbo mode.
+	mcr	p15, 0, r5, c15, c1, 0	@ CP access reg
+	mcr	p15, 0, r6, c13, c0, 0	@ PID
+	mcr	p15, 0, r7, c3, c0, 0	@ domain ID
+	orr	r1, r1, #0x18		@ cache the page table in L2
+	mcr	p15, 0, r1, c2, c0, 0	@ translation table base addr
+	mcr	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
+	mov	r0, r9			@ control register
+	b	cpu_resume_mmu
+ENDPROC(cpu_mohawk_do_resume)
+#endif
+
 	__CPUINIT
 
 	.type	__mohawk_setup, #function
diff --git a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c
index cb7658e..4e729f0 100644
--- a/arch/arm/nwfpe/fpmodule.c
+++ b/arch/arm/nwfpe/fpmodule.c
@@ -147,7 +147,7 @@
 #ifdef CONFIG_DEBUG_USER
 	if (flags & debug)
  		printk(KERN_DEBUG
-		       "NWFPE: %s[%d] takes exception %08x at %p from %08lx\n",
+		       "NWFPE: %s[%d] takes exception %08x at %pf from %08lx\n",
 		       current->comm, current->pid, flags,
 		       __builtin_return_address(0), GET_USERREG()->ARM_pc);
 #endif
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx51.h b/arch/arm/plat-mxc/include/mach/iomux-mx51.h
index c7f5169a..36c8989 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx51.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx51.h
@@ -256,13 +256,13 @@
 #define MX51_PAD_NANDF_RB1__GPIO3_9		IOMUX_PAD(0x4fc, 0x120, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB1__NANDF_RB1		IOMUX_PAD(0x4fc, 0x120, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB1__PATA_IORDY		IOMUX_PAD(0x4fc, 0x120, 1, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_NANDF_RB1__SD4_CMD		IOMUX_PAD(0x4fc, 0x120, 5, __NA_, 0, MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_NANDF_RB1__SD4_CMD		IOMUX_PAD(0x4fc, 0x120, 0x15, __NA_, 0, MX51_SDHCI_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__DISP2_WAIT		IOMUX_PAD(0x500, 0x124, 5, 0x9a8, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__ECSPI2_SCLK		IOMUX_PAD(0x500, 0x124, 2, __NA_, 0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__FEC_COL		IOMUX_PAD(0x500, 0x124, 1, 0x94c, 0, MX51_PAD_CTRL_2)
 #define MX51_PAD_NANDF_RB2__GPIO3_10		IOMUX_PAD(0x500, 0x124, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__NANDF_RB2		IOMUX_PAD(0x500, 0x124, 0, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_NANDF_RB2__USBH3_H3_DP		IOMUX_PAD(0x500, 0x124, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB2__USBH3_H3_DP		IOMUX_PAD(0x500, 0x124, 0x17, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__USBH3_NXT		IOMUX_PAD(0x500, 0x124, 6, 0xa20, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB3__DISP1_WAIT		IOMUX_PAD(0x504, 0x128, 5, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB3__ECSPI2_MISO		IOMUX_PAD(0x504, 0x128, 2, __NA_, 0, MX51_ECSPI_PAD_CTRL)
@@ -270,7 +270,7 @@
 #define MX51_PAD_NANDF_RB3__GPIO3_11		IOMUX_PAD(0x504, 0x128, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB3__NANDF_RB3		IOMUX_PAD(0x504, 0x128, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB3__USBH3_CLK		IOMUX_PAD(0x504, 0x128, 6, 0x9f8, 0, NO_PAD_CTRL)
-#define MX51_PAD_NANDF_RB3__USBH3_H3_DM		IOMUX_PAD(0x504, 0x128, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB3__USBH3_H3_DM		IOMUX_PAD(0x504, 0x128, 0x17, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO_NAND__GPIO_NAND		IOMUX_PAD(0x514, 0x12c, 0, 0x998, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO_NAND__PATA_INTRQ		IOMUX_PAD(0x514, 0x12c, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS0__GPIO3_16		IOMUX_PAD(0x518, 0x130, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
@@ -283,13 +283,13 @@
 #define MX51_PAD_NANDF_CS2__NANDF_CS2		IOMUX_PAD(0x520, 0x138, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS2__PATA_CS_0		IOMUX_PAD(0x520, 0x138, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS2__SD4_CLK		IOMUX_PAD(0x520, 0x138, 5, __NA_, 0, MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS)
-#define MX51_PAD_NANDF_CS2__USBH3_H1_DP		IOMUX_PAD(0x520, 0x138, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS2__USBH3_H1_DP		IOMUX_PAD(0x520, 0x138, 0x17, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS3__FEC_MDC		IOMUX_PAD(0x524, 0x13c, 2, __NA_, 0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS3__GPIO3_19		IOMUX_PAD(0x524, 0x13c, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS3__NANDF_CS3		IOMUX_PAD(0x524, 0x13c, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS3__PATA_CS_1		IOMUX_PAD(0x524, 0x13c, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS3__SD4_DAT0		IOMUX_PAD(0x524, 0x13c, 5, __NA_, 0, MX51_SDHCI_PAD_CTRL)
-#define MX51_PAD_NANDF_CS3__USBH3_H1_DM		IOMUX_PAD(0x524, 0x13c, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS3__USBH3_H1_DM		IOMUX_PAD(0x524, 0x13c, 0x17, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS4__FEC_TDATA1		IOMUX_PAD(0x528, 0x140, 2, __NA_, 0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS4__GPIO3_20		IOMUX_PAD(0x528, 0x140, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS4__NANDF_CS4		IOMUX_PAD(0x528, 0x140, 0, __NA_, 0, NO_PAD_CTRL)
@@ -316,7 +316,7 @@
 #define MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK	IOMUX_PAD(0x538, 0x150, 1, 0x974, 0, MX51_PAD_CTRL_4)
 #define MX51_PAD_NANDF_RDY_INT__GPIO3_24	IOMUX_PAD(0x538, 0x150, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_RDY_INT__NANDF_RDY_INT	IOMUX_PAD(0x538, 0x150, 0, 0x938, 0, NO_PAD_CTRL)
-#define MX51_PAD_NANDF_RDY_INT__SD3_CMD		IOMUX_PAD(0x538, 0x150, 5, __NA_, 0, MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_NANDF_RDY_INT__SD3_CMD		IOMUX_PAD(0x538, 0x150, 0x15, __NA_, 0, MX51_SDHCI_PAD_CTRL)
 #define MX51_PAD_NANDF_D15__ECSPI2_MOSI		IOMUX_PAD(0x53c, 0x154, 2, __NA_, 0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_NANDF_D15__GPIO3_25		IOMUX_PAD(0x53c, 0x154, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_D15__NANDF_D15		IOMUX_PAD(0x53c, 0x154, 0, __NA_, 0, NO_PAD_CTRL)
@@ -672,23 +672,23 @@
 #define MX51_PAD_DISP2_DAT5__DISP2_DAT5		IOMUX_PAD(0x770, 0x368, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT6__DISP2_DAT6		IOMUX_PAD(0x774, 0x36c, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT6__FEC_TDATA1		IOMUX_PAD(0x774, 0x36c, 2, __NA_, 0, MX51_PAD_CTRL_5)
-#define MX51_PAD_DISP2_DAT6__GPIO1_19		IOMUX_PAD(0x774, 0x36c, 5, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT6__GPIO1_19		IOMUX_PAD(0x774, 0x36c, 5, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT6__KEY_ROW4		IOMUX_PAD(0x774, 0x36c, 4, 0x9d0, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT6__USBH3_STP		IOMUX_PAD(0x774, 0x36c, 3, 0xa24, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT7__DISP2_DAT7		IOMUX_PAD(0x778, 0x370, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT7__FEC_TDATA2		IOMUX_PAD(0x778, 0x370, 2, __NA_, 0, MX51_PAD_CTRL_5)
-#define MX51_PAD_DISP2_DAT7__GPIO1_29		IOMUX_PAD(0x778, 0x370, 5, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT7__GPIO1_29		IOMUX_PAD(0x778, 0x370, 5, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT7__KEY_ROW5		IOMUX_PAD(0x778, 0x370, 4, 0x9d4, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT7__USBH3_NXT		IOMUX_PAD(0x778, 0x370, 3, 0xa20, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT8__DISP2_DAT8		IOMUX_PAD(0x77c, 0x374, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT8__FEC_TDATA3		IOMUX_PAD(0x77c, 0x374, 2, __NA_, 0, MX51_PAD_CTRL_5)
-#define MX51_PAD_DISP2_DAT8__GPIO1_30		IOMUX_PAD(0x77c, 0x374, 5, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT8__GPIO1_30		IOMUX_PAD(0x77c, 0x374, 5, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT8__KEY_ROW6		IOMUX_PAD(0x77c, 0x374, 4, 0x9d8, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT8__USBH3_DATA0	IOMUX_PAD(0x77c, 0x374, 3, 0x9fc, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT9__AUD6_RXC		IOMUX_PAD(0x780, 0x378, 4, 0x8f4, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT9__DISP2_DAT9		IOMUX_PAD(0x780, 0x378, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT9__FEC_TX_EN		IOMUX_PAD(0x780, 0x378, 2, __NA_, 0, MX51_PAD_CTRL_5)
-#define MX51_PAD_DISP2_DAT9__GPIO1_31		IOMUX_PAD(0x780, 0x378, 5, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT9__GPIO1_31		IOMUX_PAD(0x780, 0x378, 5, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT9__USBH3_DATA1	IOMUX_PAD(0x780, 0x378, 3, 0xa00, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT10__DISP2_DAT10	IOMUX_PAD(0x784, 0x37c, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT10__DISP2_SER_CS	IOMUX_PAD(0x784, 0x37c, 5, __NA_, 0, NO_PAD_CTRL)
@@ -698,7 +698,7 @@
 #define MX51_PAD_DISP2_DAT11__AUD6_TXD		IOMUX_PAD(0x788, 0x380, 4, 0x8f0, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT11__DISP2_DAT11	IOMUX_PAD(0x788, 0x380, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT11__FEC_RX_CLK	IOMUX_PAD(0x788, 0x380, 2, 0x968, 1, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT11__GPIO1_10		IOMUX_PAD(0x788, 0x380, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT11__GPIO1_10		IOMUX_PAD(0x788, 0x380, 7, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT11__USBH3_DATA3	IOMUX_PAD(0x788, 0x380, 3, 0xa08, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT12__AUD6_RXD		IOMUX_PAD(0x78c, 0x384, 4, 0x8ec, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT12__DISP2_DAT12	IOMUX_PAD(0x78c, 0x384, 0, __NA_, 0, NO_PAD_CTRL)
@@ -746,16 +746,16 @@
 #define MX51_PAD_SD1_DATA3__CSPI_SS1		IOMUX_PAD(0x7b0, 0x3a8, 2, 0x920, 1, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_SD1_DATA3__SD1_DATA3		IOMUX_PAD(0x7b0, 0x3a8, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
 #define MX51_PAD_GPIO1_0__CSPI_SS2		IOMUX_PAD(0x7b4, 0x3ac, 2, 0x924, 0, MX51_ECSPI_PAD_CTRL)
-#define MX51_PAD_GPIO1_0__GPIO1_0		IOMUX_PAD(0x7b4, 0x3ac, 1, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_0__GPIO1_0		IOMUX_PAD(0x7b4, 0x3ac, 1, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_0__SD1_CD		IOMUX_PAD(0x7b4, 0x3ac, 0, __NA_, 0, MX51_ESDHC_PAD_CTRL)
 #define MX51_PAD_GPIO1_1__CSPI_MISO		IOMUX_PAD(0x7b8, 0x3b0, 2, 0x918, 2, MX51_ECSPI_PAD_CTRL)
-#define MX51_PAD_GPIO1_1__GPIO1_1		IOMUX_PAD(0x7b8, 0x3b0, 1, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_1__GPIO1_1		IOMUX_PAD(0x7b8, 0x3b0, 1, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_1__SD1_WP		IOMUX_PAD(0x7b8, 0x3b0, 0, __NA_, 0, MX51_ESDHC_PAD_CTRL)
 #define MX51_PAD_EIM_DA12__EIM_DA12		IOMUX_PAD(__NA_, 0x04c, 0, 0x000, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_DA13__EIM_DA13		IOMUX_PAD(__NA_, 0x050, 0, 0x000, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_DA14__EIM_DA14		IOMUX_PAD(__NA_, 0x054, 0, 0x000, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_DA15__EIM_DA15		IOMUX_PAD(__NA_, 0x058, 0, 0x000, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_CMD__CSPI_MOSI		IOMUX_PAD(__NA_, 0x3b4, 2, 0x91c, 3, MX51_ECSPI_PAD_CTRL)
+#define MX51_PAD_SD2_CMD__CSPI_MOSI		IOMUX_PAD(0x7bc, 0x3b4, 2, 0x91c, 3, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_SD2_CMD__I2C1_SCL		IOMUX_PAD(0x7bc, 0x3b4, 0x11, 0x9b0, 2, MX51_I2C_PAD_CTRL)
 #define MX51_PAD_SD2_CMD__SD2_CMD		IOMUX_PAD(0x7bc, 0x3b4, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
 #define MX51_PAD_SD2_CLK__CSPI_SCLK		IOMUX_PAD(0x7c0, 0x3b8, 2, 0x914, 3, MX51_ECSPI_PAD_CTRL)
@@ -766,19 +766,19 @@
 #define MX51_PAD_SD2_DATA0__SD2_DATA0		IOMUX_PAD(0x7c4, 0x3bc, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
 #define MX51_PAD_SD2_DATA1__SD1_DAT5		IOMUX_PAD(0x7c8, 0x3c0, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_SD2_DATA1__SD2_DATA1		IOMUX_PAD(0x7c8, 0x3c0, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
-#define MX51_PAD_SD2_DATA1__USBH3_H2_DP		IOMUX_PAD(0x7c8, 0x3c0, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_DATA1__USBH3_H2_DP		IOMUX_PAD(0x7c8, 0x3c0, 0x12, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_SD2_DATA2__SD1_DAT6		IOMUX_PAD(0x7cc, 0x3c4, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_SD2_DATA2__SD2_DATA2		IOMUX_PAD(0x7cc, 0x3c4, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
-#define MX51_PAD_SD2_DATA2__USBH3_H2_DM		IOMUX_PAD(0x7cc, 0x3c4, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_DATA2__USBH3_H2_DM		IOMUX_PAD(0x7cc, 0x3c4, 0x12, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_SD2_DATA3__CSPI_SS2		IOMUX_PAD(0x7d0, 0x3c8, 2, 0x924, 1, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_SD2_DATA3__SD1_DAT7		IOMUX_PAD(0x7d0, 0x3c8, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_SD2_DATA3__SD2_DATA3		IOMUX_PAD(0x7d0, 0x3c8, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
 #define MX51_PAD_GPIO1_2__CCM_OUT_2		IOMUX_PAD(0x7d4, 0x3cc, 5, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_2__GPIO1_2		IOMUX_PAD(0x7d4, 0x3cc, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_2__GPIO1_2		IOMUX_PAD(0x7d4, 0x3cc, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_2__I2C2_SCL		IOMUX_PAD(0x7d4, 0x3cc, 0x12, 0x9b8, 3, MX51_I2C_PAD_CTRL)
 #define MX51_PAD_GPIO1_2__PLL1_BYP		IOMUX_PAD(0x7d4, 0x3cc, 7, 0x90c, 1, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_2__PWM1_PWMO		IOMUX_PAD(0x7d4, 0x3cc, 1, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_3__GPIO1_3		IOMUX_PAD(0x7d8, 0x3d0, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_3__GPIO1_3		IOMUX_PAD(0x7d8, 0x3d0, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_3__I2C2_SDA		IOMUX_PAD(0x7d8, 0x3d0, 0x12, 0x9bc, 3, MX51_I2C_PAD_CTRL)
 #define MX51_PAD_GPIO1_3__PLL2_BYP		IOMUX_PAD(0x7d8, 0x3d0, 7, 0x910, 1, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_3__PWM2_PWMO		IOMUX_PAD(0x7d8, 0x3d0, 1, __NA_, 0, NO_PAD_CTRL)
@@ -786,27 +786,27 @@
 #define MX51_PAD_PMIC_INT_REQ__PMIC_PMU_IRQ_B	IOMUX_PAD(0x7fc, 0x3d4, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_4__DISP2_EXT_CLK		IOMUX_PAD(0x804, 0x3d8, 4, 0x908, 1, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_4__EIM_RDY		IOMUX_PAD(0x804, 0x3d8, 3, 0x938, 1, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_4__GPIO1_4		IOMUX_PAD(0x804, 0x3d8, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_4__GPIO1_4		IOMUX_PAD(0x804, 0x3d8, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_4__WDOG1_WDOG_B		IOMUX_PAD(0x804, 0x3d8, 2, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_5__CSI2_MCLK		IOMUX_PAD(0x808, 0x3dc, 6, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_5__DISP2_PIN16		IOMUX_PAD(0x808, 0x3dc, 3, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_5__GPIO1_5		IOMUX_PAD(0x808, 0x3dc, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_5__GPIO1_5		IOMUX_PAD(0x808, 0x3dc, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_5__WDOG2_WDOG_B		IOMUX_PAD(0x808, 0x3dc, 2, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_6__DISP2_PIN17		IOMUX_PAD(0x80c, 0x3e0, 4, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_6__GPIO1_6		IOMUX_PAD(0x80c, 0x3e0, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_6__GPIO1_6		IOMUX_PAD(0x80c, 0x3e0, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_6__REF_EN_B		IOMUX_PAD(0x80c, 0x3e0, 3, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_7__CCM_OUT_0		IOMUX_PAD(0x810, 0x3e4, 3, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_7__GPIO1_7		IOMUX_PAD(0x810, 0x3e4, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_7__GPIO1_7		IOMUX_PAD(0x810, 0x3e4, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_7__SD2_WP		IOMUX_PAD(0x810, 0x3e4, 6, __NA_, 0, MX51_ESDHC_PAD_CTRL)
 #define MX51_PAD_GPIO1_7__SPDIF_OUT1		IOMUX_PAD(0x810, 0x3e4, 2, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_8__CSI2_DATA_EN		IOMUX_PAD(0x814, 0x3e8, 2, 0x99c, 2, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_8__GPIO1_8		IOMUX_PAD(0x814, 0x3e8, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_8__GPIO1_8		IOMUX_PAD(0x814, 0x3e8, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_8__SD2_CD		IOMUX_PAD(0x814, 0x3e8, 6, __NA_, 0, MX51_ESDHC_PAD_CTRL)
 #define MX51_PAD_GPIO1_8__USBH3_PWR		IOMUX_PAD(0x814, 0x3e8, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__CCM_OUT_1		IOMUX_PAD(0x818, 0x3ec, 3, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__DISP2_D1_CS		IOMUX_PAD(0x818, 0x3ec, 2, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__DISP2_SER_CS		IOMUX_PAD(0x818, 0x3ec, 7, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_9__GPIO1_9		IOMUX_PAD(0x818, 0x3ec, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_9__GPIO1_9		IOMUX_PAD(0x818, 0x3ec, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__SD2_LCTL		IOMUX_PAD(0x818, 0x3ec, 6, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__USBH3_OC		IOMUX_PAD(0x818, 0x3ec, 1, __NA_, 0, NO_PAD_CTRL)
 
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx53.h b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
index 527f8fe..9761e00 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx53.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
@@ -573,7 +573,7 @@
 #define MX53_PAD_EIM_D28__UART2_CTS			IOMUX_PAD(0x494, 0x14C, 2, __NA_, 0, MX53_UART_PAD_CTRL)
 #define MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO		IOMUX_PAD(0x494, 0x14C, 3, 0x82C, 1, NO_PAD_CTRL)
 #define MX53_PAD_EIM_D28__CSPI_MOSI			IOMUX_PAD(0x494, 0x14C, 4, 0x788, 1, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D28__I2C1_SDA			IOMUX_PAD(0x494, 0x14C, 5 | IOMUX_CONFIG_SION, 0x818, 1, PAD_CTRL_I2C)
+#define MX53_PAD_EIM_D28__I2C1_SDA			IOMUX_PAD(0x494, 0x14C, 5 | IOMUX_CONFIG_SION, 0x818, 1, NO_PAD_CTRL)
 #define MX53_PAD_EIM_D28__IPU_EXT_TRIG			IOMUX_PAD(0x494, 0x14C, 6, __NA_, 0, NO_PAD_CTRL)
 #define MX53_PAD_EIM_D28__IPU_DI0_PIN13			IOMUX_PAD(0x494, 0x14C, 7, __NA_, 0, NO_PAD_CTRL)
 #define MX53_PAD_EIM_D29__EMI_WEIM_D_29			IOMUX_PAD(0x498, 0x150, 0, __NA_, 0, NO_PAD_CTRL)
@@ -1187,7 +1187,7 @@
 #define MX53_PAD_GPIO_8__ESAI1_TX5_RX0			IOMUX_PAD(0x6C8, 0x338, 0, 0x7F8, 1, NO_PAD_CTRL)
 #define MX53_PAD_GPIO_8__GPIO1_8			IOMUX_PAD(0x6C8, 0x338, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX53_PAD_GPIO_8__EPIT2_EPITO			IOMUX_PAD(0x6C8, 0x338, 2, __NA_, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_8__CAN1_RXCAN			IOMUX_PAD(0x6C8, 0x338, 3, 0x760, 3, NO_PAD_CTRL)
+#define MX53_PAD_GPIO_8__CAN1_RXCAN			IOMUX_PAD(0x6C8, 0x338, 3, 0x760, 2, NO_PAD_CTRL)
 #define MX53_PAD_GPIO_8__UART2_RXD_MUX			IOMUX_PAD(0x6C8, 0x338, 4, 0x880, 5, MX53_UART_PAD_CTRL)
 #define MX53_PAD_GPIO_8__FIRI_TXD			IOMUX_PAD(0x6C8, 0x338, 5, __NA_, 0, NO_PAD_CTRL)
 #define MX53_PAD_GPIO_8__SPDIF_SRCLK			IOMUX_PAD(0x6C8, 0x338, 6, __NA_, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/mx2_cam.h b/arch/arm/plat-mxc/include/mach/mx2_cam.h
index 3c080a3..7ded6f1 100644
--- a/arch/arm/plat-mxc/include/mach/mx2_cam.h
+++ b/arch/arm/plat-mxc/include/mach/mx2_cam.h
@@ -23,7 +23,6 @@
 #ifndef __MACH_MX2_CAM_H_
 #define __MACH_MX2_CAM_H_
 
-#define MX2_CAMERA_SWAP16		(1 << 0)
 #define MX2_CAMERA_EXT_VSYNC		(1 << 1)
 #define MX2_CAMERA_CCIR			(1 << 2)
 #define MX2_CAMERA_CCIR_INTERLACE	(1 << 3)
@@ -31,7 +30,6 @@
 #define MX2_CAMERA_GATED_CLOCK		(1 << 5)
 #define MX2_CAMERA_INV_DATA		(1 << 6)
 #define MX2_CAMERA_PCLK_SAMPLE_RISING	(1 << 7)
-#define MX2_CAMERA_PACK_DIR_MSB		(1 << 8)
 
 /**
  * struct mx2_camera_platform_data - optional platform data for mx2_camera
diff --git a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h b/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h
index 9605bf2..826de74 100644
--- a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h
+++ b/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h
@@ -29,6 +29,7 @@
 #define NMK_GPIO_SLPC	0x1c
 #define NMK_GPIO_AFSLA	0x20
 #define NMK_GPIO_AFSLB	0x24
+#define NMK_GPIO_LOWEMI	0x28
 
 #define NMK_GPIO_RIMSC	0x40
 #define NMK_GPIO_FIMSC	0x44
@@ -61,7 +62,14 @@
 
 extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
 extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
+#ifdef CONFIG_PINCTRL_NOMADIK
 extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
+#else
+static inline int nmk_gpio_set_mode(int gpio, int gpio_mode)
+{
+	return -ENODEV;
+}
+#endif
 extern int nmk_gpio_get_mode(int gpio);
 
 extern void nmk_gpio_wakeups_suspend(void);
diff --git a/arch/arm/plat-nomadik/include/plat/pincfg.h b/arch/arm/plat-nomadik/include/plat/pincfg.h
index 22cb97d..9c949c7 100644
--- a/arch/arm/plat-nomadik/include/plat/pincfg.h
+++ b/arch/arm/plat-nomadik/include/plat/pincfg.h
@@ -24,6 +24,7 @@
  *	bit 16..18 - SLPM pull up/down state
  *	bit 19..20 - SLPM direction
  *	bit 21..22 - SLPM Value (if output)
+ *	bit 23..25 - PDIS value (if input)
  *
  * to facilitate the definition, the following macros are provided
  *
@@ -67,6 +68,10 @@
 /* These two replace the above in DB8500v2+ */
 #define PIN_SLPM_WAKEUP_ENABLE	(NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT)
 #define PIN_SLPM_WAKEUP_DISABLE	(NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT)
+#define PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP PIN_SLPM_WAKEUP_DISABLE
+
+#define PIN_SLPM_GPIO  PIN_SLPM_WAKEUP_ENABLE /* In SLPM, pin is a gpio */
+#define PIN_SLPM_ALTFUNC PIN_SLPM_WAKEUP_DISABLE /* In SLPM, pin is altfunc */
 
 #define PIN_DIR_SHIFT		14
 #define PIN_DIR_MASK		(0x1 << PIN_DIR_SHIFT)
@@ -105,6 +110,33 @@
 #define PIN_SLPM_VAL_LOW	((1 + 0) << PIN_SLPM_VAL_SHIFT)
 #define PIN_SLPM_VAL_HIGH	((1 + 1) << PIN_SLPM_VAL_SHIFT)
 
+#define PIN_SLPM_PDIS_SHIFT		23
+#define PIN_SLPM_PDIS_MASK		(0x3 << PIN_SLPM_PDIS_SHIFT)
+#define PIN_SLPM_PDIS(x)	\
+	(((x) & PIN_SLPM_PDIS_MASK) >> PIN_SLPM_PDIS_SHIFT)
+#define PIN_SLPM_PDIS_NO_CHANGE		(0 << PIN_SLPM_PDIS_SHIFT)
+#define PIN_SLPM_PDIS_DISABLED		(1 << PIN_SLPM_PDIS_SHIFT)
+#define PIN_SLPM_PDIS_ENABLED		(2 << PIN_SLPM_PDIS_SHIFT)
+
+#define PIN_LOWEMI_SHIFT	25
+#define PIN_LOWEMI_MASK		(0x1 << PIN_LOWEMI_SHIFT)
+#define PIN_LOWEMI(x)		(((x) & PIN_LOWEMI_MASK) >> PIN_LOWEMI_SHIFT)
+#define PIN_LOWEMI_DISABLED	(0 << PIN_LOWEMI_SHIFT)
+#define PIN_LOWEMI_ENABLED	(1 << PIN_LOWEMI_SHIFT)
+
+#define PIN_GPIOMODE_SHIFT	26
+#define PIN_GPIOMODE_MASK	(0x1 << PIN_GPIOMODE_SHIFT)
+#define PIN_GPIOMODE(x)		(((x) & PIN_GPIOMODE_MASK) >> PIN_GPIOMODE_SHIFT)
+#define PIN_GPIOMODE_DISABLED	(0 << PIN_GPIOMODE_SHIFT)
+#define PIN_GPIOMODE_ENABLED	(1 << PIN_GPIOMODE_SHIFT)
+
+#define PIN_SLEEPMODE_SHIFT	27
+#define PIN_SLEEPMODE_MASK	(0x1 << PIN_SLEEPMODE_SHIFT)
+#define PIN_SLEEPMODE(x)	(((x) & PIN_SLEEPMODE_MASK) >> PIN_SLEEPMODE_SHIFT)
+#define PIN_SLEEPMODE_DISABLED	(0 << PIN_SLEEPMODE_SHIFT)
+#define PIN_SLEEPMODE_ENABLED	(1 << PIN_SLEEPMODE_SHIFT)
+
+
 /* Shortcuts.  Use these instead of separate DIR, PULL, and VAL.  */
 #define PIN_INPUT_PULLDOWN	(PIN_DIR_INPUT | PIN_PULL_DOWN)
 #define PIN_INPUT_PULLUP	(PIN_DIR_INPUT | PIN_PULL_UP)
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index c0fe275..ed8605f 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -9,9 +9,6 @@
 obj-n :=
 obj-  :=
 
-# OCPI interconnect support for 1710, 1610 and 5912
-obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
-
 # omap_device support (OMAP2+ only at the moment)
 obj-$(CONFIG_ARCH_OMAP2) += omap_device.o
 obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index f1e46ea..0a9b9a9 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -20,6 +20,7 @@
 #include <plat/board.h>
 #include <plat/vram.h>
 #include <plat/dsp.h>
+#include <plat/dma.h>
 
 #include <plat/omap-secure.h>
 
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index 60278f4..09b07d2 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -167,8 +167,8 @@
 
 	paddr = arm_memblock_steal(size, SZ_1M);
 	if (!paddr) {
-		pr_err("%s: failed to reserve %x bytes\n",
-				__func__, size);
+		pr_err("%s: failed to reserve %llx bytes\n",
+				__func__, (unsigned long long)size);
 		return;
 	}
 
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index c58d896..987e610 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -41,6 +41,15 @@
 
 #include <plat/tc.h>
 
+/*
+ * MAX_LOGICAL_DMA_CH_COUNT: the maximum number of logical DMA
+ * channels that an instance of the SDMA IP block can support.  Used
+ * to size arrays.  (The actual maximum on a particular SoC may be less
+ * than this -- for example, OMAP1 SDMA instances only support 17 logical
+ * DMA channels.)
+ */
+#define MAX_LOGICAL_DMA_CH_COUNT		32
+
 #undef DEBUG
 
 #ifndef CONFIG_ARCH_OMAP1
@@ -883,7 +892,7 @@
 
 	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
 		int next_lch, cur_lch;
-		char dma_chan_link_map[dma_lch_count];
+		char dma_chan_link_map[MAX_LOGICAL_DMA_CH_COUNT];
 
 		dma_chan_link_map[lch] = 1;
 		/* Set the link register of the first channel */
@@ -981,7 +990,7 @@
 
 	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
 		int next_lch, cur_lch = lch;
-		char dma_chan_link_map[dma_lch_count];
+		char dma_chan_link_map[MAX_LOGICAL_DMA_CH_COUNT];
 
 		memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
 		do {
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 652139c..c4ed35e 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -349,11 +349,12 @@
 int omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
 	unsigned long rate = 0;
-	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+	struct dmtimer_platform_data *pdata;
 
 	if (unlikely(!timer))
 		return -EINVAL;
 
+	pdata = timer->pdev->dev.platform_data;
 	if (!pdata->needs_manual_reset)
 		rate = clk_get_rate(timer->fclk);
 
diff --git a/arch/arm/plat-omap/include/plat/board.h b/arch/arm/plat-omap/include/plat/board.h
index d5eb4c8..4814c5b 100644
--- a/arch/arm/plat-omap/include/plat/board.h
+++ b/arch/arm/plat-omap/include/plat/board.h
@@ -91,6 +91,8 @@
 	u32 (*usb0_init)(unsigned nwires, unsigned is_device);
 	u32 (*usb1_init)(unsigned nwires);
 	u32 (*usb2_init)(unsigned nwires, unsigned alt_pingroup);
+
+	int (*ocpi_enable)(void);
 };
 
 struct omap_lcd_config {
diff --git a/arch/arm/plat-omap/include/plat/clkdev_omap.h b/arch/arm/plat-omap/include/plat/clkdev_omap.h
index b299b8d..d0ed8c4 100644
--- a/arch/arm/plat-omap/include/plat/clkdev_omap.h
+++ b/arch/arm/plat-omap/include/plat/clkdev_omap.h
@@ -34,8 +34,7 @@
 #define CK_243X		(1 << 5)	/* 243x, 253x */
 #define CK_3430ES1	(1 << 6)	/* 34xxES1 only */
 #define CK_3430ES2PLUS	(1 << 7)	/* 34xxES2, ES3, non-Sitara 35xx only */
-#define CK_3505		(1 << 8)
-#define CK_3517		(1 << 9)
+#define CK_AM35XX	(1 << 9)	/* Sitara AM35xx */
 #define CK_36XX		(1 << 10)	/* 36xx/37xx-specific clocks */
 #define CK_443X		(1 << 11)
 #define CK_TI816X	(1 << 12)
@@ -44,7 +43,6 @@
 
 
 #define CK_34XX		(CK_3430ES1 | CK_3430ES2PLUS)
-#define CK_AM35XX	(CK_3505 | CK_3517)	/* all Sitara AM35xx */
 #define CK_3XXX		(CK_34XX | CK_AM35XX | CK_36XX)
 
 
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h
index b4d7ec3..a557b84 100644
--- a/arch/arm/plat-omap/include/plat/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -32,6 +32,8 @@
 
 extern int __init omap_init_clocksource_32k(void);
 
+extern void __init omap_check_revision(void);
+
 extern void omap_reserve(void);
 extern int omap_dss_reset(struct omap_hwmod *);
 
diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
index dc6a86b..4bdf14e 100644
--- a/arch/arm/plat-omap/include/plat/cpu.h
+++ b/arch/arm/plat-omap/include/plat/cpu.h
@@ -445,6 +445,7 @@
 
 #define OMAP446X_CLASS		0x44600044
 #define OMAP4460_REV_ES1_0	(OMAP446X_CLASS | (0x10 << 8))
+#define OMAP4460_REV_ES1_1	(OMAP446X_CLASS | (0x11 << 8))
 
 #define OMAP447X_CLASS		0x44700044
 #define OMAP4470_REV_ES1_0	(OMAP447X_CLASS | (0x10 << 8))
diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
index dc562a5..42afb4c 100644
--- a/arch/arm/plat-omap/include/plat/dma.h
+++ b/arch/arm/plat-omap/include/plat/dma.h
@@ -442,6 +442,7 @@
 	u32 (*dma_read)(int reg, int lch);
 };
 
+extern void __init omap_init_consistent_dma_size(void);
 extern void omap_set_dma_priority(int lch, int dst_port, int priority);
 extern int omap_request_dma(int dev_id, const char *dev_name,
 			void (*callback)(int lch, u16 ch_status, void *data),
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 9418f00..bdf871a 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -259,7 +259,7 @@
 	unsigned long phys_base;
 	int id;
 	int irq;
-	struct clk *iclk, *fclk;
+	struct clk *fclk;
 
 	void __iomem	*io_base;
 	void __iomem	*sys_stat;	/* TISTAT timer status */
@@ -316,12 +316,12 @@
 				OMAP_TIMER_V1_SYS_STAT_OFFSET;
 		timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
 		timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
-		timer->irq_dis = 0;
+		timer->irq_dis = NULL;
 		timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
 		timer->func_base = timer->io_base;
 	} else {
 		timer->revision = 2;
-		timer->sys_stat = 0;
+		timer->sys_stat = NULL;
 		timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
 		timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
 		timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
diff --git a/arch/arm/plat-omap/include/plat/hdq1w.h b/arch/arm/plat-omap/include/plat/hdq1w.h
new file mode 100644
index 0000000..0c1efc8
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/hdq1w.h
@@ -0,0 +1,36 @@
+/*
+ * Shared macros and function prototypes for the HDQ1W/1-wire IP block
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Paul Walmsley
+ *
+ * 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 ARCH_ARM_MACH_OMAP2_HDQ1W_H
+#define ARCH_ARM_MACH_OMAP2_HDQ1W_H
+
+#include <plat/omap_hwmod.h>
+
+/*
+ * XXX A future cleanup patch should modify
+ * drivers/w1/masters/omap_hdq.c to use these macros
+ */
+#define HDQ_CTRL_STATUS_OFFSET			0x0c
+#define HDQ_CTRL_STATUS_CLOCKENABLE_SHIFT	5
+
+
+extern int omap_hdq1w_reset(struct omap_hwmod *oh);
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index 7a38750..3e7ae0f 100644
--- a/arch/arm/plat-omap/include/plat/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -16,6 +16,7 @@
 #include <linux/mmc/host.h>
 
 #include <plat/board.h>
+#include <plat/omap_hwmod.h>
 
 #define OMAP15XX_NR_MMC		1
 #define OMAP16XX_NR_MMC		2
@@ -195,4 +196,7 @@
 }
 
 #endif
+
+extern int omap_msdi_reset(struct omap_hwmod *oh);
+
 #endif
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 9ff4444..1a52725 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -65,7 +65,6 @@
 	bool			dma_enabled;	/* To specify DMA Mode */
 	unsigned int		uartclk;	/* UART clock rate */
 	upf_t			flags;		/* UPF_* flags */
-	u32			errata;
 	unsigned int		dma_rx_buf_size;
 	unsigned int		dma_rx_timeout;
 	unsigned int		autosuspend_timeout;
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 3f26db4..c835b71 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -213,11 +213,17 @@
  */
 #define OCP_USER_MPU			(1 << 0)
 #define OCP_USER_SDMA			(1 << 1)
+#define OCP_USER_DSP			(1 << 2)
+#define OCP_USER_IVA			(1 << 3)
 
 /* omap_hwmod_ocp_if.flags bits */
 #define OCPIF_SWSUP_IDLE		(1 << 0)
 #define OCPIF_CAN_BURST			(1 << 1)
 
+/* omap_hwmod_ocp_if._int_flags possibilities */
+#define _OCPIF_INT_FLAGS_REGISTERED	(1 << 0)
+
+
 /**
  * struct omap_hwmod_ocp_if - OCP interface data
  * @master: struct omap_hwmod that initiates OCP transactions on this link
@@ -229,6 +235,7 @@
  * @width: OCP data width
  * @user: initiators using this interface (see OCP_USER_* macros above)
  * @flags: OCP interface flags (see OCPIF_* macros above)
+ * @_int_flags: internal flags (see _OCPIF_INT_FLAGS* macros above)
  *
  * It may also be useful to add a tag_cnt field for OCP2.x devices.
  *
@@ -247,6 +254,7 @@
 	u8				width;
 	u8				user;
 	u8				flags;
+	u8				_int_flags;
 };
 
 
@@ -327,9 +335,9 @@
  * then this field has to be populated with the correct offset structure.
  */
 struct omap_hwmod_class_sysconfig {
-	u16 rev_offs;
-	u16 sysc_offs;
-	u16 syss_offs;
+	u32 rev_offs;
+	u32 sysc_offs;
+	u32 syss_offs;
 	u16 sysc_flags;
 	struct omap_hwmod_sysc_fields *sysc_fields;
 	u8 srst_udelay;
@@ -476,6 +484,16 @@
 };
 
 /**
+ * struct omap_hwmod_link - internal structure linking hwmods with ocp_ifs
+ * @ocp_if: OCP interface structure record pointer
+ * @node: list_head pointing to next struct omap_hwmod_link in a list
+ */
+struct omap_hwmod_link {
+	struct omap_hwmod_ocp_if	*ocp_if;
+	struct list_head		node;
+};
+
+/**
  * struct omap_hwmod - integration data for OMAP hardware "modules" (IP blocks)
  * @name: name of the hwmod
  * @class: struct omap_hwmod_class * to the class of this hwmod
@@ -487,12 +505,10 @@
  * @_clk: pointer to the main struct clk (filled in at runtime)
  * @opt_clks: other device clocks that drivers can request (0..*)
  * @voltdm: pointer to voltage domain (filled in at runtime)
- * @masters: ptr to array of OCP ifs that this hwmod can initiate on
- * @slaves: ptr to array of OCP ifs that this hwmod can respond on
  * @dev_attr: arbitrary device attributes that can be passed to the driver
  * @_sysc_cache: internal-use hwmod flags
  * @_mpu_rt_va: cached register target start address (internal use)
- * @_mpu_port_index: cached MPU register target slave ID (internal use)
+ * @_mpu_port: cached MPU register target slave (internal use)
  * @opt_clks_cnt: number of @opt_clks
  * @master_cnt: number of @master entries
  * @slaves_cnt: number of @slave entries
@@ -511,6 +527,8 @@
  *
  * Parameter names beginning with an underscore are managed internally by
  * the omap_hwmod code and should not be set during initialization.
+ *
+ * @masters and @slaves are now deprecated.
  */
 struct omap_hwmod {
 	const char			*name;
@@ -529,15 +547,15 @@
 	struct omap_hwmod_opt_clk	*opt_clks;
 	char				*clkdm_name;
 	struct clockdomain		*clkdm;
-	struct omap_hwmod_ocp_if	**masters; /* connect to *_IA */
-	struct omap_hwmod_ocp_if	**slaves;  /* connect to *_TA */
+	struct list_head		master_ports; /* connect to *_IA */
+	struct list_head		slave_ports; /* connect to *_TA */
 	void				*dev_attr;
 	u32				_sysc_cache;
 	void __iomem			*_mpu_rt_va;
 	spinlock_t			_lock;
 	struct list_head		node;
+	struct omap_hwmod_ocp_if	*_mpu_port;
 	u16				flags;
-	u8				_mpu_port_index;
 	u8				response_lat;
 	u8				rst_lines_cnt;
 	u8				opt_clks_cnt;
@@ -549,7 +567,6 @@
 	u8				_postsetup_state;
 };
 
-int omap_hwmod_register(struct omap_hwmod **ohs);
 struct omap_hwmod *omap_hwmod_lookup(const char *name);
 int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
 			void *data);
@@ -581,6 +598,8 @@
 
 int omap_hwmod_count_resources(struct omap_hwmod *oh);
 int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res);
+int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type,
+				   const char *name, struct resource *res);
 
 struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh);
 void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh);
@@ -619,4 +638,6 @@
 extern int omap3xxx_hwmod_init(void);
 extern int omap44xx_hwmod_init(void);
 
+extern int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois);
+
 #endif
diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c
deleted file mode 100644
index ebe0c73..0000000
--- a/arch/arm/plat-omap/ocpi.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * linux/arch/arm/plat-omap/ocpi.c
- *
- * Minimal OCP bus support for omap16xx
- *
- * Copyright (C) 2003 - 2005 Nokia Corporation
- * Written by Tony Lindgren <tony@atomide.com>
- *
- * Modified for clock framework by Paul Mundt <paul.mundt@nokia.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
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-
-#define OCPI_BASE		0xfffec320
-#define OCPI_FAULT		(OCPI_BASE + 0x00)
-#define OCPI_CMD_FAULT		(OCPI_BASE + 0x04)
-#define OCPI_SINT0		(OCPI_BASE + 0x08)
-#define OCPI_TABORT		(OCPI_BASE + 0x0c)
-#define OCPI_SINT1		(OCPI_BASE + 0x10)
-#define OCPI_PROT		(OCPI_BASE + 0x14)
-#define OCPI_SEC		(OCPI_BASE + 0x18)
-
-/* USB OHCI OCPI access error registers */
-#define HOSTUEADDR	0xfffba0e0
-#define HOSTUESTATUS	0xfffba0e4
-
-static struct clk *ocpi_ck;
-
-/*
- * Enables device access to OMAP buses via the OCPI bridge
- * FIXME: Add locking
- */
-int ocpi_enable(void)
-{
-	unsigned int val;
-
-	if (!cpu_is_omap16xx())
-		return -ENODEV;
-
-	/* Enable access for OHCI in OCPI */
-	val = omap_readl(OCPI_PROT);
-	val &= ~0xff;
-	//val &= (1 << 0);	/* Allow access only to EMIFS */
-	omap_writel(val, OCPI_PROT);
-
-	val = omap_readl(OCPI_SEC);
-	val &= ~0xff;
-	omap_writel(val, OCPI_SEC);
-
-	return 0;
-}
-EXPORT_SYMBOL(ocpi_enable);
-
-static int __init omap_ocpi_init(void)
-{
-	if (!cpu_is_omap16xx())
-		return -ENODEV;
-
-	ocpi_ck = clk_get(NULL, "l3_ocpi_ck");
-	if (IS_ERR(ocpi_ck))
-		return PTR_ERR(ocpi_ck);
-
-	clk_enable(ocpi_ck);
-	ocpi_enable();
-	printk("OMAP OCPI interconnect driver loaded\n");
-
-	return 0;
-}
-
-static void __exit omap_ocpi_exit(void)
-{
-	/* REVISIT: Disable OCPI */
-
-	if (!cpu_is_omap16xx())
-		return;
-
-	clk_disable(ocpi_ck);
-	clk_put(ocpi_ck);
-}
-
-MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
-MODULE_DESCRIPTION("OMAP OCPI bus controller module");
-MODULE_LICENSE("GPL");
-module_init(omap_ocpi_init);
-module_exit(omap_ocpi_exit);
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index d50cbc6..c490240 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -475,13 +475,11 @@
 static int omap_device_fill_resources(struct omap_device *od,
 				      struct resource *res)
 {
-	int c = 0;
 	int i, r;
 
 	for (i = 0; i < od->hwmods_cnt; i++) {
 		r = omap_hwmod_fill_resources(od->hwmods[i], res);
 		res += r;
-		c += r;
 	}
 
 	return 0;
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index f9a8c53..477363c 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -196,8 +196,8 @@
 	 * Looks like we need to preserve some bootloader code at the
 	 * beginning of SRAM for jumping to flash for reboot to work...
 	 */
-	memset((void *)omap_sram_base + SRAM_BOOTLOADER_SZ, 0,
-	       omap_sram_size - SRAM_BOOTLOADER_SZ);
+	memset_io(omap_sram_base + SRAM_BOOTLOADER_SZ, 0,
+		  omap_sram_size - SRAM_BOOTLOADER_SZ);
 }
 
 /*
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index d2bbfd1..daa0327 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -31,15 +31,12 @@
 
 #include <mach/hardware.h>
 
-#include "../mach-omap2/common.h"
-
 #ifdef	CONFIG_ARCH_OMAP_OTG
 
 void __init
 omap_otg_init(struct omap_usb_config *config)
 {
 	u32		syscon;
-	int		status;
 	int		alt_pingroup = 0;
 
 	/* NOTE:  no bus or clock setup (yet?) */
@@ -104,6 +101,7 @@
 #ifdef	CONFIG_USB_GADGET_OMAP
 	if (config->otg || config->register_dev) {
 		struct platform_device *udc_device = config->udc_device;
+		int status;
 
 		syscon &= ~DEV_IDLE_EN;
 		udc_device->dev.platform_data = config;
@@ -116,6 +114,7 @@
 #if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
 	if (config->otg || config->register_host) {
 		struct platform_device *ohci_device = config->ohci_device;
+		int status;
 
 		syscon &= ~HST_IDLE_EN;
 		ohci_device->dev.platform_data = config;
@@ -128,6 +127,7 @@
 #ifdef	CONFIG_USB_OTG
 	if (config->otg) {
 		struct platform_device *otg_device = config->otg_device;
+		int status;
 
 		syscon &= ~OTG_IDLE_EN;
 		otg_device->dev.platform_data = config;
@@ -138,8 +138,6 @@
 #endif
 	pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1));
 	omap_writel(syscon, OTG_SYSCON_1);
-
-	status = 0;
 }
 
 #else
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
index 10d1608..af95af2 100644
--- a/arch/arm/plat-orion/gpio.c
+++ b/arch/arm/plat-orion/gpio.c
@@ -16,6 +16,7 @@
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/leds.h>
 
 /*
  * GPIO unit register offsets.
@@ -289,12 +290,34 @@
 		return;
 
 	spin_lock_irqsave(&ochip->lock, flags);
-	__set_level(ochip, pin, 0);
-	__set_blinking(ochip, pin, blink);
+	__set_level(ochip, pin & 31, 0);
+	__set_blinking(ochip, pin & 31, blink);
 	spin_unlock_irqrestore(&ochip->lock, flags);
 }
 EXPORT_SYMBOL(orion_gpio_set_blink);
 
+#define ORION_BLINK_HALF_PERIOD 100 /* ms */
+
+int orion_gpio_led_blink_set(unsigned gpio, int state,
+	unsigned long *delay_on, unsigned long *delay_off)
+{
+
+	if (delay_on && delay_off && !*delay_on && !*delay_off)
+		*delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
+
+	switch (state) {
+	case GPIO_LED_NO_BLINK_LOW:
+	case GPIO_LED_NO_BLINK_HIGH:
+		orion_gpio_set_blink(gpio, 0);
+		gpio_set_value(gpio, state);
+		break;
+	case GPIO_LED_BLINK:
+		orion_gpio_set_blink(gpio, 1);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(orion_gpio_led_blink_set);
+
 
 /*****************************************************************************
  * Orion GPIO IRQ
diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h
index 3abf304..bec0c98 100644
--- a/arch/arm/plat-orion/include/plat/gpio.h
+++ b/arch/arm/plat-orion/include/plat/gpio.h
@@ -19,6 +19,8 @@
  */
 void orion_gpio_set_unused(unsigned pin);
 void orion_gpio_set_blink(unsigned pin, int blink);
+int orion_gpio_led_blink_set(unsigned gpio, int state,
+	unsigned long *delay_on, unsigned long *delay_off);
 
 #define GPIO_INPUT_OK		(1 << 0)
 #define GPIO_OUTPUT_OK		(1 << 1)
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 8b928f9..1d214cb 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -30,6 +30,7 @@
 #include <linux/mmc/host.h>
 #include <linux/ioport.h>
 #include <linux/platform_data/s3c-hsudc.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #include <asm/irq.h>
 #include <asm/pmu.h>
@@ -57,7 +58,6 @@
 #include <plat/sdhci.h>
 #include <plat/ts.h>
 #include <plat/udc.h>
-#include <plat/udc-hs.h>
 #include <plat/usb-control.h>
 #include <plat/usb-phy.h>
 #include <plat/regs-iic.h>
@@ -272,16 +272,8 @@
 
 #ifdef CONFIG_S5P_DEV_G2D
 static struct resource s5p_g2d_resource[] = {
-	[0] = {
-		.start	= S5P_PA_G2D,
-		.end	= S5P_PA_G2D + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_2D,
-		.end	= IRQ_2D,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(S5P_PA_G2D, SZ_4K),
+	[1] = DEFINE_RES_IRQ(IRQ_2D),
 };
 
 struct platform_device s5p_device_g2d = {
@@ -370,7 +362,6 @@
 	.max_width	= 4,
 	.host_caps	= (MMC_CAP_4_BIT_DATA |
 			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
-	.clk_type	= S3C_SDHCI_CLK_DIV_INTERNAL,
 };
 
 struct platform_device s3c_device_hsmmc0 = {
@@ -401,7 +392,6 @@
 	.max_width	= 4,
 	.host_caps	= (MMC_CAP_4_BIT_DATA |
 			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
-	.clk_type	= S3C_SDHCI_CLK_DIV_INTERNAL,
 };
 
 struct platform_device s3c_device_hsmmc1 = {
@@ -434,7 +424,6 @@
 	.max_width	= 4,
 	.host_caps	= (MMC_CAP_4_BIT_DATA |
 			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
-	.clk_type	= S3C_SDHCI_CLK_DIV_INTERNAL,
 };
 
 struct platform_device s3c_device_hsmmc2 = {
@@ -465,7 +454,6 @@
 	.max_width	= 4,
 	.host_caps	= (MMC_CAP_4_BIT_DATA |
 			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
-	.clk_type	= S3C_SDHCI_CLK_DIV_INTERNAL,
 };
 
 struct platform_device s3c_device_hsmmc3 = {
diff --git a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h
deleted file mode 100644
index dc90f5e..0000000
--- a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h
+++ /dev/null
@@ -1,379 +0,0 @@
-/* arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      http://armlinux.simtec.co.uk/
- *      Ben Dooks <ben@simtec.co.uk>
- *
- * S3C - USB2.0 Highspeed/OtG device block registers
- *
- * 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 __PLAT_S3C64XX_REGS_USB_HSOTG_H
-#define __PLAT_S3C64XX_REGS_USB_HSOTG_H __FILE__
-
-#define S3C_HSOTG_REG(x) (x)
-
-#define S3C_GOTGCTL				S3C_HSOTG_REG(0x000)
-#define S3C_GOTGCTL_BSESVLD			(1 << 19)
-#define S3C_GOTGCTL_ASESVLD			(1 << 18)
-#define S3C_GOTGCTL_DBNC_SHORT			(1 << 17)
-#define S3C_GOTGCTL_CONID_B			(1 << 16)
-#define S3C_GOTGCTL_DEVHNPEN			(1 << 11)
-#define S3C_GOTGCTL_HSSETHNPEN			(1 << 10)
-#define S3C_GOTGCTL_HNPREQ			(1 << 9)
-#define S3C_GOTGCTL_HSTNEGSCS			(1 << 8)
-#define S3C_GOTGCTL_SESREQ			(1 << 1)
-#define S3C_GOTGCTL_SESREQSCS			(1 << 0)
-
-#define S3C_GOTGINT				S3C_HSOTG_REG(0x004)
-#define S3C_GOTGINT_DbnceDone			(1 << 19)
-#define S3C_GOTGINT_ADevTOUTChg			(1 << 18)
-#define S3C_GOTGINT_HstNegDet			(1 << 17)
-#define S3C_GOTGINT_HstnegSucStsChng		(1 << 9)
-#define S3C_GOTGINT_SesReqSucStsChng		(1 << 8)
-#define S3C_GOTGINT_SesEndDet			(1 << 2)
-
-#define S3C_GAHBCFG				S3C_HSOTG_REG(0x008)
-#define S3C_GAHBCFG_PTxFEmpLvl			(1 << 8)
-#define S3C_GAHBCFG_NPTxFEmpLvl			(1 << 7)
-#define S3C_GAHBCFG_DMAEn			(1 << 5)
-#define S3C_GAHBCFG_HBstLen_MASK		(0xf << 1)
-#define S3C_GAHBCFG_HBstLen_SHIFT		(1)
-#define S3C_GAHBCFG_HBstLen_Single		(0x0 << 1)
-#define S3C_GAHBCFG_HBstLen_Incr		(0x1 << 1)
-#define S3C_GAHBCFG_HBstLen_Incr4		(0x3 << 1)
-#define S3C_GAHBCFG_HBstLen_Incr8		(0x5 << 1)
-#define S3C_GAHBCFG_HBstLen_Incr16		(0x7 << 1)
-#define S3C_GAHBCFG_GlblIntrEn			(1 << 0)
-
-#define S3C_GUSBCFG				S3C_HSOTG_REG(0x00C)
-#define S3C_GUSBCFG_PHYLPClkSel			(1 << 15)
-#define S3C_GUSBCFG_HNPCap			(1 << 9)
-#define S3C_GUSBCFG_SRPCap			(1 << 8)
-#define S3C_GUSBCFG_PHYIf16			(1 << 3)
-#define S3C_GUSBCFG_TOutCal_MASK		(0x7 << 0)
-#define S3C_GUSBCFG_TOutCal_SHIFT		(0)
-#define S3C_GUSBCFG_TOutCal_LIMIT		(0x7)
-#define S3C_GUSBCFG_TOutCal(_x)			((_x) << 0)
-
-#define S3C_GRSTCTL				S3C_HSOTG_REG(0x010)
-
-#define S3C_GRSTCTL_AHBIdle			(1 << 31)
-#define S3C_GRSTCTL_DMAReq			(1 << 30)
-#define S3C_GRSTCTL_TxFNum_MASK			(0x1f << 6)
-#define S3C_GRSTCTL_TxFNum_SHIFT		(6)
-#define S3C_GRSTCTL_TxFNum_LIMIT		(0x1f)
-#define S3C_GRSTCTL_TxFNum(_x)			((_x) << 6)
-#define S3C_GRSTCTL_TxFFlsh			(1 << 5)
-#define S3C_GRSTCTL_RxFFlsh			(1 << 4)
-#define S3C_GRSTCTL_INTknQFlsh			(1 << 3)
-#define S3C_GRSTCTL_FrmCntrRst			(1 << 2)
-#define S3C_GRSTCTL_HSftRst			(1 << 1)
-#define S3C_GRSTCTL_CSftRst			(1 << 0)
-
-#define S3C_GINTSTS				S3C_HSOTG_REG(0x014)
-#define S3C_GINTMSK				S3C_HSOTG_REG(0x018)
-
-#define S3C_GINTSTS_WkUpInt			(1 << 31)
-#define S3C_GINTSTS_SessReqInt			(1 << 30)
-#define S3C_GINTSTS_DisconnInt			(1 << 29)
-#define S3C_GINTSTS_ConIDStsChng		(1 << 28)
-#define S3C_GINTSTS_PTxFEmp			(1 << 26)
-#define S3C_GINTSTS_HChInt			(1 << 25)
-#define S3C_GINTSTS_PrtInt			(1 << 24)
-#define S3C_GINTSTS_FetSusp			(1 << 22)
-#define S3C_GINTSTS_incompIP			(1 << 21)
-#define S3C_GINTSTS_IncomplSOIN			(1 << 20)
-#define S3C_GINTSTS_OEPInt			(1 << 19)
-#define S3C_GINTSTS_IEPInt			(1 << 18)
-#define S3C_GINTSTS_EPMis			(1 << 17)
-#define S3C_GINTSTS_EOPF			(1 << 15)
-#define S3C_GINTSTS_ISOutDrop			(1 << 14)
-#define S3C_GINTSTS_EnumDone			(1 << 13)
-#define S3C_GINTSTS_USBRst			(1 << 12)
-#define S3C_GINTSTS_USBSusp			(1 << 11)
-#define S3C_GINTSTS_ErlySusp			(1 << 10)
-#define S3C_GINTSTS_GOUTNakEff			(1 << 7)
-#define S3C_GINTSTS_GINNakEff			(1 << 6)
-#define S3C_GINTSTS_NPTxFEmp			(1 << 5)
-#define S3C_GINTSTS_RxFLvl			(1 << 4)
-#define S3C_GINTSTS_SOF				(1 << 3)
-#define S3C_GINTSTS_OTGInt			(1 << 2)
-#define S3C_GINTSTS_ModeMis			(1 << 1)
-#define S3C_GINTSTS_CurMod_Host			(1 << 0)
-
-#define S3C_GRXSTSR				S3C_HSOTG_REG(0x01C)
-#define S3C_GRXSTSP				S3C_HSOTG_REG(0x020)
-
-#define S3C_GRXSTS_FN_MASK			(0x7f << 25)
-#define S3C_GRXSTS_FN_SHIFT			(25)
-
-#define S3C_GRXSTS_PktSts_MASK			(0xf << 17)
-#define S3C_GRXSTS_PktSts_SHIFT			(17)
-#define S3C_GRXSTS_PktSts_GlobalOutNAK		(0x1 << 17)
-#define S3C_GRXSTS_PktSts_OutRX			(0x2 << 17)
-#define S3C_GRXSTS_PktSts_OutDone		(0x3 << 17)
-#define S3C_GRXSTS_PktSts_SetupDone		(0x4 << 17)
-#define S3C_GRXSTS_PktSts_SetupRX		(0x6 << 17)
-
-#define S3C_GRXSTS_DPID_MASK			(0x3 << 15)
-#define S3C_GRXSTS_DPID_SHIFT			(15)
-#define S3C_GRXSTS_ByteCnt_MASK			(0x7ff << 4)
-#define S3C_GRXSTS_ByteCnt_SHIFT		(4)
-#define S3C_GRXSTS_EPNum_MASK			(0xf << 0)
-#define S3C_GRXSTS_EPNum_SHIFT			(0)
-
-#define S3C_GRXFSIZ				S3C_HSOTG_REG(0x024)
-
-#define S3C_GNPTXFSIZ				S3C_HSOTG_REG(0x028)
-
-#define S3C_GNPTXFSIZ_NPTxFDep_MASK		(0xffff << 16)
-#define S3C_GNPTXFSIZ_NPTxFDep_SHIFT		(16)
-#define S3C_GNPTXFSIZ_NPTxFDep_LIMIT		(0xffff)
-#define S3C_GNPTXFSIZ_NPTxFDep(_x)		((_x) << 16)
-#define S3C_GNPTXFSIZ_NPTxFStAddr_MASK		(0xffff << 0)
-#define S3C_GNPTXFSIZ_NPTxFStAddr_SHIFT		(0)
-#define S3C_GNPTXFSIZ_NPTxFStAddr_LIMIT		(0xffff)
-#define S3C_GNPTXFSIZ_NPTxFStAddr(_x)		((_x) << 0)
-
-#define S3C_GNPTXSTS				S3C_HSOTG_REG(0x02C)
-
-#define S3C_GNPTXSTS_NPtxQTop_MASK		(0x7f << 24)
-#define S3C_GNPTXSTS_NPtxQTop_SHIFT		(24)
-
-#define S3C_GNPTXSTS_NPTxQSpcAvail_MASK		(0xff << 16)
-#define S3C_GNPTXSTS_NPTxQSpcAvail_SHIFT	(16)
-#define S3C_GNPTXSTS_NPTxQSpcAvail_GET(_v)	(((_v) >> 16) & 0xff)
-
-#define S3C_GNPTXSTS_NPTxFSpcAvail_MASK		(0xffff << 0)
-#define S3C_GNPTXSTS_NPTxFSpcAvail_SHIFT	(0)
-#define S3C_GNPTXSTS_NPTxFSpcAvail_GET(_v)	(((_v) >> 0) & 0xffff)
-
-
-#define S3C_HPTXFSIZ				S3C_HSOTG_REG(0x100)
-
-#define S3C_DPTXFSIZn(_a)			S3C_HSOTG_REG(0x104 + (((_a) - 1) * 4))
-
-#define S3C_DPTXFSIZn_DPTxFSize_MASK		(0xffff << 16)
-#define S3C_DPTXFSIZn_DPTxFSize_SHIFT		(16)
-#define S3C_DPTXFSIZn_DPTxFSize_GET(_v)		(((_v) >> 16) & 0xffff)
-#define S3C_DPTXFSIZn_DPTxFSize_LIMIT		(0xffff)
-#define S3C_DPTXFSIZn_DPTxFSize(_x)		((_x) << 16)
-
-#define S3C_DPTXFSIZn_DPTxFStAddr_MASK		(0xffff << 0)
-#define S3C_DPTXFSIZn_DPTxFStAddr_SHIFT		(0)
-
-/* Device mode registers */
-#define S3C_DCFG				S3C_HSOTG_REG(0x800)
-
-#define S3C_DCFG_EPMisCnt_MASK			(0x1f << 18)
-#define S3C_DCFG_EPMisCnt_SHIFT			(18)
-#define S3C_DCFG_EPMisCnt_LIMIT			(0x1f)
-#define S3C_DCFG_EPMisCnt(_x)			((_x) << 18)
-
-#define S3C_DCFG_PerFrInt_MASK			(0x3 << 11)
-#define S3C_DCFG_PerFrInt_SHIFT			(11)
-#define S3C_DCFG_PerFrInt_LIMIT			(0x3)
-#define S3C_DCFG_PerFrInt(_x)			((_x) << 11)
-
-#define S3C_DCFG_DevAddr_MASK			(0x7f << 4)
-#define S3C_DCFG_DevAddr_SHIFT			(4)
-#define S3C_DCFG_DevAddr_LIMIT			(0x7f)
-#define S3C_DCFG_DevAddr(_x)			((_x) << 4)
-
-#define S3C_DCFG_NZStsOUTHShk			(1 << 2)
-
-#define S3C_DCFG_DevSpd_MASK			(0x3 << 0)
-#define S3C_DCFG_DevSpd_SHIFT			(0)
-#define S3C_DCFG_DevSpd_HS			(0x0 << 0)
-#define S3C_DCFG_DevSpd_FS			(0x1 << 0)
-#define S3C_DCFG_DevSpd_LS			(0x2 << 0)
-#define S3C_DCFG_DevSpd_FS48			(0x3 << 0)
-
-#define S3C_DCTL				S3C_HSOTG_REG(0x804)
-
-#define S3C_DCTL_PWROnPrgDone			(1 << 11)
-#define S3C_DCTL_CGOUTNak			(1 << 10)
-#define S3C_DCTL_SGOUTNak			(1 << 9)
-#define S3C_DCTL_CGNPInNAK			(1 << 8)
-#define S3C_DCTL_SGNPInNAK			(1 << 7)
-#define S3C_DCTL_TstCtl_MASK			(0x7 << 4)
-#define S3C_DCTL_TstCtl_SHIFT			(4)
-#define S3C_DCTL_GOUTNakSts			(1 << 3)
-#define S3C_DCTL_GNPINNakSts			(1 << 2)
-#define S3C_DCTL_SftDiscon			(1 << 1)
-#define S3C_DCTL_RmtWkUpSig			(1 << 0)
-
-#define S3C_DSTS				S3C_HSOTG_REG(0x808)
-
-#define S3C_DSTS_SOFFN_MASK			(0x3fff << 8)
-#define S3C_DSTS_SOFFN_SHIFT			(8)
-#define S3C_DSTS_SOFFN_LIMIT			(0x3fff)
-#define S3C_DSTS_SOFFN(_x)			((_x) << 8)
-#define S3C_DSTS_ErraticErr			(1 << 3)
-#define S3C_DSTS_EnumSpd_MASK			(0x3 << 1)
-#define S3C_DSTS_EnumSpd_SHIFT			(1)
-#define S3C_DSTS_EnumSpd_HS			(0x0 << 1)
-#define S3C_DSTS_EnumSpd_FS			(0x1 << 1)
-#define S3C_DSTS_EnumSpd_LS			(0x2 << 1)
-#define S3C_DSTS_EnumSpd_FS48			(0x3 << 1)
-
-#define S3C_DSTS_SuspSts			(1 << 0)
-
-#define S3C_DIEPMSK				S3C_HSOTG_REG(0x810)
-
-#define S3C_DIEPMSK_TxFIFOEmpty			(1 << 7)
-#define S3C_DIEPMSK_INEPNakEffMsk		(1 << 6)
-#define S3C_DIEPMSK_INTknEPMisMsk		(1 << 5)
-#define S3C_DIEPMSK_INTknTXFEmpMsk		(1 << 4)
-#define S3C_DIEPMSK_TimeOUTMsk			(1 << 3)
-#define S3C_DIEPMSK_AHBErrMsk			(1 << 2)
-#define S3C_DIEPMSK_EPDisbldMsk			(1 << 1)
-#define S3C_DIEPMSK_XferComplMsk		(1 << 0)
-
-#define S3C_DOEPMSK				S3C_HSOTG_REG(0x814)
-
-#define S3C_DOEPMSK_Back2BackSetup		(1 << 6)
-#define S3C_DOEPMSK_OUTTknEPdisMsk		(1 << 4)
-#define S3C_DOEPMSK_SetupMsk			(1 << 3)
-#define S3C_DOEPMSK_AHBErrMsk			(1 << 2)
-#define S3C_DOEPMSK_EPDisbldMsk			(1 << 1)
-#define S3C_DOEPMSK_XferComplMsk		(1 << 0)
-
-#define S3C_DAINT				S3C_HSOTG_REG(0x818)
-#define S3C_DAINTMSK				S3C_HSOTG_REG(0x81C)
-
-#define S3C_DAINT_OutEP_SHIFT			(16)
-#define S3C_DAINT_OutEP(x)			(1 << ((x) + 16))
-#define S3C_DAINT_InEP(x)			(1 << (x))
-
-#define S3C_DTKNQR1				S3C_HSOTG_REG(0x820)
-#define S3C_DTKNQR2				S3C_HSOTG_REG(0x824)
-#define S3C_DTKNQR3				S3C_HSOTG_REG(0x830)
-#define S3C_DTKNQR4				S3C_HSOTG_REG(0x834)
-
-#define S3C_DVBUSDIS				S3C_HSOTG_REG(0x828)
-#define S3C_DVBUSPULSE				S3C_HSOTG_REG(0x82C)
-
-#define S3C_DIEPCTL0				S3C_HSOTG_REG(0x900)
-#define S3C_DOEPCTL0				S3C_HSOTG_REG(0xB00)
-#define S3C_DIEPCTL(_a)				S3C_HSOTG_REG(0x900 + ((_a) * 0x20))
-#define S3C_DOEPCTL(_a)				S3C_HSOTG_REG(0xB00 + ((_a) * 0x20))
-
-/* EP0 specialness:
- * bits[29..28] - reserved (no SetD0PID, SetD1PID)
- * bits[25..22] - should always be zero, this isn't a periodic endpoint
- * bits[10..0] - MPS setting differenct for EP0
-*/
-#define S3C_D0EPCTL_MPS_MASK			(0x3 << 0)
-#define S3C_D0EPCTL_MPS_SHIFT			(0)
-#define S3C_D0EPCTL_MPS_64			(0x0 << 0)
-#define S3C_D0EPCTL_MPS_32			(0x1 << 0)
-#define S3C_D0EPCTL_MPS_16			(0x2 << 0)
-#define S3C_D0EPCTL_MPS_8			(0x3 << 0)
-
-#define S3C_DxEPCTL_EPEna			(1 << 31)
-#define S3C_DxEPCTL_EPDis			(1 << 30)
-#define S3C_DxEPCTL_SetD1PID			(1 << 29)
-#define S3C_DxEPCTL_SetOddFr			(1 << 29)
-#define S3C_DxEPCTL_SetD0PID			(1 << 28)
-#define S3C_DxEPCTL_SetEvenFr			(1 << 28)
-#define S3C_DxEPCTL_SNAK			(1 << 27)
-#define S3C_DxEPCTL_CNAK			(1 << 26)
-#define S3C_DxEPCTL_TxFNum_MASK			(0xf << 22)
-#define S3C_DxEPCTL_TxFNum_SHIFT		(22)
-#define S3C_DxEPCTL_TxFNum_LIMIT		(0xf)
-#define S3C_DxEPCTL_TxFNum(_x)			((_x) << 22)
-
-#define S3C_DxEPCTL_Stall			(1 << 21)
-#define S3C_DxEPCTL_Snp				(1 << 20)
-#define S3C_DxEPCTL_EPType_MASK			(0x3 << 18)
-#define S3C_DxEPCTL_EPType_SHIFT		(18)
-#define S3C_DxEPCTL_EPType_Control		(0x0 << 18)
-#define S3C_DxEPCTL_EPType_Iso			(0x1 << 18)
-#define S3C_DxEPCTL_EPType_Bulk			(0x2 << 18)
-#define S3C_DxEPCTL_EPType_Intterupt		(0x3 << 18)
-
-#define S3C_DxEPCTL_NAKsts			(1 << 17)
-#define S3C_DxEPCTL_DPID			(1 << 16)
-#define S3C_DxEPCTL_EOFrNum			(1 << 16)
-#define S3C_DxEPCTL_USBActEp			(1 << 15)
-#define S3C_DxEPCTL_NextEp_MASK			(0xf << 11)
-#define S3C_DxEPCTL_NextEp_SHIFT		(11)
-#define S3C_DxEPCTL_NextEp_LIMIT		(0xf)
-#define S3C_DxEPCTL_NextEp(_x)			((_x) << 11)
-
-#define S3C_DxEPCTL_MPS_MASK			(0x7ff << 0)
-#define S3C_DxEPCTL_MPS_SHIFT			(0)
-#define S3C_DxEPCTL_MPS_LIMIT			(0x7ff)
-#define S3C_DxEPCTL_MPS(_x)			((_x) << 0)
-
-#define S3C_DIEPINT(_a)				S3C_HSOTG_REG(0x908 + ((_a) * 0x20))
-#define S3C_DOEPINT(_a)				S3C_HSOTG_REG(0xB08 + ((_a) * 0x20))
-
-#define S3C_DxEPINT_INEPNakEff			(1 << 6)
-#define S3C_DxEPINT_Back2BackSetup		(1 << 6)
-#define S3C_DxEPINT_INTknEPMis			(1 << 5)
-#define S3C_DxEPINT_INTknTXFEmp			(1 << 4)
-#define S3C_DxEPINT_OUTTknEPdis			(1 << 4)
-#define S3C_DxEPINT_Timeout			(1 << 3)
-#define S3C_DxEPINT_Setup			(1 << 3)
-#define S3C_DxEPINT_AHBErr			(1 << 2)
-#define S3C_DxEPINT_EPDisbld			(1 << 1)
-#define S3C_DxEPINT_XferCompl			(1 << 0)
-
-#define S3C_DIEPTSIZ0				S3C_HSOTG_REG(0x910)
-
-#define S3C_DIEPTSIZ0_PktCnt_MASK		(0x3 << 19)
-#define S3C_DIEPTSIZ0_PktCnt_SHIFT		(19)
-#define S3C_DIEPTSIZ0_PktCnt_LIMIT		(0x3)
-#define S3C_DIEPTSIZ0_PktCnt(_x)		((_x) << 19)
-
-#define S3C_DIEPTSIZ0_XferSize_MASK		(0x7f << 0)
-#define S3C_DIEPTSIZ0_XferSize_SHIFT		(0)
-#define S3C_DIEPTSIZ0_XferSize_LIMIT		(0x7f)
-#define S3C_DIEPTSIZ0_XferSize(_x)		((_x) << 0)
-
-
-#define DOEPTSIZ0				S3C_HSOTG_REG(0xB10)
-#define S3C_DOEPTSIZ0_SUPCnt_MASK		(0x3 << 29)
-#define S3C_DOEPTSIZ0_SUPCnt_SHIFT		(29)
-#define S3C_DOEPTSIZ0_SUPCnt_LIMIT		(0x3)
-#define S3C_DOEPTSIZ0_SUPCnt(_x)		((_x) << 29)
-
-#define S3C_DOEPTSIZ0_PktCnt			(1 << 19)
-#define S3C_DOEPTSIZ0_XferSize_MASK		(0x7f << 0)
-#define S3C_DOEPTSIZ0_XferSize_SHIFT		(0)
-
-#define S3C_DIEPTSIZ(_a)			S3C_HSOTG_REG(0x910 + ((_a) * 0x20))
-#define S3C_DOEPTSIZ(_a)			S3C_HSOTG_REG(0xB10 + ((_a) * 0x20))
-
-#define S3C_DxEPTSIZ_MC_MASK			(0x3 << 29)
-#define S3C_DxEPTSIZ_MC_SHIFT			(29)
-#define S3C_DxEPTSIZ_MC_LIMIT			(0x3)
-#define S3C_DxEPTSIZ_MC(_x)			((_x) << 29)
-
-#define S3C_DxEPTSIZ_PktCnt_MASK		(0x3ff << 19)
-#define S3C_DxEPTSIZ_PktCnt_SHIFT		(19)
-#define S3C_DxEPTSIZ_PktCnt_GET(_v)		(((_v) >> 19) & 0x3ff)
-#define S3C_DxEPTSIZ_PktCnt_LIMIT		(0x3ff)
-#define S3C_DxEPTSIZ_PktCnt(_x)			((_x) << 19)
-
-#define S3C_DxEPTSIZ_XferSize_MASK		(0x7ffff << 0)
-#define S3C_DxEPTSIZ_XferSize_SHIFT		(0)
-#define S3C_DxEPTSIZ_XferSize_GET(_v)		(((_v) >> 0) & 0x7ffff)
-#define S3C_DxEPTSIZ_XferSize_LIMIT		(0x7ffff)
-#define S3C_DxEPTSIZ_XferSize(_x)		((_x) << 0)
-
-
-#define S3C_DIEPDMA(_a)				S3C_HSOTG_REG(0x914 + ((_a) * 0x20))
-#define S3C_DOEPDMA(_a)				S3C_HSOTG_REG(0xB14 + ((_a) * 0x20))
-#define S3C_DTXFSTS(_a)				S3C_HSOTG_REG(0x918 + ((_a) * 0x20))
-
-#define S3C_EPFIFO(_a)				S3C_HSOTG_REG(0x1000 + ((_a) * 0x1000))
-
-#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_H */
diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h
index e834c5e..151cc91 100644
--- a/arch/arm/plat-samsung/include/plat/sdhci.h
+++ b/arch/arm/plat-samsung/include/plat/sdhci.h
@@ -33,18 +33,12 @@
 	S3C_SDHCI_CD_PERMANENT,	/* no CD line, card permanently wired to host */
 };
 
-enum clk_types {
-	S3C_SDHCI_CLK_DIV_INTERNAL,	/* use mmc internal clock divider */
-	S3C_SDHCI_CLK_DIV_EXTERNAL,	/* use external clock divider */
-};
-
 /**
  * struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI
  * @max_width: The maximum number of data bits supported.
  * @host_caps: Standard MMC host capabilities bit field.
  * @host_caps2: The second standard MMC host capabilities bit field.
  * @cd_type: Type of Card Detection method (see cd_types enum above)
- * @clk_type: Type of clock divider method (see clk_types enum above)
  * @ext_cd_init: Initialize external card detect subsystem. Called on
  *		 sdhci-s3c driver probe when cd_type == S3C_SDHCI_CD_EXTERNAL.
  *		 notify_func argument is a callback to the sdhci-s3c driver
@@ -69,7 +63,6 @@
 	unsigned int	host_caps2;
 	unsigned int	pm_caps;
 	enum cd_types	cd_type;
-	enum clk_types	clk_type;
 
 	int		ext_cd_gpio;
 	bool		ext_cd_gpio_invert;
diff --git a/arch/arm/plat-samsung/include/plat/udc-hs.h b/arch/arm/plat-samsung/include/plat/udc-hs.h
deleted file mode 100644
index c9e3667..0000000
--- a/arch/arm/plat-samsung/include/plat/udc-hs.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* arch/arm/plat-s3c/include/plat/udc-hs.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * S3C USB2.0 High-speed / OtG platform information
- *
- * 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.
-*/
-
-enum s3c_hsotg_dmamode {
-	S3C_HSOTG_DMA_NONE,	/* do not use DMA at-all */
-	S3C_HSOTG_DMA_ONLY,	/* always use DMA */
-	S3C_HSOTG_DMA_DRV,	/* DMA is chosen by driver */
-};
-
-/**
- * struct s3c_hsotg_plat - platform data for high-speed otg/udc
- * @dma: Whether to use DMA or not.
- * @is_osc: The clock source is an oscillator, not a crystal
- */
-struct s3c_hsotg_plat {
-	enum s3c_hsotg_dmamode	dma;
-	unsigned int		is_osc : 1;
-
-	int (*phy_init)(struct platform_device *pdev, int type);
-	int (*phy_exit)(struct platform_device *pdev, int type);
-};
-
-extern void s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd);
diff --git a/arch/arm/plat-samsung/platformdata.c b/arch/arm/plat-samsung/platformdata.c
index fa78aa7..b430e99 100644
--- a/arch/arm/plat-samsung/platformdata.c
+++ b/arch/arm/plat-samsung/platformdata.c
@@ -57,6 +57,4 @@
 		set->host_caps2 |= pd->host_caps2;
 	if (pd->pm_caps)
 		set->pm_caps |= pd->pm_caps;
-	if (pd->clk_type)
-		set->clk_type = pd->clk_type;
 }
diff --git a/arch/arm/plat-spear/Kconfig b/arch/arm/plat-spear/Kconfig
index 1bb3dbc..387655b 100644
--- a/arch/arm/plat-spear/Kconfig
+++ b/arch/arm/plat-spear/Kconfig
@@ -9,9 +9,11 @@
 	default ARCH_SPEAR3XX
 
 config ARCH_SPEAR3XX
-	bool "SPEAr3XX"
+	bool "ST SPEAr3xx with Device Tree"
 	select ARM_VIC
 	select CPU_ARM926T
+	select USE_OF
+	select PINCTRL
 	help
 	  Supports for ARM's SPEAR3XX family
 
diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile
index e0f2e5b..7744802 100644
--- a/arch/arm/plat-spear/Makefile
+++ b/arch/arm/plat-spear/Makefile
@@ -3,6 +3,6 @@
 #
 
 # Common support
-obj-y	:= clock.o restart.o time.o
+obj-y	:= clock.o restart.o time.o pl080.o
 
-obj-$(CONFIG_ARCH_SPEAR3XX)	+= shirq.o padmux.o
+obj-$(CONFIG_ARCH_SPEAR3XX)	+= shirq.o
diff --git a/arch/arm/plat-spear/include/plat/debug-macro.S b/arch/arm/plat-spear/include/plat/debug-macro.S
index 02b160a..ab3de72 100644
--- a/arch/arm/plat-spear/include/plat/debug-macro.S
+++ b/arch/arm/plat-spear/include/plat/debug-macro.S
@@ -12,7 +12,7 @@
  */
 
 #include <linux/amba/serial.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
 
 		.macro	addruart, rp, rv, tmp
 		mov	\rp, #SPEAR_DBG_UART_BASE		@ Physical base
diff --git a/arch/arm/plat-spear/include/plat/hardware.h b/arch/arm/plat-spear/include/plat/hardware.h
deleted file mode 100644
index 70187d7..0000000
--- a/arch/arm/plat-spear/include/plat/hardware.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/hardware.h
- *
- * Hardware definitions for SPEAr
- *
- * Copyright (C) 2010 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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 __PLAT_HARDWARE_H
-#define __PLAT_HARDWARE_H
-
-#endif /* __PLAT_HARDWARE_H */
diff --git a/arch/arm/plat-spear/include/plat/padmux.h b/arch/arm/plat-spear/include/plat/padmux.h
deleted file mode 100644
index 877f3adc..0000000
--- a/arch/arm/plat-spear/include/plat/padmux.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/padmux.h
- *
- * SPEAr platform specific gpio pads muxing file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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 __PLAT_PADMUX_H
-#define __PLAT_PADMUX_H
-
-#include <linux/types.h>
-
-/*
- * struct pmx_reg: configuration structure for mode reg and mux reg
- *
- * offset: offset of mode reg
- * mask: mask of mode reg
- */
-struct pmx_reg {
-	u32 offset;
-	u32 mask;
-};
-
-/*
- * struct pmx_dev_mode: configuration structure every group of modes of a device
- *
- * ids: all modes for this configuration
- * mask: mask for supported mode
- */
-struct pmx_dev_mode {
-	u32 ids;
-	u32 mask;
-};
-
-/*
- * struct pmx_mode: mode definition structure
- *
- * name: mode name
- * mask: mode mask
- */
-struct pmx_mode {
-	char *name;
-	u32 id;
-	u32 mask;
-};
-
-/*
- * struct pmx_dev: device definition structure
- *
- * name: device name
- * modes: device configuration array for different modes supported
- * mode_count: size of modes array
- * is_active: is peripheral active/enabled
- * enb_on_reset: if 1, mask bits to be cleared in reg otherwise to be set in reg
- */
-struct pmx_dev {
-	char *name;
-	struct pmx_dev_mode *modes;
-	u8 mode_count;
-	bool is_active;
-	bool enb_on_reset;
-};
-
-/*
- * struct pmx_driver: driver definition structure
- *
- * mode: mode to be set
- * devs: array of pointer to pmx devices
- * devs_count: ARRAY_SIZE of devs
- * base: base address of soc config registers
- * mode_reg: structure of mode config register
- * mux_reg: structure of device mux config register
- */
-struct pmx_driver {
-	struct pmx_mode *mode;
-	struct pmx_dev **devs;
-	u8 devs_count;
-	u32 *base;
-	struct pmx_reg mode_reg;
-	struct pmx_reg mux_reg;
-};
-
-/* pmx functions */
-int pmx_register(struct pmx_driver *driver);
-
-#endif /* __PLAT_PADMUX_H */
diff --git a/arch/arm/plat-spear/include/plat/pl080.h b/arch/arm/plat-spear/include/plat/pl080.h
new file mode 100644
index 0000000..e14a3e4
--- /dev/null
+++ b/arch/arm/plat-spear/include/plat/pl080.h
@@ -0,0 +1,21 @@
+/*
+ * arch/arm/plat-spear/include/plat/pl080.h
+ *
+ * DMAC pl080 definitions for SPEAr platform
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * 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 __PLAT_PL080_H
+#define __PLAT_PL080_H
+
+struct pl08x_dma_chan;
+int pl080_get_signal(struct pl08x_dma_chan *ch);
+void pl080_put_signal(struct pl08x_dma_chan *ch);
+
+#endif /* __PLAT_PL080_H */
diff --git a/arch/arm/plat-spear/include/plat/uncompress.h b/arch/arm/plat-spear/include/plat/uncompress.h
index 1bf8452..6dd455b 100644
--- a/arch/arm/plat-spear/include/plat/uncompress.h
+++ b/arch/arm/plat-spear/include/plat/uncompress.h
@@ -13,7 +13,7 @@
 
 #include <linux/io.h>
 #include <linux/amba/serial.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
 
 #ifndef __PLAT_UNCOMPRESS_H
 #define __PLAT_UNCOMPRESS_H
diff --git a/arch/arm/plat-spear/padmux.c b/arch/arm/plat-spear/padmux.c
deleted file mode 100644
index 555eec6..0000000
--- a/arch/arm/plat-spear/padmux.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/padmux.c
- *
- * SPEAr platform specific gpio pads muxing source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * 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/err.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <plat/padmux.h>
-
-/*
- * struct pmx: pmx definition structure
- *
- * base: base address of configuration registers
- * mode_reg: mode configurations
- * mux_reg: muxing configurations
- * active_mode: pointer to current active mode
- */
-struct pmx {
-	u32 base;
-	struct pmx_reg mode_reg;
-	struct pmx_reg mux_reg;
-	struct pmx_mode *active_mode;
-};
-
-static struct pmx *pmx;
-
-/**
- * pmx_mode_set - Enables an multiplexing mode
- * @mode - pointer to pmx mode
- *
- * It will set mode of operation in hardware.
- * Returns -ve on Err otherwise 0
- */
-static int pmx_mode_set(struct pmx_mode *mode)
-{
-	u32 val;
-
-	if (!mode->name)
-		return -EFAULT;
-
-	pmx->active_mode = mode;
-
-	val = readl(pmx->base + pmx->mode_reg.offset);
-	val &= ~pmx->mode_reg.mask;
-	val |= mode->mask & pmx->mode_reg.mask;
-	writel(val, pmx->base + pmx->mode_reg.offset);
-
-	return 0;
-}
-
-/**
- * pmx_devs_enable - Enables list of devices
- * @devs - pointer to pmx device array
- * @count - number of devices to enable
- *
- * It will enable pads for all required peripherals once and only once.
- * If peripheral is not supported by current mode then request is rejected.
- * Conflicts between peripherals are not handled and peripherals will be
- * enabled in the order they are present in pmx_dev array.
- * In case of conflicts last peripheral enabled will be present.
- * Returns -ve on Err otherwise 0
- */
-static int pmx_devs_enable(struct pmx_dev **devs, u8 count)
-{
-	u32 val, i, mask;
-
-	if (!count)
-		return -EINVAL;
-
-	val = readl(pmx->base + pmx->mux_reg.offset);
-	for (i = 0; i < count; i++) {
-		u8 j = 0;
-
-		if (!devs[i]->name || !devs[i]->modes) {
-			printk(KERN_ERR "padmux: dev name or modes is null\n");
-			continue;
-		}
-		/* check if peripheral exists in active mode */
-		if (pmx->active_mode) {
-			bool found = false;
-			for (j = 0; j < devs[i]->mode_count; j++) {
-				if (devs[i]->modes[j].ids &
-						pmx->active_mode->id) {
-					found = true;
-					break;
-				}
-			}
-			if (found == false) {
-				printk(KERN_ERR "%s device not available in %s"\
-						"mode\n", devs[i]->name,
-						pmx->active_mode->name);
-				continue;
-			}
-		}
-
-		/* enable peripheral */
-		mask = devs[i]->modes[j].mask & pmx->mux_reg.mask;
-		if (devs[i]->enb_on_reset)
-			val &= ~mask;
-		else
-			val |= mask;
-
-		devs[i]->is_active = true;
-	}
-	writel(val, pmx->base + pmx->mux_reg.offset);
-	kfree(pmx);
-
-	/* this will ensure that multiplexing can't be changed now */
-	pmx = (struct pmx *)-1;
-
-	return 0;
-}
-
-/**
- * pmx_register - registers a platform requesting pad mux feature
- * @driver - pointer to driver structure containing driver specific parameters
- *
- * Also this must be called only once. This will allocate memory for pmx
- * structure, will call pmx_mode_set, will call pmx_devs_enable.
- * Returns -ve on Err otherwise 0
- */
-int pmx_register(struct pmx_driver *driver)
-{
-	int ret = 0;
-
-	if (pmx)
-		return -EPERM;
-	if (!driver->base || !driver->devs)
-		return -EFAULT;
-
-	pmx = kzalloc(sizeof(*pmx), GFP_KERNEL);
-	if (!pmx)
-		return -ENOMEM;
-
-	pmx->base = (u32)driver->base;
-	pmx->mode_reg.offset = driver->mode_reg.offset;
-	pmx->mode_reg.mask = driver->mode_reg.mask;
-	pmx->mux_reg.offset = driver->mux_reg.offset;
-	pmx->mux_reg.mask = driver->mux_reg.mask;
-
-	/* choose mode to enable */
-	if (driver->mode) {
-		ret = pmx_mode_set(driver->mode);
-		if (ret)
-			goto pmx_fail;
-	}
-	ret = pmx_devs_enable(driver->devs, driver->devs_count);
-	if (ret)
-		goto pmx_fail;
-
-	return 0;
-
-pmx_fail:
-	return ret;
-}
diff --git a/arch/arm/plat-spear/pl080.c b/arch/arm/plat-spear/pl080.c
new file mode 100644
index 0000000..a56a067
--- /dev/null
+++ b/arch/arm/plat-spear/pl080.c
@@ -0,0 +1,80 @@
+/*
+ * arch/arm/plat-spear/pl080.c
+ *
+ * DMAC pl080 definitions for SPEAr platform
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * 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/amba/pl08x.h>
+#include <linux/amba/bus.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/spinlock_types.h>
+#include <mach/spear.h>
+#include <mach/misc_regs.h>
+
+static spinlock_t lock = __SPIN_LOCK_UNLOCKED(x);
+
+struct {
+	unsigned char busy;
+	unsigned char val;
+} signals[16] = {{0, 0}, };
+
+int pl080_get_signal(struct pl08x_dma_chan *ch)
+{
+	const struct pl08x_channel_data *cd = ch->cd;
+	unsigned int signal = cd->min_signal, val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lock, flags);
+
+	/* Return if signal is already acquired by somebody else */
+	if (signals[signal].busy &&
+			(signals[signal].val != cd->muxval)) {
+		spin_unlock_irqrestore(&lock, flags);
+		return -EBUSY;
+	}
+
+	/* If acquiring for the first time, configure it */
+	if (!signals[signal].busy) {
+		val = readl(DMA_CHN_CFG);
+
+		/*
+		 * Each request line has two bits in DMA_CHN_CFG register. To
+		 * goto the bits of current request line, do left shift of
+		 * value by 2 * signal number.
+		 */
+		val &= ~(0x3 << (signal * 2));
+		val |= cd->muxval << (signal * 2);
+		writel(val, DMA_CHN_CFG);
+	}
+
+	signals[signal].busy++;
+	signals[signal].val = cd->muxval;
+	spin_unlock_irqrestore(&lock, flags);
+
+	return signal;
+}
+
+void pl080_put_signal(struct pl08x_dma_chan *ch)
+{
+	const struct pl08x_channel_data *cd = ch->cd;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lock, flags);
+
+	/* if signal is not used */
+	if (!signals[cd->min_signal].busy)
+		BUG();
+
+	signals[cd->min_signal].busy--;
+
+	spin_unlock_irqrestore(&lock, flags);
+}
diff --git a/arch/arm/plat-spear/restart.c b/arch/arm/plat-spear/restart.c
index 16f203e..4471a23 100644
--- a/arch/arm/plat-spear/restart.c
+++ b/arch/arm/plat-spear/restart.c
@@ -13,7 +13,7 @@
 #include <linux/io.h>
 #include <asm/system_misc.h>
 #include <asm/hardware/sp810.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
 #include <mach/generic.h>
 
 void spear_restart(char mode, const char *cmd)
diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c
index abb5bde..a3164d1 100644
--- a/arch/arm/plat-spear/time.c
+++ b/arch/arm/plat-spear/time.c
@@ -15,14 +15,13 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/ioport.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/time.h>
 #include <linux/irq.h>
 #include <asm/mach/time.h>
 #include <mach/generic.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
 
 /*
  * We would use TIMER0 and TIMER1 as clockevent and clocksource.
@@ -175,7 +174,7 @@
 	.handler = spear_timer_interrupt
 };
 
-static void __init spear_clockevent_init(void)
+static void __init spear_clockevent_init(int irq)
 {
 	u32 tick_rate;
 
@@ -195,19 +194,19 @@
 
 	clockevents_register_device(&clkevt);
 
-	setup_irq(SPEAR_GPT0_CHAN0_IRQ, &spear_timer_irq);
+	setup_irq(irq, &spear_timer_irq);
 }
 
-void __init spear_setup_timer(void)
+void __init spear_setup_timer(resource_size_t base, int irq)
 {
 	int ret;
 
-	if (!request_mem_region(SPEAR_GPT0_BASE, SZ_1K, "gpt0")) {
+	if (!request_mem_region(base, SZ_1K, "gpt0")) {
 		pr_err("%s:cannot get IO addr\n", __func__);
 		return;
 	}
 
-	gpt_base = (void __iomem *)ioremap(SPEAR_GPT0_BASE, SZ_1K);
+	gpt_base = ioremap(base, SZ_1K);
 	if (!gpt_base) {
 		pr_err("%s:ioremap failed for gpt\n", __func__);
 		goto err_mem;
@@ -225,7 +224,7 @@
 		goto err_clk;
 	}
 
-	spear_clockevent_init();
+	spear_clockevent_init(irq);
 	spear_clocksource_init();
 
 	return;
@@ -235,5 +234,5 @@
 err_iomap:
 	iounmap(gpt_base);
 err_mem:
-	release_mem_region(SPEAR_GPT0_BASE, SZ_1K);
+	release_mem_region(base, SZ_1K);
 }
diff --git a/arch/avr32/include/asm/processor.h b/arch/avr32/include/asm/processor.h
index 108502b..87d8bac 100644
--- a/arch/avr32/include/asm/processor.h
+++ b/arch/avr32/include/asm/processor.h
@@ -145,9 +145,6 @@
 /* Create a kernel thread without removing it from tasklists */
 extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while(0)
-
 /* Return saved PC of a blocked thread */
 #define thread_saved_pc(tsk)    ((tsk)->thread.cpu_context.pc)
 
diff --git a/arch/avr32/include/asm/signal.h b/arch/avr32/include/asm/signal.h
index 8790dfc..ae56849 100644
--- a/arch/avr32/include/asm/signal.h
+++ b/arch/avr32/include/asm/signal.h
@@ -115,13 +115,6 @@
 #include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
-struct old_sigaction {
-	__sighandler_t sa_handler;
-	old_sigset_t sa_mask;
-	unsigned long sa_flags;
-	__sigrestore_t sa_restorer;
-};
-
 struct sigaction {
 	__sighandler_t sa_handler;
 	unsigned long sa_flags;
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index 64f886f..ae386c3 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -77,6 +77,9 @@
 	struct rt_sigframe __user *frame;
 	sigset_t set;
 
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
 	frame = (struct rt_sigframe __user *)regs->sp;
 	pr_debug("SIG return: frame = %p\n", frame);
 
@@ -87,10 +90,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
@@ -238,22 +238,16 @@
 	 */
 	ret |= !valid_user_regs(regs);
 
-	/*
-	 * Block the signal if we were unsuccessful.
-	 */
-	if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked,
-			  &ka->sa.sa_mask);
-		sigaddset(&current->blocked, sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
+	if (ret != 0) {
+		force_sigsegv(sig, current);
+		return;
 	}
 
-	if (ret == 0)
-		return;
-
-	force_sigsegv(sig, current);
+	/*
+	 * Block the signal if we were successful.
+	 */
+	block_sigmask(ka, sig);
+	clear_thread_flag(TIF_RESTORE_SIGMASK);
 }
 
 /*
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 7f3c589..79cfe26 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -1309,7 +1309,7 @@
 	  (all processors, except ADSP-BF549). This option sets
 	  the general-purpose wake-up enable (GPWE) control bit to enable
 	  wake-up upon detection of an active low signal on the /GPW (PH7) pin.
-	  On ADSP-BF549 this option enables the the same functionality on the
+	  On ADSP-BF549 this option enables the same functionality on the
 	  /MRXON pin also PH7.
 
 config PM_BFIN_WAKE_PA15
diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h
index 8af7772..4ef7cfe 100644
--- a/arch/blackfin/include/asm/processor.h
+++ b/arch/blackfin/include/asm/processor.h
@@ -75,8 +75,6 @@
 {
 }
 
-#define prepare_to_copy(tsk)	do { } while (0)
-
 extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags);
 
 /*
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index d536f35..e5bbc1a 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -99,10 +99,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
 		goto badframe;
@@ -213,9 +210,7 @@
 	return 0;
 
  give_sigsegv:
-	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-	force_sig(SIGSEGV, current);
+	force_sigsegv(sig, current);
 	return -EFAULT;
 }
 
@@ -266,15 +261,9 @@
 	/* set up the stack frame */
 	ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
-	if (ret == 0) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked,
-			  &ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	if (ret == 0)
+		block_sigmask(ka, sig);
+
 	return ret;
 }
 
diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h
index 3ff7fab..c50af7e 100644
--- a/arch/c6x/include/asm/processor.h
+++ b/arch/c6x/include/asm/processor.h
@@ -92,9 +92,6 @@
 {
 }
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 #define copy_segments(tsk, mm)		do { } while (0)
diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c
index 3b5a050..cf37478 100644
--- a/arch/c6x/kernel/signal.c
+++ b/arch/c6x/kernel/signal.c
@@ -69,6 +69,9 @@
 	struct rt_sigframe __user *frame;
 	sigset_t set;
 
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
 	/*
 	 * Since we stacked the signal on a dword boundary,
 	 * 'sp' should be dword aligned here.  If it's
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
index 289c584..e16f8f2 100644
--- a/arch/cris/arch-v10/kernel/signal.c
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -48,19 +48,11 @@
  * dummy arguments to be able to reach the regs argument.  (Note that this
  * arrangement relies on old_sigset_t occupying one register.)
  */
-int sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
-	long srp, struct pt_regs *regs)
+int sys_sigsuspend(old_sigset_t mask)
 {
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	sigset_t blocked;
+	siginitset(&blocked, mask);
+	return sigsuspend(&blocked);
 }
 
 int sys_sigaction(int sig, const struct old_sigaction __user *act,
@@ -73,10 +65,10 @@
 		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_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);
 	}
 
@@ -85,10 +77,10 @@
 	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_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;
@@ -185,10 +177,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->sc))
 		goto badframe;
@@ -224,10 +213,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
@@ -469,15 +455,9 @@
 	else
 		ret = setup_frame(sig, ka, oldset, regs);
 
-	if (ret == 0) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked,
-			&ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	if (ret == 0)
+		block_sigmask(ka, sig);
+
 	return ret;
 }
 
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c
index ce4ab1a..b338d8f 100644
--- a/arch/cris/arch-v32/kernel/signal.c
+++ b/arch/cris/arch-v32/kernel/signal.c
@@ -59,19 +59,11 @@
  * dummy arguments to be able to reach the regs argument.
  */
 int
-sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
-	       long srp, struct pt_regs *regs)
+sys_sigsuspend(old_sigset_t mask)
 {
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	sigset_t blocked;
+	siginitset(&blocked, mask);
+	return sigsuspend(&blocked);
 }
 
 int
@@ -87,11 +79,11 @@
 
 		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(newk.sa.sa_handler, &act->sa_handler) ||
-		    __get_user(newk.sa.sa_restorer, &act->sa_restorer))
+		    __get_user(newk.sa.sa_restorer, &act->sa_restorer) ||
+		    __get_user(newk.sa.sa_flags, &act->sa_flags) ||
+		    __get_user(mask, &act->sa_mask))
 			return -EFAULT;
 
-		__get_user(newk.sa.sa_flags, &act->sa_flags);
-		__get_user(mask, &act->sa_mask);
 		siginitset(&newk.sa.sa_mask, mask);
 	}
 
@@ -100,11 +92,11 @@
 	if (!retval && oact) {
 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(oldk.sa.sa_handler, &oact->sa_handler) ||
-		    __put_user(oldk.sa.sa_restorer, &oact->sa_restorer))
+		    __put_user(oldk.sa.sa_restorer, &oact->sa_restorer) ||
+		    __put_user(oldk.sa.sa_flags, &oact->sa_flags) ||
+		    __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask))
 			return -EFAULT;
 
-		__put_user(oldk.sa.sa_flags, &oact->sa_flags);
-		__put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask);
 	}
 
 	return retval;
@@ -176,12 +168,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-
-	current->blocked = set;
-
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->sc))
 		goto badframe;
@@ -222,12 +209,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-
-	current->blocked = set;
-
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
@@ -363,10 +345,7 @@
 	return 0;
 
 give_sigsegv:
-	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-
-	force_sig(SIGSEGV, current);
+	force_sigsegv(sig, current);
 	return -EFAULT;
 }
 
@@ -450,10 +429,7 @@
 	return 0;
 
 give_sigsegv:
-	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-
-	force_sig(SIGSEGV, current);
+	force_sigsegv(sig, current);
 	return -EFAULT;
 }
 
@@ -512,18 +488,8 @@
 	else
 		ret = setup_frame(sig, ka, oldset, regs);
 
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
-
-	if (ret == 0) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked,
-			&ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	if (ret == 0)
+		block_sigmask(ka, sig);
 
 	return ret;
 }
diff --git a/arch/cris/include/asm/processor.h b/arch/cris/include/asm/processor.h
index 8dc56ef..ef4e1bc 100644
--- a/arch/cris/include/asm/processor.h
+++ b/arch/cris/include/asm/processor.h
@@ -49,10 +49,6 @@
 #define task_pt_regs(task) user_regs(task_thread_info(task))
 #define current_regs() task_pt_regs(current)
 
-static inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 unsigned long get_wchan(struct task_struct *p);
diff --git a/arch/frv/include/asm/processor.h b/arch/frv/include/asm/processor.h
index 9b1a92b..dccb9d1 100644
--- a/arch/frv/include/asm/processor.h
+++ b/arch/frv/include/asm/processor.h
@@ -54,7 +54,6 @@
  * Bus types
  */
 #define EISA_bus 0
-#define MCA_bus 0
 
 struct thread_struct {
 	struct pt_regs		*frame;		/* [GR28] exception frame ptr for this thread */
@@ -103,8 +102,6 @@
 	__frame->sp	= (_usp);			\
 } while(0)
 
-extern void prepare_to_copy(struct task_struct *tsk);
-
 /* Free all resources held by a thread. */
 static inline void release_thread(struct task_struct *dead_task)
 {
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index ed09e9e..ff95f50 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -165,17 +165,6 @@
 	return do_fork(clone_flags, newsp, __frame, 0, parent_tidptr, child_tidptr);
 } /* end sys_clone() */
 
-/*****************************************************************************/
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
-	//unlazy_fpu(tsk);
-} /* end prepare_to_copy() */
-
-/*****************************************************************************/
 /*
  * set up the kernel stack and exception frames for a new process
  */
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index bab0129..8cf5dca 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -40,17 +40,9 @@
  */
 asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	sigset_t blocked;
+	siginitset(&blocked, mask);
+	return sigsuspend(&blocked);
 }
 
 asmlinkage int sys_sigaction(int sig,
@@ -64,10 +56,10 @@
 		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_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);
 	}
 
@@ -76,10 +68,10 @@
 	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_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;
@@ -158,10 +150,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(&frame->sc, &gr8))
 		goto badframe;
@@ -184,10 +173,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8))
 		goto badframe;
@@ -474,15 +460,8 @@
 	else
 		ret = setup_frame(sig, ka, oldset);
 
-	if (ret == 0) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked,
-			  &ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	if (ret == 0)
+		block_sigmask(ka, sig);
 
 	return ret;
 
diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h
index 61fabf1..4c9f6f8 100644
--- a/arch/h8300/include/asm/processor.h
+++ b/arch/h8300/include/asm/processor.h
@@ -109,8 +109,6 @@
 
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-#define prepare_to_copy(tsk)	do { } while (0)
-
 /*
  * Free current thread data structures etc..
  */
diff --git a/arch/h8300/include/asm/unistd.h b/arch/h8300/include/asm/unistd.h
index 2c3f8e6..7185113 100644
--- a/arch/h8300/include/asm/unistd.h
+++ b/arch/h8300/include/asm/unistd.h
@@ -356,6 +356,7 @@
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
 /*
  * "Conditional" syscalls
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index af842c3..d4b0555 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -49,60 +49,15 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-asmlinkage int do_sigsuspend(struct pt_regs *regs)
-{
-	old_sigset_t mask = regs->er3;
-	sigset_t saveset;
-
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs->er0 = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(regs, &saveset))
-			return -EINTR;
-	}
-}
-
 asmlinkage int
-do_rt_sigsuspend(struct pt_regs *regs)
+sys_sigsuspend(int unused1, int unused2, old_sigset_t mask)
 {
-	sigset_t *unewset = (sigset_t *)regs->er1;
-	size_t sigsetsize = (size_t)regs->er2;
-	sigset_t saveset, 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, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs->er0 = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(regs, &saveset))
-			return -EINTR;
-	}
+	sigset_t blocked;
+	siginitset(&blocked, mask);
+	return sigsuspend(&blocked);
 }
 
 asmlinkage int 
@@ -116,10 +71,10 @@
 		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_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);
 	}
 
@@ -128,10 +83,10 @@
 	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_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;
@@ -232,10 +187,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 	
 	if (restore_sigcontext(regs, &frame->sc, &er0))
 		goto badframe;
@@ -260,10 +212,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_unlock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_lock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 	
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0))
 		goto badframe;
@@ -314,7 +263,7 @@
 	return (void *)((usp - frame_size) & -8UL);
 }
 
-static void setup_frame (int sig, struct k_sigaction *ka,
+static int setup_frame (int sig, struct k_sigaction *ka,
 			 sigset_t *set, struct pt_regs *regs)
 {
 	struct sigframe *frame;
@@ -375,13 +324,14 @@
 	regs->er1 = (unsigned long)&(frame->sc);
 	regs->er5 = current->mm->start_data;	/* GOT base */
 
-	return;
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
+	return -EFAULT;
 }
 
-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 *frame;
@@ -450,10 +400,11 @@
 	regs->er2 = (unsigned long)&frame->uc;
 	regs->er5 = current->mm->start_data;	/* GOT base */
 
-	return;
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
+	return -EFAULT;
 }
 
 /*
@@ -463,6 +414,7 @@
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 	      sigset_t *oldset,	struct pt_regs * regs)
 {
+	int ret;
 	/* are we from a system call? */
 	if (regs->orig_er0 >= 0) {
 		switch (regs->er0) {
@@ -485,16 +437,14 @@
 
 	/* set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(sig, ka, info, oldset, regs);
+		ret = setup_rt_frame(sig, ka, info, oldset, regs);
 	else
-		setup_frame(sig, ka, oldset, regs);
+		ret = setup_frame(sig, ka, oldset, regs);
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked,sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	if (!ret) {
+		block_sigmask(ka, sig);
+		clear_thread_flag(TIF_RESTORE_SIGMASK);
+	}
 }
 
 /*
@@ -502,11 +452,12 @@
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset)
+statis void do_signal(struct pt_regs *regs)
 {
 	siginfo_t info;
 	int signr;
 	struct k_sigaction ka;
+	sigset_t *oldset;
 
 	/*
 	 * We want the common case to go fast, which
@@ -515,21 +466,23 @@
 	 * if so.
 	 */
 	if ((regs->ccr & 0x10))
-		return 1;
+		return;
 
 	if (try_to_freeze())
 		goto no_signal;
 
 	current->thread.esp0 = (unsigned long) regs;
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal(signr, &info, &ka, oldset, regs);
-		return 1;
+		return;
 	}
  no_signal:
 	/* Did we come from a system call? */
@@ -546,13 +499,16 @@
 			regs->pc -= 2;
 		}
 	}
-	return 0;
+
+	/* If there's no signal to deliver, we just restore the saved mask.  */
+	if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+		set_current_blocked(&current->saved_sigmask);
 }
 
 asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
 {
-	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
-		do_signal(regs, NULL);
+	if (thread_info_flags & _TIF_SIGPENDING)
+		do_signal(regs);
 
 	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 		clear_thread_flag(TIF_NOTIFY_RESUME);
diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S
index 4be2ea2..9d77e71 100644
--- a/arch/h8300/kernel/syscalls.S
+++ b/arch/h8300/kernel/syscalls.S
@@ -343,12 +343,6 @@
 SYMBOL_NAME_LABEL(sys_clone)	
 	call_sp	h8300_clone
 	
-SYMBOL_NAME_LABEL(sys_sigsuspend)
-	call_sp	do_sigsuspend
-
-SYMBOL_NAME_LABEL(sys_rt_sigsuspend)
-	call_sp	do_rt_sigsuspend
-
 SYMBOL_NAME_LABEL(sys_sigreturn)
 	call_sp	do_sigreturn
 
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index 22615dd..bc979f7 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -13,8 +13,8 @@
 	# select ARCH_REQUIRE_GPIOLIB
 	# select HAVE_CLK
 	# select IRQ_PER_CPU
-	select HAVE_IRQ_WORK
 	# select GENERIC_PENDING_IRQ if SMP
+	select HAVE_IRQ_WORK
 	select GENERIC_ATOMIC64
 	select HAVE_PERF_EVENTS
 	select HAVE_GENERIC_HARDIRQS
@@ -26,7 +26,7 @@
 	select NO_IOPORT
 	select GENERIC_IOMAP
 	select GENERIC_SMP_IDLE_THREAD
-	# mostly generic routines, with some accelerated ones
+	select STACKTRACE_SUPPORT
 	---help---
 	  Qualcomm Hexagon is a processor architecture designed for high
 	  performance and low power across a wide variety of applications.
@@ -73,15 +73,6 @@
 config GENERIC_IRQ_PROBE
 	def_bool y
 
-#config ZONE_DMA
-#	bool
-#	default y
-
-config HAS_DMA
-	bool
-	select HAVE_DMA_ATTRS
-	default y
-
 config NEED_SG_DMA_LENGTH
 	def_bool y
 
@@ -114,14 +105,11 @@
 	def_bool y
 	depends on BUG
 
-config BUG
-	def_bool y
-
 menu "Machine selection"
 
 choice
 	prompt "System type"
-	default HEXAGON_ARCH_V2
+	default HEXAGON_COMET
 
 config HEXAGON_COMET
 	bool "Comet Board"
@@ -194,8 +182,7 @@
 source "kernel/time/Kconfig"
 
 config GENERIC_GPIO
-	bool "Generic GPIO support"
-	default n
+	def_bool n
 
 endmenu
 
diff --git a/arch/hexagon/Makefile b/arch/hexagon/Makefile
index e27d030..d00d900 100644
--- a/arch/hexagon/Makefile
+++ b/arch/hexagon/Makefile
@@ -50,8 +50,3 @@
 core-y += arch/hexagon/kernel/ \
 	arch/hexagon/mm/ \
 	arch/hexagon/lib/
-
-#	arch/hexagon/platform/common/
-#
-#core-$(CONFIG_HEXAGON_COMET)		+= arch/hexagon/platform/comet/
-#machine-$(CONFIG_HEXAGON_COMET)		:= comet
diff --git a/arch/hexagon/include/asm/processor.h b/arch/hexagon/include/asm/processor.h
index 20c5dda..e8ea459 100644
--- a/arch/hexagon/include/asm/processor.h
+++ b/arch/hexagon/include/asm/processor.h
@@ -59,13 +59,6 @@
 #define cpu_relax() __vmyield()
 
 /*
- * "Unlazying all lazy status" occurs here.
- */
-static inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
-/*
  * Decides where the kernel will search for a free chunk of vm space during
  * mmaps.
  * See also arch_get_unmapped_area.
diff --git a/arch/hexagon/include/asm/spinlock_types.h b/arch/hexagon/include/asm/spinlock_types.h
index 5e937af..99b5a75 100644
--- a/arch/hexagon/include/asm/spinlock_types.h
+++ b/arch/hexagon/include/asm/spinlock_types.h
@@ -21,8 +21,6 @@
 #ifndef _ASM_SPINLOCK_TYPES_H
 #define _ASM_SPINLOCK_TYPES_H
 
-#include <linux/version.h>
-
 #ifndef __LINUX_SPINLOCK_TYPES_H
 # error "please don't include this file directly"
 #endif
diff --git a/arch/hexagon/kernel/dma.c b/arch/hexagon/kernel/dma.c
index 0f2367c..2b48751 100644
--- a/arch/hexagon/kernel/dma.c
+++ b/arch/hexagon/kernel/dma.c
@@ -54,7 +54,7 @@
 
 /* Allocates from a pool of uncached memory that was reserved at boot time */
 
-void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
+static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
 				 dma_addr_t *dma_addr, gfp_t flag,
 				 struct dma_attrs *attrs)
 {
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index ecbab34..434866e 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -272,6 +272,7 @@
 
 	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 		clear_thread_flag(TIF_NOTIFY_RESUME);
+		tracehook_notify_resume(regs);
 		if (current->replacement_session_keyring)
 			key_replace_session_keyring();
 	}
@@ -293,6 +294,9 @@
 	struct rt_sigframe __user *frame;
 	sigset_t blocked;
 
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
 	frame = (struct rt_sigframe __user *)pt_psp(regs);
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
diff --git a/arch/hexagon/kernel/time.c b/arch/hexagon/kernel/time.c
index 5d9b33b..36ba641 100644
--- a/arch/hexagon/kernel/time.c
+++ b/arch/hexagon/kernel/time.c
@@ -201,12 +201,10 @@
 		resource = rtos_timer_device.resource;
 
 	/*  ioremap here means this has to run later, after paging init  */
-	rtos_timer = ioremap(resource->start, resource->end
-		- resource->start + 1);
+	rtos_timer = ioremap(resource->start, resource_size(resource));
 
 	if (!rtos_timer) {
-		release_mem_region(resource->start, resource->end
-			- resource->start + 1);
+		release_mem_region(resource->start, resource_size(resource));
 	}
 	clocksource_register_khz(&hexagon_clocksource, pcycle_freq_mhz * 1000);
 
diff --git a/arch/hexagon/mm/vm_fault.c b/arch/hexagon/mm/vm_fault.c
index c10b76f..06695cc 100644
--- a/arch/hexagon/mm/vm_fault.c
+++ b/arch/hexagon/mm/vm_fault.c
@@ -53,6 +53,8 @@
 	int si_code = SEGV_MAPERR;
 	int fault;
 	const struct exception_table_entry *fixup;
+	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+				 (cause > 0 ? FAULT_FLAG_WRITE : 0);
 
 	/*
 	 * If we're in an interrupt or have no user context,
@@ -63,6 +65,7 @@
 
 	local_irq_enable();
 
+retry:
 	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if (!vma)
@@ -96,14 +99,23 @@
 		break;
 	}
 
-	fault = handle_mm_fault(mm, vma, address, (cause > 0));
+	fault = handle_mm_fault(mm, vma, address, flags);
+
+	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+		return;
 
 	/* The most common case -- we are done. */
 	if (likely(!(fault & VM_FAULT_ERROR))) {
-		if (fault & VM_FAULT_MAJOR)
-			current->maj_flt++;
-		else
-			current->min_flt++;
+		if (flags & FAULT_FLAG_ALLOW_RETRY) {
+			if (fault & VM_FAULT_MAJOR)
+				current->maj_flt++;
+			else
+				current->min_flt++;
+			if (fault & VM_FAULT_RETRY) {
+				flags &= ~FAULT_FLAG_ALLOW_RETRY;
+				goto retry;
+			}
+		}
 
 		up_read(&mm->mmap_sem);
 		return;
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 241d1c5..d4eb938 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -1,6 +1,7 @@
 include include/asm-generic/Kbuild.asm
 
 header-y += break.h
+header-y += cmpxchg.h
 header-y += fpu.h
 header-y += gcc_intrin.h
 header-y += ia64regs.h
diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
index f92f67a..832dd37 100644
--- a/arch/ia64/include/asm/processor.h
+++ b/arch/ia64/include/asm/processor.h
@@ -34,8 +34,7 @@
  * each (assuming 8KB page size), for a total of 8TB of user virtual
  * address space.
  */
-#define TASK_SIZE_OF(tsk)	((tsk)->thread.task_size)
-#define TASK_SIZE       	TASK_SIZE_OF(current)
+#define TASK_SIZE       	DEFAULT_TASK_SIZE
 
 /*
  * This decides where the kernel will search for a free chunk of vm
@@ -280,7 +279,6 @@
 	__u8 pad[3];
 	__u64 ksp;			/* kernel stack pointer */
 	__u64 map_base;			/* base address for get_unmapped_area() */
-	__u64 task_size;		/* limit for task size */
 	__u64 rbs_bot;			/* the base address for the RBS */
 	int last_fph_cpu;		/* CPU that may hold the contents of f32-f127 */
 
@@ -303,7 +301,6 @@
 	.ksp =		0,					\
 	.map_base =	DEFAULT_MAP_BASE,			\
 	.rbs_bot =	STACK_TOP - DEFAULT_USER_STACK_SIZE,	\
-	.task_size =	DEFAULT_TASK_SIZE,			\
 	.last_fph_cpu =  -1,					\
 	INIT_THREAD_PM						\
 	.dbr =		{0, },					\
@@ -343,9 +340,6 @@
  */
 #define release_thread(dead_task)
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 /*
  * This is the mechanism for creating a new kernel thread.
  *
diff --git a/arch/ia64/include/asm/topology.h b/arch/ia64/include/asm/topology.h
index 09f6467..a2496e4 100644
--- a/arch/ia64/include/asm/topology.h
+++ b/arch/ia64/include/asm/topology.h
@@ -70,31 +70,6 @@
 	.nr_balance_failed	= 0,			\
 }
 
-/* sched_domains SD_NODE_INIT for IA64 NUMA machines */
-#define SD_NODE_INIT (struct sched_domain) {		\
-	.parent			= NULL,			\
-	.child			= NULL,			\
-	.groups			= NULL,			\
-	.min_interval		= 8,			\
-	.max_interval		= 8*(min(num_online_cpus(), 32U)), \
-	.busy_factor		= 64,			\
-	.imbalance_pct		= 125,			\
-	.cache_nice_tries	= 2,			\
-	.busy_idx		= 3,			\
-	.idle_idx		= 2,			\
-	.newidle_idx		= 0,			\
-	.wake_idx		= 0,			\
-	.forkexec_idx		= 0,			\
-	.flags			= SD_LOAD_BALANCE	\
-				| SD_BALANCE_NEWIDLE	\
-				| SD_BALANCE_EXEC	\
-				| SD_BALANCE_FORK	\
-				| SD_SERIALIZE,		\
-	.last_balance		= jiffies,		\
-	.balance_interval	= 64,			\
-	.nr_balance_failed	= 0,			\
-}
-
 #endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_SMP
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index cc26eda..e662f17 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -372,175 +372,6 @@
 END(fsys_clock_gettime)
 
 /*
- * long fsys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize).
- */
-#if _NSIG_WORDS != 1
-# error Sorry, fsys_rt_sigprocmask() needs to be updated for _NSIG_WORDS != 1.
-#endif
-ENTRY(fsys_rt_sigprocmask)
-	.prologue
-	.altrp b6
-	.body
-
-	add r2=IA64_TASK_BLOCKED_OFFSET,r16
-	add r9=TI_FLAGS+IA64_TASK_SIZE,r16
-	cmp4.ltu p6,p0=SIG_SETMASK,r32
-
-	cmp.ne p15,p0=r0,r34			// oset != NULL?
-	tnat.nz p8,p0=r34
-	add r31=IA64_TASK_SIGHAND_OFFSET,r16
-	;;
-	ld8 r3=[r2]				// read/prefetch current->blocked
-	ld4 r9=[r9]
-	tnat.nz.or p6,p0=r35
-
-	cmp.ne.or p6,p0=_NSIG_WORDS*8,r35
-	tnat.nz.or p6,p0=r32
-(p6)	br.spnt.few .fail_einval		// fail with EINVAL
-	;;
-#ifdef CONFIG_SMP
-	ld8 r31=[r31]				// r31 <- current->sighand
-#endif
-	and r9=TIF_ALLWORK_MASK,r9
-	tnat.nz.or p8,p0=r33
-	;;
-	cmp.ne p7,p0=0,r9
-	cmp.eq p6,p0=r0,r33			// set == NULL?
-	add r31=IA64_SIGHAND_SIGLOCK_OFFSET,r31	// r31 <- current->sighand->siglock
-(p8)	br.spnt.few .fail_efault		// fail with EFAULT
-(p7)	br.spnt.many fsys_fallback_syscall	// got pending kernel work...
-(p6)	br.dpnt.many .store_mask		// -> short-circuit to just reading the signal mask
-
-	/* Argh, we actually have to do some work and _update_ the signal mask: */
-
-EX(.fail_efault, probe.r.fault r33, 3)		// verify user has read-access to *set
-EX(.fail_efault, ld8 r14=[r33])			// r14 <- *set
-	mov r17=(1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1))
-	;;
-
-	RSM_PSR_I(p0, r18, r19)			// mask interrupt delivery
-	andcm r14=r14,r17			// filter out SIGKILL & SIGSTOP
-	mov r8=EINVAL			// default to EINVAL
-
-#ifdef CONFIG_SMP
-	// __ticket_spin_trylock(r31)
-	ld4 r17=[r31]
-	;;
-	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
-	;;
-#else
-	ld8 r3=[r2]			// re-read current->blocked now that we hold the lock
-#endif
-	add r18=IA64_TASK_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r16
-	add r19=IA64_TASK_SIGNAL_OFFSET,r16
-	cmp4.eq p6,p0=SIG_BLOCK,r32
-	;;
-	ld8 r19=[r19]			// r19 <- current->signal
-	cmp4.eq p7,p0=SIG_UNBLOCK,r32
-	cmp4.eq p8,p0=SIG_SETMASK,r32
-	;;
-	ld8 r18=[r18]			// r18 <- current->pending.signal
-	.pred.rel.mutex p6,p7,p8
-(p6)	or r14=r3,r14			// SIG_BLOCK
-(p7)	andcm r14=r3,r14		// SIG_UNBLOCK
-
-(p8)	mov r14=r14			// SIG_SETMASK
-(p6)	mov r8=0			// clear error code
-	// recalc_sigpending()
-	add r17=IA64_SIGNAL_GROUP_STOP_COUNT_OFFSET,r19
-
-	add r19=IA64_SIGNAL_SHARED_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r19
-	;;
-	ld4 r17=[r17]		// r17 <- current->signal->group_stop_count
-(p7)	mov r8=0		// clear error code
-
-	ld8 r19=[r19]		// r19 <- current->signal->shared_pending
-	;;
-	cmp4.gt p6,p7=r17,r0	// p6/p7 <- (current->signal->group_stop_count > 0)?
-(p8)	mov r8=0		// clear error code
-
-	or r18=r18,r19		// r18 <- current->pending | current->signal->shared_pending
-	;;
-	// r18 <- (current->pending | current->signal->shared_pending) & ~current->blocked:
-	andcm r18=r18,r14
-	add r9=TI_FLAGS+IA64_TASK_SIZE,r16
-	;;
-
-(p7)	cmp.ne.or.andcm p6,p7=r18,r0		// p6/p7 <- signal pending
-	mov r19=0					// i must not leak kernel bits...
-(p6)	br.cond.dpnt.many .sig_pending
-	;;
-
-1:	ld4 r17=[r9]				// r17 <- current->thread_info->flags
-	;;
-	mov ar.ccv=r17
-	and r18=~_TIF_SIGPENDING,r17		// r18 <- r17 & ~(1 << TIF_SIGPENDING)
-	;;
-
-	st8 [r2]=r14				// update current->blocked with new mask
-	cmpxchg4.acq r8=[r9],r18,ar.ccv		// current->thread_info->flags <- r18
-	;;
-	cmp.ne p6,p0=r17,r8			// update failed?
-(p6)	br.cond.spnt.few 1b			// yes -> retry
-
-#ifdef CONFIG_SMP
-	// __ticket_spin_unlock(r31)
-	st2.rel [r31]=r20
-	mov r20=0					// i must not leak kernel bits...
-#endif
-	SSM_PSR_I(p0, p9, r31)
-	;;
-
-	srlz.d					// ensure psr.i is set again
-	mov r18=0					// i must not leak kernel bits...
-
-.store_mask:
-EX(.fail_efault, (p15) probe.w.fault r34, 3)	// verify user has write-access to *oset
-EX(.fail_efault, (p15) st8 [r34]=r3)
-	mov r2=0					// i must not leak kernel bits...
-	mov r3=0					// i must not leak kernel bits...
-	mov r8=0				// return 0
-	mov r9=0					// i must not leak kernel bits...
-	mov r14=0					// i must not leak kernel bits...
-	mov r17=0					// i must not leak kernel bits...
-	mov r31=0					// i must not leak kernel bits...
-	FSYS_RETURN
-
-.sig_pending:
-#ifdef CONFIG_SMP
-	// __ticket_spin_unlock(r31)
-	st2.rel [r31]=r20			// release the lock
-#endif
-	SSM_PSR_I(p0, p9, r17)
-	;;
-	srlz.d
-	br.sptk.many fsys_fallback_syscall	// with signal pending, do the heavy-weight syscall
-
-#ifdef CONFIG_SMP
-.lock_contention:
-	/* Rather than spinning here, fall back on doing a heavy-weight syscall.  */
-	SSM_PSR_I(p0, p9, r17)
-	;;
-	srlz.d
-	br.sptk.many fsys_fallback_syscall
-#endif
-END(fsys_rt_sigprocmask)
-
-/*
  * fsys_getcpu doesn't use the third parameter in this implementation. It reads
  * current_thread_info()->cpu and corresponding node in cpu_to_node_map.
  */
@@ -559,11 +390,15 @@
 	;;
 	tnat.nz p7,p0 = r33			// I guard against NaT argument
 (p7)    br.cond.spnt.few .fail_einval		// B
+	;;
+	cmp.ne p6,p0=r32,r0
+	cmp.ne p7,p0=r33,r0
+	;;
 #ifdef CONFIG_NUMA
 	movl r17=cpu_to_node_map
 	;;
-EX(.fail_efault, probe.w.fault r32, 3)		// M This takes 5 cycles
-EX(.fail_efault, probe.w.fault r33, 3)		// M This takes 5 cycles
+EX(.fail_efault, (p6) probe.w.fault r32, 3)		// M This takes 5 cycles
+EX(.fail_efault, (p7) probe.w.fault r33, 3)		// M This takes 5 cycles
 	shladd r18=r3,1,r17
 	;;
 	ld2 r20=[r18]				// r20 = cpu_to_node_map[cpu]
@@ -573,20 +408,20 @@
 (p8)	br.spnt.many fsys_fallback_syscall
 	;;
 	;;
-EX(.fail_efault, st4 [r32] = r3)
-EX(.fail_efault, st2 [r33] = r20)
+EX(.fail_efault, (p6) st4 [r32] = r3)
+EX(.fail_efault, (p7) st2 [r33] = r20)
 	mov r8=0
 	;;
 #else
-EX(.fail_efault, probe.w.fault r32, 3)		// M This takes 5 cycles
-EX(.fail_efault, probe.w.fault r33, 3)		// M This takes 5 cycles
+EX(.fail_efault, (p6) probe.w.fault r32, 3)		// M This takes 5 cycles
+EX(.fail_efault, (p7) probe.w.fault r33, 3)		// M This takes 5 cycles
 	and r2 = TIF_ALLWORK_MASK,r2
 	;;
 	cmp.ne p8,p0=0,r2
 (p8)	br.spnt.many fsys_fallback_syscall
 	;;
-EX(.fail_efault, st4 [r32] = r3)
-EX(.fail_efault, st2 [r33] = r0)
+EX(.fail_efault, (p6) st4 [r32] = r3)
+EX(.fail_efault, (p7) st2 [r33] = r0)
 	mov r8=0
 	;;
 #endif
@@ -916,7 +751,7 @@
 	data8 0				// sigaltstack
 	data8 0				// rt_sigaction
 	data8 0				// rt_sigpending
-	data8 fsys_rt_sigprocmask	// rt_sigprocmask
+	data8 0				// rt_sigprocmask
 	data8 0				// rt_sigqueueinfo	// 1180
 	data8 0				// rt_sigreturn
 	data8 0				// rt_sigsuspend
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 7bdafc8..7523501 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -201,13 +201,7 @@
 		goto give_sigsegv;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	{
-		current->blocked = set;
-		recalc_sigpending();
-	}
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(sc, scr))
 		goto give_sigsegv;
@@ -427,12 +421,7 @@
 	if (!setup_frame(sig, ka, info, oldset, scr))
 		return 0;
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked, sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	block_sigmask(ka, sig);
 
 	/*
 	 * Let tracing know that we've done the handler setup.
diff --git a/arch/m32r/include/asm/processor.h b/arch/m32r/include/asm/processor.h
index e1f46d7..da17253 100644
--- a/arch/m32r/include/asm/processor.h
+++ b/arch/m32r/include/asm/processor.h
@@ -118,8 +118,6 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-#define prepare_to_copy(tsk)	do { } while (0)
-
 /*
  * create a kernel thread without removing it from tasklists
  */
diff --git a/arch/m32r/include/asm/signal.h b/arch/m32r/include/asm/signal.h
index b2eeb0d..ea5f95e 100644
--- a/arch/m32r/include/asm/signal.h
+++ b/arch/m32r/include/asm/signal.h
@@ -110,13 +110,6 @@
 #include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
-struct old_sigaction {
-	__sighandler_t sa_handler;
-	old_sigset_t sa_mask;
-	unsigned long sa_flags;
-	__sigrestore_t sa_restorer;
-};
-
 struct sigaction {
 	__sighandler_t sa_handler;
 	unsigned long sa_flags;
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index a08697f..f54d969 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -112,10 +112,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &result))
 		goto badframe;
@@ -300,12 +297,7 @@
 	if (setup_rt_frame(sig, ka, info, oldset, regs))
 		return -EFAULT;
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked,sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	block_sigmask(ka, sig);
 	return 0;
 }
 
diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu
index 8a9c767..51b3274 100644
--- a/arch/m68k/Kconfig.cpu
+++ b/arch/m68k/Kconfig.cpu
@@ -7,7 +7,7 @@
 	help
 	  The Freescale (was Motorola) M68K family of processors implements
 	  the full 68000 processor instruction set.
-	  The Freescale ColdFire family of processors is a modern derivitive
+	  The Freescale ColdFire family of processors is a modern derivative
 	  of the 68000 processor family. They are mainly targeted at embedded
 	  applications, and are all System-On-Chip (SOC) devices, as opposed
 	  to stand alone CPUs. They implement a subset of the original 68000
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index 46460fa..f17c42a 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -153,9 +153,6 @@
 {
 }
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /*
diff --git a/arch/m68k/include/asm/thread_info.h b/arch/m68k/include/asm/thread_info.h
index e8665e6..126131f 100644
--- a/arch/m68k/include/asm/thread_info.h
+++ b/arch/m68k/include/asm/thread_info.h
@@ -71,6 +71,7 @@
  * bits 0-7 are tested at every exception exit
  * bits 8-15 are also tested at syscall exit
  */
+#define TIF_NOTIFY_RESUME	5	/* callback before returning to user */
 #define TIF_SIGPENDING		6	/* signal pending */
 #define TIF_NEED_RESCHED	7	/* rescheduling necessary */
 #define TIF_DELAYED_TRACE	14	/* single step a syscall */
diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S
index 675a854..f29e73c 100644
--- a/arch/m68k/kernel/entry_mm.S
+++ b/arch/m68k/kernel/entry_mm.S
@@ -148,7 +148,7 @@
 	jcs	do_trace_exit
 	jmi	do_delayed_trace
 	lslw	#8,%d0
-	jmi	do_signal_return
+	jne	do_signal_return
 	pea	resume_userspace
 	jra	schedule
 
@@ -172,7 +172,7 @@
 	| save top of frame
 	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
 	lslb	#1,%d0
-	jmi	do_signal_return
+	jne	do_signal_return
 	pea	resume_userspace
 	jra	schedule
 
@@ -182,7 +182,7 @@
 	subql	#4,%sp			| dummy return address
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
-	bsrl	do_signal
+	bsrl	do_notify_resume
 	addql	#4,%sp
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index 1747c70..d9f3d19 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -43,6 +43,7 @@
 #include <linux/tty.h>
 #include <linux/binfmts.h>
 #include <linux/module.h>
+#include <linux/tracehook.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -230,18 +231,9 @@
 asmlinkage int
 sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
 {
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_restore_sigmask();
-
-	return -ERESTARTNOHAND;
+	sigset_t blocked;
+	siginitset(&blocked, mask);
+	return sigsuspend(&blocked);
 }
 
 asmlinkage int
@@ -804,8 +796,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	current->blocked = set;
-	recalc_sigpending();
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->sc, frame + 1))
 		goto badframe;
@@ -830,8 +821,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	current->blocked = set;
-	recalc_sigpending();
+	set_current_blocked(&set);
 
 	if (rt_restore_ucontext(regs, sw, &frame->uc))
 		goto badframe;
@@ -1150,10 +1140,7 @@
 	if (err)
 		return;
 
-	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked,sig);
-	recalc_sigpending();
+	block_sigmask(ka, sig);
 
 	if (test_thread_flag(TIF_DELAYED_TRACE)) {
 		regs->sr &= ~0x8000;
@@ -1168,7 +1155,7 @@
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-asmlinkage void do_signal(struct pt_regs *regs)
+static void do_signal(struct pt_regs *regs)
 {
 	siginfo_t info;
 	struct k_sigaction ka;
@@ -1200,3 +1187,15 @@
 		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 	}
 }
+
+void do_notify_resume(struct pt_regs *regs)
+{
+	if (test_thread_flag(TIF_SIGPENDING))
+		do_signal(regs);
+
+	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+		tracehook_notify_resume(regs);
+		if (current->replacement_session_keyring)
+			key_replace_session_keyring();
+	}
+}
diff --git a/arch/m68k/platform/68328/entry.S b/arch/m68k/platform/68328/entry.S
index 5c39b80..7f91c2f 100644
--- a/arch/m68k/platform/68328/entry.S
+++ b/arch/m68k/platform/68328/entry.S
@@ -119,7 +119,7 @@
 	subql	#4,%sp			/* dummy return address*/
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
-	bsrw	do_signal
+	bsrw	do_notify_resume
 	addql	#4,%sp
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
diff --git a/arch/m68k/platform/68360/entry.S b/arch/m68k/platform/68360/entry.S
index aa47d1d..904fd9a 100644
--- a/arch/m68k/platform/68360/entry.S
+++ b/arch/m68k/platform/68360/entry.S
@@ -115,7 +115,7 @@
 	subql	#4,%sp			/* dummy return address*/
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
-	bsrw	do_signal
+	bsrw	do_notify_resume
 	addql	#4,%sp
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
diff --git a/arch/m68k/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S
index 281e38c..881ab8e 100644
--- a/arch/m68k/platform/coldfire/entry.S
+++ b/arch/m68k/platform/coldfire/entry.S
@@ -152,7 +152,7 @@
 	subql	#4,%sp			/* dummy return address */
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
-	jsr	do_signal
+	jsr	do_notify_resume
 	addql	#4,%sp
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
diff --git a/arch/m68k/platform/coldfire/m532x.c b/arch/m68k/platform/coldfire/m532x.c
index 8e9476d..53942236 100644
--- a/arch/m68k/platform/coldfire/m532x.c
+++ b/arch/m68k/platform/coldfire/m532x.c
@@ -7,7 +7,7 @@
  *	Copyright (C) 2000, Lineo (www.lineo.com)
  *	Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
  *	Copyright Freescale Semiconductor, Inc 2006
- *	Copyright (c) 2006, emlix, Sebastian Hess <sh@emlix.com>
+ *	Copyright (c) 2006, emlix, Sebastian Hess <shess@hessware.de>
  *
  * 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
diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h
index bffb545..af2bb96 100644
--- a/arch/microblaze/include/asm/processor.h
+++ b/arch/microblaze/include/asm/processor.h
@@ -23,7 +23,6 @@
 
 # define cpu_relax()		barrier()
 # define cpu_sleep()		do {} while (0)
-# define prepare_to_copy(tsk)	do {} while (0)
 
 #define task_pt_regs(tsk) \
 		(((struct pt_regs *)(THREAD_SIZE + task_stack_page(tsk))) - 1)
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S
index 34b526f..75c3ea1 100644
--- a/arch/microblaze/kernel/entry-nommu.S
+++ b/arch/microblaze/kernel/entry-nommu.S
@@ -132,11 +132,10 @@
 	beqi	r11, 1f
 	bralid	r15, schedule
 	nop
-1:	andi	r11, r19, _TIF_SIGPENDING
+1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 	beqid	r11, no_intr_resched
 	addk	r5, r1, r0
-	addk	r7, r0, r0
-	bralid	r15, do_signal
+	bralid	r15, do_notify_resume
 	addk	r6, r0, r0
 
 no_intr_resched:
@@ -292,8 +291,8 @@
 
 /*
  * Debug traps are like a system call, but entered via brki r14, 0x60
- * All we need to do is send the SIGTRAP signal to current, ptrace and do_signal
- * will handle the rest
+ * All we need to do is send the SIGTRAP signal to current, ptrace and
+ * do_notify_resume will handle the rest
  */
 ENTRY(_debug_exception)
 	swi	r1, r0, PER_CPU(ENTRY_SP)	/* save the current sp */
@@ -482,12 +481,11 @@
 	beqi	r11, 1f
 	bralid	r15, schedule
 	nop
-1:	andi	r11, r19, _TIF_SIGPENDING
+1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 	beqi	r11, no_work_pending
 	addk	r5, r1, r0
-	addik	r7, r0, 1
-	bralid	r15, do_signal
-	addk	r6, r0, r0
+	bralid	r15, do_notify_resume
+	addik	r6, r0, 1
 	bri	no_work_pending
 
 ENTRY(ret_to_user)
@@ -569,10 +567,6 @@
 	brid	sys_rt_sigreturn
 	addk	r5, r1, r0
 
-sys_rt_sigsuspend_wrapper:
-	brid	sys_rt_sigsuspend
-	addk	r7, r1, r0
-
 	/* Interrupt vector table */
 	.section	.init.ivt, "ax"
 	.org 0x0
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
index 66e34a3..daff9e5 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -430,13 +430,12 @@
 5:	/* get thread info from current task*/
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
 	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING;
+	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
 	beqi	r11, 1f;		/* Signals to handle, handle them */
 
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
-	addi	r7, r0, 1;		/* Arg 3: int in_syscall */
-	bralid	r15, do_signal;	/* Handle any signals */
-	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */
+	bralid	r15, do_notify_resume;	/* Handle any signals */
+	addi	r6, r0, 1;		/* Arg 2: int in_syscall */
 
 /* Finally, return to user state.  */
 1:	set_bip;			/*  Ints masked for state restore */
@@ -622,7 +621,7 @@
 	/* Maybe handle a signal */
 5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
 	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING;
+	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
 	beqi	r11, 1f;		/* Signals to handle, handle them */
 
 	/*
@@ -635,11 +634,10 @@
 	 * traps), but signal handlers may want to examine or change the
 	 * complete register state.  Here we save anything not saved by
 	 * the normal entry sequence, so that it may be safely restored
-	 * (in a possibly modified form) after do_signal returns. */
+	 * (in a possibly modified form) after do_notify_resume returns. */
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
-	addi	r7, r0, 0;		/* Arg 3: int in_syscall */
-	bralid	r15, do_signal;	/* Handle any signals */
-	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */
+	bralid	r15, do_notify_resume;	/* Handle any signals */
+	addi	r6, r0, 0;		/* Arg 2: int in_syscall */
 
 /* Finally, return to user state.  */
 1:	set_bip;			/* Ints masked for state restore */
@@ -732,13 +730,12 @@
     /* Maybe handle a signal */
 5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
 	lwi	r11, r11, TI_FLAGS; /* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING;
+	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
 	beqid	r11, no_intr_resched
 /* Handle a signal return; Pending signals should be in r18. */
-	addi	r7, r0, 0; /* Arg 3: int in_syscall */
 	addik	r5, r1, 0; /* Arg 1: struct pt_regs *regs */
-	bralid	r15, do_signal;	/* Handle any signals */
-	add	r6, r0, r0; /* Arg 2: sigset_t *oldset */
+	bralid	r15, do_notify_resume;	/* Handle any signals */
+	addi	r6, r0, 0; /* Arg 2: int in_syscall */
 
 /* Finally, return to user state. */
 no_intr_resched:
@@ -869,13 +866,12 @@
 	/* Maybe handle a signal */
 5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
 	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING;
+	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
 	beqi	r11, 1f;		/* Signals to handle, handle them */
 
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
-	addi  r7, r0, 0;	/* Arg 3: int in_syscall */
-	bralid	r15, do_signal;	/* Handle any signals */
-	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */
+	bralid	r15, do_notify_resume;	/* Handle any signals */
+	addi  r6, r0, 0;	/* Arg 2: int in_syscall */
 
 /* Finally, return to user state.  */
 1:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index 5996711..7f4c7be 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -31,6 +31,7 @@
 #include <linux/personality.h>
 #include <linux/percpu.h>
 #include <linux/linkage.h>
+#include <linux/tracehook.h>
 #include <asm/entry.h>
 #include <asm/ucontext.h>
 #include <linux/uaccess.h>
@@ -42,8 +43,6 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
-
 asmlinkage long
 sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
 		struct pt_regs *regs)
@@ -98,6 +97,9 @@
 	sigset_t set;
 	int rval;
 
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 
@@ -105,10 +107,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
 		goto badframe;
@@ -169,7 +168,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;
@@ -267,12 +266,11 @@
 		current->comm, current->pid, frame, regs->pc);
 #endif
 
-	return;
+	return 0;
 
 give_sigsegv:
-	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-	force_sig(SIGSEGV, current);
+	force_sigsegv(sig, current);
+	return -EFAULT;
 }
 
 /* Handle restarting system calls */
@@ -316,24 +314,20 @@
 handle_signal(unsigned long sig, struct k_sigaction *ka,
 		siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
+	int ret;
+
 	/* Set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(sig, ka, info, oldset, regs);
+		ret = setup_rt_frame(sig, ka, info, oldset, regs);
 	else
-		setup_rt_frame(sig, ka, NULL, oldset, regs);
+		ret = setup_rt_frame(sig, ka, NULL, oldset, regs);
 
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
+	if (ret)
+		return ret;
 
-	if (!(ka->sa.sa_flags & SA_NODEFER)) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked,
-				&current->blocked, &ka->sa.sa_mask);
-		sigaddset(&current->blocked, sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
-	return 1;
+	block_sigmask(ka, sig);
+
+	return 0;
 }
 
 /*
@@ -345,24 +339,17 @@
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
+static void do_signal(struct pt_regs *regs, int in_syscall)
 {
 	siginfo_t info;
 	int signr;
 	struct k_sigaction ka;
+	sigset_t *oldset;
 #ifdef DEBUG_SIG
-	printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall);
+	printk(KERN_INFO "do signal: %p %d\n", regs, in_syscall);
 	printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1,
 			regs->r12, current_thread_info()->flags);
 #endif
-	/*
-	 * We want the common case to go fast, which
-	 * is why we may in certain cases get here from
-	 * kernel mode. Just return without doing anything
-	 * if so.
-	 */
-	if (kernel_mode(regs))
-		return 1;
 
 	if (current_thread_info()->status & TS_RESTORE_SIGMASK)
 		oldset = &current->saved_sigmask;
@@ -374,7 +361,7 @@
 		/* Whee! Actually deliver the signal. */
 		if (in_syscall)
 			handle_restart(regs, &ka, 1);
-		if (handle_signal(signr, &ka, &info, oldset, regs)) {
+		if (!handle_signal(signr, &ka, &info, oldset, regs)) {
 			/*
 			 * A signal was successfully delivered; the saved
 			 * sigmask will have been stored in the signal frame,
@@ -384,7 +371,7 @@
 			current_thread_info()->status &=
 			    ~TS_RESTORE_SIGMASK;
 		}
-		return 1;
+		return;
 	}
 
 	if (in_syscall)
@@ -398,7 +385,25 @@
 		current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
 		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 	}
+}
 
-	/* Did we come from a system call? */
-	return 0;
+void do_notify_resume(struct pt_regs *regs, int in_syscall)
+{
+	/*
+	 * We want the common case to go fast, which
+	 * is why we may in certain cases get here from
+	 * kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if (kernel_mode(regs))
+		return;
+
+	if (test_thread_flag(TIF_SIGPENDING))
+		do_signal(regs, in_syscall);
+
+	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+		tracehook_notify_resume(regs);
+		if (current->replacement_session_keyring)
+			key_replace_session_keyring();
+	}
 }
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 186fc8c..85aad03 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -30,6 +30,7 @@
 	select HAVE_MEMBLOCK_NODE_MAP
 	select ARCH_DISCARD_MEMBLOCK
 	select GENERIC_SMP_IDLE_THREAD
+	select BUILDTIME_EXTABLE_SORT
 
 menu "Machine selection"
 
@@ -1002,12 +1003,12 @@
 	bool
 
 #
-# Endianess selection.  Sufficiently obscure so many users don't know what to
+# Endianness selection.  Sufficiently obscure so many users don't know what to
 # answer,so we try hard to limit the available choices.  Also the use of a
 # choice statement should be more obvious to the user.
 #
 choice
-	prompt "Endianess selection"
+	prompt "Endianness selection"
 	help
 	  Some MIPS machines can be configured for either little or big endian
 	  byte order. These modes require different kernels and a different
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 83ed00a..5a43aa0 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -57,7 +57,7 @@
 	  options.
 
 config CMDLINE_OVERRIDE
-	bool "Built-in command line overrides firware arguments"
+	bool "Built-in command line overrides firmware arguments"
 	default n
 	depends on CMDLINE_BOOL
 	help
diff --git a/arch/mips/include/asm/mach-ip27/topology.h b/arch/mips/include/asm/mach-ip27/topology.h
index 1b1a7d1..b2cf641 100644
--- a/arch/mips/include/asm/mach-ip27/topology.h
+++ b/arch/mips/include/asm/mach-ip27/topology.h
@@ -36,23 +36,6 @@
 
 #define node_distance(from, to)	(__node_distances[(from)][(to)])
 
-/* sched_domains SD_NODE_INIT for SGI IP27 machines */
-#define SD_NODE_INIT (struct sched_domain) {		\
-	.parent			= NULL,			\
-	.child			= NULL,			\
-	.groups			= NULL,			\
-	.min_interval		= 8,			\
-	.max_interval		= 32,			\
-	.busy_factor		= 32,			\
-	.imbalance_pct		= 125,			\
-	.cache_nice_tries	= 1,			\
-	.flags			= SD_LOAD_BALANCE |	\
-				  SD_BALANCE_EXEC,	\
-	.last_balance		= jiffies,		\
-	.balance_interval	= 1,			\
-	.nr_balance_failed	= 0,			\
-}
-
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_MACH_TOPOLOGY_H */
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 20e9dcf..5e33fab 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -310,9 +310,6 @@
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while(0)
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c
index 7f3376b..6ded9bd 100644
--- a/arch/mips/kernel/mips-mt.c
+++ b/arch/mips/kernel/mips-mt.c
@@ -209,7 +209,7 @@
 	unsigned int nconfig7 = oconfig7;
 
 	if (mt_opt_norps) {
-		printk("\"norps\" option deprectated: use \"rpsctl=\"\n");
+		printk("\"norps\" option deprecated: use \"rpsctl=\"\n");
 	}
 	if (mt_opt_rpsctl >= 0) {
 		printk("34K return prediction stack override set to %d.\n",
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
index 811084f..ab73fa2 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -1325,7 +1325,7 @@
 
 	regs = get_irq_regs();
 
-	perf_sample_data_init(&data, 0);
+	perf_sample_data_init(&data, 0, 0);
 
 	switch (counters) {
 #define HANDLE_COUNTER(n)						\
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index d5a338a..17f6ee3 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -255,15 +255,7 @@
 	uset = (sigset_t __user *) regs.regs[4];
 	if (copy_from_user(&newset, uset, sizeof(sigset_t)))
 		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	current->saved_sigmask = current->blocked;
-	set_current_blocked(&newset);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	return sigsuspend(&newset);
 }
 #endif
 
@@ -281,15 +273,7 @@
 	unewset = (sigset_t __user *) regs.regs[4];
 	if (copy_from_user(&newset, unewset, sizeof(newset)))
 		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	current->saved_sigmask = current->blocked;
-	set_current_blocked(&newset);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	return sigsuspend(&newset);
 }
 
 #ifdef CONFIG_TRAD_SIGNALS
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index ac3b8d8..b4fe2ea 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -288,15 +288,7 @@
 	uset = (compat_sigset_t __user *) regs.regs[4];
 	if (get_sigset(&newset, uset))
 		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	current->saved_sigmask = current->blocked;
-	set_current_blocked(&newset);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	return sigsuspend(&newset);
 }
 
 asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
@@ -313,15 +305,7 @@
 	uset = (compat_sigset_t __user *) regs.regs[4];
 	if (get_sigset(&newset, uset))
 		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	current->saved_sigmask = current->blocked;
-	set_current_blocked(&newset);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	return sigsuspend(&newset);
 }
 
 SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index 86eb4b0..63ffac9 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -91,15 +91,7 @@
 	if (copy_from_user(&uset, unewset, sizeof(uset)))
 		return -EFAULT;
 	sigset_from_compat(&newset, &uset);
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	current->saved_sigmask = current->blocked;
-	set_current_blocked(&newset);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	return sigsuspend(&newset);
 }
 
 asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c
index d2fa98f..c429a5b 100644
--- a/arch/mips/lantiq/xway/gpio.c
+++ b/arch/mips/lantiq/xway/gpio.c
@@ -188,7 +188,7 @@
 	int ret = platform_driver_register(&ltq_gpio_driver);
 
 	if (ret)
-		pr_info("ltq_gpio : Error registering platfom driver!");
+		pr_info("ltq_gpio : Error registering platform driver!");
 	return ret;
 }
 
diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c
index b91c7f1..aae1717 100644
--- a/arch/mips/lantiq/xway/gpio_ebu.c
+++ b/arch/mips/lantiq/xway/gpio_ebu.c
@@ -119,7 +119,7 @@
 	int ret = platform_driver_register(&ltq_ebu_driver);
 
 	if (ret)
-		pr_info("ltq_ebu : Error registering platfom driver!");
+		pr_info("ltq_ebu : Error registering platform driver!");
 	return ret;
 }
 
diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c
index ff9991c..fd07d87 100644
--- a/arch/mips/lantiq/xway/gpio_stp.c
+++ b/arch/mips/lantiq/xway/gpio_stp.c
@@ -150,7 +150,7 @@
 	int ret = platform_driver_register(&ltq_stp_driver);
 
 	if (ret)
-		pr_info("ltq_stp: error registering platfom driver");
+		pr_info("ltq_stp: error registering platform driver");
 	return ret;
 }
 
diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c
index ed3b3d317..cdb1417 100644
--- a/arch/mips/sni/pcimt.c
+++ b/arch/mips/sni/pcimt.c
@@ -29,7 +29,7 @@
 
 	scsiz = cacheconf & 7;
 	if (scsiz == 0) {
-		printk("Second level cache is deactived.\n");
+		printk("Second level cache is deactivated.\n");
 		return;
 	}
 	if (scsiz >= 6) {
diff --git a/arch/mn10300/include/asm/processor.h b/arch/mn10300/include/asm/processor.h
index f7b3c9a..247928c 100644
--- a/arch/mn10300/include/asm/processor.h
+++ b/arch/mn10300/include/asm/processor.h
@@ -139,9 +139,6 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-extern void prepare_to_copy(struct task_struct *tsk);
-
 /*
  * create a kernel thread without removing it from tasklists
  */
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index 14707f2..7dab0cd 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -208,12 +208,14 @@
 }
 
 /*
- * this gets called before we allocate a new thread and copy the current task
- * into it so that we can store lazy state into memory
+ * this gets called so that we can store lazy state into memory and copy the
+ * current task into the new thread.
  */
-void prepare_to_copy(struct task_struct *tsk)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-	unlazy_fpu(tsk);
+	unlazy_fpu(src);
+	*dst = *src;
+	return 0;
 }
 
 /*
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
index 690f4e9..890cf91 100644
--- a/arch/mn10300/kernel/signal.c
+++ b/arch/mn10300/kernel/signal.c
@@ -38,17 +38,9 @@
  */
 asmlinkage long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	sigset_t blocked;
+	siginitset(&blocked, mask);
+	return sigsuspend(&blocked);
 }
 
 /*
@@ -172,10 +164,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(current_frame(), &frame->sc, &d0))
 		goto badframe;
@@ -203,10 +192,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0))
 		goto badframe;
@@ -476,15 +462,8 @@
 	else
 		ret = setup_frame(sig, ka, oldset, regs);
 
-	if (ret == 0) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked,
-			  &ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	if (ret == 0)
+		block_sigmask(ka, sig);
 
 	return ret;
 }
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 7589051..297bd38 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -142,7 +142,7 @@
 	bool "Check for kernel stack overflow"
 	default y
 	help
-	  Make extra checks for space avaliable on stack in some
+	  Make extra checks for space available on stack in some
           critical functions. This will cause kernel to run a bit slower,
 	  but will catch most of kernel stack overruns and exit gracefuly.
 
diff --git a/arch/openrisc/include/asm/processor.h b/arch/openrisc/include/asm/processor.h
index f7516fa..30462f1 100644
--- a/arch/openrisc/include/asm/processor.h
+++ b/arch/openrisc/include/asm/processor.h
@@ -72,10 +72,6 @@
 #define task_pt_regs(task) user_regs(task_thread_info(task))
 #define current_regs() user_regs(current_thread_info())
 
-extern inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
 #define INIT_SP         (sizeof(init_stack) + (unsigned long) &init_stack)
 
 #define INIT_THREAD  { }
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index 0dc8543..c71eb6c 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -159,8 +159,8 @@
 	tmp.st_ino = stat->ino;
 	tmp.st_mode = stat->mode;
 	tmp.st_nlink = stat->nlink;
-	tmp.st_uid = stat->uid;
-	tmp.st_gid = stat->gid;
+	tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
+	tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
 	tmp.st_rdev = new_encode_dev(stat->rdev);
 	tmp.st_size = stat->size;
 	tmp.st_atime = stat->atime.tv_sec;
diff --git a/arch/parisc/include/asm/kbdleds.h b/arch/parisc/include/asm/kbdleds.h
new file mode 100644
index 0000000..2e2e75a
--- /dev/null
+++ b/arch/parisc/include/asm/kbdleds.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_PARISC_KBDLEDS_H
+#define _ASM_PARISC_KBDLEDS_H
+
+/*
+ * On HIL keyboards of PARISC machines there is no NumLock key and
+ * everyone expects the keypad to be used for numbers. That's why
+ * we can safely turn on the NUMLOCK bit.
+ */
+
+static inline int kbd_defleds(void)
+{
+#if defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)
+	return 1 << VC_NUMLOCK;
+#else
+	return 0;
+#endif
+}
+
+#endif /* _ASM_PARISC_KBDLEDS_H */
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index acdf4ca..0e8b7b8 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -328,9 +328,6 @@
 extern void release_thread(struct task_struct *);
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm);
 
 extern unsigned long get_wchan(struct task_struct *p);
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 12c1ed3..4b9cb0d 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -109,6 +109,7 @@
 		sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
 #endif
 
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
 	/* Unwind the user stack to get the rt_sigframe structure. */
 	frame = (struct rt_sigframe __user *)
@@ -131,10 +132,7 @@
 	}
 		
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	/* Good thing we saved the old gr[30], eh? */
 #ifdef CONFIG_64BIT
@@ -454,12 +452,7 @@
 	if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
 		return 0;
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked,sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	block_sigmask(ka, sig);
 
 	tracehook_signal_handler(sig, info, ka, regs, 
 		test_thread_flag(TIF_SINGLESTEP) ||
@@ -474,8 +467,6 @@
 	/* Check the return code */
 	switch (regs->gr[28]) {
 	case -ERESTART_RESTARTBLOCK:
-		current_thread_info()->restart_block.fn =
-			do_no_restart_syscall;
 	case -ERESTARTNOHAND:
 		DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
 		regs->gr[28] = -EINTR;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8a01098..0a947bd 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -350,7 +350,7 @@
 
 config KEXEC
 	bool "kexec system call (EXPERIMENTAL)"
-	depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !PPC_47x)) && EXPERIMENTAL
+	depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) && EXPERIMENTAL
 	help
 	  kexec is a system call that implements the ability to shutdown your
 	  current kernel, and to start another kernel.  It is like a reboot
@@ -367,7 +367,7 @@
 
 config CRASH_DUMP
 	bool "Build a kdump crash kernel"
-	depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP && !PPC_47x)
+	depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP)
 	select RELOCATABLE if PPC64 || 44x
 	select DYNAMIC_MEMSTART if FSL_BOOKE
 	help
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 6524c6e..950d1f7 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -69,6 +69,16 @@
 
 CFLAGS-$(CONFIG_PPC64)	:= -mminimal-toc -mtraceback=no -mcall-aixdesc
 CFLAGS-$(CONFIG_PPC32)	:= -ffixed-r2 -mmultiple
+
+CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power7,-mtune=power4)
+CFLAGS-$(CONFIG_CELL_CPU) += $(call cc-option,-mcpu=cell)
+CFLAGS-$(CONFIG_POWER4_CPU) += $(call cc-option,-mcpu=power4)
+CFLAGS-$(CONFIG_POWER5_CPU) += $(call cc-option,-mcpu=power5)
+CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6)
+CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7)
+
+CFLAGS-$(CONFIG_TUNE_CELL) += $(call cc-option,-mtune=cell)
+
 KBUILD_CPPFLAGS	+= -Iarch/$(ARCH)
 KBUILD_AFLAGS	+= -Iarch/$(ARCH)
 KBUILD_CFLAGS	+= -msoft-float -pipe -Iarch/$(ARCH) $(CFLAGS-y)
@@ -76,32 +86,11 @@
 
 CHECKFLAGS	+= -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
 
-ifeq ($(CONFIG_PPC64),y)
-GCC_BROKEN_VEC	:= $(call cc-ifversion, -lt, 0400, y)
-
-ifeq ($(CONFIG_POWER4_ONLY),y)
-ifeq ($(CONFIG_ALTIVEC),y)
-ifeq ($(GCC_BROKEN_VEC),y)
-	KBUILD_CFLAGS += $(call cc-option,-mcpu=970)
-else
-	KBUILD_CFLAGS += $(call cc-option,-mcpu=power4)
-endif
-else
-	KBUILD_CFLAGS += $(call cc-option,-mcpu=power4)
-endif
-else
-	KBUILD_CFLAGS += $(call cc-option,-mtune=power4)
-endif
-endif
-
 KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
 
-ifeq ($(CONFIG_TUNE_CELL),y)
-	KBUILD_CFLAGS += $(call cc-option,-mtune=cell)
-endif
-
-# No AltiVec instruction when building kernel
+# No AltiVec or VSX instructions when building kernel
 KBUILD_CFLAGS += $(call cc-option,-mno-altivec)
+KBUILD_CFLAGS += $(call cc-option,-mno-vsx)
 
 # No SPE instruction when building kernel
 # (We use all available options to help semi-broken compilers)
@@ -160,6 +149,7 @@
 core-$(CONFIG_PERF_EVENTS)	+= arch/powerpc/perf/
 
 drivers-$(CONFIG_OPROFILE)	+= arch/powerpc/oprofile/
+drivers-$(CONFIG_CRYPTO_DEV_NX) += drivers/crypto/nx/
 
 # Default to zImage, override when needed
 all: zImage
@@ -234,10 +224,11 @@
 # Use the file '.tmp_gas_check' for binutils tests, as gas won't output
 # to stdout and these checks are run even on install targets.
 TOUT	:= .tmp_gas_check
-# Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later for altivec
-# instructions.
-# gcc-3.4 and binutils-2.14 are a fatal combination.
 
+# Check gcc and binutils versions:
+# - gcc-3.4 and binutils-2.14 are a fatal combination
+# - Require gcc 4.0 or above on 64-bit
+# - gcc-4.2.0 has issues compiling modules on 64-bit
 checkbin:
 	@if test "$(call cc-version)" = "0304" ; then \
 		if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \
@@ -247,6 +238,12 @@
 			false; \
 		fi ; \
 	fi
+	@if test "$(call cc-version)" -lt "0400" \
+	    && test "x${CONFIG_PPC64}" = "xy" ; then \
+                echo -n "Sorry, GCC v4.0 or above is required to build " ; \
+                echo "the 64-bit powerpc kernel." ; \
+                false ; \
+        fi
 	@if test "$(call cc-fullversion)" = "040200" \
 	    && test "x${CONFIG_MODULES}${CONFIG_PPC64}" = "xyy" ; then \
 		echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \
diff --git a/arch/powerpc/boot/dts/bluestone.dts b/arch/powerpc/boot/dts/bluestone.dts
index 7bda373..9d4917a 100644
--- a/arch/powerpc/boot/dts/bluestone.dts
+++ b/arch/powerpc/boot/dts/bluestone.dts
@@ -373,5 +373,30 @@
 				0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */
 				0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>;
 		};
+
+		MSI: ppc4xx-msi@C10000000 {
+			compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+			reg = < 0xC 0x10000000 0x100
+				0xC 0x10000000 0x100>;
+			sdr-base = <0x36C>;
+			msi-data = <0x00004440>;
+			msi-mask = <0x0000ffe0>;
+			interrupts =<0 1 2 3 4 5 6 7>;
+			interrupt-parent = <&MSI>;
+			#interrupt-cells = <1>;
+			#address-cells = <0>;
+			#size-cells = <0>;
+			msi-available-ranges = <0x0 0x100>;
+			interrupt-map = <
+				0 &UIC3 0x18 1
+				1 &UIC3 0x19 1
+				2 &UIC3 0x1A 1
+				3 &UIC3 0x1B 1
+				4 &UIC3 0x1C 1
+				5 &UIC3 0x1D 1
+				6 &UIC3 0x1E 1
+				7 &UIC3 0x1F 1
+			>;
+		};
 	};
 };
diff --git a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
index 0db9ba0..c09598b 100644
--- a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
@@ -100,6 +100,7 @@
 CONFIG_SND_PCM_OSS=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
 CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_CMOS=y
 CONFIG_EXT2_FS=y
diff --git a/arch/powerpc/configs/chroma_defconfig b/arch/powerpc/configs/chroma_defconfig
index f104ccd..b1f9597 100644
--- a/arch/powerpc/configs/chroma_defconfig
+++ b/arch/powerpc/configs/chroma_defconfig
@@ -32,7 +32,7 @@
 CONFIG_INITRAMFS_COMPRESSION_GZIP=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 1196c34..07b7f2a 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -1,5 +1,4 @@
 CONFIG_PPC64=y
-CONFIG_POWER4_ONLY=y
 CONFIG_ALTIVEC=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=4
diff --git a/arch/powerpc/configs/gamecube_defconfig b/arch/powerpc/configs/gamecube_defconfig
index e74d3a4..9ef2cc1 100644
--- a/arch/powerpc/configs/gamecube_defconfig
+++ b/arch/powerpc/configs/gamecube_defconfig
@@ -8,7 +8,7 @@
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_ELF_CORE is not set
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig
index 2244d37..02ac96b 100644
--- a/arch/powerpc/configs/maple_defconfig
+++ b/arch/powerpc/configs/maple_defconfig
@@ -1,5 +1,4 @@
 CONFIG_PPC64=y
-CONFIG_POWER4_ONLY=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=4
 CONFIG_EXPERIMENTAL=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index d6b6df5..62bb723 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -141,6 +141,7 @@
 # CONFIG_SND_PPC is not set
 # CONFIG_SND_USB is not set
 CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 5b0e292..d182842 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -143,6 +143,7 @@
 # CONFIG_SND_PPC is not set
 # CONFIG_SND_USB is not set
 CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig
index f4deb0b..840a2c2 100644
--- a/arch/powerpc/configs/pasemi_defconfig
+++ b/arch/powerpc/configs/pasemi_defconfig
@@ -1,5 +1,4 @@
 CONFIG_PPC64=y
-CONFIG_POWER4_ONLY=y
 CONFIG_ALTIVEC=y
 # CONFIG_VIRT_CPU_ACCOUNTING is not set
 CONFIG_SMP=y
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index ded8678..c2f4b4a 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -6,7 +6,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
-CONFIG_SPARSE_IRQ=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_EMBEDDED=y
@@ -25,7 +24,6 @@
 CONFIG_PS3_ROM=y
 CONFIG_PS3_FLASH=y
 CONFIG_PS3_VRAM=m
-CONFIG_PS3_LPM=m
 # CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
 CONFIG_HIGH_RES_TIMERS=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
@@ -53,8 +51,6 @@
 # CONFIG_INET_DIAG is not set
 CONFIG_IPV6=y
 CONFIG_BT=m
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
@@ -63,7 +59,6 @@
 CONFIG_BT_HIDP=m
 CONFIG_BT_HCIBTUSB=m
 CONFIG_CFG80211=m
-# CONFIG_WIRELESS_EXT_SYSFS is not set
 CONFIG_MAC80211=m
 CONFIG_MAC80211_RC_PID=y
 # CONFIG_MAC80211_RC_MINSTREL is not set
@@ -181,7 +176,6 @@
 CONFIG_DEBUG_WRITECOUNT=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_LIST=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_STACKOVERFLOW=y
 CONFIG_CRYPTO_CCM=m
diff --git a/arch/powerpc/configs/wii_defconfig b/arch/powerpc/configs/wii_defconfig
index 175295f..1e2b7d0 100644
--- a/arch/powerpc/configs/wii_defconfig
+++ b/arch/powerpc/configs/wii_defconfig
@@ -9,7 +9,7 @@
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_ELF_CORE is not set
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h
index decad95..5d7fbe1 100644
--- a/arch/powerpc/include/asm/asm-compat.h
+++ b/arch/powerpc/include/asm/asm-compat.h
@@ -29,18 +29,9 @@
 #define PPC_LLARX(t, a, b, eh)	PPC_LDARX(t, a, b, eh)
 #define PPC_STLCX	stringify_in_c(stdcx.)
 #define PPC_CNTLZL	stringify_in_c(cntlzd)
+#define PPC_MTOCRF(FXM, RS) MTOCRF((FXM), (RS))
 #define PPC_LR_STKOFF	16
 #define PPC_MIN_STKFRM	112
-
-/* Move to CR, single-entry optimized version. Only available
- * on POWER4 and later.
- */
-#ifdef CONFIG_POWER4_ONLY
-#define PPC_MTOCRF	stringify_in_c(mtocrf)
-#else
-#define PPC_MTOCRF	stringify_in_c(mtcrf)
-#endif
-
 #else /* 32-bit */
 
 /* operations for longs and pointers */
diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h
index ce516e5..ac3eedb 100644
--- a/arch/powerpc/include/asm/cputhreads.h
+++ b/arch/powerpc/include/asm/cputhreads.h
@@ -9,7 +9,7 @@
  * Note: This implementation is limited to a power of 2 number of
  * threads per core and the same number for each core in the system
  * (though it would work if some processors had less threads as long
- * as the CPU numbers are still allocated, just not brought offline).
+ * as the CPU numbers are still allocated, just not brought online).
  *
  * However, the API allows for a different implementation in the future
  * if needed, as long as you only use the functions and not the variables
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 1c324ff..6122523 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -77,8 +77,27 @@
 #define H_MR_CONDITION  -43
 #define H_NOT_ENOUGH_RESOURCES -44
 #define H_R_STATE       -45
-#define H_RESCINDEND    -46
-#define H_MULTI_THREADS_ACTIVE -9005
+#define H_RESCINDED     -46
+#define H_P2		-55
+#define H_P3		-56
+#define H_P4		-57
+#define H_P5		-58
+#define H_P6		-59
+#define H_P7		-60
+#define H_P8		-61
+#define H_P9		-62
+#define H_TOO_BIG	-64
+#define H_OVERLAP	-68
+#define H_INTERRUPT	-69
+#define H_BAD_DATA	-70
+#define H_NOT_ACTIVE	-71
+#define H_SG_LIST	-72
+#define H_OP_MODE	-73
+#define H_COP_HW	-74
+#define H_UNSUPPORTED_FLAG_START	-256
+#define H_UNSUPPORTED_FLAG_END		-511
+#define H_MULTI_THREADS_ACTIVE	-9005
+#define H_OUTSTANDING_COP_OPS	-9006
 
 
 /* Long Busy is a condition that can be returned by the firmware
@@ -240,6 +259,8 @@
 #define H_GET_MPP		0x2D4
 #define H_HOME_NODE_ASSOCIATIVITY 0x2EC
 #define H_BEST_ENERGY		0x2F4
+#define H_RANDOM		0x300
+#define H_COP			0x304
 #define H_GET_MPP_X		0x314
 #define MAX_HCALL_OPCODE	H_GET_MPP_X
 
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index a76254a..531fe0c 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -20,18 +20,16 @@
 #define _ASM_POWERPC_LPPACA_H
 #ifdef __KERNEL__
 
-/* These definitions relate to hypervisors that only exist when using
+/*
+ * These definitions relate to hypervisors that only exist when using
  * a server type processor
  */
 #ifdef CONFIG_PPC_BOOK3S
 
-//=============================================================================
-//
-//	This control block contains the data that is shared between the
-//	hypervisor (PLIC) and the OS.
-//
-//
-//----------------------------------------------------------------------------
+/*
+ * This control block contains the data that is shared between the
+ * hypervisor and the OS.
+ */
 #include <linux/cache.h>
 #include <linux/threads.h>
 #include <asm/types.h>
@@ -43,123 +41,65 @@
  */
 #define NR_LPPACAS	1
 
-
-/* The Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
- * alignment is sufficient to prevent this */
+/*
+ * The Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
+ * alignment is sufficient to prevent this
+ */
 struct lppaca {
-//=============================================================================
-// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
-// NOTE: The xDynXyz fields are fields that will be dynamically changed by
-// PLIC when preparing to bring a processor online or when dispatching a
-// virtual processor!
-//=============================================================================
-	u32	desc;			// Eye catcher 0xD397D781	x00-x03
-	u16	size;			// Size of this struct		x04-x05
-	u16	reserved1;		// Reserved			x06-x07
-	u16	reserved2:14;		// Reserved			x08-x09
-	u8	shared_proc:1;		// Shared processor indicator	...
-	u8	secondary_thread:1;	// Secondary thread indicator	...
-	volatile u8 dyn_proc_status:8;	// Dynamic Status of this proc	x0A-x0A
-	u8	secondary_thread_count;	// Secondary thread count	x0B-x0B
-	volatile u16 dyn_hv_phys_proc_index;// Dynamic HV Physical Proc Index0C-x0D
-	volatile u16 dyn_hv_log_proc_index;// Dynamic HV Logical Proc Indexx0E-x0F
-	u32	decr_val;   		// Value for Decr programming 	x10-x13
-	u32	pmc_val;       		// Value for PMC regs         	x14-x17
-	volatile u32 dyn_hw_node_id;	// Dynamic Hardware Node id	x18-x1B
-	volatile u32 dyn_hw_proc_id;	// Dynamic Hardware Proc Id	x1C-x1F
-	volatile u32 dyn_pir;		// Dynamic ProcIdReg value	x20-x23
-	u32	dsei_data;           	// DSEI data                  	x24-x27
-	u64	sprg3;               	// SPRG3 value                	x28-x2F
-	u8	reserved3[40];		// Reserved			x30-x57
-	volatile u8 vphn_assoc_counts[8]; // Virtual processor home node
-					// associativity change counters x58-x5F
-	u8	reserved4[32];		// Reserved			x60-x7F
+	/* cacheline 1 contains read-only data */
 
-//=============================================================================
-// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
-//=============================================================================
-	// This Dword contains a byte for each type of interrupt that can occur.
-	// The IPI is a count while the others are just a binary 1 or 0.
-	union {
-		u64	any_int;
-		struct {
-			u16	reserved;	// Reserved - cleared by #mpasmbl
-			u8	xirr_int;	// Indicates xXirrValue is valid or Immed IO
-			u8	ipi_cnt;	// IPI Count
-			u8	decr_int;	// DECR interrupt occurred
-			u8	pdc_int;	// PDC interrupt occurred
-			u8	quantum_int;	// Interrupt quantum reached
-			u8	old_plic_deferred_ext_int;	// Old PLIC has a deferred XIRR pending
-		} fields;
-	} int_dword;
+	u32	desc;			/* Eye catcher 0xD397D781 */
+	u16	size;			/* Size of this struct */
+	u16	reserved1;
+	u16	reserved2:14;
+	u8	shared_proc:1;		/* Shared processor indicator */
+	u8	secondary_thread:1;	/* Secondary thread indicator */
+	u8	reserved3[14];
+	volatile u32 dyn_hw_node_id;	/* Dynamic hardware node id */
+	volatile u32 dyn_hw_proc_id;	/* Dynamic hardware proc id */
+	u8	reserved4[56];
+	volatile u8 vphn_assoc_counts[8]; /* Virtual processor home node */
+					  /* associativity change counters */
+	u8	reserved5[32];
 
-	// Whenever any fields in this Dword are set then PLIC will defer the
-	// processing of external interrupts.  Note that PLIC will store the
-	// XIRR directly into the xXirrValue field so that another XIRR will
-	// not be presented until this one clears.  The layout of the low
-	// 4-bytes of this Dword is up to SLIC - PLIC just checks whether the
-	// entire Dword is zero or not.  A non-zero value in the low order
-	// 2-bytes will result in SLIC being granted the highest thread
-	// priority upon return.  A 0 will return to SLIC as medium priority.
-	u64	plic_defer_ints_area;	// Entire Dword
+	/* cacheline 2 contains local read-write data */
 
-	// Used to pass the real SRR0/1 from PLIC to SLIC as well as to
-	// pass the target SRR0/1 from SLIC to PLIC on a SetAsrAndRfid.
-	u64	saved_srr0;		// Saved SRR0                   x10-x17
-	u64	saved_srr1;		// Saved SRR1                   x18-x1F
+	u8	reserved6[48];
+	u8	cede_latency_hint;
+	u8	reserved7[7];
+	u8	dtl_enable_mask;	/* Dispatch Trace Log mask */
+	u8	donate_dedicated_cpu;	/* Donate dedicated CPU cycles */
+	u8	fpregs_in_use;
+	u8	pmcregs_in_use;
+	u8	reserved8[28];
+	u64	wait_state_cycles;	/* Wait cycles for this proc */
+	u8	reserved9[28];
+	u16	slb_count;		/* # of SLBs to maintain */
+	u8	idle;			/* Indicate OS is idle */
+	u8	vmxregs_in_use;
 
-	// Used to pass parms from the OS to PLIC for SetAsrAndRfid
-	u64	saved_gpr3;		// Saved GPR3                   x20-x27
-	u64	saved_gpr4;		// Saved GPR4                   x28-x2F
-	union {
-		u64	saved_gpr5;	/* Saved GPR5               x30-x37 */
-		struct {
-			u8	cede_latency_hint;  /*			x30 */
-			u8	reserved[7];        /*		    x31-x36 */
-		} fields;
-	} gpr5_dword;
+	/* cacheline 3 is shared with other processors */
 
+	/*
+	 * This is the yield_count.  An "odd" value (low bit on) means that
+	 * the processor is yielded (either because of an OS yield or a
+	 * hypervisor preempt).  An even value implies that the processor is
+	 * currently executing.
+	 * NOTE: This value will ALWAYS be zero for dedicated processors and
+	 * will NEVER be zero for shared processors (ie, initialized to a 1).
+	 */
+	volatile u32 yield_count;
+	volatile u32 dispersion_count;	/* dispatch changed physical cpu */
+	volatile u64 cmo_faults;	/* CMO page fault count */
+	volatile u64 cmo_fault_time;	/* CMO page fault time */
+	u8	reserved10[104];
 
-	u8	dtl_enable_mask;	// Dispatch Trace Log mask	x38-x38
-	u8	donate_dedicated_cpu;	// Donate dedicated CPU cycles  x39-x39
-	u8	fpregs_in_use;		// FP regs in use               x3A-x3A
-	u8	pmcregs_in_use;		// PMC regs in use              x3B-x3B
-	volatile u32 saved_decr;	// Saved Decr Value             x3C-x3F
-	volatile u64 emulated_time_base;// Emulated TB for this thread  x40-x47
-	volatile u64 cur_plic_latency;	// Unaccounted PLIC latency     x48-x4F
-	u64	tot_plic_latency;	// Accumulated PLIC latency     x50-x57
-	u64	wait_state_cycles;	// Wait cycles for this proc    x58-x5F
-	u64	end_of_quantum;		// TB at end of quantum         x60-x67
-	u64	pdc_saved_sprg1;	// Saved SPRG1 for PMC int      x68-x6F
-	u64	pdc_saved_srr0;		// Saved SRR0 for PMC int       x70-x77
-	volatile u32 virtual_decr;	// Virtual DECR for shared procsx78-x7B
-	u16	slb_count;		// # of SLBs to maintain        x7C-x7D
-	u8	idle;			// Indicate OS is idle          x7E
-	u8	vmxregs_in_use;		// VMX registers in use         x7F
+	/* cacheline 4-5 */
 
-
-//=============================================================================
-// CACHE_LINE_3 0x0100 - 0x017F: This line is shared with other processors
-//=============================================================================
-	// This is the yield_count.  An "odd" value (low bit on) means that
-	// the processor is yielded (either because of an OS yield or a PLIC
-	// preempt).  An even value implies that the processor is currently
-	// executing.
-	// NOTE: This value will ALWAYS be zero for dedicated processors and
-	// will NEVER be zero for shared processors (ie, initialized to a 1).
-	volatile u32 yield_count;	// PLIC increments each dispatchx00-x03
-	volatile u32 dispersion_count;	// dispatch changed phys cpu    x04-x07
-	volatile u64 cmo_faults;	// CMO page fault count         x08-x0F
-	volatile u64 cmo_fault_time;	// CMO page fault time          x10-x17
-	u8	reserved7[104];		// Reserved                     x18-x7F
-
-//=============================================================================
-// CACHE_LINE_4-5 0x0180 - 0x027F Contains PMC interrupt data
-//=============================================================================
-	u32	page_ins;		// CMO Hint - # page ins by OS  x00-x03
-	u8	reserved8[148];		// Reserved                     x04-x97
-	volatile u64 dtl_idx;		// Dispatch Trace Log head idx	x98-x9F
-	u8	reserved9[96];		// Reserved                     xA0-xFF
+	u32	page_ins;		/* CMO Hint - # page ins by OS */
+	u8	reserved11[148];
+	volatile u64 dtl_idx;		/* Dispatch Trace Log head index */
+	u8	reserved12[96];
 } __attribute__((__aligned__(0x400)));
 
 extern struct lppaca lppaca[];
@@ -172,13 +112,13 @@
  * ESID is stored in the lower 64bits, then the VSID.
  */
 struct slb_shadow {
-	u32	persistent;		// Number of persistent SLBs	x00-x03
-	u32	buffer_length;		// Total shadow buffer length	x04-x07
-	u64	reserved;		// Alignment			x08-x0f
+	u32	persistent;		/* Number of persistent SLBs */
+	u32	buffer_length;		/* Total shadow buffer length */
+	u64	reserved;
 	struct	{
 		u64     esid;
 		u64	vsid;
-	} save_area[SLB_NUM_BOLTED];	//				x10-x40
+	} save_area[SLB_NUM_BOLTED];
 } ____cacheline_aligned;
 
 extern struct slb_shadow slb_shadow[];
diff --git a/arch/powerpc/include/asm/lv1call.h b/arch/powerpc/include/asm/lv1call.h
index 233f9ec..f511767 100644
--- a/arch/powerpc/include/asm/lv1call.h
+++ b/arch/powerpc/include/asm/lv1call.h
@@ -265,8 +265,8 @@
 LV1_CALL(set_spe_privilege_state_area_1_register,       3, 0,  79 )
 LV1_CALL(create_repository_node,                        6, 0,  90 )
 LV1_CALL(read_repository_node,                          5, 2,  91 )
-LV1_CALL(modify_repository_node_value,                  6, 0,  92 )
-LV1_CALL(remove_repository_node,                        4, 0,  93 )
+LV1_CALL(write_repository_node,                         6, 0,  92 )
+LV1_CALL(delete_repository_node,                        4, 0,  93 )
 LV1_CALL(read_htab_entries,                             2, 5,  95 )
 LV1_CALL(set_dabr,                                      2, 0,  96 )
 LV1_CALL(get_total_execution_time,                      2, 1, 103 )
diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h
index 23cd6cc..c07edfe 100644
--- a/arch/powerpc/include/asm/pSeries_reconfig.h
+++ b/arch/powerpc/include/asm/pSeries_reconfig.h
@@ -13,6 +13,18 @@
 #define PSERIES_RECONFIG_REMOVE		0x0002
 #define PSERIES_DRCONF_MEM_ADD		0x0003
 #define PSERIES_DRCONF_MEM_REMOVE	0x0004
+#define PSERIES_UPDATE_PROPERTY		0x0005
+
+/**
+ * pSeries_reconfig_notify - Notifier value structure for OFDT property updates
+ *
+ * @node: Device tree node which owns the property being updated
+ * @property: Updated property
+ */
+struct pSeries_reconfig_prop_update {
+	struct device_node *node;
+	struct property *property;
+};
 
 #ifdef CONFIG_PPC_PSERIES
 extern int pSeries_reconfig_notifier_register(struct notifier_block *);
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 50f73aa..1544420 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -369,7 +369,15 @@
 END_FTR_SECTION_IFCLR(CPU_FTR_601)
 #endif
 
-	
+#ifdef CONFIG_PPC64
+#define MTOCRF(FXM, RS)			\
+	BEGIN_FTR_SECTION_NESTED(848);	\
+	mtcrf	(FXM), (RS);		\
+	FTR_SECTION_ELSE_NESTED(848);	\
+	mtocrf (FXM), (RS);		\
+	ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_NOEXECUTE, 848)
+#endif
+
 /*
  * This instruction is not implemented on the PPC 603 or 601; however, on
  * the 403GCX and 405GP tlbia IS defined and tlbie is not.
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 48a26d379..55e8563 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -74,9 +74,6 @@
 void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
 void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-extern void prepare_to_copy(struct task_struct *tsk);
-
 /* Create a new kernel thread. */
 extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index 84cc784..9c21ed4 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -354,12 +354,6 @@
 #define PTRACE_GETREGS64	  22
 #define PTRACE_SETREGS64	  23
 
-/* (old) PTRACE requests with inverted arguments */
-#define PPC_PTRACE_GETREGS	0x99	/* Get GPRs 0 - 31 */
-#define PPC_PTRACE_SETREGS	0x98	/* Set GPRs 0 - 31 */
-#define PPC_PTRACE_GETFPREGS	0x97	/* Get FPRs 0 - 31 */
-#define PPC_PTRACE_SETFPREGS	0x96	/* Set FPRs 0 - 31 */
-
 /* Calls to trace a 64bit program from a 32bit program */
 #define PPC_PTRACE_PEEKTEXT_3264 0x95
 #define PPC_PTRACE_PEEKDATA_3264 0x94
diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index caf82d0..1a63202 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -21,7 +21,6 @@
 extern void enable_kernel_fp(void);
 extern void flush_fp_to_thread(struct task_struct *);
 extern void enable_kernel_altivec(void);
-extern void giveup_altivec(struct task_struct *);
 extern void load_up_altivec(struct task_struct *);
 extern int emulate_altivec(struct pt_regs *);
 extern void __giveup_vsx(struct task_struct *);
@@ -40,10 +39,15 @@
 
 #ifdef CONFIG_ALTIVEC
 extern void flush_altivec_to_thread(struct task_struct *);
+extern void giveup_altivec(struct task_struct *);
+extern void giveup_altivec_notask(void);
 #else
 static inline void flush_altivec_to_thread(struct task_struct *t)
 {
 }
+static inline void giveup_altivec(struct task_struct *t)
+{
+}
 #endif
 
 #ifdef CONFIG_VSX
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index 1a1bb00..a556ccc 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -113,7 +113,6 @@
 #define _TIF_NOERROR		(1<<TIF_NOERROR)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SYSCALL_TRACEPOINT	(1<<TIF_SYSCALL_TRACEPOINT)
-#define _TIF_RUNLATCH		(1<<TIF_RUNLATCH)
 #define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
 				 _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT)
 
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index c971858..852ed1b 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -18,12 +18,6 @@
  */
 #define RECLAIM_DISTANCE 10
 
-/*
- * Avoid creating an extra level of balancing (SD_ALLNODES) on the largest
- * POWER7 boxes which have a maximum of 32 nodes.
- */
-#define SD_NODES_PER_DOMAIN 32
-
 #include <asm/mmzone.h>
 
 static inline int cpu_to_node(int cpu)
@@ -51,36 +45,6 @@
 				 cpu_all_mask :				\
 				 cpumask_of_node(pcibus_to_node(bus)))
 
-/* sched_domains SD_NODE_INIT for PPC64 machines */
-#define SD_NODE_INIT (struct sched_domain) {				\
-	.min_interval		= 8,					\
-	.max_interval		= 32,					\
-	.busy_factor		= 32,					\
-	.imbalance_pct		= 125,					\
-	.cache_nice_tries	= 1,					\
-	.busy_idx		= 3,					\
-	.idle_idx		= 1,					\
-	.newidle_idx		= 0,					\
-	.wake_idx		= 0,					\
-	.forkexec_idx		= 0,					\
-									\
-	.flags			= 1*SD_LOAD_BALANCE			\
-				| 0*SD_BALANCE_NEWIDLE			\
-				| 1*SD_BALANCE_EXEC			\
-				| 1*SD_BALANCE_FORK			\
-				| 0*SD_BALANCE_WAKE			\
-				| 1*SD_WAKE_AFFINE			\
-				| 0*SD_PREFER_LOCAL			\
-				| 0*SD_SHARE_CPUPOWER			\
-				| 0*SD_POWERSAVINGS_BALANCE		\
-				| 0*SD_SHARE_PKG_RESOURCES		\
-				| 1*SD_SERIALIZE			\
-				| 0*SD_PREFER_SIBLING			\
-				,					\
-	.last_balance		= jiffies,				\
-	.balance_interval	= 1,					\
-}
-
 extern int __node_distance(int, int);
 #define node_distance(a, b) __node_distance(a, b)
 
diff --git a/arch/powerpc/include/asm/vio.h b/arch/powerpc/include/asm/vio.h
index 6bfd5ff..b19adf7 100644
--- a/arch/powerpc/include/asm/vio.h
+++ b/arch/powerpc/include/asm/vio.h
@@ -46,6 +46,48 @@
 
 struct iommu_table;
 
+/*
+ * Platform Facilities Option (PFO)-specific data
+ */
+
+/* Starting unit address for PFO devices on the VIO BUS */
+#define VIO_BASE_PFO_UA	0x50000000
+
+/**
+ * vio_pfo_op - PFO operation parameters
+ *
+ * @flags: h_call subfunctions and modifiers
+ * @in: Input data block logical real address
+ * @inlen: If non-negative, the length of the input data block.  If negative,
+ *	the length of the input data descriptor list in bytes.
+ * @out: Output data block logical real address
+ * @outlen: If non-negative, the length of the input data block.  If negative,
+ *	the length of the input data descriptor list in bytes.
+ * @csbcpb: Logical real address of the 4k naturally-aligned storage block
+ *	containing the CSB & optional FC field specific CPB
+ * @timeout: # of milliseconds to retry h_call, 0 for no timeout.
+ * @hcall_err: pointer to return the h_call return value, else NULL
+ */
+struct vio_pfo_op {
+	u64 flags;
+	s64 in;
+	s64 inlen;
+	s64 out;
+	s64 outlen;
+	u64 csbcpb;
+	void *done;
+	unsigned long handle;
+	unsigned int timeout;
+	long hcall_err;
+};
+
+/* End PFO specific data */
+
+enum vio_dev_family {
+	VDEVICE,	/* The OF node is a child of /vdevice */
+	PFO,		/* The OF node is a child of /ibm,platform-facilities */
+};
+
 /**
  * vio_dev - This structure is used to describe virtual I/O devices.
  *
@@ -58,6 +100,7 @@
 	const char *name;
 	const char *type;
 	uint32_t unit_address;
+	uint32_t resource_id;
 	unsigned int irq;
 	struct {
 		size_t desired;
@@ -65,6 +108,7 @@
 		size_t allocated;
 		atomic_t allocs_failed;
 	} cmo;
+	enum vio_dev_family family;
 	struct device dev;
 };
 
@@ -95,6 +139,8 @@
 
 extern void __devinit vio_unregister_device(struct vio_dev *dev);
 
+extern int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op);
+
 struct device_node;
 
 extern struct vio_dev *vio_register_device_node(
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 34b8afe9..4554dc2 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -188,10 +188,6 @@
 	DEFINE(SLBSHADOW_STACKESID,
 	       offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid));
 	DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
-	DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
-	DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1));
-	DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int));
-	DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int));
 	DEFINE(LPPACA_PMCINUSE, offsetof(struct lppaca, pmcregs_in_use));
 	DEFINE(LPPACA_DTLIDX, offsetof(struct lppaca, dtl_idx));
 	DEFINE(LPPACA_YIELDCOUNT, offsetof(struct lppaca, yield_count));
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index ef2074c..ed1718f 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -63,15 +63,9 @@
 	std	r0,GPR0(r1)
 	std	r10,GPR1(r1)
 	ACCOUNT_CPU_USER_ENTRY(r10, r11)
-	/*
-	 * This "crclr so" clears CR0.SO, which is the error indication on
-	 * return from this system call.  There must be no cmp instruction
-	 * between it and the "mfcr r9" below, otherwise if XER.SO is set,
-	 * CR0.SO will get set, causing all system calls to appear to fail.
-	 */
-	crclr	so
 	std	r2,GPR2(r1)
 	std	r3,GPR3(r1)
+	mfcr	r2
 	std	r4,GPR4(r1)
 	std	r5,GPR5(r1)
 	std	r6,GPR6(r1)
@@ -82,18 +76,20 @@
 	std	r11,GPR10(r1)
 	std	r11,GPR11(r1)
 	std	r11,GPR12(r1)
+	std	r11,_XER(r1)
+	std	r11,_CTR(r1)
 	std	r9,GPR13(r1)
-	mfcr	r9
 	mflr	r10
+	/*
+	 * This clears CR0.SO (bit 28), which is the error indication on
+	 * return from this system call.
+	 */
+	rldimi	r2,r11,28,(63-28)
 	li	r11,0xc01
-	std	r9,_CCR(r1)
 	std	r10,_LINK(r1)
 	std	r11,_TRAP(r1)
-	mfxer	r9
-	mfctr	r10
-	std	r9,_XER(r1)
-	std	r10,_CTR(r1)
 	std	r3,ORIG_GPR3(r1)
+	std	r2,_CCR(r1)
 	ld	r2,PACATOC(r13)
 	addi	r9,r1,STACK_FRAME_OVERHEAD
 	ld	r11,exception_marker@toc(r2)
@@ -154,7 +150,7 @@
 	ld	r10,TI_FLAGS(r11)
 	andi.	r11,r10,_TIF_SYSCALL_T_OR_A
 	bne-	syscall_dotrace
-syscall_dotrace_cont:
+.Lsyscall_dotrace_cont:
 	cmpldi	0,r0,NR_syscalls
 	bge-	syscall_enosys
 
@@ -211,7 +207,7 @@
 	cmpld	r3,r11
 	ld	r5,_CCR(r1)
 	bge-	syscall_error
-syscall_error_cont:
+.Lsyscall_error_cont:
 	ld	r7,_NIP(r1)
 BEGIN_FTR_SECTION
 	stdcx.	r0,0,r1			/* to clear the reservation */
@@ -246,7 +242,7 @@
 	oris	r5,r5,0x1000	/* Set SO bit in CR */
 	neg	r3,r3
 	std	r5,_CCR(r1)
-	b	syscall_error_cont
+	b	.Lsyscall_error_cont
 	
 /* Traced system call support */
 syscall_dotrace:
@@ -268,7 +264,7 @@
 	addi	r9,r1,STACK_FRAME_OVERHEAD
 	clrrdi	r10,r1,THREAD_SHIFT
 	ld	r10,TI_FLAGS(r10)
-	b	syscall_dotrace_cont
+	b	.Lsyscall_dotrace_cont
 
 syscall_enosys:
 	li	r3,-ENOSYS
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 8f880bc..f7bed44 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -94,12 +94,10 @@
 data_access_pSeries:
 	HMT_MEDIUM
 	SET_SCRATCH0(r13)
-#ifndef CONFIG_POWER4_ONLY
 BEGIN_FTR_SECTION
 	b	data_access_check_stab
 data_access_not_stab:
 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
-#endif
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD,
 				 KVMTEST, 0x300)
 
@@ -301,7 +299,6 @@
 				 EXC_STD, KVMTEST, 0x200)
 	KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200)
 
-#ifndef CONFIG_POWER4_ONLY
 	/* moved from 0x300 */
 data_access_check_stab:
 	GET_PACA(r13)
@@ -328,7 +325,6 @@
 	GET_SCRATCH0(r10)
 	std	r10,PACA_EXSLB+EX_R13(r13)
 	EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD)
-#endif /* CONFIG_POWER4_ONLY */
 
 	KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300)
 	KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380)
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 7dd2981..22d608e 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -778,14 +778,6 @@
 	blr
 
 /*
- * extern void giveup_altivec(struct task_struct *prev)
- *
- * The 44x core does not have an AltiVec unit.
- */
-_GLOBAL(giveup_altivec)
-	blr
-
-/*
  * extern void giveup_fpu(struct task_struct *prev)
  *
  * The 44x core does not have an FPU.
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 28e6259..de80e0f 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -874,14 +874,6 @@
 	sync
 	blr
 
-/*
- * extern void giveup_altivec(struct task_struct *prev)
- *
- * The e500 core does not have an AltiVec unit.
- */
-_GLOBAL(giveup_altivec)
-	blr
-
 #ifdef CONFIG_SPE
 /*
  * extern void giveup_spe(struct task_struct *prev)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 641da9e..7835a5e 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -587,7 +587,7 @@
 {
 	int cpuid;
 
-	if (cpumask_equal(mask, cpu_all_mask)) {
+	if (cpumask_equal(mask, cpu_online_mask)) {
 		static int irq_rover;
 		static DEFINE_RAW_SPINLOCK(irq_rover_lock);
 		unsigned long flags;
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 7cd07b4..386d57f 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -738,8 +738,23 @@
 	mr      r5, r31
 
 	li	r0, 0
-#elif defined(CONFIG_44x)  && !defined(CONFIG_PPC_47x)
+#elif defined(CONFIG_44x)
 
+	/* Save our parameters */
+	mr	r29, r3
+	mr	r30, r4
+	mr	r31, r5
+
+#ifdef CONFIG_PPC_47x
+	/* Check for 47x cores */
+	mfspr	r3,SPRN_PVR
+	srwi	r3,r3,16
+	cmplwi	cr0,r3,PVR_476@h
+	beq	setup_map_47x
+	cmplwi	cr0,r3,PVR_476_ISS@h
+	beq	setup_map_47x
+#endif /* CONFIG_PPC_47x */
+	
 /*
  * Code for setting up 1:1 mapping for PPC440x for KEXEC
  *
@@ -753,16 +768,15 @@
  * 5) Invalidate the tmp mapping.
  *
  * - Based on the kexec support code for FSL BookE
- * - Doesn't support 47x yet.
  *
  */
-	/* Save our parameters */
-	mr	r29, r3
-	mr	r30, r4
-	mr	r31, r5
 
-	/* Load our MSR_IS and TID to MMUCR for TLB search */
-	mfspr	r3,SPRN_PID
+	/* 
+	 * Load the PID with kernel PID (0).
+	 * Also load our MSR_IS and TID to MMUCR for TLB search.
+	 */
+	li	r3, 0
+	mtspr	SPRN_PID, r3
 	mfmsr	r4
 	andi.	r4,r4,MSR_IS@l
 	beq	wmmucr
@@ -900,6 +914,179 @@
 	li	r3, 0
 	tlbwe	r3, r24, PPC44x_TLB_PAGEID
 	sync
+	b	ppc44x_map_done
+
+#ifdef CONFIG_PPC_47x
+
+	/* 1:1 mapping for 47x */
+
+setup_map_47x:
+
+	/*
+	 * Load the kernel pid (0) to PID and also to MMUCR[TID].
+	 * Also set the MSR IS->MMUCR STS
+	 */
+	li	r3, 0
+	mtspr	SPRN_PID, r3			/* Set PID */
+	mfmsr	r4				/* Get MSR */
+	andi.	r4, r4, MSR_IS@l		/* TS=1? */
+	beq	1f				/* If not, leave STS=0 */
+	oris	r3, r3, PPC47x_MMUCR_STS@h	/* Set STS=1 */
+1:	mtspr	SPRN_MMUCR, r3			/* Put MMUCR */
+	sync
+
+	/* Find the entry we are running from */
+	bl	2f
+2:	mflr	r23
+	tlbsx	r23, 0, r23
+	tlbre	r24, r23, 0			/* TLB Word 0 */
+	tlbre	r25, r23, 1			/* TLB Word 1 */
+	tlbre	r26, r23, 2			/* TLB Word 2 */
+
+
+	/*
+	 * Invalidates all the tlb entries by writing to 256 RPNs(r4)
+	 * of 4k page size in all  4 ways (0-3 in r3).
+	 * This would invalidate the entire UTLB including the one we are
+	 * running from. However the shadow TLB entries would help us 
+	 * to continue the execution, until we flush them (rfi/isync).
+	 */
+	addis	r3, 0, 0x8000			/* specify the way */
+	addi	r4, 0, 0			/* TLB Word0 = (EPN=0, VALID = 0) */
+	addi	r5, 0, 0
+	b	clear_utlb_entry
+
+	/* Align the loop to speed things up. from head_44x.S */
+	.align	6
+
+clear_utlb_entry:
+
+	tlbwe	r4, r3, 0
+	tlbwe	r5, r3, 1
+	tlbwe	r5, r3, 2
+	addis	r3, r3, 0x2000			/* Increment the way */
+	cmpwi	r3, 0
+	bne	clear_utlb_entry
+	addis	r3, 0, 0x8000
+	addis	r4, r4, 0x100			/* Increment the EPN */
+	cmpwi	r4, 0
+	bne	clear_utlb_entry
+
+	/* Create the entries in the other address space */
+	mfmsr	r5
+	rlwinm	r7, r5, 27, 31, 31		/* Get the TS (Bit 26) from MSR */
+	xori	r7, r7, 1			/* r7 = !TS */
+
+	insrwi	r24, r7, 1, 21			/* Change the TS in the saved TLB word 0 */
+
+	/* 
+	 * write out the TLB entries for the tmp mapping
+	 * Use way '0' so that we could easily invalidate it later.
+	 */
+	lis	r3, 0x8000			/* Way '0' */ 
+
+	tlbwe	r24, r3, 0
+	tlbwe	r25, r3, 1
+	tlbwe	r26, r3, 2
+
+	/* Update the msr to the new TS */
+	insrwi	r5, r7, 1, 26
+
+	bl	1f
+1:	mflr	r6
+	addi	r6, r6, (2f-1b)
+
+	mtspr	SPRN_SRR0, r6
+	mtspr	SPRN_SRR1, r5
+	rfi
+
+	/* 
+	 * Now we are in the tmp address space.
+	 * Create a 1:1 mapping for 0-2GiB in the original TS.
+	 */
+2:
+	li	r3, 0
+	li	r4, 0				/* TLB Word 0 */
+	li	r5, 0				/* TLB Word 1 */
+	li	r6, 0
+	ori	r6, r6, PPC47x_TLB2_S_RWX	/* TLB word 2 */
+
+	li	r8, 0				/* PageIndex */
+
+	xori	r7, r7, 1			/* revert back to original TS */
+
+write_utlb:
+	rotlwi	r5, r8, 28			/* RPN = PageIndex * 256M */
+						/* ERPN = 0 as we don't use memory above 2G */
+
+	mr	r4, r5				/* EPN = RPN */
+	ori	r4, r4, (PPC47x_TLB0_VALID | PPC47x_TLB0_256M)
+	insrwi	r4, r7, 1, 21			/* Insert the TS to Word 0 */
+
+	tlbwe	r4, r3, 0			/* Write out the entries */
+	tlbwe	r5, r3, 1
+	tlbwe	r6, r3, 2
+	addi	r8, r8, 1
+	cmpwi	r8, 8				/* Have we completed ? */
+	bne	write_utlb
+
+	/* make sure we complete the TLB write up */
+	isync
+
+	/* 
+	 * Prepare to jump to the 1:1 mapping.
+	 * 1) Extract page size of the tmp mapping
+	 *    DSIZ = TLB_Word0[22:27]
+	 * 2) Calculate the physical address of the address
+	 *    to jump to.
+	 */
+	rlwinm	r10, r24, 0, 22, 27
+
+	cmpwi	r10, PPC47x_TLB0_4K
+	bne	0f
+	li	r10, 0x1000			/* r10 = 4k */
+	bl	1f
+
+0:
+	/* Defaults to 256M */
+	lis	r10, 0x1000
+	
+	bl	1f
+1:	mflr	r4
+	addi	r4, r4, (2f-1b)			/* virtual address  of 2f */
+
+	subi	r11, r10, 1			/* offsetmask = Pagesize - 1 */
+	not	r10, r11			/* Pagemask = ~(offsetmask) */
+
+	and	r5, r25, r10			/* Physical page */
+	and	r6, r4, r11			/* offset within the current page */
+
+	or	r5, r5, r6			/* Physical address for 2f */
+
+	/* Switch the TS in MSR to the original one */
+	mfmsr	r8
+	insrwi	r8, r7, 1, 26
+
+	mtspr	SPRN_SRR1, r8
+	mtspr	SPRN_SRR0, r5
+	rfi
+
+2:
+	/* Invalidate the tmp mapping */
+	lis	r3, 0x8000			/* Way '0' */
+
+	clrrwi	r24, r24, 12			/* Clear the valid bit */
+	tlbwe	r24, r3, 0
+	tlbwe	r25, r3, 1
+	tlbwe	r26, r3, 2
+
+	/* Make sure we complete the TLB write and flush the shadow TLB */
+	isync
+
+#endif
+
+ppc44x_map_done:
+
 
 	/* Restore the parameters */
 	mr	r3, r29
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 0bb1f98..fbe1a12 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -36,10 +36,7 @@
 	[0 ... (NR_LPPACAS-1)] = {
 		.desc = 0xd397d781,	/* "LpPa" */
 		.size = sizeof(struct lppaca),
-		.dyn_proc_status = 2,
-		.decr_val = 0x00ff0000,
 		.fpregs_in_use = 1,
-		.end_of_quantum = 0xfffffffffffffffful,
 		.slb_count = 64,
 		.vmxregs_in_use = 0,
 		.page_ins = 0,
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index aa05935..710f400 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -124,7 +124,7 @@
 	if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
 		giveup_altivec(current);
 	else
-		giveup_altivec(NULL);	/* just enable AltiVec for kernel - force */
+		giveup_altivec_notask();
 #else
 	giveup_altivec(last_task_used_altivec);
 #endif /* CONFIG_SMP */
@@ -711,18 +711,21 @@
 }
 
 /*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
+ * this gets called so that we can store coprocessor state into memory and
+ * copy the current task into the new thread.
  */
-void prepare_to_copy(struct task_struct *tsk)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-	flush_fp_to_thread(current);
-	flush_altivec_to_thread(current);
-	flush_vsx_to_thread(current);
-	flush_spe_to_thread(current);
+	flush_fp_to_thread(src);
+	flush_altivec_to_thread(src);
+	flush_vsx_to_thread(src);
+	flush_spe_to_thread(src);
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
-	flush_ptrace_hw_breakpoint(tsk);
+	flush_ptrace_hw_breakpoint(src);
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
+
+	*dst = *src;
+	return 0;
 }
 
 /*
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 9986027..1b488e5 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -680,6 +680,9 @@
 #define OV3_VMX			0x40	/* VMX/Altivec */
 #define OV3_DFP			0x20	/* decimal FP */
 
+/* Option vector 4: IBM PAPR implementation */
+#define OV4_MIN_ENT_CAP		0x01	/* minimum VP entitled capacity */
+
 /* Option vector 5: PAPR/OF options supported */
 #define OV5_LPAR		0x80	/* logical partitioning supported */
 #define OV5_SPLPAR		0x40	/* shared-processor LPAR supported */
@@ -701,6 +704,8 @@
 #define OV5_XCMO			0x00
 #endif
 #define OV5_TYPE1_AFFINITY	0x80	/* Type 1 NUMA affinity */
+#define OV5_PFO_HW_RNG		0x80	/* PFO Random Number Generator */
+#define OV5_PFO_HW_ENCR		0x20	/* PFO Encryption Accelerator */
 
 /* Option Vector 6: IBM PAPR hints */
 #define OV6_LINUX		0x02	/* Linux is our OS */
@@ -744,11 +749,12 @@
 	OV3_FP | OV3_VMX | OV3_DFP,
 
 	/* option vector 4: IBM PAPR implementation */
-	2 - 2,				/* length */
+	3 - 2,				/* length */
 	0,				/* don't halt */
+	OV4_MIN_ENT_CAP,		/* minimum VP entitled capacity */
 
 	/* option vector 5: PAPR/OF options */
-	13 - 2,				/* length */
+	18 - 2,				/* length */
 	0,				/* don't ignore, don't halt */
 	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
 	OV5_DONATE_DEDICATE_CPU | OV5_MSI,
@@ -762,8 +768,13 @@
 	 * must match by the macro below. Update the definition if
 	 * the structure layout changes.
 	 */
-#define IBM_ARCH_VEC_NRCORES_OFFSET	100
+#define IBM_ARCH_VEC_NRCORES_OFFSET	101
 	W(NR_CPUS),			/* number of cores supported */
+	0,
+	0,
+	0,
+	0,
+	OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR,
 
 	/* option vector 6: IBM PAPR hints */
 	4 - 2,				/* length */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index dd5e214..c10fc28 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1432,40 +1432,6 @@
 #endif
 }
 
-/*
- * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
- * we mark them as obsolete now, they will be removed in a future version
- */
-static long arch_ptrace_old(struct task_struct *child, long request,
-			    unsigned long addr, unsigned long data)
-{
-	void __user *datavp = (void __user *) data;
-
-	switch (request) {
-	case PPC_PTRACE_GETREGS:	/* Get GPRs 0 - 31. */
-		return copy_regset_to_user(child, &user_ppc_native_view,
-					   REGSET_GPR, 0, 32 * sizeof(long),
-					   datavp);
-
-	case PPC_PTRACE_SETREGS:	/* Set GPRs 0 - 31. */
-		return copy_regset_from_user(child, &user_ppc_native_view,
-					     REGSET_GPR, 0, 32 * sizeof(long),
-					     datavp);
-
-	case PPC_PTRACE_GETFPREGS:	/* Get FPRs 0 - 31. */
-		return copy_regset_to_user(child, &user_ppc_native_view,
-					   REGSET_FPR, 0, 32 * sizeof(double),
-					   datavp);
-
-	case PPC_PTRACE_SETFPREGS:	/* Set FPRs 0 - 31. */
-		return copy_regset_from_user(child, &user_ppc_native_view,
-					     REGSET_FPR, 0, 32 * sizeof(double),
-					     datavp);
-	}
-
-	return -EPERM;
-}
-
 long arch_ptrace(struct task_struct *child, long request,
 		 unsigned long addr, unsigned long data)
 {
@@ -1687,14 +1653,6 @@
 					     datavp);
 #endif
 
-	/* Old reverse args ptrace callss */
-	case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
-	case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
-	case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
-	case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */
-		ret = arch_ptrace_old(child, request, addr, data);
-		break;
-
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 469349d..8c21658 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -39,30 +39,6 @@
  * in exit.c or in signal.c.
  */
 
-/*
- * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
- * we mark them as obsolete now, they will be removed in a future version
- */
-static long compat_ptrace_old(struct task_struct *child, long request,
-			      long addr, long data)
-{
-	switch (request) {
-	case PPC_PTRACE_GETREGS:	/* Get GPRs 0 - 31. */
-		return copy_regset_to_user(child,
-					   task_user_regset_view(current), 0,
-					   0, 32 * sizeof(compat_long_t),
-					   compat_ptr(data));
-
-	case PPC_PTRACE_SETREGS:	/* Set GPRs 0 - 31. */
-		return copy_regset_from_user(child,
-					     task_user_regset_view(current), 0,
-					     0, 32 * sizeof(compat_long_t),
-					     compat_ptr(data));
-	}
-
-	return -EPERM;
-}
-
 /* Macros to workout the correct index for the FPR in the thread struct */
 #define FPRNUMBER(i) (((i) - PT_FPR0) >> 1)
 #define FPRHALF(i) (((i) - PT_FPR0) & 1)
@@ -308,8 +284,6 @@
 	case PTRACE_SETVSRREGS:
 	case PTRACE_GETREGS64:
 	case PTRACE_SETREGS64:
-	case PPC_PTRACE_GETFPREGS:
-	case PPC_PTRACE_SETFPREGS:
 	case PTRACE_KILL:
 	case PTRACE_SINGLESTEP:
 	case PTRACE_DETACH:
@@ -322,12 +296,6 @@
 		ret = arch_ptrace(child, request, addr, data);
 		break;
 
-	/* Old reverse args ptrace callss */
-	case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
-	case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
-		ret = compat_ptrace_old(child, request, addr, data);
-		break;
-
 	default:
 		ret = compat_ptrace_request(child, request, addr, data);
 		break;
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 45eb998..61f6aff 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -204,10 +204,10 @@
 
 	if (!access_ok(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);
 	return 0;
 }
@@ -244,17 +244,8 @@
 long sys_sigsuspend(old_sigset_t mask)
 {
 	sigset_t blocked;
-
-	current->saved_sigmask = current->blocked;
-
-	mask &= _BLOCKABLE;
 	siginitset(&blocked, mask);
-	set_current_blocked(&blocked);
-
- 	current->state = TASK_INTERRUPTIBLE;
- 	schedule();
-	set_restore_sigmask();
- 	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 long sys_sigaction(int sig, struct old_sigaction __user *act,
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index 4d5a3ed..e830289 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -89,6 +89,16 @@
 	/* restore registers and return */
 	blr
 
+_GLOBAL(giveup_altivec_notask)
+	mfmsr	r3
+	andis.	r4,r3,MSR_VEC@h
+	bnelr				/* Already enabled? */
+	oris	r3,r3,MSR_VEC@h
+	SYNC
+	MTMSRD(r3)			/* enable use of VMX now */
+	isync
+	blr
+
 /*
  * giveup_altivec(tsk)
  * Disable VMX for the task given as the argument,
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index a3a9990..cb87301 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -14,7 +14,9 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#include <linux/cpu.h>
 #include <linux/types.h>
+#include <linux/delay.h>
 #include <linux/stat.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -709,13 +711,26 @@
 	struct vio_driver *viodrv = to_vio_driver(dev->driver);
 	unsigned long flags;
 	size_t size;
+	bool dma_capable = false;
 
-	/*
-	 * Check to see that device has a DMA window and configure
-	 * entitlement for the device.
-	 */
-	if (of_get_property(viodev->dev.of_node,
-	                    "ibm,my-dma-window", NULL)) {
+	/* A device requires entitlement if it has a DMA window property */
+	switch (viodev->family) {
+	case VDEVICE:
+		if (of_get_property(viodev->dev.of_node,
+					"ibm,my-dma-window", NULL))
+			dma_capable = true;
+		break;
+	case PFO:
+		dma_capable = false;
+		break;
+	default:
+		dev_warn(dev, "unknown device family: %d\n", viodev->family);
+		BUG();
+		break;
+	}
+
+	/* Configure entitlement for the device. */
+	if (dma_capable) {
 		/* Check that the driver is CMO enabled and get desired DMA */
 		if (!viodrv->get_desired_dma) {
 			dev_err(dev, "%s: device driver does not support CMO\n",
@@ -1050,6 +1065,94 @@
 EXPORT_SYMBOL(vio_cmo_entitlement_update);
 EXPORT_SYMBOL(vio_cmo_set_dev_desired);
 
+
+/*
+ * Platform Facilities Option (PFO) support
+ */
+
+/**
+ * vio_h_cop_sync - Perform a synchronous PFO co-processor operation
+ *
+ * @vdev - Pointer to a struct vio_dev for device
+ * @op - Pointer to a struct vio_pfo_op for the operation parameters
+ *
+ * Calls the hypervisor to synchronously perform the PFO operation
+ * described in @op.  In the case of a busy response from the hypervisor,
+ * the operation will be re-submitted indefinitely unless a non-zero timeout
+ * is specified or an error occurs. The timeout places a limit on when to
+ * stop re-submitting a operation, the total time can be exceeded if an
+ * operation is in progress.
+ *
+ * If op->hcall_ret is not NULL, this will be set to the return from the
+ * last h_cop_op call or it will be 0 if an error not involving the h_call
+ * was encountered.
+ *
+ * Returns:
+ *	0 on success,
+ *	-EINVAL if the h_call fails due to an invalid parameter,
+ *	-E2BIG if the h_call can not be performed synchronously,
+ *	-EBUSY if a timeout is specified and has elapsed,
+ *	-EACCES if the memory area for data/status has been rescinded, or
+ *	-EPERM if a hardware fault has been indicated
+ */
+int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op)
+{
+	struct device *dev = &vdev->dev;
+	unsigned long deadline = 0;
+	long hret = 0;
+	int ret = 0;
+
+	if (op->timeout)
+		deadline = jiffies + msecs_to_jiffies(op->timeout);
+
+	while (true) {
+		hret = plpar_hcall_norets(H_COP, op->flags,
+				vdev->resource_id,
+				op->in, op->inlen, op->out,
+				op->outlen, op->csbcpb);
+
+		if (hret == H_SUCCESS ||
+		    (hret != H_NOT_ENOUGH_RESOURCES &&
+		     hret != H_BUSY && hret != H_RESOURCE) ||
+		    (op->timeout && time_after(deadline, jiffies)))
+			break;
+
+		dev_dbg(dev, "%s: hcall ret(%ld), retrying.\n", __func__, hret);
+	}
+
+	switch (hret) {
+	case H_SUCCESS:
+		ret = 0;
+		break;
+	case H_OP_MODE:
+	case H_TOO_BIG:
+		ret = -E2BIG;
+		break;
+	case H_RESCINDED:
+		ret = -EACCES;
+		break;
+	case H_HARDWARE:
+		ret = -EPERM;
+		break;
+	case H_NOT_ENOUGH_RESOURCES:
+	case H_RESOURCE:
+	case H_BUSY:
+		ret = -EBUSY;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret)
+		dev_dbg(dev, "%s: Sync h_cop_op failure (ret:%d) (hret:%ld)\n",
+				__func__, ret, hret);
+
+	op->hcall_err = hret;
+	return ret;
+}
+EXPORT_SYMBOL(vio_h_cop_sync);
+
 static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
 {
 	const unsigned char *dma_window;
@@ -1211,35 +1314,87 @@
 struct vio_dev *vio_register_device_node(struct device_node *of_node)
 {
 	struct vio_dev *viodev;
+	struct device_node *parent_node;
 	const unsigned int *unit_address;
+	const unsigned int *pfo_resid = NULL;
+	enum vio_dev_family family;
+	const char *of_node_name = of_node->name ? of_node->name : "<unknown>";
 
-	/* we need the 'device_type' property, in order to match with drivers */
-	if (of_node->type == NULL) {
-		printk(KERN_WARNING "%s: node %s missing 'device_type'\n",
-				__func__,
-				of_node->name ? of_node->name : "<unknown>");
+	/*
+	 * Determine if this node is a under the /vdevice node or under the
+	 * /ibm,platform-facilities node.  This decides the device's family.
+	 */
+	parent_node = of_get_parent(of_node);
+	if (parent_node) {
+		if (!strcmp(parent_node->full_name, "/ibm,platform-facilities"))
+			family = PFO;
+		else if (!strcmp(parent_node->full_name, "/vdevice"))
+			family = VDEVICE;
+		else {
+			pr_warn("%s: parent(%s) of %s not recognized.\n",
+					__func__,
+					parent_node->full_name,
+					of_node_name);
+			of_node_put(parent_node);
+			return NULL;
+		}
+		of_node_put(parent_node);
+	} else {
+		pr_warn("%s: could not determine the parent of node %s.\n",
+				__func__, of_node_name);
 		return NULL;
 	}
 
-	unit_address = of_get_property(of_node, "reg", NULL);
-	if (unit_address == NULL) {
-		printk(KERN_WARNING "%s: node %s missing 'reg'\n",
-				__func__,
-				of_node->name ? of_node->name : "<unknown>");
-		return NULL;
+	if (family == PFO) {
+		if (of_get_property(of_node, "interrupt-controller", NULL)) {
+			pr_debug("%s: Skipping the interrupt controller %s.\n",
+					__func__, of_node_name);
+			return NULL;
+		}
 	}
 
 	/* allocate a vio_dev for this node */
 	viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL);
-	if (viodev == NULL)
+	if (viodev == NULL) {
+		pr_warn("%s: allocation failure for VIO device.\n", __func__);
 		return NULL;
+	}
 
-	viodev->irq = irq_of_parse_and_map(of_node, 0);
+	/* we need the 'device_type' property, in order to match with drivers */
+	viodev->family = family;
+	if (viodev->family == VDEVICE) {
+		if (of_node->type != NULL)
+			viodev->type = of_node->type;
+		else {
+			pr_warn("%s: node %s is missing the 'device_type' "
+					"property.\n", __func__, of_node_name);
+			goto out;
+		}
 
-	dev_set_name(&viodev->dev, "%x", *unit_address);
+		unit_address = of_get_property(of_node, "reg", NULL);
+		if (unit_address == NULL) {
+			pr_warn("%s: node %s missing 'reg'\n",
+					__func__, of_node_name);
+			goto out;
+		}
+		dev_set_name(&viodev->dev, "%x", *unit_address);
+		viodev->irq = irq_of_parse_and_map(of_node, 0);
+		viodev->unit_address = *unit_address;
+	} else {
+		/* PFO devices need their resource_id for submitting COP_OPs
+		 * This is an optional field for devices, but is required when
+		 * performing synchronous ops */
+		pfo_resid = of_get_property(of_node, "ibm,resource-id", NULL);
+		if (pfo_resid != NULL)
+			viodev->resource_id = *pfo_resid;
+
+		unit_address = NULL;
+		dev_set_name(&viodev->dev, "%s", of_node_name);
+		viodev->type = of_node_name;
+		viodev->irq = 0;
+	}
+
 	viodev->name = of_node->name;
-	viodev->type = of_node->type;
-	viodev->unit_address = *unit_address;
 	viodev->dev.of_node = of_node_get(of_node);
 
 	if (firmware_has_feature(FW_FEATURE_CMO))
@@ -1267,16 +1422,51 @@
 	}
 
 	return viodev;
+
+out:	/* Use this exit point for any return prior to device_register */
+	kfree(viodev);
+
+	return NULL;
 }
 EXPORT_SYMBOL(vio_register_device_node);
 
+/*
+ * vio_bus_scan_for_devices - Scan OF and register each child device
+ * @root_name - OF node name for the root of the subtree to search.
+ *		This must be non-NULL
+ *
+ * Starting from the root node provide, register the device node for
+ * each child beneath the root.
+ */
+static void vio_bus_scan_register_devices(char *root_name)
+{
+	struct device_node *node_root, *node_child;
+
+	if (!root_name)
+		return;
+
+	node_root = of_find_node_by_name(NULL, root_name);
+	if (node_root) {
+
+		/*
+		 * Create struct vio_devices for each virtual device in
+		 * the device tree. Drivers will associate with them later.
+		 */
+		node_child = of_get_next_child(node_root, NULL);
+		while (node_child) {
+			vio_register_device_node(node_child);
+			node_child = of_get_next_child(node_root, node_child);
+		}
+		of_node_put(node_root);
+	}
+}
+
 /**
  * vio_bus_init: - Initialize the virtual IO bus
  */
 static int __init vio_bus_init(void)
 {
 	int err;
-	struct device_node *node_vroot;
 
 	if (firmware_has_feature(FW_FEATURE_CMO))
 		vio_cmo_sysfs_init();
@@ -1301,19 +1491,8 @@
 	if (firmware_has_feature(FW_FEATURE_CMO))
 		vio_cmo_bus_init();
 
-	node_vroot = of_find_node_by_name(NULL, "vdevice");
-	if (node_vroot) {
-		struct device_node *of_node;
-
-		/*
-		 * Create struct vio_devices for each virtual device in
-		 * the device tree. Drivers will associate with them later.
-		 */
-		for (of_node = node_vroot->child; of_node != NULL;
-				of_node = of_node->sibling)
-			vio_register_device_node(of_node);
-		of_node_put(node_vroot);
-	}
+	vio_bus_scan_register_devices("vdevice");
+	vio_bus_scan_register_devices("ibm,platform-facilities");
 
 	return 0;
 }
@@ -1436,12 +1615,28 @@
 {
 	const uint32_t *unit_address;
 	char kobj_name[20];
+	struct device_node *vnode_parent;
+	const char *dev_type;
+
+	vnode_parent = of_get_parent(vnode);
+	if (!vnode_parent)
+		return NULL;
+
+	dev_type = of_get_property(vnode_parent, "device_type", NULL);
+	of_node_put(vnode_parent);
+	if (!dev_type)
+		return NULL;
 
 	/* construct the kobject name from the device node */
-	unit_address = of_get_property(vnode, "reg", NULL);
-	if (!unit_address)
+	if (!strcmp(dev_type, "vdevice")) {
+		unit_address = of_get_property(vnode, "reg", NULL);
+		if (!unit_address)
+			return NULL;
+		snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address);
+	} else if (!strcmp(dev_type, "ibm,platform-facilities"))
+		snprintf(kobj_name, sizeof(kobj_name), "%s", vnode->name);
+	else
 		return NULL;
-	snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address);
 
 	return vio_find_name(kobj_name);
 }
diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S
index 773d38f..d73a590 100644
--- a/arch/powerpc/lib/copyuser_64.S
+++ b/arch/powerpc/lib/copyuser_64.S
@@ -30,7 +30,7 @@
 	dcbt	0,r4
 	beq	.Lcopy_page_4K
 	andi.	r6,r6,7
-	PPC_MTOCRF	0x01,r5
+	PPC_MTOCRF(0x01,r5)
 	blt	cr1,.Lshort_copy
 /* Below we want to nop out the bne if we're on a CPU that has the
  * CPU_FTR_UNALIGNED_LD_STD bit set and the CPU_FTR_CP_USE_DCBTZ bit
@@ -186,7 +186,7 @@
 	blr
 
 .Ldst_unaligned:
-	PPC_MTOCRF	0x01,r6		/* put #bytes to 8B bdry into cr7 */
+	PPC_MTOCRF(0x01,r6)		/* put #bytes to 8B bdry into cr7 */
 	subf	r5,r6,r5
 	li	r7,0
 	cmpldi	cr1,r5,16
@@ -201,7 +201,7 @@
 2:	bf	cr7*4+1,3f
 37:	lwzx	r0,r7,r4
 83:	stwx	r0,r7,r3
-3:	PPC_MTOCRF	0x01,r5
+3:	PPC_MTOCRF(0x01,r5)
 	add	r4,r6,r4
 	add	r3,r6,r3
 	b	.Ldst_aligned
diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S
index 11ce045..f4fcb0b 100644
--- a/arch/powerpc/lib/mem_64.S
+++ b/arch/powerpc/lib/mem_64.S
@@ -19,7 +19,7 @@
 	rlwimi	r4,r4,16,0,15
 	cmplw	cr1,r5,r0		/* do we get that far? */
 	rldimi	r4,r4,32,0
-	PPC_MTOCRF	1,r0
+	PPC_MTOCRF(1,r0)
 	mr	r6,r3
 	blt	cr1,8f
 	beq+	3f			/* if already 8-byte aligned */
@@ -49,7 +49,7 @@
 	bdnz	4b
 5:	srwi.	r0,r5,3
 	clrlwi	r5,r5,29
-	PPC_MTOCRF	1,r0
+	PPC_MTOCRF(1,r0)
 	beq	8f
 	bf	29,6f
 	std	r4,0(r6)
@@ -65,7 +65,7 @@
 	std	r4,0(r6)
 	addi	r6,r6,8
 8:	cmpwi	r5,0
-	PPC_MTOCRF	1,r5
+	PPC_MTOCRF(1,r5)
 	beqlr+
 	bf	29,9f
 	stw	r4,0(r6)
diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S
index e178922..82fea39 100644
--- a/arch/powerpc/lib/memcpy_64.S
+++ b/arch/powerpc/lib/memcpy_64.S
@@ -12,7 +12,7 @@
 	.align	7
 _GLOBAL(memcpy)
 	std	r3,48(r1)	/* save destination pointer for return value */
-	PPC_MTOCRF	0x01,r5
+	PPC_MTOCRF(0x01,r5)
 	cmpldi	cr1,r5,16
 	neg	r6,r3		# LS 3 bits = # bytes to 8-byte dest bdry
 	andi.	r6,r6,7
@@ -154,7 +154,7 @@
 	blr
 
 .Ldst_unaligned:
-	PPC_MTOCRF	0x01,r6		# put #bytes to 8B bdry into cr7
+	PPC_MTOCRF(0x01,r6)		# put #bytes to 8B bdry into cr7
 	subf	r5,r6,r5
 	li	r7,0
 	cmpldi	cr1,r5,16
@@ -169,7 +169,7 @@
 2:	bf	cr7*4+1,3f
 	lwzx	r0,r7,r4
 	stwx	r0,r7,r3
-3:	PPC_MTOCRF	0x01,r5
+3:	PPC_MTOCRF(0x01,r5)
 	add	r4,r6,r4
 	add	r3,r6,r3
 	b	.Ldst_aligned
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index fb05b12..1a6de0a 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -271,7 +271,8 @@
 
 unsigned long gpage_npages[MMU_PAGE_COUNT];
 
-static int __init do_gpage_early_setup(char *param, char *val)
+static int __init do_gpage_early_setup(char *param, char *val,
+				       const char *unused)
 {
 	static phys_addr_t size;
 	unsigned long npages;
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 02aee03..8f84bcb 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -1299,8 +1299,7 @@
 	if (record) {
 		struct perf_sample_data data;
 
-		perf_sample_data_init(&data, ~0ULL);
-		data.period = event->hw.last_period;
+		perf_sample_data_init(&data, ~0ULL, event->hw.last_period);
 
 		if (event->attr.sample_type & PERF_SAMPLE_ADDR)
 			perf_get_data_addr(regs, &data.addr);
diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c
index 0a6d2a9..106c533 100644
--- a/arch/powerpc/perf/core-fsl-emb.c
+++ b/arch/powerpc/perf/core-fsl-emb.c
@@ -613,8 +613,7 @@
 	if (record) {
 		struct perf_sample_data data;
 
-		perf_sample_data_init(&data, 0);
-		data.period = event->hw.last_period;
+		perf_sample_data_init(&data, 0, event->hw.last_period);
 
 		if (perf_event_overflow(event, &data, regs))
 			fsl_emb_pmu_stop(event, 0);
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 2e4e64a..8abf6fb8 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -23,6 +23,8 @@
 	default n
 	select PPC44x_SIMPLE
 	select APM821xx
+	select PCI_MSI
+	select PPC4xx_MSI
 	select PPC4xx_PCI_EXPRESS
 	select IBM_EMAC_RGMII
 	help
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 425db18..61c9550 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -78,6 +78,36 @@
 
 endchoice
 
+choice
+	prompt "CPU selection"
+	depends on PPC64
+	default GENERIC_CPU
+	help
+	  This will create a kernel which is optimised for a particular CPU.
+	  The resulting kernel may not run on other CPUs, so use this with care.
+
+	  If unsure, select Generic.
+
+config GENERIC_CPU
+	bool "Generic"
+
+config CELL_CPU
+	bool "Cell Broadband Engine"
+
+config POWER4_CPU
+	bool "POWER4"
+
+config POWER5_CPU
+	bool "POWER5"
+
+config POWER6_CPU
+	bool "POWER6"
+
+config POWER7_CPU
+	bool "POWER7"
+
+endchoice
+
 config PPC_BOOK3S
 	def_bool y
 	depends on PPC_BOOK3S_32 || PPC_BOOK3S_64
@@ -86,15 +116,6 @@
 	def_bool y
 	depends on PPC_BOOK3E_64
 
-config POWER4_ONLY
-	bool "Optimize for POWER4"
-	depends on PPC64 && PPC_BOOK3S
-	default n
-	---help---
-	  Cause the compiler to optimize for POWER4/POWER5/PPC970 processors.
-	  The resulting binary will not work on POWER3 or RS64 processors
-	  when compiled with binutils 2.15 or later.
-
 config 6xx
 	def_bool y
 	depends on PPC32 && PPC_BOOK3S
@@ -258,7 +279,7 @@
 	default y
 	---help---
 	  The PID register in server is used explicitly for ICSWX.  In
-	  embedded systems PID managment is done by the system.
+	  embedded systems PID management is done by the system.
 
 config PPC_ICSWX_USE_SIGILL
 	bool "Should a bad CT cause a SIGILL?"
@@ -266,7 +287,7 @@
 	default n
 	---help---
 	  Should a bad CT used for "non-record form ICSWX" cause an
-	  illegal intruction signal or should it be silent as
+	  illegal instruction signal or should it be silent as
 	  architected.
 
 	  If in doubt, say N here.
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 03685a3..fc536f2 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -1503,6 +1503,7 @@
 		if (bus->platform_dev == NULL)
 			return -ENOMEM;
 		bus->platform_dev->dev.platform_data = bus;
+		bus->platform_dev->dev.of_node = bus->busnode;
 		platform_device_add(bus->platform_dev);
 	}
 
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 476d9d9..46b7f02 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -7,7 +7,6 @@
 	select USB_OHCI_BIG_ENDIAN_MMIO
 	select USB_ARCH_HAS_EHCI
 	select USB_EHCI_BIG_ENDIAN_MMIO
-	select MEMORY_HOTPLUG
 	select PPC_PCI_CHOICE
 	help
 	  This option enables support for the Sony PS3 game console
@@ -74,7 +73,7 @@
 	help
 	  Include support for the PS3 AV Settings driver.
 
-	  This support is required for graphics and sound. In
+	  This support is required for PS3 graphics and sound. In
 	  general, all users will say Y or M.
 
 config PS3_SYS_MANAGER
@@ -85,9 +84,22 @@
 	help
 	  Include support for the PS3 System Manager.
 
-	  This support is required for system control.  In
+	  This support is required for PS3 system control.  In
 	  general, all users will say Y or M.
 
+config PS3_REPOSITORY_WRITE
+	bool "PS3 Repository write support" if PS3_ADVANCED
+	depends on PPC_PS3
+	default n
+	help
+	  Enables support for writing to the PS3 System Repository.
+
+	  This support is intended for bootloaders that need to store data
+	  in the repository for later boot stages.
+
+	  If in doubt, say N here and reduce the size of the kernel by a
+	  small amount.
+
 config PS3_STORAGE
 	depends on PPC_PS3
 	tristate
@@ -122,7 +134,7 @@
 
 	  This support is required to access the PS3 FLASH ROM, which
 	  contains the boot loader and some boot options.
-	  In general, all users will say Y or M.
+	  In general, PS3 OtherOS users will say Y or M.
 
 	  As this driver needs a fixed buffer of 256 KiB of memory, it can
 	  be disabled on the kernel command line using "ps3flash=off", to
@@ -156,7 +168,7 @@
 	  via the Ethernet port (UDP port number 18194).
 
 	  This driver uses a trivial implementation and is independent
-	  from the main network driver.
+	  from the main PS3 gelic network driver.
 
 	  If in doubt, say N here.
 
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index de2aea4..0c9f643 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -20,7 +20,6 @@
 
 #include <linux/kernel.h>
 #include <linux/export.h>
-#include <linux/memory_hotplug.h>
 #include <linux/memblock.h>
 #include <linux/slab.h>
 
@@ -79,12 +78,14 @@
  * @base: base address
  * @size: size in bytes
  * @offset: difference between base and rm.size
+ * @destroy: flag if region should be destroyed upon shutdown
  */
 
 struct mem_region {
 	u64 base;
 	u64 size;
 	unsigned long offset;
+	int destroy;
 };
 
 /**
@@ -96,7 +97,7 @@
  * The HV virtual address space (vas) allows for hotplug memory regions.
  * Memory regions can be created and destroyed in the vas at runtime.
  * @rm: real mode (bootmem) region
- * @r1: hotplug memory region(s)
+ * @r1: highmem region(s)
  *
  * ps3 addresses
  * virt_addr: a cpu 'translated' effective address
@@ -222,10 +223,6 @@
 	}
 }
 
-/*============================================================================*/
-/* memory hotplug routines                                                    */
-/*============================================================================*/
-
 /**
  * ps3_mm_region_create - create a memory region in the vas
  * @r: pointer to a struct mem_region to accept initialized values
@@ -262,6 +259,7 @@
 		goto zero_region;
 	}
 
+	r->destroy = 1;
 	r->offset = r->base - map.rm.size;
 	return result;
 
@@ -279,7 +277,14 @@
 {
 	int result;
 
+	if (!r->destroy) {
+		pr_info("%s:%d: Not destroying high region: %llxh %llxh\n",
+			__func__, __LINE__, r->base, r->size);
+		return;
+	}
+
 	DBG("%s:%d: r->base = %llxh\n", __func__, __LINE__, r->base);
+
 	if (r->base) {
 		result = lv1_release_memory(r->base);
 		BUG_ON(result);
@@ -288,50 +293,36 @@
 	}
 }
 
-/**
- * ps3_mm_add_memory - hot add memory
- */
-
-static int __init ps3_mm_add_memory(void)
+static int ps3_mm_get_repository_highmem(struct mem_region *r)
 {
 	int result;
-	unsigned long start_addr;
-	unsigned long start_pfn;
-	unsigned long nr_pages;
 
-	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
-		return -ENODEV;
+	/* Assume a single highmem region. */
 
-	BUG_ON(!mem_init_done);
-
-	start_addr = map.rm.size;
-	start_pfn = start_addr >> PAGE_SHIFT;
-	nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
-	DBG("%s:%d: start_addr %lxh, start_pfn %lxh, nr_pages %lxh\n",
-		__func__, __LINE__, start_addr, start_pfn, nr_pages);
-
-	result = add_memory(0, start_addr, map.r1.size);
-
-	if (result) {
-		pr_err("%s:%d: add_memory failed: (%d)\n",
-			__func__, __LINE__, result);
-		return result;
-	}
-
-	memblock_add(start_addr, map.r1.size);
-
-	result = online_pages(start_pfn, nr_pages);
+	result = ps3_repository_read_highmem_info(0, &r->base, &r->size);
 
 	if (result)
-		pr_err("%s:%d: online_pages failed: (%d)\n",
-			__func__, __LINE__, result);
+		goto zero_region;
 
+	if (!r->base || !r->size) {
+		result = -1;
+		goto zero_region;
+	}
+
+	r->offset = r->base - map.rm.size;
+
+	DBG("%s:%d: Found high region in repository: %llxh %llxh\n",
+	    __func__, __LINE__, r->base, r->size);
+
+	return 0;
+
+zero_region:
+	DBG("%s:%d: No high region in repository.\n", __func__, __LINE__);
+
+	r->size = r->base = r->offset = 0;
 	return result;
 }
 
-device_initcall(ps3_mm_add_memory);
-
 /*============================================================================*/
 /* dma routines                                                               */
 /*============================================================================*/
@@ -1217,13 +1208,23 @@
 	BUG_ON(map.rm.base);
 	BUG_ON(!map.rm.size);
 
+	/* Check if we got the highmem region from an earlier boot step */
 
-	/* arrange to do this in ps3_mm_add_memory */
-	ps3_mm_region_create(&map.r1, map.total - map.rm.size);
+	if (ps3_mm_get_repository_highmem(&map.r1))
+		ps3_mm_region_create(&map.r1, map.total - map.rm.size);
 
 	/* correct map.total for the real total amount of memory we use */
 	map.total = map.rm.size + map.r1.size;
 
+	if (!map.r1.size) {
+		DBG("%s:%d: No highmem region found\n", __func__, __LINE__);
+	} else {
+		DBG("%s:%d: Adding highmem region: %llxh %llxh\n",
+			__func__, __LINE__, map.rm.size,
+			map.total - map.rm.size);
+		memblock_add(map.rm.size, map.total - map.rm.size);
+	}
+
 	DBG(" <- %s:%d\n", __func__, __LINE__);
 }
 
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 1a633ed..d71329a 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -188,6 +188,22 @@
 int ps3_repository_read_region_total(u64 *region_total);
 int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
 	u64 *region_total);
+int ps3_repository_read_highmem_region_count(unsigned int *region_count);
+int ps3_repository_read_highmem_base(unsigned int region_index,
+	u64 *highmem_base);
+int ps3_repository_read_highmem_size(unsigned int region_index,
+	u64 *highmem_size);
+int ps3_repository_read_highmem_info(unsigned int region_index,
+	u64 *highmem_base, u64 *highmem_size);
+
+int ps3_repository_write_highmem_region_count(unsigned int region_count);
+int ps3_repository_write_highmem_base(unsigned int region_index,
+	u64 highmem_base);
+int ps3_repository_write_highmem_size(unsigned int region_index,
+	u64 highmem_size);
+int ps3_repository_write_highmem_info(unsigned int region_index,
+	u64 highmem_base, u64 highmem_size);
+int ps3_repository_delete_highmem_info(unsigned int region_index);
 
 /* repository pme info */
 
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index 7bdfea3..9b47ba7 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -779,6 +779,72 @@
 }
 
 /**
+ * ps3_repository_read_highmem_region_count - Read the number of highmem regions
+ *
+ * Bootloaders must arrange the repository nodes such that regions are indexed
+ * with a region_index from 0 to region_count-1.
+ */
+
+int ps3_repository_read_highmem_region_count(unsigned int *region_count)
+{
+	int result;
+	u64 v1 = 0;
+
+	result = read_node(PS3_LPAR_ID_CURRENT,
+		make_first_field("highmem", 0),
+		make_field("region", 0),
+		make_field("count", 0),
+		0,
+		&v1, NULL);
+	*region_count = v1;
+	return result;
+}
+
+
+int ps3_repository_read_highmem_base(unsigned int region_index,
+	u64 *highmem_base)
+{
+	return read_node(PS3_LPAR_ID_CURRENT,
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("base", 0),
+		0,
+		highmem_base, NULL);
+}
+
+int ps3_repository_read_highmem_size(unsigned int region_index,
+	u64 *highmem_size)
+{
+	return read_node(PS3_LPAR_ID_CURRENT,
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("size", 0),
+		0,
+		highmem_size, NULL);
+}
+
+/**
+ * ps3_repository_read_highmem_info - Read high memory region info
+ * @region_index: Region index, {0,..,region_count-1}.
+ * @highmem_base: High memory base address.
+ * @highmem_size: High memory size.
+ *
+ * Bootloaders that preallocate highmem regions must place the
+ * region info into the repository at these well known nodes.
+ */
+
+int ps3_repository_read_highmem_info(unsigned int region_index,
+	u64 *highmem_base, u64 *highmem_size)
+{
+	int result;
+
+	*highmem_base = 0;
+	result = ps3_repository_read_highmem_base(region_index, highmem_base);
+	return result ? result
+		: ps3_repository_read_highmem_size(region_index, highmem_size);
+}
+
+/**
  * ps3_repository_read_num_spu_reserved - Number of physical spus reserved.
  * @num_spu: Number of physical spus.
  */
@@ -1002,6 +1068,138 @@
 			    lpar, rights);
 }
 
+#if defined(CONFIG_PS3_REPOSITORY_WRITE)
+
+static int create_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
+{
+	int result;
+
+	dump_node(0, n1, n2, n3, n4, v1, v2);
+
+	result = lv1_create_repository_node(n1, n2, n3, n4, v1, v2);
+
+	if (result) {
+		pr_devel("%s:%d: lv1_create_repository_node failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static int delete_node(u64 n1, u64 n2, u64 n3, u64 n4)
+{
+	int result;
+
+	dump_node(0, n1, n2, n3, n4, 0, 0);
+
+	result = lv1_delete_repository_node(n1, n2, n3, n4);
+
+	if (result) {
+		pr_devel("%s:%d: lv1_delete_repository_node failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
+{
+	int result;
+
+	result = create_node(n1, n2, n3, n4, v1, v2);
+
+	if (!result)
+		return 0;
+
+	result = lv1_write_repository_node(n1, n2, n3, n4, v1, v2);
+
+	if (result) {
+		pr_devel("%s:%d: lv1_write_repository_node failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+int ps3_repository_write_highmem_region_count(unsigned int region_count)
+{
+	int result;
+	u64 v1 = (u64)region_count;
+
+	result = write_node(
+		make_first_field("highmem", 0),
+		make_field("region", 0),
+		make_field("count", 0),
+		0,
+		v1, 0);
+	return result;
+}
+
+int ps3_repository_write_highmem_base(unsigned int region_index,
+	u64 highmem_base)
+{
+	return write_node(
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("base", 0),
+		0,
+		highmem_base, 0);
+}
+
+int ps3_repository_write_highmem_size(unsigned int region_index,
+	u64 highmem_size)
+{
+	return write_node(
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("size", 0),
+		0,
+		highmem_size, 0);
+}
+
+int ps3_repository_write_highmem_info(unsigned int region_index,
+	u64 highmem_base, u64 highmem_size)
+{
+	int result;
+
+	result = ps3_repository_write_highmem_base(region_index, highmem_base);
+	return result ? result
+		: ps3_repository_write_highmem_size(region_index, highmem_size);
+}
+
+static int ps3_repository_delete_highmem_base(unsigned int region_index)
+{
+	return delete_node(
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("base", 0),
+		0);
+}
+
+static int ps3_repository_delete_highmem_size(unsigned int region_index)
+{
+	return delete_node(
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("size", 0),
+		0);
+}
+
+int ps3_repository_delete_highmem_info(unsigned int region_index)
+{
+	int result;
+
+	result = ps3_repository_delete_highmem_base(region_index);
+	result += ps3_repository_delete_highmem_size(region_index);
+
+	return result ? -1 : 0;
+}
+
+#endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */
+
 #if defined(DEBUG)
 
 int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 178a5f3..837cf49 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -67,7 +67,7 @@
 
 	  This option will only enable the IO event platform code. You
 	  will still need to enable or compile the actual drivers
-	  that use this infrastruture to handle IO event interrupts.
+	  that use this infrastructure to handle IO event interrupts.
 
 	  Say Y if you are unsure.
 
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index a75e37d..ecd394c 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -489,7 +489,7 @@
 	 * a stack trace will help the device-driver authors figure
 	 * out what happened.  So print that out.
 	 */
-	dump_stack();
+	WARN(1, "EEH: failure detected\n");
 	return 1;
 
 dn_unlock:
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index 342797f..13e8cc4 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -22,12 +22,12 @@
 
 static inline u8 get_cede_latency_hint(void)
 {
-	return get_lppaca()->gpr5_dword.fields.cede_latency_hint;
+	return get_lppaca()->cede_latency_hint;
 }
 
 static inline void set_cede_latency_hint(u8 latency_hint)
 {
-	get_lppaca()->gpr5_dword.fields.cede_latency_hint = latency_hint;
+	get_lppaca()->cede_latency_hint = latency_hint;
 }
 
 static inline long cede_processor(void)
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 168651a..7b3bf76 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -103,11 +103,13 @@
 {
 	return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb);
 }
+EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_register);
 
 void pSeries_reconfig_notifier_unregister(struct notifier_block *nb)
 {
 	blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb);
 }
+EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_unregister);
 
 int pSeries_reconfig_notify(unsigned long action, void *p)
 {
@@ -426,6 +428,7 @@
 static int do_update_property(char *buf, size_t bufsize)
 {
 	struct device_node *np;
+	struct pSeries_reconfig_prop_update upd_value;
 	unsigned char *value;
 	char *name, *end, *next_prop;
 	int rc, length;
@@ -454,6 +457,10 @@
 		return -ENODEV;
 	}
 
+	upd_value.node = np;
+	upd_value.property = newprop;
+	pSeries_reconfig_notify(PSERIES_UPDATE_PROPERTY, &upd_value);
+
 	rc = prom_update_property(np, newprop, oldprop);
 	if (rc)
 		return rc;
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
index 1c2d7af..82c6702 100644
--- a/arch/powerpc/sysdev/ppc4xx_msi.c
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -28,10 +28,11 @@
 #include <linux/of_platform.h>
 #include <linux/interrupt.h>
 #include <linux/export.h>
+#include <linux/kernel.h>
 #include <asm/prom.h>
 #include <asm/hw_irq.h>
 #include <asm/ppc-pci.h>
-#include <boot/dcr.h>
+#include <asm/dcr.h>
 #include <asm/dcr-regs.h>
 #include <asm/msi_bitmap.h>
 
@@ -43,13 +44,14 @@
 #define PEIH_FLUSH0	0x30
 #define PEIH_FLUSH1	0x38
 #define PEIH_CNTRST	0x48
-#define NR_MSI_IRQS	4
+
+static int msi_irqs;
 
 struct ppc4xx_msi {
 	u32 msi_addr_lo;
 	u32 msi_addr_hi;
 	void __iomem *msi_regs;
-	int msi_virqs[NR_MSI_IRQS];
+	int *msi_virqs;
 	struct msi_bitmap bitmap;
 	struct device_node *msi_dev;
 };
@@ -61,7 +63,7 @@
 {
 	int err;
 
-	err = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+	err = msi_bitmap_alloc(&msi_data->bitmap, msi_irqs,
 			      dev->dev.of_node);
 	if (err)
 		return err;
@@ -83,6 +85,11 @@
 	struct msi_desc *entry;
 	struct ppc4xx_msi *msi_data = &ppc4xx_msi;
 
+	msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int),
+					    GFP_KERNEL);
+	if (!msi_data->msi_virqs)
+		return -ENOMEM;
+
 	list_for_each_entry(entry, &dev->msi_list, list) {
 		int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
 		if (int_no >= 0)
@@ -150,12 +157,11 @@
 	if (!sdr_addr)
 		return -1;
 
-	SDR0_WRITE(sdr_addr, (u64)res.start >> 32);	 /*HIGH addr */
-	SDR0_WRITE(sdr_addr + 1, res.start & 0xFFFFFFFF); /* Low addr */
-
+	mtdcri(SDR0, *sdr_addr, upper_32_bits(res.start));	/*HIGH addr */
+	mtdcri(SDR0, *sdr_addr + 1, lower_32_bits(res.start));	/* Low addr */
 
 	msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi");
-	if (msi->msi_dev)
+	if (!msi->msi_dev)
 		return -ENODEV;
 
 	msi->msi_regs = of_iomap(msi->msi_dev, 0);
@@ -167,9 +173,12 @@
 		(u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs));
 
 	msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL);
-	msi->msi_addr_hi = 0x0;
-	msi->msi_addr_lo = (u32) msi_phys;
-	dev_dbg(&dev->dev, "PCIE-MSI: msi address 0x%x\n", msi->msi_addr_lo);
+	if (!msi_virt)
+		return -ENOMEM;
+	msi->msi_addr_hi = upper_32_bits(msi_phys);
+	msi->msi_addr_lo = lower_32_bits(msi_phys & 0xffffffff);
+	dev_dbg(&dev->dev, "PCIE-MSI: msi address high 0x%x, low 0x%x\n",
+		msi->msi_addr_hi, msi->msi_addr_lo);
 
 	/* Progam the Interrupt handler Termination addr registers */
 	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
@@ -185,6 +194,8 @@
 	out_be32(msi->msi_regs + PEIH_MSIED, *msi_data);
 	out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask);
 
+	dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
+
 	return 0;
 }
 
@@ -194,7 +205,7 @@
 	int i;
 	int virq;
 
-	for (i = 0; i < NR_MSI_IRQS; i++) {
+	for (i = 0; i < msi_irqs; i++) {
 		virq = msi->msi_virqs[i];
 		if (virq != NO_IRQ)
 			irq_dispose_mapping(virq);
@@ -215,8 +226,6 @@
 	struct resource res;
 	int err = 0;
 
-	msi = &ppc4xx_msi;/*keep the msi data for further use*/
-
 	dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n");
 
 	msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
@@ -234,6 +243,10 @@
 		goto error_out;
 	}
 
+	msi_irqs = of_irq_count(dev->dev.of_node);
+	if (!msi_irqs)
+		return -ENODEV;
+
 	if (ppc4xx_setup_pcieh_hw(dev, res, msi))
 		goto error_out;
 
@@ -242,6 +255,7 @@
 		dev_err(&dev->dev, "Error allocating MSI bitmap\n");
 		goto error_out;
 	}
+	ppc4xx_msi = *msi;
 
 	ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
 	ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index d499b30..6cbf313 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -141,9 +141,6 @@
 extern void release_thread(struct task_struct *);
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 /*
  * Return saved PC of a blocked thread.
  */
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index ab64bdb..6542652 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -173,11 +173,14 @@
 
 static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
 {
+	struct user_namespace *user_ns = current_user_ns();
 	int i;
 	u16 group;
+	kgid_t kgid;
 
 	for (i = 0; i < group_info->ngroups; i++) {
-		group = (u16)GROUP_AT(group_info, i);
+		kgid = GROUP_AT(group_info, i);
+		group = (u16)from_kgid_munged(user_ns, kgid);
 		if (put_user(group, grouplist+i))
 			return -EFAULT;
 	}
@@ -187,13 +190,20 @@
 
 static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
 {
+	struct user_namespace *user_ns = current_user_ns();
 	int i;
 	u16 group;
+	kgid_t kgid;
 
 	for (i = 0; i < group_info->ngroups; i++) {
 		if (get_user(group, grouplist+i))
 			return  -EFAULT;
-		GROUP_AT(group_info, i) = (gid_t)group;
+
+		kgid = make_kgid(user_ns, (gid_t)group);
+		if (!gid_valid(kgid))
+			return -EINVAL;
+
+		GROUP_AT(group_info, i) = kgid;
 	}
 
 	return 0;
@@ -537,8 +547,8 @@
 	tmp.__st_ino = (u32)stat->ino;
 	tmp.st_mode = stat->mode;
 	tmp.st_nlink = (unsigned int)stat->nlink;
-	tmp.st_uid = stat->uid;
-	tmp.st_gid = stat->gid;
+	tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
+	tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
 	tmp.st_rdev = huge_encode_dev(stat->rdev);
 	tmp.st_size = stat->size;
 	tmp.st_blksize = (u32)stat->blksize;
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 8a4e2b7..f626232 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -59,15 +59,8 @@
 SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask)
 {
 	sigset_t blocked;
-
-	current->saved_sigmask = current->blocked;
-	mask &= _BLOCKABLE;
 	siginitset(&blocked, mask);
-	set_current_blocked(&blocked);
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule();
-	set_restore_sigmask();
-	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 SYSCALL_DEFINE3(sigaction, int, sig, const struct old_sigaction __user *, act,
diff --git a/arch/score/include/asm/processor.h b/arch/score/include/asm/processor.h
index 7e22f21..ab3aceb 100644
--- a/arch/score/include/asm/processor.h
+++ b/arch/score/include/asm/processor.h
@@ -26,7 +26,6 @@
 
 #define cpu_relax()		barrier()
 #define release_thread(thread)	do {} while (0)
-#define prepare_to_copy(tsk)	do {} while (0)
 
 /*
  * User space process size: 2GB. This is hardcoded into a few places,
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c
index aa57440..d4a49011 100644
--- a/arch/score/kernel/signal.c
+++ b/arch/score/kernel/signal.c
@@ -28,6 +28,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/uaccess.h>
+#include <linux/tracehook.h>
 
 #include <asm/cacheflush.h>
 #include <asm/syscalls.h>
@@ -152,6 +153,9 @@
 	stack_t st;
 	int sig;
 
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
 	frame = (struct rt_sigframe __user *) regs->regs[0];
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -159,10 +163,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext);
 	if (sig < 0)
@@ -236,9 +237,7 @@
 	return 0;
 
 give_sigsegv:
-	if (signr == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-	force_sig(SIGSEGV, current);
+	force_sigsegv(signr, current);
 	return -EFAULT;
 }
 
@@ -272,12 +271,8 @@
 	 */
 	ret = setup_rt_frame(ka, regs, sig, oldset, info);
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked, sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	if (ret == 0)
+		block_sigmask(ka, sig);
 
 	return ret;
 }
@@ -356,6 +351,12 @@
 				__u32 thread_info_flags)
 {
 	/* deal with pending signal delivery */
-	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+	if (thread_info_flags & _TIF_SIGPENDING)
 		do_signal(regs);
+	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+		clear_thread_flag(TIF_NOTIFY_RESUME);
+		tracehook_notify_resume(regs);
+		if (current->replacement_session_keyring)
+			key_replace_session_keyring();
+	}
 }
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 04a8cb4..3e723aa 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -155,7 +155,8 @@
 
 config NO_IOPORT
 	def_bool !PCI
-	depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN
+	depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN && \
+		   !SH_HP6XX && !SH_SOLUTION_ENGINE
 
 config IO_TRAPPED
 	bool
@@ -286,6 +287,20 @@
 	select SYS_SUPPORTS_CMT
 	select SYS_SUPPORTS_MTU2
 
+config CPU_SUBTYPE_SH7264
+	bool "Support SH7264 processor"
+	select CPU_SH2A
+	select CPU_HAS_FPU
+	select SYS_SUPPORTS_CMT
+	select SYS_SUPPORTS_MTU2
+
+config CPU_SUBTYPE_SH7269
+	bool "Support SH7269 processor"
+	select CPU_SH2A
+	select CPU_HAS_FPU
+	select SYS_SUPPORTS_CMT
+	select SYS_SUPPORTS_MTU2
+
 config CPU_SUBTYPE_MXG
 	bool "Support MX-G processor"
 	select CPU_SH2A
@@ -425,6 +440,16 @@
 	help
 	  Select SH7724 if you have an SH-MobileR2R CPU.
 
+config CPU_SUBTYPE_SH7734
+	bool "Support SH7734 processor"
+	select CPU_SH4A
+	select CPU_SHX2
+	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select USB_ARCH_HAS_OHCI
+	select USB_ARCH_HAS_EHCI
+	help
+	  Select SH7734 if you have a SH4A SH7734 CPU.
+
 config CPU_SUBTYPE_SH7757
 	bool "Support SH7757 processor"
 	select CPU_SH4A
@@ -582,7 +607,9 @@
 config SH_CLK_CPG_LEGACY
 	depends on SH_CLK_CPG
 	def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \
-		      !CPU_SHX3 && !CPU_SUBTYPE_SH7757
+		      !CPU_SHX3 && !CPU_SUBTYPE_SH7757 && \
+		      !CPU_SUBTYPE_SH7734 && !CPU_SUBTYPE_SH7264 && \
+		      !CPU_SUBTYPE_SH7269
 
 source "kernel/time/Kconfig"
 
@@ -683,6 +710,20 @@
 
 	  If unsure, say N.
 
+config CC_STACKPROTECTOR
+	bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
+	depends on SUPERH32 && EXPERIMENTAL
+	help
+	  This option turns on the -fstack-protector GCC feature. This
+	  feature puts, at the beginning of functions, a canary value on
+	  the stack just before the return address, and validates
+	  the value just before actually returning.  Stack based buffer
+	  overflows (that need to overwrite this return address) now also
+	  overwrite the canary, which gets detected and the attack is then
+	  neutralized via a kernel panic.
+
+	  This feature requires gcc version 4.2 or above.
+
 config SMP
 	bool "Symmetric multi-processing support"
 	depends on SYS_SUPPORTS_SMP
diff --git a/arch/sh/Kconfig.cpu b/arch/sh/Kconfig.cpu
index ddf096c..770ff2d 100644
--- a/arch/sh/Kconfig.cpu
+++ b/arch/sh/Kconfig.cpu
@@ -1,7 +1,7 @@
 menu "Processor features"
 
 choice
-	prompt "Endianess selection" 
+	prompt "Endianness selection" 
 	default CPU_LITTLE_ENDIAN
 	help
 	  Some SuperH machines can be configured for either little or big
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index e14a676..46edf07 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -199,6 +199,10 @@
   KBUILD_CFLAGS += -fasynchronous-unwind-tables
 endif
 
+ifeq ($(CONFIG_CC_STACKPROTECTOR),y)
+  KBUILD_CFLAGS += -fstack-protector
+endif
+
 libs-$(CONFIG_SUPERH32)		:= arch/sh/lib/	$(libs-y)
 libs-$(CONFIG_SUPERH64)		:= arch/sh/lib64/ $(libs-y)
 
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index d893411..1f56b35 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -54,6 +54,7 @@
 	select SOLUTION_ENGINE
 	depends on CPU_SUBTYPE_SH7724
 	select ARCH_REQUIRE_GPIOLIB
+	select SND_SOC_AK4642 if SND_SIMPLE_CARD
 	help
 	  Select 7724 SolutionEngine if configuring for a Hitachi SH7724
 	  evaluation board.
@@ -133,7 +134,8 @@
 
 config SH_RSK
 	bool "Renesas Starter Kit"
-	depends on CPU_SUBTYPE_SH7201 || CPU_SUBTYPE_SH7203
+	depends on CPU_SUBTYPE_SH7201 || CPU_SUBTYPE_SH7203 || \
+	  CPU_SUBTYPE_SH7264 || CPU_SUBTYPE_SH7269
 	help
 	 Select this option if configuring for any of the RSK+ MCU
 	 evaluation platforms.
@@ -223,6 +225,7 @@
 	bool "EcoVec"
 	depends on CPU_SUBTYPE_SH7724
 	select ARCH_REQUIRE_GPIOLIB
+	select SND_SOC_DA7210 if SND_SIMPLE_CARD
 	help
 	  Renesas "R0P7724LC0011/21RL (EcoVec)" support.
 
@@ -338,8 +341,6 @@
 	help
 	  Select AP-SH4AD-0A if configuring for an ALPHAPROJECT AP-SH4AD-0A.
 
-endmenu
-
 source "arch/sh/boards/mach-r2d/Kconfig"
 source "arch/sh/boards/mach-highlander/Kconfig"
 source "arch/sh/boards/mach-sdk7780/Kconfig"
@@ -359,3 +360,5 @@
 endmenu
 
 endif
+
+endmenu
diff --git a/arch/sh/boards/board-edosk7705.c b/arch/sh/boards/board-edosk7705.c
index 541d8a2..5e24c17 100644
--- a/arch/sh/boards/board-edosk7705.c
+++ b/arch/sh/boards/board-edosk7705.c
@@ -13,6 +13,7 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/smc91x.h>
+#include <linux/sh_intc.h>
 #include <asm/machvec.h>
 #include <asm/sizes.h>
 
@@ -20,7 +21,7 @@
 #define SMC_IO_OFFSET	0x300
 #define SMC_IOADDR	(SMC_IOBASE + SMC_IO_OFFSET)
 
-#define ETHERNET_IRQ	0x09
+#define ETHERNET_IRQ	evt2irq(0x320)
 
 static void __init sh_edosk7705_init_irq(void)
 {
@@ -73,6 +74,5 @@
  */
 static struct sh_machine_vector mv_edosk7705 __initmv = {
 	.mv_name		= "EDOSK7705",
-	.mv_nr_irqs		= 80,
 	.mv_init_irq		= sh_edosk7705_init_irq,
 };
diff --git a/arch/sh/boards/board-edosk7760.c b/arch/sh/boards/board-edosk7760.c
index e9656a2..bab5b95 100644
--- a/arch/sh/boards/board-edosk7760.c
+++ b/arch/sh/boards/board-edosk7760.c
@@ -23,6 +23,7 @@
 #include <linux/platform_device.h>
 #include <linux/smc91x.h>
 #include <linux/interrupt.h>
+#include <linux/sh_intc.h>
 #include <linux/i2c.h>
 #include <linux/mtd/physmap.h>
 #include <asm/machvec.h>
@@ -40,8 +41,6 @@
 #define SMC_IO_OFFSET	0x300
 #define SMC_IOADDR	(SMC_IOBASE + SMC_IO_OFFSET)
 
-#define ETHERNET_IRQ	5
-
 /* NOR flash */
 static struct mtd_partition edosk7760_nor_flash_partitions[] = {
 	{
@@ -99,8 +98,8 @@
 		.end	= SH7760_I2C1_MMIOEND,
 		.flags	= IORESOURCE_MEM,
 	},{
-		.start	= SH7760_I2C1_IRQ,
-		.end	= SH7760_I2C1_IRQ,
+		.start	= evt2irq(0x9e0),
+		.end	= evt2irq(0x9e0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -122,8 +121,8 @@
 		.end	= SH7760_I2C0_MMIOEND,
 		.flags	= IORESOURCE_MEM,
 	}, {
-		.start	= SH7760_I2C0_IRQ,
-		.end	= SH7760_I2C0_IRQ,
+		.start	= evt2irq(0x9c0),
+		.end	= evt2irq(0x9c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -150,8 +149,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= ETHERNET_IRQ,
-		.end	= ETHERNET_IRQ,
+		.start	= evt2irq(0x2a0),
+		.end	= evt2irq(0x2a0),
 		.flags	= IORESOURCE_IRQ ,
 	}
 };
@@ -189,5 +188,4 @@
  */
 struct sh_machine_vector mv_edosk7760 __initmv = {
 	.mv_name	= "EDOSK7760",
-	.mv_nr_irqs	= 128,
 };
diff --git a/arch/sh/boards/board-espt.c b/arch/sh/boards/board-espt.c
index b3ae9d3..6cba0a7 100644
--- a/arch/sh/boards/board-espt.c
+++ b/arch/sh/boards/board-espt.c
@@ -14,6 +14,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/io.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <asm/machvec.h>
 #include <asm/sizes.h>
 
@@ -71,7 +72,7 @@
 		.flags  = IORESOURCE_MEM,
 	}, {
 
-		.start  = 57,   /* irq number */
+		.start  = evt2irq(0x920),   /* irq number */
 		.flags  = IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/boards/board-magicpanelr2.c b/arch/sh/boards/board-magicpanelr2.c
index b2ca1d9..90568f9 100644
--- a/arch/sh/boards/board-magicpanelr2.c
+++ b/arch/sh/boards/board-magicpanelr2.c
@@ -19,6 +19,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/map.h>
+#include <linux/sh_intc.h>
 #include <mach/magicpanelr2.h>
 #include <asm/heartbeat.h>
 #include <cpu/sh7720.h>
@@ -245,8 +246,8 @@
 		.flags		= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start		= 35,
-		.end		= 35,
+		.start		= evt2irq(0x660),
+		.end		= evt2irq(0x660),
 		.flags		= IORESOURCE_IRQ,
 	},
 };
@@ -358,17 +359,17 @@
 {
 	plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-5 */
 
-	irq_set_irq_type(32, IRQ_TYPE_LEVEL_LOW);    /* IRQ0 CAN1 */
-	irq_set_irq_type(33, IRQ_TYPE_LEVEL_LOW);    /* IRQ1 CAN2 */
-	irq_set_irq_type(34, IRQ_TYPE_LEVEL_LOW);    /* IRQ2 CAN3 */
-	irq_set_irq_type(35, IRQ_TYPE_LEVEL_LOW);    /* IRQ3 SMSC9115 */
-	irq_set_irq_type(36, IRQ_TYPE_EDGE_RISING);  /* IRQ4 touchscreen */
-	irq_set_irq_type(37, IRQ_TYPE_EDGE_FALLING); /* IRQ5 touchscreen */
+	irq_set_irq_type(evt2irq(0x600), IRQ_TYPE_LEVEL_LOW);    /* IRQ0 CAN1 */
+	irq_set_irq_type(evt2irq(0x620), IRQ_TYPE_LEVEL_LOW);    /* IRQ1 CAN2 */
+	irq_set_irq_type(evt2irq(0x640), IRQ_TYPE_LEVEL_LOW);    /* IRQ2 CAN3 */
+	irq_set_irq_type(evt2irq(0x660), IRQ_TYPE_LEVEL_LOW);    /* IRQ3 SMSC9115 */
+	irq_set_irq_type(evt2irq(0x680), IRQ_TYPE_EDGE_RISING);  /* IRQ4 touchscreen */
+	irq_set_irq_type(evt2irq(0x6a0), IRQ_TYPE_EDGE_FALLING); /* IRQ5 touchscreen */
 
-	intc_set_priority(32, 13);		/* IRQ0 CAN1 */
-	intc_set_priority(33, 13);		/* IRQ0 CAN2 */
-	intc_set_priority(34, 13);		/* IRQ0 CAN3 */
-	intc_set_priority(35, 6);		/* IRQ3 SMSC9115 */
+	intc_set_priority(evt2irq(0x600), 13);		/* IRQ0 CAN1 */
+	intc_set_priority(evt2irq(0x620), 13);		/* IRQ0 CAN2 */
+	intc_set_priority(evt2irq(0x640), 13);		/* IRQ0 CAN3 */
+	intc_set_priority(evt2irq(0x660), 6);		/* IRQ3 SMSC9115 */
 }
 
 /*
diff --git a/arch/sh/boards/board-polaris.c b/arch/sh/boards/board-polaris.c
index 5948663..37d03c0 100644
--- a/arch/sh/boards/board-polaris.c
+++ b/arch/sh/boards/board-polaris.c
@@ -141,6 +141,5 @@
 
 static struct sh_machine_vector mv_polaris __initmv = {
 	.mv_name		= "Polaris",
-	.mv_nr_irqs		= 61,
 	.mv_init_irq		= init_polaris_irq,
 };
diff --git a/arch/sh/boards/board-secureedge5410.c b/arch/sh/boards/board-secureedge5410.c
index 03820c3..98b3620 100644
--- a/arch/sh/boards/board-secureedge5410.c
+++ b/arch/sh/boards/board-secureedge5410.c
@@ -71,6 +71,5 @@
  */
 static struct sh_machine_vector mv_snapgear __initmv = {
 	.mv_name		= "SnapGear SecureEdge5410",
-	.mv_nr_irqs		= 72,
 	.mv_init_irq		= init_snapgear_IRQ,
 };
diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c
index 24b1ee4..5087f8b 100644
--- a/arch/sh/boards/board-sh7757lcr.c
+++ b/arch/sh/boards/board-sh7757lcr.c
@@ -19,6 +19,7 @@
 #include <linux/mmc/sh_mmcif.h>
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <linux/usb/renesas_usbhs.h>
 #include <cpu/sh7757.h>
 #include <asm/heartbeat.h>
@@ -65,8 +66,8 @@
 		.end    = 0xfef001ff,
 		.flags  = IORESOURCE_MEM,
 	}, {
-		.start  = 84,
-		.end    = 84,
+		.start  = evt2irq(0xc80),
+		.end    = evt2irq(0xc80),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -94,8 +95,8 @@
 		.end    = 0xfef009ff,
 		.flags  = IORESOURCE_MEM,
 	}, {
-		.start  = 84,
-		.end    = 84,
+		.start  = evt2irq(0xc80),
+		.end    = evt2irq(0xc80),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -139,8 +140,8 @@
 		.end    = 0xfee01fff,
 		.flags  = IORESOURCE_MEM,
 	}, {
-		.start  = 315,
-		.end    = 315,
+		.start  = evt2irq(0x2960),
+		.end    = evt2irq(0x2960),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -174,8 +175,8 @@
 		.end    = 0xfee01fff,
 		.flags  = IORESOURCE_MEM,
 	}, {
-		.start  = 316,
-		.end    = 316,
+		.start  = evt2irq(0x2980),
+		.end    = evt2irq(0x2980),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -206,11 +207,11 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 211,
+		.start	= evt2irq(0x1c60),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
-		.start	= 212,
+		.start	= evt2irq(0x1c80),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -248,7 +249,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 20,
+		.start  = evt2irq(0x480),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -284,8 +285,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 50,
-		.end	= 50,
+		.start	= evt2irq(0x840),
+		.end	= evt2irq(0x840),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/boards/board-sh7785lcr.c b/arch/sh/boards/board-sh7785lcr.c
index d0d6221..2c4771e 100644
--- a/arch/sh/boards/board-sh7785lcr.c
+++ b/arch/sh/boards/board-sh7785lcr.c
@@ -20,6 +20,7 @@
 #include <linux/i2c-pca-platform.h>
 #include <linux/i2c-algo-pca.h>
 #include <linux/usb/r8a66597.h>
+#include <linux/sh_intc.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/clk.h>
@@ -105,8 +106,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 2,
-		.end	= 2,
+		.start	= evt2irq(0x240),
+		.end	= evt2irq(0x240),
 		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
 	},
 };
@@ -135,7 +136,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[2]	= {
-		.start	= 10,
+		.start	= evt2irq(0x340),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -223,8 +224,8 @@
 		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
 	},
 	[1] = {
-		.start	= 12,
-		.end	= 12,
+		.start	= evt2irq(0x380),
+		.end	= evt2irq(0x380),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -236,8 +237,8 @@
 		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
 	},
 	[1] = {
-		.start	= 12,
-		.end	= 12,
+		.start	= evt2irq(0x380),
+		.end	= evt2irq(0x380),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/boards/board-urquell.c b/arch/sh/boards/board-urquell.c
index 24e3316..b52abcc 100644
--- a/arch/sh/boards/board-urquell.c
+++ b/arch/sh/boards/board-urquell.c
@@ -20,6 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
+#include <linux/sh_intc.h>
 #include <mach/urquell.h>
 #include <cpu/sh7786.h>
 #include <asm/heartbeat.h>
@@ -78,7 +79,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 11,
+		.start  = evt2irq(0x360),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 8cf02e3..f33ebf4 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -23,6 +23,7 @@
 #include <linux/smsc911x.h>
 #include <linux/gpio.h>
 #include <linux/videodev2.h>
+#include <linux/sh_intc.h>
 #include <media/ov772x.h>
 #include <media/soc_camera.h>
 #include <media/soc_camera_platform.h>
@@ -47,8 +48,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 35,
-		.end	= 35,
+		.start	= evt2irq(0x660),
+		.end	= evt2irq(0x660),
 		.flags	= IORESOURCE_IRQ,
 	}
 };
@@ -166,7 +167,7 @@
 		__raw_writew(0, FPGA_BKLREG);
 		gpio_set_value(GPIO_PTS3, 1);
 	}
-	
+
 	return 0;
 }
 
@@ -236,7 +237,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 28,
+		.start	= evt2irq(0x580),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -404,7 +405,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 52,
+		.start  = evt2irq(0x880),
 		.flags  = IORESOURCE_IRQ,
 	},
 	[2] = {
@@ -430,7 +431,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 100,
+		.start	= evt2irq(0xe80),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -457,7 +458,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 23,
+		.start	= evt2irq(0x4e0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/boards/mach-cayman/setup.c b/arch/sh/boards/mach-cayman/setup.c
index e89e8e1..340fd40 100644
--- a/arch/sh/boards/mach-cayman/setup.c
+++ b/arch/sh/boards/mach-cayman/setup.c
@@ -181,7 +181,6 @@
 
 static struct sh_machine_vector mv_cayman __initmv = {
 	.mv_name		= "Hitachi Cayman",
-	.mv_nr_irqs		= 64,
 	.mv_ioport_map		= cayman_ioport_map,
 	.mv_init_irq		= init_cayman_irq,
 };
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index d12fe9d..4158d70 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -29,9 +29,11 @@
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <linux/videodev2.h>
 #include <video/sh_mobile_lcdc.h>
 #include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 #include <media/sh_mobile_ceu.h>
 #include <media/soc_camera.h>
 #include <media/tw9910.h>
@@ -137,7 +139,7 @@
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start = 91,
+		.start = evt2irq(0xd60),
 		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
 	},
 };
@@ -178,8 +180,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 65,
-		.end	= 65,
+		.start	= evt2irq(0xa20),
+		.end	= evt2irq(0xa20),
 		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
 	},
 };
@@ -214,8 +216,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 66,
-		.end	= 66,
+		.start	= evt2irq(0xa40),
+		.end	= evt2irq(0xa40),
 		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
 	},
 };
@@ -261,8 +263,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 66,
-		.end	= 66,
+		.start	= evt2irq(0xa40),
+		.end	= evt2irq(0xa40),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -348,7 +350,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 106,
+		.start	= evt2irq(0xf40),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -375,7 +377,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 52,
+		.start  = evt2irq(0x880),
 		.flags  = IORESOURCE_IRQ,
 	},
 	[2] = {
@@ -406,7 +408,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 63,
+		.start  = evt2irq(0x9e0),
 		.flags  = IORESOURCE_IRQ,
 	},
 	[2] = {
@@ -437,7 +439,7 @@
 	},
 	{
 		I2C_BOARD_INFO("lis3lv02d", 0x1c),
-		.irq = 33,
+		.irq = evt2irq(0x620),
 	}
 };
 
@@ -463,7 +465,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 79,
+		.start  = evt2irq(0xbe0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -479,7 +481,8 @@
 };
 
 /* TouchScreen */
-#define IRQ0 32
+#define IRQ0 evt2irq(0x600)
+
 static int ts_get_pendown_state(void)
 {
 	int val = 0;
@@ -544,7 +547,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 100,
+		.start  = evt2irq(0xe80),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -588,7 +591,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 23,
+		.start  = evt2irq(0x4e0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -653,7 +656,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 84,
+		.start	= evt2irq(0xc80),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -794,7 +797,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 108,
+		.start  = evt2irq(0xf80),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -809,6 +812,30 @@
 	},
 };
 
+static struct asoc_simple_dai_init_info fsi_da7210_init_info = {
+	.fmt		= SND_SOC_DAIFMT_I2S,
+	.codec_daifmt	= SND_SOC_DAIFMT_CBM_CFM,
+	.cpu_daifmt	= SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct asoc_simple_card_info fsi_da7210_info = {
+	.name		= "DA7210",
+	.card		= "FSIB-DA7210",
+	.cpu_dai	= "fsib-dai",
+	.codec		= "da7210.0-001a",
+	.platform	= "sh_fsi.0",
+	.codec_dai	= "da7210-hifi",
+	.init		= &fsi_da7210_init_info,
+};
+
+static struct platform_device fsi_da7210_device = {
+	.name	= "asoc-simple-card",
+	.dev	= {
+		.platform_data	= &fsi_da7210_info,
+	},
+};
+
+
 /* IrDA */
 static struct resource irda_resources[] = {
 	[0] = {
@@ -818,7 +845,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 20,
+		.start  = evt2irq(0x480),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -855,7 +882,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 55,
+		.start  = evt2irq(0x8e0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -891,12 +918,12 @@
 	},
 	[1] = {
 		/* MMC2I */
-		.start	= 29,
+		.start	= evt2irq(0x5a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
 		/* MMC3I */
-		.start	= 30,
+		.start	= evt2irq(0x5c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -945,6 +972,7 @@
 	&camera_devices[1],
 	&camera_devices[2],
 	&fsi_device,
+	&fsi_da7210_device,
 	&irda_device,
 	&vou_device,
 #if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
diff --git a/arch/sh/boards/mach-hp6xx/setup.c b/arch/sh/boards/mach-hp6xx/setup.c
index 8c9add5..05797b3 100644
--- a/arch/sh/boards/mach-hp6xx/setup.c
+++ b/arch/sh/boards/mach-hp6xx/setup.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
+#include <linux/sh_intc.h>
 #include <sound/sh_dac_audio.h>
 #include <asm/hd64461.h>
 #include <asm/io.h>
@@ -35,7 +36,7 @@
 		.flags = IORESOURCE_MEM,
 	},
 	[2] = {
-		.start = 77,
+		.start = evt2irq(0xba0),
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -168,8 +169,6 @@
 static struct sh_machine_vector mv_hp6xx __initmv = {
 	.mv_name = "hp6xx",
 	.mv_setup = hp6xx_setup,
-	/* IRQ's : CPU(64) + CCHIP(16) + FREE_TO_USE(6) */
-	.mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM + 6,
 	/* Enable IRQ0 -> IRQ3 in IRQ_MODE */
 	.mv_init_irq = hp6xx_init_irq,
 };
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index d04a55d..158c917 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -23,6 +23,7 @@
 #include <linux/i2c.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/videodev2.h>
+#include <linux/sh_intc.h>
 #include <media/rj54n1cb0c.h>
 #include <media/soc_camera.h>
 #include <media/sh_mobile_ceu.h>
@@ -110,7 +111,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 79,
+		.start  = evt2irq(0xbe0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -175,7 +176,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 106,
+		.start	= evt2irq(0xf40),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -200,8 +201,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 65,
-		.end	= 65,
+		.start	= evtirq(0xa20),
+		.end	= evtirq(0xa20),
 		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
 	},
 };
@@ -230,8 +231,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 52,
-		.end  = 52,
+		.start  = evt2irq(0x880),
+		.end	= evt2irq(0x880),
 		.flags  = IORESOURCE_IRQ,
 	},
 	[2] = {
@@ -348,7 +349,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 100,
+		.start  = evt2irq(0xe80),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/boards/mach-lboxre2/setup.c b/arch/sh/boards/mach-lboxre2/setup.c
index 79b4e0d7..6660622 100644
--- a/arch/sh/boards/mach-lboxre2/setup.c
+++ b/arch/sh/boards/mach-lboxre2/setup.c
@@ -79,6 +79,5 @@
  */
 static struct sh_machine_vector mv_lboxre2 __initmv = {
 	.mv_name		= "L-BOX RE2",
-	.mv_nr_irqs		= 72,
 	.mv_init_irq		= init_lboxre2_IRQ,
 };
diff --git a/arch/sh/boards/mach-microdev/setup.c b/arch/sh/boards/mach-microdev/setup.c
index d8a7472..6c66ee4 100644
--- a/arch/sh/boards/mach-microdev/setup.c
+++ b/arch/sh/boards/mach-microdev/setup.c
@@ -194,7 +194,6 @@
  */
 static struct sh_machine_vector mv_sh4202_microdev __initmv = {
 	.mv_name		= "SH4-202 MicroDev",
-	.mv_nr_irqs		= 72,
 	.mv_ioport_map		= microdev_ioport_map,
 	.mv_init_irq		= init_microdev_irq,
 };
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index ff6f69c..34cd0c5 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/videodev2.h>
+#include <linux/sh_intc.h>
 #include <video/sh_mobile_lcdc.h>
 #include <media/sh_mobile_ceu.h>
 #include <media/ov772x.h>
@@ -54,7 +55,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 32, /* IRQ0 */
+		.start  = evt2irq(0x600), /* IRQ0 */
 		.flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
 	},
 };
@@ -88,7 +89,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 79,
+		.start  = evt2irq(0xbe0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -285,7 +286,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 28,
+		.start	= evt2irq(0x580),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -368,7 +369,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 52,
+		.start  = evt2irq(0x880),
 		.flags  = IORESOURCE_IRQ,
 	},
 	[2] = {
@@ -394,7 +395,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 100,
+		.start	= evt2irq(0xe80),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -420,7 +421,7 @@
 	},
 	{
 		I2C_BOARD_INFO("migor_ts", 0x51),
-		.irq = 38, /* IRQ6 */
+		.irq = evt2irq(0x6c0), /* IRQ6 */
 	},
 	{
 		I2C_BOARD_INFO("wm8978", 0x1a),
diff --git a/arch/sh/boards/mach-rsk/Kconfig b/arch/sh/boards/mach-rsk/Kconfig
index aeff3b0..458a11f 100644
--- a/arch/sh/boards/mach-rsk/Kconfig
+++ b/arch/sh/boards/mach-rsk/Kconfig
@@ -13,6 +13,16 @@
 	select ARCH_REQUIRE_GPIOLIB
 	depends on CPU_SUBTYPE_SH7203
 
+config SH_RSK7264
+	bool "RSK2+SH7264"
+	select ARCH_REQUIRE_GPIOLIB
+	depends on CPU_SUBTYPE_SH7264
+
+config SH_RSK7269
+	bool "RSK2+SH7269"
+	select ARCH_REQUIRE_GPIOLIB
+	depends on CPU_SUBTYPE_SH7269
+
 endchoice
 
 endif
diff --git a/arch/sh/boards/mach-rsk/Makefile b/arch/sh/boards/mach-rsk/Makefile
index 498da75..6a4e1b5 100644
--- a/arch/sh/boards/mach-rsk/Makefile
+++ b/arch/sh/boards/mach-rsk/Makefile
@@ -1,2 +1,4 @@
 obj-y				:= setup.o
 obj-$(CONFIG_SH_RSK7203)	+= devices-rsk7203.o
+obj-$(CONFIG_SH_RSK7264)	+= devices-rsk7264.o
+obj-$(CONFIG_SH_RSK7269)	+= devices-rsk7269.o
diff --git a/arch/sh/boards/mach-rsk/devices-rsk7264.c b/arch/sh/boards/mach-rsk/devices-rsk7264.c
new file mode 100644
index 0000000..7251e37
--- /dev/null
+++ b/arch/sh/boards/mach-rsk/devices-rsk7264.c
@@ -0,0 +1,58 @@
+/*
+ * RSK+SH7264 Support.
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe
+ *
+ * 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/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/smsc911x.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+
+static struct smsc911x_platform_config smsc911x_config = {
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+	.flags		= SMSC911X_USE_16BIT | SMSC911X_SWAP_FIFO,
+};
+
+static struct resource smsc911x_resources[] = {
+	[0] = {
+		.start		= 0x28000000,
+		.end		= 0x280000ff,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= 65,
+		.end		= 65,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smsc911x_device = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smsc911x_resources),
+	.resource	= smsc911x_resources,
+	.dev		= {
+		.platform_data = &smsc911x_config,
+	},
+};
+
+static struct platform_device *rsk7264_devices[] __initdata = {
+	&smsc911x_device,
+};
+
+static int __init rsk7264_devices_setup(void)
+{
+	return platform_add_devices(rsk7264_devices,
+				    ARRAY_SIZE(rsk7264_devices));
+}
+device_initcall(rsk7264_devices_setup);
diff --git a/arch/sh/boards/mach-rsk/devices-rsk7269.c b/arch/sh/boards/mach-rsk/devices-rsk7269.c
new file mode 100644
index 0000000..4a54459
--- /dev/null
+++ b/arch/sh/boards/mach-rsk/devices-rsk7269.c
@@ -0,0 +1,60 @@
+/*
+ * RSK+SH7269 Support
+ *
+ * Copyright (C) 2012  Renesas Electronics Europe Ltd
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * 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/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/smsc911x.h>
+#include <linux/gpio.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+
+static struct smsc911x_platform_config smsc911x_config = {
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags		= SMSC911X_USE_16BIT | SMSC911X_SWAP_FIFO,
+};
+
+static struct resource smsc911x_resources[] = {
+	[0] = {
+		.start		= 0x24000000,
+		.end		= 0x240000ff,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= 85,
+		.end		= 85,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smsc911x_device = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smsc911x_resources),
+	.resource	= smsc911x_resources,
+	.dev		= {
+		.platform_data = &smsc911x_config,
+	},
+};
+
+static struct platform_device *rsk7269_devices[] __initdata = {
+	&smsc911x_device,
+};
+
+static int __init rsk7269_devices_setup(void)
+{
+	return platform_add_devices(rsk7269_devices,
+				    ARRAY_SIZE(rsk7269_devices));
+}
+device_initcall(rsk7269_devices_setup);
diff --git a/arch/sh/boards/mach-sdk7780/setup.c b/arch/sh/boards/mach-sdk7780/setup.c
index 4da38db..2241659 100644
--- a/arch/sh/boards/mach-sdk7780/setup.c
+++ b/arch/sh/boards/mach-sdk7780/setup.c
@@ -94,7 +94,6 @@
 static struct sh_machine_vector mv_se7780 __initmv = {
 	.mv_name        = "Renesas SDK7780-R3" ,
 	.mv_setup		= sdk7780_setup,
-	.mv_nr_irqs		= 111,
 	.mv_init_irq	= init_sdk7780_IRQ,
 };
 
diff --git a/arch/sh/boards/mach-se/7206/setup.c b/arch/sh/boards/mach-se/7206/setup.c
index 8ab8330..68883ec 100644
--- a/arch/sh/boards/mach-se/7206/setup.c
+++ b/arch/sh/boards/mach-se/7206/setup.c
@@ -90,7 +90,6 @@
 
 static struct sh_machine_vector mv_se __initmv = {
 	.mv_name		= "SolutionEngine",
-	.mv_nr_irqs		= 256,
 	.mv_init_irq		= init_se7206_IRQ,
 	.mv_mode_pins		= se7206_mode_pins,
 };
diff --git a/arch/sh/boards/mach-se/770x/setup.c b/arch/sh/boards/mach-se/770x/setup.c
index 31330c6..9759d6b 100644
--- a/arch/sh/boards/mach-se/770x/setup.c
+++ b/arch/sh/boards/mach-se/770x/setup.c
@@ -184,16 +184,5 @@
 static struct sh_machine_vector mv_se __initmv = {
 	.mv_name		= "SolutionEngine",
 	.mv_setup		= smsc_setup,
-#if defined(CONFIG_CPU_SH4)
-	.mv_nr_irqs		= 48,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
-	.mv_nr_irqs		= 32,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
-	.mv_nr_irqs		= 61,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
-	.mv_nr_irqs		= 86,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-	.mv_nr_irqs             = 104,
-#endif
 	.mv_init_irq		= init_se_IRQ,
 };
diff --git a/arch/sh/boards/mach-se/7721/setup.c b/arch/sh/boards/mach-se/7721/setup.c
index 7416ad7..a0b3dba 100644
--- a/arch/sh/boards/mach-se/7721/setup.c
+++ b/arch/sh/boards/mach-se/7721/setup.c
@@ -92,6 +92,5 @@
 struct sh_machine_vector mv_se7721 __initmv = {
 	.mv_name		= "Solution Engine 7721",
 	.mv_setup		= se7721_setup,
-	.mv_nr_irqs		= 109,
 	.mv_init_irq		= init_se7721_IRQ,
 };
diff --git a/arch/sh/boards/mach-se/7722/setup.c b/arch/sh/boards/mach-se/7722/setup.c
index e1963fe..8f7f055 100644
--- a/arch/sh/boards/mach-se/7722/setup.c
+++ b/arch/sh/boards/mach-se/7722/setup.c
@@ -16,6 +16,7 @@
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/smc91x.h>
+#include <linux/sh_intc.h>
 #include <mach-se/mach/se7722.h>
 #include <mach-se/mach/mrshpc.h>
 #include <asm/machvec.h>
@@ -114,7 +115,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 79,
+		.start  = evt2irq(0xbe0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index c540b16..ffbf5bc 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -24,10 +24,12 @@
 #include <linux/input/sh_keysc.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <linux/videodev2.h>
 #include <video/sh_mobile_lcdc.h>
 #include <media/sh_mobile_ceu.h>
 #include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 #include <asm/io.h>
 #include <asm/heartbeat.h>
 #include <asm/clock.h>
@@ -197,7 +199,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 106,
+		.start	= evt2irq(0xf40),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -224,7 +226,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 52,
+		.start  = evt2irq(0x880),
 		.flags  = IORESOURCE_IRQ,
 	},
 	[2] = {
@@ -255,7 +257,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 63,
+		.start  = evt2irq(0x9e0),
 		.flags  = IORESOURCE_IRQ,
 	},
 	[2] = {
@@ -289,7 +291,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 108,
+		.start  = evt2irq(0xf80),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -304,17 +306,25 @@
 	},
 };
 
-static struct fsi_ak4642_info fsi_ak4642_info = {
+static struct asoc_simple_dai_init_info fsi2_ak4642_init_info = {
+	.fmt		= SND_SOC_DAIFMT_LEFT_J,
+	.codec_daifmt	= SND_SOC_DAIFMT_CBM_CFM,
+	.cpu_daifmt	= SND_SOC_DAIFMT_CBS_CFS,
+	.sysclk		= 11289600,
+};
+
+static struct asoc_simple_card_info fsi_ak4642_info = {
 	.name		= "AK4642",
 	.card		= "FSIA-AK4642",
 	.cpu_dai	= "fsia-dai",
 	.codec		= "ak4642-codec.0-0012",
 	.platform	= "sh_fsi.0",
-	.id		= FSI_PORT_A,
+	.codec_dai	= "ak4642-hifi",
+	.init		= &fsi2_ak4642_init_info,
 };
 
 static struct platform_device fsi_ak4642_device = {
-	.name	= "fsi-ak4642-audio",
+	.name	= "asoc-simple-card",
 	.dev	= {
 		.platform_data	= &fsi_ak4642_info,
 	},
@@ -343,7 +353,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 79,
+		.start  = evt2irq(0xbe0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -366,7 +376,7 @@
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start = 91,
+		.start = evt2irq(0xd60),
 		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
 	},
 };
@@ -397,8 +407,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 65,
-		.end	= 65,
+		.start	= evt2irq(0xa20),
+		.end	= evt2irq(0xa20),
 		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
 	},
 };
@@ -426,8 +436,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 66,
-		.end	= 66,
+		.start	= evt2irq(0xa40),
+		.end	= evt2irq(0xa40),
 		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
 	},
 };
@@ -452,7 +462,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 100,
+		.start  = evt2irq(0xe80),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -481,7 +491,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 23,
+		.start  = evt2irq(0x4e0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -511,7 +521,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 20,
+		.start  = evt2irq(0x480),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -549,7 +559,7 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 55,
+		.start  = evt2irq(0x8e0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -595,6 +605,7 @@
 #define EEPROM_DATA 0xBA20600C
 #define EEPROM_STAT 0xBA206010
 #define EEPROM_STRT 0xBA206014
+
 static int __init sh_eth_is_eeprom_ready(void)
 {
 	int t = 10000;
@@ -651,7 +662,6 @@
 extern char ms7724se_sdram_leave_start;
 extern char ms7724se_sdram_leave_end;
 
-
 static int __init arch_setup(void)
 {
 	/* enable I2C device */
@@ -928,5 +938,4 @@
 static struct sh_machine_vector mv_ms7724se __initmv = {
 	.mv_name	= "ms7724se",
 	.mv_init_irq	= init_se7724_IRQ,
-	.mv_nr_irqs	= SE7724_FPGA_IRQ_BASE + SE7724_FPGA_IRQ_NR,
 };
diff --git a/arch/sh/boards/mach-se/7751/setup.c b/arch/sh/boards/mach-se/7751/setup.c
index 4ed60c5..820f4e7 100644
--- a/arch/sh/boards/mach-se/7751/setup.c
+++ b/arch/sh/boards/mach-se/7751/setup.c
@@ -55,6 +55,5 @@
  */
 static struct sh_machine_vector mv_7751se __initmv = {
 	.mv_name		= "7751 SolutionEngine",
-	.mv_nr_irqs		= 72,
 	.mv_init_irq		= init_7751se_IRQ,
 };
diff --git a/arch/sh/boards/mach-se/7780/setup.c b/arch/sh/boards/mach-se/7780/setup.c
index 6f7c207..ae5a1d8 100644
--- a/arch/sh/boards/mach-se/7780/setup.c
+++ b/arch/sh/boards/mach-se/7780/setup.c
@@ -110,6 +110,5 @@
 static struct sh_machine_vector mv_se7780 __initmv = {
 	.mv_name                = "Solution Engine 7780" ,
 	.mv_setup               = se7780_setup ,
-	.mv_nr_irqs		= 111 ,
 	.mv_init_irq		= init_se7780_IRQ,
 };
diff --git a/arch/sh/boards/mach-se/board-se7619.c b/arch/sh/boards/mach-se/board-se7619.c
index 82b6d4a..958bcd7 100644
--- a/arch/sh/boards/mach-se/board-se7619.c
+++ b/arch/sh/boards/mach-se/board-se7619.c
@@ -22,6 +22,5 @@
 
 static struct sh_machine_vector mv_se __initmv = {
 	.mv_name		= "SolutionEngine",
-	.mv_nr_irqs		= 108,
 	.mv_mode_pins		= se7619_mode_pins,
 };
diff --git a/arch/sh/boards/mach-sh03/setup.c b/arch/sh/boards/mach-sh03/setup.c
index d4f79b2..f582dab 100644
--- a/arch/sh/boards/mach-sh03/setup.c
+++ b/arch/sh/boards/mach-sh03/setup.c
@@ -101,6 +101,5 @@
 static struct sh_machine_vector mv_sh03 __initmv = {
 	.mv_name		= "Interface (CTP/PCI-SH03)",
 	.mv_setup		= sh03_setup,
-	.mv_nr_irqs		= 48,
 	.mv_init_irq		= init_sh03_IRQ,
 };
diff --git a/arch/sh/boards/mach-sh7763rdp/setup.c b/arch/sh/boards/mach-sh7763rdp/setup.c
index dd036f1..b7c7529 100644
--- a/arch/sh/boards/mach-sh7763rdp/setup.c
+++ b/arch/sh/boards/mach-sh7763rdp/setup.c
@@ -18,6 +18,7 @@
 #include <linux/fb.h>
 #include <linux/io.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <mach/sh7763rdp.h>
 #include <asm/sh7760fb.h>
 
@@ -67,7 +68,7 @@
  * SH-Ether
  *
  * SH Ether of SH7763 has multi IRQ handling.
- * (57,58,59 -> 57)
+ * (0x920,0x940,0x960 -> 0x920)
  */
 static struct resource sh_eth_resources[] = {
 	{
@@ -79,7 +80,7 @@
 		.end    = 0xFEE01FFF,
 		.flags  = IORESOURCE_MEM,
 	}, {
-		.start  = 57,   /* irq number */
+		.start  = evt2irq(0x920),   /* irq number */
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -213,6 +214,5 @@
 static struct sh_machine_vector mv_sh7763rdp __initmv = {
 	.mv_name = "sh7763drp",
 	.mv_setup = sh7763rdp_setup,
-	.mv_nr_irqs = 112,
 	.mv_init_irq = init_sh7763rdp_IRQ,
 };
diff --git a/arch/sh/configs/rsk7264_defconfig b/arch/sh/configs/rsk7264_defconfig
new file mode 100644
index 0000000..1600426
--- /dev/null
+++ b/arch/sh/configs/rsk7264_defconfig
@@ -0,0 +1,80 @@
+CONFIG_LOCALVERSION="uClinux RSK2+SH7264"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_COUNTERS=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
+CONFIG_PROFILING=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_CPU_SUBTYPE_SH7264=y
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_SH_RSK=y
+# CONFIG_SH_TIMER_MTU2 is not set
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC911X=y
+CONFIG_SMSC_PHY=y
+CONFIG_INPUT_FF_MEMLESS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=8
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_R8A66597_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_VFAT_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_FTRACE is not set
diff --git a/arch/sh/configs/rsk7269_defconfig b/arch/sh/configs/rsk7269_defconfig
new file mode 100644
index 0000000..9f062b5
--- /dev/null
+++ b/arch/sh/configs/rsk7269_defconfig
@@ -0,0 +1,65 @@
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_CPU_SUBTYPE_SH7269=y
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x02000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_SH_RSK=y
+# CONFIG_SH_TIMER_MTU2 is not set
+CONFIG_SH_PCLK_FREQ=66700000
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC911X=y
+CONFIG_SMSC_PHY=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=8
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_R8A66597_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_VFAT_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_FTRACE is not set
diff --git a/arch/sh/configs/sh7785lcr_32bit_defconfig b/arch/sh/configs/sh7785lcr_32bit_defconfig
index 7b9c696..9bdcf72 100644
--- a/arch/sh/configs/sh7785lcr_32bit_defconfig
+++ b/arch/sh/configs/sh7785lcr_32bit_defconfig
@@ -5,7 +5,7 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index 4d58eb0..cfd5b90 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -40,23 +40,6 @@
 	  DMAC supports. This will be 4 for SH7750/SH7751/Sh7750S/SH7091 and 8 for the
 	  SH7750R/SH7751R/SH7760, 12 for the SH7723/SH7780/SH7785/SH7724, default is 6.
 
-config NR_DMA_CHANNELS_BOOL
-	depends on SH_DMA
-	bool "Override default number of maximum DMA channels"
-	help
-	  This allows you to forcibly update the maximum number of supported
-	  DMA channels for a given board. If this is unset, this will default
-	  to the number of channels that the on-chip DMAC has.
-
-config NR_DMA_CHANNELS
-	int "Maximum number of DMA channels"
-	depends on SH_DMA && NR_DMA_CHANNELS_BOOL
-	default NR_ONCHIP_DMA_CHANNELS
-	help
-	  This allows you to specify the maximum number of DMA channels to
-	  support. Setting this to a higher value allows for cascading DMACs
-	  with additional channels.
-
 config SH_DMABRG
 	bool "SH7760 DMABRG support"
 	depends on CPU_SUBTYPE_SH7760
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
index a60da6d..4c171f1 100644
--- a/arch/sh/drivers/dma/dma-sh.c
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -14,35 +14,72 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <mach-dreamcast/mach/dma.h>
 #include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/dma-sh.h>
+#include <asm/dma-register.h>
+#include <cpu/dma-register.h>
+#include <cpu/dma.h>
 
-#if defined(DMAE1_IRQ)
-#define NR_DMAE		2
-#else
-#define NR_DMAE		1
+/*
+ * Define the default configuration for dual address memory-memory transfer.
+ * The 0x400 value represents auto-request, external->external.
+ */
+#define RS_DUAL	(DM_INC | SM_INC | 0x400 | TS_INDEX2VAL(XMIT_SZ_32BIT))
+
+static unsigned long dma_find_base(unsigned int chan)
+{
+	unsigned long base = SH_DMAC_BASE0;
+
+#ifdef SH_DMAC_BASE1
+	if (chan >= 6)
+		base = SH_DMAC_BASE1;
 #endif
 
-static const char *dmae_name[] = {
-	"DMAC Address Error0", "DMAC Address Error1"
+	return base;
+}
+
+static unsigned long dma_base_addr(unsigned int chan)
+{
+	unsigned long base = dma_find_base(chan);
+
+	/* Normalize offset calculation */
+	if (chan >= 9)
+		chan -= 6;
+	if (chan >= 4)
+		base += 0x10;
+
+	return base + (chan * 0x10);
+}
+
+#ifdef CONFIG_SH_DMA_IRQ_MULTI
+static inline unsigned int get_dmte_irq(unsigned int chan)
+{
+	return chan >= 6 ? DMTE6_IRQ : DMTE0_IRQ;
+}
+#else
+
+static unsigned int dmte_irq_map[] = {
+	DMTE0_IRQ, DMTE0_IRQ + 1, DMTE0_IRQ + 2, DMTE0_IRQ + 3,
+
+#ifdef DMTE4_IRQ
+	DMTE4_IRQ, DMTE4_IRQ + 1,
+#endif
+
+#ifdef DMTE6_IRQ
+	DMTE6_IRQ, DMTE6_IRQ + 1,
+#endif
+
+#ifdef DMTE8_IRQ
+	DMTE8_IRQ, DMTE9_IRQ, DMTE10_IRQ, DMTE11_IRQ,
+#endif
 };
 
 static inline unsigned int get_dmte_irq(unsigned int chan)
 {
-	unsigned int irq = 0;
-	if (chan < ARRAY_SIZE(dmte_irq_map))
-		irq = dmte_irq_map[chan];
-
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-	if (irq > DMTE6_IRQ)
-		return DMTE6_IRQ;
-	return DMTE0_IRQ;
-#else
-	return irq;
-#endif
+	return dmte_irq_map[chan];
 }
+#endif
 
 /*
  * We determine the correct shift size based off of the CHCR transmit size
@@ -53,9 +90,10 @@
  * iterations to complete the transfer.
  */
 static unsigned int ts_shift[] = TS_SHIFT;
+
 static inline unsigned int calc_xmit_shift(struct dma_channel *chan)
 {
-	u32 chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+	u32 chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
 	int cnt = ((chcr & CHCR_TS_LOW_MASK) >> CHCR_TS_LOW_SHIFT) |
 		((chcr & CHCR_TS_HIGH_MASK) >> CHCR_TS_HIGH_SHIFT);
 
@@ -73,13 +111,13 @@
 	struct dma_channel *chan = dev_id;
 	u32 chcr;
 
-	chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+	chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
 
 	if (!(chcr & CHCR_TE))
 		return IRQ_NONE;
 
 	chcr &= ~(CHCR_IE | CHCR_DE);
-	__raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+	__raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
 
 	wake_up(&chan->wait_queue);
 
@@ -91,13 +129,8 @@
 	if (unlikely(!(chan->flags & DMA_TEI_CAPABLE)))
 		return 0;
 
-	return request_irq(get_dmte_irq(chan->chan), dma_tei,
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-				IRQF_SHARED,
-#else
-				0,
-#endif
-				chan->dev_id, chan);
+	return request_irq(get_dmte_irq(chan->chan), dma_tei, IRQF_SHARED,
+			   chan->dev_id, chan);
 }
 
 static void sh_dmac_free_dma(struct dma_channel *chan)
@@ -118,7 +151,7 @@
 		chan->flags &= ~DMA_TEI_CAPABLE;
 	}
 
-	__raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+	__raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
 
 	chan->flags |= DMA_CONFIGURED;
 	return 0;
@@ -129,13 +162,13 @@
 	int irq;
 	u32 chcr;
 
-	chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+	chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
 	chcr |= CHCR_DE;
 
 	if (chan->flags & DMA_TEI_CAPABLE)
 		chcr |= CHCR_IE;
 
-	__raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+	__raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
 
 	if (chan->flags & DMA_TEI_CAPABLE) {
 		irq = get_dmte_irq(chan->chan);
@@ -153,9 +186,9 @@
 		disable_irq(irq);
 	}
 
-	chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+	chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
 	chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
-	__raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+	__raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
 }
 
 static int sh_dmac_xfer_dma(struct dma_channel *chan)
@@ -186,13 +219,13 @@
 	 */
 	if (chan->sar || (mach_is_dreamcast() &&
 			  chan->chan == PVR2_CASCADE_CHAN))
-		__raw_writel(chan->sar, (dma_base_addr[chan->chan]+SAR));
+		__raw_writel(chan->sar, (dma_base_addr(chan->chan) + SAR));
 	if (chan->dar || (mach_is_dreamcast() &&
 			  chan->chan == PVR2_CASCADE_CHAN))
-		__raw_writel(chan->dar, (dma_base_addr[chan->chan] + DAR));
+		__raw_writel(chan->dar, (dma_base_addr(chan->chan) + DAR));
 
 	__raw_writel(chan->count >> calc_xmit_shift(chan),
-		(dma_base_addr[chan->chan] + TCR));
+		(dma_base_addr(chan->chan) + TCR));
 
 	sh_dmac_enable_dma(chan);
 
@@ -201,13 +234,32 @@
 
 static int sh_dmac_get_dma_residue(struct dma_channel *chan)
 {
-	if (!(__raw_readl(dma_base_addr[chan->chan] + CHCR) & CHCR_DE))
+	if (!(__raw_readl(dma_base_addr(chan->chan) + CHCR) & CHCR_DE))
 		return 0;
 
-	return __raw_readl(dma_base_addr[chan->chan] + TCR)
+	return __raw_readl(dma_base_addr(chan->chan) + TCR)
 		 << calc_xmit_shift(chan);
 }
 
+/*
+ * DMAOR handling
+ */
+#if defined(CONFIG_CPU_SUBTYPE_SH7723)	|| \
+    defined(CONFIG_CPU_SUBTYPE_SH7724)	|| \
+    defined(CONFIG_CPU_SUBTYPE_SH7780)	|| \
+    defined(CONFIG_CPU_SUBTYPE_SH7785)
+#define NR_DMAOR	2
+#else
+#define NR_DMAOR	1
+#endif
+
+/*
+ * DMAOR bases are broken out amongst channel groups. DMAOR0 manages
+ * channels 0 - 5, DMAOR1 6 - 11 (optional).
+ */
+#define dmaor_read_reg(n)		__raw_readw(dma_find_base((n)*6))
+#define dmaor_write_reg(n, data)	__raw_writew(data, dma_find_base(n)*6)
+
 static inline int dmaor_reset(int no)
 {
 	unsigned long dmaor = dmaor_read_reg(no);
@@ -228,36 +280,86 @@
 	return 0;
 }
 
-#if defined(CONFIG_CPU_SH4)
+/*
+ * DMAE handling
+ */
+#ifdef CONFIG_CPU_SH4
+
+#if defined(DMAE1_IRQ)
+#define NR_DMAE		2
+#else
+#define NR_DMAE		1
+#endif
+
+static const char *dmae_name[] = {
+	"DMAC Address Error0",
+	"DMAC Address Error1"
+};
+
+#ifdef CONFIG_SH_DMA_IRQ_MULTI
+static inline unsigned int get_dma_error_irq(int n)
+{
+	return get_dmte_irq(n * 6);
+}
+#else
+
+static unsigned int dmae_irq_map[] = {
+	DMAE0_IRQ,
+
+#ifdef DMAE1_IRQ
+	DMAE1_IRQ,
+#endif
+};
+
+static inline unsigned int get_dma_error_irq(int n)
+{
+	return dmae_irq_map[n];
+}
+#endif
+
 static irqreturn_t dma_err(int irq, void *dummy)
 {
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-	int cnt = 0;
-	switch (irq) {
-#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ)
-	case DMTE6_IRQ:
-		cnt++;
-#endif
-	case DMTE0_IRQ:
-		if (dmaor_read_reg(cnt) & (DMAOR_NMIF | DMAOR_AE)) {
-			disable_irq(irq);
-			/* DMA multi and error IRQ */
-			return IRQ_HANDLED;
-		}
-	default:
-		return IRQ_NONE;
-	}
-#else
-	dmaor_reset(0);
-#if defined(CONFIG_CPU_SUBTYPE_SH7723)	|| \
-		defined(CONFIG_CPU_SUBTYPE_SH7780)	|| \
-		defined(CONFIG_CPU_SUBTYPE_SH7785)
-	dmaor_reset(1);
-#endif
+	int i;
+
+	for (i = 0; i < NR_DMAOR; i++)
+		dmaor_reset(i);
+
 	disable_irq(irq);
 
 	return IRQ_HANDLED;
-#endif
+}
+
+static int dmae_irq_init(void)
+{
+	int n;
+
+	for (n = 0; n < NR_DMAE; n++) {
+		int i = request_irq(get_dma_error_irq(n), dma_err,
+				    IRQF_SHARED, dmae_name[n], NULL);
+		if (unlikely(i < 0)) {
+			printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+static void dmae_irq_free(void)
+{
+	int n;
+
+	for (n = 0; n < NR_DMAE; n++)
+		free_irq(get_dma_error_irq(n), NULL);
+}
+#else
+static inline int dmae_irq_init(void)
+{
+	return 0;
+}
+
+static void dmae_irq_free(void)
+{
 }
 #endif
 
@@ -276,72 +378,34 @@
 	.flags		= DMAC_CHANNELS_TEI_CAPABLE,
 };
 
-#ifdef CONFIG_CPU_SH4
-static unsigned int get_dma_error_irq(int n)
-{
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-	return (n == 0) ? get_dmte_irq(0) : get_dmte_irq(6);
-#else
-	return (n == 0) ? DMAE0_IRQ :
-#if defined(DMAE1_IRQ)
-				DMAE1_IRQ;
-#else
-				-1;
-#endif
-#endif
-}
-#endif
-
 static int __init sh_dmac_init(void)
 {
 	struct dma_info *info = &sh_dmac_info;
-	int i;
+	int i, rc;
 
-#ifdef CONFIG_CPU_SH4
-	int n;
-
-	for (n = 0; n < NR_DMAE; n++) {
-		i = request_irq(get_dma_error_irq(n), dma_err,
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-				IRQF_SHARED,
-#else
-				0,
-#endif
-				dmae_name[n], (void *)dmae_name[n]);
-		if (unlikely(i < 0)) {
-			printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
-			return i;
-		}
-	}
-#endif /* CONFIG_CPU_SH4 */
+	/*
+	 * Initialize DMAE, for parts that support it.
+	 */
+	rc = dmae_irq_init();
+	if (unlikely(rc != 0))
+		return rc;
 
 	/*
 	 * Initialize DMAOR, and clean up any error flags that may have
 	 * been set.
 	 */
-	i = dmaor_reset(0);
-	if (unlikely(i != 0))
-		return i;
-#if defined(CONFIG_CPU_SUBTYPE_SH7723)	|| \
-		defined(CONFIG_CPU_SUBTYPE_SH7780)	|| \
-		defined(CONFIG_CPU_SUBTYPE_SH7785)
-	i = dmaor_reset(1);
-	if (unlikely(i != 0))
-		return i;
-#endif
+	for (i = 0; i < NR_DMAOR; i++) {
+		rc = dmaor_reset(i);
+		if (unlikely(rc != 0))
+			return rc;
+	}
 
 	return register_dmac(info);
 }
 
 static void __exit sh_dmac_exit(void)
 {
-#ifdef CONFIG_CPU_SH4
-	int n;
-
-	for (n = 0; n < NR_DMAE; n++) {
-		free_irq(get_dma_error_irq(n), (void *)dmae_name[n]);
-	}
-#endif /* CONFIG_CPU_SH4 */
+	dmae_irq_free();
 	unregister_dmac(&sh_dmac_info);
 }
 
diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c
index 67ee956..4b15fed 100644
--- a/arch/sh/drivers/dma/dma-sysfs.c
+++ b/arch/sh/drivers/dma/dma-sysfs.c
@@ -29,7 +29,7 @@
 	ssize_t len = 0;
 	int i;
 
-	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+	for (i = 0; i < 16; i++) {
 		struct dma_info *info = get_dma_info(i);
 		struct dma_channel *channel = get_dma_channel(i);
 
diff --git a/arch/sh/drivers/pci/fixups-landisk.c b/arch/sh/drivers/pci/fixups-landisk.c
index ecb1d10..db5b40a 100644
--- a/arch/sh/drivers/pci/fixups-landisk.c
+++ b/arch/sh/drivers/pci/fixups-landisk.c
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
 #define PCIMCR_MRSET_OFF	0xBFFFFFFF
@@ -27,7 +28,7 @@
 	 * slot2: pin1-4 = irq7,8,5,6
 	 * slot3: pin1-4 = irq8,5,6,7
 	 */
-	int irq = ((slot + pin - 1) & 0x3) + 5;
+	int irq = ((slot + pin - 1) & 0x3) + evt2irq(0x2a0);
 
 	if ((slot | (pin - 1)) > 0x3) {
 		printk(KERN_WARNING "PCI: Bad IRQ mapping request for slot %d pin %c\n",
diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c
index f9370dce..57ed3f09 100644
--- a/arch/sh/drivers/pci/fixups-r7780rp.c
+++ b/arch/sh/drivers/pci/fixups-r7780rp.c
@@ -12,13 +12,10 @@
  */
 #include <linux/pci.h>
 #include <linux/io.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
-static char irq_tab[] __initdata = {
-	65, 66, 67, 68,
-};
-
 int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
-	return irq_tab[slot];
+	return evt2irq(0xa20) + slot;
 }
diff --git a/arch/sh/drivers/pci/fixups-sdk7780.c b/arch/sh/drivers/pci/fixups-sdk7780.c
index 0b84725..c0a015a 100644
--- a/arch/sh/drivers/pci/fixups-sdk7780.c
+++ b/arch/sh/drivers/pci/fixups-sdk7780.c
@@ -13,18 +13,28 @@
  */
 #include <linux/pci.h>
 #include <linux/io.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
+#define IRQ_INTA	evt2irq(0xa20)
+#define IRQ_INTB	evt2irq(0xa40)
+#define IRQ_INTC	evt2irq(0xa60)
+#define IRQ_INTD	evt2irq(0xa80)
+
 /* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
 static char sdk7780_irq_tab[4][16] __initdata = {
 	/* INTA */
-	{ 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ IRQ_INTA, IRQ_INTD, IRQ_INTC, IRQ_INTD, -1, -1, -1, -1, -1, -1,
+	  -1, -1, -1, -1, -1, -1 },
 	/* INTB */
-	{ 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ IRQ_INTB, IRQ_INTA, -1, IRQ_INTA, -1, -1, -1, -1, -1, -1, -1, -1,
+	  -1, -1, -1, -1 },
 	/* INTC */
-	{ 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ IRQ_INTC, IRQ_INTB, -1, IRQ_INTB, -1, -1, -1, -1, -1, -1, -1, -1,
+	  -1, -1, -1, -1 },
 	/* INTD */
-	{ 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ IRQ_INTD, IRQ_INTC, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	  -1, -1, -1 },
 };
 
 int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
diff --git a/arch/sh/drivers/pci/fixups-se7751.c b/arch/sh/drivers/pci/fixups-se7751.c
index 2ec146c..84a88ca 100644
--- a/arch/sh/drivers/pci/fixups-se7751.c
+++ b/arch/sh/drivers/pci/fixups-se7751.c
@@ -4,13 +4,14 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/io.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
 int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
 {
         switch (slot) {
-        case 0: return 13;
-        case 1: return 13;	/* AMD Ethernet controller */
+        case 0: return evt2irq(0x3a0);
+        case 1: return evt2irq(0x3a0);	/* AMD Ethernet controller */
         case 2: return -1;
         case 3: return -1;
         case 4: return -1;
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
index 1615e59..16207be 100644
--- a/arch/sh/drivers/pci/fixups-sh03.c
+++ b/arch/sh/drivers/pci/fixups-sh03.c
@@ -2,6 +2,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/sh_intc.h>
 
 int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
@@ -9,21 +10,21 @@
 
 	if (dev->bus->number == 0) {
 		switch (slot) {
-		case 4: return 5;	/* eth0       */
-		case 8: return 5;	/* eth1       */
-		case 6: return 2;	/* PCI bridge */
+		case 4: return evt2irq(0x2a0);	/* eth0       */
+		case 8: return evt2irq(0x2a0);	/* eth1       */
+		case 6: return evt2irq(0x240);	/* PCI bridge */
 		default:
 			printk(KERN_ERR "PCI: Bad IRQ mapping request "
 					"for slot %d\n", slot);
-			return 2;
+			return evt2irq(0x240);
 		}
 	} else {
 		switch (pin) {
-		case 0:   irq =  2; break;
-		case 1:   irq =  2; break;
-		case 2:   irq =  2; break;
-		case 3:   irq =  2; break;
-		case 4:   irq =  2; break;
+		case 0:   irq =  evt2irq(0x240); break;
+		case 1:   irq =  evt2irq(0x240); break;
+		case 2:   irq =  evt2irq(0x240); break;
+		case 3:   irq =  evt2irq(0x240); break;
+		case 4:   irq =  evt2irq(0x240); break;
 		default:  irq = -1; break;
 		}
 	}
diff --git a/arch/sh/drivers/pci/fixups-snapgear.c b/arch/sh/drivers/pci/fixups-snapgear.c
index 4a093c6..6e33ba4 100644
--- a/arch/sh/drivers/pci/fixups-snapgear.c
+++ b/arch/sh/drivers/pci/fixups-snapgear.c
@@ -16,6 +16,7 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
 int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
@@ -24,11 +25,11 @@
 
 	switch (slot) {
 	case 8:  /* the PCI bridge */ break;
-	case 11: irq = 8;  break; /* USB    */
-	case 12: irq = 11; break; /* PCMCIA */
-	case 13: irq = 5;  break; /* eth0   */
-	case 14: irq = 8;  break; /* eth1   */
-	case 15: irq = 11; break; /* safenet (unused) */
+	case 11: irq = evt2irq(0x300); break; /* USB    */
+	case 12: irq = evt2irq(0x360); break; /* PCMCIA */
+	case 13: irq = evt2irq(0x2a0); break; /* eth0   */
+	case 14: irq = evt2irq(0x300); break; /* eth1   */
+	case 15: irq = evt2irq(0x360); break; /* safenet (unused) */
 	}
 
 	printk("PCI: Mapping SnapGear IRQ for slot %d, pin %c to irq %d\n",
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index 4df27c4f..c045142 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/sh_clk.h>
+#include <linux/sh_intc.h>
 #include "pcie-sh7786.h"
 #include <asm/sizes.h>
 
@@ -468,7 +469,7 @@
 
 int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
-        return 71;
+        return evt2irq(0xae0);
 }
 
 static int __init sh7786_pcie_core_init(void)
diff --git a/arch/sh/include/asm/dma-sh.h b/arch/sh/include/asm/dma-sh.h
deleted file mode 100644
index f3acb8e..0000000
--- a/arch/sh/include/asm/dma-sh.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * arch/sh/include/asm/dma-sh.h
- *
- * Copyright (C) 2000  Takashi YOSHII
- * Copyright (C) 2003  Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#ifndef __DMA_SH_H
-#define __DMA_SH_H
-
-#include <asm/dma-register.h>
-#include <cpu/dma-register.h>
-#include <cpu/dma.h>
-
-/* DMAOR contorl: The DMAOR access size is different by CPU.*/
-#if defined(CONFIG_CPU_SUBTYPE_SH7723)	|| \
-    defined(CONFIG_CPU_SUBTYPE_SH7724)	|| \
-    defined(CONFIG_CPU_SUBTYPE_SH7780)	|| \
-    defined(CONFIG_CPU_SUBTYPE_SH7785)
-#define dmaor_read_reg(n) \
-    (n ? __raw_readw(SH_DMAC_BASE1 + DMAOR) \
-	: __raw_readw(SH_DMAC_BASE0 + DMAOR))
-#define dmaor_write_reg(n, data) \
-    (n ? __raw_writew(data, SH_DMAC_BASE1 + DMAOR) \
-    : __raw_writew(data, SH_DMAC_BASE0 + DMAOR))
-#else /* Other CPU */
-#define dmaor_read_reg(n) __raw_readw(SH_DMAC_BASE0 + DMAOR)
-#define dmaor_write_reg(n, data) __raw_writew(data, SH_DMAC_BASE0 + DMAOR)
-#endif
-
-static int dmte_irq_map[] __maybe_unused = {
-#if (MAX_DMA_CHANNELS >= 4)
-    DMTE0_IRQ,
-    DMTE0_IRQ + 1,
-    DMTE0_IRQ + 2,
-    DMTE0_IRQ + 3,
-#endif
-#if (MAX_DMA_CHANNELS >= 6)
-    DMTE4_IRQ,
-    DMTE4_IRQ + 1,
-#endif
-#if (MAX_DMA_CHANNELS >= 8)
-    DMTE6_IRQ,
-    DMTE6_IRQ + 1,
-#endif
-#if (MAX_DMA_CHANNELS >= 12)
-    DMTE8_IRQ,
-    DMTE9_IRQ,
-    DMTE10_IRQ,
-    DMTE11_IRQ,
-#endif
-};
-
-/*
- * Define the default configuration for dual address memory-memory transfer.
- * The 0x400 value represents auto-request, external->external.
- */
-#define RS_DUAL	(DM_INC | SM_INC | 0x400 | TS_INDEX2VAL(XMIT_SZ_32BIT))
-
-/* DMA base address */
-static u32 dma_base_addr[] __maybe_unused = {
-#if (MAX_DMA_CHANNELS >= 4)
-	SH_DMAC_BASE0 + 0x00,	/* channel 0 */
-	SH_DMAC_BASE0 + 0x10,
-	SH_DMAC_BASE0 + 0x20,
-	SH_DMAC_BASE0 + 0x30,
-#endif
-#if (MAX_DMA_CHANNELS >= 6)
-	SH_DMAC_BASE0 + 0x50,
-	SH_DMAC_BASE0 + 0x60,
-#endif
-#if (MAX_DMA_CHANNELS >= 8)
-	SH_DMAC_BASE1 + 0x00,
-	SH_DMAC_BASE1 + 0x10,
-#endif
-#if (MAX_DMA_CHANNELS >= 12)
-	SH_DMAC_BASE1 + 0x20,
-	SH_DMAC_BASE1 + 0x30,
-	SH_DMAC_BASE1 + 0x50,
-	SH_DMAC_BASE1 + 0x60, /* channel 11 */
-#endif
-};
-
-#endif /* __DMA_SH_H */
diff --git a/arch/sh/include/asm/dma.h b/arch/sh/include/asm/dma.h
index 6aa2080..fb6e4f7 100644
--- a/arch/sh/include/asm/dma.h
+++ b/arch/sh/include/asm/dma.h
@@ -15,17 +15,8 @@
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/device.h>
-#include <cpu/dma.h>
 #include <asm-generic/dma.h>
 
-#ifdef CONFIG_NR_DMA_CHANNELS
-#  define MAX_DMA_CHANNELS	(CONFIG_NR_DMA_CHANNELS)
-#elif defined(CONFIG_NR_ONCHIP_DMA_CHANNELS)
-#  define MAX_DMA_CHANNELS	(CONFIG_NR_ONCHIP_DMA_CHANNELS)
-#else
-#  define MAX_DMA_CHANNELS	0
-#endif
-
 /*
  * Read and write modes can mean drastically different things depending on the
  * channel configuration. Consult your DMAC documentation and module
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h
index bd7e79a..cbe0186 100644
--- a/arch/sh/include/asm/fixmap.h
+++ b/arch/sh/include/asm/fixmap.h
@@ -96,7 +96,7 @@
 #ifdef CONFIG_SUPERH32
 #define FIXADDR_TOP	(P4SEG - PAGE_SIZE)
 #else
-#define FIXADDR_TOP	(0xff000000 - PAGE_SIZE)
+#define FIXADDR_TOP	((unsigned long)(-PAGE_SIZE))
 #endif
 #define FIXADDR_SIZE	(__end_of_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START	(FIXADDR_TOP - FIXADDR_SIZE)
diff --git a/arch/sh/include/asm/i2c-sh7760.h b/arch/sh/include/asm/i2c-sh7760.h
index 2418211..69fee12 100644
--- a/arch/sh/include/asm/i2c-sh7760.h
+++ b/arch/sh/include/asm/i2c-sh7760.h
@@ -9,11 +9,9 @@
 
 #define SH7760_I2C0_MMIO	0xFE140000
 #define SH7760_I2C0_MMIOEND	0xFE14003B
-#define SH7760_I2C0_IRQ		62
 
 #define SH7760_I2C1_MMIO	0xFE150000
 #define SH7760_I2C1_MMIOEND	0xFE15003B
-#define SH7760_I2C1_IRQ		63
 
 struct sh7760_i2c_platdata {
 	unsigned int speed_khz;
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index ec464a6..0cf60a6 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -218,8 +218,13 @@
 __BUILD_IOPORT_STRING(l, u32)
 __BUILD_IOPORT_STRING(q, u64)
 
+#else /* !CONFIG_HAS_IOPORT */
+
+#include <asm/io_noioport.h>
+
 #endif
 
+
 #define IO_SPACE_LIMIT 0xffffffff
 
 /* synco on SH-4A, otherwise a nop */
diff --git a/arch/sh/include/asm/io_noioport.h b/arch/sh/include/asm/io_noioport.h
new file mode 100644
index 0000000..e136d28
--- /dev/null
+++ b/arch/sh/include/asm/io_noioport.h
@@ -0,0 +1,41 @@
+#ifndef __ASM_SH_IO_NOIOPORT_H
+#define __ASM_SH_IO_NOIOPORT_H
+
+static inline u8 inb(unsigned long addr)
+{
+	BUG();
+	return -1;
+}
+
+static inline u16 inw(unsigned long addr)
+{
+	BUG();
+	return -1;
+}
+
+static inline u32 inl(unsigned long addr)
+{
+	BUG();
+	return -1;
+}
+
+#define outb(x, y)	BUG()
+#define outw(x, y)	BUG()
+#define outl(x, y)	BUG()
+
+#define inb_p(addr)	inb(addr)
+#define inw_p(addr)	inw(addr)
+#define inl_p(addr)	inl(addr)
+#define outb_p(x, addr)	outb((x), (addr))
+#define outw_p(x, addr)	outw((x), (addr))
+#define outl_p(x, addr)	outl((x), (addr))
+
+#define insb(a, b, c)	BUG()
+#define insw(a, b, c)	BUG()
+#define insl(a, b, c)	BUG()
+
+#define outsb(a, b, c)	BUG()
+#define outsw(a, b, c)	BUG()
+#define outsl(a, b, c)	BUG()
+
+#endif /* __ASM_SH_IO_NOIOPORT_H */
diff --git a/arch/sh/include/asm/irq.h b/arch/sh/include/asm/irq.h
index 2a62017..0e4f532 100644
--- a/arch/sh/include/asm/irq.h
+++ b/arch/sh/include/asm/irq.h
@@ -5,12 +5,15 @@
 #include <asm/machvec.h>
 
 /*
- * A sane default based on a reasonable vector table size, platforms are
- * advised to cap this at the hard limit that they're interested in
- * through the machvec.
+ * Only legacy non-sparseirq platforms have to set a reasonably sane
+ * value here. sparseirq platforms allocate their irq_descs on the fly,
+ * so will expand automatically based on the number of registered IRQs.
  */
-#define NR_IRQS			512
-#define NR_IRQS_LEGACY		8	/* Legacy external IRQ0-7 */
+#ifdef CONFIG_SPARSE_IRQ
+# define NR_IRQS		8
+#else
+# define NR_IRQS		512
+#endif
 
 /*
  * This is a special IRQ number for indicating that no IRQ has been
diff --git a/arch/sh/include/asm/kdebug.h b/arch/sh/include/asm/kdebug.h
index 5f6d2e9..a6201f1 100644
--- a/arch/sh/include/asm/kdebug.h
+++ b/arch/sh/include/asm/kdebug.h
@@ -10,4 +10,6 @@
 	DIE_SSTEP,
 };
 
+extern void printk_address(unsigned long address, int reliable);
+
 #endif /* __ASM_SH_KDEBUG_H */
diff --git a/arch/sh/include/asm/kgdb.h b/arch/sh/include/asm/kgdb.h
index f361395..9e7d2d1 100644
--- a/arch/sh/include/asm/kgdb.h
+++ b/arch/sh/include/asm/kgdb.h
@@ -4,18 +4,6 @@
 #include <asm/cacheflush.h>
 #include <asm/ptrace.h>
 
-/* Same as pt_regs but has vbr in place of syscall_nr */
-struct kgdb_regs {
-        unsigned long regs[16];
-        unsigned long pc;
-        unsigned long pr;
-        unsigned long sr;
-        unsigned long gbr;
-        unsigned long mach;
-        unsigned long macl;
-        unsigned long vbr;
-};
-
 enum regnames {
 	GDB_R0, GDB_R1, GDB_R2, GDB_R3, GDB_R4, GDB_R5, GDB_R6, GDB_R7,
 	GDB_R8, GDB_R9, GDB_R10, GDB_R11, GDB_R12, GDB_R13, GDB_R14, GDB_R15,
@@ -23,17 +11,27 @@
 	GDB_PC, GDB_PR, GDB_SR, GDB_GBR, GDB_MACH, GDB_MACL, GDB_VBR,
 };
 
-#define NUMREGBYTES    ((GDB_VBR + 1) * 4)
+#define _GP_REGS	16
+#define _EXTRA_REGS	7
+#define GDB_SIZEOF_REG	sizeof(u32)
+
+#define DBG_MAX_REG_NUM	(_GP_REGS + _EXTRA_REGS)
+#define NUMREGBYTES	(DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG))
 
 static inline void arch_kgdb_breakpoint(void)
 {
 	__asm__ __volatile__ ("trapa #0x3c\n");
 }
 
-#define BUFMAX                 2048
-
-#define CACHE_FLUSH_IS_SAFE	1
 #define BREAK_INSTR_SIZE	2
+#define BUFMAX			2048
+
+#ifdef CONFIG_SMP
+# define CACHE_FLUSH_IS_SAFE	0
+#else
+# define CACHE_FLUSH_IS_SAFE	1
+#endif
+
 #define GDB_ADJUSTS_BREAK_OFFSET
 
 #endif /* __ASM_SH_KGDB_H */
diff --git a/arch/sh/include/asm/machvec.h b/arch/sh/include/asm/machvec.h
index 57c5c3d..eb9c20d 100644
--- a/arch/sh/include/asm/machvec.h
+++ b/arch/sh/include/asm/machvec.h
@@ -17,7 +17,6 @@
 struct sh_machine_vector {
 	void (*mv_setup)(char **cmdline_p);
 	const char *mv_name;
-	int mv_nr_irqs;
 
 	int (*mv_irq_demux)(int irq);
 	void (*mv_init_irq)(void);
diff --git a/arch/sh/include/asm/pgtable_64.h b/arch/sh/include/asm/pgtable_64.h
index 42cb9dd..dda8c82 100644
--- a/arch/sh/include/asm/pgtable_64.h
+++ b/arch/sh/include/asm/pgtable_64.h
@@ -87,9 +87,6 @@
 #define pte_unmap(pte)		do { } while (0)
 
 #ifndef __ASSEMBLY__
-#define IOBASE_VADDR	0xff000000
-#define IOBASE_END	0xffffffff
-
 /*
  * PTEL coherent flags.
  * See Chapter 17 ST50 CPU Core Volume 1, Architecture.
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h
index 6dbc1be..3d14aea 100644
--- a/arch/sh/include/asm/processor.h
+++ b/arch/sh/include/asm/processor.h
@@ -18,7 +18,8 @@
 	CPU_SH7619,
 
 	/* SH-2A types */
-	CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_MXG,
+	CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_SH7264, CPU_SH7269,
+	CPU_MXG,
 
 	/* SH-3 types */
 	CPU_SH7705, CPU_SH7706, CPU_SH7707,
@@ -32,7 +33,7 @@
 
 	/* SH-4A types */
 	CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SH7786,
-	CPU_SH7723, CPU_SH7724, CPU_SH7757, CPU_SHX3,
+	CPU_SH7723, CPU_SH7724, CPU_SH7757, CPU_SH7734, CPU_SHX3,
 
 	/* SH4AL-DSP types */
 	CPU_SH7343, CPU_SH7722, CPU_SH7366, CPU_SH7372,
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index 900f8d7..b6311fd 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -126,9 +126,6 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-void prepare_to_copy(struct task_struct *tsk);
-
 /*
  * create a kernel thread without removing it from tasklists
  */
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h
index e25c4c7..cd6029f 100644
--- a/arch/sh/include/asm/processor_64.h
+++ b/arch/sh/include/asm/processor_64.h
@@ -121,7 +121,6 @@
 	   NULL for a kernel thread. */
 	struct pt_regs *uregs;
 
-	unsigned long trap_no, error_code;
 	unsigned long address;
 	/* Hardware debugging registers may come here */
 
@@ -138,8 +137,6 @@
 	.pc		= 0,			\
         .kregs		= &fake_swapper_regs,	\
 	.uregs	        = NULL,			\
-	.trap_no	= 0,			\
-	.error_code	= 0,			\
 	.address	= 0,			\
 	.flags		= 0,			\
 }
@@ -172,7 +169,6 @@
 #define copy_segments(p, mm)	do { } while (0)
 #define release_segments(mm)	do { } while (0)
 #define forget_segments()	do { } while (0)
-#define prepare_to_copy(tsk)	do { } while (0)
 /*
  * FPU lazy state save handling.
  */
diff --git a/arch/sh/include/asm/stackprotector.h b/arch/sh/include/asm/stackprotector.h
new file mode 100644
index 0000000..d9df3a7
--- /dev/null
+++ b/arch/sh/include/asm/stackprotector.h
@@ -0,0 +1,27 @@
+#ifndef __ASM_SH_STACKPROTECTOR_H
+#define __ASM_SH_STACKPROTECTOR_H
+
+#include <linux/random.h>
+#include <linux/version.h>
+
+extern unsigned long __stack_chk_guard;
+
+/*
+ * Initialize the stackprotector canary value.
+ *
+ * NOTE: this must only be called from functions that never return,
+ * and it must always be inlined.
+ */
+static __always_inline void boot_init_stack_canary(void)
+{
+	unsigned long canary;
+
+	/* Try to get a semi random initial value. */
+	get_random_bytes(&canary, sizeof(canary));
+	canary ^= LINUX_VERSION_CODE;
+
+	current->stack_canary = canary;
+	__stack_chk_guard = current->stack_canary;
+}
+
+#endif /* __ASM_SH_STACKPROTECTOR_H */
diff --git a/arch/sh/include/asm/syscalls_32.h b/arch/sh/include/asm/syscalls_32.h
index ae717e3..6c1fa55 100644
--- a/arch/sh/include/asm/syscalls_32.h
+++ b/arch/sh/include/asm/syscalls_32.h
@@ -23,9 +23,7 @@
 			  const char __user *const __user *uargv,
 			  const char __user *const __user *uenvp,
 			  unsigned long r7, struct pt_regs __regs);
-asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r5,
-			      unsigned long r6, unsigned long r7,
-			      struct pt_regs __regs);
+asmlinkage int sys_sigsuspend(old_sigset_t mask);
 asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act,
 			     struct old_sigaction __user *oact);
 asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index b690206..0c04ffc 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -10,8 +10,18 @@
  *  - Incorporating suggestions made by Linus Torvalds and Dave Miller
  */
 #ifdef __KERNEL__
+
 #include <asm/page.h>
 
+/*
+ * Page fault error code bits
+ */
+#define FAULT_CODE_WRITE	(1 << 0)	/* write access */
+#define FAULT_CODE_INITIAL	(1 << 1)	/* initial page write */
+#define FAULT_CODE_ITLB		(1 << 2)	/* ITLB miss */
+#define FAULT_CODE_PROT		(1 << 3)	/* protection fault */
+#define FAULT_CODE_USER		(1 << 4)	/* user-mode access */
+
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
 
@@ -98,10 +108,13 @@
 #endif /* __ASSEMBLY__ */
 
 /*
- * thread information flags
- * - these are process state flags that various assembly files may need to access
- * - pending work-to-be-done flags are in LSW
- * - other flags in MSW
+ * Thread information flags
+ *
+ * - Limited to 24 bits, upper byte used for fault code encoding.
+ *
+ * - _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or
+ *   we blow the tst immediate size constraints and need to fix up
+ *   arch/sh/kernel/entry-common.S.
  */
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_SIGPENDING		1	/* signal pending */
@@ -124,12 +137,6 @@
 #define _TIF_SYSCALL_TRACEPOINT	(1 << TIF_SYSCALL_TRACEPOINT)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 
-/*
- * _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or we
- * blow the tst immediate size constraints and need to fix up
- * arch/sh/kernel/entry-common.S.
- */
-
 /* work to do in syscall trace */
 #define _TIF_WORK_SYSCALL_MASK	(_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
 				 _TIF_SYSCALL_AUDIT | _TIF_SECCOMP    | \
@@ -156,6 +163,7 @@
 #define TS_USEDFPU		0x0002	/* FPU used by this task this quantum */
 
 #ifndef __ASSEMBLY__
+
 #define HAVE_SET_RESTORE_SIGMASK	1
 static inline void set_restore_sigmask(void)
 {
@@ -163,6 +171,24 @@
 	ti->status |= TS_RESTORE_SIGMASK;
 	set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
 }
+
+#define TI_FLAG_FAULT_CODE_SHIFT	24
+
+/*
+ * Additional thread flag encoding
+ */
+static inline void set_thread_fault_code(unsigned int val)
+{
+	struct thread_info *ti = current_thread_info();
+	ti->flags = (ti->flags & (~0 >> (32 - TI_FLAG_FAULT_CODE_SHIFT)))
+		| (val << TI_FLAG_FAULT_CODE_SHIFT);
+}
+
+static inline unsigned int get_thread_fault_code(void)
+{
+	struct thread_info *ti = current_thread_info();
+	return ti->flags >> TI_FLAG_FAULT_CODE_SHIFT;
+}
 #endif	/* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/sh/include/asm/topology.h b/arch/sh/include/asm/topology.h
index 88e7340..b0a282d 100644
--- a/arch/sh/include/asm/topology.h
+++ b/arch/sh/include/asm/topology.h
@@ -3,31 +3,6 @@
 
 #ifdef CONFIG_NUMA
 
-/* sched_domains SD_NODE_INIT for sh machines */
-#define SD_NODE_INIT (struct sched_domain) {		\
-	.parent			= NULL,			\
-	.child			= NULL,			\
-	.groups			= NULL,			\
-	.min_interval		= 8,			\
-	.max_interval		= 32,			\
-	.busy_factor		= 32,			\
-	.imbalance_pct		= 125,			\
-	.cache_nice_tries	= 2,			\
-	.busy_idx		= 3,			\
-	.idle_idx		= 2,			\
-	.newidle_idx		= 0,			\
-	.wake_idx		= 0,			\
-	.forkexec_idx		= 0,			\
-	.flags			= SD_LOAD_BALANCE	\
-				| SD_BALANCE_FORK	\
-				| SD_BALANCE_EXEC	\
-				| SD_BALANCE_NEWIDLE	\
-				| SD_SERIALIZE,		\
-	.last_balance		= jiffies,		\
-	.balance_interval	= 1,			\
-	.nr_balance_failed	= 0,			\
-}
-
 #define cpu_to_node(cpu)	((void)(cpu),0)
 #define parent_node(node)	((void)(node),0)
 
diff --git a/arch/sh/include/asm/traps_64.h b/arch/sh/include/asm/traps_64.h
index c52d7f9..ef5eff91 100644
--- a/arch/sh/include/asm/traps_64.h
+++ b/arch/sh/include/asm/traps_64.h
@@ -10,8 +10,22 @@
 #ifndef __ASM_SH_TRAPS_64_H
 #define __ASM_SH_TRAPS_64_H
 
+#include <cpu/registers.h>
+
 extern void phys_stext(void);
 
+#define lookup_exception_vector()		\
+({						\
+	unsigned long _vec;			\
+						\
+	__asm__ __volatile__ (			\
+		"getcon " __EXPEVT ", %0\n\t"	\
+		: "=r" (_vec)			\
+	);					\
+						\
+	_vec;					\
+})
+
 static inline void trigger_address_error(void)
 {
 	phys_stext();
diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h
index a42a561..e800a38 100644
--- a/arch/sh/include/asm/unistd.h
+++ b/arch/sh/include/asm/unistd.h
@@ -1,13 +1,11 @@
 #ifdef __KERNEL__
 # ifdef CONFIG_SUPERH32
-
 #  include "unistd_32.h"
-#  define __ARCH_WANT_SYS_RT_SIGSUSPEND
-
 # else
 #  include "unistd_64.h"
 # endif
 
+# define __ARCH_WANT_SYS_RT_SIGSUSPEND
 # define __ARCH_WANT_IPC_PARSE_VERSION
 # define __ARCH_WANT_OLD_READDIR
 # define __ARCH_WANT_OLD_STAT
diff --git a/arch/sh/include/cpu-sh2/cpu/dma.h b/arch/sh/include/cpu-sh2/cpu/dma.h
deleted file mode 100644
index d66b43c..0000000
--- a/arch/sh/include/cpu-sh2/cpu/dma.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Definitions for the SH-2 DMAC.
- *
- * Copyright (C) 2003  Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#ifndef __ASM_CPU_SH2_DMA_H
-#define __ASM_CPU_SH2_DMA_H
-
-#define SH_MAX_DMA_CHANNELS	2
-
-#define SAR	((unsigned long[]){ 0xffffff80, 0xffffff90 })
-#define DAR	((unsigned long[]){ 0xffffff84, 0xffffff94 })
-#define DMATCR	((unsigned long[]){ 0xffffff88, 0xffffff98 })
-#define CHCR	((unsigned long[]){ 0xfffffffc, 0xffffff9c })
-
-#define DMAOR	0xffffffb0
-
-#endif /* __ASM_CPU_SH2_DMA_H */
-
diff --git a/arch/sh/include/cpu-sh2a/cpu/dma.h b/arch/sh/include/cpu-sh2a/cpu/dma.h
deleted file mode 100644
index 27a13ef..0000000
--- a/arch/sh/include/cpu-sh2a/cpu/dma.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <cpu-sh2/cpu/dma.h>
diff --git a/arch/sh/include/cpu-sh2a/cpu/sh7264.h b/arch/sh/include/cpu-sh2a/cpu/sh7264.h
new file mode 100644
index 0000000..4d1ef6d
--- /dev/null
+++ b/arch/sh/include/cpu-sh2a/cpu/sh7264.h
@@ -0,0 +1,176 @@
+#ifndef __ASM_SH7264_H__
+#define __ASM_SH7264_H__
+
+enum {
+	/* Port A */
+	GPIO_PA3, GPIO_PA2, GPIO_PA1, GPIO_PA0,
+
+	/* Port B */
+	GPIO_PB22, GPIO_PB21, GPIO_PB20,
+	GPIO_PB19, GPIO_PB18, GPIO_PB17, GPIO_PB16,
+	GPIO_PB15, GPIO_PB14, GPIO_PB13, GPIO_PB12,
+	GPIO_PB11, GPIO_PB10, GPIO_PB9, GPIO_PB8,
+	GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+	GPIO_PB3, GPIO_PB2, GPIO_PB1,
+
+	/* Port C */
+	GPIO_PC10, GPIO_PC9, GPIO_PC8,
+	GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+	GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+	/* Port D */
+	GPIO_PD15, GPIO_PD14, GPIO_PD13, GPIO_PD12,
+	GPIO_PD11, GPIO_PD10, GPIO_PD9, GPIO_PD8,
+	GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+	GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+	/* Port E */
+	GPIO_PE5, GPIO_PE4,
+	GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+	/* Port F */
+	GPIO_PF12,
+	GPIO_PF11, GPIO_PF10, GPIO_PF9, GPIO_PF8,
+	GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+	GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+	/* Port G */
+	GPIO_PG24,
+	GPIO_PG23, GPIO_PG22, GPIO_PG21, GPIO_PG20,
+	GPIO_PG19, GPIO_PG18, GPIO_PG17, GPIO_PG16,
+	GPIO_PG15, GPIO_PG14, GPIO_PG13, GPIO_PG12,
+	GPIO_PG11, GPIO_PG10, GPIO_PG9, GPIO_PG8,
+	GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+	GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+	/* Port H */
+	GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
+	GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+	/* Port I - not on device */
+
+	/* Port J */
+	GPIO_PJ11, GPIO_PJ10, GPIO_PJ9, GPIO_PJ8,
+	GPIO_PJ7, GPIO_PJ6, GPIO_PJ5, GPIO_PJ4,
+	GPIO_PJ3, GPIO_PJ2, GPIO_PJ1, GPIO_PJ0,
+
+	/* Port K */
+	GPIO_PK11, GPIO_PK10, GPIO_PK9, GPIO_PK8,
+	GPIO_PK7, GPIO_PK6, GPIO_PK5, GPIO_PK4,
+	GPIO_PK3, GPIO_PK2, GPIO_PK1, GPIO_PK0,
+
+	/* INTC: IRQ and PINT on PB/PD/PE */
+	GPIO_FN_PINT7_PG, GPIO_FN_PINT6_PG, GPIO_FN_PINT5_PG, GPIO_FN_PINT4_PG,
+	GPIO_FN_PINT3_PG, GPIO_FN_PINT2_PG, GPIO_FN_PINT1_PG,
+
+	GPIO_FN_IRQ7_PC, GPIO_FN_IRQ6_PC, GPIO_FN_IRQ5_PC, GPIO_FN_IRQ4_PC,
+	GPIO_FN_IRQ3_PG, GPIO_FN_IRQ2_PG, GPIO_FN_IRQ1_PJ, GPIO_FN_IRQ0_PJ,
+	GPIO_FN_IRQ3_PE, GPIO_FN_IRQ2_PE, GPIO_FN_IRQ1_PE, GPIO_FN_IRQ0_PE,
+
+	/* WDT */
+	GPIO_FN_WDTOVF,
+
+	/* CAN */
+	GPIO_FN_CTX1, GPIO_FN_CRX1, GPIO_FN_CTX0, GPIO_FN_CTX0_CTX1,
+	GPIO_FN_CRX0, GPIO_FN_CRX0_CRX1,
+
+	/* DMAC */
+	GPIO_FN_TEND0, GPIO_FN_DACK0, GPIO_FN_DREQ0,
+	GPIO_FN_TEND1, GPIO_FN_DACK1, GPIO_FN_DREQ1,
+
+	/* ADC */
+	GPIO_FN_ADTRG,
+
+	/* BSC */
+
+	GPIO_FN_A25, GPIO_FN_A24,
+	GPIO_FN_A23, GPIO_FN_A22, GPIO_FN_A21, GPIO_FN_A20,
+	GPIO_FN_A19, GPIO_FN_A18, GPIO_FN_A17, GPIO_FN_A16,
+	GPIO_FN_A15, GPIO_FN_A14, GPIO_FN_A13, GPIO_FN_A12,
+	GPIO_FN_A11, GPIO_FN_A10, GPIO_FN_A9, GPIO_FN_A8,
+	GPIO_FN_A7, GPIO_FN_A6, GPIO_FN_A5, GPIO_FN_A4,
+	GPIO_FN_A3, GPIO_FN_A2, GPIO_FN_A1, GPIO_FN_A0,
+	GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
+	GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
+	GPIO_FN_D7, GPIO_FN_D6, GPIO_FN_D5, GPIO_FN_D4,
+	GPIO_FN_D3, GPIO_FN_D2, GPIO_FN_D1, GPIO_FN_D0,
+
+	GPIO_FN_BS,
+	GPIO_FN_CS4, GPIO_FN_CS3, GPIO_FN_CS2, GPIO_FN_CS1, GPIO_FN_CS0,
+	GPIO_FN_CS6CE1B, GPIO_FN_CS5CE1A,
+	GPIO_FN_CE2A, GPIO_FN_CE2B,
+	GPIO_FN_RD, GPIO_FN_RDWR,
+	GPIO_FN_ICIOWRAH, GPIO_FN_ICIORD,
+	GPIO_FN_WE1DQMUWE, GPIO_FN_WE0DQML,
+	GPIO_FN_RAS, GPIO_FN_CAS, GPIO_FN_CKE,
+	GPIO_FN_WAIT, GPIO_FN_BREQ, GPIO_FN_BACK,
+	GPIO_FN_IOIS16,
+
+	/* TMU */
+	GPIO_FN_TIOC4D, GPIO_FN_TIOC4C, GPIO_FN_TIOC4B, GPIO_FN_TIOC4A,
+	GPIO_FN_TIOC3D, GPIO_FN_TIOC3C, GPIO_FN_TIOC3B, GPIO_FN_TIOC3A,
+	GPIO_FN_TIOC2B, GPIO_FN_TIOC1B, GPIO_FN_TIOC2A, GPIO_FN_TIOC1A,
+	GPIO_FN_TIOC0D, GPIO_FN_TIOC0C, GPIO_FN_TIOC0B, GPIO_FN_TIOC0A,
+	GPIO_FN_TCLKD, GPIO_FN_TCLKC, GPIO_FN_TCLKB, GPIO_FN_TCLKA,
+
+	/* SSU */
+	GPIO_FN_SCS0_PD, GPIO_FN_SSO0_PD, GPIO_FN_SSI0_PD, GPIO_FN_SSCK0_PD,
+	GPIO_FN_SCS0_PF, GPIO_FN_SSO0_PF, GPIO_FN_SSI0_PF, GPIO_FN_SSCK0_PF,
+	GPIO_FN_SCS1_PD, GPIO_FN_SSO1_PD, GPIO_FN_SSI1_PD, GPIO_FN_SSCK1_PD,
+	GPIO_FN_SCS1_PF, GPIO_FN_SSO1_PF, GPIO_FN_SSI1_PF, GPIO_FN_SSCK1_PF,
+
+	/* SCIF */
+	GPIO_FN_SCK0, GPIO_FN_SCK1, GPIO_FN_SCK2, GPIO_FN_SCK3,
+	GPIO_FN_RXD0, GPIO_FN_RXD1, GPIO_FN_RXD2, GPIO_FN_RXD3,
+	GPIO_FN_TXD0, GPIO_FN_TXD1, GPIO_FN_TXD2, GPIO_FN_TXD3,
+	GPIO_FN_RXD4, GPIO_FN_RXD5, GPIO_FN_RXD6, GPIO_FN_RXD7,
+	GPIO_FN_TXD4, GPIO_FN_TXD5, GPIO_FN_TXD6, GPIO_FN_TXD7,
+	GPIO_FN_RTS1, GPIO_FN_RTS3, GPIO_FN_CTS1, GPIO_FN_CTS3,
+
+	/* RSPI */
+	GPIO_FN_RSPCK0, GPIO_FN_MOSI0,
+	GPIO_FN_MISO0_PF12, GPIO_FN_MISO1,
+	GPIO_FN_SSL00,
+	GPIO_FN_RSPCK1, GPIO_FN_MOSI1,
+	GPIO_FN_MISO1_PG19, GPIO_FN_SSL10,
+
+	/* IIC3 */
+	GPIO_FN_SCL0, GPIO_FN_SCL1, GPIO_FN_SCL2,
+	GPIO_FN_SDA2, GPIO_FN_SDA1, GPIO_FN_SDA0,
+
+	/* SSI */
+	GPIO_FN_SSISCK0, GPIO_FN_SSIWS0, GPIO_FN_SSITXD0, GPIO_FN_SSIRXD0,
+	GPIO_FN_SSIWS1, GPIO_FN_SSIWS2, GPIO_FN_SSIWS3,
+	GPIO_FN_SSISCK1, GPIO_FN_SSISCK2, GPIO_FN_SSISCK3,
+	GPIO_FN_SSIDATA1, GPIO_FN_SSIDATA2, GPIO_FN_SSIDATA3,
+	GPIO_FN_AUDIO_CLK,
+
+	/* SIOF */
+	GPIO_FN_SIOFTXD, GPIO_FN_SIOFRXD, GPIO_FN_SIOFSYNC, GPIO_FN_SIOFSCK,
+
+	/* SPDIF */
+	GPIO_FN_SPDIF_IN,
+	GPIO_FN_SPDIF_OUT,
+
+	/* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+	GPIO_FN_FCE,
+	GPIO_FN_FRB,
+
+	/* VDC3 */
+	GPIO_FN_DV_CLK, GPIO_FN_DV_VSYNC, GPIO_FN_DV_HSYNC,
+	GPIO_FN_DV_DATA7, GPIO_FN_DV_DATA6, GPIO_FN_DV_DATA5, GPIO_FN_DV_DATA4,
+	GPIO_FN_DV_DATA3, GPIO_FN_DV_DATA2, GPIO_FN_DV_DATA1, GPIO_FN_DV_DATA0,
+	GPIO_FN_LCD_CLK, GPIO_FN_LCD_EXTCLK,
+	GPIO_FN_LCD_VSYNC, GPIO_FN_LCD_HSYNC, GPIO_FN_LCD_DE,
+	GPIO_FN_LCD_DATA15, GPIO_FN_LCD_DATA14,
+	GPIO_FN_LCD_DATA13, GPIO_FN_LCD_DATA12,
+	GPIO_FN_LCD_DATA11, GPIO_FN_LCD_DATA10,
+	GPIO_FN_LCD_DATA9, GPIO_FN_LCD_DATA8,
+	GPIO_FN_LCD_DATA7, GPIO_FN_LCD_DATA6,
+	GPIO_FN_LCD_DATA5, GPIO_FN_LCD_DATA4,
+	GPIO_FN_LCD_DATA3, GPIO_FN_LCD_DATA2,
+	GPIO_FN_LCD_DATA1, GPIO_FN_LCD_DATA0,
+	GPIO_FN_LCD_M_DISP,
+};
+
+#endif /* __ASM_SH7264_H__ */
diff --git a/arch/sh/include/cpu-sh2a/cpu/sh7269.h b/arch/sh/include/cpu-sh2a/cpu/sh7269.h
new file mode 100644
index 0000000..48d1449
--- /dev/null
+++ b/arch/sh/include/cpu-sh2a/cpu/sh7269.h
@@ -0,0 +1,201 @@
+#ifndef __ASM_SH7269_H__
+#define __ASM_SH7269_H__
+
+enum {
+	/* Port A */
+	GPIO_PA1, GPIO_PA0,
+
+	/* Port B */
+	GPIO_PB22, GPIO_PB21, GPIO_PB20,
+	GPIO_PB19, GPIO_PB18, GPIO_PB17, GPIO_PB16,
+	GPIO_PB15, GPIO_PB14, GPIO_PB13, GPIO_PB12,
+	GPIO_PB11, GPIO_PB10, GPIO_PB9, GPIO_PB8,
+	GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+	GPIO_PB3, GPIO_PB2, GPIO_PB1,
+
+	/* Port C */
+	GPIO_PC8,
+	GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+	GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+	/* Port D */
+	GPIO_PD15, GPIO_PD14, GPIO_PD13, GPIO_PD12,
+	GPIO_PD11, GPIO_PD10, GPIO_PD9, GPIO_PD8,
+	GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+	GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+	/* Port E */
+	GPIO_PE7, GPIO_PE6, GPIO_PE5, GPIO_PE4,
+	GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+	/* Port F */
+	GPIO_PF23, GPIO_PF22, GPIO_PF21, GPIO_PF20,
+	GPIO_PF19, GPIO_PF18, GPIO_PF17, GPIO_PF16,
+	GPIO_PF15, GPIO_PF14, GPIO_PF13, GPIO_PF12,
+	GPIO_PF11, GPIO_PF10, GPIO_PF9, GPIO_PF8,
+	GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+	GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+	/* Port G */
+	GPIO_PG27, GPIO_PG26, GPIO_PG25, GPIO_PG24,
+	GPIO_PG23, GPIO_PG22, GPIO_PG21, GPIO_PG20,
+	GPIO_PG19, GPIO_PG18, GPIO_PG17, GPIO_PG16,
+	GPIO_PG15, GPIO_PG14, GPIO_PG13, GPIO_PG12,
+	GPIO_PG11, GPIO_PG10, GPIO_PG9, GPIO_PG8,
+	GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+	GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+	/* Port H */
+	GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
+	GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+	/* Port I - not on device */
+
+	/* Port J */
+	GPIO_PJ31, GPIO_PJ30, GPIO_PJ29, GPIO_PJ28,
+	GPIO_PJ27, GPIO_PJ26, GPIO_PJ25, GPIO_PJ24,
+	GPIO_PJ23, GPIO_PJ22, GPIO_PJ21, GPIO_PJ20,
+	GPIO_PJ19, GPIO_PJ18, GPIO_PJ17, GPIO_PJ16,
+	GPIO_PJ15, GPIO_PJ14, GPIO_PJ13, GPIO_PJ12,
+	GPIO_PJ11, GPIO_PJ10, GPIO_PJ9, GPIO_PJ8,
+	GPIO_PJ7, GPIO_PJ6, GPIO_PJ5, GPIO_PJ4,
+	GPIO_PJ3, GPIO_PJ2, GPIO_PJ1, GPIO_PJ0,
+
+	/* INTC: IRQ and PINT */
+	GPIO_FN_IRQ7_PG, GPIO_FN_IRQ6_PG, GPIO_FN_IRQ5_PG, GPIO_FN_IRQ4_PG,
+	GPIO_FN_IRQ3_PG, GPIO_FN_IRQ2_PG, GPIO_FN_IRQ1_PG, GPIO_FN_IRQ0_PG,
+	GPIO_FN_IRQ7_PF, GPIO_FN_IRQ6_PF, GPIO_FN_IRQ5_PF, GPIO_FN_IRQ4_PF,
+	GPIO_FN_IRQ3_PJ, GPIO_FN_IRQ2_PJ, GPIO_FN_IRQ1_PJ, GPIO_FN_IRQ0_PJ,
+	GPIO_FN_IRQ1_PC, GPIO_FN_IRQ0_PC,
+
+	GPIO_FN_PINT7_PG, GPIO_FN_PINT6_PG, GPIO_FN_PINT5_PG, GPIO_FN_PINT4_PG,
+	GPIO_FN_PINT3_PG, GPIO_FN_PINT2_PG, GPIO_FN_PINT1_PG, GPIO_FN_PINT0_PG,
+	GPIO_FN_PINT7_PH, GPIO_FN_PINT6_PH, GPIO_FN_PINT5_PH, GPIO_FN_PINT4_PH,
+	GPIO_FN_PINT3_PH, GPIO_FN_PINT2_PH, GPIO_FN_PINT1_PH, GPIO_FN_PINT0_PH,
+	GPIO_FN_PINT7_PJ, GPIO_FN_PINT6_PJ, GPIO_FN_PINT5_PJ, GPIO_FN_PINT4_PJ,
+	GPIO_FN_PINT3_PJ, GPIO_FN_PINT2_PJ, GPIO_FN_PINT1_PJ, GPIO_FN_PINT0_PJ,
+
+	/* WDT */
+	GPIO_FN_WDTOVF,
+
+	/* CAN */
+	GPIO_FN_CTX1, GPIO_FN_CRX1, GPIO_FN_CTX0, GPIO_FN_CTX0_CTX1,
+	GPIO_FN_CRX0, GPIO_FN_CRX0_CRX1, GPIO_FN_CRX0_CRX1_CRX2,
+
+	/* DMAC */
+	GPIO_FN_TEND0, GPIO_FN_DACK0, GPIO_FN_DREQ0,
+	GPIO_FN_TEND1, GPIO_FN_DACK1, GPIO_FN_DREQ1,
+
+	/* ADC */
+	GPIO_FN_ADTRG,
+
+	/* BSC */
+	GPIO_FN_A25, GPIO_FN_A24,
+	GPIO_FN_A23, GPIO_FN_A22, GPIO_FN_A21, GPIO_FN_A20,
+	GPIO_FN_A19, GPIO_FN_A18, GPIO_FN_A17, GPIO_FN_A16,
+	GPIO_FN_A15, GPIO_FN_A14, GPIO_FN_A13, GPIO_FN_A12,
+	GPIO_FN_A11, GPIO_FN_A10, GPIO_FN_A9, GPIO_FN_A8,
+	GPIO_FN_A7, GPIO_FN_A6, GPIO_FN_A5, GPIO_FN_A4,
+	GPIO_FN_A3, GPIO_FN_A2, GPIO_FN_A1, GPIO_FN_A0,
+	GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
+	GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
+	GPIO_FN_D7, GPIO_FN_D6, GPIO_FN_D5, GPIO_FN_D4,
+	GPIO_FN_D3, GPIO_FN_D2, GPIO_FN_D1, GPIO_FN_D0,
+
+	GPIO_FN_BS,
+	GPIO_FN_CS4, GPIO_FN_CS3, GPIO_FN_CS2, GPIO_FN_CS1, GPIO_FN_CS0,
+	GPIO_FN_CS5CE1A,
+	GPIO_FN_CE2A, GPIO_FN_CE2B,
+	GPIO_FN_RD, GPIO_FN_RDWR,
+	GPIO_FN_WE3ICIOWRAHDQMUU, GPIO_FN_WE2ICIORDDQMUL,
+	GPIO_FN_WE1DQMUWE, GPIO_FN_WE0DQML,
+	GPIO_FN_RAS, GPIO_FN_CAS, GPIO_FN_CKE,
+	GPIO_FN_WAIT, GPIO_FN_BREQ, GPIO_FN_BACK,
+	GPIO_FN_IOIS16,
+
+	/* TMU */
+	GPIO_FN_TIOC4D, GPIO_FN_TIOC4C, GPIO_FN_TIOC4B, GPIO_FN_TIOC4A,
+	GPIO_FN_TIOC3D, GPIO_FN_TIOC3C, GPIO_FN_TIOC3B, GPIO_FN_TIOC3A,
+	GPIO_FN_TIOC2B, GPIO_FN_TIOC1B, GPIO_FN_TIOC2A, GPIO_FN_TIOC1A,
+	GPIO_FN_TIOC0D, GPIO_FN_TIOC0C, GPIO_FN_TIOC0B, GPIO_FN_TIOC0A,
+	GPIO_FN_TCLKD, GPIO_FN_TCLKC, GPIO_FN_TCLKB, GPIO_FN_TCLKA,
+
+	/* SSU */
+	GPIO_FN_SCS0_PD, GPIO_FN_SSO0_PD, GPIO_FN_SSI0_PD, GPIO_FN_SSCK0_PD,
+	GPIO_FN_SCS0_PF, GPIO_FN_SSO0_PF, GPIO_FN_SSI0_PF, GPIO_FN_SSCK0_PF,
+	GPIO_FN_SCS1_PD, GPIO_FN_SSO1_PD, GPIO_FN_SSI1_PD, GPIO_FN_SSCK1_PD,
+	GPIO_FN_SCS1_PF, GPIO_FN_SSO1_PF, GPIO_FN_SSI1_PF, GPIO_FN_SSCK1_PF,
+
+	/* SCIF */
+	GPIO_FN_SCK0, GPIO_FN_RXD0, GPIO_FN_TXD0,
+	GPIO_FN_SCK1, GPIO_FN_RXD1, GPIO_FN_TXD1, GPIO_FN_RTS1, GPIO_FN_CTS1,
+	GPIO_FN_SCK2, GPIO_FN_RXD2, GPIO_FN_TXD2,
+	GPIO_FN_SCK3, GPIO_FN_RXD3, GPIO_FN_TXD3,
+	GPIO_FN_SCK4, GPIO_FN_RXD4, GPIO_FN_TXD4,
+	GPIO_FN_SCK5, GPIO_FN_RXD5, GPIO_FN_TXD5, GPIO_FN_RTS5, GPIO_FN_CTS5,
+	GPIO_FN_SCK6, GPIO_FN_RXD6, GPIO_FN_TXD6,
+	GPIO_FN_SCK7, GPIO_FN_RXD7, GPIO_FN_TXD7, GPIO_FN_RTS7, GPIO_FN_CTS7,
+
+	/* RSPI */
+	GPIO_FN_MISO0_PJ19, GPIO_FN_MISO0_PB20,
+	GPIO_FN_MOSI0_PJ18, GPIO_FN_MOSI0_PB19,
+	GPIO_FN_SSL00_PJ17, GPIO_FN_SSL00_PB18,
+	GPIO_FN_RSPCK0_PJ16, GPIO_FN_RSPCK0_PB17,
+	GPIO_FN_RSPCK1, GPIO_FN_MOSI1,
+	GPIO_FN_MISO1, GPIO_FN_SSL10,
+
+	/* IIC3 */
+	GPIO_FN_SCL0, GPIO_FN_SCL1, GPIO_FN_SCL2,
+	GPIO_FN_SDA2, GPIO_FN_SDA1, GPIO_FN_SDA0,
+
+	/* SSI */
+	GPIO_FN_SSISCK0, GPIO_FN_SSIWS0, GPIO_FN_SSITXD0, GPIO_FN_SSIRXD0,
+	GPIO_FN_SSIWS1, GPIO_FN_SSIWS2, GPIO_FN_SSIWS3,
+	GPIO_FN_SSISCK1, GPIO_FN_SSISCK2, GPIO_FN_SSISCK3,
+	GPIO_FN_SSIDATA1, GPIO_FN_SSIDATA2, GPIO_FN_SSIDATA3,
+	GPIO_FN_AUDIO_CLK,
+	GPIO_FN_AUDIO_XOUT,
+
+	/* SIOF */
+	GPIO_FN_SIOFTXD, GPIO_FN_SIOFRXD, GPIO_FN_SIOFSYNC, GPIO_FN_SIOFSCK,
+
+	/* SPDIF */
+	GPIO_FN_SPDIF_IN,
+	GPIO_FN_SPDIF_OUT,
+
+	/* NANDFMC  */ /* NOTE Controller is not available in boot mode 0 */
+	GPIO_FN_FCE,
+	GPIO_FN_FRB,
+
+	/* VDC */
+	GPIO_FN_DV_CLK, GPIO_FN_DV_VSYNC, GPIO_FN_DV_HSYNC,
+	GPIO_FN_DV_DATA23, GPIO_FN_DV_DATA22,
+	GPIO_FN_DV_DATA21, GPIO_FN_DV_DATA20,
+	GPIO_FN_DV_DATA19, GPIO_FN_DV_DATA18,
+	GPIO_FN_DV_DATA17, GPIO_FN_DV_DATA16,
+	GPIO_FN_DV_DATA15, GPIO_FN_DV_DATA14,
+	GPIO_FN_DV_DATA13, GPIO_FN_DV_DATA12,
+	GPIO_FN_DV_DATA11, GPIO_FN_DV_DATA10,
+	GPIO_FN_DV_DATA9, GPIO_FN_DV_DATA8,
+	GPIO_FN_DV_DATA7, GPIO_FN_DV_DATA6,
+	GPIO_FN_DV_DATA5, GPIO_FN_DV_DATA4,
+	GPIO_FN_DV_DATA3, GPIO_FN_DV_DATA2,
+	GPIO_FN_DV_DATA1, GPIO_FN_DV_DATA0,
+	GPIO_FN_LCD_CLK, GPIO_FN_LCD_EXTCLK,
+	GPIO_FN_LCD_VSYNC, GPIO_FN_LCD_HSYNC, GPIO_FN_LCD_DE,
+	GPIO_FN_LCD_DATA23, GPIO_FN_LCD_DATA22,
+	GPIO_FN_LCD_DATA21, GPIO_FN_LCD_DATA20,
+	GPIO_FN_LCD_DATA19, GPIO_FN_LCD_DATA18,
+	GPIO_FN_LCD_DATA17, GPIO_FN_LCD_DATA16,
+	GPIO_FN_LCD_DATA15, GPIO_FN_LCD_DATA14,
+	GPIO_FN_LCD_DATA13, GPIO_FN_LCD_DATA12,
+	GPIO_FN_LCD_DATA11, GPIO_FN_LCD_DATA10,
+	GPIO_FN_LCD_DATA9, GPIO_FN_LCD_DATA8,
+	GPIO_FN_LCD_DATA7, GPIO_FN_LCD_DATA6,
+	GPIO_FN_LCD_DATA5, GPIO_FN_LCD_DATA4,
+	GPIO_FN_LCD_DATA3, GPIO_FN_LCD_DATA2,
+	GPIO_FN_LCD_DATA1, GPIO_FN_LCD_DATA0,
+	GPIO_FN_LCD_M_DISP,
+};
+
+#endif /* __ASM_SH7269_H__ */
diff --git a/arch/sh/include/cpu-sh3/cpu/dma.h b/arch/sh/include/cpu-sh3/cpu/dma.h
index 24e28b9..bccb414 100644
--- a/arch/sh/include/cpu-sh3/cpu/dma.h
+++ b/arch/sh/include/cpu-sh3/cpu/dma.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_CPU_SH3_DMA_H
 #define __ASM_CPU_SH3_DMA_H
 
+#include <linux/sh_intc.h>
+
 #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
     defined(CONFIG_CPU_SUBTYPE_SH7710) || \
@@ -10,14 +12,7 @@
 #define SH_DMAC_BASE0	0xa4000020
 #endif
 
-#define DMTE0_IRQ	48
-#define DMTE4_IRQ	76
-
-/* Definitions for the SuperH DMAC */
-#define TM_BURST	0x00000020
-#define TS_8		0x00000000
-#define TS_16		0x00000008
-#define TS_32		0x00000010
-#define TS_128		0x00000018
+#define DMTE0_IRQ	evt2irq(0x800)
+#define DMTE4_IRQ	evt2irq(0xb80)
 
 #endif /* __ASM_CPU_SH3_DMA_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h b/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h
deleted file mode 100644
index 9647e68..0000000
--- a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
-#define __ASM_SH_CPU_SH4_DMA_SH7780_H
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7343) || \
-	defined(CONFIG_CPU_SUBTYPE_SH7730)
-#define DMTE0_IRQ	48
-#define DMTE4_IRQ	76
-#define DMAE0_IRQ	78	/* DMA Error IRQ*/
-#define SH_DMAC_BASE0	0xFE008020
-#define SH_DMARS_BASE0	0xFE009000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-#define DMTE0_IRQ	48
-#define DMTE4_IRQ	76
-#define DMAE0_IRQ	78	/* DMA Error IRQ*/
-#define SH_DMAC_BASE0	0xFE008020
-#define SH_DMARS_BASE0	0xFE009000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
-	defined(CONFIG_CPU_SUBTYPE_SH7764)
-#define DMTE0_IRQ	34
-#define DMTE4_IRQ	44
-#define DMAE0_IRQ	38
-#define SH_DMAC_BASE0	0xFF608020
-#define SH_DMARS_BASE0	0xFF609000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-#define DMTE0_IRQ	48	/* DMAC0A*/
-#define DMTE4_IRQ	76	/* DMAC0B */
-#define DMTE6_IRQ	40
-#define DMTE8_IRQ	42	/* DMAC1A */
-#define DMTE9_IRQ	43
-#define DMTE10_IRQ	72	/* DMAC1B */
-#define DMTE11_IRQ	73
-#define DMAE0_IRQ	78	/* DMA Error IRQ*/
-#define DMAE1_IRQ	74	/* DMA Error IRQ*/
-#define SH_DMAC_BASE0	0xFE008020
-#define SH_DMAC_BASE1	0xFDC08020
-#define SH_DMARS_BASE0	0xFDC09000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-#define DMTE0_IRQ	48	/* DMAC0A*/
-#define DMTE4_IRQ	76	/* DMAC0B */
-#define DMTE6_IRQ	40
-#define DMTE8_IRQ	42	/* DMAC1A */
-#define DMTE9_IRQ	43
-#define DMTE10_IRQ	72	/* DMAC1B */
-#define DMTE11_IRQ	73
-#define DMAE0_IRQ	78	/* DMA Error IRQ*/
-#define DMAE1_IRQ	74	/* DMA Error IRQ*/
-#define SH_DMAC_BASE0	0xFE008020
-#define SH_DMAC_BASE1	0xFDC08020
-#define SH_DMARS_BASE0	0xFE009000
-#define SH_DMARS_BASE1	0xFDC09000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-#define DMTE0_IRQ	34
-#define DMTE4_IRQ	44
-#define DMTE6_IRQ	46
-#define DMTE8_IRQ	92
-#define DMTE9_IRQ	93
-#define DMTE10_IRQ	94
-#define DMTE11_IRQ	95
-#define DMAE0_IRQ	38	/* DMA Error IRQ */
-#define SH_DMAC_BASE0	0xFC808020
-#define SH_DMAC_BASE1	0xFC818020
-#define SH_DMARS_BASE0	0xFC809000
-#else /* SH7785 */
-#define DMTE0_IRQ	33
-#define DMTE4_IRQ	37
-#define DMTE6_IRQ	52
-#define DMTE8_IRQ	54
-#define DMTE9_IRQ	55
-#define DMTE10_IRQ	56
-#define DMTE11_IRQ	57
-#define DMAE0_IRQ	39	/* DMA Error IRQ0 */
-#define DMAE1_IRQ	58	/* DMA Error IRQ1 */
-#define SH_DMAC_BASE0	0xFC808020
-#define SH_DMAC_BASE1	0xFCC08020
-#define SH_DMARS_BASE0	0xFC809000
-#endif
-
-#define REQ_HE		0x000000C0
-#define REQ_H		0x00000080
-#define REQ_LE		0x00000040
-#define TM_BURST	0x00000020
-
-#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/dma.h b/arch/sh/include/cpu-sh4/cpu/dma.h
index ca747e9..a520eb2 100644
--- a/arch/sh/include/cpu-sh4/cpu/dma.h
+++ b/arch/sh/include/cpu-sh4/cpu/dma.h
@@ -1,32 +1,17 @@
 #ifndef __ASM_CPU_SH4_DMA_H
 #define __ASM_CPU_SH4_DMA_H
 
-/* SH7751/7760/7780 DMA IRQ sources */
+#include <linux/sh_intc.h>
 
-#ifdef CONFIG_CPU_SH4A
-
-#include <cpu/dma-sh4a.h>
-
-#else /* CONFIG_CPU_SH4A */
 /*
  * SH7750/SH7751/SH7760
  */
-#define DMTE0_IRQ	34
-#define DMTE4_IRQ	44
-#define DMTE6_IRQ	46
-#define DMAE0_IRQ	38
+#define DMTE0_IRQ	evt2irq(0x640)
+#define DMTE4_IRQ	evt2irq(0x780)
+#define DMTE6_IRQ	evt2irq(0x7c0)
+#define DMAE0_IRQ	evt2irq(0x6c0)
 
 #define SH_DMAC_BASE0	0xffa00000
 #define SH_DMAC_BASE1	0xffa00070
-/* Definitions for the SuperH DMAC */
-#define TM_BURST	0x00000080
-#define TS_8		0x00000010
-#define TS_16		0x00000020
-#define TS_32		0x00000030
-#define TS_64		0x00000000
-
-#define DMAOR_COD	0x00000008
-
-#endif
 
 #endif /* __ASM_CPU_SH4_DMA_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/freq.h b/arch/sh/include/cpu-sh4/cpu/freq.h
index cffd25e..1631fc2 100644
--- a/arch/sh/include/cpu-sh4/cpu/freq.h
+++ b/arch/sh/include/cpu-sh4/cpu/freq.h
@@ -47,6 +47,11 @@
 #define MSTPCR1			0xa4150034
 #define MSTPCR2			0xa4150038
 
+#elif defined(CONFIG_CPU_SUBTYPE_SH7734)
+#define FRQCR0			0xffc80000
+#define FRQCR2			0xffc80008
+#define FRQMR1			0xffc80014
+#define FRQMR2			0xffc80018
 #elif defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define FRQCR0			0xffc80000
 #define FRQCR1			0xffc80004
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7734.h b/arch/sh/include/cpu-sh4/cpu/sh7734.h
new file mode 100644
index 0000000..2fb9a7b
--- /dev/null
+++ b/arch/sh/include/cpu-sh4/cpu/sh7734.h
@@ -0,0 +1,306 @@
+#ifndef __ASM_SH7734_H__
+#define __ASM_SH7734_H__
+
+/* Pin Function Controller:
+ * GPIO_FN_xx - GPIO used to select pin function
+ * GPIO_GP_x_x - GPIO mapped to real I/O pin on CPU
+ */
+enum {
+	GPIO_GP_0_0, GPIO_GP_0_1, GPIO_GP_0_2, GPIO_GP_0_3,
+	GPIO_GP_0_4, GPIO_GP_0_5, GPIO_GP_0_6, GPIO_GP_0_7,
+	GPIO_GP_0_8, GPIO_GP_0_9, GPIO_GP_0_10, GPIO_GP_0_11,
+	GPIO_GP_0_12, GPIO_GP_0_13, GPIO_GP_0_14, GPIO_GP_0_15,
+	GPIO_GP_0_16, GPIO_GP_0_17, GPIO_GP_0_18, GPIO_GP_0_19,
+	GPIO_GP_0_20, GPIO_GP_0_21, GPIO_GP_0_22, GPIO_GP_0_23,
+	GPIO_GP_0_24, GPIO_GP_0_25, GPIO_GP_0_26, GPIO_GP_0_27,
+	GPIO_GP_0_28, GPIO_GP_0_29, GPIO_GP_0_30, GPIO_GP_0_31,
+
+	GPIO_GP_1_0, GPIO_GP_1_1, GPIO_GP_1_2, GPIO_GP_1_3,
+	GPIO_GP_1_4, GPIO_GP_1_5, GPIO_GP_1_6, GPIO_GP_1_7,
+	GPIO_GP_1_8, GPIO_GP_1_9, GPIO_GP_1_10, GPIO_GP_1_11,
+	GPIO_GP_1_12, GPIO_GP_1_13, GPIO_GP_1_14, GPIO_GP_1_15,
+	GPIO_GP_1_16, GPIO_GP_1_17, GPIO_GP_1_18, GPIO_GP_1_19,
+	GPIO_GP_1_20, GPIO_GP_1_21, GPIO_GP_1_22, GPIO_GP_1_23,
+	GPIO_GP_1_24, GPIO_GP_1_25, GPIO_GP_1_26, GPIO_GP_1_27,
+	GPIO_GP_1_28, GPIO_GP_1_29, GPIO_GP_1_30, GPIO_GP_1_31,
+
+	GPIO_GP_2_0, GPIO_GP_2_1, GPIO_GP_2_2, GPIO_GP_2_3,
+	GPIO_GP_2_4, GPIO_GP_2_5, GPIO_GP_2_6, GPIO_GP_2_7,
+	GPIO_GP_2_8, GPIO_GP_2_9, GPIO_GP_2_10, GPIO_GP_2_11,
+	GPIO_GP_2_12, GPIO_GP_2_13, GPIO_GP_2_14, GPIO_GP_2_15,
+	GPIO_GP_2_16, GPIO_GP_2_17, GPIO_GP_2_18, GPIO_GP_2_19,
+	GPIO_GP_2_20, GPIO_GP_2_21, GPIO_GP_2_22, GPIO_GP_2_23,
+	GPIO_GP_2_24, GPIO_GP_2_25, GPIO_GP_2_26, GPIO_GP_2_27,
+	GPIO_GP_2_28, GPIO_GP_2_29, GPIO_GP_2_30, GPIO_GP_2_31,
+
+	GPIO_GP_3_0, GPIO_GP_3_1, GPIO_GP_3_2, GPIO_GP_3_3,
+	GPIO_GP_3_4, GPIO_GP_3_5, GPIO_GP_3_6, GPIO_GP_3_7,
+	GPIO_GP_3_8, GPIO_GP_3_9, GPIO_GP_3_10, GPIO_GP_3_11,
+	GPIO_GP_3_12, GPIO_GP_3_13, GPIO_GP_3_14, GPIO_GP_3_15,
+	GPIO_GP_3_16, GPIO_GP_3_17, GPIO_GP_3_18, GPIO_GP_3_19,
+	GPIO_GP_3_20, GPIO_GP_3_21, GPIO_GP_3_22, GPIO_GP_3_23,
+	GPIO_GP_3_24, GPIO_GP_3_25, GPIO_GP_3_26, GPIO_GP_3_27,
+	GPIO_GP_3_28, GPIO_GP_3_29, GPIO_GP_3_30, GPIO_GP_3_31,
+
+	GPIO_GP_4_0, GPIO_GP_4_1, GPIO_GP_4_2, GPIO_GP_4_3,
+	GPIO_GP_4_4, GPIO_GP_4_5, GPIO_GP_4_6, GPIO_GP_4_7,
+	GPIO_GP_4_8, GPIO_GP_4_9, GPIO_GP_4_10, GPIO_GP_4_11,
+	GPIO_GP_4_12, GPIO_GP_4_13, GPIO_GP_4_14, GPIO_GP_4_15,
+	GPIO_GP_4_16, GPIO_GP_4_17, GPIO_GP_4_18, GPIO_GP_4_19,
+	GPIO_GP_4_20, GPIO_GP_4_21, GPIO_GP_4_22, GPIO_GP_4_23,
+	GPIO_GP_4_24, GPIO_GP_4_25, GPIO_GP_4_26, GPIO_GP_4_27,
+	GPIO_GP_4_28, GPIO_GP_4_29, GPIO_GP_4_30, GPIO_GP_4_31,
+
+	GPIO_GP_5_0, GPIO_GP_5_1, GPIO_GP_5_2, GPIO_GP_5_3,
+	GPIO_GP_5_4, GPIO_GP_5_5, GPIO_GP_5_6, GPIO_GP_5_7,
+	GPIO_GP_5_8, GPIO_GP_5_9, GPIO_GP_5_10, GPIO_GP_5_11,
+
+	GPIO_FN_CLKOUT, GPIO_FN_BS, GPIO_FN_CS0, GPIO_FN_EX_CS0, GPIO_FN_RD,
+		GPIO_FN_WE0, GPIO_FN_WE1,
+
+	GPIO_FN_SCL0, GPIO_FN_PENC0, GPIO_FN_USB_OVC0,
+
+	GPIO_FN_IRQ2_B, GPIO_FN_IRQ3_B,
+
+	/* IPSR0 */
+	GPIO_FN_A15, GPIO_FN_ST0_VCO_CLKIN, GPIO_FN_LCD_DATA15_A,
+		GPIO_FN_TIOC3D_C,
+	GPIO_FN_A14, GPIO_FN_LCD_DATA14_A, GPIO_FN_TIOC3C_C,
+	GPIO_FN_A13, GPIO_FN_LCD_DATA13_A, GPIO_FN_TIOC3B_C,
+	GPIO_FN_A12, GPIO_FN_LCD_DATA12_A, GPIO_FN_TIOC3A_C,
+	GPIO_FN_A11, GPIO_FN_ST0_D7, GPIO_FN_LCD_DATA11_A,
+		GPIO_FN_TIOC2B_C,
+	GPIO_FN_A10, GPIO_FN_ST0_D6, GPIO_FN_LCD_DATA10_A,
+		GPIO_FN_TIOC2A_C,
+	GPIO_FN_A9, GPIO_FN_ST0_D5, GPIO_FN_LCD_DATA9_A,
+		GPIO_FN_TIOC1B_C,
+	GPIO_FN_A8, GPIO_FN_ST0_D4, GPIO_FN_LCD_DATA8_A,
+		GPIO_FN_TIOC1A_C,
+	GPIO_FN_A7, GPIO_FN_ST0_D3, GPIO_FN_LCD_DATA7_A, GPIO_FN_TIOC0D_C,
+	GPIO_FN_A6, GPIO_FN_ST0_D2, GPIO_FN_LCD_DATA6_A, GPIO_FN_TIOC0C_C,
+	GPIO_FN_A5, GPIO_FN_ST0_D1, GPIO_FN_LCD_DATA5_A, GPIO_FN_TIOC0B_C,
+	GPIO_FN_A4, GPIO_FN_ST0_D0, GPIO_FN_LCD_DATA4_A, GPIO_FN_TIOC0A_C,
+	GPIO_FN_A3, GPIO_FN_ST0_VLD, GPIO_FN_LCD_DATA3_A, GPIO_FN_TCLKD_C,
+	GPIO_FN_A2, GPIO_FN_ST0_SYC, GPIO_FN_LCD_DATA2_A, GPIO_FN_TCLKC_C,
+	GPIO_FN_A1, GPIO_FN_ST0_REQ, GPIO_FN_LCD_DATA1_A, GPIO_FN_TCLKB_C,
+	GPIO_FN_A0, GPIO_FN_ST0_CLKIN, GPIO_FN_LCD_DATA0_A, GPIO_FN_TCLKA_C,
+
+	/* IPSR1 */
+	GPIO_FN_D3, GPIO_FN_SD0_DAT3_A, GPIO_FN_MMC_D3_A, GPIO_FN_ST1_D6,
+		GPIO_FN_FD3_A,
+	GPIO_FN_D2, GPIO_FN_SD0_DAT2_A, GPIO_FN_MMC_D2_A, GPIO_FN_ST1_D5,
+		GPIO_FN_FD2_A,
+	GPIO_FN_D1, GPIO_FN_SD0_DAT1_A, GPIO_FN_MMC_D1_A, GPIO_FN_ST1_D4,
+		GPIO_FN_FD1_A,
+	GPIO_FN_D0, GPIO_FN_SD0_DAT0_A, GPIO_FN_MMC_D0_A, GPIO_FN_ST1_D3,
+		GPIO_FN_FD0_A,
+	GPIO_FN_A25, GPIO_FN_TX2_D, GPIO_FN_ST1_D2,
+	GPIO_FN_A24, GPIO_FN_RX2_D, GPIO_FN_ST1_D1,
+	GPIO_FN_A23, GPIO_FN_ST1_D0, GPIO_FN_LCD_M_DISP_A,
+	GPIO_FN_A22, GPIO_FN_ST1_VLD, GPIO_FN_LCD_VEPWC_A,
+	GPIO_FN_A21, GPIO_FN_ST1_SYC, GPIO_FN_LCD_VCPWC_A,
+	GPIO_FN_A20, GPIO_FN_ST1_REQ, GPIO_FN_LCD_FLM_A,
+	GPIO_FN_A19, GPIO_FN_ST1_CLKIN, GPIO_FN_LCD_CLK_A, GPIO_FN_TIOC4D_C,
+	GPIO_FN_A18, GPIO_FN_ST1_PWM, GPIO_FN_LCD_CL2_A, GPIO_FN_TIOC4C_C,
+	GPIO_FN_A17, GPIO_FN_ST1_VCO_CLKIN, GPIO_FN_LCD_CL1_A, GPIO_FN_TIOC4B_C,
+	GPIO_FN_A16, GPIO_FN_ST0_PWM, GPIO_FN_LCD_DON_A, GPIO_FN_TIOC4A_C,
+
+	/* IPSR2 */
+	GPIO_FN_D14, GPIO_FN_TX2_B, GPIO_FN_FSE_A, GPIO_FN_ET0_TX_CLK_B,
+	GPIO_FN_D13, GPIO_FN_RX2_B, GPIO_FN_FRB_A,	GPIO_FN_ET0_ETXD6_B,
+	GPIO_FN_D12, GPIO_FN_FWE_A, GPIO_FN_ET0_ETXD5_B,
+	GPIO_FN_D11, GPIO_FN_RSPI_MISO_A, GPIO_FN_QMI_QIO1_A,
+		GPIO_FN_FRE_A, GPIO_FN_ET0_ETXD3_B,
+	GPIO_FN_D10, GPIO_FN_RSPI_MOSI_A, GPIO_FN_QMO_QIO0_A,
+		GPIO_FN_FALE_A, GPIO_FN_ET0_ETXD2_B,
+	GPIO_FN_D9, GPIO_FN_SD0_CMD_A, GPIO_FN_MMC_CMD_A, GPIO_FN_QIO3_A,
+		GPIO_FN_FCLE_A, GPIO_FN_ET0_ETXD1_B,
+	GPIO_FN_D8, GPIO_FN_SD0_CLK_A, GPIO_FN_MMC_CLK_A, GPIO_FN_QIO2_A,
+		GPIO_FN_FCE_A, GPIO_FN_ET0_GTX_CLK_B,
+	GPIO_FN_D7, GPIO_FN_RSPI_SSL_A, GPIO_FN_MMC_D7_A, GPIO_FN_QSSL_A,
+		GPIO_FN_FD7_A,
+	GPIO_FN_D6, GPIO_FN_RSPI_RSPCK_A, GPIO_FN_MMC_D6_A, GPIO_FN_QSPCLK_A,
+		GPIO_FN_FD6_A,
+	GPIO_FN_D5, GPIO_FN_SD0_WP_A, GPIO_FN_MMC_D5_A, GPIO_FN_FD5_A,
+	GPIO_FN_D4, GPIO_FN_SD0_CD_A, GPIO_FN_MMC_D4_A, GPIO_FN_ST1_D7,
+		GPIO_FN_FD4_A,
+
+	/* IPSR3 */
+	GPIO_FN_DRACK0, GPIO_FN_SD1_DAT2_A, GPIO_FN_ATAG, GPIO_FN_TCLK1_A,
+		GPIO_FN_ET0_ETXD7,
+	GPIO_FN_EX_WAIT2, GPIO_FN_SD1_DAT1_A, GPIO_FN_DACK2, GPIO_FN_CAN1_RX_C,
+		GPIO_FN_ET0_MAGIC_C, GPIO_FN_ET0_ETXD6_A,
+	GPIO_FN_EX_WAIT1, GPIO_FN_SD1_DAT0_A, GPIO_FN_DREQ2, GPIO_FN_CAN1_TX_C,
+		GPIO_FN_ET0_LINK_C, GPIO_FN_ET0_ETXD5_A,
+	GPIO_FN_EX_WAIT0, GPIO_FN_TCLK1_B,
+	GPIO_FN_RD_WR, GPIO_FN_TCLK0,
+	GPIO_FN_EX_CS5, GPIO_FN_SD1_CMD_A, GPIO_FN_ATADIR, GPIO_FN_QSSL_B,
+		GPIO_FN_ET0_ETXD3_A,
+	GPIO_FN_EX_CS4, GPIO_FN_SD1_WP_A, GPIO_FN_ATAWR, GPIO_FN_QMI_QIO1_B,
+		GPIO_FN_ET0_ETXD2_A,
+	GPIO_FN_EX_CS3, GPIO_FN_SD1_CD_A, GPIO_FN_ATARD, GPIO_FN_QMO_QIO0_B,
+		GPIO_FN_ET0_ETXD1_A,
+	GPIO_FN_EX_CS2, GPIO_FN_TX3_B, GPIO_FN_ATACS1, GPIO_FN_QSPCLK_B,
+		GPIO_FN_ET0_GTX_CLK_A,
+	GPIO_FN_EX_CS1, GPIO_FN_RX3_B, GPIO_FN_ATACS0, GPIO_FN_QIO2_B,
+		GPIO_FN_ET0_ETXD0,
+	GPIO_FN_CS1_A26, GPIO_FN_QIO3_B,
+	GPIO_FN_D15, GPIO_FN_SCK2_B,
+
+	/* IPSR4 */
+	GPIO_FN_SCK2_A, GPIO_FN_VI0_G3,
+	GPIO_FN_RTS1_B, GPIO_FN_VI0_G2,
+	GPIO_FN_CTS1_B, GPIO_FN_VI0_DATA7_VI0_G1,
+	GPIO_FN_TX1_B, GPIO_FN_VI0_DATA6_VI0_G0, GPIO_FN_ET0_PHY_INT_A,
+	GPIO_FN_RX1_B, GPIO_FN_VI0_DATA5_VI0_B5, GPIO_FN_ET0_MAGIC_A,
+	GPIO_FN_SCK1_B, GPIO_FN_VI0_DATA4_VI0_B4, GPIO_FN_ET0_LINK_A,
+	GPIO_FN_RTS0_B, GPIO_FN_VI0_DATA3_VI0_B3, GPIO_FN_ET0_MDIO_A,
+	GPIO_FN_CTS0_B, GPIO_FN_VI0_DATA2_VI0_B2, GPIO_FN_RMII0_MDIO_A,
+		GPIO_FN_ET0_MDC,
+	GPIO_FN_HTX0_A, GPIO_FN_TX1_A, GPIO_FN_VI0_DATA1_VI0_B1,
+		GPIO_FN_RMII0_MDC_A, GPIO_FN_ET0_COL,
+	GPIO_FN_HRX0_A, GPIO_FN_RX1_A, GPIO_FN_VI0_DATA0_VI0_B0,
+		GPIO_FN_RMII0_CRS_DV_A, GPIO_FN_ET0_CRS,
+	GPIO_FN_HSCK0_A, GPIO_FN_SCK1_A, GPIO_FN_VI0_VSYNC,
+		GPIO_FN_RMII0_RX_ER_A, GPIO_FN_ET0_RX_ER,
+	GPIO_FN_HRTS0_A, GPIO_FN_RTS1_A, GPIO_FN_VI0_HSYNC,
+		GPIO_FN_RMII0_TXD_EN_A, GPIO_FN_ET0_RX_DV,
+	GPIO_FN_HCTS0_A, GPIO_FN_CTS1_A, GPIO_FN_VI0_FIELD,
+		GPIO_FN_RMII0_RXD1_A, GPIO_FN_ET0_ERXD7,
+
+	/* IPSR5 */
+	GPIO_FN_SD2_CLK_A, GPIO_FN_RX2_A, GPIO_FN_VI0_G4, GPIO_FN_ET0_RX_CLK_B,
+	GPIO_FN_SD2_CMD_A, GPIO_FN_TX2_A, GPIO_FN_VI0_G5, GPIO_FN_ET0_ERXD2_B,
+	GPIO_FN_SD2_DAT0_A, GPIO_FN_RX3_A, GPIO_FN_VI0_R0, GPIO_FN_ET0_ERXD3_B,
+	GPIO_FN_SD2_DAT1_A, GPIO_FN_TX3_A, GPIO_FN_VI0_R1, GPIO_FN_ET0_MDIO_B,
+	GPIO_FN_SD2_DAT2_A, GPIO_FN_RX4_A, GPIO_FN_VI0_R2, GPIO_FN_ET0_LINK_B,
+	GPIO_FN_SD2_DAT3_A, GPIO_FN_TX4_A, GPIO_FN_VI0_R3, GPIO_FN_ET0_MAGIC_B,
+	GPIO_FN_SD2_CD_A, GPIO_FN_RX5_A, GPIO_FN_VI0_R4, GPIO_FN_ET0_PHY_INT_B,
+	GPIO_FN_SD2_WP_A, GPIO_FN_TX5_A, GPIO_FN_VI0_R5,
+	GPIO_FN_REF125CK, GPIO_FN_ADTRG, GPIO_FN_RX5_C,
+	GPIO_FN_REF50CK, GPIO_FN_CTS1_E, GPIO_FN_HCTS0_D,
+
+	/* IPSR6 */
+	GPIO_FN_DU0_DR0, GPIO_FN_SCIF_CLK_B, GPIO_FN_HRX0_D, GPIO_FN_IETX_A,
+		GPIO_FN_TCLKA_A, GPIO_FN_HIFD00,
+	GPIO_FN_DU0_DR1, GPIO_FN_SCK0_B, GPIO_FN_HTX0_D, GPIO_FN_IERX_A,
+		GPIO_FN_TCLKB_A, GPIO_FN_HIFD01,
+	GPIO_FN_DU0_DR2, GPIO_FN_RX0_B, GPIO_FN_TCLKC_A, GPIO_FN_HIFD02,
+	GPIO_FN_DU0_DR3, GPIO_FN_TX0_B, GPIO_FN_TCLKD_A, GPIO_FN_HIFD03,
+	GPIO_FN_DU0_DR4, GPIO_FN_CTS0_C, GPIO_FN_TIOC0A_A, GPIO_FN_HIFD04,
+	GPIO_FN_DU0_DR5, GPIO_FN_RTS0_C, GPIO_FN_TIOC0B_A, GPIO_FN_HIFD05,
+	GPIO_FN_DU0_DR6, GPIO_FN_SCK1_C, GPIO_FN_TIOC0C_A, GPIO_FN_HIFD06,
+	GPIO_FN_DU0_DR7, GPIO_FN_RX1_C, GPIO_FN_TIOC0D_A, GPIO_FN_HIFD07,
+	GPIO_FN_DU0_DG0, GPIO_FN_TX1_C, GPIO_FN_HSCK0_D, GPIO_FN_IECLK_A,
+		GPIO_FN_TIOC1A_A, GPIO_FN_HIFD08,
+	GPIO_FN_DU0_DG1, GPIO_FN_CTS1_C, GPIO_FN_HRTS0_D, GPIO_FN_TIOC1B_A,
+		GPIO_FN_HIFD09,
+
+	/* IPSR7 */
+	GPIO_FN_DU0_DG2, GPIO_FN_RTS1_C, GPIO_FN_RMII0_MDC_B, GPIO_FN_TIOC2A_A,
+		GPIO_FN_HIFD10,
+	GPIO_FN_DU0_DG3, GPIO_FN_SCK2_C, GPIO_FN_RMII0_MDIO_B, GPIO_FN_TIOC2B_A,
+		GPIO_FN_HIFD11,
+	GPIO_FN_DU0_DG4, GPIO_FN_RX2_C, GPIO_FN_RMII0_CRS_DV_B,
+		GPIO_FN_TIOC3A_A, GPIO_FN_HIFD12,
+	GPIO_FN_DU0_DG5, GPIO_FN_TX2_C, GPIO_FN_RMII0_RX_ER_B,
+		GPIO_FN_TIOC3B_A, GPIO_FN_HIFD13,
+	GPIO_FN_DU0_DG6, GPIO_FN_RX3_C, GPIO_FN_RMII0_RXD0_B,
+		GPIO_FN_TIOC3C_A, GPIO_FN_HIFD14,
+	GPIO_FN_DU0_DG7, GPIO_FN_TX3_C, GPIO_FN_RMII0_RXD1_B,
+		GPIO_FN_TIOC3D_A, GPIO_FN_HIFD15,
+	GPIO_FN_DU0_DB0, GPIO_FN_RX4_C, GPIO_FN_RMII0_TXD_EN_B,
+		GPIO_FN_TIOC4A_A, GPIO_FN_HIFCS,
+	GPIO_FN_DU0_DB1, GPIO_FN_TX4_C, GPIO_FN_RMII0_TXD0_B,
+		GPIO_FN_TIOC4B_A, GPIO_FN_HIFRS,
+	GPIO_FN_DU0_DB2, GPIO_FN_RX5_B, GPIO_FN_RMII0_TXD1_B,
+		GPIO_FN_TIOC4C_A, GPIO_FN_HIFWR,
+	GPIO_FN_DU0_DB3, GPIO_FN_TX5_B, GPIO_FN_TIOC4D_A, GPIO_FN_HIFRD,
+	GPIO_FN_DU0_DB4, GPIO_FN_HIFINT,
+
+	/* IPSR8 */
+	GPIO_FN_DU0_DB5, GPIO_FN_HIFDREQ,
+	GPIO_FN_DU0_DB6, GPIO_FN_HIFRDY,
+	GPIO_FN_DU0_DB7, GPIO_FN_SSI_SCK0_B, GPIO_FN_HIFEBL_B,
+	GPIO_FN_DU0_DOTCLKIN, GPIO_FN_HSPI_CS0_C, GPIO_FN_SSI_WS0_B,
+	GPIO_FN_DU0_DOTCLKOUT, GPIO_FN_HSPI_CLK0_C, GPIO_FN_SSI_SDATA0_B,
+	GPIO_FN_DU0_EXHSYNC_DU0_HSYNC, GPIO_FN_HSPI_TX0_C, GPIO_FN_SSI_SCK1_B,
+	GPIO_FN_DU0_EXVSYNC_DU0_VSYNC, GPIO_FN_HSPI_RX0_C, GPIO_FN_SSI_WS1_B,
+	GPIO_FN_DU0_EXODDF_DU0_ODDF, GPIO_FN_CAN0_RX_B, GPIO_FN_HSCK0_B,
+		GPIO_FN_SSI_SDATA1_B,
+	GPIO_FN_DU0_DISP, GPIO_FN_CAN0_TX_B, GPIO_FN_HRX0_B,
+		GPIO_FN_AUDIO_CLKA_B,
+	GPIO_FN_DU0_CDE, GPIO_FN_HTX0_B, GPIO_FN_AUDIO_CLKB_B,
+		GPIO_FN_LCD_VCPWC_B,
+	GPIO_FN_IRQ0_A, GPIO_FN_HSPI_TX_B, GPIO_FN_RX3_E, GPIO_FN_ET0_ERXD0,
+	GPIO_FN_IRQ1_A, GPIO_FN_HSPI_RX_B, GPIO_FN_TX3_E, GPIO_FN_ET0_ERXD1,
+	GPIO_FN_IRQ2_A, GPIO_FN_CTS0_A, GPIO_FN_HCTS0_B, GPIO_FN_ET0_ERXD2_A,
+	GPIO_FN_IRQ3_A, GPIO_FN_RTS0_A, GPIO_FN_HRTS0_B, GPIO_FN_ET0_ERXD3_A,
+
+	/* IPSR9 */
+	GPIO_FN_VI1_CLK_A, GPIO_FN_FD0_B, GPIO_FN_LCD_DATA0_B,
+	GPIO_FN_VI1_0_A, GPIO_FN_FD1_B, GPIO_FN_LCD_DATA1_B,
+	GPIO_FN_VI1_1_A, GPIO_FN_FD2_B, GPIO_FN_LCD_DATA2_B,
+	GPIO_FN_VI1_2_A, GPIO_FN_FD3_B, GPIO_FN_LCD_DATA3_B,
+	GPIO_FN_VI1_3_A, GPIO_FN_FD4_B, GPIO_FN_LCD_DATA4_B,
+	GPIO_FN_VI1_4_A, GPIO_FN_FD5_B, GPIO_FN_LCD_DATA5_B,
+	GPIO_FN_VI1_5_A, GPIO_FN_FD6_B, GPIO_FN_LCD_DATA6_B,
+	GPIO_FN_VI1_6_A, GPIO_FN_FD7_B, GPIO_FN_LCD_DATA7_B,
+	GPIO_FN_VI1_7_A, GPIO_FN_FCE_B, GPIO_FN_LCD_DATA8_B,
+	GPIO_FN_SSI_SCK0_A, GPIO_FN_TIOC1A_B, GPIO_FN_LCD_DATA9_B,
+	GPIO_FN_SSI_WS0_A, GPIO_FN_TIOC1B_B, GPIO_FN_LCD_DATA10_B,
+	GPIO_FN_SSI_SDATA0_A, GPIO_FN_VI1_0_B, GPIO_FN_TIOC2A_B,
+		GPIO_FN_LCD_DATA11_B,
+	GPIO_FN_SSI_SCK1_A, GPIO_FN_VI1_1_B, GPIO_FN_TIOC2B_B,
+		GPIO_FN_LCD_DATA12_B,
+	GPIO_FN_SSI_WS1_A, GPIO_FN_VI1_2_B, GPIO_FN_LCD_DATA13_B,
+	GPIO_FN_SSI_SDATA1_A, GPIO_FN_VI1_3_B, GPIO_FN_LCD_DATA14_B,
+
+	/* IPSR10 */
+	GPIO_FN_SSI_SCK23, GPIO_FN_VI1_4_B, GPIO_FN_RX1_D, GPIO_FN_FCLE_B,
+		GPIO_FN_LCD_DATA15_B,
+	GPIO_FN_SSI_WS23, GPIO_FN_VI1_5_B, GPIO_FN_TX1_D, GPIO_FN_HSCK0_C,
+		GPIO_FN_FALE_B, GPIO_FN_LCD_DON_B,
+	GPIO_FN_SSI_SDATA2, GPIO_FN_VI1_6_B, GPIO_FN_HRX0_C, GPIO_FN_FRE_B,
+		GPIO_FN_LCD_CL1_B,
+	GPIO_FN_SSI_SDATA3, GPIO_FN_VI1_7_B, GPIO_FN_HTX0_C, GPIO_FN_FWE_B,
+		GPIO_FN_LCD_CL2_B,
+	GPIO_FN_AUDIO_CLKA_A, GPIO_FN_VI1_CLK_B, GPIO_FN_SCK1_D,
+		GPIO_FN_IECLK_B, GPIO_FN_LCD_FLM_B,
+	GPIO_FN_AUDIO_CLKB_A, GPIO_FN_LCD_CLK_B,
+	GPIO_FN_AUDIO_CLKC, GPIO_FN_SCK1_E, GPIO_FN_HCTS0_C, GPIO_FN_FRB_B,
+		GPIO_FN_LCD_VEPWC_B,
+	GPIO_FN_AUDIO_CLKOUT, GPIO_FN_TX1_E, GPIO_FN_HRTS0_C, GPIO_FN_FSE_B,
+		GPIO_FN_LCD_M_DISP_B,
+	GPIO_FN_CAN_CLK_A, GPIO_FN_RX4_D,
+	GPIO_FN_CAN0_TX_A, GPIO_FN_TX4_D, GPIO_FN_MLB_CLK,
+	GPIO_FN_CAN1_RX_A, GPIO_FN_IRQ1_B,
+	GPIO_FN_CAN0_RX_A, GPIO_FN_IRQ0_B, GPIO_FN_MLB_SIG,
+	GPIO_FN_CAN1_TX_A, GPIO_FN_TX5_C, GPIO_FN_MLB_DAT,
+
+	/* IPSR11 */
+	GPIO_FN_SCL1, GPIO_FN_SCIF_CLK_C,
+	GPIO_FN_SDA1, GPIO_FN_RX1_E,
+	GPIO_FN_SDA0, GPIO_FN_HIFEBL_A,
+	GPIO_FN_SDSELF, GPIO_FN_RTS1_E,
+	GPIO_FN_SCIF_CLK_A, GPIO_FN_HSPI_CLK_A, GPIO_FN_VI0_CLK,
+		GPIO_FN_RMII0_TXD0_A, GPIO_FN_ET0_ERXD4,
+	GPIO_FN_SCK0_A, GPIO_FN_HSPI_CS_A, GPIO_FN_VI0_CLKENB,
+		GPIO_FN_RMII0_TXD1_A, GPIO_FN_ET0_ERXD5,
+	GPIO_FN_RX0_A, GPIO_FN_HSPI_RX_A, GPIO_FN_RMII0_RXD0_A,
+		GPIO_FN_ET0_ERXD6,
+	GPIO_FN_TX0_A, GPIO_FN_HSPI_TX_A,
+	GPIO_FN_PENC1, GPIO_FN_TX3_D, GPIO_FN_CAN1_TX_B, GPIO_FN_TX5_D,
+		GPIO_FN_IETX_B,
+	GPIO_FN_USB_OVC1, GPIO_FN_RX3_D, GPIO_FN_CAN1_RX_B, GPIO_FN_RX5_D,
+		GPIO_FN_IERX_B,
+	GPIO_FN_DREQ0, GPIO_FN_SD1_CLK_A, GPIO_FN_ET0_TX_EN,
+	GPIO_FN_DACK0, GPIO_FN_SD1_DAT3_A, GPIO_FN_ET0_TX_ER,
+	GPIO_FN_DREQ1, GPIO_FN_HSPI_CLK_B, GPIO_FN_RX4_B, GPIO_FN_ET0_PHY_INT_C,
+		GPIO_FN_ET0_TX_CLK_A,
+	GPIO_FN_DACK1, GPIO_FN_HSPI_CS_B, GPIO_FN_TX4_B, GPIO_FN_ET0_RX_CLK_A,
+	GPIO_FN_PRESETOUT, GPIO_FN_ST_CLKOUT,
+
+};
+
+#endif /* __ASM_SH7734_H__ */
diff --git a/arch/sh/include/cpu-sh4a/cpu/dma.h b/arch/sh/include/cpu-sh4a/cpu/dma.h
new file mode 100644
index 0000000..89afb65
--- /dev/null
+++ b/arch/sh/include/cpu-sh4a/cpu/dma.h
@@ -0,0 +1,72 @@
+#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
+#define __ASM_SH_CPU_SH4_DMA_SH7780_H
+
+#include <linux/sh_intc.h>
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7343) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7730)
+#define DMTE0_IRQ	evt2irq(0x800)
+#define DMTE4_IRQ	evt2irq(0xb80)
+#define DMAE0_IRQ	evt2irq(0xbc0)	/* DMA Error IRQ*/
+#define SH_DMAC_BASE0	0xFE008020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+#define DMTE0_IRQ	evt2irq(0x800)
+#define DMTE4_IRQ	evt2irq(0xb80)
+#define DMAE0_IRQ	evt2irq(0xbc0)	/* DMA Error IRQ*/
+#define SH_DMAC_BASE0	0xFE008020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7764)
+#define DMTE0_IRQ	evt2irq(0x640)
+#define DMTE4_IRQ	evt2irq(0x780)
+#define DMAE0_IRQ	evt2irq(0x6c0)
+#define SH_DMAC_BASE0	0xFF608020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+#define DMTE0_IRQ	evt2irq(0x800)	/* DMAC0A*/
+#define DMTE4_IRQ	evt2irq(0xb80)	/* DMAC0B */
+#define DMTE6_IRQ	evt2irq(0x700)
+#define DMTE8_IRQ	evt2irq(0x740)	/* DMAC1A */
+#define DMTE9_IRQ	evt2irq(0x760)
+#define DMTE10_IRQ	evt2irq(0xb00)	/* DMAC1B */
+#define DMTE11_IRQ	evt2irq(0xb20)
+#define DMAE0_IRQ	evt2irq(0xbc0)	/* DMA Error IRQ*/
+#define DMAE1_IRQ	evt2irq(0xb40)	/* DMA Error IRQ*/
+#define SH_DMAC_BASE0	0xFE008020
+#define SH_DMAC_BASE1	0xFDC08020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+#define DMTE0_IRQ	evt2irq(0x800)	/* DMAC0A*/
+#define DMTE4_IRQ	evt2irq(0xb80)	/* DMAC0B */
+#define DMTE6_IRQ	evt2irq(0x700)
+#define DMTE8_IRQ	evt2irq(0x740)	/* DMAC1A */
+#define DMTE9_IRQ	evt2irq(0x760)
+#define DMTE10_IRQ	evt2irq(0xb00)	/* DMAC1B */
+#define DMTE11_IRQ	evt2irq(0xb20)
+#define DMAE0_IRQ	evt2irq(0xbc0)	/* DMA Error IRQ*/
+#define DMAE1_IRQ	evt2irq(0xb40)	/* DMA Error IRQ*/
+#define SH_DMAC_BASE0	0xFE008020
+#define SH_DMAC_BASE1	0xFDC08020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#define DMTE0_IRQ	evt2irq(0x640)
+#define DMTE4_IRQ	evt2irq(0x780)
+#define DMTE6_IRQ	evt2irq(0x7c0)
+#define DMTE8_IRQ	evt2irq(0xd80)
+#define DMTE9_IRQ	evt2irq(0xda0)
+#define DMTE10_IRQ	evt2irq(0xdc0)
+#define DMTE11_IRQ	evt2irq(0xde0)
+#define DMAE0_IRQ	evt2irq(0x6c0)	/* DMA Error IRQ */
+#define SH_DMAC_BASE0	0xFC808020
+#define SH_DMAC_BASE1	0xFC818020
+#else /* SH7785 */
+#define DMTE0_IRQ	evt2irq(0x620)
+#define DMTE4_IRQ	evt2irq(0x6a0)
+#define DMTE6_IRQ	evt2irq(0x880)
+#define DMTE8_IRQ	evt2irq(0x8c0)
+#define DMTE9_IRQ	evt2irq(0x8e0)
+#define DMTE10_IRQ	evt2irq(0x900)
+#define DMTE11_IRQ	evt2irq(0x920)
+#define DMAE0_IRQ	evt2irq(0x6e0)	/* DMA Error IRQ0 */
+#define DMAE1_IRQ	evt2irq(0x940)	/* DMA Error IRQ1 */
+#define SH_DMAC_BASE0	0xFC808020
+#define SH_DMAC_BASE1	0xFCC08020
+#endif
+
+#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
diff --git a/arch/sh/include/cpu-sh5/cpu/dma.h b/arch/sh/include/cpu-sh5/cpu/dma.h
deleted file mode 100644
index 7bf6bb3..0000000
--- a/arch/sh/include/cpu-sh5/cpu/dma.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_SH_CPU_SH5_DMA_H
-#define __ASM_SH_CPU_SH5_DMA_H
-
-/* Nothing yet */
-
-#endif /* __ASM_SH_CPU_SH5_DMA_H */
diff --git a/arch/sh/include/mach-common/mach/hp6xx.h b/arch/sh/include/mach-common/mach/hp6xx.h
index bcc301a..6aaaf85 100644
--- a/arch/sh/include/mach-common/mach/hp6xx.h
+++ b/arch/sh/include/mach-common/mach/hp6xx.h
@@ -9,10 +9,11 @@
  * for more details.
  *
  */
+#include <linux/sh_intc.h>
 
-#define HP680_BTN_IRQ		32	/* IRQ0_IRQ */
-#define HP680_TS_IRQ		35	/* IRQ3_IRQ */
-#define HP680_HD64461_IRQ	36	/* IRQ4_IRQ */
+#define HP680_BTN_IRQ		evt2irq(0x600)	/* IRQ0_IRQ */
+#define HP680_TS_IRQ		evt2irq(0x660)	/* IRQ3_IRQ */
+#define HP680_HD64461_IRQ	evt2irq(0x680)	/* IRQ4_IRQ */
 
 #define DAC_LCD_BRIGHTNESS	0
 #define DAC_SPEAKER_VOLUME	1
diff --git a/arch/sh/include/mach-common/mach/lboxre2.h b/arch/sh/include/mach-common/mach/lboxre2.h
index e6d1605..3a4dcc5 100644
--- a/arch/sh/include/mach-common/mach/lboxre2.h
+++ b/arch/sh/include/mach-common/mach/lboxre2.h
@@ -11,13 +11,14 @@
  * for more details.
  *
  */
+#include <linux/sh_intc.h>
 
-#define IRQ_CF1		9	/* CF1 */
-#define IRQ_CF0		10	/* CF0 */
-#define IRQ_INTD	11	/* INTD */
-#define IRQ_ETH1	12	/* Ether1 */
-#define IRQ_ETH0	13	/* Ether0 */
-#define IRQ_INTA	14	/* INTA */
+#define IRQ_CF1		evt2irq(0x320)	/* CF1 */
+#define IRQ_CF0		evt2irq(0x340)	/* CF0 */
+#define IRQ_INTD	evt2irq(0x360)	/* INTD */
+#define IRQ_ETH1	evt2irq(0x380)	/* Ether1 */
+#define IRQ_ETH0	evt2irq(0x3a0)	/* Ether0 */
+#define IRQ_INTA	evt2irq(0x3c0)	/* INTA */
 
 void init_lboxre2_IRQ(void);
 
diff --git a/arch/sh/include/mach-common/mach/sdk7780.h b/arch/sh/include/mach-common/mach/sdk7780.h
index 697dc86..ce64e02 100644
--- a/arch/sh/include/mach-common/mach/sdk7780.h
+++ b/arch/sh/include/mach-common/mach/sdk7780.h
@@ -11,6 +11,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* Box specific addresses.  */
@@ -67,9 +68,9 @@
 
 #define SDK7780_NR_IRL			15
 /* IDE/ATA interrupt */
-#define IRQ_CFCARD				14
+#define IRQ_CFCARD			evt2irq(0x3c0)
 /* SMC interrupt */
-#define IRQ_ETHERNET			6
+#define IRQ_ETHERNET			evt2irq(0x2c0)
 
 
 /* arch/sh/boards/renesas/sdk7780/irq.c */
diff --git a/arch/sh/include/mach-common/mach/titan.h b/arch/sh/include/mach-common/mach/titan.h
index 4a674d2..fa3cd80 100644
--- a/arch/sh/include/mach-common/mach/titan.h
+++ b/arch/sh/include/mach-common/mach/titan.h
@@ -4,14 +4,16 @@
 #ifndef _ASM_SH_TITAN_H
 #define _ASM_SH_TITAN_H
 
+#include <linux/sh_intc.h>
+
 #define __IO_PREFIX titan
 #include <asm/io_generic.h>
 
 /* IRQ assignments */
-#define TITAN_IRQ_WAN		2	/* eth0 (WAN) */
-#define TITAN_IRQ_LAN		5	/* eth1 (LAN) */
-#define TITAN_IRQ_MPCIA		8	/* mPCI A */
-#define TITAN_IRQ_MPCIB		11	/* mPCI B */
-#define TITAN_IRQ_USB		11	/* USB */
+#define TITAN_IRQ_WAN		evt2irq(0x240)	/* eth0 (WAN) */
+#define TITAN_IRQ_LAN		evt2irq(0x2a0)	/* eth1 (LAN) */
+#define TITAN_IRQ_MPCIA		evt2irq(0x300)	/* mPCI A */
+#define TITAN_IRQ_MPCIB		evt2irq(0x360)	/* mPCI B */
+#define TITAN_IRQ_USB		evt2irq(0x360)	/* USB */
 
 #endif /* __ASM_SH_TITAN_H */
diff --git a/arch/sh/include/mach-dreamcast/mach/dma.h b/arch/sh/include/mach-dreamcast/mach/dma.h
index ddd68e78..1dbfdf7 100644
--- a/arch/sh/include/mach-dreamcast/mach/dma.h
+++ b/arch/sh/include/mach-dreamcast/mach/dma.h
@@ -11,9 +11,7 @@
 #define __ASM_SH_DREAMCAST_DMA_H
 
 /* Number of DMA channels */
-#define ONCHIP_NR_DMA_CHANNELS	4
 #define G2_NR_DMA_CHANNELS	4
-#define PVR2_NR_DMA_CHANNELS	1
 
 /* Channels for cascading */
 #define PVR2_CASCADE_CHAN	2
diff --git a/arch/sh/include/mach-landisk/mach/iodata_landisk.h b/arch/sh/include/mach-landisk/mach/iodata_landisk.h
index f432773..ceeea48 100644
--- a/arch/sh/include/mach-landisk/mach/iodata_landisk.h
+++ b/arch/sh/include/mach-landisk/mach/iodata_landisk.h
@@ -8,6 +8,7 @@
  *
  * IO-DATA LANDISK support
  */
+#include <linux/sh_intc.h>
 
 /* Box specific addresses.  */
 
@@ -25,15 +26,15 @@
 #define PA_PIDE_OFFSET	0x40		/* CF IDE Offset */
 #define PA_SIDE_OFFSET	0x40		/* HDD IDE Offset */
 
-#define IRQ_PCIINTA	5		/* PCI INTA IRQ */
-#define IRQ_PCIINTB	6		/* PCI INTB IRQ */
-#define IRQ_PCIINTC	7		/* PCI INTC IRQ */
-#define IRQ_PCIINTD	8		/* PCI INTD IRQ */
-#define IRQ_ATA		9		/* ATA IRQ */
-#define IRQ_FATA	10		/* FATA IRQ */
-#define IRQ_POWER	11		/* Power Switch IRQ */
-#define IRQ_BUTTON	12		/* USL-5P Button IRQ */
-#define IRQ_FAULT	13		/* USL-5P Fault  IRQ */
+#define IRQ_PCIINTA	evt2irq(0x2a0)	/* PCI INTA IRQ */
+#define IRQ_PCIINTB	evt2irq(0x2c0)	/* PCI INTB IRQ */
+#define IRQ_PCIINTC	evt2irq(0x2e0)	/* PCI INTC IRQ */
+#define IRQ_PCIINTD	evt2irq(0x300)	/* PCI INTD IRQ */
+#define IRQ_ATA		evt2irq(0x320)	/* ATA IRQ */
+#define IRQ_FATA	evt2irq(0x340)	/* FATA IRQ */
+#define IRQ_POWER	evt2irq(0x360)	/* Power Switch IRQ */
+#define IRQ_BUTTON	evt2irq(0x380)	/* USL-5P Button IRQ */
+#define IRQ_FAULT	evt2irq(0x3a0)	/* USL-5P Fault  IRQ */
 
 void init_landisk_IRQ(void);
 
diff --git a/arch/sh/include/mach-se/mach/se.h b/arch/sh/include/mach-se/mach/se.h
index 14be91c..8a6d44b 100644
--- a/arch/sh/include/mach-se/mach/se.h
+++ b/arch/sh/include/mach-se/mach/se.h
@@ -8,6 +8,7 @@
  *
  * Hitachi SolutionEngine support
  */
+#include <linux/sh_intc.h>
 
 /* Box specific addresses.  */
 
@@ -82,16 +83,16 @@
 #define INTC_IPRD       0xa4000018UL
 #define INTC_IPRE       0xa400001aUL
 
-#define IRQ0_IRQ        32
-#define IRQ1_IRQ        33
+#define IRQ0_IRQ        evt2irq(0x600)
+#define IRQ1_IRQ        evt2irq(0x620)
 #endif
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7705)
-#define IRQ_STNIC	12
-#define IRQ_CFCARD	14
+#define IRQ_STNIC	evt2irq(0x380)
+#define IRQ_CFCARD	evt2irq(0x3c0)
 #else
-#define IRQ_STNIC	10
-#define IRQ_CFCARD	7
+#define IRQ_STNIC	evt2irq(0x340)
+#define IRQ_CFCARD	evt2irq(0x2e0)
 #endif
 
 /* SH Ether support (SH7710/SH7712) */
@@ -105,9 +106,9 @@
 # define PHY_ID 0x01
 #endif
 /* Ether IRQ */
-#define SH_ETH0_IRQ	80
-#define SH_ETH1_IRQ	81
-#define SH_TSU_IRQ	82
+#define SH_ETH0_IRQ	evt2irq(0xc00)
+#define SH_ETH1_IRQ	evt2irq(0xc20)
+#define SH_TSU_IRQ	evt2irq(0xc40)
 
 void init_se_IRQ(void);
 
diff --git a/arch/sh/include/mach-se/mach/se7343.h b/arch/sh/include/mach-se/mach/se7343.h
index 8d8170d..50b5d57 100644
--- a/arch/sh/include/mach-se/mach/se7343.h
+++ b/arch/sh/include/mach-se/mach/se7343.h
@@ -8,6 +8,7 @@
  *
  * SH-Mobile SolutionEngine 7343 support
  */
+#include <linux/sh_intc.h>
 
 /* Box specific addresses.  */
 
@@ -118,10 +119,10 @@
 #define FPGA_IN		0xb1400000
 #define FPGA_OUT	0xb1400002
 
-#define IRQ0_IRQ        32
-#define IRQ1_IRQ        33
-#define IRQ4_IRQ        36
-#define IRQ5_IRQ        37
+#define IRQ0_IRQ        evt2irq(0x600)
+#define IRQ1_IRQ        evt2irq(0x620)
+#define IRQ4_IRQ        evt2irq(0x680)
+#define IRQ5_IRQ        evt2irq(0x6a0)
 
 #define SE7343_FPGA_IRQ_MRSHPC0	0
 #define SE7343_FPGA_IRQ_MRSHPC1	1
diff --git a/arch/sh/include/mach-se/mach/se7721.h b/arch/sh/include/mach-se/mach/se7721.h
index b957f60..eabd053 100644
--- a/arch/sh/include/mach-se/mach/se7721.h
+++ b/arch/sh/include/mach-se/mach/se7721.h
@@ -11,6 +11,8 @@
 
 #ifndef __ASM_SH_SE7721_H
 #define __ASM_SH_SE7721_H
+
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* Box specific addresses. */
@@ -49,9 +51,9 @@
 #define MRSHPC_PCIC_INFO	(PA_MRSHPC + 30)
 
 #define PA_LED		0xB6800000	/* 8bit LED */
-#define PA_FPGA		0xB7000000 	/* FPGA base address */
+#define PA_FPGA		0xB7000000	/* FPGA base address */
 
-#define MRSHPC_IRQ0	10
+#define MRSHPC_IRQ0	evt2irq(0x340)
 
 #define FPGA_ILSR1	(PA_FPGA + 0x02)
 #define FPGA_ILSR2	(PA_FPGA + 0x03)
diff --git a/arch/sh/include/mach-se/mach/se7722.h b/arch/sh/include/mach-se/mach/se7722.h
index 16505bf..201081e 100644
--- a/arch/sh/include/mach-se/mach/se7722.h
+++ b/arch/sh/include/mach-se/mach/se7722.h
@@ -13,6 +13,7 @@
  * for more details.
  *
  */
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* Box specific addresses.  */
@@ -31,7 +32,7 @@
 
 #define PA_PERIPHERAL	0xB0000000
 
-#define PA_PCIC         PA_PERIPHERAL   		/* MR-SHPC-01 PCMCIA */
+#define PA_PCIC         PA_PERIPHERAL		/* MR-SHPC-01 PCMCIA */
 #define PA_MRSHPC       (PA_PERIPHERAL + 0x003fffe0)    /* MR-SHPC-01 PCMCIA controller */
 #define PA_MRSHPC_MW1   (PA_PERIPHERAL + 0x00400000)    /* MR-SHPC-01 memory window base */
 #define PA_MRSHPC_MW2   (PA_PERIPHERAL + 0x00500000)    /* MR-SHPC-01 attribute window base */
@@ -51,7 +52,7 @@
 #define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
 
 #define PA_LED		(PA_PERIPHERAL + 0x00800000)	/* 8bit LED */
-#define PA_FPGA		(PA_PERIPHERAL + 0x01800000) 	/* FPGA base address */
+#define PA_FPGA		(PA_PERIPHERAL + 0x01800000)	/* FPGA base address */
 
 #define PA_LAN		(PA_AREA6_IO + 0)		/* SMC LAN91C111 */
 /* GPIO */
@@ -77,8 +78,8 @@
 #define PORT_HIZCRC     0xA405015CUL
 
 /* IRQ */
-#define IRQ0_IRQ        32
-#define IRQ1_IRQ        33
+#define IRQ0_IRQ        evt2irq(0x600)
+#define IRQ1_IRQ        evt2irq(0x620)
 
 #define IRQ01_MODE      0xb1800000
 #define IRQ01_STS       0xb1800004
diff --git a/arch/sh/include/mach-se/mach/se7724.h b/arch/sh/include/mach-se/mach/se7724.h
index 29514a3..be842dd 100644
--- a/arch/sh/include/mach-se/mach/se7724.h
+++ b/arch/sh/include/mach-se/mach/se7724.h
@@ -18,6 +18,7 @@
  * for more details.
  *
  */
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* SH Eth */
@@ -35,9 +36,9 @@
 #define IRQ2_MR		(0xba200028)
 
 /* IRQ */
-#define IRQ0_IRQ        32
-#define IRQ1_IRQ        33
-#define IRQ2_IRQ        34
+#define IRQ0_IRQ        evt2irq(0x600)
+#define IRQ1_IRQ        evt2irq(0x620)
+#define IRQ2_IRQ        evt2irq(0x640)
 
 /* Bits in IRQ012 registers */
 #define SE7724_FPGA_IRQ_BASE	220
diff --git a/arch/sh/include/mach-se/mach/se7751.h b/arch/sh/include/mach-se/mach/se7751.h
index b36792a..2718717 100644
--- a/arch/sh/include/mach-se/mach/se7751.h
+++ b/arch/sh/include/mach-se/mach/se7751.h
@@ -11,6 +11,7 @@
  * Modified for 7751 Solution Engine by
  * Ian da Silva and Jeremy Siegel, 2001.
  */
+#include <linux/sh_intc.h>
 
 /* Box specific addresses.  */
 
@@ -63,7 +64,7 @@
 #define BCR_ILCRF	(PA_BCR + 10)
 #define BCR_ILCRG	(PA_BCR + 12)
 
-#define IRQ_79C973	13
+#define IRQ_79C973	evt2irq(0x3a0)
 
 void init_7751se_IRQ(void);
 
diff --git a/arch/sh/include/mach-se/mach/se7780.h b/arch/sh/include/mach-se/mach/se7780.h
index 40e9b41..bde357c 100644
--- a/arch/sh/include/mach-se/mach/se7780.h
+++ b/arch/sh/include/mach-se/mach/se7780.h
@@ -12,6 +12,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* Box specific addresses.  */
@@ -80,13 +81,13 @@
 #define IRQPOS_PCCPW            (0 * 4)
 
 /* IDE interrupt */
-#define IRQ_IDE0                67 /* iVDR */
+#define IRQ_IDE0                evt2irq(0xa60) /* iVDR */
 
 /* SMC interrupt */
-#define SMC_IRQ                 8
+#define SMC_IRQ                 evt2irq(0x300)
 
 /* SM501 interrupt */
-#define SM501_IRQ               0
+#define SM501_IRQ               evt2irq(0x200)
 
 /* interrupt pin */
 #define IRQPIN_EXTINT1          0 /* IRQ0 pin */
diff --git a/arch/sh/kernel/cpu/proc.c b/arch/sh/kernel/cpu/proc.c
index f47be87..9e6624c 100644
--- a/arch/sh/kernel/cpu/proc.c
+++ b/arch/sh/kernel/cpu/proc.c
@@ -7,6 +7,7 @@
 static const char *cpu_name[] = {
 	[CPU_SH7201]	= "SH7201",
 	[CPU_SH7203]	= "SH7203",	[CPU_SH7263]	= "SH7263",
+	[CPU_SH7264]	= "SH7264",	[CPU_SH7269]	= "SH7269",
 	[CPU_SH7206]	= "SH7206",	[CPU_SH7619]	= "SH7619",
 	[CPU_SH7705]	= "SH7705",	[CPU_SH7706]	= "SH7706",
 	[CPU_SH7707]	= "SH7707",	[CPU_SH7708]	= "SH7708",
@@ -25,7 +26,8 @@
 	[CPU_SH5_101]	= "SH5-101",	[CPU_SH5_103]	= "SH5-103",
 	[CPU_MXG]	= "MX-G",	[CPU_SH7723]	= "SH7723",
 	[CPU_SH7366]	= "SH7366",	[CPU_SH7724]	= "SH7724",
-	[CPU_SH7372]	= "SH7372",	[CPU_SH_NONE]	= "Unknown"
+	[CPU_SH7372]	= "SH7372",	[CPU_SH7734]	= "SH7734",
+	[CPU_SH_NONE]	= "Unknown"
 };
 
 const char *get_cpu_subtype(struct sh_cpuinfo *c)
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index 0f8befc..e0b740c 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -65,7 +65,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 88, 88, 88, 88 },
+	.irqs		= SCIx_IRQ_MUXED(88),
 };
 
 static struct platform_device scif0_device = {
@@ -82,7 +82,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 92, 92, 92, 92 },
+	.irqs		= SCIx_IRQ_MUXED(92),
 };
 
 static struct platform_device scif1_device = {
@@ -99,7 +99,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 96, 96, 96, 96 },
+	.irqs		= SCIx_IRQ_MUXED(96),
 };
 
 static struct platform_device scif2_device = {
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
index 45f85c7..7fdc102 100644
--- a/arch/sh/kernel/cpu/sh2a/Makefile
+++ b/arch/sh/kernel/cpu/sh2a/Makefile
@@ -11,10 +11,14 @@
 obj-$(CONFIG_CPU_SUBTYPE_SH7201)	+= setup-sh7201.o clock-sh7201.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7203)	+= setup-sh7203.o clock-sh7203.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7263)	+= setup-sh7203.o clock-sh7203.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7264)	+= setup-sh7264.o clock-sh7264.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7206)	+= setup-sh7206.o clock-sh7206.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7269)	+= setup-sh7269.o clock-sh7269.o
 obj-$(CONFIG_CPU_SUBTYPE_MXG)		+= setup-mxg.o clock-sh7206.o
 
 # Pinmux setup
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7203)	:= pinmux-sh7203.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7264)	:= pinmux-sh7264.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7269)	:= pinmux-sh7269.o
 
 obj-$(CONFIG_GENERIC_GPIO)	+= $(pinmux-y)
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7264.c b/arch/sh/kernel/cpu/sh2a/clock-sh7264.c
new file mode 100644
index 0000000..fdf585c
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7264.c
@@ -0,0 +1,153 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/clock-sh7264.c
+ *
+ * SH7264 clock framework support
+ *
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <asm/clock.h>
+
+/* SH7264 registers */
+#define FRQCR		0xfffe0010
+#define STBCR3		0xfffe0408
+#define STBCR4		0xfffe040c
+#define STBCR5		0xfffe0410
+#define STBCR6		0xfffe0414
+#define STBCR7		0xfffe0418
+#define STBCR8		0xfffe041c
+
+static const unsigned int pll1rate[] = {8, 12};
+
+static unsigned int pll1_div;
+
+/* Fixed 32 KHz root clock for RTC */
+static struct clk r_clk = {
+	.rate           = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+	.rate		= 18000000,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+	unsigned long rate = clk->parent->rate / pll1_div;
+	return rate * pll1rate[(__raw_readw(FRQCR) >> 8) & 1];
+}
+
+static struct sh_clk_ops pll_clk_ops = {
+	.recalc		= pll_recalc,
+};
+
+static struct clk pll_clk = {
+	.ops		= &pll_clk_ops,
+	.parent		= &extal_clk,
+	.flags		= CLK_ENABLE_ON_INIT,
+};
+
+struct clk *main_clks[] = {
+	&r_clk,
+	&extal_clk,
+	&pll_clk,
+};
+
+static int div2[] = { 1, 2, 3, 4, 6, 8, 12 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+	.divisors = div2,
+	.nr_divisors = ARRAY_SIZE(div2),
+};
+
+static struct clk_div4_table div4_table = {
+	.div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_I, DIV4_P,
+       DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+  SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
+
+/* The mask field specifies the div2 entries that are valid */
+struct clk div4_clks[DIV4_NR] = {
+	[DIV4_I] = DIV4(FRQCR, 4, 0x7,  CLK_ENABLE_REG_16BIT
+					| CLK_ENABLE_ON_INIT),
+	[DIV4_P] = DIV4(FRQCR, 0, 0x78, CLK_ENABLE_REG_16BIT),
+};
+
+enum {	MSTP77, MSTP74, MSTP72,
+	MSTP60,
+	MSTP35, MSTP34, MSTP33, MSTP32, MSTP30,
+	MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+	[MSTP77] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 7, 0), /* SCIF */
+	[MSTP74] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 4, 0), /* VDC */
+	[MSTP72] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 2, 0), /* CMT */
+	[MSTP60] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR6, 0, 0), /* USB */
+	[MSTP35] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 6, 0), /* MTU2 */
+	[MSTP34] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 4, 0), /* SDHI0 */
+	[MSTP33] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 3, 0), /* SDHI1 */
+	[MSTP32] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 2, 0), /* ADC */
+	[MSTP30] = SH_CLK_MSTP8(&r_clk, STBCR3, 0, 0),	/* RTC */
+};
+
+static struct clk_lookup lookups[] = {
+	/* main clocks */
+	CLKDEV_CON_ID("rclk", &r_clk),
+	CLKDEV_CON_ID("extal", &extal_clk),
+	CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+	/* DIV4 clocks */
+	CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+	CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+
+	/* MSTP clocks */
+	CLKDEV_CON_ID("sci_ick", &mstp_clks[MSTP77]),
+	CLKDEV_CON_ID("vdc3", &mstp_clks[MSTP74]),
+	CLKDEV_CON_ID("cmt_fck", &mstp_clks[MSTP72]),
+	CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
+	CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP35]),
+	CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP34]),
+	CLKDEV_CON_ID("sdhi1", &mstp_clks[MSTP33]),
+	CLKDEV_CON_ID("adc0", &mstp_clks[MSTP32]),
+	CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP30]),
+};
+
+int __init arch_clk_init(void)
+{
+	int k, ret = 0;
+
+	if (test_mode_pin(MODE_PIN0)) {
+		if (test_mode_pin(MODE_PIN1))
+			pll1_div = 3;
+		else
+			pll1_div = 4;
+	} else
+		pll1_div = 1;
+
+	for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+		ret = clk_register(main_clks[k]);
+
+	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+	if (!ret)
+		ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+	if (!ret)
+		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
+
+	return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7269.c b/arch/sh/kernel/cpu/sh2a/clock-sh7269.c
new file mode 100644
index 0000000..6b78762
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7269.c
@@ -0,0 +1,184 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/clock-sh7269.c
+ *
+ * SH7269 clock framework support
+ *
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <asm/clock.h>
+
+/* SH7269 registers */
+#define FRQCR		0xfffe0010
+#define STBCR3 		0xfffe0408
+#define STBCR4 		0xfffe040c
+#define STBCR5 		0xfffe0410
+#define STBCR6 		0xfffe0414
+#define STBCR7 		0xfffe0418
+
+#define PLL_RATE 20
+
+/* Fixed 32 KHz root clock for RTC */
+static struct clk r_clk = {
+	.rate           = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+	.rate		= 13340000,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+	return clk->parent->rate * PLL_RATE;
+}
+
+static struct sh_clk_ops pll_clk_ops = {
+	.recalc		= pll_recalc,
+};
+
+static struct clk pll_clk = {
+	.ops		= &pll_clk_ops,
+	.parent		= &extal_clk,
+	.flags		= CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long peripheral0_recalc(struct clk *clk)
+{
+	return clk->parent->rate / 8;
+}
+
+static struct sh_clk_ops peripheral0_clk_ops = {
+	.recalc		= peripheral0_recalc,
+};
+
+static struct clk peripheral0_clk = {
+	.ops		= &peripheral0_clk_ops,
+	.parent		= &pll_clk,
+	.flags		= CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long peripheral1_recalc(struct clk *clk)
+{
+	return clk->parent->rate / 4;
+}
+
+static struct sh_clk_ops peripheral1_clk_ops = {
+	.recalc		= peripheral1_recalc,
+};
+
+static struct clk peripheral1_clk = {
+	.ops		= &peripheral1_clk_ops,
+	.parent		= &pll_clk,
+	.flags		= CLK_ENABLE_ON_INIT,
+};
+
+struct clk *main_clks[] = {
+	&r_clk,
+	&extal_clk,
+	&pll_clk,
+	&peripheral0_clk,
+	&peripheral1_clk,
+};
+
+static int div2[] = { 1, 2, 0, 4 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+	.divisors = div2,
+	.nr_divisors = ARRAY_SIZE(div2),
+};
+
+static struct clk_div4_table div4_table = {
+	.div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_I, DIV4_B,
+       DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+  SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
+
+/* The mask field specifies the div2 entries that are valid */
+struct clk div4_clks[DIV4_NR] = {
+	[DIV4_I]  = DIV4(FRQCR, 8, 0xB, CLK_ENABLE_REG_16BIT
+					| CLK_ENABLE_ON_INIT),
+	[DIV4_B]  = DIV4(FRQCR, 4, 0xA, CLK_ENABLE_REG_16BIT
+					| CLK_ENABLE_ON_INIT),
+};
+
+enum { MSTP72,
+	MSTP60,
+	MSTP47, MSTP46, MSTP45, MSTP44, MSTP43, MSTP42, MSTP41, MSTP40,
+	MSTP35, MSTP32, MSTP30,
+	MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+	[MSTP72] = SH_CLK_MSTP8(&peripheral0_clk, STBCR7, 2, 0), /* CMT */
+	[MSTP60] = SH_CLK_MSTP8(&peripheral1_clk, STBCR6, 0, 0), /* USB */
+	[MSTP47] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 7, 0), /* SCIF0 */
+	[MSTP46] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 6, 0), /* SCIF1 */
+	[MSTP45] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 5, 0), /* SCIF2 */
+	[MSTP44] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 4, 0), /* SCIF3 */
+	[MSTP43] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 3, 0), /* SCIF4 */
+	[MSTP42] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 2, 0), /* SCIF5 */
+	[MSTP41] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 1, 0), /* SCIF6 */
+	[MSTP40] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 0, 0), /* SCIF7 */
+	[MSTP35] = SH_CLK_MSTP8(&peripheral0_clk, STBCR3, 5, 0), /* MTU2 */
+	[MSTP32] = SH_CLK_MSTP8(&peripheral1_clk, STBCR3, 2, 0), /* ADC */
+	[MSTP30] = SH_CLK_MSTP8(&r_clk, STBCR3, 0, 0), /* RTC */
+};
+
+static struct clk_lookup lookups[] = {
+	/* main clocks */
+	CLKDEV_CON_ID("rclk", &r_clk),
+	CLKDEV_CON_ID("extal", &extal_clk),
+	CLKDEV_CON_ID("pll_clk", &pll_clk),
+	CLKDEV_CON_ID("peripheral_clk", &peripheral1_clk),
+
+	/* DIV4 clocks */
+	CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+	CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+
+	/* MSTP clocks */
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP47]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP46]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP45]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP44]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP43]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP42]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.6", &mstp_clks[MSTP41]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.7", &mstp_clks[MSTP40]),
+	CLKDEV_CON_ID("cmt_fck", &mstp_clks[MSTP72]),
+	CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
+	CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP35]),
+	CLKDEV_CON_ID("adc0", &mstp_clks[MSTP32]),
+	CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP30]),
+};
+
+int __init arch_clk_init(void)
+{
+	int k, ret = 0;
+
+	for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+		ret = clk_register(main_clks[k]);
+
+	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+	if (!ret)
+		ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+	if (!ret)
+		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
+
+	return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c b/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c
new file mode 100644
index 0000000..b055b55
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c
@@ -0,0 +1,2136 @@
+/*
+ * SH7264 Pinmux
+ *
+ *  Copyright (C) 2012  Renesas Electronics Europe Ltd
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7264.h>
+
+enum {
+	PINMUX_RESERVED = 0,
+
+	PINMUX_DATA_BEGIN,
+	/* Port A */
+	PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+	/* Port B */
+	PB22_DATA, PB21_DATA, PB20_DATA,
+	PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
+	PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+	PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+	PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+	PB3_DATA, PB2_DATA, PB1_DATA,
+	/* Port C */
+	PC10_DATA, PC9_DATA, PC8_DATA,
+	PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+	PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+	/* Port D */
+	PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+	PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+	PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+	PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+	/* Port E */
+	PE5_DATA, PE4_DATA,
+	PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+	/* Port F */
+	PF12_DATA,
+	PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+	PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+	PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+	/* Port G */
+	PG24_DATA,
+	PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+	PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
+	PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+	PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+	PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+	PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+	/* Port H */
+	/* NOTE - Port H does not have a Data Register, but PH Data is
+	   connected to PH Port Register */
+	PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+	PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+	/* Port I - not on device */
+	/* Port J */
+	PJ12_DATA,
+	PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+	PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+	PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
+	/* Port K */
+	PK12_DATA,
+	PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
+	PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+	PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA,
+	PINMUX_DATA_END,
+
+	PINMUX_INPUT_BEGIN,
+	FORCE_IN,
+	/* Port A */
+	PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+	/* Port B */
+	PB22_IN, PB21_IN, PB20_IN,
+	PB19_IN, PB18_IN, PB17_IN, PB16_IN,
+	PB15_IN, PB14_IN, PB13_IN, PB12_IN,
+	PB11_IN, PB10_IN, PB9_IN, PB8_IN,
+	PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+	PB3_IN, PB2_IN, PB1_IN,
+	/* Port C */
+	PC10_IN, PC9_IN, PC8_IN,
+	PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+	PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+	/* Port D */
+	PD15_IN, PD14_IN, PD13_IN, PD12_IN,
+	PD11_IN, PD10_IN, PD9_IN, PD8_IN,
+	PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+	PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+	/* Port E */
+	PE5_IN, PE4_IN,
+	PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+	/* Port F */
+	PF12_IN,
+	PF11_IN, PF10_IN, PF9_IN, PF8_IN,
+	PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+	PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+	/* Port G */
+	PG24_IN,
+	PG23_IN, PG22_IN, PG21_IN, PG20_IN,
+	PG19_IN, PG18_IN, PG17_IN, PG16_IN,
+	PG15_IN, PG14_IN, PG13_IN, PG12_IN,
+	PG11_IN, PG10_IN, PG9_IN, PG8_IN,
+	PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+	PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+	/* Port H - Port H does not have a Data Register */
+	/* Port I - not on device */
+	/* Port J */
+	PJ12_IN,
+	PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
+	PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+	PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
+	/* Port K */
+	PK12_IN,
+	PK11_IN, PK10_IN, PK9_IN, PK8_IN,
+	PK7_IN, PK6_IN, PK5_IN, PK4_IN,
+	PK3_IN, PK2_IN, PK1_IN, PK0_IN,
+	PINMUX_INPUT_END,
+
+	PINMUX_OUTPUT_BEGIN,
+	FORCE_OUT,
+	/* Port A */
+	PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+	/* Port B */
+	PB22_OUT, PB21_OUT, PB20_OUT,
+	PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
+	PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
+	PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
+	PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+	PB3_OUT, PB2_OUT, PB1_OUT,
+	/* Port C */
+	PC10_OUT, PC9_OUT, PC8_OUT,
+	PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+	PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+	/* Port D */
+	PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
+	PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
+	PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+	PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+	/* Port E */
+	PE5_OUT, PE4_OUT,
+	PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+	/* Port F */
+	PF12_OUT,
+	PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
+	PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+	PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+	/* Port G */
+	PG24_OUT,
+	PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
+	PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
+	PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
+	PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
+	PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+	PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+	/* Port H - Port H does not have a Data Register */
+	/* Port I - not on device */
+	/* Port J */
+	PJ12_OUT,
+	PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
+	PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+	PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
+	/* Port K */
+	PK12_OUT,
+	PK11_OUT, PK10_OUT, PK9_OUT, PK8_OUT,
+	PK7_OUT, PK6_OUT, PK5_OUT, PK4_OUT,
+	PK3_OUT, PK2_OUT, PK1_OUT, PK0_OUT,
+	PINMUX_OUTPUT_END,
+
+	PINMUX_FUNCTION_BEGIN,
+	/* Port A */
+	PA3_IOR_IN, PA3_IOR_OUT,
+	PA2_IOR_IN, PA2_IOR_OUT,
+	PA1_IOR_IN, PA1_IOR_OUT,
+	PA0_IOR_IN, PA0_IOR_OUT,
+
+	/* Port B */
+	PB11_IOR_IN, PB11_IOR_OUT,
+	PB10_IOR_IN, PB10_IOR_OUT,
+	PB9_IOR_IN, PB9_IOR_OUT,
+	PB8_IOR_IN, PB8_IOR_OUT,
+
+	PB22MD_00, PB22MD_01, PB22MD_10,
+	PB21MD_0, PB21MD_1,
+	PB20MD_0, PB20MD_1,
+	PB19MD_00, PB19MD_01, PB19MD_10, PB19MD_11,
+	PB18MD_00, PB18MD_01, PB18MD_10, PB18MD_11,
+	PB17MD_00, PB17MD_01, PB17MD_10, PB17MD_11,
+	PB16MD_00, PB16MD_01, PB16MD_10, PB16MD_11,
+	PB15MD_00, PB15MD_01, PB15MD_10, PB15MD_11,
+	PB14MD_00, PB14MD_01, PB14MD_10, PB14MD_11,
+	PB13MD_00, PB13MD_01, PB13MD_10, PB13MD_11,
+	PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+	PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
+	PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
+	PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
+	PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
+	PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+	PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+	PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+	PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+	PB3MD_0, PB3MD_1,
+	PB2MD_0, PB2MD_1,
+	PB1MD_0, PB1MD_1,
+
+	/* Port C */
+	PC14_IOR_IN, PC14_IOR_OUT,
+	PC13_IOR_IN, PC13_IOR_OUT,
+	PC12_IOR_IN, PC12_IOR_OUT,
+	PC11_IOR_IN, PC11_IOR_OUT,
+	PC10_IOR_IN, PC10_IOR_OUT,
+	PC9_IOR_IN, PC9_IOR_OUT,
+	PC8_IOR_IN, PC8_IOR_OUT,
+	PC7_IOR_IN, PC7_IOR_OUT,
+	PC6_IOR_IN, PC6_IOR_OUT,
+	PC5_IOR_IN, PC5_IOR_OUT,
+	PC4_IOR_IN, PC4_IOR_OUT,
+	PC3_IOR_IN, PC3_IOR_OUT,
+	PC2_IOR_IN, PC2_IOR_OUT,
+	PC1_IOR_IN, PC1_IOR_OUT,
+	PC0_IOR_IN, PC0_IOR_OUT,
+
+	PC10MD_0, PC10MD_1,
+	PC9MD_0, PC9MD_1,
+	PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11,
+	PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11,
+	PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11,
+	PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11,
+	PC4MD_0, PC4MD_1,
+	PC3MD_0, PC3MD_1,
+	PC2MD_0, PC2MD_1,
+	PC1MD_0, PC1MD_1,
+	PC0MD_0, PC0MD_1,
+
+	/* Port D */
+	PD15_IOR_IN, PD15_IOR_OUT,
+	PD14_IOR_IN, PD14_IOR_OUT,
+	PD13_IOR_IN, PD13_IOR_OUT,
+	PD12_IOR_IN, PD12_IOR_OUT,
+	PD11_IOR_IN, PD11_IOR_OUT,
+	PD10_IOR_IN, PD10_IOR_OUT,
+	PD9_IOR_IN, PD9_IOR_OUT,
+	PD8_IOR_IN, PD8_IOR_OUT,
+	PD7_IOR_IN, PD7_IOR_OUT,
+	PD6_IOR_IN, PD6_IOR_OUT,
+	PD5_IOR_IN, PD5_IOR_OUT,
+	PD4_IOR_IN, PD4_IOR_OUT,
+	PD3_IOR_IN, PD3_IOR_OUT,
+	PD2_IOR_IN, PD2_IOR_OUT,
+	PD1_IOR_IN, PD1_IOR_OUT,
+	PD0_IOR_IN, PD0_IOR_OUT,
+
+	PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
+	PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
+	PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
+	PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
+	PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
+	PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
+	PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
+	PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
+	PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
+	PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
+	PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
+	PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
+	PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
+	PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
+	PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
+	PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
+
+	/* Port E */
+	PE5_IOR_IN, PE5_IOR_OUT,
+	PE4_IOR_IN, PE4_IOR_OUT,
+	PE3_IOR_IN, PE3_IOR_OUT,
+	PE2_IOR_IN, PE2_IOR_OUT,
+	PE1_IOR_IN, PE1_IOR_OUT,
+	PE0_IOR_IN, PE0_IOR_OUT,
+
+	PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
+	PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
+	PE3MD_00, PE3MD_01, PE3MD_10, PE3MD_11,
+	PE2MD_00, PE2MD_01, PE2MD_10, PE2MD_11,
+	PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+	PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+	PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
+
+	/* Port F */
+	PF12_IOR_IN, PF12_IOR_OUT,
+	PF11_IOR_IN, PF11_IOR_OUT,
+	PF10_IOR_IN, PF10_IOR_OUT,
+	PF9_IOR_IN, PF9_IOR_OUT,
+	PF8_IOR_IN, PF8_IOR_OUT,
+	PF7_IOR_IN, PF7_IOR_OUT,
+	PF6_IOR_IN, PF6_IOR_OUT,
+	PF5_IOR_IN, PF5_IOR_OUT,
+	PF4_IOR_IN, PF4_IOR_OUT,
+	PF3_IOR_IN, PF3_IOR_OUT,
+	PF2_IOR_IN, PF2_IOR_OUT,
+	PF1_IOR_IN, PF1_IOR_OUT,
+	PF0_IOR_IN, PF0_IOR_OUT,
+
+	PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+	PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+	PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+	PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+	PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+	PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+	PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+	PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+	PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11,
+	PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+	PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+	PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+	PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+	PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+	PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+	PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+	PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+	PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+	PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+	PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+	PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+	PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+	PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+	PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+	PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+
+	/* Port G */
+	PG24_IOR_IN, PG24_IOR_OUT,
+	PG23_IOR_IN, PG23_IOR_OUT,
+	PG22_IOR_IN, PG22_IOR_OUT,
+	PG21_IOR_IN, PG21_IOR_OUT,
+	PG20_IOR_IN, PG20_IOR_OUT,
+	PG19_IOR_IN, PG19_IOR_OUT,
+	PG18_IOR_IN, PG18_IOR_OUT,
+	PG17_IOR_IN, PG17_IOR_OUT,
+	PG16_IOR_IN, PG16_IOR_OUT,
+	PG15_IOR_IN, PG15_IOR_OUT,
+	PG14_IOR_IN, PG14_IOR_OUT,
+	PG13_IOR_IN, PG13_IOR_OUT,
+	PG12_IOR_IN, PG12_IOR_OUT,
+	PG11_IOR_IN, PG11_IOR_OUT,
+	PG10_IOR_IN, PG10_IOR_OUT,
+	PG9_IOR_IN, PG9_IOR_OUT,
+	PG8_IOR_IN, PG8_IOR_OUT,
+	PG7_IOR_IN, PG7_IOR_OUT,
+	PG6_IOR_IN, PG6_IOR_OUT,
+	PG5_IOR_IN, PG5_IOR_OUT,
+	PG4_IOR_IN, PG4_IOR_OUT,
+	PG3_IOR_IN, PG3_IOR_OUT,
+	PG2_IOR_IN, PG2_IOR_OUT,
+	PG1_IOR_IN, PG1_IOR_OUT,
+	PG0_IOR_IN, PG0_IOR_OUT,
+
+	PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
+	PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11,
+	PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11,
+	PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11,
+	PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+	PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+	PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+	PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+	PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+	PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+	PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
+	PG17MD_100, PG17MD_101, PG17MD_110, PG17MD_111,
+	PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
+	PG16MD_100, PG16MD_101, PG16MD_110, PG16MD_111,
+	PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
+	PG15MD_100, PG15MD_101, PG15MD_110, PG15MD_111,
+	PG14MD_000, PG14MD_001, PG14MD_010, PG14MD_011,
+	PG14MD_100, PG14MD_101, PG14MD_110, PG14MD_111,
+	PG13MD_000, PG13MD_001, PG13MD_010, PG13MD_011,
+	PG13MD_100, PG13MD_101, PG13MD_110, PG13MD_111,
+	PG12MD_000, PG12MD_001, PG12MD_010, PG12MD_011,
+	PG12MD_100, PG12MD_101, PG12MD_110, PG12MD_111,
+	PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+	PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+	PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+	PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+	PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+	PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+	PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+	PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+	PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11,
+	PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11,
+	PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11,
+	PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11,
+	PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11,
+	PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11,
+	PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11,
+	PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+	PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+
+	/* Port H */
+	PH7MD_0, PH7MD_1,
+	PH6MD_0, PH6MD_1,
+	PH5MD_0, PH5MD_1,
+	PH4MD_0, PH4MD_1,
+	PH3MD_0, PH3MD_1,
+	PH2MD_0, PH2MD_1,
+	PH1MD_0, PH1MD_1,
+	PH0MD_0, PH0MD_1,
+
+	/* Port I - not on device */
+
+	/* Port J */
+	PJ11_IOR_IN, PJ11_IOR_OUT,
+	PJ10_IOR_IN, PJ10_IOR_OUT,
+	PJ9_IOR_IN, PJ9_IOR_OUT,
+	PJ8_IOR_IN, PJ8_IOR_OUT,
+	PJ7_IOR_IN, PJ7_IOR_OUT,
+	PJ6_IOR_IN, PJ6_IOR_OUT,
+	PJ5_IOR_IN, PJ5_IOR_OUT,
+	PJ4_IOR_IN, PJ4_IOR_OUT,
+	PJ3_IOR_IN, PJ3_IOR_OUT,
+	PJ2_IOR_IN, PJ2_IOR_OUT,
+	PJ1_IOR_IN, PJ1_IOR_OUT,
+	PJ0_IOR_IN, PJ0_IOR_OUT,
+
+	PJ11MD_00, PJ11MD_01, PJ11MD_10, PJ11MD_11,
+	PJ10MD_00, PJ10MD_01, PJ10MD_10, PJ10MD_11,
+	PJ9MD_00, PJ9MD_01, PJ9MD_10, PJ9MD_11,
+	PJ8MD_00, PJ8MD_01, PJ8MD_10, PJ8MD_11,
+	PJ7MD_00, PJ7MD_01, PJ7MD_10, PJ7MD_11,
+	PJ6MD_00, PJ6MD_01, PJ6MD_10, PJ6MD_11,
+	PJ5MD_00, PJ5MD_01, PJ5MD_10, PJ5MD_11,
+	PJ4MD_00, PJ4MD_01, PJ4MD_10, PJ4MD_11,
+	PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11,
+	PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+	PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+	PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+	PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+	PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+	PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+
+	/* Port K */
+	PK11_IOR_IN, PK11_IOR_OUT,
+	PK10_IOR_IN, PK10_IOR_OUT,
+	PK9_IOR_IN, PK9_IOR_OUT,
+	PK8_IOR_IN, PK8_IOR_OUT,
+	PK7_IOR_IN, PK7_IOR_OUT,
+	PK6_IOR_IN, PK6_IOR_OUT,
+	PK5_IOR_IN, PK5_IOR_OUT,
+	PK4_IOR_IN, PK4_IOR_OUT,
+	PK3_IOR_IN, PK3_IOR_OUT,
+	PK2_IOR_IN, PK2_IOR_OUT,
+	PK1_IOR_IN, PK1_IOR_OUT,
+	PK0_IOR_IN, PK0_IOR_OUT,
+
+	PK11MD_00, PK11MD_01, PK11MD_10, PK11MD_11,
+	PK10MD_00, PK10MD_01, PK10MD_10, PK10MD_11,
+	PK9MD_00, PK9MD_01, PK9MD_10, PK9MD_11,
+	PK8MD_00, PK8MD_01, PK8MD_10, PK8MD_11,
+	PK7MD_00, PK7MD_01, PK7MD_10, PK7MD_11,
+	PK6MD_00, PK6MD_01, PK6MD_10, PK6MD_11,
+	PK5MD_00, PK5MD_01, PK5MD_10, PK5MD_11,
+	PK4MD_00, PK4MD_01, PK4MD_10, PK4MD_11,
+	PK3MD_00, PK3MD_01, PK3MD_10, PK3MD_11,
+	PK2MD_00, PK2MD_01, PK2MD_10, PK2MD_11,
+	PK1MD_00, PK1MD_01, PK1MD_10, PK1MD_11,
+	PK0MD_00, PK0MD_01, PK0MD_10, PK0MD_11,
+	PINMUX_FUNCTION_END,
+
+	PINMUX_MARK_BEGIN,
+	/* Port A */
+
+	/* Port B */
+
+	/* Port C */
+
+	/* Port D */
+
+	/* Port E */
+
+	/* Port F */
+
+	/* Port G */
+
+	/* Port H */
+	PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
+	PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
+
+	/* Port I - not on device */
+
+	/* Port J */
+
+	/* Port K */
+
+	IRQ7_PC_MARK, IRQ6_PC_MARK, IRQ5_PC_MARK, IRQ4_PC_MARK,
+	IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
+	IRQ3_PE_MARK, IRQ2_PE_MARK, IRQ1_PE_MARK, IRQ0_PE_MARK,
+
+	PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
+	PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
+
+	SD_CD_MARK, SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
+	SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK,
+	CRX0_MARK, CRX1_MARK,
+	CTX0_MARK, CTX1_MARK,
+
+	PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
+	PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
+	PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
+	PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
+	IERXD_MARK, IETXD_MARK,
+	CRX0CRX1_MARK,
+	WDTOVF_MARK,
+
+	CRX0X1_MARK,
+
+	/* DMAC */
+	TEND0_MARK, DACK0_MARK, DREQ0_MARK,
+	TEND1_MARK, DACK1_MARK, DREQ1_MARK,
+
+	/* ADC */
+	ADTRG_MARK,
+
+	/* BSC */
+	A25_MARK, A24_MARK,
+	A23_MARK, A22_MARK, A21_MARK, A20_MARK,
+	A19_MARK, A18_MARK, A17_MARK, A16_MARK,
+	A15_MARK, A14_MARK, A13_MARK, A12_MARK,
+	A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+	A7_MARK, A6_MARK, A5_MARK, A4_MARK,
+	A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+	D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+	D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+	D7_MARK, D6_MARK, D5_MARK, D4_MARK,
+	D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+	BS_MARK,
+	CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
+	CS6CE1B_MARK, CS5CE1A_MARK,
+	CE2A_MARK, CE2B_MARK,
+	RD_MARK, RDWR_MARK,
+	ICIOWRAH_MARK,
+	ICIORD_MARK,
+	WE1DQMUWE_MARK,
+	WE0DQML_MARK,
+	RAS_MARK, CAS_MARK, CKE_MARK,
+	WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
+
+	/* TMU */
+	TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
+	TIOC1A_MARK, TIOC1B_MARK,
+	TIOC2A_MARK, TIOC2B_MARK,
+	TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
+	TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
+	TCLKA_MARK,	TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
+
+	/* SCIF */
+	SCK0_MARK, SCK1_MARK, SCK2_MARK, SCK3_MARK,
+	RXD0_MARK, RXD1_MARK, RXD2_MARK, RXD3_MARK,
+	TXD0_MARK, TXD1_MARK, TXD2_MARK, TXD3_MARK,
+	RXD4_MARK, RXD5_MARK, RXD6_MARK, RXD7_MARK,
+	TXD4_MARK, TXD5_MARK, TXD6_MARK, TXD7_MARK,
+	RTS1_MARK, RTS3_MARK,
+	CTS1_MARK, CTS3_MARK,
+
+	/* RSPI */
+	RSPCK0_MARK, RSPCK1_MARK,
+	MOSI0_MARK, MOSI1_MARK,
+	MISO0_PF12_MARK, MISO1_MARK, MISO1_PG19_MARK,
+	SSL00_MARK, SSL10_MARK,
+
+	/* IIC3 */
+	SCL0_MARK, SCL1_MARK, SCL2_MARK,
+	SDA0_MARK, SDA1_MARK, SDA2_MARK,
+
+	/* SSI */
+	SSISCK0_MARK,
+	SSIWS0_MARK,
+	SSITXD0_MARK,
+	SSIRXD0_MARK,
+	SSIWS1_MARK, SSIWS2_MARK, SSIWS3_MARK,
+	SSISCK1_MARK, SSISCK2_MARK, SSISCK3_MARK,
+	SSIDATA1_MARK, SSIDATA2_MARK, SSIDATA3_MARK,
+	AUDIO_CLK_MARK,
+
+	/* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+	SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
+
+	/* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+	SPDIF_IN_MARK, SPDIF_OUT_MARK,
+
+	/* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+	FCE_MARK,
+	FRB_MARK,
+
+	/* VDC3 */
+	DV_CLK_MARK,
+	DV_VSYNC_MARK, DV_HSYNC_MARK,
+	DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
+	DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
+	LCD_CLK_MARK, LCD_EXTCLK_MARK,
+	LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
+	LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
+	LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
+	LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
+	LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+	LCD_M_DISP_MARK,
+	PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+	/* Port A */
+	PINMUX_DATA(PA3_DATA, PA3_IN),
+	PINMUX_DATA(PA2_DATA, PA2_IN),
+	PINMUX_DATA(PA1_DATA, PA1_IN),
+	PINMUX_DATA(PA0_DATA, PA0_IN),
+
+	/* Port B */
+	PINMUX_DATA(PB22_DATA, PB22MD_00, PB22_IN, PB22_OUT),
+	PINMUX_DATA(A22_MARK, PB22MD_01),
+	PINMUX_DATA(CS4_MARK, PB22MD_10),
+
+	PINMUX_DATA(PB21_DATA, PB21MD_0, PB21_IN, PB21_OUT),
+	PINMUX_DATA(A21_MARK, PB21MD_1),
+	PINMUX_DATA(A20_MARK, PB20MD_1),
+	PINMUX_DATA(A19_MARK, PB19MD_01),
+	PINMUX_DATA(A18_MARK, PB18MD_01),
+	PINMUX_DATA(A17_MARK, PB17MD_01),
+	PINMUX_DATA(A16_MARK, PB16MD_01),
+	PINMUX_DATA(A15_MARK, PB15MD_01),
+	PINMUX_DATA(A14_MARK, PB14MD_01),
+	PINMUX_DATA(A13_MARK, PB13MD_01),
+	PINMUX_DATA(A12_MARK, PB12MD_01),
+	PINMUX_DATA(A11_MARK, PB11MD_01),
+	PINMUX_DATA(A10_MARK, PB10MD_01),
+	PINMUX_DATA(A9_MARK, PB9MD_01),
+	PINMUX_DATA(A8_MARK, PB8MD_01),
+	PINMUX_DATA(A7_MARK, PB7MD_01),
+	PINMUX_DATA(A6_MARK, PB6MD_01),
+	PINMUX_DATA(A5_MARK, PB5MD_01),
+	PINMUX_DATA(A4_MARK, PB4MD_01),
+	PINMUX_DATA(A3_MARK, PB3MD_1),
+	PINMUX_DATA(A2_MARK, PB2MD_1),
+	PINMUX_DATA(A1_MARK, PB1MD_1),
+
+	/* Port C */
+	PINMUX_DATA(PC10_DATA, PC10MD_0),
+	PINMUX_DATA(TIOC2B_MARK, PC1MD_1),
+	PINMUX_DATA(PC9_DATA, PC9MD_0),
+	PINMUX_DATA(TIOC2A_MARK, PC9MD_1),
+	PINMUX_DATA(PC8_DATA, PC8MD_00),
+	PINMUX_DATA(CS3_MARK, PC8MD_01),
+	PINMUX_DATA(TIOC4D_MARK, PC8MD_10),
+	PINMUX_DATA(IRQ7_PC_MARK, PC8MD_11),
+	PINMUX_DATA(PC7_DATA, PC7MD_00),
+	PINMUX_DATA(CKE_MARK, PC7MD_01),
+	PINMUX_DATA(TIOC4C_MARK, PC7MD_10),
+	PINMUX_DATA(IRQ6_PC_MARK, PC7MD_11),
+	PINMUX_DATA(PC6_DATA, PC6MD_00),
+	PINMUX_DATA(CAS_MARK, PC6MD_01),
+	PINMUX_DATA(TIOC4B_MARK, PC6MD_10),
+	PINMUX_DATA(IRQ5_PC_MARK, PC6MD_11),
+	PINMUX_DATA(PC5_DATA, PC5MD_00),
+	PINMUX_DATA(RAS_MARK, PC5MD_01),
+	PINMUX_DATA(TIOC4A_MARK, PC5MD_10),
+	PINMUX_DATA(IRQ4_PC_MARK, PC5MD_11),
+	PINMUX_DATA(PC4_DATA, PC4MD_0),
+	PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_1),
+	PINMUX_DATA(PC3_DATA, PC3MD_0),
+	PINMUX_DATA(WE0DQML_MARK, PC3MD_1),
+	PINMUX_DATA(PC2_DATA, PC2MD_0),
+	PINMUX_DATA(RDWR_MARK, PC2MD_1),
+	PINMUX_DATA(PC1_DATA, PC1MD_0),
+	PINMUX_DATA(RD_MARK, PC1MD_1),
+	PINMUX_DATA(PC0_DATA, PC0MD_0),
+	PINMUX_DATA(CS0_MARK, PC0MD_1),
+
+	/* Port D */
+	PINMUX_DATA(D15_MARK, PD15MD_01),
+	PINMUX_DATA(D14_MARK, PD14MD_01),
+	PINMUX_DATA(D13_MARK, PD13MD_01),
+	PINMUX_DATA(D12_MARK, PD12MD_01),
+	PINMUX_DATA(D11_MARK, PD11MD_01),
+	PINMUX_DATA(D10_MARK, PD10MD_01),
+	PINMUX_DATA(D9_MARK, PD9MD_01),
+	PINMUX_DATA(D8_MARK, PD8MD_01),
+	PINMUX_DATA(D7_MARK, PD7MD_01),
+	PINMUX_DATA(D6_MARK, PD6MD_01),
+	PINMUX_DATA(D5_MARK, PD5MD_01),
+	PINMUX_DATA(D4_MARK, PD4MD_01),
+	PINMUX_DATA(D3_MARK, PD3MD_01),
+	PINMUX_DATA(D2_MARK, PD2MD_01),
+	PINMUX_DATA(D1_MARK, PD1MD_01),
+	PINMUX_DATA(D0_MARK, PD0MD_01),
+
+	/* Port E */
+	PINMUX_DATA(PE5_DATA, PE5MD_00),
+	PINMUX_DATA(SDA2_MARK, PE5MD_01),
+	PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
+
+	PINMUX_DATA(PE4_DATA, PE4MD_00),
+	PINMUX_DATA(SCL2_MARK, PE4MD_01),
+	PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
+
+	PINMUX_DATA(PE3_DATA, PE3MD_00),
+	PINMUX_DATA(SDA1_MARK, PE3MD_01),
+	PINMUX_DATA(IRQ3_PE_MARK, PE3MD_11),
+
+	PINMUX_DATA(PE2_DATA, PE2MD_00),
+	PINMUX_DATA(SCL1_MARK, PE2MD_01),
+	PINMUX_DATA(IRQ2_PE_MARK, PE2MD_11),
+
+	PINMUX_DATA(PE1_DATA, PE1MD_000),
+	PINMUX_DATA(SDA0_MARK, PE1MD_001),
+	PINMUX_DATA(IOIS16_MARK, PE1MD_010),
+	PINMUX_DATA(IRQ1_PE_MARK, PE1MD_011),
+	PINMUX_DATA(TCLKA_MARK, PE1MD_100),
+	PINMUX_DATA(ADTRG_MARK, PE1MD_101),
+
+	PINMUX_DATA(PE0_DATA, PE0MD_00),
+	PINMUX_DATA(SCL0_MARK, PE0MD_01),
+	PINMUX_DATA(AUDIO_CLK_MARK, PE0MD_10),
+	PINMUX_DATA(IRQ0_PE_MARK, PE0MD_11),
+
+	/* Port F */
+	PINMUX_DATA(PF12_DATA, PF12MD_000),
+	PINMUX_DATA(BS_MARK, PF12MD_001),
+	PINMUX_DATA(MISO0_PF12_MARK, PF12MD_011),
+	PINMUX_DATA(TIOC3D_MARK, PF12MD_100),
+	PINMUX_DATA(SPDIF_OUT_MARK, PF12MD_101),
+
+	PINMUX_DATA(PF11_DATA, PF11MD_000),
+	PINMUX_DATA(A25_MARK, PF11MD_001),
+	PINMUX_DATA(SSIDATA3_MARK, PF11MD_010),
+	PINMUX_DATA(MOSI0_MARK, PF11MD_011),
+	PINMUX_DATA(TIOC3C_MARK, PF11MD_100),
+	PINMUX_DATA(SPDIF_IN_MARK, PF11MD_101),
+
+	PINMUX_DATA(PF10_DATA, PF10MD_000),
+	PINMUX_DATA(A24_MARK, PF10MD_001),
+	PINMUX_DATA(SSIWS3_MARK, PF10MD_010),
+	PINMUX_DATA(SSL00_MARK, PF10MD_011),
+	PINMUX_DATA(TIOC3B_MARK, PF10MD_100),
+	PINMUX_DATA(FCE_MARK, PF10MD_101),
+
+	PINMUX_DATA(PF9_DATA, PF9MD_000),
+	PINMUX_DATA(A23_MARK, PF9MD_001),
+	PINMUX_DATA(SSISCK3_MARK, PF9MD_010),
+	PINMUX_DATA(RSPCK0_MARK, PF9MD_011),
+	PINMUX_DATA(TIOC3A_MARK, PF9MD_100),
+	PINMUX_DATA(FRB_MARK, PF9MD_101),
+
+	PINMUX_DATA(PF8_DATA, PF8MD_00),
+	PINMUX_DATA(CE2B_MARK, PF8MD_01),
+	PINMUX_DATA(SSIDATA3_MARK, PF8MD_10),
+	PINMUX_DATA(DV_CLK_MARK, PF8MD_11),
+
+	PINMUX_DATA(PF7_DATA, PF7MD_000),
+	PINMUX_DATA(CE2A_MARK, PF7MD_001),
+	PINMUX_DATA(SSIWS3_MARK, PF7MD_010),
+	PINMUX_DATA(DV_DATA7_MARK, PF7MD_011),
+	PINMUX_DATA(TCLKD_MARK, PF7MD_100),
+
+	PINMUX_DATA(PF6_DATA, PF6MD_000),
+	PINMUX_DATA(CS6CE1B_MARK, PF6MD_001),
+	PINMUX_DATA(SSISCK3_MARK, PF6MD_010),
+	PINMUX_DATA(DV_DATA6_MARK, PF6MD_011),
+	PINMUX_DATA(TCLKB_MARK, PF6MD_100),
+
+	PINMUX_DATA(PF5_DATA, PF5MD_000),
+	PINMUX_DATA(CS5CE1A_MARK, PF5MD_001),
+	PINMUX_DATA(SSIDATA2_MARK, PF5MD_010),
+	PINMUX_DATA(DV_DATA5_MARK, PF5MD_011),
+	PINMUX_DATA(TCLKC_MARK, PF5MD_100),
+
+	PINMUX_DATA(PF4_DATA, PF4MD_000),
+	PINMUX_DATA(ICIOWRAH_MARK, PF4MD_001),
+	PINMUX_DATA(SSIWS2_MARK, PF4MD_010),
+	PINMUX_DATA(DV_DATA4_MARK, PF4MD_011),
+	PINMUX_DATA(TXD3_MARK, PF4MD_100),
+
+	PINMUX_DATA(PF3_DATA, PF3MD_000),
+	PINMUX_DATA(ICIORD_MARK, PF3MD_001),
+	PINMUX_DATA(SSISCK2_MARK, PF3MD_010),
+	PINMUX_DATA(DV_DATA3_MARK, PF3MD_011),
+	PINMUX_DATA(RXD3_MARK, PF3MD_100),
+
+	PINMUX_DATA(PF2_DATA, PF2MD_000),
+	PINMUX_DATA(BACK_MARK, PF2MD_001),
+	PINMUX_DATA(SSIDATA1_MARK, PF2MD_010),
+	PINMUX_DATA(DV_DATA2_MARK, PF2MD_011),
+	PINMUX_DATA(TXD2_MARK, PF2MD_100),
+	PINMUX_DATA(DACK0_MARK, PF2MD_101),
+
+	PINMUX_DATA(PF1_DATA, PF1MD_000),
+	PINMUX_DATA(BREQ_MARK, PF1MD_001),
+	PINMUX_DATA(SSIWS1_MARK, PF1MD_010),
+	PINMUX_DATA(DV_DATA1_MARK, PF1MD_011),
+	PINMUX_DATA(RXD2_MARK, PF1MD_100),
+	PINMUX_DATA(DREQ0_MARK, PF1MD_101),
+
+	PINMUX_DATA(PF0_DATA, PF0MD_000),
+	PINMUX_DATA(WAIT_MARK, PF0MD_001),
+	PINMUX_DATA(SSISCK1_MARK, PF0MD_010),
+	PINMUX_DATA(DV_DATA0_MARK, PF0MD_011),
+	PINMUX_DATA(SCK2_MARK, PF0MD_100),
+	PINMUX_DATA(TEND0_MARK, PF0MD_101),
+
+	/* Port G */
+	PINMUX_DATA(PG24_DATA, PG24MD_00),
+	PINMUX_DATA(MOSI0_MARK, PG24MD_01),
+	PINMUX_DATA(TIOC0D_MARK, PG24MD_10),
+
+	PINMUX_DATA(PG23_DATA, PG23MD_00),
+	PINMUX_DATA(MOSI1_MARK, PG23MD_01),
+	PINMUX_DATA(TIOC0C_MARK, PG23MD_10),
+
+	PINMUX_DATA(PG22_DATA, PG22MD_00),
+	PINMUX_DATA(SSL10_MARK, PG22MD_01),
+	PINMUX_DATA(TIOC0B_MARK, PG22MD_10),
+
+	PINMUX_DATA(PG21_DATA, PG21MD_00),
+	PINMUX_DATA(RSPCK1_MARK, PG21MD_01),
+	PINMUX_DATA(TIOC0A_MARK, PG21MD_10),
+
+	PINMUX_DATA(PG20_DATA, PG20MD_000),
+	PINMUX_DATA(LCD_EXTCLK_MARK, PG20MD_001),
+	PINMUX_DATA(MISO1_MARK, PG20MD_011),
+	PINMUX_DATA(TXD7_MARK, PG20MD_100),
+
+	PINMUX_DATA(PG19_DATA, PG19MD_000),
+	PINMUX_DATA(LCD_CLK_MARK, PG19MD_001),
+	PINMUX_DATA(TIOC2B_MARK, PG19MD_010),
+	PINMUX_DATA(MISO1_PG19_MARK, PG19MD_011),
+	PINMUX_DATA(RXD7_MARK, PG19MD_100),
+
+	PINMUX_DATA(PG18_DATA, PG18MD_000),
+	PINMUX_DATA(LCD_DE_MARK, PG18MD_001),
+	PINMUX_DATA(TIOC2A_MARK, PG18MD_010),
+	PINMUX_DATA(SSL10_MARK, PG18MD_011),
+	PINMUX_DATA(TXD6_MARK, PG18MD_100),
+
+	PINMUX_DATA(PG17_DATA, PG17MD_000),
+	PINMUX_DATA(LCD_HSYNC_MARK, PG17MD_001),
+	PINMUX_DATA(TIOC1B_MARK, PG17MD_010),
+	PINMUX_DATA(RSPCK1_MARK, PG17MD_011),
+	PINMUX_DATA(RXD6_MARK, PG17MD_100),
+
+	PINMUX_DATA(PG16_DATA, PG16MD_000),
+	PINMUX_DATA(LCD_VSYNC_MARK, PG16MD_001),
+	PINMUX_DATA(TIOC1A_MARK, PG16MD_010),
+	PINMUX_DATA(TXD3_MARK, PG16MD_011),
+	PINMUX_DATA(CTS1_MARK, PG16MD_100),
+
+	PINMUX_DATA(PG15_DATA, PG15MD_000),
+	PINMUX_DATA(LCD_DATA15_MARK, PG15MD_001),
+	PINMUX_DATA(TIOC0D_MARK, PG15MD_010),
+	PINMUX_DATA(RXD3_MARK, PG15MD_011),
+	PINMUX_DATA(RTS1_MARK, PG15MD_100),
+
+	PINMUX_DATA(PG14_DATA, PG14MD_000),
+	PINMUX_DATA(LCD_DATA14_MARK, PG14MD_001),
+	PINMUX_DATA(TIOC0C_MARK, PG14MD_010),
+	PINMUX_DATA(SCK1_MARK, PG14MD_100),
+
+	PINMUX_DATA(PG13_DATA, PG13MD_000),
+	PINMUX_DATA(LCD_DATA13_MARK, PG13MD_001),
+	PINMUX_DATA(TIOC0B_MARK, PG13MD_010),
+	PINMUX_DATA(TXD1_MARK, PG13MD_100),
+
+	PINMUX_DATA(PG12_DATA, PG12MD_000),
+	PINMUX_DATA(LCD_DATA12_MARK, PG12MD_001),
+	PINMUX_DATA(TIOC0A_MARK, PG12MD_010),
+	PINMUX_DATA(RXD1_MARK, PG12MD_100),
+
+	PINMUX_DATA(PG11_DATA, PG11MD_000),
+	PINMUX_DATA(LCD_DATA11_MARK, PG11MD_001),
+	PINMUX_DATA(SSITXD0_MARK, PG11MD_010),
+	PINMUX_DATA(IRQ3_PG_MARK, PG11MD_011),
+	PINMUX_DATA(TXD5_MARK, PG11MD_100),
+	PINMUX_DATA(SIOFTXD_MARK, PG11MD_101),
+
+	PINMUX_DATA(PG10_DATA, PG10MD_000),
+	PINMUX_DATA(LCD_DATA10_MARK, PG10MD_001),
+	PINMUX_DATA(SSIRXD0_MARK, PG10MD_010),
+	PINMUX_DATA(IRQ2_PG_MARK, PG10MD_011),
+	PINMUX_DATA(RXD5_MARK, PG10MD_100),
+	PINMUX_DATA(SIOFRXD_MARK, PG10MD_101),
+
+	PINMUX_DATA(PG9_DATA, PG9MD_000),
+	PINMUX_DATA(LCD_DATA9_MARK, PG9MD_001),
+	PINMUX_DATA(SSIWS0_MARK, PG9MD_010),
+	PINMUX_DATA(TXD4_MARK, PG9MD_100),
+	PINMUX_DATA(SIOFSYNC_MARK, PG9MD_101),
+
+	PINMUX_DATA(PG8_DATA, PG8MD_000),
+	PINMUX_DATA(LCD_DATA8_MARK, PG8MD_001),
+	PINMUX_DATA(SSISCK0_MARK, PG8MD_010),
+	PINMUX_DATA(RXD4_MARK, PG8MD_100),
+	PINMUX_DATA(SIOFSCK_MARK, PG8MD_101),
+
+	PINMUX_DATA(PG7_DATA, PG7MD_00),
+	PINMUX_DATA(LCD_DATA7_MARK, PG7MD_01),
+	PINMUX_DATA(SD_CD_MARK, PG7MD_10),
+	PINMUX_DATA(PINT7_PG_MARK, PG7MD_11),
+
+	PINMUX_DATA(PG6_DATA, PG7MD_00),
+	PINMUX_DATA(LCD_DATA6_MARK, PG7MD_01),
+	PINMUX_DATA(SD_WP_MARK, PG7MD_10),
+	PINMUX_DATA(PINT6_PG_MARK, PG7MD_11),
+
+	PINMUX_DATA(PG5_DATA, PG5MD_00),
+	PINMUX_DATA(LCD_DATA5_MARK, PG5MD_01),
+	PINMUX_DATA(SD_D1_MARK, PG5MD_10),
+	PINMUX_DATA(PINT5_PG_MARK, PG5MD_11),
+
+	PINMUX_DATA(PG4_DATA, PG4MD_00),
+	PINMUX_DATA(LCD_DATA4_MARK, PG4MD_01),
+	PINMUX_DATA(SD_D0_MARK, PG4MD_10),
+	PINMUX_DATA(PINT4_PG_MARK, PG4MD_11),
+
+	PINMUX_DATA(PG3_DATA, PG3MD_00),
+	PINMUX_DATA(LCD_DATA3_MARK, PG3MD_01),
+	PINMUX_DATA(SD_CLK_MARK, PG3MD_10),
+	PINMUX_DATA(PINT3_PG_MARK, PG3MD_11),
+
+	PINMUX_DATA(PG2_DATA, PG2MD_00),
+	PINMUX_DATA(LCD_DATA2_MARK, PG2MD_01),
+	PINMUX_DATA(SD_CMD_MARK, PG2MD_10),
+	PINMUX_DATA(PINT2_PG_MARK, PG2MD_11),
+
+	PINMUX_DATA(PG1_DATA, PG1MD_00),
+	PINMUX_DATA(LCD_DATA1_MARK, PG1MD_01),
+	PINMUX_DATA(SD_D3_MARK, PG1MD_10),
+	PINMUX_DATA(PINT1_PG_MARK, PG1MD_11),
+
+	PINMUX_DATA(PG0_DATA, PG0MD_000),
+	PINMUX_DATA(LCD_DATA0_MARK, PG0MD_001),
+	PINMUX_DATA(SD_D2_MARK, PG0MD_010),
+	PINMUX_DATA(PINT0_PG_MARK, PG0MD_011),
+	PINMUX_DATA(WDTOVF_MARK, PG0MD_100),
+
+	/* Port H */
+	PINMUX_DATA(PH7_DATA, PH7MD_0),
+	PINMUX_DATA(PHAN7_MARK, PH7MD_1),
+
+	PINMUX_DATA(PH6_DATA, PH6MD_0),
+	PINMUX_DATA(PHAN6_MARK, PH6MD_1),
+
+	PINMUX_DATA(PH5_DATA, PH5MD_0),
+	PINMUX_DATA(PHAN5_MARK, PH5MD_1),
+
+	PINMUX_DATA(PH4_DATA, PH4MD_0),
+	PINMUX_DATA(PHAN4_MARK, PH4MD_1),
+
+	PINMUX_DATA(PH3_DATA, PH3MD_0),
+	PINMUX_DATA(PHAN3_MARK, PH3MD_1),
+
+	PINMUX_DATA(PH2_DATA, PH2MD_0),
+	PINMUX_DATA(PHAN2_MARK, PH2MD_1),
+
+	PINMUX_DATA(PH1_DATA, PH1MD_0),
+	PINMUX_DATA(PHAN1_MARK, PH1MD_1),
+
+	PINMUX_DATA(PH0_DATA, PH0MD_0),
+	PINMUX_DATA(PHAN0_MARK, PH0MD_1),
+
+	/* Port I - not on device */
+
+	/* Port J */
+	PINMUX_DATA(PJ11_DATA, PJ11MD_00),
+	PINMUX_DATA(PWM2H_MARK, PJ11MD_01),
+	PINMUX_DATA(DACK1_MARK, PJ11MD_10),
+
+	PINMUX_DATA(PJ10_DATA, PJ10MD_00),
+	PINMUX_DATA(PWM2G_MARK, PJ10MD_01),
+	PINMUX_DATA(DREQ1_MARK, PJ10MD_10),
+
+	PINMUX_DATA(PJ9_DATA, PJ9MD_00),
+	PINMUX_DATA(PWM2F_MARK, PJ9MD_01),
+	PINMUX_DATA(TEND1_MARK, PJ9MD_10),
+
+	PINMUX_DATA(PJ8_DATA, PJ8MD_00),
+	PINMUX_DATA(PWM2E_MARK, PJ8MD_01),
+	PINMUX_DATA(RTS3_MARK, PJ8MD_10),
+
+	PINMUX_DATA(PJ7_DATA, PJ7MD_00),
+	PINMUX_DATA(TIOC1B_MARK, PJ7MD_01),
+	PINMUX_DATA(CTS3_MARK, PJ7MD_10),
+
+	PINMUX_DATA(PJ6_DATA, PJ6MD_00),
+	PINMUX_DATA(TIOC1A_MARK, PJ6MD_01),
+	PINMUX_DATA(SCK3_MARK, PJ6MD_10),
+
+	PINMUX_DATA(PJ5_DATA, PJ5MD_00),
+	PINMUX_DATA(IERXD_MARK, PJ5MD_01),
+	PINMUX_DATA(TXD3_MARK, PJ5MD_10),
+
+	PINMUX_DATA(PJ4_DATA, PJ4MD_00),
+	PINMUX_DATA(IETXD_MARK, PJ4MD_01),
+	PINMUX_DATA(RXD3_MARK, PJ4MD_10),
+
+	PINMUX_DATA(PJ3_DATA, PJ3MD_00),
+	PINMUX_DATA(CRX1_MARK, PJ3MD_01),
+	PINMUX_DATA(CRX0X1_MARK, PJ3MD_10),
+	PINMUX_DATA(IRQ1_PJ_MARK, PJ3MD_11),
+
+	PINMUX_DATA(PJ2_DATA, PJ2MD_000),
+	PINMUX_DATA(CTX1_MARK, PJ2MD_001),
+	PINMUX_DATA(CRX0CRX1_MARK, PJ2MD_010),
+	PINMUX_DATA(CS2_MARK, PJ2MD_011),
+	PINMUX_DATA(SCK0_MARK, PJ2MD_100),
+	PINMUX_DATA(LCD_M_DISP_MARK, PJ2MD_101),
+
+	PINMUX_DATA(PJ1_DATA, PJ1MD_000),
+	PINMUX_DATA(CRX0_MARK, PJ1MD_001),
+	PINMUX_DATA(IERXD_MARK, PJ1MD_010),
+	PINMUX_DATA(IRQ0_PJ_MARK, PJ1MD_011),
+	PINMUX_DATA(RXD0_MARK, PJ1MD_100),
+
+	PINMUX_DATA(PJ0_DATA, PJ0MD_000),
+	PINMUX_DATA(CTX0_MARK, PJ0MD_001),
+	PINMUX_DATA(IERXD_MARK, PJ0MD_010),
+	PINMUX_DATA(CS1_MARK, PJ0MD_011),
+	PINMUX_DATA(TXD0_MARK, PJ0MD_100),
+	PINMUX_DATA(A0_MARK, PJ0MD_101),
+
+	/* Port K */
+	PINMUX_DATA(PK11_DATA, PK11MD_00),
+	PINMUX_DATA(PWM2D_MARK, PK11MD_01),
+	PINMUX_DATA(SSITXD0_MARK, PK11MD_10),
+
+	PINMUX_DATA(PK10_DATA, PK10MD_00),
+	PINMUX_DATA(PWM2C_MARK, PK10MD_01),
+	PINMUX_DATA(SSIRXD0_MARK, PK10MD_10),
+
+	PINMUX_DATA(PK9_DATA, PK9MD_00),
+	PINMUX_DATA(PWM2B_MARK, PK9MD_01),
+	PINMUX_DATA(SSIWS0_MARK, PK9MD_10),
+
+	PINMUX_DATA(PK8_DATA, PK8MD_00),
+	PINMUX_DATA(PWM2A_MARK, PK8MD_01),
+	PINMUX_DATA(SSISCK0_MARK, PK8MD_10),
+
+	PINMUX_DATA(PK7_DATA, PK7MD_00),
+	PINMUX_DATA(PWM1H_MARK, PK7MD_01),
+	PINMUX_DATA(SD_CD_MARK, PK7MD_10),
+
+	PINMUX_DATA(PK6_DATA, PK6MD_00),
+	PINMUX_DATA(PWM1G_MARK, PK6MD_01),
+	PINMUX_DATA(SD_WP_MARK, PK6MD_10),
+
+	PINMUX_DATA(PK5_DATA, PK5MD_00),
+	PINMUX_DATA(PWM1F_MARK, PK5MD_01),
+	PINMUX_DATA(SD_D1_MARK, PK5MD_10),
+
+	PINMUX_DATA(PK4_DATA, PK4MD_00),
+	PINMUX_DATA(PWM1E_MARK, PK4MD_01),
+	PINMUX_DATA(SD_D0_MARK, PK4MD_10),
+
+	PINMUX_DATA(PK3_DATA, PK3MD_00),
+	PINMUX_DATA(PWM1D_MARK, PK3MD_01),
+	PINMUX_DATA(SD_CLK_MARK, PK3MD_10),
+
+	PINMUX_DATA(PK2_DATA, PK2MD_00),
+	PINMUX_DATA(PWM1C_MARK, PK2MD_01),
+	PINMUX_DATA(SD_CMD_MARK, PK2MD_10),
+
+	PINMUX_DATA(PK1_DATA, PK1MD_00),
+	PINMUX_DATA(PWM1B_MARK, PK1MD_01),
+	PINMUX_DATA(SD_D3_MARK, PK1MD_10),
+
+	PINMUX_DATA(PK0_DATA, PK0MD_00),
+	PINMUX_DATA(PWM1A_MARK, PK0MD_01),
+	PINMUX_DATA(SD_D2_MARK, PK0MD_10),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+
+	/* Port A */
+	PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+	PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+	PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+	PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+	/* Port B */
+	PINMUX_GPIO(GPIO_PB22, PB22_DATA),
+	PINMUX_GPIO(GPIO_PB21, PB21_DATA),
+	PINMUX_GPIO(GPIO_PB20, PB20_DATA),
+	PINMUX_GPIO(GPIO_PB19, PB19_DATA),
+	PINMUX_GPIO(GPIO_PB18, PB18_DATA),
+	PINMUX_GPIO(GPIO_PB17, PB17_DATA),
+	PINMUX_GPIO(GPIO_PB16, PB16_DATA),
+	PINMUX_GPIO(GPIO_PB15, PB15_DATA),
+	PINMUX_GPIO(GPIO_PB14, PB14_DATA),
+	PINMUX_GPIO(GPIO_PB13, PB13_DATA),
+	PINMUX_GPIO(GPIO_PB12, PB12_DATA),
+	PINMUX_GPIO(GPIO_PB11, PB11_DATA),
+	PINMUX_GPIO(GPIO_PB10, PB10_DATA),
+	PINMUX_GPIO(GPIO_PB9, PB9_DATA),
+	PINMUX_GPIO(GPIO_PB8, PB8_DATA),
+	PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+	PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+	PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+	PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+	PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+	PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+	PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+
+	/* Port C */
+	PINMUX_GPIO(GPIO_PC10, PC10_DATA),
+	PINMUX_GPIO(GPIO_PC9, PC9_DATA),
+	PINMUX_GPIO(GPIO_PC8, PC8_DATA),
+	PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+	PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+	PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+	PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+	PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+	PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+	PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+	PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+	/* Port D */
+	PINMUX_GPIO(GPIO_PD15, PD15_DATA),
+	PINMUX_GPIO(GPIO_PD14, PD14_DATA),
+	PINMUX_GPIO(GPIO_PD13, PD13_DATA),
+	PINMUX_GPIO(GPIO_PD12, PD12_DATA),
+	PINMUX_GPIO(GPIO_PD11, PD11_DATA),
+	PINMUX_GPIO(GPIO_PD10, PD10_DATA),
+	PINMUX_GPIO(GPIO_PD9, PD9_DATA),
+	PINMUX_GPIO(GPIO_PD8, PD8_DATA),
+	PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+	PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+	PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+	PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+	PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+	PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+	PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+	PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+	/* Port E */
+	PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+	PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+	PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+	PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+	PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+	PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+	/* Port F */
+	PINMUX_GPIO(GPIO_PF12, PF12_DATA),
+	PINMUX_GPIO(GPIO_PF11, PF11_DATA),
+	PINMUX_GPIO(GPIO_PF10, PF10_DATA),
+	PINMUX_GPIO(GPIO_PF9, PF9_DATA),
+	PINMUX_GPIO(GPIO_PF8, PF8_DATA),
+	PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+	PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+	PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+	PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+	PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+	PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+	PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+	PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+	/* Port G */
+	PINMUX_GPIO(GPIO_PG24, PG24_DATA),
+	PINMUX_GPIO(GPIO_PG23, PG23_DATA),
+	PINMUX_GPIO(GPIO_PG22, PG22_DATA),
+	PINMUX_GPIO(GPIO_PG21, PG21_DATA),
+	PINMUX_GPIO(GPIO_PG20, PG20_DATA),
+	PINMUX_GPIO(GPIO_PG19, PG19_DATA),
+	PINMUX_GPIO(GPIO_PG18, PG18_DATA),
+	PINMUX_GPIO(GPIO_PG17, PG17_DATA),
+	PINMUX_GPIO(GPIO_PG16, PG16_DATA),
+	PINMUX_GPIO(GPIO_PG15, PG15_DATA),
+	PINMUX_GPIO(GPIO_PG14, PG14_DATA),
+	PINMUX_GPIO(GPIO_PG13, PG13_DATA),
+	PINMUX_GPIO(GPIO_PG12, PG12_DATA),
+	PINMUX_GPIO(GPIO_PG11, PG11_DATA),
+	PINMUX_GPIO(GPIO_PG10, PG10_DATA),
+	PINMUX_GPIO(GPIO_PG9, PG9_DATA),
+	PINMUX_GPIO(GPIO_PG8, PG8_DATA),
+	PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+	PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+	PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+	PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+	PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+	PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+	PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+	PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+	/* Port H - Port H does not have a Data Register */
+
+	/* Port I - not on device */
+
+	/* Port J */
+	PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
+	PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
+	PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
+	PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
+	PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+	PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+	PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+	PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+	PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+	PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+	PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+	PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+
+	/* Port K */
+	PINMUX_GPIO(GPIO_PK11, PK11_DATA),
+	PINMUX_GPIO(GPIO_PK10, PK10_DATA),
+	PINMUX_GPIO(GPIO_PK9, PK9_DATA),
+	PINMUX_GPIO(GPIO_PK8, PK8_DATA),
+	PINMUX_GPIO(GPIO_PK7, PK7_DATA),
+	PINMUX_GPIO(GPIO_PK6, PK6_DATA),
+	PINMUX_GPIO(GPIO_PK5, PK5_DATA),
+	PINMUX_GPIO(GPIO_PK4, PK4_DATA),
+	PINMUX_GPIO(GPIO_PK3, PK3_DATA),
+	PINMUX_GPIO(GPIO_PK2, PK2_DATA),
+	PINMUX_GPIO(GPIO_PK1, PK1_DATA),
+	PINMUX_GPIO(GPIO_PK0, PK0_DATA),
+
+	/* INTC */
+	PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
+
+	PINMUX_GPIO(GPIO_FN_IRQ7_PC, IRQ7_PC_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ6_PC, IRQ6_PC_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ5_PC, IRQ5_PC_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ4_PC, IRQ4_PC_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ3_PE, IRQ3_PE_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ2_PE, IRQ2_PE_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ1_PE, IRQ1_PE_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ0_PE, IRQ0_PE_MARK),
+
+	/* WDT */
+	PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+
+	/* CAN */
+	PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
+	PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
+	PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
+	PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
+	PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0CRX1_MARK),
+
+	/* DMAC */
+	PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+	PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+
+	/* ADC */
+	PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+	/* BSCh */
+	PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+	PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+	PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+	PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+	PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+	PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+	PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+	PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
+	PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
+	PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+	PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
+	PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
+	PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
+	PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
+	PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
+	PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
+	PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
+	PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+	PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
+	PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
+	PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
+	PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
+	PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
+	PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
+	PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+	PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+
+	PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+	PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+	PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+	PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+	PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+	PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+	PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+	PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+	PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+	PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+	PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+	PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+	PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+	PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+	PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+	PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+	PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+	PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+	PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
+	PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
+	PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
+	PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
+	PINMUX_GPIO(GPIO_FN_CS6CE1B, CS6CE1B_MARK),
+	PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
+	PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+	PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+	PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+	PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+	PINMUX_GPIO(GPIO_FN_ICIOWRAH, ICIOWRAH_MARK),
+	PINMUX_GPIO(GPIO_FN_ICIORD, ICIORD_MARK),
+	PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
+	PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
+	PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
+	PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
+	PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+	PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+	PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+	PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+	PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+
+	/* TMU */
+	PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
+	PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
+	PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
+	PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
+	PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
+
+	/* SCIF */
+	PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+	PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+	PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
+	PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
+	PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
+
+	/* RSPI */
+	PINMUX_GPIO(GPIO_FN_RSPCK0, RSPCK0_MARK),
+	PINMUX_GPIO(GPIO_FN_MOSI0, MOSI0_MARK),
+	PINMUX_GPIO(GPIO_FN_MISO0_PF12, MISO0_PF12_MARK),
+	PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
+	PINMUX_GPIO(GPIO_FN_SSL00, SSL00_MARK),
+	PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
+	PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
+	PINMUX_GPIO(GPIO_FN_MISO1_PG19, MISO1_PG19_MARK),
+	PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
+
+	/* IIC3 */
+	PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+	PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+	PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+	PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+	PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+	PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+
+	/* SSI */
+	PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
+	PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
+	PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
+	PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
+	PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
+	PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
+
+	/* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+	PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
+	PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
+	PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
+	PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
+
+	/* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+	PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
+	PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
+
+	/* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+	PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+	PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+	/* VDC3 */
+	PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+
+	PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
+
+	PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
+
+	PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+
+	PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+	{ PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PA3_IN, PA3_OUT,
+		PA2_IN, PA2_OUT,
+		PA1_IN, PA1_OUT,
+		PA0_IN,	PA0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PB22MD_00, PB22MD_01, PB22MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PB21MD_0, PB21MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB20MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+
+	},
+	{ PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
+		0, PB19MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB18MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB17MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB16MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
+		0, PB15MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB14MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB13MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB12MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
+		0, PB11MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB10MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB9MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB8MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
+		0, PB7MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB6MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB5MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB4MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
+		0, PB3MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB2MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB1MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0,
+		PB22_IN, PB22_OUT,
+		PB21_IN, PB21_OUT,
+		PB20_IN, PB20_OUT,
+		PB19_IN, PB19_OUT,
+		PB18_IN, PB18_OUT,
+		PB17_IN, PB17_OUT,
+		PB16_IN, PB16_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
+		PB15_IN, PB15_OUT,
+		PB14_IN, PB14_OUT,
+		PB13_IN, PB13_OUT,
+		PB12_IN, PB12_OUT,
+		PB11_IN, PB11_OUT,
+		PB10_IN, PB10_OUT,
+		PB9_IN, PB9_OUT,
+		PB8_IN, PB8_OUT,
+		PB7_IN, PB7_OUT,
+		PB6_IN, PB6_OUT,
+		PB5_IN, PB5_OUT,
+		PB4_IN, PB4_OUT,
+		PB3_IN, PB3_OUT,
+		PB2_IN, PB2_OUT,
+		PB1_IN, PB1_OUT,
+		0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC10MD_0, PC10MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC9MD_0, PC9MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
+		PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC4MD_0, PC4MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
+		PC3MD_0, PC3MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC2MD_0, PC2MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		PC10_IN, PC10_OUT,
+		PC9_IN, PC9_OUT,
+		PC8_IN, PC8_OUT,
+		PC7_IN, PC7_OUT,
+		PC6_IN, PC6_OUT,
+		PC5_IN, PC5_OUT,
+		PC4_IN, PC4_OUT,
+		PC3_IN, PC3_OUT,
+		PC2_IN, PC2_OUT,
+		PC1_IN, PC1_OUT,
+		PC0_IN, PC0_OUT
+	 }
+	},
+
+	{ PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
+		0, PD15MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD14MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD13MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD12MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
+		0, PD11MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD10MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD9MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD8MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
+		0, PD7MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD6MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD5MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD4MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
+		0, PD3MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD2MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD1MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PD0MD_01, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
+		PD15_IN, PD15_OUT,
+		PD14_IN, PD14_OUT,
+		PD13_IN, PD13_OUT,
+		PD12_IN, PD12_OUT,
+		PD11_IN, PD11_OUT,
+		PD10_IN, PD10_OUT,
+		PD9_IN, PD9_OUT,
+		PD8_IN, PD8_OUT,
+		PD7_IN, PD7_OUT,
+		PD6_IN, PD6_OUT,
+		PD5_IN, PD5_OUT,
+		PD4_IN, PD4_OUT,
+		PD3_IN, PD3_OUT,
+		PD2_IN, PD2_OUT,
+		PD1_IN, PD1_OUT,
+		PD0_IN, PD0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PE5MD_00, PE5MD_01, 0, PE5MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PE4MD_00, PE4MD_01, 0, PE4MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
+		PE3MD_00, PE3MD_01, 0, PE3MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PE2MD_00, PE2MD_01, 0, PE2MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+		PE1MD_100, PE1MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0,
+		PE5_IN, PE5_OUT,
+		PE4_IN, PE4_OUT,
+		PE3_IN, PE3_OUT,
+		PE2_IN, PE2_OUT,
+		PE1_IN, PE1_OUT,
+		PE0_IN, PE0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
+		PF12MD_000, PF12MD_001, 0, PF12MD_011,
+		PF12MD_100, PF12MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
+		PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+		PF11MD_100, PF11MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+		PF10MD_100, PF10MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+		PF9MD_100, PF9MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
+		PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+		PF7MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+		PF6MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+		PF5MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+		PF4MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
+		PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+		PF3MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+		PF2MD_100, PF2MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+		PF1MD_100, PF1MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0
+	 }
+	},
+
+	{ PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
+		0, 0, 0, 0, 0, 0,
+		PF12_IN, PF12_OUT,
+		PF11_IN, PF11_OUT,
+		PF10_IN, PF10_OUT,
+		PF9_IN, PF9_OUT,
+		PF8_IN, PF8_OUT,
+		PF7_IN, PF7_OUT,
+		PF6_IN, PF6_OUT,
+		PF5_IN, PF5_OUT,
+		PF4_IN, PF4_OUT,
+		PF3_IN, PF3_OUT,
+		PF2_IN, PF2_OUT,
+		PF1_IN, PF1_OUT,
+		PF0_IN, PF0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PGCR7", 0xfffe38c0, 16, 4) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+		PG0MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
+		PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+		PG20MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
+		PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+		PG19MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+		PG18MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
+		PG17MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
+		PG16MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
+		PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
+		PG15MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG14MD_000, PG14MD_001, PG14MD_010, 0,
+		PG14MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG13MD_000, PG13MD_001, PG13MD_010, 0,
+		PG13MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG12MD_000, PG12MD_001, PG12MD_010, 0,
+		PG12MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
+		PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+		PG11MD_100, PG11MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+		PG10MD_100, PG10MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+		PG9MD_100, PG9MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+		PG8MD_100, PG8MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
+		PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
+		PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0,
+		PG24_IN, PG24_OUT,
+		PG23_IN, PG23_OUT,
+		PG22_IN, PG22_OUT,
+		PG21_IN, PG21_OUT,
+		PG20_IN, PG20_OUT,
+		PG19_IN, PG19_OUT,
+		PG18_IN, PG18_OUT,
+		PG17_IN, PG17_OUT,
+		PG16_IN, PG16_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
+		PG15_IN, PG15_OUT,
+		PG14_IN, PG14_OUT,
+		PG13_IN, PG13_OUT,
+		PG12_IN, PG12_OUT,
+		PG11_IN, PG11_OUT,
+		PG10_IN, PG10_OUT,
+		PG9_IN, PG9_OUT,
+		PG8_IN, PG8_OUT,
+		PG7_IN, PG7_OUT,
+		PG6_IN, PG6_OUT,
+		PG5_IN, PG5_OUT,
+		PG4_IN, PG4_OUT,
+		PG3_IN, PG3_OUT,
+		PG2_IN, PG2_OUT,
+		PG1_IN, PG1_OUT,
+		PG0_IN, PG0_OUT
+	 }
+	},
+
+	{ PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
+		PH7MD_0, PH7MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PH6MD_0, PH6MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PH5MD_0, PH5MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PH4MD_0, PH4MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
+		PH3MD_0, PH3MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PH2MD_0, PH2MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PH1MD_0, PH1MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PH0MD_0, PH0MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
+		PJ11MD_00, PJ11MD_01, PJ11MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ10MD_00, PJ10MD_01, PJ10MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ9MD_00, PJ9MD_01, PJ9MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ8MD_00, PJ8MD_01, PJ8MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
+		PJ7MD_00, PJ7MD_01, PJ7MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ6MD_00, PJ6MD_01, PJ6MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ5MD_00, PJ5MD_01, PJ5MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ4MD_00, PJ4MD_01, PJ4MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
+		PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+		PJ2MD_100, PJ2MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+		PJ1MD_100, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+		PJ0MD_100, PJ0MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, }
+	},
+	{ PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ11_IN, PJ11_OUT,
+		PJ10_IN, PJ10_OUT,
+		PJ9_IN, PJ9_OUT,
+		PJ8_IN, PJ8_OUT,
+		PJ7_IN, PJ7_OUT,
+		PJ6_IN, PJ6_OUT,
+		PJ5_IN, PJ5_OUT,
+		PJ4_IN, PJ4_OUT,
+		PJ3_IN, PJ3_OUT,
+		PJ2_IN, PJ2_OUT,
+		PJ1_IN, PJ1_OUT,
+		PJ0_IN, PJ0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PKCR2", 0xfffe392a, 16, 4) {
+		PK11MD_00, PK11MD_01, PK11MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PK10MD_00, PK10MD_01, PK10MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PK9MD_00, PK9MD_01, PK9MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PK8MD_00, PK8MD_01, PK8MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PKCR1", 0xfffe392c, 16, 4) {
+		PK7MD_00, PK7MD_01, PK7MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PK6MD_00, PK6MD_01, PK6MD_10, 0,  0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PK5MD_00, PK5MD_01, PK5MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PK4MD_00, PK4MD_01, PK4MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PKCR0", 0xfffe392e, 16, 4) {
+		PK3MD_00, PK3MD_01, PK3MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PK2MD_00, PK2MD_01, PK2MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PK1MD_00, PK1MD_01, PK1MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PK0MD_00, PK0MD_01, PK0MD_10, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PKIOR0", 0xfffe3932, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PJ11_IN, PJ11_OUT,
+		PJ10_IN, PJ10_OUT,
+		PJ9_IN, PJ9_OUT,
+		PJ8_IN, PJ8_OUT,
+		PJ7_IN, PJ7_OUT,
+		PJ6_IN, PJ6_OUT,
+		PJ5_IN, PJ5_OUT,
+		PJ4_IN, PJ4_OUT,
+		PJ3_IN, PJ3_OUT,
+		PJ2_IN, PJ2_OUT,
+		PJ1_IN, PJ1_OUT,
+		PJ0_IN, PJ0_OUT }
+	},
+	{}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+	{ PINMUX_DATA_REG("PADR1", 0xfffe3814, 16) {
+		0, 0, 0, 0, 0, 0, 0, PA3_DATA,
+		0, 0, 0, 0, 0, 0, 0, PA2_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
+		0, 0, 0, 0, 0, 0, 0, PA1_DATA,
+		0, 0, 0, 0, 0, 0, 0, PA0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB22_DATA, PB21_DATA, PB20_DATA,
+		PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
+		PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+		PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+		PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+		PB3_DATA, PB2_DATA, PB1_DATA, 0 }
+	},
+
+	{ PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
+		0, 0, 0, 0,
+		0, PC10_DATA, PC9_DATA, PC8_DATA,
+		PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+		PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
+		PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+		PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+		PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+		PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, PE5_DATA, PE4_DATA,
+		PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
+		0, 0, 0, PF12_DATA,
+		PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+		PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+		PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
+		0, 0, 0, 0, 0, 0, 0, PG24_DATA,
+		PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+		PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
+		PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+		PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+		PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+		PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
+	},
+	{ PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
+		0, 0, 0, PJ12_DATA,
+		PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+		PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+		PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
+	},
+	{ PINMUX_DATA_REG("PKDR0", 0xfffe3936, 16) {
+		0, 0, 0, PK12_DATA,
+		PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
+		PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+		PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA }
+	},
+	{ }
+};
+
+static struct pinmux_info sh7264_pinmux_info = {
+	.name = "sh7264_pfc",
+	.reserved_id = PINMUX_RESERVED,
+	.data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
+	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
+	.mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+	.first_gpio = GPIO_PA3,
+	.last_gpio = GPIO_FN_LCD_M_DISP,
+
+	.gpios = pinmux_gpios,
+	.cfg_regs = pinmux_config_regs,
+	.data_regs = pinmux_data_regs,
+
+	.gpio_data = pinmux_data,
+	.gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+	return register_pinmux(&sh7264_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c b/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
new file mode 100644
index 0000000..f25127c
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
@@ -0,0 +1,2800 @@
+/*
+ * SH7269 Pinmux
+ *
+ * Copyright (C) 2012  Renesas Electronics Europe Ltd
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7269.h>
+
+enum {
+	PINMUX_RESERVED = 0,
+
+	PINMUX_DATA_BEGIN,
+	/* Port A */
+	PA1_DATA, PA0_DATA,
+	/* Port B */
+	PB22_DATA, PB21_DATA, PB20_DATA,
+	PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
+	PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+	PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+	PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+	PB3_DATA, PB2_DATA, PB1_DATA,
+	/* Port C */
+	PC8_DATA,
+	PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+	PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+	/* Port D */
+	PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+	PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+	PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+	PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+	/* Port E */
+	PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+	PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+	/* Port F */
+	PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+	PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA,
+	PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+	PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+	PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+	PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+	/* Port G */
+	PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
+	PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+	PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
+	PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+	PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+	PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+	PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+	/* Port H */
+	/* NOTE - Port H does not have a Data Register, but PH Data is
+	   connected to PH Port Register */
+	PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+	PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+	/* Port I - not on device */
+	/* Port J */
+	PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
+	PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
+	PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
+	PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA,
+	PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
+	PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+	PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+	PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
+	PINMUX_DATA_END,
+
+	PINMUX_INPUT_BEGIN,
+	FORCE_IN,
+	/* Port A */
+	PA1_IN, PA0_IN,
+	/* Port B */
+	PB22_IN, PB21_IN, PB20_IN,
+	PB19_IN, PB18_IN, PB17_IN, PB16_IN,
+	PB15_IN, PB14_IN, PB13_IN, PB12_IN,
+	PB11_IN, PB10_IN, PB9_IN, PB8_IN,
+	PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+	PB3_IN, PB2_IN, PB1_IN,
+	/* Port C */
+	PC8_IN,
+	PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+	PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+	/* Port D */
+	PD15_IN, PD14_IN, PD13_IN, PD12_IN,
+	PD11_IN, PD10_IN, PD9_IN, PD8_IN,
+	PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+	PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+	/* Port E */
+	PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+	PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+	/* Port F */
+	PF23_IN, PF22_IN, PF21_IN, PF20_IN,
+	PF19_IN, PF18_IN, PF17_IN, PF16_IN,
+	PF15_IN, PF14_IN, PF13_IN, PF12_IN,
+	PF11_IN, PF10_IN, PF9_IN, PF8_IN,
+	PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+	PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+	/* Port G */
+	PG27_IN, PG26_IN, PG25_IN, PG24_IN,
+	PG23_IN, PG22_IN, PG21_IN, PG20_IN,
+	PG19_IN, PG18_IN, PG17_IN, PG16_IN,
+	PG15_IN, PG14_IN, PG13_IN, PG12_IN,
+	PG11_IN, PG10_IN, PG9_IN, PG8_IN,
+	PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+	PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+	/* Port H - Port H does not have a Data Register */
+	/* Port I - not on device */
+	/* Port J */
+	PJ31_IN, PJ30_IN, PJ29_IN, PJ28_IN,
+	PJ27_IN, PJ26_IN, PJ25_IN, PJ24_IN,
+	PJ23_IN, PJ22_IN, PJ21_IN, PJ20_IN,
+	PJ19_IN, PJ18_IN, PJ17_IN, PJ16_IN,
+	PJ15_IN, PJ14_IN, PJ13_IN, PJ12_IN,
+	PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
+	PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+	PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
+	PINMUX_INPUT_END,
+
+	PINMUX_OUTPUT_BEGIN,
+	FORCE_OUT,
+	/* Port A */
+	PA1_OUT, PA0_OUT,
+	/* Port B */
+	PB22_OUT, PB21_OUT, PB20_OUT,
+	PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
+	PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
+	PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
+	PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+	PB3_OUT, PB2_OUT, PB1_OUT,
+	/* Port C */
+	PC8_OUT,
+	PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+	PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+	/* Port D */
+	PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
+	PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
+	PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+	PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+	/* Port E */
+	PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+	PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+	/* Port F */
+	PF23_OUT, PF22_OUT, PF21_OUT, PF20_OUT,
+	PF19_OUT, PF18_OUT, PF17_OUT, PF16_OUT,
+	PF15_OUT, PF14_OUT, PF13_OUT, PF12_OUT,
+	PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
+	PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+	PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+	/* Port G */
+	PG27_OUT, PG26_OUT, PG25_OUT, PG24_OUT,
+	PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
+	PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
+	PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
+	PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
+	PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+	PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+	/* Port H - Port H does not have a Data Register */
+	/* Port I - not on device */
+	/* Port J */
+	PJ31_OUT, PJ30_OUT, PJ29_OUT, PJ28_OUT,
+	PJ27_OUT, PJ26_OUT, PJ25_OUT, PJ24_OUT,
+	PJ23_OUT, PJ22_OUT, PJ21_OUT, PJ20_OUT,
+	PJ19_OUT, PJ18_OUT, PJ17_OUT, PJ16_OUT,
+	PJ15_OUT, PJ14_OUT, PJ13_OUT, PJ12_OUT,
+	PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
+	PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+	PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
+	PINMUX_OUTPUT_END,
+
+	PINMUX_FUNCTION_BEGIN,
+	/* Port A */
+	PA1_IOR_IN, PA1_IOR_OUT,
+	PA0_IOR_IN, PA0_IOR_OUT,
+
+	/* Port B */
+	PB22_IOR_IN, PB22_IOR_OUT,
+	PB21_IOR_IN, PB21_IOR_OUT,
+	PB20_IOR_IN, PB20_IOR_OUT,
+	PB19_IOR_IN, PB19_IOR_OUT,
+	PB18_IOR_IN, PB18_IOR_OUT,
+	PB17_IOR_IN, PB17_IOR_OUT,
+	PB16_IOR_IN, PB16_IOR_OUT,
+
+	PB15_IOR_IN, PB15_IOR_OUT,
+	PB14_IOR_IN, PB14_IOR_OUT,
+	PB13_IOR_IN, PB13_IOR_OUT,
+	PB12_IOR_IN, PB12_IOR_OUT,
+	PB11_IOR_IN, PB11_IOR_OUT,
+	PB10_IOR_IN, PB10_IOR_OUT,
+	PB9_IOR_IN, PB9_IOR_OUT,
+	PB8_IOR_IN, PB8_IOR_OUT,
+
+	PB7_IOR_IN, PB7_IOR_OUT,
+	PB6_IOR_IN, PB6_IOR_OUT,
+	PB5_IOR_IN, PB5_IOR_OUT,
+	PB4_IOR_IN, PB4_IOR_OUT,
+	PB3_IOR_IN, PB3_IOR_OUT,
+	PB2_IOR_IN, PB2_IOR_OUT,
+	PB1_IOR_IN, PB1_IOR_OUT,
+	PB0_IOR_IN, PB0_IOR_OUT,
+
+	PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
+	PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
+	PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11,
+	PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
+	PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
+	PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
+	PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
+	PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
+	PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
+	PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
+	PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
+	PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
+	PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
+	PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
+	PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
+	PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
+	PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
+	PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
+	PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
+	PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+
+	PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
+	PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
+	PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
+	PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
+
+	PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+	PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+	PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+	PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+
+	PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11,
+	PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11,
+	PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11,
+
+	/* Port C */
+	PC8_IOR_IN, PC8_IOR_OUT,
+	PC7_IOR_IN, PC7_IOR_OUT,
+	PC6_IOR_IN, PC6_IOR_OUT,
+	PC5_IOR_IN, PC5_IOR_OUT,
+	PC4_IOR_IN, PC4_IOR_OUT,
+	PC3_IOR_IN, PC3_IOR_OUT,
+	PC2_IOR_IN, PC2_IOR_OUT,
+	PC1_IOR_IN, PC1_IOR_OUT,
+	PC0_IOR_IN, PC0_IOR_OUT,
+
+	PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
+	PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
+	PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
+	PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
+	PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
+	PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
+	PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
+	PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
+	PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11,
+
+	PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11,
+	PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11,
+	PC1MD_0, PC1MD_1,
+	PC0MD_0, PC0MD_1,
+
+	/* Port D */
+	PD15_IOR_IN, PD15_IOR_OUT,
+	PD14_IOR_IN, PD14_IOR_OUT,
+	PD13_IOR_IN, PD13_IOR_OUT,
+	PD12_IOR_IN, PD12_IOR_OUT,
+	PD11_IOR_IN, PD11_IOR_OUT,
+	PD10_IOR_IN, PD10_IOR_OUT,
+	PD9_IOR_IN, PD9_IOR_OUT,
+	PD8_IOR_IN, PD8_IOR_OUT,
+	PD7_IOR_IN, PD7_IOR_OUT,
+	PD6_IOR_IN, PD6_IOR_OUT,
+	PD5_IOR_IN, PD5_IOR_OUT,
+	PD4_IOR_IN, PD4_IOR_OUT,
+	PD3_IOR_IN, PD3_IOR_OUT,
+	PD2_IOR_IN, PD2_IOR_OUT,
+	PD1_IOR_IN, PD1_IOR_OUT,
+	PD0_IOR_IN, PD0_IOR_OUT,
+
+	PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
+	PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
+	PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
+	PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
+
+	PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
+	PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
+	PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
+	PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
+
+	PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
+	PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
+	PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
+	PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
+
+	PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
+	PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
+	PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
+	PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
+
+	/* Port E */
+	PE7_IOR_IN, PE7_IOR_OUT,
+	PE6_IOR_IN, PE6_IOR_OUT,
+	PE5_IOR_IN, PE5_IOR_OUT,
+	PE4_IOR_IN, PE4_IOR_OUT,
+	PE3_IOR_IN, PE3_IOR_OUT,
+	PE2_IOR_IN, PE2_IOR_OUT,
+	PE1_IOR_IN, PE1_IOR_OUT,
+	PE0_IOR_IN, PE0_IOR_OUT,
+
+	PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11,
+	PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11,
+	PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
+	PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
+
+	PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
+	PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
+	PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
+	PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
+	PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+	PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+	PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
+
+	/* Port F */
+	PF23_IOR_IN, PF23_IOR_OUT,
+	PF22_IOR_IN, PF22_IOR_OUT,
+	PF21_IOR_IN, PF21_IOR_OUT,
+	PF20_IOR_IN, PF20_IOR_OUT,
+	PF19_IOR_IN, PF19_IOR_OUT,
+	PF18_IOR_IN, PF18_IOR_OUT,
+	PF17_IOR_IN, PF17_IOR_OUT,
+	PF16_IOR_IN, PF16_IOR_OUT,
+	PF15_IOR_IN, PF15_IOR_OUT,
+	PF14_IOR_IN, PF14_IOR_OUT,
+	PF13_IOR_IN, PF13_IOR_OUT,
+	PF12_IOR_IN, PF12_IOR_OUT,
+	PF11_IOR_IN, PF11_IOR_OUT,
+	PF10_IOR_IN, PF10_IOR_OUT,
+	PF9_IOR_IN, PF9_IOR_OUT,
+	PF8_IOR_IN, PF8_IOR_OUT,
+	PF7_IOR_IN, PF7_IOR_OUT,
+	PF6_IOR_IN, PF6_IOR_OUT,
+	PF5_IOR_IN, PF5_IOR_OUT,
+	PF4_IOR_IN, PF4_IOR_OUT,
+	PF3_IOR_IN, PF3_IOR_OUT,
+	PF2_IOR_IN, PF2_IOR_OUT,
+	PF1_IOR_IN, PF1_IOR_OUT,
+	PF0_IOR_IN, PF0_IOR_OUT,
+
+	PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
+	PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
+	PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
+	PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
+	PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
+	PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
+	PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
+	PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
+
+	PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
+	PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
+	PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
+	PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
+	PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
+	PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
+	PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
+	PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
+
+	PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
+	PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
+	PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
+	PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
+	PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
+	PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
+	PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+	PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+
+	PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+	PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+	PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+	PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+	PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+	PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+	PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
+	PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
+
+	PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+	PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+	PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+	PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+	PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+	PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+	PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+	PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+
+	PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+	PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+	PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+	PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+	PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+	PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+	PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+	PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+
+	/* Port G */
+	PG27_IOR_IN, PG27_IOR_OUT,
+	PG26_IOR_IN, PG26_IOR_OUT,
+	PG25_IOR_IN, PG25_IOR_OUT,
+	PG24_IOR_IN, PG24_IOR_OUT,
+	PG23_IOR_IN, PG23_IOR_OUT,
+	PG22_IOR_IN, PG22_IOR_OUT,
+	PG21_IOR_IN, PG21_IOR_OUT,
+	PG20_IOR_IN, PG20_IOR_OUT,
+	PG19_IOR_IN, PG19_IOR_OUT,
+	PG18_IOR_IN, PG18_IOR_OUT,
+	PG17_IOR_IN, PG17_IOR_OUT,
+	PG16_IOR_IN, PG16_IOR_OUT,
+	PG15_IOR_IN, PG15_IOR_OUT,
+	PG14_IOR_IN, PG14_IOR_OUT,
+	PG13_IOR_IN, PG13_IOR_OUT,
+	PG12_IOR_IN, PG12_IOR_OUT,
+	PG11_IOR_IN, PG11_IOR_OUT,
+	PG10_IOR_IN, PG10_IOR_OUT,
+	PG9_IOR_IN, PG9_IOR_OUT,
+	PG8_IOR_IN, PG8_IOR_OUT,
+	PG7_IOR_IN, PG7_IOR_OUT,
+	PG6_IOR_IN, PG6_IOR_OUT,
+	PG5_IOR_IN, PG5_IOR_OUT,
+	PG4_IOR_IN, PG4_IOR_OUT,
+	PG3_IOR_IN, PG3_IOR_OUT,
+	PG2_IOR_IN, PG2_IOR_OUT,
+	PG1_IOR_IN, PG1_IOR_OUT,
+	PG0_IOR_IN, PG0_IOR_OUT,
+
+	PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11,
+	PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11,
+	PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11,
+	PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
+
+	PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
+	PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
+	PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
+	PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
+	PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
+	PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
+	PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+	PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+
+	PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+	PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+	PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+	PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+	PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11,
+	PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11,
+
+	PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11,
+	PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11,
+	PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11,
+	PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11,
+
+	PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+	PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+	PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+	PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+	PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+	PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+	PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+	PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+
+	PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
+	PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
+	PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
+	PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
+	PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
+	PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
+	PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
+	PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
+
+	PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
+	PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
+	PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
+	PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
+	PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
+	PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
+	PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+	PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+
+	/* Port H */
+	PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11,
+	PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11,
+	PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11,
+	PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11,
+
+	PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11,
+	PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11,
+	PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11,
+	PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11,
+
+	/* Port I - not on device */
+
+	/* Port J */
+	PJ31_IOR_IN, PJ31_IOR_OUT,
+	PJ30_IOR_IN, PJ30_IOR_OUT,
+	PJ29_IOR_IN, PJ29_IOR_OUT,
+	PJ28_IOR_IN, PJ28_IOR_OUT,
+	PJ27_IOR_IN, PJ27_IOR_OUT,
+	PJ26_IOR_IN, PJ26_IOR_OUT,
+	PJ25_IOR_IN, PJ25_IOR_OUT,
+	PJ24_IOR_IN, PJ24_IOR_OUT,
+	PJ23_IOR_IN, PJ23_IOR_OUT,
+	PJ22_IOR_IN, PJ22_IOR_OUT,
+	PJ21_IOR_IN, PJ21_IOR_OUT,
+	PJ20_IOR_IN, PJ20_IOR_OUT,
+	PJ19_IOR_IN, PJ19_IOR_OUT,
+	PJ18_IOR_IN, PJ18_IOR_OUT,
+	PJ17_IOR_IN, PJ17_IOR_OUT,
+	PJ16_IOR_IN, PJ16_IOR_OUT,
+	PJ15_IOR_IN, PJ15_IOR_OUT,
+	PJ14_IOR_IN, PJ14_IOR_OUT,
+	PJ13_IOR_IN, PJ13_IOR_OUT,
+	PJ12_IOR_IN, PJ12_IOR_OUT,
+	PJ11_IOR_IN, PJ11_IOR_OUT,
+	PJ10_IOR_IN, PJ10_IOR_OUT,
+	PJ9_IOR_IN, PJ9_IOR_OUT,
+	PJ8_IOR_IN, PJ8_IOR_OUT,
+	PJ7_IOR_IN, PJ7_IOR_OUT,
+	PJ6_IOR_IN, PJ6_IOR_OUT,
+	PJ5_IOR_IN, PJ5_IOR_OUT,
+	PJ4_IOR_IN, PJ4_IOR_OUT,
+	PJ3_IOR_IN, PJ3_IOR_OUT,
+	PJ2_IOR_IN, PJ2_IOR_OUT,
+	PJ1_IOR_IN, PJ1_IOR_OUT,
+	PJ0_IOR_IN, PJ0_IOR_OUT,
+
+	PJ31MD_0, PJ31MD_1,
+	PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
+	PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
+	PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
+	PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
+	PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
+	PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
+
+	PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
+	PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
+	PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
+	PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
+	PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
+	PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
+	PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
+	PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
+
+	PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
+	PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
+	PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
+	PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
+	PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
+	PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
+	PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
+	PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
+
+	PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
+	PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
+	PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
+	PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
+	PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
+	PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
+	PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
+	PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
+
+	PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
+	PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
+	PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
+	PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
+	PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
+	PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
+	PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
+	PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
+
+	PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
+	PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
+	PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
+	PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
+	PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
+	PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
+	PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
+	PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
+
+	PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
+	PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
+	PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
+	PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
+	PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
+	PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
+	PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
+	PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
+
+	PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
+	PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
+	PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+	PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+	PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+	PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+	PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+	PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+
+	PINMUX_FUNCTION_END,
+
+	PINMUX_MARK_BEGIN,
+	/* Port H */
+	PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
+	PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
+
+	/* IRQs */
+	IRQ7_PG_MARK, IRQ6_PG_MARK, IRQ5_PG_MARK, IRQ4_PG_MARK,
+	IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PG_MARK, IRQ0_PG_MARK,
+	IRQ7_PF_MARK, IRQ6_PF_MARK, IRQ5_PF_MARK, IRQ4_PF_MARK,
+	IRQ3_PJ_MARK, IRQ2_PJ_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
+	IRQ1_PC_MARK, IRQ0_PC_MARK,
+
+	PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
+	PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
+	PINT7_PH_MARK, PINT6_PH_MARK, PINT5_PH_MARK, PINT4_PH_MARK,
+	PINT3_PH_MARK, PINT2_PH_MARK, PINT1_PH_MARK, PINT0_PH_MARK,
+	PINT7_PJ_MARK, PINT6_PJ_MARK, PINT5_PJ_MARK, PINT4_PJ_MARK,
+	PINT3_PJ_MARK, PINT2_PJ_MARK, PINT1_PJ_MARK, PINT0_PJ_MARK,
+
+	/* SD */
+	SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
+	SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK, SD_CD_MARK,
+
+	/* MMC */
+	MMC_D0_MARK, MMC_D1_MARK, MMC_D2_MARK, MMC_D3_MARK,
+	MMC_D4_MARK, MMC_D5_MARK, MMC_D6_MARK, MMC_D7_MARK,
+	MMC_CLK_MARK, MMC_CMD_MARK, MMC_CD_MARK,
+
+	/* PWM */
+	PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
+	PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
+	PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
+	PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
+
+	/* IEBus */
+	IERXD_MARK, IETXD_MARK,
+
+	/* WDT */
+	WDTOVF_MARK,
+
+	/* DMAC */
+	TEND0_MARK, DACK0_MARK, DREQ0_MARK,
+	TEND1_MARK, DACK1_MARK, DREQ1_MARK,
+
+	/* ADC */
+	ADTRG_MARK,
+
+	/* BSC */
+	A25_MARK, A24_MARK,
+	A23_MARK, A22_MARK, A21_MARK, A20_MARK,
+	A19_MARK, A18_MARK, A17_MARK, A16_MARK,
+	A15_MARK, A14_MARK, A13_MARK, A12_MARK,
+	A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+	A7_MARK, A6_MARK, A5_MARK, A4_MARK,
+	A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+	D31_MARK, D30_MARK, D29_MARK, D28_MARK,
+	D27_MARK, D26_MARK, D25_MARK, D24_MARK,
+	D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+	D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+	D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+	D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+	D7_MARK, D6_MARK, D5_MARK, D4_MARK,
+	D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+	BS_MARK,
+	CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
+	CS5CE1A_MARK,
+	CE2A_MARK, CE2B_MARK,
+	RD_MARK, RDWR_MARK,
+	WE3ICIOWRAHDQMUU_MARK,
+	WE2ICIORDDQMUL_MARK,
+	WE1DQMUWE_MARK,
+	WE0DQML_MARK,
+	RAS_MARK, CAS_MARK, CKE_MARK,
+	WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
+
+	/* TMU */
+	TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
+	TIOC1A_MARK, TIOC1B_MARK,
+	TIOC2A_MARK, TIOC2B_MARK,
+	TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
+	TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
+	TCLKA_MARK, TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
+
+	/* SCIF */
+	SCK0_MARK, RXD0_MARK, TXD0_MARK,
+	SCK1_MARK, RXD1_MARK, TXD1_MARK, RTS1_MARK, CTS1_MARK,
+	SCK2_MARK, RXD2_MARK, TXD2_MARK,
+	SCK3_MARK, RXD3_MARK, TXD3_MARK,
+	SCK4_MARK, RXD4_MARK, TXD4_MARK,
+	SCK5_MARK, RXD5_MARK, TXD5_MARK, RTS5_MARK, CTS5_MARK,
+	SCK6_MARK, RXD6_MARK, TXD6_MARK,
+	SCK7_MARK, RXD7_MARK, TXD7_MARK, RTS7_MARK, CTS7_MARK,
+
+	/* RSPI */
+	MISO0_PB20_MARK, MOSI0_PB19_MARK, SSL00_PB18_MARK, RSPCK0_PB17_MARK,
+	MISO0_PJ19_MARK, MOSI0_PJ18_MARK, SSL00_PJ17_MARK, RSPCK0_PJ16_MARK,
+	MISO1_MARK, MOSI1_MARK, SSL10_MARK, RSPCK1_MARK,
+
+	/* IIC3 */
+	SCL0_MARK, SDA0_MARK,
+	SCL1_MARK, SDA1_MARK,
+	SCL2_MARK, SDA2_MARK,
+	SCL3_MARK, SDA3_MARK,
+
+	/* SSI */
+	SSISCK0_MARK, SSIWS0_MARK, SSITXD0_MARK, SSIRXD0_MARK,
+	SSISCK1_MARK, SSIWS1_MARK, SSIDATA1_MARK,
+	SSISCK2_MARK, SSIWS2_MARK, SSIDATA2_MARK,
+	SSISCK3_MARK, SSIWS3_MARK, SSIDATA3_MARK,
+	SSISCK4_MARK, SSIWS4_MARK, SSIDATA4_MARK,
+	SSISCK5_MARK, SSIWS5_MARK, SSIDATA5_MARK,
+	AUDIO_CLK_MARK,
+	AUDIO_XOUT_MARK,
+
+	/* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+	SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
+
+	/* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+	SPDIF_IN_MARK, SPDIF_OUT_MARK,
+	SPDIF_IN_PJ24_MARK, SPDIF_OUT_PJ25_MARK,
+
+	/* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+	FCE_MARK,
+	FRB_MARK,
+
+	/* CAN */
+	CRX0_MARK, CTX0_MARK,
+	CRX1_MARK, CTX1_MARK,
+	CRX2_MARK, CTX2_MARK,
+	CRX0CRX1_MARK,
+	CRX0CRX1CRX2_MARK,
+	CTX0CTX1CTX2_MARK,
+	CRX1_PJ22_MARK, CTX1_PJ23_MARK,
+	CRX2_PJ20_MARK, CTX2_PJ21_MARK,
+	CRX0CRX1_PJ22_MARK,
+	CRX0CRX1CRX2_PJ20_MARK,
+
+	/* VDC */
+	DV_CLK_MARK,
+	DV_VSYNC_MARK, DV_HSYNC_MARK,
+	DV_DATA23_MARK, DV_DATA22_MARK, DV_DATA21_MARK, DV_DATA20_MARK,
+	DV_DATA19_MARK, DV_DATA18_MARK, DV_DATA17_MARK, DV_DATA16_MARK,
+	DV_DATA15_MARK, DV_DATA14_MARK, DV_DATA13_MARK, DV_DATA12_MARK,
+	DV_DATA11_MARK, DV_DATA10_MARK, DV_DATA9_MARK, DV_DATA8_MARK,
+	DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
+	DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
+	LCD_CLK_MARK, LCD_EXTCLK_MARK,
+	LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
+	LCD_DATA23_MARK, LCD_DATA22_MARK, LCD_DATA21_MARK, LCD_DATA20_MARK,
+	LCD_DATA19_MARK, LCD_DATA18_MARK, LCD_DATA17_MARK, LCD_DATA16_MARK,
+	LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
+	LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
+	LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
+	LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+	LCD_TCON6_MARK, LCD_TCON5_MARK, LCD_TCON4_MARK,
+	LCD_TCON3_MARK, LCD_TCON2_MARK, LCD_TCON1_MARK, LCD_TCON0_MARK,
+	LCD_M_DISP_MARK,
+	PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+	/* Port A */
+	PINMUX_DATA(PA1_DATA, PA1_IN),
+	PINMUX_DATA(PA0_DATA, PA0_IN),
+
+	/* Port B */
+	PINMUX_DATA(PB22_DATA, PB22MD_000, PB22_IN, PB22_OUT),
+	PINMUX_DATA(A22_MARK, PB22MD_001),
+	PINMUX_DATA(CTX2_MARK, PB22MD_010),
+	PINMUX_DATA(IETXD_MARK, PB22MD_011),
+	PINMUX_DATA(CS4_MARK, PB22MD_100),
+
+	PINMUX_DATA(PB21_DATA, PB21MD_00, PB21_IN, PB21_OUT),
+	PINMUX_DATA(A21_MARK, PB21MD_01),
+	PINMUX_DATA(CRX2_MARK, PB21MD_10),
+	PINMUX_DATA(IERXD_MARK, PB21MD_11),
+
+	PINMUX_DATA(A20_MARK, PB20MD_001),
+	PINMUX_DATA(A19_MARK, PB19MD_001),
+	PINMUX_DATA(A18_MARK, PB18MD_001),
+	PINMUX_DATA(A17_MARK, PB17MD_001),
+	PINMUX_DATA(A16_MARK, PB16MD_001),
+	PINMUX_DATA(A15_MARK, PB15MD_001),
+	PINMUX_DATA(A14_MARK, PB14MD_001),
+	PINMUX_DATA(A13_MARK, PB13MD_001),
+	PINMUX_DATA(A12_MARK, PB12MD_01),
+	PINMUX_DATA(A11_MARK, PB11MD_01),
+	PINMUX_DATA(A10_MARK, PB10MD_01),
+	PINMUX_DATA(A9_MARK, PB9MD_01),
+	PINMUX_DATA(A8_MARK, PB8MD_01),
+	PINMUX_DATA(A7_MARK, PB7MD_01),
+	PINMUX_DATA(A6_MARK, PB6MD_01),
+	PINMUX_DATA(A5_MARK, PB5MD_01),
+	PINMUX_DATA(A4_MARK, PB4MD_01),
+	PINMUX_DATA(A3_MARK, PB3MD_01),
+	PINMUX_DATA(A2_MARK, PB2MD_01),
+	PINMUX_DATA(A1_MARK, PB1MD_01),
+
+	/* Port C */
+	PINMUX_DATA(PC8_DATA, PC8MD_000),
+	PINMUX_DATA(CS3_MARK, PC8MD_001),
+	PINMUX_DATA(TXD7_MARK, PC8MD_010),
+	PINMUX_DATA(CTX1_MARK, PC8MD_011),
+
+	PINMUX_DATA(PC7_DATA, PC7MD_000),
+	PINMUX_DATA(CKE_MARK, PC7MD_001),
+	PINMUX_DATA(RXD7_MARK, PC7MD_010),
+	PINMUX_DATA(CRX1_MARK, PC7MD_011),
+	PINMUX_DATA(CRX0CRX1_MARK, PC7MD_100),
+	PINMUX_DATA(IRQ1_PC_MARK, PC7MD_101),
+
+	PINMUX_DATA(PC6_DATA, PC6MD_000),
+	PINMUX_DATA(CAS_MARK, PC6MD_001),
+	PINMUX_DATA(SCK7_MARK, PC6MD_010),
+	PINMUX_DATA(CTX0_MARK, PC6MD_011),
+
+	PINMUX_DATA(PC5_DATA, PC5MD_000),
+	PINMUX_DATA(RAS_MARK, PC5MD_001),
+	PINMUX_DATA(CRX0_MARK, PC5MD_011),
+	PINMUX_DATA(CTX0CTX1CTX2_MARK, PC5MD_100),
+	PINMUX_DATA(IRQ0_PC_MARK, PC5MD_101),
+
+	PINMUX_DATA(PC4_DATA, PC4MD_00),
+	PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_01),
+	PINMUX_DATA(TXD6_MARK, PC4MD_10),
+
+	PINMUX_DATA(PC3_DATA, PC3MD_00),
+	PINMUX_DATA(WE0DQML_MARK, PC3MD_01),
+	PINMUX_DATA(RXD6_MARK, PC3MD_10),
+
+	PINMUX_DATA(PC2_DATA, PC2MD_00),
+	PINMUX_DATA(RDWR_MARK, PC2MD_01),
+	PINMUX_DATA(SCK5_MARK, PC2MD_10),
+
+	PINMUX_DATA(PC1_DATA, PC1MD_0),
+	PINMUX_DATA(RD_MARK, PC1MD_1),
+
+	PINMUX_DATA(PC0_DATA, PC0MD_0),
+	PINMUX_DATA(CS0_MARK, PC0MD_1),
+
+	/* Port D */
+	PINMUX_DATA(D15_MARK, PD15MD_01),
+	PINMUX_DATA(D14_MARK, PD14MD_01),
+
+	PINMUX_DATA(PD13_DATA, PD13MD_00),
+	PINMUX_DATA(D13_MARK, PD13MD_01),
+	PINMUX_DATA(PWM2F_MARK, PD13MD_10),
+
+	PINMUX_DATA(PD12_DATA, PD12MD_00),
+	PINMUX_DATA(D12_MARK, PD12MD_01),
+	PINMUX_DATA(PWM2E_MARK, PD12MD_10),
+
+	PINMUX_DATA(D11_MARK, PD11MD_01),
+	PINMUX_DATA(D10_MARK, PD10MD_01),
+	PINMUX_DATA(D9_MARK, PD9MD_01),
+	PINMUX_DATA(D8_MARK, PD8MD_01),
+	PINMUX_DATA(D7_MARK, PD7MD_01),
+	PINMUX_DATA(D6_MARK, PD6MD_01),
+	PINMUX_DATA(D5_MARK, PD5MD_01),
+	PINMUX_DATA(D4_MARK, PD4MD_01),
+	PINMUX_DATA(D3_MARK, PD3MD_01),
+	PINMUX_DATA(D2_MARK, PD2MD_01),
+	PINMUX_DATA(D1_MARK, PD1MD_01),
+	PINMUX_DATA(D0_MARK, PD0MD_01),
+
+	/* Port E */
+	PINMUX_DATA(PE7_DATA, PE7MD_00),
+	PINMUX_DATA(SDA3_MARK, PE7MD_01),
+	PINMUX_DATA(RXD7_MARK, PE7MD_10),
+
+	PINMUX_DATA(PE6_DATA, PE6MD_00),
+	PINMUX_DATA(SCL3_MARK, PE6MD_01),
+	PINMUX_DATA(RXD6_MARK, PE6MD_10),
+
+	PINMUX_DATA(PE5_DATA, PE5MD_00),
+	PINMUX_DATA(SDA2_MARK, PE5MD_01),
+	PINMUX_DATA(RXD5_MARK, PE5MD_10),
+	PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
+
+	PINMUX_DATA(PE4_DATA, PE4MD_00),
+	PINMUX_DATA(SCL2_MARK, PE4MD_01),
+	PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
+
+	PINMUX_DATA(PE3_DATA, PE3MD_000),
+	PINMUX_DATA(SDA1_MARK, PE3MD_001),
+	PINMUX_DATA(TCLKD_MARK, PE3MD_010),
+	PINMUX_DATA(ADTRG_MARK, PE3MD_011),
+	PINMUX_DATA(DV_HSYNC_MARK, PE3MD_100),
+
+	PINMUX_DATA(PE2_DATA, PE2MD_000),
+	PINMUX_DATA(SCL1_MARK, PE2MD_001),
+	PINMUX_DATA(TCLKD_MARK, PE2MD_010),
+	PINMUX_DATA(IOIS16_MARK, PE2MD_011),
+	PINMUX_DATA(DV_VSYNC_MARK, PE2MD_100),
+
+	PINMUX_DATA(PE1_DATA, PE1MD_000),
+	PINMUX_DATA(SDA0_MARK, PE1MD_001),
+	PINMUX_DATA(TCLKB_MARK, PE1MD_010),
+	PINMUX_DATA(AUDIO_CLK_MARK, PE1MD_010),
+	PINMUX_DATA(DV_CLK_MARK, PE1MD_100),
+
+	PINMUX_DATA(PE0_DATA, PE0MD_00),
+	PINMUX_DATA(SCL0_MARK, PE0MD_01),
+	PINMUX_DATA(TCLKA_MARK, PE0MD_10),
+	PINMUX_DATA(LCD_EXTCLK_MARK, PE0MD_11),
+
+	/* Port F */
+	PINMUX_DATA(PF23_DATA, PF23MD_000),
+	PINMUX_DATA(SD_D2_MARK, PF23MD_001),
+	PINMUX_DATA(TXD3_MARK, PF23MD_100),
+	PINMUX_DATA(MMC_D2_MARK, PF23MD_101),
+
+	PINMUX_DATA(PF22_DATA, PF22MD_000),
+	PINMUX_DATA(SD_D3_MARK, PF22MD_001),
+	PINMUX_DATA(RXD3_MARK, PF22MD_100),
+	PINMUX_DATA(MMC_D3_MARK, PF22MD_101),
+
+	PINMUX_DATA(PF21_DATA, PF21MD_000),
+	PINMUX_DATA(SD_CMD_MARK, PF21MD_001),
+	PINMUX_DATA(SCK3_MARK, PF21MD_100),
+	PINMUX_DATA(MMC_CMD_MARK, PF21MD_101),
+
+	PINMUX_DATA(PF20_DATA, PF20MD_000),
+	PINMUX_DATA(SD_CLK_MARK, PF20MD_001),
+	PINMUX_DATA(SSIDATA3_MARK, PF20MD_010),
+	PINMUX_DATA(MMC_CLK_MARK, PF20MD_101),
+
+	PINMUX_DATA(PF19_DATA, PF19MD_000),
+	PINMUX_DATA(SD_D0_MARK, PF19MD_001),
+	PINMUX_DATA(SSIWS3_MARK, PF19MD_010),
+	PINMUX_DATA(IRQ7_PF_MARK, PF19MD_100),
+	PINMUX_DATA(MMC_D0_MARK, PF19MD_101),
+
+	PINMUX_DATA(PF18_DATA, PF18MD_000),
+	PINMUX_DATA(SD_D1_MARK, PF18MD_001),
+	PINMUX_DATA(SSISCK3_MARK, PF18MD_010),
+	PINMUX_DATA(IRQ6_PF_MARK, PF18MD_100),
+	PINMUX_DATA(MMC_D1_MARK, PF18MD_101),
+
+	PINMUX_DATA(PF17_DATA, PF17MD_000),
+	PINMUX_DATA(SD_WP_MARK, PF17MD_001),
+	PINMUX_DATA(FRB_MARK, PF17MD_011),
+	PINMUX_DATA(IRQ5_PF_MARK, PF17MD_100),
+
+	PINMUX_DATA(PF16_DATA, PF16MD_000),
+	PINMUX_DATA(SD_CD_MARK, PF16MD_001),
+	PINMUX_DATA(FCE_MARK, PF16MD_011),
+	PINMUX_DATA(IRQ4_PF_MARK, PF16MD_100),
+	PINMUX_DATA(MMC_CD_MARK, PF16MD_101),
+
+	PINMUX_DATA(PF15_DATA, PF15MD_000),
+	PINMUX_DATA(A0_MARK, PF15MD_001),
+	PINMUX_DATA(SSIDATA2_MARK, PF15MD_010),
+	PINMUX_DATA(WDTOVF_MARK, PF15MD_011),
+	PINMUX_DATA(TXD2_MARK, PF15MD_100),
+
+	PINMUX_DATA(PF14_DATA, PF14MD_000),
+	PINMUX_DATA(A25_MARK, PF14MD_001),
+	PINMUX_DATA(SSIWS2_MARK, PF14MD_010),
+	PINMUX_DATA(RXD2_MARK, PF14MD_100),
+
+	PINMUX_DATA(PF13_DATA, PF13MD_000),
+	PINMUX_DATA(A24_MARK, PF13MD_001),
+	PINMUX_DATA(SSISCK2_MARK, PF13MD_010),
+	PINMUX_DATA(SCK2_MARK, PF13MD_100),
+
+	PINMUX_DATA(PF12_DATA, PF12MD_000),
+	PINMUX_DATA(SSIDATA1_MARK, PF12MD_010),
+	PINMUX_DATA(DV_DATA12_MARK, PF12MD_011),
+	PINMUX_DATA(TXD1_MARK, PF12MD_100),
+	PINMUX_DATA(MMC_D7_MARK, PF12MD_101),
+
+	PINMUX_DATA(PF11_DATA, PF11MD_000),
+	PINMUX_DATA(SSIWS1_MARK, PF11MD_010),
+	PINMUX_DATA(DV_DATA2_MARK, PF11MD_011),
+	PINMUX_DATA(RXD1_MARK, PF11MD_100),
+	PINMUX_DATA(MMC_D6_MARK, PF11MD_101),
+
+	PINMUX_DATA(PF10_DATA, PF10MD_000),
+	PINMUX_DATA(CS1_MARK, PF10MD_001),
+	PINMUX_DATA(SSISCK1_MARK, PF10MD_010),
+	PINMUX_DATA(DV_DATA1_MARK, PF10MD_011),
+	PINMUX_DATA(SCK1_MARK, PF10MD_100),
+	PINMUX_DATA(MMC_D5_MARK, PF10MD_101),
+
+	PINMUX_DATA(PF9_DATA, PF9MD_000),
+	PINMUX_DATA(BS_MARK, PF9MD_001),
+	PINMUX_DATA(DV_DATA0_MARK, PF9MD_011),
+	PINMUX_DATA(SCK0_MARK, PF9MD_100),
+	PINMUX_DATA(MMC_D4_MARK, PF9MD_101),
+	PINMUX_DATA(RTS1_MARK, PF9MD_110),
+
+	PINMUX_DATA(PF8_DATA, PF8MD_000),
+	PINMUX_DATA(A23_MARK, PF8MD_001),
+	PINMUX_DATA(TXD0_MARK, PF8MD_100),
+
+	PINMUX_DATA(PF7_DATA, PF7MD_000),
+	PINMUX_DATA(SSIRXD0_MARK, PF7MD_010),
+	PINMUX_DATA(RXD0_MARK, PF7MD_100),
+	PINMUX_DATA(CTS1_MARK, PF7MD_110),
+
+	PINMUX_DATA(PF6_DATA, PF6MD_000),
+	PINMUX_DATA(CE2A_MARK, PF6MD_001),
+	PINMUX_DATA(SSITXD0_MARK, PF6MD_010),
+
+	PINMUX_DATA(PF5_DATA, PF5MD_000),
+	PINMUX_DATA(SSIWS0_MARK, PF5MD_010),
+
+	PINMUX_DATA(PF4_DATA, PF4MD_000),
+	PINMUX_DATA(CS5CE1A_MARK, PF4MD_001),
+	PINMUX_DATA(SSISCK0_MARK, PF4MD_010),
+
+	PINMUX_DATA(PF3_DATA, PF3MD_000),
+	PINMUX_DATA(CS2_MARK, PF3MD_001),
+	PINMUX_DATA(MISO1_MARK, PF3MD_011),
+	PINMUX_DATA(TIOC4D_MARK, PF3MD_100),
+
+	PINMUX_DATA(PF2_DATA, PF2MD_000),
+	PINMUX_DATA(WAIT_MARK, PF2MD_001),
+	PINMUX_DATA(MOSI1_MARK, PF2MD_011),
+	PINMUX_DATA(TIOC4C_MARK, PF2MD_100),
+	PINMUX_DATA(TEND0_MARK, PF2MD_101),
+
+	PINMUX_DATA(PF1_DATA, PF1MD_000),
+	PINMUX_DATA(BACK_MARK, PF1MD_001),
+	PINMUX_DATA(TIOC4B_MARK, PF1MD_100),
+	PINMUX_DATA(DACK0_MARK, PF1MD_101),
+
+	PINMUX_DATA(PF0_DATA, PF0MD_000),
+	PINMUX_DATA(BREQ_MARK, PF0MD_001),
+	PINMUX_DATA(RSPCK1_MARK, PF0MD_011),
+	PINMUX_DATA(TIOC4A_MARK, PF0MD_100),
+	PINMUX_DATA(DREQ0_MARK, PF0MD_101),
+
+	/* Port G */
+	PINMUX_DATA(PG27_DATA, PG27MD_00),
+	PINMUX_DATA(LCD_TCON2_MARK, PG27MD_10),
+	PINMUX_DATA(LCD_EXTCLK_MARK, PG27MD_11),
+
+	PINMUX_DATA(PG26_DATA, PG26MD_00),
+	PINMUX_DATA(LCD_TCON1_MARK, PG26MD_10),
+
+	PINMUX_DATA(PG25_DATA, PG25MD_00),
+	PINMUX_DATA(LCD_TCON0_MARK, PG25MD_10),
+
+	PINMUX_DATA(PG24_DATA, PG24MD_00),
+	PINMUX_DATA(LCD_CLK_MARK, PG24MD_10),
+
+	PINMUX_DATA(PG23_DATA, PG23MD_000),
+	PINMUX_DATA(LCD_DATA23_MARK, PG23MD_010),
+	PINMUX_DATA(LCD_TCON6_MARK, PG23MD_011),
+	PINMUX_DATA(TXD5_MARK, PG23MD_100),
+
+	PINMUX_DATA(PG22_DATA, PG22MD_000),
+	PINMUX_DATA(LCD_DATA22_MARK, PG22MD_010),
+	PINMUX_DATA(LCD_TCON5_MARK, PG22MD_011),
+	PINMUX_DATA(RXD5_MARK, PG22MD_100),
+
+	PINMUX_DATA(PG21_DATA, PG21MD_000),
+	PINMUX_DATA(DV_DATA7_MARK, PG21MD_001),
+	PINMUX_DATA(LCD_DATA21_MARK, PG21MD_010),
+	PINMUX_DATA(LCD_TCON4_MARK, PG21MD_011),
+	PINMUX_DATA(TXD4_MARK, PG21MD_100),
+
+	PINMUX_DATA(PG20_DATA, PG20MD_000),
+	PINMUX_DATA(DV_DATA6_MARK, PG20MD_001),
+	PINMUX_DATA(LCD_DATA20_MARK, PG21MD_010),
+	PINMUX_DATA(LCD_TCON3_MARK, PG20MD_011),
+	PINMUX_DATA(RXD4_MARK, PG20MD_100),
+
+	PINMUX_DATA(PG19_DATA, PG19MD_000),
+	PINMUX_DATA(DV_DATA5_MARK, PG19MD_001),
+	PINMUX_DATA(LCD_DATA19_MARK, PG19MD_010),
+	PINMUX_DATA(SPDIF_OUT_MARK, PG19MD_011),
+	PINMUX_DATA(SCK5_MARK, PG19MD_100),
+
+	PINMUX_DATA(PG18_DATA, PG18MD_000),
+	PINMUX_DATA(DV_DATA4_MARK, PG18MD_001),
+	PINMUX_DATA(LCD_DATA18_MARK, PG18MD_010),
+	PINMUX_DATA(SPDIF_IN_MARK, PG18MD_011),
+	PINMUX_DATA(SCK4_MARK, PG18MD_100),
+
+// TODO hardware manual has PG17 3 bits wide in reg picture and 2 bits in description
+// we're going with 2 bits
+	PINMUX_DATA(PG17_DATA, PG17MD_00),
+	PINMUX_DATA(WE3ICIOWRAHDQMUU_MARK, PG17MD_01),
+	PINMUX_DATA(LCD_DATA17_MARK, PG17MD_10),
+
+// TODO hardware manual has PG16 3 bits wide in reg picture and 2 bits in description
+// we're going with 2 bits
+	PINMUX_DATA(PG16_DATA, PG16MD_00),
+	PINMUX_DATA(WE2ICIORDDQMUL_MARK, PG16MD_01),
+	PINMUX_DATA(LCD_DATA16_MARK, PG16MD_10),
+
+	PINMUX_DATA(PG15_DATA, PG15MD_00),
+	PINMUX_DATA(D31_MARK, PG15MD_01),
+	PINMUX_DATA(LCD_DATA15_MARK, PG15MD_10),
+	PINMUX_DATA(PINT7_PG_MARK, PG15MD_11),
+
+	PINMUX_DATA(PG14_DATA, PG14MD_00),
+	PINMUX_DATA(D30_MARK, PG14MD_01),
+	PINMUX_DATA(LCD_DATA14_MARK, PG14MD_10),
+	PINMUX_DATA(PINT6_PG_MARK, PG14MD_11),
+
+	PINMUX_DATA(PG13_DATA, PG13MD_00),
+	PINMUX_DATA(D29_MARK, PG13MD_01),
+	PINMUX_DATA(LCD_DATA13_MARK, PG13MD_10),
+	PINMUX_DATA(PINT5_PG_MARK, PG13MD_11),
+
+	PINMUX_DATA(PG12_DATA, PG12MD_00),
+	PINMUX_DATA(D28_MARK, PG12MD_01),
+	PINMUX_DATA(LCD_DATA12_MARK, PG12MD_10),
+	PINMUX_DATA(PINT4_PG_MARK, PG12MD_11),
+
+	PINMUX_DATA(PG11_DATA, PG11MD_000),
+	PINMUX_DATA(D27_MARK, PG11MD_001),
+	PINMUX_DATA(LCD_DATA11_MARK, PG11MD_010),
+	PINMUX_DATA(PINT3_PG_MARK, PG11MD_011),
+	PINMUX_DATA(TIOC3D_MARK, PG11MD_100),
+
+	PINMUX_DATA(PG10_DATA, PG10MD_000),
+	PINMUX_DATA(D26_MARK, PG10MD_001),
+	PINMUX_DATA(LCD_DATA10_MARK, PG10MD_010),
+	PINMUX_DATA(PINT2_PG_MARK, PG10MD_011),
+	PINMUX_DATA(TIOC3C_MARK, PG10MD_100),
+
+	PINMUX_DATA(PG9_DATA, PG9MD_000),
+	PINMUX_DATA(D25_MARK, PG9MD_001),
+	PINMUX_DATA(LCD_DATA9_MARK, PG9MD_010),
+	PINMUX_DATA(PINT1_PG_MARK, PG9MD_011),
+	PINMUX_DATA(TIOC3B_MARK, PG9MD_100),
+
+	PINMUX_DATA(PG8_DATA, PG8MD_000),
+	PINMUX_DATA(D24_MARK, PG8MD_001),
+	PINMUX_DATA(LCD_DATA8_MARK, PG8MD_010),
+	PINMUX_DATA(PINT0_PG_MARK, PG8MD_011),
+	PINMUX_DATA(TIOC3A_MARK, PG8MD_100),
+
+	PINMUX_DATA(PG7_DATA, PG7MD_000),
+	PINMUX_DATA(D23_MARK, PG7MD_001),
+	PINMUX_DATA(LCD_DATA7_MARK, PG7MD_010),
+	PINMUX_DATA(IRQ7_PG_MARK, PG7MD_011),
+	PINMUX_DATA(TIOC2B_MARK, PG7MD_100),
+
+	PINMUX_DATA(PG6_DATA, PG6MD_000),
+	PINMUX_DATA(D22_MARK, PG6MD_001),
+	PINMUX_DATA(LCD_DATA6_MARK, PG6MD_010),
+	PINMUX_DATA(IRQ6_PG_MARK, PG6MD_011),
+	PINMUX_DATA(TIOC2A_MARK, PG6MD_100),
+
+	PINMUX_DATA(PG5_DATA, PG5MD_000),
+	PINMUX_DATA(D21_MARK, PG5MD_001),
+	PINMUX_DATA(LCD_DATA5_MARK, PG5MD_010),
+	PINMUX_DATA(IRQ5_PG_MARK, PG5MD_011),
+	PINMUX_DATA(TIOC1B_MARK, PG5MD_100),
+
+	PINMUX_DATA(PG4_DATA, PG4MD_000),
+	PINMUX_DATA(D20_MARK, PG4MD_001),
+	PINMUX_DATA(LCD_DATA4_MARK, PG4MD_010),
+	PINMUX_DATA(IRQ4_PG_MARK, PG4MD_011),
+	PINMUX_DATA(TIOC1A_MARK, PG4MD_100),
+
+	PINMUX_DATA(PG3_DATA, PG3MD_000),
+	PINMUX_DATA(D19_MARK, PG3MD_001),
+	PINMUX_DATA(LCD_DATA3_MARK, PG3MD_010),
+	PINMUX_DATA(IRQ3_PG_MARK, PG3MD_011),
+	PINMUX_DATA(TIOC0D_MARK, PG3MD_100),
+
+	PINMUX_DATA(PG2_DATA, PG2MD_000),
+	PINMUX_DATA(D18_MARK, PG2MD_001),
+	PINMUX_DATA(LCD_DATA2_MARK, PG2MD_010),
+	PINMUX_DATA(IRQ2_PG_MARK, PG2MD_011),
+	PINMUX_DATA(TIOC0C_MARK, PG2MD_100),
+
+	PINMUX_DATA(PG1_DATA, PG1MD_000),
+	PINMUX_DATA(D17_MARK, PG1MD_001),
+	PINMUX_DATA(LCD_DATA1_MARK, PG1MD_010),
+	PINMUX_DATA(IRQ1_PG_MARK, PG1MD_011),
+	PINMUX_DATA(TIOC0B_MARK, PG1MD_100),
+
+	PINMUX_DATA(PG0_DATA, PG0MD_000),
+	PINMUX_DATA(D16_MARK, PG0MD_001),
+	PINMUX_DATA(LCD_DATA0_MARK, PG0MD_010),
+	PINMUX_DATA(IRQ0_PG_MARK, PG0MD_011),
+	PINMUX_DATA(TIOC0A_MARK, PG0MD_100),
+
+	/* Port H */
+	PINMUX_DATA(PH7_DATA, PH7MD_00),
+	PINMUX_DATA(PHAN7_MARK, PH7MD_01),
+	PINMUX_DATA(PINT7_PH_MARK, PH7MD_10),
+
+	PINMUX_DATA(PH6_DATA, PH6MD_00),
+	PINMUX_DATA(PHAN6_MARK, PH6MD_01),
+	PINMUX_DATA(PINT6_PH_MARK, PH6MD_10),
+
+	PINMUX_DATA(PH5_DATA, PH5MD_00),
+	PINMUX_DATA(PHAN5_MARK, PH5MD_01),
+	PINMUX_DATA(PINT5_PH_MARK, PH5MD_10),
+	PINMUX_DATA(LCD_EXTCLK_MARK, PH5MD_11),
+
+	PINMUX_DATA(PH4_DATA, PH4MD_00),
+	PINMUX_DATA(PHAN4_MARK, PH4MD_01),
+	PINMUX_DATA(PINT4_PH_MARK, PH4MD_10),
+
+	PINMUX_DATA(PH3_DATA, PH3MD_00),
+	PINMUX_DATA(PHAN3_MARK, PH3MD_01),
+	PINMUX_DATA(PINT3_PH_MARK, PH3MD_10),
+
+	PINMUX_DATA(PH2_DATA, PH2MD_00),
+	PINMUX_DATA(PHAN2_MARK, PH2MD_01),
+	PINMUX_DATA(PINT2_PH_MARK, PH2MD_10),
+
+	PINMUX_DATA(PH1_DATA, PH1MD_00),
+	PINMUX_DATA(PHAN1_MARK, PH1MD_01),
+	PINMUX_DATA(PINT1_PH_MARK, PH1MD_10),
+
+	PINMUX_DATA(PH0_DATA, PH0MD_00),
+	PINMUX_DATA(PHAN0_MARK, PH0MD_01),
+	PINMUX_DATA(PINT0_PH_MARK, PH0MD_10),
+
+	/* Port I - not on device */
+
+	/* Port J */
+	PINMUX_DATA(PJ31_DATA, PJ31MD_0),
+	PINMUX_DATA(DV_CLK_MARK, PJ31MD_1),
+
+	PINMUX_DATA(PJ30_DATA, PJ30MD_000),
+	PINMUX_DATA(SSIDATA5_MARK, PJ30MD_010),
+	PINMUX_DATA(TIOC2B_MARK, PJ30MD_100),
+	PINMUX_DATA(IETXD_MARK, PJ30MD_101),
+
+	PINMUX_DATA(PJ29_DATA, PJ29MD_000),
+	PINMUX_DATA(SSIWS5_MARK, PJ29MD_010),
+	PINMUX_DATA(TIOC2A_MARK, PJ29MD_100),
+	PINMUX_DATA(IERXD_MARK, PJ29MD_101),
+
+	PINMUX_DATA(PJ28_DATA, PJ28MD_000),
+	PINMUX_DATA(SSISCK5_MARK, PJ28MD_010),
+	PINMUX_DATA(TIOC1B_MARK, PJ28MD_100),
+	PINMUX_DATA(RTS7_MARK, PJ28MD_101),
+
+	PINMUX_DATA(PJ27_DATA, PJ27MD_000),
+	PINMUX_DATA(TIOC1A_MARK, PJ27MD_100),
+	PINMUX_DATA(CTS7_MARK, PJ27MD_101),
+
+	PINMUX_DATA(PJ26_DATA, PJ26MD_000),
+	PINMUX_DATA(SSIDATA4_MARK, PJ26MD_010),
+	PINMUX_DATA(LCD_TCON5_MARK, PJ26MD_011),
+	PINMUX_DATA(TXD7_MARK, PJ26MD_101),
+
+	PINMUX_DATA(PJ25_DATA, PJ25MD_000),
+	PINMUX_DATA(SSIWS4_MARK, PJ25MD_010),
+	PINMUX_DATA(LCD_TCON4_MARK, PJ25MD_011),
+	PINMUX_DATA(SPDIF_OUT_MARK, PJ25MD_100),
+	PINMUX_DATA(RXD7_MARK, PJ25MD_101),
+
+	PINMUX_DATA(PJ24_DATA, PJ24MD_000),
+	PINMUX_DATA(SSISCK4_MARK, PJ24MD_010),
+	PINMUX_DATA(LCD_TCON3_MARK, PJ24MD_011),
+	PINMUX_DATA(SPDIF_IN_MARK, PJ24MD_100),
+	PINMUX_DATA(SCK7_MARK, PJ24MD_101),
+
+	PINMUX_DATA(PJ23_DATA, PJ23MD_000),
+	PINMUX_DATA(DV_DATA23_MARK, PJ23MD_001),
+	PINMUX_DATA(LCD_DATA23_MARK, PJ23MD_010),
+	PINMUX_DATA(LCD_TCON6_MARK, PJ23MD_011),
+	PINMUX_DATA(IRQ3_PJ_MARK, PJ23MD_100),
+	PINMUX_DATA(CTX1_MARK, PJ23MD_101),
+
+	PINMUX_DATA(PJ22_DATA, PJ22MD_000),
+	PINMUX_DATA(DV_DATA22_MARK, PJ22MD_001),
+	PINMUX_DATA(LCD_DATA22_MARK, PJ22MD_010),
+	PINMUX_DATA(LCD_TCON5_MARK, PJ22MD_011),
+	PINMUX_DATA(IRQ2_PJ_MARK, PJ22MD_100),
+	PINMUX_DATA(CRX1_MARK, PJ22MD_101),
+	PINMUX_DATA(CRX0CRX1_MARK, PJ22MD_110),
+
+	PINMUX_DATA(PJ21_DATA, PJ21MD_000),
+	PINMUX_DATA(DV_DATA21_MARK, PJ21MD_001),
+	PINMUX_DATA(LCD_DATA21_MARK, PJ21MD_010),
+	PINMUX_DATA(LCD_TCON4_MARK, PJ21MD_011),
+	PINMUX_DATA(IRQ1_PJ_MARK, PJ21MD_100),
+	PINMUX_DATA(CTX2_MARK, PJ21MD_101),
+
+	PINMUX_DATA(PJ20_DATA, PJ20MD_000),
+	PINMUX_DATA(DV_DATA20_MARK, PJ20MD_001),
+	PINMUX_DATA(LCD_DATA20_MARK, PJ20MD_010),
+	PINMUX_DATA(LCD_TCON3_MARK, PJ20MD_011),
+	PINMUX_DATA(IRQ0_PJ_MARK, PJ20MD_100),
+	PINMUX_DATA(CRX2_MARK, PJ20MD_101),
+	PINMUX_DATA(CRX0CRX1CRX2_PJ20_MARK, PJ20MD_110),
+
+	PINMUX_DATA(PJ19_DATA, PJ19MD_000),
+	PINMUX_DATA(DV_DATA19_MARK, PJ19MD_001),
+	PINMUX_DATA(LCD_DATA19_MARK, PJ19MD_010),
+	PINMUX_DATA(MISO0_PJ19_MARK, PJ19MD_011),
+	PINMUX_DATA(TIOC0D_MARK, PJ19MD_100),
+	PINMUX_DATA(SIOFRXD_MARK, PJ19MD_101),
+	PINMUX_DATA(AUDIO_XOUT_MARK, PJ19MD_110),
+
+	PINMUX_DATA(PJ18_DATA, PJ18MD_000),
+	PINMUX_DATA(DV_DATA18_MARK, PJ18MD_001),
+	PINMUX_DATA(LCD_DATA18_MARK, PJ18MD_010),
+	PINMUX_DATA(MOSI0_PJ18_MARK, PJ18MD_011),
+	PINMUX_DATA(TIOC0C_MARK, PJ18MD_100),
+	PINMUX_DATA(SIOFTXD_MARK, PJ18MD_101),
+
+	PINMUX_DATA(PJ17_DATA, PJ17MD_000),
+	PINMUX_DATA(DV_DATA17_MARK, PJ17MD_001),
+	PINMUX_DATA(LCD_DATA17_MARK, PJ17MD_010),
+	PINMUX_DATA(SSL00_PJ17_MARK, PJ17MD_011),
+	PINMUX_DATA(TIOC0B_MARK, PJ17MD_100),
+	PINMUX_DATA(SIOFSYNC_MARK, PJ17MD_101),
+
+	PINMUX_DATA(PJ16_DATA, PJ16MD_000),
+	PINMUX_DATA(DV_DATA16_MARK, PJ16MD_001),
+	PINMUX_DATA(LCD_DATA16_MARK, PJ16MD_010),
+	PINMUX_DATA(RSPCK0_PJ16_MARK, PJ16MD_011),
+	PINMUX_DATA(TIOC0A_MARK, PJ16MD_100),
+	PINMUX_DATA(SIOFSCK_MARK, PJ16MD_101),
+
+	PINMUX_DATA(PJ15_DATA, PJ15MD_000),
+	PINMUX_DATA(DV_DATA15_MARK, PJ15MD_001),
+	PINMUX_DATA(LCD_DATA15_MARK, PJ15MD_010),
+	PINMUX_DATA(PINT7_PJ_MARK, PJ15MD_011),
+	PINMUX_DATA(PWM2H_MARK, PJ15MD_100),
+	PINMUX_DATA(TXD7_MARK, PJ15MD_101),
+
+	PINMUX_DATA(PJ14_DATA, PJ14MD_000),
+	PINMUX_DATA(DV_DATA14_MARK, PJ14MD_001),
+	PINMUX_DATA(LCD_DATA14_MARK, PJ14MD_010),
+	PINMUX_DATA(PINT6_PJ_MARK, PJ14MD_011),
+	PINMUX_DATA(PWM2G_MARK, PJ14MD_100),
+	PINMUX_DATA(TXD6_MARK, PJ14MD_101),
+
+	PINMUX_DATA(PJ13_DATA, PJ13MD_000),
+	PINMUX_DATA(DV_DATA13_MARK, PJ13MD_001),
+	PINMUX_DATA(LCD_DATA13_MARK, PJ13MD_010),
+	PINMUX_DATA(PINT5_PJ_MARK, PJ13MD_011),
+	PINMUX_DATA(PWM2F_MARK, PJ13MD_100),
+	PINMUX_DATA(TXD5_MARK, PJ13MD_101),
+
+	PINMUX_DATA(PJ12_DATA, PJ12MD_000),
+	PINMUX_DATA(DV_DATA12_MARK, PJ12MD_001),
+	PINMUX_DATA(LCD_DATA12_MARK, PJ12MD_010),
+	PINMUX_DATA(PINT4_PJ_MARK, PJ12MD_011),
+	PINMUX_DATA(PWM2E_MARK, PJ12MD_100),
+	PINMUX_DATA(SCK7_MARK, PJ12MD_101),
+
+	PINMUX_DATA(PJ11_DATA, PJ11MD_000),
+	PINMUX_DATA(DV_DATA11_MARK, PJ11MD_001),
+	PINMUX_DATA(LCD_DATA11_MARK, PJ11MD_010),
+	PINMUX_DATA(PINT3_PJ_MARK, PJ11MD_011),
+	PINMUX_DATA(PWM2D_MARK, PJ11MD_100),
+	PINMUX_DATA(SCK6_MARK, PJ11MD_101),
+
+	PINMUX_DATA(PJ10_DATA, PJ10MD_000),
+	PINMUX_DATA(DV_DATA10_MARK, PJ10MD_001),
+	PINMUX_DATA(LCD_DATA10_MARK, PJ10MD_010),
+	PINMUX_DATA(PINT2_PJ_MARK, PJ10MD_011),
+	PINMUX_DATA(PWM2C_MARK, PJ10MD_100),
+	PINMUX_DATA(SCK5_MARK, PJ10MD_101),
+
+	PINMUX_DATA(PJ9_DATA, PJ9MD_000),
+	PINMUX_DATA(DV_DATA9_MARK, PJ9MD_001),
+	PINMUX_DATA(LCD_DATA9_MARK, PJ9MD_010),
+	PINMUX_DATA(PINT1_PJ_MARK, PJ9MD_011),
+	PINMUX_DATA(PWM2B_MARK, PJ9MD_100),
+	PINMUX_DATA(RTS5_MARK, PJ9MD_101),
+
+	PINMUX_DATA(PJ8_DATA, PJ8MD_000),
+	PINMUX_DATA(DV_DATA8_MARK, PJ8MD_001),
+	PINMUX_DATA(LCD_DATA8_MARK, PJ8MD_010),
+	PINMUX_DATA(PINT0_PJ_MARK, PJ8MD_011),
+	PINMUX_DATA(PWM2A_MARK, PJ8MD_100),
+	PINMUX_DATA(CTS5_MARK, PJ8MD_101),
+
+	PINMUX_DATA(PJ7_DATA, PJ7MD_000),
+	PINMUX_DATA(DV_DATA7_MARK, PJ7MD_001),
+	PINMUX_DATA(LCD_DATA7_MARK, PJ7MD_010),
+	PINMUX_DATA(SD_D2_MARK, PJ7MD_011),
+	PINMUX_DATA(PWM1H_MARK, PJ7MD_100),
+
+	PINMUX_DATA(PJ6_DATA, PJ6MD_000),
+	PINMUX_DATA(DV_DATA6_MARK, PJ6MD_001),
+	PINMUX_DATA(LCD_DATA6_MARK, PJ6MD_010),
+	PINMUX_DATA(SD_D3_MARK, PJ6MD_011),
+	PINMUX_DATA(PWM1G_MARK, PJ6MD_100),
+
+	PINMUX_DATA(PJ5_DATA, PJ5MD_000),
+	PINMUX_DATA(DV_DATA5_MARK, PJ5MD_001),
+	PINMUX_DATA(LCD_DATA5_MARK, PJ5MD_010),
+	PINMUX_DATA(SD_CMD_MARK, PJ5MD_011),
+	PINMUX_DATA(PWM1F_MARK, PJ5MD_100),
+
+	PINMUX_DATA(PJ4_DATA, PJ4MD_000),
+	PINMUX_DATA(DV_DATA4_MARK, PJ4MD_001),
+	PINMUX_DATA(LCD_DATA4_MARK, PJ4MD_010),
+	PINMUX_DATA(SD_CLK_MARK, PJ4MD_011),
+	PINMUX_DATA(PWM1E_MARK, PJ4MD_100),
+
+	PINMUX_DATA(PJ3_DATA, PJ3MD_000),
+	PINMUX_DATA(DV_DATA3_MARK, PJ3MD_001),
+	PINMUX_DATA(LCD_DATA3_MARK, PJ3MD_010),
+	PINMUX_DATA(SD_D0_MARK, PJ3MD_011),
+	PINMUX_DATA(PWM1D_MARK, PJ3MD_100),
+
+	PINMUX_DATA(PJ2_DATA, PJ2MD_000),
+	PINMUX_DATA(DV_DATA2_MARK, PJ2MD_001),
+	PINMUX_DATA(LCD_DATA2_MARK, PJ2MD_010),
+	PINMUX_DATA(SD_D1_MARK, PJ2MD_011),
+	PINMUX_DATA(PWM1C_MARK, PJ2MD_100),
+
+	PINMUX_DATA(PJ1_DATA, PJ1MD_000),
+	PINMUX_DATA(DV_DATA1_MARK, PJ1MD_001),
+	PINMUX_DATA(LCD_DATA1_MARK, PJ1MD_010),
+	PINMUX_DATA(SD_WP_MARK, PJ1MD_011),
+	PINMUX_DATA(PWM1B_MARK, PJ1MD_100),
+
+	PINMUX_DATA(PJ0_DATA, PJ0MD_000),
+	PINMUX_DATA(DV_DATA0_MARK, PJ0MD_001),
+	PINMUX_DATA(LCD_DATA0_MARK, PJ0MD_010),
+	PINMUX_DATA(SD_CD_MARK, PJ0MD_011),
+	PINMUX_DATA(PWM1A_MARK, PJ0MD_100),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+	/* Port A */
+	PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+	PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+	/* Port B */
+	PINMUX_GPIO(GPIO_PB22, PB22_DATA),
+	PINMUX_GPIO(GPIO_PB21, PB21_DATA),
+	PINMUX_GPIO(GPIO_PB20, PB20_DATA),
+	PINMUX_GPIO(GPIO_PB19, PB19_DATA),
+	PINMUX_GPIO(GPIO_PB18, PB18_DATA),
+	PINMUX_GPIO(GPIO_PB17, PB17_DATA),
+	PINMUX_GPIO(GPIO_PB16, PB16_DATA),
+	PINMUX_GPIO(GPIO_PB15, PB15_DATA),
+	PINMUX_GPIO(GPIO_PB14, PB14_DATA),
+	PINMUX_GPIO(GPIO_PB13, PB13_DATA),
+	PINMUX_GPIO(GPIO_PB12, PB12_DATA),
+	PINMUX_GPIO(GPIO_PB11, PB11_DATA),
+	PINMUX_GPIO(GPIO_PB10, PB10_DATA),
+	PINMUX_GPIO(GPIO_PB9, PB9_DATA),
+	PINMUX_GPIO(GPIO_PB8, PB8_DATA),
+	PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+	PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+	PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+	PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+	PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+	PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+	PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+
+	/* Port C */
+	PINMUX_GPIO(GPIO_PC8, PC8_DATA),
+	PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+	PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+	PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+	PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+	PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+	PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+	PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+	PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+	/* Port D */
+	PINMUX_GPIO(GPIO_PD15, PD15_DATA),
+	PINMUX_GPIO(GPIO_PD14, PD14_DATA),
+	PINMUX_GPIO(GPIO_PD13, PD13_DATA),
+	PINMUX_GPIO(GPIO_PD12, PD12_DATA),
+	PINMUX_GPIO(GPIO_PD11, PD11_DATA),
+	PINMUX_GPIO(GPIO_PD10, PD10_DATA),
+	PINMUX_GPIO(GPIO_PD9, PD9_DATA),
+	PINMUX_GPIO(GPIO_PD8, PD8_DATA),
+	PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+	PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+	PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+	PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+	PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+	PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+	PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+	PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+	/* Port E */
+	PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+	PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+	PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+	PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+	PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+	PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+	PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+	PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+	/* Port F */
+	PINMUX_GPIO(GPIO_PF23, PF23_DATA),
+	PINMUX_GPIO(GPIO_PF22, PF22_DATA),
+	PINMUX_GPIO(GPIO_PF21, PF21_DATA),
+	PINMUX_GPIO(GPIO_PF20, PF20_DATA),
+	PINMUX_GPIO(GPIO_PF19, PF19_DATA),
+	PINMUX_GPIO(GPIO_PF18, PF18_DATA),
+	PINMUX_GPIO(GPIO_PF17, PF17_DATA),
+	PINMUX_GPIO(GPIO_PF16, PF16_DATA),
+	PINMUX_GPIO(GPIO_PF15, PF15_DATA),
+	PINMUX_GPIO(GPIO_PF14, PF14_DATA),
+	PINMUX_GPIO(GPIO_PF13, PF13_DATA),
+	PINMUX_GPIO(GPIO_PF12, PF12_DATA),
+	PINMUX_GPIO(GPIO_PF11, PF11_DATA),
+	PINMUX_GPIO(GPIO_PF10, PF10_DATA),
+	PINMUX_GPIO(GPIO_PF9, PF9_DATA),
+	PINMUX_GPIO(GPIO_PF8, PF8_DATA),
+	PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+	PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+	PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+	PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+	PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+	PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+	PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+	PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+	/* Port G */
+	PINMUX_GPIO(GPIO_PG27, PG27_DATA),
+	PINMUX_GPIO(GPIO_PG26, PG26_DATA),
+	PINMUX_GPIO(GPIO_PG25, PG25_DATA),
+	PINMUX_GPIO(GPIO_PG24, PG24_DATA),
+	PINMUX_GPIO(GPIO_PG23, PG23_DATA),
+	PINMUX_GPIO(GPIO_PG22, PG22_DATA),
+	PINMUX_GPIO(GPIO_PG21, PG21_DATA),
+	PINMUX_GPIO(GPIO_PG20, PG20_DATA),
+	PINMUX_GPIO(GPIO_PG19, PG19_DATA),
+	PINMUX_GPIO(GPIO_PG18, PG18_DATA),
+	PINMUX_GPIO(GPIO_PG17, PG17_DATA),
+	PINMUX_GPIO(GPIO_PG16, PG16_DATA),
+	PINMUX_GPIO(GPIO_PG15, PG15_DATA),
+	PINMUX_GPIO(GPIO_PG14, PG14_DATA),
+	PINMUX_GPIO(GPIO_PG13, PG13_DATA),
+	PINMUX_GPIO(GPIO_PG12, PG12_DATA),
+	PINMUX_GPIO(GPIO_PG11, PG11_DATA),
+	PINMUX_GPIO(GPIO_PG10, PG10_DATA),
+	PINMUX_GPIO(GPIO_PG9, PG9_DATA),
+	PINMUX_GPIO(GPIO_PG8, PG8_DATA),
+	PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+	PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+	PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+	PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+	PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+	PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+	PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+	PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+	/* Port H - Port H does not have a Data Register */
+
+	/* Port I - not on device */
+
+	/* Port J */
+	PINMUX_GPIO(GPIO_PJ31, PJ31_DATA),
+	PINMUX_GPIO(GPIO_PJ30, PJ30_DATA),
+	PINMUX_GPIO(GPIO_PJ29, PJ29_DATA),
+	PINMUX_GPIO(GPIO_PJ28, PJ28_DATA),
+	PINMUX_GPIO(GPIO_PJ27, PJ27_DATA),
+	PINMUX_GPIO(GPIO_PJ26, PJ26_DATA),
+	PINMUX_GPIO(GPIO_PJ25, PJ25_DATA),
+	PINMUX_GPIO(GPIO_PJ24, PJ24_DATA),
+	PINMUX_GPIO(GPIO_PJ23, PJ23_DATA),
+	PINMUX_GPIO(GPIO_PJ22, PJ22_DATA),
+	PINMUX_GPIO(GPIO_PJ21, PJ21_DATA),
+	PINMUX_GPIO(GPIO_PJ20, PJ20_DATA),
+	PINMUX_GPIO(GPIO_PJ19, PJ19_DATA),
+	PINMUX_GPIO(GPIO_PJ18, PJ18_DATA),
+	PINMUX_GPIO(GPIO_PJ17, PJ17_DATA),
+	PINMUX_GPIO(GPIO_PJ16, PJ16_DATA),
+	PINMUX_GPIO(GPIO_PJ15, PJ15_DATA),
+	PINMUX_GPIO(GPIO_PJ14, PJ14_DATA),
+	PINMUX_GPIO(GPIO_PJ13, PJ13_DATA),
+	PINMUX_GPIO(GPIO_PJ12, PJ12_DATA),
+	PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
+	PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
+	PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
+	PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
+	PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+	PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+	PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+	PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+	PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+	PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+	PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+	PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+
+	/* INTC */
+	PINMUX_GPIO(GPIO_FN_IRQ7_PG, IRQ7_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ6_PG, IRQ6_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ5_PG, IRQ5_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ4_PG, IRQ4_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ1_PG, IRQ1_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ0_PG, IRQ0_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ7_PF, IRQ7_PF_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ6_PF, IRQ6_PF_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ5_PF, IRQ5_PF_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ4_PF, IRQ4_PF_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ3_PJ, IRQ3_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ2_PJ, IRQ2_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ1_PC, IRQ1_PC_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ0_PC, IRQ0_PC_MARK),
+
+	PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT0_PG, PINT0_PG_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT7_PH, PINT7_PH_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT6_PH, PINT6_PH_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT5_PH, PINT5_PH_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT4_PH, PINT4_PH_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT3_PH, PINT3_PH_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT2_PH, PINT2_PH_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT1_PH, PINT1_PH_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT0_PH, PINT0_PH_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT7_PJ, PINT7_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT6_PJ, PINT6_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT5_PJ, PINT5_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT4_PJ, PINT4_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT3_PJ, PINT3_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT2_PJ, PINT2_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT1_PJ, PINT1_PJ_MARK),
+	PINMUX_GPIO(GPIO_FN_PINT0_PJ, PINT0_PJ_MARK),
+
+	/* WDT */
+	PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+
+	/* CAN */
+	PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
+	PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
+	PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
+	PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
+	PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0CRX1_MARK),
+	PINMUX_GPIO(GPIO_FN_CRX0_CRX1_CRX2, CRX0CRX1CRX2_MARK),
+
+	/* DMAC */
+	PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+	PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+
+	/* ADC */
+	PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+	/* BSCh */
+	PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+	PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+	PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+	PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+	PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+	PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+	PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+	PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
+	PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
+	PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+	PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
+	PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
+	PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
+	PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
+	PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
+	PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
+	PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
+	PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+	PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
+	PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
+	PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
+	PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
+	PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
+	PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
+	PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+	PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+
+	PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+	PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+	PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+	PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+	PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+	PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+	PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+	PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+	PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+	PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+	PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+	PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+	PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+	PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+	PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+	PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+	PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+	PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+	PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
+	PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
+	PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
+	PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
+	PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
+	PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+	PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+	PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+	PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+	PINMUX_GPIO(GPIO_FN_WE3ICIOWRAHDQMUU, WE3ICIOWRAHDQMUU_MARK),
+	PINMUX_GPIO(GPIO_FN_WE2ICIORDDQMUL, WE2ICIORDDQMUL_MARK),
+	PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
+	PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
+	PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
+	PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
+	PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+	PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+	PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+	PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+	PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+
+	/* TMU */
+	PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
+	PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
+	PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
+	PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
+	PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
+	PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
+
+	/* SCIF */
+	PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
+	PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK5, SCK5_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
+	PINMUX_GPIO(GPIO_FN_RTS5, RTS5_MARK),
+	PINMUX_GPIO(GPIO_FN_CTS5, CTS5_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK6, SCK6_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK7, SCK7_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
+	PINMUX_GPIO(GPIO_FN_RTS7, RTS7_MARK),
+	PINMUX_GPIO(GPIO_FN_CTS7, CTS7_MARK),
+
+	/* RSPI */
+	PINMUX_GPIO(GPIO_FN_RSPCK0_PJ16, RSPCK0_PJ16_MARK),
+	PINMUX_GPIO(GPIO_FN_SSL00_PJ17, SSL00_PJ17_MARK),
+	PINMUX_GPIO(GPIO_FN_MOSI0_PJ18, MOSI0_PJ18_MARK),
+	PINMUX_GPIO(GPIO_FN_MISO0_PJ19, MISO0_PJ19_MARK),
+	PINMUX_GPIO(GPIO_FN_RSPCK0_PB17, RSPCK0_PB17_MARK),
+	PINMUX_GPIO(GPIO_FN_SSL00_PB18, SSL00_PB18_MARK),
+	PINMUX_GPIO(GPIO_FN_MOSI0_PB19, MOSI0_PB19_MARK),
+	PINMUX_GPIO(GPIO_FN_MISO0_PB20, MISO0_PB20_MARK),
+	PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
+	PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
+	PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
+	PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
+
+	/* IIC3 */
+	PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+	PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+	PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+	PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+	PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+	PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+
+	/* SSI */
+	PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
+	PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
+	PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
+	PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
+	PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
+	PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
+	PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_AUDIO_XOUT, AUDIO_XOUT_MARK),
+
+	/* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+	PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
+	PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
+	PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
+	PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
+
+	/* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+	PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
+	PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
+
+	/* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+	PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+	PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+	/* VDC3 */
+	PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+
+	PINMUX_GPIO(GPIO_FN_DV_DATA23, DV_DATA23_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA22, DV_DATA22_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA21, DV_DATA21_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA20, DV_DATA20_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA19, DV_DATA19_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA18, DV_DATA18_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA17, DV_DATA17_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA16, DV_DATA16_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA15, DV_DATA15_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA14, DV_DATA14_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA13, DV_DATA13_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA12, DV_DATA12_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA11, DV_DATA11_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA10, DV_DATA10_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA9, DV_DATA9_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA8, DV_DATA8_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
+	PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
+
+	PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
+
+	PINMUX_GPIO(GPIO_FN_LCD_DATA23, LCD_DATA23_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA22, LCD_DATA22_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA21, LCD_DATA21_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA20, LCD_DATA20_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA19, LCD_DATA19_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA18, LCD_DATA18_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA17, LCD_DATA17_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA16, LCD_DATA16_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
+	PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+
+	PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+	/* "name" addr register_size Field_Width */
+
+	/* where Field_Width is 1 for single mode registers or 4 for upto 16
+	   mode registers and modes are described in assending order [0..16] */
+
+	{ PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, PA1_IN, PA1_OUT,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, PA0_IN, PA0_OUT }
+	},
+	{ PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
+		PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
+		PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
+		PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
+		PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
+		PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
+		PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
+		PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
+		PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
+		PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
+		PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
+		PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
+		PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
+		PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
+		PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0,
+		PB22_IN, PB22_OUT,
+		PB21_IN, PB21_OUT,
+		PB20_IN, PB20_OUT,
+		PB19_IN, PB19_OUT,
+		PB18_IN, PB18_OUT,
+		PB17_IN, PB17_OUT,
+		PB16_IN, PB16_OUT }
+	},
+	{ PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
+		PB15_IN, PB15_OUT,
+		PB14_IN, PB14_OUT,
+		PB13_IN, PB13_OUT,
+		PB12_IN, PB12_OUT,
+		PB11_IN, PB11_OUT,
+		PB10_IN, PB10_OUT,
+		PB9_IN, PB9_OUT,
+		PB8_IN, PB8_OUT,
+		PB7_IN, PB7_OUT,
+		PB6_IN, PB6_OUT,
+		PB5_IN, PB5_OUT,
+		PB4_IN, PB4_OUT,
+		PB3_IN, PB3_OUT,
+		PB2_IN, PB2_OUT,
+		PB1_IN, PB1_OUT,
+		0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+		PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
+		PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
+		PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
+		PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
+		PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
+		PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
+		PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		PC8_IN, PC8_OUT,
+		PC7_IN, PC7_OUT,
+		PC6_IN, PC6_OUT,
+		PC5_IN, PC5_OUT,
+		PC4_IN, PC4_OUT,
+		PC3_IN, PC3_OUT,
+		PC2_IN, PC2_OUT,
+		PC1_IN, PC1_OUT,
+		PC0_IN, PC0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
+		PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
+		PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
+		PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
+		PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
+		PD15_IN, PD15_OUT,
+		PD14_IN, PD14_OUT,
+		PD13_IN, PD13_OUT,
+		PD12_IN, PD12_OUT,
+		PD11_IN, PD11_OUT,
+		PD10_IN, PD10_OUT,
+		PD9_IN, PD9_OUT,
+		PD8_IN, PD8_OUT,
+		PD7_IN, PD7_OUT,
+		PD6_IN, PD6_OUT,
+		PD5_IN, PD5_OUT,
+		PD4_IN, PD4_OUT,
+		PD3_IN, PD3_OUT,
+		PD2_IN, PD2_OUT,
+		PD1_IN, PD1_OUT,
+		PD0_IN, PD0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
+		PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
+		PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
+		PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
+		PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+		PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PE7_IN, PE7_OUT,
+		PE6_IN, PE6_OUT,
+		PE5_IN, PE5_OUT,
+		PE4_IN, PE4_OUT,
+		PE3_IN, PE3_OUT,
+		PE2_IN, PE2_OUT,
+		PE1_IN, PE1_OUT,
+		PE0_IN, PE0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PFCR6", 0xfffe38a2, 16, 4) {
+		PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
+		PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
+		PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
+		PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
+		PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PFCR5", 0xfffe38a4, 16, 4) {
+		PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
+		PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
+		PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
+		PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
+		PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PFCR4", 0xfffe38a6, 16, 4) {
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
+		PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
+		PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
+		PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+		PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
+		PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+		PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+		PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+		PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
+		PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
+		PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+		PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+		PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+		PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+		PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
+		PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+		PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+		PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+		PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+		PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PFIOR1", 0xfffe38b0, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF23_IN, PF23_OUT,
+		PF22_IN, PF22_OUT,
+		PF21_IN, PF21_OUT,
+		PF20_IN, PF20_OUT,
+		PF19_IN, PF19_OUT,
+		PF18_IN, PF18_OUT,
+		PF17_IN, PF17_OUT,
+		PF16_IN, PF16_OUT }
+	},
+	{ PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
+		PF15_IN, PF15_OUT,
+		PF14_IN, PF14_OUT,
+		PF13_IN, PF13_OUT,
+		PF12_IN, PF12_OUT,
+		PF11_IN, PF11_OUT,
+		PF10_IN, PF10_OUT,
+		PF9_IN, PF9_OUT,
+		PF8_IN, PF8_OUT,
+		PF7_IN, PF7_OUT,
+		PF6_IN, PF6_OUT,
+		PF5_IN, PF5_OUT,
+		PF4_IN, PF4_OUT,
+		PF3_IN, PF3_OUT,
+		PF2_IN, PF2_OUT,
+		PF1_IN, PF1_OUT,
+		PF0_IN, PF0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
+		PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
+		PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
+		PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
+		PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
+		PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+		PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
+		PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+		PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+		PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
+		PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
+		PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+		PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+		PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+		PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+		PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
+		PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
+		PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
+		PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
+		PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
+		PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
+		PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
+		PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
+		PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
+		PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+		PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG27_IN, PG27_OUT,
+		PG26_IN, PG26_OUT,
+		PG25_IN, PG25_OUT,
+		PG24_IN, PG24_OUT,
+		PG23_IN, PG23_OUT,
+		PG22_IN, PG22_OUT,
+		PG21_IN, PG21_OUT,
+		PG20_IN, PG20_OUT,
+		PG19_IN, PG19_OUT,
+		PG18_IN, PG18_OUT,
+		PG17_IN, PG17_OUT,
+		PG16_IN, PG16_OUT }
+	},
+	{ PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
+		PG15_IN, PG15_OUT,
+		PG14_IN, PG14_OUT,
+		PG13_IN, PG13_OUT,
+		PG12_IN, PG12_OUT,
+		PG11_IN, PG11_OUT,
+		PG10_IN, PG10_OUT,
+		PG9_IN, PG9_OUT,
+		PG8_IN, PG8_OUT,
+		PG7_IN, PG7_OUT,
+		PG6_IN, PG6_OUT,
+		PG5_IN, PG5_OUT,
+		PG4_IN, PG4_OUT,
+		PG3_IN, PG3_OUT,
+		PG2_IN, PG2_OUT,
+		PG1_IN, PG1_OUT,
+		PG0_IN, PG0_OUT }
+	},
+
+	{ PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
+		PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
+		PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PJCR7", 0xfffe3900, 16, 4) {
+		PJ31MD_0, PJ31MD_1, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
+		PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
+		PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
+		PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PJCR6", 0xfffe3902, 16, 4) {
+		PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
+		PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
+		PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
+		PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
+		PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PJCR5", 0xfffe3904, 16, 4) {
+		PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
+		PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
+		PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
+		PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
+		PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PJCR4", 0xfffe3906, 16, 4) {
+		PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
+		PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
+		PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
+		PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
+		PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PJCR3", 0xfffe3908, 16, 4) {
+		PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
+		PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
+		PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
+		PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
+		PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
+		PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
+		PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
+		PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
+		PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
+		PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
+		PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
+		PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
+		PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
+		PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
+		PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
+		PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
+		PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+		PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+		PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0,
+
+		PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+		PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+		0, 0, 0, 0, 0, 0, 0, 0 }
+	},
+
+	{ PINMUX_CFG_REG("PJIOR1", 0xfffe3910, 16, 1) {
+		PJ31_IN, PJ31_OUT,
+		PJ30_IN, PJ30_OUT,
+		PJ29_IN, PJ29_OUT,
+		PJ28_IN, PJ28_OUT,
+		PJ27_IN, PJ27_OUT,
+		PJ26_IN, PJ26_OUT,
+		PJ25_IN, PJ25_OUT,
+		PJ24_IN, PJ24_OUT,
+		PJ23_IN, PJ23_OUT,
+		PJ22_IN, PJ22_OUT,
+		PJ21_IN, PJ21_OUT,
+		PJ20_IN, PJ20_OUT,
+		PJ19_IN, PJ19_OUT,
+		PJ18_IN, PJ18_OUT,
+		PJ17_IN, PJ17_OUT,
+		PJ16_IN, PJ16_OUT }
+	},
+	{ PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
+		PJ15_IN, PJ15_OUT,
+		PJ14_IN, PJ14_OUT,
+		PJ13_IN, PJ13_OUT,
+		PJ12_IN, PJ12_OUT,
+		PJ11_IN, PJ11_OUT,
+		PJ10_IN, PJ10_OUT,
+		PJ9_IN, PJ9_OUT,
+		PJ8_IN, PJ8_OUT,
+		PJ7_IN, PJ7_OUT,
+		PJ6_IN, PJ6_OUT,
+		PJ5_IN, PJ5_OUT,
+		PJ4_IN, PJ4_OUT,
+		PJ3_IN, PJ3_OUT,
+		PJ2_IN, PJ2_OUT,
+		PJ1_IN, PJ1_OUT,
+		PJ0_IN, PJ0_OUT }
+	},
+
+	{}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+	{ PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
+		0, 0, 0, 0, 0, 0, 0, PA1_DATA,
+		0, 0, 0, 0, 0, 0, 0, PA0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, PB22_DATA, PB21_DATA, PB20_DATA,
+		PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
+	},
+	{ PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
+		PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+		PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+		PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+		PB3_DATA, PB2_DATA, PB1_DATA, 0 }
+	},
+
+	{ PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
+		0, 0, 0, 0,
+		0, 0, 0, PC8_DATA,
+		PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+		PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
+		PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+		PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+		PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+		PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+		PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PFDR1", 0xfffe38b4, 16) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+		PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA }
+	},
+	{ PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
+		PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+		PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+		PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+		PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
+		0, 0, 0, 0,
+		PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
+		PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+		PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
+	},
+	{ PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
+		PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+		PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+		PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+		PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
+	},
+
+	{ PINMUX_DATA_REG("PJDR1", 0xfffe3914, 16) {
+		PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
+		PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
+		PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
+		PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA }
+	},
+	{ PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
+		PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
+		PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+		PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+		PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
+	},
+
+	{ }
+};
+
+static struct pinmux_info sh7269_pinmux_info = {
+	.name = "sh7269_pfc",
+	.reserved_id = PINMUX_RESERVED,
+	.data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
+	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
+	.mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+	.first_gpio = GPIO_PA1,
+	.last_gpio = GPIO_FN_LCD_M_DISP,
+
+	.gpios = pinmux_gpios,
+	.cfg_regs = pinmux_config_regs,
+	.data_regs = pinmux_data_regs,
+
+	.gpio_data = pinmux_data,
+	.gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+	return register_pinmux(&sh7269_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
index 48e97a2..5170b6a 100644
--- a/arch/sh/kernel/cpu/sh2a/probe.c
+++ b/arch/sh/kernel/cpu/sh2a/probe.c
@@ -29,6 +29,12 @@
 #elif defined(CONFIG_CPU_SUBTYPE_SH7263)
 	boot_cpu_data.type			= CPU_SH7263;
 	boot_cpu_data.flags			|= CPU_HAS_FPU;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7264)
+	boot_cpu_data.type			= CPU_SH7264;
+	boot_cpu_data.flags			|= CPU_HAS_FPU;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7269)
+	boot_cpu_data.type			= CPU_SH7269;
+	boot_cpu_data.flags			|= CPU_HAS_FPU;
 #elif defined(CONFIG_CPU_SUBTYPE_SH7206)
 	boot_cpu_data.type			= CPU_SH7206;
 	boot_cpu_data.flags			|= CPU_HAS_DSP;
diff --git a/arch/sh/kernel/cpu/sh2a/setup-mxg.c b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
index 949bf2b..f7f1cf2 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-mxg.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
@@ -204,7 +204,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 220, 220, 220, 220 },
+	.irqs		= SCIx_IRQ_MUXED(220),
 };
 
 static struct platform_device scif0_device = {
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
index 9df558d..7b84785 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
@@ -183,7 +183,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 180, 180, 180, 180 }
+	.irqs		= SCIx_IRQ_MUXED(180),
 };
 
 static struct platform_device scif0_device = {
@@ -200,7 +200,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 184, 184, 184, 184 }
+	.irqs		= SCIx_IRQ_MUXED(184),
 };
 
 static struct platform_device scif1_device = {
@@ -217,7 +217,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 188, 188, 188, 188 }
+	.irqs		= SCIx_IRQ_MUXED(188),
 };
 
 static struct platform_device scif2_device = {
@@ -234,7 +234,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 192, 192, 192, 192 }
+	.irqs		= SCIx_IRQ_MUXED(192),
 };
 
 static struct platform_device scif3_device = {
@@ -251,7 +251,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 196, 196, 196, 196 }
+	.irqs		= SCIx_IRQ_MUXED(196),
 };
 
 static struct platform_device scif4_device = {
@@ -268,7 +268,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 200, 200, 200, 200 }
+	.irqs		= SCIx_IRQ_MUXED(200),
 };
 
 static struct platform_device scif5_device = {
@@ -285,7 +285,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 204, 204, 204, 204 }
+	.irqs		= SCIx_IRQ_MUXED(204),
 };
 
 static struct platform_device scif6_device = {
@@ -302,7 +302,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 208, 208, 208, 208 }
+	.irqs		= SCIx_IRQ_MUXED(208),
 };
 
 static struct platform_device scif7_device = {
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
index 0bd744f..bfc33f6 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
@@ -180,7 +180,7 @@
 			  SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		=  { 192, 192, 192, 192 },
+	.irqs		= SCIx_IRQ_MUXED(192),
 	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -199,7 +199,7 @@
 			  SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		=  { 196, 196, 196, 196 },
+	.irqs		= SCIx_IRQ_MUXED(196),
 	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -218,7 +218,7 @@
 			  SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		=  { 200, 200, 200, 200 },
+	.irqs		= SCIx_IRQ_MUXED(200),
 	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -237,7 +237,7 @@
 			  SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		=  { 204, 204, 204, 204 },
+	.irqs		= SCIx_IRQ_MUXED(204),
 	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index 5d14f84..a501074 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -139,7 +139,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 240, 240, 240, 240 },
+	.irqs		= SCIx_IRQ_MUXED(240),
 };
 
 static struct platform_device scif0_device = {
@@ -156,7 +156,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 244, 244, 244, 244 },
+	.irqs		= SCIx_IRQ_MUXED(244),
 };
 
 static struct platform_device scif1_device = {
@@ -173,7 +173,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 248, 248, 248, 248 },
+	.irqs		= SCIx_IRQ_MUXED(248),
 };
 
 static struct platform_device scif2_device = {
@@ -190,7 +190,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 252, 252, 252, 252 },
+	.irqs		= SCIx_IRQ_MUXED(252),
 };
 
 static struct platform_device scif3_device = {
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7264.c b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
new file mode 100644
index 0000000..ce5c1b5
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
@@ -0,0 +1,606 @@
+/*
+ * SH7264 Setup
+ *
+ * Copyright (C) 2012  Renesas Electronics Europe Ltd
+ *
+ * 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 <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+#include <linux/usb/r8a66597.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+
+enum {
+	UNUSED = 0,
+
+	/* interrupt sources */
+	IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+	PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+
+	DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+	DMAC8, DMAC9, DMAC10, DMAC11, DMAC12, DMAC13, DMAC14, DMAC15,
+	USB, VDC3, CMT0, CMT1, BSC, WDT,
+	MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+	MTU3_ABCD, MTU3_TCI3V, MTU4_ABCD, MTU4_TCI4V,
+	PWMT1, PWMT2, ADC_ADI,
+	SSIF0, SSII1, SSII2, SSII3,
+	RSPDIF,
+	IIC30, IIC31, IIC32, IIC33,
+	SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+	SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+	SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+	SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+	SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
+	SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
+	SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
+	SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
+	SIO_FIFO, RSPIC0, RSPIC1,
+	RCAN0, RCAN1, IEBC, CD_ROMD,
+	NFMC, SDHI, RTC,
+	SRCC0, SRCC1, DCOMU, OFFI, IFEI,
+
+	/* interrupt groups */
+	PINT, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
+};
+
+static struct intc_vect vectors[] __initdata = {
+	INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+	INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+	INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+	INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+
+	INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+	INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+	INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+	INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+
+	INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
+	INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
+	INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
+	INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
+	INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
+	INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
+	INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
+	INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
+	INTC_IRQ(DMAC8, 140), INTC_IRQ(DMAC8, 141),
+	INTC_IRQ(DMAC9, 144), INTC_IRQ(DMAC9, 145),
+	INTC_IRQ(DMAC10, 148), INTC_IRQ(DMAC10, 149),
+	INTC_IRQ(DMAC11, 152), INTC_IRQ(DMAC11, 153),
+	INTC_IRQ(DMAC12, 156), INTC_IRQ(DMAC12, 157),
+	INTC_IRQ(DMAC13, 160), INTC_IRQ(DMAC13, 161),
+	INTC_IRQ(DMAC14, 164), INTC_IRQ(DMAC14, 165),
+	INTC_IRQ(DMAC15, 168), INTC_IRQ(DMAC15, 169),
+
+	INTC_IRQ(USB, 170),
+	INTC_IRQ(VDC3, 171), INTC_IRQ(VDC3, 172),
+	INTC_IRQ(VDC3, 173), INTC_IRQ(VDC3, 174),
+	INTC_IRQ(CMT0, 175), INTC_IRQ(CMT1, 176),
+	INTC_IRQ(BSC, 177), INTC_IRQ(WDT, 178),
+
+	INTC_IRQ(MTU0_ABCD, 179), INTC_IRQ(MTU0_ABCD, 180),
+	INTC_IRQ(MTU0_ABCD, 181), INTC_IRQ(MTU0_ABCD, 182),
+	INTC_IRQ(MTU0_VEF, 183),
+	INTC_IRQ(MTU0_VEF, 184), INTC_IRQ(MTU0_VEF, 185),
+	INTC_IRQ(MTU1_AB, 186), INTC_IRQ(MTU1_AB, 187),
+	INTC_IRQ(MTU1_VU, 188), INTC_IRQ(MTU1_VU, 189),
+	INTC_IRQ(MTU2_AB, 190), INTC_IRQ(MTU2_AB, 191),
+	INTC_IRQ(MTU2_VU, 192), INTC_IRQ(MTU2_VU, 193),
+	INTC_IRQ(MTU3_ABCD, 194), INTC_IRQ(MTU3_ABCD, 195),
+	INTC_IRQ(MTU3_ABCD, 196), INTC_IRQ(MTU3_ABCD, 197),
+	INTC_IRQ(MTU3_TCI3V, 198),
+	INTC_IRQ(MTU4_ABCD, 199), INTC_IRQ(MTU4_ABCD, 200),
+	INTC_IRQ(MTU4_ABCD, 201), INTC_IRQ(MTU4_ABCD, 202),
+	INTC_IRQ(MTU4_TCI4V, 203),
+
+	INTC_IRQ(PWMT1, 204), INTC_IRQ(PWMT2, 205),
+
+	INTC_IRQ(ADC_ADI, 206),
+
+	INTC_IRQ(SSIF0, 207), INTC_IRQ(SSIF0, 208),
+	INTC_IRQ(SSIF0, 209),
+	INTC_IRQ(SSII1, 210), INTC_IRQ(SSII1, 211),
+	INTC_IRQ(SSII2, 212), INTC_IRQ(SSII2, 213),
+	INTC_IRQ(SSII3, 214), INTC_IRQ(SSII3, 215),
+
+	INTC_IRQ(RSPDIF, 216),
+
+	INTC_IRQ(IIC30, 217), INTC_IRQ(IIC30, 218),
+	INTC_IRQ(IIC30, 219), INTC_IRQ(IIC30, 220),
+	INTC_IRQ(IIC30, 221),
+	INTC_IRQ(IIC31, 222), INTC_IRQ(IIC31, 223),
+	INTC_IRQ(IIC31, 224), INTC_IRQ(IIC31, 225),
+	INTC_IRQ(IIC31, 226),
+	INTC_IRQ(IIC32, 227), INTC_IRQ(IIC32, 228),
+	INTC_IRQ(IIC32, 229), INTC_IRQ(IIC32, 230),
+	INTC_IRQ(IIC32, 231),
+
+	INTC_IRQ(SCIF0_BRI, 232), INTC_IRQ(SCIF0_ERI, 233),
+	INTC_IRQ(SCIF0_RXI, 234), INTC_IRQ(SCIF0_TXI, 235),
+	INTC_IRQ(SCIF1_BRI, 236), INTC_IRQ(SCIF1_ERI, 237),
+	INTC_IRQ(SCIF1_RXI, 238), INTC_IRQ(SCIF1_TXI, 239),
+	INTC_IRQ(SCIF2_BRI, 240), INTC_IRQ(SCIF2_ERI, 241),
+	INTC_IRQ(SCIF2_RXI, 242), INTC_IRQ(SCIF2_TXI, 243),
+	INTC_IRQ(SCIF3_BRI, 244), INTC_IRQ(SCIF3_ERI, 245),
+	INTC_IRQ(SCIF3_RXI, 246), INTC_IRQ(SCIF3_TXI, 247),
+	INTC_IRQ(SCIF4_BRI, 248), INTC_IRQ(SCIF4_ERI, 249),
+	INTC_IRQ(SCIF4_RXI, 250), INTC_IRQ(SCIF4_TXI, 251),
+	INTC_IRQ(SCIF5_BRI, 252), INTC_IRQ(SCIF5_ERI, 253),
+	INTC_IRQ(SCIF5_RXI, 254), INTC_IRQ(SCIF5_TXI, 255),
+	INTC_IRQ(SCIF6_BRI, 256), INTC_IRQ(SCIF6_ERI, 257),
+	INTC_IRQ(SCIF6_RXI, 258), INTC_IRQ(SCIF6_TXI, 259),
+	INTC_IRQ(SCIF7_BRI, 260), INTC_IRQ(SCIF7_ERI, 261),
+	INTC_IRQ(SCIF7_RXI, 262), INTC_IRQ(SCIF7_TXI, 263),
+
+	INTC_IRQ(SIO_FIFO, 264),
+
+	INTC_IRQ(RSPIC0, 265), INTC_IRQ(RSPIC0, 266),
+	INTC_IRQ(RSPIC0, 267),
+	INTC_IRQ(RSPIC1, 268), INTC_IRQ(RSPIC1, 269),
+	INTC_IRQ(RSPIC1, 270),
+
+	INTC_IRQ(RCAN0, 271), INTC_IRQ(RCAN0, 272),
+	INTC_IRQ(RCAN0, 273), INTC_IRQ(RCAN0, 274),
+	INTC_IRQ(RCAN0, 275),
+	INTC_IRQ(RCAN1, 276), INTC_IRQ(RCAN1, 277),
+	INTC_IRQ(RCAN1, 278), INTC_IRQ(RCAN1, 279),
+	INTC_IRQ(RCAN1, 280),
+
+	INTC_IRQ(IEBC, 281),
+
+	INTC_IRQ(CD_ROMD, 282), INTC_IRQ(CD_ROMD, 283),
+	INTC_IRQ(CD_ROMD, 284), INTC_IRQ(CD_ROMD, 285),
+	INTC_IRQ(CD_ROMD, 286), INTC_IRQ(CD_ROMD, 287),
+
+	INTC_IRQ(NFMC, 288), INTC_IRQ(NFMC, 289),
+	INTC_IRQ(NFMC, 290), INTC_IRQ(NFMC, 291),
+
+	INTC_IRQ(SDHI, 292), INTC_IRQ(SDHI, 293),
+	INTC_IRQ(SDHI, 294),
+
+	INTC_IRQ(RTC, 296), INTC_IRQ(RTC, 297),
+	INTC_IRQ(RTC, 298),
+
+	INTC_IRQ(SRCC0, 299), INTC_IRQ(SRCC0, 300),
+	INTC_IRQ(SRCC0, 301), INTC_IRQ(SRCC0, 302),
+	INTC_IRQ(SRCC0, 303),
+	INTC_IRQ(SRCC1, 304), INTC_IRQ(SRCC1, 305),
+	INTC_IRQ(SRCC1, 306), INTC_IRQ(SRCC1, 307),
+	INTC_IRQ(SRCC1, 308),
+
+	INTC_IRQ(DCOMU, 310), INTC_IRQ(DCOMU, 311),
+	INTC_IRQ(DCOMU, 312),
+};
+
+static struct intc_group groups[] __initdata = {
+	INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+		   PINT4, PINT5, PINT6, PINT7),
+	INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+	INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+	INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+	INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+	INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
+	INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
+	INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
+	INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+	{ 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+	{ 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+	{ 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
+	{ 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0,  DMAC1,  DMAC2,  DMAC3 } },
+	{ 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4,  DMAC5,  DMAC6,  DMAC7 } },
+	{ 0xfffe0c04, 0, 16, 4, /* IPR08 */ { DMAC8,  DMAC9,
+					      DMAC10, DMAC11 } },
+	{ 0xfffe0c06, 0, 16, 4, /* IPR09 */ { DMAC12, DMAC13,
+					      DMAC14, DMAC15 } },
+	{ 0xfffe0c08, 0, 16, 4, /* IPR10 */ { USB, VDC3, CMT0, CMT1 } },
+	{ 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { BSC, WDT, MTU0_ABCD, MTU0_VEF } },
+	{ 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { MTU1_AB, MTU1_VU,
+					      MTU2_AB, MTU2_VU } },
+	{ 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU3_ABCD, MTU3_TCI3V,
+					      MTU4_ABCD, MTU4_TCI4V } },
+	{ 0xfffe0c10, 0, 16, 4, /* IPR14 */ { PWMT1, PWMT2, ADC_ADI, 0 } },
+	{ 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSIF0, SSII1, SSII2, SSII3 } },
+	{ 0xfffe0c14, 0, 16, 4, /* IPR16 */ { RSPDIF, IIC30, IIC31, IIC32 } },
+	{ 0xfffe0c16, 0, 16, 4, /* IPR17 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
+	{ 0xfffe0c18, 0, 16, 4, /* IPR18 */ { SCIF4, SCIF5, SCIF6, SCIF7 } },
+	{ 0xfffe0c1a, 0, 16, 4, /* IPR19 */ { SIO_FIFO, 0, RSPIC0, RSPIC1, } },
+	{ 0xfffe0c1c, 0, 16, 4, /* IPR20 */ { RCAN0, RCAN1, IEBC, CD_ROMD } },
+	{ 0xfffe0c1e, 0, 16, 4, /* IPR21 */ { NFMC, SDHI, RTC, 0 } },
+	{ 0xfffe0c20, 0, 16, 4, /* IPR22 */ { SRCC0, SRCC1, 0, DCOMU } },
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+	{ 0xfffe0808, 0, 16, /* PINTER */
+	  { 0, 0, 0, 0, 0, 0, 0, 0,
+	    PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7264", vectors, groups,
+			 mask_registers, prio_registers, NULL);
+
+static struct plat_sci_port scif0_platform_data = {
+	.mapbase	= 0xfffe8000,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 233, 234, 235, 232 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif0_device = {
+	.name		= "sh-sci",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &scif0_platform_data,
+	},
+};
+
+static struct plat_sci_port scif1_platform_data = {
+	.mapbase	= 0xfffe8800,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 237, 238, 239, 236 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif1_device = {
+	.name		= "sh-sci",
+	.id		= 1,
+	.dev		= {
+		.platform_data	= &scif1_platform_data,
+	},
+};
+
+static struct plat_sci_port scif2_platform_data = {
+	.mapbase	= 0xfffe9000,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 241, 242, 243, 240 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif2_device = {
+	.name		= "sh-sci",
+	.id		= 2,
+	.dev		= {
+		.platform_data	= &scif2_platform_data,
+	},
+};
+
+static struct plat_sci_port scif3_platform_data = {
+	.mapbase	= 0xfffe9800,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 245, 246, 247, 244 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif3_device = {
+	.name		= "sh-sci",
+	.id		= 3,
+	.dev		= {
+		.platform_data	= &scif3_platform_data,
+	},
+};
+
+static struct plat_sci_port scif4_platform_data = {
+	.mapbase	= 0xfffea000,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 249, 250, 251, 248 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif4_device = {
+	.name		= "sh-sci",
+	.id		= 4,
+	.dev		= {
+		.platform_data	= &scif4_platform_data,
+	},
+};
+
+static struct plat_sci_port scif5_platform_data = {
+	.mapbase	= 0xfffea800,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 253, 254, 255, 252 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif5_device = {
+	.name		= "sh-sci",
+	.id		= 5,
+	.dev		= {
+		.platform_data	= &scif5_platform_data,
+	},
+};
+
+static struct plat_sci_port scif6_platform_data = {
+	.mapbase	= 0xfffeb000,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 257, 258, 259, 256 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif6_device = {
+	.name		= "sh-sci",
+	.id		= 6,
+	.dev		= {
+		.platform_data	= &scif6_platform_data,
+	},
+};
+
+static struct plat_sci_port scif7_platform_data = {
+	.mapbase	= 0xfffeb800,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 261, 262, 263, 260 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif7_device = {
+	.name		= "sh-sci",
+	.id		= 7,
+	.dev		= {
+		.platform_data	= &scif7_platform_data,
+	},
+};
+
+static struct sh_timer_config cmt0_platform_data = {
+	.channel_offset = 0x02,
+	.timer_bit = 0,
+	.clockevent_rating = 125,
+	.clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt0_resources[] = {
+	[0] = {
+		.name	= "CMT0",
+		.start	= 0xfffec002,
+		.end	= 0xfffec007,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 175,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cmt0_device = {
+	.name		= "sh_cmt",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &cmt0_platform_data,
+	},
+	.resource	= cmt0_resources,
+	.num_resources	= ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+	.name = "CMT1",
+	.channel_offset = 0x08,
+	.timer_bit = 1,
+	.clockevent_rating = 125,
+	.clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt1_resources[] = {
+	[0] = {
+		.name	= "CMT1",
+		.start	= 0xfffec008,
+		.end	= 0xfffec00d,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 176,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cmt1_device = {
+	.name		= "sh_cmt",
+	.id		= 1,
+	.dev = {
+		.platform_data	= &cmt1_platform_data,
+	},
+	.resource	= cmt1_resources,
+	.num_resources	= ARRAY_SIZE(cmt1_resources),
+};
+
+static struct sh_timer_config mtu2_0_platform_data = {
+	.name = "MTU2_0",
+	.channel_offset = -0x80,
+	.timer_bit = 0,
+	.clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+	[0] = {
+		.name	= "MTU2_0",
+		.start	= 0xfffe4300,
+		.end	= 0xfffe4326,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 179,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mtu2_0_device = {
+	.name		= "sh_mtu2",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &mtu2_0_platform_data,
+	},
+	.resource	= mtu2_0_resources,
+	.num_resources	= ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+	.name = "MTU2_1",
+	.channel_offset = -0x100,
+	.timer_bit = 1,
+	.clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+	[0] = {
+		.name	= "MTU2_1",
+		.start	= 0xfffe4380,
+		.end	= 0xfffe4390,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 186,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mtu2_1_device = {
+	.name		= "sh_mtu2",
+	.id		= 1,
+	.dev = {
+		.platform_data	= &mtu2_1_platform_data,
+	},
+	.resource	= mtu2_1_resources,
+	.num_resources	= ARRAY_SIZE(mtu2_1_resources),
+};
+
+static struct resource rtc_resources[] = {
+	[0] = {
+		.start	= 0xfffe6000,
+		.end	= 0xfffe6000 + 0x30 - 1,
+		.flags	= IORESOURCE_IO,
+	},
+	[1] = {
+		/* Shared Period/Carry/Alarm IRQ */
+		.start	= 296,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device rtc_device = {
+	.name		= "sh-rtc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(rtc_resources),
+	.resource	= rtc_resources,
+};
+
+/* USB Host */
+static void usb_port_power(int port, int power)
+{
+	__raw_writew(0x200 , 0xffffc0c2) ; /* Initialise UACS25 */
+}
+
+static struct r8a66597_platdata r8a66597_data = {
+	.on_chip = 1,
+	.endian = 1,
+	.port_power = usb_port_power,
+};
+
+static struct resource r8a66597_usb_host_resources[] = {
+	[0] = {
+		.start	= 0xffffc000,
+		.end	= 0xffffc0e4,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 170,
+		.end	= 170,
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
+	},
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+	.name		= "r8a66597_hcd",
+	.id		= 0,
+	.dev = {
+		.dma_mask		= NULL,         /*  not use dma */
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &r8a66597_data,
+	},
+	.num_resources	= ARRAY_SIZE(r8a66597_usb_host_resources),
+	.resource	= r8a66597_usb_host_resources,
+};
+
+static struct platform_device *sh7264_devices[] __initdata = {
+	&scif0_device,
+	&scif1_device,
+	&scif2_device,
+	&scif3_device,
+	&scif4_device,
+	&scif5_device,
+	&scif6_device,
+	&scif7_device,
+	&cmt0_device,
+	&cmt1_device,
+	&mtu2_0_device,
+	&mtu2_1_device,
+	&rtc_device,
+	&r8a66597_usb_host_device,
+};
+
+static int __init sh7264_devices_setup(void)
+{
+	return platform_add_devices(sh7264_devices,
+				    ARRAY_SIZE(sh7264_devices));
+}
+arch_initcall(sh7264_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+	register_intc_controller(&intc_desc);
+}
+
+static struct platform_device *sh7264_early_devices[] __initdata = {
+	&scif0_device,
+	&scif1_device,
+	&scif2_device,
+	&scif3_device,
+	&scif4_device,
+	&scif5_device,
+	&scif6_device,
+	&scif7_device,
+	&cmt0_device,
+	&cmt1_device,
+	&mtu2_0_device,
+	&mtu2_1_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+	early_platform_add_devices(sh7264_early_devices,
+				   ARRAY_SIZE(sh7264_early_devices));
+}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7269.c b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
new file mode 100644
index 0000000..e82ae9d
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
@@ -0,0 +1,615 @@
+/*
+ * SH7269 Setup
+ *
+ * Copyright (C) 2012  Renesas Electronics Europe Ltd
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * 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 <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+#include <linux/usb/r8a66597.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+
+enum {
+	UNUSED = 0,
+
+	/* interrupt sources */
+	IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+	PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+
+	DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+	DMAC8, DMAC9, DMAC10, DMAC11, DMAC12, DMAC13, DMAC14, DMAC15,
+	USB, VDC4, CMT0, CMT1, BSC, WDT,
+	MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+	MTU3_ABCD, MTU3_TCI3V, MTU4_ABCD, MTU4_TCI4V,
+	PWMT1, PWMT2, ADC_ADI,
+	SSIF0, SSII1, SSII2, SSII3, SSII4, SSII5,
+	RSPDIF,
+	IIC30, IIC31, IIC32, IIC33,
+	SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+	SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+	SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+	SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+	SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
+	SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
+	SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
+	SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
+	RCAN0, RCAN1, RCAN2,
+	RSPIC0, RSPIC1,
+	IEBC, CD_ROMD,
+	NFMC,
+	SDHI0, SDHI1,
+	RTC,
+	SRCC0, SRCC1, SRCC2,
+
+	/* interrupt groups */
+	PINT, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
+};
+
+static struct intc_vect vectors[] __initdata = {
+	INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+	INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+	INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+	INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+
+	INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+	INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+	INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+	INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+
+	INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
+	INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
+	INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
+	INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
+	INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
+	INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
+	INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
+	INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
+	INTC_IRQ(DMAC8, 140), INTC_IRQ(DMAC8, 141),
+	INTC_IRQ(DMAC9, 144), INTC_IRQ(DMAC9, 145),
+	INTC_IRQ(DMAC10, 148), INTC_IRQ(DMAC10, 149),
+	INTC_IRQ(DMAC11, 152), INTC_IRQ(DMAC11, 153),
+	INTC_IRQ(DMAC12, 156), INTC_IRQ(DMAC12, 157),
+	INTC_IRQ(DMAC13, 160), INTC_IRQ(DMAC13, 161),
+	INTC_IRQ(DMAC14, 164), INTC_IRQ(DMAC14, 165),
+	INTC_IRQ(DMAC15, 168), INTC_IRQ(DMAC15, 169),
+
+	INTC_IRQ(USB, 170),
+
+	INTC_IRQ(VDC4, 171), INTC_IRQ(VDC4, 172),
+	INTC_IRQ(VDC4, 173), INTC_IRQ(VDC4, 174),
+	INTC_IRQ(VDC4, 175), INTC_IRQ(VDC4, 176),
+	INTC_IRQ(VDC4, 177), INTC_IRQ(VDC4, 177),
+
+	INTC_IRQ(CMT0, 188), INTC_IRQ(CMT1, 189),
+
+	INTC_IRQ(BSC, 190), INTC_IRQ(WDT, 191),
+
+	INTC_IRQ(MTU0_ABCD, 192), INTC_IRQ(MTU0_ABCD, 193),
+	INTC_IRQ(MTU0_ABCD, 194), INTC_IRQ(MTU0_ABCD, 195),
+	INTC_IRQ(MTU0_VEF, 196), INTC_IRQ(MTU0_VEF, 197),
+	INTC_IRQ(MTU0_VEF, 198),
+	INTC_IRQ(MTU1_AB, 199), INTC_IRQ(MTU1_AB, 200),
+	INTC_IRQ(MTU1_VU, 201), INTC_IRQ(MTU1_VU, 202),
+	INTC_IRQ(MTU2_AB, 203), INTC_IRQ(MTU2_AB, 204),
+	INTC_IRQ(MTU2_VU, 205), INTC_IRQ(MTU2_VU, 206),
+	INTC_IRQ(MTU3_ABCD, 207), INTC_IRQ(MTU3_ABCD, 208),
+	INTC_IRQ(MTU3_ABCD, 209), INTC_IRQ(MTU3_ABCD, 210),
+	INTC_IRQ(MTU3_TCI3V, 211),
+	INTC_IRQ(MTU4_ABCD, 212), INTC_IRQ(MTU4_ABCD, 213),
+	INTC_IRQ(MTU4_ABCD, 214), INTC_IRQ(MTU4_ABCD, 215),
+	INTC_IRQ(MTU4_TCI4V, 216),
+
+	INTC_IRQ(PWMT1, 217), INTC_IRQ(PWMT2, 218),
+
+	INTC_IRQ(ADC_ADI, 223),
+
+	INTC_IRQ(SSIF0, 224), INTC_IRQ(SSIF0, 225),
+	INTC_IRQ(SSIF0, 226),
+	INTC_IRQ(SSII1, 227), INTC_IRQ(SSII1, 228),
+	INTC_IRQ(SSII2, 229), INTC_IRQ(SSII2, 230),
+	INTC_IRQ(SSII3, 231), INTC_IRQ(SSII3, 232),
+	INTC_IRQ(SSII4, 233), INTC_IRQ(SSII4, 234),
+	INTC_IRQ(SSII5, 235), INTC_IRQ(SSII5, 236),
+
+	INTC_IRQ(RSPDIF, 237),
+
+	INTC_IRQ(IIC30, 238), INTC_IRQ(IIC30, 239),
+	INTC_IRQ(IIC30, 240), INTC_IRQ(IIC30, 241),
+	INTC_IRQ(IIC30, 242),
+	INTC_IRQ(IIC31, 243), INTC_IRQ(IIC31, 244),
+	INTC_IRQ(IIC31, 245), INTC_IRQ(IIC31, 246),
+	INTC_IRQ(IIC31, 247),
+	INTC_IRQ(IIC32, 248), INTC_IRQ(IIC32, 249),
+	INTC_IRQ(IIC32, 250), INTC_IRQ(IIC32, 251),
+	INTC_IRQ(IIC32, 252),
+	INTC_IRQ(IIC33, 253), INTC_IRQ(IIC33, 254),
+	INTC_IRQ(IIC33, 255), INTC_IRQ(IIC33, 256),
+	INTC_IRQ(IIC33, 257),
+
+	INTC_IRQ(SCIF0_BRI, 258), INTC_IRQ(SCIF0_ERI, 259),
+	INTC_IRQ(SCIF0_RXI, 260), INTC_IRQ(SCIF0_TXI, 261),
+	INTC_IRQ(SCIF1_BRI, 262), INTC_IRQ(SCIF1_ERI, 263),
+	INTC_IRQ(SCIF1_RXI, 264), INTC_IRQ(SCIF1_TXI, 265),
+	INTC_IRQ(SCIF2_BRI, 266), INTC_IRQ(SCIF2_ERI, 267),
+	INTC_IRQ(SCIF2_RXI, 268), INTC_IRQ(SCIF2_TXI, 269),
+	INTC_IRQ(SCIF3_BRI, 270), INTC_IRQ(SCIF3_ERI, 271),
+	INTC_IRQ(SCIF3_RXI, 272), INTC_IRQ(SCIF3_TXI, 273),
+	INTC_IRQ(SCIF4_BRI, 274), INTC_IRQ(SCIF4_ERI, 275),
+	INTC_IRQ(SCIF4_RXI, 276), INTC_IRQ(SCIF4_TXI, 277),
+	INTC_IRQ(SCIF5_BRI, 278), INTC_IRQ(SCIF5_ERI, 279),
+	INTC_IRQ(SCIF5_RXI, 280), INTC_IRQ(SCIF5_TXI, 281),
+	INTC_IRQ(SCIF6_BRI, 282), INTC_IRQ(SCIF6_ERI, 283),
+	INTC_IRQ(SCIF6_RXI, 284), INTC_IRQ(SCIF6_TXI, 285),
+	INTC_IRQ(SCIF7_BRI, 286), INTC_IRQ(SCIF7_ERI, 287),
+	INTC_IRQ(SCIF7_RXI, 288), INTC_IRQ(SCIF7_TXI, 289),
+
+	INTC_IRQ(RCAN0, 291), INTC_IRQ(RCAN0, 292),
+	INTC_IRQ(RCAN0, 293), INTC_IRQ(RCAN0, 294),
+	INTC_IRQ(RCAN0, 295),
+	INTC_IRQ(RCAN1, 296), INTC_IRQ(RCAN1, 297),
+	INTC_IRQ(RCAN1, 298), INTC_IRQ(RCAN1, 299),
+	INTC_IRQ(RCAN1, 300),
+	INTC_IRQ(RCAN2, 301), INTC_IRQ(RCAN2, 302),
+	INTC_IRQ(RCAN2, 303), INTC_IRQ(RCAN2, 304),
+	INTC_IRQ(RCAN2, 305),
+
+	INTC_IRQ(RSPIC0, 306), INTC_IRQ(RSPIC0, 307),
+	INTC_IRQ(RSPIC0, 308),
+	INTC_IRQ(RSPIC1, 309), INTC_IRQ(RSPIC1, 310),
+	INTC_IRQ(RSPIC1, 311),
+
+	INTC_IRQ(IEBC, 318),
+
+	INTC_IRQ(CD_ROMD, 319), INTC_IRQ(CD_ROMD, 320),
+	INTC_IRQ(CD_ROMD, 321), INTC_IRQ(CD_ROMD, 322),
+	INTC_IRQ(CD_ROMD, 323), INTC_IRQ(CD_ROMD, 324),
+
+	INTC_IRQ(NFMC, 325), INTC_IRQ(NFMC, 326),
+	INTC_IRQ(NFMC, 327), INTC_IRQ(NFMC, 328),
+
+	INTC_IRQ(SDHI0, 332), INTC_IRQ(SDHI0, 333),
+	INTC_IRQ(SDHI0, 334),
+	INTC_IRQ(SDHI1, 335), INTC_IRQ(SDHI1, 336),
+	INTC_IRQ(SDHI1, 337),
+
+	INTC_IRQ(RTC, 338), INTC_IRQ(RTC, 339),
+	INTC_IRQ(RTC, 340),
+
+	INTC_IRQ(SRCC0, 341), INTC_IRQ(SRCC0, 342),
+	INTC_IRQ(SRCC0, 343), INTC_IRQ(SRCC0, 344),
+	INTC_IRQ(SRCC0, 345),
+	INTC_IRQ(SRCC1, 346), INTC_IRQ(SRCC1, 347),
+	INTC_IRQ(SRCC1, 348), INTC_IRQ(SRCC1, 349),
+	INTC_IRQ(SRCC1, 350),
+	INTC_IRQ(SRCC2, 351), INTC_IRQ(SRCC2, 352),
+	INTC_IRQ(SRCC2, 353), INTC_IRQ(SRCC2, 354),
+	INTC_IRQ(SRCC2, 355),
+};
+
+static struct intc_group groups[] __initdata = {
+	INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+		   PINT4, PINT5, PINT6, PINT7),
+	INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+	INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+	INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+	INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+	INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
+	INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
+	INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
+	INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+	{ 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+	{ 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+	{ 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
+	{ 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0,  DMAC1, DMAC2,  DMAC3 } },
+	{ 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4,  DMAC5, DMAC6,  DMAC7 } },
+	{ 0xfffe0c04, 0, 16, 4, /* IPR08 */ { DMAC8,  DMAC9,
+					      DMAC10, DMAC11 } },
+	{ 0xfffe0c06, 0, 16, 4, /* IPR09 */ { DMAC12, DMAC13,
+					      DMAC14, DMAC15 } },
+	{ 0xfffe0c08, 0, 16, 4, /* IPR10 */ { USB, VDC4, VDC4, VDC4 } },
+	{ 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { 0, 0, 0, 0 } },
+	{ 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { CMT0, CMT1, BSC, WDT } },
+	{ 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU0_ABCD, MTU0_VEF,
+					      MTU1_AB, MTU1_VU } },
+	{ 0xfffe0c10, 0, 16, 4, /* IPR14 */ { MTU2_AB, MTU2_VU,
+					      MTU3_ABCD, MTU3_TCI3V } },
+	{ 0xfffe0c12, 0, 16, 4, /* IPR15 */ { MTU4_ABCD, MTU4_TCI4V,
+					      PWMT1, PWMT2 } },
+	{ 0xfffe0c14, 0, 16, 4, /* IPR16 */ { 0, 0, 0, 0 } },
+	{ 0xfffe0c16, 0, 16, 4, /* IPR17 */ { ADC_ADI, SSIF0, SSII1, SSII2 } },
+	{ 0xfffe0c18, 0, 16, 4, /* IPR18 */ { SSII3, SSII4, SSII5,  RSPDIF} },
+	{ 0xfffe0c1a, 0, 16, 4, /* IPR19 */ { IIC30, IIC31, IIC32, IIC33 } },
+	{ 0xfffe0c1c, 0, 16, 4, /* IPR20 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
+	{ 0xfffe0c1e, 0, 16, 4, /* IPR21 */ { SCIF4, SCIF5, SCIF6, SCIF7 } },
+	{ 0xfffe0c20, 0, 16, 4, /* IPR22 */ { 0, RCAN0, RCAN1, RCAN2 } },
+	{ 0xfffe0c22, 0, 16, 4, /* IPR23 */ { RSPIC0, RSPIC1, 0, 0 } },
+	{ 0xfffe0c24, 0, 16, 4, /* IPR24 */ { IEBC, CD_ROMD, NFMC, 0 } },
+	{ 0xfffe0c26, 0, 16, 4, /* IPR25 */ { SDHI0, SDHI1, RTC, 0 } },
+	{ 0xfffe0c28, 0, 16, 4, /* IPR26 */ { SRCC0, SRCC1, SRCC2, 0 } },
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+	{ 0xfffe0808, 0, 16, /* PINTER */
+	  { 0, 0, 0, 0, 0, 0, 0, 0,
+	    PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7269", vectors, groups,
+			 mask_registers, prio_registers, NULL);
+
+static struct plat_sci_port scif0_platform_data = {
+	.mapbase	= 0xe8007000,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 259, 260, 261, 258 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif0_device = {
+	.name		= "sh-sci",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &scif0_platform_data,
+	},
+};
+
+static struct plat_sci_port scif1_platform_data = {
+	.mapbase	= 0xe8007800,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 263, 264, 265, 262 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif1_device = {
+	.name		= "sh-sci",
+	.id		= 1,
+	.dev		= {
+		.platform_data	= &scif1_platform_data,
+	},
+};
+
+static struct plat_sci_port scif2_platform_data = {
+	.mapbase	= 0xe8008000,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 267, 268, 269, 266 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif2_device = {
+	.name		= "sh-sci",
+	.id		= 2,
+	.dev		= {
+		.platform_data	= &scif2_platform_data,
+	},
+};
+
+static struct plat_sci_port scif3_platform_data = {
+	.mapbase	= 0xe8008800,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 271, 272, 273, 270 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif3_device = {
+	.name		= "sh-sci",
+	.id		= 3,
+	.dev		= {
+		.platform_data	= &scif3_platform_data,
+	},
+};
+
+static struct plat_sci_port scif4_platform_data = {
+	.mapbase	= 0xe8009000,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 275, 276, 277, 274 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif4_device = {
+	.name		= "sh-sci",
+	.id		= 4,
+	.dev		= {
+		.platform_data	= &scif4_platform_data,
+	},
+};
+
+static struct plat_sci_port scif5_platform_data = {
+	.mapbase	= 0xe8009800,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 279, 280, 281, 278 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif5_device = {
+	.name		= "sh-sci",
+	.id		= 5,
+	.dev		= {
+		.platform_data	= &scif5_platform_data,
+	},
+};
+
+static struct plat_sci_port scif6_platform_data = {
+	.mapbase	= 0xe800a000,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 283, 284, 285, 282 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif6_device = {
+	.name		= "sh-sci",
+	.id		= 6,
+	.dev		= {
+		.platform_data	= &scif6_platform_data,
+	},
+};
+
+static struct plat_sci_port scif7_platform_data = {
+	.mapbase	= 0xe800a800,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.scscr		= SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+			  SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type		= PORT_SCIF,
+	.irqs		=  { 287, 288, 289, 286 },
+	.regtype	= SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif7_device = {
+	.name		= "sh-sci",
+	.id		= 7,
+	.dev		= {
+		.platform_data	= &scif7_platform_data,
+	},
+};
+
+static struct sh_timer_config cmt0_platform_data = {
+	.channel_offset = 0x02,
+	.timer_bit = 0,
+	.clockevent_rating = 125,
+	.clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt0_resources[] = {
+	[0] = {
+		.start	= 0xfffec002,
+		.end	= 0xfffec007,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 188,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cmt0_device = {
+	.name		= "sh_cmt",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &cmt0_platform_data,
+	},
+	.resource	= cmt0_resources,
+	.num_resources	= ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+	.channel_offset = 0x08,
+	.timer_bit = 1,
+	.clockevent_rating = 125,
+	.clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt1_resources[] = {
+	[0] = {
+		.start	= 0xfffec008,
+		.end	= 0xfffec00d,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 189,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cmt1_device = {
+	.name		= "sh_cmt",
+	.id		= 1,
+	.dev = {
+		.platform_data	= &cmt1_platform_data,
+	},
+	.resource	= cmt1_resources,
+	.num_resources	= ARRAY_SIZE(cmt1_resources),
+};
+
+static struct sh_timer_config mtu2_0_platform_data = {
+	.channel_offset = -0x80,
+	.timer_bit = 0,
+	.clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+	[0] = {
+		.start	= 0xfffe4300,
+		.end	= 0xfffe4326,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 192,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mtu2_0_device = {
+	.name		= "sh_mtu2",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &mtu2_0_platform_data,
+	},
+	.resource	= mtu2_0_resources,
+	.num_resources	= ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+	.channel_offset = -0x100,
+	.timer_bit = 1,
+	.clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+	[0] = {
+		.start	= 0xfffe4380,
+		.end	= 0xfffe4390,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 203,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mtu2_1_device = {
+	.name		= "sh_mtu2",
+	.id		= 1,
+	.dev = {
+		.platform_data	= &mtu2_1_platform_data,
+	},
+	.resource	= mtu2_1_resources,
+	.num_resources	= ARRAY_SIZE(mtu2_1_resources),
+};
+
+static struct resource rtc_resources[] = {
+	[0] = {
+		.start	= 0xfffe6000,
+		.end	= 0xfffe6000 + 0x30 - 1,
+		.flags	= IORESOURCE_IO,
+	},
+	[1] = {
+		/* Shared Period/Carry/Alarm IRQ */
+		.start	= 338,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device rtc_device = {
+	.name		= "sh-rtc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(rtc_resources),
+	.resource	= rtc_resources,
+};
+
+/* USB Host */
+static struct r8a66597_platdata r8a66597_data = {
+	.on_chip = 1,
+	.endian = 1,
+};
+
+static struct resource r8a66597_usb_host_resources[] = {
+	[0] = {
+		.start	= 0xe8010000,
+		.end	= 0xe80100e4,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 170,
+		.end	= 170,
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
+	},
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+	.name		= "r8a66597_hcd",
+	.id		= 0,
+	.dev = {
+		.dma_mask		= NULL,         /*  not use dma */
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &r8a66597_data,
+	},
+	.num_resources	= ARRAY_SIZE(r8a66597_usb_host_resources),
+	.resource	= r8a66597_usb_host_resources,
+};
+
+static struct platform_device *sh7269_devices[] __initdata = {
+	&scif0_device,
+	&scif1_device,
+	&scif2_device,
+	&scif3_device,
+	&scif4_device,
+	&scif5_device,
+	&scif6_device,
+	&scif7_device,
+	&cmt0_device,
+	&cmt1_device,
+	&mtu2_0_device,
+	&mtu2_1_device,
+	&rtc_device,
+	&r8a66597_usb_host_device,
+};
+
+static int __init sh7269_devices_setup(void)
+{
+	return platform_add_devices(sh7269_devices,
+				    ARRAY_SIZE(sh7269_devices));
+}
+arch_initcall(sh7269_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+	register_intc_controller(&intc_desc);
+}
+
+static struct platform_device *sh7269_early_devices[] __initdata = {
+	&scif0_device,
+	&scif1_device,
+	&scif2_device,
+	&scif3_device,
+	&scif4_device,
+	&scif5_device,
+	&scif6_device,
+	&scif7_device,
+	&cmt0_device,
+	&cmt1_device,
+	&mtu2_0_device,
+	&mtu2_1_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+	early_platform_add_devices(sh7269_early_devices,
+				   ARRAY_SIZE(sh7269_early_devices));
+}
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index f6a389c..262db6e 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -2,7 +2,7 @@
  * arch/sh/kernel/cpu/sh3/entry.S
  *
  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
- *  Copyright (C) 2003 - 2006  Paul Mundt
+ *  Copyright (C) 2003 - 2012  Paul Mundt
  *
  * 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
@@ -17,6 +17,7 @@
 #include <cpu/mmu_context.h>
 #include <asm/page.h>
 #include <asm/cache.h>
+#include <asm/thread_info.h>
 
 ! NOTE:
 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
@@ -114,22 +115,22 @@
 	.align	2
 ENTRY(tlb_miss_store)
 	bra	call_handle_tlbmiss
-	 mov	#1, r5
+	 mov	#FAULT_CODE_WRITE, r5
 
 	.align	2
 ENTRY(initial_page_write)
 	bra	call_handle_tlbmiss
-	 mov	#2, r5
+	 mov	#FAULT_CODE_INITIAL, r5
 
 	.align	2
 ENTRY(tlb_protection_violation_load)
 	bra	call_do_page_fault
-	 mov	#0, r5
+	 mov	#FAULT_CODE_PROT, r5
 
 	.align	2
 ENTRY(tlb_protection_violation_store)
 	bra	call_do_page_fault
-	 mov	#1, r5
+	 mov	#(FAULT_CODE_PROT | FAULT_CODE_WRITE), r5
 
 call_handle_tlbmiss:
 	mov.l	1f, r0
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index 2309618..03e4c96 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -14,6 +14,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/rtc.h>
 #include <cpu/serial.h>
 
@@ -75,7 +76,7 @@
 			  SCSCR_RE  | SCSCR_CKE1 | SCSCR_CKE0,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIF,
-	.irqs		= { 56, 56, 56 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x900)),
 	.ops		= &sh770x_sci_port_ops,
 	.regtype	= SCIx_SH7705_SCIF_REGTYPE,
 };
@@ -94,7 +95,7 @@
 	.scscr		= SCSCR_TIE | SCSCR_RIE | SCSCR_TE | SCSCR_RE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIF,
-	.irqs		= { 52, 52, 52 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x880)),
 	.ops		= &sh770x_sci_port_ops,
 	.regtype	= SCIx_SH7705_SCIF_REGTYPE,
 };
@@ -114,7 +115,7 @@
 		.flags  = IORESOURCE_IO,
 	},
 	[1] =	{
-		.start  = 20,
+		.start  = evt2irq(0x480),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -146,7 +147,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -174,7 +175,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -201,7 +202,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
index 3f3d5fe..ba26cd9 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
@@ -19,6 +19,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <cpu/serial.h>
 
 enum {
@@ -95,7 +96,7 @@
 		.flags  = IORESOURCE_IO,
 	},
 	[1] =	{
-		.start	= 20,
+		.start	= evt2irq(0x480),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -114,7 +115,7 @@
 	.scscr		= SCSCR_TE | SCSCR_RE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCI,
-	.irqs		= { 23, 23, 23, 0 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x4e0)),
 	.ops		= &sh770x_sci_port_ops,
 	.regshift	= 1,
 };
@@ -135,7 +136,7 @@
 	.scscr		= SCSCR_TE | SCSCR_RE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 56, 56, 56, 56 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x900)),
 	.ops		= &sh770x_sci_port_ops,
 	.regtype	= SCIx_SH3_SCIF_REGTYPE,
 };
@@ -157,7 +158,7 @@
 	.scscr		= SCSCR_TE | SCSCR_RE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_IRDA,
-	.irqs		= { 52, 52, 52, 52 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x880)),
 	.ops		= &sh770x_sci_port_ops,
 	.regshift	= 1,
 };
@@ -184,7 +185,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -212,7 +213,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -239,7 +240,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 78f6b01..93c9c5e 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -14,6 +14,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/rtc.h>
 
 enum {
@@ -77,7 +78,7 @@
 		.flags  = IORESOURCE_IO,
 	},
 	[1] =	{
-		.start  = 20,
+		.start  = evt2irq(0x480),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -103,7 +104,7 @@
 			  SCSCR_CKE1 | SCSCR_CKE0,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 52, 52, 52, 52 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x880)),
 };
 
 static struct platform_device scif0_device = {
@@ -121,7 +122,7 @@
 			  SCSCR_CKE1 | SCSCR_CKE0,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs           = { 56, 56, 56, 56 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
 };
 
 static struct platform_device scif1_device = {
@@ -145,7 +146,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -173,7 +174,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -200,7 +201,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
index 9492034..0c2f1b2 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/rtc.h>
 #include <cpu/serial.h>
 
@@ -30,7 +31,7 @@
 	},
 	[1] = {
 		/* Shared Period/Carry/Alarm IRQ */
-		.start	= 20,
+		.start	= evt2irq(0x480),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -55,7 +56,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIF,
-	.irqs		= { 80, 80, 80, 80 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xc00)),
 	.ops		= &sh7720_sci_port_ops,
 	.regtype	= SCIx_SH7705_SCIF_REGTYPE,
 };
@@ -74,7 +75,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIF,
-	.irqs           = { 81, 81, 81, 81 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
 	.ops		= &sh7720_sci_port_ops,
 	.regtype	= SCIx_SH7705_SCIF_REGTYPE,
 };
@@ -94,13 +95,14 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 67,
-		.end	= 67,
+		.start	= evt2irq(0xa60),
+		.end	= evt2irq(0xa60),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
 
 static u64 usb_ohci_dma_mask = 0xffffffffUL;
+
 static struct platform_device usb_ohci_device = {
 	.name		= "sh_ohci",
 	.id		= -1,
@@ -121,8 +123,8 @@
 	},
 	[1] = {
 		.name	= "sh_udc",
-		.start	= 65,
-		.end	= 65,
+		.start	= evt2irq(0xa20),
+		.end	= evt2irq(0xa20),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -152,7 +154,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -179,7 +181,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -206,7 +208,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -233,7 +235,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -260,7 +262,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -288,7 +290,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -316,7 +318,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -343,7 +345,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 971cf0f..0fbbd50 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -158,6 +158,9 @@
 		case 0x40: /* yon-ten-go */
 			boot_cpu_data.type = CPU_SH7372;
 			break;
+		case 0xE0: /* 0x4E0 */
+			boot_cpu_data.type = CPU_SH7734; /* SH7733/SH7734 */
+			break;
 
 		}
 		break;
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
index 5b28331..2a5320a 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -13,6 +13,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -21,7 +22,10 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 40, 41, 43, 42 },
+	.irqs		= { evt2irq(0x700),
+			    evt2irq(0x720),
+			    evt2irq(0x760),
+			    evt2irq(0x740) },
 };
 
 static struct platform_device scif0_device = {
@@ -45,7 +49,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -73,7 +77,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -100,7 +104,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index 98cc0c7..04a4551 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -13,6 +13,7 @@
 #include <linux/serial.h>
 #include <linux/io.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/serial_sci.h>
 #include <generated/machtypes.h>
 
@@ -24,7 +25,7 @@
 	},
 	[1] = {
 		/* Shared Period/Carry/Alarm IRQ */
-		.start	= 20,
+		.start	= evt2irq(0x480),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -43,7 +44,7 @@
 	.scscr		= SCSCR_TE | SCSCR_RE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCI,
-	.irqs		= { 23, 23, 23, 0 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x4e0)),
 	.regshift	= 2,
 };
 
@@ -61,7 +62,7 @@
 	.scscr		= SCSCR_TE | SCSCR_RE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 40, 40, 40, 40 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x700)),
 };
 
 static struct platform_device scif_device = {
@@ -85,7 +86,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -113,7 +114,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -140,7 +141,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -172,7 +173,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 72,
+		.start	= evt2irq(0xb00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -199,7 +200,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 76,
+		.start	= evt2irq(0xb80),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index c0b4c77..98e075a 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/serial_sci.h>
 #include <linux/io.h>
 
@@ -132,7 +133,10 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 52, 53, 55, 54 },
+	.irqs		= { evt2irq(0x880),
+			    evt2irq(0x8a0),
+			    evt2irq(0x8e0),
+			    evt2irq(0x8c0) },
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -150,7 +154,10 @@
 	.type		= PORT_SCIF,
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
-	.irqs		= { 72, 73, 75, 74 },
+	.irqs		= { evt2irq(0xb00),
+			    evt2irq(0xb20),
+			    evt2irq(0xb60),
+			    evt2irq(0xb40) },
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -168,7 +175,10 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 76, 77, 79, 78 },
+	.irqs		= { evt2irq(0xb80),
+			    evt2irq(0xba0),
+			    evt2irq(0xbe0),
+			    evt2irq(0xbc0) },
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -186,7 +196,9 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCI,
-	.irqs		= { 80, 81, 82, 0 },
+	.irqs		= { evt2irq(0xc00),
+			    evt2irq(0xc20),
+			    evt2irq(0xc40), },
 	.regshift	= 2,
 };
 
@@ -211,7 +223,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -239,7 +251,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -266,7 +278,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index 0b22d10..8fc6ec2 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_CPU_SUBTYPE_SH7722)	+= setup-sh7722.o serial-sh7722.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7723)	+= setup-sh7723.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7724)	+= setup-sh7724.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7734)	+= setup-sh7734.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7366)	+= setup-sh7366.o
 obj-$(CONFIG_CPU_SUBTYPE_SHX3)		+= setup-shx3.o intc-shx3.o
 
@@ -30,6 +31,7 @@
 clock-$(CONFIG_CPU_SUBTYPE_SH7722)	:= clock-sh7722.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7723)	:= clock-sh7723.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7724)	:= clock-sh7724.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7734)	:= clock-sh7734.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7366)	:= clock-sh7366.o
 clock-$(CONFIG_CPU_SUBTYPE_SHX3)	:= clock-shx3.o
 
@@ -37,6 +39,7 @@
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7722)	:= pinmux-sh7722.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7723)	:= pinmux-sh7723.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7724)	:= pinmux-sh7724.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7734)	:= pinmux-sh7734.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7757)	:= pinmux-sh7757.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)	:= pinmux-sh7785.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)	:= pinmux-sh7786.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
new file mode 100644
index 0000000..1697642
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
@@ -0,0 +1,266 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7734.c
+ *
+ * Clock framework for SH7734
+ *
+ * Copyright (C) 2011, 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ * Copyright (C) 2011, 2012 Renesas Solutions Corp.
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+
+static struct clk extal_clk = {
+	.rate       = 33333333,
+};
+
+#define MODEMR          (0xFFCC0020)
+#define MODEMR_MASK     (0x6)
+#define MODEMR_533MHZ   (0x2)
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+	int mode = 12;
+	u32 r = __raw_readl(MODEMR);
+
+	if ((r & MODEMR_MASK) & MODEMR_533MHZ)
+		mode = 16;
+
+	return clk->parent->rate * mode;
+}
+
+static struct sh_clk_ops pll_clk_ops = {
+	.recalc		= pll_recalc,
+};
+
+static struct clk pll_clk = {
+	.ops        = &pll_clk_ops,
+	.parent     = &extal_clk,
+	.flags      = CLK_ENABLE_ON_INIT,
+};
+
+static struct clk *main_clks[] = {
+	&extal_clk,
+	&pll_clk,
+};
+
+static int multipliers[] = { 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int divisors[] = { 1, 3, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+	.divisors = divisors,
+	.nr_divisors = ARRAY_SIZE(divisors),
+	.multipliers = multipliers,
+	.nr_multipliers = ARRAY_SIZE(multipliers),
+};
+
+static struct clk_div4_table div4_table = {
+	.div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_I, DIV4_S, DIV4_B, DIV4_M, DIV4_S1, DIV4_P, DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+	SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
+
+struct clk div4_clks[DIV4_NR] = {
+	[DIV4_I] = DIV4(FRQMR1, 28, 0x0003, CLK_ENABLE_ON_INIT),
+	[DIV4_S] = DIV4(FRQMR1, 20, 0x000C, CLK_ENABLE_ON_INIT),
+	[DIV4_B] = DIV4(FRQMR1, 16, 0x0140, CLK_ENABLE_ON_INIT),
+	[DIV4_M] = DIV4(FRQMR1, 12, 0x0004, CLK_ENABLE_ON_INIT),
+	[DIV4_S1] = DIV4(FRQMR1, 4, 0x0030, CLK_ENABLE_ON_INIT),
+	[DIV4_P] = DIV4(FRQMR1, 0, 0x0140, CLK_ENABLE_ON_INIT),
+};
+
+#define MSTPCR0	0xFFC80030
+#define MSTPCR1	0xFFC80034
+#define MSTPCR3	0xFFC8003C
+
+enum {
+	MSTP030, MSTP029, /* IIC */
+	MSTP026, MSTP025, MSTP024, /* SCIF */
+	MSTP023,
+	MSTP022, MSTP021,
+	MSTP019, /* HSCIF */
+	MSTP016, MSTP015, MSTP014, /* TMU / TIMER */
+	MSTP012, MSTP011, MSTP010, MSTP009, MSTP008, /* SSI */
+	MSTP007, /* HSPI */
+	MSTP115, /* ADMAC */
+	MSTP114, /* GETHER */
+	MSTP111, /* DMAC */
+	MSTP109, /* VIDEOIN1 */
+	MSTP108, /* VIDEOIN0 */
+	MSTP107, /* RGPVBG */
+	MSTP106, /* 2DG */
+	MSTP103, /* VIEW */
+	MSTP100, /* USB */
+	MSTP331, /* MMC */
+	MSTP330, /* MIMLB */
+	MSTP323, /* SDHI0 */
+	MSTP322, /* SDHI1 */
+	MSTP321, /* SDHI2 */
+	MSTP320, /* RQSPI */
+	MSTP319, /* SRC0 */
+	MSTP318, /* SRC1 */
+	MSTP317, /* RSPI */
+	MSTP316, /* RCAN0 */
+	MSTP315, /* RCAN1 */
+	MSTP314, /* FLTCL */
+	MSTP313, /* ADC */
+	MSTP312, /* MTU */
+	MSTP304, /* IE-BUS */
+	MSTP303, /* RTC */
+	MSTP302, /* HIF */
+	MSTP301, /* STIF0 */
+	MSTP300, /* STIF1 */
+	MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+	/* MSTPCR0 */
+	[MSTP030] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 30, 0),
+	[MSTP029] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 29, 0),
+	[MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
+	[MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
+	[MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
+	[MSTP023] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
+	[MSTP022] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
+	[MSTP021] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
+	[MSTP019] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
+	[MSTP016] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 16, 0),
+	[MSTP015] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
+	[MSTP014] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 14, 0),
+	[MSTP012] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 12, 0),
+	[MSTP011] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
+	[MSTP010] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
+	[MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
+	[MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
+	[MSTP007] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
+
+	/* MSTPCR1 */
+	[MSTP115] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 15, 0),
+	[MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
+	[MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0),
+	[MSTP109] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
+	[MSTP108] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 8, 0),
+	[MSTP107] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 7, 0),
+	[MSTP106] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 6, 0),
+	[MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0),
+	[MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 0, 0),
+
+	/* MSTPCR3 */
+	[MSTP331] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 31, 0),
+	[MSTP330] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 30, 0),
+	[MSTP323] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 23, 0),
+	[MSTP322] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 22, 0),
+	[MSTP321] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 21, 0),
+	[MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 20, 0),
+	[MSTP319] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 19, 0),
+	[MSTP318] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 18, 0),
+	[MSTP317] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 17, 0),
+	[MSTP316] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 16, 0),
+	[MSTP315] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 15, 0),
+	[MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 14, 0),
+	[MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 13, 0),
+	[MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 12, 0),
+	[MSTP304] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  4, 0),
+	[MSTP303] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  3, 0),
+	[MSTP302] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  2, 0),
+	[MSTP301] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  1, 0),
+	[MSTP300] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  0, 0),
+};
+
+static struct clk_lookup lookups[] = {
+	/* main clocks */
+	CLKDEV_CON_ID("extal", &extal_clk),
+	CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+	/* clocks */
+	CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+	CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_S]),
+	CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_M]),
+	CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+	CLKDEV_CON_ID("shyway_clk1", &div4_clks[DIV4_S1]),
+	CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+
+	/* MSTP32 clocks */
+	CLKDEV_DEV_ID("i2c-sh7734.0", &mstp_clks[MSTP030]),
+	CLKDEV_DEV_ID("i2c-sh7734.1", &mstp_clks[MSTP029]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP026]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP024]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP023]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP022]),
+	CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP021]),
+	CLKDEV_CON_ID("hscif", &mstp_clks[MSTP019]),
+	CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP016]),
+	CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP016]),
+	CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[MSTP016]),
+	CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[MSTP015]),
+	CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[MSTP015]),
+	CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[MSTP015]),
+	CLKDEV_ICK_ID("tmu_fck", "sh_tmu.6", &mstp_clks[MSTP014]),
+	CLKDEV_ICK_ID("tmu_fck", "sh_tmu.7", &mstp_clks[MSTP014]),
+	CLKDEV_ICK_ID("tmu_fck", "sh_tmu.8", &mstp_clks[MSTP014]),
+	CLKDEV_CON_ID("ssi0", &mstp_clks[MSTP012]),
+	CLKDEV_CON_ID("ssi1", &mstp_clks[MSTP011]),
+	CLKDEV_CON_ID("ssi2", &mstp_clks[MSTP010]),
+	CLKDEV_CON_ID("ssi3", &mstp_clks[MSTP009]),
+	CLKDEV_CON_ID("sss", &mstp_clks[MSTP008]),
+	CLKDEV_CON_ID("hspi", &mstp_clks[MSTP007]),
+	CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP100]),
+	CLKDEV_CON_ID("videoin0", &mstp_clks[MSTP109]),
+	CLKDEV_CON_ID("videoin1", &mstp_clks[MSTP108]),
+	CLKDEV_CON_ID("rgpvg", &mstp_clks[MSTP107]),
+	CLKDEV_CON_ID("2dg", &mstp_clks[MSTP106]),
+	CLKDEV_CON_ID("view", &mstp_clks[MSTP103]),
+
+	CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP331]),
+	CLKDEV_CON_ID("mimlb0", &mstp_clks[MSTP330]),
+	CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP323]),
+	CLKDEV_CON_ID("sdhi1", &mstp_clks[MSTP322]),
+	CLKDEV_CON_ID("sdhi2", &mstp_clks[MSTP321]),
+	CLKDEV_CON_ID("rqspi0", &mstp_clks[MSTP320]),
+	CLKDEV_CON_ID("src0", &mstp_clks[MSTP319]),
+	CLKDEV_CON_ID("src1", &mstp_clks[MSTP318]),
+	CLKDEV_CON_ID("rsp0", &mstp_clks[MSTP317]),
+	CLKDEV_CON_ID("rcan0", &mstp_clks[MSTP316]),
+	CLKDEV_CON_ID("rcan1", &mstp_clks[MSTP315]),
+	CLKDEV_CON_ID("fltcl0", &mstp_clks[MSTP314]),
+	CLKDEV_CON_ID("adc0", &mstp_clks[MSTP313]),
+	CLKDEV_CON_ID("mtu0", &mstp_clks[MSTP312]),
+	CLKDEV_CON_ID("iebus0", &mstp_clks[MSTP304]),
+	CLKDEV_DEV_ID("sh-eth.0", &mstp_clks[MSTP114]),
+	CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP303]),
+	CLKDEV_CON_ID("hif0", &mstp_clks[MSTP302]),
+	CLKDEV_CON_ID("stif0", &mstp_clks[MSTP301]),
+	CLKDEV_CON_ID("stif1", &mstp_clks[MSTP300]),
+};
+
+int __init arch_clk_init(void)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < ARRAY_SIZE(main_clks); i++)
+		ret |= clk_register(main_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(lookups); i++)
+		clkdev_add(&lookups[i]);
+
+	if (!ret)
+		ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+			&div4_table);
+
+	if (!ret)
+		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+
+	return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c
new file mode 100644
index 0000000..eed3b9d
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c
@@ -0,0 +1,2497 @@
+/*
+ * SH7734 processor support - PFC hardware block
+ *
+ * Copyright (C) 2012  Renesas Solutions Corp.
+ * Copyright (C) 2012  Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@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/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/ioport.h>
+#include <cpu/sh7734.h>
+
+#define CPU_32_PORT(fn, pfx, sfx)				\
+	PORT_10(fn, pfx, sfx), PORT_10(fn, pfx##1, sfx),	\
+	PORT_10(fn, pfx##2, sfx), PORT_1(fn, pfx##30, sfx),	\
+	PORT_1(fn, pfx##31, sfx)
+
+#define CPU_32_PORT5(fn, pfx, sfx)				\
+	PORT_1(fn, pfx##0, sfx), PORT_1(fn, pfx##1, sfx),	\
+	PORT_1(fn, pfx##2, sfx), PORT_1(fn, pfx##3, sfx),	\
+	PORT_1(fn, pfx##4, sfx), PORT_1(fn, pfx##5, sfx),	\
+	PORT_1(fn, pfx##6, sfx), PORT_1(fn, pfx##7, sfx),	\
+	PORT_1(fn, pfx##8, sfx), PORT_1(fn, pfx##9, sfx),	\
+	PORT_1(fn, pfx##10, sfx), PORT_1(fn, pfx##11, sfx)
+
+/* GPSR0 - GPSR5 */
+#define CPU_ALL_PORT(fn, pfx, sfx)				\
+	CPU_32_PORT(fn, pfx##_0_, sfx),			\
+	CPU_32_PORT(fn, pfx##_1_, sfx),				\
+	CPU_32_PORT(fn, pfx##_2_, sfx),				\
+	CPU_32_PORT(fn, pfx##_3_, sfx),				\
+	CPU_32_PORT(fn, pfx##_4_, sfx),				\
+	CPU_32_PORT5(fn, pfx##_5_, sfx)
+
+#define _GP_GPIO(pfx, sfx) PINMUX_GPIO(GPIO_GP##pfx, GP##pfx##_DATA)
+#define _GP_DATA(pfx, sfx) PINMUX_DATA(GP##pfx##_DATA, GP##pfx##_FN,	\
+				       GP##pfx##_IN, GP##pfx##_OUT)
+
+#define _GP_INOUTSEL(pfx, sfx) GP##pfx##_IN, GP##pfx##_OUT
+#define _GP_INDT(pfx, sfx) GP##pfx##_DATA
+
+#define GP_ALL(str)	CPU_ALL_PORT(_PORT_ALL, GP, str)
+#define PINMUX_GPIO_GP_ALL()	CPU_ALL_PORT(_GP_GPIO, , unused)
+#define PINMUX_DATA_GP_ALL()	CPU_ALL_PORT(_GP_DATA, , unused)
+
+#define PORT_10_REV(fn, pfx, sfx)	\
+	PORT_1(fn, pfx##9, sfx), PORT_1(fn, pfx##8, sfx),	\
+	PORT_1(fn, pfx##7, sfx), PORT_1(fn, pfx##6, sfx),	\
+	PORT_1(fn, pfx##5, sfx), PORT_1(fn, pfx##4, sfx),	\
+	PORT_1(fn, pfx##3, sfx), PORT_1(fn, pfx##2, sfx),	\
+	PORT_1(fn, pfx##1, sfx), PORT_1(fn, pfx##0, sfx)
+
+#define CPU_32_PORT_REV(fn, pfx, sfx)	\
+	PORT_1(fn, pfx##31, sfx), PORT_1(fn, pfx##30, sfx),	\
+	PORT_10_REV(fn, pfx##2, sfx), PORT_10_REV(fn, pfx##1, sfx),	\
+	PORT_10_REV(fn, pfx, sfx)
+
+#define GP_INOUTSEL(bank) CPU_32_PORT_REV(_GP_INOUTSEL, _##bank##_, unused)
+#define GP_INDT(bank) CPU_32_PORT_REV(_GP_INDT, _##bank##_, unused)
+
+#define PINMUX_IPSR_DATA(ipsr, fn) PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##fn)
+#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) PINMUX_DATA(fn##_MARK, FN_##ms, \
+							  FN_##ipsr, FN_##fn)
+
+enum {
+	PINMUX_RESERVED = 0,
+
+	PINMUX_DATA_BEGIN,
+	GP_ALL(DATA), /* GP_0_0_DATA -> GP_5_11_DATA */
+	PINMUX_DATA_END,
+
+	PINMUX_INPUT_BEGIN,
+	GP_ALL(IN), /* GP_0_0_IN -> GP_5_11_IN */
+	PINMUX_INPUT_END,
+
+	PINMUX_OUTPUT_BEGIN,
+	GP_ALL(OUT), /* GP_0_0_OUT -> GP_5_11_OUT */
+	PINMUX_OUTPUT_END,
+
+	PINMUX_FUNCTION_BEGIN,
+	GP_ALL(FN), /* GP_0_0_FN -> GP_5_11_FN */
+
+	/* GPSR0 */
+	FN_IP1_9_8, FN_IP1_11_10, FN_IP1_13_12, FN_IP1_15_14,
+	FN_IP0_7_6, FN_IP0_9_8, FN_IP0_11_10, FN_IP0_13_12,
+	FN_IP0_15_14, FN_IP0_17_16, FN_IP0_19_18, FN_IP0_21_20,
+	FN_IP0_23_22, FN_IP0_25_24, FN_IP0_27_26, FN_IP0_29_28,
+	FN_IP0_31_30, FN_IP1_1_0, FN_IP1_3_2, FN_IP1_5_4,
+	FN_IP1_7_6, FN_IP11_28, FN_IP0_1_0, FN_IP0_3_2,
+	FN_IP0_5_4, FN_IP1_17_16, FN_IP1_19_18, FN_IP1_22_20,
+	FN_IP1_25_23, FN_IP1_28_26, FN_IP1_31_29, FN_IP2_2_0,
+
+	/* GPSR1 */
+	FN_IP3_20, FN_IP3_29_27, FN_IP11_20_19, FN_IP11_22_21,
+	FN_IP2_16_14, FN_IP2_19_17, FN_IP2_22_20, FN_IP2_24_23,
+	FN_IP2_27_25, FN_IP2_30_28, FN_IP3_1_0, FN_CLKOUT,
+	FN_BS, FN_CS0, FN_IP3_2, FN_EX_CS0,
+	FN_IP3_5_3, FN_IP3_8_6, FN_IP3_11_9, FN_IP3_14_12,
+	FN_IP3_17_15, FN_RD, FN_IP3_19_18, FN_WE0,
+	FN_WE1, FN_IP2_4_3, FN_IP3_23_21, FN_IP3_26_24,
+	FN_IP2_7_5, FN_IP2_10_8, FN_IP2_13_11, FN_IP11_25_23,
+
+	/* GPSR2 */
+	FN_IP11_6_4, FN_IP11_9_7, FN_IP11_11_10, FN_IP4_2_0,
+	FN_IP8_29_28, FN_IP11_27_26, FN_IP8_22_20, FN_IP8_25_23,
+	FN_IP11_12, FN_IP8_27_26, FN_IP4_5_3, FN_IP4_8_6,
+	FN_IP4_11_9, FN_IP4_14_12, FN_IP4_17_15, FN_IP4_19_18,
+	FN_IP4_21_20, FN_IP4_23_22, FN_IP4_25_24, FN_IP4_27_26,
+	FN_IP4_29_28, FN_IP4_31_30, FN_IP5_2_0, FN_IP5_5_3,
+	FN_IP5_8_6, FN_IP5_11_9, FN_IP5_14_12, FN_IP5_17_15,
+	FN_IP5_20_18, FN_IP5_22_21, FN_IP5_24_23, FN_IP5_26_25,
+
+	/* GPSR3 */
+	FN_IP6_2_0, FN_IP6_5_3, FN_IP6_7_6, FN_IP6_9_8,
+	FN_IP6_11_10, FN_IP6_13_12, FN_IP6_15_14, FN_IP6_17_16,
+	FN_IP6_20_18, FN_IP6_23_21, FN_IP7_2_0, FN_IP7_5_3,
+	FN_IP7_8_6, FN_IP7_11_9, FN_IP7_14_12, FN_IP7_17_15,
+	FN_IP7_20_18, FN_IP7_23_21, FN_IP7_26_24, FN_IP7_28_27,
+	FN_IP7_30_29, FN_IP8_1_0, FN_IP8_3_2, FN_IP8_5_4,
+	FN_IP8_7_6, FN_IP8_9_8, FN_IP8_11_10, FN_IP8_13_12,
+	FN_IP8_15_14, FN_IP8_17_16, FN_IP8_19_18, FN_IP9_1_0,
+
+	/* GPSR4 */
+	FN_IP9_19_18, FN_IP9_21_20, FN_IP9_23_22, FN_IP9_25_24,
+	FN_IP9_11_10, FN_IP9_13_12, FN_IP9_15_14, FN_IP9_17_16,
+	FN_IP9_3_2, FN_IP9_5_4, FN_IP9_7_6, FN_IP9_9_8,
+	FN_IP9_27_26, FN_IP9_29_28, FN_IP10_2_0, FN_IP10_5_3,
+	FN_IP10_8_6, FN_IP10_11_9, FN_IP10_14_12, FN_IP10_15,
+	FN_IP10_18_16, FN_IP10_21_19, FN_IP11_0, FN_IP11_1,
+	FN_SCL0, FN_IP11_2, FN_PENC0, FN_IP11_15_13, /* Need check*/
+	FN_USB_OVC0, FN_IP11_18_16,
+	FN_IP10_22, FN_IP10_24_23,
+
+	/* GPSR5 */
+	FN_IP10_25, FN_IP11_3, FN_IRQ2_B, FN_IRQ3_B,
+	FN_IP10_27_26, /* 10 */
+	FN_IP10_29_28, /* 11 */
+
+	/* IPSR0 */
+	FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A, FN_TIOC3D_C,
+	FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C,
+	FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C,
+	FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C,
+	FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
+	FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
+	FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
+	FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
+	FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
+	FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
+	FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
+	FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
+	FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
+	FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
+	FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
+	FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C,
+
+	/* IPSR1 */
+	FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6, FN_FD3_A,
+	FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5, FN_FD2_A,
+	FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4, FN_FD1_A,
+	FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3, FN_FD0_A,
+	FN_A25, FN_TX2_D, FN_ST1_D2,
+	FN_A24, FN_RX2_D, FN_ST1_D1,
+	FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A,
+	FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A,
+	FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A,
+	FN_A20, FN_ST1_REQ, FN_LCD_FLM_A,
+	FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A,	FN_TIOC4D_C,
+	FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
+	FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A,	FN_TIOC4B_C,
+	FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C,
+
+	/* IPSR2 */
+	FN_D14, FN_TX2_B, FN_FSE_A, FN_ET0_TX_CLK_B,
+	FN_D13, FN_RX2_B, FN_FRB_A,	FN_ET0_ETXD6_B,
+	FN_D12, FN_FWE_A, FN_ET0_ETXD5_B,
+	FN_D11, FN_RSPI_MISO_A, FN_QMI_QIO1_A, FN_FRE_A,
+		FN_ET0_ETXD3_B,
+	FN_D10, FN_RSPI_MOSI_A, FN_QMO_QIO0_A, FN_FALE_A,
+		FN_ET0_ETXD2_B,
+	FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A, FN_FCLE_A,
+		FN_ET0_ETXD1_B,
+	FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A, FN_FCE_A,
+		FN_ET0_GTX_CLK_B,
+	FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A, FN_FD7_A,
+	FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A, FN_FD6_A,
+	FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
+	FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7, FN_FD4_A,
+
+	/* IPSR3 */
+	FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A, FN_ET0_ETXD7,
+	FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
+		FN_ET0_MAGIC_C, FN_ET0_ETXD6_A,
+	FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
+		FN_ET0_LINK_C, FN_ET0_ETXD5_A,
+	FN_EX_WAIT0, FN_TCLK1_B,
+	FN_RD_WR, FN_TCLK0, FN_CAN_CLK_B, FN_ET0_ETXD4,
+	FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B, FN_ET0_ETXD3_A,
+	FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B, FN_ET0_ETXD2_A,
+	FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B, FN_ET0_ETXD1_A,
+	FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B, FN_ET0_GTX_CLK_A,
+	FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B, FN_ET0_ETXD0,
+	FN_CS1_A26, FN_QIO3_B,
+	FN_D15, FN_SCK2_B,
+
+	/* IPSR4 */
+	FN_SCK2_A, FN_VI0_G3,
+	FN_RTS1_B, FN_VI0_G2,
+	FN_CTS1_B, FN_VI0_DATA7_VI0_G1,
+	FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
+	FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
+	FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
+	FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
+	FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A, FN_ET0_MDC,
+	FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A, FN_ET0_COL,
+	FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A, FN_ET0_CRS,
+	FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A, FN_ET0_RX_ER,
+	FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A, FN_ET0_RX_DV,
+	FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A, FN_ET0_ERXD7,
+
+	/* IPSR5 */
+	FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, FN_ET0_RX_CLK_B,
+	FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, FN_ET0_ERXD2_B,
+	FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, FN_ET0_ERXD3_B,
+	FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, FN_ET0_MDIO_B,
+	FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, FN_ET0_LINK_B,
+	FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, FN_ET0_MAGIC_B,
+	FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, FN_ET0_PHY_INT_B,
+	FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5,
+	FN_REF125CK, FN_ADTRG, FN_RX5_C,
+	FN_REF50CK, FN_CTS1_E, FN_HCTS0_D,
+
+	/* IPSR6 */
+	FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A, FN_TCLKA_A, FN_HIFD00,
+	FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A, FN_TCLKB_A, FN_HIFD01,
+	FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
+	FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
+	FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
+	FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
+	FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
+	FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
+	FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A, FN_TIOC1A_A, FN_HIFD08,
+	FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A, FN_HIFD09,
+
+	/* IPSR7 */
+	FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A, FN_HIFD10,
+	FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A, FN_HIFD11,
+	FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A, FN_HIFD12,
+	FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A, FN_HIFD13,
+	FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A, FN_HIFD14,
+	FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A, FN_HIFD15,
+	FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A, FN_HIFCS,
+	FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A, FN_HIFRS,
+	FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A, FN_HIFWR,
+	FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
+	FN_DU0_DB4, FN_HIFINT,
+
+	/* IPSR8 */
+	FN_DU0_DB5, FN_HIFDREQ,
+	FN_DU0_DB6, FN_HIFRDY,
+	FN_DU0_DB7, FN_SSI_SCK0_B, FN_HIFEBL_B,
+	FN_DU0_DOTCLKIN, FN_HSPI_CS0_C, FN_SSI_WS0_B,
+	FN_DU0_DOTCLKOUT, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
+	FN_DU0_EXHSYNC_DU0_HSYNC, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
+	FN_DU0_EXVSYNC_DU0_VSYNC, FN_HSPI_RX0_C, FN_SSI_WS1_B,
+	FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B, FN_SSI_SDATA1_B,
+	FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
+	FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
+	FN_IRQ0_A, FN_HSPI_TX_B, FN_RX3_E, FN_ET0_ERXD0,
+	FN_IRQ1_A, FN_HSPI_RX_B, FN_TX3_E, FN_ET0_ERXD1,
+	FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
+	FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
+
+	/* IPSR9 */
+	FN_VI1_CLK_A, FN_FD0_B, FN_LCD_DATA0_B,
+	FN_VI1_0_A, FN_FD1_B, FN_LCD_DATA1_B,
+	FN_VI1_1_A, FN_FD2_B, FN_LCD_DATA2_B,
+	FN_VI1_2_A, FN_FD3_B, FN_LCD_DATA3_B,
+	FN_VI1_3_A, FN_FD4_B, FN_LCD_DATA4_B,
+	FN_VI1_4_A, FN_FD5_B, FN_LCD_DATA5_B,
+	FN_VI1_5_A, FN_FD6_B, FN_LCD_DATA6_B,
+	FN_VI1_6_A, FN_FD7_B, FN_LCD_DATA7_B,
+	FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B,
+	FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B,
+	FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B,
+	FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
+	FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
+	FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B,
+	FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B,
+
+	/* IPSR10 */
+	FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B, FN_LCD_DATA15_B,
+	FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B, FN_LCD_DON_B,
+	FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B, FN_LCD_CL1_B,
+	FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B, FN_LCD_CL2_B,
+	FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B, FN_LCD_FLM_B,
+	FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
+	FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B, FN_LCD_VEPWC_B,
+	FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B, FN_LCD_M_DISP_B,
+	FN_CAN_CLK_A, FN_RX4_D,
+	FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK,
+	FN_CAN1_RX_A, FN_IRQ1_B,
+	FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG,
+	FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT,
+
+	/* IPSR11 */
+	FN_SCL1, FN_SCIF_CLK_C,
+	FN_SDA1, FN_RX1_E,
+	FN_SDA0, FN_HIFEBL_A,
+	FN_SDSELF, FN_RTS1_E,
+	FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A, FN_ET0_ERXD4,
+	FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A, FN_ET0_ERXD5,
+	FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
+	FN_TX0_A, FN_HSPI_TX_A,
+	FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D, FN_IETX_B,
+	FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D, FN_IERX_B,
+	FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN,
+	FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER,
+	FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C, FN_ET0_TX_CLK_A,
+	FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
+	FN_PRESETOUT, FN_ST_CLKOUT,
+
+	/* MOD_SEL1 */
+	FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
+	FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
+	FN_SEL_VIN1_0, FN_SEL_VIN1_1,
+	FN_SEL_HIF_0, FN_SEL_HIF_1,
+	FN_SEL_RSPI_0, FN_SEL_RSPI_1,
+	FN_SEL_LCDC_0, FN_SEL_LCDC_1,
+	FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2,
+	FN_SEL_ET0_0, FN_SEL_ET0_1,
+	FN_SEL_RMII_0, FN_SEL_RMII_1,
+	FN_SEL_TMU_0, FN_SEL_TMU_1,
+	FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2,
+	FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
+	FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
+	FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2,
+	FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
+	FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
+	FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
+	FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
+	FN_SEL_SSI1_0, FN_SEL_SSI1_1,
+	FN_SEL_SSI0_0, FN_SEL_SSI0_1,
+	FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
+	FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
+	FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
+	FN_SEL_MMC_0, FN_SEL_MMC_1,
+	FN_SEL_INTC_0, FN_SEL_INTC_1,
+
+	/* MOD_SEL2 */
+	FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
+	FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
+	FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
+	FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2,
+	FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2,
+	FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
+	FN_SEL_SCIF5_0, FN_SEL_SCIF5_1,
+	FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+	FN_SEL_SCIF4_0, FN_SEL_SCIF4_1,
+	FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+	FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2,
+		FN_SEL_SCIF3_3, FN_SEL_SCIF3_4,
+	FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2,
+		FN_SEL_SCIF2_3,
+	FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2,
+		FN_SEL_SCIF1_3, FN_SEL_SCIF1_4,
+	FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2,
+	FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2,
+
+	PINMUX_FUNCTION_END,
+
+	PINMUX_MARK_BEGIN,
+
+	CLKOUT_MARK, BS_MARK, CS0_MARK, EX_CS0_MARK, RD_MARK,
+	WE0_MARK, WE1_MARK,
+
+	SCL0_MARK, PENC0_MARK, USB_OVC0_MARK,
+
+	IRQ2_B_MARK, IRQ3_B_MARK,
+
+	/* IPSR0 */
+	A15_MARK, ST0_VCO_CLKIN_MARK, LCD_DATA15_A_MARK, TIOC3D_C_MARK,
+	A14_MARK, LCD_DATA14_A_MARK, TIOC3C_C_MARK,
+	A13_MARK, LCD_DATA13_A_MARK, TIOC3B_C_MARK,
+	A12_MARK, LCD_DATA12_A_MARK, TIOC3A_C_MARK,
+	A11_MARK, ST0_D7_MARK, LCD_DATA11_A_MARK, TIOC2B_C_MARK,
+	A10_MARK, ST0_D6_MARK, LCD_DATA10_A_MARK, TIOC2A_C_MARK,
+	A9_MARK, ST0_D5_MARK, LCD_DATA9_A_MARK, TIOC1B_C_MARK,
+	A8_MARK, ST0_D4_MARK, LCD_DATA8_A_MARK, TIOC1A_C_MARK,
+	A7_MARK, ST0_D3_MARK, LCD_DATA7_A_MARK, TIOC0D_C_MARK,
+	A6_MARK, ST0_D2_MARK, LCD_DATA6_A_MARK, TIOC0C_C_MARK,
+	A5_MARK, ST0_D1_MARK, LCD_DATA5_A_MARK, TIOC0B_C_MARK,
+	A4_MARK, ST0_D0_MARK, LCD_DATA4_A_MARK, TIOC0A_C_MARK,
+	A3_MARK, ST0_VLD_MARK, LCD_DATA3_A_MARK, TCLKD_C_MARK,
+	A2_MARK, ST0_SYC_MARK, LCD_DATA2_A_MARK, TCLKC_C_MARK,
+	A1_MARK, ST0_REQ_MARK, LCD_DATA1_A_MARK, TCLKB_C_MARK,
+	A0_MARK, ST0_CLKIN_MARK, LCD_DATA0_A_MARK, TCLKA_C_MARK,
+
+	/* IPSR1 */
+	D3_MARK, SD0_DAT3_A_MARK, MMC_D3_A_MARK, ST1_D6_MARK, FD3_A_MARK,
+	D2_MARK, SD0_DAT2_A_MARK, MMC_D2_A_MARK, ST1_D5_MARK, FD2_A_MARK,
+	D1_MARK, SD0_DAT1_A_MARK, MMC_D1_A_MARK, ST1_D4_MARK, FD1_A_MARK,
+	D0_MARK, SD0_DAT0_A_MARK, MMC_D0_A_MARK, ST1_D3_MARK, FD0_A_MARK,
+	A25_MARK, TX2_D_MARK, ST1_D2_MARK,
+	A24_MARK, RX2_D_MARK, ST1_D1_MARK,
+	A23_MARK, ST1_D0_MARK, LCD_M_DISP_A_MARK,
+	A22_MARK, ST1_VLD_MARK, LCD_VEPWC_A_MARK,
+	A21_MARK, ST1_SYC_MARK, LCD_VCPWC_A_MARK,
+	A20_MARK, ST1_REQ_MARK, LCD_FLM_A_MARK,
+	A19_MARK, ST1_CLKIN_MARK, LCD_CLK_A_MARK,	TIOC4D_C_MARK,
+	A18_MARK, ST1_PWM_MARK, LCD_CL2_A_MARK, TIOC4C_C_MARK,
+	A17_MARK, ST1_VCO_CLKIN_MARK, LCD_CL1_A_MARK, TIOC4B_C_MARK,
+	A16_MARK, ST0_PWM_MARK, LCD_DON_A_MARK, TIOC4A_C_MARK,
+
+	/* IPSR2 */
+	D14_MARK, TX2_B_MARK, FSE_A_MARK, ET0_TX_CLK_B_MARK,
+	D13_MARK, RX2_B_MARK, FRB_A_MARK, ET0_ETXD6_B_MARK,
+	D12_MARK, FWE_A_MARK, ET0_ETXD5_B_MARK,
+	D11_MARK, RSPI_MISO_A_MARK, QMI_QIO1_A_MARK, FRE_A_MARK,
+		ET0_ETXD3_B_MARK,
+	D10_MARK, RSPI_MOSI_A_MARK, QMO_QIO0_A_MARK, FALE_A_MARK,
+		ET0_ETXD2_B_MARK,
+	D9_MARK, SD0_CMD_A_MARK, MMC_CMD_A_MARK, QIO3_A_MARK,
+		FCLE_A_MARK, ET0_ETXD1_B_MARK,
+	D8_MARK, SD0_CLK_A_MARK, MMC_CLK_A_MARK, QIO2_A_MARK,
+		FCE_A_MARK, ET0_GTX_CLK_B_MARK,
+	D7_MARK, RSPI_SSL_A_MARK, MMC_D7_A_MARK, QSSL_A_MARK,
+		FD7_A_MARK,
+	D6_MARK, RSPI_RSPCK_A_MARK, MMC_D6_A_MARK, QSPCLK_A_MARK,
+		FD6_A_MARK,
+	D5_MARK, SD0_WP_A_MARK, MMC_D5_A_MARK, FD5_A_MARK,
+	D4_MARK, SD0_CD_A_MARK, MMC_D4_A_MARK, ST1_D7_MARK,
+		FD4_A_MARK,
+
+	/* IPSR3 */
+	DRACK0_MARK, SD1_DAT2_A_MARK, ATAG_MARK, TCLK1_A_MARK, ET0_ETXD7_MARK,
+	EX_WAIT2_MARK, SD1_DAT1_A_MARK, DACK2_MARK, CAN1_RX_C_MARK,
+		ET0_MAGIC_C_MARK, ET0_ETXD6_A_MARK,
+	EX_WAIT1_MARK, SD1_DAT0_A_MARK, DREQ2_MARK, CAN1_TX_C_MARK,
+		ET0_LINK_C_MARK, ET0_ETXD5_A_MARK,
+	EX_WAIT0_MARK, TCLK1_B_MARK,
+	RD_WR_MARK, TCLK0_MARK, CAN_CLK_B_MARK, ET0_ETXD4_MARK,
+	EX_CS5_MARK, SD1_CMD_A_MARK, ATADIR_MARK, QSSL_B_MARK,
+		ET0_ETXD3_A_MARK,
+	EX_CS4_MARK, SD1_WP_A_MARK, ATAWR_MARK, QMI_QIO1_B_MARK,
+		ET0_ETXD2_A_MARK,
+	EX_CS3_MARK, SD1_CD_A_MARK, ATARD_MARK, QMO_QIO0_B_MARK,
+		ET0_ETXD1_A_MARK,
+	EX_CS2_MARK, TX3_B_MARK, ATACS1_MARK, QSPCLK_B_MARK,
+		ET0_GTX_CLK_A_MARK,
+	EX_CS1_MARK, RX3_B_MARK, ATACS0_MARK, QIO2_B_MARK,
+		ET0_ETXD0_MARK,
+	CS1_A26_MARK, QIO3_B_MARK,
+	D15_MARK, SCK2_B_MARK,
+
+	/* IPSR4 */
+	SCK2_A_MARK, VI0_G3_MARK,
+	RTS1_B_MARK, VI0_G2_MARK,
+	CTS1_B_MARK, VI0_DATA7_VI0_G1_MARK,
+	TX1_B_MARK, VI0_DATA6_VI0_G0_MARK, ET0_PHY_INT_A_MARK,
+	RX1_B_MARK, VI0_DATA5_VI0_B5_MARK, ET0_MAGIC_A_MARK,
+	SCK1_B_MARK, VI0_DATA4_VI0_B4_MARK, ET0_LINK_A_MARK,
+	RTS0_B_MARK, VI0_DATA3_VI0_B3_MARK, ET0_MDIO_A_MARK,
+	CTS0_B_MARK, VI0_DATA2_VI0_B2_MARK, RMII0_MDIO_A_MARK,
+		ET0_MDC_MARK,
+	HTX0_A_MARK, TX1_A_MARK, VI0_DATA1_VI0_B1_MARK,
+		RMII0_MDC_A_MARK, ET0_COL_MARK,
+	HRX0_A_MARK, RX1_A_MARK, VI0_DATA0_VI0_B0_MARK,
+		RMII0_CRS_DV_A_MARK, ET0_CRS_MARK,
+	HSCK0_A_MARK, SCK1_A_MARK, VI0_VSYNC_MARK,
+		RMII0_RX_ER_A_MARK, ET0_RX_ER_MARK,
+	HRTS0_A_MARK, RTS1_A_MARK, VI0_HSYNC_MARK,
+		RMII0_TXD_EN_A_MARK, ET0_RX_DV_MARK,
+	HCTS0_A_MARK, CTS1_A_MARK, VI0_FIELD_MARK,
+		RMII0_RXD1_A_MARK, ET0_ERXD7_MARK,
+
+	/* IPSR5 */
+	SD2_CLK_A_MARK, RX2_A_MARK, VI0_G4_MARK, ET0_RX_CLK_B_MARK,
+	SD2_CMD_A_MARK, TX2_A_MARK, VI0_G5_MARK, ET0_ERXD2_B_MARK,
+	SD2_DAT0_A_MARK, RX3_A_MARK, VI0_R0_MARK, ET0_ERXD3_B_MARK,
+	SD2_DAT1_A_MARK, TX3_A_MARK, VI0_R1_MARK, ET0_MDIO_B_MARK,
+	SD2_DAT2_A_MARK, RX4_A_MARK, VI0_R2_MARK, ET0_LINK_B_MARK,
+	SD2_DAT3_A_MARK, TX4_A_MARK, VI0_R3_MARK, ET0_MAGIC_B_MARK,
+	SD2_CD_A_MARK, RX5_A_MARK, VI0_R4_MARK, ET0_PHY_INT_B_MARK,
+	SD2_WP_A_MARK, TX5_A_MARK, VI0_R5_MARK,
+	REF125CK_MARK, ADTRG_MARK, RX5_C_MARK,
+	REF50CK_MARK, CTS1_E_MARK, HCTS0_D_MARK,
+
+	/* IPSR6 */
+	DU0_DR0_MARK, SCIF_CLK_B_MARK, HRX0_D_MARK, IETX_A_MARK,
+		TCLKA_A_MARK, HIFD00_MARK,
+	DU0_DR1_MARK, SCK0_B_MARK, HTX0_D_MARK, IERX_A_MARK,
+		TCLKB_A_MARK, HIFD01_MARK,
+	DU0_DR2_MARK, RX0_B_MARK, TCLKC_A_MARK, HIFD02_MARK,
+	DU0_DR3_MARK, TX0_B_MARK, TCLKD_A_MARK, HIFD03_MARK,
+	DU0_DR4_MARK, CTS0_C_MARK, TIOC0A_A_MARK, HIFD04_MARK,
+	DU0_DR5_MARK, RTS0_C_MARK, TIOC0B_A_MARK, HIFD05_MARK,
+	DU0_DR6_MARK, SCK1_C_MARK, TIOC0C_A_MARK, HIFD06_MARK,
+	DU0_DR7_MARK, RX1_C_MARK, TIOC0D_A_MARK, HIFD07_MARK,
+	DU0_DG0_MARK, TX1_C_MARK, HSCK0_D_MARK, IECLK_A_MARK,
+		TIOC1A_A_MARK, HIFD08_MARK,
+	DU0_DG1_MARK, CTS1_C_MARK, HRTS0_D_MARK, TIOC1B_A_MARK,
+		HIFD09_MARK,
+
+	/* IPSR7 */
+	DU0_DG2_MARK, RTS1_C_MARK, RMII0_MDC_B_MARK, TIOC2A_A_MARK,
+		HIFD10_MARK,
+	DU0_DG3_MARK, SCK2_C_MARK, RMII0_MDIO_B_MARK, TIOC2B_A_MARK,
+		HIFD11_MARK,
+	DU0_DG4_MARK, RX2_C_MARK, RMII0_CRS_DV_B_MARK, TIOC3A_A_MARK,
+		HIFD12_MARK,
+	DU0_DG5_MARK, TX2_C_MARK, RMII0_RX_ER_B_MARK, TIOC3B_A_MARK,
+		HIFD13_MARK,
+	DU0_DG6_MARK, RX3_C_MARK, RMII0_RXD0_B_MARK, TIOC3C_A_MARK,
+		HIFD14_MARK,
+	DU0_DG7_MARK, TX3_C_MARK, RMII0_RXD1_B_MARK, TIOC3D_A_MARK,
+		HIFD15_MARK,
+	DU0_DB0_MARK, RX4_C_MARK, RMII0_TXD_EN_B_MARK, TIOC4A_A_MARK,
+		HIFCS_MARK,
+	DU0_DB1_MARK, TX4_C_MARK, RMII0_TXD0_B_MARK, TIOC4B_A_MARK,
+		HIFRS_MARK,
+	DU0_DB2_MARK, RX5_B_MARK, RMII0_TXD1_B_MARK, TIOC4C_A_MARK,
+		HIFWR_MARK,
+	DU0_DB3_MARK, TX5_B_MARK, TIOC4D_A_MARK, HIFRD_MARK,
+	DU0_DB4_MARK, HIFINT_MARK,
+
+	/* IPSR8 */
+	DU0_DB5_MARK, HIFDREQ_MARK,
+	DU0_DB6_MARK, HIFRDY_MARK,
+	DU0_DB7_MARK, SSI_SCK0_B_MARK, HIFEBL_B_MARK,
+	DU0_DOTCLKIN_MARK, HSPI_CS0_C_MARK, SSI_WS0_B_MARK,
+	DU0_DOTCLKOUT_MARK, HSPI_CLK0_C_MARK, SSI_SDATA0_B_MARK,
+	DU0_EXHSYNC_DU0_HSYNC_MARK, HSPI_TX0_C_MARK, SSI_SCK1_B_MARK,
+	DU0_EXVSYNC_DU0_VSYNC_MARK, HSPI_RX0_C_MARK, SSI_WS1_B_MARK,
+	DU0_EXODDF_DU0_ODDF_MARK, CAN0_RX_B_MARK, HSCK0_B_MARK,
+		SSI_SDATA1_B_MARK,
+	DU0_DISP_MARK, CAN0_TX_B_MARK, HRX0_B_MARK, AUDIO_CLKA_B_MARK,
+	DU0_CDE_MARK, HTX0_B_MARK, AUDIO_CLKB_B_MARK, LCD_VCPWC_B_MARK,
+	IRQ0_A_MARK, HSPI_TX_B_MARK, RX3_E_MARK, ET0_ERXD0_MARK,
+	IRQ1_A_MARK, HSPI_RX_B_MARK, TX3_E_MARK, ET0_ERXD1_MARK,
+	IRQ2_A_MARK, CTS0_A_MARK, HCTS0_B_MARK, ET0_ERXD2_A_MARK,
+	IRQ3_A_MARK, RTS0_A_MARK, HRTS0_B_MARK, ET0_ERXD3_A_MARK,
+
+	/* IPSR9 */
+	VI1_CLK_A_MARK, FD0_B_MARK, LCD_DATA0_B_MARK,
+	VI1_0_A_MARK, FD1_B_MARK, LCD_DATA1_B_MARK,
+	VI1_1_A_MARK, FD2_B_MARK, LCD_DATA2_B_MARK,
+	VI1_2_A_MARK, FD3_B_MARK, LCD_DATA3_B_MARK,
+	VI1_3_A_MARK, FD4_B_MARK, LCD_DATA4_B_MARK,
+	VI1_4_A_MARK, FD5_B_MARK, LCD_DATA5_B_MARK,
+	VI1_5_A_MARK, FD6_B_MARK, LCD_DATA6_B_MARK,
+	VI1_6_A_MARK, FD7_B_MARK, LCD_DATA7_B_MARK,
+	VI1_7_A_MARK, FCE_B_MARK, LCD_DATA8_B_MARK,
+	SSI_SCK0_A_MARK, TIOC1A_B_MARK, LCD_DATA9_B_MARK,
+	SSI_WS0_A_MARK, TIOC1B_B_MARK, LCD_DATA10_B_MARK,
+	SSI_SDATA0_A_MARK, VI1_0_B_MARK, TIOC2A_B_MARK, LCD_DATA11_B_MARK,
+	SSI_SCK1_A_MARK, VI1_1_B_MARK, TIOC2B_B_MARK, LCD_DATA12_B_MARK,
+	SSI_WS1_A_MARK, VI1_2_B_MARK, LCD_DATA13_B_MARK,
+	SSI_SDATA1_A_MARK, VI1_3_B_MARK, LCD_DATA14_B_MARK,
+
+	/* IPSR10 */
+	SSI_SCK23_MARK, VI1_4_B_MARK, RX1_D_MARK, FCLE_B_MARK,
+		LCD_DATA15_B_MARK,
+	SSI_WS23_MARK, VI1_5_B_MARK, TX1_D_MARK, HSCK0_C_MARK,
+		FALE_B_MARK, LCD_DON_B_MARK,
+	SSI_SDATA2_MARK, VI1_6_B_MARK, HRX0_C_MARK, FRE_B_MARK,
+		LCD_CL1_B_MARK,
+	SSI_SDATA3_MARK, VI1_7_B_MARK, HTX0_C_MARK, FWE_B_MARK,
+		LCD_CL2_B_MARK,
+	AUDIO_CLKA_A_MARK, VI1_CLK_B_MARK, SCK1_D_MARK, IECLK_B_MARK,
+		LCD_FLM_B_MARK,
+	AUDIO_CLKB_A_MARK, LCD_CLK_B_MARK,
+	AUDIO_CLKC_MARK, SCK1_E_MARK, HCTS0_C_MARK, FRB_B_MARK,
+		LCD_VEPWC_B_MARK,
+	AUDIO_CLKOUT_MARK, TX1_E_MARK, HRTS0_C_MARK, FSE_B_MARK,
+		LCD_M_DISP_B_MARK,
+	CAN_CLK_A_MARK, RX4_D_MARK,
+	CAN0_TX_A_MARK, TX4_D_MARK, MLB_CLK_MARK,
+	CAN1_RX_A_MARK, IRQ1_B_MARK,
+	CAN0_RX_A_MARK, IRQ0_B_MARK, MLB_SIG_MARK,
+	CAN1_TX_A_MARK, TX5_C_MARK, MLB_DAT_MARK,
+
+	/* IPSR11 */
+	SCL1_MARK, SCIF_CLK_C_MARK,
+	SDA1_MARK, RX1_E_MARK,
+	SDA0_MARK, HIFEBL_A_MARK,
+	SDSELF_MARK, RTS1_E_MARK,
+	SCIF_CLK_A_MARK, HSPI_CLK_A_MARK, VI0_CLK_MARK, RMII0_TXD0_A_MARK,
+		ET0_ERXD4_MARK,
+	SCK0_A_MARK, HSPI_CS_A_MARK, VI0_CLKENB_MARK, RMII0_TXD1_A_MARK,
+		ET0_ERXD5_MARK,
+	RX0_A_MARK, HSPI_RX_A_MARK, RMII0_RXD0_A_MARK, ET0_ERXD6_MARK,
+	TX0_A_MARK, HSPI_TX_A_MARK,
+	PENC1_MARK, TX3_D_MARK, CAN1_TX_B_MARK, TX5_D_MARK,
+		IETX_B_MARK,
+	USB_OVC1_MARK, RX3_D_MARK, CAN1_RX_B_MARK, RX5_D_MARK,
+		IERX_B_MARK,
+	DREQ0_MARK, SD1_CLK_A_MARK, ET0_TX_EN_MARK,
+	DACK0_MARK, SD1_DAT3_A_MARK, ET0_TX_ER_MARK,
+	DREQ1_MARK, HSPI_CLK_B_MARK, RX4_B_MARK, ET0_PHY_INT_C_MARK,
+		ET0_TX_CLK_A_MARK,
+	DACK1_MARK, HSPI_CS_B_MARK, TX4_B_MARK, ET0_RX_CLK_A_MARK,
+	PRESETOUT_MARK, ST_CLKOUT_MARK,
+
+	PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+	PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
+
+	PINMUX_DATA(CLKOUT_MARK, FN_CLKOUT),
+	PINMUX_DATA(BS_MARK, FN_BS), PINMUX_DATA(CS0_MARK, FN_CS0),
+	PINMUX_DATA(EX_CS0_MARK, FN_EX_CS0),
+	PINMUX_DATA(RD_MARK, FN_RD), PINMUX_DATA(WE0_MARK, FN_WE0),
+	PINMUX_DATA(WE1_MARK, FN_WE1),
+	PINMUX_DATA(SCL0_MARK, FN_SCL0), PINMUX_DATA(PENC0_MARK, FN_PENC0),
+	PINMUX_DATA(USB_OVC0_MARK, FN_USB_OVC0),
+	PINMUX_DATA(IRQ2_B_MARK, FN_IRQ2_B),
+		PINMUX_DATA(IRQ3_B_MARK, FN_IRQ3_B),
+
+	/* IPSR0 */
+	PINMUX_IPSR_DATA(IP0_1_0, A0),
+	PINMUX_IPSR_DATA(IP0_1_0, ST0_CLKIN),
+	PINMUX_IPSR_MODSEL_DATA(IP0_1_0, LCD_DATA0_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_1_0, TCLKA_C, SEL_MTU2_CLK_1),
+
+	PINMUX_IPSR_DATA(IP0_3_2, A1),
+	PINMUX_IPSR_DATA(IP0_3_2, ST0_REQ),
+	PINMUX_IPSR_MODSEL_DATA(IP0_3_2, LCD_DATA1_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_3_2, TCLKB_C, SEL_MTU2_CLK_1),
+
+	PINMUX_IPSR_DATA(IP0_5_4, A2),
+	PINMUX_IPSR_DATA(IP0_5_4, ST0_SYC),
+	PINMUX_IPSR_MODSEL_DATA(IP0_5_4, LCD_DATA2_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_5_4, TCLKC_C, SEL_MTU2_CLK_1),
+
+	PINMUX_IPSR_DATA(IP0_7_6, A3),
+	PINMUX_IPSR_DATA(IP0_7_6, ST0_VLD),
+	PINMUX_IPSR_MODSEL_DATA(IP0_7_6, LCD_DATA3_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_7_6, TCLKD_C, SEL_MTU2_CLK_1),
+
+	PINMUX_IPSR_DATA(IP0_9_8, A4),
+	PINMUX_IPSR_DATA(IP0_9_8, ST0_D0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_9_8, LCD_DATA4_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_9_8, TIOC0A_C, SEL_MTU2_CH0_1),
+
+	PINMUX_IPSR_DATA(IP0_11_10, A5),
+	PINMUX_IPSR_DATA(IP0_11_10, ST0_D1),
+	PINMUX_IPSR_MODSEL_DATA(IP0_11_10, LCD_DATA5_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_11_10, TIOC0B_C, SEL_MTU2_CH0_1),
+
+	PINMUX_IPSR_DATA(IP0_13_12, A6),
+	PINMUX_IPSR_DATA(IP0_13_12, ST0_D2),
+	PINMUX_IPSR_MODSEL_DATA(IP0_13_12, LCD_DATA6_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_13_12, TIOC0C_C, SEL_MTU2_CH0_1),
+
+	PINMUX_IPSR_DATA(IP0_15_14, A7),
+	PINMUX_IPSR_DATA(IP0_15_14, ST0_D3),
+	PINMUX_IPSR_MODSEL_DATA(IP0_15_14, LCD_DATA7_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_15_14, TIOC0D_C, SEL_MTU2_CH0_1),
+
+	PINMUX_IPSR_DATA(IP0_17_16, A8),
+	PINMUX_IPSR_DATA(IP0_17_16, ST0_D4),
+	PINMUX_IPSR_MODSEL_DATA(IP0_17_16, LCD_DATA8_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_17_16, TIOC1A_C, SEL_MTU2_CH1_2),
+
+	PINMUX_IPSR_DATA(IP0_19_18, A9),
+	PINMUX_IPSR_DATA(IP0_19_18, ST0_D5),
+	PINMUX_IPSR_MODSEL_DATA(IP0_19_18, LCD_DATA9_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_19_18, TIOC1B_C, SEL_MTU2_CH1_2),
+
+	PINMUX_IPSR_DATA(IP0_21_20, A10),
+	PINMUX_IPSR_DATA(IP0_21_20, ST0_D6),
+	PINMUX_IPSR_MODSEL_DATA(IP0_21_20, LCD_DATA10_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_21_20, TIOC2A_C, SEL_MTU2_CH2_2),
+
+	PINMUX_IPSR_DATA(IP0_23_22, A11),
+	PINMUX_IPSR_DATA(IP0_23_22, ST0_D7),
+	PINMUX_IPSR_MODSEL_DATA(IP0_23_22, LCD_DATA11_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_23_22, TIOC2B_C, SEL_MTU2_CH2_2),
+
+	PINMUX_IPSR_DATA(IP0_25_24, A12),
+	PINMUX_IPSR_MODSEL_DATA(IP0_25_24, LCD_DATA12_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_25_24, TIOC3A_C, SEL_MTU2_CH3_1),
+
+	PINMUX_IPSR_DATA(IP0_27_26, A13),
+	PINMUX_IPSR_MODSEL_DATA(IP0_27_26, LCD_DATA13_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_27_26, TIOC3B_C, SEL_MTU2_CH3_1),
+
+	PINMUX_IPSR_DATA(IP0_29_28, A14),
+	PINMUX_IPSR_MODSEL_DATA(IP0_29_28, LCD_DATA14_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_29_28, TIOC3C_C, SEL_MTU2_CH3_1),
+
+	PINMUX_IPSR_DATA(IP0_31_30, A15),
+	PINMUX_IPSR_DATA(IP0_31_30, ST0_VCO_CLKIN),
+	PINMUX_IPSR_MODSEL_DATA(IP0_31_30, LCD_DATA15_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP0_31_30, TIOC3D_C, SEL_MTU2_CH3_1),
+
+
+	/* IPSR1 */
+	PINMUX_IPSR_DATA(IP1_1_0, A16),
+	PINMUX_IPSR_DATA(IP1_1_0, ST0_PWM),
+	PINMUX_IPSR_MODSEL_DATA(IP1_1_0, LCD_DON_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_1_0, TIOC4A_C, SEL_MTU2_CH4_1),
+
+	PINMUX_IPSR_DATA(IP1_3_2, A17),
+	PINMUX_IPSR_DATA(IP1_3_2, ST1_VCO_CLKIN),
+	PINMUX_IPSR_MODSEL_DATA(IP1_3_2, LCD_CL1_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_3_2, TIOC4B_C, SEL_MTU2_CH4_1),
+
+	PINMUX_IPSR_DATA(IP1_5_4, A18),
+	PINMUX_IPSR_DATA(IP1_5_4, ST1_PWM),
+	PINMUX_IPSR_MODSEL_DATA(IP1_5_4, LCD_CL2_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_5_4, TIOC4C_C, SEL_MTU2_CH4_1),
+
+	PINMUX_IPSR_DATA(IP1_7_6, A19),
+	PINMUX_IPSR_DATA(IP1_7_6, ST1_CLKIN),
+	PINMUX_IPSR_MODSEL_DATA(IP1_7_6, LCD_CLK_A, SEL_LCDC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_7_6, TIOC4D_C, SEL_MTU2_CH4_1),
+
+	PINMUX_IPSR_DATA(IP1_9_8, A20),
+	PINMUX_IPSR_DATA(IP1_9_8, ST1_REQ),
+	PINMUX_IPSR_MODSEL_DATA(IP1_9_8, LCD_FLM_A, SEL_LCDC_0),
+
+	PINMUX_IPSR_DATA(IP1_11_10, A21),
+	PINMUX_IPSR_DATA(IP1_11_10, ST1_SYC),
+	PINMUX_IPSR_MODSEL_DATA(IP1_11_10, LCD_VCPWC_A, SEL_LCDC_0),
+
+	PINMUX_IPSR_DATA(IP1_13_12, A22),
+	PINMUX_IPSR_DATA(IP1_13_12, ST1_VLD),
+	PINMUX_IPSR_MODSEL_DATA(IP1_13_12, LCD_VEPWC_A, SEL_LCDC_0),
+
+	PINMUX_IPSR_DATA(IP1_15_14, A23),
+	PINMUX_IPSR_DATA(IP1_15_14, ST1_D0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_15_14, LCD_M_DISP_A, SEL_LCDC_0),
+
+	PINMUX_IPSR_DATA(IP1_17_16, A24),
+	PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
+	PINMUX_IPSR_DATA(IP1_17_16, ST1_D1),
+
+	PINMUX_IPSR_DATA(IP1_19_18, A25),
+	PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
+	PINMUX_IPSR_DATA(IP1_17_16, ST1_D2),
+
+	PINMUX_IPSR_DATA(IP1_22_20, D0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_22_20, SD0_DAT0_A, SEL_SDHI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_22_20, MMC_D0_A, SEL_MMC_0),
+	PINMUX_IPSR_DATA(IP1_22_20, ST1_D3),
+	PINMUX_IPSR_MODSEL_DATA(IP1_22_20, FD0_A, SEL_FLCTL_0),
+
+	PINMUX_IPSR_DATA(IP1_25_23, D1),
+	PINMUX_IPSR_MODSEL_DATA(IP1_25_23, SD0_DAT0_A, SEL_SDHI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_25_23, MMC_D1_A, SEL_MMC_0),
+	PINMUX_IPSR_DATA(IP1_25_23, ST1_D4),
+	PINMUX_IPSR_MODSEL_DATA(IP1_25_23, FD1_A, SEL_FLCTL_0),
+
+	PINMUX_IPSR_DATA(IP1_28_26, D2),
+	PINMUX_IPSR_MODSEL_DATA(IP1_28_26, SD0_DAT0_A, SEL_SDHI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_28_26, MMC_D2_A, SEL_MMC_0),
+	PINMUX_IPSR_DATA(IP1_28_26, ST1_D5),
+	PINMUX_IPSR_MODSEL_DATA(IP1_28_26, FD2_A, SEL_FLCTL_0),
+
+	PINMUX_IPSR_DATA(IP1_31_29, D3),
+	PINMUX_IPSR_MODSEL_DATA(IP1_31_29, SD0_DAT0_A, SEL_SDHI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP1_31_29, MMC_D3_A, SEL_MMC_0),
+	PINMUX_IPSR_DATA(IP1_31_29, ST1_D6),
+	PINMUX_IPSR_MODSEL_DATA(IP1_31_29, FD3_A, SEL_FLCTL_0),
+
+	/* IPSR2 */
+	PINMUX_IPSR_DATA(IP2_2_0, D4),
+	PINMUX_IPSR_MODSEL_DATA(IP2_2_0, SD0_CD_A, SEL_SDHI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_2_0, MMC_D4_A, SEL_MMC_0),
+	PINMUX_IPSR_DATA(IP2_2_0, ST1_D7),
+	PINMUX_IPSR_MODSEL_DATA(IP2_2_0, FD4_A, SEL_FLCTL_0),
+
+	PINMUX_IPSR_DATA(IP2_4_3, D5),
+	PINMUX_IPSR_MODSEL_DATA(IP2_4_3, SD0_WP_A, SEL_SDHI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_4_3, MMC_D5_A, SEL_MMC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_4_3, FD5_A, SEL_FLCTL_0),
+
+	PINMUX_IPSR_DATA(IP2_7_5, D6),
+	PINMUX_IPSR_MODSEL_DATA(IP2_7_5, RSPI_RSPCK_A, SEL_RSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_7_5, MMC_D6_A, SEL_MMC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_7_5, QSPCLK_A, SEL_RQSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_7_5, FD6_A, SEL_FLCTL_0),
+
+	PINMUX_IPSR_DATA(IP2_10_8, D7),
+	PINMUX_IPSR_MODSEL_DATA(IP2_10_8, RSPI_SSL_A, SEL_RSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_10_8, MMC_D7_A, SEL_MMC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_10_8, QSSL_A, SEL_RQSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_10_8, FD7_A, SEL_FLCTL_0),
+
+	PINMUX_IPSR_DATA(IP2_13_11, D8),
+	PINMUX_IPSR_MODSEL_DATA(IP2_13_11, SD0_CLK_A, SEL_SDHI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_13_11, MMC_CLK_A, SEL_MMC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_13_11, QIO2_A, SEL_RQSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_13_11, FCE_A, SEL_FLCTL_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_13_11, ET0_GTX_CLK_B, SEL_ET0_1),
+
+	PINMUX_IPSR_DATA(IP2_16_14, D9),
+	PINMUX_IPSR_MODSEL_DATA(IP2_16_14, SD0_CMD_A, SEL_SDHI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_16_14, MMC_CMD_A, SEL_MMC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_16_14, QIO3_A, SEL_RQSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_16_14, FCLE_A, SEL_FLCTL_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_16_14, ET0_ETXD1_B, SEL_ET0_1),
+
+	PINMUX_IPSR_DATA(IP2_19_17, D10),
+	PINMUX_IPSR_MODSEL_DATA(IP2_19_17, RSPI_MOSI_A, SEL_RSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_19_17, QMO_QIO0_A, SEL_RQSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_19_17, FALE_A, SEL_FLCTL_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_19_17, ET0_ETXD2_B, SEL_ET0_1),
+
+	PINMUX_IPSR_DATA(IP2_22_20, D11),
+	PINMUX_IPSR_MODSEL_DATA(IP2_22_20, RSPI_MISO_A, SEL_RSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_22_20, QMI_QIO1_A, SEL_RQSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_22_20, FRE_A, SEL_FLCTL_0),
+
+	PINMUX_IPSR_DATA(IP2_24_23, D12),
+	PINMUX_IPSR_MODSEL_DATA(IP2_24_23, FWE_A, SEL_FLCTL_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_24_23, ET0_ETXD5_B, SEL_ET0_1),
+
+	PINMUX_IPSR_DATA(IP2_27_25, D13),
+	PINMUX_IPSR_MODSEL_DATA(IP2_27_25, RX2_B, SEL_SCIF2_1),
+	PINMUX_IPSR_MODSEL_DATA(IP2_27_25, FRB_A, SEL_FLCTL_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_27_25, ET0_ETXD6_B, SEL_ET0_1),
+
+	PINMUX_IPSR_DATA(IP2_30_28, D14),
+	PINMUX_IPSR_MODSEL_DATA(IP2_30_28, TX2_B, SEL_SCIF2_1),
+	PINMUX_IPSR_MODSEL_DATA(IP2_30_28, FSE_A, SEL_FLCTL_0),
+	PINMUX_IPSR_MODSEL_DATA(IP2_30_28, ET0_TX_CLK_B, SEL_ET0_1),
+
+	/* IPSR3 */
+	PINMUX_IPSR_DATA(IP3_1_0, D15),
+	PINMUX_IPSR_MODSEL_DATA(IP3_1_0, SCK2_B, SEL_SCIF2_1),
+
+	PINMUX_IPSR_DATA(IP3_2, CS1_A26),
+	PINMUX_IPSR_MODSEL_DATA(IP3_2, QIO3_B, SEL_RQSPI_1),
+
+	PINMUX_IPSR_DATA(IP3_5_3, EX_CS1),
+	PINMUX_IPSR_MODSEL_DATA(IP3_5_3, RX3_B, SEL_SCIF2_1),
+	PINMUX_IPSR_DATA(IP3_5_3, ATACS0),
+	PINMUX_IPSR_MODSEL_DATA(IP3_5_3, QIO2_B, SEL_RQSPI_1),
+	PINMUX_IPSR_DATA(IP3_5_3, ET0_ETXD0),
+
+	PINMUX_IPSR_DATA(IP3_8_6, EX_CS2),
+	PINMUX_IPSR_MODSEL_DATA(IP3_8_6, TX3_B, SEL_SCIF3_1),
+	PINMUX_IPSR_DATA(IP3_8_6, ATACS1),
+	PINMUX_IPSR_MODSEL_DATA(IP3_8_6, QSPCLK_B, SEL_RQSPI_1),
+	PINMUX_IPSR_MODSEL_DATA(IP3_8_6, ET0_GTX_CLK_A, SEL_ET0_0),
+
+	PINMUX_IPSR_DATA(IP3_11_9, EX_CS3),
+	PINMUX_IPSR_MODSEL_DATA(IP3_11_9, SD1_CD_A, SEL_SDHI1_0),
+	PINMUX_IPSR_DATA(IP3_11_9, ATARD),
+	PINMUX_IPSR_MODSEL_DATA(IP3_11_9, QMO_QIO0_B, SEL_RQSPI_1),
+	PINMUX_IPSR_MODSEL_DATA(IP3_11_9, ET0_ETXD1_A, SEL_ET0_0),
+
+	PINMUX_IPSR_DATA(IP3_14_12, EX_CS4),
+	PINMUX_IPSR_MODSEL_DATA(IP3_14_12, SD1_WP_A, SEL_SDHI1_0),
+	PINMUX_IPSR_DATA(IP3_14_12, ATAWR),
+	PINMUX_IPSR_MODSEL_DATA(IP3_14_12, QMI_QIO1_B, SEL_RQSPI_1),
+	PINMUX_IPSR_MODSEL_DATA(IP3_14_12, ET0_ETXD2_A, SEL_ET0_0),
+
+	PINMUX_IPSR_DATA(IP3_17_15, EX_CS5),
+	PINMUX_IPSR_MODSEL_DATA(IP3_17_15, SD1_CMD_A, SEL_SDHI1_0),
+	PINMUX_IPSR_DATA(IP3_17_15, ATADIR),
+	PINMUX_IPSR_MODSEL_DATA(IP3_17_15, QSSL_B, SEL_RQSPI_1),
+	PINMUX_IPSR_MODSEL_DATA(IP3_17_15, ET0_ETXD3_A, SEL_ET0_0),
+
+	PINMUX_IPSR_DATA(IP3_19_18, RD_WR),
+	PINMUX_IPSR_DATA(IP3_19_18, TCLK0),
+	PINMUX_IPSR_MODSEL_DATA(IP3_19_18, CAN_CLK_B, SEL_RCAN_CLK_1),
+	PINMUX_IPSR_DATA(IP3_19_18, ET0_ETXD4),
+
+	PINMUX_IPSR_DATA(IP3_20, EX_WAIT0),
+	PINMUX_IPSR_MODSEL_DATA(IP3_20, TCLK1_B, SEL_TMU_1),
+
+	PINMUX_IPSR_DATA(IP3_23_21, EX_WAIT1),
+	PINMUX_IPSR_MODSEL_DATA(IP3_23_21, SD1_DAT0_A, SEL_SDHI1_0),
+	PINMUX_IPSR_DATA(IP3_23_21, DREQ2),
+	PINMUX_IPSR_MODSEL_DATA(IP3_23_21, CAN1_TX_C, SEL_RCAN1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_LINK_C, SEL_ET0_CTL_2),
+	PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_ETXD5_A, SEL_ET0_0),
+
+	PINMUX_IPSR_DATA(IP3_26_24, EX_WAIT2),
+	PINMUX_IPSR_MODSEL_DATA(IP3_26_24, SD1_DAT1_A, SEL_SDHI1_0),
+	PINMUX_IPSR_DATA(IP3_26_24, DACK2),
+	PINMUX_IPSR_MODSEL_DATA(IP3_26_24, CAN1_RX_C, SEL_RCAN1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_MAGIC_C, SEL_ET0_CTL_2),
+	PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_ETXD6_A, SEL_ET0_0),
+
+	PINMUX_IPSR_DATA(IP3_29_27, DRACK0),
+	PINMUX_IPSR_MODSEL_DATA(IP3_29_27, SD1_DAT2_A, SEL_SDHI1_0),
+	PINMUX_IPSR_DATA(IP3_29_27, ATAG),
+	PINMUX_IPSR_MODSEL_DATA(IP3_29_27, TCLK1_A, SEL_TMU_0),
+	PINMUX_IPSR_DATA(IP3_29_27, ET0_ETXD7),
+
+	/* IPSR4 */
+	PINMUX_IPSR_MODSEL_DATA(IP4_2_0, HCTS0_A, SEL_HSCIF_0),
+	PINMUX_IPSR_MODSEL_DATA(IP4_2_0, CTS1_A, SEL_SCIF1_0),
+	PINMUX_IPSR_DATA(IP4_2_0, VI0_FIELD),
+	PINMUX_IPSR_MODSEL_DATA(IP4_2_0, RMII0_RXD1_A, SEL_RMII_0),
+	PINMUX_IPSR_DATA(IP4_2_0, ET0_ERXD7),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_5_3, HRTS0_A, SEL_HSCIF_0),
+	PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RTS1_A, SEL_SCIF1_0),
+	PINMUX_IPSR_DATA(IP4_5_3, VI0_HSYNC),
+	PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RMII0_TXD_EN_A, SEL_RMII_0),
+	PINMUX_IPSR_DATA(IP4_5_3, ET0_RX_DV),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_8_6, HSCK0_A, SEL_HSCIF_0),
+	PINMUX_IPSR_MODSEL_DATA(IP4_8_6, SCK1_A, SEL_SCIF1_0),
+	PINMUX_IPSR_DATA(IP4_8_6, VI0_VSYNC),
+	PINMUX_IPSR_MODSEL_DATA(IP4_8_6, RMII0_RX_ER_A, SEL_RMII_0),
+	PINMUX_IPSR_DATA(IP4_8_6, ET0_RX_ER),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_11_9, HRX0_A, SEL_HSCIF_0),
+	PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RX1_A, SEL_SCIF1_0),
+	PINMUX_IPSR_DATA(IP4_11_9, VI0_DATA0_VI0_B0),
+	PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RMII0_CRS_DV_A, SEL_RMII_0),
+	PINMUX_IPSR_DATA(IP4_11_9, ET0_CRS),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_14_12, HTX0_A, SEL_HSCIF_0),
+	PINMUX_IPSR_MODSEL_DATA(IP4_14_12, TX1_A, SEL_SCIF1_0),
+	PINMUX_IPSR_DATA(IP4_14_12, VI0_DATA1_VI0_B1),
+	PINMUX_IPSR_MODSEL_DATA(IP4_14_12, RMII0_MDC_A, SEL_RMII_0),
+	PINMUX_IPSR_DATA(IP4_14_12, ET0_COL),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_17_15, CTS0_B, SEL_SCIF0_1),
+	PINMUX_IPSR_DATA(IP4_17_15, VI0_DATA2_VI0_B2),
+	PINMUX_IPSR_MODSEL_DATA(IP4_17_15, RMII0_MDIO_A, SEL_RMII_0),
+	PINMUX_IPSR_DATA(IP4_17_15, ET0_MDC),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_19_18, RTS0_B, SEL_SCIF0_1),
+	PINMUX_IPSR_DATA(IP4_19_18, VI0_DATA3_VI0_B3),
+	PINMUX_IPSR_MODSEL_DATA(IP4_19_18, ET0_MDIO_A, SEL_ET0_0),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_21_20, SCK1_B, SEL_SCIF1_1),
+	PINMUX_IPSR_DATA(IP4_21_20, VI0_DATA4_VI0_B4),
+	PINMUX_IPSR_MODSEL_DATA(IP4_21_20, ET0_LINK_A, SEL_ET0_CTL_0),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_23_22, RX1_B, SEL_SCIF1_1),
+	PINMUX_IPSR_DATA(IP4_23_22, VI0_DATA5_VI0_B5),
+	PINMUX_IPSR_MODSEL_DATA(IP4_23_22, ET0_MAGIC_A, SEL_ET0_CTL_0),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_25_24, TX1_B, SEL_SCIF1_1),
+	PINMUX_IPSR_DATA(IP4_25_24, VI0_DATA6_VI0_G0),
+	PINMUX_IPSR_MODSEL_DATA(IP4_25_24, ET0_PHY_INT_A, SEL_ET0_CTL_0),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_27_26, CTS1_B, SEL_SCIF1_1),
+	PINMUX_IPSR_DATA(IP4_27_26, VI0_DATA7_VI0_G1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_29_28, RTS1_B, SEL_SCIF1_1),
+	PINMUX_IPSR_DATA(IP4_29_28, VI0_G2),
+
+	PINMUX_IPSR_MODSEL_DATA(IP4_31_30, SCK2_A, SEL_SCIF2_0),
+	PINMUX_IPSR_DATA(IP4_31_30, VI0_G3),
+
+	/* IPSR5 */
+	PINMUX_IPSR_MODSEL_DATA(IP5_2_0, SD2_CLK_A, SEL_SDHI2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_2_0, RX2_A, SEL_SCIF2_0),
+	PINMUX_IPSR_DATA(IP5_2_0, VI0_G4),
+	PINMUX_IPSR_MODSEL_DATA(IP5_2_0, ET0_RX_CLK_B, SEL_ET0_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, SD2_CMD_A, SEL_SDHI2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, TX2_A, SEL_SCIF2_0),
+	PINMUX_IPSR_DATA(IP5_5_3, VI0_G5),
+	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, ET0_ERXD2_B, SEL_ET0_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP5_8_6, SD2_DAT0_A, SEL_SDHI2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_8_6, RX3_A, SEL_SCIF3_0),
+	PINMUX_IPSR_DATA(IP4_8_6, VI0_R0),
+	PINMUX_IPSR_MODSEL_DATA(IP4_8_6, ET0_ERXD2_B, SEL_ET0_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP5_11_9, SD2_DAT1_A, SEL_SDHI2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_11_9, TX3_A, SEL_SCIF3_0),
+	PINMUX_IPSR_DATA(IP5_11_9, VI0_R1),
+	PINMUX_IPSR_MODSEL_DATA(IP5_11_9, ET0_MDIO_B, SEL_ET0_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP5_14_12, SD2_DAT2_A, SEL_SDHI2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_14_12, RX4_A, SEL_SCIF4_0),
+	PINMUX_IPSR_DATA(IP5_14_12, VI0_R2),
+	PINMUX_IPSR_MODSEL_DATA(IP5_14_12, ET0_LINK_B, SEL_ET0_CTL_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP5_17_15, SD2_DAT3_A, SEL_SDHI2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_17_15, TX4_A, SEL_SCIF4_0),
+	PINMUX_IPSR_DATA(IP5_17_15, VI0_R3),
+	PINMUX_IPSR_MODSEL_DATA(IP5_17_15, ET0_MAGIC_B, SEL_ET0_CTL_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP5_20_18, SD2_CD_A, SEL_SDHI2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_20_18, RX5_A, SEL_SCIF5_0),
+	PINMUX_IPSR_DATA(IP5_20_18, VI0_R4),
+	PINMUX_IPSR_MODSEL_DATA(IP5_20_18, ET0_PHY_INT_B, SEL_ET0_CTL_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP5_22_21, SD2_WP_A, SEL_SDHI2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_22_21, TX5_A, SEL_SCIF5_0),
+	PINMUX_IPSR_DATA(IP5_22_21, VI0_R5),
+
+	PINMUX_IPSR_DATA(IP5_24_23, REF125CK),
+	PINMUX_IPSR_DATA(IP5_24_23, ADTRG),
+	PINMUX_IPSR_MODSEL_DATA(IP5_24_23, RX5_C, SEL_SCIF5_2),
+	PINMUX_IPSR_DATA(IP5_26_25, REF50CK),
+	PINMUX_IPSR_MODSEL_DATA(IP5_26_25, CTS1_E, SEL_SCIF1_3),
+	PINMUX_IPSR_MODSEL_DATA(IP5_26_25, HCTS0_D, SEL_HSCIF_3),
+
+	/* IPSR6 */
+	PINMUX_IPSR_DATA(IP6_2_0, DU0_DR0),
+	PINMUX_IPSR_MODSEL_DATA(IP6_2_0, SCIF_CLK_B, SEL_SCIF_CLK_1),
+	PINMUX_IPSR_MODSEL_DATA(IP6_2_0, HRX0_D, SEL_HSCIF_3),
+	PINMUX_IPSR_MODSEL_DATA(IP6_2_0, IETX_A, SEL_IEBUS_0),
+	PINMUX_IPSR_MODSEL_DATA(IP6_2_0, TCLKA_A, SEL_MTU2_CLK_0),
+	PINMUX_IPSR_DATA(IP6_2_0, HIFD00),
+
+	PINMUX_IPSR_DATA(IP6_5_3, DU0_DR1),
+	PINMUX_IPSR_MODSEL_DATA(IP6_5_3, SCK0_B, SEL_SCIF0_1),
+	PINMUX_IPSR_MODSEL_DATA(IP6_5_3, HTX0_D, SEL_HSCIF_3),
+	PINMUX_IPSR_MODSEL_DATA(IP6_5_3, IERX_A, SEL_IEBUS_0),
+	PINMUX_IPSR_MODSEL_DATA(IP6_5_3, TCLKB_A, SEL_MTU2_CLK_0),
+	PINMUX_IPSR_DATA(IP6_5_3, HIFD01),
+
+	PINMUX_IPSR_DATA(IP6_7_6, DU0_DR2),
+	PINMUX_IPSR_MODSEL_DATA(IP6_7_6, RX0_B, SEL_SCIF0_1),
+	PINMUX_IPSR_MODSEL_DATA(IP6_7_6, TCLKC_A, SEL_MTU2_CLK_0),
+	PINMUX_IPSR_DATA(IP6_7_6, HIFD02),
+
+	PINMUX_IPSR_DATA(IP6_9_8, DU0_DR3),
+	PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TX0_B, SEL_SCIF0_1),
+	PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TCLKD_A, SEL_MTU2_CLK_0),
+	PINMUX_IPSR_DATA(IP6_9_8, HIFD03),
+
+	PINMUX_IPSR_DATA(IP6_11_10, DU0_DR4),
+	PINMUX_IPSR_MODSEL_DATA(IP6_11_10, CTS0_C, SEL_SCIF0_2),
+	PINMUX_IPSR_MODSEL_DATA(IP6_11_10, TIOC0A_A, SEL_MTU2_CH0_0),
+	PINMUX_IPSR_DATA(IP6_11_10, HIFD04),
+
+	PINMUX_IPSR_DATA(IP6_13_12, DU0_DR5),
+	PINMUX_IPSR_MODSEL_DATA(IP6_13_12, RTS0_C, SEL_SCIF0_1),
+	PINMUX_IPSR_MODSEL_DATA(IP6_13_12, TIOC0B_A, SEL_MTU2_CH0_0),
+	PINMUX_IPSR_DATA(IP6_13_12, HIFD05),
+
+	PINMUX_IPSR_DATA(IP6_15_14, DU0_DR6),
+	PINMUX_IPSR_MODSEL_DATA(IP6_15_14, SCK1_C, SEL_SCIF1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP6_15_14, TIOC0C_A, SEL_MTU2_CH0_0),
+	PINMUX_IPSR_DATA(IP6_15_14, HIFD06),
+
+	PINMUX_IPSR_DATA(IP6_17_16, DU0_DR7),
+	PINMUX_IPSR_MODSEL_DATA(IP6_17_16, RX1_C, SEL_SCIF1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP6_17_16, TIOC0D_A, SEL_MTU2_CH0_0),
+	PINMUX_IPSR_DATA(IP6_17_16, HIFD07),
+
+	PINMUX_IPSR_DATA(IP6_20_18, DU0_DG0),
+	PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TX1_C, SEL_SCIF1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP6_20_18, HSCK0_D, SEL_HSCIF_3),
+	PINMUX_IPSR_MODSEL_DATA(IP6_20_18, IECLK_A, SEL_IEBUS_0),
+	PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TIOC1A_A, SEL_MTU2_CH1_0),
+	PINMUX_IPSR_DATA(IP6_20_18, HIFD08),
+
+	PINMUX_IPSR_DATA(IP6_23_21, DU0_DG1),
+	PINMUX_IPSR_MODSEL_DATA(IP6_23_21, CTS1_C, SEL_SCIF1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP6_23_21, HRTS0_D, SEL_HSCIF_3),
+	PINMUX_IPSR_MODSEL_DATA(IP6_23_21, TIOC1B_A, SEL_MTU2_CH1_0),
+	PINMUX_IPSR_DATA(IP6_23_21, HIFD09),
+
+	/* IPSR7 */
+	PINMUX_IPSR_DATA(IP7_2_0, DU0_DG2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RTS1_C, SEL_SCIF1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RMII0_MDC_B, SEL_RMII_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_2_0, TIOC2A_A, SEL_MTU2_CH2_0),
+	PINMUX_IPSR_DATA(IP7_2_0, HIFD10),
+
+	PINMUX_IPSR_DATA(IP7_5_3, DU0_DG3),
+	PINMUX_IPSR_MODSEL_DATA(IP7_5_3, SCK2_C, SEL_SCIF2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_5_3, RMII0_MDIO_B, SEL_RMII_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_5_3, TIOC2B_A, SEL_MTU2_CH2_0),
+	PINMUX_IPSR_DATA(IP7_5_3, HIFD11),
+
+	PINMUX_IPSR_DATA(IP7_8_6, DU0_DG4),
+	PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RX2_C, SEL_SCIF2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RMII0_CRS_DV_B, SEL_RMII_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_8_6, TIOC3A_A, SEL_MTU2_CH3_0),
+	PINMUX_IPSR_DATA(IP7_8_6, HIFD12),
+
+	PINMUX_IPSR_DATA(IP7_11_9, DU0_DG5),
+	PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TX2_C, SEL_SCIF2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_11_9, RMII0_RX_ER_B, SEL_RMII_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TIOC3B_A, SEL_MTU2_CH3_0),
+	PINMUX_IPSR_DATA(IP7_11_9, HIFD13),
+
+	PINMUX_IPSR_DATA(IP7_14_12, DU0_DG6),
+	PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RX3_C, SEL_SCIF3_2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RMII0_RXD0_B, SEL_RMII_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_14_12, TIOC3C_A, SEL_MTU2_CH3_0),
+	PINMUX_IPSR_DATA(IP7_14_12, HIFD14),
+
+	PINMUX_IPSR_DATA(IP7_17_15, DU0_DG7),
+	PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TX3_C, SEL_SCIF3_2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_17_15, RMII0_RXD1_B, SEL_RMII_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TIOC3D_A, SEL_MTU2_CH3_0),
+	PINMUX_IPSR_DATA(IP7_17_15, HIFD15),
+
+	PINMUX_IPSR_DATA(IP7_20_18, DU0_DB0),
+	PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RX4_C, SEL_SCIF4_2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RMII0_TXD_EN_B, SEL_RMII_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_20_18, TIOC4A_A, SEL_MTU2_CH4_0),
+	PINMUX_IPSR_DATA(IP7_20_18, HIFCS),
+
+	PINMUX_IPSR_DATA(IP7_23_21, DU0_DB1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TX4_C, SEL_SCIF4_2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_23_21, RMII0_TXD0_B, SEL_RMII_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TIOC4B_A, SEL_MTU2_CH4_0),
+	PINMUX_IPSR_DATA(IP7_23_21, HIFWR),
+
+	PINMUX_IPSR_DATA(IP7_26_24, DU0_DB2),
+	PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RX5_B, SEL_SCIF5_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RMII0_TXD1_B, SEL_RMII_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_26_24, TIOC4C_A, SEL_MTU2_CH4_0),
+
+	PINMUX_IPSR_DATA(IP7_28_27, DU0_DB3),
+	PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TX5_B, SEL_SCIF5_1),
+	PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TIOC4D_A, SEL_MTU2_CH4_0),
+	PINMUX_IPSR_DATA(IP7_28_27, HIFRD),
+
+	PINMUX_IPSR_DATA(IP7_30_29, DU0_DB4),
+	PINMUX_IPSR_DATA(IP7_30_29, HIFINT),
+
+	/* IPSR8 */
+	PINMUX_IPSR_DATA(IP8_1_0, DU0_DB5),
+	PINMUX_IPSR_DATA(IP8_1_0, HIFDREQ),
+
+	PINMUX_IPSR_DATA(IP8_3_2, DU0_DB6),
+	PINMUX_IPSR_DATA(IP8_3_2, HIFRDY),
+
+	PINMUX_IPSR_DATA(IP8_5_4, DU0_DB7),
+	PINMUX_IPSR_MODSEL_DATA(IP8_5_4, SSI_SCK0_B, SEL_SSI0_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_5_4, HIFEBL_B, SEL_HIF_1),
+
+	PINMUX_IPSR_DATA(IP8_7_6, DU0_DOTCLKIN),
+	PINMUX_IPSR_MODSEL_DATA(IP8_7_6, HSPI_CS0_C, SEL_HSPI_2),
+	PINMUX_IPSR_MODSEL_DATA(IP8_7_6, SSI_WS0_B, SEL_SSI0_1),
+
+	PINMUX_IPSR_DATA(IP8_9_8, DU0_DOTCLKOUT),
+	PINMUX_IPSR_MODSEL_DATA(IP8_9_8, HSPI_CLK0_C, SEL_HSPI_2),
+	PINMUX_IPSR_MODSEL_DATA(IP8_9_8, SSI_SDATA0_B, SEL_SSI0_1),
+
+	PINMUX_IPSR_DATA(IP8_11_10, DU0_EXHSYNC_DU0_HSYNC),
+	PINMUX_IPSR_MODSEL_DATA(IP8_11_10, HSPI_TX0_C, SEL_HSPI_2),
+	PINMUX_IPSR_MODSEL_DATA(IP8_11_10, SSI_SCK1_B, SEL_SSI1_1),
+
+	PINMUX_IPSR_DATA(IP8_13_12, DU0_EXVSYNC_DU0_VSYNC),
+	PINMUX_IPSR_MODSEL_DATA(IP8_13_12, HSPI_RX0_C, SEL_HSPI_2),
+	PINMUX_IPSR_MODSEL_DATA(IP8_13_12, SSI_WS1_B, SEL_SSI1_1),
+
+	PINMUX_IPSR_DATA(IP8_15_14, DU0_EXODDF_DU0_ODDF),
+	PINMUX_IPSR_MODSEL_DATA(IP8_15_14, CAN0_RX_B, SEL_RCAN0_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_15_14, HSCK0_B, SEL_HSCIF_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_15_14, SSI_SDATA1_B, SEL_SSI1_1),
+
+	PINMUX_IPSR_DATA(IP8_17_16, DU0_DISP),
+	PINMUX_IPSR_MODSEL_DATA(IP8_17_16, CAN0_TX_B, SEL_RCAN0_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_17_16, HRX0_B, SEL_HSCIF_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_17_16, AUDIO_CLKA_B, SEL_AUDIO_CLKA_1),
+
+	PINMUX_IPSR_DATA(IP8_19_18, DU0_CDE),
+	PINMUX_IPSR_MODSEL_DATA(IP8_19_18, HTX0_B, SEL_HSCIF_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_19_18, AUDIO_CLKB_B, SEL_AUDIO_CLKB_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_19_18, LCD_VCPWC_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP8_22_20, IRQ0_A, SEL_INTC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP8_22_20, HSPI_TX_B, SEL_HSPI_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_22_20, RX3_E, SEL_SCIF3_4),
+	PINMUX_IPSR_DATA(IP8_22_20, ET0_ERXD0),
+
+	PINMUX_IPSR_MODSEL_DATA(IP8_25_23, IRQ1_A, SEL_INTC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP8_25_23, HSPI_RX_B, SEL_HSPI_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_25_23, TX3_E, SEL_SCIF3_4),
+	PINMUX_IPSR_DATA(IP8_25_23, ET0_ERXD1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP8_27_26, IRQ2_A, SEL_INTC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP8_27_26, CTS0_A, SEL_SCIF0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP8_27_26, HCTS0_B, SEL_HSCIF_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_27_26, ET0_ERXD2_A, SEL_ET0_0),
+
+	PINMUX_IPSR_MODSEL_DATA(IP8_29_28, IRQ3_A, SEL_INTC_0),
+	PINMUX_IPSR_MODSEL_DATA(IP8_29_28, RTS0_A, SEL_SCIF0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP8_29_28, HRTS0_B, SEL_HSCIF_1),
+	PINMUX_IPSR_MODSEL_DATA(IP8_29_28, ET0_ERXD3_A, SEL_ET0_0),
+
+	/* IPSR9 */
+	PINMUX_IPSR_MODSEL_DATA(IP9_1_0, VI1_CLK_A, SEL_VIN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_1_0, FD0_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_1_0, LCD_DATA0_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_3_2, VI1_0_A, SEL_VIN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_3_2, FD1_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_3_2, LCD_DATA1_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_5_4, VI1_1_A, SEL_VIN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_5_4, FD2_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_5_4, LCD_DATA2_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_7_6, VI1_2_A, SEL_VIN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_7_6, FD3_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_7_6, LCD_DATA3_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_9_8, VI1_3_A, SEL_VIN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_9_8, FD4_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_9_8, LCD_DATA4_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_11_10, VI1_4_A, SEL_VIN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_11_10, FD5_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_11_10, LCD_DATA5_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_13_12, VI1_5_A, SEL_VIN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_13_12, FD6_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_13_12, LCD_DATA6_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_15_14, VI1_6_A, SEL_VIN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_15_14, FD7_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_15_14, LCD_DATA7_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_17_16, VI1_7_A, SEL_VIN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_17_16, FCE_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_17_16, LCD_DATA8_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_19_18, SSI_SCK0_A, SEL_SSI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_19_18, TIOC1A_B, SEL_MTU2_CH1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_19_18, LCD_DATA9_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_21_20, SSI_WS0_A, SEL_SSI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_21_20, TIOC1B_B, SEL_MTU2_CH1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_21_20, LCD_DATA10_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_23_22, SSI_SDATA0_A, SEL_SSI0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_23_22, VI1_0_B, SEL_VIN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_23_22, TIOC2A_B, SEL_MTU2_CH2_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_23_22, LCD_DATA11_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_25_24, SSI_SCK1_A, SEL_SSI1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_25_24, VI1_1_B, SEL_VIN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_25_24, TIOC2B_B, SEL_MTU2_CH2_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_25_24, LCD_DATA12_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_27_26, SSI_WS1_A, SEL_SSI1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_27_26, VI1_2_B, SEL_VIN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_27_26, LCD_DATA13_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP9_29_28, SSI_SDATA1_A, SEL_SSI1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP9_29_28, VI1_3_B, SEL_VIN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_29_28, LCD_DATA14_B, SEL_LCDC_1),
+
+	/* IPSE10 */
+	PINMUX_IPSR_DATA(IP10_2_0, SSI_SCK23),
+	PINMUX_IPSR_MODSEL_DATA(IP10_2_0, VI1_4_B, SEL_VIN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_2_0, RX1_D, SEL_SCIF1_3),
+	PINMUX_IPSR_MODSEL_DATA(IP10_2_0, FCLE_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_2_0, LCD_DATA15_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_DATA(IP10_5_3, SSI_WS23),
+	PINMUX_IPSR_MODSEL_DATA(IP10_5_3, VI1_5_B, SEL_VIN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_5_3, TX1_D, SEL_SCIF1_3),
+	PINMUX_IPSR_MODSEL_DATA(IP10_5_3, HSCK0_C, SEL_HSCIF_2),
+	PINMUX_IPSR_MODSEL_DATA(IP10_5_3, FALE_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_5_3, LCD_DON_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_DATA(IP10_8_6, SSI_SDATA2),
+	PINMUX_IPSR_MODSEL_DATA(IP10_8_6, VI1_6_B, SEL_VIN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_8_6, HRX0_C, SEL_HSCIF_2),
+	PINMUX_IPSR_MODSEL_DATA(IP10_8_6, FRE_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_8_6, LCD_CL1_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_DATA(IP10_11_9, SSI_SDATA3),
+	PINMUX_IPSR_MODSEL_DATA(IP10_11_9, VI1_7_B, SEL_VIN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_11_9, HTX0_C, SEL_HSCIF_2),
+	PINMUX_IPSR_MODSEL_DATA(IP10_11_9, FWE_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_11_9, LCD_CL2_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP10_14_12, AUDIO_CLKA_A, SEL_AUDIO_CLKA_0),
+	PINMUX_IPSR_MODSEL_DATA(IP10_14_12, VI1_CLK_B, SEL_VIN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_14_12, SCK1_D, SEL_SCIF1_3),
+	PINMUX_IPSR_MODSEL_DATA(IP10_14_12, IECLK_B, SEL_IEBUS_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_14_12, LCD_FLM_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP10_15, AUDIO_CLKB_A, SEL_AUDIO_CLKB_0),
+	PINMUX_IPSR_MODSEL_DATA(IP10_15, LCD_CLK_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_DATA(IP10_18_16, AUDIO_CLKC),
+	PINMUX_IPSR_MODSEL_DATA(IP10_18_16, SCK1_E, SEL_SCIF1_4),
+	PINMUX_IPSR_MODSEL_DATA(IP10_18_16, HCTS0_C, SEL_HSCIF_2),
+	PINMUX_IPSR_MODSEL_DATA(IP10_18_16, FRB_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_18_16, LCD_VEPWC_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_DATA(IP10_21_19, AUDIO_CLKOUT),
+	PINMUX_IPSR_MODSEL_DATA(IP10_21_19, TX1_E, SEL_SCIF1_4),
+	PINMUX_IPSR_MODSEL_DATA(IP10_21_19, HRTS0_C, SEL_HSCIF_2),
+	PINMUX_IPSR_MODSEL_DATA(IP10_21_19, FSE_B, SEL_FLCTL_1),
+	PINMUX_IPSR_MODSEL_DATA(IP10_21_19, LCD_M_DISP_B, SEL_LCDC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP10_22, CAN_CLK_A, SEL_RCAN_CLK_0),
+	PINMUX_IPSR_MODSEL_DATA(IP10_22, RX4_D, SEL_SCIF4_3),
+
+	PINMUX_IPSR_MODSEL_DATA(IP10_24_23, CAN0_TX_A, SEL_RCAN0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP10_24_23, TX4_D, SEL_SCIF4_3),
+	PINMUX_IPSR_DATA(IP10_24_23, MLB_CLK),
+
+	PINMUX_IPSR_MODSEL_DATA(IP10_25, CAN1_RX_A, SEL_RCAN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP10_25, IRQ1_B, SEL_INTC_1),
+
+	PINMUX_IPSR_MODSEL_DATA(IP10_27_26, CAN0_RX_A, SEL_RCAN0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP10_27_26, IRQ0_B, SEL_INTC_1),
+	PINMUX_IPSR_DATA(IP10_27_26, MLB_SIG),
+
+	PINMUX_IPSR_MODSEL_DATA(IP10_29_28, CAN1_TX_A, SEL_RCAN1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP10_29_28, TX5_C, SEL_SCIF1_2),
+	PINMUX_IPSR_DATA(IP10_29_28, MLB_DAT),
+
+	/* IPSR11 */
+	PINMUX_IPSR_DATA(IP11_0, SCL1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_0, SCIF_CLK_C, SEL_SCIF_CLK_2),
+
+	PINMUX_IPSR_DATA(IP11_1, SDA1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_0, RX1_E, SEL_SCIF1_4),
+
+	PINMUX_IPSR_DATA(IP11_2, SDA0),
+	PINMUX_IPSR_MODSEL_DATA(IP11_2, HIFEBL_A, SEL_HIF_0),
+
+	PINMUX_IPSR_DATA(IP11_3, SDSELF),
+	PINMUX_IPSR_MODSEL_DATA(IP11_3, RTS1_E, SEL_SCIF1_3),
+
+	PINMUX_IPSR_MODSEL_DATA(IP11_6_4, SCIF_CLK_A, SEL_SCIF_CLK_0),
+	PINMUX_IPSR_MODSEL_DATA(IP11_6_4, HSPI_CLK_A, SEL_HSPI_0),
+	PINMUX_IPSR_DATA(IP11_6_4, VI0_CLK),
+	PINMUX_IPSR_MODSEL_DATA(IP11_6_4, RMII0_TXD0_A, SEL_RMII_0),
+	PINMUX_IPSR_DATA(IP11_6_4, ET0_ERXD4),
+
+	PINMUX_IPSR_MODSEL_DATA(IP11_9_7, SCK0_A, SEL_SCIF0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP11_9_7, HSPI_CS_A, SEL_HSPI_0),
+	PINMUX_IPSR_DATA(IP11_9_7, VI0_CLKENB),
+	PINMUX_IPSR_MODSEL_DATA(IP11_9_7, RMII0_TXD1_A, SEL_RMII_0),
+	PINMUX_IPSR_DATA(IP11_9_7, ET0_ERXD5),
+
+	PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RX0_A, SEL_SCIF0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP11_11_10, HSPI_RX_A, SEL_HSPI_0),
+	PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RMII0_RXD0_A, SEL_RMII_0),
+	PINMUX_IPSR_DATA(IP11_11_10, ET0_ERXD6),
+
+	PINMUX_IPSR_MODSEL_DATA(IP11_12, TX0_A, SEL_SCIF0_0),
+	PINMUX_IPSR_MODSEL_DATA(IP11_12, HSPI_TX_A, SEL_HSPI_0),
+
+	PINMUX_IPSR_DATA(IP11_15_13, PENC1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX3_D, SEL_SCIF3_3),
+	PINMUX_IPSR_MODSEL_DATA(IP11_15_13, CAN1_TX_B,  SEL_RCAN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX5_D, SEL_SCIF5_3),
+	PINMUX_IPSR_MODSEL_DATA(IP11_15_13, IETX_B, SEL_IEBUS_1),
+
+	PINMUX_IPSR_DATA(IP11_18_16, USB_OVC1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX3_D, SEL_SCIF3_3),
+	PINMUX_IPSR_MODSEL_DATA(IP11_18_16, CAN1_RX_B, SEL_RCAN1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX5_D, SEL_SCIF5_3),
+	PINMUX_IPSR_MODSEL_DATA(IP11_18_16, IERX_B, SEL_IEBUS_1),
+
+	PINMUX_IPSR_DATA(IP11_20_19, DREQ0),
+	PINMUX_IPSR_MODSEL_DATA(IP11_20_19, SD1_CLK_A, SEL_SDHI1_0),
+	PINMUX_IPSR_DATA(IP11_20_19, ET0_TX_EN),
+
+	PINMUX_IPSR_DATA(IP11_22_21, DACK0),
+	PINMUX_IPSR_MODSEL_DATA(IP11_22_21, SD1_DAT3_A, SEL_SDHI1_0),
+	PINMUX_IPSR_DATA(IP11_22_21, ET0_TX_ER),
+
+	PINMUX_IPSR_DATA(IP11_25_23, DREQ1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_25_23, HSPI_CLK_B, SEL_HSPI_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_25_23, RX4_B, SEL_SCIF4_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_PHY_INT_C, SEL_ET0_CTL_0),
+	PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_TX_CLK_A, SEL_ET0_0),
+
+	PINMUX_IPSR_DATA(IP11_27_26, DACK1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_27_26, HSPI_CS_B, SEL_HSPI_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_27_26, TX4_B, SEL_SCIF3_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_27_26, ET0_RX_CLK_A, SEL_ET0_0),
+
+	PINMUX_IPSR_DATA(IP11_28, PRESETOUT),
+	PINMUX_IPSR_DATA(IP11_28, ST_CLKOUT),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+	PINMUX_GPIO_GP_ALL(),
+
+	GPIO_FN(CLKOUT), GPIO_FN(BS), GPIO_FN(CS0), GPIO_FN(EX_CS0),
+	GPIO_FN(RD), GPIO_FN(WE0), GPIO_FN(WE1),
+	GPIO_FN(SCL0), GPIO_FN(PENC0), GPIO_FN(USB_OVC0),
+	GPIO_FN(IRQ2_B), GPIO_FN(IRQ3_B),
+
+	/* IPSR0 */
+	GPIO_FN(A0), GPIO_FN(ST0_CLKIN), GPIO_FN(LCD_DATA0_A),
+	GPIO_FN(TCLKA_C),
+	GPIO_FN(A1), GPIO_FN(ST0_REQ), GPIO_FN(LCD_DATA1_A),
+	GPIO_FN(TCLKB_C),
+	GPIO_FN(A2), GPIO_FN(ST0_SYC), GPIO_FN(LCD_DATA2_A),
+	GPIO_FN(TCLKC_C),
+	GPIO_FN(A3), GPIO_FN(ST0_VLD), GPIO_FN(LCD_DATA3_A),
+	GPIO_FN(TCLKD_C),
+	GPIO_FN(A4), GPIO_FN(ST0_D0), GPIO_FN(LCD_DATA4_A),
+	GPIO_FN(TIOC0A_C),
+	GPIO_FN(A5), GPIO_FN(ST0_D1), GPIO_FN(LCD_DATA5_A),
+	GPIO_FN(TIOC0B_C),
+	GPIO_FN(A6), GPIO_FN(ST0_D2), GPIO_FN(LCD_DATA6_A),
+	GPIO_FN(TIOC0C_C),
+	GPIO_FN(A7), GPIO_FN(ST0_D3), GPIO_FN(LCD_DATA7_A),
+	GPIO_FN(TIOC0D_C),
+	GPIO_FN(A8), GPIO_FN(ST0_D4), GPIO_FN(LCD_DATA8_A),
+	GPIO_FN(TIOC1A_C),
+	GPIO_FN(A9), GPIO_FN(ST0_D5), GPIO_FN(LCD_DATA9_A),
+	GPIO_FN(TIOC1B_C),
+	GPIO_FN(A10), GPIO_FN(ST0_D6), GPIO_FN(LCD_DATA10_A),
+	GPIO_FN(TIOC2A_C),
+	GPIO_FN(A11), GPIO_FN(ST0_D7), GPIO_FN(LCD_DATA11_A),
+	GPIO_FN(TIOC2B_C),
+	GPIO_FN(A12), GPIO_FN(LCD_DATA12_A), GPIO_FN(TIOC3A_C),
+	GPIO_FN(A13), GPIO_FN(LCD_DATA13_A), GPIO_FN(TIOC3B_C),
+	GPIO_FN(A14), GPIO_FN(LCD_DATA14_A), GPIO_FN(TIOC3C_C),
+	GPIO_FN(A15), GPIO_FN(ST0_VCO_CLKIN), GPIO_FN(LCD_DATA15_A),
+	GPIO_FN(TIOC3D_C),
+
+	/* IPSR1 */
+	GPIO_FN(A16), GPIO_FN(ST0_PWM), GPIO_FN(LCD_DON_A),
+	GPIO_FN(TIOC4A_C),
+	GPIO_FN(A17), GPIO_FN(ST1_VCO_CLKIN), GPIO_FN(LCD_CL1_A),
+	GPIO_FN(TIOC4B_C),
+	GPIO_FN(A18), GPIO_FN(ST1_PWM), GPIO_FN(LCD_CL2_A),
+	GPIO_FN(TIOC4C_C),
+	GPIO_FN(A19), GPIO_FN(ST1_CLKIN), GPIO_FN(LCD_CLK_A),
+	GPIO_FN(TIOC4D_C),
+	GPIO_FN(A20), GPIO_FN(ST1_REQ), GPIO_FN(LCD_FLM_A),
+	GPIO_FN(A21), GPIO_FN(ST1_SYC), GPIO_FN(LCD_VCPWC_A),
+	GPIO_FN(A22), GPIO_FN(ST1_VLD), GPIO_FN(LCD_VEPWC_A),
+	GPIO_FN(A23), GPIO_FN(ST1_D0), GPIO_FN(LCD_M_DISP_A),
+	GPIO_FN(A24), GPIO_FN(RX2_D), GPIO_FN(ST1_D1),
+	GPIO_FN(A25), GPIO_FN(TX2_D), GPIO_FN(ST1_D2),
+	GPIO_FN(D0), GPIO_FN(SD0_DAT0_A), GPIO_FN(MMC_D0_A),
+	GPIO_FN(ST1_D3), GPIO_FN(FD0_A),
+	GPIO_FN(D1), GPIO_FN(SD0_DAT1_A), GPIO_FN(MMC_D1_A),
+	GPIO_FN(ST1_D4), GPIO_FN(FD1_A),
+	GPIO_FN(D2), GPIO_FN(SD0_DAT2_A), GPIO_FN(MMC_D2_A),
+	GPIO_FN(ST1_D5), GPIO_FN(FD2_A),
+	GPIO_FN(D3), GPIO_FN(SD0_DAT3_A), GPIO_FN(MMC_D3_A),
+	GPIO_FN(ST1_D6), GPIO_FN(FD3_A),
+
+	/* IPSR2 */
+	GPIO_FN(D4), GPIO_FN(SD0_CD_A), GPIO_FN(MMC_D4_A), GPIO_FN(ST1_D7),
+	GPIO_FN(FD4_A),
+	GPIO_FN(D5), GPIO_FN(SD0_WP_A), GPIO_FN(MMC_D5_A), GPIO_FN(FD5_A),
+	GPIO_FN(D6), GPIO_FN(RSPI_RSPCK_A), GPIO_FN(MMC_D6_A),
+		GPIO_FN(QSPCLK_A),
+	GPIO_FN(FD6_A),
+	GPIO_FN(D7), GPIO_FN(RSPI_SSL_A), GPIO_FN(MMC_D7_A), GPIO_FN(QSSL_A),
+	GPIO_FN(FD7_A),
+	GPIO_FN(D8), GPIO_FN(SD0_CLK_A), GPIO_FN(MMC_CLK_A), GPIO_FN(QIO2_A),
+	GPIO_FN(FCE_A), GPIO_FN(ET0_GTX_CLK_B),
+	GPIO_FN(D9), GPIO_FN(SD0_CMD_A), GPIO_FN(MMC_CMD_A), GPIO_FN(QIO3_A),
+	GPIO_FN(FCLE_A), GPIO_FN(ET0_ETXD1_B),
+	GPIO_FN(D10), GPIO_FN(RSPI_MOSI_A), GPIO_FN(QMO_QIO0_A),
+		GPIO_FN(FALE_A), GPIO_FN(ET0_ETXD2_B),
+	GPIO_FN(D11), GPIO_FN(RSPI_MISO_A), GPIO_FN(QMI_QIO1_A), GPIO_FN(FRE_A),
+		GPIO_FN(ET0_ETXD3_B),
+	GPIO_FN(D12), GPIO_FN(FWE_A), GPIO_FN(ET0_ETXD5_B),
+	GPIO_FN(D13), GPIO_FN(RX2_B), GPIO_FN(FRB_A), GPIO_FN(ET0_ETXD6_B),
+	GPIO_FN(D14), GPIO_FN(TX2_B), GPIO_FN(FSE_A), GPIO_FN(ET0_TX_CLK_B),
+
+	/* IPSR3 */
+	GPIO_FN(D15), GPIO_FN(SCK2_B),
+	GPIO_FN(CS1_A26), GPIO_FN(QIO3_B),
+	GPIO_FN(EX_CS1), GPIO_FN(RX3_B), GPIO_FN(ATACS0), GPIO_FN(QIO2_B),
+	GPIO_FN(ET0_ETXD0),
+	GPIO_FN(EX_CS2), GPIO_FN(TX3_B), GPIO_FN(ATACS1), GPIO_FN(QSPCLK_B),
+	GPIO_FN(ET0_GTX_CLK_A),
+	GPIO_FN(EX_CS3), GPIO_FN(SD1_CD_A), GPIO_FN(ATARD), GPIO_FN(QMO_QIO0_B),
+	GPIO_FN(ET0_ETXD1_A),
+	GPIO_FN(EX_CS4), GPIO_FN(SD1_WP_A), GPIO_FN(ATAWR), GPIO_FN(QMI_QIO1_B),
+	GPIO_FN(ET0_ETXD2_A),
+	GPIO_FN(EX_CS5), GPIO_FN(SD1_CMD_A), GPIO_FN(ATADIR), GPIO_FN(QSSL_B),
+	GPIO_FN(ET0_ETXD3_A),
+	GPIO_FN(RD_WR), GPIO_FN(TCLK1_B),
+	GPIO_FN(EX_WAIT0), GPIO_FN(TCLK1_B),
+	GPIO_FN(EX_WAIT1), GPIO_FN(SD1_DAT0_A), GPIO_FN(DREQ2),
+		GPIO_FN(CAN1_TX_C), GPIO_FN(ET0_LINK_C), GPIO_FN(ET0_ETXD5_A),
+	GPIO_FN(EX_WAIT2), GPIO_FN(SD1_DAT1_A), GPIO_FN(DACK2),
+		GPIO_FN(CAN1_RX_C), GPIO_FN(ET0_MAGIC_C), GPIO_FN(ET0_ETXD6_A),
+	GPIO_FN(DRACK0), GPIO_FN(SD1_DAT2_A), GPIO_FN(ATAG), GPIO_FN(TCLK1_A),
+	GPIO_FN(ET0_ETXD7),
+
+	/* IPSR4 */
+	GPIO_FN(HCTS0_A), GPIO_FN(CTS1_A), GPIO_FN(VI0_FIELD),
+		GPIO_FN(RMII0_RXD1_A), GPIO_FN(ET0_ERXD7),
+	GPIO_FN(HRTS0_A), GPIO_FN(RTS1_A), GPIO_FN(VI0_HSYNC),
+		GPIO_FN(RMII0_TXD_EN_A), GPIO_FN(ET0_RX_DV),
+	GPIO_FN(HSCK0_A), GPIO_FN(SCK1_A), GPIO_FN(VI0_VSYNC),
+		GPIO_FN(RMII0_RX_ER_A), GPIO_FN(ET0_RX_ER),
+	GPIO_FN(HRX0_A), GPIO_FN(RX1_A), GPIO_FN(VI0_DATA0_VI0_B0),
+		GPIO_FN(RMII0_CRS_DV_A), GPIO_FN(ET0_CRS),
+	GPIO_FN(HTX0_A), GPIO_FN(TX1_A), GPIO_FN(VI0_DATA1_VI0_B1),
+		GPIO_FN(RMII0_MDC_A), GPIO_FN(ET0_COL),
+	GPIO_FN(CTS0_B), GPIO_FN(VI0_DATA2_VI0_B2), GPIO_FN(RMII0_MDIO_A),
+		GPIO_FN(ET0_MDC),
+	GPIO_FN(RTS0_B), GPIO_FN(VI0_DATA3_VI0_B3), GPIO_FN(ET0_MDIO_A),
+	GPIO_FN(SCK1_B), GPIO_FN(VI0_DATA4_VI0_B4), GPIO_FN(ET0_LINK_A),
+	GPIO_FN(RX1_B), GPIO_FN(VI0_DATA5_VI0_B5), GPIO_FN(ET0_MAGIC_A),
+	GPIO_FN(TX1_B), GPIO_FN(VI0_DATA6_VI0_G0), GPIO_FN(ET0_PHY_INT_A),
+	GPIO_FN(CTS1_B), GPIO_FN(VI0_DATA7_VI0_G1),
+	GPIO_FN(RTS1_B), GPIO_FN(VI0_G2),
+	GPIO_FN(SCK2_A), GPIO_FN(VI0_G3),
+
+	/* IPSR5 */
+	GPIO_FN(REF50CK), GPIO_FN(CTS1_E), GPIO_FN(HCTS0_D),
+	GPIO_FN(REF125CK), GPIO_FN(ADTRG), GPIO_FN(RX5_C),
+	GPIO_FN(SD2_WP_A), GPIO_FN(TX5_A), GPIO_FN(VI0_R5),
+	GPIO_FN(SD2_CD_A), GPIO_FN(RX5_A), GPIO_FN(VI0_R4),
+		GPIO_FN(ET0_PHY_INT_B),
+	GPIO_FN(SD2_DAT3_A), GPIO_FN(TX4_A), GPIO_FN(VI0_R3),
+		GPIO_FN(ET0_MAGIC_B),
+	GPIO_FN(SD2_DAT2_A), GPIO_FN(RX4_A), GPIO_FN(VI0_R2),
+		GPIO_FN(ET0_LINK_B),
+	GPIO_FN(SD2_DAT1_A), GPIO_FN(TX3_A), GPIO_FN(VI0_R1),
+		GPIO_FN(ET0_MDIO_B),
+	GPIO_FN(SD2_DAT0_A), GPIO_FN(RX3_A), GPIO_FN(VI0_R0),
+		GPIO_FN(ET0_ERXD3_B),
+	GPIO_FN(SD2_CMD_A), GPIO_FN(TX2_A), GPIO_FN(VI0_G5),
+		GPIO_FN(ET0_ERXD2_B),
+	GPIO_FN(SD2_CLK_A), GPIO_FN(RX2_A), GPIO_FN(VI0_G4),
+		GPIO_FN(ET0_RX_CLK_B),
+
+	/* IPSR6 */
+	GPIO_FN(DU0_DG1), GPIO_FN(CTS1_C), GPIO_FN(HRTS0_D),
+		GPIO_FN(TIOC1B_A), GPIO_FN(HIFD09),
+	GPIO_FN(DU0_DG0), GPIO_FN(TX1_C), GPIO_FN(HSCK0_D),
+		GPIO_FN(IECLK_A), GPIO_FN(TIOC1A_A), GPIO_FN(HIFD08),
+	GPIO_FN(DU0_DR7), GPIO_FN(RX1_C), GPIO_FN(TIOC0D_A),
+		GPIO_FN(HIFD07),
+	GPIO_FN(DU0_DR6), GPIO_FN(SCK1_C), GPIO_FN(TIOC0C_A),
+		GPIO_FN(HIFD06),
+	GPIO_FN(DU0_DR5), GPIO_FN(RTS0_C), GPIO_FN(TIOC0B_A),
+		GPIO_FN(HIFD05),
+	GPIO_FN(DU0_DR4), GPIO_FN(CTS0_C), GPIO_FN(TIOC0A_A),
+		GPIO_FN(HIFD04),
+	GPIO_FN(DU0_DR3), GPIO_FN(TX0_B), GPIO_FN(TCLKD_A), GPIO_FN(HIFD03),
+	GPIO_FN(DU0_DR2), GPIO_FN(RX0_B), GPIO_FN(TCLKC_A), GPIO_FN(HIFD02),
+	GPIO_FN(DU0_DR1), GPIO_FN(SCK0_B), GPIO_FN(HTX0_D),
+		GPIO_FN(IERX_A), GPIO_FN(TCLKB_A), GPIO_FN(HIFD01),
+	GPIO_FN(DU0_DR0), GPIO_FN(SCIF_CLK_B), GPIO_FN(HRX0_D),
+		GPIO_FN(IETX_A), GPIO_FN(TCLKA_A), GPIO_FN(HIFD00),
+
+	/* IPSR7 */
+	GPIO_FN(DU0_DB4), GPIO_FN(HIFINT),
+	GPIO_FN(DU0_DB3), GPIO_FN(TX5_B), GPIO_FN(TIOC4D_A), GPIO_FN(HIFRD),
+	GPIO_FN(DU0_DB2), GPIO_FN(RX5_B), GPIO_FN(RMII0_TXD1_B),
+		GPIO_FN(TIOC4C_A), GPIO_FN(HIFWR),
+	GPIO_FN(DU0_DB1), GPIO_FN(TX4_C), GPIO_FN(RMII0_TXD0_B),
+		GPIO_FN(TIOC4B_A), GPIO_FN(HIFRS),
+	GPIO_FN(DU0_DB0), GPIO_FN(RX4_C), GPIO_FN(RMII0_TXD_EN_B),
+		GPIO_FN(TIOC4A_A), GPIO_FN(HIFCS),
+	GPIO_FN(DU0_DG7), GPIO_FN(TX3_C), GPIO_FN(RMII0_RXD1_B),
+		GPIO_FN(TIOC3D_A), GPIO_FN(HIFD15),
+	GPIO_FN(DU0_DG6), GPIO_FN(RX3_C), GPIO_FN(RMII0_RXD0_B),
+		GPIO_FN(TIOC3C_A), GPIO_FN(HIFD14),
+	GPIO_FN(DU0_DG5), GPIO_FN(TX2_C), GPIO_FN(RMII0_RX_ER_B),
+		GPIO_FN(TIOC3B_A), GPIO_FN(HIFD13),
+	GPIO_FN(DU0_DG4), GPIO_FN(RX2_C), GPIO_FN(RMII0_CRS_DV_B),
+		GPIO_FN(TIOC3A_A), GPIO_FN(HIFD12),
+	GPIO_FN(DU0_DG3), GPIO_FN(SCK2_C), GPIO_FN(RMII0_MDIO_B),
+		GPIO_FN(TIOC2B_A), GPIO_FN(HIFD11),
+	GPIO_FN(DU0_DG2), GPIO_FN(RTS1_C), GPIO_FN(RMII0_MDC_B),
+		GPIO_FN(TIOC2A_A), GPIO_FN(HIFD10),
+
+	/* IPSR8 */
+	GPIO_FN(IRQ3_A), GPIO_FN(RTS0_A), GPIO_FN(HRTS0_B),
+		GPIO_FN(ET0_ERXD3_A),
+	GPIO_FN(IRQ2_A), GPIO_FN(CTS0_A), GPIO_FN(HCTS0_B),
+		GPIO_FN(ET0_ERXD2_A),
+	GPIO_FN(IRQ1_A), GPIO_FN(HSPI_RX_B), GPIO_FN(TX3_E),
+		GPIO_FN(ET0_ERXD1),
+	GPIO_FN(IRQ0_A), GPIO_FN(HSPI_TX_B), GPIO_FN(RX3_E),
+		GPIO_FN(ET0_ERXD0),
+	GPIO_FN(DU0_CDE), GPIO_FN(HTX0_B), GPIO_FN(AUDIO_CLKB_B),
+		GPIO_FN(LCD_VCPWC_B),
+	GPIO_FN(DU0_DISP), GPIO_FN(CAN0_TX_B), GPIO_FN(HRX0_B),
+		GPIO_FN(AUDIO_CLKA_B),
+	GPIO_FN(DU0_EXODDF_DU0_ODDF), GPIO_FN(CAN0_RX_B), GPIO_FN(HSCK0_B),
+		GPIO_FN(SSI_SDATA1_B),
+	GPIO_FN(DU0_EXVSYNC_DU0_VSYNC), GPIO_FN(HSPI_RX0_C),
+		GPIO_FN(SSI_WS1_B),
+	GPIO_FN(DU0_EXHSYNC_DU0_HSYNC), GPIO_FN(HSPI_TX0_C),
+		GPIO_FN(SSI_SCK1_B),
+	GPIO_FN(DU0_DOTCLKOUT), GPIO_FN(HSPI_CLK0_C),
+		GPIO_FN(SSI_SDATA0_B),
+	GPIO_FN(DU0_DOTCLKIN), GPIO_FN(HSPI_CS0_C),
+		GPIO_FN(SSI_WS0_B),
+	GPIO_FN(DU0_DB7), GPIO_FN(SSI_SCK0_B), GPIO_FN(HIFEBL_B),
+	GPIO_FN(DU0_DB6), GPIO_FN(HIFRDY),
+	GPIO_FN(DU0_DB5), GPIO_FN(HIFDREQ),
+
+	/* IPSR9 */
+	GPIO_FN(SSI_SDATA1_A), GPIO_FN(VI1_3_B), GPIO_FN(LCD_DATA14_B),
+	GPIO_FN(SSI_WS1_A), GPIO_FN(VI1_2_B), GPIO_FN(LCD_DATA13_B),
+	GPIO_FN(SSI_SCK1_A), GPIO_FN(VI1_1_B), GPIO_FN(TIOC2B_B),
+		GPIO_FN(LCD_DATA12_B),
+	GPIO_FN(SSI_SDATA0_A), GPIO_FN(VI1_0_B), GPIO_FN(TIOC2A_B),
+		GPIO_FN(LCD_DATA11_B),
+	GPIO_FN(SSI_WS0_A), GPIO_FN(TIOC1B_B), GPIO_FN(LCD_DATA10_B),
+	GPIO_FN(SSI_SCK0_A), GPIO_FN(TIOC1A_B), GPIO_FN(LCD_DATA9_B),
+	GPIO_FN(VI1_7_A), GPIO_FN(FCE_B), GPIO_FN(LCD_DATA8_B),
+	GPIO_FN(VI1_6_A), GPIO_FN(FD7_B), GPIO_FN(LCD_DATA7_B),
+	GPIO_FN(VI1_5_A), GPIO_FN(FD6_B), GPIO_FN(LCD_DATA6_B),
+	GPIO_FN(VI1_4_A), GPIO_FN(FD5_B), GPIO_FN(LCD_DATA5_B),
+	GPIO_FN(VI1_3_A), GPIO_FN(FD4_B), GPIO_FN(LCD_DATA4_B),
+	GPIO_FN(VI1_2_A), GPIO_FN(FD3_B), GPIO_FN(LCD_DATA3_B),
+	GPIO_FN(VI1_1_A), GPIO_FN(FD2_B), GPIO_FN(LCD_DATA2_B),
+	GPIO_FN(VI1_0_A), GPIO_FN(FD1_B), GPIO_FN(LCD_DATA1_B),
+	GPIO_FN(VI1_CLK_A), GPIO_FN(FD0_B), GPIO_FN(LCD_DATA0_B),
+
+	/* IPSR10 */
+	GPIO_FN(CAN1_TX_A), GPIO_FN(TX5_C), GPIO_FN(MLB_DAT),
+	GPIO_FN(CAN0_RX_A), GPIO_FN(IRQ0_B), GPIO_FN(MLB_SIG),
+	GPIO_FN(CAN1_RX_A), GPIO_FN(IRQ1_B),
+	GPIO_FN(CAN0_TX_A), GPIO_FN(TX4_D), GPIO_FN(MLB_CLK),
+	GPIO_FN(CAN_CLK_A), GPIO_FN(RX4_D),
+	GPIO_FN(AUDIO_CLKOUT), GPIO_FN(TX1_E), GPIO_FN(HRTS0_C),
+		GPIO_FN(FSE_B), GPIO_FN(LCD_M_DISP_B),
+	GPIO_FN(AUDIO_CLKC), GPIO_FN(SCK1_E), GPIO_FN(HCTS0_C),
+		GPIO_FN(FRB_B), GPIO_FN(LCD_VEPWC_B),
+	GPIO_FN(AUDIO_CLKB_A), GPIO_FN(LCD_CLK_B),
+	GPIO_FN(AUDIO_CLKA_A), GPIO_FN(VI1_CLK_B), GPIO_FN(SCK1_D),
+		GPIO_FN(IECLK_B), GPIO_FN(LCD_FLM_B),
+	GPIO_FN(SSI_SDATA3), GPIO_FN(VI1_7_B), GPIO_FN(HTX0_C),
+		GPIO_FN(FWE_B), GPIO_FN(LCD_CL2_B),
+	GPIO_FN(SSI_SDATA2), GPIO_FN(VI1_6_B), GPIO_FN(HRX0_C),
+		GPIO_FN(FRE_B), GPIO_FN(LCD_CL1_B),
+	GPIO_FN(SSI_WS23), GPIO_FN(VI1_5_B), GPIO_FN(TX1_D),
+		GPIO_FN(HSCK0_C), GPIO_FN(FALE_B), GPIO_FN(LCD_DON_B),
+	GPIO_FN(SSI_SCK23), GPIO_FN(VI1_4_B), GPIO_FN(RX1_D),
+		GPIO_FN(FCLE_B), GPIO_FN(LCD_DATA15_B),
+
+	/* IPSR11 */
+	GPIO_FN(PRESETOUT), GPIO_FN(ST_CLKOUT),
+	GPIO_FN(DACK1), GPIO_FN(HSPI_CS_B), GPIO_FN(TX4_B),
+		GPIO_FN(ET0_RX_CLK_A),
+	GPIO_FN(DREQ1), GPIO_FN(HSPI_CLK_B), GPIO_FN(RX4_B),
+		GPIO_FN(ET0_PHY_INT_C), GPIO_FN(ET0_TX_CLK_A),
+	GPIO_FN(DACK0), GPIO_FN(SD1_DAT3_A), GPIO_FN(ET0_TX_ER),
+	GPIO_FN(DREQ0), GPIO_FN(SD1_CLK_A), GPIO_FN(ET0_TX_EN),
+	GPIO_FN(USB_OVC1), GPIO_FN(RX3_D), GPIO_FN(CAN1_RX_B),
+		GPIO_FN(RX5_D), GPIO_FN(IERX_B),
+	GPIO_FN(PENC1), GPIO_FN(TX3_D), GPIO_FN(CAN1_TX_B),
+		GPIO_FN(TX5_D), GPIO_FN(IETX_B),
+	GPIO_FN(TX0_A), GPIO_FN(HSPI_TX_A),
+	GPIO_FN(RX0_A), GPIO_FN(HSPI_RX_A), GPIO_FN(RMII0_RXD0_A),
+		GPIO_FN(ET0_ERXD6),
+	GPIO_FN(SCK0_A), GPIO_FN(HSPI_CS_A), GPIO_FN(VI0_CLKENB),
+		GPIO_FN(RMII0_TXD1_A), GPIO_FN(ET0_ERXD5),
+	GPIO_FN(SCIF_CLK_A), GPIO_FN(HSPI_CLK_A), GPIO_FN(VI0_CLK),
+		GPIO_FN(RMII0_TXD0_A), GPIO_FN(ET0_ERXD4),
+	GPIO_FN(SDSELF), GPIO_FN(RTS1_E),
+	GPIO_FN(SDA0), GPIO_FN(HIFEBL_A),
+	GPIO_FN(SDA1), GPIO_FN(RX1_E),
+	GPIO_FN(SCL1), GPIO_FN(SCIF_CLK_C),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+	{ PINMUX_CFG_REG("GPSR0", 0xFFFC0004, 32, 1) {
+		GP_0_31_FN, FN_IP2_2_0,
+		GP_0_30_FN, FN_IP1_31_29,
+		GP_0_29_FN, FN_IP1_28_26,
+		GP_0_28_FN, FN_IP1_25_23,
+		GP_0_27_FN, FN_IP1_22_20,
+		GP_0_26_FN, FN_IP1_19_18,
+		GP_0_25_FN, FN_IP1_17_16,
+		GP_0_24_FN, FN_IP0_5_4,
+		GP_0_23_FN, FN_IP0_3_2,
+		GP_0_22_FN, FN_IP0_1_0,
+		GP_0_21_FN, FN_IP11_28,
+		GP_0_20_FN, FN_IP1_7_6,
+		GP_0_19_FN, FN_IP1_5_4,
+		GP_0_18_FN, FN_IP1_3_2,
+		GP_0_17_FN, FN_IP1_1_0,
+		GP_0_16_FN, FN_IP0_31_30,
+		GP_0_15_FN, FN_IP0_29_28,
+		GP_0_14_FN, FN_IP0_27_26,
+		GP_0_13_FN, FN_IP0_25_24,
+		GP_0_12_FN, FN_IP0_23_22,
+		GP_0_11_FN, FN_IP0_21_20,
+		GP_0_10_FN, FN_IP0_19_18,
+		GP_0_9_FN, FN_IP0_17_16,
+		GP_0_8_FN, FN_IP0_15_14,
+		GP_0_7_FN, FN_IP0_13_12,
+		GP_0_6_FN, FN_IP0_11_10,
+		GP_0_5_FN, FN_IP0_9_8,
+		GP_0_4_FN, FN_IP0_7_6,
+		GP_0_3_FN, FN_IP1_15_14,
+		GP_0_2_FN, FN_IP1_13_12,
+		GP_0_1_FN, FN_IP1_11_10,
+		GP_0_0_FN, FN_IP1_9_8 }
+	},
+	{ PINMUX_CFG_REG("GPSR1", 0xFFFC0008, 32, 1) {
+		GP_1_31_FN, FN_IP11_25_23,
+		GP_1_30_FN, FN_IP2_13_11,
+		GP_1_29_FN, FN_IP2_10_8,
+		GP_1_28_FN, FN_IP2_7_5,
+		GP_1_27_FN, FN_IP3_26_24,
+		GP_1_26_FN, FN_IP3_23_21,
+		GP_1_25_FN, FN_IP2_4_3,
+		GP_1_24_FN, FN_WE1,
+		GP_1_23_FN, FN_WE0,
+		GP_1_22_FN, FN_IP3_19_18,
+		GP_1_21_FN, FN_RD,
+		GP_1_20_FN, FN_IP3_17_15,
+		GP_1_19_FN, FN_IP3_14_12,
+		GP_1_18_FN, FN_IP3_11_9,
+		GP_1_17_FN, FN_IP3_8_6,
+		GP_1_16_FN, FN_IP3_5_3,
+		GP_1_15_FN, FN_EX_CS0,
+		GP_1_14_FN, FN_IP3_2,
+		GP_1_13_FN, FN_CS0,
+		GP_1_12_FN, FN_BS,
+		GP_1_11_FN, FN_CLKOUT,
+		GP_1_10_FN, FN_IP3_1_0,
+		GP_1_9_FN, FN_IP2_30_28,
+		GP_1_8_FN, FN_IP2_27_25,
+		GP_1_7_FN, FN_IP2_24_23,
+		GP_1_6_FN, FN_IP2_22_20,
+		GP_1_5_FN, FN_IP2_19_17,
+		GP_1_4_FN, FN_IP2_16_14,
+		GP_1_3_FN, FN_IP11_22_21,
+		GP_1_2_FN, FN_IP11_20_19,
+		GP_1_1_FN, FN_IP3_29_27,
+		GP_1_0_FN, FN_IP3_20 }
+	},
+	{ PINMUX_CFG_REG("GPSR2", 0xFFFC000C, 32, 1) {
+		GP_2_31_FN, FN_IP4_31_30,
+		GP_2_30_FN, FN_IP5_2_0,
+		GP_2_29_FN, FN_IP5_5_3,
+		GP_2_28_FN, FN_IP5_8_6,
+		GP_2_27_FN, FN_IP5_11_9,
+		GP_2_26_FN, FN_IP5_14_12,
+		GP_2_25_FN, FN_IP5_17_15,
+		GP_2_24_FN, FN_IP5_20_18,
+		GP_2_23_FN, FN_IP5_22_21,
+		GP_2_22_FN, FN_IP5_24_23,
+		GP_2_21_FN, FN_IP5_26_25,
+		GP_2_20_FN, FN_IP4_29_28,
+		GP_2_19_FN, FN_IP4_27_26,
+		GP_2_18_FN, FN_IP4_25_24,
+		GP_2_17_FN, FN_IP4_23_22,
+		GP_2_16_FN, FN_IP4_21_20,
+		GP_2_15_FN, FN_IP4_19_18,
+		GP_2_14_FN, FN_IP4_17_15,
+		GP_2_13_FN, FN_IP4_14_12,
+		GP_2_12_FN, FN_IP4_11_9,
+		GP_2_11_FN, FN_IP4_8_6,
+		GP_2_10_FN, FN_IP4_5_3,
+		GP_2_9_FN, FN_IP8_27_26,
+		GP_2_8_FN, FN_IP11_12,
+		GP_2_7_FN, FN_IP8_25_23,
+		GP_2_6_FN, FN_IP8_22_20,
+		GP_2_5_FN, FN_IP11_27_26,
+		GP_2_4_FN, FN_IP8_29_28,
+		GP_2_3_FN, FN_IP4_2_0,
+		GP_2_2_FN, FN_IP11_11_10,
+		GP_2_1_FN, FN_IP11_9_7,
+		GP_2_0_FN, FN_IP11_6_4 }
+	},
+	{ PINMUX_CFG_REG("GPSR3", 0xFFFC0010, 32, 1) {
+		GP_3_31_FN, FN_IP9_1_0,
+		GP_3_30_FN, FN_IP8_19_18,
+		GP_3_29_FN, FN_IP8_17_16,
+		GP_3_28_FN, FN_IP8_15_14,
+		GP_3_27_FN, FN_IP8_13_12,
+		GP_3_26_FN, FN_IP8_11_10,
+		GP_3_25_FN, FN_IP8_9_8,
+		GP_3_24_FN, FN_IP8_7_6,
+		GP_3_23_FN, FN_IP8_5_4,
+		GP_3_22_FN, FN_IP8_3_2,
+		GP_3_21_FN, FN_IP8_1_0,
+		GP_3_20_FN, FN_IP7_30_29,
+		GP_3_19_FN, FN_IP7_28_27,
+		GP_3_18_FN, FN_IP7_26_24,
+		GP_3_17_FN, FN_IP7_23_21,
+		GP_3_16_FN, FN_IP7_20_18,
+		GP_3_15_FN, FN_IP7_17_15,
+		GP_3_14_FN, FN_IP7_14_12,
+		GP_3_13_FN, FN_IP7_11_9,
+		GP_3_12_FN, FN_IP7_8_6,
+		GP_3_11_FN, FN_IP7_5_3,
+		GP_3_10_FN, FN_IP7_2_0,
+		GP_3_9_FN, FN_IP6_23_21,
+		GP_3_8_FN, FN_IP6_20_18,
+		GP_3_7_FN, FN_IP6_17_16,
+		GP_3_6_FN, FN_IP6_15_14,
+		GP_3_5_FN, FN_IP6_13_12,
+		GP_3_4_FN, FN_IP6_11_10,
+		GP_3_3_FN, FN_IP6_9_8,
+		GP_3_2_FN, FN_IP6_7_6,
+		GP_3_1_FN, FN_IP6_5_3,
+		GP_3_0_FN, FN_IP6_2_0 }
+	},
+
+	{ PINMUX_CFG_REG("GPSR4", 0xFFFC0014, 32, 1) {
+		GP_4_31_FN, FN_IP10_24_23,
+		GP_4_30_FN, FN_IP10_22,
+		GP_4_29_FN, FN_IP11_18_16,
+		GP_4_28_FN, FN_USB_OVC0,
+		GP_4_27_FN, FN_IP11_15_13,
+		GP_4_26_FN, FN_PENC0,
+		GP_4_25_FN, FN_IP11_2,
+		GP_4_24_FN, FN_SCL0,
+		GP_4_23_FN, FN_IP11_1,
+		GP_4_22_FN, FN_IP11_0,
+		GP_4_21_FN, FN_IP10_21_19,
+		GP_4_20_FN, FN_IP10_18_16,
+		GP_4_19_FN, FN_IP10_15,
+		GP_4_18_FN, FN_IP10_14_12,
+		GP_4_17_FN, FN_IP10_11_9,
+		GP_4_16_FN, FN_IP10_8_6,
+		GP_4_15_FN, FN_IP10_5_3,
+		GP_4_14_FN, FN_IP10_2_0,
+		GP_4_13_FN, FN_IP9_29_28,
+		GP_4_12_FN, FN_IP9_27_26,
+		GP_4_11_FN, FN_IP9_9_8,
+		GP_4_10_FN, FN_IP9_7_6,
+		GP_4_9_FN, FN_IP9_5_4,
+		GP_4_8_FN, FN_IP9_3_2,
+		GP_4_7_FN, FN_IP9_17_16,
+		GP_4_6_FN, FN_IP9_15_14,
+		GP_4_5_FN, FN_IP9_13_12,
+		GP_4_4_FN, FN_IP9_11_10,
+		GP_4_3_FN, FN_IP9_25_24,
+		GP_4_2_FN, FN_IP9_23_22,
+		GP_4_1_FN, FN_IP9_21_20,
+		GP_4_0_FN, FN_IP9_19_18 }
+	},
+	{ PINMUX_CFG_REG("GPSR5", 0xFFFC0018, 32, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 28 */
+		0, 0, 0, 0, 0, 0, 0, 0, /* 27 - 24 */
+		0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 20 */
+		0, 0, 0, 0, 0, 0, 0, 0, /* 19 - 16 */
+		0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
+		GP_5_11_FN, FN_IP10_29_28,
+		GP_5_10_FN, FN_IP10_27_26,
+		0, 0, 0, 0, 0, 0, 0, 0, /* 9 - 6 */
+		0, 0, 0, 0, /* 5, 4 */
+		GP_5_3_FN, FN_IRQ3_B,
+		GP_5_2_FN, FN_IRQ2_B,
+		GP_5_1_FN, FN_IP11_3,
+		GP_5_0_FN, FN_IP10_25 }
+	},
+
+	{ PINMUX_CFG_REG_VAR("IPSR0", 0xFFFC001C, 32,
+			2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 2, 2, 2) {
+		/* IP0_31_30 [2] */
+		FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A,
+			FN_TIOC3D_C,
+		/* IP0_29_28 [2] */
+		FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C, 0,
+		/* IP0_27_26 [2] */
+		FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C, 0,
+		/* IP0_25_24 [2] */
+		FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C, 0,
+		/* IP0_23_22 [2] */
+		FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
+		/* IP0_21_20 [2] */
+		FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
+		/* IP0_19_18 [2] */
+		FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
+		/* IP0_17_16 [2] */
+		FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
+		/* IP0_15_14 [2] */
+		FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
+		/* IP0_13_12 [2] */
+		FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
+		/* IP0_11_10 [2] */
+		FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
+		/* IP0_9_8 [2] */
+		FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
+		/* IP0_7_6 [2] */
+		FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
+		/* IP0_5_4 [2] */
+		FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
+		/* IP0_3_2 [2] */
+		FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
+		/* IP0_1_0 [2] */
+		FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR1", 0xFFFC0020, 32,
+			3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
+		/* IP1_31_29 [3] */
+		FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6,
+			FN_FD3_A, 0, 0, 0,
+		/* IP1_28_26 [3] */
+		FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5,
+			FN_FD2_A, 0, 0, 0,
+		/* IP1_25_23 [3] */
+		FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4,
+			FN_FD1_A, 0, 0, 0,
+		/* IP1_22_20 [3] */
+		FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3,
+			FN_FD0_A, 0, 0, 0,
+		/* IP1_19_18 [2] */
+		FN_A25, FN_TX2_D, FN_ST1_D2, 0,
+		/* IP1_17_16 [2] */
+		FN_A24, FN_RX2_D, FN_ST1_D1, 0,
+		/* IP1_15_14 [2] */
+		FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A, 0,
+		/* IP1_13_12 [2] */
+		FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A, 0,
+		/* IP1_11_10 [2] */
+		FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A, 0,
+		/* IP1_9_8 [2] */
+		FN_A20, FN_ST1_REQ, FN_LCD_FLM_A, 0,
+		/* IP1_7_6 [2] */
+		FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A,	FN_TIOC4D_C,
+		/* IP1_5_4 [2] */
+		FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
+		/* IP1_3_2 [2] */
+		FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A,	FN_TIOC4B_C,
+		/* IP1_1_0 [2] */
+		FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR2", 0xFFFC0024, 32,
+			     1, 3, 3, 2, 3, 3, 3, 3, 3, 3, 2, 3) {
+		/* IP2_31 [1] */
+		0, 0,
+		/* IP2_30_28 [3] */
+		FN_D14, FN_TX2_B, 0, FN_FSE_A,
+			FN_ET0_TX_CLK_B, 0, 0, 0,
+		/* IP2_27_25 [3] */
+		FN_D13, FN_RX2_B, 0, FN_FRB_A,
+			FN_ET0_ETXD6_B, 0, 0, 0,
+		/* IP2_24_23 [2] */
+		FN_D12, 0, FN_FWE_A, FN_ET0_ETXD5_B,
+		/* IP2_22_20 [3] */
+		FN_D11, FN_RSPI_MISO_A, 0, FN_QMI_QIO1_A,
+			FN_FRE_A, FN_ET0_ETXD3_B, 0, 0,
+		/* IP2_19_17 [3] */
+		FN_D10, FN_RSPI_MOSI_A, 0, FN_QMO_QIO0_A,
+			FN_FALE_A, FN_ET0_ETXD2_B, 0, 0,
+		/* IP2_16_14 [3] */
+		FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A,
+			FN_FCLE_A, FN_ET0_ETXD1_B, 0, 0,
+		/* IP2_13_11 [3] */
+		FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A,
+			FN_FCE_A, FN_ET0_GTX_CLK_B, 0, 0,
+		/* IP2_10_8 [3] */
+		FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A,
+			FN_FD7_A, 0, 0, 0,
+		/* IP2_7_5 [3] */
+		FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A,
+			FN_FD6_A, 0, 0, 0,
+		/* IP2_4_3 [2] */
+		FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
+		/* IP2_2_0 [3] */
+		FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7,
+			FN_FD4_A, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR3", 0xFFFC0028, 32,
+				2, 3, 3, 3, 1, 2, 3, 3, 3, 3, 3, 1, 2) {
+	    /* IP3_31_30 [2] */
+		0, 0, 0, 0,
+	    /* IP3_29_27 [3] */
+		FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A,
+		FN_ET0_ETXD7, 0, 0, 0,
+	    /* IP3_26_24 [3] */
+		FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
+		FN_ET0_MAGIC_C, FN_ET0_ETXD6_A, 0, 0,
+	    /* IP3_23_21 [3] */
+		FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
+		FN_ET0_LINK_C, FN_ET0_ETXD5_A, 0, 0,
+	    /* IP3_20 [1] */
+		FN_EX_WAIT0, FN_TCLK1_B,
+	    /* IP3_19_18 [2] */
+		FN_RD_WR, FN_TCLK1_B, 0, 0,
+	    /* IP3_17_15 [3] */
+		FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B,
+		FN_ET0_ETXD3_A, 0, 0, 0,
+	    /* IP3_14_12 [3] */
+		FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B,
+		FN_ET0_ETXD2_A, 0, 0, 0,
+	    /* IP3_11_9 [3] */
+		FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B,
+		FN_ET0_ETXD1_A, 0, 0, 0,
+	    /* IP3_8_6 [3] */
+		FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B,
+		FN_ET0_GTX_CLK_A, 0, 0, 0,
+	    /* IP3_5_3 [3] */
+		FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B,
+		FN_ET0_ETXD0, 0, 0, 0,
+	    /* IP3_2 [1] */
+		FN_CS1_A26, FN_QIO3_B,
+	    /* IP3_1_0 [2] */
+		FN_D15, FN_SCK2_B, 0, 0 }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR4", 0xFFFC002C, 32,
+				2, 2, 2, 2, 2, 2 , 2, 3, 3, 3, 3, 3, 3) {
+	    /* IP4_31_30 [2] */
+		0, FN_SCK2_A, FN_VI0_G3, 0,
+	    /* IP4_29_28 [2] */
+		0, FN_RTS1_B, FN_VI0_G2, 0,
+	    /* IP4_27_26 [2] */
+		0, FN_CTS1_B, FN_VI0_DATA7_VI0_G1, 0,
+	    /* IP4_25_24 [2] */
+		0, FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
+	    /* IP4_23_22 [2] */
+		0, FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
+	    /* IP4_21_20 [2] */
+		0, FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
+	    /* IP4_19_18 [2] */
+		0, FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
+	    /* IP4_17_15 [3] */
+		0, FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A,
+			FN_ET0_MDC, 0, 0, 0,
+	    /* IP4_14_12 [3] */
+		FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A,
+			FN_ET0_COL, 0, 0, 0,
+	    /* IP4_11_9 [3] */
+		FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A,
+			FN_ET0_CRS, 0, 0, 0,
+	    /* IP4_8_6 [3] */
+		FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A,
+			FN_ET0_RX_ER, 0, 0, 0,
+	    /* IP4_5_3 [3] */
+		FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A,
+			FN_ET0_RX_DV, 0, 0, 0,
+	    /* IP4_2_0 [3] */
+		FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A,
+			FN_ET0_ERXD7, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR5", 0xFFFC0030, 32,
+				1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3) {
+	    /* IP5_31 [1] */
+	    0, 0,
+	    /* IP5_30 [1] */
+	    0, 0,
+	    /* IP5_29 [1] */
+	    0, 0,
+	    /* IP5_28 [1] */
+	    0, 0,
+	    /* IP5_27 [1] */
+	    0, 0,
+	    /* IP5_26_25 [2] */
+		FN_REF50CK, FN_CTS1_E, FN_HCTS0_D, 0,
+	    /* IP5_24_23 [2] */
+		FN_REF125CK, FN_ADTRG, FN_RX5_C, 0,
+	    /* IP5_22_21 [2] */
+		FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5, 0,
+	    /* IP5_20_18 [3] */
+		FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, 0,
+		0, 0, 0, FN_ET0_PHY_INT_B,
+	    /* IP5_17_15 [3] */
+		FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, 0,
+		0, 0, 0, FN_ET0_MAGIC_B,
+	    /* IP5_14_12 [3] */
+		FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, 0,
+		0, 0, 0, FN_ET0_LINK_B,
+	    /* IP5_11_9 [3] */
+		FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, 0,
+		0, 0, 0, FN_ET0_MDIO_B,
+	    /* IP5_8_6 [3] */
+		FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, 0,
+		0, 0, 0, FN_ET0_ERXD3_B,
+	    /* IP5_5_3 [3] */
+		FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, 0,
+		0, 0, 0, FN_ET0_ERXD2_B,
+	    /* IP5_2_0 [3] */
+		FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, 0,
+		FN_ET0_RX_CLK_B, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR6", 0xFFFC0034, 32,
+				1, 1, 1, 1, 1, 1, 1, 1,
+				3, 3, 2, 2, 2, 2, 2, 2, 3, 3) {
+	    /* IP5_31 [1] */
+	    0, 0,
+	    /* IP6_30 [1] */
+	    0, 0,
+	    /* IP6_29 [1] */
+	    0, 0,
+	    /* IP6_28 [1] */
+	    0, 0,
+	    /* IP6_27 [1] */
+	    0, 0,
+	    /* IP6_26 [1] */
+	    0, 0,
+	    /* IP6_25 [1] */
+	    0, 0,
+	    /* IP6_24 [1] */
+	    0, 0,
+	    /* IP6_23_21 [3] */
+		FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A,
+		FN_HIFD09, 0, 0, 0,
+	    /* IP6_20_18 [3] */
+		FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A,
+		FN_TIOC1A_A, FN_HIFD08, 0, 0,
+	    /* IP6_17_16 [2] */
+		FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
+	    /* IP6_15_14 [2] */
+		FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
+	    /* IP6_13_12 [2] */
+		FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
+	    /* IP6_11_10 [2] */
+		FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
+	    /* IP6_9_8 [2] */
+		FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
+	    /* IP6_7_6 [2] */
+		FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
+	    /* IP6_5_3 [3] */
+		FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A,
+		FN_TCLKB_A, FN_HIFD01, 0, 0,
+	    /* IP6_2_0 [3] */
+		FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A,
+		FN_TCLKA_A, FN_HIFD00, 0, 0 }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR7", 0xFFFC0038, 32,
+			     1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) {
+	    /* IP7_31 [1] */
+	    0, 0,
+	    /* IP7_30_29 [2] */
+		FN_DU0_DB4, 0, FN_HIFINT, 0,
+	    /* IP7_28_27 [2] */
+		FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
+	    /* IP7_26_24 [3] */
+		FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A,
+		FN_HIFWR, 0, 0, 0,
+	    /* IP7_23_21 [3] */
+		FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A,
+		FN_HIFRS, 0, 0, 0,
+	    /* IP7_20_18 [3] */
+		FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A,
+		FN_HIFCS, 0, 0, 0,
+	    /* IP7_17_15 [3] */
+		FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A,
+		FN_HIFD15, 0, 0, 0,
+	    /* IP7_14_12 [3] */
+		FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A,
+		FN_HIFD14, 0, 0, 0,
+	    /* IP7_11_9 [3] */
+		FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A,
+		FN_HIFD13, 0, 0, 0,
+	    /* IP7_8_6 [3] */
+		FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A,
+		FN_HIFD12, 0, 0, 0,
+	    /* IP7_5_3 [3] */
+		FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A,
+		FN_HIFD11, 0, 0, 0,
+	    /* IP7_2_0 [3] */
+		FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A,
+		FN_HIFD10, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR8", 0xFFFC003C, 32,
+			     2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
+	    /* IP9_31_30 [2] */
+	    0, 0, 0, 0,
+	    /* IP8_29_28 [2] */
+		FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
+	    /* IP8_27_26 [2] */
+		FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
+	    /* IP8_25_23 [3] */
+		FN_IRQ1_A, 0, FN_HSPI_RX_B, FN_TX3_E,
+			FN_ET0_ERXD1, 0, 0, 0,
+	    /* IP8_22_20 [3] */
+		FN_IRQ0_A, 0, FN_HSPI_TX_B, FN_RX3_E,
+			FN_ET0_ERXD0, 0, 0, 0,
+	    /* IP8_19_18 [2] */
+		FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
+	    /* IP8_17_16 [2] */
+		FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
+	    /* IP8_15_14 [2] */
+		FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B,
+			FN_SSI_SDATA1_B,
+	    /* IP8_13_12 [2] */
+		FN_DU0_EXVSYNC_DU0_VSYNC, 0, FN_HSPI_RX0_C, FN_SSI_WS1_B,
+	    /* IP8_11_10 [2] */
+		FN_DU0_EXHSYNC_DU0_HSYNC, 0, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
+	    /* IP8_9_8 [2] */
+		FN_DU0_DOTCLKOUT, 0, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
+	    /* IP8_7_6 [2] */
+		FN_DU0_DOTCLKIN, 0, FN_HSPI_CS0_C, FN_SSI_WS0_B,
+	    /* IP8_5_4 [2] */
+		FN_DU0_DB7, 0, FN_SSI_SCK0_B, FN_HIFEBL_B,
+	    /* IP8_3_2 [2] */
+		FN_DU0_DB6, 0, FN_HIFRDY, 0,
+	    /* IP8_1_0 [2] */
+		FN_DU0_DB5, 0, FN_HIFDREQ, 0 }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR9", 0xFFFC0040, 32,
+			     2, 2, 2, 2, 2, 2, 2, 2,
+			     2, 2, 2, 2, 2, 2, 2, 2) {
+	    /* IP9_31_30 [2] */
+	    0, 0, 0, 0,
+	    /* IP9_29_28 [2] */
+		FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B, 0,
+	    /* IP9_27_26 [2] */
+		FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B, 0,
+	    /* IP9_25_24 [2] */
+		FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
+	    /* IP9_23_22 [2] */
+		FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
+	    /* IP9_21_20 [2] */
+		FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B, 0,
+	    /* IP9_19_18 [2] */
+		FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B, 0,
+	    /* IP9_17_16 [2] */
+		FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B, 0,
+	    /* IP9_15_14 [2] */
+		FN_VI1_6_A, 0, FN_FD7_B, FN_LCD_DATA7_B,
+	    /* IP9_13_12 [2] */
+		FN_VI1_5_A, 0, FN_FD6_B, FN_LCD_DATA6_B,
+	    /* IP9_11_10 [2] */
+		FN_VI1_4_A, 0, FN_FD5_B, FN_LCD_DATA5_B,
+	    /* IP9_9_8 [2] */
+		FN_VI1_3_A, 0, FN_FD4_B, FN_LCD_DATA4_B,
+	    /* IP9_7_6 [2] */
+		FN_VI1_2_A, 0, FN_FD3_B, FN_LCD_DATA3_B,
+	    /* IP9_5_4 [2] */
+		FN_VI1_1_A, 0, FN_FD2_B, FN_LCD_DATA2_B,
+	    /* IP9_3_2 [2] */
+		FN_VI1_0_A, 0, FN_FD1_B, FN_LCD_DATA1_B,
+	    /* IP9_1_0 [2] */
+		FN_VI1_CLK_A, 0, FN_FD0_B, FN_LCD_DATA0_B }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR10", 0xFFFC0044, 32,
+					2, 2, 2, 1, 2, 1, 3,
+					3, 1, 3, 3, 3, 3, 3) {
+	    /* IP9_31_30 [2] */
+	    0, 0, 0, 0,
+	    /* IP10_29_28 [2] */
+		FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT, 0,
+	    /* IP10_27_26 [2] */
+		FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG, 0,
+	    /* IP10_25 [1] */
+		FN_CAN1_RX_A, FN_IRQ1_B,
+	    /* IP10_24_23 [2] */
+		FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK, 0,
+	    /* IP10_22 [1] */
+		FN_CAN_CLK_A, FN_RX4_D,
+	    /* IP10_21_19 [3] */
+		FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B,
+		FN_LCD_M_DISP_B, 0, 0, 0,
+	    /* IP10_18_16 [3] */
+		FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B,
+		FN_LCD_VEPWC_B, 0, 0, 0,
+	    /* IP10_15 [1] */
+		FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
+	    /* IP10_14_12 [3] */
+		FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B,
+		FN_LCD_FLM_B, 0, 0, 0,
+	    /* IP10_11_9 [3] */
+		FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B,
+		FN_LCD_CL2_B, 0, 0, 0,
+	    /* IP10_8_6 [3] */
+		FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B,
+		FN_LCD_CL1_B, 0, 0, 0,
+	    /* IP10_5_3 [3] */
+		FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B,
+		FN_LCD_DON_B, 0, 0, 0,
+	    /* IP10_2_0 [3] */
+		FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B,
+		FN_LCD_DATA15_B, 0, 0, 0 }
+	},
+	{ PINMUX_CFG_REG_VAR("IPSR11", 0xFFFC0048, 32,
+			3, 1, 2, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) {
+	    /* IP11_31_29 [3] */
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    /* IP11_28 [1] */
+		FN_PRESETOUT, FN_ST_CLKOUT,
+	    /* IP11_27_26 [2] */
+		FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
+	    /* IP11_25_23 [3] */
+		FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C,
+		FN_ET0_TX_CLK_A, 0, 0, 0,
+	    /* IP11_22_21 [2] */
+		FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER, 0,
+	    /* IP11_20_19 [2] */
+		FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN, 0,
+	    /* IP11_18_16 [3] */
+		FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D,
+		FN_IERX_B, 0, 0, 0,
+	    /* IP11_15_13 [3] */
+		FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D,
+		FN_IETX_B, 0, 0, 0,
+	    /* IP11_12 [1] */
+		FN_TX0_A, FN_HSPI_TX_A,
+	    /* IP11_11_10 [2] */
+		FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
+	    /* IP11_9_7 [3] */
+		FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A,
+		FN_ET0_ERXD5, 0, 0, 0,
+	    /* IP11_6_4 [3] */
+		FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A,
+		FN_ET0_ERXD4, 0, 0, 0,
+	    /* IP11_3 [1] */
+		FN_SDSELF, FN_RTS1_E,
+	    /* IP11_2 [1] */
+		FN_SDA0, FN_HIFEBL_A,
+	    /* IP11_1 [1] */
+		FN_SDA1, FN_RX1_E,
+	    /* IP11_0 [1] */
+		FN_SCL1, FN_SCIF_CLK_C }
+	},
+	{ PINMUX_CFG_REG_VAR("MOD_SEL1", 0xFFFC004C, 32,
+				3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2,
+				1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) {
+		/* SEL1_31_29 [3] */
+		0, 0, 0, 0, 0, 0, 0, 0,
+		/* SEL1_28 [1] */
+		FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
+		/* SEL1_27 [1] */
+		FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
+		/* SEL1_26 [1] */
+		FN_SEL_VIN1_0, FN_SEL_VIN1_1,
+		/* SEL1_25 [1] */
+		FN_SEL_HIF_0, FN_SEL_HIF_1,
+		/* SEL1_24 [1] */
+		FN_SEL_RSPI_0, FN_SEL_RSPI_1,
+		/* SEL1_23 [1] */
+		FN_SEL_LCDC_0, FN_SEL_LCDC_1,
+		/* SEL1_22_21 [2] */
+		FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2, 0,
+		/* SEL1_20 [1] */
+		FN_SEL_ET0_0, FN_SEL_ET0_1,
+		/* SEL1_19 [1] */
+		FN_SEL_RMII_0, FN_SEL_RMII_1,
+		/* SEL1_18 [1] */
+		FN_SEL_TMU_0, FN_SEL_TMU_1,
+		/* SEL1_17_16 [2] */
+		FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2, 0,
+		/* SEL1_15_14 [2] */
+		FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
+		/* SEL1_13 [1] */
+		FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
+		/* SEL1_12_11 [2] */
+		FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2, 0,
+		/* SEL1_10 [1] */
+		FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
+		/* SEL1_9 [1] */
+		FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
+		/* SEL1_8 [1] */
+		FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
+		/* SEL1_7 [1] */
+		FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
+		/* SEL1_6 [1] */
+		FN_SEL_SSI1_0, FN_SEL_SSI1_1,
+		/* SEL1_5 [1] */
+		FN_SEL_SSI0_0, FN_SEL_SSI0_1,
+		/* SEL1_4 [1] */
+		FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
+		/* SEL1_3 [1] */
+		FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
+		/* SEL1_2 [1] */
+		FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
+		/* SEL1_1 [1] */
+		FN_SEL_MMC_0, FN_SEL_MMC_1,
+		/* SEL1_0 [1] */
+		FN_SEL_INTC_0, FN_SEL_INTC_1 }
+	},
+	{ PINMUX_CFG_REG_VAR("MOD_SEL2", 0xFFFC0050, 32,
+				1, 1, 1, 1, 1, 1, 1, 1,
+				1, 1, 1, 2, 2, 1, 2, 2, 3, 2, 3, 2, 2) {
+		/* SEL2_31 [1] */
+		0, 0,
+		/* SEL2_30 [1] */
+		0, 0,
+		/* SEL2_29 [1] */
+		0, 0,
+		/* SEL2_28 [1] */
+		0, 0,
+		/* SEL2_27 [1] */
+		0, 0,
+		/* SEL2_26 [1] */
+		0, 0,
+		/* SEL2_25 [1] */
+		0, 0,
+		/* SEL2_24 [1] */
+		0, 0,
+		/* SEL2_23 [1] */
+		FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
+		/* SEL2_22 [1] */
+		FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
+		/* SEL2_21 [1] */
+		FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
+		/* SEL2_20_19 [2] */
+		FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2, 0,
+		/* SEL2_18_17 [2] */
+		FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2, 0,
+		/* SEL2_16 [1] */
+		FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
+		/* SEL2_15_14 [2] */
+		FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+		/* SEL2_13_12 [2] */
+		FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+		/* SEL2_11_9 [3] */
+		FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2, FN_SEL_SCIF3_3,
+		FN_SEL_SCIF3_4, 0, 0, 0,
+		/* SEL2_8_7 [2] */
+		FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, FN_SEL_SCIF2_3,
+		/* SEL2_6_4 [3] */
+		FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, FN_SEL_SCIF1_3,
+			FN_SEL_SCIF1_4, 0, 0, 0,
+		/* SEL2_3_2 [2] */
+		FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, 0,
+		/* SEL2_1_0 [2] */
+		FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2, 0  }
+	},
+	/* GPIO 0 - 5*/
+	{ PINMUX_CFG_REG("INOUTSEL0", 0xFFC40004, 32, 1) { GP_INOUTSEL(0) } },
+	{ PINMUX_CFG_REG("INOUTSEL1", 0xFFC41004, 32, 1) { GP_INOUTSEL(1) } },
+	{ PINMUX_CFG_REG("INOUTSEL2", 0xFFC42004, 32, 1) { GP_INOUTSEL(2) } },
+	{ PINMUX_CFG_REG("INOUTSEL3", 0xFFC43004, 32, 1) { GP_INOUTSEL(3) } },
+	{ PINMUX_CFG_REG("INOUTSEL4", 0xFFC44004, 32, 1) { GP_INOUTSEL(4) } },
+	{ PINMUX_CFG_REG("INOUTSEL5", 0xffc45004, 32, 1) {
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 24 */
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 16 */
+		0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
+		GP_5_11_IN, GP_5_11_OUT,
+		GP_5_10_IN, GP_5_10_OUT,
+		GP_5_9_IN, GP_5_9_OUT,
+		GP_5_8_IN, GP_5_8_OUT,
+		GP_5_7_IN, GP_5_7_OUT,
+		GP_5_6_IN, GP_5_6_OUT,
+		GP_5_5_IN, GP_5_5_OUT,
+		GP_5_4_IN, GP_5_4_OUT,
+		GP_5_3_IN, GP_5_3_OUT,
+		GP_5_2_IN, GP_5_2_OUT,
+		GP_5_1_IN, GP_5_1_OUT,
+		GP_5_0_IN, GP_5_0_OUT }
+	},
+	{ },
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+	/* GPIO 0 - 5*/
+	{ PINMUX_DATA_REG("INDT0", 0xFFC4000C, 32) { GP_INDT(0) } },
+	{ PINMUX_DATA_REG("INDT1", 0xFFC4100C, 32) { GP_INDT(1) } },
+	{ PINMUX_DATA_REG("INDT2", 0xFFC4200C, 32) { GP_INDT(2) } },
+	{ PINMUX_DATA_REG("INDT3", 0xFFC4300C, 32) { GP_INDT(3) } },
+	{ PINMUX_DATA_REG("INDT4", 0xFFC4400C, 32) { GP_INDT(4) } },
+	{ PINMUX_DATA_REG("INDT5", 0xFFC4500C, 32) {
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0,
+		GP_5_11_DATA, GP_5_10_DATA, GP_5_9_DATA, GP_5_8_DATA,
+		GP_5_7_DATA, GP_5_6_DATA, GP_5_5_DATA, GP_5_4_DATA,
+		GP_5_3_DATA, GP_5_2_DATA, GP_5_1_DATA, GP_5_0_DATA }
+	},
+	{ },
+};
+
+static struct resource sh7734_pfc_resources[] = {
+	[0] = { /* PFC */
+		.start	= 0xFFFC0000,
+		.end	= 0xFFFC011C,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = { /* GPIO */
+		.start	= 0xFFC40000,
+		.end	= 0xFFC4502B,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct pinmux_info sh7734_pinmux_info = {
+	.name = "sh7734_pfc",
+
+	.resource = sh7734_pfc_resources,
+	.num_resources = ARRAY_SIZE(sh7734_pfc_resources),
+
+	.unlock_reg = 0xFFFC0000,
+
+	.reserved_id = PINMUX_RESERVED,
+	.data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+	.mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+	.first_gpio = GPIO_GP_0_0,
+	.last_gpio = GPIO_FN_ST_CLKOUT,
+
+	.gpios = pinmux_gpios,
+	.cfg_regs = pinmux_config_regs,
+	.data_regs = pinmux_data_regs,
+
+	.gpio_data = pinmux_data,
+	.gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+	return register_pinmux(&sh7734_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 1b88483..b91ea83 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
@@ -13,6 +13,7 @@
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/clock.h>
 
 /* Serial */
@@ -22,7 +23,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 80, 80, 80, 80 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
 };
 
 static struct platform_device scif0_device = {
@@ -39,7 +40,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 81, 81, 81, 81 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
 };
 
 static struct platform_device scif1_device = {
@@ -56,7 +57,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 82, 82, 82, 82 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc40)),
 };
 
 static struct platform_device scif2_device = {
@@ -73,7 +74,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 83, 83, 83, 83 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc60)),
 };
 
 static struct platform_device scif3_device = {
@@ -92,8 +93,8 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 96,
-		.end    = 99,
+		.start  = evt2irq(0xe00),
+		.end    = evt2irq(0xe60),
 		.flags  = IORESOURCE_IRQ,
        },
 };
@@ -113,8 +114,8 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 44,
-		.end    = 47,
+		.start  = evt2irq(0x780),
+		.end    = evt2irq(0x7e0),
 		.flags  = IORESOURCE_IRQ,
        },
 };
@@ -129,7 +130,7 @@
 static struct uio_info vpu_platform_data = {
 	.name = "VPU4",
 	.version = "0",
-	.irq = 60,
+	.irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -157,7 +158,7 @@
 static struct uio_info veu_platform_data = {
 	.name = "VEU",
 	.version = "0",
-	.irq = 54,
+	.irq = evt2irq(0x8c0),
 };
 
 static struct resource veu_resources[] = {
@@ -185,7 +186,7 @@
 static struct uio_info jpu_platform_data = {
 	.name = "JPU",
 	.version = "0",
-	.irq = 27,
+	.irq = evt2irq(0x560),
 };
 
 static struct resource jpu_resources[] = {
@@ -224,7 +225,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -252,7 +253,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -280,7 +281,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -307,7 +308,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
index 8777386..0bd09d5 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
@@ -15,6 +15,7 @@
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/usb/r8a66597.h>
 #include <asm/clock.h>
 
@@ -25,7 +26,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 80, 80, 80, 80 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xc00)),
 };
 
 static struct platform_device scif0_device = {
@@ -44,8 +45,8 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 96,
-		.end    = 99,
+		.start  = evt2irq(0xe00),
+		.end    = evt2irq(0xe60),
 		.flags  = IORESOURCE_IRQ,
        },
 };
@@ -68,8 +69,8 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 65,
-		.end    = 65,
+		.start  = evt2irq(0xa20),
+		.end    = evt2irq(0xa20),
 		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
 	},
 };
@@ -89,7 +90,7 @@
 static struct uio_info vpu_platform_data = {
 	.name = "VPU5",
 	.version = "0",
-	.irq = 60,
+	.irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -117,7 +118,7 @@
 static struct uio_info veu0_platform_data = {
 	.name = "VEU",
 	.version = "0",
-	.irq = 54,
+	.irq = evt2irq(0x8c0),
 };
 
 static struct resource veu0_resources[] = {
@@ -145,7 +146,7 @@
 static struct uio_info veu1_platform_data = {
 	.name = "VEU",
 	.version = "0",
-	.irq = 27,
+	.irq = evt2irq(0x560),
 };
 
 static struct resource veu1_resources[] = {
@@ -184,7 +185,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -240,7 +241,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -267,7 +268,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index 8420d4b..0f5a219 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -13,6 +13,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/uio_driver.h>
 #include <linux/usb/m66592.h>
 
@@ -147,20 +148,20 @@
 	},
 	{
 		.name	= "error_irq",
-		.start	= 78,
-		.end	= 78,
+		.start	= evt2irq(0xbc0),
+		.end	= evt2irq(0xbc0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 0-3 */
-		.start	= 48,
-		.end	= 51,
+		.start	= evt2irq(0x800),
+		.end	= evt2irq(0x860),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 4-5 */
-		.start	= 76,
-		.end	= 77,
+		.start	= evt2irq(0xb80),
+		.end	= evt2irq(0xba0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -182,7 +183,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 80, 80, 80, 80 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
 	.ops		= &sh7722_sci_port_ops,
 	.regtype	= SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
@@ -201,7 +202,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 81, 81, 81, 81 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
 	.ops		= &sh7722_sci_port_ops,
 	.regtype	= SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
@@ -220,7 +221,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 82, 82, 82, 82 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc40)),
 	.ops		= &sh7722_sci_port_ops,
 	.regtype	= SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
@@ -241,17 +242,17 @@
 	},
 	[1] = {
 		/* Period IRQ */
-		.start	= 45,
+		.start	= evt2irq(0x7a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
 		/* Carry IRQ */
-		.start	= 46,
+		.start	= evt2irq(0x7c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[3] = {
 		/* Alarm IRQ */
-		.start	= 44,
+		.start	= evt2irq(0x780),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -275,8 +276,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 65,
-		.end	= 65,
+		.start	= evt2irq(0xa20),
+		.end	= evt2irq(0xa20),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -301,8 +302,8 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 96,
-		.end    = 99,
+		.start  = evt2irq(0xe00),
+		.end    = evt2irq(0xe60),
 		.flags  = IORESOURCE_IRQ,
        },
 };
@@ -317,7 +318,7 @@
 static struct uio_info vpu_platform_data = {
 	.name = "VPU4",
 	.version = "0",
-	.irq = 60,
+	.irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -345,7 +346,7 @@
 static struct uio_info veu_platform_data = {
 	.name = "VEU",
 	.version = "0",
-	.irq = 54,
+	.irq = evt2irq(0x8c0),
 };
 
 static struct resource veu_resources[] = {
@@ -373,7 +374,7 @@
 static struct uio_info jpu_platform_data = {
 	.name = "JPU",
 	.version = "0",
-	.irq = 27,
+	.irq = evt2irq(0x560),
 };
 
 static struct resource jpu_resources[] = {
@@ -412,7 +413,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -440,7 +441,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -468,7 +469,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -525,7 +526,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 108,
+		.start	= evt2irq(0xf80),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
index a188c9e..28d6fd8 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
@@ -15,6 +15,7 @@
 #include <linux/uio_driver.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
@@ -28,7 +29,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 80, 80, 80, 80 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
 	.regtype	= SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -47,7 +48,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 81, 81, 81, 81 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
 	.regtype	= SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -66,7 +67,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 82, 82, 82, 82 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc40)),
 	.regtype	= SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -85,7 +86,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_3,
 	.type           = PORT_SCIFA,
-	.irqs           = { 56, 56, 56, 56 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
 };
 
 static struct platform_device scif3_device = {
@@ -103,7 +104,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_3,
 	.type           = PORT_SCIFA,
-	.irqs           = { 88, 88, 88, 88 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xd00)),
 };
 
 static struct platform_device scif4_device = {
@@ -121,7 +122,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_3,
 	.type           = PORT_SCIFA,
-	.irqs           = { 109, 109, 109, 109 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xfa0)),
 };
 
 static struct platform_device scif5_device = {
@@ -135,7 +136,7 @@
 static struct uio_info vpu_platform_data = {
 	.name = "VPU5",
 	.version = "0",
-	.irq = 60,
+	.irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -163,7 +164,7 @@
 static struct uio_info veu0_platform_data = {
 	.name = "VEU2H",
 	.version = "0",
-	.irq = 54,
+	.irq = evt2irq(0x8c0),
 };
 
 static struct resource veu0_resources[] = {
@@ -191,7 +192,7 @@
 static struct uio_info veu1_platform_data = {
 	.name = "VEU2H",
 	.version = "0",
-	.irq = 27,
+	.irq = evt2irq(0x560),
 };
 
 static struct resource veu1_resources[] = {
@@ -230,7 +231,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -258,7 +259,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -286,7 +287,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -313,7 +314,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -340,7 +341,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 57,
+		.start	= evt2irq(0x920),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -367,7 +368,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 58,
+		.start	= evt2irq(0x940),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -394,7 +395,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 57,
+		.start	= evt2irq(0x920),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -417,17 +418,17 @@
 	},
 	[1] = {
 		/* Period IRQ */
-		.start	= 69,
+		.start	= evt2irq(0xaa0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
 		/* Carry IRQ */
-		.start	= 70,
+		.start	= evt2irq(0xac0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[3] = {
 		/* Alarm IRQ */
-		.start	= 68,
+		.start	= evt2irq(0xa80),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -450,8 +451,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 65,
-		.end	= 65,
+		.start	= evt2irq(0xa20),
+		.end	= evt2irq(0xa20),
 		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
 	},
 };
@@ -476,8 +477,8 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 96,
-		.end    = 99,
+		.start  = evt2irq(0xe00),
+		.end    = evt2irq(0xe60),
 		.flags  = IORESOURCE_IRQ,
        },
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index 4c671cf..26b74c2 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -20,6 +20,7 @@
 #include <linux/uio_driver.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 #include <linux/notifier.h>
 
@@ -215,20 +216,20 @@
 	},
 	{
 		.name	= "error_irq",
-		.start	= 78,
-		.end	= 78,
+		.start	= evt2irq(0xbc0),
+		.end	= evt2irq(0xbc0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 0-3 */
-		.start	= 48,
-		.end	= 51,
+		.start	= evt2irq(0x800),
+		.end	= evt2irq(0x860),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 4-5 */
-		.start	= 76,
-		.end	= 77,
+		.start	= evt2irq(0xb80),
+		.end	= evt2irq(0xba0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -249,20 +250,20 @@
 	},
 	{
 		.name	= "error_irq",
-		.start	= 74,
-		.end	= 74,
+		.start	= evt2irq(0xb40),
+		.end	= evt2irq(0xb40),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 0-3 */
-		.start	= 40,
-		.end	= 43,
+		.start	= evt2irq(0x700),
+		.end	= evt2irq(0x760),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 4-5 */
-		.start	= 72,
-		.end	= 73,
+		.start	= evt2irq(0xb00),
+		.end	= evt2irq(0xb20),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -295,7 +296,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 80, 80, 80, 80 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
 	.regtype	= SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -314,7 +315,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 81, 81, 81, 81 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
 	.regtype	= SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -333,7 +334,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type           = PORT_SCIF,
-	.irqs           = { 82, 82, 82, 82 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xc40)),
 	.regtype	= SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -352,7 +353,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_3,
 	.type           = PORT_SCIFA,
-	.irqs           = { 56, 56, 56, 56 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
 };
 
 static struct platform_device scif3_device = {
@@ -370,7 +371,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_3,
 	.type           = PORT_SCIFA,
-	.irqs           = { 88, 88, 88, 88 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xd00)),
 };
 
 static struct platform_device scif4_device = {
@@ -388,7 +389,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_3,
 	.type           = PORT_SCIFA,
-	.irqs           = { 109, 109, 109, 109 },
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0xfa0)),
 };
 
 static struct platform_device scif5_device = {
@@ -408,17 +409,17 @@
 	},
 	[1] = {
 		/* Period IRQ */
-		.start	= 69,
+		.start	= evt2irq(0xaa0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
 		/* Carry IRQ */
-		.start	= 70,
+		.start	= evt2irq(0xac0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[3] = {
 		/* Alarm IRQ */
-		.start	= 68,
+		.start	= evt2irq(0xa80),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -439,8 +440,8 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 96,
-		.end    = 99,
+		.start  = evt2irq(0xe00),
+		.end    = evt2irq(0xe60),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -461,8 +462,8 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start  = 92,
-		.end    = 95,
+		.start  = evt2irq(0xd80),
+		.end    = evt2irq(0xde0),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -478,7 +479,7 @@
 static struct uio_info vpu_platform_data = {
 	.name = "VPU5F",
 	.version = "0",
-	.irq = 60,
+	.irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -507,7 +508,7 @@
 static struct uio_info veu0_platform_data = {
 	.name = "VEU3F0",
 	.version = "0",
-	.irq = 83,
+	.irq = evt2irq(0xc60),
 };
 
 static struct resource veu0_resources[] = {
@@ -536,7 +537,7 @@
 static struct uio_info veu1_platform_data = {
 	.name = "VEU3F1",
 	.version = "0",
-	.irq = 54,
+	.irq = evt2irq(0x8c0),
 };
 
 static struct resource veu1_resources[] = {
@@ -633,7 +634,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 104,
+		.start	= evt2irq(0xf00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -661,7 +662,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -689,7 +690,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -716,7 +717,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -744,7 +745,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 57,
+		.start	= evt2irq(0x920),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -771,7 +772,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 58,
+		.start	= evt2irq(0x940),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -798,7 +799,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 57,
+		.start	= evt2irq(0x920),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -817,7 +818,7 @@
 static struct uio_info jpu_platform_data = {
 	.name = "JPU",
 	.version = "0",
-	.irq = 27,
+	.irq = evt2irq(0x560),
 };
 
 static struct resource jpu_resources[] = {
@@ -846,7 +847,7 @@
 static struct uio_info spu0_platform_data = {
 	.name = "SPU2DSP0",
 	.version = "0",
-	.irq = 86,
+	.irq = evt2irq(0xcc0),
 };
 
 static struct resource spu0_resources[] = {
@@ -875,7 +876,7 @@
 static struct uio_info spu1_platform_data = {
 	.name = "SPU2DSP1",
 	.version = "0",
-	.irq = 87,
+	.irq = evt2irq(0xce0),
 };
 
 static struct resource spu1_resources[] = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
new file mode 100644
index 0000000..f799971d
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
@@ -0,0 +1,800 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/setup-sh7734.c
+
+ * SH7734 Setup
+ *
+ * Copyright (C) 2011,2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ * Copyright (C) 2011,2012 Renesas Solutions Corp.
+ *
+ * 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 <linux/init.h>
+#include <linux/serial.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+#include <asm/irq.h>
+#include <cpu/sh7734.h>
+
+/* SCIF */
+static struct plat_sci_port scif0_platform_data = {
+	.mapbase        = 0xFFE40000,
+	.flags          = UPF_BOOT_AUTOCONF,
+	.scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+	.scbrr_algo_id  = SCBRR_ALGO_2,
+	.type           = PORT_SCIF,
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0x8C0)),
+	.regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif0_device = {
+	.name		= "sh-sci",
+	.id			= 0,
+	.dev		= {
+		.platform_data	= &scif0_platform_data,
+	},
+};
+
+static struct plat_sci_port scif1_platform_data = {
+	.mapbase        = 0xFFE41000,
+	.flags          = UPF_BOOT_AUTOCONF,
+	.scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type           = PORT_SCIF,
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0x8E0)),
+	.regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif1_device = {
+	.name		= "sh-sci",
+	.id         = 1,
+	.dev		= {
+		.platform_data = &scif1_platform_data,
+	},
+};
+
+static struct plat_sci_port scif2_platform_data = {
+	.mapbase        = 0xFFE42000,
+	.flags          = UPF_BOOT_AUTOCONF,
+	.scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+	.scbrr_algo_id  = SCBRR_ALGO_2,
+	.type           = PORT_SCIF,
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
+	.regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif2_device = {
+	.name		= "sh-sci",
+	.id         = 2,
+	.dev		= {
+		.platform_data = &scif2_platform_data,
+	},
+};
+
+static struct plat_sci_port scif3_platform_data = {
+	.mapbase        = 0xFFE43000,
+	.flags          = UPF_BOOT_AUTOCONF,
+	.scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
+	.scbrr_algo_id  = SCBRR_ALGO_2,
+	.type           = PORT_SCIF,
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0x920)),
+	.regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif3_device = {
+	.name		= "sh-sci",
+	.id	        = 3,
+	.dev		= {
+		.platform_data	= &scif3_platform_data,
+	},
+};
+
+static struct plat_sci_port scif4_platform_data = {
+	.mapbase        = 0xFFE44000,
+	.flags          = UPF_BOOT_AUTOCONF,
+	.scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type           = PORT_SCIF,
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0x940)),
+	.regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif4_device = {
+	.name		= "sh-sci",
+	.id	        = 4,
+	.dev		= {
+		.platform_data	= &scif4_platform_data,
+	},
+};
+
+static struct plat_sci_port scif5_platform_data = {
+	.mapbase        = 0xFFE43000,
+	.flags          = UPF_BOOT_AUTOCONF,
+	.scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+	.scbrr_algo_id	= SCBRR_ALGO_2,
+	.type           = PORT_SCIF,
+	.irqs           = SCIx_IRQ_MUXED(evt2irq(0x960)),
+	.regtype		= SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif5_device = {
+	.name		= "sh-sci",
+	.id	        = 5,
+	.dev		= {
+		.platform_data	= &scif5_platform_data,
+	},
+};
+
+/* RTC */
+static struct resource rtc_resources[] = {
+	[0] = {
+		.name	= "rtc",
+		.start	= 0xFFFC5000,
+		.end	= 0xFFFC5000 + 0x26 - 1,
+		.flags	= IORESOURCE_IO,
+	},
+	[1] = {
+		.start	= evt2irq(0xC00),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device rtc_device = {
+	.name		= "sh-rtc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(rtc_resources),
+	.resource	= rtc_resources,
+};
+
+/* I2C 0 */
+static struct resource i2c0_resources[] = {
+	[0] = {
+		.name	= "IIC0",
+		.start  = 0xFFC70000,
+		.end    = 0xFFC7000A - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = evt2irq(0x860),
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device i2c0_device = {
+	.name           = "i2c-sh7734",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(i2c0_resources),
+	.resource       = i2c0_resources,
+};
+
+/* TMU */
+static struct sh_timer_config tmu0_platform_data = {
+	.channel_offset = 0x04,
+	.timer_bit = 0,
+	.clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+	[0] = {
+		.start	= 0xFFD80008,
+		.end	= 0xFFD80014 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x400),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu0_device = {
+	.name	= "sh_tmu",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &tmu0_platform_data,
+	},
+	.resource	= tmu0_resources,
+	.num_resources	= ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+	.channel_offset = 0x10,
+	.timer_bit = 1,
+	.clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+	[0] = {
+		.start	= 0xFFD80014,
+		.end	= 0xFFD80020 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x420),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu1_device = {
+	.name		= "sh_tmu",
+	.id			= 1,
+	.dev = {
+		.platform_data	= &tmu1_platform_data,
+	},
+	.resource	= tmu1_resources,
+	.num_resources	= ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+	.channel_offset = 0x1c,
+	.timer_bit = 2,
+};
+
+static struct resource tmu2_resources[] = {
+	[0] = {
+		.start	= 0xFFD80020,
+		.end	= 0xFFD80030 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x440),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu2_device = {
+	.name		= "sh_tmu",
+	.id			= 2,
+	.dev = {
+		.platform_data	= &tmu2_platform_data,
+	},
+	.resource	= tmu2_resources,
+	.num_resources	= ARRAY_SIZE(tmu2_resources),
+};
+
+
+static struct sh_timer_config tmu3_platform_data = {
+	.channel_offset = 0x04,
+	.timer_bit = 0,
+};
+
+static struct resource tmu3_resources[] = {
+	[0] = {
+		.start	= 0xFFD81008,
+		.end	= 0xFFD81014 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x480),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu3_device = {
+	.name		= "sh_tmu",
+	.id			= 3,
+	.dev = {
+		.platform_data	= &tmu3_platform_data,
+	},
+	.resource	= tmu3_resources,
+	.num_resources	= ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+	.channel_offset = 0x10,
+	.timer_bit = 1,
+};
+
+static struct resource tmu4_resources[] = {
+	[0] = {
+		.start	= 0xFFD81014,
+		.end	= 0xFFD81020 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x4A0),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu4_device = {
+	.name		= "sh_tmu",
+	.id			= 4,
+	.dev = {
+		.platform_data	= &tmu4_platform_data,
+	},
+	.resource	= tmu4_resources,
+	.num_resources	= ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+	.channel_offset = 0x1c,
+	.timer_bit = 2,
+};
+
+static struct resource tmu5_resources[] = {
+	[0] = {
+		.start	= 0xFFD81020,
+		.end	= 0xFFD81030 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x4C0),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu5_device = {
+	.name		= "sh_tmu",
+	.id			= 5,
+	.dev = {
+		.platform_data	= &tmu5_platform_data,
+	},
+	.resource	= tmu5_resources,
+	.num_resources	= ARRAY_SIZE(tmu5_resources),
+};
+
+static struct sh_timer_config tmu6_platform_data = {
+	.channel_offset = 0x4,
+	.timer_bit = 0,
+};
+
+static struct resource tmu6_resources[] = {
+	[0] = {
+		.start	= 0xFFD82008,
+		.end	= 0xFFD82014 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x500),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu6_device = {
+	.name		= "sh_tmu",
+	.id			= 6,
+	.dev = {
+		.platform_data	= &tmu6_platform_data,
+	},
+	.resource	= tmu6_resources,
+	.num_resources	= ARRAY_SIZE(tmu6_resources),
+};
+
+static struct sh_timer_config tmu7_platform_data = {
+	.channel_offset = 0x10,
+	.timer_bit = 1,
+};
+
+static struct resource tmu7_resources[] = {
+	[0] = {
+		.start	= 0xFFD82014,
+		.end	= 0xFFD82020 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x520),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu7_device = {
+	.name		= "sh_tmu",
+	.id			= 7,
+	.dev = {
+		.platform_data	= &tmu7_platform_data,
+	},
+	.resource	= tmu7_resources,
+	.num_resources	= ARRAY_SIZE(tmu7_resources),
+};
+
+static struct sh_timer_config tmu8_platform_data = {
+	.channel_offset = 0x1c,
+	.timer_bit = 2,
+};
+
+static struct resource tmu8_resources[] = {
+	[0] = {
+		.start	= 0xFFD82020,
+		.end	= 0xFFD82030 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x540),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu8_device = {
+	.name		= "sh_tmu",
+	.id			= 8,
+	.dev = {
+		.platform_data	= &tmu8_platform_data,
+	},
+	.resource	= tmu8_resources,
+	.num_resources	= ARRAY_SIZE(tmu8_resources),
+};
+
+static struct platform_device *sh7734_devices[] __initdata = {
+	&scif0_device,
+	&scif1_device,
+	&scif2_device,
+	&scif3_device,
+	&scif4_device,
+	&scif5_device,
+	&tmu0_device,
+	&tmu1_device,
+	&tmu2_device,
+	&tmu3_device,
+	&tmu4_device,
+	&tmu5_device,
+	&tmu6_device,
+	&tmu7_device,
+	&tmu8_device,
+	&rtc_device,
+};
+
+static struct platform_device *sh7734_early_devices[] __initdata = {
+	&scif0_device,
+	&scif1_device,
+	&scif2_device,
+	&scif3_device,
+	&scif4_device,
+	&scif5_device,
+	&tmu0_device,
+	&tmu1_device,
+	&tmu2_device,
+	&tmu3_device,
+	&tmu4_device,
+	&tmu5_device,
+	&tmu6_device,
+	&tmu7_device,
+	&tmu8_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+	early_platform_add_devices(sh7734_early_devices,
+		ARRAY_SIZE(sh7734_early_devices));
+}
+
+#define GROUP 0
+enum {
+	UNUSED = 0,
+
+	/* interrupt sources */
+
+	IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
+	IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
+	IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
+	IRL0_HHLL, IRL0_HHLH, IRL0_HHHL,
+
+	IRQ0, IRQ1, IRQ2, IRQ3,
+	DU,
+	TMU00, TMU10, TMU20, TMU21,
+	TMU30, TMU40, TMU50, TMU51,
+	TMU60, TMU70, TMU80,
+	RESET_WDT,
+	USB,
+	HUDI,
+	SHDMAC,
+	SSI0, SSI1,	SSI2, SSI3,
+	VIN0,
+	RGPVG,
+	_2DG,
+	MMC,
+	HSPI,
+	LBSCATA,
+	I2C0,
+	RCAN0,
+	MIMLB,
+	SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5,
+	LBSCDMAC0, LBSCDMAC1, LBSCDMAC2,
+	RCAN1,
+	SDHI0, SDHI1,
+	IEBUS,
+	HPBDMAC0_3, HPBDMAC4_10, HPBDMAC11_18, HPBDMAC19_22, HPBDMAC23_25_27_28,
+	RTC,
+	VIN1,
+	LCDC,
+	SRC0, SRC1,
+	GETHER,
+	SDHI2,
+	GPIO0_3, GPIO4_5,
+	STIF0, STIF1,
+	ADMAC,
+	HIF,
+	FLCTL,
+	ADC,
+	MTU2,
+	RSPI,
+	QSPI,
+	HSCIF,
+	VEU3F_VE3,
+
+	/* Group */
+	/* Mask */
+	STIF_M,
+	GPIO_M,
+	HPBDMAC_M,
+	LBSCDMAC_M,
+	RCAN_M,
+	SRC_M,
+	SCIF_M,
+	LCDC_M,
+	_2DG_M,
+	VIN_M,
+	TMU_3_M,
+	TMU_0_M,
+
+	/* Priority */
+	RCAN_P,
+	LBSCDMAC_P,
+
+	/* Common */
+	SDHI,
+	SSI,
+	SPI,
+};
+
+static struct intc_vect vectors[] __initdata = {
+	INTC_VECT(DU, 0x3E0),
+	INTC_VECT(TMU00, 0x400),
+	INTC_VECT(TMU10, 0x420),
+	INTC_VECT(TMU20, 0x440),
+	INTC_VECT(TMU30, 0x480),
+	INTC_VECT(TMU40, 0x4A0),
+	INTC_VECT(TMU50, 0x4C0),
+	INTC_VECT(TMU51, 0x4E0),
+	INTC_VECT(TMU60, 0x500),
+	INTC_VECT(TMU70, 0x520),
+	INTC_VECT(TMU80, 0x540),
+	INTC_VECT(RESET_WDT, 0x560),
+	INTC_VECT(USB, 0x580),
+	INTC_VECT(HUDI, 0x600),
+	INTC_VECT(SHDMAC, 0x620),
+	INTC_VECT(SSI0, 0x6C0),
+	INTC_VECT(SSI1, 0x6E0),
+	INTC_VECT(SSI2, 0x700),
+	INTC_VECT(SSI3, 0x720),
+	INTC_VECT(VIN0, 0x740),
+	INTC_VECT(RGPVG, 0x760),
+	INTC_VECT(_2DG, 0x780),
+	INTC_VECT(MMC, 0x7A0),
+	INTC_VECT(HSPI, 0x7E0),
+	INTC_VECT(LBSCATA, 0x840),
+	INTC_VECT(I2C0, 0x860),
+	INTC_VECT(RCAN0, 0x880),
+	INTC_VECT(SCIF0, 0x8A0),
+	INTC_VECT(SCIF1, 0x8C0),
+	INTC_VECT(SCIF2, 0x900),
+	INTC_VECT(SCIF3, 0x920),
+	INTC_VECT(SCIF4, 0x940),
+	INTC_VECT(SCIF5, 0x960),
+	INTC_VECT(LBSCDMAC0, 0x9E0),
+	INTC_VECT(LBSCDMAC1, 0xA00),
+	INTC_VECT(LBSCDMAC2, 0xA20),
+	INTC_VECT(RCAN1, 0xA60),
+	INTC_VECT(SDHI0, 0xAE0),
+	INTC_VECT(SDHI1, 0xB00),
+	INTC_VECT(IEBUS, 0xB20),
+	INTC_VECT(HPBDMAC0_3, 0xB60),
+	INTC_VECT(HPBDMAC4_10, 0xB80),
+	INTC_VECT(HPBDMAC11_18, 0xBA0),
+	INTC_VECT(HPBDMAC19_22, 0xBC0),
+	INTC_VECT(HPBDMAC23_25_27_28, 0xBE0),
+	INTC_VECT(RTC, 0xC00),
+	INTC_VECT(VIN1, 0xC20),
+	INTC_VECT(LCDC, 0xC40),
+	INTC_VECT(SRC0, 0xC60),
+	INTC_VECT(SRC1, 0xC80),
+	INTC_VECT(GETHER, 0xCA0),
+	INTC_VECT(SDHI2, 0xCC0),
+	INTC_VECT(GPIO0_3, 0xCE0),
+	INTC_VECT(GPIO4_5, 0xD00),
+	INTC_VECT(STIF0, 0xD20),
+	INTC_VECT(STIF1, 0xD40),
+	INTC_VECT(ADMAC, 0xDA0),
+	INTC_VECT(HIF, 0xDC0),
+	INTC_VECT(FLCTL, 0xDE0),
+	INTC_VECT(ADC, 0xE00),
+	INTC_VECT(MTU2, 0xE20),
+	INTC_VECT(RSPI, 0xE40),
+	INTC_VECT(QSPI, 0xE60),
+	INTC_VECT(HSCIF, 0xFC0),
+	INTC_VECT(VEU3F_VE3, 0xF40),
+};
+
+static struct intc_group groups[] __initdata = {
+	/* Common */
+	INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2),
+	INTC_GROUP(SPI, HSPI, RSPI, QSPI),
+	INTC_GROUP(SSI, SSI0, SSI1, SSI2, SSI3),
+
+	/* Mask group */
+	INTC_GROUP(STIF_M, STIF0, STIF1), /* 22 */
+	INTC_GROUP(GPIO_M, GPIO0_3, GPIO4_5), /* 21 */
+	INTC_GROUP(HPBDMAC_M, HPBDMAC0_3, HPBDMAC4_10, HPBDMAC11_18,
+			HPBDMAC19_22, HPBDMAC23_25_27_28), /* 19 */
+	INTC_GROUP(LBSCDMAC_M, LBSCDMAC0, LBSCDMAC1, LBSCDMAC2), /* 18 */
+	INTC_GROUP(RCAN_M, RCAN0, RCAN1, IEBUS), /* 17 */
+	INTC_GROUP(SRC_M, SRC0, SRC1), /* 16 */
+	INTC_GROUP(SCIF_M, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5,
+			HSCIF), /* 14 */
+	INTC_GROUP(LCDC_M, LCDC, MIMLB), /* 13 */
+	INTC_GROUP(_2DG_M, _2DG, RGPVG), /* 12 */
+	INTC_GROUP(VIN_M, VIN0, VIN1), /* 10 */
+	INTC_GROUP(TMU_3_M, TMU30, TMU40, TMU50, TMU51,
+			TMU60, TMU60, TMU70, TMU80), /* 2 */
+	INTC_GROUP(TMU_0_M, TMU00, TMU10, TMU20, TMU21), /* 1 */
+
+	/* Priority group*/
+	INTC_GROUP(RCAN_P, RCAN0, RCAN1), /* INT2PRI5 */
+	INTC_GROUP(LBSCDMAC_P, LBSCDMAC0, LBSCDMAC1), /* INT2PRI5 */
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+	{ 0xFF804040, 0xFF804044, 32, /* INT2MSKRG / INT2MSKCR */
+	  { 0,
+		VEU3F_VE3,
+		SDHI, /* SDHI 0-2 */
+		ADMAC,
+		FLCTL,
+		RESET_WDT,
+		HIF,
+		ADC,
+		MTU2,
+		STIF_M, /* STIF 0,1 */
+		GPIO_M, /* GPIO 0-5*/
+		GETHER,
+		HPBDMAC_M, /* HPBDMAC 0_3 - 23_25_27_28 */
+		LBSCDMAC_M, /* LBSCDMAC 0 - 2 */
+		RCAN_M, /* RCAN, IEBUS */
+		SRC_M,	/* SRC 0,1 */
+		LBSCATA,
+		SCIF_M, /* SCIF 0-5, HSCIF */
+		LCDC_M, /* LCDC, MIMLB */
+		_2DG_M,	/* 2DG, RGPVG */
+		SPI, /* HSPI, RSPI, QSPI */
+		VIN_M,	/* VIN0, 1 */
+		SSI,	/* SSI 0-3 */
+		USB,
+		SHDMAC,
+		HUDI,
+		MMC,
+		RTC,
+		I2C0, /* I2C */ /* I2C 0, 1*/
+		TMU_3_M, /* TMU30 - TMU80 */
+		TMU_0_M, /* TMU00 - TMU21 */
+		DU } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+	{ 0xFF804000, 0, 32, 8, /* INT2PRI0 */
+		{ DU, TMU00, TMU10, TMU20 } },
+	{ 0xFF804004, 0, 32, 8, /* INT2PRI1 */
+		{ TMU30, TMU60, RTC, SDHI } },
+	{ 0xFF804008, 0, 32, 8, /* INT2PRI2 */
+		{ HUDI, SHDMAC, USB, SSI } },
+	{ 0xFF80400C, 0, 32, 8, /* INT2PRI3 */
+		{ VIN0, SPI, _2DG, LBSCATA } },
+	{ 0xFF804010, 0, 32, 8, /* INT2PRI4 */
+		{ SCIF0, SCIF3, HSCIF, LCDC } },
+	{ 0xFF804014, 0, 32, 8, /* INT2PRI5 */
+		{ RCAN_P, LBSCDMAC_P, LBSCDMAC2, MMC } },
+	{ 0xFF804018, 0, 32, 8, /* INT2PRI6 */
+		{ HPBDMAC0_3, HPBDMAC4_10, HPBDMAC11_18, HPBDMAC19_22 } },
+	{ 0xFF80401C, 0, 32, 8, /* INT2PRI7 */
+		{ HPBDMAC23_25_27_28, I2C0, SRC0, SRC1 } },
+	{ 0xFF804020, 0, 32, 8, /* INT2PRI8 */
+		{ 0 /* ADIF */, VIN1, RESET_WDT, HIF } },
+	{ 0xFF804024, 0, 32, 8, /* INT2PRI9 */
+		{ ADMAC, FLCTL, GPIO0_3, GPIO4_5 } },
+	{ 0xFF804028, 0, 32, 8, /* INT2PRI10 */
+		{ STIF0, STIF1, VEU3F_VE3, GETHER } },
+	{ 0xFF80402C, 0, 32, 8, /* INT2PRI11 */
+		{ MTU2, RGPVG, MIMLB, IEBUS } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7734", vectors, groups,
+	mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect irq3210_vectors[] __initdata = {
+	INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+	INTC_VECT(IRQ2, 0x2C0), INTC_VECT(IRQ3, 0x300),
+};
+
+static struct intc_sense_reg irq3210_sense_registers[] __initdata = {
+	{ 0xFF80201C, 32, 2, /* ICR1 */
+	{ IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static struct intc_mask_reg irq3210_ack_registers[] __initdata = {
+	{ 0xFF802024, 0, 32, /* INTREQ */
+	{ IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static struct intc_mask_reg irq3210_mask_registers[] __initdata = {
+	{ 0xFF802044, 0xFF802064, 32, /* INTMSK0 / INTMSKCLR0 */
+	{ IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static struct intc_prio_reg irq3210_prio_registers[] __initdata = {
+	{ 0xFF802010, 0, 32, 4, /* INTPRI */
+	{ IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static DECLARE_INTC_DESC_ACK(intc_desc_irq3210, "sh7734-irq3210",
+	irq3210_vectors, NULL,
+	irq3210_mask_registers, irq3210_prio_registers,
+	irq3210_sense_registers, irq3210_ack_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect vectors_irl3210[] __initdata = {
+	INTC_VECT(IRL0_LLLL, 0x200), INTC_VECT(IRL0_LLLH, 0x220),
+	INTC_VECT(IRL0_LLHL, 0x240), INTC_VECT(IRL0_LLHH, 0x260),
+	INTC_VECT(IRL0_LHLL, 0x280), INTC_VECT(IRL0_LHLH, 0x2a0),
+	INTC_VECT(IRL0_LHHL, 0x2c0), INTC_VECT(IRL0_LHHH, 0x2e0),
+	INTC_VECT(IRL0_HLLL, 0x300), INTC_VECT(IRL0_HLLH, 0x320),
+	INTC_VECT(IRL0_HLHL, 0x340), INTC_VECT(IRL0_HLHH, 0x360),
+	INTC_VECT(IRL0_HHLL, 0x380), INTC_VECT(IRL0_HHLH, 0x3a0),
+	INTC_VECT(IRL0_HHHL, 0x3c0),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irl3210, "sh7734-irl3210",
+	vectors_irl3210, NULL, mask_registers, NULL, NULL);
+
+#define INTC_ICR0		0xFF802000
+#define INTC_INTMSK0    0xFF802044
+#define INTC_INTMSK1    0xFF802048
+#define INTC_INTMSKCLR0 0xFF802064
+#define INTC_INTMSKCLR1 0xFF802068
+
+void __init plat_irq_setup(void)
+{
+	/* disable IRQ3-0 */
+	__raw_writel(0xF0000000, INTC_INTMSK0);
+
+	/* disable IRL3-0 */
+	__raw_writel(0x80000000, INTC_INTMSK1);
+
+	/* select IRL mode for IRL3-0 */
+	__raw_writel(__raw_readl(INTC_ICR0) & ~0x00800000, INTC_ICR0);
+
+	/* disable holding function, ie enable "SH-4 Mode (LVLMODE)" */
+	__raw_writel(__raw_readl(INTC_ICR0) | 0x00200000, INTC_ICR0);
+
+	register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+	switch (mode) {
+	case IRQ_MODE_IRQ3210:
+		/* select IRQ mode for IRL3-0 */
+		__raw_writel(__raw_readl(INTC_ICR0) | 0x00800000, INTC_ICR0);
+		register_intc_controller(&intc_desc_irq3210);
+		break;
+	case IRQ_MODE_IRL3210:
+		/* enable IRL0-3 but don't provide any masking */
+		__raw_writel(0x80000000, INTC_INTMSKCLR1);
+		__raw_writel(0xf0000000, INTC_INTMSKCLR0);
+		break;
+	case IRQ_MODE_IRL3210_MASK:
+		/* enable IRL0-3 and mask using cpu intc controller */
+		__raw_writel(0x80000000, INTC_INTMSKCLR0);
+		register_intc_controller(&intc_desc_irl3210);
+		break;
+	default:
+		BUG();
+	}
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index c8836cf..a770842 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -18,7 +18,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/sh_timer.h>
 #include <linux/sh_dma.h>
-
+#include <linux/sh_intc.h>
 #include <cpu/dma-register.h>
 #include <cpu/sh7757.h>
 
@@ -28,7 +28,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 40, 40, 40, 40 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x700)),
 };
 
 static struct platform_device scif2_device = {
@@ -45,7 +45,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 76, 76, 76, 76 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xb80)),
 };
 
 static struct platform_device scif3_device = {
@@ -62,7 +62,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 104, 104, 104, 104 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xF00)),
 };
 
 static struct platform_device scif4_device = {
@@ -86,7 +86,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 28,
+		.start	= evt2irq(0x580),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -114,7 +114,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 29,
+		.start	= evt2irq(0x5a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -136,7 +136,7 @@
 		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
 	},
 	[1] = {
-		.start	= 86,
+		.start	= evt2irq(0xcc0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -466,8 +466,8 @@
 	},
 	{
 		.name	= "error_irq",
-		.start	= 34,
-		.end	= 34,
+		.start	= evt2irq(0x640),
+		.end	= evt2irq(0x640),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 };
@@ -488,56 +488,56 @@
 	},
 	{
 		.name	= "error_irq",
-		.start	= 34,
-		.end	= 34,
+		.start	= evt2irq(0x640),
+		.end	= evt2irq(0x640),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 	{
 		/* IRQ for channels 4 */
-		.start	= 46,
-		.end	= 46,
+		.start	= evt2irq(0x7c0),
+		.end	= evt2irq(0x7c0),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 	{
 		/* IRQ for channels 5 */
-		.start	= 46,
-		.end	= 46,
+		.start	= evt2irq(0x7c0),
+		.end	= evt2irq(0x7c0),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 	{
 		/* IRQ for channels 6 */
-		.start	= 88,
-		.end	= 88,
+		.start	= evt2irq(0xd00),
+		.end	= evt2irq(0xd00),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 	{
 		/* IRQ for channels 7 */
-		.start	= 88,
-		.end	= 88,
+		.start	= evt2irq(0xd00),
+		.end	= evt2irq(0xd00),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 	{
 		/* IRQ for channels 8 */
-		.start	= 88,
-		.end	= 88,
+		.start	= evt2irq(0xd00),
+		.end	= evt2irq(0xd00),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 	{
 		/* IRQ for channels 9 */
-		.start	= 88,
-		.end	= 88,
+		.start	= evt2irq(0xd00),
+		.end	= evt2irq(0xd00),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 	{
 		/* IRQ for channels 10 */
-		.start	= 88,
-		.end	= 88,
+		.start	= evt2irq(0xd00),
+		.end	= evt2irq(0xd00),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 	{
 		/* IRQ for channels 11 */
-		.start	= 88,
-		.end	= 88,
+		.start	= evt2irq(0xd00),
+		.end	= evt2irq(0xd00),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 };
@@ -558,20 +558,20 @@
 	},
 	{
 		.name	= "error_irq",
-		.start	= 323,
-		.end	= 323,
+		.start	= evt2irq(0x2a60),
+		.end	= evt2irq(0x2a60),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 12 to 16 */
-		.start	= 272,
-		.end	= 276,
+		.start	= evt2irq(0x2400),
+		.end	= evt2irq(0x2480),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channel 17 */
-		.start	= 279,
-		.end	= 279,
+		.start	= evt2irq(0x24e0),
+		.end	= evt2irq(0x24e0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -592,20 +592,20 @@
 	},
 	{
 		.name	= "error_irq",
-		.start	= 324,
-		.end	= 324,
+		.start	= evt2irq(0x2a80),
+		.end	= evt2irq(0x2a80),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 18 to 22 */
-		.start	= 280,
-		.end	= 284,
+		.start	= evt2irq(0x2500),
+		.end	= evt2irq(0x2580),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channel 23 */
-		.start	= 288,
-		.end	= 288,
+		.start	= evt2irq(0x2600),
+		.end	= evt2irq(0x2600),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -668,7 +668,7 @@
 		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
 	},
 	{
-		.start	= 54,
+		.start	= evt2irq(0x8c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -687,7 +687,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.start	= 220,
+		.start	= evt2irq(0x1d80),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -706,8 +706,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 57,
-		.end	= 57,
+		.start	= evt2irq(0x920),
+		.end	= evt2irq(0x920),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -730,8 +730,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 57,
-		.end	= 57,
+		.start	= evt2irq(0x920),
+		.end	= evt2irq(0x920),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
index 0011351..bd0a8fb 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
 
@@ -22,7 +23,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 40, 40, 40, 40 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x700)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -40,7 +41,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 76, 76, 76, 76 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xb80)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -58,7 +59,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 104, 104, 104, 104 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xf00)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -78,7 +79,7 @@
 	},
 	[1] = {
 		/* Shared Period/Carry/Alarm IRQ */
-		.start  = 20,
+		.start  = evt2irq(0x480),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -97,13 +98,14 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 83,
-		.end	= 83,
+		.start	= evt2irq(0xc60),
+		.end	= evt2irq(0xc60),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
 
 static u64 usb_ohci_dma_mask = 0xffffffffUL;
+
 static struct platform_device usb_ohci_device = {
 	.name		= "sh_ohci",
 	.id		= -1,
@@ -122,8 +124,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 84,
-		.end	= 84,
+		.start	= evt2irq(0xc80),
+		.end	= evt2irq(0xc80),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -152,7 +154,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 28,
+		.start	= evt2irq(0x580),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -180,7 +182,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 29,
+		.start	= evt2irq(0x5a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -207,7 +209,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 30,
+		.start	= evt2irq(0x5c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -234,7 +236,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 96,
+		.start	= evt2irq(0xe00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -261,7 +263,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 97,
+		.start	= evt2irq(0xe20),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -288,7 +290,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 98,
+		.start	= evt2irq(0xe40),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
index 2c6aa22..256ea7a 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
@@ -12,6 +12,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -20,7 +21,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 61, 61, 61, 61 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x9a0)),
 };
 
 static struct platform_device scif0_device = {
@@ -37,7 +38,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 62, 62, 62, 62 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x9c0)),
 };
 
 static struct platform_device scif1_device = {
@@ -54,7 +55,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 63, 63, 63, 63 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x9e0)),
 };
 
 static struct platform_device scif2_device = {
@@ -71,7 +72,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 64, 64, 64, 64 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xa00)),
 };
 
 static struct platform_device scif3_device = {
@@ -88,7 +89,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 65, 65, 65, 65 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xa20)),
 };
 
 static struct platform_device scif4_device = {
@@ -105,7 +106,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 66, 66, 66, 66 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xa40)),
 };
 
 static struct platform_device scif5_device = {
@@ -122,7 +123,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 67, 67, 67, 67 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xa60)),
 };
 
 static struct platform_device scif6_device = {
@@ -139,7 +140,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 68, 68, 68, 68 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xa80)),
 };
 
 static struct platform_device scif7_device = {
@@ -156,7 +157,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 69, 69, 69, 69 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xaa0)),
 };
 
 static struct platform_device scif8_device = {
@@ -173,7 +174,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 70, 70, 70, 70 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xac0)),
 };
 
 static struct platform_device scif9_device = {
@@ -197,7 +198,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -225,7 +226,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -252,7 +253,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -279,7 +280,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 19,
+		.start	= evt2irq(0x460),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -306,7 +307,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 20,
+		.start	= evt2irq(0x480),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -333,7 +334,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 21,
+		.start	= evt2irq(0x4a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -360,7 +361,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 22,
+		.start	= evt2irq(0x4c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -387,7 +388,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 23,
+		.start	= evt2irq(0x4e0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -414,7 +415,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 24,
+		.start	= evt2irq(0x500),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index d431b00..de45b704 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -14,6 +14,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <cpu/dma-register.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -22,7 +23,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 40, 40, 40, 40 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x700)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -40,7 +41,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 76, 76, 76, 76 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0xb80)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -65,7 +66,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 28,
+		.start	= evt2irq(0x580),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -93,7 +94,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 29,
+		.start	= evt2irq(0x5a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -120,7 +121,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 30,
+		.start	= evt2irq(0x5c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -147,7 +148,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 96,
+		.start	= evt2irq(0xe00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -174,7 +175,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 97,
+		.start	= evt2irq(0xe20),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -201,7 +202,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 98,
+		.start	= evt2irq(0xe40),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -224,7 +225,7 @@
 	},
 	[1] = {
 		/* Shared Period/Carry/Alarm IRQ */
-		.start	= 20,
+		.start	= evt2irq(0x480),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -321,10 +322,13 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		/* Real DMA error IRQ is 38, and channel IRQs are 34-37, 44-45 */
+		/*
+		 * Real DMA error vector is 0x6c0, and channel
+		 * vectors are 0x640-0x6a0, 0x780-0x7a0
+		 */
 		.name	= "error_irq",
-		.start	= 34,
-		.end	= 34,
+		.start	= evt2irq(0x640),
+		.end	= evt2irq(0x640),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 };
@@ -338,10 +342,13 @@
 	},
 	/* DMAC1 has no DMARS */
 	{
-		/* Real DMA error IRQ is 38, and channel IRQs are 46-47, 92-95 */
+		/*
+		 * Real DMA error vector is 0x6c0, and channel
+		 * vectors are 0x7c0-0x7e0, 0xd80-0xde0
+		 */
 		.name	= "error_irq",
-		.start	= 46,
-		.end	= 46,
+		.start	= evt2irq(0x7c0),
+		.end	= evt2irq(0x7c0),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index 81588ef..0968ecb 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/mmzone.h>
 #include <cpu/dma-register.h>
 
@@ -24,7 +25,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 40, 40, 40, 40 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x700)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -42,7 +43,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 44, 44, 44, 44 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x780)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -60,7 +61,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 60, 60, 60, 60 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x980)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -78,7 +79,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 61, 61, 61, 61 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x9a0)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -96,7 +97,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 62, 62, 62, 62 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x9c0)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -114,7 +115,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 63, 63, 63, 63 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x9e0)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -139,7 +140,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 28,
+		.start	= evt2irq(0x580),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -167,7 +168,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 29,
+		.start	= evt2irq(0x5a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -194,7 +195,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 30,
+		.start	= evt2irq(0x5c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -221,7 +222,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 96,
+		.start	= evt2irq(0xe00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -248,7 +249,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 97,
+		.start	= evt2irq(0xe20),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -275,7 +276,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 98,
+		.start	= evt2irq(0xe40),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -375,10 +376,13 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		/* Real DMA error IRQ is 39, and channel IRQs are 33-38 */
+		/*
+		 * Real DMA error vector is 0x6e0, and channel
+		 * vectors are 0x620-0x6c0
+		 */
 		.name	= "error_irq",
-		.start	= 33,
-		.end	= 33,
+		.start	= evt2irq(0x620),
+		.end	= evt2irq(0x620),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 };
@@ -392,10 +396,13 @@
 	},
 	/* DMAC1 has no DMARS */
 	{
-		/* Real DMA error IRQ is 58, and channel IRQs are 52-57 */
+		/*
+		 * Real DMA error vector is 0x940, and channel
+		 * vectors are 0x880-0x920
+		 */
 		.name	= "error_irq",
-		.start	= 52,
-		.end	= 52,
+		.start	= evt2irq(0x880),
+		.end	= evt2irq(0x880),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
index 599022d..2e6952f 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
@@ -32,7 +32,10 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 40, 41, 43, 42 },
+	.irqs		= { evt2irq(0x700),
+			    evt2irq(0x720),
+			    evt2irq(0x760),
+			    evt2irq(0x740) },
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -53,7 +56,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 44, 44, 44, 44 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x780)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -71,7 +74,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 50, 50, 50, 50 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x840)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -89,7 +92,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 51, 51, 51, 51 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x860)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -107,7 +110,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 52, 52, 52, 52 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x880)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -125,7 +128,7 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
 	.scbrr_algo_id	= SCBRR_ALGO_1,
 	.type		= PORT_SCIF,
-	.irqs		= { 53, 53, 53, 53 },
+	.irqs		= SCIx_IRQ_MUXED(evt2irq(0x8a0)),
 	.regtype	= SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -150,7 +153,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -178,7 +181,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -205,7 +208,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -232,7 +235,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 20,
+		.start	= evt2irq(0x480),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -259,7 +262,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 21,
+		.start	= evt2irq(0x4a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -286,7 +289,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 22,
+		.start	= evt2irq(0x4c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -313,7 +316,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 45,
+		.start	= evt2irq(0x7a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -340,7 +343,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 45,
+		.start	= evt2irq(0x7a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -367,7 +370,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 45,
+		.start	= evt2irq(0x7a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -394,7 +397,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 46,
+		.start	= evt2irq(0x7c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -421,7 +424,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 46,
+		.start	= evt2irq(0x7c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -448,7 +451,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 46,
+		.start	= evt2irq(0x7c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -550,8 +553,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 77,
-		.end	= 77,
+		.start	= evt2irq(0xba0),
+		.end	= evt2irq(0xba0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -574,8 +577,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 77,
-		.end	= 77,
+		.start	= evt2irq(0xba0),
+		.end	= evt2irq(0xba0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index bb20880..688f7ed 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <cpu/shx3.h>
 #include <asm/mmzone.h>
 
@@ -32,7 +33,10 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 40, 41, 43, 42 },
+	.irqs		= { evt2irq(0x700),
+			    evt2irq(0x720),
+			    evt2irq(0x760),
+			    evt2irq(0x740) },
 };
 
 static struct platform_device scif0_device = {
@@ -49,7 +53,10 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 44, 45, 47, 46 },
+	.irqs		= { evt2irq(0x780),
+			    evt2irq(0x7a0),
+			    evt2irq(0x7e0),
+			    evt2irq(0x7c0) },
 };
 
 static struct platform_device scif1_device = {
@@ -66,7 +73,10 @@
 	.scscr		= SCSCR_RE | SCSCR_TE | SCSCR_REIE,
 	.scbrr_algo_id	= SCBRR_ALGO_2,
 	.type		= PORT_SCIF,
-	.irqs		= { 52, 53, 55, 54 },
+	.irqs		= { evt2irq(0x880),
+			    evt2irq(0x8a0),
+			    evt2irq(0x8e0),
+			    evt2irq(0x8c0) },
 };
 
 static struct platform_device scif2_device = {
@@ -90,7 +100,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 16,
+		.start	= evt2irq(0x400),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -118,7 +128,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 17,
+		.start	= evt2irq(0x420),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -145,7 +155,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 18,
+		.start	= evt2irq(0x440),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -172,7 +182,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 19,
+		.start	= evt2irq(0x460),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -199,7 +209,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 20,
+		.start	= evt2irq(0x480),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -226,7 +236,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 21,
+		.start	= evt2irq(0x4a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -484,9 +494,6 @@
 
 void __init plat_irq_setup(void)
 {
-	reserve_intc_vectors(vectors_irq, ARRAY_SIZE(vectors_irq));
-	reserve_intc_vectors(vectors_irl, ARRAY_SIZE(vectors_irl));
-
 	register_intc_controller(&intc_desc);
 }
 
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index 6b80295..ff1f0e6 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -335,7 +335,7 @@
 	/* If the fast path handler fixed the fault, just drop through quickly
 	   to the restore code right away to return to the excepting context.
 	   */
-	beqi/u	r2, 0, tr1
+	bnei/u	r2, 0, tr1
 
 fast_tlb_miss_restore:
 	ld.q	SP, SAVED_TR0, r2
@@ -1079,9 +1079,8 @@
  *
  * Kernel TLB fault handlers will get a slightly different interface.
  * (r2)   struct pt_regs *, original register's frame pointer
- * (r3)   writeaccess, whether it's a store fault as opposed to load fault
- * (r4)   execaccess, whether it's a ITLB fault as opposed to DTLB fault
- * (r5)   Effective Address of fault
+ * (r3)   page fault error code (see asm/thread_info.h)
+ * (r4)   Effective Address of fault
  * (LINK) return address
  * (SP)   = r2
  *
@@ -1092,26 +1091,25 @@
 tlb_miss_load:
 	or	SP, ZERO, r2
 	or	ZERO, ZERO, r3		/* Read */
-	or	ZERO, ZERO, r4		/* Data */
-	getcon	TEA, r5
+	getcon	TEA, r4
 	pta	call_do_page_fault, tr0
 	beq	ZERO, ZERO, tr0
 
 tlb_miss_store:
 	or	SP, ZERO, r2
-	movi	1, r3			/* Write */
-	or	ZERO, ZERO, r4		/* Data */
-	getcon	TEA, r5
+	movi	FAULT_CODE_WRITE, r3		/* Write */
+	getcon	TEA, r4
 	pta	call_do_page_fault, tr0
 	beq	ZERO, ZERO, tr0
 
 itlb_miss_or_IRQ:
 	pta	its_IRQ, tr0
 	beqi/u	r4, EVENT_INTERRUPT, tr0
+
+	/* ITLB miss */
 	or	SP, ZERO, r2
-	or	ZERO, ZERO, r3		/* Read */
-	movi	1, r4			/* Text */
-	getcon	TEA, r5
+	movi	FAULT_CODE_ITLB, r3
+	getcon	TEA, r4
 	/* Fall through */
 
 call_do_page_fault:
diff --git a/arch/sh/kernel/cpu/sh5/fpu.c b/arch/sh/kernel/cpu/sh5/fpu.c
index 4b3bb35..9f8713a 100644
--- a/arch/sh/kernel/cpu/sh5/fpu.c
+++ b/arch/sh/kernel/cpu/sh5/fpu.c
@@ -107,8 +107,5 @@
 
 	regs->pc += 4;
 
-	tsk->thread.trap_no = 11;
-	tsk->thread.error_code = 0;
-
 	force_sig(SIGFPE, tsk);
 }
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index a3ee919..dadce73 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -234,8 +234,10 @@
 #ifdef CONFIG_SPARSE_IRQ
 int __init arch_probe_nr_irqs(void)
 {
-	nr_irqs = sh_mv.mv_nr_irqs;
-	return NR_IRQS_LEGACY;
+	/*
+	 * No pre-allocated IRQs.
+	 */
+	return 0;
 }
 #endif
 
diff --git a/arch/sh/kernel/kgdb.c b/arch/sh/kernel/kgdb.c
index b117781..38b3139 100644
--- a/arch/sh/kernel/kgdb.c
+++ b/arch/sh/kernel/kgdb.c
@@ -1,7 +1,7 @@
 /*
  * SuperH KGDB support
  *
- * Copyright (C) 2008 - 2009  Paul Mundt
+ * Copyright (C) 2008 - 2012  Paul Mundt
  *
  * Single stepping taken from the old stub by Henry Bell and Jeremy Siegel.
  *
@@ -164,42 +164,89 @@
 	stepped_opcode = 0;
 }
 
-void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
+	{ "r0",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) },
+	{ "r1",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) },
+	{ "r2",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) },
+	{ "r3",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) },
+	{ "r4",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) },
+	{ "r5",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) },
+	{ "r6",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) },
+	{ "r7",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) },
+	{ "r8",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) },
+	{ "r9",		GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) },
+	{ "r10",	GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) },
+	{ "r11",	GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) },
+	{ "r12",	GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) },
+	{ "r13",	GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) },
+	{ "r14",	GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) },
+	{ "r15",	GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) },
+	{ "pc",		GDB_SIZEOF_REG, offsetof(struct pt_regs, pc) },
+	{ "pr",		GDB_SIZEOF_REG, offsetof(struct pt_regs, pr) },
+	{ "sr",		GDB_SIZEOF_REG, offsetof(struct pt_regs, sr) },
+	{ "gbr",	GDB_SIZEOF_REG, offsetof(struct pt_regs, gbr) },
+	{ "mach",	GDB_SIZEOF_REG, offsetof(struct pt_regs, mach) },
+	{ "macl",	GDB_SIZEOF_REG, offsetof(struct pt_regs, macl) },
+	{ "vbr",	GDB_SIZEOF_REG, -1 },
+};
+
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
 {
-	int i;
+	if (regno < 0 || regno >= DBG_MAX_REG_NUM)
+		return -EINVAL;
 
-	for (i = 0; i < 16; i++)
-		gdb_regs[GDB_R0 + i] = regs->regs[i];
+	if (dbg_reg_def[regno].offset != -1)
+		memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+		       dbg_reg_def[regno].size);
 
-	gdb_regs[GDB_PC] = regs->pc;
-	gdb_regs[GDB_PR] = regs->pr;
-	gdb_regs[GDB_SR] = regs->sr;
-	gdb_regs[GDB_GBR] = regs->gbr;
-	gdb_regs[GDB_MACH] = regs->mach;
-	gdb_regs[GDB_MACL] = regs->macl;
-
-	__asm__ __volatile__ ("stc vbr, %0" : "=r" (gdb_regs[GDB_VBR]));
+	return 0;
 }
 
-void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
 {
-	int i;
+	if (regno >= DBG_MAX_REG_NUM || regno < 0)
+		return NULL;
 
-	for (i = 0; i < 16; i++)
-		regs->regs[GDB_R0 + i] = gdb_regs[GDB_R0 + i];
+	if (dbg_reg_def[regno].size != -1)
+		memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+		       dbg_reg_def[regno].size);
 
-	regs->pc = gdb_regs[GDB_PC];
-	regs->pr = gdb_regs[GDB_PR];
-	regs->sr = gdb_regs[GDB_SR];
-	regs->gbr = gdb_regs[GDB_GBR];
-	regs->mach = gdb_regs[GDB_MACH];
-	regs->macl = gdb_regs[GDB_MACL];
+	switch (regno) {
+	case GDB_VBR:
+		__asm__ __volatile__ ("stc vbr, %0" : "=r" (mem));
+		break;
+	}
+
+	return dbg_reg_def[regno].name;
 }
 
 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
 {
+	struct pt_regs *thread_regs = task_pt_regs(p);
+	int reg;
+
+	/* Initialize to zero */
+	for (reg = 0; reg < DBG_MAX_REG_NUM; reg++)
+		gdb_regs[reg] = 0;
+
+	/*
+	 * Copy out GP regs 8 to 14.
+	 *
+	 * switch_to() relies on SR.RB toggling, so regs 0->7 are banked
+	 * and need privileged instructions to get to. The r15 value we
+	 * fetch from the thread info directly.
+	 */
+	for (reg = GDB_R8; reg < GDB_R15; reg++)
+		gdb_regs[reg] = thread_regs->regs[reg];
+
 	gdb_regs[GDB_R15] = p->thread.sp;
 	gdb_regs[GDB_PC] = p->thread.pc;
+
+	/*
+	 * Additional registers we have context for
+	 */
+	gdb_regs[GDB_PR] = thread_regs->pr;
+	gdb_regs[GDB_GBR] = thread_regs->gbr;
 }
 
 int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
@@ -264,6 +311,18 @@
 	local_irq_restore(flags);
 }
 
+static void kgdb_call_nmi_hook(void *ignored)
+{
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+	local_irq_enable();
+	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+	local_irq_disable();
+}
+
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
 {
 	int ret;
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c
index 3d722e4..ec05f49 100644
--- a/arch/sh/kernel/machvec.c
+++ b/arch/sh/kernel/machvec.c
@@ -121,7 +121,4 @@
 	mv_set(irq_demux);
 	mv_set(mode_pins);
 	mv_set(mem_init);
-
-	if (!sh_mv.mv_nr_irqs)
-		sh_mv.mv_nr_irqs = NR_IRQS;
 }
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index f2621ab..9b7a459 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -2,12 +2,26 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/export.h>
+#include <linux/stackprotector.h>
 
 struct kmem_cache *task_xstate_cachep = NULL;
 unsigned int xstate_size;
 
+#ifdef CONFIG_CC_STACKPROTECTOR
+unsigned long __stack_chk_guard __read_mostly;
+EXPORT_SYMBOL(__stack_chk_guard);
+#endif
+
+/*
+ * this gets called so that we can store lazy state into memory and copy the
+ * current task into the new thread.
+ */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
+#ifdef CONFIG_SUPERH32
+	unlazy_fpu(src, task_pt_regs(src));
+#endif
 	*dst = *src;
 
 	if (src->thread.xstate) {
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 94273aa..59521e8 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -22,6 +22,7 @@
 #include <linux/ftrace.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/prefetch.h>
+#include <linux/stackprotector.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/fpu.h>
@@ -155,15 +156,6 @@
 }
 EXPORT_SYMBOL(dump_fpu);
 
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
-	unlazy_fpu(tsk, task_pt_regs(tsk));
-}
-
 asmlinkage void ret_from_fork(void);
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
@@ -220,6 +212,10 @@
 {
 	struct thread_struct *next_t = &next->thread;
 
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+	__stack_chk_guard = next->stack_canary;
+#endif
+
 	unlazy_fpu(prev, task_pt_regs(prev));
 
 	/* we're going to use this soon, after a few expensive things */
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index 5901fba..cb4172c 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -53,23 +53,11 @@
  * Atomically swap in the new signal mask, and wait for a signal.
  */
 asmlinkage int
-sys_sigsuspend(old_sigset_t mask,
-	       unsigned long r5, unsigned long r6, unsigned long r7,
-	       struct pt_regs __regs)
+sys_sigsuspend(old_sigset_t mask)
 {
 	sigset_t blocked;
-
-	current->saved_sigmask = current->blocked;
-
-	mask &= _BLOCKABLE;
 	siginitset(&blocked, mask);
-	set_current_blocked(&blocked);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_restore_sigmask();
-
-	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 asmlinkage int
@@ -83,10 +71,10 @@
 		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_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);
 	}
 
@@ -95,10 +83,10 @@
 	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_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;
@@ -162,12 +150,11 @@
 	if (!(boot_cpu_data.flags & CPU_HAS_FPU))
 		return 0;
 
-	if (!used_math()) {
-		__put_user(0, &sc->sc_ownedfp);
-		return 0;
-	}
+	if (!used_math())
+		return __put_user(0, &sc->sc_ownedfp);
 
-	__put_user(1, &sc->sc_ownedfp);
+	if (__put_user(1, &sc->sc_ownedfp))
+		return -EFAULT;
 
 	/* This will cause a "finit" to be triggered by the next
 	   attempted FPU operation by the 'current' process.
@@ -207,7 +194,7 @@
 		regs->sr |= SR_FD; /* Release FPU */
 		clear_fpu(tsk, regs);
 		clear_used_math();
-		__get_user (owned_fp, &sc->sc_ownedfp);
+		err |= __get_user (owned_fp, &sc->sc_ownedfp);
 		if (owned_fp)
 			err |= restore_sigcontext_fpu(sc);
 	}
@@ -398,11 +385,14 @@
 		struct fdpic_func_descriptor __user *funcptr =
 			(struct fdpic_func_descriptor __user *)ka->sa.sa_handler;
 
-		__get_user(regs->pc, &funcptr->text);
-		__get_user(regs->regs[12], &funcptr->GOT);
+		err |= __get_user(regs->pc, &funcptr->text);
+		err |= __get_user(regs->regs[12], &funcptr->GOT);
 	} else
 		regs->pc = (unsigned long)ka->sa.sa_handler;
 
+	if (err)
+		goto give_sigsegv;
+
 	set_fs(USER_DS);
 
 	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
@@ -482,11 +472,14 @@
 		struct fdpic_func_descriptor __user *funcptr =
 			(struct fdpic_func_descriptor __user *)ka->sa.sa_handler;
 
-		__get_user(regs->pc, &funcptr->text);
-		__get_user(regs->regs[12], &funcptr->GOT);
+		err |= __get_user(regs->pc, &funcptr->text);
+		err |= __get_user(regs->regs[12], &funcptr->GOT);
 	} else
 		regs->pc = (unsigned long)ka->sa.sa_handler;
 
+	if (err)
+		goto give_sigsegv;
+
 	set_fs(USER_DS);
 
 	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 3c9a6f7..b589a35 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -83,11 +83,12 @@
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-static 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;
+	sigset_t *oldset;
 
 	/*
 	 * We want the common case to go fast, which
@@ -96,11 +97,11 @@
 	 * if so.
 	 */
 	if (!user_mode(regs))
-		return 1;
+		return;
 
 	if (current_thread_info()->status & TS_RESTORE_SIGMASK)
 		oldset = &current->saved_sigmask;
-	else if (!oldset)
+	else
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, 0);
@@ -118,7 +119,7 @@
 
 			tracehook_signal_handler(signr, &info, &ka, regs,
 					test_thread_flag(TIF_SINGLESTEP));
-			return 1;
+			return;
 		}
 	}
 
@@ -147,71 +148,18 @@
 		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 	}
 
-	return 0;
+	return;
 }
 
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
 asmlinkage int
-sys_sigsuspend(old_sigset_t mask,
-	       unsigned long r3, unsigned long r4, unsigned long r5,
-	       unsigned long r6, unsigned long r7,
-	       struct pt_regs * regs)
+sys_sigsuspend(old_sigset_t mask)
 {
-	sigset_t saveset, blocked;
-
-	saveset = current->blocked;
-
-	mask &= _BLOCKABLE;
+	sigset_t blocked;
 	siginitset(&blocked, mask);
-	set_current_blocked(&blocked);
-
-	REF_REG_RET = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		set_restore_sigmask();
-		regs->pc += 4;    /* because sys_sigreturn decrements the pc */
-		if (do_signal(regs, &saveset)) {
-			/* pc now points at signal handler. Need to decrement
-			   it because entry.S will increment it. */
-			regs->pc -= 4;
-			return -EINTR;
-		}
-	}
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
-	          unsigned long r4, unsigned long r5, unsigned long r6,
-	          unsigned long r7,
-	          struct pt_regs * regs)
-{
-	sigset_t saveset, 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, ~_BLOCKABLE);
-	saveset = current->blocked;
-	set_current_blocked(&newset);
-
-	REF_REG_RET = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		regs->pc += 4;    /* because sys_sigreturn decrements the pc */
-		if (do_signal(regs, &saveset)) {
-			/* pc now points at signal handler. Need to decrement
-			   it because entry.S will increment it. */
-			regs->pc -= 4;
-			return -EINTR;
-		}
-	}
+	return sigsuspend(&blocked);
 }
 
 asmlinkage int
@@ -225,10 +173,10 @@
 		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_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);
 	}
 
@@ -237,10 +185,10 @@
 	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_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;
@@ -732,7 +680,7 @@
 asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
 {
 	if (thread_info_flags & _TIF_SIGPENDING)
-		do_signal(regs, 0);
+		do_signal(regs);
 
 	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 		clear_thread_flag(TIF_NOTIFY_RESUME);
diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c
index 6c04860..8dae93e 100644
--- a/arch/sh/kernel/traps_64.c
+++ b/arch/sh/kernel/traps_64.c
@@ -283,8 +283,6 @@
 		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
 {
 	show_excp_regs(fn_name, trapnr, signr, regs);
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = trapnr;
 
 	if (user_mode(regs))
 		force_sig(signr, tsk);
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 2228c8c..cee6b99 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -15,8 +15,8 @@
 obj-y			+= $(cacheops-y)
 
 mmu-y			:= nommu.o extable_32.o
-mmu-$(CONFIG_MMU)	:= extable_$(BITS).o fault_$(BITS).o gup.o \
-			   ioremap.o kmap.o pgtable.o tlbflush_$(BITS).o
+mmu-$(CONFIG_MMU)	:= extable_$(BITS).o fault.o gup.o ioremap.o kmap.o \
+			   pgtable.o tlbex_$(BITS).o tlbflush_$(BITS).o
 
 obj-y			+= $(mmu-y)
 
@@ -44,7 +44,7 @@
 
 GCOV_PROFILE_pmb.o := n
 
-# Special flags for fault_64.o.  This puts restrictions on the number of
+# Special flags for tlbex_64.o.  This puts restrictions on the number of
 # caller-save registers that the compiler can target when building this file.
 # This is required because the code is called from a context in entry.S where
 # very few registers have been saved in the exception handler (for speed
@@ -59,7 +59,7 @@
 # The resources not listed below are callee save, i.e. the compiler is free to
 # use any of them and will spill them to the stack itself.
 
-CFLAGS_fault_64.o += -ffixed-r7 \
+CFLAGS_tlbex_64.o += -ffixed-r7 \
 	-ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \
 	-ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \
 	-ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
new file mode 100644
index 0000000..1fc25d8
--- /dev/null
+++ b/arch/sh/mm/fault.c
@@ -0,0 +1,514 @@
+/*
+ * Page fault handler for SH with an MMU.
+ *
+ *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 2003 - 2012  Paul Mundt
+ *
+ *  Based on linux/arch/i386/mm/fault.c:
+ *   Copyright (C) 1995  Linus Torvalds
+ *
+ * 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/kernel.h>
+#include <linux/mm.h>
+#include <linux/hardirq.h>
+#include <linux/kprobes.h>
+#include <linux/perf_event.h>
+#include <linux/kdebug.h>
+#include <asm/io_trapped.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+#include <asm/traps.h>
+
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
+{
+	int ret = 0;
+
+	if (kprobes_built_in() && !user_mode(regs)) {
+		preempt_disable();
+		if (kprobe_running() && kprobe_fault_handler(regs, trap))
+			ret = 1;
+		preempt_enable();
+	}
+
+	return ret;
+}
+
+static void
+force_sig_info_fault(int si_signo, int si_code, unsigned long address,
+		     struct task_struct *tsk)
+{
+	siginfo_t info;
+
+	info.si_signo	= si_signo;
+	info.si_errno	= 0;
+	info.si_code	= si_code;
+	info.si_addr	= (void __user *)address;
+
+	force_sig_info(si_signo, &info, tsk);
+}
+
+/*
+ * This is useful to dump out the page tables associated with
+ * 'addr' in mm 'mm'.
+ */
+static void show_pte(struct mm_struct *mm, unsigned long addr)
+{
+	pgd_t *pgd;
+
+	if (mm)
+		pgd = mm->pgd;
+	else
+		pgd = get_TTB();
+
+	printk(KERN_ALERT "pgd = %p\n", pgd);
+	pgd += pgd_index(addr);
+	printk(KERN_ALERT "[%08lx] *pgd=%0*Lx", addr,
+	       (u32)(sizeof(*pgd) * 2), (u64)pgd_val(*pgd));
+
+	do {
+		pud_t *pud;
+		pmd_t *pmd;
+		pte_t *pte;
+
+		if (pgd_none(*pgd))
+			break;
+
+		if (pgd_bad(*pgd)) {
+			printk("(bad)");
+			break;
+		}
+
+		pud = pud_offset(pgd, addr);
+		if (PTRS_PER_PUD != 1)
+			printk(", *pud=%0*Lx", (u32)(sizeof(*pud) * 2),
+			       (u64)pud_val(*pud));
+
+		if (pud_none(*pud))
+			break;
+
+		if (pud_bad(*pud)) {
+			printk("(bad)");
+			break;
+		}
+
+		pmd = pmd_offset(pud, addr);
+		if (PTRS_PER_PMD != 1)
+			printk(", *pmd=%0*Lx", (u32)(sizeof(*pmd) * 2),
+			       (u64)pmd_val(*pmd));
+
+		if (pmd_none(*pmd))
+			break;
+
+		if (pmd_bad(*pmd)) {
+			printk("(bad)");
+			break;
+		}
+
+		/* We must not map this if we have highmem enabled */
+		if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
+			break;
+
+		pte = pte_offset_kernel(pmd, addr);
+		printk(", *pte=%0*Lx", (u32)(sizeof(*pte) * 2),
+		       (u64)pte_val(*pte));
+	} while (0);
+
+	printk("\n");
+}
+
+static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
+{
+	unsigned index = pgd_index(address);
+	pgd_t *pgd_k;
+	pud_t *pud, *pud_k;
+	pmd_t *pmd, *pmd_k;
+
+	pgd += index;
+	pgd_k = init_mm.pgd + index;
+
+	if (!pgd_present(*pgd_k))
+		return NULL;
+
+	pud = pud_offset(pgd, address);
+	pud_k = pud_offset(pgd_k, address);
+	if (!pud_present(*pud_k))
+		return NULL;
+
+	if (!pud_present(*pud))
+	    set_pud(pud, *pud_k);
+
+	pmd = pmd_offset(pud, address);
+	pmd_k = pmd_offset(pud_k, address);
+	if (!pmd_present(*pmd_k))
+		return NULL;
+
+	if (!pmd_present(*pmd))
+		set_pmd(pmd, *pmd_k);
+	else {
+		/*
+		 * The page tables are fully synchronised so there must
+		 * be another reason for the fault. Return NULL here to
+		 * signal that we have not taken care of the fault.
+		 */
+		BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
+		return NULL;
+	}
+
+	return pmd_k;
+}
+
+#ifdef CONFIG_SH_STORE_QUEUES
+#define __FAULT_ADDR_LIMIT	P3_ADDR_MAX
+#else
+#define __FAULT_ADDR_LIMIT	VMALLOC_END
+#endif
+
+/*
+ * Handle a fault on the vmalloc or module mapping area
+ */
+static noinline int vmalloc_fault(unsigned long address)
+{
+	pgd_t *pgd_k;
+	pmd_t *pmd_k;
+	pte_t *pte_k;
+
+	/* Make sure we are in vmalloc/module/P3 area: */
+	if (!(address >= VMALLOC_START && address < __FAULT_ADDR_LIMIT))
+		return -1;
+
+	/*
+	 * Synchronize this task's top level page-table
+	 * with the 'reference' page table.
+	 *
+	 * Do _not_ use "current" here. We might be inside
+	 * an interrupt in the middle of a task switch..
+	 */
+	pgd_k = get_TTB();
+	pmd_k = vmalloc_sync_one(pgd_k, address);
+	if (!pmd_k)
+		return -1;
+
+	pte_k = pte_offset_kernel(pmd_k, address);
+	if (!pte_present(*pte_k))
+		return -1;
+
+	return 0;
+}
+
+static void
+show_fault_oops(struct pt_regs *regs, unsigned long address)
+{
+	if (!oops_may_print())
+		return;
+
+	printk(KERN_ALERT "BUG: unable to handle kernel ");
+	if (address < PAGE_SIZE)
+		printk(KERN_CONT "NULL pointer dereference");
+	else
+		printk(KERN_CONT "paging request");
+
+	printk(KERN_CONT " at %08lx\n", address);
+	printk(KERN_ALERT "PC:");
+	printk_address(regs->pc, 1);
+
+	show_pte(NULL, address);
+}
+
+static noinline void
+no_context(struct pt_regs *regs, unsigned long error_code,
+	   unsigned long address)
+{
+	/* Are we prepared to handle this kernel fault?  */
+	if (fixup_exception(regs))
+		return;
+
+	if (handle_trapped_io(regs, address))
+		return;
+
+	/*
+	 * Oops. The kernel tried to access some bad page. We'll have to
+	 * terminate things with extreme prejudice.
+	 */
+	bust_spinlocks(1);
+
+	show_fault_oops(regs, address);
+
+	die("Oops", regs, error_code);
+	bust_spinlocks(0);
+	do_exit(SIGKILL);
+}
+
+static void
+__bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
+		       unsigned long address, int si_code)
+{
+	struct task_struct *tsk = current;
+
+	/* User mode accesses just cause a SIGSEGV */
+	if (user_mode(regs)) {
+		/*
+		 * It's possible to have interrupts off here:
+		 */
+		local_irq_enable();
+
+		force_sig_info_fault(SIGSEGV, si_code, address, tsk);
+
+		return;
+	}
+
+	no_context(regs, error_code, address);
+}
+
+static noinline void
+bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
+		     unsigned long address)
+{
+	__bad_area_nosemaphore(regs, error_code, address, SEGV_MAPERR);
+}
+
+static void
+__bad_area(struct pt_regs *regs, unsigned long error_code,
+	   unsigned long address, int si_code)
+{
+	struct mm_struct *mm = current->mm;
+
+	/*
+	 * Something tried to access memory that isn't in our memory map..
+	 * Fix it, but check if it's kernel or user first..
+	 */
+	up_read(&mm->mmap_sem);
+
+	__bad_area_nosemaphore(regs, error_code, address, si_code);
+}
+
+static noinline void
+bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address)
+{
+	__bad_area(regs, error_code, address, SEGV_MAPERR);
+}
+
+static noinline void
+bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
+		      unsigned long address)
+{
+	__bad_area(regs, error_code, address, SEGV_ACCERR);
+}
+
+static void out_of_memory(void)
+{
+	/*
+	 * We ran out of memory, call the OOM killer, and return the userspace
+	 * (which will retry the fault, or kill us if we got oom-killed):
+	 */
+	up_read(&current->mm->mmap_sem);
+
+	pagefault_out_of_memory();
+}
+
+static void
+do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address)
+{
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->mm;
+
+	up_read(&mm->mmap_sem);
+
+	/* Kernel mode? Handle exceptions or die: */
+	if (!user_mode(regs))
+		no_context(regs, error_code, address);
+
+	force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
+}
+
+static noinline int
+mm_fault_error(struct pt_regs *regs, unsigned long error_code,
+	       unsigned long address, unsigned int fault)
+{
+	/*
+	 * Pagefault was interrupted by SIGKILL. We have no reason to
+	 * continue pagefault.
+	 */
+	if (fatal_signal_pending(current)) {
+		if (!(fault & VM_FAULT_RETRY))
+			up_read(&current->mm->mmap_sem);
+		if (!user_mode(regs))
+			no_context(regs, error_code, address);
+		return 1;
+	}
+
+	if (!(fault & VM_FAULT_ERROR))
+		return 0;
+
+	if (fault & VM_FAULT_OOM) {
+		/* Kernel mode? Handle exceptions or die: */
+		if (!user_mode(regs)) {
+			up_read(&current->mm->mmap_sem);
+			no_context(regs, error_code, address);
+			return 1;
+		}
+
+		out_of_memory();
+	} else {
+		if (fault & VM_FAULT_SIGBUS)
+			do_sigbus(regs, error_code, address);
+		else
+			BUG();
+	}
+
+	return 1;
+}
+
+static inline int access_error(int error_code, struct vm_area_struct *vma)
+{
+	if (error_code & FAULT_CODE_WRITE) {
+		/* write, present and write, not present: */
+		if (unlikely(!(vma->vm_flags & VM_WRITE)))
+			return 1;
+		return 0;
+	}
+
+	/* ITLB miss on NX page */
+	if (unlikely((error_code & FAULT_CODE_ITLB) &&
+		     !(vma->vm_flags & VM_EXEC)))
+		return 1;
+
+	/* read, not present: */
+	if (unlikely(!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))))
+		return 1;
+
+	return 0;
+}
+
+static int fault_in_kernel_space(unsigned long address)
+{
+	return address >= TASK_SIZE;
+}
+
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+					unsigned long error_code,
+					unsigned long address)
+{
+	unsigned long vec;
+	struct task_struct *tsk;
+	struct mm_struct *mm;
+	struct vm_area_struct * vma;
+	int fault;
+	int write = error_code & FAULT_CODE_WRITE;
+	unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+			      (write ? FAULT_FLAG_WRITE : 0));
+
+	tsk = current;
+	mm = tsk->mm;
+	vec = lookup_exception_vector();
+
+	/*
+	 * We fault-in kernel-space virtual memory on-demand. The
+	 * 'reference' page table is init_mm.pgd.
+	 *
+	 * NOTE! We MUST NOT take any locks for this case. We may
+	 * be in an interrupt or a critical region, and should
+	 * only copy the information from the master page table,
+	 * nothing more.
+	 */
+	if (unlikely(fault_in_kernel_space(address))) {
+		if (vmalloc_fault(address) >= 0)
+			return;
+		if (notify_page_fault(regs, vec))
+			return;
+
+		bad_area_nosemaphore(regs, error_code, address);
+		return;
+	}
+
+	if (unlikely(notify_page_fault(regs, vec)))
+		return;
+
+	/* Only enable interrupts if they were on before the fault */
+	if ((regs->sr & SR_IMASK) != SR_IMASK)
+		local_irq_enable();
+
+	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+
+	/*
+	 * If we're in an interrupt, have no user context or are running
+	 * in an atomic region then we must not take the fault:
+	 */
+	if (unlikely(in_atomic() || !mm)) {
+		bad_area_nosemaphore(regs, error_code, address);
+		return;
+	}
+
+retry:
+	down_read(&mm->mmap_sem);
+
+	vma = find_vma(mm, address);
+	if (unlikely(!vma)) {
+		bad_area(regs, error_code, address);
+		return;
+	}
+	if (likely(vma->vm_start <= address))
+		goto good_area;
+	if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
+		bad_area(regs, error_code, address);
+		return;
+	}
+	if (unlikely(expand_stack(vma, address))) {
+		bad_area(regs, error_code, address);
+		return;
+	}
+
+	/*
+	 * Ok, we have a good vm_area for this memory access, so
+	 * we can handle it..
+	 */
+good_area:
+	if (unlikely(access_error(error_code, vma))) {
+		bad_area_access_error(regs, error_code, address);
+		return;
+	}
+
+	set_thread_fault_code(error_code);
+
+	/*
+	 * If for any reason at all we couldn't handle the fault,
+	 * make sure we exit gracefully rather than endlessly redo
+	 * the fault.
+	 */
+	fault = handle_mm_fault(mm, vma, address, flags);
+
+	if (unlikely(fault & (VM_FAULT_RETRY | VM_FAULT_ERROR)))
+		if (mm_fault_error(regs, error_code, address, fault))
+			return;
+
+	if (flags & FAULT_FLAG_ALLOW_RETRY) {
+		if (fault & VM_FAULT_MAJOR) {
+			tsk->maj_flt++;
+			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+				      regs, address);
+		} else {
+			tsk->min_flt++;
+			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+				      regs, address);
+		}
+		if (fault & VM_FAULT_RETRY) {
+			flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+			/*
+			 * No need to up_read(&mm->mmap_sem) as we would
+			 * have already released it in __lock_page_or_retry
+			 * in mm/filemap.c.
+			 */
+			goto retry;
+		}
+	}
+
+	up_read(&mm->mmap_sem);
+}
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
deleted file mode 100644
index e99b104..0000000
--- a/arch/sh/mm/fault_32.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Page fault handler for SH with an MMU.
- *
- *  Copyright (C) 1999  Niibe Yutaka
- *  Copyright (C) 2003 - 2009  Paul Mundt
- *
- *  Based on linux/arch/i386/mm/fault.c:
- *   Copyright (C) 1995  Linus Torvalds
- *
- * 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/kernel.h>
-#include <linux/mm.h>
-#include <linux/hardirq.h>
-#include <linux/kprobes.h>
-#include <linux/perf_event.h>
-#include <asm/io_trapped.h>
-#include <asm/mmu_context.h>
-#include <asm/tlbflush.h>
-#include <asm/traps.h>
-
-static inline int notify_page_fault(struct pt_regs *regs, int trap)
-{
-	int ret = 0;
-
-	if (kprobes_built_in() && !user_mode(regs)) {
-		preempt_disable();
-		if (kprobe_running() && kprobe_fault_handler(regs, trap))
-			ret = 1;
-		preempt_enable();
-	}
-
-	return ret;
-}
-
-static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
-{
-	unsigned index = pgd_index(address);
-	pgd_t *pgd_k;
-	pud_t *pud, *pud_k;
-	pmd_t *pmd, *pmd_k;
-
-	pgd += index;
-	pgd_k = init_mm.pgd + index;
-
-	if (!pgd_present(*pgd_k))
-		return NULL;
-
-	pud = pud_offset(pgd, address);
-	pud_k = pud_offset(pgd_k, address);
-	if (!pud_present(*pud_k))
-		return NULL;
-
-	if (!pud_present(*pud))
-	    set_pud(pud, *pud_k);
-
-	pmd = pmd_offset(pud, address);
-	pmd_k = pmd_offset(pud_k, address);
-	if (!pmd_present(*pmd_k))
-		return NULL;
-
-	if (!pmd_present(*pmd))
-		set_pmd(pmd, *pmd_k);
-	else {
-		/*
-		 * The page tables are fully synchronised so there must
-		 * be another reason for the fault. Return NULL here to
-		 * signal that we have not taken care of the fault.
-		 */
-		BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
-		return NULL;
-	}
-
-	return pmd_k;
-}
-
-/*
- * Handle a fault on the vmalloc or module mapping area
- */
-static noinline int vmalloc_fault(unsigned long address)
-{
-	pgd_t *pgd_k;
-	pmd_t *pmd_k;
-	pte_t *pte_k;
-
-	/* Make sure we are in vmalloc/module/P3 area: */
-	if (!(address >= P3SEG && address < P3_ADDR_MAX))
-		return -1;
-
-	/*
-	 * Synchronize this task's top level page-table
-	 * with the 'reference' page table.
-	 *
-	 * Do _not_ use "current" here. We might be inside
-	 * an interrupt in the middle of a task switch..
-	 */
-	pgd_k = get_TTB();
-	pmd_k = vmalloc_sync_one(pgd_k, address);
-	if (!pmd_k)
-		return -1;
-
-	pte_k = pte_offset_kernel(pmd_k, address);
-	if (!pte_present(*pte_k))
-		return -1;
-
-	return 0;
-}
-
-static int fault_in_kernel_space(unsigned long address)
-{
-	return address >= TASK_SIZE;
-}
-
-/*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
-					unsigned long writeaccess,
-					unsigned long address)
-{
-	unsigned long vec;
-	struct task_struct *tsk;
-	struct mm_struct *mm;
-	struct vm_area_struct * vma;
-	int si_code;
-	int fault;
-	siginfo_t info;
-
-	tsk = current;
-	mm = tsk->mm;
-	si_code = SEGV_MAPERR;
-	vec = lookup_exception_vector();
-
-	/*
-	 * We fault-in kernel-space virtual memory on-demand. The
-	 * 'reference' page table is init_mm.pgd.
-	 *
-	 * NOTE! We MUST NOT take any locks for this case. We may
-	 * be in an interrupt or a critical region, and should
-	 * only copy the information from the master page table,
-	 * nothing more.
-	 */
-	if (unlikely(fault_in_kernel_space(address))) {
-		if (vmalloc_fault(address) >= 0)
-			return;
-		if (notify_page_fault(regs, vec))
-			return;
-
-		goto bad_area_nosemaphore;
-	}
-
-	if (unlikely(notify_page_fault(regs, vec)))
-		return;
-
-	/* Only enable interrupts if they were on before the fault */
-	if ((regs->sr & SR_IMASK) != SR_IMASK)
-		local_irq_enable();
-
-	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
-
-	/*
-	 * If we're in an interrupt, have no user context or are running
-	 * in an atomic region then we must not take the fault:
-	 */
-	if (in_atomic() || !mm)
-		goto no_context;
-
-	down_read(&mm->mmap_sem);
-
-	vma = find_vma(mm, address);
-	if (!vma)
-		goto bad_area;
-	if (vma->vm_start <= address)
-		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
-	if (expand_stack(vma, address))
-		goto bad_area;
-
-	/*
-	 * Ok, we have a good vm_area for this memory access, so
-	 * we can handle it..
-	 */
-good_area:
-	si_code = SEGV_ACCERR;
-	if (writeaccess) {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
-	} else {
-		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
-			goto bad_area;
-	}
-
-	/*
-	 * If for any reason at all we couldn't handle the fault,
-	 * make sure we exit gracefully rather than endlessly redo
-	 * the fault.
-	 */
-	fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0);
-	if (unlikely(fault & VM_FAULT_ERROR)) {
-		if (fault & VM_FAULT_OOM)
-			goto out_of_memory;
-		else if (fault & VM_FAULT_SIGBUS)
-			goto do_sigbus;
-		BUG();
-	}
-	if (fault & VM_FAULT_MAJOR) {
-		tsk->maj_flt++;
-		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
-				     regs, address);
-	} else {
-		tsk->min_flt++;
-		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
-				     regs, address);
-	}
-
-	up_read(&mm->mmap_sem);
-	return;
-
-	/*
-	 * Something tried to access memory that isn't in our memory map..
-	 * Fix it, but check if it's kernel or user first..
-	 */
-bad_area:
-	up_read(&mm->mmap_sem);
-
-bad_area_nosemaphore:
-	if (user_mode(regs)) {
-		info.si_signo = SIGSEGV;
-		info.si_errno = 0;
-		info.si_code = si_code;
-		info.si_addr = (void *) address;
-		force_sig_info(SIGSEGV, &info, tsk);
-		return;
-	}
-
-no_context:
-	/* Are we prepared to handle this kernel fault?  */
-	if (fixup_exception(regs))
-		return;
-
-	if (handle_trapped_io(regs, address))
-		return;
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- *
- */
-
-	bust_spinlocks(1);
-
-	if (oops_may_print()) {
-		unsigned long page;
-
-		if (address < PAGE_SIZE)
-			printk(KERN_ALERT "Unable to handle kernel NULL "
-					  "pointer dereference");
-		else
-			printk(KERN_ALERT "Unable to handle kernel paging "
-					  "request");
-		printk(" at virtual address %08lx\n", address);
-		printk(KERN_ALERT "pc = %08lx\n", regs->pc);
-		page = (unsigned long)get_TTB();
-		if (page) {
-			page = ((__typeof__(page) *)page)[address >> PGDIR_SHIFT];
-			printk(KERN_ALERT "*pde = %08lx\n", page);
-			if (page & _PAGE_PRESENT) {
-				page &= PAGE_MASK;
-				address &= 0x003ff000;
-				page = ((__typeof__(page) *)
-						__va(page))[address >>
-							    PAGE_SHIFT];
-				printk(KERN_ALERT "*pte = %08lx\n", page);
-			}
-		}
-	}
-
-	die("Oops", regs, writeaccess);
-	bust_spinlocks(0);
-	do_exit(SIGKILL);
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
-	up_read(&mm->mmap_sem);
-	if (!user_mode(regs))
-		goto no_context;
-	pagefault_out_of_memory();
-	return;
-
-do_sigbus:
-	up_read(&mm->mmap_sem);
-
-	/*
-	 * Send a sigbus, regardless of whether we were in kernel
-	 * or user mode.
-	 */
-	info.si_signo = SIGBUS;
-	info.si_errno = 0;
-	info.si_code = BUS_ADRERR;
-	info.si_addr = (void *)address;
-	force_sig_info(SIGBUS, &info, tsk);
-
-	/* Kernel mode? Handle exceptions or die */
-	if (!user_mode(regs))
-		goto no_context;
-}
-
-/*
- * Called with interrupts disabled.
- */
-asmlinkage int __kprobes
-handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess,
-	       unsigned long address)
-{
-	pgd_t *pgd;
-	pud_t *pud;
-	pmd_t *pmd;
-	pte_t *pte;
-	pte_t entry;
-
-	/*
-	 * We don't take page faults for P1, P2, and parts of P4, these
-	 * are always mapped, whether it be due to legacy behaviour in
-	 * 29-bit mode, or due to PMB configuration in 32-bit mode.
-	 */
-	if (address >= P3SEG && address < P3_ADDR_MAX) {
-		pgd = pgd_offset_k(address);
-	} else {
-		if (unlikely(address >= TASK_SIZE || !current->mm))
-			return 1;
-
-		pgd = pgd_offset(current->mm, address);
-	}
-
-	pud = pud_offset(pgd, address);
-	if (pud_none_or_clear_bad(pud))
-		return 1;
-	pmd = pmd_offset(pud, address);
-	if (pmd_none_or_clear_bad(pmd))
-		return 1;
-	pte = pte_offset_kernel(pmd, address);
-	entry = *pte;
-	if (unlikely(pte_none(entry) || pte_not_present(entry)))
-		return 1;
-	if (unlikely(writeaccess && !pte_write(entry)))
-		return 1;
-
-	if (writeaccess)
-		entry = pte_mkdirty(entry);
-	entry = pte_mkyoung(entry);
-
-	set_pte(pte, entry);
-
-#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP)
-	/*
-	 * SH-4 does not set MMUCR.RC to the corresponding TLB entry in
-	 * the case of an initial page write exception, so we need to
-	 * flush it in order to avoid potential TLB entry duplication.
-	 */
-	if (writeaccess == 2)
-		local_flush_tlb_one(get_asid(), address & PAGE_MASK);
-#endif
-
-	update_mmu_cache(NULL, address, pte);
-
-	return 0;
-}
diff --git a/arch/sh/mm/fault_64.c b/arch/sh/mm/fault_64.c
deleted file mode 100644
index 44a3410..0000000
--- a/arch/sh/mm/fault_64.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * The SH64 TLB miss.
- *
- * Original code from fault.c
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- * Fast PTE->TLB refill path
- * Copyright (C) 2003 Richard.Curnow@superh.com
- *
- * IMPORTANT NOTES :
- * The do_fast_page_fault function is called from a context in entry.S
- * where very few registers have been saved.  In particular, the code in
- * this file must be compiled not to use ANY caller-save registers that
- * are not part of the restricted save set.  Also, it means that code in
- * this file must not make calls to functions elsewhere in the kernel, or
- * else the excepting context will see corruption in its caller-save
- * registers.  Plus, the entry.S save area is non-reentrant, so this code
- * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic
- * on any exception.
- *
- * 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/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <asm/tlb.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/mmu_context.h>
-#include <cpu/registers.h>
-
-/* Callable from fault.c, so not static */
-inline void __do_tlb_refill(unsigned long address,
-                            unsigned long long is_text_not_data, pte_t *pte)
-{
-	unsigned long long ptel;
-	unsigned long long pteh=0;
-	struct tlb_info *tlbp;
-	unsigned long long next;
-
-	/* Get PTEL first */
-	ptel = pte_val(*pte);
-
-	/*
-	 * Set PTEH register
-	 */
-	pteh = neff_sign_extend(address & MMU_VPN_MASK);
-
-	/* Set the ASID. */
-	pteh |= get_asid() << PTEH_ASID_SHIFT;
-	pteh |= PTEH_VALID;
-
-	/* Set PTEL register, set_pte has performed the sign extension */
-	ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
-
-	tlbp = is_text_not_data ? &(cpu_data->itlb) : &(cpu_data->dtlb);
-	next = tlbp->next;
-	__flush_tlb_slot(next);
-	asm volatile ("putcfg %0,1,%2\n\n\t"
-		      "putcfg %0,0,%1\n"
-		      :  : "r" (next), "r" (pteh), "r" (ptel) );
-
-	next += TLB_STEP;
-	if (next > tlbp->last) next = tlbp->first;
-	tlbp->next = next;
-
-}
-
-static int handle_vmalloc_fault(struct mm_struct *mm,
-				unsigned long protection_flags,
-                                unsigned long long textaccess,
-				unsigned long address)
-{
-	pgd_t *dir;
-	pud_t *pud;
-	pmd_t *pmd;
-	static pte_t *pte;
-	pte_t entry;
-
-	dir = pgd_offset_k(address);
-
-	pud = pud_offset(dir, address);
-	if (pud_none_or_clear_bad(pud))
-		return 0;
-
-	pmd = pmd_offset(pud, address);
-	if (pmd_none_or_clear_bad(pmd))
-		return 0;
-
-	pte = pte_offset_kernel(pmd, address);
-	entry = *pte;
-
-	if (pte_none(entry) || !pte_present(entry))
-		return 0;
-	if ((pte_val(entry) & protection_flags) != protection_flags)
-		return 0;
-
-        __do_tlb_refill(address, textaccess, pte);
-
-	return 1;
-}
-
-static int handle_tlbmiss(struct mm_struct *mm,
-			  unsigned long long protection_flags,
-			  unsigned long long textaccess,
-			  unsigned long address)
-{
-	pgd_t *dir;
-	pud_t *pud;
-	pmd_t *pmd;
-	pte_t *pte;
-	pte_t entry;
-
-	/* NB. The PGD currently only contains a single entry - there is no
-	   page table tree stored for the top half of the address space since
-	   virtual pages in that region should never be mapped in user mode.
-	   (In kernel mode, the only things in that region are the 512Mb super
-	   page (locked in), and vmalloc (modules) +  I/O device pages (handled
-	   by handle_vmalloc_fault), so no PGD for the upper half is required
-	   by kernel mode either).
-
-	   See how mm->pgd is allocated and initialised in pgd_alloc to see why
-	   the next test is necessary.  - RPC */
-	if (address >= (unsigned long) TASK_SIZE)
-		/* upper half - never has page table entries. */
-		return 0;
-
-	dir = pgd_offset(mm, address);
-	if (pgd_none(*dir) || !pgd_present(*dir))
-		return 0;
-	if (!pgd_present(*dir))
-		return 0;
-
-	pud = pud_offset(dir, address);
-	if (pud_none(*pud) || !pud_present(*pud))
-		return 0;
-
-	pmd = pmd_offset(pud, address);
-	if (pmd_none(*pmd) || !pmd_present(*pmd))
-		return 0;
-
-	pte = pte_offset_kernel(pmd, address);
-	entry = *pte;
-
-	if (pte_none(entry) || !pte_present(entry))
-		return 0;
-
-	/*
-	 * If the page doesn't have sufficient protection bits set to
-	 * service the kind of fault being handled, there's not much
-	 * point doing the TLB refill.  Punt the fault to the general
-	 * handler.
-	 */
-	if ((pte_val(entry) & protection_flags) != protection_flags)
-		return 0;
-
-        __do_tlb_refill(address, textaccess, pte);
-
-	return 1;
-}
-
-/*
- * Put all this information into one structure so that everything is just
- * arithmetic relative to a single base address.  This reduces the number
- * of movi/shori pairs needed just to load addresses of static data.
- */
-struct expevt_lookup {
-	unsigned short protection_flags[8];
-	unsigned char  is_text_access[8];
-	unsigned char  is_write_access[8];
-};
-
-#define PRU (1<<9)
-#define PRW (1<<8)
-#define PRX (1<<7)
-#define PRR (1<<6)
-
-#define DIRTY (_PAGE_DIRTY | _PAGE_ACCESSED)
-#define YOUNG (_PAGE_ACCESSED)
-
-/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
-   the fault happened in user mode or privileged mode. */
-static struct expevt_lookup expevt_lookup_table = {
-	.protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
-	.is_text_access   = {1,   1,   0, 0, 0,   0,   0,   0}
-};
-
-/*
-   This routine handles page faults that can be serviced just by refilling a
-   TLB entry from an existing page table entry.  (This case represents a very
-   large majority of page faults.) Return 1 if the fault was successfully
-   handled.  Return 0 if the fault could not be handled.  (This leads into the
-   general fault handling in fault.c which deals with mapping file-backed
-   pages, stack growth, segmentation faults, swapping etc etc)
- */
-asmlinkage int do_fast_page_fault(unsigned long long ssr_md,
-				  unsigned long long expevt,
-			          unsigned long address)
-{
-	struct task_struct *tsk;
-	struct mm_struct *mm;
-	unsigned long long textaccess;
-	unsigned long long protection_flags;
-	unsigned long long index;
-	unsigned long long expevt4;
-
-	/* The next few lines implement a way of hashing EXPEVT into a
-	 * small array index which can be used to lookup parameters
-	 * specific to the type of TLBMISS being handled.
-	 *
-	 * Note:
-	 *	ITLBMISS has EXPEVT==0xa40
-	 *	RTLBMISS has EXPEVT==0x040
-	 *	WTLBMISS has EXPEVT==0x060
-	 */
-	expevt4 = (expevt >> 4);
-	/* TODO : xor ssr_md into this expression too. Then we can check
-	 * that PRU is set when it needs to be. */
-	index = expevt4 ^ (expevt4 >> 5);
-	index &= 7;
-	protection_flags = expevt_lookup_table.protection_flags[index];
-	textaccess       = expevt_lookup_table.is_text_access[index];
-
-	/* SIM
-	 * Note this is now called with interrupts still disabled
-	 * This is to cope with being called for a missing IO port
-	 * address with interrupts disabled. This should be fixed as
-	 * soon as we have a better 'fast path' miss handler.
-	 *
-	 * Plus take care how you try and debug this stuff.
-	 * For example, writing debug data to a port which you
-	 * have just faulted on is not going to work.
-	 */
-
-	tsk = current;
-	mm = tsk->mm;
-
-	if ((address >= VMALLOC_START && address < VMALLOC_END) ||
-	    (address >= IOBASE_VADDR  && address < IOBASE_END)) {
-		if (ssr_md)
-			/*
-			 * Process-contexts can never have this address
-			 * range mapped
-			 */
-			if (handle_vmalloc_fault(mm, protection_flags,
-						 textaccess, address))
-				return 1;
-	} else if (!in_interrupt() && mm) {
-		if (handle_tlbmiss(mm, protection_flags, textaccess, address))
-			return 1;
-	}
-
-	return 0;
-}
diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c
index f27dbe1..3aea25d 100644
--- a/arch/sh/mm/tlb-sh5.c
+++ b/arch/sh/mm/tlb-sh5.c
@@ -182,3 +182,43 @@
 
 	local_irq_restore(flags);
 }
+
+void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+	unsigned long long ptel;
+	unsigned long long pteh=0;
+	struct tlb_info *tlbp;
+	unsigned long long next;
+	unsigned int fault_code = get_thread_fault_code();
+
+	/* Get PTEL first */
+	ptel = pte.pte_low;
+
+	/*
+	 * Set PTEH register
+	 */
+	pteh = neff_sign_extend(address & MMU_VPN_MASK);
+
+	/* Set the ASID. */
+	pteh |= get_asid() << PTEH_ASID_SHIFT;
+	pteh |= PTEH_VALID;
+
+	/* Set PTEL register, set_pte has performed the sign extension */
+	ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+
+	if (fault_code & FAULT_CODE_ITLB)
+		tlbp = &cpu_data->itlb;
+	else
+		tlbp = &cpu_data->dtlb;
+
+	next = tlbp->next;
+	__flush_tlb_slot(next);
+	asm volatile ("putcfg %0,1,%2\n\n\t"
+		      "putcfg %0,0,%1\n"
+		      :  : "r" (next), "r" (pteh), "r" (ptel) );
+
+	next += TLB_STEP;
+	if (next > tlbp->last)
+		next = tlbp->first;
+	tlbp->next = next;
+}
diff --git a/arch/sh/mm/tlbex_32.c b/arch/sh/mm/tlbex_32.c
new file mode 100644
index 0000000..382262d
--- /dev/null
+++ b/arch/sh/mm/tlbex_32.c
@@ -0,0 +1,78 @@
+/*
+ * TLB miss handler for SH with an MMU.
+ *
+ *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 2003 - 2012  Paul Mundt
+ *
+ * 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/kernel.h>
+#include <linux/mm.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+#include <asm/mmu_context.h>
+#include <asm/thread_info.h>
+
+/*
+ * Called with interrupts disabled.
+ */
+asmlinkage int __kprobes
+handle_tlbmiss(struct pt_regs *regs, unsigned long error_code,
+	       unsigned long address)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	pte_t entry;
+
+	/*
+	 * We don't take page faults for P1, P2, and parts of P4, these
+	 * are always mapped, whether it be due to legacy behaviour in
+	 * 29-bit mode, or due to PMB configuration in 32-bit mode.
+	 */
+	if (address >= P3SEG && address < P3_ADDR_MAX) {
+		pgd = pgd_offset_k(address);
+	} else {
+		if (unlikely(address >= TASK_SIZE || !current->mm))
+			return 1;
+
+		pgd = pgd_offset(current->mm, address);
+	}
+
+	pud = pud_offset(pgd, address);
+	if (pud_none_or_clear_bad(pud))
+		return 1;
+	pmd = pmd_offset(pud, address);
+	if (pmd_none_or_clear_bad(pmd))
+		return 1;
+	pte = pte_offset_kernel(pmd, address);
+	entry = *pte;
+	if (unlikely(pte_none(entry) || pte_not_present(entry)))
+		return 1;
+	if (unlikely(error_code && !pte_write(entry)))
+		return 1;
+
+	if (error_code)
+		entry = pte_mkdirty(entry);
+	entry = pte_mkyoung(entry);
+
+	set_pte(pte, entry);
+
+#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP)
+	/*
+	 * SH-4 does not set MMUCR.RC to the corresponding TLB entry in
+	 * the case of an initial page write exception, so we need to
+	 * flush it in order to avoid potential TLB entry duplication.
+	 */
+	if (error_code == FAULT_CODE_INITIAL)
+		local_flush_tlb_one(get_asid(), address & PAGE_MASK);
+#endif
+
+	set_thread_fault_code(error_code);
+	update_mmu_cache(NULL, address, pte);
+
+	return 0;
+}
diff --git a/arch/sh/mm/tlbex_64.c b/arch/sh/mm/tlbex_64.c
new file mode 100644
index 0000000..8557548
--- /dev/null
+++ b/arch/sh/mm/tlbex_64.c
@@ -0,0 +1,166 @@
+/*
+ * The SH64 TLB miss.
+ *
+ * Original code from fault.c
+ * Copyright (C) 2000, 2001  Paolo Alberelli
+ *
+ * Fast PTE->TLB refill path
+ * Copyright (C) 2003 Richard.Curnow@superh.com
+ *
+ * IMPORTANT NOTES :
+ * The do_fast_page_fault function is called from a context in entry.S
+ * where very few registers have been saved.  In particular, the code in
+ * this file must be compiled not to use ANY caller-save registers that
+ * are not part of the restricted save set.  Also, it means that code in
+ * this file must not make calls to functions elsewhere in the kernel, or
+ * else the excepting context will see corruption in its caller-save
+ * registers.  Plus, the entry.S save area is non-reentrant, so this code
+ * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic
+ * on any exception.
+ *
+ * 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/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/kprobes.h>
+#include <asm/tlb.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+
+static int handle_tlbmiss(unsigned long long protection_flags,
+			  unsigned long address)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	pte_t entry;
+
+	if (is_vmalloc_addr((void *)address)) {
+		pgd = pgd_offset_k(address);
+	} else {
+		if (unlikely(address >= TASK_SIZE || !current->mm))
+			return 1;
+
+		pgd = pgd_offset(current->mm, address);
+	}
+
+	pud = pud_offset(pgd, address);
+	if (pud_none(*pud) || !pud_present(*pud))
+		return 1;
+
+	pmd = pmd_offset(pud, address);
+	if (pmd_none(*pmd) || !pmd_present(*pmd))
+		return 1;
+
+	pte = pte_offset_kernel(pmd, address);
+	entry = *pte;
+	if (pte_none(entry) || !pte_present(entry))
+		return 1;
+
+	/*
+	 * If the page doesn't have sufficient protection bits set to
+	 * service the kind of fault being handled, there's not much
+	 * point doing the TLB refill.  Punt the fault to the general
+	 * handler.
+	 */
+	if ((pte_val(entry) & protection_flags) != protection_flags)
+		return 1;
+
+	update_mmu_cache(NULL, address, pte);
+
+	return 0;
+}
+
+/*
+ * Put all this information into one structure so that everything is just
+ * arithmetic relative to a single base address.  This reduces the number
+ * of movi/shori pairs needed just to load addresses of static data.
+ */
+struct expevt_lookup {
+	unsigned short protection_flags[8];
+	unsigned char  is_text_access[8];
+	unsigned char  is_write_access[8];
+};
+
+#define PRU (1<<9)
+#define PRW (1<<8)
+#define PRX (1<<7)
+#define PRR (1<<6)
+
+/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
+   the fault happened in user mode or privileged mode. */
+static struct expevt_lookup expevt_lookup_table = {
+	.protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
+	.is_text_access   = {1,   1,   0, 0, 0,   0,   0,   0}
+};
+
+static inline unsigned int
+expevt_to_fault_code(unsigned long expevt)
+{
+	if (expevt == 0xa40)
+		return FAULT_CODE_ITLB;
+	else if (expevt == 0x060)
+		return FAULT_CODE_WRITE;
+
+	return 0;
+}
+
+/*
+   This routine handles page faults that can be serviced just by refilling a
+   TLB entry from an existing page table entry.  (This case represents a very
+   large majority of page faults.) Return 1 if the fault was successfully
+   handled.  Return 0 if the fault could not be handled.  (This leads into the
+   general fault handling in fault.c which deals with mapping file-backed
+   pages, stack growth, segmentation faults, swapping etc etc)
+ */
+asmlinkage int __kprobes
+do_fast_page_fault(unsigned long long ssr_md, unsigned long long expevt,
+		   unsigned long address)
+{
+	unsigned long long protection_flags;
+	unsigned long long index;
+	unsigned long long expevt4;
+	unsigned int fault_code;
+
+	/* The next few lines implement a way of hashing EXPEVT into a
+	 * small array index which can be used to lookup parameters
+	 * specific to the type of TLBMISS being handled.
+	 *
+	 * Note:
+	 *	ITLBMISS has EXPEVT==0xa40
+	 *	RTLBMISS has EXPEVT==0x040
+	 *	WTLBMISS has EXPEVT==0x060
+	 */
+	expevt4 = (expevt >> 4);
+	/* TODO : xor ssr_md into this expression too. Then we can check
+	 * that PRU is set when it needs to be. */
+	index = expevt4 ^ (expevt4 >> 5);
+	index &= 7;
+
+	fault_code = expevt_to_fault_code(expevt);
+
+	protection_flags = expevt_lookup_table.protection_flags[index];
+
+	if (expevt_lookup_table.is_text_access[index])
+		fault_code |= FAULT_CODE_ITLB;
+	if (!ssr_md)
+		fault_code |= FAULT_CODE_USER;
+
+	set_thread_fault_code(fault_code);
+
+	return handle_tlbmiss(protection_flags, address);
+}
diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c
index 11c5a18..f33fdd2 100644
--- a/arch/sh/mm/tlbflush_64.c
+++ b/arch/sh/mm/tlbflush_64.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
  * Copyright (C) 2003  Richard Curnow (/proc/tlb, bug fixes)
- * Copyright (C) 2003 - 2009 Paul Mundt
+ * Copyright (C) 2003 - 2012 Paul Mundt
  *
  * 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
@@ -28,294 +28,6 @@
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 
-extern void die(const char *,struct pt_regs *,long);
-
-#define PFLAG(val,flag)   (( (val) & (flag) ) ? #flag : "" )
-#define PPROT(flag) PFLAG(pgprot_val(prot),flag)
-
-static inline void print_prots(pgprot_t prot)
-{
-	printk("prot is 0x%016llx\n",pgprot_val(prot));
-
-	printk("%s %s %s %s %s\n",PPROT(_PAGE_SHARED),PPROT(_PAGE_READ),
-	       PPROT(_PAGE_EXECUTE),PPROT(_PAGE_WRITE),PPROT(_PAGE_USER));
-}
-
-static inline void print_vma(struct vm_area_struct *vma)
-{
-	printk("vma start 0x%08lx\n", vma->vm_start);
-	printk("vma end   0x%08lx\n", vma->vm_end);
-
-	print_prots(vma->vm_page_prot);
-	printk("vm_flags 0x%08lx\n", vma->vm_flags);
-}
-
-static inline void print_task(struct task_struct *tsk)
-{
-	printk("Task pid %d\n", task_pid_nr(tsk));
-}
-
-static pte_t *lookup_pte(struct mm_struct *mm, unsigned long address)
-{
-	pgd_t *dir;
-	pud_t *pud;
-	pmd_t *pmd;
-	pte_t *pte;
-	pte_t entry;
-
-	dir = pgd_offset(mm, address);
-	if (pgd_none(*dir))
-		return NULL;
-
-	pud = pud_offset(dir, address);
-	if (pud_none(*pud))
-		return NULL;
-
-	pmd = pmd_offset(pud, address);
-	if (pmd_none(*pmd))
-		return NULL;
-
-	pte = pte_offset_kernel(pmd, address);
-	entry = *pte;
-	if (pte_none(entry) || !pte_present(entry))
-		return NULL;
-
-	return pte;
-}
-
-/*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
-			      unsigned long textaccess, unsigned long address)
-{
-	struct task_struct *tsk;
-	struct mm_struct *mm;
-	struct vm_area_struct * vma;
-	const struct exception_table_entry *fixup;
-	pte_t *pte;
-	int fault;
-
-	/* SIM
-	 * Note this is now called with interrupts still disabled
-	 * This is to cope with being called for a missing IO port
-	 * address with interrupts disabled. This should be fixed as
-	 * soon as we have a better 'fast path' miss handler.
-	 *
-	 * Plus take care how you try and debug this stuff.
-	 * For example, writing debug data to a port which you
-	 * have just faulted on is not going to work.
-	 */
-
-	tsk = current;
-	mm = tsk->mm;
-
-	/* Not an IO address, so reenable interrupts */
-	local_irq_enable();
-
-	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
-
-	/*
-	 * If we're in an interrupt or have no user
-	 * context, we must not take the fault..
-	 */
-	if (in_atomic() || !mm)
-		goto no_context;
-
-	/* TLB misses upon some cache flushes get done under cli() */
-	down_read(&mm->mmap_sem);
-
-	vma = find_vma(mm, address);
-
-	if (!vma) {
-#ifdef DEBUG_FAULT
-		print_task(tsk);
-		printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
-		       __func__, __LINE__,
-		       address,regs->pc,textaccess,writeaccess);
-		show_regs(regs);
-#endif
-		goto bad_area;
-	}
-	if (vma->vm_start <= address) {
-		goto good_area;
-	}
-
-	if (!(vma->vm_flags & VM_GROWSDOWN)) {
-#ifdef DEBUG_FAULT
-		print_task(tsk);
-		printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
-		       __func__, __LINE__,
-		       address,regs->pc,textaccess,writeaccess);
-		show_regs(regs);
-
-		print_vma(vma);
-#endif
-		goto bad_area;
-	}
-	if (expand_stack(vma, address)) {
-#ifdef DEBUG_FAULT
-		print_task(tsk);
-		printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
-		       __func__, __LINE__,
-		       address,regs->pc,textaccess,writeaccess);
-		show_regs(regs);
-#endif
-		goto bad_area;
-	}
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
-	if (textaccess) {
-		if (!(vma->vm_flags & VM_EXEC))
-			goto bad_area;
-	} else {
-		if (writeaccess) {
-			if (!(vma->vm_flags & VM_WRITE))
-				goto bad_area;
-		} else {
-			if (!(vma->vm_flags & VM_READ))
-				goto bad_area;
-		}
-	}
-
-	/*
-	 * If for any reason at all we couldn't handle the fault,
-	 * make sure we exit gracefully rather than endlessly redo
-	 * the fault.
-	 */
-	fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0);
-	if (unlikely(fault & VM_FAULT_ERROR)) {
-		if (fault & VM_FAULT_OOM)
-			goto out_of_memory;
-		else if (fault & VM_FAULT_SIGBUS)
-			goto do_sigbus;
-		BUG();
-	}
-
-	if (fault & VM_FAULT_MAJOR) {
-		tsk->maj_flt++;
-		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
-				     regs, address);
-	} else {
-		tsk->min_flt++;
-		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
-				     regs, address);
-	}
-
-	/* If we get here, the page fault has been handled.  Do the TLB refill
-	   now from the newly-setup PTE, to avoid having to fault again right
-	   away on the same instruction. */
-	pte = lookup_pte (mm, address);
-	if (!pte) {
-		/* From empirical evidence, we can get here, due to
-		   !pte_present(pte).  (e.g. if a swap-in occurs, and the page
-		   is swapped back out again before the process that wanted it
-		   gets rescheduled?) */
-		goto no_pte;
-	}
-
-	__do_tlb_refill(address, textaccess, pte);
-
-no_pte:
-
-	up_read(&mm->mmap_sem);
-	return;
-
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
-#ifdef DEBUG_FAULT
-	printk("fault:bad area\n");
-#endif
-	up_read(&mm->mmap_sem);
-
-	if (user_mode(regs)) {
-		static int count=0;
-		siginfo_t info;
-		if (count < 4) {
-			/* This is really to help debug faults when starting
-			 * usermode, so only need a few */
-			count++;
-			printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx\n",
-				address, task_pid_nr(current), current->comm,
-				(unsigned long) regs->pc);
-#if 0
-			show_regs(regs);
-#endif
-		}
-		if (is_global_init(tsk)) {
-			panic("INIT had user mode bad_area\n");
-		}
-		tsk->thread.address = address;
-		tsk->thread.error_code = writeaccess;
-		info.si_signo = SIGSEGV;
-		info.si_errno = 0;
-		info.si_addr = (void *) address;
-		force_sig_info(SIGSEGV, &info, tsk);
-		return;
-	}
-
-no_context:
-#ifdef DEBUG_FAULT
-	printk("fault:No context\n");
-#endif
-	/* Are we prepared to handle this kernel fault?  */
-	fixup = search_exception_tables(regs->pc);
-	if (fixup) {
-		regs->pc = fixup->fixup;
-		return;
-	}
-
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- *
- */
-	if (address < PAGE_SIZE)
-		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-	else
-		printk(KERN_ALERT "Unable to handle kernel paging request");
-	printk(" at virtual address %08lx\n", address);
-	printk(KERN_ALERT "pc = %08Lx%08Lx\n", regs->pc >> 32, regs->pc & 0xffffffff);
-	die("Oops", regs, writeaccess);
-	do_exit(SIGKILL);
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
-	up_read(&mm->mmap_sem);
-	if (!user_mode(regs))
-		goto no_context;
-	pagefault_out_of_memory();
-	return;
-
-do_sigbus:
-	printk("fault:Do sigbus\n");
-	up_read(&mm->mmap_sem);
-
-	/*
-	 * Send a sigbus, regardless of whether we were in kernel
-	 * or user mode.
-	 */
-	tsk->thread.address = address;
-	tsk->thread.error_code = writeaccess;
-	tsk->thread.trap_no = 14;
-	force_sig(SIGBUS, tsk);
-
-	/* Kernel mode? Handle exceptions or die */
-	if (!user_mode(regs))
-		goto no_context;
-}
-
 void local_flush_tlb_one(unsigned long asid, unsigned long page)
 {
 	unsigned long long match, pteh=0, lpage;
@@ -458,7 +170,3 @@
 {
 	flush_tlb_all();
 }
-
-void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
-}
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index 6dd56c4..569977e 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -51,6 +51,8 @@
 MIGOR			SH_MIGOR
 RSK7201			SH_RSK7201
 RSK7203			SH_RSK7203
+RSK7264			SH_RSK7264
+RSK7269			SH_RSK7269
 AP325RXA		SH_AP325RXA
 SH2007			SH_SH2007
 SH7757LCR		SH_SH7757LCR
diff --git a/arch/sparc/configs/sparc64_defconfig b/arch/sparc/configs/sparc64_defconfig
index 3c1e858..9d8521b 100644
--- a/arch/sparc/configs/sparc64_defconfig
+++ b/arch/sparc/configs/sparc64_defconfig
@@ -5,7 +5,7 @@
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h
index 9cbd854..f74ac9e 100644
--- a/arch/sparc/include/asm/processor_32.h
+++ b/arch/sparc/include/asm/processor_32.h
@@ -108,9 +108,6 @@
 #define release_thread(tsk)		do { } while(0)
 extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 extern unsigned long get_wchan(struct task_struct *);
 
 #define task_pt_regs(tsk) ((tsk)->thread.kregs)
diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h
index e713db2..67df5cc 100644
--- a/arch/sparc/include/asm/processor_64.h
+++ b/arch/sparc/include/asm/processor_64.h
@@ -186,9 +186,6 @@
 /* Free all resources held by a thread. */
 #define release_thread(tsk)		do { } while (0)
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern unsigned long get_wchan(struct task_struct *task);
diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h
index 8b9c556..1754390 100644
--- a/arch/sparc/include/asm/topology_64.h
+++ b/arch/sparc/include/asm/topology_64.h
@@ -31,25 +31,6 @@
 	 cpu_all_mask : \
 	 cpumask_of_node(pcibus_to_node(bus)))
 
-#define SD_NODE_INIT (struct sched_domain) {		\
-	.min_interval		= 8,			\
-	.max_interval		= 32,			\
-	.busy_factor		= 32,			\
-	.imbalance_pct		= 125,			\
-	.cache_nice_tries	= 2,			\
-	.busy_idx		= 3,			\
-	.idle_idx		= 2,			\
-	.newidle_idx		= 0, 			\
-	.wake_idx		= 0,			\
-	.forkexec_idx		= 0,			\
-	.flags			= SD_LOAD_BALANCE	\
-				| SD_BALANCE_FORK	\
-				| SD_BALANCE_EXEC	\
-				| SD_SERIALIZE,		\
-	.last_balance		= jiffies,		\
-	.balance_interval	= 1,			\
-}
-
 #else /* CONFIG_NUMA */
 
 #include <asm-generic/topology.h>
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 28559ce..5713957 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -1296,8 +1296,6 @@
 
 	regs = args->regs;
 
-	perf_sample_data_init(&data, 0);
-
 	cpuc = &__get_cpu_var(cpu_hw_events);
 
 	/* If the PMU has the TOE IRQ enable bits, we need to do a
@@ -1321,7 +1319,7 @@
 		if (val & (1ULL << 31))
 			continue;
 
-		data.period = event->hw.last_period;
+		perf_sample_data_init(&data, 0, hwc->last_period);
 		if (!sparc_perf_event_set_period(event, hwc, idx))
 			continue;
 
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 948700f..bb1513e 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -215,8 +215,9 @@
 	    (((unsigned long) sf) & 3))
 		goto segv;
 
-	get_user(pc, &sf->info.si_regs.pc);
-	__get_user(npc, &sf->info.si_regs.npc);
+	if (get_user(pc, &sf->info.si_regs.pc) ||
+	    __get_user(npc, &sf->info.si_regs.npc))
+		goto segv;
 
 	if ((pc | npc) & 3)
 		goto segv;
@@ -305,8 +306,9 @@
 	    (((unsigned long) sf) & 3))
 		goto segv;
 
-	get_user(pc, &sf->regs.pc);
-	__get_user(npc, &sf->regs.npc);
+	if (get_user(pc, &sf->regs.pc) || 
+	    __get_user(npc, &sf->regs.npc))
+		goto segv;
 
 	if ((pc | npc) & 3)
 		goto segv;
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index ac8e66b..2b7e849 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -64,18 +64,8 @@
 static int _sigpause_common(old_sigset_t set)
 {
 	sigset_t blocked;
-
-	current->saved_sigmask = current->blocked;
-
-	set &= _BLOCKABLE;
 	siginitset(&blocked, set);
-	set_current_blocked(&blocked);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-
-	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 asmlinkage int sys_sigsuspend(old_sigset_t set)
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 48b0f57..eafaab4 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -242,19 +242,8 @@
 static long _sigpause_common(old_sigset_t set)
 {
 	sigset_t blocked;
-
-	current->saved_sigmask = current->blocked;
-
-	set &= _BLOCKABLE;
 	siginitset(&blocked, set);
-	set_current_blocked(&blocked);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-
-	set_restore_sigmask();
-
-	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 asmlinkage long sys_sigpause(unsigned int set)
diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c
index 29c478f..f739233 100644
--- a/arch/sparc/kernel/sys_sparc32.c
+++ b/arch/sparc/kernel/sys_sparc32.c
@@ -139,8 +139,8 @@
 	err |= put_user(stat->ino, &statbuf->st_ino);
 	err |= put_user(stat->mode, &statbuf->st_mode);
 	err |= put_user(stat->nlink, &statbuf->st_nlink);
-	err |= put_user(stat->uid, &statbuf->st_uid);
-	err |= put_user(stat->gid, &statbuf->st_gid);
+	err |= put_user(from_kuid_munged(current_user_ns(), stat->uid), &statbuf->st_uid);
+	err |= put_user(from_kgid_munged(current_user_ns(), stat->gid), &statbuf->st_gid);
 	err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev);
 	err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]);
 	err |= put_user(stat->size, &statbuf->st_size);
diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c
index 627e89a..0c9b31b 100644
--- a/arch/sparc/kernel/sys_sparc_32.c
+++ b/arch/sparc/kernel/sys_sparc_32.c
@@ -184,10 +184,10 @@
 
 		if (!access_ok(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);
 		new_ka.ka_restorer = NULL;
 	}
@@ -195,17 +195,12 @@
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		/* In the clone() case we could copy half consistent
-		 * state to the user, however this could sleep and
-		 * deadlock us if we held the signal lock on SMP.  So for
-		 * now I take the easy way out and do no locking.
-		 */
 		if (!access_ok(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;
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
index 34c1e01..15cd8a4 100644
--- a/arch/tile/include/asm/processor.h
+++ b/arch/tile/include/asm/processor.h
@@ -210,9 +210,6 @@
 	/* Nothing for now */
 }
 
-/* Prepare to copy thread state - unlazy all lazy status. */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
 extern int do_work_pending(struct pt_regs *regs, u32 flags);
diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h
index 6fdd0c8..7a7ce390 100644
--- a/arch/tile/include/asm/topology.h
+++ b/arch/tile/include/asm/topology.h
@@ -78,32 +78,6 @@
 	.balance_interval	= 32,					\
 }
 
-/* sched_domains SD_NODE_INIT for TILE architecture */
-#define SD_NODE_INIT (struct sched_domain) {				\
-	.min_interval		= 16,					\
-	.max_interval		= 512,					\
-	.busy_factor		= 32,					\
-	.imbalance_pct		= 125,					\
-	.cache_nice_tries	= 1,					\
-	.busy_idx		= 3,					\
-	.idle_idx		= 1,					\
-	.newidle_idx		= 2,					\
-	.wake_idx		= 1,					\
-	.flags			= 1*SD_LOAD_BALANCE			\
-				| 1*SD_BALANCE_NEWIDLE			\
-				| 1*SD_BALANCE_EXEC			\
-				| 1*SD_BALANCE_FORK			\
-				| 0*SD_BALANCE_WAKE			\
-				| 0*SD_WAKE_AFFINE			\
-				| 0*SD_PREFER_LOCAL			\
-				| 0*SD_SHARE_CPUPOWER			\
-				| 0*SD_SHARE_PKG_RESOURCES		\
-				| 1*SD_SERIALIZE			\
-				,					\
-	.last_balance		= jiffies,				\
-	.balance_interval	= 128,					\
-}
-
 /* By definition, we create nodes based on online memory. */
 #define node_has_online_mem(nid) 1
 
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common
index 20a49ba..43ef890 100644
--- a/arch/um/Kconfig.common
+++ b/arch/um/Kconfig.common
@@ -56,11 +56,6 @@
 	bool
 	default y
 
-# Used in kernel/irq/manage.c and include/linux/irq.h
-config IRQ_RELEASE_METHOD
-	bool
-	default y
-
 config HZ
 	int
 	default 100
diff --git a/arch/um/defconfig b/arch/um/defconfig
index fdc97e2..7823ab1 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -12,7 +12,6 @@
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_IRQ_RELEASE_METHOD=y
 CONFIG_HZ=100
 
 #
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index ca4c7eb..45e248c 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -8,6 +8,7 @@
 #include <linux/tty_flip.h>
 #include "chan.h"
 #include "os.h"
+#include "irq_kern.h"
 
 #ifdef CONFIG_NOCONFIG_CHAN
 static void *not_configged_init(char *str, int device,
@@ -213,9 +214,9 @@
 		chan = list_entry(ele, struct chan, free_list);
 
 		if (chan->input && chan->enabled)
-			free_irq(chan->line->driver->read_irq, chan);
+			um_free_irq(chan->line->driver->read_irq, chan);
 		if (chan->output && chan->enabled)
-			free_irq(chan->line->driver->write_irq, chan);
+			um_free_irq(chan->line->driver->write_irq, chan);
 		chan->enabled = 0;
 	}
 }
@@ -234,9 +235,9 @@
 	}
 	else {
 		if (chan->input && chan->enabled)
-			free_irq(chan->line->driver->read_irq, chan);
+			um_free_irq(chan->line->driver->read_irq, chan);
 		if (chan->output && chan->enabled)
-			free_irq(chan->line->driver->write_irq, chan);
+			um_free_irq(chan->line->driver->write_irq, chan);
 		chan->enabled = 0;
 	}
 	if (chan->ops->close != NULL)
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 4ab0d9c..acfd0e0 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -699,7 +699,7 @@
 static void __free_winch(struct work_struct *work)
 {
 	struct winch *winch = container_of(work, struct winch, work);
-	free_irq(WINCH_IRQ, winch);
+	um_free_irq(WINCH_IRQ, winch);
 
 	if (winch->pid != -1)
 		os_kill_process(winch->pid, 1);
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 95f4416..0d60c56 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -195,7 +195,7 @@
 
 	netif_stop_queue(dev);
 
-	free_irq(dev->irq, dev);
+	um_free_irq(dev->irq, dev);
 	if (lp->close != NULL)
 		(*lp->close)(lp->fd, &lp->user);
 	lp->fd = -1;
@@ -835,7 +835,7 @@
 	spin_lock(&opened_lock);
 	list_for_each(ele, &opened) {
 		lp = list_entry(ele, struct uml_net_private, list);
-		free_irq(lp->dev->irq, lp->dev);
+		um_free_irq(lp->dev->irq, lp->dev);
 		if ((lp->close != NULL) && (lp->fd >= 0))
 			(*lp->close)(lp->fd, &lp->user);
 		if (lp->remove != NULL)
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index e31680e..11866ff 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -254,7 +254,7 @@
 		 * connection.  Then we loop here throwing out failed
 		 * connections until a good one is found.
 		 */
-		free_irq(TELNETD_IRQ, conn);
+		um_free_irq(TELNETD_IRQ, conn);
 
 		if (conn->fd >= 0)
 			break;
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
index 8bd130f..b68bbe2 100644
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -65,7 +65,7 @@
 	 * isn't set) this will hang... */
 	wait_for_completion(&data->ready);
 
-	free_irq(XTERM_IRQ, data);
+	um_free_irq(XTERM_IRQ, data);
 
 	ret = data->new_fd;
 	*pid_out = data->pid;
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h
index 6a3f984..5888f1b 100644
--- a/arch/um/include/asm/pgtable.h
+++ b/arch/um/include/asm/pgtable.h
@@ -273,6 +273,12 @@
 }
 #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
+#define __HAVE_ARCH_PTE_SAME
+static inline int pte_same(pte_t pte_a, pte_t pte_b)
+{
+	return !((pte_val(pte_a) ^ pte_val(pte_b)) & ~_PAGE_NEWPAGE);
+}
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
@@ -348,11 +354,11 @@
 #define update_mmu_cache(vma,address,ptep) do ; while (0)
 
 /* Encode and de-code a swap entry */
-#define __swp_type(x)			(((x).val >> 4) & 0x3f)
+#define __swp_type(x)			(((x).val >> 5) & 0x1f)
 #define __swp_offset(x)			((x).val >> 11)
 
 #define __swp_entry(type, offset) \
-	((swp_entry_t) { ((type) << 4) | ((offset) << 11) })
+	((swp_entry_t) { ((type) << 5) | ((offset) << 11) })
 #define __pte_to_swp_entry(pte) \
 	((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
 #define __swp_entry_to_pte(x)		((pte_t) { (x).val })
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h
index 7827394..69f1c57 100644
--- a/arch/um/include/asm/processor-generic.h
+++ b/arch/um/include/asm/processor-generic.h
@@ -74,11 +74,6 @@
 
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-static inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
-
 extern unsigned long thread_saved_pc(struct task_struct *t);
 
 static inline void mm_copy_segments(struct mm_struct *from_mm,
diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h
index 200c4ab..c04e5ab 100644
--- a/arch/um/include/asm/thread_info.h
+++ b/arch/um/include/asm/thread_info.h
@@ -71,6 +71,7 @@
 #define TIF_MEMDIE		5	/* is terminating due to OOM killer */
 #define TIF_SYSCALL_AUDIT	6
 #define TIF_RESTORE_SIGMASK	7
+#define TIF_NOTIFY_RESUME	8
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
@@ -78,6 +79,5 @@
 #define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
 #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 
 #endif
diff --git a/arch/um/include/shared/irq_kern.h b/arch/um/include/shared/irq_kern.h
index b05d22f..7a5bfa6 100644
--- a/arch/um/include/shared/irq_kern.h
+++ b/arch/um/include/shared/irq_kern.h
@@ -13,6 +13,6 @@
 			  irq_handler_t handler,
 			  unsigned long irqflags,  const char * devname,
 			  void *dev_id);
-
+void um_free_irq(unsigned int irq, void *dev);
 #endif
 
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 71b8c94..00506c3 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -297,6 +297,13 @@
 	return 1;
 }
 
+void um_free_irq(unsigned int irq, void *dev)
+{
+	free_irq_by_irq_and_dev(irq, dev);
+	free_irq(irq, dev);
+}
+EXPORT_SYMBOL(um_free_irq);
+
 int um_request_irq(unsigned int irq, int fd, int type,
 		   irq_handler_t handler,
 		   unsigned long irqflags, const char * devname,
@@ -327,7 +334,6 @@
 /* This is used for everything else than the timer. */
 static struct irq_chip normal_irq_type = {
 	.name = "SIGIO",
-	.release = free_irq_by_irq_and_dev,
 	.irq_disable = dummy,
 	.irq_enable = dummy,
 	.irq_ack = dummy,
@@ -335,7 +341,6 @@
 
 static struct irq_chip SIGVTALRM_irq_type = {
 	.name = "SIGVTALRM",
-	.release = free_irq_by_irq_and_dev,
 	.irq_disable = dummy,
 	.irq_enable = dummy,
 	.irq_ack = dummy,
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 2b73ded..3a2235e 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -18,6 +18,7 @@
 #include <linux/seq_file.h>
 #include <linux/tick.h>
 #include <linux/threads.h>
+#include <linux/tracehook.h>
 #include <asm/current.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
@@ -114,8 +115,13 @@
 {
 	if (need_resched())
 		schedule();
-	if (test_tsk_thread_flag(current, TIF_SIGPENDING))
+	if (test_thread_flag(TIF_SIGPENDING))
 		do_signal();
+	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+		tracehook_notify_resume(&current->thread.regs);
+		if (current->replacement_session_keyring)
+			key_replace_session_keyring();
+	}
 }
 
 void exit_thread(void)
@@ -190,7 +196,7 @@
 	if (current->thread.forking) {
 	  	memcpy(&p->thread.regs.regs, &regs->regs,
 		       sizeof(p->thread.regs.regs));
-		REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.gp, 0);
+		UPT_SET_SYSCALL_RETURN(&p->thread.regs.regs, 0);
 		if (sp != 0)
 			REGS_SP(p->thread.regs.regs.gp) = sp;
 
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index fb12f4c..292e706 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -29,9 +29,6 @@
 	unsigned long sp;
 	int err;
 
-	/* Always make any pending restarted system calls return -EINTR */
-	current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
 	/* Did we come from a system call? */
 	if (PT_REGS_SYSCALL_NR(regs) >= 0) {
 		/* If so, check system call restarting.. */
@@ -77,15 +74,14 @@
 {
 	struct k_sigaction ka_copy;
 	siginfo_t info;
-	sigset_t *oldset;
 	int sig, handled_sig = 0;
 
-	if (test_thread_flag(TIF_RESTORE_SIGMASK))
-		oldset = &current->saved_sigmask;
-	else
-		oldset = &current->blocked;
-
 	while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) {
+		sigset_t *oldset;
+		if (test_thread_flag(TIF_RESTORE_SIGMASK))
+			oldset = &current->saved_sigmask;
+		else
+			oldset = &current->blocked;
 		handled_sig = 1;
 		/* Whee!  Actually deliver the signal.  */
 		if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) {
@@ -152,15 +148,8 @@
 long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
 	sigset_t blocked;
-
-	mask &= _BLOCKABLE;
 	siginitset(&blocked, mask);
-	set_current_blocked(&blocked);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_thread_flag(TIF_RESTORE_SIGMASK);
-	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
index f5173e1..05fbeb4 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -34,7 +34,7 @@
 		result = -ENOSYS;
 	else result = EXECUTE_SYSCALL(syscall, regs);
 
-	REGS_SET_SYSCALL_RETURN(r->gp, result);
+	UPT_SET_SYSCALL_RETURN(r, result);
 
 	syscall_trace(r, 1);
 }
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 7f3d4d86..f819af9 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -75,6 +75,7 @@
 		default:
 			printk(KERN_ERR "Unknown op type %d in do_ops\n",
 			       op->type);
+			BUG();
 			break;
 		}
 	}
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index c0afff7..90b310d 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -48,10 +48,6 @@
 
 extern int proc_mm;
 
-int single_count = 0;
-int multi_count = 0;
-int multi_op_count = 0;
-
 static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
 {
 	int n, i;
@@ -64,8 +60,6 @@
 		/* FIXME: Need to look up userspace_pid by cpu */
 		pid = userspace_pid[0];
 
-	multi_count++;
-
 	n = ptrace_setregs(pid, syscall_regs);
 	if (n < 0) {
 		printk(UM_KERN_ERR "Registers - \n");
@@ -126,9 +120,6 @@
 {
 	unsigned long *stack = check_init_stack(mm_idp, *addr);
 
-	if (done && *addr == NULL)
-		single_count++;
-
 	*stack += sizeof(long);
 	stack += *stack / sizeof(long);
 
@@ -141,7 +132,6 @@
 	*stack++ = args[5];
 	*stack++ = expected;
 	*stack = 0;
-	multi_op_count++;
 
 	if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) <
 		     UM_KERN_PAGE_SIZE - 10 * sizeof(long))) {
diff --git a/arch/unicore32/include/asm/processor.h b/arch/unicore32/include/asm/processor.h
index f0d780a..14382cb 100644
--- a/arch/unicore32/include/asm/processor.h
+++ b/arch/unicore32/include/asm/processor.h
@@ -68,9 +68,6 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
 unsigned long get_wchan(struct task_struct *p);
 
 #define cpu_relax()			barrier()
diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c
index 911b549..7754df6 100644
--- a/arch/unicore32/kernel/signal.c
+++ b/arch/unicore32/kernel/signal.c
@@ -370,10 +370,7 @@
 	/*
 	 * Block the signal if we were successful.
 	 */
-	sigorsets(&blocked, &tsk->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&blocked, sig);
-	set_current_blocked(&blocked);
+	block_sigmask(ka, sig);
 
 	return 0;
 }
@@ -450,15 +447,12 @@
 		    regs->UCreg_00 == -ERESTARTNOINTR) {
 			setup_syscall_restart(regs);
 		}
-
-		/* If there's no signal to deliver, we just put the saved
-		 * sigmask back.
-		 */
-		if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-			clear_thread_flag(TIF_RESTORE_SIGMASK);
-			sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
-		}
 	}
+	/* If there's no signal to deliver, we just put the saved
+	 * sigmask back.
+	 */
+	if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+		set_current_blocked(&current->saved_sigmask);
 }
 
 asmlinkage void do_notify_resume(struct pt_regs *regs,
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 2787fbe..0b2d5f2 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -12,6 +12,7 @@
 
 config X86_64
 	def_bool 64BIT
+	select X86_DEV_DMA_OPS
 
 ### Arch settings
 config X86
@@ -40,7 +41,6 @@
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_FUNCTION_GRAPH_FP_TEST
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
-	select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HAVE_KVM
 	select HAVE_ARCH_KGDB
@@ -84,9 +84,10 @@
 	select DCACHE_WORD_ACCESS
 	select GENERIC_SMP_IDLE_THREAD
 	select HAVE_ARCH_SECCOMP_FILTER
+	select BUILDTIME_EXTABLE_SORT
 
 config INSTRUCTION_DECODER
-	def_bool (KPROBES || PERF_EVENTS)
+	def_bool (KPROBES || PERF_EVENTS || UPROBES)
 
 config OUTPUT_FORMAT
 	string
@@ -242,6 +243,9 @@
 	def_bool y
 	depends on HOTPLUG_CPU
 
+config ARCH_SUPPORTS_UPROBES
+	def_bool y
+
 source "init/Kconfig"
 source "kernel/Kconfig.freezer"
 
@@ -327,6 +331,7 @@
 		NUMAQ (IBM/Sequent)
 		RDC R-321x SoC
 		SGI 320/540 (Visual Workstation)
+		STA2X11-based (e.g. Northville)
 		Summit/EXA (IBM x440)
 		Unisys ES7000 IA32 series
 		Moorestown MID devices
@@ -373,6 +378,7 @@
 	select PARAVIRT
 	depends on X86_64 && PCI
 	depends on X86_EXTENDED_PLATFORM
+	depends on SMP
 	---help---
 	  Support for ScaleMP vSMP systems.  Say 'Y' here if this kernel is
 	  supposed to run on these EM64T-based machines.  Only choose this option
@@ -459,10 +465,10 @@
 	depends on X86_32 && SMP
 	depends on X86_EXTENDED_PLATFORM
 	---help---
-	  This option compiles in the NUMAQ, Summit, bigsmp, ES7000, default
-	  subarchitectures.  It is intended for a generic binary kernel.
-	  if you select them all, kernel will probe it one by one. and will
-	  fallback to default.
+	  This option compiles in the NUMAQ, Summit, bigsmp, ES7000,
+	  STA2X11, default subarchitectures.  It is intended for a generic
+	  binary kernel. If you select them all, kernel will probe it
+	  one by one and will fallback to default.
 
 # Alphabetically sorted list of Non standard 32 bit platforms
 
@@ -502,6 +508,22 @@
 	  A kernel compiled for the Visual Workstation will run on general
 	  PCs as well. See <file:Documentation/sgi-visws.txt> for details.
 
+config STA2X11
+	bool "STA2X11 Companion Chip Support"
+	depends on X86_32_NON_STANDARD && PCI
+	select X86_DEV_DMA_OPS
+	select X86_DMA_REMAP
+	select SWIOTLB
+	select MFD_STA2X11
+	select ARCH_REQUIRE_GPIOLIB
+	default n
+	---help---
+	  This adds support for boards based on the STA2X11 IO-Hub,
+	  a.k.a. "ConneXt". The chip is used in place of the standard
+	  PC chipset, so all "standard" peripherals are missing. If this
+	  option is selected the kernel will still be able to boot on
+	  standard PC machines.
+
 config X86_SUMMIT
 	bool "Summit/EXA (IBM x440)"
 	depends on X86_32_NON_STANDARD
@@ -1238,10 +1260,6 @@
 	  Specify the maximum number of NUMA Nodes available on the target
 	  system.  Increases memory reserved to accommodate various tables.
 
-config HAVE_ARCH_BOOTMEM
-	def_bool y
-	depends on X86_32 && NUMA
-
 config HAVE_ARCH_ALLOC_REMAP
 	def_bool y
 	depends on X86_32 && NUMA
@@ -2022,16 +2040,6 @@
 
 source "drivers/eisa/Kconfig"
 
-config MCA
-	bool "MCA support"
-	---help---
-	  MicroChannel Architecture is found in some IBM PS/2 machines and
-	  laptops.  It is a bus system similar to PCI or ISA. See
-	  <file:Documentation/mca.txt> (and especially the web page given
-	  there) before attempting to build an MCA bus kernel.
-
-source "drivers/mca/Kconfig"
-
 config SCx200
 	tristate "NatSemi SCx200 support"
 	---help---
@@ -2214,6 +2222,14 @@
 	bool
 	select STOP_MACHINE if SMP
 
+config X86_DEV_DMA_OPS
+	bool
+	depends on X86_64 || STA2X11
+
+config X86_DMA_REMAP
+	bool
+	depends on STA2X11
+
 source "net/Kconfig"
 
 source "drivers/Kconfig"
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 277418f..1f25214 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -115,9 +115,10 @@
 
 # does binutils support specific instructions?
 asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1)
+avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1)
 
-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr)
-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr)
+KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr)
+KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr)
 
 LDFLAGS := -m elf_$(UTS_MACHINE)
 
@@ -205,6 +206,7 @@
 	$(Q)rm -rf $(objtree)/arch/i386
 	$(Q)rm -rf $(objtree)/arch/x86_64
 	$(Q)$(MAKE) $(clean)=$(boot)
+	$(Q)$(MAKE) $(clean)=arch/x86/tools
 
 define archhelp
   echo  '* bzImage      - Compressed kernel image (arch/x86/boot/bzImage)'
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 0cdfc0d..2c14e76 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -904,11 +904,19 @@
 
 	memset(boot_params, 0x0, 0x4000);
 
-	/* Copy first two sectors to boot_params */
-	memcpy(boot_params, image->image_base, 1024);
-
 	hdr = &boot_params->hdr;
 
+	/* Copy the second sector to boot_params */
+	memcpy(&hdr->jump, image->image_base + 512, 512);
+
+	/*
+	 * Fill out some of the header fields ourselves because the
+	 * EFI firmware loader doesn't load the first sector.
+	 */
+	hdr->root_flags = 1;
+	hdr->vid_mode = 0xffff;
+	hdr->boot_flag = 0xAA55;
+
 	/*
 	 * The EFI firmware loader could have placed the kernel image
 	 * anywhere in memory, but the kernel has various restrictions
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index f1bbeeb..8bbea6a 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -147,7 +147,7 @@
 	# Filled in by build.c
 	.long	0x0000				# AddressOfEntryPoint
 
-	.long	0x0000				# BaseOfCode
+	.long	0x0200				# BaseOfCode
 #ifdef CONFIG_X86_32
 	.long	0				# data
 #endif
@@ -189,7 +189,7 @@
 	.quad	0				# SizeOfHeapCommit
 #endif
 	.long	0				# LoaderFlags
-	.long	0x1				# NumberOfRvaAndSizes
+	.long	0x6				# NumberOfRvaAndSizes
 
 	.quad	0				# ExportTable
 	.quad	0				# ImportTable
@@ -217,18 +217,17 @@
 
 	#
 	# The EFI application loader requires a relocation section
-	# because EFI applications are relocatable and not having
-	# this section seems to confuse it. But since we don't need
-	# the loader to fixup any relocs for us just fill it with a
-	# single dummy reloc.
+	# because EFI applications must be relocatable. But since
+	# we don't need the loader to fixup any relocs for us, we
+	# just create an empty (zero-length) .reloc section header.
 	#
 	.ascii	".reloc"
 	.byte	0
 	.byte	0
-	.long	reloc_end - reloc_start
-	.long	reloc_start
-	.long	reloc_end - reloc_start		# SizeOfRawData
-	.long	reloc_start			# PointerToRawData
+	.long	0
+	.long	0
+	.long	0				# SizeOfRawData
+	.long	0				# PointerToRawData
 	.long	0				# PointerToRelocations
 	.long	0				# PointerToLineNumbers
 	.word	0				# NumberOfRelocations
@@ -469,10 +468,3 @@
 
 	.data
 dummy:	.long	0
-
-	.section .reloc
-reloc_start:
-	.long	dummy - reloc_start
-	.long	10
-	.word	0
-reloc_end:
diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c
index 40358c8..cf6083d 100644
--- a/arch/x86/boot/main.c
+++ b/arch/x86/boot/main.c
@@ -57,14 +57,20 @@
 }
 
 /*
- * Set the keyboard repeat rate to maximum.  Unclear why this
+ * Query the keyboard lock status as given by the BIOS, and
+ * set the keyboard repeat rate to maximum.  Unclear why the latter
  * is done here; this might be possible to kill off as stale code.
  */
-static void keyboard_set_repeat(void)
+static void keyboard_init(void)
 {
-	struct biosregs ireg;
+	struct biosregs ireg, oreg;
 	initregs(&ireg);
-	ireg.ax = 0x0305;
+
+	ireg.ah = 0x02;		/* Get keyboard status */
+	intcall(0x16, &ireg, &oreg);
+	boot_params.kbd_status = oreg.al;
+
+	ireg.ax = 0x0305;	/* Set keyboard repeat rate */
 	intcall(0x16, &ireg, NULL);
 }
 
@@ -151,8 +157,8 @@
 	/* Detect memory layout */
 	detect_memory();
 
-	/* Set keyboard repeat rate (why?) */
-	keyboard_set_repeat();
+	/* Set keyboard repeat rate (why?) and query the lock flags */
+	keyboard_init();
 
 	/* Query MCA information */
 	query_mca();
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 24443a3..3f61f6e 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -198,12 +198,19 @@
 
 	pe_header = get_unaligned_le32(&buf[0x3c]);
 
-	/* Size of code */
-	put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]);
-
 	/* Size of image */
 	put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
 
+	/*
+	 * Subtract the size of the first section (512 bytes) which
+	 * includes the header and .reloc section. The remaining size
+	 * is that of the .text section.
+	 */
+	file_sz -= 512;
+
+	/* Size of code */
+	put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]);
+
 #ifdef CONFIG_X86_32
 	/*
 	 * Address of entry point.
@@ -216,8 +223,14 @@
 	/* .text size */
 	put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]);
 
+	/* .text vma */
+	put_unaligned_le32(0x200, &buf[pe_header + 0xb4]);
+
 	/* .text size of initialised data */
 	put_unaligned_le32(file_sz, &buf[pe_header + 0xb8]);
+
+	/* .text file offset */
+	put_unaligned_le32(0x200, &buf[pe_header + 0xbc]);
 #else
 	/*
 	 * Address of entry point. startup_32 is at the beginning and
@@ -231,9 +244,14 @@
 	/* .text size */
 	put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]);
 
+	/* .text vma */
+	put_unaligned_le32(0x200, &buf[pe_header + 0xc4]);
+
 	/* .text size of initialised data */
 	put_unaligned_le32(file_sz, &buf[pe_header + 0xc8]);
 
+	/* .text file offset */
+	put_unaligned_le32(0x200, &buf[pe_header + 0xcc]);
 #endif /* CONFIG_X86_32 */
 #endif /* CONFIG_EFI_STUB */
 
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index c799352..ac7f5cd 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -222,27 +222,6 @@
 	}
 }
 
-static struct crypto_alg aesni_alg = {
-	.cra_name		= "aes",
-	.cra_driver_name	= "aes-aesni",
-	.cra_priority		= 300,
-	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize		= AES_BLOCK_SIZE,
-	.cra_ctxsize		= sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
-	.cra_alignmask		= 0,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(aesni_alg.cra_list),
-	.cra_u	= {
-		.cipher	= {
-			.cia_min_keysize	= AES_MIN_KEY_SIZE,
-			.cia_max_keysize	= AES_MAX_KEY_SIZE,
-			.cia_setkey		= aes_set_key,
-			.cia_encrypt		= aes_encrypt,
-			.cia_decrypt		= aes_decrypt
-		}
-	}
-};
-
 static void __aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
 	struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
@@ -257,27 +236,6 @@
 	aesni_dec(ctx, dst, src);
 }
 
-static struct crypto_alg __aesni_alg = {
-	.cra_name		= "__aes-aesni",
-	.cra_driver_name	= "__driver-aes-aesni",
-	.cra_priority		= 0,
-	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize		= AES_BLOCK_SIZE,
-	.cra_ctxsize		= sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
-	.cra_alignmask		= 0,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(__aesni_alg.cra_list),
-	.cra_u	= {
-		.cipher	= {
-			.cia_min_keysize	= AES_MIN_KEY_SIZE,
-			.cia_max_keysize	= AES_MAX_KEY_SIZE,
-			.cia_setkey		= aes_set_key,
-			.cia_encrypt		= __aes_encrypt,
-			.cia_decrypt		= __aes_decrypt
-		}
-	}
-};
-
 static int ecb_encrypt(struct blkcipher_desc *desc,
 		       struct scatterlist *dst, struct scatterlist *src,
 		       unsigned int nbytes)
@@ -326,28 +284,6 @@
 	return err;
 }
 
-static struct crypto_alg blk_ecb_alg = {
-	.cra_name		= "__ecb-aes-aesni",
-	.cra_driver_name	= "__driver-ecb-aes-aesni",
-	.cra_priority		= 0,
-	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
-	.cra_blocksize		= AES_BLOCK_SIZE,
-	.cra_ctxsize		= sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_blkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(blk_ecb_alg.cra_list),
-	.cra_u = {
-		.blkcipher = {
-			.min_keysize	= AES_MIN_KEY_SIZE,
-			.max_keysize	= AES_MAX_KEY_SIZE,
-			.setkey		= aes_set_key,
-			.encrypt	= ecb_encrypt,
-			.decrypt	= ecb_decrypt,
-		},
-	},
-};
-
 static int cbc_encrypt(struct blkcipher_desc *desc,
 		       struct scatterlist *dst, struct scatterlist *src,
 		       unsigned int nbytes)
@@ -396,28 +332,6 @@
 	return err;
 }
 
-static struct crypto_alg blk_cbc_alg = {
-	.cra_name		= "__cbc-aes-aesni",
-	.cra_driver_name	= "__driver-cbc-aes-aesni",
-	.cra_priority		= 0,
-	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
-	.cra_blocksize		= AES_BLOCK_SIZE,
-	.cra_ctxsize		= sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_blkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(blk_cbc_alg.cra_list),
-	.cra_u = {
-		.blkcipher = {
-			.min_keysize	= AES_MIN_KEY_SIZE,
-			.max_keysize	= AES_MAX_KEY_SIZE,
-			.setkey		= aes_set_key,
-			.encrypt	= cbc_encrypt,
-			.decrypt	= cbc_decrypt,
-		},
-	},
-};
-
 #ifdef CONFIG_X86_64
 static void ctr_crypt_final(struct crypto_aes_ctx *ctx,
 			    struct blkcipher_walk *walk)
@@ -461,29 +375,6 @@
 
 	return err;
 }
-
-static struct crypto_alg blk_ctr_alg = {
-	.cra_name		= "__ctr-aes-aesni",
-	.cra_driver_name	= "__driver-ctr-aes-aesni",
-	.cra_priority		= 0,
-	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
-	.cra_blocksize		= 1,
-	.cra_ctxsize		= sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_blkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(blk_ctr_alg.cra_list),
-	.cra_u = {
-		.blkcipher = {
-			.min_keysize	= AES_MIN_KEY_SIZE,
-			.max_keysize	= AES_MAX_KEY_SIZE,
-			.ivsize		= AES_BLOCK_SIZE,
-			.setkey		= aes_set_key,
-			.encrypt	= ctr_crypt,
-			.decrypt	= ctr_crypt,
-		},
-	},
-};
 #endif
 
 static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
@@ -551,281 +442,65 @@
 	cryptd_free_ablkcipher(ctx->cryptd_tfm);
 }
 
-static void ablk_init_common(struct crypto_tfm *tfm,
-			     struct cryptd_ablkcipher *cryptd_tfm)
+static int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name)
 {
 	struct async_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct cryptd_ablkcipher *cryptd_tfm;
+
+	cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0);
+	if (IS_ERR(cryptd_tfm))
+		return PTR_ERR(cryptd_tfm);
 
 	ctx->cryptd_tfm = cryptd_tfm;
 	tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
 		crypto_ablkcipher_reqsize(&cryptd_tfm->base);
+
+	return 0;
 }
 
 static int ablk_ecb_init(struct crypto_tfm *tfm)
 {
-	struct cryptd_ablkcipher *cryptd_tfm;
-
-	cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-aes-aesni", 0, 0);
-	if (IS_ERR(cryptd_tfm))
-		return PTR_ERR(cryptd_tfm);
-	ablk_init_common(tfm, cryptd_tfm);
-	return 0;
+	return ablk_init_common(tfm, "__driver-ecb-aes-aesni");
 }
 
-static struct crypto_alg ablk_ecb_alg = {
-	.cra_name		= "ecb(aes)",
-	.cra_driver_name	= "ecb-aes-aesni",
-	.cra_priority		= 400,
-	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
-	.cra_blocksize		= AES_BLOCK_SIZE,
-	.cra_ctxsize		= sizeof(struct async_aes_ctx),
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_ablkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(ablk_ecb_alg.cra_list),
-	.cra_init		= ablk_ecb_init,
-	.cra_exit		= ablk_exit,
-	.cra_u = {
-		.ablkcipher = {
-			.min_keysize	= AES_MIN_KEY_SIZE,
-			.max_keysize	= AES_MAX_KEY_SIZE,
-			.setkey		= ablk_set_key,
-			.encrypt	= ablk_encrypt,
-			.decrypt	= ablk_decrypt,
-		},
-	},
-};
-
 static int ablk_cbc_init(struct crypto_tfm *tfm)
 {
-	struct cryptd_ablkcipher *cryptd_tfm;
-
-	cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-aes-aesni", 0, 0);
-	if (IS_ERR(cryptd_tfm))
-		return PTR_ERR(cryptd_tfm);
-	ablk_init_common(tfm, cryptd_tfm);
-	return 0;
+	return ablk_init_common(tfm, "__driver-cbc-aes-aesni");
 }
 
-static struct crypto_alg ablk_cbc_alg = {
-	.cra_name		= "cbc(aes)",
-	.cra_driver_name	= "cbc-aes-aesni",
-	.cra_priority		= 400,
-	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
-	.cra_blocksize		= AES_BLOCK_SIZE,
-	.cra_ctxsize		= sizeof(struct async_aes_ctx),
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_ablkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(ablk_cbc_alg.cra_list),
-	.cra_init		= ablk_cbc_init,
-	.cra_exit		= ablk_exit,
-	.cra_u = {
-		.ablkcipher = {
-			.min_keysize	= AES_MIN_KEY_SIZE,
-			.max_keysize	= AES_MAX_KEY_SIZE,
-			.ivsize		= AES_BLOCK_SIZE,
-			.setkey		= ablk_set_key,
-			.encrypt	= ablk_encrypt,
-			.decrypt	= ablk_decrypt,
-		},
-	},
-};
-
 #ifdef CONFIG_X86_64
 static int ablk_ctr_init(struct crypto_tfm *tfm)
 {
-	struct cryptd_ablkcipher *cryptd_tfm;
-
-	cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-aes-aesni", 0, 0);
-	if (IS_ERR(cryptd_tfm))
-		return PTR_ERR(cryptd_tfm);
-	ablk_init_common(tfm, cryptd_tfm);
-	return 0;
+	return ablk_init_common(tfm, "__driver-ctr-aes-aesni");
 }
 
-static struct crypto_alg ablk_ctr_alg = {
-	.cra_name		= "ctr(aes)",
-	.cra_driver_name	= "ctr-aes-aesni",
-	.cra_priority		= 400,
-	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
-	.cra_blocksize		= 1,
-	.cra_ctxsize		= sizeof(struct async_aes_ctx),
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_ablkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(ablk_ctr_alg.cra_list),
-	.cra_init		= ablk_ctr_init,
-	.cra_exit		= ablk_exit,
-	.cra_u = {
-		.ablkcipher = {
-			.min_keysize	= AES_MIN_KEY_SIZE,
-			.max_keysize	= AES_MAX_KEY_SIZE,
-			.ivsize		= AES_BLOCK_SIZE,
-			.setkey		= ablk_set_key,
-			.encrypt	= ablk_encrypt,
-			.decrypt	= ablk_encrypt,
-			.geniv		= "chainiv",
-		},
-	},
-};
-
 #ifdef HAS_CTR
 static int ablk_rfc3686_ctr_init(struct crypto_tfm *tfm)
 {
-	struct cryptd_ablkcipher *cryptd_tfm;
-
-	cryptd_tfm = cryptd_alloc_ablkcipher(
-		"rfc3686(__driver-ctr-aes-aesni)", 0, 0);
-	if (IS_ERR(cryptd_tfm))
-		return PTR_ERR(cryptd_tfm);
-	ablk_init_common(tfm, cryptd_tfm);
-	return 0;
+	return ablk_init_common(tfm, "rfc3686(__driver-ctr-aes-aesni)");
 }
-
-static struct crypto_alg ablk_rfc3686_ctr_alg = {
-	.cra_name		= "rfc3686(ctr(aes))",
-	.cra_driver_name	= "rfc3686-ctr-aes-aesni",
-	.cra_priority		= 400,
-	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
-	.cra_blocksize		= 1,
-	.cra_ctxsize		= sizeof(struct async_aes_ctx),
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_ablkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(ablk_rfc3686_ctr_alg.cra_list),
-	.cra_init		= ablk_rfc3686_ctr_init,
-	.cra_exit		= ablk_exit,
-	.cra_u = {
-		.ablkcipher = {
-			.min_keysize = AES_MIN_KEY_SIZE+CTR_RFC3686_NONCE_SIZE,
-			.max_keysize = AES_MAX_KEY_SIZE+CTR_RFC3686_NONCE_SIZE,
-			.ivsize	     = CTR_RFC3686_IV_SIZE,
-			.setkey	     = ablk_set_key,
-			.encrypt     = ablk_encrypt,
-			.decrypt     = ablk_decrypt,
-			.geniv	     = "seqiv",
-		},
-	},
-};
 #endif
 #endif
 
 #ifdef HAS_LRW
 static int ablk_lrw_init(struct crypto_tfm *tfm)
 {
-	struct cryptd_ablkcipher *cryptd_tfm;
-
-	cryptd_tfm = cryptd_alloc_ablkcipher("fpu(lrw(__driver-aes-aesni))",
-					     0, 0);
-	if (IS_ERR(cryptd_tfm))
-		return PTR_ERR(cryptd_tfm);
-	ablk_init_common(tfm, cryptd_tfm);
-	return 0;
+	return ablk_init_common(tfm, "fpu(lrw(__driver-aes-aesni))");
 }
-
-static struct crypto_alg ablk_lrw_alg = {
-	.cra_name		= "lrw(aes)",
-	.cra_driver_name	= "lrw-aes-aesni",
-	.cra_priority		= 400,
-	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
-	.cra_blocksize		= AES_BLOCK_SIZE,
-	.cra_ctxsize		= sizeof(struct async_aes_ctx),
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_ablkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(ablk_lrw_alg.cra_list),
-	.cra_init		= ablk_lrw_init,
-	.cra_exit		= ablk_exit,
-	.cra_u = {
-		.ablkcipher = {
-			.min_keysize	= AES_MIN_KEY_SIZE + AES_BLOCK_SIZE,
-			.max_keysize	= AES_MAX_KEY_SIZE + AES_BLOCK_SIZE,
-			.ivsize		= AES_BLOCK_SIZE,
-			.setkey		= ablk_set_key,
-			.encrypt	= ablk_encrypt,
-			.decrypt	= ablk_decrypt,
-		},
-	},
-};
 #endif
 
 #ifdef HAS_PCBC
 static int ablk_pcbc_init(struct crypto_tfm *tfm)
 {
-	struct cryptd_ablkcipher *cryptd_tfm;
-
-	cryptd_tfm = cryptd_alloc_ablkcipher("fpu(pcbc(__driver-aes-aesni))",
-					     0, 0);
-	if (IS_ERR(cryptd_tfm))
-		return PTR_ERR(cryptd_tfm);
-	ablk_init_common(tfm, cryptd_tfm);
-	return 0;
+	return ablk_init_common(tfm, "fpu(pcbc(__driver-aes-aesni))");
 }
-
-static struct crypto_alg ablk_pcbc_alg = {
-	.cra_name		= "pcbc(aes)",
-	.cra_driver_name	= "pcbc-aes-aesni",
-	.cra_priority		= 400,
-	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
-	.cra_blocksize		= AES_BLOCK_SIZE,
-	.cra_ctxsize		= sizeof(struct async_aes_ctx),
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_ablkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(ablk_pcbc_alg.cra_list),
-	.cra_init		= ablk_pcbc_init,
-	.cra_exit		= ablk_exit,
-	.cra_u = {
-		.ablkcipher = {
-			.min_keysize	= AES_MIN_KEY_SIZE,
-			.max_keysize	= AES_MAX_KEY_SIZE,
-			.ivsize		= AES_BLOCK_SIZE,
-			.setkey		= ablk_set_key,
-			.encrypt	= ablk_encrypt,
-			.decrypt	= ablk_decrypt,
-		},
-	},
-};
 #endif
 
 #ifdef HAS_XTS
 static int ablk_xts_init(struct crypto_tfm *tfm)
 {
-	struct cryptd_ablkcipher *cryptd_tfm;
-
-	cryptd_tfm = cryptd_alloc_ablkcipher("fpu(xts(__driver-aes-aesni))",
-					     0, 0);
-	if (IS_ERR(cryptd_tfm))
-		return PTR_ERR(cryptd_tfm);
-	ablk_init_common(tfm, cryptd_tfm);
-	return 0;
+	return ablk_init_common(tfm, "fpu(xts(__driver-aes-aesni))");
 }
-
-static struct crypto_alg ablk_xts_alg = {
-	.cra_name		= "xts(aes)",
-	.cra_driver_name	= "xts-aes-aesni",
-	.cra_priority		= 400,
-	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
-	.cra_blocksize		= AES_BLOCK_SIZE,
-	.cra_ctxsize		= sizeof(struct async_aes_ctx),
-	.cra_alignmask		= 0,
-	.cra_type		= &crypto_ablkcipher_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(ablk_xts_alg.cra_list),
-	.cra_init		= ablk_xts_init,
-	.cra_exit		= ablk_exit,
-	.cra_u = {
-		.ablkcipher = {
-			.min_keysize	= 2 * AES_MIN_KEY_SIZE,
-			.max_keysize	= 2 * AES_MAX_KEY_SIZE,
-			.ivsize		= AES_BLOCK_SIZE,
-			.setkey		= ablk_set_key,
-			.encrypt	= ablk_encrypt,
-			.decrypt	= ablk_decrypt,
-		},
-	},
-};
 #endif
 
 #ifdef CONFIG_X86_64
@@ -1050,32 +725,6 @@
 	}
 }
 
-static struct crypto_alg rfc4106_alg = {
-	.cra_name = "rfc4106(gcm(aes))",
-	.cra_driver_name = "rfc4106-gcm-aesni",
-	.cra_priority = 400,
-	.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
-	.cra_blocksize = 1,
-	.cra_ctxsize = sizeof(struct aesni_rfc4106_gcm_ctx) + AESNI_ALIGN,
-	.cra_alignmask = 0,
-	.cra_type = &crypto_nivaead_type,
-	.cra_module = THIS_MODULE,
-	.cra_list = LIST_HEAD_INIT(rfc4106_alg.cra_list),
-	.cra_init = rfc4106_init,
-	.cra_exit = rfc4106_exit,
-	.cra_u = {
-		.aead = {
-			.setkey = rfc4106_set_key,
-			.setauthsize = rfc4106_set_authsize,
-			.encrypt = rfc4106_encrypt,
-			.decrypt = rfc4106_decrypt,
-			.geniv = "seqiv",
-			.ivsize = 8,
-			.maxauthsize = 16,
-		},
-	},
-};
-
 static int __driver_rfc4106_encrypt(struct aead_request *req)
 {
 	u8 one_entry_in_sg = 0;
@@ -1233,26 +882,316 @@
 	}
 	return retval;
 }
+#endif
 
-static struct crypto_alg __rfc4106_alg = {
+static struct crypto_alg aesni_algs[] = { {
+	.cra_name		= "aes",
+	.cra_driver_name	= "aes-aesni",
+	.cra_priority		= 300,
+	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct crypto_aes_ctx) +
+				  AESNI_ALIGN - 1,
+	.cra_alignmask		= 0,
+	.cra_module		= THIS_MODULE,
+	.cra_u	= {
+		.cipher	= {
+			.cia_min_keysize	= AES_MIN_KEY_SIZE,
+			.cia_max_keysize	= AES_MAX_KEY_SIZE,
+			.cia_setkey		= aes_set_key,
+			.cia_encrypt		= aes_encrypt,
+			.cia_decrypt		= aes_decrypt
+		}
+	}
+}, {
+	.cra_name		= "__aes-aesni",
+	.cra_driver_name	= "__driver-aes-aesni",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct crypto_aes_ctx) +
+				  AESNI_ALIGN - 1,
+	.cra_alignmask		= 0,
+	.cra_module		= THIS_MODULE,
+	.cra_u	= {
+		.cipher	= {
+			.cia_min_keysize	= AES_MIN_KEY_SIZE,
+			.cia_max_keysize	= AES_MAX_KEY_SIZE,
+			.cia_setkey		= aes_set_key,
+			.cia_encrypt		= __aes_encrypt,
+			.cia_decrypt		= __aes_decrypt
+		}
+	}
+}, {
+	.cra_name		= "__ecb-aes-aesni",
+	.cra_driver_name	= "__driver-ecb-aes-aesni",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct crypto_aes_ctx) +
+				  AESNI_ALIGN - 1,
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE,
+			.setkey		= aes_set_key,
+			.encrypt	= ecb_encrypt,
+			.decrypt	= ecb_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__cbc-aes-aesni",
+	.cra_driver_name	= "__driver-cbc-aes-aesni",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct crypto_aes_ctx) +
+				  AESNI_ALIGN - 1,
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE,
+			.setkey		= aes_set_key,
+			.encrypt	= cbc_encrypt,
+			.decrypt	= cbc_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "ecb(aes)",
+	.cra_driver_name	= "ecb-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_ecb_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "cbc(aes)",
+	.cra_driver_name	= "cbc-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_cbc_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+#ifdef CONFIG_X86_64
+}, {
+	.cra_name		= "__ctr-aes-aesni",
+	.cra_driver_name	= "__driver-ctr-aes-aesni",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct crypto_aes_ctx) +
+				  AESNI_ALIGN - 1,
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= aes_set_key,
+			.encrypt	= ctr_crypt,
+			.decrypt	= ctr_crypt,
+		},
+	},
+}, {
+	.cra_name		= "ctr(aes)",
+	.cra_driver_name	= "ctr-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_ctr_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_encrypt,
+			.geniv		= "chainiv",
+		},
+	},
+}, {
 	.cra_name		= "__gcm-aes-aesni",
 	.cra_driver_name	= "__driver-gcm-aes-aesni",
 	.cra_priority		= 0,
 	.cra_flags		= CRYPTO_ALG_TYPE_AEAD,
 	.cra_blocksize		= 1,
-	.cra_ctxsize	= sizeof(struct aesni_rfc4106_gcm_ctx) + AESNI_ALIGN,
+	.cra_ctxsize		= sizeof(struct aesni_rfc4106_gcm_ctx) +
+				  AESNI_ALIGN,
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_aead_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(__rfc4106_alg.cra_list),
 	.cra_u = {
 		.aead = {
 			.encrypt	= __driver_rfc4106_encrypt,
 			.decrypt	= __driver_rfc4106_decrypt,
 		},
 	},
-};
+}, {
+	.cra_name		= "rfc4106(gcm(aes))",
+	.cra_driver_name	= "rfc4106-gcm-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct aesni_rfc4106_gcm_ctx) +
+				  AESNI_ALIGN,
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_nivaead_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= rfc4106_init,
+	.cra_exit		= rfc4106_exit,
+	.cra_u = {
+		.aead = {
+			.setkey		= rfc4106_set_key,
+			.setauthsize	= rfc4106_set_authsize,
+			.encrypt	= rfc4106_encrypt,
+			.decrypt	= rfc4106_decrypt,
+			.geniv		= "seqiv",
+			.ivsize		= 8,
+			.maxauthsize	= 16,
+		},
+	},
+#ifdef HAS_CTR
+}, {
+	.cra_name		= "rfc3686(ctr(aes))",
+	.cra_driver_name	= "rfc3686-ctr-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_rfc3686_ctr_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize = AES_MIN_KEY_SIZE +
+				       CTR_RFC3686_NONCE_SIZE,
+			.max_keysize = AES_MAX_KEY_SIZE +
+				       CTR_RFC3686_NONCE_SIZE,
+			.ivsize	     = CTR_RFC3686_IV_SIZE,
+			.setkey	     = ablk_set_key,
+			.encrypt     = ablk_encrypt,
+			.decrypt     = ablk_decrypt,
+			.geniv	     = "seqiv",
+		},
+	},
 #endif
+#endif
+#ifdef HAS_LRW
+}, {
+	.cra_name		= "lrw(aes)",
+	.cra_driver_name	= "lrw-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_lrw_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE + AES_BLOCK_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE + AES_BLOCK_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+#endif
+#ifdef HAS_PCBC
+}, {
+	.cra_name		= "pcbc(aes)",
+	.cra_driver_name	= "pcbc-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_pcbc_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+#endif
+#ifdef HAS_XTS
+}, {
+	.cra_name		= "xts(aes)",
+	.cra_driver_name	= "xts-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_xts_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= 2 * AES_MIN_KEY_SIZE,
+			.max_keysize	= 2 * AES_MAX_KEY_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+#endif
+} };
 
 
 static const struct x86_cpu_id aesni_cpu_id[] = {
@@ -1263,120 +1202,24 @@
 
 static int __init aesni_init(void)
 {
-	int err;
+	int err, i;
 
 	if (!x86_match_cpu(aesni_cpu_id))
 		return -ENODEV;
 
-	if ((err = crypto_fpu_init()))
-		goto fpu_err;
-	if ((err = crypto_register_alg(&aesni_alg)))
-		goto aes_err;
-	if ((err = crypto_register_alg(&__aesni_alg)))
-		goto __aes_err;
-	if ((err = crypto_register_alg(&blk_ecb_alg)))
-		goto blk_ecb_err;
-	if ((err = crypto_register_alg(&blk_cbc_alg)))
-		goto blk_cbc_err;
-	if ((err = crypto_register_alg(&ablk_ecb_alg)))
-		goto ablk_ecb_err;
-	if ((err = crypto_register_alg(&ablk_cbc_alg)))
-		goto ablk_cbc_err;
-#ifdef CONFIG_X86_64
-	if ((err = crypto_register_alg(&blk_ctr_alg)))
-		goto blk_ctr_err;
-	if ((err = crypto_register_alg(&ablk_ctr_alg)))
-		goto ablk_ctr_err;
-	if ((err = crypto_register_alg(&__rfc4106_alg)))
-		goto __aead_gcm_err;
-	if ((err = crypto_register_alg(&rfc4106_alg)))
-		goto aead_gcm_err;
-#ifdef HAS_CTR
-	if ((err = crypto_register_alg(&ablk_rfc3686_ctr_alg)))
-		goto ablk_rfc3686_ctr_err;
-#endif
-#endif
-#ifdef HAS_LRW
-	if ((err = crypto_register_alg(&ablk_lrw_alg)))
-		goto ablk_lrw_err;
-#endif
-#ifdef HAS_PCBC
-	if ((err = crypto_register_alg(&ablk_pcbc_alg)))
-		goto ablk_pcbc_err;
-#endif
-#ifdef HAS_XTS
-	if ((err = crypto_register_alg(&ablk_xts_alg)))
-		goto ablk_xts_err;
-#endif
-	return err;
+	err = crypto_fpu_init();
+	if (err)
+		return err;
 
-#ifdef HAS_XTS
-ablk_xts_err:
-#endif
-#ifdef HAS_PCBC
-	crypto_unregister_alg(&ablk_pcbc_alg);
-ablk_pcbc_err:
-#endif
-#ifdef HAS_LRW
-	crypto_unregister_alg(&ablk_lrw_alg);
-ablk_lrw_err:
-#endif
-#ifdef CONFIG_X86_64
-#ifdef HAS_CTR
-	crypto_unregister_alg(&ablk_rfc3686_ctr_alg);
-ablk_rfc3686_ctr_err:
-#endif
-	crypto_unregister_alg(&rfc4106_alg);
-aead_gcm_err:
-	crypto_unregister_alg(&__rfc4106_alg);
-__aead_gcm_err:
-	crypto_unregister_alg(&ablk_ctr_alg);
-ablk_ctr_err:
-	crypto_unregister_alg(&blk_ctr_alg);
-blk_ctr_err:
-#endif
-	crypto_unregister_alg(&ablk_cbc_alg);
-ablk_cbc_err:
-	crypto_unregister_alg(&ablk_ecb_alg);
-ablk_ecb_err:
-	crypto_unregister_alg(&blk_cbc_alg);
-blk_cbc_err:
-	crypto_unregister_alg(&blk_ecb_alg);
-blk_ecb_err:
-	crypto_unregister_alg(&__aesni_alg);
-__aes_err:
-	crypto_unregister_alg(&aesni_alg);
-aes_err:
-fpu_err:
-	return err;
+	for (i = 0; i < ARRAY_SIZE(aesni_algs); i++)
+		INIT_LIST_HEAD(&aesni_algs[i].cra_list);
+
+	return crypto_register_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
 }
 
 static void __exit aesni_exit(void)
 {
-#ifdef HAS_XTS
-	crypto_unregister_alg(&ablk_xts_alg);
-#endif
-#ifdef HAS_PCBC
-	crypto_unregister_alg(&ablk_pcbc_alg);
-#endif
-#ifdef HAS_LRW
-	crypto_unregister_alg(&ablk_lrw_alg);
-#endif
-#ifdef CONFIG_X86_64
-#ifdef HAS_CTR
-	crypto_unregister_alg(&ablk_rfc3686_ctr_alg);
-#endif
-	crypto_unregister_alg(&rfc4106_alg);
-	crypto_unregister_alg(&__rfc4106_alg);
-	crypto_unregister_alg(&ablk_ctr_alg);
-	crypto_unregister_alg(&blk_ctr_alg);
-#endif
-	crypto_unregister_alg(&ablk_cbc_alg);
-	crypto_unregister_alg(&ablk_ecb_alg);
-	crypto_unregister_alg(&blk_cbc_alg);
-	crypto_unregister_alg(&blk_ecb_alg);
-	crypto_unregister_alg(&__aesni_alg);
-	crypto_unregister_alg(&aesni_alg);
+	crypto_unregister_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
 
 	crypto_fpu_exit();
 }
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 0b3f235..98bd70f 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -131,18 +131,8 @@
 asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
 	sigset_t blocked;
-
-	current->saved_sigmask = current->blocked;
-
-	mask &= _BLOCKABLE;
 	siginitset(&blocked, mask);
-	set_current_blocked(&blocked);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-
-	set_restore_sigmask();
-	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index e3e7340..20e5f7b 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -13,6 +13,7 @@
 #include <asm/thread_info.h>	
 #include <asm/segment.h>
 #include <asm/irqflags.h>
+#include <asm/asm.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
 
@@ -146,9 +147,7 @@
  	/* no need to do an access_ok check here because rbp has been
  	   32bit zero extended */ 
 1:	movl	(%rbp),%ebp
- 	.section __ex_table,"a"
- 	.quad 1b,ia32_badarg
- 	.previous	
+	_ASM_EXTABLE(1b,ia32_badarg)
 	orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	CFI_REMEMBER_STATE
@@ -303,9 +302,7 @@
 	   32bit zero extended */ 
 	/* hardware stack frame is complete now */	
 1:	movl	(%r8),%r9d
-	.section __ex_table,"a"
-	.quad 1b,ia32_badarg
-	.previous	
+	_ASM_EXTABLE(1b,ia32_badarg)
 	orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	CFI_REMEMBER_STATE
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index aec2202..4540bec 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -71,8 +71,8 @@
 {
 	typeof(ubuf->st_uid) uid = 0;
 	typeof(ubuf->st_gid) gid = 0;
-	SET_UID(uid, stat->uid);
-	SET_GID(gid, stat->gid);
+	SET_UID(uid, from_kuid_munged(current_user_ns(), stat->uid));
+	SET_GID(gid, from_kgid_munged(current_user_ns(), stat->gid));
 	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
 	    __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
 	    __put_user(stat->ino, &ubuf->__st_ino) ||
@@ -287,11 +287,6 @@
 	return ret;
 }
 
-asmlinkage long sys32_alarm(unsigned int seconds)
-{
-	return alarm_setitimer(seconds);
-}
-
 asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
 			      int options)
 {
@@ -300,11 +295,6 @@
 
 /* 32-bit timeval and related flotsam.  */
 
-asmlinkage long sys32_sysfs(int option, u32 arg1, u32 arg2)
-{
-	return sys_sysfs(option, arg1, arg2);
-}
-
 asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
 				    struct compat_timespec __user *interval)
 {
@@ -375,19 +365,6 @@
 }
 
 
-asmlinkage long sys32_personality(unsigned long personality)
-{
-	int ret;
-
-	if (personality(current->personality) == PER_LINUX32 &&
-		personality == PER_LINUX)
-		personality = PER_LINUX32;
-	ret = sys_personality(personality);
-	if (ret == PER_LINUX32)
-		ret = PER_LINUX;
-	return ret;
-}
-
 asmlinkage long sys32_sendfile(int out_fd, int in_fd,
 			       compat_off_t __user *offset, s32 count)
 {
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index d854101..eaff479 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -138,6 +138,11 @@
 	wrmsr(APIC_BASE_MSR + (reg >> 4), v, 0);
 }
 
+static inline void native_apic_msr_eoi_write(u32 reg, u32 v)
+{
+	wrmsr(APIC_BASE_MSR + (APIC_EOI >> 4), APIC_EOI_ACK, 0);
+}
+
 static inline u32 native_apic_msr_read(u32 reg)
 {
 	u64 msr;
@@ -351,6 +356,14 @@
 	/* apic ops */
 	u32 (*read)(u32 reg);
 	void (*write)(u32 reg, u32 v);
+	/*
+	 * ->eoi_write() has the same signature as ->write().
+	 *
+	 * Drivers can support both ->eoi_write() and ->write() by passing the same
+	 * callback value. Kernel can override ->eoi_write() and fall back
+	 * on write for EOI.
+	 */
+	void (*eoi_write)(u32 reg, u32 v);
 	u64 (*icr_read)(void);
 	void (*icr_write)(u32 low, u32 high);
 	void (*wait_icr_idle)(void);
@@ -426,6 +439,11 @@
 	apic->write(reg, val);
 }
 
+static inline void apic_eoi(void)
+{
+	apic->eoi_write(APIC_EOI, APIC_EOI_ACK);
+}
+
 static inline u64 apic_icr_read(void)
 {
 	return apic->icr_read();
@@ -450,6 +468,7 @@
 
 static inline u32 apic_read(u32 reg) { return 0; }
 static inline void apic_write(u32 reg, u32 val) { }
+static inline void apic_eoi(void) { }
 static inline u64 apic_icr_read(void) { return 0; }
 static inline void apic_icr_write(u32 low, u32 high) { }
 static inline void apic_wait_icr_idle(void) { }
@@ -463,9 +482,7 @@
 	 * ack_APIC_irq() actually gets compiled as a single instruction
 	 * ... yummie.
 	 */
-
-	/* Docs say use 0 for future compatibility */
-	apic_write(APIC_EOI, 0);
+	apic_eoi();
 }
 
 static inline unsigned default_get_apic_id(unsigned long x)
diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h
index 134bba0..c46bb99 100644
--- a/arch/x86/include/asm/apicdef.h
+++ b/arch/x86/include/asm/apicdef.h
@@ -37,7 +37,7 @@
 #define		APIC_ARBPRI_MASK	0xFFu
 #define	APIC_PROCPRI	0xA0
 #define	APIC_EOI	0xB0
-#define		APIC_EIO_ACK		0x0
+#define		APIC_EOI_ACK		0x0 /* Docs say 0 for future compat. */
 #define	APIC_RRR	0xC0
 #define	APIC_LDR	0xD0
 #define		APIC_LDR_MASK		(0xFFu << 24)
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
index 9412d65..1c2d247 100644
--- a/arch/x86/include/asm/asm.h
+++ b/arch/x86/include/asm/asm.h
@@ -4,11 +4,9 @@
 #ifdef __ASSEMBLY__
 # define __ASM_FORM(x)	x
 # define __ASM_FORM_COMMA(x) x,
-# define __ASM_EX_SEC	.section __ex_table, "a"
 #else
 # define __ASM_FORM(x)	" " #x " "
 # define __ASM_FORM_COMMA(x) " " #x ","
-# define __ASM_EX_SEC	" .section __ex_table,\"a\"\n"
 #endif
 
 #ifdef CONFIG_X86_32
@@ -42,17 +40,33 @@
 
 /* Exception table entry */
 #ifdef __ASSEMBLY__
-# define _ASM_EXTABLE(from,to)	    \
-	__ASM_EX_SEC ;		    \
-	_ASM_ALIGN ;		    \
-	_ASM_PTR from , to ;	    \
-	.previous
+# define _ASM_EXTABLE(from,to)					\
+	.pushsection "__ex_table","a" ;				\
+	.balign 8 ;						\
+	.long (from) - . ;					\
+	.long (to) - . ;					\
+	.popsection
+
+# define _ASM_EXTABLE_EX(from,to)				\
+	.pushsection "__ex_table","a" ;				\
+	.balign 8 ;						\
+	.long (from) - . ;					\
+	.long (to) - . + 0x7ffffff0 ;				\
+	.popsection
 #else
-# define _ASM_EXTABLE(from,to) \
-	__ASM_EX_SEC	\
-	_ASM_ALIGN "\n" \
-	_ASM_PTR #from "," #to "\n" \
-	" .previous\n"
+# define _ASM_EXTABLE(from,to)					\
+	" .pushsection \"__ex_table\",\"a\"\n"			\
+	" .balign 8\n"						\
+	" .long (" #from ") - .\n"				\
+	" .long (" #to ") - .\n"				\
+	" .popsection\n"
+
+# define _ASM_EXTABLE_EX(from,to)				\
+	" .pushsection \"__ex_table\",\"a\"\n"			\
+	" .balign 8\n"						\
+	" .long (" #from ") - .\n"				\
+	" .long (" #to ") - . + 0x7ffffff0\n"			\
+	" .popsection\n"
 #endif
 
 #endif /* _ASM_X86_ASM_H */
diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h
index 1981199..b154de7 100644
--- a/arch/x86/include/asm/atomic64_32.h
+++ b/arch/x86/include/asm/atomic64_32.h
@@ -63,7 +63,7 @@
 
 /**
  * atomic64_cmpxchg - cmpxchg atomic64 variable
- * @p: pointer to type atomic64_t
+ * @v: pointer to type atomic64_t
  * @o: expected value
  * @n: new value
  *
@@ -98,7 +98,7 @@
 /**
  * atomic64_set - set atomic64 variable
  * @v: pointer to type atomic64_t
- * @n: value to assign
+ * @i: value to assign
  *
  * Atomically sets the value of @v to @n.
  */
@@ -200,7 +200,7 @@
  * atomic64_sub_and_test - subtract value from variable and test result
  * @i: integer value to subtract
  * @v: pointer to type atomic64_t
-  *
+ *
  * Atomically subtracts @i from @v and returns
  * true if the result is zero, or false for all
  * other cases.
@@ -224,9 +224,9 @@
 
 /**
  * atomic64_dec - decrement atomic64 variable
- * @ptr: pointer to type atomic64_t
+ * @v: pointer to type atomic64_t
  *
- * Atomically decrements @ptr by 1.
+ * Atomically decrements @v by 1.
  */
 static inline void atomic64_dec(atomic64_t *v)
 {
diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h
index 2f90c51..eb45aa6 100644
--- a/arch/x86/include/asm/bootparam.h
+++ b/arch/x86/include/asm/bootparam.h
@@ -112,7 +112,8 @@
 	__u8  e820_entries;				/* 0x1e8 */
 	__u8  eddbuf_entries;				/* 0x1e9 */
 	__u8  edd_mbr_sig_buf_entries;			/* 0x1ea */
-	__u8  _pad6[6];					/* 0x1eb */
+	__u8  kbd_status;				/* 0x1eb */
+	__u8  _pad6[5];					/* 0x1ec */
 	struct setup_header hdr;    /* setup header */	/* 0x1f1 */
 	__u8  _pad7[0x290-0x1f1-sizeof(struct setup_header)];
 	__u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];	/* 0x290 */
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index d680579..fedf32b 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -229,7 +229,7 @@
 		sp = task_pt_regs(current)->sp;
 	} else {
 		/* -128 for the x32 ABI redzone */
-		sp = percpu_read(old_rsp) - 128;
+		sp = this_cpu_read(old_rsp) - 128;
 	}
 
 	return (void __user *)round_down(sp - len, 16);
diff --git a/arch/x86/include/asm/current.h b/arch/x86/include/asm/current.h
index 4d447b7..9476c04 100644
--- a/arch/x86/include/asm/current.h
+++ b/arch/x86/include/asm/current.h
@@ -11,7 +11,7 @@
 
 static __always_inline struct task_struct *get_current(void)
 {
-	return percpu_read_stable(current_task);
+	return this_cpu_read_stable(current_task);
 }
 
 #define current get_current()
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
index e95822d..8bf1c06 100644
--- a/arch/x86/include/asm/desc.h
+++ b/arch/x86/include/asm/desc.h
@@ -6,6 +6,7 @@
 #include <asm/mmu.h>
 
 #include <linux/smp.h>
+#include <linux/percpu.h>
 
 static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *info)
 {
diff --git a/arch/x86/include/asm/device.h b/arch/x86/include/asm/device.h
index 63a2a03..93e1c55 100644
--- a/arch/x86/include/asm/device.h
+++ b/arch/x86/include/asm/device.h
@@ -5,8 +5,8 @@
 #ifdef CONFIG_ACPI
 	void	*acpi_handle;
 #endif
-#ifdef CONFIG_X86_64
-struct dma_map_ops *dma_ops;
+#ifdef CONFIG_X86_DEV_DMA_OPS
+	struct dma_map_ops *dma_ops;
 #endif
 #if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU)
 	void *iommu; /* hook for IOMMU specific extension */
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index 4b4331d..61c0bd2 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -30,7 +30,7 @@
 
 static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
-#ifdef CONFIG_X86_32
+#ifndef CONFIG_X86_DEV_DMA_OPS
 	return dma_ops;
 #else
 	if (unlikely(!dev) || !dev->archdata.dma_ops)
@@ -62,6 +62,12 @@
 					dma_addr_t *dma_addr, gfp_t flag,
 					struct dma_attrs *attrs);
 
+#ifdef CONFIG_X86_DMA_REMAP /* Platform code defines bridge-specific code */
+extern bool dma_capable(struct device *dev, dma_addr_t addr, size_t size);
+extern dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
+extern phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr);
+#else
+
 static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
 {
 	if (!dev->dma_mask)
@@ -79,6 +85,7 @@
 {
 	return daddr;
 }
+#endif /* CONFIG_X86_DMA_REMAP */
 
 static inline void
 dma_cache_sync(struct device *dev, void *vaddr, size_t size,
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index 4fa8815..75f4c6d 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -290,14 +290,14 @@
 static inline void __thread_clear_has_fpu(struct task_struct *tsk)
 {
 	tsk->thread.fpu.has_fpu = 0;
-	percpu_write(fpu_owner_task, NULL);
+	this_cpu_write(fpu_owner_task, NULL);
 }
 
 /* Must be paired with a 'clts' before! */
 static inline void __thread_set_has_fpu(struct task_struct *tsk)
 {
 	tsk->thread.fpu.has_fpu = 1;
-	percpu_write(fpu_owner_task, tsk);
+	this_cpu_write(fpu_owner_task, tsk);
 }
 
 /*
@@ -344,7 +344,7 @@
  */
 static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
 {
-	return new == percpu_read_stable(fpu_owner_task) &&
+	return new == this_cpu_read_stable(fpu_owner_task) &&
 		cpu == new->thread.fpu.last_cpu;
 }
 
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index 268c783..18d9005 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -34,6 +34,7 @@
 
 #ifndef __ASSEMBLY__
 extern void mcount(void);
+extern int modifying_ftrace_code;
 
 static inline unsigned long ftrace_call_adjust(unsigned long addr)
 {
@@ -50,6 +51,8 @@
 	/* No extra data needed for x86 */
 };
 
+int ftrace_int3_handler(struct pt_regs *regs);
+
 #endif /*  CONFIG_DYNAMIC_FTRACE */
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_FUNCTION_TRACER */
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 382f75d..d3895db 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -35,14 +35,15 @@
 
 #define __ARCH_IRQ_STAT
 
-#define inc_irq_stat(member)	percpu_inc(irq_stat.member)
+#define inc_irq_stat(member)	this_cpu_inc(irq_stat.member)
 
-#define local_softirq_pending()	percpu_read(irq_stat.__softirq_pending)
+#define local_softirq_pending()	this_cpu_read(irq_stat.__softirq_pending)
 
 #define __ARCH_SET_SOFTIRQ_PENDING
 
-#define set_softirq_pending(x)	percpu_write(irq_stat.__softirq_pending, (x))
-#define or_softirq_pending(x)	percpu_or(irq_stat.__softirq_pending, (x))
+#define set_softirq_pending(x)	\
+		this_cpu_write(irq_stat.__softirq_pending, (x))
+#define or_softirq_pending(x)	this_cpu_or(irq_stat.__softirq_pending, (x))
 
 extern void ack_bad_irq(unsigned int irq);
 
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 2c4943d..73d8c53 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -5,7 +5,7 @@
 #include <asm/mpspec.h>
 #include <asm/apicdef.h>
 #include <asm/irq_vectors.h>
-
+#include <asm/x86_init.h>
 /*
  * Intel IO-APIC support for SMP and UP systems.
  *
@@ -21,15 +21,6 @@
 #define IO_APIC_REDIR_LEVEL_TRIGGER	(1 << 15)
 #define IO_APIC_REDIR_MASKED		(1 << 16)
 
-struct io_apic_ops {
-	void		(*init)  (void);
-	unsigned int	(*read)  (unsigned int apic, unsigned int reg);
-	void		(*write) (unsigned int apic, unsigned int reg, unsigned int value);
-	void		(*modify)(unsigned int apic, unsigned int reg, unsigned int value);
-};
-
-void __init set_io_apic_ops(const struct io_apic_ops *);
-
 /*
  * The structure of the IO-APIC:
  */
@@ -156,7 +147,6 @@
 extern int io_apic_set_pci_routing(struct device *dev, int irq,
 		 struct io_apic_irq_attr *irq_attr);
 void setup_IO_APIC_irq_extra(u32 gsi);
-extern void ioapic_and_gsi_init(void);
 extern void ioapic_insert_resources(void);
 
 int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr);
@@ -185,12 +175,29 @@
 
 extern void disable_ioapic_support(void);
 
+extern void __init native_io_apic_init_mappings(void);
+extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
+extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val);
+extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
+
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
+{
+	return x86_io_apic_ops.read(apic, reg);
+}
+
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+{
+	x86_io_apic_ops.write(apic, reg, value);
+}
+static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
+{
+	x86_io_apic_ops.modify(apic, reg, value);
+}
 #else  /* !CONFIG_X86_IO_APIC */
 
 #define io_apic_assign_pci_irqs 0
 #define setup_ioapic_ids_from_mpc x86_init_noop
 static const int timer_through_8259 = 0;
-static inline void ioapic_and_gsi_init(void) { }
 static inline void ioapic_insert_resources(void) { }
 #define gsi_top (NR_IRQS_LEGACY)
 static inline int mp_find_ioapic(u32 gsi) { return 0; }
@@ -212,6 +219,10 @@
 
 static inline void mp_save_irq(struct mpc_intsrc *m) { };
 static inline void disable_ioapic_support(void) { }
+#define native_io_apic_init_mappings	NULL
+#define native_io_apic_read		NULL
+#define native_io_apic_write		NULL
+#define native_io_apic_modify		NULL
 #endif
 
 #endif /* _ASM_X86_IO_APIC_H */
diff --git a/arch/x86/include/asm/irq_regs.h b/arch/x86/include/asm/irq_regs.h
index 7784322..d82250b 100644
--- a/arch/x86/include/asm/irq_regs.h
+++ b/arch/x86/include/asm/irq_regs.h
@@ -15,7 +15,7 @@
 
 static inline struct pt_regs *get_irq_regs(void)
 {
-	return percpu_read(irq_regs);
+	return this_cpu_read(irq_regs);
 }
 
 static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
@@ -23,7 +23,7 @@
 	struct pt_regs *old_regs;
 
 	old_regs = get_irq_regs();
-	percpu_write(irq_regs, new_regs);
+	this_cpu_write(irq_regs, new_regs);
 
 	return old_regs;
 }
diff --git a/arch/x86/include/asm/kbdleds.h b/arch/x86/include/asm/kbdleds.h
new file mode 100644
index 0000000..f27ac5f
--- /dev/null
+++ b/arch/x86/include/asm/kbdleds.h
@@ -0,0 +1,17 @@
+#ifndef _ASM_X86_KBDLEDS_H
+#define _ASM_X86_KBDLEDS_H
+
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
+ * This seems a good reason to start with NumLock off. That's why on X86 we
+ * ask the bios for the correct state.
+ */
+
+#include <asm/setup.h>
+
+static inline int kbd_defleds(void)
+{
+	return boot_params.kbd_status & 0x20 ? (1 << VC_NUMLOCK) : 0;
+}
+
+#endif /* _ASM_X86_KBDLEDS_H */
diff --git a/arch/x86/include/asm/kdebug.h b/arch/x86/include/asm/kdebug.h
index d73f157..2c37aad 100644
--- a/arch/x86/include/asm/kdebug.h
+++ b/arch/x86/include/asm/kdebug.h
@@ -24,7 +24,6 @@
 extern void printk_address(unsigned long address, int reliable);
 extern void die(const char *, struct pt_regs *,long);
 extern int __must_check __die(const char *, struct pt_regs *, long);
-extern void show_registers(struct pt_regs *regs);
 extern void show_trace(struct task_struct *t, struct pt_regs *regs,
 		       unsigned long *sp, unsigned long bp);
 extern void __show_regs(struct pt_regs *regs, int all);
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index e216ba0..e5b97be 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -27,6 +27,7 @@
 #include <asm/desc.h>
 #include <asm/mtrr.h>
 #include <asm/msr-index.h>
+#include <asm/asm.h>
 
 #define KVM_MAX_VCPUS 254
 #define KVM_SOFT_MAX_VCPUS 160
@@ -921,9 +922,7 @@
 	__ASM_SIZE(push) " $666b \n\t"	      \
 	"call kvm_spurious_fault \n\t"	      \
 	".popsection \n\t" \
-	".pushsection __ex_table, \"a\" \n\t" \
-	_ASM_PTR " 666b, 667b \n\t" \
-	".popsection"
+	_ASM_EXTABLE(666b, 667b)
 
 #define __kvm_handle_fault_on_reboot(insn)		\
 	____kvm_handle_fault_on_reboot(insn, "")
diff --git a/arch/x86/include/asm/mca.h b/arch/x86/include/asm/mca.h
deleted file mode 100644
index eedbb6c..0000000
--- a/arch/x86/include/asm/mca.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/* Platform specific MCA defines */
-#ifndef _ASM_X86_MCA_H
-#define _ASM_X86_MCA_H
-
-/* Maximal number of MCA slots - actually, some machines have less, but
- * they all have sufficient number of POS registers to cover 8.
- */
-#define MCA_MAX_SLOT_NR  8
-
-/* Most machines have only one MCA bus.  The only multiple bus machines
- * I know have at most two */
-#define MAX_MCA_BUSSES 2
-
-#define MCA_PRIMARY_BUS		0
-#define MCA_SECONDARY_BUS	1
-
-/* Dummy slot numbers on primary MCA for integrated functions */
-#define MCA_INTEGSCSI	(MCA_MAX_SLOT_NR)
-#define MCA_INTEGVIDEO	(MCA_MAX_SLOT_NR+1)
-#define MCA_MOTHERBOARD (MCA_MAX_SLOT_NR+2)
-
-/* Dummy POS values for integrated functions */
-#define MCA_DUMMY_POS_START	0x10000
-#define MCA_INTEGSCSI_POS	(MCA_DUMMY_POS_START+1)
-#define MCA_INTEGVIDEO_POS	(MCA_DUMMY_POS_START+2)
-#define MCA_MOTHERBOARD_POS	(MCA_DUMMY_POS_START+3)
-
-/* MCA registers */
-
-#define MCA_MOTHERBOARD_SETUP_REG	0x94
-#define MCA_ADAPTER_SETUP_REG		0x96
-#define MCA_POS_REG(n)			(0x100+(n))
-
-#define MCA_ENABLED	0x01	/* POS 2, set if adapter enabled */
-
-/* Max number of adapters, including both slots and various integrated
- * things.
- */
-#define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+3)
-
-#endif /* _ASM_X86_MCA_H */
diff --git a/arch/x86/include/asm/mca_dma.h b/arch/x86/include/asm/mca_dma.h
deleted file mode 100644
index 45271ae..0000000
--- a/arch/x86/include/asm/mca_dma.h
+++ /dev/null
@@ -1,201 +0,0 @@
-#ifndef _ASM_X86_MCA_DMA_H
-#define _ASM_X86_MCA_DMA_H
-
-#include <asm/io.h>
-#include <linux/ioport.h>
-
-/*
- * Microchannel specific DMA stuff.  DMA on an MCA machine is fairly similar to
- *   standard PC dma, but it certainly has its quirks.  DMA register addresses
- *   are in a different place and there are some added functions.  Most of this
- *   should be pretty obvious on inspection.  Note that the user must divide
- *   count by 2 when using 16-bit dma; that is not handled by these functions.
- *
- * Ramen Noodles are yummy.
- *
- *  1998 Tymm Twillman <tymm@computer.org>
- */
-
-/*
- * Registers that are used by the DMA controller; FN is the function register
- *   (tell the controller what to do) and EXE is the execution register (how
- *   to do it)
- */
-
-#define MCA_DMA_REG_FN  0x18
-#define MCA_DMA_REG_EXE 0x1A
-
-/*
- * Functions that the DMA controller can do
- */
-
-#define MCA_DMA_FN_SET_IO       0x00
-#define MCA_DMA_FN_SET_ADDR     0x20
-#define MCA_DMA_FN_GET_ADDR     0x30
-#define MCA_DMA_FN_SET_COUNT    0x40
-#define MCA_DMA_FN_GET_COUNT    0x50
-#define MCA_DMA_FN_GET_STATUS   0x60
-#define MCA_DMA_FN_SET_MODE     0x70
-#define MCA_DMA_FN_SET_ARBUS    0x80
-#define MCA_DMA_FN_MASK         0x90
-#define MCA_DMA_FN_RESET_MASK   0xA0
-#define MCA_DMA_FN_MASTER_CLEAR 0xD0
-
-/*
- * Modes (used by setting MCA_DMA_FN_MODE in the function register)
- *
- * Note that the MODE_READ is read from memory (write to device), and
- *   MODE_WRITE is vice-versa.
- */
-
-#define MCA_DMA_MODE_XFER  0x04  /* read by default */
-#define MCA_DMA_MODE_READ  0x04  /* same as XFER */
-#define MCA_DMA_MODE_WRITE 0x08  /* OR with MODE_XFER to use */
-#define MCA_DMA_MODE_IO    0x01  /* DMA from IO register */
-#define MCA_DMA_MODE_16    0x40  /* 16 bit xfers */
-
-
-/**
- *	mca_enable_dma	-	channel to enable DMA on
- *	@dmanr: DMA channel
- *
- *	Enable the MCA bus DMA on a channel. This can be called from
- *	IRQ context.
- */
-
-static inline void mca_enable_dma(unsigned int dmanr)
-{
-	outb(MCA_DMA_FN_RESET_MASK | dmanr, MCA_DMA_REG_FN);
-}
-
-/**
- *	mca_disble_dma	-	channel to disable DMA on
- *	@dmanr: DMA channel
- *
- *	Enable the MCA bus DMA on a channel. This can be called from
- *	IRQ context.
- */
-
-static inline void mca_disable_dma(unsigned int dmanr)
-{
-	outb(MCA_DMA_FN_MASK | dmanr, MCA_DMA_REG_FN);
-}
-
-/**
- *	mca_set_dma_addr -	load a 24bit DMA address
- *	@dmanr: DMA channel
- *	@a: 24bit bus address
- *
- *	Load the address register in the DMA controller. This has a 24bit
- *	limitation (16Mb).
- */
-
-static inline void mca_set_dma_addr(unsigned int dmanr, unsigned int a)
-{
-	outb(MCA_DMA_FN_SET_ADDR | dmanr, MCA_DMA_REG_FN);
-	outb(a & 0xff, MCA_DMA_REG_EXE);
-	outb((a >> 8) & 0xff, MCA_DMA_REG_EXE);
-	outb((a >> 16) & 0xff, MCA_DMA_REG_EXE);
-}
-
-/**
- *	mca_get_dma_addr -	load a 24bit DMA address
- *	@dmanr: DMA channel
- *
- *	Read the address register in the DMA controller. This has a 24bit
- *	limitation (16Mb). The return is a bus address.
- */
-
-static inline unsigned int mca_get_dma_addr(unsigned int dmanr)
-{
-	unsigned int addr;
-
-	outb(MCA_DMA_FN_GET_ADDR | dmanr, MCA_DMA_REG_FN);
-	addr = inb(MCA_DMA_REG_EXE);
-	addr |= inb(MCA_DMA_REG_EXE) << 8;
-	addr |= inb(MCA_DMA_REG_EXE) << 16;
-
-	return addr;
-}
-
-/**
- *	mca_set_dma_count -	load a 16bit transfer count
- *	@dmanr: DMA channel
- *	@count: count
- *
- *	Set the DMA count for this channel. This can be up to 64Kbytes.
- *	Setting a count of zero will not do what you expect.
- */
-
-static inline void mca_set_dma_count(unsigned int dmanr, unsigned int count)
-{
-	count--;  /* transfers one more than count -- correct for this */
-
-	outb(MCA_DMA_FN_SET_COUNT | dmanr, MCA_DMA_REG_FN);
-	outb(count & 0xff, MCA_DMA_REG_EXE);
-	outb((count >> 8) & 0xff, MCA_DMA_REG_EXE);
-}
-
-/**
- *	mca_get_dma_residue -	get the remaining bytes to transfer
- *	@dmanr: DMA channel
- *
- *	This function returns the number of bytes left to transfer
- *	on this DMA channel.
- */
-
-static inline unsigned int mca_get_dma_residue(unsigned int dmanr)
-{
-	unsigned short count;
-
-	outb(MCA_DMA_FN_GET_COUNT | dmanr, MCA_DMA_REG_FN);
-	count = 1 + inb(MCA_DMA_REG_EXE);
-	count += inb(MCA_DMA_REG_EXE) << 8;
-
-	return count;
-}
-
-/**
- *	mca_set_dma_io -	set the port for an I/O transfer
- *	@dmanr: DMA channel
- *	@io_addr: an I/O port number
- *
- *	Unlike the ISA bus DMA controllers the DMA on MCA bus can transfer
- *	with an I/O port target.
- */
-
-static inline void mca_set_dma_io(unsigned int dmanr, unsigned int io_addr)
-{
-	/*
-	 * DMA from a port address -- set the io address
-	 */
-
-	outb(MCA_DMA_FN_SET_IO | dmanr, MCA_DMA_REG_FN);
-	outb(io_addr & 0xff, MCA_DMA_REG_EXE);
-	outb((io_addr >>  8) & 0xff, MCA_DMA_REG_EXE);
-}
-
-/**
- *	mca_set_dma_mode -	set the DMA mode
- *	@dmanr: DMA channel
- *	@mode: mode to set
- *
- *	The DMA controller supports several modes. The mode values you can
- *	set are-
- *
- *	%MCA_DMA_MODE_READ when reading from the DMA device.
- *
- *	%MCA_DMA_MODE_WRITE to writing to the DMA device.
- *
- *	%MCA_DMA_MODE_IO to do DMA to or from an I/O port.
- *
- *	%MCA_DMA_MODE_16 to do 16bit transfers.
- */
-
-static inline void mca_set_dma_mode(unsigned int dmanr, unsigned int mode)
-{
-	outb(MCA_DMA_FN_SET_MODE | dmanr, MCA_DMA_REG_FN);
-	outb(mode, MCA_DMA_REG_EXE);
-}
-
-#endif /* _ASM_X86_MCA_DMA_H */
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 6902152..cdbf367 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -25,8 +25,8 @@
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
 #ifdef CONFIG_SMP
-	if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
-		percpu_write(cpu_tlbstate.state, TLBSTATE_LAZY);
+	if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
+		this_cpu_write(cpu_tlbstate.state, TLBSTATE_LAZY);
 #endif
 }
 
@@ -37,8 +37,8 @@
 
 	if (likely(prev != next)) {
 #ifdef CONFIG_SMP
-		percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
-		percpu_write(cpu_tlbstate.active_mm, next);
+		this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK);
+		this_cpu_write(cpu_tlbstate.active_mm, next);
 #endif
 		cpumask_set_cpu(cpu, mm_cpumask(next));
 
@@ -56,8 +56,8 @@
 	}
 #ifdef CONFIG_SMP
 	else {
-		percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
-		BUG_ON(percpu_read(cpu_tlbstate.active_mm) != next);
+		this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK);
+		BUG_ON(this_cpu_read(cpu_tlbstate.active_mm) != next);
 
 		if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))) {
 			/* We were in lazy tlb mode and leave_mm disabled
diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h
index 55728e1..eb05fb3 100644
--- a/arch/x86/include/asm/mmzone_32.h
+++ b/arch/x86/include/asm/mmzone_32.h
@@ -61,10 +61,4 @@
 
 #endif /* CONFIG_DISCONTIGMEM */
 
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-/* always use node 0 for bootmem on this numa platform */
-#define bootmem_arch_preferred_node(__bdata, size, align, goal, limit)	\
-	(NODE_DATA(0)->bdata)
-#endif /* CONFIG_NEED_MULTIPLE_NODES */
-
 #endif /* _ASM_X86_MMZONE_32_H */
diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h
index 9c7d95f..3e2f42a 100644
--- a/arch/x86/include/asm/mpspec.h
+++ b/arch/x86/include/asm/mpspec.h
@@ -40,7 +40,7 @@
 
 #endif /* CONFIG_X86_64 */
 
-#if defined(CONFIG_MCA) || defined(CONFIG_EISA)
+#ifdef CONFIG_EISA
 extern int mp_bus_id_to_type[MAX_MP_BUSSES];
 #endif
 
diff --git a/arch/x86/include/asm/mpspec_def.h b/arch/x86/include/asm/mpspec_def.h
index c0a955a..b31f8c0 100644
--- a/arch/x86/include/asm/mpspec_def.h
+++ b/arch/x86/include/asm/mpspec_def.h
@@ -84,7 +84,7 @@
 #define BUSTYPE_EISA	"EISA"
 #define BUSTYPE_ISA	"ISA"
 #define BUSTYPE_INTERN	"INTERN"	/* Internal BUS */
-#define BUSTYPE_MCA	"MCA"
+#define BUSTYPE_MCA	"MCA"		/* Obsolete */
 #define BUSTYPE_VL	"VL"		/* Local bus */
 #define BUSTYPE_PCI	"PCI"
 #define BUSTYPE_PCMCIA	"PCMCIA"
@@ -169,6 +169,5 @@
 	MP_BUS_ISA = 1,
 	MP_BUS_EISA,
 	MP_BUS_PCI,
-	MP_BUS_MCA,
 };
 #endif /* _ASM_X86_MPSPEC_DEF_H */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index ccb8059..957ec87 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -134,6 +134,8 @@
 #define MSR_AMD64_IBSFETCHCTL		0xc0011030
 #define MSR_AMD64_IBSFETCHLINAD		0xc0011031
 #define MSR_AMD64_IBSFETCHPHYSAD	0xc0011032
+#define MSR_AMD64_IBSFETCH_REG_COUNT	3
+#define MSR_AMD64_IBSFETCH_REG_MASK	((1UL<<MSR_AMD64_IBSFETCH_REG_COUNT)-1)
 #define MSR_AMD64_IBSOPCTL		0xc0011033
 #define MSR_AMD64_IBSOPRIP		0xc0011034
 #define MSR_AMD64_IBSOPDATA		0xc0011035
@@ -141,8 +143,11 @@
 #define MSR_AMD64_IBSOPDATA3		0xc0011037
 #define MSR_AMD64_IBSDCLINAD		0xc0011038
 #define MSR_AMD64_IBSDCPHYSAD		0xc0011039
+#define MSR_AMD64_IBSOP_REG_COUNT	7
+#define MSR_AMD64_IBSOP_REG_MASK	((1UL<<MSR_AMD64_IBSOP_REG_COUNT)-1)
 #define MSR_AMD64_IBSCTL		0xc001103a
 #define MSR_AMD64_IBSBRTARGET		0xc001103b
+#define MSR_AMD64_IBS_REG_COUNT_MAX	8 /* includes MSR_AMD64_IBSBRTARGET */
 
 /* Fam 15h MSRs */
 #define MSR_F15H_PERF_CTL		0xc0010200
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 95203d4..084ef95 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -169,14 +169,7 @@
 	return native_write_msr_safe(msr, low, high);
 }
 
-/*
- * rdmsr with exception handling.
- *
- * Please note that the exception handling works only after we've
- * switched to the "smart" #GP handler in trap_init() which knows about
- * exception tables - using this macro earlier than that causes machine
- * hangs on boxes which do not implement the @msr in the first argument.
- */
+/* rdmsr with exception handling */
 #define rdmsr_safe(msr, p1, p2)					\
 ({								\
 	int __err;						\
diff --git a/arch/x86/include/asm/nops.h b/arch/x86/include/asm/nops.h
index 405b4032..aff2b33 100644
--- a/arch/x86/include/asm/nops.h
+++ b/arch/x86/include/asm/nops.h
@@ -87,7 +87,11 @@
 #define P6_NOP8	0x0f,0x1f,0x84,0x00,0,0,0,0
 #define P6_NOP5_ATOMIC P6_NOP5
 
+#ifdef __ASSEMBLY__
+#define _ASM_MK_NOP(x) .byte x
+#else
 #define _ASM_MK_NOP(x) ".byte " __stringify(x) "\n"
+#endif
 
 #if defined(CONFIG_MK7)
 #define ASM_NOP1 _ASM_MK_NOP(K7_NOP1)
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index aa0f913..6cbbabf 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -1023,10 +1023,8 @@
 		  call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs)		\
 		 )
 
-#define GET_CR2_INTO_RCX				\
-	call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2);	\
-	movq %rax, %rcx;				\
-	xorq %rax, %rax;
+#define GET_CR2_INTO_RAX				\
+	call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2)
 
 #define PARAVIRT_ADJUST_EXCEPTION_FRAME					\
 	PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_adjust_exception_frame), \
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index 7a11910..d9b8e3f 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -46,7 +46,7 @@
 
 #ifdef CONFIG_SMP
 #define __percpu_prefix		"%%"__stringify(__percpu_seg)":"
-#define __my_cpu_offset		percpu_read(this_cpu_off)
+#define __my_cpu_offset		this_cpu_read(this_cpu_off)
 
 /*
  * Compared to the generic __my_cpu_offset version, the following
@@ -351,23 +351,15 @@
 })
 
 /*
- * percpu_read() makes gcc load the percpu variable every time it is
- * accessed while percpu_read_stable() allows the value to be cached.
- * percpu_read_stable() is more efficient and can be used if its value
+ * this_cpu_read() makes gcc load the percpu variable every time it is
+ * accessed while this_cpu_read_stable() allows the value to be cached.
+ * this_cpu_read_stable() is more efficient and can be used if its value
  * is guaranteed to be valid across cpus.  The current users include
  * get_current() and get_thread_info() both of which are actually
  * per-thread variables implemented as per-cpu variables and thus
  * stable for the duration of the respective task.
  */
-#define percpu_read(var)		percpu_from_op("mov", var, "m" (var))
-#define percpu_read_stable(var)		percpu_from_op("mov", var, "p" (&(var)))
-#define percpu_write(var, val)		percpu_to_op("mov", var, val)
-#define percpu_add(var, val)		percpu_add_op(var, val)
-#define percpu_sub(var, val)		percpu_add_op(var, -(val))
-#define percpu_and(var, val)		percpu_to_op("and", var, val)
-#define percpu_or(var, val)		percpu_to_op("or", var, val)
-#define percpu_xor(var, val)		percpu_to_op("xor", var, val)
-#define percpu_inc(var)		percpu_unary_op("inc", var)
+#define this_cpu_read_stable(var)	percpu_from_op("mov", var, "p" (&(var)))
 
 #define __this_cpu_read_1(pcp)		percpu_from_op("mov", (pcp), "m"(pcp))
 #define __this_cpu_read_2(pcp)		percpu_from_op("mov", (pcp), "m"(pcp))
@@ -512,7 +504,11 @@
 {
 	unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG;
 
-	return ((1UL << (nr % BITS_PER_LONG)) & percpu_read(*a)) != 0;
+#ifdef CONFIG_X86_64
+	return ((1UL << (nr % BITS_PER_LONG)) & __this_cpu_read_8(*a)) != 0;
+#else
+	return ((1UL << (nr % BITS_PER_LONG)) & __this_cpu_read_4(*a)) != 0;
+#endif
 }
 
 static inline int x86_this_cpu_variable_test_bit(int nr,
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 2291895..588f52e 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -158,6 +158,7 @@
 #define IBS_CAPS_OPCNT			(1U<<4)
 #define IBS_CAPS_BRNTRGT		(1U<<5)
 #define IBS_CAPS_OPCNTEXT		(1U<<6)
+#define IBS_CAPS_RIPINVALIDCHK		(1U<<7)
 
 #define IBS_CAPS_DEFAULT		(IBS_CAPS_AVAIL		\
 					 | IBS_CAPS_FETCHSAM	\
@@ -170,21 +171,28 @@
 #define IBSCTL_LVT_OFFSET_VALID		(1ULL<<8)
 #define IBSCTL_LVT_OFFSET_MASK		0x0F
 
-/* IbsFetchCtl bits/masks */
+/* ibs fetch bits/masks */
 #define IBS_FETCH_RAND_EN	(1ULL<<57)
 #define IBS_FETCH_VAL		(1ULL<<49)
 #define IBS_FETCH_ENABLE	(1ULL<<48)
 #define IBS_FETCH_CNT		0xFFFF0000ULL
 #define IBS_FETCH_MAX_CNT	0x0000FFFFULL
 
-/* IbsOpCtl bits */
+/* ibs op bits/masks */
+/* lower 4 bits of the current count are ignored: */
+#define IBS_OP_CUR_CNT		(0xFFFF0ULL<<32)
 #define IBS_OP_CNT_CTL		(1ULL<<19)
 #define IBS_OP_VAL		(1ULL<<18)
 #define IBS_OP_ENABLE		(1ULL<<17)
 #define IBS_OP_MAX_CNT		0x0000FFFFULL
 #define IBS_OP_MAX_CNT_EXT	0x007FFFFFULL	/* not a register bit mask */
+#define IBS_RIP_INVALID		(1ULL<<38)
 
+#ifdef CONFIG_X86_LOCAL_APIC
 extern u32 get_ibs_caps(void);
+#else
+static inline u32 get_ibs_caps(void) { return 0; }
+#endif
 
 #ifdef CONFIG_PERF_EVENTS
 extern void perf_events_lapic_init(void);
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index ccbb1ea..7745b257 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -579,9 +579,6 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy state */
-extern void prepare_to_copy(struct task_struct *tsk);
-
 unsigned long get_wchan(struct task_struct *p);
 
 /*
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
index 1654662..c48a950 100644
--- a/arch/x86/include/asm/segment.h
+++ b/arch/x86/include/asm/segment.h
@@ -205,13 +205,15 @@
 
 #define IDT_ENTRIES 256
 #define NUM_EXCEPTION_VECTORS 32
+/* Bitmask of exception vectors which push an error code on the stack */
+#define EXCEPTION_ERRCODE_MASK  0x00027d00
 #define GDT_SIZE (GDT_ENTRIES * 8)
 #define GDT_ENTRY_TLS_ENTRIES 3
 #define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
-extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][10];
+extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5];
 
 /*
  * Load a segment. Fall back on loading the zero
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index f8cbc6f..f483945 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -191,11 +191,11 @@
  * from the initial startup. We map APIC_BASE very early in page_setup(),
  * so this is correct in the x86 case.
  */
-#define raw_smp_processor_id() (percpu_read(cpu_number))
+#define raw_smp_processor_id() (this_cpu_read(cpu_number))
 extern int safe_smp_processor_id(void);
 
 #elif defined(CONFIG_X86_64_SMP)
-#define raw_smp_processor_id() (percpu_read(cpu_number))
+#define raw_smp_processor_id() (this_cpu_read(cpu_number))
 
 #define stack_smp_processor_id()					\
 ({								\
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 76bfa2c..b315a33 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -20,10 +20,8 @@
 
 #ifdef CONFIG_X86_32
 # define LOCK_PTR_REG "a"
-# define REG_PTR_MODE "k"
 #else
 # define LOCK_PTR_REG "D"
-# define REG_PTR_MODE "q"
 #endif
 
 #if defined(CONFIG_X86_32) && \
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h
index b5d9533..6a99859 100644
--- a/arch/x86/include/asm/stackprotector.h
+++ b/arch/x86/include/asm/stackprotector.h
@@ -75,9 +75,9 @@
 
 	current->stack_canary = canary;
 #ifdef CONFIG_X86_64
-	percpu_write(irq_stack_union.stack_canary, canary);
+	this_cpu_write(irq_stack_union.stack_canary, canary);
 #else
-	percpu_write(stack_canary.canary, canary);
+	this_cpu_write(stack_canary.canary, canary);
 #endif
 }
 
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 73cfe0d..5c25de0 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -85,6 +85,7 @@
 #define TIF_SECCOMP		8	/* secure computing */
 #define TIF_MCE_NOTIFY		10	/* notify userspace of an MCE */
 #define TIF_USER_RETURN_NOTIFY	11	/* notify kernel of userspace return */
+#define TIF_UPROBE		12	/* breakpointed or singlestepping */
 #define TIF_NOTSC		16	/* TSC is not accessible in userland */
 #define TIF_IA32		17	/* IA32 compatibility process */
 #define TIF_FORK		18	/* ret_from_fork */
@@ -109,6 +110,7 @@
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
 #define _TIF_MCE_NOTIFY		(1 << TIF_MCE_NOTIFY)
 #define _TIF_USER_RETURN_NOTIFY	(1 << TIF_USER_RETURN_NOTIFY)
+#define _TIF_UPROBE		(1 << TIF_UPROBE)
 #define _TIF_NOTSC		(1 << TIF_NOTSC)
 #define _TIF_IA32		(1 << TIF_IA32)
 #define _TIF_FORK		(1 << TIF_FORK)
@@ -204,7 +206,7 @@
 static inline struct thread_info *current_thread_info(void)
 {
 	struct thread_info *ti;
-	ti = (void *)(percpu_read_stable(kernel_stack) +
+	ti = (void *)(this_cpu_read_stable(kernel_stack) +
 		      KERNEL_STACK_OFFSET - THREAD_SIZE);
 	return ti;
 }
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index c0e108e..36a1a2a 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -62,11 +62,7 @@
 		__flush_tlb();
 }
 
-#ifdef CONFIG_X86_32
-# define TLB_FLUSH_ALL	0xffffffff
-#else
-# define TLB_FLUSH_ALL	-1ULL
-#endif
+#define TLB_FLUSH_ALL	-1UL
 
 /*
  * TLB flushing:
@@ -156,8 +152,8 @@
 
 static inline void reset_lazy_tlbstate(void)
 {
-	percpu_write(cpu_tlbstate.state, 0);
-	percpu_write(cpu_tlbstate.active_mm, &init_mm);
+	this_cpu_write(cpu_tlbstate.state, 0);
+	this_cpu_write(cpu_tlbstate.active_mm, &init_mm);
 }
 
 #endif	/* SMP */
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index b9676ae..095b215 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -92,44 +92,6 @@
 
 #define pcibus_to_node(bus) __pcibus_to_node(bus)
 
-#ifdef CONFIG_X86_32
-# define SD_CACHE_NICE_TRIES	1
-# define SD_IDLE_IDX		1
-#else
-# define SD_CACHE_NICE_TRIES	2
-# define SD_IDLE_IDX		2
-#endif
-
-/* sched_domains SD_NODE_INIT for NUMA machines */
-#define SD_NODE_INIT (struct sched_domain) {				\
-	.min_interval		= 8,					\
-	.max_interval		= 32,					\
-	.busy_factor		= 32,					\
-	.imbalance_pct		= 125,					\
-	.cache_nice_tries	= SD_CACHE_NICE_TRIES,			\
-	.busy_idx		= 3,					\
-	.idle_idx		= SD_IDLE_IDX,				\
-	.newidle_idx		= 0,					\
-	.wake_idx		= 0,					\
-	.forkexec_idx		= 0,					\
-									\
-	.flags			= 1*SD_LOAD_BALANCE			\
-				| 1*SD_BALANCE_NEWIDLE			\
-				| 1*SD_BALANCE_EXEC			\
-				| 1*SD_BALANCE_FORK			\
-				| 0*SD_BALANCE_WAKE			\
-				| 1*SD_WAKE_AFFINE			\
-				| 0*SD_PREFER_LOCAL			\
-				| 0*SD_SHARE_CPUPOWER			\
-				| 0*SD_POWERSAVINGS_BALANCE		\
-				| 0*SD_SHARE_PKG_RESOURCES		\
-				| 1*SD_SERIALIZE			\
-				| 0*SD_PREFER_SIBLING			\
-				,					\
-	.last_balance		= jiffies,				\
-	.balance_interval	= 1,					\
-}
-
 extern int __node_distance(int, int);
 #define node_distance(a, b) __node_distance(a, b)
 
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index e054459..851fe0d 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -79,11 +79,12 @@
 #define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
 
 /*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
+ * The exception table consists of pairs of addresses relative to the
+ * exception table enty itself: the first is the address of an
+ * instruction that is allowed to fault, and the second is the address
+ * at which the program should continue.  No registers are modified,
+ * so it is entirely up to the continuation code to figure out what to
+ * do.
  *
  * All the routines below use bits of fixup code that are out of line
  * with the main instruction path.  This means when everything is well,
@@ -92,10 +93,14 @@
  */
 
 struct exception_table_entry {
-	unsigned long insn, fixup;
+	int insn, fixup;
 };
+/* This is not the generic standard exception_table_entry format */
+#define ARCH_HAS_SORT_EXTABLE
+#define ARCH_HAS_SEARCH_EXTABLE
 
 extern int fixup_exception(struct pt_regs *regs);
+extern int early_fixup_exception(unsigned long *ip);
 
 /*
  * These are the main single-value transfer routines.  They automatically
@@ -202,8 +207,8 @@
 	asm volatile("1:	movl %%eax,0(%1)\n"			\
 		     "2:	movl %%edx,4(%1)\n"			\
 		     "3:\n"						\
-		     _ASM_EXTABLE(1b, 2b - 1b)				\
-		     _ASM_EXTABLE(2b, 3b - 2b)				\
+		     _ASM_EXTABLE_EX(1b, 2b)				\
+		     _ASM_EXTABLE_EX(2b, 3b)				\
 		     : : "A" (x), "r" (addr))
 
 #define __put_user_x8(x, ptr, __ret_pu)				\
@@ -408,7 +413,7 @@
 #define __get_user_asm_ex(x, addr, itype, rtype, ltype)			\
 	asm volatile("1:	mov"itype" %1,%"rtype"0\n"		\
 		     "2:\n"						\
-		     _ASM_EXTABLE(1b, 2b - 1b)				\
+		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : ltype(x) : "m" (__m(addr)))
 
 #define __put_user_nocheck(x, ptr, size)			\
@@ -450,7 +455,7 @@
 #define __put_user_asm_ex(x, addr, itype, rtype, ltype)			\
 	asm volatile("1:	mov"itype" %"rtype"0,%1\n"		\
 		     "2:\n"						\
-		     _ASM_EXTABLE(1b, 2b - 1b)				\
+		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : : ltype(x), "m" (__m(addr)))
 
 /*
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
new file mode 100644
index 0000000..1e9bed1
--- /dev/null
+++ b/arch/x86/include/asm/uprobes.h
@@ -0,0 +1,57 @@
+#ifndef _ASM_UPROBES_H
+#define _ASM_UPROBES_H
+/*
+ * User-space Probes (UProbes) for x86
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2008-2011
+ * Authors:
+ *	Srikar Dronamraju
+ *	Jim Keniston
+ */
+
+#include <linux/notifier.h>
+
+typedef u8 uprobe_opcode_t;
+
+#define MAX_UINSN_BYTES			  16
+#define UPROBE_XOL_SLOT_BYTES		 128	/* to keep it cache aligned */
+
+#define UPROBE_SWBP_INSN		0xcc
+#define UPROBE_SWBP_INSN_SIZE		   1
+
+struct arch_uprobe {
+	u16				fixups;
+	u8				insn[MAX_UINSN_BYTES];
+#ifdef CONFIG_X86_64
+	unsigned long			rip_rela_target_address;
+#endif
+};
+
+struct arch_uprobe_task {
+	unsigned long			saved_trap_nr;
+#ifdef CONFIG_X86_64
+	unsigned long			saved_scratch_register;
+#endif
+};
+
+extern int  arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm);
+extern int  arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+extern int  arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
+extern int  arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
+extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+#endif	/* _ASM_UPROBES_H */
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 764b66a..c090af1 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -188,11 +188,18 @@
 	void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
 };
 
+struct x86_io_apic_ops {
+	void		(*init)  (void);
+	unsigned int	(*read)  (unsigned int apic, unsigned int reg);
+	void		(*write) (unsigned int apic, unsigned int reg, unsigned int value);
+	void		(*modify)(unsigned int apic, unsigned int reg, unsigned int value);
+};
+
 extern struct x86_init_ops x86_init;
 extern struct x86_cpuinit_ops x86_cpuinit;
 extern struct x86_platform_ops x86_platform;
 extern struct x86_msi_ops x86_msi;
-
+extern struct x86_io_apic_ops x86_io_apic_ops;
 extern void x86_init_noop(void);
 extern void x86_init_uint_noop(unsigned int unused);
 
diff --git a/arch/x86/include/asm/xor_32.h b/arch/x86/include/asm/xor_32.h
index 133b40a..4545708 100644
--- a/arch/x86/include/asm/xor_32.h
+++ b/arch/x86/include/asm/xor_32.h
@@ -861,6 +861,9 @@
 	.do_5 = xor_sse_5,
 };
 
+/* Also try the AVX routines */
+#include "xor_avx.h"
+
 /* Also try the generic routines.  */
 #include <asm-generic/xor.h>
 
@@ -871,6 +874,7 @@
 	xor_speed(&xor_block_8regs_p);			\
 	xor_speed(&xor_block_32regs);			\
 	xor_speed(&xor_block_32regs_p);			\
+	AVX_XOR_SPEED;					\
 	if (cpu_has_xmm)				\
 		xor_speed(&xor_block_pIII_sse);		\
 	if (cpu_has_mmx) {				\
@@ -883,6 +887,6 @@
    We may also be able to load into the L1 only depending on how the cpu
    deals with a load to a line that is being prefetched.  */
 #define XOR_SELECT_TEMPLATE(FASTEST)			\
-	(cpu_has_xmm ? &xor_block_pIII_sse : FASTEST)
+	AVX_SELECT(cpu_has_xmm ? &xor_block_pIII_sse : FASTEST)
 
 #endif /* _ASM_X86_XOR_32_H */
diff --git a/arch/x86/include/asm/xor_64.h b/arch/x86/include/asm/xor_64.h
index 1549b5e..b9b2323 100644
--- a/arch/x86/include/asm/xor_64.h
+++ b/arch/x86/include/asm/xor_64.h
@@ -347,15 +347,21 @@
 	.do_5 = xor_sse_5,
 };
 
+
+/* Also try the AVX routines */
+#include "xor_avx.h"
+
 #undef XOR_TRY_TEMPLATES
 #define XOR_TRY_TEMPLATES			\
 do {						\
+	AVX_XOR_SPEED;				\
 	xor_speed(&xor_block_sse);		\
 } while (0)
 
 /* We force the use of the SSE xor block because it can write around L2.
    We may also be able to load into the L1 only depending on how the cpu
    deals with a load to a line that is being prefetched.  */
-#define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_sse)
+#define XOR_SELECT_TEMPLATE(FASTEST) \
+	AVX_SELECT(&xor_block_sse)
 
 #endif /* _ASM_X86_XOR_64_H */
diff --git a/arch/x86/include/asm/xor_avx.h b/arch/x86/include/asm/xor_avx.h
new file mode 100644
index 0000000..2510d35
--- /dev/null
+++ b/arch/x86/include/asm/xor_avx.h
@@ -0,0 +1,214 @@
+#ifndef _ASM_X86_XOR_AVX_H
+#define _ASM_X86_XOR_AVX_H
+
+/*
+ * Optimized RAID-5 checksumming functions for AVX
+ *
+ * Copyright (C) 2012 Intel Corporation
+ * Author: Jim Kukunas <james.t.kukunas@linux.intel.com>
+ *
+ * Based on Ingo Molnar and Zach Brown's respective MMX and SSE routines
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifdef CONFIG_AS_AVX
+
+#include <linux/compiler.h>
+#include <asm/i387.h>
+
+#define ALIGN32 __aligned(32)
+
+#define YMM_SAVED_REGS 4
+
+#define YMMS_SAVE \
+do { \
+	preempt_disable(); \
+	cr0 = read_cr0(); \
+	clts(); \
+	asm volatile("vmovaps %%ymm0, %0" : "=m" (ymm_save[0]) : : "memory"); \
+	asm volatile("vmovaps %%ymm1, %0" : "=m" (ymm_save[32]) : : "memory"); \
+	asm volatile("vmovaps %%ymm2, %0" : "=m" (ymm_save[64]) : : "memory"); \
+	asm volatile("vmovaps %%ymm3, %0" : "=m" (ymm_save[96]) : : "memory"); \
+} while (0);
+
+#define YMMS_RESTORE \
+do { \
+	asm volatile("sfence" : : : "memory"); \
+	asm volatile("vmovaps %0, %%ymm3" : : "m" (ymm_save[96])); \
+	asm volatile("vmovaps %0, %%ymm2" : : "m" (ymm_save[64])); \
+	asm volatile("vmovaps %0, %%ymm1" : : "m" (ymm_save[32])); \
+	asm volatile("vmovaps %0, %%ymm0" : : "m" (ymm_save[0])); \
+	write_cr0(cr0); \
+	preempt_enable(); \
+} while (0);
+
+#define BLOCK4(i) \
+		BLOCK(32 * i, 0) \
+		BLOCK(32 * (i + 1), 1) \
+		BLOCK(32 * (i + 2), 2) \
+		BLOCK(32 * (i + 3), 3)
+
+#define BLOCK16() \
+		BLOCK4(0) \
+		BLOCK4(4) \
+		BLOCK4(8) \
+		BLOCK4(12)
+
+static void xor_avx_2(unsigned long bytes, unsigned long *p0, unsigned long *p1)
+{
+	unsigned long cr0, lines = bytes >> 9;
+	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+
+	YMMS_SAVE
+
+	while (lines--) {
+#undef BLOCK
+#define BLOCK(i, reg) \
+do { \
+	asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p1[i / sizeof(*p1)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm"  #reg : : \
+		"m" (p0[i / sizeof(*p0)])); \
+	asm volatile("vmovdqa %%ymm" #reg ", %0" : \
+		"=m" (p0[i / sizeof(*p0)])); \
+} while (0);
+
+		BLOCK16()
+
+		p0 = (unsigned long *)((uintptr_t)p0 + 512);
+		p1 = (unsigned long *)((uintptr_t)p1 + 512);
+	}
+
+	YMMS_RESTORE
+}
+
+static void xor_avx_3(unsigned long bytes, unsigned long *p0, unsigned long *p1,
+	unsigned long *p2)
+{
+	unsigned long cr0, lines = bytes >> 9;
+	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+
+	YMMS_SAVE
+
+	while (lines--) {
+#undef BLOCK
+#define BLOCK(i, reg) \
+do { \
+	asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p2[i / sizeof(*p2)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+		"m" (p1[i / sizeof(*p1)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+		"m" (p0[i / sizeof(*p0)])); \
+	asm volatile("vmovdqa %%ymm" #reg ", %0" : \
+		"=m" (p0[i / sizeof(*p0)])); \
+} while (0);
+
+		BLOCK16()
+
+		p0 = (unsigned long *)((uintptr_t)p0 + 512);
+		p1 = (unsigned long *)((uintptr_t)p1 + 512);
+		p2 = (unsigned long *)((uintptr_t)p2 + 512);
+	}
+
+	YMMS_RESTORE
+}
+
+static void xor_avx_4(unsigned long bytes, unsigned long *p0, unsigned long *p1,
+	unsigned long *p2, unsigned long *p3)
+{
+	unsigned long cr0, lines = bytes >> 9;
+	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+
+	YMMS_SAVE
+
+	while (lines--) {
+#undef BLOCK
+#define BLOCK(i, reg) \
+do { \
+	asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p3[i / sizeof(*p3)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+		"m" (p2[i / sizeof(*p2)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+		"m" (p1[i / sizeof(*p1)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+		"m" (p0[i / sizeof(*p0)])); \
+	asm volatile("vmovdqa %%ymm" #reg ", %0" : \
+		"=m" (p0[i / sizeof(*p0)])); \
+} while (0);
+
+		BLOCK16();
+
+		p0 = (unsigned long *)((uintptr_t)p0 + 512);
+		p1 = (unsigned long *)((uintptr_t)p1 + 512);
+		p2 = (unsigned long *)((uintptr_t)p2 + 512);
+		p3 = (unsigned long *)((uintptr_t)p3 + 512);
+	}
+
+	YMMS_RESTORE
+}
+
+static void xor_avx_5(unsigned long bytes, unsigned long *p0, unsigned long *p1,
+	unsigned long *p2, unsigned long *p3, unsigned long *p4)
+{
+	unsigned long cr0, lines = bytes >> 9;
+	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+
+	YMMS_SAVE
+
+	while (lines--) {
+#undef BLOCK
+#define BLOCK(i, reg) \
+do { \
+	asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p4[i / sizeof(*p4)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+		"m" (p3[i / sizeof(*p3)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+		"m" (p2[i / sizeof(*p2)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+		"m" (p1[i / sizeof(*p1)])); \
+	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+		"m" (p0[i / sizeof(*p0)])); \
+	asm volatile("vmovdqa %%ymm" #reg ", %0" : \
+		"=m" (p0[i / sizeof(*p0)])); \
+} while (0);
+
+		BLOCK16()
+
+		p0 = (unsigned long *)((uintptr_t)p0 + 512);
+		p1 = (unsigned long *)((uintptr_t)p1 + 512);
+		p2 = (unsigned long *)((uintptr_t)p2 + 512);
+		p3 = (unsigned long *)((uintptr_t)p3 + 512);
+		p4 = (unsigned long *)((uintptr_t)p4 + 512);
+	}
+
+	YMMS_RESTORE
+}
+
+static struct xor_block_template xor_block_avx = {
+	.name = "avx",
+	.do_2 = xor_avx_2,
+	.do_3 = xor_avx_3,
+	.do_4 = xor_avx_4,
+	.do_5 = xor_avx_5,
+};
+
+#define AVX_XOR_SPEED \
+do { \
+	if (cpu_has_avx) \
+		xor_speed(&xor_block_avx); \
+} while (0)
+
+#define AVX_SELECT(FASTEST) \
+	(cpu_has_avx ? &xor_block_avx : FASTEST)
+
+#else
+
+#define AVX_XOR_SPEED {}
+
+#define AVX_SELECT(FASTEST) (FASTEST)
+
+#endif
+#endif
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index c6ce245..8a1b6f9 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -80,10 +80,7 @@
 			     "3:  movl $-1,%[err]\n"
 			     "    jmp  2b\n"
 			     ".previous\n"
-			     ".section __ex_table,\"a\"\n"
-			     _ASM_ALIGN "\n"
-			     _ASM_PTR "1b,3b\n"
-			     ".previous"
+			     _ASM_EXTABLE(1b,3b)
 			     : [err] "=r" (err)
 			     : "D" (buf), "a" (-1), "d" (-1), "0" (0)
 			     : "memory");
@@ -106,10 +103,7 @@
 			     "3:  movl $-1,%[err]\n"
 			     "    jmp  2b\n"
 			     ".previous\n"
-			     ".section __ex_table,\"a\"\n"
-			     _ASM_ALIGN "\n"
-			     _ASM_PTR "1b,3b\n"
-			     ".previous"
+			     _ASM_EXTABLE(1b,3b)
 			     : [err] "=r" (err)
 			     : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
 			     : "memory");	/* memory required? */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 56ebd1f..9bba5b7 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -49,7 +49,6 @@
 obj-y				+= acpi/
 obj-y				+= reboot.o
 obj-$(CONFIG_X86_32)		+= reboot_32.o
-obj-$(CONFIG_MCA)		+= mca_32.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
 obj-$(CONFIG_PCI)		+= early-quirks.o
@@ -101,6 +100,7 @@
 
 obj-$(CONFIG_SWIOTLB)			+= pci-swiotlb.o
 obj-$(CONFIG_OF)			+= devicetree.o
+obj-$(CONFIG_UPROBES)			+= uprobes.o
 
 ###
 # 64 bit specific files
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 7c439fe..8afb693 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -990,7 +990,7 @@
 	int i;
 	struct mpc_intsrc mp_irq;
 
-#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
+#ifdef CONFIG_EISA
 	/*
 	 * Fabricate the legacy ISA bus (bus #31).
 	 */
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 3722179a..39a222e 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1326,11 +1326,13 @@
 			       acked);
 			break;
 		}
-		if (cpu_has_tsc) {
-			rdtscll(ntsc);
-			max_loops = (cpu_khz << 10) - (ntsc - tsc);
-		} else
-			max_loops--;
+		if (queued) {
+			if (cpu_has_tsc) {
+				rdtscll(ntsc);
+				max_loops = (cpu_khz << 10) - (ntsc - tsc);
+			} else
+				max_loops--;
+		}
 	} while (queued && max_loops > 0);
 	WARN_ON(max_loops <= 0);
 
diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
index 359b689..0e881c4 100644
--- a/arch/x86/kernel/apic/apic_flat_64.c
+++ b/arch/x86/kernel/apic/apic_flat_64.c
@@ -227,6 +227,7 @@
 
 	.read				= native_apic_mem_read,
 	.write				= native_apic_mem_write,
+	.eoi_write			= native_apic_mem_write,
 	.icr_read			= native_apic_icr_read,
 	.icr_write			= native_apic_icr_write,
 	.wait_icr_idle			= native_apic_wait_icr_idle,
@@ -386,6 +387,7 @@
 
 	.read				= native_apic_mem_read,
 	.write				= native_apic_mem_write,
+	.eoi_write			= native_apic_mem_write,
 	.icr_read			= native_apic_icr_read,
 	.icr_write			= native_apic_icr_write,
 	.wait_icr_idle			= native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
index 634ae6c..a6e4c6e 100644
--- a/arch/x86/kernel/apic/apic_noop.c
+++ b/arch/x86/kernel/apic/apic_noop.c
@@ -181,6 +181,7 @@
 
 	.read				= noop_apic_read,
 	.write				= noop_apic_write,
+	.eoi_write			= noop_apic_write,
 	.icr_read			= noop_apic_icr_read,
 	.icr_write			= noop_apic_icr_write,
 	.wait_icr_idle			= noop_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 23e75422e..6ec6d5d 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -295,6 +295,7 @@
 
 	.read				= native_apic_mem_read,
 	.write				= native_apic_mem_write,
+	.eoi_write			= native_apic_mem_write,
 	.icr_read			= native_apic_icr_read,
 	.icr_write			= native_apic_icr_write,
 	.wait_icr_idle			= native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c
index 0cdec70..31fbdbf 100644
--- a/arch/x86/kernel/apic/bigsmp_32.c
+++ b/arch/x86/kernel/apic/bigsmp_32.c
@@ -248,6 +248,7 @@
 
 	.read				= native_apic_mem_read,
 	.write				= native_apic_mem_write,
+	.eoi_write			= native_apic_mem_write,
 	.icr_read			= native_apic_icr_read,
 	.icr_write			= native_apic_icr_write,
 	.wait_icr_idle			= native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c
index e42d1d3b9..db4ab1b 100644
--- a/arch/x86/kernel/apic/es7000_32.c
+++ b/arch/x86/kernel/apic/es7000_32.c
@@ -678,6 +678,7 @@
 
 	.read				= native_apic_mem_read,
 	.write				= native_apic_mem_write,
+	.eoi_write			= native_apic_mem_write,
 	.icr_read			= native_apic_icr_read,
 	.icr_write			= native_apic_icr_write,
 	.wait_icr_idle			= native_apic_wait_icr_idle,
@@ -742,6 +743,7 @@
 
 	.read				= native_apic_mem_read,
 	.write				= native_apic_mem_write,
+	.eoi_write			= native_apic_mem_write,
 	.icr_read			= native_apic_icr_read,
 	.icr_write			= native_apic_icr_write,
 	.wait_icr_idle			= native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index ef0648c..ac96561 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -68,24 +68,6 @@
 #define for_each_irq_pin(entry, head) \
 	for (entry = head; entry; entry = entry->next)
 
-static void		__init __ioapic_init_mappings(void);
-
-static unsigned int	__io_apic_read  (unsigned int apic, unsigned int reg);
-static void		__io_apic_write (unsigned int apic, unsigned int reg, unsigned int val);
-static void		__io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
-
-static struct io_apic_ops io_apic_ops = {
-	.init	= __ioapic_init_mappings,
-	.read	= __io_apic_read,
-	.write	= __io_apic_write,
-	.modify = __io_apic_modify,
-};
-
-void __init set_io_apic_ops(const struct io_apic_ops *ops)
-{
-	io_apic_ops = *ops;
-}
-
 #ifdef CONFIG_IRQ_REMAP
 static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
 static inline bool irq_remapped(struct irq_cfg *cfg)
@@ -158,7 +140,7 @@
 /* GSI interrupts */
 static int nr_irqs_gsi = NR_IRQS_LEGACY;
 
-#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
+#ifdef CONFIG_EISA
 int mp_bus_id_to_type[MAX_MP_BUSSES];
 #endif
 
@@ -329,21 +311,6 @@
 	irq_free_desc(at);
 }
 
-static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
-{
-	return io_apic_ops.read(apic, reg);
-}
-
-static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
-{
-	io_apic_ops.write(apic, reg, value);
-}
-
-static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
-{
-	io_apic_ops.modify(apic, reg, value);
-}
-
 
 struct io_apic {
 	unsigned int index;
@@ -365,14 +332,14 @@
 	writel(vector, &io_apic->eoi);
 }
 
-static unsigned int __io_apic_read(unsigned int apic, unsigned int reg)
+unsigned int native_io_apic_read(unsigned int apic, unsigned int reg)
 {
 	struct io_apic __iomem *io_apic = io_apic_base(apic);
 	writel(reg, &io_apic->index);
 	return readl(&io_apic->data);
 }
 
-static void __io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
 {
 	struct io_apic __iomem *io_apic = io_apic_base(apic);
 
@@ -386,7 +353,7 @@
  *
  * Older SiS APIC requires we rewrite the index register
  */
-static void __io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
+void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
 {
 	struct io_apic __iomem *io_apic = io_apic_base(apic);
 
@@ -395,29 +362,6 @@
 	writel(value, &io_apic->data);
 }
 
-static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
-{
-	struct irq_pin_list *entry;
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&ioapic_lock, flags);
-	for_each_irq_pin(entry, cfg->irq_2_pin) {
-		unsigned int reg;
-		int pin;
-
-		pin = entry->pin;
-		reg = io_apic_read(entry->apic, 0x10 + pin*2);
-		/* Is the remote IRR bit set? */
-		if (reg & IO_APIC_REDIR_REMOTE_IRR) {
-			raw_spin_unlock_irqrestore(&ioapic_lock, flags);
-			return true;
-		}
-	}
-	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
-
-	return false;
-}
-
 union entry_union {
 	struct { u32 w1, w2; };
 	struct IO_APIC_route_entry entry;
@@ -891,7 +835,7 @@
 	return -1;
 }
 
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
+#ifdef CONFIG_EISA
 /*
  * EISA Edge/Level control register, ELCR
  */
@@ -928,12 +872,6 @@
 #define default_PCI_trigger(idx)	(1)
 #define default_PCI_polarity(idx)	(1)
 
-/* MCA interrupts are always polarity zero level triggered,
- * when listed as conforming in the MP table. */
-
-#define default_MCA_trigger(idx)	(1)
-#define default_MCA_polarity(idx)	default_ISA_polarity(idx)
-
 static int irq_polarity(int idx)
 {
 	int bus = mp_irqs[idx].srcbus;
@@ -991,7 +929,7 @@
 				trigger = default_ISA_trigger(idx);
 			else
 				trigger = default_PCI_trigger(idx);
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
+#ifdef CONFIG_EISA
 			switch (mp_bus_id_to_type[bus]) {
 				case MP_BUS_ISA: /* ISA pin */
 				{
@@ -1008,11 +946,6 @@
 					/* set before the switch */
 					break;
 				}
-				case MP_BUS_MCA: /* MCA pin */
-				{
-					trigger = default_MCA_trigger(idx);
-					break;
-				}
 				default:
 				{
 					printk(KERN_WARNING "broken BIOS!!\n");
@@ -2439,6 +2372,29 @@
 atomic_t irq_mis_count;
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
+static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
+{
+	struct irq_pin_list *entry;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&ioapic_lock, flags);
+	for_each_irq_pin(entry, cfg->irq_2_pin) {
+		unsigned int reg;
+		int pin;
+
+		pin = entry->pin;
+		reg = io_apic_read(entry->apic, 0x10 + pin*2);
+		/* Is the remote IRR bit set? */
+		if (reg & IO_APIC_REDIR_REMOTE_IRR) {
+			raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+			return true;
+		}
+	}
+	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	return false;
+}
+
 static inline bool ioapic_irqd_mask(struct irq_data *data, struct irq_cfg *cfg)
 {
 	/* If we are moving the irq we need to mask it */
@@ -3756,12 +3712,7 @@
 	return res;
 }
 
-void __init ioapic_and_gsi_init(void)
-{
-	io_apic_ops.init();
-}
-
-static void __init __ioapic_init_mappings(void)
+void __init native_io_apic_init_mappings(void)
 {
 	unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
 	struct resource *ioapic_res;
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c
index 00d2422..f00a68c 100644
--- a/arch/x86/kernel/apic/numaq_32.c
+++ b/arch/x86/kernel/apic/numaq_32.c
@@ -530,6 +530,7 @@
 
 	.read				= native_apic_mem_read,
 	.write				= native_apic_mem_write,
+	.eoi_write			= native_apic_mem_write,
 	.icr_read			= native_apic_icr_read,
 	.icr_write			= native_apic_icr_write,
 	.wait_icr_idle			= native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c
index ff2c1b9..1b291da 100644
--- a/arch/x86/kernel/apic/probe_32.c
+++ b/arch/x86/kernel/apic/probe_32.c
@@ -142,6 +142,7 @@
 
 	.read				= native_apic_mem_read,
 	.write				= native_apic_mem_write,
+	.eoi_write			= native_apic_mem_write,
 	.icr_read			= native_apic_icr_read,
 	.icr_write			= native_apic_icr_write,
 	.wait_icr_idle			= native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c
index fea000b..659897c 100644
--- a/arch/x86/kernel/apic/summit_32.c
+++ b/arch/x86/kernel/apic/summit_32.c
@@ -546,6 +546,7 @@
 
 	.read				= native_apic_mem_read,
 	.write				= native_apic_mem_write,
+	.eoi_write			= native_apic_mem_write,
 	.icr_read			= native_apic_icr_read,
 	.icr_write			= native_apic_icr_write,
 	.wait_icr_idle			= native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c
index 48f3103..ff35cff 100644
--- a/arch/x86/kernel/apic/x2apic_cluster.c
+++ b/arch/x86/kernel/apic/x2apic_cluster.c
@@ -260,6 +260,7 @@
 
 	.read				= native_apic_msr_read,
 	.write				= native_apic_msr_write,
+	.eoi_write			= native_apic_msr_eoi_write,
 	.icr_read			= native_x2apic_icr_read,
 	.icr_write			= native_x2apic_icr_write,
 	.wait_icr_idle			= native_x2apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index 991e315..c17e982 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -172,6 +172,7 @@
 
 	.read				= native_apic_msr_read,
 	.write				= native_apic_msr_write,
+	.eoi_write			= native_apic_msr_eoi_write,
 	.icr_read			= native_x2apic_icr_read,
 	.icr_write			= native_x2apic_icr_write,
 	.wait_icr_idle			= native_x2apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 87bfa69..c6d03f7 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -404,6 +404,7 @@
 
 	.read				= native_apic_msr_read,
 	.write				= native_apic_msr_write,
+	.eoi_write			= native_apic_msr_eoi_write,
 	.icr_read			= native_x2apic_icr_read,
 	.icr_write			= native_x2apic_icr_write,
 	.wait_icr_idle			= native_x2apic_wait_icr_idle,
diff --git a/arch/x86/kernel/check.c b/arch/x86/kernel/check.c
index 5da1269..e2dbcb7 100644
--- a/arch/x86/kernel/check.c
+++ b/arch/x86/kernel/check.c
@@ -27,21 +27,29 @@
 
 static __init int set_corruption_check(char *arg)
 {
-	char *end;
+	ssize_t ret;
+	unsigned long val;
 
-	memory_corruption_check = simple_strtol(arg, &end, 10);
+	ret = kstrtoul(arg, 10, &val);
+	if (ret)
+		return ret;
 
-	return (*end == 0) ? 0 : -EINVAL;
+	memory_corruption_check = val;
+	return 0;
 }
 early_param("memory_corruption_check", set_corruption_check);
 
 static __init int set_corruption_check_period(char *arg)
 {
-	char *end;
+	ssize_t ret;
+	unsigned long val;
 
-	corruption_check_period = simple_strtoul(arg, &end, 10);
+	ret = kstrtoul(arg, 10, &val);
+	if (ret)
+		return ret;
 
-	return (*end == 0) ? 0 : -EINVAL;
+	corruption_check_period = val;
+	return 0;
 }
 early_param("memory_corruption_check_period", set_corruption_check_period);
 
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index cf79302..82f29e7 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1185,7 +1185,7 @@
 	oist = &per_cpu(orig_ist, cpu);
 
 #ifdef CONFIG_NUMA
-	if (cpu != 0 && percpu_read(numa_node) == 0 &&
+	if (cpu != 0 && this_cpu_read(numa_node) == 0 &&
 	    early_cpu_to_node(cpu) != NUMA_NO_NODE)
 		set_numa_node(early_cpu_to_node(cpu));
 #endif
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index b8f3653..9a7c90d 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -615,14 +615,14 @@
 					new_l2 = this_leaf.size/1024;
 					num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
 					index_msb = get_count_order(num_threads_sharing);
-					l2_id = c->apicid >> index_msb;
+					l2_id = c->apicid & ~((1 << index_msb) - 1);
 					break;
 				case 3:
 					new_l3 = this_leaf.size/1024;
 					num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
 					index_msb = get_count_order(
 							num_threads_sharing);
-					l3_id = c->apicid >> index_msb;
+					l3_id = c->apicid & ~((1 << index_msb) - 1);
 					break;
 				default:
 					break;
diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c
index 5502b28..3656537 100644
--- a/arch/x86/kernel/cpu/match.c
+++ b/arch/x86/kernel/cpu/match.c
@@ -23,7 +23,7 @@
  * %X86_MODEL_ANY, %X86_FEATURE_ANY or 0 (except for vendor)
  *
  * Arrays used to match for this should also be declared using
- * MODULE_DEVICE_TABLE(x86_cpu, ...)
+ * MODULE_DEVICE_TABLE(x86cpu, ...)
  *
  * This always matches against the boot cpu, assuming models and features are
  * consistent over all CPUs.
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 11c9166c..2afcbd2 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -583,7 +583,7 @@
 	struct mce m;
 	int i;
 
-	percpu_inc(mce_poll_count);
+	this_cpu_inc(mce_poll_count);
 
 	mce_gather_info(&m, NULL);
 
@@ -1017,7 +1017,7 @@
 
 	atomic_inc(&mce_entry);
 
-	percpu_inc(mce_exception_count);
+	this_cpu_inc(mce_exception_count);
 
 	if (!banks)
 		goto out;
@@ -1431,6 +1431,43 @@
 		 */
 		 if (c->x86 == 6 && banks > 0)
 			mce_banks[0].ctl = 0;
+
+		 /*
+		  * Turn off MC4_MISC thresholding banks on those models since
+		  * they're not supported there.
+		  */
+		 if (c->x86 == 0x15 &&
+		     (c->x86_model >= 0x10 && c->x86_model <= 0x1f)) {
+			 int i;
+			 u64 val, hwcr;
+			 bool need_toggle;
+			 u32 msrs[] = {
+				0x00000413, /* MC4_MISC0 */
+				0xc0000408, /* MC4_MISC1 */
+			 };
+
+			 rdmsrl(MSR_K7_HWCR, hwcr);
+
+			 /* McStatusWrEn has to be set */
+			 need_toggle = !(hwcr & BIT(18));
+
+			 if (need_toggle)
+				 wrmsrl(MSR_K7_HWCR, hwcr | BIT(18));
+
+			 for (i = 0; i < ARRAY_SIZE(msrs); i++) {
+				 rdmsrl(msrs[i], val);
+
+				 /* CntP bit set? */
+				 if (val & BIT(62)) {
+					 val &= ~BIT(62);
+					 wrmsrl(msrs[i], val);
+				 }
+			 }
+
+			 /* restore old settings */
+			 if (need_toggle)
+				 wrmsrl(MSR_K7_HWCR, hwcr);
+		 }
 	}
 
 	if (c->x86_vendor == X86_VENDOR_INTEL) {
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 99b5717..f4873a6 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -51,6 +51,7 @@
 	unsigned int		cpu;
 	u32			address;
 	u16			interrupt_enable;
+	bool			interrupt_capable;
 	u16			threshold_limit;
 	struct kobject		kobj;
 	struct list_head	miscj;
@@ -83,6 +84,21 @@
 	u16			old_limit;
 };
 
+static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits)
+{
+	/*
+	 * bank 4 supports APIC LVT interrupts implicitly since forever.
+	 */
+	if (bank == 4)
+		return true;
+
+	/*
+	 * IntP: interrupt present; if this bit is set, the thresholding
+	 * bank can generate APIC LVT interrupts
+	 */
+	return msr_high_bits & BIT(28);
+}
+
 static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
 {
 	int msr = (hi & MASK_LVTOFF_HI) >> 20;
@@ -104,8 +120,10 @@
 	return 1;
 };
 
-/* must be called with correct cpu affinity */
-/* Called via smp_call_function_single() */
+/*
+ * Called via smp_call_function_single(), must be called with correct
+ * cpu affinity.
+ */
 static void threshold_restart_bank(void *_tr)
 {
 	struct thresh_restart *tr = _tr;
@@ -128,6 +146,12 @@
 		    (new_count & THRESHOLD_MAX);
 	}
 
+	/* clear IntType */
+	hi &= ~MASK_INT_TYPE_HI;
+
+	if (!tr->b->interrupt_capable)
+		goto done;
+
 	if (tr->set_lvt_off) {
 		if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) {
 			/* set new lvt offset */
@@ -136,9 +160,10 @@
 		}
 	}
 
-	tr->b->interrupt_enable ?
-	    (hi = (hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) :
-	    (hi &= ~MASK_INT_TYPE_HI);
+	if (tr->b->interrupt_enable)
+		hi |= INT_TYPE_APIC;
+
+ done:
 
 	hi |= MASK_COUNT_EN_HI;
 	wrmsr(tr->b->address, lo, hi);
@@ -202,14 +227,17 @@
 			if (shared_bank[bank] && c->cpu_core_id)
 				break;
 
-			offset = setup_APIC_mce(offset,
-						(high & MASK_LVTOFF_HI) >> 20);
-
 			memset(&b, 0, sizeof(b));
-			b.cpu		= cpu;
-			b.bank		= bank;
-			b.block		= block;
-			b.address	= address;
+			b.cpu			= cpu;
+			b.bank			= bank;
+			b.block			= block;
+			b.address		= address;
+			b.interrupt_capable	= lvt_interrupt_supported(bank, high);
+
+			if (b.interrupt_capable) {
+				int new = (high & MASK_LVTOFF_HI) >> 20;
+				offset  = setup_APIC_mce(offset, new);
+			}
 
 			mce_threshold_block_init(&b, offset);
 			mce_threshold_vector = amd_threshold_interrupt;
@@ -309,6 +337,9 @@
 	struct thresh_restart tr;
 	unsigned long new;
 
+	if (!b->interrupt_capable)
+		return -EINVAL;
+
 	if (strict_strtoul(buf, 0, &new) < 0)
 		return -EINVAL;
 
@@ -390,10 +421,10 @@
 RW_ATTR(error_count);
 
 static struct attribute *default_attrs[] = {
-	&interrupt_enable.attr,
 	&threshold_limit.attr,
 	&error_count.attr,
-	NULL
+	NULL,	/* possibly interrupt_enable if supported, see below */
+	NULL,
 };
 
 #define to_block(k)	container_of(k, struct threshold_block, kobj)
@@ -467,8 +498,14 @@
 	b->cpu			= cpu;
 	b->address		= address;
 	b->interrupt_enable	= 0;
+	b->interrupt_capable	= lvt_interrupt_supported(bank, high);
 	b->threshold_limit	= THRESHOLD_MAX;
 
+	if (b->interrupt_capable)
+		threshold_ktype.default_attrs[2] = &interrupt_enable.attr;
+	else
+		threshold_ktype.default_attrs[2] = NULL;
+
 	INIT_LIST_HEAD(&b->miscj);
 
 	if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index bb8e034..e049d6d 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -484,9 +484,6 @@
 
 	/* mark unused */
 	event->hw.extra_reg.idx = EXTRA_REG_NONE;
-
-	/* mark not used */
-	event->hw.extra_reg.idx = EXTRA_REG_NONE;
 	event->hw.branch_reg.idx = EXTRA_REG_NONE;
 
 	return x86_pmu.hw_config(event);
@@ -1186,8 +1183,6 @@
 	int idx, handled = 0;
 	u64 val;
 
-	perf_sample_data_init(&data, 0);
-
 	cpuc = &__get_cpu_var(cpu_hw_events);
 
 	/*
@@ -1222,7 +1217,7 @@
 		 * event overflow
 		 */
 		handled++;
-		data.period	= event->hw.last_period;
+		perf_sample_data_init(&data, 0, event->hw.last_period);
 
 		if (!x86_perf_event_set_period(event))
 			continue;
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index 95e7fe1..11a4eb9 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -134,8 +134,13 @@
 
 static int amd_pmu_hw_config(struct perf_event *event)
 {
-	int ret = x86_pmu_hw_config(event);
+	int ret;
 
+	/* pass precise event sampling to ibs: */
+	if (event->attr.precise_ip && get_ibs_caps())
+		return -ENOENT;
+
+	ret = x86_pmu_hw_config(event);
 	if (ret)
 		return ret;
 
@@ -205,10 +210,8 @@
 	 * when we come here
 	 */
 	for (i = 0; i < x86_pmu.num_counters; i++) {
-		if (nb->owners[i] == event) {
-			cmpxchg(nb->owners+i, event, NULL);
+		if (cmpxchg(nb->owners + i, event, NULL) == event)
 			break;
-		}
 	}
 }
 
@@ -493,6 +496,7 @@
  * 0x023	DE	PERF_CTL[2:0]
  * 0x02D	LS	PERF_CTL[3]
  * 0x02E	LS	PERF_CTL[3,0]
+ * 0x031	LS	PERF_CTL[2:0] (**)
  * 0x043	CU	PERF_CTL[2:0]
  * 0x045	CU	PERF_CTL[2:0]
  * 0x046	CU	PERF_CTL[2:0]
@@ -506,10 +510,12 @@
  * 0x0DD	LS	PERF_CTL[5:0]
  * 0x0DE	LS	PERF_CTL[5:0]
  * 0x0DF	LS	PERF_CTL[5:0]
+ * 0x1C0	EX	PERF_CTL[5:3]
  * 0x1D6	EX	PERF_CTL[5:0]
  * 0x1D8	EX	PERF_CTL[5:0]
  *
- * (*) depending on the umask all FPU counters may be used
+ * (*)  depending on the umask all FPU counters may be used
+ * (**) only one unitmask enabled at a time
  */
 
 static struct event_constraint amd_f15_PMC0  = EVENT_CONSTRAINT(0, 0x01, 0);
@@ -559,6 +565,12 @@
 			return &amd_f15_PMC3;
 		case 0x02E:
 			return &amd_f15_PMC30;
+		case 0x031:
+			if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1)
+				return &amd_f15_PMC20;
+			return &emptyconstraint;
+		case 0x1C0:
+			return &amd_f15_PMC53;
 		default:
 			return &amd_f15_PMC50;
 		}
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
index 3b8a2d3..da9bcdc 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
@@ -9,6 +9,7 @@
 #include <linux/perf_event.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/ptrace.h>
 
 #include <asm/apic.h>
 
@@ -16,36 +17,591 @@
 
 #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
 
-static struct pmu perf_ibs;
+#include <linux/kprobes.h>
+#include <linux/hardirq.h>
+
+#include <asm/nmi.h>
+
+#define IBS_FETCH_CONFIG_MASK	(IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT)
+#define IBS_OP_CONFIG_MASK	IBS_OP_MAX_CNT
+
+enum ibs_states {
+	IBS_ENABLED	= 0,
+	IBS_STARTED	= 1,
+	IBS_STOPPING	= 2,
+
+	IBS_MAX_STATES,
+};
+
+struct cpu_perf_ibs {
+	struct perf_event	*event;
+	unsigned long		state[BITS_TO_LONGS(IBS_MAX_STATES)];
+};
+
+struct perf_ibs {
+	struct pmu	pmu;
+	unsigned int	msr;
+	u64		config_mask;
+	u64		cnt_mask;
+	u64		enable_mask;
+	u64		valid_mask;
+	u64		max_period;
+	unsigned long	offset_mask[1];
+	int		offset_max;
+	struct cpu_perf_ibs __percpu *pcpu;
+	u64		(*get_count)(u64 config);
+};
+
+struct perf_ibs_data {
+	u32		size;
+	union {
+		u32	data[0];	/* data buffer starts here */
+		u32	caps;
+	};
+	u64		regs[MSR_AMD64_IBS_REG_COUNT_MAX];
+};
+
+static int
+perf_event_set_period(struct hw_perf_event *hwc, u64 min, u64 max, u64 *hw_period)
+{
+	s64 left = local64_read(&hwc->period_left);
+	s64 period = hwc->sample_period;
+	int overflow = 0;
+
+	/*
+	 * If we are way outside a reasonable range then just skip forward:
+	 */
+	if (unlikely(left <= -period)) {
+		left = period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		overflow = 1;
+	}
+
+	if (unlikely(left < (s64)min)) {
+		left += period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		overflow = 1;
+	}
+
+	/*
+	 * If the hw period that triggers the sw overflow is too short
+	 * we might hit the irq handler. This biases the results.
+	 * Thus we shorten the next-to-last period and set the last
+	 * period to the max period.
+	 */
+	if (left > max) {
+		left -= max;
+		if (left > max)
+			left = max;
+		else if (left < min)
+			left = min;
+	}
+
+	*hw_period = (u64)left;
+
+	return overflow;
+}
+
+static  int
+perf_event_try_update(struct perf_event *event, u64 new_raw_count, int width)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int shift = 64 - width;
+	u64 prev_raw_count;
+	u64 delta;
+
+	/*
+	 * Careful: an NMI might modify the previous event value.
+	 *
+	 * Our tactic to handle this is to first atomically read and
+	 * exchange a new raw count - then add that new-prev delta
+	 * count to the generic event atomically:
+	 */
+	prev_raw_count = local64_read(&hwc->prev_count);
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+					new_raw_count) != prev_raw_count)
+		return 0;
+
+	/*
+	 * Now we have the new raw value and have updated the prev
+	 * timestamp already. We can now calculate the elapsed delta
+	 * (event-)time and add that to the generic event.
+	 *
+	 * Careful, not all hw sign-extends above the physical width
+	 * of the count.
+	 */
+	delta = (new_raw_count << shift) - (prev_raw_count << shift);
+	delta >>= shift;
+
+	local64_add(delta, &event->count);
+	local64_sub(delta, &hwc->period_left);
+
+	return 1;
+}
+
+static struct perf_ibs perf_ibs_fetch;
+static struct perf_ibs perf_ibs_op;
+
+static struct perf_ibs *get_ibs_pmu(int type)
+{
+	if (perf_ibs_fetch.pmu.type == type)
+		return &perf_ibs_fetch;
+	if (perf_ibs_op.pmu.type == type)
+		return &perf_ibs_op;
+	return NULL;
+}
+
+/*
+ * Use IBS for precise event sampling:
+ *
+ *  perf record -a -e cpu-cycles:p ...    # use ibs op counting cycle count
+ *  perf record -a -e r076:p ...          # same as -e cpu-cycles:p
+ *  perf record -a -e r0C1:p ...          # use ibs op counting micro-ops
+ *
+ * IbsOpCntCtl (bit 19) of IBS Execution Control Register (IbsOpCtl,
+ * MSRC001_1033) is used to select either cycle or micro-ops counting
+ * mode.
+ *
+ * The rip of IBS samples has skid 0. Thus, IBS supports precise
+ * levels 1 and 2 and the PERF_EFLAGS_EXACT is set. In rare cases the
+ * rip is invalid when IBS was not able to record the rip correctly.
+ * We clear PERF_EFLAGS_EXACT and take the rip from pt_regs then.
+ *
+ */
+static int perf_ibs_precise_event(struct perf_event *event, u64 *config)
+{
+	switch (event->attr.precise_ip) {
+	case 0:
+		return -ENOENT;
+	case 1:
+	case 2:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	switch (event->attr.type) {
+	case PERF_TYPE_HARDWARE:
+		switch (event->attr.config) {
+		case PERF_COUNT_HW_CPU_CYCLES:
+			*config = 0;
+			return 0;
+		}
+		break;
+	case PERF_TYPE_RAW:
+		switch (event->attr.config) {
+		case 0x0076:
+			*config = 0;
+			return 0;
+		case 0x00C1:
+			*config = IBS_OP_CNT_CTL;
+			return 0;
+		}
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return -EOPNOTSUPP;
+}
 
 static int perf_ibs_init(struct perf_event *event)
 {
-	if (perf_ibs.type != event->attr.type)
+	struct hw_perf_event *hwc = &event->hw;
+	struct perf_ibs *perf_ibs;
+	u64 max_cnt, config;
+	int ret;
+
+	perf_ibs = get_ibs_pmu(event->attr.type);
+	if (perf_ibs) {
+		config = event->attr.config;
+	} else {
+		perf_ibs = &perf_ibs_op;
+		ret = perf_ibs_precise_event(event, &config);
+		if (ret)
+			return ret;
+	}
+
+	if (event->pmu != &perf_ibs->pmu)
 		return -ENOENT;
+
+	if (config & ~perf_ibs->config_mask)
+		return -EINVAL;
+
+	if (hwc->sample_period) {
+		if (config & perf_ibs->cnt_mask)
+			/* raw max_cnt may not be set */
+			return -EINVAL;
+		if (!event->attr.sample_freq && hwc->sample_period & 0x0f)
+			/*
+			 * lower 4 bits can not be set in ibs max cnt,
+			 * but allowing it in case we adjust the
+			 * sample period to set a frequency.
+			 */
+			return -EINVAL;
+		hwc->sample_period &= ~0x0FULL;
+		if (!hwc->sample_period)
+			hwc->sample_period = 0x10;
+	} else {
+		max_cnt = config & perf_ibs->cnt_mask;
+		config &= ~perf_ibs->cnt_mask;
+		event->attr.sample_period = max_cnt << 4;
+		hwc->sample_period = event->attr.sample_period;
+	}
+
+	if (!hwc->sample_period)
+		return -EINVAL;
+
+	/*
+	 * If we modify hwc->sample_period, we also need to update
+	 * hwc->last_period and hwc->period_left.
+	 */
+	hwc->last_period = hwc->sample_period;
+	local64_set(&hwc->period_left, hwc->sample_period);
+
+	hwc->config_base = perf_ibs->msr;
+	hwc->config = config;
+
 	return 0;
 }
 
+static int perf_ibs_set_period(struct perf_ibs *perf_ibs,
+			       struct hw_perf_event *hwc, u64 *period)
+{
+	int overflow;
+
+	/* ignore lower 4 bits in min count: */
+	overflow = perf_event_set_period(hwc, 1<<4, perf_ibs->max_period, period);
+	local64_set(&hwc->prev_count, 0);
+
+	return overflow;
+}
+
+static u64 get_ibs_fetch_count(u64 config)
+{
+	return (config & IBS_FETCH_CNT) >> 12;
+}
+
+static u64 get_ibs_op_count(u64 config)
+{
+	u64 count = 0;
+
+	if (config & IBS_OP_VAL)
+		count += (config & IBS_OP_MAX_CNT) << 4; /* cnt rolled over */
+
+	if (ibs_caps & IBS_CAPS_RDWROPCNT)
+		count += (config & IBS_OP_CUR_CNT) >> 32;
+
+	return count;
+}
+
+static void
+perf_ibs_event_update(struct perf_ibs *perf_ibs, struct perf_event *event,
+		      u64 *config)
+{
+	u64 count = perf_ibs->get_count(*config);
+
+	/*
+	 * Set width to 64 since we do not overflow on max width but
+	 * instead on max count. In perf_ibs_set_period() we clear
+	 * prev count manually on overflow.
+	 */
+	while (!perf_event_try_update(event, count, 64)) {
+		rdmsrl(event->hw.config_base, *config);
+		count = perf_ibs->get_count(*config);
+	}
+}
+
+static inline void perf_ibs_enable_event(struct perf_ibs *perf_ibs,
+					 struct hw_perf_event *hwc, u64 config)
+{
+	wrmsrl(hwc->config_base, hwc->config | config | perf_ibs->enable_mask);
+}
+
+/*
+ * Erratum #420 Instruction-Based Sampling Engine May Generate
+ * Interrupt that Cannot Be Cleared:
+ *
+ * Must clear counter mask first, then clear the enable bit. See
+ * Revision Guide for AMD Family 10h Processors, Publication #41322.
+ */
+static inline void perf_ibs_disable_event(struct perf_ibs *perf_ibs,
+					  struct hw_perf_event *hwc, u64 config)
+{
+	config &= ~perf_ibs->cnt_mask;
+	wrmsrl(hwc->config_base, config);
+	config &= ~perf_ibs->enable_mask;
+	wrmsrl(hwc->config_base, config);
+}
+
+/*
+ * We cannot restore the ibs pmu state, so we always needs to update
+ * the event while stopping it and then reset the state when starting
+ * again. Thus, ignoring PERF_EF_RELOAD and PERF_EF_UPDATE flags in
+ * perf_ibs_start()/perf_ibs_stop() and instead always do it.
+ */
+static void perf_ibs_start(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+	u64 period;
+
+	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+		return;
+
+	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+	hwc->state = 0;
+
+	perf_ibs_set_period(perf_ibs, hwc, &period);
+	set_bit(IBS_STARTED, pcpu->state);
+	perf_ibs_enable_event(perf_ibs, hwc, period >> 4);
+
+	perf_event_update_userpage(event);
+}
+
+static void perf_ibs_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+	u64 config;
+	int stopping;
+
+	stopping = test_and_clear_bit(IBS_STARTED, pcpu->state);
+
+	if (!stopping && (hwc->state & PERF_HES_UPTODATE))
+		return;
+
+	rdmsrl(hwc->config_base, config);
+
+	if (stopping) {
+		set_bit(IBS_STOPPING, pcpu->state);
+		perf_ibs_disable_event(perf_ibs, hwc, config);
+		WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+		hwc->state |= PERF_HES_STOPPED;
+	}
+
+	if (hwc->state & PERF_HES_UPTODATE)
+		return;
+
+	/*
+	 * Clear valid bit to not count rollovers on update, rollovers
+	 * are only updated in the irq handler.
+	 */
+	config &= ~perf_ibs->valid_mask;
+
+	perf_ibs_event_update(perf_ibs, event, &config);
+	hwc->state |= PERF_HES_UPTODATE;
+}
+
 static int perf_ibs_add(struct perf_event *event, int flags)
 {
+	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+
+	if (test_and_set_bit(IBS_ENABLED, pcpu->state))
+		return -ENOSPC;
+
+	event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+	pcpu->event = event;
+
+	if (flags & PERF_EF_START)
+		perf_ibs_start(event, PERF_EF_RELOAD);
+
 	return 0;
 }
 
 static void perf_ibs_del(struct perf_event *event, int flags)
 {
+	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+
+	if (!test_and_clear_bit(IBS_ENABLED, pcpu->state))
+		return;
+
+	perf_ibs_stop(event, PERF_EF_UPDATE);
+
+	pcpu->event = NULL;
+
+	perf_event_update_userpage(event);
 }
 
-static struct pmu perf_ibs = {
-	.event_init= perf_ibs_init,
-	.add= perf_ibs_add,
-	.del= perf_ibs_del,
+static void perf_ibs_read(struct perf_event *event) { }
+
+static struct perf_ibs perf_ibs_fetch = {
+	.pmu = {
+		.task_ctx_nr	= perf_invalid_context,
+
+		.event_init	= perf_ibs_init,
+		.add		= perf_ibs_add,
+		.del		= perf_ibs_del,
+		.start		= perf_ibs_start,
+		.stop		= perf_ibs_stop,
+		.read		= perf_ibs_read,
+	},
+	.msr			= MSR_AMD64_IBSFETCHCTL,
+	.config_mask		= IBS_FETCH_CONFIG_MASK,
+	.cnt_mask		= IBS_FETCH_MAX_CNT,
+	.enable_mask		= IBS_FETCH_ENABLE,
+	.valid_mask		= IBS_FETCH_VAL,
+	.max_period		= IBS_FETCH_MAX_CNT << 4,
+	.offset_mask		= { MSR_AMD64_IBSFETCH_REG_MASK },
+	.offset_max		= MSR_AMD64_IBSFETCH_REG_COUNT,
+
+	.get_count		= get_ibs_fetch_count,
 };
 
+static struct perf_ibs perf_ibs_op = {
+	.pmu = {
+		.task_ctx_nr	= perf_invalid_context,
+
+		.event_init	= perf_ibs_init,
+		.add		= perf_ibs_add,
+		.del		= perf_ibs_del,
+		.start		= perf_ibs_start,
+		.stop		= perf_ibs_stop,
+		.read		= perf_ibs_read,
+	},
+	.msr			= MSR_AMD64_IBSOPCTL,
+	.config_mask		= IBS_OP_CONFIG_MASK,
+	.cnt_mask		= IBS_OP_MAX_CNT,
+	.enable_mask		= IBS_OP_ENABLE,
+	.valid_mask		= IBS_OP_VAL,
+	.max_period		= IBS_OP_MAX_CNT << 4,
+	.offset_mask		= { MSR_AMD64_IBSOP_REG_MASK },
+	.offset_max		= MSR_AMD64_IBSOP_REG_COUNT,
+
+	.get_count		= get_ibs_op_count,
+};
+
+static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
+{
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+	struct perf_event *event = pcpu->event;
+	struct hw_perf_event *hwc = &event->hw;
+	struct perf_sample_data data;
+	struct perf_raw_record raw;
+	struct pt_regs regs;
+	struct perf_ibs_data ibs_data;
+	int offset, size, check_rip, offset_max, throttle = 0;
+	unsigned int msr;
+	u64 *buf, *config, period;
+
+	if (!test_bit(IBS_STARTED, pcpu->state)) {
+		/*
+		 * Catch spurious interrupts after stopping IBS: After
+		 * disabling IBS there could be still incomming NMIs
+		 * with samples that even have the valid bit cleared.
+		 * Mark all this NMIs as handled.
+		 */
+		return test_and_clear_bit(IBS_STOPPING, pcpu->state) ? 1 : 0;
+	}
+
+	msr = hwc->config_base;
+	buf = ibs_data.regs;
+	rdmsrl(msr, *buf);
+	if (!(*buf++ & perf_ibs->valid_mask))
+		return 0;
+
+	config = &ibs_data.regs[0];
+	perf_ibs_event_update(perf_ibs, event, config);
+	perf_sample_data_init(&data, 0, hwc->last_period);
+	if (!perf_ibs_set_period(perf_ibs, hwc, &period))
+		goto out;	/* no sw counter overflow */
+
+	ibs_data.caps = ibs_caps;
+	size = 1;
+	offset = 1;
+	check_rip = (perf_ibs == &perf_ibs_op && (ibs_caps & IBS_CAPS_RIPINVALIDCHK));
+	if (event->attr.sample_type & PERF_SAMPLE_RAW)
+		offset_max = perf_ibs->offset_max;
+	else if (check_rip)
+		offset_max = 2;
+	else
+		offset_max = 1;
+	do {
+		rdmsrl(msr + offset, *buf++);
+		size++;
+		offset = find_next_bit(perf_ibs->offset_mask,
+				       perf_ibs->offset_max,
+				       offset + 1);
+	} while (offset < offset_max);
+	ibs_data.size = sizeof(u64) * size;
+
+	regs = *iregs;
+	if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) {
+		regs.flags &= ~PERF_EFLAGS_EXACT;
+	} else {
+		instruction_pointer_set(&regs, ibs_data.regs[1]);
+		regs.flags |= PERF_EFLAGS_EXACT;
+	}
+
+	if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+		raw.size = sizeof(u32) + ibs_data.size;
+		raw.data = ibs_data.data;
+		data.raw = &raw;
+	}
+
+	throttle = perf_event_overflow(event, &data, &regs);
+out:
+	if (throttle)
+		perf_ibs_disable_event(perf_ibs, hwc, *config);
+	else
+		perf_ibs_enable_event(perf_ibs, hwc, period >> 4);
+
+	perf_event_update_userpage(event);
+
+	return 1;
+}
+
+static int __kprobes
+perf_ibs_nmi_handler(unsigned int cmd, struct pt_regs *regs)
+{
+	int handled = 0;
+
+	handled += perf_ibs_handle_irq(&perf_ibs_fetch, regs);
+	handled += perf_ibs_handle_irq(&perf_ibs_op, regs);
+
+	if (handled)
+		inc_irq_stat(apic_perf_irqs);
+
+	return handled;
+}
+
+static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name)
+{
+	struct cpu_perf_ibs __percpu *pcpu;
+	int ret;
+
+	pcpu = alloc_percpu(struct cpu_perf_ibs);
+	if (!pcpu)
+		return -ENOMEM;
+
+	perf_ibs->pcpu = pcpu;
+
+	ret = perf_pmu_register(&perf_ibs->pmu, name, -1);
+	if (ret) {
+		perf_ibs->pcpu = NULL;
+		free_percpu(pcpu);
+	}
+
+	return ret;
+}
+
 static __init int perf_event_ibs_init(void)
 {
 	if (!ibs_caps)
 		return -ENODEV;	/* ibs not supported by the cpu */
 
-	perf_pmu_register(&perf_ibs, "ibs", -1);
+	perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch");
+	if (ibs_caps & IBS_CAPS_OPCNT)
+		perf_ibs_op.config_mask |= IBS_OP_CNT_CTL;
+	perf_ibs_pmu_init(&perf_ibs_op, "ibs_op");
+	register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs");
 	printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps);
 
 	return 0;
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 26b3e2f..166546e 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1027,8 +1027,6 @@
 	u64 status;
 	int handled;
 
-	perf_sample_data_init(&data, 0);
-
 	cpuc = &__get_cpu_var(cpu_hw_events);
 
 	/*
@@ -1082,7 +1080,7 @@
 		if (!intel_pmu_save_and_restart(event))
 			continue;
 
-		data.period = event->hw.last_period;
+		perf_sample_data_init(&data, 0, event->hw.last_period);
 
 		if (has_branch_stack(event))
 			data.br_stack = &cpuc->lbr_stack;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 7f64df1..5a3edc2 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -316,8 +316,7 @@
 
 	ds->bts_index = ds->bts_buffer_base;
 
-	perf_sample_data_init(&data, 0);
-	data.period = event->hw.last_period;
+	perf_sample_data_init(&data, 0, event->hw.last_period);
 	regs.ip     = 0;
 
 	/*
@@ -564,8 +563,7 @@
 	if (!intel_pmu_save_and_restart(event))
 		return;
 
-	perf_sample_data_init(&data, 0);
-	data.period = event->hw.last_period;
+	perf_sample_data_init(&data, 0, event->hw.last_period);
 
 	/*
 	 * We use the interrupt regs as a base because the PEBS record
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index a2dfacf..47124a7 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -1005,8 +1005,6 @@
 	int idx, handled = 0;
 	u64 val;
 
-	perf_sample_data_init(&data, 0);
-
 	cpuc = &__get_cpu_var(cpu_hw_events);
 
 	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
@@ -1034,10 +1032,12 @@
 		handled += overflow;
 
 		/* event overflow for sure */
-		data.period = event->hw.last_period;
+		perf_sample_data_init(&data, 0, hwc->last_period);
 
 		if (!x86_perf_event_set_period(event))
 			continue;
+
+
 		if (perf_event_overflow(event, &data, regs))
 			x86_pmu_stop(event, 0);
 	}
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 1b81839..571246d 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -271,7 +271,7 @@
 			current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP)
 		return 1;
 
-	show_registers(regs);
+	show_regs(regs);
 #ifdef CONFIG_X86_32
 	if (user_mode_vm(regs)) {
 		sp = regs->sp;
@@ -311,16 +311,33 @@
 
 static int __init kstack_setup(char *s)
 {
+	ssize_t ret;
+	unsigned long val;
+
 	if (!s)
 		return -EINVAL;
-	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+
+	ret = kstrtoul(s, 0, &val);
+	if (ret)
+		return ret;
+	kstack_depth_to_print = val;
 	return 0;
 }
 early_param("kstack", kstack_setup);
 
 static int __init code_bytes_setup(char *s)
 {
-	code_bytes = simple_strtoul(s, NULL, 0);
+	ssize_t ret;
+	unsigned long val;
+
+	if (!s)
+		return -EINVAL;
+
+	ret = kstrtoul(s, 0, &val);
+	if (ret)
+		return ret;
+
+	code_bytes = val;
 	if (code_bytes > 8192)
 		code_bytes = 8192;
 
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 88ec912..e0b1d78 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -82,7 +82,7 @@
 }
 
 
-void show_registers(struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
 {
 	int i;
 
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 17107bd..791b761 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -245,7 +245,7 @@
 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
-void show_registers(struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
 {
 	int i;
 	unsigned long sp;
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 7b784f4..01ccf9b 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -56,6 +56,7 @@
 #include <asm/irq_vectors.h>
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
+#include <asm/asm.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
@@ -151,10 +152,8 @@
 .pushsection .fixup, "ax"
 99:	movl $0, (%esp)
 	jmp 98b
-.section __ex_table, "a"
-	.align 4
-	.long 98b, 99b
 .popsection
+	_ASM_EXTABLE(98b,99b)
 .endm
 
 .macro PTGS_TO_GS
@@ -164,10 +163,8 @@
 .pushsection .fixup, "ax"
 99:	movl $0, PT_GS(%esp)
 	jmp 98b
-.section __ex_table, "a"
-	.align 4
-	.long 98b, 99b
 .popsection
+	_ASM_EXTABLE(98b,99b)
 .endm
 
 .macro GS_TO_REG reg
@@ -249,12 +246,10 @@
 	jmp 2b
 6:	movl $0, (%esp)
 	jmp 3b
-.section __ex_table, "a"
-	.align 4
-	.long 1b, 4b
-	.long 2b, 5b
-	.long 3b, 6b
 .popsection
+	_ASM_EXTABLE(1b,4b)
+	_ASM_EXTABLE(2b,5b)
+	_ASM_EXTABLE(3b,6b)
 	POP_GS_EX
 .endm
 
@@ -415,10 +410,7 @@
 	jae syscall_fault
 1:	movl (%ebp),%ebp
 	movl %ebp,PT_EBP(%esp)
-.section __ex_table,"a"
-	.align 4
-	.long 1b,syscall_fault
-.previous
+	_ASM_EXTABLE(1b,syscall_fault)
 
 	GET_THREAD_INFO(%ebp)
 
@@ -485,10 +477,8 @@
 .pushsection .fixup,"ax"
 2:	movl $0,PT_FS(%esp)
 	jmp 1b
-.section __ex_table,"a"
-	.align 4
-	.long 1b,2b
 .popsection
+	_ASM_EXTABLE(1b,2b)
 	PTGS_TO_GS_EX
 ENDPROC(ia32_sysenter_target)
 
@@ -543,10 +533,7 @@
 	pushl $do_iret_error
 	jmp error_code
 .previous
-.section __ex_table,"a"
-	.align 4
-	.long irq_return,iret_exc
-.previous
+	_ASM_EXTABLE(irq_return,iret_exc)
 
 	CFI_RESTORE_STATE
 ldt_ss:
@@ -901,10 +888,7 @@
 #ifdef CONFIG_PARAVIRT
 ENTRY(native_iret)
 	iret
-.section __ex_table,"a"
-	.align 4
-	.long native_iret, iret_exc
-.previous
+	_ASM_EXTABLE(native_iret, iret_exc)
 END(native_iret)
 
 ENTRY(native_irq_enable_sysexit)
@@ -1093,13 +1077,10 @@
 	movl %eax,16(%esp)
 	jmp 4b
 .previous
-.section __ex_table,"a"
-	.align 4
-	.long 1b,6b
-	.long 2b,7b
-	.long 3b,8b
-	.long 4b,9b
-.previous
+	_ASM_EXTABLE(1b,6b)
+	_ASM_EXTABLE(2b,7b)
+	_ASM_EXTABLE(3b,8b)
+	_ASM_EXTABLE(4b,9b)
 ENDPROC(xen_failsafe_callback)
 
 BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK,
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index cdc79b5..320852d 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -55,6 +55,7 @@
 #include <asm/paravirt.h>
 #include <asm/ftrace.h>
 #include <asm/percpu.h>
+#include <asm/asm.h>
 #include <linux/err.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
@@ -900,18 +901,12 @@
 
 irq_return:
 	INTERRUPT_RETURN
-
-	.section __ex_table, "a"
-	.quad irq_return, bad_iret
-	.previous
+	_ASM_EXTABLE(irq_return, bad_iret)
 
 #ifdef CONFIG_PARAVIRT
 ENTRY(native_iret)
 	iretq
-
-	.section __ex_table,"a"
-	.quad native_iret, bad_iret
-	.previous
+	_ASM_EXTABLE(native_iret, bad_iret)
 #endif
 
 	.section .fixup,"ax"
@@ -1181,10 +1176,7 @@
 	CFI_ENDPROC
 END(native_load_gs_index)
 
-	.section __ex_table,"a"
-	.align 8
-	.quad gs_change,bad_gs
-	.previous
+	_ASM_EXTABLE(gs_change,bad_gs)
 	.section .fixup,"ax"
 	/* running with kernelgs */
 bad_gs:
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index c9a281f..32ff365 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -24,40 +24,21 @@
 #include <trace/syscall.h>
 
 #include <asm/cacheflush.h>
+#include <asm/kprobes.h>
 #include <asm/ftrace.h>
 #include <asm/nops.h>
-#include <asm/nmi.h>
-
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
-/*
- * modifying_code is set to notify NMIs that they need to use
- * memory barriers when entering or exiting. But we don't want
- * to burden NMIs with unnecessary memory barriers when code
- * modification is not being done (which is most of the time).
- *
- * A mutex is already held when ftrace_arch_code_modify_prepare
- * and post_process are called. No locks need to be taken here.
- *
- * Stop machine will make sure currently running NMIs are done
- * and new NMIs will see the updated variable before we need
- * to worry about NMIs doing memory barriers.
- */
-static int modifying_code __read_mostly;
-static DEFINE_PER_CPU(int, save_modifying_code);
-
 int ftrace_arch_code_modify_prepare(void)
 {
 	set_kernel_text_rw();
 	set_all_modules_text_rw();
-	modifying_code = 1;
 	return 0;
 }
 
 int ftrace_arch_code_modify_post_process(void)
 {
-	modifying_code = 0;
 	set_all_modules_text_ro();
 	set_kernel_text_ro();
 	return 0;
@@ -90,134 +71,6 @@
 	return calc.code;
 }
 
-/*
- * Modifying code must take extra care. On an SMP machine, if
- * the code being modified is also being executed on another CPU
- * that CPU will have undefined results and possibly take a GPF.
- * We use kstop_machine to stop other CPUS from exectuing code.
- * But this does not stop NMIs from happening. We still need
- * to protect against that. We separate out the modification of
- * the code to take care of this.
- *
- * Two buffers are added: An IP buffer and a "code" buffer.
- *
- * 1) Put the instruction pointer into the IP buffer
- *    and the new code into the "code" buffer.
- * 2) Wait for any running NMIs to finish and set a flag that says
- *    we are modifying code, it is done in an atomic operation.
- * 3) Write the code
- * 4) clear the flag.
- * 5) Wait for any running NMIs to finish.
- *
- * If an NMI is executed, the first thing it does is to call
- * "ftrace_nmi_enter". This will check if the flag is set to write
- * and if it is, it will write what is in the IP and "code" buffers.
- *
- * The trick is, it does not matter if everyone is writing the same
- * content to the code location. Also, if a CPU is executing code
- * it is OK to write to that code location if the contents being written
- * are the same as what exists.
- */
-
-#define MOD_CODE_WRITE_FLAG (1 << 31)	/* set when NMI should do the write */
-static atomic_t nmi_running = ATOMIC_INIT(0);
-static int mod_code_status;		/* holds return value of text write */
-static void *mod_code_ip;		/* holds the IP to write to */
-static const void *mod_code_newcode;	/* holds the text to write to the IP */
-
-static unsigned nmi_wait_count;
-static atomic_t nmi_update_count = ATOMIC_INIT(0);
-
-int ftrace_arch_read_dyn_info(char *buf, int size)
-{
-	int r;
-
-	r = snprintf(buf, size, "%u %u",
-		     nmi_wait_count,
-		     atomic_read(&nmi_update_count));
-	return r;
-}
-
-static void clear_mod_flag(void)
-{
-	int old = atomic_read(&nmi_running);
-
-	for (;;) {
-		int new = old & ~MOD_CODE_WRITE_FLAG;
-
-		if (old == new)
-			break;
-
-		old = atomic_cmpxchg(&nmi_running, old, new);
-	}
-}
-
-static void ftrace_mod_code(void)
-{
-	/*
-	 * Yes, more than one CPU process can be writing to mod_code_status.
-	 *    (and the code itself)
-	 * But if one were to fail, then they all should, and if one were
-	 * to succeed, then they all should.
-	 */
-	mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
-					     MCOUNT_INSN_SIZE);
-
-	/* if we fail, then kill any new writers */
-	if (mod_code_status)
-		clear_mod_flag();
-}
-
-void ftrace_nmi_enter(void)
-{
-	__this_cpu_write(save_modifying_code, modifying_code);
-
-	if (!__this_cpu_read(save_modifying_code))
-		return;
-
-	if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) {
-		smp_rmb();
-		ftrace_mod_code();
-		atomic_inc(&nmi_update_count);
-	}
-	/* Must have previous changes seen before executions */
-	smp_mb();
-}
-
-void ftrace_nmi_exit(void)
-{
-	if (!__this_cpu_read(save_modifying_code))
-		return;
-
-	/* Finish all executions before clearing nmi_running */
-	smp_mb();
-	atomic_dec(&nmi_running);
-}
-
-static void wait_for_nmi_and_set_mod_flag(void)
-{
-	if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG))
-		return;
-
-	do {
-		cpu_relax();
-	} while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG));
-
-	nmi_wait_count++;
-}
-
-static void wait_for_nmi(void)
-{
-	if (!atomic_read(&nmi_running))
-		return;
-
-	do {
-		cpu_relax();
-	} while (atomic_read(&nmi_running));
-
-	nmi_wait_count++;
-}
-
 static inline int
 within(unsigned long addr, unsigned long start, unsigned long end)
 {
@@ -238,26 +91,7 @@
 	if (within(ip, (unsigned long)_text, (unsigned long)_etext))
 		ip = (unsigned long)__va(__pa(ip));
 
-	mod_code_ip = (void *)ip;
-	mod_code_newcode = new_code;
-
-	/* The buffers need to be visible before we let NMIs write them */
-	smp_mb();
-
-	wait_for_nmi_and_set_mod_flag();
-
-	/* Make sure all running NMIs have finished before we write the code */
-	smp_mb();
-
-	ftrace_mod_code();
-
-	/* Make sure the write happens before clearing the bit */
-	smp_mb();
-
-	clear_mod_flag();
-	wait_for_nmi();
-
-	return mod_code_status;
+	return probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE);
 }
 
 static const unsigned char *ftrace_nop_replace(void)
@@ -334,6 +168,336 @@
 	return ret;
 }
 
+int modifying_ftrace_code __read_mostly;
+
+/*
+ * A breakpoint was added to the code address we are about to
+ * modify, and this is the handle that will just skip over it.
+ * We are either changing a nop into a trace call, or a trace
+ * call to a nop. While the change is taking place, we treat
+ * it just like it was a nop.
+ */
+int ftrace_int3_handler(struct pt_regs *regs)
+{
+	if (WARN_ON_ONCE(!regs))
+		return 0;
+
+	if (!ftrace_location(regs->ip - 1))
+		return 0;
+
+	regs->ip += MCOUNT_INSN_SIZE - 1;
+
+	return 1;
+}
+
+static int ftrace_write(unsigned long ip, const char *val, int size)
+{
+	/*
+	 * On x86_64, kernel text mappings are mapped read-only with
+	 * CONFIG_DEBUG_RODATA. So we use the kernel identity mapping instead
+	 * of the kernel text mapping to modify the kernel text.
+	 *
+	 * For 32bit kernels, these mappings are same and we can use
+	 * kernel identity mapping to modify code.
+	 */
+	if (within(ip, (unsigned long)_text, (unsigned long)_etext))
+		ip = (unsigned long)__va(__pa(ip));
+
+	return probe_kernel_write((void *)ip, val, size);
+}
+
+static int add_break(unsigned long ip, const char *old)
+{
+	unsigned char replaced[MCOUNT_INSN_SIZE];
+	unsigned char brk = BREAKPOINT_INSTRUCTION;
+
+	if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
+		return -EFAULT;
+
+	/* Make sure it is what we expect it to be */
+	if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0)
+		return -EINVAL;
+
+	if (ftrace_write(ip, &brk, 1))
+		return -EPERM;
+
+	return 0;
+}
+
+static int add_brk_on_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned const char *old;
+	unsigned long ip = rec->ip;
+
+	old = ftrace_call_replace(ip, addr);
+
+	return add_break(rec->ip, old);
+}
+
+
+static int add_brk_on_nop(struct dyn_ftrace *rec)
+{
+	unsigned const char *old;
+
+	old = ftrace_nop_replace();
+
+	return add_break(rec->ip, old);
+}
+
+static int add_breakpoints(struct dyn_ftrace *rec, int enable)
+{
+	unsigned long ftrace_addr;
+	int ret;
+
+	ret = ftrace_test_record(rec, enable);
+
+	ftrace_addr = (unsigned long)FTRACE_ADDR;
+
+	switch (ret) {
+	case FTRACE_UPDATE_IGNORE:
+		return 0;
+
+	case FTRACE_UPDATE_MAKE_CALL:
+		/* converting nop to call */
+		return add_brk_on_nop(rec);
+
+	case FTRACE_UPDATE_MAKE_NOP:
+		/* converting a call to a nop */
+		return add_brk_on_call(rec, ftrace_addr);
+	}
+	return 0;
+}
+
+/*
+ * On error, we need to remove breakpoints. This needs to
+ * be done caefully. If the address does not currently have a
+ * breakpoint, we know we are done. Otherwise, we look at the
+ * remaining 4 bytes of the instruction. If it matches a nop
+ * we replace the breakpoint with the nop. Otherwise we replace
+ * it with the call instruction.
+ */
+static int remove_breakpoint(struct dyn_ftrace *rec)
+{
+	unsigned char ins[MCOUNT_INSN_SIZE];
+	unsigned char brk = BREAKPOINT_INSTRUCTION;
+	const unsigned char *nop;
+	unsigned long ftrace_addr;
+	unsigned long ip = rec->ip;
+
+	/* If we fail the read, just give up */
+	if (probe_kernel_read(ins, (void *)ip, MCOUNT_INSN_SIZE))
+		return -EFAULT;
+
+	/* If this does not have a breakpoint, we are done */
+	if (ins[0] != brk)
+		return -1;
+
+	nop = ftrace_nop_replace();
+
+	/*
+	 * If the last 4 bytes of the instruction do not match
+	 * a nop, then we assume that this is a call to ftrace_addr.
+	 */
+	if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0) {
+		/*
+		 * For extra paranoidism, we check if the breakpoint is on
+		 * a call that would actually jump to the ftrace_addr.
+		 * If not, don't touch the breakpoint, we make just create
+		 * a disaster.
+		 */
+		ftrace_addr = (unsigned long)FTRACE_ADDR;
+		nop = ftrace_call_replace(ip, ftrace_addr);
+
+		if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)
+			return -EINVAL;
+	}
+
+	return probe_kernel_write((void *)ip, &nop[0], 1);
+}
+
+static int add_update_code(unsigned long ip, unsigned const char *new)
+{
+	/* skip breakpoint */
+	ip++;
+	new++;
+	if (ftrace_write(ip, new, MCOUNT_INSN_SIZE - 1))
+		return -EPERM;
+	return 0;
+}
+
+static int add_update_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned long ip = rec->ip;
+	unsigned const char *new;
+
+	new = ftrace_call_replace(ip, addr);
+	return add_update_code(ip, new);
+}
+
+static int add_update_nop(struct dyn_ftrace *rec)
+{
+	unsigned long ip = rec->ip;
+	unsigned const char *new;
+
+	new = ftrace_nop_replace();
+	return add_update_code(ip, new);
+}
+
+static int add_update(struct dyn_ftrace *rec, int enable)
+{
+	unsigned long ftrace_addr;
+	int ret;
+
+	ret = ftrace_test_record(rec, enable);
+
+	ftrace_addr = (unsigned long)FTRACE_ADDR;
+
+	switch (ret) {
+	case FTRACE_UPDATE_IGNORE:
+		return 0;
+
+	case FTRACE_UPDATE_MAKE_CALL:
+		/* converting nop to call */
+		return add_update_call(rec, ftrace_addr);
+
+	case FTRACE_UPDATE_MAKE_NOP:
+		/* converting a call to a nop */
+		return add_update_nop(rec);
+	}
+
+	return 0;
+}
+
+static int finish_update_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned long ip = rec->ip;
+	unsigned const char *new;
+
+	new = ftrace_call_replace(ip, addr);
+
+	if (ftrace_write(ip, new, 1))
+		return -EPERM;
+
+	return 0;
+}
+
+static int finish_update_nop(struct dyn_ftrace *rec)
+{
+	unsigned long ip = rec->ip;
+	unsigned const char *new;
+
+	new = ftrace_nop_replace();
+
+	if (ftrace_write(ip, new, 1))
+		return -EPERM;
+	return 0;
+}
+
+static int finish_update(struct dyn_ftrace *rec, int enable)
+{
+	unsigned long ftrace_addr;
+	int ret;
+
+	ret = ftrace_update_record(rec, enable);
+
+	ftrace_addr = (unsigned long)FTRACE_ADDR;
+
+	switch (ret) {
+	case FTRACE_UPDATE_IGNORE:
+		return 0;
+
+	case FTRACE_UPDATE_MAKE_CALL:
+		/* converting nop to call */
+		return finish_update_call(rec, ftrace_addr);
+
+	case FTRACE_UPDATE_MAKE_NOP:
+		/* converting a call to a nop */
+		return finish_update_nop(rec);
+	}
+
+	return 0;
+}
+
+static void do_sync_core(void *data)
+{
+	sync_core();
+}
+
+static void run_sync(void)
+{
+	int enable_irqs = irqs_disabled();
+
+	/* We may be called with interrupts disbled (on bootup). */
+	if (enable_irqs)
+		local_irq_enable();
+	on_each_cpu(do_sync_core, NULL, 1);
+	if (enable_irqs)
+		local_irq_disable();
+}
+
+void ftrace_replace_code(int enable)
+{
+	struct ftrace_rec_iter *iter;
+	struct dyn_ftrace *rec;
+	const char *report = "adding breakpoints";
+	int count = 0;
+	int ret;
+
+	for_ftrace_rec_iter(iter) {
+		rec = ftrace_rec_iter_record(iter);
+
+		ret = add_breakpoints(rec, enable);
+		if (ret)
+			goto remove_breakpoints;
+		count++;
+	}
+
+	run_sync();
+
+	report = "updating code";
+
+	for_ftrace_rec_iter(iter) {
+		rec = ftrace_rec_iter_record(iter);
+
+		ret = add_update(rec, enable);
+		if (ret)
+			goto remove_breakpoints;
+	}
+
+	run_sync();
+
+	report = "removing breakpoints";
+
+	for_ftrace_rec_iter(iter) {
+		rec = ftrace_rec_iter_record(iter);
+
+		ret = finish_update(rec, enable);
+		if (ret)
+			goto remove_breakpoints;
+	}
+
+	run_sync();
+
+	return;
+
+ remove_breakpoints:
+	ftrace_bug(ret, rec ? rec->ip : 0);
+	printk(KERN_WARNING "Failed on %s (%d):\n", report, count);
+	for_ftrace_rec_iter(iter) {
+		rec = ftrace_rec_iter_record(iter);
+		remove_breakpoint(rec);
+	}
+}
+
+void arch_ftrace_update_code(int command)
+{
+	modifying_ftrace_code++;
+
+	ftrace_modify_all_code(command);
+
+	modifying_ftrace_code--;
+}
+
 int __init ftrace_dyn_arch_init(void *data)
 {
 	/* The return code is retured via data */
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index ce0be7c..463c979 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -21,6 +21,7 @@
 #include <asm/msr-index.h>
 #include <asm/cpufeature.h>
 #include <asm/percpu.h>
+#include <asm/nops.h>
 
 /* Physical address */
 #define pa(X) ((X) - __PAGE_OFFSET)
@@ -363,28 +364,23 @@
 	pushl $0
 	popfl
 
-#ifdef CONFIG_SMP
-	cmpb $0, ready
-	jnz checkCPUtype
-#endif /* CONFIG_SMP */
-
 /*
  * start system 32-bit setup. We need to re-do some of the things done
  * in 16-bit mode for the "real" operations.
  */
-	call setup_idt
-
-checkCPUtype:
-
-	movl $-1,X86_CPUID		#  -1 for no CPUID initially
-
+	movl setup_once_ref,%eax
+	andl %eax,%eax
+	jz 1f				# Did we do this already?
+	call *%eax
+1:
+	
 /* check if it is 486 or 386. */
 /*
  * XXX - this does a lot of unnecessary setup.  Alignment checks don't
  * apply at our cpl of 0 and the stack ought to be aligned already, and
  * we don't need to preserve eflags.
  */
-
+	movl $-1,X86_CPUID	# -1 for no CPUID initially
 	movb $3,X86		# at least 386
 	pushfl			# push EFLAGS
 	popl %eax		# get EFLAGS
@@ -450,21 +446,6 @@
 	movl $(__KERNEL_PERCPU), %eax
 	movl %eax,%fs			# set this cpu's percpu
 
-#ifdef CONFIG_CC_STACKPROTECTOR
-	/*
-	 * The linker can't handle this by relocation.  Manually set
-	 * base address in stack canary segment descriptor.
-	 */
-	cmpb $0,ready
-	jne 1f
-	movl $gdt_page,%eax
-	movl $stack_canary,%ecx
-	movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax)
-	shrl $16, %ecx
-	movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax)
-	movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax)
-1:
-#endif
 	movl $(__KERNEL_STACK_CANARY),%eax
 	movl %eax,%gs
 
@@ -473,7 +454,6 @@
 
 	cld			# gcc2 wants the direction flag cleared at all times
 	pushl $0		# fake return address for unwinder
-	movb $1, ready
 	jmp *(initial_code)
 
 /*
@@ -495,81 +475,122 @@
 	.byte 0xDB,0xE4		/* fsetpm for 287, ignored by 387 */
 	ret
 
+	
+#include "verify_cpu.S"
+
 /*
- *  setup_idt
+ *  setup_once
  *
- *  sets up a idt with 256 entries pointing to
- *  ignore_int, interrupt gates. It doesn't actually load
- *  idt - that can be done only after paging has been enabled
- *  and the kernel moved to PAGE_OFFSET. Interrupts
- *  are enabled elsewhere, when we can be relatively
- *  sure everything is ok.
+ *  The setup work we only want to run on the BSP.
  *
  *  Warning: %esi is live across this function.
  */
-setup_idt:
-	lea ignore_int,%edx
+__INIT
+setup_once:
+	/*
+	 * Set up a idt with 256 entries pointing to ignore_int,
+	 * interrupt gates. It doesn't actually load idt - that needs
+	 * to be done on each CPU. Interrupts are enabled elsewhere,
+	 * when we can be relatively sure everything is ok.
+	 */
+
+	movl $idt_table,%edi
+	movl $early_idt_handlers,%eax
+	movl $NUM_EXCEPTION_VECTORS,%ecx
+1:
+	movl %eax,(%edi)
+	movl %eax,4(%edi)
+	/* interrupt gate, dpl=0, present */
+	movl $(0x8E000000 + __KERNEL_CS),2(%edi)
+	addl $9,%eax
+	addl $8,%edi
+	loop 1b
+
+	movl $256 - NUM_EXCEPTION_VECTORS,%ecx
+	movl $ignore_int,%edx
 	movl $(__KERNEL_CS << 16),%eax
 	movw %dx,%ax		/* selector = 0x0010 = cs */
 	movw $0x8E00,%dx	/* interrupt gate - dpl=0, present */
-
-	lea idt_table,%edi
-	mov $256,%ecx
-rp_sidt:
+2:
 	movl %eax,(%edi)
 	movl %edx,4(%edi)
 	addl $8,%edi
-	dec %ecx
-	jne rp_sidt
+	loop 2b
 
-.macro	set_early_handler handler,trapno
-	lea \handler,%edx
-	movl $(__KERNEL_CS << 16),%eax
-	movw %dx,%ax
-	movw $0x8E00,%dx	/* interrupt gate - dpl=0, present */
-	lea idt_table,%edi
-	movl %eax,8*\trapno(%edi)
-	movl %edx,8*\trapno+4(%edi)
-.endm
+#ifdef CONFIG_CC_STACKPROTECTOR
+	/*
+	 * Configure the stack canary. The linker can't handle this by
+	 * relocation.  Manually set base address in stack canary
+	 * segment descriptor.
+	 */
+	movl $gdt_page,%eax
+	movl $stack_canary,%ecx
+	movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax)
+	shrl $16, %ecx
+	movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax)
+	movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax)
+#endif
 
-	set_early_handler handler=early_divide_err,trapno=0
-	set_early_handler handler=early_illegal_opcode,trapno=6
-	set_early_handler handler=early_protection_fault,trapno=13
-	set_early_handler handler=early_page_fault,trapno=14
-
+	andl $0,setup_once_ref	/* Once is enough, thanks */
 	ret
 
-early_divide_err:
-	xor %edx,%edx
-	pushl $0	/* fake errcode */
-	jmp early_fault
-
-early_illegal_opcode:
-	movl $6,%edx
-	pushl $0	/* fake errcode */
-	jmp early_fault
-
-early_protection_fault:
-	movl $13,%edx
-	jmp early_fault
-
-early_page_fault:
-	movl $14,%edx
-	jmp early_fault
-
-early_fault:
+ENTRY(early_idt_handlers)
+	# 36(%esp) %eflags
+	# 32(%esp) %cs
+	# 28(%esp) %eip
+	# 24(%rsp) error code
+	i = 0
+	.rept NUM_EXCEPTION_VECTORS
+	.if (EXCEPTION_ERRCODE_MASK >> i) & 1
+	ASM_NOP2
+	.else
+	pushl $0		# Dummy error code, to make stack frame uniform
+	.endif
+	pushl $i		# 20(%esp) Vector number
+	jmp early_idt_handler
+	i = i + 1
+	.endr
+ENDPROC(early_idt_handlers)
+	
+	/* This is global to keep gas from relaxing the jumps */
+ENTRY(early_idt_handler)
 	cld
-#ifdef CONFIG_PRINTK
-	pusha
+	cmpl $2,%ss:early_recursion_flag
+	je hlt_loop
+	incl %ss:early_recursion_flag
+
+	push %eax		# 16(%esp)
+	push %ecx		# 12(%esp)
+	push %edx		#  8(%esp)
+	push %ds		#  4(%esp)
+	push %es		#  0(%esp)
 	movl $(__KERNEL_DS),%eax
 	movl %eax,%ds
 	movl %eax,%es
-	cmpl $2,early_recursion_flag
-	je hlt_loop
-	incl early_recursion_flag
+
+	cmpl $(__KERNEL_CS),32(%esp)
+	jne 10f
+
+	leal 28(%esp),%eax	# Pointer to %eip
+	call early_fixup_exception
+	andl %eax,%eax
+	jnz ex_entry		/* found an exception entry */
+
+10:
+#ifdef CONFIG_PRINTK
+	xorl %eax,%eax
+	movw %ax,2(%esp)	/* clean up the segment values on some cpus */
+	movw %ax,6(%esp)
+	movw %ax,34(%esp)
+	leal  40(%esp),%eax
+	pushl %eax		/* %esp before the exception */
+	pushl %ebx
+	pushl %ebp
+	pushl %esi
+	pushl %edi
 	movl %cr2,%eax
 	pushl %eax
-	pushl %edx		/* trapno */
+	pushl (20+6*4)(%esp)	/* trapno */
 	pushl $fault_msg
 	call printk
 #endif
@@ -578,6 +599,17 @@
 	hlt
 	jmp hlt_loop
 
+ex_entry:
+	pop %es
+	pop %ds
+	pop %edx
+	pop %ecx
+	pop %eax
+	addl $8,%esp		/* drop vector number and error code */
+	decl %ss:early_recursion_flag
+	iret
+ENDPROC(early_idt_handler)
+
 /* This is the default interrupt "handler" :-) */
 	ALIGN
 ignore_int:
@@ -611,13 +643,18 @@
 	popl %eax
 #endif
 	iret
+ENDPROC(ignore_int)
+__INITDATA
+	.align 4
+early_recursion_flag:
+	.long 0
 
-#include "verify_cpu.S"
-
-	__REFDATA
-.align 4
+__REFDATA
+	.align 4
 ENTRY(initial_code)
 	.long i386_start_kernel
+ENTRY(setup_once_ref)
+	.long setup_once
 
 /*
  * BSS section
@@ -670,22 +707,19 @@
 ENTRY(stack_start)
 	.long init_thread_union+THREAD_SIZE
 
-early_recursion_flag:
-	.long 0
-
-ready:	.byte 0
-
+__INITRODATA
 int_msg:
 	.asciz "Unknown interrupt or fault at: %p %p %p\n"
 
 fault_msg:
 /* fault info: */
 	.ascii "BUG: Int %d: CR2 %p\n"
-/* pusha regs: */
-	.ascii "     EDI %p  ESI %p  EBP %p  ESP %p\n"
-	.ascii "     EBX %p  EDX %p  ECX %p  EAX %p\n"
+/* regs pushed in early_idt_handler: */
+	.ascii "     EDI %p  ESI %p  EBP %p  EBX %p\n"
+	.ascii "     ESP %p   ES %p   DS %p\n"
+	.ascii "     EDX %p  ECX %p  EAX %p\n"
 /* fault frame: */
-	.ascii "     err %p  EIP %p   CS %p  flg %p\n"
+	.ascii "     vec %p  err %p  EIP %p   CS %p  flg %p\n"
 	.ascii "Stack: %p %p %p %p %p %p %p %p\n"
 	.ascii "       %p %p %p %p %p %p %p %p\n"
 	.asciz "       %p %p %p %p %p %p %p %p\n"
@@ -699,6 +733,7 @@
  * segment size, and 32-bit linear address value:
  */
 
+	.data
 .globl boot_gdt_descr
 .globl idt_descr
 
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 40f4eb3..7a40f24 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -19,12 +19,15 @@
 #include <asm/cache.h>
 #include <asm/processor-flags.h>
 #include <asm/percpu.h>
+#include <asm/nops.h>
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/asm-offsets.h>
 #include <asm/paravirt.h>
+#define GET_CR2_INTO(reg) GET_CR2_INTO_RAX ; movq %rax, reg
 #else
-#define GET_CR2_INTO_RCX movq %cr2, %rcx
+#define GET_CR2_INTO(reg) movq %cr2, reg
+#define INTERRUPT_RETURN iretq
 #endif
 
 /* we are not able to switch in one step to the final KERNEL ADDRESS SPACE
@@ -270,36 +273,56 @@
 	jmp bad_address
 
 	.section ".init.text","ax"
-#ifdef CONFIG_EARLY_PRINTK
 	.globl early_idt_handlers
 early_idt_handlers:
+	# 104(%rsp) %rflags
+	#  96(%rsp) %cs
+	#  88(%rsp) %rip
+	#  80(%rsp) error code
 	i = 0
 	.rept NUM_EXCEPTION_VECTORS
-	movl $i, %esi
+	.if (EXCEPTION_ERRCODE_MASK >> i) & 1
+	ASM_NOP2
+	.else
+	pushq $0		# Dummy error code, to make stack frame uniform
+	.endif
+	pushq $i		# 72(%rsp) Vector number
 	jmp early_idt_handler
 	i = i + 1
 	.endr
-#endif
 
 ENTRY(early_idt_handler)
-#ifdef CONFIG_EARLY_PRINTK
+	cld
+
 	cmpl $2,early_recursion_flag(%rip)
 	jz  1f
 	incl early_recursion_flag(%rip)
-	GET_CR2_INTO_RCX
-	movq %rcx,%r9
-	xorl %r8d,%r8d		# zero for error code
-	movl %esi,%ecx		# get vector number
-	# Test %ecx against mask of vectors that push error code.
-	cmpl $31,%ecx
-	ja 0f
-	movl $1,%eax
-	salq %cl,%rax
-	testl $0x27d00,%eax
-	je 0f
-	popq %r8		# get error code
-0:	movq 0(%rsp),%rcx	# get ip
-	movq 8(%rsp),%rdx	# get cs
+
+	pushq %rax		# 64(%rsp)
+	pushq %rcx		# 56(%rsp)
+	pushq %rdx		# 48(%rsp)
+	pushq %rsi		# 40(%rsp)
+	pushq %rdi		# 32(%rsp)
+	pushq %r8		# 24(%rsp)
+	pushq %r9		# 16(%rsp)
+	pushq %r10		#  8(%rsp)
+	pushq %r11		#  0(%rsp)
+
+	cmpl $__KERNEL_CS,96(%rsp)
+	jne 10f
+
+	leaq 88(%rsp),%rdi	# Pointer to %rip
+	call early_fixup_exception
+	andl %eax,%eax
+	jnz 20f			# Found an exception entry
+
+10:
+#ifdef CONFIG_EARLY_PRINTK
+	GET_CR2_INTO(%r9)	# can clobber any volatile register if pv
+	movl 80(%rsp),%r8d	# error code
+	movl 72(%rsp),%esi	# vector number
+	movl 96(%rsp),%edx	# %cs
+	movq 88(%rsp),%rcx	# %rip
 	xorl %eax,%eax
 	leaq early_idt_msg(%rip),%rdi
 	call early_printk
@@ -308,17 +331,32 @@
 	call dump_stack
 #ifdef CONFIG_KALLSYMS	
 	leaq early_idt_ripmsg(%rip),%rdi
-	movq 0(%rsp),%rsi	# get rip again
+	movq 40(%rsp),%rsi	# %rip again
 	call __print_symbol
 #endif
 #endif /* EARLY_PRINTK */
 1:	hlt
 	jmp 1b
 
-#ifdef CONFIG_EARLY_PRINTK
+20:	# Exception table entry found
+	popq %r11
+	popq %r10
+	popq %r9
+	popq %r8
+	popq %rdi
+	popq %rsi
+	popq %rdx
+	popq %rcx
+	popq %rax
+	addq $16,%rsp		# drop vector number and error code
+	decl early_recursion_flag(%rip)
+	INTERRUPT_RETURN
+
+	.balign 4
 early_recursion_flag:
 	.long 0
 
+#ifdef CONFIG_EARLY_PRINTK
 early_idt_msg:
 	.asciz "PANIC: early exception %02lx rip %lx:%lx error %lx cr2 %lx\n"
 early_idt_ripmsg:
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 2d6e649..f250431 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -88,7 +88,7 @@
 		__thread_clear_has_fpu(me);
 		/* We do 'stts()' in kernel_fpu_end() */
 	} else {
-		percpu_write(fpu_owner_task, NULL);
+		this_cpu_write(fpu_owner_task, NULL);
 		clts();
 	}
 }
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index e213fc8..e2f751e 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -1037,9 +1037,9 @@
 			       "current sp %p does not match saved sp %p\n",
 			       stack_addr(regs), kcb->jprobe_saved_sp);
 			printk(KERN_ERR "Saved registers for jprobe %p\n", jp);
-			show_registers(saved_regs);
+			show_regs(saved_regs);
 			printk(KERN_ERR "Current registers\n");
-			show_registers(regs);
+			show_regs(regs);
 			BUG();
 		}
 		*regs = kcb->jprobe_saved_regs;
diff --git a/arch/x86/kernel/mca_32.c b/arch/x86/kernel/mca_32.c
deleted file mode 100644
index 7eb1e2b..0000000
--- a/arch/x86/kernel/mca_32.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- *  Written by Martin Kolinek, February 1996
- *
- * Changes:
- *
- *	Chris Beauregard July 28th, 1996
- *	- Fixed up integrated SCSI detection
- *
- *	Chris Beauregard August 3rd, 1996
- *	- Made mca_info local
- *	- Made integrated registers accessible through standard function calls
- *	- Added name field
- *	- More sanity checking
- *
- *	Chris Beauregard August 9th, 1996
- *	- Rewrote /proc/mca
- *
- *	Chris Beauregard January 7th, 1997
- *	- Added basic NMI-processing
- *	- Added more information to mca_info structure
- *
- *	David Weinehall October 12th, 1998
- *	- Made a lot of cleaning up in the source
- *	- Added use of save_flags / restore_flags
- *	- Added the 'driver_loaded' flag in MCA_adapter
- *	- Added an alternative implemention of ZP Gu's mca_find_unused_adapter
- *
- *	David Weinehall March 24th, 1999
- *	- Fixed the output of 'Driver Installed' in /proc/mca/pos
- *	- Made the Integrated Video & SCSI show up even if they have id 0000
- *
- *	Alexander Viro November 9th, 1999
- *	- Switched to regular procfs methods
- *
- *	Alfred Arnold & David Weinehall August 23rd, 2000
- *	- Added support for Planar POS-registers
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/mca.h>
-#include <linux/kprobes.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <linux/proc_fs.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <linux/init.h>
-
-static unsigned char which_scsi;
-
-int MCA_bus;
-EXPORT_SYMBOL(MCA_bus);
-
-/*
- * Motherboard register spinlock. Untested on SMP at the moment, but
- * are there any MCA SMP boxes?
- *
- * Yes - Alan
- */
-static DEFINE_SPINLOCK(mca_lock);
-
-/* Build the status info for the adapter */
-
-static void mca_configure_adapter_status(struct mca_device *mca_dev)
-{
-	mca_dev->status = MCA_ADAPTER_NONE;
-
-	mca_dev->pos_id = mca_dev->pos[0]
-		+ (mca_dev->pos[1] << 8);
-
-	if (!mca_dev->pos_id && mca_dev->slot < MCA_MAX_SLOT_NR) {
-
-		/*
-		 * id = 0x0000 usually indicates hardware failure,
-		 * however, ZP Gu (zpg@castle.net> reports that his 9556
-		 * has 0x0000 as id and everything still works. There
-		 * also seem to be an adapter with id = 0x0000; the
-		 * NCR Parallel Bus Memory Card. Until this is confirmed,
-		 * however, this code will stay.
-		 */
-
-		mca_dev->status = MCA_ADAPTER_ERROR;
-
-		return;
-	} else if (mca_dev->pos_id != 0xffff) {
-
-		/*
-		 * 0xffff usually indicates that there's no adapter,
-		 * however, some integrated adapters may have 0xffff as
-		 * their id and still be valid. Examples are on-board
-		 * VGA of the 55sx, the integrated SCSI of the 56 & 57,
-		 * and possibly also the 95 ULTIMEDIA.
-		 */
-
-		mca_dev->status = MCA_ADAPTER_NORMAL;
-	}
-
-	if ((mca_dev->pos_id == 0xffff ||
-	    mca_dev->pos_id == 0x0000) && mca_dev->slot >= MCA_MAX_SLOT_NR) {
-		int j;
-
-		for (j = 2; j < 8; j++) {
-			if (mca_dev->pos[j] != 0xff) {
-				mca_dev->status = MCA_ADAPTER_NORMAL;
-				break;
-			}
-		}
-	}
-
-	if (!(mca_dev->pos[2] & MCA_ENABLED)) {
-
-		/* enabled bit is in POS 2 */
-
-		mca_dev->status = MCA_ADAPTER_DISABLED;
-	}
-} /* mca_configure_adapter_status */
-
-/*--------------------------------------------------------------------*/
-
-static struct resource mca_standard_resources[] = {
-	{ .start = 0x60, .end = 0x60, .name = "system control port B (MCA)" },
-	{ .start = 0x90, .end = 0x90, .name = "arbitration (MCA)" },
-	{ .start = 0x91, .end = 0x91, .name = "card Select Feedback (MCA)" },
-	{ .start = 0x92, .end = 0x92, .name = "system Control port A (MCA)" },
-	{ .start = 0x94, .end = 0x94, .name = "system board setup (MCA)" },
-	{ .start = 0x96, .end = 0x97, .name = "POS (MCA)" },
-	{ .start = 0x100, .end = 0x107, .name = "POS (MCA)" }
-};
-
-#define MCA_STANDARD_RESOURCES	ARRAY_SIZE(mca_standard_resources)
-
-/*
- *	mca_read_and_store_pos - read the POS registers into a memory buffer
- *      @pos: a char pointer to 8 bytes, contains the POS register value on
- *            successful return
- *
- *	Returns 1 if a card actually exists (i.e. the pos isn't
- *	all 0xff) or 0 otherwise
- */
-static int mca_read_and_store_pos(unsigned char *pos)
-{
-	int j;
-	int found = 0;
-
-	for (j = 0; j < 8; j++) {
-		pos[j] = inb_p(MCA_POS_REG(j));
-		if (pos[j] != 0xff) {
-			/* 0xff all across means no device. 0x00 means
-			 * something's broken, but a device is
-			 * probably there.  However, if you get 0x00
-			 * from a motherboard register it won't matter
-			 * what we find.  For the record, on the
-			 * 57SLC, the integrated SCSI adapter has
-			 * 0xffff for the adapter ID, but nonzero for
-			 * other registers.  */
-
-			found = 1;
-		}
-	}
-	return found;
-}
-
-static unsigned char mca_pc_read_pos(struct mca_device *mca_dev, int reg)
-{
-	unsigned char byte;
-	unsigned long flags;
-
-	if (reg < 0 || reg >= 8)
-		return 0;
-
-	spin_lock_irqsave(&mca_lock, flags);
-	if (mca_dev->pos_register) {
-		/* Disable adapter setup, enable motherboard setup */
-
-		outb_p(0, MCA_ADAPTER_SETUP_REG);
-		outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
-
-		byte = inb_p(MCA_POS_REG(reg));
-		outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
-	} else {
-
-		/* Make sure motherboard setup is off */
-
-		outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
-
-		/* Read the appropriate register */
-
-		outb_p(0x8|(mca_dev->slot & 0xf), MCA_ADAPTER_SETUP_REG);
-		byte = inb_p(MCA_POS_REG(reg));
-		outb_p(0, MCA_ADAPTER_SETUP_REG);
-	}
-	spin_unlock_irqrestore(&mca_lock, flags);
-
-	mca_dev->pos[reg] = byte;
-
-	return byte;
-}
-
-static void mca_pc_write_pos(struct mca_device *mca_dev, int reg,
-			     unsigned char byte)
-{
-	unsigned long flags;
-
-	if (reg < 0 || reg >= 8)
-		return;
-
-	spin_lock_irqsave(&mca_lock, flags);
-
-	/* Make sure motherboard setup is off */
-
-	outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
-
-	/* Read in the appropriate register */
-
-	outb_p(0x8|(mca_dev->slot&0xf), MCA_ADAPTER_SETUP_REG);
-	outb_p(byte, MCA_POS_REG(reg));
-	outb_p(0, MCA_ADAPTER_SETUP_REG);
-
-	spin_unlock_irqrestore(&mca_lock, flags);
-
-	/* Update the global register list, while we have the byte */
-
-	mca_dev->pos[reg] = byte;
-
-}
-
-/* for the primary MCA bus, we have identity transforms */
-static int mca_dummy_transform_irq(struct mca_device *mca_dev, int irq)
-{
-	return irq;
-}
-
-static int mca_dummy_transform_ioport(struct mca_device *mca_dev, int port)
-{
-	return port;
-}
-
-static void *mca_dummy_transform_memory(struct mca_device *mca_dev, void *mem)
-{
-	return mem;
-}
-
-
-static int __init mca_init(void)
-{
-	unsigned int i, j;
-	struct mca_device *mca_dev;
-	unsigned char pos[8];
-	short mca_builtin_scsi_ports[] = {0xf7, 0xfd, 0x00};
-	struct mca_bus *bus;
-
-	/*
-	 * WARNING: Be careful when making changes here. Putting an adapter
-	 * and the motherboard simultaneously into setup mode may result in
-	 * damage to chips (according to The Indispensable PC Hardware Book
-	 * by Hans-Peter Messmer). Also, we disable system interrupts (so
-	 * that we are not disturbed in the middle of this).
-	 */
-
-	/* Make sure the MCA bus is present */
-
-	if (mca_system_init()) {
-		printk(KERN_ERR "MCA bus system initialisation failed\n");
-		return -ENODEV;
-	}
-
-	if (!MCA_bus)
-		return -ENODEV;
-
-	printk(KERN_INFO "Micro Channel bus detected.\n");
-
-	/* All MCA systems have at least a primary bus */
-	bus = mca_attach_bus(MCA_PRIMARY_BUS);
-	if (!bus)
-		goto out_nomem;
-	bus->default_dma_mask = 0xffffffffLL;
-	bus->f.mca_write_pos = mca_pc_write_pos;
-	bus->f.mca_read_pos = mca_pc_read_pos;
-	bus->f.mca_transform_irq = mca_dummy_transform_irq;
-	bus->f.mca_transform_ioport = mca_dummy_transform_ioport;
-	bus->f.mca_transform_memory = mca_dummy_transform_memory;
-
-	/* get the motherboard device */
-	mca_dev = kzalloc(sizeof(struct mca_device), GFP_KERNEL);
-	if (unlikely(!mca_dev))
-		goto out_nomem;
-
-	/*
-	 * We do not expect many MCA interrupts during initialization,
-	 * but let us be safe:
-	 */
-	spin_lock_irq(&mca_lock);
-
-	/* Make sure adapter setup is off */
-
-	outb_p(0, MCA_ADAPTER_SETUP_REG);
-
-	/* Read motherboard POS registers */
-
-	mca_dev->pos_register = 0x7f;
-	outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
-	mca_dev->name[0] = 0;
-	mca_read_and_store_pos(mca_dev->pos);
-	mca_configure_adapter_status(mca_dev);
-	/* fake POS and slot for a motherboard */
-	mca_dev->pos_id = MCA_MOTHERBOARD_POS;
-	mca_dev->slot = MCA_MOTHERBOARD;
-	mca_register_device(MCA_PRIMARY_BUS, mca_dev);
-
-	mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
-	if (unlikely(!mca_dev))
-		goto out_unlock_nomem;
-
-	/* Put motherboard into video setup mode, read integrated video
-	 * POS registers, and turn motherboard setup off.
-	 */
-
-	mca_dev->pos_register = 0xdf;
-	outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
-	mca_dev->name[0] = 0;
-	mca_read_and_store_pos(mca_dev->pos);
-	mca_configure_adapter_status(mca_dev);
-	/* fake POS and slot for the integrated video */
-	mca_dev->pos_id = MCA_INTEGVIDEO_POS;
-	mca_dev->slot = MCA_INTEGVIDEO;
-	mca_register_device(MCA_PRIMARY_BUS, mca_dev);
-
-	/*
-	 * Put motherboard into scsi setup mode, read integrated scsi
-	 * POS registers, and turn motherboard setup off.
-	 *
-	 * It seems there are two possible SCSI registers. Martin says that
-	 * for the 56,57, 0xf7 is the one, but fails on the 76.
-	 * Alfredo (apena@vnet.ibm.com) says
-	 * 0xfd works on his machine. We'll try both of them. I figure it's
-	 * a good bet that only one could be valid at a time. This could
-	 * screw up though if one is used for something else on the other
-	 * machine.
-	 */
-
-	for (i = 0; (which_scsi = mca_builtin_scsi_ports[i]) != 0; i++) {
-		outb_p(which_scsi, MCA_MOTHERBOARD_SETUP_REG);
-		if (mca_read_and_store_pos(pos))
-			break;
-	}
-	if (which_scsi) {
-		/* found a scsi card */
-		mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
-		if (unlikely(!mca_dev))
-			goto out_unlock_nomem;
-
-		for (j = 0; j < 8; j++)
-			mca_dev->pos[j] = pos[j];
-
-		mca_configure_adapter_status(mca_dev);
-		/* fake POS and slot for integrated SCSI controller */
-		mca_dev->pos_id = MCA_INTEGSCSI_POS;
-		mca_dev->slot = MCA_INTEGSCSI;
-		mca_dev->pos_register = which_scsi;
-		mca_register_device(MCA_PRIMARY_BUS, mca_dev);
-	}
-
-	/* Turn off motherboard setup */
-
-	outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
-
-	/*
-	 * Now loop over MCA slots: put each adapter into setup mode, and
-	 * read its POS registers. Then put adapter setup off.
-	 */
-
-	for (i = 0; i < MCA_MAX_SLOT_NR; i++) {
-		outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG);
-		if (!mca_read_and_store_pos(pos))
-			continue;
-
-		mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
-		if (unlikely(!mca_dev))
-			goto out_unlock_nomem;
-
-		for (j = 0; j < 8; j++)
-			mca_dev->pos[j] = pos[j];
-
-		mca_dev->driver_loaded = 0;
-		mca_dev->slot = i;
-		mca_dev->pos_register = 0;
-		mca_configure_adapter_status(mca_dev);
-		mca_register_device(MCA_PRIMARY_BUS, mca_dev);
-	}
-	outb_p(0, MCA_ADAPTER_SETUP_REG);
-
-	/* Enable interrupts and return memory start */
-	spin_unlock_irq(&mca_lock);
-
-	for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
-		request_resource(&ioport_resource, mca_standard_resources + i);
-
-	mca_do_proc_init();
-
-	return 0;
-
- out_unlock_nomem:
-	spin_unlock_irq(&mca_lock);
- out_nomem:
-	printk(KERN_EMERG "Failed memory allocation in MCA setup!\n");
-	return -ENOMEM;
-}
-
-subsys_initcall(mca_init);
-
-/*--------------------------------------------------------------------*/
-
-static __kprobes void
-mca_handle_nmi_device(struct mca_device *mca_dev, int check_flag)
-{
-	int slot = mca_dev->slot;
-
-	if (slot == MCA_INTEGSCSI) {
-		printk(KERN_CRIT "NMI: caused by MCA integrated SCSI adapter (%s)\n",
-			mca_dev->name);
-	} else if (slot == MCA_INTEGVIDEO) {
-		printk(KERN_CRIT "NMI: caused by MCA integrated video adapter (%s)\n",
-			mca_dev->name);
-	} else if (slot == MCA_MOTHERBOARD) {
-		printk(KERN_CRIT "NMI: caused by motherboard (%s)\n",
-			mca_dev->name);
-	}
-
-	/* More info available in POS 6 and 7? */
-
-	if (check_flag) {
-		unsigned char pos6, pos7;
-
-		pos6 = mca_device_read_pos(mca_dev, 6);
-		pos7 = mca_device_read_pos(mca_dev, 7);
-
-		printk(KERN_CRIT "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7);
-	}
-
-} /* mca_handle_nmi_slot */
-
-/*--------------------------------------------------------------------*/
-
-static int __kprobes mca_handle_nmi_callback(struct device *dev, void *data)
-{
-	struct mca_device *mca_dev = to_mca_device(dev);
-	unsigned char pos5;
-
-	pos5 = mca_device_read_pos(mca_dev, 5);
-
-	if (!(pos5 & 0x80)) {
-		/*
-		 *  Bit 7 of POS 5 is reset when this adapter has a hardware
-		 * error. Bit 7 it reset if there's error information
-		 * available in POS 6 and 7.
-		 */
-		mca_handle_nmi_device(mca_dev, !(pos5 & 0x40));
-		return 1;
-	}
-	return 0;
-}
-
-void __kprobes mca_handle_nmi(void)
-{
-	/*
-	 *  First try - scan the various adapters and see if a specific
-	 * adapter was responsible for the error.
-	 */
-	bus_for_each_dev(&mca_bus_type, NULL, NULL, mca_handle_nmi_callback);
-}
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index c9bda6d..fbdfc69 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -299,12 +299,11 @@
 {
 	unsigned long val;
 	int cpu = dev->id;
-	int ret = 0;
-	char *end;
+	ssize_t ret = 0;
 
-	val = simple_strtoul(buf, &end, 0);
-	if (end == buf)
-		return -EINVAL;
+	ret = kstrtoul(buf, 0, &val);
+	if (ret)
+		return ret;
 
 	if (val == 1) {
 		get_online_cpus();
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index ca470e4..b02d4dd 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -97,7 +97,7 @@
 
 	set_bit(m->busid, mp_bus_not_pci);
 	if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA) - 1) == 0) {
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
+#ifdef CONFIG_EISA
 		mp_bus_id_to_type[m->busid] = MP_BUS_ISA;
 #endif
 	} else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) {
@@ -105,12 +105,10 @@
 			x86_init.mpparse.mpc_oem_pci_bus(m);
 
 		clear_bit(m->busid, mp_bus_not_pci);
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
+#ifdef CONFIG_EISA
 		mp_bus_id_to_type[m->busid] = MP_BUS_PCI;
 	} else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) {
 		mp_bus_id_to_type[m->busid] = MP_BUS_EISA;
-	} else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA) - 1) == 0) {
-		mp_bus_id_to_type[m->busid] = MP_BUS_MCA;
 #endif
 	} else
 		printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str);
@@ -368,9 +366,6 @@
 	case 3:
 		memcpy(bus.bustype, "EISA  ", 6);
 		break;
-	case 4:
-	case 7:
-		memcpy(bus.bustype, "MCA   ", 6);
 	}
 	MP_bus_info(&bus);
 	if (mpc_default_type > 4) {
@@ -623,7 +618,7 @@
 		return;
 	/*
 	 * If it is an SMP machine we should know now, unless the
-	 * configuration is in an EISA/MCA bus machine with an
+	 * configuration is in an EISA bus machine with an
 	 * extended bios data area.
 	 *
 	 * there is a real-mode segmented pointer pointing to the
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index 585be4b..9087527 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -19,8 +19,6 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 
-#include <linux/mca.h>
-
 #if defined(CONFIG_EDAC)
 #include <linux/edac.h>
 #endif
@@ -84,7 +82,7 @@
 
 #define nmi_to_desc(type) (&nmi_desc[type])
 
-static int notrace __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b)
+static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b)
 {
 	struct nmi_desc *desc = nmi_to_desc(type);
 	struct nmiaction *a;
@@ -166,7 +164,7 @@
 }
 EXPORT_SYMBOL_GPL(unregister_nmi_handler);
 
-static notrace __kprobes void
+static __kprobes void
 pci_serr_error(unsigned char reason, struct pt_regs *regs)
 {
 	/* check to see if anyone registered against these types of errors */
@@ -197,7 +195,7 @@
 	outb(reason, NMI_REASON_PORT);
 }
 
-static notrace __kprobes void
+static __kprobes void
 io_check_error(unsigned char reason, struct pt_regs *regs)
 {
 	unsigned long i;
@@ -209,7 +207,7 @@
 	pr_emerg(
 	"NMI: IOCK error (debug interrupt?) for reason %02x on CPU %d.\n",
 		 reason, smp_processor_id());
-	show_registers(regs);
+	show_regs(regs);
 
 	if (panic_on_io_nmi)
 		panic("NMI IOCK error: Not continuing");
@@ -228,7 +226,7 @@
 	outb(reason, NMI_REASON_PORT);
 }
 
-static notrace __kprobes void
+static __kprobes void
 unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 {
 	int handled;
@@ -247,16 +245,6 @@
 
 	__this_cpu_add(nmi_stats.unknown, 1);
 
-#ifdef CONFIG_MCA
-	/*
-	 * Might actually be able to figure out what the guilty party
-	 * is:
-	 */
-	if (MCA_bus) {
-		mca_handle_nmi();
-		return;
-	}
-#endif
 	pr_emerg("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
 		 reason, smp_processor_id());
 
@@ -270,7 +258,7 @@
 static DEFINE_PER_CPU(bool, swallow_nmi);
 static DEFINE_PER_CPU(unsigned long, last_nmi_rip);
 
-static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
+static __kprobes void default_do_nmi(struct pt_regs *regs)
 {
 	unsigned char reason = 0;
 	int handled;
diff --git a/arch/x86/kernel/nmi_selftest.c b/arch/x86/kernel/nmi_selftest.c
index 2c39dcd..e31bf8d 100644
--- a/arch/x86/kernel/nmi_selftest.c
+++ b/arch/x86/kernel/nmi_selftest.c
@@ -13,6 +13,7 @@
 #include <linux/cpumask.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/percpu.h>
 
 #include <asm/apic.h>
 #include <asm/nmi.h>
@@ -117,15 +118,15 @@
 		unexpected_testcase_failures++;
 
 		if (nmi_fail == FAILURE)
-			printk("FAILED |");
+			printk(KERN_CONT "FAILED |");
 		else if (nmi_fail == TIMEOUT)
-			printk("TIMEOUT|");
+			printk(KERN_CONT "TIMEOUT|");
 		else
-			printk("ERROR  |");
+			printk(KERN_CONT "ERROR  |");
 		dump_stack();
 	} else {
 		testcase_successes++;
-		printk("  ok  |");
+		printk(KERN_CONT "  ok  |");
 	}
 	testcase_total++;
 
@@ -150,10 +151,10 @@
 
 	print_testname("remote IPI");
 	dotest(remote_ipi, SUCCESS);
-	printk("\n");
+	printk(KERN_CONT "\n");
 	print_testname("local IPI");
 	dotest(local_ipi, SUCCESS);
-	printk("\n");
+	printk(KERN_CONT "\n");
 
 	cleanup_nmi_testsuite();
 
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index ab13760..9ce8859 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -241,16 +241,16 @@
 
 static inline void enter_lazy(enum paravirt_lazy_mode mode)
 {
-	BUG_ON(percpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
+	BUG_ON(this_cpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
 
-	percpu_write(paravirt_lazy_mode, mode);
+	this_cpu_write(paravirt_lazy_mode, mode);
 }
 
 static void leave_lazy(enum paravirt_lazy_mode mode)
 {
-	BUG_ON(percpu_read(paravirt_lazy_mode) != mode);
+	BUG_ON(this_cpu_read(paravirt_lazy_mode) != mode);
 
-	percpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
+	this_cpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
 }
 
 void paravirt_enter_lazy_mmu(void)
@@ -267,7 +267,7 @@
 {
 	BUG_ON(preemptible());
 
-	if (percpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
+	if (this_cpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
 		arch_leave_lazy_mmu_mode();
 		set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
 	}
@@ -289,7 +289,7 @@
 	if (in_interrupt())
 		return PARAVIRT_LAZY_NONE;
 
-	return percpu_read(paravirt_lazy_mode);
+	return this_cpu_read(paravirt_lazy_mode);
 }
 
 void arch_flush_lazy_mmu_mode(void)
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index d0b2fb9..b72838b 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -1480,8 +1480,9 @@
 static int __init calgary_parse_options(char *p)
 {
 	unsigned int bridge;
+	unsigned long val;
 	size_t len;
-	char* endp;
+	ssize_t ret;
 
 	while (*p) {
 		if (!strncmp(p, "64k", 3))
@@ -1512,10 +1513,11 @@
 				++p;
 			if (*p == '\0')
 				break;
-			bridge = simple_strtoul(p, &endp, 0);
-			if (p == endp)
+			ret = kstrtoul(p, 0, &val);
+			if (ret)
 				break;
 
+			bridge = val;
 			if (bridge < MAX_PHB_BUS_NUM) {
 				printk(KERN_INFO "Calgary: disabling "
 				       "translation for PHB %#x\n", bridge);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index e817315..735279e 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -56,10 +56,16 @@
 struct kmem_cache *task_xstate_cachep;
 EXPORT_SYMBOL_GPL(task_xstate_cachep);
 
+/*
+ * this gets called so that we can store lazy state into memory and copy the
+ * current task into the new thread.
+ */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	int ret;
 
+	unlazy_fpu(src);
+
 	*dst = *src;
 	if (fpu_allocated(&src->thread.fpu)) {
 		memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
@@ -89,6 +95,16 @@
 				  SLAB_PANIC | SLAB_NOTRACK, NULL);
 }
 
+static inline void drop_fpu(struct task_struct *tsk)
+{
+	/*
+	 * Forget coprocessor state..
+	 */
+	tsk->fpu_counter = 0;
+	clear_fpu(tsk);
+	clear_used_math();
+}
+
 /*
  * Free current thread data structures etc..
  */
@@ -111,12 +127,8 @@
 		put_cpu();
 		kfree(bp);
 	}
-}
 
-void show_regs(struct pt_regs *regs)
-{
-	show_registers(regs);
-	show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs), 0);
+	drop_fpu(me);
 }
 
 void show_regs_common(void)
@@ -151,12 +163,7 @@
 
 	flush_ptrace_hw_breakpoint(tsk);
 	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
-	/*
-	 * Forget coprocessor state..
-	 */
-	tsk->fpu_counter = 0;
-	clear_fpu(tsk);
-	clear_used_math();
+	drop_fpu(tsk);
 }
 
 static void hard_disable_TSC(void)
@@ -385,7 +392,7 @@
 #ifdef CONFIG_X86_64
 void enter_idle(void)
 {
-	percpu_write(is_idle, 1);
+	this_cpu_write(is_idle, 1);
 	atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
 }
 
@@ -582,9 +589,17 @@
 {
 	u32 eax, ebx, ecx, edx;
 
+	/* Use mwait if idle=mwait boot option is given */
 	if (boot_option_idle_override == IDLE_FORCE_MWAIT)
 		return 1;
 
+	/*
+	 * Any idle= boot option other than idle=mwait means that we must not
+	 * use mwait. Eg: idle=halt or idle=poll or idle=nomwait
+	 */
+	if (boot_option_idle_override != IDLE_NO_OVERRIDE)
+		return 0;
+
 	if (c->cpuid_level < MWAIT_INFO)
 		return 0;
 
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index ae68473..516fa18 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -126,15 +126,6 @@
 	release_vm86_irqs(dead_task);
 }
 
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
-	unlazy_fpu(tsk);
-}
-
 int copy_thread(unsigned long clone_flags, unsigned long sp,
 	unsigned long unused,
 	struct task_struct *p, struct pt_regs *regs)
@@ -302,7 +293,7 @@
 
 	switch_fpu_finish(next_p, fpu);
 
-	percpu_write(current_task, next_p);
+	this_cpu_write(current_task, next_p);
 
 	return prev_p;
 }
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 43d8b48..61cdf7f 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -145,15 +145,6 @@
 	return get_desc_base(&t->thread.tls_array[tls]);
 }
 
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
-	unlazy_fpu(tsk);
-}
-
 int copy_thread(unsigned long clone_flags, unsigned long sp,
 		unsigned long unused,
 	struct task_struct *p, struct pt_regs *regs)
@@ -237,7 +228,7 @@
 	current->thread.usersp	= new_sp;
 	regs->ip		= new_ip;
 	regs->sp		= new_sp;
-	percpu_write(old_rsp, new_sp);
+	this_cpu_write(old_rsp, new_sp);
 	regs->cs		= _cs;
 	regs->ss		= _ss;
 	regs->flags		= X86_EFLAGS_IF;
@@ -359,11 +350,11 @@
 	/*
 	 * Switch the PDA and FPU contexts.
 	 */
-	prev->usersp = percpu_read(old_rsp);
-	percpu_write(old_rsp, next->usersp);
-	percpu_write(current_task, next_p);
+	prev->usersp = this_cpu_read(old_rsp);
+	this_cpu_write(old_rsp, next->usersp);
+	this_cpu_write(current_task, next_p);
 
-	percpu_write(kernel_stack,
+	this_cpu_write(kernel_stack,
 		  (unsigned long)task_stack_page(next_p) +
 		  THREAD_SIZE - KERNEL_STACK_OFFSET);
 
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index d840e69..77215c2 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -39,7 +39,8 @@
 enum reboot_type reboot_type = BOOT_ACPI;
 int reboot_force;
 
-/* This variable is used privately to keep track of whether or not
+/*
+ * This variable is used privately to keep track of whether or not
  * reboot_type is still set to its default value (i.e., reboot= hasn't
  * been set on the command line).  This is needed so that we can
  * suppress DMI scanning for reboot quirks.  Without it, it's
@@ -51,7 +52,8 @@
 static int reboot_cpu = -1;
 #endif
 
-/* This is set if we need to go through the 'emergency' path.
+/*
+ * This is set if we need to go through the 'emergency' path.
  * When machine_emergency_restart() is called, we may be on
  * an inconsistent state and won't be able to do a clean cleanup
  */
@@ -60,22 +62,24 @@
 /* This is set by the PCI code if either type 1 or type 2 PCI is detected */
 bool port_cf9_safe = false;
 
-/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
-   warm   Don't set the cold reboot flag
-   cold   Set the cold reboot flag
-   bios   Reboot by jumping through the BIOS (only for X86_32)
-   smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
-   triple Force a triple fault (init)
-   kbd    Use the keyboard controller. cold reset (default)
-   acpi   Use the RESET_REG in the FADT
-   efi    Use efi reset_system runtime service
-   pci    Use the so-called "PCI reset register", CF9
-   force  Avoid anything that could hang.
+/*
+ * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
+ * warm   Don't set the cold reboot flag
+ * cold   Set the cold reboot flag
+ * bios   Reboot by jumping through the BIOS (only for X86_32)
+ * smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
+ * triple Force a triple fault (init)
+ * kbd    Use the keyboard controller. cold reset (default)
+ * acpi   Use the RESET_REG in the FADT
+ * efi    Use efi reset_system runtime service
+ * pci    Use the so-called "PCI reset register", CF9
+ * force  Avoid anything that could hang.
  */
 static int __init reboot_setup(char *str)
 {
 	for (;;) {
-		/* Having anything passed on the command line via
+		/*
+		 * Having anything passed on the command line via
 		 * reboot= will cause us to disable DMI checking
 		 * below.
 		 */
@@ -98,9 +102,11 @@
 				if (isdigit(*(str+2)))
 					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
 			}
-				/* we will leave sorting out the final value
-				   when we are ready to reboot, since we might not
-				   have detected BSP APIC ID or smp_num_cpu */
+			/*
+			 * We will leave sorting out the final value
+			 * when we are ready to reboot, since we might not
+			 * have detected BSP APIC ID or smp_num_cpu
+			 */
 			break;
 #endif /* CONFIG_SMP */
 
@@ -150,6 +156,82 @@
 	return 0;
 }
 
+extern const unsigned char machine_real_restart_asm[];
+extern const u64 machine_real_restart_gdt[3];
+
+void machine_real_restart(unsigned int type)
+{
+	void *restart_va;
+	unsigned long restart_pa;
+	void (*restart_lowmem)(unsigned int);
+	u64 *lowmem_gdt;
+
+	local_irq_disable();
+
+	/*
+	 * Write zero to CMOS register number 0x0f, which the BIOS POST
+	 * routine will recognize as telling it to do a proper reboot.  (Well
+	 * that's what this book in front of me says -- it may only apply to
+	 * the Phoenix BIOS though, it's not clear).  At the same time,
+	 * disable NMIs by setting the top bit in the CMOS address register,
+	 * as we're about to do peculiar things to the CPU.  I'm not sure if
+	 * `outb_p' is needed instead of just `outb'.  Use it to be on the
+	 * safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
+	 */
+	spin_lock(&rtc_lock);
+	CMOS_WRITE(0x00, 0x8f);
+	spin_unlock(&rtc_lock);
+
+	/*
+	 * Switch back to the initial page table.
+	 */
+	load_cr3(initial_page_table);
+
+	/*
+	 * Write 0x1234 to absolute memory location 0x472.  The BIOS reads
+	 * this on booting to tell it to "Bypass memory test (also warm
+	 * boot)".  This seems like a fairly standard thing that gets set by
+	 * REBOOT.COM programs, and the previous reset routine did this
+	 * too. */
+	*((unsigned short *)0x472) = reboot_mode;
+
+	/* Patch the GDT in the low memory trampoline */
+	lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
+
+	restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
+	restart_pa = virt_to_phys(restart_va);
+	restart_lowmem = (void (*)(unsigned int))restart_pa;
+
+	/* GDT[0]: GDT self-pointer */
+	lowmem_gdt[0] =
+		(u64)(sizeof(machine_real_restart_gdt) - 1) +
+		((u64)virt_to_phys(lowmem_gdt) << 16);
+	/* GDT[1]: 64K real mode code segment */
+	lowmem_gdt[1] =
+		GDT_ENTRY(0x009b, restart_pa, 0xffff);
+
+	/* Jump to the identity-mapped low memory code */
+	restart_lowmem(type);
+}
+#ifdef CONFIG_APM_MODULE
+EXPORT_SYMBOL(machine_real_restart);
+#endif
+
+#endif /* CONFIG_X86_32 */
+
+/*
+ * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
+ */
+static int __init set_pci_reboot(const struct dmi_system_id *d)
+{
+	if (reboot_type != BOOT_CF9) {
+		reboot_type = BOOT_CF9;
+		printk(KERN_INFO "%s series board detected. "
+		       "Selecting PCI-method for reboots.\n", d->ident);
+	}
+	return 0;
+}
+
 static int __init set_kbd_reboot(const struct dmi_system_id *d)
 {
 	if (reboot_type != BOOT_KBD) {
@@ -159,7 +241,12 @@
 	return 0;
 }
 
+/*
+ * This is a single dmi_table handling all reboot quirks.  Note that
+ * REBOOT_BIOS is only available for 32bit
+ */
 static struct dmi_system_id __initdata reboot_dmi_table[] = {
+#ifdef CONFIG_X86_32
 	{	/* Handle problems with rebooting on Dell E520's */
 		.callback = set_bios_reboot,
 		.ident = "Dell E520",
@@ -184,7 +271,7 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
 		},
 	},
-	{       /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
+	{	/* Handle problems with rebooting on Dell Optiplex 745's SFF */
 		.callback = set_bios_reboot,
 		.ident = "Dell OptiPlex 745",
 		.matches = {
@@ -192,7 +279,7 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
 		},
 	},
-	{       /* Handle problems with rebooting on Dell Optiplex 745's DFF*/
+	{	/* Handle problems with rebooting on Dell Optiplex 745's DFF */
 		.callback = set_bios_reboot,
 		.ident = "Dell OptiPlex 745",
 		.matches = {
@@ -201,7 +288,7 @@
 			DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
 		},
 	},
-	{       /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
+	{	/* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
 		.callback = set_bios_reboot,
 		.ident = "Dell OptiPlex 745",
 		.matches = {
@@ -210,7 +297,7 @@
 			DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
 		},
 	},
-	{   /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
+	{	/* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
 		.callback = set_bios_reboot,
 		.ident = "Dell OptiPlex 330",
 		.matches = {
@@ -219,7 +306,7 @@
 			DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
 		},
 	},
-	{   /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
+	{	/* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
 		.callback = set_bios_reboot,
 		.ident = "Dell OptiPlex 360",
 		.matches = {
@@ -228,7 +315,7 @@
 			DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
 		},
 	},
-	{	/* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G*/
+	{	/* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */
 		.callback = set_bios_reboot,
 		.ident = "Dell OptiPlex 760",
 		.matches = {
@@ -301,7 +388,7 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
 		},
 	},
-	{       /* Handle problems with rebooting on ASUS P4S800 */
+	{	/* Handle problems with rebooting on ASUS P4S800 */
 		.callback = set_bios_reboot,
 		.ident = "ASUS P4S800",
 		.matches = {
@@ -309,7 +396,9 @@
 			DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
 		},
 	},
-	{ /* Handle reboot issue on Acer Aspire one */
+#endif /* CONFIG_X86_32 */
+
+	{	/* Handle reboot issue on Acer Aspire one */
 		.callback = set_kbd_reboot,
 		.ident = "Acer Aspire One A110",
 		.matches = {
@@ -317,96 +406,6 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
 		},
 	},
-	{ }
-};
-
-static int __init reboot_init(void)
-{
-	/* Only do the DMI check if reboot_type hasn't been overridden
-	 * on the command line
-	 */
-	if (reboot_default) {
-		dmi_check_system(reboot_dmi_table);
-	}
-	return 0;
-}
-core_initcall(reboot_init);
-
-extern const unsigned char machine_real_restart_asm[];
-extern const u64 machine_real_restart_gdt[3];
-
-void machine_real_restart(unsigned int type)
-{
-	void *restart_va;
-	unsigned long restart_pa;
-	void (*restart_lowmem)(unsigned int);
-	u64 *lowmem_gdt;
-
-	local_irq_disable();
-
-	/* Write zero to CMOS register number 0x0f, which the BIOS POST
-	   routine will recognize as telling it to do a proper reboot.  (Well
-	   that's what this book in front of me says -- it may only apply to
-	   the Phoenix BIOS though, it's not clear).  At the same time,
-	   disable NMIs by setting the top bit in the CMOS address register,
-	   as we're about to do peculiar things to the CPU.  I'm not sure if
-	   `outb_p' is needed instead of just `outb'.  Use it to be on the
-	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
-	 */
-	spin_lock(&rtc_lock);
-	CMOS_WRITE(0x00, 0x8f);
-	spin_unlock(&rtc_lock);
-
-	/*
-	 * Switch back to the initial page table.
-	 */
-	load_cr3(initial_page_table);
-
-	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
-	   this on booting to tell it to "Bypass memory test (also warm
-	   boot)".  This seems like a fairly standard thing that gets set by
-	   REBOOT.COM programs, and the previous reset routine did this
-	   too. */
-	*((unsigned short *)0x472) = reboot_mode;
-
-	/* Patch the GDT in the low memory trampoline */
-	lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
-
-	restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
-	restart_pa = virt_to_phys(restart_va);
-	restart_lowmem = (void (*)(unsigned int))restart_pa;
-
-	/* GDT[0]: GDT self-pointer */
-	lowmem_gdt[0] =
-		(u64)(sizeof(machine_real_restart_gdt) - 1) +
-		((u64)virt_to_phys(lowmem_gdt) << 16);
-	/* GDT[1]: 64K real mode code segment */
-	lowmem_gdt[1] =
-		GDT_ENTRY(0x009b, restart_pa, 0xffff);
-
-	/* Jump to the identity-mapped low memory code */
-	restart_lowmem(type);
-}
-#ifdef CONFIG_APM_MODULE
-EXPORT_SYMBOL(machine_real_restart);
-#endif
-
-#endif /* CONFIG_X86_32 */
-
-/*
- * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
- */
-static int __init set_pci_reboot(const struct dmi_system_id *d)
-{
-	if (reboot_type != BOOT_CF9) {
-		reboot_type = BOOT_CF9;
-		printk(KERN_INFO "%s series board detected. "
-		       "Selecting PCI-method for reboots.\n", d->ident);
-	}
-	return 0;
-}
-
-static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
 	{	/* Handle problems with rebooting on Apple MacBook5 */
 		.callback = set_pci_reboot,
 		.ident = "Apple MacBook5",
@@ -474,17 +473,17 @@
 	{ }
 };
 
-static int __init pci_reboot_init(void)
+static int __init reboot_init(void)
 {
-	/* Only do the DMI check if reboot_type hasn't been overridden
+	/*
+	 * Only do the DMI check if reboot_type hasn't been overridden
 	 * on the command line
 	 */
-	if (reboot_default) {
-		dmi_check_system(pci_reboot_dmi_table);
-	}
+	if (reboot_default)
+		dmi_check_system(reboot_dmi_table);
 	return 0;
 }
-core_initcall(pci_reboot_init);
+core_initcall(reboot_init);
 
 static inline void kb_wait(void)
 {
@@ -502,14 +501,14 @@
 	cpu_emergency_vmxoff();
 }
 
-/* Use NMIs as IPIs to tell all CPUs to disable virtualization
- */
+/* Use NMIs as IPIs to tell all CPUs to disable virtualization */
 static void emergency_vmx_disable_all(void)
 {
 	/* Just make sure we won't change CPUs while doing this */
 	local_irq_disable();
 
-	/* We need to disable VMX on all CPUs before rebooting, otherwise
+	/*
+	 * We need to disable VMX on all CPUs before rebooting, otherwise
 	 * we risk hanging up the machine, because the CPU ignore INIT
 	 * signals when VMX is enabled.
 	 *
@@ -528,8 +527,7 @@
 	 * is still enabling VMX.
 	 */
 	if (cpu_has_vmx() && cpu_vmx_enabled()) {
-		/* Disable VMX on this CPU.
-		 */
+		/* Disable VMX on this CPU. */
 		cpu_vmxoff();
 
 		/* Halt and disable VMX on the other CPUs */
@@ -574,12 +572,12 @@
 		/* Could also try the reset bit in the Hammer NB */
 		switch (reboot_type) {
 		case BOOT_KBD:
-			mach_reboot_fixups(); /* for board specific fixups */
+			mach_reboot_fixups(); /* For board specific fixups */
 
 			for (i = 0; i < 10; i++) {
 				kb_wait();
 				udelay(50);
-				outb(0xfe, 0x64); /* pulse reset low */
+				outb(0xfe, 0x64); /* Pulse reset low */
 				udelay(50);
 			}
 			if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
@@ -621,7 +619,7 @@
 
 		case BOOT_CF9:
 			port_cf9_safe = true;
-			/* fall through */
+			/* Fall through */
 
 		case BOOT_CF9_COND:
 			if (port_cf9_safe) {
@@ -659,7 +657,8 @@
 	/* Make certain I only run on the appropriate processor */
 	set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
 
-	/* O.K Now that I'm on the appropriate processor,
+	/*
+	 * O.K Now that I'm on the appropriate processor,
 	 * stop all of the others.
 	 */
 	stop_other_cpus();
@@ -697,12 +696,11 @@
 
 static void native_machine_halt(void)
 {
-	/* stop other cpus and apics */
+	/* Stop other cpus and apics */
 	machine_shutdown();
 
 	tboot_shutdown(TB_SHUTDOWN_HALT);
 
-	/* stop this cpu */
 	stop_this_cpu(NULL);
 }
 
@@ -713,7 +711,7 @@
 			machine_shutdown();
 		pm_power_off();
 	}
-	/* a fallback in case there is no PM info available */
+	/* A fallback in case there is no PM info available */
 	tboot_shutdown(TB_SHUTDOWN_HALT);
 }
 
@@ -775,7 +773,8 @@
 
 	cpu = raw_smp_processor_id();
 
-	/* Don't do anything if this handler is invoked on crashing cpu.
+	/*
+	 * Don't do anything if this handler is invoked on crashing cpu.
 	 * Otherwise, system will completely hang. Crashing cpu can get
 	 * an NMI if system was initially booted with nmi_watchdog parameter.
 	 */
@@ -799,7 +798,8 @@
 	apic->send_IPI_allbutself(NMI_VECTOR);
 }
 
-/* Halt all other CPUs, calling the specified function on each of them
+/*
+ * Halt all other CPUs, calling the specified function on each of them
  *
  * This function can be used to halt all other CPUs on crash
  * or emergency reboot time. The function passed as parameter
@@ -810,7 +810,7 @@
 	unsigned long msecs;
 	local_irq_disable();
 
-	/* Make a note of crashing cpu. Will be used in NMI callback.*/
+	/* Make a note of crashing cpu. Will be used in NMI callback. */
 	crashing_cpu = safe_smp_processor_id();
 
 	shootdown_callback = callback;
@@ -819,8 +819,9 @@
 	/* Would it be better to replace the trap vector here? */
 	if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
 				 NMI_FLAG_FIRST, "crash"))
-		return;		/* return what? */
-	/* Ensure the new callback function is set before sending
+		return;		/* Return what? */
+	/*
+	 * Ensure the new callback function is set before sending
 	 * out the NMI
 	 */
 	wmb();
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 1a29015..366c688 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -34,7 +34,6 @@
 #include <linux/memblock.h>
 #include <linux/seq_file.h>
 #include <linux/console.h>
-#include <linux/mca.h>
 #include <linux/root_dev.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
@@ -179,12 +178,6 @@
 /* common cpu data for all cpus */
 struct cpuinfo_x86 boot_cpu_data __read_mostly = {0, 0, 0, 0, -1, 1, 0, 0, -1};
 EXPORT_SYMBOL(boot_cpu_data);
-static void set_mca_bus(int x)
-{
-#ifdef CONFIG_MCA
-	MCA_bus = x;
-#endif
-}
 
 unsigned int def_to_bigsmp;
 
@@ -393,10 +386,9 @@
 	initrd_start = 0;
 
 	if (ramdisk_size >= (end_of_lowmem>>1)) {
-		memblock_free(ramdisk_image, ramdisk_end - ramdisk_image);
-		printk(KERN_ERR "initrd too large to handle, "
-		       "disabling initrd\n");
-		return;
+		panic("initrd too large to handle, "
+		       "disabling initrd (%lld needed, %lld available)\n",
+		       ramdisk_size, end_of_lowmem>>1);
 	}
 
 	printk(KERN_INFO "RAMDISK: %08llx - %08llx\n", ramdisk_image,
@@ -717,7 +709,6 @@
 	apm_info.bios = boot_params.apm_bios_info;
 	ist_info = boot_params.ist_info;
 	if (boot_params.sys_desc_table.length != 0) {
-		set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2);
 		machine_id = boot_params.sys_desc_table.table[0];
 		machine_submodel_id = boot_params.sys_desc_table.table[1];
 		BIOS_revision = boot_params.sys_desc_table.table[2];
@@ -1012,7 +1003,8 @@
 	init_cpu_to_node();
 
 	init_apic_mappings();
-	ioapic_and_gsi_init();
+	if (x86_io_apic_ops.init)
+		x86_io_apic_ops.init();
 
 	kvm_guest_init();
 
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 115eac4..965dfda 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -18,6 +18,7 @@
 #include <linux/personality.h>
 #include <linux/uaccess.h>
 #include <linux/user-return-notifier.h>
+#include <linux/uprobes.h>
 
 #include <asm/processor.h>
 #include <asm/ucontext.h>
@@ -478,18 +479,8 @@
 sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
 	sigset_t blocked;
-
-	current->saved_sigmask = current->blocked;
-
-	mask &= _BLOCKABLE;
 	siginitset(&blocked, mask);
-	set_current_blocked(&blocked);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-
-	set_restore_sigmask();
-	return -ERESTARTNOHAND;
+	return sigsuspend(&blocked);
 }
 
 asmlinkage int
@@ -824,6 +815,11 @@
 		mce_notify_process();
 #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
 
+	if (thread_info_flags & _TIF_UPROBE) {
+		clear_thread_flag(TIF_UPROBE);
+		uprobe_notify_resume(regs);
+	}
+
 	/* deal with pending signal delivery */
 	if (thread_info_flags & _TIF_SIGPENDING)
 		do_signal(regs);
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 66c74f4..48d2b7d 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -109,6 +109,9 @@
  *	about nothing of note with C stepping upwards.
  */
 
+static atomic_t stopping_cpu = ATOMIC_INIT(-1);
+static bool smp_no_nmi_ipi = false;
+
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
@@ -149,8 +152,6 @@
 	free_cpumask_var(allbutself);
 }
 
-static atomic_t stopping_cpu = ATOMIC_INIT(-1);
-
 static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
 {
 	/* We are registered on stopping cpu too, avoid spurious NMI */
@@ -162,47 +163,6 @@
 	return NMI_HANDLED;
 }
 
-static void native_nmi_stop_other_cpus(int wait)
-{
-	unsigned long flags;
-	unsigned long timeout;
-
-	if (reboot_force)
-		return;
-
-	/*
-	 * Use an own vector here because smp_call_function
-	 * does lots of things not suitable in a panic situation.
-	 */
-	if (num_online_cpus() > 1) {
-		/* did someone beat us here? */
-		if (atomic_cmpxchg(&stopping_cpu, -1, safe_smp_processor_id()) != -1)
-			return;
-
-		if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
-					 NMI_FLAG_FIRST, "smp_stop"))
-			/* Note: we ignore failures here */
-			return;
-
-		/* sync above data before sending NMI */
-		wmb();
-
-		apic->send_IPI_allbutself(NMI_VECTOR);
-
-		/*
-		 * Don't wait longer than a second if the caller
-		 * didn't ask us to wait.
-		 */
-		timeout = USEC_PER_SEC;
-		while (num_online_cpus() > 1 && (wait || timeout--))
-			udelay(1);
-	}
-
-	local_irq_save(flags);
-	disable_local_APIC();
-	local_irq_restore(flags);
-}
-
 /*
  * this function calls the 'stop' function on all other CPUs in the system.
  */
@@ -215,7 +175,7 @@
 	irq_exit();
 }
 
-static void native_irq_stop_other_cpus(int wait)
+static void native_stop_other_cpus(int wait)
 {
 	unsigned long flags;
 	unsigned long timeout;
@@ -226,13 +186,25 @@
 	/*
 	 * Use an own vector here because smp_call_function
 	 * does lots of things not suitable in a panic situation.
-	 * On most systems we could also use an NMI here,
-	 * but there are a few systems around where NMI
-	 * is problematic so stay with an non NMI for now
-	 * (this implies we cannot stop CPUs spinning with irq off
-	 * currently)
+	 */
+
+	/*
+	 * We start by using the REBOOT_VECTOR irq.
+	 * The irq is treated as a sync point to allow critical
+	 * regions of code on other cpus to release their spin locks
+	 * and re-enable irqs.  Jumping straight to an NMI might
+	 * accidentally cause deadlocks with further shutdown/panic
+	 * code.  By syncing, we give the cpus up to one second to
+	 * finish their work before we force them off with the NMI.
 	 */
 	if (num_online_cpus() > 1) {
+		/* did someone beat us here? */
+		if (atomic_cmpxchg(&stopping_cpu, -1, safe_smp_processor_id()) != -1)
+			return;
+
+		/* sync above data before sending IRQ */
+		wmb();
+
 		apic->send_IPI_allbutself(REBOOT_VECTOR);
 
 		/*
@@ -243,17 +215,37 @@
 		while (num_online_cpus() > 1 && (wait || timeout--))
 			udelay(1);
 	}
+	
+	/* if the REBOOT_VECTOR didn't work, try with the NMI */
+	if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi))  {
+		if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
+					 NMI_FLAG_FIRST, "smp_stop"))
+			/* Note: we ignore failures here */
+			/* Hope the REBOOT_IRQ is good enough */
+			goto finish;
 
+		/* sync above data before sending IRQ */
+		wmb();
+
+		pr_emerg("Shutting down cpus with NMI\n");
+
+		apic->send_IPI_allbutself(NMI_VECTOR);
+
+		/*
+		 * Don't wait longer than a 10 ms if the caller
+		 * didn't ask us to wait.
+		 */
+		timeout = USEC_PER_MSEC * 10;
+		while (num_online_cpus() > 1 && (wait || timeout--))
+			udelay(1);
+	}
+
+finish:
 	local_irq_save(flags);
 	disable_local_APIC();
 	local_irq_restore(flags);
 }
 
-static void native_smp_disable_nmi_ipi(void)
-{
-	smp_ops.stop_other_cpus = native_irq_stop_other_cpus;
-}
-
 /*
  * Reschedule call back.
  */
@@ -287,8 +279,8 @@
 
 static int __init nonmi_ipi_setup(char *str)
 {
-        native_smp_disable_nmi_ipi();
-        return 1;
+	smp_no_nmi_ipi = true;
+	return 1;
 }
 
 __setup("nonmi_ipi", nonmi_ipi_setup);
@@ -298,7 +290,7 @@
 	.smp_prepare_cpus	= native_smp_prepare_cpus,
 	.smp_cpus_done		= native_smp_cpus_done,
 
-	.stop_other_cpus	= native_nmi_stop_other_cpus,
+	.stop_other_cpus	= native_stop_other_cpus,
 	.smp_send_reschedule	= native_smp_send_reschedule,
 
 	.cpu_up			= native_cpu_up,
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 3acaf51..433529e 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -299,59 +299,90 @@
 		identify_secondary_cpu(c);
 }
 
-static void __cpuinit link_thread_siblings(int cpu1, int cpu2)
+static bool __cpuinit
+topology_sane(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o, const char *name)
 {
-	cpumask_set_cpu(cpu1, cpu_sibling_mask(cpu2));
-	cpumask_set_cpu(cpu2, cpu_sibling_mask(cpu1));
-	cpumask_set_cpu(cpu1, cpu_core_mask(cpu2));
-	cpumask_set_cpu(cpu2, cpu_core_mask(cpu1));
-	cpumask_set_cpu(cpu1, cpu_llc_shared_mask(cpu2));
-	cpumask_set_cpu(cpu2, cpu_llc_shared_mask(cpu1));
+	int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
+
+	return !WARN_ONCE(cpu_to_node(cpu1) != cpu_to_node(cpu2),
+		"sched: CPU #%d's %s-sibling CPU #%d is not on the same node! "
+		"[node: %d != %d]. Ignoring dependency.\n",
+		cpu1, name, cpu2, cpu_to_node(cpu1), cpu_to_node(cpu2));
 }
 
+#define link_mask(_m, c1, c2)						\
+do {									\
+	cpumask_set_cpu((c1), cpu_##_m##_mask(c2));			\
+	cpumask_set_cpu((c2), cpu_##_m##_mask(c1));			\
+} while (0)
+
+static bool __cpuinit match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+{
+	if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
+		int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
+
+		if (c->phys_proc_id == o->phys_proc_id &&
+		    per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2) &&
+		    c->compute_unit_id == o->compute_unit_id)
+			return topology_sane(c, o, "smt");
+
+	} else if (c->phys_proc_id == o->phys_proc_id &&
+		   c->cpu_core_id == o->cpu_core_id) {
+		return topology_sane(c, o, "smt");
+	}
+
+	return false;
+}
+
+static bool __cpuinit match_llc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+{
+	int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
+
+	if (per_cpu(cpu_llc_id, cpu1) != BAD_APICID &&
+	    per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2))
+		return topology_sane(c, o, "llc");
+
+	return false;
+}
+
+static bool __cpuinit match_mc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+{
+	if (c->phys_proc_id == o->phys_proc_id)
+		return topology_sane(c, o, "mc");
+
+	return false;
+}
 
 void __cpuinit set_cpu_sibling_map(int cpu)
 {
-	int i;
+	bool has_mc = boot_cpu_data.x86_max_cores > 1;
+	bool has_smt = smp_num_siblings > 1;
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	struct cpuinfo_x86 *o;
+	int i;
 
 	cpumask_set_cpu(cpu, cpu_sibling_setup_mask);
 
-	if (smp_num_siblings > 1) {
-		for_each_cpu(i, cpu_sibling_setup_mask) {
-			struct cpuinfo_x86 *o = &cpu_data(i);
-
-			if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
-				if (c->phys_proc_id == o->phys_proc_id &&
-				    per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i) &&
-				    c->compute_unit_id == o->compute_unit_id)
-					link_thread_siblings(cpu, i);
-			} else if (c->phys_proc_id == o->phys_proc_id &&
-				   c->cpu_core_id == o->cpu_core_id) {
-				link_thread_siblings(cpu, i);
-			}
-		}
-	} else {
+	if (!has_smt && !has_mc) {
 		cpumask_set_cpu(cpu, cpu_sibling_mask(cpu));
-	}
-
-	cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu));
-
-	if (__this_cpu_read(cpu_info.x86_max_cores) == 1) {
-		cpumask_copy(cpu_core_mask(cpu), cpu_sibling_mask(cpu));
+		cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu));
+		cpumask_set_cpu(cpu, cpu_core_mask(cpu));
 		c->booted_cores = 1;
 		return;
 	}
 
 	for_each_cpu(i, cpu_sibling_setup_mask) {
-		if (per_cpu(cpu_llc_id, cpu) != BAD_APICID &&
-		    per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i)) {
-			cpumask_set_cpu(i, cpu_llc_shared_mask(cpu));
-			cpumask_set_cpu(cpu, cpu_llc_shared_mask(i));
-		}
-		if (c->phys_proc_id == cpu_data(i).phys_proc_id) {
-			cpumask_set_cpu(i, cpu_core_mask(cpu));
-			cpumask_set_cpu(cpu, cpu_core_mask(i));
+		o = &cpu_data(i);
+
+		if ((i == cpu) || (has_smt && match_smt(c, o)))
+			link_mask(sibling, cpu, i);
+
+		if ((i == cpu) || (has_mc && match_llc(c, o)))
+			link_mask(llc_shared, cpu, i);
+
+		if ((i == cpu) || (has_mc && match_mc(c, o))) {
+			link_mask(core, cpu, i);
+
 			/*
 			 *  Does this new cpu bringup a new core?
 			 */
@@ -382,8 +413,7 @@
 	 * For perf, we return last level cache shared map.
 	 * And for power savings, we return cpu_core_map
 	 */
-	if ((sched_mc_power_savings || sched_smt_power_savings) &&
-	    !(cpu_has(c, X86_FEATURE_AMD_DCM)))
+	if (!(cpu_has(c, X86_FEATURE_AMD_DCM)))
 		return cpu_core_mask(cpu);
 	else
 		return cpu_llc_shared_mask(cpu);
diff --git a/arch/x86/kernel/test_rodata.c b/arch/x86/kernel/test_rodata.c
index c29e235..b79133a 100644
--- a/arch/x86/kernel/test_rodata.c
+++ b/arch/x86/kernel/test_rodata.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
+#include <asm/asm.h>
 
 int rodata_test(void)
 {
@@ -42,14 +43,7 @@
 		".section .fixup,\"ax\"\n"
 		"2:	jmp 1b\n"
 		".previous\n"
-		".section __ex_table,\"a\"\n"
-		"       .align 16\n"
-#ifdef CONFIG_X86_32
-		"	.long 0b,2b\n"
-#else
-		"	.quad 0b,2b\n"
-#endif
-		".previous"
+		_ASM_EXTABLE(0b,2b)
 		: [rslt] "=r" (result)
 		: [rodata_test] "r" (&rodata_test_data), [zero] "r" (0UL)
 	);
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index c6eba2b..24d3c91 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -14,7 +14,6 @@
 #include <linux/i8253.h>
 #include <linux/time.h>
 #include <linux/export.h>
-#include <linux/mca.h>
 
 #include <asm/vsyscall.h>
 #include <asm/x86_init.h>
@@ -58,11 +57,6 @@
 static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
 	global_clock_event->event_handler(global_clock_event);
-
-	/* MCA bus quirk: Acknowledge irq0 by setting bit 7 in port 0x61 */
-	if (MCA_bus)
-		outb_p(inb_p(0x61)| 0x80, 0x61);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index ff9281f1..ff08457 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -37,10 +37,6 @@
 #include <linux/eisa.h>
 #endif
 
-#ifdef CONFIG_MCA
-#include <linux/mca.h>
-#endif
-
 #if defined(CONFIG_EDAC)
 #include <linux/edac.h>
 #endif
@@ -50,6 +46,7 @@
 #include <asm/processor.h>
 #include <asm/debugreg.h>
 #include <linux/atomic.h>
+#include <asm/ftrace.h>
 #include <asm/traps.h>
 #include <asm/desc.h>
 #include <asm/i387.h>
@@ -303,8 +300,13 @@
 }
 
 /* May run on IST stack. */
-dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
+dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code)
 {
+#ifdef CONFIG_DYNAMIC_FTRACE
+	/* ftrace must be first, everything else may cause a recursive crash */
+	if (unlikely(modifying_ftrace_code) && ftrace_int3_handler(regs))
+		return;
+#endif
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
 	if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
 				SIGTRAP) == NOTIFY_STOP)
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
new file mode 100644
index 0000000..dc4e910
--- /dev/null
+++ b/arch/x86/kernel/uprobes.c
@@ -0,0 +1,674 @@
+/*
+ * User-space Probes (UProbes) for x86
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2008-2011
+ * Authors:
+ *	Srikar Dronamraju
+ *	Jim Keniston
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/uprobes.h>
+#include <linux/uaccess.h>
+
+#include <linux/kdebug.h>
+#include <asm/processor.h>
+#include <asm/insn.h>
+
+/* Post-execution fixups. */
+
+/* No fixup needed */
+#define UPROBE_FIX_NONE		0x0
+
+/* Adjust IP back to vicinity of actual insn */
+#define UPROBE_FIX_IP		0x1
+
+/* Adjust the return address of a call insn */
+#define UPROBE_FIX_CALL	0x2
+
+#define UPROBE_FIX_RIP_AX	0x8000
+#define UPROBE_FIX_RIP_CX	0x4000
+
+#define	UPROBE_TRAP_NR		UINT_MAX
+
+/* Adaptations for mhiramat x86 decoder v14. */
+#define OPCODE1(insn)		((insn)->opcode.bytes[0])
+#define OPCODE2(insn)		((insn)->opcode.bytes[1])
+#define OPCODE3(insn)		((insn)->opcode.bytes[2])
+#define MODRM_REG(insn)		X86_MODRM_REG(insn->modrm.value)
+
+#define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\
+	(((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) |   \
+	  (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) |   \
+	  (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) |   \
+	  (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf))    \
+	 << (row % 32))
+
+/*
+ * Good-instruction tables for 32-bit apps.  This is non-const and volatile
+ * to keep gcc from statically optimizing it out, as variable_test_bit makes
+ * some versions of gcc to think only *(unsigned long*) is used.
+ */
+static volatile u32 good_insns_32[256 / 32] = {
+	/*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f         */
+	/*      ----------------------------------------------         */
+	W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) | /* 00 */
+	W(0x10, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) , /* 10 */
+	W(0x20, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) | /* 20 */
+	W(0x30, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) , /* 30 */
+	W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */
+	W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */
+	W(0x60, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */
+	W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */
+	W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
+	W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */
+	W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */
+	W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
+	W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */
+	W(0xd0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
+	W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */
+	W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1)   /* f0 */
+	/*      ----------------------------------------------         */
+	/*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f         */
+};
+
+/* Using this for both 64-bit and 32-bit apps */
+static volatile u32 good_2byte_insns[256 / 32] = {
+	/*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f         */
+	/*      ----------------------------------------------         */
+	W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */
+	W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* 10 */
+	W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 20 */
+	W(0x30, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 30 */
+	W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */
+	W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */
+	W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 60 */
+	W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) , /* 70 */
+	W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
+	W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */
+	W(0xa0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1) | /* a0 */
+	W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
+	W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* c0 */
+	W(0xd0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
+	W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* e0 */
+	W(0xf0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)   /* f0 */
+	/*      ----------------------------------------------         */
+	/*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f         */
+};
+
+#ifdef CONFIG_X86_64
+/* Good-instruction tables for 64-bit apps */
+static volatile u32 good_insns_64[256 / 32] = {
+	/*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f         */
+	/*      ----------------------------------------------         */
+	W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 00 */
+	W(0x10, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 10 */
+	W(0x20, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 20 */
+	W(0x30, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 30 */
+	W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */
+	W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */
+	W(0x60, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */
+	W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */
+	W(0x80, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
+	W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */
+	W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */
+	W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
+	W(0xc0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */
+	W(0xd0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
+	W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */
+	W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1)   /* f0 */
+	/*      ----------------------------------------------         */
+	/*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f         */
+};
+#endif
+#undef W
+
+/*
+ * opcodes we'll probably never support:
+ *
+ *  6c-6d, e4-e5, ec-ed - in
+ *  6e-6f, e6-e7, ee-ef - out
+ *  cc, cd - int3, int
+ *  cf - iret
+ *  d6 - illegal instruction
+ *  f1 - int1/icebp
+ *  f4 - hlt
+ *  fa, fb - cli, sti
+ *  0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2
+ *
+ * invalid opcodes in 64-bit mode:
+ *
+ *  06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5
+ *  63 - we support this opcode in x86_64 but not in i386.
+ *
+ * opcodes we may need to refine support for:
+ *
+ *  0f - 2-byte instructions: For many of these instructions, the validity
+ *  depends on the prefix and/or the reg field.  On such instructions, we
+ *  just consider the opcode combination valid if it corresponds to any
+ *  valid instruction.
+ *
+ *  8f - Group 1 - only reg = 0 is OK
+ *  c6-c7 - Group 11 - only reg = 0 is OK
+ *  d9-df - fpu insns with some illegal encodings
+ *  f2, f3 - repnz, repz prefixes.  These are also the first byte for
+ *  certain floating-point instructions, such as addsd.
+ *
+ *  fe - Group 4 - only reg = 0 or 1 is OK
+ *  ff - Group 5 - only reg = 0-6 is OK
+ *
+ * others -- Do we need to support these?
+ *
+ *  0f - (floating-point?) prefetch instructions
+ *  07, 17, 1f - pop es, pop ss, pop ds
+ *  26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes --
+ *	but 64 and 65 (fs: and gs:) seem to be used, so we support them
+ *  67 - addr16 prefix
+ *  ce - into
+ *  f0 - lock prefix
+ */
+
+/*
+ * TODO:
+ * - Where necessary, examine the modrm byte and allow only valid instructions
+ * in the different Groups and fpu instructions.
+ */
+
+static bool is_prefix_bad(struct insn *insn)
+{
+	int i;
+
+	for (i = 0; i < insn->prefixes.nbytes; i++) {
+		switch (insn->prefixes.bytes[i]) {
+		case 0x26:	/* INAT_PFX_ES   */
+		case 0x2E:	/* INAT_PFX_CS   */
+		case 0x36:	/* INAT_PFX_DS   */
+		case 0x3E:	/* INAT_PFX_SS   */
+		case 0xF0:	/* INAT_PFX_LOCK */
+			return true;
+		}
+	}
+	return false;
+}
+
+static int validate_insn_32bits(struct arch_uprobe *auprobe, struct insn *insn)
+{
+	insn_init(insn, auprobe->insn, false);
+
+	/* Skip good instruction prefixes; reject "bad" ones. */
+	insn_get_opcode(insn);
+	if (is_prefix_bad(insn))
+		return -ENOTSUPP;
+
+	if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_32))
+		return 0;
+
+	if (insn->opcode.nbytes == 2) {
+		if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns))
+			return 0;
+	}
+
+	return -ENOTSUPP;
+}
+
+/*
+ * Figure out which fixups arch_uprobe_post_xol() will need to perform, and
+ * annotate arch_uprobe->fixups accordingly.  To start with,
+ * arch_uprobe->fixups is either zero or it reflects rip-related fixups.
+ */
+static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn)
+{
+	bool fix_ip = true, fix_call = false;	/* defaults */
+	int reg;
+
+	insn_get_opcode(insn);	/* should be a nop */
+
+	switch (OPCODE1(insn)) {
+	case 0xc3:		/* ret/lret */
+	case 0xcb:
+	case 0xc2:
+	case 0xca:
+		/* ip is correct */
+		fix_ip = false;
+		break;
+	case 0xe8:		/* call relative - Fix return addr */
+		fix_call = true;
+		break;
+	case 0x9a:		/* call absolute - Fix return addr, not ip */
+		fix_call = true;
+		fix_ip = false;
+		break;
+	case 0xff:
+		insn_get_modrm(insn);
+		reg = MODRM_REG(insn);
+		if (reg == 2 || reg == 3) {
+			/* call or lcall, indirect */
+			/* Fix return addr; ip is correct. */
+			fix_call = true;
+			fix_ip = false;
+		} else if (reg == 4 || reg == 5) {
+			/* jmp or ljmp, indirect */
+			/* ip is correct. */
+			fix_ip = false;
+		}
+		break;
+	case 0xea:		/* jmp absolute -- ip is correct */
+		fix_ip = false;
+		break;
+	default:
+		break;
+	}
+	if (fix_ip)
+		auprobe->fixups |= UPROBE_FIX_IP;
+	if (fix_call)
+		auprobe->fixups |= UPROBE_FIX_CALL;
+}
+
+#ifdef CONFIG_X86_64
+/*
+ * If arch_uprobe->insn doesn't use rip-relative addressing, return
+ * immediately.  Otherwise, rewrite the instruction so that it accesses
+ * its memory operand indirectly through a scratch register.  Set
+ * arch_uprobe->fixups and arch_uprobe->rip_rela_target_address
+ * accordingly.  (The contents of the scratch register will be saved
+ * before we single-step the modified instruction, and restored
+ * afterward.)
+ *
+ * We do this because a rip-relative instruction can access only a
+ * relatively small area (+/- 2 GB from the instruction), and the XOL
+ * area typically lies beyond that area.  At least for instructions
+ * that store to memory, we can't execute the original instruction
+ * and "fix things up" later, because the misdirected store could be
+ * disastrous.
+ *
+ * Some useful facts about rip-relative instructions:
+ *
+ *  - There's always a modrm byte.
+ *  - There's never a SIB byte.
+ *  - The displacement is always 4 bytes.
+ */
+static void
+handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn)
+{
+	u8 *cursor;
+	u8 reg;
+
+	if (mm->context.ia32_compat)
+		return;
+
+	auprobe->rip_rela_target_address = 0x0;
+	if (!insn_rip_relative(insn))
+		return;
+
+	/*
+	 * insn_rip_relative() would have decoded rex_prefix, modrm.
+	 * Clear REX.b bit (extension of MODRM.rm field):
+	 * we want to encode rax/rcx, not r8/r9.
+	 */
+	if (insn->rex_prefix.nbytes) {
+		cursor = auprobe->insn + insn_offset_rex_prefix(insn);
+		*cursor &= 0xfe;	/* Clearing REX.B bit */
+	}
+
+	/*
+	 * Point cursor at the modrm byte.  The next 4 bytes are the
+	 * displacement.  Beyond the displacement, for some instructions,
+	 * is the immediate operand.
+	 */
+	cursor = auprobe->insn + insn_offset_modrm(insn);
+	insn_get_length(insn);
+
+	/*
+	 * Convert from rip-relative addressing to indirect addressing
+	 * via a scratch register.  Change the r/m field from 0x5 (%rip)
+	 * to 0x0 (%rax) or 0x1 (%rcx), and squeeze out the offset field.
+	 */
+	reg = MODRM_REG(insn);
+	if (reg == 0) {
+		/*
+		 * The register operand (if any) is either the A register
+		 * (%rax, %eax, etc.) or (if the 0x4 bit is set in the
+		 * REX prefix) %r8.  In any case, we know the C register
+		 * is NOT the register operand, so we use %rcx (register
+		 * #1) for the scratch register.
+		 */
+		auprobe->fixups = UPROBE_FIX_RIP_CX;
+		/* Change modrm from 00 000 101 to 00 000 001. */
+		*cursor = 0x1;
+	} else {
+		/* Use %rax (register #0) for the scratch register. */
+		auprobe->fixups = UPROBE_FIX_RIP_AX;
+		/* Change modrm from 00 xxx 101 to 00 xxx 000 */
+		*cursor = (reg << 3);
+	}
+
+	/* Target address = address of next instruction + (signed) offset */
+	auprobe->rip_rela_target_address = (long)insn->length + insn->displacement.value;
+
+	/* Displacement field is gone; slide immediate field (if any) over. */
+	if (insn->immediate.nbytes) {
+		cursor++;
+		memmove(cursor, cursor + insn->displacement.nbytes, insn->immediate.nbytes);
+	}
+	return;
+}
+
+static int validate_insn_64bits(struct arch_uprobe *auprobe, struct insn *insn)
+{
+	insn_init(insn, auprobe->insn, true);
+
+	/* Skip good instruction prefixes; reject "bad" ones. */
+	insn_get_opcode(insn);
+	if (is_prefix_bad(insn))
+		return -ENOTSUPP;
+
+	if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_64))
+		return 0;
+
+	if (insn->opcode.nbytes == 2) {
+		if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns))
+			return 0;
+	}
+	return -ENOTSUPP;
+}
+
+static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn)
+{
+	if (mm->context.ia32_compat)
+		return validate_insn_32bits(auprobe, insn);
+	return validate_insn_64bits(auprobe, insn);
+}
+#else /* 32-bit: */
+static void handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn)
+{
+	/* No RIP-relative addressing on 32-bit */
+}
+
+static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm,  struct insn *insn)
+{
+	return validate_insn_32bits(auprobe, insn);
+}
+#endif /* CONFIG_X86_64 */
+
+/**
+ * arch_uprobe_analyze_insn - instruction analysis including validity and fixups.
+ * @mm: the probed address space.
+ * @arch_uprobe: the probepoint information.
+ * Return 0 on success or a -ve number on error.
+ */
+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm)
+{
+	int ret;
+	struct insn insn;
+
+	auprobe->fixups = 0;
+	ret = validate_insn_bits(auprobe, mm, &insn);
+	if (ret != 0)
+		return ret;
+
+	handle_riprel_insn(auprobe, mm, &insn);
+	prepare_fixups(auprobe, &insn);
+
+	return 0;
+}
+
+#ifdef CONFIG_X86_64
+/*
+ * If we're emulating a rip-relative instruction, save the contents
+ * of the scratch register and store the target address in that register.
+ */
+static void
+pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs,
+				struct arch_uprobe_task *autask)
+{
+	if (auprobe->fixups & UPROBE_FIX_RIP_AX) {
+		autask->saved_scratch_register = regs->ax;
+		regs->ax = current->utask->vaddr;
+		regs->ax += auprobe->rip_rela_target_address;
+	} else if (auprobe->fixups & UPROBE_FIX_RIP_CX) {
+		autask->saved_scratch_register = regs->cx;
+		regs->cx = current->utask->vaddr;
+		regs->cx += auprobe->rip_rela_target_address;
+	}
+}
+#else
+static void
+pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs,
+				struct arch_uprobe_task *autask)
+{
+	/* No RIP-relative addressing on 32-bit */
+}
+#endif
+
+/*
+ * arch_uprobe_pre_xol - prepare to execute out of line.
+ * @auprobe: the probepoint information.
+ * @regs: reflects the saved user state of current task.
+ */
+int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+	struct arch_uprobe_task *autask;
+
+	autask = &current->utask->autask;
+	autask->saved_trap_nr = current->thread.trap_nr;
+	current->thread.trap_nr = UPROBE_TRAP_NR;
+	regs->ip = current->utask->xol_vaddr;
+	pre_xol_rip_insn(auprobe, regs, autask);
+
+	return 0;
+}
+
+/*
+ * This function is called by arch_uprobe_post_xol() to adjust the return
+ * address pushed by a call instruction executed out of line.
+ */
+static int adjust_ret_addr(unsigned long sp, long correction)
+{
+	int rasize, ncopied;
+	long ra = 0;
+
+	if (is_ia32_task())
+		rasize = 4;
+	else
+		rasize = 8;
+
+	ncopied = copy_from_user(&ra, (void __user *)sp, rasize);
+	if (unlikely(ncopied))
+		return -EFAULT;
+
+	ra += correction;
+	ncopied = copy_to_user((void __user *)sp, &ra, rasize);
+	if (unlikely(ncopied))
+		return -EFAULT;
+
+	return 0;
+}
+
+#ifdef CONFIG_X86_64
+static bool is_riprel_insn(struct arch_uprobe *auprobe)
+{
+	return ((auprobe->fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) != 0);
+}
+
+static void
+handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction)
+{
+	if (is_riprel_insn(auprobe)) {
+		struct arch_uprobe_task *autask;
+
+		autask = &current->utask->autask;
+		if (auprobe->fixups & UPROBE_FIX_RIP_AX)
+			regs->ax = autask->saved_scratch_register;
+		else
+			regs->cx = autask->saved_scratch_register;
+
+		/*
+		 * The original instruction includes a displacement, and so
+		 * is 4 bytes longer than what we've just single-stepped.
+		 * Fall through to handle stuff like "jmpq *...(%rip)" and
+		 * "callq *...(%rip)".
+		 */
+		if (correction)
+			*correction += 4;
+	}
+}
+#else
+static void
+handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction)
+{
+	/* No RIP-relative addressing on 32-bit */
+}
+#endif
+
+/*
+ * If xol insn itself traps and generates a signal(Say,
+ * SIGILL/SIGSEGV/etc), then detect the case where a singlestepped
+ * instruction jumps back to its own address. It is assumed that anything
+ * like do_page_fault/do_trap/etc sets thread.trap_nr != -1.
+ *
+ * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr,
+ * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to
+ * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol().
+ */
+bool arch_uprobe_xol_was_trapped(struct task_struct *t)
+{
+	if (t->thread.trap_nr != UPROBE_TRAP_NR)
+		return true;
+
+	return false;
+}
+
+/*
+ * Called after single-stepping. To avoid the SMP problems that can
+ * occur when we temporarily put back the original opcode to
+ * single-step, we single-stepped a copy of the instruction.
+ *
+ * This function prepares to resume execution after the single-step.
+ * We have to fix things up as follows:
+ *
+ * Typically, the new ip is relative to the copied instruction.  We need
+ * to make it relative to the original instruction (FIX_IP).  Exceptions
+ * are return instructions and absolute or indirect jump or call instructions.
+ *
+ * If the single-stepped instruction was a call, the return address that
+ * is atop the stack is the address following the copied instruction.  We
+ * need to make it the address following the original instruction (FIX_CALL).
+ *
+ * If the original instruction was a rip-relative instruction such as
+ * "movl %edx,0xnnnn(%rip)", we have instead executed an equivalent
+ * instruction using a scratch register -- e.g., "movl %edx,(%rax)".
+ * We need to restore the contents of the scratch register and adjust
+ * the ip, keeping in mind that the instruction we executed is 4 bytes
+ * shorter than the original instruction (since we squeezed out the offset
+ * field).  (FIX_RIP_AX or FIX_RIP_CX)
+ */
+int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+	struct uprobe_task *utask;
+	long correction;
+	int result = 0;
+
+	WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
+
+	utask = current->utask;
+	current->thread.trap_nr = utask->autask.saved_trap_nr;
+	correction = (long)(utask->vaddr - utask->xol_vaddr);
+	handle_riprel_post_xol(auprobe, regs, &correction);
+	if (auprobe->fixups & UPROBE_FIX_IP)
+		regs->ip += correction;
+
+	if (auprobe->fixups & UPROBE_FIX_CALL)
+		result = adjust_ret_addr(regs->sp, correction);
+
+	return result;
+}
+
+/* callback routine for handling exceptions. */
+int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data)
+{
+	struct die_args *args = data;
+	struct pt_regs *regs = args->regs;
+	int ret = NOTIFY_DONE;
+
+	/* We are only interested in userspace traps */
+	if (regs && !user_mode_vm(regs))
+		return NOTIFY_DONE;
+
+	switch (val) {
+	case DIE_INT3:
+		if (uprobe_pre_sstep_notifier(regs))
+			ret = NOTIFY_STOP;
+
+		break;
+
+	case DIE_DEBUG:
+		if (uprobe_post_sstep_notifier(regs))
+			ret = NOTIFY_STOP;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * This function gets called when XOL instruction either gets trapped or
+ * the thread has a fatal signal, so reset the instruction pointer to its
+ * probed address.
+ */
+void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+	struct uprobe_task *utask = current->utask;
+
+	current->thread.trap_nr = utask->autask.saved_trap_nr;
+	handle_riprel_post_xol(auprobe, regs, NULL);
+	instruction_pointer_set(regs, utask->vaddr);
+}
+
+/*
+ * Skip these instructions as per the currently known x86 ISA.
+ * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 }
+ */
+bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+	int i;
+
+	for (i = 0; i < MAX_UINSN_BYTES; i++) {
+		if ((auprobe->insn[i] == 0x66))
+			continue;
+
+		if (auprobe->insn[i] == 0x90)
+			return true;
+
+		if (i == (MAX_UINSN_BYTES - 1))
+			break;
+
+		if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x1f))
+			return true;
+
+		if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x19))
+			return true;
+
+		if ((auprobe->insn[i] == 0x87) && (auprobe->insn[i+1] == 0xc0))
+			return true;
+
+		break;
+	}
+	return false;
+}
diff --git a/arch/x86/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c
index a1d804b..8eeb55a 100644
--- a/arch/x86/kernel/vsmp_64.c
+++ b/arch/x86/kernel/vsmp_64.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/pci_ids.h>
 #include <linux/pci_regs.h>
+#include <linux/smp.h>
 
 #include <asm/apic.h>
 #include <asm/pci-direct.h>
@@ -22,6 +23,8 @@
 #include <asm/paravirt.h>
 #include <asm/setup.h>
 
+#define TOPOLOGY_REGISTER_OFFSET 0x10
+
 #if defined CONFIG_PCI && defined CONFIG_PARAVIRT
 /*
  * Interrupt control on vSMPowered systems:
@@ -149,12 +152,49 @@
 	return 0;
 }
 #endif
+
+static void __init vsmp_cap_cpus(void)
+{
+#if !defined(CONFIG_X86_VSMP) && defined(CONFIG_SMP)
+	void __iomem *address;
+	unsigned int cfg, topology, node_shift, maxcpus;
+
+	/*
+	 * CONFIG_X86_VSMP is not configured, so limit the number CPUs to the
+	 * ones present in the first board, unless explicitly overridden by
+	 * setup_max_cpus
+	 */
+	if (setup_max_cpus != NR_CPUS)
+		return;
+
+	/* Read the vSMP Foundation topology register */
+	cfg = read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0);
+	address = early_ioremap(cfg + TOPOLOGY_REGISTER_OFFSET, 4);
+	if (WARN_ON(!address))
+		return;
+
+	topology = readl(address);
+	node_shift = (topology >> 16) & 0x7;
+	if (!node_shift)
+		/* The value 0 should be decoded as 8 */
+		node_shift = 8;
+	maxcpus = (topology & ((1 << node_shift) - 1)) + 1;
+
+	pr_info("vSMP CTL: Capping CPUs to %d (CONFIG_X86_VSMP is unset)\n",
+		maxcpus);
+	setup_max_cpus = maxcpus;
+	early_iounmap(address, 4);
+#endif
+}
+
 void __init vsmp_init(void)
 {
 	detect_vsmp_box();
 	if (!is_vsmp_box())
 		return;
 
+	vsmp_cap_cpus();
+
 	set_vsmp_pv_ops();
 	return;
 }
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 9cf71d0..35c5e54 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -18,6 +18,7 @@
 #include <asm/e820.h>
 #include <asm/time.h>
 #include <asm/irq.h>
+#include <asm/io_apic.h>
 #include <asm/pat.h>
 #include <asm/tsc.h>
 #include <asm/iommu.h>
@@ -119,3 +120,10 @@
 	.teardown_msi_irqs = default_teardown_msi_irqs,
 	.restore_msi_irqs = default_restore_msi_irqs,
 };
+
+struct x86_io_apic_ops x86_io_apic_ops = {
+	.init	= native_io_apic_init_mappings,
+	.read	= native_io_apic_read,
+	.write	= native_io_apic_write,
+	.modify	= native_io_apic_modify,
+};
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index e62728e..bd18149 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -48,8 +48,6 @@
 	if (!fx)
 		return;
 
-	BUG_ON(__thread_has_fpu(tsk));
-
 	xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv;
 
 	/*
diff --git a/arch/x86/lib/checksum_32.S b/arch/x86/lib/checksum_32.S
index 78d16a5..2af5df3 100644
--- a/arch/x86/lib/checksum_32.S
+++ b/arch/x86/lib/checksum_32.S
@@ -28,6 +28,7 @@
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
 #include <asm/errno.h>
+#include <asm/asm.h>
 				
 /*
  * computes a partial checksum, e.g. for TCP/UDP fragments
@@ -282,15 +283,11 @@
 
 #define SRC(y...)			\
 	9999: y;			\
-	.section __ex_table, "a";	\
-	.long 9999b, 6001f	;	\
-	.previous
+	_ASM_EXTABLE(9999b, 6001f)
 
 #define DST(y...)			\
 	9999: y;			\
-	.section __ex_table, "a";	\
-	.long 9999b, 6002f	;	\
-	.previous
+	_ASM_EXTABLE(9999b, 6002f)
 
 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
 
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index 0248402..5b2995f 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -16,6 +16,7 @@
 #include <asm/thread_info.h>
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
+#include <asm/asm.h>
 
 /*
  * By placing feature2 after feature1 in altinstructions section, we logically
@@ -63,11 +64,8 @@
 	jmp copy_user_handle_tail
 	.previous
 
-	.section __ex_table,"a"
-	.align 8
-	.quad 100b,103b
-	.quad 101b,103b
-	.previous
+	_ASM_EXTABLE(100b,103b)
+	_ASM_EXTABLE(101b,103b)
 #endif
 	.endm
 
@@ -191,29 +189,26 @@
 60:	jmp copy_user_handle_tail /* ecx is zerorest also */
 	.previous
 
-	.section __ex_table,"a"
-	.align 8
-	.quad 1b,30b
-	.quad 2b,30b
-	.quad 3b,30b
-	.quad 4b,30b
-	.quad 5b,30b
-	.quad 6b,30b
-	.quad 7b,30b
-	.quad 8b,30b
-	.quad 9b,30b
-	.quad 10b,30b
-	.quad 11b,30b
-	.quad 12b,30b
-	.quad 13b,30b
-	.quad 14b,30b
-	.quad 15b,30b
-	.quad 16b,30b
-	.quad 18b,40b
-	.quad 19b,40b
-	.quad 21b,50b
-	.quad 22b,50b
-	.previous
+	_ASM_EXTABLE(1b,30b)
+	_ASM_EXTABLE(2b,30b)
+	_ASM_EXTABLE(3b,30b)
+	_ASM_EXTABLE(4b,30b)
+	_ASM_EXTABLE(5b,30b)
+	_ASM_EXTABLE(6b,30b)
+	_ASM_EXTABLE(7b,30b)
+	_ASM_EXTABLE(8b,30b)
+	_ASM_EXTABLE(9b,30b)
+	_ASM_EXTABLE(10b,30b)
+	_ASM_EXTABLE(11b,30b)
+	_ASM_EXTABLE(12b,30b)
+	_ASM_EXTABLE(13b,30b)
+	_ASM_EXTABLE(14b,30b)
+	_ASM_EXTABLE(15b,30b)
+	_ASM_EXTABLE(16b,30b)
+	_ASM_EXTABLE(18b,40b)
+	_ASM_EXTABLE(19b,40b)
+	_ASM_EXTABLE(21b,50b)
+	_ASM_EXTABLE(22b,50b)
 	CFI_ENDPROC
 ENDPROC(copy_user_generic_unrolled)
 
@@ -259,11 +254,8 @@
 	jmp copy_user_handle_tail
 	.previous
 
-	.section __ex_table,"a"
-	.align 8
-	.quad 1b,11b
-	.quad 3b,12b
-	.previous
+	_ASM_EXTABLE(1b,11b)
+	_ASM_EXTABLE(3b,12b)
 	CFI_ENDPROC
 ENDPROC(copy_user_generic_string)
 
@@ -294,9 +286,6 @@
 	jmp copy_user_handle_tail
 	.previous
 
-	.section __ex_table,"a"
-	.align 8
-	.quad 1b,12b
-	.previous
+	_ASM_EXTABLE(1b,12b)
 	CFI_ENDPROC
 ENDPROC(copy_user_enhanced_fast_string)
diff --git a/arch/x86/lib/copy_user_nocache_64.S b/arch/x86/lib/copy_user_nocache_64.S
index cb0c112..cacddc7 100644
--- a/arch/x86/lib/copy_user_nocache_64.S
+++ b/arch/x86/lib/copy_user_nocache_64.S
@@ -14,6 +14,7 @@
 #include <asm/current.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
+#include <asm/asm.h>
 
 	.macro ALIGN_DESTINATION
 #ifdef FIX_ALIGNMENT
@@ -36,11 +37,8 @@
 	jmp copy_user_handle_tail
 	.previous
 
-	.section __ex_table,"a"
-	.align 8
-	.quad 100b,103b
-	.quad 101b,103b
-	.previous
+	_ASM_EXTABLE(100b,103b)
+	_ASM_EXTABLE(101b,103b)
 #endif
 	.endm
 
@@ -111,27 +109,25 @@
 	jmp copy_user_handle_tail
 	.previous
 
-	.section __ex_table,"a"
-	.quad 1b,30b
-	.quad 2b,30b
-	.quad 3b,30b
-	.quad 4b,30b
-	.quad 5b,30b
-	.quad 6b,30b
-	.quad 7b,30b
-	.quad 8b,30b
-	.quad 9b,30b
-	.quad 10b,30b
-	.quad 11b,30b
-	.quad 12b,30b
-	.quad 13b,30b
-	.quad 14b,30b
-	.quad 15b,30b
-	.quad 16b,30b
-	.quad 18b,40b
-	.quad 19b,40b
-	.quad 21b,50b
-	.quad 22b,50b
-	.previous
+	_ASM_EXTABLE(1b,30b)
+	_ASM_EXTABLE(2b,30b)
+	_ASM_EXTABLE(3b,30b)
+	_ASM_EXTABLE(4b,30b)
+	_ASM_EXTABLE(5b,30b)
+	_ASM_EXTABLE(6b,30b)
+	_ASM_EXTABLE(7b,30b)
+	_ASM_EXTABLE(8b,30b)
+	_ASM_EXTABLE(9b,30b)
+	_ASM_EXTABLE(10b,30b)
+	_ASM_EXTABLE(11b,30b)
+	_ASM_EXTABLE(12b,30b)
+	_ASM_EXTABLE(13b,30b)
+	_ASM_EXTABLE(14b,30b)
+	_ASM_EXTABLE(15b,30b)
+	_ASM_EXTABLE(16b,30b)
+	_ASM_EXTABLE(18b,40b)
+	_ASM_EXTABLE(19b,40b)
+	_ASM_EXTABLE(21b,50b)
+	_ASM_EXTABLE(22b,50b)
 	CFI_ENDPROC
 ENDPROC(__copy_user_nocache)
diff --git a/arch/x86/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S
index fb903b7..2419d5f 100644
--- a/arch/x86/lib/csum-copy_64.S
+++ b/arch/x86/lib/csum-copy_64.S
@@ -8,6 +8,7 @@
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
 #include <asm/errno.h>
+#include <asm/asm.h>
 
 /*
  * Checksum copy with exception handling.
@@ -31,26 +32,17 @@
 
 	.macro source
 10:
-	.section __ex_table, "a"
-	.align 8
-	.quad 10b, .Lbad_source
-	.previous
+	_ASM_EXTABLE(10b, .Lbad_source)
 	.endm
 
 	.macro dest
 20:
-	.section __ex_table, "a"
-	.align 8
-	.quad 20b, .Lbad_dest
-	.previous
+	_ASM_EXTABLE(20b, .Lbad_dest)
 	.endm
 
 	.macro ignore L=.Lignore
 30:
-	.section __ex_table, "a"
-	.align 8
-	.quad 30b, \L
-	.previous
+	_ASM_EXTABLE(30b, \L)
 	.endm
 
 
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index 51f1504..b33b1fb 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -95,10 +95,9 @@
 	CFI_ENDPROC
 END(bad_get_user)
 
-.section __ex_table,"a"
-	_ASM_PTR 1b,bad_get_user
-	_ASM_PTR 2b,bad_get_user
-	_ASM_PTR 3b,bad_get_user
+	_ASM_EXTABLE(1b,bad_get_user)
+	_ASM_EXTABLE(2b,bad_get_user)
+	_ASM_EXTABLE(3b,bad_get_user)
 #ifdef CONFIG_X86_64
-	_ASM_PTR 4b,bad_get_user
+	_ASM_EXTABLE(4b,bad_get_user)
 #endif
diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S
index 36b0d15..7f951c8 100644
--- a/arch/x86/lib/putuser.S
+++ b/arch/x86/lib/putuser.S
@@ -86,12 +86,10 @@
 	EXIT
 END(bad_put_user)
 
-.section __ex_table,"a"
-	_ASM_PTR 1b,bad_put_user
-	_ASM_PTR 2b,bad_put_user
-	_ASM_PTR 3b,bad_put_user
-	_ASM_PTR 4b,bad_put_user
+	_ASM_EXTABLE(1b,bad_put_user)
+	_ASM_EXTABLE(2b,bad_put_user)
+	_ASM_EXTABLE(3b,bad_put_user)
+	_ASM_EXTABLE(4b,bad_put_user)
 #ifdef CONFIG_X86_32
-	_ASM_PTR 5b,bad_put_user
+	_ASM_EXTABLE(5b,bad_put_user)
 #endif
-.previous
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index ef2a6a5..883b216 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -13,6 +13,7 @@
 #include <linux/interrupt.h>
 #include <asm/uaccess.h>
 #include <asm/mmx.h>
+#include <asm/asm.h>
 
 #ifdef CONFIG_X86_INTEL_USERCOPY
 /*
@@ -127,10 +128,7 @@
 		"3:	movb $1,%%al\n"
 		"	jmp 1b\n"
 		".previous\n"
-		".section __ex_table,\"a\"\n"
-		"	.align 4\n"
-		"	.long 0b,2b\n"
-		".previous"
+		_ASM_EXTABLE(0b,2b)
 		:"=&r" (n), "=&D" (s), "=&a" (res), "=&c" (tmp)
 		:"0" (n), "1" (s), "2" (0), "3" (mask)
 		:"cc");
@@ -199,47 +197,44 @@
 		       "101:   lea 0(%%eax,%0,4),%0\n"
 		       "       jmp 100b\n"
 		       ".previous\n"
-		       ".section __ex_table,\"a\"\n"
-		       "       .align 4\n"
-		       "       .long 1b,100b\n"
-		       "       .long 2b,100b\n"
-		       "       .long 3b,100b\n"
-		       "       .long 4b,100b\n"
-		       "       .long 5b,100b\n"
-		       "       .long 6b,100b\n"
-		       "       .long 7b,100b\n"
-		       "       .long 8b,100b\n"
-		       "       .long 9b,100b\n"
-		       "       .long 10b,100b\n"
-		       "       .long 11b,100b\n"
-		       "       .long 12b,100b\n"
-		       "       .long 13b,100b\n"
-		       "       .long 14b,100b\n"
-		       "       .long 15b,100b\n"
-		       "       .long 16b,100b\n"
-		       "       .long 17b,100b\n"
-		       "       .long 18b,100b\n"
-		       "       .long 19b,100b\n"
-		       "       .long 20b,100b\n"
-		       "       .long 21b,100b\n"
-		       "       .long 22b,100b\n"
-		       "       .long 23b,100b\n"
-		       "       .long 24b,100b\n"
-		       "       .long 25b,100b\n"
-		       "       .long 26b,100b\n"
-		       "       .long 27b,100b\n"
-		       "       .long 28b,100b\n"
-		       "       .long 29b,100b\n"
-		       "       .long 30b,100b\n"
-		       "       .long 31b,100b\n"
-		       "       .long 32b,100b\n"
-		       "       .long 33b,100b\n"
-		       "       .long 34b,100b\n"
-		       "       .long 35b,100b\n"
-		       "       .long 36b,100b\n"
-		       "       .long 37b,100b\n"
-		       "       .long 99b,101b\n"
-		       ".previous"
+		       _ASM_EXTABLE(1b,100b)
+		       _ASM_EXTABLE(2b,100b)
+		       _ASM_EXTABLE(3b,100b)
+		       _ASM_EXTABLE(4b,100b)
+		       _ASM_EXTABLE(5b,100b)
+		       _ASM_EXTABLE(6b,100b)
+		       _ASM_EXTABLE(7b,100b)
+		       _ASM_EXTABLE(8b,100b)
+		       _ASM_EXTABLE(9b,100b)
+		       _ASM_EXTABLE(10b,100b)
+		       _ASM_EXTABLE(11b,100b)
+		       _ASM_EXTABLE(12b,100b)
+		       _ASM_EXTABLE(13b,100b)
+		       _ASM_EXTABLE(14b,100b)
+		       _ASM_EXTABLE(15b,100b)
+		       _ASM_EXTABLE(16b,100b)
+		       _ASM_EXTABLE(17b,100b)
+		       _ASM_EXTABLE(18b,100b)
+		       _ASM_EXTABLE(19b,100b)
+		       _ASM_EXTABLE(20b,100b)
+		       _ASM_EXTABLE(21b,100b)
+		       _ASM_EXTABLE(22b,100b)
+		       _ASM_EXTABLE(23b,100b)
+		       _ASM_EXTABLE(24b,100b)
+		       _ASM_EXTABLE(25b,100b)
+		       _ASM_EXTABLE(26b,100b)
+		       _ASM_EXTABLE(27b,100b)
+		       _ASM_EXTABLE(28b,100b)
+		       _ASM_EXTABLE(29b,100b)
+		       _ASM_EXTABLE(30b,100b)
+		       _ASM_EXTABLE(31b,100b)
+		       _ASM_EXTABLE(32b,100b)
+		       _ASM_EXTABLE(33b,100b)
+		       _ASM_EXTABLE(34b,100b)
+		       _ASM_EXTABLE(35b,100b)
+		       _ASM_EXTABLE(36b,100b)
+		       _ASM_EXTABLE(37b,100b)
+		       _ASM_EXTABLE(99b,101b)
 		       : "=&c"(size), "=&D" (d0), "=&S" (d1)
 		       :  "1"(to), "2"(from), "0"(size)
 		       : "eax", "edx", "memory");
@@ -312,29 +307,26 @@
 		       "        popl %0\n"
 		       "        jmp 8b\n"
 		       ".previous\n"
-		       ".section __ex_table,\"a\"\n"
-		       "	.align 4\n"
-		       "	.long 0b,16b\n"
-		       "	.long 1b,16b\n"
-		       "	.long 2b,16b\n"
-		       "	.long 21b,16b\n"
-		       "	.long 3b,16b\n"
-		       "	.long 31b,16b\n"
-		       "	.long 4b,16b\n"
-		       "	.long 41b,16b\n"
-		       "	.long 10b,16b\n"
-		       "	.long 51b,16b\n"
-		       "	.long 11b,16b\n"
-		       "	.long 61b,16b\n"
-		       "	.long 12b,16b\n"
-		       "	.long 71b,16b\n"
-		       "	.long 13b,16b\n"
-		       "	.long 81b,16b\n"
-		       "	.long 14b,16b\n"
-		       "	.long 91b,16b\n"
-		       "	.long 6b,9b\n"
-		       "        .long 7b,16b\n"
-		       ".previous"
+		       _ASM_EXTABLE(0b,16b)
+		       _ASM_EXTABLE(1b,16b)
+		       _ASM_EXTABLE(2b,16b)
+		       _ASM_EXTABLE(21b,16b)
+		       _ASM_EXTABLE(3b,16b)
+		       _ASM_EXTABLE(31b,16b)
+		       _ASM_EXTABLE(4b,16b)
+		       _ASM_EXTABLE(41b,16b)
+		       _ASM_EXTABLE(10b,16b)
+		       _ASM_EXTABLE(51b,16b)
+		       _ASM_EXTABLE(11b,16b)
+		       _ASM_EXTABLE(61b,16b)
+		       _ASM_EXTABLE(12b,16b)
+		       _ASM_EXTABLE(71b,16b)
+		       _ASM_EXTABLE(13b,16b)
+		       _ASM_EXTABLE(81b,16b)
+		       _ASM_EXTABLE(14b,16b)
+		       _ASM_EXTABLE(91b,16b)
+		       _ASM_EXTABLE(6b,9b)
+		       _ASM_EXTABLE(7b,16b)
 		       : "=&c"(size), "=&D" (d0), "=&S" (d1)
 		       :  "1"(to), "2"(from), "0"(size)
 		       : "eax", "edx", "memory");
@@ -414,29 +406,26 @@
 	       "        popl %0\n"
 	       "        jmp 8b\n"
 	       ".previous\n"
-	       ".section __ex_table,\"a\"\n"
-	       "	.align 4\n"
-	       "	.long 0b,16b\n"
-	       "	.long 1b,16b\n"
-	       "	.long 2b,16b\n"
-	       "	.long 21b,16b\n"
-	       "	.long 3b,16b\n"
-	       "	.long 31b,16b\n"
-	       "	.long 4b,16b\n"
-	       "	.long 41b,16b\n"
-	       "	.long 10b,16b\n"
-	       "	.long 51b,16b\n"
-	       "	.long 11b,16b\n"
-	       "	.long 61b,16b\n"
-	       "	.long 12b,16b\n"
-	       "	.long 71b,16b\n"
-	       "	.long 13b,16b\n"
-	       "	.long 81b,16b\n"
-	       "	.long 14b,16b\n"
-	       "	.long 91b,16b\n"
-	       "	.long 6b,9b\n"
-	       "        .long 7b,16b\n"
-	       ".previous"
+	       _ASM_EXTABLE(0b,16b)
+	       _ASM_EXTABLE(1b,16b)
+	       _ASM_EXTABLE(2b,16b)
+	       _ASM_EXTABLE(21b,16b)
+	       _ASM_EXTABLE(3b,16b)
+	       _ASM_EXTABLE(31b,16b)
+	       _ASM_EXTABLE(4b,16b)
+	       _ASM_EXTABLE(41b,16b)
+	       _ASM_EXTABLE(10b,16b)
+	       _ASM_EXTABLE(51b,16b)
+	       _ASM_EXTABLE(11b,16b)
+	       _ASM_EXTABLE(61b,16b)
+	       _ASM_EXTABLE(12b,16b)
+	       _ASM_EXTABLE(71b,16b)
+	       _ASM_EXTABLE(13b,16b)
+	       _ASM_EXTABLE(81b,16b)
+	       _ASM_EXTABLE(14b,16b)
+	       _ASM_EXTABLE(91b,16b)
+	       _ASM_EXTABLE(6b,9b)
+	       _ASM_EXTABLE(7b,16b)
 	       : "=&c"(size), "=&D" (d0), "=&S" (d1)
 	       :  "1"(to), "2"(from), "0"(size)
 	       : "eax", "edx", "memory");
@@ -505,29 +494,26 @@
 	       "9:      lea 0(%%eax,%0,4),%0\n"
 	       "16:     jmp 8b\n"
 	       ".previous\n"
-	       ".section __ex_table,\"a\"\n"
-	       "	.align 4\n"
-	       "	.long 0b,16b\n"
-	       "	.long 1b,16b\n"
-	       "	.long 2b,16b\n"
-	       "	.long 21b,16b\n"
-	       "	.long 3b,16b\n"
-	       "	.long 31b,16b\n"
-	       "	.long 4b,16b\n"
-	       "	.long 41b,16b\n"
-	       "	.long 10b,16b\n"
-	       "	.long 51b,16b\n"
-	       "	.long 11b,16b\n"
-	       "	.long 61b,16b\n"
-	       "	.long 12b,16b\n"
-	       "	.long 71b,16b\n"
-	       "	.long 13b,16b\n"
-	       "	.long 81b,16b\n"
-	       "	.long 14b,16b\n"
-	       "	.long 91b,16b\n"
-	       "	.long 6b,9b\n"
-	       "        .long 7b,16b\n"
-	       ".previous"
+	       _ASM_EXTABLE(0b,16b)
+	       _ASM_EXTABLE(1b,16b)
+	       _ASM_EXTABLE(2b,16b)
+	       _ASM_EXTABLE(21b,16b)
+	       _ASM_EXTABLE(3b,16b)
+	       _ASM_EXTABLE(31b,16b)
+	       _ASM_EXTABLE(4b,16b)
+	       _ASM_EXTABLE(41b,16b)
+	       _ASM_EXTABLE(10b,16b)
+	       _ASM_EXTABLE(51b,16b)
+	       _ASM_EXTABLE(11b,16b)
+	       _ASM_EXTABLE(61b,16b)
+	       _ASM_EXTABLE(12b,16b)
+	       _ASM_EXTABLE(71b,16b)
+	       _ASM_EXTABLE(13b,16b)
+	       _ASM_EXTABLE(81b,16b)
+	       _ASM_EXTABLE(14b,16b)
+	       _ASM_EXTABLE(91b,16b)
+	       _ASM_EXTABLE(6b,9b)
+	       _ASM_EXTABLE(7b,16b)
 	       : "=&c"(size), "=&D" (d0), "=&S" (d1)
 	       :  "1"(to), "2"(from), "0"(size)
 	       : "eax", "edx", "memory");
@@ -574,12 +560,9 @@
 		"3:	lea 0(%3,%0,4),%0\n"				\
 		"	jmp 2b\n"					\
 		".previous\n"						\
-		".section __ex_table,\"a\"\n"				\
-		"	.align 4\n"					\
-		"	.long 4b,5b\n"					\
-		"	.long 0b,3b\n"					\
-		"	.long 1b,2b\n"					\
-		".previous"						\
+		_ASM_EXTABLE(4b,5b)					\
+		_ASM_EXTABLE(0b,3b)					\
+		_ASM_EXTABLE(1b,2b)					\
 		: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2)	\
 		: "3"(size), "0"(size), "1"(to), "2"(from)		\
 		: "memory");						\
@@ -616,12 +599,9 @@
 		"	popl %0\n"					\
 		"	jmp 2b\n"					\
 		".previous\n"						\
-		".section __ex_table,\"a\"\n"				\
-		"	.align 4\n"					\
-		"	.long 4b,5b\n"					\
-		"	.long 0b,3b\n"					\
-		"	.long 1b,6b\n"					\
-		".previous"						\
+		_ASM_EXTABLE(4b,5b)					\
+		_ASM_EXTABLE(0b,3b)					\
+		_ASM_EXTABLE(1b,6b)					\
 		: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2)	\
 		: "3"(size), "0"(size), "1"(to), "2"(from)		\
 		: "memory");						\
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 1fb85db..903ec1e 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -1,11 +1,23 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/sort.h>
 #include <asm/uaccess.h>
 
+static inline unsigned long
+ex_insn_addr(const struct exception_table_entry *x)
+{
+	return (unsigned long)&x->insn + x->insn;
+}
+static inline unsigned long
+ex_fixup_addr(const struct exception_table_entry *x)
+{
+	return (unsigned long)&x->fixup + x->fixup;
+}
 
 int fixup_exception(struct pt_regs *regs)
 {
 	const struct exception_table_entry *fixup;
+	unsigned long new_ip;
 
 #ifdef CONFIG_PNPBIOS
 	if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
@@ -23,15 +35,135 @@
 
 	fixup = search_exception_tables(regs->ip);
 	if (fixup) {
-		/* If fixup is less than 16, it means uaccess error */
-		if (fixup->fixup < 16) {
+		new_ip = ex_fixup_addr(fixup);
+
+		if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
+			/* Special hack for uaccess_err */
 			current_thread_info()->uaccess_err = 1;
-			regs->ip += fixup->fixup;
-			return 1;
+			new_ip -= 0x7ffffff0;
 		}
-		regs->ip = fixup->fixup;
+		regs->ip = new_ip;
 		return 1;
 	}
 
 	return 0;
 }
+
+/* Restricted version used during very early boot */
+int __init early_fixup_exception(unsigned long *ip)
+{
+	const struct exception_table_entry *fixup;
+	unsigned long new_ip;
+
+	fixup = search_exception_tables(*ip);
+	if (fixup) {
+		new_ip = ex_fixup_addr(fixup);
+
+		if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
+			/* uaccess handling not supported during early boot */
+			return 0;
+		}
+
+		*ip = new_ip;
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Search one exception table for an entry corresponding to the
+ * given instruction address, and return the address of the entry,
+ * or NULL if none is found.
+ * We use a binary search, and thus we assume that the table is
+ * already sorted.
+ */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+	       const struct exception_table_entry *last,
+	       unsigned long value)
+{
+	while (first <= last) {
+		const struct exception_table_entry *mid;
+		unsigned long addr;
+
+		mid = ((last - first) >> 1) + first;
+		addr = ex_insn_addr(mid);
+		if (addr < value)
+			first = mid + 1;
+		else if (addr > value)
+			last = mid - 1;
+		else
+			return mid;
+        }
+        return NULL;
+}
+
+/*
+ * The exception table needs to be sorted so that the binary
+ * search that we use to find entries in it works properly.
+ * This is used both for the kernel exception table and for
+ * the exception tables of modules that get loaded.
+ *
+ */
+static int cmp_ex(const void *a, const void *b)
+{
+	const struct exception_table_entry *x = a, *y = b;
+
+	/*
+	 * This value will always end up fittin in an int, because on
+	 * both i386 and x86-64 the kernel symbol-reachable address
+	 * space is < 2 GiB.
+	 *
+	 * This compare is only valid after normalization.
+	 */
+	return x->insn - y->insn;
+}
+
+void sort_extable(struct exception_table_entry *start,
+		  struct exception_table_entry *finish)
+{
+	struct exception_table_entry *p;
+	int i;
+
+	/* Convert all entries to being relative to the start of the section */
+	i = 0;
+	for (p = start; p < finish; p++) {
+		p->insn += i;
+		i += 4;
+		p->fixup += i;
+		i += 4;
+	}
+
+	sort(start, finish - start, sizeof(struct exception_table_entry),
+	     cmp_ex, NULL);
+
+	/* Denormalize all entries */
+	i = 0;
+	for (p = start; p < finish; p++) {
+		p->insn -= i;
+		i += 4;
+		p->fixup -= i;
+		i += 4;
+	}
+}
+
+#ifdef CONFIG_MODULES
+/*
+ * If the exception table is sorted, any referring to the module init
+ * will be at the beginning or the end.
+ */
+void trim_init_extable(struct module *m)
+{
+	/*trim the beginning*/
+	while (m->num_exentries &&
+	       within_module_init(ex_insn_addr(&m->extable[0]), m)) {
+		m->extable++;
+		m->num_exentries--;
+	}
+	/*trim the end*/
+	while (m->num_exentries &&
+	       within_module_init(ex_insn_addr(&m->extable[m->num_exentries-1]), m))
+		m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 3ecfd1aa..76dcd9d 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -582,7 +582,7 @@
 		pte_t *pte = lookup_address(address, &level);
 
 		if (pte && pte_present(*pte) && !pte_exec(*pte))
-			printk(nx_warning, current_uid());
+			printk(nx_warning, from_kuid(&init_user_ns, current_uid()));
 	}
 
 	printk(KERN_ALERT "BUG: unable to handle kernel ");
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 4f0cec7..319b6f2 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -29,8 +29,14 @@
 #endif
 ;
 
-static void __init find_early_table_space(unsigned long end, int use_pse,
-					  int use_gbpages)
+struct map_range {
+	unsigned long start;
+	unsigned long end;
+	unsigned page_size_mask;
+};
+
+static void __init find_early_table_space(struct map_range *mr, unsigned long end,
+					  int use_pse, int use_gbpages)
 {
 	unsigned long puds, pmds, ptes, tables, start = 0, good_end = end;
 	phys_addr_t base;
@@ -55,6 +61,9 @@
 #ifdef CONFIG_X86_32
 		extra += PMD_SIZE;
 #endif
+		/* The first 2/4M doesn't use large pages. */
+		extra += mr->end - mr->start;
+
 		ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	} else
 		ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -84,12 +93,6 @@
 	memblock_reserve(start, end - start);
 }
 
-struct map_range {
-	unsigned long start;
-	unsigned long end;
-	unsigned page_size_mask;
-};
-
 #ifdef CONFIG_X86_32
 #define NR_RANGE_MR 3
 #else /* CONFIG_X86_64 */
@@ -261,7 +264,7 @@
 	 * nodes are discovered.
 	 */
 	if (!after_bootmem)
-		find_early_table_space(end, use_pse, use_gbpages);
+		find_early_table_space(&mr[0], end, use_pse, use_gbpages);
 
 	for (i = 0; i < nr_range; i++)
 		ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index fc18be0..2b6b4a3 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -407,12 +407,12 @@
 phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
 	      unsigned long page_size_mask, pgprot_t prot)
 {
-	unsigned long pages = 0;
+	unsigned long pages = 0, next;
 	unsigned long last_map_addr = end;
 
 	int i = pmd_index(address);
 
-	for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
+	for (; i < PTRS_PER_PMD; i++, address = next) {
 		unsigned long pte_phys;
 		pmd_t *pmd = pmd_page + pmd_index(address);
 		pte_t *pte;
@@ -426,6 +426,8 @@
 			break;
 		}
 
+		next = (address & PMD_MASK) + PMD_SIZE;
+
 		if (pmd_val(*pmd)) {
 			if (!pmd_large(*pmd)) {
 				spin_lock(&init_mm.page_table_lock);
@@ -449,7 +451,7 @@
 			 * attributes.
 			 */
 			if (page_size_mask & (1 << PG_LEVEL_2M)) {
-				pages++;
+				last_map_addr = next;
 				continue;
 			}
 			new_prot = pte_pgprot(pte_clrhuge(*(pte_t *)pmd));
@@ -462,7 +464,7 @@
 				pfn_pte(address >> PAGE_SHIFT,
 					__pgprot(pgprot_val(prot) | _PAGE_PSE)));
 			spin_unlock(&init_mm.page_table_lock);
-			last_map_addr = (address & PMD_MASK) + PMD_SIZE;
+			last_map_addr = next;
 			continue;
 		}
 
@@ -482,11 +484,11 @@
 phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
 			 unsigned long page_size_mask)
 {
-	unsigned long pages = 0;
+	unsigned long pages = 0, next;
 	unsigned long last_map_addr = end;
 	int i = pud_index(addr);
 
-	for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE) {
+	for (; i < PTRS_PER_PUD; i++, addr = next) {
 		unsigned long pmd_phys;
 		pud_t *pud = pud_page + pud_index(addr);
 		pmd_t *pmd;
@@ -495,8 +497,9 @@
 		if (addr >= end)
 			break;
 
-		if (!after_bootmem &&
-				!e820_any_mapped(addr, addr+PUD_SIZE, 0)) {
+		next = (addr & PUD_MASK) + PUD_SIZE;
+
+		if (!after_bootmem && !e820_any_mapped(addr, next, 0)) {
 			set_pud(pud, __pud(0));
 			continue;
 		}
@@ -523,7 +526,7 @@
 			 * attributes.
 			 */
 			if (page_size_mask & (1 << PG_LEVEL_1G)) {
-				pages++;
+				last_map_addr = next;
 				continue;
 			}
 			prot = pte_pgprot(pte_clrhuge(*(pte_t *)pud));
@@ -535,7 +538,7 @@
 			set_pte((pte_t *)pud,
 				pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
 			spin_unlock(&init_mm.page_table_lock);
-			last_map_addr = (addr & PUD_MASK) + PUD_SIZE;
+			last_map_addr = next;
 			continue;
 		}
 
diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c
index 53489ff..871dd88 100644
--- a/arch/x86/mm/numa_emulation.c
+++ b/arch/x86/mm/numa_emulation.c
@@ -339,9 +339,11 @@
 	} else {
 		unsigned long n;
 
-		n = simple_strtoul(emu_cmdline, NULL, 0);
+		n = simple_strtoul(emu_cmdline, &emu_cmdline, 0);
 		ret = split_nodes_interleave(&ei, &pi, 0, max_addr, n);
 	}
+	if (*emu_cmdline == ':')
+		emu_cmdline++;
 
 	if (ret < 0)
 		goto no_emu;
@@ -418,7 +420,9 @@
 			int physj = emu_nid_to_phys[j];
 			int dist;
 
-			if (physi >= numa_dist_cnt || physj >= numa_dist_cnt)
+			if (get_option(&emu_cmdline, &dist) == 2)
+				;
+			else if (physi >= numa_dist_cnt || physj >= numa_dist_cnt)
 				dist = physi == physj ?
 					LOCAL_DISTANCE : REMOTE_DISTANCE;
 			else
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index d6c0418..5e57e11 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -61,11 +61,13 @@
  */
 void leave_mm(int cpu)
 {
-	if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
+	struct mm_struct *active_mm = this_cpu_read(cpu_tlbstate.active_mm);
+	if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
 		BUG();
-	cpumask_clear_cpu(cpu,
-			  mm_cpumask(percpu_read(cpu_tlbstate.active_mm)));
-	load_cr3(swapper_pg_dir);
+	if (cpumask_test_cpu(cpu, mm_cpumask(active_mm))) {
+		cpumask_clear_cpu(cpu, mm_cpumask(active_mm));
+		load_cr3(swapper_pg_dir);
+	}
 }
 EXPORT_SYMBOL_GPL(leave_mm);
 
@@ -152,8 +154,8 @@
 		 * BUG();
 		 */
 
-	if (f->flush_mm == percpu_read(cpu_tlbstate.active_mm)) {
-		if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {
+	if (f->flush_mm == this_cpu_read(cpu_tlbstate.active_mm)) {
+		if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {
 			if (f->flush_va == TLB_FLUSH_ALL)
 				local_flush_tlb();
 			else
@@ -322,7 +324,7 @@
 static void do_flush_tlb_all(void *info)
 {
 	__flush_tlb_all();
-	if (percpu_read(cpu_tlbstate.state) == TLBSTATE_LAZY)
+	if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_LAZY)
 		leave_mm(smp_processor_id());
 }
 
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index e76e18c..3af5a1e 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -11,6 +11,8 @@
 obj-$(CONFIG_ACPI)		+= acpi.o
 obj-y				+= legacy.o irq.o
 
+obj-$(CONFIG_STA2X11)           += sta2x11-fixup.o
+
 obj-$(CONFIG_X86_VISWS)		+= visws.o
 
 obj-$(CONFIG_X86_NUMAQ)		+= numaq_32.o
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index d0e6e40..5dd467b 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -519,3 +519,20 @@
 	}
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar);
+
+/*
+ * Twinhead H12Y needs us to block out a region otherwise we map devices
+ * there and any access kills the box.
+ *
+ *   See: https://bugzilla.kernel.org/show_bug.cgi?id=10231
+ *
+ * Match off the LPC and svid/sdid (older kernels lose the bridge subvendor)
+ */
+static void __devinit twinhead_reserve_killing_zone(struct pci_dev *dev)
+{
+        if (dev->subsystem_vendor == 0x14FF && dev->subsystem_device == 0xA003) {
+                pr_info("Reserving memory on Twinhead H12Y\n");
+                request_mem_region(0xFFB00000, 0x100000, "twinhead");
+        }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone);
diff --git a/arch/x86/pci/sta2x11-fixup.c b/arch/x86/pci/sta2x11-fixup.c
new file mode 100644
index 0000000..9d8a509
--- /dev/null
+++ b/arch/x86/pci/sta2x11-fixup.c
@@ -0,0 +1,366 @@
+/*
+ * arch/x86/pci/sta2x11-fixup.c
+ * glue code for lib/swiotlb.c and DMA translation between STA2x11
+ * AMBA memory mapping and the X86 memory mapping
+ *
+ * ST Microelectronics ConneXt (STA2X11/STA2X10)
+ *
+ * Copyright (c) 2010-2011 Wind River Systems, 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.
+ *
+ * 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/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/export.h>
+#include <linux/list.h>
+
+#define STA2X11_SWIOTLB_SIZE (4*1024*1024)
+extern int swiotlb_late_init_with_default_size(size_t default_size);
+
+/*
+ * We build a list of bus numbers that are under the ConneXt. The
+ * main bridge hosts 4 busses, which are the 4 endpoints, in order.
+ */
+#define STA2X11_NR_EP		4	/* 0..3 included */
+#define STA2X11_NR_FUNCS	8	/* 0..7 included */
+#define STA2X11_AMBA_SIZE	(512 << 20)
+
+struct sta2x11_ahb_regs { /* saved during suspend */
+	u32 base, pexlbase, pexhbase, crw;
+};
+
+struct sta2x11_mapping {
+	u32 amba_base;
+	int is_suspended;
+	struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS];
+};
+
+struct sta2x11_instance {
+	struct list_head list;
+	int bus0;
+	struct sta2x11_mapping map[STA2X11_NR_EP];
+};
+
+static LIST_HEAD(sta2x11_instance_list);
+
+/* At probe time, record new instances of this bridge (likely one only) */
+static void sta2x11_new_instance(struct pci_dev *pdev)
+{
+	struct sta2x11_instance *instance;
+
+	instance = kzalloc(sizeof(*instance), GFP_ATOMIC);
+	if (!instance)
+		return;
+	/* This has a subordinate bridge, with 4 more-subordinate ones */
+	instance->bus0 = pdev->subordinate->number + 1;
+
+	if (list_empty(&sta2x11_instance_list)) {
+		int size = STA2X11_SWIOTLB_SIZE;
+		/* First instance: register your own swiotlb area */
+		dev_info(&pdev->dev, "Using SWIOTLB (size %i)\n", size);
+		if (swiotlb_late_init_with_default_size(size))
+			dev_emerg(&pdev->dev, "init swiotlb failed\n");
+	}
+	list_add(&instance->list, &sta2x11_instance_list);
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, 0xcc17, sta2x11_new_instance);
+
+/*
+ * Utility functions used in this file from below
+ */
+static struct sta2x11_instance *sta2x11_pdev_to_instance(struct pci_dev *pdev)
+{
+	struct sta2x11_instance *instance;
+	int ep;
+
+	list_for_each_entry(instance, &sta2x11_instance_list, list) {
+		ep = pdev->bus->number - instance->bus0;
+		if (ep >= 0 && ep < STA2X11_NR_EP)
+			return instance;
+	}
+	return NULL;
+}
+
+static int sta2x11_pdev_to_ep(struct pci_dev *pdev)
+{
+	struct sta2x11_instance *instance;
+
+	instance = sta2x11_pdev_to_instance(pdev);
+	if (!instance)
+		return -1;
+
+	return pdev->bus->number - instance->bus0;
+}
+
+static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev)
+{
+	struct sta2x11_instance *instance;
+	int ep;
+
+	instance = sta2x11_pdev_to_instance(pdev);
+	if (!instance)
+		return NULL;
+	ep = sta2x11_pdev_to_ep(pdev);
+	return instance->map + ep;
+}
+
+/* This is exported, as some devices need to access the MFD registers */
+struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev)
+{
+	return sta2x11_pdev_to_instance(pdev);
+}
+EXPORT_SYMBOL(sta2x11_get_instance);
+
+
+/**
+ * p2a - Translate physical address to STA2x11 AMBA address,
+ *       used for DMA transfers to STA2x11
+ * @p: Physical address
+ * @pdev: PCI device (must be hosted within the connext)
+ */
+static dma_addr_t p2a(dma_addr_t p, struct pci_dev *pdev)
+{
+	struct sta2x11_mapping *map;
+	dma_addr_t a;
+
+	map = sta2x11_pdev_to_mapping(pdev);
+	a = p + map->amba_base;
+	return a;
+}
+
+/**
+ * a2p - Translate STA2x11 AMBA address to physical address
+ *       used for DMA transfers from STA2x11
+ * @a: STA2x11 AMBA address
+ * @pdev: PCI device (must be hosted within the connext)
+ */
+static dma_addr_t a2p(dma_addr_t a, struct pci_dev *pdev)
+{
+	struct sta2x11_mapping *map;
+	dma_addr_t p;
+
+	map = sta2x11_pdev_to_mapping(pdev);
+	p = a - map->amba_base;
+	return p;
+}
+
+/**
+ * sta2x11_swiotlb_alloc_coherent - Allocate swiotlb bounce buffers
+ *     returns virtual address. This is the only "special" function here.
+ * @dev: PCI device
+ * @size: Size of the buffer
+ * @dma_handle: DMA address
+ * @flags: memory flags
+ */
+static void *sta2x11_swiotlb_alloc_coherent(struct device *dev,
+					    size_t size,
+					    dma_addr_t *dma_handle,
+					    gfp_t flags,
+					    struct dma_attrs *attrs)
+{
+	void *vaddr;
+
+	vaddr = dma_generic_alloc_coherent(dev, size, dma_handle, flags, attrs);
+	if (!vaddr)
+		vaddr = swiotlb_alloc_coherent(dev, size, dma_handle, flags);
+	*dma_handle = p2a(*dma_handle, to_pci_dev(dev));
+	return vaddr;
+}
+
+/* We have our own dma_ops: the same as swiotlb but from alloc (above) */
+static struct dma_map_ops sta2x11_dma_ops = {
+	.alloc = sta2x11_swiotlb_alloc_coherent,
+	.free = swiotlb_free_coherent,
+	.map_page = swiotlb_map_page,
+	.unmap_page = swiotlb_unmap_page,
+	.map_sg = swiotlb_map_sg_attrs,
+	.unmap_sg = swiotlb_unmap_sg_attrs,
+	.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+	.sync_single_for_device = swiotlb_sync_single_for_device,
+	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = swiotlb_sync_sg_for_device,
+	.mapping_error = swiotlb_dma_mapping_error,
+	.dma_supported = NULL, /* FIXME: we should use this instead! */
+};
+
+/* At setup time, we use our own ops if the device is a ConneXt one */
+static void sta2x11_setup_pdev(struct pci_dev *pdev)
+{
+	struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev);
+
+	if (!instance) /* either a sta2x11 bridge or another ST device */
+		return;
+	pci_set_consistent_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+	pci_set_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+	pdev->dev.archdata.dma_ops = &sta2x11_dma_ops;
+
+	/* We must enable all devices as master, for audio DMA to work */
+	pci_set_master(pdev);
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev);
+
+/*
+ * The following three functions are exported (used in swiotlb: FIXME)
+ */
+/**
+ * dma_capable - Check if device can manage DMA transfers (FIXME: kill it)
+ * @dev: device for a PCI device
+ * @addr: DMA address
+ * @size: DMA size
+ */
+bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	struct sta2x11_mapping *map;
+
+	if (dev->archdata.dma_ops != &sta2x11_dma_ops) {
+		if (!dev->dma_mask)
+			return false;
+		return addr + size - 1 <= *dev->dma_mask;
+	}
+
+	map = sta2x11_pdev_to_mapping(to_pci_dev(dev));
+
+	if (!map || (addr < map->amba_base))
+		return false;
+	if (addr + size >= map->amba_base + STA2X11_AMBA_SIZE) {
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * phys_to_dma - Return the DMA AMBA address used for this STA2x11 device
+ * @dev: device for a PCI device
+ * @paddr: Physical address
+ */
+dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	if (dev->archdata.dma_ops != &sta2x11_dma_ops)
+		return paddr;
+	return p2a(paddr, to_pci_dev(dev));
+}
+
+/**
+ * dma_to_phys - Return the physical address used for this STA2x11 DMA address
+ * @dev: device for a PCI device
+ * @daddr: STA2x11 AMBA DMA address
+ */
+phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+	if (dev->archdata.dma_ops != &sta2x11_dma_ops)
+		return daddr;
+	return a2p(daddr, to_pci_dev(dev));
+}
+
+
+/*
+ * At boot we must set up the mappings for the pcie-to-amba bridge.
+ * It involves device access, and the same happens at suspend/resume time
+ */
+
+#define AHB_MAPB		0xCA4
+#define AHB_CRW(i)		(AHB_MAPB + 0  + (i) * 0x10)
+#define AHB_CRW_SZMASK			0xfffffc00UL
+#define AHB_CRW_ENABLE			(1 << 0)
+#define AHB_CRW_WTYPE_MEM		(2 << 1)
+#define AHB_CRW_ROE			(1UL << 3)	/* Relax Order Ena */
+#define AHB_CRW_NSE			(1UL << 4)	/* No Snoop Enable */
+#define AHB_BASE(i)		(AHB_MAPB + 4  + (i) * 0x10)
+#define AHB_PEXLBASE(i)		(AHB_MAPB + 8  + (i) * 0x10)
+#define AHB_PEXHBASE(i)		(AHB_MAPB + 12 + (i) * 0x10)
+
+/* At probe time, enable mapping for each endpoint, using the pdev */
+static void sta2x11_map_ep(struct pci_dev *pdev)
+{
+	struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
+	int i;
+
+	if (!map)
+		return;
+	pci_read_config_dword(pdev, AHB_BASE(0), &map->amba_base);
+
+	/* Configure AHB mapping */
+	pci_write_config_dword(pdev, AHB_PEXLBASE(0), 0);
+	pci_write_config_dword(pdev, AHB_PEXHBASE(0), 0);
+	pci_write_config_dword(pdev, AHB_CRW(0), STA2X11_AMBA_SIZE |
+			       AHB_CRW_WTYPE_MEM | AHB_CRW_ENABLE);
+
+	/* Disable all the other windows */
+	for (i = 1; i < STA2X11_NR_FUNCS; i++)
+		pci_write_config_dword(pdev, AHB_CRW(i), 0);
+
+	dev_info(&pdev->dev,
+		 "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n",
+		 sta2x11_pdev_to_ep(pdev),  map->amba_base,
+		 map->amba_base + STA2X11_AMBA_SIZE - 1);
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep);
+
+#ifdef CONFIG_PM /* Some register values must be saved and restored */
+
+static void suspend_mapping(struct pci_dev *pdev)
+{
+	struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
+	int i;
+
+	if (!map)
+		return;
+
+	if (map->is_suspended)
+		return;
+	map->is_suspended = 1;
+
+	/* Save all window configs */
+	for (i = 0; i < STA2X11_NR_FUNCS; i++) {
+		struct sta2x11_ahb_regs *regs = map->regs + i;
+
+		pci_read_config_dword(pdev, AHB_BASE(i), &regs->base);
+		pci_read_config_dword(pdev, AHB_PEXLBASE(i), &regs->pexlbase);
+		pci_read_config_dword(pdev, AHB_PEXHBASE(i), &regs->pexhbase);
+		pci_read_config_dword(pdev, AHB_CRW(i), &regs->crw);
+	}
+}
+DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, suspend_mapping);
+
+static void resume_mapping(struct pci_dev *pdev)
+{
+	struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
+	int i;
+
+	if (!map)
+		return;
+
+
+	if (!map->is_suspended)
+		goto out;
+	map->is_suspended = 0;
+
+	/* Restore all window configs */
+	for (i = 0; i < STA2X11_NR_FUNCS; i++) {
+		struct sta2x11_ahb_regs *regs = map->regs + i;
+
+		pci_write_config_dword(pdev, AHB_BASE(i), regs->base);
+		pci_write_config_dword(pdev, AHB_PEXLBASE(i), regs->pexlbase);
+		pci_write_config_dword(pdev, AHB_PEXHBASE(i), regs->pexhbase);
+		pci_write_config_dword(pdev, AHB_CRW(i), regs->crw);
+	}
+out:
+	pci_set_master(pdev); /* Like at boot, enable master on all devices */
+}
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, resume_mapping);
+
+#endif /* CONFIG_PM */
diff --git a/arch/x86/platform/olpc/olpc-xo1-sci.c b/arch/x86/platform/olpc/olpc-xo1-sci.c
index 1d4c783..04b8c73 100644
--- a/arch/x86/platform/olpc/olpc-xo1-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo1-sci.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
+#include <linux/pm_wakeup.h>
 #include <linux/mfd/core.h>
 #include <linux/power_supply.h>
 #include <linux/suspend.h>
@@ -83,8 +84,12 @@
 		return;
 	}
 
+	if (!!test_bit(SW_TABLET_MODE, ebook_switch_idev->sw) == state)
+		return; /* Nothing new to report. */
+
 	input_report_switch(ebook_switch_idev, SW_TABLET_MODE, state);
 	input_sync(ebook_switch_idev);
+	pm_wakeup_event(&ebook_switch_idev->dev, 0);
 }
 
 static void flip_lid_inverter(void)
@@ -123,8 +128,12 @@
 /* Report current lid switch state through input layer */
 static void send_lid_state(void)
 {
+	if (!!test_bit(SW_LID, lid_switch_idev->sw) == !lid_open)
+		return; /* Nothing new to report. */
+
 	input_report_switch(lid_switch_idev, SW_LID, !lid_open);
 	input_sync(lid_switch_idev);
+	pm_wakeup_event(&lid_switch_idev->dev, 0);
 }
 
 static ssize_t lid_wake_mode_show(struct device *dev,
@@ -213,11 +222,30 @@
 
 	dev_dbg(&pdev->dev, "sts %x gpe %x\n", sts, gpe);
 
-	if (sts & CS5536_PWRBTN_FLAG && !(sts & CS5536_WAK_FLAG)) {
-		input_report_key(power_button_idev, KEY_POWER, 1);
-		input_sync(power_button_idev);
-		input_report_key(power_button_idev, KEY_POWER, 0);
-		input_sync(power_button_idev);
+	if (sts & CS5536_PWRBTN_FLAG) {
+		if (!(sts & CS5536_WAK_FLAG)) {
+			/* Only report power button input when it was pressed
+			 * during regular operation (as opposed to when it
+			 * was used to wake the system). */
+			input_report_key(power_button_idev, KEY_POWER, 1);
+			input_sync(power_button_idev);
+			input_report_key(power_button_idev, KEY_POWER, 0);
+			input_sync(power_button_idev);
+		}
+		/* Report the wakeup event in all cases. */
+		pm_wakeup_event(&power_button_idev->dev, 0);
+	}
+
+	if ((sts & (CS5536_RTC_FLAG | CS5536_WAK_FLAG)) ==
+			(CS5536_RTC_FLAG | CS5536_WAK_FLAG)) {
+		/* When the system is woken by the RTC alarm, report the
+		 * event on the rtc device. */
+		struct device *rtc = bus_find_device_by_name(
+			&platform_bus_type, NULL, "rtc_cmos");
+		if (rtc) {
+			pm_wakeup_event(rtc, 0);
+			put_device(rtc);
+		}
 	}
 
 	if (gpe & CS5536_GPIOM7_PME_FLAG) { /* EC GPIO */
@@ -310,9 +338,10 @@
 		outb(lo, CS5536_PIC_INT_SEL2);
 	}
 
-	/* Enable SCI from power button, and clear pending interrupts */
+	/* Enable interesting SCI events, and clear pending interrupts */
 	sts = inl(acpi_base + CS5536_PM1_STS);
-	outl((CS5536_PM_PWRBTN << 16) | 0xffff, acpi_base + CS5536_PM1_STS);
+	outl(((CS5536_PM_PWRBTN | CS5536_PM_RTC) << 16) | 0xffff,
+	     acpi_base + CS5536_PM1_STS);
 
 	r = request_irq(sci_irq, xo1_sci_intr, 0, DRV_NAME, pdev);
 	if (r)
diff --git a/arch/x86/platform/visws/visws_quirks.c b/arch/x86/platform/visws/visws_quirks.c
index c7abf13..94d8a39 100644
--- a/arch/x86/platform/visws/visws_quirks.c
+++ b/arch/x86/platform/visws/visws_quirks.c
@@ -445,7 +445,7 @@
 
 	spin_lock_irqsave(&cobalt_lock, flags);
 	disable_cobalt_irq(data);
-	apic_write(APIC_EOI, APIC_EIO_ACK);
+	apic_write(APIC_EOI, APIC_EOI_ACK);
 	spin_unlock_irqrestore(&cobalt_lock, flags);
 }
 
diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h
index f3b0633..0e07adc 100644
--- a/arch/x86/um/asm/elf.h
+++ b/arch/x86/um/asm/elf.h
@@ -34,25 +34,25 @@
 #define ELF_ARCH        EM_386
 
 #define ELF_PLAT_INIT(regs, load_addr) do { \
-	PT_REGS_EBX(regs) = 0; \
-	PT_REGS_ECX(regs) = 0; \
-	PT_REGS_EDX(regs) = 0; \
-	PT_REGS_ESI(regs) = 0; \
-	PT_REGS_EDI(regs) = 0; \
-	PT_REGS_EBP(regs) = 0; \
-	PT_REGS_EAX(regs) = 0; \
+	PT_REGS_BX(regs) = 0; \
+	PT_REGS_CX(regs) = 0; \
+	PT_REGS_DX(regs) = 0; \
+	PT_REGS_SI(regs) = 0; \
+	PT_REGS_DI(regs) = 0; \
+	PT_REGS_BP(regs) = 0; \
+	PT_REGS_AX(regs) = 0; \
 } while (0)
 
 /* Shamelessly stolen from include/asm-i386/elf.h */
 
 #define ELF_CORE_COPY_REGS(pr_reg, regs) do {	\
-	pr_reg[0] = PT_REGS_EBX(regs);		\
-	pr_reg[1] = PT_REGS_ECX(regs);		\
-	pr_reg[2] = PT_REGS_EDX(regs);		\
-	pr_reg[3] = PT_REGS_ESI(regs);		\
-	pr_reg[4] = PT_REGS_EDI(regs);		\
-	pr_reg[5] = PT_REGS_EBP(regs);		\
-	pr_reg[6] = PT_REGS_EAX(regs);		\
+	pr_reg[0] = PT_REGS_BX(regs);		\
+	pr_reg[1] = PT_REGS_CX(regs);		\
+	pr_reg[2] = PT_REGS_DX(regs);		\
+	pr_reg[3] = PT_REGS_SI(regs);		\
+	pr_reg[4] = PT_REGS_DI(regs);		\
+	pr_reg[5] = PT_REGS_BP(regs);		\
+	pr_reg[6] = PT_REGS_AX(regs);		\
 	pr_reg[7] = PT_REGS_DS(regs);		\
 	pr_reg[8] = PT_REGS_ES(regs);		\
 	/* fake once used fs and gs selectors? */	\
@@ -130,13 +130,13 @@
 #define ELF_ARCH        EM_X86_64
 
 #define ELF_PLAT_INIT(regs, load_addr)    do { \
-	PT_REGS_RBX(regs) = 0; \
-	PT_REGS_RCX(regs) = 0; \
-	PT_REGS_RDX(regs) = 0; \
-	PT_REGS_RSI(regs) = 0; \
-	PT_REGS_RDI(regs) = 0; \
-	PT_REGS_RBP(regs) = 0; \
-	PT_REGS_RAX(regs) = 0; \
+	PT_REGS_BX(regs) = 0; \
+	PT_REGS_CX(regs) = 0; \
+	PT_REGS_DX(regs) = 0; \
+	PT_REGS_SI(regs) = 0; \
+	PT_REGS_DI(regs) = 0; \
+	PT_REGS_BP(regs) = 0; \
+	PT_REGS_AX(regs) = 0; \
 	PT_REGS_R8(regs) = 0; \
 	PT_REGS_R9(regs) = 0; \
 	PT_REGS_R10(regs) = 0; \
diff --git a/arch/x86/um/asm/ptrace.h b/arch/x86/um/asm/ptrace.h
index c8aca8c..950dfb7 100644
--- a/arch/x86/um/asm/ptrace.h
+++ b/arch/x86/um/asm/ptrace.h
@@ -1,5 +1,39 @@
+#ifndef __UM_X86_PTRACE_H
+#define __UM_X86_PTRACE_H
+
 #ifdef CONFIG_X86_32
 # include "ptrace_32.h"
 #else
 # include "ptrace_64.h"
 #endif
+
+#define PT_REGS_AX(r) UPT_AX(&(r)->regs)
+#define PT_REGS_BX(r) UPT_BX(&(r)->regs)
+#define PT_REGS_CX(r) UPT_CX(&(r)->regs)
+#define PT_REGS_DX(r) UPT_DX(&(r)->regs)
+
+#define PT_REGS_SI(r) UPT_SI(&(r)->regs)
+#define PT_REGS_DI(r) UPT_DI(&(r)->regs)
+#define PT_REGS_BP(r) UPT_BP(&(r)->regs)
+#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
+
+#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
+#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
+#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
+#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
+
+#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_AX(r)
+#define PT_REGS_SYSCALL_RET(r) PT_REGS_AX(r)
+
+#define PT_FIX_EXEC_STACK(sp) do ; while(0)
+
+#define profile_pc(regs) PT_REGS_IP(regs)
+
+#define UPT_RESTART_SYSCALL(r) (UPT_IP(r) -= 2)
+#define UPT_SET_SYSCALL_RETURN(r, res) (UPT_AX(r) = (res))
+
+static inline long regs_return_value(struct uml_pt_regs *regs)
+{
+	return UPT_AX(regs);
+}
+#endif /* __UM_X86_PTRACE_H */
diff --git a/arch/x86/um/asm/ptrace_32.h b/arch/x86/um/asm/ptrace_32.h
index 5d2a591..2cf2253 100644
--- a/arch/x86/um/asm/ptrace_32.h
+++ b/arch/x86/um/asm/ptrace_32.h
@@ -11,29 +11,6 @@
 #include "linux/compiler.h"
 #include "asm/ptrace-generic.h"
 
-#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
-#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs)
-#define PT_REGS_ECX(r) UPT_ECX(&(r)->regs)
-#define PT_REGS_EDX(r) UPT_EDX(&(r)->regs)
-#define PT_REGS_ESI(r) UPT_ESI(&(r)->regs)
-#define PT_REGS_EDI(r) UPT_EDI(&(r)->regs)
-#define PT_REGS_EBP(r) UPT_EBP(&(r)->regs)
-
-#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
-#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
-#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
-#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
-#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
-#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
-
-#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
-
-#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_EAX(r)
-#define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r)
-#define PT_FIX_EXEC_STACK(sp) do ; while(0)
-
-#define profile_pc(regs) PT_REGS_IP(regs)
-
 #define user_mode(r) UPT_IS_USER(&(r)->regs)
 
 /*
diff --git a/arch/x86/um/asm/ptrace_64.h b/arch/x86/um/asm/ptrace_64.h
index 706a0d8..ea7bff3 100644
--- a/arch/x86/um/asm/ptrace_64.h
+++ b/arch/x86/um/asm/ptrace_64.h
@@ -15,13 +15,6 @@
 
 #define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64
 
-#define PT_REGS_RBX(r) UPT_RBX(&(r)->regs)
-#define PT_REGS_RCX(r) UPT_RCX(&(r)->regs)
-#define PT_REGS_RDX(r) UPT_RDX(&(r)->regs)
-#define PT_REGS_RSI(r) UPT_RSI(&(r)->regs)
-#define PT_REGS_RDI(r) UPT_RDI(&(r)->regs)
-#define PT_REGS_RBP(r) UPT_RBP(&(r)->regs)
-#define PT_REGS_RAX(r) UPT_RAX(&(r)->regs)
 #define PT_REGS_R8(r) UPT_R8(&(r)->regs)
 #define PT_REGS_R9(r) UPT_R9(&(r)->regs)
 #define PT_REGS_R10(r) UPT_R10(&(r)->regs)
@@ -31,27 +24,8 @@
 #define PT_REGS_R14(r) UPT_R14(&(r)->regs)
 #define PT_REGS_R15(r) UPT_R15(&(r)->regs)
 
-#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
-#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
-#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
-#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
-#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
-#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
-
-#define PT_REGS_ORIG_RAX(r) UPT_ORIG_RAX(&(r)->regs)
-#define PT_REGS_RIP(r) UPT_IP(&(r)->regs)
-#define PT_REGS_SP(r) UPT_SP(&(r)->regs)
-
-#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
-
 /* XXX */
 #define user_mode(r) UPT_IS_USER(&(r)->regs)
-#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_RAX(r)
-#define PT_REGS_SYSCALL_RET(r) PT_REGS_RAX(r)
-
-#define PT_FIX_EXEC_STACK(sp) do ; while(0)
-
-#define profile_pc(regs) PT_REGS_IP(regs)
 
 struct user_desc;
 
diff --git a/arch/x86/um/checksum_32.S b/arch/x86/um/checksum_32.S
index f058d2f..8d0c420 100644
--- a/arch/x86/um/checksum_32.S
+++ b/arch/x86/um/checksum_32.S
@@ -26,6 +26,7 @@
  */
 
 #include <asm/errno.h>
+#include <asm/asm.h>
 				
 /*
  * computes a partial checksum, e.g. for TCP/UDP fragments
@@ -232,15 +233,11 @@
 
 #define SRC(y...)			\
 	9999: y;			\
-	.section __ex_table, "a";	\
-	.long 9999b, 6001f	;	\
-	.previous
+	_ASM_EXTABLE(9999b, 6001f)
 
 #define DST(y...)			\
 	9999: y;			\
-	.section __ex_table, "a";	\
-	.long 9999b, 6002f	;	\
-	.previous
+	_ASM_EXTABLE(9999b, 6002f)
 
 .align 4
 
diff --git a/arch/x86/um/shared/sysdep/ptrace.h b/arch/x86/um/shared/sysdep/ptrace.h
index 2bbe1ec2..6ce2d76 100644
--- a/arch/x86/um/shared/sysdep/ptrace.h
+++ b/arch/x86/um/shared/sysdep/ptrace.h
@@ -1,15 +1,74 @@
 #ifndef __SYSDEP_X86_PTRACE_H
 #define __SYSDEP_X86_PTRACE_H
 
+#include <generated/user_constants.h>
+#include "sysdep/faultinfo.h"
+
+#define MAX_REG_OFFSET (UM_FRAME_SIZE)
+#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
+
+#define REGS_IP(r) ((r)[HOST_IP])
+#define REGS_SP(r) ((r)[HOST_SP])
+#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
+#define REGS_AX(r) ((r)[HOST_AX])
+#define REGS_BX(r) ((r)[HOST_BX])
+#define REGS_CX(r) ((r)[HOST_CX])
+#define REGS_DX(r) ((r)[HOST_DX])
+#define REGS_SI(r) ((r)[HOST_SI])
+#define REGS_DI(r) ((r)[HOST_DI])
+#define REGS_BP(r) ((r)[HOST_BP])
+#define REGS_CS(r) ((r)[HOST_CS])
+#define REGS_SS(r) ((r)[HOST_SS])
+#define REGS_DS(r) ((r)[HOST_DS])
+#define REGS_ES(r) ((r)[HOST_ES])
+
+#define UPT_IP(r) REGS_IP((r)->gp)
+#define UPT_SP(r) REGS_SP((r)->gp)
+#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp)
+#define UPT_AX(r) REGS_AX((r)->gp)
+#define UPT_BX(r) REGS_BX((r)->gp)
+#define UPT_CX(r) REGS_CX((r)->gp)
+#define UPT_DX(r) REGS_DX((r)->gp)
+#define UPT_SI(r) REGS_SI((r)->gp)
+#define UPT_DI(r) REGS_DI((r)->gp)
+#define UPT_BP(r) REGS_BP((r)->gp)
+#define UPT_CS(r) REGS_CS((r)->gp)
+#define UPT_SS(r) REGS_SS((r)->gp)
+#define UPT_DS(r) REGS_DS((r)->gp)
+#define UPT_ES(r) REGS_ES((r)->gp)
+
 #ifdef __i386__
 #include "ptrace_32.h"
 #else
 #include "ptrace_64.h"
 #endif
 
-static inline long regs_return_value(struct uml_pt_regs *regs)
-{
-	return UPT_SYSCALL_RET(regs);
-}
+struct syscall_args {
+	unsigned long args[6];
+};
+
+#define SYSCALL_ARGS(r) ((struct syscall_args) \
+			 { .args = { UPT_SYSCALL_ARG1(r),	 \
+				     UPT_SYSCALL_ARG2(r),	 \
+				     UPT_SYSCALL_ARG3(r),	 \
+				     UPT_SYSCALL_ARG4(r),	 \
+				     UPT_SYSCALL_ARG5(r),	 \
+				     UPT_SYSCALL_ARG6(r) } } )
+
+struct uml_pt_regs {
+	unsigned long gp[MAX_REG_NR];
+	unsigned long fp[MAX_FP_NR];
+	struct faultinfo faultinfo;
+	long syscall;
+	int is_user;
+};
+
+#define EMPTY_UML_PT_REGS { }
+
+#define UPT_SYSCALL_NR(r) ((r)->syscall)
+#define UPT_FAULTINFO(r) (&(r)->faultinfo)
+#define UPT_IS_USER(r) ((r)->is_user)
+
+extern int user_context(unsigned long sp);
 
 #endif /* __SYSDEP_X86_PTRACE_H */
diff --git a/arch/x86/um/shared/sysdep/ptrace_32.h b/arch/x86/um/shared/sysdep/ptrace_32.h
index befd1df..b94a108 100644
--- a/arch/x86/um/shared/sysdep/ptrace_32.h
+++ b/arch/x86/um/shared/sysdep/ptrace_32.h
@@ -6,11 +6,7 @@
 #ifndef __SYSDEP_I386_PTRACE_H
 #define __SYSDEP_I386_PTRACE_H
 
-#include <generated/user_constants.h>
-#include "sysdep/faultinfo.h"
-
-#define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long))
-#define MAX_REG_OFFSET (UM_FRAME_SIZE)
+#define MAX_FP_NR HOST_FPX_SIZE
 
 static inline void update_debugregs(int seq) {}
 
@@ -24,90 +20,16 @@
 int get_using_sysemu(void);
 extern int sysemu_supported;
 
-#define REGS_IP(r) ((r)[HOST_IP])
-#define REGS_SP(r) ((r)[HOST_SP])
-#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
-#define REGS_EAX(r) ((r)[HOST_AX])
-#define REGS_EBX(r) ((r)[HOST_BX])
-#define REGS_ECX(r) ((r)[HOST_CX])
-#define REGS_EDX(r) ((r)[HOST_DX])
-#define REGS_ESI(r) ((r)[HOST_SI])
-#define REGS_EDI(r) ((r)[HOST_DI])
-#define REGS_EBP(r) ((r)[HOST_BP])
-#define REGS_CS(r) ((r)[HOST_CS])
-#define REGS_SS(r) ((r)[HOST_SS])
-#define REGS_DS(r) ((r)[HOST_DS])
-#define REGS_ES(r) ((r)[HOST_ES])
-#define REGS_FS(r) ((r)[HOST_FS])
-#define REGS_GS(r) ((r)[HOST_GS])
-
-#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res)
-
-#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
-#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
-
 #ifndef PTRACE_SYSEMU_SINGLESTEP
 #define PTRACE_SYSEMU_SINGLESTEP 32
 #endif
 
-struct uml_pt_regs {
-	unsigned long gp[MAX_REG_NR];
-	unsigned long fp[HOST_FPX_SIZE];
-	struct faultinfo faultinfo;
-	long syscall;
-	int is_user;
-};
-
-#define EMPTY_UML_PT_REGS { }
-
-#define UPT_IP(r) REGS_IP((r)->gp)
-#define UPT_SP(r) REGS_SP((r)->gp)
-#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp)
-#define UPT_EAX(r) REGS_EAX((r)->gp)
-#define UPT_EBX(r) REGS_EBX((r)->gp)
-#define UPT_ECX(r) REGS_ECX((r)->gp)
-#define UPT_EDX(r) REGS_EDX((r)->gp)
-#define UPT_ESI(r) REGS_ESI((r)->gp)
-#define UPT_EDI(r) REGS_EDI((r)->gp)
-#define UPT_EBP(r) REGS_EBP((r)->gp)
-#define UPT_ORIG_EAX(r) ((r)->syscall)
-#define UPT_CS(r) REGS_CS((r)->gp)
-#define UPT_SS(r) REGS_SS((r)->gp)
-#define UPT_DS(r) REGS_DS((r)->gp)
-#define UPT_ES(r) REGS_ES((r)->gp)
-#define UPT_FS(r) REGS_FS((r)->gp)
-#define UPT_GS(r) REGS_GS((r)->gp)
-
-#define UPT_SYSCALL_ARG1(r) UPT_EBX(r)
-#define UPT_SYSCALL_ARG2(r) UPT_ECX(r)
-#define UPT_SYSCALL_ARG3(r) UPT_EDX(r)
-#define UPT_SYSCALL_ARG4(r) UPT_ESI(r)
-#define UPT_SYSCALL_ARG5(r) UPT_EDI(r)
-#define UPT_SYSCALL_ARG6(r) UPT_EBP(r)
-
-extern int user_context(unsigned long sp);
-
-#define UPT_IS_USER(r) ((r)->is_user)
-
-struct syscall_args {
-	unsigned long args[6];
-};
-
-#define SYSCALL_ARGS(r) ((struct syscall_args) \
-			 { .args = { UPT_SYSCALL_ARG1(r),	\
-				     UPT_SYSCALL_ARG2(r),	\
-				     UPT_SYSCALL_ARG3(r),	\
-				     UPT_SYSCALL_ARG4(r),	\
-				     UPT_SYSCALL_ARG5(r),	\
-				     UPT_SYSCALL_ARG6(r) } } )
-
-#define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp)
-
-#define UPT_ORIG_SYSCALL(r) UPT_EAX(r)
-#define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r)
-#define UPT_SYSCALL_RET(r) UPT_EAX(r)
-
-#define UPT_FAULTINFO(r) (&(r)->faultinfo)
+#define UPT_SYSCALL_ARG1(r) UPT_BX(r)
+#define UPT_SYSCALL_ARG2(r) UPT_CX(r)
+#define UPT_SYSCALL_ARG3(r) UPT_DX(r)
+#define UPT_SYSCALL_ARG4(r) UPT_SI(r)
+#define UPT_SYSCALL_ARG5(r) UPT_DI(r)
+#define UPT_SYSCALL_ARG6(r) UPT_BP(r)
 
 extern void arch_init_registers(int pid);
 
diff --git a/arch/x86/um/shared/sysdep/ptrace_64.h b/arch/x86/um/shared/sysdep/ptrace_64.h
index 031edc5..919789f 100644
--- a/arch/x86/um/shared/sysdep/ptrace_64.h
+++ b/arch/x86/um/shared/sysdep/ptrace_64.h
@@ -8,22 +8,8 @@
 #ifndef __SYSDEP_X86_64_PTRACE_H
 #define __SYSDEP_X86_64_PTRACE_H
 
-#include <generated/user_constants.h>
-#include "sysdep/faultinfo.h"
+#define MAX_FP_NR HOST_FP_SIZE
 
-#define MAX_REG_OFFSET (UM_FRAME_SIZE)
-#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
-
-#define REGS_IP(r) ((r)[HOST_IP])
-#define REGS_SP(r) ((r)[HOST_SP])
-
-#define REGS_RBX(r) ((r)[HOST_BX])
-#define REGS_RCX(r) ((r)[HOST_CX])
-#define REGS_RDX(r) ((r)[HOST_DX])
-#define REGS_RSI(r) ((r)[HOST_SI])
-#define REGS_RDI(r) ((r)[HOST_DI])
-#define REGS_RBP(r) ((r)[HOST_BP])
-#define REGS_RAX(r) ((r)[HOST_AX])
 #define REGS_R8(r) ((r)[HOST_R8])
 #define REGS_R9(r) ((r)[HOST_R9])
 #define REGS_R10(r) ((r)[HOST_R10])
@@ -32,9 +18,6 @@
 #define REGS_R13(r) ((r)[HOST_R13])
 #define REGS_R14(r) ((r)[HOST_R14])
 #define REGS_R15(r) ((r)[HOST_R15])
-#define REGS_CS(r) ((r)[HOST_CS])
-#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
-#define REGS_SS(r) ((r)[HOST_SS])
 
 #define HOST_FS_BASE 21
 #define HOST_GS_BASE 22
@@ -58,45 +41,6 @@
 #define GS (HOST_GS * sizeof(long))
 #endif
 
-#define REGS_FS_BASE(r) ((r)[HOST_FS_BASE])
-#define REGS_GS_BASE(r) ((r)[HOST_GS_BASE])
-#define REGS_DS(r) ((r)[HOST_DS])
-#define REGS_ES(r) ((r)[HOST_ES])
-#define REGS_FS(r) ((r)[HOST_FS])
-#define REGS_GS(r) ((r)[HOST_GS])
-
-#define REGS_ORIG_RAX(r) ((r)[HOST_ORIG_AX])
-
-#define REGS_SET_SYSCALL_RETURN(r, res) REGS_RAX(r) = (res)
-
-#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
-#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
-
-#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
-
-#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
-
-#define REGS_TRAP(r) ((r)->trap_type)
-
-#define REGS_ERR(r) ((r)->fault_type)
-
-struct uml_pt_regs {
-	unsigned long gp[MAX_REG_NR];
-	unsigned long fp[HOST_FP_SIZE];
-	struct faultinfo faultinfo;
-	long syscall;
-	int is_user;
-};
-
-#define EMPTY_UML_PT_REGS { }
-
-#define UPT_RBX(r) REGS_RBX((r)->gp)
-#define UPT_RCX(r) REGS_RCX((r)->gp)
-#define UPT_RDX(r) REGS_RDX((r)->gp)
-#define UPT_RSI(r) REGS_RSI((r)->gp)
-#define UPT_RDI(r) REGS_RDI((r)->gp)
-#define UPT_RBP(r) REGS_RBP((r)->gp)
-#define UPT_RAX(r) REGS_RAX((r)->gp)
 #define UPT_R8(r) REGS_R8((r)->gp)
 #define UPT_R9(r) REGS_R9((r)->gp)
 #define UPT_R10(r) REGS_R10((r)->gp)
@@ -105,51 +49,14 @@
 #define UPT_R13(r) REGS_R13((r)->gp)
 #define UPT_R14(r) REGS_R14((r)->gp)
 #define UPT_R15(r) REGS_R15((r)->gp)
-#define UPT_CS(r) REGS_CS((r)->gp)
-#define UPT_FS_BASE(r) REGS_FS_BASE((r)->gp)
-#define UPT_FS(r) REGS_FS((r)->gp)
-#define UPT_GS_BASE(r) REGS_GS_BASE((r)->gp)
-#define UPT_GS(r) REGS_GS((r)->gp)
-#define UPT_DS(r) REGS_DS((r)->gp)
-#define UPT_ES(r) REGS_ES((r)->gp)
-#define UPT_CS(r) REGS_CS((r)->gp)
-#define UPT_SS(r) REGS_SS((r)->gp)
-#define UPT_ORIG_RAX(r) REGS_ORIG_RAX((r)->gp)
 
-#define UPT_IP(r) REGS_IP((r)->gp)
-#define UPT_SP(r) REGS_SP((r)->gp)
-
-#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp)
-#define UPT_SYSCALL_NR(r) ((r)->syscall)
-#define UPT_SYSCALL_RET(r) UPT_RAX(r)
-
-extern int user_context(unsigned long sp);
-
-#define UPT_IS_USER(r) ((r)->is_user)
-
-#define UPT_SYSCALL_ARG1(r) UPT_RDI(r)
-#define UPT_SYSCALL_ARG2(r) UPT_RSI(r)
-#define UPT_SYSCALL_ARG3(r) UPT_RDX(r)
+#define UPT_SYSCALL_ARG1(r) UPT_DI(r)
+#define UPT_SYSCALL_ARG2(r) UPT_SI(r)
+#define UPT_SYSCALL_ARG3(r) UPT_DX(r)
 #define UPT_SYSCALL_ARG4(r) UPT_R10(r)
 #define UPT_SYSCALL_ARG5(r) UPT_R8(r)
 #define UPT_SYSCALL_ARG6(r) UPT_R9(r)
 
-struct syscall_args {
-	unsigned long args[6];
-};
-
-#define SYSCALL_ARGS(r) ((struct syscall_args) \
-			 { .args = { UPT_SYSCALL_ARG1(r),	 \
-				     UPT_SYSCALL_ARG2(r),	 \
-				     UPT_SYSCALL_ARG3(r),	 \
-				     UPT_SYSCALL_ARG4(r),	 \
-				     UPT_SYSCALL_ARG5(r),	 \
-				     UPT_SYSCALL_ARG6(r) } } )
-
-#define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp)
-
-#define UPT_FAULTINFO(r) (&(r)->faultinfo)
-
 static inline void arch_init_registers(int pid)
 {
 }
diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c
index 4883b95..bb0fb03 100644
--- a/arch/x86/um/signal.c
+++ b/arch/x86/um/signal.c
@@ -156,6 +156,9 @@
 	struct sigcontext sc;
 	int err, pid;
 
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
 	err = copy_from_user(&sc, from, sizeof(sc));
 	if (err)
 		return err;
@@ -410,9 +413,9 @@
 
 	PT_REGS_SP(regs) = (unsigned long) frame;
 	PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
-	PT_REGS_EAX(regs) = (unsigned long) sig;
-	PT_REGS_EDX(regs) = (unsigned long) 0;
-	PT_REGS_ECX(regs) = (unsigned long) 0;
+	PT_REGS_AX(regs) = (unsigned long) sig;
+	PT_REGS_DX(regs) = (unsigned long) 0;
+	PT_REGS_CX(regs) = (unsigned long) 0;
 
 	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
 		ptrace_notify(SIGTRAP);
@@ -460,9 +463,9 @@
 
 	PT_REGS_SP(regs) = (unsigned long) frame;
 	PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
-	PT_REGS_EAX(regs) = (unsigned long) sig;
-	PT_REGS_EDX(regs) = (unsigned long) &frame->info;
-	PT_REGS_ECX(regs) = (unsigned long) &frame->uc;
+	PT_REGS_AX(regs) = (unsigned long) sig;
+	PT_REGS_DX(regs) = (unsigned long) &frame->info;
+	PT_REGS_CX(regs) = (unsigned long) &frame->uc;
 
 	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
 		ptrace_notify(SIGTRAP);
@@ -541,8 +544,8 @@
 			       set->sig[0]);
 	err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
 	if (sizeof(*set) == 16) {
-		__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
-		__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
+		err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
+		err |= __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
 	}
 	else
 		err |= __copy_to_user(&frame->uc.uc_sigmask, set,
@@ -570,17 +573,17 @@
 	}
 
 	PT_REGS_SP(regs) = (unsigned long) frame;
-	PT_REGS_RDI(regs) = sig;
+	PT_REGS_DI(regs) = sig;
 	/* In case the signal handler was declared without prototypes */
-	PT_REGS_RAX(regs) = 0;
+	PT_REGS_AX(regs) = 0;
 
 	/*
 	 * This also works for non SA_SIGINFO handlers because they expect the
 	 * next argument after the signal number on the stack.
 	 */
-	PT_REGS_RSI(regs) = (unsigned long) &frame->info;
-	PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
-	PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
+	PT_REGS_SI(regs) = (unsigned long) &frame->info;
+	PT_REGS_DX(regs) = (unsigned long) &frame->uc;
+	PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
  out:
 	return err;
 }
diff --git a/arch/x86/um/sys_call_table_64.c b/arch/x86/um/sys_call_table_64.c
index 9924776..170bd92 100644
--- a/arch/x86/um/sys_call_table_64.c
+++ b/arch/x86/um/sys_call_table_64.c
@@ -31,7 +31,6 @@
 #define stub_fork sys_fork
 #define stub_vfork sys_vfork
 #define stub_execve sys_execve
-#define stub_rt_sigsuspend sys_rt_sigsuspend
 #define stub_sigaltstack sys_sigaltstack
 #define stub_rt_sigreturn sys_rt_sigreturn
 
diff --git a/arch/x86/um/syscalls_32.c b/arch/x86/um/syscalls_32.c
index 70ca357..b853e86 100644
--- a/arch/x86/um/syscalls_32.c
+++ b/arch/x86/um/syscalls_32.c
@@ -44,10 +44,10 @@
 		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_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);
 	}
 
@@ -56,10 +56,10 @@
 	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_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;
diff --git a/arch/x86/um/sysrq_32.c b/arch/x86/um/sysrq_32.c
index 171b3e9..2d5cc51 100644
--- a/arch/x86/um/sysrq_32.c
+++ b/arch/x86/um/sysrq_32.c
@@ -23,12 +23,10 @@
         printk(" EFLAGS: %08lx\n    %s\n", PT_REGS_EFLAGS(regs),
 	       print_tainted());
         printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
-                PT_REGS_EAX(regs), PT_REGS_EBX(regs), 
-	       PT_REGS_ECX(regs), 
-	       PT_REGS_EDX(regs));
+               PT_REGS_AX(regs), PT_REGS_BX(regs), 
+	       PT_REGS_CX(regs), PT_REGS_DX(regs));
         printk("ESI: %08lx EDI: %08lx EBP: %08lx",
-	       PT_REGS_ESI(regs), PT_REGS_EDI(regs), 
-	       PT_REGS_EBP(regs));
+	       PT_REGS_SI(regs), PT_REGS_DI(regs), PT_REGS_BP(regs));
         printk(" DS: %04lx ES: %04lx\n",
 	       0xffff & PT_REGS_DS(regs), 
 	       0xffff & PT_REGS_ES(regs));
diff --git a/arch/x86/um/sysrq_64.c b/arch/x86/um/sysrq_64.c
index e891343..08258f1 100644
--- a/arch/x86/um/sysrq_64.c
+++ b/arch/x86/um/sysrq_64.c
@@ -19,15 +19,15 @@
 	printk(KERN_INFO "Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current),
 		current->comm, print_tainted(), init_utsname()->release);
 	printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff,
-	       PT_REGS_RIP(regs));
+	       PT_REGS_IP(regs));
 	printk(KERN_INFO "RSP: %016lx  EFLAGS: %08lx\n", PT_REGS_SP(regs),
 	       PT_REGS_EFLAGS(regs));
 	printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n",
-	       PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs));
+	       PT_REGS_AX(regs), PT_REGS_BX(regs), PT_REGS_CX(regs));
 	printk(KERN_INFO "RDX: %016lx RSI: %016lx RDI: %016lx\n",
-	       PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs));
+	       PT_REGS_DX(regs), PT_REGS_SI(regs), PT_REGS_DI(regs));
 	printk(KERN_INFO "RBP: %016lx R08: %016lx R09: %016lx\n",
-	       PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs));
+	       PT_REGS_BP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs));
 	printk(KERN_INFO "R10: %016lx R11: %016lx R12: %016lx\n",
 	       PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs));
 	printk(KERN_INFO "R13: %016lx R14: %016lx R15: %016lx\n",
diff --git a/arch/x86/um/tls_32.c b/arch/x86/um/tls_32.c
index c6c7131..baba84f 100644
--- a/arch/x86/um/tls_32.c
+++ b/arch/x86/um/tls_32.c
@@ -219,7 +219,7 @@
 	int idx, ret = -EFAULT;
 
 	if (copy_from_user(&info,
-			   (void __user *) UPT_ESI(&new->thread.regs.regs),
+			   (void __user *) UPT_SI(&new->thread.regs.regs),
 			   sizeof(info)))
 		goto out;
 
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index add2c2d..96ab2c0 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -20,5 +20,5 @@
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
 obj-$(CONFIG_XEN_DEBUG_FS)	+= debugfs.o
-obj-$(CONFIG_XEN_DOM0)		+= vga.o
+obj-$(CONFIG_XEN_DOM0)		+= apic.o vga.o
 obj-$(CONFIG_SWIOTLB_XEN)	+= pci-swiotlb-xen.o
diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c
new file mode 100644
index 0000000..ec57bd3
--- /dev/null
+++ b/arch/x86/xen/apic.c
@@ -0,0 +1,33 @@
+#include <linux/init.h>
+
+#include <asm/x86_init.h>
+#include <asm/apic.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/xen.h>
+#include <xen/interface/physdev.h>
+
+unsigned int xen_io_apic_read(unsigned apic, unsigned reg)
+{
+	struct physdev_apic apic_op;
+	int ret;
+
+	apic_op.apic_physbase = mpc_ioapic_addr(apic);
+	apic_op.reg = reg;
+	ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op);
+	if (!ret)
+		return apic_op.value;
+
+	/* fallback to return an emulated IO_APIC values */
+	if (reg == 0x1)
+		return 0x00170020;
+	else if (reg == 0x0)
+		return apic << 24;
+
+	return 0xfd;
+}
+
+void __init xen_init_apic(void)
+{
+	x86_io_apic_ops.read = xen_io_apic_read;
+}
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 95dccce..c0f5fac 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1396,6 +1396,8 @@
 		xen_start_info->console.domU.mfn = 0;
 		xen_start_info->console.domU.evtchn = 0;
 
+		xen_init_apic();
+
 		/* Make sure ACS will be enabled */
 		pci_request_acs();
 	}
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 69f5857..3506cd4 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1864,7 +1864,6 @@
 #endif	/* CONFIG_X86_64 */
 
 static unsigned char dummy_mapping[PAGE_SIZE] __page_aligned_bss;
-static unsigned char fake_ioapic_mapping[PAGE_SIZE] __page_aligned_bss;
 
 static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 {
@@ -1905,7 +1904,7 @@
 		 * We just don't map the IO APIC - all access is via
 		 * hypercalls.  Keep the address in the pte for reference.
 		 */
-		pte = pfn_pte(PFN_DOWN(__pa(fake_ioapic_mapping)), PAGE_KERNEL);
+		pte = pfn_pte(PFN_DOWN(__pa(dummy_mapping)), PAGE_KERNEL);
 		break;
 #endif
 
@@ -2070,7 +2069,6 @@
 	pv_mmu_ops = xen_mmu_ops;
 
 	memset(dummy_mapping, 0xff, PAGE_SIZE);
-	memset(fake_ioapic_mapping, 0xfd, PAGE_SIZE);
 }
 
 /* Protected by xen_reservation_lock. */
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index b040b0e..f9643fc 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -14,6 +14,7 @@
 #include <asm/thread_info.h>
 #include <asm/processor-flags.h>
 #include <asm/segment.h>
+#include <asm/asm.h>
 
 #include <xen/interface/xen.h>
 
@@ -137,10 +138,7 @@
 
 1:	iret
 xen_iret_end_crit:
-.section __ex_table, "a"
-	.align 4
-	.long 1b, iret_exc
-.previous
+	_ASM_EXTABLE(1b, iret_exc)
 
 hyper_iret:
 	/* put this out of line since its very rarely used */
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index b095739..45c0c06 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -92,11 +92,15 @@
 
 #ifdef CONFIG_XEN_DOM0
 void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size);
+void __init xen_init_apic(void);
 #else
 static inline void __init xen_init_vga(const struct dom0_vga_console_info *info,
 				       size_t size)
 {
 }
+static inline void __init xen_init_apic(void)
+{
+}
 #endif
 
 /* Declare an asm function, along with symbols needed to make it
diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h
index 3acb26e..5c371d8 100644
--- a/arch/xtensa/include/asm/processor.h
+++ b/arch/xtensa/include/asm/processor.h
@@ -168,9 +168,6 @@
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while(0)
 
-/* Prepare to copy thread state - unlazy all lazy status */
-extern void prepare_to_copy(struct task_struct*);
-
 /* Create a kernel thread without removing it from tasklists */
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
diff --git a/arch/xtensa/include/asm/signal.h b/arch/xtensa/include/asm/signal.h
index 633ba73..7f201b9 100644
--- a/arch/xtensa/include/asm/signal.h
+++ b/arch/xtensa/include/asm/signal.h
@@ -120,13 +120,6 @@
 #define SIG_ERR	((__sighandler_t)-1)	/* error return from signal */
 
 #ifdef __KERNEL__
-struct old_sigaction {
-	__sighandler_t sa_handler;
-	old_sigset_t sa_mask;
-	unsigned long sa_flags;
-	void (*sa_restorer)(void);
-};
-
 struct sigaction {
 	__sighandler_t sa_handler;
 	unsigned long sa_flags;
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
index efcf33b..0b9f2e1 100644
--- a/arch/xtensa/include/asm/syscall.h
+++ b/arch/xtensa/include/asm/syscall.h
@@ -15,10 +15,6 @@
 asmlinkage long xtensa_ptrace(long, long, long, long);
 asmlinkage long xtensa_sigreturn(struct pt_regs*);
 asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
-asmlinkage long xtensa_sigsuspend(struct pt_regs*);
-asmlinkage long xtensa_rt_sigsuspend(struct pt_regs*);
-asmlinkage long xtensa_sigaction(int, const struct old_sigaction*,
-				 struct old_sigaction*);
 asmlinkage long xtensa_sigaltstack(struct pt_regs *regs);
 asmlinkage long sys_rt_sigaction(int,
 				 const struct sigaction __user *,
diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h
index 6abbedd..81abfd5 100644
--- a/arch/xtensa/include/asm/thread_info.h
+++ b/arch/xtensa/include/asm/thread_info.h
@@ -131,6 +131,7 @@
 #define TIF_IRET		4	/* return with iret */
 #define TIF_MEMDIE		5	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
+#define TIF_NOTIFY_RESUME	7	/* callback before returning to user */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h
index 798ee6d..bc7e005 100644
--- a/arch/xtensa/include/asm/unistd.h
+++ b/arch/xtensa/include/asm/unistd.h
@@ -507,7 +507,7 @@
 #define __NR_rt_sigqueueinfo 			230
 __SYSCALL(230, sys_rt_sigqueueinfo, 3)
 #define __NR_rt_sigsuspend 			231
-__SYSCALL(231, xtensa_rt_sigsuspend, 2)
+__SYSCALL(231, sys_rt_sigsuspend, 2)
 
 /* Message */
 
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 6223f33..7e62360 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -409,16 +409,16 @@
 	l32i	a4, a2, TI_FLAGS
 
 	_bbsi.l	a4, TIF_NEED_RESCHED, 3f
+	_bbsi.l	a4, TIF_NOTIFY_RESUME, 2f
 	_bbci.l	a4, TIF_SIGPENDING, 4f
 
-	l32i	a4, a1, PT_DEPC
+2:	l32i	a4, a1, PT_DEPC
 	bgeui	a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
 
 	/* Call do_signal() */
 
-	movi	a4, do_signal	# int do_signal(struct pt_regs*, sigset_t*)
+	movi	a4, do_notify_resume	# int do_notify_resume(struct pt_regs*)
 	mov	a6, a1
-	movi	a7, 0
 	callx4	a4
 	j	1b
 
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 6a2d6ed..9b306e5 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -140,13 +140,16 @@
 }
 
 /*
- * This is called before the thread is copied. 
+ * this gets called so that we can store coprocessor state into memory and
+ * copy the current task into the new thread.
  */
-void prepare_to_copy(struct task_struct *tsk)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 #if XTENSA_HAVE_COPROCESSORS
-	coprocessor_flush_all(task_thread_info(tsk));
+	coprocessor_flush_all(task_thread_info(src));
 #endif
+	*dst = *src;
+	return 0;
 }
 
 /*
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index d78869a..c5e4ec0 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -20,6 +20,7 @@
 #include <linux/ptrace.h>
 #include <linux/personality.h>
 #include <linux/freezer.h>
+#include <linux/tracehook.h>
 
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -31,8 +32,6 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
-
 extern struct task_struct *coproc_owners[];
 
 struct rt_sigframe
@@ -248,6 +247,9 @@
 	sigset_t set;
 	int ret;
 
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
 	if (regs->depc > 64)
 		panic("rt_sigreturn in double exception!\n");
 
@@ -426,37 +428,6 @@
 	return -EFAULT;
 }
 
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-
-asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset, 
-    				     size_t sigsetsize,
-    				     long a2, long a3, long a4, long a5, 
-				     struct pt_regs *regs)
-{
-	sigset_t saveset, 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, ~_BLOCKABLE);
-	saveset = current->blocked;
-	set_current_blocked(&newset);
-
-	regs->areg[2] = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(regs, &saveset))
-			return -EINTR;
-	}
-}
-
 asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, 
 				   stack_t __user *uoss,
     				   long a2, long a3, long a4, long a5,
@@ -476,19 +447,19 @@
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-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;
-
-	if (!user_mode(regs))
-		return 0;
+	sigset_t oldset;
 
 	if (try_to_freeze())
 		goto no_signal;
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else
 		oldset = &current->blocked;
 
 	task_pt_regs(current)->icountlevel = 0;
@@ -532,13 +503,14 @@
 		/* Set up the stack frame */
 		ret = setup_frame(signr, &ka, &info, oldset, regs);
 		if (ret)
-			return ret;
+			return;
 
+		clear_thread_flag(TIF_RESTORE_SIGMASK);
 		block_sigmask(&ka, signr);
 		if (current->ptrace & PT_SINGLESTEP)
 			task_pt_regs(current)->icountlevel = 1;
 
-		return 1;
+		return;
 	}
 
 no_signal:
@@ -558,8 +530,27 @@
 			break;
 		}
 	}
+
+	/* If there's no signal to deliver, we just restore the saved mask.  */
+	if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+		set_current_blocked(&current->saved_sigmask);
+
 	if (current->ptrace & PT_SINGLESTEP)
 		task_pt_regs(current)->icountlevel = 1;
-	return 0;
+	return;
 }
 
+void do_notify_resume(struct pt_regs *regs)
+{
+	if (!user_mode(regs))
+		return;
+
+	if (test_thread_flag(TIF_SIGPENDING))
+		do_signal(regs);
+
+	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+		tracehook_notify_resume(regs);
+		if (current->replacement_session_keyring)
+			key_replace_session_keyring();
+	}
+}
diff --git a/arch/xtensa/variants/s6000/dmac.c b/arch/xtensa/variants/s6000/dmac.c
index dc7f7c5..340f5bb 100644
--- a/arch/xtensa/variants/s6000/dmac.c
+++ b/arch/xtensa/variants/s6000/dmac.c
@@ -1,5 +1,5 @@
 /*
- * Authors:	Oskar Schirmer <os@emlix.com>
+ * Authors:	Oskar Schirmer <oskar@scara.com>
  *		Daniel Gloeckner <dg@emlix.com>
  * (c) 2008 emlix GmbH http://www.emlix.com
  *
diff --git a/arch/xtensa/variants/s6000/gpio.c b/arch/xtensa/variants/s6000/gpio.c
index 7af0757..b89541b 100644
--- a/arch/xtensa/variants/s6000/gpio.c
+++ b/arch/xtensa/variants/s6000/gpio.c
@@ -2,8 +2,8 @@
  * s6000 gpio driver
  *
  * Copyright (c) 2009 emlix GmbH
- * Authors:	Oskar Schirmer <os@emlix.com>
- *		Johannes Weiner <jw@emlix.com>
+ * Authors:	Oskar Schirmer <oskar@scara.com>
+ *		Johannes Weiner <hannes@cmpxchg.org>
  *		Daniel Gloeckner <dg@emlix.com>
  */
 #include <linux/bitops.h>
diff --git a/arch/xtensa/variants/s6000/include/variant/dmac.h b/arch/xtensa/variants/s6000/include/variant/dmac.h
index e81735b..3f88d9f 100644
--- a/arch/xtensa/variants/s6000/include/variant/dmac.h
+++ b/arch/xtensa/variants/s6000/include/variant/dmac.h
@@ -8,7 +8,7 @@
  * Copyright (C) 2006 Tensilica Inc.
  * Copyright (C) 2008 Emlix GmbH <info@emlix.com>
  * Authors:	Fabian Godehardt <fg@emlix.com>
- *		Oskar Schirmer <os@emlix.com>
+ *		Oskar Schirmer <oskar@scara.com>
  *		Daniel Gloeckner <dg@emlix.com>
  */
 
diff --git a/arch/xtensa/variants/s6000/irq.c b/arch/xtensa/variants/s6000/irq.c
index 6651e32..81a241e 100644
--- a/arch/xtensa/variants/s6000/irq.c
+++ b/arch/xtensa/variants/s6000/irq.c
@@ -2,8 +2,8 @@
  * s6000 irq crossbar
  *
  * Copyright (c) 2009 emlix GmbH
- * Authors:	Johannes Weiner <jw@emlix.com>
- *		Oskar Schirmer <os@emlix.com>
+ * Authors:	Johannes Weiner <hannes@cmpxchg.org>
+ *		Oskar Schirmer <oskar@scara.com>
  */
 #include <linux/io.h>
 #include <asm/irq.h>
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index ea84a23..126c341 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -28,34 +28,12 @@
 struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
 EXPORT_SYMBOL_GPL(blkio_root_cgroup);
 
-static struct cgroup_subsys_state *blkiocg_create(struct cgroup *);
-static int blkiocg_can_attach(struct cgroup *, struct cgroup_taskset *);
-static void blkiocg_attach(struct cgroup *, struct cgroup_taskset *);
-static void blkiocg_destroy(struct cgroup *);
-static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
-
 /* for encoding cft->private value on file */
 #define BLKIOFILE_PRIVATE(x, val)	(((x) << 16) | (val))
 /* What policy owns the file, proportional or throttle */
 #define BLKIOFILE_POLICY(val)		(((val) >> 16) & 0xffff)
 #define BLKIOFILE_ATTR(val)		((val) & 0xffff)
 
-struct cgroup_subsys blkio_subsys = {
-	.name = "blkio",
-	.create = blkiocg_create,
-	.can_attach = blkiocg_can_attach,
-	.attach = blkiocg_attach,
-	.destroy = blkiocg_destroy,
-	.populate = blkiocg_populate,
-#ifdef CONFIG_BLK_CGROUP
-	/* note: blkio_subsys_id is otherwise defined in blk-cgroup.h */
-	.subsys_id = blkio_subsys_id,
-#endif
-	.use_id = 1,
-	.module = THIS_MODULE,
-};
-EXPORT_SYMBOL_GPL(blkio_subsys);
-
 static inline void blkio_policy_insert_node(struct blkio_cgroup *blkcg,
 					    struct blkio_policy_node *pn)
 {
@@ -1537,14 +1515,9 @@
 		.read_map = blkiocg_file_read_map,
 	},
 #endif
+	{ }	/* terminate */
 };
 
-static int blkiocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup)
-{
-	return cgroup_add_files(cgroup, subsys, blkio_files,
-				ARRAY_SIZE(blkio_files));
-}
-
 static void blkiocg_destroy(struct cgroup *cgroup)
 {
 	struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
@@ -1658,6 +1631,22 @@
 	}
 }
 
+struct cgroup_subsys blkio_subsys = {
+	.name = "blkio",
+	.create = blkiocg_create,
+	.can_attach = blkiocg_can_attach,
+	.attach = blkiocg_attach,
+	.destroy = blkiocg_destroy,
+#ifdef CONFIG_BLK_CGROUP
+	/* note: blkio_subsys_id is otherwise defined in blk-cgroup.h */
+	.subsys_id = blkio_subsys_id,
+#endif
+	.base_cftypes = blkio_files,
+	.use_id = 1,
+	.module = THIS_MODULE,
+};
+EXPORT_SYMBOL_GPL(blkio_subsys);
+
 void blkio_policy_register(struct blkio_policy_type *blkiop)
 {
 	spin_lock(&blkio_list_lock);
diff --git a/crypto/xor.c b/crypto/xor.c
index b75182d..65c7b41 100644
--- a/crypto/xor.c
+++ b/crypto/xor.c
@@ -21,6 +21,7 @@
 #include <linux/gfp.h>
 #include <linux/raid/xor.h>
 #include <linux/jiffies.h>
+#include <linux/preempt.h>
 #include <asm/xor.h>
 
 /* The xor routines to use.  */
@@ -63,12 +64,14 @@
 do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
 {
 	int speed;
-	unsigned long now;
+	unsigned long now, j;
 	int i, count, max;
 
 	tmpl->next = template_list;
 	template_list = tmpl;
 
+	preempt_disable();
+
 	/*
 	 * Count the number of XORs done during a whole jiffy, and use
 	 * this to calculate the speed of checksumming.  We use a 2-page
@@ -76,9 +79,11 @@
 	 */
 	max = 0;
 	for (i = 0; i < 5; i++) {
-		now = jiffies;
+		j = jiffies;
 		count = 0;
-		while (jiffies == now) {
+		while ((now = jiffies) == j)
+			cpu_relax();
+		while (time_before(jiffies, now + 1)) {
 			mb(); /* prevent loop optimzation */
 			tmpl->do_2(BENCH_SIZE, b1, b2);
 			mb();
@@ -89,6 +94,8 @@
 			max = count;
 	}
 
+	preempt_enable();
+
 	speed = max * (HZ * BENCH_SIZE / 1024);
 	tmpl->speed = speed;
 
@@ -129,9 +136,9 @@
 
 	if (fastest) {
 		printk(KERN_INFO "xor: automatically using best "
-			"checksumming function: %s\n",
-			fastest->name);
+				 "checksumming function:\n");
 		xor_speed(fastest);
+		goto out;
 	} else {
 		printk(KERN_INFO "xor: measuring software checksum speed\n");
 		XOR_TRY_TEMPLATES;
@@ -146,6 +153,7 @@
 
 #undef xor_speed
 
+ out:
 	free_pages((unsigned long)b1, 2);
 
 	active_template = fastest;
diff --git a/drivers/Kconfig b/drivers/Kconfig
index d236aef..bfc9186 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -140,4 +140,12 @@
 
 source "drivers/devfreq/Kconfig"
 
+source "drivers/extcon/Kconfig"
+
+source "drivers/memory/Kconfig"
+
+source "drivers/iio/Kconfig"
+
+source "drivers/vme/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 95952c8..0ee98d5 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -92,7 +92,6 @@
 obj-$(CONFIG_ACCESSIBILITY)	+= accessibility/
 obj-$(CONFIG_ISDN)		+= isdn/
 obj-$(CONFIG_EDAC)		+= edac/
-obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
 obj-y				+= lguest/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
@@ -134,3 +133,7 @@
 obj-$(CONFIG_HYPERV)		+= hv/
 
 obj-$(CONFIG_PM_DEVFREQ)	+= devfreq/
+obj-$(CONFIG_EXTCON)		+= extcon/
+obj-$(CONFIG_MEMORY)		+= memory/
+obj-$(CONFIG_IIO)		+= iio/
+obj-$(CONFIG_VME_BUS)		+= vme/
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 29a4a5c..1564e09 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -69,6 +69,7 @@
 	up_read(&bus_type_sem);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(register_acpi_bus_type);
 
 static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
 {
@@ -85,6 +86,7 @@
 	up_read(&bus_type_sem);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
 
 /* Get device's handler per its address under its parent */
 struct acpi_find_child {
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 4a29763..a128082 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -720,21 +720,21 @@
 	       acpi_device_bid(device));
 	for (i = 0; i < link->irq.possible_count; i++) {
 		if (link->irq.active == link->irq.possible[i]) {
-			printk(" *%d", link->irq.possible[i]);
+			printk(KERN_CONT " *%d", link->irq.possible[i]);
 			found = 1;
 		} else
-			printk(" %d", link->irq.possible[i]);
+			printk(KERN_CONT " %d", link->irq.possible[i]);
 	}
 
-	printk(")");
+	printk(KERN_CONT ")");
 
 	if (!found)
-		printk(" *%d", link->irq.active);
+		printk(KERN_CONT " *%d", link->irq.active);
 
 	if (!link->device->status.enabled)
-		printk(", disabled.");
+		printk(KERN_CONT ", disabled.");
 
-	printk("\n");
+	printk(KERN_CONT "\n");
 
 	list_add_tail(&link->list, &acpi_link_list);
 
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index eb6fd23..06527c5 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -887,7 +887,7 @@
 		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
 		if (ACPI_SUCCESS(status)) {
 			sleep_states[i] = 1;
-			printk(" S%d", i);
+			printk(KERN_CONT " S%d", i);
 		}
 	}
 
@@ -901,7 +901,7 @@
 		hibernation_set_ops(old_suspend_ordering ?
 			&acpi_hibernation_ops_old : &acpi_hibernation_ops);
 		sleep_states[ACPI_STATE_S4] = 1;
-		printk(" S4");
+		printk(KERN_CONT " S4");
 		if (!nosigcheck) {
 			acpi_get_table(ACPI_SIG_FACS, 1,
 				(struct acpi_table_header **)&facs);
@@ -914,11 +914,11 @@
 	status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
 	if (ACPI_SUCCESS(status)) {
 		sleep_states[ACPI_STATE_S5] = 1;
-		printk(" S5");
+		printk(KERN_CONT " S5");
 		pm_power_off_prepare = acpi_power_off_prepare;
 		pm_power_off = acpi_power_off;
 	}
-	printk(")\n");
+	printk(KERN_CONT ")\n");
 	/*
 	 * Register the tts_notifier to reboot notifier list so that the _TTS
 	 * object can also be evaluated when the system enters S5.
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index b002a47..adbbc1c 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -382,3 +382,33 @@
 }
 
 EXPORT_SYMBOL(acpi_evaluate_reference);
+
+acpi_status
+acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld *pld)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *output;
+
+	status = acpi_evaluate_object(handle, "_PLD", NULL, &buffer);
+
+	if (ACPI_FAILURE(status))
+		return status;
+
+	output = buffer.pointer;
+
+	if (!output || output->type != ACPI_TYPE_PACKAGE
+	    || !output->package.count
+	    || output->package.elements[0].type != ACPI_TYPE_BUFFER
+	    || output->package.elements[0].buffer.length > sizeof(*pld)) {
+		status = AE_TYPE;
+		goto out;
+	}
+
+	memcpy(pld, output->package.elements[0].buffer.pointer,
+	       output->package.elements[0].buffer.length);
+out:
+	kfree(buffer.pointer);
+	return status;
+}
+EXPORT_SYMBOL(acpi_get_physical_device_location);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 6bdedd7..2be8ef1 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -416,6 +416,15 @@
 
 	  If unsure, say N.
 
+config PATA_EP93XX
+	tristate "Cirrus Logic EP93xx PATA support"
+	depends on ARCH_EP93XX
+	help
+	  This option enables support for the PATA controller in
+	  the Cirrus Logic EP9312 and EP9315 ARM CPU.
+
+	  If unsure, say N.
+
 config PATA_HPT366
 	tristate "HPT 366/368 PATA support"
 	depends on PCI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 6ece5b7..a454a13 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -43,6 +43,7 @@
 obj-$(CONFIG_PATA_CS5536)	+= pata_cs5536.o
 obj-$(CONFIG_PATA_CYPRESS)	+= pata_cypress.o
 obj-$(CONFIG_PATA_EFAR)		+= pata_efar.o
+obj-$(CONFIG_PATA_EP93XX)	+= pata_ep93xx.o
 obj-$(CONFIG_PATA_HPT366)	+= pata_hpt366.o
 obj-$(CONFIG_PATA_HPT37X)	+= pata_hpt37x.o
 obj-$(CONFIG_PATA_HPT3X2N)	+= pata_hpt3x2n.o
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 7df56ec..aae1156 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -177,7 +177,7 @@
 	if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0)
 		return -ENODEV;
 
-	if (id->driver_data & ATA_GEN_INTEL_IDER)
+	if ((id->driver_data & ATA_GEN_INTEL_IDER) && !all_generic_ide)
 		if (!is_intel_ider(dev))
 			return -ENODEV;
 
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 7857e8f..3c809bf 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -1554,6 +1554,39 @@
 	return false;
 }
 
+static int prefer_ms_hyperv = 1;
+module_param(prefer_ms_hyperv, int, 0);
+
+static void piix_ignore_devices_quirk(struct ata_host *host)
+{
+#if IS_ENABLED(CONFIG_HYPERV_STORAGE)
+	static const struct dmi_system_id ignore_hyperv[] = {
+		{
+			/* On Hyper-V hypervisors the disks are exposed on
+			 * both the emulated SATA controller and on the
+			 * paravirtualised drivers.  The CD/DVD devices
+			 * are only exposed on the emulated controller.
+			 * Request we ignore ATA devices on this host.
+			 */
+			.ident = "Hyper-V Virtual Machine",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR,
+						"Microsoft Corporation"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+			},
+		},
+		{ }	/* terminate list */
+	};
+	const struct dmi_system_id *dmi = dmi_first_match(ignore_hyperv);
+
+	if (dmi && prefer_ms_hyperv) {
+		host->flags |= ATA_HOST_IGNORE_ATA;
+		dev_info(host->dev, "%s detected, ATA device ignore set\n",
+			dmi->ident);
+	}
+#endif
+}
+
 /**
  *	piix_init_one - Register PIIX ATA PCI device with kernel services
  *	@pdev: PCI device to register
@@ -1669,6 +1702,9 @@
 	}
 	host->flags |= ATA_HOST_PARALLEL_SCAN;
 
+	/* Allow hosts to specify device types to ignore when scanning. */
+	piix_ignore_devices_quirk(host);
+
 	pci_set_master(pdev);
 	return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
 }
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 23763a1..cece3a4 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1973,6 +1973,12 @@
 	if (class == ATA_DEV_ATA) {
 		if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
 			goto err_out;
+		if (ap->host->flags & ATA_HOST_IGNORE_ATA &&
+							ata_id_is_ata(id)) {
+			ata_dev_dbg(dev,
+				"host indicates ignore ATA devices, ignored\n");
+			return -ENOENT;
+		}
 	} else {
 		if (ata_id_is_ata(id))
 			goto err_out;
@@ -4051,6 +4057,7 @@
 	{ "_NEC DV5800A", 	NULL,		ATA_HORKAGE_NODMA },
 	{ "SAMSUNG CD-ROM SN-124", "N001",	ATA_HORKAGE_NODMA },
 	{ "Seagate STT20000A", NULL,		ATA_HORKAGE_NODMA },
+	{ "2GB ATA Flash Disk", "ADMA428M",	ATA_HORKAGE_NODMA },
 	/* Odd clown on sil3726/4726 PMPs */
 	{ "Config  Disk",	NULL,		ATA_HORKAGE_DISABLE },
 
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index d1fbd59..6d53cf9 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2047,6 +2047,26 @@
 }
 
 /**
+ *	ata_eh_worth_retry - analyze error and decide whether to retry
+ *	@qc: qc to possibly retry
+ *
+ *	Look at the cause of the error and decide if a retry
+ * 	might be useful or not.  We don't want to retry media errors
+ *	because the drive itself has probably already taken 10-30 seconds
+ *	doing its own internal retries before reporting the failure.
+ */
+static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc)
+{
+	if (qc->flags & AC_ERR_MEDIA)
+		return 0;	/* don't retry media errors */
+	if (qc->flags & ATA_QCFLAG_IO)
+		return 1;	/* otherwise retry anything from fs stack */
+	if (qc->err_mask & AC_ERR_INVALID)
+		return 0;	/* don't retry these */
+	return qc->err_mask != AC_ERR_DEV;  /* retry if not dev error */
+}
+
+/**
  *	ata_eh_link_autopsy - analyze error and determine recovery action
  *	@link: host link to perform autopsy on
  *
@@ -2120,9 +2140,7 @@
 			qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
 
 		/* determine whether the command is worth retrying */
-		if (qc->flags & ATA_QCFLAG_IO ||
-		    (!(qc->err_mask & AC_ERR_INVALID) &&
-		     qc->err_mask != AC_ERR_DEV))
+		if (ata_eh_worth_retry(qc))
 			qc->flags |= ATA_QCFLAG_RETRY;
 
 		/* accumulate error info */
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
new file mode 100644
index 0000000..6ef2e37
--- /dev/null
+++ b/drivers/ata/pata_ep93xx.c
@@ -0,0 +1,1044 @@
+/*
+ * EP93XX PATA controller driver.
+ *
+ * Copyright (c) 2012, Metasoft s.c.
+ *	Rafal Prylowski <prylowski@metasoft.pl>
+ *
+ * Based on pata_scc.c, pata_icside.c and on earlier version of EP93XX
+ * PATA driver by Lennert Buytenhek and Alessandro Zummo.
+ * Read/Write timings, resource management and other improvements
+ * from driver by Joao Ramos and Bartlomiej Zolnierkiewicz.
+ * DMA engine support based on spi-ep93xx.c by Mika Westerberg.
+ *
+ * Original copyrights:
+ *
+ * Support for Cirrus Logic's EP93xx (EP9312, EP9315) CPUs
+ * PATA host controller driver.
+ *
+ * Copyright (c) 2009, Bartlomiej Zolnierkiewicz
+ *
+ * Heavily based on the ep93xx-ide.c driver:
+ *
+ * Copyright (c) 2009, Joao Ramos <joao.ramos@inov.pt>
+ *		      INESC Inovacao (INOV)
+ *
+ * EP93XX PATA controller driver.
+ * Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * An ATA driver for the Cirrus Logic EP93xx PATA controller.
+ *
+ * Based on an earlier version by Alessandro Zummo, which is:
+ *   Copyright (C) 2006 Tower Technologies
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/ktime.h>
+
+#include <mach/dma.h>
+#include <mach/platform.h>
+
+#define DRV_NAME	"ep93xx-ide"
+#define DRV_VERSION	"1.0"
+
+enum {
+	/* IDE Control Register */
+	IDECTRL				= 0x00,
+	IDECTRL_CS0N			= (1 << 0),
+	IDECTRL_CS1N			= (1 << 1),
+	IDECTRL_DIORN			= (1 << 5),
+	IDECTRL_DIOWN			= (1 << 6),
+	IDECTRL_INTRQ			= (1 << 9),
+	IDECTRL_IORDY			= (1 << 10),
+	/*
+	 * the device IDE register to be accessed is selected through
+	 * IDECTRL register's specific bitfields 'DA', 'CS1N' and 'CS0N':
+	 *   b4   b3   b2    b1     b0
+	 *   A2   A1   A0   CS1N   CS0N
+	 * the values filled in this structure allows the value to be directly
+	 * ORed to the IDECTRL register, hence giving directly the A[2:0] and
+	 * CS1N/CS0N values for each IDE register.
+	 * The values correspond to the transformation:
+	 *   ((real IDE address) << 2) | CS1N value << 1 | CS0N value
+	 */
+	IDECTRL_ADDR_CMD		= 0 + 2, /* CS1 */
+	IDECTRL_ADDR_DATA		= (ATA_REG_DATA << 2) + 2,
+	IDECTRL_ADDR_ERROR		= (ATA_REG_ERR << 2) + 2,
+	IDECTRL_ADDR_FEATURE		= (ATA_REG_FEATURE << 2) + 2,
+	IDECTRL_ADDR_NSECT		= (ATA_REG_NSECT << 2) + 2,
+	IDECTRL_ADDR_LBAL		= (ATA_REG_LBAL << 2) + 2,
+	IDECTRL_ADDR_LBAM		= (ATA_REG_LBAM << 2) + 2,
+	IDECTRL_ADDR_LBAH		= (ATA_REG_LBAH << 2) + 2,
+	IDECTRL_ADDR_DEVICE		= (ATA_REG_DEVICE << 2) + 2,
+	IDECTRL_ADDR_STATUS		= (ATA_REG_STATUS << 2) + 2,
+	IDECTRL_ADDR_COMMAND		= (ATA_REG_CMD << 2) + 2,
+	IDECTRL_ADDR_ALTSTATUS		= (0x06 << 2) + 1, /* CS0 */
+	IDECTRL_ADDR_CTL		= (0x06 << 2) + 1, /* CS0 */
+
+	/* IDE Configuration Register */
+	IDECFG				= 0x04,
+	IDECFG_IDEEN			= (1 << 0),
+	IDECFG_PIO			= (1 << 1),
+	IDECFG_MDMA			= (1 << 2),
+	IDECFG_UDMA			= (1 << 3),
+	IDECFG_MODE_SHIFT		= 4,
+	IDECFG_MODE_MASK		= (0xf << 4),
+	IDECFG_WST_SHIFT		= 8,
+	IDECFG_WST_MASK			= (0x3 << 8),
+
+	/* MDMA Operation Register */
+	IDEMDMAOP			= 0x08,
+
+	/* UDMA Operation Register */
+	IDEUDMAOP			= 0x0c,
+	IDEUDMAOP_UEN			= (1 << 0),
+	IDEUDMAOP_RWOP			= (1 << 1),
+
+	/* PIO/MDMA/UDMA Data Registers */
+	IDEDATAOUT			= 0x10,
+	IDEDATAIN			= 0x14,
+	IDEMDMADATAOUT			= 0x18,
+	IDEMDMADATAIN			= 0x1c,
+	IDEUDMADATAOUT			= 0x20,
+	IDEUDMADATAIN			= 0x24,
+
+	/* UDMA Status Register */
+	IDEUDMASTS			= 0x28,
+	IDEUDMASTS_DMAIDE		= (1 << 16),
+	IDEUDMASTS_INTIDE		= (1 << 17),
+	IDEUDMASTS_SBUSY		= (1 << 18),
+	IDEUDMASTS_NDO			= (1 << 24),
+	IDEUDMASTS_NDI			= (1 << 25),
+	IDEUDMASTS_N4X			= (1 << 26),
+
+	/* UDMA Debug Status Register */
+	IDEUDMADEBUG			= 0x2c,
+};
+
+struct ep93xx_pata_data {
+	const struct platform_device *pdev;
+	void __iomem *ide_base;
+	struct ata_timing t;
+	bool iordy;
+
+	unsigned long udma_in_phys;
+	unsigned long udma_out_phys;
+
+	struct dma_chan *dma_rx_channel;
+	struct ep93xx_dma_data dma_rx_data;
+	struct dma_chan *dma_tx_channel;
+	struct ep93xx_dma_data dma_tx_data;
+};
+
+static void ep93xx_pata_clear_regs(void __iomem *base)
+{
+	writel(IDECTRL_CS0N | IDECTRL_CS1N | IDECTRL_DIORN |
+		IDECTRL_DIOWN, base + IDECTRL);
+
+	writel(0, base + IDECFG);
+	writel(0, base + IDEMDMAOP);
+	writel(0, base + IDEUDMAOP);
+	writel(0, base + IDEDATAOUT);
+	writel(0, base + IDEDATAIN);
+	writel(0, base + IDEMDMADATAOUT);
+	writel(0, base + IDEMDMADATAIN);
+	writel(0, base + IDEUDMADATAOUT);
+	writel(0, base + IDEUDMADATAIN);
+	writel(0, base + IDEUDMADEBUG);
+}
+
+static bool ep93xx_pata_check_iordy(void __iomem *base)
+{
+	return !!(readl(base + IDECTRL) & IDECTRL_IORDY);
+}
+
+/*
+ * According to EP93xx User's Guide, WST field of IDECFG specifies number
+ * of HCLK cycles to hold the data bus after a PIO write operation.
+ * It should be programmed to guarantee following delays:
+ *
+ * PIO Mode   [ns]
+ * 0          30
+ * 1          20
+ * 2          15
+ * 3          10
+ * 4          5
+ *
+ * Maximum possible value for HCLK is 100MHz.
+ */
+static int ep93xx_pata_get_wst(int pio_mode)
+{
+	int val;
+
+	if (pio_mode == 0)
+		val = 3;
+	else if (pio_mode < 3)
+		val = 2;
+	else
+		val = 1;
+
+	return val << IDECFG_WST_SHIFT;
+}
+
+static void ep93xx_pata_enable_pio(void __iomem *base, int pio_mode)
+{
+	writel(IDECFG_IDEEN | IDECFG_PIO |
+		ep93xx_pata_get_wst(pio_mode) |
+		(pio_mode << IDECFG_MODE_SHIFT), base + IDECFG);
+}
+
+/*
+ * Based on delay loop found in mach-pxa/mp900.c.
+ *
+ * Single iteration should take 5 cpu cycles. This is 25ns assuming the
+ * fastest ep93xx cpu speed (200MHz) and is better optimized for PIO4 timings
+ * than eg. 20ns.
+ */
+static void ep93xx_pata_delay(unsigned long count)
+{
+	__asm__ volatile (
+		"0:\n"
+		"mov r0, r0\n"
+		"subs %0, %1, #1\n"
+		"bge 0b\n"
+		: "=r" (count)
+		: "0" (count)
+	);
+}
+
+static unsigned long ep93xx_pata_wait_for_iordy(void __iomem *base,
+						unsigned long t2)
+{
+	/*
+	 * According to ATA specification, IORDY pin can be first sampled
+	 * tA = 35ns after activation of DIOR-/DIOW-. Maximum IORDY pulse
+	 * width is tB = 1250ns.
+	 *
+	 * We are already t2 delay loop iterations after activation of
+	 * DIOR-/DIOW-, so we set timeout to (1250 + 35) / 25 - t2 additional
+	 * delay loop iterations.
+	 */
+	unsigned long start = (1250 + 35) / 25 - t2;
+	unsigned long counter = start;
+
+	while (!ep93xx_pata_check_iordy(base) && counter--)
+		ep93xx_pata_delay(1);
+	return start - counter;
+}
+
+/* common part at start of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_begin(void __iomem *base, unsigned long addr,
+				 unsigned long t1)
+{
+	writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+	ep93xx_pata_delay(t1);
+}
+
+/* common part at end of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_end(void __iomem *base, unsigned long addr,
+			       bool iordy, unsigned long t0, unsigned long t2,
+			       unsigned long t2i)
+{
+	ep93xx_pata_delay(t2);
+	/* lengthen t2 if needed */
+	if (iordy)
+		t2 += ep93xx_pata_wait_for_iordy(base, t2);
+	writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+	if (t0 > t2 && t0 - t2 > t2i)
+		ep93xx_pata_delay(t0 - t2);
+	else
+		ep93xx_pata_delay(t2i);
+}
+
+static u16 ep93xx_pata_read(struct ep93xx_pata_data *drv_data,
+			    unsigned long addr,
+			    bool reg)
+{
+	void __iomem *base = drv_data->ide_base;
+	const struct ata_timing *t = &drv_data->t;
+	unsigned long t0 = reg ? t->cyc8b : t->cycle;
+	unsigned long t2 = reg ? t->act8b : t->active;
+	unsigned long t2i = reg ? t->rec8b : t->recover;
+
+	ep93xx_pata_rw_begin(base, addr, t->setup);
+	writel(IDECTRL_DIOWN | addr, base + IDECTRL);
+	/*
+	 * The IDEDATAIN register is loaded from the DD pins at the positive
+	 * edge of the DIORN signal. (EP93xx UG p27-14)
+	 */
+	ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+	return readl(base + IDEDATAIN);
+}
+
+/* IDE register read */
+static u16 ep93xx_pata_read_reg(struct ep93xx_pata_data *drv_data,
+				unsigned long addr)
+{
+	return ep93xx_pata_read(drv_data, addr, true);
+}
+
+/* PIO data read */
+static u16 ep93xx_pata_read_data(struct ep93xx_pata_data *drv_data,
+				 unsigned long addr)
+{
+	return ep93xx_pata_read(drv_data, addr, false);
+}
+
+static void ep93xx_pata_write(struct ep93xx_pata_data *drv_data,
+			      u16 value, unsigned long addr,
+			      bool reg)
+{
+	void __iomem *base = drv_data->ide_base;
+	const struct ata_timing *t = &drv_data->t;
+	unsigned long t0 = reg ? t->cyc8b : t->cycle;
+	unsigned long t2 = reg ? t->act8b : t->active;
+	unsigned long t2i = reg ? t->rec8b : t->recover;
+
+	ep93xx_pata_rw_begin(base, addr, t->setup);
+	/*
+	 * Value from IDEDATAOUT register is driven onto the DD pins when
+	 * DIOWN is low. (EP93xx UG p27-13)
+	 */
+	writel(value, base + IDEDATAOUT);
+	writel(IDECTRL_DIORN | addr, base + IDECTRL);
+	ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+}
+
+/* IDE register write */
+static void ep93xx_pata_write_reg(struct ep93xx_pata_data *drv_data,
+				  u16 value, unsigned long addr)
+{
+	ep93xx_pata_write(drv_data, value, addr, true);
+}
+
+/* PIO data write */
+static void ep93xx_pata_write_data(struct ep93xx_pata_data *drv_data,
+				   u16 value, unsigned long addr)
+{
+	ep93xx_pata_write(drv_data, value, addr, false);
+}
+
+static void ep93xx_pata_set_piomode(struct ata_port *ap,
+				    struct ata_device *adev)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+	struct ata_device *pair = ata_dev_pair(adev);
+	/*
+	 * Calculate timings for the delay loop, assuming ep93xx cpu speed
+	 * is 200MHz (maximum possible for ep93xx). If actual cpu speed is
+	 * slower, we will wait a bit longer in each delay.
+	 * Additional division of cpu speed by 5, because single iteration
+	 * of our delay loop takes 5 cpu cycles (25ns).
+	 */
+	unsigned long T = 1000000 / (200 / 5);
+
+	ata_timing_compute(adev, adev->pio_mode, &drv_data->t, T, 0);
+	if (pair && pair->pio_mode) {
+		struct ata_timing t;
+		ata_timing_compute(pair, pair->pio_mode, &t, T, 0);
+		ata_timing_merge(&t, &drv_data->t, &drv_data->t,
+			ATA_TIMING_SETUP | ATA_TIMING_8BIT);
+	}
+	drv_data->iordy = ata_pio_need_iordy(adev);
+
+	ep93xx_pata_enable_pio(drv_data->ide_base,
+			       adev->pio_mode - XFER_PIO_0);
+}
+
+/* Note: original code is ata_sff_check_status */
+static u8 ep93xx_pata_check_status(struct ata_port *ap)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+	return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_STATUS);
+}
+
+static u8 ep93xx_pata_check_altstatus(struct ata_port *ap)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+	return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_ALTSTATUS);
+}
+
+/* Note: original code is ata_sff_tf_load */
+static void ep93xx_pata_tf_load(struct ata_port *ap,
+				const struct ata_taskfile *tf)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		ep93xx_pata_write_reg(drv_data, tf->hob_feature,
+			IDECTRL_ADDR_FEATURE);
+		ep93xx_pata_write_reg(drv_data, tf->hob_nsect,
+			IDECTRL_ADDR_NSECT);
+		ep93xx_pata_write_reg(drv_data, tf->hob_lbal,
+			IDECTRL_ADDR_LBAL);
+		ep93xx_pata_write_reg(drv_data, tf->hob_lbam,
+			IDECTRL_ADDR_LBAM);
+		ep93xx_pata_write_reg(drv_data, tf->hob_lbah,
+			IDECTRL_ADDR_LBAH);
+	}
+
+	if (is_addr) {
+		ep93xx_pata_write_reg(drv_data, tf->feature,
+			IDECTRL_ADDR_FEATURE);
+		ep93xx_pata_write_reg(drv_data, tf->nsect, IDECTRL_ADDR_NSECT);
+		ep93xx_pata_write_reg(drv_data, tf->lbal, IDECTRL_ADDR_LBAL);
+		ep93xx_pata_write_reg(drv_data, tf->lbam, IDECTRL_ADDR_LBAM);
+		ep93xx_pata_write_reg(drv_data, tf->lbah, IDECTRL_ADDR_LBAH);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE)
+		ep93xx_pata_write_reg(drv_data, tf->device,
+			IDECTRL_ADDR_DEVICE);
+
+	ata_wait_idle(ap);
+}
+
+/* Note: original code is ata_sff_tf_read */
+static void ep93xx_pata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+	tf->command = ep93xx_pata_check_status(ap);
+	tf->feature = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_FEATURE);
+	tf->nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+	tf->lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+	tf->lbam = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAM);
+	tf->lbah = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAH);
+	tf->device = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DEVICE);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		ep93xx_pata_write_reg(drv_data, tf->ctl | ATA_HOB,
+			IDECTRL_ADDR_CTL);
+		tf->hob_feature = ep93xx_pata_read_reg(drv_data,
+			IDECTRL_ADDR_FEATURE);
+		tf->hob_nsect = ep93xx_pata_read_reg(drv_data,
+			IDECTRL_ADDR_NSECT);
+		tf->hob_lbal = ep93xx_pata_read_reg(drv_data,
+			IDECTRL_ADDR_LBAL);
+		tf->hob_lbam = ep93xx_pata_read_reg(drv_data,
+			IDECTRL_ADDR_LBAM);
+		tf->hob_lbah = ep93xx_pata_read_reg(drv_data,
+			IDECTRL_ADDR_LBAH);
+		ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+		ap->last_ctl = tf->ctl;
+	}
+}
+
+/* Note: original code is ata_sff_exec_command */
+static void ep93xx_pata_exec_command(struct ata_port *ap,
+				     const struct ata_taskfile *tf)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+	ep93xx_pata_write_reg(drv_data, tf->command,
+			  IDECTRL_ADDR_COMMAND);
+	ata_sff_pause(ap);
+}
+
+/* Note: original code is ata_sff_dev_select */
+static void ep93xx_pata_dev_select(struct ata_port *ap, unsigned int device)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+	u8 tmp = ATA_DEVICE_OBS;
+
+	if (device != 0)
+		tmp |= ATA_DEV1;
+
+	ep93xx_pata_write_reg(drv_data, tmp, IDECTRL_ADDR_DEVICE);
+	ata_sff_pause(ap);	/* needed; also flushes, for mmio */
+}
+
+/* Note: original code is ata_sff_set_devctl */
+static void ep93xx_pata_set_devctl(struct ata_port *ap, u8 ctl)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+	ep93xx_pata_write_reg(drv_data, ctl, IDECTRL_ADDR_CTL);
+}
+
+/* Note: original code is ata_sff_data_xfer */
+static unsigned int ep93xx_pata_data_xfer(struct ata_device *adev,
+					  unsigned char *buf,
+					  unsigned int buflen, int rw)
+{
+	struct ata_port *ap = adev->link->ap;
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+	u16 *data = (u16 *)buf;
+	unsigned int words = buflen >> 1;
+
+	/* Transfer multiple of 2 bytes */
+	while (words--)
+		if (rw == READ)
+			*data++ = cpu_to_le16(
+				ep93xx_pata_read_data(
+					drv_data, IDECTRL_ADDR_DATA));
+		else
+			ep93xx_pata_write_data(drv_data, le16_to_cpu(*data++),
+				IDECTRL_ADDR_DATA);
+
+	/* Transfer trailing 1 byte, if any. */
+	if (unlikely(buflen & 0x01)) {
+		unsigned char pad[2] = { };
+
+		buf += buflen - 1;
+
+		if (rw == READ) {
+			*pad = cpu_to_le16(
+				ep93xx_pata_read_data(
+					drv_data, IDECTRL_ADDR_DATA));
+			*buf = pad[0];
+		} else {
+			pad[0] = *buf;
+			ep93xx_pata_write_data(drv_data, le16_to_cpu(*pad),
+					  IDECTRL_ADDR_DATA);
+		}
+		words++;
+	}
+
+	return words << 1;
+}
+
+/* Note: original code is ata_devchk */
+static bool ep93xx_pata_device_is_present(struct ata_port *ap,
+					  unsigned int device)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+	u8 nsect, lbal;
+
+	ap->ops->sff_dev_select(ap, device);
+
+	ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+	ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+	ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_NSECT);
+	ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_LBAL);
+
+	ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+	ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+	nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+	lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+
+	if ((nsect == 0x55) && (lbal == 0xaa))
+		return true;
+
+	return false;
+}
+
+/* Note: original code is ata_sff_wait_after_reset */
+static int ep93xx_pata_wait_after_reset(struct ata_link *link,
+					unsigned int devmask,
+					unsigned long deadline)
+{
+	struct ata_port *ap = link->ap;
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+	unsigned int dev0 = devmask & (1 << 0);
+	unsigned int dev1 = devmask & (1 << 1);
+	int rc, ret = 0;
+
+	ata_msleep(ap, ATA_WAIT_AFTER_RESET);
+
+	/* always check readiness of the master device */
+	rc = ata_sff_wait_ready(link, deadline);
+	/*
+	 * -ENODEV means the odd clown forgot the D7 pulldown resistor
+	 * and TF status is 0xff, bail out on it too.
+	 */
+	if (rc)
+		return rc;
+
+	/*
+	 * if device 1 was found in ata_devchk, wait for register
+	 * access briefly, then wait for BSY to clear.
+	 */
+	if (dev1) {
+		int i;
+
+		ap->ops->sff_dev_select(ap, 1);
+
+		/*
+		 * Wait for register access.  Some ATAPI devices fail
+		 * to set nsect/lbal after reset, so don't waste too
+		 * much time on it.  We're gonna wait for !BSY anyway.
+		 */
+		for (i = 0; i < 2; i++) {
+			u8 nsect, lbal;
+
+			nsect = ep93xx_pata_read_reg(drv_data,
+				IDECTRL_ADDR_NSECT);
+			lbal = ep93xx_pata_read_reg(drv_data,
+				IDECTRL_ADDR_LBAL);
+			if (nsect == 1 && lbal == 1)
+				break;
+			msleep(50);	/* give drive a breather */
+		}
+
+		rc = ata_sff_wait_ready(link, deadline);
+		if (rc) {
+			if (rc != -ENODEV)
+				return rc;
+			ret = rc;
+		}
+	}
+	/* is all this really necessary? */
+	ap->ops->sff_dev_select(ap, 0);
+	if (dev1)
+		ap->ops->sff_dev_select(ap, 1);
+	if (dev0)
+		ap->ops->sff_dev_select(ap, 0);
+
+	return ret;
+}
+
+/* Note: original code is ata_bus_softreset */
+static int ep93xx_pata_bus_softreset(struct ata_port *ap, unsigned int devmask,
+				     unsigned long deadline)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+	ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+	udelay(20);		/* FIXME: flush */
+	ep93xx_pata_write_reg(drv_data, ap->ctl | ATA_SRST, IDECTRL_ADDR_CTL);
+	udelay(20);		/* FIXME: flush */
+	ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+	ap->last_ctl = ap->ctl;
+
+	return ep93xx_pata_wait_after_reset(&ap->link, devmask, deadline);
+}
+
+static void ep93xx_pata_release_dma(struct ep93xx_pata_data *drv_data)
+{
+	if (drv_data->dma_rx_channel) {
+		dma_release_channel(drv_data->dma_rx_channel);
+		drv_data->dma_rx_channel = NULL;
+	}
+	if (drv_data->dma_tx_channel) {
+		dma_release_channel(drv_data->dma_tx_channel);
+		drv_data->dma_tx_channel = NULL;
+	}
+}
+
+static bool ep93xx_pata_dma_filter(struct dma_chan *chan, void *filter_param)
+{
+	if (ep93xx_dma_chan_is_m2p(chan))
+		return false;
+
+	chan->private = filter_param;
+	return true;
+}
+
+static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
+{
+	const struct platform_device *pdev = drv_data->pdev;
+	dma_cap_mask_t mask;
+	struct dma_slave_config conf;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	/*
+	 * Request two channels for IDE. Another possibility would be
+	 * to request only one channel, and reprogram it's direction at
+	 * start of new transfer.
+	 */
+	drv_data->dma_rx_data.port = EP93XX_DMA_IDE;
+	drv_data->dma_rx_data.direction = DMA_FROM_DEVICE;
+	drv_data->dma_rx_data.name = "ep93xx-pata-rx";
+	drv_data->dma_rx_channel = dma_request_channel(mask,
+		ep93xx_pata_dma_filter, &drv_data->dma_rx_data);
+	if (!drv_data->dma_rx_channel)
+		return;
+
+	drv_data->dma_tx_data.port = EP93XX_DMA_IDE;
+	drv_data->dma_tx_data.direction = DMA_TO_DEVICE;
+	drv_data->dma_tx_data.name = "ep93xx-pata-tx";
+	drv_data->dma_tx_channel = dma_request_channel(mask,
+		ep93xx_pata_dma_filter, &drv_data->dma_tx_data);
+	if (!drv_data->dma_tx_channel) {
+		dma_release_channel(drv_data->dma_rx_channel);
+		return;
+	}
+
+	/* Configure receive channel direction and source address */
+	memset(&conf, 0, sizeof(conf));
+	conf.direction = DMA_FROM_DEVICE;
+	conf.src_addr = drv_data->udma_in_phys;
+	conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) {
+		dev_err(&pdev->dev, "failed to configure rx dma channel\n");
+		ep93xx_pata_release_dma(drv_data);
+		return;
+	}
+
+	/* Configure transmit channel direction and destination address */
+	memset(&conf, 0, sizeof(conf));
+	conf.direction = DMA_TO_DEVICE;
+	conf.dst_addr = drv_data->udma_out_phys;
+	conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) {
+		dev_err(&pdev->dev, "failed to configure tx dma channel\n");
+		ep93xx_pata_release_dma(drv_data);
+	}
+}
+
+static void ep93xx_pata_dma_start(struct ata_queued_cmd *qc)
+{
+	struct dma_async_tx_descriptor *txd;
+	struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+	void __iomem *base = drv_data->ide_base;
+	struct ata_device *adev = qc->dev;
+	u32 v = qc->dma_dir == DMA_TO_DEVICE ? IDEUDMAOP_RWOP : 0;
+	struct dma_chan *channel = qc->dma_dir == DMA_TO_DEVICE
+		? drv_data->dma_tx_channel : drv_data->dma_rx_channel;
+
+	txd = channel->device->device_prep_slave_sg(channel, qc->sg,
+		 qc->n_elem, qc->dma_dir, DMA_CTRL_ACK, NULL);
+	if (!txd) {
+		dev_err(qc->ap->dev, "failed to prepare slave for sg dma\n");
+		return;
+	}
+	txd->callback = NULL;
+	txd->callback_param = NULL;
+
+	if (dmaengine_submit(txd) < 0) {
+		dev_err(qc->ap->dev, "failed to submit dma transfer\n");
+		return;
+	}
+	dma_async_issue_pending(channel);
+
+	/*
+	 * When enabling UDMA operation, IDEUDMAOP register needs to be
+	 * programmed in three step sequence:
+	 * 1) set or clear the RWOP bit,
+	 * 2) perform dummy read of the register,
+	 * 3) set the UEN bit.
+	 */
+	writel(v, base + IDEUDMAOP);
+	readl(base + IDEUDMAOP);
+	writel(v | IDEUDMAOP_UEN, base + IDEUDMAOP);
+
+	writel(IDECFG_IDEEN | IDECFG_UDMA |
+		((adev->xfer_mode - XFER_UDMA_0) << IDECFG_MODE_SHIFT),
+		base + IDECFG);
+}
+
+static void ep93xx_pata_dma_stop(struct ata_queued_cmd *qc)
+{
+	struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+	void __iomem *base = drv_data->ide_base;
+
+	/* terminate all dma transfers, if not yet finished */
+	dmaengine_terminate_all(drv_data->dma_rx_channel);
+	dmaengine_terminate_all(drv_data->dma_tx_channel);
+
+	/*
+	 * To properly stop IDE-DMA, IDEUDMAOP register must to be cleared
+	 * and IDECTRL register must be set to default value.
+	 */
+	writel(0, base + IDEUDMAOP);
+	writel(readl(base + IDECTRL) | IDECTRL_DIOWN | IDECTRL_DIORN |
+		IDECTRL_CS0N | IDECTRL_CS1N, base + IDECTRL);
+
+	ep93xx_pata_enable_pio(drv_data->ide_base,
+		qc->dev->pio_mode - XFER_PIO_0);
+
+	ata_sff_dma_pause(qc->ap);
+}
+
+static void ep93xx_pata_dma_setup(struct ata_queued_cmd *qc)
+{
+	qc->ap->ops->sff_exec_command(qc->ap, &qc->tf);
+}
+
+static u8 ep93xx_pata_dma_status(struct ata_port *ap)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+	u32 val = readl(drv_data->ide_base + IDEUDMASTS);
+
+	/*
+	 * UDMA Status Register bits:
+	 *
+	 * DMAIDE - DMA request signal from UDMA state machine,
+	 * INTIDE - INT line generated by UDMA because of errors in the
+	 *          state machine,
+	 * SBUSY - UDMA state machine busy, not in idle state,
+	 * NDO   - error for data-out not completed,
+	 * NDI   - error for data-in not completed,
+	 * N4X   - error for data transferred not multiplies of four
+	 *         32-bit words.
+	 * (EP93xx UG p27-17)
+	 */
+	if (val & IDEUDMASTS_NDO || val & IDEUDMASTS_NDI ||
+	    val & IDEUDMASTS_N4X || val & IDEUDMASTS_INTIDE)
+		return ATA_DMA_ERR;
+
+	/* read INTRQ (INT[3]) pin input state */
+	if (readl(drv_data->ide_base + IDECTRL) & IDECTRL_INTRQ)
+		return ATA_DMA_INTR;
+
+	if (val & IDEUDMASTS_SBUSY || val & IDEUDMASTS_DMAIDE)
+		return ATA_DMA_ACTIVE;
+
+	return 0;
+}
+
+/* Note: original code is ata_sff_softreset */
+static int ep93xx_pata_softreset(struct ata_link *al, unsigned int *classes,
+				 unsigned long deadline)
+{
+	struct ata_port *ap = al->ap;
+	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+	unsigned int devmask = 0;
+	int rc;
+	u8 err;
+
+	/* determine if device 0/1 are present */
+	if (ep93xx_pata_device_is_present(ap, 0))
+		devmask |= (1 << 0);
+	if (slave_possible && ep93xx_pata_device_is_present(ap, 1))
+		devmask |= (1 << 1);
+
+	/* select device 0 again */
+	ap->ops->sff_dev_select(al->ap, 0);
+
+	/* issue bus reset */
+	rc = ep93xx_pata_bus_softreset(ap, devmask, deadline);
+	/* if link is ocuppied, -ENODEV too is an error */
+	if (rc && (rc != -ENODEV || sata_scr_valid(al))) {
+		ata_link_printk(al, KERN_ERR, "SRST failed (errno=%d)\n",
+				rc);
+		return rc;
+	}
+
+	/* determine by signature whether we have ATA or ATAPI devices */
+	classes[0] = ata_sff_dev_classify(&al->device[0], devmask & (1 << 0),
+					  &err);
+	if (slave_possible && err != 0x81)
+		classes[1] = ata_sff_dev_classify(&al->device[1],
+						  devmask & (1 << 1), &err);
+
+	return 0;
+}
+
+/* Note: original code is ata_sff_drain_fifo */
+static void ep93xx_pata_drain_fifo(struct ata_queued_cmd *qc)
+{
+	int count;
+	struct ata_port *ap;
+	struct ep93xx_pata_data *drv_data;
+
+	/* We only need to flush incoming data when a command was running */
+	if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+		return;
+
+	ap = qc->ap;
+	drv_data = ap->host->private_data;
+	/* Drain up to 64K of data before we give up this recovery method */
+	for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
+		     && count < 65536; count += 2)
+		ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DATA);
+
+	/* Can become DEBUG later */
+	if (count)
+		ata_port_printk(ap, KERN_DEBUG,
+				"drained %d bytes to clear DRQ.\n", count);
+
+}
+
+static int ep93xx_pata_port_start(struct ata_port *ap)
+{
+	struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+	/*
+	 * Set timings to safe values at startup (= number of ns from ATA
+	 * specification), we'll switch to properly calculated values later.
+	 */
+	drv_data->t = *ata_timing_find_mode(XFER_PIO_0);
+	return 0;
+}
+
+static struct scsi_host_template ep93xx_pata_sht = {
+	ATA_BASE_SHT(DRV_NAME),
+	/* ep93xx dma implementation limit */
+	.sg_tablesize		= 32,
+	/* ep93xx dma can't transfer 65536 bytes at once */
+	.dma_boundary		= 0x7fff,
+};
+
+static struct ata_port_operations ep93xx_pata_port_ops = {
+	.inherits		= &ata_bmdma_port_ops,
+
+	.qc_prep		= ata_noop_qc_prep,
+
+	.softreset		= ep93xx_pata_softreset,
+	.hardreset		= ATA_OP_NULL,
+
+	.sff_dev_select		= ep93xx_pata_dev_select,
+	.sff_set_devctl		= ep93xx_pata_set_devctl,
+	.sff_check_status	= ep93xx_pata_check_status,
+	.sff_check_altstatus	= ep93xx_pata_check_altstatus,
+	.sff_tf_load		= ep93xx_pata_tf_load,
+	.sff_tf_read		= ep93xx_pata_tf_read,
+	.sff_exec_command	= ep93xx_pata_exec_command,
+	.sff_data_xfer		= ep93xx_pata_data_xfer,
+	.sff_drain_fifo		= ep93xx_pata_drain_fifo,
+	.sff_irq_clear		= ATA_OP_NULL,
+
+	.set_piomode		= ep93xx_pata_set_piomode,
+
+	.bmdma_setup		= ep93xx_pata_dma_setup,
+	.bmdma_start		= ep93xx_pata_dma_start,
+	.bmdma_stop		= ep93xx_pata_dma_stop,
+	.bmdma_status		= ep93xx_pata_dma_status,
+
+	.cable_detect		= ata_cable_unknown,
+	.port_start		= ep93xx_pata_port_start,
+};
+
+static int __devinit ep93xx_pata_probe(struct platform_device *pdev)
+{
+	struct ep93xx_pata_data *drv_data;
+	struct ata_host *host;
+	struct ata_port *ap;
+	unsigned int irq;
+	struct resource *mem_res;
+	void __iomem *ide_base;
+	int err;
+
+	err = ep93xx_ide_acquire_gpio(pdev);
+	if (err)
+		return err;
+
+	/* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		err = -ENXIO;
+		goto err_rel_gpio;
+	}
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem_res) {
+		err = -ENXIO;
+		goto err_rel_gpio;
+	}
+
+	ide_base = devm_request_and_ioremap(&pdev->dev, mem_res);
+	if (!ide_base) {
+		err = -ENXIO;
+		goto err_rel_gpio;
+	}
+
+	drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+	if (!drv_data) {
+		err = -ENXIO;
+		goto err_rel_gpio;
+	}
+
+	platform_set_drvdata(pdev, drv_data);
+	drv_data->pdev = pdev;
+	drv_data->ide_base = ide_base;
+	drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN;
+	drv_data->udma_out_phys = mem_res->start + IDEUDMADATAOUT;
+	ep93xx_pata_dma_init(drv_data);
+
+	/* allocate host */
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host) {
+		err = -ENXIO;
+		goto err_rel_dma;
+	}
+
+	ep93xx_pata_clear_regs(ide_base);
+
+	host->private_data = drv_data;
+
+	ap = host->ports[0];
+	ap->dev = &pdev->dev;
+	ap->ops = &ep93xx_pata_port_ops;
+	ap->flags |= ATA_FLAG_SLAVE_POSS;
+	ap->pio_mask = ATA_PIO4;
+
+	/*
+	 * Maximum UDMA modes:
+	 * EP931x rev.E0 - UDMA2
+	 * EP931x rev.E1 - UDMA3
+	 * EP931x rev.E2 - UDMA4
+	 *
+	 * MWDMA support was removed from EP931x rev.E2,
+	 * so this driver supports only UDMA modes.
+	 */
+	if (drv_data->dma_rx_channel && drv_data->dma_tx_channel) {
+		int chip_rev = ep93xx_chip_revision();
+
+		if (chip_rev == EP93XX_CHIP_REV_E1)
+			ap->udma_mask = ATA_UDMA3;
+		else if (chip_rev == EP93XX_CHIP_REV_E2)
+			ap->udma_mask = ATA_UDMA4;
+		else
+			ap->udma_mask = ATA_UDMA2;
+	}
+
+	/* defaults, pio 0 */
+	ep93xx_pata_enable_pio(ide_base, 0);
+
+	dev_info(&pdev->dev, "version " DRV_VERSION "\n");
+
+	/* activate host */
+	err = ata_host_activate(host, irq, ata_bmdma_interrupt, 0,
+		&ep93xx_pata_sht);
+	if (err == 0)
+		return 0;
+
+err_rel_dma:
+	ep93xx_pata_release_dma(drv_data);
+err_rel_gpio:
+	ep93xx_ide_release_gpio(pdev);
+	return err;
+}
+
+static int __devexit ep93xx_pata_remove(struct platform_device *pdev)
+{
+	struct ata_host *host = platform_get_drvdata(pdev);
+	struct ep93xx_pata_data *drv_data = host->private_data;
+
+	ata_host_detach(host);
+	ep93xx_pata_release_dma(drv_data);
+	ep93xx_pata_clear_regs(drv_data->ide_base);
+	ep93xx_ide_release_gpio(pdev);
+	return 0;
+}
+
+static struct platform_driver ep93xx_pata_platform_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = ep93xx_pata_probe,
+	.remove = __devexit_p(ep93xx_pata_remove),
+};
+
+module_platform_driver(ep93xx_pata_platform_driver);
+
+MODULE_AUTHOR("Alessandro Zummo, Lennert Buytenhek, Joao Ramos, "
+		"Bartlomiej Zolnierkiewicz, Rafal Prylowski");
+MODULE_DESCRIPTION("low-level driver for cirrus ep93xx IDE controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:pata_ep93xx");
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 26a06b8..2bcef65 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -21,8 +21,7 @@
 #include "power/power.h"
 
 /* /sys/devices/system */
-/* FIXME: make static after drivers/base/sys.c is deleted */
-struct kset *system_kset;
+static struct kset *system_kset;
 
 #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
 
diff --git a/drivers/base/core.c b/drivers/base/core.c
index e28ce98..346be8b 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -25,6 +25,7 @@
 #include <linux/mutex.h>
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
+#include <linux/netdevice.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -65,7 +66,7 @@
  * @dev: struct device to get the name of
  *
  * Will return the device's driver's name if it is bound to a device.  If
- * the device is not bound to a device, it will return the name of the bus
+ * the device is not bound to a driver, it will return the name of the bus
  * it is attached to.  If it is not attached to a bus either, an empty
  * string will be returned.
  */
@@ -878,8 +879,8 @@
  * to NULL prevents an entry from being created.  class->dev_kobj must
  * be set (or cleared) before any devices are registered to the class
  * otherwise device_create_sys_dev_entry() and
- * device_remove_sys_dev_entry() will disagree about the the presence
- * of the link.
+ * device_remove_sys_dev_entry() will disagree about the presence of
+ * the link.
  */
 static struct kobject *device_to_dev_kobj(struct device *dev)
 {
@@ -1843,15 +1844,60 @@
  */
 
 #ifdef CONFIG_PRINTK
-
 int __dev_printk(const char *level, const struct device *dev,
 		 struct va_format *vaf)
 {
+	char dict[128];
+	size_t dictlen = 0;
+	const char *subsys;
+
 	if (!dev)
 		return printk("%s(NULL device *): %pV", level, vaf);
 
-	return printk("%s%s %s: %pV",
-		      level, dev_driver_string(dev), dev_name(dev), vaf);
+	if (dev->class)
+		subsys = dev->class->name;
+	else if (dev->bus)
+		subsys = dev->bus->name;
+	else
+		goto skip;
+
+	dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+			    "SUBSYSTEM=%s", subsys);
+
+	/*
+	 * Add device identifier DEVICE=:
+	 *   b12:8         block dev_t
+	 *   c127:3        char dev_t
+	 *   n8            netdev ifindex
+	 *   +sound:card0  subsystem:devname
+	 */
+	if (MAJOR(dev->devt)) {
+		char c;
+
+		if (strcmp(subsys, "block") == 0)
+			c = 'b';
+		else
+			c = 'c';
+		dictlen++;
+		dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+				   "DEVICE=%c%u:%u",
+				   c, MAJOR(dev->devt), MINOR(dev->devt));
+	} else if (strcmp(subsys, "net") == 0) {
+		struct net_device *net = to_net_dev(dev);
+
+		dictlen++;
+		dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+				    "DEVICE=n%u", net->ifindex);
+	} else {
+		dictlen++;
+		dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+				    "DEVICE=+%s:%s", subsys, dev_name(dev));
+	}
+skip:
+	return printk_emit(0, level[1] - '0',
+			   dictlen ? dict : NULL, dictlen,
+			   "%s %s: %pV",
+			   dev_driver_string(dev), dev_name(dev), vaf);
 }
 EXPORT_SYMBOL(__dev_printk);
 
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index adf937b..6345294 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -330,8 +330,4 @@
 		panic("Failed to register CPU subsystem");
 
 	cpu_dev_register_generic();
-
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-	sched_create_sysfs_power_savings_entries(cpu_subsys.dev_root);
-#endif
 }
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 524bf96..2360adb 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -309,6 +309,10 @@
  * which @match returns 1.  If @match is NULL, it's considered to
  * match all.  If found, the resource is removed atomically and freed.
  *
+ * Note that the release function for the resource will not be called,
+ * only the devres-allocated data will be freed.  The caller becomes
+ * responsible for freeing any other data.
+ *
  * RETURNS:
  * 0 if devres is found and freed, -ENOENT if not found.
  */
@@ -326,6 +330,37 @@
 }
 EXPORT_SYMBOL_GPL(devres_destroy);
 
+
+/**
+ * devres_release - Find a device resource and destroy it, calling release
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1.  If @match is NULL, it's considered to
+ * match all.  If found, the resource is removed atomically, the
+ * release function called and the resource freed.
+ *
+ * RETURNS:
+ * 0 if devres is found and freed, -ENOENT if not found.
+ */
+int devres_release(struct device *dev, dr_release_t release,
+		   dr_match_t match, void *match_data)
+{
+	void *res;
+
+	res = devres_remove(dev, release, match, match_data);
+	if (unlikely(!res))
+		return -ENOENT;
+
+	(*release)(dev, res);
+	devres_free(res);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devres_release);
+
 static int remove_nodes(struct device *dev,
 			struct list_head *first, struct list_head *end,
 			struct list_head *todo)
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 8493536..765c3a2 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -7,9 +7,9 @@
  * devtmpfs, a tmpfs-based filesystem is created. Every driver-core
  * device which requests a device node, will add a node in this
  * filesystem.
- * By default, all devices are named after the the name of the
- * device, owned by root and have a default mode of 0600. Subsystems
- * can overwrite the default setting if needed.
+ * By default, all devices are named after the name of the device,
+ * owned by root and have a default mode of 0600. Subsystems can
+ * overwrite the default setting if needed.
  */
 
 #include <linux/kernel.h>
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 07cbbc6..05c64c1 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -293,7 +293,7 @@
  * cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific
  * preparations. Coherency is only guaranteed in the specified range for the
  * specified access direction.
- * @dma_buf:	[in]	buffer to prepare cpu access for.
+ * @dmabuf:	[in]	buffer to prepare cpu access for.
  * @start:	[in]	start of range for cpu access.
  * @len:	[in]	length of range for cpu access.
  * @direction:	[in]	length of range for cpu access.
@@ -320,7 +320,7 @@
  * cpu in the kernel context. Calls end_cpu_access to allow exporter-specific
  * actions. Coherency is only guaranteed in the specified range for the
  * specified access direction.
- * @dma_buf:	[in]	buffer to complete cpu access for.
+ * @dmabuf:	[in]	buffer to complete cpu access for.
  * @start:	[in]	start of range for cpu access.
  * @len:	[in]	length of range for cpu access.
  * @direction:	[in]	length of range for cpu access.
@@ -340,7 +340,7 @@
 /**
  * dma_buf_kmap_atomic - Map a page of the buffer object into kernel address
  * space. The same restrictions as for kmap_atomic and friends apply.
- * @dma_buf:	[in]	buffer to map page from.
+ * @dmabuf:	[in]	buffer to map page from.
  * @page_num:	[in]	page in PAGE_SIZE units to map.
  *
  * This call must always succeed, any necessary preparations that might fail
@@ -356,7 +356,7 @@
 
 /**
  * dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic.
- * @dma_buf:	[in]	buffer to unmap page from.
+ * @dmabuf:	[in]	buffer to unmap page from.
  * @page_num:	[in]	page in PAGE_SIZE units to unmap.
  * @vaddr:	[in]	kernel space pointer obtained from dma_buf_kmap_atomic.
  *
@@ -375,7 +375,7 @@
 /**
  * dma_buf_kmap - Map a page of the buffer object into kernel address space. The
  * same restrictions as for kmap and friends apply.
- * @dma_buf:	[in]	buffer to map page from.
+ * @dmabuf:	[in]	buffer to map page from.
  * @page_num:	[in]	page in PAGE_SIZE units to map.
  *
  * This call must always succeed, any necessary preparations that might fail
@@ -391,7 +391,7 @@
 
 /**
  * dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap.
- * @dma_buf:	[in]	buffer to unmap page from.
+ * @dmabuf:	[in]	buffer to unmap page from.
  * @page_num:	[in]	page in PAGE_SIZE units to unmap.
  * @vaddr:	[in]	kernel space pointer obtained from dma_buf_kmap.
  *
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 3ec3896..207c27d 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -80,7 +80,7 @@
 	struct klist_iter i;
 	struct device *dev;
 
-	if (!drv)
+	if (!drv || !drv->p)
 		return NULL;
 
 	klist_iter_init_node(&drv->p->klist_devices, &i,
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 73ce9fb..83aa694 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -11,6 +11,7 @@
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_qos.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/sched.h>
@@ -38,11 +39,13 @@
 	ktime_t __start = ktime_get();						\
 	type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev);		\
 	s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start));		\
-	struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev);		\
-	if (__elapsed > __gpd_data->td.field) {					\
-		__gpd_data->td.field = __elapsed;				\
+	struct gpd_timing_data *__td = &dev_gpd_data(dev)->td;			\
+	if (!__retval && __elapsed > __td->field) {				\
+		__td->field = __elapsed;					\
 		dev_warn(dev, name " latency exceeded, new value %lld ns\n",	\
 			__elapsed);						\
+		genpd->max_off_time_changed = true;				\
+		__td->constraint_changed = true;				\
 	}									\
 	__retval;								\
 })
@@ -211,6 +214,7 @@
 		elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
 		if (elapsed_ns > genpd->power_on_latency_ns) {
 			genpd->power_on_latency_ns = elapsed_ns;
+			genpd->max_off_time_changed = true;
 			if (genpd->name)
 				pr_warning("%s: Power-on latency exceeded, "
 					"new value %lld ns\n", genpd->name,
@@ -247,6 +251,53 @@
 
 #ifdef CONFIG_PM_RUNTIME
 
+static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
+				     unsigned long val, void *ptr)
+{
+	struct generic_pm_domain_data *gpd_data;
+	struct device *dev;
+
+	gpd_data = container_of(nb, struct generic_pm_domain_data, nb);
+
+	mutex_lock(&gpd_data->lock);
+	dev = gpd_data->base.dev;
+	if (!dev) {
+		mutex_unlock(&gpd_data->lock);
+		return NOTIFY_DONE;
+	}
+	mutex_unlock(&gpd_data->lock);
+
+	for (;;) {
+		struct generic_pm_domain *genpd;
+		struct pm_domain_data *pdd;
+
+		spin_lock_irq(&dev->power.lock);
+
+		pdd = dev->power.subsys_data ?
+				dev->power.subsys_data->domain_data : NULL;
+		if (pdd) {
+			to_gpd_data(pdd)->td.constraint_changed = true;
+			genpd = dev_to_genpd(dev);
+		} else {
+			genpd = ERR_PTR(-ENODATA);
+		}
+
+		spin_unlock_irq(&dev->power.lock);
+
+		if (!IS_ERR(genpd)) {
+			mutex_lock(&genpd->lock);
+			genpd->max_off_time_changed = true;
+			mutex_unlock(&genpd->lock);
+		}
+
+		dev = dev->parent;
+		if (!dev || dev->power.ignore_children)
+			break;
+	}
+
+	return NOTIFY_DONE;
+}
+
 /**
  * __pm_genpd_save_device - Save the pre-suspend state of a device.
  * @pdd: Domain data of the device to save the state of.
@@ -435,6 +486,7 @@
 		elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
 		if (elapsed_ns > genpd->power_off_latency_ns) {
 			genpd->power_off_latency_ns = elapsed_ns;
+			genpd->max_off_time_changed = true;
 			if (genpd->name)
 				pr_warning("%s: Power-off latency exceeded, "
 					"new value %lld ns\n", genpd->name,
@@ -443,17 +495,6 @@
 	}
 
 	genpd->status = GPD_STATE_POWER_OFF;
-	genpd->power_off_time = ktime_get();
-
-	/* Update PM QoS information for devices in the domain. */
-	list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
-		struct gpd_timing_data *td = &to_gpd_data(pdd)->td;
-
-		pm_runtime_update_max_time_suspended(pdd->dev,
-					td->start_latency_ns +
-					td->restore_state_latency_ns +
-					genpd->power_on_latency_ns);
-	}
 
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
 		genpd_sd_counter_dec(link->master);
@@ -514,9 +555,6 @@
 	if (ret)
 		return ret;
 
-	pm_runtime_update_max_time_suspended(dev,
-				dev_gpd_data(dev)->td.start_latency_ns);
-
 	/*
 	 * If power.irq_safe is set, this routine will be run with interrupts
 	 * off, so it can't use mutexes.
@@ -613,6 +651,12 @@
 
 #else
 
+static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
+					    unsigned long val, void *ptr)
+{
+	return NOTIFY_DONE;
+}
+
 static inline void genpd_power_off_work_fn(struct work_struct *work) {}
 
 #define pm_genpd_runtime_suspend	NULL
@@ -1209,12 +1253,15 @@
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
 		return -EINVAL;
 
-	genpd_acquire_lock(genpd);
+	gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
+	if (!gpd_data)
+		return -ENOMEM;
 
-	if (genpd->status == GPD_STATE_POWER_OFF) {
-		ret = -EINVAL;
-		goto out;
-	}
+	mutex_init(&gpd_data->lock);
+	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
+	dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+
+	genpd_acquire_lock(genpd);
 
 	if (genpd->prepared_count > 0) {
 		ret = -EAGAIN;
@@ -1227,26 +1274,35 @@
 			goto out;
 		}
 
-	gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
-	if (!gpd_data) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
 	genpd->device_count++;
+	genpd->max_off_time_changed = true;
 
-	dev->pm_domain = &genpd->domain;
 	dev_pm_get_subsys_data(dev);
+
+	mutex_lock(&gpd_data->lock);
+	spin_lock_irq(&dev->power.lock);
+	dev->pm_domain = &genpd->domain;
 	dev->power.subsys_data->domain_data = &gpd_data->base;
 	gpd_data->base.dev = dev;
-	gpd_data->need_restore = false;
 	list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+	gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
 	if (td)
 		gpd_data->td = *td;
 
+	gpd_data->td.constraint_changed = true;
+	gpd_data->td.effective_constraint_ns = -1;
+	spin_unlock_irq(&dev->power.lock);
+	mutex_unlock(&gpd_data->lock);
+
+	genpd_release_lock(genpd);
+
+	return 0;
+
  out:
 	genpd_release_lock(genpd);
 
+	dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+	kfree(gpd_data);
 	return ret;
 }
 
@@ -1290,12 +1346,15 @@
 int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 			   struct device *dev)
 {
+	struct generic_pm_domain_data *gpd_data;
 	struct pm_domain_data *pdd;
-	int ret = -EINVAL;
+	int ret = 0;
 
 	dev_dbg(dev, "%s()\n", __func__);
 
-	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
+	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)
+	    ||  IS_ERR_OR_NULL(dev->pm_domain)
+	    ||  pd_to_genpd(dev->pm_domain) != genpd)
 		return -EINVAL;
 
 	genpd_acquire_lock(genpd);
@@ -1305,21 +1364,27 @@
 		goto out;
 	}
 
-	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
-		if (pdd->dev != dev)
-			continue;
+	genpd->device_count--;
+	genpd->max_off_time_changed = true;
 
-		list_del_init(&pdd->list_node);
-		pdd->dev = NULL;
-		dev_pm_put_subsys_data(dev);
-		dev->pm_domain = NULL;
-		kfree(to_gpd_data(pdd));
+	spin_lock_irq(&dev->power.lock);
+	dev->pm_domain = NULL;
+	pdd = dev->power.subsys_data->domain_data;
+	list_del_init(&pdd->list_node);
+	dev->power.subsys_data->domain_data = NULL;
+	spin_unlock_irq(&dev->power.lock);
 
-		genpd->device_count--;
+	gpd_data = to_gpd_data(pdd);
+	mutex_lock(&gpd_data->lock);
+	pdd->dev = NULL;
+	mutex_unlock(&gpd_data->lock);
 
-		ret = 0;
-		break;
-	}
+	genpd_release_lock(genpd);
+
+	dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+	kfree(gpd_data);
+	dev_pm_put_subsys_data(dev);
+	return 0;
 
  out:
 	genpd_release_lock(genpd);
@@ -1348,6 +1413,26 @@
 EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on);
 
 /**
+ * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
+ * @dev: Device to set/unset the flag for.
+ * @val: The new value of the device's "need restore" flag.
+ */
+void pm_genpd_dev_need_restore(struct device *dev, bool val)
+{
+	struct pm_subsys_data *psd;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->power.lock, flags);
+
+	psd = dev_to_psd(dev);
+	if (psd && psd->domain_data)
+		to_gpd_data(psd->domain_data)->need_restore = val;
+
+	spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore);
+
+/**
  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
  * @genpd: Master PM domain to add the subdomain to.
  * @subdomain: Subdomain to be added.
@@ -1378,7 +1463,7 @@
 		goto out;
 	}
 
-	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+	list_for_each_entry(link, &genpd->master_links, master_node) {
 		if (link->slave == subdomain && link->master == genpd) {
 			ret = -EINVAL;
 			goto out;
@@ -1690,6 +1775,7 @@
 	genpd->resume_count = 0;
 	genpd->device_count = 0;
 	genpd->max_off_time_ns = -1;
+	genpd->max_off_time_changed = true;
 	genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
 	genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
 	genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 66a265b..28dee30 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -14,6 +14,31 @@
 
 #ifdef CONFIG_PM_RUNTIME
 
+static int dev_update_qos_constraint(struct device *dev, void *data)
+{
+	s64 *constraint_ns_p = data;
+	s32 constraint_ns = -1;
+
+	if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
+		constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
+
+	if (constraint_ns < 0) {
+		constraint_ns = dev_pm_qos_read_value(dev);
+		constraint_ns *= NSEC_PER_USEC;
+	}
+	if (constraint_ns == 0)
+		return 0;
+
+	/*
+	 * constraint_ns cannot be negative here, because the device has been
+	 * suspended.
+	 */
+	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+		*constraint_ns_p = constraint_ns;
+
+	return 0;
+}
+
 /**
  * default_stop_ok - Default PM domain governor routine for stopping devices.
  * @dev: Device to check.
@@ -21,14 +46,52 @@
 bool default_stop_ok(struct device *dev)
 {
 	struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+	unsigned long flags;
+	s64 constraint_ns;
 
 	dev_dbg(dev, "%s()\n", __func__);
 
-	if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns == 0)
-		return true;
+	spin_lock_irqsave(&dev->power.lock, flags);
 
-	return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns
-		&& td->break_even_ns < dev->power.max_time_suspended_ns;
+	if (!td->constraint_changed) {
+		bool ret = td->cached_stop_ok;
+
+		spin_unlock_irqrestore(&dev->power.lock, flags);
+		return ret;
+	}
+	td->constraint_changed = false;
+	td->cached_stop_ok = false;
+	td->effective_constraint_ns = -1;
+	constraint_ns = __dev_pm_qos_read_value(dev);
+
+	spin_unlock_irqrestore(&dev->power.lock, flags);
+
+	if (constraint_ns < 0)
+		return false;
+
+	constraint_ns *= NSEC_PER_USEC;
+	/*
+	 * We can walk the children without any additional locking, because
+	 * they all have been suspended at this point and their
+	 * effective_constraint_ns fields won't be modified in parallel with us.
+	 */
+	if (!dev->power.ignore_children)
+		device_for_each_child(dev, &constraint_ns,
+				      dev_update_qos_constraint);
+
+	if (constraint_ns > 0) {
+		constraint_ns -= td->start_latency_ns;
+		if (constraint_ns == 0)
+			return false;
+	}
+	td->effective_constraint_ns = constraint_ns;
+	td->cached_stop_ok = constraint_ns > td->stop_latency_ns ||
+				constraint_ns == 0;
+	/*
+	 * The children have been suspended already, so we don't need to take
+	 * their stop latencies into account here.
+	 */
+	return td->cached_stop_ok;
 }
 
 /**
@@ -42,9 +105,27 @@
 	struct generic_pm_domain *genpd = pd_to_genpd(pd);
 	struct gpd_link *link;
 	struct pm_domain_data *pdd;
-	s64 min_dev_off_time_ns;
+	s64 min_off_time_ns;
 	s64 off_on_time_ns;
-	ktime_t time_now = ktime_get();
+
+	if (genpd->max_off_time_changed) {
+		struct gpd_link *link;
+
+		/*
+		 * We have to invalidate the cached results for the masters, so
+		 * use the observation that default_power_down_ok() is not
+		 * going to be called for any master until this instance
+		 * returns.
+		 */
+		list_for_each_entry(link, &genpd->slave_links, slave_node)
+			link->master->max_off_time_changed = true;
+
+		genpd->max_off_time_changed = false;
+		genpd->cached_power_down_ok = false;
+		genpd->max_off_time_ns = -1;
+	} else {
+		return genpd->cached_power_down_ok;
+	}
 
 	off_on_time_ns = genpd->power_off_latency_ns +
 				genpd->power_on_latency_ns;
@@ -61,6 +142,7 @@
 				to_gpd_data(pdd)->td.save_state_latency_ns;
 	}
 
+	min_off_time_ns = -1;
 	/*
 	 * Check if subdomains can be off for enough time.
 	 *
@@ -73,8 +155,6 @@
 		if (sd_max_off_ns < 0)
 			continue;
 
-		sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now,
-						       sd->power_off_time));
 		/*
 		 * Check if the subdomain is allowed to be off long enough for
 		 * the current domain to turn off and on (that's how much time
@@ -82,60 +162,64 @@
 		 */
 		if (sd_max_off_ns <= off_on_time_ns)
 			return false;
+
+		if (min_off_time_ns > sd_max_off_ns || min_off_time_ns < 0)
+			min_off_time_ns = sd_max_off_ns;
 	}
 
 	/*
 	 * Check if the devices in the domain can be off enough time.
 	 */
-	min_dev_off_time_ns = -1;
 	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
 		struct gpd_timing_data *td;
-		struct device *dev = pdd->dev;
-		s64 dev_off_time_ns;
+		s64 constraint_ns;
 
-		if (!dev->driver || dev->power.max_time_suspended_ns < 0)
+		if (!pdd->dev->driver)
 			continue;
 
+		/*
+		 * Check if the device is allowed to be off long enough for the
+		 * domain to turn off and on (that's how much time it will
+		 * have to wait worst case).
+		 */
 		td = &to_gpd_data(pdd)->td;
-		dev_off_time_ns = dev->power.max_time_suspended_ns -
-			(td->start_latency_ns + td->restore_state_latency_ns +
-				ktime_to_ns(ktime_sub(time_now,
-						dev->power.suspend_time)));
-		if (dev_off_time_ns <= off_on_time_ns)
+		constraint_ns = td->effective_constraint_ns;
+		/* default_stop_ok() need not be called before us. */
+		if (constraint_ns < 0) {
+			constraint_ns = dev_pm_qos_read_value(pdd->dev);
+			constraint_ns *= NSEC_PER_USEC;
+		}
+		if (constraint_ns == 0)
+			continue;
+
+		/*
+		 * constraint_ns cannot be negative here, because the device has
+		 * been suspended.
+		 */
+		constraint_ns -= td->restore_state_latency_ns;
+		if (constraint_ns <= off_on_time_ns)
 			return false;
 
-		if (min_dev_off_time_ns > dev_off_time_ns
-		    || min_dev_off_time_ns < 0)
-			min_dev_off_time_ns = dev_off_time_ns;
+		if (min_off_time_ns > constraint_ns || min_off_time_ns < 0)
+			min_off_time_ns = constraint_ns;
 	}
 
-	if (min_dev_off_time_ns < 0) {
-		/*
-		 * There are no latency constraints, so the domain can spend
-		 * arbitrary time in the "off" state.
-		 */
-		genpd->max_off_time_ns = -1;
+	genpd->cached_power_down_ok = true;
+
+	/*
+	 * If the computed minimum device off time is negative, there are no
+	 * latency constraints, so the domain can spend arbitrary time in the
+	 * "off" state.
+	 */
+	if (min_off_time_ns < 0)
 		return true;
-	}
 
 	/*
-	 * The difference between the computed minimum delta and the time needed
-	 * to turn the domain on is the maximum theoretical time this domain can
-	 * spend in the "off" state.
+	 * The difference between the computed minimum subdomain or device off
+	 * time and the time needed to turn the domain on is the maximum
+	 * theoretical time this domain can spend in the "off" state.
 	 */
-	min_dev_off_time_ns -= genpd->power_on_latency_ns;
-
-	/*
-	 * If the difference between the computed minimum delta and the time
-	 * needed to turn the domain off and back on on is smaller than the
-	 * domain's power break even time, removing power from the domain is not
-	 * worth it.
-	 */
-	if (genpd->break_even_ns >
-	    min_dev_off_time_ns - genpd->power_off_latency_ns)
-		return false;
-
-	genpd->max_off_time_ns = min_dev_off_time_ns;
+	genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
 	return true;
 }
 
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index b462c0e..e0fb5b0 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -889,6 +889,11 @@
 		if (!list_empty(&dev->power.entry))
 			list_move(&dev->power.entry, &dpm_noirq_list);
 		put_device(dev);
+
+		if (pm_wakeup_pending()) {
+			error = -EBUSY;
+			break;
+		}
 	}
 	mutex_unlock(&dpm_list_mtx);
 	if (error)
@@ -962,6 +967,11 @@
 		if (!list_empty(&dev->power.entry))
 			list_move(&dev->power.entry, &dpm_late_early_list);
 		put_device(dev);
+
+		if (pm_wakeup_pending()) {
+			error = -EBUSY;
+			break;
+		}
 	}
 	mutex_unlock(&dpm_list_mtx);
 	if (error)
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 7185557..fd849a2 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -352,21 +352,26 @@
  *
  * Will register the notifier into a notification chain that gets called
  * upon changes to the target value for the device.
+ *
+ * If the device's constraints object doesn't exist when this routine is called,
+ * it will be created (or error code will be returned if that fails).
  */
 int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
 {
-	int retval = 0;
+	int ret = 0;
 
 	mutex_lock(&dev_pm_qos_mtx);
 
-	/* Silently return if the constraints object is not present. */
-	if (dev->power.constraints)
-		retval = blocking_notifier_chain_register(
-				dev->power.constraints->notifiers,
-				notifier);
+	if (!dev->power.constraints)
+		ret = dev->power.power_state.event != PM_EVENT_INVALID ?
+			dev_pm_qos_constraints_allocate(dev) : -ENODEV;
+
+	if (!ret)
+		ret = blocking_notifier_chain_register(
+				dev->power.constraints->notifiers, notifier);
 
 	mutex_unlock(&dev_pm_qos_mtx);
-	return retval;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
 
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index bd0f394..5989487 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -282,47 +282,6 @@
 	return retval != -EACCES ? retval : -EIO;
 }
 
-struct rpm_qos_data {
-	ktime_t time_now;
-	s64 constraint_ns;
-};
-
-/**
- * rpm_update_qos_constraint - Update a given PM QoS constraint data.
- * @dev: Device whose timing data to use.
- * @data: PM QoS constraint data to update.
- *
- * Use the suspend timing data of @dev to update PM QoS constraint data pointed
- * to by @data.
- */
-static int rpm_update_qos_constraint(struct device *dev, void *data)
-{
-	struct rpm_qos_data *qos = data;
-	unsigned long flags;
-	s64 delta_ns;
-	int ret = 0;
-
-	spin_lock_irqsave(&dev->power.lock, flags);
-
-	if (dev->power.max_time_suspended_ns < 0)
-		goto out;
-
-	delta_ns = dev->power.max_time_suspended_ns -
-		ktime_to_ns(ktime_sub(qos->time_now, dev->power.suspend_time));
-	if (delta_ns <= 0) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	if (qos->constraint_ns > delta_ns || qos->constraint_ns == 0)
-		qos->constraint_ns = delta_ns;
-
- out:
-	spin_unlock_irqrestore(&dev->power.lock, flags);
-
-	return ret;
-}
-
 /**
  * rpm_suspend - Carry out runtime suspend of given device.
  * @dev: Device to suspend.
@@ -349,7 +308,6 @@
 {
 	int (*callback)(struct device *);
 	struct device *parent = NULL;
-	struct rpm_qos_data qos;
 	int retval;
 
 	trace_rpm_suspend(dev, rpmflags);
@@ -445,38 +403,14 @@
 		goto out;
 	}
 
-	qos.constraint_ns = __dev_pm_qos_read_value(dev);
-	if (qos.constraint_ns < 0) {
-		/* Negative constraint means "never suspend". */
+	if (__dev_pm_qos_read_value(dev) < 0) {
+		/* Negative PM QoS constraint means "never suspend". */
 		retval = -EPERM;
 		goto out;
 	}
-	qos.constraint_ns *= NSEC_PER_USEC;
-	qos.time_now = ktime_get();
 
 	__update_runtime_status(dev, RPM_SUSPENDING);
 
-	if (!dev->power.ignore_children) {
-		if (dev->power.irq_safe)
-			spin_unlock(&dev->power.lock);
-		else
-			spin_unlock_irq(&dev->power.lock);
-
-		retval = device_for_each_child(dev, &qos,
-					       rpm_update_qos_constraint);
-
-		if (dev->power.irq_safe)
-			spin_lock(&dev->power.lock);
-		else
-			spin_lock_irq(&dev->power.lock);
-
-		if (retval)
-			goto fail;
-	}
-
-	dev->power.suspend_time = qos.time_now;
-	dev->power.max_time_suspended_ns = qos.constraint_ns ? : -1;
-
 	if (dev->pm_domain)
 		callback = dev->pm_domain->ops.runtime_suspend;
 	else if (dev->type && dev->type->pm)
@@ -529,8 +463,6 @@
 
  fail:
 	__update_runtime_status(dev, RPM_ACTIVE);
-	dev->power.suspend_time = ktime_set(0, 0);
-	dev->power.max_time_suspended_ns = -1;
 	dev->power.deferred_resume = false;
 	wake_up_all(&dev->power.wait_queue);
 
@@ -704,9 +636,6 @@
 	if (dev->power.no_callbacks)
 		goto no_callback;	/* Assume success. */
 
-	dev->power.suspend_time = ktime_set(0, 0);
-	dev->power.max_time_suspended_ns = -1;
-
 	__update_runtime_status(dev, RPM_RESUMING);
 
 	if (dev->pm_domain)
@@ -1369,9 +1298,6 @@
 	setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
 			(unsigned long)dev);
 
-	dev->power.suspend_time = ktime_set(0, 0);
-	dev->power.max_time_suspended_ns = -1;
-
 	init_waitqueue_head(&dev->power.wait_queue);
 }
 
@@ -1389,28 +1315,3 @@
 	if (dev->power.irq_safe && dev->parent)
 		pm_runtime_put_sync(dev->parent);
 }
-
-/**
- * pm_runtime_update_max_time_suspended - Update device's suspend time data.
- * @dev: Device to handle.
- * @delta_ns: Value to subtract from the device's max_time_suspended_ns field.
- *
- * Update the device's power.max_time_suspended_ns field by subtracting
- * @delta_ns from it.  The resulting value of power.max_time_suspended_ns is
- * never negative.
- */
-void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->power.lock, flags);
-
-	if (delta_ns > 0 && dev->power.max_time_suspended_ns > 0) {
-		if (dev->power.max_time_suspended_ns > delta_ns)
-			dev->power.max_time_suspended_ns -= delta_ns;
-		else
-			dev->power.max_time_suspended_ns = 0;
-	}
-
-	spin_unlock_irqrestore(&dev->power.lock, flags);
-}
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 95c12f6..48be2ad 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -314,22 +314,41 @@
 
 static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL);
 
-static ssize_t wakeup_hit_count_show(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t wakeup_abort_count_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
 {
 	unsigned long count = 0;
 	bool enabled = false;
 
 	spin_lock_irq(&dev->power.lock);
 	if (dev->power.wakeup) {
-		count = dev->power.wakeup->hit_count;
+		count = dev->power.wakeup->wakeup_count;
 		enabled = true;
 	}
 	spin_unlock_irq(&dev->power.lock);
 	return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
 }
 
-static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL);
+static DEVICE_ATTR(wakeup_abort_count, 0444, wakeup_abort_count_show, NULL);
+
+static ssize_t wakeup_expire_count_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	unsigned long count = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		count = dev->power.wakeup->expire_count;
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_expire_count, 0444, wakeup_expire_count_show, NULL);
 
 static ssize_t wakeup_active_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -398,6 +417,27 @@
 }
 
 static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t wakeup_prevent_sleep_time_show(struct device *dev,
+					      struct device_attribute *attr,
+					      char *buf)
+{
+	s64 msec = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		msec = ktime_to_ms(dev->power.wakeup->prevent_sleep_time);
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444,
+		   wakeup_prevent_sleep_time_show, NULL);
+#endif /* CONFIG_PM_AUTOSLEEP */
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_ADVANCED_DEBUG
@@ -486,11 +526,15 @@
 	&dev_attr_wakeup.attr,
 	&dev_attr_wakeup_count.attr,
 	&dev_attr_wakeup_active_count.attr,
-	&dev_attr_wakeup_hit_count.attr,
+	&dev_attr_wakeup_abort_count.attr,
+	&dev_attr_wakeup_expire_count.attr,
 	&dev_attr_wakeup_active.attr,
 	&dev_attr_wakeup_total_time_ms.attr,
 	&dev_attr_wakeup_max_time_ms.attr,
 	&dev_attr_wakeup_last_time_ms.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+	&dev_attr_wakeup_prevent_sleep_time_ms.attr,
+#endif
 #endif
 	NULL,
 };
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 2a3e581..cbb463b 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -14,16 +14,15 @@
 #include <linux/suspend.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <trace/events/power.h>
 
 #include "power.h"
 
-#define TIMEOUT		100
-
 /*
  * If set, the suspend/hibernate code will abort transitions to a sleep state
  * if wakeup events are registered during or immediately before the transition.
  */
-bool events_check_enabled;
+bool events_check_enabled __read_mostly;
 
 /*
  * Combined counters of registered wakeup events and wakeup events in progress.
@@ -52,6 +51,8 @@
 
 static LIST_HEAD(wakeup_sources);
 
+static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
+
 /**
  * wakeup_source_prepare - Prepare a new wakeup source for initialization.
  * @ws: Wakeup source to prepare.
@@ -132,6 +133,7 @@
 	spin_lock_init(&ws->lock);
 	setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
 	ws->active = false;
+	ws->last_time = ktime_get();
 
 	spin_lock_irq(&events_lock);
 	list_add_rcu(&ws->entry, &wakeup_sources);
@@ -374,12 +376,33 @@
  */
 static void wakeup_source_activate(struct wakeup_source *ws)
 {
+	unsigned int cec;
+
 	ws->active = true;
 	ws->active_count++;
 	ws->last_time = ktime_get();
+	if (ws->autosleep_enabled)
+		ws->start_prevent_time = ws->last_time;
 
 	/* Increment the counter of events in progress. */
-	atomic_inc(&combined_event_count);
+	cec = atomic_inc_return(&combined_event_count);
+
+	trace_wakeup_source_activate(ws->name, cec);
+}
+
+/**
+ * wakeup_source_report_event - Report wakeup event using the given source.
+ * @ws: Wakeup source to report the event for.
+ */
+static void wakeup_source_report_event(struct wakeup_source *ws)
+{
+	ws->event_count++;
+	/* This is racy, but the counter is approximate anyway. */
+	if (events_check_enabled)
+		ws->wakeup_count++;
+
+	if (!ws->active)
+		wakeup_source_activate(ws);
 }
 
 /**
@@ -397,10 +420,7 @@
 
 	spin_lock_irqsave(&ws->lock, flags);
 
-	ws->event_count++;
-	if (!ws->active)
-		wakeup_source_activate(ws);
-
+	wakeup_source_report_event(ws);
 	del_timer(&ws->timer);
 	ws->timer_expires = 0;
 
@@ -432,6 +452,17 @@
 }
 EXPORT_SYMBOL_GPL(pm_stay_awake);
 
+#ifdef CONFIG_PM_AUTOSLEEP
+static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now)
+{
+	ktime_t delta = ktime_sub(now, ws->start_prevent_time);
+	ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta);
+}
+#else
+static inline void update_prevent_sleep_time(struct wakeup_source *ws,
+					     ktime_t now) {}
+#endif
+
 /**
  * wakup_source_deactivate - Mark given wakeup source as inactive.
  * @ws: Wakeup source to handle.
@@ -442,6 +473,7 @@
  */
 static void wakeup_source_deactivate(struct wakeup_source *ws)
 {
+	unsigned int cnt, inpr, cec;
 	ktime_t duration;
 	ktime_t now;
 
@@ -468,14 +500,23 @@
 	if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
 		ws->max_time = duration;
 
+	ws->last_time = now;
 	del_timer(&ws->timer);
 	ws->timer_expires = 0;
 
+	if (ws->autosleep_enabled)
+		update_prevent_sleep_time(ws, now);
+
 	/*
 	 * Increment the counter of registered wakeup events and decrement the
 	 * couter of wakeup events in progress simultaneously.
 	 */
-	atomic_add(MAX_IN_PROGRESS, &combined_event_count);
+	cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);
+	trace_wakeup_source_deactivate(ws->name, cec);
+
+	split_counters(&cnt, &inpr);
+	if (!inpr && waitqueue_active(&wakeup_count_wait_queue))
+		wake_up(&wakeup_count_wait_queue);
 }
 
 /**
@@ -536,8 +577,10 @@
 	spin_lock_irqsave(&ws->lock, flags);
 
 	if (ws->active && ws->timer_expires
-	    && time_after_eq(jiffies, ws->timer_expires))
+	    && time_after_eq(jiffies, ws->timer_expires)) {
 		wakeup_source_deactivate(ws);
+		ws->expire_count++;
+	}
 
 	spin_unlock_irqrestore(&ws->lock, flags);
 }
@@ -564,9 +607,7 @@
 
 	spin_lock_irqsave(&ws->lock, flags);
 
-	ws->event_count++;
-	if (!ws->active)
-		wakeup_source_activate(ws);
+	wakeup_source_report_event(ws);
 
 	if (!msec) {
 		wakeup_source_deactivate(ws);
@@ -609,24 +650,6 @@
 EXPORT_SYMBOL_GPL(pm_wakeup_event);
 
 /**
- * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources.
- */
-static void pm_wakeup_update_hit_counts(void)
-{
-	unsigned long flags;
-	struct wakeup_source *ws;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
-		spin_lock_irqsave(&ws->lock, flags);
-		if (ws->active)
-			ws->hit_count++;
-		spin_unlock_irqrestore(&ws->lock, flags);
-	}
-	rcu_read_unlock();
-}
-
-/**
  * pm_wakeup_pending - Check if power transition in progress should be aborted.
  *
  * Compare the current number of registered wakeup events with its preserved
@@ -648,32 +671,38 @@
 		events_check_enabled = !ret;
 	}
 	spin_unlock_irqrestore(&events_lock, flags);
-	if (ret)
-		pm_wakeup_update_hit_counts();
 	return ret;
 }
 
 /**
  * pm_get_wakeup_count - Read the number of registered wakeup events.
  * @count: Address to store the value at.
+ * @block: Whether or not to block.
  *
- * Store the number of registered wakeup events at the address in @count.  Block
- * if the current number of wakeup events being processed is nonzero.
+ * Store the number of registered wakeup events at the address in @count.  If
+ * @block is set, block until the current number of wakeup events being
+ * processed is zero.
  *
- * Return 'false' if the wait for the number of wakeup events being processed to
- * drop down to zero has been interrupted by a signal (and the current number
- * of wakeup events being processed is still nonzero).  Otherwise return 'true'.
+ * Return 'false' if the current number of wakeup events being processed is
+ * nonzero.  Otherwise return 'true'.
  */
-bool pm_get_wakeup_count(unsigned int *count)
+bool pm_get_wakeup_count(unsigned int *count, bool block)
 {
 	unsigned int cnt, inpr;
 
-	for (;;) {
-		split_counters(&cnt, &inpr);
-		if (inpr == 0 || signal_pending(current))
-			break;
-		pm_wakeup_update_hit_counts();
-		schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
+	if (block) {
+		DEFINE_WAIT(wait);
+
+		for (;;) {
+			prepare_to_wait(&wakeup_count_wait_queue, &wait,
+					TASK_INTERRUPTIBLE);
+			split_counters(&cnt, &inpr);
+			if (inpr == 0 || signal_pending(current))
+				break;
+
+			schedule();
+		}
+		finish_wait(&wakeup_count_wait_queue, &wait);
 	}
 
 	split_counters(&cnt, &inpr);
@@ -703,11 +732,37 @@
 		events_check_enabled = true;
 	}
 	spin_unlock_irq(&events_lock);
-	if (!events_check_enabled)
-		pm_wakeup_update_hit_counts();
 	return events_check_enabled;
 }
 
+#ifdef CONFIG_PM_AUTOSLEEP
+/**
+ * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
+ * @enabled: Whether to set or to clear the autosleep_enabled flags.
+ */
+void pm_wakep_autosleep_enabled(bool set)
+{
+	struct wakeup_source *ws;
+	ktime_t now = ktime_get();
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+		spin_lock_irq(&ws->lock);
+		if (ws->autosleep_enabled != set) {
+			ws->autosleep_enabled = set;
+			if (ws->active) {
+				if (set)
+					ws->start_prevent_time = now;
+				else
+					update_prevent_sleep_time(ws, now);
+			}
+		}
+		spin_unlock_irq(&ws->lock);
+	}
+	rcu_read_unlock();
+}
+#endif /* CONFIG_PM_AUTOSLEEP */
+
 static struct dentry *wakeup_sources_stats_dentry;
 
 /**
@@ -723,27 +778,37 @@
 	ktime_t max_time;
 	unsigned long active_count;
 	ktime_t active_time;
+	ktime_t prevent_sleep_time;
 	int ret;
 
 	spin_lock_irqsave(&ws->lock, flags);
 
 	total_time = ws->total_time;
 	max_time = ws->max_time;
+	prevent_sleep_time = ws->prevent_sleep_time;
 	active_count = ws->active_count;
 	if (ws->active) {
-		active_time = ktime_sub(ktime_get(), ws->last_time);
+		ktime_t now = ktime_get();
+
+		active_time = ktime_sub(now, ws->last_time);
 		total_time = ktime_add(total_time, active_time);
 		if (active_time.tv64 > max_time.tv64)
 			max_time = active_time;
+
+		if (ws->autosleep_enabled)
+			prevent_sleep_time = ktime_add(prevent_sleep_time,
+				ktime_sub(now, ws->start_prevent_time));
 	} else {
 		active_time = ktime_set(0, 0);
 	}
 
-	ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t"
-			"%lld\t\t%lld\t\t%lld\t\t%lld\n",
-			ws->name, active_count, ws->event_count, ws->hit_count,
+	ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
+			"%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
+			ws->name, active_count, ws->event_count,
+			ws->wakeup_count, ws->expire_count,
 			ktime_to_ms(active_time), ktime_to_ms(total_time),
-			ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
+			ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
+			ktime_to_ms(prevent_sleep_time));
 
 	spin_unlock_irqrestore(&ws->lock, flags);
 
@@ -758,8 +823,9 @@
 {
 	struct wakeup_source *ws;
 
-	seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t"
-		"active_since\ttotal_time\tmax_time\tlast_change\n");
+	seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
+		"expire_count\tactive_since\ttotal_time\tmax_time\t"
+		"last_change\tprevent_suspend_time\n");
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(ws, &wakeup_sources, entry)
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 9ef0a53..6be390b 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -6,6 +6,7 @@
 	default y if (REGMAP_I2C || REGMAP_SPI)
 	select LZO_COMPRESS
 	select LZO_DECOMPRESS
+	select IRQ_DOMAIN if REGMAP_IRQ
 	bool
 
 config REGMAP_I2C
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index e19e987..5ed0718 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -323,6 +323,23 @@
 			return -EILSEQ;
 	}
 
+	/* First Slave Address Descriptor should be port 0:
+	 * the main register space for the core
+	 */
+	tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
+	if (tmp <= 0) {
+		/* Try again to see if it is a bridge */
+		tmp = bcma_erom_get_addr_desc(bus, eromptr,
+					      SCAN_ADDR_TYPE_BRIDGE, 0);
+		if (tmp <= 0) {
+			return -EILSEQ;
+		} else {
+			pr_info("Bridge found\n");
+			return -ENXIO;
+		}
+	}
+	core->addr = tmp;
+
 	/* get & parse slave ports */
 	for (i = 0; i < ports[1]; i++) {
 		for (j = 0; ; j++) {
@@ -335,7 +352,7 @@
 				break;
 			} else {
 				if (i == 0 && j == 0)
-					core->addr = tmp;
+					core->addr1 = tmp;
 			}
 		}
 	}
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index aba22b2..ad591bd 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -445,6 +445,7 @@
 	.probe		= ath3k_probe,
 	.disconnect	= ath3k_disconnect,
 	.id_table	= ath3k_table,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(ath3k_driver);
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index 1e742a5..37ae175 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -279,6 +279,7 @@
 	.probe		= bcm203x_probe,
 	.disconnect	= bcm203x_disconnect,
 	.id_table	= bcm203x_table,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(bcm203x_driver);
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index b8ac1c5..32e8251 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -749,6 +749,7 @@
 	.probe		= bfusb_probe,
 	.disconnect	= bfusb_disconnect,
 	.id_table	= bfusb_table,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(bfusb_driver);
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index d894340..609861a 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -508,6 +508,7 @@
 	.probe		= bpa10x_probe,
 	.disconnect	= bpa10x_disconnect,
 	.id_table	= bpa10x_table,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(bpa10x_driver);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index cb480f1..c9463af 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -1230,6 +1230,7 @@
 #endif
 	.id_table	= btusb_table,
 	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(btusb_driver);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ee946865..ea6f632 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -585,14 +585,6 @@
 
 source "drivers/s390/char/Kconfig"
 
-config RAMOOPS
-	tristate "Log panic/oops to a RAM buffer"
-	depends on HAS_IOMEM
-	default n
-	help
-	  This enables panic and oops messages to be logged to a circular
-	  buffer in RAM where it can be read back at some later point.
-
 config MSM_SMD_PKT
 	bool "Enable device interface for some SMD packet ports"
 	default n
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 0dc5d7c..d0b27a3 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -58,7 +58,6 @@
 obj-$(CONFIG_TCG_TPM)		+= tpm/
 
 obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
-obj-$(CONFIG_RAMOOPS)		+= ramoops.o
 
 obj-$(CONFIG_JS_RTC)		+= js-rtc.o
 js-rtc-y = rtc.o
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 0689bf6..f45dad3 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -62,8 +62,8 @@
 
 config HW_RANDOM_ATMEL
 	tristate "Atmel Random Number Generator support"
-	depends on HW_RANDOM && ARCH_AT91SAM9G45
-	default HW_RANDOM
+	depends on HW_RANDOM && HAVE_CLK
+	default (HW_RANDOM && ARCH_AT91)
 	---help---
 	  This driver provides kernel-side support for the Random Number
 	  Generator hardware found on Atmel AT91 devices.
@@ -250,3 +250,16 @@
 	  (check your distro, or download from
 	  http://sourceforge.net/projects/gkernel/).  rngd periodically reads
 	  /dev/hwrng and injects the entropy into /dev/random.
+
+config HW_RANDOM_PSERIES
+	tristate "pSeries HW Random Number Generator support"
+	depends on HW_RANDOM && PPC64 && IBMVIO
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on POWER7+ machines and above
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pseries-rng.
+
+	  If unsure, say Y.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index b2ff526..d901dfa 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -22,3 +22,4 @@
 obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
 obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o
 obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
+obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index a07a5ca..1412565 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -115,22 +115,12 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-	if (!res) {
-		ret = -ENOENT;
-		goto err_region;
-	}
-
-	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
-		ret = -EBUSY;
-		goto err_region;
-	}
-
-	dev_set_drvdata(&pdev->dev, res);
-	rng_base = ioremap(res->start, resource_size(res));
+	rng_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!rng_base) {
 		ret = -ENOMEM;
 		goto err_ioremap;
 	}
+	dev_set_drvdata(&pdev->dev, res);
 
 	ret = hwrng_register(&omap_rng_ops);
 	if (ret)
@@ -145,11 +135,8 @@
 	return 0;
 
 err_register:
-	iounmap(rng_base);
 	rng_base = NULL;
 err_ioremap:
-	release_mem_region(res->start, resource_size(res));
-err_region:
 	if (cpu_is_omap24xx()) {
 		clk_disable(rng_ick);
 		clk_put(rng_ick);
@@ -159,20 +146,15 @@
 
 static int __exit omap_rng_remove(struct platform_device *pdev)
 {
-	struct resource *res = dev_get_drvdata(&pdev->dev);
-
 	hwrng_unregister(&omap_rng_ops);
 
 	omap_rng_write_reg(RNG_MASK_REG, 0x0);
 
-	iounmap(rng_base);
-
 	if (cpu_is_omap24xx()) {
 		clk_disable(rng_ick);
 		clk_put(rng_ick);
 	}
 
-	release_mem_region(res->start, resource_size(res));
 	rng_base = NULL;
 
 	return 0;
diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c
new file mode 100644
index 0000000..5f11979
--- /dev/null
+++ b/drivers/char/hw_random/pseries-rng.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 Michael Neuling IBM Corporation
+ *
+ * Driver for the pseries hardware RNG for POWER7+ and above
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/hw_random.h>
+#include <asm/vio.h>
+
+#define MODULE_NAME "pseries-rng"
+
+static int pseries_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	if (plpar_hcall(H_RANDOM, (unsigned long *)data) != H_SUCCESS) {
+		printk(KERN_ERR "pseries rng hcall error\n");
+		return 0;
+	}
+	return 8;
+}
+
+/**
+ * pseries_rng_get_desired_dma - Return desired DMA allocate for CMO operations
+ *
+ * This is a required function for a driver to operate in a CMO environment
+ * but this device does not make use of DMA allocations, return 0.
+ *
+ * Return value:
+ *	Number of bytes of IO data the driver will need to perform well -> 0
+ */
+static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev)
+{
+	return 0;
+};
+
+static struct hwrng pseries_rng = {
+	.name		= MODULE_NAME,
+	.data_read	= pseries_rng_data_read,
+};
+
+static int __init pseries_rng_probe(struct vio_dev *dev,
+		const struct vio_device_id *id)
+{
+	return hwrng_register(&pseries_rng);
+}
+
+static int __exit pseries_rng_remove(struct vio_dev *dev)
+{
+	hwrng_unregister(&pseries_rng);
+	return 0;
+}
+
+static struct vio_device_id pseries_rng_driver_ids[] = {
+	{ "ibm,random-v1", "ibm,random"},
+	{ "", "" }
+};
+MODULE_DEVICE_TABLE(vio, pseries_rng_driver_ids);
+
+static struct vio_driver pseries_rng_driver = {
+	.name = MODULE_NAME,
+	.probe = pseries_rng_probe,
+	.remove = pseries_rng_remove,
+	.get_desired_dma = pseries_rng_get_desired_dma,
+	.id_table = pseries_rng_driver_ids
+};
+
+static int __init rng_init(void)
+{
+	printk(KERN_INFO "Registering IBM pSeries RNG driver\n");
+	return vio_register_driver(&pseries_rng_driver);
+}
+
+module_init(rng_init);
+
+static void __exit rng_exit(void)
+{
+	vio_unregister_driver(&pseries_rng_driver);
+}
+module_exit(rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Neuling <mikey@neuling.org>");
+MODULE_DESCRIPTION("H/W RNG driver for IBM pSeries processors");
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index d6e9d08..67c3371 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -807,44 +807,6 @@
 };
 #endif
 
-static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv,
-			   unsigned long count, loff_t pos)
-{
-	char *line, *p;
-	int i;
-	ssize_t ret = -EFAULT;
-	size_t len = iov_length(iv, count);
-
-	line = kmalloc(len + 1, GFP_KERNEL);
-	if (line == NULL)
-		return -ENOMEM;
-
-	/*
-	 * copy all vectors into a single string, to ensure we do
-	 * not interleave our log line with other printk calls
-	 */
-	p = line;
-	for (i = 0; i < count; i++) {
-		if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len))
-			goto out;
-		p += iv[i].iov_len;
-	}
-	p[0] = '\0';
-
-	ret = printk("%s", line);
-	/* printk can add a prefix */
-	if (ret > len)
-		ret = len;
-out:
-	kfree(line);
-	return ret;
-}
-
-static const struct file_operations kmsg_fops = {
-	.aio_write = kmsg_writev,
-	.llseek = noop_llseek,
-};
-
 static const struct memdev {
 	const char *name;
 	umode_t mode;
@@ -863,7 +825,9 @@
 	 [7] = { "full", 0666, &full_fops, NULL },
 	 [8] = { "random", 0666, &random_fops, NULL },
 	 [9] = { "urandom", 0666, &urandom_fops, NULL },
-	[11] = { "kmsg", 0, &kmsg_fops, NULL },
+#ifdef CONFIG_PRINTK
+	[11] = { "kmsg", 0644, &kmsg_fops, NULL },
+#endif
 #ifdef CONFIG_CRASH_DUMP
 	[12] = { "oldmem", 0, &oldmem_fops, NULL },
 #endif
diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
deleted file mode 100644
index 2a5e45d2..0000000
--- a/drivers/char/ramoops.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * RAM Oops/Panic logger
- *
- * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.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
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/kmsg_dump.h>
-#include <linux/time.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/ramoops.h>
-
-#define RAMOOPS_KERNMSG_HDR "===="
-#define MIN_MEM_SIZE 4096UL
-
-static ulong record_size = MIN_MEM_SIZE;
-module_param(record_size, ulong, 0400);
-MODULE_PARM_DESC(record_size,
-		"size of each dump done on oops/panic");
-
-static ulong mem_address;
-module_param(mem_address, ulong, 0400);
-MODULE_PARM_DESC(mem_address,
-		"start of reserved RAM used to store oops/panic logs");
-
-static ulong mem_size;
-module_param(mem_size, ulong, 0400);
-MODULE_PARM_DESC(mem_size,
-		"size of reserved RAM used to store oops/panic logs");
-
-static int dump_oops = 1;
-module_param(dump_oops, int, 0600);
-MODULE_PARM_DESC(dump_oops,
-		"set to 1 to dump oopses, 0 to only dump panics (default 1)");
-
-static struct ramoops_context {
-	struct kmsg_dumper dump;
-	void *virt_addr;
-	phys_addr_t phys_addr;
-	unsigned long size;
-	unsigned long record_size;
-	int dump_oops;
-	int count;
-	int max_count;
-} oops_cxt;
-
-static struct platform_device *dummy;
-static struct ramoops_platform_data *dummy_data;
-
-static void ramoops_do_dump(struct kmsg_dumper *dumper,
-		enum kmsg_dump_reason reason, const char *s1, unsigned long l1,
-		const char *s2, unsigned long l2)
-{
-	struct ramoops_context *cxt = container_of(dumper,
-			struct ramoops_context, dump);
-	unsigned long s1_start, s2_start;
-	unsigned long l1_cpy, l2_cpy;
-	int res, hdr_size;
-	char *buf, *buf_orig;
-	struct timeval timestamp;
-
-	if (reason != KMSG_DUMP_OOPS &&
-	    reason != KMSG_DUMP_PANIC)
-		return;
-
-	/* Only dump oopses if dump_oops is set */
-	if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
-		return;
-
-	buf = cxt->virt_addr + (cxt->count * cxt->record_size);
-	buf_orig = buf;
-
-	memset(buf, '\0', cxt->record_size);
-	res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
-	buf += res;
-	do_gettimeofday(&timestamp);
-	res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
-	buf += res;
-
-	hdr_size = buf - buf_orig;
-	l2_cpy = min(l2, cxt->record_size - hdr_size);
-	l1_cpy = min(l1, cxt->record_size - hdr_size - l2_cpy);
-
-	s2_start = l2 - l2_cpy;
-	s1_start = l1 - l1_cpy;
-
-	memcpy(buf, s1 + s1_start, l1_cpy);
-	memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy);
-
-	cxt->count = (cxt->count + 1) % cxt->max_count;
-}
-
-static int __init ramoops_probe(struct platform_device *pdev)
-{
-	struct ramoops_platform_data *pdata = pdev->dev.platform_data;
-	struct ramoops_context *cxt = &oops_cxt;
-	int err = -EINVAL;
-
-	if (!pdata->mem_size || !pdata->record_size) {
-		pr_err("The memory size and the record size must be "
-			"non-zero\n");
-		goto fail3;
-	}
-
-	pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
-	pdata->record_size = rounddown_pow_of_two(pdata->record_size);
-
-	/* Check for the minimum memory size */
-	if (pdata->mem_size < MIN_MEM_SIZE &&
-			pdata->record_size < MIN_MEM_SIZE) {
-		pr_err("memory size too small, minium is %lu\n", MIN_MEM_SIZE);
-		goto fail3;
-	}
-
-	if (pdata->mem_size < pdata->record_size) {
-		pr_err("The memory size must be larger than the "
-			"records size\n");
-		goto fail3;
-	}
-
-	cxt->max_count = pdata->mem_size / pdata->record_size;
-	cxt->count = 0;
-	cxt->size = pdata->mem_size;
-	cxt->phys_addr = pdata->mem_address;
-	cxt->record_size = pdata->record_size;
-	cxt->dump_oops = pdata->dump_oops;
-
-	if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
-		pr_err("request mem region failed\n");
-		err = -EINVAL;
-		goto fail3;
-	}
-
-	cxt->virt_addr = ioremap(cxt->phys_addr,  cxt->size);
-	if (!cxt->virt_addr) {
-		pr_err("ioremap failed\n");
-		goto fail2;
-	}
-
-	cxt->dump.dump = ramoops_do_dump;
-	err = kmsg_dump_register(&cxt->dump);
-	if (err) {
-		pr_err("registering kmsg dumper failed\n");
-		goto fail1;
-	}
-
-	/*
-	 * Update the module parameter variables as well so they are visible
-	 * through /sys/module/ramoops/parameters/
-	 */
-	mem_size = pdata->mem_size;
-	mem_address = pdata->mem_address;
-	record_size = pdata->record_size;
-	dump_oops = pdata->dump_oops;
-
-	return 0;
-
-fail1:
-	iounmap(cxt->virt_addr);
-fail2:
-	release_mem_region(cxt->phys_addr, cxt->size);
-fail3:
-	return err;
-}
-
-static int __exit ramoops_remove(struct platform_device *pdev)
-{
-	struct ramoops_context *cxt = &oops_cxt;
-
-	if (kmsg_dump_unregister(&cxt->dump) < 0)
-		pr_warn("could not unregister kmsg_dumper\n");
-
-	iounmap(cxt->virt_addr);
-	release_mem_region(cxt->phys_addr, cxt->size);
-	return 0;
-}
-
-static struct platform_driver ramoops_driver = {
-	.remove		= __exit_p(ramoops_remove),
-	.driver		= {
-		.name	= "ramoops",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init ramoops_init(void)
-{
-	int ret;
-	ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
-	if (ret == -ENODEV) {
-		/*
-		 * If we didn't find a platform device, we use module parameters
-		 * building platform data on the fly.
-		 */
-		pr_info("platform device not found, using module parameters\n");
-		dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
-				     GFP_KERNEL);
-		if (!dummy_data)
-			return -ENOMEM;
-		dummy_data->mem_size = mem_size;
-		dummy_data->mem_address = mem_address;
-		dummy_data->record_size = record_size;
-		dummy_data->dump_oops = dump_oops;
-		dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
-			NULL, 0, dummy_data,
-			sizeof(struct ramoops_platform_data));
-
-		if (IS_ERR(dummy))
-			ret = PTR_ERR(dummy);
-		else
-			ret = 0;
-	}
-
-	return ret;
-}
-
-static void __exit ramoops_exit(void)
-{
-	platform_driver_unregister(&ramoops_driver);
-	kfree(dummy_data);
-}
-
-module_init(ramoops_init);
-module_exit(ramoops_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
-MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index 31ba11c..2c5d15b 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -167,6 +167,7 @@
 	.BOOTSTS = UNIMPLEMENTED,
 	.CTL_1 = UNIMPLEMENTED,
 };
+
 static const struct config_registers v5_config_registers = {
 	.CRC = 0,
 	.FAR = 1,
@@ -192,6 +193,31 @@
 	.CTL_1 = 19,
 };
 
+static const struct config_registers v6_config_registers = {
+	.CRC = 0,
+	.FAR = 1,
+	.FDRI = 2,
+	.FDRO = 3,
+	.CMD = 4,
+	.CTL = 5,
+	.MASK = 6,
+	.STAT = 7,
+	.LOUT = 8,
+	.COR = 9,
+	.MFWR = 10,
+	.FLR = UNIMPLEMENTED,
+	.KEY = UNIMPLEMENTED,
+	.CBC = 11,
+	.IDCODE = 12,
+	.AXSS = 13,
+	.C0R_1 = 14,
+	.CSOB = 15,
+	.WBSTAR = 16,
+	.TIMER = 17,
+	.BOOTSTS = 22,
+	.CTL_1 = 24,
+};
+
 /**
  * hwicap_command_desync - Send a DESYNC command to the ICAP port.
  * @drvdata: a pointer to the drvdata.
@@ -744,6 +770,8 @@
 			regs = &v4_config_registers;
 		} else if (!strcmp(family, "virtex5")) {
 			regs = &v5_config_registers;
+		} else if (!strcmp(family, "virtex6")) {
+			regs = &v6_config_registers;
 		}
 	}
 	return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
@@ -785,6 +813,8 @@
 			regs = &v4_config_registers;
 		} else if (!strcmp(family, "virtex5")) {
 			regs = &v5_config_registers;
+		} else if (!strcmp(family, "virtex6")) {
+			regs = &v6_config_registers;
 		}
 	}
 
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
index 8cca119..d31ee23 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.h
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
@@ -86,7 +86,7 @@
 };
 
 /* Number of times to poll the done regsiter */
-#define XHI_MAX_RETRIES     10
+#define XHI_MAX_RETRIES     5000
 
 /************ Constant Definitions *************/
 
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 5138927..99c6b20 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -18,7 +18,7 @@
 
 config CLKSRC_DBX500_PRCMU
 	bool "Clocksource PRCMU Timer"
-	depends on UX500_SOC_DB5500 || UX500_SOC_DB8500
+	depends on UX500_SOC_DB8500
 	default y
 	help
 	  Use the always on PRCMU Timer as clocksource
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
index 0bf1b89..74b830b 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -161,7 +161,7 @@
 
 static int __init db8500_cpufreq_register(void)
 {
-	if (!cpu_is_u8500v20_or_later())
+	if (!cpu_is_u8500_family())
 		return -ENODEV;
 
 	pr_info("cpufreq for DB8500 started\n");
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 371f13c..1092a77 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -297,4 +297,32 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called tegra-aes.
 
+config CRYPTO_DEV_NX
+	tristate "Support for Power7+ in-Nest cryptographic accleration"
+	depends on PPC64 && IBMVIO
+	select CRYPTO_AES
+	select CRYPTO_CBC
+	select CRYPTO_ECB
+	select CRYPTO_CCM
+	select CRYPTO_GCM
+	select CRYPTO_AUTHENC
+	select CRYPTO_XCBC
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	help
+	  Support for Power7+ in-Nest cryptographic acceleration. This
+	  module supports acceleration for AES and SHA2 algorithms. If you
+	  choose 'M' here, this module will be called nx_crypto.
+
+config CRYPTO_DEV_UX500
+	tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration"
+	depends on ARCH_U8500
+	select CRYPTO_ALGAPI
+	help
+	  Driver for ST-Ericsson UX500 crypto engine.
+
+if CRYPTO_DEV_UX500
+	source "drivers/crypto/ux500/Kconfig"
+endif # if CRYPTO_DEV_UX500
+
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index f3e64ea..0139032 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -14,3 +14,4 @@
 obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
 obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
 obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
\ No newline at end of file
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 13f8e1a..802e851 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -1244,9 +1244,9 @@
 	iounmap(core_dev->dev->ce_base);
 err_iomap:
 	free_irq(core_dev->irq, dev);
+err_request_irq:
 	irq_dispose_mapping(core_dev->irq);
 	tasklet_kill(&core_dev->tasklet);
-err_request_irq:
 	crypto4xx_destroy_sdr(core_dev->dev);
 err_build_sdr:
 	crypto4xx_destroy_gdr(core_dev->dev);
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 534a364..4eec389 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -2267,8 +2267,11 @@
 	int i, err;
 
 	dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
-	if (!dev_node)
-		return;
+	if (!dev_node) {
+		dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+		if (!dev_node)
+			return;
+	}
 
 	pdev = of_find_device_by_node(dev_node);
 	if (!pdev)
@@ -2350,8 +2353,11 @@
 	int i = 0, err = 0;
 
 	dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
-	if (!dev_node)
-		return -ENODEV;
+	if (!dev_node) {
+		dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+		if (!dev_node)
+			return -ENODEV;
+	}
 
 	pdev = of_find_device_by_node(dev_node);
 	if (!pdev)
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index c5f61c5..77557eb 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -98,6 +98,12 @@
 	rspec = 0;
 	for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring")
 		rspec++;
+	if (!rspec) {
+		/* for backward compatible with device trees */
+		for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring")
+			rspec++;
+	}
+
 	ctrlpriv->jrdev = kzalloc(sizeof(struct device *) * rspec, GFP_KERNEL);
 	if (ctrlpriv->jrdev == NULL) {
 		iounmap(&topregs->ctrl);
@@ -111,6 +117,13 @@
 		ctrlpriv->total_jobrs++;
 		ring++;
 	}
+	if (!ring) {
+		for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") {
+			caam_jr_probe(pdev, np, ring);
+			ctrlpriv->total_jobrs++;
+			ring++;
+		}
+	}
 
 	/* Check to see if QI present. If so, enable */
 	ctrlpriv->qi_present = !!(rd_reg64(&topregs->ctrl.perfmon.comp_parms) &
@@ -226,6 +239,9 @@
 	{
 		.compatible = "fsl,sec-v4.0",
 	},
+	{
+		.compatible = "fsl,sec4.0",
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, caam_match);
diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile
new file mode 100644
index 0000000..411ce59
--- /dev/null
+++ b/drivers/crypto/nx/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_CRYPTO_DEV_NX) += nx-crypto.o
+nx-crypto-objs := nx.o \
+		  nx_debugfs.o \
+		  nx-aes-cbc.o \
+		  nx-aes-ecb.o \
+		  nx-aes-gcm.o \
+		  nx-aes-ccm.o \
+		  nx-aes-ctr.o \
+		  nx-aes-xcbc.o \
+		  nx-sha256.o \
+		  nx-sha512.o
diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c
new file mode 100644
index 0000000..69ed796
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-cbc.c
@@ -0,0 +1,141 @@
+/**
+ * AES CBC routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int cbc_aes_nx_set_key(struct crypto_tfm *tfm,
+			      const u8          *in_key,
+			      unsigned int       key_len)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+
+	nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+	switch (key_len) {
+	case AES_KEYSIZE_128:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+		break;
+	case AES_KEYSIZE_192:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+		break;
+	case AES_KEYSIZE_256:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	csbcpb->cpb.hdr.mode = NX_MODE_AES_CBC;
+	memcpy(csbcpb->cpb.aes_cbc.key, in_key, key_len);
+
+	return 0;
+}
+
+static int cbc_aes_nx_crypt(struct blkcipher_desc *desc,
+			    struct scatterlist    *dst,
+			    struct scatterlist    *src,
+			    unsigned int           nbytes,
+			    int                    enc)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	int rc;
+
+	if (nbytes > nx_ctx->ap->databytelen)
+		return -EINVAL;
+
+	if (enc)
+		NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+	else
+		NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+	rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
+			       csbcpb->cpb.aes_cbc.iv);
+	if (rc)
+		goto out;
+
+	if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->aes_ops));
+	atomic64_add(csbcpb->csb.processed_byte_count,
+		     &(nx_ctx->stats->aes_bytes));
+out:
+	return rc;
+}
+
+static int cbc_aes_nx_encrypt(struct blkcipher_desc *desc,
+			      struct scatterlist    *dst,
+			      struct scatterlist    *src,
+			      unsigned int           nbytes)
+{
+	return cbc_aes_nx_crypt(desc, dst, src, nbytes, 1);
+}
+
+static int cbc_aes_nx_decrypt(struct blkcipher_desc *desc,
+			      struct scatterlist    *dst,
+			      struct scatterlist    *src,
+			      unsigned int           nbytes)
+{
+	return cbc_aes_nx_crypt(desc, dst, src, nbytes, 0);
+}
+
+struct crypto_alg nx_cbc_aes_alg = {
+	.cra_name        = "cbc(aes)",
+	.cra_driver_name = "cbc-aes-nx",
+	.cra_priority    = 300,
+	.cra_flags       = CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize   = AES_BLOCK_SIZE,
+	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+	.cra_type        = &crypto_blkcipher_type,
+	.cra_module      = THIS_MODULE,
+	.cra_list        = LIST_HEAD_INIT(nx_cbc_aes_alg.cra_list),
+	.cra_init        = nx_crypto_ctx_aes_cbc_init,
+	.cra_exit        = nx_crypto_ctx_exit,
+	.cra_blkcipher = {
+		.min_keysize = AES_MIN_KEY_SIZE,
+		.max_keysize = AES_MAX_KEY_SIZE,
+		.ivsize      = AES_BLOCK_SIZE,
+		.setkey      = cbc_aes_nx_set_key,
+		.encrypt     = cbc_aes_nx_encrypt,
+		.decrypt     = cbc_aes_nx_decrypt,
+	}
+};
diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c
new file mode 100644
index 0000000..7aeac67
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-ccm.c
@@ -0,0 +1,468 @@
+/**
+ * AES CCM routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/aead.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ccm_aes_nx_set_key(struct crypto_aead *tfm,
+			      const u8           *in_key,
+			      unsigned int        key_len)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+
+	nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+	switch (key_len) {
+	case AES_KEYSIZE_128:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+		NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	csbcpb->cpb.hdr.mode = NX_MODE_AES_CCM;
+	memcpy(csbcpb->cpb.aes_ccm.key, in_key, key_len);
+
+	csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_CCA;
+	memcpy(csbcpb_aead->cpb.aes_cca.key, in_key, key_len);
+
+	return 0;
+
+}
+
+static int ccm4309_aes_nx_set_key(struct crypto_aead *tfm,
+				  const u8           *in_key,
+				  unsigned int        key_len)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+
+	if (key_len < 3)
+		return -EINVAL;
+
+	key_len -= 3;
+
+	memcpy(nx_ctx->priv.ccm.nonce, in_key + key_len, 3);
+
+	return ccm_aes_nx_set_key(tfm, in_key, key_len);
+}
+
+static int ccm_aes_nx_setauthsize(struct crypto_aead *tfm,
+				  unsigned int authsize)
+{
+	switch (authsize) {
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	crypto_aead_crt(tfm)->authsize = authsize;
+
+	return 0;
+}
+
+static int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm,
+				      unsigned int authsize)
+{
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	crypto_aead_crt(tfm)->authsize = authsize;
+
+	return 0;
+}
+
+/* taken from crypto/ccm.c */
+static int set_msg_len(u8 *block, unsigned int msglen, int csize)
+{
+	__be32 data;
+
+	memset(block, 0, csize);
+	block += csize;
+
+	if (csize >= 4)
+		csize = 4;
+	else if (msglen > (unsigned int)(1 << (8 * csize)))
+		return -EOVERFLOW;
+
+	data = cpu_to_be32(msglen);
+	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
+
+	return 0;
+}
+
+/* taken from crypto/ccm.c */
+static inline int crypto_ccm_check_iv(const u8 *iv)
+{
+	/* 2 <= L <= 8, so 1 <= L' <= 7. */
+	if (1 > iv[0] || iv[0] > 7)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* based on code from crypto/ccm.c */
+static int generate_b0(u8 *iv, unsigned int assoclen, unsigned int authsize,
+		       unsigned int cryptlen, u8 *b0)
+{
+	unsigned int l, lp, m = authsize;
+	int rc;
+
+	memcpy(b0, iv, 16);
+
+	lp = b0[0];
+	l = lp + 1;
+
+	/* set m, bits 3-5 */
+	*b0 |= (8 * ((m - 2) / 2));
+
+	/* set adata, bit 6, if associated data is used */
+	if (assoclen)
+		*b0 |= 64;
+
+	rc = set_msg_len(b0 + 16 - l, cryptlen, l);
+
+	return rc;
+}
+
+static int generate_pat(u8                   *iv,
+			struct aead_request  *req,
+			struct nx_crypto_ctx *nx_ctx,
+			unsigned int          authsize,
+			unsigned int          nbytes,
+			u8                   *out)
+{
+	struct nx_sg *nx_insg = nx_ctx->in_sg;
+	struct nx_sg *nx_outsg = nx_ctx->out_sg;
+	unsigned int iauth_len = 0;
+	struct vio_pfo_op *op = NULL;
+	u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL;
+	int rc;
+
+	/* zero the ctr value */
+	memset(iv + 15 - iv[0], 0, iv[0] + 1);
+
+	if (!req->assoclen) {
+		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
+	} else if (req->assoclen <= 14) {
+		/* if associated data is 14 bytes or less, we do 1 GCM
+		 * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1,
+		 * which is fed in through the source buffers here */
+		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
+		b1 = nx_ctx->priv.ccm.iauth_tag;
+		iauth_len = req->assoclen;
+
+		nx_insg = nx_build_sg_list(nx_insg, b1, 16, nx_ctx->ap->sglen);
+		nx_outsg = nx_build_sg_list(nx_outsg, tmp, 16,
+					    nx_ctx->ap->sglen);
+
+		/* inlen should be negative, indicating to phyp that its a
+		 * pointer to an sg list */
+		nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) *
+					sizeof(struct nx_sg);
+		nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) *
+					sizeof(struct nx_sg);
+
+		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE;
+
+		op = &nx_ctx->op;
+		result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac;
+	} else if (req->assoclen <= 65280) {
+		/* if associated data is less than (2^16 - 2^8), we construct
+		 * B1 differently and feed in the associated data to a CCA
+		 * operation */
+		b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
+		b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
+		iauth_len = 14;
+
+		/* remaining assoc data must have scatterlist built for it */
+		nx_insg = nx_walk_and_build(nx_insg, nx_ctx->ap->sglen,
+					    req->assoc, iauth_len,
+					    req->assoclen - iauth_len);
+		nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
+						sizeof(struct nx_sg);
+
+		op = &nx_ctx->op_aead;
+		result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
+	} else {
+		/* if associated data is less than (2^32), we construct B1
+		 * differently yet again and feed in the associated data to a
+		 * CCA operation */
+		pr_err("associated data len is %u bytes (returning -EINVAL)\n",
+		       req->assoclen);
+		rc = -EINVAL;
+	}
+
+	rc = generate_b0(iv, req->assoclen, authsize, nbytes, b0);
+	if (rc)
+		goto done;
+
+	if (b1) {
+		memset(b1, 0, 16);
+		*(u16 *)b1 = (u16)req->assoclen;
+
+		scatterwalk_map_and_copy(b1 + 2, req->assoc, 0,
+					 iauth_len, SCATTERWALK_FROM_SG);
+
+		rc = nx_hcall_sync(nx_ctx, op,
+				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+		if (rc)
+			goto done;
+
+		atomic_inc(&(nx_ctx->stats->aes_ops));
+		atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+		memcpy(out, result, AES_BLOCK_SIZE);
+	}
+done:
+	return rc;
+}
+
+static int ccm_nx_decrypt(struct aead_request   *req,
+			  struct blkcipher_desc *desc)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	unsigned int nbytes = req->cryptlen;
+	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
+	struct nx_ccm_priv *priv = &nx_ctx->priv.ccm;
+	int rc = -1;
+
+	if (nbytes > nx_ctx->ap->databytelen)
+		return -EINVAL;
+
+	nbytes -= authsize;
+
+	/* copy out the auth tag to compare with later */
+	scatterwalk_map_and_copy(priv->oauth_tag,
+				 req->src, nbytes, authsize,
+				 SCATTERWALK_FROM_SG);
+
+	rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes,
+			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
+	if (rc)
+		goto out;
+
+	rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
+			       csbcpb->cpb.aes_ccm.iv_or_ctr);
+	if (rc)
+		goto out;
+
+	NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+	NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->aes_ops));
+	atomic64_add(csbcpb->csb.processed_byte_count,
+		     &(nx_ctx->stats->aes_bytes));
+
+	rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
+		    authsize) ? -EBADMSG : 0;
+out:
+	return rc;
+}
+
+static int ccm_nx_encrypt(struct aead_request   *req,
+			  struct blkcipher_desc *desc)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	unsigned int nbytes = req->cryptlen;
+	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
+	int rc = -1;
+
+	if (nbytes > nx_ctx->ap->databytelen)
+		return -EINVAL;
+
+	rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes,
+			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
+	if (rc)
+		goto out;
+
+	rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
+			       csbcpb->cpb.aes_ccm.iv_or_ctr);
+	if (rc)
+		goto out;
+
+	NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+	NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->aes_ops));
+	atomic64_add(csbcpb->csb.processed_byte_count,
+		     &(nx_ctx->stats->aes_bytes));
+
+	/* copy out the auth tag */
+	scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac,
+				 req->dst, nbytes, authsize,
+				 SCATTERWALK_TO_SG);
+out:
+	return rc;
+}
+
+static int ccm4309_aes_nx_encrypt(struct aead_request *req)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+	struct blkcipher_desc desc;
+	u8 *iv = nx_ctx->priv.ccm.iv;
+
+	iv[0] = 3;
+	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
+	memcpy(iv + 4, req->iv, 8);
+
+	desc.info = iv;
+	desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+	return ccm_nx_encrypt(req, &desc);
+}
+
+static int ccm_aes_nx_encrypt(struct aead_request *req)
+{
+	struct blkcipher_desc desc;
+	int rc;
+
+	desc.info = req->iv;
+	desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+	rc = crypto_ccm_check_iv(desc.info);
+	if (rc)
+		return rc;
+
+	return ccm_nx_encrypt(req, &desc);
+}
+
+static int ccm4309_aes_nx_decrypt(struct aead_request *req)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+	struct blkcipher_desc desc;
+	u8 *iv = nx_ctx->priv.ccm.iv;
+
+	iv[0] = 3;
+	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
+	memcpy(iv + 4, req->iv, 8);
+
+	desc.info = iv;
+	desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+	return ccm_nx_decrypt(req, &desc);
+}
+
+static int ccm_aes_nx_decrypt(struct aead_request *req)
+{
+	struct blkcipher_desc desc;
+	int rc;
+
+	desc.info = req->iv;
+	desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+	rc = crypto_ccm_check_iv(desc.info);
+	if (rc)
+		return rc;
+
+	return ccm_nx_decrypt(req, &desc);
+}
+
+/* tell the block cipher walk routines that this is a stream cipher by
+ * setting cra_blocksize to 1. Even using blkcipher_walk_virt_block
+ * during encrypt/decrypt doesn't solve this problem, because it calls
+ * blkcipher_walk_done under the covers, which doesn't use walk->blocksize,
+ * but instead uses this tfm->blocksize. */
+struct crypto_alg nx_ccm_aes_alg = {
+	.cra_name        = "ccm(aes)",
+	.cra_driver_name = "ccm-aes-nx",
+	.cra_priority    = 300,
+	.cra_flags       = CRYPTO_ALG_TYPE_AEAD |
+			   CRYPTO_ALG_NEED_FALLBACK,
+	.cra_blocksize   = 1,
+	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+	.cra_type        = &crypto_aead_type,
+	.cra_module      = THIS_MODULE,
+	.cra_list        = LIST_HEAD_INIT(nx_ccm_aes_alg.cra_list),
+	.cra_init        = nx_crypto_ctx_aes_ccm_init,
+	.cra_exit        = nx_crypto_ctx_exit,
+	.cra_aead = {
+		.ivsize      = AES_BLOCK_SIZE,
+		.maxauthsize = AES_BLOCK_SIZE,
+		.setkey      = ccm_aes_nx_set_key,
+		.setauthsize = ccm_aes_nx_setauthsize,
+		.encrypt     = ccm_aes_nx_encrypt,
+		.decrypt     = ccm_aes_nx_decrypt,
+	}
+};
+
+struct crypto_alg nx_ccm4309_aes_alg = {
+	.cra_name        = "rfc4309(ccm(aes))",
+	.cra_driver_name = "rfc4309-ccm-aes-nx",
+	.cra_priority    = 300,
+	.cra_flags       = CRYPTO_ALG_TYPE_AEAD |
+			   CRYPTO_ALG_NEED_FALLBACK,
+	.cra_blocksize   = 1,
+	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+	.cra_type        = &crypto_nivaead_type,
+	.cra_module      = THIS_MODULE,
+	.cra_list        = LIST_HEAD_INIT(nx_ccm4309_aes_alg.cra_list),
+	.cra_init        = nx_crypto_ctx_aes_ccm_init,
+	.cra_exit        = nx_crypto_ctx_exit,
+	.cra_aead = {
+		.ivsize      = 8,
+		.maxauthsize = AES_BLOCK_SIZE,
+		.setkey      = ccm4309_aes_nx_set_key,
+		.setauthsize = ccm4309_aes_nx_setauthsize,
+		.encrypt     = ccm4309_aes_nx_encrypt,
+		.decrypt     = ccm4309_aes_nx_decrypt,
+		.geniv       = "seqiv",
+	}
+};
diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c
new file mode 100644
index 0000000..52d4eb0
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-ctr.c
@@ -0,0 +1,178 @@
+/**
+ * AES CTR routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/ctr.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ctr_aes_nx_set_key(struct crypto_tfm *tfm,
+			      const u8          *in_key,
+			      unsigned int       key_len)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+
+	nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+	switch (key_len) {
+	case AES_KEYSIZE_128:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+		break;
+	case AES_KEYSIZE_192:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+		break;
+	case AES_KEYSIZE_256:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	csbcpb->cpb.hdr.mode = NX_MODE_AES_CTR;
+	memcpy(csbcpb->cpb.aes_ctr.key, in_key, key_len);
+
+	return 0;
+}
+
+static int ctr3686_aes_nx_set_key(struct crypto_tfm *tfm,
+				  const u8          *in_key,
+				  unsigned int       key_len)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+
+	if (key_len < CTR_RFC3686_NONCE_SIZE)
+		return -EINVAL;
+
+	memcpy(nx_ctx->priv.ctr.iv,
+	       in_key + key_len - CTR_RFC3686_NONCE_SIZE,
+	       CTR_RFC3686_NONCE_SIZE);
+
+	key_len -= CTR_RFC3686_NONCE_SIZE;
+
+	return ctr_aes_nx_set_key(tfm, in_key, key_len);
+}
+
+static int ctr_aes_nx_crypt(struct blkcipher_desc *desc,
+			    struct scatterlist    *dst,
+			    struct scatterlist    *src,
+			    unsigned int           nbytes)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	int rc;
+
+	if (nbytes > nx_ctx->ap->databytelen)
+		return -EINVAL;
+
+	rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
+			       csbcpb->cpb.aes_ctr.iv);
+	if (rc)
+		goto out;
+
+	if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->aes_ops));
+	atomic64_add(csbcpb->csb.processed_byte_count,
+		     &(nx_ctx->stats->aes_bytes));
+out:
+	return rc;
+}
+
+static int ctr3686_aes_nx_crypt(struct blkcipher_desc *desc,
+				struct scatterlist    *dst,
+				struct scatterlist    *src,
+				unsigned int           nbytes)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+	u8 *iv = nx_ctx->priv.ctr.iv;
+
+	memcpy(iv + CTR_RFC3686_NONCE_SIZE,
+	       desc->info, CTR_RFC3686_IV_SIZE);
+	iv[15] = 1;
+
+	desc->info = nx_ctx->priv.ctr.iv;
+
+	return ctr_aes_nx_crypt(desc, dst, src, nbytes);
+}
+
+struct crypto_alg nx_ctr_aes_alg = {
+	.cra_name        = "ctr(aes)",
+	.cra_driver_name = "ctr-aes-nx",
+	.cra_priority    = 300,
+	.cra_flags       = CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize   = 1,
+	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+	.cra_type        = &crypto_blkcipher_type,
+	.cra_module      = THIS_MODULE,
+	.cra_list        = LIST_HEAD_INIT(nx_ctr_aes_alg.cra_list),
+	.cra_init        = nx_crypto_ctx_aes_ctr_init,
+	.cra_exit        = nx_crypto_ctx_exit,
+	.cra_blkcipher = {
+		.min_keysize = AES_MIN_KEY_SIZE,
+		.max_keysize = AES_MAX_KEY_SIZE,
+		.ivsize      = AES_BLOCK_SIZE,
+		.setkey      = ctr_aes_nx_set_key,
+		.encrypt     = ctr_aes_nx_crypt,
+		.decrypt     = ctr_aes_nx_crypt,
+	}
+};
+
+struct crypto_alg nx_ctr3686_aes_alg = {
+	.cra_name        = "rfc3686(ctr(aes))",
+	.cra_driver_name = "rfc3686-ctr-aes-nx",
+	.cra_priority    = 300,
+	.cra_flags       = CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize   = 1,
+	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+	.cra_type        = &crypto_blkcipher_type,
+	.cra_module      = THIS_MODULE,
+	.cra_list        = LIST_HEAD_INIT(nx_ctr3686_aes_alg.cra_list),
+	.cra_init        = nx_crypto_ctx_aes_ctr_init,
+	.cra_exit        = nx_crypto_ctx_exit,
+	.cra_blkcipher = {
+		.min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
+		.max_keysize = AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
+		.ivsize      = CTR_RFC3686_IV_SIZE,
+		.geniv       = "seqiv",
+		.setkey      = ctr3686_aes_nx_set_key,
+		.encrypt     = ctr3686_aes_nx_crypt,
+		.decrypt     = ctr3686_aes_nx_crypt,
+	}
+};
diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c
new file mode 100644
index 0000000..7b77bc2
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-ecb.c
@@ -0,0 +1,139 @@
+/**
+ * AES ECB routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ecb_aes_nx_set_key(struct crypto_tfm *tfm,
+			      const u8          *in_key,
+			      unsigned int       key_len)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+	struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+
+	nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+	switch (key_len) {
+	case AES_KEYSIZE_128:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+		break;
+	case AES_KEYSIZE_192:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+		break;
+	case AES_KEYSIZE_256:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	csbcpb->cpb.hdr.mode = NX_MODE_AES_ECB;
+	memcpy(csbcpb->cpb.aes_ecb.key, in_key, key_len);
+
+	return 0;
+}
+
+static int ecb_aes_nx_crypt(struct blkcipher_desc *desc,
+			    struct scatterlist    *dst,
+			    struct scatterlist    *src,
+			    unsigned int           nbytes,
+			    int                    enc)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	int rc;
+
+	if (nbytes > nx_ctx->ap->databytelen)
+		return -EINVAL;
+
+	if (enc)
+		NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+	else
+		NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+	rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes, NULL);
+	if (rc)
+		goto out;
+
+	if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->aes_ops));
+	atomic64_add(csbcpb->csb.processed_byte_count,
+		     &(nx_ctx->stats->aes_bytes));
+out:
+	return rc;
+}
+
+static int ecb_aes_nx_encrypt(struct blkcipher_desc *desc,
+			      struct scatterlist    *dst,
+			      struct scatterlist    *src,
+			      unsigned int           nbytes)
+{
+	return ecb_aes_nx_crypt(desc, dst, src, nbytes, 1);
+}
+
+static int ecb_aes_nx_decrypt(struct blkcipher_desc *desc,
+			      struct scatterlist    *dst,
+			      struct scatterlist    *src,
+			      unsigned int           nbytes)
+{
+	return ecb_aes_nx_crypt(desc, dst, src, nbytes, 0);
+}
+
+struct crypto_alg nx_ecb_aes_alg = {
+	.cra_name        = "ecb(aes)",
+	.cra_driver_name = "ecb-aes-nx",
+	.cra_priority    = 300,
+	.cra_flags       = CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize   = AES_BLOCK_SIZE,
+	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+	.cra_type        = &crypto_blkcipher_type,
+	.cra_module      = THIS_MODULE,
+	.cra_list        = LIST_HEAD_INIT(nx_ecb_aes_alg.cra_list),
+	.cra_init        = nx_crypto_ctx_aes_ecb_init,
+	.cra_exit        = nx_crypto_ctx_exit,
+	.cra_blkcipher = {
+		.min_keysize = AES_MIN_KEY_SIZE,
+		.max_keysize = AES_MAX_KEY_SIZE,
+		.setkey      = ecb_aes_nx_set_key,
+		.encrypt     = ecb_aes_nx_encrypt,
+		.decrypt     = ecb_aes_nx_decrypt,
+	}
+};
diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c
new file mode 100644
index 0000000..9ab1c73
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-gcm.c
@@ -0,0 +1,353 @@
+/**
+ * AES GCM routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/aead.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int gcm_aes_nx_set_key(struct crypto_aead *tfm,
+			      const u8           *in_key,
+			      unsigned int        key_len)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+
+	nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+	switch (key_len) {
+	case AES_KEYSIZE_128:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+		NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+		break;
+	case AES_KEYSIZE_192:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+		NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_192);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+		break;
+	case AES_KEYSIZE_256:
+		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+		NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_256);
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	csbcpb->cpb.hdr.mode = NX_MODE_AES_GCM;
+	memcpy(csbcpb->cpb.aes_gcm.key, in_key, key_len);
+
+	csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_GCA;
+	memcpy(csbcpb_aead->cpb.aes_gca.key, in_key, key_len);
+
+	return 0;
+}
+
+static int gcm4106_aes_nx_set_key(struct crypto_aead *tfm,
+				  const u8           *in_key,
+				  unsigned int        key_len)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+	char *nonce = nx_ctx->priv.gcm.nonce;
+	int rc;
+
+	if (key_len < 4)
+		return -EINVAL;
+
+	key_len -= 4;
+
+	rc = gcm_aes_nx_set_key(tfm, in_key, key_len);
+	if (rc)
+		goto out;
+
+	memcpy(nonce, in_key + key_len, 4);
+out:
+	return rc;
+}
+
+static int gcm_aes_nx_setauthsize(struct crypto_aead *tfm,
+				  unsigned int authsize)
+{
+	if (authsize > crypto_aead_alg(tfm)->maxauthsize)
+		return -EINVAL;
+
+	crypto_aead_crt(tfm)->authsize = authsize;
+
+	return 0;
+}
+
+static int gcm4106_aes_nx_setauthsize(struct crypto_aead *tfm,
+				      unsigned int authsize)
+{
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	crypto_aead_crt(tfm)->authsize = authsize;
+
+	return 0;
+}
+
+static int nx_gca(struct nx_crypto_ctx  *nx_ctx,
+		  struct aead_request   *req,
+		  u8                    *out)
+{
+	struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+	int rc = -EINVAL;
+	struct scatter_walk walk;
+	struct nx_sg *nx_sg = nx_ctx->in_sg;
+
+	if (req->assoclen > nx_ctx->ap->databytelen)
+		goto out;
+
+	if (req->assoclen <= AES_BLOCK_SIZE) {
+		scatterwalk_start(&walk, req->assoc);
+		scatterwalk_copychunks(out, &walk, req->assoclen,
+				       SCATTERWALK_FROM_SG);
+		scatterwalk_done(&walk, SCATTERWALK_FROM_SG, 0);
+
+		rc = 0;
+		goto out;
+	}
+
+	nx_sg = nx_walk_and_build(nx_sg, nx_ctx->ap->sglen, req->assoc, 0,
+				  req->assoclen);
+	nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_sg) * sizeof(struct nx_sg);
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
+			   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->aes_ops));
+	atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+	memcpy(out, csbcpb_aead->cpb.aes_gca.out_pat, AES_BLOCK_SIZE);
+out:
+	return rc;
+}
+
+static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	struct blkcipher_desc desc;
+	unsigned int nbytes = req->cryptlen;
+	int rc = -EINVAL;
+
+	if (nbytes > nx_ctx->ap->databytelen)
+		goto out;
+
+	desc.info = nx_ctx->priv.gcm.iv;
+	/* initialize the counter */
+	*(u32 *)(desc.info + NX_GCM_CTR_OFFSET) = 1;
+
+	/* For scenarios where the input message is zero length, AES CTR mode
+	 * may be used. Set the source data to be a single block (16B) of all
+	 * zeros, and set the input IV value to be the same as the GMAC IV
+	 * value. - nx_wb 4.8.1.3 */
+	if (nbytes == 0) {
+		char src[AES_BLOCK_SIZE] = {};
+		struct scatterlist sg;
+
+		desc.tfm = crypto_alloc_blkcipher("ctr(aes)", 0, 0);
+		if (IS_ERR(desc.tfm)) {
+			rc = -ENOMEM;
+			goto out;
+		}
+
+		crypto_blkcipher_setkey(desc.tfm, csbcpb->cpb.aes_gcm.key,
+			NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_128 ? 16 :
+			NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_192 ? 24 : 32);
+
+		sg_init_one(&sg, src, AES_BLOCK_SIZE);
+		if (enc)
+			crypto_blkcipher_encrypt_iv(&desc, req->dst, &sg,
+						    AES_BLOCK_SIZE);
+		else
+			crypto_blkcipher_decrypt_iv(&desc, req->dst, &sg,
+						    AES_BLOCK_SIZE);
+		crypto_free_blkcipher(desc.tfm);
+
+		rc = 0;
+		goto out;
+	}
+
+	desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+	csbcpb->cpb.aes_gcm.bit_length_aad = req->assoclen * 8;
+
+	if (req->assoclen) {
+		rc = nx_gca(nx_ctx, req, csbcpb->cpb.aes_gcm.in_pat_or_aad);
+		if (rc)
+			goto out;
+	}
+
+	if (enc)
+		NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+	else
+		nbytes -= AES_BLOCK_SIZE;
+
+	csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8;
+
+	rc = nx_build_sg_lists(nx_ctx, &desc, req->dst, req->src, nbytes,
+			       csbcpb->cpb.aes_gcm.iv_or_cnt);
+	if (rc)
+		goto out;
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->aes_ops));
+	atomic64_add(csbcpb->csb.processed_byte_count,
+		     &(nx_ctx->stats->aes_bytes));
+
+	if (enc) {
+		/* copy out the auth tag */
+		scatterwalk_map_and_copy(csbcpb->cpb.aes_gcm.out_pat_or_mac,
+				 req->dst, nbytes,
+				 crypto_aead_authsize(crypto_aead_reqtfm(req)),
+				 SCATTERWALK_TO_SG);
+	} else if (req->assoclen) {
+		u8 *itag = nx_ctx->priv.gcm.iauth_tag;
+		u8 *otag = csbcpb->cpb.aes_gcm.out_pat_or_mac;
+
+		scatterwalk_map_and_copy(itag, req->dst, nbytes,
+				 crypto_aead_authsize(crypto_aead_reqtfm(req)),
+				 SCATTERWALK_FROM_SG);
+		rc = memcmp(itag, otag,
+			    crypto_aead_authsize(crypto_aead_reqtfm(req))) ?
+		     -EBADMSG : 0;
+	}
+out:
+	return rc;
+}
+
+static int gcm_aes_nx_encrypt(struct aead_request *req)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+	char *iv = nx_ctx->priv.gcm.iv;
+
+	memcpy(iv, req->iv, 12);
+
+	return gcm_aes_nx_crypt(req, 1);
+}
+
+static int gcm_aes_nx_decrypt(struct aead_request *req)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+	char *iv = nx_ctx->priv.gcm.iv;
+
+	memcpy(iv, req->iv, 12);
+
+	return gcm_aes_nx_crypt(req, 0);
+}
+
+static int gcm4106_aes_nx_encrypt(struct aead_request *req)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+	char *iv = nx_ctx->priv.gcm.iv;
+	char *nonce = nx_ctx->priv.gcm.nonce;
+
+	memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
+	memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8);
+
+	return gcm_aes_nx_crypt(req, 1);
+}
+
+static int gcm4106_aes_nx_decrypt(struct aead_request *req)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+	char *iv = nx_ctx->priv.gcm.iv;
+	char *nonce = nx_ctx->priv.gcm.nonce;
+
+	memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
+	memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8);
+
+	return gcm_aes_nx_crypt(req, 0);
+}
+
+/* tell the block cipher walk routines that this is a stream cipher by
+ * setting cra_blocksize to 1. Even using blkcipher_walk_virt_block
+ * during encrypt/decrypt doesn't solve this problem, because it calls
+ * blkcipher_walk_done under the covers, which doesn't use walk->blocksize,
+ * but instead uses this tfm->blocksize. */
+struct crypto_alg nx_gcm_aes_alg = {
+	.cra_name        = "gcm(aes)",
+	.cra_driver_name = "gcm-aes-nx",
+	.cra_priority    = 300,
+	.cra_flags       = CRYPTO_ALG_TYPE_AEAD,
+	.cra_blocksize   = 1,
+	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+	.cra_type        = &crypto_aead_type,
+	.cra_module      = THIS_MODULE,
+	.cra_list        = LIST_HEAD_INIT(nx_gcm_aes_alg.cra_list),
+	.cra_init        = nx_crypto_ctx_aes_gcm_init,
+	.cra_exit        = nx_crypto_ctx_exit,
+	.cra_aead = {
+		.ivsize      = AES_BLOCK_SIZE,
+		.maxauthsize = AES_BLOCK_SIZE,
+		.setkey      = gcm_aes_nx_set_key,
+		.setauthsize = gcm_aes_nx_setauthsize,
+		.encrypt     = gcm_aes_nx_encrypt,
+		.decrypt     = gcm_aes_nx_decrypt,
+	}
+};
+
+struct crypto_alg nx_gcm4106_aes_alg = {
+	.cra_name        = "rfc4106(gcm(aes))",
+	.cra_driver_name = "rfc4106-gcm-aes-nx",
+	.cra_priority    = 300,
+	.cra_flags       = CRYPTO_ALG_TYPE_AEAD,
+	.cra_blocksize   = 1,
+	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+	.cra_type        = &crypto_nivaead_type,
+	.cra_module      = THIS_MODULE,
+	.cra_list        = LIST_HEAD_INIT(nx_gcm4106_aes_alg.cra_list),
+	.cra_init        = nx_crypto_ctx_aes_gcm_init,
+	.cra_exit        = nx_crypto_ctx_exit,
+	.cra_aead = {
+		.ivsize      = 8,
+		.maxauthsize = AES_BLOCK_SIZE,
+		.geniv       = "seqiv",
+		.setkey      = gcm4106_aes_nx_set_key,
+		.setauthsize = gcm4106_aes_nx_setauthsize,
+		.encrypt     = gcm4106_aes_nx_encrypt,
+		.decrypt     = gcm4106_aes_nx_decrypt,
+	}
+};
diff --git a/drivers/crypto/nx/nx-aes-xcbc.c b/drivers/crypto/nx/nx-aes-xcbc.c
new file mode 100644
index 0000000..93923e4
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-xcbc.c
@@ -0,0 +1,236 @@
+/**
+ * AES XCBC routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+struct xcbc_state {
+	u8 state[AES_BLOCK_SIZE];
+	unsigned int count;
+	u8 buffer[AES_BLOCK_SIZE];
+};
+
+static int nx_xcbc_set_key(struct crypto_shash *desc,
+			   const u8            *in_key,
+			   unsigned int         key_len)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_shash_ctx(desc);
+
+	switch (key_len) {
+	case AES_KEYSIZE_128:
+		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	memcpy(nx_ctx->priv.xcbc.key, in_key, key_len);
+
+	return 0;
+}
+
+static int nx_xcbc_init(struct shash_desc *desc)
+{
+	struct xcbc_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	struct nx_sg *out_sg;
+
+	nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+	memset(sctx, 0, sizeof *sctx);
+
+	NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+	csbcpb->cpb.hdr.mode = NX_MODE_AES_XCBC_MAC;
+
+	memcpy(csbcpb->cpb.aes_xcbc.key, nx_ctx->priv.xcbc.key, AES_BLOCK_SIZE);
+	memset(nx_ctx->priv.xcbc.key, 0, sizeof *nx_ctx->priv.xcbc.key);
+
+	out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+				  AES_BLOCK_SIZE, nx_ctx->ap->sglen);
+	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+	return 0;
+}
+
+static int nx_xcbc_update(struct shash_desc *desc,
+			  const u8          *data,
+			  unsigned int       len)
+{
+	struct xcbc_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	struct nx_sg *in_sg;
+	u32 to_process, leftover;
+	int rc = 0;
+
+	if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+		/* we've hit the nx chip previously and we're updating again,
+		 * so copy over the partial digest */
+		memcpy(csbcpb->cpb.aes_xcbc.cv,
+		       csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+	}
+
+	/* 2 cases for total data len:
+	 *  1: <= AES_BLOCK_SIZE: copy into state, return 0
+	 *  2: > AES_BLOCK_SIZE: process X blocks, copy in leftover
+	 */
+	if (len + sctx->count <= AES_BLOCK_SIZE) {
+		memcpy(sctx->buffer + sctx->count, data, len);
+		sctx->count += len;
+		goto out;
+	}
+
+	/* to_process: the AES_BLOCK_SIZE data chunk to process in this
+	 * update */
+	to_process = (sctx->count + len) & ~(AES_BLOCK_SIZE - 1);
+	leftover = (sctx->count + len) & (AES_BLOCK_SIZE - 1);
+
+	/* the hardware will not accept a 0 byte operation for this algorithm
+	 * and the operation MUST be finalized to be correct. So if we happen
+	 * to get an update that falls on a block sized boundary, we must
+	 * save off the last block to finalize with later. */
+	if (!leftover) {
+		to_process -= AES_BLOCK_SIZE;
+		leftover = AES_BLOCK_SIZE;
+	}
+
+	if (sctx->count) {
+		in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buffer,
+					 sctx->count, nx_ctx->ap->sglen);
+		in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+					 to_process - sctx->count,
+					 nx_ctx->ap->sglen);
+		nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+					sizeof(struct nx_sg);
+	} else {
+		in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data, to_process,
+					 nx_ctx->ap->sglen);
+		nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+					sizeof(struct nx_sg);
+	}
+
+	NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+	if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->aes_ops));
+
+	/* copy the leftover back into the state struct */
+	memcpy(sctx->buffer, data + len - leftover, leftover);
+	sctx->count = leftover;
+
+	/* everything after the first update is continuation */
+	NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+	return rc;
+}
+
+static int nx_xcbc_final(struct shash_desc *desc, u8 *out)
+{
+	struct xcbc_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+	struct nx_sg *in_sg, *out_sg;
+	int rc = 0;
+
+	if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+		/* we've hit the nx chip previously, now we're finalizing,
+		 * so copy over the partial digest */
+		memcpy(csbcpb->cpb.aes_xcbc.cv,
+		       csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+	} else if (sctx->count == 0) {
+		/* we've never seen an update, so this is a 0 byte op. The
+		 * hardware cannot handle a 0 byte op, so just copy out the
+		 * known 0 byte result. This is cheaper than allocating a
+		 * software context to do a 0 byte op */
+		u8 data[] = { 0x75, 0xf0, 0x25, 0x1d, 0x52, 0x8a, 0xc0, 0x1c,
+			      0x45, 0x73, 0xdf, 0xd5, 0x84, 0xd7, 0x9f, 0x29 };
+		memcpy(out, data, sizeof(data));
+		goto out;
+	}
+
+	/* final is represented by continuing the operation and indicating that
+	 * this is not an intermediate operation */
+	NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+	in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buffer,
+				 sctx->count, nx_ctx->ap->sglen);
+	out_sg = nx_build_sg_list(nx_ctx->out_sg, out, AES_BLOCK_SIZE,
+				  nx_ctx->ap->sglen);
+
+	nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+	if (!nx_ctx->op.outlen) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->aes_ops));
+
+	memcpy(out, csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+out:
+	return rc;
+}
+
+struct shash_alg nx_shash_aes_xcbc_alg = {
+	.digestsize = AES_BLOCK_SIZE,
+	.init       = nx_xcbc_init,
+	.update     = nx_xcbc_update,
+	.final      = nx_xcbc_final,
+	.setkey     = nx_xcbc_set_key,
+	.descsize   = sizeof(struct xcbc_state),
+	.statesize  = sizeof(struct xcbc_state),
+	.base       = {
+		.cra_name        = "xcbc(aes)",
+		.cra_driver_name = "xcbc-aes-nx",
+		.cra_priority    = 300,
+		.cra_flags       = CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize   = AES_BLOCK_SIZE,
+		.cra_module      = THIS_MODULE,
+		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+		.cra_init        = nx_crypto_ctx_aes_xcbc_init,
+		.cra_exit        = nx_crypto_ctx_exit,
+	}
+};
diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c
new file mode 100644
index 0000000..9767315
--- /dev/null
+++ b/drivers/crypto/nx/nx-sha256.c
@@ -0,0 +1,246 @@
+/**
+ * SHA-256 routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <linux/module.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int nx_sha256_init(struct shash_desc *desc)
+{
+	struct sha256_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_sg *out_sg;
+
+	nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+
+	memset(sctx, 0, sizeof *sctx);
+
+	nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA256];
+
+	NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA256);
+	out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+				  SHA256_DIGEST_SIZE, nx_ctx->ap->sglen);
+	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+	return 0;
+}
+
+static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
+			    unsigned int len)
+{
+	struct sha256_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+	struct nx_sg *in_sg;
+	u64 to_process, leftover;
+	int rc = 0;
+
+	if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+		/* we've hit the nx chip previously and we're updating again,
+		 * so copy over the partial digest */
+		memcpy(csbcpb->cpb.sha256.input_partial_digest,
+		       csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+	}
+
+	/* 2 cases for total data len:
+	 *  1: <= SHA256_BLOCK_SIZE: copy into state, return 0
+	 *  2: > SHA256_BLOCK_SIZE: process X blocks, copy in leftover
+	 */
+	if (len + sctx->count <= SHA256_BLOCK_SIZE) {
+		memcpy(sctx->buf + sctx->count, data, len);
+		sctx->count += len;
+		goto out;
+	}
+
+	/* to_process: the SHA256_BLOCK_SIZE data chunk to process in this
+	 * update */
+	to_process = (sctx->count + len) & ~(SHA256_BLOCK_SIZE - 1);
+	leftover = (sctx->count + len) & (SHA256_BLOCK_SIZE - 1);
+
+	if (sctx->count) {
+		in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+					 sctx->count, nx_ctx->ap->sglen);
+		in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+					 to_process - sctx->count,
+					 nx_ctx->ap->sglen);
+		nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+					sizeof(struct nx_sg);
+	} else {
+		in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
+					 to_process, nx_ctx->ap->sglen);
+		nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+					sizeof(struct nx_sg);
+	}
+
+	NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+	if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->sha256_ops));
+
+	/* copy the leftover back into the state struct */
+	memcpy(sctx->buf, data + len - leftover, leftover);
+	sctx->count = leftover;
+
+	csbcpb->cpb.sha256.message_bit_length += (u64)
+		(csbcpb->cpb.sha256.spbc * 8);
+
+	/* everything after the first update is continuation */
+	NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+	return rc;
+}
+
+static int nx_sha256_final(struct shash_desc *desc, u8 *out)
+{
+	struct sha256_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+	struct nx_sg *in_sg, *out_sg;
+	int rc;
+
+	if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+		/* we've hit the nx chip previously, now we're finalizing,
+		 * so copy over the partial digest */
+		memcpy(csbcpb->cpb.sha256.input_partial_digest,
+		       csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+	}
+
+	/* final is represented by continuing the operation and indicating that
+	 * this is not an intermediate operation */
+	NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+	csbcpb->cpb.sha256.message_bit_length += (u64)(sctx->count * 8);
+
+	in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+				 sctx->count, nx_ctx->ap->sglen);
+	out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA256_DIGEST_SIZE,
+				  nx_ctx->ap->sglen);
+	nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+	if (!nx_ctx->op.outlen) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->sha256_ops));
+
+	atomic64_add(csbcpb->cpb.sha256.message_bit_length,
+		     &(nx_ctx->stats->sha256_bytes));
+	memcpy(out, csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+out:
+	return rc;
+}
+
+static int nx_sha256_export(struct shash_desc *desc, void *out)
+{
+	struct sha256_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+	struct sha256_state *octx = out;
+
+	octx->count = sctx->count +
+		      (csbcpb->cpb.sha256.message_bit_length / 8);
+	memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+	/* if no data has been processed yet, we need to export SHA256's
+	 * initial data, in case this context gets imported into a software
+	 * context */
+	if (csbcpb->cpb.sha256.message_bit_length)
+		memcpy(octx->state, csbcpb->cpb.sha256.message_digest,
+		       SHA256_DIGEST_SIZE);
+	else {
+		octx->state[0] = SHA256_H0;
+		octx->state[1] = SHA256_H1;
+		octx->state[2] = SHA256_H2;
+		octx->state[3] = SHA256_H3;
+		octx->state[4] = SHA256_H4;
+		octx->state[5] = SHA256_H5;
+		octx->state[6] = SHA256_H6;
+		octx->state[7] = SHA256_H7;
+	}
+
+	return 0;
+}
+
+static int nx_sha256_import(struct shash_desc *desc, const void *in)
+{
+	struct sha256_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+	const struct sha256_state *ictx = in;
+
+	memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+
+	sctx->count = ictx->count & 0x3f;
+	csbcpb->cpb.sha256.message_bit_length = (ictx->count & ~0x3f) * 8;
+
+	if (csbcpb->cpb.sha256.message_bit_length) {
+		memcpy(csbcpb->cpb.sha256.message_digest, ictx->state,
+		       SHA256_DIGEST_SIZE);
+
+		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+		NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+	}
+
+	return 0;
+}
+
+struct shash_alg nx_shash_sha256_alg = {
+	.digestsize = SHA256_DIGEST_SIZE,
+	.init       = nx_sha256_init,
+	.update     = nx_sha256_update,
+	.final      = nx_sha256_final,
+	.export     = nx_sha256_export,
+	.import     = nx_sha256_import,
+	.descsize   = sizeof(struct sha256_state),
+	.statesize  = sizeof(struct sha256_state),
+	.base       = {
+		.cra_name        = "sha256",
+		.cra_driver_name = "sha256-nx",
+		.cra_priority    = 300,
+		.cra_flags       = CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize   = SHA256_BLOCK_SIZE,
+		.cra_module      = THIS_MODULE,
+		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+		.cra_init        = nx_crypto_ctx_sha_init,
+		.cra_exit        = nx_crypto_ctx_exit,
+	}
+};
diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c
new file mode 100644
index 0000000..3177b8c
--- /dev/null
+++ b/drivers/crypto/nx/nx-sha512.c
@@ -0,0 +1,265 @@
+/**
+ * SHA-512 routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <linux/module.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int nx_sha512_init(struct shash_desc *desc)
+{
+	struct sha512_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_sg *out_sg;
+
+	nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+
+	memset(sctx, 0, sizeof *sctx);
+
+	nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA512];
+
+	NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA512);
+	out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+				  SHA512_DIGEST_SIZE, nx_ctx->ap->sglen);
+	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+	return 0;
+}
+
+static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
+			    unsigned int len)
+{
+	struct sha512_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+	struct nx_sg *in_sg;
+	u64 to_process, leftover, spbc_bits;
+	int rc = 0;
+
+	if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+		/* we've hit the nx chip previously and we're updating again,
+		 * so copy over the partial digest */
+		memcpy(csbcpb->cpb.sha512.input_partial_digest,
+		       csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+	}
+
+	/* 2 cases for total data len:
+	 *  1: <= SHA512_BLOCK_SIZE: copy into state, return 0
+	 *  2: > SHA512_BLOCK_SIZE: process X blocks, copy in leftover
+	 */
+	if ((u64)len + sctx->count[0] <= SHA512_BLOCK_SIZE) {
+		memcpy(sctx->buf + sctx->count[0], data, len);
+		sctx->count[0] += len;
+		goto out;
+	}
+
+	/* to_process: the SHA512_BLOCK_SIZE data chunk to process in this
+	 * update */
+	to_process = (sctx->count[0] + len) & ~(SHA512_BLOCK_SIZE - 1);
+	leftover = (sctx->count[0] + len) & (SHA512_BLOCK_SIZE - 1);
+
+	if (sctx->count[0]) {
+		in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+					 sctx->count[0], nx_ctx->ap->sglen);
+		in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+					 to_process - sctx->count[0],
+					 nx_ctx->ap->sglen);
+		nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+					sizeof(struct nx_sg);
+	} else {
+		in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
+					 to_process, nx_ctx->ap->sglen);
+		nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+					sizeof(struct nx_sg);
+	}
+
+	NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+	if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->sha512_ops));
+
+	/* copy the leftover back into the state struct */
+	memcpy(sctx->buf, data + len - leftover, leftover);
+	sctx->count[0] = leftover;
+
+	spbc_bits = csbcpb->cpb.sha512.spbc * 8;
+	csbcpb->cpb.sha512.message_bit_length_lo += spbc_bits;
+	if (csbcpb->cpb.sha512.message_bit_length_lo < spbc_bits)
+		csbcpb->cpb.sha512.message_bit_length_hi++;
+
+	/* everything after the first update is continuation */
+	NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+	return rc;
+}
+
+static int nx_sha512_final(struct shash_desc *desc, u8 *out)
+{
+	struct sha512_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+	struct nx_sg *in_sg, *out_sg;
+	u64 count0;
+	int rc;
+
+	if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+		/* we've hit the nx chip previously, now we're finalizing,
+		 * so copy over the partial digest */
+		memcpy(csbcpb->cpb.sha512.input_partial_digest,
+		       csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+	}
+
+	/* final is represented by continuing the operation and indicating that
+	 * this is not an intermediate operation */
+	NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+	count0 = sctx->count[0] * 8;
+
+	csbcpb->cpb.sha512.message_bit_length_lo += count0;
+	if (csbcpb->cpb.sha512.message_bit_length_lo < count0)
+		csbcpb->cpb.sha512.message_bit_length_hi++;
+
+	in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buf, sctx->count[0],
+				 nx_ctx->ap->sglen);
+	out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA512_DIGEST_SIZE,
+				  nx_ctx->ap->sglen);
+	nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+	if (!nx_ctx->op.outlen) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+			   desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+	if (rc)
+		goto out;
+
+	atomic_inc(&(nx_ctx->stats->sha512_ops));
+	atomic64_add(csbcpb->cpb.sha512.message_bit_length_lo,
+		     &(nx_ctx->stats->sha512_bytes));
+
+	memcpy(out, csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+out:
+	return rc;
+}
+
+static int nx_sha512_export(struct shash_desc *desc, void *out)
+{
+	struct sha512_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+	struct sha512_state *octx = out;
+
+	/* move message_bit_length (128 bits) into count and convert its value
+	 * to bytes */
+	octx->count[0] = csbcpb->cpb.sha512.message_bit_length_lo >> 3 |
+			 ((csbcpb->cpb.sha512.message_bit_length_hi & 7) << 61);
+	octx->count[1] = csbcpb->cpb.sha512.message_bit_length_hi >> 3;
+
+	octx->count[0] += sctx->count[0];
+	if (octx->count[0] < sctx->count[0])
+		octx->count[1]++;
+
+	memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+	/* if no data has been processed yet, we need to export SHA512's
+	 * initial data, in case this context gets imported into a software
+	 * context */
+	if (csbcpb->cpb.sha512.message_bit_length_hi ||
+	    csbcpb->cpb.sha512.message_bit_length_lo)
+		memcpy(octx->state, csbcpb->cpb.sha512.message_digest,
+		       SHA512_DIGEST_SIZE);
+	else {
+		octx->state[0] = SHA512_H0;
+		octx->state[1] = SHA512_H1;
+		octx->state[2] = SHA512_H2;
+		octx->state[3] = SHA512_H3;
+		octx->state[4] = SHA512_H4;
+		octx->state[5] = SHA512_H5;
+		octx->state[6] = SHA512_H6;
+		octx->state[7] = SHA512_H7;
+	}
+
+	return 0;
+}
+
+static int nx_sha512_import(struct shash_desc *desc, const void *in)
+{
+	struct sha512_state *sctx = shash_desc_ctx(desc);
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+	struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+	const struct sha512_state *ictx = in;
+
+	memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+	sctx->count[0] = ictx->count[0] & 0x3f;
+	csbcpb->cpb.sha512.message_bit_length_lo = (ictx->count[0] & ~0x3f)
+							<< 3;
+	csbcpb->cpb.sha512.message_bit_length_hi = ictx->count[1] << 3 |
+						   ictx->count[0] >> 61;
+
+	if (csbcpb->cpb.sha512.message_bit_length_hi ||
+	    csbcpb->cpb.sha512.message_bit_length_lo) {
+		memcpy(csbcpb->cpb.sha512.message_digest, ictx->state,
+		       SHA512_DIGEST_SIZE);
+
+		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+		NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+	}
+
+	return 0;
+}
+
+struct shash_alg nx_shash_sha512_alg = {
+	.digestsize = SHA512_DIGEST_SIZE,
+	.init       = nx_sha512_init,
+	.update     = nx_sha512_update,
+	.final      = nx_sha512_final,
+	.export     = nx_sha512_export,
+	.import     = nx_sha512_import,
+	.descsize   = sizeof(struct sha512_state),
+	.statesize  = sizeof(struct sha512_state),
+	.base       = {
+		.cra_name        = "sha512",
+		.cra_driver_name = "sha512-nx",
+		.cra_priority    = 300,
+		.cra_flags       = CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize   = SHA512_BLOCK_SIZE,
+		.cra_module      = THIS_MODULE,
+		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+		.cra_init        = nx_crypto_ctx_sha_init,
+		.cra_exit        = nx_crypto_ctx_exit,
+	}
+};
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
new file mode 100644
index 0000000..d7f179c
--- /dev/null
+++ b/drivers/crypto/nx/nx.c
@@ -0,0 +1,716 @@
+/**
+ * Routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/hash.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <asm/pSeries_reconfig.h>
+#include <asm/abs_addr.h>
+#include <asm/hvcall.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+/**
+ * nx_hcall_sync - make an H_COP_OP hcall for the passed in op structure
+ *
+ * @nx_ctx: the crypto context handle
+ * @op: PFO operation struct to pass in
+ * @may_sleep: flag indicating the request can sleep
+ *
+ * Make the hcall, retrying while the hardware is busy. If we cannot yield
+ * the thread, limit the number of retries to 10 here.
+ */
+int nx_hcall_sync(struct nx_crypto_ctx *nx_ctx,
+		  struct vio_pfo_op    *op,
+		  u32                   may_sleep)
+{
+	int rc, retries = 10;
+	struct vio_dev *viodev = nx_driver.viodev;
+
+	atomic_inc(&(nx_ctx->stats->sync_ops));
+
+	do {
+		rc = vio_h_cop_sync(viodev, op);
+	} while ((rc == -EBUSY && !may_sleep && retries--) ||
+	         (rc == -EBUSY && may_sleep && cond_resched()));
+
+	if (rc) {
+		dev_dbg(&viodev->dev, "vio_h_cop_sync failed: rc: %d "
+			"hcall rc: %ld\n", rc, op->hcall_err);
+		atomic_inc(&(nx_ctx->stats->errors));
+		atomic_set(&(nx_ctx->stats->last_error), op->hcall_err);
+		atomic_set(&(nx_ctx->stats->last_error_pid), current->pid);
+	}
+
+	return rc;
+}
+
+/**
+ * nx_build_sg_list - build an NX scatter list describing a single  buffer
+ *
+ * @sg_head: pointer to the first scatter list element to build
+ * @start_addr: pointer to the linear buffer
+ * @len: length of the data at @start_addr
+ * @sgmax: the largest number of scatter list elements we're allowed to create
+ *
+ * This function will start writing nx_sg elements at @sg_head and keep
+ * writing them until all of the data from @start_addr is described or
+ * until sgmax elements have been written. Scatter list elements will be
+ * created such that none of the elements describes a buffer that crosses a 4K
+ * boundary.
+ */
+struct nx_sg *nx_build_sg_list(struct nx_sg *sg_head,
+			       u8           *start_addr,
+			       unsigned int  len,
+			       u32           sgmax)
+{
+	unsigned int sg_len = 0;
+	struct nx_sg *sg;
+	u64 sg_addr = (u64)start_addr;
+	u64 end_addr;
+
+	/* determine the start and end for this address range - slightly
+	 * different if this is in VMALLOC_REGION */
+	if (is_vmalloc_addr(start_addr))
+		sg_addr = phys_to_abs(page_to_phys(vmalloc_to_page(start_addr)))
+			  + offset_in_page(sg_addr);
+	else
+		sg_addr = virt_to_abs(sg_addr);
+
+	end_addr = sg_addr + len;
+
+	/* each iteration will write one struct nx_sg element and add the
+	 * length of data described by that element to sg_len. Once @len bytes
+	 * have been described (or @sgmax elements have been written), the
+	 * loop ends. min_t is used to ensure @end_addr falls on the same page
+	 * as sg_addr, if not, we need to create another nx_sg element for the
+	 * data on the next page */
+	for (sg = sg_head; sg_len < len; sg++) {
+		sg->addr = sg_addr;
+		sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE), end_addr);
+		sg->len = sg_addr - sg->addr;
+		sg_len += sg->len;
+
+		if ((sg - sg_head) == sgmax) {
+			pr_err("nx: scatter/gather list overflow, pid: %d\n",
+			       current->pid);
+			return NULL;
+		}
+	}
+
+	/* return the moved sg_head pointer */
+	return sg;
+}
+
+/**
+ * nx_walk_and_build - walk a linux scatterlist and build an nx scatterlist
+ *
+ * @nx_dst: pointer to the first nx_sg element to write
+ * @sglen: max number of nx_sg entries we're allowed to write
+ * @sg_src: pointer to the source linux scatterlist to walk
+ * @start: number of bytes to fast-forward past at the beginning of @sg_src
+ * @src_len: number of bytes to walk in @sg_src
+ */
+struct nx_sg *nx_walk_and_build(struct nx_sg       *nx_dst,
+				unsigned int        sglen,
+				struct scatterlist *sg_src,
+				unsigned int        start,
+				unsigned int        src_len)
+{
+	struct scatter_walk walk;
+	struct nx_sg *nx_sg = nx_dst;
+	unsigned int n, offset = 0, len = src_len;
+	char *dst;
+
+	/* we need to fast forward through @start bytes first */
+	for (;;) {
+		scatterwalk_start(&walk, sg_src);
+
+		if (start < offset + sg_src->length)
+			break;
+
+		offset += sg_src->length;
+		sg_src = scatterwalk_sg_next(sg_src);
+	}
+
+	/* start - offset is the number of bytes to advance in the scatterlist
+	 * element we're currently looking at */
+	scatterwalk_advance(&walk, start - offset);
+
+	while (len && nx_sg) {
+		n = scatterwalk_clamp(&walk, len);
+		if (!n) {
+			scatterwalk_start(&walk, sg_next(walk.sg));
+			n = scatterwalk_clamp(&walk, len);
+		}
+		dst = scatterwalk_map(&walk);
+
+		nx_sg = nx_build_sg_list(nx_sg, dst, n, sglen);
+		len -= n;
+
+		scatterwalk_unmap(dst);
+		scatterwalk_advance(&walk, n);
+		scatterwalk_done(&walk, SCATTERWALK_FROM_SG, len);
+	}
+
+	/* return the moved destination pointer */
+	return nx_sg;
+}
+
+/**
+ * nx_build_sg_lists - walk the input scatterlists and build arrays of NX
+ *                     scatterlists based on them.
+ *
+ * @nx_ctx: NX crypto context for the lists we're building
+ * @desc: the block cipher descriptor for the operation
+ * @dst: destination scatterlist
+ * @src: source scatterlist
+ * @nbytes: length of data described in the scatterlists
+ * @iv: destination for the iv data, if the algorithm requires it
+ *
+ * This is common code shared by all the AES algorithms. It uses the block
+ * cipher walk routines to traverse input and output scatterlists, building
+ * corresponding NX scatterlists
+ */
+int nx_build_sg_lists(struct nx_crypto_ctx  *nx_ctx,
+		      struct blkcipher_desc *desc,
+		      struct scatterlist    *dst,
+		      struct scatterlist    *src,
+		      unsigned int           nbytes,
+		      u8                    *iv)
+{
+	struct nx_sg *nx_insg = nx_ctx->in_sg;
+	struct nx_sg *nx_outsg = nx_ctx->out_sg;
+	struct blkcipher_walk walk;
+	int rc;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	rc = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
+	if (rc)
+		goto out;
+
+	if (iv)
+		memcpy(iv, walk.iv, AES_BLOCK_SIZE);
+
+	while (walk.nbytes) {
+		nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
+					   walk.nbytes, nx_ctx->ap->sglen);
+		nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
+					    walk.nbytes, nx_ctx->ap->sglen);
+
+		rc = blkcipher_walk_done(desc, &walk, 0);
+		if (rc)
+			break;
+	}
+
+	if (walk.nbytes) {
+		nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
+					   walk.nbytes, nx_ctx->ap->sglen);
+		nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
+					    walk.nbytes, nx_ctx->ap->sglen);
+
+		rc = 0;
+	}
+
+	/* these lengths should be negative, which will indicate to phyp that
+	 * the input and output parameters are scatterlists, not linear
+	 * buffers */
+	nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) * sizeof(struct nx_sg);
+	nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) * sizeof(struct nx_sg);
+out:
+	return rc;
+}
+
+/**
+ * nx_ctx_init - initialize an nx_ctx's vio_pfo_op struct
+ *
+ * @nx_ctx: the nx context to initialize
+ * @function: the function code for the op
+ */
+void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function)
+{
+	memset(nx_ctx->kmem, 0, nx_ctx->kmem_len);
+	nx_ctx->csbcpb->csb.valid |= NX_CSB_VALID_BIT;
+
+	nx_ctx->op.flags = function;
+	nx_ctx->op.csbcpb = virt_to_abs(nx_ctx->csbcpb);
+	nx_ctx->op.in = virt_to_abs(nx_ctx->in_sg);
+	nx_ctx->op.out = virt_to_abs(nx_ctx->out_sg);
+
+	if (nx_ctx->csbcpb_aead) {
+		nx_ctx->csbcpb_aead->csb.valid |= NX_CSB_VALID_BIT;
+
+		nx_ctx->op_aead.flags = function;
+		nx_ctx->op_aead.csbcpb = virt_to_abs(nx_ctx->csbcpb_aead);
+		nx_ctx->op_aead.in = virt_to_abs(nx_ctx->in_sg);
+		nx_ctx->op_aead.out = virt_to_abs(nx_ctx->out_sg);
+	}
+}
+
+static void nx_of_update_status(struct device   *dev,
+			       struct property *p,
+			       struct nx_of    *props)
+{
+	if (!strncmp(p->value, "okay", p->length)) {
+		props->status = NX_WAITING;
+		props->flags |= NX_OF_FLAG_STATUS_SET;
+	} else {
+		dev_info(dev, "%s: status '%s' is not 'okay'\n", __func__,
+			 (char *)p->value);
+	}
+}
+
+static void nx_of_update_sglen(struct device   *dev,
+			       struct property *p,
+			       struct nx_of    *props)
+{
+	if (p->length != sizeof(props->max_sg_len)) {
+		dev_err(dev, "%s: unexpected format for "
+			"ibm,max-sg-len property\n", __func__);
+		dev_dbg(dev, "%s: ibm,max-sg-len is %d bytes "
+			"long, expected %zd bytes\n", __func__,
+			p->length, sizeof(props->max_sg_len));
+		return;
+	}
+
+	props->max_sg_len = *(u32 *)p->value;
+	props->flags |= NX_OF_FLAG_MAXSGLEN_SET;
+}
+
+static void nx_of_update_msc(struct device   *dev,
+			     struct property *p,
+			     struct nx_of    *props)
+{
+	struct msc_triplet *trip;
+	struct max_sync_cop *msc;
+	unsigned int bytes_so_far, i, lenp;
+
+	msc = (struct max_sync_cop *)p->value;
+	lenp = p->length;
+
+	/* You can't tell if the data read in for this property is sane by its
+	 * size alone. This is because there are sizes embedded in the data
+	 * structure. The best we can do is check lengths as we parse and bail
+	 * as soon as a length error is detected. */
+	bytes_so_far = 0;
+
+	while ((bytes_so_far + sizeof(struct max_sync_cop)) <= lenp) {
+		bytes_so_far += sizeof(struct max_sync_cop);
+
+		trip = msc->trip;
+
+		for (i = 0;
+		     ((bytes_so_far + sizeof(struct msc_triplet)) <= lenp) &&
+		     i < msc->triplets;
+		     i++) {
+			if (msc->fc > NX_MAX_FC || msc->mode > NX_MAX_MODE) {
+				dev_err(dev, "unknown function code/mode "
+					"combo: %d/%d (ignored)\n", msc->fc,
+					msc->mode);
+				goto next_loop;
+			}
+
+			switch (trip->keybitlen) {
+			case 128:
+			case 160:
+				props->ap[msc->fc][msc->mode][0].databytelen =
+					trip->databytelen;
+				props->ap[msc->fc][msc->mode][0].sglen =
+					trip->sglen;
+				break;
+			case 192:
+				props->ap[msc->fc][msc->mode][1].databytelen =
+					trip->databytelen;
+				props->ap[msc->fc][msc->mode][1].sglen =
+					trip->sglen;
+				break;
+			case 256:
+				if (msc->fc == NX_FC_AES) {
+					props->ap[msc->fc][msc->mode][2].
+						databytelen = trip->databytelen;
+					props->ap[msc->fc][msc->mode][2].sglen =
+						trip->sglen;
+				} else if (msc->fc == NX_FC_AES_HMAC ||
+					   msc->fc == NX_FC_SHA) {
+					props->ap[msc->fc][msc->mode][1].
+						databytelen = trip->databytelen;
+					props->ap[msc->fc][msc->mode][1].sglen =
+						trip->sglen;
+				} else {
+					dev_warn(dev, "unknown function "
+						"code/key bit len combo"
+						": (%u/256)\n", msc->fc);
+				}
+				break;
+			case 512:
+				props->ap[msc->fc][msc->mode][2].databytelen =
+					trip->databytelen;
+				props->ap[msc->fc][msc->mode][2].sglen =
+					trip->sglen;
+				break;
+			default:
+				dev_warn(dev, "unknown function code/key bit "
+					 "len combo: (%u/%u)\n", msc->fc,
+					 trip->keybitlen);
+				break;
+			}
+next_loop:
+			bytes_so_far += sizeof(struct msc_triplet);
+			trip++;
+		}
+
+		msc = (struct max_sync_cop *)trip;
+	}
+
+	props->flags |= NX_OF_FLAG_MAXSYNCCOP_SET;
+}
+
+/**
+ * nx_of_init - read openFirmware values from the device tree
+ *
+ * @dev: device handle
+ * @props: pointer to struct to hold the properties values
+ *
+ * Called once at driver probe time, this function will read out the
+ * openFirmware properties we use at runtime. If all the OF properties are
+ * acceptable, when we exit this function props->flags will indicate that
+ * we're ready to register our crypto algorithms.
+ */
+static void nx_of_init(struct device *dev, struct nx_of *props)
+{
+	struct device_node *base_node = dev->of_node;
+	struct property *p;
+
+	p = of_find_property(base_node, "status", NULL);
+	if (!p)
+		dev_info(dev, "%s: property 'status' not found\n", __func__);
+	else
+		nx_of_update_status(dev, p, props);
+
+	p = of_find_property(base_node, "ibm,max-sg-len", NULL);
+	if (!p)
+		dev_info(dev, "%s: property 'ibm,max-sg-len' not found\n",
+			 __func__);
+	else
+		nx_of_update_sglen(dev, p, props);
+
+	p = of_find_property(base_node, "ibm,max-sync-cop", NULL);
+	if (!p)
+		dev_info(dev, "%s: property 'ibm,max-sync-cop' not found\n",
+			 __func__);
+	else
+		nx_of_update_msc(dev, p, props);
+}
+
+/**
+ * nx_register_algs - register algorithms with the crypto API
+ *
+ * Called from nx_probe()
+ *
+ * If all OF properties are in an acceptable state, the driver flags will
+ * indicate that we're ready and we'll create our debugfs files and register
+ * out crypto algorithms.
+ */
+static int nx_register_algs(void)
+{
+	int rc = -1;
+
+	if (nx_driver.of.flags != NX_OF_FLAG_MASK_READY)
+		goto out;
+
+	memset(&nx_driver.stats, 0, sizeof(struct nx_stats));
+
+	rc = NX_DEBUGFS_INIT(&nx_driver);
+	if (rc)
+		goto out;
+
+	rc = crypto_register_alg(&nx_ecb_aes_alg);
+	if (rc)
+		goto out;
+
+	rc = crypto_register_alg(&nx_cbc_aes_alg);
+	if (rc)
+		goto out_unreg_ecb;
+
+	rc = crypto_register_alg(&nx_ctr_aes_alg);
+	if (rc)
+		goto out_unreg_cbc;
+
+	rc = crypto_register_alg(&nx_ctr3686_aes_alg);
+	if (rc)
+		goto out_unreg_ctr;
+
+	rc = crypto_register_alg(&nx_gcm_aes_alg);
+	if (rc)
+		goto out_unreg_ctr3686;
+
+	rc = crypto_register_alg(&nx_gcm4106_aes_alg);
+	if (rc)
+		goto out_unreg_gcm;
+
+	rc = crypto_register_alg(&nx_ccm_aes_alg);
+	if (rc)
+		goto out_unreg_gcm4106;
+
+	rc = crypto_register_alg(&nx_ccm4309_aes_alg);
+	if (rc)
+		goto out_unreg_ccm;
+
+	rc = crypto_register_shash(&nx_shash_sha256_alg);
+	if (rc)
+		goto out_unreg_ccm4309;
+
+	rc = crypto_register_shash(&nx_shash_sha512_alg);
+	if (rc)
+		goto out_unreg_s256;
+
+	rc = crypto_register_shash(&nx_shash_aes_xcbc_alg);
+	if (rc)
+		goto out_unreg_s512;
+
+	nx_driver.of.status = NX_OKAY;
+
+	goto out;
+
+out_unreg_s512:
+	crypto_unregister_shash(&nx_shash_sha512_alg);
+out_unreg_s256:
+	crypto_unregister_shash(&nx_shash_sha256_alg);
+out_unreg_ccm4309:
+	crypto_unregister_alg(&nx_ccm4309_aes_alg);
+out_unreg_ccm:
+	crypto_unregister_alg(&nx_ccm_aes_alg);
+out_unreg_gcm4106:
+	crypto_unregister_alg(&nx_gcm4106_aes_alg);
+out_unreg_gcm:
+	crypto_unregister_alg(&nx_gcm_aes_alg);
+out_unreg_ctr3686:
+	crypto_unregister_alg(&nx_ctr3686_aes_alg);
+out_unreg_ctr:
+	crypto_unregister_alg(&nx_ctr_aes_alg);
+out_unreg_cbc:
+	crypto_unregister_alg(&nx_cbc_aes_alg);
+out_unreg_ecb:
+	crypto_unregister_alg(&nx_ecb_aes_alg);
+out:
+	return rc;
+}
+
+/**
+ * nx_crypto_ctx_init - create and initialize a crypto api context
+ *
+ * @nx_ctx: the crypto api context
+ * @fc: function code for the context
+ * @mode: the function code specific mode for this context
+ */
+static int nx_crypto_ctx_init(struct nx_crypto_ctx *nx_ctx, u32 fc, u32 mode)
+{
+	if (nx_driver.of.status != NX_OKAY) {
+		pr_err("Attempt to initialize NX crypto context while device "
+		       "is not available!\n");
+		return -ENODEV;
+	}
+
+	/* we need an extra page for csbcpb_aead for these modes */
+	if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM)
+		nx_ctx->kmem_len = (4 * NX_PAGE_SIZE) +
+				   sizeof(struct nx_csbcpb);
+	else
+		nx_ctx->kmem_len = (3 * NX_PAGE_SIZE) +
+				   sizeof(struct nx_csbcpb);
+
+	nx_ctx->kmem = kmalloc(nx_ctx->kmem_len, GFP_KERNEL);
+	if (!nx_ctx->kmem)
+		return -ENOMEM;
+
+	/* the csbcpb and scatterlists must be 4K aligned pages */
+	nx_ctx->csbcpb = (struct nx_csbcpb *)(round_up((u64)nx_ctx->kmem,
+						       (u64)NX_PAGE_SIZE));
+	nx_ctx->in_sg = (struct nx_sg *)((u8 *)nx_ctx->csbcpb + NX_PAGE_SIZE);
+	nx_ctx->out_sg = (struct nx_sg *)((u8 *)nx_ctx->in_sg + NX_PAGE_SIZE);
+
+	if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM)
+		nx_ctx->csbcpb_aead =
+			(struct nx_csbcpb *)((u8 *)nx_ctx->out_sg +
+					     NX_PAGE_SIZE);
+
+	/* give each context a pointer to global stats and their OF
+	 * properties */
+	nx_ctx->stats = &nx_driver.stats;
+	memcpy(nx_ctx->props, nx_driver.of.ap[fc][mode],
+	       sizeof(struct alg_props) * 3);
+
+	return 0;
+}
+
+/* entry points from the crypto tfm initializers */
+int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm)
+{
+	return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+				  NX_MODE_AES_CCM);
+}
+
+int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm)
+{
+	return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+				  NX_MODE_AES_GCM);
+}
+
+int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm)
+{
+	return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+				  NX_MODE_AES_CTR);
+}
+
+int nx_crypto_ctx_aes_cbc_init(struct crypto_tfm *tfm)
+{
+	return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+				  NX_MODE_AES_CBC);
+}
+
+int nx_crypto_ctx_aes_ecb_init(struct crypto_tfm *tfm)
+{
+	return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+				  NX_MODE_AES_ECB);
+}
+
+int nx_crypto_ctx_sha_init(struct crypto_tfm *tfm)
+{
+	return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_SHA, NX_MODE_SHA);
+}
+
+int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm)
+{
+	return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+				  NX_MODE_AES_XCBC_MAC);
+}
+
+/**
+ * nx_crypto_ctx_exit - destroy a crypto api context
+ *
+ * @tfm: the crypto transform pointer for the context
+ *
+ * As crypto API contexts are destroyed, this exit hook is called to free the
+ * memory associated with it.
+ */
+void nx_crypto_ctx_exit(struct crypto_tfm *tfm)
+{
+	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+
+	kzfree(nx_ctx->kmem);
+	nx_ctx->csbcpb = NULL;
+	nx_ctx->csbcpb_aead = NULL;
+	nx_ctx->in_sg = NULL;
+	nx_ctx->out_sg = NULL;
+}
+
+static int __devinit nx_probe(struct vio_dev *viodev,
+			      const struct vio_device_id *id)
+{
+	dev_dbg(&viodev->dev, "driver probed: %s resource id: 0x%x\n",
+		viodev->name, viodev->resource_id);
+
+	if (nx_driver.viodev) {
+		dev_err(&viodev->dev, "%s: Attempt to register more than one "
+			"instance of the hardware\n", __func__);
+		return -EINVAL;
+	}
+
+	nx_driver.viodev = viodev;
+
+	nx_of_init(&viodev->dev, &nx_driver.of);
+
+	return nx_register_algs();
+}
+
+static int __devexit nx_remove(struct vio_dev *viodev)
+{
+	dev_dbg(&viodev->dev, "entering nx_remove for UA 0x%x\n",
+		viodev->unit_address);
+
+	if (nx_driver.of.status == NX_OKAY) {
+		NX_DEBUGFS_FINI(&nx_driver);
+
+		crypto_unregister_alg(&nx_ccm_aes_alg);
+		crypto_unregister_alg(&nx_ccm4309_aes_alg);
+		crypto_unregister_alg(&nx_gcm_aes_alg);
+		crypto_unregister_alg(&nx_gcm4106_aes_alg);
+		crypto_unregister_alg(&nx_ctr_aes_alg);
+		crypto_unregister_alg(&nx_ctr3686_aes_alg);
+		crypto_unregister_alg(&nx_cbc_aes_alg);
+		crypto_unregister_alg(&nx_ecb_aes_alg);
+		crypto_unregister_shash(&nx_shash_sha256_alg);
+		crypto_unregister_shash(&nx_shash_sha512_alg);
+		crypto_unregister_shash(&nx_shash_aes_xcbc_alg);
+	}
+
+	return 0;
+}
+
+
+/* module wide initialization/cleanup */
+static int __init nx_init(void)
+{
+	return vio_register_driver(&nx_driver.viodriver);
+}
+
+static void __exit nx_fini(void)
+{
+	vio_unregister_driver(&nx_driver.viodriver);
+}
+
+static struct vio_device_id nx_crypto_driver_ids[] __devinitdata = {
+	{ "ibm,sym-encryption-v1", "ibm,sym-encryption" },
+	{ "", "" }
+};
+MODULE_DEVICE_TABLE(vio, nx_crypto_driver_ids);
+
+/* driver state structure */
+struct nx_crypto_driver nx_driver = {
+	.viodriver = {
+		.id_table = nx_crypto_driver_ids,
+		.probe = nx_probe,
+		.remove = nx_remove,
+		.name  = NX_NAME,
+	},
+};
+
+module_init(nx_init);
+module_exit(nx_fini);
+
+MODULE_AUTHOR("Kent Yoder <yoder1@us.ibm.com>");
+MODULE_DESCRIPTION(NX_STRING);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(NX_VERSION);
diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h
new file mode 100644
index 0000000..3232b18
--- /dev/null
+++ b/drivers/crypto/nx/nx.h
@@ -0,0 +1,193 @@
+
+#ifndef __NX_H__
+#define __NX_H__
+
+#define NX_NAME		"nx-crypto"
+#define NX_STRING	"IBM Power7+ Nest Accelerator Crypto Driver"
+#define NX_VERSION	"1.0"
+
+static const char nx_driver_string[] = NX_STRING;
+static const char nx_driver_version[] = NX_VERSION;
+
+/* a scatterlist in the format PHYP is expecting */
+struct nx_sg {
+	u64 addr;
+	u32 rsvd;
+	u32 len;
+} __attribute((packed));
+
+#define NX_PAGE_SIZE		(4096)
+#define NX_MAX_SG_ENTRIES	(NX_PAGE_SIZE/(sizeof(struct nx_sg)))
+
+enum nx_status {
+	NX_DISABLED,
+	NX_WAITING,
+	NX_OKAY
+};
+
+/* msc_triplet and max_sync_cop are used only to assist in parsing the
+ * openFirmware property */
+struct msc_triplet {
+	u32 keybitlen;
+	u32 databytelen;
+	u32 sglen;
+} __packed;
+
+struct max_sync_cop {
+	u32 fc;
+	u32 mode;
+	u32 triplets;
+	struct msc_triplet trip[0];
+} __packed;
+
+struct alg_props {
+	u32 databytelen;
+	u32 sglen;
+};
+
+#define NX_OF_FLAG_MAXSGLEN_SET		(1)
+#define NX_OF_FLAG_STATUS_SET		(2)
+#define NX_OF_FLAG_MAXSYNCCOP_SET	(4)
+#define NX_OF_FLAG_MASK_READY		(NX_OF_FLAG_MAXSGLEN_SET | \
+					 NX_OF_FLAG_STATUS_SET |   \
+					 NX_OF_FLAG_MAXSYNCCOP_SET)
+struct nx_of {
+	u32 flags;
+	u32 max_sg_len;
+	enum nx_status status;
+	struct alg_props ap[NX_MAX_FC][NX_MAX_MODE][3];
+};
+
+struct nx_stats {
+	atomic_t aes_ops;
+	atomic64_t aes_bytes;
+	atomic_t sha256_ops;
+	atomic64_t sha256_bytes;
+	atomic_t sha512_ops;
+	atomic64_t sha512_bytes;
+
+	atomic_t sync_ops;
+
+	atomic_t errors;
+	atomic_t last_error;
+	atomic_t last_error_pid;
+};
+
+struct nx_debugfs {
+	struct dentry *dfs_root;
+	struct dentry *dfs_aes_ops, *dfs_aes_bytes;
+	struct dentry *dfs_sha256_ops, *dfs_sha256_bytes;
+	struct dentry *dfs_sha512_ops, *dfs_sha512_bytes;
+	struct dentry *dfs_errors, *dfs_last_error, *dfs_last_error_pid;
+};
+
+struct nx_crypto_driver {
+	struct nx_stats    stats;
+	struct nx_of       of;
+	struct vio_dev    *viodev;
+	struct vio_driver  viodriver;
+	struct nx_debugfs  dfs;
+};
+
+#define NX_GCM4106_NONCE_LEN		(4)
+#define NX_GCM_CTR_OFFSET		(12)
+struct nx_gcm_priv {
+	u8 iv[16];
+	u8 iauth_tag[16];
+	u8 nonce[NX_GCM4106_NONCE_LEN];
+};
+
+#define NX_CCM_AES_KEY_LEN		(16)
+#define NX_CCM4309_AES_KEY_LEN		(19)
+#define NX_CCM4309_NONCE_LEN		(3)
+struct nx_ccm_priv {
+	u8 iv[16];
+	u8 b0[16];
+	u8 iauth_tag[16];
+	u8 oauth_tag[16];
+	u8 nonce[NX_CCM4309_NONCE_LEN];
+};
+
+struct nx_xcbc_priv {
+	u8 key[16];
+};
+
+struct nx_ctr_priv {
+	u8 iv[16];
+};
+
+struct nx_crypto_ctx {
+	void *kmem;		  /* unaligned, kmalloc'd buffer */
+	size_t kmem_len;	  /* length of kmem */
+	struct nx_csbcpb *csbcpb; /* aligned page given to phyp @ hcall time */
+	struct vio_pfo_op op;     /* operation struct with hcall parameters */
+	struct nx_csbcpb *csbcpb_aead; /* secondary csbcpb used by AEAD algs */
+	struct vio_pfo_op op_aead;/* operation struct for csbcpb_aead */
+
+	struct nx_sg *in_sg;      /* aligned pointer into kmem to an sg list */
+	struct nx_sg *out_sg;     /* aligned pointer into kmem to an sg list */
+
+	struct alg_props *ap;	  /* pointer into props based on our key size */
+	struct alg_props props[3];/* openFirmware properties for requests */
+	struct nx_stats *stats;   /* pointer into an nx_crypto_driver for stats
+				     reporting */
+
+	union {
+		struct nx_gcm_priv gcm;
+		struct nx_ccm_priv ccm;
+		struct nx_xcbc_priv xcbc;
+		struct nx_ctr_priv ctr;
+	} priv;
+};
+
+/* prototypes */
+int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_cbc_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_ecb_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_sha_init(struct crypto_tfm *tfm);
+void nx_crypto_ctx_exit(struct crypto_tfm *tfm);
+void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function);
+int nx_hcall_sync(struct nx_crypto_ctx *ctx, struct vio_pfo_op *op,
+		  u32 may_sleep);
+struct nx_sg *nx_build_sg_list(struct nx_sg *, u8 *, unsigned int, u32);
+int nx_build_sg_lists(struct nx_crypto_ctx *, struct blkcipher_desc *,
+		      struct scatterlist *, struct scatterlist *, unsigned int,
+		      u8 *);
+struct nx_sg *nx_walk_and_build(struct nx_sg *, unsigned int,
+				struct scatterlist *, unsigned int,
+				unsigned int);
+
+#ifdef CONFIG_DEBUG_FS
+#define NX_DEBUGFS_INIT(drv)	nx_debugfs_init(drv)
+#define NX_DEBUGFS_FINI(drv)	nx_debugfs_fini(drv)
+
+int nx_debugfs_init(struct nx_crypto_driver *);
+void nx_debugfs_fini(struct nx_crypto_driver *);
+#else
+#define NX_DEBUGFS_INIT(drv)	(0)
+#define NX_DEBUGFS_FINI(drv)	(0)
+#endif
+
+#define NX_PAGE_NUM(x)		((u64)(x) & 0xfffffffffffff000ULL)
+
+extern struct crypto_alg nx_cbc_aes_alg;
+extern struct crypto_alg nx_ecb_aes_alg;
+extern struct crypto_alg nx_gcm_aes_alg;
+extern struct crypto_alg nx_gcm4106_aes_alg;
+extern struct crypto_alg nx_ctr_aes_alg;
+extern struct crypto_alg nx_ctr3686_aes_alg;
+extern struct crypto_alg nx_ccm_aes_alg;
+extern struct crypto_alg nx_ccm4309_aes_alg;
+extern struct shash_alg nx_shash_aes_xcbc_alg;
+extern struct shash_alg nx_shash_sha512_alg;
+extern struct shash_alg nx_shash_sha256_alg;
+
+extern struct nx_crypto_driver nx_driver;
+
+#define SCATTERWALK_TO_SG	1
+#define SCATTERWALK_FROM_SG	0
+
+#endif
diff --git a/drivers/crypto/nx/nx_csbcpb.h b/drivers/crypto/nx/nx_csbcpb.h
new file mode 100644
index 0000000..a304f956
--- /dev/null
+++ b/drivers/crypto/nx/nx_csbcpb.h
@@ -0,0 +1,205 @@
+
+#ifndef __NX_CSBCPB_H__
+#define __NX_CSBCPB_H__
+
+struct cop_symcpb_aes_ecb {
+	u8 key[32];
+	u8 __rsvd[80];
+} __packed;
+
+struct cop_symcpb_aes_cbc {
+	u8 iv[16];
+	u8 key[32];
+	u8 cv[16];
+	u32 spbc;
+	u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_gca {
+	u8 in_pat[16];
+	u8 key[32];
+	u8 out_pat[16];
+	u32 spbc;
+	u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_gcm {
+	u8 in_pat_or_aad[16];
+	u8 iv_or_cnt[16];
+	u64 bit_length_aad;
+	u64 bit_length_data;
+	u8 in_s0[16];
+	u8 key[32];
+	u8 __rsvd1[16];
+	u8 out_pat_or_mac[16];
+	u8 out_s0[16];
+	u8 out_cnt[16];
+	u32 spbc;
+	u8 __rsvd2[12];
+} __packed;
+
+struct cop_symcpb_aes_ctr {
+	u8 iv[16];
+	u8 key[32];
+	u8 cv[16];
+	u32 spbc;
+	u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_aes_cca {
+	u8 b0[16];
+	u8 b1[16];
+	u8 key[16];
+	u8 out_pat_or_b0[16];
+	u32 spbc;
+	u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_ccm {
+	u8 in_pat_or_b0[16];
+	u8 iv_or_ctr[16];
+	u8 in_s0[16];
+	u8 key[16];
+	u8 __rsvd1[48];
+	u8 out_pat_or_mac[16];
+	u8 out_s0[16];
+	u8 out_ctr[16];
+	u32 spbc;
+	u8 __rsvd2[12];
+} __packed;
+
+struct cop_symcpb_aes_xcbc {
+	u8 cv[16];
+	u8 key[16];
+	u8 __rsvd1[16];
+	u8 out_cv_mac[16];
+	u32 spbc;
+	u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_sha256 {
+	u64 message_bit_length;
+	u64 __rsvd1;
+	u8 input_partial_digest[32];
+	u8 message_digest[32];
+	u32 spbc;
+	u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_sha512 {
+	u64 message_bit_length_hi;
+	u64 message_bit_length_lo;
+	u8 input_partial_digest[64];
+	u8 __rsvd1[32];
+	u8 message_digest[64];
+	u32 spbc;
+	u8 __rsvd2[76];
+} __packed;
+
+#define NX_FDM_INTERMEDIATE		0x01
+#define NX_FDM_CONTINUATION		0x02
+#define NX_FDM_ENDE_ENCRYPT		0x80
+
+#define NX_CPB_FDM(c)			((c)->cpb.hdr.fdm)
+#define NX_CPB_KS_DS(c)			((c)->cpb.hdr.ks_ds)
+
+#define NX_CPB_KEY_SIZE(c)		(NX_CPB_KS_DS(c) >> 4)
+#define NX_CPB_SET_KEY_SIZE(c, x)	NX_CPB_KS_DS(c) |= ((x) << 4)
+#define NX_CPB_SET_DIGEST_SIZE(c, x)	NX_CPB_KS_DS(c) |= (x)
+
+struct cop_symcpb_header {
+	u8 mode;
+	u8 fdm;
+	u8 ks_ds;
+	u8 pad_byte;
+	u8 __rsvd[12];
+} __packed;
+
+struct cop_parameter_block {
+	struct cop_symcpb_header hdr;
+	union {
+		struct cop_symcpb_aes_ecb  aes_ecb;
+		struct cop_symcpb_aes_cbc  aes_cbc;
+		struct cop_symcpb_aes_gca  aes_gca;
+		struct cop_symcpb_aes_gcm  aes_gcm;
+		struct cop_symcpb_aes_cca  aes_cca;
+		struct cop_symcpb_aes_ccm  aes_ccm;
+		struct cop_symcpb_aes_ctr  aes_ctr;
+		struct cop_symcpb_aes_xcbc aes_xcbc;
+		struct cop_symcpb_sha256   sha256;
+		struct cop_symcpb_sha512   sha512;
+	};
+} __packed;
+
+#define NX_CSB_VALID_BIT	0x80
+
+/* co-processor status block */
+struct cop_status_block {
+	u8 valid;
+	u8 crb_seq_number;
+	u8 completion_code;
+	u8 completion_extension;
+	u32 processed_byte_count;
+	u64 address;
+} __packed;
+
+/* Nest accelerator workbook section 4.4 */
+struct nx_csbcpb {
+	unsigned char __rsvd[112];
+	struct cop_status_block csb;
+	struct cop_parameter_block cpb;
+} __packed;
+
+/* nx_csbcpb related definitions */
+#define NX_MODE_AES_ECB			0
+#define NX_MODE_AES_CBC			1
+#define NX_MODE_AES_GMAC		2
+#define NX_MODE_AES_GCA			3
+#define NX_MODE_AES_GCM			4
+#define NX_MODE_AES_CCA			5
+#define NX_MODE_AES_CCM			6
+#define NX_MODE_AES_CTR			7
+#define NX_MODE_AES_XCBC_MAC		20
+#define NX_MODE_SHA			0
+#define NX_MODE_SHA_HMAC		1
+#define NX_MODE_AES_CBC_HMAC_ETA	8
+#define NX_MODE_AES_CBC_HMAC_ATE	9
+#define NX_MODE_AES_CBC_HMAC_EAA	10
+#define NX_MODE_AES_CTR_HMAC_ETA	12
+#define NX_MODE_AES_CTR_HMAC_ATE	13
+#define NX_MODE_AES_CTR_HMAC_EAA	14
+
+#define NX_FDM_CI_FULL		0
+#define NX_FDM_CI_FIRST		1
+#define NX_FDM_CI_LAST		2
+#define NX_FDM_CI_MIDDLE	3
+
+#define NX_FDM_PR_NONE		0
+#define NX_FDM_PR_PAD		1
+
+#define NX_KS_AES_128		1
+#define NX_KS_AES_192		2
+#define NX_KS_AES_256		3
+
+#define NX_DS_SHA256		2
+#define NX_DS_SHA512		3
+
+#define NX_FC_AES		0
+#define NX_FC_SHA		2
+#define NX_FC_AES_HMAC		6
+
+#define NX_MAX_FC		(NX_FC_AES_HMAC + 1)
+#define NX_MAX_MODE		(NX_MODE_AES_XCBC_MAC + 1)
+
+#define HCOP_FC_AES          NX_FC_AES
+#define HCOP_FC_SHA          NX_FC_SHA
+#define HCOP_FC_AES_HMAC     NX_FC_AES_HMAC
+
+/* indices into the array of algorithm properties */
+#define NX_PROPS_AES_128		0
+#define NX_PROPS_AES_192		1
+#define NX_PROPS_AES_256		2
+#define NX_PROPS_SHA256			1
+#define NX_PROPS_SHA512			2
+
+#endif
diff --git a/drivers/crypto/nx/nx_debugfs.c b/drivers/crypto/nx/nx_debugfs.c
new file mode 100644
index 0000000..7ab2e8d
--- /dev/null
+++ b/drivers/crypto/nx/nx_debugfs.c
@@ -0,0 +1,103 @@
+/**
+ * debugfs routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+/*
+ * debugfs
+ *
+ * For documentation on these attributes, please see:
+ *
+ * Documentation/ABI/testing/debugfs-pfo-nx-crypto
+ */
+
+int nx_debugfs_init(struct nx_crypto_driver *drv)
+{
+	struct nx_debugfs *dfs = &drv->dfs;
+
+	dfs->dfs_root = debugfs_create_dir(NX_NAME, NULL);
+
+	dfs->dfs_aes_ops =
+		debugfs_create_u32("aes_ops",
+				   S_IRUSR | S_IRGRP | S_IROTH,
+				   dfs->dfs_root, (u32 *)&drv->stats.aes_ops);
+	dfs->dfs_sha256_ops =
+		debugfs_create_u32("sha256_ops",
+				   S_IRUSR | S_IRGRP | S_IROTH,
+				   dfs->dfs_root,
+				   (u32 *)&drv->stats.sha256_ops);
+	dfs->dfs_sha512_ops =
+		debugfs_create_u32("sha512_ops",
+				   S_IRUSR | S_IRGRP | S_IROTH,
+				   dfs->dfs_root,
+				   (u32 *)&drv->stats.sha512_ops);
+	dfs->dfs_aes_bytes =
+		debugfs_create_u64("aes_bytes",
+				   S_IRUSR | S_IRGRP | S_IROTH,
+				   dfs->dfs_root,
+				   (u64 *)&drv->stats.aes_bytes);
+	dfs->dfs_sha256_bytes =
+		debugfs_create_u64("sha256_bytes",
+				   S_IRUSR | S_IRGRP | S_IROTH,
+				   dfs->dfs_root,
+				   (u64 *)&drv->stats.sha256_bytes);
+	dfs->dfs_sha512_bytes =
+		debugfs_create_u64("sha512_bytes",
+				   S_IRUSR | S_IRGRP | S_IROTH,
+				   dfs->dfs_root,
+				   (u64 *)&drv->stats.sha512_bytes);
+	dfs->dfs_errors =
+		debugfs_create_u32("errors",
+				   S_IRUSR | S_IRGRP | S_IROTH,
+				   dfs->dfs_root, (u32 *)&drv->stats.errors);
+	dfs->dfs_last_error =
+		debugfs_create_u32("last_error",
+				   S_IRUSR | S_IRGRP | S_IROTH,
+				   dfs->dfs_root,
+				   (u32 *)&drv->stats.last_error);
+	dfs->dfs_last_error_pid =
+		debugfs_create_u32("last_error_pid",
+				   S_IRUSR | S_IRGRP | S_IROTH,
+				   dfs->dfs_root,
+				   (u32 *)&drv->stats.last_error_pid);
+	return 0;
+}
+
+void
+nx_debugfs_fini(struct nx_crypto_driver *drv)
+{
+	debugfs_remove_recursive(drv->dfs.dfs_root);
+}
+
+#endif
diff --git a/drivers/crypto/ux500/Kconfig b/drivers/crypto/ux500/Kconfig
new file mode 100644
index 0000000..b35e5c4
--- /dev/null
+++ b/drivers/crypto/ux500/Kconfig
@@ -0,0 +1,30 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Shujuan Chen (shujuan.chen@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+
+config CRYPTO_DEV_UX500_CRYP
+	tristate "UX500 crypto driver for CRYP block"
+	depends on CRYPTO_DEV_UX500
+	select CRYPTO_DES
+	help
+        This selects the crypto driver for the UX500_CRYP hardware. It supports
+        AES-ECB, CBC and CTR with keys sizes of 128, 192 and 256 bit sizes.
+
+config CRYPTO_DEV_UX500_HASH
+        tristate "UX500 crypto driver for HASH block"
+        depends on CRYPTO_DEV_UX500
+        select CRYPTO_HASH
+        select CRYPTO_HMAC
+        help
+          This selects the hash driver for the UX500_HASH hardware.
+          Depends on UX500/STM DMA if running in DMA mode.
+
+config CRYPTO_DEV_UX500_DEBUG
+	bool "Activate ux500 platform debug-mode for crypto and hash block"
+	depends on CRYPTO_DEV_UX500_CRYP || CRYPTO_DEV_UX500_HASH
+	default n
+	help
+	  Say Y if you want to add debug prints to ux500_hash and
+	  ux500_cryp devices.
diff --git a/drivers/crypto/ux500/Makefile b/drivers/crypto/ux500/Makefile
new file mode 100644
index 0000000..b9a365b
--- /dev/null
+++ b/drivers/crypto/ux500/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Shujuan Chen (shujuan.chen@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_HASH) += hash/
+obj-$(CONFIG_CRYPTO_DEV_UX500_CRYP) += cryp/
diff --git a/drivers/crypto/ux500/cryp/Makefile b/drivers/crypto/ux500/cryp/Makefile
new file mode 100644
index 0000000..e5d362a
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/Makefile
@@ -0,0 +1,13 @@
+#/*
+# * Copyright (C) ST-Ericsson SA 2010
+# * Author: shujuan.chen@stericsson.com for ST-Ericsson.
+# * License terms: GNU General Public License (GPL) version 2  */
+
+ifdef CONFIG_CRYPTO_DEV_UX500_DEBUG
+CFLAGS_cryp_core.o := -DDEBUG -O0
+CFLAGS_cryp.o := -DDEBUG -O0
+CFLAGS_cryp_irq.o := -DDEBUG -O0
+endif
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_CRYP) += ux500_cryp.o
+ux500_cryp-objs :=  cryp.o cryp_irq.o cryp_core.o
diff --git a/drivers/crypto/ux500/cryp/cryp.c b/drivers/crypto/ux500/cryp/cryp.c
new file mode 100644
index 0000000..e208cea
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp.c
@@ -0,0 +1,389 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <mach/hardware.h>
+
+#include "cryp_p.h"
+#include "cryp.h"
+
+/**
+ * cryp_wait_until_done - wait until the device logic is not busy
+ */
+void cryp_wait_until_done(struct cryp_device_data *device_data)
+{
+	while (cryp_is_logic_busy(device_data))
+		cpu_relax();
+}
+
+/**
+ * cryp_check - This routine checks Peripheral and PCell Id
+ * @device_data: Pointer to the device data struct for base address.
+ */
+int cryp_check(struct cryp_device_data *device_data)
+{
+	int peripheralid2 = 0;
+
+	if (NULL == device_data)
+		return -EINVAL;
+
+	peripheralid2 = readl_relaxed(&device_data->base->periphId2);
+
+	if (peripheralid2 != CRYP_PERIPHERAL_ID2_DB8500)
+		return -EPERM;
+
+	/* Check Peripheral and Pcell Id Register for CRYP */
+	if ((CRYP_PERIPHERAL_ID0 ==
+		readl_relaxed(&device_data->base->periphId0))
+	    && (CRYP_PERIPHERAL_ID1 ==
+		    readl_relaxed(&device_data->base->periphId1))
+	    && (CRYP_PERIPHERAL_ID3 ==
+		    readl_relaxed(&device_data->base->periphId3))
+	    && (CRYP_PCELL_ID0 ==
+		    readl_relaxed(&device_data->base->pcellId0))
+	    && (CRYP_PCELL_ID1 ==
+		    readl_relaxed(&device_data->base->pcellId1))
+	    && (CRYP_PCELL_ID2 ==
+		    readl_relaxed(&device_data->base->pcellId2))
+	    && (CRYP_PCELL_ID3 ==
+		    readl_relaxed(&device_data->base->pcellId3))) {
+		return 0;
+	}
+
+	return -EPERM;
+}
+
+/**
+ * cryp_activity - This routine enables/disable the cryptography function.
+ * @device_data: Pointer to the device data struct for base address.
+ * @cryp_crypen: Enable/Disable functionality
+ */
+void cryp_activity(struct cryp_device_data *device_data,
+		   enum cryp_crypen cryp_crypen)
+{
+	CRYP_PUT_BITS(&device_data->base->cr,
+		      cryp_crypen,
+		      CRYP_CR_CRYPEN_POS,
+		      CRYP_CR_CRYPEN_MASK);
+}
+
+/**
+ * cryp_flush_inoutfifo - Resets both the input and the output FIFOs
+ * @device_data: Pointer to the device data struct for base address.
+ */
+void cryp_flush_inoutfifo(struct cryp_device_data *device_data)
+{
+	/*
+	 * We always need to disble the hardware before trying to flush the
+	 * FIFO. This is something that isn't written in the design
+	 * specification, but we have been informed by the hardware designers
+	 * that this must be done.
+	 */
+	cryp_activity(device_data, CRYP_CRYPEN_DISABLE);
+	cryp_wait_until_done(device_data);
+
+	CRYP_SET_BITS(&device_data->base->cr, CRYP_CR_FFLUSH_MASK);
+	/*
+	 * CRYP_SR_INFIFO_READY_MASK is the expected value on the status
+	 * register when starting a new calculation, which means Input FIFO is
+	 * not full and input FIFO is empty.
+	 */
+	while (readl_relaxed(&device_data->base->sr) !=
+	       CRYP_SR_INFIFO_READY_MASK)
+		cpu_relax();
+}
+
+/**
+ * cryp_set_configuration - This routine set the cr CRYP IP
+ * @device_data: Pointer to the device data struct for base address.
+ * @cryp_config: Pointer to the configuration parameter
+ * @control_register: The control register to be written later on.
+ */
+int cryp_set_configuration(struct cryp_device_data *device_data,
+			   struct cryp_config *cryp_config,
+			   u32 *control_register)
+{
+	u32 cr_for_kse;
+
+	if (NULL == device_data || NULL == cryp_config)
+		return -EINVAL;
+
+	*control_register |= (cryp_config->keysize << CRYP_CR_KEYSIZE_POS);
+
+	/* Prepare key for decryption in AES_ECB and AES_CBC mode. */
+	if ((CRYP_ALGORITHM_DECRYPT == cryp_config->algodir) &&
+	    ((CRYP_ALGO_AES_ECB == cryp_config->algomode) ||
+	     (CRYP_ALGO_AES_CBC == cryp_config->algomode))) {
+		cr_for_kse = *control_register;
+		/*
+		 * This seems a bit odd, but it is indeed needed to set this to
+		 * encrypt even though it is a decryption that we are doing. It
+		 * also mentioned in the design spec that you need to do this.
+		 * After the keyprepartion for decrypting is done you should set
+		 * algodir back to decryption, which is done outside this if
+		 * statement.
+		 *
+		 * According to design specification we should set mode ECB
+		 * during key preparation even though we might be running CBC
+		 * when enter this function.
+		 *
+		 * Writing to KSE_ENABLED will drop CRYPEN when key preparation
+		 * is done. Therefore we need to set CRYPEN again outside this
+		 * if statement when running decryption.
+		 */
+		cr_for_kse |= ((CRYP_ALGORITHM_ENCRYPT << CRYP_CR_ALGODIR_POS) |
+			       (CRYP_ALGO_AES_ECB << CRYP_CR_ALGOMODE_POS) |
+			       (CRYP_CRYPEN_ENABLE << CRYP_CR_CRYPEN_POS) |
+			       (KSE_ENABLED << CRYP_CR_KSE_POS));
+
+		writel_relaxed(cr_for_kse, &device_data->base->cr);
+		cryp_wait_until_done(device_data);
+	}
+
+	*control_register |=
+		((cryp_config->algomode << CRYP_CR_ALGOMODE_POS) |
+		 (cryp_config->algodir << CRYP_CR_ALGODIR_POS));
+
+	return 0;
+}
+
+/**
+ * cryp_configure_protection - set the protection bits in the CRYP logic.
+ * @device_data: Pointer to the device data struct for base address.
+ * @p_protect_config:	Pointer to the protection mode and
+ *			secure mode configuration
+ */
+int cryp_configure_protection(struct cryp_device_data *device_data,
+			      struct cryp_protection_config *p_protect_config)
+{
+	if (NULL == p_protect_config)
+		return -EINVAL;
+
+	CRYP_WRITE_BIT(&device_data->base->cr,
+		       (u32) p_protect_config->secure_access,
+		       CRYP_CR_SECURE_MASK);
+	CRYP_PUT_BITS(&device_data->base->cr,
+		      p_protect_config->privilege_access,
+		      CRYP_CR_PRLG_POS,
+		      CRYP_CR_PRLG_MASK);
+
+	return 0;
+}
+
+/**
+ * cryp_is_logic_busy - returns the busy status of the CRYP logic
+ * @device_data: Pointer to the device data struct for base address.
+ */
+int cryp_is_logic_busy(struct cryp_device_data *device_data)
+{
+	return CRYP_TEST_BITS(&device_data->base->sr,
+			      CRYP_SR_BUSY_MASK);
+}
+
+/**
+ * cryp_configure_for_dma - configures the CRYP IP for DMA operation
+ * @device_data: Pointer to the device data struct for base address.
+ * @dma_req: Specifies the DMA request type value.
+ */
+void cryp_configure_for_dma(struct cryp_device_data *device_data,
+			    enum cryp_dma_req_type dma_req)
+{
+	CRYP_SET_BITS(&device_data->base->dmacr,
+		      (u32) dma_req);
+}
+
+/**
+ * cryp_configure_key_values - configures the key values for CRYP operations
+ * @device_data: Pointer to the device data struct for base address.
+ * @key_reg_index: Key value index register
+ * @key_value: The key value struct
+ */
+int cryp_configure_key_values(struct cryp_device_data *device_data,
+			      enum cryp_key_reg_index key_reg_index,
+			      struct cryp_key_value key_value)
+{
+	while (cryp_is_logic_busy(device_data))
+		cpu_relax();
+
+	switch (key_reg_index) {
+	case CRYP_KEY_REG_1:
+		writel_relaxed(key_value.key_value_left,
+				&device_data->base->key_1_l);
+		writel_relaxed(key_value.key_value_right,
+				&device_data->base->key_1_r);
+		break;
+	case CRYP_KEY_REG_2:
+		writel_relaxed(key_value.key_value_left,
+				&device_data->base->key_2_l);
+		writel_relaxed(key_value.key_value_right,
+				&device_data->base->key_2_r);
+		break;
+	case CRYP_KEY_REG_3:
+		writel_relaxed(key_value.key_value_left,
+				&device_data->base->key_3_l);
+		writel_relaxed(key_value.key_value_right,
+				&device_data->base->key_3_r);
+		break;
+	case CRYP_KEY_REG_4:
+		writel_relaxed(key_value.key_value_left,
+				&device_data->base->key_4_l);
+		writel_relaxed(key_value.key_value_right,
+				&device_data->base->key_4_r);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * cryp_configure_init_vector - configures the initialization vector register
+ * @device_data: Pointer to the device data struct for base address.
+ * @init_vector_index: Specifies the index of the init vector.
+ * @init_vector_value: Specifies the value for the init vector.
+ */
+int cryp_configure_init_vector(struct cryp_device_data *device_data,
+			       enum cryp_init_vector_index
+			       init_vector_index,
+			       struct cryp_init_vector_value
+			       init_vector_value)
+{
+	while (cryp_is_logic_busy(device_data))
+		cpu_relax();
+
+	switch (init_vector_index) {
+	case CRYP_INIT_VECTOR_INDEX_0:
+		writel_relaxed(init_vector_value.init_value_left,
+		       &device_data->base->init_vect_0_l);
+		writel_relaxed(init_vector_value.init_value_right,
+		       &device_data->base->init_vect_0_r);
+		break;
+	case CRYP_INIT_VECTOR_INDEX_1:
+		writel_relaxed(init_vector_value.init_value_left,
+		       &device_data->base->init_vect_1_l);
+		writel_relaxed(init_vector_value.init_value_right,
+		       &device_data->base->init_vect_1_r);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * cryp_save_device_context -	Store hardware registers and
+ *				other device context parameter
+ * @device_data: Pointer to the device data struct for base address.
+ * @ctx: Crypto device context
+ */
+void cryp_save_device_context(struct cryp_device_data *device_data,
+			      struct cryp_device_context *ctx,
+			      int cryp_mode)
+{
+	enum cryp_algo_mode algomode;
+	struct cryp_register *src_reg = device_data->base;
+	struct cryp_config *config =
+		(struct cryp_config *)device_data->current_ctx;
+
+	/*
+	 * Always start by disable the hardware and wait for it to finish the
+	 * ongoing calculations before trying to reprogram it.
+	 */
+	cryp_activity(device_data, CRYP_CRYPEN_DISABLE);
+	cryp_wait_until_done(device_data);
+
+	if (cryp_mode == CRYP_MODE_DMA)
+		cryp_configure_for_dma(device_data, CRYP_DMA_DISABLE_BOTH);
+
+	if (CRYP_TEST_BITS(&src_reg->sr, CRYP_SR_IFEM_MASK) == 0)
+		ctx->din = readl_relaxed(&src_reg->din);
+
+	ctx->cr = readl_relaxed(&src_reg->cr) & CRYP_CR_CONTEXT_SAVE_MASK;
+
+	switch (config->keysize) {
+	case CRYP_KEY_SIZE_256:
+		ctx->key_4_l = readl_relaxed(&src_reg->key_4_l);
+		ctx->key_4_r = readl_relaxed(&src_reg->key_4_r);
+
+	case CRYP_KEY_SIZE_192:
+		ctx->key_3_l = readl_relaxed(&src_reg->key_3_l);
+		ctx->key_3_r = readl_relaxed(&src_reg->key_3_r);
+
+	case CRYP_KEY_SIZE_128:
+		ctx->key_2_l = readl_relaxed(&src_reg->key_2_l);
+		ctx->key_2_r = readl_relaxed(&src_reg->key_2_r);
+
+	default:
+		ctx->key_1_l = readl_relaxed(&src_reg->key_1_l);
+		ctx->key_1_r = readl_relaxed(&src_reg->key_1_r);
+	}
+
+	/* Save IV for CBC mode for both AES and DES. */
+	algomode = ((ctx->cr & CRYP_CR_ALGOMODE_MASK) >> CRYP_CR_ALGOMODE_POS);
+	if (algomode == CRYP_ALGO_TDES_CBC ||
+	    algomode == CRYP_ALGO_DES_CBC ||
+	    algomode == CRYP_ALGO_AES_CBC) {
+		ctx->init_vect_0_l = readl_relaxed(&src_reg->init_vect_0_l);
+		ctx->init_vect_0_r = readl_relaxed(&src_reg->init_vect_0_r);
+		ctx->init_vect_1_l = readl_relaxed(&src_reg->init_vect_1_l);
+		ctx->init_vect_1_r = readl_relaxed(&src_reg->init_vect_1_r);
+	}
+}
+
+/**
+ * cryp_restore_device_context -	Restore hardware registers and
+ *					other device context parameter
+ * @device_data: Pointer to the device data struct for base address.
+ * @ctx: Crypto device context
+ */
+void cryp_restore_device_context(struct cryp_device_data *device_data,
+				 struct cryp_device_context *ctx)
+{
+	struct cryp_register *reg = device_data->base;
+	struct cryp_config *config =
+		(struct cryp_config *)device_data->current_ctx;
+
+	/*
+	 * Fall through for all items in switch statement. DES is captured in
+	 * the default.
+	 */
+	switch (config->keysize) {
+	case CRYP_KEY_SIZE_256:
+		writel_relaxed(ctx->key_4_l, &reg->key_4_l);
+		writel_relaxed(ctx->key_4_r, &reg->key_4_r);
+
+	case CRYP_KEY_SIZE_192:
+		writel_relaxed(ctx->key_3_l, &reg->key_3_l);
+		writel_relaxed(ctx->key_3_r, &reg->key_3_r);
+
+	case CRYP_KEY_SIZE_128:
+		writel_relaxed(ctx->key_2_l, &reg->key_2_l);
+		writel_relaxed(ctx->key_2_r, &reg->key_2_r);
+
+	default:
+		writel_relaxed(ctx->key_1_l, &reg->key_1_l);
+		writel_relaxed(ctx->key_1_r, &reg->key_1_r);
+	}
+
+	/* Restore IV for CBC mode for AES and DES. */
+	if (config->algomode == CRYP_ALGO_TDES_CBC ||
+	    config->algomode == CRYP_ALGO_DES_CBC ||
+	    config->algomode == CRYP_ALGO_AES_CBC) {
+		writel_relaxed(ctx->init_vect_0_l, &reg->init_vect_0_l);
+		writel_relaxed(ctx->init_vect_0_r, &reg->init_vect_0_r);
+		writel_relaxed(ctx->init_vect_1_l, &reg->init_vect_1_l);
+		writel_relaxed(ctx->init_vect_1_r, &reg->init_vect_1_r);
+	}
+}
diff --git a/drivers/crypto/ux500/cryp/cryp.h b/drivers/crypto/ux500/cryp/cryp.h
new file mode 100644
index 0000000..14cfd05
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp.h
@@ -0,0 +1,308 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _CRYP_H_
+#define _CRYP_H_
+
+#include <linux/completion.h>
+#include <linux/dmaengine.h>
+#include <linux/klist.h>
+#include <linux/mutex.h>
+
+#define DEV_DBG_NAME "crypX crypX:"
+
+/* CRYP enable/disable */
+enum cryp_crypen {
+	CRYP_CRYPEN_DISABLE = 0,
+	CRYP_CRYPEN_ENABLE = 1
+};
+
+/* CRYP Start Computation enable/disable */
+enum cryp_start {
+	CRYP_START_DISABLE = 0,
+	CRYP_START_ENABLE = 1
+};
+
+/* CRYP Init Signal enable/disable */
+enum cryp_init {
+	CRYP_INIT_DISABLE = 0,
+	CRYP_INIT_ENABLE = 1
+};
+
+/* Cryp State enable/disable */
+enum cryp_state {
+	CRYP_STATE_DISABLE = 0,
+	CRYP_STATE_ENABLE = 1
+};
+
+/* Key preparation bit enable */
+enum cryp_key_prep {
+	KSE_DISABLED = 0,
+	KSE_ENABLED = 1
+};
+
+/* Key size for AES */
+#define	CRYP_KEY_SIZE_128 (0)
+#define	CRYP_KEY_SIZE_192 (1)
+#define	CRYP_KEY_SIZE_256 (2)
+
+/* AES modes */
+enum cryp_algo_mode {
+	CRYP_ALGO_TDES_ECB,
+	CRYP_ALGO_TDES_CBC,
+	CRYP_ALGO_DES_ECB,
+	CRYP_ALGO_DES_CBC,
+	CRYP_ALGO_AES_ECB,
+	CRYP_ALGO_AES_CBC,
+	CRYP_ALGO_AES_CTR,
+	CRYP_ALGO_AES_XTS
+};
+
+/* Cryp Encryption or Decryption */
+enum cryp_algorithm_dir {
+	CRYP_ALGORITHM_ENCRYPT,
+	CRYP_ALGORITHM_DECRYPT
+};
+
+/* Hardware access method */
+enum cryp_mode {
+	CRYP_MODE_POLLING,
+	CRYP_MODE_INTERRUPT,
+	CRYP_MODE_DMA
+};
+
+/**
+ * struct cryp_config -
+ * @keysize: Key size for AES
+ * @algomode: AES modes
+ * @algodir: Cryp Encryption or Decryption
+ *
+ * CRYP configuration structure to be passed to set configuration
+ */
+struct cryp_config {
+	int keysize;
+	enum cryp_algo_mode algomode;
+	enum cryp_algorithm_dir algodir;
+};
+
+/**
+ * struct cryp_protection_config -
+ * @privilege_access: Privileged cryp state enable/disable
+ * @secure_access: Secure cryp state enable/disable
+ *
+ * Protection configuration structure for setting privilage access
+ */
+struct cryp_protection_config {
+	enum cryp_state privilege_access;
+	enum cryp_state secure_access;
+};
+
+/* Cryp status */
+enum cryp_status_id {
+	CRYP_STATUS_BUSY = 0x10,
+	CRYP_STATUS_OUTPUT_FIFO_FULL = 0x08,
+	CRYP_STATUS_OUTPUT_FIFO_NOT_EMPTY = 0x04,
+	CRYP_STATUS_INPUT_FIFO_NOT_FULL = 0x02,
+	CRYP_STATUS_INPUT_FIFO_EMPTY = 0x01
+};
+
+/* Cryp DMA interface */
+enum cryp_dma_req_type {
+	CRYP_DMA_DISABLE_BOTH,
+	CRYP_DMA_ENABLE_IN_DATA,
+	CRYP_DMA_ENABLE_OUT_DATA,
+	CRYP_DMA_ENABLE_BOTH_DIRECTIONS
+};
+
+enum cryp_dma_channel {
+	CRYP_DMA_RX = 0,
+	CRYP_DMA_TX
+};
+
+/* Key registers */
+enum cryp_key_reg_index {
+	CRYP_KEY_REG_1,
+	CRYP_KEY_REG_2,
+	CRYP_KEY_REG_3,
+	CRYP_KEY_REG_4
+};
+
+/* Key register left and right */
+struct cryp_key_value {
+	u32 key_value_left;
+	u32 key_value_right;
+};
+
+/* Cryp Initialization structure */
+enum cryp_init_vector_index {
+	CRYP_INIT_VECTOR_INDEX_0,
+	CRYP_INIT_VECTOR_INDEX_1
+};
+
+/* struct cryp_init_vector_value -
+ * @init_value_left
+ * @init_value_right
+ * */
+struct cryp_init_vector_value {
+	u32 init_value_left;
+	u32 init_value_right;
+};
+
+/**
+ * struct cryp_device_context - structure for a cryp context.
+ * @cr: control register
+ * @dmacr: DMA control register
+ * @imsc: Interrupt mask set/clear register
+ * @key_1_l: Key 1l register
+ * @key_1_r: Key 1r register
+ * @key_2_l: Key 2l register
+ * @key_2_r: Key 2r register
+ * @key_3_l: Key 3l register
+ * @key_3_r: Key 3r register
+ * @key_4_l: Key 4l register
+ * @key_4_r: Key 4r register
+ * @init_vect_0_l: Initialization vector 0l register
+ * @init_vect_0_r: Initialization vector 0r register
+ * @init_vect_1_l: Initialization vector 1l register
+ * @init_vect_1_r: Initialization vector 0r register
+ * @din: Data in register
+ * @dout: Data out register
+ *
+ * CRYP power management specifc structure.
+ */
+struct cryp_device_context {
+	u32 cr;
+	u32 dmacr;
+	u32 imsc;
+
+	u32 key_1_l;
+	u32 key_1_r;
+	u32 key_2_l;
+	u32 key_2_r;
+	u32 key_3_l;
+	u32 key_3_r;
+	u32 key_4_l;
+	u32 key_4_r;
+
+	u32 init_vect_0_l;
+	u32 init_vect_0_r;
+	u32 init_vect_1_l;
+	u32 init_vect_1_r;
+
+	u32 din;
+	u32 dout;
+};
+
+struct cryp_dma {
+	dma_cap_mask_t mask;
+	struct completion cryp_dma_complete;
+	struct dma_chan *chan_cryp2mem;
+	struct dma_chan *chan_mem2cryp;
+	struct stedma40_chan_cfg *cfg_cryp2mem;
+	struct stedma40_chan_cfg *cfg_mem2cryp;
+	int sg_src_len;
+	int sg_dst_len;
+	struct scatterlist *sg_src;
+	struct scatterlist *sg_dst;
+	int nents_src;
+	int nents_dst;
+};
+
+/**
+ * struct cryp_device_data - structure for a cryp device.
+ * @base: Pointer to the hardware base address.
+ * @dev: Pointer to the devices dev structure.
+ * @clk: Pointer to the device's clock control.
+ * @pwr_regulator: Pointer to the device's power control.
+ * @power_status: Current status of the power.
+ * @ctx_lock: Lock for current_ctx.
+ * @current_ctx: Pointer to the currently allocated context.
+ * @list_node: For inclusion into a klist.
+ * @dma: The dma structure holding channel configuration.
+ * @power_state: TRUE = power state on, FALSE = power state off.
+ * @power_state_spinlock: Spinlock for power_state.
+ * @restore_dev_ctx: TRUE = saved ctx, FALSE = no saved ctx.
+ */
+struct cryp_device_data {
+	struct cryp_register __iomem *base;
+	struct device *dev;
+	struct clk *clk;
+	struct regulator *pwr_regulator;
+	int power_status;
+	struct spinlock ctx_lock;
+	struct cryp_ctx *current_ctx;
+	struct klist_node list_node;
+	struct cryp_dma dma;
+	bool power_state;
+	struct spinlock power_state_spinlock;
+	bool restore_dev_ctx;
+};
+
+void cryp_wait_until_done(struct cryp_device_data *device_data);
+
+/* Initialization functions */
+
+int cryp_check(struct cryp_device_data *device_data);
+
+void cryp_activity(struct cryp_device_data *device_data,
+		   enum cryp_crypen cryp_crypen);
+
+void cryp_flush_inoutfifo(struct cryp_device_data *device_data);
+
+int cryp_set_configuration(struct cryp_device_data *device_data,
+			   struct cryp_config *cryp_config,
+			   u32 *control_register);
+
+void cryp_configure_for_dma(struct cryp_device_data *device_data,
+			    enum cryp_dma_req_type dma_req);
+
+int cryp_configure_key_values(struct cryp_device_data *device_data,
+			      enum cryp_key_reg_index key_reg_index,
+			      struct cryp_key_value key_value);
+
+int cryp_configure_init_vector(struct cryp_device_data *device_data,
+			       enum cryp_init_vector_index
+			       init_vector_index,
+			       struct cryp_init_vector_value
+			       init_vector_value);
+
+int cryp_configure_protection(struct cryp_device_data *device_data,
+			      struct cryp_protection_config *p_protect_config);
+
+/* Power management funtions */
+void cryp_save_device_context(struct cryp_device_data *device_data,
+			      struct cryp_device_context *ctx,
+			      int cryp_mode);
+
+void cryp_restore_device_context(struct cryp_device_data *device_data,
+				 struct cryp_device_context *ctx);
+
+/* Data transfer and status bits. */
+int cryp_is_logic_busy(struct cryp_device_data *device_data);
+
+int cryp_get_status(struct cryp_device_data *device_data);
+
+/**
+ * cryp_write_indata - This routine writes 32 bit data into the data input
+ *		       register of the cryptography IP.
+ * @device_data: Pointer to the device data struct for base address.
+ * @write_data: Data to write.
+ */
+int cryp_write_indata(struct cryp_device_data *device_data, u32 write_data);
+
+/**
+ * cryp_read_outdata - This routine reads the data from the data output
+ *		       register of the CRYP logic
+ * @device_data: Pointer to the device data struct for base address.
+ * @read_data: Read the data from the output FIFO.
+ */
+int cryp_read_outdata(struct cryp_device_data *device_data, u32 *read_data);
+
+#endif /* _CRYP_H_ */
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
new file mode 100644
index 0000000..7cac127
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -0,0 +1,1784 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Andreas Westin <andreas.westin@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/crypto.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/klist.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/semaphore.h>
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/ctr.h>
+#include <crypto/des.h>
+#include <crypto/scatterwalk.h>
+
+#include <plat/ste_dma40.h>
+
+#include <mach/crypto-ux500.h>
+#include <mach/hardware.h>
+
+#include "cryp_p.h"
+#include "cryp.h"
+
+#define CRYP_MAX_KEY_SIZE	32
+#define BYTES_PER_WORD		4
+
+static int cryp_mode;
+static atomic_t session_id;
+
+static struct stedma40_chan_cfg *mem_to_engine;
+static struct stedma40_chan_cfg *engine_to_mem;
+
+/**
+ * struct cryp_driver_data - data specific to the driver.
+ *
+ * @device_list: A list of registered devices to choose from.
+ * @device_allocation: A semaphore initialized with number of devices.
+ */
+struct cryp_driver_data {
+	struct klist device_list;
+	struct semaphore device_allocation;
+};
+
+/**
+ * struct cryp_ctx - Crypto context
+ * @config: Crypto mode.
+ * @key[CRYP_MAX_KEY_SIZE]: Key.
+ * @keylen: Length of key.
+ * @iv: Pointer to initialization vector.
+ * @indata: Pointer to indata.
+ * @outdata: Pointer to outdata.
+ * @datalen: Length of indata.
+ * @outlen: Length of outdata.
+ * @blocksize: Size of blocks.
+ * @updated: Updated flag.
+ * @dev_ctx: Device dependent context.
+ * @device: Pointer to the device.
+ */
+struct cryp_ctx {
+	struct cryp_config config;
+	u8 key[CRYP_MAX_KEY_SIZE];
+	u32 keylen;
+	u8 *iv;
+	const u8 *indata;
+	u8 *outdata;
+	u32 datalen;
+	u32 outlen;
+	u32 blocksize;
+	u8 updated;
+	struct cryp_device_context dev_ctx;
+	struct cryp_device_data *device;
+	u32 session_id;
+};
+
+static struct cryp_driver_data driver_data;
+
+/**
+ * uint8p_to_uint32_be - 4*uint8 to uint32 big endian
+ * @in: Data to convert.
+ */
+static inline u32 uint8p_to_uint32_be(u8 *in)
+{
+	u32 *data = (u32 *)in;
+
+	return cpu_to_be32p(data);
+}
+
+/**
+ * swap_bits_in_byte - mirror the bits in a byte
+ * @b: the byte to be mirrored
+ *
+ * The bits are swapped the following way:
+ *  Byte b include bits 0-7, nibble 1 (n1) include bits 0-3 and
+ *  nibble 2 (n2) bits 4-7.
+ *
+ *  Nibble 1 (n1):
+ *  (The "old" (moved) bit is replaced with a zero)
+ *  1. Move bit 6 and 7, 4 positions to the left.
+ *  2. Move bit 3 and 5, 2 positions to the left.
+ *  3. Move bit 1-4, 1 position to the left.
+ *
+ *  Nibble 2 (n2):
+ *  1. Move bit 0 and 1, 4 positions to the right.
+ *  2. Move bit 2 and 4, 2 positions to the right.
+ *  3. Move bit 3-6, 1 position to the right.
+ *
+ *  Combine the two nibbles to a complete and swapped byte.
+ */
+
+static inline u8 swap_bits_in_byte(u8 b)
+{
+#define R_SHIFT_4_MASK  0xc0 /* Bits 6 and 7, right shift 4 */
+#define R_SHIFT_2_MASK  0x28 /* (After right shift 4) Bits 3 and 5,
+				  right shift 2 */
+#define R_SHIFT_1_MASK  0x1e /* (After right shift 2) Bits 1-4,
+				  right shift 1 */
+#define L_SHIFT_4_MASK  0x03 /* Bits 0 and 1, left shift 4 */
+#define L_SHIFT_2_MASK  0x14 /* (After left shift 4) Bits 2 and 4,
+				  left shift 2 */
+#define L_SHIFT_1_MASK  0x78 /* (After left shift 1) Bits 3-6,
+				  left shift 1 */
+
+	u8 n1;
+	u8 n2;
+
+	/* Swap most significant nibble */
+	/* Right shift 4, bits 6 and 7 */
+	n1 = ((b  & R_SHIFT_4_MASK) >> 4) | (b  & ~(R_SHIFT_4_MASK >> 4));
+	/* Right shift 2, bits 3 and 5 */
+	n1 = ((n1 & R_SHIFT_2_MASK) >> 2) | (n1 & ~(R_SHIFT_2_MASK >> 2));
+	/* Right shift 1, bits 1-4 */
+	n1 = (n1  & R_SHIFT_1_MASK) >> 1;
+
+	/* Swap least significant nibble */
+	/* Left shift 4, bits 0 and 1 */
+	n2 = ((b  & L_SHIFT_4_MASK) << 4) | (b  & ~(L_SHIFT_4_MASK << 4));
+	/* Left shift 2, bits 2 and 4 */
+	n2 = ((n2 & L_SHIFT_2_MASK) << 2) | (n2 & ~(L_SHIFT_2_MASK << 2));
+	/* Left shift 1, bits 3-6 */
+	n2 = (n2  & L_SHIFT_1_MASK) << 1;
+
+	return n1 | n2;
+}
+
+static inline void swap_words_in_key_and_bits_in_byte(const u8 *in,
+						      u8 *out, u32 len)
+{
+	unsigned int i = 0;
+	int j;
+	int index = 0;
+
+	j = len - BYTES_PER_WORD;
+	while (j >= 0) {
+		for (i = 0; i < BYTES_PER_WORD; i++) {
+			index = len - j - BYTES_PER_WORD + i;
+			out[j + i] =
+				swap_bits_in_byte(in[index]);
+		}
+		j -= BYTES_PER_WORD;
+	}
+}
+
+static void add_session_id(struct cryp_ctx *ctx)
+{
+	/*
+	 * We never want 0 to be a valid value, since this is the default value
+	 * for the software context.
+	 */
+	if (unlikely(atomic_inc_and_test(&session_id)))
+		atomic_inc(&session_id);
+
+	ctx->session_id = atomic_read(&session_id);
+}
+
+static irqreturn_t cryp_interrupt_handler(int irq, void *param)
+{
+	struct cryp_ctx *ctx;
+	int i;
+	struct cryp_device_data *device_data;
+
+	if (param == NULL) {
+		BUG_ON(!param);
+		return IRQ_HANDLED;
+	}
+
+	/* The device is coming from the one found in hw_crypt_noxts. */
+	device_data = (struct cryp_device_data *)param;
+
+	ctx = device_data->current_ctx;
+
+	if (ctx == NULL) {
+		BUG_ON(!ctx);
+		return IRQ_HANDLED;
+	}
+
+	dev_dbg(ctx->device->dev, "[%s] (len: %d) %s, ", __func__, ctx->outlen,
+		cryp_pending_irq_src(device_data, CRYP_IRQ_SRC_OUTPUT_FIFO) ?
+		"out" : "in");
+
+	if (cryp_pending_irq_src(device_data,
+				 CRYP_IRQ_SRC_OUTPUT_FIFO)) {
+		if (ctx->outlen / ctx->blocksize > 0) {
+			for (i = 0; i < ctx->blocksize / 4; i++) {
+				*(ctx->outdata) = readl_relaxed(
+						&device_data->base->dout);
+				ctx->outdata += 4;
+				ctx->outlen -= 4;
+			}
+
+			if (ctx->outlen == 0) {
+				cryp_disable_irq_src(device_data,
+						     CRYP_IRQ_SRC_OUTPUT_FIFO);
+			}
+		}
+	} else if (cryp_pending_irq_src(device_data,
+					CRYP_IRQ_SRC_INPUT_FIFO)) {
+		if (ctx->datalen / ctx->blocksize > 0) {
+			for (i = 0 ; i < ctx->blocksize / 4; i++) {
+				writel_relaxed(ctx->indata,
+						&device_data->base->din);
+				ctx->indata += 4;
+				ctx->datalen -= 4;
+			}
+
+			if (ctx->datalen == 0)
+				cryp_disable_irq_src(device_data,
+						   CRYP_IRQ_SRC_INPUT_FIFO);
+
+			if (ctx->config.algomode == CRYP_ALGO_AES_XTS) {
+				CRYP_PUT_BITS(&device_data->base->cr,
+					      CRYP_START_ENABLE,
+					      CRYP_CR_START_POS,
+					      CRYP_CR_START_MASK);
+
+				cryp_wait_until_done(device_data);
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mode_is_aes(enum cryp_algo_mode mode)
+{
+	return	CRYP_ALGO_AES_ECB == mode ||
+		CRYP_ALGO_AES_CBC == mode ||
+		CRYP_ALGO_AES_CTR == mode ||
+		CRYP_ALGO_AES_XTS == mode;
+}
+
+static int cfg_iv(struct cryp_device_data *device_data, u32 left, u32 right,
+		  enum cryp_init_vector_index index)
+{
+	struct cryp_init_vector_value vector_value;
+
+	dev_dbg(device_data->dev, "[%s]", __func__);
+
+	vector_value.init_value_left = left;
+	vector_value.init_value_right = right;
+
+	return cryp_configure_init_vector(device_data,
+					  index,
+					  vector_value);
+}
+
+static int cfg_ivs(struct cryp_device_data *device_data, struct cryp_ctx *ctx)
+{
+	int i;
+	int status = 0;
+	int num_of_regs = ctx->blocksize / 8;
+	u32 iv[AES_BLOCK_SIZE / 4];
+
+	dev_dbg(device_data->dev, "[%s]", __func__);
+
+	/*
+	 * Since we loop on num_of_regs we need to have a check in case
+	 * someone provides an incorrect blocksize which would force calling
+	 * cfg_iv with i greater than 2 which is an error.
+	 */
+	if (num_of_regs > 2) {
+		dev_err(device_data->dev, "[%s] Incorrect blocksize %d",
+			__func__, ctx->blocksize);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ctx->blocksize / 4; i++)
+		iv[i] = uint8p_to_uint32_be(ctx->iv + i*4);
+
+	for (i = 0; i < num_of_regs; i++) {
+		status = cfg_iv(device_data, iv[i*2], iv[i*2+1],
+				(enum cryp_init_vector_index) i);
+		if (status != 0)
+			return status;
+	}
+	return status;
+}
+
+static int set_key(struct cryp_device_data *device_data,
+		   u32 left_key,
+		   u32 right_key,
+		   enum cryp_key_reg_index index)
+{
+	struct cryp_key_value key_value;
+	int cryp_error;
+
+	dev_dbg(device_data->dev, "[%s]", __func__);
+
+	key_value.key_value_left = left_key;
+	key_value.key_value_right = right_key;
+
+	cryp_error = cryp_configure_key_values(device_data,
+					       index,
+					       key_value);
+	if (cryp_error != 0)
+		dev_err(device_data->dev, "[%s]: "
+			"cryp_configure_key_values() failed!", __func__);
+
+	return cryp_error;
+}
+
+static int cfg_keys(struct cryp_ctx *ctx)
+{
+	int i;
+	int num_of_regs = ctx->keylen / 8;
+	u32 swapped_key[CRYP_MAX_KEY_SIZE / 4];
+	int cryp_error = 0;
+
+	dev_dbg(ctx->device->dev, "[%s]", __func__);
+
+	if (mode_is_aes(ctx->config.algomode)) {
+		swap_words_in_key_and_bits_in_byte((u8 *)ctx->key,
+						   (u8 *)swapped_key,
+						   ctx->keylen);
+	} else {
+		for (i = 0; i < ctx->keylen / 4; i++)
+			swapped_key[i] = uint8p_to_uint32_be(ctx->key + i*4);
+	}
+
+	for (i = 0; i < num_of_regs; i++) {
+		cryp_error = set_key(ctx->device,
+				     *(((u32 *)swapped_key)+i*2),
+				     *(((u32 *)swapped_key)+i*2+1),
+				     (enum cryp_key_reg_index) i);
+
+		if (cryp_error != 0) {
+			dev_err(ctx->device->dev, "[%s]: set_key() failed!",
+					__func__);
+			return cryp_error;
+		}
+	}
+	return cryp_error;
+}
+
+static int cryp_setup_context(struct cryp_ctx *ctx,
+			      struct cryp_device_data *device_data)
+{
+	u32 control_register = CRYP_CR_DEFAULT;
+
+	switch (cryp_mode) {
+	case CRYP_MODE_INTERRUPT:
+		writel_relaxed(CRYP_IMSC_DEFAULT, &device_data->base->imsc);
+		break;
+
+	case CRYP_MODE_DMA:
+		writel_relaxed(CRYP_DMACR_DEFAULT, &device_data->base->dmacr);
+		break;
+
+	default:
+		break;
+	}
+
+	if (ctx->updated == 0) {
+		cryp_flush_inoutfifo(device_data);
+		if (cfg_keys(ctx) != 0) {
+			dev_err(ctx->device->dev, "[%s]: cfg_keys failed!",
+				__func__);
+			return -EINVAL;
+		}
+
+		if (ctx->iv &&
+		    CRYP_ALGO_AES_ECB != ctx->config.algomode &&
+		    CRYP_ALGO_DES_ECB != ctx->config.algomode &&
+		    CRYP_ALGO_TDES_ECB != ctx->config.algomode) {
+			if (cfg_ivs(device_data, ctx) != 0)
+				return -EPERM;
+		}
+
+		cryp_set_configuration(device_data, &ctx->config,
+				       &control_register);
+		add_session_id(ctx);
+	} else if (ctx->updated == 1 &&
+		   ctx->session_id != atomic_read(&session_id)) {
+		cryp_flush_inoutfifo(device_data);
+		cryp_restore_device_context(device_data, &ctx->dev_ctx);
+
+		add_session_id(ctx);
+		control_register = ctx->dev_ctx.cr;
+	} else
+		control_register = ctx->dev_ctx.cr;
+
+	writel(control_register |
+	       (CRYP_CRYPEN_ENABLE << CRYP_CR_CRYPEN_POS),
+	       &device_data->base->cr);
+
+	return 0;
+}
+
+static int cryp_get_device_data(struct cryp_ctx *ctx,
+				struct cryp_device_data **device_data)
+{
+	int ret;
+	struct klist_iter device_iterator;
+	struct klist_node *device_node;
+	struct cryp_device_data *local_device_data = NULL;
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+	/* Wait until a device is available */
+	ret = down_interruptible(&driver_data.device_allocation);
+	if (ret)
+		return ret;  /* Interrupted */
+
+	/* Select a device */
+	klist_iter_init(&driver_data.device_list, &device_iterator);
+
+	device_node = klist_next(&device_iterator);
+	while (device_node) {
+		local_device_data = container_of(device_node,
+					   struct cryp_device_data, list_node);
+		spin_lock(&local_device_data->ctx_lock);
+		/* current_ctx allocates a device, NULL = unallocated */
+		if (local_device_data->current_ctx) {
+			device_node = klist_next(&device_iterator);
+		} else {
+			local_device_data->current_ctx = ctx;
+			ctx->device = local_device_data;
+			spin_unlock(&local_device_data->ctx_lock);
+			break;
+		}
+		spin_unlock(&local_device_data->ctx_lock);
+	}
+	klist_iter_exit(&device_iterator);
+
+	if (!device_node) {
+		/**
+		 * No free device found.
+		 * Since we allocated a device with down_interruptible, this
+		 * should not be able to happen.
+		 * Number of available devices, which are contained in
+		 * device_allocation, is therefore decremented by not doing
+		 * an up(device_allocation).
+		 */
+		return -EBUSY;
+	}
+
+	*device_data = local_device_data;
+
+	return 0;
+}
+
+static void cryp_dma_setup_channel(struct cryp_device_data *device_data,
+				   struct device *dev)
+{
+	dma_cap_zero(device_data->dma.mask);
+	dma_cap_set(DMA_SLAVE, device_data->dma.mask);
+
+	device_data->dma.cfg_mem2cryp = mem_to_engine;
+	device_data->dma.chan_mem2cryp =
+		dma_request_channel(device_data->dma.mask,
+				    stedma40_filter,
+				    device_data->dma.cfg_mem2cryp);
+
+	device_data->dma.cfg_cryp2mem = engine_to_mem;
+	device_data->dma.chan_cryp2mem =
+		dma_request_channel(device_data->dma.mask,
+				    stedma40_filter,
+				    device_data->dma.cfg_cryp2mem);
+
+	init_completion(&device_data->dma.cryp_dma_complete);
+}
+
+static void cryp_dma_out_callback(void *data)
+{
+	struct cryp_ctx *ctx = (struct cryp_ctx *) data;
+	dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+	complete(&ctx->device->dma.cryp_dma_complete);
+}
+
+static int cryp_set_dma_transfer(struct cryp_ctx *ctx,
+				 struct scatterlist *sg,
+				 int len,
+				 enum dma_data_direction direction)
+{
+	struct dma_async_tx_descriptor *desc;
+	struct dma_chan *channel = NULL;
+	dma_cookie_t cookie;
+
+	dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+	if (unlikely(!IS_ALIGNED((u32)sg, 4))) {
+		dev_err(ctx->device->dev, "[%s]: Data in sg list isn't "
+			"aligned! Addr: 0x%08x", __func__, (u32)sg);
+		return -EFAULT;
+	}
+
+	switch (direction) {
+	case DMA_TO_DEVICE:
+		channel = ctx->device->dma.chan_mem2cryp;
+		ctx->device->dma.sg_src = sg;
+		ctx->device->dma.sg_src_len = dma_map_sg(channel->device->dev,
+						 ctx->device->dma.sg_src,
+						 ctx->device->dma.nents_src,
+						 direction);
+
+		if (!ctx->device->dma.sg_src_len) {
+			dev_dbg(ctx->device->dev,
+				"[%s]: Could not map the sg list (TO_DEVICE)",
+				__func__);
+			return -EFAULT;
+		}
+
+		dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
+			"(TO_DEVICE)", __func__);
+
+		desc = channel->device->device_prep_slave_sg(channel,
+					     ctx->device->dma.sg_src,
+					     ctx->device->dma.sg_src_len,
+					     direction, DMA_CTRL_ACK, NULL);
+		break;
+
+	case DMA_FROM_DEVICE:
+		channel = ctx->device->dma.chan_cryp2mem;
+		ctx->device->dma.sg_dst = sg;
+		ctx->device->dma.sg_dst_len = dma_map_sg(channel->device->dev,
+						 ctx->device->dma.sg_dst,
+						 ctx->device->dma.nents_dst,
+						 direction);
+
+		if (!ctx->device->dma.sg_dst_len) {
+			dev_dbg(ctx->device->dev,
+				"[%s]: Could not map the sg list (FROM_DEVICE)",
+				__func__);
+			return -EFAULT;
+		}
+
+		dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
+			"(FROM_DEVICE)", __func__);
+
+		desc = channel->device->device_prep_slave_sg(channel,
+					     ctx->device->dma.sg_dst,
+					     ctx->device->dma.sg_dst_len,
+					     direction,
+					     DMA_CTRL_ACK |
+					     DMA_PREP_INTERRUPT, NULL);
+
+		desc->callback = cryp_dma_out_callback;
+		desc->callback_param = ctx;
+		break;
+
+	default:
+		dev_dbg(ctx->device->dev, "[%s]: Invalid DMA direction",
+			__func__);
+		return -EFAULT;
+	}
+
+	cookie = desc->tx_submit(desc);
+	dma_async_issue_pending(channel);
+
+	return 0;
+}
+
+static void cryp_dma_done(struct cryp_ctx *ctx)
+{
+	struct dma_chan *chan;
+
+	dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+	chan = ctx->device->dma.chan_mem2cryp;
+	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+	dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_src,
+		     ctx->device->dma.sg_src_len, DMA_TO_DEVICE);
+
+	chan = ctx->device->dma.chan_cryp2mem;
+	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+	dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_dst,
+		     ctx->device->dma.sg_dst_len, DMA_FROM_DEVICE);
+}
+
+static int cryp_dma_write(struct cryp_ctx *ctx, struct scatterlist *sg,
+			  int len)
+{
+	int error = cryp_set_dma_transfer(ctx, sg, len, DMA_TO_DEVICE);
+	dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+	if (error) {
+		dev_dbg(ctx->device->dev, "[%s]: cryp_set_dma_transfer() "
+			"failed", __func__);
+		return error;
+	}
+
+	return len;
+}
+
+static int cryp_dma_read(struct cryp_ctx *ctx, struct scatterlist *sg, int len)
+{
+	int error = cryp_set_dma_transfer(ctx, sg, len, DMA_FROM_DEVICE);
+	if (error) {
+		dev_dbg(ctx->device->dev, "[%s]: cryp_set_dma_transfer() "
+			"failed", __func__);
+		return error;
+	}
+
+	return len;
+}
+
+static void cryp_polling_mode(struct cryp_ctx *ctx,
+			      struct cryp_device_data *device_data)
+{
+	int len = ctx->blocksize / BYTES_PER_WORD;
+	int remaining_length = ctx->datalen;
+	u32 *indata = (u32 *)ctx->indata;
+	u32 *outdata = (u32 *)ctx->outdata;
+
+	while (remaining_length > 0) {
+		writesl(&device_data->base->din, indata, len);
+		indata += len;
+		remaining_length -= (len * BYTES_PER_WORD);
+		cryp_wait_until_done(device_data);
+
+		readsl(&device_data->base->dout, outdata, len);
+		outdata += len;
+		cryp_wait_until_done(device_data);
+	}
+}
+
+static int cryp_disable_power(struct device *dev,
+			      struct cryp_device_data *device_data,
+			      bool save_device_context)
+{
+	int ret = 0;
+
+	dev_dbg(dev, "[%s]", __func__);
+
+	spin_lock(&device_data->power_state_spinlock);
+	if (!device_data->power_state)
+		goto out;
+
+	spin_lock(&device_data->ctx_lock);
+	if (save_device_context && device_data->current_ctx) {
+		cryp_save_device_context(device_data,
+				&device_data->current_ctx->dev_ctx,
+				cryp_mode);
+		device_data->restore_dev_ctx = true;
+	}
+	spin_unlock(&device_data->ctx_lock);
+
+	clk_disable(device_data->clk);
+	ret = regulator_disable(device_data->pwr_regulator);
+	if (ret)
+		dev_err(dev, "[%s]: "
+				"regulator_disable() failed!",
+				__func__);
+
+	device_data->power_state = false;
+
+out:
+	spin_unlock(&device_data->power_state_spinlock);
+
+	return ret;
+}
+
+static int cryp_enable_power(
+		struct device *dev,
+		struct cryp_device_data *device_data,
+		bool restore_device_context)
+{
+	int ret = 0;
+
+	dev_dbg(dev, "[%s]", __func__);
+
+	spin_lock(&device_data->power_state_spinlock);
+	if (!device_data->power_state) {
+		ret = regulator_enable(device_data->pwr_regulator);
+		if (ret) {
+			dev_err(dev, "[%s]: regulator_enable() failed!",
+					__func__);
+			goto out;
+		}
+
+		ret = clk_enable(device_data->clk);
+		if (ret) {
+			dev_err(dev, "[%s]: clk_enable() failed!",
+					__func__);
+			regulator_disable(device_data->pwr_regulator);
+			goto out;
+		}
+		device_data->power_state = true;
+	}
+
+	if (device_data->restore_dev_ctx) {
+		spin_lock(&device_data->ctx_lock);
+		if (restore_device_context && device_data->current_ctx) {
+			device_data->restore_dev_ctx = false;
+			cryp_restore_device_context(device_data,
+					&device_data->current_ctx->dev_ctx);
+		}
+		spin_unlock(&device_data->ctx_lock);
+	}
+out:
+	spin_unlock(&device_data->power_state_spinlock);
+
+	return ret;
+}
+
+static int hw_crypt_noxts(struct cryp_ctx *ctx,
+			  struct cryp_device_data *device_data)
+{
+	int ret = 0;
+
+	const u8 *indata = ctx->indata;
+	u8 *outdata = ctx->outdata;
+	u32 datalen = ctx->datalen;
+	u32 outlen = datalen;
+
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+	ctx->outlen = ctx->datalen;
+
+	if (unlikely(!IS_ALIGNED((u32)indata, 4))) {
+		pr_debug(DEV_DBG_NAME " [%s]: Data isn't aligned! Addr: "
+			 "0x%08x", __func__, (u32)indata);
+		return -EINVAL;
+	}
+
+	ret = cryp_setup_context(ctx, device_data);
+
+	if (ret)
+		goto out;
+
+	if (cryp_mode == CRYP_MODE_INTERRUPT) {
+		cryp_enable_irq_src(device_data, CRYP_IRQ_SRC_INPUT_FIFO |
+				    CRYP_IRQ_SRC_OUTPUT_FIFO);
+
+		/*
+		 * ctx->outlen is decremented in the cryp_interrupt_handler
+		 * function. We had to add cpu_relax() (barrier) to make sure
+		 * that gcc didn't optimze away this variable.
+		 */
+		while (ctx->outlen > 0)
+			cpu_relax();
+	} else if (cryp_mode == CRYP_MODE_POLLING ||
+		   cryp_mode == CRYP_MODE_DMA) {
+		/*
+		 * The reason for having DMA in this if case is that if we are
+		 * running cryp_mode = 2, then we separate DMA routines for
+		 * handling cipher/plaintext > blocksize, except when
+		 * running the normal CRYPTO_ALG_TYPE_CIPHER, then we still use
+		 * the polling mode. Overhead of doing DMA setup eats up the
+		 * benefits using it.
+		 */
+		cryp_polling_mode(ctx, device_data);
+	} else {
+		dev_err(ctx->device->dev, "[%s]: Invalid operation mode!",
+			__func__);
+		ret = -EPERM;
+		goto out;
+	}
+
+	cryp_save_device_context(device_data, &ctx->dev_ctx, cryp_mode);
+	ctx->updated = 1;
+
+out:
+	ctx->indata = indata;
+	ctx->outdata = outdata;
+	ctx->datalen = datalen;
+	ctx->outlen = outlen;
+
+	return ret;
+}
+
+static int get_nents(struct scatterlist *sg, int nbytes)
+{
+	int nents = 0;
+
+	while (nbytes > 0) {
+		nbytes -= sg->length;
+		sg = scatterwalk_sg_next(sg);
+		nents++;
+	}
+
+	return nents;
+}
+
+static int ablk_dma_crypt(struct ablkcipher_request *areq)
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct cryp_device_data *device_data;
+
+	int bytes_written = 0;
+	int bytes_read = 0;
+	int ret;
+
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+	ctx->datalen = areq->nbytes;
+	ctx->outlen = areq->nbytes;
+
+	ret = cryp_get_device_data(ctx, &device_data);
+	if (ret)
+		return ret;
+
+	ret = cryp_setup_context(ctx, device_data);
+	if (ret)
+		goto out;
+
+	/* We have the device now, so store the nents in the dma struct. */
+	ctx->device->dma.nents_src = get_nents(areq->src, ctx->datalen);
+	ctx->device->dma.nents_dst = get_nents(areq->dst, ctx->outlen);
+
+	/* Enable DMA in- and output. */
+	cryp_configure_for_dma(device_data, CRYP_DMA_ENABLE_BOTH_DIRECTIONS);
+
+	bytes_written = cryp_dma_write(ctx, areq->src, ctx->datalen);
+	bytes_read = cryp_dma_read(ctx, areq->dst, bytes_written);
+
+	wait_for_completion(&ctx->device->dma.cryp_dma_complete);
+	cryp_dma_done(ctx);
+
+	cryp_save_device_context(device_data, &ctx->dev_ctx, cryp_mode);
+	ctx->updated = 1;
+
+out:
+	spin_lock(&device_data->ctx_lock);
+	device_data->current_ctx = NULL;
+	ctx->device = NULL;
+	spin_unlock(&device_data->ctx_lock);
+
+	/*
+	 * The down_interruptible part for this semaphore is called in
+	 * cryp_get_device_data.
+	 */
+	up(&driver_data.device_allocation);
+
+	if (unlikely(bytes_written != bytes_read))
+		return -EPERM;
+
+	return 0;
+}
+
+static int ablk_crypt(struct ablkcipher_request *areq)
+{
+	struct ablkcipher_walk walk;
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct cryp_device_data *device_data;
+	unsigned long src_paddr;
+	unsigned long dst_paddr;
+	int ret;
+	int nbytes;
+
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+	ret = cryp_get_device_data(ctx, &device_data);
+	if (ret)
+		goto out;
+
+	ablkcipher_walk_init(&walk, areq->dst, areq->src, areq->nbytes);
+	ret = ablkcipher_walk_phys(areq, &walk);
+
+	if (ret) {
+		pr_err(DEV_DBG_NAME "[%s]: ablkcipher_walk_phys() failed!",
+			__func__);
+		goto out;
+	}
+
+	while ((nbytes = walk.nbytes) > 0) {
+		ctx->iv = walk.iv;
+		src_paddr = (page_to_phys(walk.src.page) + walk.src.offset);
+		ctx->indata = phys_to_virt(src_paddr);
+
+		dst_paddr = (page_to_phys(walk.dst.page) + walk.dst.offset);
+		ctx->outdata = phys_to_virt(dst_paddr);
+
+		ctx->datalen = nbytes - (nbytes % ctx->blocksize);
+
+		ret = hw_crypt_noxts(ctx, device_data);
+		if (ret)
+			goto out;
+
+		nbytes -= ctx->datalen;
+		ret = ablkcipher_walk_done(areq, &walk, nbytes);
+		if (ret)
+			goto out;
+	}
+	ablkcipher_walk_complete(&walk);
+
+out:
+	/* Release the device */
+	spin_lock(&device_data->ctx_lock);
+	device_data->current_ctx = NULL;
+	ctx->device = NULL;
+	spin_unlock(&device_data->ctx_lock);
+
+	/*
+	 * The down_interruptible part for this semaphore is called in
+	 * cryp_get_device_data.
+	 */
+	up(&driver_data.device_allocation);
+
+	return ret;
+}
+
+static int aes_ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+				 const u8 *key, unsigned int keylen)
+{
+	struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	u32 *flags = &cipher->base.crt_flags;
+
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+	switch (keylen) {
+	case AES_KEYSIZE_128:
+		ctx->config.keysize = CRYP_KEY_SIZE_128;
+		break;
+
+	case AES_KEYSIZE_192:
+		ctx->config.keysize = CRYP_KEY_SIZE_192;
+		break;
+
+	case AES_KEYSIZE_256:
+		ctx->config.keysize = CRYP_KEY_SIZE_256;
+		break;
+
+	default:
+		pr_err(DEV_DBG_NAME "[%s]: Unknown keylen!", __func__);
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	memcpy(ctx->key, key, keylen);
+	ctx->keylen = keylen;
+
+	ctx->updated = 0;
+
+	return 0;
+}
+
+static int des_ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+				 const u8 *key, unsigned int keylen)
+{
+	struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	u32 *flags = &cipher->base.crt_flags;
+	u32 tmp[DES_EXPKEY_WORDS];
+	int ret;
+
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+	if (keylen != DES_KEY_SIZE) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_RES_BAD_KEY_LEN",
+				__func__);
+		return -EINVAL;
+	}
+
+	ret = des_ekey(tmp, key);
+	if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
+		pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_REQ_WEAK_KEY",
+				__func__);
+		return -EINVAL;
+	}
+
+	memcpy(ctx->key, key, keylen);
+	ctx->keylen = keylen;
+
+	ctx->updated = 0;
+	return 0;
+}
+
+static int des3_ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+				  const u8 *key, unsigned int keylen)
+{
+	struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	u32 *flags = &cipher->base.crt_flags;
+	const u32 *K = (const u32 *)key;
+	u32 tmp[DES3_EDE_EXPKEY_WORDS];
+	int i, ret;
+
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+	if (keylen != DES3_EDE_KEY_SIZE) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_RES_BAD_KEY_LEN",
+				__func__);
+		return -EINVAL;
+	}
+
+	/* Checking key interdependency for weak key detection. */
+	if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
+				!((K[2] ^ K[4]) | (K[3] ^ K[5]))) &&
+			(*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
+		pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_REQ_WEAK_KEY",
+				__func__);
+		return -EINVAL;
+	}
+	for (i = 0; i < 3; i++) {
+		ret = des_ekey(tmp, key + i*DES_KEY_SIZE);
+		if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+			*flags |= CRYPTO_TFM_RES_WEAK_KEY;
+			pr_debug(DEV_DBG_NAME " [%s]: "
+					"CRYPTO_TFM_REQ_WEAK_KEY", __func__);
+			return -EINVAL;
+		}
+	}
+
+	memcpy(ctx->key, key, keylen);
+	ctx->keylen = keylen;
+
+	ctx->updated = 0;
+	return 0;
+}
+
+static int cryp_blk_encrypt(struct ablkcipher_request *areq)
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+	ctx->config.algodir = CRYP_ALGORITHM_ENCRYPT;
+
+	/*
+	 * DMA does not work for DES due to a hw bug */
+	if (cryp_mode == CRYP_MODE_DMA && mode_is_aes(ctx->config.algomode))
+		return ablk_dma_crypt(areq);
+
+	/* For everything except DMA, we run the non DMA version. */
+	return ablk_crypt(areq);
+}
+
+static int cryp_blk_decrypt(struct ablkcipher_request *areq)
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+	ctx->config.algodir = CRYP_ALGORITHM_DECRYPT;
+
+	/* DMA does not work for DES due to a hw bug */
+	if (cryp_mode == CRYP_MODE_DMA && mode_is_aes(ctx->config.algomode))
+		return ablk_dma_crypt(areq);
+
+	/* For everything except DMA, we run the non DMA version. */
+	return ablk_crypt(areq);
+}
+
+struct cryp_algo_template {
+	enum cryp_algo_mode algomode;
+	struct crypto_alg crypto;
+};
+
+static int cryp_cra_init(struct crypto_tfm *tfm)
+{
+	struct cryp_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_alg *alg = tfm->__crt_alg;
+	struct cryp_algo_template *cryp_alg = container_of(alg,
+			struct cryp_algo_template,
+			crypto);
+
+	ctx->config.algomode = cryp_alg->algomode;
+	ctx->blocksize = crypto_tfm_alg_blocksize(tfm);
+
+	return 0;
+}
+
+static struct cryp_algo_template cryp_algs[] = {
+	{
+		.algomode = CRYP_ALGO_AES_ECB,
+		.crypto = {
+			.cra_name = "aes",
+			.cra_driver_name = "aes-ux500",
+			.cra_priority =	300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_blocksize = AES_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = AES_MIN_KEY_SIZE,
+					.max_keysize = AES_MAX_KEY_SIZE,
+					.setkey = aes_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt
+				}
+			}
+		}
+	},
+	{
+		.algomode = CRYP_ALGO_AES_ECB,
+		.crypto = {
+			.cra_name = "ecb(aes)",
+			.cra_driver_name = "ecb-aes-ux500",
+			.cra_priority = 300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_blocksize = AES_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = AES_MIN_KEY_SIZE,
+					.max_keysize = AES_MAX_KEY_SIZE,
+					.setkey = aes_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt,
+				}
+			}
+		}
+	},
+	{
+		.algomode = CRYP_ALGO_AES_CBC,
+		.crypto = {
+			.cra_name = "cbc(aes)",
+			.cra_driver_name = "cbc-aes-ux500",
+			.cra_priority = 300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_blocksize = AES_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = AES_MIN_KEY_SIZE,
+					.max_keysize = AES_MAX_KEY_SIZE,
+					.setkey = aes_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt,
+					.ivsize = AES_BLOCK_SIZE,
+				}
+			}
+		}
+	},
+	{
+		.algomode = CRYP_ALGO_AES_CTR,
+		.crypto = {
+			.cra_name = "ctr(aes)",
+			.cra_driver_name = "ctr-aes-ux500",
+			.cra_priority = 300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+						CRYPTO_ALG_ASYNC,
+			.cra_blocksize = AES_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = AES_MIN_KEY_SIZE,
+					.max_keysize = AES_MAX_KEY_SIZE,
+					.setkey = aes_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt,
+					.ivsize = AES_BLOCK_SIZE,
+				}
+			}
+		}
+	},
+	{
+		.algomode = CRYP_ALGO_DES_ECB,
+		.crypto = {
+			.cra_name = "des",
+			.cra_driver_name = "des-ux500",
+			.cra_priority = 300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+						CRYPTO_ALG_ASYNC,
+			.cra_blocksize = DES_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = DES_KEY_SIZE,
+					.max_keysize = DES_KEY_SIZE,
+					.setkey = des_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt
+				}
+			}
+		}
+
+	},
+	{
+		.algomode = CRYP_ALGO_TDES_ECB,
+		.crypto = {
+			.cra_name = "des3_ede",
+			.cra_driver_name = "des3_ede-ux500",
+			.cra_priority = 300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+						CRYPTO_ALG_ASYNC,
+			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = DES3_EDE_KEY_SIZE,
+					.max_keysize = DES3_EDE_KEY_SIZE,
+					.setkey = des_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt
+				}
+			}
+		}
+	},
+	{
+		.algomode = CRYP_ALGO_DES_ECB,
+		.crypto = {
+			.cra_name = "ecb(des)",
+			.cra_driver_name = "ecb-des-ux500",
+			.cra_priority = 300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_blocksize = DES_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = DES_KEY_SIZE,
+					.max_keysize = DES_KEY_SIZE,
+					.setkey = des_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt,
+				}
+			}
+		}
+	},
+	{
+		.algomode = CRYP_ALGO_TDES_ECB,
+		.crypto = {
+			.cra_name = "ecb(des3_ede)",
+			.cra_driver_name = "ecb-des3_ede-ux500",
+			.cra_priority = 300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = DES3_EDE_KEY_SIZE,
+					.max_keysize = DES3_EDE_KEY_SIZE,
+					.setkey = des3_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt,
+				}
+			}
+		}
+	},
+	{
+		.algomode = CRYP_ALGO_DES_CBC,
+		.crypto = {
+			.cra_name = "cbc(des)",
+			.cra_driver_name = "cbc-des-ux500",
+			.cra_priority = 300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_blocksize = DES_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = DES_KEY_SIZE,
+					.max_keysize = DES_KEY_SIZE,
+					.setkey = des_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt,
+				}
+			}
+		}
+	},
+	{
+		.algomode = CRYP_ALGO_TDES_CBC,
+		.crypto = {
+			.cra_name = "cbc(des3_ede)",
+			.cra_driver_name = "cbc-des3_ede-ux500",
+			.cra_priority = 300,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+			.cra_ctxsize = sizeof(struct cryp_ctx),
+			.cra_alignmask = 3,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_init = cryp_cra_init,
+			.cra_module = THIS_MODULE,
+			.cra_u = {
+				.ablkcipher = {
+					.min_keysize = DES3_EDE_KEY_SIZE,
+					.max_keysize = DES3_EDE_KEY_SIZE,
+					.setkey = des3_ablkcipher_setkey,
+					.encrypt = cryp_blk_encrypt,
+					.decrypt = cryp_blk_decrypt,
+					.ivsize = DES3_EDE_BLOCK_SIZE,
+				}
+			}
+		}
+	}
+};
+
+/**
+ * cryp_algs_register_all -
+ */
+static int cryp_algs_register_all(void)
+{
+	int ret;
+	int i;
+	int count;
+
+	pr_debug("[%s]", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(cryp_algs); i++) {
+		ret = crypto_register_alg(&cryp_algs[i].crypto);
+		if (ret) {
+			count = i;
+			pr_err("[%s] alg registration failed",
+					cryp_algs[i].crypto.cra_driver_name);
+			goto unreg;
+		}
+	}
+	return 0;
+unreg:
+	for (i = 0; i < count; i++)
+		crypto_unregister_alg(&cryp_algs[i].crypto);
+	return ret;
+}
+
+/**
+ * cryp_algs_unregister_all -
+ */
+static void cryp_algs_unregister_all(void)
+{
+	int i;
+
+	pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(cryp_algs); i++)
+		crypto_unregister_alg(&cryp_algs[i].crypto);
+}
+
+static int ux500_cryp_probe(struct platform_device *pdev)
+{
+	int ret;
+	int cryp_error = 0;
+	struct resource *res = NULL;
+	struct resource *res_irq = NULL;
+	struct cryp_device_data *device_data;
+	struct cryp_protection_config prot = {
+		.privilege_access = CRYP_STATE_ENABLE
+	};
+	struct device *dev = &pdev->dev;
+
+	dev_dbg(dev, "[%s]", __func__);
+	device_data = kzalloc(sizeof(struct cryp_device_data), GFP_ATOMIC);
+	if (!device_data) {
+		dev_err(dev, "[%s]: kzalloc() failed!", __func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	device_data->dev = dev;
+	device_data->current_ctx = NULL;
+
+	/* Grab the DMA configuration from platform data. */
+	mem_to_engine = &((struct cryp_platform_data *)
+			 dev->platform_data)->mem_to_engine;
+	engine_to_mem = &((struct cryp_platform_data *)
+			 dev->platform_data)->engine_to_mem;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "[%s]: platform_get_resource() failed",
+				__func__);
+		ret = -ENODEV;
+		goto out_kfree;
+	}
+
+	res = request_mem_region(res->start, resource_size(res), pdev->name);
+	if (res == NULL) {
+		dev_err(dev, "[%s]: request_mem_region() failed",
+				__func__);
+		ret = -EBUSY;
+		goto out_kfree;
+	}
+
+	device_data->base = ioremap(res->start, resource_size(res));
+	if (!device_data->base) {
+		dev_err(dev, "[%s]: ioremap failed!", __func__);
+		ret = -ENOMEM;
+		goto out_free_mem;
+	}
+
+	spin_lock_init(&device_data->ctx_lock);
+	spin_lock_init(&device_data->power_state_spinlock);
+
+	/* Enable power for CRYP hardware block */
+	device_data->pwr_regulator = regulator_get(&pdev->dev, "v-ape");
+	if (IS_ERR(device_data->pwr_regulator)) {
+		dev_err(dev, "[%s]: could not get cryp regulator", __func__);
+		ret = PTR_ERR(device_data->pwr_regulator);
+		device_data->pwr_regulator = NULL;
+		goto out_unmap;
+	}
+
+	/* Enable the clk for CRYP hardware block */
+	device_data->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(device_data->clk)) {
+		dev_err(dev, "[%s]: clk_get() failed!", __func__);
+		ret = PTR_ERR(device_data->clk);
+		goto out_regulator;
+	}
+
+	/* Enable device power (and clock) */
+	ret = cryp_enable_power(device_data->dev, device_data, false);
+	if (ret) {
+		dev_err(dev, "[%s]: cryp_enable_power() failed!", __func__);
+		goto out_clk;
+	}
+
+	cryp_error = cryp_check(device_data);
+	if (cryp_error != 0) {
+		dev_err(dev, "[%s]: cryp_init() failed!", __func__);
+		ret = -EINVAL;
+		goto out_power;
+	}
+
+	cryp_error = cryp_configure_protection(device_data, &prot);
+	if (cryp_error != 0) {
+		dev_err(dev, "[%s]: cryp_configure_protection() failed!",
+			__func__);
+		ret = -EINVAL;
+		goto out_power;
+	}
+
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_irq) {
+		dev_err(dev, "[%s]: IORESOURCE_IRQ unavailable",
+			__func__);
+		goto out_power;
+	}
+
+	ret = request_irq(res_irq->start,
+			  cryp_interrupt_handler,
+			  0,
+			  "cryp1",
+			  device_data);
+	if (ret) {
+		dev_err(dev, "[%s]: Unable to request IRQ", __func__);
+		goto out_power;
+	}
+
+	if (cryp_mode == CRYP_MODE_DMA)
+		cryp_dma_setup_channel(device_data, dev);
+
+	platform_set_drvdata(pdev, device_data);
+
+	/* Put the new device into the device list... */
+	klist_add_tail(&device_data->list_node, &driver_data.device_list);
+
+	/* ... and signal that a new device is available. */
+	up(&driver_data.device_allocation);
+
+	atomic_set(&session_id, 1);
+
+	ret = cryp_algs_register_all();
+	if (ret) {
+		dev_err(dev, "[%s]: cryp_algs_register_all() failed!",
+			__func__);
+		goto out_power;
+	}
+
+	return 0;
+
+out_power:
+	cryp_disable_power(device_data->dev, device_data, false);
+
+out_clk:
+	clk_put(device_data->clk);
+
+out_regulator:
+	regulator_put(device_data->pwr_regulator);
+
+out_unmap:
+	iounmap(device_data->base);
+
+out_free_mem:
+	release_mem_region(res->start, resource_size(res));
+
+out_kfree:
+	kfree(device_data);
+out:
+	return ret;
+}
+
+static int ux500_cryp_remove(struct platform_device *pdev)
+{
+	struct resource *res = NULL;
+	struct resource *res_irq = NULL;
+	struct cryp_device_data *device_data;
+
+	dev_dbg(&pdev->dev, "[%s]", __func__);
+	device_data = platform_get_drvdata(pdev);
+	if (!device_data) {
+		dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+			__func__);
+		return -ENOMEM;
+	}
+
+	/* Try to decrease the number of available devices. */
+	if (down_trylock(&driver_data.device_allocation))
+		return -EBUSY;
+
+	/* Check that the device is free */
+	spin_lock(&device_data->ctx_lock);
+	/* current_ctx allocates a device, NULL = unallocated */
+	if (device_data->current_ctx) {
+		/* The device is busy */
+		spin_unlock(&device_data->ctx_lock);
+		/* Return the device to the pool. */
+		up(&driver_data.device_allocation);
+		return -EBUSY;
+	}
+
+	spin_unlock(&device_data->ctx_lock);
+
+	/* Remove the device from the list */
+	if (klist_node_attached(&device_data->list_node))
+		klist_remove(&device_data->list_node);
+
+	/* If this was the last device, remove the services */
+	if (list_empty(&driver_data.device_list.k_list))
+		cryp_algs_unregister_all();
+
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_irq)
+		dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
+			__func__);
+	else {
+		disable_irq(res_irq->start);
+		free_irq(res_irq->start, device_data);
+	}
+
+	if (cryp_disable_power(&pdev->dev, device_data, false))
+		dev_err(&pdev->dev, "[%s]: cryp_disable_power() failed",
+			__func__);
+
+	clk_put(device_data->clk);
+	regulator_put(device_data->pwr_regulator);
+
+	iounmap(device_data->base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res)
+		release_mem_region(res->start, res->end - res->start + 1);
+
+	kfree(device_data);
+
+	return 0;
+}
+
+static void ux500_cryp_shutdown(struct platform_device *pdev)
+{
+	struct resource *res_irq = NULL;
+	struct cryp_device_data *device_data;
+
+	dev_dbg(&pdev->dev, "[%s]", __func__);
+
+	device_data = platform_get_drvdata(pdev);
+	if (!device_data) {
+		dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+			__func__);
+		return;
+	}
+
+	/* Check that the device is free */
+	spin_lock(&device_data->ctx_lock);
+	/* current_ctx allocates a device, NULL = unallocated */
+	if (!device_data->current_ctx) {
+		if (down_trylock(&driver_data.device_allocation))
+			dev_dbg(&pdev->dev, "[%s]: Cryp still in use!"
+				"Shutting down anyway...", __func__);
+		/**
+		 * (Allocate the device)
+		 * Need to set this to non-null (dummy) value,
+		 * to avoid usage if context switching.
+		 */
+		device_data->current_ctx++;
+	}
+	spin_unlock(&device_data->ctx_lock);
+
+	/* Remove the device from the list */
+	if (klist_node_attached(&device_data->list_node))
+		klist_remove(&device_data->list_node);
+
+	/* If this was the last device, remove the services */
+	if (list_empty(&driver_data.device_list.k_list))
+		cryp_algs_unregister_all();
+
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_irq)
+		dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
+			__func__);
+	else {
+		disable_irq(res_irq->start);
+		free_irq(res_irq->start, device_data);
+	}
+
+	if (cryp_disable_power(&pdev->dev, device_data, false))
+		dev_err(&pdev->dev, "[%s]: cryp_disable_power() failed",
+			__func__);
+
+}
+
+static int ux500_cryp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	int ret;
+	struct cryp_device_data *device_data;
+	struct resource *res_irq;
+	struct cryp_ctx *temp_ctx = NULL;
+
+	dev_dbg(&pdev->dev, "[%s]", __func__);
+
+	/* Handle state? */
+	device_data = platform_get_drvdata(pdev);
+	if (!device_data) {
+		dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+			__func__);
+		return -ENOMEM;
+	}
+
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_irq)
+		dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
+			__func__);
+	else
+		disable_irq(res_irq->start);
+
+	spin_lock(&device_data->ctx_lock);
+	if (!device_data->current_ctx)
+		device_data->current_ctx++;
+	spin_unlock(&device_data->ctx_lock);
+
+	if (device_data->current_ctx == ++temp_ctx) {
+		if (down_interruptible(&driver_data.device_allocation))
+			dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
+					"failed", __func__);
+		ret = cryp_disable_power(&pdev->dev, device_data, false);
+
+	} else
+		ret = cryp_disable_power(&pdev->dev, device_data, true);
+
+	if (ret)
+		dev_err(&pdev->dev, "[%s]: cryp_disable_power()", __func__);
+
+	return ret;
+}
+
+static int ux500_cryp_resume(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct cryp_device_data *device_data;
+	struct resource *res_irq;
+	struct cryp_ctx *temp_ctx = NULL;
+
+	dev_dbg(&pdev->dev, "[%s]", __func__);
+
+	device_data = platform_get_drvdata(pdev);
+	if (!device_data) {
+		dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+			__func__);
+		return -ENOMEM;
+	}
+
+	spin_lock(&device_data->ctx_lock);
+	if (device_data->current_ctx == ++temp_ctx)
+		device_data->current_ctx = NULL;
+	spin_unlock(&device_data->ctx_lock);
+
+
+	if (!device_data->current_ctx)
+		up(&driver_data.device_allocation);
+	else
+		ret = cryp_enable_power(&pdev->dev, device_data, true);
+
+	if (ret)
+		dev_err(&pdev->dev, "[%s]: cryp_enable_power() failed!",
+			__func__);
+	else {
+		res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+		if (res_irq)
+			enable_irq(res_irq->start);
+	}
+
+	return ret;
+}
+
+static struct platform_driver cryp_driver = {
+	.probe  = ux500_cryp_probe,
+	.remove = ux500_cryp_remove,
+	.shutdown = ux500_cryp_shutdown,
+	.suspend  = ux500_cryp_suspend,
+	.resume   = ux500_cryp_resume,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name  = "cryp1"
+	}
+};
+
+static int __init ux500_cryp_mod_init(void)
+{
+	pr_debug("[%s] is called!", __func__);
+	klist_init(&driver_data.device_list, NULL, NULL);
+	/* Initialize the semaphore to 0 devices (locked state) */
+	sema_init(&driver_data.device_allocation, 0);
+	return platform_driver_register(&cryp_driver);
+}
+
+static void __exit ux500_cryp_mod_fini(void)
+{
+	pr_debug("[%s] is called!", __func__);
+	platform_driver_unregister(&cryp_driver);
+	return;
+}
+
+module_init(ux500_cryp_mod_init);
+module_exit(ux500_cryp_mod_fini);
+
+module_param(cryp_mode, int, 0);
+
+MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 CRYP crypto engine.");
+MODULE_ALIAS("aes-all");
+MODULE_ALIAS("des-all");
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/ux500/cryp/cryp_irq.c b/drivers/crypto/ux500/cryp/cryp_irq.c
new file mode 100644
index 0000000..08d291c
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_irq.c
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/device.h>
+
+#include "cryp.h"
+#include "cryp_p.h"
+#include "cryp_irq.h"
+#include "cryp_irqp.h"
+
+void cryp_enable_irq_src(struct cryp_device_data *device_data, u32 irq_src)
+{
+	u32 i;
+
+	dev_dbg(device_data->dev, "[%s]", __func__);
+
+	i = readl_relaxed(&device_data->base->imsc);
+	i = i | irq_src;
+	writel_relaxed(i, &device_data->base->imsc);
+}
+
+void cryp_disable_irq_src(struct cryp_device_data *device_data, u32 irq_src)
+{
+	u32 i;
+
+	dev_dbg(device_data->dev, "[%s]", __func__);
+
+	i = readl_relaxed(&device_data->base->imsc);
+	i = i & ~irq_src;
+	writel_relaxed(i, &device_data->base->imsc);
+}
+
+bool cryp_pending_irq_src(struct cryp_device_data *device_data, u32 irq_src)
+{
+	return (readl_relaxed(&device_data->base->mis) & irq_src) > 0;
+}
diff --git a/drivers/crypto/ux500/cryp/cryp_irq.h b/drivers/crypto/ux500/cryp/cryp_irq.h
new file mode 100644
index 0000000..5a7837f
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_irq.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _CRYP_IRQ_H_
+#define _CRYP_IRQ_H_
+
+#include "cryp.h"
+
+enum cryp_irq_src_id {
+	CRYP_IRQ_SRC_INPUT_FIFO = 0x1,
+	CRYP_IRQ_SRC_OUTPUT_FIFO = 0x2,
+	CRYP_IRQ_SRC_ALL = 0x3
+};
+
+/**
+ * M0 Funtions
+ */
+void cryp_enable_irq_src(struct cryp_device_data *device_data, u32 irq_src);
+
+void cryp_disable_irq_src(struct cryp_device_data *device_data, u32 irq_src);
+
+bool cryp_pending_irq_src(struct cryp_device_data *device_data, u32 irq_src);
+
+#endif				/* _CRYP_IRQ_H_ */
diff --git a/drivers/crypto/ux500/cryp/cryp_irqp.h b/drivers/crypto/ux500/cryp/cryp_irqp.h
new file mode 100644
index 0000000..8b339cc
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_irqp.h
@@ -0,0 +1,125 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __CRYP_IRQP_H_
+#define __CRYP_IRQP_H_
+
+#include "cryp_irq.h"
+
+/**
+ *
+ * CRYP Registers - Offset mapping
+ *     +-----------------+
+ * 00h | CRYP_CR         |  Configuration register
+ *     +-----------------+
+ * 04h | CRYP_SR         |  Status register
+ *     +-----------------+
+ * 08h | CRYP_DIN        |  Data In register
+ *     +-----------------+
+ * 0ch | CRYP_DOUT       |  Data out register
+ *     +-----------------+
+ * 10h | CRYP_DMACR      |  DMA control register
+ *     +-----------------+
+ * 14h | CRYP_IMSC       |  IMSC
+ *     +-----------------+
+ * 18h | CRYP_RIS        |  Raw interrupt status
+ *     +-----------------+
+ * 1ch | CRYP_MIS        |  Masked interrupt status.
+ *     +-----------------+
+ *       Key registers
+ *       IVR registers
+ *       Peripheral
+ *       Cell IDs
+ *
+ *       Refer data structure for other register map
+ */
+
+/**
+ * struct cryp_register
+ * @cr			- Configuration register
+ * @status		- Status register
+ * @din			- Data input register
+ * @din_size		- Data input size register
+ * @dout		- Data output register
+ * @dout_size		- Data output size register
+ * @dmacr		- Dma control register
+ * @imsc		- Interrupt mask set/clear register
+ * @ris			- Raw interrupt status
+ * @mis			- Masked interrupt statu register
+ * @key_1_l		- Key register 1 L
+ * @key_1_r		- Key register 1 R
+ * @key_2_l		- Key register 2 L
+ * @key_2_r		- Key register 2 R
+ * @key_3_l		- Key register 3 L
+ * @key_3_r		- Key register 3 R
+ * @key_4_l		- Key register 4 L
+ * @key_4_r		- Key register 4 R
+ * @init_vect_0_l	- init vector 0 L
+ * @init_vect_0_r	- init vector 0 R
+ * @init_vect_1_l	- init vector 1 L
+ * @init_vect_1_r	- init vector 1 R
+ * @cryp_unused1	- unused registers
+ * @itcr		- Integration test control register
+ * @itip		- Integration test input register
+ * @itop		- Integration test output register
+ * @cryp_unused2	- unused registers
+ * @periphId0		- FE0 CRYP Peripheral Identication Register
+ * @periphId1		- FE4
+ * @periphId2		- FE8
+ * @periphId3		- FEC
+ * @pcellId0		- FF0  CRYP PCell Identication Register
+ * @pcellId1		- FF4
+ * @pcellId2		- FF8
+ * @pcellId3		- FFC
+ */
+struct cryp_register {
+	u32 cr;			/* Configuration register   */
+	u32 sr;			/* Status register          */
+	u32 din;		/* Data input register      */
+	u32 din_size;		/* Data input size register */
+	u32 dout;		/* Data output register     */
+	u32 dout_size;		/* Data output size register */
+	u32 dmacr;		/* Dma control register     */
+	u32 imsc;		/* Interrupt mask set/clear register */
+	u32 ris;		/* Raw interrupt status             */
+	u32 mis;		/* Masked interrupt statu register  */
+
+	u32 key_1_l;		/*Key register 1 L */
+	u32 key_1_r;		/*Key register 1 R */
+	u32 key_2_l;		/*Key register 2 L */
+	u32 key_2_r;		/*Key register 2 R */
+	u32 key_3_l;		/*Key register 3 L */
+	u32 key_3_r;		/*Key register 3 R */
+	u32 key_4_l;		/*Key register 4 L */
+	u32 key_4_r;		/*Key register 4 R */
+
+	u32 init_vect_0_l;	/*init vector 0 L */
+	u32 init_vect_0_r;	/*init vector 0 R */
+	u32 init_vect_1_l;	/*init vector 1 L */
+	u32 init_vect_1_r;	/*init vector 1 R */
+
+	u32 cryp_unused1[(0x80 - 0x58) / sizeof(u32)];	/* unused registers */
+	u32 itcr;		/*Integration test control register */
+	u32 itip;		/*Integration test input register */
+	u32 itop;		/*Integration test output register */
+	u32 cryp_unused2[(0xFE0 - 0x8C) / sizeof(u32)];	/* unused registers */
+
+	u32 periphId0;		/* FE0  CRYP Peripheral Identication Register */
+	u32 periphId1;		/* FE4 */
+	u32 periphId2;		/* FE8 */
+	u32 periphId3;		/* FEC */
+
+	u32 pcellId0;		/* FF0  CRYP PCell Identication Register */
+	u32 pcellId1;		/* FF4 */
+	u32 pcellId2;		/* FF8 */
+	u32 pcellId3;		/* FFC */
+};
+
+#endif
diff --git a/drivers/crypto/ux500/cryp/cryp_p.h b/drivers/crypto/ux500/cryp/cryp_p.h
new file mode 100644
index 0000000..6dcffe1
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_p.h
@@ -0,0 +1,123 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _CRYP_P_H_
+#define _CRYP_P_H_
+
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#include "cryp.h"
+#include "cryp_irqp.h"
+
+/**
+ * Generic Macros
+ */
+#define CRYP_SET_BITS(reg_name, mask) \
+	writel_relaxed((readl_relaxed(reg_name) | mask), reg_name)
+
+#define CRYP_WRITE_BIT(reg_name, val, mask) \
+	writel_relaxed(((readl_relaxed(reg_name) & ~(mask)) |\
+			((val) & (mask))), reg_name)
+
+#define CRYP_TEST_BITS(reg_name, val) \
+	(readl_relaxed(reg_name) & (val))
+
+#define CRYP_PUT_BITS(reg, val, shift, mask) \
+	writel_relaxed(((readl_relaxed(reg) & ~(mask)) | \
+		(((u32)val << shift) & (mask))), reg)
+
+/**
+ * CRYP specific Macros
+ */
+#define CRYP_PERIPHERAL_ID0		0xE3
+#define CRYP_PERIPHERAL_ID1		0x05
+
+#define CRYP_PERIPHERAL_ID2_DB8500	0x28
+#define CRYP_PERIPHERAL_ID3		0x00
+
+#define CRYP_PCELL_ID0			0x0D
+#define CRYP_PCELL_ID1			0xF0
+#define CRYP_PCELL_ID2			0x05
+#define CRYP_PCELL_ID3			0xB1
+
+/**
+ * CRYP register default values
+ */
+#define MAX_DEVICE_SUPPORT		2
+
+/* Priv set, keyrden set and datatype 8bits swapped set as default. */
+#define CRYP_CR_DEFAULT			0x0482
+#define CRYP_DMACR_DEFAULT		0x0
+#define CRYP_IMSC_DEFAULT		0x0
+#define CRYP_DIN_DEFAULT		0x0
+#define CRYP_DOUT_DEFAULT		0x0
+#define CRYP_KEY_DEFAULT		0x0
+#define CRYP_INIT_VECT_DEFAULT		0x0
+
+/**
+ * CRYP Control register specific mask
+ */
+#define CRYP_CR_SECURE_MASK		BIT(0)
+#define CRYP_CR_PRLG_MASK		BIT(1)
+#define CRYP_CR_ALGODIR_MASK		BIT(2)
+#define CRYP_CR_ALGOMODE_MASK		(BIT(5) | BIT(4) | BIT(3))
+#define CRYP_CR_DATATYPE_MASK		(BIT(7) | BIT(6))
+#define CRYP_CR_KEYSIZE_MASK		(BIT(9) | BIT(8))
+#define CRYP_CR_KEYRDEN_MASK		BIT(10)
+#define CRYP_CR_KSE_MASK		BIT(11)
+#define CRYP_CR_START_MASK		BIT(12)
+#define CRYP_CR_INIT_MASK		BIT(13)
+#define CRYP_CR_FFLUSH_MASK		BIT(14)
+#define CRYP_CR_CRYPEN_MASK		BIT(15)
+#define CRYP_CR_CONTEXT_SAVE_MASK	(CRYP_CR_SECURE_MASK |\
+					 CRYP_CR_PRLG_MASK |\
+					 CRYP_CR_ALGODIR_MASK |\
+					 CRYP_CR_ALGOMODE_MASK |\
+					 CRYP_CR_DATATYPE_MASK |\
+					 CRYP_CR_KEYSIZE_MASK |\
+					 CRYP_CR_KEYRDEN_MASK |\
+					 CRYP_CR_DATATYPE_MASK)
+
+
+#define CRYP_SR_INFIFO_READY_MASK	(BIT(0) | BIT(1))
+#define CRYP_SR_IFEM_MASK		BIT(0)
+#define CRYP_SR_BUSY_MASK		BIT(4)
+
+/**
+ * Bit position used while setting bits in register
+ */
+#define CRYP_CR_PRLG_POS		1
+#define CRYP_CR_ALGODIR_POS		2
+#define CRYP_CR_ALGOMODE_POS		3
+#define CRYP_CR_DATATYPE_POS		6
+#define CRYP_CR_KEYSIZE_POS		8
+#define CRYP_CR_KEYRDEN_POS		10
+#define CRYP_CR_KSE_POS			11
+#define CRYP_CR_START_POS		12
+#define CRYP_CR_INIT_POS		13
+#define CRYP_CR_CRYPEN_POS		15
+
+#define CRYP_SR_BUSY_POS		4
+
+/**
+ * CRYP PCRs------PC_NAND control register
+ * BIT_MASK
+ */
+#define CRYP_DMA_REQ_MASK		(BIT(1) | BIT(0))
+#define CRYP_DMA_REQ_MASK_POS		0
+
+
+struct cryp_system_context {
+	/* CRYP Register structure */
+	struct cryp_register *p_cryp_reg[MAX_DEVICE_SUPPORT];
+};
+
+#endif
diff --git a/drivers/crypto/ux500/hash/Makefile b/drivers/crypto/ux500/hash/Makefile
new file mode 100644
index 0000000..b2f90d9
--- /dev/null
+++ b/drivers/crypto/ux500/hash/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Shujuan Chen (shujuan.chen@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+ifdef CONFIG_CRYPTO_DEV_UX500_DEBUG
+CFLAGS_hash_core.o := -DDEBUG -O0
+endif
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_HASH) += ux500_hash.o
+ux500_hash-objs :=  hash_core.o
diff --git a/drivers/crypto/ux500/hash/hash_alg.h b/drivers/crypto/ux500/hash/hash_alg.h
new file mode 100644
index 0000000..cd9351c
--- /dev/null
+++ b/drivers/crypto/ux500/hash/hash_alg.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen (shujuan.chen@stericsson.com)
+ * Author: Joakim Bech (joakim.xx.bech@stericsson.com)
+ * Author: Berne Hebark (berne.hebark@stericsson.com))
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef _HASH_ALG_H
+#define _HASH_ALG_H
+
+#include <linux/bitops.h>
+
+#define HASH_BLOCK_SIZE			64
+#define HASH_DMA_ALIGN_SIZE		4
+#define HASH_DMA_PERFORMANCE_MIN_SIZE	1024
+#define HASH_BYTES_PER_WORD		4
+
+/* Maximum value of the length's high word */
+#define HASH_HIGH_WORD_MAX_VAL		0xFFFFFFFFUL
+
+/* Power on Reset values HASH registers */
+#define HASH_RESET_CR_VALUE		0x0
+#define HASH_RESET_STR_VALUE		0x0
+
+/* Number of context swap registers */
+#define HASH_CSR_COUNT			52
+
+#define HASH_RESET_CSRX_REG_VALUE	0x0
+#define HASH_RESET_CSFULL_REG_VALUE	0x0
+#define HASH_RESET_CSDATAIN_REG_VALUE	0x0
+
+#define HASH_RESET_INDEX_VAL		0x0
+#define HASH_RESET_BIT_INDEX_VAL	0x0
+#define HASH_RESET_BUFFER_VAL		0x0
+#define HASH_RESET_LEN_HIGH_VAL		0x0
+#define HASH_RESET_LEN_LOW_VAL		0x0
+
+/* Control register bitfields */
+#define HASH_CR_RESUME_MASK	0x11FCF
+
+#define HASH_CR_SWITCHON_POS	31
+#define HASH_CR_SWITCHON_MASK	BIT(31)
+
+#define HASH_CR_EMPTYMSG_POS	20
+#define HASH_CR_EMPTYMSG_MASK	BIT(20)
+
+#define HASH_CR_DINF_POS	12
+#define HASH_CR_DINF_MASK	BIT(12)
+
+#define HASH_CR_NBW_POS		8
+#define HASH_CR_NBW_MASK	0x00000F00UL
+
+#define HASH_CR_LKEY_POS	16
+#define HASH_CR_LKEY_MASK	BIT(16)
+
+#define HASH_CR_ALGO_POS	7
+#define HASH_CR_ALGO_MASK	BIT(7)
+
+#define HASH_CR_MODE_POS	6
+#define HASH_CR_MODE_MASK	BIT(6)
+
+#define HASH_CR_DATAFORM_POS	4
+#define HASH_CR_DATAFORM_MASK	(BIT(4) | BIT(5))
+
+#define HASH_CR_DMAE_POS	3
+#define HASH_CR_DMAE_MASK	BIT(3)
+
+#define HASH_CR_INIT_POS	2
+#define HASH_CR_INIT_MASK	BIT(2)
+
+#define HASH_CR_PRIVN_POS	1
+#define HASH_CR_PRIVN_MASK	BIT(1)
+
+#define HASH_CR_SECN_POS	0
+#define HASH_CR_SECN_MASK	BIT(0)
+
+/* Start register bitfields */
+#define HASH_STR_DCAL_POS	8
+#define HASH_STR_DCAL_MASK	BIT(8)
+#define HASH_STR_DEFAULT	0x0
+
+#define HASH_STR_NBLW_POS	0
+#define HASH_STR_NBLW_MASK	0x0000001FUL
+
+#define HASH_NBLW_MAX_VAL	0x1F
+
+/* PrimeCell IDs */
+#define HASH_P_ID0		0xE0
+#define HASH_P_ID1		0x05
+#define HASH_P_ID2		0x38
+#define HASH_P_ID3		0x00
+#define HASH_CELL_ID0		0x0D
+#define HASH_CELL_ID1		0xF0
+#define HASH_CELL_ID2		0x05
+#define HASH_CELL_ID3		0xB1
+
+#define HASH_SET_BITS(reg_name, mask)	\
+	writel_relaxed((readl_relaxed(reg_name) | mask), reg_name)
+
+#define HASH_CLEAR_BITS(reg_name, mask)	\
+	writel_relaxed((readl_relaxed(reg_name) & ~mask), reg_name)
+
+#define HASH_PUT_BITS(reg, val, shift, mask)	\
+	writel_relaxed(((readl(reg) & ~(mask)) |	\
+		(((u32)val << shift) & (mask))), reg)
+
+#define HASH_SET_DIN(val, len)	writesl(&device_data->base->din, (val), (len))
+
+#define HASH_INITIALIZE			\
+	HASH_PUT_BITS(			\
+		&device_data->base->cr,	\
+		0x01, HASH_CR_INIT_POS,	\
+		HASH_CR_INIT_MASK)
+
+#define HASH_SET_DATA_FORMAT(data_format)				\
+		HASH_PUT_BITS(						\
+			&device_data->base->cr,				\
+			(u32) (data_format), HASH_CR_DATAFORM_POS,	\
+			HASH_CR_DATAFORM_MASK)
+#define HASH_SET_NBLW(val)					\
+		HASH_PUT_BITS(					\
+			&device_data->base->str,		\
+			(u32) (val), HASH_STR_NBLW_POS,		\
+			HASH_STR_NBLW_MASK)
+#define HASH_SET_DCAL					\
+		HASH_PUT_BITS(				\
+			&device_data->base->str,	\
+			0x01, HASH_STR_DCAL_POS,	\
+			HASH_STR_DCAL_MASK)
+
+/* Hardware access method */
+enum hash_mode {
+	HASH_MODE_CPU,
+	HASH_MODE_DMA
+};
+
+/**
+ * struct uint64 - Structure to handle 64 bits integers.
+ * @high_word:	Most significant bits.
+ * @low_word:	Least significant bits.
+ *
+ * Used to handle 64 bits integers.
+ */
+struct uint64 {
+	u32 high_word;
+	u32 low_word;
+};
+
+/**
+ * struct hash_register - Contains all registers in ux500 hash hardware.
+ * @cr:		HASH control register (0x000).
+ * @din:	HASH data input register (0x004).
+ * @str:	HASH start register (0x008).
+ * @hx:		HASH digest register 0..7 (0x00c-0x01C).
+ * @padding0:	Reserved (0x02C).
+ * @itcr:	Integration test control register (0x080).
+ * @itip:	Integration test input register (0x084).
+ * @itop:	Integration test output register (0x088).
+ * @padding1:	Reserved (0x08C).
+ * @csfull:	HASH context full register (0x0F8).
+ * @csdatain:	HASH context swap data input register (0x0FC).
+ * @csrx:	HASH context swap register 0..51 (0x100-0x1CC).
+ * @padding2:	Reserved (0x1D0).
+ * @periphid0:	HASH peripheral identification register 0 (0xFE0).
+ * @periphid1:	HASH peripheral identification register 1 (0xFE4).
+ * @periphid2:	HASH peripheral identification register 2 (0xFE8).
+ * @periphid3:	HASH peripheral identification register 3 (0xFEC).
+ * @cellid0:	HASH PCell identification register 0 (0xFF0).
+ * @cellid1:	HASH PCell identification register 1 (0xFF4).
+ * @cellid2:	HASH PCell identification register 2 (0xFF8).
+ * @cellid3:	HASH PCell identification register 3 (0xFFC).
+ *
+ * The device communicates to the HASH via 32-bit-wide control registers
+ * accessible via the 32-bit width AMBA rev. 2.0 AHB Bus. Below is a structure
+ * with the registers used.
+ */
+struct hash_register {
+	u32 cr;
+	u32 din;
+	u32 str;
+	u32 hx[8];
+
+	u32 padding0[(0x080 - 0x02C) / sizeof(u32)];
+
+	u32 itcr;
+	u32 itip;
+	u32 itop;
+
+	u32 padding1[(0x0F8 - 0x08C) / sizeof(u32)];
+
+	u32 csfull;
+	u32 csdatain;
+	u32 csrx[HASH_CSR_COUNT];
+
+	u32 padding2[(0xFE0 - 0x1D0) / sizeof(u32)];
+
+	u32 periphid0;
+	u32 periphid1;
+	u32 periphid2;
+	u32 periphid3;
+
+	u32 cellid0;
+	u32 cellid1;
+	u32 cellid2;
+	u32 cellid3;
+};
+
+/**
+ * struct hash_state - Hash context state.
+ * @temp_cr:	Temporary HASH Control Register.
+ * @str_reg:	HASH Start Register.
+ * @din_reg:	HASH Data Input Register.
+ * @csr[52]:	HASH Context Swap Registers 0-39.
+ * @csfull:	HASH Context Swap Registers 40 ie Status flags.
+ * @csdatain:	HASH Context Swap Registers 41 ie Input data.
+ * @buffer:	Working buffer for messages going to the hardware.
+ * @length:	Length of the part of message hashed so far (floor(N/64) * 64).
+ * @index:	Valid number of bytes in buffer (N % 64).
+ * @bit_index:	Valid number of bits in buffer (N % 8).
+ *
+ * This structure is used between context switches, i.e. when ongoing jobs are
+ * interupted with new jobs. When this happens we need to store intermediate
+ * results in software.
+ *
+ * WARNING: "index" is the  member of the structure, to be sure  that "buffer"
+ * is aligned on a 4-bytes boundary. This is highly implementation dependent
+ * and MUST be checked whenever this code is ported on new platforms.
+ */
+struct hash_state {
+	u32		temp_cr;
+	u32		str_reg;
+	u32		din_reg;
+	u32		csr[52];
+	u32		csfull;
+	u32		csdatain;
+	u32		buffer[HASH_BLOCK_SIZE / sizeof(u32)];
+	struct uint64	length;
+	u8		index;
+	u8		bit_index;
+};
+
+/**
+ * enum hash_device_id - HASH device ID.
+ * @HASH_DEVICE_ID_0: Hash hardware with ID 0
+ * @HASH_DEVICE_ID_1: Hash hardware with ID 1
+ */
+enum hash_device_id {
+	HASH_DEVICE_ID_0 = 0,
+	HASH_DEVICE_ID_1 = 1
+};
+
+/**
+ * enum hash_data_format - HASH data format.
+ * @HASH_DATA_32_BITS:	32 bits data format
+ * @HASH_DATA_16_BITS:	16 bits data format
+ * @HASH_DATA_8_BITS:	8 bits data format.
+ * @HASH_DATA_1_BITS:	1 bit data format.
+ */
+enum hash_data_format {
+	HASH_DATA_32_BITS	= 0x0,
+	HASH_DATA_16_BITS	= 0x1,
+	HASH_DATA_8_BITS	= 0x2,
+	HASH_DATA_1_BIT		= 0x3
+};
+
+/**
+ * enum hash_algo - Enumeration for selecting between SHA1 or SHA2 algorithm.
+ * @HASH_ALGO_SHA1: Indicates that SHA1 is used.
+ * @HASH_ALGO_SHA2: Indicates that SHA2 (SHA256) is used.
+ */
+enum hash_algo {
+	HASH_ALGO_SHA1		= 0x0,
+	HASH_ALGO_SHA256	= 0x1
+};
+
+/**
+ * enum hash_op - Enumeration for selecting between HASH or HMAC mode.
+ * @HASH_OPER_MODE_HASH: Indicates usage of normal HASH mode.
+ * @HASH_OPER_MODE_HMAC: Indicates usage of HMAC.
+ */
+enum hash_op {
+	HASH_OPER_MODE_HASH = 0x0,
+	HASH_OPER_MODE_HMAC = 0x1
+};
+
+/**
+ * struct hash_config - Configuration data for the hardware.
+ * @data_format:	Format of data entered into the hash data in register.
+ * @algorithm:		Algorithm selection bit.
+ * @oper_mode:		Operating mode selection bit.
+ */
+struct hash_config {
+	int data_format;
+	int algorithm;
+	int oper_mode;
+};
+
+/**
+ * struct hash_dma - Structure used for dma.
+ * @mask:		DMA capabilities bitmap mask.
+ * @complete:		Used to maintain state for a "completion".
+ * @chan_mem2hash:	DMA channel.
+ * @cfg_mem2hash:	DMA channel configuration.
+ * @sg_len:		Scatterlist length.
+ * @sg:			Scatterlist.
+ * @nents:		Number of sg entries.
+ */
+struct hash_dma {
+	dma_cap_mask_t		mask;
+	struct completion	complete;
+	struct dma_chan		*chan_mem2hash;
+	void			*cfg_mem2hash;
+	int			sg_len;
+	struct scatterlist	*sg;
+	int			nents;
+};
+
+/**
+ * struct hash_ctx - The context used for hash calculations.
+ * @key:	The key used in the operation.
+ * @keylen:	The length of the key.
+ * @state:	The state of the current calculations.
+ * @config:	The current configuration.
+ * @digestsize:	The size of current digest.
+ * @device:	Pointer to the device structure.
+ */
+struct hash_ctx {
+	u8			*key;
+	u32			keylen;
+	struct hash_config	config;
+	int			digestsize;
+	struct hash_device_data	*device;
+};
+
+/**
+ * struct hash_ctx - The request context used for hash calculations.
+ * @state:	The state of the current calculations.
+ * @dma_mode:	Used in special cases (workaround), e.g. need to change to
+ *		cpu mode, if not supported/working in dma mode.
+ * @updated:	Indicates if hardware is initialized for new operations.
+ */
+struct hash_req_ctx {
+	struct hash_state	state;
+	bool			dma_mode;
+	u8			updated;
+};
+
+/**
+ * struct hash_device_data - structure for a hash device.
+ * @base:		Pointer to the hardware base address.
+ * @list_node:		For inclusion in klist.
+ * @dev:		Pointer to the device dev structure.
+ * @ctx_lock:		Spinlock for current_ctx.
+ * @current_ctx:	Pointer to the currently allocated context.
+ * @power_state:	TRUE = power state on, FALSE = power state off.
+ * @power_state_lock:	Spinlock for power_state.
+ * @regulator:		Pointer to the device's power control.
+ * @clk:		Pointer to the device's clock control.
+ * @restore_dev_state:	TRUE = saved state, FALSE = no saved state.
+ * @dma:		Structure used for dma.
+ */
+struct hash_device_data {
+	struct hash_register __iomem	*base;
+	struct klist_node	list_node;
+	struct device		*dev;
+	struct spinlock		ctx_lock;
+	struct hash_ctx		*current_ctx;
+	bool			power_state;
+	struct spinlock		power_state_lock;
+	struct regulator	*regulator;
+	struct clk		*clk;
+	bool			restore_dev_state;
+	struct hash_state	state; /* Used for saving and resuming state */
+	struct hash_dma		dma;
+};
+
+int hash_check_hw(struct hash_device_data *device_data);
+
+int hash_setconfiguration(struct hash_device_data *device_data,
+		struct hash_config *config);
+
+void hash_begin(struct hash_device_data *device_data, struct hash_ctx *ctx);
+
+void hash_get_digest(struct hash_device_data *device_data,
+		u8 *digest, int algorithm);
+
+int hash_hw_update(struct ahash_request *req);
+
+int hash_save_state(struct hash_device_data *device_data,
+		struct hash_state *state);
+
+int hash_resume_state(struct hash_device_data *device_data,
+		const struct hash_state *state);
+
+#endif
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
new file mode 100644
index 0000000..6dbb9ec
--- /dev/null
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -0,0 +1,2009 @@
+/*
+ * Cryptographic API.
+ * Support for Nomadik hardware crypto engine.
+
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * Author: Andreas Westin <andreas.westin@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/klist.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/crypto.h>
+
+#include <linux/regulator/consumer.h>
+#include <linux/dmaengine.h>
+#include <linux/bitops.h>
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/algapi.h>
+
+#include <mach/crypto-ux500.h>
+#include <mach/hardware.h>
+
+#include "hash_alg.h"
+
+#define DEV_DBG_NAME "hashX hashX:"
+
+static int hash_mode;
+module_param(hash_mode, int, 0);
+MODULE_PARM_DESC(hash_mode, "CPU or DMA mode. CPU = 0 (default), DMA = 1");
+
+/**
+ * Pre-calculated empty message digests.
+ */
+static u8 zero_message_hash_sha1[SHA1_DIGEST_SIZE] = {
+	0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d,
+	0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90,
+	0xaf, 0xd8, 0x07, 0x09
+};
+
+static u8 zero_message_hash_sha256[SHA256_DIGEST_SIZE] = {
+	0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
+	0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+	0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
+	0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55
+};
+
+/* HMAC-SHA1, no key */
+static u8 zero_message_hmac_sha1[SHA1_DIGEST_SIZE] = {
+	0xfb, 0xdb, 0x1d, 0x1b, 0x18, 0xaa, 0x6c, 0x08,
+	0x32, 0x4b, 0x7d, 0x64, 0xb7, 0x1f, 0xb7, 0x63,
+	0x70, 0x69, 0x0e, 0x1d
+};
+
+/* HMAC-SHA256, no key */
+static u8 zero_message_hmac_sha256[SHA256_DIGEST_SIZE] = {
+	0xb6, 0x13, 0x67, 0x9a, 0x08, 0x14, 0xd9, 0xec,
+	0x77, 0x2f, 0x95, 0xd7, 0x78, 0xc3, 0x5f, 0xc5,
+	0xff, 0x16, 0x97, 0xc4, 0x93, 0x71, 0x56, 0x53,
+	0xc6, 0xc7, 0x12, 0x14, 0x42, 0x92, 0xc5, 0xad
+};
+
+/**
+ * struct hash_driver_data - data specific to the driver.
+ *
+ * @device_list:	A list of registered devices to choose from.
+ * @device_allocation:	A semaphore initialized with number of devices.
+ */
+struct hash_driver_data {
+	struct klist		device_list;
+	struct semaphore	device_allocation;
+};
+
+static struct hash_driver_data	driver_data;
+
+/* Declaration of functions */
+/**
+ * hash_messagepad - Pads a message and write the nblw bits.
+ * @device_data:	Structure for the hash device.
+ * @message:		Last word of a message
+ * @index_bytes:	The number of bytes in the last message
+ *
+ * This function manages the final part of the digest calculation, when less
+ * than 512 bits (64 bytes) remain in message. This means index_bytes < 64.
+ *
+ */
+static void hash_messagepad(struct hash_device_data *device_data,
+		const u32 *message, u8 index_bytes);
+
+/**
+ * release_hash_device - Releases a previously allocated hash device.
+ * @device_data:	Structure for the hash device.
+ *
+ */
+static void release_hash_device(struct hash_device_data *device_data)
+{
+	spin_lock(&device_data->ctx_lock);
+	device_data->current_ctx->device = NULL;
+	device_data->current_ctx = NULL;
+	spin_unlock(&device_data->ctx_lock);
+
+	/*
+	 * The down_interruptible part for this semaphore is called in
+	 * cryp_get_device_data.
+	 */
+	up(&driver_data.device_allocation);
+}
+
+static void hash_dma_setup_channel(struct hash_device_data *device_data,
+				struct device *dev)
+{
+	struct hash_platform_data *platform_data = dev->platform_data;
+	dma_cap_zero(device_data->dma.mask);
+	dma_cap_set(DMA_SLAVE, device_data->dma.mask);
+
+	device_data->dma.cfg_mem2hash = platform_data->mem_to_engine;
+	device_data->dma.chan_mem2hash =
+		dma_request_channel(device_data->dma.mask,
+				platform_data->dma_filter,
+				device_data->dma.cfg_mem2hash);
+
+	init_completion(&device_data->dma.complete);
+}
+
+static void hash_dma_callback(void *data)
+{
+	struct hash_ctx *ctx = (struct hash_ctx *) data;
+
+	complete(&ctx->device->dma.complete);
+}
+
+static int hash_set_dma_transfer(struct hash_ctx *ctx, struct scatterlist *sg,
+		int len, enum dma_data_direction direction)
+{
+	struct dma_async_tx_descriptor *desc = NULL;
+	struct dma_chan *channel = NULL;
+	dma_cookie_t cookie;
+
+	if (direction != DMA_TO_DEVICE) {
+		dev_err(ctx->device->dev, "[%s] Invalid DMA direction",
+				__func__);
+		return -EFAULT;
+	}
+
+	sg->length = ALIGN(sg->length, HASH_DMA_ALIGN_SIZE);
+
+	channel = ctx->device->dma.chan_mem2hash;
+	ctx->device->dma.sg = sg;
+	ctx->device->dma.sg_len = dma_map_sg(channel->device->dev,
+			ctx->device->dma.sg, ctx->device->dma.nents,
+			direction);
+
+	if (!ctx->device->dma.sg_len) {
+		dev_err(ctx->device->dev,
+				"[%s]: Could not map the sg list (TO_DEVICE)",
+				__func__);
+		return -EFAULT;
+	}
+
+	dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
+			"(TO_DEVICE)", __func__);
+	desc = channel->device->device_prep_slave_sg(channel,
+			ctx->device->dma.sg, ctx->device->dma.sg_len,
+			direction, DMA_CTRL_ACK | DMA_PREP_INTERRUPT, NULL);
+	if (!desc) {
+		dev_err(ctx->device->dev,
+			"[%s]: device_prep_slave_sg() failed!", __func__);
+		return -EFAULT;
+	}
+
+	desc->callback = hash_dma_callback;
+	desc->callback_param = ctx;
+
+	cookie = desc->tx_submit(desc);
+	dma_async_issue_pending(channel);
+
+	return 0;
+}
+
+static void hash_dma_done(struct hash_ctx *ctx)
+{
+	struct dma_chan *chan;
+
+	chan = ctx->device->dma.chan_mem2hash;
+	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+	dma_unmap_sg(chan->device->dev, ctx->device->dma.sg,
+			ctx->device->dma.sg_len, DMA_TO_DEVICE);
+
+}
+
+static int hash_dma_write(struct hash_ctx *ctx,
+		struct scatterlist *sg, int len)
+{
+	int error = hash_set_dma_transfer(ctx, sg, len, DMA_TO_DEVICE);
+	if (error) {
+		dev_dbg(ctx->device->dev, "[%s]: hash_set_dma_transfer() "
+			"failed", __func__);
+		return error;
+	}
+
+	return len;
+}
+
+/**
+ * get_empty_message_digest - Returns a pre-calculated digest for
+ * the empty message.
+ * @device_data:	Structure for the hash device.
+ * @zero_hash:		Buffer to return the empty message digest.
+ * @zero_hash_size:	Hash size of the empty message digest.
+ * @zero_digest:	True if zero_digest returned.
+ */
+static int get_empty_message_digest(
+		struct hash_device_data *device_data,
+		u8 *zero_hash, u32 *zero_hash_size, bool *zero_digest)
+{
+	int ret = 0;
+	struct hash_ctx *ctx = device_data->current_ctx;
+	*zero_digest = false;
+
+	/**
+	 * Caller responsible for ctx != NULL.
+	 */
+
+	if (HASH_OPER_MODE_HASH == ctx->config.oper_mode) {
+		if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
+			memcpy(zero_hash, &zero_message_hash_sha1[0],
+					SHA1_DIGEST_SIZE);
+			*zero_hash_size = SHA1_DIGEST_SIZE;
+			*zero_digest = true;
+		} else if (HASH_ALGO_SHA256 ==
+				ctx->config.algorithm) {
+			memcpy(zero_hash, &zero_message_hash_sha256[0],
+					SHA256_DIGEST_SIZE);
+			*zero_hash_size = SHA256_DIGEST_SIZE;
+			*zero_digest = true;
+		} else {
+			dev_err(device_data->dev, "[%s] "
+					"Incorrect algorithm!"
+					, __func__);
+			ret = -EINVAL;
+			goto out;
+		}
+	} else if (HASH_OPER_MODE_HMAC == ctx->config.oper_mode) {
+		if (!ctx->keylen) {
+			if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
+				memcpy(zero_hash, &zero_message_hmac_sha1[0],
+						SHA1_DIGEST_SIZE);
+				*zero_hash_size = SHA1_DIGEST_SIZE;
+				*zero_digest = true;
+			} else if (HASH_ALGO_SHA256 == ctx->config.algorithm) {
+				memcpy(zero_hash, &zero_message_hmac_sha256[0],
+						SHA256_DIGEST_SIZE);
+				*zero_hash_size = SHA256_DIGEST_SIZE;
+				*zero_digest = true;
+			} else {
+				dev_err(device_data->dev, "[%s] "
+						"Incorrect algorithm!"
+						, __func__);
+				ret = -EINVAL;
+				goto out;
+			}
+		} else {
+			dev_dbg(device_data->dev, "[%s] Continue hash "
+					"calculation, since hmac key avalable",
+					__func__);
+		}
+	}
+out:
+
+	return ret;
+}
+
+/**
+ * hash_disable_power - Request to disable power and clock.
+ * @device_data:	Structure for the hash device.
+ * @save_device_state:	If true, saves the current hw state.
+ *
+ * This function request for disabling power (regulator) and clock,
+ * and could also save current hw state.
+ */
+static int hash_disable_power(
+		struct hash_device_data *device_data,
+		bool			save_device_state)
+{
+	int ret = 0;
+	struct device *dev = device_data->dev;
+
+	spin_lock(&device_data->power_state_lock);
+	if (!device_data->power_state)
+		goto out;
+
+	if (save_device_state) {
+		hash_save_state(device_data,
+				&device_data->state);
+		device_data->restore_dev_state = true;
+	}
+
+	clk_disable(device_data->clk);
+	ret = regulator_disable(device_data->regulator);
+	if (ret)
+		dev_err(dev, "[%s] regulator_disable() failed!", __func__);
+
+	device_data->power_state = false;
+
+out:
+	spin_unlock(&device_data->power_state_lock);
+
+	return ret;
+}
+
+/**
+ * hash_enable_power - Request to enable power and clock.
+ * @device_data:		Structure for the hash device.
+ * @restore_device_state:	If true, restores a previous saved hw state.
+ *
+ * This function request for enabling power (regulator) and clock,
+ * and could also restore a previously saved hw state.
+ */
+static int hash_enable_power(
+		struct hash_device_data *device_data,
+		bool			restore_device_state)
+{
+	int ret = 0;
+	struct device *dev = device_data->dev;
+
+	spin_lock(&device_data->power_state_lock);
+	if (!device_data->power_state) {
+		ret = regulator_enable(device_data->regulator);
+		if (ret) {
+			dev_err(dev, "[%s]: regulator_enable() failed!",
+					__func__);
+			goto out;
+		}
+		ret = clk_enable(device_data->clk);
+		if (ret) {
+			dev_err(dev, "[%s]: clk_enable() failed!",
+					__func__);
+			ret = regulator_disable(
+					device_data->regulator);
+			goto out;
+		}
+		device_data->power_state = true;
+	}
+
+	if (device_data->restore_dev_state) {
+		if (restore_device_state) {
+			device_data->restore_dev_state = false;
+			hash_resume_state(device_data,
+				&device_data->state);
+		}
+	}
+out:
+	spin_unlock(&device_data->power_state_lock);
+
+	return ret;
+}
+
+/**
+ * hash_get_device_data - Checks for an available hash device and return it.
+ * @hash_ctx:		Structure for the hash context.
+ * @device_data:	Structure for the hash device.
+ *
+ * This function check for an available hash device and return it to
+ * the caller.
+ * Note! Caller need to release the device, calling up().
+ */
+static int hash_get_device_data(struct hash_ctx *ctx,
+				struct hash_device_data **device_data)
+{
+	int			ret;
+	struct klist_iter	device_iterator;
+	struct klist_node	*device_node;
+	struct hash_device_data *local_device_data = NULL;
+
+	/* Wait until a device is available */
+	ret = down_interruptible(&driver_data.device_allocation);
+	if (ret)
+		return ret;  /* Interrupted */
+
+	/* Select a device */
+	klist_iter_init(&driver_data.device_list, &device_iterator);
+	device_node = klist_next(&device_iterator);
+	while (device_node) {
+		local_device_data = container_of(device_node,
+					   struct hash_device_data, list_node);
+		spin_lock(&local_device_data->ctx_lock);
+		/* current_ctx allocates a device, NULL = unallocated */
+		if (local_device_data->current_ctx) {
+			device_node = klist_next(&device_iterator);
+		} else {
+			local_device_data->current_ctx = ctx;
+			ctx->device = local_device_data;
+			spin_unlock(&local_device_data->ctx_lock);
+			break;
+		}
+		spin_unlock(&local_device_data->ctx_lock);
+	}
+	klist_iter_exit(&device_iterator);
+
+	if (!device_node) {
+		/**
+		 * No free device found.
+		 * Since we allocated a device with down_interruptible, this
+		 * should not be able to happen.
+		 * Number of available devices, which are contained in
+		 * device_allocation, is therefore decremented by not doing
+		 * an up(device_allocation).
+		 */
+		return -EBUSY;
+	}
+
+	*device_data = local_device_data;
+
+	return 0;
+}
+
+/**
+ * hash_hw_write_key - Writes the key to the hardware registries.
+ *
+ * @device_data:	Structure for the hash device.
+ * @key:		Key to be written.
+ * @keylen:		The lengt of the key.
+ *
+ * Note! This function DOES NOT write to the NBLW registry, even though
+ * specified in the the hw design spec. Either due to incorrect info in the
+ * spec or due to a bug in the hw.
+ */
+static void hash_hw_write_key(struct hash_device_data *device_data,
+		const u8 *key, unsigned int keylen)
+{
+	u32 word = 0;
+	int nwords = 1;
+
+	HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+
+	while (keylen >= 4) {
+		u32 *key_word = (u32 *)key;
+
+		HASH_SET_DIN(key_word, nwords);
+		keylen -= 4;
+		key += 4;
+	}
+
+	/* Take care of the remaining bytes in the last word */
+	if (keylen) {
+		word = 0;
+		while (keylen) {
+			word |= (key[keylen - 1] << (8 * (keylen - 1)));
+			keylen--;
+		}
+
+		HASH_SET_DIN(&word, nwords);
+	}
+
+	while (device_data->base->str & HASH_STR_DCAL_MASK)
+		cpu_relax();
+
+	HASH_SET_DCAL;
+
+	while (device_data->base->str & HASH_STR_DCAL_MASK)
+		cpu_relax();
+}
+
+/**
+ * init_hash_hw - Initialise the hash hardware for a new calculation.
+ * @device_data:	Structure for the hash device.
+ * @ctx:		The hash context.
+ *
+ * This function will enable the bits needed to clear and start a new
+ * calculation.
+ */
+static int init_hash_hw(struct hash_device_data *device_data,
+		struct hash_ctx *ctx)
+{
+	int ret = 0;
+
+	ret = hash_setconfiguration(device_data, &ctx->config);
+	if (ret) {
+		dev_err(device_data->dev, "[%s] hash_setconfiguration() "
+				"failed!", __func__);
+		return ret;
+	}
+
+	hash_begin(device_data, ctx);
+
+	if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC)
+		hash_hw_write_key(device_data, ctx->key, ctx->keylen);
+
+	return ret;
+}
+
+/**
+ * hash_get_nents - Return number of entries (nents) in scatterlist (sg).
+ *
+ * @sg:		Scatterlist.
+ * @size:	Size in bytes.
+ * @aligned:	True if sg data aligned to work in DMA mode.
+ *
+ */
+static int hash_get_nents(struct scatterlist *sg, int size, bool *aligned)
+{
+	int nents = 0;
+	bool aligned_data = true;
+
+	while (size > 0 && sg) {
+		nents++;
+		size -= sg->length;
+
+		/* hash_set_dma_transfer will align last nent */
+		if ((aligned && !IS_ALIGNED(sg->offset, HASH_DMA_ALIGN_SIZE))
+			|| (!IS_ALIGNED(sg->length, HASH_DMA_ALIGN_SIZE) &&
+				size > 0))
+			aligned_data = false;
+
+		sg = sg_next(sg);
+	}
+
+	if (aligned)
+		*aligned = aligned_data;
+
+	if (size != 0)
+		return -EFAULT;
+
+	return nents;
+}
+
+/**
+ * hash_dma_valid_data - checks for dma valid sg data.
+ * @sg:		Scatterlist.
+ * @datasize:	Datasize in bytes.
+ *
+ * NOTE! This function checks for dma valid sg data, since dma
+ * only accept datasizes of even wordsize.
+ */
+static bool hash_dma_valid_data(struct scatterlist *sg, int datasize)
+{
+	bool aligned;
+
+	/* Need to include at least one nent, else error */
+	if (hash_get_nents(sg, datasize, &aligned) < 1)
+		return false;
+
+	return aligned;
+}
+
+/**
+ * hash_init - Common hash init function for SHA1/SHA2 (SHA256).
+ * @req: The hash request for the job.
+ *
+ * Initialize structures.
+ */
+static int hash_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+
+	if (!ctx->key)
+		ctx->keylen = 0;
+
+	memset(&req_ctx->state, 0, sizeof(struct hash_state));
+	req_ctx->updated = 0;
+	if (hash_mode == HASH_MODE_DMA) {
+		if (req->nbytes < HASH_DMA_ALIGN_SIZE) {
+			req_ctx->dma_mode = false; /* Don't use DMA */
+
+			pr_debug(DEV_DBG_NAME " [%s] DMA mode, but direct "
+					"to CPU mode for data size < %d",
+					__func__, HASH_DMA_ALIGN_SIZE);
+		} else {
+			if (req->nbytes >= HASH_DMA_PERFORMANCE_MIN_SIZE &&
+					hash_dma_valid_data(req->src,
+						req->nbytes)) {
+				req_ctx->dma_mode = true;
+			} else {
+				req_ctx->dma_mode = false;
+				pr_debug(DEV_DBG_NAME " [%s] DMA mode, but use"
+						" CPU mode for datalength < %d"
+						" or non-aligned data, except "
+						"in last nent", __func__,
+						HASH_DMA_PERFORMANCE_MIN_SIZE);
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ * hash_processblock - This function processes a single block of 512 bits (64
+ *                     bytes), word aligned, starting at message.
+ * @device_data:	Structure for the hash device.
+ * @message:		Block (512 bits) of message to be written to
+ *			the HASH hardware.
+ *
+ */
+static void hash_processblock(
+		struct hash_device_data *device_data,
+		const u32 *message, int length)
+{
+	int len = length / HASH_BYTES_PER_WORD;
+	/*
+	 * NBLW bits. Reset the number of bits in last word (NBLW).
+	 */
+	HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+
+	/*
+	 * Write message data to the HASH_DIN register.
+	 */
+	HASH_SET_DIN(message, len);
+}
+
+/**
+ * hash_messagepad - Pads a message and write the nblw bits.
+ * @device_data:	Structure for the hash device.
+ * @message:		Last word of a message.
+ * @index_bytes:	The number of bytes in the last message.
+ *
+ * This function manages the final part of the digest calculation, when less
+ * than 512 bits (64 bytes) remain in message. This means index_bytes < 64.
+ *
+ */
+static void hash_messagepad(struct hash_device_data *device_data,
+		const u32 *message, u8 index_bytes)
+{
+	int nwords = 1;
+
+	/*
+	 * Clear hash str register, only clear NBLW
+	 * since DCAL will be reset by hardware.
+	 */
+	HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+
+	/* Main loop */
+	while (index_bytes >= 4) {
+		HASH_SET_DIN(message, nwords);
+		index_bytes -= 4;
+		message++;
+	}
+
+	if (index_bytes)
+		HASH_SET_DIN(message, nwords);
+
+	while (device_data->base->str & HASH_STR_DCAL_MASK)
+		cpu_relax();
+
+	/* num_of_bytes == 0 => NBLW <- 0 (32 bits valid in DATAIN) */
+	HASH_SET_NBLW(index_bytes * 8);
+	dev_dbg(device_data->dev, "[%s] DIN=0x%08x NBLW=%d", __func__,
+			readl_relaxed(&device_data->base->din),
+			(int)(readl_relaxed(&device_data->base->str) &
+				HASH_STR_NBLW_MASK));
+	HASH_SET_DCAL;
+	dev_dbg(device_data->dev, "[%s] after dcal -> DIN=0x%08x NBLW=%d",
+			__func__, readl_relaxed(&device_data->base->din),
+			(int)(readl_relaxed(&device_data->base->str) &
+				HASH_STR_NBLW_MASK));
+
+	while (device_data->base->str & HASH_STR_DCAL_MASK)
+		cpu_relax();
+}
+
+/**
+ * hash_incrementlength - Increments the length of the current message.
+ * @ctx: Hash context
+ * @incr: Length of message processed already
+ *
+ * Overflow cannot occur, because conditions for overflow are checked in
+ * hash_hw_update.
+ */
+static void hash_incrementlength(struct hash_req_ctx *ctx, u32 incr)
+{
+	ctx->state.length.low_word += incr;
+
+	/* Check for wrap-around */
+	if (ctx->state.length.low_word < incr)
+		ctx->state.length.high_word++;
+}
+
+/**
+ * hash_setconfiguration - Sets the required configuration for the hash
+ *                         hardware.
+ * @device_data:	Structure for the hash device.
+ * @config:		Pointer to a configuration structure.
+ */
+int hash_setconfiguration(struct hash_device_data *device_data,
+		struct hash_config *config)
+{
+	int ret = 0;
+
+	if (config->algorithm != HASH_ALGO_SHA1 &&
+	    config->algorithm != HASH_ALGO_SHA256)
+		return -EPERM;
+
+	/*
+	 * DATAFORM bits. Set the DATAFORM bits to 0b11, which means the data
+	 * to be written to HASH_DIN is considered as 32 bits.
+	 */
+	HASH_SET_DATA_FORMAT(config->data_format);
+
+	/*
+	 * ALGO bit. Set to 0b1 for SHA-1 and 0b0 for SHA-256
+	 */
+	switch (config->algorithm) {
+	case HASH_ALGO_SHA1:
+		HASH_SET_BITS(&device_data->base->cr, HASH_CR_ALGO_MASK);
+		break;
+
+	case HASH_ALGO_SHA256:
+		HASH_CLEAR_BITS(&device_data->base->cr, HASH_CR_ALGO_MASK);
+		break;
+
+	default:
+		dev_err(device_data->dev, "[%s] Incorrect algorithm.",
+				__func__);
+		return -EPERM;
+	}
+
+	/*
+	 * MODE bit. This bit selects between HASH or HMAC mode for the
+	 * selected algorithm. 0b0 = HASH and 0b1 = HMAC.
+	 */
+	if (HASH_OPER_MODE_HASH == config->oper_mode)
+		HASH_CLEAR_BITS(&device_data->base->cr,
+				HASH_CR_MODE_MASK);
+	else if (HASH_OPER_MODE_HMAC == config->oper_mode) {
+		HASH_SET_BITS(&device_data->base->cr,
+				HASH_CR_MODE_MASK);
+		if (device_data->current_ctx->keylen > HASH_BLOCK_SIZE) {
+			/* Truncate key to blocksize */
+			dev_dbg(device_data->dev, "[%s] LKEY set", __func__);
+			HASH_SET_BITS(&device_data->base->cr,
+					HASH_CR_LKEY_MASK);
+		} else {
+			dev_dbg(device_data->dev, "[%s] LKEY cleared",
+					__func__);
+			HASH_CLEAR_BITS(&device_data->base->cr,
+					HASH_CR_LKEY_MASK);
+		}
+	} else {	/* Wrong hash mode */
+		ret = -EPERM;
+		dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+				__func__);
+	}
+	return ret;
+}
+
+/**
+ * hash_begin - This routine resets some globals and initializes the hash
+ *              hardware.
+ * @device_data:	Structure for the hash device.
+ * @ctx:		Hash context.
+ */
+void hash_begin(struct hash_device_data *device_data, struct hash_ctx *ctx)
+{
+	/* HW and SW initializations */
+	/* Note: there is no need to initialize buffer and digest members */
+
+	while (device_data->base->str & HASH_STR_DCAL_MASK)
+		cpu_relax();
+
+	/*
+	 * INIT bit. Set this bit to 0b1 to reset the HASH processor core and
+	 * prepare the initialize the HASH accelerator to compute the message
+	 * digest of a new message.
+	 */
+	HASH_INITIALIZE;
+
+	/*
+	 * NBLW bits. Reset the number of bits in last word (NBLW).
+	 */
+	HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+}
+
+int hash_process_data(
+		struct hash_device_data *device_data,
+		struct hash_ctx *ctx, struct hash_req_ctx *req_ctx,
+		int msg_length, u8 *data_buffer, u8 *buffer, u8 *index)
+{
+	int ret = 0;
+	u32 count;
+
+	do {
+		if ((*index + msg_length) < HASH_BLOCK_SIZE) {
+			for (count = 0; count < msg_length; count++) {
+				buffer[*index + count] =
+					*(data_buffer + count);
+			}
+			*index += msg_length;
+			msg_length = 0;
+		} else {
+			if (req_ctx->updated) {
+
+				ret = hash_resume_state(device_data,
+						&device_data->state);
+				memmove(req_ctx->state.buffer,
+						device_data->state.buffer,
+						HASH_BLOCK_SIZE / sizeof(u32));
+				if (ret) {
+					dev_err(device_data->dev, "[%s] "
+							"hash_resume_state()"
+							" failed!", __func__);
+					goto out;
+				}
+			} else {
+				ret = init_hash_hw(device_data, ctx);
+				if (ret) {
+					dev_err(device_data->dev, "[%s] "
+							"init_hash_hw()"
+							" failed!", __func__);
+					goto out;
+				}
+				req_ctx->updated = 1;
+			}
+			/*
+			 * If 'data_buffer' is four byte aligned and
+			 * local buffer does not have any data, we can
+			 * write data directly from 'data_buffer' to
+			 * HW peripheral, otherwise we first copy data
+			 * to a local buffer
+			 */
+			if ((0 == (((u32)data_buffer) % 4))
+					&& (0 == *index))
+				hash_processblock(device_data,
+						(const u32 *)
+						data_buffer, HASH_BLOCK_SIZE);
+			else {
+				for (count = 0; count <
+						(u32)(HASH_BLOCK_SIZE -
+							*index);
+						count++) {
+					buffer[*index + count] =
+						*(data_buffer + count);
+				}
+				hash_processblock(device_data,
+						(const u32 *)buffer,
+						HASH_BLOCK_SIZE);
+			}
+			hash_incrementlength(req_ctx, HASH_BLOCK_SIZE);
+			data_buffer += (HASH_BLOCK_SIZE - *index);
+
+			msg_length -= (HASH_BLOCK_SIZE - *index);
+			*index = 0;
+
+			ret = hash_save_state(device_data,
+					&device_data->state);
+
+			memmove(device_data->state.buffer,
+					req_ctx->state.buffer,
+					HASH_BLOCK_SIZE / sizeof(u32));
+			if (ret) {
+				dev_err(device_data->dev, "[%s] "
+						"hash_save_state()"
+						" failed!", __func__);
+				goto out;
+			}
+		}
+	} while (msg_length != 0);
+out:
+
+	return ret;
+}
+
+/**
+ * hash_dma_final - The hash dma final function for SHA1/SHA256.
+ * @req:	The hash request for the job.
+ */
+static int hash_dma_final(struct ahash_request *req)
+{
+	int ret = 0;
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+	struct hash_device_data *device_data;
+	u8 digest[SHA256_DIGEST_SIZE];
+	int bytes_written = 0;
+
+	ret = hash_get_device_data(ctx, &device_data);
+	if (ret)
+		return ret;
+
+	dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+
+	if (req_ctx->updated) {
+		ret = hash_resume_state(device_data, &device_data->state);
+
+		if (ret) {
+			dev_err(device_data->dev, "[%s] hash_resume_state() "
+					"failed!", __func__);
+			goto out;
+		}
+
+	}
+
+	if (!req_ctx->updated) {
+		ret = hash_setconfiguration(device_data, &ctx->config);
+		if (ret) {
+			dev_err(device_data->dev, "[%s] "
+					"hash_setconfiguration() failed!",
+					__func__);
+			goto out;
+		}
+
+		/* Enable DMA input */
+		if (hash_mode != HASH_MODE_DMA || !req_ctx->dma_mode) {
+			HASH_CLEAR_BITS(&device_data->base->cr,
+					HASH_CR_DMAE_MASK);
+		} else {
+			HASH_SET_BITS(&device_data->base->cr,
+					HASH_CR_DMAE_MASK);
+			HASH_SET_BITS(&device_data->base->cr,
+					HASH_CR_PRIVN_MASK);
+		}
+
+		HASH_INITIALIZE;
+
+		if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC)
+			hash_hw_write_key(device_data, ctx->key, ctx->keylen);
+
+		/* Number of bits in last word = (nbytes * 8) % 32 */
+		HASH_SET_NBLW((req->nbytes * 8) % 32);
+		req_ctx->updated = 1;
+	}
+
+	/* Store the nents in the dma struct. */
+	ctx->device->dma.nents = hash_get_nents(req->src, req->nbytes, NULL);
+	if (!ctx->device->dma.nents) {
+		dev_err(device_data->dev, "[%s] "
+				"ctx->device->dma.nents = 0", __func__);
+		goto out;
+	}
+
+	bytes_written = hash_dma_write(ctx, req->src, req->nbytes);
+	if (bytes_written != req->nbytes) {
+		dev_err(device_data->dev, "[%s] "
+				"hash_dma_write() failed!", __func__);
+		goto out;
+	}
+
+	wait_for_completion(&ctx->device->dma.complete);
+	hash_dma_done(ctx);
+
+	while (device_data->base->str & HASH_STR_DCAL_MASK)
+		cpu_relax();
+
+	if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC && ctx->key) {
+		unsigned int keylen = ctx->keylen;
+		u8 *key = ctx->key;
+
+		dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
+				ctx->keylen);
+		hash_hw_write_key(device_data, key, keylen);
+	}
+
+	hash_get_digest(device_data, digest, ctx->config.algorithm);
+	memcpy(req->result, digest, ctx->digestsize);
+
+out:
+	release_hash_device(device_data);
+
+	/**
+	 * Allocated in setkey, and only used in HMAC.
+	 */
+	kfree(ctx->key);
+
+	return ret;
+}
+
+/**
+ * hash_hw_final - The final hash calculation function
+ * @req:	The hash request for the job.
+ */
+int hash_hw_final(struct ahash_request *req)
+{
+	int ret = 0;
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+	struct hash_device_data *device_data;
+	u8 digest[SHA256_DIGEST_SIZE];
+
+	ret = hash_get_device_data(ctx, &device_data);
+	if (ret)
+		return ret;
+
+	dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+
+	if (req_ctx->updated) {
+		ret = hash_resume_state(device_data, &device_data->state);
+
+		if (ret) {
+			dev_err(device_data->dev, "[%s] hash_resume_state() "
+					"failed!", __func__);
+			goto out;
+		}
+	} else if (req->nbytes == 0 && ctx->keylen == 0) {
+		u8 zero_hash[SHA256_DIGEST_SIZE];
+		u32 zero_hash_size = 0;
+		bool zero_digest = false;
+		/**
+		 * Use a pre-calculated empty message digest
+		 * (workaround since hw return zeroes, hw bug!?)
+		 */
+		ret = get_empty_message_digest(device_data, &zero_hash[0],
+				&zero_hash_size, &zero_digest);
+		if (!ret && likely(zero_hash_size == ctx->digestsize) &&
+				zero_digest) {
+			memcpy(req->result, &zero_hash[0], ctx->digestsize);
+			goto out;
+		} else if (!ret && !zero_digest) {
+			dev_dbg(device_data->dev, "[%s] HMAC zero msg with "
+					"key, continue...", __func__);
+		} else {
+			dev_err(device_data->dev, "[%s] ret=%d, or wrong "
+					"digest size? %s", __func__, ret,
+					(zero_hash_size == ctx->digestsize) ?
+					"true" : "false");
+			/* Return error */
+			goto out;
+		}
+	} else if (req->nbytes == 0 && ctx->keylen > 0) {
+		dev_err(device_data->dev, "[%s] Empty message with "
+				"keylength > 0, NOT supported.", __func__);
+		goto out;
+	}
+
+	if (!req_ctx->updated) {
+		ret = init_hash_hw(device_data, ctx);
+		if (ret) {
+			dev_err(device_data->dev, "[%s] init_hash_hw() "
+					"failed!", __func__);
+			goto out;
+		}
+	}
+
+	if (req_ctx->state.index) {
+		hash_messagepad(device_data, req_ctx->state.buffer,
+				req_ctx->state.index);
+	} else {
+		HASH_SET_DCAL;
+		while (device_data->base->str & HASH_STR_DCAL_MASK)
+			cpu_relax();
+	}
+
+	if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC && ctx->key) {
+		unsigned int keylen = ctx->keylen;
+		u8 *key = ctx->key;
+
+		dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
+				ctx->keylen);
+		hash_hw_write_key(device_data, key, keylen);
+	}
+
+	hash_get_digest(device_data, digest, ctx->config.algorithm);
+	memcpy(req->result, digest, ctx->digestsize);
+
+out:
+	release_hash_device(device_data);
+
+	/**
+	 * Allocated in setkey, and only used in HMAC.
+	 */
+	kfree(ctx->key);
+
+	return ret;
+}
+
+/**
+ * hash_hw_update - Updates current HASH computation hashing another part of
+ *                  the message.
+ * @req:	Byte array containing the message to be hashed (caller
+ *		allocated).
+ */
+int hash_hw_update(struct ahash_request *req)
+{
+	int ret = 0;
+	u8 index = 0;
+	u8 *buffer;
+	struct hash_device_data *device_data;
+	u8 *data_buffer;
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+	struct crypto_hash_walk walk;
+	int msg_length = crypto_hash_walk_first(req, &walk);
+
+	/* Empty message ("") is correct indata */
+	if (msg_length == 0)
+		return ret;
+
+	index = req_ctx->state.index;
+	buffer = (u8 *)req_ctx->state.buffer;
+
+	/* Check if ctx->state.length + msg_length
+	   overflows */
+	if (msg_length > (req_ctx->state.length.low_word + msg_length) &&
+			HASH_HIGH_WORD_MAX_VAL ==
+			req_ctx->state.length.high_word) {
+		pr_err(DEV_DBG_NAME " [%s] HASH_MSG_LENGTH_OVERFLOW!",
+				__func__);
+		return -EPERM;
+	}
+
+	ret = hash_get_device_data(ctx, &device_data);
+	if (ret)
+		return ret;
+
+	/* Main loop */
+	while (0 != msg_length) {
+		data_buffer = walk.data;
+		ret = hash_process_data(device_data, ctx, req_ctx, msg_length,
+				data_buffer, buffer, &index);
+
+		if (ret) {
+			dev_err(device_data->dev, "[%s] hash_internal_hw_"
+					"update() failed!", __func__);
+			goto out;
+		}
+
+		msg_length = crypto_hash_walk_done(&walk, 0);
+	}
+
+	req_ctx->state.index = index;
+	dev_dbg(device_data->dev, "[%s] indata length=%d, bin=%d))",
+			__func__, req_ctx->state.index,
+			req_ctx->state.bit_index);
+
+out:
+	release_hash_device(device_data);
+
+	return ret;
+}
+
+/**
+ * hash_resume_state - Function that resumes the state of an calculation.
+ * @device_data:	Pointer to the device structure.
+ * @device_state:	The state to be restored in the hash hardware
+ */
+int hash_resume_state(struct hash_device_data *device_data,
+		const struct hash_state *device_state)
+{
+	u32 temp_cr;
+	s32 count;
+	int hash_mode = HASH_OPER_MODE_HASH;
+
+	if (NULL == device_state) {
+		dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+				__func__);
+		return -EPERM;
+	}
+
+	/* Check correctness of index and length members */
+	if (device_state->index > HASH_BLOCK_SIZE
+	    || (device_state->length.low_word % HASH_BLOCK_SIZE) != 0) {
+		dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+				__func__);
+		return -EPERM;
+	}
+
+	/*
+	 * INIT bit. Set this bit to 0b1 to reset the HASH processor core and
+	 * prepare the initialize the HASH accelerator to compute the message
+	 * digest of a new message.
+	 */
+	HASH_INITIALIZE;
+
+	temp_cr = device_state->temp_cr;
+	writel_relaxed(temp_cr & HASH_CR_RESUME_MASK, &device_data->base->cr);
+
+	if (device_data->base->cr & HASH_CR_MODE_MASK)
+		hash_mode = HASH_OPER_MODE_HMAC;
+	else
+		hash_mode = HASH_OPER_MODE_HASH;
+
+	for (count = 0; count < HASH_CSR_COUNT; count++) {
+		if ((count >= 36) && (hash_mode == HASH_OPER_MODE_HASH))
+			break;
+
+		writel_relaxed(device_state->csr[count],
+				&device_data->base->csrx[count]);
+	}
+
+	writel_relaxed(device_state->csfull, &device_data->base->csfull);
+	writel_relaxed(device_state->csdatain, &device_data->base->csdatain);
+
+	writel_relaxed(device_state->str_reg, &device_data->base->str);
+	writel_relaxed(temp_cr, &device_data->base->cr);
+
+	return 0;
+}
+
+/**
+ * hash_save_state - Function that saves the state of hardware.
+ * @device_data:	Pointer to the device structure.
+ * @device_state:	The strucure where the hardware state should be saved.
+ */
+int hash_save_state(struct hash_device_data *device_data,
+		struct hash_state *device_state)
+{
+	u32 temp_cr;
+	u32 count;
+	int hash_mode = HASH_OPER_MODE_HASH;
+
+	if (NULL == device_state) {
+		dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+				__func__);
+		return -ENOTSUPP;
+	}
+
+	/* Write dummy value to force digest intermediate calculation. This
+	 * actually makes sure that there isn't any ongoing calculation in the
+	 * hardware.
+	 */
+	while (device_data->base->str & HASH_STR_DCAL_MASK)
+		cpu_relax();
+
+	temp_cr = readl_relaxed(&device_data->base->cr);
+
+	device_state->str_reg = readl_relaxed(&device_data->base->str);
+
+	device_state->din_reg = readl_relaxed(&device_data->base->din);
+
+	if (device_data->base->cr & HASH_CR_MODE_MASK)
+		hash_mode = HASH_OPER_MODE_HMAC;
+	else
+		hash_mode = HASH_OPER_MODE_HASH;
+
+	for (count = 0; count < HASH_CSR_COUNT; count++) {
+		if ((count >= 36) && (hash_mode == HASH_OPER_MODE_HASH))
+			break;
+
+		device_state->csr[count] =
+			readl_relaxed(&device_data->base->csrx[count]);
+	}
+
+	device_state->csfull = readl_relaxed(&device_data->base->csfull);
+	device_state->csdatain = readl_relaxed(&device_data->base->csdatain);
+
+	device_state->temp_cr = temp_cr;
+
+	return 0;
+}
+
+/**
+ * hash_check_hw - This routine checks for peripheral Ids and PCell Ids.
+ * @device_data:
+ *
+ */
+int hash_check_hw(struct hash_device_data *device_data)
+{
+	/* Checking Peripheral Ids  */
+	if (HASH_P_ID0 == readl_relaxed(&device_data->base->periphid0)
+		&& HASH_P_ID1 == readl_relaxed(&device_data->base->periphid1)
+		&& HASH_P_ID2 == readl_relaxed(&device_data->base->periphid2)
+		&& HASH_P_ID3 == readl_relaxed(&device_data->base->periphid3)
+		&& HASH_CELL_ID0 == readl_relaxed(&device_data->base->cellid0)
+		&& HASH_CELL_ID1 == readl_relaxed(&device_data->base->cellid1)
+		&& HASH_CELL_ID2 == readl_relaxed(&device_data->base->cellid2)
+		&& HASH_CELL_ID3 == readl_relaxed(&device_data->base->cellid3)
+	   ) {
+		return 0;
+	}
+
+	dev_err(device_data->dev, "[%s] HASH_UNSUPPORTED_HW!",
+			__func__);
+	return -ENOTSUPP;
+}
+
+/**
+ * hash_get_digest - Gets the digest.
+ * @device_data:	Pointer to the device structure.
+ * @digest:		User allocated byte array for the calculated digest.
+ * @algorithm:		The algorithm in use.
+ */
+void hash_get_digest(struct hash_device_data *device_data,
+		u8 *digest, int algorithm)
+{
+	u32 temp_hx_val, count;
+	int loop_ctr;
+
+	if (algorithm != HASH_ALGO_SHA1 && algorithm != HASH_ALGO_SHA256) {
+		dev_err(device_data->dev, "[%s] Incorrect algorithm %d",
+				__func__, algorithm);
+		return;
+	}
+
+	if (algorithm == HASH_ALGO_SHA1)
+		loop_ctr = SHA1_DIGEST_SIZE / sizeof(u32);
+	else
+		loop_ctr = SHA256_DIGEST_SIZE / sizeof(u32);
+
+	dev_dbg(device_data->dev, "[%s] digest array:(0x%x)",
+			__func__, (u32) digest);
+
+	/* Copy result into digest array */
+	for (count = 0; count < loop_ctr; count++) {
+		temp_hx_val = readl_relaxed(&device_data->base->hx[count]);
+		digest[count * 4] = (u8) ((temp_hx_val >> 24) & 0xFF);
+		digest[count * 4 + 1] = (u8) ((temp_hx_val >> 16) & 0xFF);
+		digest[count * 4 + 2] = (u8) ((temp_hx_val >> 8) & 0xFF);
+		digest[count * 4 + 3] = (u8) ((temp_hx_val >> 0) & 0xFF);
+	}
+}
+
+/**
+ * hash_update - The hash update function for SHA1/SHA2 (SHA256).
+ * @req: The hash request for the job.
+ */
+static int ahash_update(struct ahash_request *req)
+{
+	int ret = 0;
+	struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+
+	if (hash_mode != HASH_MODE_DMA || !req_ctx->dma_mode)
+		ret = hash_hw_update(req);
+	/* Skip update for DMA, all data will be passed to DMA in final */
+
+	if (ret) {
+		pr_err(DEV_DBG_NAME " [%s] hash_hw_update() failed!",
+				__func__);
+	}
+
+	return ret;
+}
+
+/**
+ * hash_final - The hash final function for SHA1/SHA2 (SHA256).
+ * @req:	The hash request for the job.
+ */
+static int ahash_final(struct ahash_request *req)
+{
+	int ret = 0;
+	struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+
+	pr_debug(DEV_DBG_NAME " [%s] data size: %d", __func__, req->nbytes);
+
+	if ((hash_mode == HASH_MODE_DMA) && req_ctx->dma_mode)
+		ret = hash_dma_final(req);
+	else
+		ret = hash_hw_final(req);
+
+	if (ret) {
+		pr_err(DEV_DBG_NAME " [%s] hash_hw/dma_final() failed",
+				__func__);
+	}
+
+	return ret;
+}
+
+static int hash_setkey(struct crypto_ahash *tfm,
+		const u8 *key, unsigned int keylen, int alg)
+{
+	int ret = 0;
+	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	/**
+	 * Freed in final.
+	 */
+	ctx->key = kmalloc(keylen, GFP_KERNEL);
+	if (!ctx->key) {
+		pr_err(DEV_DBG_NAME " [%s] Failed to allocate ctx->key "
+		       "for %d\n", __func__, alg);
+		return -ENOMEM;
+	}
+
+	memcpy(ctx->key, key, keylen);
+	ctx->keylen = keylen;
+
+	return ret;
+}
+
+static int ahash_sha1_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ctx->config.data_format = HASH_DATA_8_BITS;
+	ctx->config.algorithm = HASH_ALGO_SHA1;
+	ctx->config.oper_mode = HASH_OPER_MODE_HASH;
+	ctx->digestsize = SHA1_DIGEST_SIZE;
+
+	return hash_init(req);
+}
+
+static int ahash_sha256_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ctx->config.data_format = HASH_DATA_8_BITS;
+	ctx->config.algorithm = HASH_ALGO_SHA256;
+	ctx->config.oper_mode = HASH_OPER_MODE_HASH;
+	ctx->digestsize = SHA256_DIGEST_SIZE;
+
+	return hash_init(req);
+}
+
+static int ahash_sha1_digest(struct ahash_request *req)
+{
+	int ret2, ret1;
+
+	ret1 = ahash_sha1_init(req);
+	if (ret1)
+		goto out;
+
+	ret1 = ahash_update(req);
+	ret2 = ahash_final(req);
+
+out:
+	return ret1 ? ret1 : ret2;
+}
+
+static int ahash_sha256_digest(struct ahash_request *req)
+{
+	int ret2, ret1;
+
+	ret1 = ahash_sha256_init(req);
+	if (ret1)
+		goto out;
+
+	ret1 = ahash_update(req);
+	ret2 = ahash_final(req);
+
+out:
+	return ret1 ? ret1 : ret2;
+}
+
+static int hmac_sha1_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ctx->config.data_format	= HASH_DATA_8_BITS;
+	ctx->config.algorithm	= HASH_ALGO_SHA1;
+	ctx->config.oper_mode	= HASH_OPER_MODE_HMAC;
+	ctx->digestsize		= SHA1_DIGEST_SIZE;
+
+	return hash_init(req);
+}
+
+static int hmac_sha256_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ctx->config.data_format	= HASH_DATA_8_BITS;
+	ctx->config.algorithm	= HASH_ALGO_SHA256;
+	ctx->config.oper_mode	= HASH_OPER_MODE_HMAC;
+	ctx->digestsize		= SHA256_DIGEST_SIZE;
+
+	return hash_init(req);
+}
+
+static int hmac_sha1_digest(struct ahash_request *req)
+{
+	int ret2, ret1;
+
+	ret1 = hmac_sha1_init(req);
+	if (ret1)
+		goto out;
+
+	ret1 = ahash_update(req);
+	ret2 = ahash_final(req);
+
+out:
+	return ret1 ? ret1 : ret2;
+}
+
+static int hmac_sha256_digest(struct ahash_request *req)
+{
+	int ret2, ret1;
+
+	ret1 = hmac_sha256_init(req);
+	if (ret1)
+		goto out;
+
+	ret1 = ahash_update(req);
+	ret2 = ahash_final(req);
+
+out:
+	return ret1 ? ret1 : ret2;
+}
+
+static int hmac_sha1_setkey(struct crypto_ahash *tfm,
+		const u8 *key, unsigned int keylen)
+{
+	return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA1);
+}
+
+static int hmac_sha256_setkey(struct crypto_ahash *tfm,
+		const u8 *key, unsigned int keylen)
+{
+	return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA256);
+}
+
+struct hash_algo_template {
+	struct hash_config conf;
+	struct ahash_alg hash;
+};
+
+static int hash_cra_init(struct crypto_tfm *tfm)
+{
+	struct hash_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_alg *alg = tfm->__crt_alg;
+	struct hash_algo_template *hash_alg;
+
+	hash_alg = container_of(__crypto_ahash_alg(alg),
+			struct hash_algo_template,
+			hash);
+
+	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+			sizeof(struct hash_req_ctx));
+
+	ctx->config.data_format = HASH_DATA_8_BITS;
+	ctx->config.algorithm = hash_alg->conf.algorithm;
+	ctx->config.oper_mode = hash_alg->conf.oper_mode;
+
+	ctx->digestsize = hash_alg->hash.halg.digestsize;
+
+	return 0;
+}
+
+static struct hash_algo_template hash_algs[] = {
+	{
+			.conf.algorithm	= HASH_ALGO_SHA1,
+			.conf.oper_mode	= HASH_OPER_MODE_HASH,
+			.hash = {
+				.init = hash_init,
+				.update = ahash_update,
+				.final = ahash_final,
+				.digest = ahash_sha1_digest,
+				.halg.digestsize = SHA1_DIGEST_SIZE,
+				.halg.statesize = sizeof(struct hash_ctx),
+				.halg.base = {
+					.cra_name = "sha1",
+					.cra_driver_name = "sha1-ux500",
+					.cra_flags = CRYPTO_ALG_TYPE_AHASH |
+							CRYPTO_ALG_ASYNC,
+					.cra_blocksize = SHA1_BLOCK_SIZE,
+					.cra_ctxsize = sizeof(struct hash_ctx),
+					.cra_init = hash_cra_init,
+					.cra_module = THIS_MODULE,
+			}
+		}
+	},
+	{
+			.conf.algorithm		= HASH_ALGO_SHA256,
+			.conf.oper_mode		= HASH_OPER_MODE_HASH,
+			.hash = {
+				.init = hash_init,
+				.update	= ahash_update,
+				.final = ahash_final,
+				.digest = ahash_sha256_digest,
+				.halg.digestsize = SHA256_DIGEST_SIZE,
+				.halg.statesize = sizeof(struct hash_ctx),
+				.halg.base = {
+					.cra_name = "sha256",
+					.cra_driver_name = "sha256-ux500",
+					.cra_flags = CRYPTO_ALG_TYPE_AHASH |
+							CRYPTO_ALG_ASYNC,
+					.cra_blocksize = SHA256_BLOCK_SIZE,
+					.cra_ctxsize = sizeof(struct hash_ctx),
+					.cra_type = &crypto_ahash_type,
+					.cra_init = hash_cra_init,
+					.cra_module = THIS_MODULE,
+				}
+			}
+
+	},
+	{
+			.conf.algorithm		= HASH_ALGO_SHA1,
+			.conf.oper_mode		= HASH_OPER_MODE_HMAC,
+			.hash = {
+				.init = hash_init,
+				.update = ahash_update,
+				.final = ahash_final,
+				.digest = hmac_sha1_digest,
+				.setkey = hmac_sha1_setkey,
+				.halg.digestsize = SHA1_DIGEST_SIZE,
+				.halg.statesize = sizeof(struct hash_ctx),
+				.halg.base = {
+					.cra_name = "hmac(sha1)",
+					.cra_driver_name = "hmac-sha1-ux500",
+					.cra_flags = CRYPTO_ALG_TYPE_AHASH |
+							CRYPTO_ALG_ASYNC,
+					.cra_blocksize = SHA1_BLOCK_SIZE,
+					.cra_ctxsize = sizeof(struct hash_ctx),
+					.cra_type = &crypto_ahash_type,
+					.cra_init = hash_cra_init,
+					.cra_module = THIS_MODULE,
+				}
+			}
+	},
+	{
+			.conf.algorithm		= HASH_ALGO_SHA256,
+			.conf.oper_mode		= HASH_OPER_MODE_HMAC,
+			.hash = {
+				.init = hash_init,
+				.update = ahash_update,
+				.final = ahash_final,
+				.digest = hmac_sha256_digest,
+				.setkey = hmac_sha256_setkey,
+				.halg.digestsize = SHA256_DIGEST_SIZE,
+				.halg.statesize = sizeof(struct hash_ctx),
+				.halg.base = {
+					.cra_name = "hmac(sha256)",
+					.cra_driver_name = "hmac-sha256-ux500",
+					.cra_flags = CRYPTO_ALG_TYPE_AHASH |
+							CRYPTO_ALG_ASYNC,
+					.cra_blocksize = SHA256_BLOCK_SIZE,
+					.cra_ctxsize = sizeof(struct hash_ctx),
+					.cra_type = &crypto_ahash_type,
+					.cra_init = hash_cra_init,
+					.cra_module = THIS_MODULE,
+				}
+			}
+	}
+};
+
+/**
+ * hash_algs_register_all -
+ */
+static int ahash_algs_register_all(struct hash_device_data *device_data)
+{
+	int ret;
+	int i;
+	int count;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algs); i++) {
+		ret = crypto_register_ahash(&hash_algs[i].hash);
+		if (ret) {
+			count = i;
+			dev_err(device_data->dev, "[%s] alg registration failed",
+				hash_algs[i].hash.halg.base.cra_driver_name);
+			goto unreg;
+		}
+	}
+	return 0;
+unreg:
+	for (i = 0; i < count; i++)
+		crypto_unregister_ahash(&hash_algs[i].hash);
+	return ret;
+}
+
+/**
+ * hash_algs_unregister_all -
+ */
+static void ahash_algs_unregister_all(struct hash_device_data *device_data)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algs); i++)
+		crypto_unregister_ahash(&hash_algs[i].hash);
+}
+
+/**
+ * ux500_hash_probe - Function that probes the hash hardware.
+ * @pdev: The platform device.
+ */
+static int ux500_hash_probe(struct platform_device *pdev)
+{
+	int			ret = 0;
+	struct resource		*res = NULL;
+	struct hash_device_data *device_data;
+	struct device		*dev = &pdev->dev;
+
+	device_data = kzalloc(sizeof(struct hash_device_data), GFP_ATOMIC);
+	if (!device_data) {
+		dev_dbg(dev, "[%s] kzalloc() failed!", __func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	device_data->dev = dev;
+	device_data->current_ctx = NULL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_dbg(dev, "[%s] platform_get_resource() failed!", __func__);
+		ret = -ENODEV;
+		goto out_kfree;
+	}
+
+	res = request_mem_region(res->start, resource_size(res), pdev->name);
+	if (res == NULL) {
+		dev_dbg(dev, "[%s] request_mem_region() failed!", __func__);
+		ret = -EBUSY;
+		goto out_kfree;
+	}
+
+	device_data->base = ioremap(res->start, resource_size(res));
+	if (!device_data->base) {
+		dev_err(dev, "[%s] ioremap() failed!",
+				__func__);
+		ret = -ENOMEM;
+		goto out_free_mem;
+	}
+	spin_lock_init(&device_data->ctx_lock);
+	spin_lock_init(&device_data->power_state_lock);
+
+	/* Enable power for HASH1 hardware block */
+	device_data->regulator = regulator_get(dev, "v-ape");
+	if (IS_ERR(device_data->regulator)) {
+		dev_err(dev, "[%s] regulator_get() failed!", __func__);
+		ret = PTR_ERR(device_data->regulator);
+		device_data->regulator = NULL;
+		goto out_unmap;
+	}
+
+	/* Enable the clock for HASH1 hardware block */
+	device_data->clk = clk_get(dev, NULL);
+	if (IS_ERR(device_data->clk)) {
+		dev_err(dev, "[%s] clk_get() failed!", __func__);
+		ret = PTR_ERR(device_data->clk);
+		goto out_regulator;
+	}
+
+	/* Enable device power (and clock) */
+	ret = hash_enable_power(device_data, false);
+	if (ret) {
+		dev_err(dev, "[%s]: hash_enable_power() failed!", __func__);
+		goto out_clk;
+	}
+
+	ret = hash_check_hw(device_data);
+	if (ret) {
+		dev_err(dev, "[%s] hash_check_hw() failed!", __func__);
+		goto out_power;
+	}
+
+	if (hash_mode == HASH_MODE_DMA)
+		hash_dma_setup_channel(device_data, dev);
+
+	platform_set_drvdata(pdev, device_data);
+
+	/* Put the new device into the device list... */
+	klist_add_tail(&device_data->list_node, &driver_data.device_list);
+	/* ... and signal that a new device is available. */
+	up(&driver_data.device_allocation);
+
+	ret = ahash_algs_register_all(device_data);
+	if (ret) {
+		dev_err(dev, "[%s] ahash_algs_register_all() "
+				"failed!", __func__);
+		goto out_power;
+	}
+
+	dev_info(dev, "[%s] successfully probed\n", __func__);
+	return 0;
+
+out_power:
+	hash_disable_power(device_data, false);
+
+out_clk:
+	clk_put(device_data->clk);
+
+out_regulator:
+	regulator_put(device_data->regulator);
+
+out_unmap:
+	iounmap(device_data->base);
+
+out_free_mem:
+	release_mem_region(res->start, resource_size(res));
+
+out_kfree:
+	kfree(device_data);
+out:
+	return ret;
+}
+
+/**
+ * ux500_hash_remove - Function that removes the hash device from the platform.
+ * @pdev: The platform device.
+ */
+static int ux500_hash_remove(struct platform_device *pdev)
+{
+	struct resource		*res;
+	struct hash_device_data *device_data;
+	struct device		*dev = &pdev->dev;
+
+	device_data = platform_get_drvdata(pdev);
+	if (!device_data) {
+		dev_err(dev, "[%s]: platform_get_drvdata() failed!",
+			__func__);
+		return -ENOMEM;
+	}
+
+	/* Try to decrease the number of available devices. */
+	if (down_trylock(&driver_data.device_allocation))
+		return -EBUSY;
+
+	/* Check that the device is free */
+	spin_lock(&device_data->ctx_lock);
+	/* current_ctx allocates a device, NULL = unallocated */
+	if (device_data->current_ctx) {
+		/* The device is busy */
+		spin_unlock(&device_data->ctx_lock);
+		/* Return the device to the pool. */
+		up(&driver_data.device_allocation);
+		return -EBUSY;
+	}
+
+	spin_unlock(&device_data->ctx_lock);
+
+	/* Remove the device from the list */
+	if (klist_node_attached(&device_data->list_node))
+		klist_remove(&device_data->list_node);
+
+	/* If this was the last device, remove the services */
+	if (list_empty(&driver_data.device_list.k_list))
+		ahash_algs_unregister_all(device_data);
+
+	if (hash_disable_power(device_data, false))
+		dev_err(dev, "[%s]: hash_disable_power() failed",
+			__func__);
+
+	clk_put(device_data->clk);
+	regulator_put(device_data->regulator);
+
+	iounmap(device_data->base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res)
+		release_mem_region(res->start, resource_size(res));
+
+	kfree(device_data);
+
+	return 0;
+}
+
+/**
+ * ux500_hash_shutdown - Function that shutdown the hash device.
+ * @pdev: The platform device
+ */
+static void ux500_hash_shutdown(struct platform_device *pdev)
+{
+	struct resource *res = NULL;
+	struct hash_device_data *device_data;
+
+	device_data = platform_get_drvdata(pdev);
+	if (!device_data) {
+		dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
+				__func__);
+		return;
+	}
+
+	/* Check that the device is free */
+	spin_lock(&device_data->ctx_lock);
+	/* current_ctx allocates a device, NULL = unallocated */
+	if (!device_data->current_ctx) {
+		if (down_trylock(&driver_data.device_allocation))
+			dev_dbg(&pdev->dev, "[%s]: Cryp still in use!"
+				"Shutting down anyway...", __func__);
+		/**
+		 * (Allocate the device)
+		 * Need to set this to non-null (dummy) value,
+		 * to avoid usage if context switching.
+		 */
+		device_data->current_ctx++;
+	}
+	spin_unlock(&device_data->ctx_lock);
+
+	/* Remove the device from the list */
+	if (klist_node_attached(&device_data->list_node))
+		klist_remove(&device_data->list_node);
+
+	/* If this was the last device, remove the services */
+	if (list_empty(&driver_data.device_list.k_list))
+		ahash_algs_unregister_all(device_data);
+
+	iounmap(device_data->base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res)
+		release_mem_region(res->start, resource_size(res));
+
+	if (hash_disable_power(device_data, false))
+		dev_err(&pdev->dev, "[%s] hash_disable_power() failed",
+				__func__);
+}
+
+/**
+ * ux500_hash_suspend - Function that suspends the hash device.
+ * @pdev:	The platform device.
+ * @state:	-
+ */
+static int ux500_hash_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	int ret;
+	struct hash_device_data *device_data;
+	struct hash_ctx *temp_ctx = NULL;
+
+	device_data = platform_get_drvdata(pdev);
+	if (!device_data) {
+		dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
+				__func__);
+		return -ENOMEM;
+	}
+
+	spin_lock(&device_data->ctx_lock);
+	if (!device_data->current_ctx)
+		device_data->current_ctx++;
+	spin_unlock(&device_data->ctx_lock);
+
+	if (device_data->current_ctx == ++temp_ctx) {
+		if (down_interruptible(&driver_data.device_allocation))
+			dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
+					"failed", __func__);
+		ret = hash_disable_power(device_data, false);
+
+	} else
+		ret = hash_disable_power(device_data, true);
+
+	if (ret)
+		dev_err(&pdev->dev, "[%s]: hash_disable_power()", __func__);
+
+	return ret;
+}
+
+/**
+ * ux500_hash_resume - Function that resume the hash device.
+ * @pdev:	The platform device.
+ */
+static int ux500_hash_resume(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hash_device_data *device_data;
+	struct hash_ctx *temp_ctx = NULL;
+
+	device_data = platform_get_drvdata(pdev);
+	if (!device_data) {
+		dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
+				__func__);
+		return -ENOMEM;
+	}
+
+	spin_lock(&device_data->ctx_lock);
+	if (device_data->current_ctx == ++temp_ctx)
+		device_data->current_ctx = NULL;
+	spin_unlock(&device_data->ctx_lock);
+
+	if (!device_data->current_ctx)
+		up(&driver_data.device_allocation);
+	else
+		ret = hash_enable_power(device_data, true);
+
+	if (ret)
+		dev_err(&pdev->dev, "[%s]: hash_enable_power() failed!",
+			__func__);
+
+	return ret;
+}
+
+static struct platform_driver hash_driver = {
+	.probe  = ux500_hash_probe,
+	.remove = ux500_hash_remove,
+	.shutdown = ux500_hash_shutdown,
+	.suspend  = ux500_hash_suspend,
+	.resume   = ux500_hash_resume,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name  = "hash1",
+	}
+};
+
+/**
+ * ux500_hash_mod_init - The kernel module init function.
+ */
+static int __init ux500_hash_mod_init(void)
+{
+	klist_init(&driver_data.device_list, NULL, NULL);
+	/* Initialize the semaphore to 0 devices (locked state) */
+	sema_init(&driver_data.device_allocation, 0);
+
+	return platform_driver_register(&hash_driver);
+}
+
+/**
+ * ux500_hash_mod_fini - The kernel module exit function.
+ */
+static void __exit ux500_hash_mod_fini(void)
+{
+	platform_driver_unregister(&hash_driver);
+	return;
+}
+
+module_init(ux500_hash_mod_init);
+module_exit(ux500_hash_mod_fini);
+
+MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 HASH engine.");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("sha1-all");
+MODULE_ALIAS("sha256-all");
+MODULE_ALIAS("hmac-sha1-all");
+MODULE_ALIAS("hmac-sha256-all");
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 464fa21..f6b0a6e2 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -16,7 +16,7 @@
 	  is attached to a single device and returns a "representative"
 	  clock frequency of the device, which is also attached
 	  to a device by 1-to-1. The device registering devfreq takes the
-	  responsiblity to "interpret" the representative frequency and
+	  responsibility to "interpret" the representative frequency and
 	  to set its every clock accordingly with the "target" callback
 	  given to devfreq.
 
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index 574a06b..af75ddd 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/devfreq.h>
+#include "governor.h"
 
 static int devfreq_performance_func(struct devfreq *df,
 				    unsigned long *freq)
@@ -25,8 +26,14 @@
 	return 0;
 }
 
+static int performance_init(struct devfreq *devfreq)
+{
+	return update_devfreq(devfreq);
+}
+
 const struct devfreq_governor devfreq_performance = {
 	.name = "performance",
+	.init = performance_init,
 	.get_target_freq = devfreq_performance_func,
 	.no_central_polling = true,
 };
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index d742d4a..fec0cdb 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/devfreq.h>
+#include "governor.h"
 
 static int devfreq_powersave_func(struct devfreq *df,
 				  unsigned long *freq)
@@ -22,8 +23,14 @@
 	return 0;
 }
 
+static int powersave_init(struct devfreq *devfreq)
+{
+	return update_devfreq(devfreq);
+}
+
 const struct devfreq_governor devfreq_powersave = {
 	.name = "powersave",
+	.init = powersave_init,
 	.get_target_freq = devfreq_powersave_func,
 	.no_central_polling = true,
 };
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index e48ab31..5b73941 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -107,13 +107,13 @@
  *
  * CPU caches (L1 and L2)
  * DMA engines
- * Core CPU swithces
+ * Core CPU switches
  * Fabric switch units
  * PCIe interface controllers
  * other EDAC/ECC type devices that can be monitored for
  * errors, etc.
  *
- * It allows for a 2 level set of hiearchry. For example:
+ * It allows for a 2 level set of hierarchy. For example:
  *
  * cache could be composed of L1, L2 and L3 levels of cache.
  * Each CPU core would have its own L1 cache, while sharing
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index 4b15459..45b8f4b 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -56,7 +56,7 @@
  *
  *	The control structure is allocated in complete chunk
  *	from the OS. It is in turn sub allocated to the
- *	various objects that compose the struture
+ *	various objects that compose the structure
  *
  *	The structure has a 'nr_instance' array within itself.
  *	Each instance represents a major component
@@ -118,7 +118,7 @@
 		/* Calc the 'end' offset past the attributes array */
 		pvt = edac_align_ptr(&dev_attrib[count], sz_private);
 	} else {
-		/* no attribute array specificed */
+		/* no attribute array specified */
 		pvt = edac_align_ptr(dev_attrib, sz_private);
 	}
 
@@ -394,7 +394,7 @@
 
 	/* Reschedule the workq for the next time period to start again
 	 * if the number of msec is for 1 sec, then adjust to the next
-	 * whole one second to save timers fireing all over the period
+	 * whole one second to save timers firing all over the period
 	 * between integral seconds
 	 */
 	if (edac_dev->poll_msec == 1000)
@@ -563,7 +563,7 @@
  *	Remove sysfs entries for specified edac_device structure and
  *	then remove edac_device structure from global list
  *
- * @pdev:
+ * @dev:
  *	Pointer to 'struct device' representing edac_device
  *	structure to remove.
  *
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 85226cc..7f1dfcc 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -90,7 +90,7 @@
 #define MC_MAX_DOD	0x64
 
 /*
- * OFFSETS for Device 3 Function 4, as inicated on Xeon 5500 datasheet:
+ * OFFSETS for Device 3 Function 4, as indicated on Xeon 5500 datasheet:
  * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
  */
 
@@ -101,7 +101,7 @@
   #define DIMM1_COR_ERR(r)			(((r) >> 16) & 0x7fff)
   #define DIMM0_COR_ERR(r)			((r) & 0x7fff)
 
-/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */
+/* OFFSETS for Device 3 Function 2, as indicated on Xeon 5500 datasheet */
 #define MC_SSRCONTROL		0x48
   #define SSR_MODE_DISABLE	0x00
   #define SSR_MODE_ENABLE	0x01
@@ -398,7 +398,7 @@
 };
 
 /****************************************************************************
-			Anciliary status routines
+			Ancillary status routines
  ****************************************************************************/
 
 	/* MC_CONTROL bits */
@@ -1361,7 +1361,7 @@
 			      dev_descr->dev_id, *prev);
 
 	/*
-	 * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
+	 * On Xeon 55xx, the Intel QuickPath Arch Generic Non-core regs
 	 * is at addr 8086:2c40, instead of 8086:2c41. So, we need
 	 * to probe for the alternate address in case of failure
 	 */
@@ -2132,7 +2132,7 @@
 
 /*
  * get_sdram_scrub_rate		This routine convert current scrub rate value
- *				into byte/sec bandwidth accourding to
+ *				into byte/sec bandwidth according to
  *				SCRUBINTERVAL formula found in datasheet.
  */
 static int get_sdram_scrub_rate(struct mem_ctl_info *mci)
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index a203536..123204f 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -58,7 +58,7 @@
 
 /*
  * FIXME: For now, let's order by device function, as it makes
- * easier for driver's development proccess. This table should be
+ * easier for driver's development process. This table should be
  * moved to pci_id.h when submitted upstream
  */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0	0x3cf4	/* 12.6 */
@@ -375,7 +375,7 @@
 
 
 /****************************************************************************
-			Anciliary status routines
+			Ancillary status routines
  ****************************************************************************/
 
 static inline int numrank(u32 mtr)
@@ -1430,7 +1430,7 @@
 		type = "FATAL";
 
 	/*
-	 * According with Table 15-9 of the Intel Archictecture spec vol 3A,
+	 * According with Table 15-9 of the Intel Architecture spec vol 3A,
 	 * memory errors should fit in this mask:
 	 *	000f 0000 1mmm cccc (binary)
 	 * where:
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
new file mode 100644
index 0000000..29c5cf8
--- /dev/null
+++ b/drivers/extcon/Kconfig
@@ -0,0 +1,32 @@
+menuconfig EXTCON
+	tristate "External Connector Class (extcon) support"
+	help
+	  Say Y here to enable external connector class (extcon) support.
+	  This allows monitoring external connectors by userspace
+	  via sysfs and uevent and supports external connectors with
+	  multiple states; i.e., an extcon that may have multiple
+	  cables attached. For example, an external connector of a device
+	  may be used to connect an HDMI cable and a AC adaptor, and to
+	  host USB ports. Many of 30-pin connectors including PDMI are
+	  also good examples.
+
+if EXTCON
+
+comment "Extcon Device Drivers"
+
+config EXTCON_GPIO
+	tristate "GPIO extcon support"
+	depends on GENERIC_GPIO
+	help
+	  Say Y here to enable GPIO based extcon support. Note that GPIO
+	  extcon supports single state per extcon instance.
+
+config EXTCON_MAX8997
+	tristate "MAX8997 EXTCON Support"
+	depends on MFD_MAX8997
+	help
+	  If you say yes here you get support for the MUIC device of
+	  Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory
+	  detector and switch.
+
+endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
new file mode 100644
index 0000000..86020bd
--- /dev/null
+++ b/drivers/extcon/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for external connector class (extcon) devices
+#
+
+obj-$(CONFIG_EXTCON)		+= extcon_class.o
+obj-$(CONFIG_EXTCON_GPIO)	+= extcon_gpio.o
+obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
new file mode 100644
index 0000000..23416e4
--- /dev/null
+++ b/drivers/extcon/extcon-max8997.c
@@ -0,0 +1,535 @@
+/*
+ * extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC
+ *
+ *  Copyright (C) 2012 Samsung Electrnoics
+ *  Donggeun Kim <dg77.kim@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+#include <linux/extcon.h>
+
+#define	DEV_NAME			"max8997-muic"
+
+/* MAX8997-MUIC STATUS1 register */
+#define STATUS1_ADC_SHIFT		0
+#define STATUS1_ADCLOW_SHIFT		5
+#define STATUS1_ADCERR_SHIFT		6
+#define STATUS1_ADC_MASK		(0x1f << STATUS1_ADC_SHIFT)
+#define STATUS1_ADCLOW_MASK		(0x1 << STATUS1_ADCLOW_SHIFT)
+#define STATUS1_ADCERR_MASK		(0x1 << STATUS1_ADCERR_SHIFT)
+
+/* MAX8997-MUIC STATUS2 register */
+#define STATUS2_CHGTYP_SHIFT		0
+#define STATUS2_CHGDETRUN_SHIFT		3
+#define STATUS2_DCDTMR_SHIFT		4
+#define STATUS2_DBCHG_SHIFT		5
+#define STATUS2_VBVOLT_SHIFT		6
+#define STATUS2_CHGTYP_MASK		(0x7 << STATUS2_CHGTYP_SHIFT)
+#define STATUS2_CHGDETRUN_MASK		(0x1 << STATUS2_CHGDETRUN_SHIFT)
+#define STATUS2_DCDTMR_MASK		(0x1 << STATUS2_DCDTMR_SHIFT)
+#define STATUS2_DBCHG_MASK		(0x1 << STATUS2_DBCHG_SHIFT)
+#define STATUS2_VBVOLT_MASK		(0x1 << STATUS2_VBVOLT_SHIFT)
+
+/* MAX8997-MUIC STATUS3 register */
+#define STATUS3_OVP_SHIFT		2
+#define STATUS3_OVP_MASK		(0x1 << STATUS3_OVP_SHIFT)
+
+/* MAX8997-MUIC CONTROL1 register */
+#define COMN1SW_SHIFT			0
+#define COMP2SW_SHIFT			3
+#define COMN1SW_MASK			(0x7 << COMN1SW_SHIFT)
+#define COMP2SW_MASK			(0x7 << COMP2SW_SHIFT)
+#define SW_MASK				(COMP2SW_MASK | COMN1SW_MASK)
+
+#define MAX8997_SW_USB		((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT))
+#define MAX8997_SW_AUDIO	((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT))
+#define MAX8997_SW_UART		((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT))
+#define MAX8997_SW_OPEN		((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT))
+
+#define	MAX8997_ADC_GROUND		0x00
+#define	MAX8997_ADC_MHL			0x01
+#define	MAX8997_ADC_JIG_USB_1		0x18
+#define	MAX8997_ADC_JIG_USB_2		0x19
+#define	MAX8997_ADC_DESKDOCK		0x1a
+#define	MAX8997_ADC_JIG_UART		0x1c
+#define	MAX8997_ADC_CARDOCK		0x1d
+#define	MAX8997_ADC_OPEN		0x1f
+
+struct max8997_muic_irq {
+	unsigned int irq;
+	const char *name;
+};
+
+static struct max8997_muic_irq muic_irqs[] = {
+	{ MAX8997_MUICIRQ_ADCError, "muic-ADC_error" },
+	{ MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" },
+	{ MAX8997_MUICIRQ_ADC, "muic-ADC" },
+	{ MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" },
+	{ MAX8997_MUICIRQ_DBChg, "muic-DB_charger" },
+	{ MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" },
+	{ MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" },
+	{ MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" },
+	{ MAX8997_MUICIRQ_OVP, "muic-over_voltage" },
+};
+
+struct max8997_muic_info {
+	struct device *dev;
+	struct i2c_client *muic;
+	struct max8997_muic_platform_data *muic_pdata;
+
+	int irq;
+	struct work_struct irq_work;
+
+	enum max8997_muic_charger_type pre_charger_type;
+	int pre_adc;
+
+	struct mutex mutex;
+
+	struct extcon_dev	*edev;
+};
+
+const char *max8997_extcon_cable[] = {
+	[0] = "USB",
+	[1] = "USB-Host",
+	[2] = "TA",
+	[3] = "Fast-charger",
+	[4] = "Slow-charger",
+	[5] = "Charge-downstream",
+	[6] = "MHL",
+	[7] = "Dock-desk",
+	[7] = "Dock-card",
+	[8] = "JIG",
+
+	NULL,
+};
+
+static int max8997_muic_handle_usb(struct max8997_muic_info *info,
+			enum max8997_muic_usb_type usb_type, bool attached)
+{
+	int ret = 0;
+
+	if (usb_type == MAX8997_USB_HOST) {
+		/* switch to USB */
+		ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
+				attached ? MAX8997_SW_USB : MAX8997_SW_OPEN,
+				SW_MASK);
+		if (ret) {
+			dev_err(info->dev, "failed to update muic register\n");
+			goto out;
+		}
+	}
+
+	switch (usb_type) {
+	case MAX8997_USB_HOST:
+		extcon_set_cable_state(info->edev, "USB-Host", attached);
+		break;
+	case MAX8997_USB_DEVICE:
+		extcon_set_cable_state(info->edev, "USB", attached);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+out:
+	return ret;
+}
+
+static int max8997_muic_handle_dock(struct max8997_muic_info *info,
+			int adc, bool attached)
+{
+	int ret = 0;
+
+	/* switch to AUDIO */
+	ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
+				attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN,
+				SW_MASK);
+	if (ret) {
+		dev_err(info->dev, "failed to update muic register\n");
+		goto out;
+	}
+
+	switch (adc) {
+	case MAX8997_ADC_DESKDOCK:
+		extcon_set_cable_state(info->edev, "Dock-desk", attached);
+		break;
+	case MAX8997_ADC_CARDOCK:
+		extcon_set_cable_state(info->edev, "Dock-card", attached);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+out:
+	return ret;
+}
+
+static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
+			bool attached)
+{
+	int ret = 0;
+
+	/* switch to UART */
+	ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
+				attached ? MAX8997_SW_UART : MAX8997_SW_OPEN,
+				SW_MASK);
+	if (ret) {
+		dev_err(info->dev, "failed to update muic register\n");
+		goto out;
+	}
+
+	extcon_set_cable_state(info->edev, "JIG", attached);
+out:
+	return ret;
+}
+
+static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info)
+{
+	int ret = 0;
+
+	switch (info->pre_adc) {
+	case MAX8997_ADC_GROUND:
+		ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false);
+		break;
+	case MAX8997_ADC_MHL:
+		extcon_set_cable_state(info->edev, "MHL", false);
+		break;
+	case MAX8997_ADC_JIG_USB_1:
+	case MAX8997_ADC_JIG_USB_2:
+		ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false);
+		break;
+	case MAX8997_ADC_DESKDOCK:
+	case MAX8997_ADC_CARDOCK:
+		ret = max8997_muic_handle_dock(info, info->pre_adc, false);
+		break;
+	case MAX8997_ADC_JIG_UART:
+		ret = max8997_muic_handle_jig_uart(info, false);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
+{
+	int ret = 0;
+
+	switch (adc) {
+	case MAX8997_ADC_GROUND:
+		ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
+		break;
+	case MAX8997_ADC_MHL:
+		extcon_set_cable_state(info->edev, "MHL", true);
+		break;
+	case MAX8997_ADC_JIG_USB_1:
+	case MAX8997_ADC_JIG_USB_2:
+		ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true);
+		break;
+	case MAX8997_ADC_DESKDOCK:
+	case MAX8997_ADC_CARDOCK:
+		ret = max8997_muic_handle_dock(info, adc, true);
+		break;
+	case MAX8997_ADC_JIG_UART:
+		ret = max8997_muic_handle_jig_uart(info, true);
+		break;
+	case MAX8997_ADC_OPEN:
+		ret = max8997_muic_handle_adc_detach(info);
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+
+	info->pre_adc = adc;
+out:
+	return ret;
+}
+
+static int max8997_muic_handle_charger_type_detach(
+				struct max8997_muic_info *info)
+{
+	int ret = 0;
+
+	switch (info->pre_charger_type) {
+	case MAX8997_CHARGER_TYPE_USB:
+		extcon_set_cable_state(info->edev, "USB", false);
+		break;
+	case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
+		extcon_set_cable_state(info->edev, "Charge-downstream", false);
+		break;
+	case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
+		extcon_set_cable_state(info->edev, "TA", false);
+		break;
+	case MAX8997_CHARGER_TYPE_500MA:
+		extcon_set_cable_state(info->edev, "Slow-charger", false);
+		break;
+	case MAX8997_CHARGER_TYPE_1A:
+		extcon_set_cable_state(info->edev, "Fast-charger", false);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
+				enum max8997_muic_charger_type charger_type)
+{
+	u8 adc;
+	int ret;
+
+	ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc);
+	if (ret) {
+		dev_err(info->dev, "failed to read muic register\n");
+		goto out;
+	}
+
+	switch (charger_type) {
+	case MAX8997_CHARGER_TYPE_NONE:
+		ret = max8997_muic_handle_charger_type_detach(info);
+		break;
+	case MAX8997_CHARGER_TYPE_USB:
+		if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) {
+			max8997_muic_handle_usb(info,
+					MAX8997_USB_DEVICE, true);
+		}
+		break;
+	case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
+		extcon_set_cable_state(info->edev, "Charge-downstream", true);
+		break;
+	case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
+		extcon_set_cable_state(info->edev, "TA", true);
+		break;
+	case MAX8997_CHARGER_TYPE_500MA:
+		extcon_set_cable_state(info->edev, "Slow-charger", true);
+		break;
+	case MAX8997_CHARGER_TYPE_1A:
+		extcon_set_cable_state(info->edev, "Fast-charger", true);
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+
+	info->pre_charger_type = charger_type;
+out:
+	return ret;
+}
+
+static void max8997_muic_irq_work(struct work_struct *work)
+{
+	struct max8997_muic_info *info = container_of(work,
+			struct max8997_muic_info, irq_work);
+	struct max8997_dev *max8997 = i2c_get_clientdata(info->muic);
+	u8 status[2];
+	u8 adc, chg_type;
+
+	int irq_type = info->irq - max8997->irq_base;
+	int ret;
+
+	mutex_lock(&info->mutex);
+
+	ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
+				2, status);
+	if (ret) {
+		dev_err(info->dev, "failed to read muic register\n");
+		mutex_unlock(&info->mutex);
+		return;
+	}
+
+	dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
+			status[0], status[1]);
+
+	switch (irq_type) {
+	case MAX8997_MUICIRQ_ADC:
+		adc = status[0] & STATUS1_ADC_MASK;
+		adc >>= STATUS1_ADC_SHIFT;
+
+		max8997_muic_handle_adc(info, adc);
+		break;
+	case MAX8997_MUICIRQ_ChgTyp:
+		chg_type = status[1] & STATUS2_CHGTYP_MASK;
+		chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+		max8997_muic_handle_charger_type(info, chg_type);
+		break;
+	default:
+		dev_info(info->dev, "misc interrupt: irq %d occurred\n",
+				irq_type);
+		break;
+	}
+
+	mutex_unlock(&info->mutex);
+
+	return;
+}
+
+static irqreturn_t max8997_muic_irq_handler(int irq, void *data)
+{
+	struct max8997_muic_info *info = data;
+
+	dev_dbg(info->dev, "irq:%d\n", irq);
+	info->irq = irq;
+
+	schedule_work(&info->irq_work);
+
+	return IRQ_HANDLED;
+}
+
+static void max8997_muic_detect_dev(struct max8997_muic_info *info)
+{
+	int ret;
+	u8 status[2], adc, chg_type;
+
+	ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
+				2, status);
+	if (ret) {
+		dev_err(info->dev, "failed to read muic register\n");
+		return;
+	}
+
+	dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n",
+			status[0], status[1]);
+
+	adc = status[0] & STATUS1_ADC_MASK;
+	adc >>= STATUS1_ADC_SHIFT;
+
+	chg_type = status[1] & STATUS2_CHGTYP_MASK;
+	chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+	max8997_muic_handle_adc(info, adc);
+	max8997_muic_handle_charger_type(info, chg_type);
+}
+
+static int __devinit max8997_muic_probe(struct platform_device *pdev)
+{
+	struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
+	struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev);
+	struct max8997_muic_info *info;
+	int ret, i;
+
+	info = kzalloc(sizeof(struct max8997_muic_info), GFP_KERNEL);
+	if (!info) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		ret = -ENOMEM;
+		goto err_kfree;
+	}
+
+	info->dev = &pdev->dev;
+	info->muic = max8997->muic;
+
+	platform_set_drvdata(pdev, info);
+	mutex_init(&info->mutex);
+
+	INIT_WORK(&info->irq_work, max8997_muic_irq_work);
+
+	for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
+		struct max8997_muic_irq *muic_irq = &muic_irqs[i];
+
+		ret = request_threaded_irq(pdata->irq_base + muic_irq->irq,
+				NULL, max8997_muic_irq_handler,
+				0, muic_irq->name,
+				info);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"failed: irq request (IRQ: %d,"
+				" error :%d)\n",
+				muic_irq->irq, ret);
+			goto err_irq;
+		}
+	}
+
+	/* External connector */
+	info->edev = kzalloc(sizeof(struct extcon_dev), GFP_KERNEL);
+	if (!info->edev) {
+		dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
+		ret = -ENOMEM;
+		goto err_irq;
+	}
+	info->edev->name = DEV_NAME;
+	info->edev->supported_cable = max8997_extcon_cable;
+	ret = extcon_dev_register(info->edev, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register extcon device\n");
+		goto err_extcon;
+	}
+
+	/* Initialize registers according to platform data */
+	if (pdata->muic_pdata) {
+		struct max8997_muic_platform_data *mdata = info->muic_pdata;
+
+		for (i = 0; i < mdata->num_init_data; i++) {
+			max8997_write_reg(info->muic, mdata->init_data[i].addr,
+					mdata->init_data[i].data);
+		}
+	}
+
+	/* Initial device detection */
+	max8997_muic_detect_dev(info);
+
+	return ret;
+
+err_extcon:
+	kfree(info->edev);
+err_irq:
+	while (--i >= 0)
+		free_irq(pdata->irq_base + muic_irqs[i].irq, info);
+	kfree(info);
+err_kfree:
+	return ret;
+}
+
+static int __devexit max8997_muic_remove(struct platform_device *pdev)
+{
+	struct max8997_muic_info *info = platform_get_drvdata(pdev);
+	struct max8997_dev *max8997 = i2c_get_clientdata(info->muic);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
+		free_irq(max8997->irq_base + muic_irqs[i].irq, info);
+	cancel_work_sync(&info->irq_work);
+
+	extcon_dev_unregister(info->edev);
+
+	kfree(info);
+
+	return 0;
+}
+
+static struct platform_driver max8997_muic_driver = {
+	.driver		= {
+		.name	= DEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= max8997_muic_probe,
+	.remove		= __devexit_p(max8997_muic_remove),
+};
+
+module_platform_driver(max8997_muic_driver);
+
+MODULE_DESCRIPTION("Maxim MAX8997 Extcon driver");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon_class.c b/drivers/extcon/extcon_class.c
new file mode 100644
index 0000000..f598a70
--- /dev/null
+++ b/drivers/extcon/extcon_class.c
@@ -0,0 +1,832 @@
+/*
+ *  drivers/extcon/extcon_class.c
+ *
+ *  External connector (extcon) class driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Donggeun Kim <dg77.kim@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on android/drivers/switch/switch_class.c
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/slab.h>
+
+/*
+ * extcon_cable_name suggests the standard cable names for commonly used
+ * cable types.
+ *
+ * However, please do not use extcon_cable_name directly for extcon_dev
+ * struct's supported_cable pointer unless your device really supports
+ * every single port-type of the following cable names. Please choose cable
+ * names that are actually used in your extcon device.
+ */
+const char *extcon_cable_name[] = {
+	[EXTCON_USB]		= "USB",
+	[EXTCON_USB_HOST]	= "USB-Host",
+	[EXTCON_TA]		= "TA",
+	[EXTCON_FAST_CHARGER]	= "Fast-charger",
+	[EXTCON_SLOW_CHARGER]	= "Slow-charger",
+	[EXTCON_CHARGE_DOWNSTREAM]	= "Charge-downstream",
+	[EXTCON_HDMI]		= "HDMI",
+	[EXTCON_MHL]		= "MHL",
+	[EXTCON_DVI]		= "DVI",
+	[EXTCON_VGA]		= "VGA",
+	[EXTCON_DOCK]		= "Dock",
+	[EXTCON_LINE_IN]	= "Line-in",
+	[EXTCON_LINE_OUT]	= "Line-out",
+	[EXTCON_MIC_IN]		= "Microphone",
+	[EXTCON_HEADPHONE_OUT]	= "Headphone",
+	[EXTCON_SPDIF_IN]	= "SPDIF-in",
+	[EXTCON_SPDIF_OUT]	= "SPDIF-out",
+	[EXTCON_VIDEO_IN]	= "Video-in",
+	[EXTCON_VIDEO_OUT]	= "Video-out",
+	[EXTCON_MECHANICAL]	= "Mechanical",
+
+	NULL,
+};
+
+struct class *extcon_class;
+#if defined(CONFIG_ANDROID)
+static struct class_compat *switch_class;
+#endif /* CONFIG_ANDROID */
+
+static LIST_HEAD(extcon_dev_list);
+static DEFINE_MUTEX(extcon_dev_list_lock);
+
+/**
+ * check_mutually_exclusive - Check if new_state violates mutually_exclusive
+ *			    condition.
+ * @edev:	the extcon device
+ * @new_state:	new cable attach status for @edev
+ *
+ * Returns 0 if nothing violates. Returns the index + 1 for the first
+ * violated condition.
+ */
+static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
+{
+	int i = 0;
+
+	if (!edev->mutually_exclusive)
+		return 0;
+
+	for (i = 0; edev->mutually_exclusive[i]; i++) {
+		int count = 0, j;
+		u32 correspondants = new_state & edev->mutually_exclusive[i];
+		u32 exp = 1;
+
+		for (j = 0; j < 32; j++) {
+			if (exp & correspondants)
+				count++;
+			if (count > 1)
+				return i + 1;
+			exp <<= 1;
+		}
+	}
+
+	return 0;
+}
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int i, count = 0;
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	if (edev->print_state) {
+		int ret = edev->print_state(edev, buf);
+
+		if (ret >= 0)
+			return ret;
+		/* Use default if failed */
+	}
+
+	if (edev->max_supported == 0)
+		return sprintf(buf, "%u\n", edev->state);
+
+	for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
+		if (!edev->supported_cable[i])
+			break;
+		count += sprintf(buf + count, "%s=%d\n",
+				 edev->supported_cable[i],
+				 !!(edev->state & (1 << i)));
+	}
+
+	return count;
+}
+
+int extcon_set_state(struct extcon_dev *edev, u32 state);
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	u32 state;
+	ssize_t ret = 0;
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	ret = sscanf(buf, "0x%x", &state);
+	if (ret == 0)
+		ret = -EINVAL;
+	else
+		ret = extcon_set_state(edev, state);
+
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	/* Optional callback given by the user */
+	if (edev->print_name) {
+		int ret = edev->print_name(edev, buf);
+		if (ret >= 0)
+			return ret;
+	}
+
+	return sprintf(buf, "%s\n", dev_name(edev->dev));
+}
+
+static ssize_t cable_name_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+						  attr_name);
+
+	return sprintf(buf, "%s\n",
+		       cable->edev->supported_cable[cable->cable_index]);
+}
+
+static ssize_t cable_state_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+						  attr_state);
+
+	return sprintf(buf, "%d\n",
+		       extcon_get_cable_state_(cable->edev,
+					       cable->cable_index));
+}
+
+static ssize_t cable_state_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
+{
+	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+						  attr_state);
+	int ret, state;
+
+	ret = sscanf(buf, "%d", &state);
+	if (ret == 0)
+		ret = -EINVAL;
+	else
+		ret = extcon_set_cable_state_(cable->edev, cable->cable_index,
+					      state);
+
+	if (ret < 0)
+		return ret;
+	return count;
+}
+
+/**
+ * extcon_update_state() - Update the cable attach states of the extcon device
+ *			only for the masked bits.
+ * @edev:	the extcon device
+ * @mask:	the bit mask to designate updated bits.
+ * @state:	new cable attach status for @edev
+ *
+ * Changing the state sends uevent with environment variable containing
+ * the name of extcon device (envp[0]) and the state output (envp[1]).
+ * Tizen uses this format for extcon device to get events from ports.
+ * Android uses this format as well.
+ *
+ * Note that the notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
+{
+	char name_buf[120];
+	char state_buf[120];
+	char *prop_buf;
+	char *envp[3];
+	int env_offset = 0;
+	int length;
+	unsigned long flags;
+
+	spin_lock_irqsave(&edev->lock, flags);
+
+	if (edev->state != ((edev->state & ~mask) | (state & mask))) {
+		u32 old_state = edev->state;
+
+		if (check_mutually_exclusive(edev, (edev->state & ~mask) |
+						   (state & mask))) {
+			spin_unlock_irqrestore(&edev->lock, flags);
+			return -EPERM;
+		}
+
+		edev->state &= ~mask;
+		edev->state |= state & mask;
+
+		raw_notifier_call_chain(&edev->nh, old_state, edev);
+
+		/* This could be in interrupt handler */
+		prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
+		if (prop_buf) {
+			length = name_show(edev->dev, NULL, prop_buf);
+			if (length > 0) {
+				if (prop_buf[length - 1] == '\n')
+					prop_buf[length - 1] = 0;
+				snprintf(name_buf, sizeof(name_buf),
+					"NAME=%s", prop_buf);
+				envp[env_offset++] = name_buf;
+			}
+			length = state_show(edev->dev, NULL, prop_buf);
+			if (length > 0) {
+				if (prop_buf[length - 1] == '\n')
+					prop_buf[length - 1] = 0;
+				snprintf(state_buf, sizeof(state_buf),
+					"STATE=%s", prop_buf);
+				envp[env_offset++] = state_buf;
+			}
+			envp[env_offset] = NULL;
+			/* Unlock early before uevent */
+			spin_unlock_irqrestore(&edev->lock, flags);
+
+			kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp);
+			free_page((unsigned long)prop_buf);
+		} else {
+			/* Unlock early before uevent */
+			spin_unlock_irqrestore(&edev->lock, flags);
+
+			dev_err(edev->dev, "out of memory in extcon_set_state\n");
+			kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE);
+		}
+	} else {
+		/* No changes */
+		spin_unlock_irqrestore(&edev->lock, flags);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(extcon_update_state);
+
+/**
+ * extcon_set_state() - Set the cable attach states of the extcon device.
+ * @edev:	the extcon device
+ * @state:	new cable attach status for @edev
+ *
+ * Note that notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_set_state(struct extcon_dev *edev, u32 state)
+{
+	return extcon_update_state(edev, 0xffffffff, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_state);
+
+/**
+ * extcon_find_cable_index() - Get the cable index based on the cable name.
+ * @edev:	the extcon device that has the cable.
+ * @cable_name:	cable name to be searched.
+ *
+ * Note that accessing a cable state based on cable_index is faster than
+ * cable_name because using cable_name induces a loop with strncmp().
+ * Thus, when get/set_cable_state is repeatedly used, using cable_index
+ * is recommended.
+ */
+int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
+{
+	int i;
+
+	if (edev->supported_cable) {
+		for (i = 0; edev->supported_cable[i]; i++) {
+			if (!strncmp(edev->supported_cable[i],
+				cable_name, CABLE_NAME_MAX))
+				return i;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(extcon_find_cable_index);
+
+/**
+ * extcon_get_cable_state_() - Get the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @index:	cable index that can be retrieved by extcon_find_cable_index().
+ */
+int extcon_get_cable_state_(struct extcon_dev *edev, int index)
+{
+	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+		return -EINVAL;
+
+	return !!(edev->state & (1 << index));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Get the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @cable_name:	cable name.
+ *
+ * Note that this is slower than extcon_get_cable_state_.
+ */
+int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
+{
+	return extcon_get_cable_state_(edev, extcon_find_cable_index
+						(edev, cable_name));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state);
+
+/**
+ * extcon_get_cable_state_() - Set the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @index:	cable index that can be retrieved by extcon_find_cable_index().
+ * @cable_state:	the new cable status. The default semantics is
+ *			true: attached / false: detached.
+ */
+int extcon_set_cable_state_(struct extcon_dev *edev,
+			int index, bool cable_state)
+{
+	u32 state;
+
+	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+		return -EINVAL;
+
+	state = cable_state ? (1 << index) : 0;
+	return extcon_update_state(edev, 1 << index, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Set the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @cable_name:	cable name.
+ * @cable_state:	the new cable status. The default semantics is
+ *			true: attached / false: detached.
+ *
+ * Note that this is slower than extcon_set_cable_state_.
+ */
+int extcon_set_cable_state(struct extcon_dev *edev,
+			const char *cable_name, bool cable_state)
+{
+	return extcon_set_cable_state_(edev, extcon_find_cable_index
+					(edev, cable_name), cable_state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state);
+
+/**
+ * extcon_get_extcon_dev() - Get the extcon device instance from the name
+ * @extcon_name:	The extcon name provided with extcon_dev_register()
+ */
+struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
+{
+	struct extcon_dev *sd;
+
+	mutex_lock(&extcon_dev_list_lock);
+	list_for_each_entry(sd, &extcon_dev_list, entry) {
+		if (!strcmp(sd->name, extcon_name))
+			goto out;
+	}
+	sd = NULL;
+out:
+	mutex_unlock(&extcon_dev_list_lock);
+	return sd;
+}
+EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
+
+static int _call_per_cable(struct notifier_block *nb, unsigned long val,
+			   void *ptr)
+{
+	struct extcon_specific_cable_nb *obj = container_of(nb,
+			struct extcon_specific_cable_nb, internal_nb);
+	struct extcon_dev *edev = ptr;
+
+	if ((val & (1 << obj->cable_index)) !=
+	    (edev->state & (1 << obj->cable_index))) {
+		bool cable_state = true;
+
+		obj->previous_value = val;
+
+		if (val & (1 << obj->cable_index))
+			cable_state = false;
+
+		return obj->user_nb->notifier_call(obj->user_nb,
+				cable_state, ptr);
+	}
+
+	return NOTIFY_OK;
+}
+
+/**
+ * extcon_register_interest() - Register a notifier for a state change of a
+ *			      specific cable, not a entier set of cables of a
+ *			      extcon device.
+ * @obj:	an empty extcon_specific_cable_nb object to be returned.
+ * @extcon_name:	the name of extcon device.
+ * @cable_name:		the target cable name.
+ * @nb:		the notifier block to get notified.
+ *
+ * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
+ * the struct for you.
+ *
+ * extcon_register_interest is a helper function for those who want to get
+ * notification for a single specific cable's status change. If a user wants
+ * to get notification for any changes of all cables of a extcon device,
+ * he/she should use the general extcon_register_notifier().
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_interest(struct extcon_specific_cable_nb *obj,
+			     const char *extcon_name, const char *cable_name,
+			     struct notifier_block *nb)
+{
+	if (!obj || !extcon_name || !cable_name || !nb)
+		return -EINVAL;
+
+	obj->edev = extcon_get_extcon_dev(extcon_name);
+	if (!obj->edev)
+		return -ENODEV;
+
+	obj->cable_index = extcon_find_cable_index(obj->edev, cable_name);
+	if (obj->cable_index < 0)
+		return -ENODEV;
+
+	obj->user_nb = nb;
+
+	obj->internal_nb.notifier_call = _call_per_cable;
+
+	return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_unregister_interest() - Unregister the notifier registered by
+ *				extcon_register_interest().
+ * @obj:	the extcon_specific_cable_nb object returned by
+ *		extcon_register_interest().
+ */
+int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
+{
+	if (!obj)
+		return -EINVAL;
+
+	return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_register_notifier() - Register a notifee to get notified by
+ *			      any attach status changes from the extcon.
+ * @edev:	the extcon device.
+ * @nb:		a notifier block to be registered.
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_notifier(struct extcon_dev *edev,
+			struct notifier_block *nb)
+{
+	return raw_notifier_chain_register(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_register_notifier);
+
+/**
+ * extcon_unregister_notifier() - Unregister a notifee from the extcon device.
+ * @edev:	the extcon device.
+ * @nb:		a registered notifier block to be unregistered.
+ */
+int extcon_unregister_notifier(struct extcon_dev *edev,
+			struct notifier_block *nb)
+{
+	return raw_notifier_chain_unregister(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
+
+static struct device_attribute extcon_attrs[] = {
+	__ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
+	__ATTR_RO(name),
+	__ATTR_NULL,
+};
+
+static int create_extcon_class(void)
+{
+	if (!extcon_class) {
+		extcon_class = class_create(THIS_MODULE, "extcon");
+		if (IS_ERR(extcon_class))
+			return PTR_ERR(extcon_class);
+		extcon_class->dev_attrs = extcon_attrs;
+
+#if defined(CONFIG_ANDROID)
+		switch_class = class_compat_register("switch");
+		if (WARN(!switch_class, "cannot allocate"))
+			return -ENOMEM;
+#endif /* CONFIG_ANDROID */
+	}
+
+	return 0;
+}
+
+static void extcon_cleanup(struct extcon_dev *edev, bool skip)
+{
+	mutex_lock(&extcon_dev_list_lock);
+	list_del(&edev->entry);
+	mutex_unlock(&extcon_dev_list_lock);
+
+	if (!skip && get_device(edev->dev)) {
+		int index;
+
+		if (edev->mutually_exclusive && edev->max_supported) {
+			for (index = 0; edev->mutually_exclusive[index];
+			     index++)
+				kfree(edev->d_attrs_muex[index].attr.name);
+			kfree(edev->d_attrs_muex);
+			kfree(edev->attrs_muex);
+		}
+
+		for (index = 0; index < edev->max_supported; index++)
+			kfree(edev->cables[index].attr_g.name);
+
+		if (edev->max_supported) {
+			kfree(edev->extcon_dev_type.groups);
+			kfree(edev->cables);
+		}
+
+		device_unregister(edev->dev);
+		put_device(edev->dev);
+	}
+
+	kfree(edev->dev);
+}
+
+static void extcon_dev_release(struct device *dev)
+{
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	extcon_cleanup(edev, true);
+}
+
+static const char *muex_name = "mutually_exclusive";
+static void dummy_sysfs_dev_release(struct device *dev)
+{
+}
+
+/**
+ * extcon_dev_register() - Register a new extcon device
+ * @edev	: the new extcon device (should be allocated before calling)
+ * @dev		: the parent device for this extcon device.
+ *
+ * Among the members of edev struct, please set the "user initializing data"
+ * in any case and set the "optional callbacks" if required. However, please
+ * do not set the values of "internal data", which are initialized by
+ * this function.
+ */
+int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
+{
+	int ret, index = 0;
+
+	if (!extcon_class) {
+		ret = create_extcon_class();
+		if (ret < 0)
+			return ret;
+	}
+
+	if (edev->supported_cable) {
+		/* Get size of array */
+		for (index = 0; edev->supported_cable[index]; index++)
+			;
+		edev->max_supported = index;
+	} else {
+		edev->max_supported = 0;
+	}
+
+	if (index > SUPPORTED_CABLE_MAX) {
+		dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n");
+		return -EINVAL;
+	}
+
+	edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+	if (!edev->dev)
+		return -ENOMEM;
+	edev->dev->parent = dev;
+	edev->dev->class = extcon_class;
+	edev->dev->release = extcon_dev_release;
+
+	dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
+
+	if (edev->max_supported) {
+		char buf[10];
+		char *str;
+		struct extcon_cable *cable;
+
+		edev->cables = kzalloc(sizeof(struct extcon_cable) *
+				       edev->max_supported, GFP_KERNEL);
+		if (!edev->cables) {
+			ret = -ENOMEM;
+			goto err_sysfs_alloc;
+		}
+		for (index = 0; index < edev->max_supported; index++) {
+			cable = &edev->cables[index];
+
+			snprintf(buf, 10, "cable.%d", index);
+			str = kzalloc(sizeof(char) * (strlen(buf) + 1),
+				      GFP_KERNEL);
+			if (!str) {
+				for (index--; index >= 0; index--) {
+					cable = &edev->cables[index];
+					kfree(cable->attr_g.name);
+				}
+				ret = -ENOMEM;
+
+				goto err_alloc_cables;
+			}
+			strcpy(str, buf);
+
+			cable->edev = edev;
+			cable->cable_index = index;
+			cable->attrs[0] = &cable->attr_name.attr;
+			cable->attrs[1] = &cable->attr_state.attr;
+			cable->attrs[2] = NULL;
+			cable->attr_g.name = str;
+			cable->attr_g.attrs = cable->attrs;
+
+			cable->attr_name.attr.name = "name";
+			cable->attr_name.attr.mode = 0444;
+			cable->attr_name.show = cable_name_show;
+
+			cable->attr_state.attr.name = "state";
+			cable->attr_state.attr.mode = 0644;
+			cable->attr_state.show = cable_state_show;
+			cable->attr_state.store = cable_state_store;
+		}
+	}
+
+	if (edev->max_supported && edev->mutually_exclusive) {
+		char buf[80];
+		char *name;
+
+		/* Count the size of mutually_exclusive array */
+		for (index = 0; edev->mutually_exclusive[index]; index++)
+			;
+
+		edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
+					   (index + 1), GFP_KERNEL);
+		if (!edev->attrs_muex) {
+			ret = -ENOMEM;
+			goto err_muex;
+		}
+
+		edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
+					     index, GFP_KERNEL);
+		if (!edev->d_attrs_muex) {
+			ret = -ENOMEM;
+			kfree(edev->attrs_muex);
+			goto err_muex;
+		}
+
+		for (index = 0; edev->mutually_exclusive[index]; index++) {
+			sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
+			name = kzalloc(sizeof(char) * (strlen(buf) + 1),
+				       GFP_KERNEL);
+			if (!name) {
+				for (index--; index >= 0; index--) {
+					kfree(edev->d_attrs_muex[index].attr.
+					      name);
+				}
+				kfree(edev->d_attrs_muex);
+				kfree(edev->attrs_muex);
+				ret = -ENOMEM;
+				goto err_muex;
+			}
+			strcpy(name, buf);
+			edev->d_attrs_muex[index].attr.name = name;
+			edev->d_attrs_muex[index].attr.mode = 0000;
+			edev->attrs_muex[index] = &edev->d_attrs_muex[index]
+							.attr;
+		}
+		edev->attr_g_muex.name = muex_name;
+		edev->attr_g_muex.attrs = edev->attrs_muex;
+
+	}
+
+	if (edev->max_supported) {
+		edev->extcon_dev_type.groups =
+			kzalloc(sizeof(struct attribute_group *) *
+				(edev->max_supported + 2), GFP_KERNEL);
+		if (!edev->extcon_dev_type.groups) {
+			ret = -ENOMEM;
+			goto err_alloc_groups;
+		}
+
+		edev->extcon_dev_type.name = dev_name(edev->dev);
+		edev->extcon_dev_type.release = dummy_sysfs_dev_release;
+
+		for (index = 0; index < edev->max_supported; index++)
+			edev->extcon_dev_type.groups[index] =
+				&edev->cables[index].attr_g;
+		if (edev->mutually_exclusive)
+			edev->extcon_dev_type.groups[index] =
+				&edev->attr_g_muex;
+
+		edev->dev->type = &edev->extcon_dev_type;
+	}
+
+	ret = device_register(edev->dev);
+	if (ret) {
+		put_device(edev->dev);
+		goto err_dev;
+	}
+#if defined(CONFIG_ANDROID)
+	if (switch_class)
+		ret = class_compat_create_link(switch_class, edev->dev,
+					       dev);
+#endif /* CONFIG_ANDROID */
+
+	spin_lock_init(&edev->lock);
+
+	RAW_INIT_NOTIFIER_HEAD(&edev->nh);
+
+	dev_set_drvdata(edev->dev, edev);
+	edev->state = 0;
+
+	mutex_lock(&extcon_dev_list_lock);
+	list_add(&edev->entry, &extcon_dev_list);
+	mutex_unlock(&extcon_dev_list_lock);
+
+	return 0;
+
+err_dev:
+	if (edev->max_supported)
+		kfree(edev->extcon_dev_type.groups);
+err_alloc_groups:
+	if (edev->max_supported && edev->mutually_exclusive) {
+		for (index = 0; edev->mutually_exclusive[index]; index++)
+			kfree(edev->d_attrs_muex[index].attr.name);
+		kfree(edev->d_attrs_muex);
+		kfree(edev->attrs_muex);
+	}
+err_muex:
+	for (index = 0; index < edev->max_supported; index++)
+		kfree(edev->cables[index].attr_g.name);
+err_alloc_cables:
+	if (edev->max_supported)
+		kfree(edev->cables);
+err_sysfs_alloc:
+	kfree(edev->dev);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(extcon_dev_register);
+
+/**
+ * extcon_dev_unregister() - Unregister the extcon device.
+ * @edev:	the extcon device instance to be unregitered.
+ *
+ * Note that this does not call kfree(edev) because edev was not allocated
+ * by this class.
+ */
+void extcon_dev_unregister(struct extcon_dev *edev)
+{
+	extcon_cleanup(edev, false);
+}
+EXPORT_SYMBOL_GPL(extcon_dev_unregister);
+
+static int __init extcon_class_init(void)
+{
+	return create_extcon_class();
+}
+module_init(extcon_class_init);
+
+static void __exit extcon_class_exit(void)
+{
+	class_destroy(extcon_class);
+}
+module_exit(extcon_class_exit);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("External connector (extcon) class driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon_gpio.c b/drivers/extcon/extcon_gpio.c
new file mode 100644
index 0000000..fe7a07b
--- /dev/null
+++ b/drivers/extcon/extcon_gpio.c
@@ -0,0 +1,169 @@
+/*
+ *  drivers/extcon/extcon_gpio.c
+ *
+ *  Single-state GPIO extcon driver based on extcon class
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * Modified by MyungJoo Ham <myungjoo.ham@samsung.com> to support extcon
+ * (originally switch class is supported)
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/extcon.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
+#include <linux/extcon.h>
+#include <linux/extcon/extcon_gpio.h>
+
+struct gpio_extcon_data {
+	struct extcon_dev edev;
+	unsigned gpio;
+	const char *state_on;
+	const char *state_off;
+	int irq;
+	struct delayed_work work;
+	unsigned long debounce_jiffies;
+};
+
+static void gpio_extcon_work(struct work_struct *work)
+{
+	int state;
+	struct gpio_extcon_data	*data =
+		container_of(to_delayed_work(work), struct gpio_extcon_data,
+			     work);
+
+	state = gpio_get_value(data->gpio);
+	extcon_set_state(&data->edev, state);
+}
+
+static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
+{
+	struct gpio_extcon_data *extcon_data = dev_id;
+
+	schedule_delayed_work(&extcon_data->work,
+			      extcon_data->debounce_jiffies);
+	return IRQ_HANDLED;
+}
+
+static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf)
+{
+	struct gpio_extcon_data	*extcon_data =
+		container_of(edev, struct gpio_extcon_data, edev);
+	const char *state;
+	if (extcon_get_state(edev))
+		state = extcon_data->state_on;
+	else
+		state = extcon_data->state_off;
+
+	if (state)
+		return sprintf(buf, "%s\n", state);
+	return -EINVAL;
+}
+
+static int __devinit gpio_extcon_probe(struct platform_device *pdev)
+{
+	struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_extcon_data *extcon_data;
+	int ret = 0;
+
+	if (!pdata)
+		return -EBUSY;
+	if (!pdata->irq_flags) {
+		dev_err(&pdev->dev, "IRQ flag is not specified.\n");
+		return -EINVAL;
+	}
+
+	extcon_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
+				   GFP_KERNEL);
+	if (!extcon_data)
+		return -ENOMEM;
+
+	extcon_data->edev.name = pdata->name;
+	extcon_data->gpio = pdata->gpio;
+	extcon_data->state_on = pdata->state_on;
+	extcon_data->state_off = pdata->state_off;
+	if (pdata->state_on && pdata->state_off)
+		extcon_data->edev.print_state = extcon_gpio_print_state;
+	extcon_data->debounce_jiffies = msecs_to_jiffies(pdata->debounce);
+
+	ret = extcon_dev_register(&extcon_data->edev, &pdev->dev);
+	if (ret < 0)
+		goto err_extcon_dev_register;
+
+	ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name);
+	if (ret < 0)
+		goto err_request_gpio;
+
+	INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
+
+	extcon_data->irq = gpio_to_irq(extcon_data->gpio);
+	if (extcon_data->irq < 0) {
+		ret = extcon_data->irq;
+		goto err_detect_irq_num_failed;
+	}
+
+	ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler,
+				      pdata->irq_flags, pdev->name,
+				      extcon_data);
+	if (ret < 0)
+		goto err_request_irq;
+
+	/* Perform initial detection */
+	gpio_extcon_work(&extcon_data->work.work);
+
+	return 0;
+
+err_request_irq:
+err_detect_irq_num_failed:
+	gpio_free(extcon_data->gpio);
+err_request_gpio:
+	extcon_dev_unregister(&extcon_data->edev);
+err_extcon_dev_register:
+	devm_kfree(&pdev->dev, extcon_data);
+
+	return ret;
+}
+
+static int __devexit gpio_extcon_remove(struct platform_device *pdev)
+{
+	struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&extcon_data->work);
+	gpio_free(extcon_data->gpio);
+	extcon_dev_unregister(&extcon_data->edev);
+	devm_kfree(&pdev->dev, extcon_data);
+
+	return 0;
+}
+
+static struct platform_driver gpio_extcon_driver = {
+	.probe		= gpio_extcon_probe,
+	.remove		= __devexit_p(gpio_extcon_remove),
+	.driver		= {
+		.name	= "extcon-gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(gpio_extcon_driver);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_DESCRIPTION("GPIO extcon driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index cc595eb..f5552b3 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -676,6 +676,7 @@
 
 	complete(&card->done);
 }
+EXPORT_SYMBOL_GPL(fw_card_release);
 
 void fw_core_remove_card(struct fw_card *card)
 {
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index dea2dcc..db8a965 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -820,6 +820,15 @@
 }
 EXPORT_SYMBOL(fw_send_response);
 
+/**
+ * fw_get_request_speed() - returns speed at which the @request was received
+ */
+int fw_get_request_speed(struct fw_request *request)
+{
+	return request->response.speed;
+}
+EXPORT_SYMBOL(fw_get_request_speed);
+
 static void handle_exclusive_region_request(struct fw_card *card,
 					    struct fw_packet *p,
 					    struct fw_request *request,
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 9047f55..b5a2f61 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -120,21 +120,6 @@
 void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset);
 void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
 
-static inline struct fw_card *fw_card_get(struct fw_card *card)
-{
-	kref_get(&card->kref);
-
-	return card;
-}
-
-void fw_card_release(struct kref *kref);
-
-static inline void fw_card_put(struct fw_card *card)
-{
-	kref_put(&card->kref, fw_card_release);
-}
-
-
 /* -cdev */
 
 extern const struct file_operations fw_device_ops;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e03653d..eb80ba3 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -91,6 +91,12 @@
 	help
 	  Say yes here to support GPIO functionality of IT8761E super I/O chip.
 
+config GPIO_EM
+	tristate "Emma Mobile GPIO"
+	depends on ARM
+	help
+	  Say yes here to support GPIO on Renesas Emma Mobile SoCs.
+
 config GPIO_EP93XX
 	def_bool y
 	depends on ARCH_EP93XX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 007f54b..708ffb2 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -15,6 +15,7 @@
 obj-$(CONFIG_GPIO_CS5535)	+= gpio-cs5535.o
 obj-$(CONFIG_GPIO_DA9052)	+= gpio-da9052.o
 obj-$(CONFIG_ARCH_DAVINCI)	+= gpio-davinci.o
+obj-$(CONFIG_GPIO_EM)		+= gpio-em.o
 obj-$(CONFIG_GPIO_EP93XX)	+= gpio-ep93xx.o
 obj-$(CONFIG_GPIO_GE_FPGA)	+= gpio-ge.o
 obj-$(CONFIG_GPIO_IT8761E)	+= gpio-it8761e.o
@@ -36,7 +37,6 @@
 obj-$(CONFIG_GPIO_MSM_V2)	+= gpio-msm-v2.o
 obj-$(CONFIG_GPIO_MXC)		+= gpio-mxc.o
 obj-$(CONFIG_GPIO_MXS)		+= gpio-mxs.o
-obj-$(CONFIG_PLAT_NOMADIK)	+= gpio-nomadik.o
 obj-$(CONFIG_ARCH_OMAP)		+= gpio-omap.o
 obj-$(CONFIG_GPIO_PCA953X)	+= gpio-pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)	+= gpio-pcf857x.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 3dd2939..8950f62 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -83,8 +83,7 @@
 void devm_gpio_free(struct device *dev, unsigned int gpio)
 {
 
-	WARN_ON(devres_destroy(dev, devm_gpio_release, devm_gpio_match,
+	WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match,
 		&gpio));
-	gpio_free(gpio);
 }
 EXPORT_SYMBOL(devm_gpio_free);
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
new file mode 100644
index 0000000..150d976
--- /dev/null
+++ b/drivers/gpio/gpio-em.c
@@ -0,0 +1,418 @@
+/*
+ * Emma Mobile GPIO Support - GIO
+ *
+ *  Copyright (C) 2012 Magnus Damm
+ *
+ * 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
+ *
+ * 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/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_data/gpio-em.h>
+
+struct em_gio_priv {
+	void __iomem *base0;
+	void __iomem *base1;
+	unsigned int irq_base;
+	spinlock_t sense_lock;
+	struct platform_device *pdev;
+	struct gpio_chip gpio_chip;
+	struct irq_chip irq_chip;
+	struct irq_domain *irq_domain;
+};
+
+#define GIO_E1 0x00
+#define GIO_E0 0x04
+#define GIO_EM 0x04
+#define GIO_OL 0x08
+#define GIO_OH 0x0c
+#define GIO_I 0x10
+#define GIO_IIA 0x14
+#define GIO_IEN 0x18
+#define GIO_IDS 0x1c
+#define GIO_IIM 0x1c
+#define GIO_RAW 0x20
+#define GIO_MST 0x24
+#define GIO_IIR 0x28
+
+#define GIO_IDT0 0x40
+#define GIO_IDT1 0x44
+#define GIO_IDT2 0x48
+#define GIO_IDT3 0x4c
+#define GIO_RAWBL 0x50
+#define GIO_RAWBH 0x54
+#define GIO_IRBL 0x58
+#define GIO_IRBH 0x5c
+
+#define GIO_IDT(n) (GIO_IDT0 + ((n) * 4))
+
+static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs)
+{
+	if (offs < GIO_IDT0)
+		return ioread32(p->base0 + offs);
+	else
+		return ioread32(p->base1 + (offs - GIO_IDT0));
+}
+
+static inline void em_gio_write(struct em_gio_priv *p, int offs,
+				unsigned long value)
+{
+	if (offs < GIO_IDT0)
+		iowrite32(value, p->base0 + offs);
+	else
+		iowrite32(value, p->base1 + (offs - GIO_IDT0));
+}
+
+static inline struct em_gio_priv *irq_to_priv(struct irq_data *d)
+{
+	struct irq_chip *chip = irq_data_get_irq_chip(d);
+	return container_of(chip, struct em_gio_priv, irq_chip);
+}
+
+static void em_gio_irq_disable(struct irq_data *d)
+{
+	struct em_gio_priv *p = irq_to_priv(d);
+
+	em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d)));
+}
+
+static void em_gio_irq_enable(struct irq_data *d)
+{
+	struct em_gio_priv *p = irq_to_priv(d);
+
+	em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
+}
+
+#define GIO_ASYNC(x) (x + 8)
+
+static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+	[IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00),
+	[IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01),
+	[IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02),
+	[IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03),
+	[IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04),
+};
+
+static int em_gio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+	unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK];
+	struct em_gio_priv *p = irq_to_priv(d);
+	unsigned int reg, offset, shift;
+	unsigned long flags;
+	unsigned long tmp;
+
+	if (!value)
+		return -EINVAL;
+
+	offset = irqd_to_hwirq(d);
+
+	pr_debug("gio: sense irq = %d, mode = %d\n", offset, value);
+
+	/* 8 x 4 bit fields in 4 IDT registers */
+	reg = GIO_IDT(offset >> 3);
+	shift = (offset & 0x07) << 4;
+
+	spin_lock_irqsave(&p->sense_lock, flags);
+
+	/* disable the interrupt in IIA */
+	tmp = em_gio_read(p, GIO_IIA);
+	tmp &= ~BIT(offset);
+	em_gio_write(p, GIO_IIA, tmp);
+
+	/* change the sense setting in IDT */
+	tmp = em_gio_read(p, reg);
+	tmp &= ~(0xf << shift);
+	tmp |= value << shift;
+	em_gio_write(p, reg, tmp);
+
+	/* clear pending interrupts */
+	em_gio_write(p, GIO_IIR, BIT(offset));
+
+	/* enable the interrupt in IIA */
+	tmp = em_gio_read(p, GIO_IIA);
+	tmp |= BIT(offset);
+	em_gio_write(p, GIO_IIA, tmp);
+
+	spin_unlock_irqrestore(&p->sense_lock, flags);
+
+	return 0;
+}
+
+static irqreturn_t em_gio_irq_handler(int irq, void *dev_id)
+{
+	struct em_gio_priv *p = dev_id;
+	unsigned long pending;
+	unsigned int offset, irqs_handled = 0;
+
+	while ((pending = em_gio_read(p, GIO_MST))) {
+		offset = __ffs(pending);
+		em_gio_write(p, GIO_IIR, BIT(offset));
+		generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
+		irqs_handled++;
+	}
+
+	return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
+{
+	return container_of(chip, struct em_gio_priv, gpio_chip);
+}
+
+static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	em_gio_write(gpio_to_priv(chip), GIO_E0, BIT(offset));
+	return 0;
+}
+
+static int em_gio_get(struct gpio_chip *chip, unsigned offset)
+{
+	return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
+}
+
+static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
+			 unsigned shift, int value)
+{
+	/* upper 16 bits contains mask and lower 16 actual value */
+	em_gio_write(gpio_to_priv(chip), reg,
+		     (1 << (shift + 16)) | (value << shift));
+}
+
+static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	/* output is split into two registers */
+	if (offset < 16)
+		__em_gio_set(chip, GIO_OL, offset, value);
+	else
+		__em_gio_set(chip, GIO_OH, offset - 16, value);
+}
+
+static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
+				   int value)
+{
+	/* write GPIO value to output before selecting output mode of pin */
+	em_gio_set(chip, offset, value);
+	em_gio_write(gpio_to_priv(chip), GIO_E1, BIT(offset));
+	return 0;
+}
+
+static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
+}
+
+static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
+				 irq_hw_number_t hw)
+{
+	struct em_gio_priv *p = h->host_data;
+
+	pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq);
+
+	irq_set_chip_data(virq, h->host_data);
+	irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
+	set_irq_flags(virq, IRQF_VALID); /* kill me now */
+	return 0;
+}
+
+static struct irq_domain_ops em_gio_irq_domain_ops = {
+	.map	= em_gio_irq_domain_map,
+};
+
+static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
+{
+	struct platform_device *pdev = p->pdev;
+	struct gpio_em_config *pdata = pdev->dev.platform_data;
+
+	p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
+				      pdata->number_of_pins, numa_node_id());
+	if (IS_ERR_VALUE(p->irq_base)) {
+		dev_err(&pdev->dev, "cannot get irq_desc\n");
+		return -ENXIO;
+	}
+	pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
+		 pdata->gpio_base, pdata->number_of_pins, p->irq_base);
+
+	p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
+					      pdata->number_of_pins,
+					      p->irq_base, 0,
+					      &em_gio_irq_domain_ops, p);
+	if (!p->irq_domain) {
+		irq_free_descs(p->irq_base, pdata->number_of_pins);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p)
+{
+	struct gpio_em_config *pdata = p->pdev->dev.platform_data;
+
+	irq_free_descs(p->irq_base, pdata->number_of_pins);
+	/* FIXME: irq domain wants to be freed! */
+}
+
+static int __devinit em_gio_probe(struct platform_device *pdev)
+{
+	struct gpio_em_config *pdata = pdev->dev.platform_data;
+	struct em_gio_priv *p;
+	struct resource *io[2], *irq[2];
+	struct gpio_chip *gpio_chip;
+	struct irq_chip *irq_chip;
+	const char *name = dev_name(&pdev->dev);
+	int ret;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		dev_err(&pdev->dev, "failed to allocate driver data\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	p->pdev = pdev;
+	platform_set_drvdata(pdev, p);
+	spin_lock_init(&p->sense_lock);
+
+	io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+	if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) {
+		dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+
+	p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0]));
+	if (!p->base0) {
+		dev_err(&pdev->dev, "failed to remap low I/O memory\n");
+		ret = -ENXIO;
+		goto err1;
+	}
+
+	p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1]));
+	if (!p->base1) {
+		dev_err(&pdev->dev, "failed to remap high I/O memory\n");
+		ret = -ENXIO;
+		goto err2;
+	}
+
+	gpio_chip = &p->gpio_chip;
+	gpio_chip->direction_input = em_gio_direction_input;
+	gpio_chip->get = em_gio_get;
+	gpio_chip->direction_output = em_gio_direction_output;
+	gpio_chip->set = em_gio_set;
+	gpio_chip->to_irq = em_gio_to_irq;
+	gpio_chip->label = name;
+	gpio_chip->owner = THIS_MODULE;
+	gpio_chip->base = pdata->gpio_base;
+	gpio_chip->ngpio = pdata->number_of_pins;
+
+	irq_chip = &p->irq_chip;
+	irq_chip->name = name;
+	irq_chip->irq_mask = em_gio_irq_disable;
+	irq_chip->irq_unmask = em_gio_irq_enable;
+	irq_chip->irq_enable = em_gio_irq_enable;
+	irq_chip->irq_disable = em_gio_irq_disable;
+	irq_chip->irq_set_type = em_gio_irq_set_type;
+	irq_chip->flags	= IRQCHIP_SKIP_SET_WAKE;
+
+	ret = em_gio_irq_domain_init(p);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot initialize irq domain\n");
+		goto err3;
+	}
+
+	if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) {
+		dev_err(&pdev->dev, "failed to request low IRQ\n");
+		ret = -ENOENT;
+		goto err4;
+	}
+
+	if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) {
+		dev_err(&pdev->dev, "failed to request high IRQ\n");
+		ret = -ENOENT;
+		goto err5;
+	}
+
+	ret = gpiochip_add(gpio_chip);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add GPIO controller\n");
+		goto err6;
+	}
+	return 0;
+
+err6:
+	free_irq(irq[1]->start, pdev);
+err5:
+	free_irq(irq[0]->start, pdev);
+err4:
+	em_gio_irq_domain_cleanup(p);
+err3:
+	iounmap(p->base1);
+err2:
+	iounmap(p->base0);
+err1:
+	kfree(p);
+err0:
+	return ret;
+}
+
+static int __devexit em_gio_remove(struct platform_device *pdev)
+{
+	struct em_gio_priv *p = platform_get_drvdata(pdev);
+	struct resource *irq[2];
+	int ret;
+
+	ret = gpiochip_remove(&p->gpio_chip);
+	if (ret)
+		return ret;
+
+	irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+	free_irq(irq[1]->start, pdev);
+	free_irq(irq[0]->start, pdev);
+	em_gio_irq_domain_cleanup(p);
+	iounmap(p->base1);
+	iounmap(p->base0);
+	kfree(p);
+	return 0;
+}
+
+static struct platform_driver em_gio_device_driver = {
+	.probe		= em_gio_probe,
+	.remove		= __devexit_p(em_gio_remove),
+	.driver		= {
+		.name	= "em_gio",
+	}
+};
+
+module_platform_driver(em_gio_device_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/gpio/gpio-nomadik.c
deleted file mode 100644
index 839624f..0000000
--- a/drivers/gpio/gpio-nomadik.c
+++ /dev/null
@@ -1,1187 +0,0 @@
-/*
- * Generic GPIO driver for logic cells found in the Nomadik SoC
- *
- * Copyright (C) 2008,2009 STMicroelectronics
- * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
- *   Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
- * Copyright (C) 2011 Linus Walleij <linus.walleij@linaro.org>
- *
- * 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/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
-
-#include <asm/mach/irq.h>
-
-#include <plat/pincfg.h>
-#include <plat/gpio-nomadik.h>
-#include <mach/hardware.h>
-#include <asm/gpio.h>
-
-/*
- * The GPIO module in the Nomadik family of Systems-on-Chip is an
- * AMBA device, managing 32 pins and alternate functions.  The logic block
- * is currently used in the Nomadik and ux500.
- *
- * Symbols in this file are called "nmk_gpio" for "nomadik gpio"
- */
-
-#define NMK_GPIO_PER_CHIP	32
-
-struct nmk_gpio_chip {
-	struct gpio_chip chip;
-	void __iomem *addr;
-	struct clk *clk;
-	unsigned int bank;
-	unsigned int parent_irq;
-	int secondary_parent_irq;
-	u32 (*get_secondary_status)(unsigned int bank);
-	void (*set_ioforce)(bool enable);
-	spinlock_t lock;
-	bool sleepmode;
-	/* Keep track of configured edges */
-	u32 edge_rising;
-	u32 edge_falling;
-	u32 real_wake;
-	u32 rwimsc;
-	u32 fwimsc;
-	u32 slpm;
-	u32 pull_up;
-};
-
-static struct nmk_gpio_chip *
-nmk_gpio_chips[DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP)];
-
-static DEFINE_SPINLOCK(nmk_gpio_slpm_lock);
-
-#define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips)
-
-static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip,
-				unsigned offset, int gpio_mode)
-{
-	u32 bit = 1 << offset;
-	u32 afunc, bfunc;
-
-	afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit;
-	bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit;
-	if (gpio_mode & NMK_GPIO_ALT_A)
-		afunc |= bit;
-	if (gpio_mode & NMK_GPIO_ALT_B)
-		bfunc |= bit;
-	writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA);
-	writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB);
-}
-
-static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip,
-				unsigned offset, enum nmk_gpio_slpm mode)
-{
-	u32 bit = 1 << offset;
-	u32 slpm;
-
-	slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC);
-	if (mode == NMK_GPIO_SLPM_NOCHANGE)
-		slpm |= bit;
-	else
-		slpm &= ~bit;
-	writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC);
-}
-
-static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
-				unsigned offset, enum nmk_gpio_pull pull)
-{
-	u32 bit = 1 << offset;
-	u32 pdis;
-
-	pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS);
-	if (pull == NMK_GPIO_PULL_NONE) {
-		pdis |= bit;
-		nmk_chip->pull_up &= ~bit;
-	} else {
-		pdis &= ~bit;
-	}
-
-	writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS);
-
-	if (pull == NMK_GPIO_PULL_UP) {
-		nmk_chip->pull_up |= bit;
-		writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
-	} else if (pull == NMK_GPIO_PULL_DOWN) {
-		nmk_chip->pull_up &= ~bit;
-		writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
-	}
-}
-
-static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
-				  unsigned offset)
-{
-	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
-}
-
-static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip,
-				  unsigned offset, int val)
-{
-	if (val)
-		writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS);
-	else
-		writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC);
-}
-
-static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
-				  unsigned offset, int val)
-{
-	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
-	__nmk_gpio_set_output(nmk_chip, offset, val);
-}
-
-static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip,
-				     unsigned offset, int gpio_mode,
-				     bool glitch)
-{
-	u32 rwimsc = readl(nmk_chip->addr + NMK_GPIO_RWIMSC);
-	u32 fwimsc = readl(nmk_chip->addr + NMK_GPIO_FWIMSC);
-
-	if (glitch && nmk_chip->set_ioforce) {
-		u32 bit = BIT(offset);
-
-		/* Prevent spurious wakeups */
-		writel(rwimsc & ~bit, nmk_chip->addr + NMK_GPIO_RWIMSC);
-		writel(fwimsc & ~bit, nmk_chip->addr + NMK_GPIO_FWIMSC);
-
-		nmk_chip->set_ioforce(true);
-	}
-
-	__nmk_gpio_set_mode(nmk_chip, offset, gpio_mode);
-
-	if (glitch && nmk_chip->set_ioforce) {
-		nmk_chip->set_ioforce(false);
-
-		writel(rwimsc, nmk_chip->addr + NMK_GPIO_RWIMSC);
-		writel(fwimsc, nmk_chip->addr + NMK_GPIO_FWIMSC);
-	}
-}
-
-static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
-			     pin_cfg_t cfg, bool sleep, unsigned int *slpmregs)
-{
-	static const char *afnames[] = {
-		[NMK_GPIO_ALT_GPIO]	= "GPIO",
-		[NMK_GPIO_ALT_A]	= "A",
-		[NMK_GPIO_ALT_B]	= "B",
-		[NMK_GPIO_ALT_C]	= "C"
-	};
-	static const char *pullnames[] = {
-		[NMK_GPIO_PULL_NONE]	= "none",
-		[NMK_GPIO_PULL_UP]	= "up",
-		[NMK_GPIO_PULL_DOWN]	= "down",
-		[3] /* illegal */	= "??"
-	};
-	static const char *slpmnames[] = {
-		[NMK_GPIO_SLPM_INPUT]		= "input/wakeup",
-		[NMK_GPIO_SLPM_NOCHANGE]	= "no-change/no-wakeup",
-	};
-
-	int pin = PIN_NUM(cfg);
-	int pull = PIN_PULL(cfg);
-	int af = PIN_ALT(cfg);
-	int slpm = PIN_SLPM(cfg);
-	int output = PIN_DIR(cfg);
-	int val = PIN_VAL(cfg);
-	bool glitch = af == NMK_GPIO_ALT_C;
-
-	dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n",
-		pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
-		output ? "output " : "input",
-		output ? (val ? "high" : "low") : "");
-
-	if (sleep) {
-		int slpm_pull = PIN_SLPM_PULL(cfg);
-		int slpm_output = PIN_SLPM_DIR(cfg);
-		int slpm_val = PIN_SLPM_VAL(cfg);
-
-		af = NMK_GPIO_ALT_GPIO;
-
-		/*
-		 * The SLPM_* values are normal values + 1 to allow zero to
-		 * mean "same as normal".
-		 */
-		if (slpm_pull)
-			pull = slpm_pull - 1;
-		if (slpm_output)
-			output = slpm_output - 1;
-		if (slpm_val)
-			val = slpm_val - 1;
-
-		dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
-			pin,
-			slpm_pull ? pullnames[pull] : "same",
-			slpm_output ? (output ? "output" : "input") : "same",
-			slpm_val ? (val ? "high" : "low") : "same");
-	}
-
-	if (output)
-		__nmk_gpio_make_output(nmk_chip, offset, val);
-	else {
-		__nmk_gpio_make_input(nmk_chip, offset);
-		__nmk_gpio_set_pull(nmk_chip, offset, pull);
-	}
-
-	/*
-	 * If we've backed up the SLPM registers (glitch workaround), modify
-	 * the backups since they will be restored.
-	 */
-	if (slpmregs) {
-		if (slpm == NMK_GPIO_SLPM_NOCHANGE)
-			slpmregs[nmk_chip->bank] |= BIT(offset);
-		else
-			slpmregs[nmk_chip->bank] &= ~BIT(offset);
-	} else
-		__nmk_gpio_set_slpm(nmk_chip, offset, slpm);
-
-	__nmk_gpio_set_mode_safe(nmk_chip, offset, af, glitch);
-}
-
-/*
- * Safe sequence used to switch IOs between GPIO and Alternate-C mode:
- *  - Save SLPM registers
- *  - Set SLPM=0 for the IOs you want to switch and others to 1
- *  - Configure the GPIO registers for the IOs that are being switched
- *  - Set IOFORCE=1
- *  - Modify the AFLSA/B registers for the IOs that are being switched
- *  - Set IOFORCE=0
- *  - Restore SLPM registers
- *  - Any spurious wake up event during switch sequence to be ignored and
- *    cleared
- */
-static void nmk_gpio_glitch_slpm_init(unsigned int *slpm)
-{
-	int i;
-
-	for (i = 0; i < NUM_BANKS; i++) {
-		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-		unsigned int temp = slpm[i];
-
-		if (!chip)
-			break;
-
-		clk_enable(chip->clk);
-
-		slpm[i] = readl(chip->addr + NMK_GPIO_SLPC);
-		writel(temp, chip->addr + NMK_GPIO_SLPC);
-	}
-}
-
-static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm)
-{
-	int i;
-
-	for (i = 0; i < NUM_BANKS; i++) {
-		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-		if (!chip)
-			break;
-
-		writel(slpm[i], chip->addr + NMK_GPIO_SLPC);
-
-		clk_disable(chip->clk);
-	}
-}
-
-static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
-{
-	static unsigned int slpm[NUM_BANKS];
-	unsigned long flags;
-	bool glitch = false;
-	int ret = 0;
-	int i;
-
-	for (i = 0; i < num; i++) {
-		if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) {
-			glitch = true;
-			break;
-		}
-	}
-
-	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
-
-	if (glitch) {
-		memset(slpm, 0xff, sizeof(slpm));
-
-		for (i = 0; i < num; i++) {
-			int pin = PIN_NUM(cfgs[i]);
-			int offset = pin % NMK_GPIO_PER_CHIP;
-
-			if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C)
-				slpm[pin / NMK_GPIO_PER_CHIP] &= ~BIT(offset);
-		}
-
-		nmk_gpio_glitch_slpm_init(slpm);
-	}
-
-	for (i = 0; i < num; i++) {
-		struct nmk_gpio_chip *nmk_chip;
-		int pin = PIN_NUM(cfgs[i]);
-
-		nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(pin));
-		if (!nmk_chip) {
-			ret = -EINVAL;
-			break;
-		}
-
-		clk_enable(nmk_chip->clk);
-		spin_lock(&nmk_chip->lock);
-		__nmk_config_pin(nmk_chip, pin - nmk_chip->chip.base,
-				 cfgs[i], sleep, glitch ? slpm : NULL);
-		spin_unlock(&nmk_chip->lock);
-		clk_disable(nmk_chip->clk);
-	}
-
-	if (glitch)
-		nmk_gpio_glitch_slpm_restore(slpm);
-
-	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
-
-	return ret;
-}
-
-/**
- * nmk_config_pin - configure a pin's mux attributes
- * @cfg: pin confguration
- *
- * Configures a pin's mode (alternate function or GPIO), its pull up status,
- * and its sleep mode based on the specified configuration.  The @cfg is
- * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
- * are constructed using, and can be further enhanced with, the macros in
- * plat/pincfg.h.
- *
- * If a pin's mode is set to GPIO, it is configured as an input to avoid
- * side-effects.  The gpio can be manipulated later using standard GPIO API
- * calls.
- */
-int nmk_config_pin(pin_cfg_t cfg, bool sleep)
-{
-	return __nmk_config_pins(&cfg, 1, sleep);
-}
-EXPORT_SYMBOL(nmk_config_pin);
-
-/**
- * nmk_config_pins - configure several pins at once
- * @cfgs: array of pin configurations
- * @num: number of elments in the array
- *
- * Configures several pins using nmk_config_pin().  Refer to that function for
- * further information.
- */
-int nmk_config_pins(pin_cfg_t *cfgs, int num)
-{
-	return __nmk_config_pins(cfgs, num, false);
-}
-EXPORT_SYMBOL(nmk_config_pins);
-
-int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num)
-{
-	return __nmk_config_pins(cfgs, num, true);
-}
-EXPORT_SYMBOL(nmk_config_pins_sleep);
-
-/**
- * nmk_gpio_set_slpm() - configure the sleep mode of a pin
- * @gpio: pin number
- * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE,
- *
- * This register is actually in the pinmux layer, not the GPIO block itself.
- * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP
- * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code).
- * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is
- * HIGH, overriding the normal setting defined by GPIO_AFSELx registers.
- * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit),
- * the GPIOs return to the normal setting defined by GPIO_AFSELx registers.
- *
- * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO
- * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is
- * entered) regardless of the altfunction selected. Also wake-up detection is
- * ENABLED.
- *
- * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains
- * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS
- * (for altfunction GPIO) or respective on-chip peripherals (for other
- * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED.
- *
- * Note that enable_irq_wake() will automatically enable wakeup detection.
- */
-int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
-{
-	struct nmk_gpio_chip *nmk_chip;
-	unsigned long flags;
-
-	nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
-	if (!nmk_chip)
-		return -EINVAL;
-
-	clk_enable(nmk_chip->clk);
-	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
-	spin_lock(&nmk_chip->lock);
-
-	__nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode);
-
-	spin_unlock(&nmk_chip->lock);
-	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-
-/**
- * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio
- * @gpio: pin number
- * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE
- *
- * Enables/disables pull up/down on a specified pin.  This only takes effect if
- * the pin is configured as an input (either explicitly or by the alternate
- * function).
- *
- * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
- * configured as an input.  Otherwise, due to the way the controller registers
- * work, this function will change the value output on the pin.
- */
-int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
-{
-	struct nmk_gpio_chip *nmk_chip;
-	unsigned long flags;
-
-	nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
-	if (!nmk_chip)
-		return -EINVAL;
-
-	clk_enable(nmk_chip->clk);
-	spin_lock_irqsave(&nmk_chip->lock, flags);
-	__nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull);
-	spin_unlock_irqrestore(&nmk_chip->lock, flags);
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-
-/* Mode functions */
-/**
- * nmk_gpio_set_mode() - set the mux mode of a gpio pin
- * @gpio: pin number
- * @gpio_mode: one of NMK_GPIO_ALT_GPIO, NMK_GPIO_ALT_A,
- *	       NMK_GPIO_ALT_B, and NMK_GPIO_ALT_C
- *
- * Sets the mode of the specified pin to one of the alternate functions or
- * plain GPIO.
- */
-int nmk_gpio_set_mode(int gpio, int gpio_mode)
-{
-	struct nmk_gpio_chip *nmk_chip;
-	unsigned long flags;
-
-	nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
-	if (!nmk_chip)
-		return -EINVAL;
-
-	clk_enable(nmk_chip->clk);
-	spin_lock_irqsave(&nmk_chip->lock, flags);
-	__nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode);
-	spin_unlock_irqrestore(&nmk_chip->lock, flags);
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-EXPORT_SYMBOL(nmk_gpio_set_mode);
-
-int nmk_gpio_get_mode(int gpio)
-{
-	struct nmk_gpio_chip *nmk_chip;
-	u32 afunc, bfunc, bit;
-
-	nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
-	if (!nmk_chip)
-		return -EINVAL;
-
-	bit = 1 << (gpio - nmk_chip->chip.base);
-
-	clk_enable(nmk_chip->clk);
-
-	afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit;
-	bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit;
-
-	clk_disable(nmk_chip->clk);
-
-	return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0);
-}
-EXPORT_SYMBOL(nmk_gpio_get_mode);
-
-
-/* IRQ functions */
-static inline int nmk_gpio_get_bitmask(int gpio)
-{
-	return 1 << (gpio % 32);
-}
-
-static void nmk_gpio_irq_ack(struct irq_data *d)
-{
-	int gpio;
-	struct nmk_gpio_chip *nmk_chip;
-
-	gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
-	nmk_chip = irq_data_get_irq_chip_data(d);
-	if (!nmk_chip)
-		return;
-
-	clk_enable(nmk_chip->clk);
-	writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
-	clk_disable(nmk_chip->clk);
-}
-
-enum nmk_gpio_irq_type {
-	NORMAL,
-	WAKE,
-};
-
-static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
-				  int gpio, enum nmk_gpio_irq_type which,
-				  bool enable)
-{
-	u32 rimsc = which == WAKE ? NMK_GPIO_RWIMSC : NMK_GPIO_RIMSC;
-	u32 fimsc = which == WAKE ? NMK_GPIO_FWIMSC : NMK_GPIO_FIMSC;
-	u32 bitmask = nmk_gpio_get_bitmask(gpio);
-	u32 reg;
-
-	/* we must individually set/clear the two edges */
-	if (nmk_chip->edge_rising & bitmask) {
-		reg = readl(nmk_chip->addr + rimsc);
-		if (enable)
-			reg |= bitmask;
-		else
-			reg &= ~bitmask;
-		writel(reg, nmk_chip->addr + rimsc);
-	}
-	if (nmk_chip->edge_falling & bitmask) {
-		reg = readl(nmk_chip->addr + fimsc);
-		if (enable)
-			reg |= bitmask;
-		else
-			reg &= ~bitmask;
-		writel(reg, nmk_chip->addr + fimsc);
-	}
-}
-
-static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
-				int gpio, bool on)
-{
-	if (nmk_chip->sleepmode) {
-		__nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base,
-				    on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
-				    : NMK_GPIO_SLPM_WAKEUP_DISABLE);
-	}
-
-	__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
-}
-
-static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
-{
-	int gpio;
-	struct nmk_gpio_chip *nmk_chip;
-	unsigned long flags;
-	u32 bitmask;
-
-	gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
-	nmk_chip = irq_data_get_irq_chip_data(d);
-	bitmask = nmk_gpio_get_bitmask(gpio);
-	if (!nmk_chip)
-		return -EINVAL;
-
-	clk_enable(nmk_chip->clk);
-	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
-	spin_lock(&nmk_chip->lock);
-
-	__nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, enable);
-
-	if (!(nmk_chip->real_wake & bitmask))
-		__nmk_gpio_set_wake(nmk_chip, gpio, enable);
-
-	spin_unlock(&nmk_chip->lock);
-	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-
-static void nmk_gpio_irq_mask(struct irq_data *d)
-{
-	nmk_gpio_irq_maskunmask(d, false);
-}
-
-static void nmk_gpio_irq_unmask(struct irq_data *d)
-{
-	nmk_gpio_irq_maskunmask(d, true);
-}
-
-static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
-{
-	struct nmk_gpio_chip *nmk_chip;
-	unsigned long flags;
-	u32 bitmask;
-	int gpio;
-
-	gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
-	nmk_chip = irq_data_get_irq_chip_data(d);
-	if (!nmk_chip)
-		return -EINVAL;
-	bitmask = nmk_gpio_get_bitmask(gpio);
-
-	clk_enable(nmk_chip->clk);
-	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
-	spin_lock(&nmk_chip->lock);
-
-	if (irqd_irq_disabled(d))
-		__nmk_gpio_set_wake(nmk_chip, gpio, on);
-
-	if (on)
-		nmk_chip->real_wake |= bitmask;
-	else
-		nmk_chip->real_wake &= ~bitmask;
-
-	spin_unlock(&nmk_chip->lock);
-	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-
-static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
-{
-	bool enabled = !irqd_irq_disabled(d);
-	bool wake = irqd_is_wakeup_set(d);
-	int gpio;
-	struct nmk_gpio_chip *nmk_chip;
-	unsigned long flags;
-	u32 bitmask;
-
-	gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
-	nmk_chip = irq_data_get_irq_chip_data(d);
-	bitmask = nmk_gpio_get_bitmask(gpio);
-	if (!nmk_chip)
-		return -EINVAL;
-
-	if (type & IRQ_TYPE_LEVEL_HIGH)
-		return -EINVAL;
-	if (type & IRQ_TYPE_LEVEL_LOW)
-		return -EINVAL;
-
-	clk_enable(nmk_chip->clk);
-	spin_lock_irqsave(&nmk_chip->lock, flags);
-
-	if (enabled)
-		__nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false);
-
-	if (enabled || wake)
-		__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false);
-
-	nmk_chip->edge_rising &= ~bitmask;
-	if (type & IRQ_TYPE_EDGE_RISING)
-		nmk_chip->edge_rising |= bitmask;
-
-	nmk_chip->edge_falling &= ~bitmask;
-	if (type & IRQ_TYPE_EDGE_FALLING)
-		nmk_chip->edge_falling |= bitmask;
-
-	if (enabled)
-		__nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true);
-
-	if (enabled || wake)
-		__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
-
-	spin_unlock_irqrestore(&nmk_chip->lock, flags);
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-
-static unsigned int nmk_gpio_irq_startup(struct irq_data *d)
-{
-	struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
-
-	clk_enable(nmk_chip->clk);
-	nmk_gpio_irq_unmask(d);
-	return 0;
-}
-
-static void nmk_gpio_irq_shutdown(struct irq_data *d)
-{
-	struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
-
-	nmk_gpio_irq_mask(d);
-	clk_disable(nmk_chip->clk);
-}
-
-static struct irq_chip nmk_gpio_irq_chip = {
-	.name		= "Nomadik-GPIO",
-	.irq_ack	= nmk_gpio_irq_ack,
-	.irq_mask	= nmk_gpio_irq_mask,
-	.irq_unmask	= nmk_gpio_irq_unmask,
-	.irq_set_type	= nmk_gpio_irq_set_type,
-	.irq_set_wake	= nmk_gpio_irq_set_wake,
-	.irq_startup	= nmk_gpio_irq_startup,
-	.irq_shutdown	= nmk_gpio_irq_shutdown,
-};
-
-static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
-				   u32 status)
-{
-	struct nmk_gpio_chip *nmk_chip;
-	struct irq_chip *host_chip = irq_get_chip(irq);
-	unsigned int first_irq;
-
-	chained_irq_enter(host_chip, desc);
-
-	nmk_chip = irq_get_handler_data(irq);
-	first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
-	while (status) {
-		int bit = __ffs(status);
-
-		generic_handle_irq(first_irq + bit);
-		status &= ~BIT(bit);
-	}
-
-	chained_irq_exit(host_chip, desc);
-}
-
-static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-	struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
-	u32 status;
-
-	clk_enable(nmk_chip->clk);
-	status = readl(nmk_chip->addr + NMK_GPIO_IS);
-	clk_disable(nmk_chip->clk);
-
-	__nmk_gpio_irq_handler(irq, desc, status);
-}
-
-static void nmk_gpio_secondary_irq_handler(unsigned int irq,
-					   struct irq_desc *desc)
-{
-	struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
-	u32 status = nmk_chip->get_secondary_status(nmk_chip->bank);
-
-	__nmk_gpio_irq_handler(irq, desc, status);
-}
-
-static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
-{
-	unsigned int first_irq;
-	int i;
-
-	first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
-	for (i = first_irq; i < first_irq + nmk_chip->chip.ngpio; i++) {
-		irq_set_chip_and_handler(i, &nmk_gpio_irq_chip,
-					 handle_edge_irq);
-		set_irq_flags(i, IRQF_VALID);
-		irq_set_chip_data(i, nmk_chip);
-		irq_set_irq_type(i, IRQ_TYPE_EDGE_FALLING);
-	}
-
-	irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
-	irq_set_handler_data(nmk_chip->parent_irq, nmk_chip);
-
-	if (nmk_chip->secondary_parent_irq >= 0) {
-		irq_set_chained_handler(nmk_chip->secondary_parent_irq,
-					nmk_gpio_secondary_irq_handler);
-		irq_set_handler_data(nmk_chip->secondary_parent_irq, nmk_chip);
-	}
-
-	return 0;
-}
-
-/* I/O Functions */
-static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
-{
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
-
-	clk_enable(nmk_chip->clk);
-
-	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
-
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-
-static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
-{
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
-	u32 bit = 1 << offset;
-	int value;
-
-	clk_enable(nmk_chip->clk);
-
-	value = (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
-
-	clk_disable(nmk_chip->clk);
-
-	return value;
-}
-
-static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
-				int val)
-{
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
-
-	clk_enable(nmk_chip->clk);
-
-	__nmk_gpio_set_output(nmk_chip, offset, val);
-
-	clk_disable(nmk_chip->clk);
-}
-
-static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
-				int val)
-{
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
-
-	clk_enable(nmk_chip->clk);
-
-	__nmk_gpio_make_output(nmk_chip, offset, val);
-
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-
-static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
-
-	return NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base) + offset;
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-#include <linux/seq_file.h>
-
-static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
-	int mode;
-	unsigned		i;
-	unsigned		gpio = chip->base;
-	int			is_out;
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
-	const char *modes[] = {
-		[NMK_GPIO_ALT_GPIO]	= "gpio",
-		[NMK_GPIO_ALT_A]	= "altA",
-		[NMK_GPIO_ALT_B]	= "altB",
-		[NMK_GPIO_ALT_C]	= "altC",
-	};
-
-	clk_enable(nmk_chip->clk);
-
-	for (i = 0; i < chip->ngpio; i++, gpio++) {
-		const char *label = gpiochip_is_requested(chip, i);
-		bool pull;
-		u32 bit = 1 << i;
-
-		is_out = readl(nmk_chip->addr + NMK_GPIO_DIR) & bit;
-		pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
-		mode = nmk_gpio_get_mode(gpio);
-		seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
-			gpio, label ?: "(none)",
-			is_out ? "out" : "in ",
-			chip->get
-				? (chip->get(chip, i) ? "hi" : "lo")
-				: "?  ",
-			(mode < 0) ? "unknown" : modes[mode],
-			pull ? "pull" : "none");
-
-		if (label && !is_out) {
-			int		irq = gpio_to_irq(gpio);
-			struct irq_desc	*desc = irq_to_desc(irq);
-
-			/* This races with request_irq(), set_irq_type(),
-			 * and set_irq_wake() ... but those are "rare".
-			 */
-			if (irq >= 0 && desc->action) {
-				char *trigger;
-				u32 bitmask = nmk_gpio_get_bitmask(gpio);
-
-				if (nmk_chip->edge_rising & bitmask)
-					trigger = "edge-rising";
-				else if (nmk_chip->edge_falling & bitmask)
-					trigger = "edge-falling";
-				else
-					trigger = "edge-undefined";
-
-				seq_printf(s, " irq-%d %s%s",
-					irq, trigger,
-					irqd_is_wakeup_set(&desc->irq_data)
-						? " wakeup" : "");
-			}
-		}
-
-		seq_printf(s, "\n");
-	}
-
-	clk_disable(nmk_chip->clk);
-}
-
-#else
-#define nmk_gpio_dbg_show	NULL
-#endif
-
-/* This structure is replicated for each GPIO block allocated at probe time */
-static struct gpio_chip nmk_gpio_template = {
-	.direction_input	= nmk_gpio_make_input,
-	.get			= nmk_gpio_get_input,
-	.direction_output	= nmk_gpio_make_output,
-	.set			= nmk_gpio_set_output,
-	.to_irq			= nmk_gpio_to_irq,
-	.dbg_show		= nmk_gpio_dbg_show,
-	.can_sleep		= 0,
-};
-
-void nmk_gpio_clocks_enable(void)
-{
-	int i;
-
-	for (i = 0; i < NUM_BANKS; i++) {
-		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-		if (!chip)
-			continue;
-
-		clk_enable(chip->clk);
-	}
-}
-
-void nmk_gpio_clocks_disable(void)
-{
-	int i;
-
-	for (i = 0; i < NUM_BANKS; i++) {
-		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-		if (!chip)
-			continue;
-
-		clk_disable(chip->clk);
-	}
-}
-
-/*
- * Called from the suspend/resume path to only keep the real wakeup interrupts
- * (those that have had set_irq_wake() called on them) as wakeup interrupts,
- * and not the rest of the interrupts which we needed to have as wakeups for
- * cpuidle.
- *
- * PM ops are not used since this needs to be done at the end, after all the
- * other drivers are done with their suspend callbacks.
- */
-void nmk_gpio_wakeups_suspend(void)
-{
-	int i;
-
-	for (i = 0; i < NUM_BANKS; i++) {
-		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-		if (!chip)
-			break;
-
-		clk_enable(chip->clk);
-
-		chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC);
-		chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC);
-
-		writel(chip->rwimsc & chip->real_wake,
-		       chip->addr + NMK_GPIO_RWIMSC);
-		writel(chip->fwimsc & chip->real_wake,
-		       chip->addr + NMK_GPIO_FWIMSC);
-
-		if (chip->sleepmode) {
-			chip->slpm = readl(chip->addr + NMK_GPIO_SLPC);
-
-			/* 0 -> wakeup enable */
-			writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC);
-		}
-
-		clk_disable(chip->clk);
-	}
-}
-
-void nmk_gpio_wakeups_resume(void)
-{
-	int i;
-
-	for (i = 0; i < NUM_BANKS; i++) {
-		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-		if (!chip)
-			break;
-
-		clk_enable(chip->clk);
-
-		writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
-		writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
-
-		if (chip->sleepmode)
-			writel(chip->slpm, chip->addr + NMK_GPIO_SLPC);
-
-		clk_disable(chip->clk);
-	}
-}
-
-/*
- * Read the pull up/pull down status.
- * A bit set in 'pull_up' means that pull up
- * is selected if pull is enabled in PDIS register.
- * Note: only pull up/down set via this driver can
- * be detected due to HW limitations.
- */
-void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
-{
-	if (gpio_bank < NUM_BANKS) {
-		struct nmk_gpio_chip *chip = nmk_gpio_chips[gpio_bank];
-
-		if (!chip)
-			return;
-
-		*pull_up = chip->pull_up;
-	}
-}
-
-static int __devinit nmk_gpio_probe(struct platform_device *dev)
-{
-	struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
-	struct nmk_gpio_chip *nmk_chip;
-	struct gpio_chip *chip;
-	struct resource *res;
-	struct clk *clk;
-	int secondary_irq;
-	int irq;
-	int ret;
-
-	if (!pdata)
-		return -ENODEV;
-
-	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -ENOENT;
-		goto out;
-	}
-
-	irq = platform_get_irq(dev, 0);
-	if (irq < 0) {
-		ret = irq;
-		goto out;
-	}
-
-	secondary_irq = platform_get_irq(dev, 1);
-	if (secondary_irq >= 0 && !pdata->get_secondary_status) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (request_mem_region(res->start, resource_size(res),
-			       dev_name(&dev->dev)) == NULL) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	clk = clk_get(&dev->dev, NULL);
-	if (IS_ERR(clk)) {
-		ret = PTR_ERR(clk);
-		goto out_release;
-	}
-
-	nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
-	if (!nmk_chip) {
-		ret = -ENOMEM;
-		goto out_clk;
-	}
-	/*
-	 * The virt address in nmk_chip->addr is in the nomadik register space,
-	 * so we can simply convert the resource address, without remapping
-	 */
-	nmk_chip->bank = dev->id;
-	nmk_chip->clk = clk;
-	nmk_chip->addr = io_p2v(res->start);
-	nmk_chip->chip = nmk_gpio_template;
-	nmk_chip->parent_irq = irq;
-	nmk_chip->secondary_parent_irq = secondary_irq;
-	nmk_chip->get_secondary_status = pdata->get_secondary_status;
-	nmk_chip->set_ioforce = pdata->set_ioforce;
-	nmk_chip->sleepmode = pdata->supports_sleepmode;
-	spin_lock_init(&nmk_chip->lock);
-
-	chip = &nmk_chip->chip;
-	chip->base = pdata->first_gpio;
-	chip->ngpio = pdata->num_gpio;
-	chip->label = pdata->name ?: dev_name(&dev->dev);
-	chip->dev = &dev->dev;
-	chip->owner = THIS_MODULE;
-
-	ret = gpiochip_add(&nmk_chip->chip);
-	if (ret)
-		goto out_free;
-
-	BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips));
-
-	nmk_gpio_chips[nmk_chip->bank] = nmk_chip;
-	platform_set_drvdata(dev, nmk_chip);
-
-	nmk_gpio_init_irq(nmk_chip);
-
-	dev_info(&dev->dev, "at address %p\n",
-		 nmk_chip->addr);
-	return 0;
-
-out_free:
-	kfree(nmk_chip);
-out_clk:
-	clk_disable(clk);
-	clk_put(clk);
-out_release:
-	release_mem_region(res->start, resource_size(res));
-out:
-	dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret,
-		  pdata->first_gpio, pdata->first_gpio+31);
-	return ret;
-}
-
-static struct platform_driver nmk_gpio_driver = {
-	.driver = {
-		.owner = THIS_MODULE,
-		.name = "gpio",
-	},
-	.probe = nmk_gpio_probe,
-};
-
-static int __init nmk_gpio_init(void)
-{
-	return platform_driver_register(&nmk_gpio_driver);
-}
-
-core_initcall(nmk_gpio_init);
-
-MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini");
-MODULE_DESCRIPTION("Nomadik GPIO Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index fc3ace3..58a6a63 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -11,13 +11,17 @@
  *  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/clk.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/gpio-pxa.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/syscore_ops.h>
 #include <linux/slab.h>
@@ -56,6 +60,10 @@
 
 int pxa_last_gpio;
 
+#ifdef CONFIG_OF
+static struct irq_domain *domain;
+#endif
+
 struct pxa_gpio_chip {
 	struct gpio_chip chip;
 	void __iomem	*regbase;
@@ -81,7 +89,6 @@
 	PXA3XX_GPIO,
 	PXA93X_GPIO,
 	MMP_GPIO = 0x10,
-	MMP2_GPIO,
 };
 
 static DEFINE_SPINLOCK(gpio_lock);
@@ -475,22 +482,92 @@
 		gpio_type = MMP_GPIO;
 	} else if (cpu_is_mmp2()) {
 		count = 191;
-		gpio_type = MMP2_GPIO;
+		gpio_type = MMP_GPIO;
 	}
 #endif /* CONFIG_ARCH_MMP */
 	return count;
 }
 
+static struct of_device_id pxa_gpio_dt_ids[] = {
+	{ .compatible = "mrvl,pxa-gpio" },
+	{ .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO },
+	{}
+};
+
+static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
+			      irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+				 handle_edge_irq);
+	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+	return 0;
+}
+
+const struct irq_domain_ops pxa_irq_domain_ops = {
+	.map	= pxa_irq_domain_map,
+};
+
+#ifdef CONFIG_OF
+static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
+{
+	int ret, nr_banks, nr_gpios, irq_base;
+	struct device_node *prev, *next, *np = pdev->dev.of_node;
+	const struct of_device_id *of_id =
+				of_match_device(pxa_gpio_dt_ids, &pdev->dev);
+
+	if (!of_id) {
+		dev_err(&pdev->dev, "Failed to find gpio controller\n");
+		return -EFAULT;
+	}
+	gpio_type = (int)of_id->data;
+
+	next = of_get_next_child(np, NULL);
+	prev = next;
+	if (!next) {
+		dev_err(&pdev->dev, "Failed to find child gpio node\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	for (nr_banks = 1; ; nr_banks++) {
+		next = of_get_next_child(np, prev);
+		if (!next)
+			break;
+		prev = next;
+	}
+	of_node_put(prev);
+	nr_gpios = nr_banks << 5;
+	pxa_last_gpio = nr_gpios - 1;
+
+	irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
+	if (irq_base < 0) {
+		dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
+		goto err;
+	}
+	domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
+				       &pxa_irq_domain_ops, NULL);
+	return 0;
+err:
+	iounmap(gpio_reg_base);
+	return ret;
+}
+#else
+#define pxa_gpio_probe_dt(pdev)		(-1)
+#endif
+
 static int __devinit pxa_gpio_probe(struct platform_device *pdev)
 {
 	struct pxa_gpio_chip *c;
 	struct resource *res;
 	struct clk *clk;
 	struct pxa_gpio_platform_data *info;
-	int gpio, irq, ret;
+	int gpio, irq, ret, use_of = 0;
 	int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
 
-	pxa_last_gpio = pxa_gpio_nums();
+	ret = pxa_gpio_probe_dt(pdev);
+	if (ret < 0)
+		pxa_last_gpio = pxa_gpio_nums();
+	else
+		use_of = 1;
 	if (!pxa_last_gpio)
 		return -EINVAL;
 
@@ -545,25 +622,27 @@
 			writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
 	}
 
+	if (!use_of) {
 #ifdef CONFIG_ARCH_PXA
-	irq = gpio_to_irq(0);
-	irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
-				 handle_edge_irq);
-	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-	irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
-
-	irq = gpio_to_irq(1);
-	irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
-				 handle_edge_irq);
-	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-	irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
-#endif
-
-	for (irq  = gpio_to_irq(gpio_offset);
-		irq <= gpio_to_irq(pxa_last_gpio); irq++) {
+		irq = gpio_to_irq(0);
 		irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
 					 handle_edge_irq);
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
+
+		irq = gpio_to_irq(1);
+		irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+					 handle_edge_irq);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
+#endif
+
+		for (irq  = gpio_to_irq(gpio_offset);
+			irq <= gpio_to_irq(pxa_last_gpio); irq++) {
+			irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+						 handle_edge_irq);
+			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		}
 	}
 
 	irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
@@ -574,6 +653,7 @@
 	.probe		= pxa_gpio_probe,
 	.driver		= {
 		.name	= "pxa-gpio",
+		.of_match_table = pxa_gpio_dt_ids,
 	},
 };
 
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 12f349b3..dc5184d 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -26,10 +26,10 @@
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/irqdomain.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <asm/mach/irq.h>
 
-#include <mach/gpio-tegra.h>
 #include <mach/iomap.h>
 #include <mach/suspend.h>
 
@@ -108,18 +108,29 @@
 	tegra_gpio_writel(val, reg);
 }
 
-void tegra_gpio_enable(int gpio)
+static void tegra_gpio_enable(int gpio)
 {
 	tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
 }
 EXPORT_SYMBOL_GPL(tegra_gpio_enable);
 
-void tegra_gpio_disable(int gpio)
+static void tegra_gpio_disable(int gpio)
 {
 	tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
 }
 EXPORT_SYMBOL_GPL(tegra_gpio_disable);
 
+int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	return pinctrl_request_gpio(offset);
+}
+
+void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	pinctrl_free_gpio(offset);
+	tegra_gpio_disable(offset);
+}
+
 static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value);
@@ -133,6 +144,7 @@
 static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
 	tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
+	tegra_gpio_enable(offset);
 	return 0;
 }
 
@@ -141,6 +153,7 @@
 {
 	tegra_gpio_set(chip, offset, value);
 	tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
+	tegra_gpio_enable(offset);
 	return 0;
 }
 
@@ -151,13 +164,14 @@
 
 static struct gpio_chip tegra_gpio_chip = {
 	.label			= "tegra-gpio",
+	.request		= tegra_gpio_request,
+	.free			= tegra_gpio_free,
 	.direction_input	= tegra_gpio_direction_input,
 	.get			= tegra_gpio_get,
 	.direction_output	= tegra_gpio_direction_output,
 	.set			= tegra_gpio_set,
 	.to_irq			= tegra_gpio_to_irq,
 	.base			= 0,
-	.ngpio			= TEGRA_NR_GPIOS,
 };
 
 static void tegra_gpio_irq_ack(struct irq_data *d)
@@ -224,6 +238,9 @@
 
 	spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
 
+	tegra_gpio_mask_write(GPIO_MSK_OE(gpio), gpio, 0);
+	tegra_gpio_enable(gpio);
+
 	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
 		__irq_set_handler_locked(d->irq, handle_level_irq);
 	else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
@@ -490,20 +507,6 @@
 }
 postcore_initcall(tegra_gpio_init);
 
-void tegra_gpio_config(struct tegra_gpio_table *table, int num)
-{
-	int i;
-
-	for (i = 0; i < num; i++) {
-		int gpio = table[i].gpio;
-
-		if (table[i].enable)
-			tegra_gpio_enable(gpio);
-		else
-			tegra_gpio_disable(gpio);
-	}
-}
-
 #ifdef	CONFIG_DEBUG_FS
 
 #include <linux/debugfs.h>
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 0ebb7d4..ef67e18 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -1827,14 +1827,10 @@
 			r600_do_cleanup_cp(dev);
 		else
 			radeon_do_cleanup_cp(dev);
-		if (dev_priv->me_fw) {
-			release_firmware(dev_priv->me_fw);
-			dev_priv->me_fw = NULL;
-		}
-		if (dev_priv->pfp_fw) {
-			release_firmware(dev_priv->pfp_fw);
-			dev_priv->pfp_fw = NULL;
-		}
+		release_firmware(dev_priv->me_fw);
+		dev_priv->me_fw = NULL;
+		release_firmware(dev_priv->pfp_fw);
+		dev_priv->pfp_fw = NULL;
 	}
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index c58a036..456a77c 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -551,7 +551,7 @@
 
 	/* nothing to do if vm isn't bound */
 	if (vm->id == -1)
-		return 0;;
+		return 0;
 
 	bo_va = radeon_bo_va(bo, vm);
 	if (bo_va == NULL) {
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index c7008b5..0519b05 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -91,7 +91,7 @@
 	}
 	if (!domain) {
 		/* Do nothings */
-		printk(KERN_WARNING "Set domain withou domain !\n");
+		printk(KERN_WARNING "Set domain without domain !\n");
 		return 0;
 	}
 	if (domain == RADEON_GEM_DOMAIN_CPU) {
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ffddcba..034c80a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -32,9 +32,13 @@
 	  If unsure, say Y.
 
 config HID_BATTERY_STRENGTH
-	bool
+	bool "Battery level reporting for HID devices"
 	depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY
 	default n
+	---help---
+	This option adds support of reporting battery strength (for HID devices
+	that support this feature) through power_supply class so that userspace
+	tools, such as upower, can display it.
 
 config HIDRAW
 	bool "/dev/hidraw raw HID device support"
@@ -60,6 +64,18 @@
 menu "Special HID drivers"
 	depends on HID
 
+config HID_GENERIC
+	tristate "Generic HID driver"
+	depends on HID
+	default y
+	---help---
+	Support for generic HID devices.
+
+	To compile this driver as a module, choose M here: the module
+	will be called hid-generic.
+
+	If unsure, say Y.
+
 config HID_A4TECH
 	tristate "A4 tech mice" if EXPERT
 	depends on USB_HID
@@ -92,6 +108,12 @@
 	Say Y here if you want support for keyboards of	Apple iBooks, PowerBooks,
 	MacBooks, MacBook Pros and Apple Aluminum.
 
+config HID_AUREAL
+	tristate "Aureal"
+	depends on USB_HID
+	---help---
+	Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
+
 config HID_BELKIN
 	tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
 	depends on USB_HID
@@ -448,7 +470,7 @@
 	select FB_SYS_FOPS
 	---help---
 	  Provide access to PicoLCD's 256x64 monochrome display via a
-	  frambuffer device.
+	  framebuffer device.
 
 config HID_PICOLCD_BACKLIGHT
 	bool "Backlight control" if EXPERT
@@ -595,16 +617,10 @@
 config HID_WACOM
 	tristate "Wacom Bluetooth devices support"
 	depends on BT_HIDP
-	---help---
-	Support for Wacom Graphire Bluetooth tablet.
-
-config HID_WACOM_POWER_SUPPLY
-	bool "Wacom Bluetooth devices power supply status support"
-	depends on HID_WACOM
+	depends on LEDS_CLASS
 	select POWER_SUPPLY
 	---help---
-	  Say Y here if you want to enable power supply status monitoring for
-	  Wacom Bluetooth devices.
+	Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
 
 config HID_WIIMOTE
 	tristate "Nintendo Wii Remote support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 22f1d16..ca6cc9f 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -9,6 +9,8 @@
 
 obj-$(CONFIG_HID)		+= hid.o
 
+obj-$(CONFIG_HID_GENERIC)	+= hid-generic.o
+
 hid-$(CONFIG_HIDRAW)		+= hidraw.o
 
 hid-logitech-y		:= hid-lg.o
@@ -36,6 +38,7 @@
 obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o
 obj-$(CONFIG_HID_ACRUX)		+= hid-axff.o
 obj-$(CONFIG_HID_APPLE)		+= hid-apple.o
+obj-$(CONFIG_HID_AUREAL)        += hid-aureal.o
 obj-$(CONFIG_HID_BELKIN)	+= hid-belkin.o
 obj-$(CONFIG_HID_CHERRY)	+= hid-cherry.o
 obj-$(CONFIG_HID_CHICONY)	+= hid-chicony.o
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 299d238..fa10f84 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -234,7 +234,7 @@
 		}
 	}
 
-        if (iso_layout) {
+	if (iso_layout) {
 		if (asc->quirks & APPLE_ISO_KEYBOARD) {
 			trans = apple_find_translation(apple_iso_keyboard, usage->code);
 			if (trans) {
@@ -458,6 +458,9 @@
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
 			APPLE_ISO_KEYBOARD },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+				USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c
new file mode 100644
index 0000000..ba64b04
--- /dev/null
+++ b/drivers/hid/hid-aureal.c
@@ -0,0 +1,54 @@
+/*
+ *  HID driver for Aureal Cy se W-01RN USB_V3.1 devices
+ *
+ *  Copyright (c) 2010 Franco Catrin <fcatrin@gmail.com>
+ *  Copyright (c) 2010 Ben Cropley <bcropley@internode.on.net>
+ *
+ *  Based on HID sunplus driver by
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
+{
+	if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
+		dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n");
+		rdesc[53] = 0x65;
+	} return rdesc;
+}
+
+static const struct hid_device_id aureal_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, aureal_devices);
+
+static struct hid_driver aureal_driver = {
+	.name = "aureal",
+	.id_table = aureal_devices,
+	.report_fixup = aureal_report_fixup,
+};
+
+static int __init aureal_init(void)
+{
+	return hid_register_driver(&aureal_driver);
+}
+
+static void __exit aureal_exit(void)
+{
+	hid_unregister_driver(&aureal_driver);
+}
+
+module_init(aureal_init);
+module_exit(aureal_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 4da66b4..8e3a6b2 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -230,9 +230,16 @@
 		return -1;
 	}
 
-	if (parser->global.logical_maximum < parser->global.logical_minimum) {
-		hid_err(parser->device, "logical range invalid %d %d\n",
-				parser->global.logical_minimum, parser->global.logical_maximum);
+	/* Handle both signed and unsigned cases properly */
+	if ((parser->global.logical_minimum < 0 &&
+		parser->global.logical_maximum <
+		parser->global.logical_minimum) ||
+		(parser->global.logical_minimum >= 0 &&
+		(__u32)parser->global.logical_maximum <
+		(__u32)parser->global.logical_minimum)) {
+		dbg_hid("logical range invalid 0x%x 0x%x\n",
+			parser->global.logical_minimum,
+			parser->global.logical_maximum);
 		return -1;
 	}
 
@@ -546,12 +553,11 @@
 }
 
 /*
- * Free a device structure, all reports, and all fields.
+ * Close report. This function returns the device
+ * state to the point prior to hid_open_report().
  */
-
-static void hid_device_release(struct device *dev)
+static void hid_close_report(struct hid_device *device)
 {
-	struct hid_device *device = container_of(dev, struct hid_device, dev);
 	unsigned i, j;
 
 	for (i = 0; i < HID_REPORT_TYPES; i++) {
@@ -562,11 +568,34 @@
 			if (report)
 				hid_free_report(report);
 		}
+		memset(report_enum, 0, sizeof(*report_enum));
+		INIT_LIST_HEAD(&report_enum->report_list);
 	}
 
 	kfree(device->rdesc);
+	device->rdesc = NULL;
+	device->rsize = 0;
+
 	kfree(device->collection);
-	kfree(device);
+	device->collection = NULL;
+	device->collection_size = 0;
+	device->maxcollection = 0;
+	device->maxapplication = 0;
+
+	device->status &= ~HID_STAT_PARSED;
+}
+
+/*
+ * Free a device structure, all reports, and all fields.
+ */
+
+static void hid_device_release(struct device *dev)
+{
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+
+	hid_close_report(hid);
+	kfree(hid->dev_rdesc);
+	kfree(hid);
 }
 
 /*
@@ -636,6 +665,60 @@
 	return NULL;
 }
 
+static void hid_scan_usage(struct hid_device *hid, u32 usage)
+{
+	if (usage == HID_DG_CONTACTID)
+		hid->group = HID_GROUP_MULTITOUCH;
+}
+
+/*
+ * Scan a report descriptor before the device is added to the bus.
+ * Sets device groups and other properties that determine what driver
+ * to load.
+ */
+static int hid_scan_report(struct hid_device *hid)
+{
+	unsigned int page = 0, delim = 0;
+	__u8 *start = hid->dev_rdesc;
+	__u8 *end = start + hid->dev_rsize;
+	unsigned int u, u_min = 0, u_max = 0;
+	struct hid_item item;
+
+	hid->group = HID_GROUP_GENERIC;
+	while ((start = fetch_item(start, end, &item)) != NULL) {
+		if (item.format != HID_ITEM_FORMAT_SHORT)
+			return -EINVAL;
+		if (item.type == HID_ITEM_TYPE_GLOBAL) {
+			if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE)
+				page = item_udata(&item) << 16;
+		} else if (item.type == HID_ITEM_TYPE_LOCAL) {
+			if (delim > 1)
+				break;
+			u = item_udata(&item);
+			if (item.size <= 2)
+				u += page;
+			switch (item.tag) {
+			case HID_LOCAL_ITEM_TAG_DELIMITER:
+				delim += !!u;
+				break;
+			case HID_LOCAL_ITEM_TAG_USAGE:
+				hid_scan_usage(hid, u);
+				break;
+			case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+				u_min = u;
+				break;
+			case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+				u_max = u;
+				for (u = u_min; u <= u_max; u++)
+					hid_scan_usage(hid, u);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
 /**
  * hid_parse_report - parse device report
  *
@@ -643,15 +726,37 @@
  * @start: report start
  * @size: report size
  *
+ * Allocate the device report as read by the bus driver. This function should
+ * only be called from parse() in ll drivers.
+ */
+int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size)
+{
+	hid->dev_rdesc = kmemdup(start, size, GFP_KERNEL);
+	if (!hid->dev_rdesc)
+		return -ENOMEM;
+	hid->dev_rsize = size;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hid_parse_report);
+
+/**
+ * hid_open_report - open a driver-specific device report
+ *
+ * @device: hid device
+ *
  * Parse a report description into a hid_device structure. Reports are
  * enumerated, fields are attached to these reports.
  * 0 returned on success, otherwise nonzero error value.
+ *
+ * This function (or the equivalent hid_parse() macro) should only be
+ * called from probe() in drivers, before starting the device.
  */
-int hid_parse_report(struct hid_device *device, __u8 *start,
-		unsigned size)
+int hid_open_report(struct hid_device *device)
 {
 	struct hid_parser *parser;
 	struct hid_item item;
+	unsigned int size;
+	__u8 *start;
 	__u8 *end;
 	int ret;
 	static int (*dispatch_type[])(struct hid_parser *parser,
@@ -662,6 +767,14 @@
 		hid_parser_reserved
 	};
 
+	if (WARN_ON(device->status & HID_STAT_PARSED))
+		return -EBUSY;
+
+	start = device->dev_rdesc;
+	if (WARN_ON(!start))
+		return -ENODEV;
+	size = device->dev_rsize;
+
 	if (device->driver->report_fixup)
 		start = device->driver->report_fixup(device, start, &size);
 
@@ -679,6 +792,15 @@
 	parser->device = device;
 
 	end = start + size;
+
+	device->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
+				     sizeof(struct hid_collection), GFP_KERNEL);
+	if (!device->collection) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
 	ret = -EINVAL;
 	while ((start = fetch_item(start, end, &item)) != NULL) {
 
@@ -704,6 +826,7 @@
 				goto err;
 			}
 			vfree(parser);
+			device->status |= HID_STAT_PARSED;
 			return 0;
 		}
 	}
@@ -711,9 +834,10 @@
 	hid_err(device, "item fetching failed at offset %d\n", (int)(end - start));
 err:
 	vfree(parser);
+	hid_close_report(device);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(hid_parse_report);
+EXPORT_SYMBOL_GPL(hid_open_report);
 
 /*
  * Convert a signed n-bit integer to signed 32-bit integer. Common
@@ -1032,7 +1156,7 @@
 	return report;
 }
 
-void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
 		int interrupt)
 {
 	struct hid_report_enum *report_enum = hid->report_enum + type;
@@ -1040,10 +1164,11 @@
 	unsigned int a;
 	int rsize, csize = size;
 	u8 *cdata = data;
+	int ret = 0;
 
 	report = hid_get_report(report_enum, data);
 	if (!report)
-		return;
+		goto out;
 
 	if (report_enum->numbered) {
 		cdata++;
@@ -1063,14 +1188,19 @@
 
 	if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
 		hid->hiddev_report_event(hid, report);
-	if (hid->claimed & HID_CLAIMED_HIDRAW)
-		hidraw_report_event(hid, data, size);
+	if (hid->claimed & HID_CLAIMED_HIDRAW) {
+		ret = hidraw_report_event(hid, data, size);
+		if (ret)
+			goto out;
+	}
 
 	for (a = 0; a < report->maxfield; a++)
 		hid_input_field(hid, report->field[a], cdata, interrupt);
 
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_report_event(hid, report);
+out:
+	return ret;
 }
 EXPORT_SYMBOL_GPL(hid_report_raw_event);
 
@@ -1147,7 +1277,7 @@
 		}
 	}
 
-	hid_report_raw_event(hid, type, data, size, interrupt);
+	ret = hid_report_raw_event(hid, type, data, size, interrupt);
 
 unlock:
 	up(&hid->driver_lock);
@@ -1158,7 +1288,8 @@
 static bool hid_match_one_id(struct hid_device *hdev,
 		const struct hid_device_id *id)
 {
-	return id->bus == hdev->bus &&
+	return (id->bus == HID_BUS_ANY || id->bus == hdev->bus) &&
+		(id->group == HID_GROUP_ANY || id->group == hdev->group) &&
 		(id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
 		(id->product == HID_ANY_ID || id->product == hdev->product);
 }
@@ -1234,10 +1365,6 @@
 	if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
 				connect_mask & HID_CONNECT_HIDINPUT_FORCE))
 		hdev->claimed |= HID_CLAIMED_INPUT;
-	if (hdev->quirks & HID_QUIRK_MULTITOUCH) {
-		/* this device should be handled by hid-multitouch, skip it */
-		return -ENODEV;
-	}
 
 	if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
 			!hdev->hiddev_connect(hdev,
@@ -1314,13 +1441,10 @@
 
 /* a list of devices for which there is a specialized driver on HID bus */
 static const struct hid_device_id hid_have_special_driver[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
@@ -1385,60 +1509,33 @@
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
 	{ 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_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
 	{ 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_PIXCIR_MULTI_TOUCH) },
-	{ 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_10_1) },
-	{ 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) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
-	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL, USB_DEVICE_ID_GAMETEL_MT_MODE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, USB_DEVICE_ID_GOODTOUCH_000f) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
- 	{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6650) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
@@ -1447,7 +1544,6 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MULTITOUCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1480,8 +1576,6 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
@@ -1513,15 +1607,8 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT780) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT880) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
@@ -1538,9 +1625,6 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
@@ -1554,16 +1638,13 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
@@ -1578,16 +1659,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XAT, USB_DEVICE_ID_XAT_CSR) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX1) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX1) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR1) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX2) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX2) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
@@ -1631,6 +1703,7 @@
 		return -ENOMEM;
 
 	dynid->id.bus = bus;
+	dynid->id.group = HID_GROUP_ANY;
 	dynid->id.vendor = vendor;
 	dynid->id.product = product;
 	dynid->id.driver_data = driver_data;
@@ -1679,18 +1752,7 @@
 	struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
 
-	if ((hdev->quirks & HID_QUIRK_MULTITOUCH) &&
-		!strncmp(hdrv->name, "hid-multitouch", 14))
-		return 1;
-
-	if (!hid_match_device(hdev, hdrv))
-		return 0;
-
-	/* generic wants all that don't have specialized driver */
-	if (!strncmp(hdrv->name, "generic-", 8) && !hid_ignore_special_drivers)
-		return !hid_match_id(hdev, hid_have_special_driver);
-
-	return 1;
+	return hid_match_device(hdev, hdrv) != NULL;
 }
 
 static int hid_device_probe(struct device *dev)
@@ -1707,23 +1769,22 @@
 	if (!hdev->driver) {
 		id = hid_match_device(hdev, hdrv);
 		if (id == NULL) {
-			if (!((hdev->quirks & HID_QUIRK_MULTITOUCH) &&
-				!strncmp(hdrv->name, "hid-multitouch", 14))) {
-				ret = -ENODEV;
-				goto unlock;
-			}
+			ret = -ENODEV;
+			goto unlock;
 		}
 
 		hdev->driver = hdrv;
 		if (hdrv->probe) {
 			ret = hdrv->probe(hdev, id);
 		} else { /* default probe */
-			ret = hid_parse(hdev);
+			ret = hid_open_report(hdev);
 			if (!ret)
 				ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 		}
-		if (ret)
+		if (ret) {
+			hid_close_report(hdev);
 			hdev->driver = NULL;
+		}
 	}
 unlock:
 	up(&hdev->driver_lock);
@@ -1744,6 +1805,7 @@
 			hdrv->remove(hdev);
 		else /* default remove */
 			hid_hw_stop(hdev);
+		hid_close_report(hdev);
 		hdev->driver = NULL;
 	}
 
@@ -1751,6 +1813,23 @@
 	return 0;
 }
 
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+			     char *buf)
+{
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	int len;
+
+	len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
+		       hdev->bus, hdev->group, hdev->vendor, hdev->product);
+
+	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute hid_dev_attrs[] = {
+	__ATTR_RO(modalias),
+	__ATTR_NULL,
+};
+
 static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
@@ -1768,8 +1847,8 @@
 	if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
 		return -ENOMEM;
 
-	if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X",
-			hdev->bus, hdev->vendor, hdev->product))
+	if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
+			   hdev->bus, hdev->group, hdev->vendor, hdev->product))
 		return -ENOMEM;
 
 	return 0;
@@ -1777,6 +1856,7 @@
 
 static struct bus_type hid_bus_type = {
 	.name		= "hid",
+	.dev_attrs	= hid_dev_attrs,
 	.match		= hid_bus_match,
 	.probe		= hid_device_probe,
 	.remove		= hid_device_remove,
@@ -2075,6 +2155,26 @@
             && (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE)))
 		return -ENODEV;
 
+	/*
+	 * Read the device report descriptor once and use as template
+	 * for the driver-specific modifications.
+	 */
+	ret = hdev->ll_driver->parse(hdev);
+	if (ret)
+		return ret;
+	if (!hdev->dev_rdesc)
+		return -ENODEV;
+
+	/*
+	 * Scan generic devices for group information
+	 */
+	if (hid_ignore_special_drivers ||
+	    !hid_match_id(hdev, hid_have_special_driver)) {
+		ret = hid_scan_report(hdev);
+		if (ret)
+			hid_warn(hdev, "bad device descriptor (%d)\n", ret);
+	}
+
 	/* XXX hack, any other cleaner solution after the driver core
 	 * is converted to allow more than 20 bytes as the device name? */
 	dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
@@ -2103,7 +2203,6 @@
 struct hid_device *hid_allocate_device(void)
 {
 	struct hid_device *hdev;
-	unsigned int i;
 	int ret = -ENOMEM;
 
 	hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
@@ -2114,23 +2213,13 @@
 	hdev->dev.release = hid_device_release;
 	hdev->dev.bus = &hid_bus_type;
 
-	hdev->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
-			sizeof(struct hid_collection), GFP_KERNEL);
-	if (hdev->collection == NULL)
-		goto err;
-	hdev->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
-
-	for (i = 0; i < HID_REPORT_TYPES; i++)
-		INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
+	hid_close_report(hdev);
 
 	init_waitqueue_head(&hdev->debug_wait);
 	INIT_LIST_HEAD(&hdev->debug_list);
 	sema_init(&hdev->driver_lock, 1);
 
 	return hdev;
-err:
-	put_device(&hdev->dev);
-	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(hid_allocate_device);
 
@@ -2141,6 +2230,9 @@
 		hid_debug_unregister(hdev);
 		hdev->status &= ~HID_STAT_ADDED;
 	}
+	kfree(hdev->dev_rdesc);
+	hdev->dev_rdesc = NULL;
+	hdev->dev_rsize = 0;
 }
 
 /**
diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c
new file mode 100644
index 0000000..a8b3148
--- /dev/null
+++ b/drivers/hid/hid-generic.c
@@ -0,0 +1,53 @@
+/*
+ *  HID support for Linux
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2007-2008 Oliver Neukum
+ *  Copyright (c) 2006-2012 Jiri Kosina
+ *  Copyright (c) 2012 Henrik Rydberg
+ */
+
+/*
+ * 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/slab.h>
+#include <linux/kernel.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#include <linux/hid.h>
+
+static const struct hid_device_id hid_table[] = {
+	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_GENERIC, HID_ANY_ID, HID_ANY_ID) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, hid_table);
+
+static struct hid_driver hid_generic = {
+	.name = "hid-generic",
+	.id_table = hid_table,
+};
+
+static int __init hid_init(void)
+{
+	return hid_register_driver(&hid_generic);
+}
+
+static void __exit hid_exit(void)
+{
+	hid_unregister_driver(&hid_generic);
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
+MODULE_AUTHOR("Henrik Rydberg");
+MODULE_DESCRIPTION("HID generic driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 4066324..3d62781 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -430,6 +430,15 @@
 	return ret;
 }
 
+static int mousevsc_hid_parse(struct hid_device *hid)
+{
+	struct hv_device *dev = hid_get_drvdata(hid);
+	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
+
+	return hid_parse_report(hid, input_dev->report_desc,
+				input_dev->report_desc_size);
+}
+
 static int mousevsc_hid_open(struct hid_device *hid)
 {
 	return 0;
@@ -449,6 +458,7 @@
 }
 
 static struct hid_ll_driver mousevsc_ll_driver = {
+	.parse = mousevsc_hid_parse,
 	.open = mousevsc_hid_open,
 	.close = mousevsc_hid_close,
 	.start = mousevsc_hid_start,
@@ -506,13 +516,14 @@
 
 	sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
 
+	hid_set_drvdata(hid_dev, device);
+
 	ret = hid_add_device(hid_dev);
 	if (ret)
 		goto probe_err1;
 
-	ret = hid_parse_report(hid_dev, input_dev->report_desc,
-				input_dev->report_desc_size);
 
+	ret = hid_parse(hid_dev);
 	if (ret) {
 		hid_err(hid_dev, "parse failed\n");
 		goto probe_err2;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index e39aecb..9373f53 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -154,9 +154,15 @@
 #define USB_DEVICE_ID_ATMEL_MULTITOUCH	0x211c
 #define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER	0x2118
 
+#define USB_VENDOR_ID_AUREAL		0x0755
+#define USB_DEVICE_ID_AUREAL_W01RN	0x2626
+
 #define USB_VENDOR_ID_AVERMEDIA		0x07ca
 #define USB_DEVICE_ID_AVER_FM_MR800	0xb800
 
+#define USB_VENDOR_ID_BAANTO		0x2453
+#define USB_DEVICE_ID_BAANTO_MT_190W2	0x0100
+
 #define USB_VENDOR_ID_BELKIN		0x050d
 #define USB_DEVICE_ID_FLIP_KVM		0x3201
 
@@ -726,6 +732,7 @@
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U	0x0004
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U	0x0005
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062	0x0064
+#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850	0x0522
 
 #define USB_VENDOR_ID_UNITEC	0x227d
 #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709	0x0709
@@ -749,6 +756,7 @@
 #define USB_DEVICE_ID_WALTOP_PID_0038			0x0038
 #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH	0x0501
 #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH	0x0500
+#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET	0x0502
 
 #define USB_VENDOR_ID_WISEGROUP		0x0925
 #define USB_DEVICE_ID_SMARTJOY_PLUS	0x0005
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 002781c..132b001 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -225,7 +225,10 @@
 	 * Verify and convert units.
 	 * See HID specification v1.11 6.2.2.7 Global Items for unit decoding
 	 */
-	if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
+	switch (code) {
+	case ABS_X:
+	case ABS_Y:
+	case ABS_Z:
 		if (field->unit == 0x11) {		/* If centimeters */
 			/* Convert to millimeters */
 			unit_exponent += 1;
@@ -239,7 +242,13 @@
 		} else {
 			return 0;
 		}
-	} else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
+		break;
+
+	case ABS_RX:
+	case ABS_RY:
+	case ABS_RZ:
+	case ABS_TILT_X:
+	case ABS_TILT_Y:
 		if (field->unit == 0x14) {		/* If degrees */
 			/* Convert to radians */
 			prev = logical_extents;
@@ -250,7 +259,9 @@
 		} else if (field->unit != 0x12) {	/* If not radians */
 			return 0;
 		}
-	} else {
+		break;
+
+	default:
 		return 0;
 	}
 
@@ -623,6 +634,14 @@
 			map_key_clear(BTN_TOOL_RUBBER);
 			break;
 
+		case 0x3d: /* X Tilt */
+			map_abs_clear(ABS_TILT_X);
+			break;
+
+		case 0x3e: /* Y Tilt */
+			map_abs_clear(ABS_TILT_Y);
+			break;
+
 		case 0x33: /* Touch */
 		case 0x42: /* TipSwitch */
 		case 0x43: /* TipSwitch2 */
@@ -638,10 +657,6 @@
 			map_key_clear(BTN_STYLUS2);
 			break;
 
-		case 0x51: /* ContactID */
-			device->quirks |= HID_QUIRK_MULTITOUCH;
-			goto unknown;
-
 		default:  goto unknown;
 		}
 		break;
@@ -1208,13 +1223,6 @@
 		}
 	}
 
-	if (hid->quirks & HID_QUIRK_MULTITOUCH) {
-		/* generic hid does not know how to handle multitouch devices */
-		if (hidinput)
-			goto out_cleanup;
-		goto out_unwind;
-	}
-
 	if (hidinput && input_register_device(hidinput->input))
 		goto out_cleanup;
 
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index e7a7bd1..fc37ed6 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -109,23 +109,23 @@
 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
-	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
 
-	if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
+	if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
 			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
 		hid_info(hdev,
 			 "fixing up Logitech keyboard report descriptor\n");
 		rdesc[84] = rdesc[89] = 0x4d;
 		rdesc[85] = rdesc[90] = 0x10;
 	}
-	if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
+	if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
 			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
 			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
 		hid_info(hdev,
 			 "fixing up rel/abs in Logitech report descriptor\n");
 		rdesc[33] = rdesc[50] = 0x02;
 	}
-	if ((quirks & LG_FF4) && *rsize >= 101 &&
+	if ((drv_data->quirks & LG_FF4) && *rsize >= 101 &&
 			rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
 			rdesc[47] == 0x05 && rdesc[48] == 0x09) {
 		hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
@@ -278,7 +278,7 @@
 		  0,  0,  0,  0,  0,183,184,185,186,187,
 		188,189,190,191,192,193,194,  0,  0,  0
 	};
-	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
 	unsigned int hid = usage->hid;
 
 	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
@@ -289,7 +289,7 @@
 			lg_dinovo_mapping(hi, usage, bit, max))
 		return 1;
 
-	if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
+	if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
 		return 1;
 
 	if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
@@ -299,11 +299,11 @@
 
 	/* Special handling for Logitech Cordless Desktop */
 	if (field->application == HID_GD_MOUSE) {
-		if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
+		if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
 				(hid == 7 || hid == 8))
 			return -1;
 	} else {
-		if ((quirks & LG_EXPANDED_KEYMAP) &&
+		if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
 				hid < ARRAY_SIZE(e_keymap) &&
 				e_keymap[hid] != 0) {
 			hid_map_usage(hi, usage, bit, max, EV_KEY,
@@ -319,13 +319,13 @@
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
 {
-	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
 
-	if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
+	if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
 			(field->flags & HID_MAIN_ITEM_RELATIVE))
 		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
 
-	if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
+	if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
 			 usage->type == EV_REL || usage->type == EV_ABS))
 		clear_bit(usage->code, *bit);
 
@@ -335,9 +335,9 @@
 static int lg_event(struct hid_device *hdev, struct hid_field *field,
 		struct hid_usage *usage, __s32 value)
 {
-	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
 
-	if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
+	if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
 		input_event(field->hidinput->input, usage->type, usage->code,
 				-value);
 		return 1;
@@ -348,13 +348,20 @@
 
 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
-	unsigned long quirks = id->driver_data;
 	unsigned int connect_mask = HID_CONNECT_DEFAULT;
+	struct lg_drv_data *drv_data;
 	int ret;
 
-	hid_set_drvdata(hdev, (void *)quirks);
+	drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
+	if (!drv_data) {
+		hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
+		return -ENOMEM;
+	}
+	drv_data->quirks = id->driver_data;
+	
+	hid_set_drvdata(hdev, (void *)drv_data);
 
-	if (quirks & LG_NOGET)
+	if (drv_data->quirks & LG_NOGET)
 		hdev->quirks |= HID_QUIRK_NOGET;
 
 	ret = hid_parse(hdev);
@@ -363,7 +370,7 @@
 		goto err_free;
 	}
 
-	if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
+	if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
 		connect_mask &= ~HID_CONNECT_FF;
 
 	ret = hid_hw_start(hdev, connect_mask);
@@ -392,27 +399,29 @@
 		}
 	}
 
-	if (quirks & LG_FF)
+	if (drv_data->quirks & LG_FF)
 		lgff_init(hdev);
-	if (quirks & LG_FF2)
+	if (drv_data->quirks & LG_FF2)
 		lg2ff_init(hdev);
-	if (quirks & LG_FF3)
+	if (drv_data->quirks & LG_FF3)
 		lg3ff_init(hdev);
-	if (quirks & LG_FF4)
+	if (drv_data->quirks & LG_FF4)
 		lg4ff_init(hdev);
 
 	return 0;
 err_free:
+	kfree(drv_data);
 	return ret;
 }
 
 static void lg_remove(struct hid_device *hdev)
 {
-	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
-	if(quirks & LG_FF4)
+	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
+	if (drv_data->quirks & LG_FF4)
 		lg4ff_deinit(hdev);
 
 	hid_hw_stop(hdev);
+	kfree(drv_data);
 }
 
 static const struct hid_device_id lg_devices[] = {
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index 4b097286..d64cf8d 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -1,6 +1,11 @@
 #ifndef __HID_LG_H
 #define __HID_LG_H
 
+struct lg_drv_data {
+	unsigned long quirks;
+	void *device_props;	/* Device specific properties */
+};
+
 #ifdef CONFIG_LOGITECH_FF
 int lgff_init(struct hid_device *hdev);
 #else
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 6ecc9e2..f3390ee 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -1,7 +1,8 @@
 /*
- *  Force feedback support for Logitech Speed Force Wireless
+ *  Force feedback support for Logitech Gaming Wheels
  *
- *  http://wiibrew.org/wiki/Logitech_USB_steering_wheel
+ *  Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 &
+ *  Speed Force Wireless (WiiWheel)
  *
  *  Copyright (c) 2010 Simon Wood <simon@mungewell.org>
  */
@@ -51,20 +52,18 @@
 
 static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
 
-static bool list_inited;
-
 struct lg4ff_device_entry {
-	char  *device_id;	/* Use name in respective kobject structure's address as the ID */
 	__u16 range;
 	__u16 min_range;
 	__u16 max_range;
-	__u8  leds;
+#ifdef CONFIG_LEDS_CLASS
+	__u8  led_state;
+	struct led_classdev *led[5];
+#endif
 	struct list_head list;
 	void (*set_range)(struct hid_device *hid, u16 range);
 };
 
-static struct lg4ff_device_entry device_list;
-
 static const signed short lg4ff_wheel_effects[] = {
 	FF_CONSTANT,
 	FF_AUTOCENTER,
@@ -285,18 +284,20 @@
 /* Read current range and display it in terminal */
 static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct lg4ff_device_entry *uninitialized_var(entry);
-	struct list_head *h;
 	struct hid_device *hid = to_hid_device(dev);
+	struct lg4ff_device_entry *entry;
+	struct lg_drv_data *drv_data;
 	size_t count;
 
-	list_for_each(h, &device_list.list) {
-		entry = list_entry(h, struct lg4ff_device_entry, list);
-		if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
-			break;
+	drv_data = hid_get_drvdata(hid);
+	if (!drv_data) {
+		hid_err(hid, "Private driver data not found!\n");
+		return 0;
 	}
-	if (h == &device_list.list) {
-		dbg_hid("Device not found!");
+
+	entry = drv_data->device_props;
+	if (!entry) {
+		hid_err(hid, "Device properties not found!\n");
 		return 0;
 	}
 
@@ -308,19 +309,21 @@
  * according to the type of the wheel */
 static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct lg4ff_device_entry *uninitialized_var(entry);
-	struct list_head *h;
 	struct hid_device *hid = to_hid_device(dev);
+	struct lg4ff_device_entry *entry;
+	struct lg_drv_data *drv_data;
 	__u16 range = simple_strtoul(buf, NULL, 10);
 
-	list_for_each(h, &device_list.list) {
-		entry = list_entry(h, struct lg4ff_device_entry, list);
-		if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
-			break;
+	drv_data = hid_get_drvdata(hid);
+	if (!drv_data) {
+		hid_err(hid, "Private driver data not found!\n");
+		return 0;
 	}
-	if (h == &device_list.list) {
-		dbg_hid("Device not found!");
-		return count;
+
+	entry = drv_data->device_props;
+	if (!entry) {
+		hid_err(hid, "Device properties not found!\n");
+		return 0;
 	}
 
 	if (range == 0)
@@ -336,6 +339,88 @@
 	return count;
 }
 
+#ifdef CONFIG_LEDS_CLASS
+static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
+{
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+
+	report->field[0]->value[0] = 0xf8;
+	report->field[0]->value[1] = 0x12;
+	report->field[0]->value[2] = leds;
+	report->field[0]->value[3] = 0x00;
+	report->field[0]->value[4] = 0x00;
+	report->field[0]->value[5] = 0x00;
+	report->field[0]->value[6] = 0x00;
+	usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
+			enum led_brightness value)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+	struct lg4ff_device_entry *entry;
+	int i, state = 0;
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return;
+	}
+
+	entry = (struct lg4ff_device_entry *)drv_data->device_props;
+
+	if (!entry) {
+		hid_err(hid, "Device properties not found.");
+		return;
+	}
+
+	for (i = 0; i < 5; i++) {
+		if (led_cdev != entry->led[i])
+			continue;
+		state = (entry->led_state >> i) & 1;
+		if (value == LED_OFF && state) {
+			entry->led_state &= ~(1 << i);
+			lg4ff_set_leds(hid, entry->led_state);
+		} else if (value != LED_OFF && !state) {
+			entry->led_state |= 1 << i;
+			lg4ff_set_leds(hid, entry->led_state);
+		}
+		break;
+	}
+}
+
+static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+	struct lg4ff_device_entry *entry;
+	int i, value = 0;
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return LED_OFF;
+	}
+
+	entry = (struct lg4ff_device_entry *)drv_data->device_props;
+
+	if (!entry) {
+		hid_err(hid, "Device properties not found.");
+		return LED_OFF;
+	}
+
+	for (i = 0; i < 5; i++)
+		if (led_cdev == entry->led[i]) {
+			value = (entry->led_state >> i) & 1;
+			break;
+		}
+
+	return value ? LED_FULL : LED_OFF;
+}
+#endif
+
 int lg4ff_init(struct hid_device *hid)
 {
 	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
@@ -344,6 +429,7 @@
 	struct hid_report *report;
 	struct hid_field *field;
 	struct lg4ff_device_entry *entry;
+	struct lg_drv_data *drv_data;
 	struct usb_device_descriptor *udesc;
 	int error, i, j;
 	__u16 bcdDevice, rev_maj, rev_min;
@@ -423,28 +509,24 @@
 		dev->ff->set_autocenter(dev, 0);
 	}
 
-		/* Initialize device_list if this is the first device to handle by lg4ff */
-	if (!list_inited) {
-		INIT_LIST_HEAD(&device_list.list);
-		list_inited = 1;
+	/* Get private driver data */
+	drv_data = hid_get_drvdata(hid);
+	if (!drv_data) {
+		hid_err(hid, "Cannot add device, private driver data not allocated\n");
+		return -1;
 	}
 
-	/* Add the device to device_list */
+	/* Initialize device properties */
 	entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
 	if (!entry) {
-		hid_err(hid, "Cannot add device, insufficient memory.\n");
+		hid_err(hid, "Cannot add device, insufficient memory to allocate device properties.\n");
 		return -ENOMEM;
 	}
-	entry->device_id = kstrdup((&hid->dev)->kobj.name, GFP_KERNEL);
-	if (!entry->device_id) {
-		hid_err(hid, "Cannot set device_id, insufficient memory.\n");
-		kfree(entry);
-		return -ENOMEM;
-	}
+	drv_data->device_props = entry;
+
 	entry->min_range = lg4ff_devices[i].min_range;
 	entry->max_range = lg4ff_devices[i].max_range;
 	entry->set_range = lg4ff_devices[i].set_range;
-	list_add(&entry->list, &device_list.list);
 
 	/* Create sysfs interface */
 	error = device_create_file(&hid->dev, &dev_attr_range);
@@ -457,32 +539,100 @@
 	if (entry->set_range != NULL)
 		entry->set_range(hid, entry->range);
 
-	hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
+#ifdef CONFIG_LEDS_CLASS
+	/* register led subsystem - G27 only */
+	entry->led_state = 0;
+	for (j = 0; j < 5; j++)
+		entry->led[j] = NULL;
+
+	if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) {
+		struct led_classdev *led;
+		size_t name_sz;
+		char *name;
+
+		lg4ff_set_leds(hid, 0);
+
+		name_sz = strlen(dev_name(&hid->dev)) + 8;
+
+		for (j = 0; j < 5; j++) {
+			led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+			if (!led) {
+				hid_err(hid, "can't allocate memory for LED %d\n", j);
+				goto err;
+			}
+
+			name = (void *)(&led[1]);
+			snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1);
+			led->name = name;
+			led->brightness = 0;
+			led->max_brightness = 1;
+			led->brightness_get = lg4ff_led_get_brightness;
+			led->brightness_set = lg4ff_led_set_brightness;
+
+			entry->led[j] = led;
+			error = led_classdev_register(&hid->dev, led);
+
+			if (error) {
+				hid_err(hid, "failed to register LED %d. Aborting.\n", j);
+err:
+				/* Deregister LEDs (if any) */
+				for (j = 0; j < 5; j++) {
+					led = entry->led[j];
+					entry->led[j] = NULL;
+					if (!led)
+						continue;
+					led_classdev_unregister(led);
+					kfree(led);
+				}
+				goto out;	/* Let the driver continue without LEDs */
+			}
+		}
+	}
+out:
+#endif
+	hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n");
 	return 0;
 }
 
 int lg4ff_deinit(struct hid_device *hid)
 {
-	bool found = 0;
 	struct lg4ff_device_entry *entry;
-	struct list_head *h, *g;
-	list_for_each_safe(h, g, &device_list.list) {
-		entry = list_entry(h, struct lg4ff_device_entry, list);
-		if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) {
-			list_del(h);
-			kfree(entry->device_id);
-			kfree(entry);
-			found = 1;
-			break;
-		}
-	}
+	struct lg_drv_data *drv_data;
 
-	if (!found) {
-		dbg_hid("Device entry not found!\n");
+	device_remove_file(&hid->dev, &dev_attr_range);
+
+	drv_data = hid_get_drvdata(hid);
+	if (!drv_data) {
+		hid_err(hid, "Error while deinitializing device, no private driver data.\n");
+		return -1;
+	}
+	entry = drv_data->device_props;
+	if (!entry) {
+		hid_err(hid, "Error while deinitializing device, no device properties data.\n");
 		return -1;
 	}
 
-	device_remove_file(&hid->dev, &dev_attr_range);
+#ifdef CONFIG_LEDS_CLASS
+	{
+		int j;
+		struct led_classdev *led;
+
+		/* Deregister LEDs (if any) */
+		for (j = 0; j < 5; j++) {
+
+			led = entry->led[j];
+			entry->led[j] = NULL;
+			if (!led)
+				continue;
+			led_classdev_unregister(led);
+			kfree(led);
+		}
+	}
+#endif
+
+	/* Deallocate memory */
+	kfree(entry);
+
 	dbg_hid("Device successfully unregistered\n");
 	return 0;
 }
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 2b56efc..5e8a7ed 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -26,6 +26,7 @@
 #include <linux/hid.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <asm/unaligned.h>
 #include "usbhid/usbhid.h"
 #include "hid-ids.h"
 #include "hid-logitech-dj.h"
@@ -155,6 +156,14 @@
 /* Maximum size of all defined hid reports in bytes (including report id) */
 #define MAX_REPORT_SIZE 8
 
+/* Make sure all descriptors are present here */
+#define MAX_RDESC_SIZE				\
+	(sizeof(kbd_descriptor) +		\
+	 sizeof(mse_descriptor) +		\
+	 sizeof(consumer_descriptor) +		\
+	 sizeof(syscontrol_descriptor) +	\
+	 sizeof(media_descriptor))
+
 /* Number of possible hid report types that can be created by this driver.
  *
  * Right now, RF report types have the same report types (or report id's)
@@ -265,8 +274,8 @@
 		goto dj_device_allocate_fail;
 	}
 
-	dj_dev->reports_supported = le32_to_cpu(
-		dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]);
+	dj_dev->reports_supported = get_unaligned_le32(
+		dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE);
 	dj_dev->hdev = dj_hiddev;
 	dj_dev->dj_receiver_dev = djrcv_dev;
 	dj_dev->device_index = dj_report->device_index;
@@ -473,9 +482,17 @@
 	return 0;
 }
 
+static void rdcat(char **rdesc, unsigned int *rsize, const char *data, unsigned int size)
+{
+	memcpy(*rdesc + *rsize, data, size);
+	*rsize += size;
+}
+
 static int logi_dj_ll_parse(struct hid_device *hid)
 {
 	struct dj_device *djdev = hid->driver_data;
+	unsigned int rsize = 0;
+	char *rdesc;
 	int retval;
 
 	dbg_hid("%s\n", __func__);
@@ -483,70 +500,38 @@
 	djdev->hdev->version = 0x0111;
 	djdev->hdev->country = 0x00;
 
+	rdesc = kmalloc(MAX_RDESC_SIZE, GFP_KERNEL);
+	if (!rdesc)
+		return -ENOMEM;
+
 	if (djdev->reports_supported & STD_KEYBOARD) {
 		dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
 			__func__, djdev->reports_supported);
-		retval = hid_parse_report(hid,
-					  (u8 *) kbd_descriptor,
-					  sizeof(kbd_descriptor));
-		if (retval) {
-			dbg_hid("%s: sending a kbd descriptor, hid_parse failed"
-				" error: %d\n", __func__, retval);
-			return retval;
-		}
+		rdcat(&rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
 	}
 
 	if (djdev->reports_supported & STD_MOUSE) {
 		dbg_hid("%s: sending a mouse descriptor, reports_supported: "
 			"%x\n", __func__, djdev->reports_supported);
-		retval = hid_parse_report(hid,
-					  (u8 *) mse_descriptor,
-					  sizeof(mse_descriptor));
-		if (retval) {
-			dbg_hid("%s: sending a mouse descriptor, hid_parse "
-				"failed error: %d\n", __func__, retval);
-			return retval;
-		}
+		rdcat(&rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
 	}
 
 	if (djdev->reports_supported & MULTIMEDIA) {
 		dbg_hid("%s: sending a multimedia report descriptor: %x\n",
 			__func__, djdev->reports_supported);
-		retval = hid_parse_report(hid,
-					  (u8 *) consumer_descriptor,
-					  sizeof(consumer_descriptor));
-		if (retval) {
-			dbg_hid("%s: sending a consumer_descriptor, hid_parse "
-				"failed error: %d\n", __func__, retval);
-			return retval;
-		}
+		rdcat(&rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
 	}
 
 	if (djdev->reports_supported & POWER_KEYS) {
 		dbg_hid("%s: sending a power keys report descriptor: %x\n",
 			__func__, djdev->reports_supported);
-		retval = hid_parse_report(hid,
-					  (u8 *) syscontrol_descriptor,
-					  sizeof(syscontrol_descriptor));
-		if (retval) {
-			dbg_hid("%s: sending a syscontrol_descriptor, "
-				"hid_parse failed error: %d\n",
-				__func__, retval);
-			return retval;
-		}
+		rdcat(&rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
 	}
 
 	if (djdev->reports_supported & MEDIA_CENTER) {
 		dbg_hid("%s: sending a media center report descriptor: %x\n",
 			__func__, djdev->reports_supported);
-		retval = hid_parse_report(hid,
-					  (u8 *) media_descriptor,
-					  sizeof(media_descriptor));
-		if (retval) {
-			dbg_hid("%s: sending a media_descriptor, hid_parse "
-				"failed error: %d\n", __func__, retval);
-			return retval;
-		}
+		rdcat(&rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
 	}
 
 	if (djdev->reports_supported & KBD_LEDS) {
@@ -554,7 +539,10 @@
 			__func__, djdev->reports_supported);
 	}
 
-	return 0;
+	retval = hid_parse_report(hid, rdesc, rsize);
+	kfree(rdesc);
+
+	return retval;
 }
 
 static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 1d5b941..6e3332a 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -70,9 +70,16 @@
 	bool is_indirect;	/* true for touchpads */
 };
 
+struct mt_fields {
+	unsigned usages[HID_MAX_FIELDS];
+	unsigned int length;
+};
+
 struct mt_device {
 	struct mt_slot curdata;	/* placeholder of incoming data */
 	struct mt_class mtclass;	/* our mt device class */
+	struct mt_fields *fields;	/* temporary placeholder for storing the
+					   multitouch fields */
 	unsigned last_field_index;	/* last field index of the report */
 	unsigned last_slot_field;	/* the last field of a slot */
 	__s8 inputmode;		/* InputMode HID feature, -1 if non-existent */
@@ -110,6 +117,9 @@
 
 #define MT_DEFAULT_MAXCONTACT	10
 
+#define MT_USB_DEVICE(v, p)	HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p)
+#define MT_BT_DEVICE(v, p)	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p)
+
 /*
  * these device-dependent functions determine what slot corresponds
  * to a valid contact that was just read.
@@ -275,11 +285,15 @@
 	input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
 }
 
-static void set_last_slot_field(struct hid_usage *usage, struct mt_device *td,
+static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
 		struct hid_input *hi)
 {
-	if (!test_bit(usage->hid, hi->input->absbit))
-		td->last_slot_field = usage->hid;
+	struct mt_fields *f = td->fields;
+
+	if (f->length >= HID_MAX_FIELDS)
+		return;
+
+	f->usages[f->length++] = usage->hid;
 }
 
 static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -330,7 +344,7 @@
 				cls->sn_move);
 			/* touchscreen emulation */
 			set_abs(hi->input, ABS_X, field, cls->sn_move);
-			set_last_slot_field(usage, td, hi);
+			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		case HID_GD_Y:
@@ -340,7 +354,7 @@
 				cls->sn_move);
 			/* touchscreen emulation */
 			set_abs(hi->input, ABS_Y, field, cls->sn_move);
-			set_last_slot_field(usage, td, hi);
+			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		}
@@ -349,24 +363,24 @@
 	case HID_UP_DIGITIZER:
 		switch (usage->hid) {
 		case HID_DG_INRANGE:
-			set_last_slot_field(usage, td, hi);
+			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		case HID_DG_CONFIDENCE:
-			set_last_slot_field(usage, td, hi);
+			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		case HID_DG_TIPSWITCH:
 			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
 			input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
-			set_last_slot_field(usage, td, hi);
+			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		case HID_DG_CONTACTID:
 			if (!td->maxcontacts)
 				td->maxcontacts = MT_DEFAULT_MAXCONTACT;
 			input_mt_init_slots(hi->input, td->maxcontacts);
-			td->last_slot_field = usage->hid;
+			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			td->touches_by_report++;
 			return 1;
@@ -375,7 +389,7 @@
 					EV_ABS, ABS_MT_TOUCH_MAJOR);
 			set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
 				cls->sn_width);
-			set_last_slot_field(usage, td, hi);
+			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		case HID_DG_HEIGHT:
@@ -385,7 +399,7 @@
 				cls->sn_height);
 			input_set_abs_params(hi->input,
 					ABS_MT_ORIENTATION, 0, 1, 0, 0);
-			set_last_slot_field(usage, td, hi);
+			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		case HID_DG_TIPPRESSURE:
@@ -396,7 +410,7 @@
 			/* touchscreen emulation */
 			set_abs(hi->input, ABS_PRESSURE, field,
 				cls->sn_pressure);
-			set_last_slot_field(usage, td, hi);
+			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		case HID_DG_CONTACTCOUNT:
@@ -635,6 +649,31 @@
 	}
 }
 
+static void mt_post_parse_default_settings(struct mt_device *td)
+{
+	__s32 quirks = td->mtclass.quirks;
+
+	/* unknown serial device needs special quirks */
+	if (td->touches_by_report == 1) {
+		quirks |= MT_QUIRK_ALWAYS_VALID;
+		quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
+		quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
+		quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
+	}
+
+	td->mtclass.quirks = quirks;
+}
+
+static void mt_post_parse(struct mt_device *td)
+{
+	struct mt_fields *f = td->fields;
+
+	if (td->touches_by_report > 0) {
+		int field_count_per_touch = f->length / td->touches_by_report;
+		td->last_slot_field = f->usages[field_count_per_touch - 1];
+	}
+}
+
 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
 	int ret, i;
@@ -654,7 +693,6 @@
 	 * that emit events over several HID messages.
 	 */
 	hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
-	hdev->quirks &= ~HID_QUIRK_MULTITOUCH;
 
 	td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
 	if (!td) {
@@ -666,6 +704,13 @@
 	td->maxcontact_report_id = -1;
 	hid_set_drvdata(hdev, td);
 
+	td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
+	if (!td->fields) {
+		dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
 	ret = hid_parse(hdev);
 	if (ret != 0)
 		goto fail;
@@ -674,14 +719,10 @@
 	if (ret)
 		goto fail;
 
-	if (!id && td->touches_by_report == 1) {
-		/* the device has been sent by hid-generic */
-		mtclass = &td->mtclass;
-		mtclass->quirks |= MT_QUIRK_ALWAYS_VALID;
-		mtclass->quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
-		mtclass->quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
-		mtclass->quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
-	}
+	mt_post_parse(td);
+
+	if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
+		mt_post_parse_default_settings(td);
 
 	td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
 				GFP_KERNEL);
@@ -697,9 +738,13 @@
 	mt_set_maxcontacts(hdev);
 	mt_set_input_mode(hdev);
 
+	kfree(td->fields);
+	td->fields = NULL;
+
 	return 0;
 
 fail:
+	kfree(td->fields);
 	kfree(td);
 	return ret;
 }
@@ -727,50 +772,54 @@
 
 	/* 3M panels */
 	{ .driver_data = MT_CLS_3M,
-		HID_USB_DEVICE(USB_VENDOR_ID_3M,
+		MT_USB_DEVICE(USB_VENDOR_ID_3M,
 			USB_DEVICE_ID_3M1968) },
 	{ .driver_data = MT_CLS_3M,
-		HID_USB_DEVICE(USB_VENDOR_ID_3M,
+		MT_USB_DEVICE(USB_VENDOR_ID_3M,
 			USB_DEVICE_ID_3M2256) },
 	{ .driver_data = MT_CLS_3M,
-		HID_USB_DEVICE(USB_VENDOR_ID_3M,
+		MT_USB_DEVICE(USB_VENDOR_ID_3M,
 			USB_DEVICE_ID_3M3266) },
 
 	/* ActionStar panels */
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
+		MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
 			USB_DEVICE_ID_ACTIONSTAR_1011) },
 
 	/* Atmel panels */
 	{ .driver_data = MT_CLS_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_ATMEL,
+		MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
 			USB_DEVICE_ID_ATMEL_MULTITOUCH) },
 	{ .driver_data = MT_CLS_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_ATMEL,
+		MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
 			USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
 
+	/* Baanto multitouch devices */
+	{ .driver_data = MT_CLS_DEFAULT,
+		MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
+			USB_DEVICE_ID_BAANTO_MT_190W2) },
 	/* Cando panels */
 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-		HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
 			USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-		HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
 			USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-		HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
 			USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-		HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
 			USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
 
 	/* Chunghwa Telecom touch panels */
 	{  .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
+		MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
 			USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
 
 	/* CVTouch panels */
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
+		MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
 			USB_DEVICE_ID_CVTOUCH_SCREEN) },
 
 	/* Cypress panel */
@@ -780,225 +829,227 @@
 
 	/* eGalax devices (resistive) */
 	{ .driver_data = MT_CLS_EGALAX,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
 	{ .driver_data = MT_CLS_EGALAX,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
 
 	/* eGalax devices (capacitive) */
 	{ .driver_data = MT_CLS_EGALAX,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) },
 	{ .driver_data = MT_CLS_EGALAX,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) },
 	{ .driver_data = MT_CLS_EGALAX,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) },
 	{ .driver_data = MT_CLS_EGALAX,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) },
 	{ .driver_data = MT_CLS_EGALAX,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
 
 	/* Elo TouchSystems IntelliTouch Plus panel */
 	{ .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
-		HID_USB_DEVICE(USB_VENDOR_ID_ELO,
+		MT_USB_DEVICE(USB_VENDOR_ID_ELO,
 			USB_DEVICE_ID_ELO_TS2515) },
 
 	/* GeneralTouch panel */
 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-		HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
+		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
 			USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
 
 	/* Gametel game controller */
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL,
+		MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL,
 			USB_DEVICE_ID_GAMETEL_MT_MODE) },
 
 	/* GoodTouch panels */
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
+		MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
 			USB_DEVICE_ID_GOODTOUCH_000f) },
 
 	/* Hanvon panels */
 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
-		HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
+		MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
 			USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
 
 	/* Ideacom panel */
 	{ .driver_data = MT_CLS_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
+		MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
 			USB_DEVICE_ID_IDEACOM_IDC6650) },
 	{ .driver_data = MT_CLS_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
+		MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
 			USB_DEVICE_ID_IDEACOM_IDC6651) },
 
 	/* Ilitek dual touch panel */
 	{  .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_ILITEK,
+		MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
 			USB_DEVICE_ID_ILITEK_MULTITOUCH) },
 
 	/* IRTOUCH panels */
 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
-		HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
+		MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
 			USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
 
 	/* LG Display panels */
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_LG,
+		MT_USB_DEVICE(USB_VENDOR_ID_LG,
 			USB_DEVICE_ID_LG_MULTITOUCH) },
 
 	/* Lumio panels */
 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-		HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+		MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
 			USB_DEVICE_ID_CRYSTALTOUCH) },
 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-		HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+		MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
 			USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
 
 	/* MosArt panels */
 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-		HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+		MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
 			USB_DEVICE_ID_ASUS_T91MT)},
 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-		HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+		MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
 			USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-		HID_USB_DEVICE(USB_VENDOR_ID_TURBOX,
+		MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
 			USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
 
 	/* Panasonic panels */
 	{ .driver_data = MT_CLS_PANASONIC,
-		HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
+		MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
 			USB_DEVICE_ID_PANABOARD_UBT780) },
 	{ .driver_data = MT_CLS_PANASONIC,
-		HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
+		MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
 			USB_DEVICE_ID_PANABOARD_UBT880) },
 
 	/* PenMount panels */
 	{ .driver_data = MT_CLS_CONFIDENCE,
-		HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
+		MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
 			USB_DEVICE_ID_PENMOUNT_PCI) },
 
 	/* PixArt optical touch screen */
 	{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
-		HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+		MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
 			USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },
 	{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
-		HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+		MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
 			USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },
 	{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
-		HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+		MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
 			USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
 
 	/* PixCir-based panels */
 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
-		HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
+		MT_USB_DEVICE(USB_VENDOR_ID_HANVON,
 			USB_DEVICE_ID_HANVON_MULTITOUCH) },
 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
-		HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
 			USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
 
 	/* Quanta-based panels */
 	{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
-		HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+		MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
 			USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
 	{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
-		HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+		MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
 			USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) },
 	{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
-		HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+		MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
 			USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) },
 
 	/* Stantum panels */
 	{ .driver_data = MT_CLS_CONFIDENCE,
-		HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+		MT_USB_DEVICE(USB_VENDOR_ID_STANTUM,
 			USB_DEVICE_ID_MTP)},
 	{ .driver_data = MT_CLS_CONFIDENCE,
-		HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
+		MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
 			USB_DEVICE_ID_MTP_STM)},
 	{ .driver_data = MT_CLS_CONFIDENCE,
-		HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
+		MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
 			USB_DEVICE_ID_MTP_SITRONIX)},
 
 	/* TopSeed panels */
 	{ .driver_data = MT_CLS_TOPSEED,
-		HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
+		MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
 			USB_DEVICE_ID_TOPSEED2_PERIPAD_701) },
 
 	/* Touch International panels */
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
+		MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
 			USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
 
 	/* Unitec panels */
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+		MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
 			USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+		MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
 			USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
 	/* XAT */
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XAT,
+		MT_USB_DEVICE(USB_VENDOR_ID_XAT,
 			USB_DEVICE_ID_XAT_CSR) },
 
 	/* Xiroku */
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
 			USB_DEVICE_ID_XIROKU_SPX) },
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
 			USB_DEVICE_ID_XIROKU_MPX) },
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
 			USB_DEVICE_ID_XIROKU_CSR) },
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
 			USB_DEVICE_ID_XIROKU_SPX1) },
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
 			USB_DEVICE_ID_XIROKU_MPX1) },
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
 			USB_DEVICE_ID_XIROKU_CSR1) },
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
 			USB_DEVICE_ID_XIROKU_SPX2) },
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
 			USB_DEVICE_ID_XIROKU_MPX2) },
 	{ .driver_data = MT_CLS_DEFAULT,
-		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
 			USB_DEVICE_ID_XIROKU_CSR2) },
 
+	/* Generic MT device */
+	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, mt_devices);
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c
index 1f11289..3aba02b 100644
--- a/drivers/hid/hid-uclogic.c
+++ b/drivers/hid/hid-uclogic.c
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/usb.h>
 
 #include "hid-ids.h"
 
@@ -352,9 +353,125 @@
 	0xC0                /*  End Collection                      */
 };
 
+/*
+ * See TWHL850 description, device and HID report descriptors at
+ * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
+ */
+
+/* Size of the original descriptors of TWHL850 tablet */
+#define TWHL850_RDESC_ORIG_SIZE0	182
+#define TWHL850_RDESC_ORIG_SIZE1	161
+#define TWHL850_RDESC_ORIG_SIZE2	92
+
+/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
+static __u8 twhl850_rdesc_fixed0[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x09,         /*      Report ID (9),                  */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x09, 0x32,         /*          Usage (In Range),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
+	0x26, 0x00, 0x7D,   /*          Logical Maximum (32000),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
+	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0                /*  End Collection                      */
+};
+
+/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
+static __u8 twhl850_rdesc_fixed1[] = {
+	0x05, 0x01,         /*  Usage Page (Desktop),               */
+	0x09, 0x02,         /*  Usage (Mouse),                      */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x01,         /*      Report ID (1),                  */
+	0x09, 0x01,         /*      Usage (Pointer),                */
+	0xA0,               /*      Collection (Physical),          */
+	0x05, 0x09,         /*          Usage Page (Button),        */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x19, 0x01,         /*          Usage Minimum (01h),        */
+	0x29, 0x03,         /*          Usage Maximum (03h),        */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x05,         /*          Report Count (5),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x16, 0x00, 0x80,   /*          Logical Minimum (-32768),   */
+	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x02,         /*          Report Count (2),           */
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x09, 0x38,         /*          Usage (Wheel),              */
+	0x15, 0xFF,         /*          Logical Minimum (-1),       */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0xC0,               /*      End Collection,                 */
+	0xC0                /*  End Collection                      */
+};
+
+/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
+static __u8 twhl850_rdesc_fixed2[] = {
+	0x05, 0x01,         /*  Usage Page (Desktop),               */
+	0x09, 0x06,         /*  Usage (Keyboard),                   */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x03,         /*      Report ID (3),                  */
+	0x05, 0x07,         /*      Usage Page (Keyboard),          */
+	0x14,               /*      Logical Minimum (0),            */
+	0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
+	0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
+	0x25, 0x01,         /*      Logical Maximum (1),            */
+	0x75, 0x01,         /*      Report Size (1),                */
+	0x95, 0x08,         /*      Report Count (8),               */
+	0x81, 0x02,         /*      Input (Variable),               */
+	0x18,               /*      Usage Minimum (None),           */
+	0x29, 0xFF,         /*      Usage Maximum (FFh),            */
+	0x26, 0xFF, 0x00,   /*      Logical Maximum (255),          */
+	0x75, 0x08,         /*      Report Size (8),                */
+	0x95, 0x06,         /*      Report Count (6),               */
+	0x80,               /*      Input,                          */
+	0xC0                /*  End Collection                      */
+};
+
 static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 					unsigned int *rsize)
 {
+	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
+	__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
 	switch (hdev->product) {
 	case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
 		if (*rsize == PF1209_RDESC_ORIG_SIZE) {
@@ -386,6 +503,28 @@
 			*rsize = sizeof(wp1062_rdesc_fixed);
 		}
 		break;
+	case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
+		switch (iface_num) {
+		case 0:
+			if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
+				rdesc = twhl850_rdesc_fixed0;
+				*rsize = sizeof(twhl850_rdesc_fixed0);
+			}
+			break;
+		case 1:
+			if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
+				rdesc = twhl850_rdesc_fixed1;
+				*rsize = sizeof(twhl850_rdesc_fixed1);
+			}
+			break;
+		case 2:
+			if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
+				rdesc = twhl850_rdesc_fixed2;
+				*rsize = sizeof(twhl850_rdesc_fixed2);
+			}
+			break;
+		}
+		break;
 	}
 
 	return rdesc;
@@ -402,6 +541,8 @@
 				USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 				USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+				USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, uclogic_devices);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 067e296..fe23a1e 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -24,15 +24,16 @@
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/leds.h>
 #include <linux/slab.h>
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 #include <linux/power_supply.h>
-#endif
 
 #include "hid-ids.h"
 
 #define PAD_DEVICE_ID	0x0F
 
+#define WAC_CMD_LED_CONTROL     0x20
+
 struct wacom_data {
 	__u16 tool;
 	__u16 butstate;
@@ -41,16 +42,20 @@
 	__u32 id;
 	__u32 serial;
 	unsigned char high_speed;
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-	int battery_capacity;
+	__u8 battery_capacity;
+	__u8 power_raw;
+	__u8 ps_connected;
 	struct power_supply battery;
 	struct power_supply ac;
-#endif
+	__u8 led_selector;
+	struct led_classdev *leds[4];
 };
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-/*percent of battery capacity, 0 means AC online*/
-static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
+/*percent of battery capacity for Graphire
+  8th value means AC online and show 100% capacity */
+static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
+/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
+static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
 
 static enum power_supply_property wacom_battery_props[] = {
 	POWER_SUPPLY_PROP_PRESENT,
@@ -64,13 +69,123 @@
 	POWER_SUPPLY_PROP_SCOPE,
 };
 
+static void wacom_leds_set_brightness(struct led_classdev *led_dev,
+						enum led_brightness value)
+{
+	struct device *dev = led_dev->dev->parent;
+	struct hid_device *hdev;
+	struct wacom_data *wdata;
+	unsigned char *buf;
+	__u8 led = 0;
+	int i;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	wdata = hid_get_drvdata(hdev);
+	for (i = 0; i < 4; ++i) {
+		if (wdata->leds[i] == led_dev)
+			wdata->led_selector = i;
+	}
+
+	led = wdata->led_selector | 0x04;
+	buf = kzalloc(9, GFP_KERNEL);
+	if (buf) {
+		buf[0] = WAC_CMD_LED_CONTROL;
+		buf[1] = led;
+		buf[2] = value;
+		hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
+		kfree(buf);
+	}
+
+	return;
+}
+
+static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
+{
+	struct wacom_data *wdata;
+	struct device *dev = led_dev->dev->parent;
+	int value = 0;
+	int i;
+
+	wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+	for (i = 0; i < 4; ++i) {
+		if (wdata->leds[i] == led_dev) {
+			value = wdata->leds[i]->brightness;
+			break;
+		}
+	}
+
+	return value;
+}
+
+
+static int wacom_initialize_leds(struct hid_device *hdev)
+{
+	struct wacom_data *wdata = hid_get_drvdata(hdev);
+	struct led_classdev *led;
+	struct device *dev = &hdev->dev;
+	size_t namesz = strlen(dev_name(dev)) + 12;
+	char *name;
+	int i, ret;
+
+	wdata->led_selector = 0;
+
+	for (i = 0; i < 4; i++) {
+		led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+		if (!led) {
+			hid_warn(hdev,
+				 "can't allocate memory for LED selector\n");
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		name = (void *)&led[1];
+		snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
+		led->name = name;
+		led->brightness = 0;
+		led->max_brightness = 127;
+		led->brightness_get = wacom_leds_get_brightness;
+		led->brightness_set = wacom_leds_set_brightness;
+
+		wdata->leds[i] = led;
+
+		ret = led_classdev_register(dev, wdata->leds[i]);
+
+		if (ret) {
+			wdata->leds[i] = NULL;
+			kfree(led);
+			hid_warn(hdev, "can't register LED\n");
+			goto err;
+		}
+	}
+
+err:
+	return ret;
+}
+
+static void wacom_destroy_leds(struct hid_device *hdev)
+{
+	struct wacom_data *wdata = hid_get_drvdata(hdev);
+	struct led_classdev *led;
+	int i;
+
+	for (i = 0; i < 4; ++i) {
+		if (wdata->leds[i]) {
+			led = wdata->leds[i];
+			wdata->leds[i] = NULL;
+			led_classdev_unregister(led);
+			kfree(led);
+		}
+	}
+
+}
+
 static int wacom_battery_get_property(struct power_supply *psy,
 				enum power_supply_property psp,
 				union power_supply_propval *val)
 {
 	struct wacom_data *wdata = container_of(psy,
 					struct wacom_data, battery);
-	int power_state = batcap[wdata->battery_capacity];
 	int ret = 0;
 
 	switch (psp) {
@@ -81,11 +196,7 @@
 		val->intval = POWER_SUPPLY_SCOPE_DEVICE;
 		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
-		/* show 100% battery capacity when charging */
-		if (power_state == 0)
-			val->intval = 100;
-		else
-			val->intval = power_state;
+		val->intval = wdata->battery_capacity;
 		break;
 	default:
 		ret = -EINVAL;
@@ -99,17 +210,13 @@
 				union power_supply_propval *val)
 {
 	struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
-	int power_state = batcap[wdata->battery_capacity];
 	int ret = 0;
 
 	switch (psp) {
 	case POWER_SUPPLY_PROP_PRESENT:
 		/* fall through */
 	case POWER_SUPPLY_PROP_ONLINE:
-		if (power_state == 0)
-			val->intval = 1;
-		else
-			val->intval = 0;
+		val->intval = wdata->ps_connected;
 		break;
 	case POWER_SUPPLY_PROP_SCOPE:
 		val->intval = POWER_SUPPLY_SCOPE_DEVICE;
@@ -120,41 +227,16 @@
 	}
 	return ret;
 }
-#endif
 
-static void wacom_set_features(struct hid_device *hdev)
-{
-	int ret;
-	__u8 rep_data[2];
-
-	/*set high speed, tablet mode*/
-	rep_data[0] = 0x03;
-	rep_data[1] = 0x20;
-	ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
-				HID_FEATURE_REPORT);
-	return;
-}
-
-static void wacom_poke(struct hid_device *hdev, u8 speed)
+static void wacom_set_features(struct hid_device *hdev, u8 speed)
 {
 	struct wacom_data *wdata = hid_get_drvdata(hdev);
 	int limit, ret;
-	char rep_data[2];
+	__u8 rep_data[2];
 
-	rep_data[0] = 0x03 ; rep_data[1] = 0x00;
-	limit = 3;
-	do {
-		ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
-				HID_FEATURE_REPORT);
-	} while (ret < 0 && limit-- > 0);
-
-	if (ret >= 0) {
-		if (speed == 0)
-			rep_data[0] = 0x05;
-		else
-			rep_data[0] = 0x06;
-
-		rep_data[1] = 0x00;
+	switch (hdev->product) {
+	case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
+		rep_data[0] = 0x03 ; rep_data[1] = 0x00;
 		limit = 3;
 		do {
 			ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
@@ -162,17 +244,47 @@
 		} while (ret < 0 && limit-- > 0);
 
 		if (ret >= 0) {
-			wdata->high_speed = speed;
-			return;
+			if (speed == 0)
+				rep_data[0] = 0x05;
+			else
+				rep_data[0] = 0x06;
+
+			rep_data[1] = 0x00;
+			limit = 3;
+			do {
+				ret = hdev->hid_output_raw_report(hdev,
+					rep_data, 2, HID_FEATURE_REPORT);
+			} while (ret < 0 && limit-- > 0);
+
+			if (ret >= 0) {
+				wdata->high_speed = speed;
+				return;
+			}
 		}
+
+		/*
+		 * Note that if the raw queries fail, it's not a hard failure
+		 * and it is safe to continue
+		 */
+		hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+			 rep_data[0], ret);
+		break;
+	case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+		if (speed == 1)
+			wdata->features &= ~0x20;
+		else
+			wdata->features |= 0x20;
+
+		rep_data[0] = 0x03;
+		rep_data[1] = wdata->features;
+
+		ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+					HID_FEATURE_REPORT);
+		if (ret >= 0)
+			wdata->high_speed = speed;
+		break;
 	}
 
-	/*
-	 * Note that if the raw queries fail, it's not a hard failure and it
-	 * is safe to continue
-	 */
-	hid_warn(hdev, "failed to poke device, command %d, err %d\n",
-		 rep_data[0], ret);
 	return;
 }
 
@@ -196,7 +308,7 @@
 		return -EINVAL;
 
 	if (new_speed == 0 || new_speed == 1) {
-		wacom_poke(hdev, new_speed);
+		wacom_set_features(hdev, new_speed);
 		return strnlen(buf, PAGE_SIZE);
 	} else
 		return -EINVAL;
@@ -310,12 +422,16 @@
 		input_sync(input);
 	}
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-	/* Store current battery capacity */
+	/* Store current battery capacity and power supply state*/
 	rw = (data[7] >> 2 & 0x07);
-	if (rw != wdata->battery_capacity)
-		wdata->battery_capacity = rw;
-#endif
+	if (rw != wdata->power_raw) {
+		wdata->power_raw = rw;
+		wdata->battery_capacity = batcap_gr[rw];
+		if (rw == 7)
+			wdata->ps_connected = 1;
+		else
+			wdata->ps_connected = 0;
+	}
 	return 1;
 }
 
@@ -369,6 +485,7 @@
 {
 	__u16 x, y, pressure;
 	__u8 distance;
+	__u8 tilt_x, tilt_y;
 
 	switch (data[1]) {
 	case 0x80: /* Out of proximity report */
@@ -405,6 +522,8 @@
 		pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
 			| (data[1] & 0x01);
 		distance = (data[9] >> 2) & 0x3f;
+		tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
+		tilt_y = data[8] & 0x7f;
 
 		input_report_key(input, BTN_TOUCH, pressure > 1);
 
@@ -415,6 +534,8 @@
 		input_report_abs(input, ABS_Y, y);
 		input_report_abs(input, ABS_PRESSURE, pressure);
 		input_report_abs(input, ABS_DISTANCE, distance);
+		input_report_abs(input, ABS_TILT_X, tilt_x);
+		input_report_abs(input, ABS_TILT_Y, tilt_y);
 		input_report_abs(input, ABS_MISC, wdata->id);
 		input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
 		input_report_key(input, wdata->tool, 1);
@@ -455,6 +576,7 @@
 	struct input_dev *input;
 	unsigned char *data = (unsigned char *) raw_data;
 	int i;
+	__u8 power_raw;
 
 	if (!(hdev->claimed & HID_CLAIMED_INPUT))
 		return 0;
@@ -462,13 +584,15 @@
 	hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
 	input = hidinput->input;
 
-	/* Check if this is a tablet report */
-	if (data[0] != 0x03)
-		return 0;
-
 	switch (hdev->product) {
 	case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
-		return wacom_gr_parse_report(hdev, wdata, input, data);
+		if (data[0] == 0x03) {
+			return wacom_gr_parse_report(hdev, wdata, input, data);
+		} else {
+			hid_err(hdev, "Unknown report: %d,%d size:%d\n",
+					data[0], data[1], size);
+			return 0;
+		}
 		break;
 	case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
 		i = 1;
@@ -482,6 +606,13 @@
 			wacom_i4_parse_report(hdev, wdata, input, data + i);
 			i += 10;
 			wacom_i4_parse_report(hdev, wdata, input, data + i);
+			power_raw = data[i+10];
+			if (power_raw != wdata->power_raw) {
+				wdata->power_raw = power_raw;
+				wdata->battery_capacity = batcap_i4[power_raw & 0x07];
+				wdata->ps_connected = power_raw & 0x08;
+			}
+
 			break;
 		default:
 			hid_err(hdev, "Unknown report: %d,%d size:%d\n",
@@ -546,6 +677,8 @@
 		input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
 		input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
 		input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
+		input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
+		input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
 		break;
 	}
 
@@ -584,19 +717,19 @@
 		hid_warn(hdev,
 			 "can't create sysfs speed attribute err: %d\n", ret);
 
-	switch (hdev->product) {
-	case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
-		/* Set Wacom mode 2 with high reporting speed */
-		wacom_poke(hdev, 1);
-		break;
-	case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+	wdata->features = 0;
+	wacom_set_features(hdev, 1);
+
+	if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
 		sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
-		wdata->features = 0;
-		wacom_set_features(hdev);
-		break;
+		ret = wacom_initialize_leds(hdev);
+		if (ret) {
+			hid_warn(hdev,
+				 "can't create led attribute, err: %d\n", ret);
+			goto destroy_leds;
+		}
 	}
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 	wdata->battery.properties = wacom_battery_props;
 	wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
 	wdata->battery.get_property = wacom_battery_get_property;
@@ -629,16 +762,15 @@
 	}
 
 	power_supply_powers(&wdata->ac, &hdev->dev);
-#endif
 	return 0;
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 err_ac:
 	power_supply_unregister(&wdata->battery);
 err_battery:
 	device_remove_file(&hdev->dev, &dev_attr_speed);
 	hid_hw_stop(hdev);
-#endif
+destroy_leds:
+	wacom_destroy_leds(hdev);
 err_free:
 	kfree(wdata);
 	return ret;
@@ -646,16 +778,14 @@
 
 static void wacom_remove(struct hid_device *hdev)
 {
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 	struct wacom_data *wdata = hid_get_drvdata(hdev);
-#endif
+
+	wacom_destroy_leds(hdev);
 	device_remove_file(&hdev->dev, &dev_attr_speed);
 	hid_hw_stop(hdev);
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 	power_supply_unregister(&wdata->battery);
 	power_supply_unregister(&wdata->ac);
-#endif
 	kfree(hid_get_drvdata(hdev));
 }
 
@@ -693,5 +823,5 @@
 
 module_init(wacom_init);
 module_exit(wacom_exit);
+MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c
index 2cfd95c..745e4e9 100644
--- a/drivers/hid/hid-waltop.c
+++ b/drivers/hid/hid-waltop.c
@@ -502,28 +502,146 @@
 	0xC0                /*  End Collection                      */
 };
 
-struct waltop_state {
-	u8 pressure0;
-	u8 pressure1;
+/*
+ * See Sirius Battery Free Tablet description, device and HID report descriptors
+ * at
+ * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Sirius_Battery_Free_Tablet
+ */
+
+/* Size of the original report descriptor of Sirius Battery Free Tablet */
+#define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE	335
+
+/* Fixed Sirius Battery Free Tablet descriptor */
+static __u8 sirius_battery_free_tablet_rdesc_fixed[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x10,         /*      Report ID (16),                 */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x15, 0x01,         /*          Logical Minimum (1),        */
+	0x25, 0x03,         /*          Logical Maximum (3),        */
+	0x75, 0x02,         /*          Report Size (2),            */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x80,               /*          Input,                      */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x09, 0x3C,         /*          Usage (Invert),             */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x09, 0x32,         /*          Usage (In Range),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x34,               /*          Physical Minimum (0),       */
+	0x14,               /*          Logical Minimum (0),        */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
+	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
+	0x26, 0xE0, 0x2E,   /*          Logical Maximum (12000),    */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xA4,               /*          Push,                       */
+	0x55, 0xFE,         /*          Unit Exponent (-2),         */
+	0x65, 0x12,         /*          Unit (Radians),             */
+	0x35, 0x97,         /*          Physical Minimum (-105),    */
+	0x45, 0x69,         /*          Physical Maximum (105),     */
+	0x15, 0x97,         /*          Logical Minimum (-105),     */
+	0x25, 0x69,         /*          Logical Maximum (105),      */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x95, 0x02,         /*          Report Count (2),           */
+	0x09, 0x3D,         /*          Usage (X Tilt),             */
+	0x09, 0x3E,         /*          Usage (Y Tilt),             */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0xC0,               /*      End Collection,                 */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x01,         /*  Usage Page (Desktop),               */
+	0x09, 0x02,         /*  Usage (Mouse),                      */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x01,         /*      Report ID (1),                  */
+	0x09, 0x01,         /*      Usage (Pointer),                */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x09, 0x38,         /*          Usage (Wheel),              */
+	0x15, 0xFF,         /*          Logical Minimum (-1),       */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0xC0,               /*      End Collection,                 */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x01,         /*  Usage Page (Desktop),               */
+	0x09, 0x06,         /*  Usage (Keyboard),                   */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x0D,         /*      Report ID (13),                 */
+	0x05, 0x07,         /*      Usage Page (Keyboard),          */
+	0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
+	0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
+	0x14,               /*      Logical Minimum (0),            */
+	0x25, 0x01,         /*      Logical Maximum (1),            */
+	0x75, 0x01,         /*      Report Size (1),                */
+	0x95, 0x08,         /*      Report Count (8),               */
+	0x81, 0x02,         /*      Input (Variable),               */
+	0x75, 0x08,         /*      Report Size (8),                */
+	0x95, 0x01,         /*      Report Count (1),               */
+	0x81, 0x01,         /*      Input (Constant),               */
+	0x18,               /*      Usage Minimum (None),           */
+	0x29, 0x65,         /*      Usage Maximum (KB Application), */
+	0x14,               /*      Logical Minimum (0),            */
+	0x25, 0x65,         /*      Logical Maximum (101),          */
+	0x75, 0x08,         /*      Report Size (8),                */
+	0x95, 0x05,         /*      Report Count (5),               */
+	0x80,               /*      Input,                          */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x0C,         /*  Usage Page (Consumer),              */
+	0x09, 0x01,         /*  Usage (Consumer Control),           */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x0C,         /*      Report ID (12),                 */
+	0x09, 0xE9,         /*      Usage (Volume Inc),             */
+	0x09, 0xEA,         /*      Usage (Volume Dec),             */
+	0x14,               /*      Logical Minimum (0),            */
+	0x25, 0x01,         /*      Logical Maximum (1),            */
+	0x75, 0x01,         /*      Report Size (1),                */
+	0x95, 0x02,         /*      Report Count (2),               */
+	0x81, 0x02,         /*      Input (Variable),               */
+	0x75, 0x06,         /*      Report Size (6),                */
+	0x95, 0x01,         /*      Report Count (1),               */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0x75, 0x10,         /*      Report Size (16),               */
+	0x95, 0x03,         /*      Report Count (3),               */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0xC0                /*  End Collection                      */
 };
 
 static int waltop_probe(struct hid_device *hdev,
 			const struct hid_device_id *id)
 {
 	int ret;
-	struct waltop_state *s;
-
-	s = kzalloc(sizeof(*s), GFP_KERNEL);
-	if (s == NULL) {
-		hid_err(hdev, "can't allocate device state\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	s->pressure0 = 0;
-	s->pressure1 = 0;
-
-	hid_set_drvdata(hdev, s);
 
 	ret = hid_parse(hdev);
 	if (ret) {
@@ -539,7 +657,6 @@
 
 	return 0;
 err:
-	kfree(s);
 	return ret;
 }
 
@@ -583,6 +700,12 @@
 			*rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
 		}
 		break;
+	case USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET:
+		if (*rsize == SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE) {
+			rdesc = sirius_battery_free_tablet_rdesc_fixed;
+			*rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed);
+		}
+		break;
 	}
 	return rdesc;
 }
@@ -590,39 +713,72 @@
 static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
 		     u8 *data, int size)
 {
-	/* If this is a pen input report of a tablet with PID 0038 */
-	if (hdev->product == USB_DEVICE_ID_WALTOP_PID_0038 &&
-	    report->type == HID_INPUT_REPORT &&
-	    report->id == 16 &&
-	    size == 8) {
-		struct waltop_state *s = hid_get_drvdata(hdev);
-
+	/* If this is a pen input report */
+	if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {
 		/*
-		 * Ignore maximum pressure reported when a barrel button is
-		 * pressed.
+		 * Ignore reported pressure when a barrel button is pressed,
+		 * because it is rarely correct.
 		 */
 
 		/* If a barrel button is pressed */
 		if ((data[1] & 0xF) > 1) {
-			/* Use the last known pressure */
-			data[6] = s->pressure0;
-			data[7] = s->pressure1;
-		} else {
-			/* Remember reported pressure */
-			s->pressure0 = data[6];
-			s->pressure1 = data[7];
+			/* Report zero pressure */
+			data[6] = 0;
+			data[7] = 0;
 		}
 	}
 
+	/* If this is a pen input report of Sirius Battery Free Tablet */
+	if (hdev->product == USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET &&
+	    report->type == HID_INPUT_REPORT &&
+	    report->id == 16 &&
+	    size == 10) {
+		/*
+		 * The tablet reports tilt as roughly sin(a)*21 (18 means 60
+		 * degrees).
+		 *
+		 * This array stores angles as radians * 100, corresponding to
+		 * reported values up to 60 degrees, as expected by userspace.
+		 */
+		static const s8 tilt_to_radians[] = {
+			0, 5, 10, 14, 19, 24, 29, 34, 40, 45,
+			50, 56, 62, 68, 74, 81, 88, 96, 105
+		};
+
+		s8 tilt_x = (s8)data[8];
+		s8 tilt_y = (s8)data[9];
+		s8 sign_x = tilt_x >= 0 ? 1 : -1;
+		s8 sign_y = tilt_y >= 0 ? 1 : -1;
+
+		tilt_x *= sign_x;
+		tilt_y *= sign_y;
+
+		/*
+		 * Reverse the Y Tilt direction to match the HID standard and
+		 * userspace expectations. See HID Usage Tables v1.12 16.3.2
+		 * Tilt Orientation.
+		 */
+		sign_y *= -1;
+
+		/*
+		 * This effectively clamps reported tilt to 60 degrees - the
+		 * range expected by userspace
+		 */
+		if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1)
+			tilt_x = ARRAY_SIZE(tilt_to_radians) - 1;
+		if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1)
+			tilt_y = ARRAY_SIZE(tilt_to_radians) - 1;
+
+		data[8] = tilt_to_radians[tilt_x] * sign_x;
+		data[9] = tilt_to_radians[tilt_y] * sign_y;
+	}
+
 	return 0;
 }
 
 static void waltop_remove(struct hid_device *hdev)
 {
-	struct waltop_state *s = hid_get_drvdata(hdev);
-
 	hid_hw_stop(hdev);
-	kfree(s);
 }
 
 static const struct hid_device_id waltop_devices[] = {
@@ -638,6 +794,8 @@
 				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
 				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+			 USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, waltop_devices);
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index cac3589..84e2fbe 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -769,7 +769,7 @@
 
 	/*
 	 * Basic IR data is encoded into 3 bytes. The first two bytes are the
-	 * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits
+	 * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits
 	 * of both.
 	 * If data is packed, then the 3rd byte is put first and slightly
 	 * reordered. This allows to interleave packed and non-packed data to
@@ -778,17 +778,11 @@
 	 */
 
 	if (packed) {
-		x = ir[1] << 2;
-		y = ir[2] << 2;
-
-		x |= ir[0] & 0x3;
-		y |= (ir[0] >> 2) & 0x3;
+		x = ir[1] | ((ir[0] & 0x03) << 8);
+		y = ir[2] | ((ir[0] & 0x0c) << 6);
 	} else {
-		x = ir[0] << 2;
-		y = ir[1] << 2;
-
-		x |= (ir[2] >> 4) & 0x3;
-		y |= (ir[2] >> 6) & 0x3;
+		x = ir[0] | ((ir[2] & 0x30) << 4);
+		y = ir[1] | ((ir[2] & 0xc0) << 2);
 	}
 
 	input_report_abs(wdata->ir, xid, x);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index cf7d6d5..36fa77b 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -87,11 +87,13 @@
 		len = list->buffer[list->tail].len > count ?
 			count : list->buffer[list->tail].len;
 
-		if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
-			ret = -EFAULT;
-			goto out;
+		if (list->buffer[list->tail].value) {
+			if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
+				ret = -EFAULT;
+				goto out;
+			}
+			ret = len;
 		}
-		ret = len;
 
 		kfree(list->buffer[list->tail].value);
 		list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
@@ -437,19 +439,24 @@
 	.llseek =	noop_llseek,
 };
 
-void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
+int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
 {
 	struct hidraw *dev = hid->hidraw;
 	struct hidraw_list *list;
+	int ret = 0;
 
 	list_for_each_entry(list, &dev->list, node) {
-		list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
+		if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
+			ret = -ENOMEM;
+			break;
+		}
 		list->buffer[list->head].len = len;
 		list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
 		kill_fasync(&list->fasync, SIGIO, POLL_IN);
 	}
 
 	wake_up_interruptible(&dev->wait);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(hidraw_report_event);
 
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 5bf91db..482f936 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -28,6 +28,7 @@
 #include <linux/input.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/string.h>
 
 #include <linux/usb.h>
 
@@ -86,8 +87,13 @@
 			!test_bit(HID_REPORTED_IDLE, &usbhid->iofl) &&
 			!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
 		rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
-		if (rc != 0)
+		if (rc != 0) {
 			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+			if (rc == -ENOSPC)
+				set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+		} else {
+			clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+		}
 	}
 	spin_unlock_irqrestore(&usbhid->lock, flags);
 	return rc;
@@ -173,8 +179,10 @@
 
 	if (time_after(jiffies, usbhid->stop_retry)) {
 
-		/* Retries failed, so do a port reset */
-		if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+		/* Retries failed, so do a port reset unless we lack bandwidth*/
+		if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl)
+		     && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+
 			schedule_work(&usbhid->reset_work);
 			goto done;
 		}
@@ -203,7 +211,7 @@
 		return 0;
 
 	if ((kicked = (usbhid->outhead != usbhid->outtail))) {
-		dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
+		hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
 
 		r = usb_autopm_get_interface_async(usbhid->intf);
 		if (r < 0)
@@ -230,7 +238,7 @@
 		return 0;
 
 	if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) {
-		dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
+		hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
 
 		r = usb_autopm_get_interface_async(usbhid->intf);
 		if (r < 0)
@@ -399,6 +407,16 @@
  * Output interrupt completion handler.
  */
 
+static int irq_out_pump_restart(struct hid_device *hid)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	if (usbhid->outhead != usbhid->outtail)
+		return hid_submit_out(hid);
+	else
+		return -1;
+}
+
 static void hid_irq_out(struct urb *urb)
 {
 	struct hid_device *hid = urb->context;
@@ -428,7 +446,7 @@
 	else
 		usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
 
-	if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) {
+	if (!irq_out_pump_restart(hid)) {
 		/* Successfully submitted next urb in queue */
 		spin_unlock_irqrestore(&usbhid->lock, flags);
 		return;
@@ -443,6 +461,15 @@
 /*
  * Control pipe completion handler.
  */
+static int ctrl_pump_restart(struct hid_device *hid)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	if (usbhid->ctrlhead != usbhid->ctrltail)
+		return hid_submit_ctrl(hid);
+	else
+		return -1;
+}
 
 static void hid_ctrl(struct urb *urb)
 {
@@ -476,7 +503,7 @@
 	else
 		usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
 
-	if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) {
+	if (!ctrl_pump_restart(hid)) {
 		/* Successfully submitted next urb in queue */
 		spin_unlock(&usbhid->lock);
 		return;
@@ -535,11 +562,27 @@
 			 * the queue is known to run
 			 * but an earlier request may be stuck
 			 * we may need to time out
-			 * no race because this is called under
+			 * no race because the URB is blocked under
 			 * spinlock
 			 */
-			if (time_after(jiffies, usbhid->last_out + HZ * 5))
+			if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
+				usb_block_urb(usbhid->urbout);
+				/* drop lock to not deadlock if the callback is called */
+				spin_unlock(&usbhid->lock);
 				usb_unlink_urb(usbhid->urbout);
+				spin_lock(&usbhid->lock);
+				usb_unblock_urb(usbhid->urbout);
+				/*
+				 * if the unlinking has already completed
+				 * the pump will have been stopped
+				 * it must be restarted now
+				 */
+				if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+					if (!irq_out_pump_restart(hid))
+						set_bit(HID_OUT_RUNNING, &usbhid->iofl);
+
+
+			}
 		}
 		return;
 	}
@@ -583,11 +626,25 @@
 		 * the queue is known to run
 		 * but an earlier request may be stuck
 		 * we may need to time out
-		 * no race because this is called under
+		 * no race because the URB is blocked under
 		 * spinlock
 		 */
-		if (time_after(jiffies, usbhid->last_ctrl + HZ * 5))
+		if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) {
+			usb_block_urb(usbhid->urbctrl);
+			/* drop lock to not deadlock if the callback is called */
+			spin_unlock(&usbhid->lock);
 			usb_unlink_urb(usbhid->urbctrl);
+			spin_lock(&usbhid->lock);
+			usb_unblock_urb(usbhid->urbctrl);
+			/*
+			 * if the unlinking has already completed
+			 * the pump will have been stopped
+			 * it must be restarted now
+			 */
+			if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+				if (!ctrl_pump_restart(hid))
+					set_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+		}
 	}
 }
 
@@ -700,7 +757,7 @@
 int usbhid_open(struct hid_device *hid)
 {
 	struct usbhid_device *usbhid = hid->driver_data;
-	int res;
+	int res = 0;
 
 	mutex_lock(&hid_open_mut);
 	if (!hid->open++) {
@@ -708,17 +765,27 @@
 		/* the device must be awake to reliably request remote wakeup */
 		if (res < 0) {
 			hid->open--;
-			mutex_unlock(&hid_open_mut);
-			return -EIO;
+			res = -EIO;
+			goto done;
 		}
 		usbhid->intf->needs_remote_wakeup = 1;
-		if (hid_start_in(hid))
-			hid_io_error(hid);
- 
+		res = hid_start_in(hid);
+		if (res) {
+			if (res != -ENOSPC) {
+				hid_io_error(hid);
+				res = 0;
+			} else {
+				/* no use opening if resources are insufficient */
+				hid->open--;
+				res = -EBUSY;
+				usbhid->intf->needs_remote_wakeup = 0;
+			}
+		}
 		usb_autopm_put_interface(usbhid->intf);
 	}
+done:
 	mutex_unlock(&hid_open_mut);
-	return 0;
+	return res;
 }
 
 void usbhid_close(struct hid_device *hid)
@@ -1347,7 +1414,34 @@
 	struct usb_device *dev = interface_to_usbdev (intf);
 	struct hid_device *hid = usb_get_intfdata(intf);
 	struct usbhid_device *usbhid = hid->driver_data;
+	struct usb_host_interface *interface = intf->cur_altsetting;
 	int status;
+	char *rdesc;
+
+	/* Fetch and examine the HID report descriptor. If this
+	 * has changed, then rebind. Since usbcore's check of the
+	 * configuration descriptors passed, we already know that
+	 * the size of the HID report descriptor has not changed.
+	 */
+	rdesc = kmalloc(hid->rsize, GFP_KERNEL);
+	if (!rdesc) {
+		dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
+		return 1;
+	}
+	status = hid_get_class_descriptor(dev,
+				interface->desc.bInterfaceNumber,
+				HID_DT_REPORT, rdesc, hid->rsize);
+	if (status < 0) {
+		dbg_hid("reading report descriptor failed (post_reset)\n");
+		kfree(rdesc);
+		return 1;
+	}
+	status = memcmp(rdesc, hid->rdesc, hid->rsize);
+	kfree(rdesc);
+	if (status != 0) {
+		dbg_hid("report descriptor changed\n");
+		return 1;
+	}
 
 	spin_lock_irq(&usbhid->lock);
 	clear_bit(HID_RESET_PENDING, &usbhid->iofl);
@@ -1504,28 +1598,15 @@
 	.supports_autosuspend = 1,
 };
 
-static const struct hid_device_id hid_usb_table[] = {
-	{ HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
-	{ }
-};
-
 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,
-};
-
 static int __init hid_init(void)
 {
 	int retval = -ENOMEM;
 
-	retval = hid_register_driver(&hid_usb_driver);
-	if (retval)
-		goto hid_register_fail;
 	retval = usbhid_quirks_init(quirks_param);
 	if (retval)
 		goto usbhid_quirks_init_fail;
@@ -1538,8 +1619,6 @@
 usb_register_fail:
 	usbhid_quirks_exit();
 usbhid_quirks_init_fail:
-	hid_unregister_driver(&hid_usb_driver);
-hid_register_fail:
 	return retval;
 }
 
@@ -1547,7 +1626,6 @@
 {
 	usb_deregister(&hid_driver);
 	usbhid_quirks_exit();
-	hid_unregister_driver(&hid_usb_driver);
 }
 
 module_init(hid_init);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 782c639..0597ee6 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -88,6 +88,7 @@
 	{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
 	{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index b1ec0e2..14599e2 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -34,6 +34,7 @@
 #include <linux/hid.h>
 #include <linux/hiddev.h>
 #include <linux/compat.h>
+#include <linux/vmalloc.h>
 #include "usbhid.h"
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -250,13 +251,13 @@
 		} else {
 			mutex_unlock(&list->hiddev->existancelock);
 			kfree(list->hiddev);
-			kfree(list);
+			vfree(list);
 			return 0;
 		}
 	}
 
 	mutex_unlock(&list->hiddev->existancelock);
-	kfree(list);
+	vfree(list);
 
 	return 0;
 }
@@ -278,7 +279,7 @@
 	hid = usb_get_intfdata(intf);
 	hiddev = hid->hiddev;
 
-	if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+	if (!(list = vzalloc(sizeof(struct hiddev_list))))
 		return -ENOMEM;
 	mutex_init(&list->thread_lock);
 	list->hiddev = hiddev;
@@ -322,7 +323,7 @@
 	mutex_unlock(&hiddev->existancelock);
 bail:
 	file->private_data = NULL;
-	kfree(list);
+	vfree(list);
 	return res;
 }
 
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index cb8f703..1883d7b 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -55,6 +55,7 @@
 #define HID_STARTED		8
 #define HID_REPORTED_IDLE	9
 #define HID_KEYS_PRESSED	10
+#define HID_NO_BANDWIDTH	11
 
 /*
  * USB-specific HID struct, to be pointed to
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 0f6be45..bf16d72 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -92,9 +92,10 @@
 resubmit:
 	status = usb_submit_urb (urb, GFP_ATOMIC);
 	if (status)
-		err ("can't resubmit intr, %s-%s/input0, status %d",
-				mouse->usbdev->bus->bus_name,
-				mouse->usbdev->devpath, status);
+		dev_err(&mouse->usbdev->dev,
+			"can't resubmit intr, %s-%s/input0, status %d\n",
+			mouse->usbdev->bus->bus_name,
+			mouse->usbdev->devpath, status);
 }
 
 static int usb_mouse_open(struct input_dev *dev)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 9ffbfc5..2b8b8d4 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -46,40 +46,61 @@
  *
  * @icmsghdrp is of type &struct icmsg_hdr.
  * @negop is of type &struct icmsg_negotiate.
- * Set up and fill in default negotiate response message. This response can
- * come from both the vmbus driver and the hv_utils driver. The current api
- * will respond properly to both Windows 2008 and Windows 2008-R2 operating
- * systems.
+ * Set up and fill in default negotiate response message.
+ *
+ * The max_fw_version specifies the maximum framework version that
+ * we can support and max _srv_version specifies the maximum service
+ * version we can support. A special value MAX_SRV_VER can be
+ * specified to indicate that we can handle the maximum version
+ * exposed by the host.
  *
  * Mainly used by Hyper-V drivers.
  */
 void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
-			       struct icmsg_negotiate *negop, u8 *buf)
+				struct icmsg_negotiate *negop, u8 *buf,
+				int max_fw_version, int max_srv_version)
 {
-	if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
-		icmsghdrp->icmsgsize = 0x10;
+	int icframe_vercnt;
+	int icmsg_vercnt;
+	int i;
 
-		negop = (struct icmsg_negotiate *)&buf[
-			sizeof(struct vmbuspipe_hdr) +
-			sizeof(struct icmsg_hdr)];
+	icmsghdrp->icmsgsize = 0x10;
 
-		if (negop->icframe_vercnt == 2 &&
-		   negop->icversion_data[1].major == 3) {
-			negop->icversion_data[0].major = 3;
-			negop->icversion_data[0].minor = 0;
-			negop->icversion_data[1].major = 3;
-			negop->icversion_data[1].minor = 0;
-		} else {
-			negop->icversion_data[0].major = 1;
-			negop->icversion_data[0].minor = 0;
-			negop->icversion_data[1].major = 1;
-			negop->icversion_data[1].minor = 0;
-		}
+	negop = (struct icmsg_negotiate *)&buf[
+		sizeof(struct vmbuspipe_hdr) +
+		sizeof(struct icmsg_hdr)];
 
-		negop->icframe_vercnt = 1;
-		negop->icmsg_vercnt = 1;
+	icframe_vercnt = negop->icframe_vercnt;
+	icmsg_vercnt = negop->icmsg_vercnt;
+
+	/*
+	 * Select the framework version number we will
+	 * support.
+	 */
+
+	for (i = 0; i < negop->icframe_vercnt; i++) {
+		if (negop->icversion_data[i].major <= max_fw_version)
+			icframe_vercnt = negop->icversion_data[i].major;
 	}
+
+	for (i = negop->icframe_vercnt;
+		 (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
+		if (negop->icversion_data[i].major <= max_srv_version)
+			icmsg_vercnt = negop->icversion_data[i].major;
+	}
+
+	/*
+	 * Respond with the maximum framework and service
+	 * version numbers we can support.
+	 */
+	negop->icframe_vercnt = 1;
+	negop->icmsg_vercnt = 1;
+	negop->icversion_data[0].major = icframe_vercnt;
+	negop->icversion_data[0].minor = 0;
+	negop->icversion_data[1].major = icmsg_vercnt;
+	negop->icversion_data[1].minor = 0;
 }
+
 EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
 
 /*
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 15956bd..86f8885 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -252,7 +252,7 @@
  *
  * This involves a hypercall.
  */
-u16 hv_post_message(union hv_connection_id connection_id,
+int hv_post_message(union hv_connection_id connection_id,
 		  enum hv_message_type message_type,
 		  void *payload, size_t payload_size)
 {
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 6186025..0012eed 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -394,7 +394,8 @@
 			sizeof(struct vmbuspipe_hdr)];
 
 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
-			vmbus_prep_negotiate_resp(icmsghdrp, negop, recv_buffer);
+			vmbus_prep_negotiate_resp(icmsghdrp, negop,
+				 recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
 		} else {
 			kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
 				sizeof(struct vmbuspipe_hdr) +
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index dbb8b8e..d3ac6a4 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -70,7 +70,8 @@
 			sizeof(struct vmbuspipe_hdr)];
 
 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
-			vmbus_prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf);
+			vmbus_prep_negotiate_resp(icmsghdrp, negop,
+					shut_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
 		} else {
 			shutdown_msg =
 				(struct shutdown_msg_data *)&shut_txf_buf[
@@ -195,7 +196,8 @@
 				sizeof(struct vmbuspipe_hdr)];
 
 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
-			vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf);
+			vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf,
+						MAX_SRV_VER, MAX_SRV_VER);
 		} else {
 			timedatap = (struct ictimesync_data *)&time_txf_buf[
 				sizeof(struct vmbuspipe_hdr) +
@@ -234,7 +236,8 @@
 				sizeof(struct vmbuspipe_hdr)];
 
 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
-			vmbus_prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf);
+			vmbus_prep_negotiate_resp(icmsghdrp, NULL,
+				hbeat_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
 		} else {
 			heartbeat_msg =
 				(struct heartbeat_msg_data *)&hbeat_txf_buf[
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 699f0d8..b9426a6 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -495,7 +495,7 @@
 
 extern void hv_cleanup(void);
 
-extern u16 hv_post_message(union hv_connection_id connection_id,
+extern int hv_post_message(union hv_connection_id connection_id,
 			 enum hv_message_type message_type,
 			 void *payload, size_t payload_size);
 
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 8deedc1..7cd9bf4 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -318,7 +318,7 @@
 	tristate "Temperature sensor on Samsung EXYNOS4"
 	depends on ARCH_EXYNOS4
 	help
-	  If you say yes here you get support for TMU (Thermal Managment
+	  If you say yes here you get support for TMU (Thermal Management
 	  Unit) on SAMSUNG EXYNOS4 series of SoC.
 
 	  This driver can also be built as a module. If so, the module
@@ -1102,6 +1102,19 @@
 	  This driver can also be build as a module.  If so, the module
 	  will be called amc6821.
 
+config SENSORS_INA2XX
+	tristate "Texas Instruments INA219, INA226"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for INA219 and INA226 power
+	  monitor chips.
+
+	  The INA2xx driver is configured for the default configuration of
+	  the part as described in the datasheet.
+	  Default value for Rshunt is 10 mOhms.
+	  This driver can also be built as a module.  If so, the module
+	  will be called ina2xx.
+
 config SENSORS_THMC50
 	tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
 	depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 6d3f11f..e1eeac1 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -62,6 +62,7 @@
 obj-$(CONFIG_SENSORS_I5K_AMB)	+= i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)	+= ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)	+= ibmpex.o
+obj-$(CONFIG_SENSORS_INA2XX)	+= ina2xx.o
 obj-$(CONFIG_SENSORS_IT87)	+= it87.o
 obj-$(CONFIG_SENSORS_JC42)	+= jc42.o
 obj-$(CONFIG_SENSORS_JZ4740)	+= jz4740-hwmon.o
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 9140236..34ad5a2 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -107,15 +107,7 @@
 	struct kobject		*holders_dir;
 };
 
-struct ro_sensor_template {
-	char *label;
-	ssize_t (*show)(struct device *dev,
-			struct device_attribute *devattr,
-			char *buf);
-	int index;
-};
-
-struct rw_sensor_template {
+struct sensor_template {
 	char *label;
 	ssize_t (*show)(struct device *dev,
 			struct device_attribute *devattr,
@@ -469,52 +461,67 @@
 	return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME);
 }
 
+#define RO_SENSOR_TEMPLATE(_label, _show, _index)	\
+	{						\
+		.label = _label,			\
+		.show  = _show,				\
+		.index = _index,			\
+	}
+
+#define RW_SENSOR_TEMPLATE(_label, _show, _set, _index)	\
+	{						\
+		.label = _label,			\
+		.show  = _show,				\
+		.set   = _set,				\
+		.index = _index,			\
+	}
+
 /* Sensor descriptions.  If you add a sensor, update NUM_SENSORS above! */
-static struct ro_sensor_template meter_ro_attrs[] = {
-{POWER_AVERAGE_NAME, show_power, 0},
-{"power1_accuracy", show_accuracy, 0},
-{"power1_average_interval_min", show_val, 0},
-{"power1_average_interval_max", show_val, 1},
-{"power1_is_battery", show_val, 5},
-{NULL, NULL, 0},
+static struct sensor_template meter_attrs[] = {
+	RO_SENSOR_TEMPLATE(POWER_AVERAGE_NAME, show_power, 0),
+	RO_SENSOR_TEMPLATE("power1_accuracy", show_accuracy, 0),
+	RO_SENSOR_TEMPLATE("power1_average_interval_min", show_val, 0),
+	RO_SENSOR_TEMPLATE("power1_average_interval_max", show_val, 1),
+	RO_SENSOR_TEMPLATE("power1_is_battery", show_val, 5),
+	RW_SENSOR_TEMPLATE(POWER_AVG_INTERVAL_NAME, show_avg_interval,
+		set_avg_interval, 0),
+	{},
 };
 
-static struct rw_sensor_template meter_rw_attrs[] = {
-{POWER_AVG_INTERVAL_NAME, show_avg_interval, set_avg_interval, 0},
-{NULL, NULL, NULL, 0},
+static struct sensor_template misc_cap_attrs[] = {
+	RO_SENSOR_TEMPLATE("power1_cap_min", show_val, 2),
+	RO_SENSOR_TEMPLATE("power1_cap_max", show_val, 3),
+	RO_SENSOR_TEMPLATE("power1_cap_hyst", show_val, 4),
+	RO_SENSOR_TEMPLATE(POWER_ALARM_NAME, show_val, 6),
+	{},
 };
 
-static struct ro_sensor_template misc_cap_attrs[] = {
-{"power1_cap_min", show_val, 2},
-{"power1_cap_max", show_val, 3},
-{"power1_cap_hyst", show_val, 4},
-{POWER_ALARM_NAME, show_val, 6},
-{NULL, NULL, 0},
+static struct sensor_template ro_cap_attrs[] = {
+	RO_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, 0),
+	{},
 };
 
-static struct ro_sensor_template ro_cap_attrs[] = {
-{POWER_CAP_NAME, show_cap, 0},
-{NULL, NULL, 0},
+static struct sensor_template rw_cap_attrs[] = {
+	RW_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, set_cap, 0),
+	{},
 };
 
-static struct rw_sensor_template rw_cap_attrs[] = {
-{POWER_CAP_NAME, show_cap, set_cap, 0},
-{NULL, NULL, NULL, 0},
+static struct sensor_template trip_attrs[] = {
+	RW_SENSOR_TEMPLATE("power1_average_min", show_val, set_trip, 7),
+	RW_SENSOR_TEMPLATE("power1_average_max", show_val, set_trip, 8),
+	{},
 };
 
-static struct rw_sensor_template trip_attrs[] = {
-{"power1_average_min", show_val, set_trip, 7},
-{"power1_average_max", show_val, set_trip, 8},
-{NULL, NULL, NULL, 0},
+static struct sensor_template misc_attrs[] = {
+	RO_SENSOR_TEMPLATE("name", show_name, 0),
+	RO_SENSOR_TEMPLATE("power1_model_number", show_str, 0),
+	RO_SENSOR_TEMPLATE("power1_oem_info", show_str, 2),
+	RO_SENSOR_TEMPLATE("power1_serial_number", show_str, 1),
+	{},
 };
 
-static struct ro_sensor_template misc_attrs[] = {
-{"name", show_name, 0},
-{"power1_model_number", show_str, 0},
-{"power1_oem_info", show_str, 2},
-{"power1_serial_number", show_str, 1},
-{NULL, NULL, 0},
-};
+#undef RO_SENSOR_TEMPLATE
+#undef RW_SENSOR_TEMPLATE
 
 /* Read power domain data */
 static void remove_domain_devices(struct acpi_power_meter_resource *resource)
@@ -619,19 +626,24 @@
 }
 
 /* Registration and deregistration */
-static int register_ro_attrs(struct acpi_power_meter_resource *resource,
-			     struct ro_sensor_template *ro)
+static int register_attrs(struct acpi_power_meter_resource *resource,
+			  struct sensor_template *attrs)
 {
 	struct device *dev = &resource->acpi_dev->dev;
 	struct sensor_device_attribute *sensors =
 		&resource->sensors[resource->num_sensors];
 	int res = 0;
 
-	while (ro->label) {
-		sensors->dev_attr.attr.name = ro->label;
+	while (attrs->label) {
+		sensors->dev_attr.attr.name = attrs->label;
 		sensors->dev_attr.attr.mode = S_IRUGO;
-		sensors->dev_attr.show = ro->show;
-		sensors->index = ro->index;
+		sensors->dev_attr.show = attrs->show;
+		sensors->index = attrs->index;
+
+		if (attrs->set) {
+			sensors->dev_attr.attr.mode |= S_IWUSR;
+			sensors->dev_attr.store = attrs->set;
+		}
 
 		sysfs_attr_init(&sensors->dev_attr.attr);
 		res = device_create_file(dev, &sensors->dev_attr);
@@ -641,37 +653,7 @@
 		}
 		sensors++;
 		resource->num_sensors++;
-		ro++;
-	}
-
-error:
-	return res;
-}
-
-static int register_rw_attrs(struct acpi_power_meter_resource *resource,
-			     struct rw_sensor_template *rw)
-{
-	struct device *dev = &resource->acpi_dev->dev;
-	struct sensor_device_attribute *sensors =
-		&resource->sensors[resource->num_sensors];
-	int res = 0;
-
-	while (rw->label) {
-		sensors->dev_attr.attr.name = rw->label;
-		sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
-		sensors->dev_attr.show = rw->show;
-		sensors->dev_attr.store = rw->set;
-		sensors->index = rw->index;
-
-		sysfs_attr_init(&sensors->dev_attr.attr);
-		res = device_create_file(dev, &sensors->dev_attr);
-		if (res) {
-			sensors->dev_attr.attr.name = NULL;
-			goto error;
-		}
-		sensors++;
-		resource->num_sensors++;
-		rw++;
+		attrs++;
 	}
 
 error:
@@ -703,10 +685,7 @@
 		return res;
 
 	if (resource->caps.flags & POWER_METER_CAN_MEASURE) {
-		res = register_ro_attrs(resource, meter_ro_attrs);
-		if (res)
-			goto error;
-		res = register_rw_attrs(resource, meter_rw_attrs);
+		res = register_attrs(resource, meter_attrs);
 		if (res)
 			goto error;
 	}
@@ -718,28 +697,27 @@
 			goto skip_unsafe_cap;
 		}
 
-		if (resource->caps.configurable_cap) {
-			res = register_rw_attrs(resource, rw_cap_attrs);
-			if (res)
-				goto error;
-		} else {
-			res = register_ro_attrs(resource, ro_cap_attrs);
-			if (res)
-				goto error;
-		}
-		res = register_ro_attrs(resource, misc_cap_attrs);
+		if (resource->caps.configurable_cap)
+			res = register_attrs(resource, rw_cap_attrs);
+		else
+			res = register_attrs(resource, ro_cap_attrs);
+
+		if (res)
+			goto error;
+
+		res = register_attrs(resource, misc_cap_attrs);
 		if (res)
 			goto error;
 	}
+
 skip_unsafe_cap:
-
 	if (resource->caps.flags & POWER_METER_CAN_TRIP) {
-		res = register_rw_attrs(resource, trip_attrs);
+		res = register_attrs(resource, trip_attrs);
 		if (res)
 			goto error;
 	}
 
-	res = register_ro_attrs(resource, misc_attrs);
+	res = register_attrs(resource, misc_attrs);
 	if (res)
 		goto error;
 
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
index f85ce70..cfec802 100644
--- a/drivers/hwmon/ad7314.c
+++ b/drivers/hwmon/ad7314.c
@@ -18,21 +18,14 @@
 #include <linux/hwmon-sysfs.h>
 
 /*
- * AD7314 power mode
- */
-#define AD7314_PD		0x2000
-
-/*
  * AD7314 temperature masks
  */
-#define AD7314_TEMP_SIGN		0x200
 #define AD7314_TEMP_MASK		0x7FE0
-#define AD7314_TEMP_OFFSET		5
+#define AD7314_TEMP_SHIFT		5
 
 /*
  * ADT7301 and ADT7302 temperature masks
  */
-#define ADT7301_TEMP_SIGN		0x2000
 #define ADT7301_TEMP_MASK		0x3FFF
 
 enum ad7314_variant {
@@ -73,7 +66,7 @@
 		return ret;
 	switch (spi_get_device_id(chip->spi_dev)->driver_data) {
 	case ad7314:
-		data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET;
+		data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
 		data = (data << 6) >> 6;
 
 		return sprintf(buf, "%d\n", 250 * data);
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index e8e18ca..6b13f1a 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -257,15 +257,4 @@
 	.remove = __devexit_p(fam15h_power_remove),
 };
 
-static int __init fam15h_power_init(void)
-{
-	return pci_register_driver(&fam15h_power_driver);
-}
-
-static void __exit fam15h_power_exit(void)
-{
-	pci_unregister_driver(&fam15h_power_driver);
-}
-
-module_init(fam15h_power_init)
-module_exit(fam15h_power_exit)
+module_pci_driver(fam15h_power_driver);
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
new file mode 100644
index 0000000..7f3f4a3
--- /dev/null
+++ b/drivers/hwmon/ina2xx.c
@@ -0,0 +1,368 @@
+/*
+ * Driver for Texas Instruments INA219, INA226 power monitor chips
+ *
+ * INA219:
+ * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina219
+ *
+ * INA226:
+ * Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina226
+ *
+ * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ * Thanks to Jan Volkering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/platform_data/ina2xx.h>
+
+/* common register definitions */
+#define INA2XX_CONFIG			0x00
+#define INA2XX_SHUNT_VOLTAGE		0x01 /* readonly */
+#define INA2XX_BUS_VOLTAGE		0x02 /* readonly */
+#define INA2XX_POWER			0x03 /* readonly */
+#define INA2XX_CURRENT			0x04 /* readonly */
+#define INA2XX_CALIBRATION		0x05
+
+/* INA226 register definitions */
+#define INA226_MASK_ENABLE		0x06
+#define INA226_ALERT_LIMIT		0x07
+#define INA226_DIE_ID			0xFF
+
+
+/* register count */
+#define INA219_REGISTERS		6
+#define INA226_REGISTERS		8
+
+#define INA2XX_MAX_REGISTERS		8
+
+/* settings - depend on use case */
+#define INA219_CONFIG_DEFAULT		0x399F	/* PGA=8 */
+#define INA226_CONFIG_DEFAULT		0x4527	/* averages=16 */
+
+/* worst case is 68.10 ms (~14.6Hz, ina219) */
+#define INA2XX_CONVERSION_RATE		15
+
+enum ina2xx_ids { ina219, ina226 };
+
+struct ina2xx_data {
+	struct device *hwmon_dev;
+
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated;
+
+	int kind;
+	int registers;
+	u16 regs[INA2XX_MAX_REGISTERS];
+};
+
+int ina2xx_read_word(struct i2c_client *client, int reg)
+{
+	int val = i2c_smbus_read_word_data(client, reg);
+	if (unlikely(val < 0)) {
+		dev_dbg(&client->dev,
+			"Failed to read register: %d\n", reg);
+		return val;
+	}
+	return be16_to_cpu(val);
+}
+
+void ina2xx_write_word(struct i2c_client *client, int reg, int data)
+{
+	i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+}
+
+static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ina2xx_data *data = i2c_get_clientdata(client);
+	struct ina2xx_data *ret = data;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated +
+		       HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
+
+		int i;
+
+		dev_dbg(&client->dev, "Starting ina2xx update\n");
+
+		/* Read all registers */
+		for (i = 0; i < data->registers; i++) {
+			int rv = ina2xx_read_word(client, i);
+			if (rv < 0) {
+				ret = ERR_PTR(rv);
+				goto abort;
+			}
+			data->regs[i] = rv;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static int ina219_get_value(struct ina2xx_data *data, u8 reg)
+{
+	/*
+	 * calculate exact value for the given register
+	 * we assume default power-on reset settings:
+	 * bus voltage range 32V
+	 * gain = /8
+	 * adc 1 & 2 -> conversion time 532uS
+	 * mode is continuous shunt and bus
+	 * calibration value is INA219_CALIBRATION_VALUE
+	 */
+	int val = data->regs[reg];
+
+	switch (reg) {
+	case INA2XX_SHUNT_VOLTAGE:
+		/* LSB=10uV. Convert to mV. */
+		val = DIV_ROUND_CLOSEST(val, 100);
+		break;
+	case INA2XX_BUS_VOLTAGE:
+		/* LSB=4mV. Register is not right aligned, convert to mV. */
+		val = (val >> 3) * 4;
+		break;
+	case INA2XX_POWER:
+		/* LSB=20mW. Convert to uW */
+		val = val * 20 * 1000;
+		break;
+	case INA2XX_CURRENT:
+		/* LSB=1mA (selected). Is in mA */
+		break;
+	default:
+		/* programmer goofed */
+		WARN_ON_ONCE(1);
+		val = 0;
+		break;
+	}
+
+	return val;
+}
+
+static int ina226_get_value(struct ina2xx_data *data, u8 reg)
+{
+	/*
+	 * calculate exact value for the given register
+	 * we assume default power-on reset settings:
+	 * bus voltage range 32V
+	 * gain = /8
+	 * adc 1 & 2 -> conversion time 532uS
+	 * mode is continuous shunt and bus
+	 * calibration value is INA226_CALIBRATION_VALUE
+	 */
+	int val = data->regs[reg];
+
+	switch (reg) {
+	case INA2XX_SHUNT_VOLTAGE:
+		/* LSB=2.5uV. Convert to mV. */
+		val = DIV_ROUND_CLOSEST(val, 400);
+		break;
+	case INA2XX_BUS_VOLTAGE:
+		/* LSB=1.25mV. Convert to mV. */
+		val = val + DIV_ROUND_CLOSEST(val, 4);
+		break;
+	case INA2XX_POWER:
+		/* LSB=25mW. Convert to uW */
+		val = val * 25 * 1000;
+		break;
+	case INA2XX_CURRENT:
+		/* LSB=1mA (selected). Is in mA */
+		break;
+	default:
+		/* programmer goofed */
+		WARN_ON_ONCE(1);
+		val = 0;
+		break;
+	}
+
+	return val;
+}
+
+static ssize_t ina2xx_show_value(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ina2xx_data *data = ina2xx_update_device(dev);
+	int value = 0;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	switch (data->kind) {
+	case ina219:
+		value = ina219_get_value(data, attr->index);
+		break;
+	case ina226:
+		value = ina226_get_value(data, attr->index);
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		break;
+	}
+	return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+/* shunt voltage */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
+	ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
+
+/* bus voltage */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
+	ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
+
+/* calculated current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
+	ina2xx_show_value, NULL, INA2XX_CURRENT);
+
+/* calculated power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
+	ina2xx_show_value, NULL, INA2XX_POWER);
+
+/* pointers to created device attributes */
+static struct attribute *ina2xx_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_power1_input.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ina2xx_group = {
+	.attrs = ina2xx_attributes,
+};
+
+static int ina2xx_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct ina2xx_data *data;
+	struct ina2xx_platform_data *pdata;
+	int ret = 0;
+	long shunt = 10000; /* default shunt value 10mOhms */
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (client->dev.platform_data) {
+		pdata =
+		  (struct ina2xx_platform_data *)client->dev.platform_data;
+		shunt = pdata->shunt_uohms;
+	}
+
+	if (shunt <= 0)
+		return -ENODEV;
+
+	/* set the device type */
+	data->kind = id->driver_data;
+
+	switch (data->kind) {
+	case ina219:
+		/* device configuration */
+		ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT);
+
+		/* set current LSB to 1mA, shunt is in uOhms */
+		/* (equation 13 in datasheet) */
+		ina2xx_write_word(client, INA2XX_CALIBRATION, 40960000 / shunt);
+		dev_info(&client->dev,
+			 "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
+		data->registers = INA219_REGISTERS;
+		break;
+	case ina226:
+		/* device configuration */
+		ina2xx_write_word(client, INA2XX_CONFIG, INA226_CONFIG_DEFAULT);
+
+		/* set current LSB to 1mA, shunt is in uOhms */
+		/* (equation 1 in datasheet)*/
+		ina2xx_write_word(client, INA2XX_CALIBRATION, 5120000 / shunt);
+		dev_info(&client->dev,
+			 "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
+		data->registers = INA226_REGISTERS;
+		break;
+	default:
+		/* unknown device id */
+		return -ENODEV;
+	}
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group);
+	if (ret)
+		return ret;
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto out_err_hwmon;
+	}
+
+	return 0;
+
+out_err_hwmon:
+	sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
+	return ret;
+}
+
+static int ina2xx_remove(struct i2c_client *client)
+{
+	struct ina2xx_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
+
+	return 0;
+}
+
+static const struct i2c_device_id ina2xx_id[] = {
+	{ "ina219", ina219 },
+	{ "ina226", ina226 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ina2xx_id);
+
+static struct i2c_driver ina2xx_driver = {
+	.driver = {
+		.name	= "ina2xx",
+	},
+	.probe		= ina2xx_probe,
+	.remove		= ina2xx_remove,
+	.id_table	= ina2xx_id,
+};
+
+static int __init ina2xx_init(void)
+{
+	return i2c_add_driver(&ina2xx_driver);
+}
+
+static void __exit ina2xx_exit(void)
+{
+	i2c_del_driver(&ina2xx_driver);
+}
+
+MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
+MODULE_DESCRIPTION("ina2xx driver");
+MODULE_LICENSE("GPL");
+
+module_init(ina2xx_init);
+module_exit(ina2xx_exit);
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 0b204e4..e7701d9 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -19,6 +19,8 @@
  *            IT8726F  Super I/O chip w/LPC interface
  *            IT8728F  Super I/O chip w/LPC interface
  *            IT8758E  Super I/O chip w/LPC interface
+ *            IT8782F  Super I/O chip w/LPC interface
+ *            IT8783E/F Super I/O chip w/LPC interface
  *            Sis950   A clone of the IT8705F
  *
  *  Copyright (C) 2001 Chris Gauthron
@@ -59,7 +61,8 @@
 
 #define DRVNAME "it87"
 
-enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782,
+	     it8783 };
 
 static unsigned short force_id;
 module_param(force_id, ushort, 0);
@@ -137,13 +140,18 @@
 #define IT8721F_DEVID 0x8721
 #define IT8726F_DEVID 0x8726
 #define IT8728F_DEVID 0x8728
+#define IT8782F_DEVID 0x8782
+#define IT8783E_DEVID 0x8783
 #define IT87_ACT_REG  0x30
 #define IT87_BASE_REG 0x60
 
 /* Logical device 7 registers (IT8712F and later) */
+#define IT87_SIO_GPIO1_REG	0x25
 #define IT87_SIO_GPIO3_REG	0x27
 #define IT87_SIO_GPIO5_REG	0x29
+#define IT87_SIO_PINX1_REG	0x2a	/* Pin selection */
 #define IT87_SIO_PINX2_REG	0x2c	/* Pin selection */
+#define IT87_SIO_SPI_REG	0xef	/* SPI function pin select */
 #define IT87_SIO_VID_REG	0xfc	/* VID value */
 #define IT87_SIO_BEEP_PIN_REG	0xf6	/* Beep pin mapping */
 
@@ -210,6 +218,7 @@
 
 #define IT87_REG_VIN_ENABLE    0x50
 #define IT87_REG_TEMP_ENABLE   0x51
+#define IT87_REG_TEMP_EXTRA    0x55
 #define IT87_REG_BEEP_ENABLE   0x5c
 
 #define IT87_REG_CHIPID        0x58
@@ -226,9 +235,11 @@
 	u8 beep_pin;
 	u8 internal;	/* Internal sensors can be labeled */
 	/* Features skipped based on config or DMI */
+	u16 skip_in;
 	u8 skip_vid;
 	u8 skip_fan;
 	u8 skip_pwm;
+	u8 skip_temp;
 };
 
 /*
@@ -253,6 +264,7 @@
 	u8 has_fan;		/* Bitfield, fans enabled */
 	u16 fan[5];		/* Register values, possibly combined */
 	u16 fan_min[5];		/* Register values, possibly combined */
+	u8 has_temp;		/* Bitfield, temp sensors enabled */
 	s8 temp[3];		/* Register value */
 	s8 temp_high[3];	/* Register value */
 	s8 temp_low[3];		/* Register value */
@@ -304,31 +316,23 @@
 	    || data->type == it8728;
 }
 
+static int adc_lsb(const struct it87_data *data, int nr)
+{
+	int lsb = has_12mv_adc(data) ? 12 : 16;
+	if (data->in_scaled & (1 << nr))
+		lsb <<= 1;
+	return lsb;
+}
+
 static u8 in_to_reg(const struct it87_data *data, int nr, long val)
 {
-	long lsb;
-
-	if (has_12mv_adc(data)) {
-		if (data->in_scaled & (1 << nr))
-			lsb = 24;
-		else
-			lsb = 12;
-	} else
-		lsb = 16;
-
-	val = DIV_ROUND_CLOSEST(val, lsb);
+	val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr));
 	return SENSORS_LIMIT(val, 0, 255);
 }
 
 static int in_from_reg(const struct it87_data *data, int nr, int val)
 {
-	if (has_12mv_adc(data)) {
-		if (data->in_scaled & (1 << nr))
-			return val * 24;
-		else
-			return val * 12;
-	} else
-		return val * 16;
+	return val * adc_lsb(data, nr);
 }
 
 static inline u8 FAN_TO_REG(long rpm, int div)
@@ -407,7 +411,9 @@
 	    || data->type == it8718
 	    || data->type == it8720
 	    || data->type == it8721
-	    || data->type == it8728;
+	    || data->type == it8728
+	    || data->type == it8782
+	    || data->type == it8783;
 }
 
 static inline int has_old_autopwm(const struct it87_data *data)
@@ -1369,57 +1375,103 @@
 }
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static struct attribute *it87_attributes[] = {
+static struct attribute *it87_attributes_in[9][5] = {
+{
 	&sensor_dev_attr_in0_input.dev_attr.attr,
-	&sensor_dev_attr_in1_input.dev_attr.attr,
-	&sensor_dev_attr_in2_input.dev_attr.attr,
-	&sensor_dev_attr_in3_input.dev_attr.attr,
-	&sensor_dev_attr_in4_input.dev_attr.attr,
-	&sensor_dev_attr_in5_input.dev_attr.attr,
-	&sensor_dev_attr_in6_input.dev_attr.attr,
-	&sensor_dev_attr_in7_input.dev_attr.attr,
-	&sensor_dev_attr_in8_input.dev_attr.attr,
 	&sensor_dev_attr_in0_min.dev_attr.attr,
-	&sensor_dev_attr_in1_min.dev_attr.attr,
-	&sensor_dev_attr_in2_min.dev_attr.attr,
-	&sensor_dev_attr_in3_min.dev_attr.attr,
-	&sensor_dev_attr_in4_min.dev_attr.attr,
-	&sensor_dev_attr_in5_min.dev_attr.attr,
-	&sensor_dev_attr_in6_min.dev_attr.attr,
-	&sensor_dev_attr_in7_min.dev_attr.attr,
 	&sensor_dev_attr_in0_max.dev_attr.attr,
-	&sensor_dev_attr_in1_max.dev_attr.attr,
-	&sensor_dev_attr_in2_max.dev_attr.attr,
-	&sensor_dev_attr_in3_max.dev_attr.attr,
-	&sensor_dev_attr_in4_max.dev_attr.attr,
-	&sensor_dev_attr_in5_max.dev_attr.attr,
-	&sensor_dev_attr_in6_max.dev_attr.attr,
-	&sensor_dev_attr_in7_max.dev_attr.attr,
 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
 	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
 	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
 	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	NULL
+} };
 
+static const struct attribute_group it87_group_in[9] = {
+	{ .attrs = it87_attributes_in[0] },
+	{ .attrs = it87_attributes_in[1] },
+	{ .attrs = it87_attributes_in[2] },
+	{ .attrs = it87_attributes_in[3] },
+	{ .attrs = it87_attributes_in[4] },
+	{ .attrs = it87_attributes_in[5] },
+	{ .attrs = it87_attributes_in[6] },
+	{ .attrs = it87_attributes_in[7] },
+	{ .attrs = it87_attributes_in[8] },
+};
+
+static struct attribute *it87_attributes_temp[3][6] = {
+{
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
-	&sensor_dev_attr_temp2_input.dev_attr.attr,
-	&sensor_dev_attr_temp3_input.dev_attr.attr,
 	&sensor_dev_attr_temp1_max.dev_attr.attr,
-	&sensor_dev_attr_temp2_max.dev_attr.attr,
-	&sensor_dev_attr_temp3_max.dev_attr.attr,
 	&sensor_dev_attr_temp1_min.dev_attr.attr,
-	&sensor_dev_attr_temp2_min.dev_attr.attr,
-	&sensor_dev_attr_temp3_min.dev_attr.attr,
 	&sensor_dev_attr_temp1_type.dev_attr.attr,
-	&sensor_dev_attr_temp2_type.dev_attr.attr,
-	&sensor_dev_attr_temp3_type.dev_attr.attr,
 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	NULL
+} , {
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_type.dev_attr.attr,
 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	NULL
+} , {
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_type.dev_attr.attr,
 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	NULL
+} };
 
+static const struct attribute_group it87_group_temp[3] = {
+	{ .attrs = it87_attributes_temp[0] },
+	{ .attrs = it87_attributes_temp[1] },
+	{ .attrs = it87_attributes_temp[2] },
+};
+
+static struct attribute *it87_attributes[] = {
 	&dev_attr_alarms.attr,
 	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
 	&dev_attr_name.attr,
@@ -1430,7 +1482,7 @@
 	.attrs = it87_attributes,
 };
 
-static struct attribute *it87_attributes_beep[] = {
+static struct attribute *it87_attributes_in_beep[] = {
 	&sensor_dev_attr_in0_beep.dev_attr.attr,
 	&sensor_dev_attr_in1_beep.dev_attr.attr,
 	&sensor_dev_attr_in2_beep.dev_attr.attr,
@@ -1439,15 +1491,13 @@
 	&sensor_dev_attr_in5_beep.dev_attr.attr,
 	&sensor_dev_attr_in6_beep.dev_attr.attr,
 	&sensor_dev_attr_in7_beep.dev_attr.attr,
-
-	&sensor_dev_attr_temp1_beep.dev_attr.attr,
-	&sensor_dev_attr_temp2_beep.dev_attr.attr,
-	&sensor_dev_attr_temp3_beep.dev_attr.attr,
 	NULL
 };
 
-static const struct attribute_group it87_group_beep = {
-	.attrs = it87_attributes_beep,
+static struct attribute *it87_attributes_temp_beep[] = {
+	&sensor_dev_attr_temp1_beep.dev_attr.attr,
+	&sensor_dev_attr_temp2_beep.dev_attr.attr,
+	&sensor_dev_attr_temp3_beep.dev_attr.attr,
 };
 
 static struct attribute *it87_attributes_fan16[5][3+1] = { {
@@ -1651,6 +1701,12 @@
 	case IT8728F_DEVID:
 		sio_data->type = it8728;
 		break;
+	case IT8782F_DEVID:
+		sio_data->type = it8782;
+		break;
+	case IT8783E_DEVID:
+		sio_data->type = it8783;
+		break;
 	case 0xffff:	/* No device at all */
 		goto exit;
 	default:
@@ -1686,16 +1742,86 @@
 		/* The IT8705F has a different LD number for GPIO */
 		superio_select(5);
 		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+	} else if (sio_data->type == it8783) {
+		int reg25, reg27, reg2A, reg2C, regEF;
+
+		sio_data->skip_vid = 1;	/* No VID */
+
+		superio_select(GPIO);
+
+		reg25 = superio_inb(IT87_SIO_GPIO1_REG);
+		reg27 = superio_inb(IT87_SIO_GPIO3_REG);
+		reg2A = superio_inb(IT87_SIO_PINX1_REG);
+		reg2C = superio_inb(IT87_SIO_PINX2_REG);
+		regEF = superio_inb(IT87_SIO_SPI_REG);
+
+		/* Check if fan3 is there or not */
+		if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2)))
+			sio_data->skip_fan |= (1 << 2);
+		if ((reg25 & (1 << 4))
+		    || (!(reg2A & (1 << 1)) && (regEF & (1 << 0))))
+			sio_data->skip_pwm |= (1 << 2);
+
+		/* Check if fan2 is there or not */
+		if (reg27 & (1 << 7))
+			sio_data->skip_fan |= (1 << 1);
+		if (reg27 & (1 << 3))
+			sio_data->skip_pwm |= (1 << 1);
+
+		/* VIN5 */
+		if ((reg27 & (1 << 0)) || (reg2C & (1 << 2)))
+			sio_data->skip_in |= (1 << 5); /* No VIN5 */
+
+		/* VIN6 */
+		if (reg27 & (1 << 1))
+			sio_data->skip_in |= (1 << 6); /* No VIN6 */
+
+		/*
+		 * VIN7
+		 * Does not depend on bit 2 of Reg2C, contrary to datasheet.
+		 */
+		if (reg27 & (1 << 2)) {
+			/*
+			 * The data sheet is a bit unclear regarding the
+			 * internal voltage divider for VCCH5V. It says
+			 * "This bit enables and switches VIN7 (pin 91) to the
+			 * internal voltage divider for VCCH5V".
+			 * This is different to other chips, where the internal
+			 * voltage divider would connect VIN7 to an internal
+			 * voltage source. Maybe that is the case here as well.
+			 *
+			 * Since we don't know for sure, re-route it if that is
+			 * not the case, and ask the user to report if the
+			 * resulting voltage is sane.
+			 */
+			if (!(reg2C & (1 << 1))) {
+				reg2C |= (1 << 1);
+				superio_outb(IT87_SIO_PINX2_REG, reg2C);
+				pr_notice("Routing internal VCCH5V to in7.\n");
+			}
+			pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
+			pr_notice("Please report if it displays a reasonable voltage.\n");
+		}
+
+		if (reg2C & (1 << 0))
+			sio_data->internal |= (1 << 0);
+		if (reg2C & (1 << 1))
+			sio_data->internal |= (1 << 1);
+
+		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+
 	} else {
 		int reg;
+		bool uart6;
 
 		superio_select(GPIO);
 
 		reg = superio_inb(IT87_SIO_GPIO3_REG);
-		if (sio_data->type == it8721 || sio_data->type == it8728) {
+		if (sio_data->type == it8721 || sio_data->type == it8728 ||
+		    sio_data->type == it8782) {
 			/*
-			 * The IT8721F/IT8758E doesn't have VID pins at all,
-			 * not sure about the IT8728F.
+			 * IT8721F/IT8758E, and IT8782F don't have VID pins
+			 * at all, not sure about the IT8728F.
 			 */
 			sio_data->skip_vid = 1;
 		} else {
@@ -1724,6 +1850,9 @@
 			sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
 
 		reg = superio_inb(IT87_SIO_PINX2_REG);
+
+		uart6 = sio_data->type == it8782 && (reg & (1 << 2));
+
 		/*
 		 * The IT8720F has no VIN7 pin, so VCCH should always be
 		 * routed internally to VIN7 with an internal divider.
@@ -1733,8 +1862,12 @@
 		 * configured, even though the IT8720F datasheet claims
 		 * that the internal routing of VCCH to VIN7 is the default
 		 * setting. So we force the internal routing in this case.
+		 *
+		 * On IT8782F, VIN7 is multiplexed with one of the UART6 pins.
+		 * If UART6 is enabled, re-route VIN7 to the internal divider
+		 * if that is not already the case.
 		 */
-		if (sio_data->type == it8720 && !(reg & (1 << 1))) {
+		if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) {
 			reg |= (1 << 1);
 			superio_outb(IT87_SIO_PINX2_REG, reg);
 			pr_notice("Routing internal VCCH to in7\n");
@@ -1745,6 +1878,20 @@
 		    sio_data->type == it8728)
 			sio_data->internal |= (1 << 1);
 
+		/*
+		 * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7.
+		 * While VIN7 can be routed to the internal voltage divider,
+		 * VIN5 and VIN6 are not available if UART6 is enabled.
+		 *
+		 * Also, temp3 is not available if UART6 is enabled and TEMPIN3
+		 * is the temperature source. Since we can not read the
+		 * temperature source here, skip_temp is preliminary.
+		 */
+		if (uart6) {
+			sio_data->skip_in |= (1 << 5) | (1 << 6);
+			sio_data->skip_temp |= (1 << 2);
+		}
+
 		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
 	}
 	if (sio_data->beep_pin)
@@ -1782,8 +1929,22 @@
 	int i;
 
 	sysfs_remove_group(&dev->kobj, &it87_group);
-	if (sio_data->beep_pin)
-		sysfs_remove_group(&dev->kobj, &it87_group_beep);
+	for (i = 0; i < 9; i++) {
+		if (sio_data->skip_in & (1 << i))
+			continue;
+		sysfs_remove_group(&dev->kobj, &it87_group_in[i]);
+		if (it87_attributes_in_beep[i])
+			sysfs_remove_file(&dev->kobj,
+					  it87_attributes_in_beep[i]);
+	}
+	for (i = 0; i < 3; i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		sysfs_remove_group(&dev->kobj, &it87_group_temp[i]);
+		if (sio_data->beep_pin)
+			sysfs_remove_file(&dev->kobj,
+					  it87_attributes_temp_beep[i]);
+	}
 	for (i = 0; i < 5; i++) {
 		if (!(data->has_fan & (1 << i)))
 			continue;
@@ -1823,22 +1984,22 @@
 		"it8720",
 		"it8721",
 		"it8728",
+		"it8782",
+		"it8783",
 	};
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, IT87_EC_EXTENT, DRVNAME)) {
+	if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
+				 DRVNAME)) {
 		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
 			(unsigned long)res->start,
 			(unsigned long)(res->start + IT87_EC_EXTENT - 1));
-		err = -EBUSY;
-		goto ERROR0;
+		return -EBUSY;
 	}
 
-	data = kzalloc(sizeof(struct it87_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto ERROR1;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	data->addr = res->start;
 	data->type = sio_data->type;
@@ -1847,10 +2008,8 @@
 
 	/* Now, we do the remaining detection. */
 	if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
-	 || it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
-		err = -ENODEV;
-		goto ERROR2;
-	}
+	 || it87_read_value(data, IT87_REG_CHIPID) != 0x90)
+		return -ENODEV;
 
 	platform_set_drvdata(pdev, data);
 
@@ -1867,6 +2026,18 @@
 			data->in_scaled |= (1 << 7);	/* in7 is VSB */
 		if (sio_data->internal & (1 << 2))
 			data->in_scaled |= (1 << 8);	/* in8 is Vbat */
+	} else if (sio_data->type == it8782 || sio_data->type == it8783) {
+		if (sio_data->internal & (1 << 0))
+			data->in_scaled |= (1 << 3);	/* in3 is VCC5V */
+		if (sio_data->internal & (1 << 1))
+			data->in_scaled |= (1 << 7);	/* in7 is VCCH5V */
+	}
+
+	data->has_temp = 0x07;
+	if (sio_data->skip_temp & (1 << 2)) {
+		if (sio_data->type == it8782
+		    && !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
+			data->has_temp &= ~(1 << 2);
 	}
 
 	/* Initialize the IT87 chip */
@@ -1875,12 +2046,34 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&dev->kobj, &it87_group);
 	if (err)
-		goto ERROR2;
+		return err;
 
-	if (sio_data->beep_pin) {
-		err = sysfs_create_group(&dev->kobj, &it87_group_beep);
+	for (i = 0; i < 9; i++) {
+		if (sio_data->skip_in & (1 << i))
+			continue;
+		err = sysfs_create_group(&dev->kobj, &it87_group_in[i]);
 		if (err)
-			goto ERROR4;
+			goto error;
+		if (sio_data->beep_pin && it87_attributes_in_beep[i]) {
+			err = sysfs_create_file(&dev->kobj,
+						it87_attributes_in_beep[i]);
+			if (err)
+				goto error;
+		}
+	}
+
+	for (i = 0; i < 3; i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]);
+		if (err)
+			goto error;
+		if (sio_data->beep_pin) {
+			err = sysfs_create_file(&dev->kobj,
+						it87_attributes_temp_beep[i]);
+			if (err)
+				goto error;
+		}
 	}
 
 	/* Do not create fan files for disabled fans */
@@ -1891,13 +2084,13 @@
 			continue;
 		err = sysfs_create_group(&dev->kobj, &fan_group[i]);
 		if (err)
-			goto ERROR4;
+			goto error;
 
 		if (sio_data->beep_pin) {
 			err = sysfs_create_file(&dev->kobj,
 						it87_attributes_fan_beep[i]);
 			if (err)
-				goto ERROR4;
+				goto error;
 			if (!fan_beep_need_rw)
 				continue;
 
@@ -1922,14 +2115,14 @@
 			err = sysfs_create_group(&dev->kobj,
 						 &it87_group_pwm[i]);
 			if (err)
-				goto ERROR4;
+				goto error;
 
 			if (!has_old_autopwm(data))
 				continue;
 			err = sysfs_create_group(&dev->kobj,
 						 &it87_group_autopwm[i]);
 			if (err)
-				goto ERROR4;
+				goto error;
 		}
 	}
 
@@ -1939,7 +2132,7 @@
 		data->vid = sio_data->vid_value;
 		err = sysfs_create_group(&dev->kobj, &it87_group_vid);
 		if (err)
-			goto ERROR4;
+			goto error;
 	}
 
 	/* Export labels for internal sensors */
@@ -1949,25 +2142,19 @@
 		err = sysfs_create_file(&dev->kobj,
 					it87_attributes_label[i]);
 		if (err)
-			goto ERROR4;
+			goto error;
 	}
 
 	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		err = PTR_ERR(data->hwmon_dev);
-		goto ERROR4;
+		goto error;
 	}
 
 	return 0;
 
-ERROR4:
+error:
 	it87_remove_files(dev);
-ERROR2:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-ERROR1:
-	release_region(res->start, IT87_EC_EXTENT);
-ERROR0:
 	return err;
 }
 
@@ -1978,10 +2165,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	it87_remove_files(&pdev->dev);
 
-	release_region(data->addr, IT87_EC_EXTENT);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
 	return 0;
 }
 
@@ -2143,8 +2326,9 @@
 			it87_write_value(data, IT87_REG_FAN_16BIT,
 					 tmp | 0x07);
 		}
-		/* IT8705F only supports three fans. */
-		if (data->type != it87) {
+		/* IT8705F, IT8782F, and IT8783E/F only support three fans. */
+		if (data->type != it87 && data->type != it8782 &&
+		    data->type != it8783) {
 			if (tmp & (1 << 4))
 				data->has_fan |= (1 << 3); /* fan4 enabled */
 			if (tmp & (1 << 5))
@@ -2233,6 +2417,8 @@
 			}
 		}
 		for (i = 0; i < 3; i++) {
+			if (!(data->has_temp & (1 << i)))
+				continue;
 			data->temp[i] =
 				it87_read_value(data, IT87_REG_TEMP(i));
 			data->temp_high[i] =
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index 307bb32..7356b5e 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -225,15 +225,4 @@
 	.remove = __devexit_p(k10temp_remove),
 };
 
-static int __init k10temp_init(void)
-{
-	return pci_register_driver(&k10temp_driver);
-}
-
-static void __exit k10temp_exit(void)
-{
-	pci_unregister_driver(&k10temp_driver);
-}
-
-module_init(k10temp_init)
-module_exit(k10temp_exit)
+module_pci_driver(k10temp_driver);
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 5751019..35aac82 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -339,19 +339,8 @@
 	.remove = __devexit_p(k8temp_remove),
 };
 
-static int __init k8temp_init(void)
-{
-	return pci_register_driver(&k8temp_driver);
-}
-
-static void __exit k8temp_exit(void)
-{
-	pci_unregister_driver(&k8temp_driver);
-}
+module_pci_driver(k8temp_driver);
 
 MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
 MODULE_DESCRIPTION("AMD K8 core temperature monitor");
 MODULE_LICENSE("GPL");
-
-module_init(k8temp_init)
-module_exit(k8temp_exit)
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 9b382ec..6da9696 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -134,8 +134,7 @@
 	return div64_u64(dividend, divisor);
 }
 
-static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
-		unsigned int uV)
+static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV)
 {
 	struct ntc_thermistor_platform_data *pdata = data->pdata;
 	u64 mV = uV / 1000;
@@ -146,12 +145,12 @@
 
 	if (mV == 0) {
 		if (pdata->connect == NTC_CONNECTED_POSITIVE)
-			return UINT_MAX;
+			return INT_MAX;
 		return 0;
 	}
 	if (mV >= pmV)
 		return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
-			0 : UINT_MAX;
+			0 : INT_MAX;
 
 	if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
 		N = div64_u64_safe(pdO * (pmV - mV), mV);
@@ -163,113 +162,109 @@
 	else
 		N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
 
-	return (unsigned int) N;
+	if (N > INT_MAX)
+		N = INT_MAX;
+	return N;
 }
 
-static int lookup_comp(struct ntc_data *data,
-		unsigned int ohm, int *i_low, int *i_high)
+static void lookup_comp(struct ntc_data *data, unsigned int ohm,
+			int *i_low, int *i_high)
 {
-	int start, end, mid = -1;
+	int start, end, mid;
+
+	/*
+	 * Handle special cases: Resistance is higher than or equal to
+	 * resistance in first table entry, or resistance is lower or equal
+	 * to resistance in last table entry.
+	 * In these cases, return i_low == i_high, either pointing to the
+	 * beginning or to the end of the table depending on the condition.
+	 */
+	if (ohm >= data->comp[0].ohm) {
+		*i_low = 0;
+		*i_high = 0;
+		return;
+	}
+	if (ohm <= data->comp[data->n_comp - 1].ohm) {
+		*i_low = data->n_comp - 1;
+		*i_high = data->n_comp - 1;
+		return;
+	}
 
 	/* Do a binary search on compensation table */
 	start = 0;
 	end = data->n_comp;
-
-	while (end > start) {
+	while (start < end) {
 		mid = start + (end - start) / 2;
-		if (data->comp[mid].ohm < ohm)
+		/*
+		 * start <= mid < end
+		 * data->comp[start].ohm > ohm >= data->comp[end].ohm
+		 *
+		 * We could check for "ohm == data->comp[mid].ohm" here, but
+		 * that is a quite unlikely condition, and we would have to
+		 * check again after updating start. Check it at the end instead
+		 * for simplicity.
+		 */
+		if (ohm >= data->comp[mid].ohm) {
 			end = mid;
-		else if (data->comp[mid].ohm > ohm)
+		} else {
 			start = mid + 1;
-		else
-			break;
-	}
-
-	if (mid == 0) {
-		if (data->comp[mid].ohm > ohm) {
-			*i_high = mid;
-			*i_low = mid + 1;
-			return 0;
-		} else {
-			*i_low = mid;
-			*i_high = -1;
-			return -EINVAL;
+			/*
+			 * ohm >= data->comp[start].ohm might be true here,
+			 * since we set start to mid + 1. In that case, we are
+			 * done. We could keep going, but the condition is quite
+			 * likely to occur, so it is worth checking for it.
+			 */
+			if (ohm >= data->comp[start].ohm)
+				end = start;
 		}
+		/*
+		 * start <= end
+		 * data->comp[start].ohm >= ohm >= data->comp[end].ohm
+		 */
 	}
-	if (mid == (data->n_comp - 1)) {
-		if (data->comp[mid].ohm <= ohm) {
-			*i_low = mid;
-			*i_high = mid - 1;
-			return 0;
-		} else {
-			*i_low = -1;
-			*i_high = mid;
-			return -EINVAL;
-		}
-	}
-
-	if (data->comp[mid].ohm <= ohm) {
-		*i_low = mid;
-		*i_high = mid - 1;
-	} else {
-		*i_low = mid + 1;
-		*i_high = mid;
-	}
-
-	return 0;
+	/*
+	 * start == end
+	 * ohm >= data->comp[end].ohm
+	 */
+	*i_low = end;
+	if (ohm == data->comp[end].ohm)
+		*i_high = end;
+	else
+		*i_high = end - 1;
 }
 
-static int get_temp_mC(struct ntc_data *data, unsigned int ohm, int *temp)
+static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
 {
 	int low, high;
-	int ret;
+	int temp;
 
-	ret = lookup_comp(data, ohm, &low, &high);
-	if (ret) {
+	lookup_comp(data, ohm, &low, &high);
+	if (low == high) {
 		/* Unable to use linear approximation */
-		if (low != -1)
-			*temp = data->comp[low].temp_C * 1000;
-		else if (high != -1)
-			*temp = data->comp[high].temp_C * 1000;
-		else
-			return ret;
+		temp = data->comp[low].temp_C * 1000;
 	} else {
-		*temp = data->comp[low].temp_C * 1000 +
+		temp = data->comp[low].temp_C * 1000 +
 			((data->comp[high].temp_C - data->comp[low].temp_C) *
 			 1000 * ((int)ohm - (int)data->comp[low].ohm)) /
 			((int)data->comp[high].ohm - (int)data->comp[low].ohm);
 	}
-
-	return 0;
+	return temp;
 }
 
-static int ntc_thermistor_read(struct ntc_data *data, int *temp)
+static int ntc_thermistor_get_ohm(struct ntc_data *data)
 {
-	int ret;
-	int read_ohm, read_uV;
-	unsigned int ohm = 0;
+	int read_uV;
 
-	if (data->pdata->read_ohm) {
-		read_ohm = data->pdata->read_ohm();
-		if (read_ohm < 0)
-			return read_ohm;
-		ohm = (unsigned int)read_ohm;
-	}
+	if (data->pdata->read_ohm)
+		return data->pdata->read_ohm();
 
 	if (data->pdata->read_uV) {
 		read_uV = data->pdata->read_uV();
 		if (read_uV < 0)
 			return read_uV;
-		ohm = get_ohm_of_thermistor(data, (unsigned int)read_uV);
+		return get_ohm_of_thermistor(data, read_uV);
 	}
-
-	ret = get_temp_mC(data, ohm, temp);
-	if (ret) {
-		dev_dbg(data->dev, "Sensor reading function not available.\n");
-		return ret;
-	}
-
-	return 0;
+	return -EINVAL;
 }
 
 static ssize_t ntc_show_name(struct device *dev,
@@ -290,12 +285,13 @@
 		struct device_attribute *attr, char *buf)
 {
 	struct ntc_data *data = dev_get_drvdata(dev);
-	int temp, ret;
+	int ohm;
 
-	ret = ntc_thermistor_read(data, &temp);
-	if (ret)
-		return ret;
-	return sprintf(buf, "%d\n", temp);
+	ohm = ntc_thermistor_get_ohm(data);
+	if (ohm < 0)
+		return ohm;
+
+	return sprintf(buf, "%d\n", get_temp_mC(data, ohm));
 }
 
 static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
@@ -326,14 +322,14 @@
 
 	/* Either one of the two is required. */
 	if (!pdata->read_uV && !pdata->read_ohm) {
-		dev_err(&pdev->dev, "Both read_uV and read_ohm missing."
-				"Need either one of the two.\n");
+		dev_err(&pdev->dev,
+			"Both read_uV and read_ohm missing. Need either one of the two.\n");
 		return -EINVAL;
 	}
 
 	if (pdata->read_uV && pdata->read_ohm) {
-		dev_warn(&pdev->dev, "Only one of read_uV and read_ohm "
-				"is needed; ignoring read_uV.\n");
+		dev_warn(&pdev->dev,
+			 "Only one of read_uV and read_ohm is needed; ignoring read_uV.\n");
 		pdata->read_uV = NULL;
 	}
 
@@ -344,12 +340,12 @@
 				 NTC_CONNECTED_POSITIVE) ||
 				(pdata->connect != NTC_CONNECTED_POSITIVE &&
 				 pdata->connect != NTC_CONNECTED_GROUND))) {
-		dev_err(&pdev->dev, "Required data to use read_uV not "
-				"supplied.\n");
+		dev_err(&pdev->dev,
+			"Required data to use read_uV not supplied.\n");
 		return -EINVAL;
 	}
 
-	data = kzalloc(sizeof(struct ntc_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct ntc_data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -370,8 +366,7 @@
 		dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
 				pdev->id_entry->driver_data,
 				pdev->id_entry->name);
-		ret = -EINVAL;
-		goto err;
+		return -EINVAL;
 	}
 
 	platform_set_drvdata(pdev, data);
@@ -379,13 +374,13 @@
 	ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group);
 	if (ret) {
 		dev_err(data->dev, "unable to create sysfs files\n");
-		goto err;
+		return ret;
 	}
 
 	data->hwmon_dev = hwmon_device_register(data->dev);
-	if (IS_ERR_OR_NULL(data->hwmon_dev)) {
+	if (IS_ERR(data->hwmon_dev)) {
 		dev_err(data->dev, "unable to register as hwmon device.\n");
-		ret = -EINVAL;
+		ret = PTR_ERR(data->hwmon_dev);
 		goto err_after_sysfs;
 	}
 
@@ -395,8 +390,6 @@
 	return 0;
 err_after_sysfs:
 	sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
-err:
-	kfree(data);
 	return ret;
 }
 
@@ -408,8 +401,6 @@
 	sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
 	platform_set_drvdata(pdev, NULL);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d2c5095..94468a6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -351,7 +351,7 @@
 	  For details please see http://www.ti.com/davinci
 
 config I2C_DESIGNWARE_PLATFORM
-	tristate "Synopsys DesignWare Platfrom"
+	tristate "Synopsys DesignWare Platform"
 	depends on HAVE_CLK
 	help
 	  If you say yes to this option, support will be included for the
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index dfb84b7..56bce9a 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -51,6 +51,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_i2c.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <mach/irqs.h>
 #include <mach/hardware.h>
@@ -470,6 +471,7 @@
 	struct imx_i2c_struct *i2c_imx;
 	struct resource *res;
 	struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
+	struct pinctrl *pinctrl;
 	void __iomem *base;
 	resource_size_t res_size;
 	int irq, bitrate;
@@ -520,6 +522,12 @@
 	i2c_imx->base			= base;
 	i2c_imx->res			= res;
 
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		goto fail3;
+	}
+
 	/* Get I2C clock */
 	i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");
 	if (IS_ERR(i2c_imx->clk)) {
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 76b8af4..7fa73ee 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -26,6 +26,7 @@
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
 #include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <mach/common.h>
 
@@ -325,10 +326,15 @@
 	struct device *dev = &pdev->dev;
 	struct mxs_i2c_dev *i2c;
 	struct i2c_adapter *adap;
+	struct pinctrl *pinctrl;
 	struct resource *res;
 	resource_size_t res_size;
 	int err, irq;
 
+	pinctrl = devm_pinctrl_get_select_default(dev);
+	if (IS_ERR(pinctrl))
+		return PTR_ERR(pinctrl);
+
 	i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
 	if (!i2c)
 		return -ENOMEM;
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index eb8ad53..99389d2 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -23,16 +23,61 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
+#include <linux/of_i2c.h>
 
-#include <mach/hardware.h>
-#include <mach/i2c.h>
+#define I2C_PNX_TIMEOUT_DEFAULT		10 /* msec */
+#define I2C_PNX_SPEED_KHZ_DEFAULT	100
+#define I2C_PNX_REGION_SIZE		0x100
 
-#define I2C_PNX_TIMEOUT		10 /* msec */
-#define I2C_PNX_SPEED_KHZ	100
-#define I2C_PNX_REGION_SIZE	0x100
+enum {
+	mstatus_tdi = 0x00000001,
+	mstatus_afi = 0x00000002,
+	mstatus_nai = 0x00000004,
+	mstatus_drmi = 0x00000008,
+	mstatus_active = 0x00000020,
+	mstatus_scl = 0x00000040,
+	mstatus_sda = 0x00000080,
+	mstatus_rff = 0x00000100,
+	mstatus_rfe = 0x00000200,
+	mstatus_tff = 0x00000400,
+	mstatus_tfe = 0x00000800,
+};
 
-static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
+enum {
+	mcntrl_tdie = 0x00000001,
+	mcntrl_afie = 0x00000002,
+	mcntrl_naie = 0x00000004,
+	mcntrl_drmie = 0x00000008,
+	mcntrl_daie = 0x00000020,
+	mcntrl_rffie = 0x00000040,
+	mcntrl_tffie = 0x00000080,
+	mcntrl_reset = 0x00000100,
+	mcntrl_cdbmode = 0x00000400,
+};
+
+enum {
+	rw_bit = 1 << 0,
+	start_bit = 1 << 8,
+	stop_bit = 1 << 9,
+};
+
+#define I2C_REG_RX(a)	((a)->ioaddr)		/* Rx FIFO reg (RO) */
+#define I2C_REG_TX(a)	((a)->ioaddr)		/* Tx FIFO reg (WO) */
+#define I2C_REG_STS(a)	((a)->ioaddr + 0x04)	/* Status reg (RO) */
+#define I2C_REG_CTL(a)	((a)->ioaddr + 0x08)	/* Ctl reg */
+#define I2C_REG_CKL(a)	((a)->ioaddr + 0x0c)	/* Clock divider low */
+#define I2C_REG_CKH(a)	((a)->ioaddr + 0x10)	/* Clock divider high */
+#define I2C_REG_ADR(a)	((a)->ioaddr + 0x14)	/* I2C address */
+#define I2C_REG_RFL(a)	((a)->ioaddr + 0x18)	/* Rx FIFO level (RO) */
+#define I2C_REG_TFL(a)	((a)->ioaddr + 0x1c)	/* Tx FIFO level (RO) */
+#define I2C_REG_RXB(a)	((a)->ioaddr + 0x20)	/* Num of bytes Rx-ed (RO) */
+#define I2C_REG_TXB(a)	((a)->ioaddr + 0x24)	/* Num of bytes Tx-ed (RO) */
+#define I2C_REG_TXS(a)	((a)->ioaddr + 0x28)	/* Tx slave FIFO (RO) */
+#define I2C_REG_STFL(a)	((a)->ioaddr + 0x2c)	/* Tx slave FIFO level (RO) */
+
+static inline int wait_timeout(struct i2c_pnx_algo_data *data)
 {
+	long timeout = data->timeout;
 	while (timeout > 0 &&
 			(ioread32(I2C_REG_STS(data)) & mstatus_active)) {
 		mdelay(1);
@@ -41,8 +86,9 @@
 	return (timeout <= 0);
 }
 
-static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
+static inline int wait_reset(struct i2c_pnx_algo_data *data)
 {
+	long timeout = data->timeout;
 	while (timeout > 0 &&
 			(ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
 		mdelay(1);
@@ -54,7 +100,7 @@
 static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
 {
 	struct timer_list *timer = &alg_data->mif.timer;
-	unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
+	unsigned long expires = msecs_to_jiffies(alg_data->timeout);
 
 	if (expires <= 1)
 		expires = 2;
@@ -92,7 +138,7 @@
 	}
 
 	/* First, make sure bus is idle */
-	if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
+	if (wait_timeout(alg_data)) {
 		/* Somebody else is monopolizing the bus */
 		dev_err(&alg_data->adapter.dev,
 			"%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
@@ -185,7 +231,7 @@
 		if (alg_data->mif.len == 0) {
 			if (alg_data->last) {
 				/* Wait until the STOP is seen. */
-				if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+				if (wait_timeout(alg_data))
 					dev_err(&alg_data->adapter.dev,
 						"The bus is still active after timeout\n");
 			}
@@ -283,7 +329,7 @@
 		if (alg_data->mif.len == 0) {
 			if (alg_data->last)
 				/* Wait until the STOP is seen. */
-				if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+				if (wait_timeout(alg_data))
 					dev_err(&alg_data->adapter.dev,
 						"The bus is still active after timeout\n");
 
@@ -399,7 +445,7 @@
 
 	ctl |= mcntrl_reset;
 	iowrite32(ctl, I2C_REG_CTL(alg_data));
-	wait_reset(I2C_PNX_TIMEOUT, alg_data);
+	wait_reset(alg_data);
 	alg_data->mif.ret = -EIO;
 	complete(&alg_data->mif.complete);
 }
@@ -414,18 +460,18 @@
 			alg_data->adapter.name);
 		iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
 			  I2C_REG_CTL(alg_data));
-		wait_reset(I2C_PNX_TIMEOUT, alg_data);
+		wait_reset(alg_data);
 	} else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
 		/* If there is data in the fifo's after transfer,
 		 * flush fifo's by reset.
 		 */
 		iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
 			  I2C_REG_CTL(alg_data));
-		wait_reset(I2C_PNX_TIMEOUT, alg_data);
+		wait_reset(alg_data);
 	} else if (stat & mstatus_nai) {
 		iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
 			  I2C_REG_CTL(alg_data));
-		wait_reset(I2C_PNX_TIMEOUT, alg_data);
+		wait_reset(alg_data);
 	}
 }
 
@@ -568,14 +614,8 @@
 	int ret = 0;
 	struct i2c_pnx_algo_data *alg_data;
 	unsigned long freq;
-	struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
-
-	if (!i2c_pnx || !i2c_pnx->name) {
-		dev_err(&pdev->dev, "%s: no platform data supplied\n",
-		       __func__);
-		ret = -EINVAL;
-		goto out;
-	}
+	struct resource *res;
+	u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000;
 
 	alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
 	if (!alg_data) {
@@ -585,14 +625,27 @@
 
 	platform_set_drvdata(pdev, alg_data);
 
-	strlcpy(alg_data->adapter.name, i2c_pnx->name,
-		sizeof(alg_data->adapter.name));
 	alg_data->adapter.dev.parent = &pdev->dev;
 	alg_data->adapter.algo = &pnx_algorithm;
 	alg_data->adapter.algo_data = alg_data;
 	alg_data->adapter.nr = pdev->id;
-	alg_data->i2c_pnx = i2c_pnx;
 
+	alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT;
+#ifdef CONFIG_OF
+	alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node);
+	if (pdev->dev.of_node) {
+		of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+				     &speed);
+		/*
+		 * At this point, it is planned to add an OF timeout property.
+		 * As soon as there is a consensus about how to call and handle
+		 * this, sth. like the following can be put here:
+		 *
+		 * of_property_read_u32(pdev->dev.of_node, "timeout",
+		 *                      &alg_data->timeout);
+		 */
+	}
+#endif
 	alg_data->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(alg_data->clk)) {
 		ret = PTR_ERR(alg_data->clk);
@@ -603,17 +656,27 @@
 	alg_data->mif.timer.function = i2c_pnx_timeout;
 	alg_data->mif.timer.data = (unsigned long)alg_data;
 
+	snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
+		 "%s", pdev->name);
+
 	/* Register I/O resource */
-	if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE,
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Unable to get mem resource.\n");
+		ret = -EBUSY;
+		goto out_clkget;
+	}
+	if (!request_mem_region(res->start, I2C_PNX_REGION_SIZE,
 				pdev->name)) {
 		dev_err(&pdev->dev,
 		       "I/O region 0x%08x for I2C already in use.\n",
-		       i2c_pnx->base);
-		ret = -ENODEV;
+		       res->start);
+		ret = -ENOMEM;
 		goto out_clkget;
 	}
 
-	alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+	alg_data->base = res->start;
+	alg_data->ioaddr = ioremap(res->start, I2C_PNX_REGION_SIZE);
 	if (!alg_data->ioaddr) {
 		dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
 		ret = -ENOMEM;
@@ -637,20 +700,25 @@
 	 * the deglitching filter length.
 	 */
 
-	tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+	tmp = (freq / speed) / 2 - 2;
 	if (tmp > 0x3FF)
 		tmp = 0x3FF;
 	iowrite32(tmp, I2C_REG_CKH(alg_data));
 	iowrite32(tmp, I2C_REG_CKL(alg_data));
 
 	iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
-	if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
+	if (wait_reset(alg_data)) {
 		ret = -ENODEV;
 		goto out_clock;
 	}
 	init_completion(&alg_data->mif.complete);
 
-	ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt,
+	alg_data->irq = platform_get_irq(pdev, 0);
+	if (alg_data->irq < 0) {
+		dev_err(&pdev->dev, "Failed to get IRQ from platform resource\n");
+		goto out_irq;
+	}
+	ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
 			0, pdev->name, alg_data);
 	if (ret)
 		goto out_clock;
@@ -662,39 +730,39 @@
 		goto out_irq;
 	}
 
+	of_i2c_register_devices(&alg_data->adapter);
+
 	dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
-	       alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
+		alg_data->adapter.name, res->start, alg_data->irq);
 
 	return 0;
 
 out_irq:
-	free_irq(i2c_pnx->irq, alg_data);
+	free_irq(alg_data->irq, alg_data);
 out_clock:
 	clk_disable(alg_data->clk);
 out_unmap:
 	iounmap(alg_data->ioaddr);
 out_release:
-	release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+	release_mem_region(res->start, I2C_PNX_REGION_SIZE);
 out_clkget:
 	clk_put(alg_data->clk);
 out_drvdata:
 	kfree(alg_data);
 err_kzalloc:
 	platform_set_drvdata(pdev, NULL);
-out:
 	return ret;
 }
 
 static int __devexit i2c_pnx_remove(struct platform_device *pdev)
 {
 	struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
-	struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
 
-	free_irq(i2c_pnx->irq, alg_data);
+	free_irq(alg_data->irq, alg_data);
 	i2c_del_adapter(&alg_data->adapter);
 	clk_disable(alg_data->clk);
 	iounmap(alg_data->ioaddr);
-	release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+	release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
 	clk_put(alg_data->clk);
 	kfree(alg_data);
 	platform_set_drvdata(pdev, NULL);
@@ -702,10 +770,19 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id i2c_pnx_of_match[] = {
+	{ .compatible = "nxp,pnx-i2c" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, i2c_pnx_of_match);
+#endif
+
 static struct platform_driver i2c_pnx_driver = {
 	.driver = {
 		.name = "pnx-i2c",
 		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(i2c_pnx_of_match),
 	},
 	.probe = i2c_pnx_probe,
 	.remove = __devexit_p(i2c_pnx_remove),
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 7b397c6..31c47e1 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -227,6 +227,72 @@
 	return 0;
 }
 
+static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
+						    struct pmac_i2c_bus *bus)
+{
+	struct i2c_client *newdev;
+	struct device_node *node;
+
+	for_each_child_of_node(adap->dev.of_node, node) {
+		struct i2c_board_info info = {};
+		struct dev_archdata dev_ad = {};
+		const __be32 *reg;
+		char tmp[16];
+		u32 addr;
+		int len;
+
+		/* Get address & channel */
+		reg = of_get_property(node, "reg", &len);
+		if (!reg || (len < sizeof(int))) {
+			dev_err(&adap->dev, "i2c-powermac: invalid reg on %s\n",
+				node->full_name);
+			continue;
+		}
+		addr = be32_to_cpup(reg);
+
+		/* Multibus setup, check channel */
+		if (!pmac_i2c_match_adapter(node, adap))
+			continue;
+
+		dev_dbg(&adap->dev, "i2c-powermac: register %s\n",
+			node->full_name);
+
+		/* Make up a modalias. Note: we to _NOT_ want the standard
+		 * i2c drivers to match with any of our powermac stuff
+		 * unless they have been specifically modified to handle
+		 * it on a case by case basis. For example, for thermal
+		 * control, things like lm75 etc... shall match with their
+		 * corresponding windfarm drivers, _NOT_ the generic ones,
+		 * so we force a prefix of AAPL, onto the modalias to
+		 * make that happen
+		 */
+		if (of_modalias_node(node, tmp, sizeof(tmp)) < 0) {
+			dev_err(&adap->dev, "i2c-powermac: modalias failure"
+				" on %s\n", node->full_name);
+			continue;
+		}
+		snprintf(info.type, sizeof(info.type), "MAC,%s", tmp);
+
+		/* Fill out the rest of the info structure */
+		info.addr = (addr & 0xff) >> 1;
+		info.irq = irq_of_parse_and_map(node, 0);
+		info.of_node = of_node_get(node);
+		info.archdata = &dev_ad;
+
+		newdev = i2c_new_device(adap, &info);
+		if (!newdev) {
+			dev_err(&adap->dev, "i2c-powermac: Failure to register"
+				" %s\n", node->full_name);
+			of_node_put(node);
+			/* We do not dispose of the interrupt mapping on
+			 * purpose. It's not necessary (interrupt cannot be
+			 * re-used) and somebody else might have grabbed it
+			 * via direct DT lookup so let's not bother
+			 */
+			continue;
+		}
+	}
+}
 
 static int __devinit i2c_powermac_probe(struct platform_device *dev)
 {
@@ -272,6 +338,7 @@
 	adapter->algo = &i2c_powermac_algorithm;
 	i2c_set_adapdata(adapter, bus);
 	adapter->dev.parent = &dev->dev;
+	adapter->dev.of_node = dev->dev.of_node;
 	rc = i2c_add_adapter(adapter);
 	if (rc) {
 		printk(KERN_ERR "i2c-powermac: Adapter %s registration "
@@ -281,33 +348,10 @@
 
 	printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
 
-	if (!strncmp(basename, "uni-n", 5)) {
-		struct device_node *np;
-		const u32 *prop;
-		struct i2c_board_info info;
-
-		/* Instantiate I2C motion sensor if present */
-		np = of_find_node_by_name(NULL, "accelerometer");
-		if (np && of_device_is_compatible(np, "AAPL,accelerometer_1") &&
-		    (prop = of_get_property(np, "reg", NULL))) {
-			int i2c_bus;
-			const char *tmp_bus;
-
-			/* look for bus either using "reg" or by path */
-			tmp_bus = strstr(np->full_name, "/i2c-bus@");
-			if (tmp_bus)
-				i2c_bus = *(tmp_bus + 9) - '0';
-			else
-				i2c_bus = ((*prop) >> 8) & 0x0f;
-
-			if (pmac_i2c_get_channel(bus) == i2c_bus) {
-				memset(&info, 0, sizeof(struct i2c_board_info));
-				info.addr = ((*prop) & 0xff) >> 1;
-				strlcpy(info.type, "ams", I2C_NAME_SIZE);
-				i2c_new_device(adapter, &info);
-			}
-		}
-	}
+	/* Cannot use of_i2c_register_devices() due to Apple device-tree
+	 * funkyness
+	 */
+	i2c_powermac_register_devices(adapter, bus);
 
 	return rc;
 }
diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c
index c64ba73..b76a29d 100644
--- a/drivers/i2c/busses/i2c-s6000.c
+++ b/drivers/i2c/busses/i2c-s6000.c
@@ -3,7 +3,7 @@
  *
  * Description: Driver for S6000 Family I2C Interface
  * Copyright (c) 2008 emlix GmbH
- * Author:	Oskar Schirmer <os@emlix.com>
+ * Author:	Oskar Schirmer <oskar@scara.com>
  *
  * Partially based on i2c-bfin-twi.c driver by <sonic.zhang@analog.com>
  * Copyright (c) 2005-2007 Analog Devices, Inc.
diff --git a/drivers/i2c/busses/i2c-s6000.h b/drivers/i2c/busses/i2c-s6000.h
index ff23b81..4936f9f 100644
--- a/drivers/i2c/busses/i2c-s6000.h
+++ b/drivers/i2c/busses/i2c-s6000.h
@@ -6,7 +6,7 @@
  * for more details.
  *
  * Copyright (C) 2008 Emlix GmbH <info@emlix.com>
- * Author:	Oskar Schirmer <os@emlix.com>
+ * Author:	Oskar Schirmer <oskar@scara.com>
  */
 
 #ifndef __DRIVERS_I2C_BUSSES_I2C_S6000_H
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
new file mode 100644
index 0000000..56eecef
--- /dev/null
+++ b/drivers/iio/Kconfig
@@ -0,0 +1,54 @@
+#
+# Industrial I/O subsytem configuration
+#
+
+menuconfig IIO
+	tristate "Industrial I/O support"
+	depends on GENERIC_HARDIRQS
+	help
+	  The industrial I/O subsystem provides a unified framework for
+	  drivers for many different types of embedded sensors using a
+	  number of different physical interfaces (i2c, spi, etc). See
+	  Documentation/iio for more information.
+
+if IIO
+
+config IIO_BUFFER
+	bool "Enable buffer support within IIO"
+	help
+	  Provide core support for various buffer based data
+	  acquisition methods.
+
+if IIO_BUFFER
+
+config IIO_KFIFO_BUF
+	select IIO_TRIGGER
+	tristate "Industrial I/O buffering based on kfifo"
+	help
+	  A simple fifo based on kfifo.  Use this if you want a fifo
+	  rather than a ring buffer. Note that this currently provides
+	  no buffer events so it is up to userspace to work out how
+	  often to read from the buffer.
+
+endif # IIO_BUFFER
+
+config IIO_TRIGGER
+	boolean "Enable triggered sampling support"
+	help
+	  Provides IIO core support for triggers.  Currently these
+	  are used to initialize capture of samples to push into
+	  ring buffers.  The triggers are effectively a 'capture
+	  data now' interrupt.
+
+config IIO_CONSUMERS_PER_TRIGGER
+       int "Maximum number of consumers per trigger"
+       depends on IIO_TRIGGER
+       default "2"
+       help
+	This value controls the maximum number of consumers that a
+	given trigger may handle. Default is 2.
+
+source "drivers/iio/adc/Kconfig"
+source "drivers/iio/amplifiers/Kconfig"
+
+endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
new file mode 100644
index 0000000..e425afd
--- /dev/null
+++ b/drivers/iio/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the industrial I/O core.
+#
+
+obj-$(CONFIG_IIO) += industrialio.o
+industrialio-y := industrialio-core.o industrialio-event.o inkern.o
+industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
+industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
+
+obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
+
+obj-y += adc/
+obj-y += amplifiers/
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
new file mode 100644
index 0000000..9a0df81
--- /dev/null
+++ b/drivers/iio/adc/Kconfig
@@ -0,0 +1,16 @@
+#
+# ADC drivers
+#
+menu "Analog to digital converters"
+
+config AT91_ADC
+	tristate "Atmel AT91 ADC"
+	depends on ARCH_AT91
+	select IIO_BUFFER
+	select IIO_KFIFO_BUF
+	select IIO_TRIGGER
+	select SYSFS
+	help
+	  Say yes here to build support for Atmel AT91 ADC.
+
+endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
new file mode 100644
index 0000000..175c8d4
--- /dev/null
+++ b/drivers/iio/adc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for IIO ADC drivers
+#
+
+obj-$(CONFIG_AT91_ADC) += at91_adc.o
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
new file mode 100644
index 0000000..f18a95d
--- /dev/null
+++ b/drivers/iio/adc/at91_adc.c
@@ -0,0 +1,802 @@
+/*
+ * Driver for the ADC present in the Atmel AT91 evaluation boards.
+ *
+ * Copyright 2011 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <linux/platform_data/at91_adc.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+
+#include <mach/at91_adc.h>
+
+#define AT91_ADC_CHAN(st, ch) \
+	(st->registers->channel_base + (ch * 4))
+#define at91_adc_readl(st, reg) \
+	(readl_relaxed(st->reg_base + reg))
+#define at91_adc_writel(st, reg, val) \
+	(writel_relaxed(val, st->reg_base + reg))
+
+struct at91_adc_state {
+	struct clk		*adc_clk;
+	u16			*buffer;
+	unsigned long		channels_mask;
+	struct clk		*clk;
+	bool			done;
+	int			irq;
+	bool			irq_enabled;
+	u16			last_value;
+	struct mutex		lock;
+	u8			num_channels;
+	void __iomem		*reg_base;
+	struct at91_adc_reg_desc *registers;
+	u8			startup_time;
+	struct iio_trigger	**trig;
+	struct at91_adc_trigger	*trigger_list;
+	u32			trigger_number;
+	bool			use_external;
+	u32			vref_mv;
+	wait_queue_head_t	wq_data_avail;
+};
+
+static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *idev = pf->indio_dev;
+	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_buffer *buffer = idev->buffer;
+	int i, j = 0;
+
+	for (i = 0; i < idev->masklength; i++) {
+		if (!test_bit(i, idev->active_scan_mask))
+			continue;
+		st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i));
+		j++;
+	}
+
+	if (idev->scan_timestamp) {
+		s64 *timestamp = (s64 *)((u8 *)st->buffer +
+					ALIGN(j, sizeof(s64)));
+		*timestamp = pf->timestamp;
+	}
+
+	buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp);
+
+	iio_trigger_notify_done(idev->trig);
+	st->irq_enabled = true;
+
+	/* Needed to ACK the DRDY interruption */
+	at91_adc_readl(st, AT91_ADC_LCDR);
+
+	enable_irq(st->irq);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+{
+	struct iio_dev *idev = private;
+	struct at91_adc_state *st = iio_priv(idev);
+	u32 status = at91_adc_readl(st, st->registers->status_register);
+
+	if (!(status & st->registers->drdy_mask))
+		return IRQ_HANDLED;
+
+	if (iio_buffer_enabled(idev)) {
+		disable_irq_nosync(irq);
+		st->irq_enabled = false;
+		iio_trigger_poll(idev->trig, iio_get_time_ns());
+	} else {
+		st->last_value = at91_adc_readl(st, AT91_ADC_LCDR);
+		st->done = true;
+		wake_up_interruptible(&st->wq_data_avail);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int at91_adc_channel_init(struct iio_dev *idev)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_chan_spec *chan_array, *timestamp;
+	int bit, idx = 0;
+
+	idev->num_channels = bitmap_weight(&st->channels_mask,
+					   st->num_channels) + 1;
+
+	chan_array = devm_kzalloc(&idev->dev,
+				  ((idev->num_channels + 1) *
+					sizeof(struct iio_chan_spec)),
+				  GFP_KERNEL);
+
+	if (!chan_array)
+		return -ENOMEM;
+
+	for_each_set_bit(bit, &st->channels_mask, st->num_channels) {
+		struct iio_chan_spec *chan = chan_array + idx;
+
+		chan->type = IIO_VOLTAGE;
+		chan->indexed = 1;
+		chan->channel = bit;
+		chan->scan_index = idx;
+		chan->scan_type.sign = 'u';
+		chan->scan_type.realbits = 10;
+		chan->scan_type.storagebits = 16;
+		chan->info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+			IIO_CHAN_INFO_RAW_SEPARATE_BIT;
+		idx++;
+	}
+	timestamp = chan_array + idx;
+
+	timestamp->type = IIO_TIMESTAMP;
+	timestamp->channel = -1;
+	timestamp->scan_index = idx;
+	timestamp->scan_type.sign = 's';
+	timestamp->scan_type.realbits = 64;
+	timestamp->scan_type.storagebits = 64;
+
+	idev->channels = chan_array;
+	return idev->num_channels;
+}
+
+static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
+					     struct at91_adc_trigger *triggers,
+					     const char *trigger_name)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	u8 value = 0;
+	int i;
+
+	for (i = 0; i < st->trigger_number; i++) {
+		char *name = kasprintf(GFP_KERNEL,
+				"%s-dev%d-%s",
+				idev->name,
+				idev->id,
+				triggers[i].name);
+		if (!name)
+			return -ENOMEM;
+
+		if (strcmp(trigger_name, name) == 0) {
+			value = triggers[i].value;
+			kfree(name);
+			break;
+		}
+
+		kfree(name);
+	}
+
+	return value;
+}
+
+static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *idev = trig->private_data;
+	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_buffer *buffer = idev->buffer;
+	struct at91_adc_reg_desc *reg = st->registers;
+	u32 status = at91_adc_readl(st, reg->trigger_register);
+	u8 value;
+	u8 bit;
+
+	value = at91_adc_get_trigger_value_by_name(idev,
+						   st->trigger_list,
+						   idev->trig->name);
+	if (value == 0)
+		return -EINVAL;
+
+	if (state) {
+		st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL);
+		if (st->buffer == NULL)
+			return -ENOMEM;
+
+		at91_adc_writel(st, reg->trigger_register,
+				status | value);
+
+		for_each_set_bit(bit, buffer->scan_mask,
+				 st->num_channels) {
+			struct iio_chan_spec const *chan = idev->channels + bit;
+			at91_adc_writel(st, AT91_ADC_CHER,
+					AT91_ADC_CH(chan->channel));
+		}
+
+		at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask);
+
+	} else {
+		at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask);
+
+		at91_adc_writel(st, reg->trigger_register,
+				status & ~value);
+
+		for_each_set_bit(bit, buffer->scan_mask,
+				 st->num_channels) {
+			struct iio_chan_spec const *chan = idev->channels + bit;
+			at91_adc_writel(st, AT91_ADC_CHDR,
+					AT91_ADC_CH(chan->channel));
+		}
+		kfree(st->buffer);
+	}
+
+	return 0;
+}
+
+static const struct iio_trigger_ops at91_adc_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &at91_adc_configure_trigger,
+};
+
+static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
+						     struct at91_adc_trigger *trigger)
+{
+	struct iio_trigger *trig;
+	int ret;
+
+	trig = iio_trigger_alloc("%s-dev%d-%s", idev->name,
+				 idev->id, trigger->name);
+	if (trig == NULL)
+		return NULL;
+
+	trig->dev.parent = idev->dev.parent;
+	trig->private_data = idev;
+	trig->ops = &at91_adc_trigger_ops;
+
+	ret = iio_trigger_register(trig);
+	if (ret)
+		return NULL;
+
+	return trig;
+}
+
+static int at91_adc_trigger_init(struct iio_dev *idev)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	int i, ret;
+
+	st->trig = devm_kzalloc(&idev->dev,
+				st->trigger_number * sizeof(st->trig),
+				GFP_KERNEL);
+
+	if (st->trig == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	for (i = 0; i < st->trigger_number; i++) {
+		if (st->trigger_list[i].is_external && !(st->use_external))
+			continue;
+
+		st->trig[i] = at91_adc_allocate_trigger(idev,
+							st->trigger_list + i);
+		if (st->trig[i] == NULL) {
+			dev_err(&idev->dev,
+				"Could not allocate trigger %d\n", i);
+			ret = -ENOMEM;
+			goto error_trigger;
+		}
+	}
+
+	return 0;
+
+error_trigger:
+	for (i--; i >= 0; i--) {
+		iio_trigger_unregister(st->trig[i]);
+		iio_trigger_free(st->trig[i]);
+	}
+error_ret:
+	return ret;
+}
+
+static void at91_adc_trigger_remove(struct iio_dev *idev)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	int i;
+
+	for (i = 0; i < st->trigger_number; i++) {
+		iio_trigger_unregister(st->trig[i]);
+		iio_trigger_free(st->trig[i]);
+	}
+}
+
+static const struct iio_buffer_setup_ops at91_adc_buffer_ops = {
+	.preenable = &iio_sw_buffer_preenable,
+	.postenable = &iio_triggered_buffer_postenable,
+	.predisable = &iio_triggered_buffer_predisable,
+};
+
+static int at91_adc_buffer_init(struct iio_dev *idev)
+{
+	int ret;
+
+	idev->buffer = iio_kfifo_allocate(idev);
+	if (!idev->buffer) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	idev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
+					    &at91_adc_trigger_handler,
+					    IRQF_ONESHOT,
+					    idev,
+					    "%s-consumer%d",
+					    idev->name,
+					    idev->id);
+	if (idev->pollfunc == NULL) {
+		ret = -ENOMEM;
+		goto error_pollfunc;
+	}
+
+	idev->setup_ops = &at91_adc_buffer_ops;
+	idev->modes |= INDIO_BUFFER_TRIGGERED;
+
+	ret = iio_buffer_register(idev,
+				  idev->channels,
+				  idev->num_channels);
+	if (ret)
+		goto error_register;
+
+	return 0;
+
+error_register:
+	iio_dealloc_pollfunc(idev->pollfunc);
+error_pollfunc:
+	iio_kfifo_free(idev->buffer);
+error_ret:
+	return ret;
+}
+
+static void at91_adc_buffer_remove(struct iio_dev *idev)
+{
+	iio_buffer_unregister(idev);
+	iio_dealloc_pollfunc(idev->pollfunc);
+	iio_kfifo_free(idev->buffer);
+}
+
+static int at91_adc_read_raw(struct iio_dev *idev,
+			     struct iio_chan_spec const *chan,
+			     int *val, int *val2, long mask)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&st->lock);
+
+		at91_adc_writel(st, AT91_ADC_CHER,
+				AT91_ADC_CH(chan->channel));
+		at91_adc_writel(st, AT91_ADC_IER, st->registers->drdy_mask);
+		at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START);
+
+		ret = wait_event_interruptible_timeout(st->wq_data_avail,
+						       st->done,
+						       msecs_to_jiffies(1000));
+		if (ret == 0)
+			return -ETIMEDOUT;
+		else if (ret < 0)
+			return ret;
+
+		*val = st->last_value;
+
+		at91_adc_writel(st, AT91_ADC_CHDR,
+				AT91_ADC_CH(chan->channel));
+		at91_adc_writel(st, AT91_ADC_IDR, st->registers->drdy_mask);
+
+		st->last_value = 0;
+		st->done = false;
+		mutex_unlock(&st->lock);
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		*val = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val2 = 0;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int at91_adc_probe_dt(struct at91_adc_state *st,
+			     struct platform_device *pdev)
+{
+	struct iio_dev *idev = iio_priv_to_dev(st);
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *trig_node;
+	int i = 0, ret;
+	u32 prop;
+
+	if (!node)
+		return -EINVAL;
+
+	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
+
+	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
+		dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->channels_mask = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
+		dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->num_channels = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
+		dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->startup_time = prop;
+
+
+	if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
+		dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->vref_mv = prop;
+
+	st->registers = devm_kzalloc(&idev->dev,
+				     sizeof(struct at91_adc_reg_desc),
+				     GFP_KERNEL);
+	if (!st->registers) {
+		dev_err(&idev->dev, "Could not allocate register memory.\n");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
+		dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->channel_base = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
+		dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->drdy_mask = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
+		dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->status_register = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
+		dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->trigger_register = prop;
+
+	st->trigger_number = of_get_child_count(node);
+	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
+					sizeof(struct at91_adc_trigger),
+					GFP_KERNEL);
+	if (!st->trigger_list) {
+		dev_err(&idev->dev, "Could not allocate trigger list memory.\n");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	for_each_child_of_node(node, trig_node) {
+		struct at91_adc_trigger *trig = st->trigger_list + i;
+		const char *name;
+
+		if (of_property_read_string(trig_node, "trigger-name", &name)) {
+			dev_err(&idev->dev, "Missing trigger-name property in the DT.\n");
+			ret = -EINVAL;
+			goto error_ret;
+		}
+	        trig->name = name;
+
+		if (of_property_read_u32(trig_node, "trigger-value", &prop)) {
+			dev_err(&idev->dev, "Missing trigger-value property in the DT.\n");
+			ret = -EINVAL;
+			goto error_ret;
+		}
+	        trig->value = prop;
+		trig->is_external = of_property_read_bool(trig_node, "trigger-external");
+		i++;
+	}
+
+	return 0;
+
+error_ret:
+	return ret;
+}
+
+static int at91_adc_probe_pdata(struct at91_adc_state *st,
+				struct platform_device *pdev)
+{
+	struct at91_adc_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata)
+		return -EINVAL;
+
+	st->use_external = pdata->use_external_triggers;
+	st->vref_mv = pdata->vref;
+	st->channels_mask = pdata->channels_used;
+	st->num_channels = pdata->num_channels;
+	st->startup_time = pdata->startup_time;
+	st->trigger_number = pdata->trigger_number;
+	st->trigger_list = pdata->trigger_list;
+	st->registers = pdata->registers;
+
+	return 0;
+}
+
+static const struct iio_info at91_adc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &at91_adc_read_raw,
+};
+
+static int __devinit at91_adc_probe(struct platform_device *pdev)
+{
+	unsigned int prsc, mstrclk, ticks, adc_clk;
+	int ret;
+	struct iio_dev *idev;
+	struct at91_adc_state *st;
+	struct resource *res;
+
+	idev = iio_device_alloc(sizeof(struct at91_adc_state));
+	if (idev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	st = iio_priv(idev);
+
+	if (pdev->dev.of_node)
+		ret = at91_adc_probe_dt(st, pdev);
+	else
+		ret = at91_adc_probe_pdata(st, pdev);
+
+	if (ret) {
+		dev_err(&pdev->dev, "No platform data available.\n");
+		ret = -EINVAL;
+		goto error_free_device;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "No resource defined\n");
+		ret = -ENXIO;
+		goto error_ret;
+	}
+
+	platform_set_drvdata(pdev, idev);
+
+	idev->dev.parent = &pdev->dev;
+	idev->name = dev_name(&pdev->dev);
+	idev->modes = INDIO_DIRECT_MODE;
+	idev->info = &at91_adc_info;
+
+	st->irq = platform_get_irq(pdev, 0);
+	if (st->irq < 0) {
+		dev_err(&pdev->dev, "No IRQ ID is designated\n");
+		ret = -ENODEV;
+		goto error_free_device;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res),
+				"AT91 adc registers")) {
+		dev_err(&pdev->dev, "Resources are unavailable.\n");
+		ret = -EBUSY;
+		goto error_free_device;
+	}
+
+	st->reg_base = ioremap(res->start, resource_size(res));
+	if (!st->reg_base) {
+		dev_err(&pdev->dev, "Failed to map registers.\n");
+		ret = -ENOMEM;
+		goto error_release_mem;
+	}
+
+	/*
+	 * Disable all IRQs before setting up the handler
+	 */
+	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
+	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
+	ret = request_irq(st->irq,
+			  at91_adc_eoc_trigger,
+			  0,
+			  pdev->dev.driver->name,
+			  idev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
+		goto error_unmap_reg;
+	}
+
+	st->clk = clk_get(&pdev->dev, "adc_clk");
+	if (IS_ERR(st->clk)) {
+		dev_err(&pdev->dev, "Failed to get the clock.\n");
+		ret = PTR_ERR(st->clk);
+		goto error_free_irq;
+	}
+
+	ret = clk_prepare(st->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not prepare the clock.\n");
+		goto error_free_clk;
+	}
+
+	ret = clk_enable(st->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not enable the clock.\n");
+		goto error_unprepare_clk;
+	}
+
+	st->adc_clk = clk_get(&pdev->dev, "adc_op_clk");
+	if (IS_ERR(st->adc_clk)) {
+		dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
+		ret = PTR_ERR(st->clk);
+		goto error_disable_clk;
+	}
+
+	ret = clk_prepare(st->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not prepare the ADC clock.\n");
+		goto error_free_adc_clk;
+	}
+
+	ret = clk_enable(st->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not enable the ADC clock.\n");
+		goto error_unprepare_adc_clk;
+	}
+
+	/*
+	 * Prescaler rate computation using the formula from the Atmel's
+	 * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being
+	 * specified by the electrical characteristics of the board.
+	 */
+	mstrclk = clk_get_rate(st->clk);
+	adc_clk = clk_get_rate(st->adc_clk);
+	prsc = (mstrclk / (2 * adc_clk)) - 1;
+
+	if (!st->startup_time) {
+		dev_err(&pdev->dev, "No startup time available.\n");
+		ret = -EINVAL;
+		goto error_disable_adc_clk;
+	}
+
+	/*
+	 * Number of ticks needed to cover the startup time of the ADC as
+	 * defined in the electrical characteristics of the board, divided by 8.
+	 * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
+	 */
+	ticks = round_up((st->startup_time * adc_clk /
+			  1000000) - 1, 8) / 8;
+	at91_adc_writel(st, AT91_ADC_MR,
+			(AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) |
+			(AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP));
+
+	/* Setup the ADC channels available on the board */
+	ret = at91_adc_channel_init(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't initialize the channels.\n");
+		goto error_disable_adc_clk;
+	}
+
+	init_waitqueue_head(&st->wq_data_avail);
+	mutex_init(&st->lock);
+
+	ret = at91_adc_buffer_init(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+		goto error_disable_adc_clk;
+	}
+
+	ret = at91_adc_trigger_init(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+		goto error_unregister_buffer;
+	}
+
+	ret = iio_device_register(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't register the device.\n");
+		goto error_remove_triggers;
+	}
+
+	return 0;
+
+error_remove_triggers:
+	at91_adc_trigger_remove(idev);
+error_unregister_buffer:
+	at91_adc_buffer_remove(idev);
+error_disable_adc_clk:
+	clk_disable(st->adc_clk);
+error_unprepare_adc_clk:
+	clk_unprepare(st->adc_clk);
+error_free_adc_clk:
+	clk_put(st->adc_clk);
+error_disable_clk:
+	clk_disable(st->clk);
+error_unprepare_clk:
+	clk_unprepare(st->clk);
+error_free_clk:
+	clk_put(st->clk);
+error_free_irq:
+	free_irq(st->irq, idev);
+error_unmap_reg:
+	iounmap(st->reg_base);
+error_release_mem:
+	release_mem_region(res->start, resource_size(res));
+error_free_device:
+	iio_device_free(idev);
+error_ret:
+	return ret;
+}
+
+static int __devexit at91_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *idev = platform_get_drvdata(pdev);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct at91_adc_state *st = iio_priv(idev);
+
+	iio_device_unregister(idev);
+	at91_adc_trigger_remove(idev);
+	at91_adc_buffer_remove(idev);
+	clk_disable_unprepare(st->adc_clk);
+	clk_put(st->adc_clk);
+	clk_disable(st->clk);
+	clk_unprepare(st->clk);
+	clk_put(st->clk);
+	free_irq(st->irq, idev);
+	iounmap(st->reg_base);
+	release_mem_region(res->start, resource_size(res));
+	iio_device_free(idev);
+
+	return 0;
+}
+
+static const struct of_device_id at91_adc_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9260-adc" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
+
+static struct platform_driver at91_adc_driver = {
+	.probe = at91_adc_probe,
+	.remove = __devexit_p(at91_adc_remove),
+	.driver = {
+		   .name = "at91_adc",
+		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
+	},
+};
+
+module_platform_driver(at91_adc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atmel AT91 ADC Driver");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
diff --git a/drivers/iio/amplifiers/Kconfig b/drivers/iio/amplifiers/Kconfig
new file mode 100644
index 0000000..05d707e
--- /dev/null
+++ b/drivers/iio/amplifiers/Kconfig
@@ -0,0 +1,17 @@
+#
+# Gain Amplifiers, etc.
+#
+menu "Amplifiers"
+
+config AD8366
+	tristate "Analog Devices AD8366 VGA"
+	depends on SPI
+	select BITREVERSE
+	help
+	  Say yes here to build support for Analog Devices AD8366
+	  SPI Dual-Digital Variable Gain Amplifier (VGA).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad8366.
+
+endmenu
diff --git a/drivers/iio/amplifiers/Makefile b/drivers/iio/amplifiers/Makefile
new file mode 100644
index 0000000..a6ca366
--- /dev/null
+++ b/drivers/iio/amplifiers/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile iio/amplifiers
+#
+
+obj-$(CONFIG_AD8366) += ad8366.o
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
new file mode 100644
index 0000000..d8281cd
--- /dev/null
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -0,0 +1,222 @@
+/*
+ * AD8366 SPI Dual-Digital Variable Gain Amplifier (VGA)
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitrev.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+struct ad8366_state {
+	struct spi_device	*spi;
+	struct regulator	*reg;
+	unsigned char		ch[2];
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	unsigned char		data[2] ____cacheline_aligned;
+};
+
+static int ad8366_write(struct iio_dev *indio_dev,
+			unsigned char ch_a, char unsigned ch_b)
+{
+	struct ad8366_state *st = iio_priv(indio_dev);
+	int ret;
+
+	ch_a = bitrev8(ch_a & 0x3F);
+	ch_b = bitrev8(ch_b & 0x3F);
+
+	st->data[0] = ch_b >> 4;
+	st->data[1] = (ch_b << 4) | (ch_a >> 2);
+
+	ret = spi_write(st->spi, st->data, ARRAY_SIZE(st->data));
+	if (ret < 0)
+		dev_err(&indio_dev->dev, "write failed (%d)", ret);
+
+	return ret;
+}
+
+static int ad8366_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad8366_state *st = iio_priv(indio_dev);
+	int ret;
+	unsigned code;
+
+	mutex_lock(&indio_dev->mlock);
+	switch (m) {
+	case IIO_CHAN_INFO_HARDWAREGAIN:
+		code = st->ch[chan->channel];
+
+		/* Values in dB */
+		code = code * 253 + 4500;
+		*val = code / 1000;
+		*val2 = (code % 1000) * 1000;
+
+		ret = IIO_VAL_INT_PLUS_MICRO_DB;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+};
+
+static int ad8366_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val,
+			    int val2,
+			    long mask)
+{
+	struct ad8366_state *st = iio_priv(indio_dev);
+	unsigned code;
+	int ret;
+
+	if (val < 0 || val2 < 0)
+		return -EINVAL;
+
+	/* Values in dB */
+	code = (((u8)val * 1000) + ((u32)val2 / 1000));
+
+	if (code > 20500 || code < 4500)
+		return -EINVAL;
+
+	code = (code - 4500) / 253;
+
+	mutex_lock(&indio_dev->mlock);
+	switch (mask) {
+	case IIO_CHAN_INFO_HARDWAREGAIN:
+		st->ch[chan->channel] = code;
+		ret = ad8366_write(indio_dev, st->ch[0], st->ch[1]);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static const struct iio_info ad8366_info = {
+	.read_raw = &ad8366_read_raw,
+	.write_raw = &ad8366_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+#define AD8366_CHAN(_channel) {				\
+	.type = IIO_VOLTAGE,				\
+	.output = 1,					\
+	.indexed = 1,					\
+	.channel = _channel,				\
+	.info_mask = IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT,\
+}
+
+static const struct iio_chan_spec ad8366_channels[] = {
+	AD8366_CHAN(0),
+	AD8366_CHAN(1),
+};
+
+static int __devinit ad8366_probe(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev;
+	struct ad8366_state *st;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+
+	st->reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(st->reg)) {
+		ret = regulator_enable(st->reg);
+		if (ret)
+			goto error_put_reg;
+	}
+
+	spi_set_drvdata(spi, indio_dev);
+	st->spi = spi;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad8366_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = ad8366_channels;
+	indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg;
+
+	ad8366_write(indio_dev, 0 , 0);
+
+	return 0;
+
+error_disable_reg:
+	if (!IS_ERR(st->reg))
+		regulator_disable(st->reg);
+error_put_reg:
+	if (!IS_ERR(st->reg))
+		regulator_put(st->reg);
+
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad8366_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad8366_state *st = iio_priv(indio_dev);
+	struct regulator *reg = st->reg;
+
+	iio_device_unregister(indio_dev);
+
+	if (!IS_ERR(reg)) {
+		regulator_disable(reg);
+		regulator_put(reg);
+	}
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad8366_id[] = {
+	{"ad8366", 0},
+	{}
+};
+
+static struct spi_driver ad8366_driver = {
+	.driver = {
+		.name	= KBUILD_MODNAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad8366_probe,
+	.remove		= __devexit_p(ad8366_remove),
+	.id_table	= ad8366_id,
+};
+
+module_spi_driver(ad8366_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD8366 VGA");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
new file mode 100644
index 0000000..f652e6a
--- /dev/null
+++ b/drivers/iio/iio_core.h
@@ -0,0 +1,62 @@
+/* The industrial I/O core function defs.
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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.
+ *
+ * These definitions are meant for use only within the IIO core, not individual
+ * drivers.
+ */
+
+#ifndef _IIO_CORE_H_
+#define _IIO_CORE_H_
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+struct iio_chan_spec;
+struct iio_dev;
+
+
+int __iio_add_chan_devattr(const char *postfix,
+			   struct iio_chan_spec const *chan,
+			   ssize_t (*func)(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf),
+			   ssize_t (*writefunc)(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf,
+						size_t len),
+			   u64 mask,
+			   bool generic,
+			   struct device *dev,
+			   struct list_head *attr_list);
+
+/* Event interface flags */
+#define IIO_BUSY_BIT_POS 1
+
+#ifdef CONFIG_IIO_BUFFER
+struct poll_table_struct;
+
+unsigned int iio_buffer_poll(struct file *filp,
+			     struct poll_table_struct *wait);
+ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
+				      size_t n, loff_t *f_ps);
+
+
+#define iio_buffer_poll_addr (&iio_buffer_poll)
+#define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer)
+
+#else
+
+#define iio_buffer_poll_addr NULL
+#define iio_buffer_read_first_n_outer_addr NULL
+
+#endif
+
+int iio_device_register_eventset(struct iio_dev *indio_dev);
+void iio_device_unregister_eventset(struct iio_dev *indio_dev);
+int iio_event_getfd(struct iio_dev *indio_dev);
+
+#endif
diff --git a/drivers/staging/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h
similarity index 100%
rename from drivers/staging/iio/iio_core_trigger.h
rename to drivers/iio/iio_core_trigger.h
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
new file mode 100644
index 0000000..ac185b8
--- /dev/null
+++ b/drivers/iio/industrialio-buffer.c
@@ -0,0 +1,755 @@
+/* The industrial I/O core
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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.
+ *
+ * Handling of buffer allocation / resizing.
+ *
+ *
+ * Things to look at here.
+ * - Better memory allocation techniques?
+ * - Alternative access techniques?
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+
+#include <linux/iio/iio.h>
+#include "iio_core.h"
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+
+static const char * const iio_endian_prefix[] = {
+	[IIO_BE] = "be",
+	[IIO_LE] = "le",
+};
+
+/**
+ * iio_buffer_read_first_n_outer() - chrdev read for buffer access
+ *
+ * This function relies on all buffer implementations having an
+ * iio_buffer as their first element.
+ **/
+ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
+				      size_t n, loff_t *f_ps)
+{
+	struct iio_dev *indio_dev = filp->private_data;
+	struct iio_buffer *rb = indio_dev->buffer;
+
+	if (!rb || !rb->access->read_first_n)
+		return -EINVAL;
+	return rb->access->read_first_n(rb, n, buf);
+}
+
+/**
+ * iio_buffer_poll() - poll the buffer to find out if it has data
+ */
+unsigned int iio_buffer_poll(struct file *filp,
+			     struct poll_table_struct *wait)
+{
+	struct iio_dev *indio_dev = filp->private_data;
+	struct iio_buffer *rb = indio_dev->buffer;
+
+	poll_wait(filp, &rb->pollq, wait);
+	if (rb->stufftoread)
+		return POLLIN | POLLRDNORM;
+	/* need a way of knowing if there may be enough data... */
+	return 0;
+}
+
+void iio_buffer_init(struct iio_buffer *buffer)
+{
+	INIT_LIST_HEAD(&buffer->demux_list);
+	init_waitqueue_head(&buffer->pollq);
+}
+EXPORT_SYMBOL(iio_buffer_init);
+
+static ssize_t iio_show_scan_index(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	return sprintf(buf, "%u\n", to_iio_dev_attr(attr)->c->scan_index);
+}
+
+static ssize_t iio_show_fixed_type(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	u8 type = this_attr->c->scan_type.endianness;
+
+	if (type == IIO_CPU) {
+#ifdef __LITTLE_ENDIAN
+		type = IIO_LE;
+#else
+		type = IIO_BE;
+#endif
+	}
+	return sprintf(buf, "%s:%c%d/%d>>%u\n",
+		       iio_endian_prefix[type],
+		       this_attr->c->scan_type.sign,
+		       this_attr->c->scan_type.realbits,
+		       this_attr->c->scan_type.storagebits,
+		       this_attr->c->scan_type.shift);
+}
+
+static ssize_t iio_scan_el_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	int ret;
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+
+	ret = test_bit(to_iio_dev_attr(attr)->address,
+		       indio_dev->buffer->scan_mask);
+
+	return sprintf(buf, "%d\n", ret);
+}
+
+static int iio_scan_mask_clear(struct iio_buffer *buffer, int bit)
+{
+	clear_bit(bit, buffer->scan_mask);
+	return 0;
+}
+
+static ssize_t iio_scan_el_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf,
+				 size_t len)
+{
+	int ret;
+	bool state;
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_buffer *buffer = indio_dev->buffer;
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+	ret = strtobool(buf, &state);
+	if (ret < 0)
+		return ret;
+	mutex_lock(&indio_dev->mlock);
+	if (iio_buffer_enabled(indio_dev)) {
+		ret = -EBUSY;
+		goto error_ret;
+	}
+	ret = iio_scan_mask_query(indio_dev, buffer, this_attr->address);
+	if (ret < 0)
+		goto error_ret;
+	if (!state && ret) {
+		ret = iio_scan_mask_clear(buffer, this_attr->address);
+		if (ret)
+			goto error_ret;
+	} else if (state && !ret) {
+		ret = iio_scan_mask_set(indio_dev, buffer, this_attr->address);
+		if (ret)
+			goto error_ret;
+	}
+
+error_ret:
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret < 0 ? ret : len;
+
+}
+
+static ssize_t iio_scan_el_ts_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	return sprintf(buf, "%d\n", indio_dev->buffer->scan_timestamp);
+}
+
+static ssize_t iio_scan_el_ts_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf,
+				    size_t len)
+{
+	int ret;
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	bool state;
+
+	ret = strtobool(buf, &state);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+	if (iio_buffer_enabled(indio_dev)) {
+		ret = -EBUSY;
+		goto error_ret;
+	}
+	indio_dev->buffer->scan_timestamp = state;
+	indio_dev->scan_timestamp = state;
+error_ret:
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
+					const struct iio_chan_spec *chan)
+{
+	int ret, attrcount = 0;
+	struct iio_buffer *buffer = indio_dev->buffer;
+
+	ret = __iio_add_chan_devattr("index",
+				     chan,
+				     &iio_show_scan_index,
+				     NULL,
+				     0,
+				     0,
+				     &indio_dev->dev,
+				     &buffer->scan_el_dev_attr_list);
+	if (ret)
+		goto error_ret;
+	attrcount++;
+	ret = __iio_add_chan_devattr("type",
+				     chan,
+				     &iio_show_fixed_type,
+				     NULL,
+				     0,
+				     0,
+				     &indio_dev->dev,
+				     &buffer->scan_el_dev_attr_list);
+	if (ret)
+		goto error_ret;
+	attrcount++;
+	if (chan->type != IIO_TIMESTAMP)
+		ret = __iio_add_chan_devattr("en",
+					     chan,
+					     &iio_scan_el_show,
+					     &iio_scan_el_store,
+					     chan->scan_index,
+					     0,
+					     &indio_dev->dev,
+					     &buffer->scan_el_dev_attr_list);
+	else
+		ret = __iio_add_chan_devattr("en",
+					     chan,
+					     &iio_scan_el_ts_show,
+					     &iio_scan_el_ts_store,
+					     chan->scan_index,
+					     0,
+					     &indio_dev->dev,
+					     &buffer->scan_el_dev_attr_list);
+	attrcount++;
+	ret = attrcount;
+error_ret:
+	return ret;
+}
+
+static void iio_buffer_remove_and_free_scan_dev_attr(struct iio_dev *indio_dev,
+						     struct iio_dev_attr *p)
+{
+	kfree(p->dev_attr.attr.name);
+	kfree(p);
+}
+
+static void __iio_buffer_attr_cleanup(struct iio_dev *indio_dev)
+{
+	struct iio_dev_attr *p, *n;
+	struct iio_buffer *buffer = indio_dev->buffer;
+
+	list_for_each_entry_safe(p, n,
+				 &buffer->scan_el_dev_attr_list, l)
+		iio_buffer_remove_and_free_scan_dev_attr(indio_dev, p);
+}
+
+static const char * const iio_scan_elements_group_name = "scan_elements";
+
+int iio_buffer_register(struct iio_dev *indio_dev,
+			const struct iio_chan_spec *channels,
+			int num_channels)
+{
+	struct iio_dev_attr *p;
+	struct attribute **attr;
+	struct iio_buffer *buffer = indio_dev->buffer;
+	int ret, i, attrn, attrcount, attrcount_orig = 0;
+
+	if (buffer->attrs)
+		indio_dev->groups[indio_dev->groupcounter++] = buffer->attrs;
+
+	if (buffer->scan_el_attrs != NULL) {
+		attr = buffer->scan_el_attrs->attrs;
+		while (*attr++ != NULL)
+			attrcount_orig++;
+	}
+	attrcount = attrcount_orig;
+	INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
+	if (channels) {
+		/* new magic */
+		for (i = 0; i < num_channels; i++) {
+			/* Establish necessary mask length */
+			if (channels[i].scan_index >
+			    (int)indio_dev->masklength - 1)
+				indio_dev->masklength
+					= indio_dev->channels[i].scan_index + 1;
+
+			ret = iio_buffer_add_channel_sysfs(indio_dev,
+							 &channels[i]);
+			if (ret < 0)
+				goto error_cleanup_dynamic;
+			attrcount += ret;
+			if (channels[i].type == IIO_TIMESTAMP)
+				indio_dev->scan_index_timestamp =
+					channels[i].scan_index;
+		}
+		if (indio_dev->masklength && buffer->scan_mask == NULL) {
+			buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
+						    sizeof(*buffer->scan_mask),
+						    GFP_KERNEL);
+			if (buffer->scan_mask == NULL) {
+				ret = -ENOMEM;
+				goto error_cleanup_dynamic;
+			}
+		}
+	}
+
+	buffer->scan_el_group.name = iio_scan_elements_group_name;
+
+	buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
+					      sizeof(buffer->scan_el_group.attrs[0]),
+					      GFP_KERNEL);
+	if (buffer->scan_el_group.attrs == NULL) {
+		ret = -ENOMEM;
+		goto error_free_scan_mask;
+	}
+	if (buffer->scan_el_attrs)
+		memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs,
+		       sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig);
+	attrn = attrcount_orig;
+
+	list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
+		buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
+	indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
+
+	return 0;
+
+error_free_scan_mask:
+	kfree(buffer->scan_mask);
+error_cleanup_dynamic:
+	__iio_buffer_attr_cleanup(indio_dev);
+
+	return ret;
+}
+EXPORT_SYMBOL(iio_buffer_register);
+
+void iio_buffer_unregister(struct iio_dev *indio_dev)
+{
+	kfree(indio_dev->buffer->scan_mask);
+	kfree(indio_dev->buffer->scan_el_group.attrs);
+	__iio_buffer_attr_cleanup(indio_dev);
+}
+EXPORT_SYMBOL(iio_buffer_unregister);
+
+ssize_t iio_buffer_read_length(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_buffer *buffer = indio_dev->buffer;
+
+	if (buffer->access->get_length)
+		return sprintf(buf, "%d\n",
+			       buffer->access->get_length(buffer));
+
+	return 0;
+}
+EXPORT_SYMBOL(iio_buffer_read_length);
+
+ssize_t iio_buffer_write_length(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t len)
+{
+	int ret;
+	ulong val;
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_buffer *buffer = indio_dev->buffer;
+
+	ret = strict_strtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	if (buffer->access->get_length)
+		if (val == buffer->access->get_length(buffer))
+			return len;
+
+	mutex_lock(&indio_dev->mlock);
+	if (iio_buffer_enabled(indio_dev)) {
+		ret = -EBUSY;
+	} else {
+		if (buffer->access->set_length)
+			buffer->access->set_length(buffer, val);
+		ret = 0;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+EXPORT_SYMBOL(iio_buffer_write_length);
+
+ssize_t iio_buffer_store_enable(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t len)
+{
+	int ret;
+	bool requested_state, current_state;
+	int previous_mode;
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_buffer *buffer = indio_dev->buffer;
+
+	mutex_lock(&indio_dev->mlock);
+	previous_mode = indio_dev->currentmode;
+	requested_state = !(buf[0] == '0');
+	current_state = iio_buffer_enabled(indio_dev);
+	if (current_state == requested_state) {
+		printk(KERN_INFO "iio-buffer, current state requested again\n");
+		goto done;
+	}
+	if (requested_state) {
+		if (indio_dev->setup_ops->preenable) {
+			ret = indio_dev->setup_ops->preenable(indio_dev);
+			if (ret) {
+				printk(KERN_ERR
+				       "Buffer not started:"
+				       "buffer preenable failed\n");
+				goto error_ret;
+			}
+		}
+		if (buffer->access->request_update) {
+			ret = buffer->access->request_update(buffer);
+			if (ret) {
+				printk(KERN_INFO
+				       "Buffer not started:"
+				       "buffer parameter update failed\n");
+				goto error_ret;
+			}
+		}
+		/* Definitely possible for devices to support both of these.*/
+		if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
+			if (!indio_dev->trig) {
+				printk(KERN_INFO
+				       "Buffer not started: no trigger\n");
+				ret = -EINVAL;
+				goto error_ret;
+			}
+			indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
+		} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE)
+			indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
+		else { /* should never be reached */
+			ret = -EINVAL;
+			goto error_ret;
+		}
+
+		if (indio_dev->setup_ops->postenable) {
+			ret = indio_dev->setup_ops->postenable(indio_dev);
+			if (ret) {
+				printk(KERN_INFO
+				       "Buffer not started:"
+				       "postenable failed\n");
+				indio_dev->currentmode = previous_mode;
+				if (indio_dev->setup_ops->postdisable)
+					indio_dev->setup_ops->
+						postdisable(indio_dev);
+				goto error_ret;
+			}
+		}
+	} else {
+		if (indio_dev->setup_ops->predisable) {
+			ret = indio_dev->setup_ops->predisable(indio_dev);
+			if (ret)
+				goto error_ret;
+		}
+		indio_dev->currentmode = INDIO_DIRECT_MODE;
+		if (indio_dev->setup_ops->postdisable) {
+			ret = indio_dev->setup_ops->postdisable(indio_dev);
+			if (ret)
+				goto error_ret;
+		}
+	}
+done:
+	mutex_unlock(&indio_dev->mlock);
+	return len;
+
+error_ret:
+	mutex_unlock(&indio_dev->mlock);
+	return ret;
+}
+EXPORT_SYMBOL(iio_buffer_store_enable);
+
+ssize_t iio_buffer_show_enable(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
+}
+EXPORT_SYMBOL(iio_buffer_show_enable);
+
+/* note NULL used as error indicator as it doesn't make sense. */
+static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
+					  unsigned int masklength,
+					  const unsigned long *mask)
+{
+	if (bitmap_empty(mask, masklength))
+		return NULL;
+	while (*av_masks) {
+		if (bitmap_subset(mask, av_masks, masklength))
+			return av_masks;
+		av_masks += BITS_TO_LONGS(masklength);
+	}
+	return NULL;
+}
+
+static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
+				  bool timestamp)
+{
+	const struct iio_chan_spec *ch;
+	unsigned bytes = 0;
+	int length, i;
+
+	/* How much space will the demuxed element take? */
+	for_each_set_bit(i, mask,
+			 indio_dev->masklength) {
+		ch = iio_find_channel_from_si(indio_dev, i);
+		length = ch->scan_type.storagebits / 8;
+		bytes = ALIGN(bytes, length);
+		bytes += length;
+	}
+	if (timestamp) {
+		ch = iio_find_channel_from_si(indio_dev,
+					      indio_dev->scan_index_timestamp);
+		length = ch->scan_type.storagebits / 8;
+		bytes = ALIGN(bytes, length);
+		bytes += length;
+	}
+	return bytes;
+}
+
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+{
+	struct iio_buffer *buffer = indio_dev->buffer;
+	dev_dbg(&indio_dev->dev, "%s\n", __func__);
+
+	/* How much space will the demuxed element take? */
+	indio_dev->scan_bytes =
+		iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
+				       buffer->scan_timestamp);
+	buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
+
+	/* What scan mask do we actually have ?*/
+	if (indio_dev->available_scan_masks)
+		indio_dev->active_scan_mask =
+			iio_scan_mask_match(indio_dev->available_scan_masks,
+					    indio_dev->masklength,
+					    buffer->scan_mask);
+	else
+		indio_dev->active_scan_mask = buffer->scan_mask;
+	iio_update_demux(indio_dev);
+
+	if (indio_dev->info->update_scan_mode)
+		return indio_dev->info
+			->update_scan_mode(indio_dev,
+					   indio_dev->active_scan_mask);
+	return 0;
+}
+EXPORT_SYMBOL(iio_sw_buffer_preenable);
+
+/**
+ * iio_scan_mask_set() - set particular bit in the scan mask
+ * @buffer: the buffer whose scan mask we are interested in
+ * @bit: the bit to be set.
+ **/
+int iio_scan_mask_set(struct iio_dev *indio_dev,
+		      struct iio_buffer *buffer, int bit)
+{
+	const unsigned long *mask;
+	unsigned long *trialmask;
+
+	trialmask = kmalloc(sizeof(*trialmask)*
+			    BITS_TO_LONGS(indio_dev->masklength),
+			    GFP_KERNEL);
+
+	if (trialmask == NULL)
+		return -ENOMEM;
+	if (!indio_dev->masklength) {
+		WARN_ON("trying to set scanmask prior to registering buffer\n");
+		kfree(trialmask);
+		return -EINVAL;
+	}
+	bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
+	set_bit(bit, trialmask);
+
+	if (indio_dev->available_scan_masks) {
+		mask = iio_scan_mask_match(indio_dev->available_scan_masks,
+					   indio_dev->masklength,
+					   trialmask);
+		if (!mask) {
+			kfree(trialmask);
+			return -EINVAL;
+		}
+	}
+	bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
+
+	kfree(trialmask);
+
+	return 0;
+};
+EXPORT_SYMBOL_GPL(iio_scan_mask_set);
+
+int iio_scan_mask_query(struct iio_dev *indio_dev,
+			struct iio_buffer *buffer, int bit)
+{
+	if (bit > indio_dev->masklength)
+		return -EINVAL;
+
+	if (!buffer->scan_mask)
+		return 0;
+
+	return test_bit(bit, buffer->scan_mask);
+};
+EXPORT_SYMBOL_GPL(iio_scan_mask_query);
+
+/**
+ * struct iio_demux_table() - table describing demux memcpy ops
+ * @from:	index to copy from
+ * @to:	index to copy to
+ * @length:	how many bytes to copy
+ * @l:		list head used for management
+ */
+struct iio_demux_table {
+	unsigned from;
+	unsigned to;
+	unsigned length;
+	struct list_head l;
+};
+
+static unsigned char *iio_demux(struct iio_buffer *buffer,
+				 unsigned char *datain)
+{
+	struct iio_demux_table *t;
+
+	if (list_empty(&buffer->demux_list))
+		return datain;
+	list_for_each_entry(t, &buffer->demux_list, l)
+		memcpy(buffer->demux_bounce + t->to,
+		       datain + t->from, t->length);
+
+	return buffer->demux_bounce;
+}
+
+int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
+		       s64 timestamp)
+{
+	unsigned char *dataout = iio_demux(buffer, data);
+
+	return buffer->access->store_to(buffer, dataout, timestamp);
+}
+EXPORT_SYMBOL_GPL(iio_push_to_buffer);
+
+static void iio_buffer_demux_free(struct iio_buffer *buffer)
+{
+	struct iio_demux_table *p, *q;
+	list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
+		list_del(&p->l);
+		kfree(p);
+	}
+}
+
+int iio_update_demux(struct iio_dev *indio_dev)
+{
+	const struct iio_chan_spec *ch;
+	struct iio_buffer *buffer = indio_dev->buffer;
+	int ret, in_ind = -1, out_ind, length;
+	unsigned in_loc = 0, out_loc = 0;
+	struct iio_demux_table *p;
+
+	/* Clear out any old demux */
+	iio_buffer_demux_free(buffer);
+	kfree(buffer->demux_bounce);
+	buffer->demux_bounce = NULL;
+
+	/* First work out which scan mode we will actually have */
+	if (bitmap_equal(indio_dev->active_scan_mask,
+			 buffer->scan_mask,
+			 indio_dev->masklength))
+		return 0;
+
+	/* Now we have the two masks, work from least sig and build up sizes */
+	for_each_set_bit(out_ind,
+			 indio_dev->active_scan_mask,
+			 indio_dev->masklength) {
+		in_ind = find_next_bit(indio_dev->active_scan_mask,
+				       indio_dev->masklength,
+				       in_ind + 1);
+		while (in_ind != out_ind) {
+			in_ind = find_next_bit(indio_dev->active_scan_mask,
+					       indio_dev->masklength,
+					       in_ind + 1);
+			ch = iio_find_channel_from_si(indio_dev, in_ind);
+			length = ch->scan_type.storagebits/8;
+			/* Make sure we are aligned */
+			in_loc += length;
+			if (in_loc % length)
+				in_loc += length - in_loc % length;
+		}
+		p = kmalloc(sizeof(*p), GFP_KERNEL);
+		if (p == NULL) {
+			ret = -ENOMEM;
+			goto error_clear_mux_table;
+		}
+		ch = iio_find_channel_from_si(indio_dev, in_ind);
+		length = ch->scan_type.storagebits/8;
+		if (out_loc % length)
+			out_loc += length - out_loc % length;
+		if (in_loc % length)
+			in_loc += length - in_loc % length;
+		p->from = in_loc;
+		p->to = out_loc;
+		p->length = length;
+		list_add_tail(&p->l, &buffer->demux_list);
+		out_loc += length;
+		in_loc += length;
+	}
+	/* Relies on scan_timestamp being last */
+	if (buffer->scan_timestamp) {
+		p = kmalloc(sizeof(*p), GFP_KERNEL);
+		if (p == NULL) {
+			ret = -ENOMEM;
+			goto error_clear_mux_table;
+		}
+		ch = iio_find_channel_from_si(indio_dev,
+			indio_dev->scan_index_timestamp);
+		length = ch->scan_type.storagebits/8;
+		if (out_loc % length)
+			out_loc += length - out_loc % length;
+		if (in_loc % length)
+			in_loc += length - in_loc % length;
+		p->from = in_loc;
+		p->to = out_loc;
+		p->length = length;
+		list_add_tail(&p->l, &buffer->demux_list);
+		out_loc += length;
+		in_loc += length;
+	}
+	buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL);
+	if (buffer->demux_bounce == NULL) {
+		ret = -ENOMEM;
+		goto error_clear_mux_table;
+	}
+	return 0;
+
+error_clear_mux_table:
+	iio_buffer_demux_free(buffer);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_update_demux);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
new file mode 100644
index 0000000..1ddd886
--- /dev/null
+++ b/drivers/iio/industrialio-core.c
@@ -0,0 +1,913 @@
+/* The industrial I/O core
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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.
+ *
+ * Based on elements of hwmon and input subsystems.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/kdev_t.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/anon_inodes.h>
+#include <linux/debugfs.h>
+#include <linux/iio/iio.h>
+#include "iio_core.h"
+#include "iio_core_trigger.h"
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+
+/* IDA to assign each registered device a unique id*/
+static DEFINE_IDA(iio_ida);
+
+static dev_t iio_devt;
+
+#define IIO_DEV_MAX 256
+struct bus_type iio_bus_type = {
+	.name = "iio",
+};
+EXPORT_SYMBOL(iio_bus_type);
+
+static struct dentry *iio_debugfs_dentry;
+
+static const char * const iio_direction[] = {
+	[0] = "in",
+	[1] = "out",
+};
+
+static const char * const iio_chan_type_name_spec[] = {
+	[IIO_VOLTAGE] = "voltage",
+	[IIO_CURRENT] = "current",
+	[IIO_POWER] = "power",
+	[IIO_ACCEL] = "accel",
+	[IIO_ANGL_VEL] = "anglvel",
+	[IIO_MAGN] = "magn",
+	[IIO_LIGHT] = "illuminance",
+	[IIO_INTENSITY] = "intensity",
+	[IIO_PROXIMITY] = "proximity",
+	[IIO_TEMP] = "temp",
+	[IIO_INCLI] = "incli",
+	[IIO_ROT] = "rot",
+	[IIO_ANGL] = "angl",
+	[IIO_TIMESTAMP] = "timestamp",
+	[IIO_CAPACITANCE] = "capacitance",
+	[IIO_ALTVOLTAGE] = "altvoltage",
+};
+
+static const char * const iio_modifier_names[] = {
+	[IIO_MOD_X] = "x",
+	[IIO_MOD_Y] = "y",
+	[IIO_MOD_Z] = "z",
+	[IIO_MOD_LIGHT_BOTH] = "both",
+	[IIO_MOD_LIGHT_IR] = "ir",
+};
+
+/* relies on pairs of these shared then separate */
+static const char * const iio_chan_info_postfix[] = {
+	[IIO_CHAN_INFO_RAW] = "raw",
+	[IIO_CHAN_INFO_PROCESSED] = "input",
+	[IIO_CHAN_INFO_SCALE] = "scale",
+	[IIO_CHAN_INFO_OFFSET] = "offset",
+	[IIO_CHAN_INFO_CALIBSCALE] = "calibscale",
+	[IIO_CHAN_INFO_CALIBBIAS] = "calibbias",
+	[IIO_CHAN_INFO_PEAK] = "peak_raw",
+	[IIO_CHAN_INFO_PEAK_SCALE] = "peak_scale",
+	[IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW] = "quadrature_correction_raw",
+	[IIO_CHAN_INFO_AVERAGE_RAW] = "mean_raw",
+	[IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY]
+	= "filter_low_pass_3db_frequency",
+	[IIO_CHAN_INFO_SAMP_FREQ] = "sampling_frequency",
+	[IIO_CHAN_INFO_FREQUENCY] = "frequency",
+	[IIO_CHAN_INFO_PHASE] = "phase",
+	[IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
+};
+
+const struct iio_chan_spec
+*iio_find_channel_from_si(struct iio_dev *indio_dev, int si)
+{
+	int i;
+
+	for (i = 0; i < indio_dev->num_channels; i++)
+		if (indio_dev->channels[i].scan_index == si)
+			return &indio_dev->channels[i];
+	return NULL;
+}
+
+/* This turns up an awful lot */
+ssize_t iio_read_const_attr(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string);
+}
+EXPORT_SYMBOL(iio_read_const_attr);
+
+static int __init iio_init(void)
+{
+	int ret;
+
+	/* Register sysfs bus */
+	ret  = bus_register(&iio_bus_type);
+	if (ret < 0) {
+		printk(KERN_ERR
+		       "%s could not register bus type\n",
+			__FILE__);
+		goto error_nothing;
+	}
+
+	ret = alloc_chrdev_region(&iio_devt, 0, IIO_DEV_MAX, "iio");
+	if (ret < 0) {
+		printk(KERN_ERR "%s: failed to allocate char dev region\n",
+		       __FILE__);
+		goto error_unregister_bus_type;
+	}
+
+	iio_debugfs_dentry = debugfs_create_dir("iio", NULL);
+
+	return 0;
+
+error_unregister_bus_type:
+	bus_unregister(&iio_bus_type);
+error_nothing:
+	return ret;
+}
+
+static void __exit iio_exit(void)
+{
+	if (iio_devt)
+		unregister_chrdev_region(iio_devt, IIO_DEV_MAX);
+	bus_unregister(&iio_bus_type);
+	debugfs_remove(iio_debugfs_dentry);
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf,
+			      size_t count, loff_t *ppos)
+{
+	struct iio_dev *indio_dev = file->private_data;
+	char buf[20];
+	unsigned val = 0;
+	ssize_t len;
+	int ret;
+
+	ret = indio_dev->info->debugfs_reg_access(indio_dev,
+						  indio_dev->cached_reg_addr,
+						  0, &val);
+	if (ret)
+		dev_err(indio_dev->dev.parent, "%s: read failed\n", __func__);
+
+	len = snprintf(buf, sizeof(buf), "0x%X\n", val);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static ssize_t iio_debugfs_write_reg(struct file *file,
+		     const char __user *userbuf, size_t count, loff_t *ppos)
+{
+	struct iio_dev *indio_dev = file->private_data;
+	unsigned reg, val;
+	char buf[80];
+	int ret;
+
+	count = min_t(size_t, count, (sizeof(buf)-1));
+	if (copy_from_user(buf, userbuf, count))
+		return -EFAULT;
+
+	buf[count] = 0;
+
+	ret = sscanf(buf, "%i %i", &reg, &val);
+
+	switch (ret) {
+	case 1:
+		indio_dev->cached_reg_addr = reg;
+		break;
+	case 2:
+		indio_dev->cached_reg_addr = reg;
+		ret = indio_dev->info->debugfs_reg_access(indio_dev, reg,
+							  val, NULL);
+		if (ret) {
+			dev_err(indio_dev->dev.parent, "%s: write failed\n",
+				__func__);
+			return ret;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static const struct file_operations iio_debugfs_reg_fops = {
+	.open = simple_open,
+	.read = iio_debugfs_read_reg,
+	.write = iio_debugfs_write_reg,
+};
+
+static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
+{
+	debugfs_remove_recursive(indio_dev->debugfs_dentry);
+}
+
+static int iio_device_register_debugfs(struct iio_dev *indio_dev)
+{
+	struct dentry *d;
+
+	if (indio_dev->info->debugfs_reg_access == NULL)
+		return 0;
+
+	if (!iio_debugfs_dentry)
+		return 0;
+
+	indio_dev->debugfs_dentry =
+		debugfs_create_dir(dev_name(&indio_dev->dev),
+				   iio_debugfs_dentry);
+	if (indio_dev->debugfs_dentry == NULL) {
+		dev_warn(indio_dev->dev.parent,
+			 "Failed to create debugfs directory\n");
+		return -EFAULT;
+	}
+
+	d = debugfs_create_file("direct_reg_access", 0644,
+				indio_dev->debugfs_dentry,
+				indio_dev, &iio_debugfs_reg_fops);
+	if (!d) {
+		iio_device_unregister_debugfs(indio_dev);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+#else
+static int iio_device_register_debugfs(struct iio_dev *indio_dev)
+{
+	return 0;
+}
+
+static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static ssize_t iio_read_channel_ext_info(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	ext_info = &this_attr->c->ext_info[this_attr->address];
+
+	return ext_info->read(indio_dev, ext_info->private, this_attr->c, buf);
+}
+
+static ssize_t iio_write_channel_ext_info(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf,
+					 size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	ext_info = &this_attr->c->ext_info[this_attr->address];
+
+	return ext_info->write(indio_dev, ext_info->private,
+			       this_attr->c, buf, len);
+}
+
+static ssize_t iio_read_channel_info(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int val, val2;
+	bool scale_db = false;
+	int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
+					    &val, &val2, this_attr->address);
+
+	if (ret < 0)
+		return ret;
+
+	switch (ret) {
+	case IIO_VAL_INT:
+		return sprintf(buf, "%d\n", val);
+	case IIO_VAL_INT_PLUS_MICRO_DB:
+		scale_db = true;
+	case IIO_VAL_INT_PLUS_MICRO:
+		if (val2 < 0)
+			return sprintf(buf, "-%d.%06u%s\n", val, -val2,
+				scale_db ? " dB" : "");
+		else
+			return sprintf(buf, "%d.%06u%s\n", val, val2,
+				scale_db ? " dB" : "");
+	case IIO_VAL_INT_PLUS_NANO:
+		if (val2 < 0)
+			return sprintf(buf, "-%d.%09u\n", val, -val2);
+		else
+			return sprintf(buf, "%d.%09u\n", val, val2);
+	default:
+		return 0;
+	}
+}
+
+static ssize_t iio_write_channel_info(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf,
+				      size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int ret, integer = 0, fract = 0, fract_mult = 100000;
+	bool integer_part = true, negative = false;
+
+	/* Assumes decimal - precision based on number of digits */
+	if (!indio_dev->info->write_raw)
+		return -EINVAL;
+
+	if (indio_dev->info->write_raw_get_fmt)
+		switch (indio_dev->info->write_raw_get_fmt(indio_dev,
+			this_attr->c, this_attr->address)) {
+		case IIO_VAL_INT_PLUS_MICRO:
+			fract_mult = 100000;
+			break;
+		case IIO_VAL_INT_PLUS_NANO:
+			fract_mult = 100000000;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+	if (buf[0] == '-') {
+		negative = true;
+		buf++;
+	}
+
+	while (*buf) {
+		if ('0' <= *buf && *buf <= '9') {
+			if (integer_part)
+				integer = integer*10 + *buf - '0';
+			else {
+				fract += fract_mult*(*buf - '0');
+				if (fract_mult == 1)
+					break;
+				fract_mult /= 10;
+			}
+		} else if (*buf == '\n') {
+			if (*(buf + 1) == '\0')
+				break;
+			else
+				return -EINVAL;
+		} else if (*buf == '.') {
+			integer_part = false;
+		} else {
+			return -EINVAL;
+		}
+		buf++;
+	}
+	if (negative) {
+		if (integer)
+			integer = -integer;
+		else
+			fract = -fract;
+	}
+
+	ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
+					 integer, fract, this_attr->address);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
+static
+int __iio_device_attr_init(struct device_attribute *dev_attr,
+			   const char *postfix,
+			   struct iio_chan_spec const *chan,
+			   ssize_t (*readfunc)(struct device *dev,
+					       struct device_attribute *attr,
+					       char *buf),
+			   ssize_t (*writefunc)(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf,
+						size_t len),
+			   bool generic)
+{
+	int ret;
+	char *name_format, *full_postfix;
+	sysfs_attr_init(&dev_attr->attr);
+
+	/* Build up postfix of <extend_name>_<modifier>_postfix */
+	if (chan->modified && !generic) {
+		if (chan->extend_name)
+			full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
+						 iio_modifier_names[chan
+								    ->channel2],
+						 chan->extend_name,
+						 postfix);
+		else
+			full_postfix = kasprintf(GFP_KERNEL, "%s_%s",
+						 iio_modifier_names[chan
+								    ->channel2],
+						 postfix);
+	} else {
+		if (chan->extend_name == NULL)
+			full_postfix = kstrdup(postfix, GFP_KERNEL);
+		else
+			full_postfix = kasprintf(GFP_KERNEL,
+						 "%s_%s",
+						 chan->extend_name,
+						 postfix);
+	}
+	if (full_postfix == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	if (chan->differential) { /* Differential can not have modifier */
+		if (generic)
+			name_format
+				= kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
+					    iio_direction[chan->output],
+					    iio_chan_type_name_spec[chan->type],
+					    iio_chan_type_name_spec[chan->type],
+					    full_postfix);
+		else if (chan->indexed)
+			name_format
+				= kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s",
+					    iio_direction[chan->output],
+					    iio_chan_type_name_spec[chan->type],
+					    chan->channel,
+					    iio_chan_type_name_spec[chan->type],
+					    chan->channel2,
+					    full_postfix);
+		else {
+			WARN_ON("Differential channels must be indexed\n");
+			ret = -EINVAL;
+			goto error_free_full_postfix;
+		}
+	} else { /* Single ended */
+		if (generic)
+			name_format
+				= kasprintf(GFP_KERNEL, "%s_%s_%s",
+					    iio_direction[chan->output],
+					    iio_chan_type_name_spec[chan->type],
+					    full_postfix);
+		else if (chan->indexed)
+			name_format
+				= kasprintf(GFP_KERNEL, "%s_%s%d_%s",
+					    iio_direction[chan->output],
+					    iio_chan_type_name_spec[chan->type],
+					    chan->channel,
+					    full_postfix);
+		else
+			name_format
+				= kasprintf(GFP_KERNEL, "%s_%s_%s",
+					    iio_direction[chan->output],
+					    iio_chan_type_name_spec[chan->type],
+					    full_postfix);
+	}
+	if (name_format == NULL) {
+		ret = -ENOMEM;
+		goto error_free_full_postfix;
+	}
+	dev_attr->attr.name = kasprintf(GFP_KERNEL,
+					name_format,
+					chan->channel,
+					chan->channel2);
+	if (dev_attr->attr.name == NULL) {
+		ret = -ENOMEM;
+		goto error_free_name_format;
+	}
+
+	if (readfunc) {
+		dev_attr->attr.mode |= S_IRUGO;
+		dev_attr->show = readfunc;
+	}
+
+	if (writefunc) {
+		dev_attr->attr.mode |= S_IWUSR;
+		dev_attr->store = writefunc;
+	}
+	kfree(name_format);
+	kfree(full_postfix);
+
+	return 0;
+
+error_free_name_format:
+	kfree(name_format);
+error_free_full_postfix:
+	kfree(full_postfix);
+error_ret:
+	return ret;
+}
+
+static void __iio_device_attr_deinit(struct device_attribute *dev_attr)
+{
+	kfree(dev_attr->attr.name);
+}
+
+int __iio_add_chan_devattr(const char *postfix,
+			   struct iio_chan_spec const *chan,
+			   ssize_t (*readfunc)(struct device *dev,
+					       struct device_attribute *attr,
+					       char *buf),
+			   ssize_t (*writefunc)(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf,
+						size_t len),
+			   u64 mask,
+			   bool generic,
+			   struct device *dev,
+			   struct list_head *attr_list)
+{
+	int ret;
+	struct iio_dev_attr *iio_attr, *t;
+
+	iio_attr = kzalloc(sizeof *iio_attr, GFP_KERNEL);
+	if (iio_attr == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	ret = __iio_device_attr_init(&iio_attr->dev_attr,
+				     postfix, chan,
+				     readfunc, writefunc, generic);
+	if (ret)
+		goto error_iio_dev_attr_free;
+	iio_attr->c = chan;
+	iio_attr->address = mask;
+	list_for_each_entry(t, attr_list, l)
+		if (strcmp(t->dev_attr.attr.name,
+			   iio_attr->dev_attr.attr.name) == 0) {
+			if (!generic)
+				dev_err(dev, "tried to double register : %s\n",
+					t->dev_attr.attr.name);
+			ret = -EBUSY;
+			goto error_device_attr_deinit;
+		}
+	list_add(&iio_attr->l, attr_list);
+
+	return 0;
+
+error_device_attr_deinit:
+	__iio_device_attr_deinit(&iio_attr->dev_attr);
+error_iio_dev_attr_free:
+	kfree(iio_attr);
+error_ret:
+	return ret;
+}
+
+static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan)
+{
+	int ret, attrcount = 0;
+	int i;
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	if (chan->channel < 0)
+		return 0;
+	for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) {
+		ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
+					     chan,
+					     &iio_read_channel_info,
+					     &iio_write_channel_info,
+					     i/2,
+					     !(i%2),
+					     &indio_dev->dev,
+					     &indio_dev->channel_attr_list);
+		if (ret == -EBUSY && (i%2 == 0)) {
+			ret = 0;
+			continue;
+		}
+		if (ret < 0)
+			goto error_ret;
+		attrcount++;
+	}
+
+	if (chan->ext_info) {
+		unsigned int i = 0;
+		for (ext_info = chan->ext_info; ext_info->name; ext_info++) {
+			ret = __iio_add_chan_devattr(ext_info->name,
+					chan,
+					ext_info->read ?
+					    &iio_read_channel_ext_info : NULL,
+					ext_info->write ?
+					    &iio_write_channel_ext_info : NULL,
+					i,
+					ext_info->shared,
+					&indio_dev->dev,
+					&indio_dev->channel_attr_list);
+			i++;
+			if (ret == -EBUSY && ext_info->shared)
+				continue;
+
+			if (ret)
+				goto error_ret;
+
+			attrcount++;
+		}
+	}
+
+	ret = attrcount;
+error_ret:
+	return ret;
+}
+
+static void iio_device_remove_and_free_read_attr(struct iio_dev *indio_dev,
+						 struct iio_dev_attr *p)
+{
+	kfree(p->dev_attr.attr.name);
+	kfree(p);
+}
+
+static ssize_t iio_show_dev_name(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	return sprintf(buf, "%s\n", indio_dev->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
+
+static int iio_device_register_sysfs(struct iio_dev *indio_dev)
+{
+	int i, ret = 0, attrcount, attrn, attrcount_orig = 0;
+	struct iio_dev_attr *p, *n;
+	struct attribute **attr;
+
+	/* First count elements in any existing group */
+	if (indio_dev->info->attrs) {
+		attr = indio_dev->info->attrs->attrs;
+		while (*attr++ != NULL)
+			attrcount_orig++;
+	}
+	attrcount = attrcount_orig;
+	/*
+	 * New channel registration method - relies on the fact a group does
+	 * not need to be initialized if it is name is NULL.
+	 */
+	INIT_LIST_HEAD(&indio_dev->channel_attr_list);
+	if (indio_dev->channels)
+		for (i = 0; i < indio_dev->num_channels; i++) {
+			ret = iio_device_add_channel_sysfs(indio_dev,
+							   &indio_dev
+							   ->channels[i]);
+			if (ret < 0)
+				goto error_clear_attrs;
+			attrcount += ret;
+		}
+
+	if (indio_dev->name)
+		attrcount++;
+
+	indio_dev->chan_attr_group.attrs = kcalloc(attrcount + 1,
+						   sizeof(indio_dev->chan_attr_group.attrs[0]),
+						   GFP_KERNEL);
+	if (indio_dev->chan_attr_group.attrs == NULL) {
+		ret = -ENOMEM;
+		goto error_clear_attrs;
+	}
+	/* Copy across original attributes */
+	if (indio_dev->info->attrs)
+		memcpy(indio_dev->chan_attr_group.attrs,
+		       indio_dev->info->attrs->attrs,
+		       sizeof(indio_dev->chan_attr_group.attrs[0])
+		       *attrcount_orig);
+	attrn = attrcount_orig;
+	/* Add all elements from the list. */
+	list_for_each_entry(p, &indio_dev->channel_attr_list, l)
+		indio_dev->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr;
+	if (indio_dev->name)
+		indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr;
+
+	indio_dev->groups[indio_dev->groupcounter++] =
+		&indio_dev->chan_attr_group;
+
+	return 0;
+
+error_clear_attrs:
+	list_for_each_entry_safe(p, n,
+				 &indio_dev->channel_attr_list, l) {
+		list_del(&p->l);
+		iio_device_remove_and_free_read_attr(indio_dev, p);
+	}
+
+	return ret;
+}
+
+static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
+{
+
+	struct iio_dev_attr *p, *n;
+
+	list_for_each_entry_safe(p, n, &indio_dev->channel_attr_list, l) {
+		list_del(&p->l);
+		iio_device_remove_and_free_read_attr(indio_dev, p);
+	}
+	kfree(indio_dev->chan_attr_group.attrs);
+}
+
+static void iio_dev_release(struct device *device)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(device);
+	cdev_del(&indio_dev->chrdev);
+	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+		iio_device_unregister_trigger_consumer(indio_dev);
+	iio_device_unregister_eventset(indio_dev);
+	iio_device_unregister_sysfs(indio_dev);
+	iio_device_unregister_debugfs(indio_dev);
+}
+
+static struct device_type iio_dev_type = {
+	.name = "iio_device",
+	.release = iio_dev_release,
+};
+
+struct iio_dev *iio_device_alloc(int sizeof_priv)
+{
+	struct iio_dev *dev;
+	size_t alloc_size;
+
+	alloc_size = sizeof(struct iio_dev);
+	if (sizeof_priv) {
+		alloc_size = ALIGN(alloc_size, IIO_ALIGN);
+		alloc_size += sizeof_priv;
+	}
+	/* ensure 32-byte alignment of whole construct ? */
+	alloc_size += IIO_ALIGN - 1;
+
+	dev = kzalloc(alloc_size, GFP_KERNEL);
+
+	if (dev) {
+		dev->dev.groups = dev->groups;
+		dev->dev.type = &iio_dev_type;
+		dev->dev.bus = &iio_bus_type;
+		device_initialize(&dev->dev);
+		dev_set_drvdata(&dev->dev, (void *)dev);
+		mutex_init(&dev->mlock);
+		mutex_init(&dev->info_exist_lock);
+
+		dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
+		if (dev->id < 0) {
+			/* cannot use a dev_err as the name isn't available */
+			printk(KERN_ERR "Failed to get id\n");
+			kfree(dev);
+			return NULL;
+		}
+		dev_set_name(&dev->dev, "iio:device%d", dev->id);
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL(iio_device_alloc);
+
+void iio_device_free(struct iio_dev *dev)
+{
+	if (dev) {
+		ida_simple_remove(&iio_ida, dev->id);
+		kfree(dev);
+	}
+}
+EXPORT_SYMBOL(iio_device_free);
+
+/**
+ * iio_chrdev_open() - chrdev file open for buffer access and ioctls
+ **/
+static int iio_chrdev_open(struct inode *inode, struct file *filp)
+{
+	struct iio_dev *indio_dev = container_of(inode->i_cdev,
+						struct iio_dev, chrdev);
+
+	if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags))
+		return -EBUSY;
+
+	filp->private_data = indio_dev;
+
+	return 0;
+}
+
+/**
+ * iio_chrdev_release() - chrdev file close buffer access and ioctls
+ **/
+static int iio_chrdev_release(struct inode *inode, struct file *filp)
+{
+	struct iio_dev *indio_dev = container_of(inode->i_cdev,
+						struct iio_dev, chrdev);
+	clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
+	return 0;
+}
+
+/* Somewhat of a cross file organization violation - ioctls here are actually
+ * event related */
+static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct iio_dev *indio_dev = filp->private_data;
+	int __user *ip = (int __user *)arg;
+	int fd;
+
+	if (cmd == IIO_GET_EVENT_FD_IOCTL) {
+		fd = iio_event_getfd(indio_dev);
+		if (copy_to_user(ip, &fd, sizeof(fd)))
+			return -EFAULT;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static const struct file_operations iio_buffer_fileops = {
+	.read = iio_buffer_read_first_n_outer_addr,
+	.release = iio_chrdev_release,
+	.open = iio_chrdev_open,
+	.poll = iio_buffer_poll_addr,
+	.owner = THIS_MODULE,
+	.llseek = noop_llseek,
+	.unlocked_ioctl = iio_ioctl,
+	.compat_ioctl = iio_ioctl,
+};
+
+static const struct iio_buffer_setup_ops noop_ring_setup_ops;
+
+int iio_device_register(struct iio_dev *indio_dev)
+{
+	int ret;
+
+	/* configure elements for the chrdev */
+	indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
+
+	ret = iio_device_register_debugfs(indio_dev);
+	if (ret) {
+		dev_err(indio_dev->dev.parent,
+			"Failed to register debugfs interfaces\n");
+		goto error_ret;
+	}
+	ret = iio_device_register_sysfs(indio_dev);
+	if (ret) {
+		dev_err(indio_dev->dev.parent,
+			"Failed to register sysfs interfaces\n");
+		goto error_unreg_debugfs;
+	}
+	ret = iio_device_register_eventset(indio_dev);
+	if (ret) {
+		dev_err(indio_dev->dev.parent,
+			"Failed to register event set\n");
+		goto error_free_sysfs;
+	}
+	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+		iio_device_register_trigger_consumer(indio_dev);
+
+	if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&
+		indio_dev->setup_ops == NULL)
+		indio_dev->setup_ops = &noop_ring_setup_ops;
+
+	ret = device_add(&indio_dev->dev);
+	if (ret < 0)
+		goto error_unreg_eventset;
+	cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
+	indio_dev->chrdev.owner = indio_dev->info->driver_module;
+	ret = cdev_add(&indio_dev->chrdev, indio_dev->dev.devt, 1);
+	if (ret < 0)
+		goto error_del_device;
+	return 0;
+
+error_del_device:
+	device_del(&indio_dev->dev);
+error_unreg_eventset:
+	iio_device_unregister_eventset(indio_dev);
+error_free_sysfs:
+	iio_device_unregister_sysfs(indio_dev);
+error_unreg_debugfs:
+	iio_device_unregister_debugfs(indio_dev);
+error_ret:
+	return ret;
+}
+EXPORT_SYMBOL(iio_device_register);
+
+void iio_device_unregister(struct iio_dev *indio_dev)
+{
+	mutex_lock(&indio_dev->info_exist_lock);
+	indio_dev->info = NULL;
+	mutex_unlock(&indio_dev->info_exist_lock);
+	device_unregister(&indio_dev->dev);
+}
+EXPORT_SYMBOL(iio_device_unregister);
+subsys_initcall(iio_init);
+module_exit(iio_exit);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_DESCRIPTION("Industrial I/O core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
new file mode 100644
index 0000000..b49059d
--- /dev/null
+++ b/drivers/iio/industrialio-event.c
@@ -0,0 +1,453 @@
+/* Industrial I/O event handling
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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.
+ *
+ * Based on elements of hwmon and input subsystems.
+ */
+
+#include <linux/anon_inodes.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/iio/iio.h>
+#include "iio_core.h"
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+
+/**
+ * struct iio_event_interface - chrdev interface for an event line
+ * @wait:		wait queue to allow blocking reads of events
+ * @det_events:		list of detected events
+ * @dev_attr_list:	list of event interface sysfs attribute
+ * @flags:		file operations related flags including busy flag.
+ * @group:		event interface sysfs attribute group
+ */
+struct iio_event_interface {
+	wait_queue_head_t	wait;
+	DECLARE_KFIFO(det_events, struct iio_event_data, 16);
+
+	struct list_head	dev_attr_list;
+	unsigned long		flags;
+	struct attribute_group	group;
+};
+
+int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
+{
+	struct iio_event_interface *ev_int = indio_dev->event_interface;
+	struct iio_event_data ev;
+	int copied;
+
+	/* Does anyone care? */
+	spin_lock(&ev_int->wait.lock);
+	if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
+
+		ev.id = ev_code;
+		ev.timestamp = timestamp;
+
+		copied = kfifo_put(&ev_int->det_events, &ev);
+		if (copied != 0)
+			wake_up_locked_poll(&ev_int->wait, POLLIN);
+	}
+	spin_unlock(&ev_int->wait.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(iio_push_event);
+
+/**
+ * iio_event_poll() - poll the event queue to find out if it has data
+ */
+static unsigned int iio_event_poll(struct file *filep,
+			     struct poll_table_struct *wait)
+{
+	struct iio_event_interface *ev_int = filep->private_data;
+	unsigned int events = 0;
+
+	poll_wait(filep, &ev_int->wait, wait);
+
+	spin_lock(&ev_int->wait.lock);
+	if (!kfifo_is_empty(&ev_int->det_events))
+		events = POLLIN | POLLRDNORM;
+	spin_unlock(&ev_int->wait.lock);
+
+	return events;
+}
+
+static ssize_t iio_event_chrdev_read(struct file *filep,
+				     char __user *buf,
+				     size_t count,
+				     loff_t *f_ps)
+{
+	struct iio_event_interface *ev_int = filep->private_data;
+	unsigned int copied;
+	int ret;
+
+	if (count < sizeof(struct iio_event_data))
+		return -EINVAL;
+
+	spin_lock(&ev_int->wait.lock);
+	if (kfifo_is_empty(&ev_int->det_events)) {
+		if (filep->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			goto error_unlock;
+		}
+		/* Blocking on device; waiting for something to be there */
+		ret = wait_event_interruptible_locked(ev_int->wait,
+					!kfifo_is_empty(&ev_int->det_events));
+		if (ret)
+			goto error_unlock;
+		/* Single access device so no one else can get the data */
+	}
+
+	ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
+
+error_unlock:
+	spin_unlock(&ev_int->wait.lock);
+
+	return ret ? ret : copied;
+}
+
+static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
+{
+	struct iio_event_interface *ev_int = filep->private_data;
+
+	spin_lock(&ev_int->wait.lock);
+	__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
+	/*
+	 * In order to maintain a clean state for reopening,
+	 * clear out any awaiting events. The mask will prevent
+	 * any new __iio_push_event calls running.
+	 */
+	kfifo_reset_out(&ev_int->det_events);
+	spin_unlock(&ev_int->wait.lock);
+
+	return 0;
+}
+
+static const struct file_operations iio_event_chrdev_fileops = {
+	.read =  iio_event_chrdev_read,
+	.poll =  iio_event_poll,
+	.release = iio_event_chrdev_release,
+	.owner = THIS_MODULE,
+	.llseek = noop_llseek,
+};
+
+int iio_event_getfd(struct iio_dev *indio_dev)
+{
+	struct iio_event_interface *ev_int = indio_dev->event_interface;
+	int fd;
+
+	if (ev_int == NULL)
+		return -ENODEV;
+
+	spin_lock(&ev_int->wait.lock);
+	if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
+		spin_unlock(&ev_int->wait.lock);
+		return -EBUSY;
+	}
+	spin_unlock(&ev_int->wait.lock);
+	fd = anon_inode_getfd("iio:event",
+				&iio_event_chrdev_fileops, ev_int, O_RDONLY);
+	if (fd < 0) {
+		spin_lock(&ev_int->wait.lock);
+		__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
+		spin_unlock(&ev_int->wait.lock);
+	}
+	return fd;
+}
+
+static const char * const iio_ev_type_text[] = {
+	[IIO_EV_TYPE_THRESH] = "thresh",
+	[IIO_EV_TYPE_MAG] = "mag",
+	[IIO_EV_TYPE_ROC] = "roc",
+	[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
+	[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
+};
+
+static const char * const iio_ev_dir_text[] = {
+	[IIO_EV_DIR_EITHER] = "either",
+	[IIO_EV_DIR_RISING] = "rising",
+	[IIO_EV_DIR_FALLING] = "falling"
+};
+
+static ssize_t iio_ev_state_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int ret;
+	bool val;
+
+	ret = strtobool(buf, &val);
+	if (ret < 0)
+		return ret;
+
+	ret = indio_dev->info->write_event_config(indio_dev,
+						  this_attr->address,
+						  val);
+	return (ret < 0) ? ret : len;
+}
+
+static ssize_t iio_ev_state_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int val = indio_dev->info->read_event_config(indio_dev,
+						     this_attr->address);
+
+	if (val < 0)
+		return val;
+	else
+		return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t iio_ev_value_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int val, ret;
+
+	ret = indio_dev->info->read_event_value(indio_dev,
+						this_attr->address, &val);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t iio_ev_value_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	unsigned long val;
+	int ret;
+
+	if (!indio_dev->info->write_event_value)
+		return -EINVAL;
+
+	ret = strict_strtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
+						 val);
+	if (ret < 0)
+		return ret;
+
+	return len;
+}
+
+static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
+				      struct iio_chan_spec const *chan)
+{
+	int ret = 0, i, attrcount = 0;
+	u64 mask = 0;
+	char *postfix;
+	if (!chan->event_mask)
+		return 0;
+
+	for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
+		postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
+				    iio_ev_type_text[i/IIO_EV_DIR_MAX],
+				    iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
+		if (postfix == NULL) {
+			ret = -ENOMEM;
+			goto error_ret;
+		}
+		if (chan->modified)
+			mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
+						  i/IIO_EV_DIR_MAX,
+						  i%IIO_EV_DIR_MAX);
+		else if (chan->differential)
+			mask = IIO_EVENT_CODE(chan->type,
+					      0, 0,
+					      i%IIO_EV_DIR_MAX,
+					      i/IIO_EV_DIR_MAX,
+					      0,
+					      chan->channel,
+					      chan->channel2);
+		else
+			mask = IIO_UNMOD_EVENT_CODE(chan->type,
+						    chan->channel,
+						    i/IIO_EV_DIR_MAX,
+						    i%IIO_EV_DIR_MAX);
+
+		ret = __iio_add_chan_devattr(postfix,
+					     chan,
+					     &iio_ev_state_show,
+					     iio_ev_state_store,
+					     mask,
+					     0,
+					     &indio_dev->dev,
+					     &indio_dev->event_interface->
+					     dev_attr_list);
+		kfree(postfix);
+		if (ret)
+			goto error_ret;
+		attrcount++;
+		postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
+				    iio_ev_type_text[i/IIO_EV_DIR_MAX],
+				    iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
+		if (postfix == NULL) {
+			ret = -ENOMEM;
+			goto error_ret;
+		}
+		ret = __iio_add_chan_devattr(postfix, chan,
+					     iio_ev_value_show,
+					     iio_ev_value_store,
+					     mask,
+					     0,
+					     &indio_dev->dev,
+					     &indio_dev->event_interface->
+					     dev_attr_list);
+		kfree(postfix);
+		if (ret)
+			goto error_ret;
+		attrcount++;
+	}
+	ret = attrcount;
+error_ret:
+	return ret;
+}
+
+static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev)
+{
+	struct iio_dev_attr *p, *n;
+	list_for_each_entry_safe(p, n,
+				 &indio_dev->event_interface->
+				 dev_attr_list, l) {
+		kfree(p->dev_attr.attr.name);
+		kfree(p);
+	}
+}
+
+static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
+{
+	int j, ret, attrcount = 0;
+
+	INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
+	/* Dynically created from the channels array */
+	for (j = 0; j < indio_dev->num_channels; j++) {
+		ret = iio_device_add_event_sysfs(indio_dev,
+						 &indio_dev->channels[j]);
+		if (ret < 0)
+			goto error_clear_attrs;
+		attrcount += ret;
+	}
+	return attrcount;
+
+error_clear_attrs:
+	__iio_remove_event_config_attrs(indio_dev);
+
+	return ret;
+}
+
+static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
+{
+	int j;
+
+	for (j = 0; j < indio_dev->num_channels; j++)
+		if (indio_dev->channels[j].event_mask != 0)
+			return true;
+	return false;
+}
+
+static void iio_setup_ev_int(struct iio_event_interface *ev_int)
+{
+	INIT_KFIFO(ev_int->det_events);
+	init_waitqueue_head(&ev_int->wait);
+}
+
+static const char *iio_event_group_name = "events";
+int iio_device_register_eventset(struct iio_dev *indio_dev)
+{
+	struct iio_dev_attr *p;
+	int ret = 0, attrcount_orig = 0, attrcount, attrn;
+	struct attribute **attr;
+
+	if (!(indio_dev->info->event_attrs ||
+	      iio_check_for_dynamic_events(indio_dev)))
+		return 0;
+
+	indio_dev->event_interface =
+		kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
+	if (indio_dev->event_interface == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	iio_setup_ev_int(indio_dev->event_interface);
+	if (indio_dev->info->event_attrs != NULL) {
+		attr = indio_dev->info->event_attrs->attrs;
+		while (*attr++ != NULL)
+			attrcount_orig++;
+	}
+	attrcount = attrcount_orig;
+	if (indio_dev->channels) {
+		ret = __iio_add_event_config_attrs(indio_dev);
+		if (ret < 0)
+			goto error_free_setup_event_lines;
+		attrcount += ret;
+	}
+
+	indio_dev->event_interface->group.name = iio_event_group_name;
+	indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1,
+							  sizeof(indio_dev->event_interface->group.attrs[0]),
+							  GFP_KERNEL);
+	if (indio_dev->event_interface->group.attrs == NULL) {
+		ret = -ENOMEM;
+		goto error_free_setup_event_lines;
+	}
+	if (indio_dev->info->event_attrs)
+		memcpy(indio_dev->event_interface->group.attrs,
+		       indio_dev->info->event_attrs->attrs,
+		       sizeof(indio_dev->event_interface->group.attrs[0])
+		       *attrcount_orig);
+	attrn = attrcount_orig;
+	/* Add all elements from the list. */
+	list_for_each_entry(p,
+			    &indio_dev->event_interface->dev_attr_list,
+			    l)
+		indio_dev->event_interface->group.attrs[attrn++] =
+			&p->dev_attr.attr;
+	indio_dev->groups[indio_dev->groupcounter++] =
+		&indio_dev->event_interface->group;
+
+	return 0;
+
+error_free_setup_event_lines:
+	__iio_remove_event_config_attrs(indio_dev);
+	kfree(indio_dev->event_interface);
+error_ret:
+
+	return ret;
+}
+
+void iio_device_unregister_eventset(struct iio_dev *indio_dev)
+{
+	if (indio_dev->event_interface == NULL)
+		return;
+	__iio_remove_event_config_attrs(indio_dev);
+	kfree(indio_dev->event_interface->group.attrs);
+	kfree(indio_dev->event_interface);
+}
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
new file mode 100644
index 0000000..0f582df
--- /dev/null
+++ b/drivers/iio/industrialio-trigger.c
@@ -0,0 +1,509 @@
+/* The industrial I/O core, trigger handling functions
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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/idr.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include "iio_core.h"
+#include "iio_core_trigger.h"
+#include <linux/iio/trigger_consumer.h>
+
+/* RFC - Question of approach
+ * Make the common case (single sensor single trigger)
+ * simple by starting trigger capture from when first sensors
+ * is added.
+ *
+ * Complex simultaneous start requires use of 'hold' functionality
+ * of the trigger. (not implemented)
+ *
+ * Any other suggestions?
+ */
+
+static DEFINE_IDA(iio_trigger_ida);
+
+/* Single list of all available triggers */
+static LIST_HEAD(iio_trigger_list);
+static DEFINE_MUTEX(iio_trigger_list_lock);
+
+/**
+ * iio_trigger_read_name() - retrieve useful identifying name
+ **/
+static ssize_t iio_trigger_read_name(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct iio_trigger *trig = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", trig->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+/**
+ * iio_trigger_register_sysfs() - create a device for this trigger
+ * @trig_info:	the trigger
+ *
+ * Also adds any control attribute registered by the trigger driver
+ **/
+static int iio_trigger_register_sysfs(struct iio_trigger *trig_info)
+{
+	return sysfs_add_file_to_group(&trig_info->dev.kobj,
+				       &dev_attr_name.attr,
+				       NULL);
+}
+
+static void iio_trigger_unregister_sysfs(struct iio_trigger *trig_info)
+{
+	sysfs_remove_file_from_group(&trig_info->dev.kobj,
+					   &dev_attr_name.attr,
+					   NULL);
+}
+
+int iio_trigger_register(struct iio_trigger *trig_info)
+{
+	int ret;
+
+	trig_info->id = ida_simple_get(&iio_trigger_ida, 0, 0, GFP_KERNEL);
+	if (trig_info->id < 0) {
+		ret = trig_info->id;
+		goto error_ret;
+	}
+	/* Set the name used for the sysfs directory etc */
+	dev_set_name(&trig_info->dev, "trigger%ld",
+		     (unsigned long) trig_info->id);
+
+	ret = device_add(&trig_info->dev);
+	if (ret)
+		goto error_unregister_id;
+
+	ret = iio_trigger_register_sysfs(trig_info);
+	if (ret)
+		goto error_device_del;
+
+	/* Add to list of available triggers held by the IIO core */
+	mutex_lock(&iio_trigger_list_lock);
+	list_add_tail(&trig_info->list, &iio_trigger_list);
+	mutex_unlock(&iio_trigger_list_lock);
+
+	return 0;
+
+error_device_del:
+	device_del(&trig_info->dev);
+error_unregister_id:
+	ida_simple_remove(&iio_trigger_ida, trig_info->id);
+error_ret:
+	return ret;
+}
+EXPORT_SYMBOL(iio_trigger_register);
+
+void iio_trigger_unregister(struct iio_trigger *trig_info)
+{
+	mutex_lock(&iio_trigger_list_lock);
+	list_del(&trig_info->list);
+	mutex_unlock(&iio_trigger_list_lock);
+
+	iio_trigger_unregister_sysfs(trig_info);
+	ida_simple_remove(&iio_trigger_ida, trig_info->id);
+	/* Possible issue in here */
+	device_unregister(&trig_info->dev);
+}
+EXPORT_SYMBOL(iio_trigger_unregister);
+
+static struct iio_trigger *iio_trigger_find_by_name(const char *name,
+						    size_t len)
+{
+	struct iio_trigger *trig = NULL, *iter;
+
+	mutex_lock(&iio_trigger_list_lock);
+	list_for_each_entry(iter, &iio_trigger_list, list)
+		if (sysfs_streq(iter->name, name)) {
+			trig = iter;
+			break;
+		}
+	mutex_unlock(&iio_trigger_list_lock);
+
+	return trig;
+}
+
+void iio_trigger_poll(struct iio_trigger *trig, s64 time)
+{
+	int i;
+	if (!trig->use_count)
+		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
+			if (trig->subirqs[i].enabled) {
+				trig->use_count++;
+				generic_handle_irq(trig->subirq_base + i);
+			}
+}
+EXPORT_SYMBOL(iio_trigger_poll);
+
+irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private)
+{
+	iio_trigger_poll(private, iio_get_time_ns());
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll);
+
+void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time)
+{
+	int i;
+	if (!trig->use_count)
+		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
+			if (trig->subirqs[i].enabled) {
+				trig->use_count++;
+				handle_nested_irq(trig->subirq_base + i);
+			}
+}
+EXPORT_SYMBOL(iio_trigger_poll_chained);
+
+void iio_trigger_notify_done(struct iio_trigger *trig)
+{
+	trig->use_count--;
+	if (trig->use_count == 0 && trig->ops && trig->ops->try_reenable)
+		if (trig->ops->try_reenable(trig))
+			/* Missed and interrupt so launch new poll now */
+			iio_trigger_poll(trig, 0);
+}
+EXPORT_SYMBOL(iio_trigger_notify_done);
+
+/* Trigger Consumer related functions */
+static int iio_trigger_get_irq(struct iio_trigger *trig)
+{
+	int ret;
+	mutex_lock(&trig->pool_lock);
+	ret = bitmap_find_free_region(trig->pool,
+				      CONFIG_IIO_CONSUMERS_PER_TRIGGER,
+				      ilog2(1));
+	mutex_unlock(&trig->pool_lock);
+	if (ret >= 0)
+		ret += trig->subirq_base;
+
+	return ret;
+}
+
+static void iio_trigger_put_irq(struct iio_trigger *trig, int irq)
+{
+	mutex_lock(&trig->pool_lock);
+	clear_bit(irq - trig->subirq_base, trig->pool);
+	mutex_unlock(&trig->pool_lock);
+}
+
+/* Complexity in here.  With certain triggers (datardy) an acknowledgement
+ * may be needed if the pollfuncs do not include the data read for the
+ * triggering device.
+ * This is not currently handled.  Alternative of not enabling trigger unless
+ * the relevant function is in there may be the best option.
+ */
+/* Worth protecting against double additions?*/
+static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
+					struct iio_poll_func *pf)
+{
+	int ret = 0;
+	bool notinuse
+		= bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+
+	/* Prevent the module being removed whilst attached to a trigger */
+	__module_get(pf->indio_dev->info->driver_module);
+	pf->irq = iio_trigger_get_irq(trig);
+	ret = request_threaded_irq(pf->irq, pf->h, pf->thread,
+				   pf->type, pf->name,
+				   pf);
+	if (ret < 0) {
+		module_put(pf->indio_dev->info->driver_module);
+		return ret;
+	}
+
+	if (trig->ops && trig->ops->set_trigger_state && notinuse) {
+		ret = trig->ops->set_trigger_state(trig, true);
+		if (ret < 0)
+			module_put(pf->indio_dev->info->driver_module);
+	}
+
+	return ret;
+}
+
+static int iio_trigger_dettach_poll_func(struct iio_trigger *trig,
+					 struct iio_poll_func *pf)
+{
+	int ret = 0;
+	bool no_other_users
+		= (bitmap_weight(trig->pool,
+				 CONFIG_IIO_CONSUMERS_PER_TRIGGER)
+		   == 1);
+	if (trig->ops && trig->ops->set_trigger_state && no_other_users) {
+		ret = trig->ops->set_trigger_state(trig, false);
+		if (ret)
+			goto error_ret;
+	}
+	iio_trigger_put_irq(trig, pf->irq);
+	free_irq(pf->irq, pf);
+	module_put(pf->indio_dev->info->driver_module);
+
+error_ret:
+	return ret;
+}
+
+irqreturn_t iio_pollfunc_store_time(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	pf->timestamp = iio_get_time_ns();
+	return IRQ_WAKE_THREAD;
+}
+EXPORT_SYMBOL(iio_pollfunc_store_time);
+
+struct iio_poll_func
+*iio_alloc_pollfunc(irqreturn_t (*h)(int irq, void *p),
+		    irqreturn_t (*thread)(int irq, void *p),
+		    int type,
+		    struct iio_dev *indio_dev,
+		    const char *fmt,
+		    ...)
+{
+	va_list vargs;
+	struct iio_poll_func *pf;
+
+	pf = kmalloc(sizeof *pf, GFP_KERNEL);
+	if (pf == NULL)
+		return NULL;
+	va_start(vargs, fmt);
+	pf->name = kvasprintf(GFP_KERNEL, fmt, vargs);
+	va_end(vargs);
+	if (pf->name == NULL) {
+		kfree(pf);
+		return NULL;
+	}
+	pf->h = h;
+	pf->thread = thread;
+	pf->type = type;
+	pf->indio_dev = indio_dev;
+
+	return pf;
+}
+EXPORT_SYMBOL_GPL(iio_alloc_pollfunc);
+
+void iio_dealloc_pollfunc(struct iio_poll_func *pf)
+{
+	kfree(pf->name);
+	kfree(pf);
+}
+EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc);
+
+/**
+ * iio_trigger_read_current() - trigger consumer sysfs query which trigger
+ *
+ * For trigger consumers the current_trigger interface allows the trigger
+ * used by the device to be queried.
+ **/
+static ssize_t iio_trigger_read_current(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+
+	if (indio_dev->trig)
+		return sprintf(buf, "%s\n", indio_dev->trig->name);
+	return 0;
+}
+
+/**
+ * iio_trigger_write_current() trigger consumer sysfs set current trigger
+ *
+ * For trigger consumers the current_trigger interface allows the trigger
+ * used for this device to be specified at run time based on the triggers
+ * name.
+ **/
+static ssize_t iio_trigger_write_current(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf,
+					 size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_trigger *oldtrig = indio_dev->trig;
+	struct iio_trigger *trig;
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
+		mutex_unlock(&indio_dev->mlock);
+		return -EBUSY;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	trig = iio_trigger_find_by_name(buf, len);
+	if (oldtrig == trig)
+		return len;
+
+	if (trig && indio_dev->info->validate_trigger) {
+		ret = indio_dev->info->validate_trigger(indio_dev, trig);
+		if (ret)
+			return ret;
+	}
+
+	if (trig && trig->ops && trig->ops->validate_device) {
+		ret = trig->ops->validate_device(trig, indio_dev);
+		if (ret)
+			return ret;
+	}
+
+	indio_dev->trig = trig;
+
+	if (oldtrig && indio_dev->trig != oldtrig)
+		iio_trigger_put(oldtrig);
+	if (indio_dev->trig)
+		iio_trigger_get(indio_dev->trig);
+
+	return len;
+}
+
+static DEVICE_ATTR(current_trigger, S_IRUGO | S_IWUSR,
+		   iio_trigger_read_current,
+		   iio_trigger_write_current);
+
+static struct attribute *iio_trigger_consumer_attrs[] = {
+	&dev_attr_current_trigger.attr,
+	NULL,
+};
+
+static const struct attribute_group iio_trigger_consumer_attr_group = {
+	.name = "trigger",
+	.attrs = iio_trigger_consumer_attrs,
+};
+
+static void iio_trig_release(struct device *device)
+{
+	struct iio_trigger *trig = to_iio_trigger(device);
+	int i;
+
+	if (trig->subirq_base) {
+		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
+			irq_modify_status(trig->subirq_base + i,
+					  IRQ_NOAUTOEN,
+					  IRQ_NOREQUEST | IRQ_NOPROBE);
+			irq_set_chip(trig->subirq_base + i,
+				     NULL);
+			irq_set_handler(trig->subirq_base + i,
+					NULL);
+		}
+
+		irq_free_descs(trig->subirq_base,
+			       CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+	}
+	kfree(trig->name);
+	kfree(trig);
+}
+
+static struct device_type iio_trig_type = {
+	.release = iio_trig_release,
+};
+
+static void iio_trig_subirqmask(struct irq_data *d)
+{
+	struct irq_chip *chip = irq_data_get_irq_chip(d);
+	struct iio_trigger *trig
+		= container_of(chip,
+			       struct iio_trigger, subirq_chip);
+	trig->subirqs[d->irq - trig->subirq_base].enabled = false;
+}
+
+static void iio_trig_subirqunmask(struct irq_data *d)
+{
+	struct irq_chip *chip = irq_data_get_irq_chip(d);
+	struct iio_trigger *trig
+		= container_of(chip,
+			       struct iio_trigger, subirq_chip);
+	trig->subirqs[d->irq - trig->subirq_base].enabled = true;
+}
+
+struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
+{
+	va_list vargs;
+	struct iio_trigger *trig;
+	trig = kzalloc(sizeof *trig, GFP_KERNEL);
+	if (trig) {
+		int i;
+		trig->dev.type = &iio_trig_type;
+		trig->dev.bus = &iio_bus_type;
+		device_initialize(&trig->dev);
+		dev_set_drvdata(&trig->dev, (void *)trig);
+
+		mutex_init(&trig->pool_lock);
+		trig->subirq_base
+			= irq_alloc_descs(-1, 0,
+					  CONFIG_IIO_CONSUMERS_PER_TRIGGER,
+					  0);
+		if (trig->subirq_base < 0) {
+			kfree(trig);
+			return NULL;
+		}
+		va_start(vargs, fmt);
+		trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
+		va_end(vargs);
+		if (trig->name == NULL) {
+			irq_free_descs(trig->subirq_base,
+				       CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+			kfree(trig);
+			return NULL;
+		}
+		trig->subirq_chip.name = trig->name;
+		trig->subirq_chip.irq_mask = &iio_trig_subirqmask;
+		trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask;
+		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
+			irq_set_chip(trig->subirq_base + i,
+				     &trig->subirq_chip);
+			irq_set_handler(trig->subirq_base + i,
+					&handle_simple_irq);
+			irq_modify_status(trig->subirq_base + i,
+					  IRQ_NOREQUEST | IRQ_NOAUTOEN,
+					  IRQ_NOPROBE);
+		}
+		get_device(&trig->dev);
+	}
+	return trig;
+}
+EXPORT_SYMBOL(iio_trigger_alloc);
+
+void iio_trigger_free(struct iio_trigger *trig)
+{
+	if (trig)
+		put_device(&trig->dev);
+}
+EXPORT_SYMBOL(iio_trigger_free);
+
+void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
+{
+	indio_dev->groups[indio_dev->groupcounter++] =
+		&iio_trigger_consumer_attr_group;
+}
+
+void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
+{
+	/* Clean up and associated but not attached triggers references */
+	if (indio_dev->trig)
+		iio_trigger_put(indio_dev->trig);
+}
+
+int iio_triggered_buffer_postenable(struct iio_dev *indio_dev)
+{
+	return iio_trigger_attach_poll_func(indio_dev->trig,
+					    indio_dev->pollfunc);
+}
+EXPORT_SYMBOL(iio_triggered_buffer_postenable);
+
+int iio_triggered_buffer_predisable(struct iio_dev *indio_dev)
+{
+	return iio_trigger_dettach_poll_func(indio_dev->trig,
+					     indio_dev->pollfunc);
+}
+EXPORT_SYMBOL(iio_triggered_buffer_predisable);
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
new file mode 100644
index 0000000..9226458
--- /dev/null
+++ b/drivers/iio/inkern.c
@@ -0,0 +1,293 @@
+/* The industrial I/O core in kernel channel mapping
+ *
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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/err.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+#include <linux/iio/iio.h>
+#include "iio_core.h"
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/consumer.h>
+
+struct iio_map_internal {
+	struct iio_dev *indio_dev;
+	struct iio_map *map;
+	struct list_head l;
+};
+
+static LIST_HEAD(iio_map_list);
+static DEFINE_MUTEX(iio_map_list_lock);
+
+int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps)
+{
+	int i = 0, ret = 0;
+	struct iio_map_internal *mapi;
+
+	if (maps == NULL)
+		return 0;
+
+	mutex_lock(&iio_map_list_lock);
+	while (maps[i].consumer_dev_name != NULL) {
+		mapi = kzalloc(sizeof(*mapi), GFP_KERNEL);
+		if (mapi == NULL) {
+			ret = -ENOMEM;
+			goto error_ret;
+		}
+		mapi->map = &maps[i];
+		mapi->indio_dev = indio_dev;
+		list_add(&mapi->l, &iio_map_list);
+		i++;
+	}
+error_ret:
+	mutex_unlock(&iio_map_list_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_map_array_register);
+
+
+/* Assumes the exact same array (e.g. memory locations)
+ * used at unregistration as used at registration rather than
+ * more complex checking of contents.
+ */
+int iio_map_array_unregister(struct iio_dev *indio_dev,
+			     struct iio_map *maps)
+{
+	int i = 0, ret = 0;
+	bool found_it;
+	struct iio_map_internal *mapi;
+
+	if (maps == NULL)
+		return 0;
+
+	mutex_lock(&iio_map_list_lock);
+	while (maps[i].consumer_dev_name != NULL) {
+		found_it = false;
+		list_for_each_entry(mapi, &iio_map_list, l)
+			if (&maps[i] == mapi->map) {
+				list_del(&mapi->l);
+				kfree(mapi);
+				found_it = true;
+				break;
+			}
+		if (found_it == false) {
+			ret = -ENODEV;
+			goto error_ret;
+		}
+		i++;
+	}
+error_ret:
+	mutex_unlock(&iio_map_list_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_map_array_unregister);
+
+static const struct iio_chan_spec
+*iio_chan_spec_from_name(const struct iio_dev *indio_dev,
+			 const char *name)
+{
+	int i;
+	const struct iio_chan_spec *chan = NULL;
+
+	for (i = 0; i < indio_dev->num_channels; i++)
+		if (indio_dev->channels[i].datasheet_name &&
+		    strcmp(name, indio_dev->channels[i].datasheet_name) == 0) {
+			chan = &indio_dev->channels[i];
+			break;
+		}
+	return chan;
+}
+
+
+struct iio_channel *iio_st_channel_get(const char *name,
+				       const char *channel_name)
+{
+	struct iio_map_internal *c_i = NULL, *c = NULL;
+	struct iio_channel *channel;
+
+	if (name == NULL && channel_name == NULL)
+		return ERR_PTR(-ENODEV);
+
+	/* first find matching entry the channel map */
+	mutex_lock(&iio_map_list_lock);
+	list_for_each_entry(c_i, &iio_map_list, l) {
+		if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) ||
+		    (channel_name &&
+		     strcmp(channel_name, c_i->map->consumer_channel) != 0))
+			continue;
+		c = c_i;
+		get_device(&c->indio_dev->dev);
+		break;
+	}
+	mutex_unlock(&iio_map_list_lock);
+	if (c == NULL)
+		return ERR_PTR(-ENODEV);
+
+	channel = kmalloc(sizeof(*channel), GFP_KERNEL);
+	if (channel == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	channel->indio_dev = c->indio_dev;
+
+	if (c->map->adc_channel_label)
+		channel->channel =
+			iio_chan_spec_from_name(channel->indio_dev,
+						c->map->adc_channel_label);
+
+	return channel;
+}
+EXPORT_SYMBOL_GPL(iio_st_channel_get);
+
+void iio_st_channel_release(struct iio_channel *channel)
+{
+	put_device(&channel->indio_dev->dev);
+	kfree(channel);
+}
+EXPORT_SYMBOL_GPL(iio_st_channel_release);
+
+struct iio_channel *iio_st_channel_get_all(const char *name)
+{
+	struct iio_channel *chans;
+	struct iio_map_internal *c = NULL;
+	int nummaps = 0;
+	int mapind = 0;
+	int i, ret;
+
+	if (name == NULL)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&iio_map_list_lock);
+	/* first count the matching maps */
+	list_for_each_entry(c, &iio_map_list, l)
+		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
+			continue;
+		else
+			nummaps++;
+
+	if (nummaps == 0) {
+		ret = -ENODEV;
+		goto error_ret;
+	}
+
+	/* NULL terminated array to save passing size */
+	chans = kzalloc(sizeof(*chans)*(nummaps + 1), GFP_KERNEL);
+	if (chans == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	/* for each map fill in the chans element */
+	list_for_each_entry(c, &iio_map_list, l) {
+		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
+			continue;
+		chans[mapind].indio_dev = c->indio_dev;
+		chans[mapind].channel =
+			iio_chan_spec_from_name(chans[mapind].indio_dev,
+						c->map->adc_channel_label);
+		if (chans[mapind].channel == NULL) {
+			ret = -EINVAL;
+			put_device(&chans[mapind].indio_dev->dev);
+			goto error_free_chans;
+		}
+		get_device(&chans[mapind].indio_dev->dev);
+		mapind++;
+	}
+	mutex_unlock(&iio_map_list_lock);
+	if (mapind == 0) {
+		ret = -ENODEV;
+		goto error_free_chans;
+	}
+	return chans;
+
+error_free_chans:
+	for (i = 0; i < nummaps; i++)
+		if (chans[i].indio_dev)
+			put_device(&chans[i].indio_dev->dev);
+	kfree(chans);
+error_ret:
+	mutex_unlock(&iio_map_list_lock);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(iio_st_channel_get_all);
+
+void iio_st_channel_release_all(struct iio_channel *channels)
+{
+	struct iio_channel *chan = &channels[0];
+
+	while (chan->indio_dev) {
+		put_device(&chan->indio_dev->dev);
+		chan++;
+	}
+	kfree(channels);
+}
+EXPORT_SYMBOL_GPL(iio_st_channel_release_all);
+
+int iio_st_read_channel_raw(struct iio_channel *chan, int *val)
+{
+	int val2, ret;
+
+	mutex_lock(&chan->indio_dev->info_exist_lock);
+	if (chan->indio_dev->info == NULL) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
+					      val, &val2, 0);
+err_unlock:
+	mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_st_read_channel_raw);
+
+int iio_st_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
+{
+	int ret;
+
+	mutex_lock(&chan->indio_dev->info_exist_lock);
+	if (chan->indio_dev->info == NULL) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	ret = chan->indio_dev->info->read_raw(chan->indio_dev,
+					      chan->channel,
+					      val, val2,
+					      IIO_CHAN_INFO_SCALE);
+err_unlock:
+	mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_st_read_channel_scale);
+
+int iio_st_get_channel_type(struct iio_channel *chan,
+			    enum iio_chan_type *type)
+{
+	int ret = 0;
+	/* Need to verify underlying driver has not gone away */
+
+	mutex_lock(&chan->indio_dev->info_exist_lock);
+	if (chan->indio_dev->info == NULL) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	*type = chan->channel->type;
+err_unlock:
+	mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_st_get_channel_type);
diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
new file mode 100644
index 0000000..6bf9d05
--- /dev/null
+++ b/drivers/iio/kfifo_buf.c
@@ -0,0 +1,150 @@
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/kfifo.h>
+#include <linux/mutex.h>
+#include <linux/iio/kfifo_buf.h>
+
+struct iio_kfifo {
+	struct iio_buffer buffer;
+	struct kfifo kf;
+	int update_needed;
+};
+
+#define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer)
+
+static inline int __iio_allocate_kfifo(struct iio_kfifo *buf,
+				int bytes_per_datum, int length)
+{
+	if ((length == 0) || (bytes_per_datum == 0))
+		return -EINVAL;
+
+	__iio_update_buffer(&buf->buffer, bytes_per_datum, length);
+	return kfifo_alloc(&buf->kf, bytes_per_datum*length, GFP_KERNEL);
+}
+
+static int iio_request_update_kfifo(struct iio_buffer *r)
+{
+	int ret = 0;
+	struct iio_kfifo *buf = iio_to_kfifo(r);
+
+	if (!buf->update_needed)
+		goto error_ret;
+	kfifo_free(&buf->kf);
+	ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
+				   buf->buffer.length);
+error_ret:
+	return ret;
+}
+
+static int iio_get_length_kfifo(struct iio_buffer *r)
+{
+	return r->length;
+}
+
+static IIO_BUFFER_ENABLE_ATTR;
+static IIO_BUFFER_LENGTH_ATTR;
+
+static struct attribute *iio_kfifo_attributes[] = {
+	&dev_attr_length.attr,
+	&dev_attr_enable.attr,
+	NULL,
+};
+
+static struct attribute_group iio_kfifo_attribute_group = {
+	.attrs = iio_kfifo_attributes,
+	.name = "buffer",
+};
+
+static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r)
+{
+	return r->bytes_per_datum;
+}
+
+static int iio_mark_update_needed_kfifo(struct iio_buffer *r)
+{
+	struct iio_kfifo *kf = iio_to_kfifo(r);
+	kf->update_needed = true;
+	return 0;
+}
+
+static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd)
+{
+	if (r->bytes_per_datum != bpd) {
+		r->bytes_per_datum = bpd;
+		iio_mark_update_needed_kfifo(r);
+	}
+	return 0;
+}
+
+static int iio_set_length_kfifo(struct iio_buffer *r, int length)
+{
+	if (r->length != length) {
+		r->length = length;
+		iio_mark_update_needed_kfifo(r);
+	}
+	return 0;
+}
+
+static int iio_store_to_kfifo(struct iio_buffer *r,
+			      u8 *data,
+			      s64 timestamp)
+{
+	int ret;
+	struct iio_kfifo *kf = iio_to_kfifo(r);
+	ret = kfifo_in(&kf->kf, data, r->bytes_per_datum);
+	if (ret != r->bytes_per_datum)
+		return -EBUSY;
+	return 0;
+}
+
+static int iio_read_first_n_kfifo(struct iio_buffer *r,
+			   size_t n, char __user *buf)
+{
+	int ret, copied;
+	struct iio_kfifo *kf = iio_to_kfifo(r);
+
+	if (n < r->bytes_per_datum)
+		return -EINVAL;
+
+	n = rounddown(n, r->bytes_per_datum);
+	ret = kfifo_to_user(&kf->kf, buf, n, &copied);
+
+	return copied;
+}
+
+static const struct iio_buffer_access_funcs kfifo_access_funcs = {
+	.store_to = &iio_store_to_kfifo,
+	.read_first_n = &iio_read_first_n_kfifo,
+	.request_update = &iio_request_update_kfifo,
+	.get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo,
+	.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
+	.get_length = &iio_get_length_kfifo,
+	.set_length = &iio_set_length_kfifo,
+};
+
+struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
+{
+	struct iio_kfifo *kf;
+
+	kf = kzalloc(sizeof *kf, GFP_KERNEL);
+	if (!kf)
+		return NULL;
+	kf->update_needed = true;
+	iio_buffer_init(&kf->buffer);
+	kf->buffer.attrs = &iio_kfifo_attribute_group;
+	kf->buffer.access = &kfifo_access_funcs;
+
+	return &kf->buffer;
+}
+EXPORT_SYMBOL(iio_kfifo_allocate);
+
+void iio_kfifo_free(struct iio_buffer *r)
+{
+	kfree(iio_to_kfifo(r));
+}
+EXPORT_SYMBOL(iio_kfifo_free);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 33259798..55f7e57 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -25,10 +25,6 @@
 
 if INPUT
 
-config INPUT_OF_MATRIX_KEYMAP
-	depends on USE_OF
-	bool
-
 config INPUT_FF_MEMLESS
 	tristate "Support for memoryless force-feedback devices"
 	help
@@ -68,6 +64,19 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called sparse-keymap.
 
+config INPUT_MATRIXKMAP
+	tristate "Matrix keymap support library"
+	help
+	  Say Y here if you are using a driver for an input
+	  device that uses matrix keymap. This option is only
+	  useful for out-of-tree drivers since in-tree drivers
+	  select it automatically.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called matrix-keymap.
+
 comment "Userland interfaces"
 
 config INPUT_MOUSEDEV
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index b173a13a..5ca3f63 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -10,6 +10,7 @@
 obj-$(CONFIG_INPUT_FF_MEMLESS)	+= ff-memless.o
 obj-$(CONFIG_INPUT_POLLDEV)	+= input-polldev.o
 obj-$(CONFIG_INPUT_SPARSEKMAP)	+= sparse-keymap.o
+obj-$(CONFIG_INPUT_MATRIXKMAP)	+= matrix-keymap.o
 
 obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev.o
 obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o
@@ -24,4 +25,3 @@
 obj-$(CONFIG_INPUT_MISC)	+= misc/
 
 obj-$(CONFIG_INPUT_APMPOWER)	+= apm-power.o
-obj-$(CONFIG_INPUT_OF_MATRIX_KEYMAP) += of_keymap.o
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 4b2e10d..6c58bff 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -180,7 +180,10 @@
 
 static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
 {
-	if (evdev->grab != client)
+	struct evdev_client *grab = rcu_dereference_protected(evdev->grab,
+					lockdep_is_held(&evdev->mutex));
+
+	if (grab != client)
 		return  -EINVAL;
 
 	rcu_assign_pointer(evdev->grab, NULL);
@@ -259,8 +262,7 @@
 	struct evdev *evdev = client->evdev;
 
 	mutex_lock(&evdev->mutex);
-	if (evdev->grab == client)
-		evdev_ungrab(evdev, client);
+	evdev_ungrab(evdev, client);
 	mutex_unlock(&evdev->mutex);
 
 	evdev_detach_client(evdev, client);
@@ -343,7 +345,7 @@
 	struct input_event event;
 	int retval = 0;
 
-	if (count < input_event_size())
+	if (count != 0 && count < input_event_size())
 		return -EINVAL;
 
 	retval = mutex_lock_interruptible(&evdev->mutex);
@@ -355,7 +357,8 @@
 		goto out;
 	}
 
-	do {
+	while (retval + input_event_size() <= count) {
+
 		if (input_event_from_user(buffer + retval, &event)) {
 			retval = -EFAULT;
 			goto out;
@@ -364,7 +367,7 @@
 
 		input_inject_event(&evdev->handle,
 				   event.type, event.code, event.value);
-	} while (retval + input_event_size() <= count);
+	}
 
  out:
 	mutex_unlock(&evdev->mutex);
@@ -395,35 +398,49 @@
 	struct evdev_client *client = file->private_data;
 	struct evdev *evdev = client->evdev;
 	struct input_event event;
-	int retval = 0;
+	size_t read = 0;
+	int error;
 
-	if (count < input_event_size())
+	if (count != 0 && count < input_event_size())
 		return -EINVAL;
 
-	if (!(file->f_flags & O_NONBLOCK)) {
-		retval = wait_event_interruptible(evdev->wait,
-				client->packet_head != client->tail ||
-				!evdev->exist);
-		if (retval)
-			return retval;
+	for (;;) {
+		if (!evdev->exist)
+			return -ENODEV;
+
+		if (client->packet_head == client->tail &&
+		    (file->f_flags & O_NONBLOCK))
+			return -EAGAIN;
+
+		/*
+		 * count == 0 is special - no IO is done but we check
+		 * for error conditions (see above).
+		 */
+		if (count == 0)
+			break;
+
+		while (read + input_event_size() <= count &&
+		       evdev_fetch_next_event(client, &event)) {
+
+			if (input_event_to_user(buffer + read, &event))
+				return -EFAULT;
+
+			read += input_event_size();
+		}
+
+		if (read)
+			break;
+
+		if (!(file->f_flags & O_NONBLOCK)) {
+			error = wait_event_interruptible(evdev->wait,
+					client->packet_head != client->tail ||
+					!evdev->exist);
+			if (error)
+				return error;
+		}
 	}
 
-	if (!evdev->exist)
-		return -ENODEV;
-
-	while (retval + input_event_size() <= count &&
-	       evdev_fetch_next_event(client, &event)) {
-
-		if (input_event_to_user(buffer + retval, &event))
-			return -EFAULT;
-
-		retval += input_event_size();
-	}
-
-	if (retval == 0 && (file->f_flags & O_NONBLOCK))
-		return -EAGAIN;
-
-	return retval;
+	return read;
 }
 
 /* No kernel lock - fine */
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index 117a59a..5f55885 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -31,8 +31,7 @@
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/jiffies.h>
-
-#include "fixp-arith.h"
+#include <linux/fixp-arith.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Anssi Hannula <anssi.hannula@gmail.com>");
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index 422aa0a..daceafe 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -125,15 +125,4 @@
         .remove =       __devexit_p(emu_remove),
 };
 
-static int __init emu_init(void)
-{
-	return pci_register_driver(&emu_driver);
-}
-
-static void __exit emu_exit(void)
-{
-	pci_unregister_driver(&emu_driver);
-}
-
-module_init(emu_init);
-module_exit(emu_exit);
+module_pci_driver(emu_driver);
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index a3b70ff..48ad382 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -144,6 +144,7 @@
 	{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0  },
 	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
 
 static struct pci_driver fm801_gp_driver = {
 	.name =		"FM801_gameport",
@@ -152,20 +153,7 @@
 	.remove =	__devexit_p(fm801_gp_remove),
 };
 
-static int __init fm801_gp_init(void)
-{
-	return pci_register_driver(&fm801_gp_driver);
-}
-
-static void __exit fm801_gp_exit(void)
-{
-	pci_unregister_driver(&fm801_gp_driver);
-}
-
-module_init(fm801_gp_init);
-module_exit(fm801_gp_exit);
-
-MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
+module_pci_driver(fm801_gp_driver);
 
 MODULE_DESCRIPTION("FM801 gameport driver");
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index 1639ab2..85bc8dc 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -413,15 +413,4 @@
 	.disconnect	= a3d_disconnect,
 };
 
-static int __init a3d_init(void)
-{
-	return gameport_register_driver(&a3d_drv);
-}
-
-static void __exit a3d_exit(void)
-{
-	gameport_unregister_driver(&a3d_drv);
-}
-
-module_init(a3d_init);
-module_exit(a3d_exit);
+module_gameport_driver(a3d_drv);
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index b992fbf..0cbfd2d 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -557,10 +557,6 @@
 	kfree(port);
 }
 
-/*
- * The gameport device structure.
- */
-
 static struct gameport_driver adi_drv = {
 	.driver		= {
 		.name	= "adi",
@@ -570,15 +566,4 @@
 	.disconnect	= adi_disconnect,
 };
 
-static int __init adi_init(void)
-{
-	return gameport_register_driver(&adi_drv);
-}
-
-static void __exit adi_exit(void)
-{
-	gameport_unregister_driver(&adi_drv);
-}
-
-module_init(adi_init);
-module_exit(adi_exit);
+module_gameport_driver(adi_drv);
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index 3497b87..65367e4 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -261,15 +261,4 @@
 	.disconnect	= cobra_disconnect,
 };
 
-static int __init cobra_init(void)
-{
-	return gameport_register_driver(&cobra_drv);
-}
-
-static void __exit cobra_exit(void)
-{
-	gameport_unregister_driver(&cobra_drv);
-}
-
-module_init(cobra_init);
-module_exit(cobra_exit);
+module_gameport_driver(cobra_drv);
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index 0536b1b..ab1cf28 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -373,15 +373,4 @@
 	.disconnect	= gf2k_disconnect,
 };
 
-static int __init gf2k_init(void)
-{
-	return gameport_register_driver(&gf2k_drv);
-}
-
-static void __exit gf2k_exit(void)
-{
-	gameport_unregister_driver(&gf2k_drv);
-}
-
-module_init(gf2k_init);
-module_exit(gf2k_exit);
+module_gameport_driver(gf2k_drv);
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index fc55899..9e1beff 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -424,15 +424,4 @@
 	.disconnect	= grip_disconnect,
 };
 
-static int __init grip_init(void)
-{
-	return gameport_register_driver(&grip_drv);
-}
-
-static void __exit grip_exit(void)
-{
-	gameport_unregister_driver(&grip_drv);
-}
-
-module_init(grip_init);
-module_exit(grip_exit);
+module_gameport_driver(grip_drv);
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 2d47baf..c0f9c7b 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -687,15 +687,4 @@
 	.disconnect	= grip_disconnect,
 };
 
-static int __init grip_init(void)
-{
-	return gameport_register_driver(&grip_drv);
-}
-
-static void __exit grip_exit(void)
-{
-	gameport_unregister_driver(&grip_drv);
-}
-
-module_init(grip_init);
-module_exit(grip_exit);
+module_gameport_driver(grip_drv);
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index 4058d4b..55196f7 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -281,15 +281,4 @@
 	.disconnect	= guillemot_disconnect,
 };
 
-static int __init guillemot_init(void)
-{
-	return gameport_register_driver(&guillemot_drv);
-}
-
-static void __exit guillemot_exit(void)
-{
-	gameport_unregister_driver(&guillemot_drv);
-}
-
-module_init(guillemot_init);
-module_exit(guillemot_exit);
+module_gameport_driver(guillemot_drv);
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 405febd..daeeb4c 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -317,7 +317,8 @@
 			break;
 
 	if (i == 20) { /* 5 seconds */
-		err("Timeout waiting for response from device.");
+		dev_err(&input_dev->dev,
+			"Timeout waiting for response from device.\n");
 		error = -ENODEV;
 		goto fail;
 	}
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index a17b500..08f98f2 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -257,7 +257,8 @@
 
 		status = usb_submit_urb(iforce->ctrl, GFP_ATOMIC);
 		if (status) {
-			err("usb_submit_urb failed %d", status);
+			dev_err(&iforce->intf->dev,
+				"usb_submit_urb failed %d\n", status);
 			return -1;
 		}
 
@@ -265,12 +266,14 @@
 			iforce->ctrl->status != -EINPROGRESS, HZ);
 
 		if (iforce->ctrl->status) {
-			dbg("iforce->ctrl->status = %d", iforce->ctrl->status);
+			dev_dbg(&iforce->intf->dev,
+				"iforce->ctrl->status = %d\n",
+				iforce->ctrl->status);
 			usb_unlink_urb(iforce->ctrl);
 			return -1;
 		}
 #else
-		dbg("iforce_get_id_packet: iforce->bus = USB!");
+		printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n");
 #endif
 		}
 		break;
@@ -289,12 +292,15 @@
 			return -1;
 		}
 #else
-		err("iforce_get_id_packet: iforce->bus = SERIO!");
+		dev_err(&iforce->dev->dev,
+			"iforce_get_id_packet: iforce->bus = SERIO!\n");
 #endif
 		break;
 
 	default:
-		err("iforce_get_id_packet: iforce->bus = %d", iforce->bus);
+		dev_err(&iforce->dev->dev,
+			"iforce_get_id_packet: iforce->bus = %d\n",
+			iforce->bus);
 		break;
 	}
 
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 6c96631..d96aa27 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -64,7 +64,7 @@
 
 	if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
 		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
-		dev_warn(&iforce->dev->dev, "usb_submit_urb failed %d\n", n);
+		dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n);
 	}
 
 	/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -76,6 +76,7 @@
 static void iforce_usb_irq(struct urb *urb)
 {
 	struct iforce *iforce = urb->context;
+	struct device *dev = &iforce->intf->dev;
 	int status;
 
 	switch (urb->status) {
@@ -86,11 +87,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, urb->status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
 		return;
 	default:
-		dbg("%s - urb has status of: %d", __func__, urb->status);
+		dev_dbg(dev, "%s - urb has status of: %d\n",
+			__func__, urb->status);
 		goto exit;
 	}
 
@@ -100,8 +102,8 @@
 exit:
 	status = usb_submit_urb (urb, GFP_ATOMIC);
 	if (status)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __func__, status);
+		dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+			__func__, status);
 }
 
 static void iforce_usb_out(struct urb *urb)
@@ -110,7 +112,8 @@
 
 	if (urb->status) {
 		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
-		dbg("urb->status %d, exiting", urb->status);
+		dev_dbg(&iforce->intf->dev, "urb->status %d, exiting\n",
+			urb->status);
 		return;
 	}
 
@@ -155,6 +158,7 @@
 
 	iforce->bus = IFORCE_USB;
 	iforce->usbdev = dev;
+	iforce->intf = intf;
 
 	iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
 	iforce->cr.wIndex = 0;
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index 9f494b7..b1d7d9b 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -115,6 +115,7 @@
 #endif
 #ifdef CONFIG_JOYSTICK_IFORCE_USB
 	struct usb_device *usbdev;	/* USB transfer */
+	struct usb_interface *intf;
 	struct urb *irq, *out, *ctrl;
 	struct usb_ctrlrequest cr;
 #endif
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index 16fb19d..88c2262 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -311,15 +311,4 @@
 	.disconnect	= interact_disconnect,
 };
 
-static int __init interact_init(void)
-{
-	return gameport_register_driver(&interact_drv);
-}
-
-static void __exit interact_exit(void)
-{
-	gameport_unregister_driver(&interact_drv);
-}
-
-module_init(interact_init);
-module_exit(interact_exit);
+module_gameport_driver(interact_drv);
diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c
index cd894a0..7eb878b 100644
--- a/drivers/input/joystick/joydump.c
+++ b/drivers/input/joystick/joydump.c
@@ -159,15 +159,4 @@
 	.disconnect	= joydump_disconnect,
 };
 
-static int __init joydump_init(void)
-{
-	return gameport_register_driver(&joydump_drv);
-}
-
-static void __exit joydump_exit(void)
-{
-	gameport_unregister_driver(&joydump_drv);
-}
-
-module_init(joydump_init);
-module_exit(joydump_exit);
+module_gameport_driver(joydump_drv);
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index 40e4078..9fb153e 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -222,19 +222,4 @@
 	.disconnect	= magellan_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init magellan_init(void)
-{
-	return serio_register_driver(&magellan_drv);
-}
-
-static void __exit magellan_exit(void)
-{
-	serio_unregister_driver(&magellan_drv);
-}
-
-module_init(magellan_init);
-module_exit(magellan_exit);
+module_serio_driver(magellan_drv);
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index b8d8611..04c69af 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -820,15 +820,4 @@
 	.disconnect	= sw_disconnect,
 };
 
-static int __init sw_init(void)
-{
-	return gameport_register_driver(&sw_drv);
-}
-
-static void __exit sw_exit(void)
-{
-	gameport_unregister_driver(&sw_drv);
-}
-
-module_init(sw_init);
-module_exit(sw_exit);
+module_gameport_driver(sw_drv);
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index 0cd9b29..80a7b27 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -296,19 +296,4 @@
 	.disconnect	= spaceball_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init spaceball_init(void)
-{
-	return serio_register_driver(&spaceball_drv);
-}
-
-static void __exit spaceball_exit(void)
-{
-	serio_unregister_driver(&spaceball_drv);
-}
-
-module_init(spaceball_init);
-module_exit(spaceball_exit);
+module_serio_driver(spaceball_drv);
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index a694bf8..a41f291 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -237,19 +237,4 @@
 	.disconnect	= spaceorb_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init spaceorb_init(void)
-{
-	return serio_register_driver(&spaceorb_drv);
-}
-
-static void __exit spaceorb_exit(void)
-{
-	serio_unregister_driver(&spaceorb_drv);
-}
-
-module_init(spaceorb_init);
-module_exit(spaceorb_exit);
+module_serio_driver(spaceorb_drv);
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index e0db9f5..0f51a60 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -208,19 +208,4 @@
 	.disconnect	= stinger_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init stinger_init(void)
-{
-	return serio_register_driver(&stinger_drv);
-}
-
-static void __exit stinger_exit(void)
-{
-	serio_unregister_driver(&stinger_drv);
-}
-
-module_init(stinger_init);
-module_exit(stinger_exit);
+module_serio_driver(stinger_drv);
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index d6c6098..5ef9bcd 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -436,15 +436,4 @@
 	.disconnect	= tmdc_disconnect,
 };
 
-static int __init tmdc_init(void)
-{
-	return gameport_register_driver(&tmdc_drv);
-}
-
-static void __exit tmdc_exit(void)
-{
-	gameport_unregister_driver(&tmdc_drv);
-}
-
-module_init(tmdc_init);
-module_exit(tmdc_exit);
+module_gameport_driver(tmdc_drv);
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index 3f4ec73..2556a81 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -257,19 +257,4 @@
 	.disconnect	= twidjoy_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init twidjoy_init(void)
-{
-	return serio_register_driver(&twidjoy_drv);
-}
-
-static void __exit twidjoy_exit(void)
-{
-	serio_unregister_driver(&twidjoy_drv);
-}
-
-module_init(twidjoy_init);
-module_exit(twidjoy_exit);
+module_serio_driver(twidjoy_drv);
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index f72c83e..23b3071 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -217,19 +217,4 @@
 	.disconnect	= warrior_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init warrior_init(void)
-{
-	return serio_register_driver(&warrior_drv);
-}
-
-static void __exit warrior_exit(void)
-{
-	serio_unregister_driver(&warrior_drv);
-}
-
-module_init(warrior_init);
-module_exit(warrior_exit);
+module_serio_driver(warrior_drv);
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index fd7a0d5..ee16fb6 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -252,6 +252,7 @@
 struct usb_xpad {
 	struct input_dev *dev;		/* input device interface */
 	struct usb_device *udev;	/* usb device */
+	struct usb_interface *intf;	/* usb interface */
 
 	int pad_present;
 
@@ -457,6 +458,7 @@
 static void xpad_irq_in(struct urb *urb)
 {
 	struct usb_xpad *xpad = urb->context;
+	struct device *dev = &xpad->intf->dev;
 	int retval, status;
 
 	status = urb->status;
@@ -469,11 +471,11 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
 			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
+		dev_dbg(dev, "%s - nonzero urb status received: %d\n",
 			__func__, status);
 		goto exit;
 	}
@@ -492,12 +494,15 @@
 exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __func__, retval);
+		dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+			__func__, retval);
 }
 
 static void xpad_bulk_out(struct urb *urb)
 {
+	struct usb_xpad *xpad = urb->context;
+	struct device *dev = &xpad->intf->dev;
+
 	switch (urb->status) {
 	case 0:
 		/* success */
@@ -506,16 +511,20 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
 		break;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+		dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+			__func__, urb->status);
 	}
 }
 
 #if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
 static void xpad_irq_out(struct urb *urb)
 {
+	struct usb_xpad *xpad = urb->context;
+	struct device *dev = &xpad->intf->dev;
 	int retval, status;
 
 	status = urb->status;
@@ -529,19 +538,21 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__, status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__, status);
+		dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
 exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		err("%s - usb_submit_urb failed with result %d",
-		    __func__, retval);
+		dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+			__func__, retval);
 }
 
 static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
@@ -654,7 +665,8 @@
 			return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
 
 		default:
-			dbg("%s - rumble command sent to unsupported xpad type: %d",
+			dev_dbg(&xpad->dev->dev,
+				"%s - rumble command sent to unsupported xpad type: %d\n",
 				__func__, xpad->xtype);
 			return -1;
 		}
@@ -844,6 +856,7 @@
 	}
 
 	xpad->udev = udev;
+	xpad->intf = intf;
 	xpad->mapping = xpad_device[i].mapping;
 	xpad->xtype = xpad_device[i].xtype;
 
diff --git a/drivers/input/joystick/zhenhua.c b/drivers/input/joystick/zhenhua.c
index b585312..c4de438 100644
--- a/drivers/input/joystick/zhenhua.c
+++ b/drivers/input/joystick/zhenhua.c
@@ -225,19 +225,4 @@
 	.disconnect	= zhenhua_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init zhenhua_init(void)
-{
-	return serio_register_driver(&zhenhua_drv);
-}
-
-static void __exit zhenhua_exit(void)
-{
-	serio_unregister_driver(&zhenhua_drv);
-}
-
-module_init(zhenhua_init);
-module_exit(zhenhua_exit);
+module_serio_driver(zhenhua_drv);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f354813..c0e11ecc 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -166,6 +166,7 @@
 config KEYBOARD_EP93XX
 	tristate "EP93xx Matrix Keypad support"
 	depends on ARCH_EP93XX
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here to enable the matrix keypad on the Cirrus EP93XX.
 
@@ -224,6 +225,7 @@
 config KEYBOARD_TCA8418
 	tristate "TCA8418 Keypad Support"
 	depends on I2C
+	select INPUT_MATRIXKMAP
 	help
 	  This driver implements basic keypad functionality
 	  for keys connected through TCA8418 keypad decoder.
@@ -240,6 +242,7 @@
 config KEYBOARD_MATRIX
 	tristate "GPIO driven matrix keypad support"
 	depends on GENERIC_GPIO
+	select INPUT_MATRIXKMAP
 	help
 	  Enable support for GPIO driven matrix keypad.
 
@@ -309,6 +312,17 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called lm8323.
 
+config KEYBOARD_LM8333
+	tristate "LM8333 keypad chip"
+	depends on I2C
+	select INPUT_MATRIXKMAP
+	help
+	  If you say yes here you get support for the National Semiconductor
+	  LM8333 keypad controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called lm8333.
+
 config KEYBOARD_LOCOMO
 	tristate "LoCoMo Keyboard Support"
 	depends on SHARP_LOCOMO
@@ -366,6 +380,7 @@
 config KEYBOARD_IMX
 	tristate "IMX keypad support"
 	depends on ARCH_MXC
+	select INPUT_MATRIXKMAP
 	help
 	  Enable support for IMX keypad port.
 
@@ -384,6 +399,7 @@
 config KEYBOARD_NOMADIK
 	tristate "ST-Ericsson Nomadik SKE keyboard"
 	depends on PLAT_NOMADIK
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to use a keypad provided on the SKE controller
 	  used on the Ux500 and Nomadik platforms
@@ -394,7 +410,7 @@
 config KEYBOARD_TEGRA
 	tristate "NVIDIA Tegra internal matrix keyboard controller support"
 	depends on ARCH_TEGRA
-	select INPUT_OF_MATRIX_KEYMAP if USE_OF
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to use a matrix keyboard connected directly
 	  to the internal keyboard controller on Tegra SoCs.
@@ -432,6 +448,7 @@
 config KEYBOARD_PMIC8XXX
 	tristate "Qualcomm PMIC8XXX keypad support"
 	depends on MFD_PM8XXX
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to enable the driver for the PMIC8XXX
 	  keypad provided as a reference design from Qualcomm. This is intended
@@ -443,6 +460,7 @@
 config KEYBOARD_SAMSUNG
 	tristate "Samsung keypad support"
 	depends on HAVE_CLK
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to use the keypad on your Samsung mobile
 	  device.
@@ -485,6 +503,7 @@
 config KEYBOARD_STMPE
 	tristate "STMPE keypad support"
 	depends on MFD_STMPE
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to use the keypad controller on STMPE I/O
 	  expanders.
@@ -505,6 +524,7 @@
 config KEYBOARD_OMAP
 	tristate "TI OMAP keypad support"
 	depends on (ARCH_OMAP1 || ARCH_OMAP2)
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to use the OMAP keypad.
 
@@ -512,9 +532,10 @@
 	  module will be called omap-keypad.
 
 config KEYBOARD_OMAP4
-	tristate "TI OMAP4 keypad support"
+	tristate "TI OMAP4+ keypad support"
+	select INPUT_MATRIXKMAP
 	help
-	  Say Y here if you want to use the OMAP4 keypad.
+	  Say Y here if you want to use the OMAP4+ keypad.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called omap4-keypad.
@@ -522,6 +543,7 @@
 config KEYBOARD_SPEAR
 	tristate "ST SPEAR keyboard support"
 	depends on PLAT_SPEAR
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to use the SPEAR keyboard.
 
@@ -531,6 +553,7 @@
 config KEYBOARD_TC3589X
 	tristate "TC3589X Keypad support"
 	depends on MFD_TC3589X
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to use the keypad controller on
 	  TC35892/3 I/O expander.
@@ -541,6 +564,7 @@
 config KEYBOARD_TNETV107X
 	tristate "TI TNETV107X keypad support"
 	depends on ARCH_DAVINCI_TNETV107X
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to use the TNETV107X keypad.
 
@@ -550,6 +574,7 @@
 config KEYBOARD_TWL4030
 	tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
 	depends on TWL4030_CORE
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if your board use the keypad controller on
 	  TWL4030 family chips.  It's safe to say enable this
@@ -573,6 +598,7 @@
 config KEYBOARD_W90P910
 	tristate "W90P910 Matrix Keypad support"
 	depends on ARCH_W90X900
+	select INPUT_MATRIXKMAP
 	help
 	  Say Y here to enable the matrix keypad on evaluation board
 	  based on W90P910.
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index df7061f..b03b024 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -24,6 +24,7 @@
 obj-$(CONFIG_KEYBOARD_HP7XX)		+= jornada720_kbd.o
 obj-$(CONFIG_KEYBOARD_LKKBD)		+= lkkbd.o
 obj-$(CONFIG_KEYBOARD_LM8323)		+= lm8323.o
+obj-$(CONFIG_KEYBOARD_LM8333)		+= lm8333.o
 obj-$(CONFIG_KEYBOARD_LOCOMO)		+= locomokbd.o
 obj-$(CONFIG_KEYBOARD_MAPLE)		+= maple_keyb.o
 obj-$(CONFIG_KEYBOARD_MATRIX)		+= matrix_keypad.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 39ebffa..b083bf1 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -197,6 +197,7 @@
 	kpad->gc.base = gpio_data->gpio_start;
 	kpad->gc.label = kpad->client->name;
 	kpad->gc.owner = THIS_MODULE;
+	kpad->gc.names = gpio_data->names;
 
 	mutex_init(&kpad->gpio_lock);
 
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index e05a2e7..add5ffd 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -433,7 +433,7 @@
 		if (printk_ratelimit())
 			dev_warn(&serio->dev,
 				 "Spurious %s on %s. "
-				 "Some program might be trying access hardware directly.\n",
+				 "Some program might be trying to access hardware directly.\n",
 				 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
 		goto out;
 	case ATKBD_RET_ERR:
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index 0ba69f3..c46fc81 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -182,16 +182,10 @@
 }
 
 
-#ifdef CONFIG_PM
-/*
- * NOTE: I don't know if this is correct, or will work on the ep93xx.
- *
- * None of the existing ep93xx drivers have power management support.
- * But, this is basically what the pxa27x_keypad driver does.
- */
-static int ep93xx_keypad_suspend(struct platform_device *pdev,
-				 pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int ep93xx_keypad_suspend(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
 	struct input_dev *input_dev = keypad->input_dev;
 
@@ -210,8 +204,9 @@
 	return 0;
 }
 
-static int ep93xx_keypad_resume(struct platform_device *pdev)
+static int ep93xx_keypad_resume(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
 	struct input_dev *input_dev = keypad->input_dev;
 
@@ -232,10 +227,10 @@
 
 	return 0;
 }
-#else	/* !CONFIG_PM */
-#define ep93xx_keypad_suspend	NULL
-#define ep93xx_keypad_resume	NULL
-#endif	/* !CONFIG_PM */
+#endif
+
+static SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops,
+			 ep93xx_keypad_suspend, ep93xx_keypad_resume);
 
 static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
 {
@@ -308,19 +303,16 @@
 	input_dev->open = ep93xx_keypad_open;
 	input_dev->close = ep93xx_keypad_close;
 	input_dev->dev.parent = &pdev->dev;
-	input_dev->keycode = keypad->keycodes;
-	input_dev->keycodesize = sizeof(keypad->keycodes[0]);
-	input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
 
-	input_set_drvdata(input_dev, keypad);
+	err = matrix_keypad_build_keymap(keymap_data, NULL,
+					 EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS,
+					 keypad->keycodes, input_dev);
+	if (err)
+		goto failed_free_dev;
 
-	input_dev->evbit[0] = BIT_MASK(EV_KEY);
 	if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
-		input_dev->evbit[0] |= BIT_MASK(EV_REP);
-
-	matrix_keypad_build_keymap(keymap_data, 3,
-				   input_dev->keycode, input_dev->keybit);
-	platform_set_drvdata(pdev, keypad);
+		__set_bit(EV_REP, input_dev->evbit);
+	input_set_drvdata(input_dev, keypad);
 
 	err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
 			  0, pdev->name, keypad);
@@ -331,6 +323,7 @@
 	if (err)
 		goto failed_free_irq;
 
+	platform_set_drvdata(pdev, keypad);
 	device_init_wakeup(&pdev->dev, 1);
 
 	return 0;
@@ -384,11 +377,10 @@
 	.driver		= {
 		.name	= "ep93xx-keypad",
 		.owner	= THIS_MODULE,
+		.pm	= &ep93xx_keypad_pm_ops,
 	},
 	.probe		= ep93xx_keypad_probe,
 	.remove		= __devexit_p(ep93xx_keypad_remove),
-	.suspend	= ep93xx_keypad_suspend,
-	.resume		= ep93xx_keypad_resume,
 };
 module_platform_driver(ep93xx_keypad_driver);
 
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index fed31e0..589e3c2 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -583,15 +583,4 @@
 	.interrupt	= hil_dev_interrupt
 };
 
-static int __init hil_dev_init(void)
-{
-	return serio_register_driver(&hil_serio_drv);
-}
-
-static void __exit hil_dev_exit(void)
-{
-	serio_unregister_driver(&hil_serio_drv);
-}
-
-module_init(hil_dev_init);
-module_exit(hil_dev_exit);
+module_serio_driver(hil_serio_drv);
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index fb87b3b..6ee7421 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -481,7 +481,7 @@
 	}
 
 	if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
-	   keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
+	    keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
 		dev_err(&pdev->dev,
 			"invalid key data (too many rows or colums)\n");
 		error = -EINVAL;
@@ -496,14 +496,17 @@
 	input_dev->dev.parent = &pdev->dev;
 	input_dev->open = imx_keypad_open;
 	input_dev->close = imx_keypad_close;
-	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-	input_dev->keycode = keypad->keycodes;
-	input_dev->keycodesize = sizeof(keypad->keycodes[0]);
-	input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
 
-	matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT,
-				keypad->keycodes, input_dev->keybit);
+	error = matrix_keypad_build_keymap(keymap_data, NULL,
+					   MAX_MATRIX_KEY_ROWS,
+					   MAX_MATRIX_KEY_COLS,
+					   keypad->keycodes, input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to build keymap\n");
+		goto failed_clock_put;
+	}
 
+	__set_bit(EV_REP, input_dev->evbit);
 	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 	input_set_drvdata(input_dev, keypad);
 
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index fa9bb6d..fc0a63c 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -731,19 +731,4 @@
 	.interrupt	= lkkbd_interrupt,
 };
 
-/*
- * The functions for insering/removing us as a module.
- */
-static int __init lkkbd_init(void)
-{
-	return serio_register_driver(&lkkbd_drv);
-}
-
-static void __exit lkkbd_exit(void)
-{
-	serio_unregister_driver(&lkkbd_drv);
-}
-
-module_init(lkkbd_init);
-module_exit(lkkbd_exit);
-
+module_serio_driver(lkkbd_drv);
diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
new file mode 100644
index 0000000..ca168a6
--- /dev/null
+++ b/drivers/input/keyboard/lm8333.c
@@ -0,0 +1,235 @@
+/*
+ * LM8333 keypad driver
+ * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/input/lm8333.h>
+
+#define LM8333_FIFO_READ		0x20
+#define LM8333_DEBOUNCE			0x22
+#define LM8333_READ_INT			0xD0
+#define LM8333_ACTIVE			0xE4
+#define LM8333_READ_ERROR		0xF0
+
+#define LM8333_KEYPAD_IRQ		(1 << 0)
+#define LM8333_ERROR_IRQ		(1 << 3)
+
+#define LM8333_ERROR_KEYOVR		0x04
+#define LM8333_ERROR_FIFOOVR		0x40
+
+#define LM8333_FIFO_TRANSFER_SIZE	16
+
+#define LM8333_NUM_ROWS		8
+#define LM8333_NUM_COLS		16
+#define LM8333_ROW_SHIFT	4
+
+struct lm8333 {
+	struct i2c_client *client;
+	struct input_dev *input;
+	unsigned short keycodes[LM8333_NUM_ROWS << LM8333_ROW_SHIFT];
+};
+
+/* The accessors try twice because the first access may be needed for wakeup */
+#define LM8333_READ_RETRIES 2
+
+int lm8333_read8(struct lm8333 *lm8333, u8 cmd)
+{
+	int retries = 0, ret;
+
+	do {
+		ret = i2c_smbus_read_byte_data(lm8333->client, cmd);
+	} while (ret < 0 && retries++ < LM8333_READ_RETRIES);
+
+	return ret;
+}
+
+int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val)
+{
+	int retries = 0, ret;
+
+	do {
+		ret = i2c_smbus_write_byte_data(lm8333->client, cmd, val);
+	} while (ret < 0 && retries++ < LM8333_READ_RETRIES);
+
+	return ret;
+}
+
+int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf)
+{
+	int retries = 0, ret;
+
+	do {
+		ret = i2c_smbus_read_i2c_block_data(lm8333->client,
+						    cmd, len, buf);
+	} while (ret < 0 && retries++ < LM8333_READ_RETRIES);
+
+	return ret;
+}
+
+static void lm8333_key_handler(struct lm8333 *lm8333)
+{
+	struct input_dev *input = lm8333->input;
+	u8 keys[LM8333_FIFO_TRANSFER_SIZE];
+	u8 code, pressed;
+	int i, ret;
+
+	ret = lm8333_read_block(lm8333, LM8333_FIFO_READ,
+				LM8333_FIFO_TRANSFER_SIZE, keys);
+	if (ret != LM8333_FIFO_TRANSFER_SIZE) {
+		dev_err(&lm8333->client->dev,
+			"Error %d while reading FIFO\n", ret);
+		return;
+	}
+
+	for (i = 0; keys[i] && i < LM8333_FIFO_TRANSFER_SIZE; i++) {
+		pressed = keys[i] & 0x80;
+		code = keys[i] & 0x7f;
+
+		input_event(input, EV_MSC, MSC_SCAN, code);
+		input_report_key(input, lm8333->keycodes[code], pressed);
+	}
+
+	input_sync(input);
+}
+
+static irqreturn_t lm8333_irq_thread(int irq, void *data)
+{
+	struct lm8333 *lm8333 = data;
+	u8 status = lm8333_read8(lm8333, LM8333_READ_INT);
+
+	if (!status)
+		return IRQ_NONE;
+
+	if (status & LM8333_ERROR_IRQ) {
+		u8 err = lm8333_read8(lm8333, LM8333_READ_ERROR);
+
+		if (err & (LM8333_ERROR_KEYOVR | LM8333_ERROR_FIFOOVR)) {
+			u8 dummy[LM8333_FIFO_TRANSFER_SIZE];
+
+			lm8333_read_block(lm8333, LM8333_FIFO_READ,
+					LM8333_FIFO_TRANSFER_SIZE, dummy);
+		}
+		dev_err(&lm8333->client->dev, "Got error %02x\n", err);
+	}
+
+	if (status & LM8333_KEYPAD_IRQ)
+		lm8333_key_handler(lm8333);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit lm8333_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	const struct lm8333_platform_data *pdata = client->dev.platform_data;
+	struct lm8333 *lm8333;
+	struct input_dev *input;
+	int err, active_time;
+
+	if (!pdata)
+		return -EINVAL;
+
+	active_time = pdata->active_time ?: 500;
+	if (active_time / 3 <= pdata->debounce_time / 3) {
+		dev_err(&client->dev, "Active time not big enough!\n");
+		return -EINVAL;
+	}
+
+	lm8333 = kzalloc(sizeof(*lm8333), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!lm8333 || !input) {
+		err = -ENOMEM;
+		goto free_mem;
+	}
+
+	lm8333->client = client;
+	lm8333->input = input;
+
+	input->name = client->name;
+	input->dev.parent = &client->dev;
+	input->id.bustype = BUS_I2C;
+
+	input_set_capability(input, EV_MSC, MSC_SCAN);
+
+	err = matrix_keypad_build_keymap(pdata->matrix_data, NULL,
+					 LM8333_NUM_ROWS, LM8333_NUM_COLS,
+					 lm8333->keycodes, input);
+	if (err)
+		goto free_mem;
+
+	if (pdata->debounce_time) {
+		err = lm8333_write8(lm8333, LM8333_DEBOUNCE,
+				    pdata->debounce_time / 3);
+		if (err)
+			dev_warn(&client->dev, "Unable to set debounce time\n");
+	}
+
+	if (pdata->active_time) {
+		err = lm8333_write8(lm8333, LM8333_ACTIVE,
+				    pdata->active_time / 3);
+		if (err)
+			dev_warn(&client->dev, "Unable to set active time\n");
+	}
+
+	err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   "lm8333", lm8333);
+	if (err)
+		goto free_mem;
+
+	err = input_register_device(input);
+	if (err)
+		goto free_irq;
+
+	i2c_set_clientdata(client, lm8333);
+	return 0;
+
+ free_irq:
+	free_irq(client->irq, lm8333);
+ free_mem:
+	input_free_device(input);
+	kfree(lm8333);
+	return err;
+}
+
+static int __devexit lm8333_remove(struct i2c_client *client)
+{
+	struct lm8333 *lm8333 = i2c_get_clientdata(client);
+
+	free_irq(client->irq, lm8333);
+	input_unregister_device(lm8333->input);
+	kfree(lm8333);
+
+	return 0;
+}
+
+static const struct i2c_device_id lm8333_id[] = {
+	{ "lm8333", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm8333_id);
+
+static struct i2c_driver lm8333_driver = {
+	.driver = {
+		.name		= "lm8333",
+		.owner		= THIS_MODULE,
+	},
+	.probe		= lm8333_probe,
+	.remove		= __devexit_p(lm8333_remove),
+	.id_table	= lm8333_id,
+};
+module_i2c_driver(lm8333_driver);
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("LM8333 keyboard driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 9b223d7..18b7237 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -27,7 +27,6 @@
 struct matrix_keypad {
 	const struct matrix_keypad_platform_data *pdata;
 	struct input_dev *input_dev;
-	unsigned short *keycodes;
 	unsigned int row_shift;
 
 	DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS);
@@ -38,6 +37,8 @@
 	bool scan_pending;
 	bool stopped;
 	bool gpio_all_disabled;
+
+	unsigned short keycodes[];
 };
 
 /*
@@ -224,7 +225,7 @@
 	disable_row_irqs(keypad);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
 {
 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
@@ -293,16 +294,16 @@
 
 	return 0;
 }
-
-static const SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
-				matrix_keypad_suspend, matrix_keypad_resume);
 #endif
 
-static int __devinit init_matrix_gpio(struct platform_device *pdev,
-					struct matrix_keypad *keypad)
+static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
+			 matrix_keypad_suspend, matrix_keypad_resume);
+
+static int __devinit matrix_keypad_init_gpio(struct platform_device *pdev,
+					     struct matrix_keypad *keypad)
 {
 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
-	int i, err = -EINVAL;
+	int i, err;
 
 	/* initialized strobe lines as outputs, activated */
 	for (i = 0; i < pdata->num_col_gpios; i++) {
@@ -348,8 +349,7 @@
 					"matrix-keypad", keypad);
 			if (err) {
 				dev_err(&pdev->dev,
-					"Unable to acquire interrupt "
-					"for GPIO line %i\n",
+					"Unable to acquire interrupt for GPIO line %i\n",
 					pdata->row_gpios[i]);
 				goto err_free_irqs;
 			}
@@ -375,14 +375,33 @@
 	return err;
 }
 
+static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
+{
+	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+	int i;
+
+	if (pdata->clustered_irq > 0) {
+		free_irq(pdata->clustered_irq, keypad);
+	} else {
+		for (i = 0; i < pdata->num_row_gpios; i++)
+			free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
+	}
+
+	for (i = 0; i < pdata->num_row_gpios; i++)
+		gpio_free(pdata->row_gpios[i]);
+
+	for (i = 0; i < pdata->num_col_gpios; i++)
+		gpio_free(pdata->col_gpios[i]);
+}
+
 static int __devinit matrix_keypad_probe(struct platform_device *pdev)
 {
 	const struct matrix_keypad_platform_data *pdata;
 	const struct matrix_keymap_data *keymap_data;
 	struct matrix_keypad *keypad;
 	struct input_dev *input_dev;
-	unsigned short *keycodes;
 	unsigned int row_shift;
+	size_t keymap_size;
 	int err;
 
 	pdata = pdev->dev.platform_data;
@@ -398,20 +417,18 @@
 	}
 
 	row_shift = get_count_order(pdata->num_col_gpios);
-
-	keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL);
-	keycodes = kzalloc((pdata->num_row_gpios << row_shift) *
-				sizeof(*keycodes),
-			   GFP_KERNEL);
+	keymap_size = (pdata->num_row_gpios << row_shift) *
+			sizeof(keypad->keycodes[0]);
+	keypad = kzalloc(sizeof(struct matrix_keypad) + keymap_size,
+			 GFP_KERNEL);
 	input_dev = input_allocate_device();
-	if (!keypad || !keycodes || !input_dev) {
+	if (!keypad || !input_dev) {
 		err = -ENOMEM;
 		goto err_free_mem;
 	}
 
 	keypad->input_dev = input_dev;
 	keypad->pdata = pdata;
-	keypad->keycodes = keycodes;
 	keypad->row_shift = row_shift;
 	keypad->stopped = true;
 	INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
@@ -420,38 +437,38 @@
 	input_dev->name		= pdev->name;
 	input_dev->id.bustype	= BUS_HOST;
 	input_dev->dev.parent	= &pdev->dev;
-	input_dev->evbit[0]	= BIT_MASK(EV_KEY);
-	if (!pdata->no_autorepeat)
-		input_dev->evbit[0] |= BIT_MASK(EV_REP);
 	input_dev->open		= matrix_keypad_start;
 	input_dev->close	= matrix_keypad_stop;
 
-	input_dev->keycode	= keycodes;
-	input_dev->keycodesize	= sizeof(*keycodes);
-	input_dev->keycodemax	= pdata->num_row_gpios << row_shift;
+	err = matrix_keypad_build_keymap(keymap_data, NULL,
+					 pdata->num_row_gpios,
+					 pdata->num_col_gpios,
+					 keypad->keycodes, input_dev);
+	if (err)
+		goto err_free_mem;
 
-	matrix_keypad_build_keymap(keymap_data, row_shift,
-				   input_dev->keycode, input_dev->keybit);
-
+	if (!pdata->no_autorepeat)
+		__set_bit(EV_REP, input_dev->evbit);
 	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 	input_set_drvdata(input_dev, keypad);
 
-	err = init_matrix_gpio(pdev, keypad);
+	err = matrix_keypad_init_gpio(pdev, keypad);
 	if (err)
 		goto err_free_mem;
 
 	err = input_register_device(keypad->input_dev);
 	if (err)
-		goto err_free_mem;
+		goto err_free_gpio;
 
 	device_init_wakeup(&pdev->dev, pdata->wakeup);
 	platform_set_drvdata(pdev, keypad);
 
 	return 0;
 
+err_free_gpio:
+	matrix_keypad_free_gpio(keypad);
 err_free_mem:
 	input_free_device(input_dev);
-	kfree(keycodes);
 	kfree(keypad);
 	return err;
 }
@@ -459,29 +476,15 @@
 static int __devexit matrix_keypad_remove(struct platform_device *pdev)
 {
 	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
-	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
-	int i;
 
 	device_init_wakeup(&pdev->dev, 0);
 
-	if (pdata->clustered_irq > 0) {
-		free_irq(pdata->clustered_irq, keypad);
-	} else {
-		for (i = 0; i < pdata->num_row_gpios; i++)
-			free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
-	}
-
-	for (i = 0; i < pdata->num_row_gpios; i++)
-		gpio_free(pdata->row_gpios[i]);
-
-	for (i = 0; i < pdata->num_col_gpios; i++)
-		gpio_free(pdata->col_gpios[i]);
-
+	matrix_keypad_free_gpio(keypad);
 	input_unregister_device(keypad->input_dev);
-	platform_set_drvdata(pdev, NULL);
-	kfree(keypad->keycodes);
 	kfree(keypad);
 
+	platform_set_drvdata(pdev, NULL);
+
 	return 0;
 }
 
@@ -491,9 +494,7 @@
 	.driver		= {
 		.name	= "matrix-keypad",
 		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
 		.pm	= &matrix_keypad_pm_ops,
-#endif
 	},
 };
 module_platform_driver(matrix_keypad_driver);
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index 48d1cab..f971898 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -166,15 +166,4 @@
 	.disconnect	= nkbd_disconnect,
 };
 
-static int __init nkbd_init(void)
-{
-	return serio_register_driver(&nkbd_drv);
-}
-
-static void __exit nkbd_exit(void)
-{
-	serio_unregister_driver(&nkbd_drv);
-}
-
-module_init(nkbd_init);
-module_exit(nkbd_exit);
+module_serio_driver(nkbd_drv);
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
index 101e245..4ea4341 100644
--- a/drivers/input/keyboard/nomadik-ske-keypad.c
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -39,7 +39,8 @@
 #define SKE_KPRISA	(0x1 << 2)
 
 #define SKE_KEYPAD_ROW_SHIFT	3
-#define SKE_KPD_KEYMAP_SIZE	(8 * 8)
+#define SKE_KPD_NUM_ROWS	8
+#define SKE_KPD_NUM_COLS	8
 
 /* keypad auto scan registers */
 #define SKE_ASR0	0x20
@@ -63,7 +64,7 @@
 	void __iomem *reg_base;
 	struct input_dev *input;
 	const struct ske_keypad_platform_data *board;
-	unsigned short keymap[SKE_KPD_KEYMAP_SIZE];
+	unsigned short keymap[SKE_KPD_NUM_ROWS * SKE_KPD_NUM_COLS];
 	struct clk *clk;
 	spinlock_t ske_keypad_lock;
 };
@@ -261,19 +262,18 @@
 	input->name = "ux500-ske-keypad";
 	input->dev.parent = &pdev->dev;
 
-	input->keycode = keypad->keymap;
-	input->keycodesize = sizeof(keypad->keymap[0]);
-	input->keycodemax = ARRAY_SIZE(keypad->keymap);
+	error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
+					   SKE_KPD_NUM_ROWS, SKE_KPD_NUM_COLS,
+					   keypad->keymap, input);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to build keymap\n");
+		goto err_iounmap;
+	}
 
 	input_set_capability(input, EV_MSC, MSC_SCAN);
-
-	__set_bit(EV_KEY, input->evbit);
 	if (!plat->no_autorepeat)
 		__set_bit(EV_REP, input->evbit);
 
-	matrix_keypad_build_keymap(plat->keymap_data, SKE_KEYPAD_ROW_SHIFT,
-			input->keycode, input->keybit);
-
 	clk_enable(keypad->clk);
 
 	/* go through board initialization helpers */
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 6b630d9..a0222db 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -61,6 +61,7 @@
 	unsigned int cols;
 	unsigned long delay;
 	unsigned int debounce;
+	unsigned short keymap[];
 };
 
 static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
@@ -316,13 +317,6 @@
 	if (!cpu_is_omap24xx())
 		omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
 
-	input_dev->keycode      = &omap_kp[1];
-	input_dev->keycodesize  = sizeof(unsigned short);
-	input_dev->keycodemax   = keycodemax;
-
-	if (pdata->rep)
-		__set_bit(EV_REP, input_dev->evbit);
-
 	if (pdata->delay)
 		omap_kp->delay = pdata->delay;
 
@@ -371,9 +365,6 @@
 		goto err2;
 
 	/* setup input device */
-	__set_bit(EV_KEY, input_dev->evbit);
-	matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
-			input_dev->keycode, input_dev->keybit);
 	input_dev->name = "omap-keypad";
 	input_dev->phys = "omap-keypad/input0";
 	input_dev->dev.parent = &pdev->dev;
@@ -383,6 +374,15 @@
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
 
+	if (pdata->rep)
+		__set_bit(EV_REP, input_dev->evbit);
+
+	ret = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
+					 pdata->rows, pdata->cols,
+					 omap_kp->keymap, input_dev);
+	if (ret < 0)
+		goto err3;
+
 	ret = input_register_device(omap_kp->input);
 	if (ret < 0) {
 		printk(KERN_ERR "Unable to register omap-keypad input device\n");
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index e809ac0..aed5f69 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -68,19 +68,52 @@
 
 #define OMAP4_MASK_IRQSTATUSDISABLE	0xFFFF
 
+enum {
+	KBD_REVISION_OMAP4 = 0,
+	KBD_REVISION_OMAP5,
+};
+
 struct omap4_keypad {
 	struct input_dev *input;
 
 	void __iomem *base;
-	int irq;
+	unsigned int irq;
 
 	unsigned int rows;
 	unsigned int cols;
+	u32 reg_offset;
+	u32 irqreg_offset;
 	unsigned int row_shift;
 	unsigned char key_state[8];
 	unsigned short keymap[];
 };
 
+static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset)
+{
+	return __raw_readl(keypad_data->base +
+				keypad_data->reg_offset + offset);
+}
+
+static void kbd_writel(struct omap4_keypad *keypad_data, u32 offset, u32 value)
+{
+	__raw_writel(value,
+		     keypad_data->base + keypad_data->reg_offset + offset);
+}
+
+static int kbd_read_irqreg(struct omap4_keypad *keypad_data, u32 offset)
+{
+	return __raw_readl(keypad_data->base +
+				keypad_data->irqreg_offset + offset);
+}
+
+static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
+			     u32 offset, u32 value)
+{
+	__raw_writel(value,
+		     keypad_data->base + keypad_data->irqreg_offset + offset);
+}
+
+
 /* Interrupt handler */
 static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
 {
@@ -91,12 +124,11 @@
 	u32 *new_state = (u32 *) key_state;
 
 	/* Disable interrupts */
-	__raw_writel(OMAP4_VAL_IRQDISABLE,
-		     keypad_data->base + OMAP4_KBD_IRQENABLE);
+	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+			 OMAP4_VAL_IRQDISABLE);
 
-	*new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0);
-	*(new_state + 1) = __raw_readl(keypad_data->base
-						+ OMAP4_KBD_FULLCODE63_32);
+	*new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
+	*(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
 
 	for (row = 0; row < keypad_data->rows; row++) {
 		changed = key_state[row] ^ keypad_data->key_state[row];
@@ -121,12 +153,13 @@
 		sizeof(keypad_data->key_state));
 
 	/* clear pending interrupts */
-	__raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
-			keypad_data->base + OMAP4_KBD_IRQSTATUS);
+	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
+			 kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
 
 	/* enable interrupts */
-	__raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
-			keypad_data->base + OMAP4_KBD_IRQENABLE);
+	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+		OMAP4_DEF_IRQENABLE_EVENTEN |
+				OMAP4_DEF_IRQENABLE_LONGKEY);
 
 	return IRQ_HANDLED;
 }
@@ -139,16 +172,17 @@
 
 	disable_irq(keypad_data->irq);
 
-	__raw_writel(OMAP4_VAL_FUNCTIONALCFG,
-			keypad_data->base + OMAP4_KBD_CTRL);
-	__raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
-			keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
-	__raw_writel(OMAP4_VAL_IRQDISABLE,
-			keypad_data->base + OMAP4_KBD_IRQSTATUS);
-	__raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
-			keypad_data->base + OMAP4_KBD_IRQENABLE);
-	__raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
-			keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
+	kbd_writel(keypad_data, OMAP4_KBD_CTRL,
+			OMAP4_VAL_FUNCTIONALCFG);
+	kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME,
+			OMAP4_VAL_DEBOUNCINGTIME);
+	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
+			OMAP4_VAL_IRQDISABLE);
+	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+			OMAP4_DEF_IRQENABLE_EVENTEN |
+				OMAP4_DEF_IRQENABLE_LONGKEY);
+	kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE,
+			OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA);
 
 	enable_irq(keypad_data->irq);
 
@@ -162,12 +196,12 @@
 	disable_irq(keypad_data->irq);
 
 	/* Disable interrupts */
-	__raw_writel(OMAP4_VAL_IRQDISABLE,
-		     keypad_data->base + OMAP4_KBD_IRQENABLE);
+	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+			 OMAP4_VAL_IRQDISABLE);
 
 	/* clear pending interrupts */
-	__raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
-			keypad_data->base + OMAP4_KBD_IRQSTATUS);
+	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
+			 kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
 
 	enable_irq(keypad_data->irq);
 
@@ -182,6 +216,7 @@
 	struct resource *res;
 	resource_size_t size;
 	unsigned int row_shift, max_keys;
+	int rev;
 	int irq;
 	int error;
 
@@ -241,11 +276,40 @@
 	keypad_data->rows = pdata->rows;
 	keypad_data->cols = pdata->cols;
 
+	/*
+	* Enable clocks for the keypad module so that we can read
+	* revision register.
+	*/
+	pm_runtime_enable(&pdev->dev);
+	error = pm_runtime_get_sync(&pdev->dev);
+	if (error) {
+		dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+		goto err_unmap;
+	}
+	rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION);
+	rev &= 0x03 << 30;
+	rev >>= 30;
+	switch (rev) {
+	case KBD_REVISION_OMAP4:
+		keypad_data->reg_offset = 0x00;
+		keypad_data->irqreg_offset = 0x00;
+		break;
+	case KBD_REVISION_OMAP5:
+		keypad_data->reg_offset = 0x10;
+		keypad_data->irqreg_offset = 0x0c;
+		break;
+	default:
+		dev_err(&pdev->dev,
+			"Keypad reports unsupported revision %d", rev);
+		error = -EINVAL;
+		goto err_pm_put_sync;
+	}
+
 	/* input device allocation */
 	keypad_data->input = input_dev = input_allocate_device();
 	if (!input_dev) {
 		error = -ENOMEM;
-		goto err_unmap;
+		goto err_pm_put_sync;
 	}
 
 	input_dev->name = pdev->name;
@@ -258,20 +322,19 @@
 	input_dev->open = omap4_keypad_open;
 	input_dev->close = omap4_keypad_close;
 
-	input_dev->keycode	= keypad_data->keymap;
-	input_dev->keycodesize	= sizeof(keypad_data->keymap[0]);
-	input_dev->keycodemax	= max_keys;
+	error = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
+					   pdata->rows, pdata->cols,
+					   keypad_data->keymap, input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to build keymap\n");
+		goto err_free_input;
+	}
 
-	__set_bit(EV_KEY, input_dev->evbit);
 	__set_bit(EV_REP, input_dev->evbit);
-
 	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 
 	input_set_drvdata(input_dev, keypad_data);
 
-	matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
-			input_dev->keycode, input_dev->keybit);
-
 	error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
 			     IRQF_TRIGGER_RISING,
 			     "omap4-keypad", keypad_data);
@@ -280,7 +343,7 @@
 		goto err_free_input;
 	}
 
-	pm_runtime_enable(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
 
 	error = input_register_device(keypad_data->input);
 	if (error < 0) {
@@ -296,6 +359,8 @@
 	free_irq(keypad_data->irq, keypad_data);
 err_free_input:
 	input_free_device(input_dev);
+err_pm_put_sync:
+	pm_runtime_put_sync(&pdev->dev);
 err_unmap:
 	iounmap(keypad_data->base);
 err_release_mem:
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 01a1c9f..52c3465 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -626,21 +626,21 @@
 	kp->input->id.product	= 0x0001;
 	kp->input->id.vendor	= 0x0001;
 
-	kp->input->evbit[0]	= BIT_MASK(EV_KEY);
-
-	if (pdata->rep)
-		__set_bit(EV_REP, kp->input->evbit);
-
-	kp->input->keycode	= kp->keycodes;
-	kp->input->keycodemax	= PM8XXX_MATRIX_MAX_SIZE;
-	kp->input->keycodesize	= sizeof(kp->keycodes);
 	kp->input->open		= pmic8xxx_kp_open;
 	kp->input->close	= pmic8xxx_kp_close;
 
-	matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT,
-					kp->input->keycode, kp->input->keybit);
+	rc = matrix_keypad_build_keymap(keymap_data, NULL,
+					PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS,
+					kp->keycodes, kp->input);
+	if (rc) {
+		dev_err(&pdev->dev, "failed to build keymap\n");
+		goto err_get_irq;
+	}
 
+	if (pdata->rep)
+		__set_bit(EV_REP, kp->input->evbit);
 	input_set_capability(kp->input, EV_MSC, MSC_SCAN);
+
 	input_set_drvdata(kp->input, kp);
 
 	/* initialize keypad state */
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 2391ae8..a061ba6 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -454,23 +454,23 @@
 	input_dev->name = pdev->name;
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->dev.parent = &pdev->dev;
-	input_set_drvdata(input_dev, keypad);
 
 	input_dev->open = samsung_keypad_open;
 	input_dev->close = samsung_keypad_close;
 
-	input_dev->evbit[0] = BIT_MASK(EV_KEY);
-	if (!pdata->no_autorepeat)
-		input_dev->evbit[0] |= BIT_MASK(EV_REP);
+	error = matrix_keypad_build_keymap(keymap_data, NULL,
+					   pdata->rows, pdata->cols,
+					   keypad->keycodes, input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to build keymap\n");
+		goto err_put_clk;
+	}
 
 	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+	if (!pdata->no_autorepeat)
+		__set_bit(EV_REP, input_dev->evbit);
 
-	input_dev->keycode = keypad->keycodes;
-	input_dev->keycodesize = sizeof(keypad->keycodes[0]);
-	input_dev->keycodemax = pdata->rows << row_shift;
-
-	matrix_keypad_build_keymap(keymap_data, row_shift,
-			input_dev->keycode, input_dev->keybit);
+	input_set_drvdata(input_dev, keypad);
 
 	keypad->irq = platform_get_irq(pdev, 0);
 	if (keypad->irq < 0) {
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 3b6b528..6f287f7 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -19,6 +19,7 @@
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_wakeup.h>
 #include <linux/slab.h>
@@ -49,7 +50,9 @@
 #define KEY_VALUE	0x00FFFFFF
 #define ROW_MASK	0xF0
 #define COLUMN_MASK	0x0F
-#define ROW_SHIFT	4
+#define NUM_ROWS	16
+#define NUM_COLS	16
+
 #define KEY_MATRIX_SHIFT	6
 
 struct spear_kbd {
@@ -60,7 +63,8 @@
 	unsigned int irq;
 	unsigned int mode;
 	unsigned short last_key;
-	unsigned short keycodes[256];
+	unsigned short keycodes[NUM_ROWS * NUM_COLS];
+	bool rep;
 };
 
 static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
@@ -136,27 +140,49 @@
 	kbd->last_key = KEY_RESERVED;
 }
 
+#ifdef CONFIG_OF
+static int __devinit spear_kbd_parse_dt(struct platform_device *pdev,
+                                        struct spear_kbd *kbd)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int error;
+	u32 val;
+
+	if (!np) {
+		dev_err(&pdev->dev, "Missing DT data\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_bool(np, "autorepeat"))
+		kbd->rep = true;
+
+	error = of_property_read_u32(np, "st,mode", &val);
+	if (error) {
+		dev_err(&pdev->dev, "DT: Invalid or missing mode\n");
+		return error;
+	}
+
+	kbd->mode = val;
+	return 0;
+}
+#else
+static inline int spear_kbd_parse_dt(struct platform_device *pdev,
+				     struct spear_kbd *kbd)
+{
+	return -ENOSYS;
+}
+#endif
+
 static int __devinit spear_kbd_probe(struct platform_device *pdev)
 {
-	const struct kbd_platform_data *pdata = pdev->dev.platform_data;
-	const struct matrix_keymap_data *keymap;
+	struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL;
 	struct spear_kbd *kbd;
 	struct input_dev *input_dev;
 	struct resource *res;
 	int irq;
 	int error;
 
-	if (!pdata) {
-		dev_err(&pdev->dev, "Invalid platform data\n");
-		return -EINVAL;
-	}
-
-	keymap = pdata->keymap;
-	if (!keymap) {
-		dev_err(&pdev->dev, "no keymap defined\n");
-		return -EINVAL;
-	}
-
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "no keyboard resource defined\n");
@@ -179,7 +205,15 @@
 
 	kbd->input = input_dev;
 	kbd->irq = irq;
-	kbd->mode = pdata->mode;
+
+	if (!pdata) {
+		error = spear_kbd_parse_dt(pdev, kbd);
+		if (error)
+			goto err_free_mem;
+	} else {
+		kbd->mode = pdata->mode;
+		kbd->rep = pdata->rep;
+	}
 
 	kbd->res = request_mem_region(res->start, resource_size(res),
 				      pdev->name);
@@ -212,18 +246,17 @@
 	input_dev->open = spear_kbd_open;
 	input_dev->close = spear_kbd_close;
 
-	__set_bit(EV_KEY, input_dev->evbit);
-	if (pdata->rep)
+	error = matrix_keypad_build_keymap(keymap, NULL, NUM_ROWS, NUM_COLS,
+					   kbd->keycodes, input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to build keymap\n");
+		goto err_put_clk;
+	}
+
+	if (kbd->rep)
 		__set_bit(EV_REP, input_dev->evbit);
 	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 
-	input_dev->keycode = kbd->keycodes;
-	input_dev->keycodesize = sizeof(kbd->keycodes[0]);
-	input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes);
-
-	matrix_keypad_build_keymap(keymap, ROW_SHIFT,
-			input_dev->keycode, input_dev->keybit);
-
 	input_set_drvdata(input_dev, kbd);
 
 	error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd);
@@ -317,6 +350,14 @@
 
 static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume);
 
+#ifdef CONFIG_OF
+static const struct of_device_id spear_kbd_id_table[] = {
+	{ .compatible = "st,spear300-kbd" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, spear_kbd_id_table);
+#endif
+
 static struct platform_driver spear_kbd_driver = {
 	.probe		= spear_kbd_probe,
 	.remove		= __devexit_p(spear_kbd_remove),
@@ -324,6 +365,7 @@
 		.name	= "keyboard",
 		.owner	= THIS_MODULE,
 		.pm	= &spear_kbd_pm_ops,
+		.of_match_table = of_match_ptr(spear_kbd_id_table),
 	},
 };
 module_platform_driver(spear_kbd_driver);
diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c
index 9397cf9..470a877 100644
--- a/drivers/input/keyboard/stmpe-keypad.c
+++ b/drivers/input/keyboard/stmpe-keypad.c
@@ -289,19 +289,17 @@
 	input->id.bustype = BUS_I2C;
 	input->dev.parent = &pdev->dev;
 
-	input_set_capability(input, EV_MSC, MSC_SCAN);
+	ret = matrix_keypad_build_keymap(plat->keymap_data, NULL,
+					 STMPE_KEYPAD_MAX_ROWS,
+					 STMPE_KEYPAD_MAX_COLS,
+					 keypad->keymap, input);
+	if (ret)
+		goto out_freeinput;
 
-	__set_bit(EV_KEY, input->evbit);
+	input_set_capability(input, EV_MSC, MSC_SCAN);
 	if (!plat->no_autorepeat)
 		__set_bit(EV_REP, input->evbit);
 
-	input->keycode = keypad->keymap;
-	input->keycodesize = sizeof(keypad->keymap[0]);
-	input->keycodemax = ARRAY_SIZE(keypad->keymap);
-
-	matrix_keypad_build_keymap(plat->keymap_data, STMPE_KEYPAD_ROW_SHIFT,
-				   input->keycode, input->keybit);
-
 	for (i = 0; i < plat->keymap_data->keymap_size; i++) {
 		unsigned int key = plat->keymap_data->keymap[i];
 
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c
index 7437219..cc612c5 100644
--- a/drivers/input/keyboard/stowaway.c
+++ b/drivers/input/keyboard/stowaway.c
@@ -170,15 +170,4 @@
 	.disconnect	= skbd_disconnect,
 };
 
-static int __init skbd_init(void)
-{
-	return serio_register_driver(&skbd_drv);
-}
-
-static void __exit skbd_exit(void)
-{
-	serio_unregister_driver(&skbd_drv);
-}
-
-module_init(skbd_init);
-module_exit(skbd_exit);
+module_serio_driver(skbd_drv);
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index a99a04b..5f836b1 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -369,19 +369,4 @@
 	.disconnect	= sunkbd_disconnect,
 };
 
-/*
- * The functions for insering/removing us as a module.
- */
-
-static int __init sunkbd_init(void)
-{
-	return serio_register_driver(&sunkbd_drv);
-}
-
-static void __exit sunkbd_exit(void)
-{
-	serio_unregister_driver(&sunkbd_drv);
-}
-
-module_init(sunkbd_init);
-module_exit(sunkbd_exit);
+module_serio_driver(sunkbd_drv);
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c
index 2dee3e4..7d498e6 100644
--- a/drivers/input/keyboard/tc3589x-keypad.c
+++ b/drivers/input/keyboard/tc3589x-keypad.c
@@ -78,7 +78,7 @@
  * @input:      pointer to input device object
  * @board:      keypad platform device
  * @krow:	number of rows
- * @kcol:	number of coloumns
+ * @kcol:	number of columns
  * @keymap:     matrix scan code table for keycodes
  * @keypad_stopped: holds keypad status
  */
@@ -96,21 +96,15 @@
 {
 	int ret;
 	struct tc3589x *tc3589x = keypad->tc3589x;
-	u8 settle_time = keypad->board->settle_time;
-	u8 dbounce_period = keypad->board->debounce_period;
-	u8 rows = keypad->board->krow & 0xf;	/* mask out the nibble */
-	u8 column = keypad->board->kcol & 0xf;	/* mask out the nibble */
+	const struct tc3589x_keypad_platform_data *board = keypad->board;
 
-	/* validate platform configurations */
-	if (keypad->board->kcol > TC3589x_MAX_KPCOL ||
-	    keypad->board->krow > TC3589x_MAX_KPROW ||
-	    keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE ||
-	    keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE)
+	/* validate platform configuration */
+	if (board->kcol > TC3589x_MAX_KPCOL || board->krow > TC3589x_MAX_KPROW)
 		return -EINVAL;
 
 	/* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */
 	ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE,
-			(rows << KP_ROW_SHIFT) | column);
+			(board->krow << KP_ROW_SHIFT) | board->kcol);
 	if (ret < 0)
 		return ret;
 
@@ -124,12 +118,14 @@
 		return ret;
 
 	/* Configure settle time */
-	ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time);
+	ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG,
+				board->settle_time);
 	if (ret < 0)
 		return ret;
 
 	/* Configure debounce time */
-	ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period);
+	ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE,
+				board->debounce_period);
 	if (ret < 0)
 		return ret;
 
@@ -337,23 +333,22 @@
 	input->name = pdev->name;
 	input->dev.parent = &pdev->dev;
 
-	input->keycode = keypad->keymap;
-	input->keycodesize = sizeof(keypad->keymap[0]);
-	input->keycodemax = ARRAY_SIZE(keypad->keymap);
-
 	input->open = tc3589x_keypad_open;
 	input->close = tc3589x_keypad_close;
 
-	input_set_drvdata(input, keypad);
+	error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
+					   TC3589x_MAX_KPROW, TC3589x_MAX_KPCOL,
+					   keypad->keymap, input);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to build keymap\n");
+		goto err_free_mem;
+	}
 
 	input_set_capability(input, EV_MSC, MSC_SCAN);
-
-	__set_bit(EV_KEY, input->evbit);
 	if (!plat->no_autorepeat)
 		__set_bit(EV_REP, input->evbit);
 
-	matrix_keypad_build_keymap(plat->keymap_data, 0x3,
-			input->keycode, input->keybit);
+	input_set_drvdata(input, keypad);
 
 	error = request_threaded_irq(irq, NULL,
 			tc3589x_keypad_irq, plat->irqtype,
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 958ec10..5f87b28 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -342,21 +342,20 @@
 	input->id.product = 0x001;
 	input->id.version = 0x0001;
 
-	input->keycode     = keypad_data->keymap;
-	input->keycodesize = sizeof(keypad_data->keymap[0]);
-	input->keycodemax  = max_keys;
+	error = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
+					   pdata->rows, pdata->cols,
+					   keypad_data->keymap, input);
+	if (error) {
+		dev_dbg(&client->dev, "Failed to build keymap\n");
+		goto fail2;
+	}
 
-	__set_bit(EV_KEY, input->evbit);
 	if (pdata->rep)
 		__set_bit(EV_REP, input->evbit);
-
 	input_set_capability(input, EV_MSC, MSC_SCAN);
 
 	input_set_drvdata(input, keypad_data);
 
-	matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
-			input->keycode, input->keybit);
-
 	if (pdata->irq_is_gpio)
 		client->irq = gpio_to_irq(client->irq);
 
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index fe4ac95..4ffe64d 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -619,8 +619,8 @@
 }
 
 #ifdef CONFIG_OF
-static struct tegra_kbc_platform_data * __devinit
-tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
+static struct tegra_kbc_platform_data * __devinit tegra_kbc_dt_parse_pdata(
+	struct platform_device *pdev)
 {
 	struct tegra_kbc_platform_data *pdata;
 	struct device_node *np = pdev->dev.of_node;
@@ -660,10 +660,6 @@
 		pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
 	}
 
-	pdata->keymap_data = matrix_keyboard_of_fill_keymap(np, "linux,keymap");
-
-	/* FIXME: Add handling of linux,fn-keymap here */
-
 	return pdata;
 }
 #else
@@ -674,10 +670,36 @@
 }
 #endif
 
+static int __devinit tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
+{
+	const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+	const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
+	unsigned int keymap_rows = KBC_MAX_KEY;
+	int retval;
+
+	if (keymap_data && pdata->use_fn_map)
+		keymap_rows *= 2;
+
+	retval = matrix_keypad_build_keymap(keymap_data, NULL,
+					    keymap_rows, KBC_MAX_COL,
+					    kbc->keycode, kbc->idev);
+	if (retval == -ENOSYS || retval == -ENOENT) {
+		/*
+		 * If there is no OF support in kernel or keymap
+		 * property is missing, use default keymap.
+		 */
+		retval = matrix_keypad_build_keymap(
+					&tegra_kbc_default_keymap_data, NULL,
+					keymap_rows, KBC_MAX_COL,
+					kbc->keycode, kbc->idev);
+	}
+
+	return retval;
+}
+
 static int __devinit tegra_kbc_probe(struct platform_device *pdev)
 {
 	const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
-	const struct matrix_keymap_data *keymap_data;
 	struct tegra_kbc *kbc;
 	struct input_dev *input_dev;
 	struct resource *res;
@@ -757,29 +779,26 @@
 	kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
 	kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS);
 
+	kbc->wakeup_key = pdata->wakeup_key;
+	kbc->use_fn_map = pdata->use_fn_map;
+	kbc->use_ghost_filter = pdata->use_ghost_filter;
+
 	input_dev->name = pdev->name;
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->dev.parent = &pdev->dev;
 	input_dev->open = tegra_kbc_open;
 	input_dev->close = tegra_kbc_close;
 
-	input_set_drvdata(input_dev, kbc);
+	err = tegra_kbd_setup_keymap(kbc);
+	if (err) {
+		dev_err(&pdev->dev, "failed to setup keymap\n");
+		goto err_put_clk;
+	}
 
-	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+	__set_bit(EV_REP, input_dev->evbit);
 	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 
-	input_dev->keycode = kbc->keycode;
-	input_dev->keycodesize = sizeof(kbc->keycode[0]);
-	input_dev->keycodemax = KBC_MAX_KEY;
-	if (pdata->use_fn_map)
-		input_dev->keycodemax *= 2;
-
-	kbc->use_fn_map = pdata->use_fn_map;
-	kbc->use_ghost_filter = pdata->use_ghost_filter;
-	keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
-	matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
-				   input_dev->keycode, input_dev->keybit);
-	kbc->wakeup_key = pdata->wakeup_key;
+	input_set_drvdata(input_dev, kbc);
 
 	err = request_irq(kbc->irq, tegra_kbc_isr,
 			  IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc);
@@ -799,9 +818,6 @@
 	platform_set_drvdata(pdev, kbc);
 	device_init_wakeup(&pdev->dev, pdata->wakeup);
 
-	if (!pdev->dev.platform_data)
-		matrix_keyboard_of_free_keymap(pdata->keymap_data);
-
 	return 0;
 
 err_free_irq:
@@ -816,10 +832,8 @@
 	input_free_device(input_dev);
 	kfree(kbc);
 err_free_pdata:
-	if (!pdev->dev.platform_data) {
-		matrix_keyboard_of_free_keymap(pdata->keymap_data);
+	if (!pdev->dev.platform_data)
 		kfree(pdata);
-	}
 
 	return err;
 }
diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c
index fb39c94..a4a445f 100644
--- a/drivers/input/keyboard/tnetv107x-keypad.c
+++ b/drivers/input/keyboard/tnetv107x-keypad.c
@@ -247,15 +247,11 @@
 		error = -ENOMEM;
 		goto error_input;
 	}
-	input_set_drvdata(kp->input_dev, kp);
 
 	kp->input_dev->name	  = pdev->name;
 	kp->input_dev->dev.parent = &pdev->dev;
 	kp->input_dev->open	  = keypad_start;
 	kp->input_dev->close	  = keypad_stop;
-	kp->input_dev->evbit[0]	  = BIT_MASK(EV_KEY);
-	if (!pdata->no_autorepeat)
-		kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
 
 	clk_enable(kp->clk);
 	rev = keypad_read(kp, rev);
@@ -264,15 +260,20 @@
 	kp->input_dev->id.version = ((rev >> 16) & 0xfff);
 	clk_disable(kp->clk);
 
-	kp->input_dev->keycode     = kp->keycodes;
-	kp->input_dev->keycodesize = sizeof(kp->keycodes[0]);
-	kp->input_dev->keycodemax  = kp->rows << kp->row_shift;
+	error = matrix_keypad_build_keymap(keymap_data, NULL,
+					   kp->rows, kp->cols,
+					   kp->keycodes, kp->input_dev);
+	if (error) {
+		dev_err(dev, "Failed to build keymap\n");
+		goto error_reg;
+	}
 
-	matrix_keypad_build_keymap(keymap_data, kp->row_shift, kp->keycodes,
-				   kp->input_dev->keybit);
-
+	if (!pdata->no_autorepeat)
+		kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
 	input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
 
+	input_set_drvdata(kp->input_dev, kp);
+
 	error = input_register_device(kp->input_dev);
 	if (error < 0) {
 		dev_err(dev, "Could not register input device\n");
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index 67bec14..a2c6f79 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -361,14 +361,6 @@
 	kp->irq = platform_get_irq(pdev, 0);
 
 	/* setup input device */
-	__set_bit(EV_KEY, input->evbit);
-
-	/* Enable auto repeat feature of Linux input subsystem */
-	if (pdata->rep)
-		__set_bit(EV_REP, input->evbit);
-
-	input_set_capability(input, EV_MSC, MSC_SCAN);
-
 	input->name		= "TWL4030 Keypad";
 	input->phys		= "twl4030_keypad/input0";
 	input->dev.parent	= &pdev->dev;
@@ -378,12 +370,19 @@
 	input->id.product	= 0x0001;
 	input->id.version	= 0x0003;
 
-	input->keycode		= kp->keymap;
-	input->keycodesize	= sizeof(kp->keymap[0]);
-	input->keycodemax	= ARRAY_SIZE(kp->keymap);
+	error = matrix_keypad_build_keymap(keymap_data, NULL,
+					   TWL4030_MAX_ROWS,
+					   1 << TWL4030_ROW_SHIFT,
+					   kp->keymap, input);
+	if (error) {
+		dev_err(kp->dbg_dev, "Failed to build keymap\n");
+		goto err1;
+	}
 
-	matrix_keypad_build_keymap(keymap_data, TWL4030_ROW_SHIFT,
-				   input->keycode, input->keybit);
+	input_set_capability(input, EV_MSC, MSC_SCAN);
+	/* Enable auto repeat feature of Linux input subsystem */
+	if (pdata->rep)
+		__set_bit(EV_REP, input->evbit);
 
 	error = input_register_device(input);
 	if (error) {
diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c
index 99bbb7e..085ede4 100644
--- a/drivers/input/keyboard/w90p910_keypad.c
+++ b/drivers/input/keyboard/w90p910_keypad.c
@@ -42,7 +42,8 @@
 #define KGET_RAW(n)		(((n) & KEY0R) >> 3)
 #define KGET_COLUMN(n)		((n) & KEY0C)
 
-#define W90P910_MAX_KEY_NUM	(8 * 8)
+#define W90P910_NUM_ROWS	8
+#define W90P910_NUM_COLS	8
 #define W90P910_ROW_SHIFT	3
 
 struct w90p910_keypad {
@@ -51,7 +52,7 @@
 	struct input_dev *input_dev;
 	void __iomem *mmio_base;
 	int irq;
-	unsigned short keymap[W90P910_MAX_KEY_NUM];
+	unsigned short keymap[W90P910_NUM_ROWS * W90P910_NUM_COLS];
 };
 
 static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad,
@@ -190,17 +191,13 @@
 	input_dev->close = w90p910_keypad_close;
 	input_dev->dev.parent = &pdev->dev;
 
-	input_dev->keycode = keypad->keymap;
-	input_dev->keycodesize = sizeof(keypad->keymap[0]);
-	input_dev->keycodemax = ARRAY_SIZE(keypad->keymap);
-
-	input_set_drvdata(input_dev, keypad);
-
-	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
-
-	matrix_keypad_build_keymap(keymap_data, W90P910_ROW_SHIFT,
-				   input_dev->keycode, input_dev->keybit);
+	error = matrix_keypad_build_keymap(keymap_data, NULL,
+					   W90P910_NUM_ROWS, W90P910_NUM_COLS,
+					   keypad->keymap, input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to build keymap\n");
+		goto failed_put_clk;
+	}
 
 	error = request_irq(keypad->irq, w90p910_keypad_irq_handler,
 			    0, pdev->name, keypad);
@@ -209,6 +206,10 @@
 		goto failed_put_clk;
 	}
 
+	__set_bit(EV_REP, input_dev->evbit);
+	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+	input_set_drvdata(input_dev, keypad);
+
 	/* Register the input device */
 	error = input_register_device(input_dev);
 	if (error) {
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index 37b01d7..d050d9d 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -169,15 +169,4 @@
 	.disconnect	= xtkbd_disconnect,
 };
 
-static int __init xtkbd_init(void)
-{
-	return serio_register_driver(&xtkbd_drv);
-}
-
-static void __exit xtkbd_exit(void)
-{
-	serio_unregister_driver(&xtkbd_drv);
-}
-
-module_init(xtkbd_init);
-module_exit(xtkbd_exit);
+module_serio_driver(xtkbd_drv);
diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c
new file mode 100644
index 0000000..443ad64b
--- /dev/null
+++ b/drivers/input/matrix-keymap.c
@@ -0,0 +1,163 @@
+/*
+ * Helpers for matrix keyboard bindings
+ *
+ * Copyright (C) 2012 Google, Inc
+ *
+ * Author:
+ *	Olof Johansson <olof@lixom.net>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/of.h>
+#include <linux/export.h>
+#include <linux/input/matrix_keypad.h>
+
+static bool matrix_keypad_map_key(struct input_dev *input_dev,
+				  unsigned int rows, unsigned int cols,
+				  unsigned int row_shift, unsigned int key)
+{
+	unsigned short *keymap = input_dev->keycode;
+	unsigned int row = KEY_ROW(key);
+	unsigned int col = KEY_COL(key);
+	unsigned short code = KEY_VAL(key);
+
+	if (row >= rows || col >= cols) {
+		dev_err(input_dev->dev.parent,
+			"%s: invalid keymap entry 0x%x (row: %d, col: %d, rows: %d, cols: %d)\n",
+			__func__, key, row, col, rows, cols);
+		return false;
+	}
+
+	keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
+	__set_bit(code, input_dev->keybit);
+
+	return true;
+}
+
+#ifdef CONFIG_OF
+static int matrix_keypad_parse_of_keymap(const char *propname,
+					 unsigned int rows, unsigned int cols,
+					 struct input_dev *input_dev)
+{
+	struct device *dev = input_dev->dev.parent;
+	struct device_node *np = dev->of_node;
+	unsigned int row_shift = get_count_order(cols);
+	unsigned int max_keys = rows << row_shift;
+	unsigned int proplen, i, size;
+	const __be32 *prop;
+
+	if (!np)
+		return -ENOENT;
+
+	if (!propname)
+		propname = "linux,keymap";
+
+	prop = of_get_property(np, propname, &proplen);
+	if (!prop) {
+		dev_err(dev, "OF: %s property not defined in %s\n",
+			propname, np->full_name);
+		return -ENOENT;
+	}
+
+	if (proplen % sizeof(u32)) {
+		dev_err(dev, "OF: Malformed keycode property %s in %s\n",
+			propname, np->full_name);
+		return -EINVAL;
+	}
+
+	size = proplen / sizeof(u32);
+	if (size > max_keys) {
+		dev_err(dev, "OF: %s size overflow\n", propname);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < size; i++) {
+		unsigned int key = be32_to_cpup(prop + i);
+
+		if (!matrix_keypad_map_key(input_dev, rows, cols,
+					   row_shift, key))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+#else
+static int matrix_keypad_parse_of_keymap(const char *propname,
+					 unsigned int rows, unsigned int cols,
+					 struct input_dev *input_dev)
+{
+	return -ENOSYS;
+}
+#endif
+
+/**
+ * matrix_keypad_build_keymap - convert platform keymap into matrix keymap
+ * @keymap_data: keymap supplied by the platform code
+ * @keymap_name: name of device tree property containing keymap (if device
+ *	tree support is enabled).
+ * @rows: number of rows in target keymap array
+ * @cols: number of cols in target keymap array
+ * @keymap: expanded version of keymap that is suitable for use by
+ * matrix keyboard driver
+ * @input_dev: input devices for which we are setting up the keymap
+ *
+ * This function converts platform keymap (encoded with KEY() macro) into
+ * an array of keycodes that is suitable for using in a standard matrix
+ * keyboard driver that uses row and col as indices.
+ *
+ * If @keymap_data is not supplied and device tree support is enabled
+ * it will attempt load the keymap from property specified by @keymap_name
+ * argument (or "linux,keymap" if @keymap_name is %NULL).
+ *
+ * Callers are expected to set up input_dev->dev.parent before calling this
+ * function.
+ */
+int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
+			       const char *keymap_name,
+			       unsigned int rows, unsigned int cols,
+			       unsigned short *keymap,
+			       struct input_dev *input_dev)
+{
+	unsigned int row_shift = get_count_order(cols);
+	int i;
+	int error;
+
+	input_dev->keycode = keymap;
+	input_dev->keycodesize = sizeof(*keymap);
+	input_dev->keycodemax = rows << row_shift;
+
+	__set_bit(EV_KEY, input_dev->evbit);
+
+	if (keymap_data) {
+		for (i = 0; i < keymap_data->keymap_size; i++) {
+			unsigned int key = keymap_data->keymap[i];
+
+			if (!matrix_keypad_map_key(input_dev, rows, cols,
+						   row_shift, key))
+				return -EINVAL;
+		}
+	} else {
+		error = matrix_keypad_parse_of_keymap(keymap_name, rows, cols,
+						      input_dev);
+		if (error)
+			return error;
+	}
+
+	__clear_bit(KEY_RESERVED, input_dev->keybit);
+
+	return 0;
+}
+EXPORT_SYMBOL(matrix_keypad_build_keymap);
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index ab86051..082684e 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -327,7 +327,9 @@
 
 	error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
 	if (error)
-		err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+		dev_err(&dev->intf->dev,
+			"%s: usb_submit_urb (urb_ctl) failed %d\n",
+			__func__, error);
 }
 
 /*
@@ -339,7 +341,7 @@
 	const int status = urb->status;
 	int error;
 
-	dev_dbg(&urb->dev->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
+	dev_dbg(&dev->intf->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
 	     dev->irq_data->byte[0],
 	     dev->irq_data->byte[1],
 	     dev->irq_data->byte[2],
@@ -349,7 +351,7 @@
 	if (status) {
 		if (status == -ESHUTDOWN)
 			return;
-		err("%s: urb status %d", __func__, status);
+		dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status);
 	}
 
 	/* Special keys */
@@ -396,7 +398,8 @@
 
 		error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
 		if (error)
-			err("%s: usb_submit_urb (urb_ctl) failed %d",
+			dev_err(&dev->intf->dev,
+				"%s: usb_submit_urb (urb_ctl) failed %d\n",
 				__func__, error);
 	}
 
@@ -409,14 +412,14 @@
 	const int status = urb->status;
 	int error;
 
-	dev_dbg(&urb->dev->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
+	dev_dbg(&dev->intf->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
 	     dev->ctl_data->byte[0],
 	     dev->ctl_data->byte[1],
 	     dev->ctl_data->byte[2],
 	     dev->ctl_data->byte[3]);
 
 	if (status)
-		err("%s: urb status %d", __func__, status);
+		dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status);
 
 	spin_lock(&dev->ctl_submit_lock);
 
@@ -433,7 +436,8 @@
 			dev->irq_urb_pending = 1;
 			error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
 			if (error)
-				err("%s: usb_submit_urb (urb_irq) failed %d",
+				dev_err(&dev->intf->dev,
+					"%s: usb_submit_urb (urb_irq) failed %d\n",
 					__func__, error);
 		}
 	}
@@ -476,7 +480,8 @@
 				dev->ctl_data,
 				USB_PKT_LEN, USB_CTRL_SET_TIMEOUT);
 	if (error < 0 && error != -EINTR)
-		err("%s: usb_control_msg() failed %d", __func__, error);
+		dev_err(&dev->intf->dev, "%s: usb_control_msg() failed %d\n",
+			__func__, error);
 }
 
 static void cm109_stop_traffic(struct cm109_dev *dev)
@@ -518,8 +523,8 @@
 
 	error = usb_autopm_get_interface(dev->intf);
 	if (error < 0) {
-		err("%s - cannot autoresume, result %d",
-		    __func__, error);
+		dev_err(&idev->dev, "%s - cannot autoresume, result %d\n",
+			__func__, error);
 		return error;
 	}
 
@@ -537,7 +542,8 @@
 
 	error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
 	if (error)
-		err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+		dev_err(&dev->intf->dev, "%s: usb_submit_urb (urb_ctl) failed %d\n",
+			__func__, error);
 	else
 		dev->open = 1;
 
@@ -573,7 +579,7 @@
 {
 	struct cm109_dev *dev = input_get_drvdata(idev);
 
-	dev_dbg(&dev->udev->dev,
+	dev_dbg(&dev->intf->dev,
 		"input_ev: type=%u code=%u value=%d\n", type, code, value);
 
 	if (type != EV_SND)
@@ -710,7 +716,8 @@
 	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
 	ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
 	if (ret != USB_PKT_LEN)
-		err("invalid payload size %d, expected %d", ret, USB_PKT_LEN);
+		dev_err(&intf->dev, "invalid payload size %d, expected %d\n",
+			ret, USB_PKT_LEN);
 
 	/* initialise irq urb */
 	usb_fill_int_urb(dev->urb_irq, udev, pipe, dev->irq_data,
diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c
index 06517e6..a3735a0 100644
--- a/drivers/input/misc/cma3000_d0x.c
+++ b/drivers/input/misc/cma3000_d0x.c
@@ -318,7 +318,7 @@
 	mutex_init(&data->mutex);
 
 	data->mode = pdata->mode;
-	if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) {
+	if (data->mode > CMAMODE_POFF) {
 		data->mode = CMAMODE_MOTDET;
 		dev_warn(dev,
 			 "Invalid mode specified, assuming Motion Detect\n");
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
index d99151a..290fa5f 100644
--- a/drivers/input/misc/keyspan_remote.c
+++ b/drivers/input/misc/keyspan_remote.c
@@ -157,7 +157,7 @@
 	 * though so it's not too big a deal
 	 */
 	if (dev->data.pos >= dev->data.len) {
-		dev_dbg(&dev->udev->dev,
+		dev_dbg(&dev->interface->dev,
 			"%s - Error ran out of data. pos: %d, len: %d\n",
 			__func__, dev->data.pos, dev->data.len);
 		return -1;
@@ -267,7 +267,9 @@
 				remote->data.tester = remote->data.tester >> 6;
 				remote->data.bits_left -= 6;
 			} else {
-				err("%s - Unknown sequence found in system data.\n", __func__);
+				dev_err(&remote->interface->dev,
+					"%s - Unknown sequence found in system data.\n",
+					__func__);
 				remote->stage = 0;
 				return;
 			}
@@ -286,7 +288,9 @@
 				remote->data.tester = remote->data.tester >> 6;
 				remote->data.bits_left -= 6;
 			} else {
-				err("%s - Unknown sequence found in button data.\n", __func__);
+				dev_err(&remote->interface->dev,
+					"%s - Unknown sequence found in button data.\n",
+					__func__);
 				remote->stage = 0;
 				return;
 			}
@@ -302,7 +306,9 @@
 			remote->data.tester = remote->data.tester >> 6;
 			remote->data.bits_left -= 6;
 		} else {
-			err("%s - Error in message, invalid toggle.\n", __func__);
+			dev_err(&remote->interface->dev,
+				"%s - Error in message, invalid toggle.\n",
+				__func__);
 			remote->stage = 0;
 			return;
 		}
@@ -312,10 +318,11 @@
 			remote->data.tester = remote->data.tester >> 5;
 			remote->data.bits_left -= 5;
 		} else {
-			err("Bad message received, no stop bit found.\n");
+			dev_err(&remote->interface->dev,
+				"Bad message received, no stop bit found.\n");
 		}
 
-		dev_dbg(&remote->udev->dev,
+		dev_dbg(&remote->interface->dev,
 			"%s found valid message: system: %d, button: %d, toggle: %d\n",
 			__func__, message.system, message.button, message.toggle);
 
@@ -397,7 +404,9 @@
 resubmit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		err ("%s - usb_submit_urb failed with result: %d", __func__, retval);
+		dev_err(&dev->interface->dev,
+			"%s - usb_submit_urb failed with result: %d\n",
+			__func__, retval);
 }
 
 static int keyspan_open(struct input_dev *dev)
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 5403c57..306f84c 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -367,7 +367,7 @@
 
 	error = request_threaded_irq(client->irq,
 				     NULL, mpu3050_interrupt_thread,
-				     IRQF_TRIGGER_RISING,
+				     IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 				     "mpu3050", sensor);
 	if (error) {
 		dev_err(&client->dev,
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index 538f704..49c0c3e 100644
--- a/drivers/input/misc/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -65,6 +65,7 @@
 	struct urb *irq, *config;
 	struct usb_ctrlrequest *configcr;
 	struct usb_device *udev;
+	struct usb_interface *intf;
 	struct input_dev *input;
 	spinlock_t lock;
 	int static_brightness;
@@ -85,6 +86,7 @@
 static void powermate_irq(struct urb *urb)
 {
 	struct powermate_device *pm = urb->context;
+	struct device *dev = &pm->intf->dev;
 	int retval;
 
 	switch (urb->status) {
@@ -95,10 +97,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+		dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+			__func__, urb->status);
 		goto exit;
 	}
 
@@ -110,8 +114,8 @@
 exit:
 	retval = usb_submit_urb (urb, GFP_ATOMIC);
 	if (retval)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __func__, retval);
+		dev_err(dev, "%s - usb_submit_urb failed with result: %d\n",
+			__func__, retval);
 }
 
 /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
@@ -330,6 +334,7 @@
 		goto fail3;
 
 	pm->udev = udev;
+	pm->intf = intf;
 	pm->input = input_dev;
 
 	usb_make_path(udev, pm->phys, sizeof(pm->phys));
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index 14e94f5..c34f6c0 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -27,6 +27,7 @@
  */
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 #include <linux/workqueue.h>
 #include <linux/input.h>
 #include <linux/mfd/twl6040.h>
@@ -258,10 +259,13 @@
 static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
 {
 	struct twl6040_vibra_data *pdata = pdev->dev.platform_data;
+	struct device_node *node = pdev->dev.of_node;
 	struct vibra_info *info;
+	int vddvibl_uV = 0;
+	int vddvibr_uV = 0;
 	int ret;
 
-	if (!pdata) {
+	if (!pdata && !node) {
 		dev_err(&pdev->dev, "platform_data not available\n");
 		return -EINVAL;
 	}
@@ -273,11 +277,26 @@
 	}
 
 	info->dev = &pdev->dev;
+
 	info->twl6040 = dev_get_drvdata(pdev->dev.parent);
-	info->vibldrv_res = pdata->vibldrv_res;
-	info->vibrdrv_res = pdata->vibrdrv_res;
-	info->viblmotor_res = pdata->viblmotor_res;
-	info->vibrmotor_res = pdata->vibrmotor_res;
+	if (pdata) {
+		info->vibldrv_res = pdata->vibldrv_res;
+		info->vibrdrv_res = pdata->vibrdrv_res;
+		info->viblmotor_res = pdata->viblmotor_res;
+		info->vibrmotor_res = pdata->vibrmotor_res;
+		vddvibl_uV = pdata->vddvibl_uV;
+		vddvibr_uV = pdata->vddvibr_uV;
+	} else {
+		of_property_read_u32(node, "vibldrv_res", &info->vibldrv_res);
+		of_property_read_u32(node, "vibrdrv_res", &info->vibrdrv_res);
+		of_property_read_u32(node, "viblmotor_res",
+				     &info->viblmotor_res);
+		of_property_read_u32(node, "vibrmotor_res",
+				     &info->vibrmotor_res);
+		of_property_read_u32(node, "vddvibl_uV", &vddvibl_uV);
+		of_property_read_u32(node, "vddvibr_uV", &vddvibr_uV);
+	}
+
 	if ((!info->vibldrv_res && !info->viblmotor_res) ||
 	    (!info->vibrdrv_res && !info->vibrmotor_res)) {
 		dev_err(info->dev, "invalid vibra driver/motor resistance\n");
@@ -339,10 +358,9 @@
 		goto err_regulator;
 	}
 
-	if (pdata->vddvibl_uV) {
+	if (vddvibl_uV) {
 		ret = regulator_set_voltage(info->supplies[0].consumer,
-					    pdata->vddvibl_uV,
-					    pdata->vddvibl_uV);
+					    vddvibl_uV, vddvibl_uV);
 		if (ret) {
 			dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
 				ret);
@@ -350,10 +368,9 @@
 		}
 	}
 
-	if (pdata->vddvibr_uV) {
+	if (vddvibr_uV) {
 		ret = regulator_set_voltage(info->supplies[1].consumer,
-					    pdata->vddvibr_uV,
-					    pdata->vddvibr_uV);
+					    vddvibr_uV, vddvibr_uV);
 		if (ret) {
 			dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
 				ret);
@@ -401,6 +418,12 @@
 	return 0;
 }
 
+static const struct of_device_id twl6040_vibra_of_match[] = {
+	{.compatible = "ti,twl6040-vibra", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, twl6040_vibra_of_match);
+
 static struct platform_driver twl6040_vibra_driver = {
 	.probe		= twl6040_vibra_probe,
 	.remove		= __devexit_p(twl6040_vibra_remove),
@@ -408,6 +431,7 @@
 		.name	= "twl6040-vibra",
 		.owner	= THIS_MODULE,
 		.pm	= &twl6040_vibra_pm_ops,
+		.of_match_table = twl6040_vibra_of_match,
 	},
 };
 module_platform_driver(twl6040_vibra_driver);
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index f4776e7..285a5bd 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -101,6 +101,7 @@
 struct yealink_dev {
 	struct input_dev *idev;		/* input device */
 	struct usb_device *udev;	/* usb device */
+	struct usb_interface *intf;	/* usb interface */
 
 	/* irq input channel */
 	struct yld_ctl_packet	*irq_data;
@@ -428,7 +429,8 @@
 	int ret, status = urb->status;
 
 	if (status)
-		err("%s - urb status %d", __func__, status);
+		dev_err(&yld->intf->dev, "%s - urb status %d\n",
+			__func__, status);
 
 	switch (yld->irq_data->cmd) {
 	case CMD_KEYPRESS:
@@ -437,13 +439,15 @@
 		break;
 
 	case CMD_SCANCODE:
-		dbg("get scancode %x", yld->irq_data->data[0]);
+		dev_dbg(&yld->intf->dev, "get scancode %x\n",
+			yld->irq_data->data[0]);
 
 		report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
 		break;
 
 	default:
-		err("unexpected response %x", yld->irq_data->cmd);
+		dev_err(&yld->intf->dev, "unexpected response %x\n",
+			yld->irq_data->cmd);
 	}
 
 	yealink_do_idle_tasks(yld);
@@ -451,7 +455,9 @@
 	if (!yld->shutdown) {
 		ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
 		if (ret && ret != -EPERM)
-			err("%s - usb_submit_urb failed %d", __func__, ret);
+			dev_err(&yld->intf->dev,
+				"%s - usb_submit_urb failed %d\n",
+				__func__, ret);
 	}
 }
 
@@ -461,7 +467,8 @@
 	int ret = 0, status = urb->status;
 
 	if (status)
-		err("%s - urb status %d", __func__, status);
+		dev_err(&yld->intf->dev, "%s - urb status %d\n",
+			__func__, status);
 
 	switch (yld->ctl_data->cmd) {
 	case CMD_KEYPRESS:
@@ -479,7 +486,8 @@
 	}
 
 	if (ret && ret != -EPERM)
-		err("%s - usb_submit_urb failed %d", __func__, ret);
+		dev_err(&yld->intf->dev, "%s - usb_submit_urb failed %d\n",
+			__func__, ret);
 }
 
 /*******************************************************************************
@@ -511,7 +519,7 @@
 	struct yealink_dev *yld = input_get_drvdata(dev);
 	int i, ret;
 
-	dbg("%s", __func__);
+	dev_dbg(&yld->intf->dev, "%s\n", __func__);
 
 	/* force updates to device */
 	for (i = 0; i<sizeof(yld->master); i++)
@@ -526,8 +534,9 @@
 	yld->ctl_data->size	= 10;
 	yld->ctl_data->sum	= 0x100-CMD_INIT-10;
 	if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
-		dbg("%s - usb_submit_urb failed with result %d",
-		     __func__, ret);
+		dev_dbg(&yld->intf->dev,
+			"%s - usb_submit_urb failed with result %d\n",
+			__func__, ret);
 		return ret;
 	}
 	return 0;
@@ -876,6 +885,7 @@
 		return -ENOMEM;
 
 	yld->udev = udev;
+	yld->intf = intf;
 
 	yld->idev = input_dev = input_allocate_device();
 	if (!input_dev)
@@ -909,7 +919,8 @@
 	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
 	ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
 	if (ret != USB_PKT_LEN)
-		err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN);
+		dev_err(&intf->dev, "invalid payload size %d, expected %zd\n",
+			ret, USB_PKT_LEN);
 
 	/* initialise irq urb */
 	usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 9b8db82..cd6268c 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -339,4 +339,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called synaptics_usb.
 
+config MOUSE_NAVPOINT_PXA27x
+	tristate "Synaptics NavPoint (PXA27x SSP/SPI)"
+	depends on PXA27x && PXA_SSP
+	help
+	  This driver adds support for the Synaptics NavPoint touchpad connected
+	  to a PXA27x SSP port in SPI slave mode. The device emulates a mouse;
+	  a tap or tap-and-a-half drag gesture emulates the left mouse button.
+	  For example, use the xf86-input-evdev driver for an X pointing device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called navpoint.
+
 endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 4718eff..46ba755 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -12,6 +12,7 @@
 obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
 obj-$(CONFIG_MOUSE_MAPLE)		+= maplemouse.o
+obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x)	+= navpoint.o
 obj-$(CONFIG_MOUSE_PC110PAD)		+= pc110pad.o
 obj-$(CONFIG_MOUSE_PS2)			+= psmouse.o
 obj-$(CONFIG_MOUSE_PXA930_TRKBALL)	+= pxa930_trkball.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 4c6a72d..4a1347e 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -553,10 +553,7 @@
 
 	alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
 
-	input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
-	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
-	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
-	input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
+	input_mt_report_finger_count(dev, fingers);
 
 	input_report_key(dev, BTN_LEFT, left);
 	input_report_key(dev, BTN_RIGHT, right);
@@ -604,10 +601,54 @@
 
 static void alps_process_packet_v4(struct psmouse *psmouse)
 {
+	struct alps_data *priv = psmouse->private;
 	unsigned char *packet = psmouse->packet;
 	struct input_dev *dev = psmouse->dev;
+	int offset;
 	int x, y, z;
 	int left, right;
+	int x1, y1, x2, y2;
+	int fingers = 0;
+	unsigned int x_bitmap, y_bitmap;
+
+	/*
+	 * v4 has a 6-byte encoding for bitmap data, but this data is
+	 * broken up between 3 normal packets. Use priv->multi_packet to
+	 * track our position in the bitmap packet.
+	 */
+	if (packet[6] & 0x40) {
+		/* sync, reset position */
+		priv->multi_packet = 0;
+	}
+
+	if (WARN_ON_ONCE(priv->multi_packet > 2))
+		return;
+
+	offset = 2 * priv->multi_packet;
+	priv->multi_data[offset] = packet[6];
+	priv->multi_data[offset + 1] = packet[7];
+
+	if (++priv->multi_packet > 2) {
+		priv->multi_packet = 0;
+
+		x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) |
+			   ((priv->multi_data[3] & 0x60) << 3) |
+			   ((priv->multi_data[0] & 0x3f) << 2) |
+			   ((priv->multi_data[1] & 0x60) >> 5);
+		y_bitmap = ((priv->multi_data[5] & 0x01) << 10) |
+			   ((priv->multi_data[3] & 0x1f) << 5) |
+			    (priv->multi_data[1] & 0x1f);
+
+		fingers = alps_process_bitmap(x_bitmap, y_bitmap,
+					      &x1, &y1, &x2, &y2);
+
+		/* Store MT data.*/
+		priv->fingers = fingers;
+		priv->x1 = x1;
+		priv->x2 = x2;
+		priv->y1 = y1;
+		priv->y2 = y2;
+	}
 
 	left = packet[4] & 0x01;
 	right = packet[4] & 0x02;
@@ -617,21 +658,41 @@
 	y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
 	z = packet[5] & 0x7f;
 
+	/*
+	 * If there were no contacts in the bitmap, use ST
+	 * points in MT reports.
+	 * If there were two contacts or more, report MT data.
+	 */
+	if (priv->fingers < 2) {
+		x1 = x;
+		y1 = y;
+		fingers = z > 0 ? 1 : 0;
+	} else {
+		fingers = priv->fingers;
+		x1 = priv->x1;
+		x2 = priv->x2;
+		y1 = priv->y1;
+		y2 = priv->y2;
+	}
+
 	if (z >= 64)
 		input_report_key(dev, BTN_TOUCH, 1);
 	else
 		input_report_key(dev, BTN_TOUCH, 0);
 
+	alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+	input_mt_report_finger_count(dev, fingers);
+
+	input_report_key(dev, BTN_LEFT, left);
+	input_report_key(dev, BTN_RIGHT, right);
+
 	if (z > 0) {
 		input_report_abs(dev, ABS_X, x);
 		input_report_abs(dev, ABS_Y, y);
 	}
 	input_report_abs(dev, ABS_PRESSURE, z);
 
-	input_report_key(dev, BTN_TOOL_FINGER, z > 0);
-	input_report_key(dev, BTN_LEFT, left);
-	input_report_key(dev, BTN_RIGHT, right);
-
 	input_sync(dev);
 }
 
@@ -1557,6 +1618,7 @@
 		input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
 		break;
 	case ALPS_PROTO_V3:
+	case ALPS_PROTO_V4:
 		set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
 		input_mt_init_slots(dev1, 2);
 		input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
@@ -1565,8 +1627,7 @@
 		set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
 		set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
 		set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
-		/* fall through */
-	case ALPS_PROTO_V4:
+
 		input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
 		input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
 		break;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index a00a4ab9..ae1ac35 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -39,6 +39,8 @@
 	int prev_fin;			/* Finger bit from previous packet */
 	int multi_packet;		/* Multi-packet data in progress */
 	unsigned char multi_data[6];	/* Saved multi-packet data */
+	int x1, x2, y1, y2;		/* Coordinates from last MT report */
+	int fingers;			/* Number of fingers from MT report */
 	u8 quirks;
 	struct timer_list timer;
 };
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 0acbc7d..e42f1fa 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -195,6 +195,7 @@
 struct atp {
 	char			phys[64];
 	struct usb_device	*udev;		/* usb device */
+	struct usb_interface	*intf;		/* usb interface */
 	struct urb		*urb;		/* usb request block */
 	u8			*data;		/* transferred data */
 	struct input_dev	*input;		/* input dev */
@@ -253,8 +254,9 @@
  * packets (Report ID 2). This code changes device mode, so it
  * sends raw sensor reports (Report ID 5).
  */
-static int atp_geyser_init(struct usb_device *udev)
+static int atp_geyser_init(struct atp *dev)
 {
+	struct usb_device *udev = dev->udev;
 	char *data;
 	int size;
 	int i;
@@ -262,7 +264,7 @@
 
 	data = kmalloc(8, GFP_KERNEL);
 	if (!data) {
-		err("Out of memory");
+		dev_err(&dev->intf->dev, "Out of memory\n");
 		return -ENOMEM;
 	}
 
@@ -277,7 +279,7 @@
 		for (i = 0; i < 8; i++)
 			dprintk("appletouch[%d]: %d\n", i, data[i]);
 
-		err("Failed to read mode from device.");
+		dev_err(&dev->intf->dev, "Failed to read mode from device.\n");
 		ret = -EIO;
 		goto out_free;
 	}
@@ -296,7 +298,7 @@
 		for (i = 0; i < 8; i++)
 			dprintk("appletouch[%d]: %d\n", i, data[i]);
 
-		err("Failed to request geyser raw mode");
+		dev_err(&dev->intf->dev, "Failed to request geyser raw mode\n");
 		ret = -EIO;
 		goto out_free;
 	}
@@ -313,16 +315,16 @@
 static void atp_reinit(struct work_struct *work)
 {
 	struct atp *dev = container_of(work, struct atp, work);
-	struct usb_device *udev = dev->udev;
 	int retval;
 
 	dprintk("appletouch: putting appletouch to sleep (reinit)\n");
-	atp_geyser_init(udev);
+	atp_geyser_init(dev);
 
 	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
 	if (retval)
-		err("atp_reinit: usb_submit_urb failed with error %d",
-		    retval);
+		dev_err(&dev->intf->dev,
+			"atp_reinit: usb_submit_urb failed with error %d\n",
+			retval);
 }
 
 static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
@@ -400,6 +402,7 @@
 static int atp_status_check(struct urb *urb)
 {
 	struct atp *dev = urb->context;
+	struct usb_interface *intf = dev->intf;
 
 	switch (urb->status) {
 	case 0:
@@ -407,8 +410,8 @@
 		break;
 	case -EOVERFLOW:
 		if (!dev->overflow_warned) {
-			printk(KERN_WARNING "appletouch: OVERFLOW with data "
-				"length %d, actual length is %d\n",
+			dev_warn(&intf->dev,
+				"appletouch: OVERFLOW with data length %d, actual length is %d\n",
 				dev->info->datalen, dev->urb->actual_length);
 			dev->overflow_warned = true;
 		}
@@ -416,13 +419,15 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* This urb is terminated, clean up */
-		dbg("atp_complete: urb shutting down with status: %d",
-		    urb->status);
+		dev_dbg(&intf->dev,
+			"atp_complete: urb shutting down with status: %d\n",
+			urb->status);
 		return ATP_URB_STATUS_ERROR_FATAL;
 
 	default:
-		dbg("atp_complete: nonzero urb status received: %d",
-		    urb->status);
+		dev_dbg(&intf->dev,
+			"atp_complete: nonzero urb status received: %d\n",
+			urb->status);
 		return ATP_URB_STATUS_ERROR;
 	}
 
@@ -445,7 +450,8 @@
 	for (i = dev->info->xsensors; i < ATP_XSENSORS; i++) {
 		if (dev->xy_cur[i]) {
 
-			printk(KERN_INFO "appletouch: 17\" model detected.\n");
+			dev_info(&dev->intf->dev,
+				"appletouch: 17\" model detected.\n");
 
 			input_set_abs_params(dev->input, ABS_X, 0,
 					     (dev->info->xsensors_17 - 1) *
@@ -588,8 +594,9 @@
  exit:
 	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
 	if (retval)
-		err("atp_complete: usb_submit_urb failed with result %d",
-		    retval);
+		dev_err(&dev->intf->dev,
+			"atp_complete: usb_submit_urb failed with result %d\n",
+			retval);
 }
 
 /* Interrupt function for older touchpads: GEYSER3/GEYSER4 */
@@ -722,8 +729,9 @@
  exit:
 	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
 	if (retval)
-		err("atp_complete: usb_submit_urb failed with result %d",
-		    retval);
+		dev_err(&dev->intf->dev,
+			"atp_complete: usb_submit_urb failed with result %d\n",
+			retval);
 }
 
 static int atp_open(struct input_dev *input)
@@ -748,14 +756,12 @@
 
 static int atp_handle_geyser(struct atp *dev)
 {
-	struct usb_device *udev = dev->udev;
-
 	if (dev->info != &fountain_info) {
 		/* switch to raw sensor mode */
-		if (atp_geyser_init(udev))
+		if (atp_geyser_init(dev))
 			return -EIO;
 
-		printk(KERN_INFO "appletouch: Geyser mode initialized.\n");
+		dev_info(&dev->intf->dev, "Geyser mode initialized.\n");
 	}
 
 	return 0;
@@ -785,7 +791,7 @@
 		}
 	}
 	if (!int_in_endpointAddr) {
-		err("Could not find int-in endpoint");
+		dev_err(&iface->dev, "Could not find int-in endpoint\n");
 		return -EIO;
 	}
 
@@ -793,11 +799,12 @@
 	dev = kzalloc(sizeof(struct atp), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!dev || !input_dev) {
-		err("Out of memory");
+		dev_err(&iface->dev, "Out of memory\n");
 		goto err_free_devs;
 	}
 
 	dev->udev = udev;
+	dev->intf = iface;
 	dev->input = input_dev;
 	dev->info = info;
 	dev->overflow_warned = false;
@@ -886,7 +893,7 @@
 		usb_free_urb(dev->urb);
 		kfree(dev);
 	}
-	printk(KERN_INFO "input: appletouch disconnected\n");
+	dev_info(&iface->dev, "input: appletouch disconnected\n");
 }
 
 static int atp_recover(struct atp *dev)
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index f9e2758..2cf681d 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -584,7 +584,7 @@
 	int retval = 0, size;
 
 	if (!data) {
-		err("bcm5974: out of memory");
+		dev_err(&dev->intf->dev, "out of memory\n");
 		retval = -ENOMEM;
 		goto out;
 	}
@@ -597,7 +597,7 @@
 			BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
 
 	if (size != 8) {
-		err("bcm5974: could not read from device");
+		dev_err(&dev->intf->dev, "could not read from device\n");
 		retval = -EIO;
 		goto out;
 	}
@@ -615,7 +615,7 @@
 			BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
 
 	if (size != 8) {
-		err("bcm5974: could not write to device");
+		dev_err(&dev->intf->dev, "could not write to device\n");
 		retval = -EIO;
 		goto out;
 	}
@@ -631,6 +631,7 @@
 static void bcm5974_irq_button(struct urb *urb)
 {
 	struct bcm5974 *dev = urb->context;
+	struct usb_interface *intf = dev->intf;
 	int error;
 
 	switch (urb->status) {
@@ -640,10 +641,11 @@
 	case -ECONNRESET:
 	case -ENOENT:
 	case -ESHUTDOWN:
-		dbg("bcm5974: button urb shutting down: %d", urb->status);
+		dev_dbg(&intf->dev, "button urb shutting down: %d\n",
+			urb->status);
 		return;
 	default:
-		dbg("bcm5974: button urb status: %d", urb->status);
+		dev_dbg(&intf->dev, "button urb status: %d\n", urb->status);
 		goto exit;
 	}
 
@@ -654,12 +656,13 @@
 exit:
 	error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC);
 	if (error)
-		err("bcm5974: button urb failed: %d", error);
+		dev_err(&intf->dev, "button urb failed: %d\n", error);
 }
 
 static void bcm5974_irq_trackpad(struct urb *urb)
 {
 	struct bcm5974 *dev = urb->context;
+	struct usb_interface *intf = dev->intf;
 	int error;
 
 	switch (urb->status) {
@@ -669,10 +672,11 @@
 	case -ECONNRESET:
 	case -ENOENT:
 	case -ESHUTDOWN:
-		dbg("bcm5974: trackpad urb shutting down: %d", urb->status);
+		dev_dbg(&intf->dev, "trackpad urb shutting down: %d\n",
+			urb->status);
 		return;
 	default:
-		dbg("bcm5974: trackpad urb status: %d", urb->status);
+		dev_dbg(&intf->dev, "trackpad urb status: %d\n", urb->status);
 		goto exit;
 	}
 
@@ -687,7 +691,7 @@
 exit:
 	error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
 	if (error)
-		err("bcm5974: trackpad urb failed: %d", error);
+		dev_err(&intf->dev, "trackpad urb failed: %d\n", error);
 }
 
 /*
@@ -833,7 +837,7 @@
 	dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!dev || !input_dev) {
-		err("bcm5974: out of memory");
+		dev_err(&iface->dev, "out of memory\n");
 		goto err_free_devs;
 	}
 
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
new file mode 100644
index 0000000..c29ae76
--- /dev/null
+++ b/drivers/input/mouse/navpoint.c
@@ -0,0 +1,369 @@
+/*
+ * Synaptics NavPoint (PXA27x SSP/SPI) driver.
+ *
+ * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/input/navpoint.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/slab.h>
+
+/*
+ * Synaptics Modular Embedded Protocol: Module Packet Format.
+ * Module header byte 2:0 = Length (# bytes that follow)
+ * Module header byte 4:3 = Control
+ * Module header byte 7:5 = Module Address
+ */
+#define HEADER_LENGTH(byte)	((byte) & 0x07)
+#define HEADER_CONTROL(byte)	(((byte) >> 3) & 0x03)
+#define HEADER_ADDRESS(byte)	((byte) >> 5)
+
+struct navpoint {
+	struct ssp_device	*ssp;
+	struct input_dev	*input;
+	struct device		*dev;
+	int			gpio;
+	int			index;
+	u8			data[1 + HEADER_LENGTH(0xff)];
+};
+
+/*
+ * Initialization values for SSCR0_x, SSCR1_x, SSSR_x.
+ */
+static const u32 sscr0 = 0
+	| SSCR0_TUM		/* TIM = 1; No TUR interrupts */
+	| SSCR0_RIM		/* RIM = 1; No ROR interrupts */
+	| SSCR0_SSE		/* SSE = 1; SSP enabled */
+	| SSCR0_Motorola	/* FRF = 0; Motorola SPI */
+	| SSCR0_DataSize(16)	/* DSS = 15; Data size = 16-bit */
+	;
+static const u32 sscr1 = 0
+	| SSCR1_SCFR		/* SCFR = 1; SSPSCLK only during transfers */
+	| SSCR1_SCLKDIR		/* SCLKDIR = 1; Slave mode */
+	| SSCR1_SFRMDIR		/* SFRMDIR = 1; Slave mode */
+	| SSCR1_RWOT		/* RWOT = 1; Receive without transmit mode */
+	| SSCR1_RxTresh(1)	/* RFT = 0; Receive FIFO threshold = 1 */
+	| SSCR1_SPH		/* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */
+	| SSCR1_RIE		/* RIE = 1; Receive FIFO interrupt enabled */
+	;
+static const u32 sssr = 0
+	| SSSR_BCE		/* BCE = 1; Clear BCE */
+	| SSSR_TUR		/* TUR = 1; Clear TUR */
+	| SSSR_EOC		/* EOC = 1; Clear EOC */
+	| SSSR_TINT		/* TINT = 1; Clear TINT */
+	| SSSR_PINT		/* PINT = 1; Clear PINT */
+	| SSSR_ROR		/* ROR = 1; Clear ROR */
+	;
+
+/*
+ * MEP Query $22: Touchpad Coordinate Range Query is not supported by
+ * the NavPoint module, so sampled values provide the default limits.
+ */
+#define NAVPOINT_X_MIN		1278
+#define NAVPOINT_X_MAX		5340
+#define NAVPOINT_Y_MIN		1572
+#define NAVPOINT_Y_MAX		4396
+#define NAVPOINT_PRESSURE_MIN	0
+#define NAVPOINT_PRESSURE_MAX	255
+
+static void navpoint_packet(struct navpoint *navpoint)
+{
+	int finger;
+	int gesture;
+	int x, y, z;
+
+	switch (navpoint->data[0]) {
+	case 0xff:	/* Garbage (packet?) between reset and Hello packet */
+	case 0x00:	/* Module 0, NULL packet */
+		break;
+
+	case 0x0e:	/* Module 0, Absolute packet */
+		finger = (navpoint->data[1] & 0x01);
+		gesture = (navpoint->data[1] & 0x02);
+		x = ((navpoint->data[2] & 0x1f) << 8) | navpoint->data[3];
+		y = ((navpoint->data[4] & 0x1f) << 8) | navpoint->data[5];
+		z = navpoint->data[6];
+		input_report_key(navpoint->input, BTN_TOUCH, finger);
+		input_report_abs(navpoint->input, ABS_X, x);
+		input_report_abs(navpoint->input, ABS_Y, y);
+		input_report_abs(navpoint->input, ABS_PRESSURE, z);
+		input_report_key(navpoint->input, BTN_TOOL_FINGER, finger);
+		input_report_key(navpoint->input, BTN_LEFT, gesture);
+		input_sync(navpoint->input);
+		break;
+
+	case 0x19:	/* Module 0, Hello packet */
+		if ((navpoint->data[1] & 0xf0) == 0x10)
+			break;
+		/* FALLTHROUGH */
+	default:
+		dev_warn(navpoint->dev,
+			 "spurious packet: data=0x%02x,0x%02x,...\n",
+			 navpoint->data[0], navpoint->data[1]);
+		break;
+	}
+}
+
+static irqreturn_t navpoint_irq(int irq, void *dev_id)
+{
+	struct navpoint *navpoint = dev_id;
+	struct ssp_device *ssp = navpoint->ssp;
+	irqreturn_t ret = IRQ_NONE;
+	u32 status;
+
+	status = pxa_ssp_read_reg(ssp, SSSR);
+	if (status & sssr) {
+		dev_warn(navpoint->dev,
+			 "unexpected interrupt: status=0x%08x\n", status);
+		pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
+		ret = IRQ_HANDLED;
+	}
+
+	while (status & SSSR_RNE) {
+		u32 data;
+
+		data = pxa_ssp_read_reg(ssp, SSDR);
+		navpoint->data[navpoint->index + 0] = (data >> 8);
+		navpoint->data[navpoint->index + 1] = data;
+		navpoint->index += 2;
+		if (HEADER_LENGTH(navpoint->data[0]) < navpoint->index) {
+			navpoint_packet(navpoint);
+			navpoint->index = 0;
+		}
+		status = pxa_ssp_read_reg(ssp, SSSR);
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static void navpoint_up(struct navpoint *navpoint)
+{
+	struct ssp_device *ssp = navpoint->ssp;
+	int timeout;
+
+	clk_prepare_enable(ssp->clk);
+
+	pxa_ssp_write_reg(ssp, SSCR1, sscr1);
+	pxa_ssp_write_reg(ssp, SSSR, sssr);
+	pxa_ssp_write_reg(ssp, SSTO, 0);
+	pxa_ssp_write_reg(ssp, SSCR0, sscr0);	/* SSCR0_SSE written last */
+
+	/* Wait until SSP port is ready for slave clock operations */
+	for (timeout = 100; timeout != 0; --timeout) {
+		if (!(pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS))
+			break;
+		msleep(1);
+	}
+
+	if (timeout == 0)
+		dev_err(navpoint->dev,
+			"timeout waiting for SSSR[CSS] to clear\n");
+
+	if (gpio_is_valid(navpoint->gpio))
+		gpio_set_value(navpoint->gpio, 1);
+}
+
+static void navpoint_down(struct navpoint *navpoint)
+{
+	struct ssp_device *ssp = navpoint->ssp;
+
+	if (gpio_is_valid(navpoint->gpio))
+		gpio_set_value(navpoint->gpio, 0);
+
+	pxa_ssp_write_reg(ssp, SSCR0, 0);
+
+	clk_disable_unprepare(ssp->clk);
+}
+
+static int navpoint_open(struct input_dev *input)
+{
+	struct navpoint *navpoint = input_get_drvdata(input);
+
+	navpoint_up(navpoint);
+
+	return 0;
+}
+
+static void navpoint_close(struct input_dev *input)
+{
+	struct navpoint *navpoint = input_get_drvdata(input);
+
+	navpoint_down(navpoint);
+}
+
+static int __devinit navpoint_probe(struct platform_device *pdev)
+{
+	const struct navpoint_platform_data *pdata =
+					dev_get_platdata(&pdev->dev);
+	struct ssp_device *ssp;
+	struct input_dev *input;
+	struct navpoint *navpoint;
+	int error;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	if (gpio_is_valid(pdata->gpio)) {
+		error = gpio_request_one(pdata->gpio, GPIOF_OUT_INIT_LOW,
+					 "SYNAPTICS_ON");
+		if (error)
+			return error;
+	}
+
+	ssp = pxa_ssp_request(pdata->port, pdev->name);
+	if (!ssp) {
+		error = -ENODEV;
+		goto err_free_gpio;
+	}
+
+	/* HaRET does not disable devices before jumping into Linux */
+	if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
+		pxa_ssp_write_reg(ssp, SSCR0, 0);
+		dev_warn(&pdev->dev, "ssp%d already enabled\n", pdata->port);
+	}
+
+	navpoint = kzalloc(sizeof(*navpoint), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!navpoint || !input) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	navpoint->ssp = ssp;
+	navpoint->input = input;
+	navpoint->dev = &pdev->dev;
+	navpoint->gpio = pdata->gpio;
+
+	input->name = pdev->name;
+	input->dev.parent = &pdev->dev;
+
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(BTN_LEFT, input->keybit);
+	__set_bit(BTN_TOUCH, input->keybit);
+	__set_bit(BTN_TOOL_FINGER, input->keybit);
+
+	input_set_abs_params(input, ABS_X,
+			     NAVPOINT_X_MIN, NAVPOINT_X_MAX, 0, 0);
+	input_set_abs_params(input, ABS_Y,
+			     NAVPOINT_Y_MIN, NAVPOINT_Y_MAX, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE,
+			     NAVPOINT_PRESSURE_MIN, NAVPOINT_PRESSURE_MAX,
+			     0, 0);
+
+	input->open = navpoint_open;
+	input->close = navpoint_close;
+
+	input_set_drvdata(input, navpoint);
+
+	error = request_irq(ssp->irq, navpoint_irq, 0, pdev->name, navpoint);
+	if (error)
+		goto err_free_mem;
+
+	error = input_register_device(input);
+	if (error)
+		goto err_free_irq;
+
+	platform_set_drvdata(pdev, navpoint);
+	dev_dbg(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq);
+
+	return 0;
+
+err_free_irq:
+	free_irq(ssp->irq, &pdev->dev);
+err_free_mem:
+	input_free_device(input);
+	kfree(navpoint);
+	pxa_ssp_free(ssp);
+err_free_gpio:
+	if (gpio_is_valid(pdata->gpio))
+		gpio_free(pdata->gpio);
+
+	return error;
+}
+
+static int __devexit navpoint_remove(struct platform_device *pdev)
+{
+	const struct navpoint_platform_data *pdata =
+					dev_get_platdata(&pdev->dev);
+	struct navpoint *navpoint = platform_get_drvdata(pdev);
+	struct ssp_device *ssp = navpoint->ssp;
+
+	free_irq(ssp->irq, navpoint);
+
+	input_unregister_device(navpoint->input);
+	kfree(navpoint);
+
+	pxa_ssp_free(ssp);
+
+	if (gpio_is_valid(pdata->gpio))
+		gpio_free(pdata->gpio);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int navpoint_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct navpoint *navpoint = platform_get_drvdata(pdev);
+	struct input_dev *input = navpoint->input;
+
+	mutex_lock(&input->mutex);
+	if (input->users)
+		navpoint_down(navpoint);
+	mutex_unlock(&input->mutex);
+
+	return 0;
+}
+
+static int navpoint_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct navpoint *navpoint = platform_get_drvdata(pdev);
+	struct input_dev *input = navpoint->input;
+
+	mutex_lock(&input->mutex);
+	if (input->users)
+		navpoint_up(navpoint);
+	mutex_unlock(&input->mutex);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(navpoint_pm_ops, navpoint_suspend, navpoint_resume);
+
+static struct platform_driver navpoint_driver = {
+	.probe		= navpoint_probe,
+	.remove		= __devexit_p(navpoint_remove),
+	.driver = {
+		.name	= "navpoint",
+		.owner	= THIS_MODULE,
+		.pm	= &navpoint_pm_ops,
+	},
+};
+
+module_platform_driver(navpoint_driver);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:navpoint");
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 661a0ca..3f5649f 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -41,7 +41,7 @@
 #define	GET_ABS_Y(packet)	((packet[2] << 2) | (packet[3] & 0x03))
 
 /** Driver version. */
-static const char fsp_drv_ver[] = "1.0.0-K";
+static const char fsp_drv_ver[] = "1.1.0-K";
 
 /*
  * Make sure that the value being sent to FSP will not conflict with
@@ -303,6 +303,27 @@
 	return 0;
 }
 
+static int fsp_get_sn(struct psmouse *psmouse, int *sn)
+{
+	int v0, v1, v2;
+	int rc = -EIO;
+
+	/* production number since Cx is available at: 0x0b40 ~ 0x0b42 */
+	if (fsp_page_reg_write(psmouse, FSP_PAGE_0B))
+		goto out;
+	if (fsp_reg_read(psmouse, FSP_REG_SN0, &v0))
+		goto out;
+	if (fsp_reg_read(psmouse, FSP_REG_SN1, &v1))
+		goto out;
+	if (fsp_reg_read(psmouse, FSP_REG_SN2, &v2))
+		goto out;
+	*sn = (v0 << 16) | (v1 << 8) | v2;
+	rc = 0;
+out:
+	fsp_page_reg_write(psmouse, FSP_PAGE_DEFAULT);
+	return rc;
+}
+
 static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
 {
 	static const int buttons[] = {
@@ -1000,16 +1021,21 @@
 int fsp_init(struct psmouse *psmouse)
 {
 	struct fsp_data *priv;
-	int ver, rev;
+	int ver, rev, sn = 0;
 	int error;
 
 	if (fsp_get_version(psmouse, &ver) ||
 	    fsp_get_revision(psmouse, &rev)) {
 		return -ENODEV;
 	}
+	if (ver >= FSP_VER_STL3888_C0) {
+		/* firmware information is only available since C0 */
+		fsp_get_sn(psmouse, &sn);
+	}
 
-	psmouse_info(psmouse, "Finger Sensing Pad, hw: %d.%d.%d, sw: %s\n",
-		     ver >> 4, ver & 0x0F, rev, fsp_drv_ver);
+	psmouse_info(psmouse,
+		     "Finger Sensing Pad, hw: %d.%d.%d, sn: %x, sw: %s\n",
+		     ver >> 4, ver & 0x0F, rev, sn, fsp_drv_ver);
 
 	psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
 	if (!priv)
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index 334de19..aa697ec 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -65,6 +65,14 @@
 #define	FSP_BIT_SWC1_GST_GRP1	BIT(6)
 #define	FSP_BIT_SWC1_BX_COMPAT	BIT(7)
 
+#define	FSP_PAGE_0B		(0x0b)
+#define	FSP_PAGE_82		(0x82)
+#define	FSP_PAGE_DEFAULT	FSP_PAGE_82
+
+#define	FSP_REG_SN0		(0x40)
+#define	FSP_REG_SN1		(0x41)
+#define	FSP_REG_SN2		(0x42)
+
 /* Finger-sensing Pad packet formating related definitions */
 
 /* absolute packet type */
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index 17ff137b..d5928fd 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -355,15 +355,4 @@
 	.disconnect	= sermouse_disconnect,
 };
 
-static int __init sermouse_init(void)
-{
-	return serio_register_driver(&sermouse_drv);
-}
-
-static void __exit sermouse_exit(void)
-{
-	serio_unregister_driver(&sermouse_drv);
-}
-
-module_init(sermouse_init);
-module_exit(sermouse_exit);
+module_serio_driver(sermouse_drv);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index a4b14a4..c703d53 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -45,16 +45,6 @@
 #define YMIN_NOMINAL 1408
 #define YMAX_NOMINAL 4448
 
-/*
- * Synaptics touchpads report the y coordinate from bottom to top, which is
- * opposite from what userspace expects.
- * This function is used to invert y before reporting.
- */
-static int synaptics_invert_y(int y)
-{
-	return YMAX_NOMINAL + YMIN_NOMINAL - y;
-}
-
 
 /*****************************************************************************
  *	Stuff we need even when we do not want native Synaptics support
@@ -112,6 +102,16 @@
  ****************************************************************************/
 
 /*
+ * Synaptics touchpads report the y coordinate from bottom to top, which is
+ * opposite from what userspace expects.
+ * This function is used to invert y before reporting.
+ */
+static int synaptics_invert_y(int y)
+{
+	return YMAX_NOMINAL + YMIN_NOMINAL - y;
+}
+
+/*
  * Send a command to the synpatics touchpad by special commands
  */
 static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index eb9a3cf..e900d46 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -548,16 +548,4 @@
 	.disconnect	= vsxxxaa_disconnect,
 };
 
-static int __init vsxxxaa_init(void)
-{
-	return serio_register_driver(&vsxxxaa_drv);
-}
-
-static void __exit vsxxxaa_exit(void)
-{
-	serio_unregister_driver(&vsxxxaa_drv);
-}
-
-module_init(vsxxxaa_init);
-module_exit(vsxxxaa_exit);
-
+module_serio_driver(vsxxxaa_drv);
diff --git a/drivers/input/of_keymap.c b/drivers/input/of_keymap.c
deleted file mode 100644
index 061493d..0000000
--- a/drivers/input/of_keymap.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Helpers for open firmware matrix keyboard bindings
- *
- * Copyright (C) 2012 Google, Inc
- *
- * Author:
- *	Olof Johansson <olof@lixom.net>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/input.h>
-#include <linux/of.h>
-#include <linux/input/matrix_keypad.h>
-#include <linux/export.h>
-#include <linux/gfp.h>
-#include <linux/slab.h>
-
-struct matrix_keymap_data *
-matrix_keyboard_of_fill_keymap(struct device_node *np,
-			       const char *propname)
-{
-	struct matrix_keymap_data *kd;
-	u32 *keymap;
-	int proplen, i;
-	const __be32 *prop;
-
-	if (!np)
-		return NULL;
-
-	if (!propname)
-		propname = "linux,keymap";
-
-	prop = of_get_property(np, propname, &proplen);
-	if (!prop)
-		return NULL;
-
-	if (proplen % sizeof(u32)) {
-		pr_warn("Malformed keymap property %s in %s\n",
-			propname, np->full_name);
-		return NULL;
-	}
-
-	kd = kzalloc(sizeof(*kd), GFP_KERNEL);
-	if (!kd)
-		return NULL;
-
-	kd->keymap = keymap = kzalloc(proplen, GFP_KERNEL);
-	if (!kd->keymap) {
-		kfree(kd);
-		return NULL;
-	}
-
-	kd->keymap_size = proplen / sizeof(u32);
-
-	for (i = 0; i < kd->keymap_size; i++) {
-		u32 tmp = be32_to_cpup(prop + i);
-		int key_code, row, col;
-
-		row = (tmp >> 24) & 0xff;
-		col = (tmp >> 16) & 0xff;
-		key_code = tmp & 0xffff;
-		keymap[i] = KEY(row, col, key_code);
-	}
-
-	return kd;
-}
-EXPORT_SYMBOL_GPL(matrix_keyboard_of_fill_keymap);
-
-void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
-{
-	if (kd) {
-		kfree(kd->keymap);
-		kfree(kd);
-	}
-}
-EXPORT_SYMBOL_GPL(matrix_keyboard_of_free_keymap);
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index 4349474..0c42497 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -206,6 +206,7 @@
 	},
 	{ 0, }
 };
+MODULE_DEVICE_TABLE(pci, pcips2_ids);
 
 static struct pci_driver pcips2_driver = {
 	.name			= "pcips2",
@@ -214,20 +215,8 @@
 	.remove			= __devexit_p(pcips2_remove),
 };
 
-static int __init pcips2_init(void)
-{
-	return pci_register_driver(&pcips2_driver);
-}
-
-static void __exit pcips2_exit(void)
-{
-	pci_unregister_driver(&pcips2_driver);
-}
-
-module_init(pcips2_init);
-module_exit(pcips2_exit);
+module_pci_driver(pcips2_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");
-MODULE_DEVICE_TABLE(pci, pcips2_ids);
diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
index 15aa81c..a76fb64 100644
--- a/drivers/input/serio/ps2mult.c
+++ b/drivers/input/serio/ps2mult.c
@@ -304,15 +304,4 @@
 	.reconnect	= ps2mult_reconnect,
 };
 
-static int __init ps2mult_init(void)
-{
-	return serio_register_driver(&ps2mult_drv);
-}
-
-static void __exit ps2mult_exit(void)
-{
-	serio_unregister_driver(&ps2mult_drv);
-}
-
-module_init(ps2mult_init);
-module_exit(ps2mult_exit);
+module_serio_driver(ps2mult_drv);
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 4494233..59df2e7 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -165,31 +165,38 @@
 	struct serio_raw *serio_raw = client->serio_raw;
 	char uninitialized_var(c);
 	ssize_t read = 0;
-	int retval;
+	int error;
 
-	if (serio_raw->dead)
-		return -ENODEV;
+	for (;;) {
+		if (serio_raw->dead)
+			return -ENODEV;
 
-	if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
-		return -EAGAIN;
+		if (serio_raw->head == serio_raw->tail &&
+		    (file->f_flags & O_NONBLOCK))
+			return -EAGAIN;
 
-	retval = wait_event_interruptible(serio_raw->wait,
-			serio_raw->head != serio_raw->tail || serio_raw->dead);
-	if (retval)
-		return retval;
-
-	if (serio_raw->dead)
-		return -ENODEV;
-
-	while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
-		if (put_user(c, buffer++)) {
-			retval = -EFAULT;
+		if (count == 0)
 			break;
+
+		while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
+			if (put_user(c, buffer++))
+				return -EFAULT;
+			read++;
 		}
-		read++;
+
+		if (read)
+			break;
+
+		if (!(file->f_flags & O_NONBLOCK)) {
+			error = wait_event_interruptible(serio_raw->wait,
+					serio_raw->head != serio_raw->tail ||
+					serio_raw->dead);
+			if (error)
+				return error;
+		}
 	}
 
-	return read ?: retval;
+	return read;
 }
 
 static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
@@ -197,8 +204,7 @@
 {
 	struct serio_raw_client *client = file->private_data;
 	struct serio_raw *serio_raw = client->serio_raw;
-	ssize_t written = 0;
-	int retval;
+	int retval = 0;
 	unsigned char c;
 
 	retval = mutex_lock_interruptible(&serio_raw_mutex);
@@ -218,16 +224,20 @@
 			retval = -EFAULT;
 			goto out;
 		}
+
 		if (serio_write(serio_raw->serio, c)) {
-			retval = -EIO;
+			/* Either signal error or partial write */
+			if (retval == 0)
+				retval = -EIO;
 			goto out;
 		}
-		written++;
+
+		retval++;
 	}
 
 out:
 	mutex_unlock(&serio_raw_mutex);
-	return written ?: retval;
+	return retval;
 }
 
 static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
@@ -432,15 +442,4 @@
 	.manual_bind	= true,
 };
 
-static int __init serio_raw_init(void)
-{
-	return serio_register_driver(&serio_raw_drv);
-}
-
-static void __exit serio_raw_exit(void)
-{
-	serio_unregister_driver(&serio_raw_drv);
-}
-
-module_init(serio_raw_init);
-module_exit(serio_raw_exit);
+module_serio_driver(serio_raw_drv);
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index d96d4c2..1e983be 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -73,7 +73,8 @@
 	spinlock_t lock;
 	void __iomem *base_address;	/* virt. address of control registers */
 	unsigned int flags;
-	struct serio serio;		/* serio */
+	struct serio *serio;		/* serio */
+	struct device *dev;
 };
 
 /************************************/
@@ -119,7 +120,7 @@
 
 	/* Check which interrupt is active */
 	if (intr_sr & XPS2_IPIXR_RX_OVF)
-		dev_warn(drvdata->serio.dev.parent, "receive overrun error\n");
+		dev_warn(drvdata->dev, "receive overrun error\n");
 
 	if (intr_sr & XPS2_IPIXR_RX_ERR)
 		drvdata->flags |= SERIO_PARITY;
@@ -132,10 +133,10 @@
 
 		/* Error, if a byte is not received */
 		if (status) {
-			dev_err(drvdata->serio.dev.parent,
+			dev_err(drvdata->dev,
 				"wrong rcvd byte count (%d)\n", status);
 		} else {
-			serio_interrupt(&drvdata->serio, c, drvdata->flags);
+			serio_interrupt(drvdata->serio, c, drvdata->flags);
 			drvdata->flags = 0;
 		}
 	}
@@ -193,7 +194,7 @@
 	error = request_irq(drvdata->irq, &xps2_interrupt, 0,
 				DRIVER_NAME, drvdata);
 	if (error) {
-		dev_err(drvdata->serio.dev.parent,
+		dev_err(drvdata->dev,
 			"Couldn't allocate interrupt %d\n", drvdata->irq);
 		return error;
 	}
@@ -259,15 +260,16 @@
 	}
 
 	drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
-	if (!drvdata) {
-		dev_err(dev, "Couldn't allocate device private record\n");
-		return -ENOMEM;
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+	if (!drvdata || !serio) {
+		error = -ENOMEM;
+		goto failed1;
 	}
 
-	dev_set_drvdata(dev, drvdata);
-
 	spin_lock_init(&drvdata->lock);
 	drvdata->irq = r_irq.start;
+	drvdata->serio = serio;
+	drvdata->dev = dev;
 
 	phys_addr = r_mem.start;
 	remap_size = resource_size(&r_mem);
@@ -298,7 +300,6 @@
 		 (unsigned long long)phys_addr, drvdata->base_address,
 		 drvdata->irq);
 
-	serio = &drvdata->serio;
 	serio->id.type = SERIO_8042;
 	serio->write = sxps2_write;
 	serio->open = sxps2_open;
@@ -312,13 +313,14 @@
 
 	serio_register_port(serio);
 
+	platform_set_drvdata(ofdev, drvdata);
 	return 0;		/* success */
 
 failed2:
 	release_mem_region(phys_addr, remap_size);
 failed1:
+	kfree(serio);
 	kfree(drvdata);
-	dev_set_drvdata(dev, NULL);
 
 	return error;
 }
@@ -333,22 +335,21 @@
  */
 static int __devexit xps2_of_remove(struct platform_device *of_dev)
 {
-	struct device *dev = &of_dev->dev;
-	struct xps2data *drvdata = dev_get_drvdata(dev);
+	struct xps2data *drvdata = platform_get_drvdata(of_dev);
 	struct resource r_mem; /* IO mem resources */
 
-	serio_unregister_port(&drvdata->serio);
+	serio_unregister_port(drvdata->serio);
 	iounmap(drvdata->base_address);
 
 	/* Get iospace of the device */
 	if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem))
-		dev_err(dev, "invalid address\n");
+		dev_err(drvdata->dev, "invalid address\n");
 	else
 		release_mem_region(r_mem.start, resource_size(&r_mem));
 
 	kfree(drvdata);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(of_dev, NULL);
 
 	return 0;
 }
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
index f8b0b1d..e062ec8 100644
--- a/drivers/input/tablet/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -51,6 +51,7 @@
 	char name[128];
 	char phys[64];
 	struct usb_device *usbdev;
+	struct usb_interface *intf;
 	struct input_dev *input;
 	struct urb *irq;
 
@@ -63,6 +64,7 @@
 	struct usb_acecad *acecad = urb->context;
 	unsigned char *data = acecad->data;
 	struct input_dev *dev = acecad->input;
+	struct usb_interface *intf = acecad->intf;
 	int prox, status;
 
 	switch (urb->status) {
@@ -73,10 +75,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+		dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+		dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n",
+			__func__, urb->status);
 		goto resubmit;
 	}
 
@@ -105,8 +109,10 @@
 resubmit:
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status)
-		err("can't resubmit intr, %s-%s/input0, status %d",
-			acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
+		dev_err(&intf->dev,
+			"can't resubmit intr, %s-%s/input0, status %d\n",
+			acecad->usbdev->bus->bus_name,
+			acecad->usbdev->devpath, status);
 }
 
 static int usb_acecad_open(struct input_dev *dev)
@@ -168,6 +174,7 @@
 	}
 
 	acecad->usbdev = dev;
+	acecad->intf = intf;
 	acecad->input = input_dev;
 
 	if (dev->manufacturer)
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 205d16a..ee83c39 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -309,6 +309,7 @@
 struct aiptek {
 	struct input_dev *inputdev;		/* input device struct           */
 	struct usb_device *usbdev;		/* usb device struct             */
+	struct usb_interface *intf;		/* usb interface struct          */
 	struct urb *urb;			/* urb for incoming reports      */
 	dma_addr_t data_dma;			/* our dma stuffage              */
 	struct aiptek_features features;	/* tablet's array of features    */
@@ -435,6 +436,7 @@
 	struct aiptek *aiptek = urb->context;
 	unsigned char *data = aiptek->data;
 	struct input_dev *inputdev = aiptek->inputdev;
+	struct usb_interface *intf = aiptek->intf;
 	int jitterable = 0;
 	int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck;
 
@@ -447,13 +449,13 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* This urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, urb->status);
+		dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
 		return;
 
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, urb->status);
+		dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n",
+			__func__, urb->status);
 		goto exit;
 	}
 
@@ -785,7 +787,7 @@
 				 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
 		input_sync(inputdev);
 	} else {
-		dbg("Unknown report %d", data[0]);
+		dev_dbg(&intf->dev, "Unknown report %d\n", data[0]);
 	}
 
 	/* Jitter may occur when the user presses a button on the stlyus
@@ -811,8 +813,9 @@
 exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval != 0) {
-		err("%s - usb_submit_urb failed with result %d",
-		    __func__, retval);
+		dev_err(&intf->dev,
+			"%s - usb_submit_urb failed with result %d\n",
+			__func__, retval);
 	}
 }
 
@@ -912,8 +915,9 @@
 
 	if ((ret =
 	     aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
-		dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x",
-		    command, data);
+		dev_dbg(&aiptek->intf->dev,
+			"aiptek_program: failed, tried to send: 0x%02x 0x%02x\n",
+			command, data);
 	}
 	kfree(buf);
 	return ret < 0 ? ret : 0;
@@ -947,8 +951,9 @@
 
 	if ((ret =
 	     aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
-		dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x",
-		    buf[0], buf[1], buf[2]);
+		dev_dbg(&aiptek->intf->dev,
+			"aiptek_query failed: returned 0x%02x 0x%02x 0x%02x\n",
+			buf[0], buf[1], buf[2]);
 		ret = -EIO;
 	} else {
 		ret = get_unaligned_le16(buf + 1);
@@ -1726,6 +1731,7 @@
 
 	aiptek->inputdev = inputdev;
 	aiptek->usbdev = usbdev;
+	aiptek->intf = intf;
 	aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber;
 	aiptek->inDelay = 0;
 	aiptek->endDelay = 0;
@@ -1856,7 +1862,7 @@
 	if (i == ARRAY_SIZE(speeds)) {
 		dev_info(&intf->dev,
 			 "Aiptek tried all speeds, no sane response\n");
-		goto fail2;
+		goto fail3;
 	}
 
 	/* Associate this driver's struct with the usb interface.
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 89a2978..29e01ab 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -2,8 +2,6 @@
 
 GTCO digitizer USB driver
 
-Use the err() and dbg() macros from usb.h for system logging
-
 TO CHECK:  Is pressure done right on report 5?
 
 Copyright (C) 2006  GTCO CalComp
@@ -108,6 +106,7 @@
 
 	struct input_dev  *inputdevice; /* input device struct pointer  */
 	struct usb_device *usbdev; /* the usb device for this device */
+	struct usb_interface *intf;	/* the usb interface for this device */
 	struct urb        *urbinfo;	 /* urb for incoming reports      */
 	dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
 	unsigned char *   buffer;   /* databuffer for reports */
@@ -202,6 +201,7 @@
 static void parse_hid_report_descriptor(struct gtco *device, char * report,
 					int length)
 {
+	struct device *ddev = &device->intf->dev;
 	int   x, i = 0;
 
 	/* Tag primitive vars */
@@ -228,7 +228,7 @@
 	char  indentstr[10] = "";
 
 
-	dbg("======>>>>>>PARSE<<<<<<======");
+	dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n");
 
 	/* Walk  this report and pull out the info we need */
 	while (i < length) {
@@ -277,11 +277,11 @@
 				else if (data == 3)
 					strcpy(globtype, "Var|Const");
 
-				dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
-				    globalval[TAG_GLOB_REPORT_ID], inputnum,
-				    globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
-				    globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
-				    globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
+				dev_dbg(ddev, "::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits\n",
+					globalval[TAG_GLOB_REPORT_ID], inputnum,
+					globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
+					globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
+					globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
 
 
 				/*
@@ -292,7 +292,7 @@
 				 */
 				switch (inputnum) {
 				case 0:  /* X coord */
-					dbg("GER: X Usage: 0x%x", usage);
+					dev_dbg(ddev, "GER: X Usage: 0x%x\n", usage);
 					if (device->max_X == 0) {
 						device->max_X = globalval[TAG_GLOB_LOG_MAX];
 						device->min_X = globalval[TAG_GLOB_LOG_MIN];
@@ -300,7 +300,7 @@
 					break;
 
 				case 1:  /* Y coord */
-					dbg("GER: Y Usage: 0x%x", usage);
+					dev_dbg(ddev, "GER: Y Usage: 0x%x\n", usage);
 					if (device->max_Y == 0) {
 						device->max_Y = globalval[TAG_GLOB_LOG_MAX];
 						device->min_Y = globalval[TAG_GLOB_LOG_MIN];
@@ -350,10 +350,10 @@
 				maintype = 'S';
 
 				if (data == 0) {
-					dbg("======>>>>>> Physical");
+					dev_dbg(ddev, "======>>>>>> Physical\n");
 					strcpy(globtype, "Physical");
 				} else
-					dbg("======>>>>>>");
+					dev_dbg(ddev, "======>>>>>>\n");
 
 				/* Indent the debug output */
 				indent++;
@@ -368,7 +368,7 @@
 				break;
 
 			case TAG_MAIN_COL_END:
-				dbg("<<<<<<======");
+				dev_dbg(ddev, "<<<<<<======\n");
 				maintype = 'E';
 				indent--;
 				for (x = 0; x < indent; x++)
@@ -384,18 +384,18 @@
 
 			switch (size) {
 			case 1:
-				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
-				    indentstr, tag, maintype, size, globtype, data);
+				dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
+					indentstr, tag, maintype, size, globtype, data);
 				break;
 
 			case 2:
-				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
-				    indentstr, tag, maintype, size, globtype, data16);
+				dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
+					indentstr, tag, maintype, size, globtype, data16);
 				break;
 
 			case 4:
-				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
-				    indentstr, tag, maintype, size, globtype, data32);
+				dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
+					indentstr, tag, maintype, size, globtype, data32);
 				break;
 			}
 			break;
@@ -465,26 +465,26 @@
 			if (tag < TAG_GLOB_MAX) {
 				switch (size) {
 				case 1:
-					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
-					    indentstr, globtype, tag, size, data);
+					dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
+						indentstr, globtype, tag, size, data);
 					globalval[tag] = data;
 					break;
 
 				case 2:
-					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
-					    indentstr, globtype, tag, size, data16);
+					dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
+						indentstr, globtype, tag, size, data16);
 					globalval[tag] = data16;
 					break;
 
 				case 4:
-					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
-					    indentstr, globtype, tag, size, data32);
+					dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
+						indentstr, globtype, tag, size, data32);
 					globalval[tag] = data32;
 					break;
 				}
 			} else {
-				dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
-				    indentstr, tag, size);
+				dev_dbg(ddev, "%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d\n",
+					indentstr, tag, size);
 			}
 			break;
 
@@ -511,18 +511,18 @@
 
 			switch (size) {
 			case 1:
-				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
-				    indentstr, tag, globtype, size, data);
+				dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
+					indentstr, tag, globtype, size, data);
 				break;
 
 			case 2:
-				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
-				    indentstr, tag, globtype, size, data16);
+				dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
+					indentstr, tag, globtype, size, data16);
 				break;
 
 			case 4:
-				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
-				    indentstr, tag, globtype, size, data32);
+				dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
+					indentstr, tag, globtype, size, data32);
 				break;
 			}
 
@@ -714,8 +714,9 @@
 				 * the rest as 0
 				 */
 				val = device->buffer[5] & MASK_BUTTON;
-				dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
-				    val, val);
+				dev_dbg(&device->intf->dev,
+					"======>>>>>>REPORT 1: val 0x%X(%d)\n",
+					val, val);
 
 				/*
 				 * We don't apply any meaning to the button
@@ -808,7 +809,8 @@
  resubmit:
 	rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
 	if (rc != 0)
-		err("usb_submit_urb failed rc=0x%x", rc);
+		dev_err(&device->intf->dev,
+			"usb_submit_urb failed rc=0x%x\n", rc);
 }
 
 /*
@@ -838,7 +840,7 @@
 	gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!gtco || !input_dev) {
-		err("No more memory");
+		dev_err(&usbinterface->dev, "No more memory\n");
 		error = -ENOMEM;
 		goto err_free_devs;
 	}
@@ -848,12 +850,13 @@
 
 	/* Save interface information */
 	gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
+	gtco->intf = usbinterface;
 
 	/* Allocate some data for incoming reports */
 	gtco->buffer = usb_alloc_coherent(gtco->usbdev, REPORT_MAX_SIZE,
 					  GFP_KERNEL, &gtco->buf_dma);
 	if (!gtco->buffer) {
-		err("No more memory for us buffers");
+		dev_err(&usbinterface->dev, "No more memory for us buffers\n");
 		error = -ENOMEM;
 		goto err_free_devs;
 	}
@@ -861,7 +864,7 @@
 	/* Allocate URB for reports */
 	gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
 	if (!gtco->urbinfo) {
-		err("Failed to allocate URB");
+		dev_err(&usbinterface->dev, "Failed to allocate URB\n");
 		error = -ENOMEM;
 		goto err_free_buf;
 	}
@@ -873,14 +876,14 @@
 	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
 
 	/* Some debug */
-	dbg("gtco # interfaces: %d", usbinterface->num_altsetting);
-	dbg("num endpoints:     %d", usbinterface->cur_altsetting->desc.bNumEndpoints);
-	dbg("interface class:   %d", usbinterface->cur_altsetting->desc.bInterfaceClass);
-	dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType);
+	dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting);
+	dev_dbg(&usbinterface->dev, "num endpoints:     %d\n", usbinterface->cur_altsetting->desc.bNumEndpoints);
+	dev_dbg(&usbinterface->dev, "interface class:   %d\n", usbinterface->cur_altsetting->desc.bInterfaceClass);
+	dev_dbg(&usbinterface->dev, "endpoint: attribute:0x%x type:0x%x\n", endpoint->bmAttributes, endpoint->bDescriptorType);
 	if (usb_endpoint_xfer_int(endpoint))
-		dbg("endpoint: we have interrupt endpoint\n");
+		dev_dbg(&usbinterface->dev, "endpoint: we have interrupt endpoint\n");
 
-	dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen);
+	dev_dbg(&usbinterface->dev, "endpoint extra len:%d\n", usbinterface->altsetting[0].extralen);
 
 	/*
 	 * Find the HID descriptor so we can find out the size of the
@@ -888,17 +891,19 @@
 	 */
 	if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
 				     HID_DEVICE_TYPE, &hid_desc) != 0){
-		err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+		dev_err(&usbinterface->dev,
+			"Can't retrieve exta USB descriptor to get hid report descriptor length\n");
 		error = -EIO;
 		goto err_free_urb;
 	}
 
-	dbg("Extra descriptor success: type:%d  len:%d",
-	    hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
+	dev_dbg(&usbinterface->dev,
+		"Extra descriptor success: type:%d  len:%d\n",
+		hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
 
 	report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL);
 	if (!report) {
-		err("No more memory for report");
+		dev_err(&usbinterface->dev, "No more memory for report\n");
 		error = -ENOMEM;
 		goto err_free_urb;
 	}
@@ -915,7 +920,7 @@
 					 le16_to_cpu(hid_desc->wDescriptorLength),
 					 5000); /* 5 secs */
 
-		dbg("usb_control_msg result: %d", result);
+		dev_dbg(&usbinterface->dev, "usb_control_msg result: %d\n", result);
 		if (result == le16_to_cpu(hid_desc->wDescriptorLength)) {
 			parse_hid_report_descriptor(gtco, report, result);
 			break;
@@ -926,8 +931,9 @@
 
 	/* If we didn't get the report, fail */
 	if (result != le16_to_cpu(hid_desc->wDescriptorLength)) {
-		err("Failed to get HID Report Descriptor of size: %d",
-		    hid_desc->wDescriptorLength);
+		dev_err(&usbinterface->dev,
+			"Failed to get HID Report Descriptor of size: %d\n",
+			hid_desc->wDescriptorLength);
 		error = -EIO;
 		goto err_free_urb;
 	}
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index 85a5b40..3fba74b 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -33,6 +33,7 @@
 	dma_addr_t data_dma;
 	struct input_dev *dev;
 	struct usb_device *usbdev;
+	struct usb_interface *intf;
 	struct urb *irq;
 	char phys[32];
 };
@@ -53,10 +54,14 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+		dev_dbg(&kbtab->intf->dev,
+			"%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+		dev_dbg(&kbtab->intf->dev,
+			"%s - nonzero urb status received: %d\n",
+			__func__, urb->status);
 		goto exit;
 	}
 
@@ -80,8 +85,9 @@
  exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		err("%s - usb_submit_urb failed with result %d",
-		     __func__, retval);
+		dev_err(&kbtab->intf->dev,
+			"%s - usb_submit_urb failed with result %d\n",
+			__func__, retval);
 }
 
 static struct usb_device_id kbtab_ids[] = {
@@ -131,6 +137,7 @@
 		goto fail2;
 
 	kbtab->usbdev = dev;
+	kbtab->intf = intf;
 	kbtab->dev = input_dev;
 
 	usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys));
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index b4842d0..b79d451 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -135,6 +135,6 @@
 
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
 void wacom_setup_device_quirks(struct wacom_features *features);
-void wacom_setup_input_capabilities(struct input_dev *input_dev,
-				    struct wacom_wac *wacom_wac);
+int wacom_setup_input_capabilities(struct input_dev *input_dev,
+				   struct wacom_wac *wacom_wac);
 #endif
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 0d26921..cad5602 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -28,6 +28,7 @@
 #define HID_USAGE_Y_TILT		0x3e
 #define HID_USAGE_FINGER		0x22
 #define HID_USAGE_STYLUS		0x20
+#define HID_USAGE_CONTACTMAX		0x55
 #define HID_COLLECTION			0xa1
 #define HID_COLLECTION_LOGICAL		0x02
 #define HID_COLLECTION_END		0xc0
@@ -99,6 +100,7 @@
 static void wacom_sys_irq(struct urb *urb)
 {
 	struct wacom *wacom = urb->context;
+	struct device *dev = &wacom->intf->dev;
 	int retval;
 
 	switch (urb->status) {
@@ -109,10 +111,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+		dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+			__func__, urb->status);
 		goto exit;
 	}
 
@@ -122,8 +126,8 @@
 	usb_mark_last_busy(wacom->usbdev);
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __func__, retval);
+		dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+			__func__, retval);
 }
 
 static int wacom_open(struct input_dev *dev)
@@ -201,6 +205,27 @@
 	return length;
 }
 
+static void wacom_retrieve_report_data(struct usb_interface *intf,
+				       struct wacom_features *features)
+{
+	int result = 0;
+	unsigned char *rep_data;
+
+	rep_data = kmalloc(2, GFP_KERNEL);
+	if (rep_data) {
+
+		rep_data[0] = 12;
+		result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
+					  rep_data[0], &rep_data, 2,
+					  WAC_MSG_RETRIES);
+
+		if (result >= 0 && rep_data[1] > 2)
+			features->touch_max = rep_data[1];
+
+		kfree(rep_data);
+	}
+}
+
 /*
  * Interface Descriptor of wacom devices can be incomplete and
  * inconsistent so wacom_features table is used to store stylus
@@ -233,6 +258,9 @@
  * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical
  * Collection. Instead they define a Logical Collection with a single
  * Logical Maximum for both X and Y.
+ *
+ * Intuos5 touch interface does not contain useful data. We deal with
+ * this after returning from this function.
  */
 static int wacom_parse_hid(struct usb_interface *intf,
 			   struct hid_descriptor *hid_desc,
@@ -292,6 +320,10 @@
 							/* need to reset back */
 							features->pktlen = WACOM_PKGLEN_TPC2FG;
 						}
+
+						if (features->type == MTSCREEN)
+							features->pktlen = WACOM_PKGLEN_MTOUCH;
+
 						if (features->type == BAMBOO_PT) {
 							/* need to reset back */
 							features->pktlen = WACOM_PKGLEN_BBTOUCH;
@@ -324,18 +356,15 @@
 			case HID_USAGE_Y:
 				if (usage == WCM_DESKTOP) {
 					if (finger) {
-						features->device_type = BTN_TOOL_FINGER;
-						if (features->type == TABLETPC2FG) {
-							/* need to reset back */
-							features->pktlen = WACOM_PKGLEN_TPC2FG;
+						int type = features->type;
+
+						if (type == TABLETPC2FG || type == MTSCREEN) {
 							features->y_max =
 								get_unaligned_le16(&report[i + 3]);
 							features->y_phy =
 								get_unaligned_le16(&report[i + 6]);
 							i += 7;
-						} else if (features->type == BAMBOO_PT) {
-							/* need to reset back */
-							features->pktlen = WACOM_PKGLEN_BBTOUCH;
+						} else if (type == BAMBOO_PT) {
 							features->y_phy =
 								get_unaligned_le16(&report[i + 3]);
 							features->y_max =
@@ -349,10 +378,6 @@
 							i += 4;
 						}
 					} else if (pen) {
-						/* penabled only accepts exact bytes of data */
-						if (features->type == TABLETPC2FG)
-							features->pktlen = WACOM_PKGLEN_GRAPHIRE;
-						features->device_type = BTN_TOOL_PEN;
 						features->y_max =
 							get_unaligned_le16(&report[i + 3]);
 						i += 4;
@@ -374,6 +399,11 @@
 				pen = 1;
 				i++;
 				break;
+
+			case HID_USAGE_CONTACTMAX:
+				wacom_retrieve_report_data(intf, features);
+				i++;
+				break;
 			}
 			break;
 
@@ -410,22 +440,29 @@
 	if (!rep_data)
 		return error;
 
-	/* ask to report tablet data if it is MT Tablet PC or
-	 * not a Tablet PC */
-	if (features->type == TABLETPC2FG) {
-		do {
-			rep_data[0] = 3;
-			rep_data[1] = 4;
-			rep_data[2] = 0;
-			rep_data[3] = 0;
-			report_id = 3;
-			error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
-						 report_id, rep_data, 4, 1);
-			if (error >= 0)
-				error = wacom_get_report(intf,
-						WAC_HID_FEATURE_REPORT,
-						report_id, rep_data, 4, 1);
-		} while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
+	/* ask to report Wacom data */
+	if (features->device_type == BTN_TOOL_FINGER) {
+		/* if it is an MT Tablet PC touch */
+		if (features->type == TABLETPC2FG ||
+		    features->type == MTSCREEN) {
+			do {
+				rep_data[0] = 3;
+				rep_data[1] = 4;
+				rep_data[2] = 0;
+				rep_data[3] = 0;
+				report_id = 3;
+				error = wacom_set_report(intf,
+							 WAC_HID_FEATURE_REPORT,
+							 report_id,
+							 rep_data, 4, 1);
+				if (error >= 0)
+					error = wacom_get_report(intf,
+							WAC_HID_FEATURE_REPORT,
+							report_id,
+							rep_data, 4, 1);
+			} while ((error < 0 || rep_data[1] != 4) &&
+				 limit++ < WAC_MSG_RETRIES);
+		}
 	} else if (features->type != TABLETPC &&
 		   features->type != WIRELESS &&
 		   features->device_type == BTN_TOOL_PEN) {
@@ -447,7 +484,7 @@
 }
 
 static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
-		struct wacom_features *features)
+					 struct wacom_features *features)
 {
 	int error = 0;
 	struct usb_host_interface *interface = intf->cur_altsetting;
@@ -475,16 +512,21 @@
 		}
 	}
 
-	/* only Tablet PCs and Bamboo P&T need to retrieve the info */
-	if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
-	    (features->type != BAMBOO_PT))
+	/* only devices that support touch need to retrieve the info */
+	if (features->type != TABLETPC &&
+	    features->type != TABLETPC2FG &&
+	    features->type != BAMBOO_PT &&
+	    features->type != MTSCREEN) {
 		goto out;
+	}
 
-	if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
-		if (usb_get_extra_descriptor(&interface->endpoint[0],
-				HID_DEVICET_REPORT, &hid_desc)) {
-			printk("wacom: can not retrieve extra class descriptor\n");
-			error = 1;
+	error = usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc);
+	if (error) {
+		error = usb_get_extra_descriptor(&interface->endpoint[0],
+						 HID_DEVICET_REPORT, &hid_desc);
+		if (error) {
+			dev_err(&intf->dev,
+				"can not retrieve extra class descriptor\n");
 			goto out;
 		}
 	}
@@ -574,23 +616,39 @@
 static int wacom_led_control(struct wacom *wacom)
 {
 	unsigned char *buf;
-	int retval, led = 0;
+	int retval;
 
 	buf = kzalloc(9, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
-	if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
-	    wacom->wacom_wac.features.type == WACOM_24HD)
-		led = (wacom->led.select[1] << 4) | 0x40;
+	if (wacom->wacom_wac.features.type >= INTUOS5S &&
+	    wacom->wacom_wac.features.type <= INTUOS5L)	{
+		/*
+		 * Touch Ring and crop mark LED luminance may take on
+		 * one of four values:
+		 *    0 = Low; 1 = Medium; 2 = High; 3 = Off
+		 */
+		int ring_led = wacom->led.select[0] & 0x03;
+		int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
+		int crop_lum = 0;
 
-	led |=  wacom->led.select[0] | 0x4;
+		buf[0] = WAC_CMD_LED_CONTROL;
+		buf[1] = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
+	}
+	else {
+		int led = wacom->led.select[0] | 0x4;
 
-	buf[0] = WAC_CMD_LED_CONTROL;
-	buf[1] = led;
-	buf[2] = wacom->led.llv;
-	buf[3] = wacom->led.hlv;
-	buf[4] = wacom->led.img_lum;
+		if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
+		    wacom->wacom_wac.features.type == WACOM_24HD)
+			led |= (wacom->led.select[1] << 4) | 0x40;
+
+		buf[0] = WAC_CMD_LED_CONTROL;
+		buf[1] = led;
+		buf[2] = wacom->led.llv;
+		buf[3] = wacom->led.hlv;
+		buf[4] = wacom->led.img_lum;
+	}
 
 	retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL,
 				  buf, 9, WAC_CMD_RETRIES);
@@ -783,6 +841,17 @@
 	.attrs = intuos4_led_attrs,
 };
 
+static struct attribute *intuos5_led_attrs[] = {
+	&dev_attr_status0_luminance.attr,
+	&dev_attr_status_led0_select.attr,
+	NULL
+};
+
+static struct attribute_group intuos5_led_attr_group = {
+	.name = "wacom_led",
+	.attrs = intuos5_led_attrs,
+};
+
 static int wacom_initialize_leds(struct wacom *wacom)
 {
 	int error;
@@ -812,6 +881,19 @@
 					   &cintiq_led_attr_group);
 		break;
 
+	case INTUOS5S:
+	case INTUOS5:
+	case INTUOS5L:
+		wacom->led.select[0] = 0;
+		wacom->led.select[1] = 0;
+		wacom->led.llv = 32;
+		wacom->led.hlv = 0;
+		wacom->led.img_lum = 0;
+
+		error = sysfs_create_group(&wacom->intf->dev.kobj,
+					   &intuos5_led_attr_group);
+		break;
+
 	default:
 		return 0;
 	}
@@ -840,6 +922,13 @@
 		sysfs_remove_group(&wacom->intf->dev.kobj,
 				   &cintiq_led_attr_group);
 		break;
+
+	case INTUOS5S:
+	case INTUOS5:
+	case INTUOS5L:
+		sysfs_remove_group(&wacom->intf->dev.kobj,
+				   &intuos5_led_attr_group);
+		break;
 	}
 }
 
@@ -901,8 +990,10 @@
 	int error;
 
 	input_dev = input_allocate_device();
-	if (!input_dev)
-		return -ENOMEM;
+	if (!input_dev) {
+		error = -ENOMEM;
+		goto fail1;
+	}
 
 	input_dev->name = wacom_wac->name;
 	input_dev->dev.parent = &intf->dev;
@@ -912,14 +1003,20 @@
 	input_set_drvdata(input_dev, wacom);
 
 	wacom_wac->input = input_dev;
-	wacom_setup_input_capabilities(input_dev, wacom_wac);
+	error = wacom_setup_input_capabilities(input_dev, wacom_wac);
+	if (error)
+		goto fail1;
 
 	error = input_register_device(input_dev);
-	if (error) {
-		input_free_device(input_dev);
-		wacom_wac->input = NULL;
-	}
+	if (error)
+		goto fail2;
 
+	return 0;
+
+fail2:
+	input_free_device(input_dev);
+	wacom_wac->input = NULL;
+fail1:
 	return error;
 }
 
@@ -938,22 +1035,22 @@
 	wacom = usb_get_intfdata(usbdev->config->interface[1]);
 	if (wacom->wacom_wac.input)
 		input_unregister_device(wacom->wacom_wac.input);
-	wacom->wacom_wac.input = 0;
+	wacom->wacom_wac.input = NULL;
 
 	/* Touch interface */
 	wacom = usb_get_intfdata(usbdev->config->interface[2]);
 	if (wacom->wacom_wac.input)
 		input_unregister_device(wacom->wacom_wac.input);
-	wacom->wacom_wac.input = 0;
+	wacom->wacom_wac.input = NULL;
 
 	if (wacom_wac->pid == 0) {
-		printk(KERN_INFO "wacom: wireless tablet disconnected\n");
+		dev_info(&wacom->intf->dev, "wireless tablet disconnected\n");
 	} else {
 		const struct usb_device_id *id = wacom_ids;
 
-		printk(KERN_INFO
-		       "wacom: wireless tablet connected with PID %x\n",
-		       wacom_wac->pid);
+		dev_info(&wacom->intf->dev,
+			 "wireless tablet connected with PID %x\n",
+			 wacom_wac->pid);
 
 		while (id->match_flags) {
 			if (id->idVendor == USB_VENDOR_ID_WACOM &&
@@ -963,8 +1060,8 @@
 		}
 
 		if (!id->match_flags) {
-			printk(KERN_INFO
-			       "wacom: ignorning unknown PID.\n");
+			dev_info(&wacom->intf->dev,
+				 "ignoring unknown PID.\n");
 			return;
 		}
 
@@ -1035,11 +1132,33 @@
 
 	endpoint = &intf->cur_altsetting->endpoint[0].desc;
 
-	/* Retrieve the physical and logical size for OEM devices */
+	/* Retrieve the physical and logical size for touch devices */
 	error = wacom_retrieve_hid_descriptor(intf, features);
 	if (error)
 		goto fail3;
 
+	/*
+	 * Intuos5 has no useful data about its touch interface in its
+	 * HID descriptor. If this is the touch interface (wMaxPacketSize
+	 * of WACOM_PKGLEN_BBTOUCH3), override the table values.
+	 */
+	if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
+		if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) {
+			features->device_type = BTN_TOOL_FINGER;
+			features->pktlen = WACOM_PKGLEN_BBTOUCH3;
+
+			features->x_phy =
+				(features->x_max * 100) / features->x_resolution;
+			features->y_phy =
+				(features->y_max * 100) / features->y_resolution;
+
+			features->x_max = 4096;
+			features->y_max = 4096;
+		} else {
+			features->device_type = BTN_TOOL_PEN;
+		}
+	}
+
 	wacom_setup_device_quirks(features);
 
 	strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index cecd35c..004bc1b 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -61,7 +61,8 @@
 		break;
 
 	default:
-		printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
 		return 0;
         }
 
@@ -76,7 +77,8 @@
 	int prox, pressure;
 
 	if (data[0] != WACOM_REPORT_PENABLED) {
-		dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
 		return 0;
 	}
 
@@ -146,7 +148,8 @@
 	struct input_dev *input = wacom->input;
 
 	if (data[0] != WACOM_REPORT_PENABLED) {
-		printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
 		return 0;
 	}
 
@@ -175,7 +178,8 @@
 	struct input_dev *input = wacom->input;
 	int prox = data[1] & 0x20, pressure;
 
-	dbg("wacom_dtu_irq: received report #%d", data[0]);
+	dev_dbg(input->dev.parent,
+		"%s: received report #%d", __func__, data[0]);
 
 	if (prox) {
 		/* Going into proximity select tool */
@@ -211,7 +215,8 @@
 	int retval = 0;
 
 	if (data[0] != WACOM_REPORT_PENABLED) {
-		dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
 		goto exit;
 	}
 
@@ -321,6 +326,9 @@
 
 	/* Enter report */
 	if ((data[1] & 0xfc) == 0xc0) {
+		if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+			wacom->shared->stylus_in_proximity = true;
+
 		/* serial number of the tool */
 		wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
 			(data[4] << 20) + (data[5] << 12) +
@@ -406,6 +414,9 @@
 
 	/* Exit report */
 	if ((data[1] & 0xfe) == 0x80) {
+		if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+			wacom->shared->stylus_in_proximity = false;
+
 		/*
 		 * Reset all states otherwise we lose the initial states
 		 * when in-prox next time
@@ -452,6 +463,7 @@
 	if ((data[1] & 0xb8) == 0xa0) {
 		t = (data[6] << 2) | ((data[7] >> 6) & 3);
 		if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
+                    (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
 		    features->type == WACOM_21UX2 || features->type == WACOM_24HD) {
 			t = (t << 1) | (data[1] & 1);
 		}
@@ -482,9 +494,13 @@
 	unsigned int t;
 	int idx = 0, result;
 
-	if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_INTUOSREAD
-		&& data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD) {
-		dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+	if (data[0] != WACOM_REPORT_PENABLED &&
+	    data[0] != WACOM_REPORT_INTUOSREAD &&
+	    data[0] != WACOM_REPORT_INTUOSWRITE &&
+	    data[0] != WACOM_REPORT_INTUOSPAD &&
+	    data[0] != WACOM_REPORT_INTUOS5PAD) {
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
                 return 0;
 	}
 
@@ -493,7 +509,7 @@
 		idx = data[1] & 0x01;
 
 	/* pad packets. Works as a second tool and is always in prox */
-	if (data[0] == WACOM_REPORT_INTUOSPAD) {
+	if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
 		if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
 			input_report_key(input, BTN_0, (data[2] & 0x01));
 			input_report_key(input, BTN_1, (data[3] & 0x01));
@@ -569,6 +585,34 @@
 				input_report_key(input, wacom->tool[1], 0);
 				input_report_abs(input, ABS_MISC, 0);
 			}
+		} else if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
+			int i;
+
+			/* Touch ring mode switch has no capacitive sensor */
+			input_report_key(input, BTN_0, (data[3] & 0x01));
+
+			/*
+			 * ExpressKeys on Intuos5 have a capacitive sensor in
+			 * addition to the mechanical switch. Switch data is
+			 * stored in data[4], capacitive data in data[5].
+			 */
+			for (i = 0; i < 8; i++)
+				input_report_key(input, BTN_1 + i, data[4] & (1 << i));
+
+			if (data[2] & 0x80) {
+				input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
+			} else {
+				/* Out of proximity, clear wheel value. */
+				input_report_abs(input, ABS_WHEEL, 0);
+			}
+
+			if (data[2] | (data[3] & 0x01) | data[4]) {
+				input_report_key(input, wacom->tool[1], 1);
+				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+			} else {
+				input_report_key(input, wacom->tool[1], 0);
+				input_report_abs(input, ABS_MISC, 0);
+			}
 		} else {
 			if (features->type == WACOM_21UX2) {
 				input_report_key(input, BTN_0, (data[5] & 0x01));
@@ -632,7 +676,9 @@
 	    (features->type == INTUOS3 ||
 	     features->type == INTUOS3S ||
 	     features->type == INTUOS4 ||
-	     features->type == INTUOS4S)) {
+	     features->type == INTUOS4S ||
+	     features->type == INTUOS5 ||
+	     features->type == INTUOS5S)) {
 
 		return 0;
 	}
@@ -685,7 +731,8 @@
 
 		} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
 			/* I4 mouse */
-			if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
+			if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
+			    (features->type >= INTUOS5S && features->type <= INTUOS5L)) {
 				input_report_key(input, BTN_LEFT,   data[6] & 0x01);
 				input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
 				input_report_key(input, BTN_RIGHT,  data[6] & 0x04);
@@ -712,7 +759,7 @@
 				}
 			}
 		} else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
-				features->type == INTUOS4L) &&
+				features->type == INTUOS4L || features->type == INTUOS5L) &&
 			   wacom->tool[idx] == BTN_TOOL_LENS) {
 			/* Lens cursor packets */
 			input_report_key(input, BTN_LEFT,   data[8] & 0x01);
@@ -729,6 +776,72 @@
 	return 1;
 }
 
+static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid)
+{
+	int touch_max = wacom->features.touch_max;
+	int i;
+
+	if (!wacom->slots)
+		return -1;
+
+	for (i = 0; i < touch_max; ++i) {
+		if (wacom->slots[i] == contactid)
+			return i;
+	}
+	for (i = 0; i < touch_max; ++i) {
+		if (wacom->slots[i] == -1)
+			return i;
+	}
+	return -1;
+}
+
+static int wacom_mt_touch(struct wacom_wac *wacom)
+{
+	struct input_dev *input = wacom->input;
+	char *data = wacom->data;
+	int i;
+	int current_num_contacts = data[2];
+	int contacts_to_send = 0;
+
+	/*
+	 * First packet resets the counter since only the first
+	 * packet in series will have non-zero current_num_contacts.
+	 */
+	if (current_num_contacts)
+		wacom->num_contacts_left = current_num_contacts;
+
+	/* There are at most 5 contacts per packet */
+	contacts_to_send = min(5, wacom->num_contacts_left);
+
+	for (i = 0; i < contacts_to_send; i++) {
+		int offset = (WACOM_BYTES_PER_MT_PACKET * i) + 3;
+		bool touch = data[offset] & 0x1;
+		int id = le16_to_cpup((__le16 *)&data[offset + 1]);
+		int slot = find_slot_from_contactid(wacom, id);
+
+		if (slot < 0)
+			continue;
+
+		input_mt_slot(input, slot);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+		if (touch) {
+			int x = le16_to_cpup((__le16 *)&data[offset + 7]);
+			int y = le16_to_cpup((__le16 *)&data[offset + 9]);
+			input_report_abs(input, ABS_MT_POSITION_X, x);
+			input_report_abs(input, ABS_MT_POSITION_Y, y);
+		}
+		wacom->slots[slot] = touch ? id : -1;
+	}
+
+	input_mt_report_pointer_emulation(input, true);
+
+	wacom->num_contacts_left -= contacts_to_send;
+	if (wacom->num_contacts_left < 0)
+		wacom->num_contacts_left = 0;
+
+	return 1;
+}
+
 static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
 {
 	struct input_dev *input = wacom->input;
@@ -767,6 +880,9 @@
 	bool prox;
 	int x = 0, y = 0;
 
+	if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
+		return 0;
+
 	if (!wacom->shared->stylus_in_proximity) {
 		if (len == WACOM_PKGLEN_TPC1FG) {
 			prox = data[0] & 0x01;
@@ -830,14 +946,15 @@
 {
 	char *data = wacom->data;
 
-	dbg("wacom_tpc_irq: received report #%d", data[0]);
+	dev_dbg(wacom->input->dev.parent,
+		"%s: received report #%d\n", __func__, data[0]);
 
 	switch (len) {
 	case WACOM_PKGLEN_TPC1FG:
-		 return wacom_tpc_single_touch(wacom, len);
+		return wacom_tpc_single_touch(wacom, len);
 
 	case WACOM_PKGLEN_TPC2FG:
- 		return wacom_tpc_mt_touch(wacom);
+		return wacom_tpc_mt_touch(wacom);
 
 	default:
 		switch (data[0]) {
@@ -846,6 +963,9 @@
 		case WACOM_REPORT_TPCST:
 			return wacom_tpc_single_touch(wacom, len);
 
+		case WACOM_REPORT_TPCMT:
+			return wacom_mt_touch(wacom);
+
 		case WACOM_REPORT_PENABLED:
 			return wacom_tpc_pen(wacom);
 		}
@@ -1114,8 +1234,18 @@
 		sync = wacom_intuos_irq(wacom_wac);
 		break;
 
+	case INTUOS5S:
+	case INTUOS5:
+	case INTUOS5L:
+		if (len == WACOM_PKGLEN_BBTOUCH3)
+			sync = wacom_bpt3_touch(wacom_wac);
+		else
+			sync = wacom_intuos_irq(wacom_wac);
+		break;
+
 	case TABLETPC:
 	case TABLETPC2FG:
+	case MTSCREEN:
 		sync = wacom_tpc_irq(wacom_wac, len);
 		break;
 
@@ -1188,7 +1318,9 @@
 
 	/* these device have multiple inputs */
 	if (features->type == TABLETPC || features->type == TABLETPC2FG ||
-	    features->type == BAMBOO_PT || features->type == WIRELESS)
+	    features->type == BAMBOO_PT || features->type == WIRELESS ||
+	    (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
+	    features->type == MTSCREEN)
 		features->quirks |= WACOM_QUIRK_MULTI_INPUT;
 
 	/* quirk for bamboo touch with 2 low res touches */
@@ -1219,8 +1351,8 @@
        return (logical_max * 100) / physical_max;
 }
 
-void wacom_setup_input_capabilities(struct input_dev *input_dev,
-				    struct wacom_wac *wacom_wac)
+int wacom_setup_input_capabilities(struct input_dev *input_dev,
+				   struct wacom_wac *wacom_wac)
 {
 	struct wacom_features *features = &wacom_wac->features;
 	int i;
@@ -1355,6 +1487,50 @@
 		wacom_setup_intuos(wacom_wac);
 		break;
 
+	case INTUOS5:
+	case INTUOS5L:
+		if (features->device_type == BTN_TOOL_PEN) {
+			__set_bit(BTN_7, input_dev->keybit);
+			__set_bit(BTN_8, input_dev->keybit);
+		}
+		/* fall through */
+
+	case INTUOS5S:
+		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+		if (features->device_type == BTN_TOOL_PEN) {
+			for (i = 0; i < 7; i++)
+				__set_bit(BTN_0 + i, input_dev->keybit);
+
+			input_set_abs_params(input_dev, ABS_DISTANCE, 0,
+					      features->distance_max,
+					      0, 0);
+
+			input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+
+			wacom_setup_intuos(wacom_wac);
+		} else if (features->device_type == BTN_TOOL_FINGER) {
+			__clear_bit(ABS_MISC, input_dev->absbit);
+
+			__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+			__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+			__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
+			__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
+
+			input_mt_init_slots(input_dev, features->touch_max);
+
+			input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+			                     0, 255, 0, 0);
+
+			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+					     0, features->x_max,
+					     features->x_fuzz, 0);
+			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+					     0, features->y_max,
+					     features->y_fuzz, 0);
+		}
+		break;
+
 	case INTUOS4:
 	case INTUOS4L:
 		__set_bit(BTN_7, input_dev->keybit);
@@ -1372,9 +1548,19 @@
 		break;
 
 	case TABLETPC2FG:
+	case MTSCREEN:
 		if (features->device_type == BTN_TOOL_FINGER) {
 
-			input_mt_init_slots(input_dev, 2);
+			wacom_wac->slots = kmalloc(features->touch_max *
+							sizeof(int),
+						   GFP_KERNEL);
+			if (!wacom_wac->slots)
+				return -ENOMEM;
+
+			for (i = 0; i < features->touch_max; i++)
+				wacom_wac->slots[i] = -1;
+
+			input_mt_init_slots(input_dev, features->touch_max);
 			input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
 					0, MT_TOOL_MAX, 0, 0);
 			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@@ -1429,6 +1615,7 @@
 
 			__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
 			__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+			input_mt_init_slots(input_dev, features->touch_max);
 
 			if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
 				__set_bit(BTN_TOOL_TRIPLETAP,
@@ -1436,13 +1623,9 @@
 				__set_bit(BTN_TOOL_QUADTAP,
 					  input_dev->keybit);
 
-				input_mt_init_slots(input_dev, 16);
-
 				input_set_abs_params(input_dev,
 						     ABS_MT_TOUCH_MAJOR,
 						     0, 255, 0, 0);
-			} else {
-				input_mt_init_slots(input_dev, 2);
 			}
 
 			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@@ -1462,6 +1645,7 @@
 		}
 		break;
 	}
+	return 0;
 }
 
 static const struct wacom_features wacom_features_0x00 =
@@ -1629,6 +1813,24 @@
 static const struct wacom_features wacom_features_0xBC =
 	{ "Wacom Intuos4 WL",     WACOM_PKGLEN_INTUOS,    40840, 25400, 2047,
 	  63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x26 =
+	{ "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
+	  63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+	  .touch_max = 16 };
+static const struct wacom_features wacom_features_0x27 =
+	{ "Wacom Intuos5 touch M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
+	  63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+	  .touch_max = 16 };
+static const struct wacom_features wacom_features_0x28 =
+	{ "Wacom Intuos5 touch L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047,
+	  63, INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+	  .touch_max = 16 };
+static const struct wacom_features wacom_features_0x29 =
+	{ "Wacom Intuos5 S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
+	  63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x2A =
+	{ "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
+	  63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xF4 =
 	{ "Wacom Cintiq 24HD",    WACOM_PKGLEN_INTUOS,   104480, 65600, 2047,
 	  63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
@@ -1670,13 +1872,19 @@
 	  0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xE2 =
 	{ "Wacom ISDv4 E2",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,
-	  0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
 static const struct wacom_features wacom_features_0xE3 =
 	{ "Wacom ISDv4 E3",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,
-	  0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
+static const struct wacom_features wacom_features_0xE5 =
+	{ "Wacom ISDv4 E5",       WACOM_PKGLEN_MTOUCH,    26202, 16325,  255,
+	  0, MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xE6 =
 	{ "Wacom ISDv4 E6",       WACOM_PKGLEN_TPC2FG,    27760, 15694,  255,
-	  0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	.touch_max = 2 };
 static const struct wacom_features wacom_features_0xEC =
 	{ "Wacom ISDv4 EC",       WACOM_PKGLEN_GRAPHIRE,  25710, 14500,  255,
 	  0, TABLETPC,    WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1685,19 +1893,22 @@
 	  31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x84 =
 	{ "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, 0, 0, 0,
-	  0, WIRELESS, 0, 0 };
+	  0, WIRELESS, 0, 0, .touch_max = 16 };
 static const struct wacom_features wacom_features_0xD0 =
 	{ "Wacom Bamboo 2FG",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
-	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD1 =
 	{ "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
-	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD2 =
 	{ "Wacom Bamboo Craft",   WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
 	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD3 =
 	{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN,     21648, 13700, 1023,
-	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD4 =
 	{ "Wacom Bamboo Pen",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
 	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1706,28 +1917,35 @@
 	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD6 =
 	{ "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN,   14720,  9200, 1023,
-	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD7 =
 	{ "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720,  9200, 1023,
-	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD8 =
 	{ "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN,   21648, 13700, 1023,
-	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
 static const struct wacom_features wacom_features_0xDA =
 	{ "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN,  14720,  9200, 1023,
-	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
 static struct wacom_features wacom_features_0xDB =
 	{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN,  21648, 13700, 1023,
-	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 2 };
 static const struct wacom_features wacom_features_0xDD =
         { "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN,     14720,  9200, 1023,
           31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xDE =
         { "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN,    14720,  9200, 1023,
-          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 16 };
 static const struct wacom_features wacom_features_0xDF =
         { "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN,    21648, 13700, 1023,
-          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 16 };
 static const struct wacom_features wacom_features_0x6004 =
 	{ "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800,  8000,  255,
 	  0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1801,6 +2019,11 @@
 	{ USB_DEVICE_WACOM(0xBA) },
 	{ USB_DEVICE_WACOM(0xBB) },
 	{ USB_DEVICE_WACOM(0xBC) },
+	{ USB_DEVICE_WACOM(0x26) },
+	{ USB_DEVICE_WACOM(0x27) },
+	{ USB_DEVICE_WACOM(0x28) },
+	{ USB_DEVICE_WACOM(0x29) },
+	{ USB_DEVICE_WACOM(0x2A) },
 	{ USB_DEVICE_WACOM(0x3F) },
 	{ USB_DEVICE_WACOM(0xC5) },
 	{ USB_DEVICE_WACOM(0xC6) },
@@ -1836,6 +2059,7 @@
 	{ USB_DEVICE_WACOM(0x9F) },
 	{ USB_DEVICE_WACOM(0xE2) },
 	{ USB_DEVICE_WACOM(0xE3) },
+	{ USB_DEVICE_WACOM(0xE5) },
 	{ USB_DEVICE_WACOM(0xE6) },
 	{ USB_DEVICE_WACOM(0xEC) },
 	{ USB_DEVICE_WACOM(0x47) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index ba5a334..78fbd3f 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -25,6 +25,10 @@
 #define WACOM_PKGLEN_BBTOUCH3	64
 #define WACOM_PKGLEN_BBPEN	10
 #define WACOM_PKGLEN_WIRELESS	32
+#define WACOM_PKGLEN_MTOUCH	62
+
+/* wacom data size per MT contact */
+#define WACOM_BYTES_PER_MT_PACKET	11
 
 /* device IDs */
 #define STYLUS_DEVICE_ID	0x02
@@ -38,8 +42,10 @@
 #define WACOM_REPORT_INTUOSREAD		5
 #define WACOM_REPORT_INTUOSWRITE	6
 #define WACOM_REPORT_INTUOSPAD		12
+#define WACOM_REPORT_INTUOS5PAD		3
 #define WACOM_REPORT_TPC1FG		6
 #define WACOM_REPORT_TPC2FG		13
+#define WACOM_REPORT_TPCMT		13
 #define WACOM_REPORT_TPCHID		15
 #define WACOM_REPORT_TPCST		16
 
@@ -65,6 +71,9 @@
 	INTUOS4S,
 	INTUOS4,
 	INTUOS4L,
+	INTUOS5S,
+	INTUOS5,
+	INTUOS5L,
 	WACOM_24HD,
 	WACOM_21UX2,
 	CINTIQ,
@@ -72,6 +81,7 @@
 	WACOM_MO,
 	TABLETPC,
 	TABLETPC2FG,
+	MTSCREEN,
 	MAX_TYPE
 };
 
@@ -95,6 +105,7 @@
 	int pressure_fuzz;
 	int distance_fuzz;
 	unsigned quirks;
+	unsigned touch_max;
 };
 
 struct wacom_shared {
@@ -113,6 +124,8 @@
 	struct input_dev *input;
 	int pid;
 	int battery_capacity;
+	int num_contacts_left;
+	int *slots;
 };
 
 #endif
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 2a21419..98d2635 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -187,6 +187,23 @@
 	  Say Y here to enable the support for the touchscreen found
 	  on Dialog Semiconductor DA9034 PMIC.
 
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called da9034-ts.
+
+config TOUCHSCREEN_DA9052
+	tristate "Dialog DA9052/DA9053 TSI"
+	depends on PMIC_DA9052
+	help
+	  Say Y here to support the touchscreen found on Dialog Semiconductor
+	  DA9052-BC and DA9053-AA/Bx PMICs.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called da9052_tsi.
+
 config TOUCHSCREEN_DYNAPRO
 	tristate "Dynapro serial touchscreen"
 	select SERIO
@@ -306,6 +323,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called wacom_w8001.
 
+config TOUCHSCREEN_WACOM_I2C
+	tristate "Wacom Tablet support (I2C)"
+	depends on I2C
+	help
+	  Say Y here if you want to use the I2C version of the Wacom
+	  Pen Tablet.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called wacom_i2c.
+
 config TOUCHSCREEN_LPC32XX
 	tristate "LPC32XX touchscreen controller"
 	depends on ARCH_LPC32XX
@@ -489,10 +518,10 @@
 
 config TOUCHSCREEN_ATMEL_TSADCC
 	tristate "Atmel Touchscreen Interface"
-	depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+	depends on ARCH_AT91
 	help
 	  Say Y here if you have a 4-wire touchscreen connected to the
-          ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
+          ADC Controller on your Atmel SoC.
 
 	  If unsure, say N.
 
@@ -635,6 +664,7 @@
 	  - Zytronic controllers
 	  - Elo TouchSystems 2700 IntelliTouch
 	  - EasyTouch USB Touch Controller from Data Modul
+	  - e2i (Mimo monitors)
 
 	  Have a look at <http://linux.chapter7.ch/touchkit/> for
 	  a usage description and the required user-space stuff.
@@ -721,7 +751,7 @@
 
 config TOUCHSCREEN_USB_E2I
 	default y
-	bool "e2i Touchscreen controller (e.g. from Mimo 740)"
+	bool "e2i Touchscreen controller (e.g. from Mimo 740)" if EXPERT
 	depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_ZYTRONIC
@@ -744,7 +774,7 @@
 	bool "EasyTouch USB Touch controller device support" if EMBEDDED
 	depends on TOUCHSCREEN_USB_COMPOSITE
 	help
-	  Say Y here if you have a EasyTouch USB Touch controller device support.
+	  Say Y here if you have an EasyTouch USB Touch controller.
 	  If unsure, say N.
 
 config TOUCHSCREEN_TOUCHIT213
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 3d5cf8c..eb8bfe1 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -22,6 +22,7 @@
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)	+= cyttsp_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)	+= cyttsp_spi.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
+obj-$(CONFIG_TOUCHSCREEN_DA9052)	+= da9052_tsi.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
@@ -59,6 +60,7 @@
 obj-$(CONFIG_TOUCHSCREEN_TSC2007)	+= tsc2007.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)	+= ucb1400_ts.o
 obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)	+= wacom_w8001.o
+obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C)	+= wacom_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_WM831X)	+= wm831x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX)	+= wm97xx-ts.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)	+= wm9705.o
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 19d4ea6..42e6450 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -236,7 +236,6 @@
 struct mxt_message {
 	u8 reportid;
 	u8 message[7];
-	u8 checksum;
 };
 
 struct mxt_finger {
@@ -326,17 +325,12 @@
 }
 
 static void mxt_dump_message(struct device *dev,
-				  struct mxt_message *message)
+			     struct mxt_message *message)
 {
-	dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
-	dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
-	dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
-	dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
-	dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
-	dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
-	dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
-	dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
-	dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
+	dev_dbg(dev, "reportid: %u\tmessage: %02x %02x %02x %02x %02x %02x %02x\n",
+		message->reportid, message->message[0], message->message[1],
+		message->message[2], message->message[3], message->message[4],
+		message->message[5], message->message[6]);
 }
 
 static int mxt_check_bootloader(struct i2c_client *client,
@@ -506,7 +500,7 @@
 	u16 reg;
 
 	object = mxt_get_object(data, type);
-	if (!object)
+	if (!object || offset >= object->size + 1)
 		return -EINVAL;
 
 	reg = object->start_address;
@@ -1049,8 +1043,8 @@
 	return count;
 }
 
-static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
-static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
+static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
+static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store);
 
 static struct attribute *mxt_attrs[] = {
 	&dev_attr_object.attr,
@@ -1201,7 +1195,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int mxt_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
@@ -1239,13 +1233,10 @@
 
 	return 0;
 }
-
-static const struct dev_pm_ops mxt_pm_ops = {
-	.suspend	= mxt_suspend,
-	.resume		= mxt_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
+
 static const struct i2c_device_id mxt_id[] = {
 	{ "qt602240_ts", 0 },
 	{ "atmel_mxt_ts", 0 },
@@ -1258,9 +1249,7 @@
 	.driver = {
 		.name	= "atmel_mxt_ts",
 		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
 		.pm	= &mxt_pm_ops,
-#endif
 	},
 	.probe		= mxt_probe,
 	.remove		= __devexit_p(mxt_remove),
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c
new file mode 100644
index 0000000..e8df341
--- /dev/null
+++ b/drivers/input/touchscreen/da9052_tsi.c
@@ -0,0 +1,370 @@
+/*
+ * TSI driver for Dialog DA9052
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.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/input.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/da9052.h>
+
+#define TSI_PEN_DOWN_STATUS 0x40
+
+struct da9052_tsi {
+	struct da9052 *da9052;
+	struct input_dev *dev;
+	struct delayed_work ts_pen_work;
+	struct mutex mutex;
+	unsigned int irq_pendwn;
+	unsigned int irq_datardy;
+	bool stopped;
+	bool adc_on;
+};
+
+static void da9052_ts_adc_toggle(struct da9052_tsi *tsi, bool on)
+{
+	da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 0, on);
+	tsi->adc_on = on;
+}
+
+static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data)
+{
+	struct da9052_tsi *tsi = data;
+
+	if (!tsi->stopped) {
+		/* Mask PEN_DOWN event and unmask TSI_READY event */
+		disable_irq_nosync(tsi->irq_pendwn);
+		enable_irq(tsi->irq_datardy);
+
+		da9052_ts_adc_toggle(tsi, true);
+
+		schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void da9052_ts_read(struct da9052_tsi *tsi)
+{
+	struct input_dev *input = tsi->dev;
+	int ret;
+	u16 x, y, z;
+	u8 v;
+
+	ret = da9052_reg_read(tsi->da9052, DA9052_TSI_X_MSB_REG);
+	if (ret < 0)
+		return;
+
+	x = (u16) ret;
+
+	ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Y_MSB_REG);
+	if (ret < 0)
+		return;
+
+	y = (u16) ret;
+
+	ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Z_MSB_REG);
+	if (ret < 0)
+		return;
+
+	z = (u16) ret;
+
+	ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
+	if (ret < 0)
+		return;
+
+	v = (u8) ret;
+
+	x = ((x << 2) & 0x3fc) | (v & 0x3);
+	y = ((y << 2) & 0x3fc) | ((v & 0xc) >> 2);
+	z = ((z << 2) & 0x3fc) | ((v & 0x30) >> 4);
+
+	input_report_key(input, BTN_TOUCH, 1);
+	input_report_abs(input, ABS_X, x);
+	input_report_abs(input, ABS_Y, y);
+	input_report_abs(input, ABS_PRESSURE, z);
+	input_sync(input);
+}
+
+static irqreturn_t da9052_ts_datardy_irq(int irq, void *data)
+{
+	struct da9052_tsi *tsi = data;
+
+	da9052_ts_read(tsi);
+
+	return IRQ_HANDLED;
+}
+
+static void da9052_ts_pen_work(struct work_struct *work)
+{
+	struct da9052_tsi *tsi = container_of(work, struct da9052_tsi,
+					      ts_pen_work.work);
+	if (!tsi->stopped) {
+		int ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
+		if (ret < 0 || (ret & TSI_PEN_DOWN_STATUS)) {
+			/* Pen is still DOWN (or read error) */
+			schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
+		} else {
+			struct input_dev *input = tsi->dev;
+
+			/* Pen UP */
+			da9052_ts_adc_toggle(tsi, false);
+
+			/* Report Pen UP */
+			input_report_key(input, BTN_TOUCH, 0);
+			input_report_abs(input, ABS_PRESSURE, 0);
+			input_sync(input);
+
+			/*
+			 * FIXME: Fixes the unhandled irq issue when quick
+			 * pen down and pen up events occurs
+			 */
+			ret = da9052_reg_update(tsi->da9052,
+						DA9052_EVENT_B_REG, 0xC0, 0xC0);
+			if (ret < 0)
+				return;
+
+			/* Mask TSI_READY event and unmask PEN_DOWN event */
+			disable_irq(tsi->irq_datardy);
+			enable_irq(tsi->irq_pendwn);
+		}
+	}
+}
+
+static int __devinit da9052_ts_configure_gpio(struct da9052 *da9052)
+{
+	int error;
+
+	error = da9052_reg_update(da9052, DA9052_GPIO_2_3_REG, 0x30, 0);
+	if (error < 0)
+		return error;
+
+	error = da9052_reg_update(da9052, DA9052_GPIO_4_5_REG, 0x33, 0);
+	if (error < 0)
+		return error;
+
+	error = da9052_reg_update(da9052, DA9052_GPIO_6_7_REG, 0x33, 0);
+	if (error < 0)
+		return error;
+
+	return 0;
+}
+
+static int __devinit da9052_configure_tsi(struct da9052_tsi *tsi)
+{
+	int error;
+
+	error = da9052_ts_configure_gpio(tsi->da9052);
+	if (error)
+		return error;
+
+	/* Measure TSI sample every 1ms */
+	error = da9052_reg_update(tsi->da9052, DA9052_ADC_CONT_REG,
+				  1 << 6, 1 << 6);
+	if (error < 0)
+		return error;
+
+	/* TSI_DELAY: 3 slots, TSI_SKIP: 0 slots, TSI_MODE: XYZP */
+	error = da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 0xFC, 0xC0);
+	if (error < 0)
+		return error;
+
+	/* Supply TSIRef through LD09 */
+	error = da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x59);
+	if (error < 0)
+		return error;
+
+	return 0;
+}
+
+static int da9052_ts_input_open(struct input_dev *input_dev)
+{
+	struct da9052_tsi *tsi = input_get_drvdata(input_dev);
+
+	tsi->stopped = false;
+	mb();
+
+	/* Unmask PEN_DOWN event */
+	enable_irq(tsi->irq_pendwn);
+
+	/* Enable Pen Detect Circuit */
+	return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG,
+				 1 << 1, 1 << 1);
+}
+
+static void da9052_ts_input_close(struct input_dev *input_dev)
+{
+	struct da9052_tsi *tsi = input_get_drvdata(input_dev);
+
+	tsi->stopped = true;
+	mb();
+	disable_irq(tsi->irq_pendwn);
+	cancel_delayed_work_sync(&tsi->ts_pen_work);
+
+	if (tsi->adc_on) {
+		disable_irq(tsi->irq_datardy);
+		da9052_ts_adc_toggle(tsi, false);
+
+		/*
+		 * If ADC was on that means that pendwn IRQ was disabled
+		 * twice and we need to enable it to keep enable/disable
+		 * counter balanced. IRQ is still off though.
+		 */
+		enable_irq(tsi->irq_pendwn);
+	}
+
+	/* Disable Pen Detect Circuit */
+	da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
+}
+
+static int __devinit da9052_ts_probe(struct platform_device *pdev)
+{
+	struct da9052 *da9052;
+	struct da9052_tsi *tsi;
+	struct input_dev *input_dev;
+	int irq_pendwn;
+	int irq_datardy;
+	int error;
+
+	da9052 = dev_get_drvdata(pdev->dev.parent);
+	if (!da9052)
+		return -EINVAL;
+
+	irq_pendwn = platform_get_irq_byname(pdev, "PENDWN");
+	irq_datardy = platform_get_irq_byname(pdev, "TSIRDY");
+	if (irq_pendwn < 0 || irq_datardy < 0) {
+		dev_err(da9052->dev, "Unable to determine device interrupts\n");
+		return -ENXIO;
+	}
+
+	tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!tsi || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	tsi->da9052 = da9052;
+	tsi->dev = input_dev;
+	tsi->irq_pendwn = da9052->irq_base + irq_pendwn;
+	tsi->irq_datardy = da9052->irq_base + irq_datardy;
+	tsi->stopped = true;
+	INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work);
+
+	input_dev->id.version = 0x0101;
+	input_dev->id.vendor = 0x15B6;
+	input_dev->id.product = 0x9052;
+	input_dev->name = "Dialog DA9052 TouchScreen Driver";
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->open = da9052_ts_input_open;
+	input_dev->close = da9052_ts_input_close;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1023, 0, 0);
+
+	input_set_drvdata(input_dev, tsi);
+
+	/* Disable Pen Detect Circuit */
+	da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
+
+	/* Disable ADC */
+	da9052_ts_adc_toggle(tsi, false);
+
+	error = request_threaded_irq(tsi->irq_pendwn,
+				     NULL, da9052_ts_pendwn_irq,
+				     IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				     "PENDWN", tsi);
+	if (error) {
+		dev_err(tsi->da9052->dev,
+			"Failed to register PENDWN IRQ %d, error = %d\n",
+			tsi->irq_pendwn, error);
+		goto err_free_mem;
+	}
+
+	error = request_threaded_irq(tsi->irq_datardy,
+				     NULL, da9052_ts_datardy_irq,
+				     IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				     "TSIRDY", tsi);
+	if (error) {
+		dev_err(tsi->da9052->dev,
+			"Failed to register TSIRDY IRQ %d, error = %d\n",
+			tsi->irq_datardy, error);
+		goto err_free_pendwn_irq;
+	}
+
+	/* Mask PEN_DOWN and TSI_READY events */
+	disable_irq(tsi->irq_pendwn);
+	disable_irq(tsi->irq_datardy);
+
+	error = da9052_configure_tsi(tsi);
+	if (error)
+		goto err_free_datardy_irq;
+
+	error = input_register_device(tsi->dev);
+	if (error)
+		goto err_free_datardy_irq;
+
+	platform_set_drvdata(pdev, tsi);
+
+	return 0;
+
+err_free_datardy_irq:
+	free_irq(tsi->irq_datardy, tsi);
+err_free_pendwn_irq:
+	free_irq(tsi->irq_pendwn, tsi);
+err_free_mem:
+	kfree(tsi);
+	input_free_device(input_dev);
+
+	return error;
+}
+
+static int  __devexit da9052_ts_remove(struct platform_device *pdev)
+{
+	struct da9052_tsi *tsi = platform_get_drvdata(pdev);
+
+	da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19);
+
+	free_irq(tsi->irq_pendwn, tsi);
+	free_irq(tsi->irq_datardy, tsi);
+
+	input_unregister_device(tsi->dev);
+	kfree(tsi);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver da9052_tsi_driver = {
+	.probe	= da9052_ts_probe,
+	.remove	= __devexit_p(da9052_ts_remove),
+	.driver	= {
+		.name	= "da9052-tsi",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(da9052_tsi_driver);
+
+MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052");
+MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-tsi");
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
index 4553539..1809677 100644
--- a/drivers/input/touchscreen/dynapro.c
+++ b/drivers/input/touchscreen/dynapro.c
@@ -188,19 +188,4 @@
 	.disconnect	= dynapro_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init dynapro_init(void)
-{
-	return serio_register_driver(&dynapro_drv);
-}
-
-static void __exit dynapro_exit(void)
-{
-	serio_unregister_driver(&dynapro_drv);
-}
-
-module_init(dynapro_init);
-module_exit(dynapro_exit);
+module_serio_driver(dynapro_drv);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 486d31b..957423d 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -405,19 +405,4 @@
 	.disconnect	= elo_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init elo_init(void)
-{
-	return serio_register_driver(&elo_drv);
-}
-
-static void __exit elo_exit(void)
-{
-	serio_unregister_driver(&elo_drv);
-}
-
-module_init(elo_init);
-module_exit(elo_exit);
+module_serio_driver(elo_drv);
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
index 80b2180..10794dd 100644
--- a/drivers/input/touchscreen/fujitsu_ts.c
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -175,15 +175,4 @@
 	.disconnect	= fujitsu_disconnect,
 };
 
-static int __init fujitsu_init(void)
-{
-	return serio_register_driver(&fujitsu_drv);
-}
-
-static void __exit fujitsu_exit(void)
-{
-	serio_unregister_driver(&fujitsu_drv);
-}
-
-module_init(fujitsu_init);
-module_exit(fujitsu_exit);
+module_serio_driver(fujitsu_drv);
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index a54f90e0..41c71766 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -186,19 +186,4 @@
 	.disconnect	= gunze_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init gunze_init(void)
-{
-	return serio_register_driver(&gunze_drv);
-}
-
-static void __exit gunze_exit(void)
-{
-	serio_unregister_driver(&gunze_drv);
-}
-
-module_init(gunze_init);
-module_exit(gunze_exit);
+module_serio_driver(gunze_drv);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index 6107e56..b9e8686 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -476,19 +476,4 @@
 	.disconnect	= h3600ts_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init h3600ts_init(void)
-{
-	return serio_register_driver(&h3600ts_drv);
-}
-
-static void __exit h3600ts_exit(void)
-{
-	serio_unregister_driver(&h3600ts_drv);
-}
-
-module_init(h3600ts_init);
-module_exit(h3600ts_exit);
+module_serio_driver(h3600ts_drv);
diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c
index 2da6cc3..0cc47ea 100644
--- a/drivers/input/touchscreen/hampshire.c
+++ b/drivers/input/touchscreen/hampshire.c
@@ -187,19 +187,4 @@
 	.disconnect	= hampshire_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init hampshire_init(void)
-{
-	return serio_register_driver(&hampshire_drv);
-}
-
-static void __exit hampshire_exit(void)
-{
-	serio_unregister_driver(&hampshire_drv);
-}
-
-module_init(hampshire_init);
-module_exit(hampshire_exit);
+module_serio_driver(hampshire_drv);
diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c
index 192ade0..a29c99c 100644
--- a/drivers/input/touchscreen/inexio.c
+++ b/drivers/input/touchscreen/inexio.c
@@ -189,19 +189,4 @@
 	.disconnect	= inexio_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init inexio_init(void)
-{
-	return serio_register_driver(&inexio_drv);
-}
-
-static void __exit inexio_exit(void)
-{
-	serio_unregister_driver(&inexio_drv);
-}
-
-module_init(inexio_init);
-module_exit(inexio_exit);
+module_serio_driver(inexio_drv);
diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c
index afcd069..4c2b8ed 100644
--- a/drivers/input/touchscreen/lpc32xx_ts.c
+++ b/drivers/input/touchscreen/lpc32xx_ts.c
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 /*
  * Touchscreen controller register offsets
@@ -383,6 +384,14 @@
 #define LPC32XX_TS_PM_OPS NULL
 #endif
 
+#ifdef CONFIG_OF
+static struct of_device_id lpc32xx_tsc_of_match[] = {
+	{ .compatible = "nxp,lpc3220-tsc", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
+#endif
+
 static struct platform_driver lpc32xx_ts_driver = {
 	.probe		= lpc32xx_ts_probe,
 	.remove		= __devexit_p(lpc32xx_ts_remove),
@@ -390,6 +399,7 @@
 		.name	= MOD_NAME,
 		.owner	= THIS_MODULE,
 		.pm	= LPC32XX_TS_PM_OPS,
+		.of_match_table = of_match_ptr(lpc32xx_tsc_of_match),
 	},
 };
 module_platform_driver(lpc32xx_ts_driver);
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index 9077228..eb66b7c 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -202,19 +202,4 @@
 	.disconnect	= mtouch_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init mtouch_init(void)
-{
-	return serio_register_driver(&mtouch_drv);
-}
-
-static void __exit mtouch_exit(void)
-{
-	serio_unregister_driver(&mtouch_drv);
-}
-
-module_init(mtouch_init);
-module_exit(mtouch_exit);
+module_serio_driver(mtouch_drv);
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index 4c012fb..4ccde45 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -317,19 +317,4 @@
 	.disconnect	= pm_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init pm_init(void)
-{
-	return serio_register_driver(&pm_drv);
-}
-
-static void __exit pm_exit(void)
-{
-	serio_unregister_driver(&pm_drv);
-}
-
-module_init(pm_init);
-module_exit(pm_exit);
+module_serio_driver(pm_drv);
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index cbbf71b..6cb68a1 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -218,7 +218,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int st1232_ts_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
@@ -243,18 +243,25 @@
 	return 0;
 }
 
-static const struct dev_pm_ops st1232_ts_pm_ops = {
-	.suspend	= st1232_ts_suspend,
-	.resume		= st1232_ts_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
+			 st1232_ts_suspend, st1232_ts_resume);
+
 static const struct i2c_device_id st1232_ts_id[] = {
 	{ ST1232_TS_NAME, 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id st1232_ts_dt_ids[] __devinitconst = {
+	{ .compatible = "sitronix,st1232", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
+#endif
+
 static struct i2c_driver st1232_ts_driver = {
 	.probe		= st1232_ts_probe,
 	.remove		= __devexit_p(st1232_ts_remove),
@@ -262,9 +269,8 @@
 	.driver = {
 		.name	= ST1232_TS_NAME,
 		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
+		.of_match_table = of_match_ptr(st1232_ts_dt_ids),
 		.pm	= &st1232_ts_pm_ops,
-#endif
 	},
 };
 
diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c
index d1297ba..5f29e5b 100644
--- a/drivers/input/touchscreen/touchit213.c
+++ b/drivers/input/touchscreen/touchit213.c
@@ -216,19 +216,4 @@
 	.disconnect	= touchit213_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init touchit213_init(void)
-{
-	return serio_register_driver(&touchit213_drv);
-}
-
-static void __exit touchit213_exit(void)
-{
-	serio_unregister_driver(&touchit213_drv);
-}
-
-module_init(touchit213_init);
-module_exit(touchit213_exit);
+module_serio_driver(touchit213_drv);
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 3a5c142..8a2887d 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -176,19 +176,4 @@
 	.disconnect	= tr_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init tr_init(void)
-{
-	return serio_register_driver(&tr_drv);
-}
-
-static void __exit tr_exit(void)
-{
-	serio_unregister_driver(&tr_drv);
-}
-
-module_init(tr_init);
-module_exit(tr_exit);
+module_serio_driver(tr_drv);
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index 763a656..588cdcb 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -183,19 +183,4 @@
 	.disconnect	= tw_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init tw_init(void)
-{
-	return serio_register_driver(&tw_drv);
-}
-
-static void __exit tw_exit(void)
-{
-	serio_unregister_driver(&tw_drv);
-}
-
-module_init(tw_init);
-module_exit(tw_exit);
+module_serio_driver(tw_drv);
diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c
index 29d5ed4..63209aa 100644
--- a/drivers/input/touchscreen/tsc40.c
+++ b/drivers/input/touchscreen/tsc40.c
@@ -167,17 +167,7 @@
 	.disconnect     = tsc_disconnect,
 };
 
-static int __init tsc_ser_init(void)
-{
-	return serio_register_driver(&tsc_drv);
-}
-module_init(tsc_ser_init);
-
-static void __exit tsc_exit(void)
-{
-	serio_unregister_driver(&tsc_drv);
-}
-module_exit(tsc_exit);
+module_serio_driver(tsc_drv);
 
 MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 22cd96f..e32709e 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -269,8 +269,9 @@
 	                      0x01, 0x02, 0x0000, 0x0081,
 	                      NULL, 0, USB_CTRL_SET_TIMEOUT);
 
-	dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
-	    __func__, ret);
+	dev_dbg(&usbtouch->interface->dev,
+		"%s - usb_control_msg - E2I_RESET - bytes|err: %d\n",
+		__func__, ret);
 	return ret;
 }
 
@@ -425,8 +426,9 @@
 	                      MTOUCHUSB_RESET,
 	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 	                      1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-	dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
-	    __func__, ret);
+	dev_dbg(&usbtouch->interface->dev,
+		"%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d\n",
+		__func__, ret);
 	if (ret < 0)
 		return ret;
 	msleep(150);
@@ -436,8 +438,9 @@
 				      MTOUCHUSB_ASYNC_REPORT,
 				      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 				      1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
-		dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
-		    __func__, ret);
+		dev_dbg(&usbtouch->interface->dev,
+			"%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d\n",
+			__func__, ret);
 		if (ret >= 0)
 			break;
 		if (ret != -EPIPE)
@@ -737,27 +740,29 @@
 #ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
 static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
+	struct usb_interface *intf = dev->interface;
+
 	switch (pkt[0]) {
 	case 0x3A: /* command response */
-		dbg("%s: Command response %d", __func__, pkt[1]);
+		dev_dbg(&intf->dev, "%s: Command response %d\n", __func__, pkt[1]);
 		break;
 
 	case 0xC0: /* down */
 		dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
 		dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
 		dev->touch = 1;
-		dbg("%s: down %d,%d", __func__, dev->x, dev->y);
+		dev_dbg(&intf->dev, "%s: down %d,%d\n", __func__, dev->x, dev->y);
 		return 1;
 
 	case 0x80: /* up */
 		dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
 		dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
 		dev->touch = 0;
-		dbg("%s: up %d,%d", __func__, dev->x, dev->y);
+		dev_dbg(&intf->dev, "%s: up %d,%d\n", __func__, dev->x, dev->y);
 		return 1;
 
 	default:
-		dbg("%s: Unknown return %d", __func__, pkt[0]);
+		dev_dbg(&intf->dev, "%s: Unknown return %d\n", __func__, pkt[0]);
 		break;
 	}
 
@@ -812,7 +817,8 @@
 
 	priv->ack = usb_alloc_urb(0, GFP_KERNEL);
 	if (!priv->ack) {
-		dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+		dev_dbg(&usbtouch->interface->dev,
+			"%s - usb_alloc_urb failed: usbtouch->ack\n", __func__);
 		goto err_ack_buf;
 	}
 
@@ -1349,6 +1355,7 @@
 static void usbtouch_irq(struct urb *urb)
 {
 	struct usbtouch_usb *usbtouch = urb->context;
+	struct device *dev = &usbtouch->interface->dev;
 	int retval;
 
 	switch (urb->status) {
@@ -1357,20 +1364,21 @@
 		break;
 	case -ETIME:
 		/* this urb is timing out */
-		dbg("%s - urb timed out - was the device unplugged?",
-		    __func__);
+		dev_dbg(dev,
+			"%s - urb timed out - was the device unplugged?\n",
+			__func__);
 		return;
 	case -ECONNRESET:
 	case -ENOENT:
 	case -ESHUTDOWN:
 	case -EPIPE:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, urb->status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, urb->status);
+		dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+			__func__, urb->status);
 		goto exit;
 	}
 
@@ -1380,8 +1388,8 @@
 	usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		err("%s - usb_submit_urb failed with result: %d",
-		    __func__, retval);
+		dev_err(dev, "%s - usb_submit_urb failed with result: %d\n",
+			__func__, retval);
 }
 
 static int usbtouch_open(struct input_dev *input)
@@ -1456,8 +1464,9 @@
 	if (usbtouch->type->init) {
 		err = usbtouch->type->init(usbtouch);
 		if (err) {
-			dbg("%s - type->init() failed, err: %d",
-			    __func__, err);
+			dev_dbg(&intf->dev,
+				"%s - type->init() failed, err: %d\n",
+				__func__, err);
 			return err;
 		}
 	}
@@ -1532,7 +1541,8 @@
 
 	usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
 	if (!usbtouch->irq) {
-		dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);
+		dev_dbg(&intf->dev,
+			"%s - usb_alloc_urb failed: usbtouch->irq\n", __func__);
 		goto out_free_buffers;
 	}
 
@@ -1594,7 +1604,9 @@
 	if (type->alloc) {
 		err = type->alloc(usbtouch);
 		if (err) {
-			dbg("%s - type->alloc() failed, err: %d", __func__, err);
+			dev_dbg(&intf->dev,
+				"%s - type->alloc() failed, err: %d\n",
+				__func__, err);
 			goto out_free_urb;
 		}
 	}
@@ -1603,14 +1615,18 @@
 	if (type->init) {
 		err = type->init(usbtouch);
 		if (err) {
-			dbg("%s - type->init() failed, err: %d", __func__, err);
+			dev_dbg(&intf->dev,
+				"%s - type->init() failed, err: %d\n",
+				__func__, err);
 			goto out_do_exit;
 		}
 	}
 
 	err = input_register_device(usbtouch->input);
 	if (err) {
-		dbg("%s - input_register_device failed, err: %d", __func__, err);
+		dev_dbg(&intf->dev,
+			"%s - input_register_device failed, err: %d\n",
+			__func__, err);
 		goto out_do_exit;
 	}
 
@@ -1622,8 +1638,9 @@
 		err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
 		if (err) {
 			usb_autopm_put_interface(intf);
-			err("%s - usb_submit_urb failed with result: %d",
-			    __func__, err);
+			dev_err(&intf->dev,
+				"%s - usb_submit_urb failed with result: %d\n",
+				__func__, err);
 			goto out_unregister_input;
 		}
 	}
@@ -1650,12 +1667,12 @@
 {
 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
 
-	dbg("%s - called", __func__);
-
 	if (!usbtouch)
 		return;
 
-	dbg("%s - usbtouch is initialized, cleaning up", __func__);
+	dev_dbg(&intf->dev,
+		"%s - usbtouch is initialized, cleaning up\n", __func__);
+
 	usb_set_intfdata(intf, NULL);
 	/* this will stop IO via close */
 	input_unregister_device(usbtouch->input);
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
new file mode 100644
index 0000000..3557257
--- /dev/null
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -0,0 +1,282 @@
+/*
+ * Wacom Penabled Driver for I2C
+ *
+ * Copyright (c) 2011 Tatsunosuke Tobita, Wacom.
+ * <tobita.tatsunosuke@wacom.co.jp>
+ *
+ * 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 of 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <asm/unaligned.h>
+
+#define WACOM_CMD_QUERY0	0x04
+#define WACOM_CMD_QUERY1	0x00
+#define WACOM_CMD_QUERY2	0x33
+#define WACOM_CMD_QUERY3	0x02
+#define WACOM_CMD_THROW0	0x05
+#define WACOM_CMD_THROW1	0x00
+#define WACOM_QUERY_SIZE	19
+#define WACOM_RETRY_CNT		100
+
+struct wacom_features {
+	int x_max;
+	int y_max;
+	int pressure_max;
+	char fw_version;
+};
+
+struct wacom_i2c {
+	struct i2c_client *client;
+	struct input_dev *input;
+	u8 data[WACOM_QUERY_SIZE];
+};
+
+static int wacom_query_device(struct i2c_client *client,
+			      struct wacom_features *features)
+{
+	int ret;
+	u8 cmd1[] = { WACOM_CMD_QUERY0, WACOM_CMD_QUERY1,
+			WACOM_CMD_QUERY2, WACOM_CMD_QUERY3 };
+	u8 cmd2[] = { WACOM_CMD_THROW0, WACOM_CMD_THROW1 };
+	u8 data[WACOM_QUERY_SIZE];
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = sizeof(cmd1),
+			.buf = cmd1,
+		},
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = sizeof(cmd2),
+			.buf = cmd2,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = sizeof(data),
+			.buf = data,
+		},
+	};
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	features->x_max = get_unaligned_le16(&data[3]);
+	features->y_max = get_unaligned_le16(&data[5]);
+	features->pressure_max = get_unaligned_le16(&data[11]);
+	features->fw_version = get_unaligned_le16(&data[13]);
+
+	dev_dbg(&client->dev,
+		"x_max:%d, y_max:%d, pressure:%d, fw:%d\n",
+		features->x_max, features->y_max,
+		features->pressure_max, features->fw_version);
+
+	return 0;
+}
+
+static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
+{
+	struct wacom_i2c *wac_i2c = dev_id;
+	struct input_dev *input = wac_i2c->input;
+	u8 *data = wac_i2c->data;
+	unsigned int x, y, pressure;
+	unsigned char tsw, f1, f2, ers;
+	int error;
+
+	error = i2c_master_recv(wac_i2c->client,
+				wac_i2c->data, sizeof(wac_i2c->data));
+	if (error < 0)
+		goto out;
+
+	tsw = data[3] & 0x01;
+	ers = data[3] & 0x04;
+	f1 = data[3] & 0x02;
+	f2 = data[3] & 0x10;
+	x = le16_to_cpup((__le16 *)&data[4]);
+	y = le16_to_cpup((__le16 *)&data[6]);
+	pressure = le16_to_cpup((__le16 *)&data[8]);
+
+	input_report_key(input, BTN_TOUCH, tsw || ers);
+	input_report_key(input, BTN_TOOL_PEN, tsw);
+	input_report_key(input, BTN_TOOL_RUBBER, ers);
+	input_report_key(input, BTN_STYLUS, f1);
+	input_report_key(input, BTN_STYLUS2, f2);
+	input_report_abs(input, ABS_X, x);
+	input_report_abs(input, ABS_Y, y);
+	input_report_abs(input, ABS_PRESSURE, pressure);
+	input_sync(input);
+
+out:
+	return IRQ_HANDLED;
+}
+
+static int wacom_i2c_open(struct input_dev *dev)
+{
+	struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
+	struct i2c_client *client = wac_i2c->client;
+
+	enable_irq(client->irq);
+
+	return 0;
+}
+
+static void wacom_i2c_close(struct input_dev *dev)
+{
+	struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
+	struct i2c_client *client = wac_i2c->client;
+
+	disable_irq(client->irq);
+}
+
+static int __devinit wacom_i2c_probe(struct i2c_client *client,
+				     const struct i2c_device_id *id)
+{
+	struct wacom_i2c *wac_i2c;
+	struct input_dev *input;
+	struct wacom_features features;
+	int error;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "i2c_check_functionality error\n");
+		return -EIO;
+	}
+
+	error = wacom_query_device(client, &features);
+	if (error)
+		return error;
+
+	wac_i2c = kzalloc(sizeof(*wac_i2c), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!wac_i2c || !input) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	wac_i2c->client = client;
+	wac_i2c->input = input;
+
+	input->name = "Wacom I2C Digitizer";
+	input->id.bustype = BUS_I2C;
+	input->id.vendor = 0x56a;
+	input->id.version = features.fw_version;
+	input->dev.parent = &client->dev;
+	input->open = wacom_i2c_open;
+	input->close = wacom_i2c_close;
+
+	input->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+
+	__set_bit(BTN_TOOL_PEN, input->keybit);
+	__set_bit(BTN_TOOL_RUBBER, input->keybit);
+	__set_bit(BTN_STYLUS, input->keybit);
+	__set_bit(BTN_STYLUS2, input->keybit);
+	__set_bit(BTN_TOUCH, input->keybit);
+
+	input_set_abs_params(input, ABS_X, 0, features.x_max, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, features.y_max, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE,
+			     0, features.pressure_max, 0, 0);
+
+	input_set_drvdata(input, wac_i2c);
+
+	error = request_threaded_irq(client->irq, NULL, wacom_i2c_irq,
+				     IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				     "wacom_i2c", wac_i2c);
+	if (error) {
+		dev_err(&client->dev,
+			"Failed to enable IRQ, error: %d\n", error);
+		goto err_free_mem;
+	}
+
+	/* Disable the IRQ, we'll enable it in wac_i2c_open() */
+	disable_irq(client->irq);
+
+	error = input_register_device(wac_i2c->input);
+	if (error) {
+		dev_err(&client->dev,
+			"Failed to register input device, error: %d\n", error);
+		goto err_free_irq;
+	}
+
+	i2c_set_clientdata(client, wac_i2c);
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, wac_i2c);
+err_free_mem:
+	input_free_device(input);
+	kfree(wac_i2c);
+
+	return error;
+}
+
+static int __devexit wacom_i2c_remove(struct i2c_client *client)
+{
+	struct wacom_i2c *wac_i2c = i2c_get_clientdata(client);
+
+	free_irq(client->irq, wac_i2c);
+	input_unregister_device(wac_i2c->input);
+	kfree(wac_i2c);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int wacom_i2c_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	disable_irq(client->irq);
+
+	return 0;
+}
+
+static int wacom_i2c_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	enable_irq(client->irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
+
+static const struct i2c_device_id wacom_i2c_id[] = {
+	{ "WAC_I2C_EMR", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);
+
+static struct i2c_driver wacom_i2c_driver = {
+	.driver	= {
+		.name	= "wacom_i2c",
+		.owner	= THIS_MODULE,
+		.pm	= &wacom_i2c_pm,
+	},
+
+	.probe		= wacom_i2c_probe,
+	.remove		= __devexit_p(wacom_i2c_remove),
+	.id_table	= wacom_i2c_id,
+};
+module_i2c_driver(wacom_i2c_driver);
+
+MODULE_AUTHOR("Tatsunosuke Tobita <tobita.tatsunosuke@wacom.co.jp>");
+MODULE_DESCRIPTION("WACOM EMR I2C Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 1569a39..8f9ad2f 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -594,15 +594,4 @@
 	.disconnect	= w8001_disconnect,
 };
 
-static int __init w8001_init(void)
-{
-	return serio_register_driver(&w8001_drv);
-}
-
-static void __exit w8001_exit(void)
-{
-	serio_unregister_driver(&w8001_drv);
-}
-
-module_init(w8001_init);
-module_exit(w8001_exit);
+module_serio_driver(w8001_drv);
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 3bd9fff..c698437 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -43,7 +43,7 @@
 	  With this option you can enable support for AMD IOMMU hardware in
 	  your system. An IOMMU is a hardware component which provides
 	  remapping of DMA memory accesses from devices. With an AMD IOMMU you
-	  can isolate the the DMA memory of different devices and protect the
+	  can isolate the DMA memory of different devices and protect the
 	  system from misbehaving device drivers or hardware.
 
 	  You can find out if your system has an AMD IOMMU if you look into
@@ -67,7 +67,7 @@
 	---help---
 	  This option enables support for the AMD IOMMUv2 features of the IOMMU
 	  hardware. Select this option if you want to use devices that support
-	  the the PCI PRI and PASID interface.
+	  the PCI PRI and PASID interface.
 
 # Intel IOMMU support
 config DMAR_TABLE
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 3b9278b..5275887 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -148,6 +148,7 @@
 	.reset_resume =	gigaset_post_reset,
 	.pre_reset =	gigaset_pre_reset,
 	.post_reset =	gigaset_post_reset,
+	.disable_hub_initiated_lpm = 1,
 };
 
 /* get message text for usb_submit_urb return code
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index bb12d80..d0a41cb 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -124,6 +124,7 @@
 	.reset_resume =	gigaset_resume,
 	.pre_reset =	gigaset_pre_reset,
 	.post_reset =	gigaset_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 struct usb_cardstate {
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 83206e4..c65c344 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -2126,6 +2126,7 @@
 	.id_table = hfcsusb_idtab,
 	.probe = hfcsusb_probe,
 	.disconnect = hfcsusb_disconnect,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(hfcsusb_drv);
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 62c65bd..84f9c810 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1568,6 +1568,7 @@
 	.id_table = hfcusb_idtab,
 	.probe = hfc_usb_probe,
 	.disconnect = hfc_usb_disconnect,
+	.disable_hub_initiated_lpm = 1,
 };
 
 static void __exit
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
index 100296e..54ef9e4 100644
--- a/drivers/isdn/hisax/st5481_init.c
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -182,6 +182,7 @@
 	.probe =	probe_st5481,
 	.disconnect =	disconnect_st5481,
 	.id_table =	st5481_ids,
+	.disable_hub_initiated_lpm = 1,
 };
 
 static int __init st5481_usb_init(void)
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index d9f5524..8c610fa 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -46,7 +46,6 @@
 static char *isdn_revision = "$Revision: 1.1.2.3 $";
 
 extern char *isdn_net_revision;
-extern char *isdn_tty_revision;
 #ifdef CONFIG_ISDN_PPP
 extern char *isdn_ppp_revision;
 #else
@@ -2327,8 +2326,6 @@
 		dev->chanmap[i] = -1;
 		dev->m_idx[i] = -1;
 		strcpy(dev->num[i], "???");
-		init_waitqueue_head(&dev->mdm.info[i].open_wait);
-		init_waitqueue_head(&dev->mdm.info[i].close_wait);
 	}
 	if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
 		printk(KERN_WARNING "isdn: Could not register control devices\n");
@@ -2353,8 +2350,6 @@
 
 	strcpy(tmprev, isdn_revision);
 	printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
-	strcpy(tmprev, isdn_tty_revision);
-	printk("%s/", isdn_getrev(tmprev));
 	strcpy(tmprev, isdn_net_revision);
 	printk("%s/", isdn_getrev(tmprev));
 	strcpy(tmprev, isdn_ppp_revision);
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 3831abd..7bc5067 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1,5 +1,4 @@
-/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
+/*
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
  * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
@@ -12,6 +11,7 @@
 #undef ISDN_TTY_STAT_DEBUG
 
 #include <linux/isdn.h>
+#include <linux/serial.h> /* ASYNC_* flags */
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
@@ -48,9 +48,6 @@
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.1.2.3 $";
-
-
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
  * to stuff incoming data directly into a tty's flip-buffer. This
  * is done to speed up tty-receiving if the receive-queue is empty.
@@ -68,49 +65,54 @@
 	struct tty_struct *tty;
 	char last;
 
-	if (info->online) {
-		if ((tty = info->tty)) {
-			if (info->mcr & UART_MCR_RTS) {
-				len = skb->len
-#ifdef CONFIG_ISDN_AUDIO
-					+ ISDN_AUDIO_SKB_DLECOUNT(skb)
-#endif
-					;
+	if (!info->online)
+		return 0;
 
-				c = tty_buffer_request_room(tty, len);
-				if (c >= len) {
+	tty = info->port.tty;
+	if (!tty)
+		return 0;
+
+	if (!(info->mcr & UART_MCR_RTS))
+		return 0;
+
+	len = skb->len
 #ifdef CONFIG_ISDN_AUDIO
-					if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
-						int l = skb->len;
-						unsigned char *dp = skb->data;
-						while (--l) {
-							if (*dp == DLE)
-								tty_insert_flip_char(tty, DLE, 0);
-							tty_insert_flip_char(tty, *dp++, 0);
-						}
-						if (*dp == DLE)
-							tty_insert_flip_char(tty, DLE, 0);
-						last = *dp;
-					} else {
+		+ ISDN_AUDIO_SKB_DLECOUNT(skb)
 #endif
-						if (len > 1)
-							tty_insert_flip_string(tty, skb->data, len - 1);
-						last = skb->data[len - 1];
+		;
+
+	c = tty_buffer_request_room(tty, len);
+	if (c < len)
+		return 0;
+
 #ifdef CONFIG_ISDN_AUDIO
-					}
-#endif
-					if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
-						tty_insert_flip_char(tty, last, 0xFF);
-					else
-						tty_insert_flip_char(tty, last, TTY_NORMAL);
-					tty_flip_buffer_push(tty);
-					kfree_skb(skb);
-					return 1;
-				}
-			}
+	if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
+		int l = skb->len;
+		unsigned char *dp = skb->data;
+		while (--l) {
+			if (*dp == DLE)
+				tty_insert_flip_char(tty, DLE, 0);
+			tty_insert_flip_char(tty, *dp++, 0);
 		}
+		if (*dp == DLE)
+			tty_insert_flip_char(tty, DLE, 0);
+		last = *dp;
+	} else {
+#endif
+		if (len > 1)
+			tty_insert_flip_string(tty, skb->data, len - 1);
+		last = skb->data[len - 1];
+#ifdef CONFIG_ISDN_AUDIO
 	}
-	return 0;
+#endif
+	if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
+		tty_insert_flip_char(tty, last, 0xFF);
+	else
+		tty_insert_flip_char(tty, last, TTY_NORMAL);
+	tty_flip_buffer_push(tty);
+	kfree_skb(skb);
+
+	return 1;
 }
 
 /* isdn_tty_readmodem() is called periodically from within timer-interrupt.
@@ -128,35 +130,39 @@
 	modem_info *info;
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		if ((midx = dev->m_idx[i]) >= 0) {
-			info = &dev->mdm.info[midx];
-			if (info->online) {
-				r = 0;
+		midx = dev->m_idx[i];
+		if (midx < 0)
+			continue;
+
+		info = &dev->mdm.info[midx];
+		if (!info->online)
+			continue;
+
+		r = 0;
 #ifdef CONFIG_ISDN_AUDIO
-				isdn_audio_eval_dtmf(info);
-				if ((info->vonline & 1) && (info->emu.vpar[1]))
-					isdn_audio_eval_silence(info);
+		isdn_audio_eval_dtmf(info);
+		if ((info->vonline & 1) && (info->emu.vpar[1]))
+			isdn_audio_eval_silence(info);
 #endif
-				if ((tty = info->tty)) {
-					if (info->mcr & UART_MCR_RTS) {
-						/* CISCO AsyncPPP Hack */
-						if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
-							r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
-						else
-							r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
-						if (r)
-							tty_flip_buffer_push(tty);
-					} else
-						r = 1;
-				} else
-					r = 1;
-				if (r) {
-					info->rcvsched = 0;
-					resched = 1;
-				} else
-					info->rcvsched = 1;
-			}
-		}
+		tty = info->port.tty;
+		if (tty) {
+			if (info->mcr & UART_MCR_RTS) {
+				/* CISCO AsyncPPP Hack */
+				if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
+					r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
+				else
+					r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
+				if (r)
+					tty_flip_buffer_push(tty);
+			} else
+				r = 1;
+		} else
+			r = 1;
+		if (r) {
+			info->rcvsched = 0;
+			resched = 1;
+		} else
+			info->rcvsched = 1;
 	}
 	if (!resched)
 		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
@@ -294,7 +300,7 @@
 	len = skb->len;
 	if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
 					   info->isdn_channel, 1, skb)) == len) {
-		struct tty_struct *tty = info->tty;
+		struct tty_struct *tty = info->port.tty;
 		info->send_outstanding++;
 		info->msr &= ~UART_MSR_CTS;
 		info->lsr &= ~UART_LSR_TEMT;
@@ -327,7 +333,7 @@
 static int
 isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
 {
-	unsigned char *p = &info->xmit_buf[info->xmit_count];
+	unsigned char *p = &info->port.xmit_buf[info->xmit_count];
 	int count = 0;
 
 	while (len > 0) {
@@ -471,7 +477,7 @@
 		return;
 	}
 	skb_reserve(skb, skb_res);
-	memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
+	memcpy(skb_put(skb, buflen), info->port.xmit_buf, buflen);
 	info->xmit_count = 0;
 #ifdef CONFIG_ISDN_AUDIO
 	if (info->vonline & 2) {
@@ -699,7 +705,7 @@
 	printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
 #endif
 	info->rcvsched = 0;
-	isdn_tty_flush_buffer(info->tty);
+	isdn_tty_flush_buffer(info->port.tty);
 	if (info->online) {
 		info->last_lhup = local;
 		info->online = 0;
@@ -997,20 +1003,21 @@
 static void
 isdn_tty_change_speed(modem_info *info)
 {
+	struct tty_port *port = &info->port;
 	uint cflag,
 		cval,
 		quot;
 	int i;
 
-	if (!info->tty || !info->tty->termios)
+	if (!port->tty || !port->tty->termios)
 		return;
-	cflag = info->tty->termios->c_cflag;
+	cflag = port->tty->termios->c_cflag;
 
 	quot = i = cflag & CBAUD;
 	if (i & CBAUDEX) {
 		i &= ~CBAUDEX;
 		if (i < 1 || i > 2)
-			info->tty->termios->c_cflag &= ~CBAUDEX;
+			port->tty->termios->c_cflag &= ~CBAUDEX;
 		else
 			i += 15;
 	}
@@ -1040,20 +1047,20 @@
 
 	/* CTS flow control flag and modem status interrupts */
 	if (cflag & CRTSCTS) {
-		info->flags |= ISDN_ASYNC_CTS_FLOW;
+		port->flags |= ASYNC_CTS_FLOW;
 	} else
-		info->flags &= ~ISDN_ASYNC_CTS_FLOW;
+		port->flags &= ~ASYNC_CTS_FLOW;
 	if (cflag & CLOCAL)
-		info->flags &= ~ISDN_ASYNC_CHECK_CD;
+		port->flags &= ~ASYNC_CHECK_CD;
 	else {
-		info->flags |= ISDN_ASYNC_CHECK_CD;
+		port->flags |= ASYNC_CHECK_CD;
 	}
 }
 
 static int
 isdn_tty_startup(modem_info *info)
 {
-	if (info->flags & ISDN_ASYNC_INITIALIZED)
+	if (info->port.flags & ASYNC_INITIALIZED)
 		return 0;
 	isdn_lock_drivers();
 #ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1063,14 +1070,14 @@
 	 * Now, initialize the UART
 	 */
 	info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	/*
 	 * and set the speed of the serial port
 	 */
 	isdn_tty_change_speed(info);
 
-	info->flags |= ISDN_ASYNC_INITIALIZED;
+	info->port.flags |= ASYNC_INITIALIZED;
 	info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
 	info->send_outstanding = 0;
 	return 0;
@@ -1083,14 +1090,14 @@
 static void
 isdn_tty_shutdown(modem_info *info)
 {
-	if (!(info->flags & ISDN_ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		return;
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
 #endif
 	isdn_unlock_drivers();
 	info->msr &= ~UART_MSR_RI;
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
 		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
 		if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
 			isdn_tty_modem_reset_regs(info, 0);
@@ -1100,10 +1107,10 @@
 			isdn_tty_modem_hup(info, 1);
 		}
 	}
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-	info->flags &= ~ISDN_ASYNC_INITIALIZED;
+	info->port.flags &= ~ASYNC_INITIALIZED;
 }
 
 /* isdn_tty_write() is the main send-routine. It is called from the upper
@@ -1146,7 +1153,7 @@
 				isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
 						   &(m->pluscount),
 						   &(m->lastplus));
-			memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
+			memcpy(&info->port.xmit_buf[info->xmit_count], buf, c);
 #ifdef CONFIG_ISDN_AUDIO
 			if (info->vonline) {
 				int cc = isdn_tty_handleDLEdown(info, m, c);
@@ -1478,107 +1485,6 @@
  * isdn_tty_open() and friends
  * ------------------------------------------------------------
  */
-static int
-isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *info)
-{
-	DECLARE_WAITQUEUE(wait, NULL);
-	int do_clocal = 0;
-	int retval;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ISDN_ASYNC_CLOSING)) {
-		if (info->flags & ISDN_ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef MODEM_DO_RESTART
-		if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-	/*
-	 * If non-blocking mode is set, then make the check up front
-	 * and then exit.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
-		info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
-	 * isdn_tty_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-#ifdef ISDN_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	if (!(tty_hung_up_p(filp)))
-		info->count--;
-	info->blocked_open++;
-	while (1) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ISDN_ASYNC_INITIALIZED)) {
-#ifdef MODEM_DO_RESTART
-			if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ISDN_ASYNC_CLOSING) &&
-		    (do_clocal || (info->msr & UART_MSR_DCD))) {
-			break;
-		}
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-#ifdef ISDN_DEBUG_MODEM_OPEN
-		printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n",
-		       info->line, info->count);
-#endif
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-#ifdef ISDN_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	if (retval)
-		return retval;
-	info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
-	return 0;
-}
 
 /*
  * This routine is called whenever a serial port is opened.  It
@@ -1589,23 +1495,22 @@
 static int
 isdn_tty_open(struct tty_struct *tty, struct file *filp)
 {
+	struct tty_port *port;
 	modem_info *info;
 	int retval;
 
 	info = &dev->mdm.info[tty->index];
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
 		return -ENODEV;
-	if (!try_module_get(info->owner)) {
-		printk(KERN_WARNING "%s: cannot reserve module\n", __func__);
-		return -ENODEV;
-	}
+	port = &info->port;
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
-	       info->count);
+	       port->count);
 #endif
-	info->count++;
+	port->count++;
 	tty->driver_data = info;
-	info->tty = tty;
+	port->tty = tty;
+	tty->port = port;
 	/*
 	 * Start up serial port
 	 */
@@ -1614,15 +1519,13 @@
 #ifdef ISDN_DEBUG_MODEM_OPEN
 		printk(KERN_DEBUG "isdn_tty_open return after startup\n");
 #endif
-		module_put(info->owner);
 		return retval;
 	}
-	retval = isdn_tty_block_til_ready(tty, filp, info);
+	retval = tty_port_block_til_ready(port, tty, filp);
 	if (retval) {
 #ifdef ISDN_DEBUG_MODEM_OPEN
 		printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
 #endif
-		module_put(info->owner);
 		return retval;
 	}
 #ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1639,6 +1542,7 @@
 isdn_tty_close(struct tty_struct *tty, struct file *filp)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
+	struct tty_port *port = &info->port;
 	ulong timeout;
 
 	if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
@@ -1649,7 +1553,7 @@
 #endif
 		return;
 	}
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (port->count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * structure will be freed.  Info->count should always
@@ -1658,30 +1562,21 @@
 		 * serial port won't be shutdown.
 		 */
 		printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
-		       "info->count is %d\n", info->count);
-		info->count = 1;
+		       "info->count is %d\n", port->count);
+		port->count = 1;
 	}
-	if (--info->count < 0) {
+	if (--port->count < 0) {
 		printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
-		       info->line, info->count);
-		info->count = 0;
+		       info->line, port->count);
+		port->count = 0;
 	}
-	if (info->count) {
+	if (port->count) {
 #ifdef ISDN_DEBUG_MODEM_OPEN
 		printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
 #endif
-		module_put(info->owner);
 		return;
 	}
-	info->flags |= ISDN_ASYNC_CLOSING;
-	/*
-	 * Save the termios structure, since this port may have
-	 * separate termios for callout and dialin.
-	 */
-	if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
-		info->normal_termios = *tty->termios;
-	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
+	port->flags |= ASYNC_CLOSING;
 
 	tty->closing = 1;
 	/*
@@ -1690,7 +1585,7 @@
 	 * interrupt driver to stop checking the data ready bit in the
 	 * line status register.
 	 */
-	if (info->flags & ISDN_ASYNC_INITIALIZED) {
+	if (port->flags & ASYNC_INITIALIZED) {
 		tty_wait_until_sent_from_close(tty, 3000);	/* 30 seconds timeout */
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
@@ -1708,16 +1603,10 @@
 	isdn_tty_shutdown(info);
 	isdn_tty_flush_buffer(tty);
 	tty_ldisc_flush(tty);
-	info->tty = NULL;
+	port->tty = NULL;
 	info->ncarrier = 0;
-	tty->closing = 0;
-	module_put(info->owner);
-	if (info->blocked_open) {
-		msleep_interruptible(500);
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
+
+	tty_port_close_end(port, tty);
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "isdn_tty_close normal exit\n");
 #endif
@@ -1730,14 +1619,15 @@
 isdn_tty_hangup(struct tty_struct *tty)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
+	struct tty_port *port = &info->port;
 
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
 		return;
 	isdn_tty_shutdown(info);
-	info->count = 0;
-	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
+	port->count = 0;
+	port->flags &= ~ASYNC_NORMAL_ACTIVE;
+	port->tty = NULL;
+	wake_up_interruptible(&port->open_wait);
 }
 
 /* This routine initializes all emulator-data.
@@ -1864,6 +1754,16 @@
 	.tiocmset = isdn_tty_tiocmset,
 };
 
+static int isdn_tty_carrier_raised(struct tty_port *port)
+{
+	modem_info *info = container_of(port, modem_info, port);
+	return info->msr & UART_MSR_DCD;
+}
+
+static const struct tty_port_operations isdn_tty_port_ops = {
+	.carrier_raised = isdn_tty_carrier_raised,
+};
+
 int
 isdn_tty_modem_init(void)
 {
@@ -1899,9 +1799,8 @@
 			goto err_unregister;
 		}
 #endif
-#ifdef MODULE
-		info->owner = THIS_MODULE;
-#endif
+		tty_port_init(&info->port);
+		info->port.ops = &isdn_tty_port_ops;
 		spin_lock_init(&info->readlock);
 		sprintf(info->last_cause, "0000");
 		sprintf(info->last_num, "none");
@@ -1913,12 +1812,7 @@
 		isdn_tty_modem_reset_regs(info, 1);
 		info->magic = ISDN_ASYNC_MAGIC;
 		info->line = i;
-		info->tty = NULL;
 		info->x_char = 0;
-		info->count = 0;
-		info->blocked_open = 0;
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
 		info->isdn_driver = -1;
 		info->isdn_channel = -1;
 		info->drv_index = -1;
@@ -1930,13 +1824,15 @@
 #ifdef CONFIG_ISDN_AUDIO
 		skb_queue_head_init(&info->dtmf_queue);
 #endif
-		if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
+		info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5,
+				GFP_KERNEL);
+		if (!info->port.xmit_buf) {
 			printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
 			retval = -ENOMEM;
 			goto err_unregister;
 		}
 		/* Make room for T.70 header */
-		info->xmit_buf += 4;
+		info->port.xmit_buf += 4;
 	}
 	return 0;
 err_unregister:
@@ -1945,7 +1841,7 @@
 #ifdef CONFIG_ISDN_TTY_FAX
 		kfree(info->fax);
 #endif
-		kfree(info->xmit_buf - 4);
+		kfree(info->port.xmit_buf - 4);
 	}
 	tty_unregister_driver(m->tty_modem);
 err:
@@ -1966,7 +1862,7 @@
 #ifdef CONFIG_ISDN_TTY_FAX
 		kfree(info->fax);
 #endif
-		kfree(info->xmit_buf - 4);
+		kfree(info->port.xmit_buf - 4);
 	}
 	tty_unregister_driver(dev->mdm.tty_modem);
 	put_tty_driver(dev->mdm.tty_modem);
@@ -2068,7 +1964,7 @@
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		modem_info *info = &dev->mdm.info[i];
 
-		if (info->count == 0)
+		if (info->port.count == 0)
 			continue;
 		if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) &&  /* SI1 is matching */
 		    (info->emu.mdmreg[REG_SI2] == si2))	{         /* SI2 is matching */
@@ -2076,12 +1972,12 @@
 #ifdef ISDN_DEBUG_MODEM_ICALL
 			printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
 			printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
-			       info->flags, info->isdn_driver, info->isdn_channel,
-			       dev->usage[idx]);
+			       info->port.flags, info->isdn_driver,
+			       info->isdn_channel, dev->usage[idx]);
 #endif
 			if (
 #ifndef FIX_FILE_TRANSFER
-				(info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
+				(info->port.flags & ASYNC_NORMAL_ACTIVE) &&
 #endif
 				(info->isdn_driver == -1) &&
 				(info->isdn_channel == -1) &&
@@ -2120,8 +2016,7 @@
 	return (wret == 2) ? 3 : 0;
 }
 
-#define TTY_IS_ACTIVE(info)						\
-	(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
+#define TTY_IS_ACTIVE(info)	(info->port.flags & ASYNC_NORMAL_ACTIVE)
 
 int
 isdn_tty_stat_callback(int i, isdn_ctrl *c)
@@ -2212,9 +2107,9 @@
 			 * for incoming call of this device when
 			 * DCD follow the state of incoming carrier
 			 */
-			if (info->blocked_open &&
+			if (info->port.blocked_open &&
 			    (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
-				wake_up_interruptible(&info->open_wait);
+				wake_up_interruptible(&info->port.open_wait);
 			}
 
 			/* Schedule CONNECT-Message to any tty
@@ -2222,7 +2117,8 @@
 			 * set DCD-bit of its modem-status.
 			 */
 			if (TTY_IS_ACTIVE(info) ||
-			    (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
+			    (info->port.blocked_open &&
+			     (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
 				info->msr |= UART_MSR_DCD;
 				info->emu.charge = 0;
 				if (info->dialing & 0xf)
@@ -2339,8 +2235,8 @@
 	l = strlen(msg);
 
 	spin_lock_irqsave(&info->readlock, flags);
-	tty = info->tty;
-	if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
+	tty = info->port.tty;
+	if ((info->port.flags & ASYNC_CLOSING) || (!tty)) {
 		spin_unlock_irqrestore(&info->readlock, flags);
 		return;
 	}
@@ -2490,15 +2386,15 @@
 	case RESULT_NO_CARRIER:
 #ifdef ISDN_DEBUG_MODEM_HUP
 		printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
-		       (info->flags & ISDN_ASYNC_CLOSING),
-		       (!info->tty));
+		       (info->port.flags & ASYNC_CLOSING),
+		       (!info->port.tty));
 #endif
 		m->mdmreg[REG_RINGCNT] = 0;
 		del_timer(&info->nc_timer);
 		info->ncarrier = 0;
-		if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+		if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
 			return;
-		}
+
 #ifdef CONFIG_ISDN_AUDIO
 		if (info->vonline & 1) {
 #ifdef ISDN_DEBUG_MODEM_VOICE
@@ -2629,14 +2525,11 @@
 		}
 	}
 	if (code == RESULT_NO_CARRIER) {
-		if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+		if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
 			return;
-		}
-		if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
-		    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
-		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
-			tty_hangup(info->tty);
-		}
+
+		if (info->port.flags & ASYNC_CHECK_CD)
+			tty_hangup(info->port.tty);
 	}
 }
 
@@ -3803,19 +3696,19 @@
 	int midx;
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-		if (USG_MODEM(dev->usage[i]))
-			if ((midx = dev->m_idx[i]) >= 0) {
-				modem_info *info = &dev->mdm.info[midx];
-				if (info->online) {
-					ton = 1;
-					if ((info->emu.pluscount == 3) &&
-					    time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) {
-						info->emu.pluscount = 0;
-						info->online = 0;
-						isdn_tty_modem_result(RESULT_OK, info);
-					}
+		if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) {
+			modem_info *info = &dev->mdm.info[midx];
+			if (info->online) {
+				ton = 1;
+				if ((info->emu.pluscount == 3) &&
+				    time_after(jiffies,
+					    info->emu.lastplus + PLUSWAIT2)) {
+					info->emu.pluscount = 0;
+					info->online = 0;
+					isdn_tty_modem_result(RESULT_OK, info);
 				}
 			}
+		}
 	isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
 }
 
@@ -3873,15 +3766,14 @@
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		modem_info *info = &dev->mdm.info[i];
-		if (info->dialing) {
-			if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
-				info->dialing = 0;
-				isdn_tty_modem_result(RESULT_NO_CARRIER, info);
-				isdn_tty_modem_hup(info, 1);
-			}
-			else
-				ton = 1;
-		}
+		if (!info->dialing)
+			continue;
+		if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
+			info->dialing = 0;
+			isdn_tty_modem_result(RESULT_NO_CARRIER, info);
+			isdn_tty_modem_hup(info, 1);
+		} else
+			ton = 1;
 	}
 	isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
 }
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index fa51af1..a555da6 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -204,11 +204,14 @@
 	  better fan behaviour by default, and some manual control.
 
 config THERM_PM72
-	tristate "Support for thermal management on PowerMac G5"
+	tristate "Support for thermal management on PowerMac G5 (AGP)"
 	depends on I2C && I2C_POWERMAC && PPC_PMAC64
+	default n
 	help
 	  This driver provides thermostat and fan control for the desktop
-	  G5 machines. 
+	  G5 machines.
+
+	  This is deprecated, use windfarm instead.
 
 config WINDFARM
 	tristate "New PowerMac thermal control infrastructure"
@@ -221,6 +224,22 @@
 	help
 	  This driver provides thermal control for the iMacG5
 
+config WINDFARM_PM72
+	tristate "Support for thermal management on PowerMac G5 (AGP)"
+	depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+	select I2C_POWERMAC
+	help
+	  This driver provides thermal control for the PowerMac G5
+	  "AGP" variants (PowerMac 7,2 and 7,3)
+
+config WINDFARM_RM31
+	tristate "Support for thermal management on Xserve G5"
+	depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+	select I2C_POWERMAC
+	help
+	  This driver provides thermal control for the Xserve G5
+	  (RackMac3,1)
+
 config WINDFARM_PM91
 	tristate "Support for thermal management on PowerMac9,1"
 	depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 6652a6e..6753b65 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -29,6 +29,20 @@
 obj-$(CONFIG_THERM_WINDTUNNEL)	+= therm_windtunnel.o
 obj-$(CONFIG_THERM_ADT746X)	+= therm_adt746x.o
 obj-$(CONFIG_WINDFARM)	        += windfarm_core.o
+obj-$(CONFIG_WINDFARM_PM72)     += windfarm_fcu_controls.o \
+				   windfarm_ad7417_sensor.o \
+				   windfarm_lm75_sensor.o \
+				   windfarm_max6690_sensor.o \
+				   windfarm_pid.o \
+				   windfarm_cpufreq_clamp.o \
+				   windfarm_pm72.o
+obj-$(CONFIG_WINDFARM_RM31)     += windfarm_fcu_controls.o \
+				   windfarm_ad7417_sensor.o \
+				   windfarm_lm75_sensor.o \
+				   windfarm_lm87_sensor.o \
+				   windfarm_pid.o \
+				   windfarm_cpufreq_clamp.o \
+				   windfarm_rm31.o
 obj-$(CONFIG_WINDFARM_PM81)     += windfarm_smu_controls.o \
 				   windfarm_smu_sensors.o \
 				   windfarm_lm75_sensor.o windfarm_pid.o \
diff --git a/drivers/macintosh/ams/ams-i2c.c b/drivers/macintosh/ams/ams-i2c.c
index abeecd2..978eda8 100644
--- a/drivers/macintosh/ams/ams-i2c.c
+++ b/drivers/macintosh/ams/ams-i2c.c
@@ -65,7 +65,7 @@
 static int ams_i2c_remove(struct i2c_client *client);
 
 static const struct i2c_device_id ams_id[] = {
-	{ "ams", 0 },
+	{ "MAC,accelerometer_1", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ams_id);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index fc71723c..f433521 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -47,7 +47,7 @@
 
 static u8 default_limits_local[3] = {70, 50, 70};    /* local, sensor1, sensor2 */
 static u8 default_limits_chip[3] = {80, 65, 80};    /* local, sensor1, sensor2 */
-static const char *sensor_location[3];
+static const char *sensor_location[3] = { "?", "?", "?" };
 
 static int limit_adjust;
 static int fan_speed = -1;
@@ -79,18 +79,16 @@
 	int			last_speed[2];
 	int			last_var[2];
 	int			pwm_inv[2];
+	struct task_struct	*thread;
+	struct platform_device	*pdev;
+	enum {
+		ADT7460,
+		ADT7467
+	}			type;
 };
 
-static enum {ADT7460, ADT7467} therm_type;
-static int therm_bus, therm_address;
-static struct platform_device * of_dev;
-static struct thermostat* thermostat;
-static struct task_struct *thread_therm = NULL;
-
 static void write_both_fan_speed(struct thermostat *th, int speed);
 static void write_fan_speed(struct thermostat *th, int speed, int fan);
-static void thermostat_create_files(void);
-static void thermostat_remove_files(void);
 
 static int
 write_reg(struct thermostat* th, int reg, u8 data)
@@ -126,66 +124,6 @@
 	return data;
 }
 
-static struct i2c_driver thermostat_driver;
-
-static int
-attach_thermostat(struct i2c_adapter *adapter)
-{
-	unsigned long bus_no;
-	struct i2c_board_info info;
-	struct i2c_client *client;
-
-	if (strncmp(adapter->name, "uni-n", 5))
-		return -ENODEV;
-	bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
-	if (bus_no != therm_bus)
-		return -ENODEV;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE);
-	info.addr = therm_address;
-	client = i2c_new_device(adapter, &info);
-	if (!client)
-		return -ENODEV;
-
-	/*
-	 * Let i2c-core delete that device on driver removal.
-	 * This is safe because i2c-core holds the core_lock mutex for us.
-	 */
-	list_add_tail(&client->detected, &thermostat_driver.clients);
-	return 0;
-}
-
-static int
-remove_thermostat(struct i2c_client *client)
-{
-	struct thermostat *th = i2c_get_clientdata(client);
-	int i;
-	
-	thermostat_remove_files();
-
-	if (thread_therm != NULL) {
-		kthread_stop(thread_therm);
-	}
-
-	printk(KERN_INFO "adt746x: Putting max temperatures back from "
-			 "%d, %d, %d to %d, %d, %d\n",
-		th->limits[0], th->limits[1], th->limits[2],
-		th->initial_limits[0], th->initial_limits[1],
-		th->initial_limits[2]);
-
-	for (i = 0; i < 3; i++)
-		write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
-
-	write_both_fan_speed(th, -1);
-
-	thermostat = NULL;
-
-	kfree(th);
-
-	return 0;
-}
-
 static int read_fan_speed(struct thermostat *th, u8 addr)
 {
 	u8 tmp[2];
@@ -203,7 +141,7 @@
 static void write_both_fan_speed(struct thermostat *th, int speed)
 {
 	write_fan_speed(th, speed, 0);
-	if (therm_type == ADT7460)
+	if (th->type == ADT7460)
 		write_fan_speed(th, speed, 1);
 }
 
@@ -216,7 +154,7 @@
 	else if (speed < -1) 
 		speed = 0;
 	
-	if (therm_type == ADT7467 && fan == 1)
+	if (th->type == ADT7467 && fan == 1)
 		return;
 	
 	if (th->last_speed[fan] != speed) {
@@ -239,7 +177,7 @@
 		write_reg(th, FAN_SPD_SET[fan], speed);
 	} else {
 		/* back to automatic */
-		if(therm_type == ADT7460) {
+		if(th->type == ADT7460) {
 			manual = read_reg(th,
 				MANUAL_MODE[fan]) & (~MANUAL_MASK);
 			manual &= ~INVERT_MASK;
@@ -293,7 +231,7 @@
 	/* we don't care about local sensor, so we start at sensor 1 */
 	for (i = 1; i < 3; i++) {
 		int started = 0;
-		int fan_number = (therm_type == ADT7460 && i == 2);
+		int fan_number = (th->type == ADT7460 && i == 2);
 		int var = th->temps[i] - th->limits[i];
 
 		if (var > -1) {
@@ -370,118 +308,24 @@
 
 static void set_limit(struct thermostat *th, int i)
 {
-		/* Set sensor1 limit higher to avoid powerdowns */
-		th->limits[i] = default_limits_chip[i] + limit_adjust;
-		write_reg(th, LIMIT_REG[i], th->limits[i]);
+	/* Set sensor1 limit higher to avoid powerdowns */
+	th->limits[i] = default_limits_chip[i] + limit_adjust;
+	write_reg(th, LIMIT_REG[i], th->limits[i]);
 		
-		/* set our limits to normal */
-		th->limits[i] = default_limits_local[i] + limit_adjust;
+	/* set our limits to normal */
+	th->limits[i] = default_limits_local[i] + limit_adjust;
 }
 
-static int probe_thermostat(struct i2c_client *client,
-			    const struct i2c_device_id *id)
-{
-	struct thermostat* th;
-	int rc;
-	int i;
-
-	if (thermostat)
-		return 0;
-
-	th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
-	if (!th)
-		return -ENOMEM;
-
-	i2c_set_clientdata(client, th);
-	th->clt = client;
-
-	rc = read_reg(th, CONFIG_REG);
-	if (rc < 0) {
-		dev_err(&client->dev, "Thermostat failed to read config!\n");
-		kfree(th);
-		return -ENODEV;
-	}
-
-	/* force manual control to start the fan quieter */
-	if (fan_speed == -1)
-		fan_speed = 64;
-	
-	if(therm_type == ADT7460) {
-		printk(KERN_INFO "adt746x: ADT7460 initializing\n");
-		/* The 7460 needs to be started explicitly */
-		write_reg(th, CONFIG_REG, 1);
-	} else
-		printk(KERN_INFO "adt746x: ADT7467 initializing\n");
-
-	for (i = 0; i < 3; i++) {
-		th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
-		set_limit(th, i);
-	}
-
-	printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
-			 " to %d, %d, %d\n",
-			 th->initial_limits[0], th->initial_limits[1],
-			 th->initial_limits[2], th->limits[0], th->limits[1],
-			 th->limits[2]);
-
-	thermostat = th;
-
-	/* record invert bit status because fw can corrupt it after suspend */
-	th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
-	th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
-
-	/* be sure to really write fan speed the first time */
-	th->last_speed[0] = -2;
-	th->last_speed[1] = -2;
-	th->last_var[0] = -80;
-	th->last_var[1] = -80;
-
-	if (fan_speed != -1) {
-		/* manual mode, stop fans */
-		write_both_fan_speed(th, 0);
-	} else {
-		/* automatic mode */
-		write_both_fan_speed(th, -1);
-	}
-	
-	thread_therm = kthread_run(monitor_task, th, "kfand");
-
-	if (thread_therm == ERR_PTR(-ENOMEM)) {
-		printk(KERN_INFO "adt746x: Kthread creation failed\n");
-		thread_therm = NULL;
-		return -ENOMEM;
-	}
-
-	thermostat_create_files();
-
-	return 0;
-}
-
-static const struct i2c_device_id therm_adt746x_id[] = {
-	{ "therm_adt746x", 0 },
-	{ }
-};
-
-static struct i2c_driver thermostat_driver = {
-	.driver = {
-		.name	= "therm_adt746x",
-	},
-	.attach_adapter	= attach_thermostat,
-	.probe = probe_thermostat,
-	.remove = remove_thermostat,
-	.id_table = therm_adt746x_id,
-};
-
-/* 
- * Now, unfortunately, sysfs doesn't give us a nice void * we could
- * pass around to the attribute functions, so we don't really have
- * choice but implement a bunch of them...
- *
- * FIXME, it does now...
- */
 #define BUILD_SHOW_FUNC_INT(name, data)				\
 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)	\
 {								\
+	struct thermostat *th = dev_get_drvdata(dev);		\
+	return sprintf(buf, "%d\n", data);			\
+}
+
+#define BUILD_SHOW_FUNC_INT_LITE(name, data)				\
+static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)	\
+{								\
 	return sprintf(buf, "%d\n", data);			\
 }
 
@@ -494,22 +338,24 @@
 #define BUILD_SHOW_FUNC_FAN(name, data)				\
 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)       \
 {								\
+	struct thermostat *th = dev_get_drvdata(dev);		\
 	return sprintf(buf, "%d (%d rpm)\n", 			\
-		thermostat->last_speed[data],			\
-		read_fan_speed(thermostat, FAN_SPEED[data])	\
+		th->last_speed[data],				\
+		read_fan_speed(th, FAN_SPEED[data])		\
 		);						\
 }
 
 #define BUILD_STORE_FUNC_DEG(name, data)			\
 static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \
 {								\
+	struct thermostat *th = dev_get_drvdata(dev);		\
 	int val;						\
 	int i;							\
 	val = simple_strtol(buf, NULL, 10);			\
 	printk(KERN_INFO "Adjusting limits by %d degrees\n", val);	\
 	limit_adjust = val;					\
 	for (i=0; i < 3; i++)					\
-		set_limit(thermostat, i);			\
+		set_limit(th, i);				\
 	return n;						\
 }
 
@@ -525,20 +371,21 @@
 	return n;						\
 }
 
-BUILD_SHOW_FUNC_INT(sensor1_temperature,	 (read_reg(thermostat, TEMP_REG[1])))
-BUILD_SHOW_FUNC_INT(sensor2_temperature,	 (read_reg(thermostat, TEMP_REG[2])))
-BUILD_SHOW_FUNC_INT(sensor1_limit,		 thermostat->limits[1])
-BUILD_SHOW_FUNC_INT(sensor2_limit,		 thermostat->limits[2])
+BUILD_SHOW_FUNC_INT(sensor1_temperature,	 (read_reg(th, TEMP_REG[1])))
+BUILD_SHOW_FUNC_INT(sensor2_temperature,	 (read_reg(th, TEMP_REG[2])))
+BUILD_SHOW_FUNC_INT(sensor1_limit,		 th->limits[1])
+BUILD_SHOW_FUNC_INT(sensor2_limit,		 th->limits[2])
 BUILD_SHOW_FUNC_STR(sensor1_location,		 sensor_location[1])
 BUILD_SHOW_FUNC_STR(sensor2_location,		 sensor_location[2])
 
-BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed)
+BUILD_SHOW_FUNC_INT_LITE(specified_fan_speed, fan_speed)
+BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
+
 BUILD_SHOW_FUNC_FAN(sensor1_fan_speed,	 0)
 BUILD_SHOW_FUNC_FAN(sensor2_fan_speed,	 1)
 
-BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
-BUILD_SHOW_FUNC_INT(limit_adjust,	 limit_adjust)
-BUILD_STORE_FUNC_DEG(limit_adjust,	 thermostat)
+BUILD_SHOW_FUNC_INT_LITE(limit_adjust,	 limit_adjust)
+BUILD_STORE_FUNC_DEG(limit_adjust,	 th)
 		
 static DEVICE_ATTR(sensor1_temperature,	S_IRUGO,
 		   show_sensor1_temperature,NULL);
@@ -564,53 +411,77 @@
 static DEVICE_ATTR(limit_adjust,	S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
 		   show_limit_adjust,	store_limit_adjust);
 
-
-static int __init
-thermostat_init(void)
+static void thermostat_create_files(struct thermostat *th)
 {
-	struct device_node* np;
-	const u32 *prop;
-	int i = 0, offset = 0;
+	struct device_node *np = th->clt->dev.of_node;
+	struct device *dev;
+	int err;
 
-	np = of_find_node_by_name(NULL, "fan");
+	/* To maintain ABI compatibility with userspace, create
+	 * the old style platform driver and attach the attributes
+	 * to it here
+	 */
+	th->pdev = of_platform_device_create(np, "temperatures", NULL);
+	if (!th->pdev)
+		return;
+	dev = &th->pdev->dev;
+	dev_set_drvdata(dev, th);
+	err = device_create_file(dev, &dev_attr_sensor1_temperature);
+	err |= device_create_file(dev, &dev_attr_sensor2_temperature);
+	err |= device_create_file(dev, &dev_attr_sensor1_limit);
+	err |= device_create_file(dev, &dev_attr_sensor2_limit);
+	err |= device_create_file(dev, &dev_attr_sensor1_location);
+	err |= device_create_file(dev, &dev_attr_sensor2_location);
+	err |= device_create_file(dev, &dev_attr_limit_adjust);
+	err |= device_create_file(dev, &dev_attr_specified_fan_speed);
+	err |= device_create_file(dev, &dev_attr_sensor1_fan_speed);
+	if(th->type == ADT7460)
+		err |= device_create_file(dev, &dev_attr_sensor2_fan_speed);
+	if (err)
+		printk(KERN_WARNING
+			"Failed to create temperature attribute file(s).\n");
+}
+
+static void thermostat_remove_files(struct thermostat *th)
+{
+	struct device *dev;
+
+	if (!th->pdev)
+		return;
+	dev = &th->pdev->dev;
+	device_remove_file(dev, &dev_attr_sensor1_temperature);
+	device_remove_file(dev, &dev_attr_sensor2_temperature);
+	device_remove_file(dev, &dev_attr_sensor1_limit);
+	device_remove_file(dev, &dev_attr_sensor2_limit);
+	device_remove_file(dev, &dev_attr_sensor1_location);
+	device_remove_file(dev, &dev_attr_sensor2_location);
+	device_remove_file(dev, &dev_attr_limit_adjust);
+	device_remove_file(dev, &dev_attr_specified_fan_speed);
+	device_remove_file(dev, &dev_attr_sensor1_fan_speed);	
+	if (th->type == ADT7460)
+		device_remove_file(dev, &dev_attr_sensor2_fan_speed);
+	of_device_unregister(th->pdev);
+
+}
+
+static int probe_thermostat(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct device_node *np = client->dev.of_node;
+	struct thermostat* th;
+	const __be32 *prop;
+	int i, rc, vers, offset = 0;
+
 	if (!np)
-		return -ENODEV;
-	if (of_device_is_compatible(np, "adt7460"))
-		therm_type = ADT7460;
-	else if (of_device_is_compatible(np, "adt7467"))
-		therm_type = ADT7467;
-	else {
-		of_node_put(np);
-		return -ENODEV;
-	}
-
+		return -ENXIO;
 	prop = of_get_property(np, "hwsensor-params-version", NULL);
-	printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
-			 (*prop == 1)?"":"un");
-	if (*prop != 1) {
-		of_node_put(np);
-		return -ENODEV;
-	}
-
-	prop = of_get_property(np, "reg", NULL);
-	if (!prop) {
-		of_node_put(np);
-		return -ENODEV;
-	}
-
-	/* look for bus either by path or using "reg" */
-	if (strstr(np->full_name, "/i2c-bus@") != NULL) {
-		const char *tmp_bus = (strstr(np->full_name, "/i2c-bus@") + 9);
-		therm_bus = tmp_bus[0]-'0';
-	} else {
-		therm_bus = ((*prop) >> 8) & 0x0f;
-	}
-
-	therm_address = ((*prop) & 0xff) >> 1;
-
-	printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, "
-			 "limit_adjust: %d, fan_speed: %d\n",
-			 therm_bus, therm_address, limit_adjust, fan_speed);
+	if (!prop)
+		return -ENXIO;
+	vers = be32_to_cpup(prop);
+	printk(KERN_INFO "adt746x: version %d (%ssupported)\n",
+	       vers, vers == 1 ? "" : "un");
+	if (vers != 1)
+		return -ENXIO;
 
 	if (of_get_property(np, "hwsensor-location", NULL)) {
 		for (i = 0; i < 3; i++) {
@@ -623,20 +494,119 @@
 			printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]);
 			offset += strlen(sensor_location[i]) + 1;
 		}
-	} else {
-		sensor_location[0] = "?";
-		sensor_location[1] = "?";
-		sensor_location[2] = "?";
 	}
 
-	of_dev = of_platform_device_create(np, "temperatures", NULL);
-	of_node_put(np);
+	th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
+	if (!th)
+		return -ENOMEM;
 
-	if (of_dev == NULL) {
-		printk(KERN_ERR "Can't register temperatures device !\n");
+	i2c_set_clientdata(client, th);
+	th->clt = client;
+	th->type = id->driver_data;
+
+	rc = read_reg(th, CONFIG_REG);
+	if (rc < 0) {
+		dev_err(&client->dev, "Thermostat failed to read config!\n");
+		kfree(th);
 		return -ENODEV;
 	}
 
+	/* force manual control to start the fan quieter */
+	if (fan_speed == -1)
+		fan_speed = 64;
+	
+	if (th->type == ADT7460) {
+		printk(KERN_INFO "adt746x: ADT7460 initializing\n");
+		/* The 7460 needs to be started explicitly */
+		write_reg(th, CONFIG_REG, 1);
+	} else
+		printk(KERN_INFO "adt746x: ADT7467 initializing\n");
+
+	for (i = 0; i < 3; i++) {
+		th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
+		set_limit(th, i);
+	}
+
+	printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
+			 " to %d, %d, %d\n",
+			 th->initial_limits[0], th->initial_limits[1],
+			 th->initial_limits[2], th->limits[0], th->limits[1],
+			 th->limits[2]);
+
+	/* record invert bit status because fw can corrupt it after suspend */
+	th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
+	th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
+
+	/* be sure to really write fan speed the first time */
+	th->last_speed[0] = -2;
+	th->last_speed[1] = -2;
+	th->last_var[0] = -80;
+	th->last_var[1] = -80;
+
+	if (fan_speed != -1) {
+		/* manual mode, stop fans */
+		write_both_fan_speed(th, 0);
+	} else {
+		/* automatic mode */
+		write_both_fan_speed(th, -1);
+	}
+	
+	th->thread = kthread_run(monitor_task, th, "kfand");
+	if (th->thread == ERR_PTR(-ENOMEM)) {
+		printk(KERN_INFO "adt746x: Kthread creation failed\n");
+		th->thread = NULL;
+		return -ENOMEM;
+	}
+
+	thermostat_create_files(th);
+
+	return 0;
+}
+
+static int remove_thermostat(struct i2c_client *client)
+{
+	struct thermostat *th = i2c_get_clientdata(client);
+	int i;
+	
+	thermostat_remove_files(th);
+
+	if (th->thread != NULL)
+		kthread_stop(th->thread);
+
+	printk(KERN_INFO "adt746x: Putting max temperatures back from "
+			 "%d, %d, %d to %d, %d, %d\n",
+		th->limits[0], th->limits[1], th->limits[2],
+		th->initial_limits[0], th->initial_limits[1],
+		th->initial_limits[2]);
+
+	for (i = 0; i < 3; i++)
+		write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
+
+	write_both_fan_speed(th, -1);
+
+	kfree(th);
+
+	return 0;
+}
+
+static const struct i2c_device_id therm_adt746x_id[] = {
+	{ "MAC,adt7460", ADT7460 },
+	{ "MAC,adt7467", ADT7467 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, therm_adt746x_id);
+
+static struct i2c_driver thermostat_driver = {
+	.driver = {
+		.name	= "therm_adt746x",
+	},
+	.probe = probe_thermostat,
+	.remove = remove_thermostat,
+	.id_table = therm_adt746x_id,
+};
+
+static int __init thermostat_init(void)
+{
 #ifndef CONFIG_I2C_POWERMAC
 	request_module("i2c-powermac");
 #endif
@@ -644,51 +614,9 @@
 	return i2c_add_driver(&thermostat_driver);
 }
 
-static void thermostat_create_files(void)
-{
-	int err;
-
-	err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
-	err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
-	err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
-	err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_limit);
-	err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_location);
-	err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_location);
-	err |= device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
-	err |= device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
-	err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
-	if(therm_type == ADT7460)
-		err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
-	if (err)
-		printk(KERN_WARNING
-			"Failed to create temperature attribute file(s).\n");
-}
-
-static void thermostat_remove_files(void)
-{
-	if (of_dev) {
-		device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor2_temperature);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor1_limit);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor2_limit);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor1_location);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor2_location);
-		device_remove_file(&of_dev->dev, &dev_attr_limit_adjust);
-		device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
-
-		if(therm_type == ADT7460)
-			device_remove_file(&of_dev->dev,
-					   &dev_attr_sensor2_fan_speed);
-
-	}
-}
-
-static void __exit
-thermostat_exit(void)
+static void __exit thermostat_exit(void)
 {
 	i2c_del_driver(&thermostat_driver);
-	of_device_unregister(of_dev);
 }
 
 module_init(thermostat_init);
diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h
index 7a2482c..028cdac 100644
--- a/drivers/macintosh/windfarm.h
+++ b/drivers/macintosh/windfarm.h
@@ -17,7 +17,7 @@
 #include <linux/device.h>
 
 /* Display a 16.16 fixed point value */
-#define FIX32TOPRINT(f)	((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
+#define FIX32TOPRINT(f)	(((s32)(f)) >> 16),(((((s32)(f)) & 0xffff) * 1000) >> 16)
 
 /*
  * Control objects
@@ -35,12 +35,13 @@
 };
 
 struct wf_control {
-	struct list_head	link;
-	struct wf_control_ops	*ops;
-	char			*name;
-	int			type;
-	struct kref		ref;
-	struct device_attribute	attr;
+	struct list_head		link;
+	const struct wf_control_ops	*ops;
+	const char			*name;
+	int				type;
+	struct kref			ref;
+	struct device_attribute		attr;
+	void				*priv;
 };
 
 #define WF_CONTROL_TYPE_GENERIC		0
@@ -72,6 +73,26 @@
 	return ct->ops->set_value(ct, vmin);
 }
 
+static inline int wf_control_set(struct wf_control *ct, s32 val)
+{
+	return ct->ops->set_value(ct, val);
+}
+
+static inline int wf_control_get(struct wf_control *ct, s32 *val)
+{
+	return ct->ops->get_value(ct, val);
+}
+
+static inline s32 wf_control_get_min(struct wf_control *ct)
+{
+	return ct->ops->get_min(ct);
+}
+
+static inline s32 wf_control_get_max(struct wf_control *ct)
+{
+	return ct->ops->get_max(ct);
+}
+
 /*
  * Sensor objects
  */
@@ -85,11 +106,12 @@
 };
 
 struct wf_sensor {
-	struct list_head	link;
-	struct wf_sensor_ops	*ops;
-	char			*name;
-	struct kref		ref;
-	struct device_attribute	attr;
+	struct list_head		link;
+	const struct wf_sensor_ops	*ops;
+	const char			*name;
+	struct kref			ref;
+	struct device_attribute		attr;
+	void				*priv;
 };
 
 /* Same lifetime rules as controls */
@@ -99,6 +121,11 @@
 extern int wf_get_sensor(struct wf_sensor *sr);
 extern void wf_put_sensor(struct wf_sensor *sr);
 
+static inline int wf_sensor_get(struct wf_sensor *sr, s32 *val)
+{
+	return sr->ops->get_value(sr, val);
+}
+
 /* For use by clients. Note that we are a bit racy here since
  * notifier_block doesn't have a module owner field. I may fix
  * it one day ...
diff --git a/drivers/macintosh/windfarm_ad7417_sensor.c b/drivers/macintosh/windfarm_ad7417_sensor.c
new file mode 100644
index 0000000..ac3f243
--- /dev/null
+++ b/drivers/macintosh/windfarm_ad7417_sensor.c
@@ -0,0 +1,347 @@
+/*
+ * Windfarm PowerMac thermal control. AD7417 sensors
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+struct wf_ad7417_priv {
+	struct kref		ref;
+	struct i2c_client	*i2c;
+	u8			config;
+	u8			cpu;
+	const struct mpu_data	*mpu;
+	struct wf_sensor	sensors[5];
+	struct mutex		lock;
+};
+
+static int wf_ad7417_temp_get(struct wf_sensor *sr, s32 *value)
+{
+	struct wf_ad7417_priv *pv = sr->priv;
+	u8 buf[2];
+	s16 raw;
+	int rc;
+
+	*value = 0;
+	mutex_lock(&pv->lock);
+
+	/* Read temp register */
+	buf[0] = 0;
+	rc = i2c_master_send(pv->i2c, buf, 1);
+	if (rc < 0)
+		goto error;
+	rc = i2c_master_recv(pv->i2c, buf, 2);
+	if (rc < 0)
+		goto error;
+
+	/* Read a a 16-bit signed value */
+	raw = be16_to_cpup((__le16 *)buf);
+
+	/* Convert 8.8-bit to 16.16 fixed point */
+	*value = ((s32)raw) << 8;
+
+	mutex_unlock(&pv->lock);
+	return 0;
+
+error:
+	mutex_unlock(&pv->lock);
+	return -1;
+}
+
+/*
+ * Scaling factors for the AD7417 ADC converters (except
+ * for the CPU diode which is obtained from the EEPROM).
+ * Those values are obtained from the property list of
+ * the darwin driver
+ */
+#define ADC_12V_CURRENT_SCALE	0x0320	/* _AD2 */
+#define ADC_CPU_VOLTAGE_SCALE	0x00a0	/* _AD3 */
+#define ADC_CPU_CURRENT_SCALE	0x1f40	/* _AD4 */
+
+static void wf_ad7417_adc_convert(struct wf_ad7417_priv *pv,
+				  int chan, s32 raw, s32 *value)
+{
+	switch(chan) {
+	case 1: /* Diode */
+		*value = (raw * (s32)pv->mpu->mdiode +
+			((s32)pv->mpu->bdiode << 12)) >> 2;
+		break;
+	case 2: /* 12v current */
+		*value = raw * ADC_12V_CURRENT_SCALE;
+		break;
+	case 3: /* core voltage */
+		*value = raw * ADC_CPU_VOLTAGE_SCALE;
+		break;
+	case 4: /* core current */
+		*value = raw * ADC_CPU_CURRENT_SCALE;
+		break;
+	}
+}
+
+static int wf_ad7417_adc_get(struct wf_sensor *sr, s32 *value)
+{
+	struct wf_ad7417_priv *pv = sr->priv;
+	int chan = sr - pv->sensors;
+	int i, rc;
+	u8 buf[2];
+	u16 raw;
+
+	*value = 0;
+	mutex_lock(&pv->lock);
+	for (i = 0; i < 10; i++) {
+		/* Set channel */
+		buf[0] = 1;
+		buf[1] = (pv->config & 0x1f) | (chan << 5);
+		rc = i2c_master_send(pv->i2c, buf, 2);
+		if (rc < 0)
+			goto error;
+
+		/* Wait for conversion */
+		msleep(1);
+
+		/* Switch to data register */
+		buf[0] = 4;
+		rc = i2c_master_send(pv->i2c, buf, 1);
+		if (rc < 0)
+			goto error;
+
+		/* Read result */
+		rc = i2c_master_recv(pv->i2c, buf, 2);
+		if (rc < 0)
+			goto error;
+
+		/* Read a a 16-bit signed value */
+		raw = be16_to_cpup((__le16 *)buf) >> 6;
+		wf_ad7417_adc_convert(pv, chan, raw, value);
+
+		dev_vdbg(&pv->i2c->dev, "ADC chan %d [%s]"
+			 " raw value: 0x%x, conv to: 0x%08x\n",
+			 chan, sr->name, raw, *value);
+
+		mutex_unlock(&pv->lock);
+		return 0;
+
+	error:
+		dev_dbg(&pv->i2c->dev,
+			  "Error reading ADC, try %d...\n", i);
+		if (i < 9)
+			msleep(10);
+	}
+	mutex_unlock(&pv->lock);
+	return -1;
+}
+
+static void wf_ad7417_release(struct kref *ref)
+{
+	struct wf_ad7417_priv *pv = container_of(ref,
+						 struct wf_ad7417_priv, ref);
+	kfree(pv);
+}
+
+static void wf_ad7417_sensor_release(struct wf_sensor *sr)
+{
+	struct wf_ad7417_priv *pv = sr->priv;
+
+	kfree(sr->name);
+	kref_put(&pv->ref, wf_ad7417_release);
+}
+
+static const struct wf_sensor_ops wf_ad7417_temp_ops = {
+	.get_value	= wf_ad7417_temp_get,
+	.release	= wf_ad7417_sensor_release,
+	.owner		= THIS_MODULE,
+};
+
+static const struct wf_sensor_ops wf_ad7417_adc_ops = {
+	.get_value	= wf_ad7417_adc_get,
+	.release	= wf_ad7417_sensor_release,
+	.owner		= THIS_MODULE,
+};
+
+static void __devinit wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
+					   int index, const char *name,
+					   const struct wf_sensor_ops *ops)
+{
+	pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu);
+	pv->sensors[index].priv = pv;
+	pv->sensors[index].ops = ops;
+	if (!wf_register_sensor(&pv->sensors[index]))
+		kref_get(&pv->ref);
+}
+
+static void __devinit wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
+{
+	int rc;
+	u8 buf[2];
+	u8 config = 0;
+
+	/*
+	 * Read ADC the configuration register and cache it. We
+	 * also make sure Config2 contains proper values, I've seen
+	 * cases where we got stale grabage in there, thus preventing
+	 * proper reading of conv. values
+	 */
+
+	/* Clear Config2 */
+	buf[0] = 5;
+	buf[1] = 0;
+	i2c_master_send(pv->i2c, buf, 2);
+
+	/* Read & cache Config1 */
+	buf[0] = 1;
+	rc = i2c_master_send(pv->i2c, buf, 1);
+	if (rc > 0) {
+		rc = i2c_master_recv(pv->i2c, buf, 1);
+		if (rc > 0) {
+			config = buf[0];
+
+			dev_dbg(&pv->i2c->dev, "ADC config reg: %02x\n",
+				config);
+
+			/* Disable shutdown mode */
+			config &= 0xfe;
+			buf[0] = 1;
+			buf[1] = config;
+			rc = i2c_master_send(pv->i2c, buf, 2);
+		}
+	}
+	if (rc <= 0)
+		dev_err(&pv->i2c->dev, "Error reading ADC config\n");
+
+	pv->config = config;
+}
+
+static int __devinit wf_ad7417_probe(struct i2c_client *client,
+				     const struct i2c_device_id *id)
+{
+	struct wf_ad7417_priv *pv;
+	const struct mpu_data *mpu;
+	const char *loc;
+	int cpu_nr;
+
+	loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+	if (!loc) {
+		dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * Identify which CPU we belong to by looking at the first entry
+	 * in the hwsensor-location list
+	 */
+	if (!strncmp(loc, "CPU A", 5))
+		cpu_nr = 0;
+	else if (!strncmp(loc, "CPU B", 5))
+		cpu_nr = 1;
+	else {
+		pr_err("wf_ad7417: Can't identify location %s\n", loc);
+		return -ENXIO;
+	}
+	mpu = wf_get_mpu(cpu_nr);
+	if (!mpu) {
+		dev_err(&client->dev, "Failed to retrieve MPU data\n");
+		return -ENXIO;
+	}
+
+	pv = kzalloc(sizeof(struct wf_ad7417_priv), GFP_KERNEL);
+	if (pv == NULL)
+		return -ENODEV;
+
+	kref_init(&pv->ref);
+	mutex_init(&pv->lock);
+	pv->i2c = client;
+	pv->cpu = cpu_nr;
+	pv->mpu = mpu;
+	dev_set_drvdata(&client->dev, pv);
+
+	/* Initialize the chip */
+	wf_ad7417_init_chip(pv);
+
+	/*
+	 * We cannot rely on Apple device-tree giving us child
+	 * node with the names of the individual sensors so we
+	 * just hard code what we know about them
+	 */
+	wf_ad7417_add_sensor(pv, 0, "cpu-amb-temp", &wf_ad7417_temp_ops);
+	wf_ad7417_add_sensor(pv, 1, "cpu-diode-temp", &wf_ad7417_adc_ops);
+	wf_ad7417_add_sensor(pv, 2, "cpu-12v-current", &wf_ad7417_adc_ops);
+	wf_ad7417_add_sensor(pv, 3, "cpu-voltage", &wf_ad7417_adc_ops);
+	wf_ad7417_add_sensor(pv, 4, "cpu-current", &wf_ad7417_adc_ops);
+
+	return 0;
+}
+
+static int __devexit wf_ad7417_remove(struct i2c_client *client)
+{
+	struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev);
+	int i;
+
+	/* Mark client detached */
+	pv->i2c = NULL;
+
+	/* Release sensor */
+	for (i = 0; i < 5; i++)
+		wf_unregister_sensor(&pv->sensors[i]);
+
+	kref_put(&pv->ref, wf_ad7417_release);
+
+	return 0;
+}
+
+static const struct i2c_device_id wf_ad7417_id[] = {
+	{ "MAC,ad7417", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wf_ad7417_id);
+
+static struct i2c_driver wf_ad7417_driver = {
+	.driver = {
+		.name	= "wf_ad7417",
+	},
+	.probe		= wf_ad7417_probe,
+	.remove		= wf_ad7417_remove,
+	.id_table	= wf_ad7417_id,
+};
+
+static int __devinit wf_ad7417_init(void)
+{
+	/* This is only supported on these machines */
+	if (!of_machine_is_compatible("PowerMac7,2") &&
+	    !of_machine_is_compatible("PowerMac7,3") &&
+	    !of_machine_is_compatible("RackMac3,1"))
+		return -ENODEV;
+
+	return i2c_add_driver(&wf_ad7417_driver);
+}
+
+static void __devexit wf_ad7417_exit(void)
+{
+	i2c_del_driver(&wf_ad7417_driver);
+}
+
+module_init(wf_ad7417_init);
+module_exit(wf_ad7417_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("ad7417 sensor driver for PowerMacs");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index ce88979..3ee198b 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -164,13 +164,27 @@
 			       struct device_attribute *attr, char *buf)
 {
 	struct wf_control *ctrl = container_of(attr, struct wf_control, attr);
+	const char *typestr;
 	s32 val = 0;
 	int err;
 
 	err = ctrl->ops->get_value(ctrl, &val);
-	if (err < 0)
+	if (err < 0) {
+		if (err == -EFAULT)
+			return sprintf(buf, "<HW FAULT>\n");
 		return err;
-	return sprintf(buf, "%d\n", val);
+	}
+	switch(ctrl->type) {
+	case WF_CONTROL_RPM_FAN:
+		typestr = " RPM";
+		break;
+	case WF_CONTROL_PWM_FAN:
+		typestr = " %";
+		break;
+	default:
+		typestr = "";
+	}
+	return sprintf(buf, "%d%s\n", val, typestr);
 }
 
 /* This is really only for debugging... */
@@ -470,11 +484,6 @@
 {
 	DBG("wf: core loaded\n");
 
-	/* Don't register on old machines that use therm_pm72 for now */
-	if (of_machine_is_compatible("PowerMac7,2") ||
-	    of_machine_is_compatible("PowerMac7,3") ||
-	    of_machine_is_compatible("RackMac3,1"))
-		return -ENODEV;
 	platform_device_register(&wf_platform_device);
 	return 0;
 }
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c
index 1a77a7c..72d1fdf 100644
--- a/drivers/macintosh/windfarm_cpufreq_clamp.c
+++ b/drivers/macintosh/windfarm_cpufreq_clamp.c
@@ -75,12 +75,6 @@
 {
 	struct wf_control *clamp;
 
-	/* Don't register on old machines that use therm_pm72 for now */
-	if (of_machine_is_compatible("PowerMac7,2") ||
-	    of_machine_is_compatible("PowerMac7,3") ||
-	    of_machine_is_compatible("RackMac3,1"))
-		return -ENODEV;
-
 	clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
 	if (clamp == NULL)
 		return -ENOMEM;
diff --git a/drivers/macintosh/windfarm_fcu_controls.c b/drivers/macintosh/windfarm_fcu_controls.c
new file mode 100644
index 0000000..b3411ed
--- /dev/null
+++ b/drivers/macintosh/windfarm_fcu_controls.c
@@ -0,0 +1,613 @@
+/*
+ * Windfarm PowerMac thermal control. FCU fan control
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#ifdef DEBUG
+#define DBG(args...)	printk(args)
+#else
+#define DBG(args...)	do { } while(0)
+#endif
+
+/*
+ * This option is "weird" :) Basically, if you define this to 1
+ * the control loop for the RPMs fans (not PWMs) will apply the
+ * correction factor obtained from the PID to the actual RPM
+ * speed read from the FCU.
+ *
+ * If you define the below constant to 0, then it will be
+ * applied to the setpoint RPM speed, that is basically the
+ * speed we proviously "asked" for.
+ *
+ * I'm using 0 for now which is what therm_pm72 used to do and
+ * what Darwin -apparently- does based on observed behaviour.
+ */
+#define RPM_PID_USE_ACTUAL_SPEED	0
+
+/* Default min/max for pumps */
+#define CPU_PUMP_OUTPUT_MAX		3200
+#define CPU_PUMP_OUTPUT_MIN		1250
+
+#define FCU_FAN_RPM		0
+#define FCU_FAN_PWM		1
+
+struct wf_fcu_priv {
+	struct kref		ref;
+	struct i2c_client	*i2c;
+	struct mutex		lock;
+	struct list_head	fan_list;
+	int			rpm_shift;
+};
+
+struct wf_fcu_fan {
+	struct list_head	link;
+	int			id;
+	s32			min, max, target;
+	struct wf_fcu_priv	*fcu_priv;
+	struct wf_control	ctrl;
+};
+
+static void wf_fcu_release(struct kref *ref)
+{
+	struct wf_fcu_priv *pv = container_of(ref, struct wf_fcu_priv, ref);
+
+	kfree(pv);
+}
+
+static void wf_fcu_fan_release(struct wf_control *ct)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+
+	kref_put(&fan->fcu_priv->ref, wf_fcu_release);
+	kfree(fan);
+}
+
+static int wf_fcu_read_reg(struct wf_fcu_priv *pv, int reg,
+			   unsigned char *buf, int nb)
+{
+	int tries, nr, nw;
+
+	mutex_lock(&pv->lock);
+
+	buf[0] = reg;
+	tries = 0;
+	for (;;) {
+		nw = i2c_master_send(pv->i2c, buf, 1);
+		if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+			break;
+		msleep(10);
+		++tries;
+	}
+	if (nw <= 0) {
+		pr_err("Failure writing address to FCU: %d", nw);
+		nr = nw;
+		goto bail;
+	}
+	tries = 0;
+	for (;;) {
+		nr = i2c_master_recv(pv->i2c, buf, nb);
+		if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100)
+			break;
+		msleep(10);
+		++tries;
+	}
+	if (nr <= 0)
+		pr_err("wf_fcu: Failure reading data from FCU: %d", nw);
+ bail:
+	mutex_unlock(&pv->lock);
+	return nr;
+}
+
+static int wf_fcu_write_reg(struct wf_fcu_priv *pv, int reg,
+			    const unsigned char *ptr, int nb)
+{
+	int tries, nw;
+	unsigned char buf[16];
+
+	buf[0] = reg;
+	memcpy(buf+1, ptr, nb);
+	++nb;
+	tries = 0;
+	for (;;) {
+		nw = i2c_master_send(pv->i2c, buf, nb);
+		if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+			break;
+		msleep(10);
+		++tries;
+	}
+	if (nw < 0)
+		pr_err("wf_fcu: Failure writing to FCU: %d", nw);
+	return nw;
+}
+
+static int wf_fcu_fan_set_rpm(struct wf_control *ct, s32 value)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	int rc, shift = pv->rpm_shift;
+	unsigned char buf[2];
+
+	if (value < fan->min)
+		value = fan->min;
+	if (value > fan->max)
+		value = fan->max;
+
+	fan->target = value;
+
+	buf[0] = value >> (8 - shift);
+	buf[1] = value << shift;
+	rc = wf_fcu_write_reg(pv, 0x10 + (fan->id * 2), buf, 2);
+	if (rc < 0)
+		return -EIO;
+	return 0;
+}
+
+static int wf_fcu_fan_get_rpm(struct wf_control *ct, s32 *value)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	int rc, reg_base, shift = pv->rpm_shift;
+	unsigned char failure;
+	unsigned char active;
+	unsigned char buf[2];
+
+	rc = wf_fcu_read_reg(pv, 0xb, &failure, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((failure & (1 << fan->id)) != 0)
+		return -EFAULT;
+	rc = wf_fcu_read_reg(pv, 0xd, &active, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((active & (1 << fan->id)) == 0)
+		return -ENXIO;
+
+	/* Programmed value or real current speed */
+#if RPM_PID_USE_ACTUAL_SPEED
+	reg_base = 0x11;
+#else
+	reg_base = 0x10;
+#endif
+	rc = wf_fcu_read_reg(pv, reg_base + (fan->id * 2), buf, 2);
+	if (rc != 2)
+		return -EIO;
+
+	*value = (buf[0] << (8 - shift)) | buf[1] >> shift;
+
+	return 0;
+}
+
+static int wf_fcu_fan_set_pwm(struct wf_control *ct, s32 value)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	unsigned char buf[2];
+	int rc;
+
+	if (value < fan->min)
+		value = fan->min;
+	if (value > fan->max)
+		value = fan->max;
+
+	fan->target = value;
+
+	value = (value * 2559) / 1000;
+	buf[0] = value;
+	rc = wf_fcu_write_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+	if (rc < 0)
+		return -EIO;
+	return 0;
+}
+
+static int wf_fcu_fan_get_pwm(struct wf_control *ct, s32 *value)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	unsigned char failure;
+	unsigned char active;
+	unsigned char buf[2];
+	int rc;
+
+	rc = wf_fcu_read_reg(pv, 0x2b, &failure, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((failure & (1 << fan->id)) != 0)
+		return -EFAULT;
+	rc = wf_fcu_read_reg(pv, 0x2d, &active, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((active & (1 << fan->id)) == 0)
+		return -ENXIO;
+
+	rc = wf_fcu_read_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+	if (rc != 1)
+		return -EIO;
+
+	*value = (((s32)buf[0]) * 1000) / 2559;
+
+	return 0;
+}
+
+static s32 wf_fcu_fan_min(struct wf_control *ct)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+
+	return fan->min;
+}
+
+static s32 wf_fcu_fan_max(struct wf_control *ct)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+
+	return fan->max;
+}
+
+static const struct wf_control_ops wf_fcu_fan_rpm_ops = {
+	.set_value	= wf_fcu_fan_set_rpm,
+	.get_value	= wf_fcu_fan_get_rpm,
+	.get_min	= wf_fcu_fan_min,
+	.get_max	= wf_fcu_fan_max,
+	.release	= wf_fcu_fan_release,
+	.owner		= THIS_MODULE,
+};
+
+static const struct wf_control_ops wf_fcu_fan_pwm_ops = {
+	.set_value	= wf_fcu_fan_set_pwm,
+	.get_value	= wf_fcu_fan_get_pwm,
+	.get_min	= wf_fcu_fan_min,
+	.get_max	= wf_fcu_fan_max,
+	.release	= wf_fcu_fan_release,
+	.owner		= THIS_MODULE,
+};
+
+static void __devinit wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan)
+{
+	const struct mpu_data *mpu = wf_get_mpu(0);
+	u16 pump_min = 0, pump_max = 0xffff;
+	u16 tmp[4];
+
+	/* Try to fetch pumps min/max infos from eeprom */
+	if (mpu) {
+		memcpy(&tmp, mpu->processor_part_num, 8);
+		if (tmp[0] != 0xffff && tmp[1] != 0xffff) {
+			pump_min = max(pump_min, tmp[0]);
+			pump_max = min(pump_max, tmp[1]);
+		}
+		if (tmp[2] != 0xffff && tmp[3] != 0xffff) {
+			pump_min = max(pump_min, tmp[2]);
+			pump_max = min(pump_max, tmp[3]);
+		}
+	}
+
+	/* Double check the values, this _IS_ needed as the EEPROM on
+	 * some dual 2.5Ghz G5s seem, at least, to have both min & max
+	 * same to the same value ... (grrrr)
+	 */
+	if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) {
+		pump_min = CPU_PUMP_OUTPUT_MIN;
+		pump_max = CPU_PUMP_OUTPUT_MAX;
+	}
+
+	fan->min = pump_min;
+	fan->max = pump_max;
+
+	DBG("wf_fcu: pump min/max for %s set to: [%d..%d] RPM\n",
+	    fan->ctrl.name, pump_min, pump_max);
+}
+
+static void __devinit wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan)
+{
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	const struct mpu_data *mpu0 = wf_get_mpu(0);
+	const struct mpu_data *mpu1 = wf_get_mpu(1);
+
+	/* Default */
+	fan->min = 2400 >> pv->rpm_shift;
+	fan->max = 56000 >> pv->rpm_shift;
+
+	/* CPU fans have min/max in MPU */
+	if (mpu0 && !strcmp(fan->ctrl.name, "cpu-front-fan-0")) {
+		fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+		fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+		goto bail;
+	}
+	if (mpu1 && !strcmp(fan->ctrl.name, "cpu-front-fan-1")) {
+		fan->min = max(fan->min, (s32)mpu1->rminn_intake_fan);
+		fan->max = min(fan->max, (s32)mpu1->rmaxn_intake_fan);
+		goto bail;
+	}
+	if (mpu0 && !strcmp(fan->ctrl.name, "cpu-rear-fan-0")) {
+		fan->min = max(fan->min, (s32)mpu0->rminn_exhaust_fan);
+		fan->max = min(fan->max, (s32)mpu0->rmaxn_exhaust_fan);
+		goto bail;
+	}
+	if (mpu1 && !strcmp(fan->ctrl.name, "cpu-rear-fan-1")) {
+		fan->min = max(fan->min, (s32)mpu1->rminn_exhaust_fan);
+		fan->max = min(fan->max, (s32)mpu1->rmaxn_exhaust_fan);
+		goto bail;
+	}
+	/* Rackmac variants, we just use mpu0 intake */
+	if (!strncmp(fan->ctrl.name, "cpu-fan", 7)) {
+		fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+		fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+		goto bail;
+	}
+ bail:
+	DBG("wf_fcu: fan min/max for %s set to: [%d..%d] RPM\n",
+	    fan->ctrl.name, fan->min, fan->max);
+}
+
+static void __devinit wf_fcu_add_fan(struct wf_fcu_priv *pv,
+				     const char *name,
+				     int type, int id)
+{
+	struct wf_fcu_fan *fan;
+
+	fan = kzalloc(sizeof(*fan), GFP_KERNEL);
+	if (!fan)
+		return;
+	fan->fcu_priv = pv;
+	fan->id = id;
+	fan->ctrl.name = name;
+	fan->ctrl.priv = fan;
+
+	/* min/max is oddball but the code comes from
+	 * therm_pm72 which seems to work so ...
+	 */
+	if (type == FCU_FAN_RPM) {
+		if (!strncmp(name, "cpu-pump", strlen("cpu-pump")))
+			wf_fcu_get_pump_minmax(fan);
+		else
+			wf_fcu_get_rpmfan_minmax(fan);
+		fan->ctrl.type = WF_CONTROL_RPM_FAN;
+		fan->ctrl.ops = &wf_fcu_fan_rpm_ops;
+	} else {
+		fan->min = 10;
+		fan->max = 100;
+		fan->ctrl.type = WF_CONTROL_PWM_FAN;
+		fan->ctrl.ops = &wf_fcu_fan_pwm_ops;
+	}
+
+	if (wf_register_control(&fan->ctrl)) {
+		pr_err("wf_fcu: Failed to register fan %s\n", name);
+		kfree(fan);
+		return;
+	}
+	list_add(&fan->link, &pv->fan_list);
+	kref_get(&pv->ref);
+}
+
+static void __devinit wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
+{
+	/* Translation of device-tree location properties to
+	 * windfarm fan names
+	 */
+	static const struct {
+		const char *dt_name;	/* Device-tree name */
+		const char *ct_name;	/* Control name */
+	} loc_trans[] = {
+		{ "BACKSIDE",		"backside-fan",		},
+		{ "SYS CTRLR FAN",	"backside-fan",		},
+		{ "DRIVE BAY",		"drive-bay-fan",	},
+		{ "SLOT",		"slots-fan",		},
+		{ "PCI FAN",		"slots-fan",		},
+		{ "CPU A INTAKE",	"cpu-front-fan-0",	},
+		{ "CPU A EXHAUST",	"cpu-rear-fan-0",	},
+		{ "CPU B INTAKE",	"cpu-front-fan-1",	},
+		{ "CPU B EXHAUST",	"cpu-rear-fan-1",	},
+		{ "CPU A PUMP",		"cpu-pump-0",		},
+		{ "CPU B PUMP",		"cpu-pump-1",		},
+		{ "CPU A 1",		"cpu-fan-a-0",		},
+		{ "CPU A 2",		"cpu-fan-b-0",		},
+		{ "CPU A 3",		"cpu-fan-c-0",		},
+		{ "CPU B 1",		"cpu-fan-a-1",		},
+		{ "CPU B 2",		"cpu-fan-b-1",		},
+		{ "CPU B 3",		"cpu-fan-c-1",		},
+	};
+	struct device_node *np = NULL, *fcu = pv->i2c->dev.of_node;
+	int i;
+
+	DBG("Looking up FCU controls in device-tree...\n");
+
+	while ((np = of_get_next_child(fcu, np)) != NULL) {
+		int id, type = -1;
+		const char *loc;
+		const char *name;
+		const u32 *reg;
+
+		DBG(" control: %s, type: %s\n", np->name, np->type);
+
+		/* Detect control type */
+		if (!strcmp(np->type, "fan-rpm-control") ||
+		    !strcmp(np->type, "fan-rpm"))
+			type = FCU_FAN_RPM;
+		if (!strcmp(np->type, "fan-pwm-control") ||
+		    !strcmp(np->type, "fan-pwm"))
+			type = FCU_FAN_PWM;
+		/* Only care about fans for now */
+		if (type == -1)
+			continue;
+
+		/* Lookup for a matching location */
+		loc = of_get_property(np, "location", NULL);
+		reg = of_get_property(np, "reg", NULL);
+		if (loc == NULL || reg == NULL)
+			continue;
+		DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
+
+		for (i = 0; i < ARRAY_SIZE(loc_trans); i++) {
+			if (strncmp(loc, loc_trans[i].dt_name,
+				    strlen(loc_trans[i].dt_name)))
+				continue;
+			name = loc_trans[i].ct_name;
+
+			DBG(" location match, name: %s\n", name);
+
+			if (type == FCU_FAN_RPM)
+				id = ((*reg) - 0x10) / 2;
+			else
+				id = ((*reg) - 0x30) / 2;
+			if (id > 7) {
+				pr_warning("wf_fcu: Can't parse "
+				       "fan ID in device-tree for %s\n",
+					   np->full_name);
+				break;
+			}
+			wf_fcu_add_fan(pv, name, type, id);
+			break;
+		}
+	}
+}
+
+static void __devinit wf_fcu_default_fans(struct wf_fcu_priv *pv)
+{
+	/* We only support the default fans for PowerMac7,2 */
+	if (!of_machine_is_compatible("PowerMac7,2"))
+		return;
+
+	wf_fcu_add_fan(pv, "backside-fan",	FCU_FAN_PWM, 1);
+	wf_fcu_add_fan(pv, "drive-bay-fan",	FCU_FAN_RPM, 2);
+	wf_fcu_add_fan(pv, "slots-fan",		FCU_FAN_PWM, 2);
+	wf_fcu_add_fan(pv, "cpu-front-fan-0",	FCU_FAN_RPM, 3);
+	wf_fcu_add_fan(pv, "cpu-rear-fan-0",	FCU_FAN_RPM, 4);
+	wf_fcu_add_fan(pv, "cpu-front-fan-1",	FCU_FAN_RPM, 5);
+	wf_fcu_add_fan(pv, "cpu-rear-fan-1",	FCU_FAN_RPM, 6);
+}
+
+static int __devinit wf_fcu_init_chip(struct wf_fcu_priv *pv)
+{
+	unsigned char buf = 0xff;
+	int rc;
+
+	rc = wf_fcu_write_reg(pv, 0xe, &buf, 1);
+	if (rc < 0)
+		return -EIO;
+	rc = wf_fcu_write_reg(pv, 0x2e, &buf, 1);
+	if (rc < 0)
+		return -EIO;
+	rc = wf_fcu_read_reg(pv, 0, &buf, 1);
+	if (rc < 0)
+		return -EIO;
+	pv->rpm_shift = (buf == 1) ? 2 : 3;
+
+	pr_debug("wf_fcu: FCU Initialized, RPM fan shift is %d\n",
+		 pv->rpm_shift);
+
+	return 0;
+}
+
+static int __devinit wf_fcu_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	struct wf_fcu_priv *pv;
+
+	pv = kzalloc(sizeof(*pv), GFP_KERNEL);
+	if (!pv)
+		return -ENOMEM;
+
+	kref_init(&pv->ref);
+	mutex_init(&pv->lock);
+	INIT_LIST_HEAD(&pv->fan_list);
+	pv->i2c = client;
+
+	/*
+	 * First we must start the FCU which will query the
+	 * shift value to apply to RPMs
+	 */
+	if (wf_fcu_init_chip(pv)) {
+		pr_err("wf_fcu: Initialization failed !\n");
+		kfree(pv);
+		return -ENXIO;
+	}
+
+	/* First lookup fans in the device-tree */
+	wf_fcu_lookup_fans(pv);
+
+	/*
+	 * Older machines don't have the device-tree entries
+	 * we are looking for, just hard code the list
+	 */
+	if (list_empty(&pv->fan_list))
+		wf_fcu_default_fans(pv);
+
+	/* Still no fans ? FAIL */
+	if (list_empty(&pv->fan_list)) {
+		pr_err("wf_fcu: Failed to find fans for your machine\n");
+		kfree(pv);
+		return -ENODEV;
+	}
+
+	dev_set_drvdata(&client->dev, pv);
+
+	return 0;
+}
+
+static int __devexit wf_fcu_remove(struct i2c_client *client)
+{
+	struct wf_fcu_priv *pv = dev_get_drvdata(&client->dev);
+	struct wf_fcu_fan *fan;
+
+	while (!list_empty(&pv->fan_list)) {
+		fan = list_first_entry(&pv->fan_list, struct wf_fcu_fan, link);
+		list_del(&fan->link);
+		wf_unregister_control(&fan->ctrl);
+	}
+	kref_put(&pv->ref, wf_fcu_release);
+	return 0;
+}
+
+static const struct i2c_device_id wf_fcu_id[] = {
+	{ "MAC,fcu", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wf_fcu_id);
+
+static struct i2c_driver wf_fcu_driver = {
+	.driver = {
+		.name	= "wf_fcu",
+	},
+	.probe		= wf_fcu_probe,
+	.remove		= wf_fcu_remove,
+	.id_table	= wf_fcu_id,
+};
+
+static int __init wf_fcu_init(void)
+{
+	return i2c_add_driver(&wf_fcu_driver);
+}
+
+static void __exit wf_fcu_exit(void)
+{
+	i2c_del_driver(&wf_fcu_driver);
+}
+
+
+module_init(wf_fcu_init);
+module_exit(wf_fcu_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 4d6a90a..b0c2d36 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -23,7 +23,7 @@
 
 #include "windfarm.h"
 
-#define VERSION "0.2"
+#define VERSION "1.0"
 
 #undef DEBUG
 
@@ -36,8 +36,8 @@
 struct wf_lm75_sensor {
 	int			ds1775 : 1;
 	int			inited : 1;
-	struct 	i2c_client	*i2c;
-	struct 	wf_sensor	sens;
+	struct i2c_client	*i2c;
+	struct wf_sensor	sens;
 };
 #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
 
@@ -90,40 +90,19 @@
 
 static int wf_lm75_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
-{
+{	
 	struct wf_lm75_sensor *lm;
-	int rc;
-
-	lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
-	if (lm == NULL)
-		return -ENODEV;
-
-	lm->inited = 0;
-	lm->ds1775 = id->driver_data;
-	lm->i2c = client;
-	lm->sens.name = client->dev.platform_data;
-	lm->sens.ops = &wf_lm75_ops;
-	i2c_set_clientdata(client, lm);
-
-	rc = wf_register_sensor(&lm->sens);
-	if (rc)
-		kfree(lm);
-
-	return rc;
-}
-
-static struct i2c_driver wf_lm75_driver;
-
-static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
-					     u8 addr, int ds1775,
-					     const char *loc)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-	char *name;
+	int rc, ds1775 = id->driver_data;
+	const char *name, *loc;
 
 	DBG("wf_lm75: creating  %s device at address 0x%02x\n",
-	    ds1775 ? "ds1775" : "lm75", addr);
+	    ds1775 ? "ds1775" : "lm75", client->addr);
+
+	loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+	if (!loc) {
+		dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+		return -ENXIO;
+	}
 
 	/* Usual rant about sensor names not beeing very consistent in
 	 * the device-tree, oh well ...
@@ -137,68 +116,31 @@
 		name = "optical-drive-temp";
 	else if (!strcmp(loc, "HD Temp"))
 		name = "hard-drive-temp";
+	else if (!strcmp(loc, "PCI SLOTS"))
+		name = "slots-temp";
+	else if (!strcmp(loc, "CPU A INLET"))
+		name = "cpu-inlet-temp-0";
+	else if (!strcmp(loc, "CPU B INLET"))
+		name = "cpu-inlet-temp-1";
 	else
-		goto fail;
+		return -ENXIO;
+ 	
 
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = (addr >> 1) & 0x7f;
-	info.platform_data = name;
-	strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE);
-
-	client = i2c_new_device(adapter, &info);
-	if (client == NULL) {
-		printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n",
-		       ds1775 ? "ds1775" : "lm75", name);
-		goto fail;
-	}
-
-	/*
-	 * Let i2c-core delete that device on driver removal.
-	 * This is safe because i2c-core holds the core_lock mutex for us.
-	 */
-	list_add_tail(&client->detected, &wf_lm75_driver.clients);
-	return client;
- fail:
-	return NULL;
-}
-
-static int wf_lm75_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev;
-	struct pmac_i2c_bus *bus;
-
-	DBG("wf_lm75: adapter %s detected\n", adapter->name);
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
+	lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+	if (lm == NULL)
 		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
 
-	DBG("wf_lm75: bus found, looking for device...\n");
+	lm->inited = 0;
+	lm->ds1775 = ds1775;
+	lm->i2c = client;
+	lm->sens.name = (char *)name; /* XXX fix constness in structure */
+	lm->sens.ops = &wf_lm75_ops;
+	i2c_set_clientdata(client, lm);
 
-	/* Now look for lm75(s) in there */
-	for (dev = NULL;
-	     (dev = of_get_next_child(busnode, dev)) != NULL;) {
-		const char *loc =
-			of_get_property(dev, "hwsensor-location", NULL);
-		u8 addr;
-
-		/* We must re-match the adapter in order to properly check
-		 * the channel on multibus setups
-		 */
-		if (!pmac_i2c_match_adapter(dev, adapter))
-			continue;
-		addr = pmac_i2c_get_dev_addr(dev);
-		if (loc == NULL || addr == 0)
-			continue;
-		/* real lm75 */
-		if (of_device_is_compatible(dev, "lm75"))
-			wf_lm75_create(adapter, addr, 0, loc);
-		/* ds1775 (compatible, better resolution */
-		else if (of_device_is_compatible(dev, "ds1775"))
-			wf_lm75_create(adapter, addr, 1, loc);
-	}
-	return 0;
+	rc = wf_register_sensor(&lm->sens);
+	if (rc)
+		kfree(lm);
+	return rc;
 }
 
 static int wf_lm75_remove(struct i2c_client *client)
@@ -217,16 +159,16 @@
 }
 
 static const struct i2c_device_id wf_lm75_id[] = {
-	{ "wf_lm75", 0 },
-	{ "wf_ds1775", 1 },
+	{ "MAC,lm75", 0 },
+	{ "MAC,ds1775", 1 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c, wf_lm75_id);
 
 static struct i2c_driver wf_lm75_driver = {
 	.driver = {
 		.name	= "wf_lm75",
 	},
-	.attach_adapter	= wf_lm75_attach,
 	.probe		= wf_lm75_probe,
 	.remove		= wf_lm75_remove,
 	.id_table	= wf_lm75_id,
@@ -234,11 +176,6 @@
 
 static int __init wf_lm75_sensor_init(void)
 {
-	/* Don't register on old machines that use therm_pm72 for now */
-	if (of_machine_is_compatible("PowerMac7,2") ||
-	    of_machine_is_compatible("PowerMac7,3") ||
-	    of_machine_is_compatible("RackMac3,1"))
-		return -ENODEV;
 	return i2c_add_driver(&wf_lm75_driver);
 }
 
diff --git a/drivers/macintosh/windfarm_lm87_sensor.c b/drivers/macintosh/windfarm_lm87_sensor.c
new file mode 100644
index 0000000..c071aab
--- /dev/null
+++ b/drivers/macintosh/windfarm_lm87_sensor.c
@@ -0,0 +1,201 @@
+/*
+ * Windfarm PowerMac thermal control. LM87 sensor
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <asm/pmac_low_i2c.h>
+
+#include "windfarm.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)	printk(args)
+#else
+#define DBG(args...)	do { } while(0)
+#endif
+
+struct wf_lm87_sensor {
+	struct i2c_client	*i2c;
+	struct wf_sensor	sens;
+};
+#define wf_to_lm87(c) container_of(c, struct wf_lm87_sensor, sens)
+
+
+static int wf_lm87_read_reg(struct i2c_client *chip, int reg)
+{
+	int rc, tries = 0;
+	u8 buf;
+
+	for (;;) {
+		/* Set address */
+		buf = (u8)reg;
+		rc = i2c_master_send(chip, &buf, 1);
+		if (rc <= 0)
+			goto error;
+		rc = i2c_master_recv(chip, &buf, 1);
+		if (rc <= 0)
+			goto error;
+		return (int)buf;
+	error:
+		DBG("wf_lm87: Error reading LM87, retrying...\n");
+		if (++tries > 10) {
+			printk(KERN_ERR "wf_lm87: Error reading LM87 !\n");
+			return -EIO;
+		}
+		msleep(10);
+	}
+}
+
+static int wf_lm87_get(struct wf_sensor *sr, s32 *value)
+{
+	struct wf_lm87_sensor *lm = sr->priv;
+	s32 temp;
+
+	if (lm->i2c == NULL)
+		return -ENODEV;
+
+#define LM87_INT_TEMP		0x27
+
+	/* Read temperature register */
+	temp = wf_lm87_read_reg(lm->i2c, LM87_INT_TEMP);
+	if (temp < 0)
+		return temp;
+	*value = temp << 16;
+
+	return 0;
+}
+
+static void wf_lm87_release(struct wf_sensor *sr)
+{
+	struct wf_lm87_sensor *lm = wf_to_lm87(sr);
+
+	kfree(lm);
+}
+
+static struct wf_sensor_ops wf_lm87_ops = {
+	.get_value	= wf_lm87_get,
+	.release	= wf_lm87_release,
+	.owner		= THIS_MODULE,
+};
+
+static int wf_lm87_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{	
+	struct wf_lm87_sensor *lm;
+	const char *name = NULL, *loc;
+	struct device_node *np = NULL;
+	int rc;
+
+	/*
+	 * The lm87 contains a whole pile of sensors, additionally,
+	 * the Xserve G5 has several lm87's. However, for now we only
+	 * care about the internal temperature sensor
+	 */
+	while ((np = of_get_next_child(client->dev.of_node, np)) != NULL) {
+		if (strcmp(np->name, "int-temp"))
+			continue;
+		loc = of_get_property(np, "location", NULL);
+		if (!loc)
+			continue;
+		if (strstr(loc, "DIMM"))
+			name = "dimms-temp";
+		else if (strstr(loc, "Processors"))
+			name = "between-cpus-temp";
+		if (name) {
+			of_node_put(np);
+			break;
+		}
+	}
+	if (!name) {
+		pr_warning("wf_lm87: Unsupported sensor %s\n",
+			   client->dev.of_node->full_name);
+		return -ENODEV;
+	}
+
+	lm = kzalloc(sizeof(struct wf_lm87_sensor), GFP_KERNEL);
+	if (lm == NULL)
+		return -ENODEV;
+
+	lm->i2c = client;
+	lm->sens.name = name;
+	lm->sens.ops = &wf_lm87_ops;
+	lm->sens.priv = lm;
+	i2c_set_clientdata(client, lm);
+
+	rc = wf_register_sensor(&lm->sens);
+	if (rc)
+		kfree(lm);
+	return rc;
+}
+
+static int wf_lm87_remove(struct i2c_client *client)
+{
+	struct wf_lm87_sensor *lm = i2c_get_clientdata(client);
+
+	DBG("wf_lm87: i2c detatch called for %s\n", lm->sens.name);
+
+	/* Mark client detached */
+	lm->i2c = NULL;
+
+	/* release sensor */
+	wf_unregister_sensor(&lm->sens);
+
+	return 0;
+}
+
+static const struct i2c_device_id wf_lm87_id[] = {
+	{ "MAC,lm87cimt", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wf_lm87_id);
+
+static struct i2c_driver wf_lm87_driver = {
+	.driver = {
+		.name	= "wf_lm87",
+	},
+	.probe		= wf_lm87_probe,
+	.remove		= wf_lm87_remove,
+	.id_table	= wf_lm87_id,
+};
+
+static int __init wf_lm87_sensor_init(void)
+{
+	/* We only support this on the Xserve */
+	if (!of_machine_is_compatible("RackMac3,1"))
+		return -ENODEV;
+
+	return i2c_add_driver(&wf_lm87_driver);
+}
+
+static void __exit wf_lm87_sensor_exit(void)
+{
+	i2c_del_driver(&wf_lm87_driver);
+}
+
+
+module_init(wf_lm87_sensor_init);
+module_exit(wf_lm87_sensor_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("LM87 sensor objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index 8204113..371b058 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -16,7 +16,7 @@
 
 #include "windfarm.h"
 
-#define VERSION "0.2"
+#define VERSION "1.0"
 
 /* This currently only exports the external temperature sensor,
    since that's all the control loops need. */
@@ -64,9 +64,29 @@
 static int wf_max6690_probe(struct i2c_client *client,
 			    const struct i2c_device_id *id)
 {
+	const char *name, *loc;
 	struct wf_6690_sensor *max;
 	int rc;
 
+	loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+	if (!loc) {
+		dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * We only expose the external temperature register for
+	 * now as this is all we need for our control loops
+	 */
+	if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT"))
+		name = "backside-temp";
+	else if (!strcmp(loc, "NB Ambient"))
+		name = "north-bridge-temp";
+	else if (!strcmp(loc, "GPU Ambient"))
+		name = "gpu-temp";
+	else
+		return -ENXIO;
+
 	max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
 	if (max == NULL) {
 		printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: "
@@ -75,90 +95,16 @@
 	}
 
 	max->i2c = client;
-	max->sens.name = client->dev.platform_data;
+	max->sens.name = (char *)name; /* XXX fix constness in structure */
 	max->sens.ops = &wf_max6690_ops;
 	i2c_set_clientdata(client, max);
 
 	rc = wf_register_sensor(&max->sens);
-	if (rc) {
+	if (rc)
 		kfree(max);
-	}
-
 	return rc;
 }
 
-static struct i2c_driver wf_max6690_driver;
-
-static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter,
-					    u8 addr, const char *loc)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-	char *name;
-
-	if (!strcmp(loc, "BACKSIDE"))
-		name = "backside-temp";
-	else if (!strcmp(loc, "NB Ambient"))
-		name = "north-bridge-temp";
-	else if (!strcmp(loc, "GPU Ambient"))
-		name = "gpu-temp";
-	else
-		goto fail;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = addr >> 1;
-	info.platform_data = name;
-	strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE);
-
-	client = i2c_new_device(adapter, &info);
-	if (client == NULL) {
-		printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n");
-		goto fail;
-	}
-
-	/*
-	 * Let i2c-core delete that device on driver removal.
-	 * This is safe because i2c-core holds the core_lock mutex for us.
-	 */
-	list_add_tail(&client->detected, &wf_max6690_driver.clients);
-	return client;
-
- fail:
-	return NULL;
-}
-
-static int wf_max6690_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-	const char *loc;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		u8 addr;
-
-		/* We must re-match the adapter in order to properly check
-		 * the channel on multibus setups
-		 */
-		if (!pmac_i2c_match_adapter(dev, adapter))
-			continue;
-		if (!of_device_is_compatible(dev, "max6690"))
-			continue;
-		addr = pmac_i2c_get_dev_addr(dev);
-		loc = of_get_property(dev, "hwsensor-location", NULL);
-		if (loc == NULL || addr == 0)
-			continue;
-		printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
-		wf_max6690_create(adapter, addr, loc);
-	}
-
-	return 0;
-}
-
 static int wf_max6690_remove(struct i2c_client *client)
 {
 	struct wf_6690_sensor *max = i2c_get_clientdata(client);
@@ -170,15 +116,15 @@
 }
 
 static const struct i2c_device_id wf_max6690_id[] = {
-	{ "wf_max6690", 0 },
+	{ "MAC,max6690", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c, wf_max6690_id);
 
 static struct i2c_driver wf_max6690_driver = {
 	.driver = {
 		.name		= "wf_max6690",
 	},
-	.attach_adapter	= wf_max6690_attach,
 	.probe		= wf_max6690_probe,
 	.remove		= wf_max6690_remove,
 	.id_table	= wf_max6690_id,
@@ -186,11 +132,6 @@
 
 static int __init wf_max6690_sensor_init(void)
 {
-	/* Don't register on old machines that use therm_pm72 for now */
-	if (of_machine_is_compatible("PowerMac7,2") ||
-	    of_machine_is_compatible("PowerMac7,3") ||
-	    of_machine_is_compatible("RackMac3,1"))
-		return -ENODEV;
 	return i2c_add_driver(&wf_max6690_driver);
 }
 
diff --git a/drivers/macintosh/windfarm_mpu.h b/drivers/macintosh/windfarm_mpu.h
new file mode 100644
index 0000000..046edc8
--- /dev/null
+++ b/drivers/macintosh/windfarm_mpu.h
@@ -0,0 +1,105 @@
+/*
+ * Windfarm PowerMac thermal control
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#ifndef __WINDFARM_MPU_H
+#define __WINDFARM_MPU_H
+
+typedef unsigned short fu16;
+typedef int fs32;
+typedef short fs16;
+
+/* Definition of the MPU data structure which contains per CPU
+ * calibration information (among others) for the G5 machines
+ */
+struct mpu_data
+{
+	u8	signature;		/* 0x00 - EEPROM sig. */
+	u8	bytes_used;		/* 0x01 - Bytes used in eeprom (160 ?) */
+	u8	size;			/* 0x02 - EEPROM size (256 ?) */
+	u8	version;		/* 0x03 - EEPROM version */
+	u32	data_revision;		/* 0x04 - Dataset revision */
+	u8	processor_bin_code[3];	/* 0x08 - Processor BIN code */
+	u8	bin_code_expansion;	/* 0x0b - ??? (padding ?) */
+	u8	processor_num;		/* 0x0c - Number of CPUs on this MPU */
+	u8	input_mul_bus_div;	/* 0x0d - Clock input multiplier/bus divider */
+	u8	reserved1[2];		/* 0x0e - */
+	u32	input_clk_freq_high;	/* 0x10 - Input clock frequency high */
+	u8	cpu_nb_target_cycles;	/* 0x14 - ??? */
+	u8	cpu_statlat;		/* 0x15 - ??? */
+	u8	cpu_snooplat;		/* 0x16 - ??? */
+	u8	cpu_snoopacc;		/* 0x17 - ??? */
+	u8	nb_paamwin;		/* 0x18 - ??? */
+	u8	nb_statlat;		/* 0x19 - ??? */
+	u8	nb_snooplat;		/* 0x1a - ??? */
+	u8	nb_snoopwin;		/* 0x1b - ??? */
+	u8	api_bus_mode;		/* 0x1c - ??? */
+	u8	reserved2[3];		/* 0x1d - */
+	u32	input_clk_freq_low;	/* 0x20 - Input clock frequency low */
+	u8	processor_card_slot;	/* 0x24 - Processor card slot number */
+	u8	reserved3[2];		/* 0x25 - */
+	u8	padjmax;       		/* 0x27 - Max power adjustment (Not in OF!) */
+	u8	ttarget;		/* 0x28 - Target temperature */
+	u8	tmax;			/* 0x29 - Max temperature */
+	u8	pmaxh;			/* 0x2a - Max power */
+	u8	tguardband;		/* 0x2b - Guardband temp ??? Hist. len in OSX */
+	fs32	pid_gp;			/* 0x2c - PID proportional gain */
+	fs32	pid_gr;			/* 0x30 - PID reset gain */
+	fs32	pid_gd;			/* 0x34 - PID derivative gain */
+	fu16	voph;			/* 0x38 - Vop High */
+	fu16	vopl;			/* 0x3a - Vop Low */
+	fs16	nactual_die;		/* 0x3c - nActual Die */
+	fs16	nactual_heatsink;	/* 0x3e - nActual Heatsink */
+	fs16	nactual_system;		/* 0x40 - nActual System */
+	u16	calibration_flags;	/* 0x42 - Calibration flags */
+	fu16	mdiode;			/* 0x44 - Diode M value (scaling factor) */
+	fs16	bdiode;			/* 0x46 - Diode B value (offset) */
+	fs32	theta_heat_sink;	/* 0x48 - Theta heat sink */
+	u16	rminn_intake_fan;	/* 0x4c - Intake fan min RPM */
+	u16	rmaxn_intake_fan;	/* 0x4e - Intake fan max RPM */
+	u16	rminn_exhaust_fan;	/* 0x50 - Exhaust fan min RPM */
+	u16	rmaxn_exhaust_fan;	/* 0x52 - Exhaust fan max RPM */
+	u8	processor_part_num[8];	/* 0x54 - Processor part number XX pumps min/max */
+	u32	processor_lot_num;	/* 0x5c - Processor lot number */
+	u8	orig_card_sernum[0x10];	/* 0x60 - Card original serial number */
+	u8	curr_card_sernum[0x10];	/* 0x70 - Card current serial number */
+	u8	mlb_sernum[0x18];	/* 0x80 - MLB serial number */
+	u32	checksum1;		/* 0x98 - */
+	u32	checksum2;		/* 0x9c - */	
+}; /* Total size = 0xa0 */
+
+static inline const struct mpu_data *wf_get_mpu(int cpu)
+{
+	struct device_node *np;
+	char nodename[64];
+	const void *data;
+	int len;
+
+	/*
+	 * prom.c routine for finding a node by path is a bit brain dead
+	 * and requires exact @xxx unit numbers. This is a bit ugly but
+	 * will work for these machines
+	 */
+	sprintf(nodename, "/u3@0,f8000000/i2c@f8001000/cpuid@a%d", cpu ? 2 : 0);
+	np = of_find_node_by_path(nodename);
+	if (!np)
+		return NULL;
+	data = of_get_property(np, "cpuid", &len);	
+	of_node_put(np);
+	if (!data)
+		return NULL;
+
+	/*
+	 * We are naughty, we have dropped the reference to the device
+	 * node and still return a pointer to the content. We know we
+	 * can do that though as this is only ever called on PowerMac
+	 * which cannot remove those nodes
+	 */
+	return data;
+}
+
+#endif /*  __WINDFARM_MPU_H */
diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c
new file mode 100644
index 0000000..84ac913
--- /dev/null
+++ b/drivers/macintosh/windfarm_pm72.c
@@ -0,0 +1,847 @@
+/*
+ * Windfarm PowerMac thermal control.
+ * Control loops for PowerMac7,2 and 7,3
+ *
+ * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Use and redistribute under the terms of the GNU GPL v2.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <asm/prom.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+#undef LOTSA_DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)	printk(args)
+#else
+#define DBG(args...)	do { } while(0)
+#endif
+
+#ifdef LOTSA_DEBUG
+#define DBG_LOTS(args...)	printk(args)
+#else
+#define DBG_LOTS(args...)	do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 60 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+/* We currently only handle 2 chips */
+#define NR_CHIPS	2
+#define NR_CPU_FANS	3 * NR_CHIPS
+
+/* Controls and sensors */
+static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
+static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
+static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
+static struct wf_sensor *backside_temp;
+static struct wf_sensor *drives_temp;
+
+static struct wf_control *cpu_front_fans[NR_CHIPS];
+static struct wf_control *cpu_rear_fans[NR_CHIPS];
+static struct wf_control *cpu_pumps[NR_CHIPS];
+static struct wf_control *backside_fan;
+static struct wf_control *drives_fan;
+static struct wf_control *slots_fan;
+static struct wf_control *cpufreq_clamp;
+
+/* We keep a temperature history for average calculation of 180s */
+#define CPU_TEMP_HIST_SIZE	180
+
+/* Fixed speed for slot fan */
+#define	SLOTS_FAN_DEFAULT_PWM	40
+
+/* Scale value for CPU intake fans */
+#define CPU_INTAKE_SCALE	0x0000f852
+
+/* PID loop state */
+static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
+static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
+static bool cpu_pid_combined;
+static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
+static int cpu_thist_pt;
+static s64 cpu_thist_total;
+static s32 cpu_all_tmax = 100 << 16;
+static struct wf_pid_state backside_pid;
+static int backside_tick;
+static struct wf_pid_state drives_pid;
+static int drives_tick;
+
+static int nr_chips;
+static bool have_all_controls;
+static bool have_all_sensors;
+static bool started;
+
+static int failure_state;
+#define FAILURE_SENSOR		1
+#define FAILURE_FAN		2
+#define FAILURE_PERM		4
+#define FAILURE_LOW_OVERTEMP	8
+#define FAILURE_HIGH_OVERTEMP	16
+
+/* Overtemp values */
+#define LOW_OVER_AVERAGE	0
+#define LOW_OVER_IMMEDIATE	(10 << 16)
+#define LOW_OVER_CLEAR		((-10) << 16)
+#define HIGH_OVER_IMMEDIATE	(14 << 16)
+#define HIGH_OVER_AVERAGE	(10 << 16)
+#define HIGH_OVER_IMMEDIATE	(14 << 16)
+
+
+static void cpu_max_all_fans(void)
+{
+	int i;
+
+	/* We max all CPU fans in case of a sensor error. We also do the
+	 * cpufreq clamping now, even if it's supposedly done later by the
+	 * generic code anyway, we do it earlier here to react faster
+	 */
+	if (cpufreq_clamp)
+		wf_control_set_max(cpufreq_clamp);
+	for (i = 0; i < nr_chips; i++) {
+		if (cpu_front_fans[i])
+			wf_control_set_max(cpu_front_fans[i]);
+		if (cpu_rear_fans[i])
+			wf_control_set_max(cpu_rear_fans[i]);
+		if (cpu_pumps[i])
+			wf_control_set_max(cpu_pumps[i]);
+	}
+}
+
+static int cpu_check_overtemp(s32 temp)
+{
+	int new_state = 0;
+	s32 t_avg, t_old;
+	static bool first = true;
+
+	/* First check for immediate overtemps */
+	if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
+		new_state |= FAILURE_LOW_OVERTEMP;
+		if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+			printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
+			       " temperature !\n");
+	}
+	if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
+		new_state |= FAILURE_HIGH_OVERTEMP;
+		if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+			printk(KERN_ERR "windfarm: Critical overtemp due to"
+			       " immediate CPU temperature !\n");
+	}
+
+	/*
+	 * The first time around, initialize the array with the first
+	 * temperature reading
+	 */
+	if (first) {
+		int i;
+
+		cpu_thist_total = 0;
+		for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
+			cpu_thist[i] = temp;
+			cpu_thist_total += temp;
+		}
+		first = false;
+	}
+
+	/*
+	 * We calculate a history of max temperatures and use that for the
+	 * overtemp management
+	 */
+	t_old = cpu_thist[cpu_thist_pt];
+	cpu_thist[cpu_thist_pt] = temp;
+	cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
+	cpu_thist_total -= t_old;
+	cpu_thist_total += temp;
+	t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
+
+	DBG_LOTS("  t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
+		 FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
+
+	/* Now check for average overtemps */
+	if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
+		new_state |= FAILURE_LOW_OVERTEMP;
+		if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+			printk(KERN_ERR "windfarm: Overtemp due to average CPU"
+			       " temperature !\n");
+	}
+	if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
+		new_state |= FAILURE_HIGH_OVERTEMP;
+		if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+			printk(KERN_ERR "windfarm: Critical overtemp due to"
+			       " average CPU temperature !\n");
+	}
+
+	/* Now handle overtemp conditions. We don't currently use the windfarm
+	 * overtemp handling core as it's not fully suited to the needs of those
+	 * new machine. This will be fixed later.
+	 */
+	if (new_state) {
+		/* High overtemp -> immediate shutdown */
+		if (new_state & FAILURE_HIGH_OVERTEMP)
+			machine_power_off();
+		if ((failure_state & new_state) != new_state)
+			cpu_max_all_fans();
+		failure_state |= new_state;
+	} else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
+		   (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
+		printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
+		failure_state &= ~FAILURE_LOW_OVERTEMP;
+	}
+
+	return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
+}
+
+static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
+{
+	s32 dtemp, volts, amps;
+	int rc;
+
+	/* Get diode temperature */
+	rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
+	if (rc) {
+		DBG("  CPU%d: temp reading error !\n", cpu);
+		return -EIO;
+	}
+	DBG_LOTS("  CPU%d: temp   = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
+	*temp = dtemp;
+
+	/* Get voltage */
+	rc = wf_sensor_get(sens_cpu_volts[cpu], &volts);
+	if (rc) {
+		DBG("  CPU%d, volts reading error !\n", cpu);
+		return -EIO;
+	}
+	DBG_LOTS("  CPU%d: volts  = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
+
+	/* Get current */
+	rc = wf_sensor_get(sens_cpu_amps[cpu], &amps);
+	if (rc) {
+		DBG("  CPU%d, current reading error !\n", cpu);
+		return -EIO;
+	}
+	DBG_LOTS("  CPU%d: amps   = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
+
+	/* Calculate power */
+
+	/* Scale voltage and current raw sensor values according to fixed scales
+	 * obtained in Darwin and calculate power from I and V
+	 */
+	*power = (((u64)volts) * ((u64)amps)) >> 16;
+
+	DBG_LOTS("  CPU%d: power  = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
+
+	return 0;
+
+}
+
+static void cpu_fans_tick_split(void)
+{
+	int err, cpu;
+	s32 intake, temp, power, t_max = 0;
+
+	DBG_LOTS("* cpu fans_tick_split()\n");
+
+	for (cpu = 0; cpu < nr_chips; ++cpu) {
+		struct wf_cpu_pid_state *sp = &cpu_pid[cpu];
+
+		/* Read current speed */
+		wf_control_get(cpu_rear_fans[cpu], &sp->target);
+
+		DBG_LOTS("  CPU%d: cur_target = %d RPM\n", cpu, sp->target);
+
+		err = read_one_cpu_vals(cpu, &temp, &power);
+		if (err) {
+			failure_state |= FAILURE_SENSOR;
+			cpu_max_all_fans();
+			return;
+		}
+
+		/* Keep track of highest temp */
+		t_max = max(t_max, temp);
+
+		/* Handle possible overtemps */
+		if (cpu_check_overtemp(t_max))
+			return;
+
+		/* Run PID */
+		wf_cpu_pid_run(sp, power, temp);
+
+		DBG_LOTS("  CPU%d: target = %d RPM\n", cpu, sp->target);
+
+		/* Apply result directly to exhaust fan */
+		err = wf_control_set(cpu_rear_fans[cpu], sp->target);
+		if (err) {
+			pr_warning("wf_pm72: Fan %s reports error %d\n",
+			       cpu_rear_fans[cpu]->name, err);
+			failure_state |= FAILURE_FAN;
+			break;
+		}
+
+		/* Scale result for intake fan */
+		intake = (sp->target * CPU_INTAKE_SCALE) >> 16;
+		DBG_LOTS("  CPU%d: intake = %d RPM\n", cpu, intake);
+		err = wf_control_set(cpu_front_fans[cpu], intake);
+		if (err) {
+			pr_warning("wf_pm72: Fan %s reports error %d\n",
+			       cpu_front_fans[cpu]->name, err);
+			failure_state |= FAILURE_FAN;
+			break;
+		}
+	}
+}
+
+static void cpu_fans_tick_combined(void)
+{
+	s32 temp0, power0, temp1, power1, t_max = 0;
+	s32 temp, power, intake, pump;
+	struct wf_control *pump0, *pump1;
+	struct wf_cpu_pid_state *sp = &cpu_pid[0];
+	int err, cpu;
+
+	DBG_LOTS("* cpu fans_tick_combined()\n");
+
+	/* Read current speed from cpu 0 */
+	wf_control_get(cpu_rear_fans[0], &sp->target);
+
+	DBG_LOTS("  CPUs: cur_target = %d RPM\n", sp->target);
+
+	/* Read values for both CPUs */
+	err = read_one_cpu_vals(0, &temp0, &power0);
+	if (err) {
+		failure_state |= FAILURE_SENSOR;
+		cpu_max_all_fans();
+		return;
+	}
+	err = read_one_cpu_vals(1, &temp1, &power1);
+	if (err) {
+		failure_state |= FAILURE_SENSOR;
+		cpu_max_all_fans();
+		return;
+	}
+
+	/* Keep track of highest temp */
+	t_max = max(t_max, max(temp0, temp1));
+
+	/* Handle possible overtemps */
+	if (cpu_check_overtemp(t_max))
+		return;
+
+	/* Use the max temp & power of both */
+	temp = max(temp0, temp1);
+	power = max(power0, power1);
+
+	/* Run PID */
+	wf_cpu_pid_run(sp, power, temp);
+
+	/* Scale result for intake fan */
+	intake = (sp->target * CPU_INTAKE_SCALE) >> 16;
+
+	/* Same deal with pump speed */
+	pump0 = cpu_pumps[0];
+	pump1 = cpu_pumps[1];
+	if (!pump0) {
+		pump0 = pump1;
+		pump1 = NULL;
+	}
+	pump = (sp->target * wf_control_get_max(pump0)) /
+		cpu_mpu_data[0]->rmaxn_exhaust_fan;
+
+	DBG_LOTS("  CPUs: target = %d RPM\n", sp->target);
+	DBG_LOTS("  CPUs: intake = %d RPM\n", intake);
+	DBG_LOTS("  CPUs: pump   = %d RPM\n", pump);
+
+	for (cpu = 0; cpu < nr_chips; cpu++) {
+		err = wf_control_set(cpu_rear_fans[cpu], sp->target);
+		if (err) {
+			pr_warning("wf_pm72: Fan %s reports error %d\n",
+				   cpu_rear_fans[cpu]->name, err);
+			failure_state |= FAILURE_FAN;
+		}
+		err = wf_control_set(cpu_front_fans[cpu], intake);
+		if (err) {
+			pr_warning("wf_pm72: Fan %s reports error %d\n",
+				   cpu_front_fans[cpu]->name, err);
+			failure_state |= FAILURE_FAN;
+		}
+		err = 0;
+		if (cpu_pumps[cpu])
+			err = wf_control_set(cpu_pumps[cpu], pump);
+		if (err) {
+			pr_warning("wf_pm72: Pump %s reports error %d\n",
+				   cpu_pumps[cpu]->name, err);
+			failure_state |= FAILURE_FAN;
+		}
+	}
+}
+
+/* Implementation... */
+static int cpu_setup_pid(int cpu)
+{
+	struct wf_cpu_pid_param pid;
+	const struct mpu_data *mpu = cpu_mpu_data[cpu];
+	s32 tmax, ttarget, ptarget;
+	int fmin, fmax, hsize;
+
+	/* Get PID params from the appropriate MPU EEPROM */
+	tmax = mpu->tmax << 16;
+	ttarget = mpu->ttarget << 16;
+	ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;
+
+	DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
+	    cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));
+
+	/* We keep a global tmax for overtemp calculations */
+	if (tmax < cpu_all_tmax)
+		cpu_all_tmax = tmax;
+
+	/* Set PID min/max by using the rear fan min/max */
+	fmin = wf_control_get_min(cpu_rear_fans[cpu]);
+	fmax = wf_control_get_max(cpu_rear_fans[cpu]);
+	DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
+
+	/* History size */
+	hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
+	DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
+
+	/* Initialize PID loop */
+	pid.interval	= 1;	/* seconds */
+	pid.history_len = hsize;
+	pid.gd		= mpu->pid_gd;
+	pid.gp		= mpu->pid_gp;
+	pid.gr		= mpu->pid_gr;
+	pid.tmax	= tmax;
+	pid.ttarget	= ttarget;
+	pid.pmaxadj	= ptarget;
+	pid.min		= fmin;
+	pid.max		= fmax;
+
+	wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+	cpu_pid[cpu].target = 1000;
+
+	return 0;
+}
+
+/* Backside/U3 fan */
+static struct wf_pid_param backside_u3_param = {
+	.interval	= 5,
+	.history_len	= 2,
+	.gd		= 40 << 20,
+	.gp		= 5 << 20,
+	.gr		= 0,
+	.itarget	= 65 << 16,
+	.additive	= 1,
+	.min		= 20,
+	.max		= 100,
+};
+
+static struct wf_pid_param backside_u3h_param = {
+	.interval	= 5,
+	.history_len	= 2,
+	.gd		= 20 << 20,
+	.gp		= 5 << 20,
+	.gr		= 0,
+	.itarget	= 75 << 16,
+	.additive	= 1,
+	.min		= 20,
+	.max		= 100,
+};
+
+static void backside_fan_tick(void)
+{
+	s32 temp;
+	int speed;
+	int err;
+
+	if (!backside_fan || !backside_temp || !backside_tick)
+		return;
+	if (--backside_tick > 0)
+		return;
+	backside_tick = backside_pid.param.interval;
+
+	DBG_LOTS("* backside fans tick\n");
+
+	/* Update fan speed from actual fans */
+	err = wf_control_get(backside_fan, &speed);
+	if (!err)
+		backside_pid.target = speed;
+
+	err = wf_sensor_get(backside_temp, &temp);
+	if (err) {
+		printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n",
+		       err);
+		failure_state |= FAILURE_SENSOR;
+		wf_control_set_max(backside_fan);
+		return;
+	}
+	speed = wf_pid_run(&backside_pid, temp);
+
+	DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
+		 FIX32TOPRINT(temp), speed);
+
+	err = wf_control_set(backside_fan, speed);
+	if (err) {
+		printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
+		failure_state |= FAILURE_FAN;
+	}
+}
+
+static void backside_setup_pid(void)
+{
+	/* first time initialize things */
+	s32 fmin = wf_control_get_min(backside_fan);
+	s32 fmax = wf_control_get_max(backside_fan);
+	struct wf_pid_param param;
+	struct device_node *u3;
+	int u3h = 1; /* conservative by default */
+
+	u3 = of_find_node_by_path("/u3@0,f8000000");
+	if (u3 != NULL) {
+		const u32 *vers = of_get_property(u3, "device-rev", NULL);
+		if (vers)
+			if (((*vers) & 0x3f) < 0x34)
+				u3h = 0;
+		of_node_put(u3);
+	}
+
+	param = u3h ? backside_u3h_param : backside_u3_param;
+
+	param.min = max(param.min, fmin);
+	param.max = min(param.max, fmax);
+	wf_pid_init(&backside_pid, &param);
+	backside_tick = 1;
+
+	pr_info("wf_pm72: Backside control loop started.\n");
+}
+
+/* Drive bay fan */
+static const struct wf_pid_param drives_param = {
+	.interval	= 5,
+	.history_len	= 2,
+	.gd		= 30 << 20,
+	.gp		= 5 << 20,
+	.gr		= 0,
+	.itarget	= 40 << 16,
+	.additive	= 1,
+	.min		= 300,
+	.max		= 4000,
+};
+
+static void drives_fan_tick(void)
+{
+	s32 temp;
+	int speed;
+	int err;
+
+	if (!drives_fan || !drives_temp || !drives_tick)
+		return;
+	if (--drives_tick > 0)
+		return;
+	drives_tick = drives_pid.param.interval;
+
+	DBG_LOTS("* drives fans tick\n");
+
+	/* Update fan speed from actual fans */
+	err = wf_control_get(drives_fan, &speed);
+	if (!err)
+		drives_pid.target = speed;
+
+	err = wf_sensor_get(drives_temp, &temp);
+	if (err) {
+		pr_warning("wf_pm72: drive bay temp sensor error %d\n", err);
+		failure_state |= FAILURE_SENSOR;
+		wf_control_set_max(drives_fan);
+		return;
+	}
+	speed = wf_pid_run(&drives_pid, temp);
+
+	DBG_LOTS("drives PID temp=%d.%.3d speed=%d\n",
+		 FIX32TOPRINT(temp), speed);
+
+	err = wf_control_set(drives_fan, speed);
+	if (err) {
+		printk(KERN_WARNING "windfarm: drive bay fan error %d\n", err);
+		failure_state |= FAILURE_FAN;
+	}
+}
+
+static void drives_setup_pid(void)
+{
+	/* first time initialize things */
+	s32 fmin = wf_control_get_min(drives_fan);
+	s32 fmax = wf_control_get_max(drives_fan);
+	struct wf_pid_param param = drives_param;
+
+	param.min = max(param.min, fmin);
+	param.max = min(param.max, fmax);
+	wf_pid_init(&drives_pid, &param);
+	drives_tick = 1;
+
+	pr_info("wf_pm72: Drive bay control loop started.\n");
+}
+
+static void set_fail_state(void)
+{
+	cpu_max_all_fans();
+
+	if (backside_fan)
+		wf_control_set_max(backside_fan);
+	if (slots_fan)
+		wf_control_set_max(slots_fan);
+	if (drives_fan)
+		wf_control_set_max(drives_fan);
+}
+
+static void pm72_tick(void)
+{
+	int i, last_failure;
+
+	if (!started) {
+		started = 1;
+		printk(KERN_INFO "windfarm: CPUs control loops started.\n");
+		for (i = 0; i < nr_chips; ++i) {
+			if (cpu_setup_pid(i) < 0) {
+				failure_state = FAILURE_PERM;
+				set_fail_state();
+				break;
+			}
+		}
+		DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
+
+		backside_setup_pid();
+		drives_setup_pid();
+
+		/*
+		 * We don't have the right stuff to drive the PCI fan
+		 * so we fix it to a default value
+		 */
+		wf_control_set(slots_fan, SLOTS_FAN_DEFAULT_PWM);
+
+#ifdef HACKED_OVERTEMP
+		cpu_all_tmax = 60 << 16;
+#endif
+	}
+
+	/* Permanent failure, bail out */
+	if (failure_state & FAILURE_PERM)
+		return;
+
+	/*
+	 * Clear all failure bits except low overtemp which will be eventually
+	 * cleared by the control loop itself
+	 */
+	last_failure = failure_state;
+	failure_state &= FAILURE_LOW_OVERTEMP;
+	if (cpu_pid_combined)
+		cpu_fans_tick_combined();
+	else
+		cpu_fans_tick_split();
+	backside_fan_tick();
+	drives_fan_tick();
+
+	DBG_LOTS("  last_failure: 0x%x, failure_state: %x\n",
+		 last_failure, failure_state);
+
+	/* Check for failures. Any failure causes cpufreq clamping */
+	if (failure_state && last_failure == 0 && cpufreq_clamp)
+		wf_control_set_max(cpufreq_clamp);
+	if (failure_state == 0 && last_failure && cpufreq_clamp)
+		wf_control_set_min(cpufreq_clamp);
+
+	/* That's it for now, we might want to deal with other failures
+	 * differently in the future though
+	 */
+}
+
+static void pm72_new_control(struct wf_control *ct)
+{
+	bool all_controls;
+	bool had_pump = cpu_pumps[0] || cpu_pumps[1];
+
+	if (!strcmp(ct->name, "cpu-front-fan-0"))
+		cpu_front_fans[0] = ct;
+	else if (!strcmp(ct->name, "cpu-front-fan-1"))
+		cpu_front_fans[1] = ct;
+	else if (!strcmp(ct->name, "cpu-rear-fan-0"))
+		cpu_rear_fans[0] = ct;
+	else if (!strcmp(ct->name, "cpu-rear-fan-1"))
+		cpu_rear_fans[1] = ct;
+	else if (!strcmp(ct->name, "cpu-pump-0"))
+		cpu_pumps[0] = ct;
+	else if (!strcmp(ct->name, "cpu-pump-1"))
+		cpu_pumps[1] = ct;
+	else if (!strcmp(ct->name, "backside-fan"))
+		backside_fan = ct;
+	else if (!strcmp(ct->name, "slots-fan"))
+		slots_fan = ct;
+	else if (!strcmp(ct->name, "drive-bay-fan"))
+		drives_fan = ct;
+	else if (!strcmp(ct->name, "cpufreq-clamp"))
+		cpufreq_clamp = ct;
+
+	all_controls =
+		cpu_front_fans[0] &&
+		cpu_rear_fans[0] &&
+		backside_fan &&
+		slots_fan &&
+		drives_fan;
+	if (nr_chips > 1)
+		all_controls &=
+			cpu_front_fans[1] &&
+			cpu_rear_fans[1];
+	have_all_controls = all_controls;
+
+	if ((cpu_pumps[0] || cpu_pumps[1]) && !had_pump) {
+		pr_info("wf_pm72: Liquid cooling pump(s) detected,"
+			" using new algorithm !\n");
+		cpu_pid_combined = true;
+	}
+}
+
+
+static void pm72_new_sensor(struct wf_sensor *sr)
+{
+	bool all_sensors;
+
+	if (!strcmp(sr->name, "cpu-diode-temp-0"))
+		sens_cpu_temp[0] = sr;
+	else if (!strcmp(sr->name, "cpu-diode-temp-1"))
+		sens_cpu_temp[1] = sr;
+	else if (!strcmp(sr->name, "cpu-voltage-0"))
+		sens_cpu_volts[0] = sr;
+	else if (!strcmp(sr->name, "cpu-voltage-1"))
+		sens_cpu_volts[1] = sr;
+	else if (!strcmp(sr->name, "cpu-current-0"))
+		sens_cpu_amps[0] = sr;
+	else if (!strcmp(sr->name, "cpu-current-1"))
+		sens_cpu_amps[1] = sr;
+	else if (!strcmp(sr->name, "backside-temp"))
+		backside_temp = sr;
+	else if (!strcmp(sr->name, "hd-temp"))
+		drives_temp = sr;
+
+	all_sensors =
+		sens_cpu_temp[0] &&
+		sens_cpu_volts[0] &&
+		sens_cpu_amps[0] &&
+		backside_temp &&
+		drives_temp;
+	if (nr_chips > 1)
+		all_sensors &=
+			sens_cpu_temp[1] &&
+			sens_cpu_volts[1] &&
+			sens_cpu_amps[1];
+
+	have_all_sensors = all_sensors;
+}
+
+static int pm72_wf_notify(struct notifier_block *self,
+			  unsigned long event, void *data)
+{
+	switch (event) {
+	case WF_EVENT_NEW_SENSOR:
+		pm72_new_sensor(data);
+		break;
+	case WF_EVENT_NEW_CONTROL:
+		pm72_new_control(data);
+		break;
+	case WF_EVENT_TICK:
+		if (have_all_controls && have_all_sensors)
+			pm72_tick();
+	}
+	return 0;
+}
+
+static struct notifier_block pm72_events = {
+	.notifier_call = pm72_wf_notify,
+};
+
+static int wf_pm72_probe(struct platform_device *dev)
+{
+	wf_register_client(&pm72_events);
+	return 0;
+}
+
+static int __devexit wf_pm72_remove(struct platform_device *dev)
+{
+	wf_unregister_client(&pm72_events);
+
+	/* should release all sensors and controls */
+	return 0;
+}
+
+static struct platform_driver wf_pm72_driver = {
+	.probe	= wf_pm72_probe,
+	.remove	= wf_pm72_remove,
+	.driver	= {
+		.name = "windfarm",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init wf_pm72_init(void)
+{
+	struct device_node *cpu;
+	int i;
+
+	if (!of_machine_is_compatible("PowerMac7,2") &&
+	    !of_machine_is_compatible("PowerMac7,3"))
+		return -ENODEV;
+
+	/* Count the number of CPU cores */
+	nr_chips = 0;
+	for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+		++nr_chips;
+	if (nr_chips > NR_CHIPS)
+		nr_chips = NR_CHIPS;
+
+	pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
+		nr_chips);
+
+	/* Get MPU data for each CPU */
+	for (i = 0; i < nr_chips; i++) {
+		cpu_mpu_data[i] = wf_get_mpu(i);
+		if (!cpu_mpu_data[i]) {
+			pr_err("wf_pm72: Failed to find MPU data for CPU %d\n", i);
+			return -ENXIO;
+		}
+	}
+
+#ifdef MODULE
+	request_module("windfarm_fcu_controls");
+	request_module("windfarm_lm75_sensor");
+	request_module("windfarm_ad7417_sensor");
+	request_module("windfarm_max6690_sensor");
+	request_module("windfarm_cpufreq_clamp");
+#endif /* MODULE */
+
+	platform_driver_register(&wf_pm72_driver);
+	return 0;
+}
+
+static void __exit wf_pm72_exit(void)
+{
+	platform_driver_unregister(&wf_pm72_driver);
+}
+
+module_init(wf_pm72_init);
+module_exit(wf_pm72_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control for AGP PowerMac G5s");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index fc13d0f..990c876 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -302,13 +302,13 @@
 	pid_param.interval = WF_SMU_SYS_FANS_INTERVAL;
 	pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE;
 	pid_param.itarget = param->itarget;
-	pid_param.min = fan_system->ops->get_min(fan_system);
-	pid_param.max = fan_system->ops->get_max(fan_system);
+	pid_param.min = wf_control_get_min(fan_system);
+	pid_param.max = wf_control_get_max(fan_system);
 	if (fan_hd) {
 		pid_param.min =
-			max(pid_param.min,fan_hd->ops->get_min(fan_hd));
+			max(pid_param.min, wf_control_get_min(fan_hd));
 		pid_param.max =
-			min(pid_param.max,fan_hd->ops->get_max(fan_hd));
+			min(pid_param.max, wf_control_get_max(fan_hd));
 	}
 	wf_pid_init(&wf_smu_sys_fans->pid, &pid_param);
 
@@ -337,7 +337,7 @@
 	}
 	st->ticks = WF_SMU_SYS_FANS_INTERVAL;
 
-	rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+	rc = wf_sensor_get(sensor_hd_temp, &temp);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
 		       rc);
@@ -373,7 +373,7 @@
 	st->hd_setpoint = new_setpoint;
  readjust:
 	if (fan_system && wf_smu_failure_state == 0) {
-		rc = fan_system->ops->set_value(fan_system, st->sys_setpoint);
+		rc = wf_control_set(fan_system, st->sys_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: Sys fan error %d\n",
 			       rc);
@@ -381,7 +381,7 @@
 		}
 	}
 	if (fan_hd && wf_smu_failure_state == 0) {
-		rc = fan_hd->ops->set_value(fan_hd, st->hd_setpoint);
+		rc = wf_control_set(fan_hd, st->hd_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: HD fan error %d\n",
 			       rc);
@@ -447,8 +447,8 @@
 	pid_param.ttarget = tmax - tdelta;
 	pid_param.pmaxadj = maxpow - powadj;
 
-	pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
-	pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+	pid_param.min = wf_control_get_min(fan_cpu_main);
+	pid_param.max = wf_control_get_max(fan_cpu_main);
 
 	wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
 
@@ -481,7 +481,7 @@
 	}
 	st->ticks = WF_SMU_CPU_FANS_INTERVAL;
 
-	rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+	rc = wf_sensor_get(sensor_cpu_temp, &temp);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
 		       rc);
@@ -489,7 +489,7 @@
 		return;
 	}
 
-	rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+	rc = wf_sensor_get(sensor_cpu_power, &power);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
 		       rc);
@@ -525,8 +525,7 @@
 	st->cpu_setpoint = new_setpoint;
  readjust:
 	if (fan_cpu_main && wf_smu_failure_state == 0) {
-		rc = fan_cpu_main->ops->set_value(fan_cpu_main,
-						  st->cpu_setpoint);
+		rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: CPU main fan"
 			       " error %d\n", rc);
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index a9430ed..7653603 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -192,8 +192,8 @@
 	pid_param.ttarget = tmax - tdelta;
 	pid_param.pmaxadj = maxpow - powadj;
 
-	pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
-	pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+	pid_param.min = wf_control_get_min(fan_cpu_main);
+	pid_param.max = wf_control_get_max(fan_cpu_main);
 
 	wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
 
@@ -226,7 +226,7 @@
 	}
 	st->ticks = WF_SMU_CPU_FANS_INTERVAL;
 
-	rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+	rc = wf_sensor_get(sensor_cpu_temp, &temp);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
 		       rc);
@@ -234,7 +234,7 @@
 		return;
 	}
 
-	rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+	rc = wf_sensor_get(sensor_cpu_power, &power);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
 		       rc);
@@ -261,8 +261,7 @@
 	st->cpu_setpoint = new_setpoint;
  readjust:
 	if (fan_cpu_main && wf_smu_failure_state == 0) {
-		rc = fan_cpu_main->ops->set_value(fan_cpu_main,
-						  st->cpu_setpoint);
+		rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: CPU main fan"
 			       " error %d\n", rc);
@@ -270,8 +269,7 @@
 		}
 	}
 	if (fan_cpu_second && wf_smu_failure_state == 0) {
-		rc = fan_cpu_second->ops->set_value(fan_cpu_second,
-						    st->cpu_setpoint);
+		rc = wf_control_set(fan_cpu_second, st->cpu_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: CPU second fan"
 			       " error %d\n", rc);
@@ -279,8 +277,7 @@
 		}
 	}
 	if (fan_cpu_third && wf_smu_failure_state == 0) {
-		rc = fan_cpu_main->ops->set_value(fan_cpu_third,
-						  st->cpu_setpoint);
+		rc = wf_control_set(fan_cpu_third, st->cpu_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: CPU third fan"
 			       " error %d\n", rc);
@@ -312,8 +309,8 @@
 
 	/* Fill PID params */
 	param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN);
-	param.min = fan_hd->ops->get_min(fan_hd);
-	param.max = fan_hd->ops->get_max(fan_hd);
+	param.min = wf_control_get_min(fan_hd);
+	param.max = wf_control_get_max(fan_hd);
 	wf_pid_init(&wf_smu_drive_fans->pid, &param);
 
 	DBG("wf: Drive Fan control initialized.\n");
@@ -338,7 +335,7 @@
 	}
 	st->ticks = st->pid.param.interval;
 
-	rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+	rc = wf_sensor_get(sensor_hd_temp, &temp);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
 		       rc);
@@ -361,7 +358,7 @@
 	st->setpoint = new_setpoint;
  readjust:
 	if (fan_hd && wf_smu_failure_state == 0) {
-		rc = fan_hd->ops->set_value(fan_hd, st->setpoint);
+		rc = wf_control_set(fan_hd, st->setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: HD fan error %d\n",
 			       rc);
@@ -393,8 +390,8 @@
 
 	/* Fill PID params */
 	param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN);
-	param.min = fan_slots->ops->get_min(fan_slots);
-	param.max = fan_slots->ops->get_max(fan_slots);
+	param.min = wf_control_get_min(fan_slots);
+	param.max = wf_control_get_max(fan_slots);
 	wf_pid_init(&wf_smu_slots_fans->pid, &param);
 
 	DBG("wf: Slots Fan control initialized.\n");
@@ -419,7 +416,7 @@
 	}
 	st->ticks = st->pid.param.interval;
 
-	rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power);
+	rc = wf_sensor_get(sensor_slots_power, &power);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: Slots power sensor error %d\n",
 		       rc);
@@ -444,7 +441,7 @@
 	st->setpoint = new_setpoint;
  readjust:
 	if (fan_slots && wf_smu_failure_state == 0) {
-		rc = fan_slots->ops->set_value(fan_slots, st->setpoint);
+		rc = wf_control_set(fan_slots, st->setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: Slots fan error %d\n",
 			       rc);
diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c
new file mode 100644
index 0000000..3eca6d4
--- /dev/null
+++ b/drivers/macintosh/windfarm_rm31.c
@@ -0,0 +1,740 @@
+/*
+ * Windfarm PowerMac thermal control.
+ * Control loops for RackMack3,1 (Xserve G5)
+ *
+ * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Use and redistribute under the terms of the GNU GPL v2.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <asm/prom.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+#undef LOTSA_DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)	printk(args)
+#else
+#define DBG(args...)	do { } while(0)
+#endif
+
+#ifdef LOTSA_DEBUG
+#define DBG_LOTS(args...)	printk(args)
+#else
+#define DBG_LOTS(args...)	do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 60 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+/* We currently only handle 2 chips */
+#define NR_CHIPS	2
+#define NR_CPU_FANS	3 * NR_CHIPS
+
+/* Controls and sensors */
+static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
+static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
+static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
+static struct wf_sensor *backside_temp;
+static struct wf_sensor *slots_temp;
+static struct wf_sensor *dimms_temp;
+
+static struct wf_control *cpu_fans[NR_CHIPS][3];
+static struct wf_control *backside_fan;
+static struct wf_control *slots_fan;
+static struct wf_control *cpufreq_clamp;
+
+/* We keep a temperature history for average calculation of 180s */
+#define CPU_TEMP_HIST_SIZE	180
+
+/* PID loop state */
+static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
+static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
+static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
+static int cpu_thist_pt;
+static s64 cpu_thist_total;
+static s32 cpu_all_tmax = 100 << 16;
+static struct wf_pid_state backside_pid;
+static int backside_tick;
+static struct wf_pid_state slots_pid;
+static int slots_tick;
+static int slots_speed;
+static struct wf_pid_state dimms_pid;
+static int dimms_output_clamp;
+
+static int nr_chips;
+static bool have_all_controls;
+static bool have_all_sensors;
+static bool started;
+
+static int failure_state;
+#define FAILURE_SENSOR		1
+#define FAILURE_FAN		2
+#define FAILURE_PERM		4
+#define FAILURE_LOW_OVERTEMP	8
+#define FAILURE_HIGH_OVERTEMP	16
+
+/* Overtemp values */
+#define LOW_OVER_AVERAGE	0
+#define LOW_OVER_IMMEDIATE	(10 << 16)
+#define LOW_OVER_CLEAR		((-10) << 16)
+#define HIGH_OVER_IMMEDIATE	(14 << 16)
+#define HIGH_OVER_AVERAGE	(10 << 16)
+#define HIGH_OVER_IMMEDIATE	(14 << 16)
+
+
+static void cpu_max_all_fans(void)
+{
+	int i;
+
+	/* We max all CPU fans in case of a sensor error. We also do the
+	 * cpufreq clamping now, even if it's supposedly done later by the
+	 * generic code anyway, we do it earlier here to react faster
+	 */
+	if (cpufreq_clamp)
+		wf_control_set_max(cpufreq_clamp);
+	for (i = 0; i < nr_chips; i++) {
+		if (cpu_fans[i][0])
+			wf_control_set_max(cpu_fans[i][0]);
+		if (cpu_fans[i][1])
+			wf_control_set_max(cpu_fans[i][1]);
+		if (cpu_fans[i][2])
+			wf_control_set_max(cpu_fans[i][2]);
+	}
+}
+
+static int cpu_check_overtemp(s32 temp)
+{
+	int new_state = 0;
+	s32 t_avg, t_old;
+	static bool first = true;
+
+	/* First check for immediate overtemps */
+	if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
+		new_state |= FAILURE_LOW_OVERTEMP;
+		if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+			printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
+			       " temperature !\n");
+	}
+	if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
+		new_state |= FAILURE_HIGH_OVERTEMP;
+		if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+			printk(KERN_ERR "windfarm: Critical overtemp due to"
+			       " immediate CPU temperature !\n");
+	}
+
+	/*
+	 * The first time around, initialize the array with the first
+	 * temperature reading
+	 */
+	if (first) {
+		int i;
+
+		cpu_thist_total = 0;
+		for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
+			cpu_thist[i] = temp;
+			cpu_thist_total += temp;
+		}
+		first = false;
+	}
+
+	/*
+	 * We calculate a history of max temperatures and use that for the
+	 * overtemp management
+	 */
+	t_old = cpu_thist[cpu_thist_pt];
+	cpu_thist[cpu_thist_pt] = temp;
+	cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
+	cpu_thist_total -= t_old;
+	cpu_thist_total += temp;
+	t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
+
+	DBG_LOTS("  t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
+		 FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
+
+	/* Now check for average overtemps */
+	if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
+		new_state |= FAILURE_LOW_OVERTEMP;
+		if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+			printk(KERN_ERR "windfarm: Overtemp due to average CPU"
+			       " temperature !\n");
+	}
+	if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
+		new_state |= FAILURE_HIGH_OVERTEMP;
+		if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+			printk(KERN_ERR "windfarm: Critical overtemp due to"
+			       " average CPU temperature !\n");
+	}
+
+	/* Now handle overtemp conditions. We don't currently use the windfarm
+	 * overtemp handling core as it's not fully suited to the needs of those
+	 * new machine. This will be fixed later.
+	 */
+	if (new_state) {
+		/* High overtemp -> immediate shutdown */
+		if (new_state & FAILURE_HIGH_OVERTEMP)
+			machine_power_off();
+		if ((failure_state & new_state) != new_state)
+			cpu_max_all_fans();
+		failure_state |= new_state;
+	} else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
+		   (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
+		printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
+		failure_state &= ~FAILURE_LOW_OVERTEMP;
+	}
+
+	return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
+}
+
+static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
+{
+	s32 dtemp, volts, amps;
+	int rc;
+
+	/* Get diode temperature */
+	rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
+	if (rc) {
+		DBG("  CPU%d: temp reading error !\n", cpu);
+		return -EIO;
+	}
+	DBG_LOTS("  CPU%d: temp   = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
+	*temp = dtemp;
+
+	/* Get voltage */
+	rc = wf_sensor_get(sens_cpu_volts[cpu], &volts);
+	if (rc) {
+		DBG("  CPU%d, volts reading error !\n", cpu);
+		return -EIO;
+	}
+	DBG_LOTS("  CPU%d: volts  = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
+
+	/* Get current */
+	rc = wf_sensor_get(sens_cpu_amps[cpu], &amps);
+	if (rc) {
+		DBG("  CPU%d, current reading error !\n", cpu);
+		return -EIO;
+	}
+	DBG_LOTS("  CPU%d: amps   = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
+
+	/* Calculate power */
+
+	/* Scale voltage and current raw sensor values according to fixed scales
+	 * obtained in Darwin and calculate power from I and V
+	 */
+	*power = (((u64)volts) * ((u64)amps)) >> 16;
+
+	DBG_LOTS("  CPU%d: power  = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
+
+	return 0;
+
+}
+
+static void cpu_fans_tick(void)
+{
+	int err, cpu, i;
+	s32 speed, temp, power, t_max = 0;
+
+	DBG_LOTS("* cpu fans_tick_split()\n");
+
+	for (cpu = 0; cpu < nr_chips; ++cpu) {
+		struct wf_cpu_pid_state *sp = &cpu_pid[cpu];
+
+		/* Read current speed */
+		wf_control_get(cpu_fans[cpu][0], &sp->target);
+
+		err = read_one_cpu_vals(cpu, &temp, &power);
+		if (err) {
+			failure_state |= FAILURE_SENSOR;
+			cpu_max_all_fans();
+			return;
+		}
+
+		/* Keep track of highest temp */
+		t_max = max(t_max, temp);
+
+		/* Handle possible overtemps */
+		if (cpu_check_overtemp(t_max))
+			return;
+
+		/* Run PID */
+		wf_cpu_pid_run(sp, power, temp);
+
+		DBG_LOTS("  CPU%d: target = %d RPM\n", cpu, sp->target);
+
+		/* Apply DIMMs clamp */
+		speed = max(sp->target, dimms_output_clamp);
+
+		/* Apply result to all cpu fans */
+		for (i = 0; i < 3; i++) {
+			err = wf_control_set(cpu_fans[cpu][i], speed);
+			if (err) {
+				pr_warning("wf_rm31: Fan %s reports error %d\n",
+					   cpu_fans[cpu][i]->name, err);
+				failure_state |= FAILURE_FAN;
+			}
+		}
+	}
+}
+
+/* Implementation... */
+static int cpu_setup_pid(int cpu)
+{
+	struct wf_cpu_pid_param pid;
+	const struct mpu_data *mpu = cpu_mpu_data[cpu];
+	s32 tmax, ttarget, ptarget;
+	int fmin, fmax, hsize;
+
+	/* Get PID params from the appropriate MPU EEPROM */
+	tmax = mpu->tmax << 16;
+	ttarget = mpu->ttarget << 16;
+	ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;
+
+	DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
+	    cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));
+
+	/* We keep a global tmax for overtemp calculations */
+	if (tmax < cpu_all_tmax)
+		cpu_all_tmax = tmax;
+
+	/* Set PID min/max by using the rear fan min/max */
+	fmin = wf_control_get_min(cpu_fans[cpu][0]);
+	fmax = wf_control_get_max(cpu_fans[cpu][0]);
+	DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
+
+	/* History size */
+	hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
+	DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
+
+	/* Initialize PID loop */
+	pid.interval	= 1;	/* seconds */
+	pid.history_len = hsize;
+	pid.gd		= mpu->pid_gd;
+	pid.gp		= mpu->pid_gp;
+	pid.gr		= mpu->pid_gr;
+	pid.tmax	= tmax;
+	pid.ttarget	= ttarget;
+	pid.pmaxadj	= ptarget;
+	pid.min		= fmin;
+	pid.max		= fmax;
+
+	wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+	cpu_pid[cpu].target = 4000;
+	
+	return 0;
+}
+
+/* Backside/U3 fan */
+static struct wf_pid_param backside_param = {
+	.interval	= 1,
+	.history_len	= 2,
+	.gd		= 0x00500000,
+	.gp		= 0x0004cccc,
+	.gr		= 0,
+	.itarget	= 70 << 16,
+	.additive	= 0,
+	.min		= 20,
+	.max		= 100,
+};
+
+/* DIMMs temperature (clamp the backside fan) */
+static struct wf_pid_param dimms_param = {
+	.interval	= 1,
+	.history_len	= 20,
+	.gd		= 0,
+	.gp		= 0,
+	.gr		= 0x06553600,
+	.itarget	= 50 << 16,
+	.additive	= 0,
+	.min		= 4000,
+	.max		= 14000,
+};
+
+static void backside_fan_tick(void)
+{
+	s32 temp, dtemp;
+	int speed, dspeed, fan_min;
+	int err;
+
+	if (!backside_fan || !backside_temp || !dimms_temp || !backside_tick)
+		return;
+	if (--backside_tick > 0)
+		return;
+	backside_tick = backside_pid.param.interval;
+
+	DBG_LOTS("* backside fans tick\n");
+
+	/* Update fan speed from actual fans */
+	err = wf_control_get(backside_fan, &speed);
+	if (!err)
+		backside_pid.target = speed;
+
+	err = wf_sensor_get(backside_temp, &temp);
+	if (err) {
+		printk(KERN_WARNING "windfarm: U3 temp sensor error %d\n",
+		       err);
+		failure_state |= FAILURE_SENSOR;
+		wf_control_set_max(backside_fan);
+		return;
+	}
+	speed = wf_pid_run(&backside_pid, temp);
+
+	DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
+		 FIX32TOPRINT(temp), speed);
+
+	err = wf_sensor_get(dimms_temp, &dtemp);
+	if (err) {
+		printk(KERN_WARNING "windfarm: DIMMs temp sensor error %d\n",
+		       err);
+		failure_state |= FAILURE_SENSOR;
+		wf_control_set_max(backside_fan);
+		return;
+	}
+	dspeed = wf_pid_run(&dimms_pid, dtemp);
+	dimms_output_clamp = dspeed;
+
+	fan_min = (dspeed * 100) / 14000;
+	fan_min = max(fan_min, backside_param.min);
+	speed = max(speed, fan_min);
+
+	err = wf_control_set(backside_fan, speed);
+	if (err) {
+		printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
+		failure_state |= FAILURE_FAN;
+	}
+}
+
+static void backside_setup_pid(void)
+{
+	/* first time initialize things */
+	s32 fmin = wf_control_get_min(backside_fan);
+	s32 fmax = wf_control_get_max(backside_fan);
+	struct wf_pid_param param;
+
+	param = backside_param;
+	param.min = max(param.min, fmin);
+	param.max = min(param.max, fmax);
+	wf_pid_init(&backside_pid, &param);
+
+	param = dimms_param;
+	wf_pid_init(&dimms_pid, &param);
+
+	backside_tick = 1;
+
+	pr_info("wf_rm31: Backside control loop started.\n");
+}
+
+/* Slots fan */
+static const struct wf_pid_param slots_param = {
+	.interval	= 5,
+	.history_len	= 2,
+	.gd		= 30 << 20,
+	.gp		= 5 << 20,
+	.gr		= 0,
+	.itarget	= 40 << 16,
+	.additive	= 1,
+	.min		= 300,
+	.max		= 4000,
+};
+
+static void slots_fan_tick(void)
+{
+	s32 temp;
+	int speed;
+	int err;
+
+	if (!slots_fan || !slots_temp || !slots_tick)
+		return;
+	if (--slots_tick > 0)
+		return;
+	slots_tick = slots_pid.param.interval;
+
+	DBG_LOTS("* slots fans tick\n");
+
+	err = wf_sensor_get(slots_temp, &temp);
+	if (err) {
+		pr_warning("wf_rm31: slots temp sensor error %d\n", err);
+		failure_state |= FAILURE_SENSOR;
+		wf_control_set_max(slots_fan);
+		return;
+	}
+	speed = wf_pid_run(&slots_pid, temp);
+
+	DBG_LOTS("slots PID temp=%d.%.3d speed=%d\n",
+		 FIX32TOPRINT(temp), speed);
+
+	slots_speed = speed;
+	err = wf_control_set(slots_fan, speed);
+	if (err) {
+		printk(KERN_WARNING "windfarm: slots bay fan error %d\n", err);
+		failure_state |= FAILURE_FAN;
+	}
+}
+
+static void slots_setup_pid(void)
+{
+	/* first time initialize things */
+	s32 fmin = wf_control_get_min(slots_fan);
+	s32 fmax = wf_control_get_max(slots_fan);
+	struct wf_pid_param param = slots_param;
+
+	param.min = max(param.min, fmin);
+	param.max = min(param.max, fmax);
+	wf_pid_init(&slots_pid, &param);
+	slots_tick = 1;
+
+	pr_info("wf_rm31: Slots control loop started.\n");
+}
+
+static void set_fail_state(void)
+{
+	cpu_max_all_fans();
+
+	if (backside_fan)
+		wf_control_set_max(backside_fan);
+	if (slots_fan)
+		wf_control_set_max(slots_fan);
+}
+
+static void rm31_tick(void)
+{
+	int i, last_failure;
+
+	if (!started) {
+		started = 1;
+		printk(KERN_INFO "windfarm: CPUs control loops started.\n");
+		for (i = 0; i < nr_chips; ++i) {
+			if (cpu_setup_pid(i) < 0) {
+				failure_state = FAILURE_PERM;
+				set_fail_state();
+				break;
+			}
+		}
+		DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
+
+		backside_setup_pid();
+		slots_setup_pid();
+
+#ifdef HACKED_OVERTEMP
+		cpu_all_tmax = 60 << 16;
+#endif
+	}
+
+	/* Permanent failure, bail out */
+	if (failure_state & FAILURE_PERM)
+		return;
+
+	/*
+	 * Clear all failure bits except low overtemp which will be eventually
+	 * cleared by the control loop itself
+	 */
+	last_failure = failure_state;
+	failure_state &= FAILURE_LOW_OVERTEMP;
+	backside_fan_tick();
+	slots_fan_tick();
+
+	/* We do CPUs last because they can be clamped high by
+	 * DIMM temperature
+	 */
+	cpu_fans_tick();
+
+	DBG_LOTS("  last_failure: 0x%x, failure_state: %x\n",
+		 last_failure, failure_state);
+
+	/* Check for failures. Any failure causes cpufreq clamping */
+	if (failure_state && last_failure == 0 && cpufreq_clamp)
+		wf_control_set_max(cpufreq_clamp);
+	if (failure_state == 0 && last_failure && cpufreq_clamp)
+		wf_control_set_min(cpufreq_clamp);
+
+	/* That's it for now, we might want to deal with other failures
+	 * differently in the future though
+	 */
+}
+
+static void rm31_new_control(struct wf_control *ct)
+{
+	bool all_controls;
+
+	if (!strcmp(ct->name, "cpu-fan-a-0"))
+		cpu_fans[0][0] = ct;
+	else if (!strcmp(ct->name, "cpu-fan-b-0"))
+		cpu_fans[0][1] = ct;
+	else if (!strcmp(ct->name, "cpu-fan-c-0"))
+		cpu_fans[0][2] = ct;
+	else if (!strcmp(ct->name, "cpu-fan-a-1"))
+		cpu_fans[1][0] = ct;
+	else if (!strcmp(ct->name, "cpu-fan-b-1"))
+		cpu_fans[1][1] = ct;
+	else if (!strcmp(ct->name, "cpu-fan-c-1"))
+		cpu_fans[1][2] = ct;
+	else if (!strcmp(ct->name, "backside-fan"))
+		backside_fan = ct;
+	else if (!strcmp(ct->name, "slots-fan"))
+		slots_fan = ct;
+	else if (!strcmp(ct->name, "cpufreq-clamp"))
+		cpufreq_clamp = ct;
+
+	all_controls =
+		cpu_fans[0][0] &&
+		cpu_fans[0][1] &&
+		cpu_fans[0][2] &&
+		backside_fan &&
+		slots_fan;
+	if (nr_chips > 1)
+		all_controls &=
+			cpu_fans[1][0] &&
+			cpu_fans[1][1] &&
+			cpu_fans[1][2];
+	have_all_controls = all_controls;
+}
+
+
+static void rm31_new_sensor(struct wf_sensor *sr)
+{
+	bool all_sensors;
+
+	if (!strcmp(sr->name, "cpu-diode-temp-0"))
+		sens_cpu_temp[0] = sr;
+	else if (!strcmp(sr->name, "cpu-diode-temp-1"))
+		sens_cpu_temp[1] = sr;
+	else if (!strcmp(sr->name, "cpu-voltage-0"))
+		sens_cpu_volts[0] = sr;
+	else if (!strcmp(sr->name, "cpu-voltage-1"))
+		sens_cpu_volts[1] = sr;
+	else if (!strcmp(sr->name, "cpu-current-0"))
+		sens_cpu_amps[0] = sr;
+	else if (!strcmp(sr->name, "cpu-current-1"))
+		sens_cpu_amps[1] = sr;
+	else if (!strcmp(sr->name, "backside-temp"))
+		backside_temp = sr;
+	else if (!strcmp(sr->name, "slots-temp"))
+		slots_temp = sr;
+	else if (!strcmp(sr->name, "dimms-temp"))
+		dimms_temp = sr;
+
+	all_sensors =
+		sens_cpu_temp[0] &&
+		sens_cpu_volts[0] &&
+		sens_cpu_amps[0] &&
+		backside_temp &&
+		slots_temp &&
+		dimms_temp;
+	if (nr_chips > 1)
+		all_sensors &=
+			sens_cpu_temp[1] &&
+			sens_cpu_volts[1] &&
+			sens_cpu_amps[1];
+
+	have_all_sensors = all_sensors;
+}
+
+static int rm31_wf_notify(struct notifier_block *self,
+			  unsigned long event, void *data)
+{
+	switch (event) {
+	case WF_EVENT_NEW_SENSOR:
+		rm31_new_sensor(data);
+		break;
+	case WF_EVENT_NEW_CONTROL:
+		rm31_new_control(data);
+		break;
+	case WF_EVENT_TICK:
+		if (have_all_controls && have_all_sensors)
+			rm31_tick();
+	}
+	return 0;
+}
+
+static struct notifier_block rm31_events = {
+	.notifier_call = rm31_wf_notify,
+};
+
+static int wf_rm31_probe(struct platform_device *dev)
+{
+	wf_register_client(&rm31_events);
+	return 0;
+}
+
+static int __devexit wf_rm31_remove(struct platform_device *dev)
+{
+	wf_unregister_client(&rm31_events);
+
+	/* should release all sensors and controls */
+	return 0;
+}
+
+static struct platform_driver wf_rm31_driver = {
+	.probe	= wf_rm31_probe,
+	.remove	= wf_rm31_remove,
+	.driver	= {
+		.name = "windfarm",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init wf_rm31_init(void)
+{
+	struct device_node *cpu;
+	int i;
+
+	if (!of_machine_is_compatible("RackMac3,1"))
+		return -ENODEV;
+
+	/* Count the number of CPU cores */
+	nr_chips = 0;
+	for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+		++nr_chips;
+	if (nr_chips > NR_CHIPS)
+		nr_chips = NR_CHIPS;
+
+	pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
+		nr_chips);
+
+	/* Get MPU data for each CPU */
+	for (i = 0; i < nr_chips; i++) {
+		cpu_mpu_data[i] = wf_get_mpu(i);
+		if (!cpu_mpu_data[i]) {
+			pr_err("wf_rm31: Failed to find MPU data for CPU %d\n", i);
+			return -ENXIO;
+		}
+	}
+
+#ifdef MODULE
+	request_module("windfarm_fcu_controls");
+	request_module("windfarm_lm75_sensor");
+	request_module("windfarm_lm87_sensor");
+	request_module("windfarm_ad7417_sensor");
+	request_module("windfarm_max6690_sensor");
+	request_module("windfarm_cpufreq_clamp");
+#endif /* MODULE */
+
+	platform_driver_register(&wf_rm31_driver);
+	return 0;
+}
+
+static void __exit wf_rm31_exit(void)
+{
+	platform_driver_unregister(&wf_rm31_driver);
+}
+
+module_init(wf_rm31_init);
+module_exit(wf_rm31_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control for Xserve G5");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 3c2be51..c155a54 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -172,7 +172,6 @@
 
 	fct->fan_type = pwm_fan;
 	fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN;
-	sysfs_attr_init(&fct->ctrl.attr.attr);
 
 	/* We use the name & location here the same way we do for SMU sensors,
 	 * see the comment in windfarm_smu_sensors.c. The locations are a bit
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 65a8ff3..426e810 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -20,7 +20,7 @@
 
 #include "windfarm.h"
 
-#define VERSION "0.2"
+#define VERSION "1.0"
 
 #define DEBUG
 
@@ -34,11 +34,12 @@
 #define MAX_AGE		msecs_to_jiffies(800)
 
 struct wf_sat {
+	struct kref		ref;
 	int			nr;
-	atomic_t		refcnt;
 	struct mutex		mutex;
 	unsigned long		last_read; /* jiffies when cache last updated */
 	u8			cache[16];
+	struct list_head	sensors;
 	struct i2c_client	*i2c;
 	struct device_node	*node;
 };
@@ -46,11 +47,12 @@
 static struct wf_sat *sats[2];
 
 struct wf_sat_sensor {
-	int		index;
-	int		index2;		/* used for power sensors */
-	int		shift;
-	struct wf_sat	*sat;
-	struct wf_sensor sens;
+	struct list_head	link;
+	int			index;
+	int			index2;		/* used for power sensors */
+	int			shift;
+	struct wf_sat		*sat;
+	struct wf_sensor 	sens;
 };
 
 #define wf_to_sat(c)	container_of(c, struct wf_sat_sensor, sens)
@@ -142,7 +144,7 @@
 	return 0;
 }
 
-static int wf_sat_get(struct wf_sensor *sr, s32 *value)
+static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value)
 {
 	struct wf_sat_sensor *sens = wf_to_sat(sr);
 	struct wf_sat *sat = sens->sat;
@@ -175,62 +177,34 @@
 	return err;
 }
 
-static void wf_sat_release(struct wf_sensor *sr)
+static void wf_sat_release(struct kref *ref)
+{
+	struct wf_sat *sat = container_of(ref, struct wf_sat, ref);
+
+	if (sat->nr >= 0)
+		sats[sat->nr] = NULL;
+	kfree(sat);
+}
+
+static void wf_sat_sensor_release(struct wf_sensor *sr)
 {
 	struct wf_sat_sensor *sens = wf_to_sat(sr);
 	struct wf_sat *sat = sens->sat;
 
-	if (atomic_dec_and_test(&sat->refcnt)) {
-		if (sat->nr >= 0)
-			sats[sat->nr] = NULL;
-		kfree(sat);
-	}
 	kfree(sens);
+	kref_put(&sat->ref, wf_sat_release);
 }
 
 static struct wf_sensor_ops wf_sat_ops = {
-	.get_value	= wf_sat_get,
-	.release	= wf_sat_release,
+	.get_value	= wf_sat_sensor_get,
+	.release	= wf_sat_sensor_release,
 	.owner		= THIS_MODULE,
 };
 
-static struct i2c_driver wf_sat_driver;
-
-static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-	const u32 *reg;
-	u8 addr;
-
-	reg = of_get_property(dev, "reg", NULL);
-	if (reg == NULL)
-		return;
-	addr = *reg;
-	DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = (addr >> 1) & 0x7f;
-	info.platform_data = dev;
-	strlcpy(info.type, "wf_sat", I2C_NAME_SIZE);
-
-	client = i2c_new_device(adapter, &info);
-	if (client == NULL) {
-		printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
-		return;
-	}
-
-	/*
-	 * Let i2c-core delete that device on driver removal.
-	 * This is safe because i2c-core holds the core_lock mutex for us.
-	 */
-	list_add_tail(&client->detected, &wf_sat_driver.clients);
-}
-
 static int wf_sat_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
-	struct device_node *dev = client->dev.platform_data;
+	struct device_node *dev = client->dev.of_node;
 	struct wf_sat *sat;
 	struct wf_sat_sensor *sens;
 	const u32 *reg;
@@ -246,9 +220,10 @@
 		return -ENOMEM;
 	sat->nr = -1;
 	sat->node = of_node_get(dev);
-	atomic_set(&sat->refcnt, 0);
+	kref_init(&sat->ref);
 	mutex_init(&sat->mutex);
 	sat->i2c = client;
+	INIT_LIST_HEAD(&sat->sensors);
 	i2c_set_clientdata(client, sat);
 
 	vsens[0] = vsens[1] = -1;
@@ -310,14 +285,15 @@
 		sens->index2 = -1;
 		sens->shift = shift;
 		sens->sat = sat;
-		atomic_inc(&sat->refcnt);
 		sens->sens.ops = &wf_sat_ops;
 		sens->sens.name = (char *) (sens + 1);
-		snprintf(sens->sens.name, 16, "%s-%d", name, cpu);
+		snprintf((char *)sens->sens.name, 16, "%s-%d", name, cpu);
 
-		if (wf_register_sensor(&sens->sens)) {
-			atomic_dec(&sat->refcnt);
+		if (wf_register_sensor(&sens->sens))
 			kfree(sens);
+		else {
+			list_add(&sens->link, &sat->sensors);
+			kref_get(&sat->ref);
 		}
 	}
 
@@ -336,14 +312,15 @@
 		sens->index2 = isens[core];
 		sens->shift = 0;
 		sens->sat = sat;
-		atomic_inc(&sat->refcnt);
 		sens->sens.ops = &wf_sat_ops;
 		sens->sens.name = (char *) (sens + 1);
-		snprintf(sens->sens.name, 16, "cpu-power-%d", cpu);
+		snprintf((char *)sens->sens.name, 16, "cpu-power-%d", cpu);
 
-		if (wf_register_sensor(&sens->sens)) {
-			atomic_dec(&sat->refcnt);
+		if (wf_register_sensor(&sens->sens))
 			kfree(sens);
+		else {
+			list_add(&sens->link, &sat->sensors);
+			kref_get(&sat->ref);
 		}
 	}
 
@@ -353,42 +330,35 @@
 	return 0;
 }
 
-static int wf_sat_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL)
-		if (of_device_is_compatible(dev, "smu-sat"))
-			wf_sat_create(adapter, dev);
-	return 0;
-}
-
 static int wf_sat_remove(struct i2c_client *client)
 {
 	struct wf_sat *sat = i2c_get_clientdata(client);
+	struct wf_sat_sensor *sens;
 
-	/* XXX TODO */
-
+	/* release sensors */
+	while(!list_empty(&sat->sensors)) {
+		sens = list_first_entry(&sat->sensors,
+					struct wf_sat_sensor, link);
+		list_del(&sens->link);
+		wf_unregister_sensor(&sens->sens);
+	}
 	sat->i2c = NULL;
+	i2c_set_clientdata(client, NULL);
+	kref_put(&sat->ref, wf_sat_release);
+
 	return 0;
 }
 
 static const struct i2c_device_id wf_sat_id[] = {
-	{ "wf_sat", 0 },
+	{ "MAC,smu-sat", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c, wf_sat_id);
 
 static struct i2c_driver wf_sat_driver = {
 	.driver = {
 		.name		= "wf_smu_sat",
 	},
-	.attach_adapter	= wf_sat_attach,
 	.probe		= wf_sat_probe,
 	.remove		= wf_sat_remove,
 	.id_table	= wf_sat_id,
@@ -399,15 +369,13 @@
 	return i2c_add_driver(&wf_sat_driver);
 }
 
-#if 0	/* uncomment when module_exit() below is uncommented */
 static void __exit sat_sensors_exit(void)
 {
 	i2c_del_driver(&wf_sat_driver);
 }
-#endif
 
 module_init(sat_sensors_init);
-/*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */
+module_exit(sat_sensors_exit);
 
 MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
 MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
diff --git a/drivers/mca/Kconfig b/drivers/mca/Kconfig
deleted file mode 100644
index a7a0220..0000000
--- a/drivers/mca/Kconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-config MCA_LEGACY
-	bool "Legacy MCA API Support"
-	depends on MCA
-	help
-	  This compiles in support for the old slot based MCA API.  If you
-	  have an unconverted MCA driver, you will need to say Y here.  It
-	  is safe to say Y anyway.
-
-config MCA_PROC_FS
-	bool "Support for the mca entry in /proc"
-	depends on MCA_LEGACY && PROC_FS
-	help
-	  If you want the old style /proc/mca directory in addition to the
-	  new style sysfs say Y here.
diff --git a/drivers/mca/Makefile b/drivers/mca/Makefile
deleted file mode 100644
index 0794b12..0000000
--- a/drivers/mca/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# Makefile for the Linux MCA bus support
-
-obj-y	:= mca-bus.o mca-device.o mca-driver.o
-
-obj-$(CONFIG_MCA_PROC_FS)	+= mca-proc.o
-obj-$(CONFIG_MCA_LEGACY)	+= mca-legacy.o
-
diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c
deleted file mode 100644
index ada5ebb..0000000
--- a/drivers/mca/mca-bus.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA bus support functions for sysfs.
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/mca.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
-/* Very few machines have more than one MCA bus.  However, there are
- * those that do (Voyager 35xx/5xxx), so we do it this way for future
- * expansion.  None that I know have more than 2 */
-static struct mca_bus *mca_root_busses[MAX_MCA_BUSSES];
-
-#define MCA_DEVINFO(i,s) { .pos = i, .name = s }
-
-struct mca_device_info {
-	short pos_id;		/* the 2 byte pos id for this card */
-	char name[50];
-};
-
-static int mca_bus_match (struct device *dev, struct device_driver *drv)
-{
-	struct mca_device *mca_dev = to_mca_device (dev);
-	struct mca_driver *mca_drv = to_mca_driver (drv);
-	const unsigned short *mca_ids = mca_drv->id_table;
-	int i = 0;
-
-	if (mca_ids) {
-		for(i = 0; mca_ids[i]; i++) {
-			if (mca_ids[i] == mca_dev->pos_id) {
-				mca_dev->index = i;
-				return 1;
-			}
-		}
-	}
-	/* If the integrated id is present, treat it as though it were an
-	 * additional id in the id_table (it can't be because by definition,
-	 * integrated id's overflow a short */
-	if (mca_drv->integrated_id && mca_dev->pos_id ==
-	    mca_drv->integrated_id) {
-		mca_dev->index = i;
-		return 1;
-	}
-	return 0;
-}
-
-struct bus_type mca_bus_type = {
-	.name  = "MCA",
-	.match = mca_bus_match,
-};
-EXPORT_SYMBOL (mca_bus_type);
-
-static ssize_t mca_show_pos_id(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	/* four digits, \n and trailing \0 */
-	struct mca_device *mca_dev = to_mca_device(dev);
-	int len;
-
-	if(mca_dev->pos_id < MCA_DUMMY_POS_START)
-		len = sprintf(buf, "%04x\n", mca_dev->pos_id);
-	else
-		len = sprintf(buf, "none\n");
-	return len;
-}
-static ssize_t mca_show_pos(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	/* enough for 8 two byte hex chars plus space and new line */
-	int j, len=0;
-	struct mca_device *mca_dev = to_mca_device(dev);
-
-	for(j=0; j<8; j++)
-		len += sprintf(buf+len, "%02x ", mca_dev->pos[j]);
-	/* change last trailing space to new line */
-	buf[len-1] = '\n';
-	return len;
-}
-
-static DEVICE_ATTR(id, S_IRUGO, mca_show_pos_id, NULL);
-static DEVICE_ATTR(pos, S_IRUGO, mca_show_pos, NULL);
-
-int __init mca_register_device(int bus, struct mca_device *mca_dev)
-{
-	struct mca_bus *mca_bus = mca_root_busses[bus];
-	int rc;
-
-	mca_dev->dev.parent = &mca_bus->dev;
-	mca_dev->dev.bus = &mca_bus_type;
-	dev_set_name(&mca_dev->dev, "%02d:%02X", bus, mca_dev->slot);
-	mca_dev->dma_mask = mca_bus->default_dma_mask;
-	mca_dev->dev.dma_mask = &mca_dev->dma_mask;
-	mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask;
-
-	rc = device_register(&mca_dev->dev);
-	if (rc)
-		goto err_out;
-
-	rc = device_create_file(&mca_dev->dev, &dev_attr_id);
-	if (rc) goto err_out_devreg;
-	rc = device_create_file(&mca_dev->dev, &dev_attr_pos);
-	if (rc) goto err_out_id;
-
-	return 1;
-
-err_out_id:
-	device_remove_file(&mca_dev->dev, &dev_attr_id);
-err_out_devreg:
-	device_unregister(&mca_dev->dev);
-err_out:
-	return 0;
-}
-
-/* */
-struct mca_bus * __devinit mca_attach_bus(int bus)
-{
-	struct mca_bus *mca_bus;
-
-	if (unlikely(mca_root_busses[bus] != NULL)) {
-		/* This should never happen, but just in case */
-		printk(KERN_EMERG "MCA tried to add already existing bus %d\n",
-		       bus);
-		dump_stack();
-		return NULL;
-	}
-
-	mca_bus = kzalloc(sizeof(struct mca_bus), GFP_KERNEL);
-	if (!mca_bus)
-		return NULL;
-
-	dev_set_name(&mca_bus->dev, "mca%d", bus);
-	sprintf(mca_bus->name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary");
-	if (device_register(&mca_bus->dev)) {
-		kfree(mca_bus);
-		return NULL;
-	}
-
-	mca_root_busses[bus] = mca_bus;
-
-	return mca_bus;
-}
-
-int __init mca_system_init (void)
-{
-	return bus_register(&mca_bus_type);
-}
diff --git a/drivers/mca/mca-device.c b/drivers/mca/mca-device.c
deleted file mode 100644
index e7adf89..0000000
--- a/drivers/mca/mca-device.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA device support functions
- *
- * These functions support the ongoing device access API.
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/mca.h>
-#include <linux/string.h>
-
-/**
- *	mca_device_read_stored_pos - read POS register from stored data
- *	@mca_dev: device to read from
- *	@reg:  register to read from
- *
- *	Fetch a POS value that was stored at boot time by the kernel
- *	when it scanned the MCA space. The register value is returned.
- *	Missing or invalid registers report 0.
- */
-unsigned char mca_device_read_stored_pos(struct mca_device *mca_dev, int reg)
-{
-	if(reg < 0 || reg >= 8)
-		return 0;
-
-	return mca_dev->pos[reg];
-}
-EXPORT_SYMBOL(mca_device_read_stored_pos);
-
-/**
- *	mca_device_read_pos - read POS register from card
- *	@mca_dev: device to read from
- *	@reg:  register to read from
- *
- *	Fetch a POS value directly from the hardware to obtain the
- *	current value. This is much slower than
- *	mca_device_read_stored_pos and may not be invoked from
- *	interrupt context. It handles the deep magic required for
- *	onboard devices transparently.
- */
-unsigned char mca_device_read_pos(struct mca_device *mca_dev, int reg)
-{
-	struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
-	return mca_bus->f.mca_read_pos(mca_dev, reg);
-
-	return 	mca_dev->pos[reg];
-}
-EXPORT_SYMBOL(mca_device_read_pos);
-
-
-/**
- *	mca_device_write_pos - read POS register from card
- *	@mca_dev: device to write pos register to
- *	@reg:  register to write to
- *	@byte: byte to write to the POS registers
- *
- *	Store a POS value directly to the hardware. You should not
- *	normally need to use this function and should have a very good
- *	knowledge of MCA bus before you do so. Doing this wrongly can
- *	damage the hardware.
- *
- *	This function may not be used from interrupt context.
- *
- */
-void mca_device_write_pos(struct mca_device *mca_dev, int reg,
-			  unsigned char byte)
-{
-	struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
-	mca_bus->f.mca_write_pos(mca_dev, reg, byte);
-}
-EXPORT_SYMBOL(mca_device_write_pos);
-
-/**
- *	mca_device_transform_irq - transform the ADF obtained IRQ
- *	@mca_device: device whose irq needs transforming
- *	@irq: input irq from ADF
- *
- *	MCA Adapter Definition Files (ADF) contain irq, ioport, memory
- *	etc. definitions.  In systems with more than one bus, these need
- *	to be transformed through bus mapping functions to get the real
- *	system global quantities.
- *
- *	This function transforms the interrupt number and returns the
- *	transformed system global interrupt
- */
-int mca_device_transform_irq(struct mca_device *mca_dev, int irq)
-{
-	struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
-	return mca_bus->f.mca_transform_irq(mca_dev, irq);
-}
-EXPORT_SYMBOL(mca_device_transform_irq);
-
-/**
- *	mca_device_transform_ioport - transform the ADF obtained I/O port
- *	@mca_device: device whose port needs transforming
- *	@ioport: input I/O port from ADF
- *
- *	MCA Adapter Definition Files (ADF) contain irq, ioport, memory
- *	etc. definitions.  In systems with more than one bus, these need
- *	to be transformed through bus mapping functions to get the real
- *	system global quantities.
- *
- *	This function transforms the I/O port number and returns the
- *	transformed system global port number.
- *
- *	This transformation can be assumed to be linear for port ranges.
- */
-int mca_device_transform_ioport(struct mca_device *mca_dev, int port)
-{
-	struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
-	return mca_bus->f.mca_transform_ioport(mca_dev, port);
-}
-EXPORT_SYMBOL(mca_device_transform_ioport);
-
-/**
- *	mca_device_transform_memory - transform the ADF obtained memory
- *	@mca_device: device whose memory region needs transforming
- *	@mem: memory region start from ADF
- *
- *	MCA Adapter Definition Files (ADF) contain irq, ioport, memory
- *	etc. definitions.  In systems with more than one bus, these need
- *	to be transformed through bus mapping functions to get the real
- *	system global quantities.
- *
- *	This function transforms the memory region start and returns the
- *	transformed system global memory region (physical).
- *
- *	This transformation can be assumed to be linear for region ranges.
- */
-void *mca_device_transform_memory(struct mca_device *mca_dev, void *mem)
-{
-	struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
-	return mca_bus->f.mca_transform_memory(mca_dev, mem);
-}
-EXPORT_SYMBOL(mca_device_transform_memory);
-
-
-/**
- *	mca_device_claimed - check if claimed by driver
- *	@mca_dev:	device to check
- *
- *	Returns 1 if the slot has been claimed by a driver
- */
-
-int mca_device_claimed(struct mca_device *mca_dev)
-{
-	return mca_dev->driver_loaded;
-}
-EXPORT_SYMBOL(mca_device_claimed);
-
-/**
- *	mca_device_set_claim - set the claim value of the driver
- *	@mca_dev:	device to set value for
- *	@val:		claim value to set (1 claimed, 0 unclaimed)
- */
-void mca_device_set_claim(struct mca_device *mca_dev, int val)
-{
-	mca_dev->driver_loaded = val;
-}
-EXPORT_SYMBOL(mca_device_set_claim);
-
-/**
- *	mca_device_status - get the status of the device
- *	@mca_device:	device to get
- *
- *	returns an enumeration of the device status:
- *
- *	MCA_ADAPTER_NORMAL	adapter is OK.
- *	MCA_ADAPTER_NONE	no adapter at device (should never happen).
- *	MCA_ADAPTER_DISABLED	adapter is disabled.
- *	MCA_ADAPTER_ERROR	adapter cannot be initialised.
- */
-enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev)
-{
-	return mca_dev->status;
-}
-EXPORT_SYMBOL(mca_device_status);
-
-/**
- *	mca_device_set_name - set the name of the device
- *	@mca_device:	device to set the name of
- *	@name:		name to set
- */
-void mca_device_set_name(struct mca_device *mca_dev, const char *name)
-{
-	if(!mca_dev)
-		return;
-
-	strlcpy(mca_dev->name, name, sizeof(mca_dev->name));
-}
-EXPORT_SYMBOL(mca_device_set_name);
diff --git a/drivers/mca/mca-driver.c b/drivers/mca/mca-driver.c
deleted file mode 100644
index 32cd39b..0000000
--- a/drivers/mca/mca-driver.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA driver support functions for sysfs.
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-
-#include <linux/device.h>
-#include <linux/mca.h>
-#include <linux/module.h>
-
-int mca_register_driver(struct mca_driver *mca_drv)
-{
-	int r;
-
-	if (MCA_bus) {
-		mca_drv->driver.bus = &mca_bus_type;
-		if ((r = driver_register(&mca_drv->driver)) < 0)
-			return r;
-		mca_drv->integrated_id = 0;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(mca_register_driver);
-
-int mca_register_driver_integrated(struct mca_driver *mca_driver,
-				   int integrated_id)
-{
-	int r = mca_register_driver(mca_driver);
-
-	if (!r)
-		mca_driver->integrated_id = integrated_id;
-
-	return r;
-}
-EXPORT_SYMBOL(mca_register_driver_integrated);
-
-void mca_unregister_driver(struct mca_driver *mca_drv)
-{
-	if (MCA_bus)
-		driver_unregister(&mca_drv->driver);
-}
-EXPORT_SYMBOL(mca_unregister_driver);
diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c
deleted file mode 100644
index 494f0c2..0000000
--- a/drivers/mca/mca-legacy.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA bus support functions for legacy (2.4) API.
- *
- * Legacy API means the API that operates in terms of MCA slot number
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/mca-legacy.h>
-#include <asm/io.h>
-
-/* NOTE: This structure is stack allocated */
-struct mca_find_adapter_info {
-	int			id;
-	int			slot;
-	struct mca_device	*mca_dev;
-};
-
-/* The purpose of this iterator is to loop over all the devices and
- * find the one with the smallest slot number that's just greater than
- * or equal to the required slot with a matching id */
-static int mca_find_adapter_callback(struct device *dev, void *data)
-{
-	struct mca_find_adapter_info *info = data;
-	struct mca_device *mca_dev = to_mca_device(dev);
-
-	if(mca_dev->pos_id != info->id)
-		return 0;
-
-	if(mca_dev->slot < info->slot)
-		return 0;
-
-	if(!info->mca_dev || info->mca_dev->slot >= mca_dev->slot)
-		info->mca_dev = mca_dev;
-
-	return 0;
-}
-
-/**
- *	mca_find_adapter - scan for adapters
- *	@id:	MCA identification to search for
- *	@start:	starting slot
- *
- *	Search the MCA configuration for adapters matching the 16bit
- *	ID given. The first time it should be called with start as zero
- *	and then further calls made passing the return value of the
- *	previous call until %MCA_NOTFOUND is returned.
- *
- *	Disabled adapters are not reported.
- */
-
-int mca_find_adapter(int id, int start)
-{
-	struct mca_find_adapter_info info;
-
-	if(id == 0xffff)
-		return MCA_NOTFOUND;
-
-	info.slot = start;
-	info.id = id;
-	info.mca_dev = NULL;
-
-	for(;;) {
-		bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
-
-		if(info.mca_dev == NULL)
-			return MCA_NOTFOUND;
-
-		if(info.mca_dev->status != MCA_ADAPTER_DISABLED)
-			break;
-
-		/* OK, found adapter but it was disabled.  Go around
-		 * again, excluding the slot we just found */
-
-		info.slot = info.mca_dev->slot + 1;
-		info.mca_dev = NULL;
-	}
-		
-	return info.mca_dev->slot;
-}
-EXPORT_SYMBOL(mca_find_adapter);
-
-/*--------------------------------------------------------------------*/
-
-/**
- *	mca_find_unused_adapter - scan for unused adapters
- *	@id:	MCA identification to search for
- *	@start:	starting slot
- *
- *	Search the MCA configuration for adapters matching the 16bit
- *	ID given. The first time it should be called with start as zero
- *	and then further calls made passing the return value of the
- *	previous call until %MCA_NOTFOUND is returned.
- *
- *	Adapters that have been claimed by drivers and those that
- *	are disabled are not reported. This function thus allows a driver
- *	to scan for further cards when some may already be driven.
- */
-
-int mca_find_unused_adapter(int id, int start)
-{
-	struct mca_find_adapter_info info = { 0 };
-
-	if (!MCA_bus || id == 0xffff)
-		return MCA_NOTFOUND;
-
-	info.slot = start;
-	info.id = id;
-	info.mca_dev = NULL;
-
-	for(;;) {
-		bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
-
-		if(info.mca_dev == NULL)
-			return MCA_NOTFOUND;
-
-		if(info.mca_dev->status != MCA_ADAPTER_DISABLED
-		   && !info.mca_dev->driver_loaded)
-			break;
-
-		/* OK, found adapter but it was disabled or already in
-		 * use.  Go around again, excluding the slot we just
-		 * found */
-
-		info.slot = info.mca_dev->slot + 1;
-		info.mca_dev = NULL;
-	}
-		
-	return info.mca_dev->slot;
-}
-EXPORT_SYMBOL(mca_find_unused_adapter);
-
-/* NOTE: stack allocated structure */
-struct mca_find_device_by_slot_info {
-	int			slot;
-	struct mca_device 	*mca_dev;
-};
-
-static int mca_find_device_by_slot_callback(struct device *dev, void *data)
-{
-	struct mca_find_device_by_slot_info *info = data;
-	struct mca_device *mca_dev = to_mca_device(dev);
-
-	if(mca_dev->slot == info->slot)
-		info->mca_dev = mca_dev;
-
-	return 0;
-}
-
-struct mca_device *mca_find_device_by_slot(int slot)
-{
-	struct mca_find_device_by_slot_info info;
-
-	info.slot = slot;
-	info.mca_dev = NULL;
-
-	bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_device_by_slot_callback);
-
-	return info.mca_dev;
-}
-
-/**
- *	mca_read_stored_pos - read POS register from boot data
- *	@slot: slot number to read from
- *	@reg:  register to read from
- *
- *	Fetch a POS value that was stored at boot time by the kernel
- *	when it scanned the MCA space. The register value is returned.
- *	Missing or invalid registers report 0.
- */
-unsigned char mca_read_stored_pos(int slot, int reg)
-{
-	struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
-	if(!mca_dev)
-		return 0;
-
-	return mca_device_read_stored_pos(mca_dev, reg);
-}
-EXPORT_SYMBOL(mca_read_stored_pos);
-
-
-/**
- *	mca_read_pos - read POS register from card
- *	@slot: slot number to read from
- *	@reg:  register to read from
- *
- *	Fetch a POS value directly from the hardware to obtain the
- *	current value. This is much slower than mca_read_stored_pos and
- *	may not be invoked from interrupt context. It handles the
- *	deep magic required for onboard devices transparently.
- */
-
-unsigned char mca_read_pos(int slot, int reg)
-{
-	struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
-	if(!mca_dev)
-		return 0;
-
-	return mca_device_read_pos(mca_dev, reg);
-}
-EXPORT_SYMBOL(mca_read_pos);
-
-		
-/**
- *	mca_write_pos - read POS register from card
- *	@slot: slot number to read from
- *	@reg:  register to read from
- *	@byte: byte to write to the POS registers
- *
- *	Store a POS value directly from the hardware. You should not
- *	normally need to use this function and should have a very good
- *	knowledge of MCA bus before you do so. Doing this wrongly can
- *	damage the hardware.
- *
- *	This function may not be used from interrupt context.
- *
- *	Note that this a technically a Bad Thing, as IBM tech stuff says
- *	you should only set POS values through their utilities.
- *	However, some devices such as the 3c523 recommend that you write
- *	back some data to make sure the configuration is consistent.
- *	I'd say that IBM is right, but I like my drivers to work.
- *
- *	This function can't do checks to see if multiple devices end up
- *	with the same resources, so you might see magic smoke if someone
- *	screws up.
- */
-
-void mca_write_pos(int slot, int reg, unsigned char byte)
-{
-	struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
-	if(!mca_dev)
-		return;
-
-	mca_device_write_pos(mca_dev, reg, byte);
-}
-EXPORT_SYMBOL(mca_write_pos);
-
-/**
- *	mca_set_adapter_name - Set the description of the card
- *	@slot: slot to name
- *	@name: text string for the namen
- *
- *	This function sets the name reported via /proc for this
- *	adapter slot. This is for user information only. Setting a
- *	name deletes any previous name.
- */
-
-void mca_set_adapter_name(int slot, char* name)
-{
-	struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
-	if(!mca_dev)
-		return;
-
-	mca_device_set_name(mca_dev, name);
-}
-EXPORT_SYMBOL(mca_set_adapter_name);
-
-/**
- *	mca_mark_as_used - claim an MCA device
- *	@slot:	slot to claim
- *	FIXME:  should we make this threadsafe
- *
- *	Claim an MCA slot for a device driver. If the
- *	slot is already taken the function returns 1,
- *	if it is not taken it is claimed and 0 is
- *	returned.
- */
-
-int mca_mark_as_used(int slot)
-{
-	struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
-	if(!mca_dev)
-		/* FIXME: this is actually a severe error */
-		return 1;
-
-	if(mca_device_claimed(mca_dev))
-		return 1;
-
-	mca_device_set_claim(mca_dev, 1);
-
-	return 0;
-}
-EXPORT_SYMBOL(mca_mark_as_used);
-
-/**
- *	mca_mark_as_unused - release an MCA device
- *	@slot:	slot to claim
- *
- *	Release the slot for other drives to use.
- */
-
-void mca_mark_as_unused(int slot)
-{
-	struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
-	if(!mca_dev)
-		return;
-
-	mca_device_set_claim(mca_dev, 0);
-}
-EXPORT_SYMBOL(mca_mark_as_unused);
-
diff --git a/drivers/mca/mca-proc.c b/drivers/mca/mca-proc.c
deleted file mode 100644
index 81ea0d3..0000000
--- a/drivers/mca/mca-proc.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA bus support functions for the proc fs.
- *
- * NOTE: this code *requires* the legacy MCA api.
- *
- * Legacy API means the API that operates in terms of MCA slot number
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/mca.h>
-
-static int get_mca_info_helper(struct mca_device *mca_dev, char *page, int len)
-{
-	int j;
-
-	for(j=0; j<8; j++)
-		len += sprintf(page+len, "%02x ",
-			       mca_dev ? mca_dev->pos[j] : 0xff);
-	len += sprintf(page+len, " %s\n", mca_dev ? mca_dev->name : "");
-	return len;
-}
-
-static int get_mca_info(char *page, char **start, off_t off,
-			int count, int *eof, void *data)
-{
-	int i, len = 0;
-
-	if(MCA_bus) {
-		struct mca_device *mca_dev;
-		/* Format POS registers of eight MCA slots */
-
-		for(i=0; i<MCA_MAX_SLOT_NR; i++) {
-			mca_dev = mca_find_device_by_slot(i);
-
-			len += sprintf(page+len, "Slot %d: ", i+1);
-			len = get_mca_info_helper(mca_dev, page, len);
-		}
-
-		/* Format POS registers of integrated video subsystem */
-
-		mca_dev = mca_find_device_by_slot(MCA_INTEGVIDEO);
-		len += sprintf(page+len, "Video : ");
-		len = get_mca_info_helper(mca_dev, page, len);
-
-		/* Format POS registers of integrated SCSI subsystem */
-
-		mca_dev = mca_find_device_by_slot(MCA_INTEGSCSI);
-		len += sprintf(page+len, "SCSI  : ");
-		len = get_mca_info_helper(mca_dev, page, len);
-
-		/* Format POS registers of motherboard */
-
-		mca_dev = mca_find_device_by_slot(MCA_MOTHERBOARD);
-		len += sprintf(page+len, "Planar: ");
-		len = get_mca_info_helper(mca_dev, page, len);
-	} else {
-		/* Leave it empty if MCA not detected - this should *never*
-		 * happen!
-		 */
-	}
-
-	if (len <= off+count) *eof = 1;
-	*start = page + off;
-	len -= off;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
-}
-
-/*--------------------------------------------------------------------*/
-
-static int mca_default_procfn(char* buf, struct mca_device *mca_dev)
-{
-	int len = 0, i;
-	int slot = mca_dev->slot;
-
-	/* Print out the basic information */
-
-	if(slot < MCA_MAX_SLOT_NR) {
-		len += sprintf(buf+len, "Slot: %d\n", slot+1);
-	} else if(slot == MCA_INTEGSCSI) {
-		len += sprintf(buf+len, "Integrated SCSI Adapter\n");
-	} else if(slot == MCA_INTEGVIDEO) {
-		len += sprintf(buf+len, "Integrated Video Adapter\n");
-	} else if(slot == MCA_MOTHERBOARD) {
-		len += sprintf(buf+len, "Motherboard\n");
-	}
-	if (mca_dev->name[0]) {
-
-		/* Drivers might register a name without /proc handler... */
-
-		len += sprintf(buf+len, "Adapter Name: %s\n",
-			       mca_dev->name);
-	} else {
-		len += sprintf(buf+len, "Adapter Name: Unknown\n");
-	}
-	len += sprintf(buf+len, "Id: %02x%02x\n",
-		mca_dev->pos[1], mca_dev->pos[0]);
-	len += sprintf(buf+len, "Enabled: %s\nPOS: ",
-		mca_device_status(mca_dev) == MCA_ADAPTER_NORMAL ?
-			"Yes" : "No");
-	for(i=0; i<8; i++) {
-		len += sprintf(buf+len, "%02x ", mca_dev->pos[i]);
-	}
-	len += sprintf(buf+len, "\nDriver Installed: %s",
-		mca_device_claimed(mca_dev) ? "Yes" : "No");
-	buf[len++] = '\n';
-	buf[len] = 0;
-
-	return len;
-} /* mca_default_procfn() */
-
-static int get_mca_machine_info(char* page, char **start, off_t off,
-				 int count, int *eof, void *data)
-{
-	int len = 0;
-
-	len += sprintf(page+len, "Model Id: 0x%x\n", machine_id);
-	len += sprintf(page+len, "Submodel Id: 0x%x\n", machine_submodel_id);
-	len += sprintf(page+len, "BIOS Revision: 0x%x\n", BIOS_revision);
-
-	if (len <= off+count) *eof = 1;
-	*start = page + off;
-	len -= off;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
-}
-
-static int mca_read_proc(char *page, char **start, off_t off,
-				 int count, int *eof, void *data)
-{
-	struct mca_device *mca_dev = (struct mca_device *)data;
-	int len = 0;
-
-	/* Get the standard info */
-
-	len = mca_default_procfn(page, mca_dev);
-
-	/* Do any device-specific processing, if there is any */
-
-	if(mca_dev->procfn) {
-		len += mca_dev->procfn(page+len, mca_dev->slot,
-				       mca_dev->proc_dev);
-	}
-	if (len <= off+count) *eof = 1;
-	*start = page + off;
-	len -= off;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
-} /* mca_read_proc() */
-
-/*--------------------------------------------------------------------*/
-
-void __init mca_do_proc_init(void)
-{
-	int i;
-	struct proc_dir_entry *proc_mca;
-	struct proc_dir_entry* node = NULL;
-	struct mca_device *mca_dev;
-
-	proc_mca = proc_mkdir("mca", NULL);
-	create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
-	create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
-
-	/* Initialize /proc/mca entries for existing adapters */
-
-	for(i = 0; i < MCA_NUMADAPTERS; i++) {
-		enum MCA_AdapterStatus status;
-		mca_dev = mca_find_device_by_slot(i);
-		if(!mca_dev)
-			continue;
-
-		mca_dev->procfn = NULL;
-
-		if(i < MCA_MAX_SLOT_NR) sprintf(mca_dev->procname,"slot%d", i+1);
-		else if(i == MCA_INTEGVIDEO) sprintf(mca_dev->procname,"video");
-		else if(i == MCA_INTEGSCSI) sprintf(mca_dev->procname,"scsi");
-		else if(i == MCA_MOTHERBOARD) sprintf(mca_dev->procname,"planar");
-
-		status = mca_device_status(mca_dev);
-		if (status != MCA_ADAPTER_NORMAL &&
-		    status != MCA_ADAPTER_DISABLED)
-			continue;
-
-		node = create_proc_read_entry(mca_dev->procname, 0, proc_mca,
-					      mca_read_proc, (void *)mca_dev);
-
-		if(node == NULL) {
-			printk("Failed to allocate memory for MCA proc-entries!");
-			return;
-		}
-	}
-
-} /* mca_do_proc_init() */
-
-/**
- *	mca_set_adapter_procfn - Set the /proc callback
- *	@slot: slot to configure
- *	@procfn: callback function to call for /proc
- *	@dev: device information passed to the callback
- *
- *	This sets up an information callback for /proc/mca/slot?.  The
- *	function is called with the buffer, slot, and device pointer (or
- *	some equally informative context information, or nothing, if you
- *	prefer), and is expected to put useful information into the
- *	buffer.  The adapter name, ID, and POS registers get printed
- *	before this is called though, so don't do it again.
- *
- *	This should be called with a %NULL @procfn when a module
- *	unregisters, thus preventing kernel crashes and other such
- *	nastiness.
- */
-
-void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* proc_dev)
-{
-	struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
-	if(!mca_dev)
-		return;
-
-	mca_dev->procfn = procfn;
-	mca_dev->proc_dev = proc_dev;
-}
-EXPORT_SYMBOL(mca_set_adapter_procfn);
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 17e2b47..15dbe03 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -45,7 +45,7 @@
  * if we find our page, we increment the page's refcount so that it stays
  * allocated while we're using it
  */
-static int bitmap_checkpage(struct bitmap *bitmap,
+static int bitmap_checkpage(struct bitmap_counts *bitmap,
 			    unsigned long page, int create)
 __releases(bitmap->lock)
 __acquires(bitmap->lock)
@@ -76,8 +76,7 @@
 	spin_lock_irq(&bitmap->lock);
 
 	if (mappage == NULL) {
-		pr_debug("%s: bitmap map page allocation failed, hijacking\n",
-			 bmname(bitmap));
+		pr_debug("md/bitmap: map page allocation failed, hijacking\n");
 		/* failed - set the hijacked flag so that we can use the
 		 * pointer as a counter */
 		if (!bitmap->bp[page].map)
@@ -100,7 +99,7 @@
 /* if page is completely empty, put it back on the free list, or dealloc it */
 /* if page was hijacked, unmark the flag so it might get alloced next time */
 /* Note: lock should be held when calling this */
-static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
+static void bitmap_checkfree(struct bitmap_counts *bitmap, unsigned long page)
 {
 	char *ptr;
 
@@ -130,22 +129,14 @@
  */
 
 /* IO operations when bitmap is stored near all superblocks */
-static struct page *read_sb_page(struct mddev *mddev, loff_t offset,
-				 struct page *page,
-				 unsigned long index, int size)
+static int read_sb_page(struct mddev *mddev, loff_t offset,
+			struct page *page,
+			unsigned long index, int size)
 {
 	/* choose a good rdev and read the page from there */
 
 	struct md_rdev *rdev;
 	sector_t target;
-	int did_alloc = 0;
-
-	if (!page) {
-		page = alloc_page(GFP_KERNEL);
-		if (!page)
-			return ERR_PTR(-ENOMEM);
-		did_alloc = 1;
-	}
 
 	rdev_for_each(rdev, mddev) {
 		if (! test_bit(In_sync, &rdev->flags)
@@ -158,15 +149,10 @@
 				 roundup(size, bdev_logical_block_size(rdev->bdev)),
 				 page, READ, true)) {
 			page->index = index;
-			attach_page_buffers(page, NULL); /* so that free_buffer will
-							  * quietly no-op */
-			return page;
+			return 0;
 		}
 	}
-	if (did_alloc)
-		put_page(page);
-	return ERR_PTR(-EIO);
-
+	return -EIO;
 }
 
 static struct md_rdev *next_active_rdev(struct md_rdev *rdev, struct mddev *mddev)
@@ -208,6 +194,7 @@
 	struct md_rdev *rdev = NULL;
 	struct block_device *bdev;
 	struct mddev *mddev = bitmap->mddev;
+	struct bitmap_storage *store = &bitmap->storage;
 
 	while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
 		int size = PAGE_SIZE;
@@ -215,9 +202,13 @@
 
 		bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;
 
-		if (page->index == bitmap->file_pages-1)
-			size = roundup(bitmap->last_page_size,
+		if (page->index == store->file_pages-1) {
+			int last_page_size = store->bytes & (PAGE_SIZE-1);
+			if (last_page_size == 0)
+				last_page_size = PAGE_SIZE;
+			size = roundup(last_page_size,
 				       bdev_logical_block_size(bdev));
+		}
 		/* Just make sure we aren't corrupting data or
 		 * metadata
 		 */
@@ -276,10 +267,10 @@
 {
 	struct buffer_head *bh;
 
-	if (bitmap->file == NULL) {
+	if (bitmap->storage.file == NULL) {
 		switch (write_sb_page(bitmap, page, wait)) {
 		case -EINVAL:
-			bitmap->flags |= BITMAP_WRITE_ERROR;
+			set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
 		}
 	} else {
 
@@ -297,20 +288,16 @@
 			wait_event(bitmap->write_wait,
 				   atomic_read(&bitmap->pending_writes)==0);
 	}
-	if (bitmap->flags & BITMAP_WRITE_ERROR)
+	if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
 		bitmap_file_kick(bitmap);
 }
 
 static void end_bitmap_write(struct buffer_head *bh, int uptodate)
 {
 	struct bitmap *bitmap = bh->b_private;
-	unsigned long flags;
 
-	if (!uptodate) {
-		spin_lock_irqsave(&bitmap->lock, flags);
-		bitmap->flags |= BITMAP_WRITE_ERROR;
-		spin_unlock_irqrestore(&bitmap->lock, flags);
-	}
+	if (!uptodate)
+		set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
 	if (atomic_dec_and_test(&bitmap->pending_writes))
 		wake_up(&bitmap->write_wait);
 }
@@ -325,8 +312,12 @@
 }
 static void free_buffers(struct page *page)
 {
-	struct buffer_head *bh = page_buffers(page);
+	struct buffer_head *bh;
 
+	if (!PagePrivate(page))
+		return;
+
+	bh = page_buffers(page);
 	while (bh) {
 		struct buffer_head *next = bh->b_this_page;
 		free_buffer_head(bh);
@@ -343,11 +334,12 @@
  * This usage is similar to how swap files are handled, and allows us
  * to write to a file with no concerns of memory allocation failing.
  */
-static struct page *read_page(struct file *file, unsigned long index,
-			      struct bitmap *bitmap,
-			      unsigned long count)
+static int read_page(struct file *file, unsigned long index,
+		     struct bitmap *bitmap,
+		     unsigned long count,
+		     struct page *page)
 {
-	struct page *page = NULL;
+	int ret = 0;
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct buffer_head *bh;
 	sector_t block;
@@ -355,16 +347,9 @@
 	pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE,
 		 (unsigned long long)index << PAGE_SHIFT);
 
-	page = alloc_page(GFP_KERNEL);
-	if (!page)
-		page = ERR_PTR(-ENOMEM);
-	if (IS_ERR(page))
-		goto out;
-
 	bh = alloc_page_buffers(page, 1<<inode->i_blkbits, 0);
 	if (!bh) {
-		put_page(page);
-		page = ERR_PTR(-ENOMEM);
+		ret = -ENOMEM;
 		goto out;
 	}
 	attach_page_buffers(page, bh);
@@ -376,8 +361,7 @@
 			bh->b_blocknr = bmap(inode, block);
 			if (bh->b_blocknr == 0) {
 				/* Cannot use this file! */
-				free_buffers(page);
-				page = ERR_PTR(-EINVAL);
+				ret = -EINVAL;
 				goto out;
 			}
 			bh->b_bdev = inode->i_sb->s_bdev;
@@ -400,17 +384,15 @@
 
 	wait_event(bitmap->write_wait,
 		   atomic_read(&bitmap->pending_writes)==0);
-	if (bitmap->flags & BITMAP_WRITE_ERROR) {
-		free_buffers(page);
-		page = ERR_PTR(-EIO);
-	}
+	if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
+		ret = -EIO;
 out:
-	if (IS_ERR(page))
-		printk(KERN_ALERT "md: bitmap read error: (%dB @ %llu): %ld\n",
+	if (ret)
+		printk(KERN_ALERT "md: bitmap read error: (%dB @ %llu): %d\n",
 			(int)PAGE_SIZE,
 			(unsigned long long)index << PAGE_SHIFT,
-			PTR_ERR(page));
-	return page;
+			ret);
+	return ret;
 }
 
 /*
@@ -426,9 +408,9 @@
 		return;
 	if (bitmap->mddev->bitmap_info.external)
 		return;
-	if (!bitmap->sb_page) /* no superblock */
+	if (!bitmap->storage.sb_page) /* no superblock */
 		return;
-	sb = kmap_atomic(bitmap->sb_page);
+	sb = kmap_atomic(bitmap->storage.sb_page);
 	sb->events = cpu_to_le64(bitmap->mddev->events);
 	if (bitmap->mddev->events < bitmap->events_cleared)
 		/* rocking back to read-only */
@@ -438,8 +420,13 @@
 	/* Just in case these have been changed via sysfs: */
 	sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ);
 	sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind);
+	/* This might have been changed by a reshape */
+	sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors);
+	sb->chunksize = cpu_to_le32(bitmap->mddev->bitmap_info.chunksize);
+	sb->sectors_reserved = cpu_to_le32(bitmap->mddev->
+					   bitmap_info.space);
 	kunmap_atomic(sb);
-	write_page(bitmap, bitmap->sb_page, 1);
+	write_page(bitmap, bitmap->storage.sb_page, 1);
 }
 
 /* print out the bitmap file superblock */
@@ -447,9 +434,9 @@
 {
 	bitmap_super_t *sb;
 
-	if (!bitmap || !bitmap->sb_page)
+	if (!bitmap || !bitmap->storage.sb_page)
 		return;
-	sb = kmap_atomic(bitmap->sb_page);
+	sb = kmap_atomic(bitmap->storage.sb_page);
 	printk(KERN_DEBUG "%s: bitmap file superblock:\n", bmname(bitmap));
 	printk(KERN_DEBUG "         magic: %08x\n", le32_to_cpu(sb->magic));
 	printk(KERN_DEBUG "       version: %d\n", le32_to_cpu(sb->version));
@@ -488,15 +475,15 @@
 	unsigned long chunksize, daemon_sleep, write_behind;
 	int err = -EINVAL;
 
-	bitmap->sb_page = alloc_page(GFP_KERNEL);
-	if (IS_ERR(bitmap->sb_page)) {
-		err = PTR_ERR(bitmap->sb_page);
-		bitmap->sb_page = NULL;
+	bitmap->storage.sb_page = alloc_page(GFP_KERNEL);
+	if (IS_ERR(bitmap->storage.sb_page)) {
+		err = PTR_ERR(bitmap->storage.sb_page);
+		bitmap->storage.sb_page = NULL;
 		return err;
 	}
-	bitmap->sb_page->index = 0;
+	bitmap->storage.sb_page->index = 0;
 
-	sb = kmap_atomic(bitmap->sb_page);
+	sb = kmap_atomic(bitmap->storage.sb_page);
 
 	sb->magic = cpu_to_le32(BITMAP_MAGIC);
 	sb->version = cpu_to_le32(BITMAP_MAJOR_HI);
@@ -534,8 +521,8 @@
 
 	memcpy(sb->uuid, bitmap->mddev->uuid, 16);
 
-	bitmap->flags |= BITMAP_STALE;
-	sb->state |= cpu_to_le32(BITMAP_STALE);
+	set_bit(BITMAP_STALE, &bitmap->flags);
+	sb->state = cpu_to_le32(bitmap->flags);
 	bitmap->events_cleared = bitmap->mddev->events;
 	sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
 
@@ -551,31 +538,45 @@
 	bitmap_super_t *sb;
 	unsigned long chunksize, daemon_sleep, write_behind;
 	unsigned long long events;
+	unsigned long sectors_reserved = 0;
 	int err = -EINVAL;
+	struct page *sb_page;
 
+	if (!bitmap->storage.file && !bitmap->mddev->bitmap_info.offset) {
+		chunksize = 128 * 1024 * 1024;
+		daemon_sleep = 5 * HZ;
+		write_behind = 0;
+		set_bit(BITMAP_STALE, &bitmap->flags);
+		err = 0;
+		goto out_no_sb;
+	}
 	/* page 0 is the superblock, read it... */
-	if (bitmap->file) {
-		loff_t isize = i_size_read(bitmap->file->f_mapping->host);
+	sb_page = alloc_page(GFP_KERNEL);
+	if (!sb_page)
+		return -ENOMEM;
+	bitmap->storage.sb_page = sb_page;
+
+	if (bitmap->storage.file) {
+		loff_t isize = i_size_read(bitmap->storage.file->f_mapping->host);
 		int bytes = isize > PAGE_SIZE ? PAGE_SIZE : isize;
 
-		bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes);
+		err = read_page(bitmap->storage.file, 0,
+				bitmap, bytes, sb_page);
 	} else {
-		bitmap->sb_page = read_sb_page(bitmap->mddev,
-					       bitmap->mddev->bitmap_info.offset,
-					       NULL,
-					       0, sizeof(bitmap_super_t));
+		err = read_sb_page(bitmap->mddev,
+				   bitmap->mddev->bitmap_info.offset,
+				   sb_page,
+				   0, sizeof(bitmap_super_t));
 	}
-	if (IS_ERR(bitmap->sb_page)) {
-		err = PTR_ERR(bitmap->sb_page);
-		bitmap->sb_page = NULL;
+	if (err)
 		return err;
-	}
 
-	sb = kmap_atomic(bitmap->sb_page);
+	sb = kmap_atomic(sb_page);
 
 	chunksize = le32_to_cpu(sb->chunksize);
 	daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ;
 	write_behind = le32_to_cpu(sb->write_behind);
+	sectors_reserved = le32_to_cpu(sb->sectors_reserved);
 
 	/* verify that the bitmap-specific fields are valid */
 	if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
@@ -618,60 +619,32 @@
 			       "-- forcing full recovery\n",
 			       bmname(bitmap), events,
 			       (unsigned long long) bitmap->mddev->events);
-			sb->state |= cpu_to_le32(BITMAP_STALE);
+			set_bit(BITMAP_STALE, &bitmap->flags);
 		}
 	}
 
 	/* assign fields using values from superblock */
-	bitmap->mddev->bitmap_info.chunksize = chunksize;
-	bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
-	bitmap->mddev->bitmap_info.max_write_behind = write_behind;
 	bitmap->flags |= le32_to_cpu(sb->state);
 	if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
-		bitmap->flags |= BITMAP_HOSTENDIAN;
+		set_bit(BITMAP_HOSTENDIAN, &bitmap->flags);
 	bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
-	if (bitmap->flags & BITMAP_STALE)
-		bitmap->events_cleared = bitmap->mddev->events;
 	err = 0;
 out:
 	kunmap_atomic(sb);
+out_no_sb:
+	if (test_bit(BITMAP_STALE, &bitmap->flags))
+		bitmap->events_cleared = bitmap->mddev->events;
+	bitmap->mddev->bitmap_info.chunksize = chunksize;
+	bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
+	bitmap->mddev->bitmap_info.max_write_behind = write_behind;
+	if (bitmap->mddev->bitmap_info.space == 0 ||
+	    bitmap->mddev->bitmap_info.space > sectors_reserved)
+		bitmap->mddev->bitmap_info.space = sectors_reserved;
 	if (err)
 		bitmap_print_sb(bitmap);
 	return err;
 }
 
-enum bitmap_mask_op {
-	MASK_SET,
-	MASK_UNSET
-};
-
-/* record the state of the bitmap in the superblock.  Return the old value */
-static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
-			     enum bitmap_mask_op op)
-{
-	bitmap_super_t *sb;
-	int old;
-
-	if (!bitmap->sb_page) /* can't set the state */
-		return 0;
-	sb = kmap_atomic(bitmap->sb_page);
-	old = le32_to_cpu(sb->state) & bits;
-	switch (op) {
-	case MASK_SET:
-		sb->state |= cpu_to_le32(bits);
-		bitmap->flags |= bits;
-		break;
-	case MASK_UNSET:
-		sb->state &= cpu_to_le32(~bits);
-		bitmap->flags &= ~bits;
-		break;
-	default:
-		BUG();
-	}
-	kunmap_atomic(sb);
-	return old;
-}
-
 /*
  * general bitmap file operations
  */
@@ -683,17 +656,19 @@
  * file a page at a time. There's a superblock at the start of the file.
  */
 /* calculate the index of the page that contains this bit */
-static inline unsigned long file_page_index(struct bitmap *bitmap, unsigned long chunk)
+static inline unsigned long file_page_index(struct bitmap_storage *store,
+					    unsigned long chunk)
 {
-	if (!bitmap->mddev->bitmap_info.external)
+	if (store->sb_page)
 		chunk += sizeof(bitmap_super_t) << 3;
 	return chunk >> PAGE_BIT_SHIFT;
 }
 
 /* calculate the (bit) offset of this bit within a page */
-static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned long chunk)
+static inline unsigned long file_page_offset(struct bitmap_storage *store,
+					     unsigned long chunk)
 {
-	if (!bitmap->mddev->bitmap_info.external)
+	if (store->sb_page)
 		chunk += sizeof(bitmap_super_t) << 3;
 	return chunk & (PAGE_BITS - 1);
 }
@@ -705,57 +680,86 @@
  * 1 page (e.g., x86) or less than 1 page -- so the bitmap might start on page
  * 0 or page 1
  */
-static inline struct page *filemap_get_page(struct bitmap *bitmap,
+static inline struct page *filemap_get_page(struct bitmap_storage *store,
 					    unsigned long chunk)
 {
-	if (file_page_index(bitmap, chunk) >= bitmap->file_pages)
+	if (file_page_index(store, chunk) >= store->file_pages)
 		return NULL;
-	return bitmap->filemap[file_page_index(bitmap, chunk)
-			       - file_page_index(bitmap, 0)];
+	return store->filemap[file_page_index(store, chunk)
+			      - file_page_index(store, 0)];
 }
 
-static void bitmap_file_unmap(struct bitmap *bitmap)
+static int bitmap_storage_alloc(struct bitmap_storage *store,
+				unsigned long chunks, int with_super)
+{
+	int pnum;
+	unsigned long num_pages;
+	unsigned long bytes;
+
+	bytes = DIV_ROUND_UP(chunks, 8);
+	if (with_super)
+		bytes += sizeof(bitmap_super_t);
+
+	num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE);
+
+	store->filemap = kmalloc(sizeof(struct page *)
+				 * num_pages, GFP_KERNEL);
+	if (!store->filemap)
+		return -ENOMEM;
+
+	if (with_super && !store->sb_page) {
+		store->sb_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
+		if (store->sb_page == NULL)
+			return -ENOMEM;
+		store->sb_page->index = 0;
+	}
+	pnum = 0;
+	if (store->sb_page) {
+		store->filemap[0] = store->sb_page;
+		pnum = 1;
+	}
+	for ( ; pnum < num_pages; pnum++) {
+		store->filemap[pnum] = alloc_page(GFP_KERNEL|__GFP_ZERO);
+		if (!store->filemap[pnum]) {
+			store->file_pages = pnum;
+			return -ENOMEM;
+		}
+		store->filemap[pnum]->index = pnum;
+	}
+	store->file_pages = pnum;
+
+	/* We need 4 bits per page, rounded up to a multiple
+	 * of sizeof(unsigned long) */
+	store->filemap_attr = kzalloc(
+		roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
+		GFP_KERNEL);
+	if (!store->filemap_attr)
+		return -ENOMEM;
+
+	store->bytes = bytes;
+
+	return 0;
+}
+
+static void bitmap_file_unmap(struct bitmap_storage *store)
 {
 	struct page **map, *sb_page;
-	unsigned long *attr;
 	int pages;
-	unsigned long flags;
+	struct file *file;
 
-	spin_lock_irqsave(&bitmap->lock, flags);
-	map = bitmap->filemap;
-	bitmap->filemap = NULL;
-	attr = bitmap->filemap_attr;
-	bitmap->filemap_attr = NULL;
-	pages = bitmap->file_pages;
-	bitmap->file_pages = 0;
-	sb_page = bitmap->sb_page;
-	bitmap->sb_page = NULL;
-	spin_unlock_irqrestore(&bitmap->lock, flags);
+	file = store->file;
+	map = store->filemap;
+	pages = store->file_pages;
+	sb_page = store->sb_page;
 
 	while (pages--)
 		if (map[pages] != sb_page) /* 0 is sb_page, release it below */
 			free_buffers(map[pages]);
 	kfree(map);
-	kfree(attr);
+	kfree(store->filemap_attr);
 
 	if (sb_page)
 		free_buffers(sb_page);
-}
-
-static void bitmap_file_put(struct bitmap *bitmap)
-{
-	struct file *file;
-	unsigned long flags;
-
-	spin_lock_irqsave(&bitmap->lock, flags);
-	file = bitmap->file;
-	bitmap->file = NULL;
-	spin_unlock_irqrestore(&bitmap->lock, flags);
-
-	if (file)
-		wait_event(bitmap->write_wait,
-			   atomic_read(&bitmap->pending_writes)==0);
-	bitmap_file_unmap(bitmap);
 
 	if (file) {
 		struct inode *inode = file->f_path.dentry->d_inode;
@@ -773,14 +777,14 @@
 {
 	char *path, *ptr = NULL;
 
-	if (bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET) == 0) {
+	if (!test_and_set_bit(BITMAP_STALE, &bitmap->flags)) {
 		bitmap_update_sb(bitmap);
 
-		if (bitmap->file) {
+		if (bitmap->storage.file) {
 			path = kmalloc(PAGE_SIZE, GFP_KERNEL);
 			if (path)
-				ptr = d_path(&bitmap->file->f_path, path,
-					     PAGE_SIZE);
+				ptr = d_path(&bitmap->storage.file->f_path,
+					     path, PAGE_SIZE);
 
 			printk(KERN_ALERT
 			      "%s: kicking failed bitmap file %s from array!\n",
@@ -792,10 +796,6 @@
 			       "%s: disabling internal bitmap due to errors\n",
 			       bmname(bitmap));
 	}
-
-	bitmap_file_put(bitmap);
-
-	return;
 }
 
 enum bitmap_page_attr {
@@ -805,24 +805,30 @@
 	BITMAP_PAGE_NEEDWRITE = 2, /* there are cleared bits that need to be synced */
 };
 
-static inline void set_page_attr(struct bitmap *bitmap, struct page *page,
-				enum bitmap_page_attr attr)
+static inline void set_page_attr(struct bitmap *bitmap, int pnum,
+				 enum bitmap_page_attr attr)
 {
-	__set_bit((page->index<<2) + attr, bitmap->filemap_attr);
+	set_bit((pnum<<2) + attr, bitmap->storage.filemap_attr);
 }
 
-static inline void clear_page_attr(struct bitmap *bitmap, struct page *page,
-				enum bitmap_page_attr attr)
+static inline void clear_page_attr(struct bitmap *bitmap, int pnum,
+				   enum bitmap_page_attr attr)
 {
-	__clear_bit((page->index<<2) + attr, bitmap->filemap_attr);
+	clear_bit((pnum<<2) + attr, bitmap->storage.filemap_attr);
 }
 
-static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page,
+static inline int test_page_attr(struct bitmap *bitmap, int pnum,
+				 enum bitmap_page_attr attr)
+{
+	return test_bit((pnum<<2) + attr, bitmap->storage.filemap_attr);
+}
+
+static inline int test_and_clear_page_attr(struct bitmap *bitmap, int pnum,
 					   enum bitmap_page_attr attr)
 {
-	return test_bit((page->index<<2) + attr, bitmap->filemap_attr);
+	return test_and_clear_bit((pnum<<2) + attr,
+				  bitmap->storage.filemap_attr);
 }
-
 /*
  * bitmap_file_set_bit -- called before performing a write to the md device
  * to set (and eventually sync) a particular bit in the bitmap file
@@ -835,26 +841,46 @@
 	unsigned long bit;
 	struct page *page;
 	void *kaddr;
-	unsigned long chunk = block >> bitmap->chunkshift;
+	unsigned long chunk = block >> bitmap->counts.chunkshift;
 
-	if (!bitmap->filemap)
-		return;
-
-	page = filemap_get_page(bitmap, chunk);
+	page = filemap_get_page(&bitmap->storage, chunk);
 	if (!page)
 		return;
-	bit = file_page_offset(bitmap, chunk);
+	bit = file_page_offset(&bitmap->storage, chunk);
 
 	/* set the bit */
 	kaddr = kmap_atomic(page);
-	if (bitmap->flags & BITMAP_HOSTENDIAN)
+	if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
 		set_bit(bit, kaddr);
 	else
-		__set_bit_le(bit, kaddr);
+		test_and_set_bit_le(bit, kaddr);
 	kunmap_atomic(kaddr);
 	pr_debug("set file bit %lu page %lu\n", bit, page->index);
 	/* record page number so it gets flushed to disk when unplug occurs */
-	set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
+	set_page_attr(bitmap, page->index, BITMAP_PAGE_DIRTY);
+}
+
+static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
+{
+	unsigned long bit;
+	struct page *page;
+	void *paddr;
+	unsigned long chunk = block >> bitmap->counts.chunkshift;
+
+	page = filemap_get_page(&bitmap->storage, chunk);
+	if (!page)
+		return;
+	bit = file_page_offset(&bitmap->storage, chunk);
+	paddr = kmap_atomic(page);
+	if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
+		clear_bit(bit, paddr);
+	else
+		test_and_clear_bit_le(bit, paddr);
+	kunmap_atomic(paddr);
+	if (!test_page_attr(bitmap, page->index, BITMAP_PAGE_NEEDWRITE)) {
+		set_page_attr(bitmap, page->index, BITMAP_PAGE_PENDING);
+		bitmap->allclean = 0;
+	}
 }
 
 /* this gets called when the md device is ready to unplug its underlying
@@ -862,42 +888,37 @@
  * sync the dirty pages of the bitmap file to disk */
 void bitmap_unplug(struct bitmap *bitmap)
 {
-	unsigned long i, flags;
+	unsigned long i;
 	int dirty, need_write;
-	struct page *page;
 	int wait = 0;
 
-	if (!bitmap)
+	if (!bitmap || !bitmap->storage.filemap ||
+	    test_bit(BITMAP_STALE, &bitmap->flags))
 		return;
 
 	/* look at each page to see if there are any set bits that need to be
 	 * flushed out to disk */
-	for (i = 0; i < bitmap->file_pages; i++) {
-		spin_lock_irqsave(&bitmap->lock, flags);
-		if (!bitmap->filemap) {
-			spin_unlock_irqrestore(&bitmap->lock, flags);
+	for (i = 0; i < bitmap->storage.file_pages; i++) {
+		if (!bitmap->storage.filemap)
 			return;
+		dirty = test_and_clear_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
+		need_write = test_and_clear_page_attr(bitmap, i,
+						      BITMAP_PAGE_NEEDWRITE);
+		if (dirty || need_write) {
+			clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING);
+			write_page(bitmap, bitmap->storage.filemap[i], 0);
 		}
-		page = bitmap->filemap[i];
-		dirty = test_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
-		need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
-		clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
-		clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
 		if (dirty)
 			wait = 1;
-		spin_unlock_irqrestore(&bitmap->lock, flags);
-
-		if (dirty || need_write)
-			write_page(bitmap, page, 0);
 	}
 	if (wait) { /* if any writes were performed, we need to wait on them */
-		if (bitmap->file)
+		if (bitmap->storage.file)
 			wait_event(bitmap->write_wait,
 				   atomic_read(&bitmap->pending_writes)==0);
 		else
 			md_super_wait(bitmap->mddev);
 	}
-	if (bitmap->flags & BITMAP_WRITE_ERROR)
+	if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
 		bitmap_file_kick(bitmap);
 }
 EXPORT_SYMBOL(bitmap_unplug);
@@ -917,98 +938,77 @@
 static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
 {
 	unsigned long i, chunks, index, oldindex, bit;
-	struct page *page = NULL, *oldpage = NULL;
-	unsigned long num_pages, bit_cnt = 0;
+	struct page *page = NULL;
+	unsigned long bit_cnt = 0;
 	struct file *file;
-	unsigned long bytes, offset;
+	unsigned long offset;
 	int outofdate;
 	int ret = -ENOSPC;
 	void *paddr;
+	struct bitmap_storage *store = &bitmap->storage;
 
-	chunks = bitmap->chunks;
-	file = bitmap->file;
+	chunks = bitmap->counts.chunks;
+	file = store->file;
 
-	BUG_ON(!file && !bitmap->mddev->bitmap_info.offset);
+	if (!file && !bitmap->mddev->bitmap_info.offset) {
+		/* No permanent bitmap - fill with '1s'. */
+		store->filemap = NULL;
+		store->file_pages = 0;
+		for (i = 0; i < chunks ; i++) {
+			/* if the disk bit is set, set the memory bit */
+			int needed = ((sector_t)(i+1) << (bitmap->counts.chunkshift)
+				      >= start);
+			bitmap_set_memory_bits(bitmap,
+					       (sector_t)i << bitmap->counts.chunkshift,
+					       needed);
+		}
+		return 0;
+	}
 
-	outofdate = bitmap->flags & BITMAP_STALE;
+	outofdate = test_bit(BITMAP_STALE, &bitmap->flags);
 	if (outofdate)
 		printk(KERN_INFO "%s: bitmap file is out of date, doing full "
 			"recovery\n", bmname(bitmap));
 
-	bytes = DIV_ROUND_UP(bitmap->chunks, 8);
-	if (!bitmap->mddev->bitmap_info.external)
-		bytes += sizeof(bitmap_super_t);
-
-	num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE);
-
-	if (file && i_size_read(file->f_mapping->host) < bytes) {
+	if (file && i_size_read(file->f_mapping->host) < store->bytes) {
 		printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n",
-			bmname(bitmap),
-			(unsigned long) i_size_read(file->f_mapping->host),
-			bytes);
+		       bmname(bitmap),
+		       (unsigned long) i_size_read(file->f_mapping->host),
+		       store->bytes);
 		goto err;
 	}
 
-	ret = -ENOMEM;
-
-	bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
-	if (!bitmap->filemap)
-		goto err;
-
-	/* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */
-	bitmap->filemap_attr = kzalloc(
-		roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
-		GFP_KERNEL);
-	if (!bitmap->filemap_attr)
-		goto err;
-
 	oldindex = ~0L;
+	offset = 0;
+	if (!bitmap->mddev->bitmap_info.external)
+		offset = sizeof(bitmap_super_t);
 
 	for (i = 0; i < chunks; i++) {
 		int b;
-		index = file_page_index(bitmap, i);
-		bit = file_page_offset(bitmap, i);
+		index = file_page_index(&bitmap->storage, i);
+		bit = file_page_offset(&bitmap->storage, i);
 		if (index != oldindex) { /* this is a new page, read it in */
 			int count;
 			/* unmap the old page, we're done with it */
-			if (index == num_pages-1)
-				count = bytes - index * PAGE_SIZE;
+			if (index == store->file_pages-1)
+				count = store->bytes - index * PAGE_SIZE;
 			else
 				count = PAGE_SIZE;
-			if (index == 0 && bitmap->sb_page) {
-				/*
-				 * if we're here then the superblock page
-				 * contains some bits (PAGE_SIZE != sizeof sb)
-				 * we've already read it in, so just use it
-				 */
-				page = bitmap->sb_page;
-				offset = sizeof(bitmap_super_t);
-				if (!file)
-					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;
-			} else {
-				page = read_sb_page(bitmap->mddev,
-						    bitmap->mddev->bitmap_info.offset,
-						    NULL,
-						    index, count);
-				offset = 0;
-			}
-			if (IS_ERR(page)) { /* read error */
-				ret = PTR_ERR(page);
+			page = store->filemap[index];
+			if (file)
+				ret = read_page(file, index, bitmap,
+						count, page);
+			else
+				ret = read_sb_page(
+					bitmap->mddev,
+					bitmap->mddev->bitmap_info.offset,
+					page,
+					index, count);
+
+			if (ret)
 				goto err;
-			}
 
 			oldindex = index;
-			oldpage = page;
-
-			bitmap->filemap[bitmap->file_pages++] = page;
-			bitmap->last_page_size = count;
 
 			if (outofdate) {
 				/*
@@ -1022,39 +1022,33 @@
 				write_page(bitmap, page, 1);
 
 				ret = -EIO;
-				if (bitmap->flags & BITMAP_WRITE_ERROR)
+				if (test_bit(BITMAP_WRITE_ERROR,
+					     &bitmap->flags))
 					goto err;
 			}
 		}
 		paddr = kmap_atomic(page);
-		if (bitmap->flags & BITMAP_HOSTENDIAN)
+		if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
 			b = test_bit(bit, paddr);
 		else
 			b = test_bit_le(bit, paddr);
 		kunmap_atomic(paddr);
 		if (b) {
 			/* if the disk bit is set, set the memory bit */
-			int needed = ((sector_t)(i+1) << bitmap->chunkshift
+			int needed = ((sector_t)(i+1) << bitmap->counts.chunkshift
 				      >= start);
 			bitmap_set_memory_bits(bitmap,
-					       (sector_t)i << bitmap->chunkshift,
+					       (sector_t)i << bitmap->counts.chunkshift,
 					       needed);
 			bit_cnt++;
 		}
-	}
-
-	/* everything went OK */
-	ret = 0;
-	bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET);
-
-	if (bit_cnt) { /* Kick recovery if any bits were set */
-		set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery);
-		md_wakeup_thread(bitmap->mddev->thread);
+		offset = 0;
 	}
 
 	printk(KERN_INFO "%s: bitmap initialized from disk: "
-	       "read %lu/%lu pages, set %lu of %lu bits\n",
-	       bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, chunks);
+	       "read %lu pages, set %lu of %lu bits\n",
+	       bmname(bitmap), store->file_pages,
+	       bit_cnt, chunks);
 
 	return 0;
 
@@ -1071,22 +1065,38 @@
 	 */
 	int i;
 
-	spin_lock_irq(&bitmap->lock);
-	for (i = 0; i < bitmap->file_pages; i++)
-		set_page_attr(bitmap, bitmap->filemap[i],
+	if (!bitmap || !bitmap->storage.filemap)
+		return;
+	if (bitmap->storage.file)
+		/* Only one copy, so nothing needed */
+		return;
+
+	for (i = 0; i < bitmap->storage.file_pages; i++)
+		set_page_attr(bitmap, i,
 			      BITMAP_PAGE_NEEDWRITE);
 	bitmap->allclean = 0;
-	spin_unlock_irq(&bitmap->lock);
 }
 
-static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc)
+static void bitmap_count_page(struct bitmap_counts *bitmap,
+			      sector_t offset, int inc)
 {
 	sector_t chunk = offset >> bitmap->chunkshift;
 	unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
 	bitmap->bp[page].count += inc;
 	bitmap_checkfree(bitmap, page);
 }
-static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
+
+static void bitmap_set_pending(struct bitmap_counts *bitmap, sector_t offset)
+{
+	sector_t chunk = offset >> bitmap->chunkshift;
+	unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
+	struct bitmap_page *bp = &bitmap->bp[page];
+
+	if (!bp->pending)
+		bp->pending = 1;
+}
+
+static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap,
 					    sector_t offset, sector_t *blocks,
 					    int create);
 
@@ -1099,10 +1109,9 @@
 {
 	struct bitmap *bitmap;
 	unsigned long j;
-	unsigned long flags;
-	struct page *page = NULL, *lastpage = NULL;
+	unsigned long nextpage;
 	sector_t blocks;
-	void *paddr;
+	struct bitmap_counts *counts;
 
 	/* Use a mutex to guard daemon_work against
 	 * bitmap_destroy.
@@ -1124,112 +1133,90 @@
 	}
 	bitmap->allclean = 1;
 
-	spin_lock_irqsave(&bitmap->lock, flags);
-	for (j = 0; j < bitmap->chunks; j++) {
-		bitmap_counter_t *bmc;
-		if (!bitmap->filemap)
-			/* error or shutdown */
-			break;
+	/* Any file-page which is PENDING now needs to be written.
+	 * So set NEEDWRITE now, then after we make any last-minute changes
+	 * we will write it.
+	 */
+	for (j = 0; j < bitmap->storage.file_pages; j++)
+		if (test_and_clear_page_attr(bitmap, j,
+					     BITMAP_PAGE_PENDING))
+			set_page_attr(bitmap, j,
+				      BITMAP_PAGE_NEEDWRITE);
 
-		page = filemap_get_page(bitmap, j);
-
-		if (page != lastpage) {
-			/* skip this page unless it's marked as needing cleaning */
-			if (!test_page_attr(bitmap, page, BITMAP_PAGE_PENDING)) {
-				int need_write = test_page_attr(bitmap, page,
-								BITMAP_PAGE_NEEDWRITE);
-				if (need_write)
-					clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
-
-				spin_unlock_irqrestore(&bitmap->lock, flags);
-				if (need_write)
-					write_page(bitmap, page, 0);
-				spin_lock_irqsave(&bitmap->lock, flags);
-				j |= (PAGE_BITS - 1);
-				continue;
-			}
-
-			/* grab the new page, sync and release the old */
-			if (lastpage != NULL) {
-				if (test_page_attr(bitmap, lastpage,
-						   BITMAP_PAGE_NEEDWRITE)) {
-					clear_page_attr(bitmap, lastpage,
-							BITMAP_PAGE_NEEDWRITE);
-					spin_unlock_irqrestore(&bitmap->lock, flags);
-					write_page(bitmap, lastpage, 0);
-				} else {
-					set_page_attr(bitmap, lastpage,
-						      BITMAP_PAGE_NEEDWRITE);
-					bitmap->allclean = 0;
-					spin_unlock_irqrestore(&bitmap->lock, flags);
-				}
-			} else
-				spin_unlock_irqrestore(&bitmap->lock, flags);
-			lastpage = page;
-
-			/* We are possibly going to clear some bits, so make
-			 * sure that events_cleared is up-to-date.
-			 */
-			if (bitmap->need_sync &&
-			    mddev->bitmap_info.external == 0) {
-				bitmap_super_t *sb;
-				bitmap->need_sync = 0;
-				sb = kmap_atomic(bitmap->sb_page);
-				sb->events_cleared =
-					cpu_to_le64(bitmap->events_cleared);
-				kunmap_atomic(sb);
-				write_page(bitmap, bitmap->sb_page, 1);
-			}
-			spin_lock_irqsave(&bitmap->lock, flags);
-			if (!bitmap->need_sync)
-				clear_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
-			else
-				bitmap->allclean = 0;
-		}
-		bmc = bitmap_get_counter(bitmap,
-					 (sector_t)j << bitmap->chunkshift,
-					 &blocks, 0);
-		if (!bmc)
-			j |= PAGE_COUNTER_MASK;
-		else if (*bmc) {
-			if (*bmc == 1 && !bitmap->need_sync) {
-				/* we can clear the bit */
-				*bmc = 0;
-				bitmap_count_page(bitmap,
-						  (sector_t)j << bitmap->chunkshift,
-						  -1);
-
-				/* clear the bit */
-				paddr = kmap_atomic(page);
-				if (bitmap->flags & BITMAP_HOSTENDIAN)
-					clear_bit(file_page_offset(bitmap, j),
-						  paddr);
-				else
-					__clear_bit_le(
-						file_page_offset(bitmap,
-								 j),
-						paddr);
-				kunmap_atomic(paddr);
-			} else if (*bmc <= 2) {
-				*bmc = 1; /* maybe clear the bit next time */
-				set_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
-				bitmap->allclean = 0;
-			}
+	if (bitmap->need_sync &&
+	    mddev->bitmap_info.external == 0) {
+		/* Arrange for superblock update as well as
+		 * other changes */
+		bitmap_super_t *sb;
+		bitmap->need_sync = 0;
+		if (bitmap->storage.filemap) {
+			sb = kmap_atomic(bitmap->storage.sb_page);
+			sb->events_cleared =
+				cpu_to_le64(bitmap->events_cleared);
+			kunmap_atomic(sb);
+			set_page_attr(bitmap, 0,
+				      BITMAP_PAGE_NEEDWRITE);
 		}
 	}
-	spin_unlock_irqrestore(&bitmap->lock, flags);
+	/* Now look at the bitmap counters and if any are '2' or '1',
+	 * decrement and handle accordingly.
+	 */
+	counts = &bitmap->counts;
+	spin_lock_irq(&counts->lock);
+	nextpage = 0;
+	for (j = 0; j < counts->chunks; j++) {
+		bitmap_counter_t *bmc;
+		sector_t  block = (sector_t)j << counts->chunkshift;
 
-	/* now sync the final page */
-	if (lastpage != NULL) {
-		spin_lock_irqsave(&bitmap->lock, flags);
-		if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
-			clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
-			spin_unlock_irqrestore(&bitmap->lock, flags);
-			write_page(bitmap, lastpage, 0);
-		} else {
-			set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
+		if (j == nextpage) {
+			nextpage += PAGE_COUNTER_RATIO;
+			if (!counts->bp[j >> PAGE_COUNTER_SHIFT].pending) {
+				j |= PAGE_COUNTER_MASK;
+				continue;
+			}
+			counts->bp[j >> PAGE_COUNTER_SHIFT].pending = 0;
+		}
+		bmc = bitmap_get_counter(counts,
+					 block,
+					 &blocks, 0);
+
+		if (!bmc) {
+			j |= PAGE_COUNTER_MASK;
+			continue;
+		}
+		if (*bmc == 1 && !bitmap->need_sync) {
+			/* We can clear the bit */
+			*bmc = 0;
+			bitmap_count_page(counts, block, -1);
+			bitmap_file_clear_bit(bitmap, block);
+		} else if (*bmc && *bmc <= 2) {
+			*bmc = 1;
+			bitmap_set_pending(counts, block);
 			bitmap->allclean = 0;
-			spin_unlock_irqrestore(&bitmap->lock, flags);
+		}
+	}
+	spin_unlock_irq(&counts->lock);
+
+	/* Now start writeout on any page in NEEDWRITE that isn't DIRTY.
+	 * DIRTY pages need to be written by bitmap_unplug so it can wait
+	 * for them.
+	 * If we find any DIRTY page we stop there and let bitmap_unplug
+	 * handle all the rest.  This is important in the case where
+	 * the first blocking holds the superblock and it has been updated.
+	 * We mustn't write any other blocks before the superblock.
+	 */
+	for (j = 0;
+	     j < bitmap->storage.file_pages
+		     && !test_bit(BITMAP_STALE, &bitmap->flags);
+	     j++) {
+
+		if (test_page_attr(bitmap, j,
+				   BITMAP_PAGE_DIRTY))
+			/* bitmap_unplug will handle the rest */
+			break;
+		if (test_and_clear_page_attr(bitmap, j,
+					     BITMAP_PAGE_NEEDWRITE)) {
+			write_page(bitmap, bitmap->storage.filemap[j], 0);
 		}
 	}
 
@@ -1240,7 +1227,7 @@
 	mutex_unlock(&mddev->bitmap_info.mutex);
 }
 
-static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
+static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap,
 					    sector_t offset, sector_t *blocks,
 					    int create)
 __releases(bitmap->lock)
@@ -1302,10 +1289,10 @@
 		sector_t blocks;
 		bitmap_counter_t *bmc;
 
-		spin_lock_irq(&bitmap->lock);
-		bmc = bitmap_get_counter(bitmap, offset, &blocks, 1);
+		spin_lock_irq(&bitmap->counts.lock);
+		bmc = bitmap_get_counter(&bitmap->counts, offset, &blocks, 1);
 		if (!bmc) {
-			spin_unlock_irq(&bitmap->lock);
+			spin_unlock_irq(&bitmap->counts.lock);
 			return 0;
 		}
 
@@ -1317,7 +1304,7 @@
 			 */
 			prepare_to_wait(&bitmap->overflow_wait, &__wait,
 					TASK_UNINTERRUPTIBLE);
-			spin_unlock_irq(&bitmap->lock);
+			spin_unlock_irq(&bitmap->counts.lock);
 			io_schedule();
 			finish_wait(&bitmap->overflow_wait, &__wait);
 			continue;
@@ -1326,7 +1313,7 @@
 		switch (*bmc) {
 		case 0:
 			bitmap_file_set_bit(bitmap, offset);
-			bitmap_count_page(bitmap, offset, 1);
+			bitmap_count_page(&bitmap->counts, offset, 1);
 			/* fall through */
 		case 1:
 			*bmc = 2;
@@ -1334,7 +1321,7 @@
 
 		(*bmc)++;
 
-		spin_unlock_irq(&bitmap->lock);
+		spin_unlock_irq(&bitmap->counts.lock);
 
 		offset += blocks;
 		if (sectors > blocks)
@@ -1364,10 +1351,10 @@
 		unsigned long flags;
 		bitmap_counter_t *bmc;
 
-		spin_lock_irqsave(&bitmap->lock, flags);
-		bmc = bitmap_get_counter(bitmap, offset, &blocks, 0);
+		spin_lock_irqsave(&bitmap->counts.lock, flags);
+		bmc = bitmap_get_counter(&bitmap->counts, offset, &blocks, 0);
 		if (!bmc) {
-			spin_unlock_irqrestore(&bitmap->lock, flags);
+			spin_unlock_irqrestore(&bitmap->counts.lock, flags);
 			return;
 		}
 
@@ -1386,14 +1373,10 @@
 
 		(*bmc)--;
 		if (*bmc <= 2) {
-			set_page_attr(bitmap,
-				      filemap_get_page(
-					      bitmap,
-					      offset >> bitmap->chunkshift),
-				      BITMAP_PAGE_PENDING);
+			bitmap_set_pending(&bitmap->counts, offset);
 			bitmap->allclean = 0;
 		}
-		spin_unlock_irqrestore(&bitmap->lock, flags);
+		spin_unlock_irqrestore(&bitmap->counts.lock, flags);
 		offset += blocks;
 		if (sectors > blocks)
 			sectors -= blocks;
@@ -1412,8 +1395,8 @@
 		*blocks = 1024;
 		return 1; /* always resync if no bitmap */
 	}
-	spin_lock_irq(&bitmap->lock);
-	bmc = bitmap_get_counter(bitmap, offset, blocks, 0);
+	spin_lock_irq(&bitmap->counts.lock);
+	bmc = bitmap_get_counter(&bitmap->counts, offset, blocks, 0);
 	rv = 0;
 	if (bmc) {
 		/* locked */
@@ -1427,7 +1410,7 @@
 			}
 		}
 	}
-	spin_unlock_irq(&bitmap->lock);
+	spin_unlock_irq(&bitmap->counts.lock);
 	return rv;
 }
 
@@ -1464,8 +1447,8 @@
 		*blocks = 1024;
 		return;
 	}
-	spin_lock_irqsave(&bitmap->lock, flags);
-	bmc = bitmap_get_counter(bitmap, offset, blocks, 0);
+	spin_lock_irqsave(&bitmap->counts.lock, flags);
+	bmc = bitmap_get_counter(&bitmap->counts, offset, blocks, 0);
 	if (bmc == NULL)
 		goto unlock;
 	/* locked */
@@ -1476,15 +1459,13 @@
 			*bmc |= NEEDED_MASK;
 		else {
 			if (*bmc <= 2) {
-				set_page_attr(bitmap,
-					      filemap_get_page(bitmap, offset >> bitmap->chunkshift),
-					      BITMAP_PAGE_PENDING);
+				bitmap_set_pending(&bitmap->counts, offset);
 				bitmap->allclean = 0;
 			}
 		}
 	}
  unlock:
-	spin_unlock_irqrestore(&bitmap->lock, flags);
+	spin_unlock_irqrestore(&bitmap->counts.lock, flags);
 }
 EXPORT_SYMBOL(bitmap_end_sync);
 
@@ -1524,7 +1505,7 @@
 
 	bitmap->mddev->curr_resync_completed = sector;
 	set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags);
-	sector &= ~((1ULL << bitmap->chunkshift) - 1);
+	sector &= ~((1ULL << bitmap->counts.chunkshift) - 1);
 	s = 0;
 	while (s < sector && s < bitmap->mddev->resync_max_sectors) {
 		bitmap_end_sync(bitmap, s, &blocks, 0);
@@ -1538,27 +1519,25 @@
 static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed)
 {
 	/* For each chunk covered by any of these sectors, set the
-	 * counter to 1 and set resync_needed.  They should all
+	 * counter to 2 and possibly set resync_needed.  They should all
 	 * be 0 at this point
 	 */
 
 	sector_t secs;
 	bitmap_counter_t *bmc;
-	spin_lock_irq(&bitmap->lock);
-	bmc = bitmap_get_counter(bitmap, offset, &secs, 1);
+	spin_lock_irq(&bitmap->counts.lock);
+	bmc = bitmap_get_counter(&bitmap->counts, offset, &secs, 1);
 	if (!bmc) {
-		spin_unlock_irq(&bitmap->lock);
+		spin_unlock_irq(&bitmap->counts.lock);
 		return;
 	}
 	if (!*bmc) {
-		struct page *page;
 		*bmc = 2 | (needed ? NEEDED_MASK : 0);
-		bitmap_count_page(bitmap, offset, 1);
-		page = filemap_get_page(bitmap, offset >> bitmap->chunkshift);
-		set_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
+		bitmap_count_page(&bitmap->counts, offset, 1);
+		bitmap_set_pending(&bitmap->counts, offset);
 		bitmap->allclean = 0;
 	}
-	spin_unlock_irq(&bitmap->lock);
+	spin_unlock_irq(&bitmap->counts.lock);
 }
 
 /* dirty the memory and file bits for bitmap chunks "s" to "e" */
@@ -1567,11 +1546,9 @@
 	unsigned long chunk;
 
 	for (chunk = s; chunk <= e; chunk++) {
-		sector_t sec = (sector_t)chunk << bitmap->chunkshift;
+		sector_t sec = (sector_t)chunk << bitmap->counts.chunkshift;
 		bitmap_set_memory_bits(bitmap, sec, 1);
-		spin_lock_irq(&bitmap->lock);
 		bitmap_file_set_bit(bitmap, sec);
-		spin_unlock_irq(&bitmap->lock);
 		if (sec < bitmap->mddev->recovery_cp)
 			/* We are asserting that the array is dirty,
 			 * so move the recovery_cp address back so
@@ -1616,11 +1593,15 @@
 	if (!bitmap) /* there was no bitmap */
 		return;
 
-	/* release the bitmap file and kill the daemon */
-	bitmap_file_put(bitmap);
+	/* Shouldn't be needed - but just in case.... */
+	wait_event(bitmap->write_wait,
+		   atomic_read(&bitmap->pending_writes) == 0);
 
-	bp = bitmap->bp;
-	pages = bitmap->pages;
+	/* release the bitmap file  */
+	bitmap_file_unmap(&bitmap->storage);
+
+	bp = bitmap->counts.bp;
+	pages = bitmap->counts.pages;
 
 	/* free all allocated memory */
 
@@ -1659,25 +1640,19 @@
 {
 	struct bitmap *bitmap;
 	sector_t blocks = mddev->resync_max_sectors;
-	unsigned long chunks;
-	unsigned long pages;
 	struct file *file = mddev->bitmap_info.file;
 	int err;
 	struct sysfs_dirent *bm = NULL;
 
 	BUILD_BUG_ON(sizeof(bitmap_super_t) != 256);
 
-	if (!file
-	    && !mddev->bitmap_info.offset) /* bitmap disabled, nothing to do */
-		return 0;
-
 	BUG_ON(file && mddev->bitmap_info.offset);
 
 	bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL);
 	if (!bitmap)
 		return -ENOMEM;
 
-	spin_lock_init(&bitmap->lock);
+	spin_lock_init(&bitmap->counts.lock);
 	atomic_set(&bitmap->pending_writes, 0);
 	init_waitqueue_head(&bitmap->write_wait);
 	init_waitqueue_head(&bitmap->overflow_wait);
@@ -1693,7 +1668,7 @@
 	} else
 		bitmap->sysfs_can_clear = NULL;
 
-	bitmap->file = file;
+	bitmap->storage.file = file;
 	if (file) {
 		get_file(file);
 		/* As future accesses to this file will use bmap,
@@ -1724,32 +1699,15 @@
 		goto error;
 
 	bitmap->daemon_lastrun = jiffies;
-	bitmap->chunkshift = (ffz(~mddev->bitmap_info.chunksize)
-			      - BITMAP_BLOCK_SHIFT);
-
-	chunks = (blocks + (1 << bitmap->chunkshift) - 1) >>
-			bitmap->chunkshift;
-	pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO;
-
-	BUG_ON(!pages);
-
-	bitmap->chunks = chunks;
-	bitmap->pages = pages;
-	bitmap->missing_pages = pages;
-
-	bitmap->bp = kzalloc(pages * sizeof(*bitmap->bp), GFP_KERNEL);
-
-	err = -ENOMEM;
-	if (!bitmap->bp)
+	err = bitmap_resize(bitmap, blocks, mddev->bitmap_info.chunksize, 1);
+	if (err)
 		goto error;
 
 	printk(KERN_INFO "created bitmap (%lu pages) for device %s\n",
-		pages, bmname(bitmap));
+	       bitmap->counts.pages, bmname(bitmap));
 
 	mddev->bitmap = bitmap;
-
-
-	return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0;
+	return test_bit(BITMAP_WRITE_ERROR, &bitmap->flags) ? -EIO : 0;
 
  error:
 	bitmap_free(bitmap);
@@ -1790,13 +1748,17 @@
 
 	if (err)
 		goto out;
+	clear_bit(BITMAP_STALE, &bitmap->flags);
+
+	/* Kick recovery in case any bits were set */
+	set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery);
 
 	mddev->thread->timeout = mddev->bitmap_info.daemon_sleep;
 	md_wakeup_thread(mddev->thread);
 
 	bitmap_update_sb(bitmap);
 
-	if (bitmap->flags & BITMAP_WRITE_ERROR)
+	if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
 		err = -EIO;
 out:
 	return err;
@@ -1806,30 +1768,194 @@
 void bitmap_status(struct seq_file *seq, struct bitmap *bitmap)
 {
 	unsigned long chunk_kb;
-	unsigned long flags;
+	struct bitmap_counts *counts;
 
 	if (!bitmap)
 		return;
 
-	spin_lock_irqsave(&bitmap->lock, flags);
+	counts = &bitmap->counts;
+
 	chunk_kb = bitmap->mddev->bitmap_info.chunksize >> 10;
 	seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], "
 		   "%lu%s chunk",
-		   bitmap->pages - bitmap->missing_pages,
-		   bitmap->pages,
-		   (bitmap->pages - bitmap->missing_pages)
+		   counts->pages - counts->missing_pages,
+		   counts->pages,
+		   (counts->pages - counts->missing_pages)
 		   << (PAGE_SHIFT - 10),
 		   chunk_kb ? chunk_kb : bitmap->mddev->bitmap_info.chunksize,
 		   chunk_kb ? "KB" : "B");
-	if (bitmap->file) {
+	if (bitmap->storage.file) {
 		seq_printf(seq, ", file: ");
-		seq_path(seq, &bitmap->file->f_path, " \t\n");
+		seq_path(seq, &bitmap->storage.file->f_path, " \t\n");
 	}
 
 	seq_printf(seq, "\n");
-	spin_unlock_irqrestore(&bitmap->lock, flags);
 }
 
+int bitmap_resize(struct bitmap *bitmap, sector_t blocks,
+		  int chunksize, int init)
+{
+	/* If chunk_size is 0, choose an appropriate chunk size.
+	 * Then possibly allocate new storage space.
+	 * Then quiesce, copy bits, replace bitmap, and re-start
+	 *
+	 * This function is called both to set up the initial bitmap
+	 * and to resize the bitmap while the array is active.
+	 * If this happens as a result of the array being resized,
+	 * chunksize will be zero, and we need to choose a suitable
+	 * chunksize, otherwise we use what we are given.
+	 */
+	struct bitmap_storage store;
+	struct bitmap_counts old_counts;
+	unsigned long chunks;
+	sector_t block;
+	sector_t old_blocks, new_blocks;
+	int chunkshift;
+	int ret = 0;
+	long pages;
+	struct bitmap_page *new_bp;
+
+	if (chunksize == 0) {
+		/* If there is enough space, leave the chunk size unchanged,
+		 * else increase by factor of two until there is enough space.
+		 */
+		long bytes;
+		long space = bitmap->mddev->bitmap_info.space;
+
+		if (space == 0) {
+			/* We don't know how much space there is, so limit
+			 * to current size - in sectors.
+			 */
+			bytes = DIV_ROUND_UP(bitmap->counts.chunks, 8);
+			if (!bitmap->mddev->bitmap_info.external)
+				bytes += sizeof(bitmap_super_t);
+			space = DIV_ROUND_UP(bytes, 512);
+			bitmap->mddev->bitmap_info.space = space;
+		}
+		chunkshift = bitmap->counts.chunkshift;
+		chunkshift--;
+		do {
+			/* 'chunkshift' is shift from block size to chunk size */
+			chunkshift++;
+			chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift);
+			bytes = DIV_ROUND_UP(chunks, 8);
+			if (!bitmap->mddev->bitmap_info.external)
+				bytes += sizeof(bitmap_super_t);
+		} while (bytes > (space << 9));
+	} else
+		chunkshift = ffz(~chunksize) - BITMAP_BLOCK_SHIFT;
+
+	chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift);
+	memset(&store, 0, sizeof(store));
+	if (bitmap->mddev->bitmap_info.offset || bitmap->mddev->bitmap_info.file)
+		ret = bitmap_storage_alloc(&store, chunks,
+					   !bitmap->mddev->bitmap_info.external);
+	if (ret)
+		goto err;
+
+	pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO);
+
+	new_bp = kzalloc(pages * sizeof(*new_bp), GFP_KERNEL);
+	ret = -ENOMEM;
+	if (!new_bp) {
+		bitmap_file_unmap(&store);
+		goto err;
+	}
+
+	if (!init)
+		bitmap->mddev->pers->quiesce(bitmap->mddev, 1);
+
+	store.file = bitmap->storage.file;
+	bitmap->storage.file = NULL;
+
+	if (store.sb_page && bitmap->storage.sb_page)
+		memcpy(page_address(store.sb_page),
+		       page_address(bitmap->storage.sb_page),
+		       sizeof(bitmap_super_t));
+	bitmap_file_unmap(&bitmap->storage);
+	bitmap->storage = store;
+
+	old_counts = bitmap->counts;
+	bitmap->counts.bp = new_bp;
+	bitmap->counts.pages = pages;
+	bitmap->counts.missing_pages = pages;
+	bitmap->counts.chunkshift = chunkshift;
+	bitmap->counts.chunks = chunks;
+	bitmap->mddev->bitmap_info.chunksize = 1 << (chunkshift +
+						     BITMAP_BLOCK_SHIFT);
+
+	blocks = min(old_counts.chunks << old_counts.chunkshift,
+		     chunks << chunkshift);
+
+	spin_lock_irq(&bitmap->counts.lock);
+	for (block = 0; block < blocks; ) {
+		bitmap_counter_t *bmc_old, *bmc_new;
+		int set;
+
+		bmc_old = bitmap_get_counter(&old_counts, block,
+					     &old_blocks, 0);
+		set = bmc_old && NEEDED(*bmc_old);
+
+		if (set) {
+			bmc_new = bitmap_get_counter(&bitmap->counts, block,
+						     &new_blocks, 1);
+			if (*bmc_new == 0) {
+				/* need to set on-disk bits too. */
+				sector_t end = block + new_blocks;
+				sector_t start = block >> chunkshift;
+				start <<= chunkshift;
+				while (start < end) {
+					bitmap_file_set_bit(bitmap, block);
+					start += 1 << chunkshift;
+				}
+				*bmc_new = 2;
+				bitmap_count_page(&bitmap->counts,
+						  block, 1);
+				bitmap_set_pending(&bitmap->counts,
+						   block);
+			}
+			*bmc_new |= NEEDED_MASK;
+			if (new_blocks < old_blocks)
+				old_blocks = new_blocks;
+		}
+		block += old_blocks;
+	}
+
+	if (!init) {
+		int i;
+		while (block < (chunks << chunkshift)) {
+			bitmap_counter_t *bmc;
+			bmc = bitmap_get_counter(&bitmap->counts, block,
+						 &new_blocks, 1);
+			if (bmc) {
+				/* new space.  It needs to be resynced, so
+				 * we set NEEDED_MASK.
+				 */
+				if (*bmc == 0) {
+					*bmc = NEEDED_MASK | 2;
+					bitmap_count_page(&bitmap->counts,
+							  block, 1);
+					bitmap_set_pending(&bitmap->counts,
+							   block);
+				}
+			}
+			block += new_blocks;
+		}
+		for (i = 0; i < bitmap->storage.file_pages; i++)
+			set_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
+	}
+	spin_unlock_irq(&bitmap->counts.lock);
+
+	if (!init) {
+		bitmap_unplug(bitmap);
+		bitmap->mddev->pers->quiesce(bitmap->mddev, 0);
+	}
+	ret = 0;
+err:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bitmap_resize);
+
 static ssize_t
 location_show(struct mddev *mddev, char *page)
 {
@@ -1923,6 +2049,43 @@
 static struct md_sysfs_entry bitmap_location =
 __ATTR(location, S_IRUGO|S_IWUSR, location_show, location_store);
 
+/* 'bitmap/space' is the space available at 'location' for the
+ * bitmap.  This allows the kernel to know when it is safe to
+ * resize the bitmap to match a resized array.
+ */
+static ssize_t
+space_show(struct mddev *mddev, char *page)
+{
+	return sprintf(page, "%lu\n", mddev->bitmap_info.space);
+}
+
+static ssize_t
+space_store(struct mddev *mddev, const char *buf, size_t len)
+{
+	unsigned long sectors;
+	int rv;
+
+	rv = kstrtoul(buf, 10, &sectors);
+	if (rv)
+		return rv;
+
+	if (sectors == 0)
+		return -EINVAL;
+
+	if (mddev->bitmap &&
+	    sectors < (mddev->bitmap->storage.bytes + 511) >> 9)
+		return -EFBIG; /* Bitmap is too big for this small space */
+
+	/* could make sure it isn't too big, but that isn't really
+	 * needed - user-space should be careful.
+	 */
+	mddev->bitmap_info.space = sectors;
+	return len;
+}
+
+static struct md_sysfs_entry bitmap_space =
+__ATTR(space, S_IRUGO|S_IWUSR, space_show, space_store);
+
 static ssize_t
 timeout_show(struct mddev *mddev, char *page)
 {
@@ -2098,6 +2261,7 @@
 
 static struct attribute *md_bitmap_attrs[] = {
 	&bitmap_location.attr,
+	&bitmap_space.attr,
 	&bitmap_timeout.attr,
 	&bitmap_backlog.attr,
 	&bitmap_chunksize.attr,
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h
index b44b0aba..df4aeb6 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -111,9 +111,9 @@
 
 /* use these for bitmap->flags and bitmap->sb->state bit-fields */
 enum bitmap_state {
-	BITMAP_STALE  = 0x002,  /* the bitmap file is out of date or had -EIO */
-	BITMAP_WRITE_ERROR = 0x004, /* A write error has occurred */
-	BITMAP_HOSTENDIAN = 0x8000,
+	BITMAP_STALE	   = 1,  /* the bitmap file is out of date or had -EIO */
+	BITMAP_WRITE_ERROR = 2, /* A write error has occurred */
+	BITMAP_HOSTENDIAN  =15,
 };
 
 /* the superblock at the front of the bitmap file -- little endian */
@@ -128,8 +128,10 @@
 	__le32 chunksize;    /* 52  the bitmap chunk size in bytes */
 	__le32 daemon_sleep; /* 56  seconds between disk flushes */
 	__le32 write_behind; /* 60  number of outstanding write-behind writes */
+	__le32 sectors_reserved; /* 64 number of 512-byte sectors that are
+				  * reserved for the bitmap. */
 
-	__u8  pad[256 - 64]; /* set to zero */
+	__u8  pad[256 - 68]; /* set to zero */
 } bitmap_super_t;
 
 /* notes:
@@ -160,35 +162,48 @@
 	 */
 	unsigned int hijacked:1;
 	/*
+	 * If any counter in this page is '1' or '2' - and so could be
+	 * cleared then that page is marked as 'pending'
+	 */
+	unsigned int pending:1;
+	/*
 	 * count of dirty bits on the page
 	 */
-	unsigned int  count:31;
+	unsigned int  count:30;
 };
 
 /* the main bitmap structure - one per mddev */
 struct bitmap {
-	struct bitmap_page *bp;
-	unsigned long pages; /* total number of pages in the bitmap */
-	unsigned long missing_pages; /* number of pages not yet allocated */
+
+	struct bitmap_counts {
+		spinlock_t lock;
+		struct bitmap_page *bp;
+		unsigned long pages;		/* total number of pages
+						 * in the bitmap */
+		unsigned long missing_pages;	/* number of pages
+						 * not yet allocated */
+		unsigned long chunkshift;	/* chunksize = 2^chunkshift
+						 * (for bitops) */
+		unsigned long chunks;		/* Total number of data
+						 * chunks for the array */
+	} counts;
 
 	struct mddev *mddev; /* the md device that the bitmap is for */
 
-	/* bitmap chunksize -- how much data does each bit represent? */
-	unsigned long chunkshift; /* chunksize = 2^(chunkshift+9) (for bitops) */
-	unsigned long chunks; /* total number of data chunks for the array */
-
 	__u64	events_cleared;
 	int need_sync;
 
-	/* bitmap spinlock */
-	spinlock_t lock;
-
-	struct file *file; /* backing disk file */
-	struct page *sb_page; /* cached copy of the bitmap file superblock */
-	struct page **filemap; /* list of cache pages for the file */
-	unsigned long *filemap_attr; /* attributes associated w/ filemap pages */
-	unsigned long file_pages; /* number of pages in the file */
-	int last_page_size; /* bytes in the last page */
+	struct bitmap_storage {
+		struct file *file;		/* backing disk file */
+		struct page *sb_page;		/* cached copy of the bitmap
+						 * file superblock */
+		struct page **filemap;		/* list of cache pages for
+						 * the file */
+		unsigned long *filemap_attr;	/* attributes associated
+						 * w/ filemap pages */
+		unsigned long file_pages;	/* number of pages in the file*/
+		unsigned long bytes;		/* total bytes in the bitmap */
+	} storage;
 
 	unsigned long flags;
 
@@ -242,6 +257,9 @@
 
 void bitmap_unplug(struct bitmap *bitmap);
 void bitmap_daemon_work(struct mddev *mddev);
+
+int bitmap_resize(struct bitmap *bitmap, sector_t blocks,
+		  int chunksize, int init);
 #endif
 
 #endif
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 68965e6..017c34d 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -155,10 +155,7 @@
 	for (i = 0; i < rs->md.raid_disks; i++) {
 		if (rs->dev[i].meta_dev)
 			dm_put_device(rs->ti, rs->dev[i].meta_dev);
-		if (rs->dev[i].rdev.sb_page)
-			put_page(rs->dev[i].rdev.sb_page);
-		rs->dev[i].rdev.sb_page = NULL;
-		rs->dev[i].rdev.sb_loaded = 0;
+		md_rdev_clear(&rs->dev[i].rdev);
 		if (rs->dev[i].data_dev)
 			dm_put_device(rs->ti, rs->dev[i].data_dev);
 	}
@@ -606,7 +603,7 @@
 	if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) {
 		DMERR("Failed to read superblock of device at position %d",
 		      rdev->raid_disk);
-		set_bit(Faulty, &rdev->flags);
+		md_error(rdev->mddev, rdev);
 		return -EINVAL;
 	}
 
@@ -617,16 +614,18 @@
 
 static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
 {
-	struct md_rdev *r;
+	int i;
 	uint64_t failed_devices;
 	struct dm_raid_superblock *sb;
+	struct raid_set *rs = container_of(mddev, struct raid_set, md);
 
 	sb = page_address(rdev->sb_page);
 	failed_devices = le64_to_cpu(sb->failed_devices);
 
-	rdev_for_each(r, mddev)
-		if ((r->raid_disk >= 0) && test_bit(Faulty, &r->flags))
-			failed_devices |= (1ULL << r->raid_disk);
+	for (i = 0; i < mddev->raid_disks; i++)
+		if (!rs->dev[i].data_dev ||
+		    test_bit(Faulty, &(rs->dev[i].rdev.flags)))
+			failed_devices |= (1ULL << i);
 
 	memset(sb, 0, sizeof(*sb));
 
@@ -1252,12 +1251,13 @@
 {
 	struct raid_set *rs = ti->private;
 
+	set_bit(MD_CHANGE_DEVS, &rs->md.flags);
 	if (!rs->bitmap_loaded) {
 		bitmap_load(&rs->md);
 		rs->bitmap_loaded = 1;
-	} else
-		md_wakeup_thread(rs->md.thread);
+	}
 
+	clear_bit(MD_RECOVERY_FROZEN, &rs->md.recovery);
 	mddev_resume(&rs->md);
 }
 
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 01233d8..1c2f904 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -402,6 +402,7 @@
 	wake_up(&mddev->sb_wait);
 	mddev->pers->quiesce(mddev, 0);
 
+	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 	md_wakeup_thread(mddev->thread);
 	md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
 }
@@ -452,7 +453,7 @@
 			atomic_inc(&rdev->nr_pending);
 			atomic_inc(&rdev->nr_pending);
 			rcu_read_unlock();
-			bi = bio_alloc_mddev(GFP_KERNEL, 0, mddev);
+			bi = bio_alloc_mddev(GFP_NOIO, 0, mddev);
 			bi->bi_end_io = md_end_flush;
 			bi->bi_private = rdev;
 			bi->bi_bdev = rdev->bdev;
@@ -607,6 +608,7 @@
 	init_waitqueue_head(&mddev->sb_wait);
 	init_waitqueue_head(&mddev->recovery_wait);
 	mddev->reshape_position = MaxSector;
+	mddev->reshape_backwards = 0;
 	mddev->resync_min = 0;
 	mddev->resync_max = MaxSector;
 	mddev->level = LEVEL_NONE;
@@ -802,7 +804,7 @@
 	return 0;
 }
 
-static void free_disk_sb(struct md_rdev * rdev)
+void md_rdev_clear(struct md_rdev *rdev)
 {
 	if (rdev->sb_page) {
 		put_page(rdev->sb_page);
@@ -815,8 +817,10 @@
 		put_page(rdev->bb_page);
 		rdev->bb_page = NULL;
 	}
+	kfree(rdev->badblocks.page);
+	rdev->badblocks.page = NULL;
 }
-
+EXPORT_SYMBOL_GPL(md_rdev_clear);
 
 static void super_written(struct bio *bio, int error)
 {
@@ -887,6 +891,10 @@
 		rdev->meta_bdev : rdev->bdev;
 	if (metadata_op)
 		bio->bi_sector = sector + rdev->sb_start;
+	else if (rdev->mddev->reshape_position != MaxSector &&
+		 (rdev->mddev->reshape_backwards ==
+		  (sector >= rdev->mddev->reshape_position)))
+		bio->bi_sector = sector + rdev->new_data_offset;
 	else
 		bio->bi_sector = sector + rdev->data_offset;
 	bio_add_page(bio, page, size, 0);
@@ -1034,12 +1042,17 @@
 struct super_type  {
 	char		    *name;
 	struct module	    *owner;
-	int		    (*load_super)(struct md_rdev *rdev, struct md_rdev *refdev,
+	int		    (*load_super)(struct md_rdev *rdev,
+					  struct md_rdev *refdev,
 					  int minor_version);
-	int		    (*validate_super)(struct mddev *mddev, struct md_rdev *rdev);
-	void		    (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
+	int		    (*validate_super)(struct mddev *mddev,
+					      struct md_rdev *rdev);
+	void		    (*sync_super)(struct mddev *mddev,
+					  struct md_rdev *rdev);
 	unsigned long long  (*rdev_size_change)(struct md_rdev *rdev,
 						sector_t num_sectors);
+	int		    (*allow_new_offset)(struct md_rdev *rdev,
+						unsigned long long new_offset);
 };
 
 /*
@@ -1111,6 +1124,7 @@
 
 	rdev->preferred_minor = sb->md_minor;
 	rdev->data_offset = 0;
+	rdev->new_data_offset = 0;
 	rdev->sb_size = MD_SB_BYTES;
 	rdev->badblocks.shift = -1;
 
@@ -1184,7 +1198,11 @@
 		mddev->dev_sectors = ((sector_t)sb->size) * 2;
 		mddev->events = ev1;
 		mddev->bitmap_info.offset = 0;
+		mddev->bitmap_info.space = 0;
+		/* bitmap can use 60 K after the 4K superblocks */
 		mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+		mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
+		mddev->reshape_backwards = 0;
 
 		if (mddev->minor_version >= 91) {
 			mddev->reshape_position = sb->reshape_position;
@@ -1192,6 +1210,8 @@
 			mddev->new_level = sb->new_level;
 			mddev->new_layout = sb->new_layout;
 			mddev->new_chunk_sectors = sb->new_chunk >> 9;
+			if (mddev->delta_disks < 0)
+				mddev->reshape_backwards = 1;
 		} else {
 			mddev->reshape_position = MaxSector;
 			mddev->delta_disks = 0;
@@ -1218,9 +1238,12 @@
 		mddev->max_disks = MD_SB_DISKS;
 
 		if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
-		    mddev->bitmap_info.file == NULL)
+		    mddev->bitmap_info.file == NULL) {
 			mddev->bitmap_info.offset =
 				mddev->bitmap_info.default_offset;
+			mddev->bitmap_info.space =
+				mddev->bitmap_info.space;
+		}
 
 	} else if (mddev->pers == NULL) {
 		/* Insist on good event counter while assembling, except
@@ -1434,6 +1457,12 @@
 	return num_sectors;
 }
 
+static int
+super_90_allow_new_offset(struct md_rdev *rdev, unsigned long long new_offset)
+{
+	/* non-zero offset changes not possible with v0.90 */
+	return new_offset == 0;
+}
 
 /*
  * version 1 superblock
@@ -1469,6 +1498,7 @@
 	struct mdp_superblock_1 *sb;
 	int ret;
 	sector_t sb_start;
+	sector_t sectors;
 	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
 	int bmask;
 
@@ -1523,9 +1553,18 @@
 		       bdevname(rdev->bdev,b));
 		return -EINVAL;
 	}
+	if (sb->pad0 ||
+	    sb->pad3[0] ||
+	    memcmp(sb->pad3, sb->pad3+1, sizeof(sb->pad3) - sizeof(sb->pad3[1])))
+		/* Some padding is non-zero, might be a new feature */
+		return -EINVAL;
 
 	rdev->preferred_minor = 0xffff;
 	rdev->data_offset = le64_to_cpu(sb->data_offset);
+	rdev->new_data_offset = rdev->data_offset;
+	if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE) &&
+	    (le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET))
+		rdev->new_data_offset += (s32)le32_to_cpu(sb->new_offset);
 	atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read));
 
 	rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256;
@@ -1536,6 +1575,9 @@
 	if (minor_version
 	    && rdev->data_offset < sb_start + (rdev->sb_size/512))
 		return -EINVAL;
+	if (minor_version
+	    && rdev->new_data_offset < sb_start + (rdev->sb_size/512))
+		return -EINVAL;
 
 	if (sb->level == cpu_to_le32(LEVEL_MULTIPATH))
 		rdev->desc_nr = -1;
@@ -1607,16 +1649,14 @@
 		else
 			ret = 0;
 	}
-	if (minor_version)
-		rdev->sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
-			le64_to_cpu(sb->data_offset);
-	else
-		rdev->sectors = rdev->sb_start;
-	if (rdev->sectors < le64_to_cpu(sb->data_size))
+	if (minor_version) {
+		sectors = (i_size_read(rdev->bdev->bd_inode) >> 9);
+		sectors -= rdev->data_offset;
+	} else
+		sectors = rdev->sb_start;
+	if (sectors < le64_to_cpu(sb->data_size))
 		return -EINVAL;
 	rdev->sectors = le64_to_cpu(sb->data_size);
-	if (le64_to_cpu(sb->size) > rdev->sectors)
-		return -EINVAL;
 	return ret;
 }
 
@@ -1644,17 +1684,37 @@
 		mddev->dev_sectors = le64_to_cpu(sb->size);
 		mddev->events = ev1;
 		mddev->bitmap_info.offset = 0;
+		mddev->bitmap_info.space = 0;
+		/* Default location for bitmap is 1K after superblock
+		 * using 3K - total of 4K
+		 */
 		mddev->bitmap_info.default_offset = 1024 >> 9;
-		
+		mddev->bitmap_info.default_space = (4096-1024) >> 9;
+		mddev->reshape_backwards = 0;
+
 		mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
 		memcpy(mddev->uuid, sb->set_uuid, 16);
 
 		mddev->max_disks =  (4096-256)/2;
 
 		if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
-		    mddev->bitmap_info.file == NULL )
+		    mddev->bitmap_info.file == NULL) {
 			mddev->bitmap_info.offset =
 				(__s32)le32_to_cpu(sb->bitmap_offset);
+			/* Metadata doesn't record how much space is available.
+			 * For 1.0, we assume we can use up to the superblock
+			 * if before, else to 4K beyond superblock.
+			 * For others, assume no change is possible.
+			 */
+			if (mddev->minor_version > 0)
+				mddev->bitmap_info.space = 0;
+			else if (mddev->bitmap_info.offset > 0)
+				mddev->bitmap_info.space =
+					8 - mddev->bitmap_info.offset;
+			else
+				mddev->bitmap_info.space =
+					-mddev->bitmap_info.offset;
+		}
 
 		if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
 			mddev->reshape_position = le64_to_cpu(sb->reshape_position);
@@ -1662,6 +1722,11 @@
 			mddev->new_level = le32_to_cpu(sb->new_level);
 			mddev->new_layout = le32_to_cpu(sb->new_layout);
 			mddev->new_chunk_sectors = le32_to_cpu(sb->new_chunk);
+			if (mddev->delta_disks < 0 ||
+			    (mddev->delta_disks == 0 &&
+			     (le32_to_cpu(sb->feature_map)
+			      & MD_FEATURE_RESHAPE_BACKWARDS)))
+				mddev->reshape_backwards = 1;
 		} else {
 			mddev->reshape_position = MaxSector;
 			mddev->delta_disks = 0;
@@ -1735,7 +1800,6 @@
 	sb->feature_map = 0;
 	sb->pad0 = 0;
 	sb->recovery_offset = cpu_to_le64(0);
-	memset(sb->pad1, 0, sizeof(sb->pad1));
 	memset(sb->pad3, 0, sizeof(sb->pad3));
 
 	sb->utime = cpu_to_le64((__u64)mddev->utime);
@@ -1757,6 +1821,8 @@
 		sb->devflags |= WriteMostly1;
 	else
 		sb->devflags &= ~WriteMostly1;
+	sb->data_offset = cpu_to_le64(rdev->data_offset);
+	sb->data_size = cpu_to_le64(rdev->sectors);
 
 	if (mddev->bitmap && mddev->bitmap_info.file == NULL) {
 		sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_info.offset);
@@ -1781,6 +1847,16 @@
 		sb->delta_disks = cpu_to_le32(mddev->delta_disks);
 		sb->new_level = cpu_to_le32(mddev->new_level);
 		sb->new_chunk = cpu_to_le32(mddev->new_chunk_sectors);
+		if (mddev->delta_disks == 0 &&
+		    mddev->reshape_backwards)
+			sb->feature_map
+				|= cpu_to_le32(MD_FEATURE_RESHAPE_BACKWARDS);
+		if (rdev->new_data_offset != rdev->data_offset) {
+			sb->feature_map
+				|= cpu_to_le32(MD_FEATURE_NEW_OFFSET);
+			sb->new_offset = cpu_to_le32((__u32)(rdev->new_data_offset
+							     - rdev->data_offset));
+		}
 	}
 
 	if (rdev->badblocks.count == 0)
@@ -1857,6 +1933,8 @@
 	sector_t max_sectors;
 	if (num_sectors && num_sectors < rdev->mddev->dev_sectors)
 		return 0; /* component must fit device */
+	if (rdev->data_offset != rdev->new_data_offset)
+		return 0; /* too confusing */
 	if (rdev->sb_start < rdev->data_offset) {
 		/* minor versions 1 and 2; superblock before data */
 		max_sectors = i_size_read(rdev->bdev->bd_inode) >> 9;
@@ -1884,6 +1962,40 @@
 		       rdev->sb_page);
 	md_super_wait(rdev->mddev);
 	return num_sectors;
+
+}
+
+static int
+super_1_allow_new_offset(struct md_rdev *rdev,
+			 unsigned long long new_offset)
+{
+	/* All necessary checks on new >= old have been done */
+	struct bitmap *bitmap;
+	if (new_offset >= rdev->data_offset)
+		return 1;
+
+	/* with 1.0 metadata, there is no metadata to tread on
+	 * so we can always move back */
+	if (rdev->mddev->minor_version == 0)
+		return 1;
+
+	/* otherwise we must be sure not to step on
+	 * any metadata, so stay:
+	 * 36K beyond start of superblock
+	 * beyond end of badblocks
+	 * beyond write-intent bitmap
+	 */
+	if (rdev->sb_start + (32+4)*2 > new_offset)
+		return 0;
+	bitmap = rdev->mddev->bitmap;
+	if (bitmap && !rdev->mddev->bitmap_info.file &&
+	    rdev->sb_start + rdev->mddev->bitmap_info.offset +
+	    bitmap->storage.file_pages * (PAGE_SIZE>>9) > new_offset)
+		return 0;
+	if (rdev->badblocks.sector + rdev->badblocks.size > new_offset)
+		return 0;
+
+	return 1;
 }
 
 static struct super_type super_types[] = {
@@ -1894,6 +2006,7 @@
 		.validate_super	    = super_90_validate,
 		.sync_super	    = super_90_sync,
 		.rdev_size_change   = super_90_rdev_size_change,
+		.allow_new_offset   = super_90_allow_new_offset,
 	},
 	[1] = {
 		.name	= "md-1",
@@ -1902,6 +2015,7 @@
 		.validate_super	    = super_1_validate,
 		.sync_super	    = super_1_sync,
 		.rdev_size_change   = super_1_rdev_size_change,
+		.allow_new_offset   = super_1_allow_new_offset,
 	},
 };
 
@@ -2105,9 +2219,7 @@
 	sysfs_remove_link(&rdev->kobj, "block");
 	sysfs_put(rdev->sysfs_state);
 	rdev->sysfs_state = NULL;
-	kfree(rdev->badblocks.page);
 	rdev->badblocks.count = 0;
-	rdev->badblocks.page = NULL;
 	/* We need to delay this, otherwise we can deadlock when
 	 * writing to 'remove' to "dev/state".  We also need
 	 * to delay it due to rcu usage.
@@ -2158,7 +2270,7 @@
 		bdevname(rdev->bdev,b));
 	if (rdev->mddev)
 		MD_BUG();
-	free_disk_sb(rdev);
+	md_rdev_clear(rdev);
 #ifndef MODULE
 	if (test_bit(AutoDetected, &rdev->flags))
 		md_autodetect_dev(rdev->bdev->bd_dev);
@@ -2809,9 +2921,8 @@
 static ssize_t
 offset_store(struct md_rdev *rdev, const char *buf, size_t len)
 {
-	char *e;
-	unsigned long long offset = simple_strtoull(buf, &e, 10);
-	if (e==buf || (*e && *e != '\n'))
+	unsigned long long offset;
+	if (strict_strtoull(buf, 10, &offset) < 0)
 		return -EINVAL;
 	if (rdev->mddev->pers && rdev->raid_disk >= 0)
 		return -EBUSY;
@@ -2826,6 +2937,63 @@
 static struct rdev_sysfs_entry rdev_offset =
 __ATTR(offset, S_IRUGO|S_IWUSR, offset_show, offset_store);
 
+static ssize_t new_offset_show(struct md_rdev *rdev, char *page)
+{
+	return sprintf(page, "%llu\n",
+		       (unsigned long long)rdev->new_data_offset);
+}
+
+static ssize_t new_offset_store(struct md_rdev *rdev,
+				const char *buf, size_t len)
+{
+	unsigned long long new_offset;
+	struct mddev *mddev = rdev->mddev;
+
+	if (strict_strtoull(buf, 10, &new_offset) < 0)
+		return -EINVAL;
+
+	if (mddev->sync_thread)
+		return -EBUSY;
+	if (new_offset == rdev->data_offset)
+		/* reset is always permitted */
+		;
+	else if (new_offset > rdev->data_offset) {
+		/* must not push array size beyond rdev_sectors */
+		if (new_offset - rdev->data_offset
+		    + mddev->dev_sectors > rdev->sectors)
+				return -E2BIG;
+	}
+	/* Metadata worries about other space details. */
+
+	/* decreasing the offset is inconsistent with a backwards
+	 * reshape.
+	 */
+	if (new_offset < rdev->data_offset &&
+	    mddev->reshape_backwards)
+		return -EINVAL;
+	/* Increasing offset is inconsistent with forwards
+	 * reshape.  reshape_direction should be set to
+	 * 'backwards' first.
+	 */
+	if (new_offset > rdev->data_offset &&
+	    !mddev->reshape_backwards)
+		return -EINVAL;
+
+	if (mddev->pers && mddev->persistent &&
+	    !super_types[mddev->major_version]
+	    .allow_new_offset(rdev, new_offset))
+		return -E2BIG;
+	rdev->new_data_offset = new_offset;
+	if (new_offset > rdev->data_offset)
+		mddev->reshape_backwards = 1;
+	else if (new_offset < rdev->data_offset)
+		mddev->reshape_backwards = 0;
+
+	return len;
+}
+static struct rdev_sysfs_entry rdev_new_offset =
+__ATTR(new_offset, S_IRUGO|S_IWUSR, new_offset_show, new_offset_store);
+
 static ssize_t
 rdev_size_show(struct md_rdev *rdev, char *page)
 {
@@ -2870,6 +3038,8 @@
 
 	if (strict_blocks_to_sectors(buf, &sectors) < 0)
 		return -EINVAL;
+	if (rdev->data_offset != rdev->new_data_offset)
+		return -EINVAL; /* too confusing */
 	if (my_mddev->pers && rdev->raid_disk >= 0) {
 		if (my_mddev->persistent) {
 			sectors = super_types[my_mddev->major_version].
@@ -3006,6 +3176,7 @@
 	&rdev_errors.attr,
 	&rdev_slot.attr,
 	&rdev_offset.attr,
+	&rdev_new_offset.attr,
 	&rdev_size.attr,
 	&rdev_recovery_start.attr,
 	&rdev_bad_blocks.attr,
@@ -3080,6 +3251,7 @@
 	rdev->raid_disk = -1;
 	rdev->flags = 0;
 	rdev->data_offset = 0;
+	rdev->new_data_offset = 0;
 	rdev->sb_events = 0;
 	rdev->last_read_error.tv_sec  = 0;
 	rdev->last_read_error.tv_nsec = 0;
@@ -3178,8 +3350,7 @@
 abort_free:
 	if (rdev->bdev)
 		unlock_rdev(rdev);
-	free_disk_sb(rdev);
-	kfree(rdev->badblocks.page);
+	md_rdev_clear(rdev);
 	kfree(rdev);
 	return ERR_PTR(err);
 }
@@ -3419,6 +3590,7 @@
 		mddev->new_chunk_sectors = mddev->chunk_sectors;
 		mddev->raid_disks -= mddev->delta_disks;
 		mddev->delta_disks = 0;
+		mddev->reshape_backwards = 0;
 		module_put(pers->owner);
 		printk(KERN_WARNING "md: %s: %s would not accept array\n",
 		       mdname(mddev), clevel);
@@ -3492,6 +3664,7 @@
 	mddev->layout = mddev->new_layout;
 	mddev->chunk_sectors = mddev->new_chunk_sectors;
 	mddev->delta_disks = 0;
+	mddev->reshape_backwards = 0;
 	mddev->degraded = 0;
 	if (mddev->pers->sync_request == NULL) {
 		/* this is now an array without redundancy, so
@@ -3501,10 +3674,8 @@
 		del_timer_sync(&mddev->safemode_timer);
 	}
 	pers->run(mddev);
-	mddev_resume(mddev);
 	set_bit(MD_CHANGE_DEVS, &mddev->flags);
-	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
-	md_wakeup_thread(mddev->thread);
+	mddev_resume(mddev);
 	sysfs_notify(&mddev->kobj, NULL, "level");
 	md_new_event(mddev);
 	return rv;
@@ -3582,9 +3753,20 @@
 	if (mddev->pers)
 		rv = update_raid_disks(mddev, n);
 	else if (mddev->reshape_position != MaxSector) {
+		struct md_rdev *rdev;
 		int olddisks = mddev->raid_disks - mddev->delta_disks;
+
+		rdev_for_each(rdev, mddev) {
+			if (olddisks < n &&
+			    rdev->data_offset < rdev->new_data_offset)
+				return -EINVAL;
+			if (olddisks > n &&
+			    rdev->data_offset > rdev->new_data_offset)
+				return -EINVAL;
+		}
 		mddev->delta_disks = n - olddisks;
 		mddev->raid_disks = n;
+		mddev->reshape_backwards = (mddev->delta_disks < 0);
 	} else
 		mddev->raid_disks = n;
 	return rv ? rv : len;
@@ -4266,7 +4448,8 @@
 	if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
 		return sprintf(page, "none\n");
 
-	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+	    test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
 		max_sectors = mddev->resync_max_sectors;
 	else
 		max_sectors = mddev->dev_sectors;
@@ -4428,6 +4611,7 @@
 static ssize_t
 reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
 {
+	struct md_rdev *rdev;
 	char *e;
 	unsigned long long new = simple_strtoull(buf, &e, 10);
 	if (mddev->pers)
@@ -4436,9 +4620,12 @@
 		return -EINVAL;
 	mddev->reshape_position = new;
 	mddev->delta_disks = 0;
+	mddev->reshape_backwards = 0;
 	mddev->new_level = mddev->level;
 	mddev->new_layout = mddev->layout;
 	mddev->new_chunk_sectors = mddev->chunk_sectors;
+	rdev_for_each(rdev, mddev)
+		rdev->new_data_offset = rdev->data_offset;
 	return len;
 }
 
@@ -4447,6 +4634,42 @@
        reshape_position_store);
 
 static ssize_t
+reshape_direction_show(struct mddev *mddev, char *page)
+{
+	return sprintf(page, "%s\n",
+		       mddev->reshape_backwards ? "backwards" : "forwards");
+}
+
+static ssize_t
+reshape_direction_store(struct mddev *mddev, const char *buf, size_t len)
+{
+	int backwards = 0;
+	if (cmd_match(buf, "forwards"))
+		backwards = 0;
+	else if (cmd_match(buf, "backwards"))
+		backwards = 1;
+	else
+		return -EINVAL;
+	if (mddev->reshape_backwards == backwards)
+		return len;
+
+	/* check if we are allowed to change */
+	if (mddev->delta_disks)
+		return -EBUSY;
+
+	if (mddev->persistent &&
+	    mddev->major_version == 0)
+		return -EINVAL;
+
+	mddev->reshape_backwards = backwards;
+	return len;
+}
+
+static struct md_sysfs_entry md_reshape_direction =
+__ATTR(reshape_direction, S_IRUGO|S_IWUSR, reshape_direction_show,
+       reshape_direction_store);
+
+static ssize_t
 array_size_show(struct mddev *mddev, char *page)
 {
 	if (mddev->external_size)
@@ -4501,6 +4724,7 @@
 	&md_safe_delay.attr,
 	&md_array_state.attr,
 	&md_reshape_position.attr,
+	&md_reshape_direction.attr,
 	&md_array_size.attr,
 	&max_corr_read_errors.attr,
 	NULL,
@@ -4914,7 +5138,8 @@
 		err = -EINVAL;
 		mddev->pers->stop(mddev);
 	}
-	if (err == 0 && mddev->pers->sync_request) {
+	if (err == 0 && mddev->pers->sync_request &&
+	    (mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
 		err = bitmap_create(mddev);
 		if (err) {
 			printk(KERN_ERR "%s: failed to create bitmap (%d)\n",
@@ -5064,6 +5289,7 @@
 	mddev->events = 0;
 	mddev->can_decrease_events = 0;
 	mddev->delta_disks = 0;
+	mddev->reshape_backwards = 0;
 	mddev->new_level = LEVEL_NONE;
 	mddev->new_layout = 0;
 	mddev->new_chunk_sectors = 0;
@@ -5079,6 +5305,7 @@
 	mddev->merge_check_needed = 0;
 	mddev->bitmap_info.offset = 0;
 	mddev->bitmap_info.default_offset = 0;
+	mddev->bitmap_info.default_space = 0;
 	mddev->bitmap_info.chunksize = 0;
 	mddev->bitmap_info.daemon_sleep = 0;
 	mddev->bitmap_info.max_write_behind = 0;
@@ -5421,7 +5648,7 @@
 		goto out;
 
 	/* bitmap disabled, zero the first byte and copy out */
-	if (!mddev->bitmap || !mddev->bitmap->file) {
+	if (!mddev->bitmap || !mddev->bitmap->storage.file) {
 		file->pathname[0] = '\0';
 		goto copy_out;
 	}
@@ -5430,7 +5657,8 @@
 	if (!buf)
 		goto out;
 
-	ptr = d_path(&mddev->bitmap->file->f_path, buf, sizeof(file->pathname));
+	ptr = d_path(&mddev->bitmap->storage.file->f_path,
+		     buf, sizeof(file->pathname));
 	if (IS_ERR(ptr))
 		goto out;
 
@@ -5875,6 +6103,7 @@
 	set_bit(MD_CHANGE_DEVS, &mddev->flags);
 
 	mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+	mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
 	mddev->bitmap_info.offset = 0;
 
 	mddev->reshape_position = MaxSector;
@@ -5888,6 +6117,7 @@
 	mddev->new_chunk_sectors = mddev->chunk_sectors;
 	mddev->new_layout = mddev->layout;
 	mddev->delta_disks = 0;
+	mddev->reshape_backwards = 0;
 
 	return 0;
 }
@@ -5922,11 +6152,7 @@
 	 */
 	if (mddev->sync_thread)
 		return -EBUSY;
-	if (mddev->bitmap)
-		/* Sorry, cannot grow a bitmap yet, just remove it,
-		 * grow, and re-add.
-		 */
-		return -EBUSY;
+
 	rdev_for_each(rdev, mddev) {
 		sector_t avail = rdev->sectors;
 
@@ -5944,6 +6170,7 @@
 static int update_raid_disks(struct mddev *mddev, int raid_disks)
 {
 	int rv;
+	struct md_rdev *rdev;
 	/* change the number of raid disks */
 	if (mddev->pers->check_reshape == NULL)
 		return -EINVAL;
@@ -5952,11 +6179,27 @@
 		return -EINVAL;
 	if (mddev->sync_thread || mddev->reshape_position != MaxSector)
 		return -EBUSY;
+
+	rdev_for_each(rdev, mddev) {
+		if (mddev->raid_disks < raid_disks &&
+		    rdev->data_offset < rdev->new_data_offset)
+			return -EINVAL;
+		if (mddev->raid_disks > raid_disks &&
+		    rdev->data_offset > rdev->new_data_offset)
+			return -EINVAL;
+	}
+
 	mddev->delta_disks = raid_disks - mddev->raid_disks;
+	if (mddev->delta_disks < 0)
+		mddev->reshape_backwards = 1;
+	else if (mddev->delta_disks > 0)
+		mddev->reshape_backwards = 0;
 
 	rv = mddev->pers->check_reshape(mddev);
-	if (rv < 0)
+	if (rv < 0) {
 		mddev->delta_disks = 0;
+		mddev->reshape_backwards = 0;
+	}
 	return rv;
 }
 
@@ -6039,6 +6282,8 @@
 				return -EINVAL;
 			mddev->bitmap_info.offset =
 				mddev->bitmap_info.default_offset;
+			mddev->bitmap_info.space =
+				mddev->bitmap_info.default_space;
 			mddev->pers->quiesce(mddev, 1);
 			rv = bitmap_create(mddev);
 			if (!rv)
@@ -6050,7 +6295,7 @@
 			/* remove the bitmap */
 			if (!mddev->bitmap)
 				return -ENOENT;
-			if (mddev->bitmap->file)
+			if (mddev->bitmap->storage.file)
 				return -EINVAL;
 			mddev->pers->quiesce(mddev, 1);
 			bitmap_destroy(mddev);
@@ -6373,6 +6618,9 @@
 	struct mddev *mddev = mddev_find(bdev->bd_dev);
 	int err;
 
+	if (!mddev)
+		return -ENODEV;
+
 	if (mddev->gendisk != bdev->bd_disk) {
 		/* we are racing with mddev_put which is discarding this
 		 * bd_disk.
@@ -6584,7 +6832,8 @@
 
 	resync = mddev->curr_resync - atomic_read(&mddev->recovery_active);
 
-	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+	    test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
 		max_sectors = mddev->resync_max_sectors;
 	else
 		max_sectors = mddev->dev_sectors;
@@ -7147,7 +7396,7 @@
 			j = mddev->recovery_cp;
 
 	} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
-		max_sectors = mddev->dev_sectors;
+		max_sectors = mddev->resync_max_sectors;
 	else {
 		/* recovery follows the physical size of devices */
 		max_sectors = mddev->dev_sectors;
@@ -7598,7 +7847,7 @@
 			goto unlock;
 
 		if (mddev->pers->sync_request) {
-			if (spares && mddev->bitmap && ! mddev->bitmap->file) {
+			if (spares) {
 				/* We are adding a device or devices to an array
 				 * which has the bitmap stored on all devices.
 				 * So make sure all bitmap pages get written
@@ -7646,6 +7895,20 @@
 }
 EXPORT_SYMBOL(md_wait_for_blocked_rdev);
 
+void md_finish_reshape(struct mddev *mddev)
+{
+	/* called be personality module when reshape completes. */
+	struct md_rdev *rdev;
+
+	rdev_for_each(rdev, mddev) {
+		if (rdev->data_offset > rdev->new_data_offset)
+			rdev->sectors += rdev->data_offset - rdev->new_data_offset;
+		else
+			rdev->sectors -= rdev->new_data_offset - rdev->data_offset;
+		rdev->data_offset = rdev->new_data_offset;
+	}
+}
+EXPORT_SYMBOL(md_finish_reshape);
 
 /* Bad block management.
  * We can record which blocks on each device are 'bad' and so just
@@ -7894,10 +8157,15 @@
 }
 
 int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
-		       int acknowledged)
+		       int is_new)
 {
-	int rv = md_set_badblocks(&rdev->badblocks,
-				  s + rdev->data_offset, sectors, acknowledged);
+	int rv;
+	if (is_new)
+		s += rdev->new_data_offset;
+	else
+		s += rdev->data_offset;
+	rv = md_set_badblocks(&rdev->badblocks,
+			      s, sectors, 0);
 	if (rv) {
 		/* Make sure they get written out promptly */
 		sysfs_notify_dirent_safe(rdev->sysfs_state);
@@ -8003,11 +8271,15 @@
 	return rv;
 }
 
-int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors)
+int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
+			 int is_new)
 {
+	if (is_new)
+		s += rdev->new_data_offset;
+	else
+		s += rdev->data_offset;
 	return md_clear_badblocks(&rdev->badblocks,
-				  s + rdev->data_offset,
-				  sectors);
+				  s, sectors);
 }
 EXPORT_SYMBOL_GPL(rdev_clear_badblocks);
 
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 1c2063c..7b4a3c3 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -55,6 +55,7 @@
 	int		sb_loaded;
 	__u64		sb_events;
 	sector_t	data_offset;	/* start of data in array */
+	sector_t	new_data_offset;/* only relevant while reshaping */
 	sector_t 	sb_start;	/* offset of the super block (in 512byte sectors) */
 	int		sb_size;	/* bytes in the superblock */
 	int		preferred_minor;	/* autorun support */
@@ -193,8 +194,9 @@
 	return 0;
 }
 extern int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
-			      int acknowledged);
-extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors);
+			      int is_new);
+extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
+				int is_new);
 extern void md_ack_all_badblocks(struct badblocks *bb);
 
 struct mddev {
@@ -262,6 +264,7 @@
 	sector_t			reshape_position;
 	int				delta_disks, new_level, new_layout;
 	int				new_chunk_sectors;
+	int				reshape_backwards;
 
 	atomic_t			plug_cnt;	/* If device is expecting
 							 * more bios soon.
@@ -390,10 +393,13 @@
 						 * For external metadata, offset
 						 * from start of device. 
 						 */
+		unsigned long		space; /* space available at this offset */
 		loff_t			default_offset; /* this is the offset to use when
 							 * hot-adding a bitmap.  It should
 							 * eventually be settable by sysfs.
 							 */
+		unsigned long		default_space; /* space available at
+							* default offset */
 		struct mutex		mutex;
 		unsigned long		chunksize;
 		unsigned long		daemon_sleep; /* how many jiffies between updates? */
@@ -591,6 +597,7 @@
 extern void md_write_end(struct mddev *mddev);
 extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
 extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
+extern void md_finish_reshape(struct mddev *mddev);
 
 extern int mddev_congested(struct mddev *mddev, int bits);
 extern void md_flush_request(struct mddev *mddev, struct bio *bio);
@@ -615,6 +622,7 @@
 extern void md_stop(struct mddev *mddev);
 extern void md_stop_writes(struct mddev *mddev);
 extern int md_rdev_init(struct md_rdev *rdev);
+extern void md_rdev_clear(struct md_rdev *rdev);
 
 extern void mddev_suspend(struct mddev *mddev);
 extern void mddev_resume(struct mddev *mddev);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 15dd59b..835de71 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1859,7 +1859,9 @@
 
 			rdev = conf->mirrors[d].rdev;
 			if (rdev &&
-			    test_bit(In_sync, &rdev->flags) &&
+			    (test_bit(In_sync, &rdev->flags) ||
+			     (!test_bit(Faulty, &rdev->flags) &&
+			      rdev->recovery_offset >= sect + s)) &&
 			    is_badblock(rdev, sect, s,
 					&first_bad, &bad_sectors) == 0 &&
 			    sync_page_io(rdev, sect, s<<9,
@@ -2024,7 +2026,7 @@
 			continue;
 		if (test_bit(BIO_UPTODATE, &bio->bi_flags) &&
 		    test_bit(R1BIO_MadeGood, &r1_bio->state)) {
-			rdev_clear_badblocks(rdev, r1_bio->sector, s);
+			rdev_clear_badblocks(rdev, r1_bio->sector, s, 0);
 		}
 		if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
 		    test_bit(R1BIO_WriteError, &r1_bio->state)) {
@@ -2044,7 +2046,7 @@
 			struct md_rdev *rdev = conf->mirrors[m].rdev;
 			rdev_clear_badblocks(rdev,
 					     r1_bio->sector,
-					     r1_bio->sectors);
+					     r1_bio->sectors, 0);
 			rdev_dec_pending(rdev, conf->mddev);
 		} else if (r1_bio->bios[m] != NULL) {
 			/* This drive got a write error.  We need to
@@ -2598,7 +2600,8 @@
 		if (!disk->rdev ||
 		    !test_bit(In_sync, &disk->rdev->flags)) {
 			disk->head_position = 0;
-			if (disk->rdev)
+			if (disk->rdev &&
+			    (disk->rdev->saved_raid_disk < 0))
 				conf->fullsync = 1;
 		} else if (conf->last_used < 0)
 			/*
@@ -2750,9 +2753,16 @@
 	 * any io in the removed space completes, but it hardly seems
 	 * worth it.
 	 */
-	md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0));
-	if (mddev->array_sectors > raid1_size(mddev, sectors, 0))
+	sector_t newsize = raid1_size(mddev, sectors, 0);
+	if (mddev->external_size &&
+	    mddev->array_sectors > newsize)
 		return -EINVAL;
+	if (mddev->bitmap) {
+		int ret = bitmap_resize(mddev->bitmap, newsize, 0, 0);
+		if (ret)
+			return ret;
+	}
+	md_set_array_sectors(mddev, newsize);
 	set_capacity(mddev->gendisk, mddev->array_sectors);
 	revalidate_disk(mddev->gendisk);
 	if (sectors > mddev->dev_sectors &&
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 3f91c2e..987db37 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/ratelimit.h>
+#include <linux/kthread.h>
 #include "md.h"
 #include "raid10.h"
 #include "raid0.h"
@@ -68,6 +69,11 @@
 static void allow_barrier(struct r10conf *conf);
 static void lower_barrier(struct r10conf *conf);
 static int enough(struct r10conf *conf, int ignore);
+static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
+				int *skipped);
+static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio);
+static void end_reshape_write(struct bio *bio, int error);
+static void end_reshape(struct r10conf *conf);
 
 static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
 {
@@ -112,7 +118,8 @@
 	if (!r10_bio)
 		return NULL;
 
-	if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery))
+	if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery) ||
+	    test_bit(MD_RECOVERY_RESHAPE, &conf->mddev->recovery))
 		nalloc = conf->copies; /* resync */
 	else
 		nalloc = 2; /* recovery */
@@ -140,9 +147,10 @@
 		struct bio *rbio = r10_bio->devs[j].repl_bio;
 		bio = r10_bio->devs[j].bio;
 		for (i = 0; i < RESYNC_PAGES; i++) {
-			if (j == 1 && !test_bit(MD_RECOVERY_SYNC,
-						&conf->mddev->recovery)) {
-				/* we can share bv_page's during recovery */
+			if (j > 0 && !test_bit(MD_RECOVERY_SYNC,
+					       &conf->mddev->recovery)) {
+				/* we can share bv_page's during recovery
+				 * and reshape */
 				struct bio *rbio = r10_bio->devs[0].bio;
 				page = rbio->bi_io_vec[i].bv_page;
 				get_page(page);
@@ -165,10 +173,11 @@
 	while (j--)
 		for (i = 0; i < RESYNC_PAGES ; i++)
 			safe_put_page(r10_bio->devs[j].bio->bi_io_vec[i].bv_page);
-	j = -1;
+	j = 0;
 out_free_bio:
-	while (++j < nalloc) {
-		bio_put(r10_bio->devs[j].bio);
+	for ( ; j < nalloc; j++) {
+		if (r10_bio->devs[j].bio)
+			bio_put(r10_bio->devs[j].bio);
 		if (r10_bio->devs[j].repl_bio)
 			bio_put(r10_bio->devs[j].repl_bio);
 	}
@@ -504,79 +513,96 @@
  * sector offset to a virtual address
  */
 
-static void raid10_find_phys(struct r10conf *conf, struct r10bio *r10bio)
+static void __raid10_find_phys(struct geom *geo, struct r10bio *r10bio)
 {
 	int n,f;
 	sector_t sector;
 	sector_t chunk;
 	sector_t stripe;
 	int dev;
-
 	int slot = 0;
 
 	/* now calculate first sector/dev */
-	chunk = r10bio->sector >> conf->chunk_shift;
-	sector = r10bio->sector & conf->chunk_mask;
+	chunk = r10bio->sector >> geo->chunk_shift;
+	sector = r10bio->sector & geo->chunk_mask;
 
-	chunk *= conf->near_copies;
+	chunk *= geo->near_copies;
 	stripe = chunk;
-	dev = sector_div(stripe, conf->raid_disks);
-	if (conf->far_offset)
-		stripe *= conf->far_copies;
+	dev = sector_div(stripe, geo->raid_disks);
+	if (geo->far_offset)
+		stripe *= geo->far_copies;
 
-	sector += stripe << conf->chunk_shift;
+	sector += stripe << geo->chunk_shift;
 
 	/* and calculate all the others */
-	for (n=0; n < conf->near_copies; n++) {
+	for (n = 0; n < geo->near_copies; n++) {
 		int d = dev;
 		sector_t s = sector;
 		r10bio->devs[slot].addr = sector;
 		r10bio->devs[slot].devnum = d;
 		slot++;
 
-		for (f = 1; f < conf->far_copies; f++) {
-			d += conf->near_copies;
-			if (d >= conf->raid_disks)
-				d -= conf->raid_disks;
-			s += conf->stride;
+		for (f = 1; f < geo->far_copies; f++) {
+			d += geo->near_copies;
+			if (d >= geo->raid_disks)
+				d -= geo->raid_disks;
+			s += geo->stride;
 			r10bio->devs[slot].devnum = d;
 			r10bio->devs[slot].addr = s;
 			slot++;
 		}
 		dev++;
-		if (dev >= conf->raid_disks) {
+		if (dev >= geo->raid_disks) {
 			dev = 0;
-			sector += (conf->chunk_mask + 1);
+			sector += (geo->chunk_mask + 1);
 		}
 	}
-	BUG_ON(slot != conf->copies);
+}
+
+static void raid10_find_phys(struct r10conf *conf, struct r10bio *r10bio)
+{
+	struct geom *geo = &conf->geo;
+
+	if (conf->reshape_progress != MaxSector &&
+	    ((r10bio->sector >= conf->reshape_progress) !=
+	     conf->mddev->reshape_backwards)) {
+		set_bit(R10BIO_Previous, &r10bio->state);
+		geo = &conf->prev;
+	} else
+		clear_bit(R10BIO_Previous, &r10bio->state);
+
+	__raid10_find_phys(geo, r10bio);
 }
 
 static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev)
 {
 	sector_t offset, chunk, vchunk;
+	/* Never use conf->prev as this is only called during resync
+	 * or recovery, so reshape isn't happening
+	 */
+	struct geom *geo = &conf->geo;
 
-	offset = sector & conf->chunk_mask;
-	if (conf->far_offset) {
+	offset = sector & geo->chunk_mask;
+	if (geo->far_offset) {
 		int fc;
-		chunk = sector >> conf->chunk_shift;
-		fc = sector_div(chunk, conf->far_copies);
-		dev -= fc * conf->near_copies;
+		chunk = sector >> geo->chunk_shift;
+		fc = sector_div(chunk, geo->far_copies);
+		dev -= fc * geo->near_copies;
 		if (dev < 0)
-			dev += conf->raid_disks;
+			dev += geo->raid_disks;
 	} else {
-		while (sector >= conf->stride) {
-			sector -= conf->stride;
-			if (dev < conf->near_copies)
-				dev += conf->raid_disks - conf->near_copies;
+		while (sector >= geo->stride) {
+			sector -= geo->stride;
+			if (dev < geo->near_copies)
+				dev += geo->raid_disks - geo->near_copies;
 			else
-				dev -= conf->near_copies;
+				dev -= geo->near_copies;
 		}
-		chunk = sector >> conf->chunk_shift;
+		chunk = sector >> geo->chunk_shift;
 	}
-	vchunk = chunk * conf->raid_disks + dev;
-	sector_div(vchunk, conf->near_copies);
-	return (vchunk << conf->chunk_shift) + offset;
+	vchunk = chunk * geo->raid_disks + dev;
+	sector_div(vchunk, geo->near_copies);
+	return (vchunk << geo->chunk_shift) + offset;
 }
 
 /**
@@ -597,10 +623,17 @@
 	struct r10conf *conf = mddev->private;
 	sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
 	int max;
-	unsigned int chunk_sectors = mddev->chunk_sectors;
+	unsigned int chunk_sectors;
 	unsigned int bio_sectors = bvm->bi_size >> 9;
+	struct geom *geo = &conf->geo;
 
-	if (conf->near_copies < conf->raid_disks) {
+	chunk_sectors = (conf->geo.chunk_mask & conf->prev.chunk_mask) + 1;
+	if (conf->reshape_progress != MaxSector &&
+	    ((sector >= conf->reshape_progress) !=
+	     conf->mddev->reshape_backwards))
+		geo = &conf->prev;
+
+	if (geo->near_copies < geo->raid_disks) {
 		max = (chunk_sectors - ((sector & (chunk_sectors - 1))
 					+ bio_sectors)) << 9;
 		if (max < 0)
@@ -614,6 +647,12 @@
 	if (mddev->merge_check_needed) {
 		struct r10bio r10_bio;
 		int s;
+		if (conf->reshape_progress != MaxSector) {
+			/* Cannot give any guidance during reshape */
+			if (max <= biovec->bv_len && bio_sectors == 0)
+				return biovec->bv_len;
+			return 0;
+		}
 		r10_bio.sector = sector;
 		raid10_find_phys(conf, &r10_bio);
 		rcu_read_lock();
@@ -681,6 +720,7 @@
 	struct md_rdev *rdev, *best_rdev;
 	int do_balance;
 	int best_slot;
+	struct geom *geo = &conf->geo;
 
 	raid10_find_phys(conf, r10_bio);
 	rcu_read_lock();
@@ -761,11 +801,11 @@
 		 * sequential read speed for 'far copies' arrays.  So only
 		 * keep it for 'near' arrays, and review those later.
 		 */
-		if (conf->near_copies > 1 && !atomic_read(&rdev->nr_pending))
+		if (geo->near_copies > 1 && !atomic_read(&rdev->nr_pending))
 			break;
 
 		/* for far > 1 always use the lowest address */
-		if (conf->far_copies > 1)
+		if (geo->far_copies > 1)
 			new_distance = r10_bio->devs[slot].addr;
 		else
 			new_distance = abs(r10_bio->devs[slot].addr -
@@ -812,7 +852,10 @@
 	if (mddev_congested(mddev, bits))
 		return 1;
 	rcu_read_lock();
-	for (i = 0; i < conf->raid_disks && ret == 0; i++) {
+	for (i = 0;
+	     (i < conf->geo.raid_disks || i < conf->prev.raid_disks)
+		     && ret == 0;
+	     i++) {
 		struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct request_queue *q = bdev_get_queue(rdev->bdev);
@@ -973,13 +1016,24 @@
 	spin_unlock_irq(&conf->resync_lock);
 }
 
+static sector_t choose_data_offset(struct r10bio *r10_bio,
+				   struct md_rdev *rdev)
+{
+	if (!test_bit(MD_RECOVERY_RESHAPE, &rdev->mddev->recovery) ||
+	    test_bit(R10BIO_Previous, &r10_bio->state))
+		return rdev->data_offset;
+	else
+		return rdev->new_data_offset;
+}
+
 static void make_request(struct mddev *mddev, struct bio * bio)
 {
 	struct r10conf *conf = mddev->private;
 	struct r10bio *r10_bio;
 	struct bio *read_bio;
 	int i;
-	int chunk_sects = conf->chunk_mask + 1;
+	sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask);
+	int chunk_sects = chunk_mask + 1;
 	const int rw = bio_data_dir(bio);
 	const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
 	const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
@@ -988,6 +1042,7 @@
 	int plugged;
 	int sectors_handled;
 	int max_sectors;
+	int sectors;
 
 	if (unlikely(bio->bi_rw & REQ_FLUSH)) {
 		md_flush_request(mddev, bio);
@@ -997,9 +1052,10 @@
 	/* If this request crosses a chunk boundary, we need to
 	 * split it.  This will only happen for 1 PAGE (or less) requests.
 	 */
-	if (unlikely( (bio->bi_sector & conf->chunk_mask) + (bio->bi_size >> 9)
-		      > chunk_sects &&
-		    conf->near_copies < conf->raid_disks)) {
+	if (unlikely((bio->bi_sector & chunk_mask) + (bio->bi_size >> 9)
+		     > chunk_sects
+		     && (conf->geo.near_copies < conf->geo.raid_disks
+			 || conf->prev.near_copies < conf->prev.raid_disks))) {
 		struct bio_pair *bp;
 		/* Sanity check -- queue functions should prevent this happening */
 		if (bio->bi_vcnt != 1 ||
@@ -1051,10 +1107,41 @@
 	 */
 	wait_barrier(conf);
 
+	sectors = bio->bi_size >> 9;
+	while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+	    bio->bi_sector < conf->reshape_progress &&
+	    bio->bi_sector + sectors > conf->reshape_progress) {
+		/* IO spans the reshape position.  Need to wait for
+		 * reshape to pass
+		 */
+		allow_barrier(conf);
+		wait_event(conf->wait_barrier,
+			   conf->reshape_progress <= bio->bi_sector ||
+			   conf->reshape_progress >= bio->bi_sector + sectors);
+		wait_barrier(conf);
+	}
+	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+	    bio_data_dir(bio) == WRITE &&
+	    (mddev->reshape_backwards
+	     ? (bio->bi_sector < conf->reshape_safe &&
+		bio->bi_sector + sectors > conf->reshape_progress)
+	     : (bio->bi_sector + sectors > conf->reshape_safe &&
+		bio->bi_sector < conf->reshape_progress))) {
+		/* Need to update reshape_position in metadata */
+		mddev->reshape_position = conf->reshape_progress;
+		set_bit(MD_CHANGE_DEVS, &mddev->flags);
+		set_bit(MD_CHANGE_PENDING, &mddev->flags);
+		md_wakeup_thread(mddev->thread);
+		wait_event(mddev->sb_wait,
+			   !test_bit(MD_CHANGE_PENDING, &mddev->flags));
+
+		conf->reshape_safe = mddev->reshape_position;
+	}
+
 	r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
 
 	r10_bio->master_bio = bio;
-	r10_bio->sectors = bio->bi_size >> 9;
+	r10_bio->sectors = sectors;
 
 	r10_bio->mddev = mddev;
 	r10_bio->sector = bio->bi_sector;
@@ -1093,7 +1180,7 @@
 		r10_bio->devs[slot].rdev = rdev;
 
 		read_bio->bi_sector = r10_bio->devs[slot].addr +
-			rdev->data_offset;
+			choose_data_offset(r10_bio, rdev);
 		read_bio->bi_bdev = rdev->bdev;
 		read_bio->bi_end_io = raid10_end_read_request;
 		read_bio->bi_rw = READ | do_sync;
@@ -1297,7 +1384,8 @@
 		r10_bio->devs[i].bio = mbio;
 
 		mbio->bi_sector	= (r10_bio->devs[i].addr+
-				   conf->mirrors[d].rdev->data_offset);
+				   choose_data_offset(r10_bio,
+						      conf->mirrors[d].rdev));
 		mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
 		mbio->bi_end_io	= raid10_end_write_request;
 		mbio->bi_rw = WRITE | do_sync | do_fua;
@@ -1321,8 +1409,10 @@
 		 * so it cannot disappear, so the replacement cannot
 		 * become NULL here
 		 */
-		mbio->bi_sector	= (r10_bio->devs[i].addr+
-				   conf->mirrors[d].replacement->data_offset);
+		mbio->bi_sector	= (r10_bio->devs[i].addr +
+				   choose_data_offset(
+					   r10_bio,
+					   conf->mirrors[d].replacement));
 		mbio->bi_bdev = conf->mirrors[d].replacement->bdev;
 		mbio->bi_end_io	= raid10_end_write_request;
 		mbio->bi_rw = WRITE | do_sync | do_fua;
@@ -1368,19 +1458,19 @@
 	struct r10conf *conf = mddev->private;
 	int i;
 
-	if (conf->near_copies < conf->raid_disks)
+	if (conf->geo.near_copies < conf->geo.raid_disks)
 		seq_printf(seq, " %dK chunks", mddev->chunk_sectors / 2);
-	if (conf->near_copies > 1)
-		seq_printf(seq, " %d near-copies", conf->near_copies);
-	if (conf->far_copies > 1) {
-		if (conf->far_offset)
-			seq_printf(seq, " %d offset-copies", conf->far_copies);
+	if (conf->geo.near_copies > 1)
+		seq_printf(seq, " %d near-copies", conf->geo.near_copies);
+	if (conf->geo.far_copies > 1) {
+		if (conf->geo.far_offset)
+			seq_printf(seq, " %d offset-copies", conf->geo.far_copies);
 		else
-			seq_printf(seq, " %d far-copies", conf->far_copies);
+			seq_printf(seq, " %d far-copies", conf->geo.far_copies);
 	}
-	seq_printf(seq, " [%d/%d] [", conf->raid_disks,
-					conf->raid_disks - mddev->degraded);
-	for (i = 0; i < conf->raid_disks; i++)
+	seq_printf(seq, " [%d/%d] [", conf->geo.raid_disks,
+					conf->geo.raid_disks - mddev->degraded);
+	for (i = 0; i < conf->geo.raid_disks; i++)
 		seq_printf(seq, "%s",
 			      conf->mirrors[i].rdev &&
 			      test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
@@ -1392,7 +1482,7 @@
  * Don't consider the device numbered 'ignore'
  * as we might be about to remove it.
  */
-static int enough(struct r10conf *conf, int ignore)
+static int _enough(struct r10conf *conf, struct geom *geo, int ignore)
 {
 	int first = 0;
 
@@ -1403,7 +1493,7 @@
 			if (conf->mirrors[first].rdev &&
 			    first != ignore)
 				cnt++;
-			first = (first+1) % conf->raid_disks;
+			first = (first+1) % geo->raid_disks;
 		}
 		if (cnt == 0)
 			return 0;
@@ -1411,6 +1501,12 @@
 	return 1;
 }
 
+static int enough(struct r10conf *conf, int ignore)
+{
+	return _enough(conf, &conf->geo, ignore) &&
+		_enough(conf, &conf->prev, ignore);
+}
+
 static void error(struct mddev *mddev, struct md_rdev *rdev)
 {
 	char b[BDEVNAME_SIZE];
@@ -1445,7 +1541,7 @@
 	       "md/raid10:%s: Disk failure on %s, disabling device.\n"
 	       "md/raid10:%s: Operation continuing on %d devices.\n",
 	       mdname(mddev), bdevname(rdev->bdev, b),
-	       mdname(mddev), conf->raid_disks - mddev->degraded);
+	       mdname(mddev), conf->geo.raid_disks - mddev->degraded);
 }
 
 static void print_conf(struct r10conf *conf)
@@ -1458,10 +1554,10 @@
 		printk(KERN_DEBUG "(!conf)\n");
 		return;
 	}
-	printk(KERN_DEBUG " --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,
-		conf->raid_disks);
+	printk(KERN_DEBUG " --- wd:%d rd:%d\n", conf->geo.raid_disks - conf->mddev->degraded,
+		conf->geo.raid_disks);
 
-	for (i = 0; i < conf->raid_disks; i++) {
+	for (i = 0; i < conf->geo.raid_disks; i++) {
 		char b[BDEVNAME_SIZE];
 		tmp = conf->mirrors + i;
 		if (tmp->rdev)
@@ -1493,7 +1589,7 @@
 	 * Find all non-in_sync disks within the RAID10 configuration
 	 * and mark them in_sync
 	 */
-	for (i = 0; i < conf->raid_disks; i++) {
+	for (i = 0; i < conf->geo.raid_disks; i++) {
 		tmp = conf->mirrors + i;
 		if (tmp->replacement
 		    && tmp->replacement->recovery_offset == MaxSector
@@ -1535,7 +1631,7 @@
 	int err = -EEXIST;
 	int mirror;
 	int first = 0;
-	int last = conf->raid_disks - 1;
+	int last = conf->geo.raid_disks - 1;
 	struct request_queue *q = bdev_get_queue(rdev->bdev);
 
 	if (mddev->recovery_cp < MaxSector)
@@ -1543,7 +1639,7 @@
 		 * very different from resync
 		 */
 		return -EBUSY;
-	if (rdev->saved_raid_disk < 0 && !enough(conf, -1))
+	if (rdev->saved_raid_disk < 0 && !_enough(conf, &conf->prev, -1))
 		return -EINVAL;
 
 	if (rdev->raid_disk >= 0)
@@ -1635,6 +1731,7 @@
 	if (!test_bit(Faulty, &rdev->flags) &&
 	    mddev->recovery_disabled != p->recovery_disabled &&
 	    (!p->replacement || p->replacement == rdev) &&
+	    number < conf->geo.raid_disks &&
 	    enough(conf, -1)) {
 		err = -EBUSY;
 		goto abort;
@@ -1676,7 +1773,11 @@
 	struct r10conf *conf = r10_bio->mddev->private;
 	int d;
 
-	d = find_bio_disk(conf, r10_bio, bio, NULL, NULL);
+	if (bio == r10_bio->master_bio) {
+		/* this is a reshape read */
+		d = r10_bio->read_slot; /* really the read dev */
+	} else
+		d = find_bio_disk(conf, r10_bio, bio, NULL, NULL);
 
 	if (test_bit(BIO_UPTODATE, &bio->bi_flags))
 		set_bit(R10BIO_Uptodate, &r10_bio->state);
@@ -2218,7 +2319,9 @@
 				       " (%d sectors at %llu on %s)\n",
 				       mdname(mddev), s,
 				       (unsigned long long)(
-					       sect + rdev->data_offset),
+					       sect +
+					       choose_data_offset(r10_bio,
+								  rdev)),
 				       bdevname(rdev->bdev, b));
 				printk(KERN_NOTICE "md/raid10:%s: %s: failing "
 				       "drive\n",
@@ -2256,7 +2359,8 @@
 				       " (%d sectors at %llu on %s)\n",
 				       mdname(mddev), s,
 				       (unsigned long long)(
-					       sect + rdev->data_offset),
+					       sect +
+					       choose_data_offset(r10_bio, rdev)),
 				       bdevname(rdev->bdev, b));
 				printk(KERN_NOTICE "md/raid10:%s: %s: failing "
 				       "drive\n",
@@ -2269,7 +2373,8 @@
 				       " (%d sectors at %llu on %s)\n",
 				       mdname(mddev), s,
 				       (unsigned long long)(
-					       sect + rdev->data_offset),
+					       sect +
+					       choose_data_offset(r10_bio, rdev)),
 				       bdevname(rdev->bdev, b));
 				atomic_add(s, &rdev->corrected_errors);
 			}
@@ -2343,7 +2448,7 @@
 		wbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
 		md_trim_bio(wbio, sector - bio->bi_sector, sectors);
 		wbio->bi_sector = (r10_bio->devs[i].addr+
-				   rdev->data_offset+
+				   choose_data_offset(r10_bio, rdev) +
 				   (sector - r10_bio->sector));
 		wbio->bi_bdev = rdev->bdev;
 		if (submit_bio_wait(WRITE, wbio) == 0)
@@ -2420,7 +2525,7 @@
 	r10_bio->devs[slot].bio = bio;
 	r10_bio->devs[slot].rdev = rdev;
 	bio->bi_sector = r10_bio->devs[slot].addr
-		+ rdev->data_offset;
+		+ choose_data_offset(r10_bio, rdev);
 	bio->bi_bdev = rdev->bdev;
 	bio->bi_rw = READ | do_sync;
 	bio->bi_private = r10_bio;
@@ -2480,7 +2585,7 @@
 				rdev_clear_badblocks(
 					rdev,
 					r10_bio->devs[m].addr,
-					r10_bio->sectors);
+					r10_bio->sectors, 0);
 			} else {
 				if (!rdev_set_badblocks(
 					    rdev,
@@ -2496,7 +2601,7 @@
 				rdev_clear_badblocks(
 					rdev,
 					r10_bio->devs[m].addr,
-					r10_bio->sectors);
+					r10_bio->sectors, 0);
 			} else {
 				if (!rdev_set_badblocks(
 					    rdev,
@@ -2515,7 +2620,7 @@
 				rdev_clear_badblocks(
 					rdev,
 					r10_bio->devs[m].addr,
-					r10_bio->sectors);
+					r10_bio->sectors, 0);
 				rdev_dec_pending(rdev, conf->mddev);
 			} else if (bio != NULL &&
 				   !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
@@ -2532,7 +2637,7 @@
 				rdev_clear_badblocks(
 					rdev,
 					r10_bio->devs[m].addr,
-					r10_bio->sectors);
+					r10_bio->sectors, 0);
 				rdev_dec_pending(rdev, conf->mddev);
 			}
 		}
@@ -2573,6 +2678,8 @@
 		if (test_bit(R10BIO_MadeGood, &r10_bio->state) ||
 		    test_bit(R10BIO_WriteError, &r10_bio->state))
 			handle_write_completed(conf, r10_bio);
+		else if (test_bit(R10BIO_IsReshape, &r10_bio->state))
+			reshape_request_write(mddev, r10_bio);
 		else if (test_bit(R10BIO_IsSync, &r10_bio->state))
 			sync_request_write(mddev, r10_bio);
 		else if (test_bit(R10BIO_IsRecover, &r10_bio->state))
@@ -2603,7 +2710,7 @@
 	buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
 	BUG_ON(conf->r10buf_pool);
 	conf->have_replacement = 0;
-	for (i = 0; i < conf->raid_disks; i++)
+	for (i = 0; i < conf->geo.raid_disks; i++)
 		if (conf->mirrors[i].replacement)
 			conf->have_replacement = 1;
 	conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf);
@@ -2657,6 +2764,7 @@
 	sector_t sync_blocks;
 	sector_t sectors_skipped = 0;
 	int chunks_skipped = 0;
+	sector_t chunk_mask = conf->geo.chunk_mask;
 
 	if (!conf->r10buf_pool)
 		if (init_resync(conf))
@@ -2664,7 +2772,8 @@
 
  skipped:
 	max_sector = mddev->dev_sectors;
-	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+	    test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
 		max_sector = mddev->resync_max_sectors;
 	if (sector_nr >= max_sector) {
 		/* If we aborted, we need to abort the
@@ -2676,11 +2785,16 @@
 		 * we need to convert that to several
 		 * virtual addresses.
 		 */
+		if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
+			end_reshape(conf);
+			return 0;
+		}
+
 		if (mddev->curr_resync < max_sector) { /* aborted */
 			if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
 				bitmap_end_sync(mddev->bitmap, mddev->curr_resync,
 						&sync_blocks, 1);
-			else for (i=0; i<conf->raid_disks; i++) {
+			else for (i = 0; i < conf->geo.raid_disks; i++) {
 				sector_t sect =
 					raid10_find_virt(conf, mddev->curr_resync, i);
 				bitmap_end_sync(mddev->bitmap, sect,
@@ -2694,7 +2808,7 @@
 				/* Completed a full sync so the replacements
 				 * are now fully recovered.
 				 */
-				for (i = 0; i < conf->raid_disks; i++)
+				for (i = 0; i < conf->geo.raid_disks; i++)
 					if (conf->mirrors[i].replacement)
 						conf->mirrors[i].replacement
 							->recovery_offset
@@ -2707,7 +2821,11 @@
 		*skipped = 1;
 		return sectors_skipped;
 	}
-	if (chunks_skipped >= conf->raid_disks) {
+
+	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+		return reshape_request(mddev, sector_nr, skipped);
+
+	if (chunks_skipped >= conf->geo.raid_disks) {
 		/* if there has been nothing to do on any drive,
 		 * then there is nothing to do at all..
 		 */
@@ -2721,9 +2839,9 @@
 	/* make sure whole request will fit in a chunk - if chunks
 	 * are meaningful
 	 */
-	if (conf->near_copies < conf->raid_disks &&
-	    max_sector > (sector_nr | conf->chunk_mask))
-		max_sector = (sector_nr | conf->chunk_mask) + 1;
+	if (conf->geo.near_copies < conf->geo.raid_disks &&
+	    max_sector > (sector_nr | chunk_mask))
+		max_sector = (sector_nr | chunk_mask) + 1;
 	/*
 	 * If there is non-resync activity waiting for us then
 	 * put in a delay to throttle resync.
@@ -2752,7 +2870,7 @@
 		int j;
 		r10_bio = NULL;
 
-		for (i=0 ; i<conf->raid_disks; i++) {
+		for (i = 0 ; i < conf->geo.raid_disks; i++) {
 			int still_degraded;
 			struct r10bio *rb2;
 			sector_t sect;
@@ -2806,7 +2924,7 @@
 			/* Need to check if the array will still be
 			 * degraded
 			 */
-			for (j=0; j<conf->raid_disks; j++)
+			for (j = 0; j < conf->geo.raid_disks; j++)
 				if (conf->mirrors[j].rdev == NULL ||
 				    test_bit(Faulty, &conf->mirrors[j].rdev->flags)) {
 					still_degraded = 1;
@@ -2984,9 +3102,9 @@
 		r10_bio->sector = sector_nr;
 		set_bit(R10BIO_IsSync, &r10_bio->state);
 		raid10_find_phys(conf, r10_bio);
-		r10_bio->sectors = (sector_nr | conf->chunk_mask) - sector_nr +1;
+		r10_bio->sectors = (sector_nr | chunk_mask) - sector_nr + 1;
 
-		for (i=0; i<conf->copies; i++) {
+		for (i = 0; i < conf->copies; i++) {
 			int d = r10_bio->devs[i].devnum;
 			sector_t first_bad, sector;
 			int bad_sectors;
@@ -3152,16 +3270,17 @@
 	struct r10conf *conf = mddev->private;
 
 	if (!raid_disks)
-		raid_disks = conf->raid_disks;
+		raid_disks = min(conf->geo.raid_disks,
+				 conf->prev.raid_disks);
 	if (!sectors)
 		sectors = conf->dev_sectors;
 
-	size = sectors >> conf->chunk_shift;
-	sector_div(size, conf->far_copies);
+	size = sectors >> conf->geo.chunk_shift;
+	sector_div(size, conf->geo.far_copies);
 	size = size * raid_disks;
-	sector_div(size, conf->near_copies);
+	sector_div(size, conf->geo.near_copies);
 
-	return size << conf->chunk_shift;
+	return size << conf->geo.chunk_shift;
 }
 
 static void calc_sectors(struct r10conf *conf, sector_t size)
@@ -3171,10 +3290,10 @@
 	 * conf->stride
 	 */
 
-	size = size >> conf->chunk_shift;
-	sector_div(size, conf->far_copies);
-	size = size * conf->raid_disks;
-	sector_div(size, conf->near_copies);
+	size = size >> conf->geo.chunk_shift;
+	sector_div(size, conf->geo.far_copies);
+	size = size * conf->geo.raid_disks;
+	sector_div(size, conf->geo.near_copies);
 	/* 'size' is now the number of chunks in the array */
 	/* calculate "used chunks per device" */
 	size = size * conf->copies;
@@ -3182,38 +3301,76 @@
 	/* We need to round up when dividing by raid_disks to
 	 * get the stride size.
 	 */
-	size = DIV_ROUND_UP_SECTOR_T(size, conf->raid_disks);
+	size = DIV_ROUND_UP_SECTOR_T(size, conf->geo.raid_disks);
 
-	conf->dev_sectors = size << conf->chunk_shift;
+	conf->dev_sectors = size << conf->geo.chunk_shift;
 
-	if (conf->far_offset)
-		conf->stride = 1 << conf->chunk_shift;
+	if (conf->geo.far_offset)
+		conf->geo.stride = 1 << conf->geo.chunk_shift;
 	else {
-		sector_div(size, conf->far_copies);
-		conf->stride = size << conf->chunk_shift;
+		sector_div(size, conf->geo.far_copies);
+		conf->geo.stride = size << conf->geo.chunk_shift;
 	}
 }
 
+enum geo_type {geo_new, geo_old, geo_start};
+static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new)
+{
+	int nc, fc, fo;
+	int layout, chunk, disks;
+	switch (new) {
+	case geo_old:
+		layout = mddev->layout;
+		chunk = mddev->chunk_sectors;
+		disks = mddev->raid_disks - mddev->delta_disks;
+		break;
+	case geo_new:
+		layout = mddev->new_layout;
+		chunk = mddev->new_chunk_sectors;
+		disks = mddev->raid_disks;
+		break;
+	default: /* avoid 'may be unused' warnings */
+	case geo_start: /* new when starting reshape - raid_disks not
+			 * updated yet. */
+		layout = mddev->new_layout;
+		chunk = mddev->new_chunk_sectors;
+		disks = mddev->raid_disks + mddev->delta_disks;
+		break;
+	}
+	if (layout >> 17)
+		return -1;
+	if (chunk < (PAGE_SIZE >> 9) ||
+	    !is_power_of_2(chunk))
+		return -2;
+	nc = layout & 255;
+	fc = (layout >> 8) & 255;
+	fo = layout & (1<<16);
+	geo->raid_disks = disks;
+	geo->near_copies = nc;
+	geo->far_copies = fc;
+	geo->far_offset = fo;
+	geo->chunk_mask = chunk - 1;
+	geo->chunk_shift = ffz(~chunk);
+	return nc*fc;
+}
+
 static struct r10conf *setup_conf(struct mddev *mddev)
 {
 	struct r10conf *conf = NULL;
-	int nc, fc, fo;
 	int err = -EINVAL;
+	struct geom geo;
+	int copies;
 
-	if (mddev->new_chunk_sectors < (PAGE_SIZE >> 9) ||
-	    !is_power_of_2(mddev->new_chunk_sectors)) {
+	copies = setup_geo(&geo, mddev, geo_new);
+
+	if (copies == -2) {
 		printk(KERN_ERR "md/raid10:%s: chunk size must be "
 		       "at least PAGE_SIZE(%ld) and be a power of 2.\n",
 		       mdname(mddev), PAGE_SIZE);
 		goto out;
 	}
 
-	nc = mddev->new_layout & 255;
-	fc = (mddev->new_layout >> 8) & 255;
-	fo = mddev->new_layout & (1<<16);
-
-	if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
-	    (mddev->new_layout >> 17)) {
+	if (copies < 2 || copies > mddev->raid_disks) {
 		printk(KERN_ERR "md/raid10:%s: unsupported raid10 layout: 0x%8x\n",
 		       mdname(mddev), mddev->new_layout);
 		goto out;
@@ -3224,7 +3381,9 @@
 	if (!conf)
 		goto out;
 
-	conf->mirrors = kzalloc(sizeof(struct mirror_info)*mddev->raid_disks,
+	/* FIXME calc properly */
+	conf->mirrors = kzalloc(sizeof(struct mirror_info)*(mddev->raid_disks +
+							    max(0,mddev->delta_disks)),
 				GFP_KERNEL);
 	if (!conf->mirrors)
 		goto out;
@@ -3233,22 +3392,29 @@
 	if (!conf->tmppage)
 		goto out;
 
-
-	conf->raid_disks = mddev->raid_disks;
-	conf->near_copies = nc;
-	conf->far_copies = fc;
-	conf->copies = nc*fc;
-	conf->far_offset = fo;
-	conf->chunk_mask = mddev->new_chunk_sectors - 1;
-	conf->chunk_shift = ffz(~mddev->new_chunk_sectors);
-
+	conf->geo = geo;
+	conf->copies = copies;
 	conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
 					   r10bio_pool_free, conf);
 	if (!conf->r10bio_pool)
 		goto out;
 
 	calc_sectors(conf, mddev->dev_sectors);
-
+	if (mddev->reshape_position == MaxSector) {
+		conf->prev = conf->geo;
+		conf->reshape_progress = MaxSector;
+	} else {
+		if (setup_geo(&conf->prev, mddev, geo_old) != conf->copies) {
+			err = -EINVAL;
+			goto out;
+		}
+		conf->reshape_progress = mddev->reshape_position;
+		if (conf->prev.far_offset)
+			conf->prev.stride = 1 << conf->prev.chunk_shift;
+		else
+			/* far_copies must be 1 */
+			conf->prev.stride = conf->dev_sectors;
+	}
 	spin_lock_init(&conf->device_lock);
 	INIT_LIST_HEAD(&conf->retry_list);
 
@@ -3263,8 +3429,9 @@
 	return conf;
 
  out:
-	printk(KERN_ERR "md/raid10:%s: couldn't allocate memory.\n",
-	       mdname(mddev));
+	if (err == -ENOMEM)
+		printk(KERN_ERR "md/raid10:%s: couldn't allocate memory.\n",
+		       mdname(mddev));
 	if (conf) {
 		if (conf->r10bio_pool)
 			mempool_destroy(conf->r10bio_pool);
@@ -3282,12 +3449,8 @@
 	struct mirror_info *disk;
 	struct md_rdev *rdev;
 	sector_t size;
-
-	/*
-	 * copy the already verified devices into our private RAID10
-	 * bookkeeping area. [whatever we allocate in run(),
-	 * should be freed in stop()]
-	 */
+	sector_t min_offset_diff = 0;
+	int first = 1;
 
 	if (mddev->private == NULL) {
 		conf = setup_conf(mddev);
@@ -3304,17 +3467,20 @@
 
 	chunk_size = mddev->chunk_sectors << 9;
 	blk_queue_io_min(mddev->queue, chunk_size);
-	if (conf->raid_disks % conf->near_copies)
-		blk_queue_io_opt(mddev->queue, chunk_size * conf->raid_disks);
+	if (conf->geo.raid_disks % conf->geo.near_copies)
+		blk_queue_io_opt(mddev->queue, chunk_size * conf->geo.raid_disks);
 	else
 		blk_queue_io_opt(mddev->queue, chunk_size *
-				 (conf->raid_disks / conf->near_copies));
+				 (conf->geo.raid_disks / conf->geo.near_copies));
 
 	rdev_for_each(rdev, mddev) {
+		long long diff;
 
 		disk_idx = rdev->raid_disk;
-		if (disk_idx >= conf->raid_disks
-		    || disk_idx < 0)
+		if (disk_idx < 0)
+			continue;
+		if (disk_idx >= conf->geo.raid_disks &&
+		    disk_idx >= conf->prev.raid_disks)
 			continue;
 		disk = conf->mirrors + disk_idx;
 
@@ -3327,12 +3493,20 @@
 				goto out_free_conf;
 			disk->rdev = rdev;
 		}
+		diff = (rdev->new_data_offset - rdev->data_offset);
+		if (!mddev->reshape_backwards)
+			diff = -diff;
+		if (diff < 0)
+			diff = 0;
+		if (first || diff < min_offset_diff)
+			min_offset_diff = diff;
 
 		disk_stack_limits(mddev->gendisk, rdev->bdev,
 				  rdev->data_offset << 9);
 
 		disk->head_position = 0;
 	}
+
 	/* need to check that every block has at least one working mirror */
 	if (!enough(conf, -1)) {
 		printk(KERN_ERR "md/raid10:%s: not enough operational mirrors.\n",
@@ -3340,8 +3514,21 @@
 		goto out_free_conf;
 	}
 
+	if (conf->reshape_progress != MaxSector) {
+		/* must ensure that shape change is supported */
+		if (conf->geo.far_copies != 1 &&
+		    conf->geo.far_offset == 0)
+			goto out_free_conf;
+		if (conf->prev.far_copies != 1 &&
+		    conf->geo.far_offset == 0)
+			goto out_free_conf;
+	}
+
 	mddev->degraded = 0;
-	for (i = 0; i < conf->raid_disks; i++) {
+	for (i = 0;
+	     i < conf->geo.raid_disks
+		     || i < conf->prev.raid_disks;
+	     i++) {
 
 		disk = conf->mirrors + i;
 
@@ -3368,8 +3555,8 @@
 		       mdname(mddev));
 	printk(KERN_INFO
 		"md/raid10:%s: active with %d out of %d devices\n",
-		mdname(mddev), conf->raid_disks - mddev->degraded,
-		conf->raid_disks);
+		mdname(mddev), conf->geo.raid_disks - mddev->degraded,
+		conf->geo.raid_disks);
 	/*
 	 * Ok, everything is just fine now
 	 */
@@ -3386,11 +3573,11 @@
 	 * maybe...
 	 */
 	{
-		int stripe = conf->raid_disks *
+		int stripe = conf->geo.raid_disks *
 			((mddev->chunk_sectors << 9) / PAGE_SIZE);
-		stripe /= conf->near_copies;
-		if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
-			mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+		stripe /= conf->geo.near_copies;
+		if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+			mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
 	}
 
 	blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
@@ -3398,6 +3585,30 @@
 	if (md_integrity_register(mddev))
 		goto out_free_conf;
 
+	if (conf->reshape_progress != MaxSector) {
+		unsigned long before_length, after_length;
+
+		before_length = ((1 << conf->prev.chunk_shift) *
+				 conf->prev.far_copies);
+		after_length = ((1 << conf->geo.chunk_shift) *
+				conf->geo.far_copies);
+
+		if (max(before_length, after_length) > min_offset_diff) {
+			/* This cannot work */
+			printk("md/raid10: offset difference not enough to continue reshape\n");
+			goto out_free_conf;
+		}
+		conf->offset_diff = min_offset_diff;
+
+		conf->reshape_safe = conf->reshape_progress;
+		clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+		clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+		set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+		set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+		mddev->sync_thread = md_register_thread(md_do_sync, mddev,
+							"reshape");
+	}
+
 	return 0;
 
 out_free_conf:
@@ -3460,14 +3671,23 @@
 	struct r10conf *conf = mddev->private;
 	sector_t oldsize, size;
 
-	if (conf->far_copies > 1 && !conf->far_offset)
+	if (mddev->reshape_position != MaxSector)
+		return -EBUSY;
+
+	if (conf->geo.far_copies > 1 && !conf->geo.far_offset)
 		return -EINVAL;
 
 	oldsize = raid10_size(mddev, 0, 0);
 	size = raid10_size(mddev, sectors, 0);
-	md_set_array_sectors(mddev, size);
-	if (mddev->array_sectors > size)
+	if (mddev->external_size &&
+	    mddev->array_sectors > size)
 		return -EINVAL;
+	if (mddev->bitmap) {
+		int ret = bitmap_resize(mddev->bitmap, size, 0, 0);
+		if (ret)
+			return ret;
+	}
+	md_set_array_sectors(mddev, size);
 	set_capacity(mddev->gendisk, mddev->array_sectors);
 	revalidate_disk(mddev->gendisk);
 	if (sectors > mddev->dev_sectors &&
@@ -3534,6 +3754,758 @@
 	return ERR_PTR(-EINVAL);
 }
 
+static int raid10_check_reshape(struct mddev *mddev)
+{
+	/* Called when there is a request to change
+	 * - layout (to ->new_layout)
+	 * - chunk size (to ->new_chunk_sectors)
+	 * - raid_disks (by delta_disks)
+	 * or when trying to restart a reshape that was ongoing.
+	 *
+	 * We need to validate the request and possibly allocate
+	 * space if that might be an issue later.
+	 *
+	 * Currently we reject any reshape of a 'far' mode array,
+	 * allow chunk size to change if new is generally acceptable,
+	 * allow raid_disks to increase, and allow
+	 * a switch between 'near' mode and 'offset' mode.
+	 */
+	struct r10conf *conf = mddev->private;
+	struct geom geo;
+
+	if (conf->geo.far_copies != 1 && !conf->geo.far_offset)
+		return -EINVAL;
+
+	if (setup_geo(&geo, mddev, geo_start) != conf->copies)
+		/* mustn't change number of copies */
+		return -EINVAL;
+	if (geo.far_copies > 1 && !geo.far_offset)
+		/* Cannot switch to 'far' mode */
+		return -EINVAL;
+
+	if (mddev->array_sectors & geo.chunk_mask)
+			/* not factor of array size */
+			return -EINVAL;
+
+	if (!enough(conf, -1))
+		return -EINVAL;
+
+	kfree(conf->mirrors_new);
+	conf->mirrors_new = NULL;
+	if (mddev->delta_disks > 0) {
+		/* allocate new 'mirrors' list */
+		conf->mirrors_new = kzalloc(
+			sizeof(struct mirror_info)
+			*(mddev->raid_disks +
+			  mddev->delta_disks),
+			GFP_KERNEL);
+		if (!conf->mirrors_new)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+/*
+ * Need to check if array has failed when deciding whether to:
+ *  - start an array
+ *  - remove non-faulty devices
+ *  - add a spare
+ *  - allow a reshape
+ * This determination is simple when no reshape is happening.
+ * However if there is a reshape, we need to carefully check
+ * both the before and after sections.
+ * This is because some failed devices may only affect one
+ * of the two sections, and some non-in_sync devices may
+ * be insync in the section most affected by failed devices.
+ */
+static int calc_degraded(struct r10conf *conf)
+{
+	int degraded, degraded2;
+	int i;
+
+	rcu_read_lock();
+	degraded = 0;
+	/* 'prev' section first */
+	for (i = 0; i < conf->prev.raid_disks; i++) {
+		struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
+		if (!rdev || test_bit(Faulty, &rdev->flags))
+			degraded++;
+		else if (!test_bit(In_sync, &rdev->flags))
+			/* When we can reduce the number of devices in
+			 * an array, this might not contribute to
+			 * 'degraded'.  It does now.
+			 */
+			degraded++;
+	}
+	rcu_read_unlock();
+	if (conf->geo.raid_disks == conf->prev.raid_disks)
+		return degraded;
+	rcu_read_lock();
+	degraded2 = 0;
+	for (i = 0; i < conf->geo.raid_disks; i++) {
+		struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
+		if (!rdev || test_bit(Faulty, &rdev->flags))
+			degraded2++;
+		else if (!test_bit(In_sync, &rdev->flags)) {
+			/* If reshape is increasing the number of devices,
+			 * this section has already been recovered, so
+			 * it doesn't contribute to degraded.
+			 * else it does.
+			 */
+			if (conf->geo.raid_disks <= conf->prev.raid_disks)
+				degraded2++;
+		}
+	}
+	rcu_read_unlock();
+	if (degraded2 > degraded)
+		return degraded2;
+	return degraded;
+}
+
+static int raid10_start_reshape(struct mddev *mddev)
+{
+	/* A 'reshape' has been requested. This commits
+	 * the various 'new' fields and sets MD_RECOVER_RESHAPE
+	 * This also checks if there are enough spares and adds them
+	 * to the array.
+	 * We currently require enough spares to make the final
+	 * array non-degraded.  We also require that the difference
+	 * between old and new data_offset - on each device - is
+	 * enough that we never risk over-writing.
+	 */
+
+	unsigned long before_length, after_length;
+	sector_t min_offset_diff = 0;
+	int first = 1;
+	struct geom new;
+	struct r10conf *conf = mddev->private;
+	struct md_rdev *rdev;
+	int spares = 0;
+	int ret;
+
+	if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+		return -EBUSY;
+
+	if (setup_geo(&new, mddev, geo_start) != conf->copies)
+		return -EINVAL;
+
+	before_length = ((1 << conf->prev.chunk_shift) *
+			 conf->prev.far_copies);
+	after_length = ((1 << conf->geo.chunk_shift) *
+			conf->geo.far_copies);
+
+	rdev_for_each(rdev, mddev) {
+		if (!test_bit(In_sync, &rdev->flags)
+		    && !test_bit(Faulty, &rdev->flags))
+			spares++;
+		if (rdev->raid_disk >= 0) {
+			long long diff = (rdev->new_data_offset
+					  - rdev->data_offset);
+			if (!mddev->reshape_backwards)
+				diff = -diff;
+			if (diff < 0)
+				diff = 0;
+			if (first || diff < min_offset_diff)
+				min_offset_diff = diff;
+		}
+	}
+
+	if (max(before_length, after_length) > min_offset_diff)
+		return -EINVAL;
+
+	if (spares < mddev->delta_disks)
+		return -EINVAL;
+
+	conf->offset_diff = min_offset_diff;
+	spin_lock_irq(&conf->device_lock);
+	if (conf->mirrors_new) {
+		memcpy(conf->mirrors_new, conf->mirrors,
+		       sizeof(struct mirror_info)*conf->prev.raid_disks);
+		smp_mb();
+		kfree(conf->mirrors_old); /* FIXME and elsewhere */
+		conf->mirrors_old = conf->mirrors;
+		conf->mirrors = conf->mirrors_new;
+		conf->mirrors_new = NULL;
+	}
+	setup_geo(&conf->geo, mddev, geo_start);
+	smp_mb();
+	if (mddev->reshape_backwards) {
+		sector_t size = raid10_size(mddev, 0, 0);
+		if (size < mddev->array_sectors) {
+			spin_unlock_irq(&conf->device_lock);
+			printk(KERN_ERR "md/raid10:%s: array size must be reduce before number of disks\n",
+			       mdname(mddev));
+			return -EINVAL;
+		}
+		mddev->resync_max_sectors = size;
+		conf->reshape_progress = size;
+	} else
+		conf->reshape_progress = 0;
+	spin_unlock_irq(&conf->device_lock);
+
+	if (mddev->delta_disks && mddev->bitmap) {
+		ret = bitmap_resize(mddev->bitmap,
+				    raid10_size(mddev, 0,
+						conf->geo.raid_disks),
+				    0, 0);
+		if (ret)
+			goto abort;
+	}
+	if (mddev->delta_disks > 0) {
+		rdev_for_each(rdev, mddev)
+			if (rdev->raid_disk < 0 &&
+			    !test_bit(Faulty, &rdev->flags)) {
+				if (raid10_add_disk(mddev, rdev) == 0) {
+					if (rdev->raid_disk >=
+					    conf->prev.raid_disks)
+						set_bit(In_sync, &rdev->flags);
+					else
+						rdev->recovery_offset = 0;
+
+					if (sysfs_link_rdev(mddev, rdev))
+						/* Failure here  is OK */;
+				}
+			} else if (rdev->raid_disk >= conf->prev.raid_disks
+				   && !test_bit(Faulty, &rdev->flags)) {
+				/* This is a spare that was manually added */
+				set_bit(In_sync, &rdev->flags);
+			}
+	}
+	/* When a reshape changes the number of devices,
+	 * ->degraded is measured against the larger of the
+	 * pre and  post numbers.
+	 */
+	spin_lock_irq(&conf->device_lock);
+	mddev->degraded = calc_degraded(conf);
+	spin_unlock_irq(&conf->device_lock);
+	mddev->raid_disks = conf->geo.raid_disks;
+	mddev->reshape_position = conf->reshape_progress;
+	set_bit(MD_CHANGE_DEVS, &mddev->flags);
+
+	clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+	clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+	set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+	set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+
+	mddev->sync_thread = md_register_thread(md_do_sync, mddev,
+						"reshape");
+	if (!mddev->sync_thread) {
+		ret = -EAGAIN;
+		goto abort;
+	}
+	conf->reshape_checkpoint = jiffies;
+	md_wakeup_thread(mddev->sync_thread);
+	md_new_event(mddev);
+	return 0;
+
+abort:
+	mddev->recovery = 0;
+	spin_lock_irq(&conf->device_lock);
+	conf->geo = conf->prev;
+	mddev->raid_disks = conf->geo.raid_disks;
+	rdev_for_each(rdev, mddev)
+		rdev->new_data_offset = rdev->data_offset;
+	smp_wmb();
+	conf->reshape_progress = MaxSector;
+	mddev->reshape_position = MaxSector;
+	spin_unlock_irq(&conf->device_lock);
+	return ret;
+}
+
+/* Calculate the last device-address that could contain
+ * any block from the chunk that includes the array-address 's'
+ * and report the next address.
+ * i.e. the address returned will be chunk-aligned and after
+ * any data that is in the chunk containing 's'.
+ */
+static sector_t last_dev_address(sector_t s, struct geom *geo)
+{
+	s = (s | geo->chunk_mask) + 1;
+	s >>= geo->chunk_shift;
+	s *= geo->near_copies;
+	s = DIV_ROUND_UP_SECTOR_T(s, geo->raid_disks);
+	s *= geo->far_copies;
+	s <<= geo->chunk_shift;
+	return s;
+}
+
+/* Calculate the first device-address that could contain
+ * any block from the chunk that includes the array-address 's'.
+ * This too will be the start of a chunk
+ */
+static sector_t first_dev_address(sector_t s, struct geom *geo)
+{
+	s >>= geo->chunk_shift;
+	s *= geo->near_copies;
+	sector_div(s, geo->raid_disks);
+	s *= geo->far_copies;
+	s <<= geo->chunk_shift;
+	return s;
+}
+
+static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
+				int *skipped)
+{
+	/* We simply copy at most one chunk (smallest of old and new)
+	 * at a time, possibly less if that exceeds RESYNC_PAGES,
+	 * or we hit a bad block or something.
+	 * This might mean we pause for normal IO in the middle of
+	 * a chunk, but that is not a problem was mddev->reshape_position
+	 * can record any location.
+	 *
+	 * If we will want to write to a location that isn't
+	 * yet recorded as 'safe' (i.e. in metadata on disk) then
+	 * we need to flush all reshape requests and update the metadata.
+	 *
+	 * When reshaping forwards (e.g. to more devices), we interpret
+	 * 'safe' as the earliest block which might not have been copied
+	 * down yet.  We divide this by previous stripe size and multiply
+	 * by previous stripe length to get lowest device offset that we
+	 * cannot write to yet.
+	 * We interpret 'sector_nr' as an address that we want to write to.
+	 * From this we use last_device_address() to find where we might
+	 * write to, and first_device_address on the  'safe' position.
+	 * If this 'next' write position is after the 'safe' position,
+	 * we must update the metadata to increase the 'safe' position.
+	 *
+	 * When reshaping backwards, we round in the opposite direction
+	 * and perform the reverse test:  next write position must not be
+	 * less than current safe position.
+	 *
+	 * In all this the minimum difference in data offsets
+	 * (conf->offset_diff - always positive) allows a bit of slack,
+	 * so next can be after 'safe', but not by more than offset_disk
+	 *
+	 * We need to prepare all the bios here before we start any IO
+	 * to ensure the size we choose is acceptable to all devices.
+	 * The means one for each copy for write-out and an extra one for
+	 * read-in.
+	 * We store the read-in bio in ->master_bio and the others in
+	 * ->devs[x].bio and ->devs[x].repl_bio.
+	 */
+	struct r10conf *conf = mddev->private;
+	struct r10bio *r10_bio;
+	sector_t next, safe, last;
+	int max_sectors;
+	int nr_sectors;
+	int s;
+	struct md_rdev *rdev;
+	int need_flush = 0;
+	struct bio *blist;
+	struct bio *bio, *read_bio;
+	int sectors_done = 0;
+
+	if (sector_nr == 0) {
+		/* If restarting in the middle, skip the initial sectors */
+		if (mddev->reshape_backwards &&
+		    conf->reshape_progress < raid10_size(mddev, 0, 0)) {
+			sector_nr = (raid10_size(mddev, 0, 0)
+				     - conf->reshape_progress);
+		} else if (!mddev->reshape_backwards &&
+			   conf->reshape_progress > 0)
+			sector_nr = conf->reshape_progress;
+		if (sector_nr) {
+			mddev->curr_resync_completed = sector_nr;
+			sysfs_notify(&mddev->kobj, NULL, "sync_completed");
+			*skipped = 1;
+			return sector_nr;
+		}
+	}
+
+	/* We don't use sector_nr to track where we are up to
+	 * as that doesn't work well for ->reshape_backwards.
+	 * So just use ->reshape_progress.
+	 */
+	if (mddev->reshape_backwards) {
+		/* 'next' is the earliest device address that we might
+		 * write to for this chunk in the new layout
+		 */
+		next = first_dev_address(conf->reshape_progress - 1,
+					 &conf->geo);
+
+		/* 'safe' is the last device address that we might read from
+		 * in the old layout after a restart
+		 */
+		safe = last_dev_address(conf->reshape_safe - 1,
+					&conf->prev);
+
+		if (next + conf->offset_diff < safe)
+			need_flush = 1;
+
+		last = conf->reshape_progress - 1;
+		sector_nr = last & ~(sector_t)(conf->geo.chunk_mask
+					       & conf->prev.chunk_mask);
+		if (sector_nr + RESYNC_BLOCK_SIZE/512 < last)
+			sector_nr = last + 1 - RESYNC_BLOCK_SIZE/512;
+	} else {
+		/* 'next' is after the last device address that we
+		 * might write to for this chunk in the new layout
+		 */
+		next = last_dev_address(conf->reshape_progress, &conf->geo);
+
+		/* 'safe' is the earliest device address that we might
+		 * read from in the old layout after a restart
+		 */
+		safe = first_dev_address(conf->reshape_safe, &conf->prev);
+
+		/* Need to update metadata if 'next' might be beyond 'safe'
+		 * as that would possibly corrupt data
+		 */
+		if (next > safe + conf->offset_diff)
+			need_flush = 1;
+
+		sector_nr = conf->reshape_progress;
+		last  = sector_nr | (conf->geo.chunk_mask
+				     & conf->prev.chunk_mask);
+
+		if (sector_nr + RESYNC_BLOCK_SIZE/512 <= last)
+			last = sector_nr + RESYNC_BLOCK_SIZE/512 - 1;
+	}
+
+	if (need_flush ||
+	    time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
+		/* Need to update reshape_position in metadata */
+		wait_barrier(conf);
+		mddev->reshape_position = conf->reshape_progress;
+		if (mddev->reshape_backwards)
+			mddev->curr_resync_completed = raid10_size(mddev, 0, 0)
+				- conf->reshape_progress;
+		else
+			mddev->curr_resync_completed = conf->reshape_progress;
+		conf->reshape_checkpoint = jiffies;
+		set_bit(MD_CHANGE_DEVS, &mddev->flags);
+		md_wakeup_thread(mddev->thread);
+		wait_event(mddev->sb_wait, mddev->flags == 0 ||
+			   kthread_should_stop());
+		conf->reshape_safe = mddev->reshape_position;
+		allow_barrier(conf);
+	}
+
+read_more:
+	/* Now schedule reads for blocks from sector_nr to last */
+	r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+	raise_barrier(conf, sectors_done != 0);
+	atomic_set(&r10_bio->remaining, 0);
+	r10_bio->mddev = mddev;
+	r10_bio->sector = sector_nr;
+	set_bit(R10BIO_IsReshape, &r10_bio->state);
+	r10_bio->sectors = last - sector_nr + 1;
+	rdev = read_balance(conf, r10_bio, &max_sectors);
+	BUG_ON(!test_bit(R10BIO_Previous, &r10_bio->state));
+
+	if (!rdev) {
+		/* Cannot read from here, so need to record bad blocks
+		 * on all the target devices.
+		 */
+		// FIXME
+		set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+		return sectors_done;
+	}
+
+	read_bio = bio_alloc_mddev(GFP_KERNEL, RESYNC_PAGES, mddev);
+
+	read_bio->bi_bdev = rdev->bdev;
+	read_bio->bi_sector = (r10_bio->devs[r10_bio->read_slot].addr
+			       + rdev->data_offset);
+	read_bio->bi_private = r10_bio;
+	read_bio->bi_end_io = end_sync_read;
+	read_bio->bi_rw = READ;
+	read_bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+	read_bio->bi_flags |= 1 << BIO_UPTODATE;
+	read_bio->bi_vcnt = 0;
+	read_bio->bi_idx = 0;
+	read_bio->bi_size = 0;
+	r10_bio->master_bio = read_bio;
+	r10_bio->read_slot = r10_bio->devs[r10_bio->read_slot].devnum;
+
+	/* Now find the locations in the new layout */
+	__raid10_find_phys(&conf->geo, r10_bio);
+
+	blist = read_bio;
+	read_bio->bi_next = NULL;
+
+	for (s = 0; s < conf->copies*2; s++) {
+		struct bio *b;
+		int d = r10_bio->devs[s/2].devnum;
+		struct md_rdev *rdev2;
+		if (s&1) {
+			rdev2 = conf->mirrors[d].replacement;
+			b = r10_bio->devs[s/2].repl_bio;
+		} else {
+			rdev2 = conf->mirrors[d].rdev;
+			b = r10_bio->devs[s/2].bio;
+		}
+		if (!rdev2 || test_bit(Faulty, &rdev2->flags))
+			continue;
+		b->bi_bdev = rdev2->bdev;
+		b->bi_sector = r10_bio->devs[s/2].addr + rdev2->new_data_offset;
+		b->bi_private = r10_bio;
+		b->bi_end_io = end_reshape_write;
+		b->bi_rw = WRITE;
+		b->bi_flags &= ~(BIO_POOL_MASK - 1);
+		b->bi_flags |= 1 << BIO_UPTODATE;
+		b->bi_next = blist;
+		b->bi_vcnt = 0;
+		b->bi_idx = 0;
+		b->bi_size = 0;
+		blist = b;
+	}
+
+	/* Now add as many pages as possible to all of these bios. */
+
+	nr_sectors = 0;
+	for (s = 0 ; s < max_sectors; s += PAGE_SIZE >> 9) {
+		struct page *page = r10_bio->devs[0].bio->bi_io_vec[s/(PAGE_SIZE>>9)].bv_page;
+		int len = (max_sectors - s) << 9;
+		if (len > PAGE_SIZE)
+			len = PAGE_SIZE;
+		for (bio = blist; bio ; bio = bio->bi_next) {
+			struct bio *bio2;
+			if (bio_add_page(bio, page, len, 0))
+				continue;
+
+			/* Didn't fit, must stop */
+			for (bio2 = blist;
+			     bio2 && bio2 != bio;
+			     bio2 = bio2->bi_next) {
+				/* Remove last page from this bio */
+				bio2->bi_vcnt--;
+				bio2->bi_size -= len;
+				bio2->bi_flags &= ~(1<<BIO_SEG_VALID);
+			}
+			goto bio_full;
+		}
+		sector_nr += len >> 9;
+		nr_sectors += len >> 9;
+	}
+bio_full:
+	r10_bio->sectors = nr_sectors;
+
+	/* Now submit the read */
+	md_sync_acct(read_bio->bi_bdev, r10_bio->sectors);
+	atomic_inc(&r10_bio->remaining);
+	read_bio->bi_next = NULL;
+	generic_make_request(read_bio);
+	sector_nr += nr_sectors;
+	sectors_done += nr_sectors;
+	if (sector_nr <= last)
+		goto read_more;
+
+	/* Now that we have done the whole section we can
+	 * update reshape_progress
+	 */
+	if (mddev->reshape_backwards)
+		conf->reshape_progress -= sectors_done;
+	else
+		conf->reshape_progress += sectors_done;
+
+	return sectors_done;
+}
+
+static void end_reshape_request(struct r10bio *r10_bio);
+static int handle_reshape_read_error(struct mddev *mddev,
+				     struct r10bio *r10_bio);
+static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio)
+{
+	/* Reshape read completed.  Hopefully we have a block
+	 * to write out.
+	 * If we got a read error then we do sync 1-page reads from
+	 * elsewhere until we find the data - or give up.
+	 */
+	struct r10conf *conf = mddev->private;
+	int s;
+
+	if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
+		if (handle_reshape_read_error(mddev, r10_bio) < 0) {
+			/* Reshape has been aborted */
+			md_done_sync(mddev, r10_bio->sectors, 0);
+			return;
+		}
+
+	/* We definitely have the data in the pages, schedule the
+	 * writes.
+	 */
+	atomic_set(&r10_bio->remaining, 1);
+	for (s = 0; s < conf->copies*2; s++) {
+		struct bio *b;
+		int d = r10_bio->devs[s/2].devnum;
+		struct md_rdev *rdev;
+		if (s&1) {
+			rdev = conf->mirrors[d].replacement;
+			b = r10_bio->devs[s/2].repl_bio;
+		} else {
+			rdev = conf->mirrors[d].rdev;
+			b = r10_bio->devs[s/2].bio;
+		}
+		if (!rdev || test_bit(Faulty, &rdev->flags))
+			continue;
+		atomic_inc(&rdev->nr_pending);
+		md_sync_acct(b->bi_bdev, r10_bio->sectors);
+		atomic_inc(&r10_bio->remaining);
+		b->bi_next = NULL;
+		generic_make_request(b);
+	}
+	end_reshape_request(r10_bio);
+}
+
+static void end_reshape(struct r10conf *conf)
+{
+	if (test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery))
+		return;
+
+	spin_lock_irq(&conf->device_lock);
+	conf->prev = conf->geo;
+	md_finish_reshape(conf->mddev);
+	smp_wmb();
+	conf->reshape_progress = MaxSector;
+	spin_unlock_irq(&conf->device_lock);
+
+	/* read-ahead size must cover two whole stripes, which is
+	 * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
+	 */
+	if (conf->mddev->queue) {
+		int stripe = conf->geo.raid_disks *
+			((conf->mddev->chunk_sectors << 9) / PAGE_SIZE);
+		stripe /= conf->geo.near_copies;
+		if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+			conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+	}
+	conf->fullsync = 0;
+}
+
+
+static int handle_reshape_read_error(struct mddev *mddev,
+				     struct r10bio *r10_bio)
+{
+	/* Use sync reads to get the blocks from somewhere else */
+	int sectors = r10_bio->sectors;
+	struct r10bio r10b;
+	struct r10conf *conf = mddev->private;
+	int slot = 0;
+	int idx = 0;
+	struct bio_vec *bvec = r10_bio->master_bio->bi_io_vec;
+
+	r10b.sector = r10_bio->sector;
+	__raid10_find_phys(&conf->prev, &r10b);
+
+	while (sectors) {
+		int s = sectors;
+		int success = 0;
+		int first_slot = slot;
+
+		if (s > (PAGE_SIZE >> 9))
+			s = PAGE_SIZE >> 9;
+
+		while (!success) {
+			int d = r10b.devs[slot].devnum;
+			struct md_rdev *rdev = conf->mirrors[d].rdev;
+			sector_t addr;
+			if (rdev == NULL ||
+			    test_bit(Faulty, &rdev->flags) ||
+			    !test_bit(In_sync, &rdev->flags))
+				goto failed;
+
+			addr = r10b.devs[slot].addr + idx * PAGE_SIZE;
+			success = sync_page_io(rdev,
+					       addr,
+					       s << 9,
+					       bvec[idx].bv_page,
+					       READ, false);
+			if (success)
+				break;
+		failed:
+			slot++;
+			if (slot >= conf->copies)
+				slot = 0;
+			if (slot == first_slot)
+				break;
+		}
+		if (!success) {
+			/* couldn't read this block, must give up */
+			set_bit(MD_RECOVERY_INTR,
+				&mddev->recovery);
+			return -EIO;
+		}
+		sectors -= s;
+		idx++;
+	}
+	return 0;
+}
+
+static void end_reshape_write(struct bio *bio, int error)
+{
+	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+	struct r10bio *r10_bio = bio->bi_private;
+	struct mddev *mddev = r10_bio->mddev;
+	struct r10conf *conf = mddev->private;
+	int d;
+	int slot;
+	int repl;
+	struct md_rdev *rdev = NULL;
+
+	d = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
+	if (repl)
+		rdev = conf->mirrors[d].replacement;
+	if (!rdev) {
+		smp_mb();
+		rdev = conf->mirrors[d].rdev;
+	}
+
+	if (!uptodate) {
+		/* FIXME should record badblock */
+		md_error(mddev, rdev);
+	}
+
+	rdev_dec_pending(rdev, mddev);
+	end_reshape_request(r10_bio);
+}
+
+static void end_reshape_request(struct r10bio *r10_bio)
+{
+	if (!atomic_dec_and_test(&r10_bio->remaining))
+		return;
+	md_done_sync(r10_bio->mddev, r10_bio->sectors, 1);
+	bio_put(r10_bio->master_bio);
+	put_buf(r10_bio);
+}
+
+static void raid10_finish_reshape(struct mddev *mddev)
+{
+	struct r10conf *conf = mddev->private;
+
+	if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+		return;
+
+	if (mddev->delta_disks > 0) {
+		sector_t size = raid10_size(mddev, 0, 0);
+		md_set_array_sectors(mddev, size);
+		if (mddev->recovery_cp > mddev->resync_max_sectors) {
+			mddev->recovery_cp = mddev->resync_max_sectors;
+			set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+		}
+		mddev->resync_max_sectors = size;
+		set_capacity(mddev->gendisk, mddev->array_sectors);
+		revalidate_disk(mddev->gendisk);
+	} else {
+		int d;
+		for (d = conf->geo.raid_disks ;
+		     d < conf->geo.raid_disks - mddev->delta_disks;
+		     d++) {
+			struct md_rdev *rdev = conf->mirrors[d].rdev;
+			if (rdev)
+				clear_bit(In_sync, &rdev->flags);
+			rdev = conf->mirrors[d].replacement;
+			if (rdev)
+				clear_bit(In_sync, &rdev->flags);
+		}
+	}
+	mddev->layout = mddev->new_layout;
+	mddev->chunk_sectors = 1 << conf->geo.chunk_shift;
+	mddev->reshape_position = MaxSector;
+	mddev->delta_disks = 0;
+	mddev->reshape_backwards = 0;
+}
+
 static struct md_personality raid10_personality =
 {
 	.name		= "raid10",
@@ -3552,6 +4524,9 @@
 	.size		= raid10_size,
 	.resize		= raid10_resize,
 	.takeover	= raid10_takeover,
+	.check_reshape	= raid10_check_reshape,
+	.start_reshape	= raid10_start_reshape,
+	.finish_reshape	= raid10_finish_reshape,
 };
 
 static int __init raid_init(void)
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index 7c615613..135b1b0 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -14,32 +14,38 @@
 struct r10conf {
 	struct mddev		*mddev;
 	struct mirror_info	*mirrors;
-	int			raid_disks;
+	struct mirror_info	*mirrors_new, *mirrors_old;
 	spinlock_t		device_lock;
 
 	/* geometry */
-	int			near_copies;  /* number of copies laid out
+	struct geom {
+		int		raid_disks;
+		int		near_copies;  /* number of copies laid out
 					       * raid0 style */
-	int 			far_copies;   /* number of copies laid out
+		int		far_copies;   /* number of copies laid out
 					       * at large strides across drives
 					       */
-	int			far_offset;   /* far_copies are offset by 1
+		int		far_offset;   /* far_copies are offset by 1
 					       * stripe instead of many
 					       */
-	int			copies;	      /* near_copies * far_copies.
-					       * must be <= raid_disks
-					       */
-	sector_t		stride;	      /* distance between far copies.
+		sector_t	stride;	      /* distance between far copies.
 					       * This is size / far_copies unless
 					       * far_offset, in which case it is
 					       * 1 stripe.
 					       */
+		int		chunk_shift; /* shift from chunks to sectors */
+		sector_t	chunk_mask;
+	} prev, geo;
+	int			copies;	      /* near_copies * far_copies.
+					       * must be <= raid_disks
+					       */
 
 	sector_t		dev_sectors;  /* temp copy of
 					       * mddev->dev_sectors */
-
-	int			chunk_shift; /* shift from chunks to sectors */
-	sector_t		chunk_mask;
+	sector_t		reshape_progress;
+	sector_t		reshape_safe;
+	unsigned long		reshape_checkpoint;
+	sector_t		offset_diff;
 
 	struct list_head	retry_list;
 	/* queue pending writes and submit them on unplug */
@@ -136,6 +142,7 @@
 	R10BIO_Uptodate,
 	R10BIO_IsSync,
 	R10BIO_IsRecover,
+	R10BIO_IsReshape,
 	R10BIO_Degraded,
 /* Set ReadError on bios that experience a read error
  * so that raid10d knows what to do with them.
@@ -146,5 +153,10 @@
  */
 	R10BIO_MadeGood,
 	R10BIO_WriteError,
+/* During a reshape we might be performing IO on the
+ * 'previous' part of the array, in which case this
+ * flag is set
+ */
+	R10BIO_Previous,
 };
 #endif
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index f351422..d267672 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -488,6 +488,27 @@
 	return sh;
 }
 
+/* Determine if 'data_offset' or 'new_data_offset' should be used
+ * in this stripe_head.
+ */
+static int use_new_offset(struct r5conf *conf, struct stripe_head *sh)
+{
+	sector_t progress = conf->reshape_progress;
+	/* Need a memory barrier to make sure we see the value
+	 * of conf->generation, or ->data_offset that was set before
+	 * reshape_progress was updated.
+	 */
+	smp_rmb();
+	if (progress == MaxSector)
+		return 0;
+	if (sh->generation == conf->generation - 1)
+		return 0;
+	/* We are in a reshape, and this is a new-generation stripe,
+	 * so use new_data_offset.
+	 */
+	return 1;
+}
+
 static void
 raid5_end_read_request(struct bio *bi, int error);
 static void
@@ -518,6 +539,8 @@
 			replace_only = 1;
 		} else
 			continue;
+		if (test_and_clear_bit(R5_SyncIO, &sh->dev[i].flags))
+			rw |= REQ_SYNC;
 
 		bi = &sh->dev[i].req;
 		rbi = &sh->dev[i].rreq; /* For writing to replacement */
@@ -603,7 +626,12 @@
 				__func__, (unsigned long long)sh->sector,
 				bi->bi_rw, i);
 			atomic_inc(&sh->count);
-			bi->bi_sector = sh->sector + rdev->data_offset;
+			if (use_new_offset(conf, sh))
+				bi->bi_sector = (sh->sector
+						 + rdev->new_data_offset);
+			else
+				bi->bi_sector = (sh->sector
+						 + rdev->data_offset);
 			bi->bi_flags = 1 << BIO_UPTODATE;
 			bi->bi_idx = 0;
 			bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
@@ -627,7 +655,12 @@
 				__func__, (unsigned long long)sh->sector,
 				rbi->bi_rw, i);
 			atomic_inc(&sh->count);
-			rbi->bi_sector = sh->sector + rrdev->data_offset;
+			if (use_new_offset(conf, sh))
+				rbi->bi_sector = (sh->sector
+						  + rrdev->new_data_offset);
+			else
+				rbi->bi_sector = (sh->sector
+						  + rrdev->data_offset);
 			rbi->bi_flags = 1 << BIO_UPTODATE;
 			rbi->bi_idx = 0;
 			rbi->bi_io_vec[0].bv_len = STRIPE_SIZE;
@@ -1114,6 +1147,8 @@
 				dev->sector + STRIPE_SECTORS) {
 				if (wbi->bi_rw & REQ_FUA)
 					set_bit(R5_WantFUA, &dev->flags);
+				if (wbi->bi_rw & REQ_SYNC)
+					set_bit(R5_SyncIO, &dev->flags);
 				tx = async_copy_data(1, wbi, dev->page,
 					dev->sector, tx);
 				wbi = r5_next_bio(wbi, dev->sector);
@@ -1131,13 +1166,15 @@
 	int pd_idx = sh->pd_idx;
 	int qd_idx = sh->qd_idx;
 	int i;
-	bool fua = false;
+	bool fua = false, sync = false;
 
 	pr_debug("%s: stripe %llu\n", __func__,
 		(unsigned long long)sh->sector);
 
-	for (i = disks; i--; )
+	for (i = disks; i--; ) {
 		fua |= test_bit(R5_WantFUA, &sh->dev[i].flags);
+		sync |= test_bit(R5_SyncIO, &sh->dev[i].flags);
+	}
 
 	for (i = disks; i--; ) {
 		struct r5dev *dev = &sh->dev[i];
@@ -1146,6 +1183,8 @@
 			set_bit(R5_UPTODATE, &dev->flags);
 			if (fua)
 				set_bit(R5_WantFUA, &dev->flags);
+			if (sync)
+				set_bit(R5_SyncIO, &dev->flags);
 		}
 	}
 
@@ -1648,7 +1687,7 @@
 	int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
 	char b[BDEVNAME_SIZE];
 	struct md_rdev *rdev = NULL;
-
+	sector_t s;
 
 	for (i=0 ; i<disks; i++)
 		if (bi == &sh->dev[i].req)
@@ -1671,6 +1710,10 @@
 	if (!rdev)
 		rdev = conf->disks[i].rdev;
 
+	if (use_new_offset(conf, sh))
+		s = sh->sector + rdev->new_data_offset;
+	else
+		s = sh->sector + rdev->data_offset;
 	if (uptodate) {
 		set_bit(R5_UPTODATE, &sh->dev[i].flags);
 		if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
@@ -1683,8 +1726,7 @@
 				"md/raid:%s: read error corrected"
 				" (%lu sectors at %llu on %s)\n",
 				mdname(conf->mddev), STRIPE_SECTORS,
-				(unsigned long long)(sh->sector
-						     + rdev->data_offset),
+				(unsigned long long)s,
 				bdevname(rdev->bdev, b));
 			atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
 			clear_bit(R5_ReadError, &sh->dev[i].flags);
@@ -1704,8 +1746,7 @@
 				"md/raid:%s: read error on replacement device "
 				"(sector %llu on %s).\n",
 				mdname(conf->mddev),
-				(unsigned long long)(sh->sector
-						     + rdev->data_offset),
+				(unsigned long long)s,
 				bdn);
 		else if (conf->mddev->degraded >= conf->max_degraded)
 			printk_ratelimited(
@@ -1713,8 +1754,7 @@
 				"md/raid:%s: read error not correctable "
 				"(sector %llu on %s).\n",
 				mdname(conf->mddev),
-				(unsigned long long)(sh->sector
-						     + rdev->data_offset),
+				(unsigned long long)s,
 				bdn);
 		else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
 			/* Oh, no!!! */
@@ -1723,8 +1763,7 @@
 				"md/raid:%s: read error NOT corrected!! "
 				"(sector %llu on %s).\n",
 				mdname(conf->mddev),
-				(unsigned long long)(sh->sector
-						     + rdev->data_offset),
+				(unsigned long long)s,
 				bdn);
 		else if (atomic_read(&rdev->read_errors)
 			 > conf->max_nr_stripes)
@@ -3561,7 +3600,7 @@
 			if (test_and_clear_bit(R5_MadeGood, &dev->flags)) {
 				rdev = conf->disks[i].rdev;
 				rdev_clear_badblocks(rdev, sh->sector,
-						     STRIPE_SECTORS);
+						     STRIPE_SECTORS, 0);
 				rdev_dec_pending(rdev, conf->mddev);
 			}
 			if (test_and_clear_bit(R5_MadeGoodRepl, &dev->flags)) {
@@ -3570,7 +3609,7 @@
 					/* rdev have been moved down */
 					rdev = conf->disks[i].rdev;
 				rdev_clear_badblocks(rdev, sh->sector,
-						     STRIPE_SECTORS);
+						     STRIPE_SECTORS, 0);
 				rdev_dec_pending(rdev, conf->mddev);
 			}
 		}
@@ -3842,6 +3881,7 @@
 		raid_bio->bi_next = (void*)rdev;
 		align_bi->bi_bdev =  rdev->bdev;
 		align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
+		/* No reshape active, so we can trust rdev->data_offset */
 		align_bi->bi_sector += rdev->data_offset;
 
 		if (!bio_fits_rdev(align_bi) ||
@@ -3953,12 +3993,10 @@
 	plugged = mddev_check_plugged(mddev);
 	for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
 		DEFINE_WAIT(w);
-		int disks, data_disks;
 		int previous;
 
 	retry:
 		previous = 0;
-		disks = conf->raid_disks;
 		prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
 		if (unlikely(conf->reshape_progress != MaxSector)) {
 			/* spinlock is needed as reshape_progress may be
@@ -3970,13 +4008,12 @@
 			 * to check again.
 			 */
 			spin_lock_irq(&conf->device_lock);
-			if (mddev->delta_disks < 0
+			if (mddev->reshape_backwards
 			    ? logical_sector < conf->reshape_progress
 			    : logical_sector >= conf->reshape_progress) {
-				disks = conf->previous_raid_disks;
 				previous = 1;
 			} else {
-				if (mddev->delta_disks < 0
+				if (mddev->reshape_backwards
 				    ? logical_sector < conf->reshape_safe
 				    : logical_sector >= conf->reshape_safe) {
 					spin_unlock_irq(&conf->device_lock);
@@ -3986,7 +4023,6 @@
 			}
 			spin_unlock_irq(&conf->device_lock);
 		}
-		data_disks = disks - conf->max_degraded;
 
 		new_sector = raid5_compute_sector(conf, logical_sector,
 						  previous,
@@ -4009,7 +4045,7 @@
 				 */
 				int must_retry = 0;
 				spin_lock_irq(&conf->device_lock);
-				if (mddev->delta_disks < 0
+				if (mddev->reshape_backwards
 				    ? logical_sector >= conf->reshape_progress
 				    : logical_sector < conf->reshape_progress)
 					/* mismatch, need to try again */
@@ -4108,11 +4144,11 @@
 
 	if (sector_nr == 0) {
 		/* If restarting in the middle, skip the initial sectors */
-		if (mddev->delta_disks < 0 &&
+		if (mddev->reshape_backwards &&
 		    conf->reshape_progress < raid5_size(mddev, 0, 0)) {
 			sector_nr = raid5_size(mddev, 0, 0)
 				- conf->reshape_progress;
-		} else if (mddev->delta_disks >= 0 &&
+		} else if (!mddev->reshape_backwards &&
 			   conf->reshape_progress > 0)
 			sector_nr = conf->reshape_progress;
 		sector_div(sector_nr, new_data_disks);
@@ -4133,13 +4169,11 @@
 	else
 		reshape_sectors = mddev->chunk_sectors;
 
-	/* we update the metadata when there is more than 3Meg
-	 * in the block range (that is rather arbitrary, should
-	 * probably be time based) or when the data about to be
-	 * copied would over-write the source of the data at
-	 * the front of the range.
-	 * i.e. one new_stripe along from reshape_progress new_maps
-	 * to after where reshape_safe old_maps to
+	/* We update the metadata at least every 10 seconds, or when
+	 * the data about to be copied would over-write the source of
+	 * the data at the front of the range.  i.e. one new_stripe
+	 * along from reshape_progress new_maps to after where
+	 * reshape_safe old_maps to
 	 */
 	writepos = conf->reshape_progress;
 	sector_div(writepos, new_data_disks);
@@ -4147,7 +4181,7 @@
 	sector_div(readpos, data_disks);
 	safepos = conf->reshape_safe;
 	sector_div(safepos, data_disks);
-	if (mddev->delta_disks < 0) {
+	if (mddev->reshape_backwards) {
 		writepos -= min_t(sector_t, reshape_sectors, writepos);
 		readpos += reshape_sectors;
 		safepos += reshape_sectors;
@@ -4157,11 +4191,29 @@
 		safepos -= min_t(sector_t, reshape_sectors, safepos);
 	}
 
+	/* Having calculated the 'writepos' possibly use it
+	 * to set 'stripe_addr' which is where we will write to.
+	 */
+	if (mddev->reshape_backwards) {
+		BUG_ON(conf->reshape_progress == 0);
+		stripe_addr = writepos;
+		BUG_ON((mddev->dev_sectors &
+			~((sector_t)reshape_sectors - 1))
+		       - reshape_sectors - stripe_addr
+		       != sector_nr);
+	} else {
+		BUG_ON(writepos != sector_nr + reshape_sectors);
+		stripe_addr = sector_nr;
+	}
+
 	/* 'writepos' is the most advanced device address we might write.
 	 * 'readpos' is the least advanced device address we might read.
 	 * 'safepos' is the least address recorded in the metadata as having
 	 *     been reshaped.
-	 * If 'readpos' is behind 'writepos', then there is no way that we can
+	 * If there is a min_offset_diff, these are adjusted either by
+	 * increasing the safepos/readpos if diff is negative, or
+	 * increasing writepos if diff is positive.
+	 * If 'readpos' is then behind 'writepos', there is no way that we can
 	 * ensure safety in the face of a crash - that must be done by userspace
 	 * making a backup of the data.  So in that case there is no particular
 	 * rush to update metadata.
@@ -4174,7 +4226,13 @@
 	 * Maybe that number should be configurable, but I'm not sure it is
 	 * worth it.... maybe it could be a multiple of safemode_delay???
 	 */
-	if ((mddev->delta_disks < 0
+	if (conf->min_offset_diff < 0) {
+		safepos += -conf->min_offset_diff;
+		readpos += -conf->min_offset_diff;
+	} else
+		writepos += conf->min_offset_diff;
+
+	if ((mddev->reshape_backwards
 	     ? (safepos > writepos && readpos < writepos)
 	     : (safepos < writepos && readpos > writepos)) ||
 	    time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
@@ -4195,17 +4253,6 @@
 		sysfs_notify(&mddev->kobj, NULL, "sync_completed");
 	}
 
-	if (mddev->delta_disks < 0) {
-		BUG_ON(conf->reshape_progress == 0);
-		stripe_addr = writepos;
-		BUG_ON((mddev->dev_sectors &
-			~((sector_t)reshape_sectors - 1))
-		       - reshape_sectors - stripe_addr
-		       != sector_nr);
-	} else {
-		BUG_ON(writepos != sector_nr + reshape_sectors);
-		stripe_addr = sector_nr;
-	}
 	INIT_LIST_HEAD(&stripes);
 	for (i = 0; i < reshape_sectors; i += STRIPE_SECTORS) {
 		int j;
@@ -4239,7 +4286,7 @@
 		list_add(&sh->lru, &stripes);
 	}
 	spin_lock_irq(&conf->device_lock);
-	if (mddev->delta_disks < 0)
+	if (mddev->reshape_backwards)
 		conf->reshape_progress -= reshape_sectors * new_data_disks;
 	else
 		conf->reshape_progress += reshape_sectors * new_data_disks;
@@ -4952,16 +4999,42 @@
 	struct md_rdev *rdev;
 	sector_t reshape_offset = 0;
 	int i;
+	long long min_offset_diff = 0;
+	int first = 1;
 
 	if (mddev->recovery_cp != MaxSector)
 		printk(KERN_NOTICE "md/raid:%s: not clean"
 		       " -- starting background reconstruction\n",
 		       mdname(mddev));
+
+	rdev_for_each(rdev, mddev) {
+		long long diff;
+		if (rdev->raid_disk < 0)
+			continue;
+		diff = (rdev->new_data_offset - rdev->data_offset);
+		if (first) {
+			min_offset_diff = diff;
+			first = 0;
+		} else if (mddev->reshape_backwards &&
+			 diff < min_offset_diff)
+			min_offset_diff = diff;
+		else if (!mddev->reshape_backwards &&
+			 diff > min_offset_diff)
+			min_offset_diff = diff;
+	}
+
 	if (mddev->reshape_position != MaxSector) {
 		/* Check that we can continue the reshape.
-		 * Currently only disks can change, it must
-		 * increase, and we must be past the point where
-		 * a stripe over-writes itself
+		 * Difficulties arise if the stripe we would write to
+		 * next is at or after the stripe we would read from next.
+		 * For a reshape that changes the number of devices, this
+		 * is only possible for a very short time, and mdadm makes
+		 * sure that time appears to have past before assembling
+		 * the array.  So we fail if that time hasn't passed.
+		 * For a reshape that keeps the number of devices the same
+		 * mdadm must be monitoring the reshape can keeping the
+		 * critical areas read-only and backed up.  It will start
+		 * the array in read-only mode, so we check for that.
 		 */
 		sector_t here_new, here_old;
 		int old_disks;
@@ -4993,26 +5066,34 @@
 		/* here_old is the first stripe that we might need to read
 		 * from */
 		if (mddev->delta_disks == 0) {
+			if ((here_new * mddev->new_chunk_sectors !=
+			     here_old * mddev->chunk_sectors)) {
+				printk(KERN_ERR "md/raid:%s: reshape position is"
+				       " confused - aborting\n", mdname(mddev));
+				return -EINVAL;
+			}
 			/* We cannot be sure it is safe to start an in-place
-			 * reshape.  It is only safe if user-space if monitoring
+			 * reshape.  It is only safe if user-space is monitoring
 			 * and taking constant backups.
 			 * mdadm always starts a situation like this in
 			 * readonly mode so it can take control before
 			 * allowing any writes.  So just check for that.
 			 */
-			if ((here_new * mddev->new_chunk_sectors != 
-			     here_old * mddev->chunk_sectors) ||
-			    mddev->ro == 0) {
-				printk(KERN_ERR "md/raid:%s: in-place reshape must be started"
-				       " in read-only mode - aborting\n",
+			if (abs(min_offset_diff) >= mddev->chunk_sectors &&
+			    abs(min_offset_diff) >= mddev->new_chunk_sectors)
+				/* not really in-place - so OK */;
+			else if (mddev->ro == 0) {
+				printk(KERN_ERR "md/raid:%s: in-place reshape "
+				       "must be started in read-only mode "
+				       "- aborting\n",
 				       mdname(mddev));
 				return -EINVAL;
 			}
-		} else if (mddev->delta_disks < 0
-		    ? (here_new * mddev->new_chunk_sectors <=
+		} else if (mddev->reshape_backwards
+		    ? (here_new * mddev->new_chunk_sectors + min_offset_diff <=
 		       here_old * mddev->chunk_sectors)
 		    : (here_new * mddev->new_chunk_sectors >=
-		       here_old * mddev->chunk_sectors)) {
+		       here_old * mddev->chunk_sectors + (-min_offset_diff))) {
 			/* Reading from the same stripe as writing to - bad */
 			printk(KERN_ERR "md/raid:%s: reshape_position too early for "
 			       "auto-recovery - aborting.\n",
@@ -5037,6 +5118,7 @@
 	if (IS_ERR(conf))
 		return PTR_ERR(conf);
 
+	conf->min_offset_diff = min_offset_diff;
 	mddev->thread = conf->thread;
 	conf->thread = NULL;
 	mddev->private = conf;
@@ -5182,9 +5264,12 @@
 		blk_queue_io_opt(mddev->queue, chunk_size *
 				 (conf->raid_disks - conf->max_degraded));
 
-		rdev_for_each(rdev, mddev)
+		rdev_for_each(rdev, mddev) {
 			disk_stack_limits(mddev->gendisk, rdev->bdev,
 					  rdev->data_offset << 9);
+			disk_stack_limits(mddev->gendisk, rdev->bdev,
+					  rdev->new_data_offset << 9);
+		}
 	}
 
 	return 0;
@@ -5418,12 +5503,18 @@
 	 * any io in the removed space completes, but it hardly seems
 	 * worth it.
 	 */
+	sector_t newsize;
 	sectors &= ~((sector_t)mddev->chunk_sectors - 1);
-	md_set_array_sectors(mddev, raid5_size(mddev, sectors,
-					       mddev->raid_disks));
-	if (mddev->array_sectors >
-	    raid5_size(mddev, sectors, mddev->raid_disks))
+	newsize = raid5_size(mddev, sectors, mddev->raid_disks);
+	if (mddev->external_size &&
+	    mddev->array_sectors > newsize)
 		return -EINVAL;
+	if (mddev->bitmap) {
+		int ret = bitmap_resize(mddev->bitmap, sectors, 0, 0);
+		if (ret)
+			return ret;
+	}
+	md_set_array_sectors(mddev, newsize);
 	set_capacity(mddev->gendisk, mddev->array_sectors);
 	revalidate_disk(mddev->gendisk);
 	if (sectors > mddev->dev_sectors &&
@@ -5468,9 +5559,6 @@
 	    mddev->new_layout == mddev->layout &&
 	    mddev->new_chunk_sectors == mddev->chunk_sectors)
 		return 0; /* nothing to do */
-	if (mddev->bitmap)
-		/* Cannot grow a bitmap yet */
-		return -EBUSY;
 	if (has_failed(conf))
 		return -EINVAL;
 	if (mddev->delta_disks < 0) {
@@ -5505,10 +5593,14 @@
 	if (!check_stripe_cache(mddev))
 		return -ENOSPC;
 
-	rdev_for_each(rdev, mddev)
+	if (has_failed(conf))
+		return -EINVAL;
+
+	rdev_for_each(rdev, mddev) {
 		if (!test_bit(In_sync, &rdev->flags)
 		    && !test_bit(Faulty, &rdev->flags))
 			spares++;
+	}
 
 	if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded)
 		/* Not enough devices even to make a degraded array
@@ -5535,12 +5627,16 @@
 	conf->chunk_sectors = mddev->new_chunk_sectors;
 	conf->prev_algo = conf->algorithm;
 	conf->algorithm = mddev->new_layout;
-	if (mddev->delta_disks < 0)
+	conf->generation++;
+	/* Code that selects data_offset needs to see the generation update
+	 * if reshape_progress has been set - so a memory barrier needed.
+	 */
+	smp_mb();
+	if (mddev->reshape_backwards)
 		conf->reshape_progress = raid5_size(mddev, 0, 0);
 	else
 		conf->reshape_progress = 0;
 	conf->reshape_safe = conf->reshape_progress;
-	conf->generation++;
 	spin_unlock_irq(&conf->device_lock);
 
 	/* Add some new drives, as many as will fit.
@@ -5592,6 +5688,9 @@
 		mddev->recovery = 0;
 		spin_lock_irq(&conf->device_lock);
 		mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks;
+		rdev_for_each(rdev, mddev)
+			rdev->new_data_offset = rdev->data_offset;
+		smp_wmb();
 		conf->reshape_progress = MaxSector;
 		mddev->reshape_position = MaxSector;
 		spin_unlock_irq(&conf->device_lock);
@@ -5610,9 +5709,13 @@
 {
 
 	if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
+		struct md_rdev *rdev;
 
 		spin_lock_irq(&conf->device_lock);
 		conf->previous_raid_disks = conf->raid_disks;
+		rdev_for_each(rdev, conf->mddev)
+			rdev->data_offset = rdev->new_data_offset;
+		smp_wmb();
 		conf->reshape_progress = MaxSector;
 		spin_unlock_irq(&conf->device_lock);
 		wake_up(&conf->wait_for_overlap);
@@ -5652,17 +5755,18 @@
 			     d < conf->raid_disks - mddev->delta_disks;
 			     d++) {
 				struct md_rdev *rdev = conf->disks[d].rdev;
-				if (rdev &&
-				    raid5_remove_disk(mddev, rdev) == 0) {
-					sysfs_unlink_rdev(mddev, rdev);
-					rdev->raid_disk = -1;
-				}
+				if (rdev)
+					clear_bit(In_sync, &rdev->flags);
+				rdev = conf->disks[d].replacement;
+				if (rdev)
+					clear_bit(In_sync, &rdev->flags);
 			}
 		}
 		mddev->layout = conf->algorithm;
 		mddev->chunk_sectors = conf->chunk_sectors;
 		mddev->reshape_position = MaxSector;
 		mddev->delta_disks = 0;
+		mddev->reshape_backwards = 0;
 	}
 }
 
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index 8d8e139..2164021 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -285,6 +285,7 @@
 			 */
 	R5_Wantdrain,	/* dev->towrite needs to be drained */
 	R5_WantFUA,	/* Write should be FUA */
+	R5_SyncIO,	/* The IO is sync */
 	R5_WriteError,	/* got a write error - need to record it */
 	R5_MadeGood,	/* A bad block has been fixed by writing to it */
 	R5_ReadRepl,	/* Will/did read from replacement rather than orig */
@@ -385,6 +386,12 @@
 	short			generation; /* increments with every reshape */
 	unsigned long		reshape_checkpoint; /* Time we last updated
 						     * metadata */
+	long long		min_offset_diff; /* minimum difference between
+						  * data_offset and
+						  * new_data_offset across all
+						  * devices.  May be negative,
+						  * but is closest to zero.
+						  */
 
 	struct list_head	handle_list; /* stripes needing handling */
 	struct list_head	hold_list; /* preread ready stripes */
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 71f8e01..7d42c11 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -198,7 +198,6 @@
 	struct saa7146_dev *dev = video_drvdata(file);
 	struct saa7146_fh *fh = NULL;
 	int result = 0;
-
 	enum v4l2_buf_type type;
 
 	DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
@@ -227,11 +226,12 @@
 		goto out;
 	}
 
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
+	v4l2_fh_init(&fh->fh, vdev);
 
-	if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+	file->private_data = &fh->fh;
+	fh->dev = dev;
+
+	if (vdev->vfl_type == VFL_TYPE_VBI) {
 		DEB_S("initializing vbi...\n");
 		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
 			result = saa7146_vbi_uops.open(dev,file);
@@ -252,6 +252,7 @@
 	}
 
 	result = 0;
+	v4l2_fh_add(&fh->fh);
 out:
 	if (fh && result != 0) {
 		kfree(fh);
@@ -263,6 +264,7 @@
 
 static int fops_release(struct file *file)
 {
+	struct video_device *vdev = video_devdata(file);
 	struct saa7146_fh  *fh  = file->private_data;
 	struct saa7146_dev *dev = fh->dev;
 
@@ -271,7 +273,7 @@
 	if (mutex_lock_interruptible(&saa7146_devices_lock))
 		return -ERESTARTSYS;
 
-	if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+	if (vdev->vfl_type == VFL_TYPE_VBI) {
 		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
 			saa7146_vbi_uops.release(dev,file);
 		if (dev->ext_vv_data->vbi_fops.release)
@@ -280,6 +282,8 @@
 		saa7146_video_uops.release(dev,file);
 	}
 
+	v4l2_fh_del(&fh->fh);
+	v4l2_fh_exit(&fh->fh);
 	module_put(dev->ext->module);
 	file->private_data = NULL;
 	kfree(fh);
@@ -291,19 +295,22 @@
 
 static int fops_mmap(struct file *file, struct vm_area_struct * vma)
 {
+	struct video_device *vdev = video_devdata(file);
 	struct saa7146_fh *fh = file->private_data;
 	struct videobuf_queue *q;
 
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER: {
 		DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
 		       file, vma);
 		q = &fh->video_q;
 		break;
 		}
-	case V4L2_BUF_TYPE_VBI_CAPTURE: {
+	case VFL_TYPE_VBI: {
 		DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
 		       file, vma);
+		if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
+			return -ENODEV;
 		q = &fh->vbi_q;
 		break;
 		}
@@ -317,15 +324,19 @@
 
 static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
 {
+	struct video_device *vdev = video_devdata(file);
 	struct saa7146_fh *fh = file->private_data;
 	struct videobuf_buffer *buf = NULL;
 	struct videobuf_queue *q;
+	unsigned int res = v4l2_ctrl_poll(file, wait);
 
 	DEB_EE("file:%p, poll:%p\n", file, wait);
 
-	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+	if (vdev->vfl_type == VFL_TYPE_VBI) {
+		if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
+			return res | POLLOUT | POLLWRNORM;
 		if( 0 == fh->vbi_q.streaming )
-			return videobuf_poll_stream(file, &fh->vbi_q, wait);
+			return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
 		q = &fh->vbi_q;
 	} else {
 		DEB_D("using video queue\n");
@@ -337,31 +348,32 @@
 
 	if (!buf) {
 		DEB_D("buf == NULL!\n");
-		return POLLERR;
+		return res | POLLERR;
 	}
 
 	poll_wait(file, &buf->done, wait);
 	if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
 		DEB_D("poll succeeded!\n");
-		return POLLIN|POLLRDNORM;
+		return res | POLLIN | POLLRDNORM;
 	}
 
 	DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
-	return 0;
+	return res;
 }
 
 static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
+	struct video_device *vdev = video_devdata(file);
 	struct saa7146_fh *fh = file->private_data;
 
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
 /*
 		DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
 		       file, data, (unsigned long)count);
 */
 		return saa7146_video_uops.read(file,data,count,ppos);
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case VFL_TYPE_VBI:
 /*
 		DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
 		       file, data, (unsigned long)count);
@@ -377,12 +389,13 @@
 
 static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
 {
+	struct video_device *vdev = video_devdata(file);
 	struct saa7146_fh *fh = file->private_data;
 
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
 		return -EINVAL;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case VFL_TYPE_VBI:
 		if (fh->dev->ext_vv_data->vbi_fops.write)
 			return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
 		else
@@ -429,8 +442,15 @@
 	}
 }
 
+static const struct v4l2_ctrl_ops saa7146_ctrl_ops = {
+	.s_ctrl = saa7146_s_ctrl,
+};
+
 int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
 {
+	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+	struct v4l2_pix_format *fmt;
+	struct v4l2_vbi_format *vbi;
 	struct saa7146_vv *vv;
 	int err;
 
@@ -438,12 +458,32 @@
 	if (err)
 		return err;
 
+	v4l2_ctrl_handler_init(hdl, 6);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_CONTRAST, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_SATURATION, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_HFLIP, 0, 1, 1, 0);
+	if (hdl->error) {
+		err = hdl->error;
+		v4l2_ctrl_handler_free(hdl);
+		return err;
+	}
+	dev->v4l2_dev.ctrl_handler = hdl;
+
 	vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
 	if (vv == NULL) {
 		ERR("out of memory. aborting.\n");
+		v4l2_ctrl_handler_free(hdl);
 		return -ENOMEM;
 	}
-	ext_vv->ops = saa7146_video_ioctl_ops;
+	ext_vv->vid_ops = saa7146_video_ioctl_ops;
+	ext_vv->vbi_ops = saa7146_vbi_ioctl_ops;
 	ext_vv->core_ops = &saa7146_video_ioctl_ops;
 
 	DEB_EE("dev:%p\n", dev);
@@ -463,6 +503,7 @@
 	if( NULL == vv->d_clipping.cpu_addr ) {
 		ERR("out of memory. aborting.\n");
 		kfree(vv);
+		v4l2_ctrl_handler_free(hdl);
 		return -1;
 	}
 	memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
@@ -471,6 +512,39 @@
 	if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
 		saa7146_vbi_uops.init(dev,vv);
 
+	fmt = &vv->ov_fb.fmt;
+	fmt->width = vv->standard->h_max_out;
+	fmt->height = vv->standard->v_max_out;
+	fmt->pixelformat = V4L2_PIX_FMT_RGB565;
+	fmt->bytesperline = 2 * fmt->width;
+	fmt->sizeimage = fmt->bytesperline * fmt->height;
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+	fmt = &vv->video_fmt;
+	fmt->width = 384;
+	fmt->height = 288;
+	fmt->pixelformat = V4L2_PIX_FMT_BGR24;
+	fmt->field = V4L2_FIELD_ANY;
+	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	fmt->bytesperline = 3 * fmt->width;
+	fmt->sizeimage = fmt->bytesperline * fmt->height;
+
+	vbi = &vv->vbi_fmt;
+	vbi->sampling_rate	= 27000000;
+	vbi->offset		= 248; /* todo */
+	vbi->samples_per_line	= 720 * 2;
+	vbi->sample_format	= V4L2_PIX_FMT_GREY;
+
+	/* fixme: this only works for PAL */
+	vbi->start[0] = 5;
+	vbi->count[0] = 16;
+	vbi->start[1] = 312;
+	vbi->count[1] = 16;
+
+	init_timer(&vv->vbi_read_timeout);
+
+	vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+	vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
 	dev->vv_data = vv;
 	dev->vv_callback = &vv_callback;
 
@@ -486,6 +560,7 @@
 
 	v4l2_device_unregister(&dev->v4l2_dev);
 	pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
+	v4l2_ctrl_handler_free(&dev->ctrl_handler);
 	kfree(vv);
 	dev->vv_data = NULL;
 	dev->vv_callback = NULL;
@@ -509,10 +584,19 @@
 		return -ENOMEM;
 
 	vfd->fops = &video_fops;
-	vfd->ioctl_ops = &dev->ext_vv_data->ops;
+	if (type == VFL_TYPE_GRABBER)
+		vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
+	else
+		vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
 	vfd->release = video_device_release;
+	/* Locking in file operations other than ioctl should be done by
+	   the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 	vfd->lock = &dev->v4l2_lock;
+	vfd->v4l2_dev = &dev->v4l2_dev;
 	vfd->tvnorms = 0;
+	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
 	for (i = 0; i < dev->ext_vv_data->num_stds; i++)
 		vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
 	strlcpy(vfd->name, name, sizeof(vfd->name));
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index bc1f545..be746d1 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -343,9 +343,9 @@
 	struct saa7146_vv *vv = dev->vv_data;
 	__le32 *clipping = vv->d_clipping.cpu_addr;
 
-	int width = fh->ov.win.w.width;
-	int height =  fh->ov.win.w.height;
-	int clipcount = fh->ov.nclips;
+	int width = vv->ov.win.w.width;
+	int height =  vv->ov.win.w.height;
+	int clipcount = vv->ov.nclips;
 
 	u32 line_list[32];
 	u32 pixel_list[32];
@@ -365,10 +365,10 @@
 	for(i = 0; i < clipcount; i++) {
 		int l = 0, r = 0, t = 0, b = 0;
 
-		x[i] = fh->ov.clips[i].c.left;
-		y[i] = fh->ov.clips[i].c.top;
-		w[i] = fh->ov.clips[i].c.width;
-		h[i] = fh->ov.clips[i].c.height;
+		x[i] = vv->ov.clips[i].c.left;
+		y[i] = vv->ov.clips[i].c.top;
+		w[i] = vv->ov.clips[i].c.width;
+		h[i] = vv->ov.clips[i].c.height;
 
 		if( w[i] < 0) {
 			x[i] += w[i]; w[i] = -w[i];
@@ -485,13 +485,14 @@
 static void saa7146_set_clipping_rect(struct saa7146_fh *fh)
 {
 	struct saa7146_dev *dev = fh->dev;
-	enum v4l2_field field = fh->ov.win.field;
+	struct saa7146_vv *vv = dev->vv_data;
+	enum v4l2_field field = vv->ov.win.field;
 	struct	saa7146_video_dma vdma2;
 	u32 clip_format;
 	u32 arbtr_ctrl;
 
 	/* check clipcount, disable clipping if clipcount == 0*/
-	if( fh->ov.nclips == 0 ) {
+	if (vv->ov.nclips == 0) {
 		saa7146_disable_clipping(dev);
 		return;
 	}
@@ -651,8 +652,8 @@
 	struct saa7146_dev *dev = fh->dev;
 	struct saa7146_vv *vv = dev->vv_data;
 
-	saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field);
-	saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field, vv->ov_fmt->pixelformat);
+	saa7146_set_window(dev, vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.field);
+	saa7146_set_position(dev, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov.win.w.height, vv->ov.win.field, vv->ov_fmt->pixelformat);
 	saa7146_set_output_format(dev, vv->ov_fmt->trans);
 	saa7146_set_clipping_rect(fh);
 
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index b2e7183..1e71e37 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -211,7 +211,7 @@
 	DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
 	saa7146_set_vbi_capture(dev,buf,next);
 
-	mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);
+	mod_timer(&vv->vbi_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
 	return 0;
 }
 
@@ -294,7 +294,7 @@
 	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
 
 	DEB_VBI("vb:%p\n", vb);
-	saa7146_buffer_queue(dev,&vv->vbi_q,buf);
+	saa7146_buffer_queue(dev, &vv->vbi_dmaq, buf);
 }
 
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -335,16 +335,15 @@
 	/* shut down dma 3 transfers */
 	saa7146_write(dev, MC1, MASK_20);
 
-	if (vv->vbi_q.curr) {
-		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
-	}
+	if (vv->vbi_dmaq.curr)
+		saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
 
 	videobuf_queue_cancel(&fh->vbi_q);
 
 	vv->vbi_streaming = NULL;
 
-	del_timer(&vv->vbi_q.timeout);
-	del_timer(&fh->vbi_read_timeout);
+	del_timer(&vv->vbi_dmaq.timeout);
+	del_timer(&vv->vbi_read_timeout);
 
 	spin_unlock_irqrestore(&dev->slock, flags);
 }
@@ -364,12 +363,12 @@
 {
 	DEB_VBI("dev:%p\n", dev);
 
-	INIT_LIST_HEAD(&vv->vbi_q.queue);
+	INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
 
-	init_timer(&vv->vbi_q.timeout);
-	vv->vbi_q.timeout.function = saa7146_buffer_timeout;
-	vv->vbi_q.timeout.data     = (unsigned long)(&vv->vbi_q);
-	vv->vbi_q.dev              = dev;
+	init_timer(&vv->vbi_dmaq.timeout);
+	vv->vbi_dmaq.timeout.function = saa7146_buffer_timeout;
+	vv->vbi_dmaq.timeout.data     = (unsigned long)(&vv->vbi_dmaq);
+	vv->vbi_dmaq.dev              = dev;
 
 	init_waitqueue_head(&vv->vbi_wq);
 }
@@ -377,6 +376,7 @@
 static int vbi_open(struct saa7146_dev *dev, struct file *file)
 {
 	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_vv *vv = fh->dev->vv_data;
 
 	u32 arbtr_ctrl	= saa7146_read(dev, PCI_BT_V1);
 	int ret = 0;
@@ -395,19 +395,6 @@
 	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
 	saa7146_write(dev, MC2, (MASK_04|MASK_20));
 
-	memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt));
-
-	fh->vbi_fmt.sampling_rate	= 27000000;
-	fh->vbi_fmt.offset		= 248; /* todo */
-	fh->vbi_fmt.samples_per_line	= vbi_pixel_to_capture;
-	fh->vbi_fmt.sample_format	= V4L2_PIX_FMT_GREY;
-
-	/* fixme: this only works for PAL */
-	fh->vbi_fmt.start[0] = 5;
-	fh->vbi_fmt.count[0] = 16;
-	fh->vbi_fmt.start[1] = 312;
-	fh->vbi_fmt.count[1] = 16;
-
 	videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
 			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
@@ -415,9 +402,8 @@
 			    sizeof(struct saa7146_buf),
 			    file, &dev->v4l2_lock);
 
-	init_timer(&fh->vbi_read_timeout);
-	fh->vbi_read_timeout.function = vbi_read_timeout;
-	fh->vbi_read_timeout.data = (unsigned long)file;
+	vv->vbi_read_timeout.function = vbi_read_timeout;
+	vv->vbi_read_timeout.data = (unsigned long)file;
 
 	/* initialize the brs */
 	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
@@ -453,16 +439,16 @@
 	struct saa7146_vv *vv = dev->vv_data;
 	spin_lock(&dev->slock);
 
-	if (vv->vbi_q.curr) {
-		DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_q.curr);
+	if (vv->vbi_dmaq.curr) {
+		DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr);
 		/* this must be += 2, one count for each field */
 		vv->vbi_fieldcount+=2;
-		vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
-		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
+		vv->vbi_dmaq.curr->vb.field_count = vv->vbi_fieldcount;
+		saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
 	} else {
 		DEB_VBI("dev:%p\n", dev);
 	}
-	saa7146_buffer_next(dev,&vv->vbi_q,1);
+	saa7146_buffer_next(dev, &vv->vbi_dmaq, 1);
 
 	spin_unlock(&dev->slock);
 }
@@ -488,7 +474,7 @@
 		return -EBUSY;
 	}
 
-	mod_timer(&fh->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
+	mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
 	ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1,
 				   file->f_flags & O_NONBLOCK);
 /*
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index ce30533..6d14785 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -2,6 +2,8 @@
 
 #include <media/saa7146_vv.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
 #include <linux/module.h>
 
 static int max_memory = 32;
@@ -112,8 +114,8 @@
 
 	DEB_EE("dev:%p, fh:%p\n", dev, fh);
 
-	/* check if we have overlay informations */
-	if( NULL == fh->ov.fh ) {
+	/* check if we have overlay information */
+	if (vv->ov.fh == NULL) {
 		DEB_D("no overlay data available. try S_FMT first.\n");
 		return -EAGAIN;
 	}
@@ -139,19 +141,18 @@
 		return -EBUSY;
 	}
 
-	fmt.fmt.win = fh->ov.win;
+	fmt.fmt.win = vv->ov.win;
 	err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
 	if (0 != err) {
 		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
 		return -EBUSY;
 	}
-	fh->ov.win = fmt.fmt.win;
-	vv->ov_data = &fh->ov;
+	vv->ov.win = fmt.fmt.win;
 
 	DEB_D("%dx%d+%d+%d %s field=%s\n",
-	      fh->ov.win.w.width, fh->ov.win.w.height,
-	      fh->ov.win.w.left, fh->ov.win.w.top,
-	      vv->ov_fmt->name, v4l2_field_names[fh->ov.win.field]);
+	      vv->ov.win.w.width, vv->ov.win.w.height,
+	      vv->ov.win.w.left, vv->ov.win.w.top,
+	      vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]);
 
 	if (0 != (ret = saa7146_enable_overlay(fh))) {
 		DEB_D("enabling overlay failed: %d\n", ret);
@@ -202,65 +203,6 @@
 EXPORT_SYMBOL_GPL(saa7146_stop_preview);
 
 /********************************************************************************/
-/* device controls */
-
-static struct v4l2_queryctrl controls[] = {
-	{
-		.id		= V4L2_CID_BRIGHTNESS,
-		.name		= "Brightness",
-		.minimum	= 0,
-		.maximum	= 255,
-		.step		= 1,
-		.default_value	= 128,
-		.type		= V4L2_CTRL_TYPE_INTEGER,
-		.flags 		= V4L2_CTRL_FLAG_SLIDER,
-	},{
-		.id		= V4L2_CID_CONTRAST,
-		.name		= "Contrast",
-		.minimum	= 0,
-		.maximum	= 127,
-		.step		= 1,
-		.default_value	= 64,
-		.type		= V4L2_CTRL_TYPE_INTEGER,
-		.flags 		= V4L2_CTRL_FLAG_SLIDER,
-	},{
-		.id		= V4L2_CID_SATURATION,
-		.name		= "Saturation",
-		.minimum	= 0,
-		.maximum	= 127,
-		.step		= 1,
-		.default_value	= 64,
-		.type		= V4L2_CTRL_TYPE_INTEGER,
-		.flags 		= V4L2_CTRL_FLAG_SLIDER,
-	},{
-		.id		= V4L2_CID_VFLIP,
-		.name		= "Vertical Flip",
-		.minimum	= 0,
-		.maximum	= 1,
-		.type		= V4L2_CTRL_TYPE_BOOLEAN,
-	},{
-		.id		= V4L2_CID_HFLIP,
-		.name		= "Horizontal Flip",
-		.minimum	= 0,
-		.maximum	= 1,
-		.type		= V4L2_CTRL_TYPE_BOOLEAN,
-	},
-};
-static int NUM_CONTROLS = sizeof(controls)/sizeof(struct v4l2_queryctrl);
-
-#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 0)
-
-static struct v4l2_queryctrl* ctrl_by_id(int id)
-{
-	int i;
-
-	for (i = 0; i < NUM_CONTROLS; i++)
-		if (controls[i].id == id)
-			return controls+i;
-	return NULL;
-}
-
-/********************************************************************************/
 /* common pagetable functions */
 
 static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
@@ -413,7 +355,7 @@
 		}
 	}
 
-	fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
+	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
 	/* we need to have a valid format set here */
 	BUG_ON(NULL == fmt);
 
@@ -465,7 +407,7 @@
 		return -EBUSY;
 	}
 
-	fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
+	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
 	/* we need to have a valid format set here */
 	BUG_ON(NULL == fmt);
 
@@ -504,18 +446,25 @@
 
 static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
 {
+	struct video_device *vdev = video_devdata(file);
 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 
 	strcpy((char *)cap->driver, "saa7146 v4l2");
 	strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
 	sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
-	cap->version = SAA7146_VERSION_CODE;
-	cap->capabilities =
+	cap->device_caps =
 		V4L2_CAP_VIDEO_CAPTURE |
 		V4L2_CAP_VIDEO_OVERLAY |
 		V4L2_CAP_READWRITE |
 		V4L2_CAP_STREAMING;
-	cap->capabilities |= dev->ext_vv_data->capabilities;
+	cap->device_caps |= dev->ext_vv_data->capabilities;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	if (vdev->vfl_type == VFL_TYPE_GRABBER)
+		cap->device_caps &=
+			~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
+	else
+		cap->device_caps &=
+			~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
 	return 0;
 }
 
@@ -526,6 +475,7 @@
 
 	*fb = vv->ov_fb;
 	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+	fb->flags = V4L2_FBUF_FLAG_PRIMARY;
 	return 0;
 }
 
@@ -579,135 +529,58 @@
 	return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
+int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	const struct v4l2_queryctrl *ctrl;
-
-	if ((c->id <  V4L2_CID_BASE ||
-	     c->id >= V4L2_CID_LASTP1) &&
-	    (c->id <  V4L2_CID_PRIVATE_BASE ||
-	     c->id >= V4L2_CID_PRIVATE_LASTP1))
-		return -EINVAL;
-
-	ctrl = ctrl_by_id(c->id);
-	if (ctrl == NULL)
-		return -EINVAL;
-
-	DEB_EE("VIDIOC_QUERYCTRL: id:%d\n", c->id);
-	*c = *ctrl;
-	return 0;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_dev *dev = container_of(ctrl->handler,
+				struct saa7146_dev, ctrl_handler);
 	struct saa7146_vv *vv = dev->vv_data;
-	const struct v4l2_queryctrl *ctrl;
-	u32 value = 0;
+	u32 val;
 
-	ctrl = ctrl_by_id(c->id);
-	if (NULL == ctrl)
-		return -EINVAL;
-	switch (c->id) {
+	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		value = saa7146_read(dev, BCS_CTRL);
-		c->value = 0xff & (value >> 24);
-		DEB_D("V4L2_CID_BRIGHTNESS: %d\n", c->value);
+		val = saa7146_read(dev, BCS_CTRL);
+		val &= 0x00ffffff;
+		val |= (ctrl->val << 24);
+		saa7146_write(dev, BCS_CTRL, val);
+		saa7146_write(dev, MC2, MASK_22 | MASK_06);
 		break;
+
 	case V4L2_CID_CONTRAST:
-		value = saa7146_read(dev, BCS_CTRL);
-		c->value = 0x7f & (value >> 16);
-		DEB_D("V4L2_CID_CONTRAST: %d\n", c->value);
+		val = saa7146_read(dev, BCS_CTRL);
+		val &= 0xff00ffff;
+		val |= (ctrl->val << 16);
+		saa7146_write(dev, BCS_CTRL, val);
+		saa7146_write(dev, MC2, MASK_22 | MASK_06);
 		break;
+
 	case V4L2_CID_SATURATION:
-		value = saa7146_read(dev, BCS_CTRL);
-		c->value = 0x7f & (value >> 0);
-		DEB_D("V4L2_CID_SATURATION: %d\n", c->value);
-		break;
-	case V4L2_CID_VFLIP:
-		c->value = vv->vflip;
-		DEB_D("V4L2_CID_VFLIP: %d\n", c->value);
-		break;
-	case V4L2_CID_HFLIP:
-		c->value = vv->hflip;
-		DEB_D("V4L2_CID_HFLIP: %d\n", c->value);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	const struct v4l2_queryctrl *ctrl;
-
-	ctrl = ctrl_by_id(c->id);
-	if (NULL == ctrl) {
-		DEB_D("unknown control %d\n", c->id);
-		return -EINVAL;
-	}
-
-	switch (ctrl->type) {
-	case V4L2_CTRL_TYPE_BOOLEAN:
-	case V4L2_CTRL_TYPE_MENU:
-	case V4L2_CTRL_TYPE_INTEGER:
-		if (c->value < ctrl->minimum)
-			c->value = ctrl->minimum;
-		if (c->value > ctrl->maximum)
-			c->value = ctrl->maximum;
-		break;
-	default:
-		/* nothing */;
-	}
-
-	switch (c->id) {
-	case V4L2_CID_BRIGHTNESS: {
-		u32 value = saa7146_read(dev, BCS_CTRL);
-		value &= 0x00ffffff;
-		value |= (c->value << 24);
-		saa7146_write(dev, BCS_CTRL, value);
+		val = saa7146_read(dev, BCS_CTRL);
+		val &= 0xffffff00;
+		val |= (ctrl->val << 0);
+		saa7146_write(dev, BCS_CTRL, val);
 		saa7146_write(dev, MC2, MASK_22 | MASK_06);
 		break;
-	}
-	case V4L2_CID_CONTRAST: {
-		u32 value = saa7146_read(dev, BCS_CTRL);
-		value &= 0xff00ffff;
-		value |= (c->value << 16);
-		saa7146_write(dev, BCS_CTRL, value);
-		saa7146_write(dev, MC2, MASK_22 | MASK_06);
-		break;
-	}
-	case V4L2_CID_SATURATION: {
-		u32 value = saa7146_read(dev, BCS_CTRL);
-		value &= 0xffffff00;
-		value |= (c->value << 0);
-		saa7146_write(dev, BCS_CTRL, value);
-		saa7146_write(dev, MC2, MASK_22 | MASK_06);
-		break;
-	}
+
 	case V4L2_CID_HFLIP:
 		/* fixme: we can support changing VFLIP and HFLIP here... */
-		if (IS_CAPTURE_ACTIVE(fh) != 0) {
-			DEB_D("V4L2_CID_HFLIP while active capture\n");
+		if ((vv->video_status & STATUS_CAPTURE))
 			return -EBUSY;
-		}
-		vv->hflip = c->value;
+		vv->hflip = ctrl->val;
 		break;
+
 	case V4L2_CID_VFLIP:
-		if (IS_CAPTURE_ACTIVE(fh) != 0) {
-			DEB_D("V4L2_CID_VFLIP while active capture\n");
+		if ((vv->video_status & STATUS_CAPTURE))
 			return -EBUSY;
-		}
-		vv->vflip = c->value;
+		vv->vflip = ctrl->val;
 		break;
+
 	default:
 		return -EINVAL;
 	}
 
-	if (IS_OVERLAY_ACTIVE(fh) != 0) {
+	if ((vv->video_status & STATUS_OVERLAY) != 0) { /* CHECK: && (vv->video_fh == fh)) */
+		struct saa7146_fh *fh = vv->video_fh;
+
 		saa7146_stop_preview(fh);
 		saa7146_start_preview(fh);
 	}
@@ -720,6 +593,8 @@
 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 	struct saa7146_vv *vv = dev->vv_data;
 
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
 	parm->parm.capture.readbuffers = 1;
 	v4l2_video_std_frame_period(vv->standard->id,
 				    &parm->parm.capture.timeperframe);
@@ -728,19 +603,28 @@
 
 static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
 {
-	f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt;
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	f->fmt.pix = vv->video_fmt;
 	return 0;
 }
 
 static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
 {
-	f->fmt.win = ((struct saa7146_fh *)fh)->ov.win;
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	f->fmt.win = vv->ov.win;
 	return 0;
 }
 
 static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
 {
-	f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt;
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	f->fmt.vbi = vv->vbi_fmt;
 	return 0;
 }
 
@@ -787,6 +671,7 @@
 	}
 
 	f->fmt.pix.field = field;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 	if (f->fmt.pix.width > maxw)
 		f->fmt.pix.width = maxw;
 	if (f->fmt.pix.height > maxh)
@@ -883,9 +768,9 @@
 	err = vidioc_try_fmt_vid_cap(file, fh, f);
 	if (0 != err)
 		return err;
-	fh->video_fmt = f->fmt.pix;
+	vv->video_fmt = f->fmt.pix;
 	DEB_EE("set to pixelformat '%4.4s'\n",
-	       (char *)&fh->video_fmt.pixelformat);
+	       (char *)&vv->video_fmt.pixelformat);
 	return 0;
 }
 
@@ -900,17 +785,17 @@
 	err = vidioc_try_fmt_vid_overlay(file, fh, f);
 	if (0 != err)
 		return err;
-	fh->ov.win    = f->fmt.win;
-	fh->ov.nclips = f->fmt.win.clipcount;
-	if (fh->ov.nclips > 16)
-		fh->ov.nclips = 16;
-	if (copy_from_user(fh->ov.clips, f->fmt.win.clips,
-				sizeof(struct v4l2_clip) * fh->ov.nclips)) {
+	vv->ov.win    = f->fmt.win;
+	vv->ov.nclips = f->fmt.win.clipcount;
+	if (vv->ov.nclips > 16)
+		vv->ov.nclips = 16;
+	if (copy_from_user(vv->ov.clips, f->fmt.win.clips,
+				sizeof(struct v4l2_clip) * vv->ov.nclips)) {
 		return -EFAULT;
 	}
 
-	/* fh->ov.fh is used to indicate that we have valid overlay informations, too */
-	fh->ov.fh = fh;
+	/* vv->ov.fh is used to indicate that we have valid overlay informations, too */
+	vv->ov.fh = fh;
 
 	/* check if our current overlay is active */
 	if (IS_OVERLAY_ACTIVE(fh) != 0) {
@@ -1111,10 +996,14 @@
 
 	chip->ident = V4L2_IDENT_NONE;
 	chip->revision = 0;
-	if (chip->match.type == V4L2_CHIP_MATCH_HOST && !chip->match.addr) {
-		chip->ident = V4L2_IDENT_SAA7146;
+	if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+		if (v4l2_chip_match_host(&chip->match))
+			chip->ident = V4L2_IDENT_SAA7146;
 		return 0;
 	}
+	if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+	    chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
 	return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
 			core, g_chip_ident, chip);
 }
@@ -1129,7 +1018,6 @@
 	.vidioc_g_fmt_vid_overlay    = vidioc_g_fmt_vid_overlay,
 	.vidioc_try_fmt_vid_overlay  = vidioc_try_fmt_vid_overlay,
 	.vidioc_s_fmt_vid_overlay    = vidioc_s_fmt_vid_overlay,
-	.vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,
 	.vidioc_g_chip_ident         = vidioc_g_chip_ident,
 
 	.vidioc_overlay 	     = vidioc_overlay,
@@ -1141,12 +1029,29 @@
 	.vidioc_dqbuf                = vidioc_dqbuf,
 	.vidioc_g_std                = vidioc_g_std,
 	.vidioc_s_std                = vidioc_s_std,
-	.vidioc_queryctrl            = vidioc_queryctrl,
-	.vidioc_g_ctrl               = vidioc_g_ctrl,
-	.vidioc_s_ctrl               = vidioc_s_ctrl,
 	.vidioc_streamon             = vidioc_streamon,
 	.vidioc_streamoff            = vidioc_streamoff,
 	.vidioc_g_parm 		     = vidioc_g_parm,
+	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
+};
+
+const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
+	.vidioc_querycap             = vidioc_querycap,
+	.vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,
+	.vidioc_g_chip_ident         = vidioc_g_chip_ident,
+
+	.vidioc_reqbufs              = vidioc_reqbufs,
+	.vidioc_querybuf             = vidioc_querybuf,
+	.vidioc_qbuf                 = vidioc_qbuf,
+	.vidioc_dqbuf                = vidioc_dqbuf,
+	.vidioc_g_std                = vidioc_g_std,
+	.vidioc_s_std                = vidioc_s_std,
+	.vidioc_streamon             = vidioc_streamon,
+	.vidioc_streamoff            = vidioc_streamoff,
+	.vidioc_g_parm		     = vidioc_g_parm,
+	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
 };
 
 /*********************************************************************************/
@@ -1161,7 +1066,7 @@
 	buf->vb.state = VIDEOBUF_ACTIVE;
 	saa7146_set_capture(dev,buf,next);
 
-	mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT);
+	mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
 	return 0;
 }
 
@@ -1185,44 +1090,44 @@
 	DEB_CAP("vbuf:%p\n", vb);
 
 	/* sanity checks */
-	if (fh->video_fmt.width  < 48 ||
-	    fh->video_fmt.height < 32 ||
-	    fh->video_fmt.width  > vv->standard->h_max_out ||
-	    fh->video_fmt.height > vv->standard->v_max_out) {
+	if (vv->video_fmt.width  < 48 ||
+	    vv->video_fmt.height < 32 ||
+	    vv->video_fmt.width  > vv->standard->h_max_out ||
+	    vv->video_fmt.height > vv->standard->v_max_out) {
 		DEB_D("w (%d) / h (%d) out of bounds\n",
-		      fh->video_fmt.width, fh->video_fmt.height);
+		      vv->video_fmt.width, vv->video_fmt.height);
 		return -EINVAL;
 	}
 
-	size = fh->video_fmt.sizeimage;
+	size = vv->video_fmt.sizeimage;
 	if (0 != buf->vb.baddr && buf->vb.bsize < size) {
 		DEB_D("size mismatch\n");
 		return -EINVAL;
 	}
 
 	DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
-		fh->video_fmt.width, fh->video_fmt.height,
-		size, v4l2_field_names[fh->video_fmt.field]);
-	if (buf->vb.width  != fh->video_fmt.width  ||
-	    buf->vb.bytesperline != fh->video_fmt.bytesperline ||
-	    buf->vb.height != fh->video_fmt.height ||
+		vv->video_fmt.width, vv->video_fmt.height,
+		size, v4l2_field_names[vv->video_fmt.field]);
+	if (buf->vb.width  != vv->video_fmt.width  ||
+	    buf->vb.bytesperline != vv->video_fmt.bytesperline ||
+	    buf->vb.height != vv->video_fmt.height ||
 	    buf->vb.size   != size ||
 	    buf->vb.field  != field      ||
-	    buf->vb.field  != fh->video_fmt.field  ||
-	    buf->fmt       != &fh->video_fmt) {
+	    buf->vb.field  != vv->video_fmt.field  ||
+	    buf->fmt       != &vv->video_fmt) {
 		saa7146_dma_free(dev,q,buf);
 	}
 
 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		struct saa7146_format *sfmt;
 
-		buf->vb.bytesperline  = fh->video_fmt.bytesperline;
-		buf->vb.width  = fh->video_fmt.width;
-		buf->vb.height = fh->video_fmt.height;
+		buf->vb.bytesperline  = vv->video_fmt.bytesperline;
+		buf->vb.width  = vv->video_fmt.width;
+		buf->vb.height = vv->video_fmt.height;
 		buf->vb.size   = size;
 		buf->vb.field  = field;
-		buf->fmt       = &fh->video_fmt;
-		buf->vb.field  = fh->video_fmt.field;
+		buf->fmt       = &vv->video_fmt;
+		buf->vb.field  = vv->video_fmt.field;
 
 		sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
 
@@ -1258,11 +1163,12 @@
 {
 	struct file *file = q->priv_data;
 	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_vv *vv = fh->dev->vv_data;
 
 	if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS)
 		*count = MAX_SAA7146_CAPTURE_BUFFERS;
 
-	*size = fh->video_fmt.sizeimage;
+	*size = vv->video_fmt.sizeimage;
 
 	/* check if we exceed the "max_memory" parameter */
 	if( (*count * *size) > (max_memory*1048576) ) {
@@ -1283,7 +1189,7 @@
 	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
 
 	DEB_CAP("vbuf:%p\n", vb);
-	saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
+	saa7146_buffer_queue(fh->dev, &vv->video_dmaq, buf);
 }
 
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -1312,12 +1218,12 @@
 
 static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
 {
-	INIT_LIST_HEAD(&vv->video_q.queue);
+	INIT_LIST_HEAD(&vv->video_dmaq.queue);
 
-	init_timer(&vv->video_q.timeout);
-	vv->video_q.timeout.function = saa7146_buffer_timeout;
-	vv->video_q.timeout.data     = (unsigned long)(&vv->video_q);
-	vv->video_q.dev              = dev;
+	init_timer(&vv->video_dmaq.timeout);
+	vv->video_dmaq.timeout.function = saa7146_buffer_timeout;
+	vv->video_dmaq.timeout.data     = (unsigned long)(&vv->video_dmaq);
+	vv->video_dmaq.dev              = dev;
 
 	/* set some default values */
 	vv->standard = &dev->ext_vv_data->stds[0];
@@ -1331,15 +1237,6 @@
 static int video_open(struct saa7146_dev *dev, struct file *file)
 {
 	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_format *sfmt;
-
-	fh->video_fmt.width = 384;
-	fh->video_fmt.height = 288;
-	fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24;
-	fh->video_fmt.bytesperline = 0;
-	fh->video_fmt.field = V4L2_FIELD_ANY;
-	sfmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
-	fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
 
 	videobuf_queue_sg_init(&fh->video_q, &video_qops,
 			    &dev->pci->dev, &dev->slock,
@@ -1371,7 +1268,7 @@
 static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
 {
 	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_dmaqueue *q = &vv->video_q;
+	struct saa7146_dmaqueue *q = &vv->video_dmaq;
 
 	spin_lock(&dev->slock);
 	DEB_CAP("called\n");
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 4a6d5ce..bbf4945 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -204,6 +204,27 @@
 	help
 	  NXP TDA18218 silicon tuner driver.
 
+config MEDIA_TUNER_FC0011
+	tristate "Fitipower FC0011 silicon tuner"
+	depends on VIDEO_MEDIA && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Fitipower FC0011 silicon tuner driver.
+
+config MEDIA_TUNER_FC0012
+	tristate "Fitipower FC0012 silicon tuner"
+	depends on VIDEO_MEDIA && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Fitipower FC0012 silicon tuner driver.
+
+config MEDIA_TUNER_FC0013
+	tristate "Fitipower FC0013 silicon tuner"
+	depends on VIDEO_MEDIA && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Fitipower FC0013 silicon tuner driver.
+
 config MEDIA_TUNER_TDA18212
 	tristate "NXP TDA18212 silicon tuner"
 	depends on VIDEO_MEDIA && I2C
@@ -211,4 +232,10 @@
 	help
 	  NXP TDA18212 silicon tuner driver.
 
+config MEDIA_TUNER_TUA9001
+	tristate "Infineon TUA 9001 silicon tuner"
+	depends on VIDEO_MEDIA && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Infineon TUA 9001 silicon tuner driver.
 endmenu
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index f80407e..891b80e 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -28,6 +28,10 @@
 obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
+obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
+obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
+obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
+obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
 
 ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/fc0011.c b/drivers/media/common/tuners/fc0011.c
new file mode 100644
index 0000000..e488254
--- /dev/null
+++ b/drivers/media/common/tuners/fc0011.c
@@ -0,0 +1,524 @@
+/*
+ * Fitipower FC0011 tuner driver
+ *
+ * Copyright (C) 2012 Michael Buesch <m@bues.ch>
+ *
+ * Derived from FC0012 tuner driver:
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "fc0011.h"
+
+
+/* Tuner registers */
+enum {
+	FC11_REG_0,
+	FC11_REG_FA,		/* FA */
+	FC11_REG_FP,		/* FP */
+	FC11_REG_XINHI,		/* XIN high 8 bit */
+	FC11_REG_XINLO,		/* XIN low 8 bit */
+	FC11_REG_VCO,		/* VCO */
+	FC11_REG_VCOSEL,	/* VCO select */
+	FC11_REG_7,		/* Unknown tuner reg 7 */
+	FC11_REG_8,		/* Unknown tuner reg 8 */
+	FC11_REG_9,
+	FC11_REG_10,		/* Unknown tuner reg 10 */
+	FC11_REG_11,		/* Unknown tuner reg 11 */
+	FC11_REG_12,
+	FC11_REG_RCCAL,		/* RC calibrate */
+	FC11_REG_VCOCAL,	/* VCO calibrate */
+	FC11_REG_15,
+	FC11_REG_16,		/* Unknown tuner reg 16 */
+	FC11_REG_17,
+
+	FC11_NR_REGS,		/* Number of registers */
+};
+
+enum FC11_REG_VCOSEL_bits {
+	FC11_VCOSEL_2		= 0x08, /* VCO select 2 */
+	FC11_VCOSEL_1		= 0x10, /* VCO select 1 */
+	FC11_VCOSEL_CLKOUT	= 0x20, /* Fix clock out */
+	FC11_VCOSEL_BW7M	= 0x40, /* 7MHz bw */
+	FC11_VCOSEL_BW6M	= 0x80, /* 6MHz bw */
+};
+
+enum FC11_REG_RCCAL_bits {
+	FC11_RCCAL_FORCE	= 0x10, /* force */
+};
+
+enum FC11_REG_VCOCAL_bits {
+	FC11_VCOCAL_RUN		= 0,	/* VCO calibration run */
+	FC11_VCOCAL_VALUEMASK	= 0x3F,	/* VCO calibration value mask */
+	FC11_VCOCAL_OK		= 0x40,	/* VCO calibration Ok */
+	FC11_VCOCAL_RESET	= 0x80, /* VCO calibration reset */
+};
+
+
+struct fc0011_priv {
+	struct i2c_adapter *i2c;
+	u8 addr;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+
+static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = { .addr = priv->addr,
+		.flags = 0, .buf = buf, .len = 2 };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		dev_err(&priv->i2c->dev,
+			"I2C write reg failed, reg: %02x, val: %02x\n",
+			reg, val);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val)
+{
+	u8 dummy;
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->addr,
+		  .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = priv->addr,
+		  .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		dev_err(&priv->i2c->dev,
+			"I2C read failed, reg: %02x\n", reg);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int fc0011_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int fc0011_init(struct dvb_frontend *fe)
+{
+	struct fc0011_priv *priv = fe->tuner_priv;
+	int err;
+
+	if (WARN_ON(!fe->callback))
+		return -EINVAL;
+
+	err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+			   FC0011_FE_CALLBACK_POWER, priv->addr);
+	if (err) {
+		dev_err(&priv->i2c->dev, "Power-on callback failed\n");
+		return err;
+	}
+	err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+			   FC0011_FE_CALLBACK_RESET, priv->addr);
+	if (err) {
+		dev_err(&priv->i2c->dev, "Reset callback failed\n");
+		return err;
+	}
+
+	return 0;
+}
+
+/* Initiate VCO calibration */
+static int fc0011_vcocal_trigger(struct fc0011_priv *priv)
+{
+	int err;
+
+	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET);
+	if (err)
+		return err;
+	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/* Read VCO calibration value */
+static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value)
+{
+	int err;
+
+	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
+	if (err)
+		return err;
+	usleep_range(10000, 20000);
+	err = fc0011_readreg(priv, FC11_REG_VCOCAL, value);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int fc0011_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct fc0011_priv *priv = fe->tuner_priv;
+	int err;
+	unsigned int i, vco_retries;
+	u32 freq = p->frequency / 1000;
+	u32 bandwidth = p->bandwidth_hz / 1000;
+	u32 fvco, xin, xdiv, xdivr;
+	u16 frac;
+	u8 fa, fp, vco_sel, vco_cal;
+	u8 regs[FC11_NR_REGS] = { };
+
+	regs[FC11_REG_7] = 0x0F;
+	regs[FC11_REG_8] = 0x3E;
+	regs[FC11_REG_10] = 0xB8;
+	regs[FC11_REG_11] = 0x80;
+	regs[FC11_REG_RCCAL] = 0x04;
+	err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
+	err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
+	err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
+	err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
+	err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
+	if (err)
+		return -EIO;
+
+	/* Set VCO freq and VCO div */
+	if (freq < 54000) {
+		fvco = freq * 64;
+		regs[FC11_REG_VCO] = 0x82;
+	} else if (freq < 108000) {
+		fvco = freq * 32;
+		regs[FC11_REG_VCO] = 0x42;
+	} else if (freq < 216000) {
+		fvco = freq * 16;
+		regs[FC11_REG_VCO] = 0x22;
+	} else if (freq < 432000) {
+		fvco = freq * 8;
+		regs[FC11_REG_VCO] = 0x12;
+	} else {
+		fvco = freq * 4;
+		regs[FC11_REG_VCO] = 0x0A;
+	}
+
+	/* Calc XIN. The PLL reference frequency is 18 MHz. */
+	xdiv = fvco / 18000;
+	frac = fvco - xdiv * 18000;
+	frac = (frac << 15) / 18000;
+	if (frac >= 16384)
+		frac += 32786;
+	if (!frac)
+		xin = 0;
+	else if (frac < 511)
+		xin = 512;
+	else if (frac < 65026)
+		xin = frac;
+	else
+		xin = 65024;
+	regs[FC11_REG_XINHI] = xin >> 8;
+	regs[FC11_REG_XINLO] = xin;
+
+	/* Calc FP and FA */
+	xdivr = xdiv;
+	if (fvco - xdiv * 18000 >= 9000)
+		xdivr += 1; /* round */
+	fp = xdivr / 8;
+	fa = xdivr - fp * 8;
+	if (fa < 2) {
+		fp -= 1;
+		fa += 8;
+	}
+	if (fp > 0x1F) {
+		fp &= 0x1F;
+		fa &= 0xF;
+	}
+	if (fa >= fp) {
+		dev_warn(&priv->i2c->dev,
+			 "fa %02X >= fp %02X, but trying to continue\n",
+			 (unsigned int)(u8)fa, (unsigned int)(u8)fp);
+	}
+	regs[FC11_REG_FA] = fa;
+	regs[FC11_REG_FP] = fp;
+
+	/* Select bandwidth */
+	switch (bandwidth) {
+	case 8000:
+		break;
+	case 7000:
+		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M;
+		break;
+	default:
+		dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. "
+			 "Using 6000 kHz.\n",
+			 bandwidth);
+		bandwidth = 6000;
+		/* fallthrough */
+	case 6000:
+		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M;
+		break;
+	}
+
+	/* Pre VCO select */
+	if (fvco < 2320000) {
+		vco_sel = 0;
+		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+	} else if (fvco < 3080000) {
+		vco_sel = 1;
+		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+	} else {
+		vco_sel = 2;
+		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
+	}
+
+	/* Fix for low freqs */
+	if (freq < 45000) {
+		regs[FC11_REG_FA] = 0x6;
+		regs[FC11_REG_FP] = 0x11;
+	}
+
+	/* Clock out fix */
+	regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT;
+
+	/* Write the cached registers */
+	for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) {
+		err = fc0011_writereg(priv, i, regs[i]);
+		if (err)
+			return err;
+	}
+
+	/* VCO calibration */
+	err = fc0011_vcocal_trigger(priv);
+	if (err)
+		return err;
+	err = fc0011_vcocal_read(priv, &vco_cal);
+	if (err)
+		return err;
+	vco_retries = 0;
+	while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) {
+		/* Reset the tuner and try again */
+		err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+				   FC0011_FE_CALLBACK_RESET, priv->addr);
+		if (err) {
+			dev_err(&priv->i2c->dev, "Failed to reset tuner\n");
+			return err;
+		}
+		/* Reinit tuner config */
+		err = 0;
+		for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++)
+			err |= fc0011_writereg(priv, i, regs[i]);
+		err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
+		err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
+		err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
+		err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
+		err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
+		if (err)
+			return -EIO;
+		/* VCO calibration */
+		err = fc0011_vcocal_trigger(priv);
+		if (err)
+			return err;
+		err = fc0011_vcocal_read(priv, &vco_cal);
+		if (err)
+			return err;
+		vco_retries++;
+	}
+	if (!(vco_cal & FC11_VCOCAL_OK)) {
+		dev_err(&priv->i2c->dev,
+			"Failed to read VCO calibration value (got %02X)\n",
+			(unsigned int)vco_cal);
+		return -EIO;
+	}
+	vco_cal &= FC11_VCOCAL_VALUEMASK;
+
+	switch (vco_sel) {
+	case 0:
+		if (vco_cal < 8) {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+			err = fc0011_vcocal_trigger(priv);
+			if (err)
+				return err;
+		} else {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+		}
+		break;
+	case 1:
+		if (vco_cal < 5) {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+			err = fc0011_vcocal_trigger(priv);
+			if (err)
+				return err;
+		} else if (vco_cal <= 48) {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+		} else {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+			err = fc0011_vcocal_trigger(priv);
+			if (err)
+				return err;
+		}
+		break;
+	case 2:
+		if (vco_cal > 53) {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+			err = fc0011_vcocal_trigger(priv);
+			if (err)
+				return err;
+		} else {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+		}
+		break;
+	}
+	err = fc0011_vcocal_read(priv, NULL);
+	if (err)
+		return err;
+	usleep_range(10000, 50000);
+
+	err = fc0011_readreg(priv, FC11_REG_RCCAL, &regs[FC11_REG_RCCAL]);
+	if (err)
+		return err;
+	regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE;
+	err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
+	if (err)
+		return err;
+	err = fc0011_writereg(priv, FC11_REG_16, 0xB);
+	if (err)
+		return err;
+
+	dev_dbg(&priv->i2c->dev, "Tuned to "
+		"fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X "
+		"vcocal=%02X(%u) bw=%u\n",
+		(unsigned int)regs[FC11_REG_FA],
+		(unsigned int)regs[FC11_REG_FP],
+		(unsigned int)regs[FC11_REG_XINHI],
+		(unsigned int)regs[FC11_REG_XINLO],
+		(unsigned int)regs[FC11_REG_VCO],
+		(unsigned int)regs[FC11_REG_VCOSEL],
+		(unsigned int)vco_cal, vco_retries,
+		(unsigned int)bandwidth);
+
+	priv->frequency = p->frequency;
+	priv->bandwidth = p->bandwidth_hz;
+
+	return 0;
+}
+
+static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct fc0011_priv *priv = fe->tuner_priv;
+
+	*frequency = priv->frequency;
+
+	return 0;
+}
+
+static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	*frequency = 0;
+
+	return 0;
+}
+
+static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct fc0011_priv *priv = fe->tuner_priv;
+
+	*bandwidth = priv->bandwidth;
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops fc0011_tuner_ops = {
+	.info = {
+		.name		= "Fitipower FC0011",
+
+		.frequency_min	= 45000000,
+		.frequency_max	= 1000000000,
+	},
+
+	.release		= fc0011_release,
+	.init			= fc0011_init,
+
+	.set_params		= fc0011_set_params,
+
+	.get_frequency		= fc0011_get_frequency,
+	.get_if_frequency	= fc0011_get_if_frequency,
+	.get_bandwidth		= fc0011_get_bandwidth,
+};
+
+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   const struct fc0011_config *config)
+{
+	struct fc0011_priv *priv;
+
+	priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL);
+	if (!priv)
+		return NULL;
+
+	priv->i2c = i2c;
+	priv->addr = config->i2c_address;
+
+	fe->tuner_priv = priv;
+	fe->ops.tuner_ops = fc0011_tuner_ops;
+
+	dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n");
+
+	return fe;
+}
+EXPORT_SYMBOL(fc0011_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver");
+MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/fc0011.h b/drivers/media/common/tuners/fc0011.h
new file mode 100644
index 0000000..0ee581f
--- /dev/null
+++ b/drivers/media/common/tuners/fc0011.h
@@ -0,0 +1,41 @@
+#ifndef LINUX_FC0011_H_
+#define LINUX_FC0011_H_
+
+#include "dvb_frontend.h"
+
+
+/** struct fc0011_config - fc0011 hardware config
+ *
+ * @i2c_address: I2C bus address.
+ */
+struct fc0011_config {
+	u8 i2c_address;
+};
+
+/** enum fc0011_fe_callback_commands - Frontend callbacks
+ *
+ * @FC0011_FE_CALLBACK_POWER: Power on tuner hardware.
+ * @FC0011_FE_CALLBACK_RESET: Request a tuner reset.
+ */
+enum fc0011_fe_callback_commands {
+	FC0011_FE_CALLBACK_POWER,
+	FC0011_FE_CALLBACK_RESET,
+};
+
+#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\
+    defined(CONFIG_MEDIA_TUNER_FC0011_MODULE)
+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   const struct fc0011_config *config);
+#else
+static inline
+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   const struct fc0011_config *config)
+{
+	dev_err(&i2c->dev, "fc0011 driver disabled in Kconfig\n");
+	return NULL;
+}
+#endif
+
+#endif /* LINUX_FC0011_H_ */
diff --git a/drivers/media/common/tuners/fc0012-priv.h b/drivers/media/common/tuners/fc0012-priv.h
new file mode 100644
index 0000000..4577c91
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012-priv.h
@@ -0,0 +1,43 @@
+/*
+ * Fitipower FC0012 tuner driver - private includes
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_PRIV_H_
+#define _FC0012_PRIV_H_
+
+#define LOG_PREFIX "fc0012"
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct fc0012_priv {
+	struct i2c_adapter *i2c;
+	u8 addr;
+	u8 dual_master;
+	u8 xtal_freq;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/fc0012.c b/drivers/media/common/tuners/fc0012.c
new file mode 100644
index 0000000..308135a
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012.c
@@ -0,0 +1,467 @@
+/*
+ * Fitipower FC0012 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "fc0012.h"
+#include "fc0012-priv.h"
+
+static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = {
+		.addr = priv->addr, .flags = 0, .buf = buf, .len = 2
+	};
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		err("I2C read reg failed, reg: %02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0012_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int fc0012_init(struct dvb_frontend *fe)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	unsigned char reg[] = {
+		0x00,	/* dummy reg. 0 */
+		0x05,	/* reg. 0x01 */
+		0x10,	/* reg. 0x02 */
+		0x00,	/* reg. 0x03 */
+		0x00,	/* reg. 0x04 */
+		0x0f,	/* reg. 0x05: may also be 0x0a */
+		0x00,	/* reg. 0x06: divider 2, VCO slow */
+		0x00,	/* reg. 0x07: may also be 0x0f */
+		0xff,	/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
+			   Loop Bw 1/8 */
+		0x6e,	/* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
+		0xb8,	/* reg. 0x0a: Disable LO Test Buffer */
+		0x82,	/* reg. 0x0b: Output Clock is same as clock frequency,
+			   may also be 0x83 */
+		0xfc,	/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
+		0x02,	/* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
+		0x00,	/* reg. 0x0e */
+		0x00,	/* reg. 0x0f */
+		0x00,	/* reg. 0x10: may also be 0x0d */
+		0x00,	/* reg. 0x11 */
+		0x1f,	/* reg. 0x12: Set to maximum gain */
+		0x08,	/* reg. 0x13: Set to Middle Gain: 0x08,
+			   Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */
+		0x00,	/* reg. 0x14 */
+		0x04,	/* reg. 0x15: Enable LNA COMPS */
+	};
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+	case FC_XTAL_28_8_MHZ:
+		reg[0x07] |= 0x20;
+		break;
+	case FC_XTAL_36_MHZ:
+	default:
+		break;
+	}
+
+	if (priv->dual_master)
+		reg[0x0c] |= 0x02;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	for (i = 1; i < sizeof(reg); i++) {
+		ret = fc0012_writereg(priv, i, reg[i]);
+		if (ret)
+			break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (ret)
+		err("fc0012_writereg failed: %d", ret);
+
+	return ret;
+}
+
+static int fc0012_sleep(struct dvb_frontend *fe)
+{
+	/* nothing to do here */
+	return 0;
+}
+
+static int fc0012_set_params(struct dvb_frontend *fe)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 freq = p->frequency / 1000;
+	u32 delsys = p->delivery_system;
+	unsigned char reg[7], am, pm, multi, tmp;
+	unsigned long f_vco;
+	unsigned short xtal_freq_khz_2, xin, xdiv;
+	int vco_select = false;
+
+	if (fe->callback) {
+		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+			FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
+		if (ret)
+			goto exit;
+	}
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+		xtal_freq_khz_2 = 27000 / 2;
+		break;
+	case FC_XTAL_36_MHZ:
+		xtal_freq_khz_2 = 36000 / 2;
+		break;
+	case FC_XTAL_28_8_MHZ:
+	default:
+		xtal_freq_khz_2 = 28800 / 2;
+		break;
+	}
+
+	/* select frequency divider and the frequency of VCO */
+	if (freq < 37084) {		/* freq * 96 < 3560000 */
+		multi = 96;
+		reg[5] = 0x82;
+		reg[6] = 0x00;
+	} else if (freq < 55625) {	/* freq * 64 < 3560000 */
+		multi = 64;
+		reg[5] = 0x82;
+		reg[6] = 0x02;
+	} else if (freq < 74167) {	/* freq * 48 < 3560000 */
+		multi = 48;
+		reg[5] = 0x42;
+		reg[6] = 0x00;
+	} else if (freq < 111250) {	/* freq * 32 < 3560000 */
+		multi = 32;
+		reg[5] = 0x42;
+		reg[6] = 0x02;
+	} else if (freq < 148334) {	/* freq * 24 < 3560000 */
+		multi = 24;
+		reg[5] = 0x22;
+		reg[6] = 0x00;
+	} else if (freq < 222500) {	/* freq * 16 < 3560000 */
+		multi = 16;
+		reg[5] = 0x22;
+		reg[6] = 0x02;
+	} else if (freq < 296667) {	/* freq * 12 < 3560000 */
+		multi = 12;
+		reg[5] = 0x12;
+		reg[6] = 0x00;
+	} else if (freq < 445000) {	/* freq * 8 < 3560000 */
+		multi = 8;
+		reg[5] = 0x12;
+		reg[6] = 0x02;
+	} else if (freq < 593334) {	/* freq * 6 < 3560000 */
+		multi = 6;
+		reg[5] = 0x0a;
+		reg[6] = 0x00;
+	} else {
+		multi = 4;
+		reg[5] = 0x0a;
+		reg[6] = 0x02;
+	}
+
+	f_vco = freq * multi;
+
+	if (f_vco >= 3060000) {
+		reg[6] |= 0x08;
+		vco_select = true;
+	}
+
+	if (freq >= 45000) {
+		/* From divided value (XDIV) determined the FA and FP value */
+		xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
+		if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
+			xdiv++;
+
+		pm = (unsigned char)(xdiv / 8);
+		am = (unsigned char)(xdiv - (8 * pm));
+
+		if (am < 2) {
+			reg[1] = am + 8;
+			reg[2] = pm - 1;
+		} else {
+			reg[1] = am;
+			reg[2] = pm;
+		}
+	} else {
+		/* fix for frequency less than 45 MHz */
+		reg[1] = 0x06;
+		reg[2] = 0x11;
+	}
+
+	/* fix clock out */
+	reg[6] |= 0x20;
+
+	/* From VCO frequency determines the XIN ( fractional part of Delta
+	   Sigma PLL) and divided value (XDIV) */
+	xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
+	xin = (xin << 15) / xtal_freq_khz_2;
+	if (xin >= 16384)
+		xin += 32768;
+
+	reg[3] = xin >> 8;	/* xin with 9 bit resolution */
+	reg[4] = xin & 0xff;
+
+	if (delsys == SYS_DVBT) {
+		reg[6] &= 0x3f;	/* bits 6 and 7 describe the bandwidth */
+		switch (p->bandwidth_hz) {
+		case 6000000:
+			reg[6] |= 0x80;
+			break;
+		case 7000000:
+			reg[6] |= 0x40;
+			break;
+		case 8000000:
+		default:
+			break;
+		}
+	} else {
+		err("%s: modulation type not supported!", __func__);
+		return -EINVAL;
+	}
+
+	/* modified for Realtek demod */
+	reg[5] |= 0x07;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	for (i = 1; i <= 6; i++) {
+		ret = fc0012_writereg(priv, i, reg[i]);
+		if (ret)
+			goto exit;
+	}
+
+	/* VCO Calibration */
+	ret = fc0012_writereg(priv, 0x0e, 0x80);
+	if (!ret)
+		ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+	/* VCO Re-Calibration if needed */
+	if (!ret)
+		ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+	if (!ret) {
+		msleep(10);
+		ret = fc0012_readreg(priv, 0x0e, &tmp);
+	}
+	if (ret)
+		goto exit;
+
+	/* vco selection */
+	tmp &= 0x3f;
+
+	if (vco_select) {
+		if (tmp > 0x3c) {
+			reg[6] &= ~0x08;
+			ret = fc0012_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x00);
+		}
+	} else {
+		if (tmp < 0x02) {
+			reg[6] |= 0x08;
+			ret = fc0012_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x00);
+		}
+	}
+
+	priv->frequency = p->frequency;
+	priv->bandwidth = p->bandwidth_hz;
+
+exit:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	/* CHECK: always ? */
+	*frequency = 0;
+	return 0;
+}
+
+static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+#define INPUT_ADC_LEVEL	-8
+
+static int fc0012_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int ret;
+	unsigned char tmp;
+	int int_temp, lna_gain, int_lna, tot_agc_gain, power;
+	const int fc0012_lna_gain_table[] = {
+		/* low gain */
+		-63, -58, -99, -73,
+		-63, -65, -54, -60,
+		/* middle gain */
+		 71,  70,  68,  67,
+		 65,  63,  61,  58,
+		/* high gain */
+		197, 191, 188, 186,
+		184, 182, 181, 179,
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	ret = fc0012_writereg(priv, 0x12, 0x00);
+	if (ret)
+		goto err;
+
+	ret = fc0012_readreg(priv, 0x12, &tmp);
+	if (ret)
+		goto err;
+	int_temp = tmp;
+
+	ret = fc0012_readreg(priv, 0x13, &tmp);
+	if (ret)
+		goto err;
+	lna_gain = tmp & 0x1f;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (lna_gain < ARRAY_SIZE(fc0012_lna_gain_table)) {
+		int_lna = fc0012_lna_gain_table[lna_gain];
+		tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
+				(int_temp & 0x1f)) * 2;
+		power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
+
+		if (power >= 45)
+			*strength = 255;	/* 100% */
+		else if (power < -95)
+			*strength = 0;
+		else
+			*strength = (power + 95) * 255 / 140;
+
+		*strength |= *strength << 8;
+	} else {
+		ret = -1;
+	}
+
+	goto exit;
+
+err:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+exit:
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static const struct dvb_tuner_ops fc0012_tuner_ops = {
+	.info = {
+		.name           = "Fitipower FC0012",
+
+		.frequency_min  = 37000000,	/* estimate */
+		.frequency_max  = 862000000,	/* estimate */
+		.frequency_step = 0,
+	},
+
+	.release	= fc0012_release,
+
+	.init		= fc0012_init,
+	.sleep		= fc0012_sleep,
+
+	.set_params	= fc0012_set_params,
+
+	.get_frequency	= fc0012_get_frequency,
+	.get_if_frequency = fc0012_get_if_frequency,
+	.get_bandwidth	= fc0012_get_bandwidth,
+
+	.get_rf_strength = fc0012_get_rf_strength,
+};
+
+struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
+	enum fc001x_xtal_freq xtal_freq)
+{
+	struct fc0012_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c = i2c;
+	priv->dual_master = dual_master;
+	priv->addr = i2c_address;
+	priv->xtal_freq = xtal_freq;
+
+	info("Fitipower FC0012 successfully attached.");
+
+	fe->tuner_priv = priv;
+
+	memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	return fe;
+}
+EXPORT_SYMBOL(fc0012_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
+MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.6");
diff --git a/drivers/media/common/tuners/fc0012.h b/drivers/media/common/tuners/fc0012.h
new file mode 100644
index 0000000..4dbd5ef
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012.h
@@ -0,0 +1,44 @@
+/*
+ * Fitipower FC0012 tuner driver - include
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_H_
+#define _FC0012_H_
+
+#include "dvb_frontend.h"
+#include "fc001x-common.h"
+
+#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
+	(defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
+extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c,
+					u8 i2c_address, int dual_master,
+					enum fc001x_xtal_freq xtal_freq);
+#else
+static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c,
+					u8 i2c_address, int dual_master,
+					enum fc001x_xtal_freq xtal_freq)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/fc0013-priv.h b/drivers/media/common/tuners/fc0013-priv.h
new file mode 100644
index 0000000..bfd49de
--- /dev/null
+++ b/drivers/media/common/tuners/fc0013-priv.h
@@ -0,0 +1,44 @@
+/*
+ * Fitipower FC0013 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ *    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _FC0013_PRIV_H_
+#define _FC0013_PRIV_H_
+
+#define LOG_PREFIX "fc0013"
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct fc0013_priv {
+	struct i2c_adapter *i2c;
+	u8 addr;
+	u8 dual_master;
+	u8 xtal_freq;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/fc0013.c b/drivers/media/common/tuners/fc0013.c
new file mode 100644
index 0000000..bd8f0f1
--- /dev/null
+++ b/drivers/media/common/tuners/fc0013.c
@@ -0,0 +1,634 @@
+/*
+ * Fitipower FC0013 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ * partially based on driver code from Fitipower
+ * Copyright (C) 2010 Fitipower Integrated Technology Inc
+ *
+ *    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "fc0013.h"
+#include "fc0013-priv.h"
+
+static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = {
+		.addr = priv->addr, .flags = 0, .buf = buf, .len = 2
+	};
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		err("I2C read reg failed, reg: %02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0013_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int fc0013_init(struct dvb_frontend *fe)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	unsigned char reg[] = {
+		0x00,	/* reg. 0x00: dummy */
+		0x09,	/* reg. 0x01 */
+		0x16,	/* reg. 0x02 */
+		0x00,	/* reg. 0x03 */
+		0x00,	/* reg. 0x04 */
+		0x17,	/* reg. 0x05 */
+		0x02,	/* reg. 0x06 */
+		0x0a,	/* reg. 0x07: CHECK */
+		0xff,	/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
+			   Loop Bw 1/8 */
+		0x6f,	/* reg. 0x09: enable LoopThrough */
+		0xb8,	/* reg. 0x0a: Disable LO Test Buffer */
+		0x82,	/* reg. 0x0b: CHECK */
+		0xfc,	/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
+		0x01,	/* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */
+		0x00,	/* reg. 0x0e */
+		0x00,	/* reg. 0x0f */
+		0x00,	/* reg. 0x10 */
+		0x00,	/* reg. 0x11 */
+		0x00,	/* reg. 0x12 */
+		0x00,	/* reg. 0x13 */
+		0x50,	/* reg. 0x14: DVB-t High Gain, UHF.
+			   Middle Gain: 0x48, Low Gain: 0x40 */
+		0x01,	/* reg. 0x15 */
+	};
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+	case FC_XTAL_28_8_MHZ:
+		reg[0x07] |= 0x20;
+		break;
+	case FC_XTAL_36_MHZ:
+	default:
+		break;
+	}
+
+	if (priv->dual_master)
+		reg[0x0c] |= 0x02;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	for (i = 1; i < sizeof(reg); i++) {
+		ret = fc0013_writereg(priv, i, reg[i]);
+		if (ret)
+			break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (ret)
+		err("fc0013_writereg failed: %d", ret);
+
+	return ret;
+}
+
+static int fc0013_sleep(struct dvb_frontend *fe)
+{
+	/* nothing to do here */
+	return 0;
+}
+
+int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int ret;
+	u8 rc_cal;
+	int val;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	/* push rc_cal value, get rc_cal value */
+	ret = fc0013_writereg(priv, 0x10, 0x00);
+	if (ret)
+		goto error_out;
+
+	/* get rc_cal value */
+	ret = fc0013_readreg(priv, 0x10, &rc_cal);
+	if (ret)
+		goto error_out;
+
+	rc_cal &= 0x0f;
+
+	val = (int)rc_cal + rc_val;
+
+	/* forcing rc_cal */
+	ret = fc0013_writereg(priv, 0x0d, 0x11);
+	if (ret)
+		goto error_out;
+
+	/* modify rc_cal value */
+	if (val > 15)
+		ret = fc0013_writereg(priv, 0x10, 0x0f);
+	else if (val < 0)
+		ret = fc0013_writereg(priv, 0x10, 0x00);
+	else
+		ret = fc0013_writereg(priv, 0x10, (u8)val);
+
+error_out:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	return ret;
+}
+EXPORT_SYMBOL(fc0013_rc_cal_add);
+
+int fc0013_rc_cal_reset(struct dvb_frontend *fe)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	ret = fc0013_writereg(priv, 0x0d, 0x01);
+	if (!ret)
+		ret = fc0013_writereg(priv, 0x10, 0x00);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	return ret;
+}
+EXPORT_SYMBOL(fc0013_rc_cal_reset);
+
+static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq)
+{
+	int ret;
+	u8 tmp;
+
+	ret = fc0013_readreg(priv, 0x1d, &tmp);
+	if (ret)
+		goto error_out;
+	tmp &= 0xe3;
+	if (freq <= 177500) {		/* VHF Track: 7 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
+	} else if (freq <= 184500) {	/* VHF Track: 6 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x18);
+	} else if (freq <= 191500) {	/* VHF Track: 5 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x14);
+	} else if (freq <= 198500) {	/* VHF Track: 4 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x10);
+	} else if (freq <= 205500) {	/* VHF Track: 3 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c);
+	} else if (freq <= 219500) {	/* VHF Track: 2 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x08);
+	} else if (freq < 300000) {	/* VHF Track: 1 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x04);
+	} else {			/* UHF and GPS */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
+	}
+	if (ret)
+		goto error_out;
+error_out:
+	return ret;
+}
+
+static int fc0013_set_params(struct dvb_frontend *fe)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 freq = p->frequency / 1000;
+	u32 delsys = p->delivery_system;
+	unsigned char reg[7], am, pm, multi, tmp;
+	unsigned long f_vco;
+	unsigned short xtal_freq_khz_2, xin, xdiv;
+	int vco_select = false;
+
+	if (fe->callback) {
+		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+			FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
+		if (ret)
+			goto exit;
+	}
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+		xtal_freq_khz_2 = 27000 / 2;
+		break;
+	case FC_XTAL_36_MHZ:
+		xtal_freq_khz_2 = 36000 / 2;
+		break;
+	case FC_XTAL_28_8_MHZ:
+	default:
+		xtal_freq_khz_2 = 28800 / 2;
+		break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	/* set VHF track */
+	ret = fc0013_set_vhf_track(priv, freq);
+	if (ret)
+		goto exit;
+
+	if (freq < 300000) {
+		/* enable VHF filter */
+		ret = fc0013_readreg(priv, 0x07, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x07, tmp | 0x10);
+		if (ret)
+			goto exit;
+
+		/* disable UHF & disable GPS */
+		ret = fc0013_readreg(priv, 0x14, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x14, tmp & 0x1f);
+		if (ret)
+			goto exit;
+	} else if (freq <= 862000) {
+		/* disable VHF filter */
+		ret = fc0013_readreg(priv, 0x07, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
+		if (ret)
+			goto exit;
+
+		/* enable UHF & disable GPS */
+		ret = fc0013_readreg(priv, 0x14, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40);
+		if (ret)
+			goto exit;
+	} else {
+		/* disable VHF filter */
+		ret = fc0013_readreg(priv, 0x07, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
+		if (ret)
+			goto exit;
+
+		/* disable UHF & enable GPS */
+		ret = fc0013_readreg(priv, 0x14, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20);
+		if (ret)
+			goto exit;
+	}
+
+	/* select frequency divider and the frequency of VCO */
+	if (freq < 37084) {		/* freq * 96 < 3560000 */
+		multi = 96;
+		reg[5] = 0x82;
+		reg[6] = 0x00;
+	} else if (freq < 55625) {	/* freq * 64 < 3560000 */
+		multi = 64;
+		reg[5] = 0x02;
+		reg[6] = 0x02;
+	} else if (freq < 74167) {	/* freq * 48 < 3560000 */
+		multi = 48;
+		reg[5] = 0x42;
+		reg[6] = 0x00;
+	} else if (freq < 111250) {	/* freq * 32 < 3560000 */
+		multi = 32;
+		reg[5] = 0x82;
+		reg[6] = 0x02;
+	} else if (freq < 148334) {	/* freq * 24 < 3560000 */
+		multi = 24;
+		reg[5] = 0x22;
+		reg[6] = 0x00;
+	} else if (freq < 222500) {	/* freq * 16 < 3560000 */
+		multi = 16;
+		reg[5] = 0x42;
+		reg[6] = 0x02;
+	} else if (freq < 296667) {	/* freq * 12 < 3560000 */
+		multi = 12;
+		reg[5] = 0x12;
+		reg[6] = 0x00;
+	} else if (freq < 445000) {	/* freq * 8 < 3560000 */
+		multi = 8;
+		reg[5] = 0x22;
+		reg[6] = 0x02;
+	} else if (freq < 593334) {	/* freq * 6 < 3560000 */
+		multi = 6;
+		reg[5] = 0x0a;
+		reg[6] = 0x00;
+	} else if (freq < 950000) {	/* freq * 4 < 3800000 */
+		multi = 4;
+		reg[5] = 0x12;
+		reg[6] = 0x02;
+	} else {
+		multi = 2;
+		reg[5] = 0x0a;
+		reg[6] = 0x02;
+	}
+
+	f_vco = freq * multi;
+
+	if (f_vco >= 3060000) {
+		reg[6] |= 0x08;
+		vco_select = true;
+	}
+
+	if (freq >= 45000) {
+		/* From divided value (XDIV) determined the FA and FP value */
+		xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
+		if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
+			xdiv++;
+
+		pm = (unsigned char)(xdiv / 8);
+		am = (unsigned char)(xdiv - (8 * pm));
+
+		if (am < 2) {
+			reg[1] = am + 8;
+			reg[2] = pm - 1;
+		} else {
+			reg[1] = am;
+			reg[2] = pm;
+		}
+	} else {
+		/* fix for frequency less than 45 MHz */
+		reg[1] = 0x06;
+		reg[2] = 0x11;
+	}
+
+	/* fix clock out */
+	reg[6] |= 0x20;
+
+	/* From VCO frequency determines the XIN ( fractional part of Delta
+	   Sigma PLL) and divided value (XDIV) */
+	xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
+	xin = (xin << 15) / xtal_freq_khz_2;
+	if (xin >= 16384)
+		xin += 32768;
+
+	reg[3] = xin >> 8;
+	reg[4] = xin & 0xff;
+
+	if (delsys == SYS_DVBT) {
+		reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
+		switch (p->bandwidth_hz) {
+		case 6000000:
+			reg[6] |= 0x80;
+			break;
+		case 7000000:
+			reg[6] |= 0x40;
+			break;
+		case 8000000:
+		default:
+			break;
+		}
+	} else {
+		err("%s: modulation type not supported!", __func__);
+		return -EINVAL;
+	}
+
+	/* modified for Realtek demod */
+	reg[5] |= 0x07;
+
+	for (i = 1; i <= 6; i++) {
+		ret = fc0013_writereg(priv, i, reg[i]);
+		if (ret)
+			goto exit;
+	}
+
+	ret = fc0013_readreg(priv, 0x11, &tmp);
+	if (ret)
+		goto exit;
+	if (multi == 64)
+		ret = fc0013_writereg(priv, 0x11, tmp | 0x04);
+	else
+		ret = fc0013_writereg(priv, 0x11, tmp & 0xfb);
+	if (ret)
+		goto exit;
+
+	/* VCO Calibration */
+	ret = fc0013_writereg(priv, 0x0e, 0x80);
+	if (!ret)
+		ret = fc0013_writereg(priv, 0x0e, 0x00);
+
+	/* VCO Re-Calibration if needed */
+	if (!ret)
+		ret = fc0013_writereg(priv, 0x0e, 0x00);
+
+	if (!ret) {
+		msleep(10);
+		ret = fc0013_readreg(priv, 0x0e, &tmp);
+	}
+	if (ret)
+		goto exit;
+
+	/* vco selection */
+	tmp &= 0x3f;
+
+	if (vco_select) {
+		if (tmp > 0x3c) {
+			reg[6] &= ~0x08;
+			ret = fc0013_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0013_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0013_writereg(priv, 0x0e, 0x00);
+		}
+	} else {
+		if (tmp < 0x02) {
+			reg[6] |= 0x08;
+			ret = fc0013_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0013_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0013_writereg(priv, 0x0e, 0x00);
+		}
+	}
+
+	priv->frequency = p->frequency;
+	priv->bandwidth = p->bandwidth_hz;
+
+exit:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	/* always ? */
+	*frequency = 0;
+	return 0;
+}
+
+static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+#define INPUT_ADC_LEVEL	-8
+
+static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int ret;
+	unsigned char tmp;
+	int int_temp, lna_gain, int_lna, tot_agc_gain, power;
+	const int fc0013_lna_gain_table[] = {
+		/* low gain */
+		-63, -58, -99, -73,
+		-63, -65, -54, -60,
+		/* middle gain */
+		 71,  70,  68,  67,
+		 65,  63,  61,  58,
+		/* high gain */
+		197, 191, 188, 186,
+		184, 182, 181, 179,
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	ret = fc0013_writereg(priv, 0x13, 0x00);
+	if (ret)
+		goto err;
+
+	ret = fc0013_readreg(priv, 0x13, &tmp);
+	if (ret)
+		goto err;
+	int_temp = tmp;
+
+	ret = fc0013_readreg(priv, 0x14, &tmp);
+	if (ret)
+		goto err;
+	lna_gain = tmp & 0x1f;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) {
+		int_lna = fc0013_lna_gain_table[lna_gain];
+		tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
+				(int_temp & 0x1f)) * 2;
+		power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
+
+		if (power >= 45)
+			*strength = 255;	/* 100% */
+		else if (power < -95)
+			*strength = 0;
+		else
+			*strength = (power + 95) * 255 / 140;
+
+		*strength |= *strength << 8;
+	} else {
+		ret = -1;
+	}
+
+	goto exit;
+
+err:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+exit:
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static const struct dvb_tuner_ops fc0013_tuner_ops = {
+	.info = {
+		.name		= "Fitipower FC0013",
+
+		.frequency_min	= 37000000,	/* estimate */
+		.frequency_max	= 1680000000,	/* CHECK */
+		.frequency_step	= 0,
+	},
+
+	.release	= fc0013_release,
+
+	.init		= fc0013_init,
+	.sleep		= fc0013_sleep,
+
+	.set_params	= fc0013_set_params,
+
+	.get_frequency	= fc0013_get_frequency,
+	.get_if_frequency = fc0013_get_if_frequency,
+	.get_bandwidth	= fc0013_get_bandwidth,
+
+	.get_rf_strength = fc0013_get_rf_strength,
+};
+
+struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
+	enum fc001x_xtal_freq xtal_freq)
+{
+	struct fc0013_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c = i2c;
+	priv->dual_master = dual_master;
+	priv->addr = i2c_address;
+	priv->xtal_freq = xtal_freq;
+
+	info("Fitipower FC0013 successfully attached.");
+
+	fe->tuner_priv = priv;
+
+	memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	return fe;
+}
+EXPORT_SYMBOL(fc0013_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver");
+MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2");
diff --git a/drivers/media/common/tuners/fc0013.h b/drivers/media/common/tuners/fc0013.h
new file mode 100644
index 0000000..594efd6
--- /dev/null
+++ b/drivers/media/common/tuners/fc0013.h
@@ -0,0 +1,57 @@
+/*
+ * Fitipower FC0013 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ *    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _FC0013_H_
+#define _FC0013_H_
+
+#include "dvb_frontend.h"
+#include "fc001x-common.h"
+
+#if defined(CONFIG_MEDIA_TUNER_FC0013) || \
+	(defined(CONFIG_MEDIA_TUNER_FC0013_MODULE) && defined(MODULE))
+extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c,
+					u8 i2c_address, int dual_master,
+					enum fc001x_xtal_freq xtal_freq);
+extern int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val);
+extern int fc0013_rc_cal_reset(struct dvb_frontend *fe);
+#else
+static inline struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c,
+					u8 i2c_address, int dual_master,
+					enum fc001x_xtal_freq xtal_freq)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
+{
+	return 0;
+}
+
+static inline int fc0013_rc_cal_reset(struct dvb_frontend *fe)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/fc001x-common.h b/drivers/media/common/tuners/fc001x-common.h
new file mode 100644
index 0000000..7188181
--- /dev/null
+++ b/drivers/media/common/tuners/fc001x-common.h
@@ -0,0 +1,39 @@
+/*
+ * Fitipower FC0012 & FC0013 tuner driver - common defines
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC001X_COMMON_H_
+#define _FC001X_COMMON_H_
+
+enum fc001x_xtal_freq {
+	FC_XTAL_27_MHZ,		/* 27000000 */
+	FC_XTAL_28_8_MHZ,	/* 28800000 */
+	FC_XTAL_36_MHZ,		/* 36000000 */
+};
+
+/*
+ * enum fc001x_fe_callback_commands - Frontend callbacks
+ *
+ * @FC_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF
+ */
+enum fc001x_fe_callback_commands {
+	FC_FE_CALLBACK_VHF_ENABLE,
+};
+
+#endif
diff --git a/drivers/media/common/tuners/tua9001.c b/drivers/media/common/tuners/tua9001.c
new file mode 100644
index 0000000..de26070
--- /dev/null
+++ b/drivers/media/common/tuners/tua9001.c
@@ -0,0 +1,215 @@
+/*
+ * Infineon TUA 9001 silicon tuner driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "tua9001.h"
+#include "tua9001_priv.h"
+
+/* write register */
+static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val)
+{
+	int ret;
+	u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff };
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg->i2c_addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		printk(KERN_WARNING "%s: I2C wr failed=%d reg=%02x\n",
+				__func__, ret, reg);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+static int tua9001_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int tua9001_init(struct dvb_frontend *fe)
+{
+	struct tua9001_priv *priv = fe->tuner_priv;
+	int ret = 0;
+	u8 i;
+	struct reg_val data[] = {
+		{ 0x1e, 0x6512 },
+		{ 0x25, 0xb888 },
+		{ 0x39, 0x5460 },
+		{ 0x3b, 0x00c0 },
+		{ 0x3a, 0xf000 },
+		{ 0x08, 0x0000 },
+		{ 0x32, 0x0030 },
+		{ 0x41, 0x703a },
+		{ 0x40, 0x1c78 },
+		{ 0x2c, 0x1c00 },
+		{ 0x36, 0xc013 },
+		{ 0x37, 0x6f18 },
+		{ 0x27, 0x0008 },
+		{ 0x2a, 0x0001 },
+		{ 0x34, 0x0a40 },
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
+
+	for (i = 0; i < ARRAY_SIZE(data); i++) {
+		ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
+		if (ret)
+			break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
+
+	if (ret < 0)
+		pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int tua9001_set_params(struct dvb_frontend *fe)
+{
+	struct tua9001_priv *priv = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	u16 val;
+	u32 frequency;
+	struct reg_val data[2];
+
+	pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+			__func__, c->delivery_system, c->frequency,
+			c->bandwidth_hz);
+
+	switch (c->delivery_system) {
+	case SYS_DVBT:
+		switch (c->bandwidth_hz) {
+		case 8000000:
+			val  = 0x0000;
+			break;
+		case 7000000:
+			val  = 0x1000;
+			break;
+		case 6000000:
+			val  = 0x2000;
+			break;
+		case 5000000:
+			val  = 0x3000;
+			break;
+		default:
+			ret = -EINVAL;
+			goto err;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
+	}
+
+	data[0].reg = 0x04;
+	data[0].val = val;
+
+	frequency = (c->frequency - 150000000);
+	frequency /= 100;
+	frequency *= 48;
+	frequency /= 10000;
+
+	data[1].reg = 0x1f;
+	data[1].val = frequency;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
+
+	for (i = 0; i < ARRAY_SIZE(data); i++) {
+		ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
+		if (ret < 0)
+			break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
+
+err:
+	if (ret < 0)
+		pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	*frequency = 0; /* Zero-IF */
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops tua9001_tuner_ops = {
+	.info = {
+		.name           = "Infineon TUA 9001",
+
+		.frequency_min  = 170000000,
+		.frequency_max  = 862000000,
+		.frequency_step = 0,
+	},
+
+	.release = tua9001_release,
+
+	.init = tua9001_init,
+	.set_params = tua9001_set_params,
+
+	.get_if_frequency = tua9001_get_if_frequency,
+};
+
+struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
+		struct i2c_adapter *i2c, struct tua9001_config *cfg)
+{
+	struct tua9001_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->i2c = i2c;
+
+	printk(KERN_INFO "Infineon TUA 9001 successfully attached.");
+
+	memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops,
+			sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+	return fe;
+}
+EXPORT_SYMBOL(tua9001_attach);
+
+MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tua9001.h b/drivers/media/common/tuners/tua9001.h
new file mode 100644
index 0000000..38d6ae7
--- /dev/null
+++ b/drivers/media/common/tuners/tua9001.h
@@ -0,0 +1,46 @@
+/*
+ * Infineon TUA 9001 silicon tuner driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TUA9001_H
+#define TUA9001_H
+
+#include "dvb_frontend.h"
+
+struct tua9001_config {
+	/*
+	 * I2C address
+	 */
+	u8 i2c_addr;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \
+	(defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
+		struct i2c_adapter *i2c, struct tua9001_config *cfg);
+#else
+static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
+		struct i2c_adapter *i2c, struct tua9001_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/tua9001_priv.h b/drivers/media/common/tuners/tua9001_priv.h
new file mode 100644
index 0000000..73cc1ce
--- /dev/null
+++ b/drivers/media/common/tuners/tua9001_priv.h
@@ -0,0 +1,34 @@
+/*
+ * Infineon TUA 9001 silicon tuner driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TUA9001_PRIV_H
+#define TUA9001_PRIV_H
+
+struct reg_val {
+	u8 reg;
+	u16 val;
+};
+
+struct tua9001_priv {
+	struct tua9001_config *cfg;
+	struct i2c_adapter *i2c;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index eab2ea4..dcca42c 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -54,7 +54,7 @@
 	struct list_head hybrid_tuner_instance_list;
 
 	u32 if_khz;
-	u32 xtal_khz;
+	u16 xtal_khz;
 	u32 freq_hz;
 	u32 bandwidth;
 	u8  video_standard;
@@ -631,7 +631,10 @@
 		ret = xc_load_i2c_sequence(fe,  fw->data);
 		if (XC_RESULT_SUCCESS == ret)
 			ret = xc_set_xtal(fe);
-		printk(KERN_INFO "xc5000: firmware upload complete...\n");
+		if (XC_RESULT_SUCCESS == ret)
+			printk(KERN_INFO "xc5000: firmware upload complete...\n");
+		else
+			printk(KERN_ERR "xc5000: firmware upload failed...\n");
 	}
 
 out:
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index 39a73bf..b1a5474 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -34,7 +34,7 @@
 	u8   i2c_address;
 	u32  if_khz;
 	u8   radio_input;
-	u32  xtal_khz;
+	u16  xtal_khz;
 
 	int chip_id;
 };
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 48e48e8..66f52f1 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -477,7 +477,6 @@
 static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
 {
 	int i = 0;
-	unsigned int ca_message_header_len;
 
 	u32 command = 0;
 	struct ca_msg *hw_buffer;
@@ -496,7 +495,6 @@
 
 
 	if (p_ca_message->msg) {
-		ca_message_header_len = p_ca_message->length;	/*	Restore it back when you are done	*/
 		/*	EN50221 tag	*/
 		command = 0;
 
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c
index d88c4aa..131b938 100644
--- a/drivers/media/dvb/ddbridge/ddbridge-core.c
+++ b/drivers/media/dvb/ddbridge/ddbridge-core.c
@@ -31,7 +31,6 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/timer.h>
-#include <linux/version.h>
 #include <linux/i2c.h>
 #include <linux/swab.h>
 #include <linux/vmalloc.h>
@@ -1696,7 +1695,7 @@
 	.name        = "DDBridge",
 	.id_table    = ddb_id_tbl,
 	.probe       = ddb_probe,
-	.remove      = ddb_remove,
+	.remove      = __devexit_p(ddb_remove),
 };
 
 static __init int module_init_ddbridge(void)
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index faa3671..d82469f 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -568,6 +568,16 @@
 }
 EXPORT_SYMBOL(dvb_dmx_swfilter_204);
 
+void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+	spin_lock(&demux->lock);
+
+	demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
+
+	spin_unlock(&demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
+
 static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
 {
 	int i;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index a7d876f..fa7188a 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -145,5 +145,7 @@
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
 			  size_t count);
+void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
+			  size_t count);
 
 #endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index cb888d8..aebcdf2 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -182,13 +182,13 @@
 	case SYS_DMBTH:
 		return DVBV3_OFDM;
 	case SYS_ATSC:
+	case SYS_ATSCMH:
 	case SYS_DVBC_ANNEX_B:
 		return DVBV3_ATSC;
 	case SYS_UNDEFINED:
 	case SYS_ISDBC:
 	case SYS_DVBH:
 	case SYS_DAB:
-	case SYS_ATSCMH:
 	default:
 		/*
 		 * Doesn't know how to emulate those types and/or
@@ -1030,6 +1030,25 @@
 	_DTV_CMD(DTV_HIERARCHY, 0, 0),
 
 	_DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
+
+	_DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
+
+	_DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
 };
 
 static void dtv_property_dump(struct dtv_property *tvp)
@@ -1121,6 +1140,8 @@
 	case DVBV3_ATSC:
 		dprintk("%s() Preparing ATSC req\n", __func__);
 		c->modulation = p->u.vsb.modulation;
+		if (c->delivery_system == SYS_ATSCMH)
+			break;
 		if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
 			c->delivery_system = SYS_ATSC;
 		else
@@ -1367,6 +1388,54 @@
 	case DTV_DVBT2_PLP_ID:
 		tvp->u.data = c->dvbt2_plp_id;
 		break;
+
+	/* ATSC-MH */
+	case DTV_ATSCMH_FIC_VER:
+		tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver;
+		break;
+	case DTV_ATSCMH_PARADE_ID:
+		tvp->u.data = fe->dtv_property_cache.atscmh_parade_id;
+		break;
+	case DTV_ATSCMH_NOG:
+		tvp->u.data = fe->dtv_property_cache.atscmh_nog;
+		break;
+	case DTV_ATSCMH_TNOG:
+		tvp->u.data = fe->dtv_property_cache.atscmh_tnog;
+		break;
+	case DTV_ATSCMH_SGN:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sgn;
+		break;
+	case DTV_ATSCMH_PRC:
+		tvp->u.data = fe->dtv_property_cache.atscmh_prc;
+		break;
+	case DTV_ATSCMH_RS_FRAME_MODE:
+		tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_mode;
+		break;
+	case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+		tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_ensemble;
+		break;
+	case DTV_ATSCMH_RS_CODE_MODE_PRI:
+		tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_pri;
+		break;
+	case DTV_ATSCMH_RS_CODE_MODE_SEC:
+		tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_sec;
+		break;
+	case DTV_ATSCMH_SCCC_BLOCK_MODE:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_block_mode;
+		break;
+	case DTV_ATSCMH_SCCC_CODE_MODE_A:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_a;
+		break;
+	case DTV_ATSCMH_SCCC_CODE_MODE_B:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_b;
+		break;
+	case DTV_ATSCMH_SCCC_CODE_MODE_C:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_c;
+		break;
+	case DTV_ATSCMH_SCCC_CODE_MODE_D:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d;
+		break;
+
 	default:
 		return -EINVAL;
 	}
@@ -1708,6 +1777,15 @@
 	case DTV_DVBT2_PLP_ID:
 		c->dvbt2_plp_id = tvp->u.data;
 		break;
+
+	/* ATSC-MH */
+	case DTV_ATSCMH_PARADE_ID:
+		fe->dtv_property_cache.atscmh_parade_id = tvp->u.data;
+		break;
+	case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+		fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data;
+		break;
+
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index d63a821..e929d56 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -372,6 +372,24 @@
 
 	/* DVB-T2 specifics */
 	u32                     dvbt2_plp_id;
+
+	/* ATSC-MH specifics */
+	u8			atscmh_fic_ver;
+	u8			atscmh_parade_id;
+	u8			atscmh_nog;
+	u8			atscmh_tnog;
+	u8			atscmh_sgn;
+	u8			atscmh_prc;
+
+	u8			atscmh_rs_frame_mode;
+	u8			atscmh_rs_frame_ensemble;
+	u8			atscmh_rs_code_mode_pri;
+	u8			atscmh_rs_code_mode_sec;
+	u8			atscmh_sccc_block_mode;
+	u8			atscmh_sccc_code_mode_a;
+	u8			atscmh_sccc_code_mode_b;
+	u8			atscmh_sccc_code_mode_c;
+	u8			atscmh_sccc_code_mode_d;
 };
 
 struct dvb_frontend {
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 63bf456..a269493 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -409,6 +409,7 @@
 	tristate "MxL111SF DTV USB2.0 support"
 	depends on DVB_USB
 	select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+	select DVB_LG2160 if !DVB_FE_CUSTOMISE
 	select VIDEO_TVEEPROM
 	help
 	  Say Y here to support the MxL111SF USB2.0 DTV receiver.
@@ -422,3 +423,15 @@
 	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
 	help
 	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.
+
+config DVB_USB_AF9035
+	tristate "Afatech AF9035 DVB-T USB2.0 support"
+	depends on DVB_USB
+	select DVB_AF9033
+	select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Afatech AF9035 based DVB USB receiver.
+
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index b76acb5..b667ac3 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -110,6 +110,9 @@
 dvb-usb-rtl28xxu-objs = rtl28xxu.o
 obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
 
+dvb-usb-af9035-objs = af9035.o
+obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o
+
 ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
 # due to tuner-xc3028
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 7e70ea5..677fed7 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -244,8 +244,7 @@
 	u8 uninitialized_var(mbox), addr_len;
 	struct req_t req;
 
-/* TODO: implement bus lock
-
+/*
 The bus lock is needed because there is two tuners both using same I2C-address.
 Due to that the only way to select correct tuner is use demodulator I2C-gate.
 
@@ -789,7 +788,7 @@
 	/* try to load remote based USB ID */
 	if (!props->rc.core.rc_codes)
 		props->rc.core.rc_codes = af9015_rc_setup_match(
-			(vid << 16) + pid, af9015_rc_setup_usbids);
+			(vid << 16) | pid, af9015_rc_setup_usbids);
 
 	/* try to load remote based USB iManufacturer string */
 	if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) {
@@ -1220,8 +1219,8 @@
 	}
 
 	/* attach demodulator */
-	adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
-		&adap->dev->i2c_adap);
+	adap->fe_adap[0].fe = dvb_attach(af9013_attach,
+		&af9015_af9013_config[adap->id], &adap->dev->i2c_adap);
 
 	/*
 	 * AF9015 firmware does not like if it gets interrupted by I2C adapter
@@ -1324,14 +1323,15 @@
 	switch (af9015_af9013_config[adap->id].tuner) {
 	case AF9013_TUNER_MT2060:
 	case AF9013_TUNER_MT2060_2:
-		ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
-			&af9015_mt2060_config,
+		ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe,
+			&adap->dev->i2c_adap, &af9015_mt2060_config,
 			af9015_config.mt2060_if1[adap->id])
 			== NULL ? -ENODEV : 0;
 		break;
 	case AF9013_TUNER_QT1010:
 	case AF9013_TUNER_QT1010A:
-		ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
+		ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe,
+			&adap->dev->i2c_adap,
 			&af9015_qt1010_config) == NULL ? -ENODEV : 0;
 		break;
 	case AF9013_TUNER_TDA18271:
@@ -1434,69 +1434,85 @@
 };
 
 static struct usb_device_id af9015_usb_table[] = {
-	[AFATECH_9015] =
-		{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)},
-	[AFATECH_9016] =
-		{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)},
-	[WINFAST_DTV_GOLD] =
-		{USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)},
-	[PINNACLE_PCTV_71E] =
-		{USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)},
-	[KWORLD_PLUSTV_399U] =
-		{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)},
-	[TINYTWIN] = {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)},
-	[AZUREWAVE_TU700] =
-		{USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)},
-	[TERRATEC_AF9015] = {USB_DEVICE(USB_VID_TERRATEC,
+	[AFATECH_9015] = {
+		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)},
+	[AFATECH_9016] = {
+		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)},
+	[WINFAST_DTV_GOLD] = {
+		USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)},
+	[PINNACLE_PCTV_71E] = {
+		USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)},
+	[KWORLD_PLUSTV_399U] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)},
+	[TINYTWIN] = {
+		USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)},
+	[AZUREWAVE_TU700] = {
+		USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)},
+	[TERRATEC_AF9015] = {
+		USB_DEVICE(USB_VID_TERRATEC,
 				USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
-	[KWORLD_PLUSTV_PC160] =
-		{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)},
-	[AVERTV_VOLAR_X] =
-		{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
-	[XTENSIONS_380U] =
-		{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
-	[MSI_DIGIVOX_DUO] =
-		{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)},
-	[AVERTV_VOLAR_X_REV2] =
-		{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
-	[TELESTAR_STARSTICK_2] =
-		{USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2)},
-	[AVERMEDIA_A309_USB] =
-		{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
-	[MSI_DIGIVOX_MINI_III] =
-		{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
-	[KWORLD_E396] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
-	[KWORLD_E39B] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
-	[KWORLD_E395] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)},
-	[TREKSTOR_DVBT] = {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)},
-	[AVERTV_A850] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
-	[AVERTV_A805] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
-	[CONCEPTRONIC_CTVDIGRCU] =
-		{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
-	[KWORLD_MC810] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
-	[GENIUS_TVGO_DVB_T03] =
-		{USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
-	[KWORLD_399U_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
-	[KWORLD_PC160_T] =
-		{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
-	[SVEON_STV20] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
-	[TINYTWIN_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
-	[WINFAST_DTV2000DS] =
-		{USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
-	[KWORLD_UB383_T] =
-		{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
-	[KWORLD_E39A] =
-		{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
-	[AVERMEDIA_A815M] =
-		{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
-	[CINERGY_T_STICK_RC] = {USB_DEVICE(USB_VID_TERRATEC,
+	[KWORLD_PLUSTV_PC160] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)},
+	[AVERTV_VOLAR_X] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
+	[XTENSIONS_380U] = {
+		USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
+	[MSI_DIGIVOX_DUO] = {
+		USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)},
+	[AVERTV_VOLAR_X_REV2] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
+	[TELESTAR_STARSTICK_2] = {
+		USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2)},
+	[AVERMEDIA_A309_USB] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
+	[MSI_DIGIVOX_MINI_III] = {
+		USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
+	[KWORLD_E396] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
+	[KWORLD_E39B] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
+	[KWORLD_E395] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)},
+	[TREKSTOR_DVBT] = {
+		USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)},
+	[AVERTV_A850] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
+	[AVERTV_A805] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
+	[CONCEPTRONIC_CTVDIGRCU] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
+	[KWORLD_MC810] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
+	[GENIUS_TVGO_DVB_T03] = {
+		USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
+	[KWORLD_399U_2] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
+	[KWORLD_PC160_T] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
+	[SVEON_STV20] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
+	[TINYTWIN_2] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
+	[WINFAST_DTV2000DS] = {
+		USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
+	[KWORLD_UB383_T] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
+	[KWORLD_E39A] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
+	[AVERMEDIA_A815M] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
+	[CINERGY_T_STICK_RC] = {
+		USB_DEVICE(USB_VID_TERRATEC,
 				USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
-	[CINERGY_T_DUAL_RC] = {USB_DEVICE(USB_VID_TERRATEC,
+	[CINERGY_T_DUAL_RC] = {
+		USB_DEVICE(USB_VID_TERRATEC,
 				USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
-	[AVERTV_A850T] =
-		{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
-	[TINYTWIN_3] = {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
-	[SVEON_STV22] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)},
+	[AVERTV_A850T] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
+	[TINYTWIN_3] = {
+		USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
+	[SVEON_STV22] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)},
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1516,43 +1532,44 @@
 		.num_adapters = 2,
 		.adapter = {
 			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.num_frontends = 1,
+				.fe = {
+					{
+						.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+							DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
-				.pid_filter_count = 32,
-				.pid_filter       = af9015_pid_filter,
-				.pid_filter_ctrl  = af9015_pid_filter_ctrl,
+						.pid_filter_count = 32,
+						.pid_filter       = af9015_pid_filter,
+						.pid_filter_ctrl  = af9015_pid_filter_ctrl,
 
-				.frontend_attach =
-					af9015_af9013_frontend_attach,
-				.tuner_attach    = af9015_tuner_attach,
-				.stream = {
-					.type = USB_BULK,
-					.count = 6,
-					.endpoint = 0x84,
-				},
-			}},
-			},
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.frontend_attach =
-					af9015_af9013_frontend_attach,
-				.tuner_attach    = af9015_tuner_attach,
-				.stream = {
-					.type = USB_BULK,
-					.count = 6,
-					.endpoint = 0x85,
-					.u = {
-						.bulk = {
-							.buffersize =
-						TS_USB20_FRAME_SIZE,
-						}
+						.frontend_attach = af9015_af9013_frontend_attach,
+						.tuner_attach    = af9015_tuner_attach,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x84,
+						},
 					}
 				},
-			}},
+			},
+			{
+				.num_frontends = 1,
+				.fe = {
+					{
+						.frontend_attach = af9015_af9013_frontend_attach,
+						.tuner_attach    = af9015_tuner_attach,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x85,
+							.u = {
+								.bulk = {
+									.buffersize = TS_USB20_FRAME_SIZE,
+								}
+							}
+						},
+					}
+				},
 			}
 		},
 
@@ -1575,102 +1592,67 @@
 				.cold_ids = {
 					&af9015_usb_table[AFATECH_9015],
 					&af9015_usb_table[AFATECH_9016],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "Leadtek WinFast DTV Dongle Gold",
 				.cold_ids = {
 					&af9015_usb_table[WINFAST_DTV_GOLD],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "Pinnacle PCTV 71e",
 				.cold_ids = {
 					&af9015_usb_table[PINNACLE_PCTV_71E],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "KWorld PlusTV Dual DVB-T Stick " \
 					"(DVB-T 399U)",
 				.cold_ids = {
 					&af9015_usb_table[KWORLD_PLUSTV_399U],
 					&af9015_usb_table[KWORLD_399U_2],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "DigitalNow TinyTwin DVB-T Receiver",
 				.cold_ids = {
 					&af9015_usb_table[TINYTWIN],
 					&af9015_usb_table[TINYTWIN_2],
 					&af9015_usb_table[TINYTWIN_3],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "TwinHan AzureWave AD-TU700(704J)",
 				.cold_ids = {
 					&af9015_usb_table[AZUREWAVE_TU700],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "TerraTec Cinergy T USB XE",
 				.cold_ids = {
 					&af9015_usb_table[TERRATEC_AF9015],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "KWorld PlusTV Dual DVB-T PCI " \
 					"(DVB-T PC160-2T)",
 				.cold_ids = {
 					&af9015_usb_table[KWORLD_PLUSTV_PC160],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "AVerMedia AVerTV DVB-T Volar X",
 				.cold_ids = {
 					&af9015_usb_table[AVERTV_VOLAR_X],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "TerraTec Cinergy T Stick RC",
 				.cold_ids = {
 					&af9015_usb_table[CINERGY_T_STICK_RC],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "TerraTec Cinergy T Stick Dual RC",
 				.cold_ids = {
 					&af9015_usb_table[CINERGY_T_DUAL_RC],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "AverMedia AVerTV Red HD+ (A850T)",
 				.cold_ids = {
 					&af9015_usb_table[AVERTV_A850T],
-					NULL
 				},
-				.warm_ids = {NULL},
 			},
 		}
 	}, {
@@ -1686,43 +1668,44 @@
 		.num_adapters = 2,
 		.adapter = {
 			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.num_frontends = 1,
+				.fe = {
+					{
+						.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+							DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
-				.pid_filter_count = 32,
-				.pid_filter       = af9015_pid_filter,
-				.pid_filter_ctrl  = af9015_pid_filter_ctrl,
+						.pid_filter_count = 32,
+						.pid_filter       = af9015_pid_filter,
+						.pid_filter_ctrl  = af9015_pid_filter_ctrl,
 
-				.frontend_attach =
-					af9015_af9013_frontend_attach,
-				.tuner_attach    = af9015_tuner_attach,
-				.stream = {
-					.type = USB_BULK,
-					.count = 6,
-					.endpoint = 0x84,
-				},
-			}},
-			},
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.frontend_attach =
-					af9015_af9013_frontend_attach,
-				.tuner_attach    = af9015_tuner_attach,
-				.stream = {
-					.type = USB_BULK,
-					.count = 6,
-					.endpoint = 0x85,
-					.u = {
-						.bulk = {
-							.buffersize =
-						TS_USB20_FRAME_SIZE,
-						}
+						.frontend_attach = af9015_af9013_frontend_attach,
+						.tuner_attach    = af9015_tuner_attach,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x84,
+						},
 					}
 				},
-			}},
+			},
+			{
+				.num_frontends = 1,
+				.fe = {
+					{
+						.frontend_attach = af9015_af9013_frontend_attach,
+						.tuner_attach    = af9015_tuner_attach,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x85,
+							.u = {
+								.bulk = {
+									.buffersize = TS_USB20_FRAME_SIZE,
+								}
+							}
+						},
+					}
+				},
 			}
 		},
 
@@ -1744,51 +1727,33 @@
 				.name = "Xtensions XD-380",
 				.cold_ids = {
 					&af9015_usb_table[XTENSIONS_380U],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "MSI DIGIVOX Duo",
 				.cold_ids = {
 					&af9015_usb_table[MSI_DIGIVOX_DUO],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "Fujitsu-Siemens Slim Mobile USB DVB-T",
 				.cold_ids = {
 					&af9015_usb_table[AVERTV_VOLAR_X_REV2],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "Telestar Starstick 2",
 				.cold_ids = {
 					&af9015_usb_table[TELESTAR_STARSTICK_2],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "AVerMedia A309",
 				.cold_ids = {
 					&af9015_usb_table[AVERMEDIA_A309_USB],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "MSI Digi VOX mini III",
 				.cold_ids = {
 					&af9015_usb_table[MSI_DIGIVOX_MINI_III],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "KWorld USB DVB-T TV Stick II " \
 					"(VS-DVB-T 395U)",
 				.cold_ids = {
@@ -1796,34 +1761,23 @@
 					&af9015_usb_table[KWORLD_E39B],
 					&af9015_usb_table[KWORLD_E395],
 					&af9015_usb_table[KWORLD_E39A],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "TrekStor DVB-T USB Stick",
 				.cold_ids = {
 					&af9015_usb_table[TREKSTOR_DVBT],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "AverMedia AVerTV Volar Black HD " \
 					"(A850)",
 				.cold_ids = {
 					&af9015_usb_table[AVERTV_A850],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "Sveon STV22 Dual USB DVB-T Tuner HDTV",
 				.cold_ids = {
 					&af9015_usb_table[SVEON_STV22],
-					NULL
 				},
-				.warm_ids = {NULL},
 			},
 		}
 	}, {
@@ -1839,43 +1793,44 @@
 		.num_adapters = 2,
 		.adapter = {
 			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.num_frontends = 1,
+				.fe = {
+					{
+						.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+							DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
-				.pid_filter_count = 32,
-				.pid_filter       = af9015_pid_filter,
-				.pid_filter_ctrl  = af9015_pid_filter_ctrl,
+						.pid_filter_count = 32,
+						.pid_filter       = af9015_pid_filter,
+						.pid_filter_ctrl  = af9015_pid_filter_ctrl,
 
-				.frontend_attach =
-					af9015_af9013_frontend_attach,
-				.tuner_attach    = af9015_tuner_attach,
-				.stream = {
-					.type = USB_BULK,
-					.count = 6,
-					.endpoint = 0x84,
-				},
-			}},
-			},
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.frontend_attach =
-					af9015_af9013_frontend_attach,
-				.tuner_attach    = af9015_tuner_attach,
-				.stream = {
-					.type = USB_BULK,
-					.count = 6,
-					.endpoint = 0x85,
-					.u = {
-						.bulk = {
-							.buffersize =
-						TS_USB20_FRAME_SIZE,
-						}
+						.frontend_attach = af9015_af9013_frontend_attach,
+						.tuner_attach    = af9015_tuner_attach,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x84,
+						},
 					}
 				},
-			}},
+			},
+			{
+				.num_frontends = 1,
+				.fe = {
+					{
+						.frontend_attach = af9015_af9013_frontend_attach,
+						.tuner_attach    = af9015_tuner_attach,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x85,
+							.u = {
+								.bulk = {
+									.buffersize = TS_USB20_FRAME_SIZE,
+								}
+							}
+						},
+					}
+				},
 			}
 		},
 
@@ -1897,76 +1852,50 @@
 				.name = "AverMedia AVerTV Volar GPS 805 (A805)",
 				.cold_ids = {
 					&af9015_usb_table[AVERTV_A805],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
 					"V3.0",
 				.cold_ids = {
 					&af9015_usb_table[CONCEPTRONIC_CTVDIGRCU],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "KWorld Digial MC-810",
 				.cold_ids = {
 					&af9015_usb_table[KWORLD_MC810],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "Genius TVGo DVB-T03",
 				.cold_ids = {
 					&af9015_usb_table[GENIUS_TVGO_DVB_T03],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "KWorld PlusTV DVB-T PCI Pro Card " \
 					"(DVB-T PC160-T)",
 				.cold_ids = {
 					&af9015_usb_table[KWORLD_PC160_T],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "Sveon STV20 Tuner USB DVB-T HDTV",
 				.cold_ids = {
 					&af9015_usb_table[SVEON_STV20],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "Leadtek WinFast DTV2000DS",
 				.cold_ids = {
 					&af9015_usb_table[WINFAST_DTV2000DS],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "KWorld USB DVB-T Stick Mobile " \
 					"(UB383-T)",
 				.cold_ids = {
 					&af9015_usb_table[KWORLD_UB383_T],
-					NULL
 				},
-				.warm_ids = {NULL},
-			},
-			{
+			}, {
 				.name = "AverMedia AVerTV Volar M (A815Mac)",
 				.cold_ids = {
 					&af9015_usb_table[AVERMEDIA_A815M],
-					NULL
 				},
-				.warm_ids = {NULL},
 			},
 		}
 	},
@@ -2019,5 +1948,5 @@
 module_usb_driver(af9015_usb_driver);
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T");
+MODULE_DESCRIPTION("Afatech AF9015 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c
new file mode 100644
index 0000000..e83b39d
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9035.c
@@ -0,0 +1,1242 @@
+/*
+ * Afatech AF9035 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "af9035.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+static DEFINE_MUTEX(af9035_usb_mutex);
+static struct dvb_usb_device_properties af9035_properties[2];
+static int af9035_properties_count = ARRAY_SIZE(af9035_properties);
+
+static u16 af9035_checksum(const u8 *buf, size_t len)
+{
+	size_t i;
+	u16 checksum = 0;
+
+	for (i = 1; i < len; i++) {
+		if (i % 2)
+			checksum += buf[i] << 8;
+		else
+			checksum += buf[i];
+	}
+	checksum = ~checksum;
+
+	return checksum;
+}
+
+static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req)
+{
+#define BUF_LEN 64
+#define REQ_HDR_LEN 4 /* send header size */
+#define ACK_HDR_LEN 3 /* rece header size */
+#define CHECKSUM_LEN 2
+#define USB_TIMEOUT 2000
+
+	int ret, msg_len, act_len;
+	u8 buf[BUF_LEN];
+	static u8 seq; /* packet sequence number */
+	u16 checksum, tmp_checksum;
+
+	/* buffer overflow check */
+	if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
+		req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
+		pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__,
+				req->wlen, req->rlen);
+		return -EINVAL;
+	}
+
+	if (mutex_lock_interruptible(&af9035_usb_mutex) < 0)
+		return -EAGAIN;
+
+	buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
+	buf[1] = req->mbox;
+	buf[2] = req->cmd;
+	buf[3] = seq++;
+	if (req->wlen)
+		memcpy(&buf[4], req->wbuf, req->wlen);
+
+	/* calc and add checksum */
+	checksum = af9035_checksum(buf, buf[0] - 1);
+	buf[buf[0] - 1] = (checksum >> 8);
+	buf[buf[0] - 0] = (checksum & 0xff);
+
+	msg_len = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN ;
+
+	/* send req */
+	ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
+			&act_len, USB_TIMEOUT);
+	if (ret < 0)
+		err("bulk message failed=%d (%d/%d)", ret, msg_len, act_len);
+	else
+		if (act_len != msg_len)
+			ret = -EIO; /* all data is not send */
+	if (ret < 0)
+		goto err_mutex_unlock;
+
+	/* no ack for those packets */
+	if (req->cmd == CMD_FW_DL)
+		goto exit_mutex_unlock;
+
+	/* receive ack and data if read req */
+	msg_len = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
+	ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
+			&act_len, USB_TIMEOUT);
+	if (ret < 0) {
+		err("recv bulk message failed=%d", ret);
+		ret = -EIO;
+		goto err_mutex_unlock;
+	}
+
+	if (act_len != msg_len) {
+		err("recv bulk message truncated (%d != %d)", act_len, msg_len);
+		ret = -EIO;
+		goto err_mutex_unlock;
+	}
+
+	/* verify checksum */
+	checksum = af9035_checksum(buf, act_len - 2);
+	tmp_checksum = (buf[act_len - 2] << 8) | buf[act_len - 1];
+	if (tmp_checksum != checksum) {
+		err("%s: command=%02x checksum mismatch (%04x != %04x)",
+		    __func__, req->cmd, tmp_checksum, checksum);
+		ret = -EIO;
+		goto err_mutex_unlock;
+	}
+
+	/* check status */
+	if (buf[2]) {
+		pr_debug("%s: command=%02x failed fw error=%d\n", __func__,
+				req->cmd, buf[2]);
+		ret = -EIO;
+		goto err_mutex_unlock;
+	}
+
+	/* read request, copy returned data to return buf */
+	if (req->rlen)
+		memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
+
+err_mutex_unlock:
+exit_mutex_unlock:
+	mutex_unlock(&af9035_usb_mutex);
+
+	return ret;
+}
+
+/* write multiple registers */
+static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
+{
+	u8 wbuf[6 + len];
+	u8 mbox = (reg >> 16) & 0xff;
+	struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL };
+
+	wbuf[0] = len;
+	wbuf[1] = 2;
+	wbuf[2] = 0;
+	wbuf[3] = 0;
+	wbuf[4] = (reg >> 8) & 0xff;
+	wbuf[5] = (reg >> 0) & 0xff;
+	memcpy(&wbuf[6], val, len);
+
+	return af9035_ctrl_msg(d->udev, &req);
+}
+
+/* read multiple registers */
+static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
+{
+	u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff };
+	u8 mbox = (reg >> 16) & 0xff;
+	struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val };
+
+	return af9035_ctrl_msg(d->udev, &req);
+}
+
+/* write single register */
+static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val)
+{
+	return af9035_wr_regs(d, reg, &val, 1);
+}
+
+/* read single register */
+static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val)
+{
+	return af9035_rd_regs(d, reg, val, 1);
+}
+
+/* write single register with mask */
+static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
+		u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = af9035_rd_regs(d, reg, &tmp, 1);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return af9035_wr_regs(d, reg, &val, 1);
+}
+
+static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
+		struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct state *state = d->priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	/*
+	 * I2C sub header is 5 bytes long. Meaning of those bytes are:
+	 * 0: data len
+	 * 1: I2C addr << 1
+	 * 2: reg addr len
+	 *    byte 3 and 4 can be used as reg addr
+	 * 3: reg addr MSB
+	 *    used when reg addr len is set to 2
+	 * 4: reg addr LSB
+	 *    used when reg addr len is set to 1 or 2
+	 *
+	 * For the simplify we do not use register addr at all.
+	 * NOTE: As a firmware knows tuner type there is very small possibility
+	 * there could be some tuner I2C hacks done by firmware and this may
+	 * lead problems if firmware expects those bytes are used.
+	 */
+	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
+			(msg[1].flags & I2C_M_RD)) {
+		if (msg[0].len > 40 || msg[1].len > 40) {
+			/* TODO: correct limits > 40 */
+			ret = -EOPNOTSUPP;
+		} else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
+			/* integrated demod */
+			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+					msg[0].buf[2];
+			ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
+					msg[1].len);
+		} else {
+			/* I2C */
+			u8 buf[5 + msg[0].len];
+			struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
+					buf, msg[1].len, msg[1].buf };
+			buf[0] = msg[1].len;
+			buf[1] = msg[0].addr << 1;
+			buf[2] = 0x00; /* reg addr len */
+			buf[3] = 0x00; /* reg addr MSB */
+			buf[4] = 0x00; /* reg addr LSB */
+			memcpy(&buf[5], msg[0].buf, msg[0].len);
+			ret = af9035_ctrl_msg(d->udev, &req);
+		}
+	} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+		if (msg[0].len > 40) {
+			/* TODO: correct limits > 40 */
+			ret = -EOPNOTSUPP;
+		} else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
+			/* integrated demod */
+			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+					msg[0].buf[2];
+			ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
+					msg[0].len - 3);
+		} else {
+			/* I2C */
+			u8 buf[5 + msg[0].len];
+			struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf,
+					0, NULL };
+			buf[0] = msg[0].len;
+			buf[1] = msg[0].addr << 1;
+			buf[2] = 0x00; /* reg addr len */
+			buf[3] = 0x00; /* reg addr MSB */
+			buf[4] = 0x00; /* reg addr LSB */
+			memcpy(&buf[5], msg[0].buf, msg[0].len);
+			ret = af9035_ctrl_msg(d->udev, &req);
+		}
+	} else {
+		/*
+		 * We support only two kind of I2C transactions:
+		 * 1) 1 x read + 1 x write
+		 * 2) 1 x write
+		 */
+		ret = -EOPNOTSUPP;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+
+	if (ret < 0)
+		return ret;
+	else
+		return num;
+}
+
+static u32 af9035_i2c_functionality(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9035_i2c_algo = {
+	.master_xfer = af9035_i2c_master_xfer,
+	.functionality = af9035_i2c_functionality,
+};
+
+#define AF9035_POLL 250
+static int af9035_rc_query(struct dvb_usb_device *d)
+{
+	unsigned int key;
+	unsigned char b[4];
+	int ret;
+	struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
+
+	ret = af9035_ctrl_msg(d->udev, &req);
+	if (ret < 0)
+		goto err;
+
+	if ((b[2] + b[3]) == 0xff) {
+		if ((b[0] + b[1]) == 0xff) {
+			/* NEC */
+			key = b[0] << 8 | b[2];
+		} else {
+			/* ext. NEC */
+			key = b[0] << 16 | b[1] << 8 | b[2];
+		}
+	} else {
+		key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
+	}
+
+	rc_keydown(d->rc_dev, key, 0);
+
+err:
+	/* ignore errors */
+	return 0;
+}
+
+static int af9035_init(struct dvb_usb_device *d)
+{
+	struct state *state = d->priv;
+	int ret, i;
+	u16 frame_size = 87 * 188 / 4;
+	u8  packet_size = 512 / 4;
+	struct reg_val_mask tab[] = {
+		{ 0x80f99d, 0x01, 0x01 },
+		{ 0x80f9a4, 0x01, 0x01 },
+		{ 0x00dd11, 0x00, 0x20 },
+		{ 0x00dd11, 0x00, 0x40 },
+		{ 0x00dd13, 0x00, 0x20 },
+		{ 0x00dd13, 0x00, 0x40 },
+		{ 0x00dd11, 0x20, 0x20 },
+		{ 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
+		{ 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
+		{ 0x00dd0c, packet_size, 0xff},
+		{ 0x00dd11, state->dual_mode << 6, 0x40 },
+		{ 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
+		{ 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
+		{ 0x00dd0d, packet_size, 0xff },
+		{ 0x80f9a3, 0x00, 0x01 },
+		{ 0x80f9cd, 0x00, 0x01 },
+		{ 0x80f99d, 0x00, 0x01 },
+		{ 0x80f9a4, 0x00, 0x01 },
+	};
+
+	pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+		__func__, d->udev->speed, frame_size, packet_size);
+
+	/* init endpoints */
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val,
+				tab[i].mask);
+		if (ret < 0)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_identify_state(struct usb_device *udev,
+		struct dvb_usb_device_properties *props,
+		struct dvb_usb_device_description **desc,
+		int *cold)
+{
+	int ret;
+	u8 wbuf[1] = { 1 };
+	u8 rbuf[4];
+	struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
+			sizeof(rbuf), rbuf };
+
+	ret = af9035_ctrl_msg(udev, &req);
+	if (ret < 0)
+		goto err;
+
+	pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__,
+		rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
+	if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])
+		*cold = 0;
+	else
+		*cold = 1;
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_download_firmware(struct usb_device *udev,
+		const struct firmware *fw)
+{
+	int ret, i, j, len;
+	u8 wbuf[1];
+	u8 rbuf[4];
+	struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+	struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
+	struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+	u8 hdr_core;
+	u16 hdr_addr, hdr_data_len, hdr_checksum;
+	#define MAX_DATA 58
+	#define HDR_SIZE 7
+
+	/*
+	 * Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
+	 *
+	 * byte 0: MCS 51 core
+	 *  There are two inside the AF9035 (1=Link and 2=OFDM) with separate
+	 *  address spaces
+	 * byte 1-2: Big endian destination address
+	 * byte 3-4: Big endian number of data bytes following the header
+	 * byte 5-6: Big endian header checksum, apparently ignored by the chip
+	 *  Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256)
+	 */
+
+	for (i = fw->size; i > HDR_SIZE;) {
+		hdr_core = fw->data[fw->size - i + 0];
+		hdr_addr = fw->data[fw->size - i + 1] << 8;
+		hdr_addr |= fw->data[fw->size - i + 2] << 0;
+		hdr_data_len = fw->data[fw->size - i + 3] << 8;
+		hdr_data_len |= fw->data[fw->size - i + 4] << 0;
+		hdr_checksum = fw->data[fw->size - i + 5] << 8;
+		hdr_checksum |= fw->data[fw->size - i + 6] << 0;
+
+		pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n",
+				__func__, hdr_core, hdr_addr, hdr_data_len,
+				hdr_checksum);
+
+		if (((hdr_core != 1) && (hdr_core != 2)) ||
+				(hdr_data_len > i)) {
+			pr_debug("%s: bad firmware\n", __func__);
+			break;
+		}
+
+		/* download begin packet */
+		req.cmd = CMD_FW_DL_BEGIN;
+		ret = af9035_ctrl_msg(udev, &req);
+		if (ret < 0)
+			goto err;
+
+		/* download firmware packet(s) */
+		for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) {
+			len = j;
+			if (len > MAX_DATA)
+				len = MAX_DATA;
+			req_fw_dl.wlen = len;
+			req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i +
+					HDR_SIZE + hdr_data_len - j];
+			ret = af9035_ctrl_msg(udev, &req_fw_dl);
+			if (ret < 0)
+				goto err;
+		}
+
+		/* download end packet */
+		req.cmd = CMD_FW_DL_END;
+		ret = af9035_ctrl_msg(udev, &req);
+		if (ret < 0)
+			goto err;
+
+		i -= hdr_data_len + HDR_SIZE;
+
+		pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i);
+	}
+
+	/* firmware loaded, request boot */
+	req.cmd = CMD_FW_BOOT;
+	ret = af9035_ctrl_msg(udev, &req);
+	if (ret < 0)
+		goto err;
+
+	/* ensure firmware starts */
+	wbuf[0] = 1;
+	ret = af9035_ctrl_msg(udev, &req_fw_ver);
+	if (ret < 0)
+		goto err;
+
+	if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
+		info("firmware did not run");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
+			rbuf[3]);
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_download_firmware_it9135(struct usb_device *udev,
+		const struct firmware *fw)
+{
+	int ret, i, i_prev;
+	u8 wbuf[1];
+	u8 rbuf[4];
+	struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+	struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL };
+	struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+	#define HDR_SIZE 7
+
+	/*
+	 * There seems to be following firmware header. Meaning of bytes 0-3
+	 * is unknown.
+	 *
+	 * 0: 3
+	 * 1: 0, 1
+	 * 2: 0
+	 * 3: 1, 2, 3
+	 * 4: addr MSB
+	 * 5: addr LSB
+	 * 6: count of data bytes ?
+	 */
+
+	for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) {
+		if (i == fw->size ||
+				(fw->data[i + 0] == 0x03 &&
+				(fw->data[i + 1] == 0x00 ||
+				fw->data[i + 1] == 0x01) &&
+				fw->data[i + 2] == 0x00)) {
+			req_fw_dl.wlen = i - i_prev;
+			req_fw_dl.wbuf = (u8 *) &fw->data[i_prev];
+			i_prev = i;
+			ret = af9035_ctrl_msg(udev, &req_fw_dl);
+			if (ret < 0)
+				goto err;
+
+			pr_debug("%s: data uploaded=%d\n", __func__, i);
+		}
+	}
+
+	/* firmware loaded, request boot */
+	req.cmd = CMD_FW_BOOT;
+	ret = af9035_ctrl_msg(udev, &req);
+	if (ret < 0)
+		goto err;
+
+	/* ensure firmware starts */
+	wbuf[0] = 1;
+	ret = af9035_ctrl_msg(udev, &req_fw_ver);
+	if (ret < 0)
+		goto err;
+
+	if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
+		info("firmware did not run");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
+			rbuf[3]);
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+/* abuse that callback as there is no better one for reading eeprom */
+static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	struct state *state = d->priv;
+	int ret, i, eeprom_shift = 0;
+	u8 tmp;
+	u16 tmp16;
+
+	/* check if there is dual tuners */
+	ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
+	if (ret < 0)
+		goto err;
+
+	state->dual_mode = tmp;
+	pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode);
+
+	for (i = 0; i < af9035_properties[0].num_adapters; i++) {
+		/* tuner */
+		ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
+		if (ret < 0)
+			goto err;
+
+		state->af9033_config[i].tuner = tmp;
+		pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp);
+
+		switch (tmp) {
+		case AF9033_TUNER_TUA9001:
+		case AF9033_TUNER_FC0011:
+		case AF9033_TUNER_MXL5007T:
+		case AF9033_TUNER_TDA18218:
+			state->af9033_config[i].spec_inv = 1;
+			break;
+		default:
+			warn("tuner ID=%02x not supported, please report!",
+				tmp);
+		};
+
+		/* tuner IF frequency */
+		ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
+		if (ret < 0)
+			goto err;
+
+		tmp16 = tmp;
+
+		ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp);
+		if (ret < 0)
+			goto err;
+
+		tmp16 |= tmp << 8;
+
+		pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16);
+
+		eeprom_shift = 0x10; /* shift for the 2nd tuner params */
+	}
+
+	/* get demod clock */
+	ret = af9035_rd_reg(d, 0x00d800, &tmp);
+	if (ret < 0)
+		goto err;
+
+	tmp = (tmp >> 0) & 0x0f;
+
+	for (i = 0; i < af9035_properties[0].num_adapters; i++)
+		state->af9033_config[i].clock = clock_lut[tmp];
+
+	ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
+	if (ret < 0)
+		goto err;
+	pr_debug("%s: ir_mode=%02x\n", __func__, tmp);
+
+	/* don't activate rc if in HID mode or if not available */
+	if (tmp == 5) {
+		ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
+		if (ret < 0)
+			goto err;
+		pr_debug("%s: ir_type=%02x\n", __func__, tmp);
+
+		switch (tmp) {
+		case 0: /* NEC */
+		default:
+			d->props.rc.core.protocol = RC_TYPE_NEC;
+			d->props.rc.core.allowed_protos = RC_TYPE_NEC;
+			break;
+		case 1: /* RC6 */
+			d->props.rc.core.protocol = RC_TYPE_RC6;
+			d->props.rc.core.allowed_protos = RC_TYPE_RC6;
+			break;
+		}
+		d->props.rc.core.rc_query = af9035_rc_query;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+/* abuse that callback as there is no better one for reading eeprom */
+static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6])
+{
+	struct state *state = d->priv;
+	int ret, i;
+	u8 tmp;
+
+	state->dual_mode = false;
+
+	/* get demod clock */
+	ret = af9035_rd_reg(d, 0x00d800, &tmp);
+	if (ret < 0)
+		goto err;
+
+	tmp = (tmp >> 0) & 0x0f;
+
+	for (i = 0; i < af9035_properties[0].num_adapters; i++)
+		state->af9033_config[i].clock = clock_lut_it9135[tmp];
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d,
+		int cmd, int arg)
+{
+	int ret;
+
+	switch (cmd) {
+	case FC0011_FE_CALLBACK_POWER:
+		/* Tuner enable */
+		ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		/* LED */
+		ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(10000, 50000);
+		break;
+	case FC0011_FE_CALLBACK_RESET:
+		ret = af9035_wr_reg(d, 0xd8e9, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg(d, 0xd8e8, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg(d, 0xd8e7, 1);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(10000, 20000);
+
+		ret = af9035_wr_reg(d, 0xd8e7, 0);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(10000, 20000);
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
+{
+	struct state *state = d->priv;
+
+	switch (state->af9033_config[0].tuner) {
+	case AF9033_TUNER_FC0011:
+		return af9035_fc0011_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -ENODEV;
+}
+
+static int af9035_frontend_callback(void *adapter_priv, int component,
+				    int cmd, int arg)
+{
+	struct i2c_adapter *adap = adapter_priv;
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+	switch (component) {
+	case DVB_FRONTEND_COMPONENT_TUNER:
+		return af9035_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap->dev->priv;
+	int ret;
+
+	if (!state->af9033_config[adap->id].tuner) {
+		/* unsupported tuner */
+		ret = -ENODEV;
+		goto err;
+	}
+
+	if (adap->id == 0) {
+		state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
+		state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
+
+		ret = af9035_wr_reg(adap->dev, 0x00417f,
+				state->af9033_config[1].i2c_addr);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg(adap->dev, 0x00d81a,
+				state->dual_mode);
+		if (ret < 0)
+			goto err;
+	}
+
+	/* attach demodulator */
+	adap->fe_adap[0].fe = dvb_attach(af9033_attach,
+			&state->af9033_config[adap->id], &adap->dev->i2c_adap);
+	if (adap->fe_adap[0].fe == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/* disable I2C-gate */
+	adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
+	adap->fe_adap[0].fe->callback = af9035_frontend_callback;
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static struct tua9001_config af9035_tua9001_config = {
+	.i2c_addr = 0x60,
+};
+
+static const struct fc0011_config af9035_fc0011_config = {
+	.i2c_address = 0x60,
+};
+
+static struct mxl5007t_config af9035_mxl5007t_config = {
+	.xtal_freq_hz = MxL_XTAL_24_MHZ,
+	.if_freq_hz = MxL_IF_4_57_MHZ,
+	.invert_if = 0,
+	.loop_thru_enable = 0,
+	.clk_out_enable = 0,
+	.clk_out_amp = MxL_CLKOUT_AMP_0_94V,
+};
+
+static struct tda18218_config af9035_tda18218_config = {
+	.i2c_address = 0x60,
+	.i2c_wr_max = 21,
+};
+
+static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap->dev->priv;
+	int ret;
+	struct dvb_frontend *fe;
+
+	switch (state->af9033_config[adap->id].tuner) {
+	case AF9033_TUNER_TUA9001:
+		/* AF9035 gpiot3 = TUA9001 RESETN
+		   AF9035 gpiot2 = TUA9001 RXEN */
+
+		/* configure gpiot2 and gpiot2 as output */
+		ret = af9035_wr_reg_mask(adap->dev, 0x00d8ec, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(adap->dev, 0x00d8ed, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(adap->dev, 0x00d8e8, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(adap->dev, 0x00d8e9, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		/* reset tuner */
+		ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(2000, 20000);
+
+		ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		/* activate tuner RX */
+		/* TODO: use callback for TUA9001 RXEN */
+		ret = af9035_wr_reg_mask(adap->dev, 0x00d8eb, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		/* attach tuner */
+		fe = dvb_attach(tua9001_attach, adap->fe_adap[0].fe,
+				&adap->dev->i2c_adap, &af9035_tua9001_config);
+		break;
+	case AF9033_TUNER_FC0011:
+		fe = dvb_attach(fc0011_attach, adap->fe_adap[0].fe,
+				&adap->dev->i2c_adap, &af9035_fc0011_config);
+		break;
+	case AF9033_TUNER_MXL5007T:
+		ret = af9035_wr_reg(adap->dev, 0x00d8e0, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(adap->dev, 0x00d8e1, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(adap->dev, 0x00d8df, 0);
+		if (ret < 0)
+			goto err;
+
+		msleep(30);
+
+		ret = af9035_wr_reg(adap->dev, 0x00d8df, 1);
+		if (ret < 0)
+			goto err;
+
+		msleep(300);
+
+		ret = af9035_wr_reg(adap->dev, 0x00d8c0, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(adap->dev, 0x00d8c1, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(adap->dev, 0x00d8bf, 0);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(adap->dev, 0x00d8b4, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(adap->dev, 0x00d8b5, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(adap->dev, 0x00d8b3, 1);
+		if (ret < 0)
+			goto err;
+
+		/* attach tuner */
+		fe = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
+				&adap->dev->i2c_adap, 0x60, &af9035_mxl5007t_config);
+		break;
+	case AF9033_TUNER_TDA18218:
+		/* attach tuner */
+		fe = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
+				&adap->dev->i2c_adap, &af9035_tda18218_config);
+		break;
+	default:
+		fe = NULL;
+	}
+
+	if (fe == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+enum af9035_id_entry {
+	AF9035_15A4_9035,
+	AF9035_15A4_1000,
+	AF9035_15A4_1001,
+	AF9035_15A4_1002,
+	AF9035_15A4_1003,
+	AF9035_0CCD_0093,
+	AF9035_07CA_A835,
+	AF9035_07CA_B835,
+	AF9035_07CA_1867,
+	AF9035_07CA_A867,
+	AF9035_07CA_0825,
+};
+
+static struct usb_device_id af9035_id[] = {
+	[AF9035_15A4_9035] = {
+		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035)},
+	[AF9035_15A4_1000] = {
+		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000)},
+	[AF9035_15A4_1001] = {
+		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001)},
+	[AF9035_15A4_1002] = {
+		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002)},
+	[AF9035_15A4_1003] = {
+		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003)},
+	[AF9035_0CCD_0093] = {
+		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK)},
+	[AF9035_07CA_A835] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835)},
+	[AF9035_07CA_B835] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835)},
+	[AF9035_07CA_1867] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867)},
+	[AF9035_07CA_A867] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867)},
+	[AF9035_07CA_0825] = {
+		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR)},
+	{},
+};
+
+MODULE_DEVICE_TABLE(usb, af9035_id);
+
+static struct dvb_usb_device_properties af9035_properties[] = {
+	{
+		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+		.usb_ctrl = DEVICE_SPECIFIC,
+		.download_firmware = af9035_download_firmware,
+		.firmware = "dvb-usb-af9035-02.fw",
+		.no_reconnect = 1,
+
+		.size_of_priv = sizeof(struct state),
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.num_frontends = 1,
+				.fe = {
+					{
+						.frontend_attach = af9035_frontend_attach,
+						.tuner_attach = af9035_tuner_attach,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x84,
+							.u = {
+								.bulk = {
+									.buffersize = (87 * 188),
+								}
+							}
+						}
+					}
+				}
+			}
+		},
+
+		.identify_state = af9035_identify_state,
+		.read_mac_address = af9035_read_mac_address,
+
+		.i2c_algo = &af9035_i2c_algo,
+
+		.rc.core = {
+			.protocol       = RC_TYPE_UNKNOWN,
+			.module_name    = "af9035",
+			.rc_query       = NULL,
+			.rc_interval    = AF9035_POLL,
+			.allowed_protos = RC_TYPE_UNKNOWN,
+			.rc_codes       = RC_MAP_EMPTY,
+		},
+		.num_device_descs = 5,
+		.devices = {
+			{
+				.name = "Afatech AF9035 reference design",
+				.cold_ids = {
+					&af9035_id[AF9035_15A4_9035],
+					&af9035_id[AF9035_15A4_1000],
+					&af9035_id[AF9035_15A4_1001],
+					&af9035_id[AF9035_15A4_1002],
+					&af9035_id[AF9035_15A4_1003],
+				},
+			}, {
+				.name = "TerraTec Cinergy T Stick",
+				.cold_ids = {
+					&af9035_id[AF9035_0CCD_0093],
+				},
+			}, {
+				.name = "AVerMedia AVerTV Volar HD/PRO (A835)",
+				.cold_ids = {
+					&af9035_id[AF9035_07CA_A835],
+					&af9035_id[AF9035_07CA_B835],
+				},
+			}, {
+				.name = "AVerMedia HD Volar (A867)",
+				.cold_ids = {
+					&af9035_id[AF9035_07CA_1867],
+					&af9035_id[AF9035_07CA_A867],
+				},
+			}, {
+				.name = "AVerMedia Twinstar (A825)",
+				.cold_ids = {
+					&af9035_id[AF9035_07CA_0825],
+				},
+			},
+		}
+	},
+	{
+		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+		.usb_ctrl = DEVICE_SPECIFIC,
+		.download_firmware = af9035_download_firmware_it9135,
+		.firmware = "dvb-usb-it9135-01.fw",
+		.no_reconnect = 1,
+
+		.size_of_priv = sizeof(struct state),
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.num_frontends = 1,
+				.fe = {
+					{
+						.frontend_attach = af9035_frontend_attach,
+						.tuner_attach = af9035_tuner_attach,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x84,
+							.u = {
+								.bulk = {
+									.buffersize = (87 * 188),
+								}
+							}
+						}
+					}
+				}
+			}
+		},
+
+		.identify_state = af9035_identify_state,
+		.read_mac_address = af9035_read_mac_address_it9135,
+
+		.i2c_algo = &af9035_i2c_algo,
+
+		.num_device_descs = 0, /* disabled as no support for IT9135 */
+		.devices = {
+			{
+				.name = "ITE Tech. IT9135 reference design",
+			},
+		}
+	},
+};
+
+static int af9035_usb_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	int ret, i;
+	struct dvb_usb_device *d = NULL;
+	struct usb_device *udev;
+	bool found;
+
+	pr_debug("%s: interface=%d\n", __func__,
+			intf->cur_altsetting->desc.bInterfaceNumber);
+
+	/* interface 0 is used by DVB-T receiver and
+	   interface 1 is for remote controller (HID) */
+	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+		return 0;
+
+	/* Dynamic USB ID support. Replaces first device ID with current one. */
+	udev = interface_to_usbdev(intf);
+
+	for (i = 0, found = false; i < ARRAY_SIZE(af9035_id) - 1; i++) {
+		if (af9035_id[i].idVendor ==
+				le16_to_cpu(udev->descriptor.idVendor) &&
+				af9035_id[i].idProduct ==
+				le16_to_cpu(udev->descriptor.idProduct)) {
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		pr_debug("%s: using dynamic ID %04x:%04x\n", __func__,
+				le16_to_cpu(udev->descriptor.idVendor),
+				le16_to_cpu(udev->descriptor.idProduct));
+		af9035_properties[0].devices[0].cold_ids[0]->idVendor =
+				le16_to_cpu(udev->descriptor.idVendor);
+		af9035_properties[0].devices[0].cold_ids[0]->idProduct =
+				le16_to_cpu(udev->descriptor.idProduct);
+	}
+
+
+	for (i = 0; i < af9035_properties_count; i++) {
+		ret = dvb_usb_device_init(intf, &af9035_properties[i],
+				THIS_MODULE, &d, adapter_nr);
+
+		if (ret == -ENODEV)
+			continue;
+		else
+			break;
+	}
+
+	if (ret < 0)
+		goto err;
+
+	if (d) {
+		ret = af9035_init(d);
+		if (ret < 0)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9035_usb_driver = {
+	.name = "dvb_usb_af9035",
+	.probe = af9035_usb_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table = af9035_id,
+};
+
+module_usb_driver(af9035_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9035 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9035.h b/drivers/media/dvb/dvb-usb/af9035.h
new file mode 100644
index 0000000..481a1a4
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9035.h
@@ -0,0 +1,113 @@
+/*
+ * Afatech AF9035 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AF9035_H
+#define AF9035_H
+
+/* prefix for dvb-usb log writings */
+#define DVB_USB_LOG_PREFIX "af9035"
+
+#include "dvb-usb.h"
+#include "af9033.h"
+#include "tua9001.h"
+#include "fc0011.h"
+#include "mxl5007t.h"
+#include "tda18218.h"
+
+struct reg_val {
+	u32 reg;
+	u8  val;
+};
+
+struct reg_val_mask {
+	u32 reg;
+	u8  val;
+	u8  mask;
+};
+
+struct usb_req {
+	u8  cmd;
+	u8  mbox;
+	u8  wlen;
+	u8  *wbuf;
+	u8  rlen;
+	u8  *rbuf;
+};
+
+struct state {
+	bool dual_mode;
+
+	struct af9033_config af9033_config[2];
+};
+
+u32 clock_lut[] = {
+	20480000, /*      FPGA */
+	16384000, /* 16.38 MHz */
+	20480000, /* 20.48 MHz */
+	36000000, /* 36.00 MHz */
+	30000000, /* 30.00 MHz */
+	26000000, /* 26.00 MHz */
+	28000000, /* 28.00 MHz */
+	32000000, /* 32.00 MHz */
+	34000000, /* 34.00 MHz */
+	24000000, /* 24.00 MHz */
+	22000000, /* 22.00 MHz */
+	12000000, /* 12.00 MHz */
+};
+
+u32 clock_lut_it9135[] = {
+	12000000, /* 12.00 MHz */
+	20480000, /* 20.48 MHz */
+	36000000, /* 36.00 MHz */
+	30000000, /* 30.00 MHz */
+	26000000, /* 26.00 MHz */
+	28000000, /* 28.00 MHz */
+	32000000, /* 32.00 MHz */
+	34000000, /* 34.00 MHz */
+	24000000, /* 24.00 MHz */
+	22000000, /* 22.00 MHz */
+};
+
+/* EEPROM locations */
+#define EEPROM_IR_MODE            0x430d
+#define EEPROM_DUAL_MODE          0x4326
+#define EEPROM_IR_TYPE            0x4329
+#define EEPROM_1_IFFREQ_L         0x432d
+#define EEPROM_1_IFFREQ_H         0x432e
+#define EEPROM_1_TUNER_ID         0x4331
+#define EEPROM_2_IFFREQ_L         0x433d
+#define EEPROM_2_IFFREQ_H         0x433e
+#define EEPROM_2_TUNER_ID         0x4341
+
+/* USB commands */
+#define CMD_MEM_RD                  0x00
+#define CMD_MEM_WR                  0x01
+#define CMD_I2C_RD                  0x02
+#define CMD_I2C_WR                  0x03
+#define CMD_IR_GET                  0x18
+#define CMD_FW_DL                   0x21
+#define CMD_FW_QUERYINFO            0x22
+#define CMD_FW_BOOT                 0x23
+#define CMD_FW_DL_BEGIN             0x24
+#define CMD_FW_DL_END               0x25
+#define CMD_FW_SCATTER_WR           0x29
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 02290c6..7e9e00f 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -32,7 +32,7 @@
 
 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
 		err("could not acquire lock");
-		return 0;
+		return -EINTR;
 	}
 
 	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
@@ -118,7 +118,7 @@
 
 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
 		err("could not acquire lock");
-		return 0;
+		return -EINTR;
 	}
 
 	st->buf[0] = REQUEST_SET_GPIO;
@@ -139,7 +139,7 @@
 	if (st->fw_version >= 0x10201) {
 		if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
 			err("could not acquire lock");
-			return 0;
+			return -EINTR;
 		}
 
 		st->buf[0] = REQUEST_SET_USB_XFER_LEN;
@@ -178,7 +178,7 @@
 	/* Ensure nobody else hits the i2c bus while we're sending our
 	   sequence of messages, (such as the remote control thread) */
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
+		return -EINTR;
 
 	for (i = 0; i < num; i++) {
 		if (i == 0) {
@@ -228,7 +228,8 @@
 			/* Write request */
 			if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
 				err("could not acquire lock");
-				return 0;
+				mutex_unlock(&d->i2c_mutex);
+				return -EINTR;
 			}
 			st->buf[0] = REQUEST_NEW_I2C_WRITE;
 			st->buf[1] = msg[i].addr << 1;
@@ -271,10 +272,11 @@
 	int i,len;
 
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
+		return -EINTR;
 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
 		err("could not acquire lock");
-		return 0;
+		mutex_unlock(&d->i2c_mutex);
+		return -EINTR;
 	}
 
 	for (i = 0; i < num; i++) {
@@ -369,7 +371,7 @@
 
 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
 		err("could not acquire lock");
-		return 0;
+		return -EINTR;
 	}
 
 	st->buf[0] = REQUEST_SET_CLOCK;
@@ -401,7 +403,7 @@
 
 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
 		err("could not acquire lock");
-		return 0;
+		return -EINTR;
 	}
 
 	st->buf[0] = REQUEST_SET_I2C_PARAM;
@@ -561,7 +563,7 @@
 
 	if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
 		err("could not acquire lock");
-		return 0;
+		return -EINTR;
 	}
 
 	st->buf[0] = REQUEST_ENABLE_VIDEO;
@@ -611,7 +613,7 @@
 
 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
 		err("could not acquire lock");
-		return 0;
+		return -EINTR;
 	}
 
 	st->buf[0] = REQUEST_SET_RC;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index f9e966a..510001d 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -3569,6 +3569,7 @@
 	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090E) },
 	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7790E) },
 /* 80 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE8096P) },
+	{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT_2) },
 	{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3832,7 +3833,7 @@
 			},
 		},
 
-		.num_device_descs = 11,
+		.num_device_descs = 12,
 		.devices = {
 			{   "DiBcom STK7070P reference design",
 				{ &dib0700_usb_id_table[15], NULL },
@@ -3878,6 +3879,10 @@
 				{ &dib0700_usb_id_table[50], NULL },
 				{ NULL },
 			},
+			{   "Elgato EyeTV DTT rev. 2",
+				{ &dib0700_usb_id_table[81], NULL },
+				{ NULL },
+			},
 		},
 
 		.rc.core = {
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 397d8f2..7a6160b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -76,6 +76,11 @@
 #define USB_PID_AFATECH_AF9005				0x9020
 #define USB_PID_AFATECH_AF9015_9015			0x9015
 #define USB_PID_AFATECH_AF9015_9016			0x9016
+#define USB_PID_AFATECH_AF9035_1000			0x1000
+#define USB_PID_AFATECH_AF9035_1001			0x1001
+#define USB_PID_AFATECH_AF9035_1002			0x1002
+#define USB_PID_AFATECH_AF9035_1003			0x1003
+#define USB_PID_AFATECH_AF9035_9035			0x9035
 #define USB_PID_TREKSTOR_DVBT				0x901b
 #define USB_VID_ALINK_DTU				0xf170
 #define USB_PID_ANSONIC_DVBT_USB			0x6000
@@ -152,6 +157,7 @@
 #define USB_PID_KWORLD_VSTREAM_WARM			0x17df
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE		0x0055
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2		0x0069
+#define USB_PID_TERRATEC_CINERGY_T_STICK		0x0093
 #define USB_PID_TERRATEC_CINERGY_T_STICK_RC		0x0097
 #define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC	0x0099
 #define USB_PID_TWINHAN_VP7041_COLD			0x3201
@@ -221,6 +227,11 @@
 #define USB_PID_AVERMEDIA_A850T				0x850b
 #define USB_PID_AVERMEDIA_A805				0xa805
 #define USB_PID_AVERMEDIA_A815M				0x815a
+#define USB_PID_AVERMEDIA_A835				0xa835
+#define USB_PID_AVERMEDIA_B835				0xb835
+#define USB_PID_AVERMEDIA_1867				0x1867
+#define USB_PID_AVERMEDIA_A867				0xa867
+#define USB_PID_AVERMEDIA_TWINSTAR			0x0825
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_CT3650		0x300d
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
@@ -327,6 +338,7 @@
 #define USB_PID_MYGICA_D689				0xd811
 #define USB_PID_ELGATO_EYETV_DIVERSITY			0x0011
 #define USB_PID_ELGATO_EYETV_DTT			0x0021
+#define USB_PID_ELGATO_EYETV_DTT_2			0x003f
 #define USB_PID_ELGATO_EYETV_DTT_Dlx			0x0020
 #define USB_PID_ELGATO_EYETV_SAT			0x002a
 #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD		0x5000
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index 53a5c30..5c8f651 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -80,6 +80,14 @@
 		dvb_dmx_swfilter_204(&adap->demux, buffer, length);
 }
 
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream,
+				      u8 *buffer, size_t length)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+		dvb_dmx_swfilter_raw(&adap->demux, buffer, length);
+}
+
 int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
 {
 	int i, ret = 0;
@@ -90,6 +98,10 @@
 			adap->fe_adap[i].stream.complete =
 				dvb_usb_data_complete_204;
 		else
+		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD)
+			adap->fe_adap[i].stream.complete =
+				dvb_usb_data_complete_raw;
+		else
 		adap->fe_adap[i].stream.complete  = dvb_usb_data_complete;
 		adap->fe_adap[i].stream.user_priv = adap;
 		ret = usb_urb_init(&adap->fe_adap[i].stream,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 6d7d13f..99f9440 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -141,6 +141,7 @@
 #define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
 #define DVB_USB_ADAP_NEED_PID_FILTERING           0x04
 #define DVB_USB_ADAP_RECEIVES_204_BYTE_TS         0x08
+#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD         0x10
 	int caps;
 	int pid_filter_count;
 
@@ -156,7 +157,7 @@
 	int size_of_priv;
 };
 
-#define MAX_NO_OF_FE_PER_ADAP 2
+#define MAX_NO_OF_FE_PER_ADAP 3
 struct dvb_usb_adapter_properties {
 	int size_of_priv;
 
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index 451c5a7..9382895 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -148,7 +148,7 @@
 		int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i = 0, ret = 0;
+	int i = 0;
 	u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
 	u16 value;
 
@@ -162,7 +162,7 @@
 		/* read stv0299 register */
 		value = msg[0].buf[0];/* register */
 		for (i = 0; i < msg[1].len; i++) {
-			ret = dw210x_op_rw(d->udev, 0xb5, value + i, 0,
+			dw210x_op_rw(d->udev, 0xb5, value + i, 0,
 					buf6, 2, DW210X_READ_MSG);
 			msg[1].buf[i] = buf6[0];
 		}
@@ -174,7 +174,7 @@
 			buf6[0] = 0x2a;
 			buf6[1] = msg[0].buf[0];
 			buf6[2] = msg[0].buf[1];
-			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
 					buf6, 3, DW210X_WRITE_MSG);
 			break;
 		case 0x60:
@@ -187,17 +187,17 @@
 				buf6[4] = msg[0].buf[1];
 				buf6[5] = msg[0].buf[2];
 				buf6[6] = msg[0].buf[3];
-				ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+				dw210x_op_rw(d->udev, 0xb2, 0, 0,
 						buf6, 7, DW210X_WRITE_MSG);
 			} else {
 			/* read from tuner */
-				ret = dw210x_op_rw(d->udev, 0xb5, 0, 0,
+				dw210x_op_rw(d->udev, 0xb5, 0, 0,
 						buf6, 1, DW210X_READ_MSG);
 				msg[0].buf[0] = buf6[0];
 			}
 			break;
 		case (DW2102_RC_QUERY):
-			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
 					buf6, 2, DW210X_READ_MSG);
 			msg[0].buf[0] = buf6[0];
 			msg[0].buf[1] = buf6[1];
@@ -205,7 +205,7 @@
 		case (DW2102_VOLTAGE_CTRL):
 			buf6[0] = 0x30;
 			buf6[1] = msg[0].buf[0];
-			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
 					buf6, 2, DW210X_WRITE_MSG);
 			break;
 		}
@@ -221,7 +221,6 @@
 						struct i2c_msg msg[], int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int ret = 0;
 	u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
 
 	if (!d)
@@ -235,10 +234,10 @@
 		buf6[0] = msg[0].addr << 1;
 		buf6[1] = msg[0].len;
 		buf6[2] = msg[0].buf[0];
-		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+		dw210x_op_rw(d->udev, 0xc2, 0, 0,
 				buf6, msg[0].len + 2, DW210X_WRITE_MSG);
 		/* read si2109 register */
-		ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
+		dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
 				buf6, msg[1].len + 2, DW210X_READ_MSG);
 		memcpy(msg[1].buf, buf6 + 2, msg[1].len);
 
@@ -250,11 +249,11 @@
 			buf6[0] = msg[0].addr << 1;
 			buf6[1] = msg[0].len;
 			memcpy(buf6 + 2, msg[0].buf, msg[0].len);
-			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
+			dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
 					msg[0].len + 2, DW210X_WRITE_MSG);
 			break;
 		case(DW2102_RC_QUERY):
-			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
 					buf6, 2, DW210X_READ_MSG);
 			msg[0].buf[0] = buf6[0];
 			msg[0].buf[1] = buf6[1];
@@ -262,7 +261,7 @@
 		case(DW2102_VOLTAGE_CTRL):
 			buf6[0] = 0x30;
 			buf6[1] = msg[0].buf[0];
-			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
 					buf6, 2, DW210X_WRITE_MSG);
 			break;
 		}
@@ -276,7 +275,6 @@
 static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int ret = 0;
 
 	if (!d)
 		return -ENODEV;
@@ -291,10 +289,10 @@
 		obuf[0] = msg[0].addr << 1;
 		obuf[1] = msg[0].len;
 		obuf[2] = msg[0].buf[0];
-		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+		dw210x_op_rw(d->udev, 0xc2, 0, 0,
 				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
 		/* second read registers */
-		ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
+		dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
 				ibuf, msg[1].len + 2, DW210X_READ_MSG);
 		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
 
@@ -308,7 +306,7 @@
 			obuf[0] = msg[0].addr << 1;
 			obuf[1] = msg[0].len;
 			memcpy(obuf + 2, msg[0].buf, msg[0].len);
-			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+			dw210x_op_rw(d->udev, 0xc2, 0, 0,
 					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
 			break;
 		}
@@ -318,13 +316,13 @@
 			obuf[0] = msg[0].addr << 1;
 			obuf[1] = msg[0].len;
 			memcpy(obuf + 2, msg[0].buf, msg[0].len);
-			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+			dw210x_op_rw(d->udev, 0xc2, 0, 0,
 					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
 			break;
 		}
 		case(DW2102_RC_QUERY): {
 			u8 ibuf[2];
-			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
 					ibuf, 2, DW210X_READ_MSG);
 			memcpy(msg[0].buf, ibuf , 2);
 			break;
@@ -333,7 +331,7 @@
 			u8 obuf[2];
 			obuf[0] = 0x30;
 			obuf[1] = msg[0].buf[0];
-			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
 					obuf, 2, DW210X_WRITE_MSG);
 			break;
 		}
@@ -349,7 +347,6 @@
 static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int ret = 0;
 	int len, i, j;
 
 	if (!d)
@@ -361,7 +358,7 @@
 		switch (msg[j].addr) {
 		case(DW2102_RC_QUERY): {
 			u8 ibuf[2];
-			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
 					ibuf, 2, DW210X_READ_MSG);
 			memcpy(msg[j].buf, ibuf , 2);
 			break;
@@ -370,7 +367,7 @@
 			u8 obuf[2];
 			obuf[0] = 0x30;
 			obuf[1] = msg[j].buf[0];
-			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
 					obuf, 2, DW210X_WRITE_MSG);
 			break;
 		}
@@ -382,7 +379,7 @@
 			if (msg[j].flags == I2C_M_RD) {
 				/* read registers */
 				u8  ibuf[msg[j].len + 2];
-				ret = dw210x_op_rw(d->udev, 0xc3,
+				dw210x_op_rw(d->udev, 0xc3,
 						(msg[j].addr << 1) + 1, 0,
 						ibuf, msg[j].len + 2,
 						DW210X_READ_MSG);
@@ -402,7 +399,7 @@
 				do {
 					memcpy(obuf + 3, msg[j].buf + i,
 							(len > 16 ? 16 : len));
-					ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+					dw210x_op_rw(d->udev, 0xc2, 0, 0,
 						obuf, (len > 16 ? 16 : len) + 3,
 						DW210X_WRITE_MSG);
 					i += 16;
@@ -414,7 +411,7 @@
 				obuf[0] = msg[j].addr << 1;
 				obuf[1] = msg[j].len;
 				memcpy(obuf + 2, msg[j].buf, msg[j].len);
-				ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+				dw210x_op_rw(d->udev, 0xc2, 0, 0,
 						obuf, msg[j].len + 2,
 						DW210X_WRITE_MSG);
 			}
@@ -432,7 +429,7 @@
 								int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int ret = 0, i;
+	int i;
 
 	if (!d)
 		return -ENODEV;
@@ -447,10 +444,10 @@
 		obuf[0] = msg[0].addr << 1;
 		obuf[1] = msg[0].len;
 		obuf[2] = msg[0].buf[0];
-		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+		dw210x_op_rw(d->udev, 0xc2, 0, 0,
 				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
 		/* second read registers */
-		ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
+		dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
 				ibuf, msg[1].len + 2, DW210X_READ_MSG);
 		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
 
@@ -465,13 +462,13 @@
 			obuf[0] = msg[0].addr << 1;
 			obuf[1] = msg[0].len;
 			memcpy(obuf + 2, msg[0].buf, msg[0].len);
-			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+			dw210x_op_rw(d->udev, 0xc2, 0, 0,
 					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
 			break;
 		}
 		case(DW2102_RC_QUERY): {
 			u8 ibuf[2];
-			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
 					ibuf, 2, DW210X_READ_MSG);
 			memcpy(msg[0].buf, ibuf , 2);
 			break;
@@ -496,7 +493,6 @@
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	struct usb_device *udev;
-	int ret = 0;
 	int len, i, j;
 
 	if (!d)
@@ -509,7 +505,7 @@
 		switch (msg[j].addr) {
 		case (DW2102_RC_QUERY): {
 			u8 ibuf[5];
-			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
 					ibuf, 5, DW210X_READ_MSG);
 			memcpy(msg[j].buf, ibuf + 3, 2);
 			break;
@@ -519,11 +515,11 @@
 
 			obuf[0] = 1;
 			obuf[1] = msg[j].buf[1];/* off-on */
-			ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+			dw210x_op_rw(d->udev, 0x8a, 0, 0,
 					obuf, 2, DW210X_WRITE_MSG);
 			obuf[0] = 3;
 			obuf[1] = msg[j].buf[0];/* 13v-18v */
-			ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+			dw210x_op_rw(d->udev, 0x8a, 0, 0,
 					obuf, 2, DW210X_WRITE_MSG);
 			break;
 		}
@@ -532,7 +528,7 @@
 
 			obuf[0] = 5;
 			obuf[1] = msg[j].buf[0];
-			ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+			dw210x_op_rw(d->udev, 0x8a, 0, 0,
 					obuf, 2, DW210X_WRITE_MSG);
 			break;
 		}
@@ -545,7 +541,7 @@
 			if (msg[j].flags == I2C_M_RD) {
 				/* read registers */
 				u8 ibuf[msg[j].len];
-				ret = dw210x_op_rw(d->udev, 0x91, 0, 0,
+				dw210x_op_rw(d->udev, 0x91, 0, 0,
 						ibuf, msg[j].len,
 						DW210X_READ_MSG);
 				memcpy(msg[j].buf, ibuf, msg[j].len);
@@ -563,7 +559,7 @@
 				do {
 					memcpy(obuf + 3, msg[j].buf + i,
 							(len > 16 ? 16 : len));
-					ret = dw210x_op_rw(d->udev, 0x80, 0, 0,
+					dw210x_op_rw(d->udev, 0x80, 0, 0,
 						obuf, (len > 16 ? 16 : len) + 3,
 						DW210X_WRITE_MSG);
 					i += 16;
@@ -575,7 +571,7 @@
 				obuf[0] = msg[j + 1].len;
 				obuf[1] = (msg[j].addr << 1);
 				memcpy(obuf + 2, msg[j].buf, msg[j].len);
-				ret = dw210x_op_rw(d->udev,
+				dw210x_op_rw(d->udev,
 						udev->descriptor.idProduct ==
 						0x7500 ? 0x92 : 0x90, 0, 0,
 						obuf, msg[j].len + 2,
@@ -587,7 +583,7 @@
 				obuf[0] = msg[j].len + 1;
 				obuf[1] = (msg[j].addr << 1);
 				memcpy(obuf + 2, msg[j].buf, msg[j].len);
-				ret = dw210x_op_rw(d->udev, 0x80, 0, 0,
+				dw210x_op_rw(d->udev, 0x80, 0, 0,
 						obuf, msg[j].len + 2,
 						DW210X_WRITE_MSG);
 				break;
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
index 482d249..6244fe9 100644
--- a/drivers/media/dvb/dvb-usb/it913x.c
+++ b/drivers/media/dvb/dvb-usb/it913x.c
@@ -81,7 +81,7 @@
 	for (i = 0; i < IT913X_RETRY; i++) {
 		ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
 				snd, len , &actual_l, IT913X_SND_TIMEOUT);
-		if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT)
+		if (ret != -EBUSY && ret != -ETIMEDOUT)
 			break;
 	}
 
@@ -99,7 +99,7 @@
 	for (i = 0; i < IT913X_RETRY; i++) {
 		ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
 				 rev, len , &actual_l, IT913X_RCV_TIMEOUT);
-		if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT)
+		if (ret != -EBUSY && ret != -ETIMEDOUT)
 			break;
 	}
 
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
index 5dde06d..25d1031 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -373,7 +373,7 @@
 	struct lme2510_state *st = adap->dev->priv;
 	static u8 clear_pid_reg[] = LME_ALL_PIDS;
 	static u8 rbuf[1];
-	int ret;
+	int ret = 0;
 
 	deb_info(1, "PID Clearing Filter");
 
@@ -1205,14 +1205,13 @@
 		const struct usb_device_id *id)
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
-	int ret = 0;
 
 	usb_reset_configuration(udev);
 
 	usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1);
 
 	if (udev->speed != USB_SPEED_HIGH) {
-		ret = usb_reset_device(udev);
+		usb_reset_device(udev);
 		info("DEV Failed to connect in HIGH SPEED mode");
 		return -ENODEV;
 	}
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
index 72db6ee..74da5bb1 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
+++ b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
@@ -284,6 +284,7 @@
 
 	switch (delsys) {
 	case SYS_ATSC:
+	case SYS_ATSCMH:
 		bw = 0; /* ATSC */
 		break;
 	case SYS_DVBC_ANNEX_B:
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c
index 81305de..cd84279 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf.c
+++ b/drivers/media/dvb/dvb-usb/mxl111sf.c
@@ -21,6 +21,7 @@
 #include "mxl111sf-tuner.h"
 
 #include "lgdt3305.h"
+#include "lg2160.h"
 
 int dvb_usb_mxl111sf_debug;
 module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
@@ -31,6 +32,10 @@
 module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
 MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
 
+int dvb_usb_mxl111sf_spi;
+module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
+MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
+
 #define ANT_PATH_AUTO 0
 #define ANT_PATH_EXTERNAL 1
 #define ANT_PATH_INTERNAL 2
@@ -340,7 +345,6 @@
 	struct mxl111sf_state *state = d->priv;
 	struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv;
 	int ret = 0;
-	u8 tmp;
 
 	deb_info("%s(%d)\n", __func__, onoff);
 
@@ -361,6 +365,33 @@
 	return ret;
 }
 
+static int mxl111sf_ep5_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	struct dvb_usb_device *d = adap->dev;
+	struct mxl111sf_state *state = d->priv;
+	int ret = 0;
+
+	deb_info("%s(%d)\n", __func__, onoff);
+
+	if (onoff) {
+		ret = mxl111sf_enable_usb_output(state);
+		mxl_fail(ret);
+
+		ret = mxl111sf_init_i2s_port(state, 200);
+		mxl_fail(ret);
+		ret = mxl111sf_config_i2s(state, 0, 15);
+		mxl_fail(ret);
+	} else {
+		ret = mxl111sf_disable_i2s_port(state);
+		mxl_fail(ret);
+	}
+	if (state->chip_rev > MXL111SF_V6)
+		ret = mxl111sf_config_spi(state, onoff);
+	mxl_fail(ret);
+
+	return ret;
+}
+
 static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	struct dvb_usb_device *d = adap->dev;
@@ -453,6 +484,255 @@
 	return ret;
 }
 
+static struct lg2160_config hauppauge_lg2160_config = {
+	.lg_chip            = LG2160,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+};
+
+static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap->dev;
+	struct mxl111sf_state *state = d->priv;
+	int fe_id = adap->num_frontends_initialized;
+	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
+	int ret;
+
+	deb_adv("%s()\n", __func__);
+
+	/* save a pointer to the dvb_usb_device in device state */
+	state->d = d;
+	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+	state->alt_mode = adap_state->alt_mode;
+
+	if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
+		err("set interface failed");
+
+	state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+	adap_state->gpio_mode = state->gpio_mode;
+	adap_state->device_mode = MXL_TUNER_MODE;
+	adap_state->ep6_clockphase = 1;
+
+	ret = mxl1x1sf_soft_reset(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_init_tuner_demod(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_enable_usb_output(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_top_master_ctrl(state, 1);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_init_port_expander(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = get_chip_info(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
+			      &hauppauge_lg2160_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe_adap[fe_id].fe) {
+		adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
+		adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
+		adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
+		adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
+		return 0;
+	}
+	ret = -EIO;
+fail:
+	return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_config = {
+	.lg_chip            = LG2161_1019,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+	.output_if          = 2, /* LG2161_OIF_SPI_MAS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_config = {
+	.lg_chip            = LG2161_1040,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+	.output_if          = 4, /* LG2161_OIF_SPI_MAS */
+};
+
+static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap->dev;
+	struct mxl111sf_state *state = d->priv;
+	int fe_id = adap->num_frontends_initialized;
+	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
+	int ret;
+
+	deb_adv("%s()\n", __func__);
+
+	/* save a pointer to the dvb_usb_device in device state */
+	state->d = d;
+	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+	state->alt_mode = adap_state->alt_mode;
+
+	if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
+		err("set interface failed");
+
+	state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+	adap_state->gpio_mode = state->gpio_mode;
+	adap_state->device_mode = MXL_TUNER_MODE;
+	adap_state->ep6_clockphase = 1;
+
+	ret = mxl1x1sf_soft_reset(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_init_tuner_demod(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_enable_usb_output(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_top_master_ctrl(state, 1);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_init_port_expander(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = get_chip_info(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
+			      (MXL111SF_V8_200 == state->chip_rev) ?
+			      &hauppauge_lg2161_1040_config :
+			      &hauppauge_lg2161_1019_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe_adap[fe_id].fe) {
+		adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
+		adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
+		adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
+		adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
+		return 0;
+	}
+	ret = -EIO;
+fail:
+	return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_ep6_config = {
+	.lg_chip            = LG2161_1019,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+	.output_if          = 1, /* LG2161_OIF_SERIAL_TS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_ep6_config = {
+	.lg_chip            = LG2161_1040,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+	.output_if          = 7, /* LG2161_OIF_SERIAL_TS */
+};
+
+static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap->dev;
+	struct mxl111sf_state *state = d->priv;
+	int fe_id = adap->num_frontends_initialized;
+	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
+	int ret;
+
+	deb_adv("%s()\n", __func__);
+
+	/* save a pointer to the dvb_usb_device in device state */
+	state->d = d;
+	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+	state->alt_mode = adap_state->alt_mode;
+
+	if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
+		err("set interface failed");
+
+	state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+	adap_state->gpio_mode = state->gpio_mode;
+	adap_state->device_mode = MXL_TUNER_MODE;
+	adap_state->ep6_clockphase = 0;
+
+	ret = mxl1x1sf_soft_reset(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_init_tuner_demod(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_enable_usb_output(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_top_master_ctrl(state, 1);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_init_port_expander(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = get_chip_info(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
+			      (MXL111SF_V8_200 == state->chip_rev) ?
+			      &hauppauge_lg2161_1040_ep6_config :
+			      &hauppauge_lg2161_1019_ep6_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe_adap[fe_id].fe) {
+		adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
+		adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
+		adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
+		adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
+		return 0;
+	}
+	ret = -EIO;
+fail:
+	return ret;
+}
+
 static struct mxl111sf_demod_config mxl_demod_config = {
 	.read_reg        = mxl111sf_read_reg,
 	.write_reg       = mxl111sf_write_reg,
@@ -650,6 +930,18 @@
 static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties;
 static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties;
 static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties;
 
 static int mxl111sf_probe(struct usb_interface *intf,
 			  const struct usb_device_id *id)
@@ -664,12 +956,50 @@
 				       THIS_MODULE, &d, adapter_nr) ||
 	      0 == dvb_usb_device_init(intf,
 				       &mxl111sf_atsc_isoc_properties,
+				       THIS_MODULE, &d, adapter_nr) ||
+	      0 == dvb_usb_device_init(intf,
+				       &mxl111sf_atsc_mh_isoc_properties,
+				       THIS_MODULE, &d, adapter_nr) ||
+	      0 == dvb_usb_device_init(intf,
+				       &mxl111sf_mh_isoc_properties,
+				       THIS_MODULE, &d, adapter_nr) ||
+	      ((dvb_usb_mxl111sf_spi) &&
+	       (0 == dvb_usb_device_init(intf,
+					 &mxl111sf_mercury_spi_isoc_properties,
+					 THIS_MODULE, &d, adapter_nr) ||
+		0 == dvb_usb_device_init(intf,
+					 &mxl111sf_mercury_mh_spi_isoc_properties,
+					 THIS_MODULE, &d, adapter_nr))) ||
+	      0 == dvb_usb_device_init(intf,
+				       &mxl111sf_mercury_tp_isoc_properties,
+				       THIS_MODULE, &d, adapter_nr) ||
+	      0 == dvb_usb_device_init(intf,
+				       &mxl111sf_mercury_mh_tp_isoc_properties,
 				       THIS_MODULE, &d, adapter_nr))) ||
 	    0 == dvb_usb_device_init(intf,
 				     &mxl111sf_dvbt_bulk_properties,
 				     THIS_MODULE, &d, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf,
 				     &mxl111sf_atsc_bulk_properties,
+				     THIS_MODULE, &d, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf,
+				     &mxl111sf_atsc_mh_bulk_properties,
+				     THIS_MODULE, &d, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf,
+				     &mxl111sf_mh_bulk_properties,
+				     THIS_MODULE, &d, adapter_nr) ||
+	    ((dvb_usb_mxl111sf_spi) &&
+	     (0 == dvb_usb_device_init(intf,
+				       &mxl111sf_mercury_spi_bulk_properties,
+				       THIS_MODULE, &d, adapter_nr) ||
+	      0 == dvb_usb_device_init(intf,
+				       &mxl111sf_mercury_mh_spi_bulk_properties,
+				       THIS_MODULE, &d, adapter_nr))) ||
+	    0 == dvb_usb_device_init(intf,
+				     &mxl111sf_mercury_tp_bulk_properties,
+				     THIS_MODULE, &d, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf,
+				     &mxl111sf_mercury_mh_tp_bulk_properties,
 				     THIS_MODULE, &d, adapter_nr) || 0) {
 
 		struct mxl111sf_state *state = d->priv;
@@ -787,6 +1117,36 @@
 		}					\
 	}
 
+#define MXL111SF_EP5_BULK_STREAMING_CONFIG		\
+	.size_of_priv = sizeof(struct mxl111sf_adap_state), \
+	.streaming_ctrl = mxl111sf_ep5_streaming_ctrl,	\
+	.stream = {					\
+		.type = USB_BULK,			\
+		.count = 5,				\
+		.endpoint = 0x05,			\
+		.u = {					\
+			.bulk = {			\
+				.buffersize = 8192,	\
+			}				\
+		}					\
+	}
+
+#define MXL111SF_EP5_ISOC_STREAMING_CONFIG		\
+	.size_of_priv = sizeof(struct mxl111sf_adap_state), \
+	.streaming_ctrl = mxl111sf_ep5_streaming_ctrl,	\
+	.stream = {					\
+		.type = USB_ISOC,			\
+		.count = 5,				\
+		.endpoint = 0x05,			\
+		.u = {					\
+			.isoc = {			\
+				.framesperurb = 96,	\
+				.framesize = 200,	\
+				.interval = 1,		\
+			}				\
+		}					\
+	}
+
 #define MXL111SF_EP6_BULK_STREAMING_CONFIG		\
 	.size_of_priv = sizeof(struct mxl111sf_adap_state), \
 	.streaming_ctrl = mxl111sf_ep6_streaming_ctrl,	\
@@ -848,7 +1208,7 @@
 		} },
 		},
 	},
-	.num_device_descs = 4,
+	.num_device_descs = 3,
 	.devices = {
 		{   "Hauppauge 126xxx DVBT (bulk)",
 			{ NULL },
@@ -866,11 +1226,6 @@
 			  &mxl111sf_table[24], &mxl111sf_table[26],
 			  NULL },
 		},
-		{   "Hauppauge 126xxx (tp-bulk)",
-			{ NULL },
-			{ &mxl111sf_table[28], &mxl111sf_table[30],
-			  NULL },
-		},
 	}
 };
 
@@ -890,7 +1245,7 @@
 		} },
 		},
 	},
-	.num_device_descs = 4,
+	.num_device_descs = 3,
 	.devices = {
 		{   "Hauppauge 126xxx DVBT (isoc)",
 			{ NULL },
@@ -908,11 +1263,6 @@
 			  &mxl111sf_table[24], &mxl111sf_table[26],
 			  NULL },
 		},
-		{   "Hauppauge 126xxx (tp-isoc)",
-			{ NULL },
-			{ &mxl111sf_table[28], &mxl111sf_table[30],
-			  NULL },
-		},
 	}
 };
 
@@ -923,22 +1273,16 @@
 	.adapter = {
 		{
 		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 2,
+		.num_frontends = 1,
 		.fe = {{
 			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
 			.tuner_attach     = mxl111sf_attach_tuner,
 
 			MXL111SF_EP6_BULK_STREAMING_CONFIG,
-		},
-		{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_BULK_STREAMING_CONFIG,
 		}},
 		},
 	},
-	.num_device_descs = 6,
+	.num_device_descs = 2,
 	.devices = {
 		{   "Hauppauge 126xxx ATSC (bulk)",
 			{ NULL },
@@ -950,6 +1294,138 @@
 			{ &mxl111sf_table[12],
 			  NULL },
 		},
+	}
+};
+
+static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{   "Hauppauge 126xxx ATSC (isoc)",
+			{ NULL },
+			{ &mxl111sf_table[1], &mxl111sf_table[5],
+			  NULL },
+		},
+		{   "Hauppauge 117xxx ATSC (isoc)",
+			{ NULL },
+			{ &mxl111sf_table[12],
+			  NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2160_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP5_BULK_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{   "HCW 126xxx (bulk)",
+			{ NULL },
+			{ &mxl111sf_table[2], &mxl111sf_table[6],
+			  NULL },
+		},
+		{   "HCW 117xxx (bulk)",
+			{ NULL },
+			{ &mxl111sf_table[13],
+			  NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2160_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP5_ISOC_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{   "HCW 126xxx (isoc)",
+			{ NULL },
+			{ &mxl111sf_table[2], &mxl111sf_table[6],
+			  NULL },
+		},
+		{   "HCW 117xxx (isoc)",
+			{ NULL },
+			{ &mxl111sf_table[13],
+			  NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 3,
+		.fe = {{
+			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_BULK_STREAMING_CONFIG,
+		},
+		{
+			.frontend_attach  = mxl111sf_attach_demod,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP4_BULK_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2160_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP5_BULK_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 2,
+	.devices = {
 		{   "Hauppauge 126xxx ATSC+ (bulk)",
 			{ NULL },
 			{ &mxl111sf_table[0], &mxl111sf_table[3],
@@ -963,6 +1439,181 @@
 			  &mxl111sf_table[32], &mxl111sf_table[33],
 			  NULL },
 		},
+	}
+};
+
+static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 3,
+		.fe = {{
+			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
+		},
+		{
+			.frontend_attach  = mxl111sf_attach_demod,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2160_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP5_ISOC_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{   "Hauppauge 126xxx ATSC+ (isoc)",
+			{ NULL },
+			{ &mxl111sf_table[0], &mxl111sf_table[3],
+			  &mxl111sf_table[7], &mxl111sf_table[9],
+			  &mxl111sf_table[10], NULL },
+		},
+		{   "Hauppauge 117xxx ATSC+ (isoc)",
+			{ NULL },
+			{ &mxl111sf_table[11], &mxl111sf_table[14],
+			  &mxl111sf_table[16], &mxl111sf_table[17],
+			  &mxl111sf_table[32], &mxl111sf_table[33],
+			  NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 3,
+		.fe = {{
+			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_BULK_STREAMING_CONFIG,
+		},
+		{
+			.frontend_attach  = mxl111sf_attach_demod,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP4_BULK_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2161_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP5_BULK_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{   "Hauppauge Mercury (spi-bulk)",
+			{ NULL },
+			{ &mxl111sf_table[19], &mxl111sf_table[21],
+			  &mxl111sf_table[23], &mxl111sf_table[25],
+			  NULL },
+		},
+		{   "Hauppauge WinTV-Aero-M (spi-bulk)",
+			{ NULL },
+			{ &mxl111sf_table[29], &mxl111sf_table[31],
+			  NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 3,
+		.fe = {{
+			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
+		},
+		{
+			.frontend_attach  = mxl111sf_attach_demod,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2161_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP5_ISOC_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{   "Hauppauge Mercury (spi-isoc)",
+			{ NULL },
+			{ &mxl111sf_table[19], &mxl111sf_table[21],
+			  &mxl111sf_table[23], &mxl111sf_table[25],
+			  NULL },
+		},
+		{   "Hauppauge WinTV-Aero-M (spi-isoc)",
+			{ NULL },
+			{ &mxl111sf_table[29], &mxl111sf_table[31],
+			  NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 3,
+		.fe = {{
+			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_BULK_STREAMING_CONFIG,
+		},
+		{
+			.frontend_attach  = mxl111sf_attach_demod,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP4_BULK_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_BULK_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 2,
+	.devices = {
 		{   "Hauppauge Mercury (tp-bulk)",
 			{ NULL },
 			{ &mxl111sf_table[19], &mxl111sf_table[21],
@@ -977,14 +1628,14 @@
 	}
 };
 
-static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
+static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties = {
 	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
 
 	.num_adapters = 1,
 	.adapter = {
 		{
 		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 2,
+		.num_frontends = 3,
 		.fe = {{
 			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
 			.tuner_attach     = mxl111sf_attach_tuner,
@@ -996,34 +1647,19 @@
 			.tuner_attach     = mxl111sf_attach_tuner,
 
 			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
 		}},
 		},
 	},
-	.num_device_descs = 6,
+	.num_device_descs = 2,
 	.devices = {
-		{   "Hauppauge 126xxx ATSC (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[1], &mxl111sf_table[5],
-			  NULL },
-		},
-		{   "Hauppauge 117xxx ATSC (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[12],
-			  NULL },
-		},
-		{   "Hauppauge 126xxx ATSC+ (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[0], &mxl111sf_table[3],
-			  &mxl111sf_table[7], &mxl111sf_table[9],
-			  &mxl111sf_table[10], NULL },
-		},
-		{   "Hauppauge 117xxx ATSC+ (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[11], &mxl111sf_table[14],
-			  &mxl111sf_table[16], &mxl111sf_table[17],
-			  &mxl111sf_table[32], &mxl111sf_table[33],
-			  NULL },
-		},
 		{   "Hauppauge Mercury (tp-isoc)",
 			{ NULL },
 			{ &mxl111sf_table[19], &mxl111sf_table[21],
@@ -1038,6 +1674,146 @@
 	}
 };
 
+static
+struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 2,
+		.fe = {{
+			.frontend_attach  = mxl111sf_attach_demod,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP4_BULK_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_BULK_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{   "Hauppauge 126xxx (tp-bulk)",
+			{ NULL },
+			{ &mxl111sf_table[28], &mxl111sf_table[30],
+			  NULL },
+		},
+	}
+};
+
+static
+struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 2,
+		.fe = {{
+			.frontend_attach  = mxl111sf_attach_demod,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{   "Hauppauge 126xxx (tp-isoc)",
+			{ NULL },
+			{ &mxl111sf_table[28], &mxl111sf_table[30],
+			  NULL },
+		},
+	}
+};
+
+static
+struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 2,
+		.fe = {{
+			.frontend_attach  = mxl111sf_attach_demod,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP4_BULK_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2161_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP5_BULK_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{   "Hauppauge 126xxx (spi-bulk)",
+			{ NULL },
+			{ &mxl111sf_table[28], &mxl111sf_table[30],
+			  NULL },
+		},
+	}
+};
+
+static
+struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties = {
+	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
+		.num_frontends = 2,
+		.fe = {{
+			.frontend_attach  = mxl111sf_attach_demod,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+		},
+		{
+			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+			.frontend_attach  = mxl111sf_lg2161_frontend_attach,
+			.tuner_attach     = mxl111sf_attach_tuner,
+
+			MXL111SF_EP5_ISOC_STREAMING_CONFIG,
+		}},
+		},
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{   "Hauppauge 126xxx (spi-isoc)",
+			{ NULL },
+			{ &mxl111sf_table[28], &mxl111sf_table[30],
+			  NULL },
+		},
+	}
+};
+
 static struct usb_driver mxl111sf_driver = {
 	.name		= "dvb_usb_mxl111sf",
 	.probe		= mxl111sf_probe,
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
index 8f4736a..41e1f55 100644
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -322,6 +322,9 @@
 	 * since there is some demod params needed to set according to tuner.
 	 */
 
+	/* demod needs some time to wake up */
+	msleep(20);
+
 	/* open demod I2C gate */
 	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
 	if (ret)
@@ -909,6 +912,8 @@
 	int ret, i;
 	int properties_count = ARRAY_SIZE(rtl28xxu_properties);
 	struct dvb_usb_device *d;
+	struct usb_device *udev;
+	bool found;
 
 	deb_info("%s: interface=%d\n", __func__,
 		intf->cur_altsetting->desc.bInterfaceNumber);
@@ -916,6 +921,29 @@
 	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
 		return 0;
 
+	/* Dynamic USB ID support. Replaces first device ID with current one .*/
+	udev = interface_to_usbdev(intf);
+
+	for (i = 0, found = false; i < ARRAY_SIZE(rtl28xxu_table) - 1; i++) {
+		if (rtl28xxu_table[i].idVendor ==
+				le16_to_cpu(udev->descriptor.idVendor) &&
+				rtl28xxu_table[i].idProduct ==
+				le16_to_cpu(udev->descriptor.idProduct)) {
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		deb_info("%s: using dynamic ID %04x:%04x\n", __func__,
+				le16_to_cpu(udev->descriptor.idVendor),
+				le16_to_cpu(udev->descriptor.idProduct));
+		rtl28xxu_properties[0].devices[0].warm_ids[0]->idVendor =
+				le16_to_cpu(udev->descriptor.idVendor);
+		rtl28xxu_properties[0].devices[0].warm_ids[0]->idProduct =
+				le16_to_cpu(udev->descriptor.idProduct);
+	}
+
 	for (i = 0; i < properties_count; i++) {
 		ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i],
 				THIS_MODULE, &d, adapter_nr);
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 2124670..b98ebb2 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -531,6 +531,14 @@
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
 	  to support this frontend.
 
+config DVB_LG2160
+	tristate "LG Electronics LG216x based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC/MH demodulator module. Say Y when you want
+	  to support this frontend.
+
 config DVB_S5H1409
 	tristate "Samsung S5H1409 based"
 	depends on DVB_CORE && I2C
@@ -540,12 +548,26 @@
 	  to support this frontend.
 
 config DVB_AU8522
-	tristate "Auvitek AU8522 based"
-	depends on DVB_CORE && I2C && VIDEO_V4L2
+	depends on I2C
+	tristate
+
+config DVB_AU8522_DTV
+	tristate "Auvitek AU8522 based DTV demod"
+	depends on DVB_CORE && I2C
+	select DVB_AU8522
 	default m if DVB_FE_CUSTOMISE
 	help
-	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
-	  to support this frontend.
+	  An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
+	  you want to enable DTV demodulation support for this frontend.
+
+config DVB_AU8522_V4L
+	tristate "Auvitek AU8522 based ATV demod"
+	depends on VIDEO_V4L2 && I2C
+	select DVB_AU8522
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
+	  you want to enable ATV demodulation support for this frontend.
 
 config DVB_S5H1411
 	tristate "Samsung S5H1411 based"
@@ -713,6 +735,11 @@
 	  A DVB-S tuner module.
 	  Say Y when you want to support this frontend.
 
+config DVB_AF9033
+	tristate "Afatech AF9033 DVB-T demodulator"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 86fa808..cd1ac2f 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -7,7 +7,6 @@
 
 stb0899-objs = stb0899_drv.o stb0899_algo.o
 stv0900-objs = stv0900_core.o stv0900_sw.o
-au8522-objs = au8522_dig.o au8522_decoder.o
 drxd-objs = drxd_firm.o drxd_hard.o
 cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
 drxk-objs := drxk_hard.o
@@ -50,6 +49,7 @@
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
+obj-$(CONFIG_DVB_LG2160) += lg2160.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
 obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
@@ -63,7 +63,9 @@
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
 obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
-obj-$(CONFIG_DVB_AU8522) += au8522.o
+obj-$(CONFIG_DVB_AU8522) += au8522_common.o
+obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o
+obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o
 obj-$(CONFIG_DVB_TDA10048) += tda10048.o
 obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
@@ -98,4 +100,5 @@
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
+obj-$(CONFIG_DVB_AF9033) += af9033.o
 
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index 6bcbcf5..5bc570d 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -514,7 +514,6 @@
 
 static void af9013_statistics_work(struct work_struct *work)
 {
-	int ret;
 	struct af9013_state *state = container_of(work,
 		struct af9013_state, statistics_work.work);
 	unsigned int next_msec;
@@ -530,27 +529,27 @@
 	default:
 		state->statistics_step = 0;
 	case 0:
-		ret = af9013_statistics_signal_strength(&state->fe);
+		af9013_statistics_signal_strength(&state->fe);
 		state->statistics_step++;
 		next_msec = 300;
 		break;
 	case 1:
-		ret = af9013_statistics_snr_start(&state->fe);
+		af9013_statistics_snr_start(&state->fe);
 		state->statistics_step++;
 		next_msec = 200;
 		break;
 	case 2:
-		ret = af9013_statistics_ber_unc_start(&state->fe);
+		af9013_statistics_ber_unc_start(&state->fe);
 		state->statistics_step++;
 		next_msec = 1000;
 		break;
 	case 3:
-		ret = af9013_statistics_snr_result(&state->fe);
+		af9013_statistics_snr_result(&state->fe);
 		state->statistics_step++;
 		next_msec = 400;
 		break;
 	case 4:
-		ret = af9013_statistics_ber_unc_result(&state->fe);
+		af9013_statistics_ber_unc_result(&state->fe);
 		state->statistics_step++;
 		next_msec = 100;
 		break;
@@ -558,8 +557,6 @@
 
 	schedule_delayed_work(&state->statistics_work,
 		msecs_to_jiffies(next_msec));
-
-	return;
 }
 
 static int af9013_get_tune_settings(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb/frontends/af9033.c b/drivers/media/dvb/frontends/af9033.c
new file mode 100644
index 0000000..a389982
--- /dev/null
+++ b/drivers/media/dvb/frontends/af9033.c
@@ -0,0 +1,980 @@
+/*
+ * Afatech AF9033 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "af9033_priv.h"
+
+struct af9033_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct af9033_config cfg;
+
+	u32 bandwidth_hz;
+	bool ts_mode_parallel;
+	bool ts_mode_serial;
+
+	u32 ber;
+	u32 ucb;
+	unsigned long last_stat_check;
+};
+
+/* write multiple registers */
+static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
+		int len)
+{
+	int ret;
+	u8 buf[3 + len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = state->cfg.i2c_addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	buf[0] = (reg >> 16) & 0xff;
+	buf[1] = (reg >>  8) & 0xff;
+	buf[2] = (reg >>  0) & 0xff;
+	memcpy(&buf[3], val, len);
+
+	ret = i2c_transfer(state->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		printk(KERN_WARNING "%s: i2c wr failed=%d reg=%06x len=%d\n",
+				__func__, ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+/* read multiple registers */
+static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff,
+			(reg >> 0) & 0xff };
+	struct i2c_msg msg[2] = {
+		{
+			.addr = state->cfg.i2c_addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf
+		}, {
+			.addr = state->cfg.i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		printk(KERN_WARNING "%s: i2c rd failed=%d reg=%06x len=%d\n",
+				__func__, ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+
+/* write single register */
+static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val)
+{
+	return af9033_wr_regs(state, reg, &val, 1);
+}
+
+/* read single register */
+static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val)
+{
+	return af9033_rd_regs(state, reg, val, 1);
+}
+
+/* write single register with mask */
+static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
+		u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = af9033_rd_regs(state, reg, &tmp, 1);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return af9033_wr_regs(state, reg, &val, 1);
+}
+
+/* read single register with mask */
+static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
+		u8 mask)
+{
+	int ret, i;
+	u8 tmp;
+
+	ret = af9033_rd_regs(state, reg, &tmp, 1);
+	if (ret)
+		return ret;
+
+	tmp &= mask;
+
+	/* find position of the first bit */
+	for (i = 0; i < 8; i++) {
+		if ((mask >> i) & 0x01)
+			break;
+	}
+	*val = tmp >> i;
+
+	return 0;
+}
+
+static u32 af9033_div(u32 a, u32 b, u32 x)
+{
+	u32 r = 0, c = 0, i;
+
+	pr_debug("%s: a=%d b=%d x=%d\n", __func__, a, b, x);
+
+	if (a > b) {
+		c = a / b;
+		a = a - c * b;
+	}
+
+	for (i = 0; i < x; i++) {
+		if (a >= b) {
+			r += 1;
+			a -= b;
+		}
+		a <<= 1;
+		r <<= 1;
+	}
+	r = (c << (u32)x) + r;
+
+	pr_debug("%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r);
+
+	return r;
+}
+
+static void af9033_release(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+
+	kfree(state);
+}
+
+static int af9033_init(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret, i, len;
+	const struct reg_val *init;
+	u8 buf[4];
+	u32 adc_cw, clock_cw;
+	struct reg_val_mask tab[] = {
+		{ 0x80fb24, 0x00, 0x08 },
+		{ 0x80004c, 0x00, 0xff },
+		{ 0x00f641, state->cfg.tuner, 0xff },
+		{ 0x80f5ca, 0x01, 0x01 },
+		{ 0x80f715, 0x01, 0x01 },
+		{ 0x00f41f, 0x04, 0x04 },
+		{ 0x00f41a, 0x01, 0x01 },
+		{ 0x80f731, 0x00, 0x01 },
+		{ 0x00d91e, 0x00, 0x01 },
+		{ 0x00d919, 0x00, 0x01 },
+		{ 0x80f732, 0x00, 0x01 },
+		{ 0x00d91f, 0x00, 0x01 },
+		{ 0x00d91a, 0x00, 0x01 },
+		{ 0x80f730, 0x00, 0x01 },
+		{ 0x80f778, 0x00, 0xff },
+		{ 0x80f73c, 0x01, 0x01 },
+		{ 0x80f776, 0x00, 0x01 },
+		{ 0x00d8fd, 0x01, 0xff },
+		{ 0x00d830, 0x01, 0xff },
+		{ 0x00d831, 0x00, 0xff },
+		{ 0x00d832, 0x00, 0xff },
+		{ 0x80f985, state->ts_mode_serial, 0x01 },
+		{ 0x80f986, state->ts_mode_parallel, 0x01 },
+		{ 0x00d827, 0x00, 0xff },
+		{ 0x00d829, 0x00, 0xff },
+	};
+
+	/* program clock control */
+	clock_cw = af9033_div(state->cfg.clock, 1000000ul, 19ul);
+	buf[0] = (clock_cw >>  0) & 0xff;
+	buf[1] = (clock_cw >>  8) & 0xff;
+	buf[2] = (clock_cw >> 16) & 0xff;
+	buf[3] = (clock_cw >> 24) & 0xff;
+
+	pr_debug("%s: clock=%d clock_cw=%08x\n", __func__, state->cfg.clock,
+			clock_cw);
+
+	ret = af9033_wr_regs(state, 0x800025, buf, 4);
+	if (ret < 0)
+		goto err;
+
+	/* program ADC control */
+	for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
+		if (clock_adc_lut[i].clock == state->cfg.clock)
+			break;
+	}
+
+	adc_cw = af9033_div(clock_adc_lut[i].adc, 1000000ul, 19ul);
+	buf[0] = (adc_cw >>  0) & 0xff;
+	buf[1] = (adc_cw >>  8) & 0xff;
+	buf[2] = (adc_cw >> 16) & 0xff;
+
+	pr_debug("%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc,
+			adc_cw);
+
+	ret = af9033_wr_regs(state, 0x80f1cd, buf, 3);
+	if (ret < 0)
+		goto err;
+
+	/* program register table */
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val,
+				tab[i].mask);
+		if (ret < 0)
+			goto err;
+	}
+
+	/* settings for TS interface */
+	if (state->cfg.ts_mode == AF9033_TS_MODE_USB) {
+		ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+	} else {
+		ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+	}
+
+	/* load OFSM settings */
+	pr_debug("%s: load ofsm settings\n", __func__);
+	len = ARRAY_SIZE(ofsm_init);
+	init = ofsm_init;
+	for (i = 0; i < len; i++) {
+		ret = af9033_wr_reg(state, init[i].reg, init[i].val);
+		if (ret < 0)
+			goto err;
+	}
+
+	/* load tuner specific settings */
+	pr_debug("%s: load tuner specific settings\n",
+			__func__);
+	switch (state->cfg.tuner) {
+	case AF9033_TUNER_TUA9001:
+		len = ARRAY_SIZE(tuner_init_tua9001);
+		init = tuner_init_tua9001;
+		break;
+	case AF9033_TUNER_FC0011:
+		len = ARRAY_SIZE(tuner_init_fc0011);
+		init = tuner_init_fc0011;
+		break;
+	case AF9033_TUNER_MXL5007T:
+		len = ARRAY_SIZE(tuner_init_mxl5007t);
+		init = tuner_init_mxl5007t;
+		break;
+	case AF9033_TUNER_TDA18218:
+		len = ARRAY_SIZE(tuner_init_tda18218);
+		init = tuner_init_tda18218;
+		break;
+	default:
+		pr_debug("%s: unsupported tuner ID=%d\n", __func__,
+				state->cfg.tuner);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	for (i = 0; i < len; i++) {
+		ret = af9033_wr_reg(state, init[i].reg, init[i].val);
+		if (ret < 0)
+			goto err;
+	}
+
+	state->bandwidth_hz = 0; /* force to program all parameters */
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_sleep(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret, i;
+	u8 tmp;
+
+	ret = af9033_wr_reg(state, 0x80004c, 1);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg(state, 0x800000, 0);
+	if (ret < 0)
+		goto err;
+
+	for (i = 100, tmp = 1; i && tmp; i--) {
+		ret = af9033_rd_reg(state, 0x80004c, &tmp);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(200, 10000);
+	}
+
+	pr_debug("%s: loop=%d\n", __func__, i);
+
+	if (i == 0) {
+		ret = -ETIMEDOUT;
+		goto err;
+	}
+
+	ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08);
+	if (ret < 0)
+		goto err;
+
+	/* prevent current leak (?) */
+	if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+		/* enable parallel TS */
+		ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_get_tune_settings(struct dvb_frontend *fe,
+		struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 800;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+
+	return 0;
+}
+
+static int af9033_set_frontend(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i, spec_inv;
+	u8 tmp, buf[3], bandwidth_reg_val;
+	u32 if_frequency, freq_cw, adc_freq;
+
+	pr_debug("%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency,
+			c->bandwidth_hz);
+
+	/* check bandwidth */
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		bandwidth_reg_val = 0x00;
+		break;
+	case 7000000:
+		bandwidth_reg_val = 0x01;
+		break;
+	case 8000000:
+		bandwidth_reg_val = 0x02;
+		break;
+	default:
+		pr_debug("%s: invalid bandwidth_hz\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	/* program CFOE coefficients */
+	if (c->bandwidth_hz != state->bandwidth_hz) {
+		for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
+			if (coeff_lut[i].clock == state->cfg.clock &&
+				coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
+				break;
+			}
+		}
+		ret =  af9033_wr_regs(state, 0x800001,
+				coeff_lut[i].val, sizeof(coeff_lut[i].val));
+	}
+
+	/* program frequency control */
+	if (c->bandwidth_hz != state->bandwidth_hz) {
+		spec_inv = state->cfg.spec_inv ? -1 : 1;
+
+		for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
+			if (clock_adc_lut[i].clock == state->cfg.clock)
+				break;
+		}
+		adc_freq = clock_adc_lut[i].adc;
+
+		/* get used IF frequency */
+		if (fe->ops.tuner_ops.get_if_frequency)
+			fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
+		else
+			if_frequency = 0;
+
+		while (if_frequency > (adc_freq / 2))
+			if_frequency -= adc_freq;
+
+		if (if_frequency >= 0)
+			spec_inv *= -1;
+		else
+			if_frequency *= -1;
+
+		freq_cw = af9033_div(if_frequency, adc_freq, 23ul);
+
+		if (spec_inv == -1)
+			freq_cw *= -1;
+
+		/* get adc multiplies */
+		ret = af9033_rd_reg(state, 0x800045, &tmp);
+		if (ret < 0)
+			goto err;
+
+		if (tmp == 1)
+			freq_cw /= 2;
+
+		buf[0] = (freq_cw >>  0) & 0xff;
+		buf[1] = (freq_cw >>  8) & 0xff;
+		buf[2] = (freq_cw >> 16) & 0x7f;
+		ret = af9033_wr_regs(state, 0x800029, buf, 3);
+		if (ret < 0)
+			goto err;
+
+		state->bandwidth_hz = c->bandwidth_hz;
+	}
+
+	ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg(state, 0x800040, 0x00);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg(state, 0x800047, 0x00);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01);
+	if (ret < 0)
+		goto err;
+
+	if (c->frequency <= 230000000)
+		tmp = 0x00; /* VHF */
+	else
+		tmp = 0x01; /* UHF */
+
+	ret = af9033_wr_reg(state, 0x80004b, tmp);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg(state, 0x800000, 0x00);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_get_frontend(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+	u8 buf[8];
+
+	pr_debug("%s\n", __func__);
+
+	/* read all needed registers */
+	ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf));
+	if (ret < 0)
+		goto err;
+
+	switch ((buf[0] >> 0) & 3) {
+	case 0:
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		c->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	}
+
+	switch ((buf[1] >> 0) & 3) {
+	case 0:
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		c->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		c->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		c->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	switch ((buf[2] >> 0) & 7) {
+	case 0:
+		c->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		c->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		c->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		c->hierarchy = HIERARCHY_4;
+		break;
+	}
+
+	switch ((buf[3] >> 0) & 3) {
+	case 0:
+		c->modulation = QPSK;
+		break;
+	case 1:
+		c->modulation = QAM_16;
+		break;
+	case 2:
+		c->modulation = QAM_64;
+		break;
+	}
+
+	switch ((buf[4] >> 0) & 3) {
+	case 0:
+		c->bandwidth_hz = 6000000;
+		break;
+	case 1:
+		c->bandwidth_hz = 7000000;
+		break;
+	case 2:
+		c->bandwidth_hz = 8000000;
+		break;
+	}
+
+	switch ((buf[6] >> 0) & 7) {
+	case 0:
+		c->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_HP = FEC_7_8;
+		break;
+	case 5:
+		c->code_rate_HP = FEC_NONE;
+		break;
+	}
+
+	switch ((buf[7] >> 0) & 7) {
+	case 0:
+		c->code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_LP = FEC_7_8;
+		break;
+	case 5:
+		c->code_rate_LP = FEC_NONE;
+		break;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+
+	*status = 0;
+
+	/* radio channel status, 0=no result, 1=has signal, 2=no signal */
+	ret = af9033_rd_reg(state, 0x800047, &tmp);
+	if (ret < 0)
+		goto err;
+
+	/* has signal */
+	if (tmp == 0x01)
+		*status |= FE_HAS_SIGNAL;
+
+	if (tmp != 0x02) {
+		/* TPS lock */
+		ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01);
+		if (ret < 0)
+			goto err;
+
+		if (tmp)
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+					FE_HAS_VITERBI;
+
+		/* full lock */
+		ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01);
+		if (ret < 0)
+			goto err;
+
+		if (tmp)
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+					FE_HAS_VITERBI | FE_HAS_SYNC |
+					FE_HAS_LOCK;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret, i, len;
+	u8 buf[3], tmp;
+	u32 snr_val;
+	const struct val_snr *uninitialized_var(snr_lut);
+
+	/* read value */
+	ret = af9033_rd_regs(state, 0x80002c, buf, 3);
+	if (ret < 0)
+		goto err;
+
+	snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+	/* read current modulation */
+	ret = af9033_rd_reg(state, 0x80f903, &tmp);
+	if (ret < 0)
+		goto err;
+
+	switch ((tmp >> 0) & 3) {
+	case 0:
+		len = ARRAY_SIZE(qpsk_snr_lut);
+		snr_lut = qpsk_snr_lut;
+		break;
+	case 1:
+		len = ARRAY_SIZE(qam16_snr_lut);
+		snr_lut = qam16_snr_lut;
+		break;
+	case 2:
+		len = ARRAY_SIZE(qam64_snr_lut);
+		snr_lut = qam64_snr_lut;
+		break;
+	default:
+		goto err;
+	}
+
+	for (i = 0; i < len; i++) {
+		tmp = snr_lut[i].snr;
+
+		if (snr_val < snr_lut[i].val)
+			break;
+	}
+
+	*snr = tmp * 10; /* dB/10 */
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+	u8 strength2;
+
+	/* read signal strength of 0-100 scale */
+	ret = af9033_rd_reg(state, 0x800048, &strength2);
+	if (ret < 0)
+		goto err;
+
+	/* scale value to 0x0000-0xffff */
+	*strength = strength2 * 0xffff / 100;
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_update_ch_stat(struct af9033_state *state)
+{
+	int ret = 0;
+	u32 err_cnt, bit_cnt;
+	u16 abort_cnt;
+	u8 buf[7];
+
+	/* only update data every half second */
+	if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) {
+		ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf));
+		if (ret < 0)
+			goto err;
+		/* in 8 byte packets? */
+		abort_cnt = (buf[1] << 8) + buf[0];
+		/* in bits */
+		err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2];
+		/* in 8 byte packets? always(?) 0x2710 = 10000 */
+		bit_cnt = (buf[6] << 8) + buf[5];
+
+		if (bit_cnt < abort_cnt) {
+			abort_cnt = 1000;
+			state->ber = 0xffffffff;
+		} else {
+			/* 8 byte packets, that have not been rejected already */
+			bit_cnt -= (u32)abort_cnt;
+			if (bit_cnt == 0) {
+				state->ber = 0xffffffff;
+			} else {
+				err_cnt -= (u32)abort_cnt * 8 * 8;
+				bit_cnt *= 8 * 8;
+				state->ber = err_cnt * (0xffffffff / bit_cnt);
+			}
+		}
+		state->ucb += abort_cnt;
+		state->last_stat_check = jiffies;
+	}
+
+	return 0;
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+
+	ret = af9033_update_ch_stat(state);
+	if (ret < 0)
+		return ret;
+
+	*ber = state->ber;
+
+	return 0;
+}
+
+static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+
+	ret = af9033_update_ch_stat(state);
+	if (ret < 0)
+		return ret;
+
+	*ucblocks = state->ucb;
+
+	return 0;
+}
+
+static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+
+	pr_debug("%s: enable=%d\n", __func__, enable);
+
+	ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static struct dvb_frontend_ops af9033_ops;
+
+struct dvb_frontend *af9033_attach(const struct af9033_config *config,
+		struct i2c_adapter *i2c)
+{
+	int ret;
+	struct af9033_state *state;
+	u8 buf[8];
+
+	pr_debug("%s:\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL);
+	if (state == NULL)
+		goto err;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->cfg, config, sizeof(struct af9033_config));
+
+	if (state->cfg.clock != 12000000) {
+		printk(KERN_INFO "af9033: unsupported clock=%d, only " \
+				"12000000 Hz is supported currently\n",
+				state->cfg.clock);
+		goto err;
+	}
+
+	/* firmware version */
+	ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_rd_regs(state, 0x804191, &buf[4], 4);
+	if (ret < 0)
+		goto err;
+
+	printk(KERN_INFO "af9033: firmware version: LINK=%d.%d.%d.%d " \
+			"OFDM=%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3],
+			buf[4], buf[5], buf[6], buf[7]);
+
+	/* configure internal TS mode */
+	switch (state->cfg.ts_mode) {
+	case AF9033_TS_MODE_PARALLEL:
+		state->ts_mode_parallel = true;
+		break;
+	case AF9033_TS_MODE_SERIAL:
+		state->ts_mode_serial = true;
+		break;
+	case AF9033_TS_MODE_USB:
+		/* usb mode for AF9035 */
+	default:
+		break;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
+	state->fe.demodulator_priv = state;
+
+	return &state->fe;
+
+err:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(af9033_attach);
+
+static struct dvb_frontend_ops af9033_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Afatech AF9033 (DVB-T)",
+		.frequency_min = 174000000,
+		.frequency_max = 862000000,
+		.frequency_stepsize = 250000,
+		.frequency_tolerance = 0,
+		.caps =	FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = af9033_release,
+
+	.init = af9033_init,
+	.sleep = af9033_sleep,
+
+	.get_tune_settings = af9033_get_tune_settings,
+	.set_frontend = af9033_set_frontend,
+	.get_frontend = af9033_get_frontend,
+
+	.read_status = af9033_read_status,
+	.read_snr = af9033_read_snr,
+	.read_signal_strength = af9033_read_signal_strength,
+	.read_ber = af9033_read_ber,
+	.read_ucblocks = af9033_read_ucblocks,
+
+	.i2c_gate_ctrl = af9033_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/af9033.h b/drivers/media/dvb/frontends/af9033.h
new file mode 100644
index 0000000..9e302c3
--- /dev/null
+++ b/drivers/media/dvb/frontends/af9033.h
@@ -0,0 +1,75 @@
+/*
+ * Afatech AF9033 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AF9033_H
+#define AF9033_H
+
+struct af9033_config {
+	/*
+	 * I2C address
+	 */
+	u8 i2c_addr;
+
+	/*
+	 * clock Hz
+	 * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000,
+	 * 30000000, 36000000, 20480000, 16384000
+	 */
+	u32 clock;
+
+	/*
+	 * tuner
+	 */
+#define AF9033_TUNER_TUA9001     0x27 /* Infineon TUA 9001 */
+#define AF9033_TUNER_FC0011      0x28 /* Fitipower FC0011 */
+#define AF9033_TUNER_MXL5007T    0xa0 /* MaxLinear MxL5007T */
+#define AF9033_TUNER_TDA18218    0xa1 /* NXP TDA 18218HN */
+	u8 tuner;
+
+	/*
+	 * TS settings
+	 */
+#define AF9033_TS_MODE_USB       0
+#define AF9033_TS_MODE_PARALLEL  1
+#define AF9033_TS_MODE_SERIAL    2
+	u8 ts_mode:2;
+
+	/*
+	 * input spectrum inversion
+	 */
+	bool spec_inv;
+};
+
+
+#if defined(CONFIG_DVB_AF9033) || \
+	(defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE))
+extern struct dvb_frontend *af9033_attach(const struct af9033_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *af9033_attach(
+	const struct af9033_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* AF9033_H */
diff --git a/drivers/media/dvb/frontends/af9033_priv.h b/drivers/media/dvb/frontends/af9033_priv.h
new file mode 100644
index 0000000..0b783b9
--- /dev/null
+++ b/drivers/media/dvb/frontends/af9033_priv.h
@@ -0,0 +1,470 @@
+/*
+ * Afatech AF9033 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AF9033_PRIV_H
+#define AF9033_PRIV_H
+
+#include "dvb_frontend.h"
+#include "af9033.h"
+
+struct reg_val {
+	u32 reg;
+	u8  val;
+};
+
+struct reg_val_mask {
+	u32 reg;
+	u8  val;
+	u8  mask;
+};
+
+struct coeff {
+	u32 clock;
+	u32 bandwidth_hz;
+	u8 val[36];
+};
+
+struct clock_adc {
+	u32 clock;
+	u32 adc;
+};
+
+struct val_snr {
+	u32 val;
+	u8 snr;
+};
+
+/* Xtal clock vs. ADC clock lookup table */
+static const struct clock_adc clock_adc_lut[] = {
+	{ 16384000, 20480000 },
+	{ 20480000, 20480000 },
+	{ 36000000, 20250000 },
+	{ 30000000, 20156250 },
+	{ 26000000, 20583333 },
+	{ 28000000, 20416667 },
+	{ 32000000, 20500000 },
+	{ 34000000, 20187500 },
+	{ 24000000, 20500000 },
+	{ 22000000, 20625000 },
+	{ 12000000, 20250000 },
+};
+
+/* pre-calculated coeff lookup table */
+static const struct coeff coeff_lut[] = {
+	/* 12.000 MHz */
+	{ 12000000, 8000000, {
+		0x01, 0xce, 0x55, 0xc9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73,
+		0x99, 0x0f, 0x00, 0x73, 0x95, 0x72, 0x00, 0x73, 0x91, 0xd5,
+		0x00, 0x39, 0xca, 0xb9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73,
+		0x95, 0x72, 0x37, 0x02, 0xce, 0x01 }
+	},
+	{ 12000000, 7000000, {
+		0x01, 0x94, 0x8b, 0x10, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65,
+		0x25, 0xed, 0x00, 0x65, 0x22, 0xc4, 0x00, 0x65, 0x1f, 0x9b,
+		0x00, 0x32, 0x91, 0x62, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65,
+		0x22, 0xc4, 0x88, 0x02, 0x95, 0x01 }
+	},
+	{ 12000000, 6000000, {
+		0x01, 0x5a, 0xc0, 0x56, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56,
+		0xb2, 0xcb, 0x00, 0x56, 0xb0, 0x15, 0x00, 0x56, 0xad, 0x60,
+		0x00, 0x2b, 0x58, 0x0b, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56,
+		0xb0, 0x15, 0xf4, 0x02, 0x5b, 0x01 }
+	},
+};
+
+/* QPSK SNR lookup table */
+static const struct val_snr qpsk_snr_lut[] = {
+	{ 0x0b4771,  0 },
+	{ 0x0c1aed,  1 },
+	{ 0x0d0d27,  2 },
+	{ 0x0e4d19,  3 },
+	{ 0x0e5da8,  4 },
+	{ 0x107097,  5 },
+	{ 0x116975,  6 },
+	{ 0x1252d9,  7 },
+	{ 0x131fa4,  8 },
+	{ 0x13d5e1,  9 },
+	{ 0x148e53, 10 },
+	{ 0x15358b, 11 },
+	{ 0x15dd29, 12 },
+	{ 0x168112, 13 },
+	{ 0x170b61, 14 },
+	{ 0x17a532, 15 },
+	{ 0x180f94, 16 },
+	{ 0x186ed2, 17 },
+	{ 0x18b271, 18 },
+	{ 0x18e118, 19 },
+	{ 0x18ff4b, 20 },
+	{ 0x190af1, 21 },
+	{ 0x191451, 22 },
+	{ 0xffffff, 23 },
+};
+
+/* QAM16 SNR lookup table */
+static const struct val_snr qam16_snr_lut[] = {
+	{ 0x04f0d5,  0 },
+	{ 0x05387a,  1 },
+	{ 0x0573a4,  2 },
+	{ 0x05a99e,  3 },
+	{ 0x05cc80,  4 },
+	{ 0x05eb62,  5 },
+	{ 0x05fecf,  6 },
+	{ 0x060b80,  7 },
+	{ 0x062501,  8 },
+	{ 0x064865,  9 },
+	{ 0x069604, 10 },
+	{ 0x06f356, 11 },
+	{ 0x07706a, 12 },
+	{ 0x0804d3, 13 },
+	{ 0x089d1a, 14 },
+	{ 0x093e3d, 15 },
+	{ 0x09e35d, 16 },
+	{ 0x0a7c3c, 17 },
+	{ 0x0afaf8, 18 },
+	{ 0x0b719d, 19 },
+	{ 0x0bda6a, 20 },
+	{ 0x0c0c75, 21 },
+	{ 0x0c3f7d, 22 },
+	{ 0x0c5e62, 23 },
+	{ 0x0c6c31, 24 },
+	{ 0x0c7925, 25 },
+	{ 0xffffff, 26 },
+};
+
+/* QAM64 SNR lookup table */
+static const struct val_snr qam64_snr_lut[] = {
+	{ 0x0256d0,  0 },
+	{ 0x027a65,  1 },
+	{ 0x029873,  2 },
+	{ 0x02b7fe,  3 },
+	{ 0x02cf1e,  4 },
+	{ 0x02e234,  5 },
+	{ 0x02f409,  6 },
+	{ 0x030046,  7 },
+	{ 0x030844,  8 },
+	{ 0x030a02,  9 },
+	{ 0x030cde, 10 },
+	{ 0x031031, 11 },
+	{ 0x03144c, 12 },
+	{ 0x0315dd, 13 },
+	{ 0x031920, 14 },
+	{ 0x0322d0, 15 },
+	{ 0x0339fc, 16 },
+	{ 0x0364a1, 17 },
+	{ 0x038bcc, 18 },
+	{ 0x03c7d3, 19 },
+	{ 0x0408cc, 20 },
+	{ 0x043bed, 21 },
+	{ 0x048061, 22 },
+	{ 0x04be95, 23 },
+	{ 0x04fa7d, 24 },
+	{ 0x052405, 25 },
+	{ 0x05570d, 26 },
+	{ 0x059feb, 27 },
+	{ 0x05bf38, 28 },
+	{ 0xffffff, 29 },
+};
+
+static const struct reg_val ofsm_init[] = {
+	{ 0x800051, 0x01 },
+	{ 0x800070, 0x0a },
+	{ 0x80007e, 0x04 },
+	{ 0x800081, 0x0a },
+	{ 0x80008a, 0x01 },
+	{ 0x80008e, 0x01 },
+	{ 0x800092, 0x06 },
+	{ 0x800099, 0x01 },
+	{ 0x80009f, 0xe1 },
+	{ 0x8000a0, 0xcf },
+	{ 0x8000a3, 0x01 },
+	{ 0x8000a5, 0x01 },
+	{ 0x8000a6, 0x01 },
+	{ 0x8000a9, 0x00 },
+	{ 0x8000aa, 0x01 },
+	{ 0x8000ab, 0x01 },
+	{ 0x8000b0, 0x01 },
+	{ 0x8000c0, 0x05 },
+	{ 0x8000c4, 0x19 },
+	{ 0x80f000, 0x0f },
+	{ 0x80f016, 0x10 },
+	{ 0x80f017, 0x04 },
+	{ 0x80f018, 0x05 },
+	{ 0x80f019, 0x04 },
+	{ 0x80f01a, 0x05 },
+	{ 0x80f021, 0x03 },
+	{ 0x80f022, 0x0a },
+	{ 0x80f023, 0x0a },
+	{ 0x80f02b, 0x00 },
+	{ 0x80f02c, 0x01 },
+	{ 0x80f064, 0x03 },
+	{ 0x80f065, 0xf9 },
+	{ 0x80f066, 0x03 },
+	{ 0x80f067, 0x01 },
+	{ 0x80f06f, 0xe0 },
+	{ 0x80f070, 0x03 },
+	{ 0x80f072, 0x0f },
+	{ 0x80f073, 0x03 },
+	{ 0x80f078, 0x00 },
+	{ 0x80f087, 0x00 },
+	{ 0x80f09b, 0x3f },
+	{ 0x80f09c, 0x00 },
+	{ 0x80f09d, 0x20 },
+	{ 0x80f09e, 0x00 },
+	{ 0x80f09f, 0x0c },
+	{ 0x80f0a0, 0x00 },
+	{ 0x80f130, 0x04 },
+	{ 0x80f132, 0x04 },
+	{ 0x80f144, 0x1a },
+	{ 0x80f146, 0x00 },
+	{ 0x80f14a, 0x01 },
+	{ 0x80f14c, 0x00 },
+	{ 0x80f14d, 0x00 },
+	{ 0x80f14f, 0x04 },
+	{ 0x80f158, 0x7f },
+	{ 0x80f15a, 0x00 },
+	{ 0x80f15b, 0x08 },
+	{ 0x80f15d, 0x03 },
+	{ 0x80f15e, 0x05 },
+	{ 0x80f163, 0x05 },
+	{ 0x80f166, 0x01 },
+	{ 0x80f167, 0x40 },
+	{ 0x80f168, 0x0f },
+	{ 0x80f17a, 0x00 },
+	{ 0x80f17b, 0x00 },
+	{ 0x80f183, 0x01 },
+	{ 0x80f19d, 0x40 },
+	{ 0x80f1bc, 0x36 },
+	{ 0x80f1bd, 0x00 },
+	{ 0x80f1cb, 0xa0 },
+	{ 0x80f1cc, 0x01 },
+	{ 0x80f204, 0x10 },
+	{ 0x80f214, 0x00 },
+	{ 0x80f40e, 0x0a },
+	{ 0x80f40f, 0x40 },
+	{ 0x80f410, 0x08 },
+	{ 0x80f55f, 0x0a },
+	{ 0x80f561, 0x15 },
+	{ 0x80f562, 0x20 },
+	{ 0x80f5df, 0xfb },
+	{ 0x80f5e0, 0x00 },
+	{ 0x80f5e3, 0x09 },
+	{ 0x80f5e4, 0x01 },
+	{ 0x80f5e5, 0x01 },
+	{ 0x80f5f8, 0x01 },
+	{ 0x80f5fd, 0x01 },
+	{ 0x80f600, 0x05 },
+	{ 0x80f601, 0x08 },
+	{ 0x80f602, 0x0b },
+	{ 0x80f603, 0x0e },
+	{ 0x80f604, 0x11 },
+	{ 0x80f605, 0x14 },
+	{ 0x80f606, 0x17 },
+	{ 0x80f607, 0x1f },
+	{ 0x80f60e, 0x00 },
+	{ 0x80f60f, 0x04 },
+	{ 0x80f610, 0x32 },
+	{ 0x80f611, 0x10 },
+	{ 0x80f707, 0xfc },
+	{ 0x80f708, 0x00 },
+	{ 0x80f709, 0x37 },
+	{ 0x80f70a, 0x00 },
+	{ 0x80f78b, 0x01 },
+	{ 0x80f80f, 0x40 },
+	{ 0x80f810, 0x54 },
+	{ 0x80f811, 0x5a },
+	{ 0x80f905, 0x01 },
+	{ 0x80fb06, 0x03 },
+	{ 0x80fd8b, 0x00 },
+};
+
+/* Infineon TUA 9001 tuner init
+   AF9033_TUNER_TUA9001    = 0x27 */
+static const struct reg_val tuner_init_tua9001[] = {
+	{ 0x800046, 0x27 },
+	{ 0x800057, 0x00 },
+	{ 0x800058, 0x01 },
+	{ 0x80005f, 0x00 },
+	{ 0x800060, 0x00 },
+	{ 0x80006d, 0x00 },
+	{ 0x800071, 0x05 },
+	{ 0x800072, 0x02 },
+	{ 0x800074, 0x01 },
+	{ 0x800075, 0x03 },
+	{ 0x800076, 0x02 },
+	{ 0x800077, 0x00 },
+	{ 0x800078, 0x01 },
+	{ 0x800079, 0x00 },
+	{ 0x80007a, 0x7e },
+	{ 0x80007b, 0x3e },
+	{ 0x800093, 0x00 },
+	{ 0x800094, 0x01 },
+	{ 0x800095, 0x02 },
+	{ 0x800096, 0x01 },
+	{ 0x800098, 0x0a },
+	{ 0x80009b, 0x05 },
+	{ 0x80009c, 0x80 },
+	{ 0x8000b3, 0x00 },
+	{ 0x8000c1, 0x01 },
+	{ 0x8000c2, 0x00 },
+	{ 0x80f007, 0x00 },
+	{ 0x80f01f, 0x82 },
+	{ 0x80f020, 0x00 },
+	{ 0x80f029, 0x82 },
+	{ 0x80f02a, 0x00 },
+	{ 0x80f047, 0x00 },
+	{ 0x80f054, 0x00 },
+	{ 0x80f055, 0x00 },
+	{ 0x80f077, 0x01 },
+	{ 0x80f1e6, 0x00 },
+};
+
+/* Fitipower fc0011 tuner init
+   AF9033_TUNER_FC0011    = 0x28 */
+static const struct reg_val tuner_init_fc0011[] = {
+	{ 0x800046, AF9033_TUNER_FC0011 },
+	{ 0x800057, 0x00 },
+	{ 0x800058, 0x01 },
+	{ 0x80005f, 0x00 },
+	{ 0x800060, 0x00 },
+	{ 0x800068, 0xa5 },
+	{ 0x80006e, 0x01 },
+	{ 0x800071, 0x0A },
+	{ 0x800072, 0x02 },
+	{ 0x800074, 0x01 },
+	{ 0x800079, 0x01 },
+	{ 0x800093, 0x00 },
+	{ 0x800094, 0x00 },
+	{ 0x800095, 0x00 },
+	{ 0x800096, 0x00 },
+	{ 0x80009b, 0x2D },
+	{ 0x80009c, 0x60 },
+	{ 0x80009d, 0x23 },
+	{ 0x8000a4, 0x50 },
+	{ 0x8000ad, 0x50 },
+	{ 0x8000b3, 0x01 },
+	{ 0x8000b7, 0x88 },
+	{ 0x8000b8, 0xa6 },
+	{ 0x8000c3, 0x01 },
+	{ 0x8000c4, 0x01 },
+	{ 0x8000c7, 0x69 },
+	{ 0x80F007, 0x00 },
+	{ 0x80F00A, 0x1B },
+	{ 0x80F00B, 0x1B },
+	{ 0x80F00C, 0x1B },
+	{ 0x80F00D, 0x1B },
+	{ 0x80F00E, 0xFF },
+	{ 0x80F00F, 0x01 },
+	{ 0x80F010, 0x00 },
+	{ 0x80F011, 0x02 },
+	{ 0x80F012, 0xFF },
+	{ 0x80F013, 0x01 },
+	{ 0x80F014, 0x00 },
+	{ 0x80F015, 0x02 },
+	{ 0x80F01B, 0xEF },
+	{ 0x80F01C, 0x01 },
+	{ 0x80F01D, 0x0f },
+	{ 0x80F01E, 0x02 },
+	{ 0x80F01F, 0x6E },
+	{ 0x80F020, 0x00 },
+	{ 0x80F025, 0xDE },
+	{ 0x80F026, 0x00 },
+	{ 0x80F027, 0x0A },
+	{ 0x80F028, 0x03 },
+	{ 0x80F029, 0x6E },
+	{ 0x80F02A, 0x00 },
+	{ 0x80F047, 0x00 },
+	{ 0x80F054, 0x00 },
+	{ 0x80F055, 0x00 },
+	{ 0x80F077, 0x01 },
+	{ 0x80F1E6, 0x00 },
+};
+
+/* MaxLinear MxL5007T tuner init
+   AF9033_TUNER_MXL5007T    = 0xa0 */
+static const struct reg_val tuner_init_mxl5007t[] = {
+	{ 0x800046, 0x1b },
+	{ 0x800057, 0x01 },
+	{ 0x800058, 0x01 },
+	{ 0x80005f, 0x00 },
+	{ 0x800060, 0x00 },
+	{ 0x800068, 0x96 },
+	{ 0x800071, 0x05 },
+	{ 0x800072, 0x02 },
+	{ 0x800074, 0x01 },
+	{ 0x800079, 0x01 },
+	{ 0x800093, 0x00 },
+	{ 0x800094, 0x00 },
+	{ 0x800095, 0x00 },
+	{ 0x800096, 0x00 },
+	{ 0x8000b3, 0x01 },
+	{ 0x8000c1, 0x01 },
+	{ 0x8000c2, 0x00 },
+	{ 0x80f007, 0x00 },
+	{ 0x80f00c, 0x19 },
+	{ 0x80f00d, 0x1a },
+	{ 0x80f012, 0xda },
+	{ 0x80f013, 0x00 },
+	{ 0x80f014, 0x00 },
+	{ 0x80f015, 0x02 },
+	{ 0x80f01f, 0x82 },
+	{ 0x80f020, 0x00 },
+	{ 0x80f029, 0x82 },
+	{ 0x80f02a, 0x00 },
+	{ 0x80f077, 0x02 },
+	{ 0x80f1e6, 0x00 },
+};
+
+/* NXP TDA 18218HN tuner init
+   AF9033_TUNER_TDA18218    = 0xa1 */
+static const struct reg_val tuner_init_tda18218[] = {
+	{0x800046, 0xa1},
+	{0x800057, 0x01},
+	{0x800058, 0x01},
+	{0x80005f, 0x00},
+	{0x800060, 0x00},
+	{0x800071, 0x05},
+	{0x800072, 0x02},
+	{0x800074, 0x01},
+	{0x800079, 0x01},
+	{0x800093, 0x00},
+	{0x800094, 0x00},
+	{0x800095, 0x00},
+	{0x800096, 0x00},
+	{0x8000b3, 0x01},
+	{0x8000c3, 0x01},
+	{0x8000c4, 0x00},
+	{0x80f007, 0x00},
+	{0x80f00c, 0x19},
+	{0x80f00d, 0x1a},
+	{0x80f012, 0xda},
+	{0x80f013, 0x00},
+	{0x80f014, 0x00},
+	{0x80f015, 0x02},
+	{0x80f01f, 0x82},
+	{0x80f020, 0x00},
+	{0x80f029, 0x82},
+	{0x80f02a, 0x00},
+	{0x80f077, 0x02},
+	{0x80f1e6, 0x00},
+};
+
+#endif /* AF9033_PRIV_H */
+
diff --git a/drivers/media/dvb/frontends/au8522_common.c b/drivers/media/dvb/frontends/au8522_common.c
new file mode 100644
index 0000000..5cfe151
--- /dev/null
+++ b/drivers/media/dvb/frontends/au8522_common.c
@@ -0,0 +1,259 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
+    Copyright (C) 2005-2008 Auvitek International, Ltd.
+    Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "au8522_priv.h"
+
+MODULE_LICENSE("GPL");
+
+static int debug;
+
+#define dprintk(arg...)\
+  do { if (debug)\
+	 printk(arg);\
+  } while (0)
+
+/* Despite the name "hybrid_tuner", the framework works just as well for
+   hybrid demodulators as well... */
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(au8522_list_mutex);
+
+/* 16 bit registers, 8 bit values */
+int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
+
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = 0, .buf = buf, .len = 3 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+		       "ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+EXPORT_SYMBOL(au8522_writereg);
+
+u8 au8522_readreg(struct au8522_state *state, u16 reg)
+{
+	int ret;
+	u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
+	u8 b1[] = { 0 };
+
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+		  .buf = b0, .len = 2 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+		  .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+		       __func__, ret);
+	return b1[0];
+}
+EXPORT_SYMBOL(au8522_readreg);
+
+int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (state->operational_mode == AU8522_ANALOG_MODE) {
+		/* We're being asked to manage the gate even though we're
+		   not in digital mode.  This can occur if we get switched
+		   over to analog mode before the dvb_frontend kernel thread
+		   has completely shutdown */
+		return 0;
+	}
+
+	if (enable)
+		return au8522_writereg(state, 0x106, 1);
+	else
+		return au8522_writereg(state, 0x106, 0);
+}
+EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
+		     u8 client_address)
+{
+	int ret;
+
+	mutex_lock(&au8522_list_mutex);
+	ret = hybrid_tuner_request_state(struct au8522_state, (*state),
+					 hybrid_tuner_instance_list,
+					 i2c, client_address, "au8522");
+	mutex_unlock(&au8522_list_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(au8522_get_state);
+
+void au8522_release_state(struct au8522_state *state)
+{
+	mutex_lock(&au8522_list_mutex);
+	if (state != NULL)
+		hybrid_tuner_release_state(state);
+	mutex_unlock(&au8522_list_mutex);
+}
+EXPORT_SYMBOL(au8522_release_state);
+
+static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
+{
+	struct au8522_led_config *led_config = state->config->led_cfg;
+	u8 val;
+
+	/* bail out if we can't control an LED */
+	if (!led_config || !led_config->gpio_output ||
+	    !led_config->gpio_output_enable || !led_config->gpio_output_disable)
+		return 0;
+
+	val = au8522_readreg(state, 0x4000 |
+			     (led_config->gpio_output & ~0xc000));
+	if (onoff) {
+		/* enable GPIO output */
+		val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
+		val |=  (led_config->gpio_output_enable & 0xff);
+	} else {
+		/* disable GPIO output */
+		val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
+		val |=  (led_config->gpio_output_disable & 0xff);
+	}
+	return au8522_writereg(state, 0x8000 |
+			       (led_config->gpio_output & ~0xc000), val);
+}
+
+/* led = 0 | off
+ * led = 1 | signal ok
+ * led = 2 | signal strong
+ * led < 0 | only light led if leds are currently off
+ */
+int au8522_led_ctrl(struct au8522_state *state, int led)
+{
+	struct au8522_led_config *led_config = state->config->led_cfg;
+	int i, ret = 0;
+
+	/* bail out if we can't control an LED */
+	if (!led_config || !led_config->gpio_leds ||
+	    !led_config->num_led_states || !led_config->led_states)
+		return 0;
+
+	if (led < 0) {
+		/* if LED is already lit, then leave it as-is */
+		if (state->led_state)
+			return 0;
+		else
+			led *= -1;
+	}
+
+	/* toggle LED if changing state */
+	if (state->led_state != led) {
+		u8 val;
+
+		dprintk("%s: %d\n", __func__, led);
+
+		au8522_led_gpio_enable(state, 1);
+
+		val = au8522_readreg(state, 0x4000 |
+				     (led_config->gpio_leds & ~0xc000));
+
+		/* start with all leds off */
+		for (i = 0; i < led_config->num_led_states; i++)
+			val &= ~led_config->led_states[i];
+
+		/* set selected LED state */
+		if (led < led_config->num_led_states)
+			val |= led_config->led_states[led];
+		else if (led_config->num_led_states)
+			val |=
+			led_config->led_states[led_config->num_led_states - 1];
+
+		ret = au8522_writereg(state, 0x8000 |
+				      (led_config->gpio_leds & ~0xc000), val);
+		if (ret < 0)
+			return ret;
+
+		state->led_state = led;
+
+		if (led == 0)
+			au8522_led_gpio_enable(state, 0);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(au8522_led_ctrl);
+
+int au8522_init(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	dprintk("%s()\n", __func__);
+
+	state->operational_mode = AU8522_DIGITAL_MODE;
+
+	/* Clear out any state associated with the digital side of the
+	   chip, so that when it gets powered back up it won't think
+	   that it is already tuned */
+	state->current_frequency = 0;
+
+	au8522_writereg(state, 0xa4, 1 << 5);
+
+	au8522_i2c_gate_ctrl(fe, 1);
+
+	return 0;
+}
+EXPORT_SYMBOL(au8522_init);
+
+int au8522_sleep(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	dprintk("%s()\n", __func__);
+
+	/* Only power down if the digital side is currently using the chip */
+	if (state->operational_mode == AU8522_ANALOG_MODE) {
+		/* We're not in one of the expected power modes, which means
+		   that the DVB thread is probably telling us to go to sleep
+		   even though the analog frontend has already started using
+		   the chip.  So ignore the request */
+		return 0;
+	}
+
+	/* turn off led */
+	au8522_led_ctrl(state, 0);
+
+	/* Power down the chip */
+	au8522_writereg(state, 0xa4, 1 << 5);
+
+	state->current_frequency = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(au8522_sleep);
diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c
index 25f6509..5fc70d6 100644
--- a/drivers/media/dvb/frontends/au8522_dig.c
+++ b/drivers/media/dvb/frontends/au8522_dig.c
@@ -30,74 +30,11 @@
 
 static int debug;
 
-/* Despite the name "hybrid_tuner", the framework works just as well for
-   hybrid demodulators as well... */
-static LIST_HEAD(hybrid_tuner_instance_list);
-static DEFINE_MUTEX(au8522_list_mutex);
-
 #define dprintk(arg...)\
 	do { if (debug)\
 		printk(arg);\
 	} while (0)
 
-/* 16 bit registers, 8 bit values */
-int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
-
-	struct i2c_msg msg = { .addr = state->config->demod_address,
-			       .flags = 0, .buf = buf, .len = 3 };
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
-		       "ret == %i)\n", __func__, reg, data, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-u8 au8522_readreg(struct au8522_state *state, u16 reg)
-{
-	int ret;
-	u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
-	u8 b1[] = { 0 };
-
-	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address, .flags = 0,
-		  .buf = b0, .len = 2 },
-		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
-		  .buf = b1, .len = 1 } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
-		       __func__, ret);
-	return b1[0];
-}
-
-static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d)\n", __func__, enable);
-
-	if (state->operational_mode == AU8522_ANALOG_MODE) {
-		/* We're being asked to manage the gate even though we're
-		   not in digital mode.  This can occur if we get switched
-		   over to analog mode before the dvb_frontend kernel thread
-		   has completely shutdown */
-		return 0;
-	}
-
-	if (enable)
-		return au8522_writereg(state, 0x106, 1);
-	else
-		return au8522_writereg(state, 0x106, 0);
-}
-
 struct mse2snr_tab {
 	u16 val;
 	u16 data;
@@ -609,136 +546,6 @@
 	return 0;
 }
 
-/* Reset the demod hardware and reset all of the configuration registers
-   to a default state. */
-int au8522_init(struct dvb_frontend *fe)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-	dprintk("%s()\n", __func__);
-
-	state->operational_mode = AU8522_DIGITAL_MODE;
-
-	/* Clear out any state associated with the digital side of the
-	   chip, so that when it gets powered back up it won't think
-	   that it is already tuned */
-	state->current_frequency = 0;
-
-	au8522_writereg(state, 0xa4, 1 << 5);
-
-	au8522_i2c_gate_ctrl(fe, 1);
-
-	return 0;
-}
-
-static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
-{
-	struct au8522_led_config *led_config = state->config->led_cfg;
-	u8 val;
-
-	/* bail out if we can't control an LED */
-	if (!led_config || !led_config->gpio_output ||
-	    !led_config->gpio_output_enable || !led_config->gpio_output_disable)
-		return 0;
-
-	val = au8522_readreg(state, 0x4000 |
-			     (led_config->gpio_output & ~0xc000));
-	if (onoff) {
-		/* enable GPIO output */
-		val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
-		val |=  (led_config->gpio_output_enable & 0xff);
-	} else {
-		/* disable GPIO output */
-		val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
-		val |=  (led_config->gpio_output_disable & 0xff);
-	}
-	return au8522_writereg(state, 0x8000 |
-			       (led_config->gpio_output & ~0xc000), val);
-}
-
-/* led = 0 | off
- * led = 1 | signal ok
- * led = 2 | signal strong
- * led < 0 | only light led if leds are currently off
- */
-static int au8522_led_ctrl(struct au8522_state *state, int led)
-{
-	struct au8522_led_config *led_config = state->config->led_cfg;
-	int i, ret = 0;
-
-	/* bail out if we can't control an LED */
-	if (!led_config || !led_config->gpio_leds ||
-	    !led_config->num_led_states || !led_config->led_states)
-		return 0;
-
-	if (led < 0) {
-		/* if LED is already lit, then leave it as-is */
-		if (state->led_state)
-			return 0;
-		else
-			led *= -1;
-	}
-
-	/* toggle LED if changing state */
-	if (state->led_state != led) {
-		u8 val;
-
-		dprintk("%s: %d\n", __func__, led);
-
-		au8522_led_gpio_enable(state, 1);
-
-		val = au8522_readreg(state, 0x4000 |
-				     (led_config->gpio_leds & ~0xc000));
-
-		/* start with all leds off */
-		for (i = 0; i < led_config->num_led_states; i++)
-			val &= ~led_config->led_states[i];
-
-		/* set selected LED state */
-		if (led < led_config->num_led_states)
-			val |= led_config->led_states[led];
-		else if (led_config->num_led_states)
-			val |=
-			led_config->led_states[led_config->num_led_states - 1];
-
-		ret = au8522_writereg(state, 0x8000 |
-				      (led_config->gpio_leds & ~0xc000), val);
-		if (ret < 0)
-			return ret;
-
-		state->led_state = led;
-
-		if (led == 0)
-			au8522_led_gpio_enable(state, 0);
-	}
-
-	return 0;
-}
-
-int au8522_sleep(struct dvb_frontend *fe)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-	dprintk("%s()\n", __func__);
-
-	/* Only power down if the digital side is currently using the chip */
-	if (state->operational_mode == AU8522_ANALOG_MODE) {
-		/* We're not in one of the expected power modes, which means
-		   that the DVB thread is probably telling us to go to sleep
-		   even though the analog frontend has already started using
-		   the chip.  So ignore the request */
-		return 0;
-	}
-
-	/* turn off led */
-	au8522_led_ctrl(state, 0);
-
-	/* Power down the chip */
-	au8522_writereg(state, 0xa4, 1 << 5);
-
-	state->current_frequency = 0;
-
-	return 0;
-}
-
 static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
 	struct au8522_state *state = fe->demodulator_priv;
@@ -931,28 +738,6 @@
 
 static struct dvb_frontend_ops au8522_ops;
 
-int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
-		     u8 client_address)
-{
-	int ret;
-
-	mutex_lock(&au8522_list_mutex);
-	ret = hybrid_tuner_request_state(struct au8522_state, (*state),
-					 hybrid_tuner_instance_list,
-					 i2c, client_address, "au8522");
-	mutex_unlock(&au8522_list_mutex);
-
-	return ret;
-}
-
-void au8522_release_state(struct au8522_state *state)
-{
-	mutex_lock(&au8522_list_mutex);
-	if (state != NULL)
-		hybrid_tuner_release_state(state);
-	mutex_unlock(&au8522_list_mutex);
-}
-
 
 static void au8522_release(struct dvb_frontend *fe)
 {
diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
index 751e17d..6e4a438 100644
--- a/drivers/media/dvb/frontends/au8522_priv.h
+++ b/drivers/media/dvb/frontends/au8522_priv.h
@@ -81,6 +81,8 @@
 int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
 		     u8 client_address);
 void au8522_release_state(struct au8522_state *state);
+int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+int au8522_led_ctrl(struct au8522_state *state, int led);
 
 /* REGISTERS */
 #define AU8522_INPUT_CONTROL_REG081H			0x081
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 5101f10..98ecaf0 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -512,14 +512,13 @@
 static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
 	struct cx24110_state *state = fe->demodulator_priv;
-	u32 lastbyer;
 
 	if(cx24110_readreg(state,0x10)&0x40) {
 		/* the RS error counter has finished one counting window */
 		cx24110_writereg(state,0x10,0x60); /* select the byer reg */
-		lastbyer=cx24110_readreg(state,0x12)|
-			(cx24110_readreg(state,0x13)<<8)|
-			(cx24110_readreg(state,0x14)<<16);
+		cx24110_readreg(state, 0x12) |
+			(cx24110_readreg(state, 0x13) << 8) |
+			(cx24110_readreg(state, 0x14) << 16);
 		cx24110_writereg(state,0x10,0x70); /* select the bler reg */
 		state->lastbler=cx24110_readreg(state,0x12)|
 			(cx24110_readreg(state,0x13)<<8)|
diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c
index 5c7c2aa..3bba37d 100644
--- a/drivers/media/dvb/frontends/cxd2820r_core.c
+++ b/drivers/media/dvb/frontends/cxd2820r_core.c
@@ -526,12 +526,12 @@
 		if (ret)
 			goto error;
 
-		if (status & FE_HAS_SIGNAL)
+		if (status & FE_HAS_LOCK)
 			break;
 	}
 
 	/* check if we have a valid signal */
-	if (status) {
+	if (status & FE_HAS_LOCK) {
 		priv->last_tune_failed = 0;
 		return DVBFE_ALGO_SEARCH_SUCCESS;
 	} else {
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 5ceadc2..3e1eefa 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -2396,11 +2396,6 @@
 	   more common) */
 	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
 
-	/* FIXME: make sure the dev.parent field is initialized, or else
-	   request_firmware() will hit an OOPS (this should be moved somewhere
-	   more common) */
-	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
-
 	dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
 
 	/* init 7090 tuner adapter */
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c
index 80848b4..6201c59 100644
--- a/drivers/media/dvb/frontends/dib9000.c
+++ b/drivers/media/dvb/frontends/dib9000.c
@@ -31,13 +31,6 @@
 	u8 *i2c_write_buffer;
 };
 
-/* lock */
-#define DIB_LOCK struct mutex
-#define DibAcquireLock(lock) mutex_lock_interruptible(lock)
-#define DibReleaseLock(lock) mutex_unlock(lock)
-#define DibInitLock(lock) mutex_init(lock)
-#define DibFreeLock(lock)
-
 struct dib9000_pid_ctrl {
 #define DIB9000_PID_FILTER_CTRL 0
 #define DIB9000_PID_FILTER      1
@@ -82,11 +75,11 @@
 			} fe_mm[18];
 			u8 memcmd;
 
-			DIB_LOCK mbx_if_lock;	/* to protect read/write operations */
-			DIB_LOCK mbx_lock;	/* to protect the whole mailbox handling */
+			struct mutex mbx_if_lock;	/* to protect read/write operations */
+			struct mutex mbx_lock;	/* to protect the whole mailbox handling */
 
-			DIB_LOCK mem_lock;	/* to protect the memory accesses */
-			DIB_LOCK mem_mbx_lock;	/* to protect the memory-based mailbox */
+			struct mutex mem_lock;	/* to protect the memory accesses */
+			struct mutex mem_mbx_lock;	/* to protect the memory-based mailbox */
 
 #define MBX_MAX_WORDS (256 - 200 - 2)
 #define DIB9000_MSG_CACHE_SIZE 2
@@ -108,7 +101,7 @@
 	struct i2c_msg msg[2];
 	u8 i2c_write_buffer[255];
 	u8 i2c_read_buffer[255];
-	DIB_LOCK demod_lock;
+	struct mutex demod_lock;
 	u8 get_frontend_internal;
 	struct dib9000_pid_ctrl pid_ctrl[10];
 	s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
@@ -446,13 +439,13 @@
 	if (!state->platform.risc.fw_is_running)
 		return -EIO;
 
-	if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
 	dib9000_risc_mem_setup(state, cmd | 0x80);
 	dib9000_risc_mem_read_chunks(state, b, len);
-	DibReleaseLock(&state->platform.risc.mem_lock);
+	mutex_unlock(&state->platform.risc.mem_lock);
 	return 0;
 }
 
@@ -462,13 +455,13 @@
 	if (!state->platform.risc.fw_is_running)
 		return -EIO;
 
-	if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
 	dib9000_risc_mem_setup(state, cmd);
 	dib9000_risc_mem_write_chunks(state, b, m->size);
-	DibReleaseLock(&state->platform.risc.mem_lock);
+	mutex_unlock(&state->platform.risc.mem_lock);
 	return 0;
 }
 
@@ -537,7 +530,7 @@
 	if (!state->platform.risc.fw_is_running)
 		return -EINVAL;
 
-	if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
@@ -584,7 +577,7 @@
 	ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr);
 
 out:
-	DibReleaseLock(&state->platform.risc.mbx_if_lock);
+	mutex_unlock(&state->platform.risc.mbx_if_lock);
 
 	return ret;
 }
@@ -602,7 +595,7 @@
 	if (!state->platform.risc.fw_is_running)
 		return 0;
 
-	if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
 		dprintk("could not get the lock");
 		return 0;
 	}
@@ -643,7 +636,7 @@
 	/* Update register nb_mes_in_TX */
 	dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr);
 
-	DibReleaseLock(&state->platform.risc.mbx_if_lock);
+	mutex_unlock(&state->platform.risc.mbx_if_lock);
 
 	return size + 1;
 }
@@ -708,12 +701,11 @@
 static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
 {
 	int ret = 0;
-	u16 tmp;
 
 	if (!state->platform.risc.fw_is_running)
 		return -1;
 
-	if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) {
 		dprintk("could not get the lock");
 		return -1;
 	}
@@ -721,10 +713,10 @@
 	if (dib9000_mbx_count(state, 1, attr))	/* 1=RiscB */
 		ret = dib9000_mbx_fetch_to_cache(state, attr);
 
-	tmp = dib9000_read_word_attr(state, 1229, attr);	/* Clear the IRQ */
+	dib9000_read_word_attr(state, 1229, attr);	/* Clear the IRQ */
 /*      if (tmp) */
 /*              dprintk( "cleared IRQ: %x", tmp); */
-	DibReleaseLock(&state->platform.risc.mbx_lock);
+	mutex_unlock(&state->platform.risc.mbx_lock);
 
 	return ret;
 }
@@ -1193,7 +1185,7 @@
 	struct dibDVBTChannel *ch;
 	int ret = 0;
 
-	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
@@ -1323,7 +1315,7 @@
 	}
 
 error:
-	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
 	return ret;
 }
 
@@ -1678,7 +1670,7 @@
 		p[12] = 0;
 	}
 
-	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
 		dprintk("could not get the lock");
 		return 0;
 	}
@@ -1692,7 +1684,7 @@
 
 	/* do the transaction */
 	if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) {
-		DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
 		return 0;
 	}
 
@@ -1700,7 +1692,7 @@
 	if ((num > 1) && (msg[1].flags & I2C_M_RD))
 		dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len);
 
-	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
 
 	return num;
 }
@@ -1789,7 +1781,7 @@
 		return 0;
 	}
 
-	if (DibAcquireLock(&state->demod_lock) < 0) {
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
@@ -1799,7 +1791,7 @@
 
 	dprintk("PID filter enabled %d", onoff);
 	ret = dib9000_write_word(state, 294 + 1, val);
-	DibReleaseLock(&state->demod_lock);
+	mutex_unlock(&state->demod_lock);
 	return ret;
 
 }
@@ -1824,14 +1816,14 @@
 		return 0;
 	}
 
-	if (DibAcquireLock(&state->demod_lock) < 0) {
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
 	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
 	ret = dib9000_write_word(state, 300 + 1 + id,
 			onoff ? (1 << 13) | pid : 0);
-	DibReleaseLock(&state->demod_lock);
+	mutex_unlock(&state->demod_lock);
 	return ret;
 }
 EXPORT_SYMBOL(dib9000_fw_pid_filter);
@@ -1851,11 +1843,6 @@
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
 		dvb_frontend_detach(st->fe[index_frontend]);
 
-	DibFreeLock(&state->platform.risc.mbx_if_lock);
-	DibFreeLock(&state->platform.risc.mbx_lock);
-	DibFreeLock(&state->platform.risc.mem_lock);
-	DibFreeLock(&state->platform.risc.mem_mbx_lock);
-	DibFreeLock(&state->demod_lock);
 	dibx000_exit_i2c_master(&st->i2c_master);
 
 	i2c_del_adapter(&st->tuner_adap);
@@ -1875,7 +1862,7 @@
 	u8 index_frontend;
 	int ret = 0;
 
-	if (DibAcquireLock(&state->demod_lock) < 0) {
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
@@ -1887,7 +1874,7 @@
 	ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
 
 error:
-	DibReleaseLock(&state->demod_lock);
+	mutex_unlock(&state->demod_lock);
 	return ret;
 }
 
@@ -1905,7 +1892,7 @@
 	int ret = 0;
 
 	if (state->get_frontend_internal == 0) {
-		if (DibAcquireLock(&state->demod_lock) < 0) {
+		if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 			dprintk("could not get the lock");
 			return -EINTR;
 		}
@@ -1964,7 +1951,7 @@
 
 return_value:
 	if (state->get_frontend_internal == 0)
-		DibReleaseLock(&state->demod_lock);
+		mutex_unlock(&state->demod_lock);
 	return ret;
 }
 
@@ -2012,7 +1999,7 @@
 	}
 
 	state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
-	if (DibAcquireLock(&state->demod_lock) < 0) {
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 		dprintk("could not get the lock");
 		return 0;
 	}
@@ -2081,7 +2068,7 @@
 	/* check the tune result */
 	if (exit_condition == 1) {	/* tune failed */
 		dprintk("tune failed");
-		DibReleaseLock(&state->demod_lock);
+		mutex_unlock(&state->demod_lock);
 		/* tune failed; put all the pid filtering cmd to junk */
 		state->pid_ctrl_index = -1;
 		return 0;
@@ -2137,7 +2124,7 @@
 	/* turn off the diversity for the last frontend */
 	dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
 
-	DibReleaseLock(&state->demod_lock);
+	mutex_unlock(&state->demod_lock);
 	if (state->pid_ctrl_index >= 0) {
 		u8 index_pid_filter_cmd;
 		u8 pid_ctrl_index = state->pid_ctrl_index;
@@ -2175,7 +2162,7 @@
 	u8 index_frontend;
 	u16 lock = 0, lock_slave = 0;
 
-	if (DibAcquireLock(&state->demod_lock) < 0) {
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
@@ -2197,7 +2184,7 @@
 	if ((lock & 0x0008) || (lock_slave & 0x0008))
 		*stat |= FE_HAS_LOCK;
 
-	DibReleaseLock(&state->demod_lock);
+	mutex_unlock(&state->demod_lock);
 
 	return 0;
 }
@@ -2208,30 +2195,30 @@
 	u16 *c;
 	int ret = 0;
 
-	if (DibAcquireLock(&state->demod_lock) < 0) {
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
-	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
 		dprintk("could not get the lock");
 		ret = -EINTR;
 		goto error;
 	}
 	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-		DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
 		ret = -EIO;
 		goto error;
 	}
 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
 			state->i2c_read_buffer, 16 * 2);
-	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
 
 	c = (u16 *)state->i2c_read_buffer;
 
 	*ber = c[10] << 16 | c[11];
 
 error:
-	DibReleaseLock(&state->demod_lock);
+	mutex_unlock(&state->demod_lock);
 	return ret;
 }
 
@@ -2243,7 +2230,7 @@
 	u16 val;
 	int ret = 0;
 
-	if (DibAcquireLock(&state->demod_lock) < 0) {
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
@@ -2256,18 +2243,18 @@
 			*strength += val;
 	}
 
-	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
 		dprintk("could not get the lock");
 		ret = -EINTR;
 		goto error;
 	}
 	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-		DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
 		ret = -EIO;
 		goto error;
 	}
 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
-	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
 
 	val = 65535 - c[4];
 	if (val > 65535 - *strength)
@@ -2276,7 +2263,7 @@
 		*strength += val;
 
 error:
-	DibReleaseLock(&state->demod_lock);
+	mutex_unlock(&state->demod_lock);
 	return ret;
 }
 
@@ -2287,16 +2274,16 @@
 	u32 n, s, exp;
 	u16 val;
 
-	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
 		dprintk("could not get the lock");
 		return 0;
 	}
 	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-		DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
 		return 0;
 	}
 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
-	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
 
 	val = c[7];
 	n = (val >> 4) & 0xff;
@@ -2326,7 +2313,7 @@
 	u8 index_frontend;
 	u32 snr_master;
 
-	if (DibAcquireLock(&state->demod_lock) < 0) {
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
@@ -2340,7 +2327,7 @@
 	} else
 		*snr = 0;
 
-	DibReleaseLock(&state->demod_lock);
+	mutex_unlock(&state->demod_lock);
 
 	return 0;
 }
@@ -2351,27 +2338,27 @@
 	u16 *c = (u16 *)state->i2c_read_buffer;
 	int ret = 0;
 
-	if (DibAcquireLock(&state->demod_lock) < 0) {
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
 		dprintk("could not get the lock");
 		return -EINTR;
 	}
-	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
 		dprintk("could not get the lock");
 		ret = -EINTR;
 		goto error;
 	}
 	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-		DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
 		ret = -EIO;
 		goto error;
 	}
 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
-	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
 
 	*unc = c[12];
 
 error:
-	DibReleaseLock(&state->demod_lock);
+	mutex_unlock(&state->demod_lock);
 	return ret;
 }
 
@@ -2514,11 +2501,11 @@
 	st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
 	st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS;
 
-	DibInitLock(&st->platform.risc.mbx_if_lock);
-	DibInitLock(&st->platform.risc.mbx_lock);
-	DibInitLock(&st->platform.risc.mem_lock);
-	DibInitLock(&st->platform.risc.mem_mbx_lock);
-	DibInitLock(&st->demod_lock);
+	mutex_init(&st->platform.risc.mbx_if_lock);
+	mutex_init(&st->platform.risc.mbx_lock);
+	mutex_init(&st->platform.risc.mem_lock);
+	mutex_init(&st->platform.risc.mem_mbx_lock);
+	mutex_init(&st->demod_lock);
 	st->get_frontend_internal = 0;
 
 	st->pid_ctrl_index = -2;
diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h
index 3439873..216c8c3 100644
--- a/drivers/media/dvb/frontends/drxd.h
+++ b/drivers/media/dvb/frontends/drxd.h
@@ -51,9 +51,23 @@
 	 s16(*osc_deviation) (void *priv, s16 dev, int flag);
 };
 
+#if defined(CONFIG_DVB_DRXD) || \
+			(defined(CONFIG_DVB_DRXD_MODULE) && defined(MODULE))
 extern
 struct dvb_frontend *drxd_attach(const struct drxd_config *config,
 				 void *priv, struct i2c_adapter *i2c,
 				 struct device *dev);
+#else
+static inline
+struct dvb_frontend *drxd_attach(const struct drxd_config *config,
+				 void *priv, struct i2c_adapter *i2c,
+				 struct device *dev)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __func__);
+	return NULL;
+}
+#endif
+
 extern int drxd_config_i2c(struct dvb_frontend *, int);
 #endif
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c
index a414b1f..60b868f 100644
--- a/drivers/media/dvb/frontends/drxk_hard.c
+++ b/drivers/media/dvb/frontends/drxk_hard.c
@@ -1380,20 +1380,20 @@
 			     const u8 pMCImage[], u32 Length)
 {
 	const u8 *pSrc = pMCImage;
-	u16 Flags;
-	u16 Drain;
 	u32 Address;
 	u16 nBlocks;
 	u16 BlockSize;
-	u16 BlockCRC;
 	u32 offset = 0;
 	u32 i;
 	int status = 0;
 
 	dprintk(1, "\n");
 
-	/* down the drain (we don care about MAGIC_WORD) */
+	/* down the drain (we don't care about MAGIC_WORD) */
+#if 0
+	/* For future reference */
 	Drain = (pSrc[0] << 8) | pSrc[1];
+#endif
 	pSrc += sizeof(u16);
 	offset += sizeof(u16);
 	nBlocks = (pSrc[0] << 8) | pSrc[1];
@@ -1410,11 +1410,17 @@
 		pSrc += sizeof(u16);
 		offset += sizeof(u16);
 
+#if 0
+		/* For future reference */
 		Flags = (pSrc[0] << 8) | pSrc[1];
+#endif
 		pSrc += sizeof(u16);
 		offset += sizeof(u16);
 
+#if 0
+		/* For future reference */
 		BlockCRC = (pSrc[0] << 8) | pSrc[1];
+#endif
 		pSrc += sizeof(u16);
 		offset += sizeof(u16);
 
@@ -5829,7 +5835,7 @@
 		}
 		if (state->UIO_mask & 0x0002) { /* UIO-2 */
 			/* write to io pad configuration register - output mode */
-			status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+			status = write16(state, SIO_PDR_SMA_RX_CFG__A, state->m_GPIOCfg);
 			if (status < 0)
 				goto error;
 
@@ -5848,7 +5854,7 @@
 		}
 		if (state->UIO_mask & 0x0004) { /* UIO-3 */
 			/* write to io pad configuration register - output mode */
-			status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+			status = write16(state, SIO_PDR_GPIO_CFG__A, state->m_GPIOCfg);
 			if (status < 0)
 				goto error;
 
diff --git a/drivers/media/dvb/frontends/drxk_map.h b/drivers/media/dvb/frontends/drxk_map.h
index 9b11a83..23e16c1 100644
--- a/drivers/media/dvb/frontends/drxk_map.h
+++ b/drivers/media/dvb/frontends/drxk_map.h
@@ -432,6 +432,7 @@
 #define  SIO_PDR_UIO_OUT_LO__A                                             0x7F0016
 #define  SIO_PDR_OHW_CFG__A                                                0x7F001F
 #define    SIO_PDR_OHW_CFG_FREF_SEL__M                                     0x3
+#define  SIO_PDR_GPIO_CFG__A                                               0x7F0021
 #define  SIO_PDR_MSTRT_CFG__A                                              0x7F0025
 #define  SIO_PDR_MERR_CFG__A                                               0x7F0026
 #define  SIO_PDR_MCLK_CFG__A                                               0x7F0028
@@ -446,4 +447,5 @@
 #define  SIO_PDR_MD5_CFG__A                                                0x7F0030
 #define  SIO_PDR_MD6_CFG__A                                                0x7F0031
 #define  SIO_PDR_MD7_CFG__A                                                0x7F0032
+#define  SIO_PDR_SMA_RX_CFG__A                                             0x7F0037
 #define  SIO_PDR_SMA_TX_CFG__A                                             0x7F0038
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c
index af65d01..4c8ac26 100644
--- a/drivers/media/dvb/frontends/ds3000.c
+++ b/drivers/media/dvb/frontends/ds3000.c
@@ -1114,7 +1114,10 @@
 			ds3000_writereg(state,
 				ds3000_dvbs2_init_tab[i],
 				ds3000_dvbs2_init_tab[i + 1]);
-		ds3000_writereg(state, 0xfe, 0x98);
+		if (c->symbol_rate >= 30000000)
+			ds3000_writereg(state, 0xfe, 0x54);
+		else
+			ds3000_writereg(state, 0xfe, 0x98);
 		break;
 	default:
 		return 1;
diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c
index 84df03c..708cbf1 100644
--- a/drivers/media/dvb/frontends/it913x-fe.c
+++ b/drivers/media/dvb/frontends/it913x-fe.c
@@ -633,10 +633,9 @@
 static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
 	struct it913x_fe_state *state = fe->demodulator_priv;
-	int ret;
 	u8 reg[5];
 	/* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */
-	ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
+	it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
 	state->ucblocks += (u32)(reg[1] << 8) | reg[0];
 	*ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2];
 	return 0;
@@ -658,10 +657,9 @@
 {
 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 	struct it913x_fe_state *state = fe->demodulator_priv;
-	int ret;
 	u8 reg[8];
 
-	ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
+	it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
 
 	if (reg[3] < 3)
 		p->modulation = fe_con[reg[3]];
@@ -691,25 +689,25 @@
 {
 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 	struct it913x_fe_state *state = fe->demodulator_priv;
-	int ret, i;
+	int i;
 	u8 empty_ch, last_ch;
 
 	state->it913x_status = 0;
 
 	/* Set bw*/
-	ret = it913x_fe_select_bw(state, p->bandwidth_hz,
+	it913x_fe_select_bw(state, p->bandwidth_hz,
 		state->adcFrequency);
 
 	/* Training Mode Off */
-	ret = it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
+	it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
 
 	/* Clear Empty Channel */
-	ret = it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
+	it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
 
 	/* Clear bits */
-	ret = it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
+	it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
 	/* LED on */
-	ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
+	it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
 	/* Select Band*/
 	if ((p->frequency >= 51000000) && (p->frequency <= 230000000))
 		i = 0;
@@ -720,7 +718,7 @@
 	else
 		return -EOPNOTSUPP;
 
-	ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
+	it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
 
 	deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
 	switch (state->tuner_type) {
@@ -730,7 +728,7 @@
 	case IT9135_60:
 	case IT9135_61:
 	case IT9135_62:
-		ret = it9137_set_tuner(state,
+		it9137_set_tuner(state,
 			p->bandwidth_hz, p->frequency);
 		break;
 	default:
@@ -742,9 +740,9 @@
 		break;
 	}
 	/* LED off */
-	ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
+	it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
 	/* Trigger ofsm */
-	ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
+	it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
 	last_ch = 2;
 	for (i = 0; i < 40; ++i) {
 		empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
diff --git a/drivers/media/dvb/frontends/lg2160.c b/drivers/media/dvb/frontends/lg2160.c
new file mode 100644
index 0000000..a3ab1a5
--- /dev/null
+++ b/drivers/media/dvb/frontends/lg2160.c
@@ -0,0 +1,1468 @@
+/*
+ *    Support for LG2160 - ATSC/MH
+ *
+ *    Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/jiffies.h>
+#include <linux/dvb/frontend.h>
+#include "lg2160.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
+
+#define DBG_INFO 1
+#define DBG_REG  2
+
+#define lg_printk(kern, fmt, arg...)					\
+	printk(kern "%s: " fmt, __func__, ##arg)
+
+#define lg_info(fmt, arg...)	printk(KERN_INFO "lg2160: " fmt, ##arg)
+#define lg_warn(fmt, arg...)	lg_printk(KERN_WARNING,       fmt, ##arg)
+#define lg_err(fmt, arg...)	lg_printk(KERN_ERR,           fmt, ##arg)
+#define lg_dbg(fmt, arg...) if (debug & DBG_INFO)			\
+				lg_printk(KERN_DEBUG,         fmt, ##arg)
+#define lg_reg(fmt, arg...) if (debug & DBG_REG)			\
+				lg_printk(KERN_DEBUG,         fmt, ##arg)
+
+#define lg_fail(ret)							\
+({									\
+	int __ret;							\
+	__ret = (ret < 0);						\
+	if (__ret)							\
+		lg_err("error %d on line %d\n",	ret, __LINE__);		\
+	__ret;								\
+})
+
+struct lg216x_state {
+	struct i2c_adapter *i2c_adap;
+	const struct lg2160_config *cfg;
+
+	struct dvb_frontend frontend;
+
+	u32 current_frequency;
+	u8 parade_id;
+	u8 fic_ver;
+	unsigned int last_reset;
+};
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_write_reg(struct lg216x_state *state, u16 reg, u8 val)
+{
+	int ret;
+	u8 buf[] = { reg >> 8, reg & 0xff, val };
+	struct i2c_msg msg = {
+		.addr = state->cfg->i2c_addr, .flags = 0,
+		.buf = buf, .len = 3,
+	};
+
+	lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
+
+	ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+	if (ret != 1) {
+		lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
+		       msg.buf[0], msg.buf[1], msg.buf[2], ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int lg216x_read_reg(struct lg216x_state *state, u16 reg, u8 *val)
+{
+	int ret;
+	u8 reg_buf[] = { reg >> 8, reg & 0xff };
+	struct i2c_msg msg[] = {
+		{ .addr = state->cfg->i2c_addr,
+		  .flags = 0, .buf = reg_buf, .len = 2 },
+		{ .addr = state->cfg->i2c_addr,
+		  .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	lg_reg("reg: 0x%04x\n", reg);
+
+	ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+	if (ret != 2) {
+		lg_err("error (addr %02x reg %04x error (ret == %i)\n",
+		       state->cfg->i2c_addr, reg, ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EREMOTEIO;
+	}
+	return 0;
+}
+
+struct lg216x_reg {
+	u16 reg;
+	u8 val;
+};
+
+static int lg216x_write_regs(struct lg216x_state *state,
+			     struct lg216x_reg *regs, int len)
+{
+	int i, ret;
+
+	lg_reg("writing %d registers...\n", len);
+
+	for (i = 0; i < len - 1; i++) {
+		ret = lg216x_write_reg(state, regs[i].reg, regs[i].val);
+		if (lg_fail(ret))
+			return ret;
+	}
+	return 0;
+}
+
+static int lg216x_set_reg_bit(struct lg216x_state *state,
+			      u16 reg, int bit, int onoff)
+{
+	u8 val;
+	int ret;
+
+	lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
+
+	ret = lg216x_read_reg(state, reg, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= ~(1 << bit);
+	val |= (onoff & 1) << bit;
+
+	ret = lg216x_write_reg(state, reg, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret;
+
+	if (state->cfg->deny_i2c_rptr)
+		return 0;
+
+	lg_dbg("(%d)\n", enable);
+
+	ret = lg216x_set_reg_bit(state, 0x0000, 0, enable ? 0 : 1);
+
+	msleep(1);
+
+	return ret;
+}
+
+static int lg216x_soft_reset(struct lg216x_state *state)
+{
+	int ret;
+
+	lg_dbg("\n");
+
+	ret = lg216x_write_reg(state, 0x0002, 0x00);
+	if (lg_fail(ret))
+		goto fail;
+
+	msleep(20);
+	ret = lg216x_write_reg(state, 0x0002, 0x01);
+	if (lg_fail(ret))
+		goto fail;
+
+	state->last_reset = jiffies_to_msecs(jiffies);
+fail:
+	return ret;
+}
+
+static int lg216x_initialize(struct lg216x_state *state)
+{
+	int ret;
+
+	static struct lg216x_reg lg2160_init[] = {
+#if 0
+		{ .reg = 0x0015, .val = 0xe6 },
+#else
+		{ .reg = 0x0015, .val = 0xf7 },
+		{ .reg = 0x001b, .val = 0x52 },
+		{ .reg = 0x0208, .val = 0x00 },
+		{ .reg = 0x0209, .val = 0x82 },
+		{ .reg = 0x0210, .val = 0xf9 },
+		{ .reg = 0x020a, .val = 0x00 },
+		{ .reg = 0x020b, .val = 0x82 },
+		{ .reg = 0x020d, .val = 0x28 },
+		{ .reg = 0x020f, .val = 0x14 },
+#endif
+	};
+
+	static struct lg216x_reg lg2161_init[] = {
+		{ .reg = 0x0000, .val = 0x41 },
+		{ .reg = 0x0001, .val = 0xfb },
+		{ .reg = 0x0216, .val = 0x00 },
+		{ .reg = 0x0219, .val = 0x00 },
+		{ .reg = 0x021b, .val = 0x55 },
+		{ .reg = 0x0606, .val = 0x0a },
+	};
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_write_regs(state,
+					lg2160_init, ARRAY_SIZE(lg2160_init));
+		break;
+	case LG2161:
+		ret = lg216x_write_regs(state,
+					lg2161_init, ARRAY_SIZE(lg2161_init));
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_soft_reset(state);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_set_if(struct lg216x_state *state)
+{
+	u8 val;
+	int ret;
+
+	lg_dbg("%d KHz\n", state->cfg->if_khz);
+
+	ret = lg216x_read_reg(state, 0x0132, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfb;
+	val |= (0 == state->cfg->if_khz) ? 0x04 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0132, val);
+	lg_fail(ret);
+
+	/* if NOT zero IF, 6 MHz is the default */
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg2160_agc_fix(struct lg216x_state *state,
+			  int if_agc_fix, int rf_agc_fix)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0100, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xf3;
+	val |= (if_agc_fix) ? 0x08 : 0x00;
+	val |= (rf_agc_fix) ? 0x04 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0100, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+#if 0
+static int lg2160_agc_freeze(struct lg216x_state *state,
+			     int if_agc_freeze, int rf_agc_freeze)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0100, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xcf;
+	val |= (if_agc_freeze) ? 0x20 : 0x00;
+	val |= (rf_agc_freeze) ? 0x10 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0100, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+#endif
+
+static int lg2160_agc_polarity(struct lg216x_state *state,
+			       int if_agc_polarity, int rf_agc_polarity)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0100, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfc;
+	val |= (if_agc_polarity) ? 0x02 : 0x00;
+	val |= (rf_agc_polarity) ? 0x01 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0100, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg2160_tuner_pwr_save_polarity(struct lg216x_state *state,
+					  int polarity)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0008, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfe;
+	val |= (polarity) ? 0x01 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0008, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg2160_spectrum_polarity(struct lg216x_state *state,
+				    int inverted)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0132, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfd;
+	val |= (inverted) ? 0x02 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0132, val);
+	lg_fail(ret);
+fail:
+	return lg216x_soft_reset(state);
+}
+
+static int lg2160_tuner_pwr_save(struct lg216x_state *state, int onoff)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0007, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xbf;
+	val |= (onoff) ? 0x40 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0007, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg216x_set_parade(struct lg216x_state *state, int id)
+{
+	int ret;
+
+	ret = lg216x_write_reg(state, 0x013e, id & 0x7f);
+	if (lg_fail(ret))
+		goto fail;
+
+	state->parade_id = id & 0x7f;
+fail:
+	return ret;
+}
+
+static int lg216x_set_ensemble(struct lg216x_state *state, int id)
+{
+	int ret;
+	u16 reg;
+	u8 val;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		reg = 0x0400;
+		break;
+	case LG2161:
+	default:
+		reg = 0x0500;
+		break;
+	}
+
+	ret = lg216x_read_reg(state, reg, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfe;
+	val |= (id) ? 0x01 : 0x00;
+
+	ret = lg216x_write_reg(state, reg, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg2160_set_spi_clock(struct lg216x_state *state)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0014, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xf3;
+	val |= (state->cfg->spi_clock << 2);
+
+	ret = lg216x_write_reg(state, 0x0014, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg2161_set_output_interface(struct lg216x_state *state)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0014, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= ~0x07;
+	val |= state->cfg->output_if; /* FIXME: needs sanity check */
+
+	ret = lg216x_write_reg(state, 0x0014, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg216x_enable_fic(struct lg216x_state *state, int onoff)
+{
+	int ret;
+
+	ret = lg216x_write_reg(state, 0x0017, 0x23);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_write_reg(state, 0x0016, 0xfc);
+	if (lg_fail(ret))
+		goto fail;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_write_reg(state, 0x0016,
+				       0xfc | ((onoff) ? 0x02 : 0x00));
+		break;
+	case LG2161:
+		ret = lg216x_write_reg(state, 0x0016, (onoff) ? 0x10 : 0x00);
+		break;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_initialize(state);
+	if (lg_fail(ret))
+		goto fail;
+
+	if (onoff) {
+		ret = lg216x_write_reg(state, 0x0017, 0x03);
+		lg_fail(ret);
+	}
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_get_fic_version(struct lg216x_state *state, u8 *ficver)
+{
+	u8 val;
+	int ret;
+
+	*ficver = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0128, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*ficver = (val >> 3) & 0x1f;
+fail:
+	return ret;
+}
+
+#if 0
+static int lg2160_get_parade_id(struct lg216x_state *state, u8 *id)
+{
+	u8 val;
+	int ret;
+
+	*id = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0123, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*id = val & 0x7f;
+fail:
+	return ret;
+}
+#endif
+
+static int lg216x_get_nog(struct lg216x_state *state, u8 *nog)
+{
+	u8 val;
+	int ret;
+
+	*nog = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0124, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*nog = ((val >> 4) & 0x07) + 1;
+fail:
+	return ret;
+}
+
+static int lg216x_get_tnog(struct lg216x_state *state, u8 *tnog)
+{
+	u8 val;
+	int ret;
+
+	*tnog = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0125, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*tnog = val & 0x1f;
+fail:
+	return ret;
+}
+
+static int lg216x_get_sgn(struct lg216x_state *state, u8 *sgn)
+{
+	u8 val;
+	int ret;
+
+	*sgn = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0124, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*sgn = val & 0x0f;
+fail:
+	return ret;
+}
+
+static int lg216x_get_prc(struct lg216x_state *state, u8 *prc)
+{
+	u8 val;
+	int ret;
+
+	*prc = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0125, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*prc = ((val >> 5) & 0x07) + 1;
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_get_rs_frame_mode(struct lg216x_state *state,
+				    enum atscmh_rs_frame_mode *rs_framemode)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0410, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0513, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	switch ((val >> 4) & 0x03) {
+#if 1
+	default:
+#endif
+	case 0x00:
+		*rs_framemode = ATSCMH_RSFRAME_PRI_ONLY;
+		break;
+	case 0x01:
+		*rs_framemode = ATSCMH_RSFRAME_PRI_SEC;
+		break;
+#if 0
+	default:
+		*rs_framemode = ATSCMH_RSFRAME_RES;
+		break;
+#endif
+	}
+fail:
+	return ret;
+}
+
+static
+int lg216x_get_rs_frame_ensemble(struct lg216x_state *state,
+				 enum atscmh_rs_frame_ensemble *rs_frame_ens)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0400, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0500, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0x01;
+	*rs_frame_ens = (enum atscmh_rs_frame_ensemble) val;
+fail:
+	return ret;
+}
+
+static int lg216x_get_rs_code_mode(struct lg216x_state *state,
+				   enum atscmh_rs_code_mode *rs_code_pri,
+				   enum atscmh_rs_code_mode *rs_code_sec)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0410, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0513, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	*rs_code_pri = (enum atscmh_rs_code_mode) ((val >> 2) & 0x03);
+	*rs_code_sec = (enum atscmh_rs_code_mode) (val & 0x03);
+fail:
+	return ret;
+}
+
+static int lg216x_get_sccc_block_mode(struct lg216x_state *state,
+				      enum atscmh_sccc_block_mode *sccc_block)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0315, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0511, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	switch (val & 0x03) {
+	case 0x00:
+		*sccc_block = ATSCMH_SCCC_BLK_SEP;
+		break;
+	case 0x01:
+		*sccc_block = ATSCMH_SCCC_BLK_COMB;
+		break;
+	default:
+		*sccc_block = ATSCMH_SCCC_BLK_RES;
+		break;
+	}
+fail:
+	return ret;
+}
+
+static int lg216x_get_sccc_code_mode(struct lg216x_state *state,
+				     enum atscmh_sccc_code_mode *mode_a,
+				     enum atscmh_sccc_code_mode *mode_b,
+				     enum atscmh_sccc_code_mode *mode_c,
+				     enum atscmh_sccc_code_mode *mode_d)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0316, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0512, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	switch ((val >> 6) & 0x03) {
+	case 0x00:
+		*mode_a = ATSCMH_SCCC_CODE_HLF;
+		break;
+	case 0x01:
+		*mode_a = ATSCMH_SCCC_CODE_QTR;
+		break;
+	default:
+		*mode_a = ATSCMH_SCCC_CODE_RES;
+		break;
+	}
+
+	switch ((val >> 4) & 0x03) {
+	case 0x00:
+		*mode_b = ATSCMH_SCCC_CODE_HLF;
+		break;
+	case 0x01:
+		*mode_b = ATSCMH_SCCC_CODE_QTR;
+		break;
+	default:
+		*mode_b = ATSCMH_SCCC_CODE_RES;
+		break;
+	}
+
+	switch ((val >> 2) & 0x03) {
+	case 0x00:
+		*mode_c = ATSCMH_SCCC_CODE_HLF;
+		break;
+	case 0x01:
+		*mode_c = ATSCMH_SCCC_CODE_QTR;
+		break;
+	default:
+		*mode_c = ATSCMH_SCCC_CODE_RES;
+		break;
+	}
+
+	switch (val & 0x03) {
+	case 0x00:
+		*mode_d = ATSCMH_SCCC_CODE_HLF;
+		break;
+	case 0x01:
+		*mode_d = ATSCMH_SCCC_CODE_QTR;
+		break;
+	default:
+		*mode_d = ATSCMH_SCCC_CODE_RES;
+		break;
+	}
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#if 0
+static int lg216x_read_fic_err_count(struct lg216x_state *state, u8 *err)
+{
+	u8 fic_err;
+	int ret;
+
+	*err = 0;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0012, &fic_err);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x001e, &fic_err);
+		break;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = fic_err;
+fail:
+	return ret;
+}
+
+static int lg2160_read_crc_err_count(struct lg216x_state *state, u16 *err)
+{
+	u8 crc_err1, crc_err2;
+	int ret;
+
+	*err = 0;
+
+	ret = lg216x_read_reg(state, 0x0411, &crc_err1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0412, &crc_err2);
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = (u16)(((crc_err2 & 0x0f) << 8) | crc_err1);
+fail:
+	return ret;
+}
+
+static int lg2161_read_crc_err_count(struct lg216x_state *state, u16 *err)
+{
+	u8 crc_err;
+	int ret;
+
+	*err = 0;
+
+	ret = lg216x_read_reg(state, 0x0612, &crc_err);
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = (u16)crc_err;
+fail:
+	return ret;
+}
+
+static int lg216x_read_crc_err_count(struct lg216x_state *state, u16 *err)
+{
+	int ret;
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg2160_read_crc_err_count(state, err);
+		break;
+	case LG2161:
+		ret = lg2161_read_crc_err_count(state, err);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int lg2160_read_rs_err_count(struct lg216x_state *state, u16 *err)
+{
+	u8 rs_err1, rs_err2;
+	int ret;
+
+	*err = 0;
+
+	ret = lg216x_read_reg(state, 0x0413, &rs_err1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0414, &rs_err2);
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = (u16)(((rs_err2 & 0x0f) << 8) | rs_err1);
+fail:
+	return ret;
+}
+
+static int lg2161_read_rs_err_count(struct lg216x_state *state, u16 *err)
+{
+	u8 rs_err1, rs_err2;
+	int ret;
+
+	*err = 0;
+
+	ret = lg216x_read_reg(state, 0x0613, &rs_err1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0614, &rs_err2);
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = (u16)((rs_err1 << 8) | rs_err2);
+fail:
+	return ret;
+}
+
+static int lg216x_read_rs_err_count(struct lg216x_state *state, u16 *err)
+{
+	int ret;
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg2160_read_rs_err_count(state, err);
+		break;
+	case LG2161:
+		ret = lg2161_read_rs_err_count(state, err);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_get_frontend(struct dvb_frontend *fe)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret;
+
+	lg_dbg("\n");
+
+	fe->dtv_property_cache.modulation = VSB_8;
+	fe->dtv_property_cache.frequency = state->current_frequency;
+	fe->dtv_property_cache.delivery_system = SYS_ATSCMH;
+
+	ret = lg216x_get_fic_version(state,
+				     &fe->dtv_property_cache.atscmh_fic_ver);
+	if (lg_fail(ret))
+		goto fail;
+	if (state->fic_ver != fe->dtv_property_cache.atscmh_fic_ver) {
+		state->fic_ver = fe->dtv_property_cache.atscmh_fic_ver;
+
+#if 0
+		ret = lg2160_get_parade_id(state,
+				&fe->dtv_property_cache.atscmh_parade_id);
+		if (lg_fail(ret))
+			goto fail;
+/* #else */
+		fe->dtv_property_cache.atscmh_parade_id = state->parade_id;
+#endif
+		ret = lg216x_get_nog(state,
+				     &fe->dtv_property_cache.atscmh_nog);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_tnog(state,
+				      &fe->dtv_property_cache.atscmh_tnog);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_sgn(state,
+				     &fe->dtv_property_cache.atscmh_sgn);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_prc(state,
+				     &fe->dtv_property_cache.atscmh_prc);
+		if (lg_fail(ret))
+			goto fail;
+
+		ret = lg216x_get_rs_frame_mode(state,
+			(enum atscmh_rs_frame_mode *)
+			&fe->dtv_property_cache.atscmh_rs_frame_mode);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_rs_frame_ensemble(state,
+			(enum atscmh_rs_frame_ensemble *)
+			&fe->dtv_property_cache.atscmh_rs_frame_ensemble);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_rs_code_mode(state,
+			(enum atscmh_rs_code_mode *)
+			&fe->dtv_property_cache.atscmh_rs_code_mode_pri,
+			(enum atscmh_rs_code_mode *)
+			&fe->dtv_property_cache.atscmh_rs_code_mode_sec);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_sccc_block_mode(state,
+			(enum atscmh_sccc_block_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_block_mode);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_sccc_code_mode(state,
+			(enum atscmh_sccc_code_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_code_mode_a,
+			(enum atscmh_sccc_code_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_code_mode_b,
+			(enum atscmh_sccc_code_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_code_mode_c,
+			(enum atscmh_sccc_code_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_code_mode_d);
+		if (lg_fail(ret))
+			goto fail;
+	}
+#if 0
+	ret = lg216x_read_fic_err_count(state,
+				(u8 *)&fe->dtv_property_cache.atscmh_fic_err);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg216x_read_crc_err_count(state,
+				&fe->dtv_property_cache.atscmh_crc_err);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg216x_read_rs_err_count(state,
+				&fe->dtv_property_cache.atscmh_rs_err);
+	if (lg_fail(ret))
+		goto fail;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		if (((fe->dtv_property_cache.atscmh_rs_err >= 240) &&
+		     (fe->dtv_property_cache.atscmh_crc_err >= 240)) &&
+		    ((jiffies_to_msecs(jiffies) - state->last_reset) > 6000))
+			ret = lg216x_soft_reset(state);
+		break;
+	case LG2161:
+		/* no fix needed here (as far as we know) */
+		ret = 0;
+		break;
+	}
+	lg_fail(ret);
+#endif
+fail:
+	return ret;
+}
+
+static int lg216x_get_property(struct dvb_frontend *fe,
+			       struct dtv_property *tvp)
+{
+	return (DTV_ATSCMH_FIC_VER == tvp->cmd) ?
+		lg216x_get_frontend(fe) : 0;
+}
+
+
+static int lg2160_set_frontend(struct dvb_frontend *fe)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret;
+
+	lg_dbg("(%d)\n", fe->dtv_property_cache.frequency);
+
+	if (fe->ops.tuner_ops.set_params) {
+		ret = fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+		if (lg_fail(ret))
+			goto fail;
+		state->current_frequency = fe->dtv_property_cache.frequency;
+	}
+
+	ret = lg2160_agc_fix(state, 0, 0);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg2160_agc_polarity(state, 0, 0);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg2160_tuner_pwr_save_polarity(state, 1);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg216x_set_if(state);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg2160_spectrum_polarity(state, state->cfg->spectral_inversion);
+	if (lg_fail(ret))
+		goto fail;
+
+	/* be tuned before this point */
+	ret = lg216x_soft_reset(state);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg2160_tuner_pwr_save(state, 0);
+	if (lg_fail(ret))
+		goto fail;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg2160_set_spi_clock(state);
+		if (lg_fail(ret))
+			goto fail;
+		break;
+	case LG2161:
+		ret = lg2161_set_output_interface(state);
+		if (lg_fail(ret))
+			goto fail;
+		break;
+	}
+
+	ret = lg216x_set_parade(state, fe->dtv_property_cache.atscmh_parade_id);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_set_ensemble(state,
+			fe->dtv_property_cache.atscmh_rs_frame_ensemble);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_initialize(state);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_enable_fic(state, 1);
+	lg_fail(ret);
+
+	lg216x_get_frontend(fe);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg2160_read_lock_status(struct lg216x_state *state,
+				   int *acq_lock, int *sync_lock)
+{
+	u8 val;
+	int ret;
+
+	*acq_lock = 0;
+	*sync_lock = 0;
+
+	ret = lg216x_read_reg(state, 0x011b, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*sync_lock = (val & 0x20) ? 0 : 1;
+	*acq_lock  = (val & 0x40) ? 0 : 1;
+fail:
+	return ret;
+}
+
+#ifdef USE_LG2161_LOCK_BITS
+static int lg2161_read_lock_status(struct lg216x_state *state,
+				   int *acq_lock, int *sync_lock)
+{
+	u8 val;
+	int ret;
+
+	*acq_lock = 0;
+	*sync_lock = 0;
+
+	ret = lg216x_read_reg(state, 0x0304, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*sync_lock = (val & 0x80) ? 0 : 1;
+
+	ret = lg216x_read_reg(state, 0x011b, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*acq_lock  = (val & 0x40) ? 0 : 1;
+fail:
+	return ret;
+}
+#endif
+
+static int lg216x_read_lock_status(struct lg216x_state *state,
+				   int *acq_lock, int *sync_lock)
+{
+#ifdef USE_LG2161_LOCK_BITS
+	int ret;
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg2160_read_lock_status(state, acq_lock, sync_lock);
+		break;
+	case LG2161:
+		ret = lg2161_read_lock_status(state, acq_lock, sync_lock);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+#else
+	return lg2160_read_lock_status(state, acq_lock, sync_lock);
+#endif
+}
+
+static int lg216x_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret, acq_lock, sync_lock;
+
+	*status = 0;
+
+	ret = lg216x_read_lock_status(state, &acq_lock, &sync_lock);
+	if (lg_fail(ret))
+		goto fail;
+
+	lg_dbg("%s%s\n",
+	       acq_lock  ? "SIGNALEXIST " : "",
+	       sync_lock ? "SYNCLOCK"     : "");
+
+	if (acq_lock)
+		*status |= FE_HAS_SIGNAL;
+	if (sync_lock)
+		*status |= FE_HAS_SYNC;
+
+	if (*status)
+		*status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK;
+
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg2160_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	u8 snr1, snr2;
+	int ret;
+
+	*snr = 0;
+
+	ret = lg216x_read_reg(state, 0x0202, &snr1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0203, &snr2);
+	if (lg_fail(ret))
+		goto fail;
+
+	if ((snr1 == 0xba) || (snr2 == 0xdf))
+		*snr = 0;
+	else
+#if 1
+	*snr =  ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 >> 4);
+#else /* BCD */
+	*snr =  (snr2 | (snr1 << 8));
+#endif
+fail:
+	return ret;
+}
+
+static int lg2161_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	u8 snr1, snr2;
+	int ret;
+
+	*snr = 0;
+
+	ret = lg216x_read_reg(state, 0x0302, &snr1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0303, &snr2);
+	if (lg_fail(ret))
+		goto fail;
+
+	if ((snr1 == 0xba) || (snr2 == 0xfd))
+		*snr = 0;
+	else
+
+	*snr =  ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 & 0x0f);
+fail:
+	return ret;
+}
+
+static int lg216x_read_signal_strength(struct dvb_frontend *fe,
+				       u16 *strength)
+{
+#if 0
+	/* borrowed from lgdt330x.c
+	 *
+	 * Calculate strength from SNR up to 35dB
+	 * Even though the SNR can go higher than 35dB,
+	 * there is some comfort factor in having a range of
+	 * strong signals that can show at 100%
+	 */
+	struct lg216x_state *state = fe->demodulator_priv;
+	u16 snr;
+	int ret;
+#endif
+	*strength = 0;
+#if 0
+	ret = fe->ops.read_snr(fe, &snr);
+	if (lg_fail(ret))
+		goto fail;
+	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+	/* scale the range 0 - 35*2^24 into 0 - 65535 */
+	if (state->snr >= 8960 * 0x10000)
+		*strength = 0xffff;
+	else
+		*strength = state->snr / 8960;
+fail:
+	return ret;
+#else
+	return 0;
+#endif
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+#if 0
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret;
+
+	ret = lg216x_read_rs_err_count(state,
+				       &fe->dtv_property_cache.atscmh_rs_err);
+	if (lg_fail(ret))
+		goto fail;
+
+	*ucblocks = fe->dtv_property_cache.atscmh_rs_err;
+fail:
+#else
+	*ucblocks = 0;
+#endif
+	return 0;
+}
+
+static int lg216x_get_tune_settings(struct dvb_frontend *fe,
+				    struct dvb_frontend_tune_settings
+				    *fe_tune_settings)
+{
+	fe_tune_settings->min_delay_ms = 500;
+	lg_dbg("\n");
+	return 0;
+}
+
+static void lg216x_release(struct dvb_frontend *fe)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	lg_dbg("\n");
+	kfree(state);
+}
+
+static struct dvb_frontend_ops lg2160_ops = {
+	.delsys = { SYS_ATSCMH },
+	.info = {
+		.name = "LG Electronics LG2160 ATSC/MH Frontend",
+		.frequency_min      = 54000000,
+		.frequency_max      = 858000000,
+		.frequency_stepsize = 62500,
+	},
+	.i2c_gate_ctrl        = lg216x_i2c_gate_ctrl,
+#if 0
+	.init                 = lg216x_init,
+	.sleep                = lg216x_sleep,
+#endif
+	.get_property         = lg216x_get_property,
+
+	.set_frontend         = lg2160_set_frontend,
+	.get_frontend         = lg216x_get_frontend,
+	.get_tune_settings    = lg216x_get_tune_settings,
+	.read_status          = lg216x_read_status,
+#if 0
+	.read_ber             = lg216x_read_ber,
+#endif
+	.read_signal_strength = lg216x_read_signal_strength,
+	.read_snr             = lg2160_read_snr,
+	.read_ucblocks        = lg216x_read_ucblocks,
+	.release              = lg216x_release,
+};
+
+static struct dvb_frontend_ops lg2161_ops = {
+	.delsys = { SYS_ATSCMH },
+	.info = {
+		.name = "LG Electronics LG2161 ATSC/MH Frontend",
+		.frequency_min      = 54000000,
+		.frequency_max      = 858000000,
+		.frequency_stepsize = 62500,
+	},
+	.i2c_gate_ctrl        = lg216x_i2c_gate_ctrl,
+#if 0
+	.init                 = lg216x_init,
+	.sleep                = lg216x_sleep,
+#endif
+	.get_property         = lg216x_get_property,
+
+	.set_frontend         = lg2160_set_frontend,
+	.get_frontend         = lg216x_get_frontend,
+	.get_tune_settings    = lg216x_get_tune_settings,
+	.read_status          = lg216x_read_status,
+#if 0
+	.read_ber             = lg216x_read_ber,
+#endif
+	.read_signal_strength = lg216x_read_signal_strength,
+	.read_snr             = lg2161_read_snr,
+	.read_ucblocks        = lg216x_read_ucblocks,
+	.release              = lg216x_release,
+};
+
+struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
+				   struct i2c_adapter *i2c_adap)
+{
+	struct lg216x_state *state = NULL;
+
+	lg_dbg("(%d-%04x)\n",
+	       i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
+	       config ? config->i2c_addr : 0);
+
+	state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL);
+	if (state == NULL)
+		goto fail;
+
+	state->cfg = config;
+	state->i2c_adap = i2c_adap;
+	state->fic_ver = 0xff;
+	state->parade_id = 0xff;
+
+	switch (config->lg_chip) {
+	default:
+		lg_warn("invalid chip requested, defaulting to LG2160");
+		/* fall-thru */
+	case LG2160:
+		memcpy(&state->frontend.ops, &lg2160_ops,
+		       sizeof(struct dvb_frontend_ops));
+		break;
+	case LG2161:
+		memcpy(&state->frontend.ops, &lg2161_ops,
+		       sizeof(struct dvb_frontend_ops));
+		break;
+	}
+
+	state->frontend.demodulator_priv = state;
+	state->current_frequency = -1;
+	/* parade 1 by default */
+	state->frontend.dtv_property_cache.atscmh_parade_id = 1;
+
+	return &state->frontend;
+fail:
+	lg_warn("unable to detect LG216x hardware\n");
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(lg2160_attach);
+
+MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.3");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lg2160.h b/drivers/media/dvb/frontends/lg2160.h
new file mode 100644
index 0000000..9e2c0f4
--- /dev/null
+++ b/drivers/media/dvb/frontends/lg2160.h
@@ -0,0 +1,84 @@
+/*
+ *    Support for LG2160 - ATSC/MH
+ *
+ *    Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _LG2160_H_
+#define _LG2160_H_
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+enum lg_chip_type {
+	LG2160 = 0,
+	LG2161 = 1,
+};
+
+#define LG2161_1019 LG2161
+#define LG2161_1040 LG2161
+
+enum lg2160_spi_clock {
+	LG2160_SPI_3_125_MHZ = 0,
+	LG2160_SPI_6_25_MHZ = 1,
+	LG2160_SPI_12_5_MHZ = 2,
+};
+
+#if 0
+enum lg2161_oif {
+	LG2161_OIF_EBI2_SLA  = 1,
+	LG2161_OIF_SDIO_SLA  = 2,
+	LG2161_OIF_SPI_SLA   = 3,
+	LG2161_OIF_SPI_MAS   = 4,
+	LG2161_OIF_SERIAL_TS = 7,
+};
+#endif
+
+struct lg2160_config {
+	u8 i2c_addr;
+
+	/* user defined IF frequency in KHz */
+	u16 if_khz;
+
+	/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
+	int deny_i2c_rptr:1;
+
+	/* spectral inversion - 0:disabled 1:enabled */
+	int spectral_inversion:1;
+
+	unsigned int output_if;
+	enum lg2160_spi_clock spi_clock;
+	enum lg_chip_type lg_chip;
+};
+
+#if defined(CONFIG_DVB_LG2160) || (defined(CONFIG_DVB_LG2160_MODULE) && \
+				     defined(MODULE))
+extern
+struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
+				     struct i2c_adapter *i2c_adap);
+#else
+static inline
+struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
+				     struct i2c_adapter *i2c_adap)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LG2160 */
+
+#endif /* _LG2160_H_ */
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index 4de1d35..568363a 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -262,7 +262,6 @@
 
 static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
 {
-	int ret = 0;
 	u8 t;
 
 	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
@@ -296,7 +295,7 @@
 	if (priv->config->prod == LGS8GXX_PROD_LGS8913)
 		lgs8gxx_write_reg(priv, 0xC1, 0);
 
-	ret = lgs8gxx_read_reg(priv, 0xC5, &t);
+	lgs8gxx_read_reg(priv, 0xC5, &t);
 	t = (t & 0xE0) | 0x06;
 	lgs8gxx_write_reg(priv, 0xC5, t);
 
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c
index 045ee5a..312588e 100644
--- a/drivers/media/dvb/frontends/m88rs2000.c
+++ b/drivers/media/dvb/frontends/m88rs2000.c
@@ -416,9 +416,25 @@
 
 static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
 {
-	deb_info("%s: %s\n", __func__,
-		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
-		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 data;
+
+	data = m88rs2000_demod_read(state, 0xb2);
+	data |= 0x03; /* bit0 V/H, bit1 off/on */
+
+	switch (volt) {
+	case SEC_VOLTAGE_18:
+		data &= ~0x03;
+		break;
+	case SEC_VOLTAGE_13:
+		data &= ~0x03;
+		data |= 0x01;
+		break;
+	case SEC_VOLTAGE_OFF:
+		break;
+	}
+
+	m88rs2000_demod_write(state, 0xb2, data);
 
 	return 0;
 }
@@ -654,7 +670,6 @@
 static int m88rs2000_set_fec(struct m88rs2000_state *state,
 		fe_code_rate_t fec)
 {
-	int ret;
 	u16 fec_set;
 	switch (fec) {
 	/* This is not confirmed kept for reference */
@@ -677,7 +692,7 @@
 	default:
 		fec_set = 0x08;
 	}
-	ret = m88rs2000_demod_write(state, 0x76, fec_set);
+	m88rs2000_demod_write(state, 0x76, fec_set);
 
 	return 0;
 }
@@ -772,13 +787,13 @@
 		return -ENODEV;
 
 	for (i = 0; i < 25; i++) {
-		u8 reg = m88rs2000_demod_read(state, 0x8c);
+		reg = m88rs2000_demod_read(state, 0x8c);
 		if ((reg & 0x7) == 0x7) {
 			status = FE_HAS_LOCK;
 			break;
 		}
 		state->no_lock_count++;
-		if (state->no_lock_count > 15) {
+		if (state->no_lock_count == 15) {
 			reg = m88rs2000_demod_read(state, 0x70);
 			reg ^= 0x4;
 			m88rs2000_demod_write(state, 0x70, reg);
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c
index 45196c5..93612eb 100644
--- a/drivers/media/dvb/frontends/rtl2830.c
+++ b/drivers/media/dvb/frontends/rtl2830.c
@@ -374,6 +374,118 @@
 	return ret;
 }
 
+static int rtl2830_get_frontend(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+	u8 buf[3];
+
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2830_rd_regs(priv, 0x33c, buf, 2);
+	if (ret)
+		goto err;
+
+	ret = rtl2830_rd_reg(priv, 0x351, &buf[2]);
+	if (ret)
+		goto err;
+
+	dbg("%s: TPS=%02x %02x %02x", __func__, buf[0], buf[1], buf[2]);
+
+	switch ((buf[0] >> 2) & 3) {
+	case 0:
+		c->modulation = QPSK;
+		break;
+	case 1:
+		c->modulation = QAM_16;
+		break;
+	case 2:
+		c->modulation = QAM_64;
+		break;
+	}
+
+	switch ((buf[2] >> 2) & 1) {
+	case 0:
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		c->transmission_mode = TRANSMISSION_MODE_8K;
+	}
+
+	switch ((buf[2] >> 0) & 3) {
+	case 0:
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		c->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		c->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		c->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	switch ((buf[0] >> 4) & 7) {
+	case 0:
+		c->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		c->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		c->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		c->hierarchy = HIERARCHY_4;
+		break;
+	}
+
+	switch ((buf[1] >> 3) & 7) {
+	case 0:
+		c->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_HP = FEC_7_8;
+		break;
+	}
+
+	switch ((buf[1] >> 0) & 7) {
+	case 0:
+		c->code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_LP = FEC_7_8;
+		break;
+	}
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
 static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
 	struct rtl2830_priv *priv = fe->demodulator_priv;
@@ -404,14 +516,72 @@
 
 static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-	*snr = 0;
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret, hierarchy, constellation;
+	u8 buf[2], tmp;
+	u16 tmp16;
+#define CONSTELLATION_NUM 3
+#define HIERARCHY_NUM 4
+	static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
+		{ 70705899, 70705899, 70705899, 70705899 },
+		{ 82433173, 82433173, 87483115, 94445660 },
+		{ 92888734, 92888734, 95487525, 99770748 },
+	};
+
+	if (priv->sleeping)
+		return 0;
+
+	/* reports SNR in resolution of 0.1 dB */
+
+	ret = rtl2830_rd_reg(priv, 0x33c, &tmp);
+	if (ret)
+		goto err;
+
+	constellation = (tmp >> 2) & 0x03; /* [3:2] */
+	if (constellation > CONSTELLATION_NUM - 1)
+		goto err;
+
+	hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
+	if (hierarchy > HIERARCHY_NUM - 1)
+		goto err;
+
+	ret = rtl2830_rd_regs(priv, 0x40c, buf, 2);
+	if (ret)
+		goto err;
+
+	tmp16 = buf[0] << 8 | buf[1];
+
+	if (tmp16)
+		*snr = (snr_constant[constellation][hierarchy] -
+				intlog10(tmp16)) / ((1 << 24) / 100);
+	else
+		*snr = 0;
+
 	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
 }
 
 static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-	*ber = 0;
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2830_rd_regs(priv, 0x34e, buf, 2);
+	if (ret)
+		goto err;
+
+	*ber = buf[0] << 8 | buf[1];
+
 	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
 }
 
 static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
@@ -422,8 +592,32 @@
 
 static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-	*strength = 0;
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+	u16 if_agc_raw, if_agc;
+
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2830_rd_regs(priv, 0x359, buf, 2);
+	if (ret)
+		goto err;
+
+	if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff;
+
+	if (if_agc_raw & (1 << 9))
+		if_agc = -(~(if_agc_raw - 1) & 0x1ff);
+	else
+		if_agc = if_agc_raw;
+
+	*strength = (u8) (55 - if_agc / 182);
+	*strength |= *strength << 8;
+
 	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
 }
 
 static struct dvb_frontend_ops rtl2830_ops;
@@ -549,6 +743,7 @@
 	.get_tune_settings = rtl2830_get_tune_settings,
 
 	.set_frontend = rtl2830_set_frontend,
+	.get_frontend = rtl2830_get_frontend,
 
 	.read_status = rtl2830_read_status,
 	.read_snr = rtl2830_read_snr,
diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h
index 4a46476..9b20557 100644
--- a/drivers/media/dvb/frontends/rtl2830_priv.h
+++ b/drivers/media/dvb/frontends/rtl2830_priv.h
@@ -22,6 +22,7 @@
 #define RTL2830_PRIV_H
 
 #include "dvb_frontend.h"
+#include "dvb_math.h"
 #include "rtl2830.h"
 
 #define LOG_PREFIX "rtl2830"
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
index dd08f4a..8b0dc74 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb/frontends/stb0899_drv.c
@@ -637,11 +637,9 @@
 	struct stb0899_internal *internal = &state->internal;
 	int master_clk;
 	u8 agc[2];
-	u8 agc1cn;
 	u32 reg;
 
 	/* Read registers (in burst mode)	*/
-	agc1cn = stb0899_read_reg(state, STB0899_AGC1CN);
 	stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O	*/
 
 	/* Initial calculations	*/
@@ -823,15 +821,12 @@
 
 static int stb0899_diseqc_init(struct stb0899_state *state)
 {
-	struct dvb_diseqc_master_cmd tx_data;
 /*
 	struct dvb_diseqc_slave_reply rx_data;
 */
-	u8 f22_tx, f22_rx, reg;
+	u8 f22_tx, reg;
 
 	u32 mclk, tx_freq = 22000;/* count = 0, i; */
-	tx_data.msg[0] = 0xe2;
-	tx_data.msg_len = 3;
 	reg = stb0899_read_reg(state, STB0899_DISCNTRL2);
 	STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0);
 	stb0899_write_reg(state, STB0899_DISCNTRL2, reg);
@@ -849,7 +844,6 @@
 	f22_tx = mclk / (tx_freq * 32);
 	stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq	*/
 	state->rx_freq = 20000;
-	f22_rx = mclk / (state->rx_freq * 32);
 
 	return 0;
 }
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c
index def88ab..2e93e65 100644
--- a/drivers/media/dvb/frontends/stb6100.c
+++ b/drivers/media/dvb/frontends/stb6100.c
@@ -158,7 +158,6 @@
 static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
 {
 	u8 regs[STB6100_NUMREGS];
-	int rc;
 
 	struct i2c_msg msg = {
 		.addr	= state->config->tuner_address + reg,
@@ -167,7 +166,7 @@
 		.len	= 1
 	};
 
-	rc = i2c_transfer(state->i2c, &msg, 1);
+	i2c_transfer(state->i2c, &msg, 1);
 
 	if (unlikely(reg >= STB6100_NUMREGS)) {
 		dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 85c157a..d40f226 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -414,7 +414,6 @@
 	int delay;
 	int sweeprate;
 	int carrieroffset;
-	unsigned long starttime;
 	unsigned long timeout;
 	fe_spectral_inversion_t inversion;
 
@@ -543,7 +542,6 @@
 	stv0297_writereg_mask(state, 0x43, 0x10, 0x10);
 
 	/* wait for WGAGC lock */
-	starttime = jiffies;
 	timeout = jiffies + msecs_to_jiffies(2000);
 	while (time_before(jiffies, timeout)) {
 		msleep(10);
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
index ba0709b..4af2078 100644
--- a/drivers/media/dvb/frontends/stv0900_sw.c
+++ b/drivers/media/dvb/frontends/stv0900_sw.c
@@ -835,7 +835,6 @@
 		blind_tun_sw = 0,
 		modulation;
 
-	enum fe_stv0900_rolloff rolloff;
 	enum fe_stv0900_modcode foundModcod;
 
 	dprintk("%s\n", __func__);
@@ -940,7 +939,6 @@
 
 	freq1 = stv0900_read_reg(intp, CFR2);
 	freq0 = stv0900_read_reg(intp, CFR1);
-	rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS);
 	if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) {
 		stv0900_write_reg(intp, SFRSTEP, 0x00);
 		stv0900_write_bits(intp, SCAN_ENABLE, 0);
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index 4aef187..d79e69f 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -2842,7 +2842,6 @@
 {
 	struct dvb_frontend *fe = &state->frontend;
 
-	enum stv090x_rolloff rolloff;
 	enum stv090x_modcod modcod;
 
 	s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0;
@@ -2966,7 +2965,6 @@
 	f_1 = STV090x_READ_DEMOD(state, CFR2);
 	f_0 = STV090x_READ_DEMOD(state, CFR1);
 	reg = STV090x_READ_DEMOD(state, TMGOBS);
-	rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
 
 	if (state->algo == STV090x_BLIND_SEARCH) {
 		STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00);
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index ac72378..82946cd 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -525,7 +525,7 @@
 		zl10353_dump_regs(fe);
 
 	_snr = zl10353_read_register(state, SNR);
-	*snr = (_snr << 8) | _snr;
+	*snr = 10 * _snr / 8;
 
 	return 0;
 }
@@ -559,7 +559,6 @@
 {
 	struct zl10353_state *state = fe->demodulator_priv;
 	u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F };
-	int rc = 0;
 
 	if (debug_regs)
 		zl10353_dump_regs(fe);
@@ -573,7 +572,7 @@
 	/* Do a "hard" reset if not already done */
 	if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
 	    zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) {
-		rc = zl10353_write(fe, zl10353_reset_attach,
+		zl10353_write(fe, zl10353_reset_attach,
 				   sizeof(zl10353_reset_attach));
 		if (debug_regs)
 			zl10353_dump_regs(fe);
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
index 71622f6..cc0251e 100644
--- a/drivers/media/dvb/mantis/hopper_cards.c
+++ b/drivers/media/dvb/mantis/hopper_cards.c
@@ -65,7 +65,7 @@
 
 static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
 {
-	u32 stat = 0, mask = 0, lstat = 0;
+	u32 stat = 0, mask = 0;
 	u32 rst_stat = 0, rst_mask = 0;
 
 	struct mantis_pci *mantis;
@@ -80,7 +80,6 @@
 
 	stat = mmread(MANTIS_INT_STAT);
 	mask = mmread(MANTIS_INT_MASK);
-	lstat = stat & ~MANTIS_INT_RISCSTAT;
 	if (!(stat & mask))
 		return IRQ_NONE;
 
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
index c2bb90b..095cf3a 100644
--- a/drivers/media/dvb/mantis/mantis_cards.c
+++ b/drivers/media/dvb/mantis/mantis_cards.c
@@ -73,7 +73,7 @@
 
 static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
 {
-	u32 stat = 0, mask = 0, lstat = 0;
+	u32 stat = 0, mask = 0;
 	u32 rst_stat = 0, rst_mask = 0;
 
 	struct mantis_pci *mantis;
@@ -88,7 +88,6 @@
 
 	stat = mmread(MANTIS_INT_STAT);
 	mask = mmread(MANTIS_INT_MASK);
-	lstat = stat & ~MANTIS_INT_RISCSTAT;
 	if (!(stat & mask))
 		return IRQ_NONE;
 
diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c
index c61ca7d..566c407 100644
--- a/drivers/media/dvb/mantis/mantis_dma.c
+++ b/drivers/media/dvb/mantis/mantis_dma.c
@@ -199,10 +199,6 @@
 
 void mantis_dma_stop(struct mantis_pci *mantis)
 {
-	u32 stat = 0, mask = 0;
-
-	stat = mmread(MANTIS_INT_STAT);
-	mask = mmread(MANTIS_INT_MASK);
 	dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine");
 
 	mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR);
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c
index 36f2256..71ce528 100644
--- a/drivers/media/dvb/mantis/mantis_evm.c
+++ b/drivers/media/dvb/mantis/mantis_evm.c
@@ -41,10 +41,9 @@
 	struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work);
 	struct mantis_pci *mantis = ca->ca_priv;
 
-	u32 gpif_stat, gpif_mask;
+	u32 gpif_stat;
 
 	gpif_stat = mmread(MANTIS_GPIF_STATUS);
-	gpif_mask = mmread(MANTIS_GPIF_IRQCFG);
 
 	if (gpif_stat & MANTIS_GPIF_DETSTAT) {
 		if (gpif_stat & MANTIS_CARD_PLUGIN) {
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
index f129a93..3985738 100644
--- a/drivers/media/dvb/ngene/ngene-core.c
+++ b/drivers/media/dvb/ngene/ngene-core.c
@@ -1409,10 +1409,8 @@
 	if (stat < 0)
 		goto fail;
 
-	if (!stat)
-		return stat;
+	return 0;
 
-	/* otherwise error: fall through */
 fail:
 	ngwritel(0, NGENE_INT_ENABLE);
 	free_irq(dev->pci_dev->irq, dev);
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index e1f20c2..f148b19 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -481,14 +481,6 @@
 	if (p->bandwidth_hz == 8000000)
 		buf[3] |= 0x08;
 
-	if (sizeof(buf) == 6) {
-		buf[4] = buf[2];
-		buf[4] &= ~0x1c;
-		buf[4] |=  0x18;
-
-		buf[5] = (0 << 7) | (2 << 4);
-	}
-
 	msg.addr = I2C_ADDR_TUA6034 >> 1;
 	msg.flags = 0;
 	msg.buf = buf;
diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c
index 91f8c82..d6f3f10 100644
--- a/drivers/media/dvb/siano/smssdio.c
+++ b/drivers/media/dvb/siano/smssdio.c
@@ -114,7 +114,7 @@
 
 static void smssdio_interrupt(struct sdio_func *func)
 {
-	int ret, isr;
+	int ret;
 
 	struct smssdio_device *smsdev;
 	struct smscore_buffer_t *cb;
@@ -127,7 +127,7 @@
 	 * The interrupt register has no defined meaning. It is just
 	 * a way of turning of the level triggered interrupt.
 	 */
-	isr = sdio_readb(func, SMSSDIO_INT, &ret);
+	(void)sdio_readb(func, SMSSDIO_INT, &ret);
 	if (ret) {
 		sms_err("Unable to read interrupt register!\n");
 		return;
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index b1fe513..63c004a 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -542,6 +542,8 @@
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ USB_DEVICE(0x2040, 0xc090),
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0xc0a0),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ } /* Terminating entry */
 	};
 
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index ee8ee1d..1b2d151 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -107,7 +107,7 @@
 		.index		= 1,
 		.name		= "Television",
 		.type		= V4L2_INPUT_TYPE_TUNER,
-		.audioset	= 2,
+		.audioset	= 1,
 		.tuner		= 0,
 		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
 		.status		= 0,
@@ -494,7 +494,7 @@
 	dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
 
 	if (!av7110->analog_tuner_flags)
-		return 0;
+		return input ? -EINVAL : 0;
 
 	if (input >= 4)
 		return -EINVAL;
@@ -503,19 +503,38 @@
 	return av7110_dvb_c_switch(fh);
 }
 
-static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
 {
 	dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
 	if (a->index != 0)
 		return -EINVAL;
-	memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
+	*a = msp3400_v4l2_audio;
+	return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
+	if (a->index != 0)
+		return -EINVAL;
+	if (av7110->current_input >= 2)
+		return -EINVAL;
+	*a = msp3400_v4l2_audio;
 	return 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
 {
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
 	dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
-	return 0;
+	if (av7110->current_input >= 2)
+		return -EINVAL;
+	return a->index ? -EINVAL : 0;
 }
 
 static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
@@ -802,26 +821,39 @@
 		ERR("cannot init capture device. skipping\n");
 		return -ENODEV;
 	}
-	vv_data->ops.vidioc_enum_input = vidioc_enum_input;
-	vv_data->ops.vidioc_g_input = vidioc_g_input;
-	vv_data->ops.vidioc_s_input = vidioc_s_input;
-	vv_data->ops.vidioc_g_tuner = vidioc_g_tuner;
-	vv_data->ops.vidioc_s_tuner = vidioc_s_tuner;
-	vv_data->ops.vidioc_g_frequency = vidioc_g_frequency;
-	vv_data->ops.vidioc_s_frequency = vidioc_s_frequency;
-	vv_data->ops.vidioc_g_audio = vidioc_g_audio;
-	vv_data->ops.vidioc_s_audio = vidioc_s_audio;
-	vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
-	vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
-	vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
+	vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input;
+	vv_data->vid_ops.vidioc_g_input = vidioc_g_input;
+	vv_data->vid_ops.vidioc_s_input = vidioc_s_input;
+	vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner;
+	vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner;
+	vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency;
+	vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency;
+	vv_data->vid_ops.vidioc_enumaudio = vidioc_enumaudio;
+	vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio;
+	vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio;
+	vv_data->vid_ops.vidioc_g_fmt_vbi_cap = NULL;
+
+	vv_data->vbi_ops.vidioc_g_tuner = vidioc_g_tuner;
+	vv_data->vbi_ops.vidioc_s_tuner = vidioc_s_tuner;
+	vv_data->vbi_ops.vidioc_g_frequency = vidioc_g_frequency;
+	vv_data->vbi_ops.vidioc_s_frequency = vidioc_s_frequency;
+	vv_data->vbi_ops.vidioc_g_fmt_vbi_cap = NULL;
+	vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
+	vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
+	vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
+
+	if (FW_VERSION(av7110->arm_app) < 0x2623)
+		vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT;
 
 	if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
 		ERR("cannot register capture device. skipping\n");
 		saa7146_vv_release(dev);
 		return -ENODEV;
 	}
-	if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
-		ERR("cannot register vbi v4l2 device. skipping\n");
+	if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+		if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
+			ERR("cannot register vbi v4l2 device. skipping\n");
+	}
 	return 0;
 }
 
@@ -905,7 +937,7 @@
 static struct saa7146_ext_vv av7110_vv_data_st = {
 	.inputs		= 1,
 	.audios		= 1,
-	.capabilities	= V4L2_CAP_SLICED_VBI_OUTPUT,
+	.capabilities	= V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
 	.flags		= 0,
 
 	.stds		= &standard[0],
@@ -920,7 +952,7 @@
 static struct saa7146_ext_vv av7110_vv_data_c = {
 	.inputs		= 1,
 	.audios		= 1,
-	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT,
+	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
 	.flags		= SAA7146_USE_PORT_B_FOR_VBI,
 
 	.stds		= &standard[0],
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 8b32e28..12ddb53 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1483,9 +1483,9 @@
 			ERR("cannot init vv subsystem\n");
 			return err;
 		}
-		vv_data.ops.vidioc_enum_input = vidioc_enum_input;
-		vv_data.ops.vidioc_g_input = vidioc_g_input;
-		vv_data.ops.vidioc_s_input = vidioc_s_input;
+		vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+		vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+		vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
 
 		if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
 			/* fixme: proper cleanup here */
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 056138f..e1cd132 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -214,23 +214,76 @@
  * pipeline pointer must be identical for all nested calls to
  * media_entity_pipeline_start().
  */
-void media_entity_pipeline_start(struct media_entity *entity,
-				 struct media_pipeline *pipe)
+__must_check int media_entity_pipeline_start(struct media_entity *entity,
+					     struct media_pipeline *pipe)
 {
 	struct media_device *mdev = entity->parent;
 	struct media_entity_graph graph;
+	struct media_entity *entity_err = entity;
+	int ret;
 
 	mutex_lock(&mdev->graph_mutex);
 
 	media_entity_graph_walk_start(&graph, entity);
 
 	while ((entity = media_entity_graph_walk_next(&graph))) {
+		unsigned int i;
+
 		entity->stream_count++;
 		WARN_ON(entity->pipe && entity->pipe != pipe);
 		entity->pipe = pipe;
+
+		/* Already streaming --- no need to check. */
+		if (entity->stream_count > 1)
+			continue;
+
+		if (!entity->ops || !entity->ops->link_validate)
+			continue;
+
+		for (i = 0; i < entity->num_links; i++) {
+			struct media_link *link = &entity->links[i];
+
+			/* Is this pad part of an enabled link? */
+			if (!(link->flags & MEDIA_LNK_FL_ENABLED))
+				continue;
+
+			/* Are we the sink or not? */
+			if (link->sink->entity != entity)
+				continue;
+
+			ret = entity->ops->link_validate(link);
+			if (ret < 0 && ret != -ENOIOCTLCMD)
+				goto error;
+		}
 	}
 
 	mutex_unlock(&mdev->graph_mutex);
+
+	return 0;
+
+error:
+	/*
+	 * Link validation on graph failed. We revert what we did and
+	 * return the error.
+	 */
+	media_entity_graph_walk_start(&graph, entity_err);
+
+	while ((entity_err = media_entity_graph_walk_next(&graph))) {
+		entity_err->stream_count--;
+		if (entity_err->stream_count == 0)
+			entity_err->pipe = NULL;
+
+		/*
+		 * We haven't increased stream_count further than this
+		 * so we quit here.
+		 */
+		if (entity_err == entity)
+			break;
+	}
+
+	mutex_unlock(&mdev->graph_mutex);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
 
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 8db2d7f..c257da1 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -320,7 +320,7 @@
 	  module will be called radio-miropcm20.
 
 config RADIO_SF16FMI
-	tristate "SF16-FMI/SF16-FMP Radio"
+	tristate "SF16-FMI/SF16-FMP/SF16-FMD Radio"
 	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have one of these FM radio cards.
@@ -329,7 +329,7 @@
 	  module will be called radio-sf16fmi.
 
 config RADIO_SF16FMR2
-	tristate "SF16FMR2 Radio"
+	tristate "SF16-FMR2/SF16-FMD2 Radio"
 	depends on ISA && VIDEO_V4L2 && SND
 	---help---
 	  Choose Y here if you have one of these FM radio cards.
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index f36905b..63b112b 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -1,92 +1,37 @@
 /* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21.
- The device plugs into both the USB and an analog audio input, so this thing
- only deals with initialisation and frequency setting, the
- audio data has to be handled by a sound driver.
-
- Major issue: I can't find out where the device reports the signal
- strength, and indeed the windows software appearantly just looks
- at the stereo indicator as well.  So, scanning will only find
- stereo stations.  Sad, but I can't help it.
-
- Also, the windows program sends oodles of messages over to the
- device, and I couldn't figure out their meaning.  My suspicion
- is that they don't have any:-)
-
- You might find some interesting stuff about this module at
- http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
-
- Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
-
- 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
-
- History:
-
- Version 0.46:
-	Removed usb_dsbr100_open/close calls and radio->users counter. Also,
-	radio->muted changed to radio->status and suspend/resume calls updated.
-
- Version 0.45:
-	Converted to v4l2_device.
-
- Version 0.44:
-	Add suspend/resume functions, fix unplug of device,
-	a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
-
- Version 0.43:
-	Oliver Neukum: avoided DMA coherency issue
-
- Version 0.42:
-	Converted dsbr100 to use video_ioctl2
-	by Douglas Landgraf <dougsland@gmail.com>
-
- Version 0.41-ac1:
-	Alan Cox: Some cleanups and fixes
-
- Version 0.41:
-	Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
-
- Version 0.40:
-	Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
-
- Version 0.30:
-	Markus: Updates for 2.5.x kernel and more ISO compliant source
-
- Version 0.25:
-	PSL and Markus: Cleanup, radio now doesn't stop on device close
-
- Version 0.24:
-	Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
-	right.  Some minor cleanup, improved standalone compilation
-
- Version 0.23:
-	Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
-
- Version 0.22:
-	Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
-	thanks to Mike Cox for pointing the problem out.
-
- Version 0.21:
-	Markus: Minor cleanup, warnings if something goes wrong, lame attempt
-	to adhere to Documentation/CodingStyle
-
- Version 0.2:
-	Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
-	Markus: Copyright clarification
-
- Version 0.01: Markus: initial release
-
+ * The device plugs into both the USB and an analog audio input, so this thing
+ * only deals with initialisation and frequency setting, the
+ * audio data has to be handled by a sound driver.
+ *
+ * Major issue: I can't find out where the device reports the signal
+ * strength, and indeed the windows software appearantly just looks
+ * at the stereo indicator as well.  So, scanning will only find
+ * stereo stations.  Sad, but I can't help it.
+ *
+ * Also, the windows program sends oodles of messages over to the
+ * device, and I couldn't figure out their meaning.  My suspicion
+ * is that they don't have any:-)
+ *
+ * You might find some interesting stuff about this module at
+ * http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
+ *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
+ *
+ * Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
+ *
+ * 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/kernel.h>
@@ -95,17 +40,19 @@
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/videodev2.h>
+#include <linux/usb.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "0.4.7"
-
-#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
-#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
+MODULE_AUTHOR("Markus Demleitner <msdemlei@tucana.harvard.edu>");
+MODULE_DESCRIPTION("D-Link DSB-R100 USB FM radio driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.1.0");
 
 #define DSB100_VENDOR 0x04b4
 #define DSB100_PRODUCT 0x1002
@@ -122,19 +69,8 @@
 #define FREQ_MAX 108.0
 #define FREQ_MUL 16000
 
-/* defines for radio->status */
-#define STARTED	0
-#define STOPPED	1
-
 #define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev)
 
-static int usb_dsbr100_probe(struct usb_interface *intf,
-			     const struct usb_device_id *id);
-static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_suspend(struct usb_interface *intf,
-						pm_message_t message);
-static int usb_dsbr100_resume(struct usb_interface *intf);
-
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 
@@ -143,70 +79,58 @@
 	struct usb_device *usbdev;
 	struct video_device videodev;
 	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler hdl;
 
 	u8 *transfer_buffer;
 	struct mutex v4l2_lock;
 	int curfreq;
-	int stereo;
-	int status;
-};
-
-static struct usb_device_id usb_dsbr100_device_table [] = {
-	{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
-	{ }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
-
-/* USB subsystem interface */
-static struct usb_driver usb_dsbr100_driver = {
-	.name			= "dsbr100",
-	.probe			= usb_dsbr100_probe,
-	.disconnect		= usb_dsbr100_disconnect,
-	.id_table		= usb_dsbr100_device_table,
-	.suspend		= usb_dsbr100_suspend,
-	.resume			= usb_dsbr100_resume,
-	.reset_resume		= usb_dsbr100_resume,
-	.supports_autosuspend	= 0,
+	bool stereo;
+	bool muted;
 };
 
 /* Low-level device interface begins here */
 
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int dsbr100_setfreq(struct dsbr100_device *radio, unsigned freq)
+{
+	unsigned f = (freq / 16 * 80) / 1000 + 856;
+	int retval = 0;
+
+	if (!radio->muted) {
+		retval = usb_control_msg(radio->usbdev,
+				usb_rcvctrlpipe(radio->usbdev, 0),
+				DSB100_TUNE,
+				USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+				(f >> 8) & 0x00ff, f & 0xff,
+				radio->transfer_buffer, 8, 300);
+		if (retval >= 0)
+			mdelay(1);
+	}
+
+	if (retval >= 0) {
+		radio->curfreq = freq;
+		return 0;
+	}
+	dev_err(&radio->usbdev->dev,
+		"%s - usb_control_msg returned %i, request %i\n",
+			__func__, retval, DSB100_TUNE);
+	return retval;
+}
+
 /* switch on radio */
 static int dsbr100_start(struct dsbr100_device *radio)
 {
-	int retval;
-	int request;
-
-	retval = usb_control_msg(radio->usbdev,
-		usb_rcvctrlpipe(radio->usbdev, 0),
-		USB_REQ_GET_STATUS,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-		0x00, 0xC7, radio->transfer_buffer, 8, 300);
-
-	if (retval < 0) {
-		request = USB_REQ_GET_STATUS;
-		goto usb_control_msg_failed;
-	}
-
-	retval = usb_control_msg(radio->usbdev,
+	int retval = usb_control_msg(radio->usbdev,
 		usb_rcvctrlpipe(radio->usbdev, 0),
 		DSB100_ONOFF,
 		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
 		0x01, 0x00, radio->transfer_buffer, 8, 300);
 
-	if (retval < 0) {
-		request = DSB100_ONOFF;
-		goto usb_control_msg_failed;
-	}
-
-	radio->status = STARTED;
-	return (radio->transfer_buffer)[0];
-
-usb_control_msg_failed:
+	if (retval >= 0)
+		return dsbr100_setfreq(radio, radio->curfreq);
 	dev_err(&radio->usbdev->dev,
 		"%s - usb_control_msg returned %i, request %i\n",
-			__func__, retval, request);
+			__func__, retval, DSB100_ONOFF);
 	return retval;
 
 }
@@ -214,108 +138,33 @@
 /* switch off radio */
 static int dsbr100_stop(struct dsbr100_device *radio)
 {
-	int retval;
-	int request;
-
-	retval = usb_control_msg(radio->usbdev,
-		usb_rcvctrlpipe(radio->usbdev, 0),
-		USB_REQ_GET_STATUS,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-		0x16, 0x1C, radio->transfer_buffer, 8, 300);
-
-	if (retval < 0) {
-		request = USB_REQ_GET_STATUS;
-		goto usb_control_msg_failed;
-	}
-
-	retval = usb_control_msg(radio->usbdev,
+	int retval = usb_control_msg(radio->usbdev,
 		usb_rcvctrlpipe(radio->usbdev, 0),
 		DSB100_ONOFF,
 		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
 		0x00, 0x00, radio->transfer_buffer, 8, 300);
 
-	if (retval < 0) {
-		request = DSB100_ONOFF;
-		goto usb_control_msg_failed;
-	}
-
-	radio->status = STOPPED;
-	return (radio->transfer_buffer)[0];
-
-usb_control_msg_failed:
+	if (retval >= 0)
+		return 0;
 	dev_err(&radio->usbdev->dev,
 		"%s - usb_control_msg returned %i, request %i\n",
-			__func__, retval, request);
+			__func__, retval, DSB100_ONOFF);
 	return retval;
 
 }
 
-/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(struct dsbr100_device *radio)
-{
-	int retval;
-	int request;
-	int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
-
-	retval = usb_control_msg(radio->usbdev,
-		usb_rcvctrlpipe(radio->usbdev, 0),
-		DSB100_TUNE,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-		(freq >> 8) & 0x00ff, freq & 0xff,
-		radio->transfer_buffer, 8, 300);
-
-	if (retval < 0) {
-		request = DSB100_TUNE;
-		goto usb_control_msg_failed;
-	}
-
-	retval = usb_control_msg(radio->usbdev,
-		usb_rcvctrlpipe(radio->usbdev, 0),
-		USB_REQ_GET_STATUS,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-		0x96, 0xB7, radio->transfer_buffer, 8, 300);
-
-	if (retval < 0) {
-		request = USB_REQ_GET_STATUS;
-		goto usb_control_msg_failed;
-	}
-
-	retval = usb_control_msg(radio->usbdev,
-		usb_rcvctrlpipe(radio->usbdev, 0),
-		USB_REQ_GET_STATUS,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
-		0x00, 0x24, radio->transfer_buffer, 8, 300);
-
-	if (retval < 0) {
-		request = USB_REQ_GET_STATUS;
-		goto usb_control_msg_failed;
-	}
-
-	radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
-	return (radio->transfer_buffer)[0];
-
-usb_control_msg_failed:
-	radio->stereo = -1;
-	dev_err(&radio->usbdev->dev,
-		"%s - usb_control_msg returned %i, request %i\n",
-			__func__, retval, request);
-	return retval;
-}
-
 /* return the device status.  This is, in effect, just whether it
 sees a stereo signal or not.  Pity. */
 static void dsbr100_getstat(struct dsbr100_device *radio)
 {
-	int retval;
-
-	retval = usb_control_msg(radio->usbdev,
+	int retval = usb_control_msg(radio->usbdev,
 		usb_rcvctrlpipe(radio->usbdev, 0),
 		USB_REQ_GET_STATUS,
 		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-		0x00 , 0x24, radio->transfer_buffer, 8, 300);
+		0x00, 0x24, radio->transfer_buffer, 8, 300);
 
 	if (retval < 0) {
-		radio->stereo = -1;
+		radio->stereo = false;
 		dev_err(&radio->usbdev->dev,
 			"%s - usb_control_msg returned %i, request %i\n",
 				__func__, retval, USB_REQ_GET_STATUS);
@@ -332,7 +181,8 @@
 	strlcpy(v->driver, "dsbr100", sizeof(v->driver));
 	strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
 	usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER;
+	v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -349,13 +199,11 @@
 	v->type = V4L2_TUNER_RADIO;
 	v->rangelow = FREQ_MIN * FREQ_MUL;
 	v->rangehigh = FREQ_MAX * FREQ_MUL;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	if(radio->stereo)
-		v->audmode = V4L2_TUNER_MODE_STEREO;
-	else
-		v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xffff;     /* We can't get the signal strength */
+	v->rxsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO :
+		V4L2_TUNER_SUB_MONO;
+	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+	v->audmode = V4L2_TUNER_MODE_STEREO;
+	v->signal = radio->stereo ? 0xffff : 0;     /* We can't get the signal strength */
 	return 0;
 }
 
@@ -369,14 +217,12 @@
 				struct v4l2_frequency *f)
 {
 	struct dsbr100_device *radio = video_drvdata(file);
-	int retval;
 
-	radio->curfreq = f->frequency;
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 
-	retval = dsbr100_setfreq(radio);
-	if (retval < 0)
-		dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
-	return 0;
+	return dsbr100_setfreq(radio, clamp_t(unsigned, f->frequency,
+			FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
@@ -384,90 +230,26 @@
 {
 	struct dsbr100_device *radio = video_drvdata(file);
 
+	if (f->tuner)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = radio->curfreq;
 	return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-				struct v4l2_queryctrl *qc)
+static int usb_dsbr100_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	}
-
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct dsbr100_device *radio = video_drvdata(file);
+	struct dsbr100_device *radio =
+		container_of(ctrl->handler, struct dsbr100_device, hdl);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = radio->status;
-		return 0;
+		radio->muted = ctrl->val;
+		return radio->muted ? dsbr100_stop(radio) : dsbr100_start(radio);
 	}
 	return -EINVAL;
 }
 
-static int vidioc_s_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct dsbr100_device *radio = video_drvdata(file);
-	int retval;
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value) {
-			retval = dsbr100_stop(radio);
-			if (retval < 0) {
-				dev_warn(&radio->usbdev->dev,
-					 "Radio did not respond properly\n");
-				return -EBUSY;
-			}
-		} else {
-			retval = dsbr100_start(radio);
-			if (retval < 0) {
-				dev_warn(&radio->usbdev->dev,
-					 "Radio did not respond properly\n");
-				return -EBUSY;
-			}
-		}
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-				struct v4l2_audio *a)
-{
-	if (a->index > 1)
-		return -EINVAL;
-
-	strcpy(a->name, "Radio");
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
 
 /* USB subsystem interface begins here */
 
@@ -481,8 +263,17 @@
 {
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
 
-	v4l2_device_get(&radio->v4l2_dev);
 	mutex_lock(&radio->v4l2_lock);
+	/*
+	 * Disconnect is also called on unload, and in that case we need to
+	 * mute the device. This call will silently fail if it is called
+	 * after a physical disconnect.
+	 */
+	usb_control_msg(radio->usbdev,
+		usb_rcvctrlpipe(radio->usbdev, 0),
+		DSB100_ONOFF,
+		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+		0x00, 0x00, radio->transfer_buffer, 8, 300);
 	usb_set_intfdata(intf, NULL);
 	video_unregister_device(&radio->videodev);
 	v4l2_device_disconnect(&radio->v4l2_dev);
@@ -495,25 +286,13 @@
 static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
-	int retval;
 
 	mutex_lock(&radio->v4l2_lock);
-	if (radio->status == STARTED) {
-		retval = dsbr100_stop(radio);
-		if (retval < 0)
-			dev_warn(&intf->dev, "dsbr100_stop failed\n");
-
-		/* After dsbr100_stop() status set to STOPPED.
-		 * If we want driver to start radio on resume
-		 * we set status equal to STARTED.
-		 * On resume we will check status and run radio if needed.
-		 */
-		radio->status = STARTED;
-	}
+	if (!radio->muted && dsbr100_stop(radio) < 0)
+		dev_warn(&intf->dev, "dsbr100_stop failed\n");
 	mutex_unlock(&radio->v4l2_lock);
 
 	dev_info(&intf->dev, "going into suspend..\n");
-
 	return 0;
 }
 
@@ -521,18 +300,13 @@
 static int usb_dsbr100_resume(struct usb_interface *intf)
 {
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
-	int retval;
 
 	mutex_lock(&radio->v4l2_lock);
-	if (radio->status == STARTED) {
-		retval = dsbr100_start(radio);
-		if (retval < 0)
-			dev_warn(&intf->dev, "dsbr100_start failed\n");
-	}
+	if (!radio->muted && dsbr100_start(radio) < 0)
+		dev_warn(&intf->dev, "dsbr100_start failed\n");
 	mutex_unlock(&radio->v4l2_lock);
 
 	dev_info(&intf->dev, "coming out of suspend..\n");
-
 	return 0;
 }
 
@@ -541,15 +315,23 @@
 {
 	struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev);
 
+	v4l2_ctrl_handler_free(&radio->hdl);
 	v4l2_device_unregister(&radio->v4l2_dev);
 	kfree(radio->transfer_buffer);
 	kfree(radio);
 }
 
+static const struct v4l2_ctrl_ops usb_dsbr100_ctrl_ops = {
+	.s_ctrl = usb_dsbr100_s_ctrl,
+};
+
 /* File system interface */
 static const struct v4l2_file_operations usb_dsbr100_fops = {
 	.owner		= THIS_MODULE,
 	.unlocked_ioctl	= video_ioctl2,
+	.open           = v4l2_fh_open,
+	.release        = v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
 };
 
 static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
@@ -558,13 +340,9 @@
 	.vidioc_s_tuner     = vidioc_s_tuner,
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_log_status  = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 /* check if the device is present and register with v4l and usb if it is */
@@ -593,11 +371,17 @@
 	retval = v4l2_device_register(&intf->dev, v4l2_dev);
 	if (retval < 0) {
 		v4l2_err(v4l2_dev, "couldn't register v4l2_device\n");
-		kfree(radio->transfer_buffer);
-		kfree(radio);
-		return retval;
+		goto err_reg_dev;
 	}
 
+	v4l2_ctrl_handler_init(&radio->hdl, 1);
+	v4l2_ctrl_new_std(&radio->hdl, &usb_dsbr100_ctrl_ops,
+			  V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	if (radio->hdl.error) {
+		retval = radio->hdl.error;
+		v4l2_err(v4l2_dev, "couldn't register control\n");
+		goto err_reg_ctrl;
+	}
 	mutex_init(&radio->v4l2_lock);
 	strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name));
 	radio->videodev.v4l2_dev = v4l2_dev;
@@ -605,28 +389,46 @@
 	radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
 	radio->videodev.release = video_device_release_empty;
 	radio->videodev.lock = &radio->v4l2_lock;
+	radio->videodev.ctrl_handler = &radio->hdl;
+	set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
 
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->curfreq = FREQ_MIN * FREQ_MUL;
-	radio->status = STOPPED;
+	radio->muted = true;
 
 	video_set_drvdata(&radio->videodev, radio);
+	usb_set_intfdata(intf, radio);
 
 	retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
-	if (retval < 0) {
-		v4l2_err(v4l2_dev, "couldn't register video device\n");
-		v4l2_device_unregister(v4l2_dev);
-		kfree(radio->transfer_buffer);
-		kfree(radio);
-		return -EIO;
-	}
-	usb_set_intfdata(intf, radio);
-	return 0;
+	if (retval == 0)
+		return 0;
+	v4l2_err(v4l2_dev, "couldn't register video device\n");
+
+err_reg_ctrl:
+	v4l2_ctrl_handler_free(&radio->hdl);
+	v4l2_device_unregister(v4l2_dev);
+err_reg_dev:
+	kfree(radio->transfer_buffer);
+	kfree(radio);
+	return retval;
 }
 
-module_usb_driver(usb_dsbr100_driver);
+static struct usb_device_id usb_dsbr100_device_table[] = {
+	{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
+	{ }						/* Terminating entry */
+};
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
+MODULE_DEVICE_TABLE(usb, usb_dsbr100_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_dsbr100_driver = {
+	.name			= "dsbr100",
+	.probe			= usb_dsbr100_probe,
+	.disconnect		= usb_dsbr100_disconnect,
+	.id_table		= usb_dsbr100_device_table,
+	.suspend		= usb_dsbr100_suspend,
+	.resume			= usb_dsbr100_resume,
+	.reset_resume		= usb_dsbr100_resume,
+};
+
+module_usb_driver(usb_dsbr100_driver);
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 2e639ce..235c0e3 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -29,6 +29,7 @@
 #include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <linux/mutex.h>
 #include <linux/io.h>		/* outb, outb_p			*/
+#include <linux/pnp.h>
 #include <linux/slab.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
@@ -283,6 +284,16 @@
 
 static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
 
+#ifdef CONFIG_PNP
+static struct pnp_device_id gemtek_pnp_devices[] = {
+	/* AOpen FX-3D/Pro Radio */
+	{.id = "ADS7183", .driver_data = 0},
+	{.id = ""}
+};
+
+MODULE_DEVICE_TABLE(pnp, gemtek_pnp_devices);
+#endif
+
 static struct radio_isa_driver gemtek_driver = {
 	.driver = {
 		.match		= radio_isa_match,
@@ -292,6 +303,14 @@
 			.name	= "radio-gemtek",
 		},
 	},
+#ifdef CONFIG_PNP
+	.pnp_driver = {
+		.name		= "radio-gemtek",
+		.id_table	= gemtek_pnp_devices,
+		.probe		= radio_isa_pnp_probe,
+		.remove		= radio_isa_pnp_remove,
+	},
+#endif
 	.io_params = io,
 	.radio_nr_params = radio_nr,
 	.io_ports = gemtek_ioports,
@@ -305,12 +324,18 @@
 static int __init gemtek_init(void)
 {
 	gemtek_driver.probe = probe;
+#ifdef CONFIG_PNP
+	pnp_register_driver(&gemtek_driver.pnp_driver);
+#endif
 	return isa_register_driver(&gemtek_driver.driver, GEMTEK_MAX);
 }
 
 static void __exit gemtek_exit(void)
 {
 	hardmute = 1;	/* Turn off PLL */
+#ifdef CONFIG_PNP
+	pnp_unregister_driver(&gemtek_driver.pnp_driver);
+#endif
 	isa_unregister_driver(&gemtek_driver.driver);
 }
 
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
index 06f9063..3c0067d 100644
--- a/drivers/media/radio/radio-isa.c
+++ b/drivers/media/radio/radio-isa.c
@@ -150,14 +150,6 @@
 	return 0;
 }
 
-static int radio_isa_subscribe_event(struct v4l2_fh *fh,
-				struct v4l2_event_subscription *sub)
-{
-	if (sub->type == V4L2_EVENT_CTRL)
-		return v4l2_event_subscribe(fh, sub, 0);
-	return -EINVAL;
-}
-
 static const struct v4l2_ctrl_ops radio_isa_ctrl_ops = {
 	.s_ctrl = radio_isa_s_ctrl,
 };
@@ -177,7 +169,7 @@
 	.vidioc_g_frequency = radio_isa_g_frequency,
 	.vidioc_s_frequency = radio_isa_s_frequency,
 	.vidioc_log_status  = radio_isa_log_status,
-	.vidioc_subscribe_event   = radio_isa_subscribe_event,
+	.vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
@@ -199,56 +191,31 @@
 	return false;
 }
 
-int radio_isa_probe(struct device *pdev, unsigned int dev)
+struct radio_isa_card *radio_isa_alloc(struct radio_isa_driver *drv,
+				struct device *pdev)
 {
-	struct radio_isa_driver *drv = pdev->platform_data;
-	const struct radio_isa_ops *ops = drv->ops;
 	struct v4l2_device *v4l2_dev;
-	struct radio_isa_card *isa;
-	int res;
+	struct radio_isa_card *isa = drv->ops->alloc();
+	if (!isa)
+		return NULL;
 
-	isa = drv->ops->alloc();
-	if (isa == NULL)
-		return -ENOMEM;
 	dev_set_drvdata(pdev, isa);
 	isa->drv = drv;
-	isa->io = drv->io_params[dev];
 	v4l2_dev = &isa->v4l2_dev;
 	strlcpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name));
 
-	if (drv->probe && ops->probe) {
-		int i;
+	return isa;
+}
 
-		for (i = 0; i < drv->num_of_io_ports; ++i) {
-			int io = drv->io_ports[i];
+int radio_isa_common_probe(struct radio_isa_card *isa, struct device *pdev,
+				int radio_nr, unsigned region_size)
+{
+	const struct radio_isa_driver *drv = isa->drv;
+	const struct radio_isa_ops *ops = drv->ops;
+	struct v4l2_device *v4l2_dev = &isa->v4l2_dev;
+	int res;
 
-			if (request_region(io, drv->region_size, v4l2_dev->name)) {
-				bool found = ops->probe(isa, io);
-
-				release_region(io, drv->region_size);
-				if (found) {
-					isa->io = io;
-					break;
-				}
-			}
-		}
-	}
-
-	if (!radio_isa_valid_io(drv, isa->io)) {
-		int i;
-
-		if (isa->io < 0)
-			return -ENODEV;
-		v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x",
-				drv->io_ports[0]);
-		for (i = 1; i < drv->num_of_io_ports; i++)
-			printk(KERN_CONT "/0x%03x", drv->io_ports[i]);
-		printk(KERN_CONT ".\n");
-		kfree(isa);
-		return -EINVAL;
-	}
-
-	if (!request_region(isa->io, drv->region_size, v4l2_dev->name)) {
+	if (!request_region(isa->io, region_size, v4l2_dev->name)) {
 		v4l2_err(v4l2_dev, "port 0x%x already in use\n", isa->io);
 		kfree(isa);
 		return -EBUSY;
@@ -299,42 +266,126 @@
 		res = ops->s_stereo(isa, isa->stereo);
 	if (res < 0) {
 		v4l2_err(v4l2_dev, "Could not setup card\n");
-		goto err_node_reg;
+		goto err_hdl;
 	}
-	res = video_register_device(&isa->vdev, VFL_TYPE_RADIO,
-					drv->radio_nr_params[dev]);
+	res = video_register_device(&isa->vdev, VFL_TYPE_RADIO, radio_nr);
+
 	if (res < 0) {
 		v4l2_err(v4l2_dev, "Could not register device node\n");
-		goto err_node_reg;
+		goto err_hdl;
 	}
 
 	v4l2_info(v4l2_dev, "Initialized radio card %s on port 0x%03x\n",
 			drv->card, isa->io);
 	return 0;
 
-err_node_reg:
-	v4l2_ctrl_handler_free(&isa->hdl);
 err_hdl:
-	v4l2_device_unregister(&isa->v4l2_dev);
+	v4l2_ctrl_handler_free(&isa->hdl);
 err_dev_reg:
-	release_region(isa->io, drv->region_size);
+	release_region(isa->io, region_size);
 	kfree(isa);
 	return res;
 }
-EXPORT_SYMBOL_GPL(radio_isa_probe);
 
-int radio_isa_remove(struct device *pdev, unsigned int dev)
+int radio_isa_common_remove(struct radio_isa_card *isa, unsigned region_size)
 {
-	struct radio_isa_card *isa = dev_get_drvdata(pdev);
 	const struct radio_isa_ops *ops = isa->drv->ops;
 
 	ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0);
 	video_unregister_device(&isa->vdev);
 	v4l2_ctrl_handler_free(&isa->hdl);
 	v4l2_device_unregister(&isa->v4l2_dev);
-	release_region(isa->io, isa->drv->region_size);
+	release_region(isa->io, region_size);
 	v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card);
 	kfree(isa);
 	return 0;
 }
+
+int radio_isa_probe(struct device *pdev, unsigned int dev)
+{
+	struct radio_isa_driver *drv = pdev->platform_data;
+	const struct radio_isa_ops *ops = drv->ops;
+	struct v4l2_device *v4l2_dev;
+	struct radio_isa_card *isa;
+
+	isa = radio_isa_alloc(drv, pdev);
+	if (!isa)
+		return -ENOMEM;
+	isa->io = drv->io_params[dev];
+	v4l2_dev = &isa->v4l2_dev;
+
+	if (drv->probe && ops->probe) {
+		int i;
+
+		for (i = 0; i < drv->num_of_io_ports; ++i) {
+			int io = drv->io_ports[i];
+
+			if (request_region(io, drv->region_size, v4l2_dev->name)) {
+				bool found = ops->probe(isa, io);
+
+				release_region(io, drv->region_size);
+				if (found) {
+					isa->io = io;
+					break;
+				}
+			}
+		}
+	}
+
+	if (!radio_isa_valid_io(drv, isa->io)) {
+		int i;
+
+		if (isa->io < 0)
+			return -ENODEV;
+		v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x",
+				drv->io_ports[0]);
+		for (i = 1; i < drv->num_of_io_ports; i++)
+			printk(KERN_CONT "/0x%03x", drv->io_ports[i]);
+		printk(KERN_CONT ".\n");
+		kfree(isa);
+		return -EINVAL;
+	}
+
+	return radio_isa_common_probe(isa, pdev, drv->radio_nr_params[dev],
+					drv->region_size);
+}
+EXPORT_SYMBOL_GPL(radio_isa_probe);
+
+int radio_isa_remove(struct device *pdev, unsigned int dev)
+{
+	struct radio_isa_card *isa = dev_get_drvdata(pdev);
+
+	return radio_isa_common_remove(isa, isa->drv->region_size);
+}
 EXPORT_SYMBOL_GPL(radio_isa_remove);
+
+#ifdef CONFIG_PNP
+int radio_isa_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+{
+	struct pnp_driver *pnp_drv = to_pnp_driver(dev->dev.driver);
+	struct radio_isa_driver *drv = container_of(pnp_drv,
+					struct radio_isa_driver, pnp_driver);
+	struct radio_isa_card *isa;
+
+	if (!pnp_port_valid(dev, 0))
+		return -ENODEV;
+
+	isa = radio_isa_alloc(drv, &dev->dev);
+	if (!isa)
+		return -ENOMEM;
+
+	isa->io = pnp_port_start(dev, 0);
+
+	return radio_isa_common_probe(isa, &dev->dev, drv->radio_nr_params[0],
+					pnp_port_len(dev, 0));
+}
+EXPORT_SYMBOL_GPL(radio_isa_pnp_probe);
+
+void radio_isa_pnp_remove(struct pnp_dev *dev)
+{
+	struct radio_isa_card *isa = dev_get_drvdata(&dev->dev);
+
+	radio_isa_common_remove(isa, pnp_port_len(dev, 0));
+}
+EXPORT_SYMBOL_GPL(radio_isa_pnp_remove);
+#endif
diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h
index 8a0ea84..ba4c01f 100644
--- a/drivers/media/radio/radio-isa.h
+++ b/drivers/media/radio/radio-isa.h
@@ -24,6 +24,7 @@
 #define _RADIO_ISA_H_
 
 #include <linux/isa.h>
+#include <linux/pnp.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
@@ -76,6 +77,9 @@
 /* Top level structure needed to instantiate the cards */
 struct radio_isa_driver {
 	struct isa_driver driver;
+#ifdef CONFIG_PNP
+	struct pnp_driver pnp_driver;
+#endif
 	const struct radio_isa_ops *ops;
 	/* The module_param_array with the specified I/O ports */
 	int *io_params;
@@ -101,5 +105,10 @@
 int radio_isa_match(struct device *pdev, unsigned int dev);
 int radio_isa_probe(struct device *pdev, unsigned int dev);
 int radio_isa_remove(struct device *pdev, unsigned int dev);
+#ifdef CONFIG_PNP
+int radio_isa_pnp_probe(struct pnp_dev *dev,
+			const struct pnp_device_id *dev_id);
+void radio_isa_pnp_remove(struct pnp_dev *dev);
+#endif
 
 #endif
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
index 55bd1d2..79adf3e 100644
--- a/drivers/media/radio/radio-keene.c
+++ b/drivers/media/radio/radio-keene.c
@@ -28,7 +28,6 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
 #include <linux/usb.h>
-#include <linux/version.h>
 #include <linux/mutex.h>
 
 /* driver and module definitions */
@@ -149,7 +148,6 @@
 {
 	struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf));
 
-	v4l2_device_get(&radio->v4l2_dev);
 	mutex_lock(&radio->lock);
 	usb_set_intfdata(intf, NULL);
 	video_unregister_device(&radio->vdev);
@@ -158,6 +156,23 @@
 	v4l2_device_put(&radio->v4l2_dev);
 }
 
+static int usb_keene_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf));
+
+	return keene_cmd_main(radio, 0, false);
+}
+
+static int usb_keene_resume(struct usb_interface *intf)
+{
+	struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf));
+
+	mdelay(50);
+	keene_cmd_set(radio);
+	keene_cmd_main(radio, radio->curfreq, true);
+	return 0;
+}
+
 static int vidioc_querycap(struct file *file, void *priv,
 					struct v4l2_capability *v)
 {
@@ -256,18 +271,6 @@
 	return -EINVAL;
 }
 
-static int vidioc_subscribe_event(struct v4l2_fh *fh,
-				struct v4l2_event_subscription *sub)
-{
-	switch (sub->type) {
-	case V4L2_EVENT_CTRL:
-		return v4l2_event_subscribe(fh, sub, 0);
-	default:
-		return -EINVAL;
-	}
-}
-
-
 /* File system interface */
 static const struct v4l2_file_operations usb_keene_fops = {
 	.owner		= THIS_MODULE,
@@ -288,7 +291,7 @@
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
 	.vidioc_log_status = v4l2_ctrl_log_status,
-	.vidioc_subscribe_event = vidioc_subscribe_event,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
@@ -404,6 +407,9 @@
 	.probe			= usb_keene_probe,
 	.disconnect		= usb_keene_disconnect,
 	.id_table		= usb_keene_device_table,
+	.suspend		= usb_keene_suspend,
+	.resume			= usb_keene_resume,
+	.reset_resume		= usb_keene_resume,
 };
 
 static int __init keene_init(void)
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index a860a72..94cb6bc 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -62,6 +62,8 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
 
@@ -101,12 +103,17 @@
  * List isn't full and will be updated with implementation of new functions
  */
 #define AMRADIO_SET_FREQ	0xa4
+#define AMRADIO_GET_READY_FLAG	0xa5
+#define AMRADIO_GET_SIGNAL	0xa7
+#define AMRADIO_GET_FREQ	0xa8
+#define AMRADIO_SET_SEARCH_UP	0xa9
+#define AMRADIO_SET_SEARCH_DOWN	0xaa
 #define AMRADIO_SET_MUTE	0xab
+#define AMRADIO_SET_RIGHT_MUTE	0xac
+#define AMRADIO_SET_LEFT_MUTE	0xad
 #define AMRADIO_SET_MONO	0xae
-
-/* Comfortable defines for amradio_set_mute */
-#define AMRADIO_START		0x00
-#define AMRADIO_STOP		0x01
+#define AMRADIO_SET_SEARCH_LVL	0xb0
+#define AMRADIO_STOP_SEARCH	0xb1
 
 /* Comfortable defines for amradio_set_stereo */
 #define WANT_STEREO		0x00
@@ -117,29 +124,20 @@
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(radio_nr, "Radio Nr");
 
-static int usb_amradio_probe(struct usb_interface *intf,
-			     const struct usb_device_id *id);
-static void usb_amradio_disconnect(struct usb_interface *intf);
-static int usb_amradio_open(struct file *file);
-static int usb_amradio_close(struct file *file);
-static int usb_amradio_suspend(struct usb_interface *intf,
-				pm_message_t message);
-static int usb_amradio_resume(struct usb_interface *intf);
-
 /* Data for one (physical) device */
 struct amradio_device {
 	/* reference to USB and video device */
 	struct usb_device *usbdev;
 	struct usb_interface *intf;
-	struct video_device videodev;
+	struct video_device vdev;
 	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler hdl;
 
-	unsigned char *buffer;
+	u8 *buffer;
 	struct mutex lock;	/* buffer locking */
 	int curfreq;
 	int stereo;
 	int muted;
-	int initialized;
 };
 
 static inline struct amradio_device *to_amradio_dev(struct v4l2_device *v4l2_dev)
@@ -147,29 +145,8 @@
 	return container_of(v4l2_dev, struct amradio_device, v4l2_dev);
 }
 
-/* USB Device ID List */
-static struct usb_device_id usb_amradio_device_table[] = {
-	{USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
-							USB_CLASS_HID, 0, 0) },
-	{ }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
-
-/* USB subsystem interface */
-static struct usb_driver usb_amradio_driver = {
-	.name			= MR800_DRIVER_NAME,
-	.probe			= usb_amradio_probe,
-	.disconnect		= usb_amradio_disconnect,
-	.suspend		= usb_amradio_suspend,
-	.resume			= usb_amradio_resume,
-	.reset_resume		= usb_amradio_resume,
-	.id_table		= usb_amradio_device_table,
-	.supports_autosuspend	= 1,
-};
-
-/* switch on/off the radio. Send 8 bytes to device */
-static int amradio_set_mute(struct amradio_device *radio, char argument)
+static int amradio_send_cmd(struct amradio_device *radio, u8 cmd, u8 arg,
+		u8 *extra, u8 extralen, bool reply)
 {
 	int retval;
 	int size;
@@ -177,99 +154,92 @@
 	radio->buffer[0] = 0x00;
 	radio->buffer[1] = 0x55;
 	radio->buffer[2] = 0xaa;
-	radio->buffer[3] = 0x00;
-	radio->buffer[4] = AMRADIO_SET_MUTE;
-	radio->buffer[5] = argument;
+	radio->buffer[3] = extralen;
+	radio->buffer[4] = cmd;
+	radio->buffer[5] = arg;
 	radio->buffer[6] = 0x00;
-	radio->buffer[7] = 0x00;
+	radio->buffer[7] = extra || reply ? 8 : 0;
 
 	retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
-		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+		radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
 
 	if (retval < 0 || size != BUFFER_LENGTH) {
-		amradio_dev_warn(&radio->videodev.dev, "set mute failed\n");
-		return retval;
+		if (video_is_registered(&radio->vdev))
+			amradio_dev_warn(&radio->vdev.dev,
+					"cmd %02x failed\n", cmd);
+		return retval ? retval : -EIO;
 	}
+	if (!extra && !reply)
+		return 0;
 
-	radio->muted = argument;
+	if (extra) {
+		memcpy(radio->buffer, extra, extralen);
+		memset(radio->buffer + extralen, 0, 8 - extralen);
+		retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+			radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
+	} else {
+		memset(radio->buffer, 0, 8);
+		retval = usb_bulk_msg(radio->usbdev, usb_rcvbulkpipe(radio->usbdev, 0x81),
+			radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
+	}
+	if (retval == 0 && size == BUFFER_LENGTH)
+		return 0;
+	if (video_is_registered(&radio->vdev) && cmd != AMRADIO_GET_READY_FLAG)
+		amradio_dev_warn(&radio->vdev.dev, "follow-up to cmd %02x failed\n", cmd);
+	return retval ? retval : -EIO;
+}
 
-	return retval;
+/* switch on/off the radio. Send 8 bytes to device */
+static int amradio_set_mute(struct amradio_device *radio, bool mute)
+{
+	int ret = amradio_send_cmd(radio,
+			AMRADIO_SET_MUTE, mute, NULL, 0, false);
+
+	if (!ret)
+		radio->muted = mute;
+	return ret;
 }
 
 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int amradio_setfreq(struct amradio_device *radio, int freq)
+static int amradio_set_freq(struct amradio_device *radio, int freq)
 {
-	int retval;
-	int size;
 	unsigned short freq_send = 0x10 + (freq >> 3) / 25;
-
-	radio->buffer[0] = 0x00;
-	radio->buffer[1] = 0x55;
-	radio->buffer[2] = 0xaa;
-	radio->buffer[3] = 0x03;
-	radio->buffer[4] = AMRADIO_SET_FREQ;
-	radio->buffer[5] = 0x00;
-	radio->buffer[6] = 0x00;
-	radio->buffer[7] = 0x08;
-
-	retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
-		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
-
-	if (retval < 0 || size != BUFFER_LENGTH)
-		goto out_err;
+	u8 buf[3];
+	int retval;
 
 	/* frequency is calculated from freq_send and placed in first 2 bytes */
-	radio->buffer[0] = (freq_send >> 8) & 0xff;
-	radio->buffer[1] = freq_send & 0xff;
-	radio->buffer[2] = 0x01;
-	radio->buffer[3] = 0x00;
-	radio->buffer[4] = 0x00;
-	/* 5 and 6 bytes of buffer already = 0x00 */
-	radio->buffer[7] = 0x00;
+	buf[0] = (freq_send >> 8) & 0xff;
+	buf[1] = freq_send & 0xff;
+	buf[2] = 0x01;
 
-	retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
-		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
-
-	if (retval < 0 || size != BUFFER_LENGTH)
-		goto out_err;
-
+	retval = amradio_send_cmd(radio, AMRADIO_SET_FREQ, 0, buf, 3, false);
+	if (retval)
+		return retval;
 	radio->curfreq = freq;
-	goto out;
-
-out_err:
-	amradio_dev_warn(&radio->videodev.dev, "set frequency failed\n");
-out:
-	return retval;
+	msleep(40);
+	return 0;
 }
 
-static int amradio_set_stereo(struct amradio_device *radio, char argument)
+static int amradio_set_stereo(struct amradio_device *radio, bool stereo)
 {
-	int retval;
-	int size;
+	int ret = amradio_send_cmd(radio,
+			AMRADIO_SET_MONO, !stereo, NULL, 0, false);
 
-	radio->buffer[0] = 0x00;
-	radio->buffer[1] = 0x55;
-	radio->buffer[2] = 0xaa;
-	radio->buffer[3] = 0x00;
-	radio->buffer[4] = AMRADIO_SET_MONO;
-	radio->buffer[5] = argument;
-	radio->buffer[6] = 0x00;
-	radio->buffer[7] = 0x00;
+	if (!ret)
+		radio->stereo = stereo;
+	return ret;
+}
 
-	retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
-		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+static int amradio_get_stat(struct amradio_device *radio, bool *is_stereo, u32 *signal)
+{
+	int ret = amradio_send_cmd(radio,
+			AMRADIO_GET_SIGNAL, 0, NULL, 0, true);
 
-	if (retval < 0 || size != BUFFER_LENGTH) {
-		amradio_dev_warn(&radio->videodev.dev, "set stereo failed\n");
-		return retval;
-	}
-
-	if (argument == WANT_STEREO)
-		radio->stereo = 1;
-	else
-		radio->stereo = 0;
-
-	return retval;
+	if (ret)
+		return ret;
+	*is_stereo = radio->buffer[2] >> 7;
+	*signal = (radio->buffer[3] & 0xf0) << 8;
+	return 0;
 }
 
 /* Handle unplugging the device.
@@ -282,25 +252,26 @@
 	struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 
 	mutex_lock(&radio->lock);
-	/* increase the device node's refcount */
-	get_device(&radio->videodev.dev);
+	video_unregister_device(&radio->vdev);
+	amradio_set_mute(radio, true);
+	usb_set_intfdata(intf, NULL);
 	v4l2_device_disconnect(&radio->v4l2_dev);
-	video_unregister_device(&radio->videodev);
 	mutex_unlock(&radio->lock);
-	/* decrease the device node's refcount, allowing it to be released */
-	put_device(&radio->videodev.dev);
+	v4l2_device_put(&radio->v4l2_dev);
 }
 
 /* vidioc_querycap - query device capabilities */
 static int vidioc_querycap(struct file *file, void *priv,
 					struct v4l2_capability *v)
 {
-	struct amradio_device *radio = file->private_data;
+	struct amradio_device *radio = video_drvdata(file);
 
 	strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
 	strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
 	usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER;
+	v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER |
+					V4L2_CAP_HW_FREQ_SEEK;
+	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -308,44 +279,34 @@
 static int vidioc_g_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *v)
 {
-	struct amradio_device *radio = file->private_data;
+	struct amradio_device *radio = video_drvdata(file);
+	bool is_stereo = false;
 	int retval;
 
 	if (v->index > 0)
 		return -EINVAL;
 
-/* TODO: Add function which look is signal stereo or not
- * 	amradio_getstat(radio);
- */
-
-/* we call amradio_set_stereo to set radio->stereo
- * Honestly, amradio_getstat should cover this in future and
- * amradio_set_stereo shouldn't be here
- */
-	retval = amradio_set_stereo(radio, WANT_STEREO);
+	v->signal = 0;
+	retval = amradio_get_stat(radio, &is_stereo, &v->signal);
+	if (retval)
+		return retval;
 
 	strcpy(v->name, "FM");
 	v->type = V4L2_TUNER_RADIO;
 	v->rangelow = FREQ_MIN * FREQ_MUL;
 	v->rangehigh = FREQ_MAX * FREQ_MUL;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	if (radio->stereo)
-		v->audmode = V4L2_TUNER_MODE_STEREO;
-	else
-		v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xffff;     /* Can't get the signal strength, sad.. */
-	v->afc = 0; /* Don't know what is this */
-
-	return retval;
+	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+	v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+	v->audmode = radio->stereo ?
+		V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+	return 0;
 }
 
 /* vidioc_s_tuner - set tuner attributes */
 static int vidioc_s_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *v)
 {
-	struct amradio_device *radio = file->private_data;
-	int retval = -EINVAL;
+	struct amradio_device *radio = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -353,34 +314,31 @@
 	/* mono/stereo selector */
 	switch (v->audmode) {
 	case V4L2_TUNER_MODE_MONO:
-		retval = amradio_set_stereo(radio, WANT_MONO);
-		break;
-	case V4L2_TUNER_MODE_STEREO:
-		retval = amradio_set_stereo(radio, WANT_STEREO);
-		break;
+		return amradio_set_stereo(radio, WANT_MONO);
+	default:
+		return amradio_set_stereo(radio, WANT_STEREO);
 	}
-
-	return retval;
 }
 
 /* vidioc_s_frequency - set tuner radio frequency */
 static int vidioc_s_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct amradio_device *radio = file->private_data;
+	struct amradio_device *radio = video_drvdata(file);
 
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+	if (f->tuner != 0)
 		return -EINVAL;
-	return amradio_setfreq(radio, f->frequency);
+	return amradio_set_freq(radio, clamp_t(unsigned, f->frequency,
+				FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
 }
 
 /* vidioc_g_frequency - get tuner radio frequency */
 static int vidioc_g_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct amradio_device *radio = file->private_data;
+	struct amradio_device *radio = video_drvdata(file);
 
-	if (f->tuner != 0)
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
 		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = radio->curfreq;
@@ -388,148 +346,101 @@
 	return 0;
 }
 
-/* vidioc_queryctrl - enumerate control items */
-static int vidioc_queryctrl(struct file *file, void *priv,
-				struct v4l2_queryctrl *qc)
+static int vidioc_s_hw_freq_seek(struct file *file, void *priv,
+		struct v4l2_hw_freq_seek *seek)
 {
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+	static u8 buf[8] = {
+		0x3d, 0x32, 0x0f, 0x08, 0x3d, 0x32, 0x0f, 0x08
+	};
+	struct amradio_device *radio = video_drvdata(file);
+	unsigned long timeout;
+	int retval;
+
+	if (seek->tuner != 0 || !seek->wrap_around)
+		return -EINVAL;
+
+	retval = amradio_send_cmd(radio,
+			AMRADIO_SET_SEARCH_LVL, 0, buf, 8, false);
+	if (retval)
+		return retval;
+	amradio_set_freq(radio, radio->curfreq);
+	retval = amradio_send_cmd(radio,
+		seek->seek_upward ? AMRADIO_SET_SEARCH_UP : AMRADIO_SET_SEARCH_DOWN,
+		0, NULL, 0, false);
+	if (retval)
+		return retval;
+	timeout = jiffies + msecs_to_jiffies(30000);
+	for (;;) {
+		if (time_after(jiffies, timeout)) {
+			retval = -EAGAIN;
+			break;
+		}
+		if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		retval = amradio_send_cmd(radio, AMRADIO_GET_READY_FLAG,
+				0, NULL, 0, true);
+		if (retval)
+			continue;
+		amradio_send_cmd(radio, AMRADIO_GET_FREQ, 0, NULL, 0, true);
+		if (radio->buffer[1] || radio->buffer[2]) {
+			radio->curfreq = (radio->buffer[1] << 8) | radio->buffer[2];
+			radio->curfreq = (radio->curfreq - 0x10) * 200;
+			amradio_send_cmd(radio, AMRADIO_STOP_SEARCH,
+					0, NULL, 0, false);
+			amradio_set_freq(radio, radio->curfreq);
+			retval = 0;
+			break;
+		}
 	}
-
-	return -EINVAL;
-}
-
-/* vidioc_g_ctrl - get the value of a control */
-static int vidioc_g_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct amradio_device *radio = file->private_data;
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = radio->muted;
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-/* vidioc_s_ctrl - set the value of a control */
-static int vidioc_s_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct amradio_device *radio = file->private_data;
-	int retval = -EINVAL;
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
-			retval = amradio_set_mute(radio, AMRADIO_STOP);
-		else
-			retval = amradio_set_mute(radio, AMRADIO_START);
-
-		break;
-	}
-
+	amradio_send_cmd(radio, AMRADIO_STOP_SEARCH, 0, NULL, 0, false);
+	amradio_set_freq(radio, radio->curfreq);
 	return retval;
 }
 
-/* vidioc_g_audio - get audio attributes */
-static int vidioc_g_audio(struct file *file, void *priv,
-				struct v4l2_audio *a)
+static int usb_amradio_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	if (a->index > 1)
-		return -EINVAL;
+	struct amradio_device *radio =
+		container_of(ctrl->handler, struct amradio_device, hdl);
 
-	strcpy(a->name, "Radio");
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		return amradio_set_mute(radio, ctrl->val);
+	}
 
-/* vidioc_s_audio - set audio attributes  */
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	if (a->index != 0)
-		return -EINVAL;
-	return 0;
-}
-
-/* vidioc_g_input - get input */
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-/* vidioc_s_input - set input */
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	if (i != 0)
-		return -EINVAL;
-	return 0;
+	return -EINVAL;
 }
 
 static int usb_amradio_init(struct amradio_device *radio)
 {
 	int retval;
 
-	retval = amradio_set_mute(radio, AMRADIO_STOP);
+	retval = amradio_set_mute(radio, true);
 	if (retval)
 		goto out_err;
-
-	retval = amradio_set_stereo(radio, WANT_STEREO);
+	retval = amradio_set_stereo(radio, true);
 	if (retval)
 		goto out_err;
-
-	radio->initialized = 1;
-	goto out;
+	retval = amradio_set_freq(radio, radio->curfreq);
+	if (retval)
+		goto out_err;
+	return 0;
 
 out_err:
-	amradio_dev_err(&radio->videodev.dev, "initialization failed\n");
-out:
+	amradio_dev_err(&radio->vdev.dev, "initialization failed\n");
 	return retval;
 }
 
-/* open device - amradio_start() and amradio_setfreq() */
-static int usb_amradio_open(struct file *file)
-{
-	struct amradio_device *radio = video_drvdata(file);
-	int retval;
-
-	file->private_data = radio;
-	retval = usb_autopm_get_interface(radio->intf);
-	if (retval)
-		return retval;
-
-	if (unlikely(!radio->initialized)) {
-		retval = usb_amradio_init(radio);
-		if (retval)
-			usb_autopm_put_interface(radio->intf);
-	}
-	return retval;
-}
-
-/*close device */
-static int usb_amradio_close(struct file *file)
-{
-	struct amradio_device *radio = file->private_data;
-
-	if (video_is_registered(&radio->videodev))
-		usb_autopm_put_interface(radio->intf);
-	return 0;
-}
-
 /* Suspend device - stop device. Need to be checked and fixed */
 static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 
 	mutex_lock(&radio->lock);
-	if (!radio->muted && radio->initialized) {
-		amradio_set_mute(radio, AMRADIO_STOP);
-		radio->muted = 0;
+	if (!radio->muted) {
+		amradio_set_mute(radio, true);
+		radio->muted = false;
 	}
 	mutex_unlock(&radio->lock);
 
@@ -543,31 +454,28 @@
 	struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 
 	mutex_lock(&radio->lock);
-	if (unlikely(!radio->initialized))
-		goto unlock;
-
-	if (radio->stereo)
-		amradio_set_stereo(radio, WANT_STEREO);
-	else
-		amradio_set_stereo(radio, WANT_MONO);
-
-	amradio_setfreq(radio, radio->curfreq);
+	amradio_set_stereo(radio, radio->stereo);
+	amradio_set_freq(radio, radio->curfreq);
 
 	if (!radio->muted)
-		amradio_set_mute(radio, AMRADIO_START);
+		amradio_set_mute(radio, false);
 
-unlock:
 	mutex_unlock(&radio->lock);
 
 	dev_info(&intf->dev, "coming out of suspend..\n");
 	return 0;
 }
 
+static const struct v4l2_ctrl_ops usb_amradio_ctrl_ops = {
+	.s_ctrl = usb_amradio_s_ctrl,
+};
+
 /* File system interface */
 static const struct v4l2_file_operations usb_amradio_fops = {
 	.owner		= THIS_MODULE,
-	.open		= usb_amradio_open,
-	.release	= usb_amradio_close,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
 	.unlocked_ioctl	= video_ioctl2,
 };
 
@@ -577,20 +485,19 @@
 	.vidioc_s_tuner     = vidioc_s_tuner,
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
+	.vidioc_log_status  = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
-static void usb_amradio_video_device_release(struct video_device *videodev)
+static void usb_amradio_release(struct v4l2_device *v4l2_dev)
 {
-	struct amradio_device *radio = video_get_drvdata(videodev);
+	struct amradio_device *radio = to_amradio_dev(v4l2_dev);
 
 	/* free rest memory */
+	v4l2_ctrl_handler_free(&radio->hdl);
+	v4l2_device_unregister(&radio->v4l2_dev);
 	kfree(radio->buffer);
 	kfree(radio);
 }
@@ -624,23 +531,38 @@
 		goto err_v4l2;
 	}
 
+	v4l2_ctrl_handler_init(&radio->hdl, 1);
+	v4l2_ctrl_new_std(&radio->hdl, &usb_amradio_ctrl_ops,
+			  V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	if (radio->hdl.error) {
+		retval = radio->hdl.error;
+		dev_err(&intf->dev, "couldn't register control\n");
+		goto err_ctrl;
+	}
 	mutex_init(&radio->lock);
 
-	strlcpy(radio->videodev.name, radio->v4l2_dev.name,
-		sizeof(radio->videodev.name));
-	radio->videodev.v4l2_dev = &radio->v4l2_dev;
-	radio->videodev.fops = &usb_amradio_fops;
-	radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops;
-	radio->videodev.release = usb_amradio_video_device_release;
-	radio->videodev.lock = &radio->lock;
+	radio->v4l2_dev.ctrl_handler = &radio->hdl;
+	radio->v4l2_dev.release = usb_amradio_release;
+	strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+		sizeof(radio->vdev.name));
+	radio->vdev.v4l2_dev = &radio->v4l2_dev;
+	radio->vdev.fops = &usb_amradio_fops;
+	radio->vdev.ioctl_ops = &usb_amradio_ioctl_ops;
+	radio->vdev.release = video_device_release_empty;
+	radio->vdev.lock = &radio->lock;
+	set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
 
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->intf = intf;
+	usb_set_intfdata(intf, &radio->v4l2_dev);
 	radio->curfreq = 95.16 * FREQ_MUL;
 
-	video_set_drvdata(&radio->videodev, radio);
+	video_set_drvdata(&radio->vdev, radio);
+	retval = usb_amradio_init(radio);
+	if (retval)
+		goto err_vdev;
 
-	retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
+	retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO,
 					radio_nr);
 	if (retval < 0) {
 		dev_err(&intf->dev, "could not register video device\n");
@@ -650,6 +572,8 @@
 	return 0;
 
 err_vdev:
+	v4l2_ctrl_handler_free(&radio->hdl);
+err_ctrl:
 	v4l2_device_unregister(&radio->v4l2_dev);
 err_v4l2:
 	kfree(radio->buffer);
@@ -659,4 +583,24 @@
 	return retval;
 }
 
+/* USB Device ID List */
+static struct usb_device_id usb_amradio_device_table[] = {
+	{ USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
+							USB_CLASS_HID, 0, 0) },
+	{ }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_amradio_driver = {
+	.name			= MR800_DRIVER_NAME,
+	.probe			= usb_amradio_probe,
+	.disconnect		= usb_amradio_disconnect,
+	.suspend		= usb_amradio_suspend,
+	.resume			= usb_amradio_resume,
+	.reset_resume		= usb_amradio_resume,
+	.id_table		= usb_amradio_device_table,
+};
+
 module_usb_driver(usb_amradio_driver);
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index b275c5d..b1f844c 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -17,6 +17,7 @@
 #include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <linux/mutex.h>
 #include <linux/io.h>		/* outb, outb_p			*/
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include "radio-isa.h"
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 22c5743..a81d723 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -1,4 +1,4 @@
-/* SF16-FMI and SF16-FMP radio driver for Linux radio support
+/* SF16-FMI, SF16-FMP and SF16-FMD radio driver for Linux radio support
  * heavily based on rtrack driver...
  * (c) 1997 M. Kirkwood
  * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
@@ -11,7 +11,7 @@
  *
  *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
  *  No volume control - only mute/unmute - you have to use line volume
- *  control on SB-part of SF16-FMI/SF16-FMP
+ *  control on SB-part of SF16-FMI/SF16-FMP/SF16-FMD
  *
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
@@ -29,7 +29,7 @@
 #include <media/v4l2-ioctl.h>
 
 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
-MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio.");
+MODULE_DESCRIPTION("A driver for the SF16-FMI, SF16-FMP and SF16-FMD radio.");
 MODULE_LICENSE("GPL");
 MODULE_VERSION("0.0.3");
 
@@ -37,7 +37,7 @@
 static int radio_nr = -1;
 
 module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)");
+MODULE_PARM_DESC(io, "I/O address of the SF16-FMI/SF16-FMP/SF16-FMD card (0x284 or 0x384)");
 module_param(radio_nr, int, 0);
 
 struct fmi
@@ -130,7 +130,7 @@
 					struct v4l2_capability *v)
 {
 	strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
-	strlcpy(v->card, "SF16-FMx radio", sizeof(v->card));
+	strlcpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card));
 	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
 	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 	return 0;
@@ -277,8 +277,12 @@
 
 /* ladis: this is my card. does any other types exist? */
 static struct isapnp_device_id id_table[] __devinitdata = {
+		/* SF16-FMI */
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('M','F','R'), ISAPNP_FUNCTION(0xad10), 0},
+		/* SF16-FMD */
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('M','F','R'), ISAPNP_FUNCTION(0xad12), 0},
 	{	ISAPNP_CARD_END, },
 };
 
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 7c69214..52b8011 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -1,4 +1,4 @@
-/* SF16-FMR2 radio driver for Linux
+/* SF16-FMR2 and SF16-FMD2 radio driver for Linux
  * Copyright (c) 2011 Ondrej Zary
  *
  * Original driver was (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
@@ -13,15 +13,19 @@
 #include <linux/ioport.h>	/* request_region		*/
 #include <linux/io.h>		/* outb, outb_p			*/
 #include <linux/isa.h>
+#include <linux/pnp.h>
 #include <sound/tea575x-tuner.h>
 
 MODULE_AUTHOR("Ondrej Zary");
-MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver");
+MODULE_DESCRIPTION("MediaForte SF16-FMR2 and SF16-FMD2 FM radio card driver");
 MODULE_LICENSE("GPL");
 
-static int radio_nr = -1;
-module_param(radio_nr, int, 0444);
-MODULE_PARM_DESC(radio_nr, "Radio device number");
+/* these cards can only use two different ports (0x384 and 0x284) */
+#define FMR2_MAX 2
+
+static int radio_nr[FMR2_MAX] = { [0 ... (FMR2_MAX - 1)] = -1 };
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 
 struct fmr2 {
 	int io;
@@ -29,9 +33,15 @@
 	struct snd_tea575x tea;
 	struct v4l2_ctrl *volume;
 	struct v4l2_ctrl *balance;
+	bool is_fmd2;
 };
 
-/* the port is hardwired so no need to support multiple cards */
+static int num_fmr2_cards;
+static struct fmr2 *fmr2_cards[FMR2_MAX];
+static bool isa_registered;
+static bool pnp_registered;
+
+/* the port is hardwired on SF16-FMR2 */
 #define FMR2_PORT	0x384
 
 /* TEA575x tuner pins */
@@ -174,7 +184,8 @@
 {
 	struct fmr2 *fmr2 = tea->private_data;
 
-	if (inb(fmr2->io) & FMR2_HASVOL) {
+	/* FMR2 can have volume control, FMD2 can't (uses SB16 mixer) */
+	if (!fmr2->is_fmd2 && inb(fmr2->io) & FMR2_HASVOL) {
 		fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56);
 		fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0);
 		if (tea->ctrl_handler.error) {
@@ -186,22 +197,28 @@
 	return 0;
 }
 
-static int __devinit fmr2_probe(struct device *pdev, unsigned int dev)
+static struct pnp_device_id fmr2_pnp_ids[] __devinitdata = {
+	{ .id = "MFRad13" }, /* tuner subdevice of SF16-FMD2 */
+	{ .id = "" }
+};
+MODULE_DEVICE_TABLE(pnp, fmr2_pnp_ids);
+
+static int __devinit fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io)
 {
-	struct fmr2 *fmr2;
-	int err;
+	int err, i;
+	char *card_name = fmr2->is_fmd2 ? "SF16-FMD2" : "SF16-FMR2";
 
-	fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
-	if (fmr2 == NULL)
-		return -ENOMEM;
+	/* avoid errors if a card was already registered at given port */
+	for (i = 0; i < num_fmr2_cards; i++)
+		if (io == fmr2_cards[i]->io)
+			return -EBUSY;
 
-	strlcpy(fmr2->v4l2_dev.name, dev_name(pdev),
-			sizeof(fmr2->v4l2_dev.name));
-	fmr2->io = FMR2_PORT;
+	strlcpy(fmr2->v4l2_dev.name, "radio-sf16fmr2",
+			sizeof(fmr2->v4l2_dev.name)),
+	fmr2->io = io;
 
 	if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) {
 		printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io);
-		kfree(fmr2);
 		return -EBUSY;
 	}
 
@@ -210,56 +227,121 @@
 	if (err < 0) {
 		v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n");
 		release_region(fmr2->io, 2);
-		kfree(fmr2);
 		return err;
 	}
 	fmr2->tea.v4l2_dev = &fmr2->v4l2_dev;
 	fmr2->tea.private_data = fmr2;
-	fmr2->tea.radio_nr = radio_nr;
+	fmr2->tea.radio_nr = radio_nr[num_fmr2_cards];
 	fmr2->tea.ops = &fmr2_tea_ops;
 	fmr2->tea.ext_init = fmr2_tea_ext_init;
-	strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card));
-	snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "ISA:%s",
-			fmr2->v4l2_dev.name);
+	strlcpy(fmr2->tea.card, card_name, sizeof(fmr2->tea.card));
+	snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "%s:%s",
+			fmr2->is_fmd2 ? "PnP" : "ISA", dev_name(pdev));
 
 	if (snd_tea575x_init(&fmr2->tea)) {
 		printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n");
 		release_region(fmr2->io, 2);
-		kfree(fmr2);
 		return -ENODEV;
 	}
 
-	printk(KERN_INFO "radio-sf16fmr2: SF16-FMR2 radio card at 0x%x.\n", fmr2->io);
+	printk(KERN_INFO "radio-sf16fmr2: %s radio card at 0x%x.\n",
+			card_name, fmr2->io);
 	return 0;
 }
 
-static int __exit fmr2_remove(struct device *pdev, unsigned int dev)
+static int __devinit fmr2_isa_match(struct device *pdev, unsigned int ndev)
 {
-	struct fmr2 *fmr2 = dev_get_drvdata(pdev);
+	struct fmr2 *fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
+	if (!fmr2)
+		return 0;
 
+	if (fmr2_probe(fmr2, pdev, FMR2_PORT)) {
+		kfree(fmr2);
+		return 0;
+	}
+	dev_set_drvdata(pdev, fmr2);
+	fmr2_cards[num_fmr2_cards++] = fmr2;
+
+	return 1;
+}
+
+static int __devinit fmr2_pnp_probe(struct pnp_dev *pdev,
+				const struct pnp_device_id *id)
+{
+	int ret;
+	struct fmr2 *fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
+	if (!fmr2)
+		return -ENOMEM;
+
+	fmr2->is_fmd2 = true;
+	ret = fmr2_probe(fmr2, &pdev->dev, pnp_port_start(pdev, 0));
+	if (ret) {
+		kfree(fmr2);
+		return ret;
+	}
+	pnp_set_drvdata(pdev, fmr2);
+	fmr2_cards[num_fmr2_cards++] = fmr2;
+
+	return 0;
+}
+
+static void __devexit fmr2_remove(struct fmr2 *fmr2)
+{
 	snd_tea575x_exit(&fmr2->tea);
 	release_region(fmr2->io, 2);
 	v4l2_device_unregister(&fmr2->v4l2_dev);
 	kfree(fmr2);
+}
+
+static int __devexit fmr2_isa_remove(struct device *pdev, unsigned int ndev)
+{
+	fmr2_remove(dev_get_drvdata(pdev));
+	dev_set_drvdata(pdev, NULL);
+
 	return 0;
 }
 
-struct isa_driver fmr2_driver = {
-	.probe		= fmr2_probe,
-	.remove		= fmr2_remove,
+static void __devexit fmr2_pnp_remove(struct pnp_dev *pdev)
+{
+	fmr2_remove(pnp_get_drvdata(pdev));
+	pnp_set_drvdata(pdev, NULL);
+}
+
+struct isa_driver fmr2_isa_driver = {
+	.match		= fmr2_isa_match,
+	.remove		= __devexit_p(fmr2_isa_remove),
 	.driver		= {
 		.name	= "radio-sf16fmr2",
 	},
 };
 
+struct pnp_driver fmr2_pnp_driver = {
+	.name		= "radio-sf16fmr2",
+	.id_table	= fmr2_pnp_ids,
+	.probe		= fmr2_pnp_probe,
+	.remove		= __devexit_p(fmr2_pnp_remove),
+};
+
 static int __init fmr2_init(void)
 {
-	return isa_register_driver(&fmr2_driver, 1);
+	int ret;
+
+	ret = pnp_register_driver(&fmr2_pnp_driver);
+	if (!ret)
+		pnp_registered = true;
+	ret = isa_register_driver(&fmr2_isa_driver, 1);
+	if (!ret)
+		isa_registered = true;
+
+	return (pnp_registered || isa_registered) ? 0 : ret;
 }
 
 static void __exit fmr2_exit(void)
 {
-	isa_unregister_driver(&fmr2_driver);
+	if (pnp_registered)
+		pnp_unregister_driver(&fmr2_pnp_driver);
+	if (isa_registered)
+		isa_unregister_driver(&fmr2_isa_driver);
 }
 
 module_init(fmr2_init);
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 5d9a90a..7052adc 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -223,7 +223,7 @@
 		.owner	= THIS_MODULE,
 	},
 	.probe		= timbradio_probe,
-	.remove		= timbradio_remove,
+	.remove		= __devexit_p(timbradio_remove),
 };
 
 module_platform_driver(timbradio_platform_driver);
diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c
index 9474706..bb953ef 100644
--- a/drivers/media/radio/saa7706h.c
+++ b/drivers/media/radio/saa7706h.c
@@ -430,7 +430,7 @@
 		.name	= DRIVER_NAME,
 	},
 	.probe		= saa7706h_probe,
-	.remove		= saa7706h_remove,
+	.remove		= __devexit_p(saa7706h_remove),
 	.id_table	= saa7706h_id,
 };
 
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 0e740c9..969cf49 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -196,9 +196,9 @@
 	}
 
 	if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
-		dev_warn(&radio->videodev->dev, "tune does not complete\n");
+		dev_warn(&radio->videodev.dev, "tune does not complete\n");
 	if (timed_out)
-		dev_warn(&radio->videodev->dev,
+		dev_warn(&radio->videodev.dev,
 			"tune timed out after %u ms\n", tune_timeout);
 
 stop:
@@ -262,7 +262,7 @@
  */
 int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
 {
-	unsigned int spacing, band_bottom;
+	unsigned int spacing, band_bottom, band_top;
 	unsigned short chan;
 
 	/* Spacing (kHz) */
@@ -278,19 +278,26 @@
 		spacing = 0.050 * FREQ_MUL; break;
 	};
 
-	/* Bottom of Band (MHz) */
+	/* Bottom/Top of Band (MHz) */
 	switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
 	/* 0: 87.5 - 108 MHz (USA, Europe) */
 	case 0:
-		band_bottom = 87.5 * FREQ_MUL; break;
+		band_bottom = 87.5 * FREQ_MUL;
+		band_top = 108 * FREQ_MUL;
+		break;
 	/* 1: 76   - 108 MHz (Japan wide band) */
 	default:
-		band_bottom = 76   * FREQ_MUL; break;
+		band_bottom = 76 * FREQ_MUL;
+		band_top = 108 * FREQ_MUL;
+		break;
 	/* 2: 76   -  90 MHz (Japan) */
 	case 2:
-		band_bottom = 76   * FREQ_MUL; break;
+		band_bottom = 76 * FREQ_MUL;
+		band_top = 90 * FREQ_MUL;
+		break;
 	};
 
+	freq = clamp(freq, band_bottom, band_top);
 	/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
 	chan = (freq - band_bottom) / spacing;
 
@@ -320,7 +327,7 @@
 		radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
 	retval = si470x_set_register(radio, POWERCFG);
 	if (retval < 0)
-		goto done;
+		return retval;
 
 	/* currently I2C driver only uses interrupt way to seek */
 	if (radio->stci_enabled) {
@@ -344,24 +351,19 @@
 	}
 
 	if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
-		dev_warn(&radio->videodev->dev, "seek does not complete\n");
+		dev_warn(&radio->videodev.dev, "seek does not complete\n");
 	if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
-		dev_warn(&radio->videodev->dev,
+		dev_warn(&radio->videodev.dev,
 			"seek failed / band limit reached\n");
-	if (timed_out)
-		dev_warn(&radio->videodev->dev,
-			"seek timed out after %u ms\n", seek_timeout);
 
 stop:
 	/* stop seeking */
 	radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
 	retval = si470x_set_register(radio, POWERCFG);
 
-done:
 	/* try again, if timed out */
-	if ((retval == 0) && timed_out)
-		retval = -EAGAIN;
-
+	if (retval == 0 && timed_out)
+		return -EAGAIN;
 	return retval;
 }
 
@@ -463,7 +465,6 @@
 	unsigned int block_count = 0;
 
 	/* switch on rds reception */
-	mutex_lock(&radio->lock);
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 		si470x_rds_on(radio);
 
@@ -505,7 +506,6 @@
 	}
 
 done:
-	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -517,19 +517,19 @@
 		struct poll_table_struct *pts)
 {
 	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
+	unsigned long req_events = poll_requested_events(pts);
+	int retval = v4l2_ctrl_poll(file, pts);
 
-	/* switch on rds reception */
+	if (req_events & (POLLIN | POLLRDNORM)) {
+		/* switch on rds reception */
+		if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+			si470x_rds_on(radio);
 
-	mutex_lock(&radio->lock);
-	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
-		si470x_rds_on(radio);
-	mutex_unlock(&radio->lock);
+		poll_wait(file, &radio->read_queue, pts);
 
-	poll_wait(file, &radio->read_queue, pts);
-
-	if (radio->rd_index != radio->wr_index)
-		retval = POLLIN | POLLRDNORM;
+		if (radio->rd_index != radio->wr_index)
+			retval |= POLLIN | POLLRDNORM;
+	}
 
 	return retval;
 }
@@ -553,134 +553,26 @@
  * Video4Linux Interface
  **************************************************************************/
 
-/*
- * si470x_vidioc_queryctrl - enumerate control items
- */
-static int si470x_vidioc_queryctrl(struct file *file, void *priv,
-		struct v4l2_queryctrl *qc)
+
+static int si470x_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct si470x_device *radio = video_drvdata(file);
-	int retval = -EINVAL;
-
-	/* abort if qc->id is below V4L2_CID_BASE */
-	if (qc->id < V4L2_CID_BASE)
-		goto done;
-
-	/* search video control */
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15);
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	}
-
-	/* disable unsupported base controls */
-	/* to satisfy kradio and such apps */
-	if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
-		qc->flags = V4L2_CTRL_FLAG_DISABLED;
-		retval = 0;
-	}
-
-done:
-	if (retval < 0)
-		dev_warn(&radio->videodev->dev,
-			"query controls failed with %d\n", retval);
-	return retval;
-}
-
-
-/*
- * si470x_vidioc_g_ctrl - get the value of a control
- */
-static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
-		struct v4l2_control *ctrl)
-{
-	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
-
-	mutex_lock(&radio->lock);
-	/* safety checks */
-	retval = si470x_disconnect_check(radio);
-	if (retval)
-		goto done;
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = radio->registers[SYSCONFIG2] &
-				SYSCONFIG2_VOLUME;
-		break;
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = ((radio->registers[POWERCFG] &
-				POWERCFG_DMUTE) == 0) ? 1 : 0;
-		break;
-	default:
-		retval = -EINVAL;
-	}
-
-done:
-	if (retval < 0)
-		dev_warn(&radio->videodev->dev,
-			"get control failed with %d\n", retval);
-
-	mutex_unlock(&radio->lock);
-	return retval;
-}
-
-
-/*
- * si470x_vidioc_s_ctrl - set the value of a control
- */
-static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
-		struct v4l2_control *ctrl)
-{
-	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
-
-	mutex_lock(&radio->lock);
-	/* safety checks */
-	retval = si470x_disconnect_check(radio);
-	if (retval)
-		goto done;
+	struct si470x_device *radio =
+		container_of(ctrl->handler, struct si470x_device, hdl);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
 		radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
-		radio->registers[SYSCONFIG2] |= ctrl->value;
-		retval = si470x_set_register(radio, SYSCONFIG2);
-		break;
+		radio->registers[SYSCONFIG2] |= ctrl->val;
+		return si470x_set_register(radio, SYSCONFIG2);
 	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value == 1)
+		if (ctrl->val)
 			radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
 		else
 			radio->registers[POWERCFG] |= POWERCFG_DMUTE;
-		retval = si470x_set_register(radio, POWERCFG);
-		break;
+		return si470x_set_register(radio, POWERCFG);
 	default:
-		retval = -EINVAL;
+		return -EINVAL;
 	}
-
-done:
-	if (retval < 0)
-		dev_warn(&radio->videodev->dev,
-			"set control failed with %d\n", retval);
-	mutex_unlock(&radio->lock);
-	return retval;
-}
-
-
-/*
- * si470x_vidioc_g_audio - get audio attributes
- */
-static int si470x_vidioc_g_audio(struct file *file, void *priv,
-		struct v4l2_audio *audio)
-{
-	/* driver constants */
-	audio->index = 0;
-	strcpy(audio->name, "Radio");
-	audio->capability = V4L2_AUDCAP_STEREO;
-	audio->mode = 0;
-
-	return 0;
 }
 
 
@@ -691,22 +583,14 @@
 		struct v4l2_tuner *tuner)
 {
 	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
+	int retval;
 
-	mutex_lock(&radio->lock);
-	/* safety checks */
-	retval = si470x_disconnect_check(radio);
-	if (retval)
-		goto done;
-
-	if (tuner->index != 0) {
-		retval = -EINVAL;
-		goto done;
-	}
+	if (tuner->index != 0)
+		return -EINVAL;
 
 	retval = si470x_get_register(radio, STATUSRSSI);
 	if (retval < 0)
-		goto done;
+		return retval;
 
 	/* driver constants */
 	strcpy(tuner->name, "FM");
@@ -737,7 +621,7 @@
 	if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
 		tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
 	else
-		tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+		tuner->rxsubchans = V4L2_TUNER_SUB_STEREO;
 	/* If there is a reliable method of detecting an RDS channel,
 	   then this code should check for that before setting this
 	   RDS subchannel. */
@@ -754,16 +638,13 @@
 	tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
 	/* the ideal factor is 0xffff/75 = 873,8 */
 	tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
+	if (tuner->signal > 0xffff)
+		tuner->signal = 0xffff;
 
 	/* automatic frequency control: -1: freq to low, 1 freq to high */
 	/* AFCRL does only indicate that freq. differs, not if too low/high */
 	tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
 
-done:
-	if (retval < 0)
-		dev_warn(&radio->videodev->dev,
-			"get tuner failed with %d\n", retval);
-	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -775,16 +656,9 @@
 		struct v4l2_tuner *tuner)
 {
 	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
-
-	mutex_lock(&radio->lock);
-	/* safety checks */
-	retval = si470x_disconnect_check(radio);
-	if (retval)
-		goto done;
 
 	if (tuner->index != 0)
-		goto done;
+		return -EINVAL;
 
 	/* mono/stereo selector */
 	switch (tuner->audmode) {
@@ -792,20 +666,12 @@
 		radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
 		break;
 	case V4L2_TUNER_MODE_STEREO:
+	default:
 		radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
 		break;
-	default:
-		goto done;
 	}
 
-	retval = si470x_set_register(radio, POWERCFG);
-
-done:
-	if (retval < 0)
-		dev_warn(&radio->videodev->dev,
-			"set tuner failed with %d\n", retval);
-	mutex_unlock(&radio->lock);
-	return retval;
+	return si470x_set_register(radio, POWERCFG);
 }
 
 
@@ -816,28 +682,12 @@
 		struct v4l2_frequency *freq)
 {
 	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
 
-	/* safety checks */
-	mutex_lock(&radio->lock);
-	retval = si470x_disconnect_check(radio);
-	if (retval)
-		goto done;
-
-	if (freq->tuner != 0) {
-		retval = -EINVAL;
-		goto done;
-	}
+	if (freq->tuner != 0)
+		return -EINVAL;
 
 	freq->type = V4L2_TUNER_RADIO;
-	retval = si470x_get_freq(radio, &freq->frequency);
-
-done:
-	if (retval < 0)
-		dev_warn(&radio->videodev->dev,
-			"get frequency failed with %d\n", retval);
-	mutex_unlock(&radio->lock);
-	return retval;
+	return si470x_get_freq(radio, &freq->frequency);
 }
 
 
@@ -848,27 +698,11 @@
 		struct v4l2_frequency *freq)
 {
 	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
 
-	mutex_lock(&radio->lock);
-	/* safety checks */
-	retval = si470x_disconnect_check(radio);
-	if (retval)
-		goto done;
+	if (freq->tuner != 0)
+		return -EINVAL;
 
-	if (freq->tuner != 0) {
-		retval = -EINVAL;
-		goto done;
-	}
-
-	retval = si470x_set_freq(radio, freq->frequency);
-
-done:
-	if (retval < 0)
-		dev_warn(&radio->videodev->dev,
-			"set frequency failed with %d\n", retval);
-	mutex_unlock(&radio->lock);
-	return retval;
+	return si470x_set_freq(radio, freq->frequency);
 }
 
 
@@ -879,44 +713,29 @@
 		struct v4l2_hw_freq_seek *seek)
 {
 	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
 
-	mutex_lock(&radio->lock);
-	/* safety checks */
-	retval = si470x_disconnect_check(radio);
-	if (retval)
-		goto done;
+	if (seek->tuner != 0)
+		return -EINVAL;
 
-	if (seek->tuner != 0) {
-		retval = -EINVAL;
-		goto done;
-	}
-
-	retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
-
-done:
-	if (retval < 0)
-		dev_warn(&radio->videodev->dev,
-			"set hardware frequency seek failed with %d\n", retval);
-	mutex_unlock(&radio->lock);
-	return retval;
+	return si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
 }
 
+const struct v4l2_ctrl_ops si470x_ctrl_ops = {
+	.s_ctrl = si470x_s_ctrl,
+};
 
 /*
  * si470x_ioctl_ops - video device ioctl operations
  */
 static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
 	.vidioc_querycap	= si470x_vidioc_querycap,
-	.vidioc_queryctrl	= si470x_vidioc_queryctrl,
-	.vidioc_g_ctrl		= si470x_vidioc_g_ctrl,
-	.vidioc_s_ctrl		= si470x_vidioc_s_ctrl,
-	.vidioc_g_audio		= si470x_vidioc_g_audio,
 	.vidioc_g_tuner		= si470x_vidioc_g_tuner,
 	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
 	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
 	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
 	.vidioc_s_hw_freq_seek	= si470x_vidioc_s_hw_freq_seek,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 
@@ -926,6 +745,6 @@
 struct video_device si470x_viddev_template = {
 	.fops			= &si470x_fops,
 	.name			= DRIVER_NAME,
-	.release		= video_device_release,
+	.release		= video_device_release_empty,
 	.ioctl_ops		= &si470x_ioctl_ops,
 };
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index 9b546a5..a80044c 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -162,20 +162,6 @@
 
 
 /**************************************************************************
- * General Driver Functions - DISCONNECT_CHECK
- **************************************************************************/
-
-/*
- * si470x_disconnect_check - check whether radio disconnects
- */
-int si470x_disconnect_check(struct si470x_device *radio)
-{
-	return 0;
-}
-
-
-
-/**************************************************************************
  * File Operations Interface
  **************************************************************************/
 
@@ -185,12 +171,12 @@
 int si470x_fops_open(struct file *file)
 {
 	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
+	int retval = v4l2_fh_open(file);
 
-	mutex_lock(&radio->lock);
-	radio->users++;
+	if (retval)
+		return retval;
 
-	if (radio->users == 1) {
+	if (v4l2_fh_is_singular_file(file)) {
 		/* start radio */
 		retval = si470x_start(radio);
 		if (retval < 0)
@@ -205,7 +191,8 @@
 	}
 
 done:
-	mutex_unlock(&radio->lock);
+	if (retval)
+		v4l2_fh_release(file);
 	return retval;
 }
 
@@ -216,21 +203,12 @@
 int si470x_fops_release(struct file *file)
 {
 	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
 
-	/* safety check */
-	if (!radio)
-		return -ENODEV;
-
-	mutex_lock(&radio->lock);
-	radio->users--;
-	if (radio->users == 0)
+	if (v4l2_fh_is_singular_file(file))
 		/* stop radio */
-		retval = si470x_stop(radio);
+		si470x_stop(radio);
 
-	mutex_unlock(&radio->lock);
-
-	return retval;
+	return v4l2_fh_release(file);
 }
 
 
@@ -371,32 +349,25 @@
 		goto err_initial;
 	}
 
-	radio->users = 0;
 	radio->client = client;
 	mutex_init(&radio->lock);
 
-	/* video device allocation and initialization */
-	radio->videodev = video_device_alloc();
-	if (!radio->videodev) {
-		retval = -ENOMEM;
-		goto err_radio;
-	}
-	memcpy(radio->videodev, &si470x_viddev_template,
-			sizeof(si470x_viddev_template));
-	video_set_drvdata(radio->videodev, radio);
+	/* video device initialization */
+	radio->videodev = si470x_viddev_template;
+	video_set_drvdata(&radio->videodev, radio);
 
 	/* power up : need 110ms */
 	radio->registers[POWERCFG] = POWERCFG_ENABLE;
 	if (si470x_set_register(radio, POWERCFG) < 0) {
 		retval = -EIO;
-		goto err_video;
+		goto err_radio;
 	}
 	msleep(110);
 
 	/* get device and chip versions */
 	if (si470x_get_all_registers(radio) < 0) {
 		retval = -EIO;
-		goto err_video;
+		goto err_radio;
 	}
 	dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
 			radio->registers[DEVICEID], radio->registers[CHIPID]);
@@ -427,7 +398,7 @@
 	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
 	if (!radio->buffer) {
 		retval = -EIO;
-		goto err_video;
+		goto err_radio;
 	}
 
 	/* rds buffer configuration */
@@ -447,7 +418,7 @@
 	}
 
 	/* register video device */
-	retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
+	retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
 			radio_nr);
 	if (retval) {
 		dev_warn(&client->dev, "Could not register video device\n");
@@ -460,8 +431,6 @@
 	free_irq(client->irq, radio);
 err_rds:
 	kfree(radio->buffer);
-err_video:
-	video_device_release(radio->videodev);
 err_radio:
 	kfree(radio);
 err_initial:
@@ -477,7 +446,7 @@
 	struct si470x_device *radio = i2c_get_clientdata(client);
 
 	free_irq(client->irq, radio);
-	video_unregister_device(radio->videodev);
+	video_unregister_device(&radio->videodev);
 	kfree(radio);
 
 	return 0;
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index b7debb67..e9f6387 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -367,23 +367,6 @@
 
 
 /**************************************************************************
- * General Driver Functions - DISCONNECT_CHECK
- **************************************************************************/
-
-/*
- * si470x_disconnect_check - check whether radio disconnects
- */
-int si470x_disconnect_check(struct si470x_device *radio)
-{
-	if (radio->disconnected)
-		return -EIO;
-	else
-		return 0;
-}
-
-
-
-/**************************************************************************
  * RDS Driver Functions
  **************************************************************************/
 
@@ -414,9 +397,6 @@
 		}
 	}
 
-	/* safety checks */
-	if (radio->disconnected)
-		return;
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 		goto resubmit;
 
@@ -501,110 +481,28 @@
 }
 
 
-
-/**************************************************************************
- * File Operations Interface
- **************************************************************************/
-
-/*
- * si470x_fops_open - file open
- */
 int si470x_fops_open(struct file *file)
 {
-	struct si470x_device *radio = video_drvdata(file);
-	int retval;
-
-	mutex_lock(&radio->lock);
-	radio->users++;
-
-	retval = usb_autopm_get_interface(radio->intf);
-	if (retval < 0) {
-		radio->users--;
-		retval = -EIO;
-		goto done;
-	}
-
-	if (radio->users == 1) {
-		/* start radio */
-		retval = si470x_start(radio);
-		if (retval < 0) {
-			usb_autopm_put_interface(radio->intf);
-			goto done;
-		}
-
-		/* initialize interrupt urb */
-		usb_fill_int_urb(radio->int_in_urb, radio->usbdev,
-			usb_rcvintpipe(radio->usbdev,
-			radio->int_in_endpoint->bEndpointAddress),
-			radio->int_in_buffer,
-			le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize),
-			si470x_int_in_callback,
-			radio,
-			radio->int_in_endpoint->bInterval);
-
-		radio->int_in_running = 1;
-		mb();
-
-		retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL);
-		if (retval) {
-			dev_info(&radio->intf->dev,
-				 "submitting int urb failed (%d)\n", retval);
-			radio->int_in_running = 0;
-			usb_autopm_put_interface(radio->intf);
-		}
-	}
-
-done:
-	mutex_unlock(&radio->lock);
-	return retval;
+	return v4l2_fh_open(file);
 }
 
-
-/*
- * si470x_fops_release - file release
- */
 int si470x_fops_release(struct file *file)
 {
-	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
-
-	/* safety check */
-	if (!radio) {
-		retval = -ENODEV;
-		goto done;
-	}
-
-	mutex_lock(&radio->lock);
-	radio->users--;
-	if (radio->users == 0) {
-		/* shutdown interrupt handler */
-		if (radio->int_in_running) {
-			radio->int_in_running = 0;
-		if (radio->int_in_urb)
-			usb_kill_urb(radio->int_in_urb);
-		}
-
-		if (radio->disconnected) {
-			video_unregister_device(radio->videodev);
-			kfree(radio->int_in_buffer);
-			kfree(radio->buffer);
-			mutex_unlock(&radio->lock);
-			kfree(radio);
-			goto done;
-		}
-
-		/* cancel read processes */
-		wake_up_interruptible(&radio->read_queue);
-
-		/* stop radio */
-		retval = si470x_stop(radio);
-		usb_autopm_put_interface(radio->intf);
-	}
-	mutex_unlock(&radio->lock);
-done:
-	return retval;
+	return v4l2_fh_release(file);
 }
 
+static void si470x_usb_release(struct v4l2_device *v4l2_dev)
+{
+	struct si470x_device *radio =
+		container_of(v4l2_dev, struct si470x_device, v4l2_dev);
+
+	usb_free_urb(radio->int_in_urb);
+	v4l2_ctrl_handler_free(&radio->hdl);
+	v4l2_device_unregister(&radio->v4l2_dev);
+	kfree(radio->int_in_buffer);
+	kfree(radio->buffer);
+	kfree(radio);
+}
 
 
 /**************************************************************************
@@ -623,13 +521,45 @@
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
 	usb_make_path(radio->usbdev, capability->bus_info,
 			sizeof(capability->bus_info));
-	capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+	capability->device_caps = V4L2_CAP_HW_FREQ_SEEK |
 		V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
-
+	capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
 
+static int si470x_start_usb(struct si470x_device *radio)
+{
+	int retval;
+
+	/* start radio */
+	retval = si470x_start(radio);
+	if (retval < 0)
+		return retval;
+
+	v4l2_ctrl_handler_setup(&radio->hdl);
+
+	/* initialize interrupt urb */
+	usb_fill_int_urb(radio->int_in_urb, radio->usbdev,
+			usb_rcvintpipe(radio->usbdev,
+				radio->int_in_endpoint->bEndpointAddress),
+			radio->int_in_buffer,
+			le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize),
+			si470x_int_in_callback,
+			radio,
+			radio->int_in_endpoint->bInterval);
+
+	radio->int_in_running = 1;
+	mb();
+
+	retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL);
+	if (retval) {
+		dev_info(&radio->intf->dev,
+				"submitting int urb failed (%d)\n", retval);
+		radio->int_in_running = 0;
+	}
+	return retval;
+}
 
 /**************************************************************************
  * USB Interface
@@ -653,8 +583,6 @@
 		retval = -ENOMEM;
 		goto err_initial;
 	}
-	radio->users = 0;
-	radio->disconnected = 0;
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->intf = intf;
 	mutex_init(&radio->lock);
@@ -691,20 +619,35 @@
 		goto err_intbuffer;
 	}
 
-	/* video device allocation and initialization */
-	radio->videodev = video_device_alloc();
-	if (!radio->videodev) {
-		retval = -ENOMEM;
+	radio->v4l2_dev.release = si470x_usb_release;
+	retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
+	if (retval < 0) {
+		dev_err(&intf->dev, "couldn't register v4l2_device\n");
 		goto err_urb;
 	}
-	memcpy(radio->videodev, &si470x_viddev_template,
-			sizeof(si470x_viddev_template));
-	video_set_drvdata(radio->videodev, radio);
+
+	v4l2_ctrl_handler_init(&radio->hdl, 2);
+	v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops,
+			  V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops,
+			  V4L2_CID_AUDIO_VOLUME, 0, 15, 1, 15);
+	if (radio->hdl.error) {
+		retval = radio->hdl.error;
+		dev_err(&intf->dev, "couldn't register control\n");
+		goto err_dev;
+	}
+	radio->videodev = si470x_viddev_template;
+	radio->videodev.ctrl_handler = &radio->hdl;
+	radio->videodev.lock = &radio->lock;
+	radio->videodev.v4l2_dev = &radio->v4l2_dev;
+	radio->videodev.release = video_device_release_empty;
+	set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
+	video_set_drvdata(&radio->videodev, radio);
 
 	/* get device and chip versions */
 	if (si470x_get_all_registers(radio) < 0) {
 		retval = -EIO;
-		goto err_video;
+		goto err_ctrl;
 	}
 	dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
 			radio->registers[DEVICEID], radio->registers[CHIPID]);
@@ -721,7 +664,7 @@
 	/* get software and hardware versions */
 	if (si470x_get_scratch_page_versions(radio) < 0) {
 		retval = -EIO;
-		goto err_video;
+		goto err_ctrl;
 	}
 	dev_info(&intf->dev, "software version %d, hardware version %d\n",
 			radio->software_version, radio->hardware_version);
@@ -764,28 +707,35 @@
 	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
 	if (!radio->buffer) {
 		retval = -EIO;
-		goto err_video;
+		goto err_ctrl;
 	}
 
 	/* rds buffer configuration */
 	radio->wr_index = 0;
 	radio->rd_index = 0;
 	init_waitqueue_head(&radio->read_queue);
+	usb_set_intfdata(intf, radio);
+
+	/* start radio */
+	retval = si470x_start_usb(radio);
+	if (retval < 0)
+		goto err_all;
 
 	/* register video device */
-	retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
+	retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
 			radio_nr);
 	if (retval) {
-		dev_warn(&intf->dev, "Could not register video device\n");
+		dev_err(&intf->dev, "Could not register video device\n");
 		goto err_all;
 	}
-	usb_set_intfdata(intf, radio);
 
 	return 0;
 err_all:
 	kfree(radio->buffer);
-err_video:
-	video_device_release(radio->videodev);
+err_ctrl:
+	v4l2_ctrl_handler_free(&radio->hdl);
+err_dev:
+	v4l2_device_unregister(&radio->v4l2_dev);
 err_urb:
 	usb_free_urb(radio->int_in_urb);
 err_intbuffer:
@@ -803,8 +753,22 @@
 static int si470x_usb_driver_suspend(struct usb_interface *intf,
 		pm_message_t message)
 {
+	struct si470x_device *radio = usb_get_intfdata(intf);
+
 	dev_info(&intf->dev, "suspending now...\n");
 
+	/* shutdown interrupt handler */
+	if (radio->int_in_running) {
+		radio->int_in_running = 0;
+		if (radio->int_in_urb)
+			usb_kill_urb(radio->int_in_urb);
+	}
+
+	/* cancel read processes */
+	wake_up_interruptible(&radio->read_queue);
+
+	/* stop radio */
+	si470x_stop(radio);
 	return 0;
 }
 
@@ -814,9 +778,12 @@
  */
 static int si470x_usb_driver_resume(struct usb_interface *intf)
 {
+	struct si470x_device *radio = usb_get_intfdata(intf);
+
 	dev_info(&intf->dev, "resuming now...\n");
 
-	return 0;
+	/* start radio */
+	return si470x_start_usb(radio);
 }
 
 
@@ -828,28 +795,22 @@
 	struct si470x_device *radio = usb_get_intfdata(intf);
 
 	mutex_lock(&radio->lock);
-	radio->disconnected = 1;
+	v4l2_device_disconnect(&radio->v4l2_dev);
+	video_unregister_device(&radio->videodev);
 	usb_set_intfdata(intf, NULL);
-	if (radio->users == 0) {
-		/* set led to disconnect state */
-		si470x_set_led_state(radio, BLINK_ORANGE_LED);
-
-		/* Free data structures. */
-		usb_free_urb(radio->int_in_urb);
-
-		kfree(radio->int_in_buffer);
-		video_unregister_device(radio->videodev);
-		kfree(radio->buffer);
-		mutex_unlock(&radio->lock);
-		kfree(radio);
-	} else {
-		mutex_unlock(&radio->lock);
-	}
+	mutex_unlock(&radio->lock);
+	v4l2_device_put(&radio->v4l2_dev);
 }
 
 
 /*
  * si470x_usb_driver - usb driver interface
+ *
+ * A note on suspend/resume: this driver had only empty suspend/resume
+ * functions, and when I tried to test suspend/resume it always disconnected
+ * instead of resuming (using my ADS InstantFM stick). So I've decided to
+ * remove these callbacks until someone else with better hardware can
+ * implement and test this.
  */
 static struct usb_driver si470x_usb_driver = {
 	.name			= DRIVER_NAME,
@@ -857,8 +818,8 @@
 	.disconnect		= si470x_usb_driver_disconnect,
 	.suspend		= si470x_usb_driver_suspend,
 	.resume			= si470x_usb_driver_resume,
+	.reset_resume		= si470x_usb_driver_resume,
 	.id_table		= si470x_usb_driver_id_table,
-	.supports_autosuspend	= 1,
 };
 
 module_usb_driver(si470x_usb_driver);
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index f300a55..4921cab 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -36,6 +36,9 @@
 #include <linux/mutex.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-device.h>
 #include <asm/unaligned.h>
 
 
@@ -141,10 +144,9 @@
  * si470x_device - private data
  */
 struct si470x_device {
-	struct video_device *videodev;
-
-	/* driver management */
-	unsigned int users;
+	struct v4l2_device v4l2_dev;
+	struct video_device videodev;
+	struct v4l2_ctrl_handler hdl;
 
 	/* Silabs internal registers (0..15) */
 	unsigned short registers[RADIO_REGISTER_NUM];
@@ -174,9 +176,6 @@
 	/* scratch page */
 	unsigned char software_version;
 	unsigned char hardware_version;
-
-	/* driver management */
-	unsigned char disconnected;
 #endif
 
 #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
@@ -213,6 +212,7 @@
  * Common Functions
  **************************************************************************/
 extern struct video_device si470x_viddev_template;
+extern const struct v4l2_ctrl_ops si470x_ctrl_ops;
 int si470x_get_register(struct si470x_device *radio, int regnr);
 int si470x_set_register(struct si470x_device *radio, int regnr);
 int si470x_disconnect_check(struct si470x_device *radio);
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index 6418c4c..06d47e5 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -211,7 +211,7 @@
 		.name	= DRIVER_NAME,
 	},
 	.probe		= tef6862_probe,
-	.remove		= tef6862_remove,
+	.remove		= __devexit_p(tef6862_remove),
 	.id_table	= tef6862_id,
 };
 
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index 077d369..080b96a 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -518,6 +518,10 @@
 	video_set_drvdata(gradio_dev, fmdev);
 
 	gradio_dev->lock = &fmdev->mutex;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &gradio_dev->flags);
 
 	/* Register with V4L2 subsystem as RADIO device */
 	if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index a3fbb21..f97eeb8 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -69,6 +69,7 @@
 config IR_SONY_DECODER
 	tristate "Enable IR raw decoder for the Sony protocol"
 	depends on RC_CORE
+	select BITREVERSE
 	default y
 
 	---help---
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index baf907b..7be377f 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -1,7 +1,7 @@
 /*
  *  USB ATI Remote support
  *
- *                Copyright (c) 2011 Anssi Hannula <anssi.hannula@iki.fi>
+ *                Copyright (c) 2011, 2012 Anssi Hannula <anssi.hannula@iki.fi>
  *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
  *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
  *
@@ -151,13 +151,57 @@
 #undef err
 #define err(format, arg...) printk(KERN_ERR format , ## arg)
 
+struct ati_receiver_type {
+	/* either default_keymap or get_default_keymap should be set */
+	const char *default_keymap;
+	const char *(*get_default_keymap)(struct usb_interface *interface);
+};
+
+static const char *get_medion_keymap(struct usb_interface *interface)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+
+	/*
+	 * There are many different Medion remotes shipped with a receiver
+	 * with the same usb id, but the receivers have subtle differences
+	 * in the USB descriptors allowing us to detect them.
+	 */
+
+	if (udev->manufacturer && udev->product) {
+		if (udev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP) {
+
+			if (!strcmp(udev->manufacturer, "X10 Wireless Technology Inc")
+			    && !strcmp(udev->product, "USB Receiver"))
+				return RC_MAP_MEDION_X10_DIGITAINER;
+
+			if (!strcmp(udev->manufacturer, "X10 WTI")
+			    && !strcmp(udev->product, "RF receiver"))
+				return RC_MAP_MEDION_X10_OR2X;
+		} else {
+
+			 if (!strcmp(udev->manufacturer, "X10 Wireless Technology Inc")
+			    && !strcmp(udev->product, "USB Receiver"))
+				return RC_MAP_MEDION_X10;
+		}
+	}
+
+	dev_info(&interface->dev,
+		 "Unknown Medion X10 receiver, using default ati_remote Medion keymap\n");
+
+	return RC_MAP_MEDION_X10;
+}
+
+static const struct ati_receiver_type type_ati		= { .default_keymap = RC_MAP_ATI_X10 };
+static const struct ati_receiver_type type_medion	= { .get_default_keymap = get_medion_keymap };
+static const struct ati_receiver_type type_firefly	= { .default_keymap = RC_MAP_SNAPSTREAM_FIREFLY };
+
 static struct usb_device_id ati_remote_table[] = {
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_MEDION_X10 },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_SNAPSTREAM_FIREFLY },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)&type_ati },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)&type_ati },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)&type_ati },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)&type_ati },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)&type_medion },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)&type_firefly },
 	{}	/* Terminating entry */
 };
 
@@ -445,6 +489,7 @@
 	int acc;
 	int remote_num;
 	unsigned char scancode;
+	u32 wheel_keycode = KEY_RESERVED;
 	int i;
 
 	/*
@@ -484,26 +529,33 @@
 	 */
 	scancode = data[2] & 0x7f;
 
-	/* Look up event code index in the mouse translation table. */
-	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
-		if (scancode == ati_remote_tbl[i].data) {
-			index = i;
-			break;
+	dbginfo(&ati_remote->interface->dev,
+		"channel 0x%02x; key data %02x, scancode %02x\n",
+		remote_num, data[2], scancode);
+
+	if (scancode >= 0x70) {
+		/*
+		 * This is either a mouse or scrollwheel event, depending on
+		 * the remote/keymap.
+		 * Get the keycode assigned to scancode 0x78/0x70. If it is
+		 * set, assume this is a scrollwheel up/down event.
+		 */
+		wheel_keycode = rc_g_keycode_from_table(ati_remote->rdev,
+							scancode & 0x78);
+
+		if (wheel_keycode == KEY_RESERVED) {
+			/* scrollwheel was not mapped, assume mouse */
+
+			/* Look up event code index in the mouse translation table. */
+			for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
+				if (scancode == ati_remote_tbl[i].data) {
+					index = i;
+					break;
+				}
+			}
 		}
 	}
 
-	if (index >= 0) {
-		dbginfo(&ati_remote->interface->dev,
-			"channel 0x%02x; mouse data %02x; index %d; keycode %d\n",
-			remote_num, data[2], index, ati_remote_tbl[index].code);
-		if (!dev)
-			return; /* no mouse device */
-	} else
-		dbginfo(&ati_remote->interface->dev,
-			"channel 0x%02x; key data %02x, scancode %02x\n",
-			remote_num, data[2], scancode);
-
-
 	if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) {
 		input_event(dev, ati_remote_tbl[index].type,
 			ati_remote_tbl[index].code,
@@ -542,15 +594,29 @@
 
 		if (index < 0) {
 			/* Not a mouse event, hand it to rc-core. */
+			int count = 1;
 
-			/*
-			 * We don't use the rc-core repeat handling yet as
-			 * it would cause ghost repeats which would be a
-			 * regression for this driver.
-			 */
-			rc_keydown_notimeout(ati_remote->rdev, scancode,
-					     data[2]);
-			rc_keyup(ati_remote->rdev);
+			if (wheel_keycode != KEY_RESERVED) {
+				/*
+				 * This is a scrollwheel event, send the
+				 * scroll up (0x78) / down (0x70) scancode
+				 * repeatedly as many times as indicated by
+				 * rest of the scancode.
+				 */
+				count = (scancode & 0x07) + 1;
+				scancode &= 0x78;
+			}
+
+			while (count--) {
+				/*
+				* We don't use the rc-core repeat handling yet as
+				* it would cause ghost repeats which would be a
+				* regression for this driver.
+				*/
+				rc_keydown_notimeout(ati_remote->rdev, scancode,
+						     data[2]);
+				rc_keyup(ati_remote->rdev);
+			}
 			return;
 		}
 
@@ -766,6 +832,7 @@
 	struct usb_device *udev = interface_to_usbdev(interface);
 	struct usb_host_interface *iface_host = interface->cur_altsetting;
 	struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
+	struct ati_receiver_type *type = (struct ati_receiver_type *)id->driver_info;
 	struct ati_remote *ati_remote;
 	struct input_dev *input_dev;
 	struct rc_dev *rc_dev;
@@ -827,10 +894,15 @@
 	snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name),
 		 "%s mouse", ati_remote->rc_name);
 
-	if (id->driver_info)
-		rc_dev->map_name = (const char *)id->driver_info;
-	else
-		rc_dev->map_name = RC_MAP_ATI_X10;
+	rc_dev->map_name = RC_MAP_ATI_X10; /* default map */
+
+	/* set default keymap according to receiver model */
+	if (type) {
+		if (type->default_keymap)
+			rc_dev->map_name = type->default_keymap;
+		else if (type->get_default_keymap)
+			rc_dev->map_name = type->get_default_keymap(interface);
+	}
 
 	ati_remote_rc_init(ati_remote);
 	mutex_init(&ati_remote->open_mutex);
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 4a3a238..6aabf7a 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -556,11 +556,11 @@
 
 	if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED,
 			FINTEK_DRIVER_NAME, (void *)fintek))
-		goto failure;
+		goto failure2;
 
 	ret = rc_register_device(rdev);
 	if (ret)
-		goto failure;
+		goto failure3;
 
 	device_init_wakeup(&pdev->dev, true);
 	fintek->rdev = rdev;
@@ -570,12 +570,11 @@
 
 	return 0;
 
+failure3:
+	free_irq(fintek->cir_irq, fintek);
+failure2:
+	release_region(fintek->cir_addr, fintek->cir_port_len);
 failure:
-	if (fintek->cir_irq)
-		free_irq(fintek->cir_irq, fintek);
-	if (fintek->cir_addr)
-		release_region(fintek->cir_addr, fintek->cir_port_len);
-
 	rc_free_device(rdev);
 	kfree(fintek);
 
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 7f26fdf..5dd0386 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -255,7 +255,7 @@
 static struct usb_driver imon_driver = {
 	.name		= MOD_NAME,
 	.probe		= imon_probe,
-	.disconnect	= imon_disconnect,
+	.disconnect	= __devexit_p(imon_disconnect),
 	.suspend	= imon_suspend,
 	.resume		= imon_resume,
 	.id_table	= imon_usb_id_table,
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 95e6309..a820251 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -46,9 +46,9 @@
 	while (!kthread_should_stop()) {
 
 		spin_lock_irq(&raw->lock);
-		retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
+		retval = kfifo_len(&raw->kfifo);
 
-		if (!retval) {
+		if (retval < sizeof(ev)) {
 			set_current_state(TASK_INTERRUPTIBLE);
 
 			if (kthread_should_stop())
@@ -59,11 +59,9 @@
 			continue;
 		}
 
+		retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
 		spin_unlock_irq(&raw->lock);
 
-
-		BUG_ON(retval != sizeof(ev));
-
 		mutex_lock(&ir_raw_handler_lock);
 		list_for_each_entry(handler, &ir_raw_handler_list, list)
 			handler->decode(raw->dev, ev);
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index d38fbdd..7e54ec5 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -56,7 +56,7 @@
 {
 	struct sanyo_dec *data = &dev->raw->sanyo;
 	u32 scancode;
-	u8 address, not_address, command, not_command;
+	u8 address, command, not_command;
 
 	if (!(dev->raw->enabled_protocols & RC_TYPE_SANYO))
 		return 0;
@@ -154,7 +154,7 @@
 			break;
 
 		address     = bitrev16((data->bits >> 29) & 0x1fff) >> 3;
-		not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3;
+		/* not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3; */
 		command	    = bitrev8((data->bits >>  8) & 0xff);
 		not_command = bitrev8((data->bits >>  0) & 0xff);
 
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 0e49c99..36fe5a3 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1598,24 +1598,22 @@
 
 	if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED,
 			ITE_DRIVER_NAME, (void *)itdev))
-		goto failure;
+		goto failure2;
 
 	ret = rc_register_device(rdev);
 	if (ret)
-		goto failure;
+		goto failure3;
 
 	itdev->rdev = rdev;
 	ite_pr(KERN_NOTICE, "driver has been successfully loaded\n");
 
 	return 0;
 
+failure3:
+	free_irq(itdev->cir_irq, itdev);
+failure2:
+	release_region(itdev->cir_addr, itdev->params.io_region_size);
 failure:
-	if (itdev->cir_irq)
-		free_irq(itdev->cir_irq, itdev);
-
-	if (itdev->cir_addr)
-		release_region(itdev->cir_addr, itdev->params.io_region_size);
-
 	rc_free_device(rdev);
 	kfree(itdev);
 
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 49ce266..ab84d66 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -3,6 +3,7 @@
 			rc-anysee.o \
 			rc-apac-viewcomp.o \
 			rc-asus-pc39.o \
+			rc-asus-ps3-100.o \
 			rc-ati-tv-wonder-hd-600.o \
 			rc-ati-x10.o \
 			rc-avermedia-a16d.o \
@@ -52,6 +53,8 @@
 			rc-lme2510.o \
 			rc-manli.o \
 			rc-medion-x10.o \
+			rc-medion-x10-digitainer.o \
+			rc-medion-x10-or2x.o \
 			rc-msi-digivox-ii.o \
 			rc-msi-digivox-iii.o \
 			rc-msi-tvanywhere.o \
diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c
new file mode 100644
index 0000000..ba76609
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c
@@ -0,0 +1,91 @@
+/* asus-ps3-100.h - Keytable for asus_ps3_100 Remote Controller
+ *
+ * Copyright (c) 2012 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Based on a previous patch from Remi Schwartz <remi.schwartz@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 <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table asus_ps3_100[] = {
+	{ 0x081c, KEY_HOME },             /* home */
+	{ 0x081e, KEY_TV },               /* tv */
+	{ 0x0803, KEY_TEXT },             /* teletext */
+	{ 0x0829, KEY_POWER },            /* close */
+
+	{ 0x080b, KEY_RED },              /* red */
+	{ 0x080d, KEY_YELLOW },           /* yellow */
+	{ 0x0806, KEY_BLUE },             /* blue */
+	{ 0x0807, KEY_GREEN },            /* green */
+
+	/* Keys 0 to 9 */
+	{ 0x082a, KEY_0 },
+	{ 0x0816, KEY_1 },
+	{ 0x0812, KEY_2 },
+	{ 0x0814, KEY_3 },
+	{ 0x0836, KEY_4 },
+	{ 0x0832, KEY_5 },
+	{ 0x0834, KEY_6 },
+	{ 0x080e, KEY_7 },
+	{ 0x080a, KEY_8 },
+	{ 0x080c, KEY_9 },
+
+	{ 0x0815, KEY_VOLUMEUP },
+	{ 0x0826, KEY_VOLUMEDOWN },
+	{ 0x0835, KEY_CHANNELUP },        /* channel / program + */
+	{ 0x0824, KEY_CHANNELDOWN },      /* channel / program - */
+
+	{ 0x0808, KEY_UP },
+	{ 0x0804, KEY_DOWN },
+	{ 0x0818, KEY_LEFT },
+	{ 0x0810, KEY_RIGHT },
+	{ 0x0825, KEY_ENTER },            /* enter */
+
+	{ 0x0822, KEY_EXIT },             /* back */
+	{ 0x082c, KEY_AB },               /* recall */
+
+	{ 0x0820, KEY_AUDIO },            /* TV audio */
+	{ 0x0837, KEY_SCREEN },           /* snapshot */
+	{ 0x082e, KEY_ZOOM },             /* full screen */
+	{ 0x0802, KEY_MUTE },             /* mute */
+
+	{ 0x0831, KEY_REWIND },           /* backward << */
+	{ 0x0811, KEY_RECORD },           /* recording */
+	{ 0x0809, KEY_STOP },
+	{ 0x0805, KEY_FASTFORWARD },      /* forward >> */
+	{ 0x0821, KEY_PREVIOUS },         /* rew */
+	{ 0x081a, KEY_PAUSE },            /* pause */
+	{ 0x0839, KEY_PLAY },             /* play */
+	{ 0x0819, KEY_NEXT },             /* forward */
+};
+
+static struct rc_map_list asus_ps3_100_map = {
+.map = {
+	.scan    = asus_ps3_100,
+	.size    = ARRAY_SIZE(asus_ps3_100),
+	.rc_type = RC_TYPE_RC5,
+	.name    = RC_MAP_ASUS_PS3_100,
+}
+};
+
+static int __init init_rc_map_asus_ps3_100(void)
+{
+return rc_map_register(&asus_ps3_100_map);
+}
+
+static void __exit exit_rc_map_asus_ps3_100(void)
+{
+rc_map_unregister(&asus_ps3_100_map);
+}
+
+module_init(init_rc_map_asus_ps3_100)
+module_exit(exit_rc_map_asus_ps3_100)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c
index 28e376e..bd42a30 100644
--- a/drivers/media/rc/keymaps/rc-it913x-v2.c
+++ b/drivers/media/rc/keymaps/rc-it913x-v2.c
@@ -40,7 +40,7 @@
 	/* Type 2 */
 	/* keys stereo, snapshot unassigned */
 	{ 0x866b00, KEY_0 },
-	{ 0x866b1b, KEY_1 },
+	{ 0x866b01, KEY_1 },
 	{ 0x866b02, KEY_2 },
 	{ 0x866b03, KEY_3 },
 	{ 0x866b04, KEY_4 },
diff --git a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c
new file mode 100644
index 0000000..966f9b3
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c
@@ -0,0 +1,123 @@
+/*
+ * Medion X10 RF remote keytable (Digitainer variant)
+ *
+ * Copyright (C) 2012 Anssi Hannula <anssi.hannula@iki.fi>
+ *
+ * This keymap is for a variant that has a distinctive scrollwheel instead of
+ * up/down buttons (tested with P/N 40009936 / 20018268), reportedly
+ * originally shipped with Medion Digitainer but now sold separately simply as
+ * an "X10" remote.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <media/rc-map.h>
+
+static struct rc_map_table medion_x10_digitainer[] = {
+	{ 0x02, KEY_POWER },
+
+	{ 0x2c, KEY_TV },
+	{ 0x2d, KEY_VIDEO },
+	{ 0x04, KEY_DVD },    /* CD/DVD */
+	{ 0x16, KEY_TEXT },   /* "teletext" icon, i.e. a screen with lines */
+	{ 0x06, KEY_AUDIO },
+	{ 0x2e, KEY_RADIO },
+	{ 0x31, KEY_EPG },    /* a screen with an open book */
+	{ 0x05, KEY_IMAGES }, /* Photo */
+	{ 0x2f, KEY_INFO },
+
+	{ 0x78, KEY_UP },     /* scrollwheel up 1 notch */
+	/* 0x79..0x7f: 2-8 notches, driver repeats 0x78 entry */
+
+	{ 0x70, KEY_DOWN },   /* scrollwheel down 1 notch */
+	/* 0x71..0x77: 2-8 notches, driver repeats 0x70 entry */
+
+	{ 0x19, KEY_MENU },
+	{ 0x1d, KEY_LEFT },
+	{ 0x1e, KEY_OK },     /* scrollwheel press */
+	{ 0x1f, KEY_RIGHT },
+	{ 0x20, KEY_BACK },
+
+	{ 0x09, KEY_VOLUMEUP },
+	{ 0x08, KEY_VOLUMEDOWN },
+	{ 0x00, KEY_MUTE },
+
+	{ 0x1b, KEY_SELECT }, /* also has "U" rotated 90 degrees CCW */
+
+	{ 0x0b, KEY_CHANNELUP },
+	{ 0x0c, KEY_CHANNELDOWN },
+	{ 0x1c, KEY_LAST },
+
+	{ 0x32, KEY_RED },    /* also Audio */
+	{ 0x33, KEY_GREEN },  /* also Subtitle */
+	{ 0x34, KEY_YELLOW }, /* also Angle */
+	{ 0x35, KEY_BLUE },   /* also Title */
+
+	{ 0x28, KEY_STOP },
+	{ 0x29, KEY_PAUSE },
+	{ 0x25, KEY_PLAY },
+	{ 0x21, KEY_PREVIOUS },
+	{ 0x18, KEY_CAMERA },
+	{ 0x23, KEY_NEXT },
+	{ 0x24, KEY_REWIND },
+	{ 0x27, KEY_RECORD },
+	{ 0x26, KEY_FORWARD },
+
+	{ 0x0d, KEY_1 },
+	{ 0x0e, KEY_2 },
+	{ 0x0f, KEY_3 },
+	{ 0x10, KEY_4 },
+	{ 0x11, KEY_5 },
+	{ 0x12, KEY_6 },
+	{ 0x13, KEY_7 },
+	{ 0x14, KEY_8 },
+	{ 0x15, KEY_9 },
+	{ 0x17, KEY_0 },
+
+	/* these do not actually exist on this remote, but these scancodes
+	 * exist on all other Medion X10 remotes and adding them here allows
+	 * such remotes to be adequately usable with this keymap in case
+	 * this keymap is wrongly used with them (which is quite possible as
+	 * there are lots of different Medion X10 remotes): */
+	{ 0x1a, KEY_UP },
+	{ 0x22, KEY_DOWN },
+};
+
+static struct rc_map_list medion_x10_digitainer_map = {
+	.map = {
+		.scan    = medion_x10_digitainer,
+		.size    = ARRAY_SIZE(medion_x10_digitainer),
+		.rc_type = RC_TYPE_OTHER,
+		.name    = RC_MAP_MEDION_X10_DIGITAINER,
+	}
+};
+
+static int __init init_rc_map_medion_x10_digitainer(void)
+{
+	return rc_map_register(&medion_x10_digitainer_map);
+}
+
+static void __exit exit_rc_map_medion_x10_digitainer(void)
+{
+	rc_map_unregister(&medion_x10_digitainer_map);
+}
+
+module_init(init_rc_map_medion_x10_digitainer)
+module_exit(exit_rc_map_medion_x10_digitainer)
+
+MODULE_DESCRIPTION("Medion X10 RF remote keytable (Digitainer variant)");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c
new file mode 100644
index 0000000..b077300
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c
@@ -0,0 +1,108 @@
+/*
+ * Medion X10 OR22/OR24 RF remote keytable
+ *
+ * Copyright (C) 2012 Anssi Hannula <anssi.hannula@iki.fi>
+ *
+ * This keymap is for several Medion X10 remotes that have the Windows MCE
+ * button. This has been tested with a "RF VISTA Remote Control", OR24V,
+ * P/N 20035335, but should work with other variants that have the same
+ * buttons, such as OR22V and OR24E.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <media/rc-map.h>
+
+static struct rc_map_table medion_x10_or2x[] = {
+	{ 0x02, KEY_POWER },
+	{ 0x16, KEY_TEXT },   /* "T" in a box, for teletext */
+
+	{ 0x09, KEY_VOLUMEUP },
+	{ 0x08, KEY_VOLUMEDOWN },
+	{ 0x00, KEY_MUTE },
+	{ 0x0b, KEY_CHANNELUP },
+	{ 0x0c, KEY_CHANNELDOWN },
+
+	{ 0x32, KEY_RED },
+	{ 0x33, KEY_GREEN },
+	{ 0x34, KEY_YELLOW },
+	{ 0x35, KEY_BLUE },
+
+	{ 0x18, KEY_PVR },    /* record symbol inside a tv symbol */
+	{ 0x04, KEY_DVD },    /* disc symbol */
+	{ 0x31, KEY_EPG },    /* a tv schedule symbol */
+	{ 0x1c, KEY_TV },     /* play symbol inside a tv symbol */
+	{ 0x20, KEY_BACK },
+	{ 0x2f, KEY_INFO },
+
+	{ 0x1a, KEY_UP },
+	{ 0x22, KEY_DOWN },
+	{ 0x1d, KEY_LEFT },
+	{ 0x1f, KEY_RIGHT },
+	{ 0x1e, KEY_OK },
+
+	{ 0x1b, KEY_MEDIA },  /* Windows MCE button */
+
+	{ 0x21, KEY_PREVIOUS },
+	{ 0x23, KEY_NEXT },
+	{ 0x24, KEY_REWIND },
+	{ 0x26, KEY_FORWARD },
+	{ 0x25, KEY_PLAY },
+	{ 0x28, KEY_STOP },
+	{ 0x29, KEY_PAUSE },
+	{ 0x27, KEY_RECORD },
+
+	{ 0x0d, KEY_1 },
+	{ 0x0e, KEY_2 },
+	{ 0x0f, KEY_3 },
+	{ 0x10, KEY_4 },
+	{ 0x11, KEY_5 },
+	{ 0x12, KEY_6 },
+	{ 0x13, KEY_7 },
+	{ 0x14, KEY_8 },
+	{ 0x15, KEY_9 },
+	{ 0x17, KEY_0 },
+	{ 0x30, KEY_CLEAR },
+	{ 0x36, KEY_ENTER },
+	{ 0x37, KEY_NUMERIC_STAR },
+	{ 0x38, KEY_NUMERIC_POUND },
+};
+
+static struct rc_map_list medion_x10_or2x_map = {
+	.map = {
+		.scan    = medion_x10_or2x,
+		.size    = ARRAY_SIZE(medion_x10_or2x),
+		.rc_type = RC_TYPE_OTHER,
+		.name    = RC_MAP_MEDION_X10_OR2X,
+	}
+};
+
+static int __init init_rc_map_medion_x10_or2x(void)
+{
+	return rc_map_register(&medion_x10_or2x_map);
+}
+
+static void __exit exit_rc_map_medion_x10_or2x(void)
+{
+	rc_map_unregister(&medion_x10_or2x_map);
+}
+
+module_init(init_rc_map_medion_x10_or2x)
+module_exit(exit_rc_map_medion_x10_or2x)
+
+MODULE_DESCRIPTION("Medion X10 OR22/OR24 RF remote keytable");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index e150a2e..84e06d3 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -520,7 +520,7 @@
 {
 	char codes[USB_BUFLEN * 3 + 1];
 	char inout[9];
-	u8 cmd, subcmd, data1, data2, data3, data4, data5;
+	u8 cmd, subcmd, data1, data2, data3, data4;
 	struct device *dev = ir->dev;
 	int i, start, skip = 0;
 	u32 carrier, period;
@@ -553,7 +553,6 @@
 	data2  = buf[start + 3] & 0xff;
 	data3  = buf[start + 4] & 0xff;
 	data4  = buf[start + 5] & 0xff;
-	data5  = buf[start + 6] & 0xff;
 
 	switch (cmd) {
 	case MCE_CMD_NULL:
@@ -1443,7 +1442,7 @@
 static struct usb_driver mceusb_dev_driver = {
 	.name =		DRIVER_NAME,
 	.probe =	mceusb_dev_probe,
-	.disconnect =	mceusb_dev_disconnect,
+	.disconnect =	__devexit_p(mceusb_dev_disconnect),
 	.suspend =	mceusb_dev_suspend,
 	.resume =	mceusb_dev_resume,
 	.reset_resume =	mceusb_dev_resume,
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 8b2c071..dc8a7dd 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -1075,19 +1075,19 @@
 
 	if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
 			NVT_DRIVER_NAME, (void *)nvt))
-		goto failure;
+		goto failure2;
 
 	if (!request_region(nvt->cir_wake_addr,
 			    CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
-		goto failure;
+		goto failure3;
 
 	if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
 			NVT_DRIVER_NAME, (void *)nvt))
-		goto failure;
+		goto failure4;
 
 	ret = rc_register_device(rdev);
 	if (ret)
-		goto failure;
+		goto failure5;
 
 	device_init_wakeup(&pdev->dev, true);
 	nvt->rdev = rdev;
@@ -1099,17 +1099,15 @@
 
 	return 0;
 
+failure5:
+	free_irq(nvt->cir_wake_irq, nvt);
+failure4:
+	release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
+failure3:
+	free_irq(nvt->cir_irq, nvt);
+failure2:
+	release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
 failure:
-	if (nvt->cir_irq)
-		free_irq(nvt->cir_irq, nvt);
-	if (nvt->cir_addr)
-		release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
-
-	if (nvt->cir_wake_irq)
-		free_irq(nvt->cir_wake_irq, nvt);
-	if (nvt->cir_wake_addr)
-		release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
-
 	rc_free_device(rdev);
 	kfree(nvt);
 
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index efc6a51..fae1615 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -221,7 +221,6 @@
 	rc->s_idle		= loop_set_idle;
 	rc->s_learning_mode	= loop_set_learning_mode;
 	rc->s_carrier_report	= loop_set_carrier_report;
-	rc->priv		= &loopdev;
 
 	loopdev.txmask		= RXMASK_REGULAR;
 	loopdev.txcarrier	= 36000;
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index ad95c67..2878b0e 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -1277,7 +1277,7 @@
 static struct usb_driver redrat3_dev_driver = {
 	.name		= DRIVER_NAME,
 	.probe		= redrat3_dev_probe,
-	.disconnect	= redrat3_dev_disconnect,
+	.disconnect	= __devexit_p(redrat3_dev_disconnect),
 	.suspend	= redrat3_dev_suspend,
 	.resume		= redrat3_dev_resume,
 	.reset_resume	= redrat3_dev_resume,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ce1e7ba..99937c9 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -472,6 +472,9 @@
 config VIDEO_APTINA_PLL
 	tristate
 
+config VIDEO_SMIAPP_PLL
+	tristate
+
 config VIDEO_OV7670
 	tristate "OmniVision OV7670 sensor support"
 	depends on I2C && VIDEO_V4L2
@@ -556,6 +559,8 @@
 	  This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
 	  camera sensor with an embedded SoC image signal processor.
 
+source "drivers/media/video/smiapp/Kconfig"
+
 comment "Flash devices"
 
 config VIDEO_ADP1653
@@ -644,6 +649,8 @@
 
 if V4L_USB_DRIVERS
 
+source "drivers/media/video/au0828/Kconfig"
+
 source "drivers/media/video/uvc/Kconfig"
 
 source "drivers/media/video/gspca/Kconfig"
@@ -662,8 +669,6 @@
 
 source "drivers/media/video/usbvision/Kconfig"
 
-source "drivers/media/video/et61x251/Kconfig"
-
 source "drivers/media/video/sn9c102/Kconfig"
 
 source "drivers/media/video/pwc/Kconfig"
@@ -721,8 +726,6 @@
 
 if V4L_PCI_DRIVERS
 
-source "drivers/media/video/au0828/Kconfig"
-
 source "drivers/media/video/bt8xx/Kconfig"
 
 source "drivers/media/video/cx18/Kconfig"
@@ -794,6 +797,19 @@
 
 source "drivers/media/video/zoran/Kconfig"
 
+config STA2X11_VIP
+	tristate "STA2X11 VIP Video For Linux"
+	depends on STA2X11
+	select VIDEO_ADV7180 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEOBUF_DMA_CONTIG
+	depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
+	help
+	  Say Y for support for STA2X11 VIP (Video Input Port) capture
+	  device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sta2x11_vip.
+
 endif # V4L_PCI_DRIVERS
 
 #
@@ -1127,19 +1143,6 @@
 	  This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
 	  Interface
 
-config  VIDEO_SAMSUNG_S5P_FIMC
-	tristate "Samsung S5P and EXYNOS4 camera interface driver (EXPERIMENTAL)"
-	depends on VIDEO_V4L2 && I2C && PLAT_S5P && PM_RUNTIME && \
-		VIDEO_V4L2_SUBDEV_API && EXPERIMENTAL
-	select VIDEOBUF2_DMA_CONTIG
-	select V4L2_MEM2MEM_DEV
-	---help---
-	  This is a v4l2 driver for Samsung S5P and EXYNOS4 camera
-	  host interface and video postprocessor.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called s5p-fimc.
-
 config VIDEO_ATMEL_ISI
 	tristate "ATMEL Image Sensor Interface (ISI) support"
 	depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
@@ -1148,16 +1151,7 @@
 	  This module makes the ATMEL Image Sensor Interface available
 	  as a v4l2 device.
 
-config VIDEO_S5P_MIPI_CSIS
-	tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
-	depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P
-	depends on VIDEO_V4L2_SUBDEV_API && REGULATOR
-	---help---
-	  This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called s5p-csis.
-
+source "drivers/media/video/s5p-fimc/Kconfig"
 source "drivers/media/video/s5p-tv/Kconfig"
 
 endif # V4L_PLATFORM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index a6282a3..d209de0 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -79,9 +79,12 @@
 obj-$(CONFIG_VIDEO_NOON010PC30)	+= noon010pc30.o
 obj-$(CONFIG_VIDEO_M5MOLS)	+= m5mols/
 obj-$(CONFIG_VIDEO_S5K6AA)	+= s5k6aa.o
+obj-$(CONFIG_VIDEO_SMIAPP)	+= smiapp/
 obj-$(CONFIG_VIDEO_ADP1653)	+= adp1653.o
 obj-$(CONFIG_VIDEO_AS3645A)	+= as3645a.o
 
+obj-$(CONFIG_VIDEO_SMIAPP_PLL)	+= smiapp-pll.o
+
 obj-$(CONFIG_SOC_CAMERA_IMX074)		+= imx074.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
@@ -120,6 +123,7 @@
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
 obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
+obj-$(CONFIG_STA2X11_VIP) += sta2x11_vip.o
 obj-$(CONFIG_VIDEO_TIMBERDALE)	+= timblogiw.o
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
@@ -152,7 +156,6 @@
 obj-$(CONFIG_USB_STKWEBCAM)     += stkwebcam.o
 
 obj-$(CONFIG_USB_SN9C102)       += sn9c102/
-obj-$(CONFIG_USB_ET61X251)      += et61x251/
 obj-$(CONFIG_USB_PWC)           += pwc/
 obj-$(CONFIG_USB_GSPCA)         += gspca/
 
diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c
index 5b045b4..57e8709 100644
--- a/drivers/media/video/adp1653.c
+++ b/drivers/media/video/adp1653.c
@@ -34,7 +34,6 @@
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 #include <media/adp1653.h>
 #include <media/v4l2-device.h>
 
@@ -282,19 +281,19 @@
 		return -EIO;
 	}
 
-	mutex_lock(&flash->ctrls.lock);
+	mutex_lock(flash->ctrls.lock);
 	/* Reset faults before reading new ones. */
 	flash->fault = 0;
 	rval = adp1653_get_fault(flash);
-	mutex_unlock(&flash->ctrls.lock);
+	mutex_unlock(flash->ctrls.lock);
 	if (rval > 0) {
 		dev_err(&client->dev, "faults detected: 0x%1.1x\n", rval);
 		return -EIO;
 	}
 
-	mutex_lock(&flash->ctrls.lock);
+	mutex_lock(flash->ctrls.lock);
 	rval = adp1653_update_hw(flash);
-	mutex_unlock(&flash->ctrls.lock);
+	mutex_unlock(flash->ctrls.lock);
 	if (rval) {
 		dev_err(&client->dev,
 			"adp1653_update_hw failed at %s\n", __func__);
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index b8b6c4b..174bffa 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -48,6 +48,7 @@
 #define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED		0xd0
 #define ADV7180_INPUT_CONTROL_PAL_SECAM			0xe0
 #define ADV7180_INPUT_CONTROL_PAL_SECAM_PED		0xf0
+#define ADV7180_INPUT_CONTROL_INSEL_MASK		0x0f
 
 #define ADV7180_EXTENDED_OUTPUT_CONTROL_REG		0x04
 #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
@@ -55,9 +56,29 @@
 #define ADV7180_AUTODETECT_ENABLE_REG			0x07
 #define ADV7180_AUTODETECT_DEFAULT			0x7f
 
+#define ADV7180_CON_REG		0x08	/*Unsigned */
+#define CON_REG_MIN		0
+#define CON_REG_DEF		128
+#define CON_REG_MAX		255
+
+#define ADV7180_BRI_REG		0x0a	/*Signed */
+#define BRI_REG_MIN		-128
+#define BRI_REG_DEF		0
+#define BRI_REG_MAX		127
+
+#define ADV7180_HUE_REG		0x0b	/*Signed, inverted */
+#define HUE_REG_MIN		-127
+#define HUE_REG_DEF		0
+#define HUE_REG_MAX		128
+
 #define ADV7180_ADI_CTRL_REG				0x0e
 #define ADV7180_ADI_CTRL_IRQ_SPACE			0x20
 
+#define ADV7180_PWR_MAN_REG		0x0f
+#define ADV7180_PWR_MAN_ON		0x04
+#define ADV7180_PWR_MAN_OFF		0x24
+#define ADV7180_PWR_MAN_RES		0x80
+
 #define ADV7180_STATUS1_REG				0x10
 #define ADV7180_STATUS1_IN_LOCK		0x01
 #define ADV7180_STATUS1_AUTOD_MASK	0x70
@@ -78,6 +99,12 @@
 #define ADV7180_ICONF1_PSYNC_ONLY	0x10
 #define ADV7180_ICONF1_ACTIVE_TO_CLR	0xC0
 
+#define ADV7180_SD_SAT_CB_REG	0xe3	/*Unsigned */
+#define ADV7180_SD_SAT_CR_REG	0xe4	/*Unsigned */
+#define SAT_REG_MIN		0
+#define SAT_REG_DEF		128
+#define SAT_REG_MAX		255
+
 #define ADV7180_IRQ1_LOCK	0x01
 #define ADV7180_IRQ1_UNLOCK	0x02
 #define ADV7180_ISR1_ADI	0x42
@@ -90,6 +117,9 @@
 #define ADV7180_IMR3_ADI	0x4C
 #define ADV7180_IMR4_ADI	0x50
 
+#define ADV7180_NTSC_V_BIT_END_REG	0xE6
+#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
+
 struct adv7180_state {
 	struct v4l2_subdev	sd;
 	struct work_struct	work;
@@ -97,6 +127,11 @@
 	int			irq;
 	v4l2_std_id		curr_norm;
 	bool			autodetect;
+	s8			brightness;
+	s16			hue;
+	u8			contrast;
+	u8			saturation;
+	u8			input;
 };
 
 static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
@@ -155,7 +190,7 @@
 }
 
 static int __adv7180_status(struct i2c_client *client, u32 *status,
-	v4l2_std_id *std)
+			    v4l2_std_id *std)
 {
 	int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
 
@@ -192,6 +227,36 @@
 	return err;
 }
 
+static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
+			     u32 output, u32 config)
+{
+	struct adv7180_state *state = to_state(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (ret)
+		return ret;
+
+	/*We cannot discriminate between LQFP and 40-pin LFCSP, so accept
+	 * all inputs and let the card driver take care of validation
+	 */
+	if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
+		goto out;
+
+	ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
+
+	if (ret < 0)
+		goto out;
+
+	ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
+	ret = i2c_smbus_write_byte_data(client,
+					ADV7180_INPUT_CONTROL_REG, ret | input);
+	state->input = input;
+out:
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
 static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
 {
 	struct adv7180_state *state = to_state(sd);
@@ -205,7 +270,7 @@
 }
 
 static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
-	struct v4l2_dbg_chip_ident *chip)
+				struct v4l2_dbg_chip_ident *chip)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
@@ -222,9 +287,10 @@
 
 	/* all standards -> autodetect */
 	if (std == V4L2_STD_ALL) {
-		ret = i2c_smbus_write_byte_data(client,
-			ADV7180_INPUT_CONTROL_REG,
-			ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
+		ret =
+		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
+					      | state->input);
 		if (ret < 0)
 			goto out;
 
@@ -236,7 +302,8 @@
 			goto out;
 
 		ret = i2c_smbus_write_byte_data(client,
-			ADV7180_INPUT_CONTROL_REG, ret);
+						ADV7180_INPUT_CONTROL_REG,
+						ret | state->input);
 		if (ret < 0)
 			goto out;
 
@@ -249,14 +316,138 @@
 	return ret;
 }
 
+static int adv7180_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+	switch (qc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, BRI_REG_MIN, BRI_REG_MAX,
+					    1, BRI_REG_DEF);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(qc, HUE_REG_MIN, HUE_REG_MAX,
+					    1, HUE_REG_DEF);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(qc, CON_REG_MIN, CON_REG_MAX,
+					    1, CON_REG_DEF);
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(qc, SAT_REG_MIN, SAT_REG_MAX,
+					    1, SAT_REG_DEF);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int adv7180_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct adv7180_state *state = to_state(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	if (ret)
+		return ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = state->brightness;
+		break;
+	case V4L2_CID_HUE:
+		ctrl->value = state->hue;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = state->contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		ctrl->value = state->saturation;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
+static int adv7180_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct adv7180_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	if (ret)
+		return ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if ((ctrl->value > BRI_REG_MAX)
+		    || (ctrl->value < BRI_REG_MIN)) {
+			ret = -ERANGE;
+			break;
+		}
+		state->brightness = ctrl->value;
+		ret = i2c_smbus_write_byte_data(client,
+						ADV7180_BRI_REG,
+						state->brightness);
+		break;
+	case V4L2_CID_HUE:
+		if ((ctrl->value > HUE_REG_MAX)
+		    || (ctrl->value < HUE_REG_MIN)) {
+			ret = -ERANGE;
+			break;
+		}
+		state->hue = ctrl->value;
+		/*Hue is inverted according to HSL chart */
+		ret = i2c_smbus_write_byte_data(client,
+						ADV7180_HUE_REG, -state->hue);
+		break;
+	case V4L2_CID_CONTRAST:
+		if ((ctrl->value > CON_REG_MAX)
+		    || (ctrl->value < CON_REG_MIN)) {
+			ret = -ERANGE;
+			break;
+		}
+		state->contrast = ctrl->value;
+		ret = i2c_smbus_write_byte_data(client,
+						ADV7180_CON_REG,
+						state->contrast);
+		break;
+	case V4L2_CID_SATURATION:
+		if ((ctrl->value > SAT_REG_MAX)
+		    || (ctrl->value < SAT_REG_MIN)) {
+			ret = -ERANGE;
+			break;
+		}
+		/*
+		 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
+		 *Let's not confuse the user, everybody understands saturation
+		 */
+		state->saturation = ctrl->value;
+		ret = i2c_smbus_write_byte_data(client,
+						ADV7180_SD_SAT_CB_REG,
+						state->saturation);
+		if (ret < 0)
+			break;
+		ret = i2c_smbus_write_byte_data(client,
+						ADV7180_SD_SAT_CR_REG,
+						state->saturation);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
 static const struct v4l2_subdev_video_ops adv7180_video_ops = {
 	.querystd = adv7180_querystd,
 	.g_input_status = adv7180_g_input_status,
+	.s_routing = adv7180_s_routing,
 };
 
 static const struct v4l2_subdev_core_ops adv7180_core_ops = {
 	.g_chip_ident = adv7180_g_chip_ident,
 	.s_std = adv7180_s_std,
+	.queryctrl = adv7180_queryctrl,
+	.g_ctrl = adv7180_g_ctrl,
+	.s_ctrl = adv7180_s_ctrl,
 };
 
 static const struct v4l2_subdev_ops adv7180_ops = {
@@ -267,13 +458,13 @@
 static void adv7180_work(struct work_struct *work)
 {
 	struct adv7180_state *state = container_of(work, struct adv7180_state,
-		work);
+						   work);
 	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
 	u8 isr3;
 
 	mutex_lock(&state->mutex);
 	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
-		ADV7180_ADI_CTRL_IRQ_SPACE);
+				  ADV7180_ADI_CTRL_IRQ_SPACE);
 	isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
 	/* clear */
 	i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
@@ -297,13 +488,128 @@
 	return IRQ_HANDLED;
 }
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
+static int init_device(struct i2c_client *client, struct adv7180_state *state)
+{
+	int ret;
+
+	/* Initialize adv7180 */
+	/* Enable autodetection */
+	if (state->autodetect) {
+		ret =
+		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
+					      | state->input);
+		if (ret < 0)
+			return ret;
+
+		ret =
+		    i2c_smbus_write_byte_data(client,
+					      ADV7180_AUTODETECT_ENABLE_REG,
+					      ADV7180_AUTODETECT_DEFAULT);
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = v4l2_std_to_adv7180(state->curr_norm);
+		if (ret < 0)
+			return ret;
+
+		ret =
+		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+					      ret | state->input);
+		if (ret < 0)
+			return ret;
+
+	}
+	/* ITU-R BT.656-4 compatible */
+	ret = i2c_smbus_write_byte_data(client,
+			ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
+			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
+	if (ret < 0)
+		return ret;
+
+	/* Manually set V bit end position in NTSC mode */
+	ret = i2c_smbus_write_byte_data(client,
+					ADV7180_NTSC_V_BIT_END_REG,
+					ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
+	if (ret < 0)
+		return ret;
+
+	/* read current norm */
+	__adv7180_status(client, NULL, &state->curr_norm);
+
+	/* register for interrupts */
+	if (state->irq > 0) {
+		ret = request_irq(state->irq, adv7180_irq, 0, DRIVER_NAME,
+				  state);
+		if (ret)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
+						ADV7180_ADI_CTRL_IRQ_SPACE);
+		if (ret < 0)
+			return ret;
+
+		/* config the Interrupt pin to be active low */
+		ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
+						ADV7180_ICONF1_ACTIVE_LOW |
+						ADV7180_ICONF1_PSYNC_ONLY);
+		if (ret < 0)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
+		if (ret < 0)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
+		if (ret < 0)
+			return ret;
+
+		/* enable AD change interrupts interrupts */
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
+						ADV7180_IRQ3_AD_CHANGE);
+		if (ret < 0)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
+		if (ret < 0)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
+						0);
+		if (ret < 0)
+			return ret;
+	}
+
+	/*Set default value for controls */
+	ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG,
+					state->brightness);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, state->hue);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG,
+					state->contrast);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
+					state->saturation);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
+					state->saturation);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
 
 static __devinit int adv7180_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
+				   const struct i2c_device_id *id)
 {
 	struct adv7180_state *state;
 	struct v4l2_subdev *sd;
@@ -314,7 +620,7 @@
 		return -EIO;
 
 	v4l_info(client, "chip found @ 0x%02x (%s)\n",
-			client->addr << 1, client->adapter->name);
+		 client->addr, client->adapter->name);
 
 	state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
 	if (state == NULL) {
@@ -326,73 +632,17 @@
 	INIT_WORK(&state->work, adv7180_work);
 	mutex_init(&state->mutex);
 	state->autodetect = true;
+	state->brightness = BRI_REG_DEF;
+	state->hue = HUE_REG_DEF;
+	state->contrast = CON_REG_DEF;
+	state->saturation = SAT_REG_DEF;
+	state->input = 0;
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
 
-	/* Initialize adv7180 */
-	/* Enable autodetection */
-	ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
-		ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
-	if (ret < 0)
+	ret = init_device(client, state);
+	if (0 != ret)
 		goto err_unreg_subdev;
-
-	ret = i2c_smbus_write_byte_data(client, ADV7180_AUTODETECT_ENABLE_REG,
-		ADV7180_AUTODETECT_DEFAULT);
-	if (ret < 0)
-		goto err_unreg_subdev;
-
-	/* ITU-R BT.656-4 compatible */
-	ret = i2c_smbus_write_byte_data(client,
-		ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
-		ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
-	if (ret < 0)
-		goto err_unreg_subdev;
-
-	/* read current norm */
-	__adv7180_status(client, NULL, &state->curr_norm);
-
-	/* register for interrupts */
-	if (state->irq > 0) {
-		ret = request_irq(state->irq, adv7180_irq, 0, DRIVER_NAME,
-			state);
-		if (ret)
-			goto err_unreg_subdev;
-
-		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
-			ADV7180_ADI_CTRL_IRQ_SPACE);
-		if (ret < 0)
-			goto err_unreg_subdev;
-
-		/* config the Interrupt pin to be active low */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
-			ADV7180_ICONF1_ACTIVE_LOW | ADV7180_ICONF1_PSYNC_ONLY);
-		if (ret < 0)
-			goto err_unreg_subdev;
-
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
-		if (ret < 0)
-			goto err_unreg_subdev;
-
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
-		if (ret < 0)
-			goto err_unreg_subdev;
-
-		/* enable AD change interrupts interrupts */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
-			ADV7180_IRQ3_AD_CHANGE);
-		if (ret < 0)
-			goto err_unreg_subdev;
-
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
-		if (ret < 0)
-			goto err_unreg_subdev;
-
-		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
-			0);
-		if (ret < 0)
-			goto err_unreg_subdev;
-	}
-
 	return 0;
 
 err_unreg_subdev:
@@ -432,16 +682,49 @@
 	{},
 };
 
+#ifdef CONFIG_PM
+static int adv7180_suspend(struct i2c_client *client, pm_message_t state)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
+					ADV7180_PWR_MAN_OFF);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int adv7180_resume(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7180_state *state = to_state(sd);
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
+					ADV7180_PWR_MAN_ON);
+	if (ret < 0)
+		return ret;
+	ret = init_device(client, state);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+#endif
+
 MODULE_DEVICE_TABLE(i2c, adv7180_id);
 
 static struct i2c_driver adv7180_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
-		.name	= DRIVER_NAME,
-	},
-	.probe		= adv7180_probe,
-	.remove		= __devexit_p(adv7180_remove),
-	.id_table	= adv7180_id,
+		   .owner = THIS_MODULE,
+		   .name = DRIVER_NAME,
+		   },
+	.probe = adv7180_probe,
+	.remove = __devexit_p(adv7180_remove),
+#ifdef CONFIG_PM
+	.suspend = adv7180_suspend,
+	.resume = adv7180_resume,
+#endif
+	.id_table = adv7180_id,
 };
 
 module_i2c_driver(adv7180_driver);
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c
index 119b604..2b5aa67 100644
--- a/drivers/media/video/adv7343.c
+++ b/drivers/media/video/adv7343.c
@@ -130,14 +130,12 @@
 {
 	struct adv7343_state *state = to_state(sd);
 	struct adv7343_std_info *std_info;
-	int output_idx, num_std;
+	int num_std;
 	char *fsc_ptr;
 	u8 reg, val;
 	int err = 0;
 	int i = 0;
 
-	output_idx = state->output;
-
 	std_info = (struct adv7343_std_info *)stdinfo;
 	num_std = ARRAY_SIZE(stdinfo);
 
diff --git a/drivers/media/video/aptina-pll.c b/drivers/media/video/aptina-pll.c
index 0bd3813..8153a44 100644
--- a/drivers/media/video/aptina-pll.c
+++ b/drivers/media/video/aptina-pll.c
@@ -148,9 +148,8 @@
 		unsigned int mf_high;
 		unsigned int mf_low;
 
-		mf_low = max(roundup(mf_min, mf_inc),
-			     DIV_ROUND_UP(pll->ext_clock * p1,
-			       limits->int_clock_max * div));
+		mf_low = roundup(max(mf_min, DIV_ROUND_UP(pll->ext_clock * p1,
+					limits->int_clock_max * div)), mf_inc);
 		mf_high = min(mf_max, pll->ext_clock * p1 /
 			      (limits->int_clock_min * div));
 
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index b6ed44a..e346d32d 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -31,6 +31,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
 #include <linux/mutex.h>
 
 #include <asm/uaccess.h>
@@ -403,7 +404,8 @@
 	strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver));
 	strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card));
 	strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info));
-	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -709,6 +711,8 @@
 
 static const struct v4l2_file_operations ar_fops = {
 	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
 	.read		= ar_read,
 	.unlocked_ioctl	= video_ioctl2,
 };
@@ -769,6 +773,7 @@
 	ar->vdev.fops = &ar_fops;
 	ar->vdev.ioctl_ops = &ar_ioctl_ops;
 	ar->vdev.release = video_device_release_empty;
+	set_bit(V4L2_FL_USE_FH_PRIO, &ar->vdev.flags);
 	video_set_drvdata(&ar->vdev, ar);
 
 	if (vga) {
diff --git a/drivers/media/video/as3645a.c b/drivers/media/video/as3645a.c
index 7a3371f..c4b0357 100644
--- a/drivers/media/video/as3645a.c
+++ b/drivers/media/video/as3645a.c
@@ -713,7 +713,7 @@
  * The number of LEDs reported in platform data is used to compute default
  * limits. Parameters passed through platform data can override those limits.
  */
-static int as3645a_init_controls(struct as3645a *flash)
+static int __devinit as3645a_init_controls(struct as3645a *flash)
 {
 	const struct as3645a_platform_data *pdata = flash->pdata;
 	struct v4l2_ctrl *ctrl;
@@ -804,8 +804,8 @@
 	return flash->ctrls.error;
 }
 
-static int as3645a_probe(struct i2c_client *client,
-			 const struct i2c_device_id *devid)
+static int __devinit as3645a_probe(struct i2c_client *client,
+				   const struct i2c_device_id *devid)
 {
 	struct as3645a *flash;
 	int ret;
@@ -846,7 +846,7 @@
 	return ret;
 }
 
-static int __exit as3645a_remove(struct i2c_client *client)
+static int __devexit as3645a_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
 	struct as3645a *flash = to_as3645a(subdev);
@@ -877,7 +877,7 @@
 		.pm   = &as3645a_pm_ops,
 	},
 	.probe	= as3645a_probe,
-	.remove	= __exit_p(as3645a_remove),
+	.remove	= __devexit_p(as3645a_remove),
 	.id_table = as3645a_id_table,
 };
 
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
index ec3f6a0..6274a91 100644
--- a/drivers/media/video/atmel-isi.c
+++ b/drivers/media/video/atmel-isi.c
@@ -260,7 +260,7 @@
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct atmel_isi *isi = ici->priv;
 	unsigned long size;
-	int ret, bytes_per_line;
+	int ret;
 
 	/* Reset ISI */
 	ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET);
@@ -271,13 +271,7 @@
 	/* Disable all interrupts */
 	isi_writel(isi, ISI_INTDIS, ~0UL);
 
-	bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-						icd->current_fmt->host_fmt);
-
-	if (bytes_per_line < 0)
-		return bytes_per_line;
-
-	size = bytes_per_line * icd->user_height;
+	size = icd->sizeimage;
 
 	if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM)
 		*nbuffers = MAX_BUFFER_NUM;
@@ -316,13 +310,8 @@
 	struct atmel_isi *isi = ici->priv;
 	unsigned long size;
 	struct isi_dma_desc *desc;
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-						icd->current_fmt->host_fmt);
 
-	if (bytes_per_line < 0)
-		return bytes_per_line;
-
-	size = bytes_per_line * icd->user_height;
+	size = icd->sizeimage;
 
 	if (vb2_plane_size(vb, 0) < size) {
 		dev_err(icd->parent, "%s data will not fit into plane (%lu < %lu)\n",
@@ -638,6 +627,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 };
 
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index 81ba9d9..23f7fd2 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -6,7 +6,8 @@
 	select I2C_ALGOBIT
 	select VIDEO_TVEEPROM
 	select VIDEOBUF_VMALLOC
-	select DVB_AU8522 if !DVB_FE_CUSTOMISE
+	select DVB_AU8522_DTV if !DVB_FE_CUSTOMISE
+	select DVB_AU8522_V4L if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 1c6015a..e3fe9a6 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -325,6 +325,8 @@
 		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
 	{ USB_DEVICE(0x2040, 0x7281),
 		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+	{ USB_DEVICE(0x05e1, 0x0480),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
 	{ USB_DEVICE(0x2040, 0x8200),
 		.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
 	{ USB_DEVICE(0x2040, 0x7260),
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 5182167..39ece8e 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -25,6 +25,7 @@
 #include <linux/device.h>
 #include <linux/suspend.h>
 #include <media/v4l2-common.h>
+#include <media/tuner.h>
 
 #include "au0828.h"
 #include "au8522.h"
@@ -79,9 +80,16 @@
 	.vsb_if        = AU8522_IF_3_25MHZ,
 };
 
-static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
+static struct xc5000_config hauppauge_xc5000a_config = {
 	.i2c_address      = 0x61,
 	.if_khz           = 6000,
+	.chip_id          = XC5000A,
+};
+
+static struct xc5000_config hauppauge_xc5000c_config = {
+	.i2c_address      = 0x61,
+	.if_khz           = 6000,
+	.chip_id          = XC5000C,
 };
 
 static struct mxl5007t_config mxl5007t_hvr950q_config = {
@@ -383,8 +391,19 @@
 				&hauppauge_hvr950q_config,
 				&dev->i2c_adap);
 		if (dvb->frontend != NULL)
-			dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap,
-				   &hauppauge_hvr950q_tunerconfig);
+			switch (dev->board.tuner_type) {
+			default:
+			case TUNER_XC5000:
+				dvb_attach(xc5000_attach, dvb->frontend,
+					   &dev->i2c_adap,
+					   &hauppauge_xc5000a_config);
+				break;
+			case TUNER_XC5000C:
+				dvb_attach(xc5000_attach, dvb->frontend,
+					   &dev->i2c_adap,
+					   &hauppauge_xc5000c_config);
+				break;
+			}
 		break;
 	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
 		dvb->frontend = dvb_attach(au8522_attach,
@@ -411,7 +430,7 @@
 		if (dvb->frontend != NULL) {
 			dvb_attach(xc5000_attach, dvb->frontend,
 				&dev->i2c_adap,
-				&hauppauge_hvr950q_tunerconfig);
+				&hauppauge_xc5000a_config);
 		}
 		break;
 	default:
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 0b3e481..ac3dd73 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -120,7 +120,7 @@
 	struct au0828_dmaqueue  *dma_q = urb->context;
 	struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
 	unsigned long flags = 0;
-	int rc, i;
+	int i;
 
 	switch (urb->status) {
 	case 0:             /* success */
@@ -138,7 +138,7 @@
 
 	/* Copy data from URB */
 	spin_lock_irqsave(&dev->slock, flags);
-	rc = dev->isoc_ctl.isoc_copy(dev, urb);
+	dev->isoc_ctl.isoc_copy(dev, urb);
 	spin_unlock_irqrestore(&dev->slock, flags);
 
 	/* Reset urb buffers */
@@ -1881,7 +1881,7 @@
 	int retval = -ENOMEM;
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
-	int i;
+	int i, ret;
 
 	dprintk(1, "au0828_analog_register called!\n");
 
@@ -1951,8 +1951,8 @@
 	dev->vbi_dev = video_device_alloc();
 	if (NULL == dev->vbi_dev) {
 		dprintk(1, "Can't allocate vbi_device.\n");
-		kfree(dev->vdev);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err_vdev;
 	}
 
 	/* Fill the video capture device struct */
@@ -1971,8 +1971,8 @@
 	if (retval != 0) {
 		dprintk(1, "unable to register video device (error = %d).\n",
 			retval);
-		video_device_release(dev->vdev);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_vbi_dev;
 	}
 
 	/* Register the vbi device */
@@ -1981,13 +1981,18 @@
 	if (retval != 0) {
 		dprintk(1, "unable to register vbi device (error = %d).\n",
 			retval);
-		video_device_release(dev->vbi_dev);
-		video_device_release(dev->vdev);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_vbi_dev;
 	}
 
 	dprintk(1, "%s completed!\n", __func__);
 
 	return 0;
+
+err_vbi_dev:
+	video_device_release(dev->vbi_dev);
+err_vdev:
+	video_device_release(dev->vdev);
+	return ret;
 }
 
diff --git a/drivers/media/video/blackfin/bfin_capture.c b/drivers/media/video/blackfin/bfin_capture.c
index 514fcf7..0aba45e 100644
--- a/drivers/media/video/blackfin/bfin_capture.c
+++ b/drivers/media/video/blackfin/bfin_capture.c
@@ -942,6 +942,10 @@
 	INIT_LIST_HEAD(&bcap_dev->dma_queue);
 
 	vfd->lock = &bcap_dev->mutex;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 
 	/* register video device */
 	ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1);
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index e581b37..a9cfb0f 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -663,7 +663,7 @@
 		.minimum       = 0,
 		.maximum       = 65535,
 		.step          = 128,
-		.default_value = 32768,
+		.default_value = 27648,
 		.type          = V4L2_CTRL_TYPE_INTEGER,
 	},{
 		.id            = V4L2_CID_SATURATION,
@@ -4394,7 +4394,7 @@
 	if (!bttv_tvcards[btv->c.type].no_video) {
 		bttv_register_video(btv);
 		bt848_bright(btv,32768);
-		bt848_contrast(btv,32768);
+		bt848_contrast(btv, 27648);
 		bt848_hue(btv,32768);
 		bt848_sat(btv,32768);
 		audio_mute(btv, 1);
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index f09df9d..2520219 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -77,6 +77,9 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 
 /* One from column A... */
 #define QC_NOTSET 0
@@ -103,6 +106,7 @@
 struct qcam {
 	struct v4l2_device v4l2_dev;
 	struct video_device vdev;
+	struct v4l2_ctrl_handler hdl;
 	struct pardevice *pdev;
 	struct parport *pport;
 	struct mutex lock;
@@ -646,7 +650,8 @@
 	strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
 	strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card));
 	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
-	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -674,72 +679,6 @@
 	return (inp > 0) ? -EINVAL : 0;
 }
 
-static int qcam_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_BRIGHTNESS:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180);
-	case V4L2_CID_CONTRAST:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
-	case V4L2_CID_GAMMA:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105);
-	}
-	return -EINVAL;
-}
-
-static int qcam_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct qcam *qcam = video_drvdata(file);
-	int ret = 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = qcam->brightness;
-		break;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = qcam->contrast;
-		break;
-	case V4L2_CID_GAMMA:
-		ctrl->value = qcam->whitebal;
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int qcam_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct qcam *qcam = video_drvdata(file);
-	int ret = 0;
-
-	mutex_lock(&qcam->lock);
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		qcam->brightness = ctrl->value;
-		break;
-	case V4L2_CID_CONTRAST:
-		qcam->contrast = ctrl->value;
-		break;
-	case V4L2_CID_GAMMA:
-		qcam->whitebal = ctrl->value;
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	if (ret == 0) {
-		qc_setscanmode(qcam);
-		qcam->status |= QC_PARAM_CHANGE;
-	}
-	mutex_unlock(&qcam->lock);
-	return ret;
-}
-
 static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
 	struct qcam *qcam = video_drvdata(file);
@@ -856,8 +795,40 @@
 	return len;
 }
 
+static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct qcam *qcam =
+		container_of(ctrl->handler, struct qcam, hdl);
+	int ret = 0;
+
+	mutex_lock(&qcam->lock);
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		qcam->brightness = ctrl->val;
+		break;
+	case V4L2_CID_CONTRAST:
+		qcam->contrast = ctrl->val;
+		break;
+	case V4L2_CID_GAMMA:
+		qcam->whitebal = ctrl->val;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret == 0) {
+		qc_setscanmode(qcam);
+		qcam->status |= QC_PARAM_CHANGE;
+	}
+	mutex_unlock(&qcam->lock);
+	return ret;
+}
+
 static const struct v4l2_file_operations qcam_fops = {
 	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
 	.unlocked_ioctl = video_ioctl2,
 	.read		= qcam_read,
 };
@@ -867,13 +838,17 @@
 	.vidioc_g_input      		    = qcam_g_input,
 	.vidioc_s_input      		    = qcam_s_input,
 	.vidioc_enum_input   		    = qcam_enum_input,
-	.vidioc_queryctrl 		    = qcam_queryctrl,
-	.vidioc_g_ctrl  		    = qcam_g_ctrl,
-	.vidioc_s_ctrl 			    = qcam_s_ctrl,
 	.vidioc_enum_fmt_vid_cap 	    = qcam_enum_fmt_vid_cap,
 	.vidioc_g_fmt_vid_cap 		    = qcam_g_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap  		    = qcam_s_fmt_vid_cap,
 	.vidioc_try_fmt_vid_cap  	    = qcam_try_fmt_vid_cap,
+	.vidioc_log_status		    = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
+	.s_ctrl = qcam_s_ctrl,
 };
 
 /* Initialize the QuickCam driver control structure.  This is where
@@ -897,19 +872,35 @@
 		return NULL;
 	}
 
+	v4l2_ctrl_handler_init(&qcam->hdl, 3);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, 0, 255, 1, 180);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_CONTRAST, 0, 255, 1, 192);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_GAMMA, 0, 255, 1, 105);
+	if (qcam->hdl.error) {
+		v4l2_err(v4l2_dev, "couldn't register controls\n");
+		v4l2_ctrl_handler_free(&qcam->hdl);
+		kfree(qcam);
+		return NULL;
+	}
 	qcam->pport = port;
 	qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
 			NULL, 0, NULL);
 	if (qcam->pdev == NULL) {
 		v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+		v4l2_ctrl_handler_free(&qcam->hdl);
 		kfree(qcam);
 		return NULL;
 	}
 
 	strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
 	qcam->vdev.v4l2_dev = v4l2_dev;
+	qcam->vdev.ctrl_handler = &qcam->hdl;
 	qcam->vdev.fops = &qcam_fops;
 	qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+	set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
 	qcam->vdev.release = video_device_release_empty;
 	video_set_drvdata(&qcam->vdev, qcam);
 
@@ -1003,6 +994,7 @@
 static void close_bwqcam(struct qcam *qcam)
 {
 	video_unregister_device(&qcam->vdev);
+	v4l2_ctrl_handler_free(&qcam->hdl);
 	parport_unregister_device(qcam->pdev);
 	kfree(qcam);
 }
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index fda32f5..ec51e1f 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -40,10 +40,14 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 
 struct qcam {
 	struct v4l2_device v4l2_dev;
 	struct video_device vdev;
+	struct v4l2_ctrl_handler hdl;
 	struct pardevice *pdev;
 	struct parport *pport;
 	int width, height;
@@ -378,7 +382,7 @@
 static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
 {
 	struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
-	unsigned lines, pixelsperline, bitsperxfer;
+	unsigned lines, pixelsperline;
 	unsigned int is_bi_dir = qcam->bidirectional;
 	size_t wantlen, outptr = 0;
 	char tmpbuf[BUFSZ];
@@ -404,7 +408,6 @@
 
 	lines = qcam->height;
 	pixelsperline = qcam->width;
-	bitsperxfer = (is_bi_dir) ? 24 : 8;
 
 	if (is_bi_dir) {
 		/* Turn the port around */
@@ -516,7 +519,8 @@
 	strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
 	strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
 	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
-	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -544,73 +548,6 @@
 	return (inp > 0) ? -EINVAL : 0;
 }
 
-static int qcam_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_BRIGHTNESS:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240);
-	case V4L2_CID_CONTRAST:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
-	case V4L2_CID_GAMMA:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
-	}
-	return -EINVAL;
-}
-
-static int qcam_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct qcam *qcam = video_drvdata(file);
-	int ret = 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = qcam->brightness;
-		break;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = qcam->contrast;
-		break;
-	case V4L2_CID_GAMMA:
-		ctrl->value = qcam->whitebal;
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int qcam_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct qcam *qcam = video_drvdata(file);
-	int ret = 0;
-
-	mutex_lock(&qcam->lock);
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		qcam->brightness = ctrl->value;
-		break;
-	case V4L2_CID_CONTRAST:
-		qcam->contrast = ctrl->value;
-		break;
-	case V4L2_CID_GAMMA:
-		qcam->whitebal = ctrl->value;
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	if (ret == 0) {
-		parport_claim_or_block(qcam->pdev);
-		qc_setup(qcam);
-		parport_release(qcam->pdev);
-	}
-	mutex_unlock(&qcam->lock);
-	return ret;
-}
-
 static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
 	struct qcam *qcam = video_drvdata(file);
@@ -714,8 +651,41 @@
 	return len;
 }
 
+static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct qcam *qcam =
+		container_of(ctrl->handler, struct qcam, hdl);
+	int ret = 0;
+
+	mutex_lock(&qcam->lock);
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		qcam->brightness = ctrl->val;
+		break;
+	case V4L2_CID_CONTRAST:
+		qcam->contrast = ctrl->val;
+		break;
+	case V4L2_CID_GAMMA:
+		qcam->whitebal = ctrl->val;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret == 0) {
+		parport_claim_or_block(qcam->pdev);
+		qc_setup(qcam);
+		parport_release(qcam->pdev);
+	}
+	mutex_unlock(&qcam->lock);
+	return ret;
+}
+
 static const struct v4l2_file_operations qcam_fops = {
 	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
 	.unlocked_ioctl	= video_ioctl2,
 	.read		= qcam_read,
 };
@@ -725,13 +695,17 @@
 	.vidioc_g_input      		    = qcam_g_input,
 	.vidioc_s_input      		    = qcam_s_input,
 	.vidioc_enum_input   		    = qcam_enum_input,
-	.vidioc_queryctrl 		    = qcam_queryctrl,
-	.vidioc_g_ctrl  		    = qcam_g_ctrl,
-	.vidioc_s_ctrl 			    = qcam_s_ctrl,
-	.vidioc_enum_fmt_vid_cap 	    = qcam_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_cap	    = qcam_enum_fmt_vid_cap,
 	.vidioc_g_fmt_vid_cap 		    = qcam_g_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap  		    = qcam_s_fmt_vid_cap,
 	.vidioc_try_fmt_vid_cap  	    = qcam_try_fmt_vid_cap,
+	.vidioc_log_status		    = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
+	.s_ctrl = qcam_s_ctrl,
 };
 
 /* Initialize the QuickCam driver control structure. */
@@ -754,6 +728,20 @@
 		return NULL;
 	}
 
+	v4l2_ctrl_handler_init(&qcam->hdl, 3);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, 0, 255, 1, 240);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_CONTRAST, 0, 255, 1, 192);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_GAMMA, 0, 255, 1, 128);
+	if (qcam->hdl.error) {
+		v4l2_err(v4l2_dev, "couldn't register controls\n");
+		v4l2_ctrl_handler_free(&qcam->hdl);
+		kfree(qcam);
+		return NULL;
+	}
+
 	qcam->pport = port;
 	qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
 					  NULL, 0, NULL);
@@ -762,6 +750,7 @@
 
 	if (qcam->pdev == NULL) {
 		v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+		v4l2_ctrl_handler_free(&qcam->hdl);
 		kfree(qcam);
 		return NULL;
 	}
@@ -771,6 +760,8 @@
 	qcam->vdev.fops = &qcam_fops;
 	qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
 	qcam->vdev.release = video_device_release_empty;
+	qcam->vdev.ctrl_handler = &qcam->hdl;
+	set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
 	video_set_drvdata(&qcam->vdev, qcam);
 
 	mutex_init(&qcam->lock);
@@ -845,6 +836,7 @@
 static void close_cqcam(struct qcam *qcam)
 {
 	video_unregister_device(&qcam->vdev);
+	v4l2_ctrl_handler_free(&qcam->hdl);
 	parport_unregister_device(qcam->pdev);
 	kfree(qcam);
 }
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
index ab25218..cdef677 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -32,11 +32,12 @@
 #define __CPIA2_H__
 
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/poll.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 
-#include "cpia2dev.h"
 #include "cpia2_registers.h"
 
 /* define for verbose debug output */
@@ -65,7 +66,6 @@
 
 /* Flicker Modes */
 #define NEVER_FLICKER   0
-#define ANTI_FLICKER_ON 1
 #define FLICKER_60      60
 #define FLICKER_50      50
 
@@ -148,7 +148,6 @@
 #define DEFAULT_BRIGHTNESS 0x46
 #define DEFAULT_CONTRAST 0x93
 #define DEFAULT_SATURATION 0x7f
-#define DEFAULT_TARGET_KB 0x30
 
 /* Power state */
 #define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER
@@ -287,7 +286,6 @@
 	struct {
 		u8 cam_register;
 		u8 flicker_mode_req;	/* 1 if flicker on, else never flicker */
-		int mains_frequency;
 	} flicker_control;
 
 	struct {
@@ -337,7 +335,7 @@
 		u8 vc_control;
 		u8 vc_mp_direction;
 		u8 vc_mp_data;
-		u8 target_kb;
+		u8 quality;
 	} vc_params;
 
 	struct {
@@ -366,23 +364,23 @@
 	struct framebuf *next;
 };
 
-struct cpia2_fh {
-	enum v4l2_priority prio;
-	u8 mmapped;
-};
-
 struct camera_data {
 	/* locks */
+	struct v4l2_device v4l2_dev;
 	struct mutex v4l2_lock;	/* serialize file operations */
-	struct v4l2_prio_state prio;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* Lights control cluster */
+		struct v4l2_ctrl *top_light;
+		struct v4l2_ctrl *bottom_light;
+	};
+	struct v4l2_ctrl *usb_alt;
 
 	/* camera status */
-	volatile int present;	/* Is the camera still present? */
-	int open_count;		/* # of process that have camera open */
 	int first_image_seen;
-	u8 mains_freq;		/* for flicker control */
 	enum sensors sensor_type;
 	u8 flush;
+	struct v4l2_fh *stream_fh;
 	u8 mmapped;
 	int streaming;		/* 0 = no, 1 = yes */
 	int xfer_mode;		/* XFER_BULK or XFER_ISOC */
@@ -390,7 +388,7 @@
 
 	/* v4l */
 	int video_size;			/* VIDEO_SIZE_ */
-	struct video_device *vdev;	/* v4l videodev */
+	struct video_device vdev;	/* v4l videodev */
 	u32 width;
 	u32 height;			/* Its size */
 	__u32 pixelformat;       /* Format fourcc      */
@@ -425,6 +423,7 @@
 /* v4l */
 int cpia2_register_camera(struct camera_data *cam);
 void cpia2_unregister_camera(struct camera_data *cam);
+void cpia2_camera_release(struct v4l2_device *v4l2_dev);
 
 /* core */
 int cpia2_reset_camera(struct camera_data *cam);
@@ -443,7 +442,7 @@
 int cpia2_do_command(struct camera_data *cam,
 		     unsigned int command,
 		     unsigned char direction, unsigned char param);
-struct camera_data *cpia2_init_camera_struct(void);
+struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf);
 int cpia2_init_camera(struct camera_data *cam);
 int cpia2_allocate_buffers(struct camera_data *cam);
 void cpia2_free_buffers(struct camera_data *cam);
@@ -454,7 +453,6 @@
 int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma);
 void cpia2_set_property_flip(struct camera_data *cam, int prop_val);
 void cpia2_set_property_mirror(struct camera_data *cam, int prop_val);
-int cpia2_set_target_kb(struct camera_data *cam, unsigned char value);
 int cpia2_set_gpio(struct camera_data *cam, unsigned char setting);
 int cpia2_set_fps(struct camera_data *cam, int framerate);
 
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index ee91e295..17188e2 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -66,7 +66,6 @@
 static int config_sensor_500(struct camera_data *cam,
 			    int reqwidth, int reqheight);
 static int set_all_properties(struct camera_data *cam);
-static void get_color_params(struct camera_data *cam);
 static void wake_system(struct camera_data *cam);
 static void set_lowlight_boost(struct camera_data *cam);
 static void reset_camera_struct(struct camera_data *cam);
@@ -453,15 +452,6 @@
 		cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
 		cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
 		break;
-	case CPIA2_CMD_GET_VP_BRIGHTNESS:
-		cam->params.color_params.brightness = cmd.buffer.block_data[0];
-		break;
-	case CPIA2_CMD_GET_CONTRAST:
-		cam->params.color_params.contrast = cmd.buffer.block_data[0];
-		break;
-	case CPIA2_CMD_GET_VP_SATURATION:
-		cam->params.color_params.saturation = cmd.buffer.block_data[0];
-		break;
 	case CPIA2_CMD_GET_VP_GPIO_DATA:
 		cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
 		break;
@@ -617,6 +607,7 @@
 {
 	u8 tmp_reg;
 	int retval = 0;
+	int target_kb;
 	int i;
 	struct cpia2_command cmd;
 
@@ -800,9 +791,16 @@
 	}
 	cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
 
-	/* Set target size (kb) on vc */
+	/* Set target size (kb) on vc
+	   This is a heuristic based on the quality parameter and the raw
+	   framesize in kB divided by 16 (the compression factor when the
+	   quality is 100%) */
+	target_kb = (cam->width * cam->height * 2 / 16384) *
+				cam->params.vc_params.quality / 100;
+	if (target_kb < 1)
+		target_kb = 1;
 	cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
-			 TRANSFER_WRITE, cam->params.vc_params.target_kb);
+			 TRANSFER_WRITE, target_kb);
 
 	/* Wiggle VC Reset */
 	/***
@@ -1538,23 +1536,17 @@
 	 * framerate and user_mode were already set (set_default_user_mode).
 	 **/
 
-	cpia2_set_color_params(cam);
-
 	cpia2_usb_change_streaming_alternate(cam,
 					  cam->params.camera_state.stream_mode);
 
-	cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
-			 cam->params.vp_params.user_effects);
-
-	cpia2_set_flicker_mode(cam,
-			       cam->params.flicker_control.flicker_mode_req);
-
 	cpia2_do_command(cam,
 			 CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
 			 TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
 	cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
 			 cam->params.vp_params.gpio_data);
 
+	v4l2_ctrl_handler_setup(&cam->hdl);
+
 	wake_system(cam);
 
 	set_lowlight_boost(cam);
@@ -1569,7 +1561,6 @@
  *****************************************************************************/
 void cpia2_save_camera_state(struct camera_data *cam)
 {
-	get_color_params(cam);
 	cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
 	cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
 			 0);
@@ -1577,30 +1568,6 @@
 	/* Don't get framerate or target_kb. Trust the values we already have */
 }
 
-/******************************************************************************
- *
- *  get_color_params
- *
- *****************************************************************************/
-static void get_color_params(struct camera_data *cam)
-{
-	cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0);
-	cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0);
-	cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, TRANSFER_READ, 0);
-}
-
-/******************************************************************************
- *
- *  cpia2_set_color_params
- *
- *****************************************************************************/
-void cpia2_set_color_params(struct camera_data *cam)
-{
-	DBG("Setting color params\n");
-	cpia2_set_brightness(cam, cam->params.color_params.brightness);
-	cpia2_set_contrast(cam, cam->params.color_params.contrast);
-	cpia2_set_saturation(cam, cam->params.color_params.saturation);
-}
 
 /******************************************************************************
  *
@@ -1664,15 +1631,9 @@
 
 	switch(mode) {
 	case NEVER_FLICKER:
-		cam->params.flicker_control.flicker_mode_req = mode;
-		break;
 	case FLICKER_60:
-		cam->params.flicker_control.flicker_mode_req = mode;
-		cam->params.flicker_control.mains_frequency = 60;
-		break;
 	case FLICKER_50:
 		cam->params.flicker_control.flicker_mode_req = mode;
-		cam->params.flicker_control.mains_frequency = 50;
 		break;
 	default:
 		err = -EINVAL;
@@ -1701,6 +1662,7 @@
 	{
 		cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
 	}
+	cam->params.vp_params.user_effects = cam_reg;
 	cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
 			 cam_reg);
 }
@@ -1725,37 +1687,13 @@
 	{
 		cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
 	}
+	cam->params.vp_params.user_effects = cam_reg;
 	cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
 			 cam_reg);
 }
 
 /******************************************************************************
  *
- *  set_target_kb
- *
- *  The new Target KB is set in cam->params.vc_params.target_kb and
- *  activates on reset.
- *****************************************************************************/
-
-int cpia2_set_target_kb(struct camera_data *cam, unsigned char value)
-{
-	DBG("Requested target_kb = %d\n", value);
-	if (value != cam->params.vc_params.target_kb) {
-
-		cpia2_usb_stream_pause(cam);
-
-		/* reset camera for new target_kb */
-		cam->params.vc_params.target_kb = value;
-		cpia2_reset_camera(cam);
-
-		cpia2_usb_stream_resume(cam);
-	}
-
-	return 0;
-}
-
-/******************************************************************************
- *
  *  cpia2_set_gpio
  *
  *****************************************************************************/
@@ -1843,7 +1781,7 @@
 	if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
 		value++;
 	DBG("Setting brightness to %d (0x%0x)\n", value, value);
-	cpia2_do_command(cam,CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE,value);
+	cpia2_do_command(cam, CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE, value);
 }
 
 /******************************************************************************
@@ -1854,7 +1792,6 @@
 void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
 {
 	DBG("Setting contrast to %d (0x%0x)\n", value, value);
-	cam->params.color_params.contrast = value;
 	cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
 }
 
@@ -1866,7 +1803,6 @@
 void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
 {
 	DBG("Setting saturation to %d (0x%0x)\n", value, value);
-	cam->params.color_params.saturation = value;
 	cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
 }
 
@@ -2168,14 +2104,10 @@
 	/***
 	 * The following parameter values are the defaults from the register map.
 	 ***/
-	cam->params.color_params.brightness = DEFAULT_BRIGHTNESS;
-	cam->params.color_params.contrast = DEFAULT_CONTRAST;
-	cam->params.color_params.saturation = DEFAULT_SATURATION;
 	cam->params.vp_params.lowlight_boost = 0;
 
 	/* FlickerModes */
 	cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
-	cam->params.flicker_control.mains_frequency = 60;
 
 	/* jpeg params */
 	cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
@@ -2188,7 +2120,7 @@
 	cam->params.vp_params.gpio_data = 0;
 
 	/* Target kb params */
-	cam->params.vc_params.target_kb = DEFAULT_TARGET_KB;
+	cam->params.vc_params.quality = 100;
 
 	/***
 	 * Set Sensor FPS as fast as possible.
@@ -2228,7 +2160,7 @@
  *
  *  Initializes camera struct, does not call reset to fill in defaults.
  *****************************************************************************/
-struct camera_data *cpia2_init_camera_struct(void)
+struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
 {
 	struct camera_data *cam;
 
@@ -2239,8 +2171,13 @@
 		return NULL;
 	}
 
+	cam->v4l2_dev.release = cpia2_camera_release;
+	if (v4l2_device_register(&intf->dev, &cam->v4l2_dev) < 0) {
+		v4l2_err(&cam->v4l2_dev, "couldn't register v4l2_device\n");
+		kfree(cam);
+		return NULL;
+	}
 
-	cam->present = 1;
 	mutex_init(&cam->v4l2_lock);
 	init_waitqueue_head(&cam->wq_stream);
 
@@ -2373,11 +2310,6 @@
 		return -EINVAL;
 	}
 
-	if (!cam->present) {
-		LOG("%s: camera removed\n",__func__);
-		return 0;	/* EOF */
-	}
-
 	if (!cam->streaming) {
 		/* Start streaming */
 		cpia2_usb_stream_start(cam,
@@ -2393,12 +2325,12 @@
 	if (frame->status != FRAME_READY) {
 		mutex_unlock(&cam->v4l2_lock);
 		wait_event_interruptible(cam->wq_stream,
-			       !cam->present ||
+			       !video_is_registered(&cam->vdev) ||
 			       (frame = cam->curbuff)->status == FRAME_READY);
 		mutex_lock(&cam->v4l2_lock);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		if (!cam->present)
+		if (!video_is_registered(&cam->vdev))
 			return 0;
 	}
 
@@ -2423,17 +2355,10 @@
 unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
 			poll_table *wait)
 {
-	unsigned int status=0;
+	unsigned int status = v4l2_ctrl_poll(filp, wait);
 
-	if (!cam) {
-		ERR("%s: Internal error, camera_data not found!\n",__func__);
-		return POLLERR;
-	}
-
-	if (!cam->present)
-		return POLLHUP;
-
-	if(!cam->streaming) {
+	if ((poll_requested_events(wait) & (POLLIN | POLLRDNORM)) &&
+			!cam->streaming) {
 		/* Start streaming */
 		cpia2_usb_stream_start(cam,
 				       cam->params.camera_state.stream_mode);
@@ -2441,10 +2366,8 @@
 
 	poll_wait(filp, &cam->wq_stream, wait);
 
-	if(!cam->present)
-		status = POLLHUP;
-	else if(cam->curbuff->status == FRAME_READY)
-		status = POLLIN | POLLRDNORM;
+	if (cam->curbuff->status == FRAME_READY)
+		status |= POLLIN | POLLRDNORM;
 
 	return status;
 }
@@ -2462,12 +2385,9 @@
 	unsigned long start = (unsigned long) adr;
 	unsigned long page, pos;
 
-	if (!cam)
-		return -ENODEV;
-
 	DBG("mmap offset:%ld size:%ld\n", start_offset, size);
 
-	if (!cam->present)
+	if (!video_is_registered(&cam->vdev))
 		return -ENODEV;
 
 	if (size > cam->frame_size*cam->num_frames  ||
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
index 59c797c..95b5d6e 100644
--- a/drivers/media/video/cpia2/cpia2_usb.c
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -54,6 +54,8 @@
 static int cpia2_usb_probe(struct usb_interface *intf,
 			   const struct usb_device_id *id);
 static void cpia2_usb_disconnect(struct usb_interface *intf);
+static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message);
+static int cpia2_usb_resume(struct usb_interface *intf);
 
 static void free_sbufs(struct camera_data *cam);
 static void add_APPn(struct camera_data *cam);
@@ -74,6 +76,9 @@
 	.name		= "cpia2",
 	.probe		= cpia2_usb_probe,
 	.disconnect	= cpia2_usb_disconnect,
+	.suspend	= cpia2_usb_suspend,
+	.resume		= cpia2_usb_resume,
+	.reset_resume	= cpia2_usb_resume,
 	.id_table	= cpia2_id_table
 };
 
@@ -218,10 +223,9 @@
 		return;
 	}
 
-	if (!cam->streaming || !cam->present || cam->open_count == 0) {
-		LOG("Will now stop the streaming: streaming = %d, "
-		    "present=%d, open_count=%d\n",
-		    cam->streaming, cam->present, cam->open_count);
+	if (!cam->streaming || !video_is_registered(&cam->vdev)) {
+		LOG("Will now stop the streaming: streaming = %d, present=%d\n",
+		    cam->streaming, video_is_registered(&cam->vdev));
 		return;
 	}
 
@@ -392,7 +396,7 @@
 	struct cpia2_command cmd;
 	unsigned char reg;
 
-	if(!cam->present)
+	if (!video_is_registered(&cam->vdev))
 		return -ENODEV;
 
 	/***
@@ -752,8 +756,8 @@
 {
 	int ret = 0;
 	if(cam->streaming) {
-		ret = set_alternate(cam, USBIF_CMDONLY);
 		free_sbufs(cam);
+		ret = set_alternate(cam, USBIF_CMDONLY);
 	}
 	return ret;
 }
@@ -770,6 +774,10 @@
 		cam->first_image_seen = 0;
 		ret = set_alternate(cam, cam->params.camera_state.stream_mode);
 		if(ret == 0) {
+			/* for some reason the user effects need to be set
+			   again when starting streaming. */
+			cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+					cam->params.vp_params.user_effects);
 			ret = submit_urbs(cam);
 		}
 	}
@@ -784,6 +792,7 @@
 int cpia2_usb_stream_stop(struct camera_data *cam)
 {
 	int ret;
+
 	ret = cpia2_usb_stream_pause(cam);
 	cam->streaming = 0;
 	configure_transfer_mode(cam, 0);
@@ -812,7 +821,8 @@
 	/* If we get to this point, we found a CPiA2 camera */
 	LOG("CPiA2 USB camera found\n");
 
-	if((cam = cpia2_init_camera_struct()) == NULL)
+	cam = cpia2_init_camera_struct(intf);
+	if (cam == NULL)
 		return -ENOMEM;
 
 	cam->dev = udev;
@@ -825,16 +835,9 @@
 		return ret;
 	}
 
-	if ((ret = cpia2_register_camera(cam)) < 0) {
-		ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
-		kfree(cam);
-		return ret;
-	}
-
 
 	if((ret = cpia2_init_camera(cam)) < 0) {
 		ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
-		cpia2_unregister_camera(cam);
 		kfree(cam);
 		return ret;
 	}
@@ -853,6 +856,13 @@
 
 	usb_set_intfdata(intf, cam);
 
+	ret = cpia2_register_camera(cam);
+	if (ret < 0) {
+		ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
+		kfree(cam);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -865,13 +875,16 @@
 {
 	struct camera_data *cam = usb_get_intfdata(intf);
 	usb_set_intfdata(intf, NULL);
-	cam->present = 0;
 
 	DBG("Stopping stream\n");
 	cpia2_usb_stream_stop(cam);
 
+	mutex_lock(&cam->v4l2_lock);
 	DBG("Unregistering camera\n");
 	cpia2_unregister_camera(cam);
+	v4l2_device_disconnect(&cam->v4l2_dev);
+	mutex_unlock(&cam->v4l2_lock);
+	v4l2_device_put(&cam->v4l2_dev);
 
 	if(cam->buffers) {
 		DBG("Wakeup waiting processes\n");
@@ -884,14 +897,41 @@
 	DBG("Releasing interface\n");
 	usb_driver_release_interface(&cpia2_driver, intf);
 
-	if (cam->open_count == 0) {
-		DBG("Freeing camera structure\n");
-		kfree(cam);
-	}
-
 	LOG("CPiA2 camera disconnected.\n");
 }
 
+static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct camera_data *cam = usb_get_intfdata(intf);
+
+	mutex_lock(&cam->v4l2_lock);
+	if (cam->streaming) {
+		cpia2_usb_stream_stop(cam);
+		cam->streaming = 1;
+	}
+	mutex_unlock(&cam->v4l2_lock);
+
+	dev_info(&intf->dev, "going into suspend..\n");
+	return 0;
+}
+
+/* Resume device - start device. */
+static int cpia2_usb_resume(struct usb_interface *intf)
+{
+	struct camera_data *cam = usb_get_intfdata(intf);
+
+	mutex_lock(&cam->v4l2_lock);
+	v4l2_ctrl_handler_setup(&cam->hdl);
+	if (cam->streaming) {
+		cam->streaming = 0;
+		cpia2_usb_stream_start(cam,
+				cam->params.camera_state.stream_mode);
+	}
+	mutex_unlock(&cam->v4l2_lock);
+
+	dev_info(&intf->dev, "coming out of suspend..\n");
+	return 0;
+}
 
 /******************************************************************************
  *
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 077eb1d..55e9290 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -39,15 +39,15 @@
 #include <linux/videodev2.h>
 #include <linux/stringify.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 
 #include "cpia2.h"
-#include "cpia2dev.h"
 
 static int video_nr = -1;
 module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");
+MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)");
 
-static int buffer_size = 68*1024;
+static int buffer_size = 68 * 1024;
 module_param(buffer_size, int, 0);
 MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
 
@@ -62,18 +62,10 @@
 		 __stringify(USBIF_ISO_6) ", default "
 		 __stringify(DEFAULT_ALT) ")");
 
-static int flicker_freq = 60;
-module_param(flicker_freq, int, 0);
-MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" __stringify(50) "or"
-		 __stringify(60) ", default "
-		 __stringify(60) ")");
-
-static int flicker_mode = NEVER_FLICKER;
+static int flicker_mode;
 module_param(flicker_mode, int, 0);
-MODULE_PARM_DESC(flicker_mode,
-		 "Flicker supression (" __stringify(NEVER_FLICKER) "or"
-		 __stringify(ANTI_FLICKER_ON) ", default "
-		 __stringify(NEVER_FLICKER) ")");
+MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or "
+		 __stringify(60) ", default 0)");
 
 MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
 MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
@@ -82,153 +74,7 @@
 MODULE_VERSION(CPIA_VERSION);
 
 #define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
-
-struct control_menu_info {
-	int value;
-	char name[32];
-};
-
-static struct control_menu_info framerate_controls[] =
-{
-	{ CPIA2_VP_FRAMERATE_6_25, "6.25 fps" },
-	{ CPIA2_VP_FRAMERATE_7_5,  "7.5 fps"  },
-	{ CPIA2_VP_FRAMERATE_12_5, "12.5 fps" },
-	{ CPIA2_VP_FRAMERATE_15,   "15 fps"   },
-	{ CPIA2_VP_FRAMERATE_25,   "25 fps"   },
-	{ CPIA2_VP_FRAMERATE_30,   "30 fps"   },
-};
-#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls))
-
-static struct control_menu_info flicker_controls[] =
-{
-	{ NEVER_FLICKER, "Off" },
-	{ FLICKER_50,    "50 Hz" },
-	{ FLICKER_60,    "60 Hz"  },
-};
-#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls))
-
-static struct control_menu_info lights_controls[] =
-{
-	{ 0,   "Off" },
-	{ 64,  "Top" },
-	{ 128, "Bottom"  },
-	{ 192, "Both"  },
-};
-#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls))
-#define GPIO_LIGHTS_MASK 192
-
-static struct v4l2_queryctrl controls[] = {
-	{
-		.id            = V4L2_CID_BRIGHTNESS,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Brightness",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 1,
-		.default_value = DEFAULT_BRIGHTNESS,
-	},
-	{
-		.id            = V4L2_CID_CONTRAST,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Contrast",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 1,
-		.default_value = DEFAULT_CONTRAST,
-	},
-	{
-		.id            = V4L2_CID_SATURATION,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Saturation",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 1,
-		.default_value = DEFAULT_SATURATION,
-	},
-	{
-		.id            = V4L2_CID_HFLIP,
-		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-		.name          = "Mirror Horizontally",
-		.minimum       = 0,
-		.maximum       = 1,
-		.step          = 1,
-		.default_value = 0,
-	},
-	{
-		.id            = V4L2_CID_VFLIP,
-		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-		.name          = "Flip Vertically",
-		.minimum       = 0,
-		.maximum       = 1,
-		.step          = 1,
-		.default_value = 0,
-	},
-	{
-		.id            = CPIA2_CID_TARGET_KB,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Target KB",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 1,
-		.default_value = DEFAULT_TARGET_KB,
-	},
-	{
-		.id            = CPIA2_CID_GPIO,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "GPIO",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 1,
-		.default_value = 0,
-	},
-	{
-		.id            = CPIA2_CID_FLICKER_MODE,
-		.type          = V4L2_CTRL_TYPE_MENU,
-		.name          = "Flicker Reduction",
-		.minimum       = 0,
-		.maximum       = NUM_FLICKER_CONTROLS-1,
-		.step          = 1,
-		.default_value = 0,
-	},
-	{
-		.id            = CPIA2_CID_FRAMERATE,
-		.type          = V4L2_CTRL_TYPE_MENU,
-		.name          = "Framerate",
-		.minimum       = 0,
-		.maximum       = NUM_FRAMERATE_CONTROLS-1,
-		.step          = 1,
-		.default_value = NUM_FRAMERATE_CONTROLS-1,
-	},
-	{
-		.id            = CPIA2_CID_USB_ALT,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "USB Alternate",
-		.minimum       = USBIF_ISO_1,
-		.maximum       = USBIF_ISO_6,
-		.step          = 1,
-		.default_value = DEFAULT_ALT,
-	},
-	{
-		.id            = CPIA2_CID_LIGHTS,
-		.type          = V4L2_CTRL_TYPE_MENU,
-		.name          = "Lights",
-		.minimum       = 0,
-		.maximum       = NUM_LIGHTS_CONTROLS-1,
-		.step          = 1,
-		.default_value = 0,
-	},
-	{
-		.id            = CPIA2_CID_RESET_CAMERA,
-		.type          = V4L2_CTRL_TYPE_BUTTON,
-		.name          = "Reset Camera",
-		.minimum       = 0,
-		.maximum       = 0,
-		.step          = 0,
-		.default_value = 0,
-	},
-};
-#define NUM_CONTROLS (ARRAY_SIZE(controls))
-
+#define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000)
 
 /******************************************************************************
  *
@@ -238,38 +84,27 @@
 static int cpia2_open(struct file *file)
 {
 	struct camera_data *cam = video_drvdata(file);
-	struct cpia2_fh *fh;
+	int retval = v4l2_fh_open(file);
 
-	if (!cam) {
-		ERR("Internal error, camera_data not found!\n");
-		return -ENODEV;
-	}
+	if (retval)
+		return retval;
 
-	if (!cam->present)
-		return -ENODEV;
-
-	if (cam->open_count == 0) {
-		if (cpia2_allocate_buffers(cam))
+	if (v4l2_fh_is_singular_file(file)) {
+		if (cpia2_allocate_buffers(cam)) {
+			v4l2_fh_release(file);
 			return -ENOMEM;
+		}
 
 		/* reset the camera */
-		if (cpia2_reset_camera(cam) < 0)
+		if (cpia2_reset_camera(cam) < 0) {
+			v4l2_fh_release(file);
 			return -EIO;
+		}
 
 		cam->APP_len = 0;
 		cam->COM_len = 0;
 	}
 
-	fh = kmalloc(sizeof(*fh), GFP_KERNEL);
-	if (!fh)
-		return -ENOMEM;
-	file->private_data = fh;
-	fh->prio = V4L2_PRIORITY_UNSET;
-	v4l2_prio_open(&cam->prio, &fh->prio);
-	fh->mmapped = 0;
-
-	++cam->open_count;
-
 	cpia2_dbg_dump_registers(cam);
 	return 0;
 }
@@ -283,37 +118,22 @@
 {
 	struct video_device *dev = video_devdata(file);
 	struct camera_data *cam = video_get_drvdata(dev);
-	struct cpia2_fh *fh = file->private_data;
 
-	if (cam->present &&
-	    (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) {
+	if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) {
 		cpia2_usb_stream_stop(cam);
 
-		if (cam->open_count == 1) {
-			/* save camera state for later open */
-			cpia2_save_camera_state(cam);
+		/* save camera state for later open */
+		cpia2_save_camera_state(cam);
 
-			cpia2_set_low_power(cam);
-			cpia2_free_buffers(cam);
-		}
-	}
-
-	if (fh->mmapped)
-		cam->mmapped = 0;
-	v4l2_prio_close(&cam->prio, fh->prio);
-	file->private_data = NULL;
-	kfree(fh);
-
-	if (--cam->open_count == 0) {
+		cpia2_set_low_power(cam);
 		cpia2_free_buffers(cam);
-		if (!cam->present) {
-			video_unregister_device(dev);
-			kfree(cam);
-			return 0;
-		}
 	}
 
-	return 0;
+	if (cam->stream_fh == file->private_data) {
+		cam->stream_fh = NULL;
+		cam->mmapped = 0;
+	}
+	return v4l2_fh_release(file);
 }
 
 /******************************************************************************
@@ -327,16 +147,9 @@
 	struct camera_data *cam = video_drvdata(file);
 	int noblock = file->f_flags&O_NONBLOCK;
 
-	struct cpia2_fh *fh = file->private_data;
-
 	if(!cam)
 		return -EINVAL;
 
-	/* Priority check */
-	if(fh->prio != V4L2_PRIORITY_RECORD) {
-		return -EBUSY;
-	}
-
 	return cpia2_read(cam, buf, count, noblock);
 }
 
@@ -349,15 +162,6 @@
 static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
 {
 	struct camera_data *cam = video_drvdata(filp);
-	struct cpia2_fh *fh = filp->private_data;
-
-	if(!cam)
-		return POLLERR;
-
-	/* Priority check */
-	if(fh->prio != V4L2_PRIORITY_RECORD) {
-		return POLLERR;
-	}
 
 	return cpia2_poll(cam, filp, wait);
 }
@@ -384,36 +188,13 @@
 		mutex_lock(&cam->v4l2_lock);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		if(!cam->present)
+		if (!video_is_registered(&cam->vdev))
 			return -ENOTTY;
 	}
 }
 
 /******************************************************************************
  *
- *  ioctl_set_gpio
- *
- *****************************************************************************/
-
-static long cpia2_default(struct file *file, void *fh, bool valid_prio,
-			  int cmd, void *arg)
-{
-	struct camera_data *cam = video_drvdata(file);
-	__u32 gpio_val;
-
-	if (cmd != CPIA2_CID_GPIO)
-		return -EINVAL;
-
-	gpio_val = *(__u32*) arg;
-
-	if (gpio_val &~ 0xFFU)
-		return -EINVAL;
-
-	return cpia2_set_gpio(cam, (unsigned char)gpio_val);
-}
-
-/******************************************************************************
- *
  *  ioctl_querycap
  *
  *  V4L2 device capabilities
@@ -465,9 +246,11 @@
 	if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
 		memset(vc->bus_info,0, sizeof(vc->bus_info));
 
-	vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+	vc->device_caps = V4L2_CAP_VIDEO_CAPTURE |
 			   V4L2_CAP_READWRITE |
 			   V4L2_CAP_STREAMING;
+	vc->capabilities = vc->device_caps |
+			   V4L2_CAP_DEVICE_CAPS;
 
 	return 0;
 }
@@ -610,22 +393,12 @@
 					struct v4l2_format *f)
 {
 	struct camera_data *cam = video_drvdata(file);
-	struct cpia2_fh *fh = _fh;
 	int err, frame;
 
-	err = v4l2_prio_check(&cam->prio, fh->prio);
-	if (err)
-		return err;
 	err = cpia2_try_fmt_vid_cap(file, _fh, f);
 	if(err != 0)
 		return err;
 
-	/* Ensure that only this process can change the format. */
-	err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
-	if(err != 0) {
-		return err;
-	}
-
 	cam->pixelformat = f->fmt.pix.pixelformat;
 
 	/* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
@@ -713,240 +486,126 @@
 	return 0;
 }
 
-/******************************************************************************
- *
- *  ioctl_queryctrl
- *
- *  V4L2 query possible control variables
- *
- *****************************************************************************/
+struct framerate_info {
+	int value;
+	struct v4l2_fract period;
+};
 
-static int cpia2_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
+static const struct framerate_info framerate_controls[] = {
+	{ CPIA2_VP_FRAMERATE_6_25, { 4, 25 } },
+	{ CPIA2_VP_FRAMERATE_7_5,  { 2, 15 } },
+	{ CPIA2_VP_FRAMERATE_12_5, { 2, 25 } },
+	{ CPIA2_VP_FRAMERATE_15,   { 1, 15 } },
+	{ CPIA2_VP_FRAMERATE_25,   { 1, 25 } },
+	{ CPIA2_VP_FRAMERATE_30,   { 1, 30 } },
+};
+
+static int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
 {
 	struct camera_data *cam = video_drvdata(file);
+	struct v4l2_captureparm *cap = &p->parm.capture;
 	int i;
 
-	for(i=0; i<NUM_CONTROLS; ++i) {
-		if(c->id == controls[i].id) {
-			memcpy(c, controls+i, sizeof(*c));
+	if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	cap->capability = V4L2_CAP_TIMEPERFRAME;
+	cap->readbuffers = cam->num_frames;
+	for (i = 0; i < ARRAY_SIZE(framerate_controls); i++)
+		if (cam->params.vp_params.frame_rate == framerate_controls[i].value) {
+			cap->timeperframe = framerate_controls[i].period;
 			break;
 		}
-	}
+	return 0;
+}
 
-	if(i == NUM_CONTROLS)
+static int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
+{
+	struct camera_data *cam = video_drvdata(file);
+	struct v4l2_captureparm *cap = &p->parm.capture;
+	struct v4l2_fract tpf = cap->timeperframe;
+	int max = ARRAY_SIZE(framerate_controls) - 1;
+	int ret;
+	int i;
+
+	ret = cpia2_g_parm(file, fh, p);
+	if (ret || !tpf.denominator || !tpf.numerator)
+		return ret;
+
+	/* Maximum 15 fps for this model */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+	    cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+		max -= 2;
+	for (i = 0; i <= max; i++) {
+		struct v4l2_fract f1 = tpf;
+		struct v4l2_fract f2 = framerate_controls[i].period;
+
+		f1.numerator *= f2.denominator;
+		f2.numerator *= f1.denominator;
+		if (f1.numerator >= f2.numerator)
+			break;
+	}
+	if (i > max)
+		i = max;
+	cap->timeperframe = framerate_controls[i].period;
+	return cpia2_set_fps(cam, framerate_controls[i].value);
+}
+
+static const struct {
+	u32 width;
+	u32 height;
+} cpia2_framesizes[] = {
+	{ 640, 480 },
+	{ 352, 288 },
+	{ 320, 240 },
+	{ 288, 216 },
+	{ 256, 192 },
+	{ 224, 168 },
+	{ 192, 144 },
+	{ 176, 144 },
+};
+
+static int cpia2_enum_framesizes(struct file *file, void *fh,
+					 struct v4l2_frmsizeenum *fsize)
+{
+
+	if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG &&
+	    fsize->pixel_format != V4L2_PIX_FMT_JPEG)
 		return -EINVAL;
-
-	/* Some devices have additional limitations */
-	switch(c->id) {
-	case V4L2_CID_BRIGHTNESS:
-		/***
-		 * Don't let the register be set to zero - bug in VP4
-		 * flash of full brightness
-		 ***/
-		if (cam->params.pnp_id.device_type == DEVICE_STV_672)
-			c->minimum = 1;
-		break;
-	case V4L2_CID_VFLIP:
-		// VP5 Only
-		if(cam->params.pnp_id.device_type == DEVICE_STV_672)
-			c->flags |= V4L2_CTRL_FLAG_DISABLED;
-		break;
-	case CPIA2_CID_FRAMERATE:
-		if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
-		   cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
-			// Maximum 15fps
-			for(i=0; i<c->maximum; ++i) {
-				if(framerate_controls[i].value ==
-				   CPIA2_VP_FRAMERATE_15) {
-					c->maximum = i;
-					c->default_value = i;
-				}
-			}
-		}
-		break;
-	case CPIA2_CID_FLICKER_MODE:
-		// Flicker control only valid for 672.
-		if(cam->params.pnp_id.device_type != DEVICE_STV_672)
-			c->flags |= V4L2_CTRL_FLAG_DISABLED;
-		break;
-	case CPIA2_CID_LIGHTS:
-		// Light control only valid for the QX5 Microscope.
-		if(cam->params.pnp_id.product != 0x151)
-			c->flags |= V4L2_CTRL_FLAG_DISABLED;
-		break;
-	default:
-		break;
-	}
+	if (fsize->index >= ARRAY_SIZE(cpia2_framesizes))
+		return -EINVAL;
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete.width = cpia2_framesizes[fsize->index].width;
+	fsize->discrete.height = cpia2_framesizes[fsize->index].height;
 
 	return 0;
 }
 
-/******************************************************************************
- *
- *  ioctl_querymenu
- *
- *  V4L2 query possible control variables
- *
- *****************************************************************************/
-
-static int cpia2_querymenu(struct file *file, void *fh, struct v4l2_querymenu *m)
+static int cpia2_enum_frameintervals(struct file *file, void *fh,
+					   struct v4l2_frmivalenum *fival)
 {
 	struct camera_data *cam = video_drvdata(file);
+	int max = ARRAY_SIZE(framerate_controls) - 1;
+	int i;
 
-	switch(m->id) {
-	case CPIA2_CID_FLICKER_MODE:
-		if (m->index >= NUM_FLICKER_CONTROLS)
-			return -EINVAL;
-
-		strcpy(m->name, flicker_controls[m->index].name);
-		break;
-	case CPIA2_CID_FRAMERATE:
-	    {
-		int maximum = NUM_FRAMERATE_CONTROLS - 1;
-		if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
-		   cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
-			// Maximum 15fps
-			int i;
-			for(i=0; i<maximum; ++i) {
-				if(framerate_controls[i].value ==
-				   CPIA2_VP_FRAMERATE_15)
-					maximum = i;
-			}
-		}
-		if (m->index > maximum)
-			return -EINVAL;
-
-		strcpy(m->name, framerate_controls[m->index].name);
-		break;
-	    }
-	case CPIA2_CID_LIGHTS:
-		if (m->index >= NUM_LIGHTS_CONTROLS)
-			return -EINVAL;
-
-		strcpy(m->name, lights_controls[m->index].name);
-		break;
-	default:
+	if (fival->pixel_format != V4L2_PIX_FMT_MJPEG &&
+	    fival->pixel_format != V4L2_PIX_FMT_JPEG)
 		return -EINVAL;
-	}
 
-	return 0;
-}
-
-/******************************************************************************
- *
- *  ioctl_g_ctrl
- *
- *  V4L2 get the value of a control variable
- *
- *****************************************************************************/
-
-static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
-{
-	struct camera_data *cam = video_drvdata(file);
-
-	switch(c->id) {
-	case V4L2_CID_BRIGHTNESS:
-		cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS,
-				 TRANSFER_READ, 0);
-		c->value = cam->params.color_params.brightness;
-		break;
-	case V4L2_CID_CONTRAST:
-		cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST,
-				 TRANSFER_READ, 0);
-		c->value = cam->params.color_params.contrast;
-		break;
-	case V4L2_CID_SATURATION:
-		cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION,
-				 TRANSFER_READ, 0);
-		c->value = cam->params.color_params.saturation;
-		break;
-	case V4L2_CID_HFLIP:
-		cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
-				 TRANSFER_READ, 0);
-		c->value = (cam->params.vp_params.user_effects &
-			    CPIA2_VP_USER_EFFECTS_MIRROR) != 0;
-		break;
-	case V4L2_CID_VFLIP:
-		cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
-				 TRANSFER_READ, 0);
-		c->value = (cam->params.vp_params.user_effects &
-			    CPIA2_VP_USER_EFFECTS_FLIP) != 0;
-		break;
-	case CPIA2_CID_TARGET_KB:
-		c->value = cam->params.vc_params.target_kb;
-		break;
-	case CPIA2_CID_GPIO:
-		cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
-				 TRANSFER_READ, 0);
-		c->value = cam->params.vp_params.gpio_data;
-		break;
-	case CPIA2_CID_FLICKER_MODE:
-	{
-		int i, mode;
-		cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
-				 TRANSFER_READ, 0);
-		if(cam->params.flicker_control.cam_register &
-		   CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) {
-			mode = NEVER_FLICKER;
-		} else {
-		    if(cam->params.flicker_control.cam_register &
-		       CPIA2_VP_FLICKER_MODES_50HZ) {
-			mode = FLICKER_50;
-		    } else {
-			mode = FLICKER_60;
-		    }
-		}
-		for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
-			if(flicker_controls[i].value == mode) {
-				c->value = i;
-				break;
-			}
-		}
-		if(i == NUM_FLICKER_CONTROLS)
-			return -EINVAL;
-		break;
-	}
-	case CPIA2_CID_FRAMERATE:
-	{
-		int maximum = NUM_FRAMERATE_CONTROLS - 1;
-		int i;
-		for(i=0; i<= maximum; i++) {
-			if(cam->params.vp_params.frame_rate ==
-			   framerate_controls[i].value)
-				break;
-		}
-		if(i > maximum)
-			return -EINVAL;
-		c->value = i;
-		break;
-	}
-	case CPIA2_CID_USB_ALT:
-		c->value = cam->params.camera_state.stream_mode;
-		break;
-	case CPIA2_CID_LIGHTS:
-	{
-		int i;
-		cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
-				 TRANSFER_READ, 0);
-		for(i=0; i<NUM_LIGHTS_CONTROLS; i++) {
-			if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) ==
-			   lights_controls[i].value) {
-				break;
-			}
-		}
-		if(i == NUM_LIGHTS_CONTROLS)
-			return -EINVAL;
-		c->value = i;
-		break;
-	}
-	case CPIA2_CID_RESET_CAMERA:
+	/* Maximum 15 fps for this model */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+	    cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+		max -= 2;
+	if (fival->index > max)
 		return -EINVAL;
-	default:
+	for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++)
+		if (fival->width == cpia2_framesizes[i].width &&
+		    fival->height == cpia2_framesizes[i].height)
+			break;
+	if (i == ARRAY_SIZE(cpia2_framesizes))
 		return -EINVAL;
-	}
-
-	DBG("Get control id:%d, value:%d\n", c->id, c->value);
-
+	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fival->discrete = framerate_controls[fival->index].period;
 	return 0;
 }
 
@@ -958,72 +617,54 @@
  *
  *****************************************************************************/
 
-static int cpia2_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+static int cpia2_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct camera_data *cam = video_drvdata(file);
-	int i;
-	int retval = 0;
+	struct camera_data *cam =
+		container_of(ctrl->handler, struct camera_data, hdl);
+	static const int flicker_table[] = {
+		NEVER_FLICKER,
+		FLICKER_50,
+		FLICKER_60,
+	};
 
-	DBG("Set control id:%d, value:%d\n", c->id, c->value);
+	DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val);
 
-	/* Check that the value is in range */
-	for(i=0; i<NUM_CONTROLS; i++) {
-		if(c->id == controls[i].id) {
-			if(c->value < controls[i].minimum ||
-			   c->value > controls[i].maximum) {
-				return -EINVAL;
-			}
-			break;
-		}
-	}
-	if(i == NUM_CONTROLS)
-		return -EINVAL;
-
-	switch(c->id) {
+	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		cpia2_set_brightness(cam, c->value);
+		cpia2_set_brightness(cam, ctrl->val);
 		break;
 	case V4L2_CID_CONTRAST:
-		cpia2_set_contrast(cam, c->value);
+		cpia2_set_contrast(cam, ctrl->val);
 		break;
 	case V4L2_CID_SATURATION:
-		cpia2_set_saturation(cam, c->value);
+		cpia2_set_saturation(cam, ctrl->val);
 		break;
 	case V4L2_CID_HFLIP:
-		cpia2_set_property_mirror(cam, c->value);
+		cpia2_set_property_mirror(cam, ctrl->val);
 		break;
 	case V4L2_CID_VFLIP:
-		cpia2_set_property_flip(cam, c->value);
+		cpia2_set_property_flip(cam, ctrl->val);
 		break;
-	case CPIA2_CID_TARGET_KB:
-		retval = cpia2_set_target_kb(cam, c->value);
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]);
+	case V4L2_CID_ILLUMINATORS_1:
+		return cpia2_set_gpio(cam, (cam->top_light->val << 6) |
+					   (cam->bottom_light->val << 7));
+	case V4L2_CID_JPEG_ACTIVE_MARKER:
+		cam->params.compression.inhibit_htables =
+			!(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT);
 		break;
-	case CPIA2_CID_GPIO:
-		retval = cpia2_set_gpio(cam, c->value);
-		break;
-	case CPIA2_CID_FLICKER_MODE:
-		retval = cpia2_set_flicker_mode(cam,
-					      flicker_controls[c->value].value);
-		break;
-	case CPIA2_CID_FRAMERATE:
-		retval = cpia2_set_fps(cam, framerate_controls[c->value].value);
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+		cam->params.vc_params.quality = ctrl->val;
 		break;
 	case CPIA2_CID_USB_ALT:
-		retval = cpia2_usb_change_streaming_alternate(cam, c->value);
-		break;
-	case CPIA2_CID_LIGHTS:
-		retval = cpia2_set_gpio(cam, lights_controls[c->value].value);
-		break;
-	case CPIA2_CID_RESET_CAMERA:
-		cpia2_usb_stream_pause(cam);
-		cpia2_reset_camera(cam);
-		cpia2_usb_stream_resume(cam);
+		cam->params.camera_state.stream_mode = ctrl->val;
 		break;
 	default:
-		retval = -EINVAL;
+		return -EINVAL;
 	}
 
-	return retval;
+	return 0;
 }
 
 /******************************************************************************
@@ -1084,6 +725,8 @@
 
 	cam->params.compression.inhibit_htables =
 		!(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
+	parms->jpeg_markers &= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI |
+			       V4L2_JPEG_MARKER_DHT;
 
 	if(parms->APP_len != 0) {
 		if(parms->APP_len > 0 &&
@@ -1270,12 +913,12 @@
 		struct framebuf *cb=cam->curbuff;
 		mutex_unlock(&cam->v4l2_lock);
 		wait_event_interruptible(cam->wq_stream,
-					 !cam->present ||
+					 !video_is_registered(&cam->vdev) ||
 					 (cb=cam->curbuff)->status == FRAME_READY);
 		mutex_lock(&cam->v4l2_lock);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		if(!cam->present)
+		if (!video_is_registered(&cam->vdev))
 			return -ENOTTY;
 		frame = cb->num;
 	}
@@ -1299,56 +942,39 @@
 	return 0;
 }
 
-static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p)
-{
-	struct cpia2_fh *fh = _fh;
-
-	*p = fh->prio;
-	return 0;
-}
-
-static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio)
-{
-	struct camera_data *cam = video_drvdata(file);
-	struct cpia2_fh *fh = _fh;
-
-	if (cam->streaming && prio != fh->prio &&
-			fh->prio == V4L2_PRIORITY_RECORD)
-		/* Can't drop record priority while streaming */
-		return -EBUSY;
-
-	if (prio == V4L2_PRIORITY_RECORD && prio != fh->prio &&
-			v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD)
-		/* Only one program can record at a time */
-		return -EBUSY;
-	return v4l2_prio_change(&cam->prio, &fh->prio, prio);
-}
-
 static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 {
 	struct camera_data *cam = video_drvdata(file);
+	int ret = -EINVAL;
 
 	DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
 	if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
-	if (!cam->streaming)
-		return cpia2_usb_stream_start(cam,
+	if (!cam->streaming) {
+		ret = cpia2_usb_stream_start(cam,
 				cam->params.camera_state.stream_mode);
-	return -EINVAL;
+		if (!ret)
+			v4l2_ctrl_grab(cam->usb_alt, true);
+	}
+	return ret;
 }
 
 static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
 {
 	struct camera_data *cam = video_drvdata(file);
+	int ret = -EINVAL;
 
 	DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
 	if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
-	if (cam->streaming)
-		return cpia2_usb_stream_stop(cam);
-	return -EINVAL;
+	if (cam->streaming) {
+		ret = cpia2_usb_stream_stop(cam);
+		if (!ret)
+			v4l2_ctrl_grab(cam->usb_alt, false);
+	}
+	return ret;
 }
 
 /******************************************************************************
@@ -1361,16 +987,10 @@
 	struct camera_data *cam = video_drvdata(file);
 	int retval;
 
-	/* Priority check */
-	struct cpia2_fh *fh = file->private_data;
-	if(fh->prio != V4L2_PRIORITY_RECORD) {
-		return -EBUSY;
-	}
-
 	retval = cpia2_remap_buffer(cam, area);
 
 	if(!retval)
-		fh->mmapped = 1;
+		cam->stream_fh = file->private_data;
 	return retval;
 }
 
@@ -1388,15 +1008,13 @@
 	cam->frame_size = buffer_size;
 	cam->num_frames = num_buffers;
 
-	/* FlickerModes */
+	/* Flicker modes */
 	cam->params.flicker_control.flicker_mode_req = flicker_mode;
-	cam->params.flicker_control.mains_frequency = flicker_freq;
 
-	/* streamMode */
+	/* stream modes */
 	cam->params.camera_state.stream_mode = alternate;
 
 	cam->pixelformat = V4L2_PIX_FMT_JPEG;
-	v4l2_prio_init(&cam->prio);
 }
 
 static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
@@ -1408,10 +1026,6 @@
 	.vidioc_g_fmt_vid_cap		    = cpia2_g_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap		    = cpia2_s_fmt_vid_cap,
 	.vidioc_try_fmt_vid_cap		    = cpia2_try_fmt_vid_cap,
-	.vidioc_queryctrl		    = cpia2_queryctrl,
-	.vidioc_querymenu		    = cpia2_querymenu,
-	.vidioc_g_ctrl			    = cpia2_g_ctrl,
-	.vidioc_s_ctrl			    = cpia2_s_ctrl,
 	.vidioc_g_jpegcomp		    = cpia2_g_jpegcomp,
 	.vidioc_s_jpegcomp		    = cpia2_s_jpegcomp,
 	.vidioc_cropcap			    = cpia2_cropcap,
@@ -1421,9 +1035,12 @@
 	.vidioc_dqbuf			    = cpia2_dqbuf,
 	.vidioc_streamon		    = cpia2_streamon,
 	.vidioc_streamoff		    = cpia2_streamoff,
-	.vidioc_g_priority		    = cpia2_g_priority,
-	.vidioc_s_priority		    = cpia2_s_priority,
-	.vidioc_default			    = cpia2_default,
+	.vidioc_s_parm			    = cpia2_s_parm,
+	.vidioc_g_parm			    = cpia2_g_parm,
+	.vidioc_enum_framesizes		    = cpia2_enum_framesizes,
+	.vidioc_enum_frameintervals	    = cpia2_enum_frameintervals,
+	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
 };
 
 /***
@@ -1444,7 +1061,21 @@
 	.name =		"CPiA2 Camera",
 	.fops =		&cpia2_fops,
 	.ioctl_ops =	&cpia2_ioctl_ops,
-	.release =	video_device_release,
+	.release =	video_device_release_empty,
+};
+
+void cpia2_camera_release(struct v4l2_device *v4l2_dev)
+{
+	struct camera_data *cam =
+		container_of(v4l2_dev, struct camera_data, v4l2_dev);
+
+	v4l2_ctrl_handler_free(&cam->hdl);
+	v4l2_device_unregister(&cam->v4l2_dev);
+	kfree(cam);
+}
+
+static const struct v4l2_ctrl_ops cpia2_ctrl_ops = {
+	.s_ctrl = cpia2_s_ctrl,
 };
 
 /******************************************************************************
@@ -1454,20 +1085,78 @@
  *****************************************************************************/
 int cpia2_register_camera(struct camera_data *cam)
 {
-	cam->vdev = video_device_alloc();
-	if(!cam->vdev)
-		return -ENOMEM;
+	struct v4l2_ctrl_handler *hdl = &cam->hdl;
+	struct v4l2_ctrl_config cpia2_usb_alt = {
+		.ops = &cpia2_ctrl_ops,
+		.id = CPIA2_CID_USB_ALT,
+		.name = "USB Alternate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = USBIF_ISO_1,
+		.max = USBIF_ISO_6,
+		.step = 1,
+	};
+	int ret;
 
-	memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template));
-	video_set_drvdata(cam->vdev, cam);
-	cam->vdev->lock = &cam->v4l2_lock;
+	v4l2_ctrl_handler_init(hdl, 12);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_BRIGHTNESS,
+			cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
+			255, 1, DEFAULT_BRIGHTNESS);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_JPEG_ACTIVE_MARKER, 0,
+			V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
+			V4L2_JPEG_ACTIVE_MARKER_DHT);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
+			100, 1, 100);
+	cpia2_usb_alt.def = alternate;
+	cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL);
+	/* VP5 Only */
+	if (cam->params.pnp_id.device_type != DEVICE_STV_672)
+		v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	/* Flicker control only valid for 672 */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+		v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_POWER_LINE_FREQUENCY,
+			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
+	/* Light control only valid for the QX5 Microscope */
+	if (cam->params.pnp_id.product == 0x151) {
+		cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+				V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+		cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+				V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
+		v4l2_ctrl_cluster(2, &cam->top_light);
+	}
+
+	if (hdl->error) {
+		ret = hdl->error;
+		v4l2_ctrl_handler_free(hdl);
+		return ret;
+	}
+
+	cam->vdev = cpia2_template;
+	video_set_drvdata(&cam->vdev, cam);
+	cam->vdev.lock = &cam->v4l2_lock;
+	cam->vdev.ctrl_handler = hdl;
+	cam->vdev.v4l2_dev = &cam->v4l2_dev;
+	set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &cam->vdev.flags);
 
 	reset_camera_struct_v4l(cam);
 
 	/* register v4l device */
-	if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		ERR("video_register_device failed\n");
-		video_device_release(cam->vdev);
 		return -ENODEV;
 	}
 
@@ -1481,13 +1170,7 @@
  *****************************************************************************/
 void cpia2_unregister_camera(struct camera_data *cam)
 {
-	if (!cam->open_count) {
-		video_unregister_device(cam->vdev);
-	} else {
-		LOG("%s removed while open, deferring "
-		    "video_unregister_device\n",
-		    video_device_node_name(cam->vdev));
-	}
+	video_unregister_device(&cam->vdev);
 }
 
 /******************************************************************************
@@ -1524,23 +1207,12 @@
 		LOG("alternate specified is invalid, using %d\n", alternate);
 	}
 
-	if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) {
-		flicker_mode = NEVER_FLICKER;
+	if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) {
+		flicker_mode = 0;
 		LOG("Flicker mode specified is invalid, using %d\n",
 		    flicker_mode);
 	}
 
-	if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) {
-		flicker_freq = FLICKER_60;
-		LOG("Flicker mode specified is invalid, using %d\n",
-		    flicker_freq);
-	}
-
-	if(video_nr < -1 || video_nr > 64) {
-		video_nr = -1;
-		LOG("invalid video_nr specified, must be -1 to 64\n");
-	}
-
 	DBG("Using %d buffers, each %d bytes, alternate=%d\n",
 	    num_buffers, buffer_size, alternate);
 }
diff --git a/drivers/media/video/cpia2/cpia2dev.h b/drivers/media/video/cpia2/cpia2dev.h
deleted file mode 100644
index f66691f..0000000
--- a/drivers/media/video/cpia2/cpia2dev.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/****************************************************************************
- *
- *  Filename: cpia2dev.h
- *
- *  Copyright 2001, STMicrolectronics, Inc.
- *
- *  Contact:  steve.miller@st.com
- *
- *  Description:
- *     This file provides definitions for applications wanting to use the
- *     cpia2 driver beyond the generic v4l capabilities.
- *
- *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- ****************************************************************************/
-
-#ifndef CPIA2_DEV_HEADER
-#define CPIA2_DEV_HEADER
-
-#include <linux/videodev2.h>
-
-/***
- * The following defines are ioctl numbers based on video4linux private ioctls,
- * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int
- * args
- */
-#define CPIA2_IOC_SET_GPIO         _IOW('v', BASE_VIDIOC_PRIVATE + 17, __u32)
-
-/* V4L2 driver specific controls */
-#define CPIA2_CID_TARGET_KB     (V4L2_CID_PRIVATE_BASE+0)
-#define CPIA2_CID_GPIO          (V4L2_CID_PRIVATE_BASE+1)
-#define CPIA2_CID_FLICKER_MODE  (V4L2_CID_PRIVATE_BASE+2)
-#define CPIA2_CID_FRAMERATE     (V4L2_CID_PRIVATE_BASE+3)
-#define CPIA2_CID_USB_ALT       (V4L2_CID_PRIVATE_BASE+4)
-#define CPIA2_CID_LIGHTS        (V4L2_CID_PRIVATE_BASE+5)
-#define CPIA2_CID_RESET_CAMERA  (V4L2_CID_PRIVATE_BASE+6)
-
-#endif
diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c
index e118361..6d2a982 100644
--- a/drivers/media/video/cx18/cx18-alsa-main.c
+++ b/drivers/media/video/cx18/cx18-alsa-main.c
@@ -285,6 +285,7 @@
 
 	drv = driver_find("cx18", &pci_bus_type);
 	ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
+	(void)ret;	/* suppress compiler warning */
 
 	cx18_ext_init = NULL;
 	printk(KERN_INFO "cx18-alsa: module unload complete\n");
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c
index 82d195b..7a5b84a 100644
--- a/drivers/media/video/cx18/cx18-alsa-pcm.c
+++ b/drivers/media/video/cx18/cx18-alsa-pcm.c
@@ -190,7 +190,7 @@
 	ret = cx18_start_v4l2_encode_stream(s);
 	snd_cx18_unlock(cxsc);
 
-	return 0;
+	return ret;
 }
 
 static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
@@ -199,12 +199,11 @@
 	struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
 	struct cx18 *cx = to_cx18(v4l2_dev);
 	struct cx18_stream *s;
-	int ret;
 
 	/* Instruct the cx18 to stop sending packets */
 	snd_cx18_lock(cxsc);
 	s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
-	ret = cx18_stop_v4l2_encode_stream(s, 0);
+	cx18_stop_v4l2_encode_stream(s, 0);
 	clear_bit(CX18_F_S_STREAMING, &s->s_flags);
 
 	cx18_release_stream(s);
@@ -252,13 +251,10 @@
 static int snd_cx18_pcm_hw_params(struct snd_pcm_substream *substream,
 			 struct snd_pcm_hw_params *params)
 {
-	int ret;
-
 	dprintk("%s called\n", __func__);
 
-	ret = snd_pcm_alloc_vmalloc_buffer(substream,
+	return snd_pcm_alloc_vmalloc_buffer(substream,
 					   params_buffer_bytes(params));
-	return 0;
 }
 
 static int snd_cx18_pcm_hw_free(struct snd_pcm_substream *substream)
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index be49f68..35fde4e 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -1137,7 +1137,7 @@
 	}
 
 	default:
-		return -EINVAL;
+		return -ENOTTY;
 	}
 	return 0;
 }
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 0c7796e..ed81183 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -595,9 +595,8 @@
 static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
 {
 	const struct cx18_api_info *info = find_api_info(cmd);
-	u32 state, irq, req, ack, err;
+	u32 irq, req, ack, err;
 	struct cx18_mailbox __iomem *mb;
-	u32 __iomem *xpu_state;
 	wait_queue_head_t *waitq;
 	struct mutex *mb_lock;
 	unsigned long int t0, timeout, ret;
@@ -628,14 +627,12 @@
 		mb_lock = &cx->epu2apu_mb_lock;
 		irq = IRQ_EPU_TO_APU;
 		mb = &cx->scb->epu2apu_mb;
-		xpu_state = &cx->scb->apu_state;
 		break;
 	case CPU:
 		waitq = &cx->mb_cpu_waitq;
 		mb_lock = &cx->epu2cpu_mb_lock;
 		irq = IRQ_EPU_TO_CPU;
 		mb = &cx->scb->epu2cpu_mb;
-		xpu_state = &cx->scb->cpu_state;
 		break;
 	default:
 		CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu);
@@ -653,7 +650,6 @@
 	 * by a signal, we may get here and find a busy mailbox.  After waiting,
 	 * mark it "not busy" from our end, if the XPU hasn't ack'ed it still.
 	 */
-	state = cx18_readl(cx, xpu_state);
 	req = cx18_readl(cx, &mb->request);
 	timeout = msecs_to_jiffies(10);
 	ret = wait_event_timeout(*waitq,
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 638cca1..4185bcb 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -980,7 +980,6 @@
 int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
 {
 	struct cx18 *cx = s->cx;
-	unsigned long then;
 
 	if (!cx18_stream_enabled(s))
 		return -EINVAL;
@@ -999,8 +998,6 @@
 	else
 		cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
 
-	then = jiffies;
-
 	if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
 		CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
 	}
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c
index d4327da..ce2f622 100644
--- a/drivers/media/video/cx231xx/cx231xx-417.c
+++ b/drivers/media/video/cx231xx/cx231xx-417.c
@@ -1095,7 +1095,7 @@
 {
 	int version;
 	int retval;
-	u32 i, data[7];
+	u32 i;
 	u32 val = 0;
 
 	dprintk(1, "%s()\n", __func__);
@@ -1154,6 +1154,11 @@
 		CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 		0, 0);
 */
+
+#if 0
+	/* TODO */
+	u32 data[7];
+
 	/* Setup to capture VBI */
 	data[0] = 0x0001BD00;
 	data[1] = 1;          /* frames per interrupt */
@@ -1162,7 +1167,7 @@
 	data[4] = 0x206080C0; /* stop codes */
 	data[5] = 6;          /* lines */
 	data[6] = 64;         /* BPL */
-/*
+
 	cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
 		data[2], data[3], data[4], data[5], data[6]);
 
@@ -1175,7 +1180,7 @@
 		cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
 				i | 0x80000000, valid, 0, 0, 0);
 	}
-*/
+#endif
 /*	cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
 	msleep(60);
 */
@@ -1792,17 +1797,16 @@
 	struct cx231xx_fh  *fh  = file->private_data;
 
 	struct cx231xx *dev = fh->dev;
-	int rc = 0;
 	dprintk(3, "enter vidioc_streamon()\n");
 		cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
-		rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+		cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
 		if (dev->USE_ISO)
-			rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+			cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
 				       CX231XX_NUM_BUFS,
 				       dev->video_mode.max_pkt_size,
 				       cx231xx_isoc_copy);
 		else {
-			rc = cx231xx_init_bulk(dev, 320,
+			cx231xx_init_bulk(dev, 320,
 				       5,
 				       dev->ts1_mode.max_pkt_size,
 				       cx231xx_bulk_copy);
diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c
index a2c2b7d..068f78d 100644
--- a/drivers/media/video/cx231xx/cx231xx-audio.c
+++ b/drivers/media/video/cx231xx/cx231xx-audio.c
@@ -523,21 +523,24 @@
 static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream,
 					 struct snd_pcm_hw_params *hw_params)
 {
-	unsigned int channels, rate, format;
 	int ret;
 
 	dprintk("Setting capture parameters\n");
 
 	ret = snd_pcm_alloc_vmalloc_buffer(substream,
 					   params_buffer_bytes(hw_params));
-	format = params_format(hw_params);
-	rate = params_rate(hw_params);
-	channels = params_channels(hw_params);
-
+#if 0
 	/* TODO: set up cx231xx audio chip to deliver the correct audio format,
 	   current default is 48000hz multiplexed => 96000hz mono
 	   which shouldn't matter since analogue TV only supports mono */
-	return 0;
+	unsigned int channels, rate, format;
+
+	format = params_format(hw_params);
+	rate = params_rate(hw_params);
+	channels = params_channels(hw_params);
+#endif
+
+	return ret;
 }
 
 static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
@@ -586,7 +589,7 @@
 				       int cmd)
 {
 	struct cx231xx *dev = snd_pcm_substream_chip(substream);
-	int retval;
+	int retval = 0;
 
 	if (dev->state & DEV_DISCONNECTED)
 		return -ENODEV;
@@ -601,12 +604,13 @@
 		break;
 	default:
 		retval = -EINVAL;
+		break;
 	}
 	spin_unlock(&dev->adev.slock);
 
 	schedule_work(&dev->wq_trigger);
 
-	return 0;
+	return retval;
 }
 
 static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c
index 53ff26e..b085a3c 100644
--- a/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -934,33 +934,29 @@
 void cx231xx_enable656(struct cx231xx *dev)
 {
 	u8 temp = 0;
-	int status;
 	/*enable TS1 data[0:7] as output to export 656*/
 
-	status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0xFF);
+	vid_blk_write_byte(dev, TS1_PIN_CTL0, 0xFF);
 
 	/*enable TS1 clock as output to export 656*/
 
-	status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+	vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
 	temp = temp|0x04;
 
-	status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
-
+	vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
 }
 EXPORT_SYMBOL_GPL(cx231xx_enable656);
 
 void cx231xx_disable656(struct cx231xx *dev)
 {
 	u8 temp = 0;
-	int status;
 
+	vid_blk_write_byte(dev, TS1_PIN_CTL0, 0x00);
 
-	status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0x00);
-
-	status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+	vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
 	temp = temp&0xFB;
 
-	status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
+	vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
 }
 EXPORT_SYMBOL_GPL(cx231xx_disable656);
 
@@ -1320,117 +1316,115 @@
 
 void cx231xx_dump_HH_reg(struct cx231xx *dev)
 {
-	u8 status = 0;
 	u32 value = 0;
 	u16  i = 0;
 
 	value = 0x45005390;
-	status = vid_blk_write_word(dev, 0x104, value);
+	vid_blk_write_word(dev, 0x104, value);
 
 	for (i = 0x100; i < 0x140; i++) {
-		status = vid_blk_read_word(dev, i, &value);
+		vid_blk_read_word(dev, i, &value);
 		cx231xx_info("reg0x%x=0x%x\n", i, value);
 		i = i+3;
 	}
 
 	for (i = 0x300; i < 0x400; i++) {
-		status = vid_blk_read_word(dev, i, &value);
+		vid_blk_read_word(dev, i, &value);
 		cx231xx_info("reg0x%x=0x%x\n", i, value);
 		i = i+3;
 	}
 
 	for (i = 0x400; i < 0x440; i++) {
-		status = vid_blk_read_word(dev, i,  &value);
+		vid_blk_read_word(dev, i,  &value);
 		cx231xx_info("reg0x%x=0x%x\n", i, value);
 		i = i+3;
 	}
 
-	status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+	vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
 	cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
 	vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
-	status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+	vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
 	cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
 }
 
 void cx231xx_dump_SC_reg(struct cx231xx *dev)
 {
 	u8 value[4] = { 0, 0, 0, 0 };
-	int status = 0;
 	cx231xx_info("cx231xx_dump_SC_reg!\n");
 
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", BOARD_CFG_STAT, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS_MODE_REG, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_CFG_REG, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_LENGTH_REG, value[0],
 				 value[1], value[2], value[3]);
 
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_CFG_REG, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_LENGTH_REG, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", EP_MODE_SET, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN1, value[0],
 				 value[1], value[2], value[3]);
 
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN2, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN3, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK0, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK1, value[0],
 				 value[1], value[2], value[3]);
 
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK2, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_GAIN, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_CAR_REG, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG1, value[0],
 				 value[1], value[2], value[3]);
 
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG2, value[0],
 				 value[1], value[2], value[3]);
-	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
 				 value, 4);
 	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, value[0],
 				 value[1], value[2], value[3]);
@@ -1441,18 +1435,15 @@
 void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev)
 
 {
-	u8 status = 0;
 	u8 value = 0;
 
-
-
-	status = afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+	afe_read_byte(dev, ADC_STATUS2_CH3, &value);
 	value = (value & 0xFE)|0x01;
-	status = afe_write_byte(dev, ADC_STATUS2_CH3, value);
+	afe_write_byte(dev, ADC_STATUS2_CH3, value);
 
-	status = afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+	afe_read_byte(dev, ADC_STATUS2_CH3, &value);
 	value = (value & 0xFE)|0x00;
-	status = afe_write_byte(dev, ADC_STATUS2_CH3, value);
+	afe_write_byte(dev, ADC_STATUS2_CH3, value);
 
 
 /*
@@ -1464,44 +1455,43 @@
 		for low-if agc defect
 */
 
-	status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, &value);
+	afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, &value);
 	value = (value & 0xFC)|0x00;
-	status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, value);
+	afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, value);
 
-	status = afe_read_byte(dev, ADC_INPUT_CH3, &value);
+	afe_read_byte(dev, ADC_INPUT_CH3, &value);
 	value = (value & 0xF9)|0x02;
-	status = afe_write_byte(dev, ADC_INPUT_CH3, value);
+	afe_write_byte(dev, ADC_INPUT_CH3, value);
 
-	status = afe_read_byte(dev, ADC_FB_FRCRST_CH3, &value);
+	afe_read_byte(dev, ADC_FB_FRCRST_CH3, &value);
 	value = (value & 0xFB)|0x04;
-	status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, value);
+	afe_write_byte(dev, ADC_FB_FRCRST_CH3, value);
 
-	status = afe_read_byte(dev, ADC_DCSERVO_DEM_CH3, &value);
+	afe_read_byte(dev, ADC_DCSERVO_DEM_CH3, &value);
 	value = (value & 0xFC)|0x03;
-	status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, value);
+	afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, value);
 
-	status = afe_read_byte(dev, ADC_CTRL_DAC1_CH3, &value);
+	afe_read_byte(dev, ADC_CTRL_DAC1_CH3, &value);
 	value = (value & 0xFB)|0x04;
-	status = afe_write_byte(dev, ADC_CTRL_DAC1_CH3, value);
+	afe_write_byte(dev, ADC_CTRL_DAC1_CH3, value);
 
-	status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+	afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
 	value = (value & 0xF8)|0x06;
-	status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+	afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
 
-	status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+	afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
 	value = (value & 0x8F)|0x40;
-	status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+	afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
 
-	status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH3, &value);
+	afe_read_byte(dev, ADC_PWRDN_CLAMP_CH3, &value);
 	value = (value & 0xDF)|0x20;
-	status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, value);
+	afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, value);
 }
 
 void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
 		 u8 spectral_invert, u32 mode)
 {
 	u32 colibri_carrier_offset = 0;
-	u8 status = 0;
 	u32 func_mode = 0x01; /* Device has a DIF if this function is called */
 	u32 standard = 0;
 	u8 value[4] = { 0, 0, 0, 0 };
@@ -1511,15 +1501,15 @@
 	value[1] = (u8) 0x6F;
 	value[2] = (u8) 0x6F;
 	value[3] = (u8) 0x6F;
-	status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
 					PWR_CTL_EN, value, 4);
 
 	/*Set colibri for low IF*/
-	status = cx231xx_afe_set_mode(dev, AFE_MODE_LOW_IF);
+	cx231xx_afe_set_mode(dev, AFE_MODE_LOW_IF);
 
 	/* Set C2HH for low IF operation.*/
 	standard = dev->norm;
-	status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode,
+	cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode,
 						       func_mode, standard);
 
 	/* Get colibri offsets.*/
@@ -1556,7 +1546,6 @@
 		 u8 spectral_invert, u32 mode)
 {
 	unsigned long pll_freq_word;
-	int status = 0;
 	u32 dif_misc_ctrl_value = 0;
 	u64 pll_freq_u64 = 0;
 	u32 i = 0;
@@ -1567,7 +1556,7 @@
 
 	if (mode == TUNER_MODE_FM_RADIO) {
 		pll_freq_word = 0x905A1CAC;
-		status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD,  pll_freq_word);
+		vid_blk_write_word(dev, DIF_PLL_FREQ_WORD,  pll_freq_word);
 
 	} else /*KSPROPERTY_TUNER_MODE_TV*/{
 		/* Calculate the PLL frequency word based on the adjusted if_freq*/
@@ -1576,23 +1565,23 @@
 		do_div(pll_freq_u64, 50000000);
 		pll_freq_word = (u32)pll_freq_u64;
 		/*pll_freq_word = 0x3463497;*/
-		status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD,  pll_freq_word);
+		vid_blk_write_word(dev, DIF_PLL_FREQ_WORD,  pll_freq_word);
 
 	if (spectral_invert) {
 		if_freq -= 400000;
 		/* Enable Spectral Invert*/
-		status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+		vid_blk_read_word(dev, DIF_MISC_CTRL,
 					&dif_misc_ctrl_value);
 		dif_misc_ctrl_value = dif_misc_ctrl_value | 0x00200000;
-		status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+		vid_blk_write_word(dev, DIF_MISC_CTRL,
 					dif_misc_ctrl_value);
 	} else {
 		if_freq += 400000;
 		/* Disable Spectral Invert*/
-		status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+		vid_blk_read_word(dev, DIF_MISC_CTRL,
 					&dif_misc_ctrl_value);
 		dif_misc_ctrl_value = dif_misc_ctrl_value & 0xFFDFFFFF;
-		status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+		vid_blk_write_word(dev, DIF_MISC_CTRL,
 					dif_misc_ctrl_value);
 	}
 
@@ -1606,10 +1595,10 @@
 	}
 
 	cx231xx_info("Enter IF=%zd\n",
-			sizeof(Dif_set_array)/sizeof(struct dif_settings));
-	for (i = 0; i < sizeof(Dif_set_array)/sizeof(struct dif_settings); i++) {
+			ARRAY_SIZE(Dif_set_array));
+	for (i = 0; i < ARRAY_SIZE(Dif_set_array); i++) {
 		if (Dif_set_array[i].if_freq == if_freq) {
-			status = vid_blk_write_word(dev,
+			vid_blk_write_word(dev,
 			Dif_set_array[i].register_address, Dif_set_array[i].value);
 		}
 	}
@@ -3090,31 +3079,30 @@
  */
 int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len)
 {
-	int status = 0;
 	int i = 0;
 
 	/* get the lock */
 	mutex_lock(&dev->gpio_i2c_lock);
 
 	/* start */
-	status = cx231xx_gpio_i2c_start(dev);
+	cx231xx_gpio_i2c_start(dev);
 
 	/* write dev_addr */
-	status = cx231xx_gpio_i2c_write_byte(dev, dev_addr << 1);
+	cx231xx_gpio_i2c_write_byte(dev, dev_addr << 1);
 
 	/* read Ack */
-	status = cx231xx_gpio_i2c_read_ack(dev);
+	cx231xx_gpio_i2c_read_ack(dev);
 
 	for (i = 0; i < len; i++) {
 		/* Write data */
-		status = cx231xx_gpio_i2c_write_byte(dev, buf[i]);
+		cx231xx_gpio_i2c_write_byte(dev, buf[i]);
 
 		/* read Ack */
-		status = cx231xx_gpio_i2c_read_ack(dev);
+		cx231xx_gpio_i2c_read_ack(dev);
 	}
 
 	/* write End */
-	status = cx231xx_gpio_i2c_end(dev);
+	cx231xx_gpio_i2c_end(dev);
 
 	/* release the lock */
 	mutex_unlock(&dev->gpio_i2c_lock);
diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c
index 08dd930..05358d4 100644
--- a/drivers/media/video/cx231xx/cx231xx-core.c
+++ b/drivers/media/video/cx231xx/cx231xx-core.c
@@ -754,7 +754,7 @@
 		}
 	}
 
-	return 0;
+	return errCode ? -EINVAL : 0;
 }
 EXPORT_SYMBOL_GPL(cx231xx_set_mode);
 
@@ -764,7 +764,7 @@
 	int actlen, ret = -ENOMEM;
 	u32 *buffer;
 
-buffer = kzalloc(4096, GFP_KERNEL);
+	buffer = kzalloc(4096, GFP_KERNEL);
 	if (buffer == NULL) {
 		cx231xx_info("out of mem\n");
 		return -ENOMEM;
@@ -772,16 +772,16 @@
 	memcpy(&buffer[0], firmware, 4096);
 
 	ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5),
-				 buffer, 4096, &actlen, 2000);
+			buffer, 4096, &actlen, 2000);
 
 	if (ret)
 		cx231xx_info("bulk message failed: %d (%d/%d)", ret,
-				 size, actlen);
+				size, actlen);
 	else {
 		errCode = actlen != size ? -1 : 0;
 	}
-kfree(buffer);
-	return 0;
+	kfree(buffer);
+	return errCode;
 }
 
 /*****************************************************************
@@ -797,7 +797,7 @@
 	struct cx231xx_video_mode *vmode =
 	    container_of(dma_q, struct cx231xx_video_mode, vidq);
 	struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
-	int rc, i;
+	int i;
 
 	switch (urb->status) {
 	case 0:		/* success */
@@ -814,7 +814,7 @@
 
 	/* Copy data from URB */
 	spin_lock(&dev->video_mode.slock);
-	rc = dev->video_mode.isoc_ctl.isoc_copy(dev, urb);
+	dev->video_mode.isoc_ctl.isoc_copy(dev, urb);
 	spin_unlock(&dev->video_mode.slock);
 
 	/* Reset urb buffers */
@@ -822,7 +822,6 @@
 		urb->iso_frame_desc[i].status = 0;
 		urb->iso_frame_desc[i].actual_length = 0;
 	}
-	urb->status = 0;
 
 	urb->status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (urb->status) {
@@ -843,7 +842,6 @@
 	struct cx231xx_video_mode *vmode =
 	    container_of(dma_q, struct cx231xx_video_mode, vidq);
 	struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
-	int rc;
 
 	switch (urb->status) {
 	case 0:		/* success */
@@ -860,12 +858,10 @@
 
 	/* Copy data from URB */
 	spin_lock(&dev->video_mode.slock);
-	rc = dev->video_mode.bulk_ctl.bulk_copy(dev, urb);
+	dev->video_mode.bulk_ctl.bulk_copy(dev, urb);
 	spin_unlock(&dev->video_mode.slock);
 
 	/* Reset urb buffers */
-	urb->status = 0;
-
 	urb->status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (urb->status) {
 		cx231xx_isocdbg("urb resubmit failed (error=%i)\n",
@@ -1231,42 +1227,40 @@
 EXPORT_SYMBOL_GPL(cx231xx_init_bulk);
 void cx231xx_stop_TS1(struct cx231xx *dev)
 {
-	int status = 0;
 	u8 val[4] = { 0, 0, 0, 0 };
 
-			val[0] = 0x00;
-			val[1] = 0x03;
-			val[2] = 0x00;
-			val[3] = 0x00;
-			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
-				 TS_MODE_REG, val, 4);
+	val[0] = 0x00;
+	val[1] = 0x03;
+	val[2] = 0x00;
+	val[3] = 0x00;
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+			TS_MODE_REG, val, 4);
 
-			val[0] = 0x00;
-			val[1] = 0x70;
-			val[2] = 0x04;
-			val[3] = 0x00;
-			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
-				 TS1_CFG_REG, val, 4);
+	val[0] = 0x00;
+	val[1] = 0x70;
+	val[2] = 0x04;
+	val[3] = 0x00;
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+			TS1_CFG_REG, val, 4);
 }
 /* EXPORT_SYMBOL_GPL(cx231xx_stop_TS1); */
 void cx231xx_start_TS1(struct cx231xx *dev)
 {
-	int status = 0;
 	u8 val[4] = { 0, 0, 0, 0 };
 
-			val[0] = 0x03;
-			val[1] = 0x03;
-			val[2] = 0x00;
-			val[3] = 0x00;
-			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
-				 TS_MODE_REG, val, 4);
+	val[0] = 0x03;
+	val[1] = 0x03;
+	val[2] = 0x00;
+	val[3] = 0x00;
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+			TS_MODE_REG, val, 4);
 
-			val[0] = 0x04;
-			val[1] = 0xA3;
-			val[2] = 0x3B;
-			val[3] = 0x00;
-			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
-				 TS1_CFG_REG, val, 4);
+	val[0] = 0x04;
+	val[1] = 0xA3;
+	val[2] = 0x3B;
+	val[3] = 0x00;
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+			TS1_CFG_REG, val, 4);
 }
 /* EXPORT_SYMBOL_GPL(cx231xx_start_TS1); */
 /*****************************************************************
diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c
index 8cdee5f..3d15314 100644
--- a/drivers/media/video/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/video/cx231xx/cx231xx-vbi.c
@@ -83,7 +83,6 @@
  */
 static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
 {
-	struct cx231xx_buffer *buf;
 	struct cx231xx_dmaqueue *dma_q = urb->context;
 	int rc = 1;
 	unsigned char *p_buffer;
@@ -102,8 +101,6 @@
 			return 0;
 	}
 
-	buf = dev->vbi_mode.bulk_ctl.buf;
-
 	/* get buffer pointer and length */
 	p_buffer = urb->transfer_buffer;
 	buffer_size = urb->actual_length;
@@ -310,7 +307,6 @@
 	struct cx231xx_video_mode *vmode =
 	    container_of(dma_q, struct cx231xx_video_mode, vidq);
 	struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode);
-	int rc;
 
 	switch (urb->status) {
 	case 0:		/* success */
@@ -328,7 +324,7 @@
 
 	/* Copy data from URB */
 	spin_lock(&dev->vbi_mode.slock);
-	rc = dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
+	dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
 	spin_unlock(&dev->vbi_mode.slock);
 
 	/* Reset status */
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 7f916f0..523aa49 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -326,9 +326,7 @@
  */
 static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
 {
-	struct cx231xx_buffer *buf;
 	struct cx231xx_dmaqueue *dma_q = urb->context;
-	unsigned char *outp = NULL;
 	int i, rc = 1;
 	unsigned char *p_buffer;
 	u32 bytes_parsed = 0, buffer_size = 0;
@@ -346,10 +344,6 @@
 			return 0;
 	}
 
-	buf = dev->video_mode.isoc_ctl.buf;
-	if (buf != NULL)
-		outp = videobuf_to_vmalloc(&buf->vb);
-
 	for (i = 0; i < urb->number_of_packets; i++) {
 		int status = urb->iso_frame_desc[i].status;
 
@@ -429,9 +423,7 @@
 
 static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
 {
-	struct cx231xx_buffer *buf;
 	struct cx231xx_dmaqueue *dma_q = urb->context;
-	unsigned char *outp = NULL;
 	int rc = 1;
 	unsigned char *p_buffer;
 	u32 bytes_parsed = 0, buffer_size = 0;
@@ -449,10 +441,6 @@
 			return 0;
 	}
 
-	buf = dev->video_mode.bulk_ctl.buf;
-	if (buf != NULL)
-		outp = videobuf_to_vmalloc(&buf->vb);
-
 	if (1) {
 
 		/*  get buffer pointer and length */
@@ -701,13 +689,9 @@
 		buf = dev->video_mode.bulk_ctl.buf;
 
 	if (buf == NULL) {
-		u8 *outp = NULL;
 		/* first try to get the buffer */
 		get_next_buf(dma_q, &buf);
 
-		if (buf)
-			outp = videobuf_to_vmalloc(&buf->vb);
-
 		dma_q->pos = 0;
 		dma_q->field1_done = 0;
 		dma_q->current_field = -1;
@@ -2561,6 +2545,10 @@
 	vfd->release = video_device_release;
 	vfd->debug = video_debug;
 	vfd->lock = &dev->lock;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
 
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 19b5499..13739e0 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -497,6 +497,10 @@
 		.name		= "TerraTec Cinergy T PCIe Dual",
 		.portb		= CX23885_MPEG_DVB,
 		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_TEVII_S471] = {
+		.name		= "TeVii S471",
+		.portb		= CX23885_MPEG_DVB,
 	}
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -705,6 +709,10 @@
 		.subvendor = 0x153b,
 		.subdevice = 0x117e,
 		.card      = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL,
+	}, {
+		.subvendor = 0xd471,
+		.subdevice = 0x9022,
+		.card      = CX23885_BOARD_TEVII_S471,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1460,6 +1468,7 @@
 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
 	case CX23885_BOARD_TEVII_S470:
+	case CX23885_BOARD_TEVII_S471:
 	case CX23885_BOARD_DVBWORLD_2005:
 		ts1->gen_ctrl_val  = 0x5; /* Parallel */
 		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 6ad2270..697728f 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -1046,6 +1046,13 @@
 	if (cx23885_boards[dev->board].ci_type > 0)
 		cx_clear(RDR_RDRCTL1, 1 << 8);
 
+	switch (dev->board) {
+	case CX23885_BOARD_TEVII_S470:
+	case CX23885_BOARD_TEVII_S471:
+		cx_clear(RDR_RDRCTL1, 1 << 8);
+		break;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 6835eb1..a80a92c 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -1173,6 +1173,13 @@
 			break;
 		}
 		break;
+	case CX23885_BOARD_TEVII_S471:
+		i2c_bus = &dev->i2c_bus[1];
+
+		fe0->dvb.frontend = dvb_attach(ds3000_attach,
+					&tevii_ds3000_config,
+					&i2c_bus->i2c_adap);
+		break;
 	default:
 		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
 			" isn't supported yet\n",
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index f020f05..d884784 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -89,6 +89,7 @@
 #define CX23885_BOARD_MPX885                   32
 #define CX23885_BOARD_MYGICA_X8507             33
 #define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
+#define CX23885_BOARD_TEVII_S471               35
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
index bb1ce34..c2bc39c 100644
--- a/drivers/media/video/cx23885/cx23888-ir.c
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -331,9 +331,7 @@
 
 static u16 pulse_clocks_to_clock_divider(u64 count)
 {
-	u32 rem;
-
-	rem = do_div(count, (FIFO_RXTX << 2) | 0x3);
+	do_div(count, (FIFO_RXTX << 2) | 0x3);
 
 	/* net result needs to be rounded down and decremented by 1 */
 	if (count > RXCLK_RCD + 1)
diff --git a/drivers/media/video/cx25821/cx25821-alsa.c b/drivers/media/video/cx25821/cx25821-alsa.c
index 03cfac4..1858a45d 100644
--- a/drivers/media/video/cx25821/cx25821-alsa.c
+++ b/drivers/media/video/cx25821/cx25821-alsa.c
@@ -290,11 +290,9 @@
 	u32 status, pci_status;
 	u32 audint_status, audint_mask;
 	int loop, handled = 0;
-	int audint_count = 0;
 
 	audint_status = cx_read(AUD_A_INT_STAT);
 	audint_mask = cx_read(AUD_A_INT_MSK);
-	audint_count = cx_read(AUD_A_GPCNT);
 	status = cx_read(PCI_INT_STAT);
 
 	for (loop = 0; loop < 1; loop++) {
diff --git a/drivers/media/video/cx25821/cx25821-audio-upstream.c b/drivers/media/video/cx25821/cx25821-audio-upstream.c
index 20c7ca3..8b2a999 100644
--- a/drivers/media/video/cx25821/cx25821-audio-upstream.c
+++ b/drivers/media/video/cx25821/cx25821-audio-upstream.c
@@ -585,7 +585,7 @@
 static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
 {
 	struct cx25821_dev *dev = dev_id;
-	u32 msk_stat, audio_status;
+	u32 audio_status;
 	int handled = 0;
 	struct sram_channel *sram_ch;
 
@@ -594,7 +594,6 @@
 
 	sram_ch = dev->channels[dev->_audio_upstream_channel].sram_channels;
 
-	msk_stat = cx_read(sram_ch->int_mstat);
 	audio_status = cx_read(sram_ch->int_stat);
 
 	/* Only deal with our interrupt */
diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c
index 7930ca5..83c1aa6 100644
--- a/drivers/media/video/cx25821/cx25821-core.c
+++ b/drivers/media/video/cx25821/cx25821-core.c
@@ -379,14 +379,6 @@
 	return cx_read(bus->reg_stat) & 0x01;
 }
 
-void cx_i2c_read_print(struct cx25821_dev *dev, u32 reg, const char *reg_string)
-{
-	int tmp = 0;
-	u32 value = 0;
-
-	value = cx25821_i2c_read(&dev->i2c_bus[0], reg, &tmp);
-}
-
 static void cx25821_registers_init(struct cx25821_dev *dev)
 {
 	u32 tmp;
@@ -895,7 +887,7 @@
 
 static int cx25821_dev_setup(struct cx25821_dev *dev)
 {
-	int io_size = 0, i;
+	int i;
 
 	pr_info("\n***********************************\n");
 	pr_info("cx25821 set up\n");
@@ -960,7 +952,6 @@
 
 	/* PCIe stuff */
 	dev->base_io_addr = pci_resource_start(dev->pci, 0);
-	io_size = pci_resource_len(dev->pci, 0);
 
 	if (!dev->base_io_addr) {
 		CX25821_ERR("No PCI Memory resources, exiting!\n");
@@ -1317,13 +1308,12 @@
 static irqreturn_t cx25821_irq(int irq, void *dev_id)
 {
 	struct cx25821_dev *dev = dev_id;
-	u32 pci_status, pci_mask;
+	u32 pci_status;
 	u32 vid_status;
 	int i, handled = 0;
 	u32 mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
 
 	pci_status = cx_read(PCI_INT_STAT);
-	pci_mask = cx_read(PCI_INT_MSK);
 
 	if (pci_status == 0)
 		goto out;
diff --git a/drivers/media/video/cx25821/cx25821-i2c.c b/drivers/media/video/cx25821/cx25821-i2c.c
index 12d7300..6311180 100644
--- a/drivers/media/video/cx25821/cx25821-i2c.c
+++ b/drivers/media/video/cx25821/cx25821-i2c.c
@@ -361,7 +361,6 @@
 int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value)
 {
 	struct i2c_client *client = &bus->i2c_client;
-	int retval = 0;
 	int v = 0;
 	u8 addr[2] = { 0, 0 };
 	u8 buf[4] = { 0, 0, 0, 0 };
@@ -385,7 +384,7 @@
 	msgs[0].addr = 0x44;
 	msgs[1].addr = 0x44;
 
-	retval = i2c_xfer(client->adapter, msgs, 2);
+	i2c_xfer(client->adapter, msgs, 2);
 
 	v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
 	*value = v;
diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.c b/drivers/media/video/cx25821/cx25821-medusa-video.c
index 298a68d..313fb20 100644
--- a/drivers/media/video/cx25821/cx25821-medusa-video.c
+++ b/drivers/media/video/cx25821/cx25821-medusa-video.c
@@ -35,7 +35,6 @@
 static void medusa_enable_bluefield_output(struct cx25821_dev *dev, int channel,
 					   int enable)
 {
-	int ret_val = 1;
 	u32 value = 0;
 	u32 tmp = 0;
 	int out_ctrl = OUT_CTRL1;
@@ -79,13 +78,13 @@
 	value &= 0xFFFFFF7F;	/* clear BLUE_FIELD_EN */
 	if (enable)
 		value |= 0x00000080;	/* set BLUE_FIELD_EN */
-	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl, value);
+	cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl, value);
 
 	value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl_ns, &tmp);
 	value &= 0xFFFFFF7F;
 	if (enable)
 		value |= 0x00000080;	/* set BLUE_FIELD_EN */
-	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl_ns, value);
+	cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl_ns, value);
 }
 
 static int medusa_initialize_ntsc(struct cx25821_dev *dev)
@@ -431,7 +430,6 @@
 {
 	int decoder = 0;
 	int decoder_count = 0;
-	int ret_val = 0;
 	u32 hscale = 0x0;
 	u32 vscale = 0x0;
 	const int MAX_WIDTH = 720;
@@ -482,9 +480,9 @@
 
 	for (; decoder < decoder_count; decoder++) {
 		/* write scaling values for each decoder */
-		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+		cx25821_i2c_write(&dev->i2c_bus[0],
 				HSCALE_CTRL + (0x200 * decoder), hscale);
-		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+		cx25821_i2c_write(&dev->i2c_bus[0],
 				VSCALE_CTRL + (0x200 * decoder), vscale);
 	}
 
@@ -494,7 +492,6 @@
 static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
 				       int duration)
 {
-	int ret_val = 0;
 	u32 fld_cnt = 0;
 	u32 tmp = 0;
 	u32 disp_cnt_reg = DISP_AB_CNT;
@@ -537,7 +534,7 @@
 		fld_cnt |= ((u32) duration) << 16;
 	}
 
-	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt);
+	cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt);
 
 	mutex_unlock(&dev->lock);
 }
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
index 5a157cf..c8c94fb 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
+++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
@@ -587,7 +587,7 @@
 static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
 {
 	struct cx25821_dev *dev = dev_id;
-	u32 msk_stat, vid_status;
+	u32 vid_status;
 	int handled = 0;
 	int channel_num = 0;
 	struct sram_channel *sram_ch;
@@ -598,7 +598,6 @@
 	channel_num = VID_UPSTREAM_SRAM_CHANNEL_J;
 	sram_ch = dev->channels[channel_num].sram_channels;
 
-	msk_stat = cx_read(sram_ch->int_mstat);
 	vid_status = cx_read(sram_ch->int_stat);
 
 	/* Only deal with our interrupt */
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream.c b/drivers/media/video/cx25821/cx25821-video-upstream.c
index 21e7d65..52c13e0 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream.c
+++ b/drivers/media/video/cx25821/cx25821-video-upstream.c
@@ -637,7 +637,7 @@
 static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
 {
 	struct cx25821_dev *dev = dev_id;
-	u32 msk_stat, vid_status;
+	u32 vid_status;
 	int handled = 0;
 	int channel_num = 0;
 	struct sram_channel *sram_ch;
@@ -649,7 +649,6 @@
 
 	sram_ch = dev->channels[channel_num].sram_channels;
 
-	msk_stat = cx_read(sram_ch->int_mstat);
 	vid_status = cx_read(sram_ch->int_stat);
 
 	/* Only deal with our interrupt */
diff --git a/drivers/media/video/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c
index ffd8bc7..b38d437 100644
--- a/drivers/media/video/cx25821/cx25821-video.c
+++ b/drivers/media/video/cx25821/cx25821-video.c
@@ -109,25 +109,6 @@
 	return NULL;
 }
 
-void cx25821_dump_video_queue(struct cx25821_dev *dev,
-			      struct cx25821_dmaqueue *q)
-{
-	struct cx25821_buffer *buf;
-	struct list_head *item;
-	dprintk(1, "%s()\n", __func__);
-
-	if (!list_empty(&q->active)) {
-		list_for_each(item, &q->active)
-			buf = list_entry(item, struct cx25821_buffer, vb.queue);
-	}
-
-	if (!list_empty(&q->queued)) {
-		list_for_each(item, &q->queued)
-			buf = list_entry(item, struct cx25821_buffer, vb.queue);
-	}
-
-}
-
 void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
 			  u32 count)
 {
@@ -557,7 +538,7 @@
 	struct cx25821_buffer *buf =
 		container_of(vb, struct cx25821_buffer, vb);
 	int rc, init_buffer = 0;
-	u32 line0_offset, line1_offset;
+	u32 line0_offset;
 	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
 	int bpl_local = LINE_SIZE_D1;
 	int channel_opened = fh->channel_id;
@@ -639,7 +620,6 @@
 		case V4L2_FIELD_INTERLACED:
 			/* All other formats are top field first */
 			line0_offset = 0;
-			line1_offset = buf->bpl;
 			dprintk(1, "top field first\n");
 
 			cx25821_risc_buffer(dev->pci, &buf->risc,
@@ -1830,7 +1810,6 @@
 	int i = 0;
 	int cif_enable = 0;
 	int cif_width = 0;
-	u32 value = 0;
 
 	data_from_user = (struct downstream_user_struct *)arg;
 
@@ -1914,7 +1893,7 @@
 		cx_write(data_from_user->reg_address, data_from_user->reg_data);
 		break;
 	case MEDUSA_READ:
-		value = cx25821_i2c_read(&dev->i2c_bus[0],
+		cx25821_i2c_read(&dev->i2c_bus[0],
 					 (u16) data_from_user->reg_address,
 					 &data_from_user->reg_data);
 		break;
diff --git a/drivers/media/video/cx25821/cx25821-video.h b/drivers/media/video/cx25821/cx25821-video.h
index d0d9538..9652a5e 100644
--- a/drivers/media/video/cx25821/cx25821-video.h
+++ b/drivers/media/video/cx25821/cx25821-video.h
@@ -86,8 +86,6 @@
 extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc);
 extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
 
-extern void cx25821_dump_video_queue(struct cx25821_dev *dev,
-				     struct cx25821_dmaqueue *q);
 extern void cx25821_video_wakeup(struct cx25821_dev *dev,
 				 struct cx25821_dmaqueue *q, u32 count);
 
diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c
index 13c380e..38ce76e 100644
--- a/drivers/media/video/cx25840/cx25840-ir.c
+++ b/drivers/media/video/cx25840/cx25840-ir.c
@@ -316,9 +316,7 @@
 
 static u16 pulse_clocks_to_clock_divider(u64 count)
 {
-	u32 rem;
-
-	rem = do_div(count, (FIFO_RXTX << 2) | 0x3);
+	do_div(count, (FIFO_RXTX << 2) | 0x3);
 
 	/* net result needs to be rounded down and decremented by 1 */
 	if (count > RXCLK_RCD + 1)
@@ -860,12 +858,10 @@
 			       ssize_t *num)
 {
 	struct cx25840_ir_state *ir_state = to_ir_state(sd);
-	struct i2c_client *c;
 
 	if (ir_state == NULL)
 		return -ENODEV;
 
-	c = ir_state->c;
 #if 0
 	/*
 	 * FIXME - the code below is an incomplete and untested sketch of what
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig
index 60a456e..9337b56 100644
--- a/drivers/media/video/davinci/Kconfig
+++ b/drivers/media/video/davinci/Kconfig
@@ -40,6 +40,7 @@
 config VIDEO_VPFE_CAPTURE
 	tristate "VPFE Video Capture Driver"
 	depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+	depends on I2C
 	select VIDEOBUF_DMA_CONTIG
 	help
 	  Support for DMx/AMx VPFE based frame grabber. This is the
diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c
index 1f3b1c7..e106b72 100644
--- a/drivers/media/video/davinci/vpbe_display.c
+++ b/drivers/media/video/davinci/vpbe_display.c
@@ -1618,6 +1618,10 @@
 	vbd->ioctl_ops	= &vpbe_ioctl_ops;
 	vbd->minor	= -1;
 	vbd->v4l2_dev   = &disp_dev->vpbe_dev->v4l2_dev;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vbd->flags);
 	vbd->lock	= &vpbe_display_layer->opslock;
 
 	if (disp_dev->vpbe_dev->current_timings.timings_type &
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index 20cf271..49a845f 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -1761,7 +1761,7 @@
 		}
 		break;
 	default:
-		ret = -EINVAL;
+		ret = -ENOTTY;
 	}
 unlock_out:
 	mutex_unlock(&vpfe_dev->lock);
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index 6504e40..9604695 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -2228,6 +2228,10 @@
 		common = &(ch->common[VPIF_VIDEO_INDEX]);
 		spin_lock_init(&common->irqlock);
 		mutex_init(&common->lock);
+		/* Locking in file operations other than ioctl should be done
+		   by the driver, not the V4L2 core.
+		   This driver needs auditing so that this flag can be removed. */
+		set_bit(V4L2_FL_LOCK_ALL_FOPS, &ch->video_dev->flags);
 		ch->video_dev->lock = &common->lock;
 		/* Initialize prio member of channel object */
 		v4l2_prio_init(&ch->prio);
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index 7fa34b4..e6488ee 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -1778,6 +1778,10 @@
 		v4l2_prio_init(&ch->prio);
 		ch->common[VPIF_VIDEO_INDEX].fmt.type =
 						V4L2_BUF_TYPE_VIDEO_OUTPUT;
+		/* Locking in file operations other than ioctl should be done
+		   by the driver, not the V4L2 core.
+		   This driver needs auditing so that this flag can be removed. */
+		set_bit(V4L2_FL_LOCK_ALL_FOPS, &ch->video_dev->flags);
 		ch->video_dev->lock = &common->lock;
 
 		/* register video device */
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index f6f622e..928ef0d 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -49,10 +49,10 @@
 	  Empiatech em28xx chips.
 
 config VIDEO_EM28XX_RC
-        bool "EM28XX Remote Controller support"
+        tristate "EM28XX Remote Controller support"
         depends on RC_CORE
         depends on VIDEO_EM28XX
         depends on !(RC_CORE=m && VIDEO_EM28XX=y)
-        default y
+        default VIDEO_EM28XX
         ---help---
           Enables Remote Controller support on em28xx driver.
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
index 2abdf76..c8b338d 100644
--- a/drivers/media/video/em28xx/Makefile
+++ b/drivers/media/video/em28xx/Makefile
@@ -1,16 +1,15 @@
 em28xx-y :=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
 em28xx-y +=	em28xx-core.o  em28xx-vbi.o
 
-em28xx-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-input.o
-
 em28xx-alsa-objs := em28xx-audio.o
+em28xx-rc-objs := em28xx-input.o
 
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
 obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
 obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
+obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
 
 ccflags-y += -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
 ccflags-y += -Idrivers/media/dvb/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
-
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index e2a7b77..d7e2a3d 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -343,7 +343,6 @@
 static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
 					struct snd_pcm_hw_params *hw_params)
 {
-	unsigned int channels, rate, format;
 	int ret;
 
 	dprintk("Setting capture parameters\n");
@@ -352,13 +351,17 @@
 				params_buffer_bytes(hw_params));
 	if (ret < 0)
 		return ret;
-	format = params_format(hw_params);
-	rate = params_rate(hw_params);
-	channels = params_channels(hw_params);
-
+#if 0
 	/* TODO: set up em28xx audio chip to deliver the correct audio format,
 	   current default is 48000hz multiplexed => 96000hz mono
 	   which shouldn't matter since analogue TV only supports mono */
+	unsigned int channels, rate, format;
+
+	format = params_format(hw_params);
+	rate = params_rate(hw_params);
+	channels = params_channels(hw_params);
+#endif
+
 	return 0;
 }
 
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 9fd8cc7..20a7e24 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -69,6 +69,8 @@
 	unsigned int  tuner;
 };
 
+static void em28xx_pre_card_setup(struct em28xx *dev);
+
 /*
  *  Reset sequences for analog/digital modes
  */
@@ -2361,7 +2363,7 @@
 /* Since em28xx_pre_card_setup() requires a proper dev->model,
  * this won't work for boards with generic PCI IDs
  */
-void em28xx_pre_card_setup(struct em28xx *dev)
+static void em28xx_pre_card_setup(struct em28xx *dev)
 {
 	/* Set the initial XCLK and I2C clock values based on the board
 	   definition */
@@ -2661,55 +2663,7 @@
 	return -1;
 }
 
-/* ----------------------------------------------------------------------- */
-void em28xx_register_i2c_ir(struct em28xx *dev)
-{
-	/* Leadtek winfast tv USBII deluxe can find a non working IR-device */
-	/* at address 0x18, so if that address is needed for another board in */
-	/* the future, please put it after 0x1f. */
-	struct i2c_board_info info;
-	const unsigned short addr_list[] = {
-		 0x1f, 0x30, 0x47, I2C_CLIENT_END
-	};
-
-	if (disable_ir)
-		return;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	memset(&dev->init_data, 0, sizeof(dev->init_data));
-	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-
-	/* detect & configure */
-	switch (dev->model) {
-	case EM2800_BOARD_TERRATEC_CINERGY_200:
-	case EM2820_BOARD_TERRATEC_CINERGY_250:
-		dev->init_data.ir_codes = RC_MAP_EM_TERRATEC;
-		dev->init_data.get_key = em28xx_get_key_terratec;
-		dev->init_data.name = "i2c IR (EM28XX Terratec)";
-		break;
-	case EM2820_BOARD_PINNACLE_USB_2:
-		dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
-		dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
-		dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
-		break;
-	case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
-		dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
-		dev->init_data.get_key = em28xx_get_key_em_haup;
-		dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
-		break;
-	case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
-		dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
-		dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
-		dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
-		break;
-	}
-
-	if (dev->init_data.name)
-		info.platform_data = &dev->init_data;
-	i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
-}
-
-void em28xx_card_setup(struct em28xx *dev)
+static void em28xx_card_setup(struct em28xx *dev)
 {
 	/*
 	 * If the device can be a webcam, seek for a sensor.
@@ -2849,13 +2803,6 @@
 		break;
 	}
 
-#if defined(CONFIG_MODULES) && defined(MODULE)
-	if (dev->board.has_ir_i2c && !disable_ir)
-		request_module("ir-kbd-i2c");
-#endif
-	if (dev->board.has_snapshot_button)
-		em28xx_register_snapshot_button(dev);
-
 	if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) {
 		em28xx_errdev("\n\n");
 		em28xx_errdev("The support for this board weren't "
@@ -2929,9 +2876,6 @@
 	}
 
 	em28xx_tuner_setup(dev);
-
-	if(!disable_ir)
-		em28xx_ir_init(dev);
 }
 
 
@@ -2948,6 +2892,8 @@
 
 	if (dev->board.has_dvb)
 		request_module("em28xx-dvb");
+	if (dev->board.has_ir_i2c && !disable_ir)
+		request_module("em28xx-rc");
 }
 
 static void request_modules(struct em28xx *dev)
@@ -2972,12 +2918,6 @@
 */
 void em28xx_release_resources(struct em28xx *dev)
 {
-	if (dev->sbutton_input_dev)
-		em28xx_deregister_snapshot_button(dev);
-
-	if (dev->ir)
-		em28xx_ir_fini(dev);
-
 	/*FIXME: I2C IR should be disconnected */
 
 	em28xx_release_analog_resources(dev);
@@ -3005,9 +2945,6 @@
 	dev->udev = udev;
 	mutex_init(&dev->ctrl_urb_lock);
 	spin_lock_init(&dev->slock);
-	init_waitqueue_head(&dev->open);
-	init_waitqueue_head(&dev->wait_frame);
-	init_waitqueue_head(&dev->wait_stream);
 
 	dev->em28xx_write_regs = em28xx_write_regs;
 	dev->em28xx_read_reg = em28xx_read_reg;
@@ -3140,9 +3077,7 @@
 
 	/* init video dma queues */
 	INIT_LIST_HEAD(&dev->vidq.active);
-	INIT_LIST_HEAD(&dev->vidq.queued);
 	INIT_LIST_HEAD(&dev->vbiq.active);
-	INIT_LIST_HEAD(&dev->vbiq.queued);
 
 	if (dev->board.has_msp34xx) {
 		/* Send a reset to other chips via gpio */
@@ -3447,8 +3382,6 @@
 	   resources */
 	mutex_lock(&dev->lock);
 
-	wake_up_interruptible_all(&dev->open);
-
 	v4l2_device_disconnect(&dev->v4l2_dev);
 
 	if (dev->users) {
@@ -3460,8 +3393,6 @@
 		dev->state |= DEV_MISCONFIGURED;
 		em28xx_uninit_isoc(dev, dev->mode);
 		dev->state |= DEV_DISCONNECTED;
-		wake_up_interruptible(&dev->wait_frame);
-		wake_up_interruptible(&dev->wait_stream);
 	} else {
 		dev->state |= DEV_DISCONNECTED;
 		em28xx_release_resources(dev);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 53a9fb9..5717bde 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -139,6 +139,7 @@
 {
 	return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);
 }
+EXPORT_SYMBOL_GPL(em28xx_read_reg);
 
 /*
  * em28xx_write_regs_req()
@@ -205,6 +206,7 @@
 
 	return rc;
 }
+EXPORT_SYMBOL_GPL(em28xx_write_regs);
 
 /* Write a single register */
 int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val)
@@ -239,6 +241,7 @@
 
 	return em28xx_write_regs(dev, reg, &newval, 1);
 }
+EXPORT_SYMBOL_GPL(em28xx_write_reg_bits);
 
 /*
  * em28xx_is_ac97_ready()
@@ -666,7 +669,6 @@
 
 	return rc;
 }
-EXPORT_SYMBOL_GPL(em28xx_capture_start);
 
 int em28xx_vbi_supported(struct em28xx *dev)
 {
@@ -975,7 +977,6 @@
 	else
 		isoc_bufs = &dev->isoc_ctl.analog_bufs;
 
-	dev->isoc_ctl.nfields = -1;
 	for (i = 0; i < isoc_bufs->num_bufs; i++) {
 		urb = isoc_bufs->urb[i];
 		if (urb) {
@@ -1008,6 +1009,31 @@
 EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
 
 /*
+ * Stop URBs
+ */
+void em28xx_stop_urbs(struct em28xx *dev)
+{
+	int i;
+	struct urb *urb;
+	struct em28xx_usb_isoc_bufs *isoc_bufs = &dev->isoc_ctl.digital_bufs;
+
+	em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n");
+
+	for (i = 0; i < isoc_bufs->num_bufs; i++) {
+		urb = isoc_bufs->urb[i];
+		if (urb) {
+			if (!irqs_disabled())
+				usb_kill_urb(urb);
+			else
+				usb_unlink_urb(urb);
+		}
+	}
+
+	em28xx_capture_start(dev, 0);
+}
+EXPORT_SYMBOL_GPL(em28xx_stop_urbs);
+
+/*
  * Allocate URBs
  */
 int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 503a8d5..16410ac 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -183,7 +183,7 @@
 {
 	struct em28xx *dev = dvb->adapter.priv;
 
-	em28xx_capture_start(dev, 0);
+	em28xx_stop_urbs(dev);
 
 	em28xx_set_mode(dev, EM28XX_SUSPEND);
 
@@ -336,6 +336,8 @@
 	.single_master = 1,
 	.microcode_name = "dvb-demod-drxk-pctv.fw",
 	.chunk_size = 58,
+	.antenna_dvbt = true, /* disable LNA */
+	.antenna_gpio = (1 << 2), /* disable LNA */
 };
 
 static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
@@ -474,8 +476,8 @@
 static void pctv_520e_init(struct em28xx *dev)
 {
 	/*
-	 * Init TDA8295(?) analog demodulator. Looks like I2C traffic to
-	 * digital demodulator and tuner are routed via TDA8295.
+	 * Init AVF4910B analog decoder. Looks like I2C traffic to
+	 * digital demodulator and tuner are routed via AVF4910B.
 	 */
 	int i;
 	struct {
@@ -542,7 +544,8 @@
 	.i2c_address = (0xd8 >> 1),
 	.ts_mode = CXD2820R_TS_SERIAL,
 
-	/* enable LNA for DVB-T2 and DVB-C */
+	/* enable LNA for DVB-T, DVB-T2 and DVB-C */
+	.gpio_dvbt[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
 	.gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
 	.gpio_dvbc[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
 };
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index a88e169..185db65 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -553,9 +553,6 @@
 	if (i2c_scan)
 		em28xx_do_i2c_scan(dev);
 
-	/* Instantiate the IR receiver device, if present */
-	em28xx_register_i2c_ir(dev);
-
 	return 0;
 }
 
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 2630b26..fce5f76 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -80,7 +80,7 @@
  I2C IR based get keycodes - should be used with ir-kbd-i2c
  **********************************************************/
 
-int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char b;
 
@@ -108,7 +108,7 @@
 	return 1;
 }
 
-int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char buf[2];
 	u16 code;
@@ -157,7 +157,7 @@
 	return 1;
 }
 
-int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
+static int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
 				     u32 *ir_raw)
 {
 	unsigned char buf[3];
@@ -179,7 +179,8 @@
 	return 1;
 }
 
-int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key,
+					u32 *ir_raw)
 {
 	unsigned char subaddr, keydetect, key;
 
@@ -387,7 +388,138 @@
 	return rc;
 }
 
-int em28xx_ir_init(struct em28xx *dev)
+static void em28xx_register_i2c_ir(struct em28xx *dev)
+{
+	/* Leadtek winfast tv USBII deluxe can find a non working IR-device */
+	/* at address 0x18, so if that address is needed for another board in */
+	/* the future, please put it after 0x1f. */
+	struct i2c_board_info info;
+	const unsigned short addr_list[] = {
+		 0x1f, 0x30, 0x47, I2C_CLIENT_END
+	};
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	memset(&dev->init_data, 0, sizeof(dev->init_data));
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+	/* detect & configure */
+	switch (dev->model) {
+	case EM2800_BOARD_TERRATEC_CINERGY_200:
+	case EM2820_BOARD_TERRATEC_CINERGY_250:
+		dev->init_data.ir_codes = RC_MAP_EM_TERRATEC;
+		dev->init_data.get_key = em28xx_get_key_terratec;
+		dev->init_data.name = "i2c IR (EM28XX Terratec)";
+		break;
+	case EM2820_BOARD_PINNACLE_USB_2:
+		dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
+		dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
+		dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
+		break;
+	case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+		dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
+		dev->init_data.get_key = em28xx_get_key_em_haup;
+		dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
+		break;
+	case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
+		dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
+		dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
+		dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
+		break;
+	}
+
+	if (dev->init_data.name)
+		info.platform_data = &dev->init_data;
+	i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
+}
+
+/**********************************************************
+ Handle Webcam snapshot button
+ **********************************************************/
+
+static void em28xx_query_sbutton(struct work_struct *work)
+{
+	/* Poll the register and see if the button is depressed */
+	struct em28xx *dev =
+		container_of(work, struct em28xx, sbutton_query_work.work);
+	int ret;
+
+	ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP);
+
+	if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) {
+		u8 cleared;
+		/* Button is depressed, clear the register */
+		cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT;
+		em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1);
+
+		/* Not emulate the keypress */
+		input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
+				 1);
+		/* Now unpress the key */
+		input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
+				 0);
+	}
+
+	/* Schedule next poll */
+	schedule_delayed_work(&dev->sbutton_query_work,
+			      msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+}
+
+static void em28xx_register_snapshot_button(struct em28xx *dev)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	em28xx_info("Registering snapshot button...\n");
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		em28xx_errdev("input_allocate_device failed\n");
+		return;
+	}
+
+	usb_make_path(dev->udev, dev->snapshot_button_path,
+		      sizeof(dev->snapshot_button_path));
+	strlcat(dev->snapshot_button_path, "/sbutton",
+		sizeof(dev->snapshot_button_path));
+	INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
+
+	input_dev->name = "em28xx snapshot button";
+	input_dev->phys = dev->snapshot_button_path;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+	set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
+	input_dev->keycodesize = 0;
+	input_dev->keycodemax = 0;
+	input_dev->id.bustype = BUS_USB;
+	input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+	input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+	input_dev->id.version = 1;
+	input_dev->dev.parent = &dev->udev->dev;
+
+	err = input_register_device(input_dev);
+	if (err) {
+		em28xx_errdev("input_register_device failed\n");
+		input_free_device(input_dev);
+		return;
+	}
+
+	dev->sbutton_input_dev = input_dev;
+	schedule_delayed_work(&dev->sbutton_query_work,
+			      msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+	return;
+
+}
+
+static void em28xx_deregister_snapshot_button(struct em28xx *dev)
+{
+	if (dev->sbutton_input_dev != NULL) {
+		em28xx_info("Deregistering snapshot button\n");
+		cancel_delayed_work_sync(&dev->sbutton_query_work);
+		input_unregister_device(dev->sbutton_input_dev);
+		dev->sbutton_input_dev = NULL;
+	}
+	return;
+}
+
+static int em28xx_ir_init(struct em28xx *dev)
 {
 	struct em28xx_IR *ir;
 	struct rc_dev *rc;
@@ -448,6 +580,15 @@
 	if (err)
 		goto err_out_stop;
 
+	em28xx_register_i2c_ir(dev);
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+	if (dev->board.has_ir_i2c)
+		request_module("ir-kbd-i2c");
+#endif
+	if (dev->board.has_snapshot_button)
+		em28xx_register_snapshot_button(dev);
+
 	return 0;
 
  err_out_stop:
@@ -458,10 +599,12 @@
 	return err;
 }
 
-int em28xx_ir_fini(struct em28xx *dev)
+static int em28xx_ir_fini(struct em28xx *dev)
 {
 	struct em28xx_IR *ir = dev->ir;
 
+	em28xx_deregister_snapshot_button(dev);
+
 	/* skip detach on non attached boards */
 	if (!ir)
 		return 0;
@@ -475,89 +618,26 @@
 	return 0;
 }
 
-/**********************************************************
- Handle Webcam snapshot button
- **********************************************************/
+static struct em28xx_ops rc_ops = {
+	.id   = EM28XX_RC,
+	.name = "Em28xx Input Extension",
+	.init = em28xx_ir_init,
+	.fini = em28xx_ir_fini,
+};
 
-static void em28xx_query_sbutton(struct work_struct *work)
+static int __init em28xx_rc_register(void)
 {
-	/* Poll the register and see if the button is depressed */
-	struct em28xx *dev =
-		container_of(work, struct em28xx, sbutton_query_work.work);
-	int ret;
-
-	ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP);
-
-	if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) {
-		u8 cleared;
-		/* Button is depressed, clear the register */
-		cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT;
-		em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1);
-
-		/* Not emulate the keypress */
-		input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
-				 1);
-		/* Now unpress the key */
-		input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
-				 0);
-	}
-
-	/* Schedule next poll */
-	schedule_delayed_work(&dev->sbutton_query_work,
-			      msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+	return em28xx_register_extension(&rc_ops);
 }
 
-void em28xx_register_snapshot_button(struct em28xx *dev)
+static void __exit em28xx_rc_unregister(void)
 {
-	struct input_dev *input_dev;
-	int err;
-
-	em28xx_info("Registering snapshot button...\n");
-	input_dev = input_allocate_device();
-	if (!input_dev) {
-		em28xx_errdev("input_allocate_device failed\n");
-		return;
-	}
-
-	usb_make_path(dev->udev, dev->snapshot_button_path,
-		      sizeof(dev->snapshot_button_path));
-	strlcat(dev->snapshot_button_path, "/sbutton",
-		sizeof(dev->snapshot_button_path));
-	INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
-
-	input_dev->name = "em28xx snapshot button";
-	input_dev->phys = dev->snapshot_button_path;
-	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-	set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
-	input_dev->keycodesize = 0;
-	input_dev->keycodemax = 0;
-	input_dev->id.bustype = BUS_USB;
-	input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
-	input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
-	input_dev->id.version = 1;
-	input_dev->dev.parent = &dev->udev->dev;
-
-	err = input_register_device(input_dev);
-	if (err) {
-		em28xx_errdev("input_register_device failed\n");
-		input_free_device(input_dev);
-		return;
-	}
-
-	dev->sbutton_input_dev = input_dev;
-	schedule_delayed_work(&dev->sbutton_query_work,
-			      msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
-	return;
-
+	em28xx_unregister_extension(&rc_ops);
 }
 
-void em28xx_deregister_snapshot_button(struct em28xx *dev)
-{
-	if (dev->sbutton_input_dev != NULL) {
-		em28xx_info("Deregistering snapshot button\n");
-		cancel_delayed_work_sync(&dev->sbutton_query_work);
-		input_unregister_device(dev->sbutton_input_dev);
-		dev->sbutton_input_dev = NULL;
-	}
-	return;
-}
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("Em28xx Input driver");
+
+module_init(em28xx_rc_register);
+module_exit(em28xx_rc_unregister);
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 324b695..50f5f4f 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1305,9 +1305,7 @@
 	if (0 == INPUT(i)->type)
 		return -EINVAL;
 
-	dev->ctl_input = i;
-
-	video_mux(dev, dev->ctl_input);
+	video_mux(dev, i);
 	return 0;
 }
 
@@ -2262,6 +2260,7 @@
 			em28xx_release_resources(dev);
 			kfree(dev->alt_max_pkt_size);
 			kfree(dev);
+			kfree(fh);
 			return 0;
 		}
 
@@ -2286,7 +2285,6 @@
 	videobuf_mmap_free(&fh->vb_vbiq);
 	kfree(fh);
 	dev->users--;
-	wake_up_interruptible_nr(&dev->open, 1);
 	return 0;
 }
 
@@ -2497,6 +2495,10 @@
 	vfd->release	= video_device_release;
 	vfd->debug	= video_debug;
 	vfd->lock	= &dev->lock;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s",
 		 dev->name, type_name);
@@ -2518,7 +2520,6 @@
 	dev->norm = em28xx_video_template.current_norm;
 	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
 	dev->interlaced = EM28XX_INTERLACED_DEFAULT;
-	dev->ctl_input = 0;
 
 	/* Analog specific initialization */
 	dev->format = &format[0];
@@ -2532,7 +2533,7 @@
 	em28xx_set_video_format(dev, format[0].fourcc,
 				maxw, norm_maxh(dev));
 
-	video_mux(dev, dev->ctl_input);
+	video_mux(dev, 0);
 
 	/* Audio defaults */
 	dev->mute = 1;
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 2868b19..8757523 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -226,24 +226,10 @@
 		/* isoc transfer buffers for digital mode */
 	struct em28xx_usb_isoc_bufs	digital_bufs;
 
-		/* Last buffer command and region */
-	u8				cmd;
-	int				pos, size, pktsize;
-
-		/* Last field: ODD or EVEN? */
-	int				field;
-
-		/* Stores incomplete commands */
-	u32				tmp_buf;
-	int				tmp_buf_len;
-
 		/* Stores already requested buffers */
 	struct em28xx_buffer    	*vid_buf;
 	struct em28xx_buffer    	*vbi_buf;
 
-		/* Stores the number of received fields */
-	int				nfields;
-
 		/* isoc urb callback */
 	int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
 
@@ -264,12 +250,10 @@
 
 	struct list_head frame;
 	int top_field;
-	int receiving;
 };
 
 struct em28xx_dmaqueue {
 	struct list_head       active;
-	struct list_head       queued;
 
 	wait_queue_head_t          wq;
 
@@ -277,13 +261,6 @@
 	int                        pos;
 };
 
-/* io methods */
-enum em28xx_io_method {
-	IO_NONE,
-	IO_READ,
-	IO_MMAP,
-};
-
 /* inputs */
 
 #define MAX_EM28XX_INPUT 4
@@ -467,6 +444,7 @@
 /* em28xx extensions */
 #define EM28XX_AUDIO   0x10
 #define EM28XX_DVB     0x20
+#define EM28XX_RC      0x30
 
 /* em28xx resource types (used for res_get/res_lock etc */
 #define EM28XX_RESOURCE_VIDEO 0x01
@@ -577,7 +555,6 @@
 
 	/* states */
 	enum em28xx_dev_state state;
-	enum em28xx_io_method io;
 
 	/* vbi related state tracking */
 	int capture_type;
@@ -593,7 +570,6 @@
 	struct mutex ctrl_urb_lock;	/* protects urb_buf */
 	/* spinlock_t queue_lock; */
 	struct list_head inqueue, outqueue;
-	wait_queue_head_t open, wait_frame, wait_stream;
 	struct video_device *vbi_dev;
 	struct video_device *radio_dev;
 
@@ -695,6 +671,7 @@
 		     int max_packets, int num_bufs, int max_pkt_size,
 		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
 void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode);
+void em28xx_stop_urbs(struct em28xx *dev);
 int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
@@ -710,45 +687,12 @@
 
 /* Provided by em28xx-cards.c */
 extern int em2800_variant_detect(struct usb_device *udev, int model);
-extern void em28xx_pre_card_setup(struct em28xx *dev);
-extern void em28xx_card_setup(struct em28xx *dev);
 extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
-void em28xx_register_i2c_ir(struct em28xx *dev);
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_release_resources(struct em28xx *dev);
 
-/* Provided by em28xx-input.c */
-
-#ifdef CONFIG_VIDEO_EM28XX_RC
-
-int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
-int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
-int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
-				     u32 *ir_raw);
-int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key,
-				     u32 *ir_raw);
-void em28xx_register_snapshot_button(struct em28xx *dev);
-void em28xx_deregister_snapshot_button(struct em28xx *dev);
-
-int em28xx_ir_init(struct em28xx *dev);
-int em28xx_ir_fini(struct em28xx *dev);
-
-#else
-
-#define em28xx_get_key_terratec			NULL
-#define em28xx_get_key_em_haup			NULL
-#define em28xx_get_key_pinnacle_usb_grey	NULL
-#define em28xx_get_key_winfast_usbii_deluxe	NULL
-
-static inline void em28xx_register_snapshot_button(struct em28xx *dev) {}
-static inline void em28xx_deregister_snapshot_button(struct em28xx *dev) {}
-static inline int em28xx_ir_init(struct em28xx *dev) { return 0; }
-static inline int em28xx_ir_fini(struct em28xx *dev) { return 0; }
-
-#endif
-
 /* Provided by em28xx-vbi.c */
 extern struct videobuf_queue_ops em28xx_vbi_qops;
 
diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig
deleted file mode 100644
index 87981b0..0000000
--- a/drivers/media/video/et61x251/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-config USB_ET61X251
-	tristate "USB ET61X[12]51 PC Camera Controller support (DEPRECATED)"
-	depends on VIDEO_V4L2
-	default n
-	---help---
-	  This driver is DEPRECATED please use the gspca zc3xx module
-	  instead.
-
-	  Say Y here if you want support for cameras based on Etoms ET61X151
-	  or ET61X251 PC Camera Controllers.
-
-	  See <file:Documentation/video4linux/et61x251.txt> for more info.
-
-	  This driver uses the Video For Linux API. You must say Y or M to
-	  "Video For Linux" to use this driver.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called et61x251.
diff --git a/drivers/media/video/et61x251/Makefile b/drivers/media/video/et61x251/Makefile
deleted file mode 100644
index 2ff4db9..0000000
--- a/drivers/media/video/et61x251/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-et61x251-objs   := et61x251_core.o et61x251_tas5130d1b.o
-
-obj-$(CONFIG_USB_ET61X251)      += et61x251.o
-
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
deleted file mode 100644
index 337ded4..0000000
--- a/drivers/media/video/et61x251/et61x251.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ET61X251_H_
-#define _ET61X251_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/kref.h>
-
-#include "et61x251_sensor.h"
-
-/*****************************************************************************/
-
-#define ET61X251_DEBUG
-#define ET61X251_DEBUG_LEVEL         2
-#define ET61X251_MAX_DEVICES         64
-#define ET61X251_PRESERVE_IMGSCALE   0
-#define ET61X251_FORCE_MUNMAP        0
-#define ET61X251_MAX_FRAMES          32
-#define ET61X251_COMPRESSION_QUALITY 0
-#define ET61X251_URBS                2
-#define ET61X251_ISO_PACKETS         7
-#define ET61X251_ALTERNATE_SETTING   13
-#define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
-#define ET61X251_CTRL_TIMEOUT        100
-#define ET61X251_FRAME_TIMEOUT       2
-
-/*****************************************************************************/
-
-static const struct usb_device_id et61x251_id_table[] = {
-	{ USB_DEVICE(0x102c, 0x6251), },
-	{ }
-};
-
-ET61X251_SENSOR_TABLE
-
-/*****************************************************************************/
-
-enum et61x251_frame_state {
-	F_UNUSED,
-	F_QUEUED,
-	F_GRABBING,
-	F_DONE,
-	F_ERROR,
-};
-
-struct et61x251_frame_t {
-	void* bufmem;
-	struct v4l2_buffer buf;
-	enum et61x251_frame_state state;
-	struct list_head frame;
-	unsigned long vma_use_count;
-};
-
-enum et61x251_dev_state {
-	DEV_INITIALIZED = 0x01,
-	DEV_DISCONNECTED = 0x02,
-	DEV_MISCONFIGURED = 0x04,
-};
-
-enum et61x251_io_method {
-	IO_NONE,
-	IO_READ,
-	IO_MMAP,
-};
-
-enum et61x251_stream_state {
-	STREAM_OFF,
-	STREAM_INTERRUPT,
-	STREAM_ON,
-};
-
-struct et61x251_sysfs_attr {
-	u8 reg, i2c_reg;
-};
-
-struct et61x251_module_param {
-	u8 force_munmap;
-	u16 frame_timeout;
-};
-
-static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_dev_lock);
-
-struct et61x251_device {
-	struct video_device* v4ldev;
-
-	struct et61x251_sensor sensor;
-
-	struct usb_device* usbdev;
-	struct urb* urb[ET61X251_URBS];
-	void* transfer_buffer[ET61X251_URBS];
-	u8* control_buffer;
-
-	struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES];
-	struct list_head inqueue, outqueue;
-	u32 frame_count, nbuffers, nreadbuffers;
-
-	enum et61x251_io_method io;
-	enum et61x251_stream_state stream;
-
-	struct v4l2_jpegcompression compression;
-
-	struct et61x251_sysfs_attr sysfs;
-	struct et61x251_module_param module_param;
-
-	struct kref kref;
-	enum et61x251_dev_state state;
-	u8 users;
-
-	struct completion probe;
-	struct mutex open_mutex, fileop_mutex;
-	spinlock_t queue_lock;
-	wait_queue_head_t wait_open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct et61x251_device*
-et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
-{
-	return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
-}
-
-
-void
-et61x251_attach_sensor(struct et61x251_device* cam,
-		       const struct et61x251_sensor* sensor)
-{
-	memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ET61X251_DEBUG
-#define DBG(level, fmt, ...)						\
-do {									\
-	if (debug >= (level)) {						\
-		if ((level) == 1)					\
-			dev_err(&cam->usbdev->dev, fmt "\n",		\
-				##__VA_ARGS__);				\
-		else if ((level) == 2)					\
-			dev_info(&cam->usbdev->dev, fmt "\n",		\
-				 ##__VA_ARGS__);			\
-		else if ((level) >= 3)					\
-			dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
-				 __FILE__, __func__, __LINE__,		\
-				 ##__VA_ARGS__);			\
-	}								\
-} while (0)
-#define KDBG(level, fmt, ...)						\
-do {									\
-	if (debug >= (level)) {						\
-		if ((level) == 1 || (level) == 2)			\
-			pr_info(fmt "\n", ##__VA_ARGS__);		\
-		else if ((level) == 3)					\
-			pr_debug("[%s:%s:%d] " fmt "\n",		\
-				 __FILE__,  __func__, __LINE__,		\
-				 ##__VA_ARGS__);			\
-	}								\
-} while (0)
-#define V4LDBG(level, name, cmd)					\
-do {									\
-	if (debug >= (level))						\
-		v4l_print_ioctl(name, cmd);				\
-} while (0)
-#else
-#define DBG(level, fmt, ...) do {;} while(0)
-#define KDBG(level, fmt, ...) do {;} while(0)
-#define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, ...)							\
-	dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",		\
-		 __FILE__, __func__, __LINE__, ##__VA_ARGS__)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while (0) /* placeholder */
-
-#endif /* _ET61X251_H_ */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
deleted file mode 100644
index 5539f09..0000000
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ /dev/null
@@ -1,2683 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <media/v4l2-ioctl.h>
-#include <asm/byteorder.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "et61x251.h"
-
-/*****************************************************************************/
-
-#define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
-				"PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
-#define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
-#define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1.1.10"
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, et61x251_id_table);
-
-MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ET61X251_MODULE_NAME);
-MODULE_VERSION(ET61X251_MODULE_VERSION);
-MODULE_LICENSE(ET61X251_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
-		 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-		 "\n -1 = use next available (default)"
-		 "\n  n = use minor number n (integer >= 0)"
-		 "\nYou can specify up to "
-		 __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way."
-		 "\nFor example:"
-		 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-		 "\nthe second registered camera and use auto for the first"
-		 "\none and for every other camera."
-		 "\n");
-
-static bool force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
-			      ET61X251_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
-		 "\n<0|1[,...]> Force the application to unmap previously"
-		 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-		 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-		 "\nthis feature. This parameter is specific for each"
-		 "\ndetected camera."
-		 "\n 0 = do not force memory unmapping"
-		 "\n 1 = force memory unmapping (save memory)"
-		 "\nDefault value is "__MODULE_STRING(ET61X251_FORCE_MUNMAP)"."
-		 "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
-				       ET61X251_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
-		 "\n<n[,...]> Timeout for a video frame in seconds."
-		 "\nThis parameter is specific for each detected camera."
-		 "\nDefault value is "
-		 __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."
-		 "\n");
-
-#ifdef ET61X251_DEBUG
-static unsigned short debug = ET61X251_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
-		 "\n<n> Debugging information level, from 0 to 3:"
-		 "\n0 = none (use carefully)"
-		 "\n1 = critical errors"
-		 "\n2 = significant informations"
-		 "\n3 = more verbose messages"
-		 "\nLevel 3 is useful for testing only, when only "
-		 "one device is used."
-		 "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"."
-		 "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-et61x251_request_buffers(struct et61x251_device* cam, u32 count,
-			 enum et61x251_io_method io)
-{
-	struct v4l2_pix_format* p = &(cam->sensor.pix_format);
-	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-	const size_t imagesize = cam->module_param.force_munmap ||
-				 io == IO_READ ?
-				 (p->width * p->height * p->priv) / 8 :
-				 (r->width * r->height * p->priv) / 8;
-	void* buff = NULL;
-	u32 i;
-
-	if (count > ET61X251_MAX_FRAMES)
-		count = ET61X251_MAX_FRAMES;
-
-	cam->nbuffers = count;
-	while (cam->nbuffers > 0) {
-		if ((buff = vmalloc_32_user(cam->nbuffers *
-					    PAGE_ALIGN(imagesize))))
-			break;
-		cam->nbuffers--;
-	}
-
-	for (i = 0; i < cam->nbuffers; i++) {
-		cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
-		cam->frame[i].buf.index = i;
-		cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
-		cam->frame[i].buf.length = imagesize;
-		cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		cam->frame[i].buf.sequence = 0;
-		cam->frame[i].buf.field = V4L2_FIELD_NONE;
-		cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-		cam->frame[i].buf.flags = 0;
-	}
-
-	return cam->nbuffers;
-}
-
-
-static void et61x251_release_buffers(struct et61x251_device* cam)
-{
-	if (cam->nbuffers) {
-		vfree(cam->frame[0].bufmem);
-		cam->nbuffers = 0;
-	}
-	cam->frame_current = NULL;
-}
-
-
-static void et61x251_empty_framequeues(struct et61x251_device* cam)
-{
-	u32 i;
-
-	INIT_LIST_HEAD(&cam->inqueue);
-	INIT_LIST_HEAD(&cam->outqueue);
-
-	for (i = 0; i < ET61X251_MAX_FRAMES; i++) {
-		cam->frame[i].state = F_UNUSED;
-		cam->frame[i].buf.bytesused = 0;
-	}
-}
-
-
-static void et61x251_requeue_outqueue(struct et61x251_device* cam)
-{
-	struct et61x251_frame_t *i;
-
-	list_for_each_entry(i, &cam->outqueue, frame) {
-		i->state = F_QUEUED;
-		list_add(&i->frame, &cam->inqueue);
-	}
-
-	INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void et61x251_queue_unusedframes(struct et61x251_device* cam)
-{
-	unsigned long lock_flags;
-	u32 i;
-
-	for (i = 0; i < cam->nbuffers; i++)
-		if (cam->frame[i].state == F_UNUSED) {
-			cam->frame[i].state = F_QUEUED;
-			spin_lock_irqsave(&cam->queue_lock, lock_flags);
-			list_add_tail(&cam->frame[i].frame, &cam->inqueue);
-			spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-		}
-}
-
-/*****************************************************************************/
-
-int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
-{
-	struct usb_device* udev = cam->usbdev;
-	u8* buff = cam->control_buffer;
-	int res;
-
-	*buff = value;
-
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-			      0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
-	if (res < 0) {
-		DBG(3, "Failed to write a register (value 0x%02X, index "
-		       "0x%02X, error %d)", value, index, res);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int et61x251_read_reg(struct et61x251_device* cam, u16 index)
-{
-	struct usb_device* udev = cam->usbdev;
-	u8* buff = cam->control_buffer;
-	int res;
-
-	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-			      0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		DBG(3, "Failed to read a register (index 0x%02X, error %d)",
-		    index, res);
-
-	return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-static int
-et61x251_i2c_wait(struct et61x251_device* cam,
-		  const struct et61x251_sensor* sensor)
-{
-	int i, r;
-
-	for (i = 1; i <= 8; i++) {
-		if (sensor->interface == ET61X251_I2C_3WIRES) {
-			r = et61x251_read_reg(cam, 0x8e);
-			if (!(r & 0x02) && (r >= 0))
-				return 0;
-		} else {
-			r = et61x251_read_reg(cam, 0x8b);
-			if (!(r & 0x01) && (r >= 0))
-				return 0;
-		}
-		if (r < 0)
-			return -EIO;
-		udelay(8*8); /* minimum for sensors at 400kHz */
-	}
-
-	return -EBUSY;
-}
-
-
-int
-et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
-		       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
-		       u8 data8, u8 address)
-{
-	struct usb_device* udev = cam->usbdev;
-	u8* data = cam->control_buffer;
-	int err = 0, res;
-
-	data[0] = data2;
-	data[1] = data3;
-	data[2] = data4;
-	data[3] = data5;
-	data[4] = data6;
-	data[5] = data7;
-	data[6] = data8;
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-			      0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		err += res;
-
-	data[0] = address;
-	data[1] = cam->sensor.i2c_slave_id;
-	data[2] = cam->sensor.rsta | 0x02 | (n << 4);
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-			      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		err += res;
-
-	/* Start writing through the serial interface */
-	data[0] = data1;
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		err += res;
-
-	err += et61x251_i2c_wait(cam, &cam->sensor);
-
-	if (err)
-		DBG(3, "I2C raw write failed for %s image sensor",
-		    cam->sensor.name);
-
-	PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
-	      "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
-	      " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address,
-	      data1, data2, data3, data4, data5, data6, data7, data8);
-
-	return err ? -1 : 0;
-
-}
-
-
-/*****************************************************************************/
-
-static void et61x251_urb_complete(struct urb *urb)
-{
-	struct et61x251_device* cam = urb->context;
-	struct et61x251_frame_t** f;
-	size_t imagesize;
-	u8 i;
-	int err = 0;
-
-	if (urb->status == -ENOENT)
-		return;
-
-	f = &cam->frame_current;
-
-	if (cam->stream == STREAM_INTERRUPT) {
-		cam->stream = STREAM_OFF;
-		if ((*f))
-			(*f)->state = F_QUEUED;
-		DBG(3, "Stream interrupted");
-		wake_up(&cam->wait_stream);
-	}
-
-	if (cam->state & DEV_DISCONNECTED)
-		return;
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		wake_up_interruptible(&cam->wait_frame);
-		return;
-	}
-
-	if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
-		goto resubmit_urb;
-
-	if (!(*f))
-		(*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
-				  frame);
-
-	imagesize = (cam->sensor.pix_format.width *
-		     cam->sensor.pix_format.height *
-		     cam->sensor.pix_format.priv) / 8;
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		unsigned int len, status;
-		void *pos;
-		u8* b1, * b2, sof;
-		const u8 VOID_BYTES = 6;
-		size_t imglen;
-
-		len = urb->iso_frame_desc[i].actual_length;
-		status = urb->iso_frame_desc[i].status;
-		pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-		if (status) {
-			DBG(3, "Error in isochronous frame");
-			(*f)->state = F_ERROR;
-			continue;
-		}
-
-		b1 = pos++;
-		b2 = pos++;
-		sof = ((*b1 & 0x3f) == 63);
-		imglen = ((*b1 & 0xc0) << 2) | *b2;
-
-		PDBGG("Isochrnous frame: length %u, #%u i, image length %zu",
-		      len, i, imglen);
-
-		if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
-			if (sof) {
-				(*f)->state = F_GRABBING;
-				(*f)->buf.bytesused = 0;
-				do_gettimeofday(&(*f)->buf.timestamp);
-				pos += 22;
-				DBG(3, "SOF detected: new video frame");
-			}
-
-		if ((*f)->state == F_GRABBING) {
-			if (sof && (*f)->buf.bytesused) {
-				if (cam->sensor.pix_format.pixelformat ==
-							 V4L2_PIX_FMT_ET61X251)
-					goto end_of_frame;
-				else {
-					DBG(3, "Not expected SOF detected "
-					       "after %lu bytes",
-					   (unsigned long)(*f)->buf.bytesused);
-					(*f)->state = F_ERROR;
-					continue;
-				}
-			}
-
-			if ((*f)->buf.bytesused + imglen > imagesize) {
-				DBG(3, "Video frame size exceeded");
-				(*f)->state = F_ERROR;
-				continue;
-			}
-
-			pos += VOID_BYTES;
-
-			memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen);
-			(*f)->buf.bytesused += imglen;
-
-			if ((*f)->buf.bytesused == imagesize) {
-				u32 b;
-end_of_frame:
-				b = (*f)->buf.bytesused;
-				(*f)->state = F_DONE;
-				(*f)->buf.sequence= ++cam->frame_count;
-				spin_lock(&cam->queue_lock);
-				list_move_tail(&(*f)->frame, &cam->outqueue);
-				if (!list_empty(&cam->inqueue))
-					(*f) = list_entry(cam->inqueue.next,
-						       struct et61x251_frame_t,
-							  frame);
-				else
-					(*f) = NULL;
-				spin_unlock(&cam->queue_lock);
-				DBG(3, "Video frame captured: : %lu bytes",
-				       (unsigned long)(b));
-
-				if (!(*f))
-					goto resubmit_urb;
-
-				if (sof &&
-				    cam->sensor.pix_format.pixelformat ==
-							 V4L2_PIX_FMT_ET61X251)
-					goto start_of_frame;
-			}
-		}
-	}
-
-resubmit_urb:
-	urb->dev = cam->usbdev;
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (err < 0 && err != -EPERM) {
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "usb_submit_urb() failed");
-	}
-
-	wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int et61x251_start_transfer(struct et61x251_device* cam)
-{
-	struct usb_device *udev = cam->usbdev;
-	struct urb* urb;
-	struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
-						   usb_ifnum_to_if(udev, 0),
-						   ET61X251_ALTERNATE_SETTING);
-	const unsigned int psz = le16_to_cpu(altsetting->
-					     endpoint[0].desc.wMaxPacketSize);
-	s8 i, j;
-	int err = 0;
-
-	for (i = 0; i < ET61X251_URBS; i++) {
-		cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz,
-						  GFP_KERNEL);
-		if (!cam->transfer_buffer[i]) {
-			err = -ENOMEM;
-			DBG(1, "Not enough memory");
-			goto free_buffers;
-		}
-	}
-
-	for (i = 0; i < ET61X251_URBS; i++) {
-		urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL);
-		cam->urb[i] = urb;
-		if (!urb) {
-			err = -ENOMEM;
-			DBG(1, "usb_alloc_urb() failed");
-			goto free_urbs;
-		}
-		urb->dev = udev;
-		urb->context = cam;
-		urb->pipe = usb_rcvisocpipe(udev, 1);
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = ET61X251_ISO_PACKETS;
-		urb->complete = et61x251_urb_complete;
-		urb->transfer_buffer = cam->transfer_buffer[i];
-		urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS;
-		urb->interval = 1;
-		for (j = 0; j < ET61X251_ISO_PACKETS; j++) {
-			urb->iso_frame_desc[j].offset = psz * j;
-			urb->iso_frame_desc[j].length = psz;
-		}
-	}
-
-	err = et61x251_write_reg(cam, 0x01, 0x03);
-	err = et61x251_write_reg(cam, 0x00, 0x03);
-	err = et61x251_write_reg(cam, 0x08, 0x03);
-	if (err) {
-		err = -EIO;
-		DBG(1, "I/O hardware error");
-		goto free_urbs;
-	}
-
-	err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING);
-	if (err) {
-		DBG(1, "usb_set_interface() failed");
-		goto free_urbs;
-	}
-
-	cam->frame_current = NULL;
-
-	for (i = 0; i < ET61X251_URBS; i++) {
-		err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-		if (err) {
-			for (j = i-1; j >= 0; j--)
-				usb_kill_urb(cam->urb[j]);
-			DBG(1, "usb_submit_urb() failed, error %d", err);
-			goto free_urbs;
-		}
-	}
-
-	return 0;
-
-free_urbs:
-	for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
-		usb_free_urb(cam->urb[i]);
-
-free_buffers:
-	for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++)
-		kfree(cam->transfer_buffer[i]);
-
-	return err;
-}
-
-
-static int et61x251_stop_transfer(struct et61x251_device* cam)
-{
-	struct usb_device *udev = cam->usbdev;
-	s8 i;
-	int err = 0;
-
-	if (cam->state & DEV_DISCONNECTED)
-		return 0;
-
-	for (i = ET61X251_URBS-1; i >= 0; i--) {
-		usb_kill_urb(cam->urb[i]);
-		usb_free_urb(cam->urb[i]);
-		kfree(cam->transfer_buffer[i]);
-	}
-
-	err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-	if (err)
-		DBG(3, "usb_set_interface() failed");
-
-	return err;
-}
-
-
-static int et61x251_stream_interrupt(struct et61x251_device* cam)
-{
-	long timeout;
-
-	cam->stream = STREAM_INTERRUPT;
-	timeout = wait_event_timeout(cam->wait_stream,
-				     (cam->stream == STREAM_OFF) ||
-				     (cam->state & DEV_DISCONNECTED),
-				     ET61X251_URB_TIMEOUT);
-	if (cam->state & DEV_DISCONNECTED)
-		return -ENODEV;
-	else if (cam->stream != STREAM_OFF) {
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "URB timeout reached. The camera is misconfigured. To "
-		       "use it, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -EIO;
-	}
-
-	return 0;
-}
-
-/*****************************************************************************/
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-
-static int et61x251_i2c_try_read(struct et61x251_device* cam,
-				 const struct et61x251_sensor* sensor,
-				 u8 address)
-{
-	struct usb_device* udev = cam->usbdev;
-	u8* data = cam->control_buffer;
-	int err = 0, res;
-
-	data[0] = address;
-	data[1] = cam->sensor.i2c_slave_id;
-	data[2] = cam->sensor.rsta | 0x10;
-	data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-			      0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		err += res;
-
-	err += et61x251_i2c_wait(cam, sensor);
-
-	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-			      0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		err += res;
-
-	if (err)
-		DBG(3, "I2C read failed for %s image sensor", sensor->name);
-
-	PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
-
-	return err ? -1 : (int)data[0];
-}
-
-
-static int et61x251_i2c_try_write(struct et61x251_device* cam,
-				  const struct et61x251_sensor* sensor,
-				  u8 address, u8 value)
-{
-	struct usb_device* udev = cam->usbdev;
-	u8* data = cam->control_buffer;
-	int err = 0, res;
-
-	data[0] = address;
-	data[1] = cam->sensor.i2c_slave_id;
-	data[2] = cam->sensor.rsta | 0x12;
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-			      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		err += res;
-
-	data[0] = value;
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		err += res;
-
-	err += et61x251_i2c_wait(cam, sensor);
-
-	if (err)
-		DBG(3, "I2C write failed for %s image sensor", sensor->name);
-
-	PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
-
-	return err ? -1 : 0;
-}
-
-static int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
-{
-	return et61x251_i2c_try_read(cam, &cam->sensor, address);
-}
-
-static int et61x251_i2c_write(struct et61x251_device* cam,
-			      u8 address, u8 value)
-{
-	return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
-}
-
-static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
-{
-	char str[5];
-	char* endp;
-	unsigned long val;
-
-	if (len < 4) {
-		strncpy(str, buff, len);
-		str[len] = '\0';
-	} else {
-		strncpy(str, buff, 4);
-		str[4] = '\0';
-	}
-
-	val = simple_strtoul(str, &endp, 0);
-
-	*count = 0;
-	if (val <= 0xff)
-		*count = (ssize_t)(endp - str);
-	if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
-		*count += 1;
-
-	return (u8)val;
-}
-
-/*
-   NOTE 1: being inside one of the following methods implies that the v4l
-	   device exists for sure (see kobjects and reference counters)
-   NOTE 2: buffers are PAGE_SIZE long
-*/
-
-static ssize_t et61x251_show_reg(struct device* cd,
-				 struct device_attribute *attr, char* buf)
-{
-	struct et61x251_device* cam;
-	ssize_t count;
-
-	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-		return -ERESTARTSYS;
-
-	cam = video_get_drvdata(to_video_device(cd));
-	if (!cam) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENODEV;
-	}
-
-	count = sprintf(buf, "%u\n", cam->sysfs.reg);
-
-	mutex_unlock(&et61x251_sysfs_lock);
-
-	return count;
-}
-
-
-static ssize_t
-et61x251_store_reg(struct device* cd,
-		   struct device_attribute *attr, const char* buf, size_t len)
-{
-	struct et61x251_device* cam;
-	u8 index;
-	ssize_t count;
-
-	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-		return -ERESTARTSYS;
-
-	cam = video_get_drvdata(to_video_device(cd));
-	if (!cam) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENODEV;
-	}
-
-	index = et61x251_strtou8(buf, len, &count);
-	if (index > 0x8e || !count) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -EINVAL;
-	}
-
-	cam->sysfs.reg = index;
-
-	DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
-	DBG(3, "Written bytes: %zd", count);
-
-	mutex_unlock(&et61x251_sysfs_lock);
-
-	return count;
-}
-
-
-static ssize_t et61x251_show_val(struct device* cd,
-				 struct device_attribute *attr, char* buf)
-{
-	struct et61x251_device* cam;
-	ssize_t count;
-	int val;
-
-	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-		return -ERESTARTSYS;
-
-	cam = video_get_drvdata(to_video_device(cd));
-	if (!cam) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENODEV;
-	}
-
-	if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -EIO;
-	}
-
-	count = sprintf(buf, "%d\n", val);
-
-	DBG(3, "Read bytes: %zd", count);
-
-	mutex_unlock(&et61x251_sysfs_lock);
-
-	return count;
-}
-
-
-static ssize_t
-et61x251_store_val(struct device* cd, struct device_attribute *attr,
-		   const char* buf, size_t len)
-{
-	struct et61x251_device* cam;
-	u8 value;
-	ssize_t count;
-	int err;
-
-	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-		return -ERESTARTSYS;
-
-	cam = video_get_drvdata(to_video_device(cd));
-	if (!cam) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENODEV;
-	}
-
-	value = et61x251_strtou8(buf, len, &count);
-	if (!count) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -EINVAL;
-	}
-
-	err = et61x251_write_reg(cam, value, cam->sysfs.reg);
-	if (err) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -EIO;
-	}
-
-	DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X",
-	    cam->sysfs.reg, value);
-	DBG(3, "Written bytes: %zd", count);
-
-	mutex_unlock(&et61x251_sysfs_lock);
-
-	return count;
-}
-
-
-static ssize_t et61x251_show_i2c_reg(struct device* cd,
-				     struct device_attribute *attr, char* buf)
-{
-	struct et61x251_device* cam;
-	ssize_t count;
-
-	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-		return -ERESTARTSYS;
-
-	cam = video_get_drvdata(to_video_device(cd));
-	if (!cam) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENODEV;
-	}
-
-	count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
-
-	DBG(3, "Read bytes: %zd", count);
-
-	mutex_unlock(&et61x251_sysfs_lock);
-
-	return count;
-}
-
-
-static ssize_t
-et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr,
-		       const char* buf, size_t len)
-{
-	struct et61x251_device* cam;
-	u8 index;
-	ssize_t count;
-
-	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-		return -ERESTARTSYS;
-
-	cam = video_get_drvdata(to_video_device(cd));
-	if (!cam) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENODEV;
-	}
-
-	index = et61x251_strtou8(buf, len, &count);
-	if (!count) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -EINVAL;
-	}
-
-	cam->sysfs.i2c_reg = index;
-
-	DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
-	DBG(3, "Written bytes: %zd", count);
-
-	mutex_unlock(&et61x251_sysfs_lock);
-
-	return count;
-}
-
-
-static ssize_t et61x251_show_i2c_val(struct device* cd,
-				     struct device_attribute *attr, char* buf)
-{
-	struct et61x251_device* cam;
-	ssize_t count;
-	int val;
-
-	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-		return -ERESTARTSYS;
-
-	cam = video_get_drvdata(to_video_device(cd));
-	if (!cam) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENODEV;
-	}
-
-	if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENOSYS;
-	}
-
-	if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -EIO;
-	}
-
-	count = sprintf(buf, "%d\n", val);
-
-	DBG(3, "Read bytes: %zd", count);
-
-	mutex_unlock(&et61x251_sysfs_lock);
-
-	return count;
-}
-
-
-static ssize_t
-et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr,
-		       const char* buf, size_t len)
-{
-	struct et61x251_device* cam;
-	u8 value;
-	ssize_t count;
-	int err;
-
-	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-		return -ERESTARTSYS;
-
-	cam = video_get_drvdata(to_video_device(cd));
-	if (!cam) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENODEV;
-	}
-
-	if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -ENOSYS;
-	}
-
-	value = et61x251_strtou8(buf, len, &count);
-	if (!count) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -EINVAL;
-	}
-
-	err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
-	if (err) {
-		mutex_unlock(&et61x251_sysfs_lock);
-		return -EIO;
-	}
-
-	DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
-	    cam->sysfs.i2c_reg, value);
-	DBG(3, "Written bytes: %zd", count);
-
-	mutex_unlock(&et61x251_sysfs_lock);
-
-	return count;
-}
-
-
-static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
-		   et61x251_show_reg, et61x251_store_reg);
-static DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
-		   et61x251_show_val, et61x251_store_val);
-static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
-		   et61x251_show_i2c_reg, et61x251_store_i2c_reg);
-static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
-		   et61x251_show_i2c_val, et61x251_store_i2c_val);
-
-
-static int et61x251_create_sysfs(struct et61x251_device* cam)
-{
-	struct device *classdev = &(cam->v4ldev->dev);
-	int err = 0;
-
-	if ((err = device_create_file(classdev, &dev_attr_reg)))
-		goto err_out;
-	if ((err = device_create_file(classdev, &dev_attr_val)))
-		goto err_reg;
-
-	if (cam->sensor.sysfs_ops) {
-		if ((err = device_create_file(classdev, &dev_attr_i2c_reg)))
-			goto err_val;
-		if ((err = device_create_file(classdev, &dev_attr_i2c_val)))
-			goto err_i2c_reg;
-	}
-
-err_i2c_reg:
-	if (cam->sensor.sysfs_ops)
-		device_remove_file(classdev, &dev_attr_i2c_reg);
-err_val:
-	device_remove_file(classdev, &dev_attr_val);
-err_reg:
-	device_remove_file(classdev, &dev_attr_reg);
-err_out:
-	return err;
-}
-#endif /* CONFIG_VIDEO_ADV_DEBUG */
-
-/*****************************************************************************/
-
-static int
-et61x251_set_pix_format(struct et61x251_device* cam,
-			struct v4l2_pix_format* pix)
-{
-	int r, err = 0;
-
-	if ((r = et61x251_read_reg(cam, 0x12)) < 0)
-		err += r;
-	if (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
-		err += et61x251_write_reg(cam, r & 0xfd, 0x12);
-	else
-		err += et61x251_write_reg(cam, r | 0x02, 0x12);
-
-	return err ? -EIO : 0;
-}
-
-
-static int
-et61x251_set_compression(struct et61x251_device* cam,
-			 struct v4l2_jpegcompression* compression)
-{
-	int r, err = 0;
-
-	if ((r = et61x251_read_reg(cam, 0x12)) < 0)
-		err += r;
-	if (compression->quality == 0)
-		err += et61x251_write_reg(cam, r & 0xfb, 0x12);
-	else
-		err += et61x251_write_reg(cam, r | 0x04, 0x12);
-
-	return err ? -EIO : 0;
-}
-
-
-static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)
-{
-	int r = 0, err = 0;
-
-	r = et61x251_read_reg(cam, 0x12);
-	if (r < 0)
-		err += r;
-
-	if (scale == 1)
-		err += et61x251_write_reg(cam, r & ~0x01, 0x12);
-	else if (scale == 2)
-		err += et61x251_write_reg(cam, r | 0x01, 0x12);
-
-	if (err)
-		return -EIO;
-
-	PDBGG("Scaling factor: %u", scale);
-
-	return 0;
-}
-
-
-static int
-et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
-{
-	struct et61x251_sensor* s = &cam->sensor;
-	u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
-			   s->active_pixel.left),
-	    fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
-			   s->active_pixel.top),
-	    fmw_length = (u16)(rect->width),
-	    fmw_height = (u16)(rect->height);
-	int err = 0;
-
-	err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69);
-	err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a);
-	err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b);
-	err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c);
-	err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6)
-				       | ((fmw_length & 0x300) >> 4)
-				       | ((fmw_height & 0x300) >> 2), 0x6d);
-	if (err)
-		return -EIO;
-
-	PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u",
-	      fmw_sx, fmw_sy, fmw_length, fmw_height);
-
-	return 0;
-}
-
-
-static int et61x251_init(struct et61x251_device* cam)
-{
-	struct et61x251_sensor* s = &cam->sensor;
-	struct v4l2_control ctrl;
-	struct v4l2_queryctrl *qctrl;
-	struct v4l2_rect* rect;
-	u8 i = 0;
-	int err = 0;
-
-	if (!(cam->state & DEV_INITIALIZED)) {
-		mutex_init(&cam->open_mutex);
-		init_waitqueue_head(&cam->wait_open);
-		qctrl = s->qctrl;
-		rect = &(s->cropcap.defrect);
-		cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
-	} else { /* use current values */
-		qctrl = s->_qctrl;
-		rect = &(s->_rect);
-	}
-
-	err += et61x251_set_scale(cam, rect->width / s->pix_format.width);
-	err += et61x251_set_crop(cam, rect);
-	if (err)
-		return err;
-
-	if (s->init) {
-		err = s->init(cam);
-		if (err) {
-			DBG(3, "Sensor initialization failed");
-			return err;
-		}
-	}
-
-	err += et61x251_set_compression(cam, &cam->compression);
-	err += et61x251_set_pix_format(cam, &s->pix_format);
-	if (s->set_pix_format)
-		err += s->set_pix_format(cam, &s->pix_format);
-	if (err)
-		return err;
-
-	if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251)
-		DBG(3, "Compressed video format is active, quality %d",
-		    cam->compression.quality);
-	else
-		DBG(3, "Uncompressed video format is active");
-
-	if (s->set_crop)
-		if ((err = s->set_crop(cam, rect))) {
-			DBG(3, "set_crop() failed");
-			return err;
-		}
-
-	if (s->set_ctrl) {
-		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-			if (s->qctrl[i].id != 0 &&
-			    !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
-				ctrl.id = s->qctrl[i].id;
-				ctrl.value = qctrl[i].default_value;
-				err = s->set_ctrl(cam, &ctrl);
-				if (err) {
-					DBG(3, "Set %s control failed",
-					    s->qctrl[i].name);
-					return err;
-				}
-				DBG(3, "Image sensor supports '%s' control",
-				    s->qctrl[i].name);
-			}
-	}
-
-	if (!(cam->state & DEV_INITIALIZED)) {
-		mutex_init(&cam->fileop_mutex);
-		spin_lock_init(&cam->queue_lock);
-		init_waitqueue_head(&cam->wait_frame);
-		init_waitqueue_head(&cam->wait_stream);
-		cam->nreadbuffers = 2;
-		memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
-		memcpy(&(s->_rect), &(s->cropcap.defrect),
-		       sizeof(struct v4l2_rect));
-		cam->state |= DEV_INITIALIZED;
-	}
-
-	DBG(2, "Initialization succeeded");
-	return 0;
-}
-
-/*****************************************************************************/
-
-static void et61x251_release_resources(struct kref *kref)
-{
-	struct et61x251_device *cam;
-
-	mutex_lock(&et61x251_sysfs_lock);
-
-	cam = container_of(kref, struct et61x251_device, kref);
-
-	DBG(2, "V4L2 device %s deregistered",
-	    video_device_node_name(cam->v4ldev));
-	video_set_drvdata(cam->v4ldev, NULL);
-	video_unregister_device(cam->v4ldev);
-	usb_put_dev(cam->usbdev);
-	kfree(cam->control_buffer);
-	kfree(cam);
-
-	mutex_unlock(&et61x251_sysfs_lock);
-}
-
-
-static int et61x251_open(struct file *filp)
-{
-	struct et61x251_device* cam;
-	int err = 0;
-
-	if (!down_read_trylock(&et61x251_dev_lock))
-		return -ERESTARTSYS;
-
-	cam = video_drvdata(filp);
-
-	if (wait_for_completion_interruptible(&cam->probe)) {
-		up_read(&et61x251_dev_lock);
-		return -ERESTARTSYS;
-	}
-
-	kref_get(&cam->kref);
-
-	if (mutex_lock_interruptible(&cam->open_mutex)) {
-		kref_put(&cam->kref, et61x251_release_resources);
-		up_read(&et61x251_dev_lock);
-		return -ERESTARTSYS;
-	}
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		err = -ENODEV;
-		goto out;
-	}
-
-	if (cam->users) {
-		DBG(2, "Device %s is already in use",
-		       video_device_node_name(cam->v4ldev));
-		DBG(3, "Simultaneous opens are not supported");
-		if ((filp->f_flags & O_NONBLOCK) ||
-		    (filp->f_flags & O_NDELAY)) {
-			err = -EWOULDBLOCK;
-			goto out;
-		}
-		DBG(2, "A blocking open() has been requested. Wait for the "
-		       "device to be released...");
-		up_read(&et61x251_dev_lock);
-		err = wait_event_interruptible_exclusive(cam->wait_open,
-						(cam->state & DEV_DISCONNECTED)
-							 || !cam->users);
-		down_read(&et61x251_dev_lock);
-		if (err)
-			goto out;
-		if (cam->state & DEV_DISCONNECTED) {
-			err = -ENODEV;
-			goto out;
-		}
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		err = et61x251_init(cam);
-		if (err) {
-			DBG(1, "Initialization failed again. "
-			       "I will retry on next open().");
-			goto out;
-		}
-		cam->state &= ~DEV_MISCONFIGURED;
-	}
-
-	if ((err = et61x251_start_transfer(cam)))
-		goto out;
-
-	filp->private_data = cam;
-	cam->users++;
-	cam->io = IO_NONE;
-	cam->stream = STREAM_OFF;
-	cam->nbuffers = 0;
-	cam->frame_count = 0;
-	et61x251_empty_framequeues(cam);
-
-	DBG(3, "Video device %s is open",
-	    video_device_node_name(cam->v4ldev));
-
-out:
-	mutex_unlock(&cam->open_mutex);
-	if (err)
-		kref_put(&cam->kref, et61x251_release_resources);
-	up_read(&et61x251_dev_lock);
-	return err;
-}
-
-
-static int et61x251_release(struct file *filp)
-{
-	struct et61x251_device* cam;
-
-	down_write(&et61x251_dev_lock);
-
-	cam = video_drvdata(filp);
-
-	et61x251_stop_transfer(cam);
-	et61x251_release_buffers(cam);
-	cam->users--;
-	wake_up_interruptible_nr(&cam->wait_open, 1);
-
-	DBG(3, "Video device %s closed",
-	    video_device_node_name(cam->v4ldev));
-
-	kref_put(&cam->kref, et61x251_release_resources);
-
-	up_write(&et61x251_dev_lock);
-
-	return 0;
-}
-
-
-static ssize_t
-et61x251_read(struct file* filp, char __user * buf,
-	      size_t count, loff_t* f_pos)
-{
-	struct et61x251_device *cam = video_drvdata(filp);
-	struct et61x251_frame_t* f, * i;
-	unsigned long lock_flags;
-	long timeout;
-	int err = 0;
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return -ERESTARTSYS;
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		mutex_unlock(&cam->fileop_mutex);
-		return -ENODEV;
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it "
-		       "again.");
-		mutex_unlock(&cam->fileop_mutex);
-		return -EIO;
-	}
-
-	if (cam->io == IO_MMAP) {
-		DBG(3, "Close and open the device again to choose the read "
-		       "method");
-		mutex_unlock(&cam->fileop_mutex);
-		return -EBUSY;
-	}
-
-	if (cam->io == IO_NONE) {
-		if (!et61x251_request_buffers(cam, cam->nreadbuffers,
-					      IO_READ)) {
-			DBG(1, "read() failed, not enough memory");
-			mutex_unlock(&cam->fileop_mutex);
-			return -ENOMEM;
-		}
-		cam->io = IO_READ;
-		cam->stream = STREAM_ON;
-	}
-
-	if (list_empty(&cam->inqueue)) {
-		if (!list_empty(&cam->outqueue))
-			et61x251_empty_framequeues(cam);
-		et61x251_queue_unusedframes(cam);
-	}
-
-	if (!count) {
-		mutex_unlock(&cam->fileop_mutex);
-		return 0;
-	}
-
-	if (list_empty(&cam->outqueue)) {
-		if (filp->f_flags & O_NONBLOCK) {
-			mutex_unlock(&cam->fileop_mutex);
-			return -EAGAIN;
-		}
-		timeout = wait_event_interruptible_timeout
-			  ( cam->wait_frame,
-			    (!list_empty(&cam->outqueue)) ||
-			    (cam->state & DEV_DISCONNECTED) ||
-			    (cam->state & DEV_MISCONFIGURED),
-			    msecs_to_jiffies(
-				cam->module_param.frame_timeout * 1000
-			    )
-			  );
-		if (timeout < 0) {
-			mutex_unlock(&cam->fileop_mutex);
-			return timeout;
-		}
-		if (cam->state & DEV_DISCONNECTED) {
-			mutex_unlock(&cam->fileop_mutex);
-			return -ENODEV;
-		}
-		if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
-			mutex_unlock(&cam->fileop_mutex);
-			return -EIO;
-		}
-	}
-
-	f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame);
-
-	if (count > f->buf.bytesused)
-		count = f->buf.bytesused;
-
-	if (copy_to_user(buf, f->bufmem, count)) {
-		err = -EFAULT;
-		goto exit;
-	}
-	*f_pos += count;
-
-exit:
-	spin_lock_irqsave(&cam->queue_lock, lock_flags);
-	list_for_each_entry(i, &cam->outqueue, frame)
-		i->state = F_UNUSED;
-	INIT_LIST_HEAD(&cam->outqueue);
-	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-	et61x251_queue_unusedframes(cam);
-
-	PDBGG("Frame #%lu, bytes read: %zu",
-	      (unsigned long)f->buf.index, count);
-
-	mutex_unlock(&cam->fileop_mutex);
-
-	return err ? err : count;
-}
-
-
-static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
-{
-	struct et61x251_device *cam = video_drvdata(filp);
-	struct et61x251_frame_t* f;
-	unsigned long lock_flags;
-	unsigned int mask = 0;
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return POLLERR;
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		goto error;
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it "
-		       "again.");
-		goto error;
-	}
-
-	if (cam->io == IO_NONE) {
-		if (!et61x251_request_buffers(cam, cam->nreadbuffers,
-					      IO_READ)) {
-			DBG(1, "poll() failed, not enough memory");
-			goto error;
-		}
-		cam->io = IO_READ;
-		cam->stream = STREAM_ON;
-	}
-
-	if (cam->io == IO_READ) {
-		spin_lock_irqsave(&cam->queue_lock, lock_flags);
-		list_for_each_entry(f, &cam->outqueue, frame)
-			f->state = F_UNUSED;
-		INIT_LIST_HEAD(&cam->outqueue);
-		spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-		et61x251_queue_unusedframes(cam);
-	}
-
-	poll_wait(filp, &cam->wait_frame, wait);
-
-	if (!list_empty(&cam->outqueue))
-		mask |= POLLIN | POLLRDNORM;
-
-	mutex_unlock(&cam->fileop_mutex);
-
-	return mask;
-
-error:
-	mutex_unlock(&cam->fileop_mutex);
-	return POLLERR;
-}
-
-
-static void et61x251_vm_open(struct vm_area_struct* vma)
-{
-	struct et61x251_frame_t* f = vma->vm_private_data;
-	f->vma_use_count++;
-}
-
-
-static void et61x251_vm_close(struct vm_area_struct* vma)
-{
-	/* NOTE: buffers are not freed here */
-	struct et61x251_frame_t* f = vma->vm_private_data;
-	f->vma_use_count--;
-}
-
-
-static const struct vm_operations_struct et61x251_vm_ops = {
-	.open = et61x251_vm_open,
-	.close = et61x251_vm_close,
-};
-
-
-static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-	struct et61x251_device *cam = video_drvdata(filp);
-	unsigned long size = vma->vm_end - vma->vm_start,
-		      start = vma->vm_start;
-	void *pos;
-	u32 i;
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return -ERESTARTSYS;
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		mutex_unlock(&cam->fileop_mutex);
-		return -ENODEV;
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it "
-		       "again.");
-		mutex_unlock(&cam->fileop_mutex);
-		return -EIO;
-	}
-
-	if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
-		mutex_unlock(&cam->fileop_mutex);
-		return -EACCES;
-	}
-
-	if (cam->io != IO_MMAP ||
-	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-		mutex_unlock(&cam->fileop_mutex);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < cam->nbuffers; i++) {
-		if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
-			break;
-	}
-	if (i == cam->nbuffers) {
-		mutex_unlock(&cam->fileop_mutex);
-		return -EINVAL;
-	}
-
-	vma->vm_flags |= VM_IO;
-	vma->vm_flags |= VM_RESERVED;
-
-	pos = cam->frame[i].bufmem;
-	while (size > 0) { /* size is page-aligned */
-		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-			mutex_unlock(&cam->fileop_mutex);
-			return -EAGAIN;
-		}
-		start += PAGE_SIZE;
-		pos += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-
-	vma->vm_ops = &et61x251_vm_ops;
-	vma->vm_private_data = &cam->frame[i];
-	et61x251_vm_open(vma);
-
-	mutex_unlock(&cam->fileop_mutex);
-
-	return 0;
-}
-
-/*****************************************************************************/
-
-static int
-et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_capability cap = {
-		.driver = "et61x251",
-		.version = LINUX_VERSION_CODE,
-		.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-				V4L2_CAP_STREAMING,
-	};
-
-	strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-	if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-		strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
-			sizeof(cap.bus_info));
-
-	if (copy_to_user(arg, &cap, sizeof(cap)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_input i;
-
-	if (copy_from_user(&i, arg, sizeof(i)))
-		return -EFAULT;
-
-	if (i.index)
-		return -EINVAL;
-
-	memset(&i, 0, sizeof(i));
-	strcpy(i.name, "Camera");
-	i.type = V4L2_INPUT_TYPE_CAMERA;
-	i.capabilities = V4L2_IN_CAP_STD;
-
-	if (copy_to_user(arg, &i, sizeof(i)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)
-{
-	int index = 0;
-
-	if (copy_to_user(arg, &index, sizeof(index)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)
-{
-	int index;
-
-	if (copy_from_user(&index, arg, sizeof(index)))
-		return -EFAULT;
-
-	if (index != 0)
-		return -EINVAL;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
-{
-	struct et61x251_sensor* s = &cam->sensor;
-	struct v4l2_queryctrl qc;
-	u8 i;
-
-	if (copy_from_user(&qc, arg, sizeof(qc)))
-		return -EFAULT;
-
-	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-		if (qc.id && qc.id == s->qctrl[i].id) {
-			memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-			if (copy_to_user(arg, &qc, sizeof(qc)))
-				return -EFAULT;
-			return 0;
-		}
-
-	return -EINVAL;
-}
-
-
-static int
-et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
-{
-	struct et61x251_sensor* s = &cam->sensor;
-	struct v4l2_control ctrl;
-	int err = 0;
-	u8 i;
-
-	if (!s->get_ctrl && !s->set_ctrl)
-		return -EINVAL;
-
-	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-		return -EFAULT;
-
-	if (!s->get_ctrl) {
-		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-			if (ctrl.id == s->qctrl[i].id) {
-				ctrl.value = s->_qctrl[i].default_value;
-				goto exit;
-			}
-		return -EINVAL;
-	} else
-		err = s->get_ctrl(cam, &ctrl);
-
-exit:
-	if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-		return -EFAULT;
-
-	return err;
-}
-
-
-static int
-et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
-{
-	struct et61x251_sensor* s = &cam->sensor;
-	struct v4l2_control ctrl;
-	u8 i;
-	int err = 0;
-
-	if (!s->set_ctrl)
-		return -EINVAL;
-
-	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-		return -EFAULT;
-
-	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
-		if (ctrl.id == s->qctrl[i].id) {
-			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
-				return -EINVAL;
-			if (ctrl.value < s->qctrl[i].minimum ||
-			    ctrl.value > s->qctrl[i].maximum)
-				return -ERANGE;
-			ctrl.value -= ctrl.value % s->qctrl[i].step;
-			break;
-		}
-	}
-	if (i == ARRAY_SIZE(s->qctrl))
-		return -EINVAL;
-	if ((err = s->set_ctrl(cam, &ctrl)))
-		return err;
-
-	s->_qctrl[i].default_value = ctrl.value;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
-	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	cc->pixelaspect.numerator = 1;
-	cc->pixelaspect.denominator = 1;
-
-	if (copy_to_user(arg, cc, sizeof(*cc)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
-{
-	struct et61x251_sensor* s = &cam->sensor;
-	struct v4l2_crop crop = {
-		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-	};
-
-	memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
-	if (copy_to_user(arg, &crop, sizeof(crop)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
-{
-	struct et61x251_sensor* s = &cam->sensor;
-	struct v4l2_crop crop;
-	struct v4l2_rect* rect;
-	struct v4l2_rect* bounds = &(s->cropcap.bounds);
-	struct v4l2_pix_format* pix_format = &(s->pix_format);
-	u8 scale;
-	const enum et61x251_stream_state stream = cam->stream;
-	const u32 nbuffers = cam->nbuffers;
-	u32 i;
-	int err = 0;
-
-	if (copy_from_user(&crop, arg, sizeof(crop)))
-		return -EFAULT;
-
-	rect = &(crop.c);
-
-	if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	if (cam->module_param.force_munmap)
-		for (i = 0; i < cam->nbuffers; i++)
-			if (cam->frame[i].vma_use_count) {
-				DBG(3, "VIDIOC_S_CROP failed. "
-				       "Unmap the buffers first.");
-				return -EBUSY;
-			}
-
-	/* Preserve R,G or B origin */
-	rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
-	rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
-
-	if (rect->width < 16)
-		rect->width = 16;
-	if (rect->height < 16)
-		rect->height = 16;
-	if (rect->width > bounds->width)
-		rect->width = bounds->width;
-	if (rect->height > bounds->height)
-		rect->height = bounds->height;
-	if (rect->left < bounds->left)
-		rect->left = bounds->left;
-	if (rect->top < bounds->top)
-		rect->top = bounds->top;
-	if (rect->left + rect->width > bounds->left + bounds->width)
-		rect->left = bounds->left+bounds->width - rect->width;
-	if (rect->top + rect->height > bounds->top + bounds->height)
-		rect->top = bounds->top+bounds->height - rect->height;
-
-	rect->width &= ~15L;
-	rect->height &= ~15L;
-
-	if (ET61X251_PRESERVE_IMGSCALE) {
-		/* Calculate the actual scaling factor */
-		u32 a, b;
-		a = rect->width * rect->height;
-		b = pix_format->width * pix_format->height;
-		scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
-	} else
-		scale = 1;
-
-	if (cam->stream == STREAM_ON)
-		if ((err = et61x251_stream_interrupt(cam)))
-			return err;
-
-	if (copy_to_user(arg, &crop, sizeof(crop))) {
-		cam->stream = stream;
-		return -EFAULT;
-	}
-
-	if (cam->module_param.force_munmap || cam->io == IO_READ)
-		et61x251_release_buffers(cam);
-
-	err = et61x251_set_crop(cam, rect);
-	if (s->set_crop)
-		err += s->set_crop(cam, rect);
-	err += et61x251_set_scale(cam, scale);
-
-	if (err) { /* atomic, no rollback in ioctl() */
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
-		       "use the camera, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -EIO;
-	}
-
-	s->pix_format.width = rect->width/scale;
-	s->pix_format.height = rect->height/scale;
-	memcpy(&(s->_rect), rect, sizeof(*rect));
-
-	if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-	    nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
-		       "use the camera, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -ENOMEM;
-	}
-
-	if (cam->io == IO_READ)
-		et61x251_empty_framequeues(cam);
-	else if (cam->module_param.force_munmap)
-		et61x251_requeue_outqueue(cam);
-
-	cam->stream = stream;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_enum_framesizes(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_frmsizeenum frmsize;
-
-	if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
-		return -EFAULT;
-
-	if (frmsize.index != 0)
-		return -EINVAL;
-
-	if (frmsize.pixel_format != V4L2_PIX_FMT_ET61X251 &&
-	    frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
-		return -EINVAL;
-
-	frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
-	frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
-	frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
-	frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
-	frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
-	memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
-
-	if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_fmtdesc fmtd;
-
-	if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-		return -EFAULT;
-
-	if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	if (fmtd.index == 0) {
-		strcpy(fmtd.description, "bayer rgb");
-		fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
-	} else if (fmtd.index == 1) {
-		strcpy(fmtd.description, "compressed");
-		fmtd.pixelformat = V4L2_PIX_FMT_ET61X251;
-		fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-	} else
-		return -EINVAL;
-
-	fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
-	if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_format format;
-	struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
-	if (copy_from_user(&format, arg, sizeof(format)))
-		return -EFAULT;
-
-	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?
-			   0 : V4L2_COLORSPACE_SRGB;
-	pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
-			     ? 0 : (pfmt->width * pfmt->priv) / 8;
-	pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-	pfmt->field = V4L2_FIELD_NONE;
-	memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
-	if (copy_to_user(arg, &format, sizeof(format)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
-			  void __user * arg)
-{
-	struct et61x251_sensor* s = &cam->sensor;
-	struct v4l2_format format;
-	struct v4l2_pix_format* pix;
-	struct v4l2_pix_format* pfmt = &(s->pix_format);
-	struct v4l2_rect* bounds = &(s->cropcap.bounds);
-	struct v4l2_rect rect;
-	u8 scale;
-	const enum et61x251_stream_state stream = cam->stream;
-	const u32 nbuffers = cam->nbuffers;
-	u32 i;
-	int err = 0;
-
-	if (copy_from_user(&format, arg, sizeof(format)))
-		return -EFAULT;
-
-	pix = &(format.fmt.pix);
-
-	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	memcpy(&rect, &(s->_rect), sizeof(rect));
-
-	{ /* calculate the actual scaling factor */
-		u32 a, b;
-		a = rect.width * rect.height;
-		b = pix->width * pix->height;
-		scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
-	}
-
-	rect.width = scale * pix->width;
-	rect.height = scale * pix->height;
-
-	if (rect.width < 16)
-		rect.width = 16;
-	if (rect.height < 16)
-		rect.height = 16;
-	if (rect.width > bounds->left + bounds->width - rect.left)
-		rect.width = bounds->left + bounds->width - rect.left;
-	if (rect.height > bounds->top + bounds->height - rect.top)
-		rect.height = bounds->top + bounds->height - rect.top;
-
-	rect.width &= ~15L;
-	rect.height &= ~15L;
-
-	{ /* adjust the scaling factor */
-		u32 a, b;
-		a = rect.width * rect.height;
-		b = pix->width * pix->height;
-		scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
-	}
-
-	pix->width = rect.width / scale;
-	pix->height = rect.height / scale;
-
-	if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 &&
-	    pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
-		pix->pixelformat = pfmt->pixelformat;
-	pix->priv = pfmt->priv; /* bpp */
-	pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?
-			  0 : V4L2_COLORSPACE_SRGB;
-	pix->colorspace = pfmt->colorspace;
-	pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
-			    ? 0 : (pix->width * pix->priv) / 8;
-	pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-	pix->field = V4L2_FIELD_NONE;
-
-	if (cmd == VIDIOC_TRY_FMT) {
-		if (copy_to_user(arg, &format, sizeof(format)))
-			return -EFAULT;
-		return 0;
-	}
-
-	if (cam->module_param.force_munmap)
-		for (i = 0; i < cam->nbuffers; i++)
-			if (cam->frame[i].vma_use_count) {
-				DBG(3, "VIDIOC_S_FMT failed. "
-				       "Unmap the buffers first.");
-				return -EBUSY;
-			}
-
-	if (cam->stream == STREAM_ON)
-		if ((err = et61x251_stream_interrupt(cam)))
-			return err;
-
-	if (copy_to_user(arg, &format, sizeof(format))) {
-		cam->stream = stream;
-		return -EFAULT;
-	}
-
-	if (cam->module_param.force_munmap || cam->io == IO_READ)
-		et61x251_release_buffers(cam);
-
-	err += et61x251_set_pix_format(cam, pix);
-	err += et61x251_set_crop(cam, &rect);
-	if (s->set_pix_format)
-		err += s->set_pix_format(cam, pix);
-	if (s->set_crop)
-		err += s->set_crop(cam, &rect);
-	err += et61x251_set_scale(cam, scale);
-
-	if (err) { /* atomic, no rollback in ioctl() */
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
-		       "use the camera, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -EIO;
-	}
-
-	memcpy(pfmt, pix, sizeof(*pix));
-	memcpy(&(s->_rect), &rect, sizeof(rect));
-
-	if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-	    nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
-		       "use the camera, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -ENOMEM;
-	}
-
-	if (cam->io == IO_READ)
-		et61x251_empty_framequeues(cam);
-	else if (cam->module_param.force_munmap)
-		et61x251_requeue_outqueue(cam);
-
-	cam->stream = stream;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg)
-{
-	if (copy_to_user(arg, &cam->compression,
-			 sizeof(cam->compression)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_jpegcompression jc;
-	const enum et61x251_stream_state stream = cam->stream;
-	int err = 0;
-
-	if (copy_from_user(&jc, arg, sizeof(jc)))
-		return -EFAULT;
-
-	if (jc.quality != 0 && jc.quality != 1)
-		return -EINVAL;
-
-	if (cam->stream == STREAM_ON)
-		if ((err = et61x251_stream_interrupt(cam)))
-			return err;
-
-	err += et61x251_set_compression(cam, &jc);
-	if (err) { /* atomic, no rollback in ioctl() */
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-		       "problems. To use the camera, close and open "
-		       "%s again.", video_device_node_name(cam->v4ldev));
-		return -EIO;
-	}
-
-	cam->compression.quality = jc.quality;
-
-	cam->stream = stream;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_requestbuffers rb;
-	u32 i;
-	int err;
-
-	if (copy_from_user(&rb, arg, sizeof(rb)))
-		return -EFAULT;
-
-	if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-	    rb.memory != V4L2_MEMORY_MMAP)
-		return -EINVAL;
-
-	if (cam->io == IO_READ) {
-		DBG(3, "Close and open the device again to choose the mmap "
-		       "I/O method");
-		return -EBUSY;
-	}
-
-	for (i = 0; i < cam->nbuffers; i++)
-		if (cam->frame[i].vma_use_count) {
-			DBG(3, "VIDIOC_REQBUFS failed. "
-			       "Previous buffers are still mapped.");
-			return -EBUSY;
-		}
-
-	if (cam->stream == STREAM_ON)
-		if ((err = et61x251_stream_interrupt(cam)))
-			return err;
-
-	et61x251_empty_framequeues(cam);
-
-	et61x251_release_buffers(cam);
-	if (rb.count)
-		rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP);
-
-	if (copy_to_user(arg, &rb, sizeof(rb))) {
-		et61x251_release_buffers(cam);
-		cam->io = IO_NONE;
-		return -EFAULT;
-	}
-
-	cam->io = rb.count ? IO_MMAP : IO_NONE;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_buffer b;
-
-	if (copy_from_user(&b, arg, sizeof(b)))
-		return -EFAULT;
-
-	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
-		return -EINVAL;
-
-	memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
-	if (cam->frame[b.index].vma_use_count)
-		b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-	if (cam->frame[b.index].state == F_DONE)
-		b.flags |= V4L2_BUF_FLAG_DONE;
-	else if (cam->frame[b.index].state != F_UNUSED)
-		b.flags |= V4L2_BUF_FLAG_QUEUED;
-
-	if (copy_to_user(arg, &b, sizeof(b)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_buffer b;
-	unsigned long lock_flags;
-
-	if (copy_from_user(&b, arg, sizeof(b)))
-		return -EFAULT;
-
-	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
-		return -EINVAL;
-
-	if (cam->frame[b.index].state != F_UNUSED)
-		return -EINVAL;
-
-	cam->frame[b.index].state = F_QUEUED;
-
-	spin_lock_irqsave(&cam->queue_lock, lock_flags);
-	list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-	PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
-		      void __user * arg)
-{
-	struct v4l2_buffer b;
-	struct et61x251_frame_t *f;
-	unsigned long lock_flags;
-	long timeout;
-
-	if (copy_from_user(&b, arg, sizeof(b)))
-		return -EFAULT;
-
-	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
-		return -EINVAL;
-
-	if (list_empty(&cam->outqueue)) {
-		if (cam->stream == STREAM_OFF)
-			return -EINVAL;
-		if (filp->f_flags & O_NONBLOCK)
-			return -EAGAIN;
-		timeout = wait_event_interruptible_timeout
-			  ( cam->wait_frame,
-			    (!list_empty(&cam->outqueue)) ||
-			    (cam->state & DEV_DISCONNECTED) ||
-			    (cam->state & DEV_MISCONFIGURED),
-			    cam->module_param.frame_timeout *
-			    1000 * msecs_to_jiffies(1) );
-		if (timeout < 0)
-			return timeout;
-		if (cam->state & DEV_DISCONNECTED)
-			return -ENODEV;
-		if (!timeout || (cam->state & DEV_MISCONFIGURED))
-			return -EIO;
-	}
-
-	spin_lock_irqsave(&cam->queue_lock, lock_flags);
-	f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame);
-	list_del(cam->outqueue.next);
-	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-	f->state = F_UNUSED;
-
-	memcpy(&b, &f->buf, sizeof(b));
-	if (f->vma_use_count)
-		b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-	if (copy_to_user(arg, &b, sizeof(b)))
-		return -EFAULT;
-
-	PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
-{
-	int type;
-
-	if (copy_from_user(&type, arg, sizeof(type)))
-		return -EFAULT;
-
-	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-		return -EINVAL;
-
-	cam->stream = STREAM_ON;
-
-	DBG(3, "Stream on");
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg)
-{
-	int type, err;
-
-	if (copy_from_user(&type, arg, sizeof(type)))
-		return -EFAULT;
-
-	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-		return -EINVAL;
-
-	if (cam->stream == STREAM_ON)
-		if ((err = et61x251_stream_interrupt(cam)))
-			return err;
-
-	et61x251_empty_framequeues(cam);
-
-	DBG(3, "Stream off");
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_streamparm sp;
-
-	if (copy_from_user(&sp, arg, sizeof(sp)))
-		return -EFAULT;
-
-	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	sp.parm.capture.extendedmode = 0;
-	sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-	if (copy_to_user(arg, &sp, sizeof(sp)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)
-{
-	struct v4l2_streamparm sp;
-
-	if (copy_from_user(&sp, arg, sizeof(sp)))
-		return -EFAULT;
-
-	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	sp.parm.capture.extendedmode = 0;
-
-	if (sp.parm.capture.readbuffers == 0)
-		sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-	if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES)
-		sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES;
-
-	if (copy_to_user(arg, &sp, sizeof(sp)))
-		return -EFAULT;
-
-	cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-	return 0;
-}
-
-
-static long et61x251_ioctl_v4l2(struct file *filp,
-			       unsigned int cmd, void __user *arg)
-{
-	struct et61x251_device *cam = video_drvdata(filp);
-
-	switch (cmd) {
-
-	case VIDIOC_QUERYCAP:
-		return et61x251_vidioc_querycap(cam, arg);
-
-	case VIDIOC_ENUMINPUT:
-		return et61x251_vidioc_enuminput(cam, arg);
-
-	case VIDIOC_G_INPUT:
-		return et61x251_vidioc_g_input(cam, arg);
-
-	case VIDIOC_S_INPUT:
-		return et61x251_vidioc_s_input(cam, arg);
-
-	case VIDIOC_QUERYCTRL:
-		return et61x251_vidioc_query_ctrl(cam, arg);
-
-	case VIDIOC_G_CTRL:
-		return et61x251_vidioc_g_ctrl(cam, arg);
-
-	case VIDIOC_S_CTRL:
-		return et61x251_vidioc_s_ctrl(cam, arg);
-
-	case VIDIOC_CROPCAP:
-		return et61x251_vidioc_cropcap(cam, arg);
-
-	case VIDIOC_G_CROP:
-		return et61x251_vidioc_g_crop(cam, arg);
-
-	case VIDIOC_S_CROP:
-		return et61x251_vidioc_s_crop(cam, arg);
-
-	case VIDIOC_ENUM_FMT:
-		return et61x251_vidioc_enum_fmt(cam, arg);
-
-	case VIDIOC_G_FMT:
-		return et61x251_vidioc_g_fmt(cam, arg);
-
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_S_FMT:
-		return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
-
-	case VIDIOC_ENUM_FRAMESIZES:
-		return et61x251_vidioc_enum_framesizes(cam, arg);
-
-	case VIDIOC_G_JPEGCOMP:
-		return et61x251_vidioc_g_jpegcomp(cam, arg);
-
-	case VIDIOC_S_JPEGCOMP:
-		return et61x251_vidioc_s_jpegcomp(cam, arg);
-
-	case VIDIOC_REQBUFS:
-		return et61x251_vidioc_reqbufs(cam, arg);
-
-	case VIDIOC_QUERYBUF:
-		return et61x251_vidioc_querybuf(cam, arg);
-
-	case VIDIOC_QBUF:
-		return et61x251_vidioc_qbuf(cam, arg);
-
-	case VIDIOC_DQBUF:
-		return et61x251_vidioc_dqbuf(cam, filp, arg);
-
-	case VIDIOC_STREAMON:
-		return et61x251_vidioc_streamon(cam, arg);
-
-	case VIDIOC_STREAMOFF:
-		return et61x251_vidioc_streamoff(cam, arg);
-
-	case VIDIOC_G_PARM:
-		return et61x251_vidioc_g_parm(cam, arg);
-
-	case VIDIOC_S_PARM:
-		return et61x251_vidioc_s_parm(cam, arg);
-
-	default:
-		return -ENOTTY;
-
-	}
-}
-
-
-static long et61x251_ioctl(struct file *filp,
-			 unsigned int cmd, unsigned long arg)
-{
-	struct et61x251_device *cam = video_drvdata(filp);
-	long err = 0;
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return -ERESTARTSYS;
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		mutex_unlock(&cam->fileop_mutex);
-		return -ENODEV;
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it "
-		       "again.");
-		mutex_unlock(&cam->fileop_mutex);
-		return -EIO;
-	}
-
-	V4LDBG(3, "et61x251", cmd);
-
-	err = et61x251_ioctl_v4l2(filp, cmd, (void __user *)arg);
-
-	mutex_unlock(&cam->fileop_mutex);
-
-	return err;
-}
-
-
-static const struct v4l2_file_operations et61x251_fops = {
-	.owner = THIS_MODULE,
-	.open =    et61x251_open,
-	.release = et61x251_release,
-	.unlocked_ioctl =   et61x251_ioctl,
-	.read =    et61x251_read,
-	.poll =    et61x251_poll,
-	.mmap =    et61x251_mmap,
-};
-
-/*****************************************************************************/
-
-/* It exists a single interface only. We do not need to validate anything. */
-static int
-et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct et61x251_device* cam;
-	static unsigned int dev_nr;
-	unsigned int i;
-	int err = 0;
-
-	if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL)))
-		return -ENOMEM;
-
-	cam->usbdev = udev;
-
-	if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
-		DBG(1, "kmalloc() failed");
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	if (!(cam->v4ldev = video_device_alloc())) {
-		DBG(1, "video_device_alloc() failed");
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	DBG(2, "ET61X[12]51 PC Camera Controller detected "
-	       "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
-
-	for  (i = 0; et61x251_sensor_table[i]; i++) {
-		err = et61x251_sensor_table[i](cam);
-		if (!err)
-			break;
-	}
-
-	if (!err)
-		DBG(2, "%s image sensor detected", cam->sensor.name);
-	else {
-		DBG(1, "No supported image sensor detected");
-		err = -ENODEV;
-		goto fail;
-	}
-
-	if (et61x251_init(cam)) {
-		DBG(1, "Initialization failed. I will retry on open().");
-		cam->state |= DEV_MISCONFIGURED;
-	}
-
-	strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");
-	cam->v4ldev->fops = &et61x251_fops;
-	cam->v4ldev->release = video_device_release;
-	cam->v4ldev->parent = &udev->dev;
-	video_set_drvdata(cam->v4ldev, cam);
-
-	init_completion(&cam->probe);
-
-	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-				    video_nr[dev_nr]);
-	if (err) {
-		DBG(1, "V4L2 device registration failed");
-		if (err == -ENFILE && video_nr[dev_nr] == -1)
-			DBG(1, "Free /dev/videoX node not found");
-		video_nr[dev_nr] = -1;
-		dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-		complete_all(&cam->probe);
-		goto fail;
-	}
-
-	DBG(2, "V4L2 device registered as %s",
-	    video_device_node_name(cam->v4ldev));
-
-	cam->module_param.force_munmap = force_munmap[dev_nr];
-	cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
-	dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	err = et61x251_create_sysfs(cam);
-	if (!err)
-		DBG(2, "Optional device control through 'sysfs' "
-		       "interface ready");
-	else
-		DBG(2, "Failed to create 'sysfs' interface for optional "
-		       "device controlling. Error #%d", err);
-#else
-	DBG(2, "Optional device control through 'sysfs' interface disabled");
-	DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
-	       "configuration option to enable it.");
-#endif
-
-	usb_set_intfdata(intf, cam);
-	kref_init(&cam->kref);
-	usb_get_dev(cam->usbdev);
-
-	complete_all(&cam->probe);
-
-	return 0;
-
-fail:
-	if (cam) {
-		kfree(cam->control_buffer);
-		if (cam->v4ldev)
-			video_device_release(cam->v4ldev);
-		kfree(cam);
-	}
-	return err;
-}
-
-
-static void et61x251_usb_disconnect(struct usb_interface* intf)
-{
-	struct et61x251_device* cam;
-
-	down_write(&et61x251_dev_lock);
-
-	cam = usb_get_intfdata(intf);
-
-	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
-	if (cam->users) {
-		DBG(2, "Device %s is open! Deregistration and memory "
-		       "deallocation are deferred.",
-		    video_device_node_name(cam->v4ldev));
-		cam->state |= DEV_MISCONFIGURED;
-		et61x251_stop_transfer(cam);
-		cam->state |= DEV_DISCONNECTED;
-		wake_up_interruptible(&cam->wait_frame);
-		wake_up(&cam->wait_stream);
-	} else
-		cam->state |= DEV_DISCONNECTED;
-
-	wake_up_interruptible_all(&cam->wait_open);
-
-	kref_put(&cam->kref, et61x251_release_resources);
-
-	up_write(&et61x251_dev_lock);
-}
-
-
-static struct usb_driver et61x251_usb_driver = {
-	.name =       "et61x251",
-	.id_table =   et61x251_id_table,
-	.probe =      et61x251_usb_probe,
-	.disconnect = et61x251_usb_disconnect,
-};
-
-module_usb_driver(et61x251_usb_driver);
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
deleted file mode 100644
index 71a0314..0000000
--- a/drivers/media/video/et61x251/et61x251_sensor.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to ET61X[12]51 PC Camera Controllers    *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ET61X251_SENSOR_H_
-#define _ET61X251_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct et61x251_device;
-struct et61x251_sensor;
-
-/*****************************************************************************/
-
-extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam);
-
-#define ET61X251_SENSOR_TABLE                                                 \
-/* Weak detections must go at the end of the list */                          \
-static int (*et61x251_sensor_table[])(struct et61x251_device*) = {            \
-	&et61x251_probe_tas5130d1b,                                           \
-	NULL,                                                                 \
-};
-
-extern struct et61x251_device*
-et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
-
-extern void
-et61x251_attach_sensor(struct et61x251_device* cam,
-		       const struct et61x251_sensor* sensor);
-
-/*****************************************************************************/
-
-extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
-extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
-				  u8 data2, u8 data3, u8 data4, u8 data5,
-				  u8 data6, u8 data7, u8 data8, u8 address);
-
-/*****************************************************************************/
-
-enum et61x251_i2c_sysfs_ops {
-	ET61X251_I2C_READ = 0x01,
-	ET61X251_I2C_WRITE = 0x02,
-};
-
-enum et61x251_i2c_interface {
-	ET61X251_I2C_2WIRES,
-	ET61X251_I2C_3WIRES,
-};
-
-/* Repeat start condition when RSTA is high */
-enum et61x251_i2c_rsta {
-	ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */
-	ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
-};
-
-#define ET61X251_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
-
-struct et61x251_sensor {
-	char name[32];
-
-	enum et61x251_i2c_sysfs_ops sysfs_ops;
-
-	enum et61x251_i2c_interface interface;
-	u8 i2c_slave_id;
-	enum et61x251_i2c_rsta rsta;
-	struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */
-
-	struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS];
-	struct v4l2_cropcap cropcap;
-	struct v4l2_pix_format pix_format;
-
-	int (*init)(struct et61x251_device* cam);
-	int (*get_ctrl)(struct et61x251_device* cam,
-			struct v4l2_control* ctrl);
-	int (*set_ctrl)(struct et61x251_device* cam,
-			const struct v4l2_control* ctrl);
-	int (*set_crop)(struct et61x251_device* cam,
-			const struct v4l2_rect* rect);
-	int (*set_pix_format)(struct et61x251_device* cam,
-			      const struct v4l2_pix_format* pix);
-
-	/* Private */
-	struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
-	struct v4l2_rect _rect;
-};
-
-#endif /* _ET61X251_SENSOR_H_ */
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
deleted file mode 100644
index ced2e16..0000000
--- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51        *
- * PC Camera Controllers                                                   *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include "et61x251_sensor.h"
-
-
-static int tas5130d1b_init(struct et61x251_device* cam)
-{
-	int err = 0;
-
-	err += et61x251_write_reg(cam, 0x14, 0x01);
-	err += et61x251_write_reg(cam, 0x1b, 0x02);
-	err += et61x251_write_reg(cam, 0x02, 0x12);
-	err += et61x251_write_reg(cam, 0x0e, 0x60);
-	err += et61x251_write_reg(cam, 0x80, 0x61);
-	err += et61x251_write_reg(cam, 0xf0, 0x62);
-	err += et61x251_write_reg(cam, 0x03, 0x63);
-	err += et61x251_write_reg(cam, 0x14, 0x64);
-	err += et61x251_write_reg(cam, 0xf4, 0x65);
-	err += et61x251_write_reg(cam, 0x01, 0x66);
-	err += et61x251_write_reg(cam, 0x05, 0x67);
-	err += et61x251_write_reg(cam, 0x8f, 0x68);
-	err += et61x251_write_reg(cam, 0x0f, 0x8d);
-	err += et61x251_write_reg(cam, 0x08, 0x8e);
-
-	return err;
-}
-
-
-static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
-			       const struct v4l2_control* ctrl)
-{
-	int err = 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_GAIN:
-		err += et61x251_i2c_raw_write(cam, 2, 0x20,
-					      0xf6-ctrl->value, 0, 0, 0,
-					      0, 0, 0, 0);
-		break;
-	case V4L2_CID_EXPOSURE:
-		err += et61x251_i2c_raw_write(cam, 2, 0x40,
-					      0x47-ctrl->value, 0, 0, 0,
-					      0, 0, 0, 0);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return err ? -EIO : 0;
-}
-
-
-static const struct et61x251_sensor tas5130d1b = {
-	.name = "TAS5130D1B",
-	.interface = ET61X251_I2C_3WIRES,
-	.rsta = ET61X251_I2C_RSTA_STOP,
-	.active_pixel = {
-		.left = 106,
-		.top = 13,
-	},
-	.init = &tas5130d1b_init,
-	.qctrl = {
-		{
-			.id = V4L2_CID_GAIN,
-			.type = V4L2_CTRL_TYPE_INTEGER,
-			.name = "global gain",
-			.minimum = 0x00,
-			.maximum = 0xf6,
-			.step = 0x02,
-			.default_value = 0x0d,
-			.flags = 0,
-		},
-		{
-			.id = V4L2_CID_EXPOSURE,
-			.type = V4L2_CTRL_TYPE_INTEGER,
-			.name = "exposure",
-			.minimum = 0x00,
-			.maximum = 0x47,
-			.step = 0x01,
-			.default_value = 0x23,
-			.flags = 0,
-		},
-	},
-	.set_ctrl = &tas5130d1b_set_ctrl,
-	.cropcap = {
-		.bounds = {
-			.left = 0,
-			.top = 0,
-			.width = 640,
-			.height = 480,
-		},
-		.defrect = {
-			.left = 0,
-			.top = 0,
-			.width = 640,
-			.height = 480,
-		},
-	},
-	.pix_format = {
-		.width = 640,
-		.height = 480,
-		.pixelformat = V4L2_PIX_FMT_SBGGR8,
-		.priv = 8,
-	},
-};
-
-
-int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
-{
-	const struct usb_device_id tas5130d1b_id_table[] = {
-		{ USB_DEVICE(0x102c, 0x6251), },
-		{ }
-	};
-
-	/* Sensor detection is based on USB pid/vid */
-	if (!et61x251_match_id(cam, tas5130d1b_id_table))
-		return -ENODEV;
-
-	et61x251_attach_sensor(cam, &tas5130d1b);
-
-	return 0;
-}
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
index 27e3e0c..777486f 100644
--- a/drivers/media/video/fsl-viu.c
+++ b/drivers/media/video/fsl-viu.c
@@ -1544,6 +1544,10 @@
 
 	/* initialize locks */
 	mutex_init(&viu_dev->lock);
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &viu_dev->vdev->flags);
 	viu_dev->vdev->lock = &viu_dev->lock;
 	spin_lock_init(&viu_dev->slock);
 
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index 79ebe46..c901da0 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -43,7 +43,7 @@
 obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o
 obj-$(CONFIG_USB_GSPCA_ZC3XX)    += gspca_zc3xx.o
 
-gspca_main-objs     := gspca.o
+gspca_main-objs     := gspca.o autogain_functions.o
 gspca_benq-objs     := benq.o
 gspca_conex-objs    := conex.o
 gspca_cpia1-objs    := cpia1.o
diff --git a/drivers/media/video/gspca/autogain_functions.c b/drivers/media/video/gspca/autogain_functions.c
new file mode 100644
index 0000000..67db674
--- /dev/null
+++ b/drivers/media/video/gspca/autogain_functions.c
@@ -0,0 +1,178 @@
+/*
+ * Functions for auto gain.
+ *
+ * Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.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
+ */
+#include "gspca.h"
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+   http://ytse.tricolour.net/docs/LowLightOptimization.html
+
+   Returns 0 if no changes were made, 1 if the gain and or exposure settings
+   where changed. */
+int gspca_expo_autogain(
+			struct gspca_dev *gspca_dev,
+			int avg_lum,
+			int desired_avg_lum,
+			int deadzone,
+			int gain_knee,
+			int exposure_knee)
+{
+	s32 gain, orig_gain, exposure, orig_exposure;
+	int i, steps, retval = 0;
+
+	if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
+	        return 0;
+
+	orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
+	orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
+
+	/* If we are of a multiple of deadzone, do multiple steps to reach the
+	   desired lumination fast (with the risc of a slight overshoot) */
+	steps = abs(desired_avg_lum - avg_lum) / deadzone;
+
+	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+		avg_lum, desired_avg_lum, steps);
+
+	for (i = 0; i < steps; i++) {
+		if (avg_lum > desired_avg_lum) {
+			if (gain > gain_knee)
+				gain--;
+			else if (exposure > exposure_knee)
+				exposure--;
+			else if (gain > gspca_dev->gain->default_value)
+				gain--;
+			else if (exposure > gspca_dev->exposure->minimum)
+				exposure--;
+			else if (gain > gspca_dev->gain->minimum)
+				gain--;
+			else
+				break;
+		} else {
+			if (gain < gspca_dev->gain->default_value)
+				gain++;
+			else if (exposure < exposure_knee)
+				exposure++;
+			else if (gain < gain_knee)
+				gain++;
+			else if (exposure < gspca_dev->exposure->maximum)
+				exposure++;
+			else if (gain < gspca_dev->gain->maximum)
+				gain++;
+			else
+				break;
+		}
+	}
+
+	if (gain != orig_gain) {
+	        v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
+		retval = 1;
+	}
+	if (exposure != orig_exposure) {
+	        v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
+		retval = 1;
+	}
+
+	if (retval)
+		PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+			gain, exposure);
+	return retval;
+}
+EXPORT_SYMBOL(gspca_expo_autogain);
+
+/* Autogain + exposure algorithm for cameras with a coarse exposure control
+   (usually this means we can only control the clockdiv to change exposure)
+   As changing the clockdiv so that the fps drops from 30 to 15 fps for
+   example, will lead to a huge exposure change (it effectively doubles),
+   this algorithm normally tries to only adjust the gain (between 40 and
+   80 %) and if that does not help, only then changes exposure. This leads
+   to a much more stable image then using the knee algorithm which at
+   certain points of the knee graph will only try to adjust exposure,
+   which leads to oscilating as one exposure step is huge.
+
+   Returns 0 if no changes were made, 1 if the gain and or exposure settings
+   where changed. */
+int gspca_coarse_grained_expo_autogain(
+			struct gspca_dev *gspca_dev,
+			int avg_lum,
+			int desired_avg_lum,
+			int deadzone)
+{
+	s32 gain_low, gain_high, gain, orig_gain, exposure, orig_exposure;
+	int steps, retval = 0;
+
+	if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
+	        return 0;
+
+	orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
+	orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
+
+	gain_low  = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
+		    5 * 2 + gspca_dev->gain->minimum;
+	gain_high = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
+		    5 * 4 + gspca_dev->gain->minimum;
+
+	/* If we are of a multiple of deadzone, do multiple steps to reach the
+	   desired lumination fast (with the risc of a slight overshoot) */
+	steps = (desired_avg_lum - avg_lum) / deadzone;
+
+	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+		avg_lum, desired_avg_lum, steps);
+
+	if ((gain + steps) > gain_high &&
+	    exposure < gspca_dev->exposure->maximum) {
+		gain = gain_high;
+		gspca_dev->exp_too_low_cnt++;
+		gspca_dev->exp_too_high_cnt = 0;
+	} else if ((gain + steps) < gain_low &&
+		   exposure > gspca_dev->exposure->minimum) {
+		gain = gain_low;
+		gspca_dev->exp_too_high_cnt++;
+		gspca_dev->exp_too_low_cnt = 0;
+	} else {
+		gain += steps;
+		if (gain > gspca_dev->gain->maximum)
+			gain = gspca_dev->gain->maximum;
+		else if (gain < gspca_dev->gain->minimum)
+			gain = gspca_dev->gain->minimum;
+		gspca_dev->exp_too_high_cnt = 0;
+		gspca_dev->exp_too_low_cnt = 0;
+	}
+
+	if (gspca_dev->exp_too_high_cnt > 3) {
+		exposure--;
+		gspca_dev->exp_too_high_cnt = 0;
+	} else if (gspca_dev->exp_too_low_cnt > 3) {
+		exposure++;
+		gspca_dev->exp_too_low_cnt = 0;
+	}
+
+	if (gain != orig_gain) {
+	        v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
+		retval = 1;
+	}
+	if (exposure != orig_exposure) {
+	        v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
+		retval = 1;
+	}
+
+	if (retval)
+		PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+			gain, exposure);
+	return retval;
+}
+EXPORT_SYMBOL(gspca_coarse_grained_expo_autogain);
diff --git a/drivers/media/video/gspca/autogain_functions.h b/drivers/media/video/gspca/autogain_functions.h
index 46777ee..d625eaf 100644
--- a/drivers/media/video/gspca/autogain_functions.h
+++ b/drivers/media/video/gspca/autogain_functions.h
@@ -18,6 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifdef WANT_REGULAR_AUTOGAIN
 /* auto gain and exposure algorithm based on the knee algorithm described here:
    http://ytse.tricolour.net/docs/LowLightOptimization.html
 
@@ -91,7 +92,9 @@
 			gain, exposure);
 	return retval;
 }
+#endif
 
+#ifdef WANT_COARSE_EXPO_AUTOGAIN
 /* Autogain + exposure algorithm for cameras with a coarse exposure control
    (usually this means we can only control the clockdiv to change exposure)
    As changing the clockdiv so that the fps drops from 30 to 15 fps for
@@ -103,7 +106,7 @@
    which leads to oscilating as one exposure step is huge.
 
    Note this assumes that the sd struct for the cam in question has
-   exp_too_high_cnt and exp_too_high_cnt int members for use by this function.
+   exp_too_low_cnt and exp_too_high_cnt int members for use by this function.
 
    Returns 0 if no changes were made, 1 if the gain and or exposure settings
    where changed. */
@@ -177,3 +180,4 @@
 			gain, exposure);
 	return retval;
 }
+#endif
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index ea17b5d..f39fee0 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -306,7 +306,7 @@
 
 	reg_w(gspca_dev, 0x0020, reg20, 8);
 	reg_w(gspca_dev, 0x0028, reg28, 8);
-	reg_w(gspca_dev, 0x0010, reg10, 8);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
 	reg_w_val(gspca_dev, 0x0092, 0x03);
 
 	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
@@ -326,7 +326,7 @@
 	}
 	reg_w(gspca_dev, 0x007b, reg7b, 6);
 	reg_w_val(gspca_dev, 0x00f8, 0x00);
-	reg_w(gspca_dev, 0x0010, reg10, 8);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
 	reg_w_val(gspca_dev, 0x0098, 0x41);
 	for (i = 0; i < 11; i++) {
 		if (i == 3 || i == 5 || i == 8)
diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c
index 0107513..6e26c93 100644
--- a/drivers/media/video/gspca/finepix.c
+++ b/drivers/media/video/gspca/finepix.c
@@ -94,7 +94,11 @@
 
 	/* loop reading a frame */
 again:
-	while (gspca_dev->present && gspca_dev->streaming) {
+	while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			break;
+#endif
 
 		/* request a frame */
 		mutex_lock(&gspca_dev->usb_lock);
@@ -102,7 +106,11 @@
 		mutex_unlock(&gspca_dev->usb_lock);
 		if (ret < 0)
 			break;
-		if (!gspca_dev->present || !gspca_dev->streaming)
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			break;
+#endif
+		if (!gspca_dev->dev || !gspca_dev->streaming)
 			break;
 
 		/* the frame comes in parts */
@@ -117,7 +125,11 @@
 				 * error. Just restart. */
 				goto again;
 			}
-			if (!gspca_dev->present || !gspca_dev->streaming)
+#ifdef CONFIG_PM
+			if (gspca_dev->frozen)
+				goto out;
+#endif
+			if (!gspca_dev->dev || !gspca_dev->streaming)
 				goto out;
 			if (len < FPIX_MAX_TRANSFER ||
 				(data[len - 2] == 0xff &&
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index c84e260..c549574 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -405,6 +405,9 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
+	if (!sd->gspca_dev.present)
+		return;
+
 	return sd->dev_post_unset_alt(gspca_dev);
 }
 
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index ca5a2b1..137166d 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -38,6 +38,9 @@
 #include <linux/uaccess.h>
 #include <linux/ktime.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
 
 #include "gspca.h"
 
@@ -592,16 +595,13 @@
 static void gspca_stream_off(struct gspca_dev *gspca_dev)
 {
 	gspca_dev->streaming = 0;
-	if (gspca_dev->present) {
-		if (gspca_dev->sd_desc->stopN)
-			gspca_dev->sd_desc->stopN(gspca_dev);
-		destroy_urbs(gspca_dev);
-		gspca_input_destroy_urb(gspca_dev);
-		gspca_set_alt0(gspca_dev);
-		gspca_input_create_urb(gspca_dev);
-	}
-
-	/* always call stop0 to free the subdriver's resources */
+	gspca_dev->usb_err = 0;
+	if (gspca_dev->sd_desc->stopN)
+		gspca_dev->sd_desc->stopN(gspca_dev);
+	destroy_urbs(gspca_dev);
+	gspca_input_destroy_urb(gspca_dev);
+	gspca_set_alt0(gspca_dev);
+	gspca_input_create_urb(gspca_dev);
 	if (gspca_dev->sd_desc->stop0)
 		gspca_dev->sd_desc->stop0(gspca_dev);
 	PDEBUG(D_STREAM, "stream off OK");
@@ -847,14 +847,6 @@
 	struct ep_tb_s ep_tb[MAX_ALT];
 	int n, ret, xfer, alt, alt_idx;
 
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
-
-	if (!gspca_dev->present) {
-		ret = -ENODEV;
-		goto unlock;
-	}
-
 	/* reset the streaming variables */
 	gspca_dev->image = NULL;
 	gspca_dev->image_len = 0;
@@ -869,7 +861,7 @@
 	if (gspca_dev->sd_desc->isoc_init) {
 		ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
 		if (ret < 0)
-			goto unlock;
+			return ret;
 	}
 	xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
 				   : USB_ENDPOINT_XFER_ISOC;
@@ -880,8 +872,7 @@
 		ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer);
 		if (ep == NULL) {
 			pr_err("bad altsetting %d\n", gspca_dev->alt);
-			ret = -EIO;
-			goto out;
+			return -EIO;
 		}
 		ep_tb[0].alt = gspca_dev->alt;
 		alt_idx = 1;
@@ -892,8 +883,7 @@
 		alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb);
 		if (alt_idx <= 0) {
 			pr_err("no transfer endpoint found\n");
-			ret = -EIO;
-			goto unlock;
+			return -EIO;
 		}
 	}
 
@@ -988,8 +978,6 @@
 	}
 out:
 	gspca_input_create_urb(gspca_dev);
-unlock:
-	mutex_unlock(&gspca_dev->usb_lock);
 	return ret;
 }
 
@@ -1006,6 +994,8 @@
 
 	/* set the current control values to their default values
 	 * which may have changed in sd_init() */
+	/* does nothing if ctrl_handler == NULL */
+	v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
 	ctrl = gspca_dev->cam.ctrls;
 	if (ctrl != NULL) {
 		for (i = 0;
@@ -1057,77 +1047,50 @@
 static int vidioc_g_register(struct file *file, void *priv,
 			struct v4l2_dbg_register *reg)
 {
-	int ret;
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
 	if (!gspca_dev->sd_desc->get_chip_ident)
-		return -EINVAL;
+		return -ENOTTY;
 
 	if (!gspca_dev->sd_desc->get_register)
-		return -EINVAL;
+		return -ENOTTY;
 
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
 	gspca_dev->usb_err = 0;
-	if (gspca_dev->present)
-		ret = gspca_dev->sd_desc->get_register(gspca_dev, reg);
-	else
-		ret = -ENODEV;
-	mutex_unlock(&gspca_dev->usb_lock);
-
-	return ret;
+	return gspca_dev->sd_desc->get_register(gspca_dev, reg);
 }
 
 static int vidioc_s_register(struct file *file, void *priv,
 			struct v4l2_dbg_register *reg)
 {
-	int ret;
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
 	if (!gspca_dev->sd_desc->get_chip_ident)
-		return -EINVAL;
+		return -ENOTTY;
 
 	if (!gspca_dev->sd_desc->set_register)
-		return -EINVAL;
+		return -ENOTTY;
 
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
 	gspca_dev->usb_err = 0;
-	if (gspca_dev->present)
-		ret = gspca_dev->sd_desc->set_register(gspca_dev, reg);
-	else
-		ret = -ENODEV;
-	mutex_unlock(&gspca_dev->usb_lock);
-
-	return ret;
+	return gspca_dev->sd_desc->set_register(gspca_dev, reg);
 }
 #endif
 
 static int vidioc_g_chip_ident(struct file *file, void *priv,
 			struct v4l2_dbg_chip_ident *chip)
 {
-	int ret;
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
 	if (!gspca_dev->sd_desc->get_chip_ident)
-		return -EINVAL;
+		return -ENOTTY;
 
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
 	gspca_dev->usb_err = 0;
-	if (gspca_dev->present)
-		ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip);
-	else
-		ret = -ENODEV;
-	mutex_unlock(&gspca_dev->usb_lock);
-
-	return ret;
+	return gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip);
 }
 
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
 				struct v4l2_fmtdesc *fmtdesc)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	int i, j, index;
 	__u32 fmt_tb[8];
 
@@ -1169,7 +1132,7 @@
 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 			    struct v4l2_format *fmt)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	int mode;
 
 	mode = gspca_dev->curr_mode;
@@ -1214,7 +1177,7 @@
 			      void *priv,
 			      struct v4l2_format *fmt)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	int ret;
 
 	ret = try_fmt_vid_cap(gspca_dev, fmt);
@@ -1226,7 +1189,7 @@
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 			    struct v4l2_format *fmt)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	int ret;
 
 	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
@@ -1265,7 +1228,7 @@
 static int vidioc_enum_framesizes(struct file *file, void *priv,
 				  struct v4l2_frmsizeenum *fsize)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	int i;
 	__u32 index = 0;
 
@@ -1291,7 +1254,7 @@
 static int vidioc_enum_frameintervals(struct file *filp, void *priv,
 				      struct v4l2_frmivalenum *fival)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(filp);
 	int mode = wxh_to_mode(gspca_dev, fival->width, fival->height);
 	__u32 i;
 
@@ -1316,31 +1279,30 @@
 	return -EINVAL;
 }
 
-static void gspca_release(struct video_device *vfd)
+static void gspca_release(struct v4l2_device *v4l2_device)
 {
-	struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev);
+	struct gspca_dev *gspca_dev =
+		container_of(v4l2_device, struct gspca_dev, v4l2_dev);
 
 	PDEBUG(D_PROBE, "%s released",
 		video_device_node_name(&gspca_dev->vdev));
 
+	v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler);
+	v4l2_device_unregister(&gspca_dev->v4l2_dev);
 	kfree(gspca_dev->usb_buf);
 	kfree(gspca_dev);
 }
 
 static int dev_open(struct file *file)
 {
-	struct gspca_dev *gspca_dev;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
 	PDEBUG(D_STREAM, "[%s] open", current->comm);
-	gspca_dev = (struct gspca_dev *) video_devdata(file);
-	if (!gspca_dev->present)
-		return -ENODEV;
 
 	/* protect the subdriver against rmmod */
 	if (!try_module_get(gspca_dev->module))
 		return -ENODEV;
 
-	file->private_data = gspca_dev;
 #ifdef GSPCA_DEBUG
 	/* activate the v4l2 debug */
 	if (gspca_debug & D_V4L2)
@@ -1350,49 +1312,44 @@
 		gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
 					| V4L2_DEBUG_IOCTL_ARG);
 #endif
-	return 0;
+	return v4l2_fh_open(file);
 }
 
 static int dev_close(struct file *file)
 {
-	struct gspca_dev *gspca_dev = file->private_data;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
 	PDEBUG(D_STREAM, "[%s] close", current->comm);
-	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+
+	/* Needed for gspca_stream_off, always lock before queue_lock! */
+	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
 		return -ERESTARTSYS;
 
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock)) {
+		mutex_unlock(&gspca_dev->usb_lock);
+		return -ERESTARTSYS;
+	}
+
 	/* if the file did the capture, free the streaming resources */
 	if (gspca_dev->capt_file == file) {
-		if (gspca_dev->streaming) {
-			mutex_lock(&gspca_dev->usb_lock);
-			gspca_dev->usb_err = 0;
+		if (gspca_dev->streaming)
 			gspca_stream_off(gspca_dev);
-			mutex_unlock(&gspca_dev->usb_lock);
-		}
 		frame_free(gspca_dev);
 	}
-	file->private_data = NULL;
 	module_put(gspca_dev->module);
 	mutex_unlock(&gspca_dev->queue_lock);
+	mutex_unlock(&gspca_dev->usb_lock);
 
 	PDEBUG(D_STREAM, "close done");
 
-	return 0;
+	return v4l2_fh_release(file);
 }
 
 static int vidioc_querycap(struct file *file, void  *priv,
 			   struct v4l2_capability *cap)
 {
-	struct gspca_dev *gspca_dev = priv;
-	int ret;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
-	/* protect the access to the usb device */
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
-	if (!gspca_dev->present) {
-		ret = -ENODEV;
-		goto out;
-	}
 	strlcpy((char *) cap->driver, gspca_dev->sd_desc->name,
 			sizeof cap->driver);
 	if (gspca_dev->dev->product != NULL) {
@@ -1406,13 +1363,11 @@
 	}
 	usb_make_path(gspca_dev->dev, (char *) cap->bus_info,
 			sizeof(cap->bus_info));
-	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
 			  | V4L2_CAP_STREAMING
 			  | V4L2_CAP_READWRITE;
-	ret = 0;
-out:
-	mutex_unlock(&gspca_dev->usb_lock);
-	return ret;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
 }
 
 static int get_ctrl(struct gspca_dev *gspca_dev,
@@ -1435,7 +1390,7 @@
 static int vidioc_queryctrl(struct file *file, void *priv,
 			   struct v4l2_queryctrl *q_ctrl)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	const struct ctrl *ctrls;
 	struct gspca_ctrl *gspca_ctrl;
 	int i, idx;
@@ -1478,10 +1433,10 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 			 struct v4l2_control *ctrl)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	const struct ctrl *ctrls;
 	struct gspca_ctrl *gspca_ctrl;
-	int idx, ret;
+	int idx;
 
 	idx = get_ctrl(gspca_dev, ctrl->id);
 	if (idx < 0)
@@ -1501,74 +1456,52 @@
 			return -ERANGE;
 	}
 	PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
-	if (!gspca_dev->present) {
-		ret = -ENODEV;
-		goto out;
-	}
 	gspca_dev->usb_err = 0;
-	if (ctrls->set != NULL) {
-		ret = ctrls->set(gspca_dev, ctrl->value);
-		goto out;
-	}
+	if (ctrls->set != NULL)
+		return ctrls->set(gspca_dev, ctrl->value);
 	if (gspca_ctrl != NULL) {
 		gspca_ctrl->val = ctrl->value;
 		if (ctrls->set_control != NULL
 		 && gspca_dev->streaming)
 			ctrls->set_control(gspca_dev);
 	}
-	ret = gspca_dev->usb_err;
-out:
-	mutex_unlock(&gspca_dev->usb_lock);
-	return ret;
+	return gspca_dev->usb_err;
 }
 
 static int vidioc_g_ctrl(struct file *file, void *priv,
 			 struct v4l2_control *ctrl)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	const struct ctrl *ctrls;
-	int idx, ret;
+	int idx;
 
 	idx = get_ctrl(gspca_dev, ctrl->id);
 	if (idx < 0)
 		return -EINVAL;
 	ctrls = &gspca_dev->sd_desc->ctrls[idx];
 
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
-	if (!gspca_dev->present) {
-		ret = -ENODEV;
-		goto out;
-	}
 	gspca_dev->usb_err = 0;
-	if (ctrls->get != NULL) {
-		ret = ctrls->get(gspca_dev, &ctrl->value);
-		goto out;
-	}
+	if (ctrls->get != NULL)
+		return ctrls->get(gspca_dev, &ctrl->value);
 	if (gspca_dev->cam.ctrls != NULL)
 		ctrl->value = gspca_dev->cam.ctrls[idx].val;
-	ret = 0;
-out:
-	mutex_unlock(&gspca_dev->usb_lock);
-	return ret;
+	return 0;
 }
 
 static int vidioc_querymenu(struct file *file, void *priv,
 			    struct v4l2_querymenu *qmenu)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
 	if (!gspca_dev->sd_desc->querymenu)
-		return -EINVAL;
+		return -ENOTTY;
 	return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu);
 }
 
 static int vidioc_enum_input(struct file *file, void *priv,
 				struct v4l2_input *input)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
 	if (input->index != 0)
 		return -EINVAL;
@@ -1595,7 +1528,7 @@
 static int vidioc_reqbufs(struct file *file, void *priv,
 			  struct v4l2_requestbuffers *rb)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	int i, ret = 0, streaming;
 
 	i = rb->memory;			/* (avoid compilation warning) */
@@ -1635,10 +1568,7 @@
 	/* stop streaming */
 	streaming = gspca_dev->streaming;
 	if (streaming) {
-		mutex_lock(&gspca_dev->usb_lock);
-		gspca_dev->usb_err = 0;
 		gspca_stream_off(gspca_dev);
-		mutex_unlock(&gspca_dev->usb_lock);
 
 		/* Don't restart the stream when switching from read
 		 * to mmap mode */
@@ -1666,7 +1596,7 @@
 static int vidioc_querybuf(struct file *file, void *priv,
 			   struct v4l2_buffer *v4l2_buf)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	struct gspca_frame *frame;
 
 	if (v4l2_buf->index < 0
@@ -1681,7 +1611,7 @@
 static int vidioc_streamon(struct file *file, void *priv,
 			   enum v4l2_buf_type buf_type)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	int ret;
 
 	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -1722,7 +1652,7 @@
 static int vidioc_streamoff(struct file *file, void *priv,
 				enum v4l2_buf_type buf_type)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	int ret;
 
 	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -1743,13 +1673,7 @@
 	}
 
 	/* stop streaming */
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
-		ret = -ERESTARTSYS;
-		goto out;
-	}
-	gspca_dev->usb_err = 0;
 	gspca_stream_off(gspca_dev);
-	mutex_unlock(&gspca_dev->usb_lock);
 	/* In case another thread is waiting in dqbuf */
 	wake_up_interruptible(&gspca_dev->wq);
 
@@ -1766,71 +1690,44 @@
 static int vidioc_g_jpegcomp(struct file *file, void *priv,
 			struct v4l2_jpegcompression *jpegcomp)
 {
-	struct gspca_dev *gspca_dev = priv;
-	int ret;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
 	if (!gspca_dev->sd_desc->get_jcomp)
-		return -EINVAL;
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
+		return -ENOTTY;
 	gspca_dev->usb_err = 0;
-	if (gspca_dev->present)
-		ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
-	else
-		ret = -ENODEV;
-	mutex_unlock(&gspca_dev->usb_lock);
-	return ret;
+	return gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
 }
 
 static int vidioc_s_jpegcomp(struct file *file, void *priv,
 			struct v4l2_jpegcompression *jpegcomp)
 {
-	struct gspca_dev *gspca_dev = priv;
-	int ret;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 
 	if (!gspca_dev->sd_desc->set_jcomp)
-		return -EINVAL;
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
+		return -ENOTTY;
 	gspca_dev->usb_err = 0;
-	if (gspca_dev->present)
-		ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
-	else
-		ret = -ENODEV;
-	mutex_unlock(&gspca_dev->usb_lock);
-	return ret;
+	return gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
 }
 
 static int vidioc_g_parm(struct file *filp, void *priv,
 			struct v4l2_streamparm *parm)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(filp);
 
 	parm->parm.capture.readbuffers = gspca_dev->nbufread;
 
 	if (gspca_dev->sd_desc->get_streamparm) {
-		int ret;
-
-		if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-			return -ERESTARTSYS;
-		if (gspca_dev->present) {
-			gspca_dev->usb_err = 0;
-			gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
-			ret = gspca_dev->usb_err;
-		} else {
-			ret = -ENODEV;
-		}
-		mutex_unlock(&gspca_dev->usb_lock);
-		return ret;
+		gspca_dev->usb_err = 0;
+		gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
+		return gspca_dev->usb_err;
 	}
-
 	return 0;
 }
 
 static int vidioc_s_parm(struct file *filp, void *priv,
 			struct v4l2_streamparm *parm)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(filp);
 	int n;
 
 	n = parm->parm.capture.readbuffers;
@@ -1840,19 +1737,9 @@
 		gspca_dev->nbufread = n;
 
 	if (gspca_dev->sd_desc->set_streamparm) {
-		int ret;
-
-		if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-			return -ERESTARTSYS;
-		if (gspca_dev->present) {
-			gspca_dev->usb_err = 0;
-			gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
-			ret = gspca_dev->usb_err;
-		} else {
-			ret = -ENODEV;
-		}
-		mutex_unlock(&gspca_dev->usb_lock);
-		return ret;
+		gspca_dev->usb_err = 0;
+		gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
+		return gspca_dev->usb_err;
 	}
 
 	return 0;
@@ -1860,7 +1747,7 @@
 
 static int dev_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct gspca_dev *gspca_dev = file->private_data;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	struct gspca_frame *frame;
 	struct page *page;
 	unsigned long addr, start, size;
@@ -1872,10 +1759,6 @@
 
 	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
 		return -ERESTARTSYS;
-	if (!gspca_dev->present) {
-		ret = -ENODEV;
-		goto out;
-	}
 	if (gspca_dev->capt_file != file) {
 		ret = -EINVAL;
 		goto out;
@@ -1963,7 +1846,7 @@
 static int vidioc_dqbuf(struct file *file, void *priv,
 			struct v4l2_buffer *v4l2_buf)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	struct gspca_frame *frame;
 	int i, j, ret;
 
@@ -2003,14 +1886,6 @@
 
 	gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
 
-	if (gspca_dev->sd_desc->dq_callback) {
-		mutex_lock(&gspca_dev->usb_lock);
-		gspca_dev->usb_err = 0;
-		if (gspca_dev->present)
-			gspca_dev->sd_desc->dq_callback(gspca_dev);
-		mutex_unlock(&gspca_dev->usb_lock);
-	}
-
 	frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
 	memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
 	PDEBUG(D_FRAM, "dqbuf %d", j);
@@ -2027,6 +1902,15 @@
 	}
 out:
 	mutex_unlock(&gspca_dev->queue_lock);
+
+	if (ret == 0 && gspca_dev->sd_desc->dq_callback) {
+		mutex_lock(&gspca_dev->usb_lock);
+		gspca_dev->usb_err = 0;
+		if (gspca_dev->present)
+			gspca_dev->sd_desc->dq_callback(gspca_dev);
+		mutex_unlock(&gspca_dev->usb_lock);
+	}
+
 	return ret;
 }
 
@@ -2039,7 +1923,7 @@
 static int vidioc_qbuf(struct file *file, void *priv,
 			struct v4l2_buffer *v4l2_buf)
 {
-	struct gspca_dev *gspca_dev = priv;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	struct gspca_frame *frame;
 	int i, index, ret;
 
@@ -2098,6 +1982,10 @@
 	int i, ret;
 
 	PDEBUG(D_STREAM, "read alloc");
+
+	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+		return -ERESTARTSYS;
+
 	if (gspca_dev->nframes == 0) {
 		struct v4l2_requestbuffers rb;
 
@@ -2108,7 +1996,7 @@
 		ret = vidioc_reqbufs(file, gspca_dev, &rb);
 		if (ret != 0) {
 			PDEBUG(D_STREAM, "read reqbuf err %d", ret);
-			return ret;
+			goto out;
 		}
 		memset(&v4l2_buf, 0, sizeof v4l2_buf);
 		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -2118,61 +2006,69 @@
 			ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
 			if (ret != 0) {
 				PDEBUG(D_STREAM, "read qbuf err: %d", ret);
-				return ret;
+				goto out;
 			}
 		}
-		gspca_dev->memory = GSPCA_MEMORY_READ;
 	}
 
 	/* start streaming */
 	ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE);
 	if (ret != 0)
 		PDEBUG(D_STREAM, "read streamon err %d", ret);
+out:
+	mutex_unlock(&gspca_dev->usb_lock);
 	return ret;
 }
 
 static unsigned int dev_poll(struct file *file, poll_table *wait)
 {
-	struct gspca_dev *gspca_dev = file->private_data;
-	int ret;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	unsigned long req_events = poll_requested_events(wait);
+	int ret = 0;
 
 	PDEBUG(D_FRAM, "poll");
 
-	poll_wait(file, &gspca_dev->wq, wait);
+	if (req_events & POLLPRI)
+		ret |= v4l2_ctrl_poll(file, wait);
 
-	/* if reqbufs is not done, the user would use read() */
-	if (gspca_dev->memory == GSPCA_MEMORY_NO) {
-		ret = read_alloc(gspca_dev, file);
-		if (ret != 0)
-			return POLLERR;
+	if (req_events & (POLLIN | POLLRDNORM)) {
+		/* if reqbufs is not done, the user would use read() */
+		if (gspca_dev->memory == GSPCA_MEMORY_NO) {
+			if (read_alloc(gspca_dev, file) != 0) {
+				ret |= POLLERR;
+				goto out;
+			}
+		}
+
+		poll_wait(file, &gspca_dev->wq, wait);
+
+		/* check if an image has been received */
+		if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) {
+			ret |= POLLERR;
+			goto out;
+		}
+		if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
+			ret |= POLLIN | POLLRDNORM;
+		mutex_unlock(&gspca_dev->queue_lock);
 	}
 
-	if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
-		return POLLERR;
-
-	/* check if an image has been received */
-	if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
-		ret = POLLIN | POLLRDNORM;	/* yes */
-	else
-		ret = 0;
-	mutex_unlock(&gspca_dev->queue_lock);
+out:
 	if (!gspca_dev->present)
-		return POLLHUP;
+		ret |= POLLHUP;
+
 	return ret;
 }
 
 static ssize_t dev_read(struct file *file, char __user *data,
 		    size_t count, loff_t *ppos)
 {
-	struct gspca_dev *gspca_dev = file->private_data;
+	struct gspca_dev *gspca_dev = video_drvdata(file);
 	struct gspca_frame *frame;
 	struct v4l2_buffer v4l2_buf;
 	struct timeval timestamp;
 	int n, ret, ret2;
 
 	PDEBUG(D_FRAM, "read (%zd)", count);
-	if (!gspca_dev->present)
-		return -ENODEV;
 	if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */
 		ret = read_alloc(gspca_dev, file);
 		if (ret != 0)
@@ -2266,13 +2162,15 @@
 	.vidioc_s_register	= vidioc_s_register,
 #endif
 	.vidioc_g_chip_ident	= vidioc_g_chip_ident,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static const struct video_device gspca_template = {
 	.name = "gspca main driver",
 	.fops = &dev_fops,
 	.ioctl_ops = &dev_ioctl_ops,
-	.release = gspca_release,
+	.release = video_device_release_empty, /* We use v4l2_dev.release */
 };
 
 /* initialize the controls */
@@ -2344,9 +2242,24 @@
 		}
 	}
 
+	gspca_dev->v4l2_dev.release = gspca_release;
+	ret = v4l2_device_register(&intf->dev, &gspca_dev->v4l2_dev);
+	if (ret)
+		goto out;
 	gspca_dev->sd_desc = sd_desc;
 	gspca_dev->nbufread = 2;
 	gspca_dev->empty_packet = -1;	/* don't check the empty packets */
+	gspca_dev->vdev = gspca_template;
+	gspca_dev->vdev.v4l2_dev = &gspca_dev->v4l2_dev;
+	video_set_drvdata(&gspca_dev->vdev, gspca_dev);
+	set_bit(V4L2_FL_USE_FH_PRIO, &gspca_dev->vdev.flags);
+	gspca_dev->module = module;
+	gspca_dev->present = 1;
+
+	mutex_init(&gspca_dev->usb_lock);
+	gspca_dev->vdev.lock = &gspca_dev->usb_lock;
+	mutex_init(&gspca_dev->queue_lock);
+	init_waitqueue_head(&gspca_dev->wq);
 
 	/* configure the subdriver and initialize the USB device */
 	ret = sd_desc->config(gspca_dev, id);
@@ -2357,21 +2270,26 @@
 	ret = sd_desc->init(gspca_dev);
 	if (ret < 0)
 		goto out;
+	if (sd_desc->init_controls)
+		ret = sd_desc->init_controls(gspca_dev);
+	if (ret < 0)
+		goto out;
 	gspca_set_default_mode(gspca_dev);
 
 	ret = gspca_input_connect(gspca_dev);
 	if (ret)
 		goto out;
 
-	mutex_init(&gspca_dev->usb_lock);
-	mutex_init(&gspca_dev->queue_lock);
-	init_waitqueue_head(&gspca_dev->wq);
+	/*
+	 * Don't take usb_lock for these ioctls. This improves latency if
+	 * usb_lock is taken for a long time, e.g. when changing a control
+	 * value, and a new frame is ready to be dequeued.
+	 */
+	v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_DQBUF);
+	v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QBUF);
+	v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QUERYBUF);
 
 	/* init video stuff */
-	memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);
-	gspca_dev->vdev.parent = &intf->dev;
-	gspca_dev->module = module;
-	gspca_dev->present = 1;
 	ret = video_register_device(&gspca_dev->vdev,
 				  VFL_TYPE_GRABBER,
 				  -1);
@@ -2391,6 +2309,7 @@
 	if (gspca_dev->input_dev)
 		input_unregister_device(gspca_dev->input_dev);
 #endif
+	v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler);
 	kfree(gspca_dev->usb_buf);
 	kfree(gspca_dev);
 	return ret;
@@ -2437,11 +2356,12 @@
 
 	PDEBUG(D_PROBE, "%s disconnect",
 		video_device_node_name(&gspca_dev->vdev));
+
 	mutex_lock(&gspca_dev->usb_lock);
 
+	usb_set_intfdata(intf, NULL);
+	gspca_dev->dev = NULL;
 	gspca_dev->present = 0;
-	wake_up_interruptible(&gspca_dev->wq);
-
 	destroy_urbs(gspca_dev);
 
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
@@ -2452,18 +2372,19 @@
 		input_unregister_device(input_dev);
 	}
 #endif
+	/* Free subdriver's streaming resources / stop sd workqueue(s) */
+	if (gspca_dev->sd_desc->stop0 && gspca_dev->streaming)
+		gspca_dev->sd_desc->stop0(gspca_dev);
+	gspca_dev->streaming = 0;
+	wake_up_interruptible(&gspca_dev->wq);
 
-	/* the device is freed at exit of this function */
-	gspca_dev->dev = NULL;
-	mutex_unlock(&gspca_dev->usb_lock);
-
-	usb_set_intfdata(intf, NULL);
-
-	/* release the device */
-	/* (this will call gspca_release() immediately or on last close) */
+	v4l2_device_disconnect(&gspca_dev->v4l2_dev);
 	video_unregister_device(&gspca_dev->vdev);
 
-/*	PDEBUG(D_PROBE, "disconnect complete"); */
+	mutex_unlock(&gspca_dev->usb_lock);
+
+	/* (this will call gspca_release() immediately or on last close) */
+	v4l2_device_put(&gspca_dev->v4l2_dev);
 }
 EXPORT_SYMBOL(gspca_disconnect);
 
@@ -2474,7 +2395,9 @@
 
 	if (!gspca_dev->streaming)
 		return 0;
+	mutex_lock(&gspca_dev->usb_lock);
 	gspca_dev->frozen = 1;		/* avoid urb error messages */
+	gspca_dev->usb_err = 0;
 	if (gspca_dev->sd_desc->stopN)
 		gspca_dev->sd_desc->stopN(gspca_dev);
 	destroy_urbs(gspca_dev);
@@ -2482,6 +2405,7 @@
 	gspca_set_alt0(gspca_dev);
 	if (gspca_dev->sd_desc->stop0)
 		gspca_dev->sd_desc->stop0(gspca_dev);
+	mutex_unlock(&gspca_dev->usb_lock);
 	return 0;
 }
 EXPORT_SYMBOL(gspca_suspend);
@@ -2489,105 +2413,28 @@
 int gspca_resume(struct usb_interface *intf)
 {
 	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+	int streaming, ret = 0;
 
+	mutex_lock(&gspca_dev->usb_lock);
 	gspca_dev->frozen = 0;
+	gspca_dev->usb_err = 0;
 	gspca_dev->sd_desc->init(gspca_dev);
 	gspca_input_create_urb(gspca_dev);
-	if (gspca_dev->streaming)
-		return gspca_init_transfer(gspca_dev);
-	return 0;
+	/*
+	 * Most subdrivers send all ctrl values on sd_start and thus
+	 * only write to the device registers on s_ctrl when streaming ->
+	 * Clear streaming to avoid setting all ctrls twice.
+	 */
+	streaming = gspca_dev->streaming;
+	gspca_dev->streaming = 0;
+	v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
+	if (streaming)
+		ret = gspca_init_transfer(gspca_dev);
+	mutex_unlock(&gspca_dev->usb_lock);
+	return ret;
 }
 EXPORT_SYMBOL(gspca_resume);
 #endif
-/* -- cam driver utility functions -- */
-
-/* auto gain and exposure algorithm based on the knee algorithm described here:
-   http://ytse.tricolour.net/docs/LowLightOptimization.html
-
-   Returns 0 if no changes were made, 1 if the gain and or exposure settings
-   where changed. */
-int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
-	int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee)
-{
-	int i, steps, gain, orig_gain, exposure, orig_exposure, autogain;
-	const struct ctrl *gain_ctrl = NULL;
-	const struct ctrl *exposure_ctrl = NULL;
-	const struct ctrl *autogain_ctrl = NULL;
-	int retval = 0;
-
-	for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-		if (gspca_dev->ctrl_dis & (1 << i))
-			continue;
-		if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN)
-			gain_ctrl = &gspca_dev->sd_desc->ctrls[i];
-		if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE)
-			exposure_ctrl = &gspca_dev->sd_desc->ctrls[i];
-		if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN)
-			autogain_ctrl = &gspca_dev->sd_desc->ctrls[i];
-	}
-	if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) {
-		PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called "
-			"on cam without (auto)gain/exposure");
-		return 0;
-	}
-
-	if (gain_ctrl->get(gspca_dev, &gain) ||
-			exposure_ctrl->get(gspca_dev, &exposure) ||
-			autogain_ctrl->get(gspca_dev, &autogain) || !autogain)
-		return 0;
-
-	orig_gain = gain;
-	orig_exposure = exposure;
-
-	/* If we are of a multiple of deadzone, do multiple steps to reach the
-	   desired lumination fast (with the risc of a slight overshoot) */
-	steps = abs(desired_avg_lum - avg_lum) / deadzone;
-
-	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
-		avg_lum, desired_avg_lum, steps);
-
-	for (i = 0; i < steps; i++) {
-		if (avg_lum > desired_avg_lum) {
-			if (gain > gain_knee)
-				gain--;
-			else if (exposure > exposure_knee)
-				exposure--;
-			else if (gain > gain_ctrl->qctrl.default_value)
-				gain--;
-			else if (exposure > exposure_ctrl->qctrl.minimum)
-				exposure--;
-			else if (gain > gain_ctrl->qctrl.minimum)
-				gain--;
-			else
-				break;
-		} else {
-			if (gain < gain_ctrl->qctrl.default_value)
-				gain++;
-			else if (exposure < exposure_knee)
-				exposure++;
-			else if (gain < gain_knee)
-				gain++;
-			else if (exposure < exposure_ctrl->qctrl.maximum)
-				exposure++;
-			else if (gain < gain_ctrl->qctrl.maximum)
-				gain++;
-			else
-				break;
-		}
-	}
-
-	if (gain != orig_gain) {
-		gain_ctrl->set(gspca_dev, gain);
-		retval = 1;
-	}
-	if (exposure != orig_exposure) {
-		exposure_ctrl->set(gspca_dev, exposure);
-		retval = 1;
-	}
-
-	return retval;
-}
-EXPORT_SYMBOL(gspca_auto_gain_n_exposure);
 
 /* -- module insert / remove -- */
 static int __init gspca_init(void)
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 589009f..dc688c7 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -6,6 +6,8 @@
 #include <linux/usb.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
 #include <linux/mutex.h>
 
 /* compilation option */
@@ -115,6 +117,7 @@
 /* mandatory operations */
 	cam_cf_op config;	/* called on probe */
 	cam_op init;		/* called on probe and resume */
+	cam_op init_controls;	/* called on probe */
 	cam_op start;		/* called on stream on after URBs creation */
 	cam_pkt_op pkt_scan;
 /* optional operations */
@@ -158,8 +161,10 @@
 struct gspca_dev {
 	struct video_device vdev;	/* !! must be the first item */
 	struct module *module;		/* subdriver handling the device */
+	struct v4l2_device v4l2_dev;
 	struct usb_device *dev;
 	struct file *capt_file;		/* file doing video capture */
+					/* protected by queue_lock */
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 	struct input_dev *input_dev;
 	char phys[64];			/* physical device path */
@@ -169,6 +174,16 @@
 	const struct sd_desc *sd_desc;		/* subdriver description */
 	unsigned ctrl_dis;		/* disabled controls (bit map) */
 	unsigned ctrl_inac;		/* inactive controls (bit map) */
+	struct v4l2_ctrl_handler ctrl_handler;
+
+	/* autogain and exposure or gain control cluster, these are global as
+	   the autogain/exposure functions in autogain_functions.c use them */
+	struct {
+		struct v4l2_ctrl *autogain;
+		struct v4l2_ctrl *exposure;
+		struct v4l2_ctrl *gain;
+		int exp_too_low_cnt, exp_too_high_cnt;
+	};
 
 #define USB_BUF_SZ 64
 	__u8 *usb_buf;				/* buffer for USB exchanges */
@@ -189,7 +204,7 @@
 	u8 fr_o;				/* next frame to dequeue */
 	__u8 last_packet_type;
 	__s8 empty_packet;		/* if (-1) don't check empty packets */
-	__u8 streaming;
+	__u8 streaming;			/* protected by both mutexes (*) */
 
 	__u8 curr_mode;			/* current camera mode */
 	__u32 pixfmt;			/* current mode parameters */
@@ -211,6 +226,10 @@
 	__u8 iface;			/* USB interface number */
 	__u8 alt;			/* USB alternate setting */
 	u8 audio;			/* presence of audio device */
+
+	/* (*) These variables are proteced by both usb_lock and queue_lock,
+	   that is any code setting them is holding *both*, which means that
+	   any code getting them needs to hold at least one of them */
 };
 
 int gspca_dev_probe(struct usb_interface *intf,
@@ -232,6 +251,9 @@
 int gspca_suspend(struct usb_interface *intf, pm_message_t message);
 int gspca_resume(struct usb_interface *intf);
 #endif
-int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
+int gspca_expo_autogain(struct gspca_dev *gspca_dev, int avg_lum,
 	int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
+int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev,
+        int avg_lum, int desired_avg_lum, int deadzone);
+
 #endif /* GSPCAV2_H */
diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c
index 53f58ef..9c591c7 100644
--- a/drivers/media/video/gspca/jl2005bcd.c
+++ b/drivers/media/video/gspca/jl2005bcd.c
@@ -335,7 +335,11 @@
 		goto quit_stream;
 	}
 
-	while (gspca_dev->present && gspca_dev->streaming) {
+	while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			break;
+#endif
 		/* Check if this is a new frame. If so, start the frame first */
 		if (!header_read) {
 			mutex_lock(&gspca_dev->usb_lock);
@@ -367,7 +371,7 @@
 					buffer, act_len);
 			header_read = 1;
 		}
-		while (bytes_left > 0 && gspca_dev->present) {
+		while (bytes_left > 0 && gspca_dev->dev) {
 			data_len = bytes_left > JL2005C_MAX_TRANSFER ?
 				JL2005C_MAX_TRANSFER : bytes_left;
 			ret = usb_bulk_msg(gspca_dev->dev,
@@ -390,7 +394,7 @@
 		}
 	}
 quit_stream:
-	if (gspca_dev->present) {
+	if (gspca_dev->dev) {
 		mutex_lock(&gspca_dev->usb_lock);
 		jl2005c_stop(gspca_dev);
 		mutex_unlock(&gspca_dev->usb_lock);
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index b023146..ec7b21e 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -30,22 +30,19 @@
 MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-/* controls */
-enum e_ctrl {
-	BRIGHTNESS,
-	COLORS,
-	GAMMA,
-	SHARPNESS,
-	ILLUM_TOP,
-	ILLUM_BOT,
-	NCTRLS		/* number of controls */
-};
-
 /* specific webcam descriptor */
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
 
-	struct gspca_ctrl ctrls[NCTRLS];
+	struct v4l2_ctrl *brightness;
+	struct v4l2_ctrl *saturation;
+	struct v4l2_ctrl *sharpness;
+	struct v4l2_ctrl *gamma;
+	struct { /* illuminator control cluster */
+		struct v4l2_ctrl *illum_top;
+		struct v4l2_ctrl *illum_bottom;
+	};
+	struct v4l2_ctrl *jpegqual;
 
 	u8 quality;
 #define QUALITY_MIN 40
@@ -56,89 +53,10 @@
 };
 
 /* V4L2 controls supported by the driver */
-static void setbrightness(struct gspca_dev *gspca_dev);
-static void setcolors(struct gspca_dev *gspca_dev);
-static void setgamma(struct gspca_dev *gspca_dev);
-static void setsharpness(struct gspca_dev *gspca_dev);
-static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
-
-static const struct ctrl sd_ctrls[NCTRLS] = {
-[BRIGHTNESS] = {
-	    {
-		.id      = V4L2_CID_BRIGHTNESS,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Brightness",
-		.minimum = 0,
-		.maximum = 30,
-		.step    = 1,
-		.default_value = 15,
-	    },
-	    .set_control = setbrightness
-	},
-[COLORS] = {
-	    {
-		.id      = V4L2_CID_SATURATION,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Color",
-		.minimum = 1,
-		.maximum = 255,
-		.step    = 1,
-		.default_value = 200,
-	    },
-	    .set_control = setcolors
-	},
-[GAMMA] = {
-	    {
-		.id      = V4L2_CID_GAMMA,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Gamma",
-		.minimum = 0,
-		.maximum = 3,
-		.step    = 1,
-		.default_value = 1,
-	    },
-	    .set_control = setgamma
-	},
-[SHARPNESS] = {
-	    {
-		.id	 = V4L2_CID_SHARPNESS,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Sharpness",
-		.minimum = 0,
-		.maximum = 2,
-		.step    = 1,
-		.default_value = 1,
-	    },
-	    .set_control = setsharpness
-	},
-[ILLUM_TOP] = {
-	    {
-		.id	 = V4L2_CID_ILLUMINATORS_1,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Top illuminator",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-		.default_value = 0,
-		.flags = V4L2_CTRL_FLAG_UPDATE,
-	    },
-	    .set = sd_setilluminator1
-	},
-[ILLUM_BOT] = {
-	    {
-		.id	 = V4L2_CID_ILLUMINATORS_2,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Bottom illuminator",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-		.default_value = 0,
-		.flags = V4L2_CTRL_FLAG_UPDATE,
-	    },
-	    .set = sd_setilluminator2
-	},
-};
+static void setbrightness(struct gspca_dev *gspca_dev, s32 val);
+static void setcolors(struct gspca_dev *gspca_dev, s32 val);
+static void setgamma(struct gspca_dev *gspca_dev, s32 val);
+static void setsharpness(struct gspca_dev *gspca_dev, s32 val);
 
 static const struct v4l2_pix_format vga_mode[] = {
 	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -198,59 +116,130 @@
 	reg_w(gspca_dev, 4);
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
+static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
 	gspca_dev->usb_buf[0] = 0x61;
-	gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val;
+	gspca_dev->usb_buf[1] = val;
 	reg_w(gspca_dev, 2);
 }
 
-static void setcolors(struct gspca_dev *gspca_dev)
+static void setcolors(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-	s16 val;
-
-	val = sd->ctrls[COLORS].val;
 	gspca_dev->usb_buf[0] = 0x5f;
 	gspca_dev->usb_buf[1] = val << 3;
 	gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;
 	reg_w(gspca_dev, 3);
 }
 
-static void setgamma(struct gspca_dev *gspca_dev)
+static void setgamma(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
 	gspca_dev->usb_buf[0] = 0x06;
-	gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40;
+	gspca_dev->usb_buf[1] = val * 0x40;
 	reg_w(gspca_dev, 2);
 }
 
-static void setsharpness(struct gspca_dev *gspca_dev)
+static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
 	gspca_dev->usb_buf[0] = 0x67;
-	gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
+	gspca_dev->usb_buf[1] = val * 4 + 3;
 	reg_w(gspca_dev, 2);
 }
 
-static void setilluminators(struct gspca_dev *gspca_dev)
+static void setilluminators(struct gspca_dev *gspca_dev, bool top, bool bottom)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
+	/* both are off if not streaming */
 	gspca_dev->usb_buf[0] = 0x22;
-	if (sd->ctrls[ILLUM_TOP].val)
+	if (top)
 		gspca_dev->usb_buf[1] = 0x76;
-	else if (sd->ctrls[ILLUM_BOT].val)
+	else if (bottom)
 		gspca_dev->usb_buf[1] = 0x7a;
 	else
 		gspca_dev->usb_buf[1] = 0x7e;
 	reg_w(gspca_dev, 2);
 }
 
+static int mars_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	gspca_dev->usb_err = 0;
+
+	if (ctrl->id == V4L2_CID_ILLUMINATORS_1) {
+		/* only one can be on at a time */
+		if (ctrl->is_new && ctrl->val)
+			sd->illum_bottom->val = 0;
+		if (sd->illum_bottom->is_new && sd->illum_bottom->val)
+			sd->illum_top->val = 0;
+	}
+
+	if (!gspca_dev->streaming)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		setbrightness(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		setcolors(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_GAMMA:
+		setgamma(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_ILLUMINATORS_1:
+		setilluminators(gspca_dev, sd->illum_top->val,
+					   sd->illum_bottom->val);
+		break;
+	case V4L2_CID_SHARPNESS:
+		setsharpness(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+		jpeg_set_qual(sd->jpeg_hdr, ctrl->val);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops mars_ctrl_ops = {
+	.s_ctrl = mars_s_ctrl,
+};
+
+/* this function is called at probe time */
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 7);
+	sd->brightness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 30, 1, 15);
+	sd->saturation = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 200);
+	sd->gamma = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+			V4L2_CID_GAMMA, 0, 3, 1, 1);
+	sd->sharpness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+			V4L2_CID_SHARPNESS, 0, 2, 1, 1);
+	sd->illum_top = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+			V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+	sd->illum_top->flags |= V4L2_CTRL_FLAG_UPDATE;
+	sd->illum_bottom = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+			V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
+	sd->illum_bottom->flags |= V4L2_CTRL_FLAG_UPDATE;
+	sd->jpegqual = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+			V4L2_CID_JPEG_COMPRESSION_QUALITY,
+			QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF);
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+	v4l2_ctrl_cluster(2, &sd->illum_top);
+	return 0;
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
 			const struct usb_device_id *id)
@@ -261,7 +250,6 @@
 	cam = &gspca_dev->cam;
 	cam->cam_mode = vga_mode;
 	cam->nmodes = ARRAY_SIZE(vga_mode);
-	cam->ctrls = sd->ctrls;
 	sd->quality = QUALITY_DEF;
 	return 0;
 }
@@ -269,7 +257,6 @@
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-	gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
 	return 0;
 }
 
@@ -282,7 +269,7 @@
 	/* create the JPEG header */
 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x21);		/* JPEG 422 */
-	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+	jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
 
 	data = gspca_dev->usb_buf;
 
@@ -301,7 +288,7 @@
 	data[5] = 0x30;		/* reg 4, MI, PAS5101 :
 				 *	0x30 for 24mhz , 0x28 for 12mhz */
 	data[6] = 0x02;		/* reg 5, H start - was 0x04 */
-	data[7] = sd->ctrls[GAMMA].val * 0x40;	/* reg 0x06: gamma */
+	data[7] = v4l2_ctrl_g_ctrl(sd->gamma) * 0x40;	/* reg 0x06: gamma */
 	data[8] = 0x01;		/* reg 7, V start - was 0x03 */
 /*	if (h_size == 320 ) */
 /*		data[9]= 0x56;	 * reg 8, 24MHz, 2:1 scale down */
@@ -333,16 +320,16 @@
 				/* reg 0x5f/0x60 (LE) = saturation */
 				/* h (60): xxxx x100
 				 * l (5f): xxxx x000 */
-	data[2] = sd->ctrls[COLORS].val << 3;
-	data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04;
-	data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */
+	data[2] = v4l2_ctrl_g_ctrl(sd->saturation) << 3;
+	data[3] = ((v4l2_ctrl_g_ctrl(sd->saturation) >> 2) & 0xf8) | 0x04;
+	data[4] = v4l2_ctrl_g_ctrl(sd->brightness); /* reg 0x61 = brightness */
 	data[5] = 0x00;
 
 	reg_w(gspca_dev, 6);
 
 	data[0] = 0x67;
 /*jfm: from win trace*/
-	data[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
+	data[1] = v4l2_ctrl_g_ctrl(sd->sharpness) * 4 + 3;
 	data[2] = 0x14;
 	reg_w(gspca_dev, 3);
 
@@ -365,7 +352,9 @@
 	data[1] = 0x4d;		/* ISOC transferring enable... */
 	reg_w(gspca_dev, 2);
 
-	gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */
+	setilluminators(gspca_dev, v4l2_ctrl_g_ctrl(sd->illum_top),
+				   v4l2_ctrl_g_ctrl(sd->illum_bottom));
+
 	return gspca_dev->usb_err;
 }
 
@@ -373,11 +362,9 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
-	if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) {
-		sd->ctrls[ILLUM_TOP].val = 0;
-		sd->ctrls[ILLUM_BOT].val = 0;
-		setilluminators(gspca_dev);
+	if (v4l2_ctrl_g_ctrl(sd->illum_top) ||
+	    v4l2_ctrl_g_ctrl(sd->illum_bottom)) {
+		setilluminators(gspca_dev, false, false);
 		msleep(20);
 	}
 
@@ -424,43 +411,16 @@
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
-static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	/* only one illuminator may be on */
-	sd->ctrls[ILLUM_TOP].val = val;
-	if (val)
-		sd->ctrls[ILLUM_BOT].val = 0;
-	setilluminators(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	/* only one illuminator may be on */
-	sd->ctrls[ILLUM_BOT].val = val;
-	if (val)
-		sd->ctrls[ILLUM_TOP].val = 0;
-	setilluminators(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
 static int sd_set_jcomp(struct gspca_dev *gspca_dev,
 			struct v4l2_jpegcompression *jcomp)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
 
-	if (jcomp->quality < QUALITY_MIN)
-		sd->quality = QUALITY_MIN;
-	else if (jcomp->quality > QUALITY_MAX)
-		sd->quality = QUALITY_MAX;
-	else
-		sd->quality = jcomp->quality;
-	if (gspca_dev->streaming)
-		jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+	ret = v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
+	if (ret)
+		return ret;
+	jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
 	return 0;
 }
 
@@ -470,7 +430,7 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	memset(jcomp, 0, sizeof *jcomp);
-	jcomp->quality = sd->quality;
+	jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
 	jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
 			| V4L2_JPEG_MARKER_DQT;
 	return 0;
@@ -479,10 +439,9 @@
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
-	.ctrls = sd_ctrls,
-	.nctrls = NCTRLS,
 	.config = sd_config,
 	.init = sd_init,
+	.init_controls = sd_init_controls,
 	.start = sd_start,
 	.stopN = sd_stopN,
 	.pkt_scan = sd_pkt_scan,
@@ -513,6 +472,7 @@
 #ifdef CONFIG_PM
 	.suspend = gspca_suspend,
 	.resume = gspca_resume,
+	.reset_resume = gspca_resume,
 #endif
 };
 
diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c
index 7167cac..42e0219 100644
--- a/drivers/media/video/gspca/nw80x.c
+++ b/drivers/media/video/gspca/nw80x.c
@@ -2001,6 +2001,8 @@
 	return gspca_dev->usb_err;
 }
 
+#define WANT_REGULAR_AUTOGAIN
+#define WANT_COARSE_EXPO_AUTOGAIN
 #include "autogain_functions.h"
 
 static void do_autogain(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index 739e8a2..183457c 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -2804,7 +2804,7 @@
 	/* add OV7670 here
 	 * it appears to be wrongly detected as a 7610 by default */
 	if (rc < 0) {
-		PDEBUG(D_ERR, "Error detecting sensor type");
+		pr_err("Error detecting sensor type\n");
 		return;
 	}
 	if ((rc & 3) == 3) {
@@ -2832,12 +2832,12 @@
 		/* try to read product id registers */
 		high = i2c_r(sd, 0x0a);
 		if (high < 0) {
-			PDEBUG(D_ERR, "Error detecting camera chip PID");
+			pr_err("Error detecting camera chip PID\n");
 			return;
 		}
 		low = i2c_r(sd, 0x0b);
 		if (low < 0) {
-			PDEBUG(D_ERR, "Error detecting camera chip VER");
+			pr_err("Error detecting camera chip VER\n");
 			return;
 		}
 		if (high == 0x76) {
@@ -2863,7 +2863,7 @@
 				sd->sensor = SEN_OV7660;
 				break;
 			default:
-				PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
+				pr_err("Unknown sensor: 0x76%02x\n", low);
 				return;
 			}
 		} else {
@@ -2884,7 +2884,7 @@
 	/* Detect sensor (sub)type */
 	rc = i2c_r(sd, OV7610_REG_COM_I);
 	if (rc < 0) {
-		PDEBUG(D_ERR, "Error detecting sensor type");
+		pr_err("Error detecting sensor type\n");
 		return;
 	}
 
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 0475339..b5acb1e 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -34,6 +34,8 @@
 
 #include "gspca.h"
 
+#include <linux/fixp-arith.h>
+
 #define OV534_REG_ADDRESS	0xf1	/* sensor address */
 #define OV534_REG_SUBADDR	0xf2
 #define OV534_REG_WRITE		0xf3
@@ -53,6 +55,8 @@
 
 /* controls */
 enum e_ctrl {
+	HUE,
+	SATURATION,
 	BRIGHTNESS,
 	CONTRAST,
 	GAIN,
@@ -63,7 +67,6 @@
 	SHARPNESS,
 	HFLIP,
 	VFLIP,
-	COLORS,
 	LIGHTFREQ,
 	NCTRLS		/* number of controls */
 };
@@ -87,6 +90,8 @@
 };
 
 /* V4L2 controls supported by the driver */
+static void sethue(struct gspca_dev *gspca_dev);
+static void setsaturation(struct gspca_dev *gspca_dev);
 static void setbrightness(struct gspca_dev *gspca_dev);
 static void setcontrast(struct gspca_dev *gspca_dev);
 static void setgain(struct gspca_dev *gspca_dev);
@@ -96,13 +101,36 @@
 static void setaec(struct gspca_dev *gspca_dev);
 static void setsharpness(struct gspca_dev *gspca_dev);
 static void sethvflip(struct gspca_dev *gspca_dev);
-static void setcolors(struct gspca_dev *gspca_dev);
 static void setlightfreq(struct gspca_dev *gspca_dev);
 
 static int sd_start(struct gspca_dev *gspca_dev);
 static void sd_stopN(struct gspca_dev *gspca_dev);
 
 static const struct ctrl sd_ctrls[] = {
+[HUE] = {
+		{
+			.id      = V4L2_CID_HUE,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Hue",
+			.minimum = -90,
+			.maximum = 90,
+			.step    = 1,
+			.default_value = 0,
+		},
+		.set_control = sethue
+	},
+[SATURATION] = {
+		{
+			.id      = V4L2_CID_SATURATION,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Saturation",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
+			.default_value = 64,
+		},
+		.set_control = setsaturation
+	},
 [BRIGHTNESS] = {
 		{
 			.id      = V4L2_CID_BRIGHTNESS,
@@ -223,18 +251,6 @@
 		},
 		.set_control = sethvflip
 	},
-[COLORS] = {
-		{
-			.id      = V4L2_CID_SATURATION,
-			.type    = V4L2_CTRL_TYPE_INTEGER,
-			.name    = "Saturation",
-			.minimum = 0,
-			.maximum = 6,
-			.step    = 1,
-			.default_value = 3,
-		},
-		.set_control = setcolors
-	},
 [LIGHTFREQ] = {
 		{
 			.id      = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -684,7 +700,7 @@
 	{ 0x9c, 0x20 },
 	{ 0x9e, 0x81 },
 
-	{ 0xa6, 0x04 },
+	{ 0xa6, 0x07 },
 	{ 0x7e, 0x0c },
 	{ 0x7f, 0x16 },
 	{ 0x80, 0x2a },
@@ -955,6 +971,74 @@
 	PDEBUG(D_PROBE, "frame_rate: %d", r->fps);
 }
 
+static void sethue(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int val;
+
+	val = sd->ctrls[HUE].val;
+	if (sd->sensor == SENSOR_OV767x) {
+		/* TBD */
+	} else {
+		s16 huesin;
+		s16 huecos;
+
+		/* fixp_sin and fixp_cos accept only positive values, while
+		 * our val is between -90 and 90
+		 */
+		val += 360;
+
+		/* According to the datasheet the registers expect HUESIN and
+		 * HUECOS to be the result of the trigonometric functions,
+		 * scaled by 0x80.
+		 *
+		 * The 0x100 here represents the maximun absolute value
+		 * returned byt fixp_sin and fixp_cos, so the scaling will
+		 * consider the result like in the interval [-1.0, 1.0].
+		 */
+		huesin = fixp_sin(val) * 0x80 / 0x100;
+		huecos = fixp_cos(val) * 0x80 / 0x100;
+
+		if (huesin < 0) {
+			sccb_reg_write(gspca_dev, 0xab,
+				sccb_reg_read(gspca_dev, 0xab) | 0x2);
+			huesin = -huesin;
+		} else {
+			sccb_reg_write(gspca_dev, 0xab,
+				sccb_reg_read(gspca_dev, 0xab) & ~0x2);
+
+		}
+		sccb_reg_write(gspca_dev, 0xa9, (u8)huecos);
+		sccb_reg_write(gspca_dev, 0xaa, (u8)huesin);
+	}
+}
+
+static void setsaturation(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int val;
+
+	val = sd->ctrls[SATURATION].val;
+	if (sd->sensor == SENSOR_OV767x) {
+		int i;
+		static u8 color_tb[][6] = {
+			{0x42, 0x42, 0x00, 0x11, 0x30, 0x41},
+			{0x52, 0x52, 0x00, 0x16, 0x3c, 0x52},
+			{0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66},
+			{0x80, 0x80, 0x00, 0x22, 0x5e, 0x80},
+			{0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a},
+			{0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8},
+			{0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd},
+		};
+
+		for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++)
+			sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]);
+	} else {
+		sccb_reg_write(gspca_dev, 0xa7, val); /* U saturation */
+		sccb_reg_write(gspca_dev, 0xa8, val); /* V saturation */
+	}
+}
+
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1132,26 +1216,6 @@
 	}
 }
 
-static void setcolors(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	u8 val;
-	int i;
-	static u8 color_tb[][6] = {
-		{0x42, 0x42, 0x00, 0x11, 0x30, 0x41},
-		{0x52, 0x52, 0x00, 0x16, 0x3c, 0x52},
-		{0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66},
-		{0x80, 0x80, 0x00, 0x22, 0x5e, 0x80},
-		{0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a},
-		{0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8},
-		{0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd},
-	};
-
-	val = sd->ctrls[COLORS].val;
-	for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++)
-		sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]);
-}
-
 static void setlightfreq(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1225,9 +1289,13 @@
 
 	if ((sensor_id & 0xfff0) == 0x7670) {
 		sd->sensor = SENSOR_OV767x;
-		gspca_dev->ctrl_dis = (1 << GAIN) |
+		gspca_dev->ctrl_dis = (1 << HUE) |
+					(1 << GAIN) |
 					(1 << AGC) |
 					(1 << SHARPNESS);	/* auto */
+		sd->ctrls[SATURATION].min = 0,
+		sd->ctrls[SATURATION].max = 6,
+		sd->ctrls[SATURATION].def = 3,
 		sd->ctrls[BRIGHTNESS].min = -127;
 		sd->ctrls[BRIGHTNESS].max = 127;
 		sd->ctrls[BRIGHTNESS].def = 0;
@@ -1243,7 +1311,6 @@
 		gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode);
 	} else {
 		sd->sensor = SENSOR_OV772x;
-		gspca_dev->ctrl_dis = (1 << COLORS);
 		gspca_dev->cam.bulk = 1;
 		gspca_dev->cam.bulk_size = 16384;
 		gspca_dev->cam.bulk_nurbs = 2;
@@ -1302,6 +1369,9 @@
 
 	set_frame_rate(gspca_dev);
 
+	if (!(gspca_dev->ctrl_dis & (1 << HUE)))
+		sethue(gspca_dev);
+	setsaturation(gspca_dev);
 	if (!(gspca_dev->ctrl_dis & (1 << AGC)))
 		setagc(gspca_dev);
 	setawb(gspca_dev);
@@ -1314,8 +1384,6 @@
 	if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS)))
 		setsharpness(gspca_dev);
 	sethvflip(gspca_dev);
-	if (!(gspca_dev->ctrl_dis & (1 << COLORS)))
-		setcolors(gspca_dev);
 	setlightfreq(gspca_dev);
 
 	ov534_set_led(gspca_dev, 1);
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index e6601b8..b579730 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -1376,7 +1376,7 @@
 				ARRAY_SIZE(ov562x_init_2));
 		reg_w(gspca_dev, 0xe0, 0x00);
 	} else {
-		err("Unknown sensor %04x", sensor_id);
+		pr_err("Unknown sensor %04x", sensor_id);
 		return -EINVAL;
 	}
 
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 3844c49..fa661c6 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -29,6 +29,8 @@
 
 #include <linux/input.h>
 #include "gspca.h"
+/* Include pac common sof detection functions */
+#include "pac_common.h"
 
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("Pixart PAC207");
@@ -39,16 +41,17 @@
 #define PAC207_BRIGHTNESS_MIN		0
 #define PAC207_BRIGHTNESS_MAX		255
 #define PAC207_BRIGHTNESS_DEFAULT	46
+#define PAC207_BRIGHTNESS_REG		0x08
 
 #define PAC207_EXPOSURE_MIN		3
 #define PAC207_EXPOSURE_MAX		90 /* 1 sec expo time / 1 fps */
 #define PAC207_EXPOSURE_DEFAULT		5 /* power on default: 3 */
-#define PAC207_EXPOSURE_KNEE		9 /* fps: 90 / exposure -> 9: 10 fps */
+#define PAC207_EXPOSURE_REG		0x02
 
 #define PAC207_GAIN_MIN			0
 #define PAC207_GAIN_MAX			31
 #define PAC207_GAIN_DEFAULT		7 /* power on default: 9 */
-#define PAC207_GAIN_KNEE		15
+#define PAC207_GAIN_REG			0x0e
 
 #define PAC207_AUTOGAIN_DEADZONE	30
 
@@ -56,13 +59,9 @@
 struct sd {
 	struct gspca_dev gspca_dev;		/* !! must be the first item */
 
+	struct v4l2_ctrl *brightness;
+
 	u8 mode;
-
-	u8 brightness;
-	u8 exposure;
-	u8 autogain;
-	u8 gain;
-
 	u8 sof_read;
 	u8 header_read;
 	u8 autogain_ignore_frames;
@@ -70,80 +69,6 @@
 	atomic_t avg_lum;
 };
 
-/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static const struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
-	{
-	    {
-		.id      = V4L2_CID_BRIGHTNESS,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Brightness",
-		.minimum = PAC207_BRIGHTNESS_MIN,
-		.maximum = PAC207_BRIGHTNESS_MAX,
-		.step = 1,
-		.default_value = PAC207_BRIGHTNESS_DEFAULT,
-		.flags = 0,
-	    },
-	    .set = sd_setbrightness,
-	    .get = sd_getbrightness,
-	},
-#define SD_EXPOSURE 1
-	{
-	    {
-		.id = V4L2_CID_EXPOSURE,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Exposure",
-		.minimum = PAC207_EXPOSURE_MIN,
-		.maximum = PAC207_EXPOSURE_MAX,
-		.step = 1,
-		.default_value = PAC207_EXPOSURE_DEFAULT,
-		.flags = 0,
-	    },
-	    .set = sd_setexposure,
-	    .get = sd_getexposure,
-	},
-#define SD_AUTOGAIN 2
-	{
-	    {
-		.id	  = V4L2_CID_AUTOGAIN,
-		.type	= V4L2_CTRL_TYPE_BOOLEAN,
-		.name	= "Auto Gain",
-		.minimum = 0,
-		.maximum = 1,
-		.step	= 1,
-#define AUTOGAIN_DEF 1
-		.default_value = AUTOGAIN_DEF,
-		.flags = 0,
-	    },
-	    .set = sd_setautogain,
-	    .get = sd_getautogain,
-	},
-#define SD_GAIN 3
-	{
-	    {
-		.id = V4L2_CID_GAIN,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Gain",
-		.minimum = PAC207_GAIN_MIN,
-		.maximum = PAC207_GAIN_MAX,
-		.step = 1,
-		.default_value = PAC207_GAIN_DEFAULT,
-		.flags = 0,
-	    },
-	    .set = sd_setgain,
-	    .get = sd_getgain,
-	},
-};
-
 static const struct v4l2_pix_format sif_mode[] = {
 	{176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
 		.bytesperline = 176,
@@ -167,39 +92,44 @@
 	{0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00},
 };
 
-static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
+static void pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
 	const u8 *buffer, u16 length)
 {
 	struct usb_device *udev = gspca_dev->dev;
 	int err;
 
+	if (gspca_dev->usb_err < 0)
+		return;
+
 	memcpy(gspca_dev->usb_buf, buffer, length);
 
 	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
 			0x00, index,
 			gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
-	if (err < 0)
+	if (err < 0) {
 		pr_err("Failed to write registers to index 0x%04X, error %d\n",
 		       index, err);
-
-	return err;
+		gspca_dev->usb_err = err;
+	}
 }
 
-
-static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
+static void pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
 {
 	struct usb_device *udev = gspca_dev->dev;
 	int err;
 
+	if (gspca_dev->usb_err < 0)
+		return;
+
 	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
 			value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
-	if (err)
+	if (err) {
 		pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n",
 		       index, value, err);
-
-	return err;
+		gspca_dev->usb_err = err;
+	}
 }
 
 static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
@@ -207,6 +137,9 @@
 	struct usb_device *udev = gspca_dev->dev;
 	int res;
 
+	if (gspca_dev->usb_err < 0)
+		return 0;
+
 	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
 			0x00, index,
@@ -214,7 +147,8 @@
 	if (res < 0) {
 		pr_err("Failed to read a register (index 0x%04X, error %d)\n",
 		       index, res);
-		return res;
+		gspca_dev->usb_err = res;
+		return 0;
 	}
 
 	return gspca_dev->usb_buf[0];
@@ -224,7 +158,6 @@
 static int sd_config(struct gspca_dev *gspca_dev,
 			const struct usb_device_id *id)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
 	struct cam *cam;
 	u8 idreg[2];
 
@@ -247,10 +180,6 @@
 	cam = &gspca_dev->cam;
 	cam->cam_mode = sif_mode;
 	cam->nmodes = ARRAY_SIZE(sif_mode);
-	sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
-	sd->exposure = PAC207_EXPOSURE_DEFAULT;
-	sd->gain = PAC207_GAIN_DEFAULT;
-	sd->autogain = AUTOGAIN_DEF;
 
 	return 0;
 }
@@ -264,6 +193,87 @@
 				 * Bit_2=Compression test mode enable */
 	pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
 
+	return gspca_dev->usb_err;
+}
+
+static void setcontrol(struct gspca_dev *gspca_dev, u16 reg, u16 val)
+{
+	pac207_write_reg(gspca_dev, reg, val);
+	pac207_write_reg(gspca_dev, 0x13, 0x01);	/* Bit 0, auto clear */
+	pac207_write_reg(gspca_dev, 0x1c, 0x01);	/* not documented */
+}
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	gspca_dev->usb_err = 0;
+
+	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
+		/* when switching to autogain set defaults to make sure
+		   we are on a valid point of the autogain gain /
+		   exposure knee graph, and give this change time to
+		   take effect before doing autogain. */
+		gspca_dev->exposure->val    = PAC207_EXPOSURE_DEFAULT;
+		gspca_dev->gain->val        = PAC207_GAIN_DEFAULT;
+		sd->autogain_ignore_frames  = PAC_AUTOGAIN_IGNORE_FRAMES;
+	}
+
+	if (!gspca_dev->streaming)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		setcontrol(gspca_dev, PAC207_BRIGHTNESS_REG, ctrl->val);
+		break;
+	case V4L2_CID_AUTOGAIN:
+		if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
+			setcontrol(gspca_dev, PAC207_EXPOSURE_REG,
+				   gspca_dev->exposure->val);
+		if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
+			setcontrol(gspca_dev, PAC207_GAIN_REG,
+				   gspca_dev->gain->val);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+	.s_ctrl = sd_s_ctrl,
+};
+
+/* this function is called at probe time */
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+
+	sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+				V4L2_CID_BRIGHTNESS,
+				PAC207_BRIGHTNESS_MIN, PAC207_BRIGHTNESS_MAX,
+				1, PAC207_BRIGHTNESS_DEFAULT);
+	gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+				V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+				V4L2_CID_EXPOSURE,
+				PAC207_EXPOSURE_MIN, PAC207_EXPOSURE_MAX,
+				1, PAC207_EXPOSURE_DEFAULT);
+	gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+				V4L2_CID_GAIN,
+				PAC207_GAIN_MIN, PAC207_GAIN_MAX,
+				1, PAC207_GAIN_DEFAULT);
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+	v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
 	return 0;
 }
 
@@ -285,11 +295,13 @@
 	else
 		pac207_write_reg(gspca_dev, 0x4a, 0x30);
 	pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
-	pac207_write_reg(gspca_dev, 0x08, sd->brightness);
+	pac207_write_reg(gspca_dev, 0x08, v4l2_ctrl_g_ctrl(sd->brightness));
 
 	/* PGA global gain (Bit 4-0) */
-	pac207_write_reg(gspca_dev, 0x0e, sd->gain);
-	pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
+	pac207_write_reg(gspca_dev, 0x0e,
+		v4l2_ctrl_g_ctrl(gspca_dev->gain));
+	pac207_write_reg(gspca_dev, 0x02,
+		v4l2_ctrl_g_ctrl(gspca_dev->exposure)); /* PXCK = 12MHz /n */
 
 	mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
 	if (gspca_dev->width == 176) {	/* 176x144 */
@@ -308,7 +320,7 @@
 	sd->sof_read = 0;
 	sd->autogain_ignore_frames = 0;
 	atomic_set(&sd->avg_lum, -1);
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -318,8 +330,6 @@
 	pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
 }
 
-/* Include pac common sof detection functions */
-#include "pac_common.h"
 
 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
 {
@@ -331,9 +341,8 @@
 
 	if (sd->autogain_ignore_frames > 0)
 		sd->autogain_ignore_frames--;
-	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
-			90, PAC207_AUTOGAIN_DEADZONE,
-			PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
+	else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
+			90, PAC207_AUTOGAIN_DEADZONE))
 		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
@@ -384,118 +393,6 @@
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	pac207_write_reg(gspca_dev, 0x08, sd->brightness);
-	pac207_write_reg(gspca_dev, 0x13, 0x01);	/* Bit 0, auto clear */
-	pac207_write_reg(gspca_dev, 0x1c, 0x01);	/* not documented */
-}
-
-static void setexposure(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	pac207_write_reg(gspca_dev, 0x02, sd->exposure);
-	pac207_write_reg(gspca_dev, 0x13, 0x01);	/* Bit 0, auto clear */
-	pac207_write_reg(gspca_dev, 0x1c, 0x01);	/* not documented */
-}
-
-static void setgain(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	pac207_write_reg(gspca_dev, 0x0e, sd->gain);
-	pac207_write_reg(gspca_dev, 0x13, 0x01);	/* Bit 0, auto clear */
-	pac207_write_reg(gspca_dev, 0x1c, 0x01);	/* not documented */
-}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->brightness = val;
-	if (gspca_dev->streaming)
-		setbrightness(gspca_dev);
-	return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->brightness;
-	return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->exposure = val;
-	if (gspca_dev->streaming)
-		setexposure(gspca_dev);
-	return 0;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->exposure;
-	return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->gain = val;
-	if (gspca_dev->streaming)
-		setgain(gspca_dev);
-	return 0;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->gain;
-	return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->autogain = val;
-	/* when switching to autogain set defaults to make sure
-	   we are on a valid point of the autogain gain /
-	   exposure knee graph, and give this change time to
-	   take effect before doing autogain. */
-	if (sd->autogain) {
-		sd->exposure = PAC207_EXPOSURE_DEFAULT;
-		sd->gain = PAC207_GAIN_DEFAULT;
-		if (gspca_dev->streaming) {
-			sd->autogain_ignore_frames =
-				PAC_AUTOGAIN_IGNORE_FRAMES;
-			setexposure(gspca_dev);
-			setgain(gspca_dev);
-		}
-	}
-
-	return 0;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->autogain;
-	return 0;
-}
-
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,		/* interrupt packet data */
@@ -518,10 +415,9 @@
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
-	.ctrls = sd_ctrls,
-	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
 	.init = sd_init,
+	.init_controls = sd_init_controls,
 	.start = sd_start,
 	.stopN = sd_stopN,
 	.dq_callback = pac207_do_auto_gain,
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 30662fc..a0369a5 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -23,43 +23,58 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
-/* Some documentation about various registers as determined by trial and error.
-
-   Register page 1:
-
-   Address	Description
-   0x78		Global control, bit 6 controls the LED (inverted)
-
-   Register page 3:
-
-   Address	Description
-   0x02		Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
-		the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
-   0x03		Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
-   0x04		Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
-		63 -> ~27 fps, the 2 msb's must always be 1 !!
-   0x05		Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
-		1 -> ~30 fps, 2 -> ~20 fps
-   0x0e		Exposure bits 0-7, 0-448, 0 = use full frame time
-   0x0f		Exposure bit 8, 0-448, 448 = no exposure at all
-   0x10		Master gain 0-31
-   0x21		Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
-
-   The registers are accessed in the following functions:
-
-   Page | Register   | Function
-   -----+------------+---------------------------------------------------
-    0   | 0x0f..0x20 | setcolors()
-    0   | 0xa2..0xab | setbrightcont()
-    0   | 0xc5       | setredbalance()
-    0   | 0xc6       | setwhitebalance()
-    0   | 0xc7       | setbluebalance()
-    0   | 0xdc       | setbrightcont(), setcolors()
-    3   | 0x02       | setexposure()
-    3   | 0x10       | setgain()
-    3   | 0x11       | setcolors(), setgain(), setexposure(), sethvflip()
-    3   | 0x21       | sethvflip()
-*/
+/*
+ * Some documentation about various registers as determined by trial and error.
+ *
+ * Register page 1:
+ *
+ * Address	Description
+ * 0x78		Global control, bit 6 controls the LED (inverted)
+ * 0x80		Compression balance, 2 interesting settings:
+ *		0x0f Default
+ *		0x50 Values >= this switch the camera to a lower compression,
+ *		     using the same table for both luminance and chrominance.
+ *		     This gives a sharper picture. Only usable when running
+ *		     at < 15 fps! Note currently the driver does not use this
+ *		     as the quality gain is small and the generated JPG-s are
+ *		     only understood by v4l-utils >= 0.8.9
+ *
+ * Register page 3:
+ *
+ * Address	Description
+ * 0x02		Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
+ *		the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
+ * 0x03		Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
+ * 0x04		Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
+ *		63 -> ~27 fps, the 2 msb's must always be 1 !!
+ * 0x05		Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
+ *		1 -> ~30 fps, 2 -> ~20 fps
+ * 0x0e		Exposure bits 0-7, 0-448, 0 = use full frame time
+ * 0x0f		Exposure bit 8, 0-448, 448 = no exposure at all
+ * 0x10		Gain 0-31
+ * 0x12		Another gain 0-31, unlike 0x10 this one seems to start with an
+ *		amplification value of 1 rather then 0 at its lowest setting
+ * 0x21		Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+ * 0x80		Another framerate control, best left at 1, moving it from 1 to
+ *		2 causes the framerate to become 3/4th of what it was, and
+ *		also seems to cause pixel averaging, resulting in an effective
+ *		resolution of 320x240 and thus a much blockier image
+ *
+ * The registers are accessed in the following functions:
+ *
+ * Page | Register   | Function
+ * -----+------------+---------------------------------------------------
+ *  0   | 0x0f..0x20 | setcolors()
+ *  0   | 0xa2..0xab | setbrightcont()
+ *  0   | 0xc5       | setredbalance()
+ *  0   | 0xc6       | setwhitebalance()
+ *  0   | 0xc7       | setbluebalance()
+ *  0   | 0xdc       | setbrightcont(), setcolors()
+ *  3   | 0x02       | setexposure()
+ *  3   | 0x10, 0x12 | setgain()
+ *  3   | 0x11       | setcolors(), setgain(), setexposure(), sethvflip()
+ *  3   | 0x21       | sethvflip()
+ */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
@@ -89,7 +104,6 @@
 	NCTRLS		/* number of controls */
 };
 
-/* specific webcam descriptor for pac7302 */
 struct sd {
 	struct gspca_dev gspca_dev;		/* !! must be the first item */
 
@@ -198,10 +212,10 @@
 		.type    = V4L2_CTRL_TYPE_INTEGER,
 		.name    = "Gain",
 		.minimum = 0,
-		.maximum = 255,
+		.maximum = 62,
 		.step    = 1,
-#define GAIN_DEF 127
-#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
+#define GAIN_DEF 15
+#define GAIN_KNEE 46
 		.default_value = GAIN_DEF,
 	    },
 	    .set_control = setgain
@@ -270,7 +284,6 @@
 #define LOAD_PAGE3		255
 #define END_OF_SEQUENCE		0
 
-/* pac 7302 */
 static const u8 init_7302[] = {
 /*	index,value */
 	0xff, 0x01,		/* page 1 */
@@ -509,7 +522,6 @@
 	return 0;
 }
 
-/* This function is used by pac7302 only */
 static void setbrightcont(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -536,7 +548,6 @@
 	reg_w(gspca_dev, 0xdc, 0x01);
 }
 
-/* This function is used by pac7302 only */
 static void setcolors(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -590,9 +601,19 @@
 static void setgain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	u8 reg10, reg12;
+
+	if (sd->ctrls[GAIN].val < 32) {
+		reg10 = sd->ctrls[GAIN].val;
+		reg12 = 0;
+	} else {
+		reg10 = 31;
+		reg12 = sd->ctrls[GAIN].val - 31;
+	}
 
 	reg_w(gspca_dev, 0xff, 0x03);			/* page 3 */
-	reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
+	reg_w(gspca_dev, 0x10, reg10);
+	reg_w(gspca_dev, 0x12, reg12);
 
 	/* load registers to sensor (Bit 0, auto clear) */
 	reg_w(gspca_dev, 0x11, 0x01);
@@ -604,28 +625,36 @@
 	u8 clockdiv;
 	u16 exposure;
 
-	/* register 2 of frame 3 contains the clock divider configuring the
-	   no fps according to the formula: 90 / reg. sd->exposure is the
-	   desired exposure time in 0.5 ms. */
+	/*
+	 * Register 2 of frame 3 contains the clock divider configuring the
+	 * no fps according to the formula: 90 / reg. sd->exposure is the
+	 * desired exposure time in 0.5 ms.
+	 */
 	clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
 
-	/* Note clockdiv = 3 also works, but when running at 30 fps, depending
-	   on the scene being recorded, the camera switches to another
-	   quantization table for certain JPEG blocks, and we don't know how
-	   to decompress these blocks. So we cap the framerate at 15 fps */
+	/*
+	 * Note clockdiv = 3 also works, but when running at 30 fps, depending
+	 * on the scene being recorded, the camera switches to another
+	 * quantization table for certain JPEG blocks, and we don't know how
+	 * to decompress these blocks. So we cap the framerate at 15 fps.
+	 */
 	if (clockdiv < 6)
 		clockdiv = 6;
 	else if (clockdiv > 63)
 		clockdiv = 63;
 
-	/* reg2 MUST be a multiple of 3, except when between 6 and 12?
-	   Always round up, otherwise we cannot get the desired frametime
-	   using the partial frame time exposure control */
+	/*
+	 * Register 2 MUST be a multiple of 3, except when between 6 and 12?
+	 * Always round up, otherwise we cannot get the desired frametime
+	 * using the partial frame time exposure control.
+	 */
 	if (clockdiv < 6 || clockdiv > 12)
 		clockdiv = ((clockdiv + 2) / 3) * 3;
 
-	/* frame exposure time in ms = 1000 * clockdiv / 90    ->
-	exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
+	/*
+	 * frame exposure time in ms = 1000 * clockdiv / 90    ->
+	 * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90)
+	 */
 	exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
 	/* 0 = use full frametime, 448 = no exposure, reverse it */
 	exposure = 448 - exposure;
@@ -643,10 +672,12 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	/* when switching to autogain set defaults to make sure
-	   we are on a valid point of the autogain gain /
-	   exposure knee graph, and give this change time to
-	   take effect before doing autogain. */
+	/*
+	 * When switching to autogain set defaults to make sure
+	 * we are on a valid point of the autogain gain /
+	 * exposure knee graph, and give this change time to
+	 * take effect before doing autogain.
+	 */
 	if (sd->ctrls[AUTOGAIN].val) {
 		sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
 		sd->ctrls[GAIN].val = GAIN_DEF;
@@ -700,8 +731,6 @@
 	setautogain(gspca_dev);
 	sethvflip(gspca_dev);
 
-	/* only resolution 640x480 is supported for pac7302 */
-
 	sd->sof_read = 0;
 	atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val);
 
@@ -729,9 +758,7 @@
 	reg_w(gspca_dev, 0x78, 0x40);
 }
 
-/* !! coarse_grained_expo_autogain is not used !! */
-#define exp_too_low_cnt flags
-#define exp_too_high_cnt sof_read
+#define WANT_REGULAR_AUTOGAIN
 #include "autogain_functions.h"
 
 static void do_autogain(struct gspca_dev *gspca_dev)
@@ -792,10 +819,12 @@
 	if (sof) {
 		int n, lum_offset, footer_length;
 
-		/* 6 bytes after the FF D9 EOF marker a number of lumination
-		   bytes are send corresponding to different parts of the
-		   image, the 14th and 15th byte after the EOF seem to
-		   correspond to the center of the image */
+		/*
+		 * 6 bytes after the FF D9 EOF marker a number of lumination
+		 * bytes are send corresponding to different parts of the
+		 * image, the 14th and 15th byte after the EOF seem to
+		 * correspond to the center of the image.
+		 */
 		lum_offset = 61 + sizeof pac_sof_marker;
 		footer_length = 74;
 
@@ -839,9 +868,10 @@
 	u8 index;
 	u8 value;
 
-	/* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
-			       long on the USB bus)
-	*/
+	/*
+	 * reg->reg: bit0..15: reserved for register index (wIndex is 16bit
+	 *		       long on the USB bus)
+	 */
 	if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
 	    reg->match.addr == 0 &&
 	    (reg->reg < 0x000000ff) &&
@@ -852,9 +882,11 @@
 		index = reg->reg;
 		value = reg->val;
 
-		/* Note that there shall be no access to other page
-		   by any other function between the page swith and
-		   the actual register write */
+		/*
+		 * Note that there shall be no access to other page
+		 * by any other function between the page switch and
+		 * the actual register write.
+		 */
 		reg_w(gspca_dev, 0xff, 0x00);		/* page 0 */
 		reg_w(gspca_dev, index, value);
 
@@ -940,6 +972,7 @@
 	{USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
 	{USB_DEVICE(0x093a, 0x2625)},
 	{USB_DEVICE(0x093a, 0x2626)},
+	{USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
 	{USB_DEVICE(0x093a, 0x2628)},
 	{USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
 	{USB_DEVICE(0x093a, 0x262a)},
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 1ac1111..2cb7d95 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -20,34 +20,42 @@
  */
 
 /* Some documentation about various registers as determined by trial and error.
-   When the register addresses differ between the 7202 and the 7311 the 2
-   different addresses are written as 7302addr/7311addr, when one of the 2
-   addresses is a - sign that register description is not valid for the
-   matching IC.
-
-   Register page 1:
-
-   Address	Description
-   -/0x08	Unknown compressor related, must always be 8 except when not
-		in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
-   -/0x1b	Auto white balance related, bit 0 is AWB enable (inverted)
-		bits 345 seem to toggle per color gains on/off (inverted)
-   0x78		Global control, bit 6 controls the LED (inverted)
-   -/0x80	JPEG compression ratio ? Best not touched
-
-   Register page 3/4:
-
-   Address	Description
-   0x02		Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
-		the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
-   -/0x0f	Master gain 1-245, low value = high gain
-   0x10/-	Master gain 0-31
-   -/0x10	Another gain 0-15, limited influence (1-2x gain I guess)
-   0x21		Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
-   -/0x27	Seems to toggle various gains on / off, Setting bit 7 seems to
-		completely disable the analog amplification block. Set to 0x68
-		for max gain, 0x14 for minimal gain.
-*/
+ *
+ * Register page 1:
+ *
+ * Address	Description
+ * 0x08		Unknown compressor related, must always be 8 except when not
+ *		in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
+ * 0x1b		Auto white balance related, bit 0 is AWB enable (inverted)
+ *		bits 345 seem to toggle per color gains on/off (inverted)
+ * 0x78		Global control, bit 6 controls the LED (inverted)
+ * 0x80		Compression balance, interesting settings:
+ *		0x01 Use this to allow the camera to switch to higher compr.
+ *		     on the fly. Needed to stay within bandwidth @ 640x480@30
+ *		0x1c From usb captures under Windows for 640x480
+ *		0x2a Values >= this switch the camera to a lower compression,
+ *		     using the same table for both luminance and chrominance.
+ *		     This gives a sharper picture. Usable only at 640x480@ <
+ *		     15 fps or 320x240 / 160x120. Note currently the driver
+ *		     does not use this as the quality gain is small and the
+ *		     generated JPG-s are only understood by v4l-utils >= 0.8.9
+ *		0x3f From usb captures under Windows for 320x240
+ *		0x69 From usb captures under Windows for 160x120
+ *
+ * Register page 4:
+ *
+ * Address	Description
+ * 0x02		Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
+ *		the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
+ * 0x0f		Master gain 1-245, low value = high gain
+ * 0x10		Another gain 0-15, limited influence (1-2x gain I guess)
+ * 0x21		Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+ *		Note setting vflip disabled leads to a much lower image quality,
+ *		so we always vflip, and tell userspace to flip it back
+ * 0x27		Seems to toggle various gains on / off, Setting bit 7 seems to
+ *		completely disable the analog amplification block. Set to 0x68
+ *		for max gain, 0x14 for minimal gain.
+ */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
@@ -55,21 +63,21 @@
 
 #include <linux/input.h>
 #include "gspca.h"
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
+#define PAC7311_GAIN_DEFAULT     122
+#define PAC7311_EXPOSURE_DEFAULT   3 /* 20 fps, avoid using high compr. */
 
 MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
 MODULE_DESCRIPTION("Pixart PAC7311");
 MODULE_LICENSE("GPL");
 
-/* specific webcam descriptor for pac7311 */
 struct sd {
 	struct gspca_dev gspca_dev;		/* !! must be the first item */
 
-	unsigned char contrast;
-	unsigned char gain;
-	unsigned char exposure;
-	unsigned char autogain;
-	__u8 hflip;
-	__u8 vflip;
+	struct v4l2_ctrl *contrast;
+	struct v4l2_ctrl *hflip;
 
 	u8 sof_read;
 	u8 autogain_ignore_frames;
@@ -77,114 +85,6 @@
 	atomic_t avg_lum;
 };
 
-/* V4L2 controls supported by the driver */
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
-
-static const struct ctrl sd_ctrls[] = {
-/* This control is for both the 7302 and the 7311 */
-	{
-	    {
-		.id      = V4L2_CID_CONTRAST,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Contrast",
-		.minimum = 0,
-#define CONTRAST_MAX 255
-		.maximum = CONTRAST_MAX,
-		.step    = 1,
-#define CONTRAST_DEF 127
-		.default_value = CONTRAST_DEF,
-	    },
-	    .set = sd_setcontrast,
-	    .get = sd_getcontrast,
-	},
-/* All controls below are for both the 7302 and the 7311 */
-	{
-	    {
-		.id      = V4L2_CID_GAIN,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Gain",
-		.minimum = 0,
-#define GAIN_MAX 255
-		.maximum = GAIN_MAX,
-		.step    = 1,
-#define GAIN_DEF 127
-#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
-		.default_value = GAIN_DEF,
-	    },
-	    .set = sd_setgain,
-	    .get = sd_getgain,
-	},
-	{
-	    {
-		.id      = V4L2_CID_EXPOSURE,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Exposure",
-		.minimum = 0,
-#define EXPOSURE_MAX 255
-		.maximum = EXPOSURE_MAX,
-		.step    = 1,
-#define EXPOSURE_DEF  16 /*  32 ms / 30 fps */
-#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
-		.default_value = EXPOSURE_DEF,
-	    },
-	    .set = sd_setexposure,
-	    .get = sd_getexposure,
-	},
-	{
-	    {
-		.id      = V4L2_CID_AUTOGAIN,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Auto Gain",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-#define AUTOGAIN_DEF 1
-		.default_value = AUTOGAIN_DEF,
-	    },
-	    .set = sd_setautogain,
-	    .get = sd_getautogain,
-	},
-	{
-	    {
-		.id      = V4L2_CID_HFLIP,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Mirror",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-#define HFLIP_DEF 0
-		.default_value = HFLIP_DEF,
-	    },
-	    .set = sd_sethflip,
-	    .get = sd_gethflip,
-	},
-	{
-	    {
-		.id      = V4L2_CID_VFLIP,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Vflip",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-#define VFLIP_DEF 0
-		.default_value = VFLIP_DEF,
-	    },
-	    .set = sd_setvflip,
-	    .get = sd_getvflip,
-	},
-};
-
 static const struct v4l2_pix_format vga_mode[] = {
 	{160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
 		.bytesperline = 160,
@@ -206,8 +106,8 @@
 #define LOAD_PAGE4		254
 #define END_OF_SEQUENCE		0
 
-/* pac 7311 */
 static const __u8 init_7311[] = {
+	0xff, 0x01,
 	0x78, 0x40,	/* Bit_0=start stream, Bit_6=LED */
 	0x78, 0x40,	/* Bit_0=start stream, Bit_6=LED */
 	0x78, 0x44,	/* Bit_0=start stream, Bit_6=LED */
@@ -387,90 +287,73 @@
 static int sd_config(struct gspca_dev *gspca_dev,
 			const struct usb_device_id *id)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-	struct cam *cam;
+	struct cam *cam = &gspca_dev->cam;
 
-	cam = &gspca_dev->cam;
-
-	PDEBUG(D_CONF, "Find Sensor PAC7311");
 	cam->cam_mode = vga_mode;
 	cam->nmodes = ARRAY_SIZE(vga_mode);
+	cam->input_flags = V4L2_IN_ST_VFLIP;
 
-	sd->contrast = CONTRAST_DEF;
-	sd->gain = GAIN_DEF;
-	sd->exposure = EXPOSURE_DEF;
-	sd->autogain = AUTOGAIN_DEF;
-	sd->hflip = HFLIP_DEF;
-	sd->vflip = VFLIP_DEF;
 	return 0;
 }
 
-/* This function is used by pac7311 only */
-static void setcontrast(struct gspca_dev *gspca_dev)
+static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
 	reg_w(gspca_dev, 0xff, 0x04);
-	reg_w(gspca_dev, 0x10, sd->contrast >> 4);
+	reg_w(gspca_dev, 0x10, val);
 	/* load registers to sensor (Bit 0, auto clear) */
 	reg_w(gspca_dev, 0x11, 0x01);
 }
 
-static void setgain(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-	int gain = GAIN_MAX - sd->gain;
-
-	if (gain < 1)
-		gain = 1;
-	else if (gain > 245)
-		gain = 245;
 	reg_w(gspca_dev, 0xff, 0x04);			/* page 4 */
 	reg_w(gspca_dev, 0x0e, 0x00);
-	reg_w(gspca_dev, 0x0f, gain);
+	reg_w(gspca_dev, 0x0f, gspca_dev->gain->maximum - val + 1);
 
 	/* load registers to sensor (Bit 0, auto clear) */
 	reg_w(gspca_dev, 0x11, 0x01);
 }
 
-static void setexposure(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-	__u8 reg;
-
-	/* register 2 of frame 3/4 contains the clock divider configuring the
-	   no fps according to the formula: 60 / reg. sd->exposure is the
-	   desired exposure time in ms. */
-	reg = 120 * sd->exposure / 1000;
-	if (reg < 2)
-		reg = 2;
-	else if (reg > 63)
-		reg = 63;
-
 	reg_w(gspca_dev, 0xff, 0x04);			/* page 4 */
-	reg_w(gspca_dev, 0x02, reg);
+	reg_w(gspca_dev, 0x02, val);
 
-	/* Page 1 register 8 must always be 0x08 except when not in
-	   640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
+	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0x11, 0x01);
+
+	/*
+	 * Page 1 register 8 must always be 0x08 except when not in
+	 *  640x480 mode and page 4 reg 2 <= 3 then it must be 9
+	 */
 	reg_w(gspca_dev, 0xff, 0x01);
-	if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
-			reg <= 3) {
+	if (gspca_dev->width != 640 && val <= 3)
 		reg_w(gspca_dev, 0x08, 0x09);
-	} else {
+	else
 		reg_w(gspca_dev, 0x08, 0x08);
-	}
+
+	/*
+	 * Page1 register 80 sets the compression balance, normally we
+	 * want / use 0x1c, but for 640x480@30fps we must allow the
+	 * camera to use higher compression or we may run out of
+	 * bandwidth.
+	 */
+	if (gspca_dev->width == 640 && val == 2)
+		reg_w(gspca_dev, 0x80, 0x01);
+	else
+		reg_w(gspca_dev, 0x80, 0x1c);
 
 	/* load registers to sensor (Bit 0, auto clear) */
 	reg_w(gspca_dev, 0x11, 0x01);
 }
 
-static void sethvflip(struct gspca_dev *gspca_dev)
+static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
 	__u8 data;
 
 	reg_w(gspca_dev, 0xff, 0x04);			/* page 4 */
-	data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
+	data = (hflip ? 0x04 : 0x00) |
+	       (vflip ? 0x08 : 0x00);
 	reg_w(gspca_dev, 0x21, data);
 
 	/* load registers to sensor (Bit 0, auto clear) */
@@ -484,6 +367,82 @@
 	return gspca_dev->usb_err;
 }
 
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	gspca_dev->usb_err = 0;
+
+	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
+		/* when switching to autogain set defaults to make sure
+		   we are on a valid point of the autogain gain /
+		   exposure knee graph, and give this change time to
+		   take effect before doing autogain. */
+		gspca_dev->exposure->val    = PAC7311_EXPOSURE_DEFAULT;
+		gspca_dev->gain->val        = PAC7311_GAIN_DEFAULT;
+		sd->autogain_ignore_frames  = PAC_AUTOGAIN_IGNORE_FRAMES;
+	}
+
+	if (!gspca_dev->streaming)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_CONTRAST:
+		setcontrast(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_AUTOGAIN:
+		if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
+			setexposure(gspca_dev, gspca_dev->exposure->val);
+		if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
+			setgain(gspca_dev, gspca_dev->gain->val);
+		break;
+	case V4L2_CID_HFLIP:
+		sethvflip(gspca_dev, sd->hflip->val, 1);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+	.s_ctrl = sd_s_ctrl,
+};
+
+/* this function is called at probe time */
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+
+	sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+					V4L2_CID_CONTRAST, 0, 15, 1, 7);
+	gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+					V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+					V4L2_CID_EXPOSURE, 2, 63, 1,
+					PAC7311_EXPOSURE_DEFAULT);
+	gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+					V4L2_CID_GAIN, 0, 244, 1,
+					PAC7311_GAIN_DEFAULT);
+	sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+		V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+
+	v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
+	return 0;
+}
+
+/* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -492,19 +451,19 @@
 
 	reg_w_var(gspca_dev, start_7311,
 		page4_7311, sizeof(page4_7311));
-	setcontrast(gspca_dev);
-	setgain(gspca_dev);
-	setexposure(gspca_dev);
-	sethvflip(gspca_dev);
+	setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast));
+	setgain(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->gain));
+	setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure));
+	sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), 1);
 
 	/* set correct resolution */
 	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
-	case 2:					/* 160x120 pac7311 */
+	case 2:					/* 160x120 */
 		reg_w(gspca_dev, 0xff, 0x01);
 		reg_w(gspca_dev, 0x17, 0x20);
 		reg_w(gspca_dev, 0x87, 0x10);
 		break;
-	case 1:					/* 320x240 pac7311 */
+	case 1:					/* 320x240 */
 		reg_w(gspca_dev, 0xff, 0x01);
 		reg_w(gspca_dev, 0x17, 0x30);
 		reg_w(gspca_dev, 0x87, 0x11);
@@ -541,14 +500,6 @@
 	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
 }
 
-/* called on streamoff with alt 0 and on disconnect for 7311 */
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* Include pac common sof detection functions */
-#include "pac_common.h"
-
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -558,13 +509,13 @@
 	if (avg_lum == -1)
 		return;
 
-	desired_lum = 200;
+	desired_lum = 170;
 	deadzone = 20;
 
 	if (sd->autogain_ignore_frames > 0)
 		sd->autogain_ignore_frames--;
-	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
-			deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+	else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
+						    desired_lum, deadzone))
 		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
@@ -628,10 +579,12 @@
 	if (sof) {
 		int n, lum_offset, footer_length;
 
-		/* 6 bytes after the FF D9 EOF marker a number of lumination
-		   bytes are send corresponding to different parts of the
-		   image, the 14th and 15th byte after the EOF seem to
-		   correspond to the center of the image */
+		/*
+		 * 6 bytes after the FF D9 EOF marker a number of lumination
+		 * bytes are send corresponding to different parts of the
+		 * image, the 14th and 15th byte after the EOF seem to
+		 * correspond to the center of the image.
+		 */
 		lum_offset = 24 + sizeof pac_sof_marker;
 		footer_length = 26;
 
@@ -668,127 +621,6 @@
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->contrast = val;
-	if (gspca_dev->streaming)
-		setcontrast(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->contrast;
-	return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->gain = val;
-	if (gspca_dev->streaming)
-		setgain(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->gain;
-	return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->exposure = val;
-	if (gspca_dev->streaming)
-		setexposure(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->exposure;
-	return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->autogain = val;
-	/* when switching to autogain set defaults to make sure
-	   we are on a valid point of the autogain gain /
-	   exposure knee graph, and give this change time to
-	   take effect before doing autogain. */
-	if (sd->autogain) {
-		sd->exposure = EXPOSURE_DEF;
-		sd->gain = GAIN_DEF;
-		if (gspca_dev->streaming) {
-			sd->autogain_ignore_frames =
-				PAC_AUTOGAIN_IGNORE_FRAMES;
-			setexposure(gspca_dev);
-			setgain(gspca_dev);
-		}
-	}
-
-	return gspca_dev->usb_err;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->autogain;
-	return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->hflip = val;
-	if (gspca_dev->streaming)
-		sethvflip(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->hflip;
-	return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->vflip = val;
-	if (gspca_dev->streaming)
-		sethvflip(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->vflip;
-	return 0;
-}
-
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,		/* interrupt packet data */
@@ -820,16 +652,13 @@
 }
 #endif
 
-/* sub-driver description for pac7311 */
 static const struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
-	.ctrls = sd_ctrls,
-	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
 	.init = sd_init,
+	.init_controls = sd_init_controls,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 	.dq_callback = do_autogain,
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 7e71aa2..ad09820 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -59,35 +59,38 @@
 #define SENSOR_MT9M111	9
 #define SENSOR_MT9M112  10
 #define SENSOR_HV7131R	11
-#define SENSOR_MT9VPRB	20
+#define SENSOR_MT9VPRB	12
 
 /* camera flags */
 #define HAS_NO_BUTTON	0x1
 #define LED_REVERSE	0x2 /* some cameras unset gpio to turn on leds */
 #define FLIP_DETECT	0x4
 
-enum e_ctrl {
-	BRIGHTNESS,
-	CONTRAST,
-	SATURATION,
-	HUE,
-	GAMMA,
-	BLUE,
-	RED,
-	VFLIP,
-	HFLIP,
-	EXPOSURE,
-	GAIN,
-	AUTOGAIN,
-	QUALITY,
-	NCTRLS		/* number of controls */
-};
-
 /* specific webcam descriptor */
 struct sd {
 	struct gspca_dev gspca_dev;
 
-	struct gspca_ctrl ctrls[NCTRLS];
+	struct { /* color control cluster */
+		struct v4l2_ctrl *brightness;
+		struct v4l2_ctrl *contrast;
+		struct v4l2_ctrl *saturation;
+		struct v4l2_ctrl *hue;
+	};
+	struct { /* blue/red balance control cluster */
+		struct v4l2_ctrl *blue;
+		struct v4l2_ctrl *red;
+	};
+	struct { /* h/vflip control cluster */
+		struct v4l2_ctrl *hflip;
+		struct v4l2_ctrl *vflip;
+	};
+	struct v4l2_ctrl *gamma;
+	struct { /* autogain and exposure or gain control cluster */
+		struct v4l2_ctrl *autogain;
+		struct v4l2_ctrl *exposure;
+		struct v4l2_ctrl *gain;
+	};
+	struct v4l2_ctrl *jpegqual;
 
 	struct work_struct work;
 	struct workqueue_struct *work_thread;
@@ -105,6 +108,7 @@
 	u8 exposure_step;
 
 	u8 i2c_addr;
+	u8 i2c_intf;
 	u8 sensor;
 	u8 hstart;
 	u8 vstart;
@@ -166,175 +170,6 @@
 	{}
 };
 
-static void set_cmatrix(struct gspca_dev *gspca_dev);
-static void set_gamma(struct gspca_dev *gspca_dev);
-static void set_redblue(struct gspca_dev *gspca_dev);
-static void set_hvflip(struct gspca_dev *gspca_dev);
-static void set_exposure(struct gspca_dev *gspca_dev);
-static void set_gain(struct gspca_dev *gspca_dev);
-static void set_quality(struct gspca_dev *gspca_dev);
-
-static const struct ctrl sd_ctrls[NCTRLS] = {
-[BRIGHTNESS] = {
-	    {
-		.id      = V4L2_CID_BRIGHTNESS,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Brightness",
-		.minimum = 0,
-		.maximum = 0xff,
-		.step    = 1,
-		.default_value = 0x7f
-	    },
-	    .set_control = set_cmatrix
-	},
-[CONTRAST] = {
-	    {
-		.id      = V4L2_CID_CONTRAST,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Contrast",
-		.minimum = 0,
-		.maximum = 0xff,
-		.step    = 1,
-		.default_value = 0x7f
-	    },
-	    .set_control = set_cmatrix
-	},
-[SATURATION] = {
-	    {
-		.id      = V4L2_CID_SATURATION,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Saturation",
-		.minimum = 0,
-		.maximum = 0xff,
-		.step    = 1,
-		.default_value = 0x7f
-	    },
-	    .set_control = set_cmatrix
-	},
-[HUE] = {
-	    {
-		.id      = V4L2_CID_HUE,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Hue",
-		.minimum = -180,
-		.maximum = 180,
-		.step    = 1,
-		.default_value = 0
-	    },
-	    .set_control = set_cmatrix
-	},
-[GAMMA] = {
-	    {
-		.id      = V4L2_CID_GAMMA,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Gamma",
-		.minimum = 0,
-		.maximum = 0xff,
-		.step    = 1,
-		.default_value = 0x10
-	    },
-	    .set_control = set_gamma
-	},
-[BLUE] = {
-	    {
-		.id	 = V4L2_CID_BLUE_BALANCE,
-		.type	 = V4L2_CTRL_TYPE_INTEGER,
-		.name	 = "Blue Balance",
-		.minimum = 0,
-		.maximum = 0x7f,
-		.step	 = 1,
-		.default_value = 0x28
-	    },
-	    .set_control = set_redblue
-	},
-[RED] = {
-	    {
-		.id	 = V4L2_CID_RED_BALANCE,
-		.type	 = V4L2_CTRL_TYPE_INTEGER,
-		.name	 = "Red Balance",
-		.minimum = 0,
-		.maximum = 0x7f,
-		.step	 = 1,
-		.default_value = 0x28
-	    },
-	    .set_control = set_redblue
-	},
-[HFLIP] = {
-	    {
-		.id      = V4L2_CID_HFLIP,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Horizontal Flip",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-		.default_value = 0,
-	    },
-	    .set_control = set_hvflip
-	},
-[VFLIP] = {
-	    {
-		.id      = V4L2_CID_VFLIP,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Vertical Flip",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-		.default_value = 0,
-	    },
-	    .set_control = set_hvflip
-	},
-[EXPOSURE] = {
-	    {
-		.id      = V4L2_CID_EXPOSURE,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Exposure",
-		.minimum = 0,
-		.maximum = 0x1780,
-		.step    = 1,
-		.default_value = 0x33,
-	    },
-	    .set_control = set_exposure
-	},
-[GAIN] = {
-	    {
-		.id      = V4L2_CID_GAIN,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Gain",
-		.minimum = 0,
-		.maximum = 28,
-		.step    = 1,
-		.default_value = 0,
-	    },
-	    .set_control = set_gain
-	},
-[AUTOGAIN] = {
-	    {
-		.id      = V4L2_CID_AUTOGAIN,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Auto Exposure",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-		.default_value = 1,
-	    },
-	},
-[QUALITY] = {
-	    {
-		.id      = V4L2_CID_JPEG_COMPRESSION_QUALITY,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Compression Quality",
-#define QUALITY_MIN 50
-#define QUALITY_MAX 90
-#define QUALITY_DEF 80
-		.minimum = QUALITY_MIN,
-		.maximum = QUALITY_MAX,
-		.step    = 1,
-		.default_value = QUALITY_DEF,
-	    },
-	    .set_control = set_quality
-	},
-};
-
 static const struct v4l2_pix_format vga_mode[] = {
 	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 160,
@@ -747,7 +582,7 @@
 	4,   2,   0,  -1,  -3,  -5,  -7,  -9, -11
 };
 
-static u16 i2c_ident[] = {
+static const u16 i2c_ident[] = {
 	V4L2_IDENT_OV9650,
 	V4L2_IDENT_OV9655,
 	V4L2_IDENT_SOI968,
@@ -760,9 +595,10 @@
 	V4L2_IDENT_MT9M111,
 	V4L2_IDENT_MT9M112,
 	V4L2_IDENT_HV7131R,
+[SENSOR_MT9VPRB] = V4L2_IDENT_UNKNOWN,
 };
 
-static u16 bridge_init[][2] = {
+static const u16 bridge_init[][2] = {
 	{0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
 	{0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
 	{0x1068, 0x30}, {0x1069, 0x20},	{0x106a, 0x10},
@@ -786,7 +622,7 @@
 };
 
 /* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
-static u8 ov_gain[] = {
+static const u8 ov_gain[] = {
 	0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
 	0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
 	0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
@@ -798,7 +634,7 @@
 };
 
 /* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
-static u16 micron1_gain[] = {
+static const u16 micron1_gain[] = {
 	/* 1x   1.25x   1.5x    1.75x */
 	0x0020, 0x0028, 0x0030, 0x0038,
 	/* 2x   2.25x   2.5x    2.75x */
@@ -819,7 +655,7 @@
 
 /* mt9m001 sensor uses a different gain formula then other micron sensors */
 /* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
-static u16 micron2_gain[] = {
+static const u16 micron2_gain[] = {
 	/* 1x   1.25x   1.5x    1.75x */
 	0x0008, 0x000a, 0x000c, 0x000e,
 	/* 2x   2.25x   2.5x    2.75x */
@@ -839,7 +675,7 @@
 };
 
 /* Gain = .5 + bit[7:0] / 16 */
-static u8 hv7131r_gain[] = {
+static const u8 hv7131r_gain[] = {
 	0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
 	0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
 	0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
@@ -850,7 +686,7 @@
 	0x78 /* 8x */
 };
 
-static struct i2c_reg_u8 soi968_init[] = {
+static const struct i2c_reg_u8 soi968_init[] = {
 	{0x0c, 0x00}, {0x0f, 0x1f},
 	{0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
 	{0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
@@ -864,7 +700,7 @@
 	{0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
 };
 
-static struct i2c_reg_u8 ov7660_init[] = {
+static const struct i2c_reg_u8 ov7660_init[] = {
 	{0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
 	{0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
 	{0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
@@ -872,11 +708,11 @@
 	   0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */
 	{0x17, 0x10}, {0x18, 0x61},
 	{0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
-	{0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
-	{0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
+	{0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0x00},
+	{0x2e, 0x00}, {0x01, 0x78}, {0x02, 0x50},
 };
 
-static struct i2c_reg_u8 ov7670_init[] = {
+static const struct i2c_reg_u8 ov7670_init[] = {
 	{0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
 	{0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
 	{0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
@@ -933,7 +769,7 @@
 	{0x93, 0x00},
 };
 
-static struct i2c_reg_u8 ov9650_init[] = {
+static const struct i2c_reg_u8 ov9650_init[] = {
 	{0x00, 0x00}, {0x01, 0x78},
 	{0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
 	{0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
@@ -963,7 +799,7 @@
 	{0xaa, 0x92}, {0xab, 0x0a},
 };
 
-static struct i2c_reg_u8 ov9655_init[] = {
+static const struct i2c_reg_u8 ov9655_init[] = {
 	{0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
 	{0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
 	{0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
@@ -990,7 +826,7 @@
 	{0x04, 0x03}, {0x00, 0x13},
 };
 
-static struct i2c_reg_u16 mt9v112_init[] = {
+static const struct i2c_reg_u16 mt9v112_init[] = {
 	{0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
 	{0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
 	{0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
@@ -1009,7 +845,7 @@
 	{0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
 };
 
-static struct i2c_reg_u16 mt9v111_init[] = {
+static const struct i2c_reg_u16 mt9v111_init[] = {
 	{0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
 	{0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
 	{0x2e, 0x0c64},	{0x2f, 0x0064}, {0x06, 0x600e},
@@ -1019,7 +855,7 @@
 	{0x0e, 0x0008}, {0x20, 0x0000}
 };
 
-static struct i2c_reg_u16 mt9v011_init[] = {
+static const struct i2c_reg_u16 mt9v011_init[] = {
 	{0x07, 0x0002},	{0x0d, 0x0001},	{0x0d, 0x0000},
 	{0x01, 0x0008},	{0x02, 0x0016},	{0x03, 0x01e1},
 	{0x04, 0x0281},	{0x05, 0x0083},	{0x06, 0x0006},
@@ -1046,7 +882,7 @@
 	{0x06, 0x0029},	{0x05, 0x0009},
 };
 
-static struct i2c_reg_u16 mt9m001_init[] = {
+static const struct i2c_reg_u16 mt9m001_init[] = {
 	{0x0d, 0x0001},
 	{0x0d, 0x0000},
 	{0x04, 0x0500},		/* hres = 1280 */
@@ -1062,21 +898,21 @@
 	{0x35, 0x0057},
 };
 
-static struct i2c_reg_u16 mt9m111_init[] = {
+static const struct i2c_reg_u16 mt9m111_init[] = {
 	{0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
 	{0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
 	{0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
 	{0xf0, 0x0000},
 };
 
-static struct i2c_reg_u16 mt9m112_init[] = {
+static const struct i2c_reg_u16 mt9m112_init[] = {
 	{0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
 	{0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
 	{0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
 	{0xf0, 0x0000},
 };
 
-static struct i2c_reg_u8 hv7131r_init[] = {
+static const struct i2c_reg_u8 hv7131r_init[] = {
 	{0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
 	{0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
 	{0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
@@ -1167,7 +1003,7 @@
 	 * from the point of view of the bridge, the length
 	 * includes the address
 	 */
-	row[0] = 0x81 | (2 << 4);
+	row[0] = sd->i2c_intf | (2 << 4);
 	row[1] = sd->i2c_addr;
 	row[2] = reg;
 	row[3] = val;
@@ -1180,7 +1016,7 @@
 }
 
 static void i2c_w1_buf(struct gspca_dev *gspca_dev,
-			struct i2c_reg_u8 *buf, int sz)
+			const struct i2c_reg_u8 *buf, int sz)
 {
 	while (--sz >= 0) {
 		i2c_w1(gspca_dev, buf->reg, buf->val);
@@ -1197,7 +1033,7 @@
 	 * from the point of view of the bridge, the length
 	 * includes the address
 	 */
-	row[0] = 0x81 | (3 << 4);
+	row[0] = sd->i2c_intf | (3 << 4);
 	row[1] = sd->i2c_addr;
 	row[2] = reg;
 	row[3] = val >> 8;
@@ -1210,7 +1046,7 @@
 }
 
 static void i2c_w2_buf(struct gspca_dev *gspca_dev,
-			struct i2c_reg_u16 *buf, int sz)
+			const struct i2c_reg_u16 *buf, int sz)
 {
 	while (--sz >= 0) {
 		i2c_w2(gspca_dev, buf->reg, buf->val);
@@ -1223,7 +1059,7 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 row[8];
 
-	row[0] = 0x81 | (1 << 4);
+	row[0] = sd->i2c_intf | (1 << 4);
 	row[1] = sd->i2c_addr;
 	row[2] = reg;
 	row[3] = 0;
@@ -1232,7 +1068,7 @@
 	row[6] = 0;
 	row[7] = 0x10;
 	i2c_w(gspca_dev, row);
-	row[0] = 0x81 | (1 << 4) | 0x02;
+	row[0] = sd->i2c_intf | (1 << 4) | 0x02;
 	row[2] = 0;
 	i2c_w(gspca_dev, row);
 	reg_r(gspca_dev, 0x10c2, 5);
@@ -1244,7 +1080,7 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 row[8];
 
-	row[0] = 0x81 | (1 << 4);
+	row[0] = sd->i2c_intf | (1 << 4);
 	row[1] = sd->i2c_addr;
 	row[2] = reg;
 	row[3] = 0;
@@ -1253,7 +1089,7 @@
 	row[6] = 0;
 	row[7] = 0x10;
 	i2c_w(gspca_dev, row);
-	row[0] = 0x81 | (2 << 4) | 0x02;
+	row[0] = sd->i2c_intf | (2 << 4) | 0x02;
 	row[2] = 0;
 	i2c_w(gspca_dev, row);
 	reg_r(gspca_dev, 0x10c2, 5);
@@ -1294,8 +1130,6 @@
 	if (gspca_dev->usb_err < 0)
 		pr_err("OV9655 sensor initialization failed\n");
 
-	/* disable hflip and vflip */
-	gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
 	sd->hstart = 1;
 	sd->vstart = 2;
 }
@@ -1310,9 +1144,6 @@
 	if (gspca_dev->usb_err < 0)
 		pr_err("SOI968 sensor initialization failed\n");
 
-	/* disable hflip and vflip */
-	gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP)
-				| (1 << EXPOSURE);
 	sd->hstart = 60;
 	sd->vstart = 11;
 }
@@ -1340,8 +1171,6 @@
 	if (gspca_dev->usb_err < 0)
 		pr_err("OV7670 sensor initialization failed\n");
 
-	/* disable hflip and vflip */
-	gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
 	sd->hstart = 0;
 	sd->vstart = 1;
 }
@@ -1378,9 +1207,6 @@
 			pr_err("MT9V111 sensor initialization failed\n");
 			return;
 		}
-		gspca_dev->ctrl_dis = (1 << EXPOSURE)
-					| (1 << AUTOGAIN)
-					| (1 << GAIN);
 		sd->hstart = 2;
 		sd->vstart = 2;
 		sd->sensor = SENSOR_MT9V111;
@@ -1422,8 +1248,6 @@
 	if (gspca_dev->usb_err < 0)
 		pr_err("MT9M112 sensor initialization failed\n");
 
-	gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
-				| (1 << GAIN);
 	sd->hstart = 0;
 	sd->vstart = 2;
 }
@@ -1436,8 +1260,6 @@
 	if (gspca_dev->usb_err < 0)
 		pr_err("MT9M111 sensor initialization failed\n");
 
-	gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
-				| (1 << GAIN);
 	sd->hstart = 0;
 	sd->vstart = 2;
 }
@@ -1470,8 +1292,6 @@
 	if (gspca_dev->usb_err < 0)
 		pr_err("MT9M001 sensor initialization failed\n");
 
-	/* disable hflip and vflip */
-	gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
 	sd->hstart = 1;
 	sd->vstart = 1;
 }
@@ -1488,20 +1308,18 @@
 	sd->vstart = 1;
 }
 
-static void set_cmatrix(struct gspca_dev *gspca_dev)
+static void set_cmatrix(struct gspca_dev *gspca_dev,
+		s32 brightness, s32 contrast, s32 satur, s32 hue)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-	int satur;
-	s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val;
+	s32 hue_coord, hue_index = 180 + hue;
 	u8 cmatrix[21];
 
 	memset(cmatrix, 0, sizeof cmatrix);
-	cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26;
+	cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26;
 	cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
 	cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
-	cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80;
+	cmatrix[18] = brightness - 0x80;
 
-	satur = sd->ctrls[SATURATION].val;
 	hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
 	cmatrix[6] = hue_coord;
 	cmatrix[7] = (hue_coord >> 8) & 0x0f;
@@ -1529,11 +1347,10 @@
 	reg_w(gspca_dev, 0x10e1, cmatrix, 21);
 }
 
-static void set_gamma(struct gspca_dev *gspca_dev)
+static void set_gamma(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
 	u8 gamma[17];
-	u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100;
+	u8 gval = val * 0xb8 / 0x100;
 
 	gamma[0] = 0x0a;
 	gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
@@ -1556,26 +1373,21 @@
 	reg_w(gspca_dev, 0x1190, gamma, 17);
 }
 
-static void set_redblue(struct gspca_dev *gspca_dev)
+static void set_redblue(struct gspca_dev *gspca_dev, s32 blue, s32 red)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val);
-	reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val);
+	reg_w1(gspca_dev, 0x118c, red);
+	reg_w1(gspca_dev, 0x118f, blue);
 }
 
-static void set_hvflip(struct gspca_dev *gspca_dev)
+static void set_hvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
 {
-	u8 value, tslb, hflip, vflip;
+	u8 value, tslb;
 	u16 value2;
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
-		hflip = !sd->ctrls[HFLIP].val;
-		vflip = !sd->ctrls[VFLIP].val;
-	} else {
-		hflip = sd->ctrls[HFLIP].val;
-		vflip = sd->ctrls[VFLIP].val;
+		hflip = !hflip;
+		vflip = !vflip;
 	}
 
 	switch (sd->sensor) {
@@ -1638,20 +1450,38 @@
 	}
 }
 
-static void set_exposure(struct gspca_dev *gspca_dev)
+static void set_exposure(struct gspca_dev *gspca_dev, s32 expo)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
-	int expo;
+	u8 exp[8] = {sd->i2c_intf, sd->i2c_addr,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
+	int expo2;
 
-	expo = sd->ctrls[EXPOSURE].val;
+	if (gspca_dev->streaming)
+		exp[7] = 0x1e;
+
 	switch (sd->sensor) {
 	case SENSOR_OV7660:
 	case SENSOR_OV7670:
 	case SENSOR_OV9655:
 	case SENSOR_OV9650:
+		if (expo > 547)
+			expo2 = 547;
+		else
+			expo2 = expo;
+		exp[0] |= (2 << 4);
+		exp[2] = 0x10;			/* AECH */
+		exp[3] = expo2 >> 2;
+		exp[7] = 0x10;
+		i2c_w(gspca_dev, exp);
+		exp[2] = 0x04;			/* COM1 */
+		exp[3] = expo2 & 0x0003;
+		exp[7] = 0x10;
+		i2c_w(gspca_dev, exp);
+		expo -= expo2;
+		exp[7] = 0x1e;
 		exp[0] |= (3 << 4);
-		exp[2] = 0x2d;
+		exp[2] = 0x2d;			/* ADVFL & ADVFH */
 		exp[3] = expo;
 		exp[4] = expo >> 8;
 		break;
@@ -1676,13 +1506,15 @@
 	i2c_w(gspca_dev, exp);
 }
 
-static void set_gain(struct gspca_dev *gspca_dev)
+static void set_gain(struct gspca_dev *gspca_dev, s32 g)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
-	int g;
+	u8 gain[8] = {sd->i2c_intf, sd->i2c_addr,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
 
-	g = sd->ctrls[GAIN].val;
+	if (gspca_dev->streaming)
+		gain[7] = 0x15;		/* or 1d ? */
+
 	switch (sd->sensor) {
 	case SENSOR_OV7660:
 	case SENSOR_OV7670:
@@ -1721,11 +1553,11 @@
 	i2c_w(gspca_dev, gain);
 }
 
-static void set_quality(struct gspca_dev *gspca_dev)
+static void set_quality(struct gspca_dev *gspca_dev, s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+	jpeg_set_qual(sd->jpeg_hdr, val);
 	reg_w1(gspca_dev, 0x1061, 0x01);	/* stop transfer */
 	reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
 	reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
@@ -1827,6 +1659,7 @@
 	sd->sensor = id->driver_info >> 8;
 	sd->i2c_addr = id->driver_info;
 	sd->flags = id->driver_info >> 16;
+	sd->i2c_intf = 0x80;			/* i2c 100 Kb/s */
 
 	switch (sd->sensor) {
 	case SENSOR_MT9M112:
@@ -1840,6 +1673,9 @@
 		cam->cam_mode = mono_mode;
 		cam->nmodes = ARRAY_SIZE(mono_mode);
 		break;
+	case SENSOR_HV7131R:
+		sd->i2c_intf = 0x81;			/* i2c 400 Kb/s */
+		/* fall thru */
 	default:
 		cam->cam_mode = vga_mode;
 		cam->nmodes = ARRAY_SIZE(vga_mode);
@@ -1850,13 +1686,133 @@
 	sd->older_step = 0;
 	sd->exposure_step = 16;
 
-	gspca_dev->cam.ctrls = sd->ctrls;
-
 	INIT_WORK(&sd->work, qual_upd);
 
 	return 0;
 }
 
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	gspca_dev->usb_err = 0;
+
+	if (!gspca_dev->streaming)
+		return 0;
+
+	switch (ctrl->id) {
+	/* color control cluster */
+	case V4L2_CID_BRIGHTNESS:
+		set_cmatrix(gspca_dev, sd->brightness->val,
+			sd->contrast->val, sd->saturation->val, sd->hue->val);
+		break;
+	case V4L2_CID_GAMMA:
+		set_gamma(gspca_dev, ctrl->val);
+		break;
+	/* blue/red balance cluster */
+	case V4L2_CID_BLUE_BALANCE:
+		set_redblue(gspca_dev, sd->blue->val, sd->red->val);
+		break;
+	/* h/vflip cluster */
+	case V4L2_CID_HFLIP:
+		set_hvflip(gspca_dev, sd->hflip->val, sd->vflip->val);
+		break;
+	/* standalone exposure control */
+	case V4L2_CID_EXPOSURE:
+		set_exposure(gspca_dev, ctrl->val);
+		break;
+	/* standalone gain control */
+	case V4L2_CID_GAIN:
+		set_gain(gspca_dev, ctrl->val);
+		break;
+	/* autogain + exposure or gain control cluster */
+	case V4L2_CID_AUTOGAIN:
+		if (sd->sensor == SENSOR_SOI968)
+			set_gain(gspca_dev, sd->gain->val);
+		else
+			set_exposure(gspca_dev, sd->exposure->val);
+		break;
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+		set_quality(gspca_dev, ctrl->val);
+		break;
+	}
+	return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+	.s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 13);
+
+	sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+	sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 127);
+	sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 127);
+	sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_HUE, -180, 180, 1, 0);
+	v4l2_ctrl_cluster(4, &sd->brightness);
+
+	sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_GAMMA, 0, 255, 1, 0x10);
+
+	sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0x28);
+	sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_RED_BALANCE, 0, 127, 1, 0x28);
+	v4l2_ctrl_cluster(2, &sd->blue);
+
+	if (sd->sensor != SENSOR_OV9655 && sd->sensor != SENSOR_SOI968 &&
+	    sd->sensor != SENSOR_OV7670 && sd->sensor != SENSOR_MT9M001 &&
+	    sd->sensor != SENSOR_MT9VPRB) {
+		sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+		sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+		v4l2_ctrl_cluster(2, &sd->hflip);
+	}
+
+	if (sd->sensor != SENSOR_SOI968 && sd->sensor != SENSOR_MT9VPRB &&
+	    sd->sensor != SENSOR_MT9M112 && sd->sensor != SENSOR_MT9M111 &&
+	    sd->sensor != SENSOR_MT9V111)
+		sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_EXPOSURE, 0, 0x1780, 1, 0x33);
+
+	if (sd->sensor != SENSOR_MT9VPRB && sd->sensor != SENSOR_MT9M112 &&
+	    sd->sensor != SENSOR_MT9M111 && sd->sensor != SENSOR_MT9V111) {
+		sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_GAIN, 0, 28, 1, 0);
+		sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+		if (sd->sensor == SENSOR_SOI968)
+			/* this sensor doesn't have the exposure control and
+			   autogain is clustered with gain instead. This works
+			   because sd->exposure == NULL. */
+			v4l2_ctrl_auto_cluster(3, &sd->autogain, 0, false);
+		else
+			/* Otherwise autogain is clustered with exposure. */
+			v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
+	}
+
+	sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80);
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+	return 0;
+}
+
 static int sd_init(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1949,7 +1905,6 @@
 		pr_err("Unsupported sensor\n");
 		gspca_dev->usb_err = -ENODEV;
 	}
-
 	return gspca_dev->usb_err;
 }
 
@@ -2025,8 +1980,8 @@
 
 		if (intf->num_altsetting != 9) {
 			pr_warn("sn9c20x camera with unknown number of alt "
-			        "settings (%d), please report!\n",
-			        intf->num_altsetting);
+				"settings (%d), please report!\n",
+				intf->num_altsetting);
 			gspca_dev->alt = intf->num_altsetting;
 			return 0;
 		}
@@ -2067,7 +2022,7 @@
 
 	jpeg_define(sd->jpeg_hdr, height, width,
 			0x21);
-	jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+	jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
 
 	if (mode & MODE_RAW)
 		fmt = 0x2d;
@@ -2104,12 +2059,17 @@
 	reg_w1(gspca_dev, 0x1189, scale);
 	reg_w1(gspca_dev, 0x10e0, fmt);
 
-	set_cmatrix(gspca_dev);
-	set_gamma(gspca_dev);
-	set_redblue(gspca_dev);
-	set_gain(gspca_dev);
-	set_exposure(gspca_dev);
-	set_hvflip(gspca_dev);
+	set_cmatrix(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness),
+			v4l2_ctrl_g_ctrl(sd->contrast),
+			v4l2_ctrl_g_ctrl(sd->saturation),
+			v4l2_ctrl_g_ctrl(sd->hue));
+	set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
+	set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue),
+			v4l2_ctrl_g_ctrl(sd->red));
+	set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
+	set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
+	set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
+			v4l2_ctrl_g_ctrl(sd->vflip));
 
 	reg_w1(gspca_dev, 0x1007, 0x20);
 	reg_w1(gspca_dev, 0x1061, 0x03);
@@ -2148,6 +2108,9 @@
 static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	s32 cur_exp = v4l2_ctrl_g_ctrl(sd->exposure);
+	s32 max = sd->exposure->maximum - sd->exposure_step;
+	s32 min = sd->exposure->minimum + sd->exposure_step;
 	s16 new_exp;
 
 	/*
@@ -2156,16 +2119,15 @@
 	 * and exposure steps
 	 */
 	if (avg_lum < MIN_AVG_LUM) {
-		if (sd->ctrls[EXPOSURE].val > 0x1770)
+		if (cur_exp > max)
 			return;
 
-		new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step;
-		if (new_exp > 0x1770)
-			new_exp = 0x1770;
-		if (new_exp < 0x10)
-			new_exp = 0x10;
-		sd->ctrls[EXPOSURE].val = new_exp;
-		set_exposure(gspca_dev);
+		new_exp = cur_exp + sd->exposure_step;
+		if (new_exp > max)
+			new_exp = max;
+		if (new_exp < min)
+			new_exp = min;
+		v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
 
 		sd->older_step = sd->old_step;
 		sd->old_step = 1;
@@ -2176,15 +2138,14 @@
 			sd->exposure_step += 2;
 	}
 	if (avg_lum > MAX_AVG_LUM) {
-		if (sd->ctrls[EXPOSURE].val < 0x10)
+		if (cur_exp < min)
 			return;
-		new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step;
-		if (new_exp > 0x1700)
-			new_exp = 0x1770;
-		if (new_exp < 0x10)
-			new_exp = 0x10;
-		sd->ctrls[EXPOSURE].val = new_exp;
-		set_exposure(gspca_dev);
+		new_exp = cur_exp - sd->exposure_step;
+		if (new_exp > max)
+			new_exp = max;
+		if (new_exp < min)
+			new_exp = min;
+		v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
 		sd->older_step = sd->old_step;
 		sd->old_step = 0;
 
@@ -2198,19 +2159,12 @@
 static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
 
-	if (avg_lum < MIN_AVG_LUM) {
-		if (sd->ctrls[GAIN].val + 1 <= 28) {
-			sd->ctrls[GAIN].val++;
-			set_gain(gspca_dev);
-		}
-	}
-	if (avg_lum > MAX_AVG_LUM) {
-		if (sd->ctrls[GAIN].val > 0) {
-			sd->ctrls[GAIN].val--;
-			set_gain(gspca_dev);
-		}
-	}
+	if (avg_lum < MIN_AVG_LUM && cur_gain < sd->gain->maximum)
+		v4l2_ctrl_s_ctrl(sd->gain, cur_gain + 1);
+	if (avg_lum > MAX_AVG_LUM && cur_gain > sd->gain->minimum)
+		v4l2_ctrl_s_ctrl(sd->gain, cur_gain - 1);
 }
 
 static void sd_dqcallback(struct gspca_dev *gspca_dev)
@@ -2218,7 +2172,7 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	int avg_lum;
 
-	if (!sd->ctrls[AUTOGAIN].val)
+	if (!v4l2_ctrl_g_ctrl(sd->autogain))
 		return;
 
 	avg_lum = atomic_read(&sd->avg_lum);
@@ -2234,10 +2188,11 @@
 {
 	struct sd *sd = container_of(work, struct sd, work);
 	struct gspca_dev *gspca_dev = &sd->gspca_dev;
+	s32 qual = v4l2_ctrl_g_ctrl(sd->jpegqual);
 
 	mutex_lock(&gspca_dev->usb_lock);
-	PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val);
-	set_quality(gspca_dev);
+	PDEBUG(D_STREAM, "qual_upd %d%%", qual);
+	set_quality(gspca_dev, qual);
 	mutex_unlock(&gspca_dev->usb_lock);
 }
 
@@ -2286,14 +2241,18 @@
 	if (new_qual != 0) {
 		sd->nchg += new_qual;
 		if (sd->nchg < -6 || sd->nchg >= 12) {
+			/* Note: we are in interrupt context, so we can't
+			   use v4l2_ctrl_g/s_ctrl here. Access the value
+			   directly instead. */
+			s32 curqual = sd->jpegqual->cur.val;
 			sd->nchg = 0;
-			new_qual += sd->ctrls[QUALITY].val;
-			if (new_qual < QUALITY_MIN)
-				new_qual = QUALITY_MIN;
-			else if (new_qual > QUALITY_MAX)
-				new_qual = QUALITY_MAX;
-			if (new_qual != sd->ctrls[QUALITY].val) {
-				sd->ctrls[QUALITY].val = new_qual;
+			new_qual += curqual;
+			if (new_qual < sd->jpegqual->minimum)
+				new_qual = sd->jpegqual->minimum;
+			else if (new_qual > sd->jpegqual->maximum)
+				new_qual = sd->jpegqual->maximum;
+			if (new_qual != curqual) {
+				sd->jpegqual->cur.val = new_qual;
 				queue_work(sd->work_thread, &sd->work);
 			}
 		}
@@ -2309,7 +2268,7 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int avg_lum, is_jpeg;
-	static u8 frame_header[] =
+	static const u8 frame_header[] =
 		{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
 
 	is_jpeg = (sd->fmt & 0x03) == 0;
@@ -2373,10 +2332,9 @@
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
 	.name = KBUILD_MODNAME,
-	.ctrls = sd_ctrls,
-	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
 	.init = sd_init,
+	.init_controls = sd_init_controls,
 	.isoc_init = sd_isoc_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 6a1148d..e2bdf8f 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -1000,6 +1000,8 @@
 	}
 }
 
+#define WANT_REGULAR_AUTOGAIN
+#define WANT_COARSE_EXPO_AUTOGAIN
 #include "autogain_functions.h"
 
 static void do_autogain(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 863c755..4d1696d 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -2800,10 +2800,7 @@
 	}
 }
 
-/* !! coarse_grained_expo_autogain is not used !! */
-#define exp_too_low_cnt bridge
-#define exp_too_high_cnt sensor
-
+#define WANT_REGULAR_AUTOGAIN
 #include "autogain_functions.h"
 
 static void do_autogain(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c
index 2fe3c29..04f5465 100644
--- a/drivers/media/video/gspca/sq905.c
+++ b/drivers/media/video/gspca/sq905.c
@@ -232,7 +232,11 @@
 	frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage
 			+ FRAME_HEADER_LEN;
 
-	while (gspca_dev->present && gspca_dev->streaming) {
+	while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			break;
+#endif
 		/* request some data and then read it until we have
 		 * a complete frame. */
 		bytes_left = frame_sz;
@@ -242,7 +246,7 @@
 		   we must finish reading an entire frame, otherwise the
 		   next time we stream we start reading in the middle of a
 		   frame. */
-		while (bytes_left > 0 && gspca_dev->present) {
+		while (bytes_left > 0 && gspca_dev->dev) {
 			data_len = bytes_left > SQ905_MAX_TRANSFER ?
 				SQ905_MAX_TRANSFER : bytes_left;
 			ret = sq905_read_data(gspca_dev, buffer, data_len, 1);
@@ -274,7 +278,7 @@
 				gspca_frame_add(gspca_dev, LAST_PACKET,
 						NULL, 0);
 		}
-		if (gspca_dev->present) {
+		if (gspca_dev->dev) {
 			/* acknowledge the frame */
 			mutex_lock(&gspca_dev->usb_lock);
 			ret = sq905_ack_frame(gspca_dev);
@@ -284,7 +288,7 @@
 		}
 	}
 quit_stream:
-	if (gspca_dev->present) {
+	if (gspca_dev->dev) {
 		mutex_lock(&gspca_dev->usb_lock);
 		sq905_command(gspca_dev, SQ905_CLEAR);
 		mutex_unlock(&gspca_dev->usb_lock);
diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
index ae78363..f34ddb0 100644
--- a/drivers/media/video/gspca/sq905c.c
+++ b/drivers/media/video/gspca/sq905c.c
@@ -150,7 +150,11 @@
 		goto quit_stream;
 	}
 
-	while (gspca_dev->present && gspca_dev->streaming) {
+	while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			break;
+#endif
 		/* Request the header, which tells the size to download */
 		ret = usb_bulk_msg(gspca_dev->dev,
 				usb_rcvbulkpipe(gspca_dev->dev, 0x81),
@@ -169,7 +173,7 @@
 		packet_type = FIRST_PACKET;
 		gspca_frame_add(gspca_dev, packet_type,
 				buffer, FRAME_HEADER_LEN);
-		while (bytes_left > 0 && gspca_dev->present) {
+		while (bytes_left > 0 && gspca_dev->dev) {
 			data_len = bytes_left > SQ905C_MAX_TRANSFER ?
 				SQ905C_MAX_TRANSFER : bytes_left;
 			ret = usb_bulk_msg(gspca_dev->dev,
@@ -191,7 +195,7 @@
 		}
 	}
 quit_stream:
-	if (gspca_dev->present) {
+	if (gspca_dev->dev) {
 		mutex_lock(&gspca_dev->usb_lock);
 		sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
 		mutex_unlock(&gspca_dev->usb_lock);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 91d99b4..999ec77 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -261,6 +261,17 @@
 	return (err < 0) ? err : 0;
 }
 
+/* this function is called at probe time */
+static int stv06xx_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(D_PROBE, "Initializing controls");
+
+	gspca_dev->vdev.ctrl_handler = &gspca_dev->ctrl_handler;
+	return sd->sensor->init_controls(sd);
+}
+
 /* Start the camera */
 static int stv06xx_start(struct gspca_dev *gspca_dev)
 {
@@ -512,6 +523,7 @@
 	.name = MODULE_NAME,
 	.config = stv06xx_config,
 	.init = stv06xx_init,
+	.init_controls = stv06xx_init_controls,
 	.start = stv06xx_start,
 	.stopN = stv06xx_stopN,
 	.pkt_scan = stv06xx_pkt_scan,
@@ -530,9 +542,8 @@
 
 	PDEBUG(D_PROBE, "Configuring camera");
 
-	sd->desc = sd_desc;
 	sd->bridge = id->driver_info;
-	gspca_dev->sd_desc = &sd->desc;
+	gspca_dev->sd_desc = &sd_desc;
 
 	if (dump_bridge)
 		stv06xx_dump_bridge(sd);
@@ -594,11 +605,12 @@
 {
 	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
 	struct sd *sd = (struct sd *) gspca_dev;
+	void *priv = sd->sensor_priv;
 	PDEBUG(D_PROBE, "Disconnecting the stv06xx device");
 
-	if (sd->sensor->disconnect)
-		sd->sensor->disconnect(sd);
+	sd->sensor = NULL;
 	gspca_disconnect(intf);
+	kfree(priv);
 }
 
 static struct usb_driver sd_driver = {
@@ -609,6 +621,7 @@
 #ifdef CONFIG_PM
 	.suspend = gspca_suspend,
 	.resume = gspca_resume,
+	.reset_resume = gspca_resume,
 #endif
 };
 
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h
index d270a59..34957a4 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.h
@@ -89,9 +89,6 @@
 	/* A pointer to the currently connected sensor */
 	const struct stv06xx_sensor *sensor;
 
-	/* A pointer to the sd_desc struct */
-	struct sd_desc desc;
-
 	/* Sensor private data */
 	void *sensor_priv;
 
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
index a8698b7..06fa54c5e 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
@@ -32,36 +32,6 @@
 
 #include "stv06xx_hdcs.h"
 
-static const struct ctrl hdcs1x00_ctrl[] = {
-	{
-		{
-			.id		= V4L2_CID_EXPOSURE,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "exposure",
-			.minimum	= 0x00,
-			.maximum	= 0xff,
-			.step		= 0x1,
-			.default_value	= HDCS_DEFAULT_EXPOSURE,
-			.flags		= V4L2_CTRL_FLAG_SLIDER
-		},
-		.set = hdcs_set_exposure,
-		.get = hdcs_get_exposure
-	}, {
-		{
-			.id		= V4L2_CID_GAIN,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "gain",
-			.minimum	= 0x00,
-			.maximum	= 0xff,
-			.step		= 0x1,
-			.default_value	= HDCS_DEFAULT_GAIN,
-			.flags		= V4L2_CTRL_FLAG_SLIDER
-		},
-		.set = hdcs_set_gain,
-		.get = hdcs_get_gain
-	}
-};
-
 static struct v4l2_pix_format hdcs1x00_mode[] = {
 	{
 		HDCS_1X00_DEF_WIDTH,
@@ -76,36 +46,6 @@
 	}
 };
 
-static const struct ctrl hdcs1020_ctrl[] = {
-	{
-		{
-			.id		= V4L2_CID_EXPOSURE,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "exposure",
-			.minimum	= 0x00,
-			.maximum	= 0xffff,
-			.step		= 0x1,
-			.default_value	= HDCS_DEFAULT_EXPOSURE,
-			.flags		= V4L2_CTRL_FLAG_SLIDER
-		},
-		.set = hdcs_set_exposure,
-		.get = hdcs_get_exposure
-	}, {
-		{
-			.id		= V4L2_CID_GAIN,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "gain",
-			.minimum	= 0x00,
-			.maximum	= 0xff,
-			.step		= 0x1,
-			.default_value	= HDCS_DEFAULT_GAIN,
-			.flags		= V4L2_CTRL_FLAG_SLIDER
-		},
-		.set = hdcs_set_gain,
-		.get = hdcs_get_gain
-	}
-};
-
 static struct v4l2_pix_format hdcs1020_mode[] = {
 	{
 		HDCS_1020_DEF_WIDTH,
@@ -150,7 +90,6 @@
 	} exp;
 
 	int psmp;
-	u8 exp_cache, gain_cache;
 };
 
 static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
@@ -232,16 +171,6 @@
 	return err;
 }
 
-static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	struct hdcs *hdcs = sd->sensor_priv;
-
-	*val = hdcs->exp_cache;
-
-	return 0;
-}
-
 static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -260,9 +189,6 @@
 	int cycles, err;
 	u8 exp[14];
 
-	val &= 0xff;
-	hdcs->exp_cache = val;
-
 	cycles = val * HDCS_CLK_FREQ_MHZ * 257;
 
 	ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
@@ -336,12 +262,9 @@
 
 static int hdcs_set_gains(struct sd *sd, u8 g)
 {
-	struct hdcs *hdcs = sd->sensor_priv;
 	int err;
 	u8 gains[4];
 
-	hdcs->gain_cache = g;
-
 	/* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */
 	if (g > 127)
 		g = 0x80 | (g / 2);
@@ -352,17 +275,7 @@
 	gains[3] = g;
 
 	err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
-		return err;
-}
-
-static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	struct hdcs *hdcs = sd->sensor_priv;
-
-	*val = hdcs->gain_cache;
-
-	return 0;
+	return err;
 }
 
 static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -420,6 +333,39 @@
 	return err;
 }
 
+static int hdcs_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	int err = -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN:
+		err = hdcs_set_gain(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_EXPOSURE:
+		err = hdcs_set_exposure(gspca_dev, ctrl->val);
+		break;
+	}
+	return err;
+}
+
+static const struct v4l2_ctrl_ops hdcs_ctrl_ops = {
+	.s_ctrl = hdcs_s_ctrl,
+};
+
+static int hdcs_init_controls(struct sd *sd)
+{
+	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+	v4l2_ctrl_handler_init(hdl, 2);
+	v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops,
+			V4L2_CID_EXPOSURE, 0, 0xff, 1, HDCS_DEFAULT_EXPOSURE);
+	v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops,
+			V4L2_CID_GAIN, 0, 0xff, 1, HDCS_DEFAULT_GAIN);
+	return hdl->error;
+}
+
 static int hdcs_probe_1x00(struct sd *sd)
 {
 	struct hdcs *hdcs;
@@ -434,8 +380,6 @@
 
 	sd->gspca_dev.cam.cam_mode = hdcs1x00_mode;
 	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode);
-	sd->desc.ctrls = hdcs1x00_ctrl;
-	sd->desc.nctrls = ARRAY_SIZE(hdcs1x00_ctrl);
 
 	hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
 	if (!hdcs)
@@ -493,8 +437,6 @@
 
 	sd->gspca_dev.cam.cam_mode = hdcs1020_mode;
 	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode);
-	sd->desc.ctrls = hdcs1020_ctrl;
-	sd->desc.nctrls = ARRAY_SIZE(hdcs1020_ctrl);
 
 	hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
 	if (!hdcs)
@@ -537,12 +479,6 @@
 	return hdcs_set_state(sd, HDCS_STATE_SLEEP);
 }
 
-static void hdcs_disconnect(struct sd *sd)
-{
-	PDEBUG(D_PROBE, "Disconnecting the sensor");
-	kfree(sd->sensor_priv);
-}
-
 static int hdcs_init(struct sd *sd)
 {
 	struct hdcs *hdcs = sd->sensor_priv;
@@ -587,16 +523,7 @@
 	if (err < 0)
 		return err;
 
-	err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN);
-	if (err < 0)
-		return err;
-
-	err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
-	if (err < 0)
-		return err;
-
-	err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
-	return err;
+	return hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
 }
 
 static int hdcs_dump(struct sd *sd)
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
index a14a84a..1ba9158 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
@@ -131,14 +131,12 @@
 static int hdcs_probe_1020(struct sd *sd);
 static int hdcs_start(struct sd *sd);
 static int hdcs_init(struct sd *sd);
+static int hdcs_init_controls(struct sd *sd);
 static int hdcs_stop(struct sd *sd);
 static int hdcs_dump(struct sd *sd);
-static void hdcs_disconnect(struct sd *sd);
 
-static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
 static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
 static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
 
 const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
 	.name = "HP HDCS-1000/1100",
@@ -152,10 +150,10 @@
 	.max_packet_size = { 847 },
 
 	.init = hdcs_init,
+	.init_controls = hdcs_init_controls,
 	.probe = hdcs_probe_1x00,
 	.start = hdcs_start,
 	.stop = hdcs_stop,
-	.disconnect = hdcs_disconnect,
 	.dump = hdcs_dump,
 };
 
@@ -171,6 +169,7 @@
 	.max_packet_size = { 847 },
 
 	.init = hdcs_init,
+	.init_controls = hdcs_init_controls,
 	.probe = hdcs_probe_1020,
 	.start = hdcs_start,
 	.stop = hdcs_stop,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
index 26f14fc..cdfc3d0 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
@@ -48,105 +48,16 @@
 
 #include "stv06xx_pb0100.h"
 
-static const struct ctrl pb0100_ctrl[] = {
-#define GAIN_IDX 0
-	{
-		{
-			.id		= V4L2_CID_GAIN,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "Gain",
-			.minimum	= 0,
-			.maximum	= 255,
-			.step		= 1,
-			.default_value  = 128
-		},
-		.set = pb0100_set_gain,
-		.get = pb0100_get_gain
-	},
-#define RED_BALANCE_IDX 1
-	{
-		{
-			.id		= V4L2_CID_RED_BALANCE,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "Red Balance",
-			.minimum	= -255,
-			.maximum	= 255,
-			.step		= 1,
-			.default_value  = 0
-		},
-		.set = pb0100_set_red_balance,
-		.get = pb0100_get_red_balance
-	},
-#define BLUE_BALANCE_IDX 2
-	{
-		{
-			.id		= V4L2_CID_BLUE_BALANCE,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "Blue Balance",
-			.minimum	= -255,
-			.maximum	= 255,
-			.step		= 1,
-			.default_value  = 0
-		},
-		.set = pb0100_set_blue_balance,
-		.get = pb0100_get_blue_balance
-	},
-#define EXPOSURE_IDX 3
-	{
-		{
-			.id		= V4L2_CID_EXPOSURE,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "Exposure",
-			.minimum	= 0,
-			.maximum	= 511,
-			.step		= 1,
-			.default_value  = 12
-		},
-		.set = pb0100_set_exposure,
-		.get = pb0100_get_exposure
-	},
-#define AUTOGAIN_IDX 4
-	{
-		{
-			.id		= V4L2_CID_AUTOGAIN,
-			.type		= V4L2_CTRL_TYPE_BOOLEAN,
-			.name		= "Automatic Gain and Exposure",
-			.minimum	= 0,
-			.maximum	= 1,
-			.step		= 1,
-			.default_value  = 1
-		},
-		.set = pb0100_set_autogain,
-		.get = pb0100_get_autogain
-	},
-#define AUTOGAIN_TARGET_IDX 5
-	{
-		{
-			.id		= V4L2_CTRL_CLASS_USER + 0x1000,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "Automatic Gain Target",
-			.minimum	= 0,
-			.maximum	= 255,
-			.step		= 1,
-			.default_value  = 128
-		},
-		.set = pb0100_set_autogain_target,
-		.get = pb0100_get_autogain_target
-	},
-#define NATURAL_IDX 6
-	{
-		{
-			.id		= V4L2_CTRL_CLASS_USER + 0x1001,
-			.type		= V4L2_CTRL_TYPE_BOOLEAN,
-			.name		= "Natural Light Source",
-			.minimum	= 0,
-			.maximum	= 1,
-			.step		= 1,
-			.default_value  = 1
-		},
-		.set = pb0100_set_natural,
-		.get = pb0100_get_natural
-	}
+struct pb0100_ctrls {
+	struct { /* one big happy control cluster... */
+		struct v4l2_ctrl *autogain;
+		struct v4l2_ctrl *gain;
+		struct v4l2_ctrl *exposure;
+		struct v4l2_ctrl *red;
+		struct v4l2_ctrl *blue;
+		struct v4l2_ctrl *natural;
+	};
+	struct v4l2_ctrl *target;
 };
 
 static struct v4l2_pix_format pb0100_mode[] = {
@@ -174,38 +85,104 @@
 	}
 };
 
+static int pb0100_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+	struct pb0100_ctrls *ctrls = sd->sensor_priv;
+	int err = -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+		err = pb0100_set_autogain(gspca_dev, ctrl->val);
+		if (err)
+			break;
+		if (ctrl->val)
+			break;
+		err = pb0100_set_gain(gspca_dev, ctrls->gain->val);
+		if (err)
+			break;
+		err = pb0100_set_exposure(gspca_dev, ctrls->exposure->val);
+		break;
+	case V4L2_CTRL_CLASS_USER + 0x1001:
+		err = pb0100_set_autogain_target(gspca_dev, ctrl->val);
+		break;
+	}
+	return err;
+}
+
+static const struct v4l2_ctrl_ops pb0100_ctrl_ops = {
+	.s_ctrl = pb0100_s_ctrl,
+};
+
+static int pb0100_init_controls(struct sd *sd)
+{
+	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+	struct pb0100_ctrls *ctrls;
+	static const struct v4l2_ctrl_config autogain_target = {
+		.ops = &pb0100_ctrl_ops,
+		.id = V4L2_CTRL_CLASS_USER + 0x1000,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Automatic Gain Target",
+		.max = 255,
+		.step = 1,
+		.def = 128,
+	};
+	static const struct v4l2_ctrl_config natural_light = {
+		.ops = &pb0100_ctrl_ops,
+		.id = V4L2_CTRL_CLASS_USER + 0x1001,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Natural Light Source",
+		.max = 1,
+		.step = 1,
+		.def = 1,
+	};
+
+	ctrls = kzalloc(sizeof(*ctrls), GFP_KERNEL);
+	if (!ctrls)
+		return -ENOMEM;
+
+	v4l2_ctrl_handler_init(hdl, 6);
+	ctrls->autogain = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	ctrls->exposure = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+			V4L2_CID_EXPOSURE, 0, 511, 1, 12);
+	ctrls->gain = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+			V4L2_CID_GAIN, 0, 255, 1, 128);
+	ctrls->red = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+			V4L2_CID_RED_BALANCE, -255, 255, 1, 0);
+	ctrls->blue = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+			V4L2_CID_BLUE_BALANCE, -255, 255, 1, 0);
+	ctrls->natural = v4l2_ctrl_new_custom(hdl, &natural_light, NULL);
+	ctrls->target = v4l2_ctrl_new_custom(hdl, &autogain_target, NULL);
+	if (hdl->error) {
+		kfree(ctrls);
+		return hdl->error;
+	}
+	sd->sensor_priv = ctrls;
+	v4l2_ctrl_auto_cluster(5, &ctrls->autogain, 0, false);
+	return 0;
+}
+
 static int pb0100_probe(struct sd *sd)
 {
 	u16 sensor;
-	int i, err;
-	s32 *sensor_settings;
+	int err;
 
 	err = stv06xx_read_sensor(sd, PB_IDENT, &sensor);
 
 	if (err < 0)
 		return -ENODEV;
+	if ((sensor >> 8) != 0x64)
+		return -ENODEV;
 
-	if ((sensor >> 8) == 0x64) {
-		sensor_settings = kmalloc(
-				ARRAY_SIZE(pb0100_ctrl) * sizeof(s32),
-				GFP_KERNEL);
-		if (!sensor_settings)
-			return -ENOMEM;
+	pr_info("Photobit pb0100 sensor detected\n");
 
-		pr_info("Photobit pb0100 sensor detected\n");
+	sd->gspca_dev.cam.cam_mode = pb0100_mode;
+	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
 
-		sd->gspca_dev.cam.cam_mode = pb0100_mode;
-		sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
-		sd->desc.ctrls = pb0100_ctrl;
-		sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl);
-		for (i = 0; i < sd->desc.nctrls; i++)
-			sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value;
-		sd->sensor_priv = sensor_settings;
-
-		return 0;
-	}
-
-	return -ENODEV;
+	return 0;
 }
 
 static int pb0100_start(struct sd *sd)
@@ -214,7 +191,6 @@
 	struct usb_host_interface *alt;
 	struct usb_interface *intf;
 	struct cam *cam = &sd->gspca_dev.cam;
-	s32 *sensor_settings = sd->sensor_priv;
 	u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
 
 	intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
@@ -255,13 +231,6 @@
 		stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
 	}
 
-	/* set_gain also sets red and blue balance */
-	pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
-	pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
-	pb0100_set_autogain_target(&sd->gspca_dev,
-				   sensor_settings[AUTOGAIN_TARGET_IDX]);
-	pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]);
-
 	err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1));
 	PDEBUG(D_STREAM, "Started stream, status: %d", err);
 
@@ -285,12 +254,6 @@
 	return (err < 0) ? err : 0;
 }
 
-static void pb0100_disconnect(struct sd *sd)
-{
-	sd->sensor = NULL;
-	kfree(sd->sensor_priv);
-}
-
 /* FIXME: Sort the init commands out and put them into tables,
 	  this is only for getting the camera to work */
 /* FIXME: No error handling for now,
@@ -362,62 +325,32 @@
 	return 0;
 }
 
-static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[GAIN_IDX];
-
-	return 0;
-}
-
 static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	int err;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
+	struct pb0100_ctrls *ctrls = sd->sensor_priv;
 
-	if (sensor_settings[AUTOGAIN_IDX])
-		return -EBUSY;
-
-	sensor_settings[GAIN_IDX] = val;
 	err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
 	if (!err)
 		err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
 	PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err);
 
 	if (!err)
-		err = pb0100_set_red_balance(gspca_dev,
-					     sensor_settings[RED_BALANCE_IDX]);
+		err = pb0100_set_red_balance(gspca_dev, ctrls->red->val);
 	if (!err)
-		err = pb0100_set_blue_balance(gspca_dev,
-					    sensor_settings[BLUE_BALANCE_IDX]);
+		err = pb0100_set_blue_balance(gspca_dev, ctrls->blue->val);
 
 	return err;
 }
 
-static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[RED_BALANCE_IDX];
-
-	return 0;
-}
-
 static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
 	int err;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
+	struct pb0100_ctrls *ctrls = sd->sensor_priv;
 
-	if (sensor_settings[AUTOGAIN_IDX])
-		return -EBUSY;
-
-	sensor_settings[RED_BALANCE_IDX] = val;
-	val += sensor_settings[GAIN_IDX];
+	val += ctrls->gain->val;
 	if (val < 0)
 		val = 0;
 	else if (val > 255)
@@ -429,27 +362,13 @@
 	return err;
 }
 
-static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[BLUE_BALANCE_IDX];
-
-	return 0;
-}
-
 static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
 	int err;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
+	struct pb0100_ctrls *ctrls = sd->sensor_priv;
 
-	if (sensor_settings[AUTOGAIN_IDX])
-		return -EBUSY;
-
-	sensor_settings[BLUE_BALANCE_IDX] = val;
-	val += sensor_settings[GAIN_IDX];
+	val += ctrls->gain->val;
 	if (val < 0)
 		val = 0;
 	else if (val > 255)
@@ -461,51 +380,25 @@
 	return err;
 }
 
-static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[EXPOSURE_IDX];
-
-	return 0;
-}
-
 static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
-	int err;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
+	int err;
 
-	if (sensor_settings[AUTOGAIN_IDX])
-		return -EBUSY;
-
-	sensor_settings[EXPOSURE_IDX] = val;
 	err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
 	PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err);
 
 	return err;
 }
 
-static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[AUTOGAIN_IDX];
-
-	return 0;
-}
-
 static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	int err;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
+	struct pb0100_ctrls *ctrls = sd->sensor_priv;
 
-	sensor_settings[AUTOGAIN_IDX] = val;
-	if (sensor_settings[AUTOGAIN_IDX]) {
-		if (sensor_settings[NATURAL_IDX])
+	if (val) {
+		if (ctrls->natural->val)
 			val = BIT(6)|BIT(4)|BIT(0);
 		else
 			val = BIT(4)|BIT(0);
@@ -514,29 +407,15 @@
 
 	err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
 	PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d",
-	       sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX],
-	       err);
+	       val, ctrls->natural->val, err);
 
 	return err;
 }
 
-static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[AUTOGAIN_TARGET_IDX];
-
-	return 0;
-}
-
 static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
 {
 	int err, totalpixels, brightpixels, darkpixels;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	sensor_settings[AUTOGAIN_TARGET_IDX] = val;
 
 	/* Number of pixels counted by the sensor when subsampling the pixels.
 	 * Slightly larger than the real value to avoid oscillation */
@@ -553,23 +432,3 @@
 
 	return err;
 }
-
-static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[NATURAL_IDX];
-
-	return 0;
-}
-
-static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	sensor_settings[NATURAL_IDX] = val;
-
-	return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]);
-}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
index 757de24..5071e53 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
@@ -112,25 +112,17 @@
 static int pb0100_probe(struct sd *sd);
 static int pb0100_start(struct sd *sd);
 static int pb0100_init(struct sd *sd);
+static int pb0100_init_controls(struct sd *sd);
 static int pb0100_stop(struct sd *sd);
 static int pb0100_dump(struct sd *sd);
-static void pb0100_disconnect(struct sd *sd);
 
 /* V4L2 controls supported by the driver */
-static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
 static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
 static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
 static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
 static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val);
 static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val);
 static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val);
-static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val);
 
 const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
 	.name = "PB-0100",
@@ -142,11 +134,11 @@
 	.max_packet_size = { 847, 923 },
 
 	.init = pb0100_init,
+	.init_controls = pb0100_init_controls,
 	.probe = pb0100_probe,
 	.start = pb0100_start,
 	.stop = pb0100_stop,
 	.dump = pb0100_dump,
-	.disconnect = pb0100_disconnect,
 };
 
 #endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
index fb229d8..3a498c2 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
@@ -63,8 +63,8 @@
 	/* Performs a initialization sequence */
 	int (*init)(struct sd *sd);
 
-	/* Executed at device disconnect */
-	void (*disconnect)(struct sd *sd);
+	/* Initializes the controls */
+	int (*init_controls)(struct sd *sd);
 
 	/* Reads a sensor register */
 	int (*read_sensor)(struct sd *sd, const u8 address,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
index 9940e03..8a57990 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
@@ -30,20 +30,6 @@
 
 #include "stv06xx_st6422.h"
 
-/* controls */
-enum e_ctrl {
-	BRIGHTNESS,
-	CONTRAST,
-	GAIN,
-	EXPOSURE,
-	NCTRLS		/* number of controls */
-};
-
-/* sensor settings */
-struct st6422_settings {
-	struct gspca_ctrl ctrls[NCTRLS];
-};
-
 static struct v4l2_pix_format st6422_mode[] = {
 	/* Note we actually get 124 lines of data, of which we skip the 4st
 	   4 as they are garbage */
@@ -74,83 +60,70 @@
 };
 
 /* V4L2 controls supported by the driver */
-static void st6422_set_brightness(struct gspca_dev *gspca_dev);
-static void st6422_set_contrast(struct gspca_dev *gspca_dev);
-static void st6422_set_gain(struct gspca_dev *gspca_dev);
-static void st6422_set_exposure(struct gspca_dev *gspca_dev);
+static int setbrightness(struct sd *sd, s32 val);
+static int setcontrast(struct sd *sd, s32 val);
+static int setgain(struct sd *sd, u8 gain);
+static int setexposure(struct sd *sd, s16 expo);
 
-static const struct ctrl st6422_ctrl[NCTRLS] = {
-[BRIGHTNESS] = {
-		{
-			.id		= V4L2_CID_BRIGHTNESS,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "Brightness",
-			.minimum	= 0,
-			.maximum	= 31,
-			.step		= 1,
-			.default_value  = 3
-		},
-		.set_control = st6422_set_brightness
-	},
-[CONTRAST] = {
-		{
-			.id		= V4L2_CID_CONTRAST,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "Contrast",
-			.minimum	= 0,
-			.maximum	= 15,
-			.step		= 1,
-			.default_value  = 11
-		},
-		.set_control = st6422_set_contrast
-	},
-[GAIN] = {
-		{
-			.id		= V4L2_CID_GAIN,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "Gain",
-			.minimum	= 0,
-			.maximum	= 255,
-			.step		= 1,
-			.default_value  = 64
-		},
-		.set_control = st6422_set_gain
-	},
-[EXPOSURE] = {
-		{
-			.id		= V4L2_CID_EXPOSURE,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "Exposure",
-			.minimum	= 0,
-#define EXPOSURE_MAX 1023
-			.maximum	= EXPOSURE_MAX,
-			.step		= 1,
-			.default_value  = 256
-		},
-		.set_control = st6422_set_exposure
-	},
+static int st6422_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+	int err = -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		err = setbrightness(sd, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		err = setcontrast(sd, ctrl->val);
+		break;
+	case V4L2_CID_GAIN:
+		err = setgain(sd, ctrl->val);
+		break;
+	case V4L2_CID_EXPOSURE:
+		err = setexposure(sd, ctrl->val);
+		break;
+	}
+
+	/* commit settings */
+	if (err >= 0)
+		err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+	sd->gspca_dev.usb_err = err;
+	return err;
+}
+
+static const struct v4l2_ctrl_ops st6422_ctrl_ops = {
+	.s_ctrl = st6422_s_ctrl,
 };
 
+static int st6422_init_controls(struct sd *sd)
+{
+	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 31, 1, 3);
+	v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 15, 1, 11);
+	v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops,
+			V4L2_CID_EXPOSURE, 0, 1023, 1, 256);
+	v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops,
+			V4L2_CID_GAIN, 0, 255, 1, 64);
+
+	return hdl->error;
+}
+
 static int st6422_probe(struct sd *sd)
 {
-	struct st6422_settings *sensor_settings;
-
 	if (sd->bridge != BRIDGE_ST6422)
 		return -ENODEV;
 
 	pr_info("st6422 sensor detected\n");
 
-	sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL);
-	if (!sensor_settings)
-		return -ENOMEM;
-
 	sd->gspca_dev.cam.cam_mode = st6422_mode;
 	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode);
-	sd->gspca_dev.cam.ctrls = sensor_settings->ctrls;
-	sd->desc.ctrls = st6422_ctrl;
-	sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl);
-	sd->sensor_priv = sensor_settings;
-
 	return 0;
 }
 
@@ -239,38 +212,22 @@
 	return err;
 }
 
-static void st6422_disconnect(struct sd *sd)
+static int setbrightness(struct sd *sd, s32 val)
 {
-	sd->sensor = NULL;
-	kfree(sd->sensor_priv);
-}
-
-static int setbrightness(struct sd *sd)
-{
-	struct st6422_settings *sensor_settings = sd->sensor_priv;
-
 	/* val goes from 0 -> 31 */
-	return stv06xx_write_bridge(sd, 0x1432,
-			sensor_settings->ctrls[BRIGHTNESS].val);
+	return stv06xx_write_bridge(sd, 0x1432, val);
 }
 
-static int setcontrast(struct sd *sd)
+static int setcontrast(struct sd *sd, s32 val)
 {
-	struct st6422_settings *sensor_settings = sd->sensor_priv;
-
 	/* Val goes from 0 -> 15 */
-	return stv06xx_write_bridge(sd, 0x143a,
-			sensor_settings->ctrls[CONTRAST].val | 0xf0);
+	return stv06xx_write_bridge(sd, 0x143a, val | 0xf0);
 }
 
-static int setgain(struct sd *sd)
+static int setgain(struct sd *sd, u8 gain)
 {
-	struct st6422_settings *sensor_settings = sd->sensor_priv;
-	u8 gain;
 	int err;
 
-	gain = sensor_settings->ctrls[GAIN].val;
-
 	/* Set red, green, blue, gain */
 	err = stv06xx_write_bridge(sd, 0x0509, gain);
 	if (err < 0)
@@ -292,13 +249,10 @@
 	return stv06xx_write_bridge(sd, 0x050d, 0x01);
 }
 
-static int setexposure(struct sd *sd)
+static int setexposure(struct sd *sd, s16 expo)
 {
-	struct st6422_settings *sensor_settings = sd->sensor_priv;
-	u16 expo;
 	int err;
 
-	expo = sensor_settings->ctrls[EXPOSURE].val;
 	err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff);
 	if (err < 0)
 		return err;
@@ -318,22 +272,6 @@
 	if (err < 0)
 		return err;
 
-	err = setbrightness(sd);
-	if (err < 0)
-		return err;
-
-	err = setcontrast(sd);
-	if (err < 0)
-		return err;
-
-	err = setexposure(sd);
-	if (err < 0)
-		return err;
-
-	err = setgain(sd);
-	if (err < 0)
-		return err;
-
 	/* commit settings */
 	err = stv06xx_write_bridge(sd, 0x143f, 0x01);
 	return (err < 0) ? err : 0;
@@ -345,59 +283,3 @@
 
 	return 0;
 }
-
-static void st6422_set_brightness(struct gspca_dev *gspca_dev)
-{
-	int err;
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	err = setbrightness(sd);
-
-	/* commit settings */
-	if (err >= 0)
-		err = stv06xx_write_bridge(sd, 0x143f, 0x01);
-
-	gspca_dev->usb_err = err;
-}
-
-static void st6422_set_contrast(struct gspca_dev *gspca_dev)
-{
-	int err;
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	err = setcontrast(sd);
-
-	/* commit settings */
-	if (err >= 0)
-		err = stv06xx_write_bridge(sd, 0x143f, 0x01);
-
-	gspca_dev->usb_err = err;
-}
-
-static void st6422_set_gain(struct gspca_dev *gspca_dev)
-{
-	int err;
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	err = setgain(sd);
-
-	/* commit settings */
-	if (err >= 0)
-		err = stv06xx_write_bridge(sd, 0x143f, 0x01);
-
-	gspca_dev->usb_err = err;
-}
-
-static void st6422_set_exposure(struct gspca_dev *gspca_dev)
-{
-	int err;
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	err = setexposure(sd);
-
-	/* commit settings */
-	if (err >= 0)
-		err = stv06xx_write_bridge(sd, 0x143f, 0x01);
-
-	gspca_dev->usb_err = err;
-}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
index d7498e0..8f20fbf 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
@@ -34,8 +34,8 @@
 static int st6422_probe(struct sd *sd);
 static int st6422_start(struct sd *sd);
 static int st6422_init(struct sd *sd);
+static int st6422_init_controls(struct sd *sd);
 static int st6422_stop(struct sd *sd);
-static void st6422_disconnect(struct sd *sd);
 
 const struct stv06xx_sensor stv06xx_sensor_st6422 = {
 	.name = "ST6422",
@@ -43,10 +43,10 @@
 	.min_packet_size = { 300, 847 },
 	.max_packet_size = { 300, 847 },
 	.init = st6422_init,
+	.init_controls = st6422_init_controls,
 	.probe = st6422_probe,
 	.start = st6422_start,
 	.stop = st6422_stop,
-	.disconnect = st6422_disconnect,
 };
 
 #endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
index a5c69d9..748e142 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
@@ -44,130 +44,83 @@
 	}
 };
 
-static const struct ctrl vv6410_ctrl[] = {
-#define HFLIP_IDX 0
-	{
-		{
-			.id		= V4L2_CID_HFLIP,
-			.type		= V4L2_CTRL_TYPE_BOOLEAN,
-			.name		= "horizontal flip",
-			.minimum	= 0,
-			.maximum	= 1,
-			.step		= 1,
-			.default_value	= 0
-		},
-		.set = vv6410_set_hflip,
-		.get = vv6410_get_hflip
-	},
-#define VFLIP_IDX 1
-	{
-		{
-			.id		= V4L2_CID_VFLIP,
-			.type		= V4L2_CTRL_TYPE_BOOLEAN,
-			.name		= "vertical flip",
-			.minimum	= 0,
-			.maximum	= 1,
-			.step		= 1,
-			.default_value	= 0
-		},
-		.set = vv6410_set_vflip,
-		.get = vv6410_get_vflip
-	},
-#define GAIN_IDX 2
-	{
-		{
-			.id		= V4L2_CID_GAIN,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "analog gain",
-			.minimum	= 0,
-			.maximum	= 15,
-			.step		= 1,
-			.default_value  = 10
-		},
-		.set = vv6410_set_analog_gain,
-		.get = vv6410_get_analog_gain
-	},
-#define EXPOSURE_IDX 3
-	{
-		{
-			.id		= V4L2_CID_EXPOSURE,
-			.type		= V4L2_CTRL_TYPE_INTEGER,
-			.name		= "exposure",
-			.minimum	= 0,
-			.maximum	= 32768,
-			.step		= 1,
-			.default_value  = 20000
-		},
-		.set = vv6410_set_exposure,
-		.get = vv6410_get_exposure
+static int vv6410_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	int err = -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		err = vv6410_set_hflip(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_VFLIP:
+		err = vv6410_set_vflip(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_GAIN:
+		err = vv6410_set_analog_gain(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_EXPOSURE:
+		err = vv6410_set_exposure(gspca_dev, ctrl->val);
+		break;
 	}
-	};
+	return err;
+}
+
+static const struct v4l2_ctrl_ops vv6410_ctrl_ops = {
+	.s_ctrl = vv6410_s_ctrl,
+};
 
 static int vv6410_probe(struct sd *sd)
 {
 	u16 data;
-	int err, i;
-	s32 *sensor_settings;
+	int err;
 
 	err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
 	if (err < 0)
 		return -ENODEV;
 
-	if (data == 0x19) {
-		pr_info("vv6410 sensor detected\n");
+	if (data != 0x19)
+		return -ENODEV;
 
-		sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32),
-					  GFP_KERNEL);
-		if (!sensor_settings)
-			return -ENOMEM;
+	pr_info("vv6410 sensor detected\n");
 
-		sd->gspca_dev.cam.cam_mode = vv6410_mode;
-		sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode);
-		sd->desc.ctrls = vv6410_ctrl;
-		sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl);
+	sd->gspca_dev.cam.cam_mode = vv6410_mode;
+	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode);
+	return 0;
+}
 
-		for (i = 0; i < sd->desc.nctrls; i++)
-			sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value;
-		sd->sensor_priv = sensor_settings;
-		return 0;
-	}
-	return -ENODEV;
+static int vv6410_init_controls(struct sd *sd)
+{
+	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
+			V4L2_CID_EXPOSURE, 0, 32768, 1, 20000);
+	v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
+			V4L2_CID_GAIN, 0, 15, 1, 10);
+	return hdl->error;
 }
 
 static int vv6410_init(struct sd *sd)
 {
 	int err = 0, i;
-	s32 *sensor_settings = sd->sensor_priv;
 
-	for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
+	for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++)
 		stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data);
-	}
 
 	if (err < 0)
 		return err;
 
 	err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
 					 ARRAY_SIZE(vv6410_sensor_init));
-	if (err < 0)
-		return err;
-
-	err = vv6410_set_exposure(&sd->gspca_dev,
-				   sensor_settings[EXPOSURE_IDX]);
-	if (err < 0)
-		return err;
-
-	err = vv6410_set_analog_gain(&sd->gspca_dev,
-				      sensor_settings[GAIN_IDX]);
-
 	return (err < 0) ? err : 0;
 }
 
-static void vv6410_disconnect(struct sd *sd)
-{
-	sd->sensor = NULL;
-	kfree(sd->sensor_priv);
-}
-
 static int vv6410_start(struct sd *sd)
 {
 	int err;
@@ -233,25 +186,12 @@
 	return (err < 0) ? err : 0;
 }
 
-static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[HFLIP_IDX];
-	PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
-	return 0;
-}
-
 static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
 	int err;
 	u16 i2c_data;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
 
-	sensor_settings[HFLIP_IDX] = val;
 	err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
 	if (err < 0)
 		return err;
@@ -267,25 +207,12 @@
 	return (err < 0) ? err : 0;
 }
 
-static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[VFLIP_IDX];
-	PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
-	return 0;
-}
-
 static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
 	int err;
 	u16 i2c_data;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
 
-	sensor_settings[VFLIP_IDX] = val;
 	err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
 	if (err < 0)
 		return err;
@@ -301,52 +228,23 @@
 	return (err < 0) ? err : 0;
 }
 
-static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[GAIN_IDX];
-
-	PDEBUG(D_V4L2, "Read analog gain %d", *val);
-
-	return 0;
-}
-
 static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	int err;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
 
-	sensor_settings[GAIN_IDX] = val;
 	PDEBUG(D_V4L2, "Set analog gain to %d", val);
 	err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
 
 	return (err < 0) ? err : 0;
 }
 
-static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
-
-	*val = sensor_settings[EXPOSURE_IDX];
-
-	PDEBUG(D_V4L2, "Read exposure %d", *val);
-
-	return 0;
-}
-
 static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
 	int err;
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 *sensor_settings = sd->sensor_priv;
 	unsigned int fine, coarse;
 
-	sensor_settings[EXPOSURE_IDX] = val;
-
 	val = (val * val >> 14) + val / 4;
 
 	fine = val % VV6410_CIF_LINELENGTH;
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
index a25b887..53e67b4 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -178,18 +178,14 @@
 static int vv6410_probe(struct sd *sd);
 static int vv6410_start(struct sd *sd);
 static int vv6410_init(struct sd *sd);
+static int vv6410_init_controls(struct sd *sd);
 static int vv6410_stop(struct sd *sd);
 static int vv6410_dump(struct sd *sd);
-static void vv6410_disconnect(struct sd *sd);
 
 /* V4L2 controls supported by the driver */
-static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val);
 static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
 static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
 
 const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
@@ -202,11 +198,11 @@
 	.min_packet_size = { 1023 },
 	.max_packet_size = { 1023 },
 	.init = vv6410_init,
+	.init_controls = vv6410_init_controls,
 	.probe = vv6410_probe,
 	.start = vv6410_start,
 	.stop = vv6410_stop,
 	.dump = vv6410_dump,
-	.disconnect = vv6410_disconnect,
 };
 
 /* If NULL, only single value to write, stored in len */
diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c
index 444d3c5..c6326d1 100644
--- a/drivers/media/video/gspca/topro.c
+++ b/drivers/media/video/gspca/topro.c
@@ -4675,11 +4675,9 @@
 /* -- do autogain -- */
 /* gain setting is done in setexposure() for tp6810 */
 static void setgain(struct gspca_dev *gspca_dev) {}
-/* !! coarse_grained_expo_autogain is not used !! */
-#define exp_too_low_cnt bridge
-#define exp_too_high_cnt sensor
-
+#define WANT_REGULAR_AUTOGAIN
 #include "autogain_functions.h"
+
 static void sd_dq_callback(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c
index 911152e..15a30f7 100644
--- a/drivers/media/video/gspca/vicam.c
+++ b/drivers/media/video/gspca/vicam.c
@@ -37,9 +37,12 @@
 #include <linux/ihex.h>
 #include "gspca.h"
 
+#define VICAM_FIRMWARE "vicam/firmware.fw"
+
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(VICAM_FIRMWARE);
 
 enum e_ctrl {
 	GAIN,
@@ -222,7 +225,11 @@
 		goto exit;
 	}
 
-	while (gspca_dev->present && gspca_dev->streaming) {
+	while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			break;
+#endif
 		ret = vicam_read_frame(gspca_dev, buffer, frame_sz);
 		if (ret < 0)
 			break;
@@ -268,7 +275,7 @@
 	const struct firmware *uninitialized_var(fw);
 	u8 *firmware_buf;
 
-	ret = request_ihex_firmware(&fw, "vicam/firmware.fw",
+	ret = request_ihex_firmware(&fw, VICAM_FIRMWARE,
 				    &gspca_dev->dev->dev);
 	if (ret) {
 		pr_err("Failed to load \"vicam/firmware.fw\": %d\n", ret);
@@ -324,7 +331,7 @@
 	dev->work_thread = NULL;
 	mutex_lock(&gspca_dev->usb_lock);
 
-	if (gspca_dev->present)
+	if (gspca_dev->dev)
 		vicam_set_camera_power(gspca_dev, 0);
 }
 
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 7d9a4f1..f0bacee 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -32,29 +32,25 @@
 
 static int force_sensor = -1;
 
-#define REG08_DEF 3		/* default JPEG compression (70%) */
+#define REG08_DEF 3		/* default JPEG compression (75%) */
 #include "zc3xx-reg.h"
 
-/* controls */
-enum e_ctrl {
-	BRIGHTNESS,
-	CONTRAST,
-	EXPOSURE,
-	GAMMA,
-	AUTOGAIN,
-	LIGHTFREQ,
-	SHARPNESS,
-	QUALITY,
-	NCTRLS		/* number of controls */
-};
-
-#define AUTOGAIN_DEF 1
-
 /* specific webcam descriptor */
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
 
-	struct gspca_ctrl ctrls[NCTRLS];
+	struct { /* gamma/brightness/contrast control cluster */
+		struct v4l2_ctrl *gamma;
+		struct v4l2_ctrl *brightness;
+		struct v4l2_ctrl *contrast;
+	};
+	struct { /* autogain/exposure control cluster */
+		struct v4l2_ctrl *autogain;
+		struct v4l2_ctrl *exposure;
+	};
+	struct v4l2_ctrl *plfreq;
+	struct v4l2_ctrl *sharpness;
+	struct v4l2_ctrl *jpegqual;
 
 	struct work_struct work;
 	struct workqueue_struct *work_thread;
@@ -94,114 +90,6 @@
 	SENSOR_MAX
 };
 
-/* V4L2 controls supported by the driver */
-static void setcontrast(struct gspca_dev *gspca_dev);
-static void setexposure(struct gspca_dev *gspca_dev);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static void setlightfreq(struct gspca_dev *gspca_dev);
-static void setsharpness(struct gspca_dev *gspca_dev);
-static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val);
-
-static const struct ctrl sd_ctrls[NCTRLS] = {
-[BRIGHTNESS] = {
-	    {
-		.id      = V4L2_CID_BRIGHTNESS,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Brightness",
-		.minimum = 0,
-		.maximum = 255,
-		.step    = 1,
-		.default_value = 128,
-	    },
-	    .set_control = setcontrast
-	},
-[CONTRAST] = {
-	    {
-		.id      = V4L2_CID_CONTRAST,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Contrast",
-		.minimum = 0,
-		.maximum = 255,
-		.step    = 1,
-		.default_value = 128,
-	    },
-	    .set_control = setcontrast
-	},
-[EXPOSURE] = {
-	    {
-		.id      = V4L2_CID_EXPOSURE,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Exposure",
-		.minimum = 0x30d,
-		.maximum	= 0x493e,
-		.step		= 1,
-		.default_value  = 0x927
-	    },
-	    .set_control = setexposure
-	},
-[GAMMA] = {
-	    {
-		.id      = V4L2_CID_GAMMA,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Gamma",
-		.minimum = 1,
-		.maximum = 6,
-		.step    = 1,
-		.default_value = 4,
-	    },
-	    .set_control = setcontrast
-	},
-[AUTOGAIN] = {
-	    {
-		.id      = V4L2_CID_AUTOGAIN,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Auto Gain",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-		.default_value = AUTOGAIN_DEF,
-		.flags   = V4L2_CTRL_FLAG_UPDATE
-	    },
-	    .set = sd_setautogain
-	},
-[LIGHTFREQ] = {
-	    {
-		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
-		.type    = V4L2_CTRL_TYPE_MENU,
-		.name    = "Light frequency filter",
-		.minimum = 0,
-		.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
-		.step    = 1,
-		.default_value = 0,
-	    },
-	    .set_control = setlightfreq
-	},
-[SHARPNESS] = {
-	    {
-		.id	 = V4L2_CID_SHARPNESS,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Sharpness",
-		.minimum = 0,
-		.maximum = 3,
-		.step    = 1,
-		.default_value = 2,
-	    },
-	    .set_control = setsharpness
-	},
-[QUALITY] = {
-	    {
-		.id	 = V4L2_CID_JPEG_COMPRESSION_QUALITY,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Compression Quality",
-		.minimum = 40,
-		.maximum = 70,
-		.step    = 1,
-		.default_value = 70	/* updated in sd_init() */
-	    },
-	    .set = sd_setquality
-	},
-};
-
 static const struct v4l2_pix_format vga_mode[] = {
 	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 320,
@@ -241,8 +129,11 @@
 		.priv = 0},
 };
 
-/* bridge reg08 -> JPEG quality conversion table */
-static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/};
+/*
+ * Bridge reg08 bits 1-2 -> JPEG quality conversion table. Note the highest
+ * quality setting is not usable as USB 1 does not have enough bandwidth.
+ */
+static u8 jpeg_qual[] = {50, 75, 87, /* 94 */};
 
 /* usb exchanges */
 struct usb_action {
@@ -5818,10 +5709,8 @@
 		reg_w(gspca_dev, matrix[i], 0x010a + i);
 }
 
-static void setsharpness(struct gspca_dev *gspca_dev)
+static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-	int sharpness;
 	static const u8 sharpness_tb[][2] = {
 		{0x02, 0x03},
 		{0x04, 0x07},
@@ -5829,19 +5718,18 @@
 		{0x10, 0x1e}
 	};
 
-	sharpness = sd->ctrls[SHARPNESS].val;
-	reg_w(gspca_dev, sharpness_tb[sharpness][0], 0x01c6);
+	reg_w(gspca_dev, sharpness_tb[val][0], 0x01c6);
 	reg_r(gspca_dev, 0x01c8);
 	reg_r(gspca_dev, 0x01c9);
 	reg_r(gspca_dev, 0x01ca);
-	reg_w(gspca_dev, sharpness_tb[sharpness][1], 0x01cb);
+	reg_w(gspca_dev, sharpness_tb[val][1], 0x01cb);
 }
 
-static void setcontrast(struct gspca_dev *gspca_dev)
+static void setcontrast(struct gspca_dev *gspca_dev,
+		s32 gamma, s32 brightness, s32 contrast)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
 	const u8 *Tgamma;
-	int g, i, brightness, contrast, adj, gp1, gp2;
+	int g, i, adj, gp1, gp2;
 	u8 gr[16];
 	static const u8 delta_b[16] =		/* delta for brightness */
 		{0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d,
@@ -5864,10 +5752,10 @@
 		 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff},
 	};
 
-	Tgamma = gamma_tb[sd->ctrls[GAMMA].val - 1];
+	Tgamma = gamma_tb[gamma - 1];
 
-	contrast = ((int) sd->ctrls[CONTRAST].val - 128); /* -128 / 127 */
-	brightness = ((int) sd->ctrls[BRIGHTNESS].val - 128); /* -128 / 92 */
+	contrast -= 128; /* -128 / 127 */
+	brightness -= 128; /* -128 / 92 */
 	adj = 0;
 	gp1 = gp2 = 0;
 	for (i = 0; i < 16; i++) {
@@ -5894,25 +5782,15 @@
 		reg_w(gspca_dev, gr[i], 0x0130 + i);	/* gradient */
 }
 
-static void getexposure(struct gspca_dev *gspca_dev)
+static s32 getexposure(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	if (sd->sensor != SENSOR_HV7131R)
-		return;
-	sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9)
+	return (i2c_read(gspca_dev, 0x25) << 9)
 		| (i2c_read(gspca_dev, 0x26) << 1)
 		| (i2c_read(gspca_dev, 0x27) >> 7);
 }
 
-static void setexposure(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-	int val;
-
-	if (sd->sensor != SENSOR_HV7131R)
-		return;
-	val = sd->ctrls[EXPOSURE].val;
 	i2c_write(gspca_dev, 0x25, val >> 9, 0x00);
 	i2c_write(gspca_dev, 0x26, val >> 1, 0x00);
 	i2c_write(gspca_dev, 0x27, val << 7, 0x00);
@@ -5921,20 +5799,8 @@
 static void setquality(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	s8 reg07;
-
-	reg07 = 0;
-	switch (sd->sensor) {
-	case SENSOR_OV7620:
-		reg07 = 0x30;
-		break;
-	case SENSOR_HV7131R:
-	case SENSOR_PAS202B:
-		return;			/* done by work queue */
-	}
+	jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08 >> 1]);
 	reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
-	if (reg07 != 0)
-		reg_w(gspca_dev, reg07, 0x0007);
 }
 
 /* Matches the sensor's internal frame rate to the lighting frequency.
@@ -5943,7 +5809,7 @@
  *	60Hz, for American lighting
  *	0 = No Fliker (for outdoore usage)
  */
-static void setlightfreq(struct gspca_dev *gspca_dev)
+static void setlightfreq(struct gspca_dev *gspca_dev, s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int i, mode;
@@ -6027,7 +5893,7 @@
 		 tas5130c_60HZ, tas5130c_60HZScale},
 	};
 
-	i = sd->ctrls[LIGHTFREQ].val * 2;
+	i = val * 2;
 	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
 	if (mode)
 		i++;			/* 320x240 */
@@ -6037,14 +5903,14 @@
 	usb_exchange(gspca_dev, zc3_freq);
 	switch (sd->sensor) {
 	case SENSOR_GC0305:
-		if (mode				/* if 320x240 */
-		    && sd->ctrls[LIGHTFREQ].val == 1)	/* and 50Hz */
+		if (mode		/* if 320x240 */
+		    && val == 1)	/* and 50Hz */
 			reg_w(gspca_dev, 0x85, 0x018d);
 					/* win: 0x80, 0x018d */
 		break;
 	case SENSOR_OV7620:
-		if (!mode) {				/* if 640x480 */
-			if (sd->ctrls[LIGHTFREQ].val != 0) /* and filter */
+		if (!mode) {		/* if 640x480 */
+			if (val != 0)	/* and filter */
 				reg_w(gspca_dev, 0x40, 0x0002);
 			else
 				reg_w(gspca_dev, 0x44, 0x0002);
@@ -6056,22 +5922,15 @@
 	}
 }
 
-static void setautogain(struct gspca_dev *gspca_dev)
+static void setautogain(struct gspca_dev *gspca_dev, s32 val)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-	u8 autoval;
-
-	if (sd->ctrls[AUTOGAIN].val)
-		autoval = 0x42;
-	else
-		autoval = 0x02;
-	reg_w(gspca_dev, autoval, 0x0180);
+	reg_w(gspca_dev, val ? 0x42 : 0x02, 0x0180);
 }
 
-/* update the transfer parameters */
-/* This function is executed from a work queue. */
-/* The exact use of the bridge registers 07 and 08 is not known.
- * The following algorithm has been adapted from ms-win traces */
+/*
+ * Update the transfer parameters.
+ * This function is executed from a work queue.
+ */
 static void transfer_update(struct work_struct *work)
 {
 	struct sd *sd = container_of(work, struct sd, work);
@@ -6079,96 +5938,55 @@
 	int change, good;
 	u8 reg07, reg11;
 
-	/* synchronize with the main driver and initialize the registers */
-	mutex_lock(&gspca_dev->usb_lock);
-	reg07 = 0;					/* max */
-	reg_w(gspca_dev, reg07, 0x0007);
-	reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
-	mutex_unlock(&gspca_dev->usb_lock);
+	/* reg07 gets set to 0 by sd_start before starting us */
+	reg07 = 0;
 
 	good = 0;
 	for (;;) {
 		msleep(100);
 
-		/* get the transfer status */
-		/* the bit 0 of the bridge register 11 indicates overflow */
 		mutex_lock(&gspca_dev->usb_lock);
-		if (!gspca_dev->present || !gspca_dev->streaming)
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
 			goto err;
+#endif
+		if (!gspca_dev->dev || !gspca_dev->streaming)
+			goto err;
+
+		/* Bit 0 of register 11 indicates FIFO overflow */
+		gspca_dev->usb_err = 0;
 		reg11 = reg_r(gspca_dev, 0x0011);
-		if (gspca_dev->usb_err < 0
-		 || !gspca_dev->present || !gspca_dev->streaming)
+		if (gspca_dev->usb_err)
 			goto err;
 
 		change = reg11 & 0x01;
 		if (change) {				/* overflow */
-			switch (reg07) {
-			case 0:				/* max */
-				reg07 = sd->sensor == SENSOR_HV7131R
-						? 0x30 : 0x32;
-				if (sd->reg08 != 0) {
-					change = 3;
-					sd->reg08--;
-				}
-				break;
-			case 0x32:
-				reg07 -= 4;
-				break;
-			default:
-				reg07 -= 2;
-				break;
-			case 2:
-				change = 0;		/* already min */
-				break;
-			}
 			good = 0;
+
+			if (reg07 == 0) /* Bit Rate Control not enabled? */
+				reg07 = 0x32; /* Allow 98 bytes / unit */
+			else if (reg07 > 2)
+				reg07 -= 2; /* Decrease allowed bytes / unit */
+			else
+				change = 0;
 		} else {				/* no overflow */
-			if (reg07 != 0) {		/* if not max */
-				good++;
-				if (good >= 10) {
-					good = 0;
+			good++;
+			if (good >= 10) {
+				good = 0;
+				if (reg07) { /* BRC enabled? */
 					change = 1;
-					reg07 += 2;
-					switch (reg07) {
-					case 0x30:
-						if (sd->sensor == SENSOR_PAS202B)
-							reg07 += 2;
-						break;
-					case 0x32:
-					case 0x34:
+					if (reg07 < 0x32)
+						reg07 += 2;
+					else
 						reg07 = 0;
-						break;
-					}
-				}
-			} else {			/* reg07 max */
-				if (sd->reg08 < sizeof jpeg_qual - 1) {
-					good++;
-					if (good > 10) {
-						sd->reg08++;
-						change = 2;
-					}
 				}
 			}
 		}
 		if (change) {
-			if (change & 1) {
-				reg_w(gspca_dev, reg07, 0x0007);
-				if (gspca_dev->usb_err < 0
-				 || !gspca_dev->present
-				 || !gspca_dev->streaming)
-					goto err;
-			}
-			if (change & 2) {
-				reg_w(gspca_dev, sd->reg08,
-						ZC3XX_R008_CLOCKSETTING);
-				if (gspca_dev->usb_err < 0
-				 || !gspca_dev->present
-				 || !gspca_dev->streaming)
-					goto err;
-				sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08];
-				jpeg_set_qual(sd->jpeg_hdr,
-						jpeg_qual[sd->reg08]);
-			}
+			gspca_dev->usb_err = 0;
+			reg_w(gspca_dev, reg07, 0x0007);
+			if (gspca_dev->usb_err)
+				goto err;
 		}
 		mutex_unlock(&gspca_dev->usb_lock);
 	}
@@ -6503,7 +6321,6 @@
 	/* define some sensors from the vendor/product */
 	sd->sensor = id->driver_info;
 
-	gspca_dev->cam.ctrls = sd->ctrls;
 	sd->reg08 = REG08_DEF;
 
 	INIT_WORK(&sd->work, transfer_update);
@@ -6511,12 +6328,87 @@
 	return 0;
 }
 
-/* this function is called at probe and resume time */
-static int sd_init(struct gspca_dev *gspca_dev)
+static int zcxx_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-	struct cam *cam;
-	int sensor;
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+		gspca_dev->usb_err = 0;
+		if (ctrl->val && sd->exposure && gspca_dev->streaming)
+			sd->exposure->val = getexposure(gspca_dev);
+		return gspca_dev->usb_err;
+	}
+	return -EINVAL;
+}
+
+static int zcxx_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+	int i, qual;
+
+	gspca_dev->usb_err = 0;
+
+	if (ctrl->id == V4L2_CID_JPEG_COMPRESSION_QUALITY) {
+		qual = sd->reg08 >> 1;
+
+		for (i = 0; i < ARRAY_SIZE(jpeg_qual); i++) {
+			if (ctrl->val <= jpeg_qual[i])
+				break;
+		}
+		if (i > 0 && i == qual && ctrl->val < jpeg_qual[i])
+			i--;
+
+		/* With high quality settings we need max bandwidth */
+		if (i >= 2 && gspca_dev->streaming &&
+		    !gspca_dev->cam.needs_full_bandwidth)
+			return -EBUSY;
+
+		sd->reg08 = (i << 1) | 1;
+		ctrl->val = jpeg_qual[i];
+	}
+
+	if (!gspca_dev->streaming)
+		return 0;
+
+	switch (ctrl->id) {
+	/* gamma/brightness/contrast cluster */
+	case V4L2_CID_GAMMA:
+		setcontrast(gspca_dev, sd->gamma->val,
+				sd->brightness->val, sd->contrast->val);
+		break;
+	/* autogain/exposure cluster */
+	case V4L2_CID_AUTOGAIN:
+		setautogain(gspca_dev, ctrl->val);
+		if (!gspca_dev->usb_err && !ctrl->val && sd->exposure)
+			setexposure(gspca_dev, sd->exposure->val);
+		break;
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		setlightfreq(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_SHARPNESS:
+		setsharpness(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+		setquality(gspca_dev);
+		break;
+	}
+	return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops zcxx_ctrl_ops = {
+	.g_volatile_ctrl = zcxx_g_volatile_ctrl,
+	.s_ctrl = zcxx_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *)gspca_dev;
+	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
 	static const u8 gamma[SENSOR_MAX] = {
 		[SENSOR_ADCM2700] =	4,
 		[SENSOR_CS2102] =	4,
@@ -6538,6 +6430,48 @@
 		[SENSOR_PO2030] =	4,
 		[SENSOR_TAS5130C] =	3,
 	};
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 8);
+	sd->brightness = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	sd->contrast = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 128);
+	sd->gamma = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+			V4L2_CID_GAMMA, 1, 6, 1, gamma[sd->sensor]);
+	if (sd->sensor == SENSOR_HV7131R)
+		sd->exposure = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+			V4L2_CID_EXPOSURE, 0x30d, 0x493e, 1, 0x927);
+	sd->autogain = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	if (sd->sensor != SENSOR_OV7630C)
+		sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &zcxx_ctrl_ops,
+			V4L2_CID_POWER_LINE_FREQUENCY,
+			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
+			V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
+	sd->sharpness = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+			V4L2_CID_SHARPNESS, 0, 3, 1,
+			sd->sensor == SENSOR_PO2030 ? 0 : 2);
+	sd->jpegqual = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+			V4L2_CID_JPEG_COMPRESSION_QUALITY,
+			jpeg_qual[0], jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1], 1,
+			jpeg_qual[REG08_DEF >> 1]);
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+	v4l2_ctrl_cluster(3, &sd->gamma);
+	if (sd->sensor == SENSOR_HV7131R)
+		v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true);
+	return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	int sensor;
 	static const u8 mode_tb[SENSOR_MAX] = {
 		[SENSOR_ADCM2700] =	2,
 		[SENSOR_CS2102] =	1,
@@ -6559,27 +6493,6 @@
 		[SENSOR_PO2030] =	1,
 		[SENSOR_TAS5130C] =	1,
 	};
-	static const u8 reg08_tb[SENSOR_MAX] = {
-		[SENSOR_ADCM2700] =	1,
-		[SENSOR_CS2102] =	3,
-		[SENSOR_CS2102K] =	3,
-		[SENSOR_GC0303] =	2,
-		[SENSOR_GC0305] =	3,
-		[SENSOR_HDCS2020] =	1,
-		[SENSOR_HV7131B] =	3,
-		[SENSOR_HV7131R] =	3,
-		[SENSOR_ICM105A] =	3,
-		[SENSOR_MC501CB] =	3,
-		[SENSOR_MT9V111_1] =	3,
-		[SENSOR_MT9V111_3] =	3,
-		[SENSOR_OV7620] =	1,
-		[SENSOR_OV7630C] =	3,
-		[SENSOR_PAS106] =	3,
-		[SENSOR_PAS202B] =	3,
-		[SENSOR_PB0330] =	3,
-		[SENSOR_PO2030] =	2,
-		[SENSOR_TAS5130C] =	3,
-	};
 
 	sensor = zcxx_probeSensor(gspca_dev);
 	if (sensor >= 0)
@@ -6688,7 +6601,6 @@
 		case 0x2030:
 			PDEBUG(D_PROBE, "Find Sensor PO2030");
 			sd->sensor = SENSOR_PO2030;
-			sd->ctrls[SHARPNESS].def = 0;	/* from win traces */
 			break;
 		case 0x7620:
 			PDEBUG(D_PROBE, "Find Sensor OV7620");
@@ -6730,36 +6642,18 @@
 		break;
 	}
 
-	sd->ctrls[GAMMA].def = gamma[sd->sensor];
-	sd->reg08 = reg08_tb[sd->sensor];
-	sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08];
-	sd->ctrls[QUALITY].min = jpeg_qual[0];
-	sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1];
-
-	switch (sd->sensor) {
-	case SENSOR_HV7131R:
-		gspca_dev->ctrl_dis = (1 << QUALITY);
-		break;
-	case SENSOR_OV7630C:
-		gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
-		break;
-	case SENSOR_PAS202B:
-		gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE);
-		break;
-	default:
-		gspca_dev->ctrl_dis = (1 << EXPOSURE);
-		break;
-	}
-#if AUTOGAIN_DEF
-	if (sd->ctrls[AUTOGAIN].val)
-		gspca_dev->ctrl_inac = (1 << EXPOSURE);
-#endif
-
 	/* switch off the led */
 	reg_w(gspca_dev, 0x01, 0x0000);
 	return gspca_dev->usb_err;
 }
 
+static int sd_pre_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	gspca_dev->cam.needs_full_bandwidth = (sd->reg08 >= 4) ? 1 : 0;
+	return 0;
+}
+
 static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -6864,7 +6758,7 @@
 		reg_w(gspca_dev, 0x03, 0x0008);
 		break;
 	}
-	setsharpness(gspca_dev);
+	setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness));
 
 	/* set the gamma tables when not set */
 	switch (sd->sensor) {
@@ -6873,7 +6767,9 @@
 	case SENSOR_OV7630C:
 		break;
 	default:
-		setcontrast(gspca_dev);
+		setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma),
+				v4l2_ctrl_g_ctrl(sd->brightness),
+				v4l2_ctrl_g_ctrl(sd->contrast));
 		break;
 	}
 	setmatrix(gspca_dev);			/* one more time? */
@@ -6885,8 +6781,10 @@
 		break;
 	}
 	setquality(gspca_dev);
-	jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]);
-	setlightfreq(gspca_dev);
+	/* Start with BRC disabled, transfer_update will enable it if needed */
+	reg_w(gspca_dev, 0x00, 0x0007);
+	if (sd->plfreq)
+		setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq));
 
 	switch (sd->sensor) {
 	case SENSOR_ADCM2700:
@@ -6897,7 +6795,7 @@
 		reg_w(gspca_dev, 0x40, 0x0117);
 		break;
 	case SENSOR_HV7131R:
-		setexposure(gspca_dev);
+		setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
 		reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
 		break;
 	case SENSOR_GC0305:
@@ -6921,21 +6819,16 @@
 		break;
 	}
 
-	setautogain(gspca_dev);
+	setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));
 
-	/* start the transfer update thread if needed */
-	if (gspca_dev->usb_err >= 0) {
-		switch (sd->sensor) {
-		case SENSOR_HV7131R:
-		case SENSOR_PAS202B:
-			sd->work_thread =
-				create_singlethread_workqueue(KBUILD_MODNAME);
-			queue_work(sd->work_thread, &sd->work);
-			break;
-		}
-	}
+	if (gspca_dev->usb_err < 0)
+		return gspca_dev->usb_err;
 
-	return gspca_dev->usb_err;
+	/* Start the transfer parameters update thread */
+	sd->work_thread = create_singlethread_workqueue(KBUILD_MODNAME);
+	queue_work(sd->work_thread, &sd->work);
+
+	return 0;
 }
 
 /* called on streamoff with alt 0 and on disconnect */
@@ -6949,7 +6842,7 @@
 		mutex_lock(&gspca_dev->usb_lock);
 		sd->work_thread = NULL;
 	}
-	if (!gspca_dev->present)
+	if (!gspca_dev->dev)
 		return;
 	send_unknown(gspca_dev, sd->sensor);
 }
@@ -6987,72 +6880,17 @@
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->ctrls[AUTOGAIN].val = val;
-	if (val) {
-		gspca_dev->ctrl_inac |= (1 << EXPOSURE);
-	} else {
-		gspca_dev->ctrl_inac &= ~(1 << EXPOSURE);
-		if (gspca_dev->streaming)
-			getexposure(gspca_dev);
-	}
-	if (gspca_dev->streaming)
-		setautogain(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_querymenu(struct gspca_dev *gspca_dev,
-			struct v4l2_querymenu *menu)
-{
-	switch (menu->id) {
-	case V4L2_CID_POWER_LINE_FREQUENCY:
-		switch (menu->index) {
-		case 0:		/* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
-			strcpy((char *) menu->name, "NoFliker");
-			return 0;
-		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
-			strcpy((char *) menu->name, "50 Hz");
-			return 0;
-		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
-			strcpy((char *) menu->name, "60 Hz");
-			return 0;
-		}
-		break;
-	}
-	return -EINVAL;
-}
-
-static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) {
-		if (val <= jpeg_qual[i])
-			break;
-	}
-	if (i > 0
-	 && i == sd->reg08
-	 && val < jpeg_qual[sd->reg08])
-		i--;
-	sd->reg08 = i;
-	sd->ctrls[QUALITY].val = jpeg_qual[i];
-	if (gspca_dev->streaming)
-		jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
-	return gspca_dev->usb_err;
-}
-
 static int sd_set_jcomp(struct gspca_dev *gspca_dev,
 			struct v4l2_jpegcompression *jcomp)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
 
-	sd_setquality(gspca_dev, jcomp->quality);
-	jcomp->quality = sd->ctrls[QUALITY].val;
-	return gspca_dev->usb_err;
+	ret = v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
+	if (ret)
+		return ret;
+	jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
+	return 0;
 }
 
 static int sd_get_jcomp(struct gspca_dev *gspca_dev,
@@ -7061,7 +6899,7 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	memset(jcomp, 0, sizeof *jcomp);
-	jcomp->quality = sd->ctrls[QUALITY].val;
+	jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
 	jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
 			| V4L2_JPEG_MARKER_DQT;
 	return 0;
@@ -7085,14 +6923,13 @@
 
 static const struct sd_desc sd_desc = {
 	.name = KBUILD_MODNAME,
-	.ctrls = sd_ctrls,
-	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
 	.init = sd_init,
+	.init_controls = sd_init_controls,
+	.isoc_init = sd_pre_start,
 	.start = sd_start,
 	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
-	.querymenu = sd_querymenu,
 	.get_jcomp = sd_get_jcomp,
 	.set_jcomp = sd_set_jcomp,
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
@@ -7176,6 +7013,7 @@
 #ifdef CONFIG_PM
 	.suspend = gspca_suspend,
 	.resume = gspca_resume,
+	.reset_resume = gspca_resume,
 #endif
 };
 
diff --git a/drivers/media/video/hdpvr/hdpvr-control.c b/drivers/media/video/hdpvr/hdpvr-control.c
index 068df4b..ae8f229 100644
--- a/drivers/media/video/hdpvr/hdpvr-control.c
+++ b/drivers/media/video/hdpvr/hdpvr-control.c
@@ -113,6 +113,8 @@
 			 "get input lines info returned: %d, %s\n", ret,
 			 print_buf);
 	}
+#else
+	(void)ret;	/* suppress compiler warning */
 #endif
 	lines = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
 	mutex_unlock(&dev->usbc_mutex);
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 6510110..304f43e 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -303,7 +303,7 @@
 	/* allocate memory for our device state and initialize it */
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev) {
-		err("Out of memory");
+		dev_err(&interface->dev, "Out of memory\n");
 		goto error;
 	}
 
@@ -311,7 +311,7 @@
 
 	/* register v4l2_device early so it can be used for printks */
 	if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
-		err("v4l2_device_register failed");
+		dev_err(&interface->dev, "v4l2_device_register failed\n");
 		goto error;
 	}
 
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index 11ffe9c..0e9e156 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -994,7 +994,7 @@
 	default:
 		return -EINVAL;
 	}
-	return 0;
+	return ret;
 }
 
 static int vidioc_try_ext_ctrls(struct file *file, void *priv,
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index a62322d..366434f 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -40,15 +40,15 @@
 
 #define HEXIUM_INPUTS	9
 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
-	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
 };
 
 #define HEXIUM_AUDIOS	0
@@ -59,11 +59,6 @@
 	u8 byte;
 };
 
-#define HEXIUM_CONTROLS	1
-static struct v4l2_queryctrl hexium_controls[] = {
-	{ V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
-};
-
 #define HEXIUM_GEMINI_V_1_0		1
 #define HEXIUM_GEMINI_DUAL_V_1_0	2
 
@@ -76,7 +71,6 @@
 
 	int 		cur_input;	/* current input */
 	v4l2_std_id 	cur_std;	/* current standard */
-	int		cur_bw;		/* current black/white status */
 };
 
 /* Samsung KS0127B decoder default registers */
@@ -119,18 +113,10 @@
 	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
 };
 
-static struct hexium_data hexium_pal_bw[] = {
-	{ 0x01, 0x52 },	{ 0x12, 0x64 },	{ 0x2D, 0x2C },	{ 0x2E, 0x9B },	{ -1 , 0xFF }
-};
-
 static struct hexium_data hexium_ntsc[] = {
 	{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
 };
 
-static struct hexium_data hexium_ntsc_bw[] = {
-	{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
-};
-
 static struct hexium_data hexium_secam[] = {
 	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
 };
@@ -264,93 +250,6 @@
 	return 0;
 }
 
-/* the saa7146 provides some controls (brightness, contrast, saturation)
-   which gets registered *after* this function. because of this we have
-   to return with a value != 0 even if the function succeeded.. */
-static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	int i;
-
-	for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
-		if (hexium_controls[i].id == qc->id) {
-			*qc = hexium_controls[i];
-			DEB_D("VIDIOC_QUERYCTRL %d\n", qc->id);
-			return 0;
-		}
-	}
-	return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct hexium *hexium = (struct hexium *) dev->ext_priv;
-	int i;
-
-	for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
-		if (hexium_controls[i].id == vc->id)
-			break;
-	}
-
-	if (i < 0)
-		return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
-
-	if (vc->id == V4L2_CID_PRIVATE_BASE) {
-		vc->value = hexium->cur_bw;
-		DEB_D("VIDIOC_G_CTRL BW:%d\n", vc->value);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct hexium *hexium = (struct hexium *) dev->ext_priv;
-	int i = 0;
-
-	for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
-		if (hexium_controls[i].id == vc->id)
-			break;
-	}
-
-	if (i < 0)
-		return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
-
-	if (vc->id == V4L2_CID_PRIVATE_BASE)
-		hexium->cur_bw = vc->value;
-
-	DEB_D("VIDIOC_S_CTRL BW:%d\n", hexium->cur_bw);
-
-	if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
-		hexium_set_standard(hexium, hexium_pal);
-		return 0;
-	}
-	if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
-		hexium_set_standard(hexium, hexium_ntsc);
-		return 0;
-	}
-	if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
-		hexium_set_standard(hexium, hexium_secam);
-		return 0;
-	}
-	if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
-		hexium_set_standard(hexium, hexium_pal_bw);
-		return 0;
-	}
-	if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
-		hexium_set_standard(hexium, hexium_ntsc_bw);
-		return 0;
-	}
-	if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std)
-		/* fixme: is there no bw secam mode? */
-		return -EINVAL;
-
-	return -EINVAL;
-}
-
-
 static struct saa7146_ext_vv vv_data;
 
 /* this function only gets called when the probing was successful */
@@ -399,12 +298,10 @@
 	hexium->cur_input = 0;
 
 	saa7146_vv_init(dev, &vv_data);
-	vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
-	vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
-	vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
-	vv_data.ops.vidioc_enum_input = vidioc_enum_input;
-	vv_data.ops.vidioc_g_input = vidioc_g_input;
-	vv_data.ops.vidioc_s_input = vidioc_s_input;
+
+	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
 	ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
 	if (ret < 0) {
 		pr_err("cannot register capture v4l2 device. skipping.\n");
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index 23debc9..a1eb26d 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -41,15 +41,15 @@
 
 #define HEXIUM_INPUTS	9
 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
-	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
 };
 
 #define HEXIUM_AUDIOS	0
@@ -371,9 +371,9 @@
 	DEB_EE("\n");
 
 	saa7146_vv_init(dev, &vv_data);
-	vv_data.ops.vidioc_enum_input = vidioc_enum_input;
-	vv_data.ops.vidioc_g_input = vidioc_g_input;
-	vv_data.ops.vidioc_s_input = vidioc_s_input;
+	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
 	if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
 		pr_err("cannot register capture v4l2 device. skipping.\n");
 		return -1;
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 679262e..057929e 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1201,9 +1201,9 @@
 		struct v4l2_ctrl_handler *hdl = itv->v4l2_dev.ctrl_handler;
 
 		itv->ctrl_pts = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
-				V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 1, 0);
+				V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 0, 0);
 		itv->ctrl_frame = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
-				V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0x7fffffff, 1, 0);
+				V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0, 0, 0);
 		/* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported,
 		   mask that menu item. */
 		itv->ctrl_audio_playback =
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index c9663e8..9ff69b5 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -746,8 +746,9 @@
 	return res;
 }
 
-unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
+unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait)
 {
+	unsigned long req_events = poll_requested_events(wait);
 	struct ivtv_open_id *id = fh2id(filp->private_data);
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
@@ -755,7 +756,8 @@
 	unsigned res = 0;
 
 	/* Start a capture if there is none */
-	if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+	if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags) &&
+			(req_events & (POLLIN | POLLRDNORM))) {
 		int rc;
 
 		rc = ivtv_start_capture(id);
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 989e556..f7d57b3 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -135,7 +135,6 @@
 int ivtv_set_speed(struct ivtv *itv, int speed)
 {
 	u32 data[CX2341X_MBOX_MAX_DATA];
-	struct ivtv_stream *s;
 	int single_step = (speed == 1 || speed == -1);
 	DEFINE_WAIT(wait);
 
@@ -145,8 +144,6 @@
 	if (speed == itv->speed && !single_step)
 		return 0;
 
-	s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
-
 	if (single_step && (speed < 0) == (itv->speed < 0)) {
 		/* Single step video and no need to change direction */
 		ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);
@@ -1468,8 +1465,9 @@
 	switch (sub->type) {
 	case V4L2_EVENT_VSYNC:
 	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
 	case V4L2_EVENT_CTRL:
-		return v4l2_event_subscribe(fh, sub, 0);
+		return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
 	default:
 		return -EINVAL;
 	}
@@ -1827,7 +1825,7 @@
 		return ivtv_decoder_ioctls(file, cmd, (void *)arg);
 
 	default:
-		return -EINVAL;
+		return -ENOTTY;
 	}
 	return 0;
 }
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 7ea5ca7..6738592 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -228,6 +228,10 @@
 	s->vdev->release = video_device_release;
 	s->vdev->tvnorms = V4L2_STD_ALL;
 	s->vdev->lock = &itv->serialize_lock;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &s->vdev->flags);
 	set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags);
 	ivtv_set_funcs(s->vdev);
 	return 0;
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index e5e7fa9..05b94aa 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -1293,6 +1293,7 @@
 
 	drv = driver_find("ivtv", &pci_bus_type);
 	err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
+	(void)err;	/* suppress compiler warning */
 	if (!registered) {
 		printk(KERN_ERR "ivtvfb:  no cards found\n");
 		return -ENODEV;
@@ -1309,6 +1310,7 @@
 
 	drv = driver_find("ivtv", &pci_bus_type);
 	err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
+	(void)err;	/* suppress compiler warning */
 }
 
 module_init(ivtvfb_init);
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h
index 4b021e1..bb58991 100644
--- a/drivers/media/video/m5mols/m5mols.h
+++ b/drivers/media/video/m5mols/m5mols.h
@@ -21,11 +21,6 @@
 
 extern int m5mols_debug;
 
-#define to_m5mols(__sd)	container_of(__sd, struct m5mols_info, sd)
-
-#define to_sd(__ctrl) \
-	(&container_of(__ctrl->handler, struct m5mols_info, handle)->sd)
-
 enum m5mols_restype {
 	M5MOLS_RESTYPE_MONITOR,
 	M5MOLS_RESTYPE_CAPTURE,
@@ -163,21 +158,27 @@
  * @ffmt: current fmt according to resolution type
  * @res_type: current resolution type
  * @irq_waitq: waitqueue for the capture
- * @flags: state variable for the interrupt handler
+ * @irq_done: set to 1 in the interrupt handler
  * @handle: control handler
- * @autoexposure: Auto Exposure control
- * @exposure: Exposure control
- * @autowb: Auto White Balance control
- * @colorfx: Color effect control
- * @saturation:	Saturation control
- * @zoom: Zoom control
+ * @auto_exposure: auto/manual exposure control
+ * @exposure_bias: exposure compensation control
+ * @exposure: manual exposure control
+ * @metering: exposure metering control
+ * @auto_iso: auto/manual ISO sensitivity control
+ * @iso: manual ISO sensitivity control
+ * @auto_wb: auto white balance control
+ * @lock_3a: 3A lock control
+ * @colorfx: color effect control
+ * @saturation: saturation control
+ * @zoom: zoom control
+ * @wdr: wide dynamic range control
+ * @stabilization: image stabilization control
+ * @jpeg_quality: JPEG compression quality control
  * @ver: information of the version
  * @cap: the capture mode attributes
- * @power: current sensor's power status
  * @isp_ready: 1 when the ISP controller has completed booting
+ * @power: current sensor's power status
  * @ctrl_sync: 1 when the control handler state is restored in H/W
- * @lock_ae: true means the Auto Exposure is locked
- * @lock_awb: true means the Aut WhiteBalance is locked
  * @resolution:	register value for current resolution
  * @mode: register value for current operation mode
  * @set_power: optional power callback to the board code
@@ -193,15 +194,27 @@
 	atomic_t irq_done;
 
 	struct v4l2_ctrl_handler handle;
+	struct {
+		/* exposure/exposure bias/auto exposure cluster */
+		struct v4l2_ctrl *auto_exposure;
+		struct v4l2_ctrl *exposure_bias;
+		struct v4l2_ctrl *exposure;
+		struct v4l2_ctrl *metering;
+	};
+	struct {
+		/* iso/auto iso cluster */
+		struct v4l2_ctrl *auto_iso;
+		struct v4l2_ctrl *iso;
+	};
+	struct v4l2_ctrl *auto_wb;
 
-	/* Autoexposure/exposure control cluster */
-	struct v4l2_ctrl *autoexposure;
-	struct v4l2_ctrl *exposure;
-
-	struct v4l2_ctrl *autowb;
+	struct v4l2_ctrl *lock_3a;
 	struct v4l2_ctrl *colorfx;
 	struct v4l2_ctrl *saturation;
 	struct v4l2_ctrl *zoom;
+	struct v4l2_ctrl *wdr;
+	struct v4l2_ctrl *stabilization;
+	struct v4l2_ctrl *jpeg_quality;
 
 	struct m5mols_version ver;
 	struct m5mols_capture cap;
@@ -210,8 +223,6 @@
 	unsigned int power:1;
 	unsigned int ctrl_sync:1;
 
-	bool lock_ae;
-	bool lock_awb;
 	u8 resolution;
 	u8 mode;
 
@@ -282,7 +293,7 @@
  * The available executing order between each modes are as follows:
  *   PARAMETER <---> MONITOR <---> CAPTURE
  */
-int m5mols_mode(struct m5mols_info *info, u8 mode);
+int m5mols_set_mode(struct m5mols_info *info, u8 mode);
 
 int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
 int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
@@ -291,9 +302,33 @@
 int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
 int m5mols_lock_3a(struct m5mols_info *info, bool lock);
 int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
+int m5mols_init_controls(struct v4l2_subdev *sd);
 
 /* The firmware function */
 int m5mols_update_fw(struct v4l2_subdev *sd,
 		     int (*set_power)(struct m5mols_info *, bool));
 
+static inline struct m5mols_info *to_m5mols(struct v4l2_subdev *subdev)
+{
+	return container_of(subdev, struct m5mols_info, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	struct m5mols_info *info = container_of(ctrl->handler,
+						struct m5mols_info, handle);
+	return &info->sd;
+}
+
+static inline void m5mols_set_ctrl_mode(struct v4l2_ctrl *ctrl,
+					unsigned int mode)
+{
+	ctrl->priv = (void *)mode;
+}
+
+static inline unsigned int m5mols_get_ctrl_mode(struct v4l2_ctrl *ctrl)
+{
+	return (unsigned int)ctrl->priv;
+}
+
 #endif	/* M5MOLS_H */
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c
index ba25e8e..cb243bd 100644
--- a/drivers/media/video/m5mols/m5mols_capture.c
+++ b/drivers/media/video/m5mols/m5mols_capture.c
@@ -106,7 +106,6 @@
 int m5mols_start_capture(struct m5mols_info *info)
 {
 	struct v4l2_subdev *sd = &info->sd;
-	u8 resolution = info->resolution;
 	int ret;
 
 	/*
@@ -114,22 +113,18 @@
 	 * format. The frame capture is initiated during switching from Monitor
 	 * to Capture mode.
 	 */
-	ret = m5mols_mode(info, REG_MONITOR);
+	ret = m5mols_set_mode(info, REG_MONITOR);
 	if (!ret)
 		ret = m5mols_restore_controls(info);
 	if (!ret)
 		ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
 	if (!ret)
-		ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
+		ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution);
 	if (!ret)
-		ret = m5mols_lock_3a(info, true);
-	if (!ret)
-		ret = m5mols_mode(info, REG_CAPTURE);
+		ret = m5mols_set_mode(info, REG_CAPTURE);
 	if (!ret)
 		/* Wait until a frame is captured to ISP internal memory */
 		ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
-	if (!ret)
-		ret = m5mols_lock_3a(info, false);
 	if (ret)
 		return ret;
 
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c
index d135d20..392a028 100644
--- a/drivers/media/video/m5mols/m5mols_controls.c
+++ b/drivers/media/video/m5mols/m5mols_controls.c
@@ -139,7 +139,7 @@
 	if (mode > REG_SCENE_CANDLE)
 		return -EINVAL;
 
-	ret = m5mols_lock_3a(info, false);
+	ret = v4l2_ctrl_s_ctrl(info->lock_3a, 0);
 	if (!ret)
 		ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
 	if (!ret)
@@ -169,7 +169,7 @@
 	if (!ret)
 		ret = m5mols_write(sd, AE_ISO, scenemode.iso);
 	if (!ret)
-		ret = m5mols_mode(info, REG_CAPTURE);
+		ret = m5mols_set_mode(info, REG_CAPTURE);
 	if (!ret)
 		ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
 	if (!ret)
@@ -181,119 +181,448 @@
 	if (!ret)
 		ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
 	if (!ret)
-		ret = m5mols_mode(info, REG_MONITOR);
+		ret = m5mols_set_mode(info, REG_MONITOR);
 
 	return ret;
 }
 
-static int m5mols_lock_ae(struct m5mols_info *info, bool lock)
+static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
 {
+	bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
 	int ret = 0;
 
-	if (info->lock_ae != lock)
-		ret = m5mols_write(&info->sd, AE_LOCK,
-				lock ? REG_AE_LOCK : REG_AE_UNLOCK);
-	if (!ret)
-		info->lock_ae = lock;
+	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
+		bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
 
-	return ret;
-}
+		ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ?
+				   REG_AE_LOCK : REG_AE_UNLOCK);
+		if (ret)
+			return ret;
+	}
 
-static int m5mols_lock_awb(struct m5mols_info *info, bool lock)
-{
-	int ret = 0;
+	if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
+	    && info->auto_wb->val) {
+		bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
 
-	if (info->lock_awb != lock)
-		ret = m5mols_write(&info->sd, AWB_LOCK,
-				lock ? REG_AWB_LOCK : REG_AWB_UNLOCK);
-	if (!ret)
-		info->lock_awb = lock;
+		ret = m5mols_write(&info->sd, AWB_LOCK, awb_lock ?
+				   REG_AWB_LOCK : REG_AWB_UNLOCK);
+		if (ret)
+			return ret;
+	}
 
-	return ret;
-}
+	if (!info->ver.af || !af_lock)
+		return ret;
 
-/* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */
-int m5mols_lock_3a(struct m5mols_info *info, bool lock)
-{
-	int ret;
-
-	ret = m5mols_lock_ae(info, lock);
-	if (!ret)
-		ret = m5mols_lock_awb(info, lock);
-	/* Don't need to handle unlocking AF */
-	if (!ret && is_available_af(info) && lock)
+	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
 		ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
 
 	return ret;
 }
 
-/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */
-int m5mols_set_ctrl(struct v4l2_ctrl *ctrl)
+static int m5mols_set_metering_mode(struct m5mols_info *info, int mode)
+{
+	unsigned int metering;
+
+	switch (mode) {
+	case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
+		metering = REG_AE_CENTER;
+		break;
+	case V4L2_EXPOSURE_METERING_SPOT:
+		metering = REG_AE_SPOT;
+		break;
+	default:
+		metering = REG_AE_ALL;
+		break;
+	}
+
+	return m5mols_write(&info->sd, AE_MODE, metering);
+}
+
+static int m5mols_set_exposure(struct m5mols_info *info, int exposure)
+{
+	struct v4l2_subdev *sd = &info->sd;
+	int ret = 0;
+
+	if (exposure == V4L2_EXPOSURE_AUTO) {
+		/* Unlock auto exposure */
+		info->lock_3a->val &= ~V4L2_LOCK_EXPOSURE;
+		m5mols_3a_lock(info, info->lock_3a);
+
+		ret = m5mols_set_metering_mode(info, info->metering->val);
+		if (ret < 0)
+			return ret;
+
+		v4l2_dbg(1, m5mols_debug, sd,
+			 "%s: exposure bias: %#x, metering: %#x\n",
+			 __func__, info->exposure_bias->val,
+			 info->metering->val);
+
+		return m5mols_write(sd, AE_INDEX, info->exposure_bias->val);
+	}
+
+	if (exposure == V4L2_EXPOSURE_MANUAL) {
+		ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
+		if (ret == 0)
+			ret = m5mols_write(sd, AE_MAN_GAIN_MON,
+					   info->exposure->val);
+		if (ret == 0)
+			ret = m5mols_write(sd, AE_MAN_GAIN_CAP,
+					   info->exposure->val);
+
+		v4l2_dbg(1, m5mols_debug, sd, "%s: exposure: %#x\n",
+			 __func__, info->exposure->val);
+	}
+
+	return ret;
+}
+
+static int m5mols_set_white_balance(struct m5mols_info *info, int val)
+{
+	static const unsigned short wb[][2] = {
+		{ V4L2_WHITE_BALANCE_INCANDESCENT,  REG_AWB_INCANDESCENT },
+		{ V4L2_WHITE_BALANCE_FLUORESCENT,   REG_AWB_FLUORESCENT_1 },
+		{ V4L2_WHITE_BALANCE_FLUORESCENT_H, REG_AWB_FLUORESCENT_2 },
+		{ V4L2_WHITE_BALANCE_HORIZON,       REG_AWB_HORIZON },
+		{ V4L2_WHITE_BALANCE_DAYLIGHT,      REG_AWB_DAYLIGHT },
+		{ V4L2_WHITE_BALANCE_FLASH,         REG_AWB_LEDLIGHT },
+		{ V4L2_WHITE_BALANCE_CLOUDY,        REG_AWB_CLOUDY },
+		{ V4L2_WHITE_BALANCE_SHADE,         REG_AWB_SHADE },
+		{ V4L2_WHITE_BALANCE_AUTO,          REG_AWB_AUTO },
+	};
+	int i;
+	struct v4l2_subdev *sd = &info->sd;
+	int ret = -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(wb); i++) {
+		int awb;
+		if (wb[i][0] != val)
+			continue;
+
+		v4l2_dbg(1, m5mols_debug, sd,
+			 "Setting white balance to: %#x\n", wb[i][0]);
+
+		awb = wb[i][0] == V4L2_WHITE_BALANCE_AUTO;
+		ret = m5mols_write(sd, AWB_MODE, awb ? REG_AWB_AUTO :
+						 REG_AWB_PRESET);
+		if (ret < 0)
+			return ret;
+
+		if (!awb)
+			ret = m5mols_write(sd, AWB_MANUAL, wb[i][1]);
+	}
+
+	return ret;
+}
+
+static int m5mols_set_saturation(struct m5mols_info *info, int val)
+{
+	int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val);
+	if (ret < 0)
+		return ret;
+
+	return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON);
+}
+
+static int m5mols_set_color_effect(struct m5mols_info *info, int val)
+{
+	unsigned int m_effect = REG_COLOR_EFFECT_OFF;
+	unsigned int p_effect = REG_EFFECT_OFF;
+	unsigned int cfix_r = 0, cfix_b = 0;
+	struct v4l2_subdev *sd = &info->sd;
+	int ret = 0;
+
+	switch (val) {
+	case V4L2_COLORFX_BW:
+		m_effect = REG_COLOR_EFFECT_ON;
+		break;
+	case V4L2_COLORFX_NEGATIVE:
+		p_effect = REG_EFFECT_NEGA;
+		break;
+	case V4L2_COLORFX_EMBOSS:
+		p_effect = REG_EFFECT_EMBOSS;
+		break;
+	case V4L2_COLORFX_SEPIA:
+		m_effect = REG_COLOR_EFFECT_ON;
+		cfix_r = REG_CFIXR_SEPIA;
+		cfix_b = REG_CFIXB_SEPIA;
+		break;
+	}
+
+	ret = m5mols_write(sd, PARM_EFFECT, p_effect);
+	if (!ret)
+		ret = m5mols_write(sd, MON_EFFECT, m_effect);
+
+	if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) {
+		ret = m5mols_write(sd, MON_CFIXR, cfix_r);
+		if (!ret)
+			ret = m5mols_write(sd, MON_CFIXB, cfix_b);
+	}
+
+	v4l2_dbg(1, m5mols_debug, sd,
+		 "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n",
+		 p_effect, m_effect, cfix_r, cfix_b, ret);
+
+	return ret;
+}
+
+static int m5mols_set_iso(struct m5mols_info *info, int auto_iso)
+{
+	u32 iso = auto_iso ? 0 : info->iso->val + 1;
+
+	return m5mols_write(&info->sd, AE_ISO, iso);
+}
+
+static int m5mols_set_wdr(struct m5mols_info *info, int wdr)
+{
+	int ret;
+
+	ret = m5mols_write(&info->sd, MON_TONE_CTL, wdr ? 9 : 5);
+	if (ret < 0)
+		return ret;
+
+	ret = m5mols_set_mode(info, REG_CAPTURE);
+	if (ret < 0)
+		return ret;
+
+	return m5mols_write(&info->sd, CAPP_WDR_EN, wdr);
+}
+
+static int m5mols_set_stabilization(struct m5mols_info *info, int val)
+{
+	struct v4l2_subdev *sd = &info->sd;
+	unsigned int evp = val ? 0xe : 0x0;
+	int ret;
+
+	ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, evp);
+	if (ret < 0)
+		return ret;
+
+	return m5mols_write(sd, AE_EV_PRESET_CAPTURE, evp);
+}
+
+static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct v4l2_subdev *sd = to_sd(ctrl);
 	struct m5mols_info *info = to_m5mols(sd);
-	int ret;
+	int ret = 0;
+	u8 status;
+
+	v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n",
+		 __func__, ctrl->name, info->isp_ready);
+
+	if (!info->isp_ready)
+		return -EBUSY;
 
 	switch (ctrl->id) {
+	case V4L2_CID_ISO_SENSITIVITY_AUTO:
+		ret = m5mols_read_u8(sd, AE_ISO, &status);
+		if (ret == 0)
+			ctrl->val = !status;
+		if (status != REG_ISO_AUTO)
+			info->iso->val = status - 1;
+		break;
+
+	case V4L2_CID_3A_LOCK:
+		ctrl->val &= ~0x7;
+
+		ret = m5mols_read_u8(sd, AE_LOCK, &status);
+		if (ret)
+			return ret;
+		if (status)
+			info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
+
+		ret = m5mols_read_u8(sd, AWB_LOCK, &status);
+		if (ret)
+			return ret;
+		if (status)
+			info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
+
+		ret = m5mols_read_u8(sd, AF_EXECUTE, &status);
+		if (!status)
+			info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
+		break;
+	}
+
+	return ret;
+}
+
+static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	unsigned int ctrl_mode = m5mols_get_ctrl_mode(ctrl);
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct m5mols_info *info = to_m5mols(sd);
+	int last_mode = info->mode;
+	int ret = 0;
+
+	/*
+	 * If needed, defer restoring the controls until
+	 * the device is fully initialized.
+	 */
+	if (!info->isp_ready) {
+		info->ctrl_sync = 0;
+		return 0;
+	}
+
+	v4l2_dbg(1, m5mols_debug, sd, "%s: %s, val: %d, priv: %#x\n",
+		 __func__, ctrl->name, ctrl->val, (int)ctrl->priv);
+
+	if (ctrl_mode && ctrl_mode != info->mode) {
+		ret = m5mols_set_mode(info, ctrl_mode);
+		if (ret < 0)
+			return ret;
+	}
+
+	switch (ctrl->id) {
+	case V4L2_CID_3A_LOCK:
+		ret = m5mols_3a_lock(info, ctrl);
+		break;
+
 	case V4L2_CID_ZOOM_ABSOLUTE:
-		return m5mols_write(sd, MON_ZOOM, ctrl->val);
+		ret = m5mols_write(sd, MON_ZOOM, ctrl->val);
+		break;
 
 	case V4L2_CID_EXPOSURE_AUTO:
-		ret = m5mols_lock_ae(info,
-			ctrl->val == V4L2_EXPOSURE_AUTO ? false : true);
-		if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO)
-			ret = m5mols_write(sd, AE_MODE, REG_AE_ALL);
-		if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) {
-			int val = info->exposure->val;
-			ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
-			if (!ret)
-				ret = m5mols_write(sd, AE_MAN_GAIN_MON, val);
-			if (!ret)
-				ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val);
-		}
-		return ret;
+		ret = m5mols_set_exposure(info, ctrl->val);
+		break;
 
-	case V4L2_CID_AUTO_WHITE_BALANCE:
-		ret = m5mols_lock_awb(info, ctrl->val ? false : true);
-		if (!ret)
-			ret = m5mols_write(sd, AWB_MODE, ctrl->val ?
-				REG_AWB_AUTO : REG_AWB_PRESET);
-		return ret;
+	case V4L2_CID_ISO_SENSITIVITY:
+		ret = m5mols_set_iso(info, ctrl->val);
+		break;
+
+	case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+		ret = m5mols_set_white_balance(info, ctrl->val);
+		break;
 
 	case V4L2_CID_SATURATION:
-		ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val);
-		if (!ret)
-			ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON);
-		return ret;
+		ret = m5mols_set_saturation(info, ctrl->val);
+		break;
 
 	case V4L2_CID_COLORFX:
-		/*
-		 * This control uses two kinds of registers: normal & color.
-		 * The normal effect belongs to category 1, while the color
-		 * one belongs to category 2.
-		 *
-		 * The normal effect uses one register: CAT1_EFFECT.
-		 * The color effect uses three registers:
-		 * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB.
-		 */
-		ret = m5mols_write(sd, PARM_EFFECT,
-			ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA :
-			ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS :
-			REG_EFFECT_OFF);
-		if (!ret)
-			ret = m5mols_write(sd, MON_EFFECT,
-				ctrl->val == V4L2_COLORFX_SEPIA ?
-				REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF);
-		if (!ret)
-			ret = m5mols_write(sd, MON_CFIXR,
-				ctrl->val == V4L2_COLORFX_SEPIA ?
-				REG_CFIXR_SEPIA : 0);
-		if (!ret)
-			ret = m5mols_write(sd, MON_CFIXB,
-				ctrl->val == V4L2_COLORFX_SEPIA ?
-				REG_CFIXB_SEPIA : 0);
+		ret = m5mols_set_color_effect(info, ctrl->val);
+		break;
+
+	case V4L2_CID_WIDE_DYNAMIC_RANGE:
+		ret = m5mols_set_wdr(info, ctrl->val);
+		break;
+
+	case V4L2_CID_IMAGE_STABILIZATION:
+		ret = m5mols_set_stabilization(info, ctrl->val);
+		break;
+
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+		ret = m5mols_write(sd, CAPP_JPEG_RATIO, ctrl->val);
+		break;
+	}
+
+	if (ret == 0 && info->mode != last_mode)
+		ret = m5mols_set_mode(info, last_mode);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
+	.g_volatile_ctrl	= m5mols_g_volatile_ctrl,
+	.s_ctrl			= m5mols_s_ctrl,
+};
+
+/* Supported manual ISO values */
+static const s64 iso_qmenu[] = {
+	/* AE_ISO: 0x01...0x07 */
+	50, 100, 200, 400, 800, 1600, 3200
+};
+
+/* Supported Exposure Bias values, -2.0EV...+2.0EV */
+static const s64 ev_bias_qmenu[] = {
+	/* AE_INDEX: 0x00...0x08 */
+	-2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000
+};
+
+int m5mols_init_controls(struct v4l2_subdev *sd)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+	u16 exposure_max;
+	u16 zoom_step;
+	int ret;
+
+	/* Determine the firmware dependant control range and step values */
+	ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max);
+	if (ret < 0)
+		return ret;
+
+	zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
+	v4l2_ctrl_handler_init(&info->handle, 20);
+
+	info->auto_wb = v4l2_ctrl_new_std_menu(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+			9, ~0x3fe, V4L2_WHITE_BALANCE_AUTO);
+
+	/* Exposure control cluster */
+	info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
+			1, ~0x03, V4L2_EXPOSURE_AUTO);
+
+	info->exposure = v4l2_ctrl_new_std(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
+			0, exposure_max, 1, exposure_max / 2);
+
+	info->exposure_bias = v4l2_ctrl_new_int_menu(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS,
+			ARRAY_SIZE(ev_bias_qmenu) - 1,
+			ARRAY_SIZE(ev_bias_qmenu)/2 - 1,
+			ev_bias_qmenu);
+
+	info->metering = v4l2_ctrl_new_std_menu(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE_METERING,
+			2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE);
+
+	/* ISO control cluster */
+	info->auto_iso = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_ISO_SENSITIVITY_AUTO, 1, ~0x03, 1);
+
+	info->iso = v4l2_ctrl_new_int_menu(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
+			ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
+
+	info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_SATURATION, 1, 5, 1, 3);
+
+	info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1);
+
+	info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE);
+
+	info->wdr = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0);
+
+	info->stabilization = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0);
+
+	info->jpeg_quality = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80);
+
+	info->lock_3a = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_3A_LOCK, 0, 0x7, 0, 0);
+
+	if (info->handle.error) {
+		int ret = info->handle.error;
+		v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
+		v4l2_ctrl_handler_free(&info->handle);
 		return ret;
 	}
 
-	return -EINVAL;
+	v4l2_ctrl_auto_cluster(4, &info->auto_exposure, 1, false);
+	info->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
+				V4L2_CTRL_FLAG_UPDATE;
+	v4l2_ctrl_auto_cluster(2, &info->auto_iso, 0, false);
+
+	info->lock_3a->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+	m5mols_set_ctrl_mode(info->auto_exposure, REG_PARAMETER);
+	m5mols_set_ctrl_mode(info->auto_wb, REG_PARAMETER);
+	m5mols_set_ctrl_mode(info->colorfx, REG_MONITOR);
+
+	sd->ctrl_handler = &info->handle;
+
+	return 0;
 }
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
index d718aee..ac7d28b 100644
--- a/drivers/media/video/m5mols/m5mols_core.c
+++ b/drivers/media/video/m5mols/m5mols_core.c
@@ -362,14 +362,14 @@
 }
 
 /**
- * m5mols_mode - manage the M-5MOLS's mode
+ * m5mols_set_mode - set the M-5MOLS controller mode
  * @mode: the required operation mode
  *
  * The commands of M-5MOLS are grouped into specific modes. Each functionality
- * can be guaranteed only when the sensor is operating in mode which which
- * a command belongs to.
+ * can be guaranteed only when the sensor is operating in mode which a command
+ * belongs to.
  */
-int m5mols_mode(struct m5mols_info *info, u8 mode)
+int m5mols_set_mode(struct m5mols_info *info, u8 mode)
 {
 	struct v4l2_subdev *sd = &info->sd;
 	int ret = -EINVAL;
@@ -645,13 +645,13 @@
 	struct v4l2_subdev *sd = &info->sd;
 	int ret;
 
-	ret = m5mols_mode(info, REG_PARAMETER);
+	ret = m5mols_set_mode(info, REG_PARAMETER);
 	if (!ret)
 		ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
 	if (!ret)
 		ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
 	if (!ret)
-		ret = m5mols_mode(info, REG_MONITOR);
+		ret = m5mols_set_mode(info, REG_MONITOR);
 	if (!ret)
 		ret = m5mols_restore_controls(info);
 
@@ -674,42 +674,13 @@
 		return ret;
 	}
 
-	return m5mols_mode(info, REG_PARAMETER);
+	return m5mols_set_mode(info, REG_PARAMETER);
 }
 
 static const struct v4l2_subdev_video_ops m5mols_video_ops = {
 	.s_stream	= m5mols_s_stream,
 };
 
-static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct v4l2_subdev *sd = to_sd(ctrl);
-	struct m5mols_info *info = to_m5mols(sd);
-	int ispstate = info->mode;
-	int ret;
-
-	/*
-	 * If needed, defer restoring the controls until
-	 * the device is fully initialized.
-	 */
-	if (!info->isp_ready) {
-		info->ctrl_sync = 0;
-		return 0;
-	}
-
-	ret = m5mols_mode(info, REG_PARAMETER);
-	if (ret < 0)
-		return ret;
-	ret = m5mols_set_ctrl(ctrl);
-	if (ret < 0)
-		return ret;
-	return m5mols_mode(info, ispstate);
-}
-
-static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
-	.s_ctrl	= m5mols_s_ctrl,
-};
-
 static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
 {
 	struct v4l2_subdev *sd = &info->sd;
@@ -802,52 +773,6 @@
 	return ret;
 }
 
-static int m5mols_init_controls(struct m5mols_info *info)
-{
-	struct v4l2_subdev *sd = &info->sd;
-	u16 max_exposure;
-	u16 step_zoom;
-	int ret;
-
-	/* Determine value's range & step of controls for various FW version */
-	ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure);
-	if (!ret)
-		step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
-	if (ret)
-		return ret;
-
-	v4l2_ctrl_handler_init(&info->handle, 6);
-	info->autowb = v4l2_ctrl_new_std(&info->handle,
-			&m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
-			0, 1, 1, 0);
-	info->saturation = v4l2_ctrl_new_std(&info->handle,
-			&m5mols_ctrl_ops, V4L2_CID_SATURATION,
-			1, 5, 1, 3);
-	info->zoom = v4l2_ctrl_new_std(&info->handle,
-			&m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE,
-			1, 70, step_zoom, 1);
-	info->exposure = v4l2_ctrl_new_std(&info->handle,
-			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
-			0, max_exposure, 1, (int)max_exposure/2);
-	info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
-			&m5mols_ctrl_ops, V4L2_CID_COLORFX,
-			4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
-	info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
-			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
-			1, 0, V4L2_EXPOSURE_AUTO);
-
-	sd->ctrl_handler = &info->handle;
-	if (info->handle.error) {
-		v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
-		v4l2_ctrl_handler_free(&info->handle);
-		return info->handle.error;
-	}
-
-	v4l2_ctrl_cluster(2, &info->autoexposure);
-
-	return 0;
-}
-
 /**
  * m5mols_s_power - Main sensor power control function
  *
@@ -868,7 +793,7 @@
 	}
 
 	if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
-		ret = m5mols_mode(info, REG_MONITOR);
+		ret = m5mols_set_mode(info, REG_MONITOR);
 		if (!ret)
 			ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
 		if (!ret)
@@ -1010,7 +935,7 @@
 
 	ret = m5mols_fw_start(sd);
 	if (!ret)
-		ret = m5mols_init_controls(info);
+		ret = m5mols_init_controls(sd);
 
 	m5mols_sensor_power(info, false);
 	if (!ret)
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h
index ae4aced..14d4be7 100644
--- a/drivers/media/video/m5mols/m5mols_reg.h
+++ b/drivers/media/video/m5mols/m5mols_reg.h
@@ -310,6 +310,7 @@
 #define REG_JPEG		0x10
 
 #define CAPP_MAIN_IMAGE_SIZE	I2C_REG(CAT_CAPT_PARM, 0x01, 1)
+#define CAPP_JPEG_RATIO		I2C_REG(CAT_CAPT_PARM, 0x17, 1)
 
 #define CAPP_MCC_MODE		I2C_REG(CAT_CAPT_PARM, 0x1d, 1)
 #define REG_MCC_OFF		0x00
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c
index 996ac34..ce2b7b4 100644
--- a/drivers/media/video/marvell-ccic/mcam-core.c
+++ b/drivers/media/video/marvell-ccic/mcam-core.c
@@ -1356,7 +1356,6 @@
 			goto out;
 	}
 	mcam_set_config_needed(cam, 1);
-	ret = 0;
 out:
 	mutex_unlock(&cam->s_mutex);
 	return ret;
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
index 12897e8..d2dec58 100644
--- a/drivers/media/video/mem2mem_testdev.c
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -40,7 +40,7 @@
 #define MIN_H 32
 #define MAX_W 640
 #define MAX_H 480
-#define DIM_ALIGN_MASK 0x08 /* 8-alignment for dimensions */
+#define DIM_ALIGN_MASK 7 /* 8-byte alignment for line length */
 
 /* Flags that indicate a format can be used for capture/output */
 #define MEM2MEM_CAPTURE	(1 << 0)
@@ -958,6 +958,10 @@
 	}
 
 	*vfd = m2mtest_videodev;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 	vfd->lock = &dev->dev_mutex;
 
 	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index b09a3c8..7bc7752 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1570,7 +1570,7 @@
 		return meyeioc_stilljcapt((int *) arg);
 
 	default:
-		return -EINVAL;
+		return -ENOTTY;
 	}
 
 }
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 82ce507..aeb22be 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -597,19 +597,23 @@
 	return 0;
 }
 
-static int msp_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int msp_suspend(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	v4l_dbg(1, msp_debug, client, "suspend\n");
 	msp_reset(client);
 	return 0;
 }
 
-static int msp_resume(struct i2c_client *client)
+static int msp_resume(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	v4l_dbg(1, msp_debug, client, "resume\n");
 	msp_wake_thread(client);
 	return 0;
 }
+#endif
 
 /* ----------------------------------------------------------------------- */
 
@@ -863,6 +867,10 @@
 
 /* ----------------------------------------------------------------------- */
 
+static const struct dev_pm_ops msp3400_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(msp_suspend, msp_resume)
+};
+
 static const struct i2c_device_id msp_id[] = {
 	{ "msp3400", 0 },
 	{ }
@@ -873,11 +881,10 @@
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "msp3400",
+		.pm	= &msp3400_pm_ops,
 	},
 	.probe		= msp_probe,
 	.remove		= msp_remove,
-	.suspend	= msp_suspend,
-	.resume		= msp_resume,
 	.id_table	= msp_id,
 };
 
diff --git a/drivers/media/video/mt9m032.c b/drivers/media/video/mt9m032.c
index 645973c..3c1e626 100644
--- a/drivers/media/video/mt9m032.c
+++ b/drivers/media/video/mt9m032.c
@@ -838,9 +838,9 @@
 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
 	struct mt9m032 *sensor = to_mt9m032(subdev);
 
-	v4l2_device_unregister_subdev(&sensor->subdev);
+	v4l2_device_unregister_subdev(subdev);
 	v4l2_ctrl_handler_free(&sensor->ctrls);
-	media_entity_cleanup(&sensor->subdev.entity);
+	media_entity_cleanup(&subdev->entity);
 	mutex_destroy(&sensor->lock);
 	kfree(sensor);
 	return 0;
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
index c81eaf4f..8f061d9 100644
--- a/drivers/media/video/mt9p031.c
+++ b/drivers/media/video/mt9p031.c
@@ -14,6 +14,7 @@
 
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/log2.h>
@@ -90,7 +91,14 @@
 #define		MT9P031_GLOBAL_GAIN_MAX			1024
 #define		MT9P031_GLOBAL_GAIN_DEF			8
 #define		MT9P031_GLOBAL_GAIN_MULT		(1 << 6)
+#define MT9P031_ROW_BLACK_TARGET			0x49
 #define MT9P031_ROW_BLACK_DEF_OFFSET			0x4b
+#define MT9P031_GREEN1_OFFSET				0x60
+#define MT9P031_GREEN2_OFFSET				0x61
+#define MT9P031_BLACK_LEVEL_CALIBRATION			0x62
+#define		MT9P031_BLC_MANUAL_BLC			(1 << 0)
+#define MT9P031_RED_OFFSET				0x63
+#define MT9P031_BLUE_OFFSET				0x64
 #define MT9P031_TEST_PATTERN				0xa0
 #define		MT9P031_TEST_PATTERN_SHIFT		3
 #define		MT9P031_TEST_PATTERN_ENABLE		(1 << 0)
@@ -99,17 +107,27 @@
 #define MT9P031_TEST_PATTERN_RED			0xa2
 #define MT9P031_TEST_PATTERN_BLUE			0xa3
 
+enum mt9p031_model {
+	MT9P031_MODEL_COLOR,
+	MT9P031_MODEL_MONOCHROME,
+};
+
 struct mt9p031 {
 	struct v4l2_subdev subdev;
 	struct media_pad pad;
 	struct v4l2_rect crop;  /* Sensor window */
 	struct v4l2_mbus_framefmt format;
-	struct v4l2_ctrl_handler ctrls;
 	struct mt9p031_platform_data *pdata;
 	struct mutex power_lock; /* lock to protect power_count */
 	int power_count;
 
+	enum mt9p031_model model;
 	struct aptina_pll pll;
+	int reset;
+
+	struct v4l2_ctrl_handler ctrls;
+	struct v4l2_ctrl *blc_auto;
+	struct v4l2_ctrl *blc_offset;
 
 	/* Registers cache */
 	u16 output_control;
@@ -241,8 +259,8 @@
 static int mt9p031_power_on(struct mt9p031 *mt9p031)
 {
 	/* Ensure RESET_BAR is low */
-	if (mt9p031->pdata->reset) {
-		mt9p031->pdata->reset(&mt9p031->subdev, 1);
+	if (mt9p031->reset != -1) {
+		gpio_set_value(mt9p031->reset, 0);
 		usleep_range(1000, 2000);
 	}
 
@@ -252,8 +270,8 @@
 					 mt9p031->pdata->ext_freq);
 
 	/* Now RESET_BAR must be high */
-	if (mt9p031->pdata->reset) {
-		mt9p031->pdata->reset(&mt9p031->subdev, 0);
+	if (mt9p031->reset != -1) {
+		gpio_set_value(mt9p031->reset, 1);
 		usleep_range(1000, 2000);
 	}
 
@@ -262,8 +280,8 @@
 
 static void mt9p031_power_off(struct mt9p031 *mt9p031)
 {
-	if (mt9p031->pdata->reset) {
-		mt9p031->pdata->reset(&mt9p031->subdev, 1);
+	if (mt9p031->reset != -1) {
+		gpio_set_value(mt9p031->reset, 0);
 		usleep_range(1000, 2000);
 	}
 
@@ -557,6 +575,10 @@
  */
 
 #define V4L2_CID_TEST_PATTERN		(V4L2_CID_USER_BASE | 0x1001)
+#define V4L2_CID_BLC_AUTO		(V4L2_CID_USER_BASE | 0x1002)
+#define V4L2_CID_BLC_TARGET_LEVEL	(V4L2_CID_USER_BASE | 0x1003)
+#define V4L2_CID_BLC_ANALOG_OFFSET	(V4L2_CID_USER_BASE | 0x1004)
+#define V4L2_CID_BLC_DIGITAL_OFFSET	(V4L2_CID_USER_BASE | 0x1005)
 
 static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
 {
@@ -621,11 +643,17 @@
 
 	case V4L2_CID_TEST_PATTERN:
 		if (!ctrl->val) {
-			ret = mt9p031_set_mode2(mt9p031,
-					0, MT9P031_READ_MODE_2_ROW_BLC);
-			if (ret < 0)
-				return ret;
-
+			/* Restore the black level compensation settings. */
+			if (mt9p031->blc_auto->cur.val != 0) {
+				ret = mt9p031_s_ctrl(mt9p031->blc_auto);
+				if (ret < 0)
+					return ret;
+			}
+			if (mt9p031->blc_offset->cur.val != 0) {
+				ret = mt9p031_s_ctrl(mt9p031->blc_offset);
+				if (ret < 0)
+					return ret;
+			}
 			return mt9p031_write(client, MT9P031_TEST_PATTERN,
 					     MT9P031_TEST_PATTERN_DISABLE);
 		}
@@ -640,10 +668,14 @@
 		if (ret < 0)
 			return ret;
 
+		/* Disable digital black level compensation when using a test
+		 * pattern.
+		 */
 		ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
 					0);
 		if (ret < 0)
 			return ret;
+
 		ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0);
 		if (ret < 0)
 			return ret;
@@ -651,7 +683,40 @@
 		return mt9p031_write(client, MT9P031_TEST_PATTERN,
 				((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT)
 				| MT9P031_TEST_PATTERN_ENABLE);
+
+	case V4L2_CID_BLC_AUTO:
+		ret = mt9p031_set_mode2(mt9p031,
+				ctrl->val ? 0 : MT9P031_READ_MODE_2_ROW_BLC,
+				ctrl->val ? MT9P031_READ_MODE_2_ROW_BLC : 0);
+		if (ret < 0)
+			return ret;
+
+		return mt9p031_write(client, MT9P031_BLACK_LEVEL_CALIBRATION,
+				     ctrl->val ? 0 : MT9P031_BLC_MANUAL_BLC);
+
+	case V4L2_CID_BLC_TARGET_LEVEL:
+		return mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
+				     ctrl->val);
+
+	case V4L2_CID_BLC_ANALOG_OFFSET:
+		data = ctrl->val & ((1 << 9) - 1);
+
+		ret = mt9p031_write(client, MT9P031_GREEN1_OFFSET, data);
+		if (ret < 0)
+			return ret;
+		ret = mt9p031_write(client, MT9P031_GREEN2_OFFSET, data);
+		if (ret < 0)
+			return ret;
+		ret = mt9p031_write(client, MT9P031_RED_OFFSET, data);
+		if (ret < 0)
+			return ret;
+		return mt9p031_write(client, MT9P031_BLUE_OFFSET, data);
+
+	case V4L2_CID_BLC_DIGITAL_OFFSET:
+		return mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET,
+				     ctrl->val & ((1 << 12) - 1));
 	}
+
 	return 0;
 }
 
@@ -685,6 +750,46 @@
 		.flags		= 0,
 		.menu_skip_mask	= 0,
 		.qmenu		= mt9p031_test_pattern_menu,
+	}, {
+		.ops		= &mt9p031_ctrl_ops,
+		.id		= V4L2_CID_BLC_AUTO,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "BLC, Auto",
+		.min		= 0,
+		.max		= 1,
+		.step		= 1,
+		.def		= 1,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9p031_ctrl_ops,
+		.id		= V4L2_CID_BLC_TARGET_LEVEL,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "BLC Target Level",
+		.min		= 0,
+		.max		= 4095,
+		.step		= 1,
+		.def		= 168,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9p031_ctrl_ops,
+		.id		= V4L2_CID_BLC_ANALOG_OFFSET,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "BLC Analog Offset",
+		.min		= -255,
+		.max		= 255,
+		.step		= 1,
+		.def		= 32,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9p031_ctrl_ops,
+		.id		= V4L2_CID_BLC_DIGITAL_OFFSET,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "BLC Digital Offset",
+		.min		= -2048,
+		.max		= 2047,
+		.step		= 1,
+		.def		= 40,
+		.flags		= 0,
 	}
 };
 
@@ -764,7 +869,7 @@
 
 	format = v4l2_subdev_get_try_format(fh, 0);
 
-	if (mt9p031->pdata->version == MT9P031_MONOCHROME_VERSION)
+	if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
 		format->code = V4L2_MBUS_FMT_Y12_1X12;
 	else
 		format->code = V4L2_MBUS_FMT_SGRBG12_1X12;
@@ -842,6 +947,8 @@
 	mt9p031->pdata = pdata;
 	mt9p031->output_control	= MT9P031_OUTPUT_CONTROL_DEF;
 	mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC;
+	mt9p031->model = did->driver_data;
+	mt9p031->reset = -1;
 
 	v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 4);
 
@@ -862,9 +969,16 @@
 
 	mt9p031->subdev.ctrl_handler = &mt9p031->ctrls;
 
-	if (mt9p031->ctrls.error)
+	if (mt9p031->ctrls.error) {
 		printk(KERN_INFO "%s: control initialization error %d\n",
 		       __func__, mt9p031->ctrls.error);
+		ret = mt9p031->ctrls.error;
+		goto done;
+	}
+
+	mt9p031->blc_auto = v4l2_ctrl_find(&mt9p031->ctrls, V4L2_CID_BLC_AUTO);
+	mt9p031->blc_offset = v4l2_ctrl_find(&mt9p031->ctrls,
+					     V4L2_CID_BLC_DIGITAL_OFFSET);
 
 	mutex_init(&mt9p031->power_lock);
 	v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);
@@ -882,7 +996,7 @@
 	mt9p031->crop.left = MT9P031_COLUMN_START_DEF;
 	mt9p031->crop.top = MT9P031_ROW_START_DEF;
 
-	if (mt9p031->pdata->version == MT9P031_MONOCHROME_VERSION)
+	if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
 		mt9p031->format.code = V4L2_MBUS_FMT_Y12_1X12;
 	else
 		mt9p031->format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
@@ -892,10 +1006,22 @@
 	mt9p031->format.field = V4L2_FIELD_NONE;
 	mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
 
+	if (pdata->reset != -1) {
+		ret = gpio_request_one(pdata->reset, GPIOF_OUT_INIT_LOW,
+				       "mt9p031_rst");
+		if (ret < 0)
+			goto done;
+
+		mt9p031->reset = pdata->reset;
+	}
+
 	ret = mt9p031_pll_setup(mt9p031);
 
 done:
 	if (ret < 0) {
+		if (mt9p031->reset != -1)
+			gpio_free(mt9p031->reset);
+
 		v4l2_ctrl_handler_free(&mt9p031->ctrls);
 		media_entity_cleanup(&mt9p031->subdev.entity);
 		kfree(mt9p031);
@@ -912,13 +1038,16 @@
 	v4l2_ctrl_handler_free(&mt9p031->ctrls);
 	v4l2_device_unregister_subdev(subdev);
 	media_entity_cleanup(&subdev->entity);
+	if (mt9p031->reset != -1)
+		gpio_free(mt9p031->reset);
 	kfree(mt9p031);
 
 	return 0;
 }
 
 static const struct i2c_device_id mt9p031_id[] = {
-	{ "mt9p031", 0 },
+	{ "mt9p031", MT9P031_MODEL_COLOR },
+	{ "mt9p031m", MT9P031_MODEL_MONOCHROME },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mt9p031_id);
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index 8d1445f..e1ae46a 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -453,6 +453,7 @@
 	 * I2C Master Clock Divider
 	 */
 	mt9t112_reg_write(ret, client, 0x0014, 0x3046);
+	mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */
 	mt9t112_reg_write(ret, client, 0x0022, 0x0190);
 	mt9t112_reg_write(ret, client, 0x3B84, 0x0212);
 
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c
index 75e253a..4ba4884 100644
--- a/drivers/media/video/mt9v032.c
+++ b/drivers/media/video/mt9v032.c
@@ -481,7 +481,7 @@
 
 	case V4L2_CID_EXPOSURE_AUTO:
 		return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
-					      ctrl->val);
+					      !ctrl->val);
 
 	case V4L2_CID_EXPOSURE:
 		return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 055d11d..4296a83 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -126,13 +126,8 @@
 			      unsigned int *size)
 {
 	struct soc_camera_device *icd = vq->priv_data;
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-						icd->current_fmt->host_fmt);
 
-	if (bytes_per_line < 0)
-		return bytes_per_line;
-
-	*size = bytes_per_line * icd->user_height;
+	*size = icd->sizeimage;
 
 	if (!*count)
 		*count = 32;
@@ -171,11 +166,6 @@
 	struct soc_camera_device *icd = vq->priv_data;
 	struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
 	int ret;
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-						icd->current_fmt->host_fmt);
-
-	if (bytes_per_line < 0)
-		return bytes_per_line;
 
 	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
 		vb, vb->baddr, vb->bsize);
@@ -202,7 +192,7 @@
 		vb->state	= VIDEOBUF_NEEDS_INIT;
 	}
 
-	vb->size = bytes_per_line * vb->height;
+	vb->size = icd->sizeimage;
 	if (0 != vb->baddr && vb->bsize < vb->size) {
 		ret = -EINVAL;
 		goto out;
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
index 18afaee..ded26b7 100644
--- a/drivers/media/video/mx2_camera.c
+++ b/drivers/media/video/mx2_camera.c
@@ -22,6 +22,7 @@
 #include <linux/gcd.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/math64.h>
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/time.h>
@@ -344,6 +345,19 @@
 					PRP_INTR_CH2OVF,
 		}
 	},
+	{
+		.in_fmt		= V4L2_MBUS_FMT_UYVY8_2X8,
+		.out_fmt	= V4L2_PIX_FMT_YUV420,
+		.cfg		= {
+			.channel	= 2,
+			.in_fmt		= PRP_CNTL_DATA_IN_YUV422,
+			.out_fmt	= PRP_CNTL_CH2_OUT_YUV420,
+			.src_pixel	= 0x22000888, /* YUV422 (YUYV) */
+			.irq_flags	= PRP_INTR_RDERR | PRP_INTR_CH2WERR |
+					PRP_INTR_CH2FC | PRP_INTR_LBOVF |
+					PRP_INTR_CH2OVF,
+		}
+	},
 };
 
 static struct mx2_fmt_cfg *mx27_emma_prp_get_format(
@@ -525,8 +539,6 @@
 	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct mx2_camera_dev *pcdev = ici->priv;
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-			icd->current_fmt->host_fmt);
 
 	dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]);
 
@@ -534,12 +546,9 @@
 	if (fmt != NULL)
 		return -ENOTTY;
 
-	if (bytes_per_line < 0)
-		return bytes_per_line;
-
 	alloc_ctxs[0] = pcdev->alloc_ctx;
 
-	sizes[0] = bytes_per_line * icd->user_height;
+	sizes[0] = icd->sizeimage;
 
 	if (0 == *count)
 		*count = 32;
@@ -555,16 +564,11 @@
 static int mx2_videobuf_prepare(struct vb2_buffer *vb)
 {
 	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-			icd->current_fmt->host_fmt);
 	int ret = 0;
 
 	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
 		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
-	if (bytes_per_line < 0)
-		return bytes_per_line;
-
 #ifdef DEBUG
 	/*
 	 * This can be useful if you want to see if we actually fill
@@ -574,7 +578,7 @@
 	       0xaa, vb2_get_plane_payload(vb, 0));
 #endif
 
-	vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height);
+	vb2_set_plane_payload(vb, 0, icd->sizeimage);
 	if (vb2_plane_vaddr(vb, 0) &&
 	    vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
 		ret = -EINVAL;
@@ -980,6 +984,7 @@
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct mx2_camera_dev *pcdev = ici->priv;
 	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	const struct soc_camera_format_xlate *xlate;
 	unsigned long common_flags;
 	int ret;
 	int bytesperline;
@@ -1024,14 +1029,31 @@
 		return ret;
 	}
 
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	if (!xlate) {
+		dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+		return -EINVAL;
+	}
+
+	if (xlate->code == V4L2_MBUS_FMT_YUYV8_2X8) {
+		csicr1 |= CSICR1_PACK_DIR;
+		csicr1 &= ~CSICR1_SWAP16_EN;
+		dev_dbg(icd->parent, "already yuyv format, don't convert\n");
+	} else if (xlate->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+		csicr1 &= ~CSICR1_PACK_DIR;
+		csicr1 |= CSICR1_SWAP16_EN;
+		dev_dbg(icd->parent, "convert uyvy mbus format into yuyv\n");
+	} else {
+		dev_warn(icd->parent, "mbus format not supported\n");
+		return -EINVAL;
+	}
+
 	if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
 		csicr1 |= CSICR1_REDGE;
 	if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
 		csicr1 |= CSICR1_SOF_POL;
 	if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
 		csicr1 |= CSICR1_HSYNC_POL;
-	if (pcdev->platform_flags & MX2_CAMERA_SWAP16)
-		csicr1 |= CSICR1_SWAP16_EN;
 	if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
 		csicr1 |= CSICR1_EXT_VSYNC;
 	if (pcdev->platform_flags & MX2_CAMERA_CCIR)
@@ -1042,8 +1064,6 @@
 		csicr1 |= CSICR1_GCLK_MODE;
 	if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
 		csicr1 |= CSICR1_INV_DATA;
-	if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB)
-		csicr1 |= CSICR1_PACK_DIR;
 
 	pcdev->csicr1 = csicr1;
 
@@ -1118,7 +1138,8 @@
 		return 0;
 	}
 
-	if (code == V4L2_MBUS_FMT_YUYV8_2X8) {
+	if (code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+	    code == V4L2_MBUS_FMT_UYVY8_2X8) {
 		formats++;
 		if (xlate) {
 			/*
@@ -1134,6 +1155,18 @@
 		}
 	}
 
+	if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
+		formats++;
+		if (xlate) {
+			xlate->host_fmt =
+				soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8);
+			xlate->code	= code;
+			dev_dbg(dev, "Providing host format %s for sensor code %d\n",
+				xlate->host_fmt->name, code);
+			xlate++;
+		}
+	}
+
 	/* Generic pass-trough */
 	formats++;
 	if (xlate) {
@@ -1363,17 +1396,20 @@
 				xlate->host_fmt);
 		if (pix->bytesperline < 0)
 			return pix->bytesperline;
-		pix->sizeimage = pix->height * pix->bytesperline;
+		pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
+						pix->bytesperline, pix->height);
 		/* Check against the CSIRXCNT limit */
 		if (pix->sizeimage > 4 * 0x3ffff) {
 			/* Adjust geometry, preserve aspect ratio */
-			unsigned int new_height = int_sqrt(4 * 0x3ffff *
-					pix->height / pix->bytesperline);
+			unsigned int new_height = int_sqrt(div_u64(0x3ffffULL *
+					4 * pix->height, pix->bytesperline));
 			pix->width = new_height * pix->width / pix->height;
 			pix->height = new_height;
 			pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
 							xlate->host_fmt);
 			BUG_ON(pix->bytesperline < 0);
+			pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
+						pix->bytesperline, pix->height);
 		}
 	}
 
@@ -1752,6 +1788,8 @@
 	pcdev->soc_host.priv		= pcdev;
 	pcdev->soc_host.v4l2_dev.dev	= &pdev->dev;
 	pcdev->soc_host.nr		= pdev->id;
+	if (cpu_is_mx25())
+		pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE;
 
 	pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
 	if (IS_ERR(pcdev->alloc_ctx)) {
diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c
index ba89a74..0bd5815 100644
--- a/drivers/media/video/mx2_emmaprp.c
+++ b/drivers/media/video/mx2_emmaprp.c
@@ -755,7 +755,7 @@
 
 	memset(src_vq, 0, sizeof(*src_vq));
 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-	src_vq->io_modes = VB2_MMAP;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
 	src_vq->drv_priv = ctx;
 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	src_vq->ops = &emmaprp_qops;
@@ -767,7 +767,7 @@
 
 	memset(dst_vq, 0, sizeof(*dst_vq));
 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	dst_vq->io_modes = VB2_MMAP;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
 	dst_vq->drv_priv = ctx;
 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	dst_vq->ops = &emmaprp_qops;
@@ -904,6 +904,10 @@
 	}
 
 	*vfd = emmaprp_videodev;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 	vfd->lock = &pcdev->dev_mutex;
 
 	video_set_drvdata(vfd, pcdev);
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 93c35ef..02d54a0 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -199,8 +199,6 @@
 	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct mx3_camera_dev *mx3_cam = ici->priv;
-	int bytes_per_line;
-	unsigned int height;
 
 	if (!mx3_cam->idmac_channel[0])
 		return -EINVAL;
@@ -208,21 +206,29 @@
 	if (fmt) {
 		const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
 								fmt->fmt.pix.pixelformat);
+		unsigned int bytes_per_line;
+		int ret;
+
 		if (!xlate)
 			return -EINVAL;
-		bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
-							 xlate->host_fmt);
-		height = fmt->fmt.pix.height;
+
+		ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
+					      xlate->host_fmt);
+		if (ret < 0)
+			return ret;
+
+		bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
+
+		ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
+					  fmt->fmt.pix.height);
+		if (ret < 0)
+			return ret;
+
+		sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
 	} else {
 		/* Called from VIDIOC_REQBUFS or in compatibility mode */
-		bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-						icd->current_fmt->host_fmt);
-		height = icd->user_height;
+		sizes[0] = icd->sizeimage;
 	}
-	if (bytes_per_line < 0)
-		return bytes_per_line;
-
-	sizes[0] = bytes_per_line * height;
 
 	alloc_ctxs[0] = mx3_cam->alloc_ctx;
 
@@ -267,14 +273,11 @@
 	struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
 	struct idmac_video_param *video = &ichan->params.video;
 	const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, host_fmt);
 	unsigned long flags;
 	dma_cookie_t cookie;
 	size_t new_size;
 
-	BUG_ON(bytes_per_line <= 0);
-
-	new_size = bytes_per_line * icd->user_height;
+	new_size = icd->sizeimage;
 
 	if (vb2_plane_size(vb, 0) < new_size) {
 		dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n",
@@ -314,9 +317,9 @@
 		 * horizontal parameters in this case are expressed in bytes,
 		 * not in pixels.
 		 */
-		video->out_width	= bytes_per_line;
+		video->out_width	= icd->bytesperline;
 		video->out_height	= icd->user_height;
-		video->out_stride	= bytes_per_line;
+		video->out_stride	= icd->bytesperline;
 	} else {
 		/*
 		 * For IPU known formats the pixel unit will be managed
@@ -642,12 +645,14 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_NONE,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	}, {
 		.fourcc			= V4L2_PIX_FMT_GREY,
 		.name			= "Monochrome 8 bit",
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_NONE,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 };
 
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 2e41317..b520a45 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -31,10 +31,11 @@
 #include <media/saa7115.h>
 #include <linux/module.h>
 
-#include "mxb.h"
 #include "tea6415c.h"
 #include "tea6420.h"
 
+#define MXB_AUDIOS	6
+
 #define I2C_SAA7111A  0x24
 #define	I2C_TDA9840   0x42
 #define	I2C_TEA6415C  0x43
@@ -62,10 +63,14 @@
 enum { TUNER, AUX1, AUX3, AUX3_YC };
 
 static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
-	{ TUNER,	"Tuner",		V4L2_INPUT_TYPE_TUNER,	1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ AUX1,		"AUX1",			V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ AUX3,		"AUX3 Composite",	V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ AUX3_YC,	"AUX3 S-Video",		V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ TUNER,   "Tuner",          V4L2_INPUT_TYPE_TUNER,  0x3f, 0,
+		V4L2_STD_PAL_BG | V4L2_STD_PAL_I, 0, V4L2_IN_CAP_STD },
+	{ AUX1,	   "AUX1",           V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
+		V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ AUX3,	   "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
+		V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ AUX3_YC, "AUX3 S-Video",   V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
+		V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
 };
 
 /* this array holds the information, which port of the saa7146 each
@@ -90,6 +95,36 @@
 	u32 output;
 };
 
+/* these are the available audio sources, which can switched
+   to the line- and cd-output individually */
+static struct v4l2_audio mxb_audios[MXB_AUDIOS] = {
+	    {
+		.index	= 0,
+		.name	= "Tuner",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 1,
+		.name	= "AUX1",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 2,
+		.name	= "AUX2",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 3,
+		.name	= "AUX3",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 4,
+		.name	= "Radio (X9)",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 5,
+		.name	= "CD-ROM (X10)",
+		.capability = V4L2_AUDCAP_STEREO,
+	}
+};
+
 /* These are the necessary input-output-pins for bringing one audio source
    (see above) to the CD-output. Note that gain is set to 0 in this table. */
 static struct mxb_routing TEA6420_cd[MXB_AUDIOS + 1][2] = {
@@ -114,11 +149,6 @@
 	{ { 6, 3 }, { 6, 2 } }	/* Mute */
 };
 
-#define MAXCONTROLS	1
-static struct v4l2_queryctrl mxb_controls[] = {
-	{ V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
-};
-
 struct mxb
 {
 	struct video_device	*video_dev;
@@ -135,6 +165,7 @@
 
 	int	cur_mode;	/* current audio mode (mono, stereo, ...) */
 	int	cur_input;	/* current input */
+	int	cur_audinput;	/* current audio input */
 	int	cur_mute;	/* current mute status */
 	struct v4l2_frequency	cur_freq;	/* current frequency the tuner is tuned to */
 };
@@ -150,16 +181,21 @@
 #define call_all(dev, o, f, args...) \
 	v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)
 
-static inline void tea6420_route_cd(struct mxb *mxb, int idx)
+static void mxb_update_audmode(struct mxb *mxb)
+{
+	struct v4l2_tuner t = {
+		.audmode = mxb->cur_mode,
+	};
+
+	tda9840_call(mxb, tuner, s_tuner, &t);
+}
+
+static inline void tea6420_route(struct mxb *mxb, int idx)
 {
 	v4l2_subdev_call(mxb->tea6420_1, audio, s_routing,
 		TEA6420_cd[idx][0].input, TEA6420_cd[idx][0].output, 0);
 	v4l2_subdev_call(mxb->tea6420_2, audio, s_routing,
 		TEA6420_cd[idx][1].input, TEA6420_cd[idx][1].output, 0);
-}
-
-static inline void tea6420_route_line(struct mxb *mxb, int idx)
-{
 	v4l2_subdev_call(mxb->tea6420_1, audio, s_routing,
 		TEA6420_line[idx][0].input, TEA6420_line[idx][0].output, 0);
 	v4l2_subdev_call(mxb->tea6420_2, audio, s_routing,
@@ -168,16 +204,45 @@
 
 static struct saa7146_extension extension;
 
+static int mxb_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct saa7146_dev *dev = container_of(ctrl->handler,
+				struct saa7146_dev, ctrl_handler);
+	struct mxb *mxb = dev->ext_priv;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		mxb->cur_mute = ctrl->val;
+		/* switch the audio-source */
+		tea6420_route(mxb, ctrl->val ? 6 :
+				video_audio_connect[mxb->cur_input]);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops mxb_ctrl_ops = {
+	.s_ctrl = mxb_s_ctrl,
+};
+
 static int mxb_probe(struct saa7146_dev *dev)
 {
+	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
 	struct mxb *mxb = NULL;
 
+	v4l2_ctrl_new_std(hdl, &mxb_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	if (hdl->error)
+		return hdl->error;
 	mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
 	if (mxb == NULL) {
 		DEB_D("not enough kernel memory\n");
 		return -ENOMEM;
 	}
 
+
 	snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
 
 	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
@@ -214,6 +279,8 @@
 	/* we store the pointer in our private data field */
 	dev->ext_priv = mxb;
 
+	v4l2_ctrl_handler_setup(hdl);
+
 	return 0;
 }
 
@@ -286,6 +353,9 @@
 
 	int i = 0, err = 0;
 
+	/* mute audio on tea6420s */
+	tea6420_route(mxb, 6);
+
 	/* select video mode in saa7111a */
 	saa7111a_call(mxb, core, s_std, std);
 
@@ -306,12 +376,12 @@
 	tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
 
 	/* set a default video standard */
+	/* These two gpio calls set the GPIO pins that control the tda9820 */
+	saa7146_write(dev, GPIO_CTRL, 0x00404050);
+	saa7111a_call(mxb, core, s_gpio, 1);
+	saa7111a_call(mxb, core, s_std, std);
 	tuner_call(mxb, core, s_std, std);
 
-	/* mute audio on tea6420s */
-	tea6420_route_line(mxb, 6);
-	tea6420_route_cd(mxb, 6);
-
 	/* switch to tuner-channel on tea6415c */
 	tea6415c_call(mxb, video, s_routing, 3, 17, 0);
 
@@ -320,9 +390,11 @@
 
 	/* the rest for mxb */
 	mxb->cur_input = 0;
+	mxb->cur_audinput = video_audio_connect[mxb->cur_input];
 	mxb->cur_mute = 1;
 
 	mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
+	mxb_update_audmode(mxb);
 
 	/* check if the saa7740 (aka 'sound arena module') is present
 	   on the mxb. if so, we must initialize it. due to lack of
@@ -385,69 +457,6 @@
 }
 */
 
-static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	int i;
-
-	for (i = MAXCONTROLS - 1; i >= 0; i--) {
-		if (mxb_controls[i].id == qc->id) {
-			*qc = mxb_controls[i];
-			DEB_D("VIDIOC_QUERYCTRL %d\n", qc->id);
-			return 0;
-		}
-	}
-	return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct mxb *mxb = (struct mxb *)dev->ext_priv;
-	int i;
-
-	for (i = MAXCONTROLS - 1; i >= 0; i--) {
-		if (mxb_controls[i].id == vc->id)
-			break;
-	}
-
-	if (i < 0)
-		return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
-
-	if (vc->id == V4L2_CID_AUDIO_MUTE) {
-		vc->value = mxb->cur_mute;
-		DEB_D("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d\n", vc->value);
-		return 0;
-	}
-
-	DEB_EE("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d\n", vc->value);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct mxb *mxb = (struct mxb *)dev->ext_priv;
-	int i = 0;
-
-	for (i = MAXCONTROLS - 1; i >= 0; i--) {
-		if (mxb_controls[i].id == vc->id)
-			break;
-	}
-
-	if (i < 0)
-		return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
-
-	if (vc->id == V4L2_CID_AUDIO_MUTE) {
-		mxb->cur_mute = vc->value;
-		/* switch the audio-source */
-		tea6420_route_line(mxb, vc->value ? 6 :
-				video_audio_connect[mxb->cur_input]);
-		DEB_EE("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d\n", vc->value);
-	}
-	return 0;
-}
-
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
 	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
@@ -519,9 +528,12 @@
 	if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0))
 		pr_err("VIDIOC_S_INPUT: could not address saa7111a\n");
 
+	mxb->cur_audinput = video_audio_connect[input];
 	/* switch the audio-source only if necessary */
 	if (0 == mxb->cur_mute)
-		tea6420_route_line(mxb, video_audio_connect[input]);
+		tea6420_route(mxb, mxb->cur_audinput);
+	if (mxb->cur_audinput == 0)
+		mxb_update_audmode(mxb);
 
 	return 0;
 }
@@ -563,17 +575,20 @@
 	return call_all(dev, tuner, s_tuner, t);
 }
 
+static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+	return call_all(dev, video, querystd, norm);
+}
+
 static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
 {
 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 	struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-	if (mxb->cur_input) {
-		DEB_D("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
-		      mxb->cur_input);
+	if (f->tuner)
 		return -EINVAL;
-	}
-
 	*f = mxb->cur_freq;
 
 	DEB_EE("VIDIOC_G_FREQ: freq:0x%08x\n", mxb->cur_freq.frequency);
@@ -592,17 +607,18 @@
 	if (V4L2_TUNER_ANALOG_TV != f->type)
 		return -EINVAL;
 
-	if (mxb->cur_input) {
-		DEB_D("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",
-		      mxb->cur_input);
-		return -EINVAL;
-	}
-
-	mxb->cur_freq = *f;
 	DEB_EE("VIDIOC_S_FREQUENCY: freq:0x%08x\n", mxb->cur_freq.frequency);
 
 	/* tune in desired frequency */
-	tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
+	tuner_call(mxb, tuner, s_frequency, f);
+	/* let the tuner subdev clamp the frequency to the tuner range */
+	tuner_call(mxb, tuner, g_frequency, f);
+	mxb->cur_freq = *f;
+	if (mxb->cur_audinput == 0)
+		mxb_update_audmode(mxb);
+
+	if (mxb->cur_input)
+		return 0;
 
 	/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
 	spin_lock(&dev->slock);
@@ -612,25 +628,40 @@
 	return 0;
 }
 
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+	if (a->index >= MXB_AUDIOS)
+		return -EINVAL;
+	*a = mxb_audios[a->index];
+	return 0;
+}
+
 static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
 {
 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 	struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-	if (a->index > MXB_INPUTS) {
-		DEB_D("VIDIOC_G_AUDIO %d out of range\n", a->index);
-		return -EINVAL;
-	}
-
-	DEB_EE("VIDIOC_G_AUDIO %d\n", a->index);
-	memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
+	DEB_EE("VIDIOC_G_AUDIO\n");
+	*a = mxb_audios[mxb->cur_audinput];
 	return 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
 {
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
 	DEB_D("VIDIOC_S_AUDIO %d\n", a->index);
-	return 0;
+	if (mxb_inputs[mxb->cur_input].audioset & (1 << a->index)) {
+		if (mxb->cur_audinput != a->index) {
+			mxb->cur_audinput = a->index;
+			tea6420_route(mxb, a->index);
+			if (mxb->cur_audinput == 0)
+				mxb_update_audmode(mxb);
+		}
+		return 0;
+	}
+	return -EINVAL;
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -638,61 +669,32 @@
 {
 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 
-	return call_all(dev, core, g_register, reg);
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (v4l2_chip_match_host(&reg->match)) {
+		reg->val = saa7146_read(dev, reg->reg);
+		reg->size = 4;
+		return 0;
+	}
+	call_all(dev, core, g_register, reg);
+	return 0;
 }
 
 static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
 {
 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (v4l2_chip_match_host(&reg->match)) {
+		saa7146_write(dev, reg->reg, reg->val);
+		reg->size = 4;
+		return 0;
+	}
 	return call_all(dev, core, s_register, reg);
 }
 #endif
 
-static long vidioc_default(struct file *file, void *fh, bool valid_prio,
-							int cmd, void *arg)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct mxb *mxb = (struct mxb *)dev->ext_priv;
-
-	switch (cmd) {
-	case MXB_S_AUDIO_CD:
-	{
-		int i = *(int *)arg;
-
-		if (i < 0 || i >= MXB_AUDIOS) {
-			DEB_D("invalid argument to MXB_S_AUDIO_CD: i:%d\n", i);
-			return -EINVAL;
-		}
-
-		DEB_EE("MXB_S_AUDIO_CD: i:%d\n", i);
-
-		tea6420_route_cd(mxb, i);
-		return 0;
-	}
-	case MXB_S_AUDIO_LINE:
-	{
-		int i = *(int *)arg;
-
-		if (i < 0 || i >= MXB_AUDIOS) {
-			DEB_D("invalid argument to MXB_S_AUDIO_LINE: i:%d\n",
-			      i);
-			return -EINVAL;
-		}
-
-		DEB_EE("MXB_S_AUDIO_LINE: i:%d\n", i);
-		tea6420_route_line(mxb, i);
-		return 0;
-	}
-	default:
-/*
-		DEB2(pr_err("does not handle this ioctl\n"));
-*/
-		return -ENOIOCTLCMD;
-	}
-	return 0;
-}
-
 static struct saa7146_ext_vv vv_data;
 
 /* this function only gets called when the probing was successful */
@@ -709,23 +711,21 @@
 	}
 	mxb = (struct mxb *)dev->ext_priv;
 
-	vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
-	vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
-	vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
-	vv_data.ops.vidioc_enum_input = vidioc_enum_input;
-	vv_data.ops.vidioc_g_input = vidioc_g_input;
-	vv_data.ops.vidioc_s_input = vidioc_s_input;
-	vv_data.ops.vidioc_g_tuner = vidioc_g_tuner;
-	vv_data.ops.vidioc_s_tuner = vidioc_s_tuner;
-	vv_data.ops.vidioc_g_frequency = vidioc_g_frequency;
-	vv_data.ops.vidioc_s_frequency = vidioc_s_frequency;
-	vv_data.ops.vidioc_g_audio = vidioc_g_audio;
-	vv_data.ops.vidioc_s_audio = vidioc_s_audio;
+	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
+	vv_data.vid_ops.vidioc_querystd = vidioc_querystd;
+	vv_data.vid_ops.vidioc_g_tuner = vidioc_g_tuner;
+	vv_data.vid_ops.vidioc_s_tuner = vidioc_s_tuner;
+	vv_data.vid_ops.vidioc_g_frequency = vidioc_g_frequency;
+	vv_data.vid_ops.vidioc_s_frequency = vidioc_s_frequency;
+	vv_data.vid_ops.vidioc_enumaudio = vidioc_enumaudio;
+	vv_data.vid_ops.vidioc_g_audio = vidioc_g_audio;
+	vv_data.vid_ops.vidioc_s_audio = vidioc_s_audio;
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	vv_data.ops.vidioc_g_register = vidioc_g_register;
-	vv_data.ops.vidioc_s_register = vidioc_s_register;
+	vv_data.vid_ops.vidioc_g_register = vidioc_g_register;
+	vv_data.vid_ops.vidioc_s_register = vidioc_s_register;
 #endif
-	vv_data.ops.vidioc_default = vidioc_default;
 	if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
 		ERR("cannot register capture v4l2 device. skipping.\n");
 		saa7146_vv_release(dev);
@@ -752,6 +752,9 @@
 
 	DEB_EE("dev:%p\n", dev);
 
+	/* mute audio on tea6420s */
+	tea6420_route(mxb, 6);
+
 	saa7146_unregister_device(&mxb->video_dev,dev);
 	if (MXB_BOARD_CAN_DO_VBI(dev))
 		saa7146_unregister_device(&mxb->vbi_dev, dev);
@@ -773,20 +776,24 @@
 		v4l2_std_id std = V4L2_STD_PAL_I;
 
 		DEB_D("VIDIOC_S_STD: setting mxb for PAL_I\n");
-		/* set the 7146 gpio register -- I don't know what this does exactly */
+		/* These two gpio calls set the GPIO pins that control the tda9820 */
 		saa7146_write(dev, GPIO_CTRL, 0x00404050);
-		/* unset the 7111 gpio register -- I don't know what this does exactly */
 		saa7111a_call(mxb, core, s_gpio, 0);
-		tuner_call(mxb, core, s_std, std);
+		saa7111a_call(mxb, core, s_std, std);
+		if (mxb->cur_input == 0)
+			tuner_call(mxb, core, s_std, std);
 	} else {
 		v4l2_std_id std = V4L2_STD_PAL_BG;
 
+		if (mxb->cur_input)
+			std = standard->id;
 		DEB_D("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM\n");
-		/* set the 7146 gpio register -- I don't know what this does exactly */
+		/* These two gpio calls set the GPIO pins that control the tda9820 */
 		saa7146_write(dev, GPIO_CTRL, 0x00404050);
-		/* set the 7111 gpio register -- I don't know what this does exactly */
 		saa7111a_call(mxb, core, s_gpio, 1);
-		tuner_call(mxb, core, s_std, std);
+		saa7111a_call(mxb, core, s_std, std);
+		if (mxb->cur_input == 0)
+			tuner_call(mxb, core, s_std, std);
 	}
 	return 0;
 }
@@ -836,14 +843,14 @@
 
 static struct saa7146_ext_vv vv_data = {
 	.inputs		= MXB_INPUTS,
-	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
+	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_AUDIO,
 	.stds		= &standard[0],
 	.num_stds	= sizeof(standard)/sizeof(struct saa7146_standard),
 	.std_callback	= &std_callback,
 };
 
 static struct saa7146_extension extension = {
-	.name		= MXB_IDENTIFIER,
+	.name		= "Multimedia eXtension Board",
 	.flags		= SAA7146_USE_I2C_IRQ,
 
 	.pci_tbl	= &pci_tbl[0],
diff --git a/drivers/media/video/mxb.h b/drivers/media/video/mxb.h
deleted file mode 100644
index 400a57b..0000000
--- a/drivers/media/video/mxb.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __MXB__
-#define __MXB__
-
-#define BASE_VIDIOC_MXB 10
-
-#define MXB_S_AUDIO_CD		_IOW  ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+0, int)
-#define MXB_S_AUDIO_LINE	_IOW  ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+1, int)
-
-#define MXB_IDENTIFIER "Multimedia eXtension Board"
-
-#define MXB_AUDIOS	6
-
-/* these are the available audio sources, which can switched
-   to the line- and cd-output individually */
-static struct v4l2_audio mxb_audios[MXB_AUDIOS] = {
-	    {
-		.index	= 0,
-		.name	= "Tuner",
-		.capability = V4L2_AUDCAP_STEREO,
-	} , {
-		.index	= 1,
-		.name	= "AUX1",
-		.capability = V4L2_AUDCAP_STEREO,
-	} , {
-		.index	= 2,
-		.name	= "AUX2",
-		.capability = V4L2_AUDCAP_STEREO,
-	} , {
-		.index	= 3,
-		.name	= "AUX3",
-		.capability = V4L2_AUDCAP_STEREO,
-	} , {
-		.index	= 4,
-		.name	= "Radio (X9)",
-		.capability = V4L2_AUDCAP_STEREO,
-	} , {
-		.index	= 5,
-		.name	= "CD-ROM (X10)",
-		.capability = V4L2_AUDCAP_STEREO,
-	}
-};
-#endif
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c
index c20f5ec..c7e4114 100644
--- a/drivers/media/video/omap1_camera.c
+++ b/drivers/media/video/omap1_camera.c
@@ -206,15 +206,10 @@
 		unsigned int *size)
 {
 	struct soc_camera_device *icd = vq->priv_data;
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-			icd->current_fmt->host_fmt);
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct omap1_cam_dev *pcdev = ici->priv;
 
-	if (bytes_per_line < 0)
-		return bytes_per_line;
-
-	*size = bytes_per_line * icd->user_height;
+	*size = icd->sizeimage;
 
 	if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode))
 		*count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode);
@@ -256,15 +251,10 @@
 {
 	struct soc_camera_device *icd = vq->priv_data;
 	struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb);
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-			icd->current_fmt->host_fmt);
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct omap1_cam_dev *pcdev = ici->priv;
 	int ret;
 
-	if (bytes_per_line < 0)
-		return bytes_per_line;
-
 	WARN_ON(!list_empty(&vb->queue));
 
 	BUG_ON(NULL == icd->current_fmt);
@@ -281,7 +271,7 @@
 		vb->state  = VIDEOBUF_NEEDS_INIT;
 	}
 
-	vb->size = bytes_per_line * vb->height;
+	vb->size = icd->sizeimage;
 
 	if (vb->baddr && vb->bsize < vb->size) {
 		ret = -EINVAL;
@@ -999,6 +989,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_VYUY8_2X8,
@@ -1008,6 +999,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_YUYV8_2X8,
@@ -1017,6 +1009,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_YVYU8_2X8,
@@ -1026,6 +1019,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
@@ -1035,6 +1029,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
@@ -1044,6 +1039,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_RGB565_2X8_BE,
@@ -1053,6 +1049,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_RGB565_2X8_LE,
@@ -1062,6 +1059,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 },
 };
diff --git a/drivers/media/video/omap24xxcam-dma.c b/drivers/media/video/omap24xxcam-dma.c
index 3ea38a8..b5ae170 100644
--- a/drivers/media/video/omap24xxcam-dma.c
+++ b/drivers/media/video/omap24xxcam-dma.c
@@ -38,7 +38,7 @@
  */
 
 /* Ack all interrupt on CSR and IRQSTATUS_L0 */
-static void omap24xxcam_dmahw_ack_all(unsigned long base)
+static void omap24xxcam_dmahw_ack_all(void __iomem *base)
 {
 	u32 csr;
 	int i;
@@ -52,7 +52,7 @@
 }
 
 /* Ack dmach on CSR and IRQSTATUS_L0 */
-static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach)
+static u32 omap24xxcam_dmahw_ack_ch(void __iomem *base, int dmach)
 {
 	u32 csr;
 
@@ -65,12 +65,12 @@
 	return csr;
 }
 
-static int omap24xxcam_dmahw_running(unsigned long base, int dmach)
+static int omap24xxcam_dmahw_running(void __iomem *base, int dmach)
 {
 	return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
 }
 
-static void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach,
+static void omap24xxcam_dmahw_transfer_setup(void __iomem *base, int dmach,
 					     dma_addr_t start, u32 len)
 {
 	omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
@@ -112,7 +112,7 @@
 			    | CAMDMA_CICR_DROP_IE);
 }
 
-static void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach)
+static void omap24xxcam_dmahw_transfer_start(void __iomem *base, int dmach)
 {
 	omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
 			    CAMDMA_CCR_SEL_SRC_DST_SYNC
@@ -124,7 +124,7 @@
 			    | CAMDMA_CCR_SYNCHRO_CAMERA);
 }
 
-static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach,
+static void omap24xxcam_dmahw_transfer_chain(void __iomem *base, int dmach,
 					     int free_dmach)
 {
 	int prev_dmach, ch;
@@ -160,7 +160,7 @@
  * controller may not be idle after this routine completes, because
  * the completion routines might start new transfers.
  */
-static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach)
+static void omap24xxcam_dmahw_abort_ch(void __iomem *base, int dmach)
 {
 	/* mask all interrupts from this channel */
 	omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
@@ -171,7 +171,7 @@
 	omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
 }
 
-static void omap24xxcam_dmahw_init(unsigned long base)
+static void omap24xxcam_dmahw_init(void __iomem *base)
 {
 	omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
 			    CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
@@ -362,7 +362,7 @@
 }
 
 static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
-				 unsigned long base)
+				 void __iomem *base)
 {
 	int ch;
 
@@ -577,7 +577,7 @@
 }
 
 void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
-			    unsigned long base,
+			    void __iomem *base,
 			    void (*reset_callback)(unsigned long data),
 			    unsigned long reset_callback_data)
 {
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index 7d38641..e5015b0 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -1776,8 +1776,7 @@
 	cam->mmio_size = resource_size(mem);
 
 	/* map the region */
-	cam->mmio_base = (unsigned long)
-		ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+	cam->mmio_base = ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
 	if (!cam->mmio_base) {
 		dev_err(cam->dev, "cannot map camera register I/O region\n");
 		goto err;
diff --git a/drivers/media/video/omap24xxcam.h b/drivers/media/video/omap24xxcam.h
index 2ce67f5..d59727a 100644
--- a/drivers/media/video/omap24xxcam.h
+++ b/drivers/media/video/omap24xxcam.h
@@ -429,7 +429,7 @@
 struct omap24xxcam_dma {
 	spinlock_t lock;	/* Lock for the whole structure. */
 
-	unsigned long base;	/* base address for dma controller */
+	void __iomem *base;	/* base address for dma controller */
 
 	/* While dma_stop!=0, an attempt to start a new DMA transfer will
 	 * fail.
@@ -491,7 +491,7 @@
 
 	/*** hardware resources ***/
 	unsigned int irq;
-	unsigned long mmio_base;
+	void __iomem *mmio_base;
 	unsigned long mmio_base_phys;
 	unsigned long mmio_size;
 
@@ -544,22 +544,22 @@
  *
  */
 
-static inline u32 omap24xxcam_reg_in(unsigned long base, u32 offset)
+static inline u32 omap24xxcam_reg_in(u32 __iomem *base, u32 offset)
 {
 	return readl(base + offset);
 }
 
-static inline u32 omap24xxcam_reg_out(unsigned long base, u32 offset,
+static inline u32 omap24xxcam_reg_out(u32 __iomem *base, u32 offset,
 					  u32 val)
 {
 	writel(val, base + offset);
 	return val;
 }
 
-static inline u32 omap24xxcam_reg_merge(unsigned long base, u32 offset,
+static inline u32 omap24xxcam_reg_merge(u32 __iomem *base, u32 offset,
 					    u32 val, u32 mask)
 {
-	u32 addr = base + offset;
+	u32 __iomem *addr = base + offset;
 	u32 new_val = (readl(addr) & ~mask) | (val & mask);
 
 	writel(new_val, addr);
@@ -585,7 +585,7 @@
 			    int len, sgdma_callback_t callback, void *arg);
 void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma);
 void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
-			    unsigned long base,
+			    void __iomem *base,
 			    void (*reset_callback)(unsigned long data),
 			    unsigned long reset_callback_data);
 void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma);
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
index 12d5f92..1c34763 100644
--- a/drivers/media/video/omap3isp/isp.c
+++ b/drivers/media/video/omap3isp/isp.c
@@ -329,19 +329,6 @@
 	isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
 }
 
-/**
- * isp_set_pixel_clock - Configures the ISP pixel clock
- * @isp: OMAP3 ISP device
- * @pixelclk: Average pixel clock in Hz
- *
- * Set the average pixel clock required by the sensor. The ISP will use the
- * lowest possible memory bandwidth settings compatible with the clock.
- **/
-static void isp_set_pixel_clock(struct isp_device *isp, unsigned int pixelclk)
-{
-	isp->isp_ccdc.vpcfg.pixelclk = pixelclk;
-}
-
 void omap3isp_hist_dma_done(struct isp_device *isp)
 {
 	if (omap3isp_ccdc_busy(&isp->isp_ccdc) ||
@@ -739,6 +726,17 @@
 	unsigned long flags;
 	int ret;
 
+	/* If the preview engine crashed it might not respond to read/write
+	 * operations on the L4 bus. This would result in a bus fault and a
+	 * kernel oops. Refuse to start streaming in that case. This check must
+	 * be performed before the loop below to avoid starting entities if the
+	 * pipeline won't start anyway (those entities would then likely fail to
+	 * stop, making the problem worse).
+	 */
+	if ((pipe->entities & isp->crashed) &
+	    (1U << isp->isp_prev.subdev.entity.id))
+		return -EIO;
+
 	spin_lock_irqsave(&pipe->lock, flags);
 	pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
 	spin_unlock_irqrestore(&pipe->lock, flags);
@@ -774,14 +772,6 @@
 		}
 	}
 
-	/* Frame number propagation. In continuous streaming mode the number
-	 * is incremented in the frame start ISR. In mem-to-mem mode
-	 * singleshot is used and frame start IRQs are not available.
-	 * Thus we have to increment the number here.
-	 */
-	if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT)
-		atomic_inc(&pipe->frame_number);
-
 	return 0;
 }
 
@@ -879,13 +869,15 @@
 
 		if (ret) {
 			dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
+			/* If the entity failed to stopped, assume it has
+			 * crashed. Mark it as such, the ISP will be reset when
+			 * applications will release it.
+			 */
+			isp->crashed |= 1U << subdev->entity.id;
 			failure = -ETIMEDOUT;
 		}
 	}
 
-	if (failure < 0)
-		isp->needs_reset = true;
-
 	return failure;
 }
 
@@ -1069,6 +1061,7 @@
 		udelay(1);
 	}
 
+	isp->crashed = 0;
 	return 0;
 }
 
@@ -1495,11 +1488,13 @@
 	BUG_ON(isp->ref_count == 0);
 	if (--isp->ref_count == 0) {
 		isp_disable_interrupts(isp);
-		isp_save_ctx(isp);
-		if (isp->needs_reset) {
+		if (isp->domain)
+			isp_save_ctx(isp);
+		/* Reset the ISP if an entity has failed to stop. This is the
+		 * only way to recover from such conditions.
+		 */
+		if (isp->crashed)
 			isp_reset(isp);
-			isp->needs_reset = false;
-		}
 		isp_disable_clocks(isp);
 	}
 	mutex_unlock(&isp->isp_mutex);
@@ -1970,7 +1965,7 @@
  *
  * Always returns 0.
  */
-static int isp_remove(struct platform_device *pdev)
+static int __devexit isp_remove(struct platform_device *pdev)
 {
 	struct isp_device *isp = platform_get_drvdata(pdev);
 	int i;
@@ -1981,6 +1976,7 @@
 	omap3isp_get(isp);
 	iommu_detach_device(isp->domain, &pdev->dev);
 	iommu_domain_free(isp->domain);
+	isp->domain = NULL;
 	omap3isp_put(isp);
 
 	free_irq(isp->irq_num, isp);
@@ -2050,7 +2046,7 @@
  *   -EINVAL if couldn't install ISR,
  *   or clk_get return error value.
  */
-static int isp_probe(struct platform_device *pdev)
+static int __devinit isp_probe(struct platform_device *pdev)
 {
 	struct isp_platform_data *pdata = pdev->dev.platform_data;
 	struct isp_device *isp;
@@ -2068,7 +2064,6 @@
 
 	isp->autoidle = autoidle;
 	isp->platform_cb.set_xclk = isp_set_xclk;
-	isp->platform_cb.set_pixel_clock = isp_set_pixel_clock;
 
 	mutex_init(&isp->isp_mutex);
 	spin_lock_init(&isp->stat_lock);
@@ -2218,7 +2213,7 @@
 
 static struct platform_driver omap3isp_driver = {
 	.probe = isp_probe,
-	.remove = isp_remove,
+	.remove = __devexit_p(isp_remove),
 	.id_table = omap3isp_id_table,
 	.driver = {
 		.owner = THIS_MODULE,
diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h
index d96603e..fc7af3e 100644
--- a/drivers/media/video/omap3isp/isp.h
+++ b/drivers/media/video/omap3isp/isp.h
@@ -129,7 +129,6 @@
 	int (*csiphy_config)(struct isp_csiphy *phy,
 			     struct isp_csiphy_dphy_cfg *dphy,
 			     struct isp_csiphy_lanes_cfg *lanes);
-	void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
 };
 
 /*
@@ -145,6 +144,7 @@
  * @raw_dmamask: Raw DMA mask
  * @stat_lock: Spinlock for handling statistics
  * @isp_mutex: Mutex for serializing requests to ISP.
+ * @crashed: Bitmask of crashed entities (indexed by entity ID)
  * @has_context: Context has been saved at least once and can be restored.
  * @ref_count: Reference count for handling multiple ISP requests.
  * @cam_ick: Pointer to camera interface clock structure.
@@ -184,7 +184,7 @@
 	/* ISP Obj */
 	spinlock_t stat_lock;	/* common lock for statistic drivers */
 	struct mutex isp_mutex;	/* For handling ref_count field */
-	bool needs_reset;
+	u32 crashed;
 	int has_context;
 	int ref_count;
 	unsigned int autoidle;
@@ -237,10 +237,6 @@
 			       const struct isp_parallel_platform_data *pdata,
 			       unsigned int shift);
 
-#define ISP_XCLK_NONE			0
-#define ISP_XCLK_A			1
-#define ISP_XCLK_B			2
-
 struct isp_device *omap3isp_get(struct isp_device *isp);
 void omap3isp_put(struct isp_device *isp);
 
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
index eaabc27..7e32331 100644
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -38,6 +38,9 @@
 #include "ispreg.h"
 #include "ispccdc.h"
 
+#define CCDC_MIN_WIDTH		32
+#define CCDC_MIN_HEIGHT		32
+
 static struct v4l2_mbus_framefmt *
 __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
 		  unsigned int pad, enum v4l2_subdev_format_whence which);
@@ -836,8 +839,8 @@
 
 	if (pipe->input)
 		div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
-	else if (ccdc->vpcfg.pixelclk)
-		div = l3_ick / ccdc->vpcfg.pixelclk;
+	else if (pipe->external_rate)
+		div = l3_ick / pipe->external_rate;
 
 	div = clamp(div, 2U, max_div);
 	fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
@@ -1118,6 +1121,7 @@
 	struct isp_parallel_platform_data *pdata = NULL;
 	struct v4l2_subdev *sensor;
 	struct v4l2_mbus_framefmt *format;
+	const struct v4l2_rect *crop;
 	const struct isp_format_info *fmt_info;
 	struct v4l2_subdev_format fmt_src;
 	unsigned int depth_out;
@@ -1211,14 +1215,14 @@
 		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
 
 	/* CCDC_PAD_SOURCE_OF */
-	format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
+	crop = &ccdc->crop;
 
-	isp_reg_writel(isp, (0 << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
-		       ((format->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
+	isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
+		       ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
 		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
-	isp_reg_writel(isp, 0 << ISPCCDC_VERT_START_SLV0_SHIFT,
+	isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT,
 		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
-	isp_reg_writel(isp, (format->height - 1)
+	isp_reg_writel(isp, (crop->height - 1)
 			<< ISPCCDC_VERT_LINES_NLV_SHIFT,
 		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
 
@@ -1410,6 +1414,9 @@
 	struct video_device *vdev = ccdc->subdev.devnode;
 	struct v4l2_event event;
 
+	/* Frame number propagation */
+	atomic_inc(&pipe->frame_number);
+
 	memset(&event, 0, sizeof(event));
 	event.type = V4L2_EVENT_FRAME_SYNC;
 	event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number);
@@ -1703,7 +1710,7 @@
 	if (sub->id != 0)
 		return -EINVAL;
 
-	return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS);
+	return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS, NULL);
 }
 
 static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
@@ -1790,6 +1797,16 @@
 		return &ccdc->formats[pad];
 }
 
+static struct v4l2_rect *
+__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+		enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF);
+	else
+		return &ccdc->crop;
+}
+
 /*
  * ccdc_try_format - Try video format on a pad
  * @ccdc: ISP CCDC device
@@ -1806,6 +1823,7 @@
 	const struct isp_format_info *info;
 	unsigned int width = fmt->width;
 	unsigned int height = fmt->height;
+	struct v4l2_rect *crop;
 	unsigned int i;
 
 	switch (pad) {
@@ -1831,14 +1849,10 @@
 		format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
 		memcpy(fmt, format, sizeof(*fmt));
 
-		/* The data formatter truncates the number of horizontal output
-		 * pixels to a multiple of 16. To avoid clipping data, allow
-		 * callers to request an output size bigger than the input size
-		 * up to the nearest multiple of 16.
-		 */
-		fmt->width = clamp_t(u32, width, 32, fmt->width + 15);
-		fmt->width &= ~15;
-		fmt->height = clamp_t(u32, height, 32, fmt->height);
+		/* Hardcode the output size to the crop rectangle size. */
+		crop = __ccdc_get_crop(ccdc, fh, which);
+		fmt->width = crop->width;
+		fmt->height = crop->height;
 		break;
 
 	case CCDC_PAD_SOURCE_VP:
@@ -1866,6 +1880,49 @@
 }
 
 /*
+ * ccdc_try_crop - Validate a crop rectangle
+ * @ccdc: ISP CCDC device
+ * @sink: format on the sink pad
+ * @crop: crop rectangle to be validated
+ */
+static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
+			  const struct v4l2_mbus_framefmt *sink,
+			  struct v4l2_rect *crop)
+{
+	const struct isp_format_info *info;
+	unsigned int max_width;
+
+	/* For Bayer formats, restrict left/top and width/height to even values
+	 * to keep the Bayer pattern.
+	 */
+	info = omap3isp_video_format_info(sink->code);
+	if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+		crop->left &= ~1;
+		crop->top &= ~1;
+	}
+
+	crop->left = clamp_t(u32, crop->left, 0, sink->width - CCDC_MIN_WIDTH);
+	crop->top = clamp_t(u32, crop->top, 0, sink->height - CCDC_MIN_HEIGHT);
+
+	/* The data formatter truncates the number of horizontal output pixels
+	 * to a multiple of 16. To avoid clipping data, allow callers to request
+	 * an output size bigger than the input size up to the nearest multiple
+	 * of 16.
+	 */
+	max_width = (sink->width - crop->left + 15) & ~15;
+	crop->width = clamp_t(u32, crop->width, CCDC_MIN_WIDTH, max_width)
+		    & ~15;
+	crop->height = clamp_t(u32, crop->height, CCDC_MIN_HEIGHT,
+			       sink->height - crop->top);
+
+	/* Odd width/height values don't make sense for Bayer formats. */
+	if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+		crop->width &= ~1;
+		crop->height &= ~1;
+	}
+}
+
+/*
  * ccdc_enum_mbus_code - Handle pixel format enumeration
  * @sd     : pointer to v4l2 subdev structure
  * @fh : V4L2 subdev file handle
@@ -1937,6 +1994,93 @@
 }
 
 /*
+ * ccdc_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the output formatter
+ * source pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_selection *sel)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (sel->pad != CCDC_PAD_SOURCE_OF)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = INT_MAX;
+		sel->r.height = INT_MAX;
+
+		format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+		ccdc_try_crop(ccdc, format, &sel->r);
+		break;
+
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+		sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * ccdc_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the output
+ * formatter source pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_selection *sel)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+	    sel->pad != CCDC_PAD_SOURCE_OF)
+		return -EINVAL;
+
+	/* The crop rectangle can't be changed while streaming. */
+	if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
+		return -EBUSY;
+
+	/* Modifying the crop rectangle always changes the format on the source
+	 * pad. If the KEEP_CONFIG flag is set, just return the current crop
+	 * rectangle.
+	 */
+	if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) {
+		sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+		return 0;
+	}
+
+	format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+	ccdc_try_crop(ccdc, format, &sel->r);
+	*__ccdc_get_crop(ccdc, fh, sel->which) = sel->r;
+
+	/* Update the source format. */
+	format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which);
+	ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which);
+
+	return 0;
+}
+
+/*
  * ccdc_get_format - Retrieve the video format on a pad
  * @sd : ISP CCDC V4L2 subdevice
  * @fh : V4L2 subdev file handle
@@ -1973,6 +2117,7 @@
 {
 	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
 	struct v4l2_mbus_framefmt *format;
+	struct v4l2_rect *crop;
 
 	format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
 	if (format == NULL)
@@ -1983,6 +2128,16 @@
 
 	/* Propagate the format from sink to source */
 	if (fmt->pad == CCDC_PAD_SINK) {
+		/* Reset the crop rectangle. */
+		crop = __ccdc_get_crop(ccdc, fh, fmt->which);
+		crop->left = 0;
+		crop->top = 0;
+		crop->width = fmt->format.width;
+		crop->height = fmt->format.height;
+
+		ccdc_try_crop(ccdc, &fmt->format, crop);
+
+		/* Update the source formats. */
 		format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
 					   fmt->which);
 		*format = fmt->format;
@@ -2000,6 +2155,69 @@
 }
 
 /*
+ * Decide whether desired output pixel code can be obtained with
+ * the lane shifter by shifting the input pixel code.
+ * @in: input pixelcode to shifter
+ * @out: output pixelcode from shifter
+ * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
+ *
+ * return true if the combination is possible
+ * return false otherwise
+ */
+static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in,
+			      enum v4l2_mbus_pixelcode out,
+			      unsigned int additional_shift)
+{
+	const struct isp_format_info *in_info, *out_info;
+
+	if (in == out)
+		return true;
+
+	in_info = omap3isp_video_format_info(in);
+	out_info = omap3isp_video_format_info(out);
+
+	if ((in_info->flavor == 0) || (out_info->flavor == 0))
+		return false;
+
+	if (in_info->flavor != out_info->flavor)
+		return false;
+
+	return in_info->bpp - out_info->bpp + additional_shift <= 6;
+}
+
+static int ccdc_link_validate(struct v4l2_subdev *sd,
+			      struct media_link *link,
+			      struct v4l2_subdev_format *source_fmt,
+			      struct v4l2_subdev_format *sink_fmt)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	unsigned long parallel_shift;
+
+	/* Check if the two ends match */
+	if (source_fmt->format.width != sink_fmt->format.width ||
+	    source_fmt->format.height != sink_fmt->format.height)
+		return -EPIPE;
+
+	/* We've got a parallel sensor here. */
+	if (ccdc->input == CCDC_INPUT_PARALLEL) {
+		struct isp_parallel_platform_data *pdata =
+			&((struct isp_v4l2_subdevs_group *)
+			  media_entity_to_v4l2_subdev(link->source->entity)
+			  ->host_priv)->bus.parallel;
+		parallel_shift = pdata->data_lane_shift * 2;
+	} else {
+		parallel_shift = 0;
+	}
+
+	/* Lane shifter may be used to drop bits on CCDC sink pad */
+	if (!ccdc_is_shiftable(source_fmt->format.code,
+			       sink_fmt->format.code, parallel_shift))
+		return -EPIPE;
+
+	return 0;
+}
+
+/*
  * ccdc_init_formats - Initialize formats on all pads
  * @sd: ISP CCDC V4L2 subdevice
  * @fh: V4L2 subdev file handle
@@ -2041,6 +2259,9 @@
 	.enum_frame_size = ccdc_enum_frame_size,
 	.get_fmt = ccdc_get_format,
 	.set_fmt = ccdc_set_format,
+	.get_selection = ccdc_get_selection,
+	.set_selection = ccdc_set_selection,
+	.link_validate = ccdc_link_validate,
 };
 
 /* V4L2 subdev operations */
@@ -2150,6 +2371,7 @@
 /* media operations */
 static const struct media_entity_operations ccdc_media_ops = {
 	.link_setup = ccdc_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
 };
 
 void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)
@@ -2276,8 +2498,6 @@
 	ccdc->clamp.oblen = 0;
 	ccdc->clamp.dcsubval = 0;
 
-	ccdc->vpcfg.pixelclk = 0;
-
 	ccdc->update = OMAP3ISP_CCDC_BLCLAMP;
 	ccdc_apply_controls(ccdc);
 
diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h
index 6d0264b..890f6b3 100644
--- a/drivers/media/video/omap3isp/ispccdc.h
+++ b/drivers/media/video/omap3isp/ispccdc.h
@@ -80,14 +80,6 @@
 	u8 bt_r656_en;
 };
 
-/*
- * struct ispccdc_vp - Structure for Video Port parameters
- * @pixelclk: Input pixel clock in Hz
- */
-struct ispccdc_vp {
-	unsigned int pixelclk;
-};
-
 enum ispccdc_lsc_state {
 	LSC_STATE_STOPPED = 0,
 	LSC_STATE_STOPPING = 1,
@@ -147,6 +139,7 @@
  * @subdev: V4L2 subdevice
  * @pads: Sink and source media entity pads
  * @formats: Active video formats
+ * @crop: Active crop rectangle on the OF source pad
  * @input: Active input
  * @output: Active outputs
  * @video_out: Output video node
@@ -161,7 +154,6 @@
  * @update: Bitmask of controls to update during the next interrupt
  * @shadow_update: Controls update in progress by userspace
  * @syncif: Interface synchronization configuration
- * @vpcfg: Video port configuration
  * @underrun: A buffer underrun occurred and a new buffer has been queued
  * @state: Streaming state
  * @lock: Serializes shadow_update with interrupt handler
@@ -173,6 +165,7 @@
 	struct v4l2_subdev subdev;
 	struct media_pad pads[CCDC_PADS_NUM];
 	struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM];
+	struct v4l2_rect crop;
 
 	enum ccdc_input_entity input;
 	unsigned int output;
@@ -190,7 +183,6 @@
 	unsigned int shadow_update;
 
 	struct ispccdc_syncif syncif;
-	struct ispccdc_vp vpcfg;
 
 	unsigned int underrun:1;
 	enum isp_pipeline_stream_state state;
diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c
index 70ddbf3..85f0de8 100644
--- a/drivers/media/video/omap3isp/ispccp2.c
+++ b/drivers/media/video/omap3isp/ispccp2.c
@@ -161,7 +161,6 @@
 static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
 {
 	struct isp_device *isp = to_isp_device(ccp2);
-	struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
 	int i;
 
 	if (enable && ccp2->vdds_csib)
@@ -178,19 +177,6 @@
 			ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN,
 			enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0);
 
-	/* For frame count propagation */
-	if (pipe->do_propagation) {
-		/* We may want the Frame Start IRQ from LC0 */
-		if (enable)
-			isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2,
-				    ISPCCP2_LC01_IRQENABLE,
-				    ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
-		else
-			isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2,
-				    ISPCCP2_LC01_IRQENABLE,
-				    ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
-	}
-
 	if (!enable && ccp2->vdds_csib)
 		regulator_disable(ccp2->vdds_csib);
 }
@@ -350,7 +336,6 @@
 	      ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
 	      ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ |
 	      ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ |
-	      ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ |
 	      ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ |
 	      ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ;
 
@@ -613,14 +598,6 @@
 	if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping))
 		return;
 
-	/* Frame number propagation */
-	if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) {
-		struct isp_pipeline *pipe =
-			to_isp_pipeline(&ccp2->subdev.entity);
-		if (pipe->do_propagation)
-			atomic_inc(&pipe->frame_number);
-	}
-
 	/* Handle queued buffers on frame end interrupts */
 	if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ)
 		ccp2_isr_buffer(ccp2);
@@ -1021,6 +998,7 @@
 /* media operations */
 static const struct media_entity_operations ccp2_media_ops = {
 	.link_setup = ccp2_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
 };
 
 /*
diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c
index fcb5168..a172436 100644
--- a/drivers/media/video/omap3isp/ispcsi2.c
+++ b/drivers/media/video/omap3isp/ispcsi2.c
@@ -378,21 +378,17 @@
 static void csi2_irq_ctx_set(struct isp_device *isp,
 			     struct isp_csi2_device *csi2, int enable)
 {
-	u32 reg = ISPCSI2_CTX_IRQSTATUS_FE_IRQ;
 	int i;
 
-	if (csi2->use_fs_irq)
-		reg |= ISPCSI2_CTX_IRQSTATUS_FS_IRQ;
-
 	for (i = 0; i < 8; i++) {
-		isp_reg_writel(isp, reg, csi2->regs1,
+		isp_reg_writel(isp, ISPCSI2_CTX_IRQSTATUS_FE_IRQ, csi2->regs1,
 			       ISPCSI2_CTX_IRQSTATUS(i));
 		if (enable)
 			isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
-				    reg);
+				    ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
 		else
 			isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
-				    reg);
+				    ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
 	}
 }
 
@@ -690,14 +686,6 @@
 	status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
 	isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
 
-	/* Propagate frame number */
-	if (status & ISPCSI2_CTX_IRQSTATUS_FS_IRQ) {
-		struct isp_pipeline *pipe =
-				     to_isp_pipeline(&csi2->subdev.entity);
-		if (pipe->do_propagation)
-			atomic_inc(&pipe->frame_number);
-	}
-
 	if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ))
 		return;
 
@@ -1047,14 +1035,12 @@
 {
 	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
 	struct isp_device *isp = csi2->isp;
-	struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
 	struct isp_video *video_out = &csi2->video_out;
 
 	switch (enable) {
 	case ISP_PIPELINE_STREAM_CONTINUOUS:
 		if (omap3isp_csiphy_acquire(csi2->phy) < 0)
 			return -ENODEV;
-		csi2->use_fs_irq = pipe->do_propagation;
 		if (csi2->output & CSI2_OUTPUT_MEMORY)
 			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
 		csi2_configure(csi2);
@@ -1181,6 +1167,7 @@
 /* media operations */
 static const struct media_entity_operations csi2_media_ops = {
 	.link_setup = csi2_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
 };
 
 void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2)
diff --git a/drivers/media/video/omap3isp/ispcsi2.h b/drivers/media/video/omap3isp/ispcsi2.h
index 885ad79..c57729b 100644
--- a/drivers/media/video/omap3isp/ispcsi2.h
+++ b/drivers/media/video/omap3isp/ispcsi2.h
@@ -145,7 +145,6 @@
 	u32 output; /* output to CCDC, memory or both? */
 	bool dpcm_decompress;
 	unsigned int frame_skip;
-	bool use_fs_irq;
 
 	struct isp_csiphy *phy;
 	struct isp_csi2_ctx_cfg contexts[ISP_CSI2_MAX_CTX_NUM + 1];
diff --git a/drivers/media/video/omap3isp/ispcsiphy.c b/drivers/media/video/omap3isp/ispcsiphy.c
index 5be37ce..348f67e 100644
--- a/drivers/media/video/omap3isp/ispcsiphy.c
+++ b/drivers/media/video/omap3isp/ispcsiphy.c
@@ -186,7 +186,9 @@
 	if (rval < 0)
 		goto done;
 
-	omap3isp_csi2_reset(phy->csi2);
+	rval = omap3isp_csi2_reset(phy->csi2);
+	if (rval < 0)
+		goto done;
 
 	csiphy_dphy_config(phy);
 	csiphy_lanes_config(phy);
diff --git a/drivers/media/video/omap3isp/ispcsiphy.h b/drivers/media/video/omap3isp/ispcsiphy.h
index 9596dc6..e93a661 100644
--- a/drivers/media/video/omap3isp/ispcsiphy.h
+++ b/drivers/media/video/omap3isp/ispcsiphy.h
@@ -27,22 +27,11 @@
 #ifndef OMAP3_ISP_CSI_PHY_H
 #define OMAP3_ISP_CSI_PHY_H
 
+#include <media/omap3isp.h>
+
 struct isp_csi2_device;
 struct regulator;
 
-struct csiphy_lane {
-	u8 pos;
-	u8 pol;
-};
-
-#define ISP_CSIPHY2_NUM_DATA_LANES	2
-#define ISP_CSIPHY1_NUM_DATA_LANES	1
-
-struct isp_csiphy_lanes_cfg {
-	struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
-	struct csiphy_lane clk;
-};
-
 struct isp_csiphy_dphy_cfg {
 	u8 ths_term;
 	u8 ths_settle;
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c
index 6d0fb2c..8a4935e 100644
--- a/drivers/media/video/omap3isp/isppreview.c
+++ b/drivers/media/video/omap3isp/isppreview.c
@@ -441,23 +441,6 @@
 }
 
 /*
- * preview_enable_cfa - Enable/Disable the CFA Interpolation.
- * @enable: 1 - Enables the CFA.
- */
-static void
-preview_enable_cfa(struct isp_prev_device *prev, u8 enable)
-{
-	struct isp_device *isp = to_isp_device(prev);
-
-	if (enable)
-		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-			    ISPPRV_PCR_CFAEN);
-	else
-		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-			    ISPPRV_PCR_CFAEN);
-}
-
-/*
  * preview_enable_gammabypass - Enables/Disables the GammaByPass
  * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
  *          0 - Goes through Gamma Correction. input and output is 10bit.
@@ -608,12 +591,12 @@
 }
 
 /*
- * Configures the RGB-YCbYCr conversion matrix
+ * Configures the color space conversion (RGB toYCbYCr) matrix
  * @prev_csc: Structure containing the RGB to YCbYCr matrix and the
  *            YCbCr offset.
  */
 static void
-preview_config_rgb_to_ycbcr(struct isp_prev_device *prev, const void *prev_csc)
+preview_config_csc(struct isp_prev_device *prev, const void *prev_csc)
 {
 	struct isp_device *isp = to_isp_device(prev);
 	const struct omap3isp_prev_csc *csc = prev_csc;
@@ -649,12 +632,18 @@
 static void
 preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
 {
-	struct prev_params *params = &prev->params;
+	struct prev_params *params;
+	unsigned long flags;
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	params = (prev->params.active & OMAP3ISP_PREV_CONTRAST)
+	       ? &prev->params.params[0] : &prev->params.params[1];
 
 	if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
 		params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
-		prev->update |= PREV_CONTRAST;
+		params->update |= OMAP3ISP_PREV_CONTRAST;
 	}
+	spin_unlock_irqrestore(&prev->params.lock, flags);
 }
 
 /*
@@ -681,12 +670,18 @@
 static void
 preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
 {
-	struct prev_params *params = &prev->params;
+	struct prev_params *params;
+	unsigned long flags;
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	params = (prev->params.active & OMAP3ISP_PREV_BRIGHTNESS)
+	       ? &prev->params.params[0] : &prev->params.params[1];
 
 	if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
 		params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
-		prev->update |= PREV_BRIGHTNESS;
+		params->update |= OMAP3ISP_PREV_BRIGHTNESS;
 	}
+	spin_unlock_irqrestore(&prev->params.lock, flags);
 }
 
 /*
@@ -721,159 +716,188 @@
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
 }
 
+static u32
+preview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow)
+{
+	u32 active = prev->params.active;
+
+	if (shadow) {
+		/* Mark all shadow parameters we are going to touch as busy. */
+		prev->params.params[0].busy |= ~active & update;
+		prev->params.params[1].busy |= active & update;
+	} else {
+		/* Mark all active parameters we are going to touch as busy. */
+		update = (prev->params.params[0].update & active)
+		       | (prev->params.params[1].update & ~active);
+
+		prev->params.params[0].busy |= active & update;
+		prev->params.params[1].busy |= ~active & update;
+	}
+
+	return update;
+}
+
+static void
+preview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow)
+{
+	u32 active = prev->params.active;
+
+	if (shadow) {
+		/* Set the update flag for shadow parameters that have been
+		 * updated and clear the busy flag for all shadow parameters.
+		 */
+		prev->params.params[0].update |= (~active & update);
+		prev->params.params[1].update |= (active & update);
+		prev->params.params[0].busy &= active;
+		prev->params.params[1].busy &= ~active;
+	} else {
+		/* Clear the update flag for active parameters that have been
+		 * applied and the busy flag for all active parameters.
+		 */
+		prev->params.params[0].update &= ~(active & update);
+		prev->params.params[1].update &= ~(~active & update);
+		prev->params.params[0].busy &= ~active;
+		prev->params.params[1].busy &= active;
+	}
+}
+
+static void preview_params_switch(struct isp_prev_device *prev)
+{
+	u32 to_switch;
+
+	/* Switch active parameters with updated shadow parameters when the
+	 * shadow parameter has been updated and neither the active not the
+	 * shadow parameter is busy.
+	 */
+	to_switch = (prev->params.params[0].update & ~prev->params.active)
+		  | (prev->params.params[1].update & prev->params.active);
+	to_switch &= ~(prev->params.params[0].busy |
+		       prev->params.params[1].busy);
+	if (to_switch == 0)
+		return;
+
+	prev->params.active ^= to_switch;
+
+	/* Remove the update flag for the shadow copy of parameters we have
+	 * switched.
+	 */
+	prev->params.params[0].update &= ~(~prev->params.active & to_switch);
+	prev->params.params[1].update &= ~(prev->params.active & to_switch);
+}
+
 /* preview parameters update structure */
 struct preview_update {
-	int cfg_bit;
-	int feature_bit;
 	void (*config)(struct isp_prev_device *, const void *);
 	void (*enable)(struct isp_prev_device *, u8);
+	unsigned int param_offset;
+	unsigned int param_size;
+	unsigned int config_offset;
+	bool skip;
 };
 
-static struct preview_update update_attrs[] = {
-	{OMAP3ISP_PREV_LUMAENH, PREV_LUMA_ENHANCE,
+/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
+static const struct preview_update update_attrs[] = {
+	/* OMAP3ISP_PREV_LUMAENH */ {
 		preview_config_luma_enhancement,
-		preview_enable_luma_enhancement},
-	{OMAP3ISP_PREV_INVALAW, PREV_INVERSE_ALAW,
+		preview_enable_luma_enhancement,
+		offsetof(struct prev_params, luma),
+		FIELD_SIZEOF(struct prev_params, luma),
+		offsetof(struct omap3isp_prev_update_config, luma),
+	}, /* OMAP3ISP_PREV_INVALAW */ {
 		NULL,
-		preview_enable_invalaw},
-	{OMAP3ISP_PREV_HRZ_MED, PREV_HORZ_MEDIAN_FILTER,
+		preview_enable_invalaw,
+	}, /* OMAP3ISP_PREV_HRZ_MED */ {
 		preview_config_hmed,
-		preview_enable_hmed},
-	{OMAP3ISP_PREV_CFA, PREV_CFA,
+		preview_enable_hmed,
+		offsetof(struct prev_params, hmed),
+		FIELD_SIZEOF(struct prev_params, hmed),
+		offsetof(struct omap3isp_prev_update_config, hmed),
+	}, /* OMAP3ISP_PREV_CFA */ {
 		preview_config_cfa,
-		preview_enable_cfa},
-	{OMAP3ISP_PREV_CHROMA_SUPP, PREV_CHROMA_SUPPRESS,
+		NULL,
+		offsetof(struct prev_params, cfa),
+		FIELD_SIZEOF(struct prev_params, cfa),
+		offsetof(struct omap3isp_prev_update_config, cfa),
+	}, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
 		preview_config_chroma_suppression,
-		preview_enable_chroma_suppression},
-	{OMAP3ISP_PREV_WB, PREV_WB,
+		preview_enable_chroma_suppression,
+		offsetof(struct prev_params, csup),
+		FIELD_SIZEOF(struct prev_params, csup),
+		offsetof(struct omap3isp_prev_update_config, csup),
+	}, /* OMAP3ISP_PREV_WB */ {
 		preview_config_whitebalance,
-		NULL},
-	{OMAP3ISP_PREV_BLKADJ, PREV_BLKADJ,
+		NULL,
+		offsetof(struct prev_params, wbal),
+		FIELD_SIZEOF(struct prev_params, wbal),
+		offsetof(struct omap3isp_prev_update_config, wbal),
+	}, /* OMAP3ISP_PREV_BLKADJ */ {
 		preview_config_blkadj,
-		NULL},
-	{OMAP3ISP_PREV_RGB2RGB, PREV_RGB2RGB,
+		NULL,
+		offsetof(struct prev_params, blkadj),
+		FIELD_SIZEOF(struct prev_params, blkadj),
+		offsetof(struct omap3isp_prev_update_config, blkadj),
+	}, /* OMAP3ISP_PREV_RGB2RGB */ {
 		preview_config_rgb_blending,
-		NULL},
-	{OMAP3ISP_PREV_COLOR_CONV, PREV_COLOR_CONV,
-		preview_config_rgb_to_ycbcr,
-		NULL},
-	{OMAP3ISP_PREV_YC_LIMIT, PREV_YCLIMITS,
+		NULL,
+		offsetof(struct prev_params, rgb2rgb),
+		FIELD_SIZEOF(struct prev_params, rgb2rgb),
+		offsetof(struct omap3isp_prev_update_config, rgb2rgb),
+	}, /* OMAP3ISP_PREV_COLOR_CONV */ {
+		preview_config_csc,
+		NULL,
+		offsetof(struct prev_params, csc),
+		FIELD_SIZEOF(struct prev_params, csc),
+		offsetof(struct omap3isp_prev_update_config, csc),
+	}, /* OMAP3ISP_PREV_YC_LIMIT */ {
 		preview_config_yc_range,
-		NULL},
-	{OMAP3ISP_PREV_DEFECT_COR, PREV_DEFECT_COR,
+		NULL,
+		offsetof(struct prev_params, yclimit),
+		FIELD_SIZEOF(struct prev_params, yclimit),
+		offsetof(struct omap3isp_prev_update_config, yclimit),
+	}, /* OMAP3ISP_PREV_DEFECT_COR */ {
 		preview_config_dcor,
-		preview_enable_dcor},
-	{OMAP3ISP_PREV_GAMMABYPASS, PREV_GAMMA_BYPASS,
+		preview_enable_dcor,
+		offsetof(struct prev_params, dcor),
+		FIELD_SIZEOF(struct prev_params, dcor),
+		offsetof(struct omap3isp_prev_update_config, dcor),
+	}, /* OMAP3ISP_PREV_GAMMABYPASS */ {
 		NULL,
-		preview_enable_gammabypass},
-	{OMAP3ISP_PREV_DRK_FRM_CAPTURE, PREV_DARK_FRAME_CAPTURE,
+		preview_enable_gammabypass,
+	}, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
 		NULL,
-		preview_enable_drkframe_capture},
-	{OMAP3ISP_PREV_DRK_FRM_SUBTRACT, PREV_DARK_FRAME_SUBTRACT,
+		preview_enable_drkframe_capture,
+	}, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
 		NULL,
-		preview_enable_drkframe},
-	{OMAP3ISP_PREV_LENS_SHADING, PREV_LENS_SHADING,
+		preview_enable_drkframe,
+	}, /* OMAP3ISP_PREV_LENS_SHADING */ {
 		preview_config_drkf_shadcomp,
-		preview_enable_drkframe},
-	{OMAP3ISP_PREV_NF, PREV_NOISE_FILTER,
+		preview_enable_drkframe,
+	}, /* OMAP3ISP_PREV_NF */ {
 		preview_config_noisefilter,
-		preview_enable_noisefilter},
-	{OMAP3ISP_PREV_GAMMA, PREV_GAMMA,
+		preview_enable_noisefilter,
+		offsetof(struct prev_params, nf),
+		FIELD_SIZEOF(struct prev_params, nf),
+		offsetof(struct omap3isp_prev_update_config, nf),
+	}, /* OMAP3ISP_PREV_GAMMA */ {
 		preview_config_gammacorrn,
-		NULL},
-	{-1, PREV_CONTRAST,
+		NULL,
+		offsetof(struct prev_params, gamma),
+		FIELD_SIZEOF(struct prev_params, gamma),
+		offsetof(struct omap3isp_prev_update_config, gamma),
+	}, /* OMAP3ISP_PREV_CONTRAST */ {
 		preview_config_contrast,
-		NULL},
-	{-1, PREV_BRIGHTNESS,
+		NULL,
+		offsetof(struct prev_params, contrast),
+		0, true,
+	}, /* OMAP3ISP_PREV_BRIGHTNESS */ {
 		preview_config_brightness,
-		NULL},
+		NULL,
+		offsetof(struct prev_params, brightness),
+		0, true,
+	},
 };
 
 /*
- * __preview_get_ptrs - helper function which return pointers to members
- *                         of params and config structures.
- * @params - pointer to preview_params structure.
- * @param - return pointer to appropriate structure field.
- * @configs - pointer to update config structure.
- * @config - return pointer to appropriate structure field.
- * @bit - for which feature to return pointers.
- * Return size of corresponding prev_params member
- */
-static u32
-__preview_get_ptrs(struct prev_params *params, void **param,
-		   struct omap3isp_prev_update_config *configs,
-		   void __user **config, u32 bit)
-{
-#define CHKARG(cfgs, cfg, field)				\
-	if (cfgs && cfg) {					\
-		*(cfg) = (cfgs)->field;				\
-	}
-
-	switch (bit) {
-	case PREV_HORZ_MEDIAN_FILTER:
-		*param = &params->hmed;
-		CHKARG(configs, config, hmed)
-		return sizeof(params->hmed);
-	case PREV_NOISE_FILTER:
-		*param = &params->nf;
-		CHKARG(configs, config, nf)
-		return sizeof(params->nf);
-		break;
-	case PREV_CFA:
-		*param = &params->cfa;
-		CHKARG(configs, config, cfa)
-		return sizeof(params->cfa);
-	case PREV_LUMA_ENHANCE:
-		*param = &params->luma;
-		CHKARG(configs, config, luma)
-		return sizeof(params->luma);
-	case PREV_CHROMA_SUPPRESS:
-		*param = &params->csup;
-		CHKARG(configs, config, csup)
-		return sizeof(params->csup);
-	case PREV_DEFECT_COR:
-		*param = &params->dcor;
-		CHKARG(configs, config, dcor)
-		return sizeof(params->dcor);
-	case PREV_BLKADJ:
-		*param = &params->blk_adj;
-		CHKARG(configs, config, blkadj)
-		return sizeof(params->blk_adj);
-	case PREV_YCLIMITS:
-		*param = &params->yclimit;
-		CHKARG(configs, config, yclimit)
-		return sizeof(params->yclimit);
-	case PREV_RGB2RGB:
-		*param = &params->rgb2rgb;
-		CHKARG(configs, config, rgb2rgb)
-		return sizeof(params->rgb2rgb);
-	case PREV_COLOR_CONV:
-		*param = &params->rgb2ycbcr;
-		CHKARG(configs, config, csc)
-		return sizeof(params->rgb2ycbcr);
-	case PREV_WB:
-		*param = &params->wbal;
-		CHKARG(configs, config, wbal)
-		return sizeof(params->wbal);
-	case PREV_GAMMA:
-		*param = &params->gamma;
-		CHKARG(configs, config, gamma)
-		return sizeof(params->gamma);
-	case PREV_CONTRAST:
-		*param = &params->contrast;
-		return 0;
-	case PREV_BRIGHTNESS:
-		*param = &params->brightness;
-		return 0;
-	default:
-		*param = NULL;
-		*config = NULL;
-		break;
-	}
-	return 0;
-}
-
-/*
  * preview_config - Copy and update local structure with userspace preview
  *                  configuration.
  * @prev: ISP preview engine
@@ -885,84 +909,103 @@
 static int preview_config(struct isp_prev_device *prev,
 			  struct omap3isp_prev_update_config *cfg)
 {
-	struct prev_params *params;
-	struct preview_update *attr;
-	int i, bit, rval = 0;
+	unsigned long flags;
+	unsigned int i;
+	int rval = 0;
+	u32 update;
+	u32 active;
 
-	params = &prev->params;
+	if (cfg->update == 0)
+		return 0;
 
-	if (prev->state != ISP_PIPELINE_STREAM_STOPPED) {
-		unsigned long flags;
+	/* Mark the shadow parameters we're going to update as busy. */
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_lock(prev, cfg->update, true);
+	active = prev->params.active;
+	spin_unlock_irqrestore(&prev->params.lock, flags);
 
-		spin_lock_irqsave(&prev->lock, flags);
-		prev->shadow_update = 1;
-		spin_unlock_irqrestore(&prev->lock, flags);
-	}
+	update = 0;
 
 	for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
-		attr = &update_attrs[i];
-		bit = 0;
+		const struct preview_update *attr = &update_attrs[i];
+		struct prev_params *params;
+		unsigned int bit = 1 << i;
 
-		if (!(cfg->update & attr->cfg_bit))
+		if (attr->skip || !(cfg->update & bit))
 			continue;
 
-		bit = cfg->flag & attr->cfg_bit;
-		if (bit) {
-			void *to = NULL, __user *from = NULL;
-			unsigned long sz = 0;
+		params = &prev->params.params[!!(active & bit)];
 
-			sz = __preview_get_ptrs(params, &to, cfg, &from,
-						   bit);
-			if (to && from && sz) {
-				if (copy_from_user(to, from, sz)) {
+		if (cfg->flag & bit) {
+			void __user *from = *(void * __user *)
+				((void *)cfg + attr->config_offset);
+			void *to = (void *)params + attr->param_offset;
+			size_t size = attr->param_size;
+
+			if (to && from && size) {
+				if (copy_from_user(to, from, size)) {
 					rval = -EFAULT;
 					break;
 				}
 			}
-			params->features |= attr->feature_bit;
+			params->features |= bit;
 		} else {
-			params->features &= ~attr->feature_bit;
+			params->features &= ~bit;
 		}
 
-		prev->update |= attr->feature_bit;
+		update |= bit;
 	}
 
-	prev->shadow_update = 0;
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_unlock(prev, update, true);
+	preview_params_switch(prev);
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+
 	return rval;
 }
 
 /*
  * preview_setup_hw - Setup preview registers and/or internal memory
  * @prev: pointer to preview private structure
+ * @update: Bitmask of parameters to setup
+ * @active: Bitmask of parameters active in set 0
  * Note: can be called from interrupt context
  * Return none
  */
-static void preview_setup_hw(struct isp_prev_device *prev)
+static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
+			     u32 active)
 {
-	struct prev_params *params = &prev->params;
-	struct preview_update *attr;
-	int i, bit;
-	void *param_ptr;
+	unsigned int i;
+	u32 features;
+
+	if (update == 0)
+		return;
+
+	features = (prev->params.params[0].features & active)
+		 | (prev->params.params[1].features & ~active);
 
 	for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
-		attr = &update_attrs[i];
+		const struct preview_update *attr = &update_attrs[i];
+		struct prev_params *params;
+		unsigned int bit = 1 << i;
+		void *param_ptr;
 
-		if (!(prev->update & attr->feature_bit))
+		if (!(update & bit))
 			continue;
-		bit = params->features & attr->feature_bit;
-		if (bit) {
+
+		params = &prev->params.params[!(active & bit)];
+
+		if (params->features & bit) {
 			if (attr->config) {
-				__preview_get_ptrs(params, &param_ptr, NULL,
-						      NULL, bit);
+				param_ptr = (void *)params + attr->param_offset;
 				attr->config(prev, param_ptr);
 			}
 			if (attr->enable)
 				attr->enable(prev, 1);
-		} else
+		} else {
 			if (attr->enable)
 				attr->enable(prev, 0);
-
-		prev->update &= ~attr->feature_bit;
+		}
 	}
 }
 
@@ -1000,13 +1043,17 @@
 static void preview_config_averager(struct isp_prev_device *prev, u8 average)
 {
 	struct isp_device *isp = to_isp_device(prev);
+	struct prev_params *params;
 	int reg = 0;
 
-	if (prev->params.cfa.format == OMAP3ISP_CFAFMT_BAYER)
+	params = (prev->params.active & OMAP3ISP_PREV_CFA)
+	       ? &prev->params.params[0] : &prev->params.params[1];
+
+	if (params->cfa.format == OMAP3ISP_CFAFMT_BAYER)
 		reg = ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
 		      ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
 		      average;
-	else if (prev->params.cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON)
+	else if (params->cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON)
 		reg = ISPPRV_AVE_EVENDIST_3 << ISPPRV_AVE_EVENDIST_SHIFT |
 		      ISPPRV_AVE_ODDDIST_3 << ISPPRV_AVE_ODDDIST_SHIFT |
 		      average;
@@ -1014,6 +1061,27 @@
 }
 
 /*
+ * preview_config_input_format - Configure the input format
+ * @prev: The preview engine
+ * @format: Format on the preview engine sink pad
+ *
+ * Enable CFA interpolation for Bayer formats and disable it for greyscale
+ * formats.
+ */
+static void preview_config_input_format(struct isp_prev_device *prev,
+					const struct v4l2_mbus_framefmt *format)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (format->code != V4L2_MBUS_FMT_Y10_1X10)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_CFAEN);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_CFAEN);
+}
+
+/*
  * preview_config_input_size - Configure the input frame size
  *
  * The preview engine crops several rows and columns internally depending on
@@ -1024,32 +1092,37 @@
  *
  * See the explanation at the PREV_MARGIN_* definitions for more details.
  */
-static void preview_config_input_size(struct isp_prev_device *prev)
+static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
 {
+	const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
 	struct isp_device *isp = to_isp_device(prev);
-	struct prev_params *params = &prev->params;
 	unsigned int sph = prev->crop.left;
 	unsigned int eph = prev->crop.left + prev->crop.width - 1;
 	unsigned int slv = prev->crop.top;
 	unsigned int elv = prev->crop.top + prev->crop.height - 1;
+	u32 features;
 
-	if (params->features & PREV_CFA) {
+	if (format->code == V4L2_MBUS_FMT_Y10_1X10) {
 		sph -= 2;
 		eph += 2;
 		slv -= 2;
 		elv += 2;
 	}
-	if (params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER)) {
+
+	features = (prev->params.params[0].features & active)
+		 | (prev->params.params[1].features & ~active);
+
+	if (features & (OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF)) {
 		sph -= 2;
 		eph += 2;
 		slv -= 2;
 		elv += 2;
 	}
-	if (params->features & PREV_HORZ_MEDIAN_FILTER) {
+	if (features & OMAP3ISP_PREV_HRZ_MED) {
 		sph -= 2;
 		eph += 2;
 	}
-	if (params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))
+	if (features & (OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH))
 		sph -= 2;
 
 	isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
@@ -1184,8 +1257,16 @@
  */
 void omap3isp_preview_restore_context(struct isp_device *isp)
 {
-	isp->isp_prev.update = PREV_FEATURES_END - 1;
-	preview_setup_hw(&isp->isp_prev);
+	struct isp_prev_device *prev = &isp->isp_prev;
+	const u32 update = OMAP3ISP_PREV_FEATURES_END - 1;
+
+	prev->params.params[0].update = prev->params.active & update;
+	prev->params.params[1].update = ~prev->params.active & update;
+
+	preview_setup_hw(prev, update, prev->params.active);
+
+	prev->params.params[0].update = 0;
+	prev->params.params[1].update = 0;
 }
 
 /*
@@ -1244,12 +1325,21 @@
 /*
  * preview_init_params - init image processing parameters.
  * @prev: pointer to previewer private structure
- * return none
  */
 static void preview_init_params(struct isp_prev_device *prev)
 {
-	struct prev_params *params = &prev->params;
-	int i = 0;
+	struct prev_params *params;
+	unsigned int i;
+
+	spin_lock_init(&prev->params.lock);
+
+	prev->params.active = ~0;
+	prev->params.params[0].busy = 0;
+	prev->params.params[0].update = OMAP3ISP_PREV_FEATURES_END - 1;
+	prev->params.params[1].busy = 0;
+	prev->params.params[1].update = 0;
+
+	params = &prev->params.params[0];
 
 	/* Init values */
 	params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
@@ -1277,22 +1367,22 @@
 	params->wbal.coef1 = FLR_WBAL_COEF;
 	params->wbal.coef2 = FLR_WBAL_COEF;
 	params->wbal.coef3 = FLR_WBAL_COEF;
-	params->blk_adj.red = FLR_BLKADJ_RED;
-	params->blk_adj.green = FLR_BLKADJ_GREEN;
-	params->blk_adj.blue = FLR_BLKADJ_BLUE;
+	params->blkadj.red = FLR_BLKADJ_RED;
+	params->blkadj.green = FLR_BLKADJ_GREEN;
+	params->blkadj.blue = FLR_BLKADJ_BLUE;
 	params->rgb2rgb = flr_rgb2rgb;
-	params->rgb2ycbcr = flr_prev_csc;
+	params->csc = flr_prev_csc;
 	params->yclimit.minC = ISPPRV_YC_MIN;
 	params->yclimit.maxC = ISPPRV_YC_MAX;
 	params->yclimit.minY = ISPPRV_YC_MIN;
 	params->yclimit.maxY = ISPPRV_YC_MAX;
 
-	params->features = PREV_CFA | PREV_DEFECT_COR | PREV_NOISE_FILTER
-			 | PREV_GAMMA | PREV_BLKADJ | PREV_YCLIMITS
-			 | PREV_RGB2RGB | PREV_COLOR_CONV | PREV_WB
-			 | PREV_BRIGHTNESS | PREV_CONTRAST;
-
-	prev->update = PREV_FEATURES_END - 1;
+	params->features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR
+			 | OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA
+			 | OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT
+			 | OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV
+			 | OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS
+			 | OMAP3ISP_PREV_CONTRAST;
 }
 
 /*
@@ -1321,8 +1411,17 @@
 {
 	struct isp_device *isp = to_isp_device(prev);
 	struct v4l2_mbus_framefmt *format;
+	unsigned long flags;
+	u32 update;
+	u32 active;
 
-	preview_setup_hw(prev);
+	spin_lock_irqsave(&prev->params.lock, flags);
+	/* Mark all active parameters we are going to touch as busy. */
+	update = preview_params_lock(prev, 0, false);
+	active = prev->params.active;
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+
+	preview_setup_hw(prev, update, active);
 
 	if (prev->output & PREVIEW_OUTPUT_MEMORY)
 		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
@@ -1343,7 +1442,8 @@
 
 	preview_adjust_bandwidth(prev);
 
-	preview_config_input_size(prev);
+	preview_config_input_format(prev, format);
+	preview_config_input_size(prev, active);
 
 	if (prev->input == PREVIEW_INPUT_CCDC)
 		preview_config_inlineoffset(prev, 0);
@@ -1360,6 +1460,10 @@
 
 	preview_config_averager(prev, 0);
 	preview_config_ycpos(prev, format->code);
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_unlock(prev, update, false);
+	spin_unlock_irqrestore(&prev->params.lock, flags);
 }
 
 /* -----------------------------------------------------------------------------
@@ -1448,25 +1552,30 @@
 void omap3isp_preview_isr(struct isp_prev_device *prev)
 {
 	unsigned long flags;
+	u32 update;
+	u32 active;
 
 	if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
 		return;
 
-	spin_lock_irqsave(&prev->lock, flags);
-	if (prev->shadow_update)
-		goto done;
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_switch(prev);
+	update = preview_params_lock(prev, 0, false);
+	active = prev->params.active;
+	spin_unlock_irqrestore(&prev->params.lock, flags);
 
-	preview_setup_hw(prev);
-	preview_config_input_size(prev);
-
-done:
-	spin_unlock_irqrestore(&prev->lock, flags);
+	preview_setup_hw(prev, update, active);
+	preview_config_input_size(prev, active);
 
 	if (prev->input == PREVIEW_INPUT_MEMORY ||
 	    prev->output & PREVIEW_OUTPUT_MEMORY)
 		preview_isr_buffer(prev);
 	else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
 		preview_enable_oneshot(prev);
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_unlock(prev, update, false);
+	spin_unlock_irqrestore(&prev->params.lock, flags);
 }
 
 /* -----------------------------------------------------------------------------
@@ -1552,7 +1661,6 @@
 	struct isp_video *video_out = &prev->video_out;
 	struct isp_device *isp = to_isp_device(prev);
 	struct device *dev = to_device(prev);
-	unsigned long flags;
 
 	if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
 		if (enable == ISP_PIPELINE_STREAM_STOPPED)
@@ -1589,11 +1697,9 @@
 		if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
 					      &prev->stopping))
 			dev_dbg(dev, "%s: stop timeout.\n", sd->name);
-		spin_lock_irqsave(&prev->lock, flags);
 		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
 		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
 		omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
-		spin_unlock_irqrestore(&prev->lock, flags);
 		isp_video_dmaqueue_flags_clr(video_out);
 		break;
 	}
@@ -1624,6 +1730,7 @@
 
 /* previewer format descriptions */
 static const unsigned int preview_input_fmts[] = {
+	V4L2_MBUS_FMT_Y10_1X10,
 	V4L2_MBUS_FMT_SGRBG10_1X10,
 	V4L2_MBUS_FMT_SRGGB10_1X10,
 	V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -1822,55 +1929,89 @@
 }
 
 /*
- * preview_get_crop - Retrieve the crop rectangle on a pad
+ * preview_get_selection - Retrieve a selection rectangle on a pad
  * @sd: ISP preview V4L2 subdevice
  * @fh: V4L2 subdev file handle
- * @crop: crop rectangle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the sink pad.
  *
  * Return 0 on success or a negative error code otherwise.
  */
-static int preview_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
-			    struct v4l2_subdev_crop *crop)
-{
-	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
-
-	/* Cropping is only supported on the sink pad. */
-	if (crop->pad != PREV_PAD_SINK)
-		return -EINVAL;
-
-	crop->rect = *__preview_get_crop(prev, fh, crop->which);
-	return 0;
-}
-
-/*
- * preview_set_crop - Retrieve the crop rectangle on a pad
- * @sd: ISP preview V4L2 subdevice
- * @fh: V4L2 subdev file handle
- * @crop: crop rectangle
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static int preview_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
-			    struct v4l2_subdev_crop *crop)
+static int preview_get_selection(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
 {
 	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
 	struct v4l2_mbus_framefmt *format;
 
-	/* Cropping is only supported on the sink pad. */
-	if (crop->pad != PREV_PAD_SINK)
+	if (sel->pad != PREV_PAD_SINK)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = INT_MAX;
+		sel->r.height = INT_MAX;
+
+		format = __preview_get_format(prev, fh, PREV_PAD_SINK,
+					      sel->which);
+		preview_try_crop(prev, format, &sel->r);
+		break;
+
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+		sel->r = *__preview_get_crop(prev, fh, sel->which);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * preview_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP preview V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the sink pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int preview_set_selection(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
+{
+	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+	    sel->pad != PREV_PAD_SINK)
 		return -EINVAL;
 
 	/* The crop rectangle can't be changed while streaming. */
 	if (prev->state != ISP_PIPELINE_STREAM_STOPPED)
 		return -EBUSY;
 
-	format = __preview_get_format(prev, fh, PREV_PAD_SINK, crop->which);
-	preview_try_crop(prev, format, &crop->rect);
-	*__preview_get_crop(prev, fh, crop->which) = crop->rect;
+	/* Modifying the crop rectangle always changes the format on the source
+	 * pad. If the KEEP_CONFIG flag is set, just return the current crop
+	 * rectangle.
+	 */
+	if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) {
+		sel->r = *__preview_get_crop(prev, fh, sel->which);
+		return 0;
+	}
+
+	format = __preview_get_format(prev, fh, PREV_PAD_SINK, sel->which);
+	preview_try_crop(prev, format, &sel->r);
+	*__preview_get_crop(prev, fh, sel->which) = sel->r;
 
 	/* Update the source format. */
-	format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, crop->which);
-	preview_try_format(prev, fh, PREV_PAD_SOURCE, format, crop->which);
+	format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, sel->which);
+	preview_try_format(prev, fh, PREV_PAD_SOURCE, format, sel->which);
 
 	return 0;
 }
@@ -1979,8 +2120,8 @@
 	.enum_frame_size = preview_enum_frame_size,
 	.get_fmt = preview_get_format,
 	.set_fmt = preview_set_format,
-	.get_crop = preview_get_crop,
-	.set_crop = preview_set_crop,
+	.get_selection = preview_get_selection,
+	.set_selection = preview_set_selection,
 };
 
 /* subdev operations */
@@ -2076,6 +2217,7 @@
 /* media operations */
 static const struct media_entity_operations preview_media_ops = {
 	.link_setup = preview_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
 };
 
 void omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
@@ -2201,7 +2343,7 @@
 }
 
 /*
- * isp_preview_init - Previewer initialization.
+ * omap3isp_preview_init - Previewer initialization.
  * @dev : Pointer to ISP device
  * return -ENOMEM or zero on success
  */
@@ -2209,8 +2351,8 @@
 {
 	struct isp_prev_device *prev = &isp->isp_prev;
 
-	spin_lock_init(&prev->lock);
 	init_waitqueue_head(&prev->wait);
+
 	preview_init_params(prev);
 
 	return preview_init_entities(prev);
diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h
index 0968660..6663ab6 100644
--- a/drivers/media/video/omap3isp/isppreview.h
+++ b/drivers/media/video/omap3isp/isppreview.h
@@ -45,29 +45,10 @@
 #define ISPPRV_CONTRAST_HIGH		0xFF
 #define ISPPRV_CONTRAST_UNITS		0x1
 
-/* Features list */
-#define PREV_LUMA_ENHANCE		OMAP3ISP_PREV_LUMAENH
-#define PREV_INVERSE_ALAW		OMAP3ISP_PREV_INVALAW
-#define PREV_HORZ_MEDIAN_FILTER		OMAP3ISP_PREV_HRZ_MED
-#define PREV_CFA			OMAP3ISP_PREV_CFA
-#define PREV_CHROMA_SUPPRESS		OMAP3ISP_PREV_CHROMA_SUPP
-#define PREV_WB				OMAP3ISP_PREV_WB
-#define PREV_BLKADJ			OMAP3ISP_PREV_BLKADJ
-#define PREV_RGB2RGB			OMAP3ISP_PREV_RGB2RGB
-#define PREV_COLOR_CONV			OMAP3ISP_PREV_COLOR_CONV
-#define PREV_YCLIMITS			OMAP3ISP_PREV_YC_LIMIT
-#define PREV_DEFECT_COR			OMAP3ISP_PREV_DEFECT_COR
-#define PREV_GAMMA_BYPASS		OMAP3ISP_PREV_GAMMABYPASS
-#define PREV_DARK_FRAME_CAPTURE		OMAP3ISP_PREV_DRK_FRM_CAPTURE
-#define PREV_DARK_FRAME_SUBTRACT	OMAP3ISP_PREV_DRK_FRM_SUBTRACT
-#define PREV_LENS_SHADING		OMAP3ISP_PREV_LENS_SHADING
-#define PREV_NOISE_FILTER		OMAP3ISP_PREV_NF
-#define PREV_GAMMA			OMAP3ISP_PREV_GAMMA
-
-#define PREV_CONTRAST			(1 << 17)
-#define PREV_BRIGHTNESS			(1 << 18)
-#define PREV_AVERAGER			(1 << 19)
-#define PREV_FEATURES_END		(1 << 20)
+/* Additional features not listed in linux/omap3isp.h */
+#define OMAP3ISP_PREV_CONTRAST		(1 << 17)
+#define OMAP3ISP_PREV_BRIGHTNESS	(1 << 18)
+#define OMAP3ISP_PREV_FEATURES_END	(1 << 19)
 
 enum preview_input_entity {
 	PREVIEW_INPUT_NONE,
@@ -88,6 +69,8 @@
 
 /*
  * struct prev_params - Structure for all configuration
+ * @busy: Bitmask of busy parameters (being updated or used)
+ * @update: Bitmask of the parameters to be updated
  * @features: Set of features enabled.
  * @cfa: CFA coefficients.
  * @csup: Chroma suppression coefficients.
@@ -96,15 +79,17 @@
  * @dcor: Noise filter coefficients.
  * @gamma: Gamma coefficients.
  * @wbal: White Balance parameters.
- * @blk_adj: Black adjustment parameters.
+ * @blkadj: Black adjustment parameters.
  * @rgb2rgb: RGB blending parameters.
- * @rgb2ycbcr: RGB to ycbcr parameters.
+ * @csc: Color space conversion (RGB to YCbCr) parameters.
  * @hmed: Horizontal median filter.
  * @yclimit: YC limits parameters.
  * @contrast: Contrast.
  * @brightness: Brightness.
  */
 struct prev_params {
+	u32 busy;
+	u32 update;
 	u32 features;
 	struct omap3isp_prev_cfa cfa;
 	struct omap3isp_prev_csup csup;
@@ -113,35 +98,15 @@
 	struct omap3isp_prev_dcor dcor;
 	struct omap3isp_prev_gtables gamma;
 	struct omap3isp_prev_wbal wbal;
-	struct omap3isp_prev_blkadj blk_adj;
+	struct omap3isp_prev_blkadj blkadj;
 	struct omap3isp_prev_rgbtorgb rgb2rgb;
-	struct omap3isp_prev_csc rgb2ycbcr;
+	struct omap3isp_prev_csc csc;
 	struct omap3isp_prev_hmed hmed;
 	struct omap3isp_prev_yclimit yclimit;
 	u8 contrast;
 	u8 brightness;
 };
 
-/*
- * struct isptables_update - Structure for Table Configuration.
- * @update: Specifies which tables should be updated.
- * @flag: Specifies which tables should be enabled.
- * @nf: Pointer to structure for Noise Filter
- * @lsc: Pointer to LSC gain table. (currently not used)
- * @gamma: Pointer to gamma correction tables.
- * @cfa: Pointer to color filter array configuration.
- * @wbal: Pointer to colour and digital gain configuration.
- */
-struct isptables_update {
-	u32 update;
-	u32 flag;
-	struct omap3isp_prev_nf *nf;
-	u32 *lsc;
-	struct omap3isp_prev_gtables *gamma;
-	struct omap3isp_prev_cfa *cfa;
-	struct omap3isp_prev_wbal *wbal;
-};
-
 /* Sink and source previewer pads */
 #define PREV_PAD_SINK			0
 #define PREV_PAD_SOURCE			1
@@ -157,12 +122,11 @@
  * @output: Bitmask of the active output
  * @video_in: Input video entity
  * @video_out: Output video entity
- * @params: Module configuration data
- * @shadow_update: If set, update the hardware configured in the next interrupt
+ * @params.params : Active and shadow parameters sets
+ * @params.active: Bitmask of parameters active in set 0
+ * @params.lock: Parameters lock, protects params.active and params.shadow
  * @underrun: Whether the preview entity has queued buffers on the output
  * @state: Current preview pipeline state
- * @lock: Shadow update lock
- * @update: Bitmask of the parameters to be updated
  *
  * This structure is used to store the OMAP ISP Preview module Information.
  */
@@ -179,13 +143,15 @@
 	struct isp_video video_in;
 	struct isp_video video_out;
 
-	struct prev_params params;
-	unsigned int shadow_update:1;
+	struct {
+		struct prev_params params[2];
+		u32 active;
+		spinlock_t lock;
+	} params;
+
 	enum isp_pipeline_stream_state state;
 	wait_queue_head_t wait;
 	atomic_t stopping;
-	spinlock_t lock;
-	u32 update;
 };
 
 struct isp_device;
diff --git a/drivers/media/video/omap3isp/ispqueue.h b/drivers/media/video/omap3isp/ispqueue.h
index 92c5a12..908dfd7 100644
--- a/drivers/media/video/omap3isp/ispqueue.h
+++ b/drivers/media/video/omap3isp/ispqueue.h
@@ -90,7 +90,7 @@
 	void *vaddr;
 
 	/* For userspace buffers. */
-	unsigned long vm_flags;
+	vm_flags_t vm_flags;
 	unsigned long offset;
 	unsigned int npages;
 	struct page **pages;
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c
index 6958a9e..14041c9 100644
--- a/drivers/media/video/omap3isp/ispresizer.c
+++ b/drivers/media/video/omap3isp/ispresizer.c
@@ -1188,32 +1188,6 @@
 }
 
 /*
- * resizer_g_crop - handle get crop subdev operation
- * @sd : pointer to v4l2 subdev structure
- * @pad : subdev pad
- * @crop : pointer to crop structure
- * @which : active or try format
- * return zero
- */
-static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
-			  struct v4l2_subdev_crop *crop)
-{
-	struct isp_res_device *res = v4l2_get_subdevdata(sd);
-	struct v4l2_mbus_framefmt *format;
-	struct resizer_ratio ratio;
-
-	/* Only sink pad has crop capability */
-	if (crop->pad != RESZ_PAD_SINK)
-		return -EINVAL;
-
-	format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
-	crop->rect = *__resizer_get_crop(res, fh, crop->which);
-	resizer_calc_ratios(res, &crop->rect, format, &ratio);
-
-	return 0;
-}
-
-/*
  * resizer_try_crop - mangles crop parameters.
  */
 static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
@@ -1223,7 +1197,7 @@
 	const unsigned int spv = DEFAULT_PHASE;
 	const unsigned int sph = DEFAULT_PHASE;
 
-	/* Crop rectangle is constrained to the output size so that zoom ratio
+	/* Crop rectangle is constrained by the output size so that zoom ratio
 	 * cannot exceed +/-4.0.
 	 */
 	unsigned int min_width =
@@ -1248,51 +1222,115 @@
 }
 
 /*
- * resizer_s_crop - handle set crop subdev operation
- * @sd : pointer to v4l2 subdev structure
- * @pad : subdev pad
- * @crop : pointer to crop structure
- * @which : active or try format
- * return -EINVAL or zero when succeed
+ * resizer_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the sink pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
  */
-static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
-			  struct v4l2_subdev_crop *crop)
+static int resizer_get_selection(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
+{
+	struct isp_res_device *res = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format_source;
+	struct v4l2_mbus_framefmt *format_sink;
+	struct resizer_ratio ratio;
+
+	if (sel->pad != RESZ_PAD_SINK)
+		return -EINVAL;
+
+	format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+					   sel->which);
+	format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+					     sel->which);
+
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = INT_MAX;
+		sel->r.height = INT_MAX;
+
+		resizer_try_crop(format_sink, format_source, &sel->r);
+		resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+		break;
+
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+		sel->r = *__resizer_get_crop(res, fh, sel->which);
+		resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * resizer_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the sink pad.
+ *
+ * FIXME: This function currently behaves as if the KEEP_CONFIG selection flag
+ * was always set.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int resizer_set_selection(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
 {
 	struct isp_res_device *res = v4l2_get_subdevdata(sd);
 	struct isp_device *isp = to_isp_device(res);
 	struct v4l2_mbus_framefmt *format_sink, *format_source;
 	struct resizer_ratio ratio;
 
-	/* Only sink pad has crop capability */
-	if (crop->pad != RESZ_PAD_SINK)
+	if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+	    sel->pad != RESZ_PAD_SINK)
 		return -EINVAL;
 
 	format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
-					   crop->which);
+					   sel->which);
 	format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
-					     crop->which);
+					     sel->which);
 
 	dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
-		crop->rect.left, crop->rect.top, crop->rect.width,
-		crop->rect.height, crop->which);
+		sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+		sel->which);
 
 	dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
 		format_sink->width, format_sink->height,
 		format_source->width, format_source->height);
 
-	resizer_try_crop(format_sink, format_source, &crop->rect);
-	*__resizer_get_crop(res, fh, crop->which) = crop->rect;
-	resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
+	/* Clamp the crop rectangle to the bounds, and then mangle it further to
+	 * fulfill the TRM equations. Store the clamped but otherwise unmangled
+	 * rectangle to avoid cropping the input multiple times: when an
+	 * application sets the output format, the current crop rectangle is
+	 * mangled during crop rectangle computation, which would lead to a new,
+	 * smaller input crop rectangle every time the output size is set if we
+	 * stored the mangled rectangle.
+	 */
+	resizer_try_crop(format_sink, format_source, &sel->r);
+	*__resizer_get_crop(res, fh, sel->which) = sel->r;
+	resizer_calc_ratios(res, &sel->r, format_source, &ratio);
 
-	if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
 		return 0;
 
 	res->ratio = ratio;
-	res->crop.active = crop->rect;
+	res->crop.active = sel->r;
 
 	/*
-	 * s_crop can be called while streaming is on. In this case
-	 * the crop values will be set in the next IRQ.
+	 * set_selection can be called while streaming is on. In this case the
+	 * crop values will be set in the next IRQ.
 	 */
 	if (res->state != ISP_PIPELINE_STREAM_STOPPED)
 		res->applycrop = 1;
@@ -1530,8 +1568,8 @@
 	.enum_frame_size = resizer_enum_frame_size,
 	.get_fmt = resizer_get_format,
 	.set_fmt = resizer_set_format,
-	.get_crop = resizer_g_crop,
-	.set_crop = resizer_s_crop,
+	.get_selection = resizer_get_selection,
+	.set_selection = resizer_set_selection,
 };
 
 /* subdev operations */
@@ -1603,6 +1641,7 @@
 /* media operations */
 static const struct media_entity_operations resizer_media_ops = {
 	.link_setup = resizer_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
 };
 
 void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c
index 11871ec..b8640be 100644
--- a/drivers/media/video/omap3isp/ispstat.c
+++ b/drivers/media/video/omap3isp/ispstat.c
@@ -1032,7 +1032,7 @@
 	if (sub->type != stat->event_type)
 		return -EINVAL;
 
-	return v4l2_event_subscribe(fh, sub, STAT_NEVENTS);
+	return v4l2_event_subscribe(fh, sub, STAT_NEVENTS, NULL);
 }
 
 int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c
index b020700..b37379d 100644
--- a/drivers/media/video/omap3isp/ispvideo.c
+++ b/drivers/media/video/omap3isp/ispvideo.c
@@ -46,6 +46,10 @@
  * Helper functions
  */
 
+/*
+ * NOTE: When adding new media bus codes, always remember to add
+ * corresponding in-memory formats to the table below!!!
+ */
 static struct isp_format_info formats[] = {
 	{ V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
 	  V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
@@ -68,9 +72,18 @@
 	{ V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
 	  V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
 	  V4L2_PIX_FMT_SRGGB8, 8, },
+	{ V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
+	  V4L2_MBUS_FMT_SBGGR10_1X10, 0,
+	  V4L2_PIX_FMT_SBGGR10DPCM8, 8, },
+	{ V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
+	  V4L2_MBUS_FMT_SGBRG10_1X10, 0,
+	  V4L2_PIX_FMT_SGBRG10DPCM8, 8, },
 	{ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
 	  V4L2_MBUS_FMT_SGRBG10_1X10, 0,
 	  V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
+	{ V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
+	  V4L2_MBUS_FMT_SRGGB10_1X10, 0,
+	  V4L2_PIX_FMT_SRGGB10DPCM8, 8, },
 	{ V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
 	  V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
 	  V4L2_PIX_FMT_SBGGR10, 10, },
@@ -117,37 +130,6 @@
 }
 
 /*
- * Decide whether desired output pixel code can be obtained with
- * the lane shifter by shifting the input pixel code.
- * @in: input pixelcode to shifter
- * @out: output pixelcode from shifter
- * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
- *
- * return true if the combination is possible
- * return false otherwise
- */
-static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in,
-		enum v4l2_mbus_pixelcode out,
-		unsigned int additional_shift)
-{
-	const struct isp_format_info *in_info, *out_info;
-
-	if (in == out)
-		return true;
-
-	in_info = omap3isp_video_format_info(in);
-	out_info = omap3isp_video_format_info(out);
-
-	if ((in_info->flavor == 0) || (out_info->flavor == 0))
-		return false;
-
-	if (in_info->flavor != out_info->flavor)
-		return false;
-
-	return in_info->bpp - out_info->bpp + additional_shift <= 6;
-}
-
-/*
  * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
  * @video: ISP video instance
  * @mbus: v4l2_mbus_framefmt format (input)
@@ -242,8 +224,8 @@
 }
 
 /* Return a pointer to the ISP video instance at the far end of the pipeline. */
-static struct isp_video *
-isp_video_far_end(struct isp_video *video)
+static int isp_video_get_graph_data(struct isp_video *video,
+				    struct isp_pipeline *pipe)
 {
 	struct media_entity_graph graph;
 	struct media_entity *entity = &video->video.entity;
@@ -254,21 +236,38 @@
 	media_entity_graph_walk_start(&graph, entity);
 
 	while ((entity = media_entity_graph_walk_next(&graph))) {
+		struct isp_video *__video;
+
+		pipe->entities |= 1 << entity->id;
+
+		if (far_end != NULL)
+			continue;
+
 		if (entity == &video->video.entity)
 			continue;
 
 		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
 			continue;
 
-		far_end = to_isp_video(media_entity_to_video_device(entity));
-		if (far_end->type != video->type)
-			break;
-
-		far_end = NULL;
+		__video = to_isp_video(media_entity_to_video_device(entity));
+		if (__video->type != video->type)
+			far_end = __video;
 	}
 
 	mutex_unlock(&mdev->graph_mutex);
-	return far_end;
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		pipe->input = far_end;
+		pipe->output = video;
+	} else {
+		if (far_end == NULL)
+			return -EPIPE;
+
+		pipe->input = video;
+		pipe->output = far_end;
+	}
+
+	return 0;
 }
 
 /*
@@ -285,52 +284,24 @@
 static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
 {
 	struct isp_device *isp = pipe->output->isp;
-	struct v4l2_subdev_format fmt_source;
-	struct v4l2_subdev_format fmt_sink;
 	struct media_pad *pad;
 	struct v4l2_subdev *subdev;
-	int ret;
-
-	pipe->max_rate = pipe->l3_ick;
 
 	subdev = isp_video_remote_subdev(pipe->output, NULL);
 	if (subdev == NULL)
 		return -EPIPE;
 
 	while (1) {
-		unsigned int shifter_link;
 		/* Retrieve the sink format */
 		pad = &subdev->entity.pads[0];
 		if (!(pad->flags & MEDIA_PAD_FL_SINK))
 			break;
 
-		fmt_sink.pad = pad->index;
-		fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_sink);
-		if (ret < 0 && ret != -ENOIOCTLCMD)
-			return -EPIPE;
-
 		/* Update the maximum frame rate */
 		if (subdev == &isp->isp_res.subdev)
 			omap3isp_resizer_max_rate(&isp->isp_res,
 						  &pipe->max_rate);
 
-		/* Check ccdc maximum data rate when data comes from sensor
-		 * TODO: Include ccdc rate in pipe->max_rate and compare the
-		 *       total pipe rate with the input data rate from sensor.
-		 */
-		if (subdev == &isp->isp_ccdc.subdev && pipe->input == NULL) {
-			unsigned int rate = UINT_MAX;
-
-			omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
-			if (isp->isp_ccdc.vpcfg.pixelclk > rate)
-				return -ENOSPC;
-		}
-
-		/* If sink pad is on CCDC, the link has the lane shifter
-		 * in the middle of it. */
-		shifter_link = subdev == &isp->isp_ccdc.subdev;
-
 		/* Retrieve the source format. Return an error if no source
 		 * entity can be found, and stop checking the pipeline if the
 		 * source entity isn't a subdev.
@@ -343,32 +314,6 @@
 			break;
 
 		subdev = media_entity_to_v4l2_subdev(pad->entity);
-
-		fmt_source.pad = pad->index;
-		fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
-		if (ret < 0 && ret != -ENOIOCTLCMD)
-			return -EPIPE;
-
-		/* Check if the two ends match */
-		if (fmt_source.format.width != fmt_sink.format.width ||
-		    fmt_source.format.height != fmt_sink.format.height)
-			return -EPIPE;
-
-		if (shifter_link) {
-			unsigned int parallel_shift = 0;
-			if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) {
-				struct isp_parallel_platform_data *pdata =
-					&((struct isp_v4l2_subdevs_group *)
-					      subdev->host_priv)->bus.parallel;
-				parallel_shift = pdata->data_lane_shift * 2;
-			}
-			if (!isp_video_is_shiftable(fmt_source.format.code,
-						fmt_sink.format.code,
-						parallel_shift))
-				return -EPIPE;
-		} else if (fmt_source.format.code != fmt_sink.format.code)
-			return -EPIPE;
 	}
 
 	return 0;
@@ -923,6 +868,92 @@
 					  file->f_flags & O_NONBLOCK);
 }
 
+static int isp_video_check_external_subdevs(struct isp_video *video,
+					    struct isp_pipeline *pipe)
+{
+	struct isp_device *isp = video->isp;
+	struct media_entity *ents[] = {
+		&isp->isp_csi2a.subdev.entity,
+		&isp->isp_csi2c.subdev.entity,
+		&isp->isp_ccp2.subdev.entity,
+		&isp->isp_ccdc.subdev.entity
+	};
+	struct media_pad *source_pad;
+	struct media_entity *source = NULL;
+	struct media_entity *sink;
+	struct v4l2_subdev_format fmt;
+	struct v4l2_ext_controls ctrls;
+	struct v4l2_ext_control ctrl;
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < ARRAY_SIZE(ents); i++) {
+		/* Is the entity part of the pipeline? */
+		if (!(pipe->entities & (1 << ents[i]->id)))
+			continue;
+
+		/* ISP entities have always sink pad == 0. Find source. */
+		source_pad = media_entity_remote_source(&ents[i]->pads[0]);
+		if (source_pad == NULL)
+			continue;
+
+		source = source_pad->entity;
+		sink = ents[i];
+		break;
+	}
+
+	if (!source) {
+		dev_warn(isp->dev, "can't find source, failing now\n");
+		return ret;
+	}
+
+	if (media_entity_type(source) != MEDIA_ENT_T_V4L2_SUBDEV)
+		return 0;
+
+	pipe->external = media_entity_to_v4l2_subdev(source);
+
+	fmt.pad = source_pad->index;
+	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(sink),
+			       pad, get_fmt, NULL, &fmt);
+	if (unlikely(ret < 0)) {
+		dev_warn(isp->dev, "get_fmt returned null!\n");
+		return ret;
+	}
+
+	pipe->external_bpp = omap3isp_video_format_info(fmt.format.code)->bpp;
+
+	memset(&ctrls, 0, sizeof(ctrls));
+	memset(&ctrl, 0, sizeof(ctrl));
+
+	ctrl.id = V4L2_CID_PIXEL_RATE;
+
+	ctrls.count = 1;
+	ctrls.controls = &ctrl;
+
+	ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &ctrls);
+	if (ret < 0) {
+		dev_warn(isp->dev, "no pixel rate control in subdev %s\n",
+			 pipe->external->name);
+		return ret;
+	}
+
+	pipe->external_rate = ctrl.value64;
+
+	if (pipe->entities & (1 << isp->isp_ccdc.subdev.entity.id)) {
+		unsigned int rate = UINT_MAX;
+		/*
+		 * Check that maximum allowed CCDC pixel rate isn't
+		 * exceeded by the pixel rate.
+		 */
+		omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
+		if (pipe->external_rate > rate)
+			return -ENOSPC;
+	}
+
+	return 0;
+}
+
 /*
  * Stream management
  *
@@ -961,7 +992,6 @@
 	struct isp_video *video = video_drvdata(file);
 	enum isp_pipeline_state state;
 	struct isp_pipeline *pipe;
-	struct isp_video *far_end;
 	unsigned long flags;
 	int ret;
 
@@ -980,46 +1010,45 @@
 	 */
 	pipe = video->video.entity.pipe
 	     ? to_isp_pipeline(&video->video.entity) : &video->pipe;
-	media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+
+	pipe->entities = 0;
+
+	if (video->isp->pdata->set_constraints)
+		video->isp->pdata->set_constraints(video->isp, true);
+	pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
+	pipe->max_rate = pipe->l3_ick;
+
+	ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+	if (ret < 0)
+		goto err_pipeline_start;
 
 	/* Verify that the currently configured format matches the output of
 	 * the connected subdev.
 	 */
 	ret = isp_video_check_format(video, vfh);
 	if (ret < 0)
-		goto error;
+		goto err_check_format;
 
 	video->bpl_padding = ret;
 	video->bpl_value = vfh->format.fmt.pix.bytesperline;
 
-	/* Find the ISP video node connected at the far end of the pipeline and
-	 * update the pipeline.
-	 */
-	far_end = isp_video_far_end(video);
+	ret = isp_video_get_graph_data(video, pipe);
+	if (ret < 0)
+		goto err_check_format;
 
-	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT;
-		pipe->input = far_end;
-		pipe->output = video;
-	} else {
-		if (far_end == NULL) {
-			ret = -EPIPE;
-			goto error;
-		}
-
+	else
 		state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT;
-		pipe->input = video;
-		pipe->output = far_end;
-	}
 
-	if (video->isp->pdata->set_constraints)
-		video->isp->pdata->set_constraints(video->isp, true);
-	pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
+	ret = isp_video_check_external_subdevs(video, pipe);
+	if (ret < 0)
+		goto err_check_format;
 
 	/* Validate the pipeline and update its state. */
 	ret = isp_video_validate_pipeline(pipe);
 	if (ret < 0)
-		goto error;
+		goto err_check_format;
 
 	pipe->error = false;
 
@@ -1041,7 +1070,7 @@
 
 	ret = omap3isp_video_queue_streamon(&vfh->queue);
 	if (ret < 0)
-		goto error;
+		goto err_check_format;
 
 	/* In sensor-to-memory mode, the stream can be started synchronously
 	 * to the stream on command. In memory-to-memory mode, it will be
@@ -1051,32 +1080,34 @@
 		ret = omap3isp_pipeline_set_stream(pipe,
 					      ISP_PIPELINE_STREAM_CONTINUOUS);
 		if (ret < 0)
-			goto error;
+			goto err_set_stream;
 		spin_lock_irqsave(&video->queue->irqlock, flags);
 		if (list_empty(&video->dmaqueue))
 			video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
 		spin_unlock_irqrestore(&video->queue->irqlock, flags);
 	}
 
-error:
-	if (ret < 0) {
-		omap3isp_video_queue_streamoff(&vfh->queue);
-		if (video->isp->pdata->set_constraints)
-			video->isp->pdata->set_constraints(video->isp, false);
-		media_entity_pipeline_stop(&video->video.entity);
-		/* The DMA queue must be emptied here, otherwise CCDC interrupts
-		 * that will get triggered the next time the CCDC is powered up
-		 * will try to access buffers that might have been freed but
-		 * still present in the DMA queue. This can easily get triggered
-		 * if the above omap3isp_pipeline_set_stream() call fails on a
-		 * system with a free-running sensor.
-		 */
-		INIT_LIST_HEAD(&video->dmaqueue);
-		video->queue = NULL;
-	}
+	video->streaming = 1;
 
-	if (!ret)
-		video->streaming = 1;
+	mutex_unlock(&video->stream_lock);
+	return 0;
+
+err_set_stream:
+	omap3isp_video_queue_streamoff(&vfh->queue);
+err_check_format:
+	media_entity_pipeline_stop(&video->video.entity);
+err_pipeline_start:
+	if (video->isp->pdata->set_constraints)
+		video->isp->pdata->set_constraints(video->isp, false);
+	/* The DMA queue must be emptied here, otherwise CCDC interrupts that
+	 * will get triggered the next time the CCDC is powered up will try to
+	 * access buffers that might have been freed but still present in the
+	 * DMA queue. This can easily get triggered if the above
+	 * omap3isp_pipeline_set_stream() call fails on a system with a
+	 * free-running sensor.
+	 */
+	INIT_LIST_HEAD(&video->dmaqueue);
+	video->queue = NULL;
 
 	mutex_unlock(&video->stream_lock);
 	return ret;
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h
index d91bdb9..5acc909 100644
--- a/drivers/media/video/omap3isp/ispvideo.h
+++ b/drivers/media/video/omap3isp/ispvideo.h
@@ -88,6 +88,7 @@
 /*
  * struct isp_pipeline - An ISP hardware pipeline
  * @error: A hardware error occurred during capture
+ * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
  */
 struct isp_pipeline {
 	struct media_pipeline pipe;
@@ -96,12 +97,16 @@
 	enum isp_pipeline_stream_state stream_state;
 	struct isp_video *input;
 	struct isp_video *output;
+	u32 entities;
 	unsigned long l3_ick;
 	unsigned int max_rate;
 	atomic_t frame_number;
 	bool do_propagation; /* of frame number */
 	bool error;
 	struct v4l2_fract max_timeperframe;
+	struct v4l2_subdev *external;
+	unsigned int external_rate;
+	unsigned int external_bpp;
 };
 
 #define to_isp_pipeline(__e) \
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c
index 80e0779..0bc9331 100644
--- a/drivers/media/video/ov5642.c
+++ b/drivers/media/video/ov5642.c
@@ -1025,8 +1025,6 @@
 	priv->crop_rect.height	= OV5642_DEFAULT_HEIGHT;
 	priv->crop_rect.left	= (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
 	priv->crop_rect.top	= (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
-	priv->crop_rect.width	= OV5642_DEFAULT_WIDTH;
-	priv->crop_rect.height	= OV5642_DEFAULT_HEIGHT;
 	priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
 	priv->total_height = BLANKING_MIN_HEIGHT;
 
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index e753b5e..af2d908 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -30,15 +30,19 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
+#include <linux/isa.h>
 #include <asm/io.h>
 
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-device.h>
 
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.4");
+MODULE_VERSION("0.0.5");
 
 #define MOTOROLA	1
 #define PHILIPS2	2               /* SAA7191 */
@@ -55,11 +59,11 @@
 struct pms {
 	struct v4l2_device v4l2_dev;
 	struct video_device vdev;
+	struct v4l2_ctrl_handler hdl;
 	int height;
 	int width;
 	int depth;
 	int input;
-	s32 brightness, saturation, hue, contrast;
 	struct mutex lock;
 	int i2c_count;
 	struct i2c_info i2cinfo[64];
@@ -72,8 +76,6 @@
 	void __iomem *mem;
 };
 
-static struct pms pms_card;
-
 /*
  *	I/O ports and Shared Memory
  */
@@ -676,8 +678,10 @@
 
 	strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver));
 	strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card));
-	strlcpy(vcap->bus_info, "ISA", sizeof(vcap->bus_info));
-	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	snprintf(vcap->bus_info, sizeof(vcap->bus_info),
+			"ISA:%s", dev->v4l2_dev.name);
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -716,11 +720,9 @@
 	if (inp > 3)
 		return -EINVAL;
 
-	mutex_lock(&dev->lock);
 	dev->input = inp;
 	pms_videosource(dev, inp & 1);
 	pms_vcrinput(dev, inp >> 1);
-	mutex_unlock(&dev->lock);
 	return 0;
 }
 
@@ -738,7 +740,6 @@
 	int ret = 0;
 
 	dev->std = *std;
-	mutex_lock(&dev->lock);
 	if (dev->std & V4L2_STD_NTSC) {
 		pms_framerate(dev, 30);
 		pms_secamcross(dev, 0);
@@ -762,81 +763,31 @@
 		pms_format(dev, 0);
 		break;
 	}*/
-	mutex_unlock(&dev->lock);
-	return 0;
-}
-
-static int pms_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_BRIGHTNESS:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 139);
-	case V4L2_CID_CONTRAST:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 70);
-	case V4L2_CID_SATURATION:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 64);
-	case V4L2_CID_HUE:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0);
-	}
-	return -EINVAL;
-}
-
-static int pms_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct pms *dev = video_drvdata(file);
-	int ret = 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = dev->brightness;
-		break;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = dev->contrast;
-		break;
-	case V4L2_CID_SATURATION:
-		ctrl->value = dev->saturation;
-		break;
-	case V4L2_CID_HUE:
-		ctrl->value = dev->hue;
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
 	return ret;
 }
 
-static int pms_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
+static int pms_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct pms *dev = video_drvdata(file);
+	struct pms *dev = container_of(ctrl->handler, struct pms, hdl);
 	int ret = 0;
 
-	mutex_lock(&dev->lock);
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		dev->brightness = ctrl->value;
-		pms_brightness(dev, dev->brightness);
+		pms_brightness(dev, ctrl->val);
 		break;
 	case V4L2_CID_CONTRAST:
-		dev->contrast = ctrl->value;
-		pms_contrast(dev, dev->contrast);
+		pms_contrast(dev, ctrl->val);
 		break;
 	case V4L2_CID_SATURATION:
-		dev->saturation = ctrl->value;
-		pms_saturation(dev, dev->saturation);
+		pms_saturation(dev, ctrl->val);
 		break;
 	case V4L2_CID_HUE:
-		dev->hue = ctrl->value;
-		pms_hue(dev, dev->hue);
+		pms_hue(dev, ctrl->val);
 		break;
 	default:
 		ret = -EINVAL;
 		break;
 	}
-	mutex_unlock(&dev->lock);
 	return ret;
 }
 
@@ -884,13 +835,11 @@
 
 	if (ret)
 		return ret;
-	mutex_lock(&dev->lock);
 	dev->width = pix->width;
 	dev->height = pix->height;
 	dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16;
 	pms_resolution(dev, dev->width, dev->height);
 	/* Ok we figured out what to use from our wide choice */
-	mutex_unlock(&dev->lock);
 	return 0;
 }
 
@@ -901,7 +850,7 @@
 		  "RGB 5:5:5", V4L2_PIX_FMT_RGB555,
 		  { 0, 0, 0, 0 }
 		},
-		{ 0, 0, 0,
+		{ 1, 0, 0,
 		  "RGB 5:6:5", V4L2_PIX_FMT_RGB565,
 		  { 0, 0, 0, 0 }
 		},
@@ -922,32 +871,43 @@
 	struct pms *dev = video_drvdata(file);
 	int len;
 
-	mutex_lock(&dev->lock);
 	len = pms_capture(dev, buf, (dev->depth == 15), count);
-	mutex_unlock(&dev->lock);
 	return len;
 }
 
+static unsigned int pms_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct v4l2_fh *fh = file->private_data;
+	unsigned int res = POLLIN | POLLRDNORM;
+
+	if (v4l2_event_pending(fh))
+		res |= POLLPRI;
+	poll_wait(file, &fh->wait, wait);
+	return res;
+}
+
 static const struct v4l2_file_operations pms_fops = {
 	.owner		= THIS_MODULE,
+	.open           = v4l2_fh_open,
+	.release        = v4l2_fh_release,
+	.poll           = pms_poll,
 	.unlocked_ioctl	= video_ioctl2,
 	.read           = pms_read,
 };
 
 static const struct v4l2_ioctl_ops pms_ioctl_ops = {
-	.vidioc_querycap    		    = pms_querycap,
-	.vidioc_g_input      		    = pms_g_input,
-	.vidioc_s_input      		    = pms_s_input,
-	.vidioc_enum_input   		    = pms_enum_input,
-	.vidioc_g_std 			    = pms_g_std,
-	.vidioc_s_std 			    = pms_s_std,
-	.vidioc_queryctrl 		    = pms_queryctrl,
-	.vidioc_g_ctrl  		    = pms_g_ctrl,
-	.vidioc_s_ctrl 			    = pms_s_ctrl,
-	.vidioc_enum_fmt_vid_cap 	    = pms_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap 		    = pms_g_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap  		    = pms_s_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap  	    = pms_try_fmt_vid_cap,
+	.vidioc_querycap	    = pms_querycap,
+	.vidioc_g_input		    = pms_g_input,
+	.vidioc_s_input		    = pms_s_input,
+	.vidioc_enum_input	    = pms_enum_input,
+	.vidioc_g_std		    = pms_g_std,
+	.vidioc_s_std		    = pms_s_std,
+	.vidioc_enum_fmt_vid_cap    = pms_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	    = pms_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	    = pms_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap     = pms_try_fmt_vid_cap,
+	.vidioc_subscribe_event     = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event   = v4l2_event_unsubscribe,
 };
 
 /*
@@ -956,7 +916,6 @@
 
 static int init_mediavision(struct pms *dev)
 {
-	int id;
 	int idec, decst;
 	int i;
 	static const unsigned char i2c_defs[] = {
@@ -988,7 +947,6 @@
 	outb(dev->io >> 4, 0x9a01);	/* Set IO port */
 
 
-	id = mvv_read(dev, 3);
 	decst = pms_i2c_stat(dev, 0x43);
 
 	if (decst != -1)
@@ -1068,76 +1026,125 @@
 module_param(enable, int, 0);
 #endif
 
-static int __init pms_init(void)
+static const struct v4l2_ctrl_ops pms_ctrl_ops = {
+	.s_ctrl = pms_s_ctrl,
+};
+
+static int pms_probe(struct device *pdev, unsigned int card)
 {
-	struct pms *dev = &pms_card;
-	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+	struct pms *dev;
+	struct v4l2_device *v4l2_dev;
+	struct v4l2_ctrl_handler *hdl;
 	int res;
 
-	strlcpy(v4l2_dev->name, "pms", sizeof(v4l2_dev->name));
-
-	v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.03\n");
-
 #ifndef MODULE
 	if (!enable) {
-		v4l2_err(v4l2_dev,
-			"PMS: not enabled, use pms.enable=1 to probe\n");
+		pr_err("PMS: not enabled, use pms.enable=1 to probe\n");
 		return -ENODEV;
 	}
 #endif
 
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL)
+		return -ENOMEM;
+
 	dev->decoder = PHILIPS2;
 	dev->io = io_port;
 	dev->data = io_port + 1;
+	v4l2_dev = &dev->v4l2_dev;
+	hdl = &dev->hdl;
 
-	if (init_mediavision(dev)) {
-		v4l2_err(v4l2_dev, "Board not found.\n");
-		return -ENODEV;
-	}
-
-	res = v4l2_device_register(NULL, v4l2_dev);
+	res = v4l2_device_register(pdev, v4l2_dev);
 	if (res < 0) {
 		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-		return res;
+		goto free_dev;
+	}
+	v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.05\n");
+
+	res = init_mediavision(dev);
+	if (res) {
+		v4l2_err(v4l2_dev, "Board not found.\n");
+		goto free_io;
 	}
 
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 139);
+	v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 70);
+	v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 64);
+	v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+			V4L2_CID_HUE, 0, 255, 1, 0);
+	if (hdl->error) {
+		res = hdl->error;
+		goto free_hdl;
+	}
+
+	mutex_init(&dev->lock);
 	strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
 	dev->vdev.v4l2_dev = v4l2_dev;
+	dev->vdev.ctrl_handler = hdl;
 	dev->vdev.fops = &pms_fops;
 	dev->vdev.ioctl_ops = &pms_ioctl_ops;
 	dev->vdev.release = video_device_release_empty;
+	dev->vdev.lock = &dev->lock;
+	dev->vdev.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+	set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
 	video_set_drvdata(&dev->vdev, dev);
-	mutex_init(&dev->lock);
 	dev->std = V4L2_STD_NTSC_M;
 	dev->height = 240;
 	dev->width = 320;
-	dev->depth = 15;
-	dev->brightness = 139;
-	dev->contrast = 70;
-	dev->hue = 0;
-	dev->saturation = 64;
+	dev->depth = 16;
 	pms_swsense(dev, 75);
 	pms_resolution(dev, 320, 240);
 	pms_videosource(dev, 0);
 	pms_vcrinput(dev, 0);
-	if (video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
-		v4l2_device_unregister(&dev->v4l2_dev);
-		release_region(dev->io, 3);
-		release_region(0x9a01, 1);
-		iounmap(dev->mem);
-		return -EINVAL;
-	}
+	v4l2_ctrl_handler_setup(hdl);
+	res = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
+	if (res >= 0)
+		return 0;
+
+free_hdl:
+	v4l2_ctrl_handler_free(hdl);
+	v4l2_device_unregister(&dev->v4l2_dev);
+free_io:
+	release_region(dev->io, 3);
+	release_region(0x9a01, 1);
+	iounmap(dev->mem);
+free_dev:
+	kfree(dev);
+	return res;
+}
+
+static int pms_remove(struct device *pdev, unsigned int card)
+{
+	struct pms *dev = dev_get_drvdata(pdev);
+
+	video_unregister_device(&dev->vdev);
+	v4l2_ctrl_handler_free(&dev->hdl);
+	release_region(dev->io, 3);
+	release_region(0x9a01, 1);
+	iounmap(dev->mem);
 	return 0;
 }
 
+static struct isa_driver pms_driver = {
+	.probe		= pms_probe,
+	.remove		= pms_remove,
+	.driver		= {
+		.name	= "pms",
+	},
+};
+
+static int __init pms_init(void)
+{
+	return isa_register_driver(&pms_driver, 1);
+}
+
 static void __exit pms_exit(void)
 {
-	struct pms *dev = &pms_card;
-
-	video_unregister_device(&dev->vdev);
-	release_region(dev->io, 3);
-	release_region(0x9a01, 1);
-	iounmap(dev->mem);
+	isa_unregister_driver(&pms_driver);
 }
 
 module_init(pms_init);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 305e6aa..036952f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -317,18 +317,16 @@
 	v4l2_std_id std_mask_eeprom; // Hardware supported selections
 	v4l2_std_id std_mask_avail;  // Which standards we may select from
 	v4l2_std_id std_mask_cur;    // Currently selected standard(s)
-	unsigned int std_enum_cnt;   // # of enumerated standards
 	int std_enum_cur;            // selected standard enumeration value
 	int std_dirty;               // True if std_mask_cur has changed
 	struct pvr2_ctl_info std_info_enum;
 	struct pvr2_ctl_info std_info_avail;
 	struct pvr2_ctl_info std_info_cur;
-	struct v4l2_standard *std_defs;
-	const char **std_enum_names;
+	struct pvr2_ctl_info std_info_detect;
 
 	// Generated string names, one per actual V4L2 standard
 	const char *std_mask_ptrs[32];
-	char std_mask_names[32][10];
+	char std_mask_names[32][16];
 
 	int unit_number;             /* ID for driver instance */
 	unsigned long serial_number; /* ID for hardware itself */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index ebc2c7e..fb828ba 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -334,8 +334,6 @@
 static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
 static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw);
 static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
-static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
 static void pvr2_hdw_quiescent_timeout(unsigned long);
 static void pvr2_hdw_decoder_stabilization_timeout(unsigned long);
 static void pvr2_hdw_encoder_wait_timeout(unsigned long);
@@ -346,7 +344,7 @@
 				void *write_data,unsigned int write_len,
 				void *read_data,unsigned int read_len);
 static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw);
-
+static v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw);
 
 static void trace_stbit(const char *name,int val)
 {
@@ -840,6 +838,12 @@
 	return 0;
 }
 
+static int ctrl_stddetect_get(struct pvr2_ctrl *cptr, int *vp)
+{
+	*vp = pvr2_hdw_get_detected_std(cptr->hdw);
+	return 0;
+}
+
 static int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp)
 {
 	*vp = cptr->hdw->std_mask_avail;
@@ -854,8 +858,7 @@
 	ns = (ns & ~m) | (v & m);
 	if (ns == hdw->std_mask_avail) return 0;
 	hdw->std_mask_avail = ns;
-	pvr2_hdw_internal_set_std_avail(hdw);
-	pvr2_hdw_internal_find_stdenum(hdw);
+	hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
 	return 0;
 }
 
@@ -895,7 +898,6 @@
 	if (ns == hdw->std_mask_cur) return 0;
 	hdw->std_mask_cur = ns;
 	hdw->std_dirty = !0;
-	pvr2_hdw_internal_find_stdenum(hdw);
 	return 0;
 }
 
@@ -941,40 +943,6 @@
 }
 
 
-static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
-{
-	struct pvr2_hdw *hdw = cptr->hdw;
-	if (v < 0) return -EINVAL;
-	if (v > hdw->std_enum_cnt) return -EINVAL;
-	hdw->std_enum_cur = v;
-	if (!v) return 0;
-	v--;
-	if (hdw->std_mask_cur == hdw->std_defs[v].id) return 0;
-	hdw->std_mask_cur = hdw->std_defs[v].id;
-	hdw->std_dirty = !0;
-	return 0;
-}
-
-
-static int ctrl_stdenumcur_get(struct pvr2_ctrl *cptr,int *vp)
-{
-	*vp = cptr->hdw->std_enum_cur;
-	return 0;
-}
-
-
-static int ctrl_stdenumcur_is_dirty(struct pvr2_ctrl *cptr)
-{
-	return cptr->hdw->std_dirty != 0;
-}
-
-
-static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
-{
-	cptr->hdw->std_dirty = 0;
-}
-
-
 #define DEFINT(vmin,vmax) \
 	.type = pvr2_ctl_int, \
 	.def.type_int.min_value = vmin, \
@@ -1293,15 +1261,14 @@
 		.sym_to_val = ctrl_std_sym_to_val,
 		.type = pvr2_ctl_bitmask,
 	},{
-		.desc = "Video Standard Name",
-		.name = "video_standard",
-		.internal_id = PVR2_CID_STDENUM,
+		.desc = "Video Standards Detected Mask",
+		.name = "video_standard_mask_detected",
+		.internal_id = PVR2_CID_STDDETECT,
 		.skip_init = !0,
-		.get_value = ctrl_stdenumcur_get,
-		.set_value = ctrl_stdenumcur_set,
-		.is_dirty = ctrl_stdenumcur_is_dirty,
-		.clear_dirty = ctrl_stdenumcur_clear_dirty,
-		.type = pvr2_ctl_enum,
+		.get_value = ctrl_stddetect_get,
+		.val_to_sym = ctrl_std_val_to_sym,
+		.sym_to_val = ctrl_std_sym_to_val,
+		.type = pvr2_ctl_bitmask,
 	}
 };
 
@@ -1936,7 +1903,7 @@
 		hdw->std_mask_avail |= std2;
 	}
 
-	pvr2_hdw_internal_set_std_avail(hdw);
+	hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
 
 	if (std1) {
 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1);
@@ -1945,7 +1912,6 @@
 			   bcnt,buf);
 		hdw->std_mask_cur = std1;
 		hdw->std_dirty = !0;
-		pvr2_hdw_internal_find_stdenum(hdw);
 		return;
 	}
 	if (std3) {
@@ -1955,7 +1921,6 @@
 			   " (determined by device type): %.*s",bcnt,buf);
 		hdw->std_mask_cur = std3;
 		hdw->std_dirty = !0;
-		pvr2_hdw_internal_find_stdenum(hdw);
 		return;
 	}
 
@@ -1975,24 +1940,10 @@
 				   bcnt,buf);
 			hdw->std_mask_cur = std_eeprom_maps[idx].std;
 			hdw->std_dirty = !0;
-			pvr2_hdw_internal_find_stdenum(hdw);
 			return;
 		}
 	}
 
-	if (hdw->std_enum_cnt > 1) {
-		// Autoselect the first listed standard
-		hdw->std_enum_cur = 1;
-		hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id;
-		hdw->std_dirty = !0;
-		pvr2_trace(PVR2_TRACE_STD,
-			   "Initial video standard auto-selected to %s",
-			   hdw->std_defs[hdw->std_enum_cur-1].name);
-		return;
-	}
-
-	pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-		   "Unable to select a viable initial video standard");
 }
 
 
@@ -2594,14 +2545,6 @@
 		cptr->info = ciptr;
 	}
 
-	// Initialize video standard enum dynamic control
-	cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM);
-	if (cptr) {
-		memcpy(&hdw->std_info_enum,cptr->info,
-		       sizeof(hdw->std_info_enum));
-		cptr->info = &hdw->std_info_enum;
-
-	}
 	// Initialize control data regarding video standard masks
 	valid_std_mask = pvr2_std_get_usable();
 	for (idx = 0; idx < 32; idx++) {
@@ -2629,7 +2572,17 @@
 		cptr->info = &hdw->std_info_cur;
 		hdw->std_info_cur.def.type_bitmask.bit_names =
 			hdw->std_mask_ptrs;
-		hdw->std_info_avail.def.type_bitmask.valid_bits =
+		hdw->std_info_cur.def.type_bitmask.valid_bits =
+			valid_std_mask;
+	}
+	cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDDETECT);
+	if (cptr) {
+		memcpy(&hdw->std_info_detect,cptr->info,
+		       sizeof(hdw->std_info_detect));
+		cptr->info = &hdw->std_info_detect;
+		hdw->std_info_detect.def.type_bitmask.bit_names =
+			hdw->std_mask_ptrs;
+		hdw->std_info_detect.def.type_bitmask.valid_bits =
 			valid_std_mask;
 	}
 
@@ -2711,8 +2664,6 @@
 		kfree(hdw->ctl_write_buffer);
 		kfree(hdw->controls);
 		kfree(hdw->mpeg_ctrl_info);
-		kfree(hdw->std_defs);
-		kfree(hdw->std_enum_names);
 		kfree(hdw);
 	}
 	return NULL;
@@ -2788,8 +2739,6 @@
 	} while (0); mutex_unlock(&pvr2_unit_mtx);
 	kfree(hdw->controls);
 	kfree(hdw->mpeg_ctrl_info);
-	kfree(hdw->std_defs);
-	kfree(hdw->std_enum_names);
 	kfree(hdw);
 }
 
@@ -2812,86 +2761,6 @@
 }
 
 
-// Attempt to autoselect an appropriate value for std_enum_cur given
-// whatever is currently in std_mask_cur
-static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw)
-{
-	unsigned int idx;
-	for (idx = 1; idx < hdw->std_enum_cnt; idx++) {
-		if (hdw->std_defs[idx-1].id == hdw->std_mask_cur) {
-			hdw->std_enum_cur = idx;
-			return;
-		}
-	}
-	hdw->std_enum_cur = 0;
-}
-
-
-// Calculate correct set of enumerated standards based on currently known
-// set of available standards bits.
-static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw)
-{
-	struct v4l2_standard *newstd;
-	unsigned int std_cnt;
-	unsigned int idx;
-
-	newstd = pvr2_std_create_enum(&std_cnt,hdw->std_mask_avail);
-
-	if (hdw->std_defs) {
-		kfree(hdw->std_defs);
-		hdw->std_defs = NULL;
-	}
-	hdw->std_enum_cnt = 0;
-	if (hdw->std_enum_names) {
-		kfree(hdw->std_enum_names);
-		hdw->std_enum_names = NULL;
-	}
-
-	if (!std_cnt) {
-		pvr2_trace(
-			PVR2_TRACE_ERROR_LEGS,
-			"WARNING: Failed to identify any viable standards");
-	}
-
-	/* Set up the dynamic control for this standard */
-	hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL);
-	if (hdw->std_enum_names) {
-		hdw->std_enum_names[0] = "none";
-		for (idx = 0; idx < std_cnt; idx++)
-			hdw->std_enum_names[idx+1] = newstd[idx].name;
-		hdw->std_info_enum.def.type_enum.value_names =
-						hdw->std_enum_names;
-		hdw->std_info_enum.def.type_enum.count = std_cnt+1;
-	} else {
-		pvr2_trace(
-			PVR2_TRACE_ERROR_LEGS,
-			"WARNING: Failed to alloc memory for names");
-		hdw->std_info_enum.def.type_enum.value_names = NULL;
-		hdw->std_info_enum.def.type_enum.count = 0;
-	}
-	hdw->std_defs = newstd;
-	hdw->std_enum_cnt = std_cnt+1;
-	hdw->std_enum_cur = 0;
-	hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
-}
-
-
-int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,
-			       struct v4l2_standard *std,
-			       unsigned int idx)
-{
-	int ret = -EINVAL;
-	if (!idx) return ret;
-	LOCK_TAKE(hdw->big_lock); do {
-		if (idx >= hdw->std_enum_cnt) break;
-		idx--;
-		memcpy(std,hdw->std_defs+idx,sizeof(*std));
-		ret = 0;
-	} while (0); LOCK_GIVE(hdw->big_lock);
-	return ret;
-}
-
-
 /* Get the number of defined controls */
 unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw)
 {
@@ -2995,11 +2864,13 @@
 		pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
 	}
 
-int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std)
+v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw)
 {
+	v4l2_std_id std;
+	std = (v4l2_std_id)hdw->std_mask_avail;
 	v4l2_device_call_all(&hdw->v4l2_dev, 0,
-			     video, querystd, std);
-	return 0;
+			     video, querystd, &std);
+	return std;
 }
 
 /* Execute whatever commands are required to update the state of all the
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 6654658..8060fc6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -28,7 +28,6 @@
 
 /* Private internal control ids, look these up with
    pvr2_hdw_get_ctrl_by_id() - these are NOT visible in V4L */
-#define PVR2_CID_STDENUM 1
 #define PVR2_CID_STDCUR 2
 #define PVR2_CID_STDAVAIL 3
 #define PVR2_CID_INPUT 4
@@ -46,6 +45,7 @@
 #define PVR2_CID_CROPCAPBT 16
 #define PVR2_CID_CROPCAPBW 17
 #define PVR2_CID_CROPCAPBH 18
+#define PVR2_CID_STDDETECT 19
 
 /* Legal values for the INPUT state variable */
 #define PVR2_CVAL_INPUT_TV 0
@@ -210,13 +210,6 @@
 /* Get handle to video output stream */
 struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
 
-/* Emit a video standard struct */
-int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
-			       unsigned int idx);
-
-/* Get the detected video standard */
-int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std);
-
 /* Enable / disable retrieval of CPU firmware or prom contents.  This must
    be enabled before pvr2_hdw_cpufw_get() will function.  Note that doing
    this may prevent the device from running (and leaving this mode may
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index e1111d9..7bddfae 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -107,7 +107,6 @@
 		// This should really be V4L2_PIX_FMT_MPEG, but xawtv
 		// breaks when I do that.
 		.pixelformat    = 0, // V4L2_PIX_FMT_MPEG,
-		.reserved       = { 0, 0, 0, 0 }
 	}
 };
 
@@ -145,741 +144,740 @@
 				.start = { 0, 0 },
 				.count = { 0, 0 },
 				.flags = 0,
-				.reserved = { 0, 0 }
 			}
 		}
 	}
 };
 
 
+
 /*
- * pvr_ioctl()
- *
- * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
- *
+ * This is part of Video 4 Linux API. These procedures handle ioctl() calls.
  */
-static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+	memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+	strlcpy(cap->bus_info, pvr2_hdw_get_bus_info(hdw),
+			sizeof(cap->bus_info));
+	strlcpy(cap->card, pvr2_hdw_get_desc(hdw), sizeof(cap->card));
+	return 0;
+}
+
+static int pvr2_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
 {
 	struct pvr2_v4l2_fh *fh = file->private_data;
 	struct pvr2_v4l2 *vp = fh->vhead;
-	struct pvr2_v4l2_dev *pdi = fh->pdi;
+
+	*p = v4l2_prio_max(&vp->prio);
+	return 0;
+}
+
+static int pvr2_s_priority(struct file *file, void *priv, enum v4l2_priority prio)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_v4l2 *vp = fh->vhead;
+
+	return v4l2_prio_change(&vp->prio, &fh->prio, prio);
+}
+
+static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
 	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
-	long ret = -EINVAL;
+	int val = 0;
+	int ret;
 
-	if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
-		v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
-	}
+	ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), &val);
+	*std = val;
+	return ret;
+}
 
-	if (!pvr2_hdw_dev_ok(hdw)) {
-		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-			   "ioctl failed - bad or no context");
-		return -EFAULT;
-	}
+int pvr2_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
 
-	/* check priority */
-	switch (cmd) {
-	case VIDIOC_S_CTRL:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_S_FREQUENCY:
-		ret = v4l2_prio_check(&vp->prio, fh->prio);
-		if (ret)
-			return ret;
-	}
+	return pvr2_ctrl_set_value(
+		pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), *std);
+}
 
-	switch (cmd) {
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability *cap = arg;
+static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	int val = 0;
+	int ret;
 
-		memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
-		strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
-			sizeof(cap->bus_info));
-		strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
+	ret = pvr2_ctrl_get_value(
+		pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDDETECT), &val);
+	*std = val;
+	return ret;
+}
 
-		ret = 0;
+static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	struct pvr2_ctrl *cptr;
+	struct v4l2_input tmp;
+	unsigned int cnt;
+	int val;
+	int ret;
+
+	cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.index = vi->index;
+	ret = 0;
+	if (vi->index >= fh->input_cnt)
+		return -EINVAL;
+	val = fh->input_map[vi->index];
+	switch (val) {
+	case PVR2_CVAL_INPUT_TV:
+	case PVR2_CVAL_INPUT_DTV:
+	case PVR2_CVAL_INPUT_RADIO:
+		tmp.type = V4L2_INPUT_TYPE_TUNER;
 		break;
-	}
-
-	case VIDIOC_G_PRIORITY:
-	{
-		enum v4l2_priority *p = arg;
-
-		*p = v4l2_prio_max(&vp->prio);
-		ret = 0;
+	case PVR2_CVAL_INPUT_SVIDEO:
+	case PVR2_CVAL_INPUT_COMPOSITE:
+		tmp.type = V4L2_INPUT_TYPE_CAMERA;
 		break;
+	default:
+		return -EINVAL;
 	}
 
-	case VIDIOC_S_PRIORITY:
-	{
-		enum v4l2_priority *prio = arg;
+	cnt = 0;
+	pvr2_ctrl_get_valname(cptr, val,
+			tmp.name, sizeof(tmp.name) - 1, &cnt);
+	tmp.name[cnt] = 0;
 
-		ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
-		break;
-	}
+	/* Don't bother with audioset, since this driver currently
+	   always switches the audio whenever the video is
+	   switched. */
 
-	case VIDIOC_ENUMSTD:
-	{
-		struct v4l2_standard *vs = (struct v4l2_standard *)arg;
-		int idx = vs->index;
-		ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
-		break;
-	}
+	/* Handling std is a tougher problem.  It doesn't make
+	   sense in cases where a device might be multi-standard.
+	   We could just copy out the current value for the
+	   standard, but it can change over time.  For now just
+	   leave it zero. */
+	*vi = tmp;
+	return 0;
+}
 
-	case VIDIOC_QUERYSTD:
-	{
-		v4l2_std_id *std = arg;
-		*std = V4L2_STD_ALL;
-		ret = pvr2_hdw_get_detected_std(hdw, std);
-		break;
-	}
+static int pvr2_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	unsigned int idx;
+	struct pvr2_ctrl *cptr;
+	int val;
+	int ret;
 
-	case VIDIOC_G_STD:
-	{
-		int val = 0;
-		ret = pvr2_ctrl_get_value(
-			pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
-		*(v4l2_std_id *)arg = val;
-		break;
-	}
-
-	case VIDIOC_S_STD:
-	{
-		ret = pvr2_ctrl_set_value(
-			pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
-			*(v4l2_std_id *)arg);
-		break;
-	}
-
-	case VIDIOC_ENUMINPUT:
-	{
-		struct pvr2_ctrl *cptr;
-		struct v4l2_input *vi = (struct v4l2_input *)arg;
-		struct v4l2_input tmp;
-		unsigned int cnt;
-		int val;
-
-		cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
-
-		memset(&tmp,0,sizeof(tmp));
-		tmp.index = vi->index;
-		ret = 0;
-		if (vi->index >= fh->input_cnt) {
-			ret = -EINVAL;
+	cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
+	val = 0;
+	ret = pvr2_ctrl_get_value(cptr, &val);
+	*i = 0;
+	for (idx = 0; idx < fh->input_cnt; idx++) {
+		if (fh->input_map[idx] == val) {
+			*i = idx;
 			break;
 		}
-		val = fh->input_map[vi->index];
-		switch (val) {
-		case PVR2_CVAL_INPUT_TV:
-		case PVR2_CVAL_INPUT_DTV:
-		case PVR2_CVAL_INPUT_RADIO:
-			tmp.type = V4L2_INPUT_TYPE_TUNER;
-			break;
-		case PVR2_CVAL_INPUT_SVIDEO:
-		case PVR2_CVAL_INPUT_COMPOSITE:
-			tmp.type = V4L2_INPUT_TYPE_CAMERA;
-			break;
-		default:
-			ret = -EINVAL;
-			break;
-		}
-		if (ret < 0) break;
-
-		cnt = 0;
-		pvr2_ctrl_get_valname(cptr,val,
-				      tmp.name,sizeof(tmp.name)-1,&cnt);
-		tmp.name[cnt] = 0;
-
-		/* Don't bother with audioset, since this driver currently
-		   always switches the audio whenever the video is
-		   switched. */
-
-		/* Handling std is a tougher problem.  It doesn't make
-		   sense in cases where a device might be multi-standard.
-		   We could just copy out the current value for the
-		   standard, but it can change over time.  For now just
-		   leave it zero. */
-
-		memcpy(vi, &tmp, sizeof(tmp));
-
-		ret = 0;
-		break;
-	}
-
-	case VIDIOC_G_INPUT:
-	{
-		unsigned int idx;
-		struct pvr2_ctrl *cptr;
-		struct v4l2_input *vi = (struct v4l2_input *)arg;
-		int val;
-		cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
-		val = 0;
-		ret = pvr2_ctrl_get_value(cptr,&val);
-		vi->index = 0;
-		for (idx = 0; idx < fh->input_cnt; idx++) {
-			if (fh->input_map[idx] == val) {
-				vi->index = idx;
-				break;
-			}
-		}
-		break;
-	}
-
-	case VIDIOC_S_INPUT:
-	{
-		struct v4l2_input *vi = (struct v4l2_input *)arg;
-		if (vi->index >= fh->input_cnt) {
-			ret = -ERANGE;
-			break;
-		}
-		ret = pvr2_ctrl_set_value(
-			pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
-			fh->input_map[vi->index]);
-		break;
-	}
-
-	case VIDIOC_ENUMAUDIO:
-	{
-		/* pkt: FIXME: We are returning one "fake" input here
-		   which could very well be called "whatever_we_like".
-		   This is for apps that want to see an audio input
-		   just to feel comfortable, as well as to test if
-		   it can do stereo or sth. There is actually no guarantee
-		   that the actual audio input cannot change behind the app's
-		   back, but most applications should not mind that either.
-
-		   Hopefully, mplayer people will work with us on this (this
-		   whole mess is to support mplayer pvr://), or Hans will come
-		   up with a more standard way to say "we have inputs but we
-		   don 't want you to change them independent of video" which
-		   will sort this mess.
-		 */
-		struct v4l2_audio *vin = arg;
-		ret = -EINVAL;
-		if (vin->index > 0) break;
-		strncpy(vin->name, "PVRUSB2 Audio",14);
-		vin->capability = V4L2_AUDCAP_STEREO;
-		ret = 0;
-		break;
-		break;
-	}
-
-	case VIDIOC_G_AUDIO:
-	{
-		/* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
-		struct v4l2_audio *vin = arg;
-		memset(vin,0,sizeof(*vin));
-		vin->index = 0;
-		strncpy(vin->name, "PVRUSB2 Audio",14);
-		vin->capability = V4L2_AUDCAP_STEREO;
-		ret = 0;
-		break;
-	}
-
-	case VIDIOC_G_TUNER:
-	{
-		struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
-
-		if (vt->index != 0) break; /* Only answer for the 1st tuner */
-
-		pvr2_hdw_execute_tuner_poll(hdw);
-		ret = pvr2_hdw_get_tuner_status(hdw,vt);
-		break;
-	}
-
-	case VIDIOC_S_TUNER:
-	{
-		struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
-
-		if (vt->index != 0)
-			break;
-
-		ret = pvr2_ctrl_set_value(
-			pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
-			vt->audmode);
-		break;
-	}
-
-	case VIDIOC_S_FREQUENCY:
-	{
-		const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
-		unsigned long fv;
-		struct v4l2_tuner vt;
-		int cur_input;
-		struct pvr2_ctrl *ctrlp;
-		ret = pvr2_hdw_get_tuner_status(hdw,&vt);
-		if (ret != 0) break;
-		ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
-		ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
-		if (ret != 0) break;
-		if (vf->type == V4L2_TUNER_RADIO) {
-			if (cur_input != PVR2_CVAL_INPUT_RADIO) {
-				pvr2_ctrl_set_value(ctrlp,
-						    PVR2_CVAL_INPUT_RADIO);
-			}
-		} else {
-			if (cur_input == PVR2_CVAL_INPUT_RADIO) {
-				pvr2_ctrl_set_value(ctrlp,
-						    PVR2_CVAL_INPUT_TV);
-			}
-		}
-		fv = vf->frequency;
-		if (vt.capability & V4L2_TUNER_CAP_LOW) {
-			fv = (fv * 125) / 2;
-		} else {
-			fv = fv * 62500;
-		}
-		ret = pvr2_ctrl_set_value(
-			pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
-		break;
-	}
-
-	case VIDIOC_G_FREQUENCY:
-	{
-		struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
-		int val = 0;
-		int cur_input;
-		struct v4l2_tuner vt;
-		ret = pvr2_hdw_get_tuner_status(hdw,&vt);
-		if (ret != 0) break;
-		ret = pvr2_ctrl_get_value(
-			pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
-			&val);
-		if (ret != 0) break;
-		pvr2_ctrl_get_value(
-			pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
-			&cur_input);
-		if (cur_input == PVR2_CVAL_INPUT_RADIO) {
-			vf->type = V4L2_TUNER_RADIO;
-		} else {
-			vf->type = V4L2_TUNER_ANALOG_TV;
-		}
-		if (vt.capability & V4L2_TUNER_CAP_LOW) {
-			val = (val * 2) / 125;
-		} else {
-			val /= 62500;
-		}
-		vf->frequency = val;
-		break;
-	}
-
-	case VIDIOC_ENUM_FMT:
-	{
-		struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
-
-		/* Only one format is supported : mpeg.*/
-		if (fd->index != 0)
-			break;
-
-		memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
-		ret = 0;
-		break;
-	}
-
-	case VIDIOC_G_FMT:
-	{
-		struct v4l2_format *vf = (struct v4l2_format *)arg;
-		int val;
-		switch(vf->type) {
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
-			       sizeof(struct v4l2_format));
-			val = 0;
-			pvr2_ctrl_get_value(
-				pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
-				&val);
-			vf->fmt.pix.width = val;
-			val = 0;
-			pvr2_ctrl_get_value(
-				pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
-				&val);
-			vf->fmt.pix.height = val;
-			ret = 0;
-			break;
-		case V4L2_BUF_TYPE_VBI_CAPTURE:
-			// ????? Still need to figure out to do VBI correctly
-			ret = -EINVAL;
-			break;
-		default:
-			ret = -EINVAL;
-			break;
-		}
-		break;
-	}
-
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_S_FMT:
-	{
-		struct v4l2_format *vf = (struct v4l2_format *)arg;
-
-		ret = 0;
-		switch(vf->type) {
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-			int lmin,lmax,ldef;
-			struct pvr2_ctrl *hcp,*vcp;
-			int h = vf->fmt.pix.height;
-			int w = vf->fmt.pix.width;
-			hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
-			vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
-
-			lmin = pvr2_ctrl_get_min(hcp);
-			lmax = pvr2_ctrl_get_max(hcp);
-			pvr2_ctrl_get_def(hcp, &ldef);
-			if (w == -1) {
-				w = ldef;
-			} else if (w < lmin) {
-				w = lmin;
-			} else if (w > lmax) {
-				w = lmax;
-			}
-			lmin = pvr2_ctrl_get_min(vcp);
-			lmax = pvr2_ctrl_get_max(vcp);
-			pvr2_ctrl_get_def(vcp, &ldef);
-			if (h == -1) {
-				h = ldef;
-			} else if (h < lmin) {
-				h = lmin;
-			} else if (h > lmax) {
-				h = lmax;
-			}
-
-			memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
-			       sizeof(struct v4l2_format));
-			vf->fmt.pix.width = w;
-			vf->fmt.pix.height = h;
-
-			if (cmd == VIDIOC_S_FMT) {
-				pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
-				pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
-			}
-		} break;
-		case V4L2_BUF_TYPE_VBI_CAPTURE:
-			// ????? Still need to figure out to do VBI correctly
-			ret = -EINVAL;
-			break;
-		default:
-			ret = -EINVAL;
-			break;
-		}
-		break;
-	}
-
-	case VIDIOC_STREAMON:
-	{
-		if (!fh->pdi->stream) {
-			/* No stream defined for this node.  This means
-			   that we're not currently allowed to stream from
-			   this node. */
-			ret = -EPERM;
-			break;
-		}
-		ret = pvr2_hdw_set_stream_type(hdw,pdi->config);
-		if (ret < 0) return ret;
-		ret = pvr2_hdw_set_streaming(hdw,!0);
-		break;
-	}
-
-	case VIDIOC_STREAMOFF:
-	{
-		if (!fh->pdi->stream) {
-			/* No stream defined for this node.  This means
-			   that we're not currently allowed to stream from
-			   this node. */
-			ret = -EPERM;
-			break;
-		}
-		ret = pvr2_hdw_set_streaming(hdw,0);
-		break;
-	}
-
-	case VIDIOC_QUERYCTRL:
-	{
-		struct pvr2_ctrl *cptr;
-		int val;
-		struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
-		ret = 0;
-		if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
-			cptr = pvr2_hdw_get_ctrl_nextv4l(
-				hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
-			if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
-		} else {
-			cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
-		}
-		if (!cptr) {
-			pvr2_trace(PVR2_TRACE_V4LIOCTL,
-				   "QUERYCTRL id=0x%x not implemented here",
-				   vc->id);
-			ret = -EINVAL;
-			break;
-		}
-
-		pvr2_trace(PVR2_TRACE_V4LIOCTL,
-			   "QUERYCTRL id=0x%x mapping name=%s (%s)",
-			   vc->id,pvr2_ctrl_get_name(cptr),
-			   pvr2_ctrl_get_desc(cptr));
-		strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
-		vc->flags = pvr2_ctrl_get_v4lflags(cptr);
-		pvr2_ctrl_get_def(cptr, &val);
-		vc->default_value = val;
-		switch (pvr2_ctrl_get_type(cptr)) {
-		case pvr2_ctl_enum:
-			vc->type = V4L2_CTRL_TYPE_MENU;
-			vc->minimum = 0;
-			vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
-			vc->step = 1;
-			break;
-		case pvr2_ctl_bool:
-			vc->type = V4L2_CTRL_TYPE_BOOLEAN;
-			vc->minimum = 0;
-			vc->maximum = 1;
-			vc->step = 1;
-			break;
-		case pvr2_ctl_int:
-			vc->type = V4L2_CTRL_TYPE_INTEGER;
-			vc->minimum = pvr2_ctrl_get_min(cptr);
-			vc->maximum = pvr2_ctrl_get_max(cptr);
-			vc->step = 1;
-			break;
-		default:
-			pvr2_trace(PVR2_TRACE_V4LIOCTL,
-				   "QUERYCTRL id=0x%x name=%s not mappable",
-				   vc->id,pvr2_ctrl_get_name(cptr));
-			ret = -EINVAL;
-			break;
-		}
-		break;
-	}
-
-	case VIDIOC_QUERYMENU:
-	{
-		struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
-		unsigned int cnt = 0;
-		ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
-					    vm->index,
-					    vm->name,sizeof(vm->name)-1,
-					    &cnt);
-		vm->name[cnt] = 0;
-		break;
-	}
-
-	case VIDIOC_G_CTRL:
-	{
-		struct v4l2_control *vc = (struct v4l2_control *)arg;
-		int val = 0;
-		ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
-					  &val);
-		vc->value = val;
-		break;
-	}
-
-	case VIDIOC_S_CTRL:
-	{
-		struct v4l2_control *vc = (struct v4l2_control *)arg;
-		ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
-					  vc->value);
-		break;
-	}
-
-	case VIDIOC_G_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *ctls =
-			(struct v4l2_ext_controls *)arg;
-		struct v4l2_ext_control *ctrl;
-		unsigned int idx;
-		int val;
-		ret = 0;
-		for (idx = 0; idx < ctls->count; idx++) {
-			ctrl = ctls->controls + idx;
-			ret = pvr2_ctrl_get_value(
-				pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
-			if (ret) {
-				ctls->error_idx = idx;
-				break;
-			}
-			/* Ensure that if read as a 64 bit value, the user
-			   will still get a hopefully sane value */
-			ctrl->value64 = 0;
-			ctrl->value = val;
-		}
-		break;
-	}
-
-	case VIDIOC_S_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *ctls =
-			(struct v4l2_ext_controls *)arg;
-		struct v4l2_ext_control *ctrl;
-		unsigned int idx;
-		ret = 0;
-		for (idx = 0; idx < ctls->count; idx++) {
-			ctrl = ctls->controls + idx;
-			ret = pvr2_ctrl_set_value(
-				pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
-				ctrl->value);
-			if (ret) {
-				ctls->error_idx = idx;
-				break;
-			}
-		}
-		break;
-	}
-
-	case VIDIOC_TRY_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *ctls =
-			(struct v4l2_ext_controls *)arg;
-		struct v4l2_ext_control *ctrl;
-		struct pvr2_ctrl *pctl;
-		unsigned int idx;
-		/* For the moment just validate that the requested control
-		   actually exists. */
-		ret = 0;
-		for (idx = 0; idx < ctls->count; idx++) {
-			ctrl = ctls->controls + idx;
-			pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
-			if (!pctl) {
-				ret = -EINVAL;
-				ctls->error_idx = idx;
-				break;
-			}
-		}
-		break;
-	}
-
-	case VIDIOC_CROPCAP:
-	{
-		struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
-		if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = pvr2_hdw_get_cropcap(hdw, cap);
-		cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
-		break;
-	}
-	case VIDIOC_G_CROP:
-	{
-		struct v4l2_crop *crop = (struct v4l2_crop *)arg;
-		int val = 0;
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = pvr2_ctrl_get_value(
-			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
-		if (ret != 0) {
-			ret = -EINVAL;
-			break;
-		}
-		crop->c.left = val;
-		ret = pvr2_ctrl_get_value(
-			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
-		if (ret != 0) {
-			ret = -EINVAL;
-			break;
-		}
-		crop->c.top = val;
-		ret = pvr2_ctrl_get_value(
-			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
-		if (ret != 0) {
-			ret = -EINVAL;
-			break;
-		}
-		crop->c.width = val;
-		ret = pvr2_ctrl_get_value(
-			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
-		if (ret != 0) {
-			ret = -EINVAL;
-			break;
-		}
-		crop->c.height = val;
-	}
-	case VIDIOC_S_CROP:
-	{
-		struct v4l2_crop *crop = (struct v4l2_crop *)arg;
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = pvr2_ctrl_set_value(
-			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
-			crop->c.left);
-		if (ret != 0) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = pvr2_ctrl_set_value(
-			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
-			crop->c.top);
-		if (ret != 0) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = pvr2_ctrl_set_value(
-			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
-			crop->c.width);
-		if (ret != 0) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = pvr2_ctrl_set_value(
-			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
-			crop->c.height);
-		if (ret != 0) {
-			ret = -EINVAL;
-			break;
-		}
-	}
-	case VIDIOC_LOG_STATUS:
-	{
-		pvr2_hdw_trigger_module_log(hdw);
-		ret = 0;
-		break;
-	}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	case VIDIOC_DBG_S_REGISTER:
-	case VIDIOC_DBG_G_REGISTER:
-	{
-		u64 val;
-		struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg;
-		if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
-		ret = pvr2_hdw_register_access(
-			hdw, &req->match, req->reg,
-			cmd == VIDIOC_DBG_S_REGISTER, &val);
-		if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
-		break;
-	}
-#endif
-
-	default :
-		ret = -ENOTTY;
-		break;
-	}
-
-	pvr2_hdw_commit_ctl(hdw);
-
-	if (ret < 0) {
-		if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
-			pvr2_trace(PVR2_TRACE_V4LIOCTL,
-				   "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
-		} else {
-			if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
-				pvr2_trace(PVR2_TRACE_V4LIOCTL,
-					   "pvr2_v4l2_do_ioctl failure, ret=%ld"
-					   " command was:", ret);
-				v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
-						cmd);
-			}
-		}
-	} else {
-		pvr2_trace(PVR2_TRACE_V4LIOCTL,
-			   "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
-			   ret, ret);
 	}
 	return ret;
 }
 
+static int pvr2_s_input(struct file *file, void *priv, unsigned int inp)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+	if (inp >= fh->input_cnt)
+		return -EINVAL;
+	return pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT),
+			fh->input_map[inp]);
+}
+
+static int pvr2_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin)
+{
+	/* pkt: FIXME: We are returning one "fake" input here
+	   which could very well be called "whatever_we_like".
+	   This is for apps that want to see an audio input
+	   just to feel comfortable, as well as to test if
+	   it can do stereo or sth. There is actually no guarantee
+	   that the actual audio input cannot change behind the app's
+	   back, but most applications should not mind that either.
+
+	   Hopefully, mplayer people will work with us on this (this
+	   whole mess is to support mplayer pvr://), or Hans will come
+	   up with a more standard way to say "we have inputs but we
+	   don 't want you to change them independent of video" which
+	   will sort this mess.
+	 */
+
+	if (vin->index > 0)
+		return -EINVAL;
+	strncpy(vin->name, "PVRUSB2 Audio", 14);
+	vin->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int pvr2_g_audio(struct file *file, void *priv, struct v4l2_audio *vin)
+{
+	/* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
+	vin->index = 0;
+	strncpy(vin->name, "PVRUSB2 Audio", 14);
+	vin->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int pvr2_s_audio(struct file *file, void *priv, struct v4l2_audio *vout)
+{
+	if (vout->index)
+		return -EINVAL;
+	return 0;
+}
+
+static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+	if (vt->index != 0)
+		return -EINVAL; /* Only answer for the 1st tuner */
+
+	pvr2_hdw_execute_tuner_poll(hdw);
+	return pvr2_hdw_get_tuner_status(hdw, vt);
+}
+
+static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	return pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_AUDIOMODE),
+			vt->audmode);
+}
+
+int pvr2_s_frequency(struct file *file, void *priv, struct v4l2_frequency *vf)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	unsigned long fv;
+	struct v4l2_tuner vt;
+	int cur_input;
+	struct pvr2_ctrl *ctrlp;
+	int ret;
+
+	ret = pvr2_hdw_get_tuner_status(hdw, &vt);
+	if (ret != 0)
+		return ret;
+	ctrlp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
+	ret = pvr2_ctrl_get_value(ctrlp, &cur_input);
+	if (ret != 0)
+		return ret;
+	if (vf->type == V4L2_TUNER_RADIO) {
+		if (cur_input != PVR2_CVAL_INPUT_RADIO)
+			pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_RADIO);
+	} else {
+		if (cur_input == PVR2_CVAL_INPUT_RADIO)
+			pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_TV);
+	}
+	fv = vf->frequency;
+	if (vt.capability & V4L2_TUNER_CAP_LOW)
+		fv = (fv * 125) / 2;
+	else
+		fv = fv * 62500;
+	return pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
+}
+
+static int pvr2_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	int val = 0;
+	int cur_input;
+	struct v4l2_tuner vt;
+	int ret;
+
+	ret = pvr2_hdw_get_tuner_status(hdw, &vt);
+	if (ret != 0)
+		return ret;
+	ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_FREQUENCY),
+			&val);
+	if (ret != 0)
+		return ret;
+	pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT),
+			&cur_input);
+	if (cur_input == PVR2_CVAL_INPUT_RADIO)
+		vf->type = V4L2_TUNER_RADIO;
+	else
+		vf->type = V4L2_TUNER_ANALOG_TV;
+	if (vt.capability & V4L2_TUNER_CAP_LOW)
+		val = (val * 2) / 125;
+	else
+		val /= 62500;
+	vf->frequency = val;
+	return 0;
+}
+
+static int pvr2_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fd)
+{
+	/* Only one format is supported : mpeg.*/
+	if (fd->index != 0)
+		return -EINVAL;
+
+	memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
+	return 0;
+}
+
+static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	int val;
+
+	memcpy(vf, &pvr_format[PVR_FORMAT_PIX], sizeof(struct v4l2_format));
+	val = 0;
+	pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES),
+			&val);
+	vf->fmt.pix.width = val;
+	val = 0;
+	pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES),
+			&val);
+	vf->fmt.pix.height = val;
+	return 0;
+}
+
+static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	int lmin, lmax, ldef;
+	struct pvr2_ctrl *hcp, *vcp;
+	int h = vf->fmt.pix.height;
+	int w = vf->fmt.pix.width;
+
+	hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES);
+	vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES);
+
+	lmin = pvr2_ctrl_get_min(hcp);
+	lmax = pvr2_ctrl_get_max(hcp);
+	pvr2_ctrl_get_def(hcp, &ldef);
+	if (w == -1)
+		w = ldef;
+	else if (w < lmin)
+		w = lmin;
+	else if (w > lmax)
+		w = lmax;
+	lmin = pvr2_ctrl_get_min(vcp);
+	lmax = pvr2_ctrl_get_max(vcp);
+	pvr2_ctrl_get_def(vcp, &ldef);
+	if (h == -1)
+		h = ldef;
+	else if (h < lmin)
+		h = lmin;
+	else if (h > lmax)
+		h = lmax;
+
+	memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+			sizeof(struct v4l2_format));
+	vf->fmt.pix.width = w;
+	vf->fmt.pix.height = h;
+	return 0;
+}
+
+static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	struct pvr2_ctrl *hcp, *vcp;
+	int ret = pvr2_try_fmt_vid_cap(file, fh, vf);
+
+	if (ret)
+		return ret;
+	hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES);
+	vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES);
+	pvr2_ctrl_set_value(hcp, vf->fmt.pix.width);
+	pvr2_ctrl_set_value(vcp, vf->fmt.pix.height);
+	return 0;
+}
+
+static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	struct pvr2_v4l2_dev *pdi = fh->pdi;
+	int ret;
+
+	if (!fh->pdi->stream) {
+		/* No stream defined for this node.  This means
+		   that we're not currently allowed to stream from
+		   this node. */
+		return -EPERM;
+	}
+	ret = pvr2_hdw_set_stream_type(hdw, pdi->config);
+	if (ret < 0)
+		return ret;
+	return pvr2_hdw_set_streaming(hdw, !0);
+}
+
+static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+	if (!fh->pdi->stream) {
+		/* No stream defined for this node.  This means
+		   that we're not currently allowed to stream from
+		   this node. */
+		return -EPERM;
+	}
+	return pvr2_hdw_set_streaming(hdw, 0);
+}
+
+static int pvr2_queryctrl(struct file *file, void *priv,
+		struct v4l2_queryctrl *vc)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	struct pvr2_ctrl *cptr;
+	int val;
+	int ret;
+
+	ret = 0;
+	if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+		cptr = pvr2_hdw_get_ctrl_nextv4l(
+				hdw, (vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
+		if (cptr)
+			vc->id = pvr2_ctrl_get_v4lid(cptr);
+	} else {
+		cptr = pvr2_hdw_get_ctrl_v4l(hdw, vc->id);
+	}
+	if (!cptr) {
+		pvr2_trace(PVR2_TRACE_V4LIOCTL,
+				"QUERYCTRL id=0x%x not implemented here",
+				vc->id);
+		return -EINVAL;
+	}
+
+	pvr2_trace(PVR2_TRACE_V4LIOCTL,
+			"QUERYCTRL id=0x%x mapping name=%s (%s)",
+			vc->id, pvr2_ctrl_get_name(cptr),
+			pvr2_ctrl_get_desc(cptr));
+	strlcpy(vc->name, pvr2_ctrl_get_desc(cptr), sizeof(vc->name));
+	vc->flags = pvr2_ctrl_get_v4lflags(cptr);
+	pvr2_ctrl_get_def(cptr, &val);
+	vc->default_value = val;
+	switch (pvr2_ctrl_get_type(cptr)) {
+	case pvr2_ctl_enum:
+		vc->type = V4L2_CTRL_TYPE_MENU;
+		vc->minimum = 0;
+		vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
+		vc->step = 1;
+		break;
+	case pvr2_ctl_bool:
+		vc->type = V4L2_CTRL_TYPE_BOOLEAN;
+		vc->minimum = 0;
+		vc->maximum = 1;
+		vc->step = 1;
+		break;
+	case pvr2_ctl_int:
+		vc->type = V4L2_CTRL_TYPE_INTEGER;
+		vc->minimum = pvr2_ctrl_get_min(cptr);
+		vc->maximum = pvr2_ctrl_get_max(cptr);
+		vc->step = 1;
+		break;
+	default:
+		pvr2_trace(PVR2_TRACE_V4LIOCTL,
+				"QUERYCTRL id=0x%x name=%s not mappable",
+				vc->id, pvr2_ctrl_get_name(cptr));
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu *vm)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	unsigned int cnt = 0;
+	int ret;
+
+	ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw, vm->id),
+			vm->index,
+			vm->name, sizeof(vm->name) - 1,
+			&cnt);
+	vm->name[cnt] = 0;
+	return ret;
+}
+
+static int pvr2_g_ctrl(struct file *file, void *priv, struct v4l2_control *vc)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	int val = 0;
+	int ret;
+
+	ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id),
+			&val);
+	vc->value = val;
+	return ret;
+}
+
+static int pvr2_s_ctrl(struct file *file, void *priv, struct v4l2_control *vc)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+	return pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id),
+			vc->value);
+}
+
+static int pvr2_g_ext_ctrls(struct file *file, void *priv,
+					struct v4l2_ext_controls *ctls)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	struct v4l2_ext_control *ctrl;
+	unsigned int idx;
+	int val;
+	int ret;
+
+	ret = 0;
+	for (idx = 0; idx < ctls->count; idx++) {
+		ctrl = ctls->controls + idx;
+		ret = pvr2_ctrl_get_value(
+				pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id), &val);
+		if (ret) {
+			ctls->error_idx = idx;
+			return ret;
+		}
+		/* Ensure that if read as a 64 bit value, the user
+		   will still get a hopefully sane value */
+		ctrl->value64 = 0;
+		ctrl->value = val;
+	}
+	return 0;
+}
+
+static int pvr2_s_ext_ctrls(struct file *file, void *priv,
+		struct v4l2_ext_controls *ctls)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	struct v4l2_ext_control *ctrl;
+	unsigned int idx;
+	int ret;
+
+	ret = 0;
+	for (idx = 0; idx < ctls->count; idx++) {
+		ctrl = ctls->controls + idx;
+		ret = pvr2_ctrl_set_value(
+				pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id),
+				ctrl->value);
+		if (ret) {
+			ctls->error_idx = idx;
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int pvr2_try_ext_ctrls(struct file *file, void *priv,
+		struct v4l2_ext_controls *ctls)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	struct v4l2_ext_control *ctrl;
+	struct pvr2_ctrl *pctl;
+	unsigned int idx;
+	int ret;
+
+	/* For the moment just validate that the requested control
+	   actually exists. */
+	ret = 0;
+	for (idx = 0; idx < ctls->count; idx++) {
+		ctrl = ctls->controls + idx;
+		pctl = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id);
+		if (!pctl) {
+			ctls->error_idx = idx;
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int pvr2_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	int ret;
+
+	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	ret = pvr2_hdw_get_cropcap(hdw, cap);
+	cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
+	return ret;
+}
+
+static int pvr2_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	int val = 0;
+	int ret;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
+	if (ret != 0)
+		return -EINVAL;
+	crop->c.left = val;
+	ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
+	if (ret != 0)
+		return -EINVAL;
+	crop->c.top = val;
+	ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
+	if (ret != 0)
+		return -EINVAL;
+	crop->c.width = val;
+	ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
+	if (ret != 0)
+		return -EINVAL;
+	crop->c.height = val;
+	return 0;
+}
+
+static int pvr2_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	struct v4l2_cropcap cap;
+	int ret;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	ret = pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
+			crop->c.left);
+	if (ret != 0)
+		return -EINVAL;
+	ret = pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
+			crop->c.top);
+	if (ret != 0)
+		return -EINVAL;
+	ret = pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
+			crop->c.width);
+	if (ret != 0)
+		return -EINVAL;
+	ret = pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
+			crop->c.height);
+	if (ret != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int pvr2_log_status(struct file *file, void *priv)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+	pvr2_hdw_trigger_module_log(hdw);
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int pvr2_g_register(struct file *file, void *priv, struct v4l2_dbg_register *req)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	u64 val;
+	int ret;
+
+	ret = pvr2_hdw_register_access(
+			hdw, &req->match, req->reg,
+			0, &val);
+	req->val = val;
+	return ret;
+}
+
+static int pvr2_s_register(struct file *file, void *priv, struct v4l2_dbg_register *req)
+{
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	u64 val;
+	int ret;
+
+	val = req->val;
+	ret = pvr2_hdw_register_access(
+			hdw, &req->match, req->reg,
+			1, &val);
+	return ret;
+}
+#endif
+
+static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
+	.vidioc_querycap		    = pvr2_querycap,
+	.vidioc_g_priority		    = pvr2_g_priority,
+	.vidioc_s_priority		    = pvr2_s_priority,
+	.vidioc_s_audio			    = pvr2_s_audio,
+	.vidioc_g_audio			    = pvr2_g_audio,
+	.vidioc_enumaudio		    = pvr2_enumaudio,
+	.vidioc_enum_input		    = pvr2_enum_input,
+	.vidioc_cropcap			    = pvr2_cropcap,
+	.vidioc_s_crop			    = pvr2_s_crop,
+	.vidioc_g_crop			    = pvr2_g_crop,
+	.vidioc_g_input			    = pvr2_g_input,
+	.vidioc_s_input			    = pvr2_s_input,
+	.vidioc_g_frequency		    = pvr2_g_frequency,
+	.vidioc_s_frequency		    = pvr2_s_frequency,
+	.vidioc_s_tuner			    = pvr2_s_tuner,
+	.vidioc_g_tuner			    = pvr2_g_tuner,
+	.vidioc_g_std			    = pvr2_g_std,
+	.vidioc_s_std			    = pvr2_s_std,
+	.vidioc_querystd		    = pvr2_querystd,
+	.vidioc_log_status		    = pvr2_log_status,
+	.vidioc_enum_fmt_vid_cap	    = pvr2_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap		    = pvr2_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		    = pvr2_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		    = pvr2_try_fmt_vid_cap,
+	.vidioc_streamon		    = pvr2_streamon,
+	.vidioc_streamoff		    = pvr2_streamoff,
+	.vidioc_queryctrl		    = pvr2_queryctrl,
+	.vidioc_querymenu		    = pvr2_querymenu,
+	.vidioc_g_ctrl			    = pvr2_g_ctrl,
+	.vidioc_s_ctrl			    = pvr2_s_ctrl,
+	.vidioc_g_ext_ctrls		    = pvr2_g_ext_ctrls,
+	.vidioc_s_ext_ctrls		    = pvr2_s_ext_ctrls,
+	.vidioc_try_ext_ctrls		    = pvr2_try_ext_ctrls,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register		    = pvr2_g_register,
+	.vidioc_s_register		    = pvr2_s_register,
+#endif
+};
+
 static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
 {
 	struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
@@ -961,7 +959,56 @@
 			   unsigned int cmd, unsigned long arg)
 {
 
-	return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
+	struct pvr2_v4l2_fh *fh = file->private_data;
+	struct pvr2_v4l2 *vp = fh->vhead;
+	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+	long ret = -EINVAL;
+
+	if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL)
+		v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), cmd);
+
+	if (!pvr2_hdw_dev_ok(hdw)) {
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "ioctl failed - bad or no context");
+		return -EFAULT;
+	}
+
+	/* check priority */
+	switch (cmd) {
+	case VIDIOC_S_CTRL:
+	case VIDIOC_S_STD:
+	case VIDIOC_S_INPUT:
+	case VIDIOC_S_TUNER:
+	case VIDIOC_S_FREQUENCY:
+		ret = v4l2_prio_check(&vp->prio, fh->prio);
+		if (ret)
+			return ret;
+	}
+
+	ret = video_ioctl2(file, cmd, arg);
+
+	pvr2_hdw_commit_ctl(hdw);
+
+	if (ret < 0) {
+		if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+			pvr2_trace(PVR2_TRACE_V4LIOCTL,
+				   "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
+		} else {
+			if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+				pvr2_trace(PVR2_TRACE_V4LIOCTL,
+					   "pvr2_v4l2_do_ioctl failure, ret=%ld"
+					   " command was:", ret);
+				v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
+						cmd);
+			}
+		}
+	} else {
+		pvr2_trace(PVR2_TRACE_V4LIOCTL,
+			   "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
+			   ret, ret);
+	}
+	return ret;
+
 }
 
 
@@ -1262,10 +1309,12 @@
 	struct usb_device *usbdev;
 	int mindevnum;
 	int unit_number;
+	struct pvr2_hdw *hdw;
 	int *nr_ptr = NULL;
 	dip->v4lp = vp;
 
-	usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw);
+	hdw = vp->channel.mc_head->hdw;
+	usbdev = pvr2_hdw_get_dev(hdw);
 	dip->v4l_type = v4l_type;
 	switch (v4l_type) {
 	case VFL_TYPE_GRABBER:
@@ -1300,9 +1349,17 @@
 
 	memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
 	dip->devbase.release = pvr2_video_device_release;
+	dip->devbase.ioctl_ops = &pvr2_ioctl_ops;
+	{
+		int val;
+		pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw,
+						PVR2_CID_STDAVAIL), &val);
+		dip->devbase.tvnorms = (v4l2_std_id)val;
+	}
 
 	mindevnum = -1;
-	unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
+	unit_number = pvr2_hdw_get_unit_number(hdw);
 	if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
 		mindevnum = nr_ptr[unit_number];
 	}
@@ -1319,7 +1376,7 @@
 	       video_device_node_name(&dip->devbase),
 	       pvr2_config_get_name(dip->config));
 
-	pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
+	pvr2_hdw_v4l_store_minor_number(hdw,
 					dip->minor_type,dip->devbase.minor);
 }
 
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 122fbd0..ec4e2ef 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -357,6 +357,7 @@
 		PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
 }
 
+/* Both v4l2_lock and vb_queue_lock should be locked when calling this */
 static int pwc_isoc_init(struct pwc_device *pdev)
 {
 	struct usb_device *udev;
@@ -366,9 +367,6 @@
 	struct usb_host_interface *idesc = NULL;
 	int compression = 0; /* 0..3 = uncompressed..high */
 
-	if (pdev->iso_init)
-		return 0;
-
 	pdev->vsync = 0;
 	pdev->vlast_packet_size = 0;
 	pdev->fill_buf = NULL;
@@ -418,7 +416,6 @@
 		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
 		if (urb == NULL) {
 			PWC_ERROR("Failed to allocate urb %d\n", i);
-			pdev->iso_init = 1;
 			pwc_isoc_cleanup(pdev);
 			return -ENOMEM;
 		}
@@ -435,7 +432,6 @@
 							  &urb->transfer_dma);
 		if (urb->transfer_buffer == NULL) {
 			PWC_ERROR("Failed to allocate urb buffer %d\n", i);
-			pdev->iso_init = 1;
 			pwc_isoc_cleanup(pdev);
 			return -ENOMEM;
 		}
@@ -455,13 +451,11 @@
 		ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL);
 		if (ret == -ENOSPC && compression < 3) {
 			compression++;
-			pdev->iso_init = 1;
 			pwc_isoc_cleanup(pdev);
 			goto retry;
 		}
 		if (ret) {
 			PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
-			pdev->iso_init = 1;
 			pwc_isoc_cleanup(pdev);
 			return ret;
 		}
@@ -469,7 +463,6 @@
 	}
 
 	/* All is done... */
-	pdev->iso_init = 1;
 	PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
 	return 0;
 }
@@ -507,21 +500,19 @@
 	}
 }
 
+/* Both v4l2_lock and vb_queue_lock should be locked when calling this */
 static void pwc_isoc_cleanup(struct pwc_device *pdev)
 {
 	PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
 
-	if (pdev->iso_init == 0)
-		return;
-
 	pwc_iso_stop(pdev);
 	pwc_iso_free(pdev);
 	usb_set_interface(pdev->udev, 0, 0);
 
-	pdev->iso_init = 0;
 	PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
 }
 
+/* Must be called with vb_queue_lock hold */
 static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
 {
 	unsigned long flags = 0;
@@ -573,18 +564,13 @@
 
 int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file)
 {
-	int r = 0;
-
-	mutex_lock(&pdev->capt_file_lock);
 	if (pdev->capt_file != NULL &&
-	    pdev->capt_file != file) {
-		r = -EBUSY;
-		goto leave;
-	}
+	    pdev->capt_file != file)
+		return -EBUSY;
+
 	pdev->capt_file = file;
-leave:
-	mutex_unlock(&pdev->capt_file_lock);
-	return r;
+
+	return 0;
 }
 
 static void pwc_video_release(struct v4l2_device *v)
@@ -592,6 +578,7 @@
 	struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
 
 	v4l2_ctrl_handler_free(&pdev->ctrl_handler);
+	v4l2_device_unregister(&pdev->v4l2_dev);
 	kfree(pdev->ctrl_buf);
 	kfree(pdev);
 }
@@ -600,10 +587,25 @@
 {
 	struct pwc_device *pdev = video_drvdata(file);
 
+	/*
+	 * If we're still streaming vb2_queue_release will call stream_stop
+	 * so we must take both the v4l2_lock and the vb_queue_lock.
+	 */
+	if (mutex_lock_interruptible(&pdev->v4l2_lock))
+		return -ERESTARTSYS;
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock)) {
+		mutex_unlock(&pdev->v4l2_lock);
+		return -ERESTARTSYS;
+	}
+
 	if (pdev->capt_file == file) {
 		vb2_queue_release(&pdev->vb_queue);
 		pdev->capt_file = NULL;
 	}
+
+	mutex_unlock(&pdev->vb_queue_lock);
+	mutex_unlock(&pdev->v4l2_lock);
+
 	return v4l2_fh_release(file);
 }
 
@@ -611,35 +613,81 @@
 			      size_t count, loff_t *ppos)
 {
 	struct pwc_device *pdev = video_drvdata(file);
+	int lock_v4l2 = 0;
+	ssize_t ret;
 
-	if (!pdev->udev)
-		return -ENODEV;
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
 
-	if (pwc_test_n_set_capt_file(pdev, file))
-		return -EBUSY;
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret)
+		goto out;
 
-	return vb2_read(&pdev->vb_queue, buf, count, ppos,
-			file->f_flags & O_NONBLOCK);
+	/* stream_start will get called so we must take the v4l2_lock */
+	if (pdev->vb_queue.fileio == NULL)
+		lock_v4l2 = 1;
+
+	/* Use try_lock, since we're taking the locks in the *wrong* order! */
+	if (lock_v4l2 && !mutex_trylock(&pdev->v4l2_lock)) {
+		ret = -ERESTARTSYS;
+		goto out;
+	}
+	ret = vb2_read(&pdev->vb_queue, buf, count, ppos,
+		       file->f_flags & O_NONBLOCK);
+	if (lock_v4l2)
+		mutex_unlock(&pdev->v4l2_lock);
+out:
+	mutex_unlock(&pdev->vb_queue_lock);
+	return ret;
 }
 
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
 {
 	struct pwc_device *pdev = video_drvdata(file);
+	struct vb2_queue *q = &pdev->vb_queue;
+	unsigned long req_events = poll_requested_events(wait);
+	unsigned int ret = POLL_ERR;
+	int lock_v4l2 = 0;
 
-	if (!pdev->udev)
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
 		return POLL_ERR;
 
-	return vb2_poll(&pdev->vb_queue, file, wait);
+	/* Will this start fileio and thus call start_stream? */
+	if ((req_events & (POLLIN | POLLRDNORM)) &&
+	    q->num_buffers == 0 && !q->streaming && q->fileio == NULL) {
+		if (pwc_test_n_set_capt_file(pdev, file))
+			goto out;
+		lock_v4l2 = 1;
+	}
+
+	/* Use try_lock, since we're taking the locks in the *wrong* order! */
+	if (lock_v4l2 && !mutex_trylock(&pdev->v4l2_lock))
+		goto out;
+	ret = vb2_poll(&pdev->vb_queue, file, wait);
+	if (lock_v4l2)
+		mutex_unlock(&pdev->v4l2_lock);
+
+out:
+	if (!pdev->udev)
+		ret |= POLLHUP;
+	mutex_unlock(&pdev->vb_queue_lock);
+	return ret;
 }
 
 static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct pwc_device *pdev = video_drvdata(file);
+	int ret;
 
-	if (pdev->capt_file != file)
-		return -EBUSY;
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
 
-	return vb2_mmap(&pdev->vb_queue, vma);
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret == 0)
+		ret = vb2_mmap(&pdev->vb_queue, vma);
+
+	mutex_unlock(&pdev->vb_queue_lock);
+	return ret;
 }
 
 /***************************************************************************/
@@ -715,12 +763,14 @@
 	struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
 	unsigned long flags = 0;
 
-	spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
 	/* Check the device has not disconnected between prep and queuing */
-	if (pdev->udev)
-		list_add_tail(&buf->list, &pdev->queued_bufs);
-	else
+	if (!pdev->udev) {
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+		return;
+	}
+
+	spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
+	list_add_tail(&buf->list, &pdev->queued_bufs);
 	spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
 }
 
@@ -729,11 +779,8 @@
 	struct pwc_device *pdev = vb2_get_drv_priv(vq);
 	int r;
 
-	mutex_lock(&pdev->udevlock);
-	if (!pdev->udev) {
-		r = -ENODEV;
-		goto leave;
-	}
+	if (!pdev->udev)
+		return -ENODEV;
 
 	/* Turn on camera and set LEDS on */
 	pwc_camera_power(pdev, 1);
@@ -747,8 +794,7 @@
 		/* And cleanup any queued bufs!! */
 		pwc_cleanup_queued_bufs(pdev);
 	}
-leave:
-	mutex_unlock(&pdev->udevlock);
+
 	return r;
 }
 
@@ -756,19 +802,29 @@
 {
 	struct pwc_device *pdev = vb2_get_drv_priv(vq);
 
-	mutex_lock(&pdev->udevlock);
 	if (pdev->udev) {
 		pwc_set_leds(pdev, 0, 0);
 		pwc_camera_power(pdev, 0);
 		pwc_isoc_cleanup(pdev);
 	}
-	mutex_unlock(&pdev->udevlock);
 
 	pwc_cleanup_queued_bufs(pdev);
 
 	return 0;
 }
 
+static void wait_prepare(struct vb2_queue *vq)
+{
+	struct pwc_device *pdev = vb2_get_drv_priv(vq);
+	mutex_unlock(&pdev->vb_queue_lock);
+}
+
+static void wait_finish(struct vb2_queue *vq)
+{
+	struct pwc_device *pdev = vb2_get_drv_priv(vq);
+	mutex_lock(&pdev->vb_queue_lock);
+}
+
 static struct vb2_ops pwc_vb_queue_ops = {
 	.queue_setup		= queue_setup,
 	.buf_init		= buffer_init,
@@ -778,6 +834,8 @@
 	.buf_queue		= buffer_queue,
 	.start_streaming	= start_streaming,
 	.stop_streaming		= stop_streaming,
+	.wait_prepare		= wait_prepare,
+	.wait_finish		= wait_finish,
 };
 
 /***************************************************************************/
@@ -1057,8 +1115,8 @@
 	pdev->features = features;
 	pwc_construct(pdev); /* set min/max sizes correct */
 
-	mutex_init(&pdev->capt_file_lock);
-	mutex_init(&pdev->udevlock);
+	mutex_init(&pdev->v4l2_lock);
+	mutex_init(&pdev->vb_queue_lock);
 	spin_lock_init(&pdev->queued_bufs_lock);
 	INIT_LIST_HEAD(&pdev->queued_bufs);
 
@@ -1130,6 +1188,16 @@
 
 	pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler;
 	pdev->vdev.v4l2_dev = &pdev->v4l2_dev;
+	pdev->vdev.lock = &pdev->v4l2_lock;
+
+	/*
+	 * Don't take v4l2_lock for these ioctls. This improves latency if
+	 * v4l2_lock is taken for a long time, e.g. when changing a control
+	 * value, and a new frame is ready to be dequeued.
+	 */
+	v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_DQBUF);
+	v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_QBUF);
+	v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_QUERYBUF);
 
 	rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1);
 	if (rc < 0) {
@@ -1185,16 +1253,20 @@
 	struct v4l2_device *v = usb_get_intfdata(intf);
 	struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
 
-	mutex_lock(&pdev->udevlock);
+	mutex_lock(&pdev->v4l2_lock);
+
+	mutex_lock(&pdev->vb_queue_lock);
 	/* No need to keep the urbs around after disconnection */
-	pwc_isoc_cleanup(pdev);
+	if (pdev->vb_queue.streaming)
+		pwc_isoc_cleanup(pdev);
 	pdev->udev = NULL;
-	mutex_unlock(&pdev->udevlock);
-
 	pwc_cleanup_queued_bufs(pdev);
+	mutex_unlock(&pdev->vb_queue_lock);
 
+	v4l2_device_disconnect(&pdev->v4l2_dev);
 	video_unregister_device(&pdev->vdev);
-	v4l2_device_unregister(&pdev->v4l2_dev);
+
+	mutex_unlock(&pdev->v4l2_lock);
 
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
 	if (pdev->button_dev)
@@ -1229,15 +1301,4 @@
 MODULE_ALIAS("pwcx");
 MODULE_VERSION( PWC_VERSION );
 
-static int __init usb_pwc_init(void)
-{
-	return usb_register(&pwc_driver);
-}
-
-static void __exit usb_pwc_exit(void)
-{
-	usb_deregister(&pwc_driver);
-}
-
-module_init(usb_pwc_init);
-module_exit(usb_pwc_exit);
+module_usb_driver(pwc_driver);
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 2834e3e..c691e29 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -464,26 +464,24 @@
 	struct pwc_device *pdev = video_drvdata(file);
 	int ret, pixelformat, compression = 0;
 
-	if (pwc_test_n_set_capt_file(pdev, file))
-		return -EBUSY;
-
 	ret = pwc_vidioc_try_fmt(pdev, f);
 	if (ret < 0)
 		return ret;
 
-	pixelformat = f->fmt.pix.pixelformat;
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
 
-	mutex_lock(&pdev->udevlock);
-	if (!pdev->udev) {
-		ret = -ENODEV;
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret)
 		goto leave;
-	}
 
-	if (pdev->iso_init) {
+	if (pdev->vb_queue.streaming) {
 		ret = -EBUSY;
 		goto leave;
 	}
 
+	pixelformat = f->fmt.pix.pixelformat;
+
 	PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
 			"format=%c%c%c%c\n",
 			f->fmt.pix.width, f->fmt.pix.height, pdev->vframes,
@@ -499,7 +497,7 @@
 
 	pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
 leave:
-	mutex_unlock(&pdev->udevlock);
+	mutex_unlock(&pdev->vb_queue_lock);
 	return ret;
 }
 
@@ -507,9 +505,6 @@
 {
 	struct pwc_device *pdev = video_drvdata(file);
 
-	if (!pdev->udev)
-		return -ENODEV;
-
 	strcpy(cap->driver, PWC_NAME);
 	strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card));
 	usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
@@ -540,15 +535,12 @@
 	return i ? -EINVAL : 0;
 }
 
-static int pwc_g_volatile_ctrl_unlocked(struct v4l2_ctrl *ctrl)
+static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct pwc_device *pdev =
 		container_of(ctrl->handler, struct pwc_device, ctrl_handler);
 	int ret = 0;
 
-	if (!pdev->udev)
-		return -ENODEV;
-
 	switch (ctrl->id) {
 	case V4L2_CID_AUTO_WHITE_BALANCE:
 		if (pdev->color_bal_valid &&
@@ -615,18 +607,6 @@
 	return ret;
 }
 
-static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct pwc_device *pdev =
-		container_of(ctrl->handler, struct pwc_device, ctrl_handler);
-	int ret;
-
-	mutex_lock(&pdev->udevlock);
-	ret = pwc_g_volatile_ctrl_unlocked(ctrl);
-	mutex_unlock(&pdev->udevlock);
-	return ret;
-}
-
 static int pwc_set_awb(struct pwc_device *pdev)
 {
 	int ret;
@@ -648,7 +628,7 @@
 		if (pdev->auto_white_balance->val == awb_indoor ||
 		    pdev->auto_white_balance->val == awb_outdoor ||
 		    pdev->auto_white_balance->val == awb_fl)
-			pwc_g_volatile_ctrl_unlocked(pdev->auto_white_balance);
+			pwc_g_volatile_ctrl(pdev->auto_white_balance);
 	}
 	if (pdev->auto_white_balance->val != awb_manual)
 		return 0;
@@ -812,13 +792,6 @@
 		container_of(ctrl->handler, struct pwc_device, ctrl_handler);
 	int ret = 0;
 
-	mutex_lock(&pdev->udevlock);
-
-	if (!pdev->udev) {
-		ret = -ENODEV;
-		goto leave;
-	}
-
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
 		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
@@ -915,8 +888,6 @@
 	if (ret)
 		PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret);
 
-leave:
-	mutex_unlock(&pdev->udevlock);
 	return ret;
 }
 
@@ -949,11 +920,9 @@
 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
-	mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */
 	PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
 			pdev->width, pdev->height);
 	pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
-	mutex_unlock(&pdev->udevlock);
 	return 0;
 }
 
@@ -968,70 +937,98 @@
 		       struct v4l2_requestbuffers *rb)
 {
 	struct pwc_device *pdev = video_drvdata(file);
+	int ret;
 
-	if (pwc_test_n_set_capt_file(pdev, file))
-		return -EBUSY;
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
 
-	return vb2_reqbufs(&pdev->vb_queue, rb);
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret == 0)
+		ret = vb2_reqbufs(&pdev->vb_queue, rb);
+
+	mutex_unlock(&pdev->vb_queue_lock);
+	return ret;
 }
 
 static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
 	struct pwc_device *pdev = video_drvdata(file);
+	int ret;
 
-	return vb2_querybuf(&pdev->vb_queue, buf);
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
+
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret == 0)
+		ret = vb2_querybuf(&pdev->vb_queue, buf);
+
+	mutex_unlock(&pdev->vb_queue_lock);
+	return ret;
 }
 
 static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
 	struct pwc_device *pdev = video_drvdata(file);
+	int ret;
 
-	if (!pdev->udev)
-		return -ENODEV;
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
 
-	if (pdev->capt_file != file)
-		return -EBUSY;
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret == 0)
+		ret = vb2_qbuf(&pdev->vb_queue, buf);
 
-	return vb2_qbuf(&pdev->vb_queue, buf);
+	mutex_unlock(&pdev->vb_queue_lock);
+	return ret;
 }
 
 static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
 	struct pwc_device *pdev = video_drvdata(file);
+	int ret;
 
-	if (!pdev->udev)
-		return -ENODEV;
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
 
-	if (pdev->capt_file != file)
-		return -EBUSY;
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret == 0)
+		ret = vb2_dqbuf(&pdev->vb_queue, buf,
+				file->f_flags & O_NONBLOCK);
 
-	return vb2_dqbuf(&pdev->vb_queue, buf, file->f_flags & O_NONBLOCK);
+	mutex_unlock(&pdev->vb_queue_lock);
+	return ret;
 }
 
 static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
 {
 	struct pwc_device *pdev = video_drvdata(file);
+	int ret;
 
-	if (!pdev->udev)
-		return -ENODEV;
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
 
-	if (pdev->capt_file != file)
-		return -EBUSY;
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret == 0)
+		ret = vb2_streamon(&pdev->vb_queue, i);
 
-	return vb2_streamon(&pdev->vb_queue, i);
+	mutex_unlock(&pdev->vb_queue_lock);
+	return ret;
 }
 
 static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
 {
 	struct pwc_device *pdev = video_drvdata(file);
+	int ret;
 
-	if (!pdev->udev)
-		return -ENODEV;
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
 
-	if (pdev->capt_file != file)
-		return -EBUSY;
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret == 0)
+		ret = vb2_streamoff(&pdev->vb_queue, i);
 
-	return vb2_streamoff(&pdev->vb_queue, i);
+	mutex_unlock(&pdev->vb_queue_lock);
+	return ret;
 }
 
 static int pwc_enum_framesizes(struct file *file, void *fh,
@@ -1119,19 +1116,17 @@
 	    parm->parm.capture.timeperframe.numerator == 0)
 		return -EINVAL;
 
-	if (pwc_test_n_set_capt_file(pdev, file))
-		return -EBUSY;
-
 	fps = parm->parm.capture.timeperframe.denominator /
 	      parm->parm.capture.timeperframe.numerator;
 
-	mutex_lock(&pdev->udevlock);
-	if (!pdev->udev) {
-		ret = -ENODEV;
-		goto leave;
-	}
+	if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+		return -ERESTARTSYS;
 
-	if (pdev->iso_init) {
+	ret = pwc_test_n_set_capt_file(pdev, file);
+	if (ret)
+		goto leave;
+
+	if (pdev->vb_queue.streaming) {
 		ret = -EBUSY;
 		goto leave;
 	}
@@ -1142,7 +1137,7 @@
 	pwc_g_parm(file, fh, parm);
 
 leave:
-	mutex_unlock(&pdev->udevlock);
+	mutex_unlock(&pdev->vb_queue_lock);
 	return ret;
 }
 
@@ -1166,4 +1161,6 @@
 	.vidioc_enum_frameintervals	    = pwc_enum_frameintervals,
 	.vidioc_g_parm			    = pwc_g_parm,
 	.vidioc_s_parm			    = pwc_s_parm,
+	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
 };
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index e4d4d71..d6b5b21 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -221,9 +221,17 @@
 	struct video_device vdev;
 	struct v4l2_device v4l2_dev;
 
-	/* Pointer to our usb_device, may be NULL after unplug */
-	struct usb_device *udev;
-	struct mutex udevlock;
+	/* videobuf2 queue and queued buffers list */
+	struct vb2_queue vb_queue;
+	struct list_head queued_bufs;
+	spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+
+	/* Note if taking both locks v4l2_lock must always be locked first! */
+	struct mutex v4l2_lock;      /* Protects everything else */
+	struct mutex vb_queue_lock;  /* Protects vb_queue and capt_file */
+
+	/* Pointer to our usb_device, will be NULL after unplug */
+	struct usb_device *udev; /* Both mutexes most be hold when setting! */
 
 	/* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
 	int type;
@@ -232,7 +240,6 @@
 
 	/*** Video data ***/
 	struct file *capt_file;	/* file doing video capture */
-	struct mutex capt_file_lock;
 	int vendpoint;		/* video isoc endpoint */
 	int vcinterface;	/* video control interface */
 	int valternate;		/* alternate interface needed */
@@ -251,12 +258,6 @@
 	unsigned char *ctrl_buf;
 
 	struct urb *urbs[MAX_ISO_BUFS];
-	char iso_init;
-
-	/* videobuf2 queue and queued buffers list */
-	struct vb2_queue vb_queue;
-	struct list_head queued_bufs;
-	spinlock_t queued_bufs_lock;
 
 	/*
 	 * Frame currently being filled, this only gets touched by the
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 5a413f4..9c21e01 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -241,15 +241,10 @@
 			      unsigned int *size)
 {
 	struct soc_camera_device *icd = vq->priv_data;
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-						icd->current_fmt->host_fmt);
-
-	if (bytes_per_line < 0)
-		return bytes_per_line;
 
 	dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
 
-	*size = bytes_per_line * icd->user_height;
+	*size = icd->sizeimage;
 
 	if (0 == *count)
 		*count = 32;
@@ -435,11 +430,6 @@
 	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
 	int ret;
 	int size_y, size_u = 0, size_v = 0;
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-						icd->current_fmt->host_fmt);
-
-	if (bytes_per_line < 0)
-		return bytes_per_line;
 
 	dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
 		vb, vb->baddr, vb->bsize);
@@ -474,7 +464,7 @@
 		vb->state	= VIDEOBUF_NEEDS_INIT;
 	}
 
-	vb->size = bytes_per_line * vb->height;
+	vb->size = icd->sizeimage;
 	if (0 != vb->baddr && vb->bsize < vb->size) {
 		ret = -EINVAL;
 		goto out;
@@ -1244,6 +1234,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
 	},
 };
 
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 4894cbb..01c2179 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -634,13 +634,11 @@
 	const char *tmpbuf;
 	char *vbuf = videobuf_to_vmalloc(&buf->vb);
 	unsigned long last_frame;
-	struct s2255_framei *frm;
 
 	if (!vbuf)
 		return;
 	last_frame = channel->last_frame;
 	if (last_frame != -1) {
-		frm = &channel->buffer.frame[last_frame];
 		tmpbuf =
 		    (const char *)channel->buffer.frame[last_frame].lpvbits;
 		switch (buf->fmt->fourcc) {
@@ -987,7 +985,6 @@
 	struct videobuf_queue *q = &fh->vb_vidq;
 	struct s2255_mode mode;
 	int ret;
-	int norm;
 
 	ret = vidioc_try_fmt_vid_cap(file, fh, f);
 
@@ -1018,7 +1015,6 @@
 	channel->height = f->fmt.pix.height;
 	fh->vb_vidq.field = f->fmt.pix.field;
 	fh->type = f->type;
-	norm = norm_minw(&channel->vdev);
 	if (channel->width > norm_minw(&channel->vdev)) {
 		if (channel->height > norm_minh(&channel->vdev)) {
 			if (channel->cap_parm.capturemode &
@@ -1826,8 +1822,7 @@
 		usb_free_urb(dev->fw_data->fw_urb);
 		dev->fw_data->fw_urb = NULL;
 	}
-	if (dev->fw_data->fw)
-		release_firmware(dev->fw_data->fw);
+	release_firmware(dev->fw_data->fw);
 	kfree(dev->fw_data->pfw_data);
 	kfree(dev->fw_data);
 	/* reset the DSP so firmware can be reloaded next time */
@@ -1949,6 +1944,10 @@
 		/* register 4 video devices */
 		channel->vdev = template;
 		channel->vdev.lock = &dev->lock;
+		/* Locking in file operations other than ioctl should be done
+		   by the driver, not the V4L2 core.
+		   This driver needs auditing so that this flag can be removed. */
+		set_bit(V4L2_FL_LOCK_ALL_FOPS, &channel->vdev.flags);
 		channel->vdev.v4l2_dev = &dev->v4l2_dev;
 		video_set_drvdata(&channel->vdev, channel);
 		if (video_nr == -1)
diff --git a/drivers/media/video/s5p-fimc/Kconfig b/drivers/media/video/s5p-fimc/Kconfig
new file mode 100644
index 0000000..a564f7e
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/Kconfig
@@ -0,0 +1,48 @@
+
+config VIDEO_SAMSUNG_S5P_FIMC
+	bool "Samsung S5P/EXYNOS SoC camera interface driver (experimental)"
+	depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME
+	depends on EXPERIMENTAL
+	help
+	  Say Y here to enable camera host interface devices for
+	  Samsung S5P and EXYNOS SoC series.
+
+if VIDEO_SAMSUNG_S5P_FIMC
+
+config VIDEO_S5P_FIMC
+	tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
+	depends on I2C
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	help
+	  This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host
+	  interface and video postprocessor (FIMC and FIMC-LITE) devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called s5p-fimc.
+
+config VIDEO_S5P_MIPI_CSIS
+	tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver"
+	depends on REGULATOR
+	help
+	  This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2
+	  receiver (MIPI-CSIS) devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called s5p-csis.
+
+if ARCH_EXYNOS
+
+config VIDEO_EXYNOS_FIMC_LITE
+	tristate "EXYNOS FIMC-LITE camera interface driver"
+	depends on I2C
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  This is a V4L2 driver for Samsung EXYNOS4/5 SoC FIMC-LITE camera
+	  host interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called exynos-fimc-lite.
+endif
+
+endif # VIDEO_SAMSUNG_S5P_FIMC
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile
index 33dec7f..4648514 100644
--- a/drivers/media/video/s5p-fimc/Makefile
+++ b/drivers/media/video/s5p-fimc/Makefile
@@ -1,5 +1,7 @@
-s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o fimc-mdevice.o
+s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o fimc-mdevice.o
+exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o
 s5p-csis-objs := mipi-csis.o
 
 obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS)	+= s5p-csis.o
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)	+= s5p-fimc.o
+obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE)	+= exynos-fimc-lite.o
+obj-$(CONFIG_VIDEO_S5P_FIMC)		+= s5p-fimc.o
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 7e9b2c6..3545745 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -1,8 +1,8 @@
 /*
  * Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver
  *
- * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
- * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@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
@@ -29,20 +29,22 @@
 
 #include "fimc-mdevice.h"
 #include "fimc-core.h"
+#include "fimc-reg.h"
 
-static int fimc_init_capture(struct fimc_dev *fimc)
+static int fimc_capture_hw_init(struct fimc_dev *fimc)
 {
 	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct fimc_pipeline *p = &fimc->pipeline;
 	struct fimc_sensor_info *sensor;
 	unsigned long flags;
 	int ret = 0;
 
-	if (fimc->pipeline.sensor == NULL || ctx == NULL)
+	if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL)
 		return -ENXIO;
 	if (ctx->s_frame.fmt == NULL)
 		return -EINVAL;
 
-	sensor = v4l2_get_subdev_hostdata(fimc->pipeline.sensor);
+	sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]);
 
 	spin_lock_irqsave(&fimc->slock, flags);
 	fimc_prepare_dma_offset(ctx, &ctx->d_frame);
@@ -60,7 +62,7 @@
 		fimc_hw_set_mainscaler(ctx);
 		fimc_hw_set_target_format(ctx);
 		fimc_hw_set_rotation(ctx);
-		fimc_hw_set_effect(ctx, false);
+		fimc_hw_set_effect(ctx);
 		fimc_hw_set_output_path(ctx);
 		fimc_hw_set_out_dma(ctx);
 		if (fimc->variant->has_alpha)
@@ -71,6 +73,14 @@
 	return ret;
 }
 
+/*
+ * Reinitialize the driver so it is ready to start the streaming again.
+ * Set fimc->state to indicate stream off and the hardware shut down state.
+ * If not suspending (@suspend is false), return any buffers to videobuf2.
+ * Otherwise put any owned buffers onto the pending buffers queue, so they
+ * can be re-spun when the device is being resumed. Also perform FIMC
+ * software reset and disable streaming on the whole pipeline if required.
+ */
 static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
 {
 	struct fimc_vid_cap *cap = &fimc->vid_cap;
@@ -83,7 +93,9 @@
 
 	fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT |
 			 1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM);
-	if (!suspend)
+	if (suspend)
+		fimc->state |= (1 << ST_CAPT_SUSPENDED);
+	else
 		fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED);
 
 	/* Release unused buffers */
@@ -99,7 +111,6 @@
 		else
 			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
 	}
-	set_bit(ST_CAPT_SUSPENDED, &fimc->state);
 
 	fimc_hw_reset(fimc);
 	cap->buf_index = 0;
@@ -107,7 +118,7 @@
 	spin_unlock_irqrestore(&fimc->slock, flags);
 
 	if (streaming)
-		return fimc_pipeline_s_stream(fimc, 0);
+		return fimc_pipeline_s_stream(&fimc->pipeline, 0);
 	else
 		return 0;
 }
@@ -138,32 +149,96 @@
  * spinlock held. It updates the camera pixel crop, rotation and
  * image flip in H/W.
  */
-int fimc_capture_config_update(struct fimc_ctx *ctx)
+static int fimc_capture_config_update(struct fimc_ctx *ctx)
 {
 	struct fimc_dev *fimc = ctx->fimc_dev;
 	int ret;
 
-	if (!test_bit(ST_CAPT_APPLY_CFG, &fimc->state))
-		return 0;
-
-	spin_lock(&ctx->slock);
 	fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+
 	ret = fimc_set_scaler_info(ctx);
-	if (ret == 0) {
-		fimc_hw_set_prescaler(ctx);
-		fimc_hw_set_mainscaler(ctx);
-		fimc_hw_set_target_format(ctx);
-		fimc_hw_set_rotation(ctx);
-		fimc_prepare_dma_offset(ctx, &ctx->d_frame);
-		fimc_hw_set_out_dma(ctx);
-		if (fimc->variant->has_alpha)
-			fimc_hw_set_rgb_alpha(ctx);
-		clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
-	}
-	spin_unlock(&ctx->slock);
+	if (ret)
+		return ret;
+
+	fimc_hw_set_prescaler(ctx);
+	fimc_hw_set_mainscaler(ctx);
+	fimc_hw_set_target_format(ctx);
+	fimc_hw_set_rotation(ctx);
+	fimc_hw_set_effect(ctx);
+	fimc_prepare_dma_offset(ctx, &ctx->d_frame);
+	fimc_hw_set_out_dma(ctx);
+	if (fimc->variant->has_alpha)
+		fimc_hw_set_rgb_alpha(ctx);
+
+	clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
 	return ret;
 }
 
+void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)
+{
+	struct fimc_vid_cap *cap = &fimc->vid_cap;
+	struct fimc_vid_buffer *v_buf;
+	struct timeval *tv;
+	struct timespec ts;
+
+	if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
+		wake_up(&fimc->irq_queue);
+		goto done;
+	}
+
+	if (!list_empty(&cap->active_buf_q) &&
+	    test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) {
+		ktime_get_real_ts(&ts);
+
+		v_buf = fimc_active_queue_pop(cap);
+
+		tv = &v_buf->vb.v4l2_buf.timestamp;
+		tv->tv_sec = ts.tv_sec;
+		tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+		v_buf->vb.v4l2_buf.sequence = cap->frame_count++;
+
+		vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
+	}
+
+	if (!list_empty(&cap->pending_buf_q)) {
+
+		v_buf = fimc_pending_queue_pop(cap);
+		fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
+		v_buf->index = cap->buf_index;
+
+		/* Move the buffer to the capture active queue */
+		fimc_active_queue_add(cap, v_buf);
+
+		dbg("next frame: %d, done frame: %d",
+		    fimc_hw_get_frame_index(fimc), v_buf->index);
+
+		if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+			cap->buf_index = 0;
+	}
+
+	if (cap->active_buf_cnt == 0) {
+		if (deq_buf)
+			clear_bit(ST_CAPT_RUN, &fimc->state);
+
+		if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+			cap->buf_index = 0;
+	} else {
+		set_bit(ST_CAPT_RUN, &fimc->state);
+	}
+
+	if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state))
+		fimc_capture_config_update(cap->ctx);
+done:
+	if (cap->active_buf_cnt == 1) {
+		fimc_deactivate_capture(fimc);
+		clear_bit(ST_CAPT_STREAM, &fimc->state);
+	}
+
+	dbg("frame: %d, active_buf_cnt: %d",
+	    fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
+}
+
+
 static int start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	struct fimc_ctx *ctx = q->drv_priv;
@@ -174,9 +249,11 @@
 
 	vid_cap->frame_count = 0;
 
-	ret = fimc_init_capture(fimc);
-	if (ret)
-		goto error;
+	ret = fimc_capture_hw_init(fimc);
+	if (ret) {
+		fimc_capture_state_cleanup(fimc, false);
+		return ret;
+	}
 
 	set_bit(ST_CAPT_PEND, &fimc->state);
 
@@ -187,13 +264,10 @@
 		fimc_activate_capture(ctx);
 
 		if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
-			fimc_pipeline_s_stream(fimc, 1);
+			fimc_pipeline_s_stream(&fimc->pipeline, 1);
 	}
 
 	return 0;
-error:
-	fimc_capture_state_cleanup(fimc, false);
-	return ret;
 }
 
 static int stop_streaming(struct vb2_queue *q)
@@ -214,7 +288,7 @@
 	int ret = fimc_stop_capture(fimc, suspend);
 	if (ret)
 		return ret;
-	return fimc_pipeline_shutdown(fimc);
+	return fimc_pipeline_shutdown(&fimc->pipeline);
 }
 
 static void buffer_queue(struct vb2_buffer *vb);
@@ -230,9 +304,9 @@
 
 	INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
 	vid_cap->buf_index = 0;
-	fimc_pipeline_initialize(fimc, &fimc->vid_cap.vfd->entity,
+	fimc_pipeline_initialize(&fimc->pipeline, &vid_cap->vfd->entity,
 				 false);
-	fimc_init_capture(fimc);
+	fimc_capture_hw_init(fimc);
 
 	clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
 
@@ -347,7 +421,7 @@
 		spin_unlock_irqrestore(&fimc->slock, flags);
 
 		if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
-			fimc_pipeline_s_stream(fimc, 1);
+			fimc_pipeline_s_stream(&fimc->pipeline, 1);
 		return;
 	}
 	spin_unlock_irqrestore(&fimc->slock, flags);
@@ -389,15 +463,15 @@
 
 	if (WARN_ON(vid_cap->ctx == NULL))
 		return -ENXIO;
-	if (vid_cap->ctx->ctrls_rdy)
+	if (vid_cap->ctx->ctrls.ready)
 		return 0;
 
 	ret = fimc_ctrls_create(vid_cap->ctx);
-	if (ret || vid_cap->user_subdev_api)
+	if (ret || vid_cap->user_subdev_api || !vid_cap->ctx->ctrls.ready)
 		return ret;
 
-	return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrl_handler,
-				    fimc->pipeline.sensor->ctrl_handler);
+	return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler,
+		    fimc->pipeline.subdevs[IDX_SENSOR]->ctrl_handler);
 }
 
 static int fimc_capture_set_default_format(struct fimc_dev *fimc);
@@ -420,7 +494,7 @@
 	pm_runtime_get_sync(&fimc->pdev->dev);
 
 	if (++fimc->vid_cap.refcnt == 1) {
-		ret = fimc_pipeline_initialize(fimc,
+		ret = fimc_pipeline_initialize(&fimc->pipeline,
 			       &fimc->vid_cap.vfd->entity, true);
 		if (ret < 0) {
 			dev_err(&fimc->pdev->dev,
@@ -448,7 +522,7 @@
 	if (--fimc->vid_cap.refcnt == 0) {
 		clear_bit(ST_CAPT_BUSY, &fimc->state);
 		fimc_stop_capture(fimc, false);
-		fimc_pipeline_shutdown(fimc);
+		fimc_pipeline_shutdown(&fimc->pipeline);
 		clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
 	}
 
@@ -495,7 +569,7 @@
 {
 	bool rotation = ctx->rotation == 90 || ctx->rotation == 270;
 	struct fimc_dev *fimc = ctx->fimc_dev;
-	struct samsung_fimc_variant *var = fimc->variant;
+	struct fimc_variant *var = fimc->variant;
 	struct fimc_pix_limit *pl = var->pix_limit;
 	struct fimc_frame *dst = &ctx->d_frame;
 	u32 depth, min_w, max_w, min_h, align_h = 3;
@@ -537,8 +611,13 @@
 	}
 	/* Apply the scaler and the output DMA constraints */
 	max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w;
-	min_w = ctx->state & FIMC_DST_CROP ? dst->width : var->min_out_pixsize;
-	min_h = ctx->state & FIMC_DST_CROP ? dst->height : var->min_out_pixsize;
+	if (ctx->state & FIMC_COMPOSE) {
+		min_w = dst->offs_h + dst->width;
+		min_h = dst->offs_v + dst->height;
+	} else {
+		min_w = var->min_out_pixsize;
+		min_h = var->min_out_pixsize;
+	}
 	if (var->min_vsize_align == 1 && !rotation)
 		align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1;
 
@@ -556,12 +635,13 @@
 	return ffmt;
 }
 
-static void fimc_capture_try_crop(struct fimc_ctx *ctx, struct v4l2_rect *r,
-				  int pad)
+static void fimc_capture_try_selection(struct fimc_ctx *ctx,
+				       struct v4l2_rect *r,
+				       int target)
 {
 	bool rotate = ctx->rotation == 90 || ctx->rotation == 270;
 	struct fimc_dev *fimc = ctx->fimc_dev;
-	struct samsung_fimc_variant *var = fimc->variant;
+	struct fimc_variant *var = fimc->variant;
 	struct fimc_pix_limit *pl = var->pix_limit;
 	struct fimc_frame *sink = &ctx->s_frame;
 	u32 max_w, max_h, min_w = 0, min_h = 0, min_sz;
@@ -575,7 +655,7 @@
 		r->left   = r->top = 0;
 		return;
 	}
-	if (pad == FIMC_SD_PAD_SOURCE) {
+	if (target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
 		if (ctx->rotation != 90 && ctx->rotation != 270)
 			align_h = 1;
 		max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3));
@@ -589,8 +669,7 @@
 		max_sc_h = max_sc_v = 1;
 	}
 	/*
-	 * For the crop rectangle at source pad the following constraints
-	 * must be met:
+	 * For the compose rectangle the following constraints must be met:
 	 * - it must fit in the sink pad format rectangle (f_width/f_height);
 	 * - maximum downscaling ratio is 64;
 	 * - maximum crop size depends if the rotator is used or not;
@@ -602,7 +681,8 @@
 		      rotate ? pl->out_rot_en_w : pl->out_rot_dis_w,
 		      rotate ? sink->f_height : sink->f_width);
 	max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height);
-	if (pad == FIMC_SD_PAD_SOURCE) {
+
+	if (target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
 		min_w = min_t(u32, max_w, sink->f_width / max_sc_h);
 		min_h = min_t(u32, max_h, sink->f_height / max_sc_v);
 		if (rotate) {
@@ -613,13 +693,13 @@
 	v4l_bound_align_image(&r->width, min_w, max_w, ffs(min_sz) - 1,
 			      &r->height, min_h, max_h, align_h,
 			      align_sz);
-	/* Adjust left/top if cropping rectangle is out of bounds */
+	/* Adjust left/top if crop/compose rectangle is out of bounds */
 	r->left = clamp_t(u32, r->left, 0, sink->f_width - r->width);
 	r->top  = clamp_t(u32, r->top, 0, sink->f_height - r->height);
 	r->left = round_down(r->left, var->hor_offs_align);
 
-	dbg("pad%d: (%d,%d)/%dx%d, sink fmt: %dx%d",
-	    pad, r->left, r->top, r->width, r->height,
+	dbg("target %#x: (%d,%d)/%dx%d, sink fmt: %dx%d",
+	    target, r->left, r->top, r->width, r->height,
 	    sink->f_width, sink->f_height);
 }
 
@@ -669,8 +749,8 @@
 				    bool set)
 {
 	struct fimc_dev *fimc = ctx->fimc_dev;
-	struct v4l2_subdev *sd = fimc->pipeline.sensor;
-	struct v4l2_subdev *csis = fimc->pipeline.csis;
+	struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+	struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS];
 	struct v4l2_subdev_format sfmt;
 	struct v4l2_mbus_framefmt *mf = &sfmt.format;
 	struct fimc_fmt *ffmt = NULL;
@@ -851,7 +931,7 @@
 
 	set_frame_bounds(ff, pix->width, pix->height);
 	/* Reset the composition rectangle if not yet configured */
-	if (!(ctx->state & FIMC_DST_CROP))
+	if (!(ctx->state & FIMC_COMPOSE))
 		set_frame_crop(ff, 0, 0, pix->width, pix->height);
 
 	fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color));
@@ -878,7 +958,7 @@
 			       struct v4l2_input *i)
 {
 	struct fimc_dev *fimc = video_drvdata(file);
-	struct v4l2_subdev *sd = fimc->pipeline.sensor;
+	struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
 
 	if (i->index != 0)
 		return -EINVAL;
@@ -927,7 +1007,7 @@
 		if (!(pad->flags & MEDIA_PAD_FL_SINK))
 			break;
 		/* Don't call FIMC subdev operation to avoid nested locking */
-		if (sd == fimc->vid_cap.subdev) {
+		if (sd == &fimc->vid_cap.subdev) {
 			struct fimc_frame *ff = &vid_cap->ctx->s_frame;
 			sink_fmt.format.width = ff->f_width;
 			sink_fmt.format.height = ff->f_height;
@@ -970,7 +1050,8 @@
 	if (fimc_capture_active(fimc))
 		return -EBUSY;
 
-	media_entity_pipeline_start(&p->sensor->entity, p->pipe);
+	media_entity_pipeline_start(&p->subdevs[IDX_SENSOR]->entity,
+				    p->m_pipeline);
 
 	if (fimc->vid_cap.user_subdev_api) {
 		ret = fimc_pipeline_validate(fimc);
@@ -984,7 +1065,7 @@
 			    enum v4l2_buf_type type)
 {
 	struct fimc_dev *fimc = video_drvdata(file);
-	struct v4l2_subdev *sd = fimc->pipeline.sensor;
+	struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
 	int ret;
 
 	ret = vb2_streamoff(&fimc->vid_cap.vbq, type);
@@ -1100,29 +1181,18 @@
 	struct v4l2_rect rect = s->r;
 	struct fimc_frame *f;
 	unsigned long flags;
-	unsigned int pad;
 
 	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 		return -EINVAL;
 
-	switch (s->target) {
-	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-	case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+	if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE)
 		f = &ctx->d_frame;
-		pad = FIMC_SD_PAD_SOURCE;
-		break;
-	case V4L2_SEL_TGT_CROP_BOUNDS:
-	case V4L2_SEL_TGT_CROP_DEFAULT:
-	case V4L2_SEL_TGT_CROP_ACTIVE:
+	else if (s->target == V4L2_SEL_TGT_CROP_ACTIVE)
 		f = &ctx->s_frame;
-		pad = FIMC_SD_PAD_SINK;
-		break;
-	default:
+	else
 		return -EINVAL;
-	}
 
-	fimc_capture_try_crop(ctx, &rect, pad);
+	fimc_capture_try_selection(ctx, &rect, s->target);
 
 	if (s->flags & V4L2_SEL_FLAG_LE &&
 	    !enclosed_rectangle(&rect, &s->r))
@@ -1243,7 +1313,7 @@
 					 struct fimc_vid_buffer, list);
 			vb2_set_plane_payload(&buf->vb, 0, *((u32 *)arg));
 		}
-		fimc_capture_irq_handler(fimc, true);
+		fimc_capture_irq_handler(fimc, 1);
 		fimc_deactivate_capture(fimc);
 		spin_unlock_irqrestore(&fimc->slock, irq_flags);
 	}
@@ -1334,77 +1404,122 @@
 	ff->fmt = ffmt;
 
 	/* Reset the crop rectangle if required. */
-	if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_DST_CROP)))
+	if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_COMPOSE)))
 		set_frame_crop(ff, 0, 0, mf->width, mf->height);
 
 	if (fmt->pad == FIMC_SD_PAD_SINK)
-		ctx->state &= ~FIMC_DST_CROP;
+		ctx->state &= ~FIMC_COMPOSE;
 	mutex_unlock(&fimc->lock);
 	return 0;
 }
 
-static int fimc_subdev_get_crop(struct v4l2_subdev *sd,
-				struct v4l2_subdev_fh *fh,
-				struct v4l2_subdev_crop *crop)
+static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_fh *fh,
+				     struct v4l2_subdev_selection *sel)
 {
 	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
 	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
-	struct v4l2_rect *r = &crop->rect;
-	struct fimc_frame *ff;
+	struct fimc_frame *f = &ctx->s_frame;
+	struct v4l2_rect *r = &sel->r;
+	struct v4l2_rect *try_sel;
 
-	if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
-		crop->rect = *v4l2_subdev_get_try_crop(fh, crop->pad);
-		return 0;
-	}
-	ff = crop->pad == FIMC_SD_PAD_SINK ?
-		&ctx->s_frame : &ctx->d_frame;
+	if (sel->pad != FIMC_SD_PAD_SINK)
+		return -EINVAL;
 
 	mutex_lock(&fimc->lock);
-	r->left	  = ff->offs_h;
-	r->top	  = ff->offs_v;
-	r->width  = ff->width;
-	r->height = ff->height;
+
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+		f = &ctx->d_frame;
+	case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+		r->width = f->o_width;
+		r->height = f->o_height;
+		r->left = 0;
+		r->top = 0;
+		mutex_unlock(&fimc->lock);
+		return 0;
+
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+		try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
+		break;
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+		try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
+		f = &ctx->d_frame;
+		break;
+	default:
+		mutex_unlock(&fimc->lock);
+		return -EINVAL;
+	}
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+		sel->r = *try_sel;
+	} else {
+		r->left = f->offs_h;
+		r->top = f->offs_v;
+		r->width = f->width;
+		r->height = f->height;
+	}
+
+	dbg("target %#x: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",
+	    sel->pad, r->left, r->top, r->width, r->height,
+	    f->f_width, f->f_height);
+
 	mutex_unlock(&fimc->lock);
-
-	dbg("ff:%p, pad%d: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",
-	    ff, crop->pad, r->left, r->top, r->width, r->height,
-	    ff->f_width, ff->f_height);
-
 	return 0;
 }
 
-static int fimc_subdev_set_crop(struct v4l2_subdev *sd,
-				struct v4l2_subdev_fh *fh,
-				struct v4l2_subdev_crop *crop)
+static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_fh *fh,
+				     struct v4l2_subdev_selection *sel)
 {
 	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
 	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
-	struct v4l2_rect *r = &crop->rect;
-	struct fimc_frame *ff;
+	struct fimc_frame *f = &ctx->s_frame;
+	struct v4l2_rect *r = &sel->r;
+	struct v4l2_rect *try_sel;
 	unsigned long flags;
 
-	dbg("(%d,%d)/%dx%d", r->left, r->top, r->width, r->height);
-
-	ff = crop->pad == FIMC_SD_PAD_SOURCE ?
-		&ctx->d_frame : &ctx->s_frame;
+	if (sel->pad != FIMC_SD_PAD_SINK)
+		return -EINVAL;
 
 	mutex_lock(&fimc->lock);
-	fimc_capture_try_crop(ctx, r, crop->pad);
+	fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP_ACTIVE);
 
-	if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+		f = &ctx->d_frame;
+	case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+		r->width = f->o_width;
+		r->height = f->o_height;
+		r->left = 0;
+		r->top = 0;
 		mutex_unlock(&fimc->lock);
-		*v4l2_subdev_get_try_crop(fh, crop->pad) = *r;
 		return 0;
+
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+		try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
+		break;
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+		try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
+		f = &ctx->d_frame;
+		break;
+	default:
+		mutex_unlock(&fimc->lock);
+		return -EINVAL;
 	}
-	spin_lock_irqsave(&fimc->slock, flags);
-	set_frame_crop(ff, r->left, r->top, r->width, r->height);
-	if (crop->pad == FIMC_SD_PAD_SOURCE)
-		ctx->state |= FIMC_DST_CROP;
 
-	set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
-	spin_unlock_irqrestore(&fimc->slock, flags);
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+		*try_sel = sel->r;
+	} else {
+		spin_lock_irqsave(&fimc->slock, flags);
+		set_frame_crop(f, r->left, r->top, r->width, r->height);
+		set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+		spin_unlock_irqrestore(&fimc->slock, flags);
+		if (sel->target == V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL)
+			ctx->state |= FIMC_COMPOSE;
+	}
 
-	dbg("pad%d: (%d,%d)/%dx%d", crop->pad, r->left, r->top,
+	dbg("target %#x: (%d,%d)/%dx%d", sel->target, r->left, r->top,
 	    r->width, r->height);
 
 	mutex_unlock(&fimc->lock);
@@ -1413,63 +1528,16 @@
 
 static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {
 	.enum_mbus_code = fimc_subdev_enum_mbus_code,
+	.get_selection = fimc_subdev_get_selection,
+	.set_selection = fimc_subdev_set_selection,
 	.get_fmt = fimc_subdev_get_fmt,
 	.set_fmt = fimc_subdev_set_fmt,
-	.get_crop = fimc_subdev_get_crop,
-	.set_crop = fimc_subdev_set_crop,
 };
 
 static struct v4l2_subdev_ops fimc_subdev_ops = {
 	.pad = &fimc_subdev_pad_ops,
 };
 
-static int fimc_create_capture_subdev(struct fimc_dev *fimc,
-				      struct v4l2_device *v4l2_dev)
-{
-	struct v4l2_subdev *sd;
-	int ret;
-
-	sd = kzalloc(sizeof(*sd), GFP_KERNEL);
-	if (!sd)
-		return -ENOMEM;
-
-	v4l2_subdev_init(sd, &fimc_subdev_ops);
-	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
-	snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id);
-
-	fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
-	fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
-	ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
-				fimc->vid_cap.sd_pads, 0);
-	if (ret)
-		goto me_err;
-	ret = v4l2_device_register_subdev(v4l2_dev, sd);
-	if (ret)
-		goto sd_err;
-
-	fimc->vid_cap.subdev = sd;
-	v4l2_set_subdevdata(sd, fimc);
-	sd->entity.ops = &fimc_sd_media_ops;
-	return 0;
-sd_err:
-	media_entity_cleanup(&sd->entity);
-me_err:
-	kfree(sd);
-	return ret;
-}
-
-static void fimc_destroy_capture_subdev(struct fimc_dev *fimc)
-{
-	struct v4l2_subdev *sd = fimc->vid_cap.subdev;
-
-	if (!sd)
-		return;
-	media_entity_cleanup(&sd->entity);
-	v4l2_device_unregister_subdev(sd);
-	kfree(sd);
-	fimc->vid_cap.subdev = NULL;
-}
-
 /* Set default format at the sensor and host interface */
 static int fimc_capture_set_default_format(struct fimc_dev *fimc)
 {
@@ -1488,7 +1556,7 @@
 }
 
 /* fimc->lock must be already initialized */
-int fimc_register_capture_device(struct fimc_dev *fimc,
+static int fimc_register_capture_device(struct fimc_dev *fimc,
 				 struct v4l2_device *v4l2_dev)
 {
 	struct video_device *vfd;
@@ -1502,11 +1570,11 @@
 		return -ENOMEM;
 
 	ctx->fimc_dev	 = fimc;
-	ctx->in_path	 = FIMC_CAMERA;
-	ctx->out_path	 = FIMC_DMA;
+	ctx->in_path	 = FIMC_IO_CAMERA;
+	ctx->out_path	 = FIMC_IO_DMA;
 	ctx->state	 = FIMC_CTX_CAP;
 	ctx->s_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
-	ctx->d_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
+	ctx->d_frame.fmt = ctx->s_frame.fmt;
 
 	vfd = video_device_alloc();
 	if (!vfd) {
@@ -1514,8 +1582,7 @@
 		goto err_vd_alloc;
 	}
 
-	snprintf(vfd->name, sizeof(vfd->name), "%s.capture",
-		 dev_name(&fimc->pdev->dev));
+	snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.capture", fimc->id);
 
 	vfd->fops	= &fimc_capture_fops;
 	vfd->ioctl_ops	= &fimc_capture_ioctl_ops;
@@ -1523,6 +1590,10 @@
 	vfd->minor	= -1;
 	vfd->release	= video_device_release;
 	vfd->lock	= &fimc->lock;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 	video_set_drvdata(vfd, fimc);
 
 	vid_cap = &fimc->vid_cap;
@@ -1533,7 +1604,6 @@
 
 	INIT_LIST_HEAD(&vid_cap->pending_buf_q);
 	INIT_LIST_HEAD(&vid_cap->active_buf_q);
-	spin_lock_init(&ctx->slock);
 	vid_cap->ctx = ctx;
 
 	q = &fimc->vid_cap.vbq;
@@ -1547,18 +1617,22 @@
 
 	vb2_queue_init(q);
 
-	fimc->vid_cap.vd_pad.flags = MEDIA_PAD_FL_SINK;
-	ret = media_entity_init(&vfd->entity, 1, &fimc->vid_cap.vd_pad, 0);
+	vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
+	ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);
 	if (ret)
 		goto err_ent;
-	ret = fimc_create_capture_subdev(fimc, v4l2_dev);
-	if (ret)
-		goto err_sd_reg;
 
-	vfd->ctrl_handler = &ctx->ctrl_handler;
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto err_vd;
+
+	v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+
+	vfd->ctrl_handler = &ctx->ctrls.handler;
 	return 0;
 
-err_sd_reg:
+err_vd:
 	media_entity_cleanup(&vfd->entity);
 err_ent:
 	video_device_release(vfd);
@@ -1567,17 +1641,73 @@
 	return ret;
 }
 
-void fimc_unregister_capture_device(struct fimc_dev *fimc)
+static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)
 {
-	struct video_device *vfd = fimc->vid_cap.vfd;
+	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+	int ret;
 
-	if (vfd) {
-		media_entity_cleanup(&vfd->entity);
-		/* Can also be called if video device was
-		   not registered */
-		video_unregister_device(vfd);
+	ret = fimc_register_m2m_device(fimc, sd->v4l2_dev);
+	if (ret)
+		return ret;
+
+	ret = fimc_register_capture_device(fimc, sd->v4l2_dev);
+	if (ret)
+		fimc_unregister_m2m_device(fimc);
+
+	return ret;
+}
+
+static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd)
+{
+	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+
+	if (fimc == NULL)
+		return;
+
+	fimc_unregister_m2m_device(fimc);
+
+	if (fimc->vid_cap.vfd) {
+		media_entity_cleanup(&fimc->vid_cap.vfd->entity);
+		video_unregister_device(fimc->vid_cap.vfd);
+		fimc->vid_cap.vfd = NULL;
 	}
-	fimc_destroy_capture_subdev(fimc);
+
 	kfree(fimc->vid_cap.ctx);
 	fimc->vid_cap.ctx = NULL;
 }
+
+static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = {
+	.registered = fimc_capture_subdev_registered,
+	.unregistered = fimc_capture_subdev_unregistered,
+};
+
+int fimc_initialize_capture_subdev(struct fimc_dev *fimc)
+{
+	struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
+	int ret;
+
+	v4l2_subdev_init(sd, &fimc_subdev_ops);
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id);
+
+	fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
+				fimc->vid_cap.sd_pads, 0);
+	if (ret)
+		return ret;
+
+	sd->entity.ops = &fimc_sd_media_ops;
+	sd->internal_ops = &fimc_capture_sd_internal_ops;
+	v4l2_set_subdevdata(sd, fimc);
+	return 0;
+}
+
+void fimc_unregister_capture_subdev(struct fimc_dev *fimc)
+{
+	struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
+
+	v4l2_device_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_set_subdevdata(sd, NULL);
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index e09ba7b..fedcd56 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -1,8 +1,8 @@
 /*
- * Samsung S5P/EXYNOS4 SoC series camera interface (video postprocessor) driver
+ * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver
  *
- * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
- * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2010-2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@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
@@ -28,6 +28,7 @@
 #include <media/videobuf2-dma-contig.h>
 
 #include "fimc-core.h"
+#include "fimc-reg.h"
 #include "fimc-mdevice.h"
 
 static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
@@ -39,7 +40,7 @@
 		.name		= "RGB565",
 		.fourcc		= V4L2_PIX_FMT_RGB565,
 		.depth		= { 16 },
-		.color		= S5P_FIMC_RGB565,
+		.color		= FIMC_FMT_RGB565,
 		.memplanes	= 1,
 		.colplanes	= 1,
 		.flags		= FMT_FLAGS_M2M,
@@ -47,7 +48,7 @@
 		.name		= "BGR666",
 		.fourcc		= V4L2_PIX_FMT_BGR666,
 		.depth		= { 32 },
-		.color		= S5P_FIMC_RGB666,
+		.color		= FIMC_FMT_RGB666,
 		.memplanes	= 1,
 		.colplanes	= 1,
 		.flags		= FMT_FLAGS_M2M,
@@ -55,7 +56,7 @@
 		.name		= "ARGB8888, 32 bpp",
 		.fourcc		= V4L2_PIX_FMT_RGB32,
 		.depth		= { 32 },
-		.color		= S5P_FIMC_RGB888,
+		.color		= FIMC_FMT_RGB888,
 		.memplanes	= 1,
 		.colplanes	= 1,
 		.flags		= FMT_FLAGS_M2M | FMT_HAS_ALPHA,
@@ -63,7 +64,7 @@
 		.name		= "ARGB1555",
 		.fourcc		= V4L2_PIX_FMT_RGB555,
 		.depth		= { 16 },
-		.color		= S5P_FIMC_RGB555,
+		.color		= FIMC_FMT_RGB555,
 		.memplanes	= 1,
 		.colplanes	= 1,
 		.flags		= FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
@@ -71,7 +72,7 @@
 		.name		= "ARGB4444",
 		.fourcc		= V4L2_PIX_FMT_RGB444,
 		.depth		= { 16 },
-		.color		= S5P_FIMC_RGB444,
+		.color		= FIMC_FMT_RGB444,
 		.memplanes	= 1,
 		.colplanes	= 1,
 		.flags		= FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
@@ -79,7 +80,7 @@
 		.name		= "YUV 4:2:2 packed, YCbYCr",
 		.fourcc		= V4L2_PIX_FMT_YUYV,
 		.depth		= { 16 },
-		.color		= S5P_FIMC_YCBYCR422,
+		.color		= FIMC_FMT_YCBYCR422,
 		.memplanes	= 1,
 		.colplanes	= 1,
 		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
@@ -88,7 +89,7 @@
 		.name		= "YUV 4:2:2 packed, CbYCrY",
 		.fourcc		= V4L2_PIX_FMT_UYVY,
 		.depth		= { 16 },
-		.color		= S5P_FIMC_CBYCRY422,
+		.color		= FIMC_FMT_CBYCRY422,
 		.memplanes	= 1,
 		.colplanes	= 1,
 		.mbus_code	= V4L2_MBUS_FMT_UYVY8_2X8,
@@ -97,7 +98,7 @@
 		.name		= "YUV 4:2:2 packed, CrYCbY",
 		.fourcc		= V4L2_PIX_FMT_VYUY,
 		.depth		= { 16 },
-		.color		= S5P_FIMC_CRYCBY422,
+		.color		= FIMC_FMT_CRYCBY422,
 		.memplanes	= 1,
 		.colplanes	= 1,
 		.mbus_code	= V4L2_MBUS_FMT_VYUY8_2X8,
@@ -106,7 +107,7 @@
 		.name		= "YUV 4:2:2 packed, YCrYCb",
 		.fourcc		= V4L2_PIX_FMT_YVYU,
 		.depth		= { 16 },
-		.color		= S5P_FIMC_YCRYCB422,
+		.color		= FIMC_FMT_YCRYCB422,
 		.memplanes	= 1,
 		.colplanes	= 1,
 		.mbus_code	= V4L2_MBUS_FMT_YVYU8_2X8,
@@ -115,7 +116,7 @@
 		.name		= "YUV 4:2:2 planar, Y/Cb/Cr",
 		.fourcc		= V4L2_PIX_FMT_YUV422P,
 		.depth		= { 12 },
-		.color		= S5P_FIMC_YCBYCR422,
+		.color		= FIMC_FMT_YCBYCR422,
 		.memplanes	= 1,
 		.colplanes	= 3,
 		.flags		= FMT_FLAGS_M2M,
@@ -123,7 +124,7 @@
 		.name		= "YUV 4:2:2 planar, Y/CbCr",
 		.fourcc		= V4L2_PIX_FMT_NV16,
 		.depth		= { 16 },
-		.color		= S5P_FIMC_YCBYCR422,
+		.color		= FIMC_FMT_YCBYCR422,
 		.memplanes	= 1,
 		.colplanes	= 2,
 		.flags		= FMT_FLAGS_M2M,
@@ -131,7 +132,7 @@
 		.name		= "YUV 4:2:2 planar, Y/CrCb",
 		.fourcc		= V4L2_PIX_FMT_NV61,
 		.depth		= { 16 },
-		.color		= S5P_FIMC_YCRYCB422,
+		.color		= FIMC_FMT_YCRYCB422,
 		.memplanes	= 1,
 		.colplanes	= 2,
 		.flags		= FMT_FLAGS_M2M,
@@ -139,7 +140,7 @@
 		.name		= "YUV 4:2:0 planar, YCbCr",
 		.fourcc		= V4L2_PIX_FMT_YUV420,
 		.depth		= { 12 },
-		.color		= S5P_FIMC_YCBCR420,
+		.color		= FIMC_FMT_YCBCR420,
 		.memplanes	= 1,
 		.colplanes	= 3,
 		.flags		= FMT_FLAGS_M2M,
@@ -147,14 +148,14 @@
 		.name		= "YUV 4:2:0 planar, Y/CbCr",
 		.fourcc		= V4L2_PIX_FMT_NV12,
 		.depth		= { 12 },
-		.color		= S5P_FIMC_YCBCR420,
+		.color		= FIMC_FMT_YCBCR420,
 		.memplanes	= 1,
 		.colplanes	= 2,
 		.flags		= FMT_FLAGS_M2M,
 	}, {
 		.name		= "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
 		.fourcc		= V4L2_PIX_FMT_NV12M,
-		.color		= S5P_FIMC_YCBCR420,
+		.color		= FIMC_FMT_YCBCR420,
 		.depth		= { 8, 4 },
 		.memplanes	= 2,
 		.colplanes	= 2,
@@ -162,7 +163,7 @@
 	}, {
 		.name		= "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
 		.fourcc		= V4L2_PIX_FMT_YUV420M,
-		.color		= S5P_FIMC_YCBCR420,
+		.color		= FIMC_FMT_YCBCR420,
 		.depth		= { 8, 2, 2 },
 		.memplanes	= 3,
 		.colplanes	= 3,
@@ -170,7 +171,7 @@
 	}, {
 		.name		= "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
 		.fourcc		= V4L2_PIX_FMT_NV12MT,
-		.color		= S5P_FIMC_YCBCR420,
+		.color		= FIMC_FMT_YCBCR420,
 		.depth		= { 8, 4 },
 		.memplanes	= 2,
 		.colplanes	= 2,
@@ -178,7 +179,7 @@
 	}, {
 		.name		= "JPEG encoded data",
 		.fourcc		= V4L2_PIX_FMT_JPEG,
-		.color		= S5P_FIMC_JPEG,
+		.color		= FIMC_FMT_JPEG,
 		.depth		= { 8 },
 		.memplanes	= 1,
 		.colplanes	= 1,
@@ -187,12 +188,12 @@
 	},
 };
 
-static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
+struct fimc_fmt *fimc_get_format(unsigned int index)
 {
-	if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-		return FMT_FLAGS_M2M_IN;
-	else
-		return FMT_FLAGS_M2M_OUT;
+	if (index >= ARRAY_SIZE(fimc_formats))
+		return NULL;
+
+	return &fimc_formats[index];
 }
 
 int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
@@ -230,7 +231,7 @@
 
 int fimc_set_scaler_info(struct fimc_ctx *ctx)
 {
-	struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+	struct fimc_variant *variant = ctx->fimc_dev->variant;
 	struct device *dev = &ctx->fimc_dev->pdev->dev;
 	struct fimc_scaler *sc = &ctx->scaler;
 	struct fimc_frame *s_frame = &ctx->s_frame;
@@ -293,126 +294,9 @@
 	return 0;
 }
 
-static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
-{
-	struct vb2_buffer *src_vb, *dst_vb;
-
-	if (!ctx || !ctx->m2m_ctx)
-		return;
-
-	src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-	dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-
-	if (src_vb && dst_vb) {
-		v4l2_m2m_buf_done(src_vb, vb_state);
-		v4l2_m2m_buf_done(dst_vb, vb_state);
-		v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
-				    ctx->m2m_ctx);
-	}
-}
-
-/* Complete the transaction which has been scheduled for execution. */
-static int fimc_m2m_shutdown(struct fimc_ctx *ctx)
-{
-	struct fimc_dev *fimc = ctx->fimc_dev;
-	int ret;
-
-	if (!fimc_m2m_pending(fimc))
-		return 0;
-
-	fimc_ctx_state_lock_set(FIMC_CTX_SHUT, ctx);
-
-	ret = wait_event_timeout(fimc->irq_queue,
-			   !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
-			   FIMC_SHUTDOWN_TIMEOUT);
-
-	return ret == 0 ? -ETIMEDOUT : ret;
-}
-
-static int start_streaming(struct vb2_queue *q, unsigned int count)
-{
-	struct fimc_ctx *ctx = q->drv_priv;
-	int ret;
-
-	ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
-	return ret > 0 ? 0 : ret;
-}
-
-static int stop_streaming(struct vb2_queue *q)
-{
-	struct fimc_ctx *ctx = q->drv_priv;
-	int ret;
-
-	ret = fimc_m2m_shutdown(ctx);
-	if (ret == -ETIMEDOUT)
-		fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
-
-	pm_runtime_put(&ctx->fimc_dev->pdev->dev);
-	return 0;
-}
-
-void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final)
-{
-	struct fimc_vid_cap *cap = &fimc->vid_cap;
-	struct fimc_vid_buffer *v_buf;
-	struct timeval *tv;
-	struct timespec ts;
-
-	if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
-		wake_up(&fimc->irq_queue);
-		return;
-	}
-
-	if (!list_empty(&cap->active_buf_q) &&
-	    test_bit(ST_CAPT_RUN, &fimc->state) && final) {
-		ktime_get_real_ts(&ts);
-
-		v_buf = fimc_active_queue_pop(cap);
-
-		tv = &v_buf->vb.v4l2_buf.timestamp;
-		tv->tv_sec = ts.tv_sec;
-		tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
-		v_buf->vb.v4l2_buf.sequence = cap->frame_count++;
-
-		vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
-	}
-
-	if (!list_empty(&cap->pending_buf_q)) {
-
-		v_buf = fimc_pending_queue_pop(cap);
-		fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
-		v_buf->index = cap->buf_index;
-
-		/* Move the buffer to the capture active queue */
-		fimc_active_queue_add(cap, v_buf);
-
-		dbg("next frame: %d, done frame: %d",
-		    fimc_hw_get_frame_index(fimc), v_buf->index);
-
-		if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
-			cap->buf_index = 0;
-	}
-
-	if (cap->active_buf_cnt == 0) {
-		if (final)
-			clear_bit(ST_CAPT_RUN, &fimc->state);
-
-		if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
-			cap->buf_index = 0;
-	} else {
-		set_bit(ST_CAPT_RUN, &fimc->state);
-	}
-
-	fimc_capture_config_update(cap->ctx);
-
-	dbg("frame: %d, active_buf_cnt: %d",
-	    fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
-}
-
 static irqreturn_t fimc_irq_handler(int irq, void *priv)
 {
 	struct fimc_dev *fimc = priv;
-	struct fimc_vid_cap *cap = &fimc->vid_cap;
 	struct fimc_ctx *ctx;
 
 	fimc_hw_clear_irq(fimc);
@@ -430,21 +314,16 @@
 			spin_unlock(&fimc->slock);
 			fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
 
-			spin_lock(&ctx->slock);
 			if (ctx->state & FIMC_CTX_SHUT) {
 				ctx->state &= ~FIMC_CTX_SHUT;
 				wake_up(&fimc->irq_queue);
 			}
-			spin_unlock(&ctx->slock);
+			return IRQ_HANDLED;
 		}
-		return IRQ_HANDLED;
 	} else if (test_bit(ST_CAPT_PEND, &fimc->state)) {
-		fimc_capture_irq_handler(fimc,
-				 !test_bit(ST_CAPT_JPEG, &fimc->state));
-		if (cap->active_buf_cnt == 1) {
-			fimc_deactivate_capture(fimc);
-			clear_bit(ST_CAPT_STREAM, &fimc->state);
-		}
+		int last_buf = test_bit(ST_CAPT_JPEG, &fimc->state) &&
+				fimc->vid_cap.reqbufs_count == 1;
+		fimc_capture_irq_handler(fimc, !last_buf);
 	}
 out:
 	spin_unlock(&fimc->slock);
@@ -482,7 +361,7 @@
 		case 3:
 			paddr->cb = (u32)(paddr->y + pix_size);
 			/* decompose Y into Y/Cb/Cr */
-			if (S5P_FIMC_YCBCR420 == frame->fmt->color)
+			if (FIMC_FMT_YCBCR420 == frame->fmt->color)
 				paddr->cr = (u32)(paddr->cb
 						+ (pix_size >> 2));
 			else /* 422 */
@@ -510,40 +389,40 @@
 void fimc_set_yuv_order(struct fimc_ctx *ctx)
 {
 	/* The one only mode supported in SoC. */
-	ctx->in_order_2p = S5P_FIMC_LSB_CRCB;
-	ctx->out_order_2p = S5P_FIMC_LSB_CRCB;
+	ctx->in_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
+	ctx->out_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
 
 	/* Set order for 1 plane input formats. */
 	switch (ctx->s_frame.fmt->color) {
-	case S5P_FIMC_YCRYCB422:
-		ctx->in_order_1p = S5P_MSCTRL_ORDER422_CBYCRY;
+	case FIMC_FMT_YCRYCB422:
+		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY;
 		break;
-	case S5P_FIMC_CBYCRY422:
-		ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCRYCB;
+	case FIMC_FMT_CBYCRY422:
+		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB;
 		break;
-	case S5P_FIMC_CRYCBY422:
-		ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCBYCR;
+	case FIMC_FMT_CRYCBY422:
+		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR;
 		break;
-	case S5P_FIMC_YCBYCR422:
+	case FIMC_FMT_YCBYCR422:
 	default:
-		ctx->in_order_1p = S5P_MSCTRL_ORDER422_CRYCBY;
+		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY;
 		break;
 	}
 	dbg("ctx->in_order_1p= %d", ctx->in_order_1p);
 
 	switch (ctx->d_frame.fmt->color) {
-	case S5P_FIMC_YCRYCB422:
-		ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CBYCRY;
+	case FIMC_FMT_YCRYCB422:
+		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY;
 		break;
-	case S5P_FIMC_CBYCRY422:
-		ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCRYCB;
+	case FIMC_FMT_CBYCRY422:
+		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB;
 		break;
-	case S5P_FIMC_CRYCBY422:
-		ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCBYCR;
+	case FIMC_FMT_CRYCBY422:
+		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR;
 		break;
-	case S5P_FIMC_YCBYCR422:
+	case FIMC_FMT_YCBYCR422:
 	default:
-		ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CRYCBY;
+		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY;
 		break;
 	}
 	dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
@@ -551,7 +430,7 @@
 
 void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
 {
-	struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+	struct fimc_variant *variant = ctx->fimc_dev->variant;
 	u32 i, depth = 0;
 
 	for (i = 0; i < f->fmt->colplanes; i++)
@@ -574,7 +453,7 @@
 			f->dma_offset.cb_h >>= 1;
 			f->dma_offset.cr_h >>= 1;
 		}
-		if (f->fmt->color == S5P_FIMC_YCBCR420) {
+		if (f->fmt->color == FIMC_FMT_YCBCR420) {
 			f->dma_offset.cb_v >>= 1;
 			f->dma_offset.cr_v >>= 1;
 		}
@@ -584,203 +463,58 @@
 	    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.
- *
- * @ctx: hardware context information
- * @flags: flags indicating which parameters to check/update
- *
- * Return: 0 if dimensions are valid or non zero otherwise.
- */
-int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
+int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
 {
-	struct fimc_frame *s_frame, *d_frame;
-	struct vb2_buffer *vb = NULL;
-	int ret = 0;
+	struct fimc_effect *effect = &ctx->effect;
 
-	s_frame = &ctx->s_frame;
-	d_frame = &ctx->d_frame;
-
-	if (flags & FIMC_PARAMS) {
-		/* Prepare the DMA offset ratios for scaler. */
-		fimc_prepare_dma_offset(ctx, &ctx->s_frame);
-		fimc_prepare_dma_offset(ctx, &ctx->d_frame);
-
-		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);
-	}
-
-	if (flags & FIMC_SRC_ADDR) {
-		vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-		ret = fimc_prepare_addr(ctx, vb, s_frame, &s_frame->paddr);
-		if (ret)
-			return ret;
-	}
-
-	if (flags & FIMC_DST_ADDR) {
-		vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
-		ret = fimc_prepare_addr(ctx, vb, d_frame, &d_frame->paddr);
-	}
-
-	return ret;
-}
-
-static void fimc_dma_run(void *priv)
-{
-	struct fimc_ctx *ctx = priv;
-	struct fimc_dev *fimc;
-	unsigned long flags;
-	u32 ret;
-
-	if (WARN(!ctx, "null hardware context\n"))
-		return;
-
-	fimc = ctx->fimc_dev;
-	spin_lock_irqsave(&fimc->slock, flags);
-	set_bit(ST_M2M_PEND, &fimc->state);
-
-	spin_lock(&ctx->slock);
-	ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR);
-	ret = fimc_prepare_config(ctx, ctx->state);
-	if (ret)
-		goto dma_unlock;
-
-	/* Reconfigure hardware if the context has changed. */
-	if (fimc->m2m.ctx != ctx) {
-		ctx->state |= FIMC_PARAMS;
-		fimc->m2m.ctx = ctx;
-	}
-	fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr);
-
-	if (ctx->state & FIMC_PARAMS) {
-		fimc_hw_set_input_path(ctx);
-		fimc_hw_set_in_dma(ctx);
-		ret = fimc_set_scaler_info(ctx);
-		if (ret) {
-			spin_unlock(&fimc->slock);
-			goto dma_unlock;
-		}
-		fimc_hw_set_prescaler(ctx);
-		fimc_hw_set_mainscaler(ctx);
-		fimc_hw_set_target_format(ctx);
-		fimc_hw_set_rotation(ctx);
-		fimc_hw_set_effect(ctx, false);
-	}
-
-	fimc_hw_set_output_path(ctx);
-	if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS))
-		fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1);
-
-	if (ctx->state & FIMC_PARAMS) {
-		fimc_hw_set_out_dma(ctx);
-		if (fimc->variant->has_alpha)
-			fimc_hw_set_rgb_alpha(ctx);
-	}
-
-	fimc_activate_capture(ctx);
-
-	ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP |
-		       FIMC_SRC_FMT | FIMC_DST_FMT);
-	fimc_hw_activate_input_dma(fimc, true);
-dma_unlock:
-	spin_unlock(&ctx->slock);
-	spin_unlock_irqrestore(&fimc->slock, flags);
-}
-
-static void fimc_job_abort(void *priv)
-{
-	fimc_m2m_shutdown(priv);
-}
-
-static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
-			    unsigned int *num_buffers, unsigned int *num_planes,
-			    unsigned int sizes[], void *allocators[])
-{
-	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
-	struct fimc_frame *f;
-	int i;
-
-	f = ctx_get_frame(ctx, vq->type);
-	if (IS_ERR(f))
-		return PTR_ERR(f);
-	/*
-	 * Return number of non-contigous planes (plane buffers)
-	 * depending on the configured color format.
-	 */
-	if (!f->fmt)
+	switch (colorfx) {
+	case V4L2_COLORFX_NONE:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
+		break;
+	case V4L2_COLORFX_BW:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
+		effect->pat_cb = 128;
+		effect->pat_cr = 128;
+		break;
+	case V4L2_COLORFX_SEPIA:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
+		effect->pat_cb = 115;
+		effect->pat_cr = 145;
+		break;
+	case V4L2_COLORFX_NEGATIVE:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_NEGATIVE;
+		break;
+	case V4L2_COLORFX_EMBOSS:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_EMBOSSING;
+		break;
+	case V4L2_COLORFX_ART_FREEZE:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_ARTFREEZE;
+		break;
+	case V4L2_COLORFX_SILHOUETTE:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_SILHOUETTE;
+		break;
+	case V4L2_COLORFX_SET_CBCR:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
+		effect->pat_cb = ctx->ctrls.colorfx_cbcr->val >> 8;
+		effect->pat_cr = ctx->ctrls.colorfx_cbcr->val & 0xff;
+		break;
+	default:
 		return -EINVAL;
-
-	*num_planes = f->fmt->memplanes;
-	for (i = 0; i < f->fmt->memplanes; i++) {
-		sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8;
-		allocators[i] = ctx->fimc_dev->alloc_ctx;
 	}
-	return 0;
-}
-
-static int fimc_buf_prepare(struct vb2_buffer *vb)
-{
-	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-	struct fimc_frame *frame;
-	int i;
-
-	frame = ctx_get_frame(ctx, vb->vb2_queue->type);
-	if (IS_ERR(frame))
-		return PTR_ERR(frame);
-
-	for (i = 0; i < frame->fmt->memplanes; i++)
-		vb2_set_plane_payload(vb, i, frame->payload[i]);
 
 	return 0;
 }
 
-static void fimc_buf_queue(struct vb2_buffer *vb)
-{
-	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-
-	dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
-
-	if (ctx->m2m_ctx)
-		v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
-}
-
-static void fimc_lock(struct vb2_queue *vq)
-{
-	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
-	mutex_lock(&ctx->fimc_dev->lock);
-}
-
-static void fimc_unlock(struct vb2_queue *vq)
-{
-	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
-	mutex_unlock(&ctx->fimc_dev->lock);
-}
-
-static struct vb2_ops fimc_qops = {
-	.queue_setup	 = fimc_queue_setup,
-	.buf_prepare	 = fimc_buf_prepare,
-	.buf_queue	 = fimc_buf_queue,
-	.wait_prepare	 = fimc_unlock,
-	.wait_finish	 = fimc_lock,
-	.stop_streaming	 = stop_streaming,
-	.start_streaming = start_streaming,
-};
-
 /*
  * V4L2 controls handling
  */
 #define ctrl_to_ctx(__ctrl) \
-	container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler)
+	container_of((__ctrl)->handler, struct fimc_ctx, ctrls.handler)
 
 static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
 {
 	struct fimc_dev *fimc = ctx->fimc_dev;
-	struct samsung_fimc_variant *variant = fimc->variant;
+	struct fimc_variant *variant = fimc->variant;
 	unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT;
 	int ret = 0;
 
@@ -815,7 +549,14 @@
 	case V4L2_CID_ALPHA_COMPONENT:
 		ctx->d_frame.alpha = ctrl->val;
 		break;
+
+	case V4L2_CID_COLORFX:
+		ret = fimc_set_color_effect(ctx, ctrl->val);
+		if (ret)
+			return ret;
+		break;
 	}
+
 	ctx->state |= FIMC_PARAMS;
 	set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
 	return 0;
@@ -827,9 +568,9 @@
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&ctx->slock, flags);
+	spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
 	ret = __fimc_s_ctrl(ctx, ctrl);
-	spin_unlock_irqrestore(&ctx->slock, flags);
+	spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
 
 	return ret;
 }
@@ -840,71 +581,93 @@
 
 int fimc_ctrls_create(struct fimc_ctx *ctx)
 {
-	struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+	struct fimc_variant *variant = ctx->fimc_dev->variant;
 	unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
+	struct fimc_ctrls *ctrls = &ctx->ctrls;
+	struct v4l2_ctrl_handler *handler = &ctrls->handler;
 
-	if (ctx->ctrls_rdy)
+	if (ctx->ctrls.ready)
 		return 0;
-	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
 
-	ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
+	v4l2_ctrl_handler_init(handler, 6);
+
+	ctrls->rotate = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 					V4L2_CID_ROTATE, 0, 270, 90, 0);
-	ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
+	ctrls->hflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 					V4L2_CID_HFLIP, 0, 1, 1, 0);
-	ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
+	ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 					V4L2_CID_VFLIP, 0, 1, 1, 0);
+
 	if (variant->has_alpha)
-		ctx->ctrl_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
-				    &fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
-				    0, max_alpha, 1, 0);
+		ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
+					V4L2_CID_ALPHA_COMPONENT,
+					0, max_alpha, 1, 0);
 	else
-		ctx->ctrl_alpha = NULL;
+		ctrls->alpha = NULL;
 
-	ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
+	ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, &fimc_ctrl_ops,
+				V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR,
+				~0x983f, V4L2_COLORFX_NONE);
 
-	return ctx->ctrl_handler.error;
+	ctrls->colorfx_cbcr = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
+				V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0);
+
+	ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
+
+	if (!handler->error) {
+		v4l2_ctrl_cluster(3, &ctrls->colorfx);
+		ctrls->ready = true;
+	}
+
+	return handler->error;
 }
 
 void fimc_ctrls_delete(struct fimc_ctx *ctx)
 {
-	if (ctx->ctrls_rdy) {
-		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
-		ctx->ctrls_rdy = false;
-		ctx->ctrl_alpha = NULL;
+	struct fimc_ctrls *ctrls = &ctx->ctrls;
+
+	if (ctrls->ready) {
+		v4l2_ctrl_handler_free(&ctrls->handler);
+		ctrls->ready = false;
+		ctrls->alpha = NULL;
 	}
 }
 
 void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
 {
 	unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
+	struct fimc_ctrls *ctrls = &ctx->ctrls;
 
-	if (!ctx->ctrls_rdy)
+	if (!ctrls->ready)
 		return;
 
-	mutex_lock(&ctx->ctrl_handler.lock);
-	v4l2_ctrl_activate(ctx->ctrl_rotate, active);
-	v4l2_ctrl_activate(ctx->ctrl_hflip, active);
-	v4l2_ctrl_activate(ctx->ctrl_vflip, active);
-	if (ctx->ctrl_alpha)
-		v4l2_ctrl_activate(ctx->ctrl_alpha, active && has_alpha);
+	mutex_lock(&ctrls->handler.lock);
+	v4l2_ctrl_activate(ctrls->rotate, active);
+	v4l2_ctrl_activate(ctrls->hflip, active);
+	v4l2_ctrl_activate(ctrls->vflip, active);
+	v4l2_ctrl_activate(ctrls->colorfx, active);
+	if (ctrls->alpha)
+		v4l2_ctrl_activate(ctrls->alpha, active && has_alpha);
 
 	if (active) {
-		ctx->rotation = ctx->ctrl_rotate->val;
-		ctx->hflip    = ctx->ctrl_hflip->val;
-		ctx->vflip    = ctx->ctrl_vflip->val;
+		fimc_set_color_effect(ctx, ctrls->colorfx->cur.val);
+		ctx->rotation = ctrls->rotate->val;
+		ctx->hflip    = ctrls->hflip->val;
+		ctx->vflip    = ctrls->vflip->val;
 	} else {
+		ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
 		ctx->rotation = 0;
 		ctx->hflip    = 0;
 		ctx->vflip    = 0;
 	}
-	mutex_unlock(&ctx->ctrl_handler.lock);
+	mutex_unlock(&ctrls->handler.lock);
 }
 
 /* Update maximum value of the alpha color control */
 void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
 {
 	struct fimc_dev *fimc = ctx->fimc_dev;
-	struct v4l2_ctrl *ctrl = ctx->ctrl_alpha;
+	struct v4l2_ctrl *ctrl = ctx->ctrls.alpha;
 
 	if (ctrl == NULL || !fimc->variant->has_alpha)
 		return;
@@ -918,39 +681,6 @@
 	v4l2_ctrl_unlock(ctrl);
 }
 
-/*
- * V4L2 ioctl handlers
- */
-static int fimc_m2m_querycap(struct file *file, void *fh,
-			     struct v4l2_capability *cap)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-	struct fimc_dev *fimc = ctx->fimc_dev;
-
-	strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
-	strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
-	cap->bus_info[0] = 0;
-	cap->capabilities = V4L2_CAP_STREAMING |
-		V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
-
-	return 0;
-}
-
-static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
-				    struct v4l2_fmtdesc *f)
-{
-	struct fimc_fmt *fmt;
-
-	fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
-			       f->index);
-	if (!fmt)
-		return -EINVAL;
-
-	strncpy(f->description, fmt->name, sizeof(f->description) - 1);
-	f->pixelformat = fmt->fourcc;
-	return 0;
-}
-
 int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f)
 {
 	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
@@ -1029,18 +759,6 @@
 	}
 }
 
-static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
-				 struct v4l2_format *f)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-	struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
-
-	if (IS_ERR(frame))
-		return PTR_ERR(frame);
-
-	return fimc_fill_format(frame, f);
-}
-
 /**
  * fimc_find_format - lookup fimc color format by fourcc or media bus format
  * @pixelformat: fourcc to match, ignored if null
@@ -1073,535 +791,10 @@
 	return def_fmt;
 }
 
-static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
-{
-	struct fimc_dev *fimc = ctx->fimc_dev;
-	struct samsung_fimc_variant *variant = fimc->variant;
-	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
-	struct fimc_fmt *fmt;
-	u32 max_w, mod_x, mod_y;
-
-	if (!IS_M2M(f->type))
-		return -EINVAL;
-
-	dbg("w: %d, h: %d", pix->width, pix->height);
-
-	fmt = fimc_find_format(&pix->pixelformat, NULL,
-			       get_m2m_fmt_flags(f->type), 0);
-	if (WARN(fmt == NULL, "Pixel format lookup failed"))
-		return -EINVAL;
-
-	if (pix->field == V4L2_FIELD_ANY)
-		pix->field = V4L2_FIELD_NONE;
-	else if (pix->field != V4L2_FIELD_NONE)
-		return -EINVAL;
-
-	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		max_w = variant->pix_limit->scaler_dis_w;
-		mod_x = ffs(variant->min_inp_pixsize) - 1;
-	} else {
-		max_w = variant->pix_limit->out_rot_dis_w;
-		mod_x = ffs(variant->min_out_pixsize) - 1;
-	}
-
-	if (tiled_fmt(fmt)) {
-		mod_x = 6; /* 64 x 32 pixels tile */
-		mod_y = 5;
-	} else {
-		if (variant->min_vsize_align == 1)
-			mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
-		else
-			mod_y = ffs(variant->min_vsize_align) - 1;
-	}
-
-	v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
-		&pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
-
-	fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
-	return 0;
-}
-
-static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
-				   struct v4l2_format *f)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-
-	return fimc_try_fmt_mplane(ctx, f);
-}
-
-static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
-				 struct v4l2_format *f)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-	struct fimc_dev *fimc = ctx->fimc_dev;
-	struct vb2_queue *vq;
-	struct fimc_frame *frame;
-	struct v4l2_pix_format_mplane *pix;
-	int i, ret = 0;
-
-	ret = fimc_try_fmt_mplane(ctx, f);
-	if (ret)
-		return ret;
-
-	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
-
-	if (vb2_is_busy(vq)) {
-		v4l2_err(fimc->m2m.vfd, "queue (%d) busy\n", f->type);
-		return -EBUSY;
-	}
-
-	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-		frame = &ctx->s_frame;
-	else
-		frame = &ctx->d_frame;
-
-	pix = &f->fmt.pix_mp;
-	frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
-				      get_m2m_fmt_flags(f->type), 0);
-	if (!frame->fmt)
-		return -EINVAL;
-
-	/* Update RGB Alpha control state and value range */
-	fimc_alpha_ctrl_update(ctx);
-
-	for (i = 0; i < frame->fmt->colplanes; i++) {
-		frame->payload[i] =
-			(pix->width * pix->height * frame->fmt->depth[i]) / 8;
-	}
-
-	fimc_fill_frame(frame, f);
-
-	ctx->scaler.enabled = 1;
-
-	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-		fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
-	else
-		fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx);
-
-	dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
-
-	return 0;
-}
-
-static int fimc_m2m_reqbufs(struct file *file, void *fh,
-			    struct v4l2_requestbuffers *reqbufs)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-
-	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int fimc_m2m_querybuf(struct file *file, void *fh,
-			     struct v4l2_buffer *buf)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-
-	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int fimc_m2m_qbuf(struct file *file, void *fh,
-			 struct v4l2_buffer *buf)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-
-	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int fimc_m2m_dqbuf(struct file *file, void *fh,
-			  struct v4l2_buffer *buf)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-
-	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int fimc_m2m_streamon(struct file *file, void *fh,
-			     enum v4l2_buf_type type)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-
-	/* The source and target color format need to be set */
-	if (V4L2_TYPE_IS_OUTPUT(type)) {
-		if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx))
-			return -EINVAL;
-	} else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) {
-		return -EINVAL;
-	}
-
-	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int fimc_m2m_streamoff(struct file *file, void *fh,
-			    enum v4l2_buf_type type)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-
-	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
-static int fimc_m2m_cropcap(struct file *file, void *fh,
-			    struct v4l2_cropcap *cr)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-	struct fimc_frame *frame;
-
-	frame = ctx_get_frame(ctx, cr->type);
-	if (IS_ERR(frame))
-		return PTR_ERR(frame);
-
-	cr->bounds.left		= 0;
-	cr->bounds.top		= 0;
-	cr->bounds.width	= frame->o_width;
-	cr->bounds.height	= frame->o_height;
-	cr->defrect		= cr->bounds;
-
-	return 0;
-}
-
-static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-	struct fimc_frame *frame;
-
-	frame = ctx_get_frame(ctx, cr->type);
-	if (IS_ERR(frame))
-		return PTR_ERR(frame);
-
-	cr->c.left = frame->offs_h;
-	cr->c.top = frame->offs_v;
-	cr->c.width = frame->width;
-	cr->c.height = frame->height;
-
-	return 0;
-}
-
-static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
-{
-	struct fimc_dev *fimc = ctx->fimc_dev;
-	struct fimc_frame *f;
-	u32 min_size, halign, depth = 0;
-	int i;
-
-	if (cr->c.top < 0 || cr->c.left < 0) {
-		v4l2_err(fimc->m2m.vfd,
-			"doesn't support negative values for top & left\n");
-		return -EINVAL;
-	}
-	if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-		f = &ctx->d_frame;
-	else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-		f = &ctx->s_frame;
-	else
-		return -EINVAL;
-
-	min_size = (f == &ctx->s_frame) ?
-		fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
-
-	/* Get pixel alignment constraints. */
-	if (fimc->variant->min_vsize_align == 1)
-		halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
-	else
-		halign = ffs(fimc->variant->min_vsize_align) - 1;
-
-	for (i = 0; i < f->fmt->colplanes; i++)
-		depth += f->fmt->depth[i];
-
-	v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
-			      ffs(min_size) - 1,
-			      &cr->c.height, min_size, f->o_height,
-			      halign, 64/(ALIGN(depth, 8)));
-
-	/* adjust left/top if cropping rectangle is out of bounds */
-	if (cr->c.left + cr->c.width > f->o_width)
-		cr->c.left = f->o_width - cr->c.width;
-	if (cr->c.top + cr->c.height > f->o_height)
-		cr->c.top = f->o_height - cr->c.height;
-
-	cr->c.left = round_down(cr->c.left, min_size);
-	cr->c.top  = round_down(cr->c.top, fimc->variant->hor_offs_align);
-
-	dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
-	    cr->c.left, cr->c.top, cr->c.width, cr->c.height,
-	    f->f_width, f->f_height);
-
-	return 0;
-}
-
-static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(fh);
-	struct fimc_dev *fimc = ctx->fimc_dev;
-	struct fimc_frame *f;
-	int ret;
-
-	ret = fimc_m2m_try_crop(ctx, cr);
-	if (ret)
-		return ret;
-
-	f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
-		&ctx->s_frame : &ctx->d_frame;
-
-	/* Check to see if scaling ratio is within supported range */
-	if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
-		if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-			ret = fimc_check_scaler_ratio(ctx, cr->c.width,
-					cr->c.height, ctx->d_frame.width,
-					ctx->d_frame.height, ctx->rotation);
-		} else {
-			ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
-					ctx->s_frame.height, cr->c.width,
-					cr->c.height, ctx->rotation);
-		}
-		if (ret) {
-			v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
-			return -EINVAL;
-		}
-	}
-
-	f->offs_h = cr->c.left;
-	f->offs_v = cr->c.top;
-	f->width  = cr->c.width;
-	f->height = cr->c.height;
-
-	fimc_ctx_state_lock_set(FIMC_PARAMS, ctx);
-
-	return 0;
-}
-
-static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
-	.vidioc_querycap		= fimc_m2m_querycap,
-
-	.vidioc_enum_fmt_vid_cap_mplane	= fimc_m2m_enum_fmt_mplane,
-	.vidioc_enum_fmt_vid_out_mplane	= fimc_m2m_enum_fmt_mplane,
-
-	.vidioc_g_fmt_vid_cap_mplane	= fimc_m2m_g_fmt_mplane,
-	.vidioc_g_fmt_vid_out_mplane	= fimc_m2m_g_fmt_mplane,
-
-	.vidioc_try_fmt_vid_cap_mplane	= fimc_m2m_try_fmt_mplane,
-	.vidioc_try_fmt_vid_out_mplane	= fimc_m2m_try_fmt_mplane,
-
-	.vidioc_s_fmt_vid_cap_mplane	= fimc_m2m_s_fmt_mplane,
-	.vidioc_s_fmt_vid_out_mplane	= fimc_m2m_s_fmt_mplane,
-
-	.vidioc_reqbufs			= fimc_m2m_reqbufs,
-	.vidioc_querybuf		= fimc_m2m_querybuf,
-
-	.vidioc_qbuf			= fimc_m2m_qbuf,
-	.vidioc_dqbuf			= fimc_m2m_dqbuf,
-
-	.vidioc_streamon		= fimc_m2m_streamon,
-	.vidioc_streamoff		= fimc_m2m_streamoff,
-
-	.vidioc_g_crop			= fimc_m2m_g_crop,
-	.vidioc_s_crop			= fimc_m2m_s_crop,
-	.vidioc_cropcap			= fimc_m2m_cropcap
-
-};
-
-static int queue_init(void *priv, struct vb2_queue *src_vq,
-		      struct vb2_queue *dst_vq)
-{
-	struct fimc_ctx *ctx = priv;
-	int ret;
-
-	memset(src_vq, 0, sizeof(*src_vq));
-	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
-	src_vq->drv_priv = ctx;
-	src_vq->ops = &fimc_qops;
-	src_vq->mem_ops = &vb2_dma_contig_memops;
-	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-
-	ret = vb2_queue_init(src_vq);
-	if (ret)
-		return ret;
-
-	memset(dst_vq, 0, sizeof(*dst_vq));
-	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
-	dst_vq->drv_priv = ctx;
-	dst_vq->ops = &fimc_qops;
-	dst_vq->mem_ops = &vb2_dma_contig_memops;
-	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-
-	return vb2_queue_init(dst_vq);
-}
-
-static int fimc_m2m_open(struct file *file)
-{
-	struct fimc_dev *fimc = video_drvdata(file);
-	struct fimc_ctx *ctx;
-	int ret;
-
-	dbg("pid: %d, state: 0x%lx, refcnt: %d",
-		task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
-
-	/*
-	 * Return if the corresponding video capture node
-	 * is already opened.
-	 */
-	if (fimc->vid_cap.refcnt > 0)
-		return -EBUSY;
-
-	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
-	if (!ctx)
-		return -ENOMEM;
-	v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
-	ctx->fimc_dev = fimc;
-
-	/* Default color format */
-	ctx->s_frame.fmt = &fimc_formats[0];
-	ctx->d_frame.fmt = &fimc_formats[0];
-
-	ret = fimc_ctrls_create(ctx);
-	if (ret)
-		goto error_fh;
-
-	/* Use separate control handler per file handle */
-	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
-	file->private_data = &ctx->fh;
-	v4l2_fh_add(&ctx->fh);
-
-	/* Setup the device context for memory-to-memory mode */
-	ctx->state = FIMC_CTX_M2M;
-	ctx->flags = 0;
-	ctx->in_path = FIMC_DMA;
-	ctx->out_path = FIMC_DMA;
-	spin_lock_init(&ctx->slock);
-
-	ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
-	if (IS_ERR(ctx->m2m_ctx)) {
-		ret = PTR_ERR(ctx->m2m_ctx);
-		goto error_c;
-	}
-
-	if (fimc->m2m.refcnt++ == 0)
-		set_bit(ST_M2M_RUN, &fimc->state);
-	return 0;
-
-error_c:
-	fimc_ctrls_delete(ctx);
-error_fh:
-	v4l2_fh_del(&ctx->fh);
-	v4l2_fh_exit(&ctx->fh);
-	kfree(ctx);
-	return ret;
-}
-
-static int fimc_m2m_release(struct file *file)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
-	struct fimc_dev *fimc = ctx->fimc_dev;
-
-	dbg("pid: %d, state: 0x%lx, refcnt= %d",
-		task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
-
-	v4l2_m2m_ctx_release(ctx->m2m_ctx);
-	fimc_ctrls_delete(ctx);
-	v4l2_fh_del(&ctx->fh);
-	v4l2_fh_exit(&ctx->fh);
-
-	if (--fimc->m2m.refcnt <= 0)
-		clear_bit(ST_M2M_RUN, &fimc->state);
-	kfree(ctx);
-	return 0;
-}
-
-static unsigned int fimc_m2m_poll(struct file *file,
-				  struct poll_table_struct *wait)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
-
-	return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
-}
-
-
-static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
-
-	return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-}
-
-static const struct v4l2_file_operations fimc_m2m_fops = {
-	.owner		= THIS_MODULE,
-	.open		= fimc_m2m_open,
-	.release	= fimc_m2m_release,
-	.poll		= fimc_m2m_poll,
-	.unlocked_ioctl	= video_ioctl2,
-	.mmap		= fimc_m2m_mmap,
-};
-
-static struct v4l2_m2m_ops m2m_ops = {
-	.device_run	= fimc_dma_run,
-	.job_abort	= fimc_job_abort,
-};
-
-int fimc_register_m2m_device(struct fimc_dev *fimc,
-			     struct v4l2_device *v4l2_dev)
-{
-	struct video_device *vfd;
-	struct platform_device *pdev;
-	int ret = 0;
-
-	if (!fimc)
-		return -ENODEV;
-
-	pdev = fimc->pdev;
-	fimc->v4l2_dev = v4l2_dev;
-
-	vfd = video_device_alloc();
-	if (!vfd) {
-		v4l2_err(v4l2_dev, "Failed to allocate video device\n");
-		return -ENOMEM;
-	}
-
-	vfd->fops	= &fimc_m2m_fops;
-	vfd->ioctl_ops	= &fimc_m2m_ioctl_ops;
-	vfd->v4l2_dev	= v4l2_dev;
-	vfd->minor	= -1;
-	vfd->release	= video_device_release;
-	vfd->lock	= &fimc->lock;
-
-	snprintf(vfd->name, sizeof(vfd->name), "%s.m2m", dev_name(&pdev->dev));
-	video_set_drvdata(vfd, fimc);
-
-	fimc->m2m.vfd = vfd;
-	fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
-	if (IS_ERR(fimc->m2m.m2m_dev)) {
-		v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
-		ret = PTR_ERR(fimc->m2m.m2m_dev);
-		goto err_init;
-	}
-
-	ret = media_entity_init(&vfd->entity, 0, NULL, 0);
-	if (!ret)
-		return 0;
-
-	v4l2_m2m_release(fimc->m2m.m2m_dev);
-err_init:
-	video_device_release(fimc->m2m.vfd);
-	return ret;
-}
-
-void fimc_unregister_m2m_device(struct fimc_dev *fimc)
-{
-	if (!fimc)
-		return;
-
-	if (fimc->m2m.m2m_dev)
-		v4l2_m2m_release(fimc->m2m.m2m_dev);
-	if (fimc->m2m.vfd) {
-		media_entity_cleanup(&fimc->m2m.vfd->entity);
-		/* Can also be called if video device wasn't registered */
-		video_unregister_device(fimc->m2m.vfd);
-	}
-}
-
 static void fimc_clk_put(struct fimc_dev *fimc)
 {
 	int i;
-	for (i = 0; i < fimc->num_clocks; i++) {
+	for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
 		if (IS_ERR_OR_NULL(fimc->clock[i]))
 			continue;
 		clk_unprepare(fimc->clock[i]);
@@ -1614,7 +807,7 @@
 {
 	int i, ret;
 
-	for (i = 0; i < fimc->num_clocks; i++) {
+	for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
 		fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
 		if (IS_ERR(fimc->clock[i]))
 			goto err;
@@ -1672,15 +865,12 @@
 
 static int fimc_probe(struct platform_device *pdev)
 {
+	struct fimc_drvdata *drv_data = fimc_get_drvdata(pdev);
+	struct s5p_platform_fimc *pdata;
 	struct fimc_dev *fimc;
 	struct resource *res;
-	struct samsung_fimc_driverdata *drv_data;
-	struct s5p_platform_fimc *pdata;
 	int ret = 0;
 
-	drv_data = (struct samsung_fimc_driverdata *)
-		platform_get_device_id(pdev)->driver_data;
-
 	if (pdev->id >= drv_data->num_entities) {
 		dev_err(&pdev->dev, "Invalid platform device id: %d\n",
 			pdev->id);
@@ -1714,28 +904,29 @@
 		dev_err(&pdev->dev, "Failed to get IRQ resource\n");
 		return -ENXIO;
 	}
-	fimc->irq = res->start;
 
-	fimc->num_clocks = MAX_FIMC_CLOCKS;
 	ret = fimc_clk_get(fimc);
 	if (ret)
 		return ret;
 	clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
 	clk_enable(fimc->clock[CLK_BUS]);
 
-	platform_set_drvdata(pdev, fimc);
-
-	ret = devm_request_irq(&pdev->dev, fimc->irq, fimc_irq_handler,
-			       0, pdev->name, fimc);
+	ret = devm_request_irq(&pdev->dev, res->start, fimc_irq_handler,
+			       0, dev_name(&pdev->dev), fimc);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
 		goto err_clk;
 	}
 
+	ret = fimc_initialize_capture_subdev(fimc);
+	if (ret)
+		goto err_clk;
+
+	platform_set_drvdata(pdev, fimc);
 	pm_runtime_enable(&pdev->dev);
 	ret = pm_runtime_get_sync(&pdev->dev);
 	if (ret < 0)
-		goto err_clk;
+		goto err_sd;
 	/* Initialize contiguous memory allocator */
 	fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
 	if (IS_ERR(fimc->alloc_ctx)) {
@@ -1747,9 +938,10 @@
 
 	pm_runtime_put(&pdev->dev);
 	return 0;
-
 err_pm:
 	pm_runtime_put(&pdev->dev);
+err_sd:
+	fimc_unregister_capture_subdev(fimc);
 err_clk:
 	fimc_clk_put(fimc);
 	return ret;
@@ -1834,6 +1026,7 @@
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 
+	fimc_unregister_capture_subdev(fimc);
 	vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
 
 	clk_disable(fimc->clock[CLK_BUS]);
@@ -1879,7 +1072,7 @@
 	},
 };
 
-static struct samsung_fimc_variant fimc0_variant_s5p = {
+static struct fimc_variant fimc0_variant_s5p = {
 	.has_inp_rot	 = 1,
 	.has_out_rot	 = 1,
 	.has_cam_if	 = 1,
@@ -1891,17 +1084,17 @@
 	.pix_limit	 = &s5p_pix_limit[0],
 };
 
-static struct samsung_fimc_variant fimc2_variant_s5p = {
+static struct fimc_variant fimc2_variant_s5p = {
 	.has_cam_if	 = 1,
 	.min_inp_pixsize = 16,
 	.min_out_pixsize = 16,
 	.hor_offs_align	 = 8,
 	.min_vsize_align = 16,
 	.out_buf_count	 = 4,
-	.pix_limit = &s5p_pix_limit[1],
+	.pix_limit	 = &s5p_pix_limit[1],
 };
 
-static struct samsung_fimc_variant fimc0_variant_s5pv210 = {
+static struct fimc_variant fimc0_variant_s5pv210 = {
 	.pix_hoff	 = 1,
 	.has_inp_rot	 = 1,
 	.has_out_rot	 = 1,
@@ -1914,7 +1107,7 @@
 	.pix_limit	 = &s5p_pix_limit[1],
 };
 
-static struct samsung_fimc_variant fimc1_variant_s5pv210 = {
+static struct fimc_variant fimc1_variant_s5pv210 = {
 	.pix_hoff	 = 1,
 	.has_inp_rot	 = 1,
 	.has_out_rot	 = 1,
@@ -1928,7 +1121,7 @@
 	.pix_limit	 = &s5p_pix_limit[2],
 };
 
-static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
+static struct fimc_variant fimc2_variant_s5pv210 = {
 	.has_cam_if	 = 1,
 	.pix_hoff	 = 1,
 	.min_inp_pixsize = 16,
@@ -1939,7 +1132,7 @@
 	.pix_limit	 = &s5p_pix_limit[2],
 };
 
-static struct samsung_fimc_variant fimc0_variant_exynos4 = {
+static struct fimc_variant fimc0_variant_exynos4 = {
 	.pix_hoff	 = 1,
 	.has_inp_rot	 = 1,
 	.has_out_rot	 = 1,
@@ -1955,7 +1148,7 @@
 	.pix_limit	 = &s5p_pix_limit[1],
 };
 
-static struct samsung_fimc_variant fimc3_variant_exynos4 = {
+static struct fimc_variant fimc3_variant_exynos4 = {
 	.pix_hoff	 = 1,
 	.has_cam_if	 = 1,
 	.has_cistatus2	 = 1,
@@ -1970,7 +1163,7 @@
 };
 
 /* S5PC100 */
-static struct samsung_fimc_driverdata fimc_drvdata_s5p = {
+static struct fimc_drvdata fimc_drvdata_s5p = {
 	.variant = {
 		[0] = &fimc0_variant_s5p,
 		[1] = &fimc0_variant_s5p,
@@ -1981,7 +1174,7 @@
 };
 
 /* S5PV210, S5PC110 */
-static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
+static struct fimc_drvdata fimc_drvdata_s5pv210 = {
 	.variant = {
 		[0] = &fimc0_variant_s5pv210,
 		[1] = &fimc1_variant_s5pv210,
@@ -1991,8 +1184,8 @@
 	.lclk_frequency = 166000000UL,
 };
 
-/* S5PV310, S5PC210 */
-static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = {
+/* EXYNOS4210, S5PV310, S5PC210 */
+static struct fimc_drvdata fimc_drvdata_exynos4 = {
 	.variant = {
 		[0] = &fimc0_variant_exynos4,
 		[1] = &fimc0_variant_exynos4,
@@ -2036,7 +1229,7 @@
 
 int __init fimc_register_driver(void)
 {
-	return platform_driver_probe(&fimc_driver, fimc_probe);
+	return platform_driver_register(&fimc_driver);
 }
 
 void __exit fimc_unregister_driver(void)
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 84fd835..95b27ae 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
+ * Copyright (C) 2010 - 2012 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 version 2 as
@@ -17,6 +17,7 @@
 #include <linux/types.h>
 #include <linux/videodev2.h>
 #include <linux/io.h>
+#include <asm/sizes.h>
 
 #include <media/media-entity.h>
 #include <media/videobuf2-core.h>
@@ -26,8 +27,6 @@
 #include <media/v4l2-mediabus.h>
 #include <media/s5p_fimc.h>
 
-#include "regs-fimc.h"
-
 #define err(fmt, args...) \
 	printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
 
@@ -78,26 +77,31 @@
 #define fimc_capture_busy(dev) test_bit(ST_CAPT_BUSY, &(dev)->state)
 
 enum fimc_datapath {
-	FIMC_CAMERA,
-	FIMC_DMA,
-	FIMC_LCDFIFO,
-	FIMC_WRITEBACK
+	FIMC_IO_NONE,
+	FIMC_IO_CAMERA,
+	FIMC_IO_DMA,
+	FIMC_IO_LCDFIFO,
+	FIMC_IO_WRITEBACK,
+	FIMC_IO_ISP,
 };
 
 enum fimc_color_fmt {
-	S5P_FIMC_RGB444 = 0x10,
-	S5P_FIMC_RGB555,
-	S5P_FIMC_RGB565,
-	S5P_FIMC_RGB666,
-	S5P_FIMC_RGB888,
-	S5P_FIMC_RGB30_LOCAL,
-	S5P_FIMC_YCBCR420 = 0x20,
-	S5P_FIMC_YCBYCR422,
-	S5P_FIMC_YCRYCB422,
-	S5P_FIMC_CBYCRY422,
-	S5P_FIMC_CRYCBY422,
-	S5P_FIMC_YCBCR444_LOCAL,
-	S5P_FIMC_JPEG = 0x40,
+	FIMC_FMT_RGB444 = 0x10,
+	FIMC_FMT_RGB555,
+	FIMC_FMT_RGB565,
+	FIMC_FMT_RGB666,
+	FIMC_FMT_RGB888,
+	FIMC_FMT_RGB30_LOCAL,
+	FIMC_FMT_YCBCR420 = 0x20,
+	FIMC_FMT_YCBYCR422,
+	FIMC_FMT_YCRYCB422,
+	FIMC_FMT_CBYCRY422,
+	FIMC_FMT_CRYCBY422,
+	FIMC_FMT_YCBCR444_LOCAL,
+	FIMC_FMT_JPEG = 0x40,
+	FIMC_FMT_RAW8 = 0x80,
+	FIMC_FMT_RAW10,
+	FIMC_FMT_RAW12,
 };
 
 #define fimc_fmt_is_rgb(x) (!!((x) & 0x10))
@@ -106,24 +110,11 @@
 #define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \
 			__strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 
-/* Cb/Cr chrominance components order for 2 plane Y/CbCr 4:2:2 formats. */
-#define	S5P_FIMC_LSB_CRCB	S5P_CIOCTRL_ORDER422_2P_LSB_CRCB
-
-/* The embedded image effect selection */
-#define	S5P_FIMC_EFFECT_ORIGINAL	S5P_CIIMGEFF_FIN_BYPASS
-#define	S5P_FIMC_EFFECT_ARBITRARY	S5P_CIIMGEFF_FIN_ARBITRARY
-#define	S5P_FIMC_EFFECT_NEGATIVE	S5P_CIIMGEFF_FIN_NEGATIVE
-#define	S5P_FIMC_EFFECT_ARTFREEZE	S5P_CIIMGEFF_FIN_ARTFREEZE
-#define	S5P_FIMC_EFFECT_EMBOSSING	S5P_CIIMGEFF_FIN_EMBOSSING
-#define	S5P_FIMC_EFFECT_SIKHOUETTE	S5P_CIIMGEFF_FIN_SILHOUETTE
-
 /* The hardware context state. */
 #define	FIMC_PARAMS		(1 << 0)
-#define	FIMC_SRC_ADDR		(1 << 1)
-#define	FIMC_DST_ADDR		(1 << 2)
 #define	FIMC_SRC_FMT		(1 << 3)
 #define	FIMC_DST_FMT		(1 << 4)
-#define	FIMC_DST_CROP		(1 << 5)
+#define	FIMC_COMPOSE		(1 << 5)
 #define	FIMC_CTX_M2M		(1 << 16)
 #define	FIMC_CTX_CAP		(1 << 17)
 #define	FIMC_CTX_SHUT		(1 << 18)
@@ -333,7 +324,7 @@
 	struct fimc_ctx			*ctx;
 	struct vb2_alloc_ctx		*alloc_ctx;
 	struct video_device		*vfd;
-	struct v4l2_subdev		*subdev;
+	struct v4l2_subdev		subdev;
 	struct media_pad		vd_pad;
 	struct v4l2_mbus_framefmt	mf;
 	struct media_pad		sd_pads[FIMC_SD_PADS_NUM];
@@ -370,8 +361,7 @@
 };
 
 /**
- * struct samsung_fimc_variant - camera interface variant information
- *
+ * struct fimc_variant - FIMC device variant information
  * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
  * @has_inp_rot: set if has input rotator
  * @has_out_rot: set if has output rotator
@@ -386,7 +376,7 @@
  * @min_vsize_align: minimum vertical pixel size alignment
  * @out_buf_count: the number of buffers in output DMA sequence
  */
-struct samsung_fimc_variant {
+struct fimc_variant {
 	unsigned int	pix_hoff:1;
 	unsigned int	has_inp_rot:1;
 	unsigned int	has_out_rot:1;
@@ -403,23 +393,19 @@
 };
 
 /**
- * struct samsung_fimc_driverdata - per device type driver data for init time.
- *
- * @variant: the variant information for this driver.
- * @dev_cnt: number of fimc sub-devices available in SoC
- * @lclk_frequency: fimc bus clock frequency
+ * struct fimc_drvdata - per device type driver data
+ * @variant: variant information for this device
+ * @num_entities: number of fimc instances available in a SoC
+ * @lclk_frequency: local bus clock frequency
  */
-struct samsung_fimc_driverdata {
-	struct samsung_fimc_variant *variant[FIMC_MAX_DEVS];
-	unsigned long	lclk_frequency;
-	int		num_entities;
+struct fimc_drvdata {
+	struct fimc_variant *variant[FIMC_MAX_DEVS];
+	int num_entities;
+	unsigned long lclk_frequency;
 };
 
-struct fimc_pipeline {
-	struct media_pipeline *pipe;
-	struct v4l2_subdev *sensor;
-	struct v4l2_subdev *csis;
-};
+#define fimc_get_drvdata(_pdev) \
+	((struct fimc_drvdata *) platform_get_device_id(_pdev)->driver_data)
 
 struct fimc_ctx;
 
@@ -431,10 +417,8 @@
  * @pdata:	pointer to the device platform data
  * @variant:	the IP variant information
  * @id:		FIMC device index (0..FIMC_MAX_DEVS)
- * @num_clocks: the number of clocks managed by this device instance
  * @clock:	clocks required for FIMC operation
  * @regs:	the mapped hardware registers
- * @irq:	FIMC interrupt number
  * @irq_queue:	interrupt handler waitqueue
  * @v4l2_dev:	root v4l2_device
  * @m2m:	memory-to-memory V4L2 device information
@@ -448,12 +432,10 @@
 	struct mutex			lock;
 	struct platform_device		*pdev;
 	struct s5p_platform_fimc	*pdata;
-	struct samsung_fimc_variant	*variant;
+	struct fimc_variant		*variant;
 	u16				id;
-	u16				num_clocks;
 	struct clk			*clock[MAX_FIMC_CLOCKS];
 	void __iomem			*regs;
-	int				irq;
 	wait_queue_head_t		irq_queue;
 	struct v4l2_device		*v4l2_dev;
 	struct fimc_m2m_device		m2m;
@@ -464,8 +446,31 @@
 };
 
 /**
+ * struct fimc_ctrls - v4l2 controls structure
+ * @handler: the control handler
+ * @colorfx: image effect control
+ * @colorfx_cbcr: Cb/Cr coefficients control
+ * @rotate: image rotation control
+ * @hflip: horizontal flip control
+ * @vflip: vertical flip control
+ * @alpha: RGB alpha control
+ * @ready: true if @handler is initialized
+ */
+struct fimc_ctrls {
+	struct v4l2_ctrl_handler handler;
+	struct {
+		struct v4l2_ctrl *colorfx;
+		struct v4l2_ctrl *colorfx_cbcr;
+	};
+	struct v4l2_ctrl *rotate;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *alpha;
+	bool ready;
+};
+
+/**
  * fimc_ctx - the device context data
- * @slock:		spinlock protecting this data structure
  * @s_frame:		source frame properties
  * @d_frame:		destination frame properties
  * @out_order_1p:	output 1-plane YCBCR order
@@ -484,15 +489,9 @@
  * @fimc_dev:		the FIMC device this context applies to
  * @m2m_ctx:		memory-to-memory device context
  * @fh:			v4l2 file handle
- * @ctrl_handler:	v4l2 controls handler
- * @ctrl_rotate		image rotation control
- * @ctrl_hflip		horizontal flip control
- * @ctrl_vflip		vertical flip control
- * @ctrl_alpha		RGB alpha control
- * @ctrls_rdy:		true if the control handler is initialized
+ * @ctrls:		v4l2 controls structure
  */
 struct fimc_ctx {
-	spinlock_t		slock;
 	struct fimc_frame	s_frame;
 	struct fimc_frame	d_frame;
 	u32			out_order_1p;
@@ -511,12 +510,7 @@
 	struct fimc_dev		*fimc_dev;
 	struct v4l2_m2m_ctx	*m2m_ctx;
 	struct v4l2_fh		fh;
-	struct v4l2_ctrl_handler ctrl_handler;
-	struct v4l2_ctrl	*ctrl_rotate;
-	struct v4l2_ctrl	*ctrl_hflip;
-	struct v4l2_ctrl	*ctrl_vflip;
-	struct v4l2_ctrl	*ctrl_alpha;
-	bool			ctrls_rdy;
+	struct fimc_ctrls	ctrls;
 };
 
 #define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh)
@@ -560,13 +554,13 @@
 	return ret;
 }
 
-static inline void fimc_ctx_state_lock_set(u32 state, struct fimc_ctx *ctx)
+static inline void fimc_ctx_state_set(u32 state, struct fimc_ctx *ctx)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&ctx->slock, flags);
+	spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
 	ctx->state |= state;
-	spin_unlock_irqrestore(&ctx->slock, flags);
+	spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
 }
 
 static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx)
@@ -574,9 +568,9 @@
 	unsigned long flags;
 	bool ret;
 
-	spin_lock_irqsave(&ctx->slock, flags);
+	spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
 	ret = (ctx->state & mask) == mask;
-	spin_unlock_irqrestore(&ctx->slock, flags);
+	spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
 	return ret;
 }
 
@@ -589,61 +583,13 @@
 static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt)
 {
 	switch (fmt->color) {
-	case S5P_FIMC_RGB444:	return 0x0f;
-	case S5P_FIMC_RGB555:	return 0x01;
-	case S5P_FIMC_RGB888:	return 0xff;
+	case FIMC_FMT_RGB444:	return 0x0f;
+	case FIMC_FMT_RGB555:	return 0x01;
+	case FIMC_FMT_RGB888:	return 0xff;
 	default:		return 0;
 	};
 }
 
-static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
-{
-	u32 cfg = readl(dev->regs + S5P_CIGCTRL);
-	cfg |= S5P_CIGCTRL_IRQ_CLR;
-	writel(cfg, dev->regs + S5P_CIGCTRL);
-}
-
-static inline void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
-{
-	u32 cfg = readl(dev->regs + S5P_CISCCTRL);
-	if (on)
-		cfg |= S5P_CISCCTRL_SCALERSTART;
-	else
-		cfg &= ~S5P_CISCCTRL_SCALERSTART;
-	writel(cfg, dev->regs + S5P_CISCCTRL);
-}
-
-static inline void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
-{
-	u32 cfg = readl(dev->regs + S5P_MSCTRL);
-	if (on)
-		cfg |= S5P_MSCTRL_ENVID;
-	else
-		cfg &= ~S5P_MSCTRL_ENVID;
-	writel(cfg, dev->regs + S5P_MSCTRL);
-}
-
-static inline void fimc_hw_dis_capture(struct fimc_dev *dev)
-{
-	u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
-	cfg &= ~(S5P_CIIMGCPT_IMGCPTEN | S5P_CIIMGCPT_IMGCPTEN_SC);
-	writel(cfg, dev->regs + S5P_CIIMGCPT);
-}
-
-/**
- * fimc_hw_set_dma_seq - configure output DMA buffer sequence
- * @mask: each bit corresponds to one of 32 output buffer registers set
- *	  1 to include buffer in the sequence, 0 to disable
- *
- * This function mask output DMA ring buffers, i.e. it allows to configure
- * which of the output buffer address registers will be used by the DMA
- * engine.
- */
-static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask)
-{
-	writel(mask, dev->regs + S5P_CIFCNTSEQ);
-}
-
 static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
 					       enum v4l2_buf_type type)
 {
@@ -665,48 +611,6 @@
 	return frame;
 }
 
-/* Return an index to the buffer actually being written. */
-static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
-{
-	u32 reg;
-
-	if (dev->variant->has_cistatus2) {
-		reg = readl(dev->regs + S5P_CISTATUS2) & 0x3F;
-		return reg > 0 ? --reg : reg;
-	} else {
-		reg = readl(dev->regs + S5P_CISTATUS);
-		return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
-			S5P_CISTATUS_FRAMECNT_SHIFT;
-	}
-}
-
-/* -----------------------------------------------------*/
-/* fimc-reg.c						*/
-void fimc_hw_reset(struct fimc_dev *fimc);
-void fimc_hw_set_rotation(struct fimc_ctx *ctx);
-void fimc_hw_set_target_format(struct fimc_ctx *ctx);
-void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
-void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
-void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
-void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
-void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
-void fimc_hw_en_capture(struct fimc_ctx *ctx);
-void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active);
-void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
-void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
-void fimc_hw_set_input_path(struct fimc_ctx *ctx);
-void fimc_hw_set_output_path(struct fimc_ctx *ctx);
-void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
-void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
-			     int index);
-int fimc_hw_set_camera_source(struct fimc_dev *fimc,
-			      struct s5p_fimc_isp_info *cam);
-int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
-int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
-				struct s5p_fimc_isp_info *cam);
-int fimc_hw_set_camera_type(struct fimc_dev *fimc,
-			    struct s5p_fimc_isp_info *cam);
-
 /* -----------------------------------------------------*/
 /* fimc-core.c */
 int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
@@ -720,6 +624,7 @@
 			       struct v4l2_pix_format_mplane *pix);
 struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code,
 				  unsigned int mask, int index);
+struct fimc_fmt *fimc_get_format(unsigned int index);
 
 int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
 			    int dw, int dh, int rotation);
@@ -730,7 +635,7 @@
 void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f);
 void fimc_set_yuv_order(struct fimc_ctx *ctx);
 void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f);
-void fimc_capture_irq_handler(struct fimc_dev *fimc, bool done);
+void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf);
 
 int fimc_register_m2m_device(struct fimc_dev *fimc,
 			     struct v4l2_device *v4l2_dev);
@@ -739,33 +644,18 @@
 void fimc_unregister_driver(void);
 
 /* -----------------------------------------------------*/
+/* fimc-m2m.c */
+void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state);
+
+/* -----------------------------------------------------*/
 /* fimc-capture.c					*/
-int fimc_register_capture_device(struct fimc_dev *fimc,
-				 struct v4l2_device *v4l2_dev);
-void fimc_unregister_capture_device(struct fimc_dev *fimc);
+int fimc_initialize_capture_subdev(struct fimc_dev *fimc);
+void fimc_unregister_capture_subdev(struct fimc_dev *fimc);
 int fimc_capture_ctrls_create(struct fimc_dev *fimc);
-int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
-			     struct fimc_vid_buffer *fimc_vb);
 void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
 			void *arg);
 int fimc_capture_suspend(struct fimc_dev *fimc);
 int fimc_capture_resume(struct fimc_dev *fimc);
-int fimc_capture_config_update(struct fimc_ctx *ctx);
-
-/* Locking: the caller holds fimc->slock */
-static inline void fimc_activate_capture(struct fimc_ctx *ctx)
-{
-	fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
-	fimc_hw_en_capture(ctx);
-}
-
-static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
-{
-	fimc_hw_en_lastirq(fimc, true);
-	fimc_hw_dis_capture(fimc);
-	fimc_hw_enable_scaler(fimc, false);
-	fimc_hw_en_lastirq(fimc, false);
-}
 
 /*
  * Buffer list manipulation functions. Must be called with fimc.slock held.
diff --git a/drivers/media/video/s5p-fimc/fimc-lite-reg.c b/drivers/media/video/s5p-fimc/fimc-lite-reg.c
new file mode 100644
index 0000000..419adfb
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-lite-reg.c
@@ -0,0 +1,300 @@
+/*
+ * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@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/io.h>
+#include <linux/delay.h>
+#include <media/s5p_fimc.h>
+
+#include "fimc-lite-reg.h"
+#include "fimc-lite.h"
+#include "fimc-core.h"
+
+#define FLITE_RESET_TIMEOUT 50 /* in ms */
+
+void flite_hw_reset(struct fimc_lite *dev)
+{
+	unsigned long end = jiffies + msecs_to_jiffies(FLITE_RESET_TIMEOUT);
+	u32 cfg;
+
+	cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	cfg |= FLITE_REG_CIGCTRL_SWRST_REQ;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+	while (time_is_after_jiffies(end)) {
+		cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+		if (cfg & FLITE_REG_CIGCTRL_SWRST_RDY)
+			break;
+		usleep_range(1000, 5000);
+	}
+
+	cfg |= FLITE_REG_CIGCTRL_SWRST;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_clear_pending_irq(struct fimc_lite *dev)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS);
+	cfg &= ~FLITE_REG_CISTATUS_IRQ_CAM;
+	writel(cfg, dev->regs + FLITE_REG_CISTATUS);
+}
+
+u32 flite_hw_get_interrupt_source(struct fimc_lite *dev)
+{
+	u32 intsrc = readl(dev->regs + FLITE_REG_CISTATUS);
+	return intsrc & FLITE_REG_CISTATUS_IRQ_MASK;
+}
+
+void flite_hw_clear_last_capture_end(struct fimc_lite *dev)
+{
+
+	u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS2);
+	cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
+	writel(cfg, dev->regs + FLITE_REG_CISTATUS2);
+}
+
+void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
+{
+	u32 cfg, intsrc;
+
+	/* Select interrupts to be enabled for each output mode */
+	if (dev->out_path == FIMC_IO_DMA) {
+		intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
+			 FLITE_REG_CIGCTRL_IRQ_LASTEN |
+			 FLITE_REG_CIGCTRL_IRQ_STARTEN;
+	} else {
+		/* An output to the FIMC-IS */
+		intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
+			 FLITE_REG_CIGCTRL_IRQ_LASTEN;
+	}
+
+	cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	cfg |= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK;
+	cfg &= ~intsrc;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_capture_start(struct fimc_lite *dev)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
+	cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
+	writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
+}
+
+void flite_hw_capture_stop(struct fimc_lite *dev)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
+	cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
+	writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
+}
+
+/*
+ * Test pattern (color bars) enable/disable. External sensor
+ * pixel clock must be active for the test pattern to work.
+ */
+void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	if (on)
+		cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+	else
+		cfg &= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+static const u32 src_pixfmt_map[8][3] = {
+	{ V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR,
+	  FLITE_REG_CIGCTRL_YUV422_1P },
+	{ V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB,
+	  FLITE_REG_CIGCTRL_YUV422_1P },
+	{ V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY,
+	  FLITE_REG_CIGCTRL_YUV422_1P },
+	{ V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY,
+	  FLITE_REG_CIGCTRL_YUV422_1P },
+	{ V4L2_PIX_FMT_SGRBG8, 0, FLITE_REG_CIGCTRL_RAW8 },
+	{ V4L2_PIX_FMT_SGRBG10, 0, FLITE_REG_CIGCTRL_RAW10 },
+	{ V4L2_PIX_FMT_SGRBG12, 0, FLITE_REG_CIGCTRL_RAW12 },
+	{ V4L2_MBUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) },
+};
+
+/* Set camera input pixel format and resolution */
+void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
+{
+	enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code;
+	unsigned int i = ARRAY_SIZE(src_pixfmt_map);
+	u32 cfg;
+
+	while (i-- >= 0) {
+		if (src_pixfmt_map[i][0] == pixelcode)
+			break;
+	}
+
+	if (i == 0 && src_pixfmt_map[i][0] != pixelcode) {
+		v4l2_err(dev->vfd,
+			 "Unsupported pixel code, falling back to %#08x\n",
+			 src_pixfmt_map[i][0]);
+	}
+
+	cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	cfg &= ~FLITE_REG_CIGCTRL_FMT_MASK;
+	cfg |= src_pixfmt_map[i][2];
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+	cfg = readl(dev->regs + FLITE_REG_CISRCSIZE);
+	cfg &= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK |
+		 FLITE_REG_CISRCSIZE_SIZE_CAM_MASK);
+	cfg |= (f->f_width << 16) | f->f_height;
+	cfg |= src_pixfmt_map[i][1];
+	writel(cfg, dev->regs + FLITE_REG_CISRCSIZE);
+}
+
+/* Set the camera host input window offsets (cropping) */
+void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f)
+{
+	u32 hoff2, voff2;
+	u32 cfg;
+
+	cfg = readl(dev->regs + FLITE_REG_CIWDOFST);
+	cfg &= ~FLITE_REG_CIWDOFST_OFST_MASK;
+	cfg |= (f->rect.left << 16) | f->rect.top;
+	cfg |= FLITE_REG_CIWDOFST_WINOFSEN;
+	writel(cfg, dev->regs + FLITE_REG_CIWDOFST);
+
+	hoff2 = f->f_width - f->rect.width - f->rect.left;
+	voff2 = f->f_height - f->rect.height - f->rect.top;
+
+	cfg = (hoff2 << 16) | voff2;
+	writel(cfg, dev->regs + FLITE_REG_CIWDOFST2);
+}
+
+/* Select camera port (A, B) */
+static void flite_hw_set_camera_port(struct fimc_lite *dev, int id)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIGENERAL);
+	if (id == 0)
+		cfg &= ~FLITE_REG_CIGENERAL_CAM_B;
+	else
+		cfg |= FLITE_REG_CIGENERAL_CAM_B;
+	writel(cfg, dev->regs + FLITE_REG_CIGENERAL);
+}
+
+/* Select serial or parallel bus, camera port (A,B) and set signals polarity */
+void flite_hw_set_camera_bus(struct fimc_lite *dev,
+			     struct s5p_fimc_isp_info *s_info)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	unsigned int flags = s_info->flags;
+
+	if (s_info->bus_type != FIMC_MIPI_CSI2) {
+		cfg &= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI |
+			 FLITE_REG_CIGCTRL_INVPOLPCLK |
+			 FLITE_REG_CIGCTRL_INVPOLVSYNC |
+			 FLITE_REG_CIGCTRL_INVPOLHREF);
+
+		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+			cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK;
+
+		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+			cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC;
+
+		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+			cfg |= FLITE_REG_CIGCTRL_INVPOLHREF;
+	} else {
+		cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
+	}
+
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+	flite_hw_set_camera_port(dev, s_info->mux_id);
+}
+
+void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
+{
+	static const u32 pixcode[4][2] = {
+		{ V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
+		{ V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB },
+		{ V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY },
+		{ V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
+	};
+	u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
+	unsigned int i = ARRAY_SIZE(pixcode);
+
+	while (i-- >= 0)
+		if (pixcode[i][0] == dev->fmt->mbus_code)
+			break;
+	cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;
+	writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT);
+}
+
+void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f)
+{
+	u32 cfg;
+
+	/* Maximum output pixel size */
+	cfg = readl(dev->regs + FLITE_REG_CIOCAN);
+	cfg &= ~FLITE_REG_CIOCAN_MASK;
+	cfg = (f->f_height << 16) | f->f_width;
+	writel(cfg, dev->regs + FLITE_REG_CIOCAN);
+
+	/* DMA offsets */
+	cfg = readl(dev->regs + FLITE_REG_CIOOFF);
+	cfg &= ~FLITE_REG_CIOOFF_MASK;
+	cfg |= (f->rect.top << 16) | f->rect.left;
+	writel(cfg, dev->regs + FLITE_REG_CIOOFF);
+}
+
+/* Enable/disable output DMA, set output pixel size and offsets (composition) */
+void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
+			     bool enable)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+
+	if (!enable) {
+		cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
+		writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+		return;
+	}
+
+	cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+	flite_hw_set_out_order(dev, f);
+	flite_hw_set_dma_window(dev, f);
+}
+
+void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
+{
+	struct {
+		u32 offset;
+		const char * const name;
+	} registers[] = {
+		{ 0x00, "CISRCSIZE" },
+		{ 0x04, "CIGCTRL" },
+		{ 0x08, "CIIMGCPT" },
+		{ 0x0c, "CICPTSEQ" },
+		{ 0x10, "CIWDOFST" },
+		{ 0x14, "CIWDOFST2" },
+		{ 0x18, "CIODMAFMT" },
+		{ 0x20, "CIOCAN" },
+		{ 0x24, "CIOOFF" },
+		{ 0x30, "CIOSA" },
+		{ 0x40, "CISTATUS" },
+		{ 0x44, "CISTATUS2" },
+		{ 0xf0, "CITHOLD" },
+		{ 0xfc, "CIGENERAL" },
+	};
+	u32 i;
+
+	pr_info("--- %s ---\n", label);
+	for (i = 0; i < ARRAY_SIZE(registers); i++) {
+		u32 cfg = readl(dev->regs + registers[i].offset);
+		pr_info("%s: %s:\t0x%08x\n", __func__, registers[i].name, cfg);
+	}
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-lite-reg.h b/drivers/media/video/s5p-fimc/fimc-lite-reg.h
new file mode 100644
index 0000000..adb9e9e
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-lite-reg.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2012 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_LITE_REG_H_
+#define FIMC_LITE_REG_H_
+
+#include "fimc-lite.h"
+
+/* Camera Source size */
+#define FLITE_REG_CISRCSIZE			0x00
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR	(0 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB	(1 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY	(2 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY	(3 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_MASK	(0x3 << 14)
+#define FLITE_REG_CISRCSIZE_SIZE_CAM_MASK	(0x3fff << 16 | 0x3fff)
+
+/* Global control */
+#define FLITE_REG_CIGCTRL			0x04
+#define FLITE_REG_CIGCTRL_YUV422_1P		(0x1e << 24)
+#define FLITE_REG_CIGCTRL_RAW8			(0x2a << 24)
+#define FLITE_REG_CIGCTRL_RAW10			(0x2b << 24)
+#define FLITE_REG_CIGCTRL_RAW12			(0x2c << 24)
+#define FLITE_REG_CIGCTRL_RAW14			(0x2d << 24)
+/* User defined formats. x = 0...15 */
+#define FLITE_REG_CIGCTRL_USER(x)		((0x30 + x - 1) << 24)
+#define FLITE_REG_CIGCTRL_FMT_MASK		(0x3f << 24)
+#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE	(1 << 21)
+#define FLITE_REG_CIGCTRL_ODMA_DISABLE		(1 << 20)
+#define FLITE_REG_CIGCTRL_SWRST_REQ		(1 << 19)
+#define FLITE_REG_CIGCTRL_SWRST_RDY		(1 << 18)
+#define FLITE_REG_CIGCTRL_SWRST			(1 << 17)
+#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR	(1 << 15)
+#define FLITE_REG_CIGCTRL_INVPOLPCLK		(1 << 14)
+#define FLITE_REG_CIGCTRL_INVPOLVSYNC		(1 << 13)
+#define FLITE_REG_CIGCTRL_INVPOLHREF		(1 << 12)
+/* Interrupts mask bits (1 disables an interrupt) */
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN		(1 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN		(1 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN		(1 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN		(1 << 5)
+#define FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK	(0xf << 5)
+#define FLITE_REG_CIGCTRL_SELCAM_MIPI		(1 << 3)
+
+/* Image Capture Enable */
+#define FLITE_REG_CIIMGCPT			0x08
+#define FLITE_REG_CIIMGCPT_IMGCPTEN		(1 << 31)
+#define FLITE_REG_CIIMGCPT_CPT_FREN		(1 << 25)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT	(1 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN		(0 << 18)
+
+/* Capture Sequence */
+#define FLITE_REG_CICPTSEQ			0x0c
+
+/* Camera Window Offset */
+#define FLITE_REG_CIWDOFST			0x10
+#define FLITE_REG_CIWDOFST_WINOFSEN		(1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVIY		(1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVFICB		(1 << 15)
+#define FLITE_REG_CIWDOFST_CLROVFICR		(1 << 14)
+#define FLITE_REG_CIWDOFST_OFST_MASK		((0x1fff << 16) | 0x1fff)
+
+/* Camera Window Offset2 */
+#define FLITE_REG_CIWDOFST2			0x14
+
+/* Camera Output DMA Format */
+#define FLITE_REG_CIODMAFMT			0x18
+#define FLITE_REG_CIODMAFMT_RAW_CON		(1 << 15)
+#define FLITE_REG_CIODMAFMT_PACK12		(1 << 14)
+#define FLITE_REG_CIODMAFMT_CRYCBY		(0 << 4)
+#define FLITE_REG_CIODMAFMT_CBYCRY		(1 << 4)
+#define FLITE_REG_CIODMAFMT_YCRYCB		(2 << 4)
+#define FLITE_REG_CIODMAFMT_YCBYCR		(3 << 4)
+#define FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK	(0x3 << 4)
+
+/* Camera Output Canvas */
+#define FLITE_REG_CIOCAN			0x20
+#define FLITE_REG_CIOCAN_MASK			((0x3fff << 16) | 0x3fff)
+
+/* Camera Output DMA Offset */
+#define FLITE_REG_CIOOFF			0x24
+#define FLITE_REG_CIOOFF_MASK			((0x3fff << 16) | 0x3fff)
+
+/* Camera Output DMA Start Address */
+#define FLITE_REG_CIOSA				0x30
+
+/* Camera Status */
+#define FLITE_REG_CISTATUS			0x40
+#define FLITE_REG_CISTATUS_MIPI_VVALID		(1 << 22)
+#define FLITE_REG_CISTATUS_MIPI_HVALID		(1 << 21)
+#define FLITE_REG_CISTATUS_MIPI_DVALID		(1 << 20)
+#define FLITE_REG_CISTATUS_ITU_VSYNC		(1 << 14)
+#define FLITE_REG_CISTATUS_ITU_HREFF		(1 << 13)
+#define FLITE_REG_CISTATUS_OVFIY		(1 << 10)
+#define FLITE_REG_CISTATUS_OVFICB		(1 << 9)
+#define FLITE_REG_CISTATUS_OVFICR		(1 << 8)
+#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW	(1 << 7)
+#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND	(1 << 6)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART	(1 << 5)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND	(1 << 4)
+#define FLITE_REG_CISTATUS_IRQ_CAM		(1 << 0)
+#define FLITE_REG_CISTATUS_IRQ_MASK		(0xf << 4)
+
+/* Camera Status2 */
+#define FLITE_REG_CISTATUS2			0x44
+#define FLITE_REG_CISTATUS2_LASTCAPEND		(1 << 1)
+#define FLITE_REG_CISTATUS2_FRMEND		(1 << 0)
+
+/* Qos Threshold */
+#define FLITE_REG_CITHOLD			0xf0
+#define FLITE_REG_CITHOLD_W_QOS_EN		(1 << 30)
+
+/* Camera General Purpose */
+#define FLITE_REG_CIGENERAL			0xfc
+/* b0: 1 - camera B, 0 - camera A */
+#define FLITE_REG_CIGENERAL_CAM_B		(1 << 0)
+
+/* ----------------------------------------------------------------------------
+ * Function declarations
+ */
+void flite_hw_reset(struct fimc_lite *dev);
+void flite_hw_clear_pending_irq(struct fimc_lite *dev);
+u32 flite_hw_get_interrupt_source(struct fimc_lite *dev);
+void flite_hw_clear_last_capture_end(struct fimc_lite *dev);
+void flite_hw_set_interrupt_mask(struct fimc_lite *dev);
+void flite_hw_capture_start(struct fimc_lite *dev);
+void flite_hw_capture_stop(struct fimc_lite *dev);
+void flite_hw_set_camera_bus(struct fimc_lite *dev,
+			     struct s5p_fimc_isp_info *s_info);
+void flite_hw_set_camera_polarity(struct fimc_lite *dev,
+				  struct s5p_fimc_isp_info *cam);
+void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f);
+void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f);
+
+void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
+			     bool enable);
+void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f);
+void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on);
+void flite_hw_dump_regs(struct fimc_lite *dev, const char *label);
+
+static inline void flite_hw_set_output_addr(struct fimc_lite *dev, u32 paddr)
+{
+	writel(paddr, dev->regs + FLITE_REG_CIOSA);
+}
+#endif /* FIMC_LITE_REG_H */
diff --git a/drivers/media/video/s5p-fimc/fimc-lite.c b/drivers/media/video/s5p-fimc/fimc-lite.c
new file mode 100644
index 0000000..400d701a
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-lite.c
@@ -0,0 +1,1576 @@
+/*
+ * Samsung EXYNOS FIMC-LITE (camera host interface) driver
+*
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@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.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-mdevice.h"
+#include "fimc-core.h"
+#include "fimc-lite-reg.h"
+
+static int debug;
+module_param(debug, int, 0644);
+
+static const struct fimc_fmt fimc_lite_formats[] = {
+	{
+		.name		= "YUV 4:2:2 packed, YCbYCr",
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_YCBYCR422,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
+	}, {
+		.name		= "YUV 4:2:2 packed, CbYCrY",
+		.fourcc		= V4L2_PIX_FMT_UYVY,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_CBYCRY422,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_UYVY8_2X8,
+	}, {
+		.name		= "YUV 4:2:2 packed, CrYCbY",
+		.fourcc		= V4L2_PIX_FMT_VYUY,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_CRYCBY422,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_VYUY8_2X8,
+	}, {
+		.name		= "YUV 4:2:2 packed, YCrYCb",
+		.fourcc		= V4L2_PIX_FMT_YVYU,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_YCRYCB422,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_YVYU8_2X8,
+	}, {
+		.name		= "RAW8 (GRBG)",
+		.fourcc		= V4L2_PIX_FMT_SGRBG8,
+		.depth		= { 8 },
+		.color		= FIMC_FMT_RAW8,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_SGRBG8_1X8,
+	}, {
+		.name		= "RAW10 (GRBG)",
+		.fourcc		= V4L2_PIX_FMT_SGRBG10,
+		.depth		= { 10 },
+		.color		= FIMC_FMT_RAW10,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_SGRBG10_1X10,
+	}, {
+		.name		= "RAW12 (GRBG)",
+		.fourcc		= V4L2_PIX_FMT_SGRBG12,
+		.depth		= { 12 },
+		.color		= FIMC_FMT_RAW12,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_SGRBG12_1X12,
+	},
+};
+
+/**
+ * fimc_lite_find_format - lookup fimc color format by fourcc or media bus code
+ * @pixelformat: fourcc to match, ignored if null
+ * @mbus_code: media bus code to match, ignored if null
+ * @index: index to the fimc_lite_formats array, ignored if negative
+ */
+static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
+					const u32 *mbus_code, int index)
+{
+	const struct fimc_fmt *fmt, *def_fmt = NULL;
+	unsigned int i;
+	int id = 0;
+
+	if (index >= (int)ARRAY_SIZE(fimc_lite_formats))
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) {
+		fmt = &fimc_lite_formats[i];
+		if (pixelformat && fmt->fourcc == *pixelformat)
+			return fmt;
+		if (mbus_code && fmt->mbus_code == *mbus_code)
+			return fmt;
+		if (index == id)
+			def_fmt = fmt;
+		id++;
+	}
+	return def_fmt;
+}
+
+static int fimc_lite_hw_init(struct fimc_lite *fimc)
+{
+	struct fimc_pipeline *pipeline = &fimc->pipeline;
+	struct fimc_sensor_info *sensor;
+	unsigned long flags;
+
+	if (pipeline->subdevs[IDX_SENSOR] == NULL)
+		return -ENXIO;
+
+	if (fimc->fmt == NULL)
+		return -EINVAL;
+
+	sensor = v4l2_get_subdev_hostdata(pipeline->subdevs[IDX_SENSOR]);
+	spin_lock_irqsave(&fimc->slock, flags);
+
+	flite_hw_set_camera_bus(fimc, sensor->pdata);
+	flite_hw_set_source_format(fimc, &fimc->inp_frame);
+	flite_hw_set_window_offset(fimc, &fimc->inp_frame);
+	flite_hw_set_output_dma(fimc, &fimc->out_frame, true);
+	flite_hw_set_interrupt_mask(fimc);
+	flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
+
+	if (debug > 0)
+		flite_hw_dump_regs(fimc, __func__);
+
+	spin_unlock_irqrestore(&fimc->slock, flags);
+	return 0;
+}
+
+/*
+ * Reinitialize the driver so it is ready to start the streaming again.
+ * Set fimc->state to indicate stream off and the hardware shut down state.
+ * If not suspending (@suspend is false), return any buffers to videobuf2.
+ * Otherwise put any owned buffers onto the pending buffers queue, so they
+ * can be re-spun when the device is being resumed. Also perform FIMC
+ * software reset and disable streaming on the whole pipeline if required.
+ */
+static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend)
+{
+	struct flite_buffer *buf;
+	unsigned long flags;
+	bool streaming;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	streaming = fimc->state & (1 << ST_SENSOR_STREAM);
+
+	fimc->state &= ~(1 << ST_FLITE_RUN | 1 << ST_FLITE_OFF |
+			 1 << ST_FLITE_STREAM | 1 << ST_SENSOR_STREAM);
+	if (suspend)
+		fimc->state |= (1 << ST_FLITE_SUSPENDED);
+	else
+		fimc->state &= ~(1 << ST_FLITE_PENDING |
+				 1 << ST_FLITE_SUSPENDED);
+
+	/* Release unused buffers */
+	while (!suspend && !list_empty(&fimc->pending_buf_q)) {
+		buf = fimc_lite_pending_queue_pop(fimc);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+	/* If suspending put unused buffers onto pending queue */
+	while (!list_empty(&fimc->active_buf_q)) {
+		buf = fimc_lite_active_queue_pop(fimc);
+		if (suspend)
+			fimc_lite_pending_queue_add(fimc, buf);
+		else
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	flite_hw_reset(fimc);
+
+	if (!streaming)
+		return 0;
+
+	return fimc_pipeline_s_stream(&fimc->pipeline, 0);
+}
+
+static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend)
+{
+	unsigned long flags;
+
+	if (!fimc_lite_active(fimc))
+		return 0;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	set_bit(ST_FLITE_OFF, &fimc->state);
+	flite_hw_capture_stop(fimc);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	wait_event_timeout(fimc->irq_queue,
+			   !test_bit(ST_FLITE_OFF, &fimc->state),
+			   (2*HZ/10)); /* 200 ms */
+
+	return fimc_lite_reinit(fimc, suspend);
+}
+
+/* Must be called  with fimc.slock spinlock held. */
+static void fimc_lite_config_update(struct fimc_lite *fimc)
+{
+	flite_hw_set_window_offset(fimc, &fimc->inp_frame);
+	flite_hw_set_dma_window(fimc, &fimc->out_frame);
+	flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
+	clear_bit(ST_FLITE_CONFIG, &fimc->state);
+}
+
+static irqreturn_t flite_irq_handler(int irq, void *priv)
+{
+	struct fimc_lite *fimc = priv;
+	struct flite_buffer *vbuf;
+	unsigned long flags;
+	struct timeval *tv;
+	struct timespec ts;
+	u32 intsrc;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+
+	intsrc = flite_hw_get_interrupt_source(fimc);
+	flite_hw_clear_pending_irq(fimc);
+
+	if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) {
+		wake_up(&fimc->irq_queue);
+		goto done;
+	}
+
+	if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) {
+		clear_bit(ST_FLITE_RUN, &fimc->state);
+		fimc->events.data_overflow++;
+	}
+
+	if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) {
+		flite_hw_clear_last_capture_end(fimc);
+		clear_bit(ST_FLITE_STREAM, &fimc->state);
+		wake_up(&fimc->irq_queue);
+	}
+
+	if (fimc->out_path != FIMC_IO_DMA)
+		goto done;
+
+	if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
+	    test_bit(ST_FLITE_RUN, &fimc->state) &&
+	    !list_empty(&fimc->active_buf_q) &&
+	    !list_empty(&fimc->pending_buf_q)) {
+		vbuf = fimc_lite_active_queue_pop(fimc);
+		ktime_get_ts(&ts);
+		tv = &vbuf->vb.v4l2_buf.timestamp;
+		tv->tv_sec = ts.tv_sec;
+		tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+		vbuf->vb.v4l2_buf.sequence = fimc->frame_count++;
+		vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE);
+
+		vbuf = fimc_lite_pending_queue_pop(fimc);
+		flite_hw_set_output_addr(fimc, vbuf->paddr);
+		fimc_lite_active_queue_add(fimc, vbuf);
+	}
+
+	if (test_bit(ST_FLITE_CONFIG, &fimc->state))
+		fimc_lite_config_update(fimc);
+
+	if (list_empty(&fimc->pending_buf_q)) {
+		flite_hw_capture_stop(fimc);
+		clear_bit(ST_FLITE_STREAM, &fimc->state);
+	}
+done:
+	set_bit(ST_FLITE_RUN, &fimc->state);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+	return IRQ_HANDLED;
+}
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct fimc_lite *fimc = q->drv_priv;
+	int ret;
+
+	fimc->frame_count = 0;
+
+	ret = fimc_lite_hw_init(fimc);
+	if (ret) {
+		fimc_lite_reinit(fimc, false);
+		return ret;
+	}
+
+	set_bit(ST_FLITE_PENDING, &fimc->state);
+
+	if (!list_empty(&fimc->active_buf_q) &&
+	    !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) {
+		flite_hw_capture_start(fimc);
+
+		if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
+			fimc_pipeline_s_stream(&fimc->pipeline, 1);
+	}
+	if (debug > 0)
+		flite_hw_dump_regs(fimc, __func__);
+
+	return 0;
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+	struct fimc_lite *fimc = q->drv_priv;
+
+	if (!fimc_lite_active(fimc))
+		return -EINVAL;
+
+	return fimc_lite_stop_capture(fimc, false);
+}
+
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
+		       unsigned int *num_buffers, unsigned int *num_planes,
+		       unsigned int sizes[], void *allocators[])
+{
+	const struct v4l2_pix_format_mplane *pixm = NULL;
+	struct fimc_lite *fimc = vq->drv_priv;
+	struct flite_frame *frame = &fimc->out_frame;
+	const struct fimc_fmt *fmt = fimc->fmt;
+	unsigned long wh;
+	int i;
+
+	if (pfmt) {
+		pixm = &pfmt->fmt.pix_mp;
+		fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, -1);
+		wh = pixm->width * pixm->height;
+	} else {
+		wh = frame->f_width * frame->f_height;
+	}
+
+	if (fmt == NULL)
+		return -EINVAL;
+
+	*num_planes = fmt->memplanes;
+
+	for (i = 0; i < fmt->memplanes; i++) {
+		unsigned int size = (wh * fmt->depth[i]) / 8;
+		if (pixm)
+			sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
+		else
+			sizes[i] = size;
+		allocators[i] = fimc->alloc_ctx;
+	}
+
+	return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct fimc_lite *fimc = vq->drv_priv;
+	int i;
+
+	if (fimc->fmt == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < fimc->fmt->memplanes; i++) {
+		unsigned long size = fimc->payload[i];
+
+		if (vb2_plane_size(vb, i) < size) {
+			v4l2_err(fimc->vfd,
+				 "User buffer too small (%ld < %ld)\n",
+				 vb2_plane_size(vb, i), size);
+			return -EINVAL;
+		}
+		vb2_set_plane_payload(vb, i, size);
+	}
+
+	return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+	struct flite_buffer *buf
+		= container_of(vb, struct flite_buffer, vb);
+	struct fimc_lite *fimc = vb2_get_drv_priv(vb->vb2_queue);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+	if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) &&
+	    !test_bit(ST_FLITE_STREAM, &fimc->state) &&
+	    list_empty(&fimc->active_buf_q)) {
+		flite_hw_set_output_addr(fimc, buf->paddr);
+		fimc_lite_active_queue_add(fimc, buf);
+	} else {
+		fimc_lite_pending_queue_add(fimc, buf);
+	}
+
+	if (vb2_is_streaming(&fimc->vb_queue) &&
+	    !list_empty(&fimc->pending_buf_q) &&
+	    !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) {
+		flite_hw_capture_start(fimc);
+		spin_unlock_irqrestore(&fimc->slock, flags);
+
+		if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
+			fimc_pipeline_s_stream(&fimc->pipeline, 1);
+		return;
+	}
+	spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static void fimc_lock(struct vb2_queue *vq)
+{
+	struct fimc_lite *fimc = vb2_get_drv_priv(vq);
+	mutex_lock(&fimc->lock);
+}
+
+static void fimc_unlock(struct vb2_queue *vq)
+{
+	struct fimc_lite *fimc = vb2_get_drv_priv(vq);
+	mutex_unlock(&fimc->lock);
+}
+
+static const struct vb2_ops fimc_lite_qops = {
+	.queue_setup	 = queue_setup,
+	.buf_prepare	 = buffer_prepare,
+	.buf_queue	 = buffer_queue,
+	.wait_prepare	 = fimc_unlock,
+	.wait_finish	 = fimc_lock,
+	.start_streaming = start_streaming,
+	.stop_streaming	 = stop_streaming,
+};
+
+static void fimc_lite_clear_event_counters(struct fimc_lite *fimc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	memset(&fimc->events, 0, sizeof(fimc->events));
+	spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static int fimc_lite_open(struct file *file)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	int ret = v4l2_fh_open(file);
+
+	if (ret)
+		return ret;
+
+	set_bit(ST_FLITE_IN_USE, &fimc->state);
+	pm_runtime_get_sync(&fimc->pdev->dev);
+
+	if (++fimc->ref_count != 1 || fimc->out_path != FIMC_IO_DMA)
+		return ret;
+
+	ret = fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity,
+				       true);
+	if (ret < 0) {
+		v4l2_err(fimc->vfd, "Video pipeline initialization failed\n");
+		pm_runtime_put_sync(&fimc->pdev->dev);
+		fimc->ref_count--;
+		v4l2_fh_release(file);
+		clear_bit(ST_FLITE_IN_USE, &fimc->state);
+	}
+
+	fimc_lite_clear_event_counters(fimc);
+	return ret;
+}
+
+static int fimc_lite_close(struct file *file)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) {
+		clear_bit(ST_FLITE_IN_USE, &fimc->state);
+		fimc_lite_stop_capture(fimc, false);
+		fimc_pipeline_shutdown(&fimc->pipeline);
+		clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
+	}
+
+	pm_runtime_put(&fimc->pdev->dev);
+
+	if (fimc->ref_count == 0)
+		vb2_queue_release(&fimc->vb_queue);
+
+	return v4l2_fh_release(file);
+}
+
+static unsigned int fimc_lite_poll(struct file *file,
+				   struct poll_table_struct *wait)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	return vb2_poll(&fimc->vb_queue, file, wait);
+}
+
+static int fimc_lite_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	return vb2_mmap(&fimc->vb_queue, vma);
+}
+
+static const struct v4l2_file_operations fimc_lite_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fimc_lite_open,
+	.release	= fimc_lite_close,
+	.poll		= fimc_lite_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= fimc_lite_mmap,
+};
+
+/*
+ * Format and crop negotiation helpers
+ */
+
+static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc,
+					u32 *width, u32 *height,
+					u32 *code, u32 *fourcc, int pad)
+{
+	struct flite_variant *variant = fimc->variant;
+	const struct fimc_fmt *fmt;
+
+	fmt = fimc_lite_find_format(fourcc, code, 0);
+	if (WARN_ON(!fmt))
+		return NULL;
+
+	if (code)
+		*code = fmt->mbus_code;
+	if (fourcc)
+		*fourcc = fmt->fourcc;
+
+	if (pad == FLITE_SD_PAD_SINK) {
+		v4l_bound_align_image(width, 8, variant->max_width,
+				      ffs(variant->out_width_align) - 1,
+				      height, 0, variant->max_height, 0, 0);
+	} else {
+		v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width,
+				      ffs(variant->out_width_align) - 1,
+				      height, 0, fimc->inp_frame.rect.height,
+				      0, 0);
+	}
+
+	v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n",
+		 code ? *code : 0, *width, *height);
+
+	return fmt;
+}
+
+static void fimc_lite_try_crop(struct fimc_lite *fimc, struct v4l2_rect *r)
+{
+	struct flite_frame *frame = &fimc->inp_frame;
+
+	v4l_bound_align_image(&r->width, 0, frame->f_width, 0,
+			      &r->height, 0, frame->f_height, 0, 0);
+
+	/* Adjust left/top if cropping rectangle got out of bounds */
+	r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
+	r->left = round_down(r->left, fimc->variant->win_hor_offs_align);
+	r->top  = clamp_t(u32, r->top, 0, frame->f_height - r->height);
+
+	v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d",
+		 r->left, r->top, r->width, r->height,
+		 frame->f_width, frame->f_height);
+}
+
+static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r)
+{
+	struct flite_frame *frame = &fimc->out_frame;
+	struct v4l2_rect *crop_rect = &fimc->inp_frame.rect;
+
+	/* Scaling is not supported so we enforce compose rectangle size
+	   same as size of the sink crop rectangle. */
+	r->width = crop_rect->width;
+	r->height = crop_rect->height;
+
+	/* Adjust left/top if the composing rectangle got out of bounds */
+	r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
+	r->left = round_down(r->left, fimc->variant->out_hor_offs_align);
+	r->top  = clamp_t(u32, r->top, 0, fimc->out_frame.f_height - r->height);
+
+	v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d",
+		 r->left, r->top, r->width, r->height,
+		 frame->f_width, frame->f_height);
+}
+
+/*
+ * Video node ioctl operations
+ */
+static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+					struct v4l2_capability *cap)
+{
+	strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver));
+	cap->bus_info[0] = 0;
+	cap->card[0] = 0;
+	cap->capabilities = V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv,
+				     struct v4l2_fmtdesc *f)
+{
+	const struct fimc_fmt *fmt;
+
+	if (f->index >= ARRAY_SIZE(fimc_lite_formats))
+		return -EINVAL;
+
+	fmt = &fimc_lite_formats[f->index];
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static int fimc_lite_g_fmt_mplane(struct file *file, void *fh,
+				  struct v4l2_format *f)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+	struct v4l2_plane_pix_format *plane_fmt = &pixm->plane_fmt[0];
+	struct flite_frame *frame = &fimc->out_frame;
+	const struct fimc_fmt *fmt = fimc->fmt;
+
+	plane_fmt->bytesperline = (frame->f_width * fmt->depth[0]) / 8;
+	plane_fmt->sizeimage = plane_fmt->bytesperline * frame->f_height;
+
+	pixm->num_planes = fmt->memplanes;
+	pixm->pixelformat = fmt->fourcc;
+	pixm->width = frame->f_width;
+	pixm->height = frame->f_height;
+	pixm->field = V4L2_FIELD_NONE;
+	pixm->colorspace = V4L2_COLORSPACE_JPEG;
+	return 0;
+}
+
+static int fimc_lite_try_fmt(struct fimc_lite *fimc,
+			     struct v4l2_pix_format_mplane *pixm,
+			     const struct fimc_fmt **ffmt)
+{
+	struct flite_variant *variant = fimc->variant;
+	u32 bpl = pixm->plane_fmt[0].bytesperline;
+	const struct fimc_fmt *fmt;
+
+	fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0);
+	if (WARN_ON(fmt == NULL))
+		return -EINVAL;
+	if (ffmt)
+		*ffmt = fmt;
+	v4l_bound_align_image(&pixm->width, 8, variant->max_width,
+			      ffs(variant->out_width_align) - 1,
+			      &pixm->height, 0, variant->max_height, 0, 0);
+
+	if ((bpl == 0 || ((bpl * 8) / fmt->depth[0]) < pixm->width))
+		pixm->plane_fmt[0].bytesperline = (pixm->width *
+						   fmt->depth[0]) / 8;
+
+	if (pixm->plane_fmt[0].sizeimage == 0)
+		pixm->plane_fmt[0].sizeimage = (pixm->width * pixm->height *
+						fmt->depth[0]) / 8;
+	pixm->num_planes = fmt->memplanes;
+	pixm->pixelformat = fmt->fourcc;
+	pixm->colorspace = V4L2_COLORSPACE_JPEG;
+	pixm->field = V4L2_FIELD_NONE;
+	return 0;
+}
+
+static int fimc_lite_try_fmt_mplane(struct file *file, void *fh,
+				    struct v4l2_format *f)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, NULL);
+}
+
+static int fimc_lite_s_fmt_mplane(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct flite_frame *frame = &fimc->out_frame;
+	const struct fimc_fmt *fmt = NULL;
+	int ret;
+
+	if (vb2_is_busy(&fimc->vb_queue))
+		return -EBUSY;
+
+	ret = fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, &fmt);
+	if (ret < 0)
+		return ret;
+
+	fimc->fmt = fmt;
+	fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8,
+			       pixm->plane_fmt[0].sizeimage);
+	frame->f_width = pixm->width;
+	frame->f_height = pixm->height;
+
+	return 0;
+}
+
+static int fimc_pipeline_validate(struct fimc_lite *fimc)
+{
+	struct v4l2_subdev *sd = &fimc->subdev;
+	struct v4l2_subdev_format sink_fmt, src_fmt;
+	struct media_pad *pad;
+	int ret;
+
+	while (1) {
+		/* Retrieve format at the sink pad */
+		pad = &sd->entity.pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+		/* Don't call FIMC subdev operation to avoid nested locking */
+		if (sd == &fimc->subdev) {
+			struct flite_frame *ff = &fimc->out_frame;
+			sink_fmt.format.width = ff->f_width;
+			sink_fmt.format.height = ff->f_height;
+			sink_fmt.format.code = fimc->fmt->mbus_code;
+		} else {
+			sink_fmt.pad = pad->index;
+			sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+			ret = v4l2_subdev_call(sd, pad, get_fmt, NULL,
+					       &sink_fmt);
+			if (ret < 0 && ret != -ENOIOCTLCMD)
+				return -EPIPE;
+		}
+		/* Retrieve format at the source pad */
+		pad = media_entity_remote_source(pad);
+		if (pad == NULL ||
+		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+			break;
+
+		sd = media_entity_to_v4l2_subdev(pad->entity);
+		src_fmt.pad = pad->index;
+		src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			return -EPIPE;
+
+		if (src_fmt.format.width != sink_fmt.format.width ||
+		    src_fmt.format.height != sink_fmt.format.height ||
+		    src_fmt.format.code != sink_fmt.format.code)
+			return -EPIPE;
+	}
+	return 0;
+}
+
+static int fimc_lite_streamon(struct file *file, void *priv,
+			      enum v4l2_buf_type type)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR];
+	struct fimc_pipeline *p = &fimc->pipeline;
+	int ret;
+
+	if (fimc_lite_active(fimc))
+		return -EBUSY;
+
+	media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
+
+	ret = fimc_pipeline_validate(fimc);
+	if (ret) {
+		media_entity_pipeline_stop(&sensor->entity);
+		return ret;
+	}
+
+	return vb2_streamon(&fimc->vb_queue, type);
+}
+
+static int fimc_lite_streamoff(struct file *file, void *priv,
+			       enum v4l2_buf_type type)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+	int ret;
+
+	ret = vb2_streamoff(&fimc->vb_queue, type);
+	if (ret == 0)
+		media_entity_pipeline_stop(&sd->entity);
+	return ret;
+}
+
+static int fimc_lite_reqbufs(struct file *file, void *priv,
+			     struct v4l2_requestbuffers *reqbufs)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	int ret;
+
+	reqbufs->count = max_t(u32, FLITE_REQ_BUFS_MIN, reqbufs->count);
+	ret = vb2_reqbufs(&fimc->vb_queue, reqbufs);
+	if (!ret < 0)
+		fimc->reqbufs_count = reqbufs->count;
+
+	return ret;
+}
+
+static int fimc_lite_querybuf(struct file *file, void *priv,
+			      struct v4l2_buffer *buf)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_querybuf(&fimc->vb_queue, buf);
+}
+
+static int fimc_lite_qbuf(struct file *file, void *priv,
+			  struct v4l2_buffer *buf)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_qbuf(&fimc->vb_queue, buf);
+}
+
+static int fimc_lite_dqbuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_dqbuf(&fimc->vb_queue, buf, file->f_flags & O_NONBLOCK);
+}
+
+static int fimc_lite_create_bufs(struct file *file, void *priv,
+				 struct v4l2_create_buffers *create)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_create_bufs(&fimc->vb_queue, create);
+}
+
+static int fimc_lite_prepare_buf(struct file *file, void *priv,
+				 struct v4l2_buffer *b)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_prepare_buf(&fimc->vb_queue, b);
+}
+
+/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
+static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+	if (a->left < b->left || a->top < b->top)
+		return 0;
+	if (a->left + a->width > b->left + b->width)
+		return 0;
+	if (a->top + a->height > b->top + b->height)
+		return 0;
+
+	return 1;
+}
+
+static int fimc_lite_g_selection(struct file *file, void *fh,
+				 struct v4l2_selection *sel)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct flite_frame *f = &fimc->out_frame;
+
+	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = f->f_width;
+		sel->r.height = f->f_height;
+		return 0;
+
+	case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+		sel->r = f->rect;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int fimc_lite_s_selection(struct file *file, void *fh,
+				 struct v4l2_selection *sel)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct flite_frame *f = &fimc->out_frame;
+	struct v4l2_rect rect = sel->r;
+	unsigned long flags;
+
+	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
+	    sel->target != V4L2_SEL_TGT_COMPOSE_ACTIVE)
+		return -EINVAL;
+
+	fimc_lite_try_compose(fimc, &rect);
+
+	if ((sel->flags & V4L2_SEL_FLAG_LE) &&
+	    !enclosed_rectangle(&rect, &sel->r))
+		return -ERANGE;
+
+	if ((sel->flags & V4L2_SEL_FLAG_GE) &&
+	    !enclosed_rectangle(&sel->r, &rect))
+		return -ERANGE;
+
+	sel->r = rect;
+	spin_lock_irqsave(&fimc->slock, flags);
+	f->rect = rect;
+	set_bit(ST_FLITE_CONFIG, &fimc->state);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = {
+	.vidioc_querycap		= fimc_vidioc_querycap_capture,
+	.vidioc_enum_fmt_vid_cap_mplane	= fimc_lite_enum_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= fimc_lite_try_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= fimc_lite_s_fmt_mplane,
+	.vidioc_g_fmt_vid_cap_mplane	= fimc_lite_g_fmt_mplane,
+	.vidioc_g_selection		= fimc_lite_g_selection,
+	.vidioc_s_selection		= fimc_lite_s_selection,
+	.vidioc_reqbufs			= fimc_lite_reqbufs,
+	.vidioc_querybuf		= fimc_lite_querybuf,
+	.vidioc_prepare_buf		= fimc_lite_prepare_buf,
+	.vidioc_create_bufs		= fimc_lite_create_bufs,
+	.vidioc_qbuf			= fimc_lite_qbuf,
+	.vidioc_dqbuf			= fimc_lite_dqbuf,
+	.vidioc_streamon		= fimc_lite_streamon,
+	.vidioc_streamoff		= fimc_lite_streamoff,
+};
+
+/* Capture subdev media entity operations */
+static int fimc_lite_link_setup(struct media_entity *entity,
+				const struct media_pad *local,
+				const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	unsigned int remote_ent_type = media_entity_type(remote->entity);
+
+	if (WARN_ON(fimc == NULL))
+		return 0;
+
+	v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x",
+		 __func__, local->entity->name, remote->entity->name,
+		 flags, fimc->source_subdev_grp_id);
+
+	switch (local->index) {
+	case FIMC_SD_PAD_SINK:
+		if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV)
+			return -EINVAL;
+
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (fimc->source_subdev_grp_id != 0)
+				return -EBUSY;
+			fimc->source_subdev_grp_id = sd->grp_id;
+			return 0;
+		}
+
+		fimc->source_subdev_grp_id = 0;
+		break;
+
+	case FIMC_SD_PAD_SOURCE:
+		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+			fimc->out_path = FIMC_IO_NONE;
+			return 0;
+		}
+		if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV)
+			fimc->out_path = FIMC_IO_ISP;
+		else
+			fimc->out_path = FIMC_IO_DMA;
+		break;
+
+	default:
+		v4l2_err(sd, "Invalid pad index\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct media_entity_operations fimc_lite_subdev_media_ops = {
+	.link_setup = fimc_lite_link_setup,
+};
+
+static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_fh *fh,
+					   struct v4l2_subdev_mbus_code_enum *code)
+{
+	const struct fimc_fmt *fmt;
+
+	fmt = fimc_lite_find_format(NULL, NULL, code->index);
+	if (!fmt)
+		return -EINVAL;
+	code->code = fmt->mbus_code;
+	return 0;
+}
+
+static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_fh *fh,
+				    struct v4l2_subdev_format *fmt)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *mf = &fmt->format;
+	struct flite_frame *f = &fimc->out_frame;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		fmt->format = *mf;
+		return 0;
+	}
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+	mutex_lock(&fimc->lock);
+	mf->code = fimc->fmt->mbus_code;
+
+	if (fmt->pad == FLITE_SD_PAD_SINK) {
+		/* full camera input frame size */
+		mf->width = f->f_width;
+		mf->height = f->f_height;
+	} else {
+		/* crop size */
+		mf->width = f->rect.width;
+		mf->height = f->rect.height;
+	}
+	mutex_unlock(&fimc->lock);
+	return 0;
+}
+
+static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_fh *fh,
+				    struct v4l2_subdev_format *fmt)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *mf = &fmt->format;
+	struct flite_frame *sink = &fimc->inp_frame;
+	const struct fimc_fmt *ffmt;
+
+	v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d",
+		 fmt->pad, mf->code, mf->width, mf->height);
+
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+	mutex_lock(&fimc->lock);
+
+	if ((fimc->out_path == FIMC_IO_ISP && sd->entity.stream_count > 0) ||
+	    (fimc->out_path == FIMC_IO_DMA && vb2_is_busy(&fimc->vb_queue))) {
+		mutex_unlock(&fimc->lock);
+		return -EBUSY;
+	}
+
+	ffmt = fimc_lite_try_format(fimc, &mf->width, &mf->height,
+				    &mf->code, NULL, fmt->pad);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		*mf = fmt->format;
+		mutex_unlock(&fimc->lock);
+		return 0;
+	}
+
+	if (fmt->pad == FLITE_SD_PAD_SINK) {
+		sink->f_width = mf->width;
+		sink->f_height = mf->height;
+		fimc->fmt = ffmt;
+		/* Set sink crop rectangle */
+		sink->rect.width = mf->width;
+		sink->rect.height = mf->height;
+		sink->rect.left = 0;
+		sink->rect.top = 0;
+		/* Reset source crop rectangle */
+		fimc->out_frame.rect = sink->rect;
+	} else {
+		/* Allow changing format only on sink pad */
+		mf->code = fimc->fmt->mbus_code;
+		mf->width = sink->rect.width;
+		mf->height = sink->rect.height;
+	}
+
+	mutex_unlock(&fimc->lock);
+	return 0;
+}
+
+static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_fh *fh,
+					  struct v4l2_subdev_selection *sel)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct flite_frame *f = &fimc->inp_frame;
+
+	if ((sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL &&
+	     sel->target != V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS) ||
+	    sel->pad != FLITE_SD_PAD_SINK)
+		return -EINVAL;
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+		sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad);
+		return 0;
+	}
+
+	mutex_lock(&fimc->lock);
+	if (sel->target == V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL) {
+		sel->r = f->rect;
+	} else {
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = f->f_width;
+		sel->r.height = f->f_height;
+	}
+	mutex_unlock(&fimc->lock);
+
+	v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d",
+		 __func__, f->rect.left, f->rect.top, f->rect.width,
+		 f->rect.height, f->f_width, f->f_height);
+
+	return 0;
+}
+
+static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_fh *fh,
+					  struct v4l2_subdev_selection *sel)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct flite_frame *f = &fimc->inp_frame;
+	int ret = 0;
+
+	if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+	    sel->pad != FLITE_SD_PAD_SINK)
+		return -EINVAL;
+
+	mutex_lock(&fimc->lock);
+	fimc_lite_try_crop(fimc, &sel->r);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+		*v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r;
+	} else {
+		unsigned long flags;
+		spin_lock_irqsave(&fimc->slock, flags);
+		f->rect = sel->r;
+		/* Same crop rectangle on the source pad */
+		fimc->out_frame.rect = sel->r;
+		set_bit(ST_FLITE_CONFIG, &fimc->state);
+		spin_unlock_irqrestore(&fimc->slock, flags);
+	}
+	mutex_unlock(&fimc->lock);
+
+	v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d",
+		 __func__, f->rect.left, f->rect.top, f->rect.width,
+		 f->rect.height, f->f_width, f->f_height);
+
+	return ret;
+}
+
+static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+	if (fimc->out_path == FIMC_IO_DMA)
+		return -ENOIOCTLCMD;
+
+	/* TODO: */
+
+	return 0;
+}
+
+static int fimc_lite_subdev_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+	if (fimc->out_path == FIMC_IO_DMA)
+		return -ENOIOCTLCMD;
+
+	/* TODO: */
+
+	return 0;
+}
+
+static int fimc_lite_log_status(struct v4l2_subdev *sd)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+	flite_hw_dump_regs(fimc, __func__);
+	return 0;
+}
+
+static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct vb2_queue *q = &fimc->vb_queue;
+	struct video_device *vfd;
+	int ret;
+
+	fimc->fmt = &fimc_lite_formats[0];
+	fimc->out_path = FIMC_IO_DMA;
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(sd->v4l2_dev, "Failed to allocate video device\n");
+		return -ENOMEM;
+	}
+
+	snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture",
+		 fimc->index);
+
+	vfd->fops = &fimc_lite_fops;
+	vfd->ioctl_ops = &fimc_lite_ioctl_ops;
+	vfd->v4l2_dev = sd->v4l2_dev;
+	vfd->minor = -1;
+	vfd->release = video_device_release;
+	vfd->lock = &fimc->lock;
+	fimc->vfd = vfd;
+	fimc->ref_count = 0;
+	fimc->reqbufs_count = 0;
+
+	INIT_LIST_HEAD(&fimc->pending_buf_q);
+	INIT_LIST_HEAD(&fimc->active_buf_q);
+
+	memset(q, 0, sizeof(*q));
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->ops = &fimc_lite_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct flite_buffer);
+	q->drv_priv = fimc;
+
+	vb2_queue_init(q);
+
+	fimc->vd_pad.flags = MEDIA_PAD_FL_SINK;
+	ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0);
+	if (ret)
+		goto err;
+
+	video_set_drvdata(vfd, fimc);
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto err_vd;
+
+	v4l2_info(sd->v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+	return 0;
+
+ err_vd:
+	media_entity_cleanup(&vfd->entity);
+ err:
+	video_device_release(vfd);
+	return ret;
+}
+
+static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+	if (fimc == NULL)
+		return;
+
+	if (fimc->vfd) {
+		video_unregister_device(fimc->vfd);
+		media_entity_cleanup(&fimc->vfd->entity);
+		fimc->vfd = NULL;
+	}
+}
+
+static const struct v4l2_subdev_internal_ops fimc_lite_subdev_internal_ops = {
+	.registered = fimc_lite_subdev_registered,
+	.unregistered = fimc_lite_subdev_unregistered,
+};
+
+static const struct v4l2_subdev_pad_ops fimc_lite_subdev_pad_ops = {
+	.enum_mbus_code = fimc_lite_subdev_enum_mbus_code,
+	.get_selection = fimc_lite_subdev_get_selection,
+	.set_selection = fimc_lite_subdev_set_selection,
+	.get_fmt = fimc_lite_subdev_get_fmt,
+	.set_fmt = fimc_lite_subdev_set_fmt,
+};
+
+static const struct v4l2_subdev_video_ops fimc_lite_subdev_video_ops = {
+	.s_stream = fimc_lite_subdev_s_stream,
+};
+
+static const struct v4l2_subdev_core_ops fimc_lite_core_ops = {
+	.s_power = fimc_lite_subdev_s_power,
+	.log_status = fimc_lite_log_status,
+};
+
+static struct v4l2_subdev_ops fimc_lite_subdev_ops = {
+	.core = &fimc_lite_core_ops,
+	.video = &fimc_lite_subdev_video_ops,
+	.pad = &fimc_lite_subdev_pad_ops,
+};
+
+static int fimc_lite_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct fimc_lite *fimc = container_of(ctrl->handler, struct fimc_lite,
+					      ctrl_handler);
+	set_bit(ST_FLITE_CONFIG, &fimc->state);
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops fimc_lite_ctrl_ops = {
+	.s_ctrl	= fimc_lite_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config fimc_lite_ctrl = {
+	.ops	= &fimc_lite_ctrl_ops,
+	.id	= V4L2_CTRL_CLASS_USER | 0x1001,
+	.type	= V4L2_CTRL_TYPE_BOOLEAN,
+	.name	= "Test Pattern 640x480",
+};
+
+static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
+{
+	struct v4l2_ctrl_handler *handler = &fimc->ctrl_handler;
+	struct v4l2_subdev *sd = &fimc->subdev;
+	int ret;
+
+	v4l2_subdev_init(sd, &fimc_lite_subdev_ops);
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index);
+
+	fimc->subdev_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	fimc->subdev_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
+				fimc->subdev_pads, 0);
+	if (ret)
+		return ret;
+
+	v4l2_ctrl_handler_init(handler, 1);
+	fimc->test_pattern = v4l2_ctrl_new_custom(handler, &fimc_lite_ctrl,
+						  NULL);
+	if (handler->error) {
+		media_entity_cleanup(&sd->entity);
+		return handler->error;
+	}
+
+	sd->ctrl_handler = handler;
+	sd->internal_ops = &fimc_lite_subdev_internal_ops;
+	sd->entity.ops = &fimc_lite_subdev_media_ops;
+	v4l2_set_subdevdata(sd, fimc);
+
+	return 0;
+}
+
+static void fimc_lite_unregister_capture_subdev(struct fimc_lite *fimc)
+{
+	struct v4l2_subdev *sd = &fimc->subdev;
+
+	v4l2_device_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(&fimc->ctrl_handler);
+	v4l2_set_subdevdata(sd, NULL);
+}
+
+static void fimc_lite_clk_put(struct fimc_lite *fimc)
+{
+	if (IS_ERR_OR_NULL(fimc->clock))
+		return;
+
+	clk_unprepare(fimc->clock);
+	clk_put(fimc->clock);
+	fimc->clock = NULL;
+}
+
+static int fimc_lite_clk_get(struct fimc_lite *fimc)
+{
+	int ret;
+
+	fimc->clock = clk_get(&fimc->pdev->dev, FLITE_CLK_NAME);
+	if (IS_ERR(fimc->clock))
+		return PTR_ERR(fimc->clock);
+
+	ret = clk_prepare(fimc->clock);
+	if (ret < 0) {
+		clk_put(fimc->clock);
+		fimc->clock = NULL;
+	}
+	return ret;
+}
+
+static int __devinit fimc_lite_probe(struct platform_device *pdev)
+{
+	struct flite_drvdata *drv_data = fimc_lite_get_drvdata(pdev);
+	struct fimc_lite *fimc;
+	struct resource *res;
+	int ret;
+
+	fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
+	if (!fimc)
+		return -ENOMEM;
+
+	fimc->index = pdev->id;
+	fimc->variant = drv_data->variant[fimc->index];
+	fimc->pdev = pdev;
+
+	init_waitqueue_head(&fimc->irq_queue);
+	spin_lock_init(&fimc->slock);
+	mutex_init(&fimc->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (fimc->regs == NULL) {
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENOENT;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "Failed to get IRQ resource\n");
+		return -ENXIO;
+	}
+
+	ret = fimc_lite_clk_get(fimc);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(&pdev->dev, res->start, flite_irq_handler,
+			       0, dev_name(&pdev->dev), fimc);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
+		goto err_clk;
+	}
+
+	/* The video node will be created within the subdev's registered() op */
+	ret = fimc_lite_create_capture_subdev(fimc);
+	if (ret)
+		goto err_clk;
+
+	platform_set_drvdata(pdev, fimc);
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0)
+		goto err_sd;
+
+	fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(fimc->alloc_ctx)) {
+		ret = PTR_ERR(fimc->alloc_ctx);
+		goto err_pm;
+	}
+	pm_runtime_put(&pdev->dev);
+
+	dev_dbg(&pdev->dev, "FIMC-LITE.%d registered successfully\n",
+		fimc->index);
+	return 0;
+err_pm:
+	pm_runtime_put(&pdev->dev);
+err_sd:
+	fimc_lite_unregister_capture_subdev(fimc);
+err_clk:
+	fimc_lite_clk_put(fimc);
+	return ret;
+}
+
+static int fimc_lite_runtime_resume(struct device *dev)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+
+	clk_enable(fimc->clock);
+	return 0;
+}
+
+static int fimc_lite_runtime_suspend(struct device *dev)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+
+	clk_disable(fimc->clock);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fimc_lite_resume(struct device *dev)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+	struct flite_buffer *buf;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
+	    !test_bit(ST_FLITE_IN_USE, &fimc->state)) {
+		spin_unlock_irqrestore(&fimc->slock, flags);
+		return 0;
+	}
+	flite_hw_reset(fimc);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	if (!test_and_clear_bit(ST_FLITE_SUSPENDED, &fimc->state))
+		return 0;
+
+	INIT_LIST_HEAD(&fimc->active_buf_q);
+	fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity, false);
+	fimc_lite_hw_init(fimc);
+	clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
+
+	for (i = 0; i < fimc->reqbufs_count; i++) {
+		if (list_empty(&fimc->pending_buf_q))
+			break;
+		buf = fimc_lite_pending_queue_pop(fimc);
+		buffer_queue(&buf->vb);
+	}
+	return 0;
+}
+
+static int fimc_lite_suspend(struct device *dev)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+	bool suspend = test_bit(ST_FLITE_IN_USE, &fimc->state);
+	int ret;
+
+	if (test_and_set_bit(ST_LPM, &fimc->state))
+		return 0;
+
+	ret = fimc_lite_stop_capture(fimc, suspend);
+	if (ret)
+		return ret;
+
+	return fimc_pipeline_shutdown(&fimc->pipeline);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int __devexit fimc_lite_remove(struct platform_device *pdev)
+{
+	struct fimc_lite *fimc = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	fimc_lite_unregister_capture_subdev(fimc);
+	vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
+	fimc_lite_clk_put(fimc);
+
+	dev_info(dev, "Driver unloaded\n");
+	return 0;
+}
+
+static struct flite_variant fimc_lite0_variant_exynos4 = {
+	.max_width		= 8192,
+	.max_height		= 8192,
+	.out_width_align	= 8,
+	.win_hor_offs_align	= 2,
+	.out_hor_offs_align	= 8,
+};
+
+/* EXYNOS4212, EXYNOS4412 */
+static struct flite_drvdata fimc_lite_drvdata_exynos4 = {
+	.variant = {
+		[0] = &fimc_lite0_variant_exynos4,
+		[1] = &fimc_lite0_variant_exynos4,
+	},
+};
+
+static struct platform_device_id fimc_lite_driver_ids[] = {
+	{
+		.name		= "exynos-fimc-lite",
+		.driver_data	= (unsigned long)&fimc_lite_drvdata_exynos4,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids);
+
+static const struct dev_pm_ops fimc_lite_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume)
+	SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume,
+			   NULL)
+};
+
+static struct platform_driver fimc_lite_driver = {
+	.probe		= fimc_lite_probe,
+	.remove		= __devexit_p(fimc_lite_remove),
+	.id_table	= fimc_lite_driver_ids,
+	.driver = {
+		.name		= FIMC_LITE_DRV_NAME,
+		.owner		= THIS_MODULE,
+		.pm		= &fimc_lite_pm_ops,
+	}
+};
+module_platform_driver(fimc_lite_driver);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" FIMC_LITE_DRV_NAME);
diff --git a/drivers/media/video/s5p-fimc/fimc-lite.h b/drivers/media/video/s5p-fimc/fimc-lite.h
new file mode 100644
index 0000000..44424ee
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-lite.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2012 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_LITE_H_
+#define FIMC_LITE_H_
+
+#include <asm/sizes.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5p_fimc.h>
+
+#include "fimc-core.h"
+
+#define FIMC_LITE_DRV_NAME	"exynos-fimc-lite"
+#define FLITE_CLK_NAME		"flite"
+#define FIMC_LITE_MAX_DEVS	2
+#define FLITE_REQ_BUFS_MIN	2
+
+/* Bit index definitions for struct fimc_lite::state */
+enum {
+	ST_FLITE_LPM,
+	ST_FLITE_PENDING,
+	ST_FLITE_RUN,
+	ST_FLITE_STREAM,
+	ST_FLITE_SUSPENDED,
+	ST_FLITE_OFF,
+	ST_FLITE_IN_USE,
+	ST_FLITE_CONFIG,
+	ST_SENSOR_STREAM,
+};
+
+#define FLITE_SD_PAD_SINK	0
+#define FLITE_SD_PAD_SOURCE	1
+#define FLITE_SD_PADS_NUM	2
+
+struct flite_variant {
+	unsigned short max_width;
+	unsigned short max_height;
+	unsigned short out_width_align;
+	unsigned short win_hor_offs_align;
+	unsigned short out_hor_offs_align;
+};
+
+struct flite_drvdata {
+	struct flite_variant *variant[FIMC_LITE_MAX_DEVS];
+};
+
+#define fimc_lite_get_drvdata(_pdev) \
+	((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data)
+
+struct fimc_lite_events {
+	unsigned int data_overflow;
+};
+
+#define FLITE_MAX_PLANES	1
+
+/**
+ * struct flite_frame - source/target frame properties
+ * @f_width: full pixel width
+ * @f_height: full pixel height
+ * @rect: crop/composition rectangle
+ */
+struct flite_frame {
+	u16 f_width;
+	u16 f_height;
+	struct v4l2_rect rect;
+};
+
+/**
+ * struct flite_buffer - video buffer structure
+ * @vb:    vb2 buffer
+ * @list:  list head for the buffers queue
+ * @paddr: precalculated physical address
+ */
+struct flite_buffer {
+	struct vb2_buffer vb;
+	struct list_head list;
+	dma_addr_t paddr;
+};
+
+/**
+ * struct fimc_lite - fimc lite structure
+ * @pdev: pointer to FIMC-LITE platform device
+ * @variant: variant information for this IP
+ * @v4l2_dev: pointer to top the level v4l2_device
+ * @vfd: video device node
+ * @fh: v4l2 file handle
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @subdev: FIMC-LITE subdev
+ * @vd_pad: media (sink) pad for the capture video node
+ * @subdev_pads: the subdev media pads
+ * @ctrl_handler: v4l2 control handler
+ * @test_pattern: test pattern controls
+ * @index: FIMC-LITE platform device index
+ * @pipeline: video capture pipeline data structure
+ * @slock: spinlock protecting this data structure and the hw registers
+ * @lock: mutex serializing video device and the subdev operations
+ * @clock: FIMC-LITE gate clock
+ * @regs: memory mapped io registers
+ * @irq_queue: interrupt handler waitqueue
+ * @fmt: pointer to color format description structure
+ * @payload: image size in bytes (w x h x bpp)
+ * @inp_frame: camera input frame structure
+ * @out_frame: DMA output frame structure
+ * @out_path: output data path (DMA or FIFO)
+ * @source_subdev_grp_id: source subdev group id
+ * @state: driver state flags
+ * @pending_buf_q: pending buffers queue head
+ * @active_buf_q: the queue head of buffers scheduled in hardware
+ * @vb_queue: vb2 buffers queue
+ * @active_buf_count: number of video buffers scheduled in hardware
+ * @frame_count: the captured frames counter
+ * @reqbufs_count: the number of buffers requested with REQBUFS ioctl
+ * @ref_count: driver's private reference counter
+ */
+struct fimc_lite {
+	struct platform_device	*pdev;
+	struct flite_variant	*variant;
+	struct v4l2_device	*v4l2_dev;
+	struct video_device	*vfd;
+	struct v4l2_fh		fh;
+	struct vb2_alloc_ctx	*alloc_ctx;
+	struct v4l2_subdev	subdev;
+	struct media_pad	vd_pad;
+	struct media_pad	subdev_pads[FLITE_SD_PADS_NUM];
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_ctrl	*test_pattern;
+	u32			index;
+	struct fimc_pipeline	pipeline;
+
+	struct mutex		lock;
+	spinlock_t		slock;
+
+	struct clk		*clock;
+	void __iomem		*regs;
+	wait_queue_head_t	irq_queue;
+
+	const struct fimc_fmt	*fmt;
+	unsigned long		payload[FLITE_MAX_PLANES];
+	struct flite_frame	inp_frame;
+	struct flite_frame	out_frame;
+	enum fimc_datapath	out_path;
+	unsigned int		source_subdev_grp_id;
+
+	unsigned long		state;
+	struct list_head	pending_buf_q;
+	struct list_head	active_buf_q;
+	struct vb2_queue	vb_queue;
+	unsigned int		frame_count;
+	unsigned int		reqbufs_count;
+	int			ref_count;
+
+	struct fimc_lite_events	events;
+};
+
+static inline bool fimc_lite_active(struct fimc_lite *fimc)
+{
+	unsigned long flags;
+	bool ret;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	ret = fimc->state & (1 << ST_FLITE_RUN) ||
+		fimc->state & (1 << ST_FLITE_PENDING);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+	return ret;
+}
+
+static inline void fimc_lite_active_queue_add(struct fimc_lite *dev,
+					 struct flite_buffer *buf)
+{
+	list_add_tail(&buf->list, &dev->active_buf_q);
+}
+
+static inline struct flite_buffer *fimc_lite_active_queue_pop(
+					struct fimc_lite *dev)
+{
+	struct flite_buffer *buf = list_entry(dev->active_buf_q.next,
+					      struct flite_buffer, list);
+	list_del(&buf->list);
+	return buf;
+}
+
+static inline void fimc_lite_pending_queue_add(struct fimc_lite *dev,
+					struct flite_buffer *buf)
+{
+	list_add_tail(&buf->list, &dev->pending_buf_q);
+}
+
+static inline struct flite_buffer *fimc_lite_pending_queue_pop(
+					struct fimc_lite *dev)
+{
+	struct flite_buffer *buf = list_entry(dev->pending_buf_q.next,
+					      struct flite_buffer, list);
+	list_del(&buf->list);
+	return buf;
+}
+
+#endif /* FIMC_LITE_H_ */
diff --git a/drivers/media/video/s5p-fimc/fimc-m2m.c b/drivers/media/video/s5p-fimc/fimc-m2m.c
new file mode 100644
index 0000000..4c58e05
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-m2m.c
@@ -0,0 +1,824 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@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/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-core.h"
+#include "fimc-reg.h"
+#include "fimc-mdevice.h"
+
+
+static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
+{
+	if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return FMT_FLAGS_M2M_IN;
+	else
+		return FMT_FLAGS_M2M_OUT;
+}
+
+void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
+{
+	struct vb2_buffer *src_vb, *dst_vb;
+
+	if (!ctx || !ctx->m2m_ctx)
+		return;
+
+	src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+	if (src_vb && dst_vb) {
+		v4l2_m2m_buf_done(src_vb, vb_state);
+		v4l2_m2m_buf_done(dst_vb, vb_state);
+		v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
+				    ctx->m2m_ctx);
+	}
+}
+
+/* Complete the transaction which has been scheduled for execution. */
+static int fimc_m2m_shutdown(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	int ret;
+
+	if (!fimc_m2m_pending(fimc))
+		return 0;
+
+	fimc_ctx_state_set(FIMC_CTX_SHUT, ctx);
+
+	ret = wait_event_timeout(fimc->irq_queue,
+			   !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
+			   FIMC_SHUTDOWN_TIMEOUT);
+
+	return ret == 0 ? -ETIMEDOUT : ret;
+}
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct fimc_ctx *ctx = q->drv_priv;
+	int ret;
+
+	ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
+	return ret > 0 ? 0 : ret;
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+	struct fimc_ctx *ctx = q->drv_priv;
+	int ret;
+
+	ret = fimc_m2m_shutdown(ctx);
+	if (ret == -ETIMEDOUT)
+		fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+
+	pm_runtime_put(&ctx->fimc_dev->pdev->dev);
+	return 0;
+}
+
+static void fimc_device_run(void *priv)
+{
+	struct vb2_buffer *vb = NULL;
+	struct fimc_ctx *ctx = priv;
+	struct fimc_frame *sf, *df;
+	struct fimc_dev *fimc;
+	unsigned long flags;
+	u32 ret;
+
+	if (WARN(!ctx, "Null context\n"))
+		return;
+
+	fimc = ctx->fimc_dev;
+	spin_lock_irqsave(&fimc->slock, flags);
+
+	set_bit(ST_M2M_PEND, &fimc->state);
+	sf = &ctx->s_frame;
+	df = &ctx->d_frame;
+
+	if (ctx->state & FIMC_PARAMS) {
+		/* Prepare the DMA offsets for scaler */
+		fimc_prepare_dma_offset(ctx, sf);
+		fimc_prepare_dma_offset(ctx, df);
+	}
+
+	vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	ret = fimc_prepare_addr(ctx, vb, sf, &sf->paddr);
+	if (ret)
+		goto dma_unlock;
+
+	vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	ret = fimc_prepare_addr(ctx, vb, df, &df->paddr);
+	if (ret)
+		goto dma_unlock;
+
+	/* Reconfigure hardware if the context has changed. */
+	if (fimc->m2m.ctx != ctx) {
+		ctx->state |= FIMC_PARAMS;
+		fimc->m2m.ctx = ctx;
+	}
+
+	if (ctx->state & FIMC_PARAMS) {
+		fimc_set_yuv_order(ctx);
+		fimc_hw_set_input_path(ctx);
+		fimc_hw_set_in_dma(ctx);
+		ret = fimc_set_scaler_info(ctx);
+		if (ret)
+			goto dma_unlock;
+		fimc_hw_set_prescaler(ctx);
+		fimc_hw_set_mainscaler(ctx);
+		fimc_hw_set_target_format(ctx);
+		fimc_hw_set_rotation(ctx);
+		fimc_hw_set_effect(ctx);
+		fimc_hw_set_out_dma(ctx);
+		if (fimc->variant->has_alpha)
+			fimc_hw_set_rgb_alpha(ctx);
+		fimc_hw_set_output_path(ctx);
+	}
+	fimc_hw_set_input_addr(fimc, &sf->paddr);
+	fimc_hw_set_output_addr(fimc, &df->paddr, -1);
+
+	fimc_activate_capture(ctx);
+	ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP |
+		       FIMC_SRC_FMT | FIMC_DST_FMT);
+	fimc_hw_activate_input_dma(fimc, true);
+
+dma_unlock:
+	spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static void fimc_job_abort(void *priv)
+{
+	fimc_m2m_shutdown(priv);
+}
+
+static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+			    unsigned int *num_buffers, unsigned int *num_planes,
+			    unsigned int sizes[], void *allocators[])
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+	struct fimc_frame *f;
+	int i;
+
+	f = ctx_get_frame(ctx, vq->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+	/*
+	 * Return number of non-contigous planes (plane buffers)
+	 * depending on the configured color format.
+	 */
+	if (!f->fmt)
+		return -EINVAL;
+
+	*num_planes = f->fmt->memplanes;
+	for (i = 0; i < f->fmt->memplanes; i++) {
+		sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8;
+		allocators[i] = ctx->fimc_dev->alloc_ctx;
+	}
+	return 0;
+}
+
+static int fimc_buf_prepare(struct vb2_buffer *vb)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct fimc_frame *frame;
+	int i;
+
+	frame = ctx_get_frame(ctx, vb->vb2_queue->type);
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	for (i = 0; i < frame->fmt->memplanes; i++)
+		vb2_set_plane_payload(vb, i, frame->payload[i]);
+
+	return 0;
+}
+
+static void fimc_buf_queue(struct vb2_buffer *vb)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+	if (ctx->m2m_ctx)
+		v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void fimc_lock(struct vb2_queue *vq)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+	mutex_lock(&ctx->fimc_dev->lock);
+}
+
+static void fimc_unlock(struct vb2_queue *vq)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+	mutex_unlock(&ctx->fimc_dev->lock);
+}
+
+static struct vb2_ops fimc_qops = {
+	.queue_setup	 = fimc_queue_setup,
+	.buf_prepare	 = fimc_buf_prepare,
+	.buf_queue	 = fimc_buf_queue,
+	.wait_prepare	 = fimc_unlock,
+	.wait_finish	 = fimc_lock,
+	.stop_streaming	 = stop_streaming,
+	.start_streaming = start_streaming,
+};
+
+/*
+ * V4L2 ioctl handlers
+ */
+static int fimc_m2m_querycap(struct file *file, void *fh,
+			     struct v4l2_capability *cap)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+
+	strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
+	strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
+	cap->bus_info[0] = 0;
+	cap->capabilities = V4L2_CAP_STREAMING |
+		V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+	return 0;
+}
+
+static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
+				    struct v4l2_fmtdesc *f)
+{
+	struct fimc_fmt *fmt;
+
+	fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
+			       f->index);
+	if (!fmt)
+		return -EINVAL;
+
+	strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
+				 struct v4l2_format *f)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
+
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	return fimc_fill_format(frame, f);
+}
+
+static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_variant *variant = fimc->variant;
+	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+	struct fimc_fmt *fmt;
+	u32 max_w, mod_x, mod_y;
+
+	if (!IS_M2M(f->type))
+		return -EINVAL;
+
+	dbg("w: %d, h: %d", pix->width, pix->height);
+
+	fmt = fimc_find_format(&pix->pixelformat, NULL,
+			       get_m2m_fmt_flags(f->type), 0);
+	if (WARN(fmt == NULL, "Pixel format lookup failed"))
+		return -EINVAL;
+
+	if (pix->field == V4L2_FIELD_ANY)
+		pix->field = V4L2_FIELD_NONE;
+	else if (pix->field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		max_w = variant->pix_limit->scaler_dis_w;
+		mod_x = ffs(variant->min_inp_pixsize) - 1;
+	} else {
+		max_w = variant->pix_limit->out_rot_dis_w;
+		mod_x = ffs(variant->min_out_pixsize) - 1;
+	}
+
+	if (tiled_fmt(fmt)) {
+		mod_x = 6; /* 64 x 32 pixels tile */
+		mod_y = 5;
+	} else {
+		if (variant->min_vsize_align == 1)
+			mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
+		else
+			mod_y = ffs(variant->min_vsize_align) - 1;
+	}
+
+	v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
+		&pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
+
+	fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
+	return 0;
+}
+
+static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
+				   struct v4l2_format *f)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return fimc_try_fmt_mplane(ctx, f);
+}
+
+static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
+				 struct v4l2_format *f)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct vb2_queue *vq;
+	struct fimc_frame *frame;
+	struct v4l2_pix_format_mplane *pix;
+	int i, ret = 0;
+
+	ret = fimc_try_fmt_mplane(ctx, f);
+	if (ret)
+		return ret;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(fimc->m2m.vfd, "queue (%d) busy\n", f->type);
+		return -EBUSY;
+	}
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		frame = &ctx->s_frame;
+	else
+		frame = &ctx->d_frame;
+
+	pix = &f->fmt.pix_mp;
+	frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
+				      get_m2m_fmt_flags(f->type), 0);
+	if (!frame->fmt)
+		return -EINVAL;
+
+	/* Update RGB Alpha control state and value range */
+	fimc_alpha_ctrl_update(ctx);
+
+	for (i = 0; i < frame->fmt->colplanes; i++) {
+		frame->payload[i] =
+			(pix->width * pix->height * frame->fmt->depth[i]) / 8;
+	}
+
+	fimc_fill_frame(frame, f);
+
+	ctx->scaler.enabled = 1;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		fimc_ctx_state_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
+	else
+		fimc_ctx_state_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx);
+
+	dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
+
+	return 0;
+}
+
+static int fimc_m2m_reqbufs(struct file *file, void *fh,
+			    struct v4l2_requestbuffers *reqbufs)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int fimc_m2m_querybuf(struct file *file, void *fh,
+			     struct v4l2_buffer *buf)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_qbuf(struct file *file, void *fh,
+			 struct v4l2_buffer *buf)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_dqbuf(struct file *file, void *fh,
+			  struct v4l2_buffer *buf)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_streamon(struct file *file, void *fh,
+			     enum v4l2_buf_type type)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	/* The source and target color format need to be set */
+	if (V4L2_TYPE_IS_OUTPUT(type)) {
+		if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx))
+			return -EINVAL;
+	} else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) {
+		return -EINVAL;
+	}
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int fimc_m2m_streamoff(struct file *file, void *fh,
+			    enum v4l2_buf_type type)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int fimc_m2m_cropcap(struct file *file, void *fh,
+			    struct v4l2_cropcap *cr)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_frame *frame;
+
+	frame = ctx_get_frame(ctx, cr->type);
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	cr->bounds.left = 0;
+	cr->bounds.top = 0;
+	cr->bounds.width = frame->o_width;
+	cr->bounds.height = frame->o_height;
+	cr->defrect = cr->bounds;
+
+	return 0;
+}
+
+static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_frame *frame;
+
+	frame = ctx_get_frame(ctx, cr->type);
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	cr->c.left = frame->offs_h;
+	cr->c.top = frame->offs_v;
+	cr->c.width = frame->width;
+	cr->c.height = frame->height;
+
+	return 0;
+}
+
+static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_frame *f;
+	u32 min_size, halign, depth = 0;
+	int i;
+
+	if (cr->c.top < 0 || cr->c.left < 0) {
+		v4l2_err(fimc->m2m.vfd,
+			"doesn't support negative values for top & left\n");
+		return -EINVAL;
+	}
+	if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		f = &ctx->d_frame;
+	else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		f = &ctx->s_frame;
+	else
+		return -EINVAL;
+
+	min_size = (f == &ctx->s_frame) ?
+		fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
+
+	/* Get pixel alignment constraints. */
+	if (fimc->variant->min_vsize_align == 1)
+		halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
+	else
+		halign = ffs(fimc->variant->min_vsize_align) - 1;
+
+	for (i = 0; i < f->fmt->colplanes; i++)
+		depth += f->fmt->depth[i];
+
+	v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
+			      ffs(min_size) - 1,
+			      &cr->c.height, min_size, f->o_height,
+			      halign, 64/(ALIGN(depth, 8)));
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (cr->c.left + cr->c.width > f->o_width)
+		cr->c.left = f->o_width - cr->c.width;
+	if (cr->c.top + cr->c.height > f->o_height)
+		cr->c.top = f->o_height - cr->c.height;
+
+	cr->c.left = round_down(cr->c.left, min_size);
+	cr->c.top  = round_down(cr->c.top, fimc->variant->hor_offs_align);
+
+	dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+	    cr->c.left, cr->c.top, cr->c.width, cr->c.height,
+	    f->f_width, f->f_height);
+
+	return 0;
+}
+
+static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_frame *f;
+	int ret;
+
+	ret = fimc_m2m_try_crop(ctx, cr);
+	if (ret)
+		return ret;
+
+	f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
+		&ctx->s_frame : &ctx->d_frame;
+
+	/* Check to see if scaling ratio is within supported range */
+	if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
+		if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			ret = fimc_check_scaler_ratio(ctx, cr->c.width,
+					cr->c.height, ctx->d_frame.width,
+					ctx->d_frame.height, ctx->rotation);
+		} else {
+			ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
+					ctx->s_frame.height, cr->c.width,
+					cr->c.height, ctx->rotation);
+		}
+		if (ret) {
+			v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
+			return -EINVAL;
+		}
+	}
+
+	f->offs_h = cr->c.left;
+	f->offs_v = cr->c.top;
+	f->width  = cr->c.width;
+	f->height = cr->c.height;
+
+	fimc_ctx_state_set(FIMC_PARAMS, ctx);
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
+	.vidioc_querycap		= fimc_m2m_querycap,
+	.vidioc_enum_fmt_vid_cap_mplane	= fimc_m2m_enum_fmt_mplane,
+	.vidioc_enum_fmt_vid_out_mplane	= fimc_m2m_enum_fmt_mplane,
+	.vidioc_g_fmt_vid_cap_mplane	= fimc_m2m_g_fmt_mplane,
+	.vidioc_g_fmt_vid_out_mplane	= fimc_m2m_g_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= fimc_m2m_try_fmt_mplane,
+	.vidioc_try_fmt_vid_out_mplane	= fimc_m2m_try_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= fimc_m2m_s_fmt_mplane,
+	.vidioc_s_fmt_vid_out_mplane	= fimc_m2m_s_fmt_mplane,
+	.vidioc_reqbufs			= fimc_m2m_reqbufs,
+	.vidioc_querybuf		= fimc_m2m_querybuf,
+	.vidioc_qbuf			= fimc_m2m_qbuf,
+	.vidioc_dqbuf			= fimc_m2m_dqbuf,
+	.vidioc_streamon		= fimc_m2m_streamon,
+	.vidioc_streamoff		= fimc_m2m_streamoff,
+	.vidioc_g_crop			= fimc_m2m_g_crop,
+	.vidioc_s_crop			= fimc_m2m_s_crop,
+	.vidioc_cropcap			= fimc_m2m_cropcap
+
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq)
+{
+	struct fimc_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	src_vq->drv_priv = ctx;
+	src_vq->ops = &fimc_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	dst_vq->drv_priv = ctx;
+	dst_vq->ops = &fimc_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int fimc_m2m_open(struct file *file)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct fimc_ctx *ctx;
+	int ret;
+
+	dbg("pid: %d, state: 0x%lx, refcnt: %d",
+	    task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
+
+	/*
+	 * Return if the corresponding video capture node
+	 * is already opened.
+	 */
+	if (fimc->vid_cap.refcnt > 0)
+		return -EBUSY;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+	v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
+	ctx->fimc_dev = fimc;
+
+	/* Default color format */
+	ctx->s_frame.fmt = fimc_get_format(0);
+	ctx->d_frame.fmt = fimc_get_format(0);
+
+	ret = fimc_ctrls_create(ctx);
+	if (ret)
+		goto error_fh;
+
+	/* Use separate control handler per file handle */
+	ctx->fh.ctrl_handler = &ctx->ctrls.handler;
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	/* Setup the device context for memory-to-memory mode */
+	ctx->state = FIMC_CTX_M2M;
+	ctx->flags = 0;
+	ctx->in_path = FIMC_IO_DMA;
+	ctx->out_path = FIMC_IO_DMA;
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		ret = PTR_ERR(ctx->m2m_ctx);
+		goto error_c;
+	}
+
+	if (fimc->m2m.refcnt++ == 0)
+		set_bit(ST_M2M_RUN, &fimc->state);
+	return 0;
+
+error_c:
+	fimc_ctrls_delete(ctx);
+error_fh:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+	return ret;
+}
+
+static int fimc_m2m_release(struct file *file)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+
+	dbg("pid: %d, state: 0x%lx, refcnt= %d",
+		task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
+
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	fimc_ctrls_delete(ctx);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+
+	if (--fimc->m2m.refcnt <= 0)
+		clear_bit(ST_M2M_RUN, &fimc->state);
+	kfree(ctx);
+	return 0;
+}
+
+static unsigned int fimc_m2m_poll(struct file *file,
+				  struct poll_table_struct *wait)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
+
+	return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+
+static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
+
+	return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations fimc_m2m_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fimc_m2m_open,
+	.release	= fimc_m2m_release,
+	.poll		= fimc_m2m_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= fimc_m2m_mmap,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+	.device_run	= fimc_device_run,
+	.job_abort	= fimc_job_abort,
+};
+
+int fimc_register_m2m_device(struct fimc_dev *fimc,
+			     struct v4l2_device *v4l2_dev)
+{
+	struct video_device *vfd;
+	struct platform_device *pdev;
+	int ret = 0;
+
+	if (!fimc)
+		return -ENODEV;
+
+	pdev = fimc->pdev;
+	fimc->v4l2_dev = v4l2_dev;
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(v4l2_dev, "Failed to allocate video device\n");
+		return -ENOMEM;
+	}
+
+	vfd->fops = &fimc_m2m_fops;
+	vfd->ioctl_ops = &fimc_m2m_ioctl_ops;
+	vfd->v4l2_dev = v4l2_dev;
+	vfd->minor = -1;
+	vfd->release = video_device_release;
+	vfd->lock = &fimc->lock;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
+
+	snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
+	video_set_drvdata(vfd, fimc);
+
+	fimc->m2m.vfd = vfd;
+	fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
+	if (IS_ERR(fimc->m2m.m2m_dev)) {
+		v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
+		ret = PTR_ERR(fimc->m2m.m2m_dev);
+		goto err_init;
+	}
+
+	ret = media_entity_init(&vfd->entity, 0, NULL, 0);
+	if (ret)
+		goto err_me;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto err_vd;
+
+	v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+	return 0;
+
+err_vd:
+	media_entity_cleanup(&vfd->entity);
+err_me:
+	v4l2_m2m_release(fimc->m2m.m2m_dev);
+err_init:
+	video_device_release(fimc->m2m.vfd);
+	return ret;
+}
+
+void fimc_unregister_m2m_device(struct fimc_dev *fimc)
+{
+	if (!fimc)
+		return;
+
+	if (fimc->m2m.m2m_dev)
+		v4l2_m2m_release(fimc->m2m.m2m_dev);
+	if (fimc->m2m.vfd) {
+		media_entity_cleanup(&fimc->m2m.vfd->entity);
+		/* Can also be called if video device wasn't registered */
+		video_unregister_device(fimc->m2m.vfd);
+	}
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index 62ed37e..6753c45 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -25,6 +25,7 @@
 #include <media/media-device.h>
 
 #include "fimc-core.h"
+#include "fimc-lite.h"
 #include "fimc-mdevice.h"
 #include "mipi-csis.h"
 
@@ -37,22 +38,46 @@
  *
  * Caller holds the graph mutex.
  */
-void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me)
+void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me)
 {
-	struct media_entity_graph graph;
+	struct media_pad *pad = &me->pads[0];
 	struct v4l2_subdev *sd;
+	int i;
 
-	media_entity_graph_walk_start(&graph, me);
+	for (i = 0; i < IDX_MAX; i++)
+		p->subdevs[i] = NULL;
 
-	while ((me = media_entity_graph_walk_next(&graph))) {
-		if (media_entity_type(me) != MEDIA_ENT_T_V4L2_SUBDEV)
-			continue;
-		sd = media_entity_to_v4l2_subdev(me);
+	while (1) {
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
 
-		if (sd->grp_id == SENSOR_GROUP_ID)
-			fimc->pipeline.sensor = sd;
-		else if (sd->grp_id == CSIS_GROUP_ID)
-			fimc->pipeline.csis = sd;
+		/* source pad */
+		pad = media_entity_remote_source(pad);
+		if (pad == NULL ||
+		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+			break;
+
+		sd = media_entity_to_v4l2_subdev(pad->entity);
+
+		switch (sd->grp_id) {
+		case SENSOR_GROUP_ID:
+			p->subdevs[IDX_SENSOR] = sd;
+			break;
+		case CSIS_GROUP_ID:
+			p->subdevs[IDX_CSIS] = sd;
+			break;
+		case FLITE_GROUP_ID:
+			p->subdevs[IDX_FLITE] = sd;
+			break;
+		case FIMC_GROUP_ID:
+			/* No need to control FIMC subdev through subdev ops */
+			break;
+		default:
+			pr_warn("%s: Unknown subdev grp_id: %#x\n",
+				__func__, sd->grp_id);
+		}
+		/* sink pad */
+		pad = &sd->entity.pads[0];
 	}
 }
 
@@ -85,30 +110,27 @@
 /**
  * fimc_pipeline_s_power - change power state of all pipeline subdevs
  * @fimc: fimc device terminating the pipeline
- * @state: 1 to enable power or 0 for power down
+ * @state: true to power on, false to power off
  *
- * Need to be called with the graph mutex held.
+ * Needs to be called with the graph mutex held.
  */
-int fimc_pipeline_s_power(struct fimc_dev *fimc, int state)
+int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state)
 {
-	int ret = 0;
+	unsigned int i;
+	int ret;
 
-	if (fimc->pipeline.sensor == NULL)
+	if (p->subdevs[IDX_SENSOR] == NULL)
 		return -ENXIO;
 
-	if (state) {
-		ret = __subdev_set_power(fimc->pipeline.csis, 1);
-		if (ret && ret != -ENXIO)
+	for (i = 0; i < IDX_MAX; i++) {
+		unsigned int idx = state ? (IDX_MAX - 1) - i : i;
+
+		ret = __subdev_set_power(p->subdevs[idx], state);
+		if (ret < 0 && ret != -ENXIO)
 			return ret;
-		return __subdev_set_power(fimc->pipeline.sensor, 1);
 	}
 
-	ret = __subdev_set_power(fimc->pipeline.sensor, 0);
-	if (ret)
-		return ret;
-	ret = __subdev_set_power(fimc->pipeline.csis, 0);
-
-	return ret == -ENXIO ? 0 : ret;
+	return 0;
 }
 
 /**
@@ -119,32 +141,36 @@
  *
  * This function must be called with the graph mutex held.
  */
-static int __fimc_pipeline_initialize(struct fimc_dev *fimc,
+static int __fimc_pipeline_initialize(struct fimc_pipeline *p,
 				      struct media_entity *me, bool prep)
 {
 	int ret;
 
 	if (prep)
-		fimc_pipeline_prepare(fimc, me);
-	if (fimc->pipeline.sensor == NULL)
+		fimc_pipeline_prepare(p, me);
+
+	if (p->subdevs[IDX_SENSOR] == NULL)
 		return -EINVAL;
-	ret = fimc_md_set_camclk(fimc->pipeline.sensor, true);
+
+	ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true);
 	if (ret)
 		return ret;
-	return fimc_pipeline_s_power(fimc, 1);
+
+	return fimc_pipeline_s_power(p, 1);
 }
 
-int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
+int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me,
 			     bool prep)
 {
 	int ret;
 
 	mutex_lock(&me->parent->graph_mutex);
-	ret =  __fimc_pipeline_initialize(fimc, me, prep);
+	ret =  __fimc_pipeline_initialize(p, me, prep);
 	mutex_unlock(&me->parent->graph_mutex);
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(fimc_pipeline_initialize);
 
 /**
  * __fimc_pipeline_shutdown - disable the sensor clock and pipeline power
@@ -154,52 +180,55 @@
  * sensor clock.
  * Called with the graph mutex held.
  */
-int __fimc_pipeline_shutdown(struct fimc_dev *fimc)
+int __fimc_pipeline_shutdown(struct fimc_pipeline *p)
 {
 	int ret = 0;
 
-	if (fimc->pipeline.sensor) {
-		ret = fimc_pipeline_s_power(fimc, 0);
-		fimc_md_set_camclk(fimc->pipeline.sensor, false);
+	if (p->subdevs[IDX_SENSOR]) {
+		ret = fimc_pipeline_s_power(p, 0);
+		fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false);
 	}
 	return ret == -ENXIO ? 0 : ret;
 }
 
-int fimc_pipeline_shutdown(struct fimc_dev *fimc)
+int fimc_pipeline_shutdown(struct fimc_pipeline *p)
 {
-	struct media_entity *me = &fimc->vid_cap.vfd->entity;
+	struct media_entity *me = &p->subdevs[IDX_SENSOR]->entity;
 	int ret;
 
 	mutex_lock(&me->parent->graph_mutex);
-	ret = __fimc_pipeline_shutdown(fimc);
+	ret = __fimc_pipeline_shutdown(p);
 	mutex_unlock(&me->parent->graph_mutex);
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(fimc_pipeline_shutdown);
 
 /**
  * fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs
- * @fimc: fimc device terminating the pipeline
+ * @pipeline: video pipeline structure
  * @on: passed as the s_stream call argument
  */
-int fimc_pipeline_s_stream(struct fimc_dev *fimc, int on)
+int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
 {
-	struct fimc_pipeline *p = &fimc->pipeline;
-	int ret = 0;
+	int i, ret;
 
-	if (p->sensor == NULL)
+	if (p->subdevs[IDX_SENSOR] == NULL)
 		return -ENODEV;
 
-	if ((on && p->csis) || !on)
-		ret = v4l2_subdev_call(on ? p->csis : p->sensor,
-				       video, s_stream, on);
-	if (ret < 0 && ret != -ENOIOCTLCMD)
-		return ret;
-	if ((!on && p->csis) || on)
-		ret = v4l2_subdev_call(on ? p->sensor : p->csis,
-				       video, s_stream, on);
-	return ret == -ENOIOCTLCMD ? 0 : ret;
+	for (i = 0; i < IDX_MAX; i++) {
+		unsigned int idx = on ? (IDX_MAX - 1) - i : i;
+
+		ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on);
+
+		if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+			return ret;
+	}
+
+	return 0;
+
 }
+EXPORT_SYMBOL_GPL(fimc_pipeline_s_stream);
 
 /*
  * Sensor subdevice helper functions
@@ -214,14 +243,20 @@
 		return NULL;
 
 	adapter = i2c_get_adapter(s_info->pdata->i2c_bus_num);
-	if (!adapter)
-		return NULL;
+	if (!adapter) {
+		v4l2_warn(&fmd->v4l2_dev,
+			  "Failed to get I2C adapter %d, deferring probe\n",
+			  s_info->pdata->i2c_bus_num);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
 	sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter,
 				       s_info->pdata->board_info, NULL);
 	if (IS_ERR_OR_NULL(sd)) {
 		i2c_put_adapter(adapter);
-		v4l2_err(&fmd->v4l2_dev, "Failed to acquire subdev\n");
-		return NULL;
+		v4l2_warn(&fmd->v4l2_dev,
+			  "Failed to acquire subdev %s, deferring probe\n",
+			  s_info->pdata->board_info->type);
+		return ERR_PTR(-EPROBE_DEFER);
 	}
 	v4l2_set_subdev_hostdata(sd, s_info);
 	sd->grp_id = SENSOR_GROUP_ID;
@@ -269,13 +304,22 @@
 
 	fmd->num_sensors = num_clients;
 	for (i = 0; i < num_clients; i++) {
+		struct v4l2_subdev *sd;
+
 		fmd->sensor[i].pdata = &pdata->isp_info[i];
 		ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true);
 		if (ret)
 			break;
-		fmd->sensor[i].subdev =
-			fimc_md_register_sensor(fmd, &fmd->sensor[i]);
+		sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]);
 		ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false);
+
+		if (!IS_ERR(sd)) {
+			fmd->sensor[i].subdev = sd;
+		} else {
+			fmd->sensor[i].subdev = NULL;
+			ret = PTR_ERR(sd);
+			break;
+		}
 		if (ret)
 			break;
 	}
@@ -289,21 +333,50 @@
 static int fimc_register_callback(struct device *dev, void *p)
 {
 	struct fimc_dev *fimc = dev_get_drvdata(dev);
+	struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
 	struct fimc_md *fmd = p;
-	int ret;
+	int ret = 0;
 
 	if (!fimc || !fimc->pdev)
 		return 0;
+
 	if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS)
 		return 0;
 
 	fmd->fimc[fimc->pdev->id] = fimc;
-	ret = fimc_register_m2m_device(fimc, &fmd->v4l2_dev);
-	if (ret)
-		return ret;
-	ret = fimc_register_capture_device(fimc, &fmd->v4l2_dev);
-	if (!ret)
-		fimc->vid_cap.user_subdev_api = fmd->user_subdev_api;
+	sd->grp_id = FIMC_GROUP_ID;
+
+	ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+	if (ret) {
+		v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n",
+			 fimc->id, ret);
+	}
+
+	return ret;
+}
+
+static int fimc_lite_register_callback(struct device *dev, void *p)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+	struct v4l2_subdev *sd = &fimc->subdev;
+	struct fimc_md *fmd = p;
+	int ret;
+
+	if (fimc == NULL)
+		return 0;
+
+	if (fimc->index >= FIMC_LITE_MAX_DEVS)
+		return 0;
+
+	fmd->fimc_lite[fimc->index] = fimc;
+	sd->grp_id = FLITE_GROUP_ID;
+
+	ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+	if (ret) {
+		v4l2_err(&fmd->v4l2_dev,
+			 "Failed to register FIMC-LITE.%d (%d)\n",
+			 fimc->index, ret);
+	}
 	return ret;
 }
 
@@ -336,22 +409,56 @@
  */
 static int fimc_md_register_platform_entities(struct fimc_md *fmd)
 {
+	struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
 	struct device_driver *driver;
-	int ret;
+	int ret, i;
 
 	driver = driver_find(FIMC_MODULE_NAME, &platform_bus_type);
-	if (!driver)
-		return -ENODEV;
+	if (!driver) {
+		v4l2_warn(&fmd->v4l2_dev,
+			 "%s driver not found, deffering probe\n",
+			 FIMC_MODULE_NAME);
+		return -EPROBE_DEFER;
+	}
+
 	ret = driver_for_each_device(driver, NULL, fmd,
 				     fimc_register_callback);
 	if (ret)
 		return ret;
 
-	driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
-	if (driver)
+	driver = driver_find(FIMC_LITE_DRV_NAME, &platform_bus_type);
+	if (driver && try_module_get(driver->owner)) {
 		ret = driver_for_each_device(driver, NULL, fmd,
-					     csis_register_callback);
-	return ret;
+					     fimc_lite_register_callback);
+		if (ret)
+			return ret;
+		module_put(driver->owner);
+	}
+	/*
+	 * Check if there is any sensor on the MIPI-CSI2 bus and
+	 * if not skip the s5p-csis module loading.
+	 */
+	if (pdata == NULL)
+		return 0;
+	for (i = 0; i < pdata->num_clients; i++) {
+		if (pdata->isp_info[i].bus_type == FIMC_MIPI_CSI2) {
+			ret = 1;
+			break;
+		}
+	}
+	if (!ret)
+		return 0;
+
+	driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
+	if (!driver || !try_module_get(driver->owner)) {
+		v4l2_warn(&fmd->v4l2_dev,
+			 "%s driver not found, deffering probe\n",
+			 CSIS_DRIVER_NAME);
+		return -EPROBE_DEFER;
+	}
+
+	return driver_for_each_device(driver, NULL, fmd,
+				      csis_register_callback);
 }
 
 static void fimc_md_unregister_entities(struct fimc_md *fmd)
@@ -361,14 +468,20 @@
 	for (i = 0; i < FIMC_MAX_DEVS; i++) {
 		if (fmd->fimc[i] == NULL)
 			continue;
-		fimc_unregister_m2m_device(fmd->fimc[i]);
-		fimc_unregister_capture_device(fmd->fimc[i]);
+		v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev);
 		fmd->fimc[i] = NULL;
 	}
+	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
+		if (fmd->fimc_lite[i] == NULL)
+			continue;
+		v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev);
+		fmd->fimc_lite[i] = NULL;
+	}
 	for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
 		if (fmd->csis[i].sd == NULL)
 			continue;
 		v4l2_device_unregister_subdev(fmd->csis[i].sd);
+		module_put(fmd->csis[i].sd->owner);
 		fmd->csis[i].sd = NULL;
 	}
 	for (i = 0; i < fmd->num_sensors; i++) {
@@ -379,35 +492,6 @@
 	}
 }
 
-static int fimc_md_register_video_nodes(struct fimc_md *fmd)
-{
-	struct video_device *vdev;
-	int i, ret = 0;
-
-	for (i = 0; i < FIMC_MAX_DEVS && !ret; i++) {
-		if (!fmd->fimc[i])
-			continue;
-
-		vdev = fmd->fimc[i]->m2m.vfd;
-		if (vdev) {
-			ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
-			if (ret)
-				break;
-			v4l2_info(&fmd->v4l2_dev, "Registered %s as /dev/%s\n",
-				  vdev->name, video_device_node_name(vdev));
-		}
-
-		vdev = fmd->fimc[i]->vid_cap.vfd;
-		if (vdev == NULL)
-			continue;
-		ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
-		v4l2_info(&fmd->v4l2_dev, "Registered %s as /dev/%s\n",
-			  vdev->name, video_device_node_name(vdev));
-	}
-
-	return ret;
-}
-
 /**
  * __fimc_md_create_fimc_links - create links to all FIMC entities
  * @fmd: fimc media device
@@ -416,29 +500,29 @@
  * @pad: the source entity pad index
  * @fimc_id: index of the fimc device for which link should be enabled
  */
-static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
-				       struct media_entity *source,
-				       struct v4l2_subdev *sensor,
-				       int pad, int fimc_id)
+static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
+					    struct media_entity *source,
+					    struct v4l2_subdev *sensor,
+					    int pad, int fimc_id)
 {
 	struct fimc_sensor_info *s_info;
 	struct media_entity *sink;
-	unsigned int flags;
+	unsigned int flags = 0;
 	int ret, i;
 
 	for (i = 0; i < FIMC_MAX_DEVS; i++) {
 		if (!fmd->fimc[i])
-			break;
+			continue;
 		/*
 		 * Some FIMC variants are not fitted with camera capture
 		 * interface. Skip creating a link from sensor for those.
 		 */
-		if (sensor->grp_id == SENSOR_GROUP_ID &&
-		    !fmd->fimc[i]->variant->has_cam_if)
+		if (!fmd->fimc[i]->variant->has_cam_if)
 			continue;
 
 		flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
-		sink = &fmd->fimc[i]->vid_cap.subdev->entity;
+
+		sink = &fmd->fimc[i]->vid_cap.subdev.entity;
 		ret = media_entity_create_link(source, pad, sink,
 					      FIMC_SD_PAD_SINK, flags);
 		if (ret)
@@ -453,7 +537,7 @@
 		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
 			  source->name, flags ? '=' : '-', sink->name);
 
-		if (flags == 0)
+		if (flags == 0 || sensor == NULL)
 			continue;
 		s_info = v4l2_get_subdev_hostdata(sensor);
 		if (!WARN_ON(s_info == NULL)) {
@@ -463,9 +547,55 @@
 			spin_unlock_irqrestore(&fmd->slock, irq_flags);
 		}
 	}
+
+	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
+		if (!fmd->fimc_lite[i])
+			continue;
+
+		flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
+
+		sink = &fmd->fimc_lite[i]->subdev.entity;
+		ret = media_entity_create_link(source, pad, sink,
+					       FLITE_SD_PAD_SINK, flags);
+		if (ret)
+			return ret;
+
+		/* Notify FIMC-LITE subdev entity */
+		ret = media_entity_call(sink, link_setup, &sink->pads[0],
+					&source->pads[pad], flags);
+		if (ret)
+			break;
+
+		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
+			  source->name, flags ? '=' : '-', sink->name);
+	}
 	return 0;
 }
 
+/* Create links from FIMC-LITE source pads to other entities */
+static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
+{
+	struct media_entity *source, *sink;
+	unsigned int flags = MEDIA_LNK_FL_ENABLED;
+	int i, ret;
+
+	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
+		struct fimc_lite *fimc = fmd->fimc_lite[i];
+		if (fimc == NULL)
+			continue;
+		source = &fimc->subdev.entity;
+		sink = &fimc->vfd->entity;
+		/* FIMC-LITE's subdev and video node */
+		ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
+					       sink, 0, flags);
+		if (ret)
+			break;
+		/* TODO: create links to other entities */
+	}
+
+	return ret;
+}
+
 /**
  * fimc_md_create_links - create default links between registered entities
  *
@@ -522,8 +652,7 @@
 			v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
 				  sensor->entity.name, csis->entity.name);
 
-			source = &csis->entity;
-			pad = CSIS_PAD_SOURCE;
+			source = NULL;
 			break;
 
 		case FIMC_ITU_601...FIMC_ITU_656:
@@ -539,15 +668,27 @@
 		if (source == NULL)
 			continue;
 
-		ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad,
-						  fimc_id++);
+		ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor,
+						       pad, fimc_id++);
 	}
+
+	fimc_id = 0;
+	for (i = 0; i < ARRAY_SIZE(fmd->csis); i++) {
+		if (fmd->csis[i].sd == NULL)
+			continue;
+		source = &fmd->csis[i].sd->entity;
+		pad = CSIS_PAD_SOURCE;
+
+		ret = __fimc_md_create_fimc_sink_links(fmd, source, NULL,
+						       pad, fimc_id++);
+	}
+
 	/* Create immutable links between each FIMC's subdev and video node */
 	flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
 	for (i = 0; i < FIMC_MAX_DEVS; i++) {
 		if (!fmd->fimc[i])
 			continue;
-		source = &fmd->fimc[i]->vid_cap.subdev->entity;
+		source = &fmd->fimc[i]->vid_cap.subdev.entity;
 		sink = &fmd->fimc[i]->vid_cap.vfd->entity;
 		ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
 					      sink, 0, flags);
@@ -555,7 +696,7 @@
 			break;
 	}
 
-	return ret;
+	return __fimc_md_create_flite_source_links(fmd);
 }
 
 /*
@@ -663,24 +804,40 @@
 static int fimc_md_link_notify(struct media_pad *source,
 			       struct media_pad *sink, u32 flags)
 {
+	struct fimc_lite *fimc_lite = NULL;
+	struct fimc_dev *fimc = NULL;
+	struct fimc_pipeline *pipeline;
 	struct v4l2_subdev *sd;
-	struct fimc_dev *fimc;
 	int ret = 0;
 
 	if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
 		return 0;
 
 	sd = media_entity_to_v4l2_subdev(sink->entity);
-	fimc = v4l2_get_subdevdata(sd);
+
+	switch (sd->grp_id) {
+	case FLITE_GROUP_ID:
+		fimc_lite = v4l2_get_subdevdata(sd);
+		pipeline = &fimc_lite->pipeline;
+		break;
+	case FIMC_GROUP_ID:
+		fimc = v4l2_get_subdevdata(sd);
+		pipeline = &fimc->pipeline;
+		break;
+	default:
+		return 0;
+	}
 
 	if (!(flags & MEDIA_LNK_FL_ENABLED)) {
-		ret = __fimc_pipeline_shutdown(fimc);
-		fimc->pipeline.sensor = NULL;
-		fimc->pipeline.csis = NULL;
+		ret = __fimc_pipeline_shutdown(pipeline);
+		pipeline->subdevs[IDX_SENSOR] = NULL;
+		pipeline->subdevs[IDX_CSIS] = NULL;
 
-		mutex_lock(&fimc->lock);
-		fimc_ctrls_delete(fimc->vid_cap.ctx);
-		mutex_unlock(&fimc->lock);
+		if (fimc) {
+			mutex_lock(&fimc->lock);
+			fimc_ctrls_delete(fimc->vid_cap.ctx);
+			mutex_unlock(&fimc->lock);
+		}
 		return ret;
 	}
 	/*
@@ -688,14 +845,23 @@
 	 * pipeline is already in use, i.e. its video node is opened.
 	 * Recreate the controls destroyed during the link deactivation.
 	 */
-	mutex_lock(&fimc->lock);
-	if (fimc->vid_cap.refcnt > 0) {
-		ret = __fimc_pipeline_initialize(fimc, source->entity, true);
+	if (fimc) {
+		mutex_lock(&fimc->lock);
+		if (fimc->vid_cap.refcnt > 0) {
+			ret = __fimc_pipeline_initialize(pipeline,
+							 source->entity, true);
 		if (!ret)
 			ret = fimc_capture_ctrls_create(fimc);
+		}
+		mutex_unlock(&fimc->lock);
+	} else {
+		mutex_lock(&fimc_lite->lock);
+		if (fimc_lite->ref_count > 0) {
+			ret = __fimc_pipeline_initialize(pipeline,
+							 source->entity, true);
+		}
+		mutex_unlock(&fimc_lite->lock);
 	}
-	mutex_unlock(&fimc->lock);
-
 	return ret ? -EPIPE : ret;
 }
 
@@ -744,7 +910,7 @@
 static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
 		   fimc_md_sysfs_show, fimc_md_sysfs_store);
 
-static int __devinit fimc_md_probe(struct platform_device *pdev)
+static int fimc_md_probe(struct platform_device *pdev)
 {
 	struct v4l2_device *v4l2_dev;
 	struct fimc_md *fmd;
@@ -776,42 +942,48 @@
 	ret = media_device_register(&fmd->media_dev);
 	if (ret < 0) {
 		v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
-		goto err2;
+		goto err_md;
 	}
 	ret = fimc_md_get_clocks(fmd);
 	if (ret)
-		goto err3;
+		goto err_clk;
 
 	fmd->user_subdev_api = false;
+
+	/* Protect the media graph while we're registering entities */
+	mutex_lock(&fmd->media_dev.graph_mutex);
+
 	ret = fimc_md_register_platform_entities(fmd);
 	if (ret)
-		goto err3;
+		goto err_unlock;
 
 	if (pdev->dev.platform_data) {
 		ret = fimc_md_register_sensor_entities(fmd);
 		if (ret)
-			goto err3;
+			goto err_unlock;
 	}
 	ret = fimc_md_create_links(fmd);
 	if (ret)
-		goto err3;
+		goto err_unlock;
 	ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev);
 	if (ret)
-		goto err3;
-	ret = fimc_md_register_video_nodes(fmd);
-	if (ret)
-		goto err3;
+		goto err_unlock;
 
 	ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode);
-	if (!ret) {
-		platform_set_drvdata(pdev, fmd);
-		return 0;
-	}
-err3:
+	if (ret)
+		goto err_unlock;
+
+	platform_set_drvdata(pdev, fmd);
+	mutex_unlock(&fmd->media_dev.graph_mutex);
+	return 0;
+
+err_unlock:
+	mutex_unlock(&fmd->media_dev.graph_mutex);
+err_clk:
 	media_device_unregister(&fmd->media_dev);
 	fimc_md_put_clocks(fmd);
 	fimc_md_unregister_entities(fmd);
-err2:
+err_md:
 	v4l2_device_unregister(&fmd->v4l2_dev);
 	return ret;
 }
@@ -841,10 +1013,12 @@
 int __init fimc_md_init(void)
 {
 	int ret;
+
 	request_module("s5p-csis");
 	ret = fimc_register_driver();
 	if (ret)
 		return ret;
+
 	return platform_driver_register(&fimc_md_driver);
 }
 void __exit fimc_md_exit(void)
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.h b/drivers/media/video/s5p-fimc/fimc-mdevice.h
index da37808..3b8a349 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.h
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 - 2012 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 version 2 as
@@ -18,12 +18,15 @@
 #include <media/v4l2-subdev.h>
 
 #include "fimc-core.h"
+#include "fimc-lite.h"
 #include "mipi-csis.h"
 
-/* Group IDs of sensor, MIPI CSIS and the writeback subdevs. */
+/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */
 #define SENSOR_GROUP_ID		(1 << 8)
 #define CSIS_GROUP_ID		(1 << 9)
 #define WRITEBACK_GROUP_ID	(1 << 10)
+#define FIMC_GROUP_ID		(1 << 11)
+#define FLITE_GROUP_ID		(1 << 12)
 
 #define FIMC_MAX_SENSORS	8
 #define FIMC_MAX_CAMCLKS	2
@@ -73,6 +76,7 @@
 	struct fimc_sensor_info sensor[FIMC_MAX_SENSORS];
 	int num_sensors;
 	struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS];
+	struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS];
 	struct fimc_dev *fimc[FIMC_MAX_DEVS];
 	struct media_device media_dev;
 	struct v4l2_device v4l2_dev;
@@ -108,11 +112,11 @@
 }
 
 int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
-void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me);
-int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
+void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me);
+int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me,
 			     bool resume);
-int fimc_pipeline_shutdown(struct fimc_dev *fimc);
-int fimc_pipeline_s_power(struct fimc_dev *fimc, int state);
-int fimc_pipeline_s_stream(struct fimc_dev *fimc, int state);
+int fimc_pipeline_shutdown(struct fimc_pipeline *p);
+int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state);
+int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool state);
 
 #endif
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 15466d0..1fc4ce8 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -1,9 +1,8 @@
 /*
  * Register interface file for Samsung Camera Interface (FIMC) driver
  *
- * Copyright (c) 2010 Samsung Electronics
- *
- * Sylwester Nawrocki, s.nawrocki@samsung.com
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@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
@@ -12,9 +11,9 @@
 
 #include <linux/io.h>
 #include <linux/delay.h>
-#include <mach/map.h>
 #include <media/s5p_fimc.h>
 
+#include "fimc-reg.h"
 #include "fimc-core.h"
 
 
@@ -22,19 +21,19 @@
 {
 	u32 cfg;
 
-	cfg = readl(dev->regs + S5P_CISRCFMT);
-	cfg |= S5P_CISRCFMT_ITU601_8BIT;
-	writel(cfg, dev->regs + S5P_CISRCFMT);
+	cfg = readl(dev->regs + FIMC_REG_CISRCFMT);
+	cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
+	writel(cfg, dev->regs + FIMC_REG_CISRCFMT);
 
 	/* Software reset. */
-	cfg = readl(dev->regs + S5P_CIGCTRL);
-	cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL);
-	writel(cfg, dev->regs + S5P_CIGCTRL);
+	cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+	cfg |= (FIMC_REG_CIGCTRL_SWRST | FIMC_REG_CIGCTRL_IRQ_LEVEL);
+	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
 	udelay(10);
 
-	cfg = readl(dev->regs + S5P_CIGCTRL);
-	cfg &= ~S5P_CIGCTRL_SWRST;
-	writel(cfg, dev->regs + S5P_CIGCTRL);
+	cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+	cfg &= ~FIMC_REG_CIGCTRL_SWRST;
+	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
 
 	if (dev->variant->out_buf_count > 4)
 		fimc_hw_set_dma_seq(dev, 0xF);
@@ -42,32 +41,32 @@
 
 static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
 {
-	u32 flip = S5P_MSCTRL_FLIP_NORMAL;
+	u32 flip = FIMC_REG_MSCTRL_FLIP_NORMAL;
 
 	if (ctx->hflip)
-		flip = S5P_MSCTRL_FLIP_X_MIRROR;
+		flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR;
 	if (ctx->vflip)
-		flip = S5P_MSCTRL_FLIP_Y_MIRROR;
+		flip = FIMC_REG_MSCTRL_FLIP_Y_MIRROR;
 
 	if (ctx->rotation <= 90)
 		return flip;
 
-	return (flip ^ S5P_MSCTRL_FLIP_180) & S5P_MSCTRL_FLIP_180;
+	return (flip ^ FIMC_REG_MSCTRL_FLIP_180) & FIMC_REG_MSCTRL_FLIP_180;
 }
 
 static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
 {
-	u32 flip = S5P_CITRGFMT_FLIP_NORMAL;
+	u32 flip = FIMC_REG_CITRGFMT_FLIP_NORMAL;
 
 	if (ctx->hflip)
-		flip |= S5P_CITRGFMT_FLIP_X_MIRROR;
+		flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR;
 	if (ctx->vflip)
-		flip |= S5P_CITRGFMT_FLIP_Y_MIRROR;
+		flip |= FIMC_REG_CITRGFMT_FLIP_Y_MIRROR;
 
 	if (ctx->rotation <= 90)
 		return flip;
 
-	return (flip ^ S5P_CITRGFMT_FLIP_180) & S5P_CITRGFMT_FLIP_180;
+	return (flip ^ FIMC_REG_CITRGFMT_FLIP_180) & FIMC_REG_CITRGFMT_FLIP_180;
 }
 
 void fimc_hw_set_rotation(struct fimc_ctx *ctx)
@@ -75,9 +74,9 @@
 	u32 cfg, flip;
 	struct fimc_dev *dev = ctx->fimc_dev;
 
-	cfg = readl(dev->regs + S5P_CITRGFMT);
-	cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 |
-		 S5P_CITRGFMT_FLIP_180);
+	cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
+	cfg &= ~(FIMC_REG_CITRGFMT_INROT90 | FIMC_REG_CITRGFMT_OUTROT90 |
+		 FIMC_REG_CITRGFMT_FLIP_180);
 
 	/*
 	 * The input and output rotator cannot work simultaneously.
@@ -85,21 +84,21 @@
 	 * in direct fifo output mode.
 	 */
 	if (ctx->rotation == 90 || ctx->rotation == 270) {
-		if (ctx->out_path == FIMC_LCDFIFO)
-			cfg |= S5P_CITRGFMT_INROT90;
+		if (ctx->out_path == FIMC_IO_LCDFIFO)
+			cfg |= FIMC_REG_CITRGFMT_INROT90;
 		else
-			cfg |= S5P_CITRGFMT_OUTROT90;
+			cfg |= FIMC_REG_CITRGFMT_OUTROT90;
 	}
 
-	if (ctx->out_path == FIMC_DMA) {
+	if (ctx->out_path == FIMC_IO_DMA) {
 		cfg |= fimc_hw_get_target_flip(ctx);
-		writel(cfg, dev->regs + S5P_CITRGFMT);
+		writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
 	} else {
 		/* LCD FIFO path */
-		flip = readl(dev->regs + S5P_MSCTRL);
-		flip &= ~S5P_MSCTRL_FLIP_MASK;
+		flip = readl(dev->regs + FIMC_REG_MSCTRL);
+		flip &= ~FIMC_REG_MSCTRL_FLIP_MASK;
 		flip |= fimc_hw_get_in_flip(ctx);
-		writel(flip, dev->regs + S5P_MSCTRL);
+		writel(flip, dev->regs + FIMC_REG_MSCTRL);
 	}
 }
 
@@ -110,43 +109,40 @@
 	struct fimc_frame *frame = &ctx->d_frame;
 
 	dbg("w= %d, h= %d color: %d", frame->width,
-		frame->height, frame->fmt->color);
+	    frame->height, frame->fmt->color);
 
-	cfg = readl(dev->regs + S5P_CITRGFMT);
-	cfg &= ~(S5P_CITRGFMT_FMT_MASK | S5P_CITRGFMT_HSIZE_MASK |
-		  S5P_CITRGFMT_VSIZE_MASK);
+	cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
+	cfg &= ~(FIMC_REG_CITRGFMT_FMT_MASK | FIMC_REG_CITRGFMT_HSIZE_MASK |
+		 FIMC_REG_CITRGFMT_VSIZE_MASK);
 
 	switch (frame->fmt->color) {
-	case S5P_FIMC_RGB444...S5P_FIMC_RGB888:
-		cfg |= S5P_CITRGFMT_RGB;
+	case FIMC_FMT_RGB444...FIMC_FMT_RGB888:
+		cfg |= FIMC_REG_CITRGFMT_RGB;
 		break;
-	case S5P_FIMC_YCBCR420:
-		cfg |= S5P_CITRGFMT_YCBCR420;
+	case FIMC_FMT_YCBCR420:
+		cfg |= FIMC_REG_CITRGFMT_YCBCR420;
 		break;
-	case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
+	case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
 		if (frame->fmt->colplanes == 1)
-			cfg |= S5P_CITRGFMT_YCBCR422_1P;
+			cfg |= FIMC_REG_CITRGFMT_YCBCR422_1P;
 		else
-			cfg |= S5P_CITRGFMT_YCBCR422;
+			cfg |= FIMC_REG_CITRGFMT_YCBCR422;
 		break;
 	default:
 		break;
 	}
 
-	if (ctx->rotation == 90 || ctx->rotation == 270) {
-		cfg |= S5P_CITRGFMT_HSIZE(frame->height);
-		cfg |= S5P_CITRGFMT_VSIZE(frame->width);
-	} else {
+	if (ctx->rotation == 90 || ctx->rotation == 270)
+		cfg |= (frame->height << 16) | frame->width;
+	else
+		cfg |= (frame->width << 16) | frame->height;
 
-		cfg |= S5P_CITRGFMT_HSIZE(frame->width);
-		cfg |= S5P_CITRGFMT_VSIZE(frame->height);
-	}
+	writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
 
-	writel(cfg, dev->regs + S5P_CITRGFMT);
-
-	cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK;
+	cfg = readl(dev->regs + FIMC_REG_CITAREA);
+	cfg &= ~FIMC_REG_CITAREA_MASK;
 	cfg |= (frame->width * frame->height);
-	writel(cfg, dev->regs + S5P_CITAREA);
+	writel(cfg, dev->regs + FIMC_REG_CITAREA);
 }
 
 static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
@@ -155,87 +151,82 @@
 	struct fimc_frame *frame = &ctx->d_frame;
 	u32 cfg;
 
-	cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
-	cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
-	writel(cfg, dev->regs + S5P_ORGOSIZE);
+	cfg = (frame->f_height << 16) | frame->f_width;
+	writel(cfg, dev->regs + FIMC_REG_ORGOSIZE);
 
 	/* Select color space conversion equation (HD/SD size).*/
-	cfg = readl(dev->regs + S5P_CIGCTRL);
+	cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
 	if (frame->f_width >= 1280) /* HD */
-		cfg |= S5P_CIGCTRL_CSC_ITU601_709;
+		cfg |= FIMC_REG_CIGCTRL_CSC_ITU601_709;
 	else	/* SD */
-		cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
-	writel(cfg, dev->regs + S5P_CIGCTRL);
+		cfg &= ~FIMC_REG_CIGCTRL_CSC_ITU601_709;
+	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
 
 }
 
 void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
 {
-	u32 cfg;
 	struct fimc_dev *dev = ctx->fimc_dev;
 	struct fimc_frame *frame = &ctx->d_frame;
 	struct fimc_dma_offset *offset = &frame->dma_offset;
 	struct fimc_fmt *fmt = frame->fmt;
+	u32 cfg;
 
 	/* Set the input dma offsets. */
-	cfg = 0;
-	cfg |= S5P_CIO_OFFS_HOR(offset->y_h);
-	cfg |= S5P_CIO_OFFS_VER(offset->y_v);
-	writel(cfg, dev->regs + S5P_CIOYOFF);
+	cfg = (offset->y_v << 16) | offset->y_h;
+	writel(cfg, dev->regs + FIMC_REG_CIOYOFF);
 
-	cfg = 0;
-	cfg |= S5P_CIO_OFFS_HOR(offset->cb_h);
-	cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
-	writel(cfg, dev->regs + S5P_CIOCBOFF);
+	cfg = (offset->cb_v << 16) | offset->cb_h;
+	writel(cfg, dev->regs + FIMC_REG_CIOCBOFF);
 
-	cfg = 0;
-	cfg |= S5P_CIO_OFFS_HOR(offset->cr_h);
-	cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
-	writel(cfg, dev->regs + S5P_CIOCROFF);
+	cfg = (offset->cr_v << 16) | offset->cr_h;
+	writel(cfg, dev->regs + FIMC_REG_CIOCROFF);
 
 	fimc_hw_set_out_dma_size(ctx);
 
 	/* Configure chroma components order. */
-	cfg = readl(dev->regs + S5P_CIOCTRL);
+	cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
 
-	cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK |
-		 S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK);
+	cfg &= ~(FIMC_REG_CIOCTRL_ORDER2P_MASK |
+		 FIMC_REG_CIOCTRL_ORDER422_MASK |
+		 FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK |
+		 FIMC_REG_CIOCTRL_RGB16FMT_MASK);
 
 	if (fmt->colplanes == 1)
 		cfg |= ctx->out_order_1p;
 	else if (fmt->colplanes == 2)
-		cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE;
+		cfg |= ctx->out_order_2p | FIMC_REG_CIOCTRL_YCBCR_2PLANE;
 	else if (fmt->colplanes == 3)
-		cfg |= S5P_CIOCTRL_YCBCR_3PLANE;
+		cfg |= FIMC_REG_CIOCTRL_YCBCR_3PLANE;
 
-	if (fmt->color == S5P_FIMC_RGB565)
-		cfg |= S5P_CIOCTRL_RGB565;
-	else if (fmt->color == S5P_FIMC_RGB555)
-		cfg |= S5P_CIOCTRL_ARGB1555;
-	else if (fmt->color == S5P_FIMC_RGB444)
-		cfg |= S5P_CIOCTRL_ARGB4444;
+	if (fmt->color == FIMC_FMT_RGB565)
+		cfg |= FIMC_REG_CIOCTRL_RGB565;
+	else if (fmt->color == FIMC_FMT_RGB555)
+		cfg |= FIMC_REG_CIOCTRL_ARGB1555;
+	else if (fmt->color == FIMC_FMT_RGB444)
+		cfg |= FIMC_REG_CIOCTRL_ARGB4444;
 
-	writel(cfg, dev->regs + S5P_CIOCTRL);
+	writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
 }
 
 static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
 {
-	u32 cfg = readl(dev->regs + S5P_ORGISIZE);
+	u32 cfg = readl(dev->regs + FIMC_REG_ORGISIZE);
 	if (enable)
-		cfg |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+		cfg |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
 	else
-		cfg &= ~S5P_CIREAL_ISIZE_AUTOLOAD_EN;
-	writel(cfg, dev->regs + S5P_ORGISIZE);
+		cfg &= ~FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
+	writel(cfg, dev->regs + FIMC_REG_ORGISIZE);
 }
 
 void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
 {
-	u32 cfg = readl(dev->regs + S5P_CIOCTRL);
+	u32 cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
 	if (enable)
-		cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
+		cfg |= FIMC_REG_CIOCTRL_LASTIRQ_ENABLE;
 	else
-		cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
-	writel(cfg, dev->regs + S5P_CIOCTRL);
+		cfg &= ~FIMC_REG_CIOCTRL_LASTIRQ_ENABLE;
+	writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
 }
 
 void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
@@ -245,15 +236,13 @@
 	u32 cfg, shfactor;
 
 	shfactor = 10 - (sc->hfactor + sc->vfactor);
+	cfg = shfactor << 28;
 
-	cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor);
-	cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio);
-	cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio);
-	writel(cfg, dev->regs + S5P_CISCPRERATIO);
+	cfg |= (sc->pre_hratio << 16) | sc->pre_vratio;
+	writel(cfg, dev->regs + FIMC_REG_CISCPRERATIO);
 
-	cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
-	cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height);
-	writel(cfg, dev->regs + S5P_CISCPREDST);
+	cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height;
+	writel(cfg, dev->regs + FIMC_REG_CISCPREDST);
 }
 
 static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
@@ -263,93 +252,95 @@
 	struct fimc_frame *src_frame = &ctx->s_frame;
 	struct fimc_frame *dst_frame = &ctx->d_frame;
 
-	u32 cfg = readl(dev->regs + S5P_CISCCTRL);
+	u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
 
-	cfg &= ~(S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE |
-		 S5P_CISCCTRL_SCALEUP_H | S5P_CISCCTRL_SCALEUP_V |
-		 S5P_CISCCTRL_SCALERBYPASS | S5P_CISCCTRL_ONE2ONE |
-		 S5P_CISCCTRL_INRGB_FMT_MASK | S5P_CISCCTRL_OUTRGB_FMT_MASK |
-		 S5P_CISCCTRL_INTERLACE | S5P_CISCCTRL_RGB_EXT);
+	cfg &= ~(FIMC_REG_CISCCTRL_CSCR2Y_WIDE | FIMC_REG_CISCCTRL_CSCY2R_WIDE |
+		 FIMC_REG_CISCCTRL_SCALEUP_H | FIMC_REG_CISCCTRL_SCALEUP_V |
+		 FIMC_REG_CISCCTRL_SCALERBYPASS | FIMC_REG_CISCCTRL_ONE2ONE |
+		 FIMC_REG_CISCCTRL_INRGB_FMT_MASK | FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK |
+		 FIMC_REG_CISCCTRL_INTERLACE | FIMC_REG_CISCCTRL_RGB_EXT);
 
 	if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
-		cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE);
+		cfg |= (FIMC_REG_CISCCTRL_CSCR2Y_WIDE |
+			FIMC_REG_CISCCTRL_CSCY2R_WIDE);
 
 	if (!sc->enabled)
-		cfg |= S5P_CISCCTRL_SCALERBYPASS;
+		cfg |= FIMC_REG_CISCCTRL_SCALERBYPASS;
 
 	if (sc->scaleup_h)
-		cfg |= S5P_CISCCTRL_SCALEUP_H;
+		cfg |= FIMC_REG_CISCCTRL_SCALEUP_H;
 
 	if (sc->scaleup_v)
-		cfg |= S5P_CISCCTRL_SCALEUP_V;
+		cfg |= FIMC_REG_CISCCTRL_SCALEUP_V;
 
 	if (sc->copy_mode)
-		cfg |= S5P_CISCCTRL_ONE2ONE;
+		cfg |= FIMC_REG_CISCCTRL_ONE2ONE;
 
-	if (ctx->in_path == FIMC_DMA) {
+	if (ctx->in_path == FIMC_IO_DMA) {
 		switch (src_frame->fmt->color) {
-		case S5P_FIMC_RGB565:
-			cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565;
+		case FIMC_FMT_RGB565:
+			cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB565;
 			break;
-		case S5P_FIMC_RGB666:
-			cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666;
+		case FIMC_FMT_RGB666:
+			cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB666;
 			break;
-		case S5P_FIMC_RGB888:
-			cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888;
+		case FIMC_FMT_RGB888:
+			cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB888;
 			break;
 		}
 	}
 
-	if (ctx->out_path == FIMC_DMA) {
+	if (ctx->out_path == FIMC_IO_DMA) {
 		u32 color = dst_frame->fmt->color;
 
-		if (color >= S5P_FIMC_RGB444 && color <= S5P_FIMC_RGB565)
-			cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565;
-		else if (color == S5P_FIMC_RGB666)
-			cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666;
-		else if (color == S5P_FIMC_RGB888)
-			cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
+		if (color >= FIMC_FMT_RGB444 && color <= FIMC_FMT_RGB565)
+			cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565;
+		else if (color == FIMC_FMT_RGB666)
+			cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666;
+		else if (color == FIMC_FMT_RGB888)
+			cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888;
 	} else {
-		cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
+		cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888;
 
 		if (ctx->flags & FIMC_SCAN_MODE_INTERLACED)
-			cfg |= S5P_CISCCTRL_INTERLACE;
+			cfg |= FIMC_REG_CISCCTRL_INTERLACE;
 	}
 
-	writel(cfg, dev->regs + S5P_CISCCTRL);
+	writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
 }
 
 void fimc_hw_set_mainscaler(struct fimc_ctx *ctx)
 {
 	struct fimc_dev *dev = ctx->fimc_dev;
-	struct samsung_fimc_variant *variant = dev->variant;
+	struct fimc_variant *variant = dev->variant;
 	struct fimc_scaler *sc = &ctx->scaler;
 	u32 cfg;
 
 	dbg("main_hratio= 0x%X  main_vratio= 0x%X",
-		sc->main_hratio, sc->main_vratio);
+	    sc->main_hratio, sc->main_vratio);
 
 	fimc_hw_set_scaler(ctx);
 
-	cfg = readl(dev->regs + S5P_CISCCTRL);
-	cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK);
+	cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+	cfg &= ~(FIMC_REG_CISCCTRL_MHRATIO_MASK |
+		 FIMC_REG_CISCCTRL_MVRATIO_MASK);
 
 	if (variant->has_mainscaler_ext) {
-		cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio);
-		cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio);
-		writel(cfg, dev->regs + S5P_CISCCTRL);
+		cfg |= FIMC_REG_CISCCTRL_MHRATIO_EXT(sc->main_hratio);
+		cfg |= FIMC_REG_CISCCTRL_MVRATIO_EXT(sc->main_vratio);
+		writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
 
-		cfg = readl(dev->regs + S5P_CIEXTEN);
+		cfg = readl(dev->regs + FIMC_REG_CIEXTEN);
 
-		cfg &= ~(S5P_CIEXTEN_MVRATIO_EXT_MASK |
-			 S5P_CIEXTEN_MHRATIO_EXT_MASK);
-		cfg |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio);
-		cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio);
-		writel(cfg, dev->regs + S5P_CIEXTEN);
+		cfg &= ~(FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK |
+			 FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK);
+		cfg |= FIMC_REG_CIEXTEN_MHRATIO_EXT(sc->main_hratio);
+		cfg |= FIMC_REG_CIEXTEN_MVRATIO_EXT(sc->main_vratio);
+		writel(cfg, dev->regs + FIMC_REG_CIEXTEN);
 	} else {
-		cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio);
-		cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio);
-		writel(cfg, dev->regs + S5P_CISCCTRL);
+		cfg |= FIMC_REG_CISCCTRL_MHRATIO(sc->main_hratio);
+		cfg |= FIMC_REG_CISCCTRL_MVRATIO(sc->main_vratio);
+		writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
 	}
 }
 
@@ -357,40 +348,41 @@
 {
 	struct fimc_dev *dev = ctx->fimc_dev;
 
-	u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
+	u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
 
-	if (ctx->out_path == FIMC_DMA) {
+	if (ctx->out_path == FIMC_IO_DMA) {
 		/* one shot mode */
-		cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
+		cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE |
+			FIMC_REG_CIIMGCPT_IMGCPTEN;
 	} else {
 		/* Continuous frame capture mode (freerun). */
-		cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
-			 S5P_CIIMGCPT_CPT_FRMOD_CNT);
-		cfg |= S5P_CIIMGCPT_IMGCPTEN;
+		cfg &= ~(FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE |
+			 FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT);
+		cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;
 	}
 
 	if (ctx->scaler.enabled)
-		cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
+		cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN_SC;
 
-	writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT);
+	cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;
+	writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
 }
 
-void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active)
+void fimc_hw_set_effect(struct fimc_ctx *ctx)
 {
 	struct fimc_dev *dev = ctx->fimc_dev;
 	struct fimc_effect *effect = &ctx->effect;
 	u32 cfg = 0;
 
-	if (active) {
-		cfg |= S5P_CIIMGEFF_IE_SC_AFTER | S5P_CIIMGEFF_IE_ENABLE;
+	if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) {
+		cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER |
+			FIMC_REG_CIIMGEFF_IE_ENABLE;
 		cfg |= effect->type;
-		if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) {
-			cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb);
-			cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr);
-		}
+		if (effect->type == FIMC_REG_CIIMGEFF_FIN_ARBITRARY)
+			cfg |= (effect->pat_cb << 13) | effect->pat_cr;
 	}
 
-	writel(cfg, dev->regs + S5P_CIIMGEFF);
+	writel(cfg, dev->regs + FIMC_REG_CIIMGEFF);
 }
 
 void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
@@ -402,10 +394,10 @@
 	if (!(frame->fmt->flags & FMT_HAS_ALPHA))
 		return;
 
-	cfg = readl(dev->regs + S5P_CIOCTRL);
-	cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK;
+	cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
+	cfg &= ~FIMC_REG_CIOCTRL_ALPHA_OUT_MASK;
 	cfg |= (frame->alpha << 4);
-	writel(cfg, dev->regs + S5P_CIOCTRL);
+	writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
 }
 
 static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
@@ -415,16 +407,14 @@
 	u32 cfg_o = 0;
 	u32 cfg_r = 0;
 
-	if (FIMC_LCDFIFO == ctx->out_path)
-		cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+	if (FIMC_IO_LCDFIFO == ctx->out_path)
+		cfg_r |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
 
-	cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width);
-	cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height);
-	cfg_r |= S5P_CIREAL_ISIZE_WIDTH(frame->width);
-	cfg_r |= S5P_CIREAL_ISIZE_HEIGHT(frame->height);
+	cfg_o |= (frame->f_height << 16) | frame->f_width;
+	cfg_r |= (frame->height << 16) | frame->width;
 
-	writel(cfg_o, dev->regs + S5P_ORGISIZE);
-	writel(cfg_r, dev->regs + S5P_CIREAL_ISIZE);
+	writel(cfg_o, dev->regs + FIMC_REG_ORGISIZE);
+	writel(cfg_r, dev->regs + FIMC_REG_CIREAL_ISIZE);
 }
 
 void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
@@ -435,80 +425,77 @@
 	u32 cfg;
 
 	/* Set the pixel offsets. */
-	cfg = S5P_CIO_OFFS_HOR(offset->y_h);
-	cfg |= S5P_CIO_OFFS_VER(offset->y_v);
-	writel(cfg, dev->regs + S5P_CIIYOFF);
+	cfg = (offset->y_v << 16) | offset->y_h;
+	writel(cfg, dev->regs + FIMC_REG_CIIYOFF);
 
-	cfg = S5P_CIO_OFFS_HOR(offset->cb_h);
-	cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
-	writel(cfg, dev->regs + S5P_CIICBOFF);
+	cfg = (offset->cb_v << 16) | offset->cb_h;
+	writel(cfg, dev->regs + FIMC_REG_CIICBOFF);
 
-	cfg = S5P_CIO_OFFS_HOR(offset->cr_h);
-	cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
-	writel(cfg, dev->regs + S5P_CIICROFF);
+	cfg = (offset->cr_v << 16) | offset->cr_h;
+	writel(cfg, dev->regs + FIMC_REG_CIICROFF);
 
 	/* Input original and real size. */
 	fimc_hw_set_in_dma_size(ctx);
 
 	/* Use DMA autoload only in FIFO mode. */
-	fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO);
+	fimc_hw_en_autoload(dev, ctx->out_path == FIMC_IO_LCDFIFO);
 
 	/* Set the input DMA to process single frame only. */
-	cfg = readl(dev->regs + S5P_MSCTRL);
-	cfg &= ~(S5P_MSCTRL_INFORMAT_MASK
-		| S5P_MSCTRL_IN_BURST_COUNT_MASK
-		| S5P_MSCTRL_INPUT_MASK
-		| S5P_MSCTRL_C_INT_IN_MASK
-		| S5P_MSCTRL_2P_IN_ORDER_MASK);
+	cfg = readl(dev->regs + FIMC_REG_MSCTRL);
+	cfg &= ~(FIMC_REG_MSCTRL_INFORMAT_MASK
+		 | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK
+		 | FIMC_REG_MSCTRL_INPUT_MASK
+		 | FIMC_REG_MSCTRL_C_INT_IN_MASK
+		 | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK);
 
-	cfg |= (S5P_MSCTRL_IN_BURST_COUNT(4)
-		| S5P_MSCTRL_INPUT_MEMORY
-		| S5P_MSCTRL_FIFO_CTRL_FULL);
+	cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4)
+		| FIMC_REG_MSCTRL_INPUT_MEMORY
+		| FIMC_REG_MSCTRL_FIFO_CTRL_FULL);
 
 	switch (frame->fmt->color) {
-	case S5P_FIMC_RGB565...S5P_FIMC_RGB888:
-		cfg |= S5P_MSCTRL_INFORMAT_RGB;
+	case FIMC_FMT_RGB565...FIMC_FMT_RGB888:
+		cfg |= FIMC_REG_MSCTRL_INFORMAT_RGB;
 		break;
-	case S5P_FIMC_YCBCR420:
-		cfg |= S5P_MSCTRL_INFORMAT_YCBCR420;
+	case FIMC_FMT_YCBCR420:
+		cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR420;
 
 		if (frame->fmt->colplanes == 2)
-			cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE;
+			cfg |= ctx->in_order_2p | FIMC_REG_MSCTRL_C_INT_IN_2PLANE;
 		else
-			cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
+			cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE;
 
 		break;
-	case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
+	case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
 		if (frame->fmt->colplanes == 1) {
 			cfg |= ctx->in_order_1p
-				| S5P_MSCTRL_INFORMAT_YCBCR422_1P;
+				| FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P;
 		} else {
-			cfg |= S5P_MSCTRL_INFORMAT_YCBCR422;
+			cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR422;
 
 			if (frame->fmt->colplanes == 2)
 				cfg |= ctx->in_order_2p
-					| S5P_MSCTRL_C_INT_IN_2PLANE;
+					| FIMC_REG_MSCTRL_C_INT_IN_2PLANE;
 			else
-				cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
+				cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE;
 		}
 		break;
 	default:
 		break;
 	}
 
-	writel(cfg, dev->regs + S5P_MSCTRL);
+	writel(cfg, dev->regs + FIMC_REG_MSCTRL);
 
 	/* Input/output DMA linear/tiled mode. */
-	cfg = readl(dev->regs + S5P_CIDMAPARAM);
-	cfg &= ~S5P_CIDMAPARAM_TILE_MASK;
+	cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM);
+	cfg &= ~FIMC_REG_CIDMAPARAM_TILE_MASK;
 
 	if (tiled_fmt(ctx->s_frame.fmt))
-		cfg |= S5P_CIDMAPARAM_R_64X32;
+		cfg |= FIMC_REG_CIDMAPARAM_R_64X32;
 
 	if (tiled_fmt(ctx->d_frame.fmt))
-		cfg |= S5P_CIDMAPARAM_W_64X32;
+		cfg |= FIMC_REG_CIDMAPARAM_W_64X32;
 
-	writel(cfg, dev->regs + S5P_CIDMAPARAM);
+	writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM);
 }
 
 
@@ -516,40 +503,40 @@
 {
 	struct fimc_dev *dev = ctx->fimc_dev;
 
-	u32 cfg = readl(dev->regs + S5P_MSCTRL);
-	cfg &= ~S5P_MSCTRL_INPUT_MASK;
+	u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
+	cfg &= ~FIMC_REG_MSCTRL_INPUT_MASK;
 
-	if (ctx->in_path == FIMC_DMA)
-		cfg |= S5P_MSCTRL_INPUT_MEMORY;
+	if (ctx->in_path == FIMC_IO_DMA)
+		cfg |= FIMC_REG_MSCTRL_INPUT_MEMORY;
 	else
-		cfg |= S5P_MSCTRL_INPUT_EXTCAM;
+		cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM;
 
-	writel(cfg, dev->regs + S5P_MSCTRL);
+	writel(cfg, dev->regs + FIMC_REG_MSCTRL);
 }
 
 void fimc_hw_set_output_path(struct fimc_ctx *ctx)
 {
 	struct fimc_dev *dev = ctx->fimc_dev;
 
-	u32 cfg = readl(dev->regs + S5P_CISCCTRL);
-	cfg &= ~S5P_CISCCTRL_LCDPATHEN_FIFO;
-	if (ctx->out_path == FIMC_LCDFIFO)
-		cfg |= S5P_CISCCTRL_LCDPATHEN_FIFO;
-	writel(cfg, dev->regs + S5P_CISCCTRL);
+	u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+	cfg &= ~FIMC_REG_CISCCTRL_LCDPATHEN_FIFO;
+	if (ctx->out_path == FIMC_IO_LCDFIFO)
+		cfg |= FIMC_REG_CISCCTRL_LCDPATHEN_FIFO;
+	writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
 }
 
 void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
 {
-	u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
-	cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS;
-	writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
+	u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE);
+	cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS;
+	writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
 
-	writel(paddr->y, dev->regs + S5P_CIIYSA(0));
-	writel(paddr->cb, dev->regs + S5P_CIICBSA(0));
-	writel(paddr->cr, dev->regs + S5P_CIICRSA(0));
+	writel(paddr->y, dev->regs + FIMC_REG_CIIYSA(0));
+	writel(paddr->cb, dev->regs + FIMC_REG_CIICBSA(0));
+	writel(paddr->cr, dev->regs + FIMC_REG_CIICRSA(0));
 
-	cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS;
-	writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
+	cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS;
+	writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
 }
 
 void fimc_hw_set_output_addr(struct fimc_dev *dev,
@@ -557,9 +544,9 @@
 {
 	int i = (index == -1) ? 0 : index;
 	do {
-		writel(paddr->y, dev->regs + S5P_CIOYSA(i));
-		writel(paddr->cb, dev->regs + S5P_CIOCBSA(i));
-		writel(paddr->cr, dev->regs + S5P_CIOCRSA(i));
+		writel(paddr->y, dev->regs + FIMC_REG_CIOYSA(i));
+		writel(paddr->cb, dev->regs + FIMC_REG_CIOCBSA(i));
+		writel(paddr->cr, dev->regs + FIMC_REG_CIOCRSA(i));
 		dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
 		    i, paddr->y, paddr->cb, paddr->cr);
 	} while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
@@ -568,32 +555,45 @@
 int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
 				struct s5p_fimc_isp_info *cam)
 {
-	u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
+	u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
 
-	cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
-		 S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC |
-		 S5P_CIGCTRL_INVPOLFIELD);
+	cfg &= ~(FIMC_REG_CIGCTRL_INVPOLPCLK | FIMC_REG_CIGCTRL_INVPOLVSYNC |
+		 FIMC_REG_CIGCTRL_INVPOLHREF | FIMC_REG_CIGCTRL_INVPOLHSYNC |
+		 FIMC_REG_CIGCTRL_INVPOLFIELD);
 
 	if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
-		cfg |= S5P_CIGCTRL_INVPOLPCLK;
+		cfg |= FIMC_REG_CIGCTRL_INVPOLPCLK;
 
 	if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
-		cfg |= S5P_CIGCTRL_INVPOLVSYNC;
+		cfg |= FIMC_REG_CIGCTRL_INVPOLVSYNC;
 
 	if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
-		cfg |= S5P_CIGCTRL_INVPOLHREF;
+		cfg |= FIMC_REG_CIGCTRL_INVPOLHREF;
 
 	if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
-		cfg |= S5P_CIGCTRL_INVPOLHSYNC;
+		cfg |= FIMC_REG_CIGCTRL_INVPOLHSYNC;
 
 	if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW)
-		cfg |= S5P_CIGCTRL_INVPOLFIELD;
+		cfg |= FIMC_REG_CIGCTRL_INVPOLFIELD;
 
-	writel(cfg, fimc->regs + S5P_CIGCTRL);
+	writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
 
 	return 0;
 }
 
+struct mbus_pixfmt_desc {
+	u32 pixelcode;
+	u32 cisrcfmt;
+	u16 bus_width;
+};
+
+static const struct mbus_pixfmt_desc pix_desc[] = {
+	{ V4L2_MBUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 },
+	{ V4L2_MBUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 },
+	{ V4L2_MBUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 },
+	{ V4L2_MBUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 },
+};
+
 int fimc_hw_set_camera_source(struct fimc_dev *fimc,
 			      struct s5p_fimc_isp_info *cam)
 {
@@ -602,18 +602,6 @@
 	u32 bus_width;
 	int i;
 
-	static const struct {
-		u32 pixelcode;
-		u32 cisrcfmt;
-		u16 bus_width;
-	} pix_desc[] = {
-		{ V4L2_MBUS_FMT_YUYV8_2X8, S5P_CISRCFMT_ORDER422_YCBYCR, 8 },
-		{ V4L2_MBUS_FMT_YVYU8_2X8, S5P_CISRCFMT_ORDER422_YCRYCB, 8 },
-		{ V4L2_MBUS_FMT_VYUY8_2X8, S5P_CISRCFMT_ORDER422_CRYCBY, 8 },
-		{ V4L2_MBUS_FMT_UYVY8_2X8, S5P_CISRCFMT_ORDER422_CBYCRY, 8 },
-		/* TODO: Add pixel codes for 16-bit bus width */
-	};
-
 	if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
 		for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
 			if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
@@ -632,41 +620,37 @@
 
 		if (cam->bus_type == FIMC_ITU_601) {
 			if (bus_width == 8)
-				cfg |= S5P_CISRCFMT_ITU601_8BIT;
+				cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
 			else if (bus_width == 16)
-				cfg |= S5P_CISRCFMT_ITU601_16BIT;
+				cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT;
 		} /* else defaults to ITU-R BT.656 8-bit */
 	} else if (cam->bus_type == FIMC_MIPI_CSI2) {
 		if (fimc_fmt_is_jpeg(f->fmt->color))
-			cfg |= S5P_CISRCFMT_ITU601_8BIT;
+			cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
 	}
 
-	cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
-	writel(cfg, fimc->regs + S5P_CISRCFMT);
+	cfg |= (f->o_width << 16) | f->o_height;
+	writel(cfg, fimc->regs + FIMC_REG_CISRCFMT);
 	return 0;
 }
 
-
-int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
+void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
 {
 	u32 hoff2, voff2;
 
-	u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
+	u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST);
 
-	cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
-	cfg |=  S5P_CIWDOFST_OFF_EN |
-		S5P_CIWDOFST_HOROFF(f->offs_h) |
-		S5P_CIWDOFST_VEROFF(f->offs_v);
+	cfg &= ~(FIMC_REG_CIWDOFST_HOROFF_MASK | FIMC_REG_CIWDOFST_VEROFF_MASK);
+	cfg |=  FIMC_REG_CIWDOFST_OFF_EN |
+		(f->offs_h << 16) | f->offs_v;
 
-	writel(cfg, fimc->regs + S5P_CIWDOFST);
+	writel(cfg, fimc->regs + FIMC_REG_CIWDOFST);
 
 	/* See CIWDOFSTn register description in the datasheet for details. */
 	hoff2 = f->o_width - f->width - f->offs_h;
 	voff2 = f->o_height - f->height - f->offs_v;
-	cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
-
-	writel(cfg, fimc->regs + S5P_CIWDOFST2);
-	return 0;
+	cfg = (hoff2 << 16) | voff2;
+	writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2);
 }
 
 int fimc_hw_set_camera_type(struct fimc_dev *fimc,
@@ -674,28 +658,29 @@
 {
 	u32 cfg, tmp;
 	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+	u32 csis_data_alignment = 32;
 
-	cfg = readl(fimc->regs + S5P_CIGCTRL);
+	cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
 
 	/* Select ITU B interface, disable Writeback path and test pattern. */
-	cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
-		S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
-		S5P_CIGCTRL_SELCAM_MIPI_A | S5P_CIGCTRL_CAM_JPEG);
+	cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A |
+		FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB |
+		FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG);
 
 	if (cam->bus_type == FIMC_MIPI_CSI2) {
-		cfg |= S5P_CIGCTRL_SELCAM_MIPI;
+		cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI;
 
 		if (cam->mux_id == 0)
-			cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
+			cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A;
 
 		/* TODO: add remaining supported formats. */
 		switch (vid_cap->mf.code) {
 		case V4L2_MBUS_FMT_VYUY8_2X8:
-			tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
+			tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT;
 			break;
 		case V4L2_MBUS_FMT_JPEG_1X8:
-			tmp = S5P_CSIIMGFMT_USER(1);
-			cfg |= S5P_CIGCTRL_CAM_JPEG;
+			tmp = FIMC_REG_CSIIMGFMT_USER(1);
+			cfg |= FIMC_REG_CIGCTRL_CAM_JPEG;
 			break;
 		default:
 			v4l2_err(fimc->vid_cap.vfd,
@@ -703,21 +688,86 @@
 				 vid_cap->mf.code);
 			return -EINVAL;
 		}
-		tmp |= (cam->csi_data_align == 32) << 8;
+		tmp |= (csis_data_alignment == 32) << 8;
 
-		writel(tmp, fimc->regs + S5P_CSIIMGFMT);
+		writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT);
 
 	} else if (cam->bus_type == FIMC_ITU_601 ||
 		   cam->bus_type == FIMC_ITU_656) {
 		if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
-			cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
+			cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A;
 	} else if (cam->bus_type == FIMC_LCD_WB) {
-		cfg |= S5P_CIGCTRL_CAMIF_SELWB;
+		cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
 	} else {
 		err("invalid camera bus type selected\n");
 		return -EINVAL;
 	}
-	writel(cfg, fimc->regs + S5P_CIGCTRL);
+	writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
 
 	return 0;
 }
+
+void fimc_hw_clear_irq(struct fimc_dev *dev)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+	cfg |= FIMC_REG_CIGCTRL_IRQ_CLR;
+	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
+}
+
+void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+	if (on)
+		cfg |= FIMC_REG_CISCCTRL_SCALERSTART;
+	else
+		cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART;
+	writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
+}
+
+void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
+	if (on)
+		cfg |= FIMC_REG_MSCTRL_ENVID;
+	else
+		cfg &= ~FIMC_REG_MSCTRL_ENVID;
+	writel(cfg, dev->regs + FIMC_REG_MSCTRL);
+}
+
+void fimc_hw_dis_capture(struct fimc_dev *dev)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
+	cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN | FIMC_REG_CIIMGCPT_IMGCPTEN_SC);
+	writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
+}
+
+/* Return an index to the buffer actually being written. */
+u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
+{
+	u32 reg;
+
+	if (dev->variant->has_cistatus2) {
+		reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3F;
+		return reg > 0 ? --reg : reg;
+	}
+
+	reg = readl(dev->regs + FIMC_REG_CISTATUS);
+
+	return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >>
+		FIMC_REG_CISTATUS_FRAMECNT_SHIFT;
+}
+
+/* Locking: the caller holds fimc->slock */
+void fimc_activate_capture(struct fimc_ctx *ctx)
+{
+	fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
+	fimc_hw_en_capture(ctx);
+}
+
+void fimc_deactivate_capture(struct fimc_dev *fimc)
+{
+	fimc_hw_en_lastirq(fimc, true);
+	fimc_hw_dis_capture(fimc);
+	fimc_hw_enable_scaler(fimc, false);
+	fimc_hw_en_lastirq(fimc, false);
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.h b/drivers/media/video/s5p-fimc/fimc-reg.h
new file mode 100644
index 0000000..579ac8a
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-reg.h
@@ -0,0 +1,326 @@
+/*
+ * Samsung camera host interface (FIMC) registers definition
+ *
+ * Copyright (C) 2010 - 2012 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_REG_H_
+#define FIMC_REG_H_
+
+#include "fimc-core.h"
+
+/* Input source format */
+#define FIMC_REG_CISRCFMT			0x00
+#define FIMC_REG_CISRCFMT_ITU601_8BIT		(1 << 31)
+#define FIMC_REG_CISRCFMT_ITU601_16BIT		(1 << 29)
+#define FIMC_REG_CISRCFMT_ORDER422_YCBYCR	(0 << 14)
+#define FIMC_REG_CISRCFMT_ORDER422_YCRYCB	(1 << 14)
+#define FIMC_REG_CISRCFMT_ORDER422_CBYCRY	(2 << 14)
+#define FIMC_REG_CISRCFMT_ORDER422_CRYCBY	(3 << 14)
+
+/* Window offset */
+#define FIMC_REG_CIWDOFST			0x04
+#define FIMC_REG_CIWDOFST_OFF_EN		(1 << 31)
+#define FIMC_REG_CIWDOFST_CLROVFIY		(1 << 30)
+#define FIMC_REG_CIWDOFST_CLROVRLB		(1 << 29)
+#define FIMC_REG_CIWDOFST_HOROFF_MASK		(0x7ff << 16)
+#define FIMC_REG_CIWDOFST_CLROVFICB		(1 << 15)
+#define FIMC_REG_CIWDOFST_CLROVFICR		(1 << 14)
+#define FIMC_REG_CIWDOFST_VEROFF_MASK		(0xfff << 0)
+
+/* Global control */
+#define FIMC_REG_CIGCTRL			0x08
+#define FIMC_REG_CIGCTRL_SWRST			(1 << 31)
+#define FIMC_REG_CIGCTRL_CAMRST_A		(1 << 30)
+#define FIMC_REG_CIGCTRL_SELCAM_ITU_A		(1 << 29)
+#define FIMC_REG_CIGCTRL_TESTPAT_NORMAL		(0 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_COLOR_BAR	(1 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_HOR_INC	(2 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_VER_INC	(3 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_MASK		(3 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_SHIFT		27
+#define FIMC_REG_CIGCTRL_INVPOLPCLK		(1 << 26)
+#define FIMC_REG_CIGCTRL_INVPOLVSYNC		(1 << 25)
+#define FIMC_REG_CIGCTRL_INVPOLHREF		(1 << 24)
+#define FIMC_REG_CIGCTRL_IRQ_OVFEN		(1 << 22)
+#define FIMC_REG_CIGCTRL_HREF_MASK		(1 << 21)
+#define FIMC_REG_CIGCTRL_IRQ_LEVEL		(1 << 20)
+#define FIMC_REG_CIGCTRL_IRQ_CLR		(1 << 19)
+#define FIMC_REG_CIGCTRL_IRQ_ENABLE		(1 << 16)
+#define FIMC_REG_CIGCTRL_SHDW_DISABLE		(1 << 12)
+#define FIMC_REG_CIGCTRL_CAM_JPEG		(1 << 8)
+#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A		(1 << 7)
+#define FIMC_REG_CIGCTRL_CAMIF_SELWB		(1 << 6)
+/* 0 - ITU601; 1 - ITU709 */
+#define FIMC_REG_CIGCTRL_CSC_ITU601_709		(1 << 5)
+#define FIMC_REG_CIGCTRL_INVPOLHSYNC		(1 << 4)
+#define FIMC_REG_CIGCTRL_SELCAM_MIPI		(1 << 3)
+#define FIMC_REG_CIGCTRL_INVPOLFIELD		(1 << 1)
+#define FIMC_REG_CIGCTRL_INTERLACE		(1 << 0)
+
+/* Window offset 2 */
+#define FIMC_REG_CIWDOFST2			0x14
+#define FIMC_REG_CIWDOFST2_HOROFF_MASK		(0xfff << 16)
+#define FIMC_REG_CIWDOFST2_VEROFF_MASK		(0xfff << 0)
+
+/* Output DMA Y/Cb/Cr plane start addresses */
+#define FIMC_REG_CIOYSA(n)			(0x18 + (n) * 4)
+#define FIMC_REG_CIOCBSA(n)			(0x28 + (n) * 4)
+#define FIMC_REG_CIOCRSA(n)			(0x38 + (n) * 4)
+
+/* Target image format */
+#define FIMC_REG_CITRGFMT			0x48
+#define FIMC_REG_CITRGFMT_INROT90		(1 << 31)
+#define FIMC_REG_CITRGFMT_YCBCR420		(0 << 29)
+#define FIMC_REG_CITRGFMT_YCBCR422		(1 << 29)
+#define FIMC_REG_CITRGFMT_YCBCR422_1P		(2 << 29)
+#define FIMC_REG_CITRGFMT_RGB			(3 << 29)
+#define FIMC_REG_CITRGFMT_FMT_MASK		(3 << 29)
+#define FIMC_REG_CITRGFMT_HSIZE_MASK		(0xfff << 16)
+#define FIMC_REG_CITRGFMT_FLIP_SHIFT		14
+#define FIMC_REG_CITRGFMT_FLIP_NORMAL		(0 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_X_MIRROR		(1 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_Y_MIRROR		(2 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_180		(3 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_MASK		(3 << 14)
+#define FIMC_REG_CITRGFMT_OUTROT90		(1 << 13)
+#define FIMC_REG_CITRGFMT_VSIZE_MASK		(0xfff << 0)
+
+/* Output DMA control */
+#define FIMC_REG_CIOCTRL			0x4c
+#define FIMC_REG_CIOCTRL_ORDER422_MASK		(3 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY	(0 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY	(1 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB	(2 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_YCBYCR	(3 << 0)
+#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE		(1 << 2)
+#define FIMC_REG_CIOCTRL_YCBCR_3PLANE		(0 << 3)
+#define FIMC_REG_CIOCTRL_YCBCR_2PLANE		(1 << 3)
+#define FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK	(1 << 3)
+#define FIMC_REG_CIOCTRL_ALPHA_OUT_MASK		(0xff << 4)
+#define FIMC_REG_CIOCTRL_RGB16FMT_MASK		(3 << 16)
+#define FIMC_REG_CIOCTRL_RGB565			(0 << 16)
+#define FIMC_REG_CIOCTRL_ARGB1555		(1 << 16)
+#define FIMC_REG_CIOCTRL_ARGB4444		(2 << 16)
+#define FIMC_REG_CIOCTRL_ORDER2P_SHIFT		24
+#define FIMC_REG_CIOCTRL_ORDER2P_MASK		(3 << 24)
+#define FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB	(0 << 24)
+
+/* Pre-scaler control 1 */
+#define FIMC_REG_CISCPRERATIO			0x50
+
+#define FIMC_REG_CISCPREDST			0x54
+
+/* Main scaler control */
+#define FIMC_REG_CISCCTRL			0x58
+#define FIMC_REG_CISCCTRL_SCALERBYPASS		(1 << 31)
+#define FIMC_REG_CISCCTRL_SCALEUP_H		(1 << 30)
+#define FIMC_REG_CISCCTRL_SCALEUP_V		(1 << 29)
+#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE		(1 << 28)
+#define FIMC_REG_CISCCTRL_CSCY2R_WIDE		(1 << 27)
+#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO	(1 << 26)
+#define FIMC_REG_CISCCTRL_INTERLACE		(1 << 25)
+#define FIMC_REG_CISCCTRL_SCALERSTART		(1 << 15)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB565	(0 << 13)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB666	(1 << 13)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB888	(2 << 13)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_MASK	(3 << 13)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565	(0 << 11)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666	(1 << 11)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888	(2 << 11)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK	(3 << 11)
+#define FIMC_REG_CISCCTRL_RGB_EXT		(1 << 10)
+#define FIMC_REG_CISCCTRL_ONE2ONE		(1 << 9)
+#define FIMC_REG_CISCCTRL_MHRATIO(x)		((x) << 16)
+#define FIMC_REG_CISCCTRL_MVRATIO(x)		((x) << 0)
+#define FIMC_REG_CISCCTRL_MHRATIO_MASK		(0x1ff << 16)
+#define FIMC_REG_CISCCTRL_MVRATIO_MASK		(0x1ff << 0)
+#define FIMC_REG_CISCCTRL_MHRATIO_EXT(x)	(((x) >> 6) << 16)
+#define FIMC_REG_CISCCTRL_MVRATIO_EXT(x)	(((x) >> 6) << 0)
+
+/* Target area */
+#define FIMC_REG_CITAREA			0x5c
+#define FIMC_REG_CITAREA_MASK			0x0fffffff
+
+/* General status */
+#define FIMC_REG_CISTATUS			0x64
+#define FIMC_REG_CISTATUS_OVFIY			(1 << 31)
+#define FIMC_REG_CISTATUS_OVFICB		(1 << 30)
+#define FIMC_REG_CISTATUS_OVFICR		(1 << 29)
+#define FIMC_REG_CISTATUS_VSYNC			(1 << 28)
+#define FIMC_REG_CISTATUS_FRAMECNT_MASK		(3 << 26)
+#define FIMC_REG_CISTATUS_FRAMECNT_SHIFT	26
+#define FIMC_REG_CISTATUS_WINOFF_EN		(1 << 25)
+#define FIMC_REG_CISTATUS_IMGCPT_EN		(1 << 22)
+#define FIMC_REG_CISTATUS_IMGCPT_SCEN		(1 << 21)
+#define FIMC_REG_CISTATUS_VSYNC_A		(1 << 20)
+#define FIMC_REG_CISTATUS_VSYNC_B		(1 << 19)
+#define FIMC_REG_CISTATUS_OVRLB			(1 << 18)
+#define FIMC_REG_CISTATUS_FRAME_END		(1 << 17)
+#define FIMC_REG_CISTATUS_LASTCAPT_END		(1 << 16)
+#define FIMC_REG_CISTATUS_VVALID_A		(1 << 15)
+#define FIMC_REG_CISTATUS_VVALID_B		(1 << 14)
+
+/* Indexes to the last and the currently processed buffer. */
+#define FIMC_REG_CISTATUS2			0x68
+
+/* Image capture control */
+#define FIMC_REG_CIIMGCPT			0xc0
+#define FIMC_REG_CIIMGCPT_IMGCPTEN		(1 << 31)
+#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC		(1 << 30)
+#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE	(1 << 25)
+#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT		(1 << 18)
+
+/* Frame capture sequence */
+#define FIMC_REG_CICPTSEQ			0xc4
+
+/* Image effect */
+#define FIMC_REG_CIIMGEFF			0xd0
+#define FIMC_REG_CIIMGEFF_IE_ENABLE		(1 << 30)
+#define FIMC_REG_CIIMGEFF_IE_SC_BEFORE		(0 << 29)
+#define FIMC_REG_CIIMGEFF_IE_SC_AFTER		(1 << 29)
+#define FIMC_REG_CIIMGEFF_FIN_BYPASS		(0 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_ARBITRARY		(1 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_NEGATIVE		(2 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_ARTFREEZE		(3 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_EMBOSSING		(4 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_SILHOUETTE	(5 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_MASK		(7 << 26)
+#define FIMC_REG_CIIMGEFF_PAT_CBCR_MASK		((0xff << 13) | 0xff)
+
+/* Input DMA Y/Cb/Cr plane start address 0/1 */
+#define FIMC_REG_CIIYSA(n)			(0xd4 + (n) * 0x70)
+#define FIMC_REG_CIICBSA(n)			(0xd8 + (n) * 0x70)
+#define FIMC_REG_CIICRSA(n)			(0xdc + (n) * 0x70)
+
+/* Real input DMA image size */
+#define FIMC_REG_CIREAL_ISIZE			0xf8
+#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN	(1 << 31)
+#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS	(1 << 30)
+
+/* Input DMA control */
+#define FIMC_REG_MSCTRL				0xfc
+#define FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK	(0xf << 24)
+#define FIMC_REG_MSCTRL_2P_IN_ORDER_MASK	(3 << 16)
+#define FIMC_REG_MSCTRL_2P_IN_ORDER_SHIFT	16
+#define FIMC_REG_MSCTRL_C_INT_IN_3PLANE		(0 << 15)
+#define FIMC_REG_MSCTRL_C_INT_IN_2PLANE		(1 << 15)
+#define FIMC_REG_MSCTRL_C_INT_IN_MASK		(1 << 15)
+#define FIMC_REG_MSCTRL_FLIP_SHIFT		13
+#define FIMC_REG_MSCTRL_FLIP_MASK		(3 << 13)
+#define FIMC_REG_MSCTRL_FLIP_NORMAL		(0 << 13)
+#define FIMC_REG_MSCTRL_FLIP_X_MIRROR		(1 << 13)
+#define FIMC_REG_MSCTRL_FLIP_Y_MIRROR		(2 << 13)
+#define FIMC_REG_MSCTRL_FLIP_180		(3 << 13)
+#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL		(1 << 12)
+#define FIMC_REG_MSCTRL_ORDER422_SHIFT		4
+#define FIMC_REG_MSCTRL_ORDER422_YCBYCR		(0 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_CBYCRY		(1 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_YCRYCB		(2 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_CRYCBY		(3 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_MASK		(3 << 4)
+#define FIMC_REG_MSCTRL_INPUT_EXTCAM		(0 << 3)
+#define FIMC_REG_MSCTRL_INPUT_MEMORY		(1 << 3)
+#define FIMC_REG_MSCTRL_INPUT_MASK		(1 << 3)
+#define FIMC_REG_MSCTRL_INFORMAT_YCBCR420	(0 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422	(1 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P	(2 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_RGB		(3 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_MASK		(3 << 1)
+#define FIMC_REG_MSCTRL_ENVID			(1 << 0)
+#define FIMC_REG_MSCTRL_IN_BURST_COUNT(x)	((x) << 24)
+
+/* Output DMA Y/Cb/Cr offset */
+#define FIMC_REG_CIOYOFF			0x168
+#define FIMC_REG_CIOCBOFF			0x16c
+#define FIMC_REG_CIOCROFF			0x170
+
+/* Input DMA Y/Cb/Cr offset */
+#define FIMC_REG_CIIYOFF			0x174
+#define FIMC_REG_CIICBOFF			0x178
+#define FIMC_REG_CIICROFF			0x17c
+
+/* Input DMA original image size */
+#define FIMC_REG_ORGISIZE			0x180
+
+/* Output DMA original image size */
+#define FIMC_REG_ORGOSIZE			0x184
+
+/* Real output DMA image size (extension register) */
+#define FIMC_REG_CIEXTEN			0x188
+#define FIMC_REG_CIEXTEN_MHRATIO_EXT(x)		(((x) & 0x3f) << 10)
+#define FIMC_REG_CIEXTEN_MVRATIO_EXT(x)		((x) & 0x3f)
+#define FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK	(0x3f << 10)
+#define FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK	0x3f
+
+#define FIMC_REG_CIDMAPARAM			0x18c
+#define FIMC_REG_CIDMAPARAM_R_LINEAR		(0 << 29)
+#define FIMC_REG_CIDMAPARAM_R_64X32		(3 << 29)
+#define FIMC_REG_CIDMAPARAM_W_LINEAR		(0 << 13)
+#define FIMC_REG_CIDMAPARAM_W_64X32		(3 << 13)
+#define FIMC_REG_CIDMAPARAM_TILE_MASK		((3 << 29) | (3 << 13))
+
+/* MIPI CSI image format */
+#define FIMC_REG_CSIIMGFMT			0x194
+#define FIMC_REG_CSIIMGFMT_YCBCR422_8BIT	0x1e
+#define FIMC_REG_CSIIMGFMT_RAW8			0x2a
+#define FIMC_REG_CSIIMGFMT_RAW10		0x2b
+#define FIMC_REG_CSIIMGFMT_RAW12		0x2c
+/* User defined formats. x = 0...16. */
+#define FIMC_REG_CSIIMGFMT_USER(x)		(0x30 + x - 1)
+
+/* Output frame buffer sequence mask */
+#define FIMC_REG_CIFCNTSEQ			0x1fc
+
+/*
+ * Function declarations
+ */
+void fimc_hw_reset(struct fimc_dev *fimc);
+void fimc_hw_set_rotation(struct fimc_ctx *ctx);
+void fimc_hw_set_target_format(struct fimc_ctx *ctx);
+void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
+void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
+void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
+void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
+void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
+void fimc_hw_en_capture(struct fimc_ctx *ctx);
+void fimc_hw_set_effect(struct fimc_ctx *ctx);
+void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
+void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
+void fimc_hw_set_input_path(struct fimc_ctx *ctx);
+void fimc_hw_set_output_path(struct fimc_ctx *ctx);
+void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
+void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
+			     int index);
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+			      struct s5p_fimc_isp_info *cam);
+void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+				struct s5p_fimc_isp_info *cam);
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+			    struct s5p_fimc_isp_info *cam);
+void fimc_hw_clear_irq(struct fimc_dev *dev);
+void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on);
+void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on);
+void fimc_hw_dis_capture(struct fimc_dev *dev);
+u32 fimc_hw_get_frame_index(struct fimc_dev *dev);
+void fimc_activate_capture(struct fimc_ctx *ctx);
+void fimc_deactivate_capture(struct fimc_dev *fimc);
+
+/**
+ * fimc_hw_set_dma_seq - configure output DMA buffer sequence
+ * @mask: bitmask for the DMA output buffer registers, set to 0 to skip buffer
+ * This function masks output DMA ring buffers, it allows to select which of
+ * the 32 available output buffer address registers will be used by the DMA
+ * engine.
+ */
+static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask)
+{
+	writel(mask, dev->regs + FIMC_REG_CIFCNTSEQ);
+}
+
+#endif /* FIMC_REG_H_ */
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c
index f44f690..2f73d9e 100644
--- a/drivers/media/video/s5p-fimc/mipi-csis.c
+++ b/drivers/media/video/s5p-fimc/mipi-csis.c
@@ -127,20 +127,24 @@
  *                       multiple of 2^pix_width_alignment
  * @code: corresponding media bus code
  * @fmt_reg: S5PCSIS_CONFIG register value
+ * @data_alignment: MIPI-CSI data alignment in bits
  */
 struct csis_pix_format {
 	unsigned int pix_width_alignment;
 	enum v4l2_mbus_pixelcode code;
 	u32 fmt_reg;
+	u8 data_alignment;
 };
 
 static const struct csis_pix_format s5pcsis_formats[] = {
 	{
 		.code = V4L2_MBUS_FMT_VYUY8_2X8,
 		.fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
+		.data_alignment = 32,
 	}, {
 		.code = V4L2_MBUS_FMT_JPEG_1X8,
 		.fmt_reg = S5PCSIS_CFG_FMT_USER(1),
+		.data_alignment = 32,
 	},
 };
 
@@ -239,7 +243,7 @@
 	s5pcsis_set_hsync_settle(state, pdata->hs_settle);
 
 	val = s5pcsis_read(state, S5PCSIS_CTRL);
-	if (pdata->alignment == 32)
+	if (state->csis_fmt->data_alignment == 32)
 		val |= S5PCSIS_CTRL_ALIGN_32BIT;
 	else /* 24-bits */
 		val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
@@ -711,19 +715,8 @@
 	},
 };
 
-static int __init s5pcsis_init(void)
-{
-	return platform_driver_probe(&s5pcsis_driver, s5pcsis_probe);
-}
-
-static void __exit s5pcsis_exit(void)
-{
-	platform_driver_unregister(&s5pcsis_driver);
-}
-
-module_init(s5pcsis_init);
-module_exit(s5pcsis_exit);
+module_platform_driver(s5pcsis_driver);
 
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-MODULE_DESCRIPTION("S5P/EXYNOS4 MIPI CSI receiver driver");
+MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC MIPI-CSI2 receiver driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h
deleted file mode 100644
index c7a5bc5..0000000
--- a/drivers/media/video/s5p-fimc/regs-fimc.h
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Register definition file for Samsung Camera Interface (FIMC) driver
- *
- * Copyright (c) 2010 Samsung Electronics
- *
- * 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 REGS_FIMC_H_
-#define REGS_FIMC_H_
-
-/* Input source format */
-#define S5P_CISRCFMT			0x00
-#define S5P_CISRCFMT_ITU601_8BIT	(1 << 31)
-#define S5P_CISRCFMT_ITU601_16BIT	(1 << 29)
-#define S5P_CISRCFMT_ORDER422_YCBYCR	(0 << 14)
-#define S5P_CISRCFMT_ORDER422_YCRYCB	(1 << 14)
-#define S5P_CISRCFMT_ORDER422_CBYCRY	(2 << 14)
-#define S5P_CISRCFMT_ORDER422_CRYCBY	(3 << 14)
-#define S5P_CISRCFMT_HSIZE(x)		((x) << 16)
-#define S5P_CISRCFMT_VSIZE(x)		((x) << 0)
-
-/* Window offset */
-#define S5P_CIWDOFST			0x04
-#define S5P_CIWDOFST_OFF_EN		(1 << 31)
-#define S5P_CIWDOFST_CLROVFIY		(1 << 30)
-#define S5P_CIWDOFST_CLROVRLB		(1 << 29)
-#define S5P_CIWDOFST_HOROFF_MASK	(0x7ff << 16)
-#define S5P_CIWDOFST_CLROVFICB		(1 << 15)
-#define S5P_CIWDOFST_CLROVFICR		(1 << 14)
-#define S5P_CIWDOFST_HOROFF(x)		((x) << 16)
-#define S5P_CIWDOFST_VEROFF(x)		((x) << 0)
-#define S5P_CIWDOFST_VEROFF_MASK	(0xfff << 0)
-
-/* Global control */
-#define S5P_CIGCTRL			0x08
-#define S5P_CIGCTRL_SWRST		(1 << 31)
-#define S5P_CIGCTRL_CAMRST_A		(1 << 30)
-#define S5P_CIGCTRL_SELCAM_ITU_A	(1 << 29)
-#define S5P_CIGCTRL_TESTPAT_NORMAL	(0 << 27)
-#define S5P_CIGCTRL_TESTPAT_COLOR_BAR	(1 << 27)
-#define S5P_CIGCTRL_TESTPAT_HOR_INC	(2 << 27)
-#define S5P_CIGCTRL_TESTPAT_VER_INC	(3 << 27)
-#define S5P_CIGCTRL_TESTPAT_MASK	(3 << 27)
-#define S5P_CIGCTRL_TESTPAT_SHIFT	(27)
-#define S5P_CIGCTRL_INVPOLPCLK		(1 << 26)
-#define S5P_CIGCTRL_INVPOLVSYNC		(1 << 25)
-#define S5P_CIGCTRL_INVPOLHREF		(1 << 24)
-#define S5P_CIGCTRL_IRQ_OVFEN		(1 << 22)
-#define S5P_CIGCTRL_HREF_MASK		(1 << 21)
-#define S5P_CIGCTRL_IRQ_LEVEL		(1 << 20)
-#define S5P_CIGCTRL_IRQ_CLR		(1 << 19)
-#define S5P_CIGCTRL_IRQ_ENABLE		(1 << 16)
-#define S5P_CIGCTRL_SHDW_DISABLE	(1 << 12)
-#define S5P_CIGCTRL_CAM_JPEG		(1 << 8)
-#define S5P_CIGCTRL_SELCAM_MIPI_A	(1 << 7)
-#define S5P_CIGCTRL_CAMIF_SELWB		(1 << 6)
-/* 0 - ITU601; 1 - ITU709 */
-#define S5P_CIGCTRL_CSC_ITU601_709	(1 << 5)
-#define S5P_CIGCTRL_INVPOLHSYNC		(1 << 4)
-#define S5P_CIGCTRL_SELCAM_MIPI		(1 << 3)
-#define S5P_CIGCTRL_INVPOLFIELD		(1 << 1)
-#define S5P_CIGCTRL_INTERLACE		(1 << 0)
-
-/* Window offset 2 */
-#define S5P_CIWDOFST2			0x14
-#define S5P_CIWDOFST2_HOROFF_MASK	(0xfff << 16)
-#define S5P_CIWDOFST2_VEROFF_MASK	(0xfff << 0)
-#define S5P_CIWDOFST2_HOROFF(x)		((x) << 16)
-#define S5P_CIWDOFST2_VEROFF(x)		((x) << 0)
-
-/* Output DMA Y/Cb/Cr plane start addresses */
-#define S5P_CIOYSA(n)			(0x18 + (n) * 4)
-#define S5P_CIOCBSA(n)			(0x28 + (n) * 4)
-#define S5P_CIOCRSA(n)			(0x38 + (n) * 4)
-
-/* Target image format */
-#define S5P_CITRGFMT			0x48
-#define S5P_CITRGFMT_INROT90		(1 << 31)
-#define S5P_CITRGFMT_YCBCR420		(0 << 29)
-#define S5P_CITRGFMT_YCBCR422		(1 << 29)
-#define S5P_CITRGFMT_YCBCR422_1P	(2 << 29)
-#define S5P_CITRGFMT_RGB		(3 << 29)
-#define S5P_CITRGFMT_FMT_MASK		(3 << 29)
-#define S5P_CITRGFMT_HSIZE_MASK		(0xfff << 16)
-#define S5P_CITRGFMT_FLIP_SHIFT		(14)
-#define S5P_CITRGFMT_FLIP_NORMAL	(0 << 14)
-#define S5P_CITRGFMT_FLIP_X_MIRROR	(1 << 14)
-#define S5P_CITRGFMT_FLIP_Y_MIRROR	(2 << 14)
-#define S5P_CITRGFMT_FLIP_180		(3 << 14)
-#define S5P_CITRGFMT_FLIP_MASK		(3 << 14)
-#define S5P_CITRGFMT_OUTROT90		(1 << 13)
-#define S5P_CITRGFMT_VSIZE_MASK		(0xfff << 0)
-#define S5P_CITRGFMT_HSIZE(x)		((x) << 16)
-#define S5P_CITRGFMT_VSIZE(x)		((x) << 0)
-
-/* Output DMA control */
-#define S5P_CIOCTRL			0x4c
-#define S5P_CIOCTRL_ORDER422_MASK	(3 << 0)
-#define S5P_CIOCTRL_ORDER422_CRYCBY	(0 << 0)
-#define S5P_CIOCTRL_ORDER422_CBYCRY	(1 << 0)
-#define S5P_CIOCTRL_ORDER422_YCRYCB	(2 << 0)
-#define S5P_CIOCTRL_ORDER422_YCBYCR	(3 << 0)
-#define S5P_CIOCTRL_LASTIRQ_ENABLE	(1 << 2)
-#define S5P_CIOCTRL_YCBCR_3PLANE	(0 << 3)
-#define S5P_CIOCTRL_YCBCR_2PLANE	(1 << 3)
-#define S5P_CIOCTRL_YCBCR_PLANE_MASK	(1 << 3)
-#define S5P_CIOCTRL_ALPHA_OUT_MASK	(0xff << 4)
-#define S5P_CIOCTRL_RGB16FMT_MASK	(3 << 16)
-#define S5P_CIOCTRL_RGB565		(0 << 16)
-#define S5P_CIOCTRL_ARGB1555		(1 << 16)
-#define S5P_CIOCTRL_ARGB4444		(2 << 16)
-#define S5P_CIOCTRL_ORDER2P_SHIFT	(24)
-#define S5P_CIOCTRL_ORDER2P_MASK	(3 << 24)
-#define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24)
-
-/* Pre-scaler control 1 */
-#define S5P_CISCPRERATIO		0x50
-#define S5P_CISCPRERATIO_SHFACTOR(x)	((x) << 28)
-#define S5P_CISCPRERATIO_HOR(x)		((x) << 16)
-#define S5P_CISCPRERATIO_VER(x)		((x) << 0)
-
-#define S5P_CISCPREDST			0x54
-#define S5P_CISCPREDST_WIDTH(x)		((x) << 16)
-#define S5P_CISCPREDST_HEIGHT(x)	((x) << 0)
-
-/* Main scaler control */
-#define S5P_CISCCTRL			0x58
-#define S5P_CISCCTRL_SCALERBYPASS	(1 << 31)
-#define S5P_CISCCTRL_SCALEUP_H		(1 << 30)
-#define S5P_CISCCTRL_SCALEUP_V		(1 << 29)
-#define S5P_CISCCTRL_CSCR2Y_WIDE	(1 << 28)
-#define S5P_CISCCTRL_CSCY2R_WIDE	(1 << 27)
-#define S5P_CISCCTRL_LCDPATHEN_FIFO	(1 << 26)
-#define S5P_CISCCTRL_INTERLACE		(1 << 25)
-#define S5P_CISCCTRL_SCALERSTART	(1 << 15)
-#define S5P_CISCCTRL_INRGB_FMT_RGB565	(0 << 13)
-#define S5P_CISCCTRL_INRGB_FMT_RGB666	(1 << 13)
-#define S5P_CISCCTRL_INRGB_FMT_RGB888	(2 << 13)
-#define S5P_CISCCTRL_INRGB_FMT_MASK	(3 << 13)
-#define S5P_CISCCTRL_OUTRGB_FMT_RGB565	(0 << 11)
-#define S5P_CISCCTRL_OUTRGB_FMT_RGB666	(1 << 11)
-#define S5P_CISCCTRL_OUTRGB_FMT_RGB888	(2 << 11)
-#define S5P_CISCCTRL_OUTRGB_FMT_MASK	(3 << 11)
-#define S5P_CISCCTRL_RGB_EXT		(1 << 10)
-#define S5P_CISCCTRL_ONE2ONE		(1 << 9)
-#define S5P_CISCCTRL_MHRATIO(x)		((x) << 16)
-#define S5P_CISCCTRL_MVRATIO(x)		((x) << 0)
-#define S5P_CISCCTRL_MHRATIO_MASK	(0x1ff << 16)
-#define S5P_CISCCTRL_MVRATIO_MASK	(0x1ff << 0)
-#define S5P_CISCCTRL_MHRATIO_EXT(x)	(((x) >> 6) << 16)
-#define S5P_CISCCTRL_MVRATIO_EXT(x)	(((x) >> 6) << 0)
-
-/* Target area */
-#define S5P_CITAREA			0x5c
-#define S5P_CITAREA_MASK		0x0fffffff
-
-/* General status */
-#define S5P_CISTATUS			0x64
-#define S5P_CISTATUS_OVFIY		(1 << 31)
-#define S5P_CISTATUS_OVFICB		(1 << 30)
-#define S5P_CISTATUS_OVFICR		(1 << 29)
-#define S5P_CISTATUS_VSYNC		(1 << 28)
-#define S5P_CISTATUS_FRAMECNT_MASK	(3 << 26)
-#define S5P_CISTATUS_FRAMECNT_SHIFT	26
-#define S5P_CISTATUS_WINOFF_EN		(1 << 25)
-#define S5P_CISTATUS_IMGCPT_EN		(1 << 22)
-#define S5P_CISTATUS_IMGCPT_SCEN	(1 << 21)
-#define S5P_CISTATUS_VSYNC_A		(1 << 20)
-#define S5P_CISTATUS_VSYNC_B		(1 << 19)
-#define S5P_CISTATUS_OVRLB		(1 << 18)
-#define S5P_CISTATUS_FRAME_END		(1 << 17)
-#define S5P_CISTATUS_LASTCAPT_END	(1 << 16)
-#define S5P_CISTATUS_VVALID_A		(1 << 15)
-#define S5P_CISTATUS_VVALID_B		(1 << 14)
-
-/* Indexes to the last and the currently processed buffer. */
-#define S5P_CISTATUS2			0x68
-
-/* Image capture control */
-#define S5P_CIIMGCPT			0xc0
-#define S5P_CIIMGCPT_IMGCPTEN		(1 << 31)
-#define S5P_CIIMGCPT_IMGCPTEN_SC	(1 << 30)
-#define S5P_CIIMGCPT_CPT_FREN_ENABLE	(1 << 25)
-#define S5P_CIIMGCPT_CPT_FRMOD_CNT	(1 << 18)
-
-/* Frame capture sequence */
-#define S5P_CICPTSEQ			0xc4
-
-/* Image effect */
-#define S5P_CIIMGEFF			0xd0
-#define S5P_CIIMGEFF_IE_ENABLE		(1 << 30)
-#define S5P_CIIMGEFF_IE_SC_BEFORE	(0 << 29)
-#define S5P_CIIMGEFF_IE_SC_AFTER	(1 << 29)
-#define S5P_CIIMGEFF_FIN_BYPASS		(0 << 26)
-#define S5P_CIIMGEFF_FIN_ARBITRARY	(1 << 26)
-#define S5P_CIIMGEFF_FIN_NEGATIVE	(2 << 26)
-#define S5P_CIIMGEFF_FIN_ARTFREEZE	(3 << 26)
-#define S5P_CIIMGEFF_FIN_EMBOSSING	(4 << 26)
-#define S5P_CIIMGEFF_FIN_SILHOUETTE	(5 << 26)
-#define S5P_CIIMGEFF_FIN_MASK		(7 << 26)
-#define S5P_CIIMGEFF_PAT_CBCR_MASK	((0xff < 13) | (0xff < 0))
-#define S5P_CIIMGEFF_PAT_CB(x)		((x) << 13)
-#define S5P_CIIMGEFF_PAT_CR(x)		((x) << 0)
-
-/* Input DMA Y/Cb/Cr plane start address 0/1 */
-#define S5P_CIIYSA(n)			(0xd4 + (n) * 0x70)
-#define S5P_CIICBSA(n)			(0xd8 + (n) * 0x70)
-#define S5P_CIICRSA(n)			(0xdc + (n) * 0x70)
-
-/* Real input DMA image size */
-#define S5P_CIREAL_ISIZE		0xf8
-#define S5P_CIREAL_ISIZE_AUTOLOAD_EN	(1 << 31)
-#define S5P_CIREAL_ISIZE_ADDR_CH_DIS	(1 << 30)
-#define S5P_CIREAL_ISIZE_HEIGHT(x)	((x) << 16)
-#define S5P_CIREAL_ISIZE_WIDTH(x)	((x) << 0)
-
-
-/* Input DMA control */
-#define S5P_MSCTRL			0xfc
-#define S5P_MSCTRL_IN_BURST_COUNT_MASK	(0xF << 24)
-#define S5P_MSCTRL_2P_IN_ORDER_MASK	(3 << 16)
-#define S5P_MSCTRL_2P_IN_ORDER_SHIFT	16
-#define S5P_MSCTRL_C_INT_IN_3PLANE	(0 << 15)
-#define S5P_MSCTRL_C_INT_IN_2PLANE	(1 << 15)
-#define S5P_MSCTRL_C_INT_IN_MASK	(1 << 15)
-#define S5P_MSCTRL_FLIP_SHIFT		13
-#define S5P_MSCTRL_FLIP_MASK		(3 << 13)
-#define S5P_MSCTRL_FLIP_NORMAL		(0 << 13)
-#define S5P_MSCTRL_FLIP_X_MIRROR	(1 << 13)
-#define S5P_MSCTRL_FLIP_Y_MIRROR	(2 << 13)
-#define S5P_MSCTRL_FLIP_180		(3 << 13)
-#define S5P_MSCTRL_FIFO_CTRL_FULL	(1 << 12)
-#define S5P_MSCTRL_ORDER422_SHIFT	4
-#define S5P_MSCTRL_ORDER422_YCBYCR	(0 << 4)
-#define S5P_MSCTRL_ORDER422_CBYCRY	(1 << 4)
-#define S5P_MSCTRL_ORDER422_YCRYCB	(2 << 4)
-#define S5P_MSCTRL_ORDER422_CRYCBY	(3 << 4)
-#define S5P_MSCTRL_ORDER422_MASK	(3 << 4)
-#define S5P_MSCTRL_INPUT_EXTCAM		(0 << 3)
-#define S5P_MSCTRL_INPUT_MEMORY		(1 << 3)
-#define S5P_MSCTRL_INPUT_MASK		(1 << 3)
-#define S5P_MSCTRL_INFORMAT_YCBCR420	(0 << 1)
-#define S5P_MSCTRL_INFORMAT_YCBCR422	(1 << 1)
-#define S5P_MSCTRL_INFORMAT_YCBCR422_1P	(2 << 1)
-#define S5P_MSCTRL_INFORMAT_RGB		(3 << 1)
-#define S5P_MSCTRL_INFORMAT_MASK	(3 << 1)
-#define S5P_MSCTRL_ENVID		(1 << 0)
-#define S5P_MSCTRL_IN_BURST_COUNT(x)	((x) << 24)
-
-/* Output DMA Y/Cb/Cr offset */
-#define S5P_CIOYOFF			0x168
-#define S5P_CIOCBOFF			0x16c
-#define S5P_CIOCROFF			0x170
-
-/* Input DMA Y/Cb/Cr offset */
-#define S5P_CIIYOFF			0x174
-#define S5P_CIICBOFF			0x178
-#define S5P_CIICROFF			0x17c
-
-#define S5P_CIO_OFFS_VER(x)		((x) << 16)
-#define S5P_CIO_OFFS_HOR(x)		((x) << 0)
-
-/* Input DMA original image size */
-#define S5P_ORGISIZE			0x180
-
-/* Output DMA original image size */
-#define S5P_ORGOSIZE			0x184
-
-#define S5P_ORIG_SIZE_VER(x)		((x) << 16)
-#define S5P_ORIG_SIZE_HOR(x)		((x) << 0)
-
-/* Real output DMA image size (extension register) */
-#define S5P_CIEXTEN			0x188
-#define S5P_CIEXTEN_MHRATIO_EXT(x)	(((x) & 0x3f) << 10)
-#define S5P_CIEXTEN_MVRATIO_EXT(x)	((x) & 0x3f)
-#define S5P_CIEXTEN_MHRATIO_EXT_MASK	(0x3f << 10)
-#define S5P_CIEXTEN_MVRATIO_EXT_MASK	0x3f
-
-#define S5P_CIDMAPARAM			0x18c
-#define S5P_CIDMAPARAM_R_LINEAR		(0 << 29)
-#define S5P_CIDMAPARAM_R_64X32		(3 << 29)
-#define S5P_CIDMAPARAM_W_LINEAR		(0 << 13)
-#define S5P_CIDMAPARAM_W_64X32		(3 << 13)
-#define S5P_CIDMAPARAM_TILE_MASK	((3 << 29) | (3 << 13))
-
-/* MIPI CSI image format */
-#define S5P_CSIIMGFMT			0x194
-#define S5P_CSIIMGFMT_YCBCR422_8BIT	0x1e
-#define S5P_CSIIMGFMT_RAW8		0x2a
-#define S5P_CSIIMGFMT_RAW10		0x2b
-#define S5P_CSIIMGFMT_RAW12		0x2c
-/* User defined formats. x = 0...16. */
-#define S5P_CSIIMGFMT_USER(x)		(0x30 + x - 1)
-
-/* Output frame buffer sequence mask */
-#define S5P_CIFCNTSEQ			0x1FC
-
-#endif /* REGS_FIMC_H_ */
diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c
index 789de74..7c98ee7 100644
--- a/drivers/media/video/s5p-g2d/g2d.c
+++ b/drivers/media/video/s5p-g2d/g2d.c
@@ -65,7 +65,7 @@
 };
 #define NUM_FORMATS ARRAY_SIZE(formats)
 
-struct g2d_frame def_frame = {
+static struct g2d_frame def_frame = {
 	.width		= DEFAULT_WIDTH,
 	.height		= DEFAULT_HEIGHT,
 	.c_width	= DEFAULT_WIDTH,
@@ -77,7 +77,7 @@
 	.bottom		= DEFAULT_HEIGHT,
 };
 
-struct g2d_fmt *find_fmt(struct v4l2_format *f)
+static struct g2d_fmt *find_fmt(struct v4l2_format *f)
 {
 	unsigned int i;
 	for (i = 0; i < NUM_FORMATS; i++) {
@@ -202,7 +202,7 @@
 	.s_ctrl		= g2d_s_ctrl,
 };
 
-int g2d_setup_ctrls(struct g2d_ctx *ctx)
+static int g2d_setup_ctrls(struct g2d_ctx *ctx)
 {
 	struct g2d_dev *dev = ctx->dev;
 
@@ -546,11 +546,11 @@
 	struct g2d_dev *dev = ctx->dev;
 	int ret;
 
-	if (dev->curr == 0) /* No job currently running */
+	if (dev->curr == NULL) /* No job currently running */
 		return;
 
 	ret = wait_event_timeout(dev->irq_queue,
-		dev->curr == 0,
+		dev->curr == NULL,
 		msecs_to_jiffies(G2D_TIMEOUT));
 }
 
@@ -599,19 +599,19 @@
 	g2d_clear_int(dev);
 	clk_disable(dev->gate);
 
-	BUG_ON(ctx == 0);
+	BUG_ON(ctx == NULL);
 
 	src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
 	dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
 
-	BUG_ON(src == 0);
-	BUG_ON(dst == 0);
+	BUG_ON(src == NULL);
+	BUG_ON(dst == NULL);
 
 	v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
 	v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
 	v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
 
-	dev->curr = 0;
+	dev->curr = NULL;
 	wake_up(&dev->irq_queue);
 	return IRQ_HANDLED;
 }
@@ -674,42 +674,27 @@
 	struct resource *res;
 	int ret = 0;
 
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 		return -ENOMEM;
+
 	spin_lock_init(&dev->ctrl_lock);
 	mutex_init(&dev->mutex);
 	atomic_set(&dev->num_inst, 0);
 	init_waitqueue_head(&dev->irq_queue);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "failed to find registers\n");
-		ret = -ENOENT;
-		goto free_dev;
-	}
 
-	dev->res_regs = request_mem_region(res->start, resource_size(res),
-						dev_name(&pdev->dev));
-
-	if (!dev->res_regs) {
-		dev_err(&pdev->dev, "failed to obtain register region\n");
-		ret = -ENOENT;
-		goto free_dev;
-	}
-
-	dev->regs = ioremap(res->start, resource_size(res));
-	if (!dev->regs) {
-		dev_err(&pdev->dev, "failed to map registers\n");
-		ret = -ENOENT;
-		goto rel_res_regs;
+	dev->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (dev->regs == NULL) {
+			dev_err(&pdev->dev, "Failed to obtain io memory\n");
+			return -ENOENT;
 	}
 
 	dev->clk = clk_get(&pdev->dev, "sclk_fimg2d");
 	if (IS_ERR_OR_NULL(dev->clk)) {
 		dev_err(&pdev->dev, "failed to get g2d clock\n");
-		ret = -ENXIO;
-		goto unmap_regs;
+		return -ENXIO;
 	}
 
 	ret = clk_prepare(dev->clk);
@@ -740,7 +725,8 @@
 
 	dev->irq = res->start;
 
-	ret = request_irq(dev->irq, g2d_isr, 0, pdev->name, dev);
+	ret = devm_request_irq(&pdev->dev, dev->irq, g2d_isr,
+						0, pdev->name, dev);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to install IRQ\n");
 		goto put_clk_gate;
@@ -749,7 +735,7 @@
 	dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
 	if (IS_ERR(dev->alloc_ctx)) {
 		ret = PTR_ERR(dev->alloc_ctx);
-		goto rel_irq;
+		goto unprep_clk_gate;
 	}
 
 	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
@@ -762,6 +748,10 @@
 		goto unreg_v4l2_dev;
 	}
 	*vfd = g2d_videodev;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 	vfd->lock = &dev->mutex;
 	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
 	if (ret) {
@@ -793,8 +783,6 @@
 	v4l2_device_unregister(&dev->v4l2_dev);
 alloc_ctx_cleanup:
 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
-rel_irq:
-	free_irq(dev->irq, dev);
 unprep_clk_gate:
 	clk_unprepare(dev->gate);
 put_clk_gate:
@@ -803,12 +791,7 @@
 	clk_unprepare(dev->clk);
 put_clk:
 	clk_put(dev->clk);
-unmap_regs:
-	iounmap(dev->regs);
-rel_res_regs:
-	release_resource(dev->res_regs);
-free_dev:
-	kfree(dev);
+
 	return ret;
 }
 
@@ -821,14 +804,10 @@
 	video_unregister_device(dev->vfd);
 	v4l2_device_unregister(&dev->v4l2_dev);
 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
-	free_irq(dev->irq, dev);
 	clk_unprepare(dev->gate);
 	clk_put(dev->gate);
 	clk_unprepare(dev->clk);
 	clk_put(dev->clk);
-	iounmap(dev->regs);
-	release_resource(dev->res_regs);
-	kfree(dev);
 	return 0;
 }
 
diff --git a/drivers/media/video/s5p-g2d/g2d.h b/drivers/media/video/s5p-g2d/g2d.h
index 1b82065..6b765b0 100644
--- a/drivers/media/video/s5p-g2d/g2d.h
+++ b/drivers/media/video/s5p-g2d/g2d.h
@@ -23,7 +23,6 @@
 	spinlock_t		ctrl_lock;
 	atomic_t		num_inst;
 	struct vb2_alloc_ctx	*alloc_ctx;
-	struct resource		*res_regs;
 	void __iomem		*regs;
 	struct clk		*clk;
 	struct clk		*gate;
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c
index 5a49c30..28b5225d 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.c
@@ -813,7 +813,7 @@
 	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
 }
 
-int s5p_jpeg_g_selection(struct file *file, void *priv,
+static int s5p_jpeg_g_selection(struct file *file, void *priv,
 			 struct v4l2_selection *s)
 {
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
@@ -1290,7 +1290,7 @@
 	int ret;
 
 	/* JPEG IP abstraction struct */
-	jpeg = kzalloc(sizeof(struct s5p_jpeg), GFP_KERNEL);
+	jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
 	if (!jpeg)
 		return -ENOMEM;
 
@@ -1300,43 +1300,25 @@
 
 	/* memory-mapped registers */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "cannot find IO resource\n");
-		ret = -ENOENT;
-		goto jpeg_alloc_rollback;
-	}
 
-	jpeg->ioarea = request_mem_region(res->start, resource_size(res),
-					  pdev->name);
-	if (!jpeg->ioarea) {
-		dev_err(&pdev->dev, "cannot request IO\n");
-		ret = -ENXIO;
-		goto jpeg_alloc_rollback;
+	jpeg->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (jpeg->regs == NULL) {
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENOENT;
 	}
 
-	jpeg->regs = ioremap(res->start, resource_size(res));
-	if (!jpeg->regs) {
-		dev_err(&pdev->dev, "cannot map IO\n");
-		ret = -ENXIO;
-		goto mem_region_rollback;
-	}
-
-	dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
-		jpeg->regs, jpeg->ioarea, res);
-
 	/* interrupt service routine registration */
 	jpeg->irq = ret = platform_get_irq(pdev, 0);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "cannot find IRQ\n");
-		goto ioremap_rollback;
+		return ret;
 	}
 
-	ret = request_irq(jpeg->irq, s5p_jpeg_irq, 0,
-			  dev_name(&pdev->dev), jpeg);
-
+	ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0,
+			dev_name(&pdev->dev), jpeg);
 	if (ret) {
 		dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
-		goto ioremap_rollback;
+		return ret;
 	}
 
 	/* clocks */
@@ -1344,7 +1326,7 @@
 	if (IS_ERR(jpeg->clk)) {
 		dev_err(&pdev->dev, "cannot get clock\n");
 		ret = PTR_ERR(jpeg->clk);
-		goto request_irq_rollback;
+		return ret;
 	}
 	dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
 	clk_enable(jpeg->clk);
@@ -1386,6 +1368,10 @@
 	jpeg->vfd_encoder->release	= video_device_release;
 	jpeg->vfd_encoder->lock		= &jpeg->lock;
 	jpeg->vfd_encoder->v4l2_dev	= &jpeg->v4l2_dev;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &jpeg->vfd_encoder->flags);
 
 	ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
 	if (ret) {
@@ -1413,6 +1399,10 @@
 	jpeg->vfd_decoder->release	= video_device_release;
 	jpeg->vfd_decoder->lock		= &jpeg->lock;
 	jpeg->vfd_decoder->v4l2_dev	= &jpeg->v4l2_dev;
+	/* Locking in file operations other than ioctl should be done by the driver,
+	   not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &jpeg->vfd_decoder->flags);
 
 	ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
 	if (ret) {
@@ -1456,18 +1446,6 @@
 	clk_disable(jpeg->clk);
 	clk_put(jpeg->clk);
 
-request_irq_rollback:
-	free_irq(jpeg->irq, jpeg);
-
-ioremap_rollback:
-	iounmap(jpeg->regs);
-
-mem_region_rollback:
-	release_resource(jpeg->ioarea);
-	release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
-
-jpeg_alloc_rollback:
-	kfree(jpeg);
 	return ret;
 }
 
@@ -1488,14 +1466,6 @@
 	clk_disable(jpeg->clk);
 	clk_put(jpeg->clk);
 
-	free_irq(jpeg->irq, jpeg);
-
-	iounmap(jpeg->regs);
-
-	release_resource(jpeg->ioarea);
-	release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
-	kfree(jpeg);
-
 	return 0;
 }
 
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h
index 38d7367..9d0cd2b 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.h
@@ -54,7 +54,6 @@
  * @vfd_encoder:	video device node for encoder mem2mem mode
  * @vfd_decoder:	video device node for decoder mem2mem mode
  * @m2m_dev:		v4l2 mem2mem device data
- * @ioarea:		JPEG IP memory region
  * @regs:		JPEG IP registers mapping
  * @irq:		JPEG IP irq
  * @clk:		JPEG IP clock
@@ -70,7 +69,6 @@
 	struct video_device	*vfd_decoder;
 	struct v4l2_m2m_dev	*m2m_dev;
 
-	struct resource		*ioarea;
 	void __iomem		*regs;
 	unsigned int		irq;
 	struct clk		*clk;
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c
index 83fe461..9bb68e7 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc.c
@@ -70,7 +70,7 @@
 	wake_up(&dev->queue);
 }
 
-void s5p_mfc_watchdog(unsigned long arg)
+static void s5p_mfc_watchdog(unsigned long arg)
 {
 	struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
 
@@ -373,7 +373,7 @@
 
 	/* If no context is available then all necessary
 	 * processing has been done. */
-	if (ctx == 0)
+	if (ctx == NULL)
 		return;
 
 	dev = ctx->dev;
@@ -429,7 +429,7 @@
 	struct s5p_mfc_dev *dev;
 	unsigned int guard_width, guard_height;
 
-	if (ctx == 0)
+	if (ctx == NULL)
 		return;
 	dev = ctx->dev;
 	if (ctx->c_ops->post_seq_start) {
@@ -496,7 +496,7 @@
 	struct s5p_mfc_dev *dev;
 	unsigned long flags;
 
-	if (ctx == 0)
+	if (ctx == NULL)
 		return;
 	dev = ctx->dev;
 	s5p_mfc_clear_int_flags(dev);
@@ -772,7 +772,7 @@
 err_init_hw:
 	s5p_mfc_release_firmware(dev);
 err_alloc_fw:
-	dev->ctx[ctx->num] = 0;
+	dev->ctx[ctx->num] = NULL;
 	del_timer_sync(&dev->watchdog_timer);
 	s5p_mfc_clock_off();
 err_pwr_enable:
@@ -849,7 +849,7 @@
 	}
 	mfc_debug(2, "Shutting down clock\n");
 	s5p_mfc_clock_off();
-	dev->ctx[ctx->num] = 0;
+	dev->ctx[ctx->num] = NULL;
 	s5p_mfc_dec_ctrls_delete(ctx);
 	v4l2_fh_del(&ctx->fh);
 	v4l2_fh_exit(&ctx->fh);
@@ -948,7 +948,7 @@
 	int ret;
 
 	pr_debug("%s++\n", __func__);
-	dev = kzalloc(sizeof *dev, GFP_KERNEL);
+	dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
 	if (!dev) {
 		dev_err(&pdev->dev, "Not enough memory for MFC device\n");
 		return -ENOMEM;
@@ -959,49 +959,35 @@
 	dev->plat_dev = pdev;
 	if (!dev->plat_dev) {
 		dev_err(&pdev->dev, "No platform data specified\n");
-		ret = -ENODEV;
-		goto err_dev;
+		return -ENODEV;
 	}
 
 	ret = s5p_mfc_init_pm(dev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to get mfc clock source\n");
-		goto err_clk;
+		return ret;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "failed to get memory region resource\n");
-		ret = -ENOENT;
-		goto err_res;
-	}
 
-	dev->mfc_mem = request_mem_region(res->start, resource_size(res),
-					  pdev->name);
-	if (dev->mfc_mem == NULL) {
-		dev_err(&pdev->dev, "failed to get memory region\n");
-		ret = -ENOENT;
-		goto err_mem_reg;
-	}
-	dev->regs_base = ioremap(dev->mfc_mem->start, resource_size(dev->mfc_mem));
+	dev->regs_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (dev->regs_base == NULL) {
-		dev_err(&pdev->dev, "failed to ioremap address region\n");
-		ret = -ENOENT;
-		goto err_ioremap;
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENOENT;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (res == NULL) {
 		dev_err(&pdev->dev, "failed to get irq resource\n");
 		ret = -ENOENT;
-		goto err_get_res;
+		goto err_res;
 	}
 	dev->irq = res->start;
-	ret = request_irq(dev->irq, s5p_mfc_irq, IRQF_DISABLED, pdev->name,
-									dev);
+	ret = devm_request_irq(&pdev->dev, dev->irq, s5p_mfc_irq,
+					IRQF_DISABLED, pdev->name, dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
-		goto err_req_irq;
+		goto err_res;
 	}
 
 	dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l",
@@ -1009,20 +995,20 @@
 	if (!dev->mem_dev_l) {
 		mfc_err("Mem child (L) device get failed\n");
 		ret = -ENODEV;
-		goto err_find_child;
+		goto err_res;
 	}
 	dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r",
 					   match_child);
 	if (!dev->mem_dev_r) {
 		mfc_err("Mem child (R) device get failed\n");
 		ret = -ENODEV;
-		goto err_find_child;
+		goto err_res;
 	}
 
 	dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l);
 	if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) {
 		ret = PTR_ERR(dev->alloc_ctx[0]);
-		goto err_mem_init_ctx_0;
+		goto err_res;
 	}
 	dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r);
 	if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) {
@@ -1048,6 +1034,10 @@
 	vfd->ioctl_ops	= get_dec_v4l2_ioctl_ops();
 	vfd->release	= video_device_release,
 	vfd->lock	= &dev->mfc_mutex;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 	vfd->v4l2_dev	= &dev->v4l2_dev;
 	snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
 	dev->vfd_dec	= vfd;
@@ -1072,6 +1062,8 @@
 	vfd->ioctl_ops	= get_enc_v4l2_ioctl_ops();
 	vfd->release	= video_device_release,
 	vfd->lock	= &dev->mfc_mutex;
+	/* This should not be necessary */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 	vfd->v4l2_dev	= &dev->v4l2_dev;
 	snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
 	dev->vfd_enc	= vfd;
@@ -1110,22 +1102,9 @@
 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
 err_mem_init_ctx_1:
 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
-err_mem_init_ctx_0:
-err_find_child:
-	free_irq(dev->irq, dev);
-err_req_irq:
-err_get_res:
-	iounmap(dev->regs_base);
-	dev->regs_base = NULL;
-err_ioremap:
-	release_resource(dev->mfc_mem);
-	kfree(dev->mfc_mem);
-err_mem_reg:
 err_res:
 	s5p_mfc_final_pm(dev);
-err_clk:
-err_dev:
-	kfree(dev);
+
 	pr_debug("%s-- with error\n", __func__);
 	return ret;
 
@@ -1148,15 +1127,7 @@
 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
 
-	free_irq(dev->irq, dev);
-	iounmap(dev->regs_base);
-	if (dev->mfc_mem) {
-		release_resource(dev->mfc_mem);
-		kfree(dev->mfc_mem);
-		dev->mfc_mem = NULL;
-	}
 	s5p_mfc_final_pm(dev);
-	kfree(dev);
 	return 0;
 }
 
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_common.h b/drivers/media/video/s5p-mfc/s5p_mfc_common.h
index 91146fa..bd5706a 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_common.h
@@ -185,7 +185,6 @@
  * @mem_dev_r:		child device of the right memory bank (1)
  * @regs_base:		base address of the MFC hw registers
  * @irq:		irq resource
- * @mfc_mem:		MFC registers memory resource
  * @dec_ctrl_handler:	control framework handler for decoding
  * @enc_ctrl_handler:	control framework handler for encoding
  * @pm:			power management control
@@ -221,7 +220,6 @@
 	struct device		*mem_dev_r;
 	void __iomem		*regs_base;
 	int			irq;
-	struct resource		*mfc_mem;
 	struct v4l2_ctrl_handler dec_ctrl_handler;
 	struct v4l2_ctrl_handler enc_ctrl_handler;
 	struct s5p_mfc_pm	pm;
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
index f2481a8..08a5cfe 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
@@ -52,7 +52,7 @@
 	s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc(
 		dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size);
 	if (IS_ERR(s5p_mfc_bitproc_buf)) {
-		s5p_mfc_bitproc_buf = 0;
+		s5p_mfc_bitproc_buf = NULL;
 		mfc_err("Allocating bitprocessor buffer failed\n");
 		release_firmware(fw_blob);
 		return -ENOMEM;
@@ -63,7 +63,7 @@
 		mfc_err("The base memory for bank 1 is not aligned to 128KB\n");
 		vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
 		s5p_mfc_bitproc_phys = 0;
-		s5p_mfc_bitproc_buf = 0;
+		s5p_mfc_bitproc_buf = NULL;
 		release_firmware(fw_blob);
 		return -EIO;
 	}
@@ -72,7 +72,7 @@
 		mfc_err("Bitprocessor memory remap failed\n");
 		vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
 		s5p_mfc_bitproc_phys = 0;
-		s5p_mfc_bitproc_buf = 0;
+		s5p_mfc_bitproc_buf = NULL;
 		release_firmware(fw_blob);
 		return -EIO;
 	}
@@ -82,7 +82,7 @@
 	if (IS_ERR(b_base)) {
 		vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
 		s5p_mfc_bitproc_phys = 0;
-		s5p_mfc_bitproc_buf = 0;
+		s5p_mfc_bitproc_buf = NULL;
 		mfc_err("Allocating bank2 base failed\n");
 	release_firmware(fw_blob);
 		return -ENOMEM;
@@ -94,7 +94,7 @@
 		mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
 		vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
 		s5p_mfc_bitproc_phys = 0;
-		s5p_mfc_bitproc_buf = 0;
+		s5p_mfc_bitproc_buf = NULL;
 		release_firmware(fw_blob);
 		return -EIO;
 	}
@@ -126,7 +126,7 @@
 		release_firmware(fw_blob);
 		return -ENOMEM;
 	}
-	if (s5p_mfc_bitproc_buf == 0 || s5p_mfc_bitproc_phys == 0) {
+	if (s5p_mfc_bitproc_buf == NULL || s5p_mfc_bitproc_phys == 0) {
 		mfc_err("MFC firmware is not allocated or was not mapped correctly\n");
 		release_firmware(fw_blob);
 		return -EINVAL;
@@ -146,9 +146,9 @@
 	if (!s5p_mfc_bitproc_buf)
 		return -EINVAL;
 	vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
-	s5p_mfc_bitproc_virt =  0;
+	s5p_mfc_bitproc_virt = NULL;
 	s5p_mfc_bitproc_phys = 0;
-	s5p_mfc_bitproc_buf = 0;
+	s5p_mfc_bitproc_buf = NULL;
 	return 0;
 }
 
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
index dff9dc7..acedb20 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
@@ -1436,7 +1436,8 @@
 	.s_ctrl = s5p_mfc_enc_s_ctrl,
 };
 
-int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
+static int vidioc_s_parm(struct file *file, void *priv,
+			 struct v4l2_streamparm *a)
 {
 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
 
@@ -1452,7 +1453,8 @@
 	return 0;
 }
 
-int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
+static int vidioc_g_parm(struct file *file, void *priv,
+			 struct v4l2_streamparm *a)
 {
 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
 
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
index e08b21c..e6217cb 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
@@ -43,7 +43,7 @@
 	ctx->desc_buf = vb2_dma_contig_memops.alloc(
 			dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE);
 	if (IS_ERR_VALUE((int)ctx->desc_buf)) {
-		ctx->desc_buf = 0;
+		ctx->desc_buf = NULL;
 		mfc_err("Allocating DESC buffer failed\n");
 		return -ENOMEM;
 	}
@@ -54,7 +54,7 @@
 	if (desc_virt == NULL) {
 		vb2_dma_contig_memops.put(ctx->desc_buf);
 		ctx->desc_phys = 0;
-		ctx->desc_buf = 0;
+		ctx->desc_buf = NULL;
 		mfc_err("Remapping DESC buffer failed\n");
 		return -ENOMEM;
 	}
@@ -69,7 +69,7 @@
 	if (ctx->desc_phys) {
 		vb2_dma_contig_memops.put(ctx->desc_buf);
 		ctx->desc_phys = 0;
-		ctx->desc_buf = 0;
+		ctx->desc_buf = NULL;
 	}
 }
 
@@ -186,7 +186,7 @@
 		ctx->bank1_buf = vb2_dma_contig_memops.alloc(
 		dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size);
 		if (IS_ERR(ctx->bank1_buf)) {
-			ctx->bank1_buf = 0;
+			ctx->bank1_buf = NULL;
 			printk(KERN_ERR
 			       "Buf alloc for decoding failed (port A)\n");
 			return -ENOMEM;
@@ -200,7 +200,7 @@
 		ctx->bank2_buf = vb2_dma_contig_memops.alloc(
 		dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size);
 		if (IS_ERR(ctx->bank2_buf)) {
-			ctx->bank2_buf = 0;
+			ctx->bank2_buf = NULL;
 			mfc_err("Buf alloc for decoding failed (port B)\n");
 			return -ENOMEM;
 		}
@@ -216,13 +216,13 @@
 {
 	if (ctx->bank1_buf) {
 		vb2_dma_contig_memops.put(ctx->bank1_buf);
-		ctx->bank1_buf = 0;
+		ctx->bank1_buf = NULL;
 		ctx->bank1_phys = 0;
 		ctx->bank1_size = 0;
 	}
 	if (ctx->bank2_buf) {
 		vb2_dma_contig_memops.put(ctx->bank2_buf);
-		ctx->bank2_buf = 0;
+		ctx->bank2_buf = NULL;
 		ctx->bank2_phys = 0;
 		ctx->bank2_size = 0;
 	}
@@ -244,7 +244,7 @@
 	if (IS_ERR(ctx->ctx_buf)) {
 		mfc_err("Allocating context buffer failed\n");
 		ctx->ctx_phys = 0;
-		ctx->ctx_buf = 0;
+		ctx->ctx_buf = NULL;
 		return -ENOMEM;
 	}
 	ctx->ctx_phys = s5p_mfc_mem_cookie(
@@ -256,7 +256,7 @@
 		mfc_err("Remapping instance buffer failed\n");
 		vb2_dma_contig_memops.put(ctx->ctx_buf);
 		ctx->ctx_phys = 0;
-		ctx->ctx_buf = 0;
+		ctx->ctx_buf = NULL;
 		return -ENOMEM;
 	}
 	/* Zero content of the allocated memory */
@@ -265,7 +265,7 @@
 	if (s5p_mfc_init_shm(ctx) < 0) {
 		vb2_dma_contig_memops.put(ctx->ctx_buf);
 		ctx->ctx_phys = 0;
-		ctx->ctx_buf = 0;
+		ctx->ctx_buf = NULL;
 		return -ENOMEM;
 	}
 	return 0;
@@ -277,12 +277,12 @@
 	if (ctx->ctx_buf) {
 		vb2_dma_contig_memops.put(ctx->ctx_buf);
 		ctx->ctx_phys = 0;
-		ctx->ctx_buf = 0;
+		ctx->ctx_buf = NULL;
 	}
 	if (ctx->shm_alloc) {
 		vb2_dma_contig_memops.put(ctx->shm_alloc);
-		ctx->shm_alloc = 0;
-		ctx->shm = 0;
+		ctx->shm_alloc = NULL;
+		ctx->shm = NULL;
 	}
 }
 
@@ -296,7 +296,7 @@
 }
 
 /* Set registers for shared buffer */
-void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
 {
 	struct s5p_mfc_dev *dev = ctx->dev;
 	mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR);
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
index 4865d25..20cb6ee 100644
--- a/drivers/media/video/s5p-tv/hdmi_drv.c
+++ b/drivers/media/video/s5p-tv/hdmi_drv.c
@@ -42,7 +42,23 @@
 MODULE_LICENSE("GPL");
 
 /* default preset configured on probe */
-#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
+#define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94
+
+struct hdmi_pulse {
+	u32 beg;
+	u32 end;
+};
+
+struct hdmi_timings {
+	struct hdmi_pulse hact;
+	u32 hsyn_pol; /* 0 - high, 1 - low */
+	struct hdmi_pulse hsyn;
+	u32 interlaced;
+	struct hdmi_pulse vact[2];
+	u32 vsyn_pol; /* 0 - high, 1 - low */
+	u32 vsyn_off;
+	struct hdmi_pulse vsyn[2];
+};
 
 struct hdmi_resources {
 	struct clk *hdmi;
@@ -70,64 +86,15 @@
 	/** subdev of MHL interface */
 	struct v4l2_subdev *mhl_sd;
 	/** configuration of current graphic mode */
-	const struct hdmi_preset_conf *cur_conf;
+	const struct hdmi_timings *cur_conf;
+	/** flag indicating that timings are dirty */
+	int cur_conf_dirty;
 	/** current preset */
 	u32 cur_preset;
 	/** other resources */
 	struct hdmi_resources res;
 };
 
-struct hdmi_tg_regs {
-	u8 cmd;
-	u8 h_fsz_l;
-	u8 h_fsz_h;
-	u8 hact_st_l;
-	u8 hact_st_h;
-	u8 hact_sz_l;
-	u8 hact_sz_h;
-	u8 v_fsz_l;
-	u8 v_fsz_h;
-	u8 vsync_l;
-	u8 vsync_h;
-	u8 vsync2_l;
-	u8 vsync2_h;
-	u8 vact_st_l;
-	u8 vact_st_h;
-	u8 vact_sz_l;
-	u8 vact_sz_h;
-	u8 field_chg_l;
-	u8 field_chg_h;
-	u8 vact_st2_l;
-	u8 vact_st2_h;
-	u8 vsync_top_hdmi_l;
-	u8 vsync_top_hdmi_h;
-	u8 vsync_bot_hdmi_l;
-	u8 vsync_bot_hdmi_h;
-	u8 field_top_hdmi_l;
-	u8 field_top_hdmi_h;
-	u8 field_bot_hdmi_l;
-	u8 field_bot_hdmi_h;
-};
-
-struct hdmi_core_regs {
-	u8 h_blank[2];
-	u8 v_blank[3];
-	u8 h_v_line[3];
-	u8 vsync_pol[1];
-	u8 int_pro_mode[1];
-	u8 v_blank_f[3];
-	u8 h_sync_gen[3];
-	u8 v_sync_gen1[3];
-	u8 v_sync_gen2[3];
-	u8 v_sync_gen3[3];
-};
-
-struct hdmi_preset_conf {
-	struct hdmi_core_regs core;
-	struct hdmi_tg_regs tg;
-	struct v4l2_mbus_framefmt mbus_fmt;
-};
-
 static struct platform_device_id hdmi_driver_types[] = {
 	{
 		.name		= "s5pv210-hdmi",
@@ -165,6 +132,21 @@
 	writeb(value, hdev->regs + reg_id);
 }
 
+static inline
+void hdmi_writebn(struct hdmi_device *hdev, u32 reg_id, int n, u32 value)
+{
+	switch (n) {
+	default:
+		writeb(value >> 24, hdev->regs + reg_id + 12);
+	case 3:
+		writeb(value >> 16, hdev->regs + reg_id + 8);
+	case 2:
+		writeb(value >>  8, hdev->regs + reg_id + 4);
+	case 1:
+		writeb(value >>  0, hdev->regs + reg_id + 0);
+	}
+}
+
 static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
 {
 	return readl(hdev->regs + reg_id);
@@ -211,77 +193,72 @@
 }
 
 static void hdmi_timing_apply(struct hdmi_device *hdev,
-	const struct hdmi_preset_conf *conf)
+	const struct hdmi_timings *t)
 {
-	const struct hdmi_core_regs *core = &conf->core;
-	const struct hdmi_tg_regs *tg = &conf->tg;
-
 	/* setting core registers */
-	hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
-	hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
-	hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]);
-	hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]);
-	hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]);
-	hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]);
-	hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]);
-	hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]);
-	hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
-	hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
-	hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
-	hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
-	hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
-	hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
-	hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
-	hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
-	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
-	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
-	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
-	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
-	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
-	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
-	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
-	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
-	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+	hdmi_writebn(hdev, HDMI_H_BLANK_0, 2, t->hact.beg);
+	hdmi_writebn(hdev, HDMI_H_SYNC_GEN_0, 3,
+		(t->hsyn_pol << 20) | (t->hsyn.end << 10) | t->hsyn.beg);
+	hdmi_writeb(hdev, HDMI_VSYNC_POL, t->vsyn_pol);
+	hdmi_writebn(hdev, HDMI_V_BLANK_0, 3,
+		(t->vact[0].beg << 11) | t->vact[0].end);
+	hdmi_writebn(hdev, HDMI_V_SYNC_GEN_1_0, 3,
+		(t->vsyn[0].beg << 12) | t->vsyn[0].end);
+	if (t->interlaced) {
+		u32 vsyn_trans = t->hsyn.beg + t->vsyn_off;
+
+		hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 1);
+		hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
+			(t->hact.end << 12) | t->vact[1].end);
+		hdmi_writebn(hdev, HDMI_V_BLANK_F_0, 3,
+			(t->vact[1].end << 11) | t->vact[1].beg);
+		hdmi_writebn(hdev, HDMI_V_SYNC_GEN_2_0, 3,
+			(t->vsyn[1].beg << 12) | t->vsyn[1].end);
+		hdmi_writebn(hdev, HDMI_V_SYNC_GEN_3_0, 3,
+			(vsyn_trans << 12) | vsyn_trans);
+	} else {
+		hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 0);
+		hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
+			(t->hact.end << 12) | t->vact[0].end);
+	}
+
 	/* Timing generator registers */
-	hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
-	hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
-	hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
-	hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
-	hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
-	hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
-	hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
-	hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
-	hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
-	hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
-	hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
-	hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
-	hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
-	hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
-	hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
-	hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
-	hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
-	hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
-	hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
-	hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
-	hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
-	hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
-	hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
-	hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
-	hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
-	hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
-	hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
-	hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+	hdmi_writebn(hdev, HDMI_TG_H_FSZ_L, 2, t->hact.end);
+	hdmi_writebn(hdev, HDMI_TG_HACT_ST_L, 2, t->hact.beg);
+	hdmi_writebn(hdev, HDMI_TG_HACT_SZ_L, 2, t->hact.end - t->hact.beg);
+	hdmi_writebn(hdev, HDMI_TG_VSYNC_L, 2, t->vsyn[0].beg);
+	hdmi_writebn(hdev, HDMI_TG_VACT_ST_L, 2, t->vact[0].beg);
+	hdmi_writebn(hdev, HDMI_TG_VACT_SZ_L, 2,
+		t->vact[0].end - t->vact[0].beg);
+	hdmi_writebn(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, 2, t->vsyn[0].beg);
+	hdmi_writebn(hdev, HDMI_TG_FIELD_TOP_HDMI_L, 2, t->vsyn[0].beg);
+	if (t->interlaced) {
+		hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_FIELD_EN);
+		hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[1].end);
+		hdmi_writebn(hdev, HDMI_TG_VSYNC2_L, 2, t->vsyn[1].beg);
+		hdmi_writebn(hdev, HDMI_TG_FIELD_CHG_L, 2, t->vact[0].end);
+		hdmi_writebn(hdev, HDMI_TG_VACT_ST2_L, 2, t->vact[1].beg);
+		hdmi_writebn(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, 2, t->vsyn[1].beg);
+		hdmi_writebn(hdev, HDMI_TG_FIELD_BOT_HDMI_L, 2, t->vsyn[1].beg);
+	} else {
+		hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_FIELD_EN);
+		hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[0].end);
+	}
 }
 
 static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
 {
 	struct device *dev = hdmi_dev->dev;
-	const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
+	const struct hdmi_timings *conf = hdmi_dev->cur_conf;
 	struct v4l2_dv_preset preset;
 	int ret;
 
 	dev_dbg(dev, "%s\n", __func__);
 
+	/* skip if conf is already synchronized with HW */
+	if (!hdmi_dev->cur_conf_dirty)
+		return 0;
+
 	/* reset hdmiphy */
 	hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
 	mdelay(10);
@@ -307,6 +284,8 @@
 	/* setting core registers */
 	hdmi_timing_apply(hdmi_dev, conf);
 
+	hdmi_dev->cur_conf_dirty = 0;
+
 	return 0;
 }
 
@@ -398,156 +377,126 @@
 #undef DUMPREG
 }
 
-static const struct hdmi_preset_conf hdmi_conf_480p = {
-	.core = {
-		.h_blank = {0x8a, 0x00},
-		.v_blank = {0x0d, 0x6a, 0x01},
-		.h_v_line = {0x0d, 0xa2, 0x35},
-		.vsync_pol = {0x01},
-		.int_pro_mode = {0x00},
-		.v_blank_f = {0x00, 0x00, 0x00},
-		.h_sync_gen = {0x0e, 0x30, 0x11},
-		.v_sync_gen1 = {0x0f, 0x90, 0x00},
-		/* other don't care */
-	},
-	.tg = {
-		0x00, /* cmd */
-		0x5a, 0x03, /* h_fsz */
-		0x8a, 0x00, 0xd0, 0x02, /* hact */
-		0x0d, 0x02, /* v_fsz */
-		0x01, 0x00, 0x33, 0x02, /* vsync */
-		0x2d, 0x00, 0xe0, 0x01, /* vact */
-		0x33, 0x02, /* field_chg */
-		0x49, 0x02, /* vact_st2 */
-		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
-		0x01, 0x00, 0x33, 0x02, /* field top/bot */
-	},
-	.mbus_fmt = {
-		.width = 720,
-		.height = 480,
-		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
-		.field = V4L2_FIELD_NONE,
-		.colorspace = V4L2_COLORSPACE_SRGB,
-	},
+static const struct hdmi_timings hdmi_timings_480p = {
+	.hact = { .beg = 138, .end = 858 },
+	.hsyn_pol = 1,
+	.hsyn = { .beg = 16, .end = 16 + 62 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 42 + 3, .end = 522 + 3 },
+	.vsyn_pol = 1,
+	.vsyn[0] = { .beg = 6 + 3, .end = 12 + 3},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_720p60 = {
-	.core = {
-		.h_blank = {0x72, 0x01},
-		.v_blank = {0xee, 0xf2, 0x00},
-		.h_v_line = {0xee, 0x22, 0x67},
-		.vsync_pol = {0x00},
-		.int_pro_mode = {0x00},
-		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
-		.h_sync_gen = {0x6c, 0x50, 0x02},
-		.v_sync_gen1 = {0x0a, 0x50, 0x00},
-		/* other don't care */
-	},
-	.tg = {
-		0x00, /* cmd */
-		0x72, 0x06, /* h_fsz */
-		0x72, 0x01, 0x00, 0x05, /* hact */
-		0xee, 0x02, /* v_fsz */
-		0x01, 0x00, 0x33, 0x02, /* vsync */
-		0x1e, 0x00, 0xd0, 0x02, /* vact */
-		0x33, 0x02, /* field_chg */
-		0x49, 0x02, /* vact_st2 */
-		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
-		0x01, 0x00, 0x33, 0x02, /* field top/bot */
-	},
-	.mbus_fmt = {
-		.width = 1280,
-		.height = 720,
-		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
-		.field = V4L2_FIELD_NONE,
-		.colorspace = V4L2_COLORSPACE_SRGB,
-	},
+static const struct hdmi_timings hdmi_timings_576p50 = {
+	.hact = { .beg = 144, .end = 864 },
+	.hsyn_pol = 1,
+	.hsyn = { .beg = 12, .end = 12 + 64 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 44 + 5, .end = 620 + 5 },
+	.vsyn_pol = 1,
+	.vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
-	.core = {
-		.h_blank = {0xd0, 0x02},
-		.v_blank = {0x65, 0x6c, 0x01},
-		.h_v_line = {0x65, 0x04, 0xa5},
-		.vsync_pol = {0x00},
-		.int_pro_mode = {0x00},
-		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
-		.h_sync_gen = {0x0e, 0xea, 0x08},
-		.v_sync_gen1 = {0x09, 0x40, 0x00},
-		/* other don't care */
-	},
-	.tg = {
-		0x00, /* cmd */
-		0x98, 0x08, /* h_fsz */
-		0x18, 0x01, 0x80, 0x07, /* hact */
-		0x65, 0x04, /* v_fsz */
-		0x01, 0x00, 0x33, 0x02, /* vsync */
-		0x2d, 0x00, 0x38, 0x04, /* vact */
-		0x33, 0x02, /* field_chg */
-		0x49, 0x02, /* vact_st2 */
-		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
-		0x01, 0x00, 0x33, 0x02, /* field top/bot */
-	},
-	.mbus_fmt = {
-		.width = 1920,
-		.height = 1080,
-		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
-		.field = V4L2_FIELD_NONE,
-		.colorspace = V4L2_COLORSPACE_SRGB,
-	},
+static const struct hdmi_timings hdmi_timings_720p60 = {
+	.hact = { .beg = 370, .end = 1650 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 110, .end = 110 + 40 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
-	.core = {
-		.h_blank = {0x18, 0x01},
-		.v_blank = {0x65, 0x6c, 0x01},
-		.h_v_line = {0x65, 0x84, 0x89},
-		.vsync_pol = {0x00},
-		.int_pro_mode = {0x00},
-		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
-		.h_sync_gen = {0x56, 0x08, 0x02},
-		.v_sync_gen1 = {0x09, 0x40, 0x00},
-		/* other don't care */
-	},
-	.tg = {
-		0x00, /* cmd */
-		0x98, 0x08, /* h_fsz */
-		0x18, 0x01, 0x80, 0x07, /* hact */
-		0x65, 0x04, /* v_fsz */
-		0x01, 0x00, 0x33, 0x02, /* vsync */
-		0x2d, 0x00, 0x38, 0x04, /* vact */
-		0x33, 0x02, /* field_chg */
-		0x48, 0x02, /* vact_st2 */
-		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
-		0x01, 0x00, 0x33, 0x02, /* field top/bot */
-	},
-	.mbus_fmt = {
-		.width = 1920,
-		.height = 1080,
-		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
-		.field = V4L2_FIELD_NONE,
-		.colorspace = V4L2_COLORSPACE_SRGB,
-	},
+static const struct hdmi_timings hdmi_timings_720p50 = {
+	.hact = { .beg = 700, .end = 1980 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 440, .end = 440 + 40 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p24 = {
+	.hact = { .beg = 830, .end = 2750 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 638, .end = 638 + 44 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p60 = {
+	.hact = { .beg = 280, .end = 2200 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 88, .end = 88 + 44 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct hdmi_timings hdmi_timings_1080i60 = {
+	.hact = { .beg = 280, .end = 2200 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 88, .end = 88 + 44 },
+	.interlaced = 1,
+	.vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
+	.vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
+	.vsyn_pol = 0,
+	.vsyn_off = 1100,
+	.vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
+	.vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
+};
+
+static const struct hdmi_timings hdmi_timings_1080i50 = {
+	.hact = { .beg = 720, .end = 2640 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 528, .end = 528 + 44 },
+	.interlaced = 1,
+	.vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
+	.vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
+	.vsyn_pol = 0,
+	.vsyn_off = 1320,
+	.vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
+	.vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p50 = {
+	.hact = { .beg = 720, .end = 2640 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 528, .end = 528 + 44 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
 };
 
 static const struct {
 	u32 preset;
-	const struct hdmi_preset_conf *conf;
-} hdmi_conf[] = {
-	{ V4L2_DV_480P59_94, &hdmi_conf_480p },
-	{ V4L2_DV_720P59_94, &hdmi_conf_720p60 },
-	{ V4L2_DV_1080P50, &hdmi_conf_1080p50 },
-	{ V4L2_DV_1080P30, &hdmi_conf_1080p60 },
-	{ V4L2_DV_1080P60, &hdmi_conf_1080p60 },
+	const struct hdmi_timings *timings;
+} hdmi_timings[] = {
+	{ V4L2_DV_480P59_94, &hdmi_timings_480p },
+	{ V4L2_DV_576P50, &hdmi_timings_576p50 },
+	{ V4L2_DV_720P50, &hdmi_timings_720p50 },
+	{ V4L2_DV_720P59_94, &hdmi_timings_720p60 },
+	{ V4L2_DV_720P60, &hdmi_timings_720p60 },
+	{ V4L2_DV_1080P24, &hdmi_timings_1080p24 },
+	{ V4L2_DV_1080P30, &hdmi_timings_1080p60 },
+	{ V4L2_DV_1080P50, &hdmi_timings_1080p50 },
+	{ V4L2_DV_1080I50, &hdmi_timings_1080i50 },
+	{ V4L2_DV_1080I60, &hdmi_timings_1080i60 },
+	{ V4L2_DV_1080P60, &hdmi_timings_1080p60 },
 };
 
-static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset)
+static const struct hdmi_timings *hdmi_preset2timings(u32 preset)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(hdmi_conf); ++i)
-		if (hdmi_conf[i].preset == preset)
-			return  hdmi_conf[i].conf;
+	for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i)
+		if (hdmi_timings[i].preset == preset)
+			return  hdmi_timings[i].timings;
 	return NULL;
 }
 
@@ -559,6 +508,10 @@
 
 	dev_dbg(dev, "%s\n", __func__);
 
+	ret = hdmi_conf_apply(hdev);
+	if (ret)
+		return ret;
+
 	ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
 	if (ret)
 		return ret;
@@ -671,14 +624,15 @@
 {
 	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
 	struct device *dev = hdev->dev;
-	const struct hdmi_preset_conf *conf;
+	const struct hdmi_timings *conf;
 
-	conf = hdmi_preset2conf(preset->preset);
+	conf = hdmi_preset2timings(preset->preset);
 	if (conf == NULL) {
 		dev_err(dev, "preset (%u) not supported\n", preset->preset);
 		return -EINVAL;
 	}
 	hdev->cur_conf = conf;
+	hdev->cur_conf_dirty = 1;
 	hdev->cur_preset = preset->preset;
 	return 0;
 }
@@ -695,21 +649,32 @@
 	  struct v4l2_mbus_framefmt *fmt)
 {
 	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
-	struct device *dev = hdev->dev;
+	const struct hdmi_timings *t = hdev->cur_conf;
 
-	dev_dbg(dev, "%s\n", __func__);
+	dev_dbg(hdev->dev, "%s\n", __func__);
 	if (!hdev->cur_conf)
 		return -EINVAL;
-	*fmt = hdev->cur_conf->mbus_fmt;
+	memset(fmt, 0, sizeof *fmt);
+	fmt->width = t->hact.end - t->hact.beg;
+	fmt->height = t->vact[0].end - t->vact[0].beg;
+	fmt->code = V4L2_MBUS_FMT_FIXED; /* means RGB888 */
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+	if (t->interlaced) {
+		fmt->field = V4L2_FIELD_INTERLACED;
+		fmt->height *= 2;
+	} else {
+		fmt->field = V4L2_FIELD_NONE;
+	}
 	return 0;
 }
 
 static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
 	struct v4l2_dv_enum_preset *preset)
 {
-	if (preset->index >= ARRAY_SIZE(hdmi_conf))
+	if (preset->index >= ARRAY_SIZE(hdmi_timings))
 		return -EINVAL;
-	return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset);
+	return v4l_fill_dv_preset_info(hdmi_timings[preset->index].preset,
+		preset);
 }
 
 static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
@@ -737,6 +702,8 @@
 	dev_dbg(dev, "%s\n", __func__);
 	v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0);
 	hdmi_resource_poweroff(&hdev->res);
+	/* flag that device context is lost */
+	hdev->cur_conf_dirty = 1;
 	return 0;
 }
 
@@ -750,10 +717,6 @@
 
 	hdmi_resource_poweron(&hdev->res);
 
-	ret = hdmi_conf_apply(hdev);
-	if (ret)
-		goto fail;
-
 	/* starting MHL */
 	ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1);
 	if (hdev->mhl_sd && ret)
@@ -993,7 +956,8 @@
 	strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
 	hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
 	/* FIXME: missing fail preset is not supported */
-	hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
+	hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset);
+	hdmi_dev->cur_conf_dirty = 1;
 
 	/* storing subdev for call that have only access to struct device */
 	dev_set_drvdata(dev, sd);
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c
index 0afef77..f67b386 100644
--- a/drivers/media/video/s5p-tv/hdmiphy_drv.c
+++ b/drivers/media/video/s5p-tv/hdmiphy_drv.c
@@ -26,53 +26,188 @@
 MODULE_LICENSE("GPL");
 
 struct hdmiphy_conf {
-	u32 preset;
+	unsigned long pixclk;
 	const u8 *data;
 };
 
-static const u8 hdmiphy_conf27[32] = {
-	0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
-	0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
-	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
-	0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x00,
+struct hdmiphy_ctx {
+	struct v4l2_subdev sd;
+	const struct hdmiphy_conf *conf_tab;
 };
 
-static const u8 hdmiphy_conf74_175[32] = {
-	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
-	0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
-	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
-	0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
+static const struct hdmiphy_conf hdmiphy_conf_s5pv210[] = {
+	{ .pixclk = 27000000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+		0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 27027000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
+		0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 74176000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B,
+		0x6D, 0x10, 0x01, 0x52, 0xEF, 0xF3, 0x54, 0xB9,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xA5, 0x26, 0x01, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 74250000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40,
+		0x6A, 0x10, 0x01, 0x52, 0xFF, 0xF1, 0x54, 0xBA,
+		0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xA4, 0x26, 0x01, 0x00, 0x00, 0x00, }
+	},
+	{ /* end marker */ }
 };
 
-static const u8 hdmiphy_conf74_25[32] = {
-	0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
-	0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
-	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xe0,
-	0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
+static const struct hdmiphy_conf hdmiphy_conf_exynos4210[] = {
+	{ .pixclk = 27000000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+		0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 27027000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
+		0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 74176000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B,
+		0x6D, 0x10, 0x01, 0x51, 0xEF, 0xF3, 0x54, 0xB9,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xA5, 0x26, 0x01, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 74250000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40,
+		0x6A, 0x10, 0x01, 0x51, 0xFF, 0xF1, 0x54, 0xBA,
+		0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xA4, 0x26, 0x01, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 148352000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B,
+		0x6D, 0x18, 0x00, 0x51, 0xEF, 0xF3, 0x54, 0xB9,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x11, 0x40, 0xA5, 0x26, 0x02, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 148500000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40,
+		0x6A, 0x18, 0x00, 0x51, 0xFF, 0xF1, 0x54, 0xBA,
+		0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x11, 0x40, 0xA4, 0x26, 0x02, 0x00, 0x00, 0x00, }
+	},
+	{ /* end marker */ }
 };
 
-static const u8 hdmiphy_conf148_5[32] = {
-	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
-	0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
-	0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
-	0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
+static const struct hdmiphy_conf hdmiphy_conf_exynos4212[] = {
+	{ .pixclk = 27000000, .data = (u8 [32]) {
+		0x01, 0x11, 0x2D, 0x75, 0x00, 0x01, 0x00, 0x08,
+		0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71,
+		0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 27027000, .data = (u8 [32]) {
+		0x01, 0x91, 0x2D, 0x72, 0x00, 0x64, 0x12, 0x08,
+		0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71,
+		0x54, 0xE2, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 74176000, .data = (u8 [32]) {
+		0x01, 0x91, 0x3E, 0x35, 0x00, 0x5B, 0xDE, 0x08,
+		0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52,
+		0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 74250000, .data = (u8 [32]) {
+		0x01, 0x91, 0x3E, 0x35, 0x00, 0x40, 0xF0, 0x08,
+		0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52,
+		0x54, 0xA4, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 148500000, .data = (u8 [32]) {
+		0x01, 0x91, 0x3E, 0x15, 0x00, 0x40, 0xF0, 0x08,
+		0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0xA4,
+		0x54, 0x4A, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ /* end marker */ }
 };
 
-static const struct hdmiphy_conf hdmiphy_conf[] = {
-	{ V4L2_DV_480P59_94, hdmiphy_conf27 },
-	{ V4L2_DV_1080P30, hdmiphy_conf74_175 },
-	{ V4L2_DV_720P59_94, hdmiphy_conf74_175 },
-	{ V4L2_DV_720P60, hdmiphy_conf74_25 },
-	{ V4L2_DV_1080P50, hdmiphy_conf148_5 },
-	{ V4L2_DV_1080P60, hdmiphy_conf148_5 },
+static const struct hdmiphy_conf hdmiphy_conf_exynos4412[] = {
+	{ .pixclk = 27000000, .data = (u8 [32]) {
+		0x01, 0x11, 0x2D, 0x75, 0x40, 0x01, 0x00, 0x08,
+		0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 27027000, .data = (u8 [32]) {
+		0x01, 0x91, 0x2D, 0x72, 0x40, 0x64, 0x12, 0x08,
+		0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 74176000, .data = (u8 [32]) {
+		0x01, 0x91, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0x08,
+		0x81, 0x20, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 74250000, .data = (u8 [32]) {
+		0x01, 0x91, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
+		0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 148500000, .data = (u8 [32]) {
+		0x01, 0x91, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
+		0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0x4B, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ /* end marker */ }
 };
 
-const u8 *hdmiphy_preset2conf(u32 preset)
+static inline struct hdmiphy_ctx *sd_to_ctx(struct v4l2_subdev *sd)
 {
-	int i;
-	for (i = 0; i < ARRAY_SIZE(hdmiphy_conf); ++i)
-		if (hdmiphy_conf[i].preset == preset)
-			return hdmiphy_conf[i].data;
+	return container_of(sd, struct hdmiphy_ctx, sd);
+}
+
+static unsigned long hdmiphy_preset_to_pixclk(u32 preset)
+{
+	static const unsigned long pixclk[] = {
+		[V4L2_DV_480P59_94] =  27000000,
+		[V4L2_DV_576P50]    =  27000000,
+		[V4L2_DV_720P59_94] =  74176000,
+		[V4L2_DV_720P50]    =  74250000,
+		[V4L2_DV_720P60]    =  74250000,
+		[V4L2_DV_1080P24]   =  74250000,
+		[V4L2_DV_1080P30]   =  74250000,
+		[V4L2_DV_1080I50]   =  74250000,
+		[V4L2_DV_1080I60]   =  74250000,
+		[V4L2_DV_1080P50]   = 148500000,
+		[V4L2_DV_1080P60]   = 148500000,
+	};
+	if (preset < ARRAY_SIZE(pixclk))
+		return pixclk[preset];
+	else
+		return 0;
+}
+
+static const u8 *hdmiphy_find_conf(u32 preset, const struct hdmiphy_conf *conf)
+{
+	unsigned long pixclk;
+
+	pixclk = hdmiphy_preset_to_pixclk(preset);
+	if (!pixclk)
+		return NULL;
+
+	for (; conf->pixclk; ++conf)
+		if (conf->pixclk == pixclk)
+			return conf->data;
 	return NULL;
 }
 
@@ -88,11 +223,12 @@
 	const u8 *data;
 	u8 buffer[32];
 	int ret;
+	struct hdmiphy_ctx *ctx = sd_to_ctx(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct device *dev = &client->dev;
 
 	dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
-	data = hdmiphy_preset2conf(preset->preset);
+	data = hdmiphy_find_conf(preset->preset, ctx->conf_tab);
 	if (!data) {
 		dev_err(dev, "format not supported\n");
 		return -EINVAL;
@@ -146,21 +282,36 @@
 static int __devinit hdmiphy_probe(struct i2c_client *client,
 	const struct i2c_device_id *id)
 {
-	static struct v4l2_subdev sd;
+	struct hdmiphy_ctx *ctx;
 
-	v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->conf_tab = (struct hdmiphy_conf *)id->driver_data;
+	v4l2_i2c_subdev_init(&ctx->sd, client, &hdmiphy_ops);
+
 	dev_info(&client->dev, "probe successful\n");
 	return 0;
 }
 
 static int __devexit hdmiphy_remove(struct i2c_client *client)
 {
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct hdmiphy_ctx *ctx = sd_to_ctx(sd);
+
+	kfree(ctx);
 	dev_info(&client->dev, "remove successful\n");
+
 	return 0;
 }
 
 static const struct i2c_device_id hdmiphy_id[] = {
-	{ "hdmiphy", 0 },
+	{ "hdmiphy", (unsigned long)hdmiphy_conf_exynos4210 },
+	{ "hdmiphy-s5pv210", (unsigned long)hdmiphy_conf_s5pv210 },
+	{ "hdmiphy-exynos4210", (unsigned long)hdmiphy_conf_exynos4210 },
+	{ "hdmiphy-exynos4212", (unsigned long)hdmiphy_conf_exynos4212 },
+	{ "hdmiphy-exynos4412", (unsigned long)hdmiphy_conf_exynos4412 },
 	{ },
 };
 MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h
index 1597078..ddb422e 100644
--- a/drivers/media/video/s5p-tv/mixer.h
+++ b/drivers/media/video/s5p-tv/mixer.h
@@ -226,6 +226,7 @@
 /* event flags used  */
 enum mxr_devide_flags {
 	MXR_EVENT_VSYNC = 0,
+	MXR_EVENT_TOP = 1,
 };
 
 /** drivers instance */
@@ -293,7 +294,7 @@
 	struct mxr_output_conf *output_cont, int output_count);
 
 /** releasing common video resources */
-void __devexit mxr_release_video(struct mxr_device *mdev);
+void mxr_release_video(struct mxr_device *mdev);
 
 struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
 struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
index a2c0c25..edca065 100644
--- a/drivers/media/video/s5p-tv/mixer_drv.c
+++ b/drivers/media/video/s5p-tv/mixer_drv.c
@@ -461,7 +461,7 @@
 static int __init mxr_init(void)
 {
 	int i, ret;
-	static const char banner[] __initdata = KERN_INFO
+	static const char banner[] __initconst = KERN_INFO
 		"Samsung TV Mixer driver, "
 		"(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
 	printk(banner);
diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/video/s5p-tv/mixer_reg.c
index 4800a3c..3b1670a 100644
--- a/drivers/media/video/s5p-tv/mixer_reg.c
+++ b/drivers/media/video/s5p-tv/mixer_reg.c
@@ -296,21 +296,25 @@
 	/* wake up process waiting for VSYNC */
 	if (val & MXR_INT_STATUS_VSYNC) {
 		set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+		/* toggle TOP field event if working in interlaced mode */
+		if (~mxr_read(mdev, MXR_CFG) & MXR_CFG_SCAN_PROGRASSIVE)
+			change_bit(MXR_EVENT_TOP, &mdev->event_flags);
 		wake_up(&mdev->event_queue);
+		/* vsync interrupt use different bit for read and clear */
+		val &= ~MXR_INT_STATUS_VSYNC;
+		val |= MXR_INT_CLEAR_VSYNC;
 	}
 
 	/* clear interrupts */
-	if (~val & MXR_INT_EN_VSYNC) {
-		/* vsync interrupt use different bit for read and clear */
-		val &= ~MXR_INT_EN_VSYNC;
-		val |= MXR_INT_CLEAR_VSYNC;
-	}
 	mxr_write(mdev, MXR_INT_STATUS, val);
 
 	spin_unlock(&mdev->reg_slock);
 	/* leave on non-vsync event */
 	if (~val & MXR_INT_CLEAR_VSYNC)
 		return IRQ_HANDLED;
+	/* skip layer update on bottom field */
+	if (!test_bit(MXR_EVENT_TOP, &mdev->event_flags))
+		return IRQ_HANDLED;
 	for (i = 0; i < MXR_MAX_LAYERS; ++i)
 		mxr_irq_layer_handle(mdev->layer[i]);
 	return IRQ_HANDLED;
@@ -333,6 +337,7 @@
 
 	/* start MIXER */
 	mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
+	set_bit(MXR_EVENT_TOP, &mdev->event_flags);
 
 	spin_unlock_irqrestore(&mdev->reg_slock, flags);
 }
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
index f7ca5cc..33fde2a 100644
--- a/drivers/media/video/s5p-tv/mixer_video.c
+++ b/drivers/media/video/s5p-tv/mixer_video.c
@@ -140,7 +140,7 @@
 	return ret;
 }
 
-void __devexit mxr_release_video(struct mxr_device *mdev)
+void mxr_release_video(struct mxr_device *mdev)
 {
 	int i;
 
@@ -853,8 +853,8 @@
 	*nplanes = fmt->num_subframes;
 	for (i = 0; i < fmt->num_subframes; ++i) {
 		alloc_ctxs[i] = layer->mdev->alloc_ctx;
-		sizes[i] = PAGE_ALIGN(planes[i].sizeimage);
-		mxr_dbg(mdev, "size[%d] = %08lx\n", i, sizes[i]);
+		sizes[i] = planes[i].sizeimage;
+		mxr_dbg(mdev, "size[%d] = %08x\n", i, sizes[i]);
 	}
 
 	if (*nbuffers == 0)
@@ -1069,6 +1069,10 @@
 	set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
 
 	video_set_drvdata(&layer->vfd, layer);
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &layer->vfd.flags);
 	layer->vfd.lock = &layer->mutex;
 	layer->vfd.v4l2_dev = &mdev->v4l2_dev;
 
diff --git a/drivers/media/video/s5p-tv/regs-hdmi.h b/drivers/media/video/s5p-tv/regs-hdmi.h
index 33247d1..a889d1f 100644
--- a/drivers/media/video/s5p-tv/regs-hdmi.h
+++ b/drivers/media/video/s5p-tv/regs-hdmi.h
@@ -140,6 +140,7 @@
 #define HDMI_MODE_MASK			(3 << 0)
 
 /* HDMI_TG_CMD */
+#define HDMI_TG_FIELD_EN		(1 << 1)
 #define HDMI_TG_EN			(1 << 0)
 
 #endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 53aae59..bc08f1d 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5080,6 +5080,36 @@
 			.gpio = 0x0200000,
 		},
 	},
+	[SAA7134_BOARD_ASUSTeK_PS3_100] = {
+		.name           = "Asus My Cinema PS3-100",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 2,
+		.gpiomask       = 1 << 21,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp,
+			.vmux = 0,
+			.amux = LINE2,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
 	[SAA7134_BOARD_REAL_ANGEL_220] = {
 		.name           = "Zogis Real Angel 220",
 		.audio_clock    = 0x00187de7,
@@ -6877,6 +6907,12 @@
 		.driver_data  = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
 	}, {
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x48cd,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_PS3_100,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor    = 0x17de,
 		.subdevice    = 0x7128,
@@ -7347,6 +7383,7 @@
 	case SAA7134_BOARD_KWORLD_TERMINATOR:
 	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
 	case SAA7134_BOARD_FLYDVBT_LR301:
+	case SAA7134_BOARD_ASUSTeK_PS3_100:
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
 	case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
@@ -7811,6 +7848,14 @@
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		break;
 	}
+	case SAA7134_BOARD_ASUSTeK_PS3_100:
+	{
+		u8 data[] = { 0x3c, 0x33, 0x60};
+		struct i2c_msg msg = {.addr = 0x0b, .flags = 0, .buf = data,
+						       .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		break;
+	}
 	case SAA7134_BOARD_FLYDVB_TRIO:
 	{
 		u8 temp = 0;
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index aaa5c97..5dfd826 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -881,6 +881,20 @@
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
+static struct tda1004x_config asus_ps3_100_config = {
+	.demod_address = 0x0b,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch = 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
 /* ------------------------------------------------------------------
  * special case: this card uses saa713x GPIO22 for the mode switch
  */
@@ -1647,6 +1661,31 @@
 						&dev->i2c_adap, 0, 0) == NULL) {
 					wprintk("%s: Asus Tiger 3in1, no lnbp21"
 						" found!\n", __func__);
+				       goto dettach_frontend;
+			       }
+		       }
+	       }
+	       break;
+	case SAA7134_BOARD_ASUSTeK_PS3_100:
+		if (!use_frontend) {     /* terrestrial */
+			if (configure_tda827x_fe(dev, &asus_ps3_100_config,
+						 &tda827x_cfg_2) < 0)
+				goto dettach_frontend;
+	       } else {                /* satellite */
+			fe0->dvb.frontend = dvb_attach(tda10086_attach,
+						       &flydvbs, &dev->i2c_adap);
+			if (fe0->dvb.frontend) {
+				if (dvb_attach(tda826x_attach,
+					       fe0->dvb.frontend, 0x60,
+					       &dev->i2c_adap, 0) == NULL) {
+					wprintk("%s: Asus My Cinema PS3-100, no "
+						"tda826x found!\n", __func__);
+					goto dettach_frontend;
+				}
+				if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+					       &dev->i2c_adap, 0, 0) == NULL) {
+					wprintk("%s: Asus My Cinema PS3-100, no lnbp21"
+						" found!\n", __func__);
 					goto dettach_frontend;
 				}
 			}
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 48d2878..05c6e21 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -753,6 +753,13 @@
 		mask_keycode = 0xffff;
 		raw_decode   = true;
 		break;
+	case SAA7134_BOARD_ASUSTeK_PS3_100:
+		ir_codes     = RC_MAP_ASUS_PS3_100;
+		mask_keydown = 0x0040000;
+		mask_keyup   = 0x0040000;
+		mask_keycode = 0xffff;
+		raw_decode   = true;
+		break;
 	case SAA7134_BOARD_ENCORE_ENLTV:
 	case SAA7134_BOARD_ENCORE_ENLTV_FM:
 		ir_codes     = RC_MAP_ENCORE_ENLTV;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 417034e..6de10b1 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -2036,7 +2036,7 @@
 	mode = dev->thread.mode;
 	if (UNSET == mode) {
 		rx   = saa7134_tvaudio_getstereo(dev);
-		mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+		mode = saa7134_tvaudio_rx2mode(rx);
 	}
 	if (mode != t->audmode)
 		dev->thread.mode = t->audmode;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index f625060..89c8333 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -332,6 +332,7 @@
 #define SAA7134_BOARD_BEHOLD_503FM          187
 #define SAA7134_BOARD_SENSORAY811_911       188
 #define SAA7134_BOARD_KWORLD_PC150U         189
+#define SAA7134_BOARD_ASUSTeK_PS3_100      190
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c
index 273cf80..d8e6c8f 100644
--- a/drivers/media/video/saa7164/saa7164-vbi.c
+++ b/drivers/media/video/saa7164/saa7164-vbi.c
@@ -952,7 +952,7 @@
 
 		/* Stop the hardware, regardless */
 		result = saa7164_vbi_stop_port(port);
-		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		if (result != SAA_OK) {
 			printk(KERN_ERR "%s() pause/forced stop transition "
 				"failed, res = 0x%x\n", __func__, result);
 		}
@@ -971,7 +971,7 @@
 		/* Stop the hardware, regardless */
 		result = saa7164_vbi_acquire_port(port);
 		result = saa7164_vbi_stop_port(port);
-		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		if (result != SAA_OK) {
 			printk(KERN_ERR "%s() run/forced stop transition "
 				"failed, res = 0x%x\n", __func__, result);
 		}
diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h
index 742b341..8d120e3 100644
--- a/drivers/media/video/saa7164/saa7164.h
+++ b/drivers/media/video/saa7164/saa7164.h
@@ -611,11 +611,6 @@
 		printk(KERN_WARNING "%s: " fmt, dev->name, ## arg);\
 	} while (0)
 
-#define log_err(fmt, arg...)\
-	do { \
-		printk(KERN_ERROR "%s: " fmt, dev->name, ## arg);\
-	} while (0)
-
 #define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2))
 #define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2))
 
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 424dfac..0baaf94 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -210,27 +210,33 @@
 	struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct sh_mobile_ceu_dev *pcdev = ici->priv;
-	int bytes_per_line;
-	unsigned int height;
 
 	if (fmt) {
 		const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
 								fmt->fmt.pix.pixelformat);
+		unsigned int bytes_per_line;
+		int ret;
+
 		if (!xlate)
 			return -EINVAL;
-		bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
-							 xlate->host_fmt);
-		height = fmt->fmt.pix.height;
+
+		ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
+					      xlate->host_fmt);
+		if (ret < 0)
+			return ret;
+
+		bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
+
+		ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
+					  fmt->fmt.pix.height);
+		if (ret < 0)
+			return ret;
+
+		sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
 	} else {
 		/* Called from VIDIOC_REQBUFS or in compatibility mode */
-		bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-						icd->current_fmt->host_fmt);
-		height = icd->user_height;
+		sizes[0] = icd->sizeimage;
 	}
-	if (bytes_per_line < 0)
-		return bytes_per_line;
-
-	sizes[0] = bytes_per_line * height;
 
 	alloc_ctxs[0] = pcdev->alloc_ctx;
 
@@ -336,21 +342,15 @@
 
 	ceu_write(pcdev, top1, phys_addr_top);
 	if (V4L2_FIELD_NONE != pcdev->field) {
-		if (planar)
-			phys_addr_bottom = phys_addr_top + icd->user_width;
-		else
-			phys_addr_bottom = phys_addr_top +
-				soc_mbus_bytes_per_line(icd->user_width,
-							icd->current_fmt->host_fmt);
+		phys_addr_bottom = phys_addr_top + icd->bytesperline;
 		ceu_write(pcdev, bottom1, phys_addr_bottom);
 	}
 
 	if (planar) {
-		phys_addr_top += icd->user_width *
-			icd->user_height;
+		phys_addr_top += icd->bytesperline * icd->user_height;
 		ceu_write(pcdev, top2, phys_addr_top);
 		if (V4L2_FIELD_NONE != pcdev->field) {
-			phys_addr_bottom = phys_addr_top + icd->user_width;
+			phys_addr_bottom = phys_addr_top + icd->bytesperline;
 			ceu_write(pcdev, bottom2, phys_addr_bottom);
 		}
 	}
@@ -377,13 +377,8 @@
 	struct sh_mobile_ceu_dev *pcdev = ici->priv;
 	struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
 	unsigned long size;
-	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-						icd->current_fmt->host_fmt);
 
-	if (bytes_per_line < 0)
-		goto error;
-
-	size = icd->user_height * bytes_per_line;
+	size = icd->sizeimage;
 
 	if (vb2_plane_size(vb, 0) < size) {
 		dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n",
@@ -682,10 +677,7 @@
 			in_width *= 2;
 			left_offset *= 2;
 		}
-		cdwdr_width = width;
 	} else {
-		int bytes_per_line = soc_mbus_bytes_per_line(width,
-						icd->current_fmt->host_fmt);
 		unsigned int w_factor;
 
 		switch (icd->current_fmt->host_fmt->packing) {
@@ -698,13 +690,10 @@
 
 		in_width = cam->width * w_factor;
 		left_offset *= w_factor;
-
-		if (bytes_per_line < 0)
-			cdwdr_width = width;
-		else
-			cdwdr_width = bytes_per_line;
 	}
 
+	cdwdr_width = icd->bytesperline;
+
 	height = icd->user_height;
 	in_height = cam->height;
 	if (V4L2_FIELD_NONE != pcdev->field) {
@@ -881,11 +870,13 @@
 
 	value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
 	value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
-	value |= pcdev->is_16bit ? 1 << 12 : 0;
 
-	/* CSI2 mode */
-	if (pcdev->pdata->csi2)
+	if (pcdev->pdata->csi2) /* CSI2 mode */
 		value |= 3 << 12;
+	else if (pcdev->is_16bit)
+		value |= 1 << 12;
+	else if (pcdev->pdata->flags & SH_CEU_FLAG_LOWER_8BIT)
+		value |= 2 << 12;
 
 	ceu_write(pcdev, CAMCR, value);
 
@@ -964,24 +955,28 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_1_5X8,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_2Y_C,
 	}, {
 		.fourcc			= V4L2_PIX_FMT_NV21,
 		.name			= "NV21",
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_1_5X8,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_2Y_C,
 	}, {
 		.fourcc			= V4L2_PIX_FMT_NV16,
 		.name			= "NV16",
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_Y_C,
 	}, {
 		.fourcc			= V4L2_PIX_FMT_NV61,
 		.name			= "NV61",
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_Y_C,
 	},
 };
 
@@ -1845,6 +1840,8 @@
 	return 0;
 }
 
+#define CEU_CHDW_MAX	8188U	/* Maximum line stride */
+
 static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
 				 struct v4l2_format *f)
 {
@@ -1863,8 +1860,12 @@
 
 	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
 	if (!xlate) {
-		dev_warn(icd->parent, "Format %x not found\n", pixfmt);
-		return -EINVAL;
+		xlate = icd->current_fmt;
+		dev_dbg(icd->parent, "Format %x not found, keeping %x\n",
+			pixfmt, xlate->host_fmt->fourcc);
+		pixfmt = xlate->host_fmt->fourcc;
+		pix->pixelformat = pixfmt;
+		pix->colorspace = icd->colorspace;
 	}
 
 	/* FIXME: calculate using depth and bus width */
@@ -1923,10 +1924,20 @@
 			pix->width = width;
 		if (mf.height > height)
 			pix->height = height;
+
+		pix->bytesperline = max(pix->bytesperline, pix->width);
+		pix->bytesperline = min(pix->bytesperline, CEU_CHDW_MAX);
+		pix->bytesperline &= ~3;
+		break;
+
+	default:
+		/* Configurable stride isn't supported in pass-through mode. */
+		pix->bytesperline  = 0;
 	}
 
 	pix->width	&= ~3;
 	pix->height	&= ~3;
+	pix->sizeimage	= 0;
 
 	dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
 		__func__, ret, pix->pixelformat, pix->width, pix->height);
@@ -2145,6 +2156,7 @@
 	pcdev->ici.nr = pdev->id;
 	pcdev->ici.drv_name = dev_name(&pdev->dev);
 	pcdev->ici.ops = &sh_mobile_ceu_host_ops;
+	pcdev->ici.capabilities = SOCAM_HOST_CAP_STRIDE;
 
 	pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
 	if (IS_ERR(pcdev->alloc_ctx)) {
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
index 9644bd8..8fd1874 100644
--- a/drivers/media/video/sh_vou.c
+++ b/drivers/media/video/sh_vou.c
@@ -1390,6 +1390,10 @@
 	vdev->v4l2_dev = &vou_dev->v4l2_dev;
 	vdev->release = video_device_release;
 	vdev->lock = &vou_dev->fop_lock;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
 
 	vou_dev->vdev = vdev;
 	video_set_drvdata(vdev, vou_dev);
diff --git a/drivers/media/video/smiapp-pll.c b/drivers/media/video/smiapp-pll.c
new file mode 100644
index 0000000..a2e41a2
--- /dev/null
+++ b/drivers/media/video/smiapp-pll.c
@@ -0,0 +1,418 @@
+/*
+ * drivers/media/video/smiapp-pll.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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
+ *
+ */
+
+#include <linux/gcd.h>
+#include <linux/lcm.h>
+#include <linux/module.h>
+
+#include "smiapp-pll.h"
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even(uint32_t a)
+{
+	return max_t(uint32_t, 1, a & ~1);
+}
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even_up(uint32_t a)
+{
+	if (a == 1)
+		return 1;
+	return (a + 1) & ~1;
+}
+
+static inline uint32_t is_one_or_even(uint32_t a)
+{
+	if (a == 1)
+		return 1;
+	if (a & 1)
+		return 0;
+
+	return 1;
+}
+
+static int bounds_check(struct device *dev, uint32_t val,
+			uint32_t min, uint32_t max, char *str)
+{
+	if (val >= min && val <= max)
+		return 0;
+
+	dev_warn(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
+
+	return -EINVAL;
+}
+
+static void print_pll(struct device *dev, struct smiapp_pll *pll)
+{
+	dev_dbg(dev, "pre_pll_clk_div\t%d\n",  pll->pre_pll_clk_div);
+	dev_dbg(dev, "pll_multiplier \t%d\n",  pll->pll_multiplier);
+	if (pll->flags != SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+		dev_dbg(dev, "op_sys_clk_div \t%d\n", pll->op_sys_clk_div);
+		dev_dbg(dev, "op_pix_clk_div \t%d\n", pll->op_pix_clk_div);
+	}
+	dev_dbg(dev, "vt_sys_clk_div \t%d\n",  pll->vt_sys_clk_div);
+	dev_dbg(dev, "vt_pix_clk_div \t%d\n",  pll->vt_pix_clk_div);
+
+	dev_dbg(dev, "ext_clk_freq_hz \t%d\n", pll->ext_clk_freq_hz);
+	dev_dbg(dev, "pll_ip_clk_freq_hz \t%d\n", pll->pll_ip_clk_freq_hz);
+	dev_dbg(dev, "pll_op_clk_freq_hz \t%d\n", pll->pll_op_clk_freq_hz);
+	if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+		dev_dbg(dev, "op_sys_clk_freq_hz \t%d\n",
+			pll->op_sys_clk_freq_hz);
+		dev_dbg(dev, "op_pix_clk_freq_hz \t%d\n",
+			pll->op_pix_clk_freq_hz);
+	}
+	dev_dbg(dev, "vt_sys_clk_freq_hz \t%d\n", pll->vt_sys_clk_freq_hz);
+	dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz);
+}
+
+int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
+			 struct smiapp_pll *pll)
+{
+	uint32_t sys_div;
+	uint32_t best_pix_div = INT_MAX >> 1;
+	uint32_t vt_op_binning_div;
+	uint32_t lane_op_clock_ratio;
+	uint32_t mul, div;
+	uint32_t more_mul_min, more_mul_max;
+	uint32_t more_mul_factor;
+	uint32_t min_vt_div, max_vt_div, vt_div;
+	uint32_t min_sys_div, max_sys_div;
+	unsigned int i;
+	int rval;
+
+	if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
+		lane_op_clock_ratio = pll->lanes;
+	else
+		lane_op_clock_ratio = 1;
+	dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
+
+	dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal,
+		pll->binning_vertical);
+
+	/* CSI transfers 2 bits per clock per lane; thus times 2 */
+	pll->pll_op_clk_freq_hz = pll->link_freq * 2
+		* (pll->lanes / lane_op_clock_ratio);
+
+	/* Figure out limits for pre-pll divider based on extclk */
+	dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n",
+		limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+	limits->max_pre_pll_clk_div =
+		min_t(uint16_t, limits->max_pre_pll_clk_div,
+		      clk_div_even(pll->ext_clk_freq_hz /
+				   limits->min_pll_ip_freq_hz));
+	limits->min_pre_pll_clk_div =
+		max_t(uint16_t, limits->min_pre_pll_clk_div,
+		      clk_div_even_up(
+			      DIV_ROUND_UP(pll->ext_clk_freq_hz,
+					   limits->max_pll_ip_freq_hz)));
+	dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
+		limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+
+	i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
+	mul = div_u64(pll->pll_op_clk_freq_hz, i);
+	div = pll->ext_clk_freq_hz / i;
+	dev_dbg(dev, "mul %d / div %d\n", mul, div);
+
+	limits->min_pre_pll_clk_div =
+		max_t(uint16_t, limits->min_pre_pll_clk_div,
+		      clk_div_even_up(
+			      DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
+					   limits->max_pll_op_freq_hz)));
+	dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n",
+		limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+
+	if (limits->min_pre_pll_clk_div > limits->max_pre_pll_clk_div) {
+		dev_err(dev, "unable to compute pre_pll divisor\n");
+		return -EINVAL;
+	}
+
+	pll->pre_pll_clk_div = limits->min_pre_pll_clk_div;
+
+	/*
+	 * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
+	 * too high.
+	 */
+	dev_dbg(dev, "pre_pll_clk_div %d\n", pll->pre_pll_clk_div);
+
+	/* Don't go above max pll multiplier. */
+	more_mul_max = limits->max_pll_multiplier / mul;
+	dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %d\n",
+		more_mul_max);
+	/* Don't go above max pll op frequency. */
+	more_mul_max =
+		min_t(int,
+		      more_mul_max,
+		      limits->max_pll_op_freq_hz
+		      / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
+	dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %d\n",
+		more_mul_max);
+	/* Don't go above the division capability of op sys clock divider. */
+	more_mul_max = min(more_mul_max,
+			   limits->max_op_sys_clk_div * pll->pre_pll_clk_div
+			   / div);
+	dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n",
+		more_mul_max);
+	/* Ensure we won't go above min_pll_multiplier. */
+	more_mul_max = min(more_mul_max,
+			   DIV_ROUND_UP(limits->max_pll_multiplier, mul));
+	dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %d\n",
+		more_mul_max);
+
+	/* Ensure we won't go below min_pll_op_freq_hz. */
+	more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
+				    pll->ext_clk_freq_hz / pll->pre_pll_clk_div
+				    * mul);
+	dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %d\n",
+		more_mul_min);
+	/* Ensure we won't go below min_pll_multiplier. */
+	more_mul_min = max(more_mul_min,
+			   DIV_ROUND_UP(limits->min_pll_multiplier, mul));
+	dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %d\n",
+		more_mul_min);
+
+	if (more_mul_min > more_mul_max) {
+		dev_warn(dev,
+			 "unable to compute more_mul_min and more_mul_max");
+		return -EINVAL;
+	}
+
+	more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
+	dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor);
+	more_mul_factor = lcm(more_mul_factor, limits->min_op_sys_clk_div);
+	dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
+		more_mul_factor);
+	i = roundup(more_mul_min, more_mul_factor);
+	if (!is_one_or_even(i))
+		i <<= 1;
+
+	dev_dbg(dev, "final more_mul: %d\n", i);
+	if (i > more_mul_max) {
+		dev_warn(dev, "final more_mul is bad, max %d", more_mul_max);
+		return -EINVAL;
+	}
+
+	pll->pll_multiplier = mul * i;
+	pll->op_sys_clk_div = div * i / pll->pre_pll_clk_div;
+	dev_dbg(dev, "op_sys_clk_div: %d\n", pll->op_sys_clk_div);
+
+	pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
+		/ pll->pre_pll_clk_div;
+
+	pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
+		* pll->pll_multiplier;
+
+	/* Derive pll_op_clk_freq_hz. */
+	pll->op_sys_clk_freq_hz =
+		pll->pll_op_clk_freq_hz / pll->op_sys_clk_div;
+
+	pll->op_pix_clk_div = pll->bits_per_pixel;
+	dev_dbg(dev, "op_pix_clk_div: %d\n", pll->op_pix_clk_div);
+
+	pll->op_pix_clk_freq_hz =
+		pll->op_sys_clk_freq_hz / pll->op_pix_clk_div;
+
+	/*
+	 * Some sensors perform analogue binning and some do this
+	 * digitally. The ones doing this digitally can be roughly be
+	 * found out using this formula. The ones doing this digitally
+	 * should run at higher clock rate, so smaller divisor is used
+	 * on video timing side.
+	 */
+	if (limits->min_line_length_pck_bin > limits->min_line_length_pck
+	    / pll->binning_horizontal)
+		vt_op_binning_div = pll->binning_horizontal;
+	else
+		vt_op_binning_div = 1;
+	dev_dbg(dev, "vt_op_binning_div: %d\n", vt_op_binning_div);
+
+	/*
+	 * Profile 2 supports vt_pix_clk_div E [4, 10]
+	 *
+	 * Horizontal binning can be used as a base for difference in
+	 * divisors. One must make sure that horizontal blanking is
+	 * enough to accommodate the CSI-2 sync codes.
+	 *
+	 * Take scaling factor into account as well.
+	 *
+	 * Find absolute limits for the factor of vt divider.
+	 */
+	dev_dbg(dev, "scale_m: %d\n", pll->scale_m);
+	min_vt_div = DIV_ROUND_UP(pll->op_pix_clk_div * pll->op_sys_clk_div
+				  * pll->scale_n,
+				  lane_op_clock_ratio * vt_op_binning_div
+				  * pll->scale_m);
+
+	/* Find smallest and biggest allowed vt divisor. */
+	dev_dbg(dev, "min_vt_div: %d\n", min_vt_div);
+	min_vt_div = max(min_vt_div,
+			 DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+				      limits->max_vt_pix_clk_freq_hz));
+	dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n",
+		min_vt_div);
+	min_vt_div = max_t(uint32_t, min_vt_div,
+			   limits->min_vt_pix_clk_div
+			   * limits->min_vt_sys_clk_div);
+	dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div);
+
+	max_vt_div = limits->max_vt_sys_clk_div * limits->max_vt_pix_clk_div;
+	dev_dbg(dev, "max_vt_div: %d\n", max_vt_div);
+	max_vt_div = min(max_vt_div,
+			 DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+				      limits->min_vt_pix_clk_freq_hz));
+	dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n",
+		max_vt_div);
+
+	/*
+	 * Find limitsits for sys_clk_div. Not all values are possible
+	 * with all values of pix_clk_div.
+	 */
+	min_sys_div = limits->min_vt_sys_clk_div;
+	dev_dbg(dev, "min_sys_div: %d\n", min_sys_div);
+	min_sys_div = max(min_sys_div,
+			  DIV_ROUND_UP(min_vt_div,
+				       limits->max_vt_pix_clk_div));
+	dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div);
+	min_sys_div = max(min_sys_div,
+			  pll->pll_op_clk_freq_hz
+			  / limits->max_vt_sys_clk_freq_hz);
+	dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div);
+	min_sys_div = clk_div_even_up(min_sys_div);
+	dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div);
+
+	max_sys_div = limits->max_vt_sys_clk_div;
+	dev_dbg(dev, "max_sys_div: %d\n", max_sys_div);
+	max_sys_div = min(max_sys_div,
+			  DIV_ROUND_UP(max_vt_div,
+				       limits->min_vt_pix_clk_div));
+	dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div);
+	max_sys_div = min(max_sys_div,
+			  DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+				       limits->min_vt_pix_clk_freq_hz));
+	dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div);
+
+	/*
+	 * Find pix_div such that a legal pix_div * sys_div results
+	 * into a value which is not smaller than div, the desired
+	 * divisor.
+	 */
+	for (vt_div = min_vt_div; vt_div <= max_vt_div;
+	     vt_div += 2 - (vt_div & 1)) {
+		for (sys_div = min_sys_div;
+		     sys_div <= max_sys_div;
+		     sys_div += 2 - (sys_div & 1)) {
+			int pix_div = DIV_ROUND_UP(vt_div, sys_div);
+
+			if (pix_div < limits->min_vt_pix_clk_div
+			    || pix_div > limits->max_vt_pix_clk_div) {
+				dev_dbg(dev,
+					"pix_div %d too small or too big (%d--%d)\n",
+					pix_div,
+					limits->min_vt_pix_clk_div,
+					limits->max_vt_pix_clk_div);
+				continue;
+			}
+
+			/* Check if this one is better. */
+			if (pix_div * sys_div
+			    <= roundup(min_vt_div, best_pix_div))
+				best_pix_div = pix_div;
+		}
+		if (best_pix_div < INT_MAX >> 1)
+			break;
+	}
+
+	pll->vt_sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
+	pll->vt_pix_clk_div = best_pix_div;
+
+	pll->vt_sys_clk_freq_hz =
+		pll->pll_op_clk_freq_hz / pll->vt_sys_clk_div;
+	pll->vt_pix_clk_freq_hz =
+		pll->vt_sys_clk_freq_hz / pll->vt_pix_clk_div;
+
+	pll->pixel_rate_csi =
+		pll->op_pix_clk_freq_hz * lane_op_clock_ratio;
+
+	print_pll(dev, pll);
+
+	rval = bounds_check(dev, pll->pre_pll_clk_div,
+			    limits->min_pre_pll_clk_div,
+			    limits->max_pre_pll_clk_div, "pre_pll_clk_div");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->pll_ip_clk_freq_hz,
+			limits->min_pll_ip_freq_hz, limits->max_pll_ip_freq_hz,
+			"pll_ip_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->pll_multiplier,
+			limits->min_pll_multiplier, limits->max_pll_multiplier,
+			"pll_multiplier");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->pll_op_clk_freq_hz,
+			limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
+			"pll_op_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->op_sys_clk_div,
+			limits->min_op_sys_clk_div, limits->max_op_sys_clk_div,
+			"op_sys_clk_div");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->op_pix_clk_div,
+			limits->min_op_pix_clk_div, limits->max_op_pix_clk_div,
+			"op_pix_clk_div");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->op_sys_clk_freq_hz,
+			limits->min_op_sys_clk_freq_hz,
+			limits->max_op_sys_clk_freq_hz,
+			"op_sys_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->op_pix_clk_freq_hz,
+			limits->min_op_pix_clk_freq_hz,
+			limits->max_op_pix_clk_freq_hz,
+			"op_pix_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->vt_sys_clk_freq_hz,
+			limits->min_vt_sys_clk_freq_hz,
+			limits->max_vt_sys_clk_freq_hz,
+			"vt_sys_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->vt_pix_clk_freq_hz,
+			limits->min_vt_pix_clk_freq_hz,
+			limits->max_vt_pix_clk_freq_hz,
+			"vt_pix_clk_freq_hz");
+
+	return rval;
+}
+EXPORT_SYMBOL_GPL(smiapp_pll_calculate);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
+MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/smiapp-pll.h b/drivers/media/video/smiapp-pll.h
new file mode 100644
index 0000000..9eab63f
--- /dev/null
+++ b/drivers/media/video/smiapp-pll.h
@@ -0,0 +1,103 @@
+/*
+ * drivers/media/video/smiapp-pll.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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 SMIAPP_PLL_H
+#define SMIAPP_PLL_H
+
+#include <linux/device.h>
+
+struct smiapp_pll {
+	uint8_t lanes;
+	uint8_t binning_horizontal;
+	uint8_t binning_vertical;
+	uint8_t scale_m;
+	uint8_t scale_n;
+	uint8_t bits_per_pixel;
+	uint16_t flags;
+	uint32_t link_freq;
+
+	uint16_t pre_pll_clk_div;
+	uint16_t pll_multiplier;
+	uint16_t op_sys_clk_div;
+	uint16_t op_pix_clk_div;
+	uint16_t vt_sys_clk_div;
+	uint16_t vt_pix_clk_div;
+
+	uint32_t ext_clk_freq_hz;
+	uint32_t pll_ip_clk_freq_hz;
+	uint32_t pll_op_clk_freq_hz;
+	uint32_t op_sys_clk_freq_hz;
+	uint32_t op_pix_clk_freq_hz;
+	uint32_t vt_sys_clk_freq_hz;
+	uint32_t vt_pix_clk_freq_hz;
+
+	uint32_t pixel_rate_csi;
+};
+
+struct smiapp_pll_limits {
+	/* Strict PLL limits */
+	uint32_t min_ext_clk_freq_hz;
+	uint32_t max_ext_clk_freq_hz;
+	uint16_t min_pre_pll_clk_div;
+	uint16_t max_pre_pll_clk_div;
+	uint32_t min_pll_ip_freq_hz;
+	uint32_t max_pll_ip_freq_hz;
+	uint16_t min_pll_multiplier;
+	uint16_t max_pll_multiplier;
+	uint32_t min_pll_op_freq_hz;
+	uint32_t max_pll_op_freq_hz;
+
+	uint16_t min_vt_sys_clk_div;
+	uint16_t max_vt_sys_clk_div;
+	uint32_t min_vt_sys_clk_freq_hz;
+	uint32_t max_vt_sys_clk_freq_hz;
+	uint16_t min_vt_pix_clk_div;
+	uint16_t max_vt_pix_clk_div;
+	uint32_t min_vt_pix_clk_freq_hz;
+	uint32_t max_vt_pix_clk_freq_hz;
+
+	uint16_t min_op_sys_clk_div;
+	uint16_t max_op_sys_clk_div;
+	uint32_t min_op_sys_clk_freq_hz;
+	uint32_t max_op_sys_clk_freq_hz;
+	uint16_t min_op_pix_clk_div;
+	uint16_t max_op_pix_clk_div;
+	uint32_t min_op_pix_clk_freq_hz;
+	uint32_t max_op_pix_clk_freq_hz;
+
+	/* Other relevant limits */
+	uint32_t min_line_length_pck_bin;
+	uint32_t min_line_length_pck;
+};
+
+/* op pix clock is for all lanes in total normally */
+#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE			(1 << 0)
+#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS				(1 << 1)
+
+struct device;
+
+int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
+			 struct smiapp_pll *pll);
+
+#endif /* SMIAPP_PLL_H */
diff --git a/drivers/media/video/smiapp/Kconfig b/drivers/media/video/smiapp/Kconfig
new file mode 100644
index 0000000..f7b35ff
--- /dev/null
+++ b/drivers/media/video/smiapp/Kconfig
@@ -0,0 +1,6 @@
+config VIDEO_SMIAPP
+	tristate "SMIA++/SMIA sensor support"
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	select VIDEO_SMIAPP_PLL
+	---help---
+	  This is a generic driver for SMIA++/SMIA camera modules.
diff --git a/drivers/media/video/smiapp/Makefile b/drivers/media/video/smiapp/Makefile
new file mode 100644
index 0000000..36b0cfa
--- /dev/null
+++ b/drivers/media/video/smiapp/Makefile
@@ -0,0 +1,5 @@
+smiapp-objs			+= smiapp-core.o smiapp-regs.o \
+				   smiapp-quirk.o smiapp-limits.o
+obj-$(CONFIG_VIDEO_SMIAPP)	+= smiapp.o
+
+ccflags-y += -Idrivers/media/video
diff --git a/drivers/media/video/smiapp/smiapp-core.c b/drivers/media/video/smiapp/smiapp-core.c
new file mode 100644
index 0000000..f518026
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-core.c
@@ -0,0 +1,2894 @@
+/*
+ * drivers/media/video/smiapp/smiapp-core.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Based on smiapp driver by Vimarsh Zutshi
+ * Based on jt8ev1.c by Vimarsh Zutshi
+ * Based on smia-sensor.c by Tuukka Toivonen <tuukkat76@gmail.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
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+
+#include "smiapp.h"
+
+#define SMIAPP_ALIGN_DIM(dim, flags)		\
+	((flags) & V4L2_SUBDEV_SEL_FLAG_SIZE_GE	\
+	 ? ALIGN((dim), 2)			\
+	 : (dim) & ~1)
+
+/*
+ * smiapp_module_idents - supported camera modules
+ */
+static const struct smiapp_module_ident smiapp_module_idents[] = {
+	SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"),
+	SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"),
+	SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"),
+	SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"),
+	SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"),
+	SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk),
+	SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"),
+	SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"),
+	SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk),
+	SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk),
+	SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk),
+};
+
+/*
+ *
+ * Dynamic Capability Identification
+ *
+ */
+
+static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc;
+	unsigned int i;
+	int rval;
+	int line_count = 0;
+	int embedded_start = -1, embedded_end = -1;
+	int image_start = 0;
+
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE,
+			   &fmt_model_type);
+	if (rval)
+		return rval;
+
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE,
+			   &fmt_model_subtype);
+	if (rval)
+		return rval;
+
+	ncol_desc = (fmt_model_subtype
+		     & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK)
+		>> SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT;
+	nrow_desc = fmt_model_subtype
+		& SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK;
+
+	dev_dbg(&client->dev, "format_model_type %s\n",
+		fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE
+		? "2 byte" :
+		fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE
+		? "4 byte" : "is simply bad");
+
+	for (i = 0; i < ncol_desc + nrow_desc; i++) {
+		u32 desc;
+		u32 pixelcode;
+		u32 pixels;
+		char *which;
+		char *what;
+
+		if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) {
+			rval = smiapp_read(
+				sensor,
+				SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i),
+				&desc);
+			if (rval)
+				return rval;
+
+			pixelcode =
+				(desc
+				 & SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK)
+				>> SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT;
+			pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK;
+		} else if (fmt_model_type
+			   == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) {
+			rval = smiapp_read(
+				sensor,
+				SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i),
+				&desc);
+			if (rval)
+				return rval;
+
+			pixelcode =
+				(desc
+				 & SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK)
+				>> SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT;
+			pixels = desc & SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK;
+		} else {
+			dev_dbg(&client->dev,
+				"invalid frame format model type %d\n",
+				fmt_model_type);
+			return -EINVAL;
+		}
+
+		if (i < ncol_desc)
+			which = "columns";
+		else
+			which = "rows";
+
+		switch (pixelcode) {
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED:
+			what = "embedded";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY:
+			what = "dummy";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK:
+			what = "black";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK:
+			what = "dark";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE:
+			what = "visible";
+			break;
+		default:
+			what = "invalid";
+			dev_dbg(&client->dev, "pixelcode %d\n", pixelcode);
+			break;
+		}
+
+		dev_dbg(&client->dev, "%s pixels: %d %s\n",
+			what, pixels, which);
+
+		if (i < ncol_desc)
+			continue;
+
+		/* Handle row descriptors */
+		if (pixelcode
+		    == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED) {
+			embedded_start = line_count;
+		} else {
+			if (pixelcode == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE
+			    || pixels >= sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES] / 2)
+				image_start = line_count;
+			if (embedded_start != -1 && embedded_end == -1)
+				embedded_end = line_count;
+		}
+		line_count += pixels;
+	}
+
+	if (embedded_start == -1 || embedded_end == -1) {
+		embedded_start = 0;
+		embedded_end = 0;
+	}
+
+	dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
+		embedded_start, embedded_end);
+	dev_dbg(&client->dev, "image data starts at line %d\n", image_start);
+
+	return 0;
+}
+
+static int smiapp_pll_configure(struct smiapp_sensor *sensor)
+{
+	struct smiapp_pll *pll = &sensor->pll;
+	int rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt_pix_clk_div);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt_sys_clk_div);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_PRE_PLL_CLK_DIV, pll->pre_pll_clk_div);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_PLL_MULTIPLIER, pll->pll_multiplier);
+	if (rval < 0)
+		return rval;
+
+	/* Lane op clock ratio does not apply here. */
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS,
+		DIV_ROUND_UP(pll->op_sys_clk_freq_hz, 1000000 / 256 / 256));
+	if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
+		return rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op_pix_clk_div);
+	if (rval < 0)
+		return rval;
+
+	return smiapp_write(
+		sensor, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op_sys_clk_div);
+}
+
+static int smiapp_pll_update(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct smiapp_pll_limits lim = {
+		.min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV],
+		.max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV],
+		.min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ],
+		.max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ],
+		.min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER],
+		.max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER],
+		.min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ],
+		.max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ],
+
+		.min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV],
+		.max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV],
+		.min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV],
+		.max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV],
+		.min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ],
+		.max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ],
+		.min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ],
+		.max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ],
+
+		.min_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV],
+		.max_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV],
+		.min_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV],
+		.max_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV],
+		.min_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ],
+		.max_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ],
+		.min_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ],
+		.max_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ],
+
+		.min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN],
+		.min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK],
+	};
+	struct smiapp_pll *pll = &sensor->pll;
+	int rval;
+
+	memset(&sensor->pll, 0, sizeof(sensor->pll));
+
+	pll->lanes = sensor->platform_data->lanes;
+	pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
+
+	if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) {
+		/*
+		 * Fill in operational clock divisors limits from the
+		 * video timing ones. On profile 0 sensors the
+		 * requirements regarding them are essentially the
+		 * same as on VT ones.
+		 */
+		lim.min_op_sys_clk_div = lim.min_vt_sys_clk_div;
+		lim.max_op_sys_clk_div = lim.max_vt_sys_clk_div;
+		lim.min_op_pix_clk_div = lim.min_vt_pix_clk_div;
+		lim.max_op_pix_clk_div = lim.max_vt_pix_clk_div;
+		lim.min_op_sys_clk_freq_hz = lim.min_vt_sys_clk_freq_hz;
+		lim.max_op_sys_clk_freq_hz = lim.max_vt_sys_clk_freq_hz;
+		lim.min_op_pix_clk_freq_hz = lim.min_vt_pix_clk_freq_hz;
+		lim.max_op_pix_clk_freq_hz = lim.max_vt_pix_clk_freq_hz;
+		/* Profile 0 sensors have no separate OP clock branch. */
+		pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
+	}
+
+	if (smiapp_needs_quirk(sensor,
+			       SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE))
+		pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+
+	pll->binning_horizontal = sensor->binning_horizontal;
+	pll->binning_vertical = sensor->binning_vertical;
+	pll->link_freq =
+		sensor->link_freq->qmenu_int[sensor->link_freq->val];
+	pll->scale_m = sensor->scale_m;
+	pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+	pll->bits_per_pixel = sensor->csi_format->compressed;
+
+	rval = smiapp_pll_calculate(&client->dev, &lim, pll);
+	if (rval < 0)
+		return rval;
+
+	sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz;
+	sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi;
+
+	return 0;
+}
+
+
+/*
+ *
+ * V4L2 Controls handling
+ *
+ */
+
+static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
+{
+	struct v4l2_ctrl *ctrl = sensor->exposure;
+	int max;
+
+	max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+		+ sensor->vblank->val
+		- sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
+
+	ctrl->maximum = max;
+	if (ctrl->default_value > max)
+		ctrl->default_value = max;
+	if (ctrl->val > max)
+		ctrl->val = max;
+	if (ctrl->cur.val > max)
+		ctrl->cur.val = max;
+}
+
+/*
+ * Order matters.
+ *
+ * 1. Bits-per-pixel, descending.
+ * 2. Bits-per-pixel compressed, descending.
+ * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel
+ *    orders must be defined.
+ */
+static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = {
+	{ V4L2_MBUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, },
+	{ V4L2_MBUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, },
+	{ V4L2_MBUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, },
+	{ V4L2_MBUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, },
+	{ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+	{ V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+	{ V4L2_MBUS_FMT_SGRBG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+	{ V4L2_MBUS_FMT_SBGGR8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+};
+
+const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
+
+#define to_csi_format_idx(fmt) (((unsigned long)(fmt)			\
+				 - (unsigned long)smiapp_csi_data_formats) \
+				/ sizeof(*smiapp_csi_data_formats))
+
+static u32 smiapp_pixel_order(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int flip = 0;
+
+	if (sensor->hflip) {
+		if (sensor->hflip->val)
+			flip |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
+
+		if (sensor->vflip->val)
+			flip |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
+	}
+
+	flip ^= sensor->hvflip_inv_mask;
+
+	dev_dbg(&client->dev, "flip %d\n", flip);
+	return sensor->default_pixel_order ^ flip;
+}
+
+static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int csi_format_idx =
+		to_csi_format_idx(sensor->csi_format) & ~3;
+	unsigned int internal_csi_format_idx =
+		to_csi_format_idx(sensor->internal_csi_format) & ~3;
+	unsigned int pixel_order = smiapp_pixel_order(sensor);
+
+	sensor->mbus_frame_fmts =
+		sensor->default_mbus_frame_fmts << pixel_order;
+	sensor->csi_format =
+		&smiapp_csi_data_formats[csi_format_idx + pixel_order];
+	sensor->internal_csi_format =
+		&smiapp_csi_data_formats[internal_csi_format_idx
+					 + pixel_order];
+
+	BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order
+	       >= ARRAY_SIZE(smiapp_csi_data_formats));
+	BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0);
+
+	dev_dbg(&client->dev, "new pixel order %s\n",
+		pixel_order_str[pixel_order]);
+}
+
+static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct smiapp_sensor *sensor =
+		container_of(ctrl->handler, struct smiapp_subdev, ctrl_handler)
+			->sensor;
+	u32 orient = 0;
+	int exposure;
+	int rval;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ANALOGUE_GAIN:
+		return smiapp_write(
+			sensor,
+			SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL, ctrl->val);
+
+	case V4L2_CID_EXPOSURE:
+		return smiapp_write(
+			sensor,
+			SMIAPP_REG_U16_COARSE_INTEGRATION_TIME, ctrl->val);
+
+	case V4L2_CID_HFLIP:
+	case V4L2_CID_VFLIP:
+		if (sensor->streaming)
+			return -EBUSY;
+
+		if (sensor->hflip->val)
+			orient |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
+
+		if (sensor->vflip->val)
+			orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+		orient ^= sensor->hvflip_inv_mask;
+		rval = smiapp_write(sensor,
+				    SMIAPP_REG_U8_IMAGE_ORIENTATION,
+				    orient);
+		if (rval < 0)
+			return rval;
+
+		smiapp_update_mbus_formats(sensor);
+
+		return 0;
+
+	case V4L2_CID_VBLANK:
+		exposure = sensor->exposure->val;
+
+		__smiapp_update_exposure_limits(sensor);
+
+		if (exposure > sensor->exposure->maximum) {
+			sensor->exposure->val =
+				sensor->exposure->maximum;
+			rval = smiapp_set_ctrl(
+				sensor->exposure);
+			if (rval < 0)
+				return rval;
+		}
+
+		return smiapp_write(
+			sensor, SMIAPP_REG_U16_FRAME_LENGTH_LINES,
+			sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+			+ ctrl->val);
+
+	case V4L2_CID_HBLANK:
+		return smiapp_write(
+			sensor, SMIAPP_REG_U16_LINE_LENGTH_PCK,
+			sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
+			+ ctrl->val);
+
+	case V4L2_CID_LINK_FREQ:
+		if (sensor->streaming)
+			return -EBUSY;
+
+		return smiapp_pll_update(sensor);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
+	.s_ctrl = smiapp_set_ctrl,
+};
+
+static int smiapp_init_controls(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int max;
+	int rval;
+
+	rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7);
+	if (rval)
+		return rval;
+	sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
+
+	sensor->analog_gain = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_ANALOGUE_GAIN,
+		sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN],
+		sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX],
+		max(sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1U),
+		sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]);
+
+	/* Exposure limits will be updated soon, use just something here. */
+	sensor->exposure = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_EXPOSURE, 0, 0, 1, 0);
+
+	sensor->hflip = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_HFLIP, 0, 1, 1, 0);
+	sensor->vflip = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	sensor->vblank = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_VBLANK, 0, 1, 1, 0);
+
+	if (sensor->vblank)
+		sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+	sensor->hblank = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_HBLANK, 0, 1, 1, 0);
+
+	if (sensor->hblank)
+		sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+	sensor->pixel_rate_parray = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+
+	if (sensor->pixel_array->ctrl_handler.error) {
+		dev_err(&client->dev,
+			"pixel array controls initialization failed (%d)\n",
+			sensor->pixel_array->ctrl_handler.error);
+		rval = sensor->pixel_array->ctrl_handler.error;
+		goto error;
+	}
+
+	sensor->pixel_array->sd.ctrl_handler =
+		&sensor->pixel_array->ctrl_handler;
+
+	v4l2_ctrl_cluster(2, &sensor->hflip);
+
+	rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0);
+	if (rval)
+		goto error;
+	sensor->src->ctrl_handler.lock = &sensor->mutex;
+
+	for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++);
+
+	sensor->link_freq = v4l2_ctrl_new_int_menu(
+		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_LINK_FREQ, max, 0,
+		sensor->platform_data->op_sys_clock);
+
+	sensor->pixel_rate_csi = v4l2_ctrl_new_std(
+		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+
+	if (sensor->src->ctrl_handler.error) {
+		dev_err(&client->dev,
+			"src controls initialization failed (%d)\n",
+			sensor->src->ctrl_handler.error);
+		rval = sensor->src->ctrl_handler.error;
+		goto error;
+	}
+
+	sensor->src->sd.ctrl_handler =
+		&sensor->src->ctrl_handler;
+
+	return 0;
+
+error:
+	v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler);
+	v4l2_ctrl_handler_free(&sensor->src->ctrl_handler);
+
+	return rval;
+}
+
+static void smiapp_free_controls(struct smiapp_sensor *sensor)
+{
+	unsigned int i;
+
+	for (i = 0; i < sensor->ssds_used; i++)
+		v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler);
+}
+
+static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
+			     unsigned int n)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int i;
+	u32 val;
+	int rval;
+
+	for (i = 0; i < n; i++) {
+		rval = smiapp_read(
+			sensor, smiapp_reg_limits[limit[i]].addr, &val);
+		if (rval)
+			return rval;
+		sensor->limits[limit[i]] = val;
+		dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n",
+			smiapp_reg_limits[limit[i]].addr,
+			smiapp_reg_limits[limit[i]].what, val, val);
+	}
+
+	return 0;
+}
+
+static int smiapp_get_all_limits(struct smiapp_sensor *sensor)
+{
+	unsigned int i;
+	int rval;
+
+	for (i = 0; i < SMIAPP_LIMIT_LAST; i++) {
+		rval = smiapp_get_limits(sensor, &i, 1);
+		if (rval < 0)
+			return rval;
+	}
+
+	if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0)
+		smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16);
+
+	return 0;
+}
+
+static int smiapp_get_limits_binning(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	static u32 const limits[] = {
+		SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN,
+		SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN,
+		SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN,
+		SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN,
+		SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN,
+	};
+	static u32 const limits_replace[] = {
+		SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES,
+		SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES,
+		SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK,
+		SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK,
+		SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN,
+	};
+	unsigned int i;
+	int rval;
+
+	if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY] ==
+	    SMIAPP_BINNING_CAPABILITY_NO) {
+		for (i = 0; i < ARRAY_SIZE(limits); i++)
+			sensor->limits[limits[i]] =
+				sensor->limits[limits_replace[i]];
+
+		return 0;
+	}
+
+	rval = smiapp_get_limits(sensor, limits, ARRAY_SIZE(limits));
+	if (rval < 0)
+		return rval;
+
+	/*
+	 * Sanity check whether the binning limits are valid. If not,
+	 * use the non-binning ones.
+	 */
+	if (sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN]
+	    && sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN]
+	    && sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN])
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(limits); i++) {
+		dev_dbg(&client->dev,
+			"replace limit 0x%8.8x \"%s\" = %d, 0x%x\n",
+			smiapp_reg_limits[limits[i]].addr,
+			smiapp_reg_limits[limits[i]].what,
+			sensor->limits[limits_replace[i]],
+			sensor->limits[limits_replace[i]]);
+		sensor->limits[limits[i]] =
+			sensor->limits[limits_replace[i]];
+	}
+
+	return 0;
+}
+
+static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int type, n;
+	unsigned int i, pixel_order;
+	int rval;
+
+	rval = smiapp_read(
+		sensor, SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE, &type);
+	if (rval)
+		return rval;
+
+	dev_dbg(&client->dev, "data_format_model_type %d\n", type);
+
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_PIXEL_ORDER,
+			   &pixel_order);
+	if (rval)
+		return rval;
+
+	if (pixel_order >= ARRAY_SIZE(pixel_order_str)) {
+		dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order);
+		return -EINVAL;
+	}
+
+	dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order,
+		pixel_order_str[pixel_order]);
+
+	switch (type) {
+	case SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL:
+		n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N;
+		break;
+	case SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED:
+		n = SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	sensor->default_pixel_order = pixel_order;
+	sensor->mbus_frame_fmts = 0;
+
+	for (i = 0; i < n; i++) {
+		unsigned int fmt, j;
+
+		rval = smiapp_read(
+			sensor,
+			SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(i), &fmt);
+		if (rval)
+			return rval;
+
+		dev_dbg(&client->dev, "bpp %d, compressed %d\n",
+			fmt >> 8, (u8)fmt);
+
+		for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) {
+			const struct smiapp_csi_data_format *f =
+				&smiapp_csi_data_formats[j];
+
+			if (f->pixel_order != SMIAPP_PIXEL_ORDER_GRBG)
+				continue;
+
+			if (f->width != fmt >> 8 || f->compressed != (u8)fmt)
+				continue;
+
+			dev_dbg(&client->dev, "jolly good! %d\n", j);
+
+			sensor->default_mbus_frame_fmts |= 1 << j;
+			if (!sensor->csi_format) {
+				sensor->csi_format = f;
+				sensor->internal_csi_format = f;
+			}
+		}
+	}
+
+	if (!sensor->csi_format) {
+		dev_err(&client->dev, "no supported mbus code found\n");
+		return -EINVAL;
+	}
+
+	smiapp_update_mbus_formats(sensor);
+
+	return 0;
+}
+
+static void smiapp_update_blanking(struct smiapp_sensor *sensor)
+{
+	struct v4l2_ctrl *vblank = sensor->vblank;
+	struct v4l2_ctrl *hblank = sensor->hblank;
+
+	vblank->minimum =
+		max_t(int,
+		      sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
+		      sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
+		      sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
+	vblank->maximum =
+		sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
+		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
+
+	vblank->val = clamp_t(int, vblank->val,
+			      vblank->minimum, vblank->maximum);
+	vblank->default_value = vblank->minimum;
+	vblank->val = vblank->val;
+	vblank->cur.val = vblank->val;
+
+	hblank->minimum =
+		max_t(int,
+		      sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
+		      sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
+		      sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
+	hblank->maximum =
+		sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
+		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width;
+
+	hblank->val = clamp_t(int, hblank->val,
+			      hblank->minimum, hblank->maximum);
+	hblank->default_value = hblank->minimum;
+	hblank->val = hblank->val;
+	hblank->cur.val = hblank->val;
+
+	__smiapp_update_exposure_limits(sensor);
+}
+
+static int smiapp_update_mode(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int binning_mode;
+	int rval;
+
+	dev_dbg(&client->dev, "frame size: %dx%d\n",
+		sensor->src->crop[SMIAPP_PAD_SRC].width,
+		sensor->src->crop[SMIAPP_PAD_SRC].height);
+	dev_dbg(&client->dev, "csi format width: %d\n",
+		sensor->csi_format->width);
+
+	/* Binning has to be set up here; it affects limits */
+	if (sensor->binning_horizontal == 1 &&
+	    sensor->binning_vertical == 1) {
+		binning_mode = 0;
+	} else {
+		u8 binning_type =
+			(sensor->binning_horizontal << 4)
+			| sensor->binning_vertical;
+
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U8_BINNING_TYPE, binning_type);
+		if (rval < 0)
+			return rval;
+
+		binning_mode = 1;
+	}
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_BINNING_MODE, binning_mode);
+	if (rval < 0)
+		return rval;
+
+	/* Get updated limits due to binning */
+	rval = smiapp_get_limits_binning(sensor);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_pll_update(sensor);
+	if (rval < 0)
+		return rval;
+
+	/* Output from pixel array, including blanking */
+	smiapp_update_blanking(sensor);
+
+	dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val);
+	dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val);
+
+	dev_dbg(&client->dev, "real timeperframe\t100/%d\n",
+		sensor->pll.vt_pix_clk_freq_hz /
+		((sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
+		  + sensor->hblank->val) *
+		 (sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+		  + sensor->vblank->val) / 100));
+
+	return 0;
+}
+
+/*
+ *
+ * SMIA++ NVM handling
+ *
+ */
+static int smiapp_read_nvm(struct smiapp_sensor *sensor,
+			   unsigned char *nvm)
+{
+	u32 i, s, p, np, v;
+	int rval = 0, rval2;
+
+	np = sensor->nvm_size / SMIAPP_NVM_PAGE_SIZE;
+	for (p = 0; p < np; p++) {
+		rval = smiapp_write(
+			sensor,
+			SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p);
+		if (rval)
+			goto out;
+
+		rval = smiapp_write(sensor,
+				    SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL,
+				    SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN |
+				    SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN);
+		if (rval)
+			goto out;
+
+		for (i = 0; i < 1000; i++) {
+			rval = smiapp_read(
+				sensor,
+				SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s);
+
+			if (rval)
+				goto out;
+
+			if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
+				break;
+
+			if (--i == 0) {
+				rval = -ETIMEDOUT;
+				goto out;
+			}
+
+		}
+
+		for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) {
+			rval = smiapp_read(
+				sensor,
+				SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i,
+				&v);
+			if (rval)
+				goto out;
+
+			*nvm++ = v;
+		}
+	}
+
+out:
+	rval2 = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0);
+	if (rval < 0)
+		return rval;
+	else
+		return rval2;
+}
+
+/*
+ *
+ * SMIA++ CCI address control
+ *
+ */
+static int smiapp_change_cci_addr(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+	u32 val;
+
+	client->addr = sensor->platform_data->i2c_addr_dfl;
+
+	rval = smiapp_write(sensor,
+			    SMIAPP_REG_U8_CCI_ADDRESS_CONTROL,
+			    sensor->platform_data->i2c_addr_alt << 1);
+	if (rval)
+		return rval;
+
+	client->addr = sensor->platform_data->i2c_addr_alt;
+
+	/* verify addr change went ok */
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val);
+	if (rval)
+		return rval;
+
+	if (val != sensor->platform_data->i2c_addr_alt << 1)
+		return -ENODEV;
+
+	return 0;
+}
+
+/*
+ *
+ * SMIA++ Mode Control
+ *
+ */
+static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor)
+{
+	struct smiapp_flash_strobe_parms *strobe_setup;
+	unsigned int ext_freq = sensor->platform_data->ext_clk;
+	u32 tmp;
+	u32 strobe_adjustment;
+	u32 strobe_width_high_rs;
+	int rval;
+
+	strobe_setup = sensor->platform_data->strobe_setup;
+
+	/*
+	 * How to calculate registers related to strobe length. Please
+	 * do not change, or if you do at least know what you're
+	 * doing. :-)
+	 *
+	 * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25
+	 *
+	 * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl
+	 *	/ EXTCLK freq [Hz]) * flash_strobe_adjustment
+	 *
+	 * tFlash_strobe_width_ctrl E N, [1 - 0xffff]
+	 * flash_strobe_adjustment E N, [1 - 0xff]
+	 *
+	 * The formula above is written as below to keep it on one
+	 * line:
+	 *
+	 * l / 10^6 = w / e * a
+	 *
+	 * Let's mark w * a by x:
+	 *
+	 * x = w * a
+	 *
+	 * Thus, we get:
+	 *
+	 * x = l * e / 10^6
+	 *
+	 * The strobe width must be at least as long as requested,
+	 * thus rounding upwards is needed.
+	 *
+	 * x = (l * e + 10^6 - 1) / 10^6
+	 * -----------------------------
+	 *
+	 * Maximum possible accuracy is wanted at all times. Thus keep
+	 * a as small as possible.
+	 *
+	 * Calculate a, assuming maximum w, with rounding upwards:
+	 *
+	 * a = (x + (2^16 - 1) - 1) / (2^16 - 1)
+	 * -------------------------------------
+	 *
+	 * Thus, we also get w, with that a, with rounding upwards:
+	 *
+	 * w = (x + a - 1) / a
+	 * -------------------
+	 *
+	 * To get limits:
+	 *
+	 * x E [1, (2^16 - 1) * (2^8 - 1)]
+	 *
+	 * Substituting maximum x to the original formula (with rounding),
+	 * the maximum l is thus
+	 *
+	 * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1
+	 *
+	 * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e
+	 * --------------------------------------------------
+	 *
+	 * flash_strobe_length must be clamped between 1 and
+	 * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq.
+	 *
+	 * Then,
+	 *
+	 * flash_strobe_adjustment = ((flash_strobe_length *
+	 *	EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1)
+	 *
+	 * tFlash_strobe_width_ctrl = ((flash_strobe_length *
+	 *	EXTCLK freq + 10^6 - 1) / 10^6 +
+	 *	flash_strobe_adjustment - 1) / flash_strobe_adjustment
+	 */
+	tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) -
+		      1000000 + 1, ext_freq);
+	strobe_setup->strobe_width_high_us =
+		clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp);
+
+	tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq +
+			1000000 - 1), 1000000ULL);
+	strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1);
+	strobe_width_high_rs = (tmp + strobe_adjustment - 1) /
+				strobe_adjustment;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_MODE_RS,
+			    strobe_setup->mode);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT,
+			    strobe_adjustment);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL,
+		strobe_width_high_rs);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL,
+			    strobe_setup->strobe_delay);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_FLASH_STROBE_START_POINT,
+			    strobe_setup->stobe_start_point);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_TRIGGER_RS,
+			    strobe_setup->trigger);
+
+out:
+	sensor->platform_data->strobe_setup->trigger = 0;
+
+	return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+static int smiapp_power_on(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int sleep;
+	int rval;
+
+	rval = regulator_enable(sensor->vana);
+	if (rval) {
+		dev_err(&client->dev, "failed to enable vana regulator\n");
+		return rval;
+	}
+	usleep_range(1000, 1000);
+
+	if (sensor->platform_data->set_xclk)
+		rval = sensor->platform_data->set_xclk(
+			&sensor->src->sd, sensor->platform_data->ext_clk);
+	else
+		rval = clk_enable(sensor->ext_clk);
+	if (rval < 0) {
+		dev_dbg(&client->dev, "failed to set xclk\n");
+		goto out_xclk_fail;
+	}
+	usleep_range(1000, 1000);
+
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_set_value(sensor->platform_data->xshutdown, 1);
+
+	sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk);
+	usleep_range(sleep, sleep);
+
+	/*
+	 * Failures to respond to the address change command have been noticed.
+	 * Those failures seem to be caused by the sensor requiring a longer
+	 * boot time than advertised. An additional 10ms delay seems to work
+	 * around the issue, but the SMIA++ I2C write retry hack makes the delay
+	 * unnecessary. The failures need to be investigated to find a proper
+	 * fix, and a delay will likely need to be added here if the I2C write
+	 * retry hack is reverted before the root cause of the boot time issue
+	 * is found.
+	 */
+
+	if (sensor->platform_data->i2c_addr_alt) {
+		rval = smiapp_change_cci_addr(sensor);
+		if (rval) {
+			dev_err(&client->dev, "cci address change error\n");
+			goto out_cci_addr_fail;
+		}
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_SOFTWARE_RESET,
+			    SMIAPP_SOFTWARE_RESET);
+	if (rval < 0) {
+		dev_err(&client->dev, "software reset failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	if (sensor->platform_data->i2c_addr_alt) {
+		rval = smiapp_change_cci_addr(sensor);
+		if (rval) {
+			dev_err(&client->dev, "cci address change error\n");
+			goto out_cci_addr_fail;
+		}
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_COMPRESSION_MODE,
+			    SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR);
+	if (rval) {
+		dev_err(&client->dev, "compression mode set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ,
+		sensor->platform_data->ext_clk / (1000000 / (1 << 8)));
+	if (rval) {
+		dev_err(&client->dev, "extclk frequency set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE,
+			    sensor->platform_data->lanes - 1);
+	if (rval) {
+		dev_err(&client->dev, "csi lane mode set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_FAST_STANDBY_CTRL,
+			    SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE);
+	if (rval) {
+		dev_err(&client->dev, "fast standby set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE,
+			    sensor->platform_data->csi_signalling_mode);
+	if (rval) {
+		dev_err(&client->dev, "csi signalling mode set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	/* DPHY control done by sensor based on requested link rate */
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL,
+			    SMIAPP_DPHY_CTRL_UI);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_call_quirk(sensor, post_poweron);
+	if (rval) {
+		dev_err(&client->dev, "post_poweron quirks failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	/* Are we still initialising...? If yes, return here. */
+	if (!sensor->pixel_array)
+		return 0;
+
+	rval = v4l2_ctrl_handler_setup(
+		&sensor->pixel_array->ctrl_handler);
+	if (rval)
+		goto out_cci_addr_fail;
+
+	rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
+	if (rval)
+		goto out_cci_addr_fail;
+
+	mutex_lock(&sensor->mutex);
+	rval = smiapp_update_mode(sensor);
+	mutex_unlock(&sensor->mutex);
+	if (rval < 0)
+		goto out_cci_addr_fail;
+
+	return 0;
+
+out_cci_addr_fail:
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_set_value(sensor->platform_data->xshutdown, 0);
+	if (sensor->platform_data->set_xclk)
+		sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+	else
+		clk_disable(sensor->ext_clk);
+
+out_xclk_fail:
+	regulator_disable(sensor->vana);
+	return rval;
+}
+
+static void smiapp_power_off(struct smiapp_sensor *sensor)
+{
+	/*
+	 * Currently power/clock to lens are enable/disabled separately
+	 * but they are essentially the same signals. So if the sensor is
+	 * powered off while the lens is powered on the sensor does not
+	 * really see a power off and next time the cci address change
+	 * will fail. So do a soft reset explicitly here.
+	 */
+	if (sensor->platform_data->i2c_addr_alt)
+		smiapp_write(sensor,
+			     SMIAPP_REG_U8_SOFTWARE_RESET,
+			     SMIAPP_SOFTWARE_RESET);
+
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_set_value(sensor->platform_data->xshutdown, 0);
+	if (sensor->platform_data->set_xclk)
+		sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+	else
+		clk_disable(sensor->ext_clk);
+	usleep_range(5000, 5000);
+	regulator_disable(sensor->vana);
+	sensor->streaming = 0;
+}
+
+static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int ret = 0;
+
+	mutex_lock(&sensor->power_mutex);
+
+	/*
+	 * If the power count is modified from 0 to != 0 or from != 0
+	 * to 0, update the power state.
+	 */
+	if (!sensor->power_count == !on)
+		goto out;
+
+	if (on) {
+		/* Power on and perform initialisation. */
+		ret = smiapp_power_on(sensor);
+		if (ret < 0)
+			goto out;
+	} else {
+		smiapp_power_off(sensor);
+	}
+
+	/* Update the power count. */
+	sensor->power_count += on ? 1 : -1;
+	WARN_ON(sensor->power_count < 0);
+
+out:
+	mutex_unlock(&sensor->power_mutex);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Video stream management
+ */
+
+static int smiapp_start_streaming(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	mutex_lock(&sensor->mutex);
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_CSI_DATA_FORMAT,
+			    (sensor->csi_format->width << 8) |
+			    sensor->csi_format->compressed);
+	if (rval)
+		goto out;
+
+	rval = smiapp_pll_configure(sensor);
+	if (rval)
+		goto out;
+
+	/* Analog crop start coordinates */
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_X_ADDR_START,
+			    sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_ADDR_START,
+			    sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top);
+	if (rval < 0)
+		goto out;
+
+	/* Analog crop end coordinates */
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_X_ADDR_END,
+		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left
+		+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - 1);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_Y_ADDR_END,
+		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top
+		+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - 1);
+	if (rval < 0)
+		goto out;
+
+	/*
+	 * Output from pixel array, including blanking, is set using
+	 * controls below. No need to set here.
+	 */
+
+	/* Digital crop */
+	if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+	    == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].left);
+		if (rval < 0)
+			goto out;
+
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].top);
+		if (rval < 0)
+			goto out;
+
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].width);
+		if (rval < 0)
+			goto out;
+
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].height);
+		if (rval < 0)
+			goto out;
+	}
+
+	/* Scaling */
+	if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+	    != SMIAPP_SCALING_CAPABILITY_NONE) {
+		rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE,
+				    sensor->scaling_mode);
+		if (rval < 0)
+			goto out;
+
+		rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALE_M,
+				    sensor->scale_m);
+		if (rval < 0)
+			goto out;
+	}
+
+	/* Output size from sensor */
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_X_OUTPUT_SIZE,
+			    sensor->src->crop[SMIAPP_PAD_SRC].width);
+	if (rval < 0)
+		goto out;
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_OUTPUT_SIZE,
+			    sensor->src->crop[SMIAPP_PAD_SRC].height);
+	if (rval < 0)
+		goto out;
+
+	if ((sensor->flash_capability &
+	     (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
+	      SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
+	    sensor->platform_data->strobe_setup != NULL &&
+	    sensor->platform_data->strobe_setup->trigger != 0) {
+		rval = smiapp_setup_flash_strobe(sensor);
+		if (rval)
+			goto out;
+	}
+
+	rval = smiapp_call_quirk(sensor, pre_streamon);
+	if (rval) {
+		dev_err(&client->dev, "pre_streamon quirks failed\n");
+		goto out;
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
+			    SMIAPP_MODE_SELECT_STREAMING);
+
+out:
+	mutex_unlock(&sensor->mutex);
+
+	return rval;
+}
+
+static int smiapp_stop_streaming(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	mutex_lock(&sensor->mutex);
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
+			    SMIAPP_MODE_SELECT_SOFTWARE_STANDBY);
+	if (rval)
+		goto out;
+
+	rval = smiapp_call_quirk(sensor, post_streamoff);
+	if (rval)
+		dev_err(&client->dev, "post_streamoff quirks failed\n");
+
+out:
+	mutex_unlock(&sensor->mutex);
+	return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	if (sensor->streaming == enable)
+		return 0;
+
+	if (enable) {
+		sensor->streaming = 1;
+		rval = smiapp_start_streaming(sensor);
+		if (rval < 0)
+			sensor->streaming = 0;
+	} else {
+		rval = smiapp_stop_streaming(sensor);
+		sensor->streaming = 0;
+	}
+
+	return rval;
+}
+
+static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	unsigned int i;
+	int idx = -1;
+	int rval = -EINVAL;
+
+	mutex_lock(&sensor->mutex);
+
+	dev_err(&client->dev, "subdev %s, pad %d, index %d\n",
+		subdev->name, code->pad, code->index);
+
+	if (subdev != &sensor->src->sd || code->pad != SMIAPP_PAD_SRC) {
+		if (code->index)
+			goto out;
+
+		code->code = sensor->internal_csi_format->code;
+		rval = 0;
+		goto out;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+		if (sensor->mbus_frame_fmts & (1 << i))
+			idx++;
+
+		if (idx == code->index) {
+			code->code = smiapp_csi_data_formats[i].code;
+			dev_err(&client->dev, "found index %d, i %d, code %x\n",
+				code->index, i, code->code);
+			rval = 0;
+			break;
+		}
+	}
+
+out:
+	mutex_unlock(&sensor->mutex);
+
+	return rval;
+}
+
+static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev,
+				  unsigned int pad)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+	if (subdev == &sensor->src->sd && pad == SMIAPP_PAD_SRC)
+		return sensor->csi_format->code;
+	else
+		return sensor->internal_csi_format->code;
+}
+
+static int __smiapp_get_format(struct v4l2_subdev *subdev,
+			       struct v4l2_subdev_fh *fh,
+			       struct v4l2_subdev_format *fmt)
+{
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+	} else {
+		struct v4l2_rect *r;
+
+		if (fmt->pad == ssd->source_pad)
+			r = &ssd->crop[ssd->source_pad];
+		else
+			r = &ssd->sink_fmt;
+
+		fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
+		fmt->format.width = r->width;
+		fmt->format.height = r->height;
+	}
+
+	return 0;
+}
+
+static int smiapp_get_format(struct v4l2_subdev *subdev,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	mutex_lock(&sensor->mutex);
+	rval = __smiapp_get_format(subdev, fh, fmt);
+	mutex_unlock(&sensor->mutex);
+
+	return rval;
+}
+
+static void smiapp_get_crop_compose(struct v4l2_subdev *subdev,
+				    struct v4l2_subdev_fh *fh,
+				    struct v4l2_rect **crops,
+				    struct v4l2_rect **comps, int which)
+{
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	unsigned int i;
+
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		if (crops)
+			for (i = 0; i < subdev->entity.num_pads; i++)
+				crops[i] = &ssd->crop[i];
+		if (comps)
+			*comps = &ssd->compose;
+	} else {
+		if (crops) {
+			for (i = 0; i < subdev->entity.num_pads; i++) {
+				crops[i] = v4l2_subdev_get_try_crop(fh, i);
+				BUG_ON(!crops[i]);
+			}
+		}
+		if (comps) {
+			*comps = v4l2_subdev_get_try_compose(fh,
+							     SMIAPP_PAD_SINK);
+			BUG_ON(!*comps);
+		}
+	}
+}
+
+/* Changes require propagation only on sink pad. */
+static void smiapp_propagate(struct v4l2_subdev *subdev,
+			     struct v4l2_subdev_fh *fh, int which,
+			     int target)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+
+	smiapp_get_crop_compose(subdev, fh, crops, &comp, which);
+
+	switch (target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+		comp->width = crops[SMIAPP_PAD_SINK]->width;
+		comp->height = crops[SMIAPP_PAD_SINK]->height;
+		if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+			if (ssd == sensor->scaler) {
+				sensor->scale_m =
+					sensor->limits[
+						SMIAPP_LIMIT_SCALER_N_MIN];
+				sensor->scaling_mode =
+					SMIAPP_SCALING_MODE_NONE;
+			} else if (ssd == sensor->binner) {
+				sensor->binning_horizontal = 1;
+				sensor->binning_vertical = 1;
+			}
+		}
+		/* Fall through */
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+		*crops[SMIAPP_PAD_SRC] = *comp;
+		break;
+	default:
+		BUG();
+	}
+}
+
+static const struct smiapp_csi_data_format
+*smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code)
+{
+	const struct smiapp_csi_data_format *csi_format = sensor->csi_format;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+		if (sensor->mbus_frame_fmts & (1 << i)
+		    && smiapp_csi_data_formats[i].code == code)
+			return &smiapp_csi_data_formats[i];
+	}
+
+	return csi_format;
+}
+
+static int smiapp_set_format(struct v4l2_subdev *subdev,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *crops[SMIAPP_PADS];
+
+	mutex_lock(&sensor->mutex);
+
+	/*
+	 * Media bus code is changeable on src subdev's source pad. On
+	 * other source pads we just get format here.
+	 */
+	if (fmt->pad == ssd->source_pad) {
+		u32 code = fmt->format.code;
+		int rval = __smiapp_get_format(subdev, fh, fmt);
+
+		if (!rval && subdev == &sensor->src->sd) {
+			const struct smiapp_csi_data_format *csi_format =
+				smiapp_validate_csi_data_format(sensor, code);
+			if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+				sensor->csi_format = csi_format;
+			fmt->format.code = csi_format->code;
+		}
+
+		mutex_unlock(&sensor->mutex);
+		return rval;
+	}
+
+	/* Sink pad. Width and height are changeable here. */
+	fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
+	fmt->format.width &= ~1;
+	fmt->format.height &= ~1;
+
+	fmt->format.width =
+		clamp(fmt->format.width,
+		      sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+		      sensor->limits[SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE]);
+	fmt->format.height =
+		clamp(fmt->format.height,
+		      sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+		      sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]);
+
+	smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which);
+
+	crops[ssd->sink_pad]->left = 0;
+	crops[ssd->sink_pad]->top = 0;
+	crops[ssd->sink_pad]->width = fmt->format.width;
+	crops[ssd->sink_pad]->height = fmt->format.height;
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		ssd->sink_fmt = *crops[ssd->sink_pad];
+	smiapp_propagate(subdev, fh, fmt->which,
+			 V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL);
+
+	mutex_unlock(&sensor->mutex);
+
+	return 0;
+}
+
+/*
+ * Calculate goodness of scaled image size compared to expected image
+ * size and flags provided.
+ */
+#define SCALING_GOODNESS		100000
+#define SCALING_GOODNESS_EXTREME	100000000
+static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
+			    int h, int ask_h, u32 flags)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	int val = 0;
+
+	w &= ~1;
+	ask_w &= ~1;
+	h &= ~1;
+	ask_h &= ~1;
+
+	if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_GE) {
+		if (w < ask_w)
+			val -= SCALING_GOODNESS;
+		if (h < ask_h)
+			val -= SCALING_GOODNESS;
+	}
+
+	if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_LE) {
+		if (w > ask_w)
+			val -= SCALING_GOODNESS;
+		if (h > ask_h)
+			val -= SCALING_GOODNESS;
+	}
+
+	val -= abs(w - ask_w);
+	val -= abs(h - ask_h);
+
+	if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
+		val -= SCALING_GOODNESS_EXTREME;
+
+	dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
+		w, ask_h, h, ask_h, val);
+
+	return val;
+}
+
+static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
+				      struct v4l2_subdev_fh *fh,
+				      struct v4l2_subdev_selection *sel,
+				      struct v4l2_rect **crops,
+				      struct v4l2_rect *comp)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	unsigned int i;
+	unsigned int binh = 1, binv = 1;
+	unsigned int best = scaling_goodness(
+		subdev,
+		crops[SMIAPP_PAD_SINK]->width, sel->r.width,
+		crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags);
+
+	for (i = 0; i < sensor->nbinning_subtypes; i++) {
+		int this = scaling_goodness(
+			subdev,
+			crops[SMIAPP_PAD_SINK]->width
+			/ sensor->binning_subtypes[i].horizontal,
+			sel->r.width,
+			crops[SMIAPP_PAD_SINK]->height
+			/ sensor->binning_subtypes[i].vertical,
+			sel->r.height, sel->flags);
+
+		if (this > best) {
+			binh = sensor->binning_subtypes[i].horizontal;
+			binv = sensor->binning_subtypes[i].vertical;
+			best = this;
+		}
+	}
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		sensor->binning_vertical = binv;
+		sensor->binning_horizontal = binh;
+	}
+
+	sel->r.width = (crops[SMIAPP_PAD_SINK]->width / binh) & ~1;
+	sel->r.height = (crops[SMIAPP_PAD_SINK]->height / binv) & ~1;
+}
+
+/*
+ * Calculate best scaling ratio and mode for given output resolution.
+ *
+ * Try all of these: horizontal ratio, vertical ratio and smallest
+ * size possible (horizontally).
+ *
+ * Also try whether horizontal scaler or full scaler gives a better
+ * result.
+ */
+static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
+				      struct v4l2_subdev_fh *fh,
+				      struct v4l2_subdev_selection *sel,
+				      struct v4l2_rect **crops,
+				      struct v4l2_rect *comp)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	u32 min, max, a, b, max_m;
+	u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+	int mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+	u32 try[4];
+	u32 ntry = 0;
+	unsigned int i;
+	int best = INT_MIN;
+
+	sel->r.width = min_t(unsigned int, sel->r.width,
+			     crops[SMIAPP_PAD_SINK]->width);
+	sel->r.height = min_t(unsigned int, sel->r.height,
+			      crops[SMIAPP_PAD_SINK]->height);
+
+	a = crops[SMIAPP_PAD_SINK]->width
+		* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.width;
+	b = crops[SMIAPP_PAD_SINK]->height
+		* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.height;
+	max_m = crops[SMIAPP_PAD_SINK]->width
+		* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
+		/ sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
+
+	a = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+		max(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+	b = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+		max(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+	max_m = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+		    max(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+
+	dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
+
+	min = min(max_m, min(a, b));
+	max = min(max_m, max(a, b));
+
+	try[ntry] = min;
+	ntry++;
+	if (min != max) {
+		try[ntry] = max;
+		ntry++;
+	}
+	if (max != max_m) {
+		try[ntry] = min + 1;
+		ntry++;
+		if (min != max) {
+			try[ntry] = max + 1;
+			ntry++;
+		}
+	}
+
+	for (i = 0; i < ntry; i++) {
+		int this = scaling_goodness(
+			subdev,
+			crops[SMIAPP_PAD_SINK]->width
+			/ try[i]
+			* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+			sel->r.width,
+			crops[SMIAPP_PAD_SINK]->height,
+			sel->r.height,
+			sel->flags);
+
+		dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i);
+
+		if (this > best) {
+			scale_m = try[i];
+			mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+			best = this;
+		}
+
+		if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		    == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+			continue;
+
+		this = scaling_goodness(
+			subdev, crops[SMIAPP_PAD_SINK]->width
+			/ try[i]
+			* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+			sel->r.width,
+			crops[SMIAPP_PAD_SINK]->height
+			/ try[i]
+			* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+			sel->r.height,
+			sel->flags);
+
+		if (this > best) {
+			scale_m = try[i];
+			mode = SMIAPP_SCALING_MODE_BOTH;
+			best = this;
+		}
+	}
+
+	sel->r.width =
+		(crops[SMIAPP_PAD_SINK]->width
+		 / scale_m
+		 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1;
+	if (mode == SMIAPP_SCALING_MODE_BOTH)
+		sel->r.height =
+			(crops[SMIAPP_PAD_SINK]->height
+			 / scale_m
+			 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN])
+			& ~1;
+	else
+		sel->r.height = crops[SMIAPP_PAD_SINK]->height;
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		sensor->scale_m = scale_m;
+		sensor->scaling_mode = mode;
+	}
+}
+/* We're only called on source pads. This function sets scaling. */
+static int smiapp_set_compose(struct v4l2_subdev *subdev,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+
+	smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+
+	sel->r.top = 0;
+	sel->r.left = 0;
+
+	if (ssd == sensor->binner)
+		smiapp_set_compose_binner(subdev, fh, sel, crops, comp);
+	else
+		smiapp_set_compose_scaler(subdev, fh, sel, crops, comp);
+
+	*comp = sel->r;
+	smiapp_propagate(subdev, fh, sel->which,
+			 V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		return smiapp_update_mode(sensor);
+
+	return 0;
+}
+
+static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+
+	/* We only implement crop in three places. */
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+	case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+		if (ssd == sensor->pixel_array
+		    && sel->pad == SMIAPP_PA_PAD_SRC)
+			return 0;
+		if (ssd == sensor->src
+		    && sel->pad == SMIAPP_PAD_SRC)
+			return 0;
+		if (ssd == sensor->scaler
+		    && sel->pad == SMIAPP_PAD_SINK
+		    && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+		    == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
+			return 0;
+		return -EINVAL;
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+		if (sel->pad == ssd->source_pad)
+			return -EINVAL;
+		if (ssd == sensor->binner)
+			return 0;
+		if (ssd == sensor->scaler
+		    && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		    != SMIAPP_SCALING_CAPABILITY_NONE)
+			return 0;
+		/* Fall through */
+	default:
+		return -EINVAL;
+	}
+}
+
+static int smiapp_set_crop(struct v4l2_subdev *subdev,
+			   struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *src_size, *crops[SMIAPP_PADS];
+	struct v4l2_rect _r;
+
+	smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		if (sel->pad == ssd->sink_pad)
+			src_size = &ssd->sink_fmt;
+		else
+			src_size = &ssd->compose;
+	} else {
+		if (sel->pad == ssd->sink_pad) {
+			_r.left = 0;
+			_r.top = 0;
+			_r.width = v4l2_subdev_get_try_format(fh, sel->pad)
+				->width;
+			_r.height = v4l2_subdev_get_try_format(fh, sel->pad)
+				->height;
+			src_size = &_r;
+		} else {
+			src_size =
+				v4l2_subdev_get_try_compose(
+					fh, ssd->sink_pad);
+		}
+	}
+
+	if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SRC) {
+		sel->r.left = 0;
+		sel->r.top = 0;
+	}
+
+	sel->r.width = min(sel->r.width, src_size->width);
+	sel->r.height = min(sel->r.height, src_size->height);
+
+	sel->r.left = min(sel->r.left, src_size->width - sel->r.width);
+	sel->r.top = min(sel->r.top, src_size->height - sel->r.height);
+
+	*crops[sel->pad] = sel->r;
+
+	if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK)
+		smiapp_propagate(subdev, fh, sel->which,
+				 V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL);
+
+	return 0;
+}
+
+static int __smiapp_get_selection(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+	struct v4l2_rect sink_fmt;
+	int ret;
+
+	ret = __smiapp_sel_supported(subdev, sel);
+	if (ret)
+		return ret;
+
+	smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		sink_fmt = ssd->sink_fmt;
+	} else {
+		struct v4l2_mbus_framefmt *fmt =
+			v4l2_subdev_get_try_format(fh, ssd->sink_pad);
+
+		sink_fmt.left = 0;
+		sink_fmt.top = 0;
+		sink_fmt.width = fmt->width;
+		sink_fmt.height = fmt->height;
+	}
+
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+		if (ssd == sensor->pixel_array) {
+			sel->r.width =
+				sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+			sel->r.height =
+				sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+		} else if (sel->pad == ssd->sink_pad) {
+			sel->r = sink_fmt;
+		} else {
+			sel->r = *comp;
+		}
+		break;
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+		sel->r = *crops[sel->pad];
+		break;
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+		sel->r = *comp;
+		break;
+	}
+
+	return 0;
+}
+
+static int smiapp_get_selection(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	mutex_lock(&sensor->mutex);
+	rval = __smiapp_get_selection(subdev, fh, sel);
+	mutex_unlock(&sensor->mutex);
+
+	return rval;
+}
+static int smiapp_set_selection(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int ret;
+
+	ret = __smiapp_sel_supported(subdev, sel);
+	if (ret)
+		return ret;
+
+	mutex_lock(&sensor->mutex);
+
+	sel->r.left = max(0, sel->r.left & ~1);
+	sel->r.top = max(0, sel->r.top & ~1);
+	sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags));
+	sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags));
+
+	sel->r.width = max_t(unsigned int,
+			     sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+			     sel->r.width);
+	sel->r.height = max_t(unsigned int,
+			      sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+			      sel->r.height);
+
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+		ret = smiapp_set_crop(subdev, fh, sel);
+		break;
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+		ret = smiapp_set_compose(subdev, fh, sel);
+		break;
+	default:
+		BUG();
+	}
+
+	mutex_unlock(&sensor->mutex);
+	return ret;
+}
+
+static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+	*frames = sensor->frame_skip;
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * sysfs attributes
+ */
+
+static ssize_t
+smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
+		      char *buf)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	unsigned int nbytes;
+
+	if (!sensor->dev_init_done)
+		return -EBUSY;
+
+	if (!sensor->nvm_size) {
+		/* NVM not read yet - read it now */
+		sensor->nvm_size = sensor->platform_data->nvm_size;
+		if (smiapp_set_power(subdev, 1) < 0)
+			return -ENODEV;
+		if (smiapp_read_nvm(sensor, sensor->nvm)) {
+			dev_err(&client->dev, "nvm read failed\n");
+			return -ENODEV;
+		}
+		smiapp_set_power(subdev, 0);
+	}
+	/*
+	 * NVM is still way below a PAGE_SIZE, so we can safely
+	 * assume this for now.
+	 */
+	nbytes = min_t(unsigned int, sensor->nvm_size, PAGE_SIZE);
+	memcpy(buf, sensor->nvm, nbytes);
+
+	return nbytes;
+}
+static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL);
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int smiapp_identify_module(struct v4l2_subdev *subdev)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_module_info *minfo = &sensor->minfo;
+	unsigned int i;
+	int rval = 0;
+
+	minfo->name = SMIAPP_NAME;
+
+	/* Module info */
+	rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID,
+				 &minfo->manufacturer_id);
+	if (!rval)
+		rval = smiapp_read_8only(sensor, SMIAPP_REG_U16_MODEL_ID,
+					 &minfo->model_id);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_REVISION_NUMBER_MAJOR,
+					 &minfo->revision_number_major);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_REVISION_NUMBER_MINOR,
+					 &minfo->revision_number_minor);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_MODULE_DATE_YEAR,
+					 &minfo->module_year);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_MODULE_DATE_MONTH,
+					 &minfo->module_month);
+	if (!rval)
+		rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MODULE_DATE_DAY,
+					 &minfo->module_day);
+
+	/* Sensor info */
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID,
+					 &minfo->sensor_manufacturer_id);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U16_SENSOR_MODEL_ID,
+					 &minfo->sensor_model_id);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_SENSOR_REVISION_NUMBER,
+					 &minfo->sensor_revision_number);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION,
+					 &minfo->sensor_firmware_version);
+
+	/* SMIA */
+	if (!rval)
+		rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION,
+					 &minfo->smia_version);
+	if (!rval)
+		rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
+					 &minfo->smiapp_version);
+
+	if (rval) {
+		dev_err(&client->dev, "sensor detection failed\n");
+		return -ENODEV;
+	}
+
+	dev_dbg(&client->dev, "module 0x%2.2x-0x%4.4x\n",
+		minfo->manufacturer_id, minfo->model_id);
+
+	dev_dbg(&client->dev,
+		"module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n",
+		minfo->revision_number_major, minfo->revision_number_minor,
+		minfo->module_year, minfo->module_month, minfo->module_day);
+
+	dev_dbg(&client->dev, "sensor 0x%2.2x-0x%4.4x\n",
+		minfo->sensor_manufacturer_id, minfo->sensor_model_id);
+
+	dev_dbg(&client->dev,
+		"sensor revision 0x%2.2x firmware version 0x%2.2x\n",
+		minfo->sensor_revision_number, minfo->sensor_firmware_version);
+
+	dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n",
+		minfo->smia_version, minfo->smiapp_version);
+
+	/*
+	 * Some modules have bad data in the lvalues below. Hope the
+	 * rvalues have better stuff. The lvalues are module
+	 * parameters whereas the rvalues are sensor parameters.
+	 */
+	if (!minfo->manufacturer_id && !minfo->model_id) {
+		minfo->manufacturer_id = minfo->sensor_manufacturer_id;
+		minfo->model_id = minfo->sensor_model_id;
+		minfo->revision_number_major = minfo->sensor_revision_number;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) {
+		if (smiapp_module_idents[i].manufacturer_id
+		    != minfo->manufacturer_id)
+			continue;
+		if (smiapp_module_idents[i].model_id != minfo->model_id)
+			continue;
+		if (smiapp_module_idents[i].flags
+		    & SMIAPP_MODULE_IDENT_FLAG_REV_LE) {
+			if (smiapp_module_idents[i].revision_number_major
+			    < minfo->revision_number_major)
+				continue;
+		} else {
+			if (smiapp_module_idents[i].revision_number_major
+			    != minfo->revision_number_major)
+				continue;
+		}
+
+		minfo->name = smiapp_module_idents[i].name;
+		minfo->quirk = smiapp_module_idents[i].quirk;
+		break;
+	}
+
+	if (i >= ARRAY_SIZE(smiapp_module_idents))
+		dev_warn(&client->dev,
+			 "no quirks for this module; let's hope it's fully compliant\n");
+
+	dev_dbg(&client->dev, "the sensor is called %s, ident %2.2x%4.4x%2.2x\n",
+		minfo->name, minfo->manufacturer_id, minfo->model_id,
+		minfo->revision_number_major);
+
+	strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name));
+
+	return 0;
+}
+
+static const struct v4l2_subdev_ops smiapp_ops;
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
+static const struct media_entity_operations smiapp_entity_ops;
+
+static int smiapp_registered(struct v4l2_subdev *subdev)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_subdev *last = NULL;
+	u32 tmp;
+	unsigned int i;
+	int rval;
+
+	sensor->vana = regulator_get(&client->dev, "VANA");
+	if (IS_ERR(sensor->vana)) {
+		dev_err(&client->dev, "could not get regulator for vana\n");
+		return -ENODEV;
+	}
+
+	if (!sensor->platform_data->set_xclk) {
+		sensor->ext_clk = clk_get(&client->dev,
+					  sensor->platform_data->ext_clk_name);
+		if (IS_ERR(sensor->ext_clk)) {
+			dev_err(&client->dev, "could not get clock %s\n",
+				sensor->platform_data->ext_clk_name);
+			rval = -ENODEV;
+			goto out_clk_get;
+		}
+
+		rval = clk_set_rate(sensor->ext_clk,
+				    sensor->platform_data->ext_clk);
+		if (rval < 0) {
+			dev_err(&client->dev,
+				"unable to set clock %s freq to %u\n",
+				sensor->platform_data->ext_clk_name,
+				sensor->platform_data->ext_clk);
+			rval = -ENODEV;
+			goto out_clk_set_rate;
+		}
+	}
+
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
+		if (gpio_request_one(sensor->platform_data->xshutdown, 0,
+				     "SMIA++ xshutdown") != 0) {
+			dev_err(&client->dev,
+				"unable to acquire reset gpio %d\n",
+				sensor->platform_data->xshutdown);
+			rval = -ENODEV;
+			goto out_clk_set_rate;
+		}
+	}
+
+	rval = smiapp_power_on(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_smiapp_power_on;
+	}
+
+	rval = smiapp_identify_module(subdev);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_power_off;
+	}
+
+	rval = smiapp_get_all_limits(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_power_off;
+	}
+
+	/*
+	 * Handle Sensor Module orientation on the board.
+	 *
+	 * The application of H-FLIP and V-FLIP on the sensor is modified by
+	 * the sensor orientation on the board.
+	 *
+	 * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
+	 * both H-FLIP and V-FLIP for normal operation which also implies
+	 * that a set/unset operation for user space HFLIP and VFLIP v4l2
+	 * controls will need to be internally inverted.
+	 *
+	 * Rotation also changes the bayer pattern.
+	 */
+	if (sensor->platform_data->module_board_orient ==
+	    SMIAPP_MODULE_BOARD_ORIENT_180)
+		sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
+					  SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+	rval = smiapp_get_mbus_formats(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_power_off;
+	}
+
+	if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
+		u32 val;
+
+		rval = smiapp_read(sensor,
+				   SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
+		if (rval < 0) {
+			rval = -ENODEV;
+			goto out_power_off;
+		}
+		sensor->nbinning_subtypes = min_t(u8, val,
+						  SMIAPP_BINNING_SUBTYPES);
+
+		for (i = 0; i < sensor->nbinning_subtypes; i++) {
+			rval = smiapp_read(
+				sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val);
+			if (rval < 0) {
+				rval = -ENODEV;
+				goto out_power_off;
+			}
+			sensor->binning_subtypes[i] =
+				*(struct smiapp_binning_subtype *)&val;
+
+			dev_dbg(&client->dev, "binning %xx%x\n",
+				sensor->binning_subtypes[i].horizontal,
+				sensor->binning_subtypes[i].vertical);
+		}
+	}
+	sensor->binning_horizontal = 1;
+	sensor->binning_vertical = 1;
+
+	/* SMIA++ NVM initialization - it will be read from the sensor
+	 * when it is first requested by userspace.
+	 */
+	if (sensor->minfo.smiapp_version && sensor->platform_data->nvm_size) {
+		sensor->nvm = kzalloc(sensor->platform_data->nvm_size,
+				      GFP_KERNEL);
+		if (sensor->nvm == NULL) {
+			dev_err(&client->dev, "nvm buf allocation failed\n");
+			rval = -ENOMEM;
+			goto out_power_off;
+		}
+
+		if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
+			dev_err(&client->dev, "sysfs nvm entry failed\n");
+			rval = -EBUSY;
+			goto out_power_off;
+		}
+	}
+
+	rval = smiapp_call_quirk(sensor, limits);
+	if (rval) {
+		dev_err(&client->dev, "limits quirks failed\n");
+		goto out_nvm_release;
+	}
+
+	/* We consider this as profile 0 sensor if any of these are zero. */
+	if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
+	    !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
+	    !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
+	    !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
+		sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
+	} else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		   != SMIAPP_SCALING_CAPABILITY_NONE) {
+		if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		    == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+			sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
+		else
+			sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
+		sensor->scaler = &sensor->ssds[sensor->ssds_used];
+		sensor->ssds_used++;
+	} else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+		   == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+		sensor->scaler = &sensor->ssds[sensor->ssds_used];
+		sensor->ssds_used++;
+	}
+	sensor->binner = &sensor->ssds[sensor->ssds_used];
+	sensor->ssds_used++;
+	sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
+	sensor->ssds_used++;
+
+	sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+
+	for (i = 0; i < SMIAPP_SUBDEVS; i++) {
+		struct {
+			struct smiapp_subdev *ssd;
+			char *name;
+		} const __this[] = {
+			{ sensor->scaler, "scaler", },
+			{ sensor->binner, "binner", },
+			{ sensor->pixel_array, "pixel array", },
+		}, *_this = &__this[i];
+		struct smiapp_subdev *this = _this->ssd;
+
+		if (!this)
+			continue;
+
+		if (this != sensor->src)
+			v4l2_subdev_init(&this->sd, &smiapp_ops);
+
+		this->sensor = sensor;
+
+		if (this == sensor->pixel_array) {
+			this->npads = 1;
+		} else {
+			this->npads = 2;
+			this->source_pad = 1;
+		}
+
+		snprintf(this->sd.name,
+			 sizeof(this->sd.name), "%s %s",
+			 sensor->minfo.name, _this->name);
+
+		this->sink_fmt.width =
+			sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+		this->sink_fmt.height =
+			sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+		this->compose.width = this->sink_fmt.width;
+		this->compose.height = this->sink_fmt.height;
+		this->crop[this->source_pad] = this->compose;
+		this->pads[this->source_pad].flags = MEDIA_PAD_FL_SOURCE;
+		if (this != sensor->pixel_array) {
+			this->crop[this->sink_pad] = this->compose;
+			this->pads[this->sink_pad].flags = MEDIA_PAD_FL_SINK;
+		}
+
+		this->sd.entity.ops = &smiapp_entity_ops;
+
+		if (last == NULL) {
+			last = this;
+			continue;
+		}
+
+		this->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+		this->sd.internal_ops = &smiapp_internal_ops;
+		this->sd.owner = NULL;
+		v4l2_set_subdevdata(&this->sd, client);
+
+		rval = media_entity_init(&this->sd.entity,
+					 this->npads, this->pads, 0);
+		if (rval) {
+			dev_err(&client->dev,
+				"media_entity_init failed\n");
+			goto out_nvm_release;
+		}
+
+		rval = media_entity_create_link(&this->sd.entity,
+						this->source_pad,
+						&last->sd.entity,
+						last->sink_pad,
+						MEDIA_LNK_FL_ENABLED |
+						MEDIA_LNK_FL_IMMUTABLE);
+		if (rval) {
+			dev_err(&client->dev,
+				"media_entity_create_link failed\n");
+			goto out_nvm_release;
+		}
+
+		rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
+						   &this->sd);
+		if (rval) {
+			dev_err(&client->dev,
+				"v4l2_device_register_subdev failed\n");
+			goto out_nvm_release;
+		}
+
+		last = this;
+	}
+
+	dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
+
+	sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+
+	/* final steps */
+	smiapp_read_frame_fmt(sensor);
+	rval = smiapp_init_controls(sensor);
+	if (rval < 0)
+		goto out_nvm_release;
+
+	rval = smiapp_update_mode(sensor);
+	if (rval) {
+		dev_err(&client->dev, "update mode failed\n");
+		goto out_nvm_release;
+	}
+
+	sensor->streaming = false;
+	sensor->dev_init_done = true;
+
+	/* check flash capability */
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp);
+	sensor->flash_capability = tmp;
+	if (rval)
+		goto out_nvm_release;
+
+	smiapp_power_off(sensor);
+
+	return 0;
+
+out_nvm_release:
+	device_remove_file(&client->dev, &dev_attr_nvm);
+
+out_power_off:
+	kfree(sensor->nvm);
+	sensor->nvm = NULL;
+	smiapp_power_off(sensor);
+
+out_smiapp_power_on:
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_free(sensor->platform_data->xshutdown);
+
+out_clk_set_rate:
+	clk_put(sensor->ext_clk);
+	sensor->ext_clk = NULL;
+
+out_clk_get:
+	regulator_put(sensor->vana);
+	sensor->vana = NULL;
+	return rval;
+}
+
+static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
+	struct smiapp_sensor *sensor = ssd->sensor;
+	u32 mbus_code =
+		smiapp_csi_data_formats[smiapp_pixel_order(sensor)].code;
+	unsigned int i;
+
+	mutex_lock(&sensor->mutex);
+
+	for (i = 0; i < ssd->npads; i++) {
+		struct v4l2_mbus_framefmt *try_fmt =
+			v4l2_subdev_get_try_format(fh, i);
+		struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i);
+		struct v4l2_rect *try_comp;
+
+		try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+		try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+		try_fmt->code = mbus_code;
+
+		try_crop->top = 0;
+		try_crop->left = 0;
+		try_crop->width = try_fmt->width;
+		try_crop->height = try_fmt->height;
+
+		if (ssd != sensor->pixel_array)
+			continue;
+
+		try_comp = v4l2_subdev_get_try_compose(fh, i);
+		*try_comp = *try_crop;
+	}
+
+	mutex_unlock(&sensor->mutex);
+
+	return smiapp_set_power(sd, 1);
+}
+
+static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return smiapp_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_video_ops smiapp_video_ops = {
+	.s_stream = smiapp_set_stream,
+};
+
+static const struct v4l2_subdev_core_ops smiapp_core_ops = {
+	.s_power = smiapp_set_power,
+};
+
+static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
+	.enum_mbus_code = smiapp_enum_mbus_code,
+	.get_fmt = smiapp_get_format,
+	.set_fmt = smiapp_set_format,
+	.get_selection = smiapp_get_selection,
+	.set_selection = smiapp_set_selection,
+};
+
+static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
+	.g_skip_frames = smiapp_get_skip_frames,
+};
+
+static const struct v4l2_subdev_ops smiapp_ops = {
+	.core = &smiapp_core_ops,
+	.video = &smiapp_video_ops,
+	.pad = &smiapp_pad_ops,
+	.sensor = &smiapp_sensor_ops,
+};
+
+static const struct media_entity_operations smiapp_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = {
+	.registered = smiapp_registered,
+	.open = smiapp_open,
+	.close = smiapp_close,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops = {
+	.open = smiapp_open,
+	.close = smiapp_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * I2C Driver
+ */
+
+#ifdef CONFIG_PM
+
+static int smiapp_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	bool streaming;
+
+	BUG_ON(mutex_is_locked(&sensor->mutex));
+
+	if (sensor->power_count == 0)
+		return 0;
+
+	if (sensor->streaming)
+		smiapp_stop_streaming(sensor);
+
+	streaming = sensor->streaming;
+
+	smiapp_power_off(sensor);
+
+	/* save state for resume */
+	sensor->streaming = streaming;
+
+	return 0;
+}
+
+static int smiapp_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	if (sensor->power_count == 0)
+		return 0;
+
+	rval = smiapp_power_on(sensor);
+	if (rval)
+		return rval;
+
+	if (sensor->streaming)
+		rval = smiapp_start_streaming(sensor);
+
+	return rval;
+}
+
+#else
+
+#define smiapp_suspend	NULL
+#define smiapp_resume	NULL
+
+#endif /* CONFIG_PM */
+
+static int smiapp_probe(struct i2c_client *client,
+			const struct i2c_device_id *devid)
+{
+	struct smiapp_sensor *sensor;
+	int rval;
+
+	if (client->dev.platform_data == NULL)
+		return -ENODEV;
+
+	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+	if (sensor == NULL)
+		return -ENOMEM;
+
+	sensor->platform_data = client->dev.platform_data;
+	mutex_init(&sensor->mutex);
+	mutex_init(&sensor->power_mutex);
+	sensor->src = &sensor->ssds[sensor->ssds_used];
+
+	v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
+	sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
+	sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sensor->src->sensor = sensor;
+
+	sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
+	rval = media_entity_init(&sensor->src->sd.entity, 2,
+				 sensor->src->pads, 0);
+	if (rval < 0)
+		kfree(sensor);
+
+	return rval;
+}
+
+static int __exit smiapp_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	unsigned int i;
+
+	if (sensor->power_count) {
+		if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+			gpio_set_value(sensor->platform_data->xshutdown, 0);
+		if (sensor->platform_data->set_xclk)
+			sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+		else
+			clk_disable(sensor->ext_clk);
+		sensor->power_count = 0;
+	}
+
+	if (sensor->nvm) {
+		device_remove_file(&client->dev, &dev_attr_nvm);
+		kfree(sensor->nvm);
+	}
+
+	for (i = 0; i < sensor->ssds_used; i++) {
+		media_entity_cleanup(&sensor->ssds[i].sd.entity);
+		v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
+	}
+	smiapp_free_controls(sensor);
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_free(sensor->platform_data->xshutdown);
+	if (sensor->ext_clk)
+		clk_put(sensor->ext_clk);
+	if (sensor->vana)
+		regulator_put(sensor->vana);
+
+	kfree(sensor);
+
+	return 0;
+}
+
+static const struct i2c_device_id smiapp_id_table[] = {
+	{ SMIAPP_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, smiapp_id_table);
+
+static const struct dev_pm_ops smiapp_pm_ops = {
+	.suspend	= smiapp_suspend,
+	.resume		= smiapp_resume,
+};
+
+static struct i2c_driver smiapp_i2c_driver = {
+	.driver	= {
+		.name = SMIAPP_NAME,
+		.pm = &smiapp_pm_ops,
+	},
+	.probe	= smiapp_probe,
+	.remove	= __exit_p(smiapp_remove),
+	.id_table = smiapp_id_table,
+};
+
+module_i2c_driver(smiapp_i2c_driver);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
+MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/smiapp/smiapp-limits.c b/drivers/media/video/smiapp/smiapp-limits.c
new file mode 100644
index 0000000..0800e09
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-limits.c
@@ -0,0 +1,132 @@
+/*
+ * drivers/media/video/smiapp/smiapp-limits.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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
+ *
+ */
+
+#include "smiapp.h"
+
+struct smiapp_reg_limits smiapp_reg_limits[] = {
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY, "analogue_gain_capability" }, /* 0 */
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN, "analogue_gain_code_min" },
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX, "analogue_gain_code_max" },
+	{ SMIAPP_REG_U8_THS_ZERO_MIN, "ths_zero_min" },
+	{ SMIAPP_REG_U8_TCLK_TRAIL_MIN, "tclk_trail_min" },
+	{ SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY, "integration_time_capability" }, /* 5 */
+	{ SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN, "coarse_integration_time_min" },
+	{ SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN, "coarse_integration_time_max_margin" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN, "fine_integration_time_min" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN, "fine_integration_time_max_margin" },
+	{ SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY, "digital_gain_capability" }, /* 10 */
+	{ SMIAPP_REG_U16_DIGITAL_GAIN_MIN, "digital_gain_min" },
+	{ SMIAPP_REG_U16_DIGITAL_GAIN_MAX, "digital_gain_max" },
+	{ SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ, "min_ext_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ, "max_ext_clk_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV, "min_pre_pll_clk_div" }, /* 15 */
+	{ SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV, "max_pre_pll_clk_div" },
+	{ SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ, "min_pll_ip_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ, "max_pll_ip_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_PLL_MULTIPLIER, "min_pll_multiplier" },
+	{ SMIAPP_REG_U16_MAX_PLL_MULTIPLIER, "max_pll_multiplier" }, /* 20 */
+	{ SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ, "min_pll_op_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ, "max_pll_op_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV, "min_vt_sys_clk_div" },
+	{ SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV, "max_vt_sys_clk_div" },
+	{ SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ, "min_vt_sys_clk_freq_hz" }, /* 25 */
+	{ SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ, "max_vt_sys_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ, "min_vt_pix_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ, "max_vt_pix_clk_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV, "min_vt_pix_clk_div" },
+	{ SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV, "max_vt_pix_clk_div" }, /* 30 */
+	{ SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES, "min_frame_length_lines" },
+	{ SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES, "max_frame_length_lines" },
+	{ SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK, "min_line_length_pck" },
+	{ SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK, "max_line_length_pck" },
+	{ SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK, "min_line_blanking_pck" }, /* 35 */
+	{ SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES, "min_frame_blanking_lines" },
+	{ SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE, "min_line_length_pck_step_size" },
+	{ SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV, "min_op_sys_clk_div" },
+	{ SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV, "max_op_sys_clk_div" },
+	{ SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ, "min_op_sys_clk_freq_hz" }, /* 40 */
+	{ SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ, "max_op_sys_clk_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV, "min_op_pix_clk_div" },
+	{ SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV, "max_op_pix_clk_div" },
+	{ SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ, "min_op_pix_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ, "max_op_pix_clk_freq_hz" }, /* 45 */
+	{ SMIAPP_REG_U16_X_ADDR_MIN, "x_addr_min" },
+	{ SMIAPP_REG_U16_Y_ADDR_MIN, "y_addr_min" },
+	{ SMIAPP_REG_U16_X_ADDR_MAX, "x_addr_max" },
+	{ SMIAPP_REG_U16_Y_ADDR_MAX, "y_addr_max" },
+	{ SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE, "min_x_output_size" }, /* 50 */
+	{ SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE, "min_y_output_size" },
+	{ SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE, "max_x_output_size" },
+	{ SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE, "max_y_output_size" },
+	{ SMIAPP_REG_U16_MIN_EVEN_INC, "min_even_inc" },
+	{ SMIAPP_REG_U16_MAX_EVEN_INC, "max_even_inc" }, /* 55 */
+	{ SMIAPP_REG_U16_MIN_ODD_INC, "min_odd_inc" },
+	{ SMIAPP_REG_U16_MAX_ODD_INC, "max_odd_inc" },
+	{ SMIAPP_REG_U16_SCALING_CAPABILITY, "scaling_capability" },
+	{ SMIAPP_REG_U16_SCALER_M_MIN, "scaler_m_min" },
+	{ SMIAPP_REG_U16_SCALER_M_MAX, "scaler_m_max" }, /* 60 */
+	{ SMIAPP_REG_U16_SCALER_N_MIN, "scaler_n_min" },
+	{ SMIAPP_REG_U16_SCALER_N_MAX, "scaler_n_max" },
+	{ SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY, "spatial_sampling_capability" },
+	{ SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY, "digital_crop_capability" },
+	{ SMIAPP_REG_U16_COMPRESSION_CAPABILITY, "compression_capability" }, /* 65 */
+	{ SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY, "fifo_support_capability" },
+	{ SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY, "dphy_ctrl_capability" },
+	{ SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY, "csi_lane_mode_capability" },
+	{ SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY, "csi_signalling_mode_capability" },
+	{ SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY, "fast_standby_capability" }, /* 70 */
+	{ SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY, "cci_address_control_capability" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS, "max_per_lane_bitrate_1_lane_mode_mbps" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS, "max_per_lane_bitrate_2_lane_mode_mbps" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS, "max_per_lane_bitrate_3_lane_mode_mbps" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS, "max_per_lane_bitrate_4_lane_mode_mbps" }, /* 75 */
+	{ SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY, "temp_sensor_capability" },
+	{ SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN, "min_frame_length_lines_bin" },
+	{ SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN, "max_frame_length_lines_bin" },
+	{ SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN, "min_line_length_pck_bin" },
+	{ SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN, "max_line_length_pck_bin" }, /* 80 */
+	{ SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN, "min_line_blanking_pck_bin" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN, "fine_integration_time_min_bin" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, "fine_integration_time_max_margin_bin" },
+	{ SMIAPP_REG_U8_BINNING_CAPABILITY, "binning_capability" },
+	{ SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY, "binning_weighting_capability" }, /* 85 */
+	{ SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY, "data_transfer_if_capability" },
+	{ SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY, "shading_correction_capability" },
+	{ SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY, "green_imbalance_capability" },
+	{ SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY, "black_level_capability" },
+	{ SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY, "module_specific_correction_capability" }, /* 90 */
+	{ SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY, "defect_correction_capability" },
+	{ SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2, "defect_correction_capability_2" },
+	{ SMIAPP_REG_U8_EDOF_CAPABILITY, "edof_capability" },
+	{ SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY, "colour_feedback_capability" },
+	{ SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY, "estimation_mode_capability" }, /* 95 */
+	{ SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY, "estimation_zone_capability" },
+	{ SMIAPP_REG_U16_CAPABILITY_TRDY_MIN, "capability_trdy_min" },
+	{ SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, "flash_mode_capability" },
+	{ SMIAPP_REG_U8_ACTUATOR_CAPABILITY, "actuator_capability" },
+	{ SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1, "bracketing_lut_capability_1" }, /* 100 */
+	{ SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2, "bracketing_lut_capability_2" },
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP, "analogue_gain_code_step" },
+	{ 0, NULL },
+};
diff --git a/drivers/media/video/smiapp/smiapp-limits.h b/drivers/media/video/smiapp/smiapp-limits.h
new file mode 100644
index 0000000..7f4836bb
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-limits.h
@@ -0,0 +1,128 @@
+/*
+ * drivers/media/video/smiapp/smiapp-limits.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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
+ *
+ */
+
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY			0
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN			1
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX			2
+#define SMIAPP_LIMIT_THS_ZERO_MIN				3
+#define SMIAPP_LIMIT_TCLK_TRAIL_MIN				4
+#define SMIAPP_LIMIT_INTEGRATION_TIME_CAPABILITY		5
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN		6
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN		7
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN			8
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN		9
+#define SMIAPP_LIMIT_DIGITAL_GAIN_CAPABILITY			10
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MIN				11
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MAX				12
+#define SMIAPP_LIMIT_MIN_EXT_CLK_FREQ_HZ			13
+#define SMIAPP_LIMIT_MAX_EXT_CLK_FREQ_HZ			14
+#define SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV			15
+#define SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV			16
+#define SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ				17
+#define SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ				18
+#define SMIAPP_LIMIT_MIN_PLL_MULTIPLIER				19
+#define SMIAPP_LIMIT_MAX_PLL_MULTIPLIER				20
+#define SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ				21
+#define SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ				22
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV				23
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV				24
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ			25
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ			26
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ			27
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ			28
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV				29
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV				30
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES			31
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES			32
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK			33
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK			34
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK			35
+#define SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES			36
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_STEP_SIZE		37
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV				38
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV				39
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ			40
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ			41
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV				42
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV				43
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ			44
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ			45
+#define SMIAPP_LIMIT_X_ADDR_MIN					46
+#define SMIAPP_LIMIT_Y_ADDR_MIN					47
+#define SMIAPP_LIMIT_X_ADDR_MAX					48
+#define SMIAPP_LIMIT_Y_ADDR_MAX					49
+#define SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE				50
+#define SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE				51
+#define SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE				52
+#define SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE				53
+#define SMIAPP_LIMIT_MIN_EVEN_INC				54
+#define SMIAPP_LIMIT_MAX_EVEN_INC				55
+#define SMIAPP_LIMIT_MIN_ODD_INC				56
+#define SMIAPP_LIMIT_MAX_ODD_INC				57
+#define SMIAPP_LIMIT_SCALING_CAPABILITY				58
+#define SMIAPP_LIMIT_SCALER_M_MIN				59
+#define SMIAPP_LIMIT_SCALER_M_MAX				60
+#define SMIAPP_LIMIT_SCALER_N_MIN				61
+#define SMIAPP_LIMIT_SCALER_N_MAX				62
+#define SMIAPP_LIMIT_SPATIAL_SAMPLING_CAPABILITY		63
+#define SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY			64
+#define SMIAPP_LIMIT_COMPRESSION_CAPABILITY			65
+#define SMIAPP_LIMIT_FIFO_SUPPORT_CAPABILITY			66
+#define SMIAPP_LIMIT_DPHY_CTRL_CAPABILITY			67
+#define SMIAPP_LIMIT_CSI_LANE_MODE_CAPABILITY			68
+#define SMIAPP_LIMIT_CSI_SIGNALLING_MODE_CAPABILITY		69
+#define SMIAPP_LIMIT_FAST_STANDBY_CAPABILITY			70
+#define SMIAPP_LIMIT_CCI_ADDRESS_CONTROL_CAPABILITY		71
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS	72
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS	73
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS	74
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS	75
+#define SMIAPP_LIMIT_TEMP_SENSOR_CAPABILITY			76
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN			77
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN			78
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN			79
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN			80
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN			81
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN		82
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN	83
+#define SMIAPP_LIMIT_BINNING_CAPABILITY				84
+#define SMIAPP_LIMIT_BINNING_WEIGHTING_CAPABILITY		85
+#define SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY		86
+#define SMIAPP_LIMIT_SHADING_CORRECTION_CAPABILITY		87
+#define SMIAPP_LIMIT_GREEN_IMBALANCE_CAPABILITY			88
+#define SMIAPP_LIMIT_BLACK_LEVEL_CAPABILITY			89
+#define SMIAPP_LIMIT_MODULE_SPECIFIC_CORRECTION_CAPABILITY	90
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY		91
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY_2		92
+#define SMIAPP_LIMIT_EDOF_CAPABILITY				93
+#define SMIAPP_LIMIT_COLOUR_FEEDBACK_CAPABILITY			94
+#define SMIAPP_LIMIT_ESTIMATION_MODE_CAPABILITY			95
+#define SMIAPP_LIMIT_ESTIMATION_ZONE_CAPABILITY			96
+#define SMIAPP_LIMIT_CAPABILITY_TRDY_MIN			97
+#define SMIAPP_LIMIT_FLASH_MODE_CAPABILITY			98
+#define SMIAPP_LIMIT_ACTUATOR_CAPABILITY			99
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_1		100
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_2		101
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP			102
+#define SMIAPP_LIMIT_LAST					103
diff --git a/drivers/media/video/smiapp/smiapp-quirk.c b/drivers/media/video/smiapp/smiapp-quirk.c
new file mode 100644
index 0000000..55e8795
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-quirk.c
@@ -0,0 +1,306 @@
+/*
+ * drivers/media/video/smiapp/smiapp-quirk.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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
+ *
+ */
+
+#include <linux/delay.h>
+
+#include "smiapp.h"
+
+static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val)
+{
+	return smiapp_write(sensor, (SMIA_REG_8BIT << 16) | reg, val);
+}
+
+static int smiapp_write_8s(struct smiapp_sensor *sensor,
+			   struct smiapp_reg_8 *regs, int len)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	for (; len > 0; len--, regs++) {
+		rval = smiapp_write_8(sensor, regs->reg, regs->val);
+		if (rval < 0) {
+			dev_err(&client->dev,
+				"error %d writing reg 0x%4.4x, val 0x%2.2x",
+				rval, regs->reg, regs->val);
+			return rval;
+		}
+	}
+
+	return 0;
+}
+
+void smiapp_replace_limit(struct smiapp_sensor *sensor,
+			  u32 limit, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+	dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" = %d, 0x%x\n",
+		smiapp_reg_limits[limit].addr,
+		smiapp_reg_limits[limit].what, val, val);
+	sensor->limits[limit] = val;
+}
+
+int smiapp_replace_limit_at(struct smiapp_sensor *sensor,
+			    u32 reg, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int i;
+
+	for (i = 0; smiapp_reg_limits[i].addr; i++) {
+		if ((smiapp_reg_limits[i].addr & 0xffff) != reg)
+			continue;
+
+		smiapp_replace_limit(sensor, i, val);
+
+		return 0;
+	}
+
+	dev_dbg(&client->dev, "quirk: bad register 0x%4.4x\n", reg);
+
+	return -EINVAL;
+}
+
+bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
+		      u32 reg, u32 *val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	const struct smia_reg *sreg;
+
+	if (!sensor->minfo.quirk)
+		return false;
+
+	sreg = sensor->minfo.quirk->regs;
+
+	if (!sreg)
+		return false;
+
+	while (sreg->type) {
+		u16 type = reg >> 16;
+		u16 reg16 = reg;
+
+		if (sreg->type != type || sreg->reg != reg16) {
+			sreg++;
+			continue;
+		}
+
+		switch ((u8)type) {
+		case SMIA_REG_8BIT:
+			dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%2.2x\n",
+				reg, sreg->val);
+			break;
+		case SMIA_REG_16BIT:
+			dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%4.4x\n",
+				reg, sreg->val);
+			break;
+		case SMIA_REG_32BIT:
+			dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%8.8x\n",
+				reg, sreg->val);
+			break;
+		}
+
+		*val = sreg->val;
+
+		return true;
+	}
+
+	return false;
+}
+
+static int jt8ew9_limits(struct smiapp_sensor *sensor)
+{
+	if (sensor->minfo.revision_number_major < 0x03)
+		sensor->frame_skip = 1;
+
+	/* Below 24 gain doesn't have effect at all, */
+	/* but ~59 is needed for full dynamic range */
+	smiapp_replace_limit(sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN, 59);
+	smiapp_replace_limit(
+		sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX, 6000);
+
+	return 0;
+}
+
+static int jt8ew9_post_poweron(struct smiapp_sensor *sensor)
+{
+	struct smiapp_reg_8 regs[] = {
+		{ 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */
+		{ 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+		{ 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+		{ 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */
+		{ 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+		{ 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+		{ 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+		{ 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+		{ 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */
+		{ 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+		{ 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+		{ 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+		{ 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+		/* Taken from v03. No idea what the rest are. */
+		{ 0x32e0, 0x05 },
+		{ 0x32e1, 0x05 },
+		{ 0x32e2, 0x04 },
+		{ 0x32e5, 0x04 },
+		{ 0x32e6, 0x04 },
+
+	};
+
+	return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_jt8ew9_quirk = {
+	.limits = jt8ew9_limits,
+	.post_poweron = jt8ew9_post_poweron,
+};
+
+static int imx125es_post_poweron(struct smiapp_sensor *sensor)
+{
+	/* Taken from v02. No idea what the other two are. */
+	struct smiapp_reg_8 regs[] = {
+		/*
+		 * 0x3302: clk during frame blanking:
+		 * 0x00 - HS mode, 0x01 - LP11
+		 */
+		{ 0x3302, 0x01 },
+		{ 0x302d, 0x00 },
+		{ 0x3b08, 0x8c },
+	};
+
+	return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_imx125es_quirk = {
+	.post_poweron = imx125es_post_poweron,
+};
+
+static int jt8ev1_limits(struct smiapp_sensor *sensor)
+{
+	smiapp_replace_limit(sensor, SMIAPP_LIMIT_X_ADDR_MAX, 4271);
+	smiapp_replace_limit(sensor,
+			     SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, 184);
+
+	return 0;
+}
+
+static int jt8ev1_post_poweron(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	struct smiapp_reg_8 regs[] = {
+		{ 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */
+		{ 0x30a3, 0xd0 }, /* FLASH STROBE enable */
+		{ 0x3237, 0x00 }, /* For control of pulse timing for ADC */
+		{ 0x3238, 0x43 },
+		{ 0x3301, 0x06 }, /* For analog bias for sensor */
+		{ 0x3302, 0x06 },
+		{ 0x3304, 0x00 },
+		{ 0x3305, 0x88 },
+		{ 0x332a, 0x14 },
+		{ 0x332c, 0x6b },
+		{ 0x3336, 0x01 },
+		{ 0x333f, 0x1f },
+		{ 0x3355, 0x00 },
+		{ 0x3356, 0x20 },
+		{ 0x33bf, 0x20 }, /* Adjust the FBC speed */
+		{ 0x33c9, 0x20 },
+		{ 0x33ce, 0x30 }, /* Adjust the parameter for logic function */
+		{ 0x33cf, 0xec }, /* For Black sun */
+		{ 0x3328, 0x80 }, /* Ugh. No idea what's this. */
+	};
+
+	struct smiapp_reg_8 regs_96[] = {
+		{ 0x30ae, 0x00 }, /* For control of ADC clock */
+		{ 0x30af, 0xd0 },
+		{ 0x30b0, 0x01 },
+	};
+
+	rval = smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+	if (rval < 0)
+		return rval;
+
+	switch (sensor->platform_data->ext_clk) {
+	case 9600000:
+		return smiapp_write_8s(sensor, regs_96,
+				       ARRAY_SIZE(regs_96));
+	default:
+		dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n",
+			 sensor->platform_data->ext_clk);
+		return 0;
+	}
+}
+
+static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor)
+{
+	return smiapp_write_8(sensor, 0x3328, 0x00);
+}
+
+static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
+{
+	int rval;
+
+	/* Workaround: allows fast standby to work properly */
+	rval = smiapp_write_8(sensor, 0x3205, 0x04);
+	if (rval < 0)
+		return rval;
+
+	/* Wait for 1 ms + one line => 2 ms is likely enough */
+	usleep_range(2000, 2000);
+
+	/* Restore it */
+	rval = smiapp_write_8(sensor, 0x3205, 0x00);
+	if (rval < 0)
+		return rval;
+
+	return smiapp_write_8(sensor, 0x3328, 0x80);
+}
+
+const struct smiapp_quirk smiapp_jt8ev1_quirk = {
+	.limits = jt8ev1_limits,
+	.post_poweron = jt8ev1_post_poweron,
+	.pre_streamon = jt8ev1_pre_streamon,
+	.post_streamoff = jt8ev1_post_streamoff,
+	.flags = SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE,
+};
+
+static int tcm8500md_limits(struct smiapp_sensor *sensor)
+{
+	smiapp_replace_limit(sensor, SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ, 2700000);
+
+	return 0;
+}
+
+const struct smiapp_quirk smiapp_tcm8500md_quirk = {
+	.limits = tcm8500md_limits,
+};
diff --git a/drivers/media/video/smiapp/smiapp-quirk.h b/drivers/media/video/smiapp/smiapp-quirk.h
new file mode 100644
index 0000000..f4dcaab
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-quirk.h
@@ -0,0 +1,83 @@
+/*
+ * drivers/media/video/smiapp/smiapp-quirk.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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 __SMIAPP_QUIRK__
+#define __SMIAPP_QUIRK__
+
+struct smiapp_sensor;
+
+/**
+ * struct smiapp_quirk - quirks for sensors that deviate from SMIA++ standard
+ *
+ * @limits: Replace sensor->limits with values which can't be read from
+ *	    sensor registers. Called the first time the sensor is powered up.
+ * @post_poweron: Called always after the sensor has been fully powered on.
+ * @pre_streamon: Called just before streaming is enabled.
+ * @post_streamon: Called right after stopping streaming.
+ */
+struct smiapp_quirk {
+	int (*limits)(struct smiapp_sensor *sensor);
+	int (*post_poweron)(struct smiapp_sensor *sensor);
+	int (*pre_streamon)(struct smiapp_sensor *sensor);
+	int (*post_streamoff)(struct smiapp_sensor *sensor);
+	const struct smia_reg *regs;
+	unsigned long flags;
+};
+
+/* op pix clock is for all lanes in total normally */
+#define SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE			(1 << 0)
+#define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY			(1 << 1)
+
+struct smiapp_reg_8 {
+	u16 reg;
+	u8 val;
+};
+
+void smiapp_replace_limit(struct smiapp_sensor *sensor,
+			  u32 limit, u32 val);
+bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
+		      u32 reg, u32 *val);
+
+#define SMIAPP_MK_QUIRK_REG(_reg, _val) \
+	{				\
+		.type = (_reg >> 16),	\
+		.reg = (u16)_reg,	\
+		.val = _val,		\
+	}
+
+#define smiapp_call_quirk(_sensor, _quirk, ...)				\
+	(_sensor->minfo.quirk &&					\
+	 _sensor->minfo.quirk->_quirk ?					\
+	 _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0)
+
+#define smiapp_needs_quirk(_sensor, _quirk)		\
+	(_sensor->minfo.quirk ?				\
+	 _sensor->minfo.quirk->flags & _quirk : 0)
+
+extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
+extern const struct smiapp_quirk smiapp_imx125es_quirk;
+extern const struct smiapp_quirk smiapp_jt8ew9_quirk;
+extern const struct smiapp_quirk smiapp_tcm8500md_quirk;
+
+#endif /* __SMIAPP_QUIRK__ */
diff --git a/drivers/media/video/smiapp/smiapp-reg-defs.h b/drivers/media/video/smiapp/smiapp-reg-defs.h
new file mode 100644
index 0000000..a089eb8
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-reg-defs.h
@@ -0,0 +1,503 @@
+/*
+ * drivers/media/video/smiapp/smiapp-reg-defs.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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
+ *
+ */
+#define SMIAPP_REG_MK_U8(r) ((SMIA_REG_8BIT << 16) | (r))
+#define SMIAPP_REG_MK_U16(r) ((SMIA_REG_16BIT << 16) | (r))
+#define SMIAPP_REG_MK_U32(r) ((SMIA_REG_32BIT << 16) | (r))
+
+#define SMIAPP_REG_MK_F32(r) (SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | (r))
+
+#define SMIAPP_REG_U16_MODEL_ID					SMIAPP_REG_MK_U16(0x0000)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR			SMIAPP_REG_MK_U8(0x0002)
+#define SMIAPP_REG_U8_MANUFACTURER_ID				SMIAPP_REG_MK_U8(0x0003)
+#define SMIAPP_REG_U8_SMIA_VERSION				SMIAPP_REG_MK_U8(0x0004)
+#define SMIAPP_REG_U8_FRAME_COUNT				SMIAPP_REG_MK_U8(0x0005)
+#define SMIAPP_REG_U8_PIXEL_ORDER				SMIAPP_REG_MK_U8(0x0006)
+#define SMIAPP_REG_U16_DATA_PEDESTAL				SMIAPP_REG_MK_U16(0x0008)
+#define SMIAPP_REG_U8_PIXEL_DEPTH				SMIAPP_REG_MK_U8(0x000c)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR			SMIAPP_REG_MK_U8(0x0010)
+#define SMIAPP_REG_U8_SMIAPP_VERSION				SMIAPP_REG_MK_U8(0x0011)
+#define SMIAPP_REG_U8_MODULE_DATE_YEAR				SMIAPP_REG_MK_U8(0x0012)
+#define SMIAPP_REG_U8_MODULE_DATE_MONTH				SMIAPP_REG_MK_U8(0x0013)
+#define SMIAPP_REG_U8_MODULE_DATE_DAY				SMIAPP_REG_MK_U8(0x0014)
+#define SMIAPP_REG_U8_MODULE_DATE_PHASE				SMIAPP_REG_MK_U8(0x0015)
+#define SMIAPP_REG_U16_SENSOR_MODEL_ID				SMIAPP_REG_MK_U16(0x0016)
+#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER			SMIAPP_REG_MK_U8(0x0018)
+#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID			SMIAPP_REG_MK_U8(0x0019)
+#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION			SMIAPP_REG_MK_U8(0x001a)
+#define SMIAPP_REG_U32_SERIAL_NUMBER				SMIAPP_REG_MK_U32(0x001c)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE			SMIAPP_REG_MK_U8(0x0040)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE		SMIAPP_REG_MK_U8(0x0041)
+#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n)		SMIAPP_REG_MK_U16(0x0042 + ((n) << 1)) /* 0 <= n <= 14 */
+#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n)		SMIAPP_REG_MK_U32(0x0060 + ((n) << 2)) /* 0 <= n <= 7 */
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY			SMIAPP_REG_MK_U16(0x0080)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN			SMIAPP_REG_MK_U16(0x0084)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX			SMIAPP_REG_MK_U16(0x0086)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP			SMIAPP_REG_MK_U16(0x0088)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE			SMIAPP_REG_MK_U16(0x008a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0				SMIAPP_REG_MK_U16(0x008c)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0				SMIAPP_REG_MK_U16(0x008e)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1				SMIAPP_REG_MK_U16(0x0090)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1				SMIAPP_REG_MK_U16(0x0092)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE			SMIAPP_REG_MK_U8(0x00c0)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE			SMIAPP_REG_MK_U8(0x00c1)
+#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n)		SMIAPP_REG_MK_U16(0x00c2 + ((n) << 1))
+#define SMIAPP_REG_U8_MODE_SELECT				SMIAPP_REG_MK_U8(0x0100)
+#define SMIAPP_REG_U8_IMAGE_ORIENTATION				SMIAPP_REG_MK_U8(0x0101)
+#define SMIAPP_REG_U8_SOFTWARE_RESET				SMIAPP_REG_MK_U8(0x0103)
+#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD			SMIAPP_REG_MK_U8(0x0104)
+#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES			SMIAPP_REG_MK_U8(0x0105)
+#define SMIAPP_REG_U8_FAST_STANDBY_CTRL				SMIAPP_REG_MK_U8(0x0106)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL			SMIAPP_REG_MK_U8(0x0107)
+#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL			SMIAPP_REG_MK_U8(0x0108)
+#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL			SMIAPP_REG_MK_U8(0x0109)
+#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER			SMIAPP_REG_MK_U8(0x0110)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE			SMIAPP_REG_MK_U8(0x0111)
+#define SMIAPP_REG_U16_CSI_DATA_FORMAT				SMIAPP_REG_MK_U16(0x0112)
+#define SMIAPP_REG_U8_CSI_LANE_MODE				SMIAPP_REG_MK_U8(0x0114)
+#define SMIAPP_REG_U8_CSI2_10_TO_8_DT				SMIAPP_REG_MK_U8(0x0115)
+#define SMIAPP_REG_U8_CSI2_10_TO_7_DT				SMIAPP_REG_MK_U8(0x0116)
+#define SMIAPP_REG_U8_CSI2_10_TO_6_DT				SMIAPP_REG_MK_U8(0x0117)
+#define SMIAPP_REG_U8_CSI2_12_TO_8_DT				SMIAPP_REG_MK_U8(0x0118)
+#define SMIAPP_REG_U8_CSI2_12_TO_7_DT				SMIAPP_REG_MK_U8(0x0119)
+#define SMIAPP_REG_U8_CSI2_12_TO_6_DT				SMIAPP_REG_MK_U8(0x011a)
+#define SMIAPP_REG_U8_CSI2_14_TO_10_DT				SMIAPP_REG_MK_U8(0x011b)
+#define SMIAPP_REG_U8_CSI2_14_TO_8_DT				SMIAPP_REG_MK_U8(0x011c)
+#define SMIAPP_REG_U8_CSI2_16_TO_10_DT				SMIAPP_REG_MK_U8(0x011d)
+#define SMIAPP_REG_U8_CSI2_16_TO_8_DT				SMIAPP_REG_MK_U8(0x011e)
+#define SMIAPP_REG_U8_GAIN_MODE					SMIAPP_REG_MK_U8(0x0120)
+#define SMIAPP_REG_U16_VANA_VOLTAGE				SMIAPP_REG_MK_U16(0x0130)
+#define SMIAPP_REG_U16_VDIG_VOLTAGE				SMIAPP_REG_MK_U16(0x0132)
+#define SMIAPP_REG_U16_VIO_VOLTAGE				SMIAPP_REG_MK_U16(0x0134)
+#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ			SMIAPP_REG_MK_U16(0x0136)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL			SMIAPP_REG_MK_U8(0x0138)
+#define SMIAPP_REG_U8_TEMP_SENSOR_MODE				SMIAPP_REG_MK_U8(0x0139)
+#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT			SMIAPP_REG_MK_U8(0x013a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME			SMIAPP_REG_MK_U16(0x0200)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME			SMIAPP_REG_MK_U16(0x0202)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL		SMIAPP_REG_MK_U16(0x0204)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR		SMIAPP_REG_MK_U16(0x0206)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED			SMIAPP_REG_MK_U16(0x0208)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE			SMIAPP_REG_MK_U16(0x020a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB		SMIAPP_REG_MK_U16(0x020c)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR			SMIAPP_REG_MK_U16(0x020e)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_RED				SMIAPP_REG_MK_U16(0x0210)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE			SMIAPP_REG_MK_U16(0x0212)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB			SMIAPP_REG_MK_U16(0x0214)
+#define SMIAPP_REG_U16_VT_PIX_CLK_DIV				SMIAPP_REG_MK_U16(0x0300)
+#define SMIAPP_REG_U16_VT_SYS_CLK_DIV				SMIAPP_REG_MK_U16(0x0302)
+#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV				SMIAPP_REG_MK_U16(0x0304)
+#define SMIAPP_REG_U16_PLL_MULTIPLIER				SMIAPP_REG_MK_U16(0x0306)
+#define SMIAPP_REG_U16_OP_PIX_CLK_DIV				SMIAPP_REG_MK_U16(0x0308)
+#define SMIAPP_REG_U16_OP_SYS_CLK_DIV				SMIAPP_REG_MK_U16(0x030a)
+#define SMIAPP_REG_U16_FRAME_LENGTH_LINES			SMIAPP_REG_MK_U16(0x0340)
+#define SMIAPP_REG_U16_LINE_LENGTH_PCK				SMIAPP_REG_MK_U16(0x0342)
+#define SMIAPP_REG_U16_X_ADDR_START				SMIAPP_REG_MK_U16(0x0344)
+#define SMIAPP_REG_U16_Y_ADDR_START				SMIAPP_REG_MK_U16(0x0346)
+#define SMIAPP_REG_U16_X_ADDR_END				SMIAPP_REG_MK_U16(0x0348)
+#define SMIAPP_REG_U16_Y_ADDR_END				SMIAPP_REG_MK_U16(0x034a)
+#define SMIAPP_REG_U16_X_OUTPUT_SIZE				SMIAPP_REG_MK_U16(0x034c)
+#define SMIAPP_REG_U16_Y_OUTPUT_SIZE				SMIAPP_REG_MK_U16(0x034e)
+#define SMIAPP_REG_U16_X_EVEN_INC				SMIAPP_REG_MK_U16(0x0380)
+#define SMIAPP_REG_U16_X_ODD_INC				SMIAPP_REG_MK_U16(0x0382)
+#define SMIAPP_REG_U16_Y_EVEN_INC				SMIAPP_REG_MK_U16(0x0384)
+#define SMIAPP_REG_U16_Y_ODD_INC				SMIAPP_REG_MK_U16(0x0386)
+#define SMIAPP_REG_U16_SCALING_MODE				SMIAPP_REG_MK_U16(0x0400)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING				SMIAPP_REG_MK_U16(0x0402)
+#define SMIAPP_REG_U16_SCALE_M					SMIAPP_REG_MK_U16(0x0404)
+#define SMIAPP_REG_U16_SCALE_N					SMIAPP_REG_MK_U16(0x0406)
+#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET			SMIAPP_REG_MK_U16(0x0408)
+#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET			SMIAPP_REG_MK_U16(0x040a)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH			SMIAPP_REG_MK_U16(0x040c)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT		SMIAPP_REG_MK_U16(0x040e)
+#define SMIAPP_REG_U16_COMPRESSION_MODE				SMIAPP_REG_MK_U16(0x0500)
+#define SMIAPP_REG_U16_TEST_PATTERN_MODE			SMIAPP_REG_MK_U16(0x0600)
+#define SMIAPP_REG_U16_TEST_DATA_RED				SMIAPP_REG_MK_U16(0x0602)
+#define SMIAPP_REG_U16_TEST_DATA_GREENR				SMIAPP_REG_MK_U16(0x0604)
+#define SMIAPP_REG_U16_TEST_DATA_BLUE				SMIAPP_REG_MK_U16(0x0606)
+#define SMIAPP_REG_U16_TEST_DATA_GREENB				SMIAPP_REG_MK_U16(0x0608)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH			SMIAPP_REG_MK_U16(0x060a)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION		SMIAPP_REG_MK_U16(0x060c)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH			SMIAPP_REG_MK_U16(0x060e)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION			SMIAPP_REG_MK_U16(0x0610)
+#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS			SMIAPP_REG_MK_U16(0x0700)
+#define SMIAPP_REG_U8_TCLK_POST					SMIAPP_REG_MK_U8(0x0800)
+#define SMIAPP_REG_U8_THS_PREPARE				SMIAPP_REG_MK_U8(0x0801)
+#define SMIAPP_REG_U8_THS_ZERO_MIN				SMIAPP_REG_MK_U8(0x0802)
+#define SMIAPP_REG_U8_THS_TRAIL					SMIAPP_REG_MK_U8(0x0803)
+#define SMIAPP_REG_U8_TCLK_TRAIL_MIN				SMIAPP_REG_MK_U8(0x0804)
+#define SMIAPP_REG_U8_TCLK_PREPARE				SMIAPP_REG_MK_U8(0x0805)
+#define SMIAPP_REG_U8_TCLK_ZERO					SMIAPP_REG_MK_U8(0x0806)
+#define SMIAPP_REG_U8_TLPX					SMIAPP_REG_MK_U8(0x0807)
+#define SMIAPP_REG_U8_DPHY_CTRL					SMIAPP_REG_MK_U8(0x0808)
+#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS		SMIAPP_REG_MK_U32(0x0820)
+#define SMIAPP_REG_U8_BINNING_MODE				SMIAPP_REG_MK_U8(0x0900)
+#define SMIAPP_REG_U8_BINNING_TYPE				SMIAPP_REG_MK_U8(0x0901)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING				SMIAPP_REG_MK_U8(0x0902)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL			SMIAPP_REG_MK_U8(0x0a00)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS			SMIAPP_REG_MK_U8(0x0a01)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT		SMIAPP_REG_MK_U8(0x0a02)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0			SMIAPP_REG_MK_U8(0x0a04)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1			SMIAPP_REG_MK_U8(0x0a05)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2			SMIAPP_REG_MK_U8(0x0a06)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3			SMIAPP_REG_MK_U8(0x0a07)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4			SMIAPP_REG_MK_U8(0x0a08)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5			SMIAPP_REG_MK_U8(0x0a09)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12		SMIAPP_REG_MK_U8(0x0a10)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13		SMIAPP_REG_MK_U8(0x0a11)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14		SMIAPP_REG_MK_U8(0x0a12)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15		SMIAPP_REG_MK_U8(0x0a13)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16		SMIAPP_REG_MK_U8(0x0a14)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17		SMIAPP_REG_MK_U8(0x0a15)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18		SMIAPP_REG_MK_U8(0x0a16)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19		SMIAPP_REG_MK_U8(0x0a17)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20		SMIAPP_REG_MK_U8(0x0a18)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21		SMIAPP_REG_MK_U8(0x0a19)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22		SMIAPP_REG_MK_U8(0x0a1a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23		SMIAPP_REG_MK_U8(0x0a1b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24		SMIAPP_REG_MK_U8(0x0a1c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25		SMIAPP_REG_MK_U8(0x0a1d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26		SMIAPP_REG_MK_U8(0x0a1e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27		SMIAPP_REG_MK_U8(0x0a1f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28		SMIAPP_REG_MK_U8(0x0a20)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29		SMIAPP_REG_MK_U8(0x0a21)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30		SMIAPP_REG_MK_U8(0x0a22)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31		SMIAPP_REG_MK_U8(0x0a23)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32		SMIAPP_REG_MK_U8(0x0a24)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33		SMIAPP_REG_MK_U8(0x0a25)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34		SMIAPP_REG_MK_U8(0x0a26)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35		SMIAPP_REG_MK_U8(0x0a27)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36		SMIAPP_REG_MK_U8(0x0a28)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37		SMIAPP_REG_MK_U8(0x0a29)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38		SMIAPP_REG_MK_U8(0x0a2a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39		SMIAPP_REG_MK_U8(0x0a2b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40		SMIAPP_REG_MK_U8(0x0a2c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41		SMIAPP_REG_MK_U8(0x0a2d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42		SMIAPP_REG_MK_U8(0x0a2e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43		SMIAPP_REG_MK_U8(0x0a2f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44		SMIAPP_REG_MK_U8(0x0a30)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45		SMIAPP_REG_MK_U8(0x0a31)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46		SMIAPP_REG_MK_U8(0x0a32)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47		SMIAPP_REG_MK_U8(0x0a33)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48		SMIAPP_REG_MK_U8(0x0a34)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49		SMIAPP_REG_MK_U8(0x0a35)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50		SMIAPP_REG_MK_U8(0x0a36)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51		SMIAPP_REG_MK_U8(0x0a37)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52		SMIAPP_REG_MK_U8(0x0a38)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53		SMIAPP_REG_MK_U8(0x0a39)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54		SMIAPP_REG_MK_U8(0x0a3a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55		SMIAPP_REG_MK_U8(0x0a3b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56		SMIAPP_REG_MK_U8(0x0a3c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57		SMIAPP_REG_MK_U8(0x0a3d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58		SMIAPP_REG_MK_U8(0x0a3e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59		SMIAPP_REG_MK_U8(0x0a3f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60		SMIAPP_REG_MK_U8(0x0a40)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61		SMIAPP_REG_MK_U8(0x0a41)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62		SMIAPP_REG_MK_U8(0x0a42)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63		SMIAPP_REG_MK_U8(0x0a43)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL			SMIAPP_REG_MK_U8(0x0a44)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS			SMIAPP_REG_MK_U8(0x0a45)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT		SMIAPP_REG_MK_U8(0x0a46)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0			SMIAPP_REG_MK_U8(0x0a48)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1			SMIAPP_REG_MK_U8(0x0a49)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2			SMIAPP_REG_MK_U8(0x0a4a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3			SMIAPP_REG_MK_U8(0x0a4b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4			SMIAPP_REG_MK_U8(0x0a4c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5			SMIAPP_REG_MK_U8(0x0a4d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6			SMIAPP_REG_MK_U8(0x0a4e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7			SMIAPP_REG_MK_U8(0x0a4f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8			SMIAPP_REG_MK_U8(0x0a50)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9			SMIAPP_REG_MK_U8(0x0a51)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10		SMIAPP_REG_MK_U8(0x0a52)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11		SMIAPP_REG_MK_U8(0x0a53)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12		SMIAPP_REG_MK_U8(0x0a54)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13		SMIAPP_REG_MK_U8(0x0a55)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14		SMIAPP_REG_MK_U8(0x0a56)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15		SMIAPP_REG_MK_U8(0x0a57)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16		SMIAPP_REG_MK_U8(0x0a58)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17		SMIAPP_REG_MK_U8(0x0a59)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18		SMIAPP_REG_MK_U8(0x0a5a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19		SMIAPP_REG_MK_U8(0x0a5b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20		SMIAPP_REG_MK_U8(0x0a5c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21		SMIAPP_REG_MK_U8(0x0a5d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22		SMIAPP_REG_MK_U8(0x0a5e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23		SMIAPP_REG_MK_U8(0x0a5f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24		SMIAPP_REG_MK_U8(0x0a60)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25		SMIAPP_REG_MK_U8(0x0a61)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26		SMIAPP_REG_MK_U8(0x0a62)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27		SMIAPP_REG_MK_U8(0x0a63)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28		SMIAPP_REG_MK_U8(0x0a64)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29		SMIAPP_REG_MK_U8(0x0a65)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30		SMIAPP_REG_MK_U8(0x0a66)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31		SMIAPP_REG_MK_U8(0x0a67)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32		SMIAPP_REG_MK_U8(0x0a68)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33		SMIAPP_REG_MK_U8(0x0a69)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34		SMIAPP_REG_MK_U8(0x0a6a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35		SMIAPP_REG_MK_U8(0x0a6b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36		SMIAPP_REG_MK_U8(0x0a6c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37		SMIAPP_REG_MK_U8(0x0a6d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38		SMIAPP_REG_MK_U8(0x0a6e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39		SMIAPP_REG_MK_U8(0x0a6f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40		SMIAPP_REG_MK_U8(0x0a70)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41		SMIAPP_REG_MK_U8(0x0a71)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42		SMIAPP_REG_MK_U8(0x0a72)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43		SMIAPP_REG_MK_U8(0x0a73)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44		SMIAPP_REG_MK_U8(0x0a74)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45		SMIAPP_REG_MK_U8(0x0a75)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46		SMIAPP_REG_MK_U8(0x0a76)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47		SMIAPP_REG_MK_U8(0x0a77)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48		SMIAPP_REG_MK_U8(0x0a78)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49		SMIAPP_REG_MK_U8(0x0a79)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50		SMIAPP_REG_MK_U8(0x0a7a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51		SMIAPP_REG_MK_U8(0x0a7b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52		SMIAPP_REG_MK_U8(0x0a7c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53		SMIAPP_REG_MK_U8(0x0a7d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54		SMIAPP_REG_MK_U8(0x0a7e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55		SMIAPP_REG_MK_U8(0x0a7f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56		SMIAPP_REG_MK_U8(0x0a80)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57		SMIAPP_REG_MK_U8(0x0a81)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58		SMIAPP_REG_MK_U8(0x0a82)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59		SMIAPP_REG_MK_U8(0x0a83)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60		SMIAPP_REG_MK_U8(0x0a84)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61		SMIAPP_REG_MK_U8(0x0a85)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62		SMIAPP_REG_MK_U8(0x0a86)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63		SMIAPP_REG_MK_U8(0x0a87)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE			SMIAPP_REG_MK_U8(0x0b00)
+#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL		SMIAPP_REG_MK_U8(0x0b01)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE		SMIAPP_REG_MK_U8(0x0b02)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT		SMIAPP_REG_MK_U8(0x0b03)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE		SMIAPP_REG_MK_U8(0x0b04)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b05)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b06)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT		SMIAPP_REG_MK_U8(0x0b07)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b08)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT		SMIAPP_REG_MK_U8(0x0b09)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b0a)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT		SMIAPP_REG_MK_U8(0x0b0b)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE		SMIAPP_REG_MK_U8(0x0b0c)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT		SMIAPP_REG_MK_U8(0x0b0d)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b0e)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST		SMIAPP_REG_MK_U8(0x0b0f)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST		SMIAPP_REG_MK_U8(0x0b10)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE	SMIAPP_REG_MK_U8(0x0b11)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST	SMIAPP_REG_MK_U8(0x0b12)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE	SMIAPP_REG_MK_U8(0x0b13)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST	SMIAPP_REG_MK_U8(0x0b14)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE	SMIAPP_REG_MK_U8(0x0b15)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST	SMIAPP_REG_MK_U8(0x0b16)
+#define SMIAPP_REG_U8_EDOF_MODE					SMIAPP_REG_MK_U8(0x0b80)
+#define SMIAPP_REG_U8_SHARPNESS					SMIAPP_REG_MK_U8(0x0b83)
+#define SMIAPP_REG_U8_DENOISING					SMIAPP_REG_MK_U8(0x0b84)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC				SMIAPP_REG_MK_U8(0x0b85)
+#define SMIAPP_REG_U16_DEPTH_OF_FIELD				SMIAPP_REG_MK_U16(0x0b86)
+#define SMIAPP_REG_U16_FOCUS_DISTANCE				SMIAPP_REG_MK_U16(0x0b88)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL			SMIAPP_REG_MK_U8(0x0b8a)
+#define SMIAPP_REG_U16_COLOUR_TEMPERATURE			SMIAPP_REG_MK_U16(0x0b8c)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR			SMIAPP_REG_MK_U16(0x0b8e)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED			SMIAPP_REG_MK_U16(0x0b90)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE			SMIAPP_REG_MK_U16(0x0b92)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB			SMIAPP_REG_MK_U16(0x0b94)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE			SMIAPP_REG_MK_U8(0x0bc0)
+#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING			SMIAPP_REG_MK_U16(0x0bc2)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START			SMIAPP_REG_MK_U16(0x0bc4)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START			SMIAPP_REG_MK_U16(0x0bc6)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH			SMIAPP_REG_MK_U16(0x0bc8)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT			SMIAPP_REG_MK_U16(0x0bca)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1			SMIAPP_REG_MK_U8(0x0c00)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2			SMIAPP_REG_MK_U8(0x0c01)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1		SMIAPP_REG_MK_U8(0x0c02)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2		SMIAPP_REG_MK_U8(0x0c03)
+#define SMIAPP_REG_U16_TRDY_CTRL				SMIAPP_REG_MK_U16(0x0c04)
+#define SMIAPP_REG_U16_TRDOUT_CTRL				SMIAPP_REG_MK_U16(0x0c06)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL		SMIAPP_REG_MK_U16(0x0c08)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL		SMIAPP_REG_MK_U16(0x0c0a)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL			SMIAPP_REG_MK_U16(0x0c0c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL		SMIAPP_REG_MK_U16(0x0c0e)
+#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL			SMIAPP_REG_MK_U16(0x0c10)
+#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT			SMIAPP_REG_MK_U8(0x0c12)
+#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT			SMIAPP_REG_MK_U16(0x0c14)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL		SMIAPP_REG_MK_U16(0x0c16)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL		SMIAPP_REG_MK_U16(0x0c18)
+#define SMIAPP_REG_U8_FLASH_MODE_RS				SMIAPP_REG_MK_U8(0x0c1a)
+#define SMIAPP_REG_U8_FLASH_TRIGGER_RS				SMIAPP_REG_MK_U8(0x0c1b)
+#define SMIAPP_REG_U8_FLASH_STATUS				SMIAPP_REG_MK_U8(0x0c1c)
+#define SMIAPP_REG_U8_SA_STROBE_MODE				SMIAPP_REG_MK_U8(0x0c1d)
+#define SMIAPP_REG_U16_SA_STROBE_START_POINT			SMIAPP_REG_MK_U16(0x0c1e)
+#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL			SMIAPP_REG_MK_U16(0x0c20)
+#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL			SMIAPP_REG_MK_U16(0x0c22)
+#define SMIAPP_REG_U8_SA_STROBE_TRIGGER				SMIAPP_REG_MK_U8(0x0c24)
+#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS			SMIAPP_REG_MK_U8(0x0c25)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL	SMIAPP_REG_MK_U16(0x0c26)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL		SMIAPP_REG_MK_U16(0x0c28)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL		SMIAPP_REG_MK_U8(0x0c2a)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL			SMIAPP_REG_MK_U8(0x0c2b)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL		SMIAPP_REG_MK_U16(0x0c2c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL		SMIAPP_REG_MK_U16(0x0c2e)
+#define SMIAPP_REG_U8_LOW_LEVEL_CTRL				SMIAPP_REG_MK_U8(0x0c80)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT			SMIAPP_REG_MK_U16(0x0c82)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_T3				SMIAPP_REG_MK_U16(0x0c84)
+#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT			SMIAPP_REG_MK_U8(0x0c86)
+#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3			SMIAPP_REG_MK_U16(0x0c88)
+#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT			SMIAPP_REG_MK_U8(0x0c8a)
+#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3			SMIAPP_REG_MK_U16(0x0c8c)
+#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT			SMIAPP_REG_MK_U8(0x0c8e)
+#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL				SMIAPP_REG_MK_U8(0x0d00)
+#define SMIAPP_REG_U8_OPERATION_MODE				SMIAPP_REG_MK_U8(0x0d01)
+#define SMIAPP_REG_U8_ACT_STATE1				SMIAPP_REG_MK_U8(0x0d02)
+#define SMIAPP_REG_U8_ACT_STATE2				SMIAPP_REG_MK_U8(0x0d03)
+#define SMIAPP_REG_U16_FOCUS_CHANGE				SMIAPP_REG_MK_U16(0x0d80)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL			SMIAPP_REG_MK_U16(0x0d82)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1		SMIAPP_REG_MK_U16(0x0d84)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2		SMIAPP_REG_MK_U16(0x0d86)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1			SMIAPP_REG_MK_U8(0x0d88)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2			SMIAPP_REG_MK_U8(0x0d89)
+#define SMIAPP_REG_U8_POSITION					SMIAPP_REG_MK_U8(0x0d8a)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL			SMIAPP_REG_MK_U8(0x0e00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_MODE			SMIAPP_REG_MK_U8(0x0e01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL		SMIAPP_REG_MK_U8(0x0e02)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_START			SMIAPP_REG_MK_U8(0x0e10)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_END			SMIAPP_REG_MK_U8(0x0eff)
+#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY		SMIAPP_REG_MK_U16(0x1000)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN		SMIAPP_REG_MK_U16(0x1004)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN	SMIAPP_REG_MK_U16(0x1006)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN		SMIAPP_REG_MK_U16(0x1008)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN		SMIAPP_REG_MK_U16(0x100a)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY			SMIAPP_REG_MK_U16(0x1080)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN				SMIAPP_REG_MK_U16(0x1084)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX				SMIAPP_REG_MK_U16(0x1086)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE			SMIAPP_REG_MK_U16(0x1088)
+#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1100)
+#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1104)
+#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV			SMIAPP_REG_MK_U16(0x1108)
+#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV			SMIAPP_REG_MK_U16(0x110a)
+#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ			SMIAPP_REG_MK_F32(0x110c)
+#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ			SMIAPP_REG_MK_F32(0x1110)
+#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER			SMIAPP_REG_MK_U16(0x1114)
+#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER			SMIAPP_REG_MK_U16(0x1116)
+#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ			SMIAPP_REG_MK_F32(0x1118)
+#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ			SMIAPP_REG_MK_F32(0x111c)
+#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV			SMIAPP_REG_MK_U16(0x1120)
+#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV			SMIAPP_REG_MK_U16(0x1122)
+#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1124)
+#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1128)
+#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x112c)
+#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1130)
+#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV			SMIAPP_REG_MK_U16(0x1134)
+#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV			SMIAPP_REG_MK_U16(0x1136)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES			SMIAPP_REG_MK_U16(0x1140)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES			SMIAPP_REG_MK_U16(0x1142)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK			SMIAPP_REG_MK_U16(0x1144)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK			SMIAPP_REG_MK_U16(0x1146)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK			SMIAPP_REG_MK_U16(0x1148)
+#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES			SMIAPP_REG_MK_U16(0x114a)
+#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE		SMIAPP_REG_MK_U8(0x114c)
+#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV			SMIAPP_REG_MK_U16(0x1160)
+#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV			SMIAPP_REG_MK_U16(0x1162)
+#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1164)
+#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1168)
+#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV			SMIAPP_REG_MK_U16(0x116c)
+#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV			SMIAPP_REG_MK_U16(0x116e)
+#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1170)
+#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1174)
+#define SMIAPP_REG_U16_X_ADDR_MIN				SMIAPP_REG_MK_U16(0x1180)
+#define SMIAPP_REG_U16_Y_ADDR_MIN				SMIAPP_REG_MK_U16(0x1182)
+#define SMIAPP_REG_U16_X_ADDR_MAX				SMIAPP_REG_MK_U16(0x1184)
+#define SMIAPP_REG_U16_Y_ADDR_MAX				SMIAPP_REG_MK_U16(0x1186)
+#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE			SMIAPP_REG_MK_U16(0x1188)
+#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE			SMIAPP_REG_MK_U16(0x118a)
+#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE			SMIAPP_REG_MK_U16(0x118c)
+#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE			SMIAPP_REG_MK_U16(0x118e)
+#define SMIAPP_REG_U16_MIN_EVEN_INC				SMIAPP_REG_MK_U16(0x11c0)
+#define SMIAPP_REG_U16_MAX_EVEN_INC				SMIAPP_REG_MK_U16(0x11c2)
+#define SMIAPP_REG_U16_MIN_ODD_INC				SMIAPP_REG_MK_U16(0x11c4)
+#define SMIAPP_REG_U16_MAX_ODD_INC				SMIAPP_REG_MK_U16(0x11c6)
+#define SMIAPP_REG_U16_SCALING_CAPABILITY			SMIAPP_REG_MK_U16(0x1200)
+#define SMIAPP_REG_U16_SCALER_M_MIN				SMIAPP_REG_MK_U16(0x1204)
+#define SMIAPP_REG_U16_SCALER_M_MAX				SMIAPP_REG_MK_U16(0x1206)
+#define SMIAPP_REG_U16_SCALER_N_MIN				SMIAPP_REG_MK_U16(0x1208)
+#define SMIAPP_REG_U16_SCALER_N_MAX				SMIAPP_REG_MK_U16(0x120a)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY		SMIAPP_REG_MK_U16(0x120c)
+#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY			SMIAPP_REG_MK_U8(0x120e)
+#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY			SMIAPP_REG_MK_U16(0x1300)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED			SMIAPP_REG_MK_U16(0x1400)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED		SMIAPP_REG_MK_U16(0x1402)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED			SMIAPP_REG_MK_U16(0x1404)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN		SMIAPP_REG_MK_U16(0x1406)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN		SMIAPP_REG_MK_U16(0x1408)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN		SMIAPP_REG_MK_U16(0x140a)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE			SMIAPP_REG_MK_U16(0x140c)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE		SMIAPP_REG_MK_U16(0x140e)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE		SMIAPP_REG_MK_U16(0x1410)
+#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS				SMIAPP_REG_MK_U16(0x1500)
+#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY			SMIAPP_REG_MK_U8(0x1502)
+#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY			SMIAPP_REG_MK_U8(0x1600)
+#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY			SMIAPP_REG_MK_U8(0x1601)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY		SMIAPP_REG_MK_U8(0x1602)
+#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY			SMIAPP_REG_MK_U8(0x1603)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY		SMIAPP_REG_MK_U8(0x1604)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS	SMIAPP_REG_MK_U32(0x1608)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS	SMIAPP_REG_MK_U32(0x160c)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS	SMIAPP_REG_MK_U32(0x1610)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS	SMIAPP_REG_MK_U32(0x1614)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY			SMIAPP_REG_MK_U8(0x1618)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN		SMIAPP_REG_MK_U16(0x1700)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN		SMIAPP_REG_MK_U16(0x1702)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN			SMIAPP_REG_MK_U16(0x1704)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN			SMIAPP_REG_MK_U16(0x1706)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN		SMIAPP_REG_MK_U16(0x1708)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN		SMIAPP_REG_MK_U16(0x170a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN	SMIAPP_REG_MK_U16(0x170c)
+#define SMIAPP_REG_U8_BINNING_CAPABILITY			SMIAPP_REG_MK_U8(0x1710)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY		SMIAPP_REG_MK_U8(0x1711)
+#define SMIAPP_REG_U8_BINNING_SUBTYPES				SMIAPP_REG_MK_U8(0x1712)
+#define SMIAPP_REG_U8_BINNING_TYPE_n(n)				SMIAPP_REG_MK_U8(0x1713 + (n)) /* 1 <= n <= 237 */
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY		SMIAPP_REG_MK_U8(0x1800)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY		SMIAPP_REG_MK_U8(0x1900)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY		SMIAPP_REG_MK_U8(0x1901)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY			SMIAPP_REG_MK_U8(0x1902)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY	SMIAPP_REG_MK_U8(0x1903)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY		SMIAPP_REG_MK_U16(0x1904)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2		SMIAPP_REG_MK_U16(0x1906)
+#define SMIAPP_REG_U8_EDOF_CAPABILITY				SMIAPP_REG_MK_U8(0x1980)
+#define SMIAPP_REG_U8_ESTIMATION_FRAMES				SMIAPP_REG_MK_U8(0x1981)
+#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ			SMIAPP_REG_MK_U8(0x1982)
+#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ			SMIAPP_REG_MK_U8(0x1983)
+#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ		SMIAPP_REG_MK_U8(0x1984)
+#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ		SMIAPP_REG_MK_U8(0x1985)
+#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ		SMIAPP_REG_MK_U8(0x1986)
+#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY		SMIAPP_REG_MK_U8(0x1987)
+#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM			SMIAPP_REG_MK_U8(0x1988)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY		SMIAPP_REG_MK_U8(0x19c0)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY		SMIAPP_REG_MK_U8(0x19c1)
+#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD			SMIAPP_REG_MK_U16(0x19c2)
+#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE			SMIAPP_REG_MK_U16(0x19c4)
+#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN			SMIAPP_REG_MK_U16(0x1a00)
+#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY			SMIAPP_REG_MK_U8(0x1a02)
+#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR		SMIAPP_REG_MK_U16(0x1b02)
+#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY			SMIAPP_REG_MK_U8(0x1b04)
+#define SMIAPP_REG_U16_ACTUATOR_TYPE				SMIAPP_REG_MK_U16(0x1b40)
+#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS				SMIAPP_REG_MK_U8(0x1b42)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS			SMIAPP_REG_MK_U16(0x1b44)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1		SMIAPP_REG_MK_U8(0x1c00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2		SMIAPP_REG_MK_U8(0x1c01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE			SMIAPP_REG_MK_U8(0x1c02)
diff --git a/drivers/media/video/smiapp/smiapp-reg.h b/drivers/media/video/smiapp/smiapp-reg.h
new file mode 100644
index 0000000..d0167aa
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-reg.h
@@ -0,0 +1,122 @@
+/*
+ * drivers/media/video/smiapp/smiapp-reg.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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 __SMIAPP_REG_H_
+#define __SMIAPP_REG_H_
+
+#include "smiapp-reg-defs.h"
+
+/* Bits for above register */
+#define SMIAPP_IMAGE_ORIENTATION_HFLIP		(1 << 0)
+#define SMIAPP_IMAGE_ORIENTATION_VFLIP		(1 << 1)
+
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN		(1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN		(0 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN		(1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR	(1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY	(1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY	(1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA		(1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE		(1 << 3)
+
+#define SMIAPP_SOFTWARE_RESET				(1 << 0)
+
+#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE	(1 << 0)
+#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE	(1 << 1)
+
+#define SMIAPP_DPHY_CTRL_AUTOMATIC			0
+/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */
+#define SMIAPP_DPHY_CTRL_UI				1
+#define SMIAPP_DPHY_CTRL_REGISTER			2
+
+#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR	1
+#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR	2
+
+#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY		0
+#define SMIAPP_MODE_SELECT_STREAMING			1
+
+#define SMIAPP_SCALING_MODE_NONE			0
+#define SMIAPP_SCALING_MODE_HORIZONTAL			1
+#define SMIAPP_SCALING_MODE_BOTH			2
+
+#define SMIAPP_SCALING_CAPABILITY_NONE			0
+#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL		1
+#define SMIAPP_SCALING_CAPABILITY_BOTH			2 /* horizontal/both */
+
+/* digital crop right before scaler */
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE		0
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP	1
+
+#define SMIAPP_BINNING_CAPABILITY_NO			0
+#define SMIAPP_BINNING_CAPABILITY_YES			1
+
+/* Maximum number of binning subtypes */
+#define SMIAPP_BINNING_SUBTYPES				253
+
+#define SMIAPP_PIXEL_ORDER_GRBG				0
+#define SMIAPP_PIXEL_ORDER_RGGB				1
+#define SMIAPP_PIXEL_ORDER_BGGR				2
+#define SMIAPP_PIXEL_ORDER_GBRG				3
+
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL		1
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED		2
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N		8
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N	16
+
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE		0x01
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE		0x02
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK	0x0f
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK	0xf0
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT	4
+
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK	0xf000
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT	12
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK		0x0fff
+
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK	0xf0000000
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT	28
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK		0x0000ffff
+
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED	1
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY	2
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK	3
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK		4
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE	5
+
+#define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES	0
+#define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE		1
+
+/* Scaling N factor */
+#define SMIAPP_SCALE_N					16
+
+/* Image statistics registers */
+/* Registers 0x2000 to 0x2fff are reserved for future
+ * use for statistics features.
+ */
+
+/* Manufacturer Specific Registers: 0x3000 to 0x3fff
+ * The manufacturer specifies these as a black box.
+ */
+
+#endif /* __SMIAPP_REG_H_ */
diff --git a/drivers/media/video/smiapp/smiapp-regs.c b/drivers/media/video/smiapp/smiapp-regs.c
new file mode 100644
index 0000000..b1812b1
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-regs.c
@@ -0,0 +1,273 @@
+/*
+ * drivers/media/video/smiapp/smiapp-regs.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+
+#include "smiapp.h"
+#include "smiapp-regs.h"
+
+static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
+					 uint32_t phloat)
+{
+	int32_t exp;
+	uint64_t man;
+
+	if (phloat >= 0x80000000) {
+		dev_err(&client->dev, "this is a negative number\n");
+		return 0;
+	}
+
+	if (phloat == 0x7f800000)
+		return ~0; /* Inf. */
+
+	if ((phloat & 0x7f800000) == 0x7f800000) {
+		dev_err(&client->dev, "NaN or other special number\n");
+		return 0;
+	}
+
+	/* Valid cases begin here */
+	if (phloat == 0)
+		return 0; /* Valid zero */
+
+	if (phloat > 0x4f800000)
+		return ~0; /* larger than 4294967295 */
+
+	/*
+	 * Unbias exponent (note how phloat is now guaranteed to
+	 * have 0 in the high bit)
+	 */
+	exp = ((int32_t)phloat >> 23) - 127;
+
+	/* Extract mantissa, add missing '1' bit and it's in MHz */
+	man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
+
+	if (exp < 0)
+		man >>= -exp;
+	else
+		man <<= exp;
+
+	man >>= 23; /* Remove mantissa bias */
+
+	return man & 0xffffffff;
+}
+
+
+/*
+ * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg,
+			   u16 len, u32 *val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct i2c_msg msg;
+	unsigned char data[4];
+	u16 offset = reg;
+	int r;
+
+	msg.addr = client->addr;
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = data;
+
+	/* high byte goes out first */
+	data[0] = (u8) (offset >> 8);
+	data[1] = (u8) offset;
+	r = i2c_transfer(client->adapter, &msg, 1);
+	if (r != 1) {
+		if (r >= 0)
+			r = -EBUSY;
+		goto err;
+	}
+
+	msg.len = len;
+	msg.flags = I2C_M_RD;
+	r = i2c_transfer(client->adapter, &msg, 1);
+	if (r != 1) {
+		if (r >= 0)
+			r = -EBUSY;
+		goto err;
+	}
+
+	*val = 0;
+	/* high byte comes first */
+	switch (len) {
+	case SMIA_REG_32BIT:
+		*val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
+			data[3];
+		break;
+	case SMIA_REG_16BIT:
+		*val = (data[0] << 8) + data[1];
+		break;
+	case SMIA_REG_8BIT:
+		*val = data[0];
+		break;
+	default:
+		BUG();
+	}
+
+	return 0;
+
+err:
+	dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
+
+	return r;
+}
+
+/* Read a register using 8-bit access only. */
+static int ____smiapp_read_8only(struct smiapp_sensor *sensor, u16 reg,
+				 u16 len, u32 *val)
+{
+	unsigned int i;
+	int rval;
+
+	*val = 0;
+
+	for (i = 0; i < len; i++) {
+		u32 val8;
+
+		rval = ____smiapp_read(sensor, reg + i, 1, &val8);
+		if (rval < 0)
+			return rval;
+		*val |= val8 << ((len - i - 1) << 3);
+	}
+
+	return 0;
+}
+
+/*
+ * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val,
+			 bool only8)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int len = (u8)(reg >> 16);
+	int rval;
+
+	if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT
+	    && len != SMIA_REG_32BIT)
+		return -EINVAL;
+
+	if (smiapp_quirk_reg(sensor, reg, val))
+		goto found_quirk;
+
+	if (len == SMIA_REG_8BIT && !only8)
+		rval = ____smiapp_read(sensor, (u16)reg, len, val);
+	else
+		rval = ____smiapp_read_8only(sensor, (u16)reg, len, val);
+	if (rval < 0)
+		return rval;
+
+found_quirk:
+	if (reg & SMIA_REG_FLAG_FLOAT)
+		*val = float_to_u32_mul_1000000(client, *val);
+
+	return 0;
+}
+
+int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+{
+	return __smiapp_read(
+		sensor, reg, val,
+		smiapp_needs_quirk(sensor,
+				   SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY));
+}
+
+int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+{
+	return __smiapp_read(sensor, reg, val, true);
+}
+
+/*
+ * Write to a 8/16-bit register.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct i2c_msg msg;
+	unsigned char data[6];
+	unsigned int retries;
+	unsigned int flags = reg >> 24;
+	unsigned int len = (u8)(reg >> 16);
+	u16 offset = reg;
+	int r;
+
+	if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT &&
+	     len != SMIA_REG_32BIT) || flags)
+		return -EINVAL;
+
+	msg.addr = client->addr;
+	msg.flags = 0; /* Write */
+	msg.len = 2 + len;
+	msg.buf = data;
+
+	/* high byte goes out first */
+	data[0] = (u8) (reg >> 8);
+	data[1] = (u8) (reg & 0xff);
+
+	switch (len) {
+	case SMIA_REG_8BIT:
+		data[2] = val;
+		break;
+	case SMIA_REG_16BIT:
+		data[2] = val >> 8;
+		data[3] = val;
+		break;
+	case SMIA_REG_32BIT:
+		data[2] = val >> 24;
+		data[3] = val >> 16;
+		data[4] = val >> 8;
+		data[5] = val;
+		break;
+	default:
+		BUG();
+	}
+
+	for (retries = 0; retries < 5; retries++) {
+		/*
+		 * Due to unknown reason sensor stops responding. This
+		 * loop is a temporaty solution until the root cause
+		 * is found.
+		 */
+		r = i2c_transfer(client->adapter, &msg, 1);
+		if (r == 1) {
+			if (retries)
+				dev_err(&client->dev,
+					"sensor i2c stall encountered. "
+					"retries: %d\n", retries);
+			return 0;
+		}
+
+		usleep_range(2000, 2000);
+	}
+
+	dev_err(&client->dev,
+		"wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
+
+	return r;
+}
diff --git a/drivers/media/video/smiapp/smiapp-regs.h b/drivers/media/video/smiapp/smiapp-regs.h
new file mode 100644
index 0000000..7f9013b
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-regs.h
@@ -0,0 +1,49 @@
+/*
+ * include/media/smiapp/smiapp-regs.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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 SMIAPP_REGS_H
+#define SMIAPP_REGS_H
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+
+/* Use upper 8 bits of the type field for flags */
+#define SMIA_REG_FLAG_FLOAT		(1 << 24)
+
+#define SMIA_REG_8BIT			1
+#define SMIA_REG_16BIT			2
+#define SMIA_REG_32BIT			4
+struct smia_reg {
+	u16 type;
+	u16 reg;			/* 16-bit offset */
+	u32 val;			/* 8/16/32-bit value */
+};
+
+struct smiapp_sensor;
+
+int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val);
+int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val);
+int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val);
+
+#endif
diff --git a/drivers/media/video/smiapp/smiapp.h b/drivers/media/video/smiapp/smiapp.h
new file mode 100644
index 0000000..587f7f1
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp.h
@@ -0,0 +1,252 @@
+/*
+ * drivers/media/video/smiapp/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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 __SMIAPP_PRIV_H_
+#define __SMIAPP_PRIV_H_
+
+#include <linux/mutex.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <media/smiapp.h>
+
+#include "smiapp-pll.h"
+#include "smiapp-reg.h"
+#include "smiapp-regs.h"
+#include "smiapp-quirk.h"
+
+/*
+ * Standard SMIA++ constants
+ */
+#define SMIA_VERSION_1			10
+#define SMIAPP_VERSION_0_8		8 /* Draft 0.8 */
+#define SMIAPP_VERSION_0_9		9 /* Draft 0.9 */
+#define SMIAPP_VERSION_1		10
+
+#define SMIAPP_PROFILE_0		0
+#define SMIAPP_PROFILE_1		1
+#define SMIAPP_PROFILE_2		2
+
+#define SMIAPP_NVM_PAGE_SIZE		64	/* bytes */
+
+#define SMIAPP_RESET_DELAY_CLOCKS	2400
+#define SMIAPP_RESET_DELAY(clk)				\
+	(1000 +	(SMIAPP_RESET_DELAY_CLOCKS * 1000	\
+		 + (clk) / 1000 - 1) / ((clk) / 1000))
+
+#include "smiapp-limits.h"
+
+struct smiapp_quirk;
+
+#define SMIAPP_MODULE_IDENT_FLAG_REV_LE		(1 << 0)
+
+struct smiapp_module_ident {
+	u8 manufacturer_id;
+	u16 model_id;
+	u8 revision_number_major;
+
+	u8 flags;
+
+	char *name;
+	const struct smiapp_quirk *quirk;
+};
+
+struct smiapp_module_info {
+	u32 manufacturer_id;
+	u32 model_id;
+	u32 revision_number_major;
+	u32 revision_number_minor;
+
+	u32 module_year;
+	u32 module_month;
+	u32 module_day;
+
+	u32 sensor_manufacturer_id;
+	u32 sensor_model_id;
+	u32 sensor_revision_number;
+	u32 sensor_firmware_version;
+
+	u32 smia_version;
+	u32 smiapp_version;
+
+	u32 smiapp_profile;
+
+	char *name;
+	const struct smiapp_quirk *quirk;
+};
+
+#define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk)	\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = fl,							\
+	  .name = _name,						\
+	  .quirk = _quirk, }
+
+#define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk)	\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE,			\
+	  .name = _name,						\
+	  .quirk = _quirk, }
+
+#define SMIAPP_IDENT_L(manufacturer, model, rev, _name)			\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE,			\
+	  .name = _name, }
+
+#define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk)		\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = 0,							\
+	  .name = _name,						\
+	  .quirk = _quirk, }
+
+#define SMIAPP_IDENT(manufacturer, model, rev, _name)			\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = 0,							\
+	  .name = _name, }
+
+struct smiapp_reg_limits {
+	u32 addr;
+	char *what;
+};
+
+extern struct smiapp_reg_limits smiapp_reg_limits[];
+
+struct smiapp_csi_data_format {
+	u32 code;
+	u8 width;
+	u8 compressed;
+	u8 pixel_order;
+};
+
+#define SMIAPP_SUBDEVS			3
+
+#define SMIAPP_PA_PAD_SRC		0
+#define SMIAPP_PAD_SINK			0
+#define SMIAPP_PAD_SRC			1
+#define SMIAPP_PADS			2
+
+struct smiapp_binning_subtype {
+	u8 horizontal:4;
+	u8 vertical:4;
+} __packed;
+
+struct smiapp_subdev {
+	struct v4l2_subdev sd;
+	struct media_pad pads[2];
+	struct v4l2_rect sink_fmt;
+	struct v4l2_rect crop[2];
+	struct v4l2_rect compose; /* compose on sink */
+	unsigned short sink_pad;
+	unsigned short source_pad;
+	int npads;
+	struct smiapp_sensor *sensor;
+	struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/*
+ * struct smiapp_sensor - Main device structure
+ */
+struct smiapp_sensor {
+	/*
+	 * "mutex" is used to serialise access to all fields here
+	 * except v4l2_ctrls at the end of the struct. "mutex" is also
+	 * used to serialise access to file handle specific
+	 * information. The exception to this rule is the power_mutex
+	 * below.
+	 */
+	struct mutex mutex;
+	/*
+	 * power_mutex is used to serialise power management related
+	 * activities. Acquiring "mutex" at that time isn't necessary
+	 * since there are no other users anyway.
+	 */
+	struct mutex power_mutex;
+	struct smiapp_subdev ssds[SMIAPP_SUBDEVS];
+	u32 ssds_used;
+	struct smiapp_subdev *src;
+	struct smiapp_subdev *binner;
+	struct smiapp_subdev *scaler;
+	struct smiapp_subdev *pixel_array;
+	struct smiapp_platform_data *platform_data;
+	struct regulator *vana;
+	struct clk *ext_clk;
+	u32 limits[SMIAPP_LIMIT_LAST];
+	u8 nbinning_subtypes;
+	struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES];
+	u32 mbus_frame_fmts;
+	const struct smiapp_csi_data_format *csi_format;
+	const struct smiapp_csi_data_format *internal_csi_format;
+	u32 default_mbus_frame_fmts;
+	int default_pixel_order;
+
+	u8 binning_horizontal;
+	u8 binning_vertical;
+
+	u8 scale_m;
+	u8 scaling_mode;
+
+	u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
+	u8 flash_capability;
+	u8 frame_skip;
+
+	int power_count;
+
+	bool streaming;
+	bool dev_init_done;
+
+	u8 *nvm;		/* nvm memory buffer */
+	unsigned int nvm_size;	/* bytes */
+
+	struct smiapp_module_info minfo;
+
+	struct smiapp_pll pll;
+
+	/* Pixel array controls */
+	struct v4l2_ctrl *analog_gain;
+	struct v4l2_ctrl *exposure;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *hblank;
+	struct v4l2_ctrl *pixel_rate_parray;
+	/* src controls */
+	struct v4l2_ctrl *link_freq;
+	struct v4l2_ctrl *pixel_rate_csi;
+};
+
+#define to_smiapp_subdev(_sd)				\
+	container_of(_sd, struct smiapp_subdev, sd)
+
+#define to_smiapp_sensor(_sd)	\
+	(to_smiapp_subdev(_sd)->sensor)
+
+#endif /* __SMIAPP_PRIV_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index c2882fa..19ea780 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -995,10 +995,8 @@
 
 static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
 {
-	long timeout;
-
 	cam->stream = STREAM_INTERRUPT;
-	timeout = wait_event_timeout(cam->wait_stream,
+	wait_event_timeout(cam->wait_stream,
 				     (cam->stream == STREAM_OFF) ||
 				     (cam->state & DEV_DISCONNECTED),
 				     SN9C102_URB_TIMEOUT);
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index aedb970..0421bf9 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -164,35 +164,38 @@
 			      struct v4l2_format *f)
 {
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	const struct soc_camera_format_xlate *xlate;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	int ret;
 
 	dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
 		pixfmtstr(pix->pixelformat), pix->width, pix->height);
 
-	pix->bytesperline = 0;
-	pix->sizeimage = 0;
+	if (!(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) {
+		pix->bytesperline = 0;
+		pix->sizeimage = 0;
+	}
 
 	ret = ici->ops->try_fmt(icd, f);
 	if (ret < 0)
 		return ret;
 
-	if (!pix->sizeimage) {
-		if (!pix->bytesperline) {
-			const struct soc_camera_format_xlate *xlate;
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate)
+		return -EINVAL;
 
-			xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
-			if (!xlate)
-				return -EINVAL;
+	ret = soc_mbus_bytes_per_line(pix->width, xlate->host_fmt);
+	if (ret < 0)
+		return ret;
 
-			ret = soc_mbus_bytes_per_line(pix->width,
-						      xlate->host_fmt);
-			if (ret > 0)
-				pix->bytesperline = ret;
-		}
-		if (pix->bytesperline)
-			pix->sizeimage = pix->bytesperline * pix->height;
-	}
+	pix->bytesperline = max_t(u32, pix->bytesperline, ret);
+
+	ret = soc_mbus_image_size(xlate->host_fmt, pix->bytesperline,
+				  pix->height);
+	if (ret < 0)
+		return ret;
+
+	pix->sizeimage = max_t(u32, pix->sizeimage, ret);
 
 	return 0;
 }
@@ -257,13 +260,13 @@
 	return v4l2_subdev_call(sd, core, g_std, a);
 }
 
-static int soc_camera_enum_fsizes(struct file *file, void *fh,
+static int soc_camera_enum_framesizes(struct file *file, void *fh,
 					 struct v4l2_frmsizeenum *fsize)
 {
 	struct soc_camera_device *icd = file->private_data;
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
-	return ici->ops->enum_fsizes(icd, fsize);
+	return ici->ops->enum_framesizes(icd, fsize);
 }
 
 static int soc_camera_reqbufs(struct file *file, void *priv,
@@ -1244,8 +1247,8 @@
 	return v4l2_subdev_call(sd, video, s_parm, parm);
 }
 
-static int default_enum_fsizes(struct soc_camera_device *icd,
-			  struct v4l2_frmsizeenum *fsize)
+static int default_enum_framesizes(struct soc_camera_device *icd,
+				   struct v4l2_frmsizeenum *fsize)
 {
 	int ret;
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -1259,7 +1262,7 @@
 	/* map xlate-code to pixel_format, sensor only handle xlate-code*/
 	fsize_mbus.pixel_format = xlate->code;
 
-	ret = v4l2_subdev_call(sd, video, enum_mbus_fsizes, &fsize_mbus);
+	ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus);
 	if (ret < 0)
 		return ret;
 
@@ -1298,8 +1301,8 @@
 		ici->ops->set_parm = default_s_parm;
 	if (!ici->ops->get_parm)
 		ici->ops->get_parm = default_g_parm;
-	if (!ici->ops->enum_fsizes)
-		ici->ops->enum_fsizes = default_enum_fsizes;
+	if (!ici->ops->enum_framesizes)
+		ici->ops->enum_framesizes = default_enum_framesizes;
 
 	mutex_lock(&list_lock);
 	list_for_each_entry(ix, &hosts, list) {
@@ -1390,7 +1393,7 @@
 	.vidioc_s_input		 = soc_camera_s_input,
 	.vidioc_s_std		 = soc_camera_s_std,
 	.vidioc_g_std		 = soc_camera_g_std,
-	.vidioc_enum_framesizes  = soc_camera_enum_fsizes,
+	.vidioc_enum_framesizes  = soc_camera_enum_framesizes,
 	.vidioc_reqbufs		 = soc_camera_reqbufs,
 	.vidioc_querybuf	 = soc_camera_querybuf,
 	.vidioc_qbuf		 = soc_camera_qbuf,
@@ -1429,6 +1432,10 @@
 	vdev->tvnorms		= V4L2_STD_UNKNOWN;
 	vdev->ctrl_handler	= &icd->ctrl_handler;
 	vdev->lock		= &icd->video_lock;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
 
 	icd->vdev = vdev;
 
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index cf7f219..89dce09 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -24,6 +24,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_YVYU8_2X8,
@@ -33,6 +34,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_UYVY8_2X8,
@@ -42,6 +44,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_VYUY8_2X8,
@@ -51,6 +54,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
@@ -60,6 +64,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
@@ -69,6 +74,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_RGB565_2X8_LE,
@@ -78,6 +84,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_RGB565_2X8_BE,
@@ -87,6 +94,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SBGGR8_1X8,
@@ -96,6 +104,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_NONE,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -105,6 +114,7 @@
 		.bits_per_sample	= 10,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_Y8_1X8,
@@ -114,6 +124,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_NONE,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_Y10_1X10,
@@ -123,6 +134,7 @@
 		.bits_per_sample	= 10,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
@@ -132,6 +144,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
@@ -141,6 +154,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADLO,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
@@ -150,6 +164,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
@@ -159,6 +174,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADLO,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_JPEG_1X8,
@@ -168,6 +184,7 @@
 		.bits_per_sample        = 8,
 		.packing                = SOC_MBUS_PACKING_VARIABLE,
 		.order                  = SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
@@ -177,6 +194,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_YUYV8_1_5X8,
@@ -186,6 +204,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_1_5X8,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_YVYU8_1_5X8,
@@ -195,6 +214,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_1_5X8,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_UYVY8_1X16,
@@ -204,6 +224,7 @@
 		.bits_per_sample	= 16,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_VYUY8_1X16,
@@ -213,6 +234,7 @@
 		.bits_per_sample	= 16,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_YUYV8_1X16,
@@ -222,6 +244,7 @@
 		.bits_per_sample	= 16,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_YVYU8_1X16,
@@ -231,6 +254,7 @@
 		.bits_per_sample	= 16,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SGRBG8_1X8,
@@ -240,6 +264,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_NONE,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
@@ -249,6 +274,7 @@
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_NONE,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SGBRG10_1X10,
@@ -258,6 +284,7 @@
 		.bits_per_sample	= 10,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SGRBG10_1X10,
@@ -267,6 +294,7 @@
 		.bits_per_sample	= 10,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SRGGB10_1X10,
@@ -276,6 +304,7 @@
 		.bits_per_sample	= 10,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SBGGR12_1X12,
@@ -285,6 +314,7 @@
 		.bits_per_sample	= 12,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SGBRG12_1X12,
@@ -294,6 +324,7 @@
 		.bits_per_sample	= 12,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SGRBG12_1X12,
@@ -303,6 +334,7 @@
 		.bits_per_sample	= 12,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 }, {
 	.code = V4L2_MBUS_FMT_SRGGB12_1X12,
@@ -312,6 +344,7 @@
 		.bits_per_sample	= 12,
 		.packing		= SOC_MBUS_PACKING_EXTEND16,
 		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 },
 };
@@ -345,6 +378,9 @@
 
 s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
 {
+	if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
+		return width * mf->bits_per_sample / 8;
+
 	switch (mf->packing) {
 	case SOC_MBUS_PACKING_NONE:
 		return width * mf->bits_per_sample / 8;
@@ -361,6 +397,24 @@
 }
 EXPORT_SYMBOL(soc_mbus_bytes_per_line);
 
+s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
+			u32 bytes_per_line, u32 height)
+{
+	if (mf->layout == SOC_MBUS_LAYOUT_PACKED)
+		return bytes_per_line * height;
+
+	switch (mf->packing) {
+	case SOC_MBUS_PACKING_2X8_PADHI:
+	case SOC_MBUS_PACKING_2X8_PADLO:
+		return bytes_per_line * height * 2;
+	case SOC_MBUS_PACKING_1_5X8:
+		return bytes_per_line * height * 3 / 2;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL(soc_mbus_image_size);
+
 const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
 	enum v4l2_mbus_pixelcode code,
 	const struct soc_mbus_lookup *lookup,
diff --git a/drivers/media/video/sta2x11_vip.c b/drivers/media/video/sta2x11_vip.c
new file mode 100644
index 0000000..4c10205
--- /dev/null
+++ b/drivers/media/video/sta2x11_vip.c
@@ -0,0 +1,1550 @@
+/*
+ * This is the driver for the STA2x11 Video Input Port.
+ *
+ * Copyright (C) 2010       WindRiver Systems, Inc.
+ *
+ * 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".
+ *
+ * Author: Andreas Kies <andreas.kies@windriver.com>
+ *		Vlad Lungu <vlad.lungu@windriver.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#include <linux/videodev2.h>
+
+#include <linux/kmod.h>
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "sta2x11_vip.h"
+
+#define DRV_NAME "sta2x11_vip"
+#define DRV_VERSION "1.3"
+
+#ifndef PCI_DEVICE_ID_STMICRO_VIP
+#define PCI_DEVICE_ID_STMICRO_VIP 0xCC0D
+#endif
+
+#define MAX_FRAMES 4
+
+/*Register offsets*/
+#define DVP_CTL		0x00
+#define DVP_TFO		0x04
+#define DVP_TFS		0x08
+#define DVP_BFO		0x0C
+#define DVP_BFS		0x10
+#define DVP_VTP         0x14
+#define DVP_VBP         0x18
+#define DVP_VMP		0x1C
+#define DVP_ITM		0x98
+#define DVP_ITS		0x9C
+#define DVP_STA		0xA0
+#define DVP_HLFLN	0xA8
+#define DVP_RGB		0xC0
+#define DVP_PKZ		0xF0
+
+/*Register fields*/
+#define DVP_CTL_ENA	0x00000001
+#define DVP_CTL_RST	0x80000000
+#define DVP_CTL_DIS	(~0x00040001)
+
+#define DVP_IT_VSB	0x00000008
+#define DVP_IT_VST	0x00000010
+#define DVP_IT_FIFO	0x00000020
+
+#define DVP_HLFLN_SD	0x00000001
+
+#define REG_WRITE(vip, reg, value) iowrite32((value), (vip->iomem)+(reg))
+#define REG_READ(vip, reg) ioread32((vip->iomem)+(reg))
+
+#define SAVE_COUNT 8
+#define AUX_COUNT 3
+#define IRQ_COUNT 1
+
+/**
+ * struct sta2x11_vip - All internal data for one instance of device
+ * @v4l2_dev: device registered in v4l layer
+ * @video_dev: properties of our device
+ * @pdev: PCI device
+ * @adapter: contains I2C adapter information
+ * @register_save_area: All relevant register are saved here during suspend
+ * @decoder: contains information about video DAC
+ * @format: pixel format, fixed UYVY
+ * @std: video standard (e.g. PAL/NTSC)
+ * @input: input line for video signal ( 0 or 1 )
+ * @users: Number of open of device ( max. 1 )
+ * @disabled: Device is in power down state
+ * @mutex: ensures exclusive opening of device
+ * @slock: for excluse acces of registers
+ * @vb_vidq: queue maintained by videobuf layer
+ * @capture: linked list of capture buffer
+ * @active: struct videobuf_buffer currently beingg filled
+ * @started: device is ready to capture frame
+ * @closing: device will be shut down
+ * @tcount: Number of top frames
+ * @bcount: Number of bottom frames
+ * @overflow: Number of FIFO overflows
+ * @mem_spare: small buffer of unused frame
+ * @dma_spare: dma addres of mem_spare
+ * @iomem: hardware base address
+ * @config: I2C and gpio config from platform
+ *
+ * All non-local data is accessed via this structure.
+ */
+
+struct sta2x11_vip {
+	struct v4l2_device v4l2_dev;
+	struct video_device *video_dev;
+	struct pci_dev *pdev;
+	struct i2c_adapter *adapter;
+	unsigned int register_save_area[IRQ_COUNT + SAVE_COUNT + AUX_COUNT];
+	struct v4l2_subdev *decoder;
+	struct v4l2_pix_format format;
+	v4l2_std_id std;
+	unsigned int input;
+	int users;
+	int disabled;
+	struct mutex mutex;	/* exclusive access during open */
+	spinlock_t slock;	/* spin lock for hardware and queue access */
+	struct videobuf_queue vb_vidq;
+	struct list_head capture;
+	struct videobuf_buffer *active;
+	int started, closing, tcount, bcount;
+	int overflow;
+	void *mem_spare;
+	dma_addr_t dma_spare;
+	void *iomem;
+	struct vip_config *config;
+};
+
+static const unsigned int registers_to_save[AUX_COUNT] = {
+	DVP_HLFLN, DVP_RGB, DVP_PKZ
+};
+
+static struct v4l2_pix_format formats_50[] = {
+	{			/*PAL interlaced */
+	 .width = 720,
+	 .height = 576,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_INTERLACED,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 576,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+	{			/*PAL top */
+	 .width = 720,
+	 .height = 288,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_TOP,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 288,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+	{			/*PAL bottom */
+	 .width = 720,
+	 .height = 288,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_BOTTOM,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 288,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+
+};
+
+static struct v4l2_pix_format formats_60[] = {
+	{			/*NTSC interlaced */
+	 .width = 720,
+	 .height = 480,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_INTERLACED,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 480,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+	{			/*NTSC top */
+	 .width = 720,
+	 .height = 240,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_TOP,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 240,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+	{			/*NTSC bottom */
+	 .width = 720,
+	 .height = 240,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_BOTTOM,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 240,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+};
+
+/**
+ * buf_setup - Get size and number of video buffer
+ * @vq: queue in videobuf
+ * @count: Number of buffers (1..MAX_FRAMES).
+ *		0 use default value.
+ * @size:  size of buffer in bytes
+ *
+ * returns size and number of buffers
+ * a preset value of 0 returns the default number.
+ * return value: 0, always succesfull.
+ */
+static int buf_setup(struct videobuf_queue *vq, unsigned int *count,
+		     unsigned int *size)
+{
+	struct sta2x11_vip *vip = vq->priv_data;
+
+	*size = vip->format.width * vip->format.height * 2;
+	if (0 == *count || MAX_FRAMES < *count)
+		*count = MAX_FRAMES;
+	return 0;
+};
+
+/**
+ * buf_prepare - prepare buffer for usage
+ * @vq: queue in videobuf layer
+ * @vb: buffer to be prepared
+ * @field: type of video data (interlaced/non-interlaced)
+ *
+ * Allocate or realloc buffer
+ * return value: 0, successful.
+ *
+ * -EINVAL, supplied buffer is too small.
+ *
+ *  other, buffer could not be locked.
+ */
+static int buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+		       enum v4l2_field field)
+{
+	struct sta2x11_vip *vip = vq->priv_data;
+	int ret;
+
+	vb->size = vip->format.width * vip->format.height * 2;
+	if ((0 != vb->baddr) && (vb->bsize < vb->size))
+		return -EINVAL;
+	vb->width = vip->format.width;
+	vb->height = vip->format.height;
+	vb->field = field;
+
+	if (VIDEOBUF_NEEDS_INIT == vb->state) {
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret)
+			goto fail;
+	}
+	vb->state = VIDEOBUF_PREPARED;
+	return 0;
+fail:
+	videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+	return ret;
+}
+
+/**
+ * buf_queu - queue buffer for filling
+ * @vq: queue in videobuf layer
+ * @vb: buffer to be queued
+ *
+ * if capturing is already running, the buffer will be queued. Otherwise
+ * capture is started and the buffer is used directly.
+ */
+static void buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct sta2x11_vip *vip = vq->priv_data;
+	u32 dma;
+
+	vb->state = VIDEOBUF_QUEUED;
+
+	if (vip->active) {
+		list_add_tail(&vb->queue, &vip->capture);
+		return;
+	}
+
+	vip->started = 1;
+	vip->tcount = 0;
+	vip->bcount = 0;
+	vip->active = vb;
+	vb->state = VIDEOBUF_ACTIVE;
+
+	dma = videobuf_to_dma_contig(vb);
+
+	REG_WRITE(vip, DVP_TFO, (0 << 16) | (0));
+	/* despite of interlace mode, upper and lower frames start at zero */
+	REG_WRITE(vip, DVP_BFO, (0 << 16) | (0));
+
+	switch (vip->format.field) {
+	case V4L2_FIELD_INTERLACED:
+		REG_WRITE(vip, DVP_TFS,
+			  ((vip->format.height / 2 - 1) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_BFS, ((vip->format.height / 2 - 1) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_VTP, dma);
+		REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
+		REG_WRITE(vip, DVP_VMP, 4 * vip->format.width);
+		break;
+	case V4L2_FIELD_TOP:
+		REG_WRITE(vip, DVP_TFS,
+			  ((vip->format.height - 1) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_BFS, ((0) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_VTP, dma);
+		REG_WRITE(vip, DVP_VBP, dma);
+		REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
+		break;
+	case V4L2_FIELD_BOTTOM:
+		REG_WRITE(vip, DVP_TFS, ((0) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_BFS,
+			  ((vip->format.height) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_VTP, dma);
+		REG_WRITE(vip, DVP_VBP, dma);
+		REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
+		break;
+
+	default:
+		pr_warning("VIP: unknown field format\n");
+		return;
+	}
+
+	REG_WRITE(vip, DVP_CTL, DVP_CTL_ENA);
+}
+
+/**
+ * buff_release - release buffer
+ * @vq: queue in videobuf layer
+ * @vb: buffer to be released
+ *
+ * release buffer in videobuf layer
+ */
+static void buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+
+	videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops vip_qops = {
+	.buf_setup = buf_setup,
+	.buf_prepare = buf_prepare,
+	.buf_queue = buf_queue,
+	.buf_release = buf_release,
+};
+
+/**
+ * vip_open - open video device
+ * @file: descriptor of device
+ *
+ * open device, make sure it is only opened once.
+ * return value: 0, no error.
+ *
+ * -EBUSY, device is already opened
+ *
+ * -ENOMEM, no memory for auxiliary DMA buffer
+ */
+static int vip_open(struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	mutex_lock(&vip->mutex);
+	vip->users++;
+
+	if (vip->users > 1) {
+		vip->users--;
+		mutex_unlock(&vip->mutex);
+		return -EBUSY;
+	}
+
+	file->private_data = dev;
+	vip->overflow = 0;
+	vip->started = 0;
+	vip->closing = 0;
+	vip->active = NULL;
+
+	INIT_LIST_HEAD(&vip->capture);
+	vip->mem_spare = dma_alloc_coherent(&vip->pdev->dev, 64,
+					    &vip->dma_spare, GFP_KERNEL);
+	if (!vip->mem_spare) {
+		vip->users--;
+		mutex_unlock(&vip->mutex);
+		return -ENOMEM;
+	}
+
+	mutex_unlock(&vip->mutex);
+	videobuf_queue_dma_contig_init_cached(&vip->vb_vidq,
+					      &vip_qops,
+					      &vip->pdev->dev,
+					      &vip->slock,
+					      V4L2_BUF_TYPE_VIDEO_CAPTURE,
+					      V4L2_FIELD_INTERLACED,
+					      sizeof(struct videobuf_buffer),
+					      vip, NULL);
+	REG_READ(vip, DVP_ITS);
+	REG_WRITE(vip, DVP_HLFLN, DVP_HLFLN_SD);
+	REG_WRITE(vip, DVP_ITM, DVP_IT_VSB | DVP_IT_VST);
+	REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
+	REG_WRITE(vip, DVP_CTL, 0);
+	REG_READ(vip, DVP_ITS);
+	return 0;
+}
+
+/**
+ * vip_close - close video device
+ * @file: descriptor of device
+ *
+ * close video device, wait until all pending operations are finished
+ * ( maximum FRAME_MAX buffers pending )
+ * Turn off interrupts.
+ *
+ * return value: 0, always succesful.
+ */
+static int vip_close(struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	vip->closing = 1;
+	if (vip->active)
+		videobuf_waiton(&vip->vb_vidq, vip->active, 0, 0);
+	spin_lock_irq(&vip->slock);
+
+	REG_WRITE(vip, DVP_ITM, 0);
+	REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
+	REG_WRITE(vip, DVP_CTL, 0);
+	REG_READ(vip, DVP_ITS);
+
+	vip->started = 0;
+	vip->active = NULL;
+
+	spin_unlock_irq(&vip->slock);
+
+	videobuf_stop(&vip->vb_vidq);
+	videobuf_mmap_free(&vip->vb_vidq);
+
+	dma_free_coherent(&vip->pdev->dev, 64, vip->mem_spare, vip->dma_spare);
+	file->private_data = NULL;
+	mutex_lock(&vip->mutex);
+	vip->users--;
+	mutex_unlock(&vip->mutex);
+	return 0;
+}
+
+/**
+ * vip_read - read from video input
+ * @file: descriptor of device
+ * @data: user buffer
+ * @count: number of bytes to be read
+ * @ppos: position within stream
+ *
+ * read video data from video device.
+ * handling is done in generic videobuf layer
+ * return value: provided by videobuf layer
+ */
+static ssize_t vip_read(struct file *file, char __user *data,
+			size_t count, loff_t *ppos)
+{
+	struct video_device *dev = file->private_data;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_read_stream(&vip->vb_vidq, data, count, ppos, 0,
+				    file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vip_mmap - map user buffer
+ * @file: descriptor of device
+ * @vma: user buffer
+ *
+ * map user space buffer into kernel mode, including DMA address.
+ * handling is done in generic videobuf layer.
+ * return value: provided by videobuf layer
+ */
+static int vip_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *dev = file->private_data;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_mmap_mapper(&vip->vb_vidq, vma);
+}
+
+/**
+ * vip_poll - poll for event
+ * @file: descriptor of device
+ * @wait: contains events to be waited for
+ *
+ * wait for event related to video device.
+ * handling is done in generic videobuf layer.
+ * return value: provided by videobuf layer
+ */
+static unsigned int vip_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct video_device *dev = file->private_data;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_poll_stream(file, &vip->vb_vidq, wait);
+}
+
+/**
+ * vidioc_querycap - return capabilities of device
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @cap: contains return values
+ *
+ * the capabilities of the device are returned
+ *
+ * return value: 0, no error.
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	memset(cap, 0, sizeof(struct v4l2_capability));
+	strcpy(cap->driver, DRV_NAME);
+	strcpy(cap->card, DRV_NAME);
+	cap->version = 0;
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+		 pci_name(vip->pdev));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+	    V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+/**
+ * vidioc_s_std - set video standard
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @std: contains standard to be set
+ *
+ * the video standard is set
+ *
+ * return value: 0, no error.
+ *
+ * -EIO, no input signal detected
+ *
+ * other, returned from video DAC.
+ */
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+	v4l2_std_id oldstd = vip->std, newstd;
+	int status;
+
+	if (V4L2_STD_ALL == *std) {
+		v4l2_subdev_call(vip->decoder, core, s_std, *std);
+		ssleep(2);
+		v4l2_subdev_call(vip->decoder, video, querystd, &newstd);
+		v4l2_subdev_call(vip->decoder, video, g_input_status, &status);
+		if (status & V4L2_IN_ST_NO_SIGNAL)
+			return -EIO;
+		*std = vip->std = newstd;
+		if (oldstd != *std) {
+			if (V4L2_STD_525_60 & (*std))
+				vip->format = formats_60[0];
+			else
+				vip->format = formats_50[0];
+		}
+		return 0;
+	}
+
+	if (oldstd != *std) {
+		if (V4L2_STD_525_60 & (*std))
+			vip->format = formats_60[0];
+		else
+			vip->format = formats_50[0];
+	}
+
+	return v4l2_subdev_call(vip->decoder, core, s_std, *std);
+}
+
+/**
+ * vidioc_g_std - get video standard
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @std: contains return values
+ *
+ * the current video standard is returned
+ *
+ * return value: 0, no error.
+ */
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	*std = vip->std;
+	return 0;
+}
+
+/**
+ * vidioc_querystd - get possible video standards
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @std: contains return values
+ *
+ * all possible video standards are returned
+ *
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return v4l2_subdev_call(vip->decoder, video, querystd, std);
+
+}
+
+/**
+ * vidioc_queryctl - get possible control settings
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @ctrl: contains return values
+ *
+ * return possible values for a control
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_queryctrl(struct file *file, void *priv,
+			    struct v4l2_queryctrl *ctrl)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return v4l2_subdev_call(vip->decoder, core, queryctrl, ctrl);
+}
+
+/**
+ * vidioc_g_ctl - get control value
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @ctrl: contains return values
+ *
+ * return setting for a control value
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return v4l2_subdev_call(vip->decoder, core, g_ctrl, ctrl);
+}
+
+/**
+ * vidioc_s_ctl - set control value
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @ctrl: contains value to be set
+ *
+ * set value for a specific control
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_s_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return v4l2_subdev_call(vip->decoder, core, s_ctrl, ctrl);
+}
+
+/**
+ * vidioc_enum_input - return name of input line
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @inp: contains return values
+ *
+ * the user friendly name of the input line is returned
+ *
+ * return value: 0, no error.
+ *
+ * -EINVAL, input line number out of range
+ */
+static int vidioc_enum_input(struct file *file, void *priv,
+			     struct v4l2_input *inp)
+{
+	if (inp->index > 1)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std = V4L2_STD_ALL;
+	sprintf(inp->name, "Camera %u", inp->index);
+
+	return 0;
+}
+
+/**
+ * vidioc_s_input - set input line
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @i: new input line number
+ *
+ * the current active input line is set
+ *
+ * return value: 0, no error.
+ *
+ * -EINVAL, line number out of range
+ */
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+	int ret;
+
+	if (i > 1)
+		return -EINVAL;
+	ret = v4l2_subdev_call(vip->decoder, video, s_routing, i, 0, 0);
+
+	if (!ret)
+		vip->input = i;
+
+	return 0;
+}
+
+/**
+ * vidioc_g_input - return input line
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @i: returned input line number
+ *
+ * the current active input line is returned
+ *
+ * return value: always 0.
+ */
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	*i = vip->input;
+	return 0;
+}
+
+/**
+ * vidioc_enum_fmt_vid_cap - return video capture format
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: returned format information
+ *
+ * returns name and format of video capture
+ * Only UYVY is supported by hardware.
+ *
+ * return value: always 0.
+ */
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+
+	if (f->index != 0)
+		return -EINVAL;
+
+	strcpy(f->description, "4:2:2, packed, UYVY");
+	f->pixelformat = V4L2_PIX_FMT_UYVY;
+	f->flags = 0;
+	return 0;
+}
+
+/**
+ * vidioc_try_fmt_vid_cap - set video capture format
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: new format
+ *
+ * new video format is set which includes width and
+ * field type. width is fixed to 720, no scaling.
+ * Only UYVY is supported by this hardware.
+ * the minimum height is 200, the maximum is 576 (PAL)
+ *
+ * return value: 0, no error
+ *
+ * -EINVAL, pixel or field format not supported
+ *
+ */
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+	int interlace_lim;
+
+	if (V4L2_PIX_FMT_UYVY != f->fmt.pix.pixelformat)
+		return -EINVAL;
+
+	if (V4L2_STD_525_60 & vip->std)
+		interlace_lim = 240;
+	else
+		interlace_lim = 288;
+
+	switch (f->fmt.pix.field) {
+	case V4L2_FIELD_ANY:
+		if (interlace_lim < f->fmt.pix.height)
+			f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+		else
+			f->fmt.pix.field = V4L2_FIELD_BOTTOM;
+		break;
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		if (interlace_lim < f->fmt.pix.height)
+			f->fmt.pix.height = interlace_lim;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	f->fmt.pix.height &= ~1;
+	if (2 * interlace_lim < f->fmt.pix.height)
+		f->fmt.pix.height = 2 * interlace_lim;
+	if (200 > f->fmt.pix.height)
+		f->fmt.pix.height = 200;
+	f->fmt.pix.width = 720;
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.width * 2 * f->fmt.pix.height;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	f->fmt.pix.priv = 0;
+	return 0;
+}
+
+/**
+ * vidioc_s_fmt_vid_cap - set current video format parameters
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: returned format information
+ *
+ * set new capture format
+ * return value: 0, no error
+ *
+ * other, delivered by video DAC routine.
+ */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+	int ret;
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	memcpy(&vip->format, &f->fmt.pix, sizeof(struct v4l2_pix_format));
+	return 0;
+}
+
+/**
+ * vidioc_g_fmt_vid_cap - get current video format parameters
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: contains format information
+ *
+ * returns current video format parameters
+ *
+ * return value: 0, always successful
+ */
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	memcpy(&f->fmt.pix, &vip->format, sizeof(struct v4l2_pix_format));
+	return 0;
+}
+
+/**
+ * vidioc_reqfs - request buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *p)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_reqbufs(&vip->vb_vidq, p);
+}
+
+/**
+ * vidioc_querybuf - query buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * query buffer state.
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_querybuf(&vip->vb_vidq, p);
+}
+
+/**
+ * vidioc_qbuf - queue a buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_qbuf(&vip->vb_vidq, p);
+}
+
+/**
+ * vidioc_dqbuf - dequeue a buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_dqbuf(&vip->vb_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vidioc_streamon - turn on streaming
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @type: type of capture
+ *
+ * turn on streaming.
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_streamon(&vip->vb_vidq);
+}
+
+/**
+ * vidioc_streamoff - turn off streaming
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @type: type of capture
+ *
+ * turn off streaming.
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_streamoff(&vip->vb_vidq);
+}
+
+static const struct v4l2_file_operations vip_fops = {
+	.owner = THIS_MODULE,
+	.open = vip_open,
+	.release = vip_close,
+	.ioctl = video_ioctl2,
+	.read = vip_read,
+	.mmap = vip_mmap,
+	.poll = vip_poll
+};
+
+static const struct v4l2_ioctl_ops vip_ioctl_ops = {
+	.vidioc_querycap = vidioc_querycap,
+	.vidioc_s_std = vidioc_s_std,
+	.vidioc_g_std = vidioc_g_std,
+	.vidioc_querystd = vidioc_querystd,
+	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_s_ctrl = vidioc_s_ctrl,
+	.vidioc_enum_input = vidioc_enum_input,
+	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_s_input = vidioc_s_input,
+	.vidioc_g_input = vidioc_g_input,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+	.vidioc_reqbufs = vidioc_reqbufs,
+	.vidioc_querybuf = vidioc_querybuf,
+	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_dqbuf = vidioc_dqbuf,
+	.vidioc_streamon = vidioc_streamon,
+	.vidioc_streamoff = vidioc_streamoff,
+};
+
+static struct video_device video_dev_template = {
+	.name = DRV_NAME,
+	.release = video_device_release,
+	.fops = &vip_fops,
+	.ioctl_ops = &vip_ioctl_ops,
+	.tvnorms = V4L2_STD_ALL,
+};
+
+/**
+ * vip_irq - interrupt routine
+ * @irq: Number of interrupt ( not used, correct number is assumed )
+ * @vip: local data structure containing all information
+ *
+ * check for both frame interrupts set ( top and bottom ).
+ * check FIFO overflow, but limit number of log messages after open.
+ * signal a complete buffer if done.
+ * dequeue a new buffer if available.
+ * disable VIP if no buffer available.
+ *
+ * return value: IRQ_NONE, interrupt was not generated by VIP
+ *
+ * IRQ_HANDLED, interrupt done.
+ */
+static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip)
+{
+	u32 status, dma;
+	unsigned long flags;
+	struct videobuf_buffer *vb;
+
+	status = REG_READ(vip, DVP_ITS);
+
+	if (!status) {
+		pr_debug("VIP: irq ignored\n");
+		return IRQ_NONE;
+	}
+
+	if (!vip->started)
+		return IRQ_HANDLED;
+
+	if (status & DVP_IT_VSB)
+		vip->bcount++;
+
+	if (status & DVP_IT_VST)
+		vip->tcount++;
+
+	if ((DVP_IT_VSB | DVP_IT_VST) == (status & (DVP_IT_VST | DVP_IT_VSB))) {
+		/* this is bad, we are too slow, hope the condition is gone
+		 * on the next frame */
+		pr_info("VIP: both irqs\n");
+		return IRQ_HANDLED;
+	}
+
+	if (status & DVP_IT_FIFO) {
+		if (5 > vip->overflow++)
+			pr_info("VIP: fifo overflow\n");
+	}
+
+	if (2 > vip->tcount)
+		return IRQ_HANDLED;
+
+	if (status & DVP_IT_VSB)
+		return IRQ_HANDLED;
+
+	spin_lock_irqsave(&vip->slock, flags);
+
+	REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) & ~DVP_CTL_ENA);
+	if (vip->active) {
+		do_gettimeofday(&vip->active->ts);
+		vip->active->field_count++;
+		vip->active->state = VIDEOBUF_DONE;
+		wake_up(&vip->active->done);
+		vip->active = NULL;
+	}
+	if (!vip->closing) {
+		if (list_empty(&vip->capture))
+			goto done;
+
+		vb = list_first_entry(&vip->capture, struct videobuf_buffer,
+				      queue);
+		if (NULL == vb) {
+			pr_info("VIP: no buffer\n");
+			goto done;
+		}
+		vb->state = VIDEOBUF_ACTIVE;
+		list_del(&vb->queue);
+		vip->active = vb;
+		dma = videobuf_to_dma_contig(vb);
+		switch (vip->format.field) {
+		case V4L2_FIELD_INTERLACED:
+			REG_WRITE(vip, DVP_VTP, dma);
+			REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
+			break;
+		case V4L2_FIELD_TOP:
+		case V4L2_FIELD_BOTTOM:
+			REG_WRITE(vip, DVP_VTP, dma);
+			REG_WRITE(vip, DVP_VBP, dma);
+			break;
+		default:
+			pr_warning("VIP: unknown field format\n");
+			goto done;
+			break;
+		}
+		REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) | DVP_CTL_ENA);
+	}
+done:
+	spin_unlock_irqrestore(&vip->slock, flags);
+	return IRQ_HANDLED;
+}
+
+/**
+ * vip_gpio_reserve - reserve gpio pin
+ * @dev: device
+ * @pin: GPIO pin number
+ * @dir: direction, input or output
+ * @name: GPIO pin name
+ *
+ */
+static int vip_gpio_reserve(struct device *dev, int pin, int dir,
+			    const char *name)
+{
+	int ret;
+
+	if (pin == -1)
+		return 0;
+
+	ret = gpio_request(pin, name);
+	if (ret) {
+		dev_err(dev, "Failed to allocate pin %d (%s)\n", pin, name);
+		return ret;
+	}
+
+	ret = gpio_direction_output(pin, dir);
+	if (ret) {
+		dev_err(dev, "Failed to set direction for pin %d (%s)\n",
+			pin, name);
+		gpio_free(pin);
+		return ret;
+	}
+
+	ret = gpio_export(pin, false);
+	if (ret) {
+		dev_err(dev, "Failed to export pin %d (%s)\n", pin, name);
+		gpio_free(pin);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * vip_gpio_release - release gpio pin
+ * @dev: device
+ * @pin: GPIO pin number
+ * @name: GPIO pin name
+ *
+ */
+static void vip_gpio_release(struct device *dev, int pin, const char *name)
+{
+	if (pin != -1) {
+		dev_dbg(dev, "releasing pin %d (%s)\n",	pin, name);
+		gpio_unexport(pin);
+		gpio_free(pin);
+	}
+}
+
+/**
+ * sta2x11_vip_init_one - init one instance of video device
+ * @pdev: PCI device
+ * @ent: (not used)
+ *
+ * allocate reset pins for DAC.
+ * Reset video DAC, this is done via reset line.
+ * allocate memory for managing device
+ * request interrupt
+ * map IO region
+ * register device
+ * find and initialize video DAC
+ *
+ * return value: 0, no error
+ *
+ * -ENOMEM, no memory
+ *
+ * -ENODEV, device could not be detected or registered
+ */
+static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
+					  const struct pci_device_id *ent)
+{
+	int ret;
+	struct sta2x11_vip *vip;
+	struct vip_config *config;
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	config = dev_get_platdata(&pdev->dev);
+	if (!config) {
+		dev_info(&pdev->dev, "VIP slot disabled\n");
+		ret = -EINVAL;
+		goto disable;
+	}
+
+	ret = vip_gpio_reserve(&pdev->dev, config->pwr_pin, 0,
+			       config->pwr_name);
+	if (ret)
+		goto disable;
+
+	if (config->reset_pin >= 0) {
+		ret = vip_gpio_reserve(&pdev->dev, config->reset_pin, 0,
+				       config->reset_name);
+		if (ret) {
+			vip_gpio_release(&pdev->dev, config->pwr_pin,
+					 config->pwr_name);
+			goto disable;
+		}
+	}
+
+	if (config->pwr_pin != -1) {
+		/* Datasheet says 5ms between PWR and RST */
+		usleep_range(5000, 25000);
+		ret = gpio_direction_output(config->pwr_pin, 1);
+	}
+
+	if (config->reset_pin != -1) {
+		/* Datasheet says 5ms between PWR and RST */
+		usleep_range(5000, 25000);
+		ret = gpio_direction_output(config->reset_pin, 1);
+	}
+	usleep_range(5000, 25000);
+
+	vip = kzalloc(sizeof(struct sta2x11_vip), GFP_KERNEL);
+	if (!vip) {
+		ret = -ENOMEM;
+		goto release_gpios;
+	}
+
+	vip->pdev = pdev;
+	vip->std = V4L2_STD_PAL;
+	vip->format = formats_50[0];
+	vip->config = config;
+
+	if (v4l2_device_register(&pdev->dev, &vip->v4l2_dev))
+		goto free_mem;
+
+	dev_dbg(&pdev->dev, "BAR #0 at 0x%lx 0x%lx irq %d\n",
+		(unsigned long)pci_resource_start(pdev, 0),
+		(unsigned long)pci_resource_len(pdev, 0), pdev->irq);
+
+	pci_set_master(pdev);
+
+	ret = pci_request_regions(pdev, DRV_NAME);
+	if (ret)
+		goto unreg;
+
+	vip->iomem = pci_iomap(pdev, 0, 0x100);
+	if (!vip->iomem) {
+		ret = -ENOMEM; /* FIXME */
+		goto release;
+	}
+
+	pci_enable_msi(pdev);
+
+	INIT_LIST_HEAD(&vip->capture);
+	spin_lock_init(&vip->slock);
+	mutex_init(&vip->mutex);
+	vip->started = 0;
+	vip->disabled = 0;
+
+	ret = request_irq(pdev->irq,
+			  (irq_handler_t) vip_irq,
+			  IRQF_SHARED, DRV_NAME, vip);
+	if (ret) {
+		dev_err(&pdev->dev, "request_irq failed\n");
+		ret = -ENODEV;
+		goto unmap;
+	}
+
+	vip->video_dev = video_device_alloc();
+	if (!vip->video_dev) {
+		ret = -ENOMEM;
+		goto release_irq;
+	}
+
+	*(vip->video_dev) = video_dev_template;
+	video_set_drvdata(vip->video_dev, vip);
+
+	ret = video_register_device(vip->video_dev, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto vrelease;
+
+	vip->adapter = i2c_get_adapter(vip->config->i2c_id);
+	if (!vip->adapter) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "no I2C adapter found\n");
+		goto vunreg;
+	}
+
+	vip->decoder = v4l2_i2c_new_subdev(&vip->v4l2_dev, vip->adapter,
+					   "adv7180", vip->config->i2c_addr,
+					   NULL);
+	if (!vip->decoder) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "no decoder found\n");
+		goto vunreg;
+	}
+
+	i2c_put_adapter(vip->adapter);
+
+	v4l2_subdev_call(vip->decoder, core, init, 0);
+
+	pr_info("STA2X11 Video Input Port (VIP) loaded\n");
+	return 0;
+
+vunreg:
+	video_set_drvdata(vip->video_dev, NULL);
+vrelease:
+	if (video_is_registered(vip->video_dev))
+		video_unregister_device(vip->video_dev);
+	else
+		video_device_release(vip->video_dev);
+release_irq:
+	free_irq(pdev->irq, vip);
+	pci_disable_msi(pdev);
+unmap:
+	pci_iounmap(pdev, vip->iomem);
+	mutex_destroy(&vip->mutex);
+release:
+	pci_release_regions(pdev);
+unreg:
+	v4l2_device_unregister(&vip->v4l2_dev);
+free_mem:
+	kfree(vip);
+release_gpios:
+	vip_gpio_release(&pdev->dev, config->reset_pin, config->reset_name);
+	vip_gpio_release(&pdev->dev, config->pwr_pin, config->pwr_name);
+disable:
+	/*
+	 * do not call pci_disable_device on sta2x11 because it break all
+	 * other Bus masters on this EP
+	 */
+	return ret;
+}
+
+/**
+ * sta2x11_vip_remove_one - release device
+ * @pdev: PCI device
+ *
+ * Undo everything done in .._init_one
+ *
+ * unregister video device
+ * free interrupt
+ * unmap ioadresses
+ * free memory
+ * free GPIO pins
+ */
+static void __devexit sta2x11_vip_remove_one(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+	struct sta2x11_vip *vip =
+	    container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+
+	video_set_drvdata(vip->video_dev, NULL);
+	video_unregister_device(vip->video_dev);
+	/*do not call video_device_release() here, is already done */
+	free_irq(pdev->irq, vip);
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, vip->iomem);
+	pci_release_regions(pdev);
+
+	v4l2_device_unregister(&vip->v4l2_dev);
+	mutex_destroy(&vip->mutex);
+
+	vip_gpio_release(&pdev->dev, vip->config->pwr_pin,
+			 vip->config->pwr_name);
+	vip_gpio_release(&pdev->dev, vip->config->reset_pin,
+			 vip->config->reset_name);
+
+	kfree(vip);
+	/*
+	 * do not call pci_disable_device on sta2x11 because it break all
+	 * other Bus masters on this EP
+	 */
+}
+
+#ifdef CONFIG_PM
+
+/**
+ * sta2x11_vip_suspend - set device into power save mode
+ * @pdev: PCI device
+ * @state: new state of device
+ *
+ * all relevant registers are saved and an attempt to set a new state is made.
+ *
+ * return value: 0 always indicate success,
+ * even if device could not be disabled. (workaround for hardware problem)
+ *
+ * reurn value : 0, always succesful, even if hardware does not not support
+ * power down mode.
+ */
+static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+	struct sta2x11_vip *vip =
+	    container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&vip->slock, flags);
+	vip->register_save_area[0] = REG_READ(vip, DVP_CTL);
+	REG_WRITE(vip, DVP_CTL, vip->register_save_area[0] & DVP_CTL_DIS);
+	vip->register_save_area[SAVE_COUNT] = REG_READ(vip, DVP_ITM);
+	REG_WRITE(vip, DVP_ITM, 0);
+	for (i = 1; i < SAVE_COUNT; i++)
+		vip->register_save_area[i] = REG_READ(vip, 4 * i);
+	for (i = 0; i < AUX_COUNT; i++)
+		vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i] =
+		    REG_READ(vip, registers_to_save[i]);
+	spin_unlock_irqrestore(&vip->slock, flags);
+	/* save pci state */
+	pci_save_state(pdev);
+	if (pci_set_power_state(pdev, pci_choose_state(pdev, state))) {
+		/*
+		 * do not call pci_disable_device on sta2x11 because it
+		 * break all other Bus masters on this EP
+		 */
+		vip->disabled = 1;
+	}
+
+	pr_info("VIP: suspend\n");
+	return 0;
+}
+
+/**
+ * sta2x11_vip_resume - resume device operation
+ * @pdev : PCI device
+ *
+ * re-enable device, set PCI state to powered and restore registers.
+ * resume normal device operation afterwards.
+ *
+ * return value: 0, no error.
+ *
+ * other, could not set device to power on state.
+ */
+static int sta2x11_vip_resume(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+	struct sta2x11_vip *vip =
+	    container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+	unsigned long flags;
+	int ret, i;
+
+	pr_info("VIP: resume\n");
+	/* restore pci state */
+	if (vip->disabled) {
+		ret = pci_enable_device(pdev);
+		if (ret) {
+			pr_warning("VIP: Can't enable device.\n");
+			return ret;
+		}
+		vip->disabled = 0;
+	}
+	ret = pci_set_power_state(pdev, PCI_D0);
+	if (ret) {
+		/*
+		 * do not call pci_disable_device on sta2x11 because it
+		 * break all other Bus masters on this EP
+		 */
+		pr_warning("VIP: Can't enable device.\n");
+		vip->disabled = 1;
+		return ret;
+	}
+
+	pci_restore_state(pdev);
+
+	spin_lock_irqsave(&vip->slock, flags);
+	for (i = 1; i < SAVE_COUNT; i++)
+		REG_WRITE(vip, 4 * i, vip->register_save_area[i]);
+	for (i = 0; i < AUX_COUNT; i++)
+		REG_WRITE(vip, registers_to_save[i],
+			  vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i]);
+	REG_WRITE(vip, DVP_CTL, vip->register_save_area[0]);
+	REG_WRITE(vip, DVP_ITM, vip->register_save_area[SAVE_COUNT]);
+	spin_unlock_irqrestore(&vip->slock, flags);
+	return 0;
+}
+
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = {
+	{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)},
+	{0,}
+};
+
+static struct pci_driver sta2x11_vip_driver = {
+	.name = DRV_NAME,
+	.probe = sta2x11_vip_init_one,
+	.remove = __devexit_p(sta2x11_vip_remove_one),
+	.id_table = sta2x11_vip_pci_tbl,
+#ifdef CONFIG_PM
+	.suspend = sta2x11_vip_suspend,
+	.resume = sta2x11_vip_resume,
+#endif
+};
+
+static int __init sta2x11_vip_init_module(void)
+{
+	return pci_register_driver(&sta2x11_vip_driver);
+}
+
+static void __exit sta2x11_vip_exit_module(void)
+{
+	pci_unregister_driver(&sta2x11_vip_driver);
+}
+
+#ifdef MODULE
+module_init(sta2x11_vip_init_module);
+module_exit(sta2x11_vip_exit_module);
+#else
+late_initcall_sync(sta2x11_vip_init_module);
+#endif
+
+MODULE_DESCRIPTION("STA2X11 Video Input Port driver");
+MODULE_AUTHOR("Wind River");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("sta2x11 video input");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, sta2x11_vip_pci_tbl);
diff --git a/drivers/media/video/sta2x11_vip.h b/drivers/media/video/sta2x11_vip.h
new file mode 100644
index 0000000..4f81a13
--- /dev/null
+++ b/drivers/media/video/sta2x11_vip.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011 Wind River Systems, 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.
+ *
+ * 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
+ *
+ * Author:  Anders Wallin <anders.wallin@windriver.com>
+ *
+ */
+
+#ifndef __STA2X11_VIP_H
+#define __STA2X11_VIP_H
+
+/**
+ * struct vip_config - video input configuration data
+ * @pwr_name: ADV powerdown name
+ * @pwr_pin: ADV powerdown pin
+ * @reset_name: ADV reset name
+ * @reset_pin: ADV reset pin
+ */
+struct vip_config {
+	const char *pwr_name;
+	int pwr_pin;
+	const char *reset_name;
+	int reset_pin;
+	int i2c_id;
+	int i2c_addr;
+};
+
+#endif /* __STA2X11_VIP_H */
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index d427f84..86a0fc5 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -38,13 +38,13 @@
 #include "stk-webcam.h"
 
 
-static bool hflip = 1;
+static bool hflip;
 module_param(hflip, bool, 0444);
-MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");
+MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 0");
 
-static bool vflip = 1;
+static bool vflip;
 module_param(vflip, bool, 0444);
-MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");
+MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 0");
 
 static int debug;
 module_param(debug, int, 0444);
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index 465d708..3d7ddd9 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -66,41 +66,11 @@
 				val, reg);
 }
 
-static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
-{
-	int byte;
-
-	if (t->index)
-		return -EINVAL;
-
-	switch (t->audmode) {
-	case V4L2_TUNER_MODE_STEREO:
-		byte = TDA9840_SET_STEREO;
-		break;
-	case V4L2_TUNER_MODE_LANG1_LANG2:
-		byte = TDA9840_SET_BOTH;
-		break;
-	case V4L2_TUNER_MODE_LANG1:
-		byte = TDA9840_SET_LANG1;
-		break;
-	case V4L2_TUNER_MODE_LANG2:
-		byte = TDA9840_SET_LANG2;
-		break;
-	default:
-		byte = TDA9840_SET_MONO;
-		break;
-	}
-	v4l2_dbg(1, debug, sd, "TDA9840_SWITCH: 0x%02x\n", byte);
-	tda9840_write(sd, SWITCH, byte);
-	return 0;
-}
-
-static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
+static int tda9840_status(struct v4l2_subdev *sd)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	u8 byte;
 
-	t->rxsubchans = V4L2_TUNER_SUB_MONO;
 	if (1 != i2c_master_recv(client, &byte, 1)) {
 		v4l2_dbg(1, debug, sd,
 			"i2c_master_recv() failed\n");
@@ -114,8 +84,51 @@
 	}
 
 	v4l2_dbg(1, debug, sd, "TDA9840_DETECT: byte: 0x%02x\n", byte);
+	return byte & 0x60;
+}
 
-	switch (byte & 0x60) {
+static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
+{
+	int stat = tda9840_status(sd);
+	int byte;
+
+	if (t->index)
+		return -EINVAL;
+
+	stat = stat < 0 ? 0 : stat;
+	if (stat == 0 || stat == 0x60) /* mono input */
+		byte = TDA9840_SET_MONO;
+	else if (stat == 0x40) /* stereo input */
+		byte = (t->audmode == V4L2_TUNER_MODE_MONO) ?
+			TDA9840_SET_MONO : TDA9840_SET_STEREO;
+	else { /* bilingual */
+		switch (t->audmode) {
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			byte = TDA9840_SET_BOTH;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			byte = TDA9840_SET_LANG2;
+			break;
+		default:
+			byte = TDA9840_SET_LANG1;
+			break;
+		}
+	}
+	v4l2_dbg(1, debug, sd, "TDA9840_SWITCH: 0x%02x\n", byte);
+	tda9840_write(sd, SWITCH, byte);
+	return 0;
+}
+
+static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
+{
+	int stat = tda9840_status(sd);
+
+	if (stat < 0)
+		return stat;
+
+	t->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+	switch (stat & 0x60) {
 	case 0x00:
 		t->rxsubchans = V4L2_TUNER_SUB_MONO;
 		break;
diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c
index a794ae6..bfbf9e5 100644
--- a/drivers/media/video/tlg2300/pd-video.c
+++ b/drivers/media/video/tlg2300/pd-video.c
@@ -150,7 +150,6 @@
 	strcpy(cap->driver, "tele-video");
 	strcpy(cap->card, "Telegent Poseidon");
 	usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info));
-	cap->version = KERNEL_VERSION(0, 0, 1);
 	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
 				V4L2_CAP_AUDIO | V4L2_CAP_STREAMING |
 				V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
index 859eb90..e80b7e1 100644
--- a/drivers/media/video/tm6000/tm6000-input.c
+++ b/drivers/media/video/tm6000/tm6000-input.c
@@ -168,7 +168,6 @@
 	struct tm6000_IR *ir = dev->ir;
 	struct tm6000_ir_poll_result poll_result;
 	char *buf;
-	int rc;
 
 	dprintk(2, "%s\n",__func__);
 	if (urb->status < 0 || urb->actual_length <= 0) {
@@ -192,7 +191,7 @@
 	dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
 	rc_keydown(ir->rc, poll_result.rc_data, 0);
 
-	rc = usb_submit_urb(urb, GFP_ATOMIC);
+	usb_submit_urb(urb, GFP_ATOMIC);
 	/*
 	 * Flash the led. We can't do it here, as it is running on IRQ context.
 	 * So, use the scheduler to do it, in a few ms.
diff --git a/drivers/media/video/tm6000/tm6000-stds.c b/drivers/media/video/tm6000/tm6000-stds.c
index 9dc0831..5e28d6a 100644
--- a/drivers/media/video/tm6000/tm6000-stds.c
+++ b/drivers/media/video/tm6000/tm6000-stds.c
@@ -338,7 +338,6 @@
 	uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
 	uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
 	uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */
-	uint8_t nicam_flag = 0; /* No NICAM */
 
 	if (dev->radio) {
 		tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
@@ -398,7 +397,6 @@
 		} else {
 			areg_05 = 0x07;
 		}
-		nicam_flag = 1;
 		break;
 	/* other */
 	case 3:
diff --git a/drivers/media/video/tm6000/tm6000-video.c b/drivers/media/video/tm6000/tm6000-video.c
index bc13db7..f7034df 100644
--- a/drivers/media/video/tm6000/tm6000-video.c
+++ b/drivers/media/video/tm6000/tm6000-video.c
@@ -169,7 +169,6 @@
 			       struct tm6000_buffer   **buf)
 {
 	struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-	char *outp;
 
 	if (list_empty(&dma_q->active)) {
 		dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
@@ -179,11 +178,6 @@
 
 	*buf = list_entry(dma_q->active.next,
 			struct tm6000_buffer, vb.queue);
-
-	/* Cleans up buffer - Useful for testing for frame/URB loss */
-	outp = videobuf_to_vmalloc(&(*buf)->vb);
-
-	return;
 }
 
 /*
@@ -211,7 +205,7 @@
 {
 	struct tm6000_dmaqueue  *dma_q = urb->context;
 	struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-	u8 *ptr = data, *endp = data+len, c;
+	u8 *ptr = data, *endp = data+len;
 	unsigned long header = 0;
 	int rc = 0;
 	unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
@@ -264,7 +258,6 @@
 			}
 
 			/* split the header fields */
-			c = (header >> 24) & 0xff;
 			size = ((header & 0x7e) << 1);
 			if (size > 0)
 				size -= 4;
@@ -889,7 +882,6 @@
 
 	strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
 	strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
-	cap->version = TM6000_VERSION;
 	cap->capabilities =	V4L2_CAP_VIDEO_CAPTURE |
 				V4L2_CAP_STREAMING     |
 				V4L2_CAP_AUDIO         |
@@ -1732,6 +1724,10 @@
 	vfd->release = video_device_release;
 	vfd->debug = tm6000_debug;
 	vfd->lock = &dev->lock;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
 
diff --git a/drivers/media/video/tm6000/tm6000.h b/drivers/media/video/tm6000/tm6000.h
index 27ba659..6df4186 100644
--- a/drivers/media/video/tm6000/tm6000.h
+++ b/drivers/media/video/tm6000/tm6000.h
@@ -33,8 +33,6 @@
 #include "dvb_frontend.h"
 #include "dmxdev.h"
 
-#define TM6000_VERSION KERNEL_VERSION(0, 0, 2)
-
 /* Inputs */
 enum tm6000_itype {
 	TM6000_INPUT_TV	= 1,
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index a5c6397..3e050e1 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -1241,8 +1241,10 @@
 	return 0;
 }
 
-static int tuner_suspend(struct i2c_client *c, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int tuner_suspend(struct device *dev)
 {
+	struct i2c_client *c = to_i2c_client(dev);
 	struct tuner *t = to_tuner(i2c_get_clientdata(c));
 	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
@@ -1254,8 +1256,9 @@
 	return 0;
 }
 
-static int tuner_resume(struct i2c_client *c)
+static int tuner_resume(struct device *dev)
 {
+	struct i2c_client *c = to_i2c_client(dev);
 	struct tuner *t = to_tuner(i2c_get_clientdata(c));
 
 	tuner_dbg("resume\n");
@@ -1266,6 +1269,7 @@
 
 	return 0;
 }
+#endif
 
 static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
@@ -1310,6 +1314,10 @@
  * I2C structs and module init functions
  */
 
+static const struct dev_pm_ops tuner_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(tuner_suspend, tuner_resume)
+};
+
 static const struct i2c_device_id tuner_id[] = {
 	{ "tuner", }, /* autodetect */
 	{ }
@@ -1320,12 +1328,11 @@
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "tuner",
+		.pm	= &tuner_pm_ops,
 	},
 	.probe		= tuner_probe,
 	.remove		= tuner_remove,
 	.command	= tuner_command,
-	.suspend	= tuner_suspend,
-	.resume		= tuner_resume,
 	.id_table	= tuner_id,
 };
 
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 1326e11..b786742 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -822,7 +822,7 @@
 	if (index)
 		return -EINVAL;
 
-	*code = V4L2_MBUS_FMT_YUYV8_2X8;
+	*code = V4L2_MBUS_FMT_UYVY8_2X8;
 	return 0;
 }
 
@@ -830,23 +830,16 @@
 			    struct v4l2_mbus_framefmt *f)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
-	v4l2_std_id std;
 
 	if (f == NULL)
 		return -EINVAL;
 
 	tvp5150_reset(sd, 0);
 
-	/* Calculate height and width based on current standard */
-	if (decoder->norm == V4L2_STD_ALL)
-		std = tvp5150_read_std(sd);
-	else
-		std = decoder->norm;
-
 	f->width = decoder->rect.width;
 	f->height = decoder->rect.height;
 
-	f->code = V4L2_MBUS_FMT_YUYV8_2X8;
+	f->code = V4L2_MBUS_FMT_UYVY8_2X8;
 	f->field = V4L2_FIELD_SEQ_TB;
 	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c
index d7676d8..fb6a5b5 100644
--- a/drivers/media/video/tvp7002.c
+++ b/drivers/media/video/tvp7002.c
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/module.h>
+#include <linux/v4l2-dv-timings.h>
 #include <media/tvp7002.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
@@ -328,6 +329,7 @@
 /* Preset definition for handling device operation */
 struct tvp7002_preset_definition {
 	u32 preset;
+	struct v4l2_dv_timings timings;
 	const struct i2c_reg_value *p_settings;
 	enum v4l2_colorspace color_space;
 	enum v4l2_field scanmode;
@@ -341,6 +343,7 @@
 static const struct tvp7002_preset_definition tvp7002_presets[] = {
 	{
 		V4L2_DV_720P60,
+		V4L2_DV_BT_CEA_1280X720P60,
 		tvp7002_parms_720P60,
 		V4L2_COLORSPACE_REC709,
 		V4L2_FIELD_NONE,
@@ -351,6 +354,7 @@
 	},
 	{
 		V4L2_DV_1080I60,
+		V4L2_DV_BT_CEA_1920X1080I60,
 		tvp7002_parms_1080I60,
 		V4L2_COLORSPACE_REC709,
 		V4L2_FIELD_INTERLACED,
@@ -361,6 +365,7 @@
 	},
 	{
 		V4L2_DV_1080I50,
+		V4L2_DV_BT_CEA_1920X1080I50,
 		tvp7002_parms_1080I50,
 		V4L2_COLORSPACE_REC709,
 		V4L2_FIELD_INTERLACED,
@@ -371,6 +376,7 @@
 	},
 	{
 		V4L2_DV_720P50,
+		V4L2_DV_BT_CEA_1280X720P50,
 		tvp7002_parms_720P50,
 		V4L2_COLORSPACE_REC709,
 		V4L2_FIELD_NONE,
@@ -381,6 +387,7 @@
 	},
 	{
 		V4L2_DV_1080P60,
+		V4L2_DV_BT_CEA_1920X1080P60,
 		tvp7002_parms_1080P60,
 		V4L2_COLORSPACE_REC709,
 		V4L2_FIELD_NONE,
@@ -391,6 +398,7 @@
 	},
 	{
 		V4L2_DV_480P59_94,
+		V4L2_DV_BT_CEA_720X480P59_94,
 		tvp7002_parms_480P,
 		V4L2_COLORSPACE_SMPTE170M,
 		V4L2_FIELD_NONE,
@@ -401,6 +409,7 @@
 	},
 	{
 		V4L2_DV_576P50,
+		V4L2_DV_BT_CEA_720X576P50,
 		tvp7002_parms_576P,
 		V4L2_COLORSPACE_SMPTE170M,
 		V4L2_FIELD_NONE,
@@ -605,6 +614,35 @@
 	return -EINVAL;
 }
 
+static int tvp7002_s_dv_timings(struct v4l2_subdev *sd,
+					struct v4l2_dv_timings *dv_timings)
+{
+	struct tvp7002 *device = to_tvp7002(sd);
+	const struct v4l2_bt_timings *bt = &dv_timings->bt;
+	int i;
+
+	if (dv_timings->type != V4L2_DV_BT_656_1120)
+		return -EINVAL;
+	for (i = 0; i < NUM_PRESETS; i++) {
+		const struct v4l2_bt_timings *t = &tvp7002_presets[i].timings.bt;
+
+		if (!memcmp(bt, t, &bt->standards - &bt->width)) {
+			device->current_preset = &tvp7002_presets[i];
+			return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings);
+		}
+	}
+	return -EINVAL;
+}
+
+static int tvp7002_g_dv_timings(struct v4l2_subdev *sd,
+					struct v4l2_dv_timings *dv_timings)
+{
+	struct tvp7002 *device = to_tvp7002(sd);
+
+	*dv_timings = device->current_preset->timings;
+	return 0;
+}
+
 /*
  * tvp7002_s_ctrl() - Set a control
  * @ctrl: ptr to v4l2_ctrl struct
@@ -666,11 +704,9 @@
  * Returns the current DV preset by TVP7002. If no active input is
  * detected, returns -EINVAL
  */
-static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
-						struct v4l2_dv_preset *qpreset)
+static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index)
 {
 	const struct tvp7002_preset_definition *presets = tvp7002_presets;
-	struct tvp7002 *device;
 	u8 progressive;
 	u32 lpfr;
 	u32 cpln;
@@ -679,12 +715,9 @@
 	u8 lpf_msb;
 	u8 cpl_lsb;
 	u8 cpl_msb;
-	int index;
 
-	/* Return invalid preset if no active input is detected */
-	qpreset->preset = V4L2_DV_INVALID;
-
-	device = to_tvp7002(sd);
+	/* Return invalid index if no active input is detected */
+	*index = NUM_PRESETS;
 
 	/* Read standards from device registers */
 	tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_LSBS, &lpf_lsb, &error);
@@ -705,8 +738,8 @@
 	progressive = (lpf_msb & TVP7002_INPR_MASK) >> TVP7002_IP_SHIFT;
 
 	/* Do checking of video modes */
-	for (index = 0; index < NUM_PRESETS; index++, presets++)
-		if (lpfr  == presets->lines_per_frame &&
+	for (*index = 0; *index < NUM_PRESETS; (*index)++, presets++)
+		if (lpfr == presets->lines_per_frame &&
 			progressive == presets->progressive) {
 			if (presets->cpl_min == 0xffff)
 				break;
@@ -714,17 +747,42 @@
 				break;
 		}
 
-	if (index == NUM_PRESETS) {
+	if (*index == NUM_PRESETS) {
 		v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n",
 								lpfr, cpln);
-		return 0;
+		return -ENOLINK;
 	}
 
-	/* Set values in found preset */
-	qpreset->preset = presets->preset;
-
 	/* Update lines per frame and clocks per line info */
-	v4l2_dbg(1, debug, sd, "detected preset: %d\n", presets->preset);
+	v4l2_dbg(1, debug, sd, "detected preset: %d\n", *index);
+	return 0;
+}
+
+static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
+					struct v4l2_dv_preset *qpreset)
+{
+	int index;
+	int err = tvp7002_query_dv(sd, &index);
+
+	if (err || index == NUM_PRESETS) {
+		qpreset->preset = V4L2_DV_INVALID;
+		if (err == -ENOLINK)
+			err = 0;
+		return err;
+	}
+	qpreset->preset = tvp7002_presets[index].preset;
+	return 0;
+}
+
+static int tvp7002_query_dv_timings(struct v4l2_subdev *sd,
+					struct v4l2_dv_timings *timings)
+{
+	int index;
+	int err = tvp7002_query_dv(sd, &index);
+
+	if (err)
+		return err;
+	*timings = tvp7002_presets[index].timings;
 	return 0;
 }
 
@@ -894,6 +952,17 @@
 	return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset);
 }
 
+static int tvp7002_enum_dv_timings(struct v4l2_subdev *sd,
+		struct v4l2_enum_dv_timings *timings)
+{
+	/* Check requested format index is within range */
+	if (timings->index >= NUM_PRESETS)
+		return -EINVAL;
+
+	timings->timings = tvp7002_presets[timings->index].timings;
+	return 0;
+}
+
 static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
 	.s_ctrl = tvp7002_s_ctrl,
 };
@@ -920,6 +989,10 @@
 	.enum_dv_presets = tvp7002_enum_dv_presets,
 	.s_dv_preset = tvp7002_s_dv_preset,
 	.query_dv_preset = tvp7002_query_dv_preset,
+	.g_dv_timings = tvp7002_g_dv_timings,
+	.s_dv_timings = tvp7002_s_dv_timings,
+	.enum_dv_timings = tvp7002_enum_dv_timings,
+	.query_dv_timings = tvp7002_query_dv_timings,
 	.s_stream = tvp7002_s_stream,
 	.g_mbus_fmt = tvp7002_mbus_fmt,
 	.try_mbus_fmt = tvp7002_mbus_fmt,
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index f344411..c9b2042 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -601,13 +601,12 @@
 								unsigned char *decompressed, int *start_pos,
 								int *block_typestart_pos, int len)
 {
-	int rest_pixel, idx, max_pos, pos, extra_pos, block_len, block_type_pos, block_type_len;
+	int rest_pixel, idx, pos, extra_pos, block_len, block_type_pos, block_type_len;
 	unsigned char block_byte, block_code, block_type, block_type_byte, integrator;
 
 	integrator = 0;
 	pos = *start_pos;
 	block_type_pos = *block_typestart_pos;
-	max_pos = 396; /* pos + len; */
 	extra_pos = pos;
 	block_len = 0;
 	block_byte = 0;
@@ -702,7 +701,7 @@
 	unsigned char strip_data[USBVISION_STRIP_LEN_MAX];
 	unsigned char strip_header[USBVISION_STRIP_HEADER_LEN];
 	int idx, idx_end, strip_len, strip_ptr, startblock_pos, block_pos, block_type_pos;
-	int clipmask_index, bytes_per_pixel, rc;
+	int clipmask_index;
 	int image_size;
 	unsigned char rv, gv, bv;
 	static unsigned char *Y, *U, *V;
@@ -769,7 +768,6 @@
 		return parse_state_next_frame;
 	}
 
-	bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
 	clipmask_index = frame->curline * MAX_FRAME_WIDTH;
 
 	scratch_get(usbvision, strip_data, strip_len);
@@ -781,14 +779,14 @@
 
 	usbvision->block_pos = block_pos;
 
-	rc = usbvision_decompress(usbvision, strip_data, Y, &block_pos, &block_type_pos, idx_end);
+	usbvision_decompress(usbvision, strip_data, Y, &block_pos, &block_type_pos, idx_end);
 	if (strip_len > usbvision->max_strip_len)
 		usbvision->max_strip_len = strip_len;
 
 	if (frame->curline % 2)
-		rc = usbvision_decompress(usbvision, strip_data, V, &block_pos, &block_type_pos, idx_end / 2);
+		usbvision_decompress(usbvision, strip_data, V, &block_pos, &block_type_pos, idx_end / 2);
 	else
-		rc = usbvision_decompress(usbvision, strip_data, U, &block_pos, &block_type_pos, idx_end / 2);
+		usbvision_decompress(usbvision, strip_data, U, &block_pos, &block_type_pos, idx_end / 2);
 
 	if (block_pos > usbvision->comprblock_pos)
 		usbvision->comprblock_pos = block_pos;
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 5a74f5e..9bd8f08 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -1296,6 +1296,10 @@
 	if (NULL == vdev)
 		return NULL;
 	*vdev = *vdev_template;
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
 	vdev->lock = &usbvision->v4l2_lock;
 	vdev->v4l2_dev = &usbvision->v4l2_dev;
 	snprintf(vdev->name, sizeof(vdev->name), "%s", name);
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 0efd3b1..af26bbe 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -21,6 +21,7 @@
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/atomic.h>
+#include <media/v4l2-ctrls.h>
 
 #include "uvcvideo.h"
 
@@ -420,6 +421,8 @@
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
 		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+		.master_id	= V4L2_CID_HUE_AUTO,
+		.master_manual	= 0,
 	},
 	{
 		.id		= V4L2_CID_SATURATION,
@@ -492,6 +495,7 @@
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
 		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+		.slave_ids	= { V4L2_CID_HUE, },
 	},
 	{
 		.id		= V4L2_CID_EXPOSURE_AUTO,
@@ -504,6 +508,7 @@
 		.data_type	= UVC_CTRL_DATA_TYPE_BITMASK,
 		.menu_info	= exposure_auto_controls,
 		.menu_count	= ARRAY_SIZE(exposure_auto_controls),
+		.slave_ids	= { V4L2_CID_EXPOSURE_ABSOLUTE, },
 	},
 	{
 		.id		= V4L2_CID_EXPOSURE_AUTO_PRIORITY,
@@ -524,6 +529,8 @@
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
 		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+		.master_id	= V4L2_CID_EXPOSURE_AUTO,
+		.master_manual	= V4L2_EXPOSURE_MANUAL,
 	},
 	{
 		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
@@ -534,6 +541,7 @@
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
 		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+		.slave_ids	= { V4L2_CID_WHITE_BALANCE_TEMPERATURE, },
 	},
 	{
 		.id		= V4L2_CID_WHITE_BALANCE_TEMPERATURE,
@@ -544,6 +552,8 @@
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
 		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+		.master_id	= V4L2_CID_AUTO_WHITE_BALANCE,
+		.master_manual	= 0,
 	},
 	{
 		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
@@ -554,6 +564,8 @@
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
 		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+		.slave_ids	= { V4L2_CID_BLUE_BALANCE,
+				    V4L2_CID_RED_BALANCE },
 	},
 	{
 		.id		= V4L2_CID_BLUE_BALANCE,
@@ -564,6 +576,8 @@
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
 		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+		.master_id	= V4L2_CID_AUTO_WHITE_BALANCE,
+		.master_manual	= 0,
 	},
 	{
 		.id		= V4L2_CID_RED_BALANCE,
@@ -574,6 +588,8 @@
 		.offset		= 16,
 		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
 		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+		.master_id	= V4L2_CID_AUTO_WHITE_BALANCE,
+		.master_manual	= 0,
 	},
 	{
 		.id		= V4L2_CID_FOCUS_ABSOLUTE,
@@ -584,6 +600,8 @@
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
 		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+		.master_id	= V4L2_CID_FOCUS_AUTO,
+		.master_manual	= 0,
 	},
 	{
 		.id		= V4L2_CID_FOCUS_AUTO,
@@ -594,6 +612,7 @@
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
 		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+		.slave_ids	= { V4L2_CID_FOCUS_ABSOLUTE, },
 	},
 	{
 		.id		= V4L2_CID_IRIS_ABSOLUTE,
@@ -899,25 +918,54 @@
 	return 0;
 }
 
-int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
-	struct v4l2_queryctrl *v4l2_ctrl)
+static int __uvc_ctrl_get(struct uvc_video_chain *chain,
+	struct uvc_control *ctrl, struct uvc_control_mapping *mapping,
+	s32 *value)
 {
-	struct uvc_control *ctrl;
-	struct uvc_control_mapping *mapping;
 	struct uvc_menu_info *menu;
 	unsigned int i;
 	int ret;
 
-	ret = mutex_lock_interruptible(&chain->ctrl_mutex);
-	if (ret < 0)
-		return -ERESTARTSYS;
+	if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0)
+		return -EINVAL;
 
-	ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
-	if (ctrl == NULL) {
-		ret = -EINVAL;
-		goto done;
+	if (!ctrl->loaded) {
+		ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
+				chain->dev->intfnum, ctrl->info.selector,
+				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+				ctrl->info.size);
+		if (ret < 0)
+			return ret;
+
+		ctrl->loaded = 1;
 	}
 
+	*value = mapping->get(mapping, UVC_GET_CUR,
+		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+
+	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+		menu = mapping->menu_info;
+		for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+			if (menu->value == *value) {
+				*value = i;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
+	struct uvc_control *ctrl,
+	struct uvc_control_mapping *mapping,
+	struct v4l2_queryctrl *v4l2_ctrl)
+{
+	struct uvc_control_mapping *master_map = NULL;
+	struct uvc_control *master_ctrl = NULL;
+	struct uvc_menu_info *menu;
+	unsigned int i;
+
 	memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
 	v4l2_ctrl->id = mapping->id;
 	v4l2_ctrl->type = mapping->v4l2_type;
@@ -929,10 +977,23 @@
 	if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
 		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
-	if (!ctrl->cached) {
-		ret = uvc_ctrl_populate_cache(chain, ctrl);
+	if (mapping->master_id)
+		__uvc_find_control(ctrl->entity, mapping->master_id,
+				   &master_map, &master_ctrl, 0);
+	if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
+		s32 val;
+		int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
 		if (ret < 0)
-			goto done;
+			return ret;
+
+		if (val != mapping->master_manual)
+				v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+	}
+
+	if (!ctrl->cached) {
+		int ret = uvc_ctrl_populate_cache(chain, ctrl);
+		if (ret < 0)
+			return ret;
 	}
 
 	if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
@@ -954,19 +1015,19 @@
 			}
 		}
 
-		goto done;
+		return 0;
 
 	case V4L2_CTRL_TYPE_BOOLEAN:
 		v4l2_ctrl->minimum = 0;
 		v4l2_ctrl->maximum = 1;
 		v4l2_ctrl->step = 1;
-		goto done;
+		return 0;
 
 	case V4L2_CTRL_TYPE_BUTTON:
 		v4l2_ctrl->minimum = 0;
 		v4l2_ctrl->maximum = 0;
 		v4l2_ctrl->step = 0;
-		goto done;
+		return 0;
 
 	default:
 		break;
@@ -984,6 +1045,27 @@
 		v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
 				  uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
 
+	return 0;
+}
+
+int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
+	struct v4l2_queryctrl *v4l2_ctrl)
+{
+	struct uvc_control *ctrl;
+	struct uvc_control_mapping *mapping;
+	int ret;
+
+	ret = mutex_lock_interruptible(&chain->ctrl_mutex);
+	if (ret < 0)
+		return -ERESTARTSYS;
+
+	ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
+	if (ctrl == NULL) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl);
 done:
 	mutex_unlock(&chain->ctrl_mutex);
 	return ret;
@@ -1054,6 +1136,174 @@
 	return ret;
 }
 
+/* --------------------------------------------------------------------------
+ * Ctrl event handling
+ */
+
+static void uvc_ctrl_fill_event(struct uvc_video_chain *chain,
+	struct v4l2_event *ev,
+	struct uvc_control *ctrl,
+	struct uvc_control_mapping *mapping,
+	s32 value, u32 changes)
+{
+	struct v4l2_queryctrl v4l2_ctrl;
+
+	__uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl);
+
+	memset(ev->reserved, 0, sizeof(ev->reserved));
+	ev->type = V4L2_EVENT_CTRL;
+	ev->id = v4l2_ctrl.id;
+	ev->u.ctrl.value = value;
+	ev->u.ctrl.changes = changes;
+	ev->u.ctrl.type = v4l2_ctrl.type;
+	ev->u.ctrl.flags = v4l2_ctrl.flags;
+	ev->u.ctrl.minimum = v4l2_ctrl.minimum;
+	ev->u.ctrl.maximum = v4l2_ctrl.maximum;
+	ev->u.ctrl.step = v4l2_ctrl.step;
+	ev->u.ctrl.default_value = v4l2_ctrl.default_value;
+}
+
+static void uvc_ctrl_send_event(struct uvc_fh *handle,
+	struct uvc_control *ctrl, struct uvc_control_mapping *mapping,
+	s32 value, u32 changes)
+{
+	struct v4l2_subscribed_event *sev;
+	struct v4l2_event ev;
+
+	if (list_empty(&mapping->ev_subs))
+		return;
+
+	uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, value, changes);
+
+	list_for_each_entry(sev, &mapping->ev_subs, node) {
+		if (sev->fh && (sev->fh != &handle->vfh ||
+		    (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK) ||
+		    (changes & V4L2_EVENT_CTRL_CH_FLAGS)))
+			v4l2_event_queue_fh(sev->fh, &ev);
+	}
+}
+
+static void uvc_ctrl_send_slave_event(struct uvc_fh *handle,
+	struct uvc_control *master, u32 slave_id,
+	const struct v4l2_ext_control *xctrls, unsigned int xctrls_count)
+{
+	struct uvc_control_mapping *mapping = NULL;
+	struct uvc_control *ctrl = NULL;
+	u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
+	unsigned int i;
+	s32 val = 0;
+
+	/*
+	 * We can skip sending an event for the slave if the slave
+	 * is being modified in the same transaction.
+	 */
+	for (i = 0; i < xctrls_count; i++) {
+		if (xctrls[i].id == slave_id)
+			return;
+	}
+
+	__uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0);
+	if (ctrl == NULL)
+		return;
+
+	if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
+		changes |= V4L2_EVENT_CTRL_CH_VALUE;
+
+	uvc_ctrl_send_event(handle, ctrl, mapping, val, changes);
+}
+
+static void uvc_ctrl_send_events(struct uvc_fh *handle,
+	const struct v4l2_ext_control *xctrls, unsigned int xctrls_count)
+{
+	struct uvc_control_mapping *mapping;
+	struct uvc_control *ctrl;
+	u32 changes = V4L2_EVENT_CTRL_CH_VALUE;
+	unsigned int i;
+	unsigned int j;
+
+	for (i = 0; i < xctrls_count; ++i) {
+		ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
+
+		for (j = 0; j < ARRAY_SIZE(mapping->slave_ids); ++j) {
+			if (!mapping->slave_ids[j])
+				break;
+			uvc_ctrl_send_slave_event(handle, ctrl,
+						  mapping->slave_ids[j],
+						  xctrls, xctrls_count);
+		}
+
+		/*
+		 * If the master is being modified in the same transaction
+		 * flags may change too.
+		 */
+		if (mapping->master_id) {
+			for (j = 0; j < xctrls_count; j++) {
+				if (xctrls[j].id == mapping->master_id) {
+					changes |= V4L2_EVENT_CTRL_CH_FLAGS;
+					break;
+				}
+			}
+		}
+
+		uvc_ctrl_send_event(handle, ctrl, mapping, xctrls[i].value,
+				    changes);
+	}
+}
+
+static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
+{
+	struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
+	struct uvc_control_mapping *mapping;
+	struct uvc_control *ctrl;
+	int ret;
+
+	ret = mutex_lock_interruptible(&handle->chain->ctrl_mutex);
+	if (ret < 0)
+		return -ERESTARTSYS;
+
+	ctrl = uvc_find_control(handle->chain, sev->id, &mapping);
+	if (ctrl == NULL) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	list_add_tail(&sev->node, &mapping->ev_subs);
+	if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) {
+		struct v4l2_event ev;
+		u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
+		s32 val = 0;
+
+		if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
+			changes |= V4L2_EVENT_CTRL_CH_VALUE;
+
+		uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val,
+				    changes);
+		/* Mark the queue as active, allowing this initial
+		   event to be accepted. */
+		sev->elems = elems;
+		v4l2_event_queue_fh(sev->fh, &ev);
+	}
+
+done:
+	mutex_unlock(&handle->chain->ctrl_mutex);
+	return ret;
+}
+
+static void uvc_ctrl_del_event(struct v4l2_subscribed_event *sev)
+{
+	struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
+
+	mutex_lock(&handle->chain->ctrl_mutex);
+	list_del(&sev->node);
+	mutex_unlock(&handle->chain->ctrl_mutex);
+}
+
+const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops = {
+	.add = uvc_ctrl_add_event,
+	.del = uvc_ctrl_del_event,
+	.replace = v4l2_ctrl_replace,
+	.merge = v4l2_ctrl_merge,
+};
 
 /* --------------------------------------------------------------------------
  * Control transactions
@@ -1101,9 +1351,12 @@
 
 		/* Reset the loaded flag for auto-update controls that were
 		 * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
-		 * uvc_ctrl_get from using the cached value.
+		 * uvc_ctrl_get from using the cached value, and for write-only
+		 * controls to prevent uvc_ctrl_set from setting bits not
+		 * explicitly set by the user.
 		 */
-		if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE)
+		if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE ||
+		    !(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
 			ctrl->loaded = 0;
 
 		if (!ctrl->dirty)
@@ -1131,8 +1384,11 @@
 	return 0;
 }
 
-int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
+int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
+		      const struct v4l2_ext_control *xctrls,
+		      unsigned int xctrls_count)
 {
+	struct uvc_video_chain *chain = handle->chain;
 	struct uvc_entity *entity;
 	int ret = 0;
 
@@ -1143,6 +1399,8 @@
 			goto done;
 	}
 
+	if (!rollback)
+		uvc_ctrl_send_events(handle, xctrls, xctrls_count);
 done:
 	mutex_unlock(&chain->ctrl_mutex);
 	return ret;
@@ -1153,39 +1411,12 @@
 {
 	struct uvc_control *ctrl;
 	struct uvc_control_mapping *mapping;
-	struct uvc_menu_info *menu;
-	unsigned int i;
-	int ret;
 
 	ctrl = uvc_find_control(chain, xctrl->id, &mapping);
-	if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0)
+	if (ctrl == NULL)
 		return -EINVAL;
 
-	if (!ctrl->loaded) {
-		ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
-				chain->dev->intfnum, ctrl->info.selector,
-				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
-				ctrl->info.size);
-		if (ret < 0)
-			return ret;
-
-		ctrl->loaded = 1;
-	}
-
-	xctrl->value = mapping->get(mapping, UVC_GET_CUR,
-		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
-
-	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
-		menu = mapping->menu_info;
-		for (i = 0; i < mapping->menu_count; ++i, ++menu) {
-			if (menu->value == xctrl->value) {
-				xctrl->value = i;
-				break;
-			}
-		}
-	}
-
-	return 0;
+	return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
 }
 
 int uvc_ctrl_set(struct uvc_video_chain *chain,
@@ -1641,6 +1872,8 @@
 	if (map == NULL)
 		return -ENOMEM;
 
+	INIT_LIST_HEAD(&map->ev_subs);
+
 	size = sizeof(*mapping->menu_info) * mapping->menu_count;
 	map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
 	if (map->menu_info == NULL) {
@@ -1653,7 +1886,6 @@
 	if (map->set == NULL)
 		map->set = uvc_set_le_value;
 
-	map->ctrl = &ctrl->info;
 	list_add_tail(&map->list, &ctrl->info.mappings);
 	uvc_trace(UVC_TRACE_CONTROL,
 		"Adding mapping '%s' to control %pUl/%u.\n",
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index 8f54e24..9288fbd 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -207,6 +207,19 @@
 	return ret;
 }
 
+#ifndef CONFIG_MMU
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+		unsigned long pgoff)
+{
+	unsigned long ret;
+
+	mutex_lock(&queue->mutex);
+	ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+#endif
+
 unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
 			    poll_table *wait)
 {
@@ -237,36 +250,6 @@
 	return allocated;
 }
 
-#ifndef CONFIG_MMU
-/*
- * Get unmapped area.
- *
- * NO-MMU arch need this function to make mmap() work correctly.
- */
-unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
-		unsigned long pgoff)
-{
-	struct uvc_buffer *buffer;
-	unsigned int i;
-	unsigned long ret;
-
-	mutex_lock(&queue->mutex);
-	for (i = 0; i < queue->count; ++i) {
-		buffer = &queue->buffer[i];
-		if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
-			break;
-	}
-	if (i == queue->count) {
-		ret = -EINVAL;
-		goto done;
-	}
-	ret = (unsigned long)buf->mem;
-done:
-	mutex_unlock(&queue->mutex);
-	return ret;
-}
-#endif
-
 /*
  * Enable or disable the video buffers queue.
  *
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index ff2cddd..759bef8 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -25,6 +25,8 @@
 #include <linux/atomic.h>
 
 #include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-ioctl.h>
 
 #include "uvcvideo.h"
@@ -505,6 +507,8 @@
 		}
 	}
 
+	v4l2_fh_init(&handle->vfh, stream->vdev);
+	v4l2_fh_add(&handle->vfh);
 	handle->chain = stream->chain;
 	handle->stream = stream;
 	handle->state = UVC_HANDLE_PASSIVE;
@@ -528,6 +532,8 @@
 
 	/* Release the file handle. */
 	uvc_dismiss_privileges(handle);
+	v4l2_fh_del(&handle->vfh);
+	v4l2_fh_exit(&handle->vfh);
 	kfree(handle);
 	file->private_data = NULL;
 
@@ -584,7 +590,7 @@
 			return ret;
 
 		ret = uvc_ctrl_get(chain, &xctrl);
-		uvc_ctrl_rollback(chain);
+		uvc_ctrl_rollback(handle);
 		if (ret >= 0)
 			ctrl->value = xctrl.value;
 		break;
@@ -605,10 +611,10 @@
 
 		ret = uvc_ctrl_set(chain, &xctrl);
 		if (ret < 0) {
-			uvc_ctrl_rollback(chain);
+			uvc_ctrl_rollback(handle);
 			return ret;
 		}
-		ret = uvc_ctrl_commit(chain);
+		ret = uvc_ctrl_commit(handle, &xctrl, 1);
 		if (ret == 0)
 			ctrl->value = xctrl.value;
 		break;
@@ -630,13 +636,13 @@
 		for (i = 0; i < ctrls->count; ++ctrl, ++i) {
 			ret = uvc_ctrl_get(chain, ctrl);
 			if (ret < 0) {
-				uvc_ctrl_rollback(chain);
+				uvc_ctrl_rollback(handle);
 				ctrls->error_idx = i;
 				return ret;
 			}
 		}
 		ctrls->error_idx = 0;
-		ret = uvc_ctrl_rollback(chain);
+		ret = uvc_ctrl_rollback(handle);
 		break;
 	}
 
@@ -654,7 +660,7 @@
 		for (i = 0; i < ctrls->count; ++ctrl, ++i) {
 			ret = uvc_ctrl_set(chain, ctrl);
 			if (ret < 0) {
-				uvc_ctrl_rollback(chain);
+				uvc_ctrl_rollback(handle);
 				ctrls->error_idx = i;
 				return ret;
 			}
@@ -663,9 +669,10 @@
 		ctrls->error_idx = 0;
 
 		if (cmd == VIDIOC_S_EXT_CTRLS)
-			ret = uvc_ctrl_commit(chain);
+			ret = uvc_ctrl_commit(handle,
+					      ctrls->controls, ctrls->count);
 		else
-			ret = uvc_ctrl_rollback(chain);
+			ret = uvc_ctrl_rollback(handle);
 		break;
 	}
 
@@ -687,7 +694,7 @@
 					break;
 			}
 			pin = iterm->id;
-		} else if (pin < selector->bNrInPins) {
+		} else if (index < selector->bNrInPins) {
 			pin = selector->baSourceID[index];
 			list_for_each_entry(iterm, &chain->entities, chain) {
 				if (!UVC_ENTITY_IS_ITERM(iterm))
@@ -990,6 +997,26 @@
 		return uvc_video_enable(stream, 0);
 	}
 
+	case VIDIOC_SUBSCRIBE_EVENT:
+	{
+		struct v4l2_event_subscription *sub = arg;
+
+		switch (sub->type) {
+		case V4L2_EVENT_CTRL:
+			return v4l2_event_subscribe(&handle->vfh, sub, 0,
+						    &uvc_ctrl_sub_ev_ops);
+		default:
+			return -EINVAL;
+		}
+	}
+
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+		return v4l2_event_unsubscribe(&handle->vfh, arg);
+
+	case VIDIOC_DQEVENT:
+		return v4l2_event_dequeue(&handle->vfh, arg,
+					  file->f_flags & O_NONBLOCK);
+
 	/* Analog video standards make no sense for digital cameras. */
 	case VIDIOC_ENUMSTD:
 	case VIDIOC_QUERYSTD:
@@ -1097,7 +1124,8 @@
 	    __put_user(kp->menu_count, &up->menu_count))
 		return -EFAULT;
 
-	__clear_user(up->reserved, sizeof(up->reserved));
+	if (__clear_user(up->reserved, sizeof(up->reserved)))
+		return -EFAULT;
 
 	if (kp->menu_count == 0)
 		return 0;
@@ -1105,8 +1133,6 @@
 	if (get_user(p, &up->menu_info))
 		return -EFAULT;
 	umenus = compat_ptr(p);
-	if (!access_ok(VERIFY_WRITE, umenus, kp->menu_count * sizeof(*umenus)))
-		return -EFAULT;
 
 	if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus)))
 		return -EFAULT;
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 67f88d8..7c3d082 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -13,6 +13,8 @@
 #include <linux/videodev2.h>
 #include <media/media-device.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
 #include <media/videobuf2-core.h>
 
 /* --------------------------------------------------------------------------
@@ -153,8 +155,7 @@
 
 struct uvc_control_mapping {
 	struct list_head list;
-
-	struct uvc_control_info *ctrl;
+	struct list_head ev_subs;
 
 	__u32 id;
 	__u8 name[32];
@@ -169,6 +170,10 @@
 	struct uvc_menu_info *menu_info;
 	__u32 menu_count;
 
+	__u32 master_id;
+	__s32 master_manual;
+	__u32 slave_ids[2];
+
 	__s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
 		      const __u8 *data);
 	void (*set) (struct uvc_control_mapping *mapping, __s32 value,
@@ -524,6 +529,7 @@
 };
 
 struct uvc_fh {
+	struct v4l2_fh vfh;
 	struct uvc_video_chain *chain;
 	struct uvc_streaming *stream;
 	enum uvc_handle_state state;
@@ -643,6 +649,8 @@
 extern int uvc_status_resume(struct uvc_device *dev);
 
 /* Controls */
+extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
+
 extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 		struct v4l2_queryctrl *v4l2_ctrl);
 extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
@@ -655,14 +663,18 @@
 extern int uvc_ctrl_resume_device(struct uvc_device *dev);
 
 extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
-extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
-static inline int uvc_ctrl_commit(struct uvc_video_chain *chain)
+extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
+			const struct v4l2_ext_control *xctrls,
+			unsigned int xctrls_count);
+static inline int uvc_ctrl_commit(struct uvc_fh *handle,
+			const struct v4l2_ext_control *xctrls,
+			unsigned int xctrls_count)
 {
-	return __uvc_ctrl_commit(chain, 0);
+	return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count);
 }
-static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain)
+static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
 {
-	return __uvc_ctrl_commit(chain, 1);
+	return __uvc_ctrl_commit(handle, 1, NULL, 0);
 }
 
 extern int uvc_ctrl_get(struct uvc_video_chain *chain,
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 2829d25..5327ad3 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -37,7 +37,7 @@
 
 struct v4l2_window32 {
 	struct v4l2_rect        w;
-	enum v4l2_field  	field;
+	__u32		  	field;	/* enum v4l2_field */
 	__u32			chromakey;
 	compat_caddr_t		clips; /* actually struct v4l2_clip32 * */
 	__u32			clipcount;
@@ -147,7 +147,7 @@
 }
 
 struct v4l2_format32 {
-	enum v4l2_buf_type type;
+	__u32	type;	/* enum v4l2_buf_type */
 	union {
 		struct v4l2_pix_format	pix;
 		struct v4l2_pix_format_mplane	pix_mp;
@@ -170,7 +170,7 @@
 struct v4l2_create_buffers32 {
 	__u32			index;
 	__u32			count;
-	enum v4l2_memory        memory;
+	__u32			memory;	/* enum v4l2_memory */
 	struct v4l2_format32	format;
 	__u32			reserved[8];
 };
@@ -311,16 +311,16 @@
 
 struct v4l2_buffer32 {
 	__u32			index;
-	enum v4l2_buf_type      type;
+	__u32			type;	/* enum v4l2_buf_type */
 	__u32			bytesused;
 	__u32			flags;
-	enum v4l2_field		field;
+	__u32			field;	/* enum v4l2_field */
 	struct compat_timeval	timestamp;
 	struct v4l2_timecode	timecode;
 	__u32			sequence;
 
 	/* memory location */
-	enum v4l2_memory        memory;
+	__u32			memory;	/* enum v4l2_memory */
 	union {
 		__u32           offset;
 		compat_long_t   userptr;
@@ -1023,6 +1023,9 @@
 	case VIDIOC_UNSUBSCRIBE_EVENT:
 	case VIDIOC_CREATE_BUFS32:
 	case VIDIOC_PREPARE_BUF32:
+	case VIDIOC_ENUM_DV_TIMINGS:
+	case VIDIOC_QUERY_DV_TIMINGS:
+	case VIDIOC_DV_TIMINGS_CAP:
 		ret = do_video_ioctl(file, cmd, arg);
 		break;
 
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 18015c0..9abd9ab 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -230,6 +230,19 @@
 		"Aperture Priority Mode",
 		NULL
 	};
+	static const char * const camera_exposure_metering[] = {
+		"Average",
+		"Center Weighted",
+		"Spot",
+		NULL
+	};
+	static const char * const camera_auto_focus_range[] = {
+		"Auto",
+		"Normal",
+		"Macro",
+		"Infinity",
+		NULL
+	};
 	static const char * const colorfx[] = {
 		"None",
 		"Black & White",
@@ -241,6 +254,47 @@
 		"Grass Green",
 		"Skin Whiten",
 		"Vivid",
+		"Aqua",
+		"Art Freeze",
+		"Silhouette",
+		"Solarization",
+		"Antique",
+		"Set Cb/Cr",
+		NULL
+	};
+	static const char * const auto_n_preset_white_balance[] = {
+		"Manual",
+		"Auto",
+		"Incandescent",
+		"Fluorescent",
+		"Fluorescent H",
+		"Horizon",
+		"Daylight",
+		"Flash",
+		"Cloudy",
+		"Shade",
+		NULL,
+	};
+	static const char * const camera_iso_sensitivity_auto[] = {
+		"Manual",
+		"Auto",
+		NULL
+	};
+	static const char * const scene_mode[] = {
+		"None",
+		"Backlight",
+		"Beach/Snow",
+		"Candle Light",
+		"Dusk/Dawn",
+		"Fall Colors",
+		"Fireworks",
+		"Landscape",
+		"Night",
+		"Party/Indoor",
+		"Portrait",
+		"Sports",
+		"Sunset",
+		"Text",
 		NULL
 	};
 	static const char * const tune_preemphasis[] = {
@@ -410,8 +464,18 @@
 		return camera_power_line_frequency;
 	case V4L2_CID_EXPOSURE_AUTO:
 		return camera_exposure_auto;
+	case V4L2_CID_EXPOSURE_METERING:
+		return camera_exposure_metering;
+	case V4L2_CID_AUTO_FOCUS_RANGE:
+		return camera_auto_focus_range;
 	case V4L2_CID_COLORFX:
 		return colorfx;
+	case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+		return auto_n_preset_white_balance;
+	case V4L2_CID_ISO_SENSITIVITY_AUTO:
+		return camera_iso_sensitivity_auto;
+	case V4L2_CID_SCENE_MODE:
+		return scene_mode;
 	case V4L2_CID_TUNE_PREEMPHASIS:
 		return tune_preemphasis;
 	case V4L2_CID_FLASH_LED_MODE:
@@ -493,6 +557,7 @@
 	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:	return "Min Number of Capture Buffers";
 	case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:	return "Min Number of Output Buffers";
 	case V4L2_CID_ALPHA_COMPONENT:		return "Alpha Component";
+	case V4L2_CID_COLORFX_CBCR:		return "Color Effects, CbCr";
 
 	/* MPEG controls */
 	/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -590,13 +655,26 @@
 	case V4L2_CID_TILT_ABSOLUTE:		return "Tilt, Absolute";
 	case V4L2_CID_FOCUS_ABSOLUTE:		return "Focus, Absolute";
 	case V4L2_CID_FOCUS_RELATIVE:		return "Focus, Relative";
-	case V4L2_CID_FOCUS_AUTO:		return "Focus, Automatic";
+	case V4L2_CID_FOCUS_AUTO:		return "Focus, Automatic Continuous";
 	case V4L2_CID_ZOOM_ABSOLUTE:		return "Zoom, Absolute";
 	case V4L2_CID_ZOOM_RELATIVE:		return "Zoom, Relative";
 	case V4L2_CID_ZOOM_CONTINUOUS:		return "Zoom, Continuous";
 	case V4L2_CID_PRIVACY:			return "Privacy";
 	case V4L2_CID_IRIS_ABSOLUTE:		return "Iris, Absolute";
 	case V4L2_CID_IRIS_RELATIVE:		return "Iris, Relative";
+	case V4L2_CID_AUTO_EXPOSURE_BIAS:	return "Auto Exposure, Bias";
+	case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: return "White Balance, Auto & Preset";
+	case V4L2_CID_WIDE_DYNAMIC_RANGE:	return "Wide Dynamic Range";
+	case V4L2_CID_IMAGE_STABILIZATION:	return "Image Stabilization";
+	case V4L2_CID_ISO_SENSITIVITY:		return "ISO Sensitivity";
+	case V4L2_CID_ISO_SENSITIVITY_AUTO:	return "ISO Sensitivity, Auto";
+	case V4L2_CID_EXPOSURE_METERING:	return "Exposure, Metering Mode";
+	case V4L2_CID_SCENE_MODE:		return "Scene Mode";
+	case V4L2_CID_3A_LOCK:			return "3A Lock";
+	case V4L2_CID_AUTO_FOCUS_START:		return "Auto Focus, Start";
+	case V4L2_CID_AUTO_FOCUS_STOP:		return "Auto Focus, Stop";
+	case V4L2_CID_AUTO_FOCUS_STATUS:	return "Auto Focus, Status";
+	case V4L2_CID_AUTO_FOCUS_RANGE:		return "Auto Focus, Range";
 
 	/* FM Radio Modulator control */
 	/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -644,6 +722,17 @@
 	case V4L2_CID_JPEG_COMPRESSION_QUALITY:	return "Compression Quality";
 	case V4L2_CID_JPEG_ACTIVE_MARKER:	return "Active Markers";
 
+	/* Image source controls */
+	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image Source Controls";
+	case V4L2_CID_VBLANK:			return "Vertical Blanking";
+	case V4L2_CID_HBLANK:			return "Horizontal Blanking";
+	case V4L2_CID_ANALOGUE_GAIN:		return "Analogue Gain";
+
+	/* Image processing controls */
+	case V4L2_CID_IMAGE_PROC_CLASS:		return "Image Processing Controls";
+	case V4L2_CID_LINK_FREQ:		return "Link Frequency";
+	case V4L2_CID_PIXEL_RATE:		return "Pixel Rate";
+
 	default:
 		return NULL;
 	}
@@ -688,6 +777,8 @@
 	case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
 	case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
 	case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+	case V4L2_CID_WIDE_DYNAMIC_RANGE:
+	case V4L2_CID_IMAGE_STABILIZATION:
 		*type = V4L2_CTRL_TYPE_BOOLEAN;
 		*min = 0;
 		*max = *step = 1;
@@ -696,6 +787,8 @@
 	case V4L2_CID_TILT_RESET:
 	case V4L2_CID_FLASH_STROBE:
 	case V4L2_CID_FLASH_STROBE_STOP:
+	case V4L2_CID_AUTO_FOCUS_START:
+	case V4L2_CID_AUTO_FOCUS_STOP:
 		*type = V4L2_CTRL_TYPE_BUTTON;
 		*flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
 		*min = *max = *step = *def = 0;
@@ -719,7 +812,9 @@
 	case V4L2_CID_MPEG_STREAM_TYPE:
 	case V4L2_CID_MPEG_STREAM_VBI_FMT:
 	case V4L2_CID_EXPOSURE_AUTO:
+	case V4L2_CID_AUTO_FOCUS_RANGE:
 	case V4L2_CID_COLORFX:
+	case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
 	case V4L2_CID_TUNE_PREEMPHASIS:
 	case V4L2_CID_FLASH_LED_MODE:
 	case V4L2_CID_FLASH_STROBE_SOURCE:
@@ -733,18 +828,30 @@
 	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
 	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
 	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+	case V4L2_CID_ISO_SENSITIVITY_AUTO:
+	case V4L2_CID_EXPOSURE_METERING:
+	case V4L2_CID_SCENE_MODE:
 		*type = V4L2_CTRL_TYPE_MENU;
 		break;
+	case V4L2_CID_LINK_FREQ:
+		*type = V4L2_CTRL_TYPE_INTEGER_MENU;
+		break;
 	case V4L2_CID_RDS_TX_PS_NAME:
 	case V4L2_CID_RDS_TX_RADIO_TEXT:
 		*type = V4L2_CTRL_TYPE_STRING;
 		break;
+	case V4L2_CID_ISO_SENSITIVITY:
+	case V4L2_CID_AUTO_EXPOSURE_BIAS:
+		*type = V4L2_CTRL_TYPE_INTEGER_MENU;
+		break;
 	case V4L2_CID_USER_CLASS:
 	case V4L2_CID_CAMERA_CLASS:
 	case V4L2_CID_MPEG_CLASS:
 	case V4L2_CID_FM_TX_CLASS:
 	case V4L2_CID_FLASH_CLASS:
 	case V4L2_CID_JPEG_CLASS:
+	case V4L2_CID_IMAGE_SOURCE_CLASS:
+	case V4L2_CID_IMAGE_PROC_CLASS:
 		*type = V4L2_CTRL_TYPE_CTRL_CLASS;
 		/* You can neither read not write these */
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -759,6 +866,8 @@
 		break;
 	case V4L2_CID_FLASH_FAULT:
 	case V4L2_CID_JPEG_ACTIVE_MARKER:
+	case V4L2_CID_3A_LOCK:
+	case V4L2_CID_AUTO_FOCUS_STATUS:
 		*type = V4L2_CTRL_TYPE_BITMASK;
 		break;
 	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
@@ -768,8 +877,12 @@
 		break;
 	case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
 	case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+		*flags |= V4L2_CTRL_FLAG_VOLATILE;
+		/* Fall through */
+	case V4L2_CID_PIXEL_RATE:
 		*type = V4L2_CTRL_TYPE_INTEGER64;
-		*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE;
+		*flags |= V4L2_CTRL_FLAG_READ_ONLY;
+		*min = *max = *step = *def = 0;
 		break;
 	default:
 		*type = V4L2_CTRL_TYPE_INTEGER;
@@ -817,6 +930,7 @@
 		*flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
 		break;
 	case V4L2_CID_FLASH_STROBE_STATUS:
+	case V4L2_CID_AUTO_FOCUS_STATUS:
 	case V4L2_CID_FLASH_READY:
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY;
 		break;
@@ -852,7 +966,8 @@
 		ev->u.ctrl.value64 = ctrl->cur.val64;
 	ev->u.ctrl.minimum = ctrl->minimum;
 	ev->u.ctrl.maximum = ctrl->maximum;
-	if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+	if (ctrl->type == V4L2_CTRL_TYPE_MENU
+	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
 		ev->u.ctrl.step = 1;
 	else
 		ev->u.ctrl.step = ctrl->step;
@@ -1083,10 +1198,13 @@
 		return 0;
 
 	case V4L2_CTRL_TYPE_MENU:
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
 		if (val < ctrl->minimum || val > ctrl->maximum)
 			return -ERANGE;
-		if (ctrl->qmenu[val][0] == '\0' ||
-		    (ctrl->menu_skip_mask & (1 << val)))
+		if (ctrl->menu_skip_mask & (1 << val))
+			return -EINVAL;
+		if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
+		    ctrl->qmenu[val][0] == '\0')
 			return -EINVAL;
 		return 0;
 
@@ -1114,6 +1232,7 @@
 	case V4L2_CTRL_TYPE_INTEGER:
 	case V4L2_CTRL_TYPE_BOOLEAN:
 	case V4L2_CTRL_TYPE_MENU:
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
 	case V4L2_CTRL_TYPE_BITMASK:
 	case V4L2_CTRL_TYPE_BUTTON:
 	case V4L2_CTRL_TYPE_CTRL_CLASS:
@@ -1152,7 +1271,8 @@
 int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
 			   unsigned nr_of_controls_hint)
 {
-	mutex_init(&hdl->lock);
+	hdl->lock = &hdl->_lock;
+	mutex_init(hdl->lock);
 	INIT_LIST_HEAD(&hdl->ctrls);
 	INIT_LIST_HEAD(&hdl->ctrl_refs);
 	hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
@@ -1173,7 +1293,7 @@
 	if (hdl == NULL || hdl->buckets == NULL)
 		return;
 
-	mutex_lock(&hdl->lock);
+	mutex_lock(hdl->lock);
 	/* Free all nodes */
 	list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
 		list_del(&ref->node);
@@ -1190,7 +1310,7 @@
 	hdl->buckets = NULL;
 	hdl->cached = NULL;
 	hdl->error = 0;
-	mutex_unlock(&hdl->lock);
+	mutex_unlock(hdl->lock);
 }
 EXPORT_SYMBOL(v4l2_ctrl_handler_free);
 
@@ -1255,9 +1375,9 @@
 	struct v4l2_ctrl_ref *ref = NULL;
 
 	if (hdl) {
-		mutex_lock(&hdl->lock);
+		mutex_lock(hdl->lock);
 		ref = find_ref(hdl, id);
-		mutex_unlock(&hdl->lock);
+		mutex_unlock(hdl->lock);
 	}
 	return ref;
 }
@@ -1304,7 +1424,7 @@
 
 	INIT_LIST_HEAD(&new_ref->node);
 
-	mutex_lock(&hdl->lock);
+	mutex_lock(hdl->lock);
 
 	/* Add immediately at the end of the list if the list is empty, or if
 	   the last element in the list has a lower ID.
@@ -1334,7 +1454,7 @@
 	hdl->buckets[bucket] = new_ref;
 
 unlock:
-	mutex_unlock(&hdl->lock);
+	mutex_unlock(hdl->lock);
 	return 0;
 }
 
@@ -1343,7 +1463,8 @@
 			const struct v4l2_ctrl_ops *ops,
 			u32 id, const char *name, enum v4l2_ctrl_type type,
 			s32 min, s32 max, u32 step, s32 def,
-			u32 flags, const char * const *qmenu, void *priv)
+			u32 flags, const char * const *qmenu,
+			const s64 *qmenu_int, void *priv)
 {
 	struct v4l2_ctrl *ctrl;
 	unsigned sz_extra = 0;
@@ -1356,6 +1477,7 @@
 	    (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
 	    (type == V4L2_CTRL_TYPE_BITMASK && max == 0) ||
 	    (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
+	    (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL) ||
 	    (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
 		handler_set_err(hdl, -ERANGE);
 		return NULL;
@@ -1366,6 +1488,7 @@
 	}
 	if ((type == V4L2_CTRL_TYPE_INTEGER ||
 	     type == V4L2_CTRL_TYPE_MENU ||
+	     type == V4L2_CTRL_TYPE_INTEGER_MENU ||
 	     type == V4L2_CTRL_TYPE_BOOLEAN) &&
 	    (def < min || def > max)) {
 		handler_set_err(hdl, -ERANGE);
@@ -1400,7 +1523,10 @@
 	ctrl->minimum = min;
 	ctrl->maximum = max;
 	ctrl->step = step;
-	ctrl->qmenu = qmenu;
+	if (type == V4L2_CTRL_TYPE_MENU)
+		ctrl->qmenu = qmenu;
+	else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
+		ctrl->qmenu_int = qmenu_int;
 	ctrl->priv = priv;
 	ctrl->cur.val = ctrl->val = ctrl->default_value = def;
 
@@ -1414,9 +1540,9 @@
 		kfree(ctrl);
 		return NULL;
 	}
-	mutex_lock(&hdl->lock);
+	mutex_lock(hdl->lock);
 	list_add_tail(&ctrl->node, &hdl->ctrls);
-	mutex_unlock(&hdl->lock);
+	mutex_unlock(hdl->lock);
 	return ctrl;
 }
 
@@ -1427,6 +1553,7 @@
 	struct v4l2_ctrl *ctrl;
 	const char *name = cfg->name;
 	const char * const *qmenu = cfg->qmenu;
+	const s64 *qmenu_int = cfg->qmenu_int;
 	enum v4l2_ctrl_type type = cfg->type;
 	u32 flags = cfg->flags;
 	s32 min = cfg->min;
@@ -1438,18 +1565,24 @@
 		v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
 								&def, &flags);
 
-	is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU);
+	is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU ||
+		   cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU);
 	if (is_menu)
 		WARN_ON(step);
 	else
 		WARN_ON(cfg->menu_skip_mask);
-	if (is_menu && qmenu == NULL)
+	if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL)
 		qmenu = v4l2_ctrl_get_menu(cfg->id);
+	else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU &&
+		 qmenu_int == NULL) {
+		handler_set_err(hdl, -EINVAL);
+		return NULL;
+	}
 
 	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name,
 			type, min, max,
 			is_menu ? cfg->menu_skip_mask : step,
-			def, flags, qmenu, priv);
+			def, flags, qmenu, qmenu_int, priv);
 	if (ctrl)
 		ctrl->is_private = cfg->is_private;
 	return ctrl;
@@ -1466,12 +1599,13 @@
 	u32 flags;
 
 	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-	if (type == V4L2_CTRL_TYPE_MENU) {
+	if (type == V4L2_CTRL_TYPE_MENU
+	    || type == V4L2_CTRL_TYPE_INTEGER_MENU) {
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, type,
-				    min, max, step, def, flags, NULL, NULL);
+			     min, max, step, def, flags, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std);
 
@@ -1493,10 +1627,31 @@
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, type,
-				    0, max, mask, def, flags, qmenu, NULL);
+			     0, max, mask, def, flags, qmenu, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
 
+/* Helper function for standard integer menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
+			const struct v4l2_ctrl_ops *ops,
+			u32 id, s32 max, s32 def, const s64 *qmenu_int)
+{
+	const char *name;
+	enum v4l2_ctrl_type type;
+	s32 min;
+	s32 step;
+	u32 flags;
+
+	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+	if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
+		handler_set_err(hdl, -EINVAL);
+		return NULL;
+	}
+	return v4l2_ctrl_new(hdl, ops, id, name, type,
+			     0, max, 0, def, flags, NULL, qmenu_int, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
+
 /* Add a control from another handler to this handler */
 struct v4l2_ctrl *v4l2_ctrl_add_ctrl(struct v4l2_ctrl_handler *hdl,
 					  struct v4l2_ctrl *ctrl)
@@ -1525,7 +1680,7 @@
 		return 0;
 	if (hdl->error)
 		return hdl->error;
-	mutex_lock(&add->lock);
+	mutex_lock(add->lock);
 	list_for_each_entry(ref, &add->ctrl_refs, node) {
 		struct v4l2_ctrl *ctrl = ref->ctrl;
 
@@ -1539,7 +1694,7 @@
 		if (ret)
 			break;
 	}
-	mutex_unlock(&add->lock);
+	mutex_unlock(add->lock);
 	return ret;
 }
 EXPORT_SYMBOL(v4l2_ctrl_add_handler);
@@ -1659,6 +1814,9 @@
 	case V4L2_CTRL_TYPE_MENU:
 		printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
 		break;
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
+		printk(KERN_CONT "%lld", ctrl->qmenu_int[ctrl->cur.val]);
+		break;
 	case V4L2_CTRL_TYPE_BITMASK:
 		printk(KERN_CONT "0x%08x", ctrl->cur.val);
 		break;
@@ -1700,11 +1858,11 @@
 	len = strlen(prefix);
 	if (len && prefix[len - 1] != ' ')
 		colon = ": ";
-	mutex_lock(&hdl->lock);
+	mutex_lock(hdl->lock);
 	list_for_each_entry(ctrl, &hdl->ctrls, node)
 		if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
 			log_ctrl(ctrl, prefix, colon);
-	mutex_unlock(&hdl->lock);
+	mutex_unlock(hdl->lock);
 }
 EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
 
@@ -1716,7 +1874,7 @@
 
 	if (hdl == NULL)
 		return 0;
-	mutex_lock(&hdl->lock);
+	mutex_lock(hdl->lock);
 	list_for_each_entry(ctrl, &hdl->ctrls, node)
 		ctrl->done = false;
 
@@ -1741,7 +1899,7 @@
 		if (ret)
 			break;
 	}
-	mutex_unlock(&hdl->lock);
+	mutex_unlock(hdl->lock);
 	return ret;
 }
 EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
@@ -1756,7 +1914,7 @@
 	if (hdl == NULL)
 		return -EINVAL;
 
-	mutex_lock(&hdl->lock);
+	mutex_lock(hdl->lock);
 
 	/* Try to find it */
 	ref = find_ref(hdl, id);
@@ -1781,7 +1939,7 @@
 					break;
 		}
 	}
-	mutex_unlock(&hdl->lock);
+	mutex_unlock(hdl->lock);
 	if (!ref)
 		return -EINVAL;
 
@@ -1795,7 +1953,8 @@
 	qc->minimum = ctrl->minimum;
 	qc->maximum = ctrl->maximum;
 	qc->default_value = ctrl->default_value;
-	if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+	if (ctrl->type == V4L2_CTRL_TYPE_MENU
+	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
 		qc->step = 1;
 	else
 		qc->step = ctrl->step;
@@ -1825,16 +1984,33 @@
 
 	qm->reserved = 0;
 	/* Sanity checks */
-	if (ctrl->qmenu == NULL ||
-	    i < ctrl->minimum || i > ctrl->maximum)
+	switch (ctrl->type) {
+	case V4L2_CTRL_TYPE_MENU:
+		if (ctrl->qmenu == NULL)
+			return -EINVAL;
+		break;
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
+		if (ctrl->qmenu_int == NULL)
+			return -EINVAL;
+		break;
+	default:
 		return -EINVAL;
+	}
+
+	if (i < ctrl->minimum || i > ctrl->maximum)
+		return -EINVAL;
+
 	/* Use mask to see if this menu item should be skipped */
 	if (ctrl->menu_skip_mask & (1 << i))
 		return -EINVAL;
 	/* Empty menu items should also be skipped */
-	if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
-		return -EINVAL;
-	strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+	if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
+		if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
+			return -EINVAL;
+		strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+	} else {
+		qm->value = ctrl->qmenu_int[i];
+	}
 	return 0;
 }
 EXPORT_SYMBOL(v4l2_querymenu);
@@ -1940,7 +2116,7 @@
 	   belong to the same cluster. */
 
 	/* This has to be done with the handler lock taken. */
-	mutex_lock(&hdl->lock);
+	mutex_lock(hdl->lock);
 
 	/* First zero the helper field in the master control references */
 	for (i = 0; i < cs->count; i++)
@@ -1962,7 +2138,7 @@
 		/* Point the mref helper to the current helper struct. */
 		mref->helper = h;
 	}
-	mutex_unlock(&hdl->lock);
+	mutex_unlock(hdl->lock);
 	return 0;
 }
 
@@ -1996,7 +2172,8 @@
 		return class_check(hdl, cs->ctrl_class);
 
 	if (cs->count > ARRAY_SIZE(helper)) {
-		helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+		helpers = kmalloc_array(cs->count, sizeof(helper[0]),
+					GFP_KERNEL);
 		if (helpers == NULL)
 			return -ENOMEM;
 	}
@@ -2218,7 +2395,8 @@
 		return class_check(hdl, cs->ctrl_class);
 
 	if (cs->count > ARRAY_SIZE(helper)) {
-		helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+		helpers = kmalloc_array(cs->count, sizeof(helper[0]),
+					GFP_KERNEL);
 		if (!helpers)
 			return -ENOMEM;
 	}
@@ -2381,9 +2559,13 @@
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
 
-void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
-				struct v4l2_subscribed_event *sev)
+static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
 {
+	struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
+	if (ctrl == NULL)
+		return -EINVAL;
+
 	v4l2_ctrl_lock(ctrl);
 	list_add_tail(&sev->node, &ctrl->ev_subs);
 	if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
@@ -2394,20 +2576,46 @@
 		if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
 			changes |= V4L2_EVENT_CTRL_CH_VALUE;
 		fill_event(&ev, ctrl, changes);
+		/* Mark the queue as active, allowing this initial
+		   event to be accepted. */
+		sev->elems = elems;
 		v4l2_event_queue_fh(sev->fh, &ev);
 	}
 	v4l2_ctrl_unlock(ctrl);
+	return 0;
 }
-EXPORT_SYMBOL(v4l2_ctrl_add_event);
 
-void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
-				struct v4l2_subscribed_event *sev)
+static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
 {
+	struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
 	v4l2_ctrl_lock(ctrl);
 	list_del(&sev->node);
 	v4l2_ctrl_unlock(ctrl);
 }
-EXPORT_SYMBOL(v4l2_ctrl_del_event);
+
+void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)
+{
+	u32 old_changes = old->u.ctrl.changes;
+
+	old->u.ctrl = new->u.ctrl;
+	old->u.ctrl.changes |= old_changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_replace);
+
+void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)
+{
+	new->u.ctrl.changes |= old->u.ctrl.changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_merge);
+
+const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = {
+	.add = v4l2_ctrl_add_event,
+	.del = v4l2_ctrl_del_event,
+	.replace = v4l2_ctrl_replace,
+	.merge = v4l2_ctrl_merge,
+};
+EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops);
 
 int v4l2_ctrl_log_status(struct file *file, void *fh)
 {
@@ -2425,7 +2633,7 @@
 				struct v4l2_event_subscription *sub)
 {
 	if (sub->type == V4L2_EVENT_CTRL)
-		return v4l2_event_subscribe(fh, sub, 0);
+		return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
 	return -EINVAL;
 }
 EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 70bec54..5ccbd46 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -274,11 +274,12 @@
 
 	if (!vdev->fops->read)
 		return -EINVAL;
-	if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+	if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
+	    mutex_lock_interruptible(vdev->lock))
 		return -ERESTARTSYS;
 	if (video_is_registered(vdev))
 		ret = vdev->fops->read(filp, buf, sz, off);
-	if (vdev->lock)
+	if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
 		mutex_unlock(vdev->lock);
 	return ret;
 }
@@ -291,11 +292,12 @@
 
 	if (!vdev->fops->write)
 		return -EINVAL;
-	if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+	if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
+	    mutex_lock_interruptible(vdev->lock))
 		return -ERESTARTSYS;
 	if (video_is_registered(vdev))
 		ret = vdev->fops->write(filp, buf, sz, off);
-	if (vdev->lock)
+	if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
 		mutex_unlock(vdev->lock);
 	return ret;
 }
@@ -307,11 +309,11 @@
 
 	if (!vdev->fops->poll)
 		return DEFAULT_POLLMASK;
-	if (vdev->lock)
+	if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
 		mutex_lock(vdev->lock);
 	if (video_is_registered(vdev))
 		ret = vdev->fops->poll(filp, poll);
-	if (vdev->lock)
+	if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
 		mutex_unlock(vdev->lock);
 	return ret;
 }
@@ -322,11 +324,19 @@
 	int ret = -ENODEV;
 
 	if (vdev->fops->unlocked_ioctl) {
-		if (vdev->lock && mutex_lock_interruptible(vdev->lock))
-			return -ERESTARTSYS;
+		bool locked = false;
+
+		if (vdev->lock) {
+			/* always lock unless the cmd is marked as "don't use lock" */
+			locked = !v4l2_is_known_ioctl(cmd) ||
+				 !test_bit(_IOC_NR(cmd), vdev->disable_locking);
+
+			if (locked && mutex_lock_interruptible(vdev->lock))
+				return -ERESTARTSYS;
+		}
 		if (video_is_registered(vdev))
 			ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
-		if (vdev->lock)
+		if (locked)
 			mutex_unlock(vdev->lock);
 	} else if (vdev->fops->ioctl) {
 		/* This code path is a replacement for the BKL. It is a major
@@ -391,11 +401,12 @@
 
 	if (!vdev->fops->mmap)
 		return ret;
-	if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+	if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
+	    mutex_lock_interruptible(vdev->lock))
 		return -ERESTARTSYS;
 	if (video_is_registered(vdev))
 		ret = vdev->fops->mmap(filp, vm);
-	if (vdev->lock)
+	if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
 		mutex_unlock(vdev->lock);
 	return ret;
 }
@@ -418,7 +429,8 @@
 	video_get(vdev);
 	mutex_unlock(&videodev_lock);
 	if (vdev->fops->open) {
-		if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
+		if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
+		    mutex_lock_interruptible(vdev->lock)) {
 			ret = -ERESTARTSYS;
 			goto err;
 		}
@@ -426,7 +438,7 @@
 			ret = vdev->fops->open(filp);
 		else
 			ret = -ENODEV;
-		if (vdev->lock)
+		if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
 			mutex_unlock(vdev->lock);
 	}
 
@@ -444,10 +456,10 @@
 	int ret = 0;
 
 	if (vdev->fops->release) {
-		if (vdev->lock)
+		if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
 			mutex_lock(vdev->lock);
 		vdev->fops->release(filp);
-		if (vdev->lock)
+		if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
 			mutex_unlock(vdev->lock);
 	}
 	/* decrease the refcount unconditionally since the release()
@@ -508,6 +520,175 @@
 	return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
 }
 
+#define SET_VALID_IOCTL(ops, cmd, op)			\
+	if (ops->op)					\
+		set_bit(_IOC_NR(cmd), valid_ioctls)
+
+/* This determines which ioctls are actually implemented in the driver.
+   It's a one-time thing which simplifies video_ioctl2 as it can just do
+   a bit test.
+
+   Note that drivers can override this by setting bits to 1 in
+   vdev->valid_ioctls. If an ioctl is marked as 1 when this function is
+   called, then that ioctl will actually be marked as unimplemented.
+
+   It does that by first setting up the local valid_ioctls bitmap, and
+   at the end do a:
+
+   vdev->valid_ioctls = valid_ioctls & ~(vdev->valid_ioctls)
+ */
+static void determine_valid_ioctls(struct video_device *vdev)
+{
+	DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
+	const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
+
+	bitmap_zero(valid_ioctls, BASE_VIDIOC_PRIVATE);
+
+	SET_VALID_IOCTL(ops, VIDIOC_QUERYCAP, vidioc_querycap);
+	if (ops->vidioc_g_priority ||
+			test_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags))
+		set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls);
+	if (ops->vidioc_s_priority ||
+			test_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags))
+		set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls);
+	if (ops->vidioc_enum_fmt_vid_cap ||
+	    ops->vidioc_enum_fmt_vid_out ||
+	    ops->vidioc_enum_fmt_vid_cap_mplane ||
+	    ops->vidioc_enum_fmt_vid_out_mplane ||
+	    ops->vidioc_enum_fmt_vid_overlay ||
+	    ops->vidioc_enum_fmt_type_private)
+		set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
+	if (ops->vidioc_g_fmt_vid_cap ||
+	    ops->vidioc_g_fmt_vid_out ||
+	    ops->vidioc_g_fmt_vid_cap_mplane ||
+	    ops->vidioc_g_fmt_vid_out_mplane ||
+	    ops->vidioc_g_fmt_vid_overlay ||
+	    ops->vidioc_g_fmt_vbi_cap ||
+	    ops->vidioc_g_fmt_vid_out_overlay ||
+	    ops->vidioc_g_fmt_vbi_out ||
+	    ops->vidioc_g_fmt_sliced_vbi_cap ||
+	    ops->vidioc_g_fmt_sliced_vbi_out ||
+	    ops->vidioc_g_fmt_type_private)
+		set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
+	if (ops->vidioc_s_fmt_vid_cap ||
+	    ops->vidioc_s_fmt_vid_out ||
+	    ops->vidioc_s_fmt_vid_cap_mplane ||
+	    ops->vidioc_s_fmt_vid_out_mplane ||
+	    ops->vidioc_s_fmt_vid_overlay ||
+	    ops->vidioc_s_fmt_vbi_cap ||
+	    ops->vidioc_s_fmt_vid_out_overlay ||
+	    ops->vidioc_s_fmt_vbi_out ||
+	    ops->vidioc_s_fmt_sliced_vbi_cap ||
+	    ops->vidioc_s_fmt_sliced_vbi_out ||
+	    ops->vidioc_s_fmt_type_private)
+		set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
+	if (ops->vidioc_try_fmt_vid_cap ||
+	    ops->vidioc_try_fmt_vid_out ||
+	    ops->vidioc_try_fmt_vid_cap_mplane ||
+	    ops->vidioc_try_fmt_vid_out_mplane ||
+	    ops->vidioc_try_fmt_vid_overlay ||
+	    ops->vidioc_try_fmt_vbi_cap ||
+	    ops->vidioc_try_fmt_vid_out_overlay ||
+	    ops->vidioc_try_fmt_vbi_out ||
+	    ops->vidioc_try_fmt_sliced_vbi_cap ||
+	    ops->vidioc_try_fmt_sliced_vbi_out ||
+	    ops->vidioc_try_fmt_type_private)
+		set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
+	SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
+	SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
+	SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
+	SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf);
+	SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay);
+	SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf);
+	SET_VALID_IOCTL(ops, VIDIOC_S_FBUF, vidioc_s_fbuf);
+	SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
+	SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
+	if (vdev->tvnorms)
+		set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
+	if (ops->vidioc_g_std || vdev->current_norm)
+		set_bit(_IOC_NR(VIDIOC_G_STD), valid_ioctls);
+	SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std);
+	SET_VALID_IOCTL(ops, VIDIOC_QUERYSTD, vidioc_querystd);
+	SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input);
+	SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input);
+	SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input);
+	SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output);
+	SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output);
+	SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output);
+	/* Note: the control handler can also be passed through the filehandle,
+	   and that can't be tested here. If the bit for these control ioctls
+	   is set, then the ioctl is valid. But if it is 0, then it can still
+	   be valid if the filehandle passed the control handler. */
+	if (vdev->ctrl_handler || ops->vidioc_queryctrl)
+		set_bit(_IOC_NR(VIDIOC_QUERYCTRL), valid_ioctls);
+	if (vdev->ctrl_handler || ops->vidioc_g_ctrl || ops->vidioc_g_ext_ctrls)
+		set_bit(_IOC_NR(VIDIOC_G_CTRL), valid_ioctls);
+	if (vdev->ctrl_handler || ops->vidioc_s_ctrl || ops->vidioc_s_ext_ctrls)
+		set_bit(_IOC_NR(VIDIOC_S_CTRL), valid_ioctls);
+	if (vdev->ctrl_handler || ops->vidioc_g_ext_ctrls)
+		set_bit(_IOC_NR(VIDIOC_G_EXT_CTRLS), valid_ioctls);
+	if (vdev->ctrl_handler || ops->vidioc_s_ext_ctrls)
+		set_bit(_IOC_NR(VIDIOC_S_EXT_CTRLS), valid_ioctls);
+	if (vdev->ctrl_handler || ops->vidioc_try_ext_ctrls)
+		set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls);
+	if (vdev->ctrl_handler || ops->vidioc_querymenu)
+		set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls);
+	SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDIO, vidioc_enumaudio);
+	SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio);
+	SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio);
+	SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDOUT, vidioc_enumaudout);
+	SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout);
+	SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout);
+	SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator);
+	SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator);
+	if (ops->vidioc_g_crop || ops->vidioc_g_selection)
+		set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls);
+	if (ops->vidioc_s_crop || ops->vidioc_s_selection)
+		set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
+	SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
+	SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
+	if (ops->vidioc_cropcap || ops->vidioc_g_selection)
+		set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
+	SET_VALID_IOCTL(ops, VIDIOC_G_JPEGCOMP, vidioc_g_jpegcomp);
+	SET_VALID_IOCTL(ops, VIDIOC_S_JPEGCOMP, vidioc_s_jpegcomp);
+	SET_VALID_IOCTL(ops, VIDIOC_G_ENC_INDEX, vidioc_g_enc_index);
+	SET_VALID_IOCTL(ops, VIDIOC_ENCODER_CMD, vidioc_encoder_cmd);
+	SET_VALID_IOCTL(ops, VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd);
+	SET_VALID_IOCTL(ops, VIDIOC_DECODER_CMD, vidioc_decoder_cmd);
+	SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd);
+	if (ops->vidioc_g_parm || vdev->current_norm)
+		set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
+	SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm);
+	SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner);
+	SET_VALID_IOCTL(ops, VIDIOC_S_TUNER, vidioc_s_tuner);
+	SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency);
+	SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
+	SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap);
+	SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	SET_VALID_IOCTL(ops, VIDIOC_DBG_G_REGISTER, vidioc_g_register);
+	SET_VALID_IOCTL(ops, VIDIOC_DBG_S_REGISTER, vidioc_s_register);
+#endif
+	SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident);
+	SET_VALID_IOCTL(ops, VIDIOC_S_HW_FREQ_SEEK, vidioc_s_hw_freq_seek);
+	SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes);
+	SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals);
+	SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets);
+	SET_VALID_IOCTL(ops, VIDIOC_S_DV_PRESET, vidioc_s_dv_preset);
+	SET_VALID_IOCTL(ops, VIDIOC_G_DV_PRESET, vidioc_g_dv_preset);
+	SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset);
+	SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings);
+	SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings);
+	/* yes, really vidioc_subscribe_event */
+	SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
+	SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
+	SET_VALID_IOCTL(ops, VIDIOC_UNSUBSCRIBE_EVENT, vidioc_unsubscribe_event);
+	SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs);
+	SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
+	bitmap_andnot(vdev->valid_ioctls, valid_ioctls, vdev->valid_ioctls,
+			BASE_VIDIOC_PRIVATE);
+}
+
 /**
  *	__video_register_device - register video4linux devices
  *	@vdev: video device structure we want to register
@@ -654,6 +835,13 @@
 	WARN_ON(video_device[vdev->minor] != NULL);
 	vdev->index = get_index(vdev);
 	mutex_unlock(&videodev_lock);
+	/* if no lock was passed, then make sure the LOCK_ALL_FOPS bit is
+	   clear and warn if it wasn't. */
+	if (vdev->lock == NULL)
+		WARN_ON(test_and_clear_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags));
+
+	if (vdev->ioctl_ops)
+		determine_valid_ioctls(vdev);
 
 	/* Part 3: Initialize the character device */
 	vdev->cdev = cdev_alloc();
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c
index c26ad96..ef2a33c 100644
--- a/drivers/media/video/v4l2-event.c
+++ b/drivers/media/video/v4l2-event.c
@@ -25,7 +25,6 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
-#include <media/v4l2-ctrls.h>
 
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -120,6 +119,14 @@
 	if (sev == NULL)
 		return;
 
+	/*
+	 * If the event has been added to the fh->subscribed list, but its
+	 * add op has not completed yet elems will be 0, treat this as
+	 * not being subscribed.
+	 */
+	if (!sev->elems)
+		return;
+
 	/* Increase event sequence number on fh. */
 	fh->sequence++;
 
@@ -132,14 +139,14 @@
 		sev->first = sev_pos(sev, 1);
 		fh->navailable--;
 		if (sev->elems == 1) {
-			if (sev->replace) {
-				sev->replace(&kev->event, ev);
+			if (sev->ops && sev->ops->replace) {
+				sev->ops->replace(&kev->event, ev);
 				copy_payload = false;
 			}
-		} else if (sev->merge) {
+		} else if (sev->ops && sev->ops->merge) {
 			struct v4l2_kevent *second_oldest =
 				sev->events + sev_pos(sev, 0);
-			sev->merge(&kev->event, &second_oldest->event);
+			sev->ops->merge(&kev->event, &second_oldest->event);
 		}
 	}
 
@@ -195,24 +202,11 @@
 }
 EXPORT_SYMBOL_GPL(v4l2_event_pending);
 
-static void ctrls_replace(struct v4l2_event *old, const struct v4l2_event *new)
-{
-	u32 old_changes = old->u.ctrl.changes;
-
-	old->u.ctrl = new->u.ctrl;
-	old->u.ctrl.changes |= old_changes;
-}
-
-static void ctrls_merge(const struct v4l2_event *old, struct v4l2_event *new)
-{
-	new->u.ctrl.changes |= old->u.ctrl.changes;
-}
-
 int v4l2_event_subscribe(struct v4l2_fh *fh,
-			 struct v4l2_event_subscription *sub, unsigned elems)
+			 struct v4l2_event_subscription *sub, unsigned elems,
+			 const struct v4l2_subscribed_event_ops *ops)
 {
 	struct v4l2_subscribed_event *sev, *found_ev;
-	struct v4l2_ctrl *ctrl = NULL;
 	unsigned long flags;
 	unsigned i;
 
@@ -221,11 +215,6 @@
 
 	if (elems < 1)
 		elems = 1;
-	if (sub->type == V4L2_EVENT_CTRL) {
-		ctrl = v4l2_ctrl_find(fh->ctrl_handler, sub->id);
-		if (ctrl == NULL)
-			return -EINVAL;
-	}
 
 	sev = kzalloc(sizeof(*sev) + sizeof(struct v4l2_kevent) * elems, GFP_KERNEL);
 	if (!sev)
@@ -236,11 +225,7 @@
 	sev->id = sub->id;
 	sev->flags = sub->flags;
 	sev->fh = fh;
-	sev->elems = elems;
-	if (ctrl) {
-		sev->replace = ctrls_replace;
-		sev->merge = ctrls_merge;
-	}
+	sev->ops = ops;
 
 	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
 	found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
@@ -248,11 +233,22 @@
 		list_add(&sev->list, &fh->subscribed);
 	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
 
-	/* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */
-	if (found_ev)
+	if (found_ev) {
 		kfree(sev);
-	else if (ctrl)
-		v4l2_ctrl_add_event(ctrl, sev);
+		return 0; /* Already listening */
+	}
+
+	if (sev->ops && sev->ops->add) {
+		int ret = sev->ops->add(sev, elems);
+		if (ret) {
+			sev->ops = NULL;
+			v4l2_event_unsubscribe(fh, sub);
+			return ret;
+		}
+	}
+
+	/* Mark as ready for use */
+	sev->elems = elems;
 
 	return 0;
 }
@@ -306,12 +302,9 @@
 	}
 
 	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
-	if (sev && sev->type == V4L2_EVENT_CTRL) {
-		struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id);
 
-		if (ctrl)
-			v4l2_ctrl_del_event(ctrl, sev);
-	}
+	if (sev && sev->ops && sev->ops->del)
+		sev->ops->del(sev);
 
 	kfree(sev);
 
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 5b2ec1f..91be4e8 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -55,19 +55,6 @@
 	memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \
 	0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field))
 
-#define have_fmt_ops(foo) (						\
-	ops->vidioc_##foo##_fmt_vid_cap ||				\
-	ops->vidioc_##foo##_fmt_vid_out ||				\
-	ops->vidioc_##foo##_fmt_vid_cap_mplane ||			\
-	ops->vidioc_##foo##_fmt_vid_out_mplane ||			\
-	ops->vidioc_##foo##_fmt_vid_overlay ||				\
-	ops->vidioc_##foo##_fmt_vbi_cap ||				\
-	ops->vidioc_##foo##_fmt_vid_out_overlay ||			\
-	ops->vidioc_##foo##_fmt_vbi_out ||				\
-	ops->vidioc_##foo##_fmt_sliced_vbi_cap ||			\
-	ops->vidioc_##foo##_fmt_sliced_vbi_out ||			\
-	ops->vidioc_##foo##_fmt_type_private)
-
 struct std_descr {
 	v4l2_std_id std;
 	const char *descr;
@@ -195,93 +182,118 @@
 
 /* ------------------------------------------------------------------ */
 /* debug help functions                                               */
-static const char *v4l2_ioctls[] = {
-	[_IOC_NR(VIDIOC_QUERYCAP)]         = "VIDIOC_QUERYCAP",
-	[_IOC_NR(VIDIOC_RESERVED)]         = "VIDIOC_RESERVED",
-	[_IOC_NR(VIDIOC_ENUM_FMT)]         = "VIDIOC_ENUM_FMT",
-	[_IOC_NR(VIDIOC_G_FMT)]            = "VIDIOC_G_FMT",
-	[_IOC_NR(VIDIOC_S_FMT)]            = "VIDIOC_S_FMT",
-	[_IOC_NR(VIDIOC_REQBUFS)]          = "VIDIOC_REQBUFS",
-	[_IOC_NR(VIDIOC_QUERYBUF)]         = "VIDIOC_QUERYBUF",
-	[_IOC_NR(VIDIOC_G_FBUF)]           = "VIDIOC_G_FBUF",
-	[_IOC_NR(VIDIOC_S_FBUF)]           = "VIDIOC_S_FBUF",
-	[_IOC_NR(VIDIOC_OVERLAY)]          = "VIDIOC_OVERLAY",
-	[_IOC_NR(VIDIOC_QBUF)]             = "VIDIOC_QBUF",
-	[_IOC_NR(VIDIOC_DQBUF)]            = "VIDIOC_DQBUF",
-	[_IOC_NR(VIDIOC_STREAMON)]         = "VIDIOC_STREAMON",
-	[_IOC_NR(VIDIOC_STREAMOFF)]        = "VIDIOC_STREAMOFF",
-	[_IOC_NR(VIDIOC_G_PARM)]           = "VIDIOC_G_PARM",
-	[_IOC_NR(VIDIOC_S_PARM)]           = "VIDIOC_S_PARM",
-	[_IOC_NR(VIDIOC_G_STD)]            = "VIDIOC_G_STD",
-	[_IOC_NR(VIDIOC_S_STD)]            = "VIDIOC_S_STD",
-	[_IOC_NR(VIDIOC_ENUMSTD)]          = "VIDIOC_ENUMSTD",
-	[_IOC_NR(VIDIOC_ENUMINPUT)]        = "VIDIOC_ENUMINPUT",
-	[_IOC_NR(VIDIOC_G_CTRL)]           = "VIDIOC_G_CTRL",
-	[_IOC_NR(VIDIOC_S_CTRL)]           = "VIDIOC_S_CTRL",
-	[_IOC_NR(VIDIOC_G_TUNER)]          = "VIDIOC_G_TUNER",
-	[_IOC_NR(VIDIOC_S_TUNER)]          = "VIDIOC_S_TUNER",
-	[_IOC_NR(VIDIOC_G_AUDIO)]          = "VIDIOC_G_AUDIO",
-	[_IOC_NR(VIDIOC_S_AUDIO)]          = "VIDIOC_S_AUDIO",
-	[_IOC_NR(VIDIOC_QUERYCTRL)]        = "VIDIOC_QUERYCTRL",
-	[_IOC_NR(VIDIOC_QUERYMENU)]        = "VIDIOC_QUERYMENU",
-	[_IOC_NR(VIDIOC_G_INPUT)]          = "VIDIOC_G_INPUT",
-	[_IOC_NR(VIDIOC_S_INPUT)]          = "VIDIOC_S_INPUT",
-	[_IOC_NR(VIDIOC_G_OUTPUT)]         = "VIDIOC_G_OUTPUT",
-	[_IOC_NR(VIDIOC_S_OUTPUT)]         = "VIDIOC_S_OUTPUT",
-	[_IOC_NR(VIDIOC_ENUMOUTPUT)]       = "VIDIOC_ENUMOUTPUT",
-	[_IOC_NR(VIDIOC_G_AUDOUT)]         = "VIDIOC_G_AUDOUT",
-	[_IOC_NR(VIDIOC_S_AUDOUT)]         = "VIDIOC_S_AUDOUT",
-	[_IOC_NR(VIDIOC_G_MODULATOR)]      = "VIDIOC_G_MODULATOR",
-	[_IOC_NR(VIDIOC_S_MODULATOR)]      = "VIDIOC_S_MODULATOR",
-	[_IOC_NR(VIDIOC_G_FREQUENCY)]      = "VIDIOC_G_FREQUENCY",
-	[_IOC_NR(VIDIOC_S_FREQUENCY)]      = "VIDIOC_S_FREQUENCY",
-	[_IOC_NR(VIDIOC_CROPCAP)]          = "VIDIOC_CROPCAP",
-	[_IOC_NR(VIDIOC_G_CROP)]           = "VIDIOC_G_CROP",
-	[_IOC_NR(VIDIOC_S_CROP)]           = "VIDIOC_S_CROP",
-	[_IOC_NR(VIDIOC_G_SELECTION)]      = "VIDIOC_G_SELECTION",
-	[_IOC_NR(VIDIOC_S_SELECTION)]      = "VIDIOC_S_SELECTION",
-	[_IOC_NR(VIDIOC_G_JPEGCOMP)]       = "VIDIOC_G_JPEGCOMP",
-	[_IOC_NR(VIDIOC_S_JPEGCOMP)]       = "VIDIOC_S_JPEGCOMP",
-	[_IOC_NR(VIDIOC_QUERYSTD)]         = "VIDIOC_QUERYSTD",
-	[_IOC_NR(VIDIOC_TRY_FMT)]          = "VIDIOC_TRY_FMT",
-	[_IOC_NR(VIDIOC_ENUMAUDIO)]        = "VIDIOC_ENUMAUDIO",
-	[_IOC_NR(VIDIOC_ENUMAUDOUT)]       = "VIDIOC_ENUMAUDOUT",
-	[_IOC_NR(VIDIOC_G_PRIORITY)]       = "VIDIOC_G_PRIORITY",
-	[_IOC_NR(VIDIOC_S_PRIORITY)]       = "VIDIOC_S_PRIORITY",
-	[_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
-	[_IOC_NR(VIDIOC_LOG_STATUS)]       = "VIDIOC_LOG_STATUS",
-	[_IOC_NR(VIDIOC_G_EXT_CTRLS)]      = "VIDIOC_G_EXT_CTRLS",
-	[_IOC_NR(VIDIOC_S_EXT_CTRLS)]      = "VIDIOC_S_EXT_CTRLS",
-	[_IOC_NR(VIDIOC_TRY_EXT_CTRLS)]    = "VIDIOC_TRY_EXT_CTRLS",
-#if 1
-	[_IOC_NR(VIDIOC_ENUM_FRAMESIZES)]  = "VIDIOC_ENUM_FRAMESIZES",
-	[_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS",
-	[_IOC_NR(VIDIOC_G_ENC_INDEX)] 	   = "VIDIOC_G_ENC_INDEX",
-	[_IOC_NR(VIDIOC_ENCODER_CMD)] 	   = "VIDIOC_ENCODER_CMD",
-	[_IOC_NR(VIDIOC_TRY_ENCODER_CMD)]  = "VIDIOC_TRY_ENCODER_CMD",
 
-	[_IOC_NR(VIDIOC_DECODER_CMD)]	   = "VIDIOC_DECODER_CMD",
-	[_IOC_NR(VIDIOC_TRY_DECODER_CMD)]  = "VIDIOC_TRY_DECODER_CMD",
-	[_IOC_NR(VIDIOC_DBG_S_REGISTER)]   = "VIDIOC_DBG_S_REGISTER",
-	[_IOC_NR(VIDIOC_DBG_G_REGISTER)]   = "VIDIOC_DBG_G_REGISTER",
+struct v4l2_ioctl_info {
+	unsigned int ioctl;
+	u16 flags;
+	const char * const name;
+};
 
-	[_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT",
-	[_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)]   = "VIDIOC_S_HW_FREQ_SEEK",
+/* This control needs a priority check */
+#define INFO_FL_PRIO	(1 << 0)
+/* This control can be valid if the filehandle passes a control handler. */
+#define INFO_FL_CTRL	(1 << 1)
+
+#define IOCTL_INFO(_ioctl, _flags) [_IOC_NR(_ioctl)] = {	\
+	.ioctl = _ioctl,					\
+	.flags = _flags,					\
+	.name = #_ioctl,					\
+}
+
+static struct v4l2_ioctl_info v4l2_ioctls[] = {
+	IOCTL_INFO(VIDIOC_QUERYCAP, 0),
+	IOCTL_INFO(VIDIOC_ENUM_FMT, 0),
+	IOCTL_INFO(VIDIOC_G_FMT, 0),
+	IOCTL_INFO(VIDIOC_S_FMT, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_REQBUFS, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_QUERYBUF, 0),
+	IOCTL_INFO(VIDIOC_G_FBUF, 0),
+	IOCTL_INFO(VIDIOC_S_FBUF, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_OVERLAY, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_QBUF, 0),
+	IOCTL_INFO(VIDIOC_DQBUF, 0),
+	IOCTL_INFO(VIDIOC_STREAMON, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_STREAMOFF, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_PARM, 0),
+	IOCTL_INFO(VIDIOC_S_PARM, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_STD, 0),
+	IOCTL_INFO(VIDIOC_S_STD, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_ENUMSTD, 0),
+	IOCTL_INFO(VIDIOC_ENUMINPUT, 0),
+	IOCTL_INFO(VIDIOC_G_CTRL, INFO_FL_CTRL),
+	IOCTL_INFO(VIDIOC_S_CTRL, INFO_FL_PRIO | INFO_FL_CTRL),
+	IOCTL_INFO(VIDIOC_G_TUNER, 0),
+	IOCTL_INFO(VIDIOC_S_TUNER, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_AUDIO, 0),
+	IOCTL_INFO(VIDIOC_S_AUDIO, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_QUERYCTRL, INFO_FL_CTRL),
+	IOCTL_INFO(VIDIOC_QUERYMENU, INFO_FL_CTRL),
+	IOCTL_INFO(VIDIOC_G_INPUT, 0),
+	IOCTL_INFO(VIDIOC_S_INPUT, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_OUTPUT, 0),
+	IOCTL_INFO(VIDIOC_S_OUTPUT, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_ENUMOUTPUT, 0),
+	IOCTL_INFO(VIDIOC_G_AUDOUT, 0),
+	IOCTL_INFO(VIDIOC_S_AUDOUT, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_MODULATOR, 0),
+	IOCTL_INFO(VIDIOC_S_MODULATOR, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_FREQUENCY, 0),
+	IOCTL_INFO(VIDIOC_S_FREQUENCY, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_CROPCAP, 0),
+	IOCTL_INFO(VIDIOC_G_CROP, 0),
+	IOCTL_INFO(VIDIOC_S_CROP, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_SELECTION, 0),
+	IOCTL_INFO(VIDIOC_S_SELECTION, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_JPEGCOMP, 0),
+	IOCTL_INFO(VIDIOC_S_JPEGCOMP, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_QUERYSTD, 0),
+	IOCTL_INFO(VIDIOC_TRY_FMT, 0),
+	IOCTL_INFO(VIDIOC_ENUMAUDIO, 0),
+	IOCTL_INFO(VIDIOC_ENUMAUDOUT, 0),
+	IOCTL_INFO(VIDIOC_G_PRIORITY, 0),
+	IOCTL_INFO(VIDIOC_S_PRIORITY, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_SLICED_VBI_CAP, 0),
+	IOCTL_INFO(VIDIOC_LOG_STATUS, 0),
+	IOCTL_INFO(VIDIOC_G_EXT_CTRLS, INFO_FL_CTRL),
+	IOCTL_INFO(VIDIOC_S_EXT_CTRLS, INFO_FL_PRIO | INFO_FL_CTRL),
+	IOCTL_INFO(VIDIOC_TRY_EXT_CTRLS, 0),
+	IOCTL_INFO(VIDIOC_ENUM_FRAMESIZES, 0),
+	IOCTL_INFO(VIDIOC_ENUM_FRAMEINTERVALS, 0),
+	IOCTL_INFO(VIDIOC_G_ENC_INDEX, 0),
+	IOCTL_INFO(VIDIOC_ENCODER_CMD, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_TRY_ENCODER_CMD, 0),
+	IOCTL_INFO(VIDIOC_DECODER_CMD, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_TRY_DECODER_CMD, 0),
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	IOCTL_INFO(VIDIOC_DBG_S_REGISTER, 0),
+	IOCTL_INFO(VIDIOC_DBG_G_REGISTER, 0),
 #endif
-	[_IOC_NR(VIDIOC_ENUM_DV_PRESETS)]  = "VIDIOC_ENUM_DV_PRESETS",
-	[_IOC_NR(VIDIOC_S_DV_PRESET)]	   = "VIDIOC_S_DV_PRESET",
-	[_IOC_NR(VIDIOC_G_DV_PRESET)]	   = "VIDIOC_G_DV_PRESET",
-	[_IOC_NR(VIDIOC_QUERY_DV_PRESET)]  = "VIDIOC_QUERY_DV_PRESET",
-	[_IOC_NR(VIDIOC_S_DV_TIMINGS)]     = "VIDIOC_S_DV_TIMINGS",
-	[_IOC_NR(VIDIOC_G_DV_TIMINGS)]     = "VIDIOC_G_DV_TIMINGS",
-	[_IOC_NR(VIDIOC_DQEVENT)]	   = "VIDIOC_DQEVENT",
-	[_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)]  = "VIDIOC_SUBSCRIBE_EVENT",
-	[_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT",
-	[_IOC_NR(VIDIOC_CREATE_BUFS)]      = "VIDIOC_CREATE_BUFS",
-	[_IOC_NR(VIDIOC_PREPARE_BUF)]      = "VIDIOC_PREPARE_BUF",
+	IOCTL_INFO(VIDIOC_DBG_G_CHIP_IDENT, 0),
+	IOCTL_INFO(VIDIOC_S_HW_FREQ_SEEK, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_ENUM_DV_PRESETS, 0),
+	IOCTL_INFO(VIDIOC_S_DV_PRESET, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_DV_PRESET, 0),
+	IOCTL_INFO(VIDIOC_QUERY_DV_PRESET, 0),
+	IOCTL_INFO(VIDIOC_S_DV_TIMINGS, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_G_DV_TIMINGS, 0),
+	IOCTL_INFO(VIDIOC_DQEVENT, 0),
+	IOCTL_INFO(VIDIOC_SUBSCRIBE_EVENT, 0),
+	IOCTL_INFO(VIDIOC_UNSUBSCRIBE_EVENT, 0),
+	IOCTL_INFO(VIDIOC_CREATE_BUFS, INFO_FL_PRIO),
+	IOCTL_INFO(VIDIOC_PREPARE_BUF, 0),
+	IOCTL_INFO(VIDIOC_ENUM_DV_TIMINGS, 0),
+	IOCTL_INFO(VIDIOC_QUERY_DV_TIMINGS, 0),
+	IOCTL_INFO(VIDIOC_DV_TIMINGS_CAP, 0),
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
+bool v4l2_is_known_ioctl(unsigned int cmd)
+{
+	if (_IOC_NR(cmd) >= V4L2_IOCTLS)
+		return false;
+	return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd;
+}
+
 /* Common ioctl debug function. This function can be used by
    external ioctl messages as well as internal V4L ioctl */
 void v4l_printk_ioctl(unsigned int cmd)
@@ -297,7 +309,7 @@
 			type = "v4l2";
 			break;
 		}
-		printk("%s", v4l2_ioctls[_IOC_NR(cmd)]);
+		printk("%s", v4l2_ioctls[_IOC_NR(cmd)].name);
 		return;
 	default:
 		type = "unknown";
@@ -359,6 +371,34 @@
 						r->width, r->height);
 };
 
+static void dbgtimings(struct video_device *vfd,
+			const struct v4l2_dv_timings *p)
+{
+	switch (p->type) {
+	case V4L2_DV_BT_656_1120:
+		dbgarg2("bt-656/1120:interlaced=%d,"
+				" pixelclock=%lld,"
+				" width=%d, height=%d, polarities=%x,"
+				" hfrontporch=%d, hsync=%d,"
+				" hbackporch=%d, vfrontporch=%d,"
+				" vsync=%d, vbackporch=%d,"
+				" il_vfrontporch=%d, il_vsync=%d,"
+				" il_vbackporch=%d, standards=%x, flags=%x\n",
+				p->bt.interlaced, p->bt.pixelclock,
+				p->bt.width, p->bt.height,
+				p->bt.polarities, p->bt.hfrontporch,
+				p->bt.hsync, p->bt.hbackporch,
+				p->bt.vfrontporch, p->bt.vsync,
+				p->bt.vbackporch, p->bt.il_vfrontporch,
+				p->bt.il_vsync, p->bt.il_vbackporch,
+				p->bt.standards, p->bt.flags);
+		break;
+	default:
+		dbgarg2("Unknown type %d!\n", p->type);
+		break;
+	}
+}
+
 static inline void v4l_print_pix_fmt(struct video_device *vfd,
 						struct v4l2_pix_format *fmt)
 {
@@ -504,7 +544,6 @@
 	void *fh = file->private_data;
 	struct v4l2_fh *vfh = NULL;
 	int use_fh_prio = 0;
-	long ret_prio = 0;
 	long ret = -ENOTTY;
 
 	if (ops == NULL) {
@@ -513,19 +552,30 @@
 		return ret;
 	}
 
-	if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
-				!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
-		v4l_print_ioctl(vfd->name, cmd);
-		printk(KERN_CONT "\n");
-	}
-
 	if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
 		vfh = file->private_data;
 		use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
 	}
 
-	if (use_fh_prio)
-		ret_prio = v4l2_prio_check(vfd->prio, vfh->prio);
+	if (v4l2_is_known_ioctl(cmd)) {
+		struct v4l2_ioctl_info *info = &v4l2_ioctls[_IOC_NR(cmd)];
+
+	        if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) &&
+		    !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler))
+			return -ENOTTY;
+
+		if (use_fh_prio && (info->flags & INFO_FL_PRIO)) {
+			ret = v4l2_prio_check(vfd->prio, vfh->prio);
+			if (ret)
+				return ret;
+		}
+	}
+
+	if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
+				!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
+		v4l_print_ioctl(vfd->name, cmd);
+		printk(KERN_CONT "\n");
+	}
 
 	switch (cmd) {
 
@@ -534,9 +584,6 @@
 	{
 		struct v4l2_capability *cap = (struct v4l2_capability *)arg;
 
-		if (!ops->vidioc_querycap)
-			break;
-
 		cap->version = LINUX_VERSION_CODE;
 		ret = ops->vidioc_querycap(file, fh, cap);
 		if (!ret)
@@ -570,14 +617,11 @@
 	{
 		enum v4l2_priority *p = arg;
 
-		if (!ops->vidioc_s_priority && !use_fh_prio)
-			break;
 		dbgarg(cmd, "setting priority to %d\n", *p);
 		if (ops->vidioc_s_priority)
 			ret = ops->vidioc_s_priority(file, fh, *p);
 		else
-			ret = ret_prio ? ret_prio :
-				v4l2_prio_change(&vfd->v4l2_dev->prio,
+			ret = v4l2_prio_change(&vfd->v4l2_dev->prio,
 							&vfh->prio, *p);
 		break;
 	}
@@ -587,6 +631,7 @@
 	{
 		struct v4l2_fmtdesc *f = arg;
 
+		ret = -EINVAL;
 		switch (f->type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 			if (likely(ops->vidioc_enum_fmt_vid_cap))
@@ -619,7 +664,7 @@
 		default:
 			break;
 		}
-		if (likely (!ret))
+		if (likely(!ret))
 			dbgarg(cmd, "index=%d, type=%d, flags=%d, "
 				"pixelformat=%c%c%c%c, description='%s'\n",
 				f->index, f->type, f->flags,
@@ -628,14 +673,6 @@
 				(f->pixelformat >> 16) & 0xff,
 				(f->pixelformat >> 24) & 0xff,
 				f->description);
-		else if (ret == -ENOTTY &&
-			 (ops->vidioc_enum_fmt_vid_cap ||
-			  ops->vidioc_enum_fmt_vid_out ||
-			  ops->vidioc_enum_fmt_vid_cap_mplane ||
-			  ops->vidioc_enum_fmt_vid_out_mplane ||
-			  ops->vidioc_enum_fmt_vid_overlay ||
-			  ops->vidioc_enum_fmt_type_private))
-			ret = -EINVAL;
 		break;
 	}
 	case VIDIOC_G_FMT:
@@ -645,6 +682,7 @@
 		/* FIXME: Should be one dump per type */
 		dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
 
+		ret = -EINVAL;
 		switch (f->type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 			if (ops->vidioc_g_fmt_vid_cap)
@@ -706,21 +744,12 @@
 								fh, f);
 			break;
 		}
-		if (unlikely(ret == -ENOTTY && have_fmt_ops(g)))
-			ret = -EINVAL;
-
 		break;
 	}
 	case VIDIOC_S_FMT:
 	{
 		struct v4l2_format *f = (struct v4l2_format *)arg;
 
-		if (!have_fmt_ops(s))
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		ret = -EINVAL;
 
 		/* FIXME: Should be one dump per type */
@@ -804,6 +833,7 @@
 		/* FIXME: Should be one dump per type */
 		dbgarg(cmd, "type=%s\n", prt_names(f->type,
 						v4l2_type_names));
+		ret = -EINVAL;
 		switch (f->type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 			CLEAR_AFTER_FIELD(f, fmt.pix);
@@ -876,8 +906,6 @@
 								fh, f);
 			break;
 		}
-		if (unlikely(ret == -ENOTTY && have_fmt_ops(try)))
-			ret = -EINVAL;
 		break;
 	}
 	/* FIXME: Those buf reqs could be handled here,
@@ -888,12 +916,6 @@
 	{
 		struct v4l2_requestbuffers *p = arg;
 
-		if (!ops->vidioc_reqbufs)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		ret = check_fmt(ops, p->type);
 		if (ret)
 			break;
@@ -912,8 +934,6 @@
 	{
 		struct v4l2_buffer *p = arg;
 
-		if (!ops->vidioc_querybuf)
-			break;
 		ret = check_fmt(ops, p->type);
 		if (ret)
 			break;
@@ -927,8 +947,6 @@
 	{
 		struct v4l2_buffer *p = arg;
 
-		if (!ops->vidioc_qbuf)
-			break;
 		ret = check_fmt(ops, p->type);
 		if (ret)
 			break;
@@ -942,8 +960,6 @@
 	{
 		struct v4l2_buffer *p = arg;
 
-		if (!ops->vidioc_dqbuf)
-			break;
 		ret = check_fmt(ops, p->type);
 		if (ret)
 			break;
@@ -957,12 +973,6 @@
 	{
 		int *i = arg;
 
-		if (!ops->vidioc_overlay)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "value=%d\n", *i);
 		ret = ops->vidioc_overlay(file, fh, *i);
 		break;
@@ -971,8 +981,6 @@
 	{
 		struct v4l2_framebuffer *p = arg;
 
-		if (!ops->vidioc_g_fbuf)
-			break;
 		ret = ops->vidioc_g_fbuf(file, fh, arg);
 		if (!ret) {
 			dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
@@ -986,12 +994,6 @@
 	{
 		struct v4l2_framebuffer *p = arg;
 
-		if (!ops->vidioc_s_fbuf)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
 			p->capability, p->flags, (unsigned long)p->base);
 		v4l_print_pix_fmt(vfd, &p->fmt);
@@ -1002,12 +1004,6 @@
 	{
 		enum v4l2_buf_type i = *(int *)arg;
 
-		if (!ops->vidioc_streamon)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
 		ret = ops->vidioc_streamon(file, fh, i);
 		break;
@@ -1016,12 +1012,6 @@
 	{
 		enum v4l2_buf_type i = *(int *)arg;
 
-		if (!ops->vidioc_streamoff)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
 		ret = ops->vidioc_streamoff(file, fh, i);
 		break;
@@ -1091,13 +1081,6 @@
 
 		dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id);
 
-		if (!ops->vidioc_s_std)
-			break;
-
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		ret = -EINVAL;
 		norm = (*id) & vfd->tvnorms;
 		if (vfd->tvnorms && !norm)	/* Check if std is supported */
@@ -1115,8 +1098,6 @@
 	{
 		v4l2_std_id *p = arg;
 
-		if (!ops->vidioc_querystd)
-			break;
 		/*
 		 * If nothing detected, it should return all supported
 		 * Drivers just need to mask the std argument, in order
@@ -1150,9 +1131,6 @@
 		if (ops->vidioc_s_dv_timings)
 			p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS;
 
-		if (!ops->vidioc_enum_input)
-			break;
-
 		ret = ops->vidioc_enum_input(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1168,8 +1146,6 @@
 	{
 		unsigned int *i = arg;
 
-		if (!ops->vidioc_g_input)
-			break;
 		ret = ops->vidioc_g_input(file, fh, i);
 		if (!ret)
 			dbgarg(cmd, "value=%d\n", *i);
@@ -1179,12 +1155,6 @@
 	{
 		unsigned int *i = arg;
 
-		if (!ops->vidioc_s_input)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "value=%d\n", *i);
 		ret = ops->vidioc_s_input(file, fh, *i);
 		break;
@@ -1195,9 +1165,6 @@
 	{
 		struct v4l2_output *p = arg;
 
-		if (!ops->vidioc_enum_output)
-			break;
-
 		/*
 		 * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS &
 		 * CAP_STD here based on ioctl handler provided by the
@@ -1224,8 +1191,6 @@
 	{
 		unsigned int *i = arg;
 
-		if (!ops->vidioc_g_output)
-			break;
 		ret = ops->vidioc_g_output(file, fh, i);
 		if (!ret)
 			dbgarg(cmd, "value=%d\n", *i);
@@ -1235,12 +1200,6 @@
 	{
 		unsigned int *i = arg;
 
-		if (!ops->vidioc_s_output)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "value=%d\n", *i);
 		ret = ops->vidioc_s_output(file, fh, *i);
 		break;
@@ -1310,10 +1269,6 @@
 		if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
 			!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
 			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 
 		dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
 
@@ -1369,10 +1324,6 @@
 		if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
 				!ops->vidioc_s_ext_ctrls)
 			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		v4l_print_ext_ctrls(cmd, vfd, p, 1);
 		if (vfh && vfh->ctrl_handler)
 			ret = v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p);
@@ -1428,8 +1379,6 @@
 	{
 		struct v4l2_audio *p = arg;
 
-		if (!ops->vidioc_enumaudio)
-			break;
 		ret = ops->vidioc_enumaudio(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
@@ -1443,9 +1392,6 @@
 	{
 		struct v4l2_audio *p = arg;
 
-		if (!ops->vidioc_g_audio)
-			break;
-
 		ret = ops->vidioc_g_audio(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
@@ -1459,12 +1405,6 @@
 	{
 		struct v4l2_audio *p = arg;
 
-		if (!ops->vidioc_s_audio)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
 					"mode=0x%x\n", p->index, p->name,
 					p->capability, p->mode);
@@ -1475,8 +1415,6 @@
 	{
 		struct v4l2_audioout *p = arg;
 
-		if (!ops->vidioc_enumaudout)
-			break;
 		dbgarg(cmd, "Enum for index=%d\n", p->index);
 		ret = ops->vidioc_enumaudout(file, fh, p);
 		if (!ret)
@@ -1489,9 +1427,6 @@
 	{
 		struct v4l2_audioout *p = arg;
 
-		if (!ops->vidioc_g_audout)
-			break;
-
 		ret = ops->vidioc_g_audout(file, fh, p);
 		if (!ret)
 			dbgarg2("index=%d, name=%s, capability=%d, "
@@ -1503,12 +1438,6 @@
 	{
 		struct v4l2_audioout *p = arg;
 
-		if (!ops->vidioc_s_audout)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "index=%d, name=%s, capability=%d, "
 					"mode=%d\n", p->index, p->name,
 					p->capability, p->mode);
@@ -1520,8 +1449,6 @@
 	{
 		struct v4l2_modulator *p = arg;
 
-		if (!ops->vidioc_g_modulator)
-			break;
 		ret = ops->vidioc_g_modulator(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "index=%d, name=%s, "
@@ -1536,12 +1463,6 @@
 	{
 		struct v4l2_modulator *p = arg;
 
-		if (!ops->vidioc_s_modulator)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "index=%d, name=%s, capability=%d, "
 				"rangelow=%d, rangehigh=%d, txsubchans=%d\n",
 				p->index, p->name, p->capability, p->rangelow,
@@ -1553,9 +1474,6 @@
 	{
 		struct v4l2_crop *p = arg;
 
-		if (!ops->vidioc_g_crop && !ops->vidioc_g_selection)
-			break;
-
 		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
 
 		if (ops->vidioc_g_crop) {
@@ -1587,13 +1505,6 @@
 	{
 		struct v4l2_crop *p = arg;
 
-		if (!ops->vidioc_s_crop && !ops->vidioc_s_selection)
-			break;
-
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
 		dbgrect(vfd, "", &p->c);
 
@@ -1620,9 +1531,6 @@
 	{
 		struct v4l2_selection *p = arg;
 
-		if (!ops->vidioc_g_selection)
-			break;
-
 		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
 
 		ret = ops->vidioc_g_selection(file, fh, p);
@@ -1634,13 +1542,6 @@
 	{
 		struct v4l2_selection *p = arg;
 
-		if (!ops->vidioc_s_selection)
-			break;
-
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 
 		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
 		dbgrect(vfd, "", &p->r);
@@ -1653,9 +1554,6 @@
 		struct v4l2_cropcap *p = arg;
 
 		/*FIXME: Should also show v4l2_fract pixelaspect */
-		if (!ops->vidioc_cropcap && !ops->vidioc_g_selection)
-			break;
-
 		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
 		if (ops->vidioc_cropcap) {
 			ret = ops->vidioc_cropcap(file, fh, p);
@@ -1699,9 +1597,6 @@
 	{
 		struct v4l2_jpegcompression *p = arg;
 
-		if (!ops->vidioc_g_jpegcomp)
-			break;
-
 		ret = ops->vidioc_g_jpegcomp(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "quality=%d, APPn=%d, "
@@ -1715,12 +1610,6 @@
 	{
 		struct v4l2_jpegcompression *p = arg;
 
-		if (!ops->vidioc_g_jpegcomp)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, "
 					"COM_len=%d, jpeg_markers=%d\n",
 					p->quality, p->APPn, p->APP_len,
@@ -1732,8 +1621,6 @@
 	{
 		struct v4l2_enc_idx *p = arg;
 
-		if (!ops->vidioc_g_enc_index)
-			break;
 		ret = ops->vidioc_g_enc_index(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "entries=%d, entries_cap=%d\n",
@@ -1744,12 +1631,6 @@
 	{
 		struct v4l2_encoder_cmd *p = arg;
 
-		if (!ops->vidioc_encoder_cmd)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		ret = ops->vidioc_encoder_cmd(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1759,8 +1640,6 @@
 	{
 		struct v4l2_encoder_cmd *p = arg;
 
-		if (!ops->vidioc_try_encoder_cmd)
-			break;
 		ret = ops->vidioc_try_encoder_cmd(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1770,12 +1649,6 @@
 	{
 		struct v4l2_decoder_cmd *p = arg;
 
-		if (!ops->vidioc_decoder_cmd)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		ret = ops->vidioc_decoder_cmd(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1785,8 +1658,6 @@
 	{
 		struct v4l2_decoder_cmd *p = arg;
 
-		if (!ops->vidioc_try_decoder_cmd)
-			break;
 		ret = ops->vidioc_try_decoder_cmd(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1796,8 +1667,6 @@
 	{
 		struct v4l2_streamparm *p = arg;
 
-		if (!ops->vidioc_g_parm && !vfd->current_norm)
-			break;
 		if (ops->vidioc_g_parm) {
 			ret = check_fmt(ops, p->type);
 			if (ret)
@@ -1825,12 +1694,6 @@
 	{
 		struct v4l2_streamparm *p = arg;
 
-		if (!ops->vidioc_s_parm)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		ret = check_fmt(ops, p->type);
 		if (ret)
 			break;
@@ -1843,9 +1706,6 @@
 	{
 		struct v4l2_tuner *p = arg;
 
-		if (!ops->vidioc_g_tuner)
-			break;
-
 		p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
 			V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 		ret = ops->vidioc_g_tuner(file, fh, p);
@@ -1864,12 +1724,6 @@
 	{
 		struct v4l2_tuner *p = arg;
 
-		if (!ops->vidioc_s_tuner)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
 			V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 		dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1887,9 +1741,6 @@
 	{
 		struct v4l2_frequency *p = arg;
 
-		if (!ops->vidioc_g_frequency)
-			break;
-
 		p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
 			V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 		ret = ops->vidioc_g_frequency(file, fh, p);
@@ -1903,12 +1754,6 @@
 		struct v4l2_frequency *p = arg;
 		enum v4l2_tuner_type type;
 
-		if (!ops->vidioc_s_frequency)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
 			V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 		dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1923,9 +1768,6 @@
 	{
 		struct v4l2_sliced_vbi_cap *p = arg;
 
-		if (!ops->vidioc_g_sliced_vbi_cap)
-			break;
-
 		/* Clear up to type, everything after type is zerod already */
 		memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
 
@@ -1937,8 +1779,6 @@
 	}
 	case VIDIOC_LOG_STATUS:
 	{
-		if (!ops->vidioc_log_status)
-			break;
 		if (vfd->v4l2_dev)
 			pr_info("%s: =================  START STATUS  =================\n",
 				vfd->v4l2_dev->name);
@@ -1948,38 +1788,34 @@
 				vfd->v4l2_dev->name);
 		break;
 	}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
 	case VIDIOC_DBG_G_REGISTER:
 	{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
 		struct v4l2_dbg_register *p = arg;
 
-		if (ops->vidioc_g_register) {
-			if (!capable(CAP_SYS_ADMIN))
-				ret = -EPERM;
-			else
-				ret = ops->vidioc_g_register(file, fh, p);
-		}
+		if (!capable(CAP_SYS_ADMIN))
+			ret = -EPERM;
+		else
+			ret = ops->vidioc_g_register(file, fh, p);
+#endif
 		break;
 	}
 	case VIDIOC_DBG_S_REGISTER:
 	{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
 		struct v4l2_dbg_register *p = arg;
 
-		if (ops->vidioc_s_register) {
-			if (!capable(CAP_SYS_ADMIN))
-				ret = -EPERM;
-			else
-				ret = ops->vidioc_s_register(file, fh, p);
-		}
+		if (!capable(CAP_SYS_ADMIN))
+			ret = -EPERM;
+		else
+			ret = ops->vidioc_s_register(file, fh, p);
+#endif
 		break;
 	}
-#endif
 	case VIDIOC_DBG_G_CHIP_IDENT:
 	{
 		struct v4l2_dbg_chip_ident *p = arg;
 
-		if (!ops->vidioc_g_chip_ident)
-			break;
 		p->ident = V4L2_IDENT_NONE;
 		p->revision = 0;
 		ret = ops->vidioc_g_chip_ident(file, fh, p);
@@ -1992,12 +1828,6 @@
 		struct v4l2_hw_freq_seek *p = arg;
 		enum v4l2_tuner_type type;
 
-		if (!ops->vidioc_s_hw_freq_seek)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
 			V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 		dbgarg(cmd,
@@ -2013,9 +1843,6 @@
 	{
 		struct v4l2_frmsizeenum *p = arg;
 
-		if (!ops->vidioc_enum_framesizes)
-			break;
-
 		ret = ops->vidioc_enum_framesizes(file, fh, p);
 		dbgarg(cmd,
 			"index=%d, pixelformat=%c%c%c%c, type=%d ",
@@ -2049,9 +1876,6 @@
 	{
 		struct v4l2_frmivalenum *p = arg;
 
-		if (!ops->vidioc_enum_frameintervals)
-			break;
-
 		ret = ops->vidioc_enum_frameintervals(file, fh, p);
 		dbgarg(cmd,
 			"index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
@@ -2084,9 +1908,6 @@
 	{
 		struct v4l2_dv_enum_preset *p = arg;
 
-		if (!ops->vidioc_enum_dv_presets)
-			break;
-
 		ret = ops->vidioc_enum_dv_presets(file, fh, p);
 		if (!ret)
 			dbgarg(cmd,
@@ -2100,13 +1921,6 @@
 	{
 		struct v4l2_dv_preset *p = arg;
 
-		if (!ops->vidioc_s_dv_preset)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
-
 		dbgarg(cmd, "preset=%d\n", p->preset);
 		ret = ops->vidioc_s_dv_preset(file, fh, p);
 		break;
@@ -2115,9 +1929,6 @@
 	{
 		struct v4l2_dv_preset *p = arg;
 
-		if (!ops->vidioc_g_dv_preset)
-			break;
-
 		ret = ops->vidioc_g_dv_preset(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "preset=%d\n", p->preset);
@@ -2127,9 +1938,6 @@
 	{
 		struct v4l2_dv_preset *p = arg;
 
-		if (!ops->vidioc_query_dv_preset)
-			break;
-
 		ret = ops->vidioc_query_dv_preset(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "preset=%d\n", p->preset);
@@ -2139,32 +1947,13 @@
 	{
 		struct v4l2_dv_timings *p = arg;
 
-		if (!ops->vidioc_s_dv_timings)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
-
+		dbgtimings(vfd, p);
 		switch (p->type) {
 		case V4L2_DV_BT_656_1120:
-			dbgarg2("bt-656/1120:interlaced=%d, pixelclock=%lld,"
-				" width=%d, height=%d, polarities=%x,"
-				" hfrontporch=%d, hsync=%d, hbackporch=%d,"
-				" vfrontporch=%d, vsync=%d, vbackporch=%d,"
-				" il_vfrontporch=%d, il_vsync=%d,"
-				" il_vbackporch=%d\n",
-				p->bt.interlaced, p->bt.pixelclock,
-				p->bt.width, p->bt.height, p->bt.polarities,
-				p->bt.hfrontporch, p->bt.hsync,
-				p->bt.hbackporch, p->bt.vfrontporch,
-				p->bt.vsync, p->bt.vbackporch,
-				p->bt.il_vfrontporch, p->bt.il_vsync,
-				p->bt.il_vbackporch);
 			ret = ops->vidioc_s_dv_timings(file, fh, p);
 			break;
 		default:
-			dbgarg2("Unknown type %d!\n", p->type);
+			ret = -EINVAL;
 			break;
 		}
 		break;
@@ -2173,33 +1962,61 @@
 	{
 		struct v4l2_dv_timings *p = arg;
 
-		if (!ops->vidioc_g_dv_timings)
+		ret = ops->vidioc_g_dv_timings(file, fh, p);
+		if (!ret)
+			dbgtimings(vfd, p);
+		break;
+	}
+	case VIDIOC_ENUM_DV_TIMINGS:
+	{
+		struct v4l2_enum_dv_timings *p = arg;
+
+		if (!ops->vidioc_enum_dv_timings)
 			break;
 
-		ret = ops->vidioc_g_dv_timings(file, fh, p);
+		ret = ops->vidioc_enum_dv_timings(file, fh, p);
 		if (!ret) {
-			switch (p->type) {
-			case V4L2_DV_BT_656_1120:
-				dbgarg2("bt-656/1120:interlaced=%d,"
-					" pixelclock=%lld,"
-					" width=%d, height=%d, polarities=%x,"
-					" hfrontporch=%d, hsync=%d,"
-					" hbackporch=%d, vfrontporch=%d,"
-					" vsync=%d, vbackporch=%d,"
-					" il_vfrontporch=%d, il_vsync=%d,"
-					" il_vbackporch=%d\n",
-					p->bt.interlaced, p->bt.pixelclock,
-					p->bt.width, p->bt.height,
-					p->bt.polarities, p->bt.hfrontporch,
-					p->bt.hsync, p->bt.hbackporch,
-					p->bt.vfrontporch, p->bt.vsync,
-					p->bt.vbackporch, p->bt.il_vfrontporch,
-					p->bt.il_vsync, p->bt.il_vbackporch);
-				break;
-			default:
-				dbgarg2("Unknown type %d!\n", p->type);
-				break;
-			}
+			dbgarg(cmd, "index=%d: ", p->index);
+			dbgtimings(vfd, &p->timings);
+		}
+		break;
+	}
+	case VIDIOC_QUERY_DV_TIMINGS:
+	{
+		struct v4l2_dv_timings *p = arg;
+
+		if (!ops->vidioc_query_dv_timings)
+			break;
+
+		ret = ops->vidioc_query_dv_timings(file, fh, p);
+		if (!ret)
+			dbgtimings(vfd, p);
+		break;
+	}
+	case VIDIOC_DV_TIMINGS_CAP:
+	{
+		struct v4l2_dv_timings_cap *p = arg;
+
+		if (!ops->vidioc_dv_timings_cap)
+			break;
+
+		ret = ops->vidioc_dv_timings_cap(file, fh, p);
+		if (ret)
+			break;
+		switch (p->type) {
+		case V4L2_DV_BT_656_1120:
+			dbgarg(cmd,
+			       "type=%d, width=%u-%u, height=%u-%u, "
+			       "pixelclock=%llu-%llu, standards=%x, capabilities=%x ",
+			       p->type,
+			       p->bt.min_width, p->bt.max_width,
+			       p->bt.min_height, p->bt.max_height,
+			       p->bt.min_pixelclock, p->bt.max_pixelclock,
+			       p->bt.standards, p->bt.capabilities);
+			break;
+		default:
+			dbgarg(cmd, "unknown type ");
+			break;
 		}
 		break;
 	}
@@ -2207,9 +2024,6 @@
 	{
 		struct v4l2_event *ev = arg;
 
-		if (!ops->vidioc_subscribe_event)
-			break;
-
 		ret = v4l2_event_dequeue(fh, ev, file->f_flags & O_NONBLOCK);
 		if (ret < 0) {
 			dbgarg(cmd, "no pending events?");
@@ -2226,9 +2040,6 @@
 	{
 		struct v4l2_event_subscription *sub = arg;
 
-		if (!ops->vidioc_subscribe_event)
-			break;
-
 		ret = ops->vidioc_subscribe_event(fh, sub);
 		if (ret < 0) {
 			dbgarg(cmd, "failed, ret=%ld", ret);
@@ -2241,9 +2052,6 @@
 	{
 		struct v4l2_event_subscription *sub = arg;
 
-		if (!ops->vidioc_unsubscribe_event)
-			break;
-
 		ret = ops->vidioc_unsubscribe_event(fh, sub);
 		if (ret < 0) {
 			dbgarg(cmd, "failed, ret=%ld", ret);
@@ -2256,12 +2064,6 @@
 	{
 		struct v4l2_create_buffers *create = arg;
 
-		if (!ops->vidioc_create_bufs)
-			break;
-		if (ret_prio) {
-			ret = ret_prio;
-			break;
-		}
 		ret = check_fmt(ops, create->format.type);
 		if (ret)
 			break;
@@ -2275,8 +2077,6 @@
 	{
 		struct v4l2_buffer *b = arg;
 
-		if (!ops->vidioc_prepare_buf)
-			break;
 		ret = check_fmt(ops, b->type);
 		if (ret)
 			break;
@@ -2289,7 +2089,9 @@
 	default:
 		if (!ops->vidioc_default)
 			break;
-		ret = ops->vidioc_default(file, fh, ret_prio >= 0, cmd, arg);
+		ret = ops->vidioc_default(file, fh, use_fh_prio ?
+				v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0,
+				cmd, arg);
 		break;
 	} /* switch */
 
@@ -2463,7 +2265,9 @@
 			err = -EFAULT;
 		goto out_array_args;
 	}
-	if (err < 0)
+	/* VIDIOC_QUERY_DV_TIMINGS can return an error, but still have valid
+	   results that must be returned. */
+	if (err < 0 && cmd != VIDIOC_QUERY_DV_TIMINGS)
 		goto out;
 
 out_array_args:
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 6fe88e9..db6e859 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -35,14 +35,9 @@
 static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
 {
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-	/* Allocate try format and crop in the same memory block */
-	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
-			      * sd->entity.num_pads, GFP_KERNEL);
-	if (fh->try_fmt == NULL)
+	fh->pad = kzalloc(sizeof(*fh->pad) * sd->entity.num_pads, GFP_KERNEL);
+	if (fh->pad == NULL)
 		return -ENOMEM;
-
-	fh->try_crop = (struct v4l2_rect *)
-		(fh->try_fmt + sd->entity.num_pads);
 #endif
 	return 0;
 }
@@ -50,9 +45,8 @@
 static void subdev_fh_free(struct v4l2_subdev_fh *fh)
 {
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-	kfree(fh->try_fmt);
-	fh->try_fmt = NULL;
-	fh->try_crop = NULL;
+	kfree(fh->pad);
+	fh->pad = NULL;
 #endif
 }
 
@@ -234,6 +228,8 @@
 
 	case VIDIOC_SUBDEV_G_CROP: {
 		struct v4l2_subdev_crop *crop = arg;
+		struct v4l2_subdev_selection sel;
+		int rval;
 
 		if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
 		    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -242,11 +238,27 @@
 		if (crop->pad >= sd->entity.num_pads)
 			return -EINVAL;
 
-		return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
+		rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
+		if (rval != -ENOIOCTLCMD)
+			return rval;
+
+		memset(&sel, 0, sizeof(sel));
+		sel.which = crop->which;
+		sel.pad = crop->pad;
+		sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL;
+
+		rval = v4l2_subdev_call(
+			sd, pad, get_selection, subdev_fh, &sel);
+
+		crop->rect = sel.r;
+
+		return rval;
 	}
 
 	case VIDIOC_SUBDEV_S_CROP: {
 		struct v4l2_subdev_crop *crop = arg;
+		struct v4l2_subdev_selection sel;
+		int rval;
 
 		if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
 		    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -255,7 +267,22 @@
 		if (crop->pad >= sd->entity.num_pads)
 			return -EINVAL;
 
-		return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
+		rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
+		if (rval != -ENOIOCTLCMD)
+			return rval;
+
+		memset(&sel, 0, sizeof(sel));
+		sel.which = crop->which;
+		sel.pad = crop->pad;
+		sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL;
+		sel.r = crop->rect;
+
+		rval = v4l2_subdev_call(
+			sd, pad, set_selection, subdev_fh, &sel);
+
+		crop->rect = sel.r;
+
+		return rval;
 	}
 
 	case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
@@ -293,6 +320,34 @@
 		return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh,
 					fie);
 	}
+
+	case VIDIOC_SUBDEV_G_SELECTION: {
+		struct v4l2_subdev_selection *sel = arg;
+
+		if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
+		    sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+			return -EINVAL;
+
+		if (sel->pad >= sd->entity.num_pads)
+			return -EINVAL;
+
+		return v4l2_subdev_call(
+			sd, pad, get_selection, subdev_fh, sel);
+	}
+
+	case VIDIOC_SUBDEV_S_SELECTION: {
+		struct v4l2_subdev_selection *sel = arg;
+
+		if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
+		    sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+			return -EINVAL;
+
+		if (sel->pad >= sd->entity.num_pads)
+			return -EINVAL;
+
+		return v4l2_subdev_call(
+			sd, pad, set_selection, subdev_fh, sel);
+	}
 #endif
 	default:
 		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
@@ -332,6 +387,70 @@
 	.poll = subdev_poll,
 };
 
+#ifdef CONFIG_MEDIA_CONTROLLER
+int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
+				      struct media_link *link,
+				      struct v4l2_subdev_format *source_fmt,
+				      struct v4l2_subdev_format *sink_fmt)
+{
+	if (source_fmt->format.width != sink_fmt->format.width
+	    || source_fmt->format.height != sink_fmt->format.height
+	    || source_fmt->format.code != sink_fmt->format.code)
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
+
+static int
+v4l2_subdev_link_validate_get_format(struct media_pad *pad,
+				     struct v4l2_subdev_format *fmt)
+{
+	switch (media_entity_type(pad->entity)) {
+	case MEDIA_ENT_T_V4L2_SUBDEV:
+		fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		fmt->pad = pad->index;
+		return v4l2_subdev_call(media_entity_to_v4l2_subdev(
+						pad->entity),
+					pad, get_fmt, NULL, fmt);
+	default:
+		WARN(1, "Driver bug! Wrong media entity type %d, entity %s\n",
+		     media_entity_type(pad->entity), pad->entity->name);
+		/* Fall through */
+	case MEDIA_ENT_T_DEVNODE_V4L:
+		return -EINVAL;
+	}
+}
+
+int v4l2_subdev_link_validate(struct media_link *link)
+{
+	struct v4l2_subdev *sink;
+	struct v4l2_subdev_format sink_fmt, source_fmt;
+	int rval;
+
+	rval = v4l2_subdev_link_validate_get_format(
+		link->source, &source_fmt);
+	if (rval < 0)
+		return 0;
+
+	rval = v4l2_subdev_link_validate_get_format(
+		link->sink, &sink_fmt);
+	if (rval < 0)
+		return 0;
+
+	sink = media_entity_to_v4l2_subdev(link->sink->entity);
+
+	rval = v4l2_subdev_call(sink, pad, link_validate, link,
+				&source_fmt, &sink_fmt);
+	if (rval != -ENOIOCTLCMD)
+		return rval;
+
+	return v4l2_subdev_link_validate_default(
+		sink, link, &source_fmt, &sink_fmt);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
+#endif /* CONFIG_MEDIA_CONTROLLER */
+
 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
 {
 	INIT_LIST_HEAD(&sd->list);
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 20f7237..308e150 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -18,6 +18,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/ov7670.h>
 #include <media/videobuf-dma-sg.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
@@ -1347,11 +1348,21 @@
 	return false;
 }
 
+static struct ov7670_config sensor_cfg = {
+	/* The XO-1.5 (only known user) clocks the camera at 90MHz. */
+	.clock_speed = 90,
+};
+
 static __devinit int viacam_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct i2c_adapter *sensor_adapter;
 	struct viafb_dev *viadev = pdev->dev.platform_data;
+	struct i2c_board_info ov7670_info = {
+		.type = "ov7670",
+		.addr = 0x42 >> 1,
+		.platform_data = &sensor_cfg,
+	};
 
 	/*
 	 * Note that there are actually two capture channels on
@@ -1433,8 +1444,8 @@
 	 * is OLPC-specific.  0x42 assumption is ov7670-specific.
 	 */
 	sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
-	cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter,
-			"ov7670", 0x42 >> 1, NULL);
+	cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, sensor_adapter,
+			&ov7670_info, NULL);
 	if (cam->sensor == NULL) {
 		dev_err(&pdev->dev, "Unable to find the sensor!\n");
 		ret = -ENODEV;
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index de4fa4e..ffdf59c 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -1129,6 +1129,7 @@
 				  struct videobuf_queue *q,
 				  poll_table *wait)
 {
+	unsigned long req_events = poll_requested_events(wait);
 	struct videobuf_buffer *buf = NULL;
 	unsigned int rc = 0;
 
@@ -1137,7 +1138,7 @@
 		if (!list_empty(&q->stream))
 			buf = list_entry(q->stream.next,
 					 struct videobuf_buffer, stream);
-	} else {
+	} else if (req_events & (POLLIN | POLLRDNORM)) {
 		if (!q->reading)
 			__videobuf_read_start(q);
 		if (!q->reading) {
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index c969111..b6b5cc1 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -27,6 +27,7 @@
 	u32 magic;
 	void *vaddr;
 	dma_addr_t dma_handle;
+	bool cached;
 	unsigned long size;
 };
 
@@ -37,8 +38,58 @@
 		BUG();							    \
 	}
 
-static void
-videobuf_vm_open(struct vm_area_struct *vma)
+static int __videobuf_dc_alloc(struct device *dev,
+			       struct videobuf_dma_contig_memory *mem,
+			       unsigned long size, unsigned long flags)
+{
+	mem->size = size;
+	if (mem->cached) {
+		mem->vaddr = alloc_pages_exact(mem->size, flags | GFP_DMA);
+		if (mem->vaddr) {
+			int err;
+
+			mem->dma_handle = dma_map_single(dev, mem->vaddr,
+							 mem->size,
+							 DMA_FROM_DEVICE);
+			err = dma_mapping_error(dev, mem->dma_handle);
+			if (err) {
+				dev_err(dev, "dma_map_single failed\n");
+
+				free_pages_exact(mem->vaddr, mem->size);
+				mem->vaddr = 0;
+				return err;
+			}
+		}
+	} else
+		mem->vaddr = dma_alloc_coherent(dev, mem->size,
+						&mem->dma_handle, flags);
+
+	if (!mem->vaddr) {
+		dev_err(dev, "memory alloc size %ld failed\n", mem->size);
+		return -ENOMEM;
+	}
+
+	dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
+
+	return 0;
+}
+
+static void __videobuf_dc_free(struct device *dev,
+			       struct videobuf_dma_contig_memory *mem)
+{
+	if (mem->cached) {
+		if (!mem->vaddr)
+			return;
+		dma_unmap_single(dev, mem->dma_handle, mem->size,
+				 DMA_FROM_DEVICE);
+		free_pages_exact(mem->vaddr, mem->size);
+	} else
+		dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
+
+	mem->vaddr = NULL;
+}
+
+static void videobuf_vm_open(struct vm_area_struct *vma)
 {
 	struct videobuf_mapping *map = vma->vm_private_data;
 
@@ -91,12 +142,11 @@
 				dev_dbg(q->dev, "buf[%d] freeing %p\n",
 					i, mem->vaddr);
 
-				dma_free_coherent(q->dev, mem->size,
-						  mem->vaddr, mem->dma_handle);
+				__videobuf_dc_free(q->dev, mem);
 				mem->vaddr = NULL;
 			}
 
-			q->bufs[i]->map   = NULL;
+			q->bufs[i]->map = NULL;
 			q->bufs[i]->baddr = 0;
 		}
 
@@ -107,8 +157,8 @@
 }
 
 static const struct vm_operations_struct videobuf_vm_ops = {
-	.open     = videobuf_vm_open,
-	.close    = videobuf_vm_close,
+	.open	= videobuf_vm_open,
+	.close	= videobuf_vm_close,
 };
 
 /**
@@ -178,26 +228,38 @@
 		pages_done++;
 	}
 
- out_up:
+out_up:
 	up_read(&current->mm->mmap_sem);
 
 	return ret;
 }
 
-static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached)
 {
 	struct videobuf_dma_contig_memory *mem;
 	struct videobuf_buffer *vb;
 
 	vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
 	if (vb) {
-		mem = vb->priv = ((char *)vb) + size;
+		vb->priv = ((char *)vb) + size;
+		mem = vb->priv;
 		mem->magic = MAGIC_DC_MEM;
+		mem->cached = cached;
 	}
 
 	return vb;
 }
 
+static struct videobuf_buffer *__videobuf_alloc_uncached(size_t size)
+{
+	return __videobuf_alloc_vb(size, false);
+}
+
+static struct videobuf_buffer *__videobuf_alloc_cached(size_t size)
+{
+	return __videobuf_alloc_vb(size, true);
+}
+
 static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
 {
 	struct videobuf_dma_contig_memory *mem = buf->priv;
@@ -235,28 +297,32 @@
 			return videobuf_dma_contig_user_get(mem, vb);
 
 		/* allocate memory for the read() method */
-		mem->size = PAGE_ALIGN(vb->size);
-		mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
-						&mem->dma_handle, GFP_KERNEL);
-		if (!mem->vaddr) {
-			dev_err(q->dev, "dma_alloc_coherent %ld failed\n",
-					 mem->size);
+		if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
+					GFP_KERNEL))
 			return -ENOMEM;
-		}
-
-		dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n",
-			mem->vaddr, mem->size);
 		break;
 	case V4L2_MEMORY_OVERLAY:
 	default:
-		dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n",
-			__func__);
+		dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
+static int __videobuf_sync(struct videobuf_queue *q,
+			   struct videobuf_buffer *buf)
+{
+	struct videobuf_dma_contig_memory *mem = buf->priv;
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+	dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size,
+				DMA_FROM_DEVICE);
+
+	return 0;
+}
+
 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 				  struct videobuf_buffer *buf,
 				  struct vm_area_struct *vma)
@@ -265,6 +331,8 @@
 	struct videobuf_mapping *map;
 	int retval;
 	unsigned long size;
+	unsigned long pos, start = vma->vm_start;
+	struct page *page;
 
 	dev_dbg(q->dev, "%s\n", __func__);
 
@@ -282,41 +350,50 @@
 	BUG_ON(!mem);
 	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 
-	mem->size = PAGE_ALIGN(buf->bsize);
-	mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
-					&mem->dma_handle, GFP_KERNEL);
-	if (!mem->vaddr) {
-		dev_err(q->dev, "dma_alloc_coherent size %ld failed\n",
-			mem->size);
+	if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
+				GFP_KERNEL | __GFP_COMP))
 		goto error;
-	}
-	dev_dbg(q->dev, "dma_alloc_coherent data is at addr %p (size %ld)\n",
-		mem->vaddr, mem->size);
 
 	/* Try to remap memory */
 
 	size = vma->vm_end - vma->vm_start;
 	size = (size < mem->size) ? size : mem->size;
 
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	retval = remap_pfn_range(vma, vma->vm_start,
-				 mem->dma_handle >> PAGE_SHIFT,
-				 size, vma->vm_page_prot);
-	if (retval) {
-		dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
-		dma_free_coherent(q->dev, mem->size,
-				  mem->vaddr, mem->dma_handle);
-		goto error;
+	if (!mem->cached)
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	pos = (unsigned long)mem->vaddr;
+
+	while (size > 0) {
+		page = virt_to_page((void *)pos);
+		if (NULL == page) {
+			dev_err(q->dev, "mmap: virt_to_page failed\n");
+			__videobuf_dc_free(q->dev, mem);
+			goto error;
+		}
+		retval = vm_insert_page(vma, start, page);
+		if (retval) {
+			dev_err(q->dev, "mmap: insert failed with error %d\n",
+				retval);
+			__videobuf_dc_free(q->dev, mem);
+			goto error;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
 	}
 
-	vma->vm_ops          = &videobuf_vm_ops;
-	vma->vm_flags       |= VM_DONTEXPAND;
+	vma->vm_ops = &videobuf_vm_ops;
+	vma->vm_flags |= VM_DONTEXPAND;
 	vma->vm_private_data = map;
 
 	dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
 		map, q, vma->vm_start, vma->vm_end,
-		(long int)buf->bsize,
-		vma->vm_pgoff, buf->i);
+		(long int)buf->bsize, vma->vm_pgoff, buf->i);
 
 	videobuf_vm_open(vma);
 
@@ -328,12 +405,20 @@
 }
 
 static struct videobuf_qtype_ops qops = {
-	.magic        = MAGIC_QTYPE_OPS,
+	.magic		= MAGIC_QTYPE_OPS,
+	.alloc_vb	= __videobuf_alloc_uncached,
+	.iolock		= __videobuf_iolock,
+	.mmap_mapper	= __videobuf_mmap_mapper,
+	.vaddr		= __videobuf_to_vaddr,
+};
 
-	.alloc_vb     = __videobuf_alloc_vb,
-	.iolock       = __videobuf_iolock,
-	.mmap_mapper  = __videobuf_mmap_mapper,
-	.vaddr        = __videobuf_to_vaddr,
+static struct videobuf_qtype_ops qops_cached = {
+	.magic		= MAGIC_QTYPE_OPS,
+	.alloc_vb	= __videobuf_alloc_cached,
+	.iolock		= __videobuf_iolock,
+	.sync		= __videobuf_sync,
+	.mmap_mapper	= __videobuf_mmap_mapper,
+	.vaddr		= __videobuf_to_vaddr,
 };
 
 void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
@@ -351,6 +436,20 @@
 }
 EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
 
+void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q,
+					   const struct videobuf_queue_ops *ops,
+					   struct device *dev,
+					   spinlock_t *irqlock,
+					   enum v4l2_buf_type type,
+					   enum v4l2_field field,
+					   unsigned int msize,
+					   void *priv, struct mutex *ext_lock)
+{
+	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+				 priv, &qops_cached, ext_lock);
+}
+EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init_cached);
+
 dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
 {
 	struct videobuf_dma_contig_memory *mem = buf->priv;
@@ -389,7 +488,7 @@
 
 	/* read() method */
 	if (mem->vaddr) {
-		dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
+		__videobuf_dc_free(q->dev, mem);
 		mem->vaddr = NULL;
 	}
 }
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index 59cb54a..94d83a4 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -45,7 +45,6 @@
 	struct videobuf_dvb *dvb = data;
 	struct videobuf_buffer *buf;
 	unsigned long flags;
-	int err;
 	void *outp;
 
 	dprintk("dvb thread started\n");
@@ -57,7 +56,7 @@
 		buf = list_entry(dvb->dvbq.stream.next,
 				 struct videobuf_buffer, stream);
 		list_del(&buf->stream);
-		err = videobuf_waiton(&dvb->dvbq, buf, 0, 1);
+		videobuf_waiton(&dvb->dvbq, buf, 0, 1);
 
 		/* no more feeds left or stop_feed() asked us to quit */
 		if (0 == dvb->nfeeds)
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 2e8f1df..9d4e9ed 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -19,6 +19,9 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
 #include <media/videobuf2-core.h>
 
 static int debug;
@@ -1642,32 +1645,46 @@
  * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
  * will be reported as available for writing.
  *
+ * If the driver uses struct v4l2_fh, then vb2_poll() will also check for any
+ * pending events.
+ *
  * The return values from this function are intended to be directly returned
  * from poll handler in driver.
  */
 unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
 {
-	unsigned long flags;
-	unsigned int ret;
+	struct video_device *vfd = video_devdata(file);
+	unsigned long req_events = poll_requested_events(wait);
 	struct vb2_buffer *vb = NULL;
+	unsigned int res = 0;
+	unsigned long flags;
+
+	if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
+		struct v4l2_fh *fh = file->private_data;
+
+		if (v4l2_event_pending(fh))
+			res = POLLPRI;
+		else if (req_events & POLLPRI)
+			poll_wait(file, &fh->wait, wait);
+	}
 
 	/*
 	 * Start file I/O emulator only if streaming API has not been used yet.
 	 */
 	if (q->num_buffers == 0 && q->fileio == NULL) {
-		if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ)) {
-			ret = __vb2_init_fileio(q, 1);
-			if (ret)
-				return POLLERR;
+		if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
+				(req_events & (POLLIN | POLLRDNORM))) {
+			if (__vb2_init_fileio(q, 1))
+				return res | POLLERR;
 		}
-		if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE)) {
-			ret = __vb2_init_fileio(q, 0);
-			if (ret)
-				return POLLERR;
+		if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) &&
+				(req_events & (POLLOUT | POLLWRNORM))) {
+			if (__vb2_init_fileio(q, 0))
+				return res | POLLERR;
 			/*
 			 * Write to OUTPUT queue can be done immediately.
 			 */
-			return POLLOUT | POLLWRNORM;
+			return res | POLLOUT | POLLWRNORM;
 		}
 	}
 
@@ -1675,7 +1692,7 @@
 	 * There is nothing to wait for if no buffers have already been queued.
 	 */
 	if (list_empty(&q->queued_list))
-		return POLLERR;
+		return res | POLLERR;
 
 	poll_wait(file, &q->done_wq, wait);
 
@@ -1690,10 +1707,11 @@
 
 	if (vb && (vb->state == VB2_BUF_STATE_DONE
 			|| vb->state == VB2_BUF_STATE_ERROR)) {
-		return (V4L2_TYPE_IS_OUTPUT(q->type)) ? POLLOUT | POLLWRNORM :
-			POLLIN | POLLRDNORM;
+		return (V4L2_TYPE_IS_OUTPUT(q->type)) ?
+				res | POLLOUT | POLLWRNORM :
+				res | POLLIN | POLLRDNORM;
 	}
-	return 0;
+	return res;
 }
 EXPORT_SYMBOL_GPL(vb2_poll);
 
@@ -1839,7 +1857,6 @@
 	 * (multiplane buffers are not supported).
 	 */
 	if (q->bufs[0]->num_planes != 1) {
-		fileio->req.count = 0;
 		ret = -EBUSY;
 		goto err_reqbufs;
 	}
@@ -1886,6 +1903,7 @@
 	return ret;
 
 err_reqbufs:
+	fileio->req.count = 0;
 	vb2_reqbufs(q, &fileio->req);
 
 err_kfree:
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 5e8b071..0960d7f 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -95,6 +95,16 @@
 		.depth    = 16,
 	},
 	{
+		.name     = "4:2:2, packed, YVYU",
+		.fourcc   = V4L2_PIX_FMT_YVYU,
+		.depth    = 16,
+	},
+	{
+		.name     = "4:2:2, packed, VYUY",
+		.fourcc   = V4L2_PIX_FMT_VYUY,
+		.depth    = 16,
+	},
+	{
 		.name     = "RGB565 (LE)",
 		.fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
 		.depth    = 16,
@@ -114,6 +124,26 @@
 		.fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
 		.depth    = 16,
 	},
+	{
+		.name     = "RGB24 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB24, /* rgb */
+		.depth    = 24,
+	},
+	{
+		.name     = "RGB24 (BE)",
+		.fourcc   = V4L2_PIX_FMT_BGR24, /* bgr */
+		.depth    = 24,
+	},
+	{
+		.name     = "RGB32 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB32, /* argb */
+		.depth    = 32,
+	},
+	{
+		.name     = "RGB32 (BE)",
+		.fourcc   = V4L2_PIX_FMT_BGR32, /* bgra */
+		.depth    = 32,
+	},
 };
 
 static struct vivi_fmt *get_format(struct v4l2_format *f)
@@ -170,6 +200,7 @@
 		struct v4l2_ctrl	   *gain;
 	};
 	struct v4l2_ctrl	   *volume;
+	struct v4l2_ctrl	   *alpha;
 	struct v4l2_ctrl	   *button;
 	struct v4l2_ctrl	   *boolean;
 	struct v4l2_ctrl	   *int32;
@@ -177,6 +208,7 @@
 	struct v4l2_ctrl	   *menu;
 	struct v4l2_ctrl	   *string;
 	struct v4l2_ctrl	   *bitmask;
+	struct v4l2_ctrl	   *int_menu;
 
 	spinlock_t                 slock;
 	struct mutex		   mutex;
@@ -203,8 +235,10 @@
 	enum v4l2_field		   field;
 	unsigned int		   field_count;
 
-	u8 			   bars[9][3];
-	u8 			   line[MAX_WIDTH * 4];
+	u8			   bars[9][3];
+	u8			   line[MAX_WIDTH * 8];
+	unsigned int		   pixelsize;
+	u8			   alpha_component;
 };
 
 /* ------------------------------------------------------------------
@@ -283,6 +317,8 @@
 		switch (dev->fmt->fourcc) {
 		case V4L2_PIX_FMT_YUYV:
 		case V4L2_PIX_FMT_UYVY:
+		case V4L2_PIX_FMT_YVYU:
+		case V4L2_PIX_FMT_VYUY:
 			is_yuv = 1;
 			break;
 		case V4L2_PIX_FMT_RGB565:
@@ -297,6 +333,11 @@
 			g >>= 3;
 			b >>= 3;
 			break;
+		case V4L2_PIX_FMT_RGB24:
+		case V4L2_PIX_FMT_BGR24:
+		case V4L2_PIX_FMT_RGB32:
+		case V4L2_PIX_FMT_BGR32:
+			break;
 		}
 
 		if (is_yuv) {
@@ -316,9 +357,11 @@
 #define TSTAMP_INPUT_X	10
 #define TSTAMP_MIN_X	(54 + TSTAMP_INPUT_X)
 
-static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos)
+/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
+static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
 {
 	u8 r_y, g_u, b_v;
+	u8 alpha = dev->alpha_component;
 	int color;
 	u8 *p;
 
@@ -326,46 +369,56 @@
 	g_u = dev->bars[colorpos][1]; /* G or precalculated U */
 	b_v = dev->bars[colorpos][2]; /* B or precalculated V */
 
-	for (color = 0; color < 4; color++) {
+	for (color = 0; color < dev->pixelsize; color++) {
 		p = buf + color;
 
 		switch (dev->fmt->fourcc) {
 		case V4L2_PIX_FMT_YUYV:
 			switch (color) {
 			case 0:
-			case 2:
 				*p = r_y;
 				break;
 			case 1:
-				*p = g_u;
-				break;
-			case 3:
-				*p = b_v;
+				*p = odd ? b_v : g_u;
 				break;
 			}
 			break;
 		case V4L2_PIX_FMT_UYVY:
 			switch (color) {
+			case 0:
+				*p = odd ? b_v : g_u;
+				break;
 			case 1:
-			case 3:
 				*p = r_y;
 				break;
+			}
+			break;
+		case V4L2_PIX_FMT_YVYU:
+			switch (color) {
 			case 0:
-				*p = g_u;
+				*p = r_y;
 				break;
-			case 2:
-				*p = b_v;
+			case 1:
+				*p = odd ? g_u : b_v;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_VYUY:
+			switch (color) {
+			case 0:
+				*p = odd ? g_u : b_v;
+				break;
+			case 1:
+				*p = r_y;
 				break;
 			}
 			break;
 		case V4L2_PIX_FMT_RGB565:
 			switch (color) {
 			case 0:
-			case 2:
 				*p = (g_u << 5) | b_v;
 				break;
 			case 1:
-			case 3:
 				*p = (r_y << 3) | (g_u >> 3);
 				break;
 			}
@@ -373,11 +426,9 @@
 		case V4L2_PIX_FMT_RGB565X:
 			switch (color) {
 			case 0:
-			case 2:
 				*p = (r_y << 3) | (g_u >> 3);
 				break;
 			case 1:
-			case 3:
 				*p = (g_u << 5) | b_v;
 				break;
 			}
@@ -385,27 +436,81 @@
 		case V4L2_PIX_FMT_RGB555:
 			switch (color) {
 			case 0:
-			case 2:
 				*p = (g_u << 5) | b_v;
 				break;
 			case 1:
-			case 3:
-				*p = (r_y << 2) | (g_u >> 3);
+				*p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
 				break;
 			}
 			break;
 		case V4L2_PIX_FMT_RGB555X:
 			switch (color) {
 			case 0:
-			case 2:
-				*p = (r_y << 2) | (g_u >> 3);
+				*p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
 				break;
 			case 1:
-			case 3:
 				*p = (g_u << 5) | b_v;
 				break;
 			}
 			break;
+		case V4L2_PIX_FMT_RGB24:
+			switch (color) {
+			case 0:
+				*p = r_y;
+				break;
+			case 1:
+				*p = g_u;
+				break;
+			case 2:
+				*p = b_v;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_BGR24:
+			switch (color) {
+			case 0:
+				*p = b_v;
+				break;
+			case 1:
+				*p = g_u;
+				break;
+			case 2:
+				*p = r_y;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_RGB32:
+			switch (color) {
+			case 0:
+				*p = alpha;
+				break;
+			case 1:
+				*p = r_y;
+				break;
+			case 2:
+				*p = g_u;
+				break;
+			case 3:
+				*p = b_v;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_BGR32:
+			switch (color) {
+			case 0:
+				*p = b_v;
+				break;
+			case 1:
+				*p = g_u;
+				break;
+			case 2:
+				*p = r_y;
+				break;
+			case 3:
+				*p = alpha;
+				break;
+			}
+			break;
 		}
 	}
 }
@@ -414,10 +519,10 @@
 {
 	int w;
 
-	for (w = 0; w < dev->width * 2; w += 2) {
-		int colorpos = (w / (dev->width / 8) % 8);
+	for (w = 0; w < dev->width * 2; w++) {
+		int colorpos = w / (dev->width / 8) % 8;
 
-		gen_twopix(dev, dev->line + w * 2, colorpos);
+		gen_twopix(dev, dev->line + w * dev->pixelsize, colorpos, w & 1);
 	}
 }
 
@@ -433,7 +538,7 @@
 	/* Print stream time */
 	for (line = y; line < y + 16; line++) {
 		int j = 0;
-		char *pos = basep + line * dev->width * 2 + x * 2;
+		char *pos = basep + line * dev->width * dev->pixelsize + x * dev->pixelsize;
 		char *s;
 
 		for (s = text; *s; s++) {
@@ -443,9 +548,9 @@
 			for (i = 0; i < 7; i++, j++) {
 				/* Draw white font on black background */
 				if (chr & (1 << (7 - i)))
-					gen_twopix(dev, pos + j * 2, WHITE);
+					gen_twopix(dev, pos + j * dev->pixelsize, WHITE, (x+y) & 1);
 				else
-					gen_twopix(dev, pos + j * 2, TEXT_BLACK);
+					gen_twopix(dev, pos + j * dev->pixelsize, TEXT_BLACK, (x+y) & 1);
 			}
 		}
 	}
@@ -466,7 +571,9 @@
 		return;
 
 	for (h = 0; h < hmax; h++)
-		memcpy(vbuf + h * wmax * 2, dev->line + (dev->mv_count % wmax) * 2, wmax * 2);
+		memcpy(vbuf + h * wmax * dev->pixelsize,
+		       dev->line + (dev->mv_count % wmax) * dev->pixelsize,
+		       wmax * dev->pixelsize);
 
 	/* Updates stream time */
 
@@ -484,15 +591,16 @@
 	gen_text(dev, vbuf, line++ * 16, 16, str);
 
 	gain = v4l2_ctrl_g_ctrl(dev->gain);
-	mutex_lock(&dev->ctrl_handler.lock);
+	mutex_lock(dev->ctrl_handler.lock);
 	snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
 			dev->brightness->cur.val,
 			dev->contrast->cur.val,
 			dev->saturation->cur.val,
 			dev->hue->cur.val);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
-	snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d ",
-			dev->autogain->cur.val, gain, dev->volume->cur.val);
+	snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
+			dev->autogain->cur.val, gain, dev->volume->cur.val,
+			dev->alpha->cur.val);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
 	snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
 			dev->int32->cur.val,
@@ -503,8 +611,12 @@
 			dev->boolean->cur.val,
 			dev->menu->qmenu[dev->menu->cur.val],
 			dev->string->cur.string);
-	mutex_unlock(&dev->ctrl_handler.lock);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
+			dev->int_menu->qmenu_int[dev->int_menu->cur.val],
+			dev->int_menu->cur.val);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	mutex_unlock(dev->ctrl_handler.lock);
 	if (dev->button_pressed) {
 		dev->button_pressed--;
 		snprintf(str, sizeof(str), " button pressed!");
@@ -657,7 +769,7 @@
 	struct vivi_dev *dev = vb2_get_drv_priv(vq);
 	unsigned long size;
 
-	size = dev->width * dev->height * 2;
+	size = dev->width * dev->height * dev->pixelsize;
 
 	if (0 == *nbuffers)
 		*nbuffers = 32;
@@ -721,7 +833,7 @@
 	    dev->height < 32 || dev->height > MAX_HEIGHT)
 		return -EINVAL;
 
-	size = dev->width * dev->height * 2;
+	size = dev->width * dev->height * dev->pixelsize;
 	if (vb2_plane_size(vb, 0) < size) {
 		dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
 				__func__, vb2_plane_size(vb, 0), size);
@@ -915,6 +1027,7 @@
 	}
 
 	dev->fmt = get_format(f);
+	dev->pixelsize = dev->fmt->depth / 8;
 	dev->width = f->fmt.pix.width;
 	dev->height = f->fmt.pix.height;
 	dev->field = f->fmt.pix.field;
@@ -1016,8 +1129,15 @@
 {
 	struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
 
-	if (ctrl == dev->button)
-		dev->button_pressed = 30;
+	switch (ctrl->id) {
+	case V4L2_CID_ALPHA_COMPONENT:
+		dev->alpha_component = ctrl->val;
+		break;
+	default:
+		if (ctrl == dev->button)
+			dev->button_pressed = 30;
+		break;
+	}
 	return 0;
 }
 
@@ -1039,17 +1159,10 @@
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct vivi_dev *dev = video_drvdata(file);
-	struct v4l2_fh *fh = file->private_data;
 	struct vb2_queue *q = &dev->vb_vidq;
-	unsigned int res;
 
 	dprintk(dev, 1, "%s\n", __func__);
-	res = vb2_poll(q, file, wait);
-	if (v4l2_event_pending(fh))
-		res |= POLLPRI;
-	else
-		poll_wait(file, &fh->wait, wait);
-	return res;
+	return vb2_poll(q, file, wait);
 }
 
 static int vivi_close(struct file *file)
@@ -1165,6 +1278,22 @@
 	.step = 0,
 };
 
+static const s64 vivi_ctrl_int_menu_values[] = {
+	1, 1, 2, 3, 5, 8, 13, 21, 42,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 7,
+	.name = "Integer menu",
+	.type = V4L2_CTRL_TYPE_INTEGER_MENU,
+	.min = 1,
+	.max = 8,
+	.def = 4,
+	.menu_skip_mask = 0x02,
+	.qmenu_int = vivi_ctrl_int_menu_values,
+};
+
 static const struct v4l2_file_operations vivi_fops = {
 	.owner		= THIS_MODULE,
 	.open           = v4l2_fh_open,
@@ -1252,6 +1381,7 @@
 	dev->fmt = &formats[0];
 	dev->width = 640;
 	dev->height = 480;
+	dev->pixelsize = dev->fmt->depth / 8;
 	hdl = &dev->ctrl_handler;
 	v4l2_ctrl_handler_init(hdl, 11);
 	dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
@@ -1268,6 +1398,8 @@
 			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
 	dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
 			V4L2_CID_GAIN, 0, 255, 1, 100);
+	dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
 	dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
 	dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
 	dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
@@ -1275,6 +1407,7 @@
 	dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
 	dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
 	dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
+	dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
 	if (hdl->error) {
 		ret = hdl->error;
 		goto unreg_dev;
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 7fd7ac5..db2a600 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -62,6 +62,9 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 #include <linux/parport.h>
 
 /*#define DEBUG*/				/* Undef me for production */
@@ -104,6 +107,7 @@
 
 struct w9966 {
 	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler hdl;
 	unsigned char dev_state;
 	unsigned char i2c_state;
 	unsigned short ppmode;
@@ -567,7 +571,8 @@
 	strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver));
 	strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card));
 	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
-	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -595,67 +600,25 @@
 	return (inp > 0) ? -EINVAL : 0;
 }
 
-static int cam_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
+static int cam_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	switch (qc->id) {
-	case V4L2_CID_BRIGHTNESS:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
-	case V4L2_CID_CONTRAST:
-		return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
-	case V4L2_CID_SATURATION:
-		return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
-	case V4L2_CID_HUE:
-		return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-	}
-	return -EINVAL;
-}
-
-static int cam_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct w9966 *cam = video_drvdata(file);
-	int ret = 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = cam->brightness;
-		break;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = cam->contrast;
-		break;
-	case V4L2_CID_SATURATION:
-		ctrl->value = cam->color;
-		break;
-	case V4L2_CID_HUE:
-		ctrl->value = cam->hue;
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int cam_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct w9966 *cam = video_drvdata(file);
+	struct w9966 *cam =
+		container_of(ctrl->handler, struct w9966, hdl);
 	int ret = 0;
 
 	mutex_lock(&cam->lock);
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		cam->brightness = ctrl->value;
+		cam->brightness = ctrl->val;
 		break;
 	case V4L2_CID_CONTRAST:
-		cam->contrast = ctrl->value;
+		cam->contrast = ctrl->val;
 		break;
 	case V4L2_CID_SATURATION:
-		cam->color = ctrl->value;
+		cam->color = ctrl->val;
 		break;
 	case V4L2_CID_HUE:
-		cam->hue = ctrl->value;
+		cam->hue = ctrl->val;
 		break;
 	default:
 		ret = -EINVAL;
@@ -813,6 +776,9 @@
 
 static const struct v4l2_file_operations w9966_fops = {
 	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
 	.unlocked_ioctl = video_ioctl2,
 	.read           = w9966_v4l_read,
 };
@@ -822,13 +788,17 @@
 	.vidioc_g_input      		    = cam_g_input,
 	.vidioc_s_input      		    = cam_s_input,
 	.vidioc_enum_input   		    = cam_enum_input,
-	.vidioc_queryctrl 		    = cam_queryctrl,
-	.vidioc_g_ctrl  		    = cam_g_ctrl,
-	.vidioc_s_ctrl 			    = cam_s_ctrl,
 	.vidioc_enum_fmt_vid_cap 	    = cam_enum_fmt_vid_cap,
 	.vidioc_g_fmt_vid_cap 		    = cam_g_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap  		    = cam_s_fmt_vid_cap,
 	.vidioc_try_fmt_vid_cap  	    = cam_try_fmt_vid_cap,
+	.vidioc_log_status		    = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops cam_ctrl_ops = {
+	.s_ctrl = cam_s_ctrl,
 };
 
 
@@ -849,6 +819,20 @@
 		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
 		return -1;
 	}
+
+	v4l2_ctrl_handler_init(&cam->hdl, 4);
+	v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+			  V4L2_CID_CONTRAST, -64, 64, 1, 64);
+	v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+			  V4L2_CID_SATURATION, -64, 64, 1, 64);
+	v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+			  V4L2_CID_HUE, -128, 127, 1, 0);
+	if (cam->hdl.error) {
+		v4l2_err(v4l2_dev, "couldn't register controls\n");
+		return -1;
+	}
 	cam->pport = port;
 	cam->brightness = 128;
 	cam->contrast = 64;
@@ -898,6 +882,8 @@
 	cam->vdev.fops = &w9966_fops;
 	cam->vdev.ioctl_ops = &w9966_ioctl_ops;
 	cam->vdev.release = video_device_release_empty;
+	cam->vdev.ctrl_handler = &cam->hdl;
+	set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
 	video_set_drvdata(&cam->vdev, cam);
 
 	mutex_init(&cam->lock);
@@ -923,6 +909,8 @@
 		w9966_set_state(cam, W9966_STATE_VDEV, 0);
 	}
 
+	v4l2_ctrl_handler_free(&cam->hdl);
+
 	/* Terminate from IEEE1284 mode and release pdev block */
 	if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
 		w9966_pdev_claim(cam);
diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c
index e86173b..a4cd504 100644
--- a/drivers/media/video/zoran/zoran_device.c
+++ b/drivers/media/video/zoran/zoran_device.c
@@ -542,11 +542,9 @@
 	u32 *mask;
 	int x, y, width, height;
 	unsigned i, j, k;
-	u32 reg;
 
 	/* fill mask with one bits */
 	memset(fh->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
-	reg = 0;
 
 	for (i = 0; i < count; ++i) {
 		/* pick up local copy of clip */
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 4c09ab7..c573109 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -1131,8 +1131,14 @@
 }
 
 
-static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height,
-	struct v4l2_clip __user *clips, int clipcount, void __user *bitmap)
+static int setup_window(struct zoran_fh *fh,
+			int x,
+			int y,
+			int width,
+			int height,
+			struct v4l2_clip __user *clips,
+			unsigned int clipcount,
+			void __user *bitmap)
 {
 	struct zoran *zr = fh->zr;
 	struct v4l2_clip *vcp = NULL;
@@ -1155,6 +1161,14 @@
 		return -EINVAL;
 	}
 
+	if (clipcount > 2048) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - invalid clipcount\n",
+			 ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+
 	/*
 	 * The video front end needs 4-byte alinged line sizes, we correct that
 	 * silently here if necessary
@@ -1218,7 +1232,7 @@
 				   (width * height + 7) / 8)) {
 			return -EFAULT;
 		}
-	} else if (clipcount > 0) {
+	} else if (clipcount) {
 		/* write our own bitmap from the clips */
 		vcp = vmalloc(sizeof(struct v4l2_clip) * (clipcount + 4));
 		if (vcp == NULL) {
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index cd2e39f..e44cb33 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -507,14 +507,12 @@
 	const char *tmpbuf;
 	char *vbuf = videobuf_to_vmalloc(&buf->vb);
 	unsigned long last_frame;
-	struct zr364xx_framei *frm;
 
 	if (!vbuf)
 		return;
 
 	last_frame = cam->last_frame;
 	if (last_frame != -1) {
-		frm = &cam->buffer.frame[last_frame];
 		tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
 		switch (buf->fmt->fourcc) {
 		case V4L2_PIX_FMT_JPEG:
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
new file mode 100644
index 0000000..067f311
--- /dev/null
+++ b/drivers/memory/Kconfig
@@ -0,0 +1,43 @@
+#
+# Memory devices
+#
+
+menuconfig MEMORY
+	bool "Memory Controller drivers"
+
+if MEMORY
+
+config TI_EMIF
+	tristate "Texas Instruments EMIF driver"
+	depends on ARCH_OMAP2PLUS
+	select DDR
+	help
+	  This driver is for the EMIF module available in Texas Instruments
+	  SoCs. EMIF is an SDRAM controller that, based on its revision,
+	  supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols.
+	  This driver takes care of only LPDDR2 memories presently. The
+	  functions of the driver includes re-configuring AC timing
+	  parameters and other settings during frequency, voltage and
+	  temperature changes
+
+config TEGRA20_MC
+	bool "Tegra20 Memory Controller(MC) driver"
+	default y
+	depends on ARCH_TEGRA_2x_SOC
+	help
+	  This driver is for the Memory Controller(MC) module available
+	  in Tegra20 SoCs, mainly for a address translation fault
+	  analysis, especially for IOMMU/GART(Graphics Address
+	  Relocation Table) module.
+
+config TEGRA30_MC
+	bool "Tegra30 Memory Controller(MC) driver"
+	default y
+	depends on ARCH_TEGRA_3x_SOC
+	help
+	  This driver is for the Memory Controller(MC) module available
+	  in Tegra30 SoCs, mainly for a address translation fault
+	  analysis, especially for IOMMU/SMMU(System Memory Management
+	  Unit) module.
+
+endif
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
new file mode 100644
index 0000000..42b3ce9
--- /dev/null
+++ b/drivers/memory/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for memory devices
+#
+
+obj-$(CONFIG_TI_EMIF)		+= emif.o
+obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
+obj-$(CONFIG_TEGRA30_MC)	+= tegra30-mc.o
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
new file mode 100644
index 0000000..33a4396b
--- /dev/null
+++ b/drivers/memory/emif.c
@@ -0,0 +1,1670 @@
+/*
+ * EMIF driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@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.
+ */
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/platform_data/emif_plat.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <memory/jedec_ddr.h>
+#include "emif.h"
+
+/**
+ * struct emif_data - Per device static data for driver's use
+ * @duplicate:			Whether the DDR devices attached to this EMIF
+ *				instance are exactly same as that on EMIF1. In
+ *				this case we can save some memory and processing
+ * @temperature_level:		Maximum temperature of LPDDR2 devices attached
+ *				to this EMIF - read from MR4 register. If there
+ *				are two devices attached to this EMIF, this
+ *				value is the maximum of the two temperature
+ *				levels.
+ * @node:			node in the device list
+ * @base:			base address of memory-mapped IO registers.
+ * @dev:			device pointer.
+ * @addressing			table with addressing information from the spec
+ * @regs_cache:			An array of 'struct emif_regs' that stores
+ *				calculated register values for different
+ *				frequencies, to avoid re-calculating them on
+ *				each DVFS transition.
+ * @curr_regs:			The set of register values used in the last
+ *				frequency change (i.e. corresponding to the
+ *				frequency in effect at the moment)
+ * @plat_data:			Pointer to saved platform data.
+ * @debugfs_root:		dentry to the root folder for EMIF in debugfs
+ */
+struct emif_data {
+	u8				duplicate;
+	u8				temperature_level;
+	u8				lpmode;
+	struct list_head		node;
+	unsigned long			irq_state;
+	void __iomem			*base;
+	struct device			*dev;
+	const struct lpddr2_addressing	*addressing;
+	struct emif_regs		*regs_cache[EMIF_MAX_NUM_FREQUENCIES];
+	struct emif_regs		*curr_regs;
+	struct emif_platform_data	*plat_data;
+	struct dentry			*debugfs_root;
+};
+
+static struct emif_data *emif1;
+static spinlock_t	emif_lock;
+static unsigned long	irq_state;
+static u32		t_ck; /* DDR clock period in ps */
+static LIST_HEAD(device_list);
+
+static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif,
+	struct emif_regs *regs)
+{
+	u32 type = emif->plat_data->device_info->type;
+	u32 ip_rev = emif->plat_data->ip_rev;
+
+	seq_printf(s, "EMIF register cache dump for %dMHz\n",
+		regs->freq/1000000);
+
+	seq_printf(s, "ref_ctrl_shdw\t: 0x%08x\n", regs->ref_ctrl_shdw);
+	seq_printf(s, "sdram_tim1_shdw\t: 0x%08x\n", regs->sdram_tim1_shdw);
+	seq_printf(s, "sdram_tim2_shdw\t: 0x%08x\n", regs->sdram_tim2_shdw);
+	seq_printf(s, "sdram_tim3_shdw\t: 0x%08x\n", regs->sdram_tim3_shdw);
+
+	if (ip_rev == EMIF_4D) {
+		seq_printf(s, "read_idle_ctrl_shdw_normal\t: 0x%08x\n",
+			regs->read_idle_ctrl_shdw_normal);
+		seq_printf(s, "read_idle_ctrl_shdw_volt_ramp\t: 0x%08x\n",
+			regs->read_idle_ctrl_shdw_volt_ramp);
+	} else if (ip_rev == EMIF_4D5) {
+		seq_printf(s, "dll_calib_ctrl_shdw_normal\t: 0x%08x\n",
+			regs->dll_calib_ctrl_shdw_normal);
+		seq_printf(s, "dll_calib_ctrl_shdw_volt_ramp\t: 0x%08x\n",
+			regs->dll_calib_ctrl_shdw_volt_ramp);
+	}
+
+	if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) {
+		seq_printf(s, "ref_ctrl_shdw_derated\t: 0x%08x\n",
+			regs->ref_ctrl_shdw_derated);
+		seq_printf(s, "sdram_tim1_shdw_derated\t: 0x%08x\n",
+			regs->sdram_tim1_shdw_derated);
+		seq_printf(s, "sdram_tim3_shdw_derated\t: 0x%08x\n",
+			regs->sdram_tim3_shdw_derated);
+	}
+}
+
+static int emif_regdump_show(struct seq_file *s, void *unused)
+{
+	struct emif_data	*emif	= s->private;
+	struct emif_regs	**regs_cache;
+	int			i;
+
+	if (emif->duplicate)
+		regs_cache = emif1->regs_cache;
+	else
+		regs_cache = emif->regs_cache;
+
+	for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) {
+		do_emif_regdump_show(s, emif, regs_cache[i]);
+		seq_printf(s, "\n");
+	}
+
+	return 0;
+}
+
+static int emif_regdump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, emif_regdump_show, inode->i_private);
+}
+
+static const struct file_operations emif_regdump_fops = {
+	.open			= emif_regdump_open,
+	.read			= seq_read,
+	.release		= single_release,
+};
+
+static int emif_mr4_show(struct seq_file *s, void *unused)
+{
+	struct emif_data *emif = s->private;
+
+	seq_printf(s, "MR4=%d\n", emif->temperature_level);
+	return 0;
+}
+
+static int emif_mr4_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, emif_mr4_show, inode->i_private);
+}
+
+static const struct file_operations emif_mr4_fops = {
+	.open			= emif_mr4_open,
+	.read			= seq_read,
+	.release		= single_release,
+};
+
+static int __init_or_module emif_debugfs_init(struct emif_data *emif)
+{
+	struct dentry	*dentry;
+	int		ret;
+
+	dentry = debugfs_create_dir(dev_name(emif->dev), NULL);
+	if (IS_ERR(dentry)) {
+		ret = PTR_ERR(dentry);
+		goto err0;
+	}
+	emif->debugfs_root = dentry;
+
+	dentry = debugfs_create_file("regcache_dump", S_IRUGO,
+			emif->debugfs_root, emif, &emif_regdump_fops);
+	if (IS_ERR(dentry)) {
+		ret = PTR_ERR(dentry);
+		goto err1;
+	}
+
+	dentry = debugfs_create_file("mr4", S_IRUGO,
+			emif->debugfs_root, emif, &emif_mr4_fops);
+	if (IS_ERR(dentry)) {
+		ret = PTR_ERR(dentry);
+		goto err1;
+	}
+
+	return 0;
+err1:
+	debugfs_remove_recursive(emif->debugfs_root);
+err0:
+	return ret;
+}
+
+static void __exit emif_debugfs_exit(struct emif_data *emif)
+{
+	debugfs_remove_recursive(emif->debugfs_root);
+	emif->debugfs_root = NULL;
+}
+
+/*
+ * Calculate the period of DDR clock from frequency value
+ */
+static void set_ddr_clk_period(u32 freq)
+{
+	/* Divide 10^12 by frequency to get period in ps */
+	t_ck = (u32)DIV_ROUND_UP_ULL(1000000000000ull, freq);
+}
+
+/*
+ * Get bus width used by EMIF. Note that this may be different from the
+ * bus width of the DDR devices used. For instance two 16-bit DDR devices
+ * may be connected to a given CS of EMIF. In this case bus width as far
+ * as EMIF is concerned is 32, where as the DDR bus width is 16 bits.
+ */
+static u32 get_emif_bus_width(struct emif_data *emif)
+{
+	u32		width;
+	void __iomem	*base = emif->base;
+
+	width = (readl(base + EMIF_SDRAM_CONFIG) & NARROW_MODE_MASK)
+			>> NARROW_MODE_SHIFT;
+	width = width == 0 ? 32 : 16;
+
+	return width;
+}
+
+/*
+ * Get the CL from SDRAM_CONFIG register
+ */
+static u32 get_cl(struct emif_data *emif)
+{
+	u32		cl;
+	void __iomem	*base = emif->base;
+
+	cl = (readl(base + EMIF_SDRAM_CONFIG) & CL_MASK) >> CL_SHIFT;
+
+	return cl;
+}
+
+static void set_lpmode(struct emif_data *emif, u8 lpmode)
+{
+	u32 temp;
+	void __iomem *base = emif->base;
+
+	temp = readl(base + EMIF_POWER_MANAGEMENT_CONTROL);
+	temp &= ~LP_MODE_MASK;
+	temp |= (lpmode << LP_MODE_SHIFT);
+	writel(temp, base + EMIF_POWER_MANAGEMENT_CONTROL);
+}
+
+static void do_freq_update(void)
+{
+	struct emif_data *emif;
+
+	/*
+	 * Workaround for errata i728: Disable LPMODE during FREQ_UPDATE
+	 *
+	 * i728 DESCRIPTION:
+	 * The EMIF automatically puts the SDRAM into self-refresh mode
+	 * after the EMIF has not performed accesses during
+	 * EMIF_PWR_MGMT_CTRL[7:4] REG_SR_TIM number of DDR clock cycles
+	 * and the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field is set
+	 * to 0x2. If during a small window the following three events
+	 * occur:
+	 * - The SR_TIMING counter expires
+	 * - And frequency change is requested
+	 * - And OCP access is requested
+	 * Then it causes instable clock on the DDR interface.
+	 *
+	 * WORKAROUND
+	 * To avoid the occurrence of the three events, the workaround
+	 * is to disable the self-refresh when requesting a frequency
+	 * change. Before requesting a frequency change the software must
+	 * program EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x0. When the
+	 * frequency change has been done, the software can reprogram
+	 * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x2
+	 */
+	list_for_each_entry(emif, &device_list, node) {
+		if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+			set_lpmode(emif, EMIF_LP_MODE_DISABLE);
+	}
+
+	/*
+	 * TODO: Do FREQ_UPDATE here when an API
+	 * is available for this as part of the new
+	 * clock framework
+	 */
+
+	list_for_each_entry(emif, &device_list, node) {
+		if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+			set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH);
+	}
+}
+
+/* Find addressing table entry based on the device's type and density */
+static const struct lpddr2_addressing *get_addressing_table(
+	const struct ddr_device_info *device_info)
+{
+	u32		index, type, density;
+
+	type = device_info->type;
+	density = device_info->density;
+
+	switch (type) {
+	case DDR_TYPE_LPDDR2_S4:
+		index = density - 1;
+		break;
+	case DDR_TYPE_LPDDR2_S2:
+		switch (density) {
+		case DDR_DENSITY_1Gb:
+		case DDR_DENSITY_2Gb:
+			index = density + 3;
+			break;
+		default:
+			index = density - 1;
+		}
+		break;
+	default:
+		return NULL;
+	}
+
+	return &lpddr2_jedec_addressing_table[index];
+}
+
+/*
+ * Find the the right timing table from the array of timing
+ * tables of the device using DDR clock frequency
+ */
+static const struct lpddr2_timings *get_timings_table(struct emif_data *emif,
+		u32 freq)
+{
+	u32				i, min, max, freq_nearest;
+	const struct lpddr2_timings	*timings = NULL;
+	const struct lpddr2_timings	*timings_arr = emif->plat_data->timings;
+	struct				device *dev = emif->dev;
+
+	/* Start with a very high frequency - 1GHz */
+	freq_nearest = 1000000000;
+
+	/*
+	 * Find the timings table such that:
+	 *  1. the frequency range covers the required frequency(safe) AND
+	 *  2. the max_freq is closest to the required frequency(optimal)
+	 */
+	for (i = 0; i < emif->plat_data->timings_arr_size; i++) {
+		max = timings_arr[i].max_freq;
+		min = timings_arr[i].min_freq;
+		if ((freq >= min) && (freq <= max) && (max < freq_nearest)) {
+			freq_nearest = max;
+			timings = &timings_arr[i];
+		}
+	}
+
+	if (!timings)
+		dev_err(dev, "%s: couldn't find timings for - %dHz\n",
+			__func__, freq);
+
+	dev_dbg(dev, "%s: timings table: freq %d, speed bin freq %d\n",
+		__func__, freq, freq_nearest);
+
+	return timings;
+}
+
+static u32 get_sdram_ref_ctrl_shdw(u32 freq,
+		const struct lpddr2_addressing *addressing)
+{
+	u32 ref_ctrl_shdw = 0, val = 0, freq_khz, t_refi;
+
+	/* Scale down frequency and t_refi to avoid overflow */
+	freq_khz = freq / 1000;
+	t_refi = addressing->tREFI_ns / 100;
+
+	/*
+	 * refresh rate to be set is 'tREFI(in us) * freq in MHz
+	 * division by 10000 to account for change in units
+	 */
+	val = t_refi * freq_khz / 10000;
+	ref_ctrl_shdw |= val << REFRESH_RATE_SHIFT;
+
+	return ref_ctrl_shdw;
+}
+
+static u32 get_sdram_tim_1_shdw(const struct lpddr2_timings *timings,
+		const struct lpddr2_min_tck *min_tck,
+		const struct lpddr2_addressing *addressing)
+{
+	u32 tim1 = 0, val = 0;
+
+	val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1;
+	tim1 |= val << T_WTR_SHIFT;
+
+	if (addressing->num_banks == B8)
+		val = DIV_ROUND_UP(timings->tFAW, t_ck*4);
+	else
+		val = max(min_tck->tRRD, DIV_ROUND_UP(timings->tRRD, t_ck));
+	tim1 |= (val - 1) << T_RRD_SHIFT;
+
+	val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab, t_ck) - 1;
+	tim1 |= val << T_RC_SHIFT;
+
+	val = max(min_tck->tRASmin, DIV_ROUND_UP(timings->tRAS_min, t_ck));
+	tim1 |= (val - 1) << T_RAS_SHIFT;
+
+	val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1;
+	tim1 |= val << T_WR_SHIFT;
+
+	val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD, t_ck)) - 1;
+	tim1 |= val << T_RCD_SHIFT;
+
+	val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab, t_ck)) - 1;
+	tim1 |= val << T_RP_SHIFT;
+
+	return tim1;
+}
+
+static u32 get_sdram_tim_1_shdw_derated(const struct lpddr2_timings *timings,
+		const struct lpddr2_min_tck *min_tck,
+		const struct lpddr2_addressing *addressing)
+{
+	u32 tim1 = 0, val = 0;
+
+	val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1;
+	tim1 = val << T_WTR_SHIFT;
+
+	/*
+	 * tFAW is approximately 4 times tRRD. So add 1875*4 = 7500ps
+	 * to tFAW for de-rating
+	 */
+	if (addressing->num_banks == B8) {
+		val = DIV_ROUND_UP(timings->tFAW + 7500, 4 * t_ck) - 1;
+	} else {
+		val = DIV_ROUND_UP(timings->tRRD + 1875, t_ck);
+		val = max(min_tck->tRRD, val) - 1;
+	}
+	tim1 |= val << T_RRD_SHIFT;
+
+	val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab + 1875, t_ck);
+	tim1 |= (val - 1) << T_RC_SHIFT;
+
+	val = DIV_ROUND_UP(timings->tRAS_min + 1875, t_ck);
+	val = max(min_tck->tRASmin, val) - 1;
+	tim1 |= val << T_RAS_SHIFT;
+
+	val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1;
+	tim1 |= val << T_WR_SHIFT;
+
+	val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD + 1875, t_ck));
+	tim1 |= (val - 1) << T_RCD_SHIFT;
+
+	val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab + 1875, t_ck));
+	tim1 |= (val - 1) << T_RP_SHIFT;
+
+	return tim1;
+}
+
+static u32 get_sdram_tim_2_shdw(const struct lpddr2_timings *timings,
+		const struct lpddr2_min_tck *min_tck,
+		const struct lpddr2_addressing *addressing,
+		u32 type)
+{
+	u32 tim2 = 0, val = 0;
+
+	val = min_tck->tCKE - 1;
+	tim2 |= val << T_CKE_SHIFT;
+
+	val = max(min_tck->tRTP, DIV_ROUND_UP(timings->tRTP, t_ck)) - 1;
+	tim2 |= val << T_RTP_SHIFT;
+
+	/* tXSNR = tRFCab_ps + 10 ns(tRFCab_ps for LPDDR2). */
+	val = DIV_ROUND_UP(addressing->tRFCab_ps + 10000, t_ck) - 1;
+	tim2 |= val << T_XSNR_SHIFT;
+
+	/* XSRD same as XSNR for LPDDR2 */
+	tim2 |= val << T_XSRD_SHIFT;
+
+	val = max(min_tck->tXP, DIV_ROUND_UP(timings->tXP, t_ck)) - 1;
+	tim2 |= val << T_XP_SHIFT;
+
+	return tim2;
+}
+
+static u32 get_sdram_tim_3_shdw(const struct lpddr2_timings *timings,
+		const struct lpddr2_min_tck *min_tck,
+		const struct lpddr2_addressing *addressing,
+		u32 type, u32 ip_rev, u32 derated)
+{
+	u32 tim3 = 0, val = 0, t_dqsck;
+
+	val = timings->tRAS_max_ns / addressing->tREFI_ns - 1;
+	val = val > 0xF ? 0xF : val;
+	tim3 |= val << T_RAS_MAX_SHIFT;
+
+	val = DIV_ROUND_UP(addressing->tRFCab_ps, t_ck) - 1;
+	tim3 |= val << T_RFC_SHIFT;
+
+	t_dqsck = (derated == EMIF_DERATED_TIMINGS) ?
+		timings->tDQSCK_max_derated : timings->tDQSCK_max;
+	if (ip_rev == EMIF_4D5)
+		val = DIV_ROUND_UP(t_dqsck + 1000, t_ck) - 1;
+	else
+		val = DIV_ROUND_UP(t_dqsck, t_ck) - 1;
+
+	tim3 |= val << T_TDQSCKMAX_SHIFT;
+
+	val = DIV_ROUND_UP(timings->tZQCS, t_ck) - 1;
+	tim3 |= val << ZQ_ZQCS_SHIFT;
+
+	val = DIV_ROUND_UP(timings->tCKESR, t_ck);
+	val = max(min_tck->tCKESR, val) - 1;
+	tim3 |= val << T_CKESR_SHIFT;
+
+	if (ip_rev == EMIF_4D5) {
+		tim3 |= (EMIF_T_CSTA - 1) << T_CSTA_SHIFT;
+
+		val = DIV_ROUND_UP(EMIF_T_PDLL_UL, 128) - 1;
+		tim3 |= val << T_PDLL_UL_SHIFT;
+	}
+
+	return tim3;
+}
+
+static u32 get_zq_config_reg(const struct lpddr2_addressing *addressing,
+		bool cs1_used, bool cal_resistors_per_cs)
+{
+	u32 zq = 0, val = 0;
+
+	val = EMIF_ZQCS_INTERVAL_US * 1000 / addressing->tREFI_ns;
+	zq |= val << ZQ_REFINTERVAL_SHIFT;
+
+	val = DIV_ROUND_UP(T_ZQCL_DEFAULT_NS, T_ZQCS_DEFAULT_NS) - 1;
+	zq |= val << ZQ_ZQCL_MULT_SHIFT;
+
+	val = DIV_ROUND_UP(T_ZQINIT_DEFAULT_NS, T_ZQCL_DEFAULT_NS) - 1;
+	zq |= val << ZQ_ZQINIT_MULT_SHIFT;
+
+	zq |= ZQ_SFEXITEN_ENABLE << ZQ_SFEXITEN_SHIFT;
+
+	if (cal_resistors_per_cs)
+		zq |= ZQ_DUALCALEN_ENABLE << ZQ_DUALCALEN_SHIFT;
+	else
+		zq |= ZQ_DUALCALEN_DISABLE << ZQ_DUALCALEN_SHIFT;
+
+	zq |= ZQ_CS0EN_MASK; /* CS0 is used for sure */
+
+	val = cs1_used ? 1 : 0;
+	zq |= val << ZQ_CS1EN_SHIFT;
+
+	return zq;
+}
+
+static u32 get_temp_alert_config(const struct lpddr2_addressing *addressing,
+		const struct emif_custom_configs *custom_configs, bool cs1_used,
+		u32 sdram_io_width, u32 emif_bus_width)
+{
+	u32 alert = 0, interval, devcnt;
+
+	if (custom_configs && (custom_configs->mask &
+				EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL))
+		interval = custom_configs->temp_alert_poll_interval_ms;
+	else
+		interval = TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS;
+
+	interval *= 1000000;			/* Convert to ns */
+	interval /= addressing->tREFI_ns;	/* Convert to refresh cycles */
+	alert |= (interval << TA_REFINTERVAL_SHIFT);
+
+	/*
+	 * sdram_io_width is in 'log2(x) - 1' form. Convert emif_bus_width
+	 * also to this form and subtract to get TA_DEVCNT, which is
+	 * in log2(x) form.
+	 */
+	emif_bus_width = __fls(emif_bus_width) - 1;
+	devcnt = emif_bus_width - sdram_io_width;
+	alert |= devcnt << TA_DEVCNT_SHIFT;
+
+	/* DEVWDT is in 'log2(x) - 3' form */
+	alert |= (sdram_io_width - 2) << TA_DEVWDT_SHIFT;
+
+	alert |= 1 << TA_SFEXITEN_SHIFT;
+	alert |= 1 << TA_CS0EN_SHIFT;
+	alert |= (cs1_used ? 1 : 0) << TA_CS1EN_SHIFT;
+
+	return alert;
+}
+
+static u32 get_read_idle_ctrl_shdw(u8 volt_ramp)
+{
+	u32 idle = 0, val = 0;
+
+	/*
+	 * Maximum value in normal conditions and increased frequency
+	 * when voltage is ramping
+	 */
+	if (volt_ramp)
+		val = READ_IDLE_INTERVAL_DVFS / t_ck / 64 - 1;
+	else
+		val = 0x1FF;
+
+	/*
+	 * READ_IDLE_CTRL register in EMIF4D has same offset and fields
+	 * as DLL_CALIB_CTRL in EMIF4D5, so use the same shifts
+	 */
+	idle |= val << DLL_CALIB_INTERVAL_SHIFT;
+	idle |= EMIF_READ_IDLE_LEN_VAL << ACK_WAIT_SHIFT;
+
+	return idle;
+}
+
+static u32 get_dll_calib_ctrl_shdw(u8 volt_ramp)
+{
+	u32 calib = 0, val = 0;
+
+	if (volt_ramp == DDR_VOLTAGE_RAMPING)
+		val = DLL_CALIB_INTERVAL_DVFS / t_ck / 16 - 1;
+	else
+		val = 0; /* Disabled when voltage is stable */
+
+	calib |= val << DLL_CALIB_INTERVAL_SHIFT;
+	calib |= DLL_CALIB_ACK_WAIT_VAL << ACK_WAIT_SHIFT;
+
+	return calib;
+}
+
+static u32 get_ddr_phy_ctrl_1_attilaphy_4d(const struct lpddr2_timings *timings,
+	u32 freq, u8 RL)
+{
+	u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY, val = 0;
+
+	val = RL + DIV_ROUND_UP(timings->tDQSCK_max, t_ck) - 1;
+	phy |= val << READ_LATENCY_SHIFT_4D;
+
+	if (freq <= 100000000)
+		val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY;
+	else if (freq <= 200000000)
+		val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY;
+	else
+		val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY;
+
+	phy |= val << DLL_SLAVE_DLY_CTRL_SHIFT_4D;
+
+	return phy;
+}
+
+static u32 get_phy_ctrl_1_intelliphy_4d5(u32 freq, u8 cl)
+{
+	u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY, half_delay;
+
+	/*
+	 * DLL operates at 266 MHz. If DDR frequency is near 266 MHz,
+	 * half-delay is not needed else set half-delay
+	 */
+	if (freq >= 265000000 && freq < 267000000)
+		half_delay = 0;
+	else
+		half_delay = 1;
+
+	phy |= half_delay << DLL_HALF_DELAY_SHIFT_4D5;
+	phy |= ((cl + DIV_ROUND_UP(EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS,
+			t_ck) - 1) << READ_LATENCY_SHIFT_4D5);
+
+	return phy;
+}
+
+static u32 get_ext_phy_ctrl_2_intelliphy_4d5(void)
+{
+	u32 fifo_we_slave_ratio;
+
+	fifo_we_slave_ratio =  DIV_ROUND_CLOSEST(
+		EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck);
+
+	return fifo_we_slave_ratio | fifo_we_slave_ratio << 11 |
+		fifo_we_slave_ratio << 22;
+}
+
+static u32 get_ext_phy_ctrl_3_intelliphy_4d5(void)
+{
+	u32 fifo_we_slave_ratio;
+
+	fifo_we_slave_ratio =  DIV_ROUND_CLOSEST(
+		EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck);
+
+	return fifo_we_slave_ratio >> 10 | fifo_we_slave_ratio << 1 |
+		fifo_we_slave_ratio << 12 | fifo_we_slave_ratio << 23;
+}
+
+static u32 get_ext_phy_ctrl_4_intelliphy_4d5(void)
+{
+	u32 fifo_we_slave_ratio;
+
+	fifo_we_slave_ratio =  DIV_ROUND_CLOSEST(
+		EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck);
+
+	return fifo_we_slave_ratio >> 9 | fifo_we_slave_ratio << 2 |
+		fifo_we_slave_ratio << 13;
+}
+
+static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
+{
+	u32 pwr_mgmt_ctrl	= 0, timeout;
+	u32 lpmode		= EMIF_LP_MODE_SELF_REFRESH;
+	u32 timeout_perf	= EMIF_LP_MODE_TIMEOUT_PERFORMANCE;
+	u32 timeout_pwr		= EMIF_LP_MODE_TIMEOUT_POWER;
+	u32 freq_threshold	= EMIF_LP_MODE_FREQ_THRESHOLD;
+
+	struct emif_custom_configs *cust_cfgs = emif->plat_data->custom_configs;
+
+	if (cust_cfgs && (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE)) {
+		lpmode		= cust_cfgs->lpmode;
+		timeout_perf	= cust_cfgs->lpmode_timeout_performance;
+		timeout_pwr	= cust_cfgs->lpmode_timeout_power;
+		freq_threshold  = cust_cfgs->lpmode_freq_threshold;
+	}
+
+	/* Timeout based on DDR frequency */
+	timeout = freq >= freq_threshold ? timeout_perf : timeout_pwr;
+
+	/* The value to be set in register is "log2(timeout) - 3" */
+	if (timeout < 16) {
+		timeout = 0;
+	} else {
+		timeout = __fls(timeout) - 3;
+		if (timeout & (timeout - 1))
+			timeout++;
+	}
+
+	switch (lpmode) {
+	case EMIF_LP_MODE_CLOCK_STOP:
+		pwr_mgmt_ctrl = (timeout << CS_TIM_SHIFT) |
+					SR_TIM_MASK | PD_TIM_MASK;
+		break;
+	case EMIF_LP_MODE_SELF_REFRESH:
+		/* Workaround for errata i735 */
+		if (timeout < 6)
+			timeout = 6;
+
+		pwr_mgmt_ctrl = (timeout << SR_TIM_SHIFT) |
+					CS_TIM_MASK | PD_TIM_MASK;
+		break;
+	case EMIF_LP_MODE_PWR_DN:
+		pwr_mgmt_ctrl = (timeout << PD_TIM_SHIFT) |
+					CS_TIM_MASK | SR_TIM_MASK;
+		break;
+	case EMIF_LP_MODE_DISABLE:
+	default:
+		pwr_mgmt_ctrl = CS_TIM_MASK |
+					PD_TIM_MASK | SR_TIM_MASK;
+	}
+
+	/* No CS_TIM in EMIF_4D5 */
+	if (ip_rev == EMIF_4D5)
+		pwr_mgmt_ctrl &= ~CS_TIM_MASK;
+
+	pwr_mgmt_ctrl |= lpmode << LP_MODE_SHIFT;
+
+	return pwr_mgmt_ctrl;
+}
+
+/*
+ * Get the temperature level of the EMIF instance:
+ * Reads the MR4 register of attached SDRAM parts to find out the temperature
+ * level. If there are two parts attached(one on each CS), then the temperature
+ * level for the EMIF instance is the higher of the two temperatures.
+ */
+static void get_temperature_level(struct emif_data *emif)
+{
+	u32		temp, temperature_level;
+	void __iomem	*base;
+
+	base = emif->base;
+
+	/* Read mode register 4 */
+	writel(DDR_MR4, base + EMIF_LPDDR2_MODE_REG_CONFIG);
+	temperature_level = readl(base + EMIF_LPDDR2_MODE_REG_DATA);
+	temperature_level = (temperature_level & MR4_SDRAM_REF_RATE_MASK) >>
+				MR4_SDRAM_REF_RATE_SHIFT;
+
+	if (emif->plat_data->device_info->cs1_used) {
+		writel(DDR_MR4 | CS_MASK, base + EMIF_LPDDR2_MODE_REG_CONFIG);
+		temp = readl(base + EMIF_LPDDR2_MODE_REG_DATA);
+		temp = (temp & MR4_SDRAM_REF_RATE_MASK)
+				>> MR4_SDRAM_REF_RATE_SHIFT;
+		temperature_level = max(temp, temperature_level);
+	}
+
+	/* treat everything less than nominal(3) in MR4 as nominal */
+	if (unlikely(temperature_level < SDRAM_TEMP_NOMINAL))
+		temperature_level = SDRAM_TEMP_NOMINAL;
+
+	/* if we get reserved value in MR4 persist with the existing value */
+	if (likely(temperature_level != SDRAM_TEMP_RESERVED_4))
+		emif->temperature_level = temperature_level;
+}
+
+/*
+ * Program EMIF shadow registers that are not dependent on temperature
+ * or voltage
+ */
+static void setup_registers(struct emif_data *emif, struct emif_regs *regs)
+{
+	void __iomem	*base = emif->base;
+
+	writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW);
+	writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW);
+
+	/* Settings specific for EMIF4D5 */
+	if (emif->plat_data->ip_rev != EMIF_4D5)
+		return;
+	writel(regs->ext_phy_ctrl_2_shdw, base + EMIF_EXT_PHY_CTRL_2_SHDW);
+	writel(regs->ext_phy_ctrl_3_shdw, base + EMIF_EXT_PHY_CTRL_3_SHDW);
+	writel(regs->ext_phy_ctrl_4_shdw, base + EMIF_EXT_PHY_CTRL_4_SHDW);
+}
+
+/*
+ * When voltage ramps dll calibration and forced read idle should
+ * happen more often
+ */
+static void setup_volt_sensitive_regs(struct emif_data *emif,
+		struct emif_regs *regs, u32 volt_state)
+{
+	u32		calib_ctrl;
+	void __iomem	*base = emif->base;
+
+	/*
+	 * EMIF_READ_IDLE_CTRL in EMIF4D refers to the same register as
+	 * EMIF_DLL_CALIB_CTRL in EMIF4D5 and dll_calib_ctrl_shadow_*
+	 * is an alias of the respective read_idle_ctrl_shdw_* (members of
+	 * a union). So, the below code takes care of both cases
+	 */
+	if (volt_state == DDR_VOLTAGE_RAMPING)
+		calib_ctrl = regs->dll_calib_ctrl_shdw_volt_ramp;
+	else
+		calib_ctrl = regs->dll_calib_ctrl_shdw_normal;
+
+	writel(calib_ctrl, base + EMIF_DLL_CALIB_CTRL_SHDW);
+}
+
+/*
+ * setup_temperature_sensitive_regs() - set the timings for temperature
+ * sensitive registers. This happens once at initialisation time based
+ * on the temperature at boot time and subsequently based on the temperature
+ * alert interrupt. Temperature alert can happen when the temperature
+ * increases or drops. So this function can have the effect of either
+ * derating the timings or going back to nominal values.
+ */
+static void setup_temperature_sensitive_regs(struct emif_data *emif,
+		struct emif_regs *regs)
+{
+	u32		tim1, tim3, ref_ctrl, type;
+	void __iomem	*base = emif->base;
+	u32		temperature;
+
+	type = emif->plat_data->device_info->type;
+
+	tim1 = regs->sdram_tim1_shdw;
+	tim3 = regs->sdram_tim3_shdw;
+	ref_ctrl = regs->ref_ctrl_shdw;
+
+	/* No de-rating for non-lpddr2 devices */
+	if (type != DDR_TYPE_LPDDR2_S2 && type != DDR_TYPE_LPDDR2_S4)
+		goto out;
+
+	temperature = emif->temperature_level;
+	if (temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH) {
+		ref_ctrl = regs->ref_ctrl_shdw_derated;
+	} else if (temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS) {
+		tim1 = regs->sdram_tim1_shdw_derated;
+		tim3 = regs->sdram_tim3_shdw_derated;
+		ref_ctrl = regs->ref_ctrl_shdw_derated;
+	}
+
+out:
+	writel(tim1, base + EMIF_SDRAM_TIMING_1_SHDW);
+	writel(tim3, base + EMIF_SDRAM_TIMING_3_SHDW);
+	writel(ref_ctrl, base + EMIF_SDRAM_REFRESH_CTRL_SHDW);
+}
+
+static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
+{
+	u32		old_temp_level;
+	irqreturn_t	ret = IRQ_HANDLED;
+
+	spin_lock_irqsave(&emif_lock, irq_state);
+	old_temp_level = emif->temperature_level;
+	get_temperature_level(emif);
+
+	if (unlikely(emif->temperature_level == old_temp_level)) {
+		goto out;
+	} else if (!emif->curr_regs) {
+		dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n");
+		goto out;
+	}
+
+	if (emif->temperature_level < old_temp_level ||
+		emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
+		/*
+		 * Temperature coming down - defer handling to thread OR
+		 * Temperature far too high - do kernel_power_off() from
+		 * thread context
+		 */
+		ret = IRQ_WAKE_THREAD;
+	} else {
+		/* Temperature is going up - handle immediately */
+		setup_temperature_sensitive_regs(emif, emif->curr_regs);
+		do_freq_update();
+	}
+
+out:
+	spin_unlock_irqrestore(&emif_lock, irq_state);
+	return ret;
+}
+
+static irqreturn_t emif_interrupt_handler(int irq, void *dev_id)
+{
+	u32			interrupts;
+	struct emif_data	*emif = dev_id;
+	void __iomem		*base = emif->base;
+	struct device		*dev = emif->dev;
+	irqreturn_t		ret = IRQ_HANDLED;
+
+	/* Save the status and clear it */
+	interrupts = readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS);
+	writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS);
+
+	/*
+	 * Handle temperature alert
+	 * Temperature alert should be same for all ports
+	 * So, it's enough to process it only for one of the ports
+	 */
+	if (interrupts & TA_SYS_MASK)
+		ret = handle_temp_alert(base, emif);
+
+	if (interrupts & ERR_SYS_MASK)
+		dev_err(dev, "Access error from SYS port - %x\n", interrupts);
+
+	if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) {
+		/* Save the status and clear it */
+		interrupts = readl(base + EMIF_LL_OCP_INTERRUPT_STATUS);
+		writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_STATUS);
+
+		if (interrupts & ERR_LL_MASK)
+			dev_err(dev, "Access error from LL port - %x\n",
+				interrupts);
+	}
+
+	return ret;
+}
+
+static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
+{
+	struct emif_data	*emif = dev_id;
+
+	if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
+		dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
+		kernel_power_off();
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&emif_lock, irq_state);
+
+	if (emif->curr_regs) {
+		setup_temperature_sensitive_regs(emif, emif->curr_regs);
+		do_freq_update();
+	} else {
+		dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n");
+	}
+
+	spin_unlock_irqrestore(&emif_lock, irq_state);
+
+	return IRQ_HANDLED;
+}
+
+static void clear_all_interrupts(struct emif_data *emif)
+{
+	void __iomem	*base = emif->base;
+
+	writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS),
+		base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS);
+	if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE)
+		writel(readl(base + EMIF_LL_OCP_INTERRUPT_STATUS),
+			base + EMIF_LL_OCP_INTERRUPT_STATUS);
+}
+
+static void disable_and_clear_all_interrupts(struct emif_data *emif)
+{
+	void __iomem		*base = emif->base;
+
+	/* Disable all interrupts */
+	writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET),
+		base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR);
+	if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE)
+		writel(readl(base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET),
+			base + EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR);
+
+	/* Clear all interrupts */
+	clear_all_interrupts(emif);
+}
+
+static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq)
+{
+	u32		interrupts, type;
+	void __iomem	*base = emif->base;
+
+	type = emif->plat_data->device_info->type;
+
+	clear_all_interrupts(emif);
+
+	/* Enable interrupts for SYS interface */
+	interrupts = EN_ERR_SYS_MASK;
+	if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4)
+		interrupts |= EN_TA_SYS_MASK;
+	writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET);
+
+	/* Enable interrupts for LL interface */
+	if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) {
+		/* TA need not be enabled for LL */
+		interrupts = EN_ERR_LL_MASK;
+		writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET);
+	}
+
+	/* setup IRQ handlers */
+	return devm_request_threaded_irq(emif->dev, irq,
+				    emif_interrupt_handler,
+				    emif_threaded_isr,
+				    0, dev_name(emif->dev),
+				    emif);
+
+}
+
+static void __init_or_module emif_onetime_settings(struct emif_data *emif)
+{
+	u32				pwr_mgmt_ctrl, zq, temp_alert_cfg;
+	void __iomem			*base = emif->base;
+	const struct lpddr2_addressing	*addressing;
+	const struct ddr_device_info	*device_info;
+
+	device_info = emif->plat_data->device_info;
+	addressing = get_addressing_table(device_info);
+
+	/*
+	 * Init power management settings
+	 * We don't know the frequency yet. Use a high frequency
+	 * value for a conservative timeout setting
+	 */
+	pwr_mgmt_ctrl = get_pwr_mgmt_ctrl(1000000000, emif,
+			emif->plat_data->ip_rev);
+	emif->lpmode = (pwr_mgmt_ctrl & LP_MODE_MASK) >> LP_MODE_SHIFT;
+	writel(pwr_mgmt_ctrl, base + EMIF_POWER_MANAGEMENT_CONTROL);
+
+	/* Init ZQ calibration settings */
+	zq = get_zq_config_reg(addressing, device_info->cs1_used,
+		device_info->cal_resistors_per_cs);
+	writel(zq, base + EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG);
+
+	/* Check temperature level temperature level*/
+	get_temperature_level(emif);
+	if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN)
+		dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
+
+	/* Init temperature polling */
+	temp_alert_cfg = get_temp_alert_config(addressing,
+		emif->plat_data->custom_configs, device_info->cs1_used,
+		device_info->io_width, get_emif_bus_width(emif));
+	writel(temp_alert_cfg, base + EMIF_TEMPERATURE_ALERT_CONFIG);
+
+	/*
+	 * Program external PHY control registers that are not frequency
+	 * dependent
+	 */
+	if (emif->plat_data->phy_type != EMIF_PHY_TYPE_INTELLIPHY)
+		return;
+	writel(EMIF_EXT_PHY_CTRL_1_VAL, base + EMIF_EXT_PHY_CTRL_1_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_5_VAL, base + EMIF_EXT_PHY_CTRL_5_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_6_VAL, base + EMIF_EXT_PHY_CTRL_6_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_7_VAL, base + EMIF_EXT_PHY_CTRL_7_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_8_VAL, base + EMIF_EXT_PHY_CTRL_8_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_9_VAL, base + EMIF_EXT_PHY_CTRL_9_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_10_VAL, base + EMIF_EXT_PHY_CTRL_10_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_11_VAL, base + EMIF_EXT_PHY_CTRL_11_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_12_VAL, base + EMIF_EXT_PHY_CTRL_12_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_13_VAL, base + EMIF_EXT_PHY_CTRL_13_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_14_VAL, base + EMIF_EXT_PHY_CTRL_14_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_15_VAL, base + EMIF_EXT_PHY_CTRL_15_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_16_VAL, base + EMIF_EXT_PHY_CTRL_16_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_17_VAL, base + EMIF_EXT_PHY_CTRL_17_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_18_VAL, base + EMIF_EXT_PHY_CTRL_18_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_19_VAL, base + EMIF_EXT_PHY_CTRL_19_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_20_VAL, base + EMIF_EXT_PHY_CTRL_20_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_21_VAL, base + EMIF_EXT_PHY_CTRL_21_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_22_VAL, base + EMIF_EXT_PHY_CTRL_22_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_23_VAL, base + EMIF_EXT_PHY_CTRL_23_SHDW);
+	writel(EMIF_EXT_PHY_CTRL_24_VAL, base + EMIF_EXT_PHY_CTRL_24_SHDW);
+}
+
+static void get_default_timings(struct emif_data *emif)
+{
+	struct emif_platform_data *pd = emif->plat_data;
+
+	pd->timings		= lpddr2_jedec_timings;
+	pd->timings_arr_size	= ARRAY_SIZE(lpddr2_jedec_timings);
+
+	dev_warn(emif->dev, "%s: using default timings\n", __func__);
+}
+
+static int is_dev_data_valid(u32 type, u32 density, u32 io_width, u32 phy_type,
+		u32 ip_rev, struct device *dev)
+{
+	int valid;
+
+	valid = (type == DDR_TYPE_LPDDR2_S4 ||
+			type == DDR_TYPE_LPDDR2_S2)
+		&& (density >= DDR_DENSITY_64Mb
+			&& density <= DDR_DENSITY_8Gb)
+		&& (io_width >= DDR_IO_WIDTH_8
+			&& io_width <= DDR_IO_WIDTH_32);
+
+	/* Combinations of EMIF and PHY revisions that we support today */
+	switch (ip_rev) {
+	case EMIF_4D:
+		valid = valid && (phy_type == EMIF_PHY_TYPE_ATTILAPHY);
+		break;
+	case EMIF_4D5:
+		valid = valid && (phy_type == EMIF_PHY_TYPE_INTELLIPHY);
+		break;
+	default:
+		valid = 0;
+	}
+
+	if (!valid)
+		dev_err(dev, "%s: invalid DDR details\n", __func__);
+	return valid;
+}
+
+static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs,
+		struct device *dev)
+{
+	int valid = 1;
+
+	if ((cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE) &&
+		(cust_cfgs->lpmode != EMIF_LP_MODE_DISABLE))
+		valid = cust_cfgs->lpmode_freq_threshold &&
+			cust_cfgs->lpmode_timeout_performance &&
+			cust_cfgs->lpmode_timeout_power;
+
+	if (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL)
+		valid = valid && cust_cfgs->temp_alert_poll_interval_ms;
+
+	if (!valid)
+		dev_warn(dev, "%s: invalid custom configs\n", __func__);
+
+	return valid;
+}
+
+static struct emif_data *__init_or_module get_device_details(
+		struct platform_device *pdev)
+{
+	u32				size;
+	struct emif_data		*emif = NULL;
+	struct ddr_device_info		*dev_info;
+	struct emif_custom_configs	*cust_cfgs;
+	struct emif_platform_data	*pd;
+	struct device			*dev;
+	void				*temp;
+
+	pd = pdev->dev.platform_data;
+	dev = &pdev->dev;
+
+	if (!(pd && pd->device_info && is_dev_data_valid(pd->device_info->type,
+			pd->device_info->density, pd->device_info->io_width,
+			pd->phy_type, pd->ip_rev, dev))) {
+		dev_err(dev, "%s: invalid device data\n", __func__);
+		goto error;
+	}
+
+	emif	= devm_kzalloc(dev, sizeof(*emif), GFP_KERNEL);
+	temp	= devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL);
+
+	if (!emif || !pd || !dev_info) {
+		dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__);
+		goto error;
+	}
+
+	memcpy(temp, pd, sizeof(*pd));
+	pd = temp;
+	memcpy(dev_info, pd->device_info, sizeof(*dev_info));
+
+	pd->device_info		= dev_info;
+	emif->plat_data		= pd;
+	emif->dev		= dev;
+	emif->temperature_level	= SDRAM_TEMP_NOMINAL;
+
+	/*
+	 * For EMIF instances other than EMIF1 see if the devices connected
+	 * are exactly same as on EMIF1(which is typically the case). If so,
+	 * mark it as a duplicate of EMIF1 and skip copying timings data.
+	 * This will save some memory and some computation later.
+	 */
+	emif->duplicate = emif1 && (memcmp(dev_info,
+		emif1->plat_data->device_info,
+		sizeof(struct ddr_device_info)) == 0);
+
+	if (emif->duplicate) {
+		pd->timings = NULL;
+		pd->min_tck = NULL;
+		goto out;
+	} else if (emif1) {
+		dev_warn(emif->dev, "%s: Non-symmetric DDR geometry\n",
+			__func__);
+	}
+
+	/*
+	 * Copy custom configs - ignore allocation error, if any, as
+	 * custom_configs is not very critical
+	 */
+	cust_cfgs = pd->custom_configs;
+	if (cust_cfgs && is_custom_config_valid(cust_cfgs, dev)) {
+		temp = devm_kzalloc(dev, sizeof(*cust_cfgs), GFP_KERNEL);
+		if (temp)
+			memcpy(temp, cust_cfgs, sizeof(*cust_cfgs));
+		else
+			dev_warn(dev, "%s:%d: allocation error\n", __func__,
+				__LINE__);
+		pd->custom_configs = temp;
+	}
+
+	/*
+	 * Copy timings and min-tck values from platform data. If it is not
+	 * available or if memory allocation fails, use JEDEC defaults
+	 */
+	size = sizeof(struct lpddr2_timings) * pd->timings_arr_size;
+	if (pd->timings) {
+		temp = devm_kzalloc(dev, size, GFP_KERNEL);
+		if (temp) {
+			memcpy(temp, pd->timings, sizeof(*pd->timings));
+			pd->timings = temp;
+		} else {
+			dev_warn(dev, "%s:%d: allocation error\n", __func__,
+				__LINE__);
+			get_default_timings(emif);
+		}
+	} else {
+		get_default_timings(emif);
+	}
+
+	if (pd->min_tck) {
+		temp = devm_kzalloc(dev, sizeof(*pd->min_tck), GFP_KERNEL);
+		if (temp) {
+			memcpy(temp, pd->min_tck, sizeof(*pd->min_tck));
+			pd->min_tck = temp;
+		} else {
+			dev_warn(dev, "%s:%d: allocation error\n", __func__,
+				__LINE__);
+			pd->min_tck = &lpddr2_jedec_min_tck;
+		}
+	} else {
+		pd->min_tck = &lpddr2_jedec_min_tck;
+	}
+
+out:
+	return emif;
+
+error:
+	return NULL;
+}
+
+static int __init_or_module emif_probe(struct platform_device *pdev)
+{
+	struct emif_data	*emif;
+	struct resource		*res;
+	int			irq;
+
+	emif = get_device_details(pdev);
+	if (!emif) {
+		pr_err("%s: error getting device data\n", __func__);
+		goto error;
+	}
+
+	list_add(&emif->node, &device_list);
+	emif->addressing = get_addressing_table(emif->plat_data->device_info);
+
+	/* Save pointers to each other in emif and device structures */
+	emif->dev = &pdev->dev;
+	platform_set_drvdata(pdev, emif);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(emif->dev, "%s: error getting memory resource\n",
+			__func__);
+		goto error;
+	}
+
+	emif->base = devm_request_and_ioremap(emif->dev, res);
+	if (!emif->base) {
+		dev_err(emif->dev, "%s: devm_request_and_ioremap() failed\n",
+			__func__);
+		goto error;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(emif->dev, "%s: error getting IRQ resource - %d\n",
+			__func__, irq);
+		goto error;
+	}
+
+	emif_onetime_settings(emif);
+	emif_debugfs_init(emif);
+	disable_and_clear_all_interrupts(emif);
+	setup_interrupts(emif, irq);
+
+	/* One-time actions taken on probing the first device */
+	if (!emif1) {
+		emif1 = emif;
+		spin_lock_init(&emif_lock);
+
+		/*
+		 * TODO: register notifiers for frequency and voltage
+		 * change here once the respective frameworks are
+		 * available
+		 */
+	}
+
+	dev_info(&pdev->dev, "%s: device configured with addr = %p and IRQ%d\n",
+		__func__, emif->base, irq);
+
+	return 0;
+error:
+	return -ENODEV;
+}
+
+static int __exit emif_remove(struct platform_device *pdev)
+{
+	struct emif_data *emif = platform_get_drvdata(pdev);
+
+	emif_debugfs_exit(emif);
+
+	return 0;
+}
+
+static void emif_shutdown(struct platform_device *pdev)
+{
+	struct emif_data	*emif = platform_get_drvdata(pdev);
+
+	disable_and_clear_all_interrupts(emif);
+}
+
+static int get_emif_reg_values(struct emif_data *emif, u32 freq,
+		struct emif_regs *regs)
+{
+	u32				cs1_used, ip_rev, phy_type;
+	u32				cl, type;
+	const struct lpddr2_timings	*timings;
+	const struct lpddr2_min_tck	*min_tck;
+	const struct ddr_device_info	*device_info;
+	const struct lpddr2_addressing	*addressing;
+	struct emif_data		*emif_for_calc;
+	struct device			*dev;
+	const struct emif_custom_configs *custom_configs;
+
+	dev = emif->dev;
+	/*
+	 * If the devices on this EMIF instance is duplicate of EMIF1,
+	 * use EMIF1 details for the calculation
+	 */
+	emif_for_calc	= emif->duplicate ? emif1 : emif;
+	timings		= get_timings_table(emif_for_calc, freq);
+	addressing	= emif_for_calc->addressing;
+	if (!timings || !addressing) {
+		dev_err(dev, "%s: not enough data available for %dHz",
+			__func__, freq);
+		return -1;
+	}
+
+	device_info	= emif_for_calc->plat_data->device_info;
+	type		= device_info->type;
+	cs1_used	= device_info->cs1_used;
+	ip_rev		= emif_for_calc->plat_data->ip_rev;
+	phy_type	= emif_for_calc->plat_data->phy_type;
+
+	min_tck		= emif_for_calc->plat_data->min_tck;
+	custom_configs	= emif_for_calc->plat_data->custom_configs;
+
+	set_ddr_clk_period(freq);
+
+	regs->ref_ctrl_shdw = get_sdram_ref_ctrl_shdw(freq, addressing);
+	regs->sdram_tim1_shdw = get_sdram_tim_1_shdw(timings, min_tck,
+			addressing);
+	regs->sdram_tim2_shdw = get_sdram_tim_2_shdw(timings, min_tck,
+			addressing, type);
+	regs->sdram_tim3_shdw = get_sdram_tim_3_shdw(timings, min_tck,
+		addressing, type, ip_rev, EMIF_NORMAL_TIMINGS);
+
+	cl = get_cl(emif);
+
+	if (phy_type == EMIF_PHY_TYPE_ATTILAPHY && ip_rev == EMIF_4D) {
+		regs->phy_ctrl_1_shdw = get_ddr_phy_ctrl_1_attilaphy_4d(
+			timings, freq, cl);
+	} else if (phy_type == EMIF_PHY_TYPE_INTELLIPHY && ip_rev == EMIF_4D5) {
+		regs->phy_ctrl_1_shdw = get_phy_ctrl_1_intelliphy_4d5(freq, cl);
+		regs->ext_phy_ctrl_2_shdw = get_ext_phy_ctrl_2_intelliphy_4d5();
+		regs->ext_phy_ctrl_3_shdw = get_ext_phy_ctrl_3_intelliphy_4d5();
+		regs->ext_phy_ctrl_4_shdw = get_ext_phy_ctrl_4_intelliphy_4d5();
+	} else {
+		return -1;
+	}
+
+	/* Only timeout values in pwr_mgmt_ctrl_shdw register */
+	regs->pwr_mgmt_ctrl_shdw =
+		get_pwr_mgmt_ctrl(freq, emif_for_calc, ip_rev) &
+		(CS_TIM_MASK | SR_TIM_MASK | PD_TIM_MASK);
+
+	if (ip_rev & EMIF_4D) {
+		regs->read_idle_ctrl_shdw_normal =
+			get_read_idle_ctrl_shdw(DDR_VOLTAGE_STABLE);
+
+		regs->read_idle_ctrl_shdw_volt_ramp =
+			get_read_idle_ctrl_shdw(DDR_VOLTAGE_RAMPING);
+	} else if (ip_rev & EMIF_4D5) {
+		regs->dll_calib_ctrl_shdw_normal =
+			get_dll_calib_ctrl_shdw(DDR_VOLTAGE_STABLE);
+
+		regs->dll_calib_ctrl_shdw_volt_ramp =
+			get_dll_calib_ctrl_shdw(DDR_VOLTAGE_RAMPING);
+	}
+
+	if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) {
+		regs->ref_ctrl_shdw_derated = get_sdram_ref_ctrl_shdw(freq / 4,
+			addressing);
+
+		regs->sdram_tim1_shdw_derated =
+			get_sdram_tim_1_shdw_derated(timings, min_tck,
+				addressing);
+
+		regs->sdram_tim3_shdw_derated = get_sdram_tim_3_shdw(timings,
+			min_tck, addressing, type, ip_rev,
+			EMIF_DERATED_TIMINGS);
+	}
+
+	regs->freq = freq;
+
+	return 0;
+}
+
+/*
+ * get_regs() - gets the cached emif_regs structure for a given EMIF instance
+ * given frequency(freq):
+ *
+ * As an optimisation, every EMIF instance other than EMIF1 shares the
+ * register cache with EMIF1 if the devices connected on this instance
+ * are same as that on EMIF1(indicated by the duplicate flag)
+ *
+ * If we do not have an entry corresponding to the frequency given, we
+ * allocate a new entry and calculate the values
+ *
+ * Upon finding the right reg dump, save it in curr_regs. It can be
+ * directly used for thermal de-rating and voltage ramping changes.
+ */
+static struct emif_regs *get_regs(struct emif_data *emif, u32 freq)
+{
+	int			i;
+	struct emif_regs	**regs_cache;
+	struct emif_regs	*regs = NULL;
+	struct device		*dev;
+
+	dev = emif->dev;
+	if (emif->curr_regs && emif->curr_regs->freq == freq) {
+		dev_dbg(dev, "%s: using curr_regs - %u Hz", __func__, freq);
+		return emif->curr_regs;
+	}
+
+	if (emif->duplicate)
+		regs_cache = emif1->regs_cache;
+	else
+		regs_cache = emif->regs_cache;
+
+	for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) {
+		if (regs_cache[i]->freq == freq) {
+			regs = regs_cache[i];
+			dev_dbg(dev,
+				"%s: reg dump found in reg cache for %u Hz\n",
+				__func__, freq);
+			break;
+		}
+	}
+
+	/*
+	 * If we don't have an entry for this frequency in the cache create one
+	 * and calculate the values
+	 */
+	if (!regs) {
+		regs = devm_kzalloc(emif->dev, sizeof(*regs), GFP_ATOMIC);
+		if (!regs)
+			return NULL;
+
+		if (get_emif_reg_values(emif, freq, regs)) {
+			devm_kfree(emif->dev, regs);
+			return NULL;
+		}
+
+		/*
+		 * Now look for an un-used entry in the cache and save the
+		 * newly created struct. If there are no free entries
+		 * over-write the last entry
+		 */
+		for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++)
+			;
+
+		if (i >= EMIF_MAX_NUM_FREQUENCIES) {
+			dev_warn(dev, "%s: regs_cache full - reusing a slot!!\n",
+				__func__);
+			i = EMIF_MAX_NUM_FREQUENCIES - 1;
+			devm_kfree(emif->dev, regs_cache[i]);
+		}
+		regs_cache[i] = regs;
+	}
+
+	return regs;
+}
+
+static void do_volt_notify_handling(struct emif_data *emif, u32 volt_state)
+{
+	dev_dbg(emif->dev, "%s: voltage notification : %d", __func__,
+		volt_state);
+
+	if (!emif->curr_regs) {
+		dev_err(emif->dev,
+			"%s: volt-notify before registers are ready: %d\n",
+			__func__, volt_state);
+		return;
+	}
+
+	setup_volt_sensitive_regs(emif, emif->curr_regs, volt_state);
+}
+
+/*
+ * TODO: voltage notify handling should be hooked up to
+ * regulator framework as soon as the necessary support
+ * is available in mainline kernel. This function is un-used
+ * right now.
+ */
+static void __attribute__((unused)) volt_notify_handling(u32 volt_state)
+{
+	struct emif_data *emif;
+
+	spin_lock_irqsave(&emif_lock, irq_state);
+
+	list_for_each_entry(emif, &device_list, node)
+		do_volt_notify_handling(emif, volt_state);
+	do_freq_update();
+
+	spin_unlock_irqrestore(&emif_lock, irq_state);
+}
+
+static void do_freq_pre_notify_handling(struct emif_data *emif, u32 new_freq)
+{
+	struct emif_regs *regs;
+
+	regs = get_regs(emif, new_freq);
+	if (!regs)
+		return;
+
+	emif->curr_regs = regs;
+
+	/*
+	 * Update the shadow registers:
+	 * Temperature and voltage-ramp sensitive settings are also configured
+	 * in terms of DDR cycles. So, we need to update them too when there
+	 * is a freq change
+	 */
+	dev_dbg(emif->dev, "%s: setting up shadow registers for %uHz",
+		__func__, new_freq);
+	setup_registers(emif, regs);
+	setup_temperature_sensitive_regs(emif, regs);
+	setup_volt_sensitive_regs(emif, regs, DDR_VOLTAGE_STABLE);
+
+	/*
+	 * Part of workaround for errata i728. See do_freq_update()
+	 * for more details
+	 */
+	if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+		set_lpmode(emif, EMIF_LP_MODE_DISABLE);
+}
+
+/*
+ * TODO: frequency notify handling should be hooked up to
+ * clock framework as soon as the necessary support is
+ * available in mainline kernel. This function is un-used
+ * right now.
+ */
+static void __attribute__((unused)) freq_pre_notify_handling(u32 new_freq)
+{
+	struct emif_data *emif;
+
+	/*
+	 * NOTE: we are taking the spin-lock here and releases it
+	 * only in post-notifier. This doesn't look good and
+	 * Sparse complains about it, but this seems to be
+	 * un-avoidable. We need to lock a sequence of events
+	 * that is split between EMIF and clock framework.
+	 *
+	 * 1. EMIF driver updates EMIF timings in shadow registers in the
+	 *    frequency pre-notify callback from clock framework
+	 * 2. clock framework sets up the registers for the new frequency
+	 * 3. clock framework initiates a hw-sequence that updates
+	 *    the frequency EMIF timings synchronously.
+	 *
+	 * All these 3 steps should be performed as an atomic operation
+	 * vis-a-vis similar sequence in the EMIF interrupt handler
+	 * for temperature events. Otherwise, there could be race
+	 * conditions that could result in incorrect EMIF timings for
+	 * a given frequency
+	 */
+	spin_lock_irqsave(&emif_lock, irq_state);
+
+	list_for_each_entry(emif, &device_list, node)
+		do_freq_pre_notify_handling(emif, new_freq);
+}
+
+static void do_freq_post_notify_handling(struct emif_data *emif)
+{
+	/*
+	 * Part of workaround for errata i728. See do_freq_update()
+	 * for more details
+	 */
+	if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+		set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH);
+}
+
+/*
+ * TODO: frequency notify handling should be hooked up to
+ * clock framework as soon as the necessary support is
+ * available in mainline kernel. This function is un-used
+ * right now.
+ */
+static void __attribute__((unused)) freq_post_notify_handling(void)
+{
+	struct emif_data *emif;
+
+	list_for_each_entry(emif, &device_list, node)
+		do_freq_post_notify_handling(emif);
+
+	/*
+	 * Lock is done in pre-notify handler. See freq_pre_notify_handling()
+	 * for more details
+	 */
+	spin_unlock_irqrestore(&emif_lock, irq_state);
+}
+
+static struct platform_driver emif_driver = {
+	.remove		= __exit_p(emif_remove),
+	.shutdown	= emif_shutdown,
+	.driver = {
+		.name = "emif",
+	},
+};
+
+static int __init_or_module emif_register(void)
+{
+	return platform_driver_probe(&emif_driver, emif_probe);
+}
+
+static void __exit emif_unregister(void)
+{
+	platform_driver_unregister(&emif_driver);
+}
+
+module_init(emif_register);
+module_exit(emif_unregister);
+MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:emif");
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h
new file mode 100644
index 0000000..bfe08ba
--- /dev/null
+++ b/drivers/memory/emif.h
@@ -0,0 +1,589 @@
+/*
+ * Defines for the EMIF driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@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.
+ */
+#ifndef __EMIF_H
+#define __EMIF_H
+
+/*
+ * Maximum number of different frequencies supported by EMIF driver
+ * Determines the number of entries in the pointer array for register
+ * cache
+ */
+#define EMIF_MAX_NUM_FREQUENCIES			6
+
+/* State of the core voltage */
+#define DDR_VOLTAGE_STABLE				0
+#define DDR_VOLTAGE_RAMPING				1
+
+/* Defines for timing De-rating */
+#define EMIF_NORMAL_TIMINGS				0
+#define EMIF_DERATED_TIMINGS				1
+
+/* Length of the forced read idle period in terms of cycles */
+#define EMIF_READ_IDLE_LEN_VAL				5
+
+/*
+ * forced read idle interval to be used when voltage
+ * is changed as part of DVFS/DPS - 1ms
+ */
+#define READ_IDLE_INTERVAL_DVFS				(1*1000000)
+
+/*
+ * Forced read idle interval to be used when voltage is stable
+ * 50us - or maximum value will do
+ */
+#define READ_IDLE_INTERVAL_NORMAL			(50*1000000)
+
+/* DLL calibration interval when voltage is NOT stable - 1us */
+#define DLL_CALIB_INTERVAL_DVFS				(1*1000000)
+
+#define DLL_CALIB_ACK_WAIT_VAL				5
+
+/* Interval between ZQCS commands - hw team recommended value */
+#define EMIF_ZQCS_INTERVAL_US				(50*1000)
+/* Enable ZQ Calibration on exiting Self-refresh */
+#define ZQ_SFEXITEN_ENABLE				1
+/*
+ * ZQ Calibration simultaneously on both chip-selects:
+ * Needs one calibration resistor per CS
+ */
+#define	ZQ_DUALCALEN_DISABLE				0
+#define	ZQ_DUALCALEN_ENABLE				1
+
+#define T_ZQCS_DEFAULT_NS				90
+#define T_ZQCL_DEFAULT_NS				360
+#define T_ZQINIT_DEFAULT_NS				1000
+
+/* DPD_EN */
+#define DPD_DISABLE					0
+#define DPD_ENABLE					1
+
+/*
+ * Default values for the low-power entry to be used if not provided by user.
+ * OMAP4/5 has a hw bug(i735) due to which this value can not be less than 512
+ * Timeout values are in DDR clock 'cycles' and frequency threshold in Hz
+ */
+#define EMIF_LP_MODE_TIMEOUT_PERFORMANCE		2048
+#define EMIF_LP_MODE_TIMEOUT_POWER			512
+#define EMIF_LP_MODE_FREQ_THRESHOLD			400000000
+
+/* DDR_PHY_CTRL_1 values for EMIF4D - ATTILA PHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY		0x049FF000
+#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY	0x41
+#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY	0x80
+#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF
+
+/* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY		0x0E084200
+#define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS	10000
+
+/* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */
+#define TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS		360
+
+#define EMIF_T_CSTA					3
+#define EMIF_T_PDLL_UL					128
+
+/* External PHY control registers magic values */
+#define EMIF_EXT_PHY_CTRL_1_VAL				0x04020080
+#define EMIF_EXT_PHY_CTRL_5_VAL				0x04010040
+#define EMIF_EXT_PHY_CTRL_6_VAL				0x01004010
+#define EMIF_EXT_PHY_CTRL_7_VAL				0x00001004
+#define EMIF_EXT_PHY_CTRL_8_VAL				0x04010040
+#define EMIF_EXT_PHY_CTRL_9_VAL				0x01004010
+#define EMIF_EXT_PHY_CTRL_10_VAL			0x00001004
+#define EMIF_EXT_PHY_CTRL_11_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_12_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_13_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_14_VAL			0x80080080
+#define EMIF_EXT_PHY_CTRL_15_VAL			0x00800800
+#define EMIF_EXT_PHY_CTRL_16_VAL			0x08102040
+#define EMIF_EXT_PHY_CTRL_17_VAL			0x00000001
+#define EMIF_EXT_PHY_CTRL_18_VAL			0x540A8150
+#define EMIF_EXT_PHY_CTRL_19_VAL			0xA81502A0
+#define EMIF_EXT_PHY_CTRL_20_VAL			0x002A0540
+#define EMIF_EXT_PHY_CTRL_21_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_22_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_23_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_24_VAL			0x00000077
+
+#define EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS	1200
+
+/* Registers offset */
+#define EMIF_MODULE_ID_AND_REVISION			0x0000
+#define EMIF_STATUS					0x0004
+#define EMIF_SDRAM_CONFIG				0x0008
+#define EMIF_SDRAM_CONFIG_2				0x000c
+#define EMIF_SDRAM_REFRESH_CONTROL			0x0010
+#define EMIF_SDRAM_REFRESH_CTRL_SHDW			0x0014
+#define EMIF_SDRAM_TIMING_1				0x0018
+#define EMIF_SDRAM_TIMING_1_SHDW			0x001c
+#define EMIF_SDRAM_TIMING_2				0x0020
+#define EMIF_SDRAM_TIMING_2_SHDW			0x0024
+#define EMIF_SDRAM_TIMING_3				0x0028
+#define EMIF_SDRAM_TIMING_3_SHDW			0x002c
+#define EMIF_LPDDR2_NVM_TIMING				0x0030
+#define EMIF_LPDDR2_NVM_TIMING_SHDW			0x0034
+#define EMIF_POWER_MANAGEMENT_CONTROL			0x0038
+#define EMIF_POWER_MANAGEMENT_CTRL_SHDW			0x003c
+#define EMIF_LPDDR2_MODE_REG_DATA			0x0040
+#define EMIF_LPDDR2_MODE_REG_CONFIG			0x0050
+#define EMIF_OCP_CONFIG					0x0054
+#define EMIF_OCP_CONFIG_VALUE_1				0x0058
+#define EMIF_OCP_CONFIG_VALUE_2				0x005c
+#define EMIF_IODFT_TEST_LOGIC_GLOBAL_CONTROL		0x0060
+#define EMIF_IODFT_TEST_LOGIC_CTRL_MISR_RESULT		0x0064
+#define EMIF_IODFT_TEST_LOGIC_ADDRESS_MISR_RESULT	0x0068
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_1	0x006c
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_2	0x0070
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_3	0x0074
+#define EMIF_PERFORMANCE_COUNTER_1			0x0080
+#define EMIF_PERFORMANCE_COUNTER_2			0x0084
+#define EMIF_PERFORMANCE_COUNTER_CONFIG			0x0088
+#define EMIF_PERFORMANCE_COUNTER_MASTER_REGION_SELECT	0x008c
+#define EMIF_PERFORMANCE_COUNTER_TIME			0x0090
+#define EMIF_MISC_REG					0x0094
+#define EMIF_DLL_CALIB_CTRL				0x0098
+#define EMIF_DLL_CALIB_CTRL_SHDW			0x009c
+#define EMIF_END_OF_INTERRUPT				0x00a0
+#define EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS		0x00a4
+#define EMIF_LL_OCP_INTERRUPT_RAW_STATUS		0x00a8
+#define EMIF_SYSTEM_OCP_INTERRUPT_STATUS		0x00ac
+#define EMIF_LL_OCP_INTERRUPT_STATUS			0x00b0
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET		0x00b4
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_SET		0x00b8
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR		0x00bc
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR		0x00c0
+#define EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG	0x00c8
+#define EMIF_TEMPERATURE_ALERT_CONFIG			0x00cc
+#define EMIF_OCP_ERROR_LOG				0x00d0
+#define EMIF_READ_WRITE_LEVELING_RAMP_WINDOW		0x00d4
+#define EMIF_READ_WRITE_LEVELING_RAMP_CONTROL		0x00d8
+#define EMIF_READ_WRITE_LEVELING_CONTROL		0x00dc
+#define EMIF_DDR_PHY_CTRL_1				0x00e4
+#define EMIF_DDR_PHY_CTRL_1_SHDW			0x00e8
+#define EMIF_DDR_PHY_CTRL_2				0x00ec
+#define EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING	0x0100
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING 0x0104
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING 0x0108
+#define EMIF_READ_WRITE_EXECUTION_THRESHOLD		0x0120
+#define EMIF_COS_CONFIG					0x0124
+#define EMIF_PHY_STATUS_1				0x0140
+#define EMIF_PHY_STATUS_2				0x0144
+#define EMIF_PHY_STATUS_3				0x0148
+#define EMIF_PHY_STATUS_4				0x014c
+#define EMIF_PHY_STATUS_5				0x0150
+#define EMIF_PHY_STATUS_6				0x0154
+#define EMIF_PHY_STATUS_7				0x0158
+#define EMIF_PHY_STATUS_8				0x015c
+#define EMIF_PHY_STATUS_9				0x0160
+#define EMIF_PHY_STATUS_10				0x0164
+#define EMIF_PHY_STATUS_11				0x0168
+#define EMIF_PHY_STATUS_12				0x016c
+#define EMIF_PHY_STATUS_13				0x0170
+#define EMIF_PHY_STATUS_14				0x0174
+#define EMIF_PHY_STATUS_15				0x0178
+#define EMIF_PHY_STATUS_16				0x017c
+#define EMIF_PHY_STATUS_17				0x0180
+#define EMIF_PHY_STATUS_18				0x0184
+#define EMIF_PHY_STATUS_19				0x0188
+#define EMIF_PHY_STATUS_20				0x018c
+#define EMIF_PHY_STATUS_21				0x0190
+#define EMIF_EXT_PHY_CTRL_1				0x0200
+#define EMIF_EXT_PHY_CTRL_1_SHDW			0x0204
+#define EMIF_EXT_PHY_CTRL_2				0x0208
+#define EMIF_EXT_PHY_CTRL_2_SHDW			0x020c
+#define EMIF_EXT_PHY_CTRL_3				0x0210
+#define EMIF_EXT_PHY_CTRL_3_SHDW			0x0214
+#define EMIF_EXT_PHY_CTRL_4				0x0218
+#define EMIF_EXT_PHY_CTRL_4_SHDW			0x021c
+#define EMIF_EXT_PHY_CTRL_5				0x0220
+#define EMIF_EXT_PHY_CTRL_5_SHDW			0x0224
+#define EMIF_EXT_PHY_CTRL_6				0x0228
+#define EMIF_EXT_PHY_CTRL_6_SHDW			0x022c
+#define EMIF_EXT_PHY_CTRL_7				0x0230
+#define EMIF_EXT_PHY_CTRL_7_SHDW			0x0234
+#define EMIF_EXT_PHY_CTRL_8				0x0238
+#define EMIF_EXT_PHY_CTRL_8_SHDW			0x023c
+#define EMIF_EXT_PHY_CTRL_9				0x0240
+#define EMIF_EXT_PHY_CTRL_9_SHDW			0x0244
+#define EMIF_EXT_PHY_CTRL_10				0x0248
+#define EMIF_EXT_PHY_CTRL_10_SHDW			0x024c
+#define EMIF_EXT_PHY_CTRL_11				0x0250
+#define EMIF_EXT_PHY_CTRL_11_SHDW			0x0254
+#define EMIF_EXT_PHY_CTRL_12				0x0258
+#define EMIF_EXT_PHY_CTRL_12_SHDW			0x025c
+#define EMIF_EXT_PHY_CTRL_13				0x0260
+#define EMIF_EXT_PHY_CTRL_13_SHDW			0x0264
+#define EMIF_EXT_PHY_CTRL_14				0x0268
+#define EMIF_EXT_PHY_CTRL_14_SHDW			0x026c
+#define EMIF_EXT_PHY_CTRL_15				0x0270
+#define EMIF_EXT_PHY_CTRL_15_SHDW			0x0274
+#define EMIF_EXT_PHY_CTRL_16				0x0278
+#define EMIF_EXT_PHY_CTRL_16_SHDW			0x027c
+#define EMIF_EXT_PHY_CTRL_17				0x0280
+#define EMIF_EXT_PHY_CTRL_17_SHDW			0x0284
+#define EMIF_EXT_PHY_CTRL_18				0x0288
+#define EMIF_EXT_PHY_CTRL_18_SHDW			0x028c
+#define EMIF_EXT_PHY_CTRL_19				0x0290
+#define EMIF_EXT_PHY_CTRL_19_SHDW			0x0294
+#define EMIF_EXT_PHY_CTRL_20				0x0298
+#define EMIF_EXT_PHY_CTRL_20_SHDW			0x029c
+#define EMIF_EXT_PHY_CTRL_21				0x02a0
+#define EMIF_EXT_PHY_CTRL_21_SHDW			0x02a4
+#define EMIF_EXT_PHY_CTRL_22				0x02a8
+#define EMIF_EXT_PHY_CTRL_22_SHDW			0x02ac
+#define EMIF_EXT_PHY_CTRL_23				0x02b0
+#define EMIF_EXT_PHY_CTRL_23_SHDW			0x02b4
+#define EMIF_EXT_PHY_CTRL_24				0x02b8
+#define EMIF_EXT_PHY_CTRL_24_SHDW			0x02bc
+#define EMIF_EXT_PHY_CTRL_25				0x02c0
+#define EMIF_EXT_PHY_CTRL_25_SHDW			0x02c4
+#define EMIF_EXT_PHY_CTRL_26				0x02c8
+#define EMIF_EXT_PHY_CTRL_26_SHDW			0x02cc
+#define EMIF_EXT_PHY_CTRL_27				0x02d0
+#define EMIF_EXT_PHY_CTRL_27_SHDW			0x02d4
+#define EMIF_EXT_PHY_CTRL_28				0x02d8
+#define EMIF_EXT_PHY_CTRL_28_SHDW			0x02dc
+#define EMIF_EXT_PHY_CTRL_29				0x02e0
+#define EMIF_EXT_PHY_CTRL_29_SHDW			0x02e4
+#define EMIF_EXT_PHY_CTRL_30				0x02e8
+#define EMIF_EXT_PHY_CTRL_30_SHDW			0x02ec
+
+/* Registers shifts and masks */
+
+/* EMIF_MODULE_ID_AND_REVISION */
+#define SCHEME_SHIFT					30
+#define SCHEME_MASK					(0x3 << 30)
+#define MODULE_ID_SHIFT					16
+#define MODULE_ID_MASK					(0xfff << 16)
+#define RTL_VERSION_SHIFT				11
+#define RTL_VERSION_MASK				(0x1f << 11)
+#define MAJOR_REVISION_SHIFT				8
+#define MAJOR_REVISION_MASK				(0x7 << 8)
+#define MINOR_REVISION_SHIFT				0
+#define MINOR_REVISION_MASK				(0x3f << 0)
+
+/* STATUS */
+#define BE_SHIFT					31
+#define BE_MASK						(1 << 31)
+#define DUAL_CLK_MODE_SHIFT				30
+#define DUAL_CLK_MODE_MASK				(1 << 30)
+#define FAST_INIT_SHIFT					29
+#define FAST_INIT_MASK					(1 << 29)
+#define RDLVLGATETO_SHIFT				6
+#define RDLVLGATETO_MASK				(1 << 6)
+#define RDLVLTO_SHIFT					5
+#define RDLVLTO_MASK					(1 << 5)
+#define WRLVLTO_SHIFT					4
+#define WRLVLTO_MASK					(1 << 4)
+#define PHY_DLL_READY_SHIFT				2
+#define PHY_DLL_READY_MASK				(1 << 2)
+
+/* SDRAM_CONFIG */
+#define SDRAM_TYPE_SHIFT				29
+#define SDRAM_TYPE_MASK					(0x7 << 29)
+#define IBANK_POS_SHIFT					27
+#define IBANK_POS_MASK					(0x3 << 27)
+#define DDR_TERM_SHIFT					24
+#define DDR_TERM_MASK					(0x7 << 24)
+#define DDR2_DDQS_SHIFT					23
+#define DDR2_DDQS_MASK					(1 << 23)
+#define DYN_ODT_SHIFT					21
+#define DYN_ODT_MASK					(0x3 << 21)
+#define DDR_DISABLE_DLL_SHIFT				20
+#define DDR_DISABLE_DLL_MASK				(1 << 20)
+#define SDRAM_DRIVE_SHIFT				18
+#define SDRAM_DRIVE_MASK				(0x3 << 18)
+#define CWL_SHIFT					16
+#define CWL_MASK					(0x3 << 16)
+#define NARROW_MODE_SHIFT				14
+#define NARROW_MODE_MASK				(0x3 << 14)
+#define CL_SHIFT					10
+#define CL_MASK						(0xf << 10)
+#define ROWSIZE_SHIFT					7
+#define ROWSIZE_MASK					(0x7 << 7)
+#define IBANK_SHIFT					4
+#define IBANK_MASK					(0x7 << 4)
+#define EBANK_SHIFT					3
+#define EBANK_MASK					(1 << 3)
+#define PAGESIZE_SHIFT					0
+#define PAGESIZE_MASK					(0x7 << 0)
+
+/* SDRAM_CONFIG_2 */
+#define CS1NVMEN_SHIFT					30
+#define CS1NVMEN_MASK					(1 << 30)
+#define EBANK_POS_SHIFT					27
+#define EBANK_POS_MASK					(1 << 27)
+#define RDBNUM_SHIFT					4
+#define RDBNUM_MASK					(0x3 << 4)
+#define RDBSIZE_SHIFT					0
+#define RDBSIZE_MASK					(0x7 << 0)
+
+/* SDRAM_REFRESH_CONTROL */
+#define INITREF_DIS_SHIFT				31
+#define INITREF_DIS_MASK				(1 << 31)
+#define SRT_SHIFT					29
+#define SRT_MASK					(1 << 29)
+#define ASR_SHIFT					28
+#define ASR_MASK					(1 << 28)
+#define PASR_SHIFT					24
+#define PASR_MASK					(0x7 << 24)
+#define REFRESH_RATE_SHIFT				0
+#define REFRESH_RATE_MASK				(0xffff << 0)
+
+/* SDRAM_TIMING_1 */
+#define T_RTW_SHIFT					29
+#define T_RTW_MASK					(0x7 << 29)
+#define T_RP_SHIFT					25
+#define T_RP_MASK					(0xf << 25)
+#define T_RCD_SHIFT					21
+#define T_RCD_MASK					(0xf << 21)
+#define T_WR_SHIFT					17
+#define T_WR_MASK					(0xf << 17)
+#define T_RAS_SHIFT					12
+#define T_RAS_MASK					(0x1f << 12)
+#define T_RC_SHIFT					6
+#define T_RC_MASK					(0x3f << 6)
+#define T_RRD_SHIFT					3
+#define T_RRD_MASK					(0x7 << 3)
+#define T_WTR_SHIFT					0
+#define T_WTR_MASK					(0x7 << 0)
+
+/* SDRAM_TIMING_2 */
+#define T_XP_SHIFT					28
+#define T_XP_MASK					(0x7 << 28)
+#define T_ODT_SHIFT					25
+#define T_ODT_MASK					(0x7 << 25)
+#define T_XSNR_SHIFT					16
+#define T_XSNR_MASK					(0x1ff << 16)
+#define T_XSRD_SHIFT					6
+#define T_XSRD_MASK					(0x3ff << 6)
+#define T_RTP_SHIFT					3
+#define T_RTP_MASK					(0x7 << 3)
+#define T_CKE_SHIFT					0
+#define T_CKE_MASK					(0x7 << 0)
+
+/* SDRAM_TIMING_3 */
+#define T_PDLL_UL_SHIFT					28
+#define T_PDLL_UL_MASK					(0xf << 28)
+#define T_CSTA_SHIFT					24
+#define T_CSTA_MASK					(0xf << 24)
+#define T_CKESR_SHIFT					21
+#define T_CKESR_MASK					(0x7 << 21)
+#define ZQ_ZQCS_SHIFT					15
+#define ZQ_ZQCS_MASK					(0x3f << 15)
+#define T_TDQSCKMAX_SHIFT				13
+#define T_TDQSCKMAX_MASK				(0x3 << 13)
+#define T_RFC_SHIFT					4
+#define T_RFC_MASK					(0x1ff << 4)
+#define T_RAS_MAX_SHIFT					0
+#define T_RAS_MAX_MASK					(0xf << 0)
+
+/* POWER_MANAGEMENT_CONTROL */
+#define PD_TIM_SHIFT					12
+#define PD_TIM_MASK					(0xf << 12)
+#define DPD_EN_SHIFT					11
+#define DPD_EN_MASK					(1 << 11)
+#define LP_MODE_SHIFT					8
+#define LP_MODE_MASK					(0x7 << 8)
+#define SR_TIM_SHIFT					4
+#define SR_TIM_MASK					(0xf << 4)
+#define CS_TIM_SHIFT					0
+#define CS_TIM_MASK					(0xf << 0)
+
+/* LPDDR2_MODE_REG_DATA */
+#define VALUE_0_SHIFT					0
+#define VALUE_0_MASK					(0x7f << 0)
+
+/* LPDDR2_MODE_REG_CONFIG */
+#define CS_SHIFT					31
+#define CS_MASK						(1 << 31)
+#define REFRESH_EN_SHIFT				30
+#define REFRESH_EN_MASK					(1 << 30)
+#define ADDRESS_SHIFT					0
+#define ADDRESS_MASK					(0xff << 0)
+
+/* OCP_CONFIG */
+#define SYS_THRESH_MAX_SHIFT				24
+#define SYS_THRESH_MAX_MASK				(0xf << 24)
+#define MPU_THRESH_MAX_SHIFT				20
+#define MPU_THRESH_MAX_MASK				(0xf << 20)
+#define LL_THRESH_MAX_SHIFT				16
+#define LL_THRESH_MAX_MASK				(0xf << 16)
+
+/* PERFORMANCE_COUNTER_1 */
+#define COUNTER1_SHIFT					0
+#define COUNTER1_MASK					(0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_2 */
+#define COUNTER2_SHIFT					0
+#define COUNTER2_MASK					(0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_CONFIG */
+#define CNTR2_MCONNID_EN_SHIFT				31
+#define CNTR2_MCONNID_EN_MASK				(1 << 31)
+#define CNTR2_REGION_EN_SHIFT				30
+#define CNTR2_REGION_EN_MASK				(1 << 30)
+#define CNTR2_CFG_SHIFT					16
+#define CNTR2_CFG_MASK					(0xf << 16)
+#define CNTR1_MCONNID_EN_SHIFT				15
+#define CNTR1_MCONNID_EN_MASK				(1 << 15)
+#define CNTR1_REGION_EN_SHIFT				14
+#define CNTR1_REGION_EN_MASK				(1 << 14)
+#define CNTR1_CFG_SHIFT					0
+#define CNTR1_CFG_MASK					(0xf << 0)
+
+/* PERFORMANCE_COUNTER_MASTER_REGION_SELECT */
+#define MCONNID2_SHIFT					24
+#define MCONNID2_MASK					(0xff << 24)
+#define REGION_SEL2_SHIFT				16
+#define REGION_SEL2_MASK				(0x3 << 16)
+#define MCONNID1_SHIFT					8
+#define MCONNID1_MASK					(0xff << 8)
+#define REGION_SEL1_SHIFT				0
+#define REGION_SEL1_MASK				(0x3 << 0)
+
+/* PERFORMANCE_COUNTER_TIME */
+#define TOTAL_TIME_SHIFT				0
+#define TOTAL_TIME_MASK					(0xffffffff << 0)
+
+/* DLL_CALIB_CTRL */
+#define ACK_WAIT_SHIFT					16
+#define ACK_WAIT_MASK					(0xf << 16)
+#define DLL_CALIB_INTERVAL_SHIFT			0
+#define DLL_CALIB_INTERVAL_MASK				(0x1ff << 0)
+
+/* END_OF_INTERRUPT */
+#define EOI_SHIFT					0
+#define EOI_MASK					(1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_SYS_SHIFT					2
+#define DNV_SYS_MASK					(1 << 2)
+#define TA_SYS_SHIFT					1
+#define TA_SYS_MASK					(1 << 1)
+#define ERR_SYS_SHIFT					0
+#define ERR_SYS_MASK					(1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_LL_SHIFT					2
+#define DNV_LL_MASK					(1 << 2)
+#define TA_LL_SHIFT					1
+#define TA_LL_MASK					(1 << 1)
+#define ERR_LL_SHIFT					0
+#define ERR_LL_MASK					(1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_SYS_SHIFT				2
+#define EN_DNV_SYS_MASK					(1 << 2)
+#define EN_TA_SYS_SHIFT					1
+#define EN_TA_SYS_MASK					(1 << 1)
+#define EN_ERR_SYS_SHIFT					0
+#define EN_ERR_SYS_MASK					(1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_LL_SHIFT					2
+#define EN_DNV_LL_MASK					(1 << 2)
+#define EN_TA_LL_SHIFT					1
+#define EN_TA_LL_MASK					(1 << 1)
+#define EN_ERR_LL_SHIFT					0
+#define EN_ERR_LL_MASK					(1 << 0)
+
+/* SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG */
+#define ZQ_CS1EN_SHIFT					31
+#define ZQ_CS1EN_MASK					(1 << 31)
+#define ZQ_CS0EN_SHIFT					30
+#define ZQ_CS0EN_MASK					(1 << 30)
+#define ZQ_DUALCALEN_SHIFT				29
+#define ZQ_DUALCALEN_MASK				(1 << 29)
+#define ZQ_SFEXITEN_SHIFT				28
+#define ZQ_SFEXITEN_MASK				(1 << 28)
+#define ZQ_ZQINIT_MULT_SHIFT				18
+#define ZQ_ZQINIT_MULT_MASK				(0x3 << 18)
+#define ZQ_ZQCL_MULT_SHIFT				16
+#define ZQ_ZQCL_MULT_MASK				(0x3 << 16)
+#define ZQ_REFINTERVAL_SHIFT				0
+#define ZQ_REFINTERVAL_MASK				(0xffff << 0)
+
+/* TEMPERATURE_ALERT_CONFIG */
+#define TA_CS1EN_SHIFT					31
+#define TA_CS1EN_MASK					(1 << 31)
+#define TA_CS0EN_SHIFT					30
+#define TA_CS0EN_MASK					(1 << 30)
+#define TA_SFEXITEN_SHIFT				28
+#define TA_SFEXITEN_MASK				(1 << 28)
+#define TA_DEVWDT_SHIFT					26
+#define TA_DEVWDT_MASK					(0x3 << 26)
+#define TA_DEVCNT_SHIFT					24
+#define TA_DEVCNT_MASK					(0x3 << 24)
+#define TA_REFINTERVAL_SHIFT				0
+#define TA_REFINTERVAL_MASK				(0x3fffff << 0)
+
+/* OCP_ERROR_LOG */
+#define MADDRSPACE_SHIFT				14
+#define MADDRSPACE_MASK					(0x3 << 14)
+#define MBURSTSEQ_SHIFT					11
+#define MBURSTSEQ_MASK					(0x7 << 11)
+#define MCMD_SHIFT					8
+#define MCMD_MASK					(0x7 << 8)
+#define MCONNID_SHIFT					0
+#define MCONNID_MASK					(0xff << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D */
+#define DLL_SLAVE_DLY_CTRL_SHIFT_4D			4
+#define DLL_SLAVE_DLY_CTRL_MASK_4D			(0xFF << 4)
+#define READ_LATENCY_SHIFT_4D				0
+#define READ_LATENCY_MASK_4D				(0xf << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D5 */
+#define DLL_HALF_DELAY_SHIFT_4D5			21
+#define DLL_HALF_DELAY_MASK_4D5				(1 << 21)
+#define READ_LATENCY_SHIFT_4D5				0
+#define READ_LATENCY_MASK_4D5				(0x1f << 0)
+
+/* DDR_PHY_CTRL_1_SHDW */
+#define DDR_PHY_CTRL_1_SHDW_SHIFT			5
+#define DDR_PHY_CTRL_1_SHDW_MASK			(0x7ffffff << 5)
+#define READ_LATENCY_SHDW_SHIFT				0
+#define READ_LATENCY_SHDW_MASK				(0x1f << 0)
+
+#ifndef __ASSEMBLY__
+/*
+ * Structure containing shadow of important registers in EMIF
+ * The calculation function fills in this structure to be later used for
+ * initialisation and DVFS
+ */
+struct emif_regs {
+	u32 freq;
+	u32 ref_ctrl_shdw;
+	u32 ref_ctrl_shdw_derated;
+	u32 sdram_tim1_shdw;
+	u32 sdram_tim1_shdw_derated;
+	u32 sdram_tim2_shdw;
+	u32 sdram_tim3_shdw;
+	u32 sdram_tim3_shdw_derated;
+	u32 pwr_mgmt_ctrl_shdw;
+	union {
+		u32 read_idle_ctrl_shdw_normal;
+		u32 dll_calib_ctrl_shdw_normal;
+	};
+	union {
+		u32 read_idle_ctrl_shdw_volt_ramp;
+		u32 dll_calib_ctrl_shdw_volt_ramp;
+	};
+
+	u32 phy_ctrl_1_shdw;
+	u32 ext_phy_ctrl_2_shdw;
+	u32 ext_phy_ctrl_3_shdw;
+	u32 ext_phy_ctrl_4_shdw;
+};
+#endif /* __ASSEMBLY__ */
+#endif /* __EMIF_H */
diff --git a/drivers/memory/tegra20-mc.c b/drivers/memory/tegra20-mc.c
new file mode 100644
index 0000000..3ed49c1
--- /dev/null
+++ b/drivers/memory/tegra20-mc.c
@@ -0,0 +1,257 @@
+/*
+ * Tegra20 Memory Controller
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#define DRV_NAME "tegra20-mc"
+
+#define MC_INTSTATUS			0x0
+#define MC_INTMASK			0x4
+
+#define MC_INT_ERR_SHIFT		6
+#define MC_INT_ERR_MASK			(0x1f << MC_INT_ERR_SHIFT)
+#define MC_INT_DECERR_EMEM		BIT(MC_INT_ERR_SHIFT)
+#define MC_INT_INVALID_GART_PAGE	BIT(MC_INT_ERR_SHIFT + 1)
+#define MC_INT_SECURITY_VIOLATION	BIT(MC_INT_ERR_SHIFT + 2)
+#define MC_INT_ARBITRATION_EMEM		BIT(MC_INT_ERR_SHIFT + 3)
+
+#define MC_GART_ERROR_REQ		0x30
+#define MC_DECERR_EMEM_OTHERS_STATUS	0x58
+#define MC_SECURITY_VIOLATION_STATUS	0x74
+
+#define SECURITY_VIOLATION_TYPE		BIT(30)	/* 0=TRUSTZONE, 1=CARVEOUT */
+
+#define MC_CLIENT_ID_MASK		0x3f
+
+#define NUM_MC_REG_BANKS		2
+
+struct tegra20_mc {
+	void __iomem *regs[NUM_MC_REG_BANKS];
+	struct device *dev;
+};
+
+static inline u32 mc_readl(struct tegra20_mc *mc, u32 offs)
+{
+	u32 val = 0;
+
+	if (offs < 0x24)
+		val = readl(mc->regs[0] + offs);
+	if (offs < 0x400)
+		val = readl(mc->regs[1] + offs - 0x3c);
+
+	return val;
+}
+
+static inline void mc_writel(struct tegra20_mc *mc, u32 val, u32 offs)
+{
+	if (offs < 0x24) {
+		writel(val, mc->regs[0] + offs);
+		return;
+	}
+	if (offs < 0x400) {
+		writel(val, mc->regs[1] + offs - 0x3c);
+		return;
+	}
+}
+
+static const char * const tegra20_mc_client[] = {
+	"cbr_display0a",
+	"cbr_display0ab",
+	"cbr_display0b",
+	"cbr_display0bb",
+	"cbr_display0c",
+	"cbr_display0cb",
+	"cbr_display1b",
+	"cbr_display1bb",
+	"cbr_eppup",
+	"cbr_g2pr",
+	"cbr_g2sr",
+	"cbr_mpeunifbr",
+	"cbr_viruv",
+	"csr_avpcarm7r",
+	"csr_displayhc",
+	"csr_displayhcb",
+	"csr_fdcdrd",
+	"csr_g2dr",
+	"csr_host1xdmar",
+	"csr_host1xr",
+	"csr_idxsrd",
+	"csr_mpcorer",
+	"csr_mpe_ipred",
+	"csr_mpeamemrd",
+	"csr_mpecsrd",
+	"csr_ppcsahbdmar",
+	"csr_ppcsahbslvr",
+	"csr_texsrd",
+	"csr_vdebsevr",
+	"csr_vdember",
+	"csr_vdemcer",
+	"csr_vdetper",
+	"cbw_eppu",
+	"cbw_eppv",
+	"cbw_eppy",
+	"cbw_mpeunifbw",
+	"cbw_viwsb",
+	"cbw_viwu",
+	"cbw_viwv",
+	"cbw_viwy",
+	"ccw_g2dw",
+	"csw_avpcarm7w",
+	"csw_fdcdwr",
+	"csw_host1xw",
+	"csw_ispw",
+	"csw_mpcorew",
+	"csw_mpecswr",
+	"csw_ppcsahbdmaw",
+	"csw_ppcsahbslvw",
+	"csw_vdebsevw",
+	"csw_vdembew",
+	"csw_vdetpmw",
+};
+
+static void tegra20_mc_decode(struct tegra20_mc *mc, int n)
+{
+	u32 addr, req;
+	const char *client = "Unknown";
+	int idx, cid;
+	const struct reg_info {
+		u32 offset;
+		u32 write_bit;	/* 0=READ, 1=WRITE */
+		int cid_shift;
+		char *message;
+	} reg[] = {
+		{
+			.offset = MC_DECERR_EMEM_OTHERS_STATUS,
+			.write_bit = 31,
+			.message = "MC_DECERR",
+		},
+		{
+			.offset	= MC_GART_ERROR_REQ,
+			.cid_shift = 1,
+			.message = "MC_GART_ERR",
+
+		},
+		{
+			.offset = MC_SECURITY_VIOLATION_STATUS,
+			.write_bit = 31,
+			.message = "MC_SECURITY_ERR",
+		},
+	};
+
+	idx = n - MC_INT_ERR_SHIFT;
+	if ((idx < 0) || (idx >= ARRAY_SIZE(reg))) {
+		dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
+				    BIT(n));
+		return;
+	}
+
+	req = mc_readl(mc, reg[idx].offset);
+	cid = (req >> reg[idx].cid_shift) & MC_CLIENT_ID_MASK;
+	if (cid < ARRAY_SIZE(tegra20_mc_client))
+		client = tegra20_mc_client[cid];
+
+	addr = mc_readl(mc, reg[idx].offset + sizeof(u32));
+
+	dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s)\n",
+			   reg[idx].message, req, addr, client,
+			   (req & BIT(reg[idx].write_bit)) ? "write" : "read",
+			   (reg[idx].offset == MC_SECURITY_VIOLATION_STATUS) ?
+			   ((req & SECURITY_VIOLATION_TYPE) ?
+			    "carveout" : "trustzone") : "");
+}
+
+static const struct of_device_id tegra20_mc_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra20-mc", },
+	{},
+};
+
+static irqreturn_t tegra20_mc_isr(int irq, void *data)
+{
+	u32 stat, mask, bit;
+	struct tegra20_mc *mc = data;
+
+	stat = mc_readl(mc, MC_INTSTATUS);
+	mask = mc_readl(mc, MC_INTMASK);
+	mask &= stat;
+	if (!mask)
+		return IRQ_NONE;
+	while ((bit = ffs(mask)) != 0)
+		tegra20_mc_decode(mc, bit - 1);
+	mc_writel(mc, stat, MC_INTSTATUS);
+	return IRQ_HANDLED;
+}
+
+static int __devinit tegra20_mc_probe(struct platform_device *pdev)
+{
+	struct resource *irq;
+	struct tegra20_mc *mc;
+	int i, err;
+	u32 intmask;
+
+	mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
+	if (!mc)
+		return -ENOMEM;
+	mc->dev = &pdev->dev;
+
+	for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
+		struct resource *res;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res)
+			return -ENODEV;
+		mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
+		if (!mc->regs[i])
+			return -EBUSY;
+	}
+
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq)
+		return -ENODEV;
+	err = devm_request_irq(&pdev->dev, irq->start, tegra20_mc_isr,
+			       IRQF_SHARED, dev_name(&pdev->dev), mc);
+	if (err)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, mc);
+
+	intmask = MC_INT_INVALID_GART_PAGE |
+		MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
+	mc_writel(mc, intmask, MC_INTMASK);
+	return 0;
+}
+
+static struct platform_driver tegra20_mc_driver = {
+	.probe = tegra20_mc_probe,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = tegra20_mc_of_match,
+	},
+};
+module_platform_driver(tegra20_mc_driver);
+
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 MC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c
new file mode 100644
index 0000000..e56ff04
--- /dev/null
+++ b/drivers/memory/tegra30-mc.c
@@ -0,0 +1,382 @@
+/*
+ * Tegra30 Memory Controller
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#define DRV_NAME "tegra30-mc"
+
+#define MC_INTSTATUS			0x0
+#define MC_INTMASK			0x4
+
+#define MC_INT_ERR_SHIFT		6
+#define MC_INT_ERR_MASK			(0x1f << MC_INT_ERR_SHIFT)
+#define MC_INT_DECERR_EMEM		BIT(MC_INT_ERR_SHIFT)
+#define MC_INT_SECURITY_VIOLATION	BIT(MC_INT_ERR_SHIFT + 2)
+#define MC_INT_ARBITRATION_EMEM		BIT(MC_INT_ERR_SHIFT + 3)
+#define MC_INT_INVALID_SMMU_PAGE	BIT(MC_INT_ERR_SHIFT + 4)
+
+#define MC_ERR_STATUS			0x8
+#define MC_ERR_ADR			0xc
+
+#define MC_ERR_TYPE_SHIFT		28
+#define MC_ERR_TYPE_MASK		(7 << MC_ERR_TYPE_SHIFT)
+#define MC_ERR_TYPE_DECERR_EMEM		2
+#define MC_ERR_TYPE_SECURITY_TRUSTZONE	3
+#define MC_ERR_TYPE_SECURITY_CARVEOUT	4
+#define MC_ERR_TYPE_INVALID_SMMU_PAGE	6
+
+#define MC_ERR_INVALID_SMMU_PAGE_SHIFT	25
+#define MC_ERR_INVALID_SMMU_PAGE_MASK	(7 << MC_ERR_INVALID_SMMU_PAGE_SHIFT)
+#define MC_ERR_RW_SHIFT			16
+#define MC_ERR_RW			BIT(MC_ERR_RW_SHIFT)
+#define MC_ERR_SECURITY			BIT(MC_ERR_RW_SHIFT + 1)
+
+#define SECURITY_VIOLATION_TYPE		BIT(30)	/* 0=TRUSTZONE, 1=CARVEOUT */
+
+#define MC_EMEM_ARB_CFG			0x90
+#define MC_EMEM_ARB_OUTSTANDING_REQ	0x94
+#define MC_EMEM_ARB_TIMING_RCD		0x98
+#define MC_EMEM_ARB_TIMING_RP		0x9c
+#define MC_EMEM_ARB_TIMING_RC		0xa0
+#define MC_EMEM_ARB_TIMING_RAS		0xa4
+#define MC_EMEM_ARB_TIMING_FAW		0xa8
+#define MC_EMEM_ARB_TIMING_RRD		0xac
+#define MC_EMEM_ARB_TIMING_RAP2PRE	0xb0
+#define MC_EMEM_ARB_TIMING_WAP2PRE	0xb4
+#define MC_EMEM_ARB_TIMING_R2R		0xb8
+#define MC_EMEM_ARB_TIMING_W2W		0xbc
+#define MC_EMEM_ARB_TIMING_R2W		0xc0
+#define MC_EMEM_ARB_TIMING_W2R		0xc4
+
+#define MC_EMEM_ARB_DA_TURNS		0xd0
+#define MC_EMEM_ARB_DA_COVERS		0xd4
+#define MC_EMEM_ARB_MISC0		0xd8
+#define MC_EMEM_ARB_MISC1		0xdc
+
+#define MC_EMEM_ARB_RING3_THROTTLE	0xe4
+#define MC_EMEM_ARB_OVERRIDE		0xe8
+
+#define MC_TIMING_CONTROL		0xfc
+
+#define MC_CLIENT_ID_MASK		0x7f
+
+#define NUM_MC_REG_BANKS		4
+
+struct tegra30_mc {
+	void __iomem *regs[NUM_MC_REG_BANKS];
+	struct device *dev;
+	u32 ctx[0];
+};
+
+static inline u32 mc_readl(struct tegra30_mc *mc, u32 offs)
+{
+	u32 val = 0;
+
+	if (offs < 0x10)
+		val = readl(mc->regs[0] + offs);
+	if (offs < 0x1f0)
+		val = readl(mc->regs[1] + offs - 0x3c);
+	if (offs < 0x228)
+		val = readl(mc->regs[2] + offs - 0x200);
+	if (offs < 0x400)
+		val = readl(mc->regs[3] + offs - 0x284);
+
+	return val;
+}
+
+static inline void mc_writel(struct tegra30_mc *mc, u32 val, u32 offs)
+{
+	if (offs < 0x10) {
+		writel(val, mc->regs[0] + offs);
+		return;
+	}
+	if (offs < 0x1f0) {
+		writel(val, mc->regs[1] + offs - 0x3c);
+		return;
+	}
+	if (offs < 0x228) {
+		writel(val, mc->regs[2] + offs - 0x200);
+		return;
+	}
+	if (offs < 0x400) {
+		writel(val, mc->regs[3] + offs - 0x284);
+		return;
+	}
+}
+
+static const char * const tegra30_mc_client[] = {
+	"csr_ptcr",
+	"cbr_display0a",
+	"cbr_display0ab",
+	"cbr_display0b",
+	"cbr_display0bb",
+	"cbr_display0c",
+	"cbr_display0cb",
+	"cbr_display1b",
+	"cbr_display1bb",
+	"cbr_eppup",
+	"cbr_g2pr",
+	"cbr_g2sr",
+	"cbr_mpeunifbr",
+	"cbr_viruv",
+	"csr_afir",
+	"csr_avpcarm7r",
+	"csr_displayhc",
+	"csr_displayhcb",
+	"csr_fdcdrd",
+	"csr_fdcdrd2",
+	"csr_g2dr",
+	"csr_hdar",
+	"csr_host1xdmar",
+	"csr_host1xr",
+	"csr_idxsrd",
+	"csr_idxsrd2",
+	"csr_mpe_ipred",
+	"csr_mpeamemrd",
+	"csr_mpecsrd",
+	"csr_ppcsahbdmar",
+	"csr_ppcsahbslvr",
+	"csr_satar",
+	"csr_texsrd",
+	"csr_texsrd2",
+	"csr_vdebsevr",
+	"csr_vdember",
+	"csr_vdemcer",
+	"csr_vdetper",
+	"csr_mpcorelpr",
+	"csr_mpcorer",
+	"cbw_eppu",
+	"cbw_eppv",
+	"cbw_eppy",
+	"cbw_mpeunifbw",
+	"cbw_viwsb",
+	"cbw_viwu",
+	"cbw_viwv",
+	"cbw_viwy",
+	"ccw_g2dw",
+	"csw_afiw",
+	"csw_avpcarm7w",
+	"csw_fdcdwr",
+	"csw_fdcdwr2",
+	"csw_hdaw",
+	"csw_host1xw",
+	"csw_ispw",
+	"csw_mpcorelpw",
+	"csw_mpcorew",
+	"csw_mpecswr",
+	"csw_ppcsahbdmaw",
+	"csw_ppcsahbslvw",
+	"csw_sataw",
+	"csw_vdebsevw",
+	"csw_vdedbgw",
+	"csw_vdembew",
+	"csw_vdetpmw",
+};
+
+static void tegra30_mc_decode(struct tegra30_mc *mc, int n)
+{
+	u32 err, addr;
+	const char * const mc_int_err[] = {
+		"MC_DECERR",
+		"Unknown",
+		"MC_SECURITY_ERR",
+		"MC_ARBITRATION_EMEM",
+		"MC_SMMU_ERR",
+	};
+	const char * const err_type[] = {
+		"Unknown",
+		"Unknown",
+		"DECERR_EMEM",
+		"SECURITY_TRUSTZONE",
+		"SECURITY_CARVEOUT",
+		"Unknown",
+		"INVALID_SMMU_PAGE",
+		"Unknown",
+	};
+	char attr[6];
+	int cid, perm, type, idx;
+	const char *client = "Unknown";
+
+	idx = n - MC_INT_ERR_SHIFT;
+	if ((idx < 0) || (idx >= ARRAY_SIZE(mc_int_err)) || (idx == 1)) {
+		dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
+				    BIT(n));
+		return;
+	}
+
+	err = readl(mc + MC_ERR_STATUS);
+
+	type = (err & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT;
+	perm = (err & MC_ERR_INVALID_SMMU_PAGE_MASK) >>
+		MC_ERR_INVALID_SMMU_PAGE_SHIFT;
+	if (type == MC_ERR_TYPE_INVALID_SMMU_PAGE)
+		sprintf(attr, "%c-%c-%c",
+			(perm & BIT(2)) ? 'R' : '-',
+			(perm & BIT(1)) ? 'W' : '-',
+			(perm & BIT(0)) ? 'S' : '-');
+	else
+		attr[0] = '\0';
+
+	cid = err & MC_CLIENT_ID_MASK;
+	if (cid < ARRAY_SIZE(tegra30_mc_client))
+		client = tegra30_mc_client[cid];
+
+	addr = readl(mc + MC_ERR_ADR);
+
+	dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s %s %s)\n",
+			   mc_int_err[idx], err, addr, client,
+			   (err & MC_ERR_SECURITY) ? "secure" : "non-secure",
+			   (err & MC_ERR_RW) ? "write" : "read",
+			   err_type[type], attr);
+}
+
+static const u32 tegra30_mc_ctx[] = {
+	MC_EMEM_ARB_CFG,
+	MC_EMEM_ARB_OUTSTANDING_REQ,
+	MC_EMEM_ARB_TIMING_RCD,
+	MC_EMEM_ARB_TIMING_RP,
+	MC_EMEM_ARB_TIMING_RC,
+	MC_EMEM_ARB_TIMING_RAS,
+	MC_EMEM_ARB_TIMING_FAW,
+	MC_EMEM_ARB_TIMING_RRD,
+	MC_EMEM_ARB_TIMING_RAP2PRE,
+	MC_EMEM_ARB_TIMING_WAP2PRE,
+	MC_EMEM_ARB_TIMING_R2R,
+	MC_EMEM_ARB_TIMING_W2W,
+	MC_EMEM_ARB_TIMING_R2W,
+	MC_EMEM_ARB_TIMING_W2R,
+	MC_EMEM_ARB_DA_TURNS,
+	MC_EMEM_ARB_DA_COVERS,
+	MC_EMEM_ARB_MISC0,
+	MC_EMEM_ARB_MISC1,
+	MC_EMEM_ARB_RING3_THROTTLE,
+	MC_EMEM_ARB_OVERRIDE,
+	MC_INTMASK,
+};
+
+static int tegra30_mc_suspend(struct device *dev)
+{
+	int i;
+	struct tegra30_mc *mc = dev_get_drvdata(dev);
+
+	for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
+		mc->ctx[i] = mc_readl(mc, tegra30_mc_ctx[i]);
+	return 0;
+}
+
+static int tegra30_mc_resume(struct device *dev)
+{
+	int i;
+	struct tegra30_mc *mc = dev_get_drvdata(dev);
+
+	for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
+		mc_writel(mc, mc->ctx[i], tegra30_mc_ctx[i]);
+
+	mc_writel(mc, 1, MC_TIMING_CONTROL);
+	/* Read-back to ensure that write reached */
+	mc_readl(mc, MC_TIMING_CONTROL);
+	return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
+			    tegra30_mc_suspend,
+			    tegra30_mc_resume, NULL);
+
+static const struct of_device_id tegra30_mc_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra30-mc", },
+	{},
+};
+
+static irqreturn_t tegra30_mc_isr(int irq, void *data)
+{
+	u32 stat, mask, bit;
+	struct tegra30_mc *mc = data;
+
+	stat = mc_readl(mc, MC_INTSTATUS);
+	mask = mc_readl(mc, MC_INTMASK);
+	mask &= stat;
+	if (!mask)
+		return IRQ_NONE;
+	while ((bit = ffs(mask)) != 0)
+		tegra30_mc_decode(mc, bit - 1);
+	mc_writel(mc, stat, MC_INTSTATUS);
+	return IRQ_HANDLED;
+}
+
+static int __devinit tegra30_mc_probe(struct platform_device *pdev)
+{
+	struct resource *irq;
+	struct tegra30_mc *mc;
+	size_t bytes;
+	int err, i;
+	u32 intmask;
+
+	bytes = sizeof(*mc) + sizeof(u32) * ARRAY_SIZE(tegra30_mc_ctx);
+	mc = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL);
+	if (!mc)
+		return -ENOMEM;
+	mc->dev = &pdev->dev;
+
+	for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
+		struct resource *res;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res)
+			return -ENODEV;
+		mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
+		if (!mc->regs[i])
+			return -EBUSY;
+	}
+
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq)
+		return -ENODEV;
+	err = devm_request_irq(&pdev->dev, irq->start, tegra30_mc_isr,
+			       IRQF_SHARED, dev_name(&pdev->dev), mc);
+	if (err)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, mc);
+
+	intmask = MC_INT_INVALID_SMMU_PAGE |
+		MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
+	mc_writel(mc, intmask, MC_INTMASK);
+	return 0;
+}
+
+static struct platform_driver tegra30_mc_driver = {
+	.probe = tegra30_mc_probe,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = tegra30_mc_of_match,
+		.pm = &tegra30_mc_pm,
+	},
+};
+module_platform_driver(tegra30_mc_driver);
+
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 MC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
index 6d115c7..506c36f 100644
--- a/drivers/message/i2o/i2o_proc.c
+++ b/drivers/message/i2o/i2o_proc.c
@@ -283,7 +283,6 @@
 	"Local Bus",
 	"ISA",
 	"EISA",
-	"MCA",
 	"PCI",
 	"PCMCIA",
 	"NUBUS",
@@ -351,18 +350,6 @@
 					   EisaSlotNumber);
 				break;
 
-			case I2O_BUS_MCA:
-				seq_printf(seq, "     IOBase: %0#6x,",
-					   hrt->hrt_entry[i].bus.mca_bus.
-					   McaBaseIOPort);
-				seq_printf(seq, " MemoryBase: %0#10x,",
-					   hrt->hrt_entry[i].bus.mca_bus.
-					   McaBaseMemoryAddress);
-				seq_printf(seq, " Slot: %0#4x,",
-					   hrt->hrt_entry[i].bus.mca_bus.
-					   McaSlotNumber);
-				break;
-
 			case I2O_BUS_PCI:
 				seq_printf(seq, "     Bus: %0#4x",
 					   hrt->hrt_entry[i].bus.pci_bus.
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b5a0032..f4b4dad 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -377,7 +377,6 @@
 
 config MFD_DA9052_SPI
 	bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI"
-	select IRQ_DOMAIN
 	select REGMAP_SPI
 	select REGMAP_IRQ
 	select PMIC_DA9052
@@ -390,7 +389,6 @@
 
 config MFD_DA9052_I2C
 	bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C"
-	select IRQ_DOMAIN
 	select REGMAP_I2C
 	select REGMAP_IRQ
 	select PMIC_DA9052
@@ -417,7 +415,7 @@
 	select MFD_CORE
 	help
 	  Say yes here to support for Maxim Semiconductor MAX8925. This is
-	  a Power Management IC. This driver provies common support for
+	  a Power Management IC. This driver provides common support for
 	  accessing the device, additional drivers must be enabled in order
 	  to use the functionality of the device.
 
@@ -440,7 +438,7 @@
 	help
 	  Say yes here to support for Maxim Semiconductor MAX8998 and
 	  National Semiconductor LP3974. This is a Power Management IC.
-	  This driver provies common support for accessing the device,
+	  This driver provides common support for accessing the device,
 	  additional drivers must be enabled in order to use the functionality
 	  of the device.
 
@@ -451,7 +449,7 @@
 	select REGMAP_I2C
 	help
 	 Support for the Samsung Electronics S5M MFD series.
-	 This driver provies common support for accessing the device,
+	 This driver provides common support for accessing the device,
 	 additional drivers must be enabled in order to use the functionality
 	 of the device
 
@@ -561,7 +559,6 @@
 	bool "Support Wolfson Microelectronics WM8994"
 	select MFD_CORE
 	select REGMAP_I2C
-	select IRQ_DOMAIN
 	select REGMAP_IRQ
 	depends on I2C=y && GENERIC_HARDIRQS
 	help
@@ -652,23 +649,6 @@
 	  This enables the PCAP ASIC present on EZX Phones. This is
 	  needed for MMC, TouchScreen, Sound, USB, etc..
 
-config AB5500_CORE
-	bool "ST-Ericsson AB5500 Mixed Signal Power Management chip"
-	depends on ABX500_CORE && MFD_DB5500_PRCMU
-	select MFD_CORE
-	help
-	  Select this option to enable access to AB5500 power management
-	  chip. This connects to the db5500 chip via the I2C bus via PRCMU.
-	  This chip embeds various other multimedia funtionalities as well.
-
-config AB5500_DEBUG
-	bool "Enable debug info via debugfs"
-	depends on AB5500_CORE && DEBUG_FS
-	default y if DEBUG_FS
-	help
-	  Select this option if you want debug information from the AB5500
-	  using the debug filesystem, debugfs.
-
 config AB8500_CORE
 	bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
 	depends on GENERIC_HARDIRQS && ABX500_CORE
@@ -715,16 +695,6 @@
 	  system controller running an XP70 microprocessor, which is accessed
 	  through a register map.
 
-config MFD_DB5500_PRCMU
-	bool "ST-Ericsson DB5500 Power Reset Control Management Unit"
-	depends on UX500_SOC_DB5500
-	select MFD_CORE
-	help
-	  Select this option to enable support for the DB5500 Power Reset
-	  and Control Management Unit. This is basically an autonomous
-	  system controller running an XP70 microprocessor, which is accessed
-	  through a register map.
-
 config MFD_CS5535
 	tristate "Support for CS5535 and CS5536 southbridge core functions"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 77293e1..43672b8 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -87,15 +87,12 @@
 obj-$(CONFIG_ABX500_CORE)	+= abx500-core.o
 obj-$(CONFIG_AB3100_CORE)	+= ab3100-core.o
 obj-$(CONFIG_AB3100_OTP)	+= ab3100-otp.o
-obj-$(CONFIG_AB5500_CORE)	+= ab5500-core.o
-obj-$(CONFIG_AB5500_DEBUG)	+= ab5500-debugfs.o
 obj-$(CONFIG_AB8500_CORE)	+= ab8500-core.o ab8500-sysctrl.o
 obj-$(CONFIG_AB8500_DEBUG)	+= ab8500-debugfs.o
 obj-$(CONFIG_AB8500_GPADC)	+= ab8500-gpadc.o
 obj-$(CONFIG_MFD_DB8500_PRCMU)	+= db8500-prcmu.o
 # ab8500-i2c need to come after db8500-prcmu (which provides the channel)
 obj-$(CONFIG_AB8500_I2C_CORE)	+= ab8500-i2c.o
-obj-$(CONFIG_MFD_DB5500_PRCMU)	+= db5500-prcmu.o
 obj-$(CONFIG_MFD_TIMBERDALE)    += timberdale.o
 obj-$(CONFIG_PMIC_ADP5520)	+= adp5520.o
 obj-$(CONFIG_LPC_SCH)		+= lpc_sch.o
diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c
deleted file mode 100644
index 54d0fe4..0000000
--- a/drivers/mfd/ab5500-core.c
+++ /dev/null
@@ -1,1439 +0,0 @@
-/*
- * Copyright (C) 2007-2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Low-level core for exclusive access to the AB5500 IC on the I2C bus
- * and some basic chip-configuration.
- * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- * Author: Mattias Wallin <mattias.wallin@stericsson.com>
- * Author: Rickard Andersson <rickard.andersson@stericsson.com>
- * Author: Karl Komierowski  <karl.komierowski@stericsson.com>
- * Author: Bibek Basu <bibek.basu@stericsson.com>
- *
- * TODO: Event handling with irq_chip. Waiting for PRCMU fw support.
- */
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/random.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab5500.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/db5500-prcmu.h>
-
-#include "ab5500-core.h"
-#include "ab5500-debugfs.h"
-
-#define AB5500_NUM_EVENT_REG 23
-#define AB5500_IT_LATCH0_REG 0x40
-#define AB5500_IT_MASK0_REG 0x60
-
-/*
- * Permissible register ranges for reading and writing per device and bank.
- *
- * The ranges must be listed in increasing address order, and no overlaps are
- * allowed. It is assumed that write permission implies read permission
- * (i.e. only RO and RW permissions should be used).  Ranges with write
- * permission must not be split up.
- */
-
-#define NO_RANGE {.count = 0, .range = NULL,}
-static struct ab5500_i2c_banks ab5500_bank_ranges[AB5500_NUM_DEVICES] = {
-	[AB5500_DEVID_USB] =  {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_USB,
-				.nranges = 12,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x01,
-						.last = 0x01,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x80,
-						.last = 0x83,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x87,
-						.last = 0x8A,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x8B,
-						.last = 0x8B,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0x91,
-						.last = 0x92,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0x93,
-						.last = 0x93,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x94,
-						.last = 0x94,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0xA8,
-						.last = 0xB0,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0xB2,
-						.last = 0xB2,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0xB4,
-						.last = 0xBC,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0xBF,
-						.last = 0xBF,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0xC1,
-						.last = 0xC5,
-						.perm = AB5500_PERM_RO,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_ADC] =  {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_ADC,
-				.nranges = 6,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x1F,
-						.last = 0x22,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0x23,
-						.last = 0x24,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x26,
-						.last = 0x2D,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0x2F,
-						.last = 0x34,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x37,
-						.last = 0x57,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x58,
-						.last = 0x58,
-						.perm = AB5500_PERM_RO,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_LEDS] =  {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_LED,
-				.nranges = 1,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x00,
-						.last = 0x0C,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_VIDEO] =   {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_VDENC,
-				.nranges = 12,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x00,
-						.last = 0x08,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x09,
-						.last = 0x09,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0x0A,
-						.last = 0x12,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x15,
-						.last = 0x19,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x1B,
-						.last = 0x21,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x27,
-						.last = 0x2C,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x41,
-						.last = 0x41,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x45,
-						.last = 0x5B,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x5D,
-						.last = 0x5D,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x69,
-						.last = 0x69,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x6C,
-						.last = 0x6D,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x80,
-						.last = 0x81,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_REGULATORS] =   {
-		.nbanks = 2,
-		.bank =  (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_STARTUP,
-				.nranges = 12,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x00,
-						.last = 0x01,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x1F,
-						.last = 0x1F,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x2E,
-						.last = 0x2E,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0x2F,
-						.last = 0x30,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x50,
-						.last = 0x51,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x60,
-						.last = 0x61,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x66,
-						.last = 0x8A,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x8C,
-						.last = 0x96,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0xAA,
-						.last = 0xB4,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0xB7,
-						.last = 0xBF,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0xC1,
-						.last = 0xCA,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0xD3,
-						.last = 0xE0,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-			{
-				.bankid = AB5500_BANK_SIM_USBSIM,
-				.nranges = 1,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x13,
-						.last = 0x19,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_SIM] =   {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_SIM_USBSIM,
-				.nranges = 1,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x13,
-						.last = 0x19,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_RTC] =   {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_RTC,
-				.nranges = 2,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x00,
-						.last = 0x04,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0x06,
-						.last = 0x0C,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_CHARGER] =   {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_CHG,
-				.nranges = 2,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x11,
-						.last = 0x11,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0x12,
-						.last = 0x1B,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_FUELGAUGE] =   {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_FG_BATTCOM_ACC,
-				.nranges = 2,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x00,
-						.last = 0x0B,
-						.perm = AB5500_PERM_RO,
-					},
-					{
-						.first = 0x0C,
-						.last = 0x10,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_VIBRATOR] =   {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_VIBRA,
-				.nranges = 2,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x10,
-						.last = 0x13,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0xFE,
-						.last = 0xFE,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_CODEC] =   {
-		.nbanks = 1,
-		.bank = (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_AUDIO_HEADSETUSB,
-				.nranges = 2,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x00,
-						.last = 0x48,
-						.perm = AB5500_PERM_RW,
-					},
-					{
-						.first = 0xEB,
-						.last = 0xFB,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-	[AB5500_DEVID_POWER] = {
-		.nbanks	= 2,
-		.bank	= (struct ab5500_i2c_ranges []) {
-			{
-				.bankid = AB5500_BANK_STARTUP,
-				.nranges = 1,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x30,
-						.last = 0x30,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-			{
-				.bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
-				.nranges = 1,
-				.range = (struct ab5500_reg_range[]) {
-					{
-						.first = 0x01,
-						.last = 0x01,
-						.perm = AB5500_PERM_RW,
-					},
-				},
-			},
-		},
-	},
-};
-
-#define AB5500_IRQ(bank, bit)	((bank) * 8 + (bit))
-
-/* I appologize for the resource names beeing a mix of upper case
- * and lower case but I want them to be exact as the documentation */
-static struct mfd_cell ab5500_devs[AB5500_NUM_DEVICES] = {
-	[AB5500_DEVID_LEDS] = {
-		.name = "ab5500-leds",
-		.id = AB5500_DEVID_LEDS,
-	},
-	[AB5500_DEVID_POWER] = {
-		.name = "ab5500-power",
-		.id = AB5500_DEVID_POWER,
-	},
-	[AB5500_DEVID_REGULATORS] = {
-		.name = "ab5500-regulator",
-		.id = AB5500_DEVID_REGULATORS,
-	},
-	[AB5500_DEVID_SIM] = {
-		.name = "ab5500-sim",
-		.id = AB5500_DEVID_SIM,
-		.num_resources = 1,
-		.resources = (struct resource[]) {
-			{
-				.name = "SIMOFF",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(2, 0), /*rising*/
-				.end = AB5500_IRQ(2, 1), /*falling*/
-			},
-		},
-	},
-	[AB5500_DEVID_RTC] = {
-		.name = "ab5500-rtc",
-		.id = AB5500_DEVID_RTC,
-		.num_resources = 1,
-		.resources = (struct resource[]) {
-			{
-				.name	= "RTC_Alarm",
-				.flags	= IORESOURCE_IRQ,
-				.start	= AB5500_IRQ(1, 7),
-				.end	= AB5500_IRQ(1, 7),
-			}
-		},
-	},
-	[AB5500_DEVID_CHARGER] = {
-		.name = "ab5500-charger",
-		.id = AB5500_DEVID_CHARGER,
-	},
-	[AB5500_DEVID_ADC] = {
-		.name = "ab5500-adc",
-		.id = AB5500_DEVID_ADC,
-		.num_resources = 10,
-		.resources = (struct resource[]) {
-			{
-				.name = "TRIGGER-0",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 0),
-				.end = AB5500_IRQ(0, 0),
-			},
-			{
-				.name = "TRIGGER-1",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 1),
-				.end = AB5500_IRQ(0, 1),
-			},
-			{
-				.name = "TRIGGER-2",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 2),
-				.end = AB5500_IRQ(0, 2),
-			},
-			{
-				.name = "TRIGGER-3",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 3),
-				.end = AB5500_IRQ(0, 3),
-			},
-			{
-				.name = "TRIGGER-4",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 4),
-				.end = AB5500_IRQ(0, 4),
-			},
-			{
-				.name = "TRIGGER-5",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 5),
-				.end = AB5500_IRQ(0, 5),
-			},
-			{
-				.name = "TRIGGER-6",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 6),
-				.end = AB5500_IRQ(0, 6),
-			},
-			{
-				.name = "TRIGGER-7",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 7),
-				.end = AB5500_IRQ(0, 7),
-			},
-			{
-				.name = "TRIGGER-VBAT",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 8),
-				.end = AB5500_IRQ(0, 8),
-			},
-			{
-				.name = "TRIGGER-VBAT-TXON",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(0, 9),
-				.end = AB5500_IRQ(0, 9),
-			},
-		},
-	},
-	[AB5500_DEVID_FUELGAUGE] = {
-		.name = "ab5500-fuelgauge",
-		.id = AB5500_DEVID_FUELGAUGE,
-		.num_resources = 6,
-		.resources = (struct resource[]) {
-			{
-				.name = "Batt_attach",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(7, 5),
-				.end = AB5500_IRQ(7, 5),
-			},
-			{
-				.name = "Batt_removal",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(7, 6),
-				.end = AB5500_IRQ(7, 6),
-			},
-			{
-				.name = "UART_framing",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(7, 7),
-				.end = AB5500_IRQ(7, 7),
-			},
-			{
-				.name = "UART_overrun",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(8, 0),
-				.end = AB5500_IRQ(8, 0),
-			},
-			{
-				.name = "UART_Rdy_RX",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(8, 1),
-				.end = AB5500_IRQ(8, 1),
-			},
-			{
-				.name = "UART_Rdy_TX",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(8, 2),
-				.end = AB5500_IRQ(8, 2),
-			},
-		},
-	},
-	[AB5500_DEVID_VIBRATOR] = {
-		.name = "ab5500-vibrator",
-		.id = AB5500_DEVID_VIBRATOR,
-	},
-	[AB5500_DEVID_CODEC] = {
-		.name = "ab5500-codec",
-		.id = AB5500_DEVID_CODEC,
-		.num_resources = 3,
-		.resources = (struct resource[]) {
-			{
-				.name = "audio_spkr1_ovc",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(9, 5),
-				.end = AB5500_IRQ(9, 5),
-			},
-			{
-				.name = "audio_plllocked",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(9, 6),
-				.end = AB5500_IRQ(9, 6),
-			},
-			{
-				.name = "audio_spkr2_ovc",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(17, 4),
-				.end = AB5500_IRQ(17, 4),
-			},
-		},
-	},
-	[AB5500_DEVID_USB] = {
-		.name = "ab5500-usb",
-		.id = AB5500_DEVID_USB,
-		.num_resources = 36,
-		.resources = (struct resource[]) {
-			{
-				.name = "Link_Update",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(22, 1),
-				.end = AB5500_IRQ(22, 1),
-			},
-			{
-				.name = "DCIO",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(8, 3),
-				.end = AB5500_IRQ(8, 4),
-			},
-			{
-				.name = "VBUS_R",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(8, 5),
-				.end = AB5500_IRQ(8, 5),
-			},
-			{
-				.name = "VBUS_F",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(8, 6),
-				.end = AB5500_IRQ(8, 6),
-			},
-			{
-				.name = "CHGstate_10_PCVBUSchg",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(8, 7),
-				.end = AB5500_IRQ(8, 7),
-			},
-			{
-				.name = "DCIOreverse_ovc",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(9, 0),
-				.end = AB5500_IRQ(9, 0),
-			},
-			{
-				.name = "USBCharDetDone",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(9, 1),
-				.end = AB5500_IRQ(9, 1),
-			},
-			{
-				.name = "DCIO_no_limit",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(9, 2),
-				.end = AB5500_IRQ(9, 2),
-			},
-			{
-				.name = "USB_suspend",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(9, 3),
-				.end = AB5500_IRQ(9, 3),
-			},
-			{
-				.name = "DCIOreverse_fwdcurrent",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(9, 4),
-				.end = AB5500_IRQ(9, 4),
-			},
-			{
-				.name = "Vbus_Imeasmax_change",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(9, 5),
-				.end = AB5500_IRQ(9, 6),
-			},
-			{
-				.name = "OVV",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(14, 5),
-				.end = AB5500_IRQ(14, 5),
-			},
-			{
-				.name = "USBcharging_NOTok",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(15, 3),
-				.end = AB5500_IRQ(15, 3),
-			},
-			{
-				.name = "usb_adp_sensoroff",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(15, 6),
-				.end = AB5500_IRQ(15, 6),
-			},
-			{
-				.name = "usb_adp_probeplug",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(15, 7),
-				.end = AB5500_IRQ(15, 7),
-			},
-			{
-				.name = "usb_adp_sinkerror",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(16, 0),
-				.end = AB5500_IRQ(16, 6),
-			},
-			{
-				.name = "usb_adp_sourceerror",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(16, 1),
-				.end = AB5500_IRQ(16, 1),
-			},
-			{
-				.name = "usb_idgnd_r",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(16, 2),
-				.end = AB5500_IRQ(16, 2),
-			},
-			{
-				.name = "usb_idgnd_f",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(16, 3),
-				.end = AB5500_IRQ(16, 3),
-			},
-			{
-				.name = "usb_iddetR1",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(16, 4),
-				.end = AB5500_IRQ(16, 5),
-			},
-			{
-				.name = "usb_iddetR2",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(16, 6),
-				.end = AB5500_IRQ(16, 7),
-			},
-			{
-				.name = "usb_iddetR3",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(17, 0),
-				.end = AB5500_IRQ(17, 1),
-			},
-			{
-				.name = "usb_iddetR4",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(17, 2),
-				.end = AB5500_IRQ(17, 3),
-			},
-			{
-				.name = "CharTempWindowOk",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(17, 7),
-				.end = AB5500_IRQ(18, 0),
-			},
-			{
-				.name = "USB_SprDetect",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(18, 1),
-				.end = AB5500_IRQ(18, 1),
-			},
-			{
-				.name = "usb_adp_probe_unplug",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(18, 2),
-				.end = AB5500_IRQ(18, 2),
-			},
-			{
-				.name = "VBUSChDrop",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(18, 3),
-				.end = AB5500_IRQ(18, 4),
-			},
-			{
-				.name = "dcio_char_rec_done",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(18, 5),
-				.end = AB5500_IRQ(18, 5),
-			},
-			{
-				.name = "Charging_stopped_by_temp",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(18, 6),
-				.end = AB5500_IRQ(18, 6),
-			},
-			{
-				.name = "CHGstate_11_SafeModeVBUS",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(21, 1),
-				.end = AB5500_IRQ(21, 2),
-			},
-			{
-				.name = "CHGstate_12_comletedVBUS",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(21, 2),
-				.end = AB5500_IRQ(21, 2),
-			},
-			{
-				.name = "CHGstate_13_completedVBUS",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(21, 3),
-				.end = AB5500_IRQ(21, 3),
-			},
-			{
-				.name = "CHGstate_14_FullChgDCIO",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(21, 4),
-				.end = AB5500_IRQ(21, 4),
-			},
-			{
-				.name = "CHGstate_15_SafeModeDCIO",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(21, 5),
-				.end = AB5500_IRQ(21, 5),
-			},
-			{
-				.name = "CHGstate_16_OFFsuspendDCIO",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(21, 6),
-				.end = AB5500_IRQ(21, 6),
-			},
-			{
-				.name = "CHGstate_17_completedDCIO",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(21, 7),
-				.end = AB5500_IRQ(21, 7),
-			},
-		},
-	},
-	[AB5500_DEVID_OTP] = {
-		.name = "ab5500-otp",
-		.id = AB5500_DEVID_OTP,
-	},
-	[AB5500_DEVID_VIDEO] = {
-		.name = "ab5500-video",
-		.id = AB5500_DEVID_VIDEO,
-		.num_resources = 1,
-		.resources = (struct resource[]) {
-			{
-				.name = "plugTVdet",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(22, 2),
-				.end = AB5500_IRQ(22, 2),
-			},
-		},
-	},
-	[AB5500_DEVID_DBIECI] = {
-		.name = "ab5500-dbieci",
-		.id = AB5500_DEVID_DBIECI,
-		.num_resources = 10,
-		.resources = (struct resource[]) {
-			{
-				.name = "COLL",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(14, 0),
-				.end = AB5500_IRQ(14, 0),
-			},
-			{
-				.name = "RESERR",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(14, 1),
-				.end = AB5500_IRQ(14, 1),
-			},
-			{
-				.name = "FRAERR",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(14, 2),
-				.end = AB5500_IRQ(14, 2),
-			},
-			{
-				.name = "COMERR",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(14, 3),
-				.end = AB5500_IRQ(14, 3),
-			},
-			{
-				.name = "BSI_indicator",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(14, 4),
-				.end = AB5500_IRQ(14, 4),
-			},
-			{
-				.name = "SPDSET",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(14, 6),
-				.end = AB5500_IRQ(14, 6),
-			},
-			{
-				.name = "DSENT",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(14, 7),
-				.end = AB5500_IRQ(14, 7),
-			},
-			{
-				.name = "DREC",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(15, 0),
-				.end = AB5500_IRQ(15, 0),
-			},
-			{
-				.name = "ACCINT",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(15, 1),
-				.end = AB5500_IRQ(15, 1),
-			},
-			{
-				.name = "NOPINT",
-				.flags = IORESOURCE_IRQ,
-				.start = AB5500_IRQ(15, 2),
-				.end = AB5500_IRQ(15, 2),
-			},
-		},
-	},
-	[AB5500_DEVID_ONSWA] = {
-		.name = "ab5500-onswa",
-		.id = AB5500_DEVID_ONSWA,
-		.num_resources = 2,
-		.resources = (struct resource[]) {
-			{
-				.name	= "ONSWAn_rising",
-				.flags	= IORESOURCE_IRQ,
-				.start	= AB5500_IRQ(1, 3),
-				.end	= AB5500_IRQ(1, 3),
-			},
-			{
-				.name	= "ONSWAn_falling",
-				.flags	= IORESOURCE_IRQ,
-				.start	= AB5500_IRQ(1, 4),
-				.end	= AB5500_IRQ(1, 4),
-			},
-		},
-	},
-};
-
-/*
- * Functionality for getting/setting register values.
- */
-int ab5500_get_register_interruptible_raw(struct ab5500 *ab,
-					  u8 bank, u8 reg,
-					  u8 *value)
-{
-	int err;
-
-	if (bank >= AB5500_NUM_BANKS)
-		return -EINVAL;
-
-	err = mutex_lock_interruptible(&ab->access_mutex);
-	if (err)
-		return err;
-	err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr, reg, value, 1);
-
-	mutex_unlock(&ab->access_mutex);
-	return err;
-}
-
-static int get_register_page_interruptible(struct ab5500 *ab, u8 bank,
-	u8 first_reg, u8 *regvals, u8 numregs)
-{
-	int err;
-
-	if (bank >= AB5500_NUM_BANKS)
-		return -EINVAL;
-
-	err = mutex_lock_interruptible(&ab->access_mutex);
-	if (err)
-		return err;
-
-	while (numregs) {
-		/* The hardware limit for get page is 4 */
-		u8 curnum = min_t(u8, numregs, 4u);
-
-		err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr,
-					    first_reg, regvals, curnum);
-		if (err)
-			goto out;
-
-		numregs -= curnum;
-		first_reg += curnum;
-		regvals += curnum;
-	}
-
-out:
-	mutex_unlock(&ab->access_mutex);
-	return err;
-}
-
-int ab5500_mask_and_set_register_interruptible_raw(struct ab5500 *ab, u8 bank,
-	u8 reg, u8 bitmask, u8 bitvalues)
-{
-	int err = 0;
-
-	if (bank >= AB5500_NUM_BANKS)
-		return -EINVAL;
-
-	if (bitmask) {
-		u8 buf;
-
-		err = mutex_lock_interruptible(&ab->access_mutex);
-		if (err)
-			return err;
-
-		if (bitmask == 0xFF) /* No need to read in this case. */
-			buf = bitvalues;
-		else { /* Read and modify the register value. */
-			err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr,
-				reg, &buf, 1);
-			if (err)
-				return err;
-
-			buf = ((~bitmask & buf) | (bitmask & bitvalues));
-		}
-		/* Write the new value. */
-		err = db5500_prcmu_abb_write(bankinfo[bank].slave_addr, reg,
-					     &buf, 1);
-
-		mutex_unlock(&ab->access_mutex);
-	}
-	return err;
-}
-
-static int
-set_register_interruptible(struct ab5500 *ab, u8 bank, u8 reg, u8 value)
-{
-	return ab5500_mask_and_set_register_interruptible_raw(ab, bank, reg,
-							      0xff, value);
-}
-
-/*
- * Read/write permission checking functions.
- */
-static const struct ab5500_i2c_ranges *get_bankref(u8 devid, u8 bank)
-{
-	u8 i;
-
-	if (devid < AB5500_NUM_DEVICES) {
-		for (i = 0; i < ab5500_bank_ranges[devid].nbanks; i++) {
-			if (ab5500_bank_ranges[devid].bank[i].bankid == bank)
-				return &ab5500_bank_ranges[devid].bank[i];
-		}
-	}
-	return NULL;
-}
-
-static bool page_write_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg)
-{
-	u8 i; /* range loop index */
-	const struct ab5500_i2c_ranges *bankref;
-
-	bankref = get_bankref(devid, bank);
-	if (bankref == NULL || last_reg < first_reg)
-		return false;
-
-	for (i = 0; i < bankref->nranges; i++) {
-		if (first_reg < bankref->range[i].first)
-			break;
-		if ((last_reg <= bankref->range[i].last) &&
-			(bankref->range[i].perm & AB5500_PERM_WR))
-			return true;
-	}
-	return false;
-}
-
-static bool reg_write_allowed(u8 devid, u8 bank, u8 reg)
-{
-	return page_write_allowed(devid, bank, reg, reg);
-}
-
-static bool page_read_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg)
-{
-	u8 i;
-	const struct ab5500_i2c_ranges *bankref;
-
-	bankref = get_bankref(devid, bank);
-	if (bankref == NULL || last_reg < first_reg)
-		return false;
-
-
-	/* Find the range (if it exists in the list) that includes first_reg. */
-	for (i = 0; i < bankref->nranges; i++) {
-		if (first_reg < bankref->range[i].first)
-			return false;
-		if (first_reg <= bankref->range[i].last)
-			break;
-	}
-	/* Make sure that the entire range up to and including last_reg is
-	 * readable. This may span several of the ranges in the list.
-	 */
-	while ((i < bankref->nranges) &&
-		(bankref->range[i].perm & AB5500_PERM_RD)) {
-		if (last_reg <= bankref->range[i].last)
-			return true;
-		if ((++i >= bankref->nranges) ||
-			(bankref->range[i].first !=
-				(bankref->range[i - 1].last + 1))) {
-			break;
-		}
-	}
-	return false;
-}
-
-static bool reg_read_allowed(u8 devid, u8 bank, u8 reg)
-{
-	return page_read_allowed(devid, bank, reg, reg);
-}
-
-
-/*
- * The exported register access functionality.
- */
-static int ab5500_get_chip_id(struct device *dev)
-{
-	struct ab5500 *ab = dev_get_drvdata(dev->parent);
-
-	return (int)ab->chip_id;
-}
-
-static int ab5500_mask_and_set_register_interruptible(struct device *dev,
-		u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
-{
-	struct ab5500 *ab;
-	struct platform_device *pdev = to_platform_device(dev);
-
-	if ((AB5500_NUM_BANKS <= bank) ||
-		!reg_write_allowed(pdev->id, bank, reg))
-		return -EINVAL;
-
-	ab = dev_get_drvdata(dev->parent);
-	return ab5500_mask_and_set_register_interruptible_raw(ab, bank, reg,
-		bitmask, bitvalues);
-}
-
-static int ab5500_set_register_interruptible(struct device *dev, u8 bank,
-	u8 reg, u8 value)
-{
-	return ab5500_mask_and_set_register_interruptible(dev, bank, reg, 0xFF,
-		value);
-}
-
-static int ab5500_get_register_interruptible(struct device *dev, u8 bank,
-		u8 reg, u8 *value)
-{
-	struct ab5500 *ab;
-	struct platform_device *pdev = to_platform_device(dev);
-
-	if ((AB5500_NUM_BANKS <= bank) ||
-		!reg_read_allowed(pdev->id, bank, reg))
-		return -EINVAL;
-
-	ab = dev_get_drvdata(dev->parent);
-	return ab5500_get_register_interruptible_raw(ab, bank, reg, value);
-}
-
-static int ab5500_get_register_page_interruptible(struct device *dev, u8 bank,
-		u8 first_reg, u8 *regvals, u8 numregs)
-{
-	struct ab5500 *ab;
-	struct platform_device *pdev = to_platform_device(dev);
-
-	if ((AB5500_NUM_BANKS <= bank) ||
-		!page_read_allowed(pdev->id, bank,
-			first_reg, (first_reg + numregs - 1)))
-		return -EINVAL;
-
-	ab = dev_get_drvdata(dev->parent);
-	return get_register_page_interruptible(ab, bank, first_reg, regvals,
-		numregs);
-}
-
-static int
-ab5500_event_registers_startup_state_get(struct device *dev, u8 *event)
-{
-	struct ab5500 *ab;
-
-	ab = dev_get_drvdata(dev->parent);
-	if (!ab->startup_events_read)
-		return -EAGAIN; /* Try again later */
-
-	memcpy(event, ab->startup_events, AB5500_NUM_EVENT_REG);
-	return 0;
-}
-
-static struct abx500_ops ab5500_ops = {
-	.get_chip_id = ab5500_get_chip_id,
-	.get_register = ab5500_get_register_interruptible,
-	.set_register = ab5500_set_register_interruptible,
-	.get_register_page = ab5500_get_register_page_interruptible,
-	.set_register_page = NULL,
-	.mask_and_set_register = ab5500_mask_and_set_register_interruptible,
-	.event_registers_startup_state_get =
-		ab5500_event_registers_startup_state_get,
-	.startup_irq_enabled = NULL,
-};
-
-/*
- * ab5500_setup : Basic set-up, datastructure creation/destruction
- *		  and I2C interface.This sets up a default config
- *		  in the AB5500 chip so that it will work as expected.
- * @ab :	  Pointer to ab5500 structure
- * @settings :    Pointer to struct abx500_init_settings
- * @size :        Size of init data
- */
-static int __init ab5500_setup(struct ab5500 *ab,
-	struct abx500_init_settings *settings, unsigned int size)
-{
-	int err = 0;
-	int i;
-
-	for (i = 0; i < size; i++) {
-		err = ab5500_mask_and_set_register_interruptible_raw(ab,
-			settings[i].bank,
-			settings[i].reg,
-			0xFF, settings[i].setting);
-		if (err)
-			goto exit_no_setup;
-
-		/* If event mask register update the event mask in ab5500 */
-		if ((settings[i].bank == AB5500_BANK_IT) &&
-			(AB5500_MASK_BASE <= settings[i].reg) &&
-			(settings[i].reg <= AB5500_MASK_END)) {
-			ab->mask[settings[i].reg - AB5500_MASK_BASE] =
-				settings[i].setting;
-		}
-	}
-exit_no_setup:
-	return err;
-}
-
-struct ab_family_id {
-	u8	id;
-	char	*name;
-};
-
-static const struct ab_family_id ids[] __initdata = {
-	/* AB5500 */
-	{
-		.id = AB5500_1_0,
-		.name = "1.0"
-	},
-	{
-		.id = AB5500_1_1,
-		.name = "1.1"
-	},
-	/* Terminator */
-	{
-		.id = 0x00,
-	}
-};
-
-static int __init ab5500_probe(struct platform_device *pdev)
-{
-	struct ab5500 *ab;
-	struct ab5500_platform_data *ab5500_plf_data =
-		pdev->dev.platform_data;
-	int err;
-	int i;
-
-	ab = kzalloc(sizeof(struct ab5500), GFP_KERNEL);
-	if (!ab) {
-		dev_err(&pdev->dev,
-			"could not allocate ab5500 device\n");
-		return -ENOMEM;
-	}
-
-	/* Initialize data structure */
-	mutex_init(&ab->access_mutex);
-	mutex_init(&ab->irq_lock);
-	ab->dev = &pdev->dev;
-
-	platform_set_drvdata(pdev, ab);
-
-	/* Read chip ID register */
-	err = ab5500_get_register_interruptible_raw(ab,
-					AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
-					AB5500_CHIP_ID, &ab->chip_id);
-	if (err) {
-		dev_err(&pdev->dev, "could not communicate with the analog "
-			"baseband chip\n");
-		goto exit_no_detect;
-	}
-
-	for (i = 0; ids[i].id != 0x0; i++) {
-		if (ids[i].id == ab->chip_id) {
-			snprintf(&ab->chip_name[0], sizeof(ab->chip_name) - 1,
-				"AB5500 %s", ids[i].name);
-			break;
-		}
-	}
-	if (ids[i].id == 0x0) {
-		dev_err(&pdev->dev, "unknown analog baseband chip id: 0x%x\n",
-			ab->chip_id);
-		dev_err(&pdev->dev, "driver not started!\n");
-		goto exit_no_detect;
-	}
-
-	/* Clear and mask all interrupts */
-	for (i = 0; i < AB5500_NUM_IRQ_REGS; i++) {
-		u8 latchreg = AB5500_IT_LATCH0_REG + i;
-		u8 maskreg = AB5500_IT_MASK0_REG + i;
-		u8 val;
-
-		ab5500_get_register_interruptible_raw(ab, AB5500_BANK_IT,
-						      latchreg, &val);
-		set_register_interruptible(ab, AB5500_BANK_IT, maskreg, 0xff);
-		ab->mask[i] = ab->oldmask[i] = 0xff;
-	}
-
-	err = abx500_register_ops(&pdev->dev, &ab5500_ops);
-	if (err) {
-		dev_err(&pdev->dev, "ab5500_register ops error\n");
-		goto exit_no_detect;
-	}
-
-	/* Set up and register the platform devices. */
-	for (i = 0; i < AB5500_NUM_DEVICES; i++) {
-		ab5500_devs[i].platform_data = ab5500_plf_data->dev_data[i];
-		ab5500_devs[i].pdata_size =
-			sizeof(ab5500_plf_data->dev_data[i]);
-	}
-
-	err = mfd_add_devices(&pdev->dev, 0, ab5500_devs,
-		ARRAY_SIZE(ab5500_devs), NULL,
-		ab5500_plf_data->irq.base);
-	if (err) {
-		dev_err(&pdev->dev, "ab5500_mfd_add_device error\n");
-		goto exit_no_detect;
-	}
-
-	err = ab5500_setup(ab, ab5500_plf_data->init_settings,
-		ab5500_plf_data->init_settings_sz);
-	if (err) {
-		dev_err(&pdev->dev, "ab5500_setup error\n");
-		goto exit_no_detect;
-	}
-
-	ab5500_setup_debugfs(ab);
-
-	dev_info(&pdev->dev, "detected AB chip: %s\n", &ab->chip_name[0]);
-	return 0;
-
-exit_no_detect:
-	kfree(ab);
-	return err;
-}
-
-static int __exit ab5500_remove(struct platform_device *pdev)
-{
-	struct ab5500 *ab = platform_get_drvdata(pdev);
-
-	ab5500_remove_debugfs();
-	mfd_remove_devices(&pdev->dev);
-	kfree(ab);
-	return 0;
-}
-
-static struct platform_driver ab5500_driver = {
-	.driver = {
-		.name = "ab5500-core",
-		.owner = THIS_MODULE,
-	},
-	.remove  = __exit_p(ab5500_remove),
-};
-
-static int __init ab5500_core_init(void)
-{
-	return platform_driver_probe(&ab5500_driver, ab5500_probe);
-}
-
-static void __exit ab5500_core_exit(void)
-{
-	platform_driver_unregister(&ab5500_driver);
-}
-
-subsys_initcall(ab5500_core_init);
-module_exit(ab5500_core_exit);
-
-MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
-MODULE_DESCRIPTION("AB5500 core driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c
deleted file mode 100644
index 7200694..0000000
--- a/drivers/mfd/ab5500-debugfs.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * Copyright (C) 2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Debugfs support for the AB5500 MFD driver
- */
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab5500.h>
-#include <linux/uaccess.h>
-
-#include "ab5500-core.h"
-#include "ab5500-debugfs.h"
-
-static struct ab5500_i2c_ranges ab5500_reg_ranges[AB5500_NUM_BANKS] = {
-	[AB5500_BANK_LED] = {
-		.bankid = AB5500_BANK_LED,
-		.nranges = 1,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x00,
-				.last = 0x0C,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_ADC] = {
-		.bankid = AB5500_BANK_ADC,
-		.nranges = 6,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x1F,
-				.last = 0x22,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x23,
-				.last = 0x24,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x26,
-				.last = 0x2D,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x2F,
-				.last = 0x34,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x37,
-				.last = 0x57,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x58,
-				.last = 0x58,
-				.perm = AB5500_PERM_RO,
-			},
-		},
-	},
-	[AB5500_BANK_RTC] = {
-		.bankid = AB5500_BANK_RTC,
-		.nranges = 2,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x00,
-				.last = 0x04,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x06,
-				.last = 0x0C,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_STARTUP] = {
-		.bankid = AB5500_BANK_STARTUP,
-		.nranges = 12,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x00,
-				.last = 0x01,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x1F,
-				.last = 0x1F,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x2E,
-				.last = 0x2E,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x2F,
-				.last = 0x30,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x50,
-				.last = 0x51,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x60,
-				.last = 0x61,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x66,
-				.last = 0x8A,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x8C,
-				.last = 0x96,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0xAA,
-				.last = 0xB4,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0xB7,
-				.last = 0xBF,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0xC1,
-				.last = 0xCA,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0xD3,
-				.last = 0xE0,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_DBI_ECI] = {
-		.bankid = AB5500_BANK_DBI_ECI,
-		.nranges = 3,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x00,
-				.last = 0x07,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x10,
-				.last = 0x10,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x13,
-				.last = 0x13,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_CHG] = {
-		.bankid = AB5500_BANK_CHG,
-		.nranges = 2,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x11,
-				.last = 0x11,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x12,
-				.last = 0x1B,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_FG_BATTCOM_ACC] = {
-		.bankid = AB5500_BANK_FG_BATTCOM_ACC,
-		.nranges = 2,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x00,
-				.last = 0x0B,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x0C,
-				.last = 0x10,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_USB] = {
-		.bankid = AB5500_BANK_USB,
-		.nranges = 12,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x01,
-				.last = 0x01,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x80,
-				.last = 0x83,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x87,
-				.last = 0x8A,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x8B,
-				.last = 0x8B,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x91,
-				.last = 0x92,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x93,
-				.last = 0x93,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x94,
-				.last = 0x94,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0xA8,
-				.last = 0xB0,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0xB2,
-				.last = 0xB2,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0xB4,
-				.last = 0xBC,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0xBF,
-				.last = 0xBF,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0xC1,
-				.last = 0xC5,
-				.perm = AB5500_PERM_RO,
-			},
-		},
-	},
-	[AB5500_BANK_IT] = {
-		.bankid = AB5500_BANK_IT,
-		.nranges = 4,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x00,
-				.last = 0x02,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x20,
-				.last = 0x36,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x40,
-				.last = 0x56,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x60,
-				.last = 0x76,
-				.perm = AB5500_PERM_RO,
-			},
-		},
-	},
-	[AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = {
-		.bankid = AB5500_BANK_VDDDIG_IO_I2C_CLK_TST,
-		.nranges = 7,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x02,
-				.last = 0x02,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x12,
-				.last = 0x12,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x30,
-				.last = 0x34,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x40,
-				.last = 0x44,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x50,
-				.last = 0x54,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x60,
-				.last = 0x64,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x70,
-				.last = 0x74,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = {
-		.bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
-		.nranges = 13,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x01,
-				.last = 0x01,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x02,
-				.last = 0x02,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x0D,
-				.last = 0x0F,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x1C,
-				.last = 0x1C,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x1E,
-				.last = 0x1E,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x20,
-				.last = 0x21,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x25,
-				.last = 0x25,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x28,
-				.last = 0x2A,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x30,
-				.last = 0x33,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x40,
-				.last = 0x43,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x50,
-				.last = 0x53,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x60,
-				.last = 0x63,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x70,
-				.last = 0x73,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_VIBRA] = {
-		.bankid = AB5500_BANK_VIBRA,
-		.nranges = 2,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x10,
-				.last = 0x13,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0xFE,
-				.last = 0xFE,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_AUDIO_HEADSETUSB] = {
-		.bankid = AB5500_BANK_AUDIO_HEADSETUSB,
-		.nranges = 2,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x00,
-				.last = 0x48,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0xEB,
-				.last = 0xFB,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_SIM_USBSIM] = {
-		.bankid = AB5500_BANK_SIM_USBSIM,
-		.nranges = 1,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x13,
-				.last = 0x19,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-	[AB5500_BANK_VDENC] = {
-		.bankid = AB5500_BANK_VDENC,
-		.nranges = 12,
-		.range = (struct ab5500_reg_range[]) {
-			{
-				.first = 0x00,
-				.last = 0x08,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x09,
-				.last = 0x09,
-				.perm = AB5500_PERM_RO,
-			},
-			{
-				.first = 0x0A,
-				.last = 0x12,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x15,
-				.last = 0x19,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x1B,
-				.last = 0x21,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x27,
-				.last = 0x2C,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x41,
-				.last = 0x41,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x45,
-				.last = 0x5B,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x5D,
-				.last = 0x5D,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x69,
-				.last = 0x69,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x6C,
-				.last = 0x6D,
-				.perm = AB5500_PERM_RW,
-			},
-			{
-				.first = 0x80,
-				.last = 0x81,
-				.perm = AB5500_PERM_RW,
-			},
-		},
-	},
-};
-
-static int ab5500_registers_print(struct seq_file *s, void *p)
-{
-	struct ab5500 *ab = s->private;
-	unsigned int i;
-	u8 bank = (u8)ab->debug_bank;
-
-	seq_printf(s, "ab5500 register values:\n");
-	for (bank = 0; bank < AB5500_NUM_BANKS; bank++) {
-		seq_printf(s, " bank %u, %s (0x%x):\n", bank,
-				bankinfo[bank].name,
-				bankinfo[bank].slave_addr);
-		for (i = 0; i < ab5500_reg_ranges[bank].nranges; i++) {
-			u8 reg;
-			int err;
-
-			for (reg = ab5500_reg_ranges[bank].range[i].first;
-				reg <= ab5500_reg_ranges[bank].range[i].last;
-				reg++) {
-				u8 value;
-
-				err = ab5500_get_register_interruptible_raw(ab,
-								bank, reg,
-								&value);
-				if (err < 0) {
-					dev_err(ab->dev, "get_reg failed %d"
-						"bank 0x%x reg 0x%x\n",
-						err, bank, reg);
-					return err;
-				}
-
-				err = seq_printf(s, "[%d/0x%02X]: 0x%02X\n",
-						bank, reg, value);
-				if (err < 0) {
-					dev_err(ab->dev,
-						"seq_printf overflow\n");
-					/*
-					 * Error is not returned here since
-					 * the output is wanted in any case
-					 */
-					return 0;
-				}
-			}
-		}
-	}
-	return 0;
-}
-
-static int ab5500_registers_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, ab5500_registers_print, inode->i_private);
-}
-
-static const struct file_operations ab5500_registers_fops = {
-	.open = ab5500_registers_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-	.owner = THIS_MODULE,
-};
-
-static int ab5500_bank_print(struct seq_file *s, void *p)
-{
-	struct ab5500 *ab = s->private;
-
-	seq_printf(s, "%d\n", ab->debug_bank);
-	return 0;
-}
-
-static int ab5500_bank_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, ab5500_bank_print, inode->i_private);
-}
-
-static ssize_t ab5500_bank_write(struct file *file,
-	const char __user *user_buf,
-	size_t count, loff_t *ppos)
-{
-	struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
-	char buf[32];
-	int buf_size;
-	unsigned long user_bank;
-	int err;
-
-	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf) - 1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	err = strict_strtoul(buf, 0, &user_bank);
-	if (err)
-		return -EINVAL;
-
-	if (user_bank >= AB5500_NUM_BANKS) {
-		dev_err(ab->dev,
-			"debugfs error input > number of banks\n");
-		return -EINVAL;
-	}
-
-	ab->debug_bank = user_bank;
-
-	return buf_size;
-}
-
-static int ab5500_address_print(struct seq_file *s, void *p)
-{
-	struct ab5500 *ab = s->private;
-
-	seq_printf(s, "0x%02X\n", ab->debug_address);
-	return 0;
-}
-
-static int ab5500_address_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, ab5500_address_print, inode->i_private);
-}
-
-static ssize_t ab5500_address_write(struct file *file,
-	const char __user *user_buf,
-	size_t count, loff_t *ppos)
-{
-	struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
-	char buf[32];
-	int buf_size;
-	unsigned long user_address;
-	int err;
-
-	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf) - 1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	err = strict_strtoul(buf, 0, &user_address);
-	if (err)
-		return -EINVAL;
-	if (user_address > 0xff) {
-		dev_err(ab->dev,
-			"debugfs error input > 0xff\n");
-		return -EINVAL;
-	}
-	ab->debug_address = user_address;
-	return buf_size;
-}
-
-static int ab5500_val_print(struct seq_file *s, void *p)
-{
-	struct ab5500 *ab = s->private;
-	int err;
-	u8 regvalue;
-
-	err = ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
-		(u8)ab->debug_address, &regvalue);
-	if (err) {
-		dev_err(ab->dev, "get_reg failed %d, bank 0x%x"
-			", reg 0x%x\n", err, ab->debug_bank,
-			ab->debug_address);
-		return -EINVAL;
-	}
-	seq_printf(s, "0x%02X\n", regvalue);
-
-	return 0;
-}
-
-static int ab5500_val_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, ab5500_val_print, inode->i_private);
-}
-
-static ssize_t ab5500_val_write(struct file *file,
-	const char __user *user_buf,
-	size_t count, loff_t *ppos)
-{
-	struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
-	char buf[32];
-	int buf_size;
-	unsigned long user_val;
-	int err;
-	u8 regvalue;
-
-	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf)-1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	err = strict_strtoul(buf, 0, &user_val);
-	if (err)
-		return -EINVAL;
-	if (user_val > 0xff) {
-		dev_err(ab->dev,
-			"debugfs error input > 0xff\n");
-		return -EINVAL;
-	}
-	err = ab5500_mask_and_set_register_interruptible_raw(
-		ab, (u8)ab->debug_bank,
-		(u8)ab->debug_address, 0xFF, (u8)user_val);
-	if (err)
-		return -EINVAL;
-
-	ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
-		(u8)ab->debug_address, &regvalue);
-	if (err)
-		return -EINVAL;
-
-	return buf_size;
-}
-
-static const struct file_operations ab5500_bank_fops = {
-	.open = ab5500_bank_open,
-	.write = ab5500_bank_write,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-	.owner = THIS_MODULE,
-};
-
-static const struct file_operations ab5500_address_fops = {
-	.open = ab5500_address_open,
-	.write = ab5500_address_write,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-	.owner = THIS_MODULE,
-};
-
-static const struct file_operations ab5500_val_fops = {
-	.open = ab5500_val_open,
-	.write = ab5500_val_write,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-	.owner = THIS_MODULE,
-};
-
-static struct dentry *ab5500_dir;
-static struct dentry *ab5500_reg_file;
-static struct dentry *ab5500_bank_file;
-static struct dentry *ab5500_address_file;
-static struct dentry *ab5500_val_file;
-
-void __init ab5500_setup_debugfs(struct ab5500 *ab)
-{
-	ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP;
-	ab->debug_address = AB5500_CHIP_ID;
-
-	ab5500_dir = debugfs_create_dir("ab5500", NULL);
-	if (!ab5500_dir)
-		goto exit_no_debugfs;
-
-	ab5500_reg_file = debugfs_create_file("all-bank-registers",
-		S_IRUGO, ab5500_dir, ab, &ab5500_registers_fops);
-	if (!ab5500_reg_file)
-		goto exit_destroy_dir;
-
-	ab5500_bank_file = debugfs_create_file("register-bank",
-		(S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_bank_fops);
-	if (!ab5500_bank_file)
-		goto exit_destroy_reg;
-
-	ab5500_address_file = debugfs_create_file("register-address",
-		(S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_address_fops);
-	if (!ab5500_address_file)
-		goto exit_destroy_bank;
-
-	ab5500_val_file = debugfs_create_file("register-value",
-		(S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_val_fops);
-	if (!ab5500_val_file)
-		goto exit_destroy_address;
-
-	return;
-
-exit_destroy_address:
-	debugfs_remove(ab5500_address_file);
-exit_destroy_bank:
-	debugfs_remove(ab5500_bank_file);
-exit_destroy_reg:
-	debugfs_remove(ab5500_reg_file);
-exit_destroy_dir:
-	debugfs_remove(ab5500_dir);
-exit_no_debugfs:
-	dev_err(ab->dev, "failed to create debugfs entries.\n");
-	return;
-}
-
-void __exit ab5500_remove_debugfs(void)
-{
-	debugfs_remove(ab5500_val_file);
-	debugfs_remove(ab5500_address_file);
-	debugfs_remove(ab5500_bank_file);
-	debugfs_remove(ab5500_reg_file);
-	debugfs_remove(ab5500_dir);
-}
diff --git a/drivers/mfd/ab5500-debugfs.h b/drivers/mfd/ab5500-debugfs.h
deleted file mode 100644
index 7330a9b..0000000
--- a/drivers/mfd/ab5500-debugfs.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Debugfs interface to the AB5500 core driver
- */
-
-#ifdef CONFIG_DEBUG_FS
-
-void ab5500_setup_debugfs(struct ab5500 *ab);
-void ab5500_remove_debugfs(void);
-
-#else /* !CONFIG_DEBUG_FS */
-
-static inline void ab5500_setup_debugfs(struct ab5500 *ab)
-{
-}
-
-static inline void ab5500_remove_debugfs(void)
-{
-}
-
-#endif
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c
deleted file mode 100644
index bb115b2..0000000
--- a/drivers/mfd/db5500-prcmu.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- *
- * U5500 PRCM Unit interface driver
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/completion.h>
-#include <linux/irq.h>
-#include <linux/jiffies.h>
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/dbx500-prcmu.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-#include <mach/db5500-regs.h>
-#include "dbx500-prcmu-regs.h"
-
-#define _PRCM_MB_HEADER (tcdm_base + 0xFE8)
-#define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0)
-#define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1)
-#define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2)
-#define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3)
-#define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4)
-#define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5)
-#define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6)
-#define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7)
-#define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8)
-#define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9)
-#define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa)
-#define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb)
-#define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc)
-#define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd)
-#define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe)
-#define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf)
-
-/* Req Mailboxes */
-#define PRCM_REQ_MB0 (tcdm_base + 0xFD8)
-#define PRCM_REQ_MB1 (tcdm_base + 0xFCC)
-#define PRCM_REQ_MB2 (tcdm_base + 0xFC4)
-#define PRCM_REQ_MB3 (tcdm_base + 0xFC0)
-#define PRCM_REQ_MB4 (tcdm_base + 0xF98)
-#define PRCM_REQ_MB5 (tcdm_base + 0xF90)
-#define PRCM_REQ_MB6 (tcdm_base + 0xF8C)
-#define PRCM_REQ_MB7 (tcdm_base + 0xF84)
-
-/* Ack Mailboxes */
-#define PRCM_ACK_MB0 (tcdm_base + 0xF38)
-#define PRCM_ACK_MB1 (tcdm_base + 0xF30)
-#define PRCM_ACK_MB2 (tcdm_base + 0xF24)
-#define PRCM_ACK_MB3 (tcdm_base + 0xF20)
-#define PRCM_ACK_MB4 (tcdm_base + 0xF1C)
-#define PRCM_ACK_MB5 (tcdm_base + 0xF14)
-#define PRCM_ACK_MB6 (tcdm_base + 0xF0C)
-#define PRCM_ACK_MB7 (tcdm_base + 0xF08)
-
-enum mb_return_code {
-	RC_SUCCESS,
-	RC_FAIL,
-};
-
-/* Mailbox 0 headers. */
-enum mb0_header {
-	/* request */
-	RMB0H_PWR_STATE_TRANS = 1,
-	RMB0H_WAKE_UP_CFG,
-	RMB0H_RD_WAKE_UP_ACK,
-	/* acknowledge */
-	AMB0H_WAKE_UP = 1,
-};
-
-/* Mailbox 5 headers. */
-enum mb5_header {
-	MB5H_I2C_WRITE = 1,
-	MB5H_I2C_READ,
-};
-
-/* Request mailbox 5 fields. */
-#define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0)
-#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1)
-#define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2)
-#define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4)
-
-/* Acknowledge mailbox 5 fields. */
-#define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0)
-#define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4)
-
-#define NUM_MB 8
-#define MBOX_BIT BIT
-#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
-
-/*
-* Used by MCDE to setup all necessary PRCMU registers
-*/
-#define PRCMU_RESET_DSIPLL			0x00004000
-#define PRCMU_UNCLAMP_DSIPLL			0x00400800
-
-/* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/
-#define PRCMU_DSI_CLOCK_SETTING			0x00000128
-/* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */
-#define PRCMU_DSI_LP_CLOCK_SETTING		0x00000135
-#define PRCMU_PLLDSI_FREQ_SETTING		0x00020121
-#define PRCMU_DSI_PLLOUT_SEL_SETTING		0x00000002
-#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV		0x03000201
-#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV		0x00000101
-
-#define PRCMU_ENABLE_PLLDSI			0x00000001
-#define PRCMU_DISABLE_PLLDSI			0x00000000
-
-#define PRCMU_DSI_RESET_SW			0x00000003
-#define PRCMU_RESOUTN0_PIN			0x00000001
-#define PRCMU_RESOUTN1_PIN			0x00000002
-#define PRCMU_RESOUTN2_PIN			0x00000004
-
-#define PRCMU_PLLDSI_LOCKP_LOCKED		0x3
-
-/*
- * mb0_transfer - state needed for mailbox 0 communication.
- * @lock:		The transaction lock.
- */
-static struct {
-	spinlock_t lock;
-} mb0_transfer;
-
-/*
- * mb5_transfer - state needed for mailbox 5 communication.
- * @lock:	The transaction lock.
- * @work:	The transaction completion structure.
- * @ack:	Reply ("acknowledge") data.
- */
-static struct {
-	struct mutex lock;
-	struct completion work;
-	struct {
-		u8 header;
-		u8 status;
-		u8 value[4];
-	} ack;
-} mb5_transfer;
-
-/* PRCMU TCDM base IO address. */
-static __iomem void *tcdm_base;
-
-/**
- * db5500_prcmu_abb_read() - Read register value(s) from the ABB.
- * @slave:	The I2C slave address.
- * @reg:	The (start) register address.
- * @value:	The read out value(s).
- * @size:	The number of registers to read.
- *
- * Reads register value(s) from the ABB.
- * @size has to be <= 4.
- */
-int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
-{
-	int r;
-
-	if ((size < 1) || (4 < size))
-		return -EINVAL;
-
-	mutex_lock(&mb5_transfer.lock);
-
-	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
-		cpu_relax();
-	writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
-	writeb(reg, PRCM_REQ_MB5_I2C_REG);
-	writeb(size, PRCM_REQ_MB5_I2C_SIZE);
-	writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER);
-
-	writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
-	wait_for_completion(&mb5_transfer.work);
-
-	r = 0;
-	if ((mb5_transfer.ack.header == MB5H_I2C_READ) &&
-		(mb5_transfer.ack.status == RC_SUCCESS))
-		memcpy(value, mb5_transfer.ack.value, (size_t)size);
-	else
-		r = -EIO;
-
-	mutex_unlock(&mb5_transfer.lock);
-
-	return r;
-}
-
-/**
- * db5500_prcmu_abb_write() - Write register value(s) to the ABB.
- * @slave:	The I2C slave address.
- * @reg:	The (start) register address.
- * @value:	The value(s) to write.
- * @size:	The number of registers to write.
- *
- * Writes register value(s) to the ABB.
- * @size has to be <= 4.
- */
-int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
-{
-	int r;
-
-	if ((size < 1) || (4 < size))
-		return -EINVAL;
-
-	mutex_lock(&mb5_transfer.lock);
-
-	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
-		cpu_relax();
-	writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
-	writeb(reg, PRCM_REQ_MB5_I2C_REG);
-	writeb(size, PRCM_REQ_MB5_I2C_SIZE);
-	memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size);
-	writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER);
-
-	writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
-	wait_for_completion(&mb5_transfer.work);
-
-	if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) &&
-		(mb5_transfer.ack.status == RC_SUCCESS))
-		r = 0;
-	else
-		r = -EIO;
-
-	mutex_unlock(&mb5_transfer.lock);
-
-	return r;
-}
-
-int db5500_prcmu_enable_dsipll(void)
-{
-	int i;
-
-	/* Enable DSIPLL_RESETN resets */
-	writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
-	/* Unclamp DSIPLL in/out */
-	writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
-	/* Set DSI PLL FREQ */
-	writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
-	writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
-		PRCM_DSI_PLLOUT_SEL);
-	/* Enable Escape clocks */
-	writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
-
-	/* Start DSI PLL */
-	writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
-	/* Reset DSI PLL */
-	writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET);
-	for (i = 0; i < 10; i++) {
-		if ((readl(PRCM_PLLDSI_LOCKP) &
-			PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED)
-			break;
-		udelay(100);
-	}
-	/* Release DSIPLL_RESETN */
-	writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET);
-	return 0;
-}
-
-int db5500_prcmu_disable_dsipll(void)
-{
-	/* Disable dsi pll */
-	writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
-	/* Disable  escapeclock */
-	writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
-	return 0;
-}
-
-int db5500_prcmu_set_display_clocks(void)
-{
-	/* HDMI and TVCLK Should be handled somewhere else */
-	/* PLLDIV=8, PLLSW=2, CLKEN=1 */
-	writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
-	/* PLLDIV=14, PLLSW=2, CLKEN=1 */
-	writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
-	return 0;
-}
-
-static void ack_dbb_wakeup(void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mb0_transfer.lock, flags);
-
-	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
-		cpu_relax();
-
-	writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER);
-	writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
-
-	spin_unlock_irqrestore(&mb0_transfer.lock, flags);
-}
-
-static inline void print_unknown_header_warning(u8 n, u8 header)
-{
-	pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
-		header, n);
-}
-
-static bool read_mailbox_0(void)
-{
-	bool r;
-	u8 header;
-
-	header = readb(PRCM_ACK_MB0_HEADER);
-	switch (header) {
-	case AMB0H_WAKE_UP:
-		r = true;
-		break;
-	default:
-		print_unknown_header_warning(0, header);
-		r = false;
-		break;
-	}
-	writel(MBOX_BIT(0), PRCM_ARM_IT1_CLR);
-	return r;
-}
-
-static bool read_mailbox_1(void)
-{
-	writel(MBOX_BIT(1), PRCM_ARM_IT1_CLR);
-	return false;
-}
-
-static bool read_mailbox_2(void)
-{
-	writel(MBOX_BIT(2), PRCM_ARM_IT1_CLR);
-	return false;
-}
-
-static bool read_mailbox_3(void)
-{
-	writel(MBOX_BIT(3), PRCM_ARM_IT1_CLR);
-	return false;
-}
-
-static bool read_mailbox_4(void)
-{
-	writel(MBOX_BIT(4), PRCM_ARM_IT1_CLR);
-	return false;
-}
-
-static bool read_mailbox_5(void)
-{
-	u8 header;
-
-	header = readb(PRCM_ACK_MB5_HEADER);
-	switch (header) {
-	case MB5H_I2C_READ:
-		memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4);
-	case MB5H_I2C_WRITE:
-		mb5_transfer.ack.header = header;
-		mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE);
-		complete(&mb5_transfer.work);
-		break;
-	default:
-		print_unknown_header_warning(5, header);
-		break;
-	}
-	writel(MBOX_BIT(5), PRCM_ARM_IT1_CLR);
-	return false;
-}
-
-static bool read_mailbox_6(void)
-{
-	writel(MBOX_BIT(6), PRCM_ARM_IT1_CLR);
-	return false;
-}
-
-static bool read_mailbox_7(void)
-{
-	writel(MBOX_BIT(7), PRCM_ARM_IT1_CLR);
-	return false;
-}
-
-static bool (* const read_mailbox[NUM_MB])(void) = {
-	read_mailbox_0,
-	read_mailbox_1,
-	read_mailbox_2,
-	read_mailbox_3,
-	read_mailbox_4,
-	read_mailbox_5,
-	read_mailbox_6,
-	read_mailbox_7
-};
-
-static irqreturn_t prcmu_irq_handler(int irq, void *data)
-{
-	u32 bits;
-	u8 n;
-	irqreturn_t r;
-
-	bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
-	if (unlikely(!bits))
-		return IRQ_NONE;
-
-	r = IRQ_HANDLED;
-	for (n = 0; bits; n++) {
-		if (bits & MBOX_BIT(n)) {
-			bits -= MBOX_BIT(n);
-			if (read_mailbox[n]())
-				r = IRQ_WAKE_THREAD;
-		}
-	}
-	return r;
-}
-
-static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
-{
-	ack_dbb_wakeup();
-	return IRQ_HANDLED;
-}
-
-void __init db5500_prcmu_early_init(void)
-{
-	tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
-	spin_lock_init(&mb0_transfer.lock);
-	mutex_init(&mb5_transfer.lock);
-	init_completion(&mb5_transfer.work);
-}
-
-/**
- * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
- *
- */
-int __init db5500_prcmu_init(void)
-{
-	int r = 0;
-
-	if (ux500_is_svp() || !cpu_is_u5500())
-		return -ENODEV;
-
-	/* Clean up the mailbox interrupts after pre-kernel code. */
-	writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
-
-	r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler,
-		prcmu_irq_thread_fn, 0, "prcmu", NULL);
-	if (r < 0) {
-		pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n");
-		return -EBUSY;
-	}
-	return 0;
-}
-
-arch_initcall(db5500_prcmu_init);
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 9fd4f63..738722c 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -813,7 +813,8 @@
 		mc13xxx_add_subdevice(mc13xxx, "%s-adc");
 
 	if (mc13xxx->flags & MC13XXX_USE_CODEC)
-		mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
+					pdata->codec, sizeof(*pdata->codec));
 
 	if (mc13xxx->flags & MC13XXX_USE_RTC)
 		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c
index e7ff783..5a62e6bf 100644
--- a/drivers/mfd/tps65911-comparator.c
+++ b/drivers/mfd/tps65911-comparator.c
@@ -26,7 +26,7 @@
 #define COMP1					1
 #define COMP2					2
 
-/* Comparator 1 voltage selection table in milivolts */
+/* Comparator 1 voltage selection table in millivolts */
 static const u16 COMP_VSEL_TABLE[] = {
 	0, 2500, 2500, 2500, 2500, 2550, 2600, 2650,
 	2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050,
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c779509..2661f6e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -452,14 +452,32 @@
 	  still useful.
 
 config BMP085
-	tristate "BMP085 digital pressure sensor"
+	bool
+	depends on SYSFS
+
+config BMP085_I2C
+	tristate "BMP085 digital pressure sensor on I2C"
+	select BMP085
+	select REGMAP_I2C
 	depends on I2C && SYSFS
 	help
-	  If you say yes here you get support for the Bosch Sensortec
-	  BMP085 digital pressure sensor.
+	  Say Y here if you want to support Bosch Sensortec's digital pressure
+	  sensor hooked to an I2C bus.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called bmp085.
+	  module will be called bmp085-i2c.
+
+config BMP085_SPI
+	tristate "BMP085 digital pressure sensor on SPI"
+	select BMP085
+	select REGMAP_SPI
+	depends on SPI_MASTER && SYSFS
+	help
+	  Say Y here if you want to support Bosch Sensortec's digital pressure
+	  sensor hooked to an SPI bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bmp085-spi.
 
 config PCH_PHUB
 	tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
@@ -490,14 +508,6 @@
 	  stereo and mono audio, video, microphone and UART data to use
 	  a common connector port.
 
-config MAX8997_MUIC
-	tristate "MAX8997 MUIC Support"
-	depends on MFD_MAX8997
-	help
-	  If you say yes here you get support for the MUIC device of
-	  Maxim MAX8997 PMIC.
-	  The MAX8997 MUIC is a USB port accessory detector and switch.
-
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
@@ -506,4 +516,5 @@
 source "drivers/misc/lis3lv02d/Kconfig"
 source "drivers/misc/carma/Kconfig"
 source "drivers/misc/altera-stapl/Kconfig"
+source "drivers/misc/mei/Kconfig"
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 3e1d801..456972f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -11,6 +11,8 @@
 obj-$(CONFIG_ATMEL_SSC)		+= atmel-ssc.o
 obj-$(CONFIG_ATMEL_TCLIB)	+= atmel_tclib.o
 obj-$(CONFIG_BMP085)		+= bmp085.o
+obj-$(CONFIG_BMP085_I2C)	+= bmp085-i2c.o
+obj-$(CONFIG_BMP085_SPI)	+= bmp085-spi.o
 obj-$(CONFIG_ICS932S401)	+= ics932s401.o
 obj-$(CONFIG_LKDTM)		+= lkdtm.o
 obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
@@ -48,4 +50,4 @@
 obj-y				+= carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
 obj-$(CONFIG_ALTERA_STAPL)	+=altera-stapl/
-obj-$(CONFIG_MAX8997_MUIC)	+= max8997-muic.o
+obj-$(CONFIG_INTEL_MEI)		+= mei/
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index 1d1d426..6938f1b 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -749,7 +749,7 @@
 }
 EXPORT_SYMBOL(ad_dpot_probe);
 
-__devexit int ad_dpot_remove(struct device *dev)
+int ad_dpot_remove(struct device *dev)
 {
 	struct dpot_data *data = dev_get_drvdata(dev);
 	int i;
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c
index 54f6f39..f1f9877 100644
--- a/drivers/misc/bh1780gli.c
+++ b/drivers/misc/bh1780gli.c
@@ -248,7 +248,7 @@
 
 static struct i2c_driver bh1780_driver = {
 	.probe		= bh1780_probe,
-	.remove		= bh1780_remove,
+	.remove		= __devexit_p(bh1780_remove),
 	.id_table	= bh1780_id,
 	.driver = {
 		.name = "bh1780",
diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c
new file mode 100644
index 0000000..9943971
--- /dev/null
+++ b/drivers/misc/bmp085-i2c.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012  Bosch Sensortec GmbH
+ * Copyright (c) 2012  Unixphere AB
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include "bmp085.h"
+
+#define BMP085_I2C_ADDRESS	0x77
+
+static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
+							I2C_CLIENT_END };
+
+static int bmp085_i2c_detect(struct i2c_client *client,
+			     struct i2c_board_info *info)
+{
+	if (client->addr != BMP085_I2C_ADDRESS)
+		return -ENODEV;
+
+	return bmp085_detect(&client->dev);
+}
+
+static int __devinit bmp085_i2c_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+{
+	int err;
+	struct regmap *regmap = devm_regmap_init_i2c(client,
+						     &bmp085_regmap_config);
+
+	if (IS_ERR(regmap)) {
+		err = PTR_ERR(regmap);
+		dev_err(&client->dev, "Failed to init regmap: %d\n", err);
+		return err;
+	}
+
+	return bmp085_probe(&client->dev, regmap);
+}
+
+static int bmp085_i2c_remove(struct i2c_client *client)
+{
+	return bmp085_remove(&client->dev);
+}
+
+static const struct of_device_id bmp085_of_match[] = {
+	{ .compatible = "bosch,bmp085", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bmp085_of_match);
+
+static const struct i2c_device_id bmp085_id[] = {
+	{ BMP085_NAME, 0 },
+	{ "bmp180", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, bmp085_id);
+
+static struct i2c_driver bmp085_i2c_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= BMP085_NAME,
+		.of_match_table = bmp085_of_match
+	},
+	.id_table	= bmp085_id,
+	.probe		= bmp085_i2c_probe,
+	.remove		= __devexit_p(bmp085_i2c_remove),
+
+	.detect		= bmp085_i2c_detect,
+	.address_list	= normal_i2c
+};
+
+module_i2c_driver(bmp085_i2c_driver);
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("BMP085 I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c
new file mode 100644
index 0000000..78aaff9
--- /dev/null
+++ b/drivers/misc/bmp085-spi.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012  Bosch Sensortec GmbH
+ * Copyright (c) 2012  Unixphere AB
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+#include "bmp085.h"
+
+static int __devinit bmp085_spi_probe(struct spi_device *client)
+{
+	int err;
+	struct regmap *regmap;
+
+	client->bits_per_word = 8;
+	err = spi_setup(client);
+	if (err < 0) {
+		dev_err(&client->dev, "spi_setup failed!\n");
+		return err;
+	}
+
+	regmap = devm_regmap_init_spi(client, &bmp085_regmap_config);
+	if (IS_ERR(regmap)) {
+		err = PTR_ERR(regmap);
+		dev_err(&client->dev, "Failed to init regmap: %d\n", err);
+		return err;
+	}
+
+	return bmp085_probe(&client->dev, regmap);
+}
+
+static int bmp085_spi_remove(struct spi_device *client)
+{
+	return bmp085_remove(&client->dev);
+}
+
+static const struct of_device_id bmp085_of_match[] = {
+	{ .compatible = "bosch,bmp085", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bmp085_of_match);
+
+static const struct spi_device_id bmp085_id[] = {
+	{ "bmp180", 0 },
+	{ "bmp181", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, bmp085_id);
+
+static struct spi_driver bmp085_spi_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= BMP085_NAME,
+		.of_match_table = bmp085_of_match
+	},
+	.id_table	= bmp085_id,
+	.probe		= bmp085_spi_probe,
+	.remove		= __devexit_p(bmp085_spi_remove)
+};
+
+static int __init bmp085_spi_init(void)
+{
+	return spi_register_driver(&bmp085_spi_driver);
+}
+
+static void __exit bmp085_spi_exit(void)
+{
+	spi_unregister_driver(&bmp085_spi_driver);
+}
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("BMP085 SPI bus driver");
+MODULE_LICENSE("GPL");
+
+module_init(bmp085_spi_init);
+module_exit(bmp085_spi_exit);
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c
index 76c3064..62e4182 100644
--- a/drivers/misc/bmp085.c
+++ b/drivers/misc/bmp085.c
@@ -1,62 +1,62 @@
 /*  Copyright (c) 2010  Christoph Mair <christoph.mair@gmail.com>
-
-    This driver supports the bmp085 digital barometric pressure
-    and temperature sensor from Bosch Sensortec. The datasheet
-    is available from their website:
-    http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf
-
-    A pressure measurement is issued by reading from pressure0_input.
-    The return value ranges from 30000 to 110000 pascal with a resulution
-    of 1 pascal (0.01 millibar) which enables measurements from 9000m above
-    to 500m below sea level.
-
-    The temperature can be read from temp0_input. Values range from
-    -400 to 850 representing the ambient temperature in degree celsius
-    multiplied by 10.The resolution is 0.1 celsius.
-
-    Because ambient pressure is temperature dependent, a temperature
-    measurement will be executed automatically even if the user is reading
-    from pressure0_input. This happens if the last temperature measurement
-    has been executed more then one second ago.
-
-    To decrease RMS noise from pressure measurements, the bmp085 can
-    autonomously calculate the average of up to eight samples. This is
-    set up by writing to the oversampling sysfs file. Accepted values
-    are 0, 1, 2 and 3. 2^x when x is the value written to this file
-    specifies the number of samples used to calculate the ambient pressure.
-    RMS noise is specified with six pascal (without averaging) and decreases
-    down to 3 pascal when using an oversampling setting of 3.
-
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
+ *  Copyright (c) 2012  Bosch Sensortec GmbH
+ *  Copyright (c) 2012  Unixphere AB
+ *
+ *  This driver supports the bmp085 and bmp18x digital barometric pressure
+ *  and temperature sensors from Bosch Sensortec. The datasheets
+ *  are available from their website:
+ *  http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf
+ *  http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP180-DS000-07.pdf
+ *
+ *  A pressure measurement is issued by reading from pressure0_input.
+ *  The return value ranges from 30000 to 110000 pascal with a resulution
+ *  of 1 pascal (0.01 millibar) which enables measurements from 9000m above
+ *  to 500m below sea level.
+ *
+ *  The temperature can be read from temp0_input. Values range from
+ *  -400 to 850 representing the ambient temperature in degree celsius
+ *  multiplied by 10.The resolution is 0.1 celsius.
+ *
+ *  Because ambient pressure is temperature dependent, a temperature
+ *  measurement will be executed automatically even if the user is reading
+ *  from pressure0_input. This happens if the last temperature measurement
+ *  has been executed more then one second ago.
+ *
+ *  To decrease RMS noise from pressure measurements, the bmp085 can
+ *  autonomously calculate the average of up to eight samples. This is
+ *  set up by writing to the oversampling sysfs file. Accepted values
+ *  are 0, 1, 2 and 3. 2^x when x is the value written to this file
+ *  specifies the number of samples used to calculate the ambient pressure.
+ *  RMS noise is specified with six pascal (without averaging) and decreases
+ *  down to 3 pascal when using an oversampling setting of 3.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
 #include <linux/module.h>
+#include <linux/device.h>
 #include <linux/init.h>
-#include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include "bmp085.h"
 
-
-#define BMP085_I2C_ADDRESS		0x77
 #define BMP085_CHIP_ID			0x55
-
 #define BMP085_CALIBRATION_DATA_START	0xAA
 #define BMP085_CALIBRATION_DATA_LENGTH	11	/* 16 bit values */
 #define BMP085_CHIP_ID_REG		0xD0
-#define BMP085_VERSION_REG		0xD1
 #define BMP085_CTRL_REG			0xF4
 #define BMP085_TEMP_MEASUREMENT		0x2E
 #define BMP085_PRESSURE_MEASUREMENT	0x34
@@ -65,12 +65,6 @@
 #define BMP085_CONVERSION_REGISTER_XLSB	0xF8
 #define BMP085_TEMP_CONVERSION_TIME	5
 
-#define BMP085_CLIENT_NAME		"bmp085"
-
-
-static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
-							I2C_CLIENT_END };
-
 struct bmp085_calibration_data {
 	s16 AC1, AC2, AC3;
 	u16 AC4, AC5, AC6;
@@ -78,35 +72,30 @@
 	s16 MB, MC, MD;
 };
 
-
-/* Each client has this additional data */
 struct bmp085_data {
-	struct i2c_client *client;
-	struct mutex lock;
-	struct bmp085_calibration_data calibration;
-	u32 raw_temperature;
-	u32 raw_pressure;
-	unsigned char oversampling_setting;
+	struct	device *dev;
+	struct  regmap *regmap;
+	struct	mutex lock;
+	struct	bmp085_calibration_data calibration;
+	u8	oversampling_setting;
+	u32	raw_temperature;
+	u32	raw_pressure;
+	u32	temp_measurement_period;
 	unsigned long last_temp_measurement;
-	s32 b6; /* calculated temperature correction coefficient */
+	u8	chip_id;
+	s32	b6; /* calculated temperature correction coefficient */
 };
 
-
-static s32 bmp085_read_calibration_data(struct i2c_client *client)
+static s32 bmp085_read_calibration_data(struct bmp085_data *data)
 {
 	u16 tmp[BMP085_CALIBRATION_DATA_LENGTH];
-	struct bmp085_data *data = i2c_get_clientdata(client);
 	struct bmp085_calibration_data *cali = &(data->calibration);
-	s32 status = i2c_smbus_read_i2c_block_data(client,
-				BMP085_CALIBRATION_DATA_START,
-				BMP085_CALIBRATION_DATA_LENGTH*sizeof(u16),
-				(u8 *)tmp);
+	s32 status = regmap_bulk_read(data->regmap,
+				BMP085_CALIBRATION_DATA_START, (u8 *)tmp,
+				(BMP085_CALIBRATION_DATA_LENGTH << 1));
 	if (status < 0)
 		return status;
 
-	if (status != BMP085_CALIBRATION_DATA_LENGTH*sizeof(u16))
-		return -EIO;
-
 	cali->AC1 =  be16_to_cpu(tmp[0]);
 	cali->AC2 =  be16_to_cpu(tmp[1]);
 	cali->AC3 =  be16_to_cpu(tmp[2]);
@@ -121,30 +110,26 @@
 	return 0;
 }
 
-
 static s32 bmp085_update_raw_temperature(struct bmp085_data *data)
 {
 	u16 tmp;
 	s32 status;
 
 	mutex_lock(&data->lock);
-	status = i2c_smbus_write_byte_data(data->client, BMP085_CTRL_REG,
-						BMP085_TEMP_MEASUREMENT);
-	if (status != 0) {
-		dev_err(&data->client->dev,
+	status = regmap_write(data->regmap, BMP085_CTRL_REG,
+			      BMP085_TEMP_MEASUREMENT);
+	if (status < 0) {
+		dev_err(data->dev,
 			"Error while requesting temperature measurement.\n");
 		goto exit;
 	}
 	msleep(BMP085_TEMP_CONVERSION_TIME);
 
-	status = i2c_smbus_read_i2c_block_data(data->client,
-		BMP085_CONVERSION_REGISTER_MSB, sizeof(tmp), (u8 *)&tmp);
-	if (status < 0)
-		goto exit;
-	if (status != sizeof(tmp)) {
-		dev_err(&data->client->dev,
+	status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
+				 &tmp, sizeof(tmp));
+	if (status < 0) {
+		dev_err(data->dev,
 			"Error while reading temperature measurement result\n");
-		status = -EIO;
 		goto exit;
 	}
 	data->raw_temperature = be16_to_cpu(tmp);
@@ -162,10 +147,11 @@
 	s32 status;
 
 	mutex_lock(&data->lock);
-	status = i2c_smbus_write_byte_data(data->client, BMP085_CTRL_REG,
-		BMP085_PRESSURE_MEASUREMENT + (data->oversampling_setting<<6));
-	if (status != 0) {
-		dev_err(&data->client->dev,
+	status = regmap_write(data->regmap, BMP085_CTRL_REG,
+			BMP085_PRESSURE_MEASUREMENT +
+			(data->oversampling_setting << 6));
+	if (status < 0) {
+		dev_err(data->dev,
 			"Error while requesting pressure measurement.\n");
 		goto exit;
 	}
@@ -174,14 +160,11 @@
 	msleep(2+(3 << data->oversampling_setting));
 
 	/* copy data into a u32 (4 bytes), but skip the first byte. */
-	status = i2c_smbus_read_i2c_block_data(data->client,
-			BMP085_CONVERSION_REGISTER_MSB, 3, ((u8 *)&tmp)+1);
-	if (status < 0)
-		goto exit;
-	if (status != 3) {
-		dev_err(&data->client->dev,
+	status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
+				 ((u8 *)&tmp)+1, 3);
+	if (status < 0) {
+		dev_err(data->dev,
 			"Error while reading pressure measurement results\n");
-		status = -EIO;
 		goto exit;
 	}
 	data->raw_pressure = be32_to_cpu((tmp));
@@ -193,7 +176,6 @@
 	return status;
 }
 
-
 /*
  * This function starts the temperature measurement and returns the value
  * in tenth of a degree celsius.
@@ -205,7 +187,7 @@
 	int status;
 
 	status = bmp085_update_raw_temperature(data);
-	if (status != 0)
+	if (status < 0)
 		goto exit;
 
 	x1 = ((data->raw_temperature - cali->AC6) * cali->AC5) >> 15;
@@ -222,8 +204,10 @@
 /*
  * This function starts the pressure measurement and returns the value
  * in millibar. Since the pressure depends on the ambient temperature,
- * a temperature measurement is executed if the last known value is older
- * than one second.
+ * a temperature measurement is executed according to the given temperature
+ * measurement period (default is 1 sec boundary). This period could vary
+ * and needs to be adjusted according to the sensor environment, i.e. if big
+ * temperature variations then the temperature needs to be read out often.
  */
 static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure)
 {
@@ -234,16 +218,16 @@
 	int status;
 
 	/* alt least every second force an update of the ambient temperature */
-	if (data->last_temp_measurement == 0 ||
-			time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) {
+	if ((data->last_temp_measurement == 0) ||
+	    time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) {
 		status = bmp085_get_temperature(data, NULL);
-		if (status != 0)
-			goto exit;
+		if (status < 0)
+			return status;
 	}
 
 	status = bmp085_update_raw_pressure(data);
-	if (status != 0)
-		goto exit;
+	if (status < 0)
+		return status;
 
 	x1 = (data->b6 * data->b6) >> 12;
 	x1 *= cali->B2;
@@ -274,15 +258,14 @@
 
 	*pressure = p;
 
-exit:
-	return status;
+	return 0;
 }
 
 /*
  * This function sets the chip-internal oversampling. Valid values are 0..3.
  * The chip will use 2^oversampling samples for internal averaging.
  * This influences the measurement time and the accuracy; larger values
- * increase both. The datasheet gives on overview on how measurement time,
+ * increase both. The datasheet gives an overview on how measurement time,
  * accuracy and noise correlate.
  */
 static void bmp085_set_oversampling(struct bmp085_data *data,
@@ -306,22 +289,25 @@
 				struct device_attribute *attr,
 				const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct bmp085_data *data = i2c_get_clientdata(client);
+	struct bmp085_data *data = dev_get_drvdata(dev);
 	unsigned long oversampling;
-	int success = strict_strtoul(buf, 10, &oversampling);
-	if (success == 0) {
+	int err = kstrtoul(buf, 10, &oversampling);
+
+	if (err == 0) {
+		mutex_lock(&data->lock);
 		bmp085_set_oversampling(data, oversampling);
+		mutex_unlock(&data->lock);
 		return count;
 	}
-	return success;
+
+	return err;
 }
 
 static ssize_t show_oversampling(struct device *dev,
 				 struct device_attribute *attr, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct bmp085_data *data = i2c_get_clientdata(client);
+	struct bmp085_data *data = dev_get_drvdata(dev);
+
 	return sprintf(buf, "%u\n", bmp085_get_oversampling(data));
 }
 static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO,
@@ -333,11 +319,10 @@
 {
 	int temperature;
 	int status;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct bmp085_data *data = i2c_get_clientdata(client);
+	struct bmp085_data *data = dev_get_drvdata(dev);
 
 	status = bmp085_get_temperature(data, &temperature);
-	if (status != 0)
+	if (status < 0)
 		return status;
 	else
 		return sprintf(buf, "%d\n", temperature);
@@ -350,11 +335,10 @@
 {
 	int pressure;
 	int status;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct bmp085_data *data = i2c_get_clientdata(client);
+	struct bmp085_data *data = dev_get_drvdata(dev);
 
 	status = bmp085_get_pressure(data, &pressure);
-	if (status != 0)
+	if (status < 0)
 		return status;
 	else
 		return sprintf(buf, "%d\n", pressure);
@@ -373,38 +357,70 @@
 	.attrs = bmp085_attributes,
 };
 
-static int bmp085_detect(struct i2c_client *client, struct i2c_board_info *info)
+int bmp085_detect(struct device *dev)
 {
-	if (client->addr != BMP085_I2C_ADDRESS)
-		return -ENODEV;
+	struct bmp085_data *data = dev_get_drvdata(dev);
+	unsigned int id;
+	int ret;
 
-	if (i2c_smbus_read_byte_data(client, BMP085_CHIP_ID_REG) != BMP085_CHIP_ID)
+	ret = regmap_read(data->regmap, BMP085_CHIP_ID_REG, &id);
+	if (ret < 0)
+		return ret;
+
+	if (id != data->chip_id)
 		return -ENODEV;
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(bmp085_detect);
 
-static int bmp085_init_client(struct i2c_client *client)
+static void __init bmp085_get_of_properties(struct bmp085_data *data)
 {
-	unsigned char version;
-	int status;
-	struct bmp085_data *data = i2c_get_clientdata(client);
-	data->client = client;
-	status = bmp085_read_calibration_data(client);
-	if (status != 0)
-		goto exit;
-	version = i2c_smbus_read_byte_data(client, BMP085_VERSION_REG);
-	data->last_temp_measurement = 0;
-	data->oversampling_setting = 3;
-	mutex_init(&data->lock);
-	dev_info(&data->client->dev, "BMP085 ver. %d.%d found.\n",
-			(version & 0x0F), (version & 0xF0) >> 4);
-exit:
-	return status;
+#ifdef CONFIG_OF
+	struct device_node *np = data->dev->of_node;
+	u32 prop;
+
+	if (!np)
+		return;
+
+	if (!of_property_read_u32(np, "chip-id", &prop))
+		data->chip_id = prop & 0xff;
+
+	if (!of_property_read_u32(np, "temp-measurement-period", &prop))
+		data->temp_measurement_period = (prop/100)*HZ;
+
+	if (!of_property_read_u32(np, "default-oversampling", &prop))
+		data->oversampling_setting = prop & 0xff;
+#endif
 }
 
-static int __devinit bmp085_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
+static int bmp085_init_client(struct bmp085_data *data)
+{
+	int status = bmp085_read_calibration_data(data);
+
+	if (status < 0)
+		return status;
+
+	/* default settings */
+	data->chip_id = BMP085_CHIP_ID;
+	data->last_temp_measurement = 0;
+	data->temp_measurement_period = 1*HZ;
+	data->oversampling_setting = 3;
+
+	bmp085_get_of_properties(data);
+
+	mutex_init(&data->lock);
+
+	return 0;
+}
+
+struct regmap_config bmp085_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8
+};
+EXPORT_SYMBOL_GPL(bmp085_regmap_config);
+
+__devinit int bmp085_probe(struct device *dev, struct regmap *regmap)
 {
 	struct bmp085_data *data;
 	int err = 0;
@@ -415,58 +431,48 @@
 		goto exit;
 	}
 
-	/* default settings after POR */
-	data->oversampling_setting = 0x00;
-
-	i2c_set_clientdata(client, data);
+	dev_set_drvdata(dev, data);
+	data->dev = dev;
+	data->regmap = regmap;
 
 	/* Initialize the BMP085 chip */
-	err = bmp085_init_client(client);
-	if (err != 0)
+	err = bmp085_init_client(data);
+	if (err < 0)
 		goto exit_free;
 
+	err = bmp085_detect(dev);
+	if (err < 0) {
+		dev_err(dev, "%s: chip_id failed!\n", BMP085_NAME);
+		goto exit_free;
+	}
+
 	/* Register sysfs hooks */
-	err = sysfs_create_group(&client->dev.kobj, &bmp085_attr_group);
+	err = sysfs_create_group(&dev->kobj, &bmp085_attr_group);
 	if (err)
 		goto exit_free;
 
-	dev_info(&data->client->dev, "Successfully initialized bmp085!\n");
-	goto exit;
+	dev_info(dev, "Successfully initialized %s!\n", BMP085_NAME);
+
+	return 0;
 
 exit_free:
 	kfree(data);
 exit:
 	return err;
 }
+EXPORT_SYMBOL_GPL(bmp085_probe);
 
-static int __devexit bmp085_remove(struct i2c_client *client)
+int bmp085_remove(struct device *dev)
 {
-	sysfs_remove_group(&client->dev.kobj, &bmp085_attr_group);
-	kfree(i2c_get_clientdata(client));
+	struct bmp085_data *data = dev_get_drvdata(dev);
+
+	sysfs_remove_group(&data->dev->kobj, &bmp085_attr_group);
+	kfree(data);
+
 	return 0;
 }
+EXPORT_SYMBOL_GPL(bmp085_remove);
 
-static const struct i2c_device_id bmp085_id[] = {
-	{ "bmp085", 0 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, bmp085_id);
-
-static struct i2c_driver bmp085_driver = {
-	.driver = {
-		.owner = THIS_MODULE,
-		.name	= "bmp085"
-	},
-	.id_table	= bmp085_id,
-	.probe		= bmp085_probe,
-	.remove		= __devexit_p(bmp085_remove),
-
-	.detect		= bmp085_detect,
-	.address_list	= normal_i2c
-};
-
-module_i2c_driver(bmp085_driver);
-
-MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com");
+MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com>");
 MODULE_DESCRIPTION("BMP085 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085.h b/drivers/misc/bmp085.h
new file mode 100644
index 0000000..2b8f615
--- /dev/null
+++ b/drivers/misc/bmp085.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012  Bosch Sensortec GmbH
+ * Copyright (c) 2012  Unixphere AB
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BMP085_H
+#define _BMP085_H
+
+#include <linux/regmap.h>
+
+#define BMP085_NAME		"bmp085"
+
+extern struct regmap_config bmp085_regmap_config;
+
+int bmp085_probe(struct device *dev, struct regmap *regmap);
+int bmp085_remove(struct device *dev);
+int bmp085_detect(struct device *dev);
+
+#endif
diff --git a/drivers/misc/c2port/Kconfig b/drivers/misc/c2port/Kconfig
index e46af9a..33ee834 100644
--- a/drivers/misc/c2port/Kconfig
+++ b/drivers/misc/c2port/Kconfig
@@ -5,7 +5,7 @@
 menuconfig C2PORT
 	tristate "Silicon Labs C2 port support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
-	default no
+	default n
 	help
 	  This option enables support for Silicon Labs C2 port used to
 	  program Silicon micro controller chips (and other 8051 compatible).
@@ -23,8 +23,8 @@
 
 config C2PORT_DURAMAR_2150
 	tristate "C2 port support for Eurotech's Duramar 2150 (EXPERIMENTAL)"
-	depends on X86 && C2PORT
-	default no
+	depends on X86
+	default n
 	help
 	  This option enables C2 support for the Eurotech's Duramar 2150
 	  on board micro controller.
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 01ab3c9..0842c29 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -50,6 +50,7 @@
 #define	AT25_SR_BP1	0x08
 #define	AT25_SR_WPEN	0x80		/* writeprotect enable */
 
+#define	AT25_INSTR_BIT3	0x08		/* Additional address bit in instr */
 
 #define EE_MAXADDRLEN	3		/* 24 bit addresses, up to 2 MBytes */
 
@@ -75,6 +76,7 @@
 	ssize_t			status;
 	struct spi_transfer	t[2];
 	struct spi_message	m;
+	u8			instr;
 
 	if (unlikely(offset >= at25->bin.size))
 		return 0;
@@ -84,7 +86,12 @@
 		return count;
 
 	cp = command;
-	*cp++ = AT25_READ;
+
+	instr = AT25_READ;
+	if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
+		if (offset >= (1U << (at25->addrlen * 8)))
+			instr |= AT25_INSTR_BIT3;
+	*cp++ = instr;
 
 	/* 8/16/24-bit address is written MSB first */
 	switch (at25->addrlen) {
@@ -167,14 +174,14 @@
 	/* For write, rollover is within the page ... so we write at
 	 * most one page, then manually roll over to the next page.
 	 */
-	bounce[0] = AT25_WRITE;
 	mutex_lock(&at25->lock);
 	do {
 		unsigned long	timeout, retries;
 		unsigned	segment;
 		unsigned	offset = (unsigned) off;
-		u8		*cp = bounce + 1;
+		u8		*cp = bounce;
 		int		sr;
+		u8		instr;
 
 		*cp = AT25_WREN;
 		status = spi_write(at25->spi, cp, 1);
@@ -184,6 +191,12 @@
 			break;
 		}
 
+		instr = AT25_WRITE;
+		if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
+			if (offset >= (1U << (at25->addrlen * 8)))
+				instr |= AT25_INSTR_BIT3;
+		*cp++ = instr;
+
 		/* 8/16/24-bit address is written MSB first */
 		switch (at25->addrlen) {
 		default:	/* case 3 */
diff --git a/drivers/misc/max8997-muic.c b/drivers/misc/max8997-muic.c
deleted file mode 100644
index 19591ea..0000000
--- a/drivers/misc/max8997-muic.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * max8997-muic.c - MAX8997 muic driver for the Maxim 8997
- *
- *  Copyright (C) 2011 Samsung Electrnoics
- *  Donggeun Kim <dg77.kim@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.
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/kobject.h>
-#include <linux/mfd/max8997.h>
-#include <linux/mfd/max8997-private.h>
-
-/* MAX8997-MUIC STATUS1 register */
-#define STATUS1_ADC_SHIFT		0
-#define STATUS1_ADCLOW_SHIFT		5
-#define STATUS1_ADCERR_SHIFT		6
-#define STATUS1_ADC_MASK		(0x1f << STATUS1_ADC_SHIFT)
-#define STATUS1_ADCLOW_MASK		(0x1 << STATUS1_ADCLOW_SHIFT)
-#define STATUS1_ADCERR_MASK		(0x1 << STATUS1_ADCERR_SHIFT)
-
-/* MAX8997-MUIC STATUS2 register */
-#define STATUS2_CHGTYP_SHIFT		0
-#define STATUS2_CHGDETRUN_SHIFT		3
-#define STATUS2_DCDTMR_SHIFT		4
-#define STATUS2_DBCHG_SHIFT		5
-#define STATUS2_VBVOLT_SHIFT		6
-#define STATUS2_CHGTYP_MASK		(0x7 << STATUS2_CHGTYP_SHIFT)
-#define STATUS2_CHGDETRUN_MASK		(0x1 << STATUS2_CHGDETRUN_SHIFT)
-#define STATUS2_DCDTMR_MASK		(0x1 << STATUS2_DCDTMR_SHIFT)
-#define STATUS2_DBCHG_MASK		(0x1 << STATUS2_DBCHG_SHIFT)
-#define STATUS2_VBVOLT_MASK		(0x1 << STATUS2_VBVOLT_SHIFT)
-
-/* MAX8997-MUIC STATUS3 register */
-#define STATUS3_OVP_SHIFT		2
-#define STATUS3_OVP_MASK		(0x1 << STATUS3_OVP_SHIFT)
-
-/* MAX8997-MUIC CONTROL1 register */
-#define COMN1SW_SHIFT			0
-#define COMP2SW_SHIFT			3
-#define COMN1SW_MASK			(0x7 << COMN1SW_SHIFT)
-#define COMP2SW_MASK			(0x7 << COMP2SW_SHIFT)
-#define SW_MASK				(COMP2SW_MASK | COMN1SW_MASK)
-
-#define MAX8997_SW_USB		((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT))
-#define MAX8997_SW_AUDIO	((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT))
-#define MAX8997_SW_UART		((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT))
-#define MAX8997_SW_OPEN		((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT))
-
-#define	MAX8997_ADC_GROUND		0x00
-#define	MAX8997_ADC_MHL			0x01
-#define	MAX8997_ADC_JIG_USB_1		0x18
-#define	MAX8997_ADC_JIG_USB_2		0x19
-#define	MAX8997_ADC_DESKDOCK		0x1a
-#define	MAX8997_ADC_JIG_UART		0x1c
-#define	MAX8997_ADC_CARDOCK		0x1d
-#define	MAX8997_ADC_OPEN		0x1f
-
-struct max8997_muic_irq {
-	unsigned int irq;
-	const char *name;
-};
-
-static struct max8997_muic_irq muic_irqs[] = {
-	{ MAX8997_MUICIRQ_ADCError, "muic-ADC_error" },
-	{ MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" },
-	{ MAX8997_MUICIRQ_ADC, "muic-ADC" },
-	{ MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" },
-	{ MAX8997_MUICIRQ_DBChg, "muic-DB_charger" },
-	{ MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" },
-	{ MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" },
-	{ MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" },
-	{ MAX8997_MUICIRQ_OVP, "muic-over_voltage" },
-};
-
-struct max8997_muic_info {
-	struct device *dev;
-	struct max8997_dev *iodev;
-	struct i2c_client *muic;
-	struct max8997_muic_platform_data *muic_pdata;
-
-	int irq;
-	struct work_struct irq_work;
-
-	enum max8997_muic_charger_type pre_charger_type;
-	int pre_adc;
-
-	struct mutex mutex;
-};
-
-static int max8997_muic_handle_usb(struct max8997_muic_info *info,
-			enum max8997_muic_usb_type usb_type, bool attached)
-{
-	struct max8997_muic_platform_data *mdata = info->muic_pdata;
-	int ret = 0;
-
-	if (usb_type == MAX8997_USB_HOST) {
-		/* switch to USB */
-		ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
-				attached ? MAX8997_SW_USB : MAX8997_SW_OPEN,
-				SW_MASK);
-		if (ret) {
-			dev_err(info->dev, "failed to update muic register\n");
-			goto out;
-		}
-	}
-
-	if (mdata->usb_callback)
-		mdata->usb_callback(usb_type, attached);
-out:
-	return ret;
-}
-
-static void max8997_muic_handle_mhl(struct max8997_muic_info *info,
-			bool attached)
-{
-	struct max8997_muic_platform_data *mdata = info->muic_pdata;
-
-	if (mdata->mhl_callback)
-		mdata->mhl_callback(attached);
-}
-
-static int max8997_muic_handle_dock(struct max8997_muic_info *info,
-			int adc, bool attached)
-{
-	struct max8997_muic_platform_data *mdata = info->muic_pdata;
-	int ret = 0;
-
-	/* switch to AUDIO */
-	ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
-				attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN,
-				SW_MASK);
-	if (ret) {
-		dev_err(info->dev, "failed to update muic register\n");
-		goto out;
-	}
-
-	switch (adc) {
-	case MAX8997_ADC_DESKDOCK:
-		if (mdata->deskdock_callback)
-			mdata->deskdock_callback(attached);
-		break;
-	case MAX8997_ADC_CARDOCK:
-		if (mdata->cardock_callback)
-			mdata->cardock_callback(attached);
-		break;
-	default:
-		break;
-	}
-out:
-	return ret;
-}
-
-static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
-			bool attached)
-{
-	struct max8997_muic_platform_data *mdata = info->muic_pdata;
-	int ret = 0;
-
-	/* switch to UART */
-	ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
-				attached ? MAX8997_SW_UART : MAX8997_SW_OPEN,
-				SW_MASK);
-	if (ret) {
-		dev_err(info->dev, "failed to update muic register\n");
-		goto out;
-	}
-
-	if (mdata->uart_callback)
-		mdata->uart_callback(attached);
-out:
-	return ret;
-}
-
-static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info)
-{
-	int ret = 0;
-
-	switch (info->pre_adc) {
-	case MAX8997_ADC_GROUND:
-		ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false);
-		break;
-	case MAX8997_ADC_MHL:
-		max8997_muic_handle_mhl(info, false);
-		break;
-	case MAX8997_ADC_JIG_USB_1:
-	case MAX8997_ADC_JIG_USB_2:
-		ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false);
-		break;
-	case MAX8997_ADC_DESKDOCK:
-	case MAX8997_ADC_CARDOCK:
-		ret = max8997_muic_handle_dock(info, info->pre_adc, false);
-		break;
-	case MAX8997_ADC_JIG_UART:
-		ret = max8997_muic_handle_jig_uart(info, false);
-		break;
-	default:
-		break;
-	}
-
-	return ret;
-}
-
-static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
-{
-	int ret = 0;
-
-	switch (adc) {
-	case MAX8997_ADC_GROUND:
-		ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
-		break;
-	case MAX8997_ADC_MHL:
-		max8997_muic_handle_mhl(info, true);
-		break;
-	case MAX8997_ADC_JIG_USB_1:
-	case MAX8997_ADC_JIG_USB_2:
-		ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true);
-		break;
-	case MAX8997_ADC_DESKDOCK:
-	case MAX8997_ADC_CARDOCK:
-		ret = max8997_muic_handle_dock(info, adc, true);
-		break;
-	case MAX8997_ADC_JIG_UART:
-		ret = max8997_muic_handle_jig_uart(info, true);
-		break;
-	case MAX8997_ADC_OPEN:
-		ret = max8997_muic_handle_adc_detach(info);
-		break;
-	default:
-		break;
-	}
-
-	info->pre_adc = adc;
-
-	return ret;
-}
-
-static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
-				enum max8997_muic_charger_type charger_type)
-{
-	struct max8997_muic_platform_data *mdata = info->muic_pdata;
-	u8 adc;
-	int ret;
-
-	ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc);
-	if (ret) {
-		dev_err(info->dev, "failed to read muic register\n");
-		goto out;
-	}
-
-	switch (charger_type) {
-	case MAX8997_CHARGER_TYPE_NONE:
-		if (mdata->charger_callback)
-			mdata->charger_callback(false, charger_type);
-		if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) {
-			max8997_muic_handle_usb(info,
-					MAX8997_USB_DEVICE, false);
-		}
-		break;
-	case MAX8997_CHARGER_TYPE_USB:
-		if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) {
-			max8997_muic_handle_usb(info,
-					MAX8997_USB_DEVICE, true);
-		}
-		if (mdata->charger_callback)
-			mdata->charger_callback(true, charger_type);
-		break;
-	case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
-	case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
-	case MAX8997_CHARGER_TYPE_500MA:
-	case MAX8997_CHARGER_TYPE_1A:
-		if (mdata->charger_callback)
-			mdata->charger_callback(true, charger_type);
-		break;
-	default:
-		break;
-	}
-
-	info->pre_charger_type = charger_type;
-out:
-	return ret;
-}
-
-static void max8997_muic_irq_work(struct work_struct *work)
-{
-	struct max8997_muic_info *info = container_of(work,
-			struct max8997_muic_info, irq_work);
-	struct max8997_platform_data *pdata =
-				dev_get_platdata(info->iodev->dev);
-	u8 status[3];
-	u8 adc, chg_type;
-
-	int irq_type = info->irq - pdata->irq_base;
-	int ret;
-
-	mutex_lock(&info->mutex);
-
-	ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
-				3, status);
-	if (ret) {
-		dev_err(info->dev, "failed to read muic register\n");
-		mutex_unlock(&info->mutex);
-		return;
-	}
-
-	dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
-			status[0], status[1]);
-
-	switch (irq_type) {
-	case MAX8997_MUICIRQ_ADC:
-		adc = status[0] & STATUS1_ADC_MASK;
-		adc >>= STATUS1_ADC_SHIFT;
-
-		max8997_muic_handle_adc(info, adc);
-		break;
-	case MAX8997_MUICIRQ_ChgTyp:
-		chg_type = status[1] & STATUS2_CHGTYP_MASK;
-		chg_type >>= STATUS2_CHGTYP_SHIFT;
-
-		max8997_muic_handle_charger_type(info, chg_type);
-		break;
-	default:
-		dev_info(info->dev, "misc interrupt: %s occurred\n",
-			 muic_irqs[irq_type].name);
-		break;
-	}
-
-	mutex_unlock(&info->mutex);
-
-	return;
-}
-
-static irqreturn_t max8997_muic_irq_handler(int irq, void *data)
-{
-	struct max8997_muic_info *info = data;
-
-	dev_dbg(info->dev, "irq:%d\n", irq);
-	info->irq = irq;
-
-	schedule_work(&info->irq_work);
-
-	return IRQ_HANDLED;
-}
-
-static void max8997_muic_detect_dev(struct max8997_muic_info *info)
-{
-	int ret;
-	u8 status[2], adc, chg_type;
-
-	ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
-				2, status);
-	if (ret) {
-		dev_err(info->dev, "failed to read muic register\n");
-		return;
-	}
-
-	dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n",
-			status[0], status[1]);
-
-	adc = status[0] & STATUS1_ADC_MASK;
-	adc >>= STATUS1_ADC_SHIFT;
-
-	chg_type = status[1] & STATUS2_CHGTYP_MASK;
-	chg_type >>= STATUS2_CHGTYP_SHIFT;
-
-	max8997_muic_handle_adc(info, adc);
-	max8997_muic_handle_charger_type(info, chg_type);
-}
-
-static void max8997_initialize_device(struct max8997_muic_info *info)
-{
-	struct max8997_muic_platform_data *mdata = info->muic_pdata;
-	int i;
-
-	for (i = 0; i < mdata->num_init_data; i++) {
-		max8997_write_reg(info->muic, mdata->init_data[i].addr,
-				mdata->init_data[i].data);
-	}
-}
-
-static int __devinit max8997_muic_probe(struct platform_device *pdev)
-{
-	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-	struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
-	struct max8997_muic_info *info;
-	int ret, i;
-
-	info = kzalloc(sizeof(struct max8997_muic_info), GFP_KERNEL);
-	if (!info) {
-		dev_err(&pdev->dev, "failed to allocate memory\n");
-		ret = -ENOMEM;
-		goto err_kfree;
-	}
-
-	if (!pdata->muic_pdata) {
-		dev_err(&pdev->dev, "failed to get platform_data\n");
-		ret = -EINVAL;
-		goto err_pdata;
-	}
-	info->muic_pdata = pdata->muic_pdata;
-
-	info->dev = &pdev->dev;
-	info->iodev = iodev;
-	info->muic = iodev->muic;
-
-	platform_set_drvdata(pdev, info);
-	mutex_init(&info->mutex);
-
-	INIT_WORK(&info->irq_work, max8997_muic_irq_work);
-
-	for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
-		struct max8997_muic_irq *muic_irq = &muic_irqs[i];
-
-		ret = request_threaded_irq(pdata->irq_base + muic_irq->irq,
-				NULL, max8997_muic_irq_handler,
-				0, muic_irq->name,
-				info);
-		if (ret) {
-			dev_err(&pdev->dev,
-				"failed: irq request (IRQ: %d,"
-				" error :%d)\n",
-				muic_irq->irq, ret);
-
-			for (i = i - 1; i >= 0; i--)
-				free_irq(muic_irq->irq, info);
-
-			goto err_irq;
-		}
-	}
-
-	/* Initialize registers according to platform data */
-	max8997_initialize_device(info);
-
-	/* Initial device detection */
-	max8997_muic_detect_dev(info);
-
-	return ret;
-
-err_irq:
-err_pdata:
-	kfree(info);
-err_kfree:
-	return ret;
-}
-
-static int __devexit max8997_muic_remove(struct platform_device *pdev)
-{
-	struct max8997_muic_info *info = platform_get_drvdata(pdev);
-	struct max8997_platform_data *pdata =
-				dev_get_platdata(info->iodev->dev);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
-		free_irq(pdata->irq_base + muic_irqs[i].irq, info);
-	cancel_work_sync(&info->irq_work);
-
-	kfree(info);
-
-	return 0;
-}
-
-static struct platform_driver max8997_muic_driver = {
-	.driver		= {
-		.name	= "max8997-muic",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= max8997_muic_probe,
-	.remove		= __devexit_p(max8997_muic_remove),
-};
-
-module_platform_driver(max8997_muic_driver);
-
-MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver");
-MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mei/Kconfig b/drivers/misc/mei/Kconfig
similarity index 100%
rename from drivers/staging/mei/Kconfig
rename to drivers/misc/mei/Kconfig
diff --git a/drivers/staging/mei/Makefile b/drivers/misc/mei/Makefile
similarity index 100%
rename from drivers/staging/mei/Makefile
rename to drivers/misc/mei/Makefile
diff --git a/drivers/staging/mei/hw.h b/drivers/misc/mei/hw.h
similarity index 100%
rename from drivers/staging/mei/hw.h
rename to drivers/misc/mei/hw.h
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
new file mode 100644
index 0000000..a7d0bb0
--- /dev/null
+++ b/drivers/misc/mei/init.c
@@ -0,0 +1,735 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, 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.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include "mei_dev.h"
+#include "hw.h"
+#include "interface.h"
+#include <linux/mei.h>
+
+const uuid_le mei_amthi_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
+						0xa8, 0x46, 0xe0, 0xff, 0x65,
+						0x81, 0x4c);
+
+/**
+ * mei_io_list_init - Sets up a queue list.
+ *
+ * @list: An instance io list structure
+ * @dev: the device structure
+ */
+void mei_io_list_init(struct mei_io_list *list)
+{
+	/* initialize our queue list */
+	INIT_LIST_HEAD(&list->mei_cb.cb_list);
+}
+
+/**
+ * mei_io_list_flush - removes list entry belonging to cl.
+ *
+ * @list:  An instance of our list structure
+ * @cl: private data of the file object
+ */
+void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl)
+{
+	struct mei_cl_cb *pos;
+	struct mei_cl_cb *next;
+
+	list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) {
+		if (pos->file_private) {
+			struct mei_cl *cl_tmp;
+			cl_tmp = (struct mei_cl *)pos->file_private;
+			if (mei_cl_cmp_id(cl, cl_tmp))
+				list_del(&pos->cb_list);
+		}
+	}
+}
+/**
+ * mei_cl_flush_queues - flushes queue lists belonging to cl.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ */
+int mei_cl_flush_queues(struct mei_cl *cl)
+{
+	if (!cl || !cl->dev)
+		return -EINVAL;
+
+	dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
+	mei_io_list_flush(&cl->dev->read_list, cl);
+	mei_io_list_flush(&cl->dev->write_list, cl);
+	mei_io_list_flush(&cl->dev->write_waiting_list, cl);
+	mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
+	mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
+	mei_io_list_flush(&cl->dev->amthi_cmd_list, cl);
+	mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl);
+	return 0;
+}
+
+
+
+/**
+ * mei_reset_iamthif_params - initializes mei device iamthif
+ *
+ * @dev: the device structure
+ */
+static void mei_reset_iamthif_params(struct mei_device *dev)
+{
+	/* reset iamthif parameters. */
+	dev->iamthif_current_cb = NULL;
+	dev->iamthif_msg_buf_size = 0;
+	dev->iamthif_msg_buf_index = 0;
+	dev->iamthif_canceled = false;
+	dev->iamthif_ioctl = false;
+	dev->iamthif_state = MEI_IAMTHIF_IDLE;
+	dev->iamthif_timer = 0;
+}
+
+/**
+ * init_mei_device - allocates and initializes the mei device structure
+ *
+ * @pdev: The pci device structure
+ *
+ * returns The mei_device_device pointer on success, NULL on failure.
+ */
+struct mei_device *mei_device_init(struct pci_dev *pdev)
+{
+	struct mei_device *dev;
+
+	dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	/* setup our list array */
+	INIT_LIST_HEAD(&dev->file_list);
+	INIT_LIST_HEAD(&dev->wd_cl.link);
+	INIT_LIST_HEAD(&dev->iamthif_cl.link);
+	mutex_init(&dev->device_lock);
+	init_waitqueue_head(&dev->wait_recvd_msg);
+	init_waitqueue_head(&dev->wait_stop_wd);
+	dev->mei_state = MEI_INITIALIZING;
+	dev->iamthif_state = MEI_IAMTHIF_IDLE;
+	dev->wd_interface_reg = false;
+
+
+	mei_io_list_init(&dev->read_list);
+	mei_io_list_init(&dev->write_list);
+	mei_io_list_init(&dev->write_waiting_list);
+	mei_io_list_init(&dev->ctrl_wr_list);
+	mei_io_list_init(&dev->ctrl_rd_list);
+	mei_io_list_init(&dev->amthi_cmd_list);
+	mei_io_list_init(&dev->amthi_read_complete_list);
+	dev->pdev = pdev;
+	return dev;
+}
+
+/**
+ * mei_hw_init - initializes host and fw to start work.
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_hw_init(struct mei_device *dev)
+{
+	int err = 0;
+	int ret;
+
+	mutex_lock(&dev->device_lock);
+
+	dev->host_hw_state = mei_hcsr_read(dev);
+	dev->me_hw_state = mei_mecsr_read(dev);
+	dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n",
+	    dev->host_hw_state, dev->me_hw_state);
+
+	/* acknowledge interrupt and stop interupts */
+	if ((dev->host_hw_state & H_IS) == H_IS)
+		mei_reg_write(dev, H_CSR, dev->host_hw_state);
+
+	dev->recvd_msg = false;
+	dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
+
+	mei_reset(dev, 1);
+
+	dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
+	    dev->host_hw_state, dev->me_hw_state);
+
+	/* wait for ME to turn on ME_RDY */
+	if (!dev->recvd_msg) {
+		mutex_unlock(&dev->device_lock);
+		err = wait_event_interruptible_timeout(dev->wait_recvd_msg,
+			dev->recvd_msg, MEI_INTEROP_TIMEOUT);
+		mutex_lock(&dev->device_lock);
+	}
+
+	if (err <= 0 && !dev->recvd_msg) {
+		dev->mei_state = MEI_DISABLED;
+		dev_dbg(&dev->pdev->dev,
+			"wait_event_interruptible_timeout failed"
+			"on wait for ME to turn on ME_RDY.\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
+	      ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
+		dev->mei_state = MEI_DISABLED;
+		dev_dbg(&dev->pdev->dev,
+			"host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
+			dev->host_hw_state, dev->me_hw_state);
+
+		if (!(dev->host_hw_state & H_RDY))
+			dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n");
+
+		if (!(dev->me_hw_state & ME_RDY_HRA))
+			dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
+
+		dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (dev->version.major_version != HBM_MAJOR_VERSION ||
+	    dev->version.minor_version != HBM_MINOR_VERSION) {
+		dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	dev->recvd_msg = false;
+	dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
+	    dev->host_hw_state, dev->me_hw_state);
+	dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n");
+	dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
+	dev_dbg(&dev->pdev->dev, "MEI  start success.\n");
+	ret = 0;
+
+out:
+	mutex_unlock(&dev->device_lock);
+	return ret;
+}
+
+/**
+ * mei_hw_reset - resets fw via mei csr register.
+ *
+ * @dev: the device structure
+ * @interrupts_enabled: if interrupt should be enabled after reset.
+ */
+static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled)
+{
+	dev->host_hw_state |= (H_RST | H_IG);
+
+	if (interrupts_enabled)
+		mei_enable_interrupts(dev);
+	else
+		mei_disable_interrupts(dev);
+}
+
+/**
+ * mei_reset - resets host and fw.
+ *
+ * @dev: the device structure
+ * @interrupts_enabled: if interrupt should be enabled after reset.
+ */
+void mei_reset(struct mei_device *dev, int interrupts_enabled)
+{
+	struct mei_cl *cl_pos = NULL;
+	struct mei_cl *cl_next = NULL;
+	struct mei_cl_cb *cb_pos = NULL;
+	struct mei_cl_cb *cb_next = NULL;
+	bool unexpected;
+
+	if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
+		dev->need_reset = true;
+		return;
+	}
+
+	unexpected = (dev->mei_state != MEI_INITIALIZING &&
+			dev->mei_state != MEI_DISABLED &&
+			dev->mei_state != MEI_POWER_DOWN &&
+			dev->mei_state != MEI_POWER_UP);
+
+	dev->host_hw_state = mei_hcsr_read(dev);
+
+	dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n",
+	    dev->host_hw_state);
+
+	mei_hw_reset(dev, interrupts_enabled);
+
+	dev->host_hw_state &= ~H_RST;
+	dev->host_hw_state |= H_IG;
+
+	mei_hcsr_set(dev);
+
+	dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n",
+	    dev->host_hw_state);
+
+	dev->need_reset = false;
+
+	if (dev->mei_state != MEI_INITIALIZING) {
+		if (dev->mei_state != MEI_DISABLED &&
+		    dev->mei_state != MEI_POWER_DOWN)
+			dev->mei_state = MEI_RESETING;
+
+		list_for_each_entry_safe(cl_pos,
+				cl_next, &dev->file_list, link) {
+			cl_pos->state = MEI_FILE_DISCONNECTED;
+			cl_pos->mei_flow_ctrl_creds = 0;
+			cl_pos->read_cb = NULL;
+			cl_pos->timer_count = 0;
+		}
+		/* remove entry if already in list */
+		dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n");
+		mei_remove_client_from_file_list(dev,
+				dev->wd_cl.host_client_id);
+
+		mei_remove_client_from_file_list(dev,
+				dev->iamthif_cl.host_client_id);
+
+		mei_reset_iamthif_params(dev);
+		dev->wd_due_counter = 0;
+		dev->extra_write_index = 0;
+	}
+
+	dev->me_clients_num = 0;
+	dev->rd_msg_hdr = 0;
+	dev->stop = false;
+	dev->wd_pending = false;
+
+	/* update the state of the registers after reset */
+	dev->host_hw_state = mei_hcsr_read(dev);
+	dev->me_hw_state = mei_mecsr_read(dev);
+
+	dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
+	    dev->host_hw_state, dev->me_hw_state);
+
+	if (unexpected)
+		dev_warn(&dev->pdev->dev, "unexpected reset.\n");
+
+	/* Wake up all readings so they can be interrupted */
+	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+		if (waitqueue_active(&cl_pos->rx_wait)) {
+			dev_dbg(&dev->pdev->dev, "Waking up client!\n");
+			wake_up_interruptible(&cl_pos->rx_wait);
+		}
+	}
+	/* remove all waiting requests */
+	list_for_each_entry_safe(cb_pos, cb_next,
+			&dev->write_list.mei_cb.cb_list, cb_list) {
+		list_del(&cb_pos->cb_list);
+		mei_free_cb_private(cb_pos);
+	}
+}
+
+
+
+/**
+ * host_start_message - mei host sends start message.
+ *
+ * @dev: the device structure
+ *
+ * returns none.
+ */
+void mei_host_start_message(struct mei_device *dev)
+{
+	struct mei_msg_hdr *mei_hdr;
+	struct hbm_host_version_request *host_start_req;
+
+	/* host start message */
+	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+	mei_hdr->host_addr = 0;
+	mei_hdr->me_addr = 0;
+	mei_hdr->length = sizeof(struct hbm_host_version_request);
+	mei_hdr->msg_complete = 1;
+	mei_hdr->reserved = 0;
+
+	host_start_req =
+	    (struct hbm_host_version_request *) &dev->wr_msg_buf[1];
+	memset(host_start_req, 0, sizeof(struct hbm_host_version_request));
+	host_start_req->hbm_cmd = HOST_START_REQ_CMD;
+	host_start_req->host_version.major_version = HBM_MAJOR_VERSION;
+	host_start_req->host_version.minor_version = HBM_MINOR_VERSION;
+	dev->recvd_msg = false;
+	if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
+				       mei_hdr->length)) {
+		dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
+		dev->mei_state = MEI_RESETING;
+		mei_reset(dev, 1);
+	}
+	dev->init_clients_state = MEI_START_MESSAGE;
+	dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
+	return ;
+}
+
+/**
+ * host_enum_clients_message - host sends enumeration client request message.
+ *
+ * @dev: the device structure
+ *
+ * returns none.
+ */
+void mei_host_enum_clients_message(struct mei_device *dev)
+{
+	struct mei_msg_hdr *mei_hdr;
+	struct hbm_host_enum_request *host_enum_req;
+	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+	/* enumerate clients */
+	mei_hdr->host_addr = 0;
+	mei_hdr->me_addr = 0;
+	mei_hdr->length = sizeof(struct hbm_host_enum_request);
+	mei_hdr->msg_complete = 1;
+	mei_hdr->reserved = 0;
+
+	host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
+	memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request));
+	host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
+	if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
+				mei_hdr->length)) {
+		dev->mei_state = MEI_RESETING;
+		dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
+		mei_reset(dev, 1);
+	}
+	dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
+	dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
+	return;
+}
+
+
+/**
+ * allocate_me_clients_storage - allocates storage for me clients
+ *
+ * @dev: the device structure
+ *
+ * returns none.
+ */
+void mei_allocate_me_clients_storage(struct mei_device *dev)
+{
+	struct mei_me_client *clients;
+	int b;
+
+	/* count how many ME clients we have */
+	for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
+		dev->me_clients_num++;
+
+	if (dev->me_clients_num <= 0)
+		return ;
+
+
+	if (dev->me_clients != NULL) {
+		kfree(dev->me_clients);
+		dev->me_clients = NULL;
+	}
+	dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
+		dev->me_clients_num * sizeof(struct mei_me_client));
+	/* allocate storage for ME clients representation */
+	clients = kcalloc(dev->me_clients_num,
+			sizeof(struct mei_me_client), GFP_KERNEL);
+	if (!clients) {
+		dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
+		dev->mei_state = MEI_RESETING;
+		mei_reset(dev, 1);
+		return ;
+	}
+	dev->me_clients = clients;
+	return ;
+}
+/**
+ * host_client_properties - reads properties for client
+ *
+ * @dev: the device structure
+ *
+ * returns:
+ * 	< 0 - Error.
+ *  = 0 - no more clients.
+ *  = 1 - still have clients to send properties request.
+ */
+int mei_host_client_properties(struct mei_device *dev)
+{
+	struct mei_msg_hdr *mei_header;
+	struct hbm_props_request *host_cli_req;
+	int b;
+	u8 client_num = dev->me_client_presentation_num;
+
+	b = dev->me_client_index;
+	b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b);
+	if (b < MEI_CLIENTS_MAX) {
+		dev->me_clients[client_num].client_id = b;
+		dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
+		mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
+		mei_header->host_addr = 0;
+		mei_header->me_addr = 0;
+		mei_header->length = sizeof(struct hbm_props_request);
+		mei_header->msg_complete = 1;
+		mei_header->reserved = 0;
+
+		host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1];
+
+		memset(host_cli_req, 0, sizeof(struct hbm_props_request));
+
+		host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
+		host_cli_req->address = b;
+
+		if (mei_write_message(dev, mei_header,
+				(unsigned char *)host_cli_req,
+				mei_header->length)) {
+			dev->mei_state = MEI_RESETING;
+			dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
+			mei_reset(dev, 1);
+			return -EIO;
+		}
+
+		dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
+		dev->me_client_index = b;
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * mei_init_file_private - initializes private file structure.
+ *
+ * @priv: private file structure to be initialized
+ * @file: the file structure
+ */
+void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
+{
+	memset(priv, 0, sizeof(struct mei_cl));
+	init_waitqueue_head(&priv->wait);
+	init_waitqueue_head(&priv->rx_wait);
+	init_waitqueue_head(&priv->tx_wait);
+	INIT_LIST_HEAD(&priv->link);
+	priv->reading_state = MEI_IDLE;
+	priv->writing_state = MEI_IDLE;
+	priv->dev = dev;
+}
+
+int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
+{
+	int i, res = -1;
+
+	for (i = 0; i < dev->me_clients_num; ++i)
+		if (uuid_le_cmp(cuuid,
+				dev->me_clients[i].props.protocol_name) == 0) {
+			res = i;
+			break;
+		}
+
+	return res;
+}
+
+
+/**
+ * mei_find_me_client_update_filext - searches for ME client guid
+ *                       sets client_id in mei_file_private if found
+ * @dev: the device structure
+ * @priv: private file structure to set client_id in
+ * @cguid: searched guid of ME client
+ * @client_id: id of host client to be set in file private structure
+ *
+ * returns ME client index
+ */
+u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
+				const uuid_le *cguid, u8 client_id)
+{
+	int i;
+
+	if (!dev || !priv || !cguid)
+		return 0;
+
+	/* check for valid client id */
+	i = mei_find_me_client_index(dev, *cguid);
+	if (i >= 0) {
+		priv->me_client_id = dev->me_clients[i].client_id;
+		priv->state = MEI_FILE_CONNECTING;
+		priv->host_client_id = client_id;
+
+		list_add_tail(&priv->link, &dev->file_list);
+		return (u8)i;
+	}
+
+	return 0;
+}
+
+/**
+ * host_init_iamthif - mei initialization iamthif client.
+ *
+ * @dev: the device structure
+ *
+ */
+void mei_host_init_iamthif(struct mei_device *dev)
+{
+	u8 i;
+	unsigned char *msg_buf;
+
+	mei_cl_init(&dev->iamthif_cl, dev);
+	dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
+
+	/* find ME amthi client */
+	i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl,
+			    &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
+	if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
+		dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
+		return;
+	}
+
+	/* Assign iamthif_mtu to the value received from ME  */
+
+	dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
+	dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
+			dev->me_clients[i].props.max_msg_length);
+
+	kfree(dev->iamthif_msg_buf);
+	dev->iamthif_msg_buf = NULL;
+
+	/* allocate storage for ME message buffer */
+	msg_buf = kcalloc(dev->iamthif_mtu,
+			sizeof(unsigned char), GFP_KERNEL);
+	if (!msg_buf) {
+		dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n");
+		return;
+	}
+
+	dev->iamthif_msg_buf = msg_buf;
+
+	if (mei_connect(dev, &dev->iamthif_cl)) {
+		dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n");
+		dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
+		dev->iamthif_cl.host_client_id = 0;
+	} else {
+		dev->iamthif_cl.timer_count = CONNECT_TIMEOUT;
+	}
+}
+
+/**
+ * mei_alloc_file_private - allocates a private file structure and sets it up.
+ * @file: the file structure
+ *
+ * returns  The allocated file or NULL on failure
+ */
+struct mei_cl *mei_cl_allocate(struct mei_device *dev)
+{
+	struct mei_cl *cl;
+
+	cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
+	if (!cl)
+		return NULL;
+
+	mei_cl_init(cl, dev);
+
+	return cl;
+}
+
+
+
+/**
+ * mei_disconnect_host_client - sends disconnect message to fw from host client.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
+{
+	int rets, err;
+	long timeout = 15;	/* 15 seconds */
+	struct mei_cl_cb *cb;
+
+	if (!dev || !cl)
+		return -ENODEV;
+
+	if (cl->state != MEI_FILE_DISCONNECTING)
+		return 0;
+
+	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
+	if (!cb)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&cb->cb_list);
+	cb->file_private = cl;
+	cb->major_file_operations = MEI_CLOSE;
+	if (dev->mei_host_buffer_is_empty) {
+		dev->mei_host_buffer_is_empty = false;
+		if (mei_disconnect(dev, cl)) {
+			rets = -ENODEV;
+			dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n");
+			goto free;
+		}
+		mdelay(10); /* Wait for hardware disconnection ready */
+		list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list);
+	} else {
+		dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
+		list_add_tail(&cb->cb_list,
+				&dev->ctrl_wr_list.mei_cb.cb_list);
+	}
+	mutex_unlock(&dev->device_lock);
+
+	err = wait_event_timeout(dev->wait_recvd_msg,
+		 (MEI_FILE_DISCONNECTED == cl->state),
+		 timeout * HZ);
+
+	mutex_lock(&dev->device_lock);
+	if (MEI_FILE_DISCONNECTED == cl->state) {
+		rets = 0;
+		dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
+	} else {
+		rets = -ENODEV;
+		if (MEI_FILE_DISCONNECTED != cl->state)
+			dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
+
+		if (err)
+			dev_dbg(&dev->pdev->dev,
+					"wait failed disconnect err=%08x\n",
+					err);
+
+		dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
+	}
+
+	mei_io_list_flush(&dev->ctrl_rd_list, cl);
+	mei_io_list_flush(&dev->ctrl_wr_list, cl);
+free:
+	mei_free_cb_private(cb);
+	return rets;
+}
+
+/**
+ * mei_remove_client_from_file_list -
+ *	removes file private data from device file list
+ *
+ * @dev: the device structure
+ * @host_client_id: host client id to be removed
+ */
+void mei_remove_client_from_file_list(struct mei_device *dev,
+				       u8 host_client_id)
+{
+	struct mei_cl *cl_pos = NULL;
+	struct mei_cl *cl_next = NULL;
+	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+		if (host_client_id == cl_pos->host_client_id) {
+			dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
+					cl_pos->host_client_id,
+					cl_pos->me_client_id);
+			list_del_init(&cl_pos->link);
+			break;
+		}
+	}
+}
diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c
new file mode 100644
index 0000000..428d21e
--- /dev/null
+++ b/drivers/misc/mei/interface.c
@@ -0,0 +1,428 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, 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.
+ *
+ */
+
+#include <linux/pci.h>
+#include "mei_dev.h"
+#include <linux/mei.h>
+#include "interface.h"
+
+
+
+/**
+ * mei_set_csr_register - writes H_CSR register to the mei device,
+ * and ignores the H_IS bit for it is write-one-to-zero.
+ *
+ * @dev: the device structure
+ */
+void mei_hcsr_set(struct mei_device *dev)
+{
+	if ((dev->host_hw_state & H_IS) == H_IS)
+		dev->host_hw_state &= ~H_IS;
+	mei_reg_write(dev, H_CSR, dev->host_hw_state);
+	dev->host_hw_state = mei_hcsr_read(dev);
+}
+
+/**
+ * mei_csr_enable_interrupts - enables mei device interrupts
+ *
+ * @dev: the device structure
+ */
+void mei_enable_interrupts(struct mei_device *dev)
+{
+	dev->host_hw_state |= H_IE;
+	mei_hcsr_set(dev);
+}
+
+/**
+ * mei_csr_disable_interrupts - disables mei device interrupts
+ *
+ * @dev: the device structure
+ */
+void mei_disable_interrupts(struct mei_device *dev)
+{
+	dev->host_hw_state &= ~H_IE;
+	mei_hcsr_set(dev);
+}
+
+/**
+ * _host_get_filled_slots - gets number of device filled buffer slots
+ *
+ * @device: the device structure
+ *
+ * returns number of filled slots
+ */
+static unsigned char _host_get_filled_slots(const struct mei_device *dev)
+{
+	char read_ptr, write_ptr;
+
+	read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8);
+	write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16);
+
+	return (unsigned char) (write_ptr - read_ptr);
+}
+
+/**
+ * mei_host_buffer_is_empty - checks if host buffer is empty.
+ *
+ * @dev: the device structure
+ *
+ * returns 1 if empty, 0 - otherwise.
+ */
+int mei_host_buffer_is_empty(struct mei_device *dev)
+{
+	unsigned char filled_slots;
+
+	dev->host_hw_state = mei_hcsr_read(dev);
+	filled_slots = _host_get_filled_slots(dev);
+
+	if (filled_slots == 0)
+		return 1;
+
+	return 0;
+}
+
+/**
+ * mei_count_empty_write_slots - counts write empty slots.
+ *
+ * @dev: the device structure
+ *
+ * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
+ */
+int mei_count_empty_write_slots(struct mei_device *dev)
+{
+	unsigned char buffer_depth, filled_slots, empty_slots;
+
+	dev->host_hw_state = mei_hcsr_read(dev);
+	buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
+	filled_slots = _host_get_filled_slots(dev);
+	empty_slots = buffer_depth - filled_slots;
+
+	/* check for overflow */
+	if (filled_slots > buffer_depth)
+		return -EOVERFLOW;
+
+	return empty_slots;
+}
+
+/**
+ * mei_write_message - writes a message to mei device.
+ *
+ * @dev: the device structure
+ * @header: header of message
+ * @write_buffer: message buffer will be written
+ * @write_length: message size will be written
+ *
+ * This function returns -EIO if write has failed
+ */
+int mei_write_message(struct mei_device *dev,
+		      struct mei_msg_hdr *header,
+		      unsigned char *write_buffer,
+		      unsigned long write_length)
+{
+	u32 temp_msg = 0;
+	unsigned long bytes_written = 0;
+	unsigned char buffer_depth, filled_slots, empty_slots;
+	unsigned long dw_to_write;
+
+	dev->host_hw_state = mei_hcsr_read(dev);
+
+	dev_dbg(&dev->pdev->dev,
+			"host_hw_state = 0x%08x.\n",
+			dev->host_hw_state);
+
+	dev_dbg(&dev->pdev->dev,
+			"mei_write_message header=%08x.\n",
+			*((u32 *) header));
+
+	buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
+	filled_slots = _host_get_filled_slots(dev);
+	empty_slots = buffer_depth - filled_slots;
+	dev_dbg(&dev->pdev->dev,
+			"filled = %hu, empty = %hu.\n",
+			filled_slots, empty_slots);
+
+	dw_to_write = ((write_length + 3) / 4);
+
+	if (dw_to_write > empty_slots)
+		return -EIO;
+
+	mei_reg_write(dev, H_CB_WW, *((u32 *) header));
+
+	while (write_length >= 4) {
+		mei_reg_write(dev, H_CB_WW,
+				*(u32 *) (write_buffer + bytes_written));
+		bytes_written += 4;
+		write_length -= 4;
+	}
+
+	if (write_length > 0) {
+		memcpy(&temp_msg, &write_buffer[bytes_written], write_length);
+		mei_reg_write(dev, H_CB_WW, temp_msg);
+	}
+
+	dev->host_hw_state |= H_IG;
+	mei_hcsr_set(dev);
+	dev->me_hw_state = mei_mecsr_read(dev);
+	if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * mei_count_full_read_slots - counts read full slots.
+ *
+ * @dev: the device structure
+ *
+ * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
+ */
+int mei_count_full_read_slots(struct mei_device *dev)
+{
+	char read_ptr, write_ptr;
+	unsigned char buffer_depth, filled_slots;
+
+	dev->me_hw_state = mei_mecsr_read(dev);
+	buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24);
+	read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8);
+	write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16);
+	filled_slots = (unsigned char) (write_ptr - read_ptr);
+
+	/* check for overflow */
+	if (filled_slots > buffer_depth)
+		return -EOVERFLOW;
+
+	dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
+	return (int)filled_slots;
+}
+
+/**
+ * mei_read_slots - reads a message from mei device.
+ *
+ * @dev: the device structure
+ * @buffer: message buffer will be written
+ * @buffer_length: message size will be read
+ */
+void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
+		    unsigned long buffer_length)
+{
+	u32 *reg_buf = (u32 *)buffer;
+
+	for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
+		*reg_buf++ = mei_mecbrw_read(dev);
+
+	if (buffer_length > 0) {
+		u32 reg = mei_mecbrw_read(dev);
+		memcpy(reg_buf, &reg, buffer_length);
+	}
+
+	dev->host_hw_state |= H_IG;
+	mei_hcsr_set(dev);
+}
+
+/**
+ * mei_flow_ctrl_creds - checks flow_control credentials.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
+ *	-ENOENT if mei_cl is not present
+ *	-EINVAL if single_recv_buf == 0
+ */
+int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
+{
+	int i;
+
+	if (!dev->me_clients_num)
+		return 0;
+
+	if (cl->mei_flow_ctrl_creds > 0)
+		return 1;
+
+	for (i = 0; i < dev->me_clients_num; i++) {
+		struct mei_me_client  *me_cl = &dev->me_clients[i];
+		if (me_cl->client_id == cl->me_client_id) {
+			if (me_cl->mei_flow_ctrl_creds) {
+				if (WARN_ON(me_cl->props.single_recv_buf == 0))
+					return -EINVAL;
+				return 1;
+			} else {
+				return 0;
+			}
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ * mei_flow_ctrl_reduce - reduces flow_control.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ * @returns
+ *	0 on success
+ *	-ENOENT when me client is not found
+ *	-EINVAL when ctrl credits are <= 0
+ */
+int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
+{
+	int i;
+
+	if (!dev->me_clients_num)
+		return -ENOENT;
+
+	for (i = 0; i < dev->me_clients_num; i++) {
+		struct mei_me_client  *me_cl = &dev->me_clients[i];
+		if (me_cl->client_id == cl->me_client_id) {
+			if (me_cl->props.single_recv_buf != 0) {
+				if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
+					return -EINVAL;
+				dev->me_clients[i].mei_flow_ctrl_creds--;
+			} else {
+				if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+					return -EINVAL;
+				cl->mei_flow_ctrl_creds--;
+			}
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ * mei_send_flow_control - sends flow control to fw.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
+{
+	struct mei_msg_hdr *mei_hdr;
+	struct hbm_flow_control *mei_flow_control;
+
+	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+	mei_hdr->host_addr = 0;
+	mei_hdr->me_addr = 0;
+	mei_hdr->length = sizeof(struct hbm_flow_control);
+	mei_hdr->msg_complete = 1;
+	mei_hdr->reserved = 0;
+
+	mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
+	memset(mei_flow_control, 0, sizeof(*mei_flow_control));
+	mei_flow_control->host_addr = cl->host_client_id;
+	mei_flow_control->me_addr = cl->me_client_id;
+	mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD;
+	memset(mei_flow_control->reserved, 0,
+			sizeof(mei_flow_control->reserved));
+	dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
+		cl->host_client_id, cl->me_client_id);
+
+	return mei_write_message(dev, mei_hdr,
+				(unsigned char *) mei_flow_control,
+				sizeof(struct hbm_flow_control));
+}
+
+/**
+ * mei_other_client_is_connecting - checks if other
+ *    client with the same client id is connected.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * returns 1 if other client is connected, 0 - otherwise.
+ */
+int mei_other_client_is_connecting(struct mei_device *dev,
+				struct mei_cl *cl)
+{
+	struct mei_cl *cl_pos = NULL;
+	struct mei_cl *cl_next = NULL;
+
+	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+		if ((cl_pos->state == MEI_FILE_CONNECTING) &&
+			(cl_pos != cl) &&
+			cl->me_client_id == cl_pos->me_client_id)
+			return 1;
+
+	}
+	return 0;
+}
+
+/**
+ * mei_disconnect - sends disconnect message to fw.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
+{
+	struct mei_msg_hdr *mei_hdr;
+	struct hbm_client_disconnect_request *mei_cli_disconnect;
+
+	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+	mei_hdr->host_addr = 0;
+	mei_hdr->me_addr = 0;
+	mei_hdr->length = sizeof(struct hbm_client_disconnect_request);
+	mei_hdr->msg_complete = 1;
+	mei_hdr->reserved = 0;
+
+	mei_cli_disconnect =
+	    (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1];
+	memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect));
+	mei_cli_disconnect->host_addr = cl->host_client_id;
+	mei_cli_disconnect->me_addr = cl->me_client_id;
+	mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD;
+	mei_cli_disconnect->reserved[0] = 0;
+
+	return mei_write_message(dev, mei_hdr,
+				(unsigned char *) mei_cli_disconnect,
+				sizeof(struct hbm_client_disconnect_request));
+}
+
+/**
+ * mei_connect - sends connect message to fw.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_connect(struct mei_device *dev, struct mei_cl *cl)
+{
+	struct mei_msg_hdr *mei_hdr;
+	struct hbm_client_connect_request *mei_cli_connect;
+
+	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+	mei_hdr->host_addr = 0;
+	mei_hdr->me_addr = 0;
+	mei_hdr->length = sizeof(struct hbm_client_connect_request);
+	mei_hdr->msg_complete = 1;
+	mei_hdr->reserved = 0;
+
+	mei_cli_connect =
+	    (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
+	mei_cli_connect->host_addr = cl->host_client_id;
+	mei_cli_connect->me_addr = cl->me_client_id;
+	mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD;
+	mei_cli_connect->reserved = 0;
+
+	return mei_write_message(dev, mei_hdr,
+				(unsigned char *) mei_cli_connect,
+				sizeof(struct hbm_client_connect_request));
+}
diff --git a/drivers/misc/mei/interface.h b/drivers/misc/mei/interface.h
new file mode 100644
index 0000000..ddff5d1
--- /dev/null
+++ b/drivers/misc/mei/interface.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, 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.
+ *
+ */
+
+
+
+#ifndef _MEI_INTERFACE_H_
+#define _MEI_INTERFACE_H_
+
+#include <linux/mei.h>
+#include "mei_dev.h"
+
+
+#define AMT_WD_DEFAULT_TIMEOUT 120	/* seconds */
+#define AMT_WD_MIN_TIMEOUT 120	/* seconds */
+#define AMT_WD_MAX_TIMEOUT 65535	/* seconds */
+
+#define MEI_WATCHDOG_DATA_SIZE         16
+#define MEI_START_WD_DATA_SIZE         20
+#define MEI_WD_PARAMS_SIZE             4
+
+
+void mei_read_slots(struct mei_device *dev,
+		     unsigned char *buffer,
+		     unsigned long buffer_length);
+
+int mei_write_message(struct mei_device *dev,
+			     struct mei_msg_hdr *header,
+			     unsigned char *write_buffer,
+			     unsigned long write_length);
+
+int mei_host_buffer_is_empty(struct mei_device *dev);
+
+int mei_count_full_read_slots(struct mei_device *dev);
+
+int mei_count_empty_write_slots(struct mei_device *dev);
+
+int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
+
+int mei_wd_send(struct mei_device *dev);
+int mei_wd_stop(struct mei_device *dev, bool preserve);
+int mei_wd_host_init(struct mei_device *dev);
+/*
+ * mei_watchdog_register  - Registering watchdog interface
+ *   once we got connection to the WD Client
+ * @dev - mei device
+ */
+void mei_watchdog_register(struct mei_device *dev);
+/*
+ * mei_watchdog_unregister  - Unregistering watchdog interface
+ * @dev - mei device
+ */
+void mei_watchdog_unregister(struct mei_device *dev);
+
+int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl);
+
+int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl);
+
+int mei_disconnect(struct mei_device *dev, struct mei_cl *cl);
+int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl);
+int mei_connect(struct mei_device *dev, struct mei_cl *cl);
+
+#endif /* _MEI_INTERFACE_H_ */
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
new file mode 100644
index 0000000..93936f1
--- /dev/null
+++ b/drivers/misc/mei/interrupt.c
@@ -0,0 +1,1590 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, 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.
+ *
+ */
+
+
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/jiffies.h>
+
+#include "mei_dev.h"
+#include <linux/mei.h>
+#include "hw.h"
+#include "interface.h"
+
+
+/**
+ * mei_interrupt_quick_handler - The ISR of the MEI device
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ */
+irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
+{
+	struct mei_device *dev = (struct mei_device *) dev_id;
+	u32 csr_reg = mei_hcsr_read(dev);
+
+	if ((csr_reg & H_IS) != H_IS)
+		return IRQ_NONE;
+
+	/* clear H_IS bit in H_CSR */
+	mei_reg_write(dev, H_CSR, csr_reg);
+
+	return IRQ_WAKE_THREAD;
+}
+
+/**
+ * _mei_cmpl - processes completed operation.
+ *
+ * @cl: private data of the file object.
+ * @cb_pos: callback block.
+ */
+static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
+{
+	if (cb_pos->major_file_operations == MEI_WRITE) {
+		mei_free_cb_private(cb_pos);
+		cb_pos = NULL;
+		cl->writing_state = MEI_WRITE_COMPLETE;
+		if (waitqueue_active(&cl->tx_wait))
+			wake_up_interruptible(&cl->tx_wait);
+
+	} else if (cb_pos->major_file_operations == MEI_READ &&
+			MEI_READING == cl->reading_state) {
+		cl->reading_state = MEI_READ_COMPLETE;
+		if (waitqueue_active(&cl->rx_wait))
+			wake_up_interruptible(&cl->rx_wait);
+
+	}
+}
+
+/**
+ * _mei_cmpl_iamthif - processes completed iamthif operation.
+ *
+ * @dev: the device structure.
+ * @cb_pos: callback block.
+ */
+static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos)
+{
+	if (dev->iamthif_canceled != 1) {
+		dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
+		dev->iamthif_stall_timer = 0;
+		memcpy(cb_pos->response_buffer.data,
+				dev->iamthif_msg_buf,
+				dev->iamthif_msg_buf_index);
+		list_add_tail(&cb_pos->cb_list,
+				&dev->amthi_read_complete_list.mei_cb.cb_list);
+		dev_dbg(&dev->pdev->dev, "amthi read completed.\n");
+		dev->iamthif_timer = jiffies;
+		dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
+				dev->iamthif_timer);
+	} else {
+		mei_run_next_iamthif_cmd(dev);
+	}
+
+	dev_dbg(&dev->pdev->dev, "completing amthi call back.\n");
+	wake_up_interruptible(&dev->iamthif_cl.wait);
+}
+
+
+/**
+ * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to
+ * handle the read amthi message data processing.
+ *
+ * @complete_list: An instance of our list structure
+ * @dev: the device structure
+ * @mei_hdr: header of amthi message
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list,
+		struct mei_device *dev,
+		struct mei_msg_hdr *mei_hdr)
+{
+	struct mei_cl *cl;
+	struct mei_cl_cb *cb;
+	unsigned char *buffer;
+
+	BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
+	BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
+
+	buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
+	BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
+
+	mei_read_slots(dev, buffer, mei_hdr->length);
+
+	dev->iamthif_msg_buf_index += mei_hdr->length;
+
+	if (!mei_hdr->msg_complete)
+		return 0;
+
+	dev_dbg(&dev->pdev->dev,
+			"amthi_message_buffer_index =%d\n",
+			mei_hdr->length);
+
+	dev_dbg(&dev->pdev->dev, "completed amthi read.\n ");
+	if (!dev->iamthif_current_cb)
+		return -ENODEV;
+
+	cb = dev->iamthif_current_cb;
+	dev->iamthif_current_cb = NULL;
+
+	cl = (struct mei_cl *)cb->file_private;
+	if (!cl)
+		return -ENODEV;
+
+	dev->iamthif_stall_timer = 0;
+	cb->information =	dev->iamthif_msg_buf_index;
+	cb->read_time = jiffies;
+	if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) {
+		/* found the iamthif cb */
+		dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n ");
+		dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n ");
+		list_add_tail(&cb->cb_list,
+						&complete_list->mei_cb.cb_list);
+	}
+	return 0;
+}
+
+/**
+ * _mei_irq_thread_state_ok - checks if mei header matches file private data
+ *
+ * @cl: private data of the file object
+ * @mei_hdr: header of mei client message
+ *
+ * returns !=0 if matches, 0 if no match.
+ */
+static int _mei_irq_thread_state_ok(struct mei_cl *cl,
+				struct mei_msg_hdr *mei_hdr)
+{
+	return (cl->host_client_id == mei_hdr->host_addr &&
+		cl->me_client_id == mei_hdr->me_addr &&
+		cl->state == MEI_FILE_CONNECTED &&
+		MEI_READ_COMPLETE != cl->reading_state);
+}
+
+/**
+ * mei_irq_thread_read_client_message - bottom half read routine after ISR to
+ * handle the read mei client message data processing.
+ *
+ * @complete_list: An instance of our list structure
+ * @dev: the device structure
+ * @mei_hdr: header of mei client message
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
+		struct mei_device *dev,
+		struct mei_msg_hdr *mei_hdr)
+{
+	struct mei_cl *cl;
+	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+	unsigned char *buffer = NULL;
+
+	dev_dbg(&dev->pdev->dev, "start client msg\n");
+	if (list_empty(&dev->read_list.mei_cb.cb_list))
+		goto quit;
+
+	list_for_each_entry_safe(cb_pos, cb_next,
+			&dev->read_list.mei_cb.cb_list, cb_list) {
+		cl = (struct mei_cl *)cb_pos->file_private;
+		if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
+			cl->reading_state = MEI_READING;
+			buffer = cb_pos->response_buffer.data + cb_pos->information;
+
+			if (cb_pos->response_buffer.size <
+					mei_hdr->length + cb_pos->information) {
+				dev_dbg(&dev->pdev->dev, "message overflow.\n");
+				list_del(&cb_pos->cb_list);
+				return -ENOMEM;
+			}
+			if (buffer)
+				mei_read_slots(dev, buffer, mei_hdr->length);
+
+			cb_pos->information += mei_hdr->length;
+			if (mei_hdr->msg_complete) {
+				cl->status = 0;
+				list_del(&cb_pos->cb_list);
+				dev_dbg(&dev->pdev->dev,
+					"completed read host client = %d,"
+					"ME client = %d, "
+					"data length = %lu\n",
+					cl->host_client_id,
+					cl->me_client_id,
+					cb_pos->information);
+
+				*(cb_pos->response_buffer.data +
+					cb_pos->information) = '\0';
+				dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n",
+					cb_pos->response_buffer.data);
+				list_add_tail(&cb_pos->cb_list,
+					&complete_list->mei_cb.cb_list);
+			}
+
+			break;
+		}
+
+	}
+
+quit:
+	dev_dbg(&dev->pdev->dev, "message read\n");
+	if (!buffer) {
+		mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
+		dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
+				*(u32 *) dev->rd_msg_buf);
+	}
+
+	return 0;
+}
+
+/**
+ * _mei_irq_thread_iamthif_read - prepares to read iamthif data.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots)
+{
+
+	if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
+			+ sizeof(struct hbm_flow_control))) {
+		return -EMSGSIZE;
+	}
+	*slots -= (sizeof(struct mei_msg_hdr) +
+				sizeof(struct hbm_flow_control) + 3) / 4;
+	if (mei_send_flow_control(dev, &dev->iamthif_cl)) {
+		dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
+		return -EIO;
+	}
+
+	dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
+	dev->iamthif_state = MEI_IAMTHIF_READING;
+	dev->iamthif_flow_control_pending = false;
+	dev->iamthif_msg_buf_index = 0;
+	dev->iamthif_msg_buf_size = 0;
+	dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
+	dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
+	return 0;
+}
+
+/**
+ * _mei_irq_thread_close - processes close related operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
+				struct mei_cl_cb *cb_pos,
+				struct mei_cl *cl,
+				struct mei_io_list *cmpl_list)
+{
+	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+			sizeof(struct hbm_client_disconnect_request))) {
+		*slots -= (sizeof(struct mei_msg_hdr) +
+			sizeof(struct hbm_client_disconnect_request) + 3) / 4;
+
+		if (mei_disconnect(dev, cl)) {
+			cl->status = 0;
+			cb_pos->information = 0;
+			list_move_tail(&cb_pos->cb_list,
+					&cmpl_list->mei_cb.cb_list);
+			return -EMSGSIZE;
+		} else {
+			cl->state = MEI_FILE_DISCONNECTING;
+			cl->status = 0;
+			cb_pos->information = 0;
+			list_move_tail(&cb_pos->cb_list,
+					&dev->ctrl_rd_list.mei_cb.cb_list);
+			cl->timer_count = MEI_CONNECT_TIMEOUT;
+		}
+	} else {
+		/* return the cancel routine */
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+/**
+ * is_treat_specially_client - checks if the message belongs
+ * to the file private data.
+ *
+ * @cl: private data of the file object
+ * @rs: connect response bus message
+ *
+ */
+static bool is_treat_specially_client(struct mei_cl *cl,
+		struct hbm_client_connect_response *rs)
+{
+
+	if (cl->host_client_id == rs->host_addr &&
+	    cl->me_client_id == rs->me_addr) {
+		if (!rs->status) {
+			cl->state = MEI_FILE_CONNECTED;
+			cl->status = 0;
+
+		} else {
+			cl->state = MEI_FILE_DISCONNECTED;
+			cl->status = -ENODEV;
+		}
+		cl->timer_count = 0;
+
+		return true;
+	}
+	return false;
+}
+
+/**
+ * mei_client_connect_response - connects to response irq routine
+ *
+ * @dev: the device structure
+ * @rs: connect response bus message
+ */
+static void mei_client_connect_response(struct mei_device *dev,
+		struct hbm_client_connect_response *rs)
+{
+
+	struct mei_cl *cl;
+	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+
+	dev_dbg(&dev->pdev->dev,
+			"connect_response:\n"
+			"ME Client = %d\n"
+			"Host Client = %d\n"
+			"Status = %d\n",
+			rs->me_addr,
+			rs->host_addr,
+			rs->status);
+
+	/* if WD or iamthif client treat specially */
+
+	if (is_treat_specially_client(&(dev->wd_cl), rs)) {
+		dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
+		mei_watchdog_register(dev);
+
+		/* next step in the state maching */
+		mei_host_init_iamthif(dev);
+		return;
+	}
+
+	if (is_treat_specially_client(&(dev->iamthif_cl), rs)) {
+		dev->iamthif_state = MEI_IAMTHIF_IDLE;
+		return;
+	}
+	list_for_each_entry_safe(cb_pos, cb_next,
+				&dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
+
+		cl = (struct mei_cl *)cb_pos->file_private;
+		if (!cl) {
+			list_del(&cb_pos->cb_list);
+			return;
+		}
+		if (MEI_IOCTL == cb_pos->major_file_operations) {
+			if (is_treat_specially_client(cl, rs)) {
+				list_del(&cb_pos->cb_list);
+				cl->status = 0;
+				cl->timer_count = 0;
+				break;
+			}
+		}
+	}
+}
+
+/**
+ * mei_client_disconnect_response - disconnects from response irq routine
+ *
+ * @dev: the device structure
+ * @rs: disconnect response bus message
+ */
+static void mei_client_disconnect_response(struct mei_device *dev,
+					struct hbm_client_connect_response *rs)
+{
+	struct mei_cl *cl;
+	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+
+	dev_dbg(&dev->pdev->dev,
+			"disconnect_response:\n"
+			"ME Client = %d\n"
+			"Host Client = %d\n"
+			"Status = %d\n",
+			rs->me_addr,
+			rs->host_addr,
+			rs->status);
+
+	list_for_each_entry_safe(cb_pos, cb_next,
+			&dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
+		cl = (struct mei_cl *)cb_pos->file_private;
+
+		if (!cl) {
+			list_del(&cb_pos->cb_list);
+			return;
+		}
+
+		dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
+		if (cl->host_client_id == rs->host_addr &&
+		    cl->me_client_id == rs->me_addr) {
+
+			list_del(&cb_pos->cb_list);
+			if (!rs->status)
+				cl->state = MEI_FILE_DISCONNECTED;
+
+			cl->status = 0;
+			cl->timer_count = 0;
+			break;
+		}
+	}
+}
+
+/**
+ * same_flow_addr - tells if they have the same address.
+ *
+ * @file: private data of the file object.
+ * @flow: flow control.
+ *
+ * returns  !=0, same; 0,not.
+ */
+static int same_flow_addr(struct mei_cl *cl, struct hbm_flow_control *flow)
+{
+	return (cl->host_client_id == flow->host_addr &&
+		cl->me_client_id == flow->me_addr);
+}
+
+/**
+ * add_single_flow_creds - adds single buffer credentials.
+ *
+ * @file: private data ot the file object.
+ * @flow: flow control.
+ */
+static void add_single_flow_creds(struct mei_device *dev,
+				  struct hbm_flow_control *flow)
+{
+	struct mei_me_client *client;
+	int i;
+
+	for (i = 0; i < dev->me_clients_num; i++) {
+		client = &dev->me_clients[i];
+		if (client && flow->me_addr == client->client_id) {
+			if (client->props.single_recv_buf) {
+				client->mei_flow_ctrl_creds++;
+				dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
+				    flow->me_addr);
+				dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
+				    client->mei_flow_ctrl_creds);
+			} else {
+				BUG();	/* error in flow control */
+			}
+		}
+	}
+}
+
+/**
+ * mei_client_flow_control_response - flow control response irq routine
+ *
+ * @dev: the device structure
+ * @flow_control: flow control response bus message
+ */
+static void mei_client_flow_control_response(struct mei_device *dev,
+		struct hbm_flow_control *flow_control)
+{
+	struct mei_cl *cl_pos = NULL;
+	struct mei_cl *cl_next = NULL;
+
+	if (!flow_control->host_addr) {
+		/* single receive buffer */
+		add_single_flow_creds(dev, flow_control);
+	} else {
+		/* normal connection */
+		list_for_each_entry_safe(cl_pos, cl_next,
+				&dev->file_list, link) {
+			dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in file_list\n");
+
+			dev_dbg(&dev->pdev->dev, "cl of host client %d ME client %d.\n",
+			    cl_pos->host_client_id,
+			    cl_pos->me_client_id);
+			dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
+			    flow_control->host_addr,
+			    flow_control->me_addr);
+			if (same_flow_addr(cl_pos, flow_control)) {
+				dev_dbg(&dev->pdev->dev, "recv ctrl msg for host  %d ME %d.\n",
+				    flow_control->host_addr,
+				    flow_control->me_addr);
+				cl_pos->mei_flow_ctrl_creds++;
+				dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
+				    cl_pos->mei_flow_ctrl_creds);
+				break;
+			}
+		}
+	}
+}
+
+/**
+ * same_disconn_addr - tells if they have the same address
+ *
+ * @file: private data of the file object.
+ * @disconn: disconnection request.
+ *
+ * returns !=0, same; 0,not.
+ */
+static int same_disconn_addr(struct mei_cl *cl,
+			     struct hbm_client_disconnect_request *disconn)
+{
+	return (cl->host_client_id == disconn->host_addr &&
+		cl->me_client_id == disconn->me_addr);
+}
+
+/**
+ * mei_client_disconnect_request - disconnects from request irq routine
+ *
+ * @dev: the device structure.
+ * @disconnect_req: disconnect request bus message.
+ */
+static void mei_client_disconnect_request(struct mei_device *dev,
+		struct hbm_client_disconnect_request *disconnect_req)
+{
+	struct mei_msg_hdr *mei_hdr;
+	struct hbm_client_connect_response *disconnect_res;
+	struct mei_cl *cl_pos = NULL;
+	struct mei_cl *cl_next = NULL;
+
+	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+		if (same_disconn_addr(cl_pos, disconnect_req)) {
+			dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
+					disconnect_req->host_addr,
+					disconnect_req->me_addr);
+			cl_pos->state = MEI_FILE_DISCONNECTED;
+			cl_pos->timer_count = 0;
+			if (cl_pos == &dev->wd_cl) {
+				dev->wd_due_counter = 0;
+				dev->wd_pending = false;
+			} else if (cl_pos == &dev->iamthif_cl)
+				dev->iamthif_timer = 0;
+
+			/* prepare disconnect response */
+			mei_hdr =
+				(struct mei_msg_hdr *) &dev->ext_msg_buf[0];
+			mei_hdr->host_addr = 0;
+			mei_hdr->me_addr = 0;
+			mei_hdr->length =
+				sizeof(struct hbm_client_connect_response);
+			mei_hdr->msg_complete = 1;
+			mei_hdr->reserved = 0;
+
+			disconnect_res =
+				(struct hbm_client_connect_response *)
+				&dev->ext_msg_buf[1];
+			disconnect_res->host_addr = cl_pos->host_client_id;
+			disconnect_res->me_addr = cl_pos->me_client_id;
+			disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
+			disconnect_res->status = 0;
+			dev->extra_write_index = 2;
+			break;
+		}
+	}
+}
+
+
+/**
+ * mei_irq_thread_read_bus_message - bottom half read routine after ISR to
+ * handle the read bus message cmd processing.
+ *
+ * @dev: the device structure
+ * @mei_hdr: header of bus message
+ */
+static void mei_irq_thread_read_bus_message(struct mei_device *dev,
+		struct mei_msg_hdr *mei_hdr)
+{
+	struct mei_bus_message *mei_msg;
+	struct hbm_host_version_response *version_res;
+	struct hbm_client_connect_response *connect_res;
+	struct hbm_client_connect_response *disconnect_res;
+	struct hbm_flow_control *flow_control;
+	struct hbm_props_response *props_res;
+	struct hbm_host_enum_response *enum_res;
+	struct hbm_client_disconnect_request *disconnect_req;
+	struct hbm_host_stop_request *host_stop_req;
+	int res;
+
+
+	/* read the message to our buffer */
+	BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
+	mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
+	mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
+
+	switch (mei_msg->hbm_cmd) {
+	case HOST_START_RES_CMD:
+		version_res = (struct hbm_host_version_response *) mei_msg;
+		if (version_res->host_version_supported) {
+			dev->version.major_version = HBM_MAJOR_VERSION;
+			dev->version.minor_version = HBM_MINOR_VERSION;
+			if (dev->mei_state == MEI_INIT_CLIENTS &&
+			    dev->init_clients_state == MEI_START_MESSAGE) {
+				dev->init_clients_timer = 0;
+				mei_host_enum_clients_message(dev);
+			} else {
+				dev->recvd_msg = false;
+				dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
+				mei_reset(dev, 1);
+				return;
+			}
+		} else {
+			dev->version = version_res->me_max_version;
+			/* send stop message */
+			mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
+			mei_hdr->host_addr = 0;
+			mei_hdr->me_addr = 0;
+			mei_hdr->length = sizeof(struct hbm_host_stop_request);
+			mei_hdr->msg_complete = 1;
+			mei_hdr->reserved = 0;
+
+			host_stop_req = (struct hbm_host_stop_request *)
+							&dev->wr_msg_buf[1];
+
+			memset(host_stop_req,
+					0,
+					sizeof(struct hbm_host_stop_request));
+			host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
+			host_stop_req->reason = DRIVER_STOP_REQUEST;
+			mei_write_message(dev, mei_hdr,
+					   (unsigned char *) (host_stop_req),
+					   mei_hdr->length);
+			dev_dbg(&dev->pdev->dev, "version mismatch.\n");
+			return;
+		}
+
+		dev->recvd_msg = true;
+		dev_dbg(&dev->pdev->dev, "host start response message received.\n");
+		break;
+
+	case CLIENT_CONNECT_RES_CMD:
+		connect_res =
+			(struct hbm_client_connect_response *) mei_msg;
+		mei_client_connect_response(dev, connect_res);
+		dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
+		wake_up(&dev->wait_recvd_msg);
+		break;
+
+	case CLIENT_DISCONNECT_RES_CMD:
+		disconnect_res =
+			(struct hbm_client_connect_response *) mei_msg;
+		mei_client_disconnect_response(dev, disconnect_res);
+		dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
+		wake_up(&dev->wait_recvd_msg);
+		break;
+
+	case MEI_FLOW_CONTROL_CMD:
+		flow_control = (struct hbm_flow_control *) mei_msg;
+		mei_client_flow_control_response(dev, flow_control);
+		dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
+		break;
+
+	case HOST_CLIENT_PROPERTIES_RES_CMD:
+		props_res = (struct hbm_props_response *)mei_msg;
+		if (props_res->status || !dev->me_clients) {
+			dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
+			mei_reset(dev, 1);
+			return;
+		}
+		if (dev->me_clients[dev->me_client_presentation_num]
+					.client_id == props_res->address) {
+
+			dev->me_clients[dev->me_client_presentation_num].props
+						= props_res->client_properties;
+
+			if (dev->mei_state == MEI_INIT_CLIENTS &&
+			    dev->init_clients_state ==
+					MEI_CLIENT_PROPERTIES_MESSAGE) {
+				dev->me_client_index++;
+				dev->me_client_presentation_num++;
+
+				/** Send Client Properties request **/
+				res = mei_host_client_properties(dev);
+				if (res < 0) {
+					dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed");
+					return;
+				} else if (!res) {
+					/*
+					 * No more clients to send to.
+					 * Clear Map for indicating now ME clients
+					 * with associated host client
+					 */
+					bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
+					dev->open_handle_count = 0;
+
+					/*
+					 * Reserving the first three client IDs
+					 * Client Id 0 - Reserved for MEI Bus Message communications
+					 * Client Id 1 - Reserved for Watchdog
+					 * Client ID 2 - Reserved for AMTHI
+					 */
+					bitmap_set(dev->host_clients_map, 0, 3);
+					dev->mei_state = MEI_ENABLED;
+
+					/* if wd initialization fails, initialization the AMTHI client,
+					 * otherwise the AMTHI client will be initialized after the WD client connect response
+					 * will be received
+					 */
+					if (mei_wd_host_init(dev))
+						mei_host_init_iamthif(dev);
+				}
+
+			} else {
+				dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message");
+				mei_reset(dev, 1);
+				return;
+			}
+		} else {
+			dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n");
+			mei_reset(dev, 1);
+			return;
+		}
+		break;
+
+	case HOST_ENUM_RES_CMD:
+		enum_res = (struct hbm_host_enum_response *) mei_msg;
+		memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
+		if (dev->mei_state == MEI_INIT_CLIENTS &&
+		    dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
+				dev->init_clients_timer = 0;
+				dev->me_client_presentation_num = 0;
+				dev->me_client_index = 0;
+				mei_allocate_me_clients_storage(dev);
+				dev->init_clients_state =
+					MEI_CLIENT_PROPERTIES_MESSAGE;
+				mei_host_client_properties(dev);
+		} else {
+			dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
+			mei_reset(dev, 1);
+			return;
+		}
+		break;
+
+	case HOST_STOP_RES_CMD:
+		dev->mei_state = MEI_DISABLED;
+		dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
+		mei_reset(dev, 1);
+		break;
+
+	case CLIENT_DISCONNECT_REQ_CMD:
+		/* search for client */
+		disconnect_req =
+			(struct hbm_client_disconnect_request *) mei_msg;
+		mei_client_disconnect_request(dev, disconnect_req);
+		break;
+
+	case ME_STOP_REQ_CMD:
+		/* prepare stop request */
+		mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
+		mei_hdr->host_addr = 0;
+		mei_hdr->me_addr = 0;
+		mei_hdr->length = sizeof(struct hbm_host_stop_request);
+		mei_hdr->msg_complete = 1;
+		mei_hdr->reserved = 0;
+		host_stop_req =
+			(struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
+		memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request));
+		host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
+		host_stop_req->reason = DRIVER_STOP_REQUEST;
+		host_stop_req->reserved[0] = 0;
+		host_stop_req->reserved[1] = 0;
+		dev->extra_write_index = 2;
+		break;
+
+	default:
+		BUG();
+		break;
+
+	}
+}
+
+
+/**
+ * _mei_hb_read - processes read related operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_read(struct mei_device *dev,	s32 *slots,
+			struct mei_cl_cb *cb_pos,
+			struct mei_cl *cl,
+			struct mei_io_list *cmpl_list)
+{
+	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+			sizeof(struct hbm_flow_control))) {
+		/* return the cancel routine */
+		list_del(&cb_pos->cb_list);
+		return -EBADMSG;
+	}
+
+	*slots -= (sizeof(struct mei_msg_hdr) +
+			sizeof(struct hbm_flow_control) + 3) / 4;
+	if (mei_send_flow_control(dev, cl)) {
+		cl->status = -ENODEV;
+		cb_pos->information = 0;
+		list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list);
+		return -ENODEV;
+	}
+	list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list);
+
+	return 0;
+}
+
+
+/**
+ * _mei_irq_thread_ioctl - processes ioctl related operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
+			struct mei_cl_cb *cb_pos,
+			struct mei_cl *cl,
+			struct mei_io_list *cmpl_list)
+{
+	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+			sizeof(struct hbm_client_connect_request))) {
+		cl->state = MEI_FILE_CONNECTING;
+		*slots -= (sizeof(struct mei_msg_hdr) +
+			sizeof(struct hbm_client_connect_request) + 3) / 4;
+		if (mei_connect(dev, cl)) {
+			cl->status = -ENODEV;
+			cb_pos->information = 0;
+			list_del(&cb_pos->cb_list);
+			return -ENODEV;
+		} else {
+			list_move_tail(&cb_pos->cb_list,
+				&dev->ctrl_rd_list.mei_cb.cb_list);
+			cl->timer_count = MEI_CONNECT_TIMEOUT;
+		}
+	} else {
+		/* return the cancel routine */
+		list_del(&cb_pos->cb_list);
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+/**
+ * _mei_irq_thread_cmpl - processes completed and no-iamthif operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_cmpl(struct mei_device *dev,	s32 *slots,
+			struct mei_cl_cb *cb_pos,
+			struct mei_cl *cl,
+			struct mei_io_list *cmpl_list)
+{
+	struct mei_msg_hdr *mei_hdr;
+
+	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+			(cb_pos->request_buffer.size -
+			cb_pos->information))) {
+		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+		mei_hdr->host_addr = cl->host_client_id;
+		mei_hdr->me_addr = cl->me_client_id;
+		mei_hdr->length = cb_pos->request_buffer.size -
+					cb_pos->information;
+		mei_hdr->msg_complete = 1;
+		mei_hdr->reserved = 0;
+		dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d"
+			"mei_hdr->msg_complete = %d\n",
+				cb_pos->request_buffer.size,
+				mei_hdr->msg_complete);
+		dev_dbg(&dev->pdev->dev, "cb_pos->information  =%lu\n",
+				cb_pos->information);
+		dev_dbg(&dev->pdev->dev, "mei_hdr->length  =%d\n",
+				mei_hdr->length);
+		*slots -= (sizeof(struct mei_msg_hdr) +
+				mei_hdr->length + 3) / 4;
+		if (mei_write_message(dev, mei_hdr,
+				(unsigned char *)
+				(cb_pos->request_buffer.data +
+				cb_pos->information),
+				mei_hdr->length)) {
+			cl->status = -ENODEV;
+			list_move_tail(&cb_pos->cb_list,
+				&cmpl_list->mei_cb.cb_list);
+			return -ENODEV;
+		} else {
+			if (mei_flow_ctrl_reduce(dev, cl))
+				return -ENODEV;
+			cl->status = 0;
+			cb_pos->information += mei_hdr->length;
+			list_move_tail(&cb_pos->cb_list,
+				&dev->write_waiting_list.mei_cb.cb_list);
+		}
+	} else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
+		/* buffer is still empty */
+		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+		mei_hdr->host_addr = cl->host_client_id;
+		mei_hdr->me_addr = cl->me_client_id;
+		mei_hdr->length =
+			(*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+		mei_hdr->msg_complete = 0;
+		mei_hdr->reserved = 0;
+
+		(*slots) -= (sizeof(struct mei_msg_hdr) +
+				mei_hdr->length + 3) / 4;
+		if (mei_write_message(dev, mei_hdr,
+					(unsigned char *)
+					(cb_pos->request_buffer.data +
+					cb_pos->information),
+					mei_hdr->length)) {
+			cl->status = -ENODEV;
+			list_move_tail(&cb_pos->cb_list,
+				&cmpl_list->mei_cb.cb_list);
+			return -ENODEV;
+		} else {
+			cb_pos->information += mei_hdr->length;
+			dev_dbg(&dev->pdev->dev,
+					"cb_pos->request_buffer.size =%d"
+					" mei_hdr->msg_complete = %d\n",
+					cb_pos->request_buffer.size,
+					mei_hdr->msg_complete);
+			dev_dbg(&dev->pdev->dev, "cb_pos->information  =%lu\n",
+					cb_pos->information);
+			dev_dbg(&dev->pdev->dev, "mei_hdr->length  =%d\n",
+					mei_hdr->length);
+		}
+		return -EMSGSIZE;
+	} else {
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+/**
+ * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots,
+			struct mei_cl_cb *cb_pos,
+			struct mei_cl *cl,
+			struct mei_io_list *cmpl_list)
+{
+	struct mei_msg_hdr *mei_hdr;
+
+	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+			dev->iamthif_msg_buf_size -
+			dev->iamthif_msg_buf_index)) {
+		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+		mei_hdr->host_addr = cl->host_client_id;
+		mei_hdr->me_addr = cl->me_client_id;
+		mei_hdr->length = dev->iamthif_msg_buf_size -
+			dev->iamthif_msg_buf_index;
+		mei_hdr->msg_complete = 1;
+		mei_hdr->reserved = 0;
+
+		*slots -= (sizeof(struct mei_msg_hdr) +
+				mei_hdr->length + 3) / 4;
+
+		if (mei_write_message(dev, mei_hdr,
+					(dev->iamthif_msg_buf +
+					dev->iamthif_msg_buf_index),
+					mei_hdr->length)) {
+			dev->iamthif_state = MEI_IAMTHIF_IDLE;
+			cl->status = -ENODEV;
+			list_del(&cb_pos->cb_list);
+			return -ENODEV;
+		} else {
+			if (mei_flow_ctrl_reduce(dev, cl))
+				return -ENODEV;
+			dev->iamthif_msg_buf_index += mei_hdr->length;
+			cb_pos->information = dev->iamthif_msg_buf_index;
+			cl->status = 0;
+			dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
+			dev->iamthif_flow_control_pending = true;
+			/* save iamthif cb sent to amthi client */
+			dev->iamthif_current_cb = cb_pos;
+			list_move_tail(&cb_pos->cb_list,
+				&dev->write_waiting_list.mei_cb.cb_list);
+
+		}
+	} else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
+			/* buffer is still empty */
+		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+		mei_hdr->host_addr = cl->host_client_id;
+		mei_hdr->me_addr = cl->me_client_id;
+		mei_hdr->length =
+			(*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+		mei_hdr->msg_complete = 0;
+		mei_hdr->reserved = 0;
+
+		*slots -= (sizeof(struct mei_msg_hdr) +
+				mei_hdr->length + 3) / 4;
+
+		if (mei_write_message(dev, mei_hdr,
+					(dev->iamthif_msg_buf +
+					dev->iamthif_msg_buf_index),
+					mei_hdr->length)) {
+			cl->status = -ENODEV;
+			list_del(&cb_pos->cb_list);
+		} else {
+			dev->iamthif_msg_buf_index += mei_hdr->length;
+		}
+		return -EMSGSIZE;
+	} else {
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+/**
+ * mei_irq_thread_read_handler - bottom half read routine after ISR to
+ * handle the read processing.
+ *
+ * @cmpl_list: An instance of our list structure
+ * @dev: the device structure
+ * @slots: slots to read.
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list,
+		struct mei_device *dev,
+		s32 *slots)
+{
+	struct mei_msg_hdr *mei_hdr;
+	struct mei_cl *cl_pos = NULL;
+	struct mei_cl *cl_next = NULL;
+	int ret = 0;
+
+	if (!dev->rd_msg_hdr) {
+		dev->rd_msg_hdr = mei_mecbrw_read(dev);
+		dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
+		(*slots)--;
+		dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
+	}
+	mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
+	dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length);
+
+	if (mei_hdr->reserved || !dev->rd_msg_hdr) {
+		dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
+		ret = -EBADMSG;
+		goto end;
+	}
+
+	if (mei_hdr->host_addr || mei_hdr->me_addr) {
+		list_for_each_entry_safe(cl_pos, cl_next,
+					&dev->file_list, link) {
+			dev_dbg(&dev->pdev->dev,
+					"list_for_each_entry_safe read host"
+					" client = %d, ME client = %d\n",
+					cl_pos->host_client_id,
+					cl_pos->me_client_id);
+			if (cl_pos->host_client_id == mei_hdr->host_addr &&
+			    cl_pos->me_client_id == mei_hdr->me_addr)
+				break;
+		}
+
+		if (&cl_pos->link == &dev->file_list) {
+			dev_dbg(&dev->pdev->dev, "corrupted message header\n");
+			ret = -EBADMSG;
+			goto end;
+		}
+	}
+	if (((*slots) * sizeof(u32)) < mei_hdr->length) {
+		dev_dbg(&dev->pdev->dev,
+				"we can't read the message slots =%08x.\n",
+				*slots);
+		/* we can't read the message */
+		ret = -ERANGE;
+		goto end;
+	}
+
+	/* decide where to read the message too */
+	if (!mei_hdr->host_addr) {
+		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
+		mei_irq_thread_read_bus_message(dev, mei_hdr);
+		dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
+	} else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
+		   (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
+		   (dev->iamthif_state == MEI_IAMTHIF_READING)) {
+		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
+		dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
+				mei_hdr->length);
+		ret = mei_irq_thread_read_amthi_message(cmpl_list,
+							dev, mei_hdr);
+		if (ret)
+			goto end;
+
+	} else {
+		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
+		ret = mei_irq_thread_read_client_message(cmpl_list,
+							 dev, mei_hdr);
+		if (ret)
+			goto end;
+
+	}
+
+	/* reset the number of slots and header */
+	*slots = mei_count_full_read_slots(dev);
+	dev->rd_msg_hdr = 0;
+
+	if (*slots == -EOVERFLOW) {
+		/* overflow - reset */
+		dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
+		/* set the event since message has been read */
+		ret = -ERANGE;
+		goto end;
+	}
+end:
+	return ret;
+}
+
+
+/**
+ * mei_irq_thread_write_handler - bottom half write routine after
+ * ISR to handle the write processing.
+ *
+ * @cmpl_list: An instance of our list structure
+ * @dev: the device structure
+ * @slots: slots to write.
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
+		struct mei_device *dev,
+		s32 *slots)
+{
+
+	struct mei_cl *cl;
+	struct mei_cl_cb *pos = NULL, *next = NULL;
+	struct mei_io_list *list;
+	int ret;
+
+	if (!mei_host_buffer_is_empty(dev)) {
+		dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
+		return 0;
+	}
+	*slots = mei_count_empty_write_slots(dev);
+	/* complete all waiting for write CB */
+	dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
+
+	list = &dev->write_waiting_list;
+	list_for_each_entry_safe(pos, next,
+			&list->mei_cb.cb_list, cb_list) {
+		cl = (struct mei_cl *)pos->file_private;
+		if (cl == NULL)
+			continue;
+
+		cl->status = 0;
+		list_del(&pos->cb_list);
+		if (MEI_WRITING == cl->writing_state &&
+		   (pos->major_file_operations == MEI_WRITE) &&
+		   (cl != &dev->iamthif_cl)) {
+			dev_dbg(&dev->pdev->dev,
+				"MEI WRITE COMPLETE\n");
+			cl->writing_state = MEI_WRITE_COMPLETE;
+			list_add_tail(&pos->cb_list,
+				&cmpl_list->mei_cb.cb_list);
+		}
+		if (cl == &dev->iamthif_cl) {
+			dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n");
+			if (dev->iamthif_flow_control_pending) {
+				ret = _mei_irq_thread_iamthif_read(
+						dev, slots);
+				if (ret)
+					return ret;
+			}
+		}
+	}
+
+	if (dev->stop && !dev->wd_pending) {
+		dev->wd_stopped = true;
+		wake_up_interruptible(&dev->wait_stop_wd);
+		return 0;
+	}
+
+	if (dev->extra_write_index) {
+		dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n",
+				dev->extra_write_index);
+		mei_write_message(dev,
+				(struct mei_msg_hdr *) &dev->ext_msg_buf[0],
+				(unsigned char *) &dev->ext_msg_buf[1],
+				(dev->extra_write_index - 1) * sizeof(u32));
+		*slots -= dev->extra_write_index;
+		dev->extra_write_index = 0;
+	}
+	if (dev->mei_state == MEI_ENABLED) {
+		if (dev->wd_pending &&
+			mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
+			if (mei_wd_send(dev))
+				dev_dbg(&dev->pdev->dev, "wd send failed.\n");
+			else
+				if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
+					return -ENODEV;
+
+			dev->wd_pending = false;
+
+			if (dev->wd_timeout) {
+				*slots -= (sizeof(struct mei_msg_hdr) +
+					 MEI_START_WD_DATA_SIZE + 3) / 4;
+				dev->wd_due_counter = 2;
+			} else {
+				*slots -= (sizeof(struct mei_msg_hdr) +
+					 MEI_WD_PARAMS_SIZE + 3) / 4;
+				dev->wd_due_counter = 0;
+			}
+
+		}
+	}
+	if (dev->stop)
+		return -ENODEV;
+
+	/* complete control write list CB */
+	dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
+	list_for_each_entry_safe(pos, next,
+				&dev->ctrl_wr_list.mei_cb.cb_list, cb_list) {
+		cl = (struct mei_cl *) pos->file_private;
+		if (!cl) {
+			list_del(&pos->cb_list);
+			return -ENODEV;
+		}
+		switch (pos->major_file_operations) {
+		case MEI_CLOSE:
+			/* send disconnect message */
+			ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list);
+			if (ret)
+				return ret;
+
+			break;
+		case MEI_READ:
+			/* send flow control message */
+			ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list);
+			if (ret)
+				return ret;
+
+			break;
+		case MEI_IOCTL:
+			/* connect message */
+			if (mei_other_client_is_connecting(dev, cl))
+				continue;
+			ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list);
+			if (ret)
+				return ret;
+
+			break;
+
+		default:
+			BUG();
+		}
+
+	}
+	/* complete  write list CB */
+	dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
+	list_for_each_entry_safe(pos, next,
+			&dev->write_list.mei_cb.cb_list, cb_list) {
+		cl = (struct mei_cl *)pos->file_private;
+		if (cl == NULL)
+			continue;
+
+		if (cl != &dev->iamthif_cl) {
+			if (!mei_flow_ctrl_creds(dev, cl)) {
+				dev_dbg(&dev->pdev->dev,
+					"No flow control"
+				    " credentials for client"
+				    " %d, not sending.\n",
+				    cl->host_client_id);
+				continue;
+			}
+			ret = _mei_irq_thread_cmpl(dev, slots,
+					    pos,
+					    cl, cmpl_list);
+			if (ret)
+				return ret;
+
+		} else if (cl == &dev->iamthif_cl) {
+			/* IAMTHIF IOCTL */
+			dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n");
+			if (!mei_flow_ctrl_creds(dev, cl)) {
+				dev_dbg(&dev->pdev->dev,
+					"No flow control"
+				    " credentials for amthi"
+				    " client %d.\n",
+				    cl->host_client_id);
+				continue;
+			}
+			ret = _mei_irq_thread_cmpl_iamthif(dev,
+						slots,
+						pos,
+						cl,
+						cmpl_list);
+			if (ret)
+				return ret;
+
+		}
+
+	}
+	return 0;
+}
+
+
+
+/**
+ * mei_timer - timer function.
+ *
+ * @work: pointer to the work_struct structure
+ *
+ * NOTE: This function is called by timer interrupt work
+ */
+void mei_timer(struct work_struct *work)
+{
+	unsigned long timeout;
+	struct mei_cl *cl_pos = NULL;
+	struct mei_cl *cl_next = NULL;
+	struct list_head *amthi_complete_list = NULL;
+	struct mei_cl_cb  *cb_pos = NULL;
+	struct mei_cl_cb  *cb_next = NULL;
+
+	struct mei_device *dev = container_of(work,
+					struct mei_device, timer_work.work);
+
+
+	mutex_lock(&dev->device_lock);
+	if (dev->mei_state != MEI_ENABLED) {
+		if (dev->mei_state == MEI_INIT_CLIENTS) {
+			if (dev->init_clients_timer) {
+				if (--dev->init_clients_timer == 0) {
+					dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
+						dev->init_clients_state);
+					mei_reset(dev, 1);
+				}
+			}
+		}
+		goto out;
+	}
+	/*** connect/disconnect timeouts ***/
+	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+		if (cl_pos->timer_count) {
+			if (--cl_pos->timer_count == 0) {
+				dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
+				mei_reset(dev, 1);
+				goto out;
+			}
+		}
+	}
+
+	if (dev->iamthif_stall_timer) {
+		if (--dev->iamthif_stall_timer == 0) {
+			dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
+			mei_reset(dev, 1);
+			dev->iamthif_msg_buf_size = 0;
+			dev->iamthif_msg_buf_index = 0;
+			dev->iamthif_canceled = false;
+			dev->iamthif_ioctl = true;
+			dev->iamthif_state = MEI_IAMTHIF_IDLE;
+			dev->iamthif_timer = 0;
+
+			if (dev->iamthif_current_cb)
+				mei_free_cb_private(dev->iamthif_current_cb);
+
+			dev->iamthif_file_object = NULL;
+			dev->iamthif_current_cb = NULL;
+			mei_run_next_iamthif_cmd(dev);
+		}
+	}
+
+	if (dev->iamthif_timer) {
+
+		timeout = dev->iamthif_timer +
+				msecs_to_jiffies(IAMTHIF_READ_TIMER);
+
+		dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
+				dev->iamthif_timer);
+		dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
+		dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
+		if (time_after(jiffies, timeout)) {
+			/*
+			 * User didn't read the AMTHI data on time (15sec)
+			 * freeing AMTHI for other requests
+			 */
+
+			dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
+
+			amthi_complete_list = &dev->amthi_read_complete_list.
+					mei_cb.cb_list;
+
+			list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) {
+
+				cl_pos = cb_pos->file_object->private_data;
+
+				/* Finding the AMTHI entry. */
+				if (cl_pos == &dev->iamthif_cl)
+					list_del(&cb_pos->cb_list);
+			}
+			if (dev->iamthif_current_cb)
+				mei_free_cb_private(dev->iamthif_current_cb);
+
+			dev->iamthif_file_object->private_data = NULL;
+			dev->iamthif_file_object = NULL;
+			dev->iamthif_current_cb = NULL;
+			dev->iamthif_timer = 0;
+			mei_run_next_iamthif_cmd(dev);
+
+		}
+	}
+out:
+	schedule_delayed_work(&dev->timer_work, 2 * HZ);
+	mutex_unlock(&dev->device_lock);
+}
+
+/**
+ *  mei_interrupt_thread_handler - function called after ISR to handle the interrupt
+ * processing.
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ *
+ */
+irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
+{
+	struct mei_device *dev = (struct mei_device *) dev_id;
+	struct mei_io_list complete_list;
+	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+	struct mei_cl *cl;
+	s32 slots;
+	int rets;
+	bool  bus_message_received;
+
+
+	dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
+	/* initialize our complete list */
+	mutex_lock(&dev->device_lock);
+	mei_io_list_init(&complete_list);
+	dev->host_hw_state = mei_hcsr_read(dev);
+
+	/* Ack the interrupt here
+	 * In case of MSI we don't go through the quick handler */
+	if (pci_dev_msi_enabled(dev->pdev))
+		mei_reg_write(dev, H_CSR, dev->host_hw_state);
+
+	dev->me_hw_state = mei_mecsr_read(dev);
+
+	/* check if ME wants a reset */
+	if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
+	    dev->mei_state != MEI_RESETING &&
+	    dev->mei_state != MEI_INITIALIZING) {
+		dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+		mei_reset(dev, 1);
+		mutex_unlock(&dev->device_lock);
+		return IRQ_HANDLED;
+	}
+
+	/*  check if we need to start the dev */
+	if ((dev->host_hw_state & H_RDY) == 0) {
+		if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
+			dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
+			dev->host_hw_state |= (H_IE | H_IG | H_RDY);
+			mei_hcsr_set(dev);
+			dev->mei_state = MEI_INIT_CLIENTS;
+			dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
+			/* link is established
+			 * start sending messages.
+			 */
+			mei_host_start_message(dev);
+			mutex_unlock(&dev->device_lock);
+			return IRQ_HANDLED;
+		} else {
+			dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+			mutex_unlock(&dev->device_lock);
+			return IRQ_HANDLED;
+		}
+	}
+	/* check slots available for reading */
+	slots = mei_count_full_read_slots(dev);
+	dev_dbg(&dev->pdev->dev, "slots =%08x  extra_write_index =%08x.\n",
+		slots, dev->extra_write_index);
+	while (slots > 0 && !dev->extra_write_index) {
+		dev_dbg(&dev->pdev->dev, "slots =%08x  extra_write_index =%08x.\n",
+				slots, dev->extra_write_index);
+		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
+		rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
+		if (rets)
+			goto end;
+	}
+	rets = mei_irq_thread_write_handler(&complete_list, dev, &slots);
+end:
+	dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
+	dev->host_hw_state = mei_hcsr_read(dev);
+	dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
+
+	bus_message_received = false;
+	if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
+		dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
+		bus_message_received = true;
+	}
+	mutex_unlock(&dev->device_lock);
+	if (bus_message_received) {
+		dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
+		wake_up_interruptible(&dev->wait_recvd_msg);
+		bus_message_received = false;
+	}
+	if (list_empty(&complete_list.mei_cb.cb_list))
+		return IRQ_HANDLED;
+
+
+	list_for_each_entry_safe(cb_pos, cb_next,
+			&complete_list.mei_cb.cb_list, cb_list) {
+		cl = (struct mei_cl *)cb_pos->file_private;
+		list_del(&cb_pos->cb_list);
+		if (cl) {
+			if (cl != &dev->iamthif_cl) {
+				dev_dbg(&dev->pdev->dev, "completing call back.\n");
+				_mei_cmpl(cl, cb_pos);
+				cb_pos = NULL;
+			} else if (cl == &dev->iamthif_cl) {
+				_mei_cmpl_iamthif(dev, cb_pos);
+			}
+		}
+	}
+	return IRQ_HANDLED;
+}
diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c
new file mode 100644
index 0000000..f9cced6
--- /dev/null
+++ b/drivers/misc/mei/iorw.c
@@ -0,0 +1,590 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, 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.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/aio.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/uuid.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+
+
+#include "mei_dev.h"
+#include "hw.h"
+#include <linux/mei.h>
+#include "interface.h"
+
+
+
+/**
+ * mei_ioctl_connect_client - the connect to fw client IOCTL function
+ *
+ * @dev: the device structure
+ * @data: IOCTL connect data, input and output parameters
+ * @file: private data of the file object
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_ioctl_connect_client(struct file *file,
+			struct mei_connect_client_data *data)
+{
+	struct mei_device *dev;
+	struct mei_cl_cb *cb;
+	struct mei_client *client;
+	struct mei_cl *cl;
+	struct mei_cl *cl_pos = NULL;
+	struct mei_cl *cl_next = NULL;
+	long timeout = CONNECT_TIMEOUT;
+	int i;
+	int err;
+	int rets;
+
+	cl = file->private_data;
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
+
+	dev = cl->dev;
+
+	dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n");
+
+
+	/* buffered ioctl cb */
+	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
+	if (!cb) {
+		rets = -ENOMEM;
+		goto end;
+	}
+	INIT_LIST_HEAD(&cb->cb_list);
+
+	cb->major_file_operations = MEI_IOCTL;
+
+	if (dev->mei_state != MEI_ENABLED) {
+		rets = -ENODEV;
+		goto end;
+	}
+	if (cl->state != MEI_FILE_INITIALIZING &&
+	    cl->state != MEI_FILE_DISCONNECTED) {
+		rets = -EBUSY;
+		goto end;
+	}
+
+	/* find ME client we're trying to connect to */
+	i = mei_find_me_client_index(dev, data->in_client_uuid);
+	if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
+		cl->me_client_id = dev->me_clients[i].client_id;
+		cl->state = MEI_FILE_CONNECTING;
+	}
+
+	dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
+			cl->me_client_id);
+	dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
+			dev->me_clients[i].props.protocol_version);
+	dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
+			dev->me_clients[i].props.max_msg_length);
+
+	/* if we're connecting to amthi client then we will use the
+	 * existing connection
+	 */
+	if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
+		dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
+		if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
+			rets = -ENODEV;
+			goto end;
+		}
+		clear_bit(cl->host_client_id, dev->host_clients_map);
+		list_for_each_entry_safe(cl_pos, cl_next,
+					 &dev->file_list, link) {
+			if (mei_cl_cmp_id(cl, cl_pos)) {
+				dev_dbg(&dev->pdev->dev,
+					"remove file private data node host"
+				    " client = %d, ME client = %d.\n",
+				    cl_pos->host_client_id,
+				    cl_pos->me_client_id);
+				list_del(&cl_pos->link);
+			}
+
+		}
+		dev_dbg(&dev->pdev->dev, "free file private data memory.\n");
+		kfree(cl);
+
+		cl = NULL;
+		file->private_data = &dev->iamthif_cl;
+
+		client = &data->out_client_properties;
+		client->max_msg_length =
+			dev->me_clients[i].props.max_msg_length;
+		client->protocol_version =
+			dev->me_clients[i].props.protocol_version;
+		rets = dev->iamthif_cl.status;
+
+		goto end;
+	}
+
+	if (cl->state != MEI_FILE_CONNECTING) {
+		rets = -ENODEV;
+		goto end;
+	}
+
+
+	/* prepare the output buffer */
+	client = &data->out_client_properties;
+	client->max_msg_length = dev->me_clients[i].props.max_msg_length;
+	client->protocol_version = dev->me_clients[i].props.protocol_version;
+	dev_dbg(&dev->pdev->dev, "Can connect?\n");
+	if (dev->mei_host_buffer_is_empty
+	    && !mei_other_client_is_connecting(dev, cl)) {
+		dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
+		dev->mei_host_buffer_is_empty = false;
+		if (mei_connect(dev, cl)) {
+			dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
+			rets = -ENODEV;
+			goto end;
+		} else {
+			dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n");
+			cl->timer_count = MEI_CONNECT_TIMEOUT;
+			cb->file_private = cl;
+			list_add_tail(&cb->cb_list,
+				      &dev->ctrl_rd_list.mei_cb.
+				      cb_list);
+		}
+
+
+	} else {
+		dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n");
+		cb->file_private = cl;
+		dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n");
+		list_add_tail(&cb->cb_list,
+			      &dev->ctrl_wr_list.mei_cb.cb_list);
+	}
+	mutex_unlock(&dev->device_lock);
+	err = wait_event_timeout(dev->wait_recvd_msg,
+			(MEI_FILE_CONNECTED == cl->state ||
+			 MEI_FILE_DISCONNECTED == cl->state),
+			timeout * HZ);
+
+	mutex_lock(&dev->device_lock);
+	if (MEI_FILE_CONNECTED == cl->state) {
+		dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n");
+		rets = cl->status;
+		goto end;
+	} else {
+		dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n",
+		    cl->state);
+		if (!err) {
+			dev_dbg(&dev->pdev->dev,
+				"wait_event_interruptible_timeout failed on client"
+				" connect message fw response message.\n");
+		}
+		rets = -EFAULT;
+
+		mei_io_list_flush(&dev->ctrl_rd_list, cl);
+		mei_io_list_flush(&dev->ctrl_wr_list, cl);
+		goto end;
+	}
+	rets = 0;
+end:
+	dev_dbg(&dev->pdev->dev, "free connect cb memory.");
+	kfree(cb);
+	return rets;
+}
+
+/**
+ * find_amthi_read_list_entry - finds a amthilist entry for current file
+ *
+ * @dev: the device structure
+ * @file: pointer to file object
+ *
+ * returns   returned a list entry on success, NULL on failure.
+ */
+struct mei_cl_cb *find_amthi_read_list_entry(
+		struct mei_device *dev,
+		struct file *file)
+{
+	struct mei_cl *cl_temp;
+	struct mei_cl_cb *pos = NULL;
+	struct mei_cl_cb *next = NULL;
+
+	list_for_each_entry_safe(pos, next,
+	    &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) {
+		cl_temp = (struct mei_cl *)pos->file_private;
+		if (cl_temp && cl_temp == &dev->iamthif_cl &&
+			pos->file_object == file)
+			return pos;
+	}
+	return NULL;
+}
+
+/**
+ * amthi_read - read data from AMTHI client
+ *
+ * @dev: the device structure
+ * @if_num:  minor number
+ * @file: pointer to file object
+ * @*ubuf: pointer to user data in user space
+ * @length: data length to read
+ * @offset: data read offset
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns
+ *  returned data length on success,
+ *  zero if no data to read,
+ *  negative on failure.
+ */
+int amthi_read(struct mei_device *dev, struct file *file,
+	       char __user *ubuf, size_t length, loff_t *offset)
+{
+	int rets;
+	int wait_ret;
+	struct mei_cl_cb *cb = NULL;
+	struct mei_cl *cl = file->private_data;
+	unsigned long timeout;
+	int i;
+
+	/* Only Posible if we are in timeout */
+	if (!cl || cl != &dev->iamthif_cl) {
+		dev_dbg(&dev->pdev->dev, "bad file ext.\n");
+		return -ETIMEDOUT;
+	}
+
+	for (i = 0; i < dev->me_clients_num; i++) {
+		if (dev->me_clients[i].client_id ==
+		    dev->iamthif_cl.me_client_id)
+			break;
+	}
+
+	if (i == dev->me_clients_num) {
+		dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
+		return -ENODEV;
+	}
+	if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id))
+		return -ENODEV;
+
+	dev_dbg(&dev->pdev->dev, "checking amthi data\n");
+	cb = find_amthi_read_list_entry(dev, file);
+
+	/* Check for if we can block or not*/
+	if (cb == NULL && file->f_flags & O_NONBLOCK)
+		return -EAGAIN;
+
+
+	dev_dbg(&dev->pdev->dev, "waiting for amthi data\n");
+	while (cb == NULL) {
+		/* unlock the Mutex */
+		mutex_unlock(&dev->device_lock);
+
+		wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
+			(cb = find_amthi_read_list_entry(dev, file)));
+
+		if (wait_ret)
+			return -ERESTARTSYS;
+
+		dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
+
+		/* Locking again the Mutex */
+		mutex_lock(&dev->device_lock);
+	}
+
+
+	dev_dbg(&dev->pdev->dev, "Got amthi data\n");
+	dev->iamthif_timer = 0;
+
+	if (cb) {
+		timeout = cb->read_time +
+					msecs_to_jiffies(IAMTHIF_READ_TIMER);
+		dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
+				timeout);
+
+		if  (time_after(jiffies, timeout)) {
+			dev_dbg(&dev->pdev->dev, "amthi Time out\n");
+			/* 15 sec for the message has expired */
+			list_del(&cb->cb_list);
+			rets = -ETIMEDOUT;
+			goto free;
+		}
+	}
+	/* if the whole message will fit remove it from the list */
+	if (cb->information >= *offset && length >= (cb->information - *offset))
+		list_del(&cb->cb_list);
+	else if (cb->information > 0 && cb->information <= *offset) {
+		/* end of the message has been reached */
+		list_del(&cb->cb_list);
+		rets = 0;
+		goto free;
+	}
+		/* else means that not full buffer will be read and do not
+		 * remove message from deletion list
+		 */
+
+	dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n",
+	    cb->response_buffer.size);
+	dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n",
+	    cb->information);
+
+	/* length is being turncated to PAGE_SIZE, however,
+	 * the information may be longer */
+	length = min_t(size_t, length, (cb->information - *offset));
+
+	if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
+		rets = -EFAULT;
+	else {
+		rets = length;
+		if ((*offset + length) < cb->information) {
+			*offset += length;
+			goto out;
+		}
+	}
+free:
+	dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n");
+	*offset = 0;
+	mei_free_cb_private(cb);
+out:
+	return rets;
+}
+
+/**
+ * mei_start_read - the start read client message function.
+ *
+ * @dev: the device structure
+ * @if_num:  minor number
+ * @cl: private data of the file object
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
+{
+	struct mei_cl_cb *cb;
+	int rets = 0;
+	int i;
+
+	if (cl->state != MEI_FILE_CONNECTED)
+		return -ENODEV;
+
+	if (dev->mei_state != MEI_ENABLED)
+		return -ENODEV;
+
+	dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
+	if (cl->read_pending || cl->read_cb) {
+		dev_dbg(&dev->pdev->dev, "read is pending.\n");
+		return -EBUSY;
+	}
+
+	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
+	if (!cb)
+		return -ENOMEM;
+
+	dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
+		cl->host_client_id, cl->me_client_id);
+
+	for (i = 0; i < dev->me_clients_num; i++) {
+		if (dev->me_clients[i].client_id == cl->me_client_id)
+			break;
+
+	}
+
+	if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
+		rets = -ENODEV;
+		goto unlock;
+	}
+
+	if (i == dev->me_clients_num) {
+		rets = -ENODEV;
+		goto unlock;
+	}
+
+	cb->response_buffer.size = dev->me_clients[i].props.max_msg_length;
+	cb->response_buffer.data =
+			kmalloc(cb->response_buffer.size, GFP_KERNEL);
+	if (!cb->response_buffer.data) {
+		rets = -ENOMEM;
+		goto unlock;
+	}
+	dev_dbg(&dev->pdev->dev, "allocation call back data success.\n");
+	cb->major_file_operations = MEI_READ;
+	/* make sure information is zero before we start */
+	cb->information = 0;
+	cb->file_private = (void *) cl;
+	cl->read_cb = cb;
+	if (dev->mei_host_buffer_is_empty) {
+		dev->mei_host_buffer_is_empty = false;
+		if (mei_send_flow_control(dev, cl)) {
+			rets = -ENODEV;
+			goto unlock;
+		}
+		list_add_tail(&cb->cb_list, &dev->read_list.mei_cb.cb_list);
+	} else {
+		list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list);
+	}
+	return rets;
+unlock:
+	mei_free_cb_private(cb);
+	return rets;
+}
+
+/**
+ * amthi_write - write iamthif data to amthi client
+ *
+ * @dev: the device structure
+ * @cb: mei call back struct
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
+{
+	struct mei_msg_hdr mei_hdr;
+	int ret;
+
+	if (!dev || !cb)
+		return -ENODEV;
+
+	dev_dbg(&dev->pdev->dev, "write data to amthi client.\n");
+
+	dev->iamthif_state = MEI_IAMTHIF_WRITING;
+	dev->iamthif_current_cb = cb;
+	dev->iamthif_file_object = cb->file_object;
+	dev->iamthif_canceled = false;
+	dev->iamthif_ioctl = true;
+	dev->iamthif_msg_buf_size = cb->request_buffer.size;
+	memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
+	       cb->request_buffer.size);
+
+	ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl);
+	if (ret < 0)
+		return ret;
+
+	if (ret && dev->mei_host_buffer_is_empty) {
+		ret = 0;
+		dev->mei_host_buffer_is_empty = false;
+		if (cb->request_buffer.size >
+			(((dev->host_hw_state & H_CBD) >> 24) * sizeof(u32))
+				-sizeof(struct mei_msg_hdr)) {
+			mei_hdr.length =
+			    (((dev->host_hw_state & H_CBD) >> 24) *
+			    sizeof(u32)) - sizeof(struct mei_msg_hdr);
+			mei_hdr.msg_complete = 0;
+		} else {
+			mei_hdr.length = cb->request_buffer.size;
+			mei_hdr.msg_complete = 1;
+		}
+
+		mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
+		mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
+		mei_hdr.reserved = 0;
+		dev->iamthif_msg_buf_index += mei_hdr.length;
+		if (mei_write_message(dev, &mei_hdr,
+					(unsigned char *)(dev->iamthif_msg_buf),
+					mei_hdr.length))
+			return -ENODEV;
+
+		if (mei_hdr.msg_complete) {
+			if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl))
+				return -ENODEV;
+			dev->iamthif_flow_control_pending = true;
+			dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
+			dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n");
+			dev->iamthif_current_cb = cb;
+			dev->iamthif_file_object = cb->file_object;
+			list_add_tail(&cb->cb_list,
+				      &dev->write_waiting_list.mei_cb.cb_list);
+		} else {
+			dev_dbg(&dev->pdev->dev, "message does not complete, "
+					"so add amthi cb to write list.\n");
+			list_add_tail(&cb->cb_list,
+				      &dev->write_list.mei_cb.cb_list);
+		}
+	} else {
+		if (!(dev->mei_host_buffer_is_empty))
+			dev_dbg(&dev->pdev->dev, "host buffer is not empty");
+
+		dev_dbg(&dev->pdev->dev, "No flow control credentials, "
+				"so add iamthif cb to write list.\n");
+		list_add_tail(&cb->cb_list, &dev->write_list.mei_cb.cb_list);
+	}
+	return 0;
+}
+
+/**
+ * iamthif_ioctl_send_msg - send cmd data to amthi client
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success, <0 on failure.
+ */
+void mei_run_next_iamthif_cmd(struct mei_device *dev)
+{
+	struct mei_cl *cl_tmp;
+	struct mei_cl_cb *pos = NULL;
+	struct mei_cl_cb *next = NULL;
+	int status;
+
+	if (!dev)
+		return;
+
+	dev->iamthif_msg_buf_size = 0;
+	dev->iamthif_msg_buf_index = 0;
+	dev->iamthif_canceled = false;
+	dev->iamthif_ioctl = true;
+	dev->iamthif_state = MEI_IAMTHIF_IDLE;
+	dev->iamthif_timer = 0;
+	dev->iamthif_file_object = NULL;
+
+	dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n");
+
+	list_for_each_entry_safe(pos, next,
+			&dev->amthi_cmd_list.mei_cb.cb_list, cb_list) {
+		list_del(&pos->cb_list);
+		cl_tmp = (struct mei_cl *)pos->file_private;
+
+		if (cl_tmp && cl_tmp == &dev->iamthif_cl) {
+			status = amthi_write(dev, pos);
+			if (status) {
+				dev_dbg(&dev->pdev->dev,
+					"amthi write failed status = %d\n",
+						status);
+				return;
+			}
+			break;
+		}
+	}
+}
+
+/**
+ * mei_free_cb_private - free mei_cb_private related memory
+ *
+ * @cb: mei callback struct
+ */
+void mei_free_cb_private(struct mei_cl_cb *cb)
+{
+	if (cb == NULL)
+		return;
+
+	kfree(cb->request_buffer.data);
+	kfree(cb->response_buffer.data);
+	kfree(cb);
+}
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
new file mode 100644
index 0000000..c703332
--- /dev/null
+++ b/drivers/misc/mei/main.c
@@ -0,0 +1,1230 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, 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.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/aio.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/uuid.h>
+#include <linux/compat.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+
+#include "mei_dev.h"
+#include <linux/mei.h>
+#include "interface.h"
+
+static const char mei_driver_name[] = "mei";
+
+/* The device pointer */
+/* Currently this driver works as long as there is only a single AMT device. */
+struct pci_dev *mei_device;
+
+/* mei_pci_tbl - PCI Device ID Table */
+static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
+
+	/* required last entry */
+	{0, }
+};
+
+MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
+
+static DEFINE_MUTEX(mei_mutex);
+
+
+/**
+ * mei_clear_list - removes all callbacks associated with file
+ *		from mei_cb_list
+ *
+ * @dev: device structure.
+ * @file: file structure
+ * @mei_cb_list: callbacks list
+ *
+ * mei_clear_list is called to clear resources associated with file
+ * when application calls close function or Ctrl-C was pressed
+ *
+ * returns true if callback removed from the list, false otherwise
+ */
+static bool mei_clear_list(struct mei_device *dev,
+		struct file *file, struct list_head *mei_cb_list)
+{
+	struct mei_cl_cb *cb_pos = NULL;
+	struct mei_cl_cb *cb_next = NULL;
+	struct file *file_temp;
+	bool removed = false;
+
+	/* list all list member */
+	list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) {
+		file_temp = (struct file *)cb_pos->file_object;
+		/* check if list member associated with a file */
+		if (file_temp == file) {
+			/* remove member from the list */
+			list_del(&cb_pos->cb_list);
+			/* check if cb equal to current iamthif cb */
+			if (dev->iamthif_current_cb == cb_pos) {
+				dev->iamthif_current_cb = NULL;
+				/* send flow control to iamthif client */
+				mei_send_flow_control(dev, &dev->iamthif_cl);
+			}
+			/* free all allocated buffers */
+			mei_free_cb_private(cb_pos);
+			cb_pos = NULL;
+			removed = true;
+		}
+	}
+	return removed;
+}
+
+/**
+ * mei_clear_lists - removes all callbacks associated with file
+ *
+ * @dev: device structure
+ * @file: file structure
+ *
+ * mei_clear_lists is called to clear resources associated with file
+ * when application calls close function or Ctrl-C was pressed
+ *
+ * returns true if callback removed from the list, false otherwise
+ */
+static bool mei_clear_lists(struct mei_device *dev, struct file *file)
+{
+	bool removed = false;
+
+	/* remove callbacks associated with a file */
+	mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list);
+	if (mei_clear_list(dev, file,
+			    &dev->amthi_read_complete_list.mei_cb.cb_list))
+		removed = true;
+
+	mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list);
+
+	if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list))
+		removed = true;
+
+	if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list))
+		removed = true;
+
+	if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list))
+		removed = true;
+
+	/* check if iamthif_current_cb not NULL */
+	if (dev->iamthif_current_cb && !removed) {
+		/* check file and iamthif current cb association */
+		if (dev->iamthif_current_cb->file_object == file) {
+			/* remove cb */
+			mei_free_cb_private(dev->iamthif_current_cb);
+			dev->iamthif_current_cb = NULL;
+			removed = true;
+		}
+	}
+	return removed;
+}
+/**
+ * find_read_list_entry - find read list entry
+ *
+ * @dev: device structure
+ * @file: pointer to file structure
+ *
+ * returns cb on success, NULL on error
+ */
+static struct mei_cl_cb *find_read_list_entry(
+		struct mei_device *dev,
+		struct mei_cl *cl)
+{
+	struct mei_cl_cb *pos = NULL;
+	struct mei_cl_cb *next = NULL;
+
+	dev_dbg(&dev->pdev->dev, "remove read_list CB\n");
+	list_for_each_entry_safe(pos, next,
+			&dev->read_list.mei_cb.cb_list, cb_list) {
+		struct mei_cl *cl_temp;
+		cl_temp = (struct mei_cl *)pos->file_private;
+
+		if (mei_cl_cmp_id(cl, cl_temp))
+			return pos;
+	}
+	return NULL;
+}
+
+/**
+ * mei_open - the open function
+ *
+ * @inode: pointer to inode structure
+ * @file: pointer to file structure
+ *
+ * returns 0 on success, <0 on error
+ */
+static int mei_open(struct inode *inode, struct file *file)
+{
+	struct mei_cl *cl;
+	struct mei_device *dev;
+	unsigned long cl_id;
+	int err;
+
+	err = -ENODEV;
+	if (!mei_device)
+		goto out;
+
+	dev = pci_get_drvdata(mei_device);
+	if (!dev)
+		goto out;
+
+	mutex_lock(&dev->device_lock);
+	err = -ENOMEM;
+	cl = mei_cl_allocate(dev);
+	if (!cl)
+		goto out_unlock;
+
+	err = -ENODEV;
+	if (dev->mei_state != MEI_ENABLED) {
+		dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED  mei_state= %d\n",
+		    dev->mei_state);
+		goto out_unlock;
+	}
+	err = -EMFILE;
+	if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT)
+		goto out_unlock;
+
+	cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
+	if (cl_id >= MEI_CLIENTS_MAX)
+		goto out_unlock;
+
+	cl->host_client_id  = cl_id;
+
+	dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id);
+
+	dev->open_handle_count++;
+
+	list_add_tail(&cl->link, &dev->file_list);
+
+	set_bit(cl->host_client_id, dev->host_clients_map);
+	cl->state = MEI_FILE_INITIALIZING;
+	cl->sm_state = 0;
+
+	file->private_data = cl;
+	mutex_unlock(&dev->device_lock);
+
+	return nonseekable_open(inode, file);
+
+out_unlock:
+	mutex_unlock(&dev->device_lock);
+	kfree(cl);
+out:
+	return err;
+}
+
+/**
+ * mei_release - the release function
+ *
+ * @inode: pointer to inode structure
+ * @file: pointer to file structure
+ *
+ * returns 0 on success, <0 on error
+ */
+static int mei_release(struct inode *inode, struct file *file)
+{
+	struct mei_cl *cl = file->private_data;
+	struct mei_cl_cb *cb;
+	struct mei_device *dev;
+	int rets = 0;
+
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
+
+	dev = cl->dev;
+
+	mutex_lock(&dev->device_lock);
+	if (cl != &dev->iamthif_cl) {
+		if (cl->state == MEI_FILE_CONNECTED) {
+			cl->state = MEI_FILE_DISCONNECTING;
+			dev_dbg(&dev->pdev->dev,
+				"disconnecting client host client = %d, "
+			    "ME client = %d\n",
+			    cl->host_client_id,
+			    cl->me_client_id);
+			rets = mei_disconnect_host_client(dev, cl);
+		}
+		mei_cl_flush_queues(cl);
+		dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
+		    cl->host_client_id,
+		    cl->me_client_id);
+
+		if (dev->open_handle_count > 0) {
+			clear_bit(cl->host_client_id, dev->host_clients_map);
+			dev->open_handle_count--;
+		}
+		mei_remove_client_from_file_list(dev, cl->host_client_id);
+
+		/* free read cb */
+		cb = NULL;
+		if (cl->read_cb) {
+			cb = find_read_list_entry(dev, cl);
+			/* Remove entry from read list */
+			if (cb)
+				list_del(&cb->cb_list);
+
+			cb = cl->read_cb;
+			cl->read_cb = NULL;
+		}
+
+		file->private_data = NULL;
+
+		if (cb) {
+			mei_free_cb_private(cb);
+			cb = NULL;
+		}
+
+		kfree(cl);
+	} else {
+		if (dev->open_handle_count > 0)
+			dev->open_handle_count--;
+
+		if (dev->iamthif_file_object == file &&
+		    dev->iamthif_state != MEI_IAMTHIF_IDLE) {
+
+			dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n",
+			    dev->iamthif_state);
+			dev->iamthif_canceled = true;
+			if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
+				dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n");
+				mei_run_next_iamthif_cmd(dev);
+			}
+		}
+
+		if (mei_clear_lists(dev, file))
+			dev->iamthif_state = MEI_IAMTHIF_IDLE;
+
+	}
+	mutex_unlock(&dev->device_lock);
+	return rets;
+}
+
+
+/**
+ * mei_read - the read function.
+ *
+ * @file: pointer to file structure
+ * @ubuf: pointer to user buffer
+ * @length: buffer length
+ * @offset: data offset in buffer
+ *
+ * returns >=0 data length on success , <0 on error
+ */
+static ssize_t mei_read(struct file *file, char __user *ubuf,
+			size_t length, loff_t *offset)
+{
+	struct mei_cl *cl = file->private_data;
+	struct mei_cl_cb *cb_pos = NULL;
+	struct mei_cl_cb *cb = NULL;
+	struct mei_device *dev;
+	int i;
+	int rets;
+	int err;
+
+
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
+
+	dev = cl->dev;
+
+	mutex_lock(&dev->device_lock);
+	if (dev->mei_state != MEI_ENABLED) {
+		rets = -ENODEV;
+		goto out;
+	}
+
+	if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
+		/* Do not allow to read watchdog client */
+		i = mei_find_me_client_index(dev, mei_wd_guid);
+		if (i >= 0) {
+			struct mei_me_client *me_client = &dev->me_clients[i];
+
+			if (cl->me_client_id == me_client->client_id) {
+				rets = -EBADF;
+				goto out;
+			}
+		}
+	} else {
+		cl->sm_state &= ~MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
+	}
+
+	if (cl == &dev->iamthif_cl) {
+		rets = amthi_read(dev, file, ubuf, length, offset);
+		goto out;
+	}
+
+	if (cl->read_cb && cl->read_cb->information > *offset) {
+		cb = cl->read_cb;
+		goto copy_buffer;
+	} else if (cl->read_cb && cl->read_cb->information > 0 &&
+		   cl->read_cb->information <= *offset) {
+		cb = cl->read_cb;
+		rets = 0;
+		goto free;
+	} else if ((!cl->read_cb || !cl->read_cb->information) &&
+		    *offset > 0) {
+		/*Offset needs to be cleaned for contiguous reads*/
+		*offset = 0;
+		rets = 0;
+		goto out;
+	}
+
+	err = mei_start_read(dev, cl);
+	if (err && err != -EBUSY) {
+		dev_dbg(&dev->pdev->dev,
+			"mei start read failure with status = %d\n", err);
+		rets = err;
+		goto out;
+	}
+
+	if (MEI_READ_COMPLETE != cl->reading_state &&
+			!waitqueue_active(&cl->rx_wait)) {
+		if (file->f_flags & O_NONBLOCK) {
+			rets = -EAGAIN;
+			goto out;
+		}
+
+		mutex_unlock(&dev->device_lock);
+
+		if (wait_event_interruptible(cl->rx_wait,
+			(MEI_READ_COMPLETE == cl->reading_state ||
+			 MEI_FILE_INITIALIZING == cl->state ||
+			 MEI_FILE_DISCONNECTED == cl->state ||
+			 MEI_FILE_DISCONNECTING == cl->state))) {
+			if (signal_pending(current))
+				return -EINTR;
+			return -ERESTARTSYS;
+		}
+
+		mutex_lock(&dev->device_lock);
+		if (MEI_FILE_INITIALIZING == cl->state ||
+		    MEI_FILE_DISCONNECTED == cl->state ||
+		    MEI_FILE_DISCONNECTING == cl->state) {
+			rets = -EBUSY;
+			goto out;
+		}
+	}
+
+	cb = cl->read_cb;
+
+	if (!cb) {
+		rets = -ENODEV;
+		goto out;
+	}
+	if (cl->reading_state != MEI_READ_COMPLETE) {
+		rets = 0;
+		goto out;
+	}
+	/* now copy the data to user space */
+copy_buffer:
+	dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n",
+	    cb->response_buffer.size);
+	dev_dbg(&dev->pdev->dev, "cb->information - %lu\n",
+	    cb->information);
+	if (length == 0 || ubuf == NULL || *offset > cb->information) {
+		rets = -EMSGSIZE;
+		goto free;
+	}
+
+	/* length is being truncated to PAGE_SIZE, however, */
+	/* information size may be longer */
+	length = min_t(size_t, length, (cb->information - *offset));
+
+	if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
+		rets = -EFAULT;
+		goto free;
+	}
+
+	rets = length;
+	*offset += length;
+	if ((unsigned long)*offset < cb->information)
+		goto out;
+
+free:
+	cb_pos = find_read_list_entry(dev, cl);
+	/* Remove entry from read list */
+	if (cb_pos)
+		list_del(&cb_pos->cb_list);
+	mei_free_cb_private(cb);
+	cl->reading_state = MEI_IDLE;
+	cl->read_cb = NULL;
+	cl->read_pending = 0;
+out:
+	dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets);
+	mutex_unlock(&dev->device_lock);
+	return rets;
+}
+
+/**
+ * mei_write - the write function.
+ *
+ * @file: pointer to file structure
+ * @ubuf: pointer to user buffer
+ * @length: buffer length
+ * @offset: data offset in buffer
+ *
+ * returns >=0 data length on success , <0 on error
+ */
+static ssize_t mei_write(struct file *file, const char __user *ubuf,
+			 size_t length, loff_t *offset)
+{
+	struct mei_cl *cl = file->private_data;
+	struct mei_cl_cb *write_cb = NULL;
+	struct mei_msg_hdr mei_hdr;
+	struct mei_device *dev;
+	unsigned long timeout = 0;
+	int rets;
+	int i;
+
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
+
+	dev = cl->dev;
+
+	mutex_lock(&dev->device_lock);
+
+	if (dev->mei_state != MEI_ENABLED) {
+		mutex_unlock(&dev->device_lock);
+		return -ENODEV;
+	}
+
+	if (cl == &dev->iamthif_cl) {
+		write_cb = find_amthi_read_list_entry(dev, file);
+
+		if (write_cb) {
+			timeout = write_cb->read_time +
+					msecs_to_jiffies(IAMTHIF_READ_TIMER);
+
+			if (time_after(jiffies, timeout) ||
+				 cl->reading_state == MEI_READ_COMPLETE) {
+					*offset = 0;
+					list_del(&write_cb->cb_list);
+					mei_free_cb_private(write_cb);
+					write_cb = NULL;
+			}
+		}
+	}
+
+	/* free entry used in read */
+	if (cl->reading_state == MEI_READ_COMPLETE) {
+		*offset = 0;
+		write_cb = find_read_list_entry(dev, cl);
+		if (write_cb) {
+			list_del(&write_cb->cb_list);
+			mei_free_cb_private(write_cb);
+			write_cb = NULL;
+			cl->reading_state = MEI_IDLE;
+			cl->read_cb = NULL;
+			cl->read_pending = 0;
+		}
+	} else if (cl->reading_state == MEI_IDLE && !cl->read_pending)
+		*offset = 0;
+
+
+	write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
+	if (!write_cb) {
+		mutex_unlock(&dev->device_lock);
+		return -ENOMEM;
+	}
+
+	write_cb->file_object = file;
+	write_cb->file_private = cl;
+	write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
+	rets = -ENOMEM;
+	if (!write_cb->request_buffer.data)
+		goto unlock_dev;
+
+	dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length);
+
+	rets = -EFAULT;
+	if (copy_from_user(write_cb->request_buffer.data, ubuf, length))
+		goto unlock_dev;
+
+	cl->sm_state = 0;
+	if (length == 4 &&
+	    ((memcmp(mei_wd_state_independence_msg[0],
+				 write_cb->request_buffer.data, 4) == 0) ||
+	     (memcmp(mei_wd_state_independence_msg[1],
+				 write_cb->request_buffer.data, 4) == 0) ||
+	     (memcmp(mei_wd_state_independence_msg[2],
+				 write_cb->request_buffer.data, 4) == 0)))
+		cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
+
+	INIT_LIST_HEAD(&write_cb->cb_list);
+	if (cl == &dev->iamthif_cl) {
+		write_cb->response_buffer.data =
+		    kmalloc(dev->iamthif_mtu, GFP_KERNEL);
+		if (!write_cb->response_buffer.data) {
+			rets = -ENOMEM;
+			goto unlock_dev;
+		}
+		if (dev->mei_state != MEI_ENABLED) {
+			rets = -ENODEV;
+			goto unlock_dev;
+		}
+		for (i = 0; i < dev->me_clients_num; i++) {
+			if (dev->me_clients[i].client_id ==
+				dev->iamthif_cl.me_client_id)
+				break;
+		}
+
+		if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
+			rets = -ENODEV;
+			goto unlock_dev;
+		}
+		if (i == dev->me_clients_num ||
+		    (dev->me_clients[i].client_id !=
+		      dev->iamthif_cl.me_client_id)) {
+			rets = -ENODEV;
+			goto unlock_dev;
+		} else if (length > dev->me_clients[i].props.max_msg_length ||
+			   length <= 0) {
+			rets = -EMSGSIZE;
+			goto unlock_dev;
+		}
+
+		write_cb->response_buffer.size = dev->iamthif_mtu;
+		write_cb->major_file_operations = MEI_IOCTL;
+		write_cb->information = 0;
+		write_cb->request_buffer.size = length;
+		if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
+			rets = -ENODEV;
+			goto unlock_dev;
+		}
+
+		if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) ||
+				dev->iamthif_state != MEI_IAMTHIF_IDLE) {
+			dev_dbg(&dev->pdev->dev, "amthi_state = %d\n",
+					(int) dev->iamthif_state);
+			dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n");
+			list_add_tail(&write_cb->cb_list,
+					&dev->amthi_cmd_list.mei_cb.cb_list);
+			rets = length;
+		} else {
+			dev_dbg(&dev->pdev->dev, "call amthi write\n");
+			rets = amthi_write(dev, write_cb);
+
+			if (rets) {
+				dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n",
+				    rets);
+				goto unlock_dev;
+			}
+			rets = length;
+		}
+		mutex_unlock(&dev->device_lock);
+		return rets;
+	}
+
+	write_cb->major_file_operations = MEI_WRITE;
+	/* make sure information is zero before we start */
+
+	write_cb->information = 0;
+	write_cb->request_buffer.size = length;
+
+	dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n",
+	    cl->host_client_id, cl->me_client_id);
+	if (cl->state != MEI_FILE_CONNECTED) {
+		rets = -ENODEV;
+		dev_dbg(&dev->pdev->dev, "host client = %d,  is not connected to ME client = %d",
+		    cl->host_client_id,
+		    cl->me_client_id);
+		goto unlock_dev;
+	}
+	for (i = 0; i < dev->me_clients_num; i++) {
+		if (dev->me_clients[i].client_id ==
+		    cl->me_client_id)
+			break;
+	}
+	if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
+		rets = -ENODEV;
+		goto unlock_dev;
+	}
+	if (i == dev->me_clients_num) {
+		rets = -ENODEV;
+		goto unlock_dev;
+	}
+	if (length > dev->me_clients[i].props.max_msg_length || length <= 0) {
+		rets = -EINVAL;
+		goto unlock_dev;
+	}
+	write_cb->file_private = cl;
+
+	rets = mei_flow_ctrl_creds(dev, cl);
+	if (rets < 0)
+		goto unlock_dev;
+
+	if (rets && dev->mei_host_buffer_is_empty) {
+		rets = 0;
+		dev->mei_host_buffer_is_empty = false;
+		if (length > ((((dev->host_hw_state & H_CBD) >> 24) *
+			sizeof(u32)) - sizeof(struct mei_msg_hdr))) {
+
+			mei_hdr.length =
+				(((dev->host_hw_state & H_CBD) >> 24) *
+				sizeof(u32)) -
+				sizeof(struct mei_msg_hdr);
+			mei_hdr.msg_complete = 0;
+		} else {
+			mei_hdr.length = length;
+			mei_hdr.msg_complete = 1;
+		}
+		mei_hdr.host_addr = cl->host_client_id;
+		mei_hdr.me_addr = cl->me_client_id;
+		mei_hdr.reserved = 0;
+		dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n",
+		    *((u32 *) &mei_hdr));
+		if (mei_write_message(dev, &mei_hdr,
+			(unsigned char *) (write_cb->request_buffer.data),
+			mei_hdr.length)) {
+			rets = -ENODEV;
+			goto unlock_dev;
+		}
+		cl->writing_state = MEI_WRITING;
+		write_cb->information = mei_hdr.length;
+		if (mei_hdr.msg_complete) {
+			if (mei_flow_ctrl_reduce(dev, cl)) {
+				rets = -ENODEV;
+				goto unlock_dev;
+			}
+			list_add_tail(&write_cb->cb_list,
+				      &dev->write_waiting_list.mei_cb.cb_list);
+		} else {
+			list_add_tail(&write_cb->cb_list,
+				      &dev->write_list.mei_cb.cb_list);
+		}
+
+	} else {
+
+		write_cb->information = 0;
+		cl->writing_state = MEI_WRITING;
+		list_add_tail(&write_cb->cb_list,
+			      &dev->write_list.mei_cb.cb_list);
+	}
+	mutex_unlock(&dev->device_lock);
+	return length;
+
+unlock_dev:
+	mutex_unlock(&dev->device_lock);
+	mei_free_cb_private(write_cb);
+	return rets;
+}
+
+
+/**
+ * mei_ioctl - the IOCTL function
+ *
+ * @file: pointer to file structure
+ * @cmd: ioctl command
+ * @data: pointer to mei message structure
+ *
+ * returns 0 on success , <0 on error
+ */
+static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
+{
+	struct mei_device *dev;
+	struct mei_cl *cl = file->private_data;
+	struct mei_connect_client_data *connect_data = NULL;
+	int rets;
+
+	if (cmd != IOCTL_MEI_CONNECT_CLIENT)
+		return -EINVAL;
+
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
+
+	dev = cl->dev;
+
+	dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
+
+	mutex_lock(&dev->device_lock);
+	if (dev->mei_state != MEI_ENABLED) {
+		rets = -ENODEV;
+		goto out;
+	}
+
+	dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
+
+	connect_data = kzalloc(sizeof(struct mei_connect_client_data),
+							GFP_KERNEL);
+	if (!connect_data) {
+		rets = -ENOMEM;
+		goto out;
+	}
+	dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
+	if (copy_from_user(connect_data, (char __user *)data,
+				sizeof(struct mei_connect_client_data))) {
+		dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
+		rets = -EFAULT;
+		goto out;
+	}
+	rets = mei_ioctl_connect_client(file, connect_data);
+
+	/* if all is ok, copying the data back to user. */
+	if (rets)
+		goto out;
+
+	dev_dbg(&dev->pdev->dev, "copy connect data to user\n");
+	if (copy_to_user((char __user *)data, connect_data,
+				sizeof(struct mei_connect_client_data))) {
+		dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
+		rets = -EFAULT;
+		goto out;
+	}
+
+out:
+	kfree(connect_data);
+	mutex_unlock(&dev->device_lock);
+	return rets;
+}
+
+/**
+ * mei_compat_ioctl - the compat IOCTL function
+ *
+ * @file: pointer to file structure
+ * @cmd: ioctl command
+ * @data: pointer to mei message structure
+ *
+ * returns 0 on success , <0 on error
+ */
+#ifdef CONFIG_COMPAT
+static long mei_compat_ioctl(struct file *file,
+			unsigned int cmd, unsigned long data)
+{
+	return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data));
+}
+#endif
+
+
+/**
+ * mei_poll - the poll function
+ *
+ * @file: pointer to file structure
+ * @wait: pointer to poll_table structure
+ *
+ * returns poll mask
+ */
+static unsigned int mei_poll(struct file *file, poll_table *wait)
+{
+	struct mei_cl *cl = file->private_data;
+	struct mei_device *dev;
+	unsigned int mask = 0;
+
+	if (WARN_ON(!cl || !cl->dev))
+		return mask;
+
+	dev = cl->dev;
+
+	mutex_lock(&dev->device_lock);
+
+	if (dev->mei_state != MEI_ENABLED)
+		goto out;
+
+
+	if (cl == &dev->iamthif_cl) {
+		mutex_unlock(&dev->device_lock);
+		poll_wait(file, &dev->iamthif_cl.wait, wait);
+		mutex_lock(&dev->device_lock);
+		if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
+			dev->iamthif_file_object == file) {
+			mask |= (POLLIN | POLLRDNORM);
+			dev_dbg(&dev->pdev->dev, "run next amthi cb\n");
+			mei_run_next_iamthif_cmd(dev);
+		}
+		goto out;
+	}
+
+	mutex_unlock(&dev->device_lock);
+	poll_wait(file, &cl->tx_wait, wait);
+	mutex_lock(&dev->device_lock);
+	if (MEI_WRITE_COMPLETE == cl->writing_state)
+		mask |= (POLLIN | POLLRDNORM);
+
+out:
+	mutex_unlock(&dev->device_lock);
+	return mask;
+}
+
+/*
+ * file operations structure will be used for mei char device.
+ */
+static const struct file_operations mei_fops = {
+	.owner = THIS_MODULE,
+	.read = mei_read,
+	.unlocked_ioctl = mei_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = mei_compat_ioctl,
+#endif
+	.open = mei_open,
+	.release = mei_release,
+	.write = mei_write,
+	.poll = mei_poll,
+	.llseek = no_llseek
+};
+
+
+/*
+ * Misc Device Struct
+ */
+static struct miscdevice  mei_misc_device = {
+		.name = "mei",
+		.fops = &mei_fops,
+		.minor = MISC_DYNAMIC_MINOR,
+};
+
+/**
+ * mei_probe - Device Initialization Routine
+ *
+ * @pdev: PCI device structure
+ * @ent: entry in kcs_pci_tbl
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int __devinit mei_probe(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
+{
+	struct mei_device *dev;
+	int err;
+
+	mutex_lock(&mei_mutex);
+	if (mei_device) {
+		err = -EEXIST;
+		goto end;
+	}
+	/* enable pci dev */
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "failed to enable pci device.\n");
+		goto end;
+	}
+	/* set PCI host mastering  */
+	pci_set_master(pdev);
+	/* pci request regions for mei driver */
+	err = pci_request_regions(pdev, mei_driver_name);
+	if (err) {
+		dev_err(&pdev->dev, "failed to get pci regions.\n");
+		goto disable_device;
+	}
+	/* allocates and initializes the mei dev structure */
+	dev = mei_device_init(pdev);
+	if (!dev) {
+		err = -ENOMEM;
+		goto release_regions;
+	}
+	/* mapping  IO device memory */
+	dev->mem_addr = pci_iomap(pdev, 0, 0);
+	if (!dev->mem_addr) {
+		dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
+		err = -ENOMEM;
+		goto free_device;
+	}
+	pci_enable_msi(pdev);
+
+	 /* request and enable interrupt */
+	if (pci_dev_msi_enabled(pdev))
+		err = request_threaded_irq(pdev->irq,
+			NULL,
+			mei_interrupt_thread_handler,
+			0, mei_driver_name, dev);
+	else
+		err = request_threaded_irq(pdev->irq,
+			mei_interrupt_quick_handler,
+			mei_interrupt_thread_handler,
+			IRQF_SHARED, mei_driver_name, dev);
+
+	if (err) {
+		dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
+		       pdev->irq);
+		goto unmap_memory;
+	}
+	INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
+	if (mei_hw_init(dev)) {
+		dev_err(&pdev->dev, "init hw failure.\n");
+		err = -ENODEV;
+		goto release_irq;
+	}
+
+	err = misc_register(&mei_misc_device);
+	if (err)
+		goto release_irq;
+
+	mei_device = pdev;
+	pci_set_drvdata(pdev, dev);
+
+
+	schedule_delayed_work(&dev->timer_work, HZ);
+
+	mutex_unlock(&mei_mutex);
+
+	pr_debug("initialization successful.\n");
+
+	return 0;
+
+release_irq:
+	/* disable interrupts */
+	dev->host_hw_state = mei_hcsr_read(dev);
+	mei_disable_interrupts(dev);
+	flush_scheduled_work();
+	free_irq(pdev->irq, dev);
+	pci_disable_msi(pdev);
+unmap_memory:
+	pci_iounmap(pdev, dev->mem_addr);
+free_device:
+	kfree(dev);
+release_regions:
+	pci_release_regions(pdev);
+disable_device:
+	pci_disable_device(pdev);
+end:
+	mutex_unlock(&mei_mutex);
+	dev_err(&pdev->dev, "initialization failed.\n");
+	return err;
+}
+
+/**
+ * mei_remove - Device Removal Routine
+ *
+ * @pdev: PCI device structure
+ *
+ * mei_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+static void __devexit mei_remove(struct pci_dev *pdev)
+{
+	struct mei_device *dev;
+
+	if (mei_device != pdev)
+		return;
+
+	dev = pci_get_drvdata(pdev);
+	if (!dev)
+		return;
+
+	mutex_lock(&dev->device_lock);
+
+	mei_wd_stop(dev, false);
+
+	mei_device = NULL;
+
+	if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
+		dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
+		mei_disconnect_host_client(dev, &dev->iamthif_cl);
+	}
+	if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
+		dev->wd_cl.state = MEI_FILE_DISCONNECTING;
+		mei_disconnect_host_client(dev, &dev->wd_cl);
+	}
+
+	/* Unregistering watchdog device */
+	mei_watchdog_unregister(dev);
+
+	/* remove entry if already in list */
+	dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
+	mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id);
+	mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id);
+
+	dev->iamthif_current_cb = NULL;
+	dev->me_clients_num = 0;
+
+	mutex_unlock(&dev->device_lock);
+
+	flush_scheduled_work();
+
+	/* disable interrupts */
+	mei_disable_interrupts(dev);
+
+	free_irq(pdev->irq, dev);
+	pci_disable_msi(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+	if (dev->mem_addr)
+		pci_iounmap(pdev, dev->mem_addr);
+
+	kfree(dev);
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+#ifdef CONFIG_PM
+static int mei_pci_suspend(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct mei_device *dev = pci_get_drvdata(pdev);
+	int err;
+
+	if (!dev)
+		return -ENODEV;
+	mutex_lock(&dev->device_lock);
+	/* Stop watchdog if exists */
+	err = mei_wd_stop(dev, true);
+	/* Set new mei state */
+	if (dev->mei_state == MEI_ENABLED ||
+	    dev->mei_state == MEI_RECOVERING_FROM_RESET) {
+		dev->mei_state = MEI_POWER_DOWN;
+		mei_reset(dev, 0);
+	}
+	mutex_unlock(&dev->device_lock);
+
+	free_irq(pdev->irq, dev);
+	pci_disable_msi(pdev);
+
+	return err;
+}
+
+static int mei_pci_resume(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct mei_device *dev;
+	int err;
+
+	dev = pci_get_drvdata(pdev);
+	if (!dev)
+		return -ENODEV;
+
+	pci_enable_msi(pdev);
+
+	/* request and enable interrupt */
+	if (pci_dev_msi_enabled(pdev))
+		err = request_threaded_irq(pdev->irq,
+			NULL,
+			mei_interrupt_thread_handler,
+			0, mei_driver_name, dev);
+	else
+		err = request_threaded_irq(pdev->irq,
+			mei_interrupt_quick_handler,
+			mei_interrupt_thread_handler,
+			IRQF_SHARED, mei_driver_name, dev);
+
+	if (err) {
+		dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
+				pdev->irq);
+		return err;
+	}
+
+	mutex_lock(&dev->device_lock);
+	dev->mei_state = MEI_POWER_UP;
+	mei_reset(dev, 1);
+	mutex_unlock(&dev->device_lock);
+
+	/* Start timer if stopped in suspend */
+	schedule_delayed_work(&dev->timer_work, HZ);
+
+	return err;
+}
+static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
+#define MEI_PM_OPS	(&mei_pm_ops)
+#else
+#define MEI_PM_OPS	NULL
+#endif /* CONFIG_PM */
+/*
+ *  PCI driver structure
+ */
+static struct pci_driver mei_driver = {
+	.name = mei_driver_name,
+	.id_table = mei_pci_tbl,
+	.probe = mei_probe,
+	.remove = __devexit_p(mei_remove),
+	.shutdown = __devexit_p(mei_remove),
+	.driver.pm = MEI_PM_OPS,
+};
+
+/**
+ * mei_init_module - Driver Registration Routine
+ *
+ * mei_init_module is the first routine called when the driver is
+ * loaded. All it does is to register with the PCI subsystem.
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int __init mei_init_module(void)
+{
+	int ret;
+
+	pr_debug("loading.\n");
+	/* init pci module */
+	ret = pci_register_driver(&mei_driver);
+	if (ret < 0)
+		pr_err("error registering driver.\n");
+
+	return ret;
+}
+
+module_init(mei_init_module);
+
+/**
+ * mei_exit_module - Driver Exit Cleanup Routine
+ *
+ * mei_exit_module is called just before the driver is removed
+ * from memory.
+ */
+static void __exit mei_exit_module(void)
+{
+	misc_deregister(&mei_misc_device);
+	pci_unregister_driver(&mei_driver);
+
+	pr_debug("unloaded successfully.\n");
+}
+
+module_exit(mei_exit_module);
+
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
new file mode 100644
index 0000000..63d7ee9
--- /dev/null
+++ b/drivers/misc/mei/mei_dev.h
@@ -0,0 +1,428 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, 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.
+ *
+ */
+
+#ifndef _MEI_DEV_H_
+#define _MEI_DEV_H_
+
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/mei.h>
+#include "hw.h"
+
+/*
+ * watch dog definition
+ */
+#define MEI_WATCHDOG_DATA_SIZE         16
+#define MEI_START_WD_DATA_SIZE         20
+#define MEI_WD_PARAMS_SIZE             4
+#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT       (1 << 0)
+
+#define MEI_RD_MSG_BUF_SIZE           (128 * sizeof(u32))
+
+/*
+ * MEI PCI Device object
+ */
+extern struct pci_dev *mei_device;
+
+
+/*
+ * AMTHI Client UUID
+ */
+extern const uuid_le mei_amthi_guid;
+
+/*
+ * Watchdog Client UUID
+ */
+extern const uuid_le mei_wd_guid;
+
+/*
+ * Watchdog independence state message
+ */
+extern const u8 mei_wd_state_independence_msg[3][4];
+
+/*
+ * Number of File descriptors/handles
+ * that can be opened to the driver.
+ *
+ * Limit to 253: 255 Total Clients
+ * minus internal client for AMTHI
+ * minus internal client for Watchdog
+ */
+#define  MEI_MAX_OPEN_HANDLE_COUNT	253
+
+/*
+ * Number of Maximum MEI Clients
+ */
+#define MEI_CLIENTS_MAX 255
+
+/* File state */
+enum file_state {
+	MEI_FILE_INITIALIZING = 0,
+	MEI_FILE_CONNECTING,
+	MEI_FILE_CONNECTED,
+	MEI_FILE_DISCONNECTING,
+	MEI_FILE_DISCONNECTED
+};
+
+/* MEI device states */
+enum mei_states {
+	MEI_INITIALIZING = 0,
+	MEI_INIT_CLIENTS,
+	MEI_ENABLED,
+	MEI_RESETING,
+	MEI_DISABLED,
+	MEI_RECOVERING_FROM_RESET,
+	MEI_POWER_DOWN,
+	MEI_POWER_UP
+};
+
+/* init clients states*/
+enum mei_init_clients_states {
+	MEI_START_MESSAGE = 0,
+	MEI_ENUM_CLIENTS_MESSAGE,
+	MEI_CLIENT_PROPERTIES_MESSAGE
+};
+
+enum iamthif_states {
+	MEI_IAMTHIF_IDLE,
+	MEI_IAMTHIF_WRITING,
+	MEI_IAMTHIF_FLOW_CONTROL,
+	MEI_IAMTHIF_READING,
+	MEI_IAMTHIF_READ_COMPLETE
+};
+
+enum mei_file_transaction_states {
+	MEI_IDLE,
+	MEI_WRITING,
+	MEI_WRITE_COMPLETE,
+	MEI_FLOW_CONTROL,
+	MEI_READING,
+	MEI_READ_COMPLETE
+};
+
+/* MEI CB */
+enum mei_cb_major_types {
+	MEI_READ = 0,
+	MEI_WRITE,
+	MEI_IOCTL,
+	MEI_OPEN,
+	MEI_CLOSE
+};
+
+/*
+ * Intel MEI message data struct
+ */
+struct mei_message_data {
+	u32 size;
+	unsigned char *data;
+} __packed;
+
+
+struct mei_cl_cb {
+	struct list_head cb_list;
+	enum mei_cb_major_types major_file_operations;
+	void *file_private;
+	struct mei_message_data request_buffer;
+	struct mei_message_data response_buffer;
+	unsigned long information;
+	unsigned long read_time;
+	struct file *file_object;
+};
+
+/* MEI client instance carried as file->pirvate_data*/
+struct mei_cl {
+	struct list_head link;
+	struct mei_device *dev;
+	enum file_state state;
+	wait_queue_head_t tx_wait;
+	wait_queue_head_t rx_wait;
+	wait_queue_head_t wait;
+	int read_pending;
+	int status;
+	/* ID of client connected */
+	u8 host_client_id;
+	u8 me_client_id;
+	u8 mei_flow_ctrl_creds;
+	u8 timer_count;
+	enum mei_file_transaction_states reading_state;
+	enum mei_file_transaction_states writing_state;
+	int sm_state;
+	struct mei_cl_cb *read_cb;
+};
+
+struct mei_io_list {
+	struct mei_cl_cb mei_cb;
+};
+
+/* MEI private device struct */
+struct mei_device {
+	struct pci_dev *pdev;	/* pointer to pci device struct */
+	/*
+	 * lists of queues
+	 */
+	 /* array of pointers to aio lists */
+	struct mei_io_list read_list;		/* driver read queue */
+	struct mei_io_list write_list;		/* driver write queue */
+	struct mei_io_list write_waiting_list;	/* write waiting queue */
+	struct mei_io_list ctrl_wr_list;	/* managed write IOCTL list */
+	struct mei_io_list ctrl_rd_list;	/* managed read IOCTL list */
+	struct mei_io_list amthi_cmd_list;	/* amthi list for cmd waiting */
+
+	/* driver managed amthi list for reading completed amthi cmd data */
+	struct mei_io_list amthi_read_complete_list;
+	/*
+	 * list of files
+	 */
+	struct list_head file_list;
+	long open_handle_count;
+	/*
+	 * memory of device
+	 */
+	unsigned int mem_base;
+	unsigned int mem_length;
+	void __iomem *mem_addr;
+	/*
+	 * lock for the device
+	 */
+	struct mutex device_lock; /* device lock */
+	struct delayed_work timer_work;	/* MEI timer delayed work (timeouts) */
+	bool recvd_msg;
+	/*
+	 * hw states of host and fw(ME)
+	 */
+	u32 host_hw_state;
+	u32 me_hw_state;
+	/*
+	 * waiting queue for receive message from FW
+	 */
+	wait_queue_head_t wait_recvd_msg;
+	wait_queue_head_t wait_stop_wd;
+
+	/*
+	 * mei device  states
+	 */
+	enum mei_states mei_state;
+	enum mei_init_clients_states init_clients_state;
+	u16 init_clients_timer;
+	bool stop;
+	bool need_reset;
+
+	u32 extra_write_index;
+	unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];	/* control messages */
+	u32 wr_msg_buf[128];	/* used for control messages */
+	u32 ext_msg_buf[8];	/* for control responses */
+	u32 rd_msg_hdr;
+
+	struct hbm_version version;
+
+	struct mei_me_client *me_clients; /* Note: memory has to be allocated */
+	DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
+	DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
+	u8 me_clients_num;
+	u8 me_client_presentation_num;
+	u8 me_client_index;
+	bool mei_host_buffer_is_empty;
+
+	struct mei_cl wd_cl;
+	bool wd_pending;
+	bool wd_stopped;
+	bool wd_bypass;	/* if false, don't refresh watchdog ME client */
+	u16 wd_timeout;	/* seconds ((wd_data[1] << 8) + wd_data[0]) */
+	u16 wd_due_counter;
+	unsigned char wd_data[MEI_START_WD_DATA_SIZE];
+
+
+
+	struct file *iamthif_file_object;
+	struct mei_cl iamthif_cl;
+	struct mei_cl_cb *iamthif_current_cb;
+	int iamthif_mtu;
+	unsigned long iamthif_timer;
+	u32 iamthif_stall_timer;
+	unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */
+	u32 iamthif_msg_buf_size;
+	u32 iamthif_msg_buf_index;
+	enum iamthif_states iamthif_state;
+	bool iamthif_flow_control_pending;
+	bool iamthif_ioctl;
+	bool iamthif_canceled;
+
+	bool wd_interface_reg;
+};
+
+
+/*
+ * mei init function prototypes
+ */
+struct mei_device *mei_device_init(struct pci_dev *pdev);
+void mei_reset(struct mei_device *dev, int interrupts);
+int mei_hw_init(struct mei_device *dev);
+int mei_task_initialize_clients(void *data);
+int mei_initialize_clients(struct mei_device *dev);
+int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl);
+void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id);
+void mei_host_init_iamthif(struct mei_device *dev);
+void mei_allocate_me_clients_storage(struct mei_device *dev);
+
+
+u8 mei_find_me_client_update_filext(struct mei_device *dev,
+				struct mei_cl *priv,
+				const uuid_le *cguid, u8 client_id);
+
+/*
+ * MEI IO List Functions
+ */
+void mei_io_list_init(struct mei_io_list *list);
+void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl);
+
+/*
+ * MEI ME Client Functions
+ */
+
+struct mei_cl *mei_cl_allocate(struct mei_device *dev);
+void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
+int mei_cl_flush_queues(struct mei_cl *cl);
+/**
+ * mei_cl_cmp_id - tells if file private data have same id
+ *
+ * @fe1: private data of 1. file object
+ * @fe2: private data of 2. file object
+ *
+ * returns true  - if ids are the same and not NULL
+ */
+static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
+				const struct mei_cl *cl2)
+{
+	return cl1 && cl2 &&
+		(cl1->host_client_id == cl2->host_client_id) &&
+		(cl1->me_client_id == cl2->me_client_id);
+}
+
+
+
+/*
+ * MEI Host Client Functions
+ */
+void mei_host_start_message(struct mei_device *dev);
+void mei_host_enum_clients_message(struct mei_device *dev);
+int mei_host_client_properties(struct mei_device *dev);
+
+/*
+ *  MEI interrupt functions prototype
+ */
+irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id);
+irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id);
+void mei_timer(struct work_struct *work);
+
+/*
+ *  MEI input output function prototype
+ */
+int mei_ioctl_connect_client(struct file *file,
+			struct mei_connect_client_data *data);
+
+int mei_start_read(struct mei_device *dev, struct mei_cl *cl);
+
+int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb);
+
+int amthi_read(struct mei_device *dev, struct file *file,
+	      char __user *ubuf, size_t length, loff_t *offset);
+
+struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev,
+						struct file *file);
+
+void mei_run_next_iamthif_cmd(struct mei_device *dev);
+
+void mei_free_cb_private(struct mei_cl_cb *priv_cb);
+
+int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
+
+/*
+ * Register Access Function
+ */
+
+/**
+ * mei_reg_read - Reads 32bit data from the mei device
+ *
+ * @dev: the device structure
+ * @offset: offset from which to read the data
+ *
+ * returns register value (u32)
+ */
+static inline u32 mei_reg_read(struct mei_device *dev, unsigned long offset)
+{
+	return ioread32(dev->mem_addr + offset);
+}
+
+/**
+ * mei_reg_write - Writes 32bit data to the mei device
+ *
+ * @dev: the device structure
+ * @offset: offset from which to write the data
+ * @value: register value to write (u32)
+ */
+static inline void mei_reg_write(struct mei_device *dev,
+				unsigned long offset, u32 value)
+{
+	iowrite32(value, dev->mem_addr + offset);
+}
+
+/**
+ * mei_hcsr_read - Reads 32bit data from the host CSR
+ *
+ * @dev: the device structure
+ *
+ * returns the byte read.
+ */
+static inline u32 mei_hcsr_read(struct mei_device *dev)
+{
+	return mei_reg_read(dev, H_CSR);
+}
+
+/**
+ * mei_mecsr_read - Reads 32bit data from the ME CSR
+ *
+ * @dev: the device structure
+ *
+ * returns ME_CSR_HA register value (u32)
+ */
+static inline u32 mei_mecsr_read(struct mei_device *dev)
+{
+	return mei_reg_read(dev, ME_CSR_HA);
+}
+
+/**
+ * get_me_cb_rw - Reads 32bit data from the mei ME_CB_RW register
+ *
+ * @dev: the device structure
+ *
+ * returns ME_CB_RW register value (u32)
+ */
+static inline u32 mei_mecbrw_read(struct mei_device *dev)
+{
+	return mei_reg_read(dev, ME_CB_RW);
+}
+
+
+/*
+ * mei interface function prototypes
+ */
+void mei_hcsr_set(struct mei_device *dev);
+void mei_csr_clear_his(struct mei_device *dev);
+
+void mei_enable_interrupts(struct mei_device *dev);
+void mei_disable_interrupts(struct mei_device *dev);
+
+#endif
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
new file mode 100644
index 0000000..6be5605
--- /dev/null
+++ b/drivers/misc/mei/wd.c
@@ -0,0 +1,379 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, 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.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/watchdog.h>
+
+#include "mei_dev.h"
+#include "hw.h"
+#include "interface.h"
+#include <linux/mei.h>
+
+static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
+static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
+
+const u8 mei_wd_state_independence_msg[3][4] = {
+	{0x05, 0x02, 0x51, 0x10},
+	{0x05, 0x02, 0x52, 0x10},
+	{0x07, 0x02, 0x01, 0x10}
+};
+
+/*
+ * AMT Watchdog Device
+ */
+#define INTEL_AMT_WATCHDOG_ID "INTCAMT"
+
+/* UUIDs for AMT F/W clients */
+const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
+						0x9D, 0xA9, 0x15, 0x14, 0xCB,
+						0x32, 0xAB);
+
+static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
+{
+	dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
+	memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
+	memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, &timeout, sizeof(u16));
+}
+
+/**
+ * host_init_wd - mei initialization wd.
+ *
+ * @dev: the device structure
+ * returns -ENENT if wd client cannot be found
+ *         -EIO if write has failed
+ */
+int mei_wd_host_init(struct mei_device *dev)
+{
+	mei_cl_init(&dev->wd_cl, dev);
+
+	/* look for WD client and connect to it */
+	dev->wd_cl.state = MEI_FILE_DISCONNECTED;
+	dev->wd_timeout = AMT_WD_DEFAULT_TIMEOUT;
+
+	/* find ME WD client */
+	mei_find_me_client_update_filext(dev, &dev->wd_cl,
+				&mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
+
+	dev_dbg(&dev->pdev->dev, "wd: check client\n");
+	if (MEI_FILE_CONNECTING != dev->wd_cl.state) {
+		dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
+		return -ENOENT;
+	}
+
+	if (mei_connect(dev, &dev->wd_cl)) {
+		dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
+		dev->wd_cl.state = MEI_FILE_DISCONNECTED;
+		dev->wd_cl.host_client_id = 0;
+		return -EIO;
+	}
+	dev->wd_cl.timer_count = CONNECT_TIMEOUT;
+
+	return 0;
+}
+
+/**
+ * mei_wd_send - sends watch dog message to fw.
+ *
+ * @dev: the device structure
+ *
+ * returns 0 if success,
+ *	-EIO when message send fails
+ *	-EINVAL when invalid message is to be sent
+ */
+int mei_wd_send(struct mei_device *dev)
+{
+	struct mei_msg_hdr *mei_hdr;
+
+	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+	mei_hdr->host_addr = dev->wd_cl.host_client_id;
+	mei_hdr->me_addr = dev->wd_cl.me_client_id;
+	mei_hdr->msg_complete = 1;
+	mei_hdr->reserved = 0;
+
+	if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE))
+		mei_hdr->length = MEI_START_WD_DATA_SIZE;
+	else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE))
+		mei_hdr->length = MEI_WD_PARAMS_SIZE;
+	else
+		return -EINVAL;
+
+	return mei_write_message(dev, mei_hdr, dev->wd_data, mei_hdr->length);
+}
+
+/**
+ * mei_wd_stop - sends watchdog stop message to fw.
+ *
+ * @dev: the device structure
+ * @preserve: indicate if to keep the timeout value
+ *
+ * returns 0 if success,
+ *	-EIO when message send fails
+ *	-EINVAL when invalid message is to be sent
+ */
+int mei_wd_stop(struct mei_device *dev, bool preserve)
+{
+	int ret;
+	u16 wd_timeout = dev->wd_timeout;
+
+	cancel_delayed_work(&dev->timer_work);
+	if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
+		return 0;
+
+	dev->wd_timeout = 0;
+	dev->wd_due_counter = 0;
+	memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
+	dev->stop = true;
+
+	ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
+	if (ret < 0)
+		goto out;
+
+	if (ret && dev->mei_host_buffer_is_empty) {
+		ret = 0;
+		dev->mei_host_buffer_is_empty = false;
+
+		if (!mei_wd_send(dev)) {
+			ret = mei_flow_ctrl_reduce(dev, &dev->wd_cl);
+			if (ret)
+				goto out;
+		} else {
+			dev_err(&dev->pdev->dev, "wd: send stop failed\n");
+		}
+
+		dev->wd_pending = false;
+	} else {
+		dev->wd_pending = true;
+	}
+	dev->wd_stopped = false;
+	mutex_unlock(&dev->device_lock);
+
+	ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
+					dev->wd_stopped, 10 * HZ);
+	mutex_lock(&dev->device_lock);
+	if (dev->wd_stopped) {
+		dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
+		ret = 0;
+	} else {
+		if (!ret)
+			ret = -ETIMEDOUT;
+		dev_warn(&dev->pdev->dev,
+			"wd: stop failed to complete ret=%d.\n", ret);
+	}
+
+	if (preserve)
+		dev->wd_timeout = wd_timeout;
+
+out:
+	return ret;
+}
+
+/*
+ * mei_wd_ops_start - wd start command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_start(struct watchdog_device *wd_dev)
+{
+	int err = -ENODEV;
+	struct mei_device *dev;
+
+	dev = pci_get_drvdata(mei_device);
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->device_lock);
+
+	if (dev->mei_state != MEI_ENABLED) {
+		dev_dbg(&dev->pdev->dev,
+			"wd: mei_state != MEI_ENABLED  mei_state = %d\n",
+			dev->mei_state);
+		goto end_unlock;
+	}
+
+	if (dev->wd_cl.state != MEI_FILE_CONNECTED)	{
+		dev_dbg(&dev->pdev->dev,
+			"MEI Driver is not connected to Watchdog Client\n");
+		goto end_unlock;
+	}
+
+	mei_wd_set_start_timeout(dev, dev->wd_timeout);
+
+	err = 0;
+end_unlock:
+	mutex_unlock(&dev->device_lock);
+	return err;
+}
+
+/*
+ * mei_wd_ops_stop -  wd stop command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
+{
+	struct mei_device *dev;
+	dev = pci_get_drvdata(mei_device);
+
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->device_lock);
+	mei_wd_stop(dev, false);
+	mutex_unlock(&dev->device_lock);
+
+	return 0;
+}
+
+/*
+ * mei_wd_ops_ping - wd ping command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
+{
+	int ret = 0;
+	struct mei_device *dev;
+	dev = pci_get_drvdata(mei_device);
+
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->device_lock);
+
+	if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
+		dev_err(&dev->pdev->dev, "wd: not connected.\n");
+		ret = -ENODEV;
+		goto end;
+	}
+
+	/* Check if we can send the ping to HW*/
+	if (dev->mei_host_buffer_is_empty &&
+		mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
+
+		dev->mei_host_buffer_is_empty = false;
+		dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
+
+		if (mei_wd_send(dev)) {
+			dev_err(&dev->pdev->dev, "wd: send failed.\n");
+			ret = -EIO;
+			goto end;
+		}
+
+		if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) {
+			dev_err(&dev->pdev->dev,
+				"wd: mei_flow_ctrl_reduce() failed.\n");
+			ret = -EIO;
+			goto end;
+		}
+
+	} else {
+		dev->wd_pending = true;
+	}
+
+end:
+	mutex_unlock(&dev->device_lock);
+	return ret;
+}
+
+/*
+ * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ * @timeout - timeout value to set
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
+{
+	struct mei_device *dev;
+	dev = pci_get_drvdata(mei_device);
+
+	if (!dev)
+		return -ENODEV;
+
+	/* Check Timeout value */
+	if (timeout < AMT_WD_MIN_TIMEOUT || timeout > AMT_WD_MAX_TIMEOUT)
+		return -EINVAL;
+
+	mutex_lock(&dev->device_lock);
+
+	dev->wd_timeout = timeout;
+	wd_dev->timeout = timeout;
+	mei_wd_set_start_timeout(dev, dev->wd_timeout);
+
+	mutex_unlock(&dev->device_lock);
+
+	return 0;
+}
+
+/*
+ * Watchdog Device structs
+ */
+static const struct watchdog_ops wd_ops = {
+		.owner = THIS_MODULE,
+		.start = mei_wd_ops_start,
+		.stop = mei_wd_ops_stop,
+		.ping = mei_wd_ops_ping,
+		.set_timeout = mei_wd_ops_set_timeout,
+};
+static const struct watchdog_info wd_info = {
+		.identity = INTEL_AMT_WATCHDOG_ID,
+		.options = WDIOF_KEEPALIVEPING,
+};
+
+static struct watchdog_device amt_wd_dev = {
+		.info = &wd_info,
+		.ops = &wd_ops,
+		.timeout = AMT_WD_DEFAULT_TIMEOUT,
+		.min_timeout = AMT_WD_MIN_TIMEOUT,
+		.max_timeout = AMT_WD_MAX_TIMEOUT,
+};
+
+
+void  mei_watchdog_register(struct mei_device *dev)
+{
+	dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", dev->wd_timeout);
+
+	dev->wd_due_counter = !!dev->wd_timeout;
+
+	if (watchdog_register_device(&amt_wd_dev)) {
+		dev_err(&dev->pdev->dev,
+			"wd: unable to register watchdog device.\n");
+		dev->wd_interface_reg = false;
+	} else {
+		dev_dbg(&dev->pdev->dev,
+			"wd: successfully register watchdog interface.\n");
+		dev->wd_interface_reg = true;
+	}
+}
+
+void mei_watchdog_unregister(struct mei_device *dev)
+{
+	if (dev->wd_interface_reg)
+		watchdog_unregister_device(&amt_wd_dev);
+	dev->wd_interface_reg = false;
+}
+
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index 10fc478..9fbcacd 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -65,10 +65,6 @@
 #define PCI_VENDOR_ID_ROHM			0x10db
 #define PCI_DEVICE_ID_ROHM_ML7213_PHUB		0x801A
 
-/* Macros for ML7213 */
-#define PCI_VENDOR_ID_ROHM			0x10db
-#define PCI_DEVICE_ID_ROHM_ML7213_PHUB		0x801A
-
 /* Macros for ML7223 */
 #define PCI_DEVICE_ID_ROHM_ML7223_mPHUB	0x8012 /* for Bus-m */
 #define PCI_DEVICE_ID_ROHM_ML7223_nPHUB	0x8002 /* for Bus-n */
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 383133b..b7eb545 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -888,7 +888,7 @@
 	.name		= PCINAME,
 	.id_table	= pci_ids,
 	.probe		= pti_pci_probe,
-	.remove		= pti_pci_remove,
+	.remove		= __devexit_p(pti_pci_remove),
 };
 
 /**
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index e3f5af9..bb03ddd 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -39,6 +39,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
 #include <linux/fsl/mxs-dma.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <mach/mxs.h>
 #include <mach/common.h>
@@ -682,6 +683,7 @@
 	struct mmc_host *mmc;
 	struct resource *iores, *dmares, *r;
 	struct mxs_mmc_platform_data *pdata;
+	struct pinctrl *pinctrl;
 	int ret = 0, irq_err, irq_dma;
 	dma_cap_mask_t mask;
 
@@ -719,6 +721,12 @@
 	host->irq = irq_err;
 	host->sdio_irq_en = 0;
 
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		goto out_iounmap;
+	}
+
 	host->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(host->clk)) {
 		ret = PTR_ERR(host->clk);
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 8abdaf6..d190d04 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
 #include <mach/esdhc.h>
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
@@ -68,6 +69,7 @@
 	int flags;
 	u32 scratchpad;
 	enum imx_esdhc_type devtype;
+	struct pinctrl *pinctrl;
 	struct esdhc_platform_data boarddata;
 };
 
@@ -467,6 +469,12 @@
 	clk_prepare_enable(clk);
 	pltfm_host->clk = clk;
 
+	imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(imx_data->pinctrl)) {
+		err = PTR_ERR(imx_data->pinctrl);
+		goto pin_err;
+	}
+
 	host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 
 	if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
@@ -558,6 +566,7 @@
 		gpio_free(boarddata->wp_gpio);
 no_card_detect_pin:
 no_board_data:
+pin_err:
 	clk_disable_unprepare(pltfm_host->clk);
 	clk_put(pltfm_host->clk);
 err_clk_get:
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 53b2650..ff5a169 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -269,7 +269,6 @@
 				"failed to allocate power gpio\n");
 			goto err_power_req;
 		}
-		tegra_gpio_enable(plat->power_gpio);
 		gpio_direction_output(plat->power_gpio, 1);
 	}
 
@@ -280,7 +279,6 @@
 				"failed to allocate cd gpio\n");
 			goto err_cd_req;
 		}
-		tegra_gpio_enable(plat->cd_gpio);
 		gpio_direction_input(plat->cd_gpio);
 
 		rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq,
@@ -301,7 +299,6 @@
 				"failed to allocate wp gpio\n");
 			goto err_wp_req;
 		}
-		tegra_gpio_enable(plat->wp_gpio);
 		gpio_direction_input(plat->wp_gpio);
 	}
 
@@ -329,23 +326,17 @@
 	clk_disable(pltfm_host->clk);
 	clk_put(pltfm_host->clk);
 err_clk_get:
-	if (gpio_is_valid(plat->wp_gpio)) {
-		tegra_gpio_disable(plat->wp_gpio);
+	if (gpio_is_valid(plat->wp_gpio))
 		gpio_free(plat->wp_gpio);
-	}
 err_wp_req:
 	if (gpio_is_valid(plat->cd_gpio))
 		free_irq(gpio_to_irq(plat->cd_gpio), host);
 err_cd_irq_req:
-	if (gpio_is_valid(plat->cd_gpio)) {
-		tegra_gpio_disable(plat->cd_gpio);
+	if (gpio_is_valid(plat->cd_gpio))
 		gpio_free(plat->cd_gpio);
-	}
 err_cd_req:
-	if (gpio_is_valid(plat->power_gpio)) {
-		tegra_gpio_disable(plat->power_gpio);
+	if (gpio_is_valid(plat->power_gpio))
 		gpio_free(plat->power_gpio);
-	}
 err_power_req:
 err_no_plat:
 	sdhci_pltfm_free(pdev);
@@ -362,21 +353,16 @@
 
 	sdhci_remove_host(host, dead);
 
-	if (gpio_is_valid(plat->wp_gpio)) {
-		tegra_gpio_disable(plat->wp_gpio);
+	if (gpio_is_valid(plat->wp_gpio))
 		gpio_free(plat->wp_gpio);
-	}
 
 	if (gpio_is_valid(plat->cd_gpio)) {
 		free_irq(gpio_to_irq(plat->cd_gpio), host);
-		tegra_gpio_disable(plat->cd_gpio);
 		gpio_free(plat->cd_gpio);
 	}
 
-	if (gpio_is_valid(plat->power_gpio)) {
-		tegra_gpio_disable(plat->power_gpio);
+	if (gpio_is_valid(plat->power_gpio))
 		gpio_free(plat->power_gpio);
-	}
 
 	clk_disable(pltfm_host->clk);
 	clk_put(pltfm_host->clk);
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 8272c02..50aa90a 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -383,7 +383,7 @@
  * leveling counters are stored.  To access this last area of 4 bytes, a special
  * mode must be input to the flash ASIC.
  *
- * Returns 0 if no error occured, -EIO else.
+ * Returns 0 if no error occurred, -EIO else.
  */
 static int doc_set_extra_page_mode(struct docg3 *docg3)
 {
@@ -681,7 +681,7 @@
  *  - one read of 512 bytes at offset 0
  *  - one read of 512 bytes at offset 512 + 16
  *
- * Returns 0 if successful, -EIO if a read error occured.
+ * Returns 0 if successful, -EIO if a read error occurred.
  */
 static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1,
 				 int page, int offset)
@@ -839,7 +839,7 @@
  *
  * Reads flash memory OOB area of pages.
  *
- * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured
+ * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred
  */
 static int doc_read_oob(struct mtd_info *mtd, loff_t from,
 			struct mtd_oob_ops *ops)
@@ -971,7 +971,7 @@
  * Reads flash memory pages. This function does not read the OOB chunk, but only
  * the page data.
  *
- * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured
+ * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred
  */
 static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
 	     size_t *retlen, u_char *buf)
@@ -1109,7 +1109,7 @@
  * Wait for the chip to be ready again after erase or write operation, and check
  * erase/write status.
  *
- * Returns 0 if erase successfull, -EIO if erase/write issue, -ETIMEOUT if
+ * Returns 0 if erase successful, -EIO if erase/write issue, -ETIMEOUT if
  * timeout
  */
 static int doc_write_erase_wait_status(struct docg3 *docg3)
@@ -1186,7 +1186,7 @@
  * Erase a bunch of contiguous blocks, by pairs, as a "mtd" page of 1024 is
  * split into 2 pages of 512 bytes on 2 contiguous blocks.
  *
- * Returns 0 if erase successful, -EINVAL if adressing error, -EIO if erase
+ * Returns 0 if erase successful, -EINVAL if addressing error, -EIO if erase
  * issue
  */
 static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
@@ -1397,7 +1397,7 @@
  * Or provide data without OOB, and then a all zeroed OOB will be used (ECC will
  * still be filled in if asked for).
  *
- * Returns 0 is successfull, EINVAL if length is not 14 bytes
+ * Returns 0 is successful, EINVAL if length is not 14 bytes
  */
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
 			 struct mtd_oob_ops *ops)
@@ -1945,7 +1945,7 @@
  * docg3_resume - Awakens docg3 floor
  * @pdev: platfrom device
  *
- * Returns 0 (always successfull)
+ * Returns 0 (always successful)
  */
 static int docg3_resume(struct platform_device *pdev)
 {
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c
index 2e42ec2..04769a4 100644
--- a/drivers/mtd/nand/autcpu12.c
+++ b/drivers/mtd/nand/autcpu12.c
@@ -102,10 +102,10 @@
 		void __iomem *addr;
 		unsigned char bits;
 
-		addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
-		bits = (ctrl & NAND_CLE) << 4;
+		bits = clps_readb(AUTCPU12_SMC_PORT_OFFSET) & ~0x30;
+		bits |= (ctrl & NAND_CLE) << 4;
 		bits |= (ctrl & NAND_ALE) << 2;
-		writeb((readb(addr) & ~0x30) | bits, addr);
+		clps_writeb(bits, AUTCPU12_SMC_PORT_OFFSET);
 
 		addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET;
 		writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr);
@@ -120,9 +120,7 @@
  */
 int autcpu12_device_ready(struct mtd_info *mtd)
 {
-	void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
-
-	return readb(addr) & AUTCPU12_SMC_RDY;
+	return clps_readb(AUTCPU12_SMC_PORT_OFFSET) & AUTCPU12_SMC_RDY;
 }
 
 /*
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 9ec51ce..b68e043 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/mtd/gpmi-nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/pinctrl/consumer.h>
 #include "gpmi-nand.h"
 
 /* add our owner bbt descriptor */
@@ -476,6 +477,7 @@
 static int __devinit acquire_resources(struct gpmi_nand_data *this)
 {
 	struct resources *res = &this->resources;
+	struct pinctrl *pinctrl;
 	int ret;
 
 	ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
@@ -494,6 +496,12 @@
 	if (ret)
 		goto exit_dma_channels;
 
+	pinctrl = devm_pinctrl_get_select_default(&this->pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		goto exit_pin;
+	}
+
 	res->clock = clk_get(&this->pdev->dev, NULL);
 	if (IS_ERR(res->clock)) {
 		pr_err("can not get the clock\n");
@@ -503,6 +511,7 @@
 	return 0;
 
 exit_clock:
+exit_pin:
 	release_dma_channels(this);
 exit_dma_channels:
 	release_bch_irq(this);
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c
index 11e4878..9bf5ce5 100644
--- a/drivers/mtd/nand/h1910.c
+++ b/drivers/mtd/nand/h1910.c
@@ -24,7 +24,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <asm/io.h>
-#include <mach/hardware.h>	/* for CLPS7111_VIRT_BASE */
+#include <mach/hardware.h>
 #include <asm/sizes.h>
 #include <mach/h1900-gpio.h>
 #include <mach/ipaq.h>
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 1d3bfb2..0f50ef3 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -74,11 +75,13 @@
 static int __init orion_nand_probe(struct platform_device *pdev)
 {
 	struct mtd_info *mtd;
+	struct mtd_part_parser_data ppdata = {};
 	struct nand_chip *nc;
 	struct orion_nand_data *board;
 	struct resource *res;
 	void __iomem *io_base;
 	int ret = 0;
+	u32 val = 0;
 
 	nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
 	if (!nc) {
@@ -101,7 +104,32 @@
 		goto no_res;
 	}
 
-	board = pdev->dev.platform_data;
+	if (pdev->dev.of_node) {
+		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
+					GFP_KERNEL);
+		if (!board) {
+			printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
+			ret = -ENOMEM;
+			goto no_res;
+		}
+		if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
+			board->cle = (u8)val;
+		else
+			board->cle = 0;
+		if (!of_property_read_u32(pdev->dev.of_node, "ale", &val))
+			board->ale = (u8)val;
+		else
+			board->ale = 1;
+		if (!of_property_read_u32(pdev->dev.of_node,
+						"bank-width", &val))
+			board->width = (u8)val * 8;
+		else
+			board->width = 8;
+		if (!of_property_read_u32(pdev->dev.of_node,
+						"chip-delay", &val))
+			board->chip_delay = (u8)val;
+	} else
+		board = pdev->dev.platform_data;
 
 	mtd->priv = nc;
 	mtd->owner = THIS_MODULE;
@@ -115,6 +143,10 @@
 	if (board->chip_delay)
 		nc->chip_delay = board->chip_delay;
 
+	WARN(board->width > 16,
+		"%d bit bus width out of range",
+		board->width);
+
 	if (board->width == 16)
 		nc->options |= NAND_BUSWIDTH_16;
 
@@ -129,8 +161,9 @@
 	}
 
 	mtd->name = "orion_nand";
-	ret = mtd_device_parse_register(mtd, NULL, NULL, board->parts,
-					board->nr_parts);
+	ppdata.of_node = pdev->dev.of_node;
+	ret = mtd_device_parse_register(mtd, NULL, &ppdata,
+			board->parts, board->nr_parts);
 	if (ret) {
 		nand_release(mtd);
 		goto no_dev;
@@ -161,11 +194,19 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id orion_nand_of_match_table[] = {
+	{ .compatible = "mrvl,orion-nand", },
+	{},
+};
+#endif
+
 static struct platform_driver orion_nand_driver = {
 	.remove		= __devexit_p(orion_nand_remove),
 	.driver		= {
 		.name	= "orion_nand",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(orion_nand_of_match_table),
 	},
 };
 
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 4dcc752..738ee8d 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -52,12 +52,4 @@
 	   work on top of UBI. Do not enable this unless you use legacy
 	   software.
 
-config MTD_UBI_DEBUG
-	bool "UBI debugging"
-	depends on SYSFS
-	select DEBUG_FS
-	select KALLSYMS
-	help
-	  This option enables UBI debugging.
-
 endif # MTD_UBI
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
index c9302a5..a0803ac 100644
--- a/drivers/mtd/ubi/Makefile
+++ b/drivers/mtd/ubi/Makefile
@@ -1,7 +1,6 @@
 obj-$(CONFIG_MTD_UBI) += ubi.o
 
-ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o
-ubi-y += misc.o
+ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o attach.o
+ubi-y += misc.o debug.o
 
-ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o
 obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
new file mode 100644
index 0000000..bd27cbb
--- /dev/null
+++ b/drivers/mtd/ubi/attach.c
@@ -0,0 +1,1631 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * UBI attaching sub-system.
+ *
+ * This sub-system is responsible for attaching MTD devices and it also
+ * implements flash media scanning.
+ *
+ * The attaching information is represented by a &struct ubi_attach_info'
+ * object. Information about volumes is represented by &struct ubi_ainf_volume
+ * objects which are kept in volume RB-tree with root at the @volumes field.
+ * The RB-tree is indexed by the volume ID.
+ *
+ * Logical eraseblocks are represented by &struct ubi_ainf_peb objects. These
+ * objects are kept in per-volume RB-trees with the root at the corresponding
+ * &struct ubi_ainf_volume object. To put it differently, we keep an RB-tree of
+ * per-volume objects and each of these objects is the root of RB-tree of
+ * per-LEB objects.
+ *
+ * Corrupted physical eraseblocks are put to the @corr list, free physical
+ * eraseblocks are put to the @free list and the physical eraseblock to be
+ * erased are put to the @erase list.
+ *
+ * About corruptions
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * UBI protects EC and VID headers with CRC-32 checksums, so it can detect
+ * whether the headers are corrupted or not. Sometimes UBI also protects the
+ * data with CRC-32, e.g., when it executes the atomic LEB change operation, or
+ * when it moves the contents of a PEB for wear-leveling purposes.
+ *
+ * UBI tries to distinguish between 2 types of corruptions.
+ *
+ * 1. Corruptions caused by power cuts. These are expected corruptions and UBI
+ * tries to handle them gracefully, without printing too many warnings and
+ * error messages. The idea is that we do not lose important data in these
+ * cases - we may lose only the data which were being written to the media just
+ * before the power cut happened, and the upper layers (e.g., UBIFS) are
+ * supposed to handle such data losses (e.g., by using the FS journal).
+ *
+ * When UBI detects a corruption (CRC-32 mismatch) in a PEB, and it looks like
+ * the reason is a power cut, UBI puts this PEB to the @erase list, and all
+ * PEBs in the @erase list are scheduled for erasure later.
+ *
+ * 2. Unexpected corruptions which are not caused by power cuts. During
+ * attaching, such PEBs are put to the @corr list and UBI preserves them.
+ * Obviously, this lessens the amount of available PEBs, and if at some  point
+ * UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly informs
+ * about such PEBs every time the MTD device is attached.
+ *
+ * However, it is difficult to reliably distinguish between these types of
+ * corruptions and UBI's strategy is as follows (in case of attaching by
+ * scanning). UBI assumes corruption type 2 if the VID header is corrupted and
+ * the data area does not contain all 0xFFs, and there were no bit-flips or
+ * integrity errors (e.g., ECC errors in case of NAND) while reading the data
+ * area.  Otherwise UBI assumes corruption type 1. So the decision criteria
+ * are as follows.
+ *   o If the data area contains only 0xFFs, there are no data, and it is safe
+ *     to just erase this PEB - this is corruption type 1.
+ *   o If the data area has bit-flips or data integrity errors (ECC errors on
+ *     NAND), it is probably a PEB which was being erased when power cut
+ *     happened, so this is corruption type 1. However, this is just a guess,
+ *     which might be wrong.
+ *   o Otherwise this it corruption type 2.
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include <linux/math64.h>
+#include <linux/random.h>
+#include "ubi.h"
+
+static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai);
+
+/* Temporary variables used during scanning */
+static struct ubi_ec_hdr *ech;
+static struct ubi_vid_hdr *vidh;
+
+/**
+ * add_to_list - add physical eraseblock to a list.
+ * @ai: attaching information
+ * @pnum: physical eraseblock number to add
+ * @vol_id: the last used volume id for the PEB
+ * @lnum: the last used LEB number for the PEB
+ * @ec: erase counter of the physical eraseblock
+ * @to_head: if not zero, add to the head of the list
+ * @list: the list to add to
+ *
+ * This function allocates a 'struct ubi_ainf_peb' object for physical
+ * eraseblock @pnum and adds it to the "free", "erase", or "alien" lists.
+ * It stores the @lnum and @vol_id alongside, which can both be
+ * %UBI_UNKNOWN if they are not available, not readable, or not assigned.
+ * If @to_head is not zero, PEB will be added to the head of the list, which
+ * basically means it will be processed first later. E.g., we add corrupted
+ * PEBs (corrupted due to power cuts) to the head of the erase list to make
+ * sure we erase them first and get rid of corruptions ASAP. This function
+ * returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int add_to_list(struct ubi_attach_info *ai, int pnum, int vol_id,
+		       int lnum, int ec, int to_head, struct list_head *list)
+{
+	struct ubi_ainf_peb *aeb;
+
+	if (list == &ai->free) {
+		dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
+	} else if (list == &ai->erase) {
+		dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
+	} else if (list == &ai->alien) {
+		dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
+		ai->alien_peb_count += 1;
+	} else
+		BUG();
+
+	aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+	if (!aeb)
+		return -ENOMEM;
+
+	aeb->pnum = pnum;
+	aeb->vol_id = vol_id;
+	aeb->lnum = lnum;
+	aeb->ec = ec;
+	if (to_head)
+		list_add(&aeb->u.list, list);
+	else
+		list_add_tail(&aeb->u.list, list);
+	return 0;
+}
+
+/**
+ * add_corrupted - add a corrupted physical eraseblock.
+ * @ai: attaching information
+ * @pnum: physical eraseblock number to add
+ * @ec: erase counter of the physical eraseblock
+ *
+ * This function allocates a 'struct ubi_ainf_peb' object for a corrupted
+ * physical eraseblock @pnum and adds it to the 'corr' list.  The corruption
+ * was presumably not caused by a power cut. Returns zero in case of success
+ * and a negative error code in case of failure.
+ */
+static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
+{
+	struct ubi_ainf_peb *aeb;
+
+	dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
+
+	aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+	if (!aeb)
+		return -ENOMEM;
+
+	ai->corr_peb_count += 1;
+	aeb->pnum = pnum;
+	aeb->ec = ec;
+	list_add(&aeb->u.list, &ai->corr);
+	return 0;
+}
+
+/**
+ * validate_vid_hdr - check volume identifier header.
+ * @vid_hdr: the volume identifier header to check
+ * @av: information about the volume this logical eraseblock belongs to
+ * @pnum: physical eraseblock number the VID header came from
+ *
+ * This function checks that data stored in @vid_hdr is consistent. Returns
+ * non-zero if an inconsistency was found and zero if not.
+ *
+ * Note, UBI does sanity check of everything it reads from the flash media.
+ * Most of the checks are done in the I/O sub-system. Here we check that the
+ * information in the VID header is consistent to the information in other VID
+ * headers of the same volume.
+ */
+static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
+			    const struct ubi_ainf_volume *av, int pnum)
+{
+	int vol_type = vid_hdr->vol_type;
+	int vol_id = be32_to_cpu(vid_hdr->vol_id);
+	int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+	int data_pad = be32_to_cpu(vid_hdr->data_pad);
+
+	if (av->leb_count != 0) {
+		int av_vol_type;
+
+		/*
+		 * This is not the first logical eraseblock belonging to this
+		 * volume. Ensure that the data in its VID header is consistent
+		 * to the data in previous logical eraseblock headers.
+		 */
+
+		if (vol_id != av->vol_id) {
+			ubi_err("inconsistent vol_id");
+			goto bad;
+		}
+
+		if (av->vol_type == UBI_STATIC_VOLUME)
+			av_vol_type = UBI_VID_STATIC;
+		else
+			av_vol_type = UBI_VID_DYNAMIC;
+
+		if (vol_type != av_vol_type) {
+			ubi_err("inconsistent vol_type");
+			goto bad;
+		}
+
+		if (used_ebs != av->used_ebs) {
+			ubi_err("inconsistent used_ebs");
+			goto bad;
+		}
+
+		if (data_pad != av->data_pad) {
+			ubi_err("inconsistent data_pad");
+			goto bad;
+		}
+	}
+
+	return 0;
+
+bad:
+	ubi_err("inconsistent VID header at PEB %d", pnum);
+	ubi_dump_vid_hdr(vid_hdr);
+	ubi_dump_av(av);
+	return -EINVAL;
+}
+
+/**
+ * add_volume - add volume to the attaching information.
+ * @ai: attaching information
+ * @vol_id: ID of the volume to add
+ * @pnum: physical eraseblock number
+ * @vid_hdr: volume identifier header
+ *
+ * If the volume corresponding to the @vid_hdr logical eraseblock is already
+ * present in the attaching information, this function does nothing. Otherwise
+ * it adds corresponding volume to the attaching information. Returns a pointer
+ * to the allocated "av" object in case of success and a negative error code in
+ * case of failure.
+ */
+static struct ubi_ainf_volume *add_volume(struct ubi_attach_info *ai,
+					  int vol_id, int pnum,
+					  const struct ubi_vid_hdr *vid_hdr)
+{
+	struct ubi_ainf_volume *av;
+	struct rb_node **p = &ai->volumes.rb_node, *parent = NULL;
+
+	ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
+
+	/* Walk the volume RB-tree to look if this volume is already present */
+	while (*p) {
+		parent = *p;
+		av = rb_entry(parent, struct ubi_ainf_volume, rb);
+
+		if (vol_id == av->vol_id)
+			return av;
+
+		if (vol_id > av->vol_id)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+
+	/* The volume is absent - add it */
+	av = kmalloc(sizeof(struct ubi_ainf_volume), GFP_KERNEL);
+	if (!av)
+		return ERR_PTR(-ENOMEM);
+
+	av->highest_lnum = av->leb_count = 0;
+	av->vol_id = vol_id;
+	av->root = RB_ROOT;
+	av->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+	av->data_pad = be32_to_cpu(vid_hdr->data_pad);
+	av->compat = vid_hdr->compat;
+	av->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
+							    : UBI_STATIC_VOLUME;
+	if (vol_id > ai->highest_vol_id)
+		ai->highest_vol_id = vol_id;
+
+	rb_link_node(&av->rb, parent, p);
+	rb_insert_color(&av->rb, &ai->volumes);
+	ai->vols_found += 1;
+	dbg_bld("added volume %d", vol_id);
+	return av;
+}
+
+/**
+ * compare_lebs - find out which logical eraseblock is newer.
+ * @ubi: UBI device description object
+ * @aeb: first logical eraseblock to compare
+ * @pnum: physical eraseblock number of the second logical eraseblock to
+ * compare
+ * @vid_hdr: volume identifier header of the second logical eraseblock
+ *
+ * This function compares 2 copies of a LEB and informs which one is newer. In
+ * case of success this function returns a positive value, in case of failure, a
+ * negative error code is returned. The success return codes use the following
+ * bits:
+ *     o bit 0 is cleared: the first PEB (described by @aeb) is newer than the
+ *       second PEB (described by @pnum and @vid_hdr);
+ *     o bit 0 is set: the second PEB is newer;
+ *     o bit 1 is cleared: no bit-flips were detected in the newer LEB;
+ *     o bit 1 is set: bit-flips were detected in the newer LEB;
+ *     o bit 2 is cleared: the older LEB is not corrupted;
+ *     o bit 2 is set: the older LEB is corrupted.
+ */
+static int compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
+			int pnum, const struct ubi_vid_hdr *vid_hdr)
+{
+	void *buf;
+	int len, err, second_is_newer, bitflips = 0, corrupted = 0;
+	uint32_t data_crc, crc;
+	struct ubi_vid_hdr *vh = NULL;
+	unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
+
+	if (sqnum2 == aeb->sqnum) {
+		/*
+		 * This must be a really ancient UBI image which has been
+		 * created before sequence numbers support has been added. At
+		 * that times we used 32-bit LEB versions stored in logical
+		 * eraseblocks. That was before UBI got into mainline. We do not
+		 * support these images anymore. Well, those images still work,
+		 * but only if no unclean reboots happened.
+		 */
+		ubi_err("unsupported on-flash UBI format\n");
+		return -EINVAL;
+	}
+
+	/* Obviously the LEB with lower sequence counter is older */
+	second_is_newer = (sqnum2 > aeb->sqnum);
+
+	/*
+	 * Now we know which copy is newer. If the copy flag of the PEB with
+	 * newer version is not set, then we just return, otherwise we have to
+	 * check data CRC. For the second PEB we already have the VID header,
+	 * for the first one - we'll need to re-read it from flash.
+	 *
+	 * Note: this may be optimized so that we wouldn't read twice.
+	 */
+
+	if (second_is_newer) {
+		if (!vid_hdr->copy_flag) {
+			/* It is not a copy, so it is newer */
+			dbg_bld("second PEB %d is newer, copy_flag is unset",
+				pnum);
+			return 1;
+		}
+	} else {
+		if (!aeb->copy_flag) {
+			/* It is not a copy, so it is newer */
+			dbg_bld("first PEB %d is newer, copy_flag is unset",
+				pnum);
+			return bitflips << 1;
+		}
+
+		vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
+		if (!vh)
+			return -ENOMEM;
+
+		pnum = aeb->pnum;
+		err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
+		if (err) {
+			if (err == UBI_IO_BITFLIPS)
+				bitflips = 1;
+			else {
+				ubi_err("VID of PEB %d header is bad, but it "
+					"was OK earlier, err %d", pnum, err);
+				if (err > 0)
+					err = -EIO;
+
+				goto out_free_vidh;
+			}
+		}
+
+		vid_hdr = vh;
+	}
+
+	/* Read the data of the copy and check the CRC */
+
+	len = be32_to_cpu(vid_hdr->data_size);
+	buf = vmalloc(len);
+	if (!buf) {
+		err = -ENOMEM;
+		goto out_free_vidh;
+	}
+
+	err = ubi_io_read_data(ubi, buf, pnum, 0, len);
+	if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
+		goto out_free_buf;
+
+	data_crc = be32_to_cpu(vid_hdr->data_crc);
+	crc = crc32(UBI_CRC32_INIT, buf, len);
+	if (crc != data_crc) {
+		dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
+			pnum, crc, data_crc);
+		corrupted = 1;
+		bitflips = 0;
+		second_is_newer = !second_is_newer;
+	} else {
+		dbg_bld("PEB %d CRC is OK", pnum);
+		bitflips = !!err;
+	}
+
+	vfree(buf);
+	ubi_free_vid_hdr(ubi, vh);
+
+	if (second_is_newer)
+		dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
+	else
+		dbg_bld("first PEB %d is newer, copy_flag is set", pnum);
+
+	return second_is_newer | (bitflips << 1) | (corrupted << 2);
+
+out_free_buf:
+	vfree(buf);
+out_free_vidh:
+	ubi_free_vid_hdr(ubi, vh);
+	return err;
+}
+
+/**
+ * ubi_add_to_av - add used physical eraseblock to the attaching information.
+ * @ubi: UBI device description object
+ * @ai: attaching information
+ * @pnum: the physical eraseblock number
+ * @ec: erase counter
+ * @vid_hdr: the volume identifier header
+ * @bitflips: if bit-flips were detected when this physical eraseblock was read
+ *
+ * This function adds information about a used physical eraseblock to the
+ * 'used' tree of the corresponding volume. The function is rather complex
+ * because it has to handle cases when this is not the first physical
+ * eraseblock belonging to the same logical eraseblock, and the newer one has
+ * to be picked, while the older one has to be dropped. This function returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
+		  int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips)
+{
+	int err, vol_id, lnum;
+	unsigned long long sqnum;
+	struct ubi_ainf_volume *av;
+	struct ubi_ainf_peb *aeb;
+	struct rb_node **p, *parent = NULL;
+
+	vol_id = be32_to_cpu(vid_hdr->vol_id);
+	lnum = be32_to_cpu(vid_hdr->lnum);
+	sqnum = be64_to_cpu(vid_hdr->sqnum);
+
+	dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, bitflips %d",
+		pnum, vol_id, lnum, ec, sqnum, bitflips);
+
+	av = add_volume(ai, vol_id, pnum, vid_hdr);
+	if (IS_ERR(av))
+		return PTR_ERR(av);
+
+	if (ai->max_sqnum < sqnum)
+		ai->max_sqnum = sqnum;
+
+	/*
+	 * Walk the RB-tree of logical eraseblocks of volume @vol_id to look
+	 * if this is the first instance of this logical eraseblock or not.
+	 */
+	p = &av->root.rb_node;
+	while (*p) {
+		int cmp_res;
+
+		parent = *p;
+		aeb = rb_entry(parent, struct ubi_ainf_peb, u.rb);
+		if (lnum != aeb->lnum) {
+			if (lnum < aeb->lnum)
+				p = &(*p)->rb_left;
+			else
+				p = &(*p)->rb_right;
+			continue;
+		}
+
+		/*
+		 * There is already a physical eraseblock describing the same
+		 * logical eraseblock present.
+		 */
+
+		dbg_bld("this LEB already exists: PEB %d, sqnum %llu, EC %d",
+			aeb->pnum, aeb->sqnum, aeb->ec);
+
+		/*
+		 * Make sure that the logical eraseblocks have different
+		 * sequence numbers. Otherwise the image is bad.
+		 *
+		 * However, if the sequence number is zero, we assume it must
+		 * be an ancient UBI image from the era when UBI did not have
+		 * sequence numbers. We still can attach these images, unless
+		 * there is a need to distinguish between old and new
+		 * eraseblocks, in which case we'll refuse the image in
+		 * 'compare_lebs()'. In other words, we attach old clean
+		 * images, but refuse attaching old images with duplicated
+		 * logical eraseblocks because there was an unclean reboot.
+		 */
+		if (aeb->sqnum == sqnum && sqnum != 0) {
+			ubi_err("two LEBs with same sequence number %llu",
+				sqnum);
+			ubi_dump_aeb(aeb, 0);
+			ubi_dump_vid_hdr(vid_hdr);
+			return -EINVAL;
+		}
+
+		/*
+		 * Now we have to drop the older one and preserve the newer
+		 * one.
+		 */
+		cmp_res = compare_lebs(ubi, aeb, pnum, vid_hdr);
+		if (cmp_res < 0)
+			return cmp_res;
+
+		if (cmp_res & 1) {
+			/*
+			 * This logical eraseblock is newer than the one
+			 * found earlier.
+			 */
+			err = validate_vid_hdr(vid_hdr, av, pnum);
+			if (err)
+				return err;
+
+			err = add_to_list(ai, aeb->pnum, aeb->vol_id,
+					  aeb->lnum, aeb->ec, cmp_res & 4,
+					  &ai->erase);
+			if (err)
+				return err;
+
+			aeb->ec = ec;
+			aeb->pnum = pnum;
+			aeb->vol_id = vol_id;
+			aeb->lnum = lnum;
+			aeb->scrub = ((cmp_res & 2) || bitflips);
+			aeb->copy_flag = vid_hdr->copy_flag;
+			aeb->sqnum = sqnum;
+
+			if (av->highest_lnum == lnum)
+				av->last_data_size =
+					be32_to_cpu(vid_hdr->data_size);
+
+			return 0;
+		} else {
+			/*
+			 * This logical eraseblock is older than the one found
+			 * previously.
+			 */
+			return add_to_list(ai, pnum, vol_id, lnum, ec,
+					   cmp_res & 4, &ai->erase);
+		}
+	}
+
+	/*
+	 * We've met this logical eraseblock for the first time, add it to the
+	 * attaching information.
+	 */
+
+	err = validate_vid_hdr(vid_hdr, av, pnum);
+	if (err)
+		return err;
+
+	aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+	if (!aeb)
+		return -ENOMEM;
+
+	aeb->ec = ec;
+	aeb->pnum = pnum;
+	aeb->vol_id = vol_id;
+	aeb->lnum = lnum;
+	aeb->scrub = bitflips;
+	aeb->copy_flag = vid_hdr->copy_flag;
+	aeb->sqnum = sqnum;
+
+	if (av->highest_lnum <= lnum) {
+		av->highest_lnum = lnum;
+		av->last_data_size = be32_to_cpu(vid_hdr->data_size);
+	}
+
+	av->leb_count += 1;
+	rb_link_node(&aeb->u.rb, parent, p);
+	rb_insert_color(&aeb->u.rb, &av->root);
+	return 0;
+}
+
+/**
+ * ubi_find_av - find volume in the attaching information.
+ * @ai: attaching information
+ * @vol_id: the requested volume ID
+ *
+ * This function returns a pointer to the volume description or %NULL if there
+ * are no data about this volume in the attaching information.
+ */
+struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai,
+				    int vol_id)
+{
+	struct ubi_ainf_volume *av;
+	struct rb_node *p = ai->volumes.rb_node;
+
+	while (p) {
+		av = rb_entry(p, struct ubi_ainf_volume, rb);
+
+		if (vol_id == av->vol_id)
+			return av;
+
+		if (vol_id > av->vol_id)
+			p = p->rb_left;
+		else
+			p = p->rb_right;
+	}
+
+	return NULL;
+}
+
+/**
+ * ubi_remove_av - delete attaching information about a volume.
+ * @ai: attaching information
+ * @av: the volume attaching information to delete
+ */
+void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
+{
+	struct rb_node *rb;
+	struct ubi_ainf_peb *aeb;
+
+	dbg_bld("remove attaching information about volume %d", av->vol_id);
+
+	while ((rb = rb_first(&av->root))) {
+		aeb = rb_entry(rb, struct ubi_ainf_peb, u.rb);
+		rb_erase(&aeb->u.rb, &av->root);
+		list_add_tail(&aeb->u.list, &ai->erase);
+	}
+
+	rb_erase(&av->rb, &ai->volumes);
+	kfree(av);
+	ai->vols_found -= 1;
+}
+
+/**
+ * early_erase_peb - erase a physical eraseblock.
+ * @ubi: UBI device description object
+ * @ai: attaching information
+ * @pnum: physical eraseblock number to erase;
+ * @ec: erase counter value to write (%UBI_UNKNOWN if it is unknown)
+ *
+ * This function erases physical eraseblock 'pnum', and writes the erase
+ * counter header to it. This function should only be used on UBI device
+ * initialization stages, when the EBA sub-system had not been yet initialized.
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int early_erase_peb(struct ubi_device *ubi,
+			   const struct ubi_attach_info *ai, int pnum, int ec)
+{
+	int err;
+	struct ubi_ec_hdr *ec_hdr;
+
+	if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
+		/*
+		 * Erase counter overflow. Upgrade UBI and use 64-bit
+		 * erase counters internally.
+		 */
+		ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec);
+		return -EINVAL;
+	}
+
+	ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+	if (!ec_hdr)
+		return -ENOMEM;
+
+	ec_hdr->ec = cpu_to_be64(ec);
+
+	err = ubi_io_sync_erase(ubi, pnum, 0);
+	if (err < 0)
+		goto out_free;
+
+	err = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr);
+
+out_free:
+	kfree(ec_hdr);
+	return err;
+}
+
+/**
+ * ubi_early_get_peb - get a free physical eraseblock.
+ * @ubi: UBI device description object
+ * @ai: attaching information
+ *
+ * This function returns a free physical eraseblock. It is supposed to be
+ * called on the UBI initialization stages when the wear-leveling sub-system is
+ * not initialized yet. This function picks a physical eraseblocks from one of
+ * the lists, writes the EC header if it is needed, and removes it from the
+ * list.
+ *
+ * This function returns a pointer to the "aeb" of the found free PEB in case
+ * of success and an error code in case of failure.
+ */
+struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
+				       struct ubi_attach_info *ai)
+{
+	int err = 0;
+	struct ubi_ainf_peb *aeb, *tmp_aeb;
+
+	if (!list_empty(&ai->free)) {
+		aeb = list_entry(ai->free.next, struct ubi_ainf_peb, u.list);
+		list_del(&aeb->u.list);
+		dbg_bld("return free PEB %d, EC %d", aeb->pnum, aeb->ec);
+		return aeb;
+	}
+
+	/*
+	 * We try to erase the first physical eraseblock from the erase list
+	 * and pick it if we succeed, or try to erase the next one if not. And
+	 * so forth. We don't want to take care about bad eraseblocks here -
+	 * they'll be handled later.
+	 */
+	list_for_each_entry_safe(aeb, tmp_aeb, &ai->erase, u.list) {
+		if (aeb->ec == UBI_UNKNOWN)
+			aeb->ec = ai->mean_ec;
+
+		err = early_erase_peb(ubi, ai, aeb->pnum, aeb->ec+1);
+		if (err)
+			continue;
+
+		aeb->ec += 1;
+		list_del(&aeb->u.list);
+		dbg_bld("return PEB %d, EC %d", aeb->pnum, aeb->ec);
+		return aeb;
+	}
+
+	ubi_err("no free eraseblocks");
+	return ERR_PTR(-ENOSPC);
+}
+
+/**
+ * check_corruption - check the data area of PEB.
+ * @ubi: UBI device description object
+ * @vid_hrd: the (corrupted) VID header of this PEB
+ * @pnum: the physical eraseblock number to check
+ *
+ * This is a helper function which is used to distinguish between VID header
+ * corruptions caused by power cuts and other reasons. If the PEB contains only
+ * 0xFF bytes in the data area, the VID header is most probably corrupted
+ * because of a power cut (%0 is returned in this case). Otherwise, it was
+ * probably corrupted for some other reasons (%1 is returned in this case). A
+ * negative error code is returned if a read error occurred.
+ *
+ * If the corruption reason was a power cut, UBI can safely erase this PEB.
+ * Otherwise, it should preserve it to avoid possibly destroying important
+ * information.
+ */
+static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
+			    int pnum)
+{
+	int err;
+
+	mutex_lock(&ubi->buf_mutex);
+	memset(ubi->peb_buf, 0x00, ubi->leb_size);
+
+	err = ubi_io_read(ubi, ubi->peb_buf, pnum, ubi->leb_start,
+			  ubi->leb_size);
+	if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
+		/*
+		 * Bit-flips or integrity errors while reading the data area.
+		 * It is difficult to say for sure what type of corruption is
+		 * this, but presumably a power cut happened while this PEB was
+		 * erased, so it became unstable and corrupted, and should be
+		 * erased.
+		 */
+		err = 0;
+		goto out_unlock;
+	}
+
+	if (err)
+		goto out_unlock;
+
+	if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size))
+		goto out_unlock;
+
+	ubi_err("PEB %d contains corrupted VID header, and the data does not "
+		"contain all 0xFF, this may be a non-UBI PEB or a severe VID "
+		"header corruption which requires manual inspection", pnum);
+	ubi_dump_vid_hdr(vid_hdr);
+	dbg_msg("hexdump of PEB %d offset %d, length %d",
+		pnum, ubi->leb_start, ubi->leb_size);
+	ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+			       ubi->peb_buf, ubi->leb_size, 1);
+	err = 1;
+
+out_unlock:
+	mutex_unlock(&ubi->buf_mutex);
+	return err;
+}
+
+/**
+ * scan_peb - scan and process UBI headers of a PEB.
+ * @ubi: UBI device description object
+ * @ai: attaching information
+ * @pnum: the physical eraseblock number
+ *
+ * This function reads UBI headers of PEB @pnum, checks them, and adds
+ * information about this PEB to the corresponding list or RB-tree in the
+ * "attaching info" structure. Returns zero if the physical eraseblock was
+ * successfully handled and a negative error code in case of failure.
+ */
+static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
+		    int pnum)
+{
+	long long uninitialized_var(ec);
+	int err, bitflips = 0, vol_id, ec_err = 0;
+
+	dbg_bld("scan PEB %d", pnum);
+
+	/* Skip bad physical eraseblocks */
+	err = ubi_io_is_bad(ubi, pnum);
+	if (err < 0)
+		return err;
+	else if (err) {
+		ai->bad_peb_count += 1;
+		return 0;
+	}
+
+	err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
+	if (err < 0)
+		return err;
+	switch (err) {
+	case 0:
+		break;
+	case UBI_IO_BITFLIPS:
+		bitflips = 1;
+		break;
+	case UBI_IO_FF:
+		ai->empty_peb_count += 1;
+		return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
+				   UBI_UNKNOWN, 0, &ai->erase);
+	case UBI_IO_FF_BITFLIPS:
+		ai->empty_peb_count += 1;
+		return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
+				   UBI_UNKNOWN, 1, &ai->erase);
+	case UBI_IO_BAD_HDR_EBADMSG:
+	case UBI_IO_BAD_HDR:
+		/*
+		 * We have to also look at the VID header, possibly it is not
+		 * corrupted. Set %bitflips flag in order to make this PEB be
+		 * moved and EC be re-created.
+		 */
+		ec_err = err;
+		ec = UBI_UNKNOWN;
+		bitflips = 1;
+		break;
+	default:
+		ubi_err("'ubi_io_read_ec_hdr()' returned unknown code %d", err);
+		return -EINVAL;
+	}
+
+	if (!ec_err) {
+		int image_seq;
+
+		/* Make sure UBI version is OK */
+		if (ech->version != UBI_VERSION) {
+			ubi_err("this UBI version is %d, image version is %d",
+				UBI_VERSION, (int)ech->version);
+			return -EINVAL;
+		}
+
+		ec = be64_to_cpu(ech->ec);
+		if (ec > UBI_MAX_ERASECOUNTER) {
+			/*
+			 * Erase counter overflow. The EC headers have 64 bits
+			 * reserved, but we anyway make use of only 31 bit
+			 * values, as this seems to be enough for any existing
+			 * flash. Upgrade UBI and use 64-bit erase counters
+			 * internally.
+			 */
+			ubi_err("erase counter overflow, max is %d",
+				UBI_MAX_ERASECOUNTER);
+			ubi_dump_ec_hdr(ech);
+			return -EINVAL;
+		}
+
+		/*
+		 * Make sure that all PEBs have the same image sequence number.
+		 * This allows us to detect situations when users flash UBI
+		 * images incorrectly, so that the flash has the new UBI image
+		 * and leftovers from the old one. This feature was added
+		 * relatively recently, and the sequence number was always
+		 * zero, because old UBI implementations always set it to zero.
+		 * For this reasons, we do not panic if some PEBs have zero
+		 * sequence number, while other PEBs have non-zero sequence
+		 * number.
+		 */
+		image_seq = be32_to_cpu(ech->image_seq);
+		if (!ubi->image_seq && image_seq)
+			ubi->image_seq = image_seq;
+		if (ubi->image_seq && image_seq &&
+		    ubi->image_seq != image_seq) {
+			ubi_err("bad image sequence number %d in PEB %d, "
+				"expected %d", image_seq, pnum, ubi->image_seq);
+			ubi_dump_ec_hdr(ech);
+			return -EINVAL;
+		}
+	}
+
+	/* OK, we've done with the EC header, let's look at the VID header */
+
+	err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);
+	if (err < 0)
+		return err;
+	switch (err) {
+	case 0:
+		break;
+	case UBI_IO_BITFLIPS:
+		bitflips = 1;
+		break;
+	case UBI_IO_BAD_HDR_EBADMSG:
+		if (ec_err == UBI_IO_BAD_HDR_EBADMSG)
+			/*
+			 * Both EC and VID headers are corrupted and were read
+			 * with data integrity error, probably this is a bad
+			 * PEB, bit it is not marked as bad yet. This may also
+			 * be a result of power cut during erasure.
+			 */
+			ai->maybe_bad_peb_count += 1;
+	case UBI_IO_BAD_HDR:
+		if (ec_err)
+			/*
+			 * Both headers are corrupted. There is a possibility
+			 * that this a valid UBI PEB which has corresponding
+			 * LEB, but the headers are corrupted. However, it is
+			 * impossible to distinguish it from a PEB which just
+			 * contains garbage because of a power cut during erase
+			 * operation. So we just schedule this PEB for erasure.
+			 *
+			 * Besides, in case of NOR flash, we deliberately
+			 * corrupt both headers because NOR flash erasure is
+			 * slow and can start from the end.
+			 */
+			err = 0;
+		else
+			/*
+			 * The EC was OK, but the VID header is corrupted. We
+			 * have to check what is in the data area.
+			 */
+			err = check_corruption(ubi, vidh, pnum);
+
+		if (err < 0)
+			return err;
+		else if (!err)
+			/* This corruption is caused by a power cut */
+			err = add_to_list(ai, pnum, UBI_UNKNOWN,
+					  UBI_UNKNOWN, ec, 1, &ai->erase);
+		else
+			/* This is an unexpected corruption */
+			err = add_corrupted(ai, pnum, ec);
+		if (err)
+			return err;
+		goto adjust_mean_ec;
+	case UBI_IO_FF_BITFLIPS:
+		err = add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
+				  ec, 1, &ai->erase);
+		if (err)
+			return err;
+		goto adjust_mean_ec;
+	case UBI_IO_FF:
+		if (ec_err)
+			err = add_to_list(ai, pnum, UBI_UNKNOWN,
+					  UBI_UNKNOWN, ec, 1, &ai->erase);
+		else
+			err = add_to_list(ai, pnum, UBI_UNKNOWN,
+					  UBI_UNKNOWN, ec, 0, &ai->free);
+		if (err)
+			return err;
+		goto adjust_mean_ec;
+	default:
+		ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d",
+			err);
+		return -EINVAL;
+	}
+
+	vol_id = be32_to_cpu(vidh->vol_id);
+	if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
+		int lnum = be32_to_cpu(vidh->lnum);
+
+		/* Unsupported internal volume */
+		switch (vidh->compat) {
+		case UBI_COMPAT_DELETE:
+			ubi_msg("\"delete\" compatible internal volume %d:%d"
+				" found, will remove it", vol_id, lnum);
+			err = add_to_list(ai, pnum, vol_id, lnum,
+					  ec, 1, &ai->erase);
+			if (err)
+				return err;
+			return 0;
+
+		case UBI_COMPAT_RO:
+			ubi_msg("read-only compatible internal volume %d:%d"
+				" found, switch to read-only mode",
+				vol_id, lnum);
+			ubi->ro_mode = 1;
+			break;
+
+		case UBI_COMPAT_PRESERVE:
+			ubi_msg("\"preserve\" compatible internal volume %d:%d"
+				" found", vol_id, lnum);
+			err = add_to_list(ai, pnum, vol_id, lnum,
+					  ec, 0, &ai->alien);
+			if (err)
+				return err;
+			return 0;
+
+		case UBI_COMPAT_REJECT:
+			ubi_err("incompatible internal volume %d:%d found",
+				vol_id, lnum);
+			return -EINVAL;
+		}
+	}
+
+	if (ec_err)
+		ubi_warn("valid VID header but corrupted EC header at PEB %d",
+			 pnum);
+	err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
+	if (err)
+		return err;
+
+adjust_mean_ec:
+	if (!ec_err) {
+		ai->ec_sum += ec;
+		ai->ec_count += 1;
+		if (ec > ai->max_ec)
+			ai->max_ec = ec;
+		if (ec < ai->min_ec)
+			ai->min_ec = ec;
+	}
+
+	return 0;
+}
+
+/**
+ * late_analysis - analyze the overall situation with PEB.
+ * @ubi: UBI device description object
+ * @ai: attaching information
+ *
+ * This is a helper function which takes a look what PEBs we have after we
+ * gather information about all of them ("ai" is compete). It decides whether
+ * the flash is empty and should be formatted of whether there are too many
+ * corrupted PEBs and we should not attach this MTD device. Returns zero if we
+ * should proceed with attaching the MTD device, and %-EINVAL if we should not.
+ */
+static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai)
+{
+	struct ubi_ainf_peb *aeb;
+	int max_corr, peb_count;
+
+	peb_count = ubi->peb_count - ai->bad_peb_count - ai->alien_peb_count;
+	max_corr = peb_count / 20 ?: 8;
+
+	/*
+	 * Few corrupted PEBs is not a problem and may be just a result of
+	 * unclean reboots. However, many of them may indicate some problems
+	 * with the flash HW or driver.
+	 */
+	if (ai->corr_peb_count) {
+		ubi_err("%d PEBs are corrupted and preserved",
+			ai->corr_peb_count);
+		printk(KERN_ERR "Corrupted PEBs are:");
+		list_for_each_entry(aeb, &ai->corr, u.list)
+			printk(KERN_CONT " %d", aeb->pnum);
+		printk(KERN_CONT "\n");
+
+		/*
+		 * If too many PEBs are corrupted, we refuse attaching,
+		 * otherwise, only print a warning.
+		 */
+		if (ai->corr_peb_count >= max_corr) {
+			ubi_err("too many corrupted PEBs, refusing");
+			return -EINVAL;
+		}
+	}
+
+	if (ai->empty_peb_count + ai->maybe_bad_peb_count == peb_count) {
+		/*
+		 * All PEBs are empty, or almost all - a couple PEBs look like
+		 * they may be bad PEBs which were not marked as bad yet.
+		 *
+		 * This piece of code basically tries to distinguish between
+		 * the following situations:
+		 *
+		 * 1. Flash is empty, but there are few bad PEBs, which are not
+		 *    marked as bad so far, and which were read with error. We
+		 *    want to go ahead and format this flash. While formatting,
+		 *    the faulty PEBs will probably be marked as bad.
+		 *
+		 * 2. Flash contains non-UBI data and we do not want to format
+		 *    it and destroy possibly important information.
+		 */
+		if (ai->maybe_bad_peb_count <= 2) {
+			ai->is_empty = 1;
+			ubi_msg("empty MTD device detected");
+			get_random_bytes(&ubi->image_seq,
+					 sizeof(ubi->image_seq));
+		} else {
+			ubi_err("MTD device is not UBI-formatted and possibly "
+				"contains non-UBI data - refusing it");
+			return -EINVAL;
+		}
+
+	}
+
+	return 0;
+}
+
+/**
+ * scan_all - scan entire MTD device.
+ * @ubi: UBI device description object
+ *
+ * This function does full scanning of an MTD device and returns complete
+ * information about it in form of a "struct ubi_attach_info" object. In case
+ * of failure, an error code is returned.
+ */
+static struct ubi_attach_info *scan_all(struct ubi_device *ubi)
+{
+	int err, pnum;
+	struct rb_node *rb1, *rb2;
+	struct ubi_ainf_volume *av;
+	struct ubi_ainf_peb *aeb;
+	struct ubi_attach_info *ai;
+
+	ai = kzalloc(sizeof(struct ubi_attach_info), GFP_KERNEL);
+	if (!ai)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&ai->corr);
+	INIT_LIST_HEAD(&ai->free);
+	INIT_LIST_HEAD(&ai->erase);
+	INIT_LIST_HEAD(&ai->alien);
+	ai->volumes = RB_ROOT;
+
+	err = -ENOMEM;
+	ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
+					       sizeof(struct ubi_ainf_peb),
+					       0, 0, NULL);
+	if (!ai->aeb_slab_cache)
+		goto out_ai;
+
+	ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+	if (!ech)
+		goto out_ai;
+
+	vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
+	if (!vidh)
+		goto out_ech;
+
+	for (pnum = 0; pnum < ubi->peb_count; pnum++) {
+		cond_resched();
+
+		dbg_gen("process PEB %d", pnum);
+		err = scan_peb(ubi, ai, pnum);
+		if (err < 0)
+			goto out_vidh;
+	}
+
+	dbg_msg("scanning is finished");
+
+	/* Calculate mean erase counter */
+	if (ai->ec_count)
+		ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count);
+
+	err = late_analysis(ubi, ai);
+	if (err)
+		goto out_vidh;
+
+	/*
+	 * In case of unknown erase counter we use the mean erase counter
+	 * value.
+	 */
+	ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+		ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
+			if (aeb->ec == UBI_UNKNOWN)
+				aeb->ec = ai->mean_ec;
+	}
+
+	list_for_each_entry(aeb, &ai->free, u.list) {
+		if (aeb->ec == UBI_UNKNOWN)
+			aeb->ec = ai->mean_ec;
+	}
+
+	list_for_each_entry(aeb, &ai->corr, u.list)
+		if (aeb->ec == UBI_UNKNOWN)
+			aeb->ec = ai->mean_ec;
+
+	list_for_each_entry(aeb, &ai->erase, u.list)
+		if (aeb->ec == UBI_UNKNOWN)
+			aeb->ec = ai->mean_ec;
+
+	err = self_check_ai(ubi, ai);
+	if (err)
+		goto out_vidh;
+
+	ubi_free_vid_hdr(ubi, vidh);
+	kfree(ech);
+
+	return ai;
+
+out_vidh:
+	ubi_free_vid_hdr(ubi, vidh);
+out_ech:
+	kfree(ech);
+out_ai:
+	ubi_destroy_ai(ai);
+	return ERR_PTR(err);
+}
+
+/**
+ * ubi_attach - attach an MTD device.
+ * @ubi: UBI device descriptor
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_attach(struct ubi_device *ubi)
+{
+	int err;
+	struct ubi_attach_info *ai;
+
+	ai = scan_all(ubi);
+	if (IS_ERR(ai))
+		return PTR_ERR(ai);
+
+	ubi->bad_peb_count = ai->bad_peb_count;
+	ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
+	ubi->corr_peb_count = ai->corr_peb_count;
+	ubi->max_ec = ai->max_ec;
+	ubi->mean_ec = ai->mean_ec;
+	ubi_msg("max. sequence number:       %llu", ai->max_sqnum);
+
+	err = ubi_read_volume_table(ubi, ai);
+	if (err)
+		goto out_ai;
+
+	err = ubi_wl_init(ubi, ai);
+	if (err)
+		goto out_vtbl;
+
+	err = ubi_eba_init(ubi, ai);
+	if (err)
+		goto out_wl;
+
+	ubi_destroy_ai(ai);
+	return 0;
+
+out_wl:
+	ubi_wl_close(ubi);
+out_vtbl:
+	ubi_free_internal_volumes(ubi);
+	vfree(ubi->vtbl);
+out_ai:
+	ubi_destroy_ai(ai);
+	return err;
+}
+
+/**
+ * destroy_av - free volume attaching information.
+ * @av: volume attaching information
+ * @ai: attaching information
+ *
+ * This function destroys the volume attaching information.
+ */
+static void destroy_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
+{
+	struct ubi_ainf_peb *aeb;
+	struct rb_node *this = av->root.rb_node;
+
+	while (this) {
+		if (this->rb_left)
+			this = this->rb_left;
+		else if (this->rb_right)
+			this = this->rb_right;
+		else {
+			aeb = rb_entry(this, struct ubi_ainf_peb, u.rb);
+			this = rb_parent(this);
+			if (this) {
+				if (this->rb_left == &aeb->u.rb)
+					this->rb_left = NULL;
+				else
+					this->rb_right = NULL;
+			}
+
+			kmem_cache_free(ai->aeb_slab_cache, aeb);
+		}
+	}
+	kfree(av);
+}
+
+/**
+ * ubi_destroy_ai - destroy attaching information.
+ * @ai: attaching information
+ */
+void ubi_destroy_ai(struct ubi_attach_info *ai)
+{
+	struct ubi_ainf_peb *aeb, *aeb_tmp;
+	struct ubi_ainf_volume *av;
+	struct rb_node *rb;
+
+	list_for_each_entry_safe(aeb, aeb_tmp, &ai->alien, u.list) {
+		list_del(&aeb->u.list);
+		kmem_cache_free(ai->aeb_slab_cache, aeb);
+	}
+	list_for_each_entry_safe(aeb, aeb_tmp, &ai->erase, u.list) {
+		list_del(&aeb->u.list);
+		kmem_cache_free(ai->aeb_slab_cache, aeb);
+	}
+	list_for_each_entry_safe(aeb, aeb_tmp, &ai->corr, u.list) {
+		list_del(&aeb->u.list);
+		kmem_cache_free(ai->aeb_slab_cache, aeb);
+	}
+	list_for_each_entry_safe(aeb, aeb_tmp, &ai->free, u.list) {
+		list_del(&aeb->u.list);
+		kmem_cache_free(ai->aeb_slab_cache, aeb);
+	}
+
+	/* Destroy the volume RB-tree */
+	rb = ai->volumes.rb_node;
+	while (rb) {
+		if (rb->rb_left)
+			rb = rb->rb_left;
+		else if (rb->rb_right)
+			rb = rb->rb_right;
+		else {
+			av = rb_entry(rb, struct ubi_ainf_volume, rb);
+
+			rb = rb_parent(rb);
+			if (rb) {
+				if (rb->rb_left == &av->rb)
+					rb->rb_left = NULL;
+				else
+					rb->rb_right = NULL;
+			}
+
+			destroy_av(ai, av);
+		}
+	}
+
+	if (ai->aeb_slab_cache)
+		kmem_cache_destroy(ai->aeb_slab_cache);
+
+	kfree(ai);
+}
+
+/**
+ * self_check_ai - check the attaching information.
+ * @ubi: UBI device description object
+ * @ai: attaching information
+ *
+ * This function returns zero if the attaching information is all right, and a
+ * negative error code if not or if an error occurred.
+ */
+static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
+{
+	int pnum, err, vols_found = 0;
+	struct rb_node *rb1, *rb2;
+	struct ubi_ainf_volume *av;
+	struct ubi_ainf_peb *aeb, *last_aeb;
+	uint8_t *buf;
+
+	if (!ubi->dbg->chk_gen)
+		return 0;
+
+	/*
+	 * At first, check that attaching information is OK.
+	 */
+	ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+		int leb_count = 0;
+
+		cond_resched();
+
+		vols_found += 1;
+
+		if (ai->is_empty) {
+			ubi_err("bad is_empty flag");
+			goto bad_av;
+		}
+
+		if (av->vol_id < 0 || av->highest_lnum < 0 ||
+		    av->leb_count < 0 || av->vol_type < 0 || av->used_ebs < 0 ||
+		    av->data_pad < 0 || av->last_data_size < 0) {
+			ubi_err("negative values");
+			goto bad_av;
+		}
+
+		if (av->vol_id >= UBI_MAX_VOLUMES &&
+		    av->vol_id < UBI_INTERNAL_VOL_START) {
+			ubi_err("bad vol_id");
+			goto bad_av;
+		}
+
+		if (av->vol_id > ai->highest_vol_id) {
+			ubi_err("highest_vol_id is %d, but vol_id %d is there",
+				ai->highest_vol_id, av->vol_id);
+			goto out;
+		}
+
+		if (av->vol_type != UBI_DYNAMIC_VOLUME &&
+		    av->vol_type != UBI_STATIC_VOLUME) {
+			ubi_err("bad vol_type");
+			goto bad_av;
+		}
+
+		if (av->data_pad > ubi->leb_size / 2) {
+			ubi_err("bad data_pad");
+			goto bad_av;
+		}
+
+		last_aeb = NULL;
+		ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
+			cond_resched();
+
+			last_aeb = aeb;
+			leb_count += 1;
+
+			if (aeb->pnum < 0 || aeb->ec < 0) {
+				ubi_err("negative values");
+				goto bad_aeb;
+			}
+
+			if (aeb->ec < ai->min_ec) {
+				ubi_err("bad ai->min_ec (%d), %d found",
+					ai->min_ec, aeb->ec);
+				goto bad_aeb;
+			}
+
+			if (aeb->ec > ai->max_ec) {
+				ubi_err("bad ai->max_ec (%d), %d found",
+					ai->max_ec, aeb->ec);
+				goto bad_aeb;
+			}
+
+			if (aeb->pnum >= ubi->peb_count) {
+				ubi_err("too high PEB number %d, total PEBs %d",
+					aeb->pnum, ubi->peb_count);
+				goto bad_aeb;
+			}
+
+			if (av->vol_type == UBI_STATIC_VOLUME) {
+				if (aeb->lnum >= av->used_ebs) {
+					ubi_err("bad lnum or used_ebs");
+					goto bad_aeb;
+				}
+			} else {
+				if (av->used_ebs != 0) {
+					ubi_err("non-zero used_ebs");
+					goto bad_aeb;
+				}
+			}
+
+			if (aeb->lnum > av->highest_lnum) {
+				ubi_err("incorrect highest_lnum or lnum");
+				goto bad_aeb;
+			}
+		}
+
+		if (av->leb_count != leb_count) {
+			ubi_err("bad leb_count, %d objects in the tree",
+				leb_count);
+			goto bad_av;
+		}
+
+		if (!last_aeb)
+			continue;
+
+		aeb = last_aeb;
+
+		if (aeb->lnum != av->highest_lnum) {
+			ubi_err("bad highest_lnum");
+			goto bad_aeb;
+		}
+	}
+
+	if (vols_found != ai->vols_found) {
+		ubi_err("bad ai->vols_found %d, should be %d",
+			ai->vols_found, vols_found);
+		goto out;
+	}
+
+	/* Check that attaching information is correct */
+	ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+		last_aeb = NULL;
+		ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
+			int vol_type;
+
+			cond_resched();
+
+			last_aeb = aeb;
+
+			err = ubi_io_read_vid_hdr(ubi, aeb->pnum, vidh, 1);
+			if (err && err != UBI_IO_BITFLIPS) {
+				ubi_err("VID header is not OK (%d)", err);
+				if (err > 0)
+					err = -EIO;
+				return err;
+			}
+
+			vol_type = vidh->vol_type == UBI_VID_DYNAMIC ?
+				   UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
+			if (av->vol_type != vol_type) {
+				ubi_err("bad vol_type");
+				goto bad_vid_hdr;
+			}
+
+			if (aeb->sqnum != be64_to_cpu(vidh->sqnum)) {
+				ubi_err("bad sqnum %llu", aeb->sqnum);
+				goto bad_vid_hdr;
+			}
+
+			if (av->vol_id != be32_to_cpu(vidh->vol_id)) {
+				ubi_err("bad vol_id %d", av->vol_id);
+				goto bad_vid_hdr;
+			}
+
+			if (av->compat != vidh->compat) {
+				ubi_err("bad compat %d", vidh->compat);
+				goto bad_vid_hdr;
+			}
+
+			if (aeb->lnum != be32_to_cpu(vidh->lnum)) {
+				ubi_err("bad lnum %d", aeb->lnum);
+				goto bad_vid_hdr;
+			}
+
+			if (av->used_ebs != be32_to_cpu(vidh->used_ebs)) {
+				ubi_err("bad used_ebs %d", av->used_ebs);
+				goto bad_vid_hdr;
+			}
+
+			if (av->data_pad != be32_to_cpu(vidh->data_pad)) {
+				ubi_err("bad data_pad %d", av->data_pad);
+				goto bad_vid_hdr;
+			}
+		}
+
+		if (!last_aeb)
+			continue;
+
+		if (av->highest_lnum != be32_to_cpu(vidh->lnum)) {
+			ubi_err("bad highest_lnum %d", av->highest_lnum);
+			goto bad_vid_hdr;
+		}
+
+		if (av->last_data_size != be32_to_cpu(vidh->data_size)) {
+			ubi_err("bad last_data_size %d", av->last_data_size);
+			goto bad_vid_hdr;
+		}
+	}
+
+	/*
+	 * Make sure that all the physical eraseblocks are in one of the lists
+	 * or trees.
+	 */
+	buf = kzalloc(ubi->peb_count, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (pnum = 0; pnum < ubi->peb_count; pnum++) {
+		err = ubi_io_is_bad(ubi, pnum);
+		if (err < 0) {
+			kfree(buf);
+			return err;
+		} else if (err)
+			buf[pnum] = 1;
+	}
+
+	ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb)
+		ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
+			buf[aeb->pnum] = 1;
+
+	list_for_each_entry(aeb, &ai->free, u.list)
+		buf[aeb->pnum] = 1;
+
+	list_for_each_entry(aeb, &ai->corr, u.list)
+		buf[aeb->pnum] = 1;
+
+	list_for_each_entry(aeb, &ai->erase, u.list)
+		buf[aeb->pnum] = 1;
+
+	list_for_each_entry(aeb, &ai->alien, u.list)
+		buf[aeb->pnum] = 1;
+
+	err = 0;
+	for (pnum = 0; pnum < ubi->peb_count; pnum++)
+		if (!buf[pnum]) {
+			ubi_err("PEB %d is not referred", pnum);
+			err = 1;
+		}
+
+	kfree(buf);
+	if (err)
+		goto out;
+	return 0;
+
+bad_aeb:
+	ubi_err("bad attaching information about LEB %d", aeb->lnum);
+	ubi_dump_aeb(aeb, 0);
+	ubi_dump_av(av);
+	goto out;
+
+bad_av:
+	ubi_err("bad attaching information about volume %d", av->vol_id);
+	ubi_dump_av(av);
+	goto out;
+
+bad_vid_hdr:
+	ubi_err("bad attaching information about volume %d", av->vol_id);
+	ubi_dump_av(av);
+	ubi_dump_vid_hdr(vidh);
+
+out:
+	dump_stack();
+	return -EINVAL;
+}
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 0fde9fc..2c5ed5c 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -27,10 +27,6 @@
  * module load parameters or the kernel boot parameters. If MTD devices were
  * specified, UBI does not attach any MTD device, but it is possible to do
  * later using the "UBI control device".
- *
- * At the moment we only attach UBI devices by scanning, which will become a
- * bottleneck when flashes reach certain large size. Then one may improve UBI
- * and add other methods, although it does not seem to be easy to do.
  */
 
 #include <linux/err.h>
@@ -554,10 +550,10 @@
 }
 
 /**
- * free_internal_volumes - free internal volumes.
+ * ubi_free_internal_volumes - free internal volumes.
  * @ubi: UBI device description object
  */
-static void free_internal_volumes(struct ubi_device *ubi)
+void ubi_free_internal_volumes(struct ubi_device *ubi)
 {
 	int i;
 
@@ -569,59 +565,6 @@
 }
 
 /**
- * attach_by_scanning - attach an MTD device using scanning method.
- * @ubi: UBI device descriptor
- *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
- *
- * Note, currently this is the only method to attach UBI devices. Hopefully in
- * the future we'll have more scalable attaching methods and avoid full media
- * scanning. But even in this case scanning will be needed as a fall-back
- * attaching method if there are some on-flash table corruptions.
- */
-static int attach_by_scanning(struct ubi_device *ubi)
-{
-	int err;
-	struct ubi_scan_info *si;
-
-	si = ubi_scan(ubi);
-	if (IS_ERR(si))
-		return PTR_ERR(si);
-
-	ubi->bad_peb_count = si->bad_peb_count;
-	ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
-	ubi->corr_peb_count = si->corr_peb_count;
-	ubi->max_ec = si->max_ec;
-	ubi->mean_ec = si->mean_ec;
-	ubi_msg("max. sequence number:       %llu", si->max_sqnum);
-
-	err = ubi_read_volume_table(ubi, si);
-	if (err)
-		goto out_si;
-
-	err = ubi_wl_init_scan(ubi, si);
-	if (err)
-		goto out_vtbl;
-
-	err = ubi_eba_init_scan(ubi, si);
-	if (err)
-		goto out_wl;
-
-	ubi_scan_destroy_si(si);
-	return 0;
-
-out_wl:
-	ubi_wl_close(ubi);
-out_vtbl:
-	free_internal_volumes(ubi);
-	vfree(ubi->vtbl);
-out_si:
-	ubi_scan_destroy_si(si);
-	return err;
-}
-
-/**
  * io_init - initialize I/O sub-system for a given UBI device.
  * @ubi: UBI device description object
  *
@@ -790,11 +733,11 @@
 	ubi_msg("data offset:                %d", ubi->leb_start);
 
 	/*
-	 * Note, ideally, we have to initialize ubi->bad_peb_count here. But
+	 * Note, ideally, we have to initialize @ubi->bad_peb_count here. But
 	 * unfortunately, MTD does not provide this information. We should loop
 	 * over all physical eraseblocks and invoke mtd->block_is_bad() for
-	 * each physical eraseblock. So, we skip ubi->bad_peb_count
-	 * uninitialized and initialize it after scanning.
+	 * each physical eraseblock. So, we leave @ubi->bad_peb_count
+	 * uninitialized so far.
 	 */
 
 	return 0;
@@ -805,7 +748,7 @@
  * @ubi: UBI device description object
  * @vol_id: ID of the volume to re-size
  *
- * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in
+ * This function re-sizes the volume marked by the %UBI_VTBL_AUTORESIZE_FLG in
  * the volume table to the largest possible size. See comments in ubi-header.h
  * for more description of the flag. Returns zero in case of success and a
  * negative error code in case of failure.
@@ -881,7 +824,7 @@
 	for (i = 0; i < UBI_MAX_DEVICES; i++) {
 		ubi = ubi_devices[i];
 		if (ubi && mtd->index == ubi->mtd->index) {
-			dbg_err("mtd%d is already attached to ubi%d",
+			ubi_err("mtd%d is already attached to ubi%d",
 				mtd->index, i);
 			return -EEXIST;
 		}
@@ -907,7 +850,7 @@
 			if (!ubi_devices[ubi_num])
 				break;
 		if (ubi_num == UBI_MAX_DEVICES) {
-			dbg_err("only %d UBI devices may be created",
+			ubi_err("only %d UBI devices may be created",
 				UBI_MAX_DEVICES);
 			return -ENFILE;
 		}
@@ -917,7 +860,7 @@
 
 		/* Make sure ubi_num is not busy */
 		if (ubi_devices[ubi_num]) {
-			dbg_err("ubi%d already exists", ubi_num);
+			ubi_err("ubi%d already exists", ubi_num);
 			return -EEXIST;
 		}
 	}
@@ -937,7 +880,7 @@
 	spin_lock_init(&ubi->volumes_lock);
 
 	ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
-	dbg_msg("sizeof(struct ubi_scan_leb) %zu", sizeof(struct ubi_scan_leb));
+	dbg_msg("sizeof(struct ubi_ainf_peb) %zu", sizeof(struct ubi_ainf_peb));
 	dbg_msg("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));
 
 	err = io_init(ubi);
@@ -953,9 +896,9 @@
 	if (err)
 		goto out_free;
 
-	err = attach_by_scanning(ubi);
+	err = ubi_attach(ubi);
 	if (err) {
-		dbg_err("failed to attach by scanning, error %d", err);
+		ubi_err("failed to attach mtd%d, error %d", mtd->index, err);
 		goto out_debugging;
 	}
 
@@ -1020,7 +963,7 @@
 	uif_close(ubi);
 out_detach:
 	ubi_wl_close(ubi);
-	free_internal_volumes(ubi);
+	ubi_free_internal_volumes(ubi);
 	vfree(ubi->vtbl);
 out_debugging:
 	ubi_debugging_exit_dev(ubi);
@@ -1092,7 +1035,7 @@
 	ubi_debugfs_exit_dev(ubi);
 	uif_close(ubi);
 	ubi_wl_close(ubi);
-	free_internal_volumes(ubi);
+	ubi_free_internal_volumes(ubi);
 	vfree(ubi->vtbl);
 	put_mtd_device(ubi->mtd);
 	ubi_debugging_exit_dev(ubi);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index ad76592..acec85d 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -63,7 +63,7 @@
 	users = vol->readers + vol->writers + vol->exclusive;
 	ubi_assert(users > 0);
 	if (users > 1) {
-		dbg_err("%d users for volume %d", users, vol->vol_id);
+		ubi_err("%d users for volume %d", users, vol->vol_id);
 		err = -EBUSY;
 	} else {
 		vol->readers = vol->writers = 0;
@@ -159,7 +159,7 @@
 
 	if (vol->updating) {
 		/* Update is in progress, seeking is prohibited */
-		dbg_err("updating");
+		ubi_err("updating");
 		return -EBUSY;
 	}
 
@@ -178,7 +178,7 @@
 	}
 
 	if (new_offset < 0 || new_offset > vol->used_bytes) {
-		dbg_err("bad seek %lld", new_offset);
+		ubi_err("bad seek %lld", new_offset);
 		return -EINVAL;
 	}
 
@@ -216,11 +216,11 @@
 		count, *offp, vol->vol_id);
 
 	if (vol->updating) {
-		dbg_err("updating");
+		ubi_err("updating");
 		return -EBUSY;
 	}
 	if (vol->upd_marker) {
-		dbg_err("damaged volume, update marker is set");
+		ubi_err("damaged volume, update marker is set");
 		return -EBADF;
 	}
 	if (*offp == vol->used_bytes || count == 0)
@@ -300,7 +300,7 @@
 
 	lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
 	if (off & (ubi->min_io_size - 1)) {
-		dbg_err("unaligned position");
+		ubi_err("unaligned position");
 		return -EINVAL;
 	}
 
@@ -309,7 +309,7 @@
 
 	/* We can write only in fractions of the minimum I/O unit */
 	if (count & (ubi->min_io_size - 1)) {
-		dbg_err("unaligned write length");
+		ubi_err("unaligned write length");
 		return -EINVAL;
 	}
 
@@ -334,8 +334,7 @@
 			break;
 		}
 
-		err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len,
-					UBI_UNKNOWN);
+		err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len);
 		if (err)
 			break;
 
@@ -477,9 +476,6 @@
 		if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
 		    req.bytes < 0 || req.lnum >= vol->usable_leb_size)
 			break;
-		if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM &&
-		    req.dtype != UBI_UNKNOWN)
-			break;
 
 		err = get_exclusive(desc);
 		if (err < 0)
@@ -518,7 +514,7 @@
 		if (err)
 			break;
 
-		err = ubi_wl_flush(ubi);
+		err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
 		break;
 	}
 
@@ -532,7 +528,7 @@
 			err = -EFAULT;
 			break;
 		}
-		err = ubi_leb_map(desc, req.lnum, req.dtype);
+		err = ubi_leb_map(desc, req.lnum);
 		break;
 	}
 
@@ -647,8 +643,8 @@
 	return 0;
 
 bad:
-	dbg_err("bad volume creation request");
-	ubi_dbg_dump_mkvol_req(req);
+	ubi_err("bad volume creation request");
+	ubi_dump_mkvol_req(req);
 	return err;
 }
 
@@ -713,12 +709,12 @@
 	for (i = 0; i < req->count - 1; i++) {
 		for (n = i + 1; n < req->count; n++) {
 			if (req->ents[i].vol_id == req->ents[n].vol_id) {
-				dbg_err("duplicated volume id %d",
+				ubi_err("duplicated volume id %d",
 					req->ents[i].vol_id);
 				return -EINVAL;
 			}
 			if (!strcmp(req->ents[i].name, req->ents[n].name)) {
-				dbg_err("duplicated volume name \"%s\"",
+				ubi_err("duplicated volume name \"%s\"",
 					req->ents[i].name);
 				return -EINVAL;
 			}
@@ -741,7 +737,7 @@
 		re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
 		if (IS_ERR(re->desc)) {
 			err = PTR_ERR(re->desc);
-			dbg_err("cannot open volume %d, error %d", vol_id, err);
+			ubi_err("cannot open volume %d, error %d", vol_id, err);
 			kfree(re);
 			goto out_free;
 		}
@@ -800,7 +796,7 @@
 				continue;
 
 			/* The volume exists but busy, or an error occurred */
-			dbg_err("cannot open volume \"%s\", error %d",
+			ubi_err("cannot open volume \"%s\", error %d",
 				re->new_name, err);
 			goto out_free;
 		}
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 61af9bb..9f957c2 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -18,24 +18,49 @@
  * Author: Artem Bityutskiy (Битюцкий Артём)
  */
 
-/*
- * Here we keep all the UBI debugging stuff which should normally be disabled
- * and compiled-out, but it is extremely helpful when hunting bugs or doing big
- * changes.
- */
-
-#ifdef CONFIG_MTD_UBI_DEBUG
-
 #include "ubi.h"
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
 
+
 /**
- * ubi_dbg_dump_ec_hdr - dump an erase counter header.
+ * ubi_dump_flash - dump a region of flash.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to dump
+ * @offset: the starting offset within the physical eraseblock to dump
+ * @len: the length of the region to dump
+ */
+void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
+{
+	int err;
+	size_t read;
+	void *buf;
+	loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
+
+	buf = vmalloc(len);
+	if (!buf)
+		return;
+	err = mtd_read(ubi->mtd, addr, len, &read, buf);
+	if (err && err != -EUCLEAN) {
+		ubi_err("error %d while reading %d bytes from PEB %d:%d, "
+			"read %zd bytes", err, len, pnum, offset, read);
+		goto out;
+	}
+
+	ubi_msg("dumping %d bytes of data from PEB %d, offset %d",
+		len, pnum, offset);
+	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
+out:
+	vfree(buf);
+	return;
+}
+
+/**
+ * ubi_dump_ec_hdr - dump an erase counter header.
  * @ec_hdr: the erase counter header to dump
  */
-void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
+void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
 {
 	printk(KERN_DEBUG "Erase counter header dump:\n");
 	printk(KERN_DEBUG "\tmagic          %#08x\n",
@@ -57,10 +82,10 @@
 }
 
 /**
- * ubi_dbg_dump_vid_hdr - dump a volume identifier header.
+ * ubi_dump_vid_hdr - dump a volume identifier header.
  * @vid_hdr: the volume identifier header to dump
  */
-void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
+void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
 {
 	printk(KERN_DEBUG "Volume identifier header dump:\n");
 	printk(KERN_DEBUG "\tmagic     %08x\n", be32_to_cpu(vid_hdr->magic));
@@ -82,10 +107,10 @@
 }
 
 /**
- * ubi_dbg_dump_vol_info- dump volume information.
+ * ubi_dump_vol_info - dump volume information.
  * @vol: UBI volume description object
  */
-void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
+void ubi_dump_vol_info(const struct ubi_volume *vol)
 {
 	printk(KERN_DEBUG "Volume information dump:\n");
 	printk(KERN_DEBUG "\tvol_id          %d\n", vol->vol_id);
@@ -112,11 +137,11 @@
 }
 
 /**
- * ubi_dbg_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
+ * ubi_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
  * @r: the object to dump
  * @idx: volume table index
  */
-void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
+void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
 {
 	int name_len = be16_to_cpu(r->name_len);
 
@@ -146,44 +171,44 @@
 }
 
 /**
- * ubi_dbg_dump_sv - dump a &struct ubi_scan_volume object.
- * @sv: the object to dump
+ * ubi_dump_av - dump a &struct ubi_ainf_volume object.
+ * @av: the object to dump
  */
-void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv)
+void ubi_dump_av(const struct ubi_ainf_volume *av)
 {
-	printk(KERN_DEBUG "Volume scanning information dump:\n");
-	printk(KERN_DEBUG "\tvol_id         %d\n", sv->vol_id);
-	printk(KERN_DEBUG "\thighest_lnum   %d\n", sv->highest_lnum);
-	printk(KERN_DEBUG "\tleb_count      %d\n", sv->leb_count);
-	printk(KERN_DEBUG "\tcompat         %d\n", sv->compat);
-	printk(KERN_DEBUG "\tvol_type       %d\n", sv->vol_type);
-	printk(KERN_DEBUG "\tused_ebs       %d\n", sv->used_ebs);
-	printk(KERN_DEBUG "\tlast_data_size %d\n", sv->last_data_size);
-	printk(KERN_DEBUG "\tdata_pad       %d\n", sv->data_pad);
+	printk(KERN_DEBUG "Volume attaching information dump:\n");
+	printk(KERN_DEBUG "\tvol_id         %d\n", av->vol_id);
+	printk(KERN_DEBUG "\thighest_lnum   %d\n", av->highest_lnum);
+	printk(KERN_DEBUG "\tleb_count      %d\n", av->leb_count);
+	printk(KERN_DEBUG "\tcompat         %d\n", av->compat);
+	printk(KERN_DEBUG "\tvol_type       %d\n", av->vol_type);
+	printk(KERN_DEBUG "\tused_ebs       %d\n", av->used_ebs);
+	printk(KERN_DEBUG "\tlast_data_size %d\n", av->last_data_size);
+	printk(KERN_DEBUG "\tdata_pad       %d\n", av->data_pad);
 }
 
 /**
- * ubi_dbg_dump_seb - dump a &struct ubi_scan_leb object.
- * @seb: the object to dump
+ * ubi_dump_aeb - dump a &struct ubi_ainf_peb object.
+ * @aeb: the object to dump
  * @type: object type: 0 - not corrupted, 1 - corrupted
  */
-void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type)
+void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type)
 {
-	printk(KERN_DEBUG "eraseblock scanning information dump:\n");
-	printk(KERN_DEBUG "\tec       %d\n", seb->ec);
-	printk(KERN_DEBUG "\tpnum     %d\n", seb->pnum);
+	printk(KERN_DEBUG "eraseblock attaching information dump:\n");
+	printk(KERN_DEBUG "\tec       %d\n", aeb->ec);
+	printk(KERN_DEBUG "\tpnum     %d\n", aeb->pnum);
 	if (type == 0) {
-		printk(KERN_DEBUG "\tlnum     %d\n", seb->lnum);
-		printk(KERN_DEBUG "\tscrub    %d\n", seb->scrub);
-		printk(KERN_DEBUG "\tsqnum    %llu\n", seb->sqnum);
+		printk(KERN_DEBUG "\tlnum     %d\n", aeb->lnum);
+		printk(KERN_DEBUG "\tscrub    %d\n", aeb->scrub);
+		printk(KERN_DEBUG "\tsqnum    %llu\n", aeb->sqnum);
 	}
 }
 
 /**
- * ubi_dbg_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
+ * ubi_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
  * @req: the object to dump
  */
-void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
+void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req)
 {
 	char nm[17];
 
@@ -200,38 +225,6 @@
 }
 
 /**
- * ubi_dbg_dump_flash - dump a region of flash.
- * @ubi: UBI device description object
- * @pnum: the physical eraseblock number to dump
- * @offset: the starting offset within the physical eraseblock to dump
- * @len: the length of the region to dump
- */
-void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
-{
-	int err;
-	size_t read;
-	void *buf;
-	loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
-
-	buf = vmalloc(len);
-	if (!buf)
-		return;
-	err = mtd_read(ubi->mtd, addr, len, &read, buf);
-	if (err && err != -EUCLEAN) {
-		ubi_err("error %d while reading %d bytes from PEB %d:%d, "
-			"read %zd bytes", err, len, pnum, offset, read);
-		goto out;
-	}
-
-	dbg_msg("dumping %d bytes of data from PEB %d, offset %d",
-		len, pnum, offset);
-	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
-out:
-	vfree(buf);
-	return;
-}
-
-/**
  * ubi_debugging_init_dev - initialize debugging for an UBI device.
  * @ubi: UBI device description object
  *
@@ -479,5 +472,3 @@
 {
 	debugfs_remove_recursive(ubi->dbg->dfs_dir);
 }
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index ead2cd1..d5d2645 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -21,21 +21,20 @@
 #ifndef __UBI_DEBUG_H__
 #define __UBI_DEBUG_H__
 
-#ifdef CONFIG_MTD_UBI_DEBUG
+void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
+void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
+void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
+
 #include <linux/random.h>
 
 #define ubi_assert(expr)  do {                                               \
 	if (unlikely(!(expr))) {                                             \
 		printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
 		       __func__, __LINE__, current->pid);                    \
-		ubi_dbg_dump_stack();                                        \
+		dump_stack();                                                \
 	}                                                                    \
 } while (0)
 
-#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
-
-#define ubi_dbg_dump_stack() dump_stack()
-
 #define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  \
 		print_hex_dump(l, ps, pt, r, g, b, len, a)
 
@@ -58,17 +57,13 @@
 /* Initialization and build messages */
 #define dbg_bld(fmt, ...) ubi_dbg_msg("bld", fmt, ##__VA_ARGS__)
 
-void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
-void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
-void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
-void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
-void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
-void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
-void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
-void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
-int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
-int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
-			int offset, int len);
+void ubi_dump_vol_info(const struct ubi_volume *vol);
+void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
+void ubi_dump_av(const struct ubi_ainf_volume *av);
+void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type);
+void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req);
+int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+			  int len);
 int ubi_debugging_init_dev(struct ubi_device *ubi);
 void ubi_debugging_exit_dev(struct ubi_device *ubi);
 int ubi_debugfs_init(void);
@@ -167,73 +162,4 @@
 	return 0;
 }
 
-#else
-
-/* Use "if (0)" to make compiler check arguments even if debugging is off */
-#define ubi_assert(expr)  do {                                               \
-	if (0) {                                                             \
-		printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
-		       __func__, __LINE__, current->pid);                    \
-	}                                                                    \
-} while (0)
-
-#define dbg_err(fmt, ...) do {                                               \
-	if (0)                                                               \
-		ubi_err(fmt, ##__VA_ARGS__);                                 \
-} while (0)
-
-#define ubi_dbg_msg(fmt, ...) do {                                           \
-	if (0)                                                               \
-		printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__);                  \
-} while (0)
-
-#define dbg_msg(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gen(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_eba(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_wl(fmt, ...)   ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_io(fmt, ...)   ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_bld(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
-
-static inline void ubi_dbg_dump_stack(void)                          { return; }
-static inline void
-ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)                 { return; }
-static inline void
-ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)              { return; }
-static inline void
-ubi_dbg_dump_vol_info(const struct ubi_volume *vol)                  { return; }
-static inline void
-ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)   { return; }
-static inline void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) { return; }
-static inline void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb,
-				    int type)                        { return; }
-static inline void
-ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)              { return; }
-static inline void ubi_dbg_dump_flash(struct ubi_device *ubi,
-				      int pnum, int offset, int len) { return; }
-static inline void
-ubi_dbg_print_hex_dump(const char *l, const char *ps, int pt, int r,
-		       int g, const void *b, size_t len, bool a)     { return; }
-static inline int ubi_dbg_check_all_ff(struct ubi_device *ubi,
-				       int pnum, int offset,
-				       int len)                    { return 0; }
-static inline int ubi_dbg_check_write(struct ubi_device *ubi,
-				      const void *buf, int pnum,
-				      int offset, int len)         { return 0; }
-
-static inline int ubi_debugging_init_dev(struct ubi_device *ubi)   { return 0; }
-static inline void ubi_debugging_exit_dev(struct ubi_device *ubi)  { return; }
-static inline int ubi_debugfs_init(void)                           { return 0; }
-static inline void ubi_debugfs_exit(void)                          { return; }
-static inline int ubi_debugfs_init_dev(struct ubi_device *ubi)     { return 0; }
-static inline void ubi_debugfs_exit_dev(struct ubi_device *ubi)    { return; }
-
-static inline int
-ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)              { return 0; }
-static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi) { return 0; }
-static inline int
-ubi_dbg_is_write_failure(const struct ubi_device *ubi)             { return 0; }
-static inline int
-ubi_dbg_is_erase_failure(const struct ubi_device *ubi)             { return 0; }
-
-#endif /* !CONFIG_MTD_UBI_DEBUG */
 #endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 2455d62..b703ac7 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -341,7 +341,7 @@
 	dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
 
 	vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
-	err = ubi_wl_put_peb(ubi, pnum, 0);
+	err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0);
 
 out_unlock:
 	leb_write_unlock(ubi, vol_id, lnum);
@@ -507,7 +507,7 @@
 		return -ENOMEM;
 
 retry:
-	new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN);
+	new_pnum = ubi_wl_get_peb(ubi);
 	if (new_pnum < 0) {
 		ubi_free_vid_hdr(ubi, vid_hdr);
 		return new_pnum;
@@ -550,7 +550,7 @@
 	ubi_free_vid_hdr(ubi, vid_hdr);
 
 	vol->eba_tbl[lnum] = new_pnum;
-	ubi_wl_put_peb(ubi, pnum, 1);
+	ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
 
 	ubi_msg("data was successfully recovered");
 	return 0;
@@ -558,7 +558,7 @@
 out_unlock:
 	mutex_unlock(&ubi->buf_mutex);
 out_put:
-	ubi_wl_put_peb(ubi, new_pnum, 1);
+	ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
 	ubi_free_vid_hdr(ubi, vid_hdr);
 	return err;
 
@@ -568,7 +568,7 @@
 	 * get another one.
 	 */
 	ubi_warn("failed to write to PEB %d", new_pnum);
-	ubi_wl_put_peb(ubi, new_pnum, 1);
+	ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
 	if (++tries > UBI_IO_RETRIES) {
 		ubi_free_vid_hdr(ubi, vid_hdr);
 		return err;
@@ -585,7 +585,6 @@
  * @buf: the data to write
  * @offset: offset within the logical eraseblock where to write
  * @len: how many bytes to write
- * @dtype: data type
  *
  * This function writes data to logical eraseblock @lnum of a dynamic volume
  * @vol. Returns zero in case of success and a negative error code in case
@@ -593,7 +592,7 @@
  * written to the flash media, but may be some garbage.
  */
 int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
-		      const void *buf, int offset, int len, int dtype)
+		      const void *buf, int offset, int len)
 {
 	int err, pnum, tries = 0, vol_id = vol->vol_id;
 	struct ubi_vid_hdr *vid_hdr;
@@ -641,7 +640,7 @@
 	vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
 retry:
-	pnum = ubi_wl_get_peb(ubi, dtype);
+	pnum = ubi_wl_get_peb(ubi);
 	if (pnum < 0) {
 		ubi_free_vid_hdr(ubi, vid_hdr);
 		leb_write_unlock(ubi, vol_id, lnum);
@@ -687,7 +686,7 @@
 	 * eraseblock, so just put it and request a new one. We assume that if
 	 * this physical eraseblock went bad, the erase code will handle that.
 	 */
-	err = ubi_wl_put_peb(ubi, pnum, 1);
+	err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
 	if (err || ++tries > UBI_IO_RETRIES) {
 		ubi_ro_mode(ubi);
 		leb_write_unlock(ubi, vol_id, lnum);
@@ -707,7 +706,6 @@
  * @lnum: logical eraseblock number
  * @buf: data to write
  * @len: how many bytes to write
- * @dtype: data type
  * @used_ebs: how many logical eraseblocks will this volume contain
  *
  * This function writes data to logical eraseblock @lnum of static volume
@@ -724,8 +722,7 @@
  * code in case of failure.
  */
 int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
-			 int lnum, const void *buf, int len, int dtype,
-			 int used_ebs)
+			 int lnum, const void *buf, int len, int used_ebs)
 {
 	int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id;
 	struct ubi_vid_hdr *vid_hdr;
@@ -763,7 +760,7 @@
 	vid_hdr->data_crc = cpu_to_be32(crc);
 
 retry:
-	pnum = ubi_wl_get_peb(ubi, dtype);
+	pnum = ubi_wl_get_peb(ubi);
 	if (pnum < 0) {
 		ubi_free_vid_hdr(ubi, vid_hdr);
 		leb_write_unlock(ubi, vol_id, lnum);
@@ -807,7 +804,7 @@
 		return err;
 	}
 
-	err = ubi_wl_put_peb(ubi, pnum, 1);
+	err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
 	if (err || ++tries > UBI_IO_RETRIES) {
 		ubi_ro_mode(ubi);
 		leb_write_unlock(ubi, vol_id, lnum);
@@ -827,7 +824,6 @@
  * @lnum: logical eraseblock number
  * @buf: data to write
  * @len: how many bytes to write
- * @dtype: data type
  *
  * This function changes the contents of a logical eraseblock atomically. @buf
  * has to contain new logical eraseblock data, and @len - the length of the
@@ -839,7 +835,7 @@
  * LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
  */
 int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
-			      int lnum, const void *buf, int len, int dtype)
+			      int lnum, const void *buf, int len)
 {
 	int err, pnum, tries = 0, vol_id = vol->vol_id;
 	struct ubi_vid_hdr *vid_hdr;
@@ -856,7 +852,7 @@
 		err = ubi_eba_unmap_leb(ubi, vol, lnum);
 		if (err)
 			return err;
-		return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+		return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0);
 	}
 
 	vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
@@ -881,7 +877,7 @@
 	vid_hdr->data_crc = cpu_to_be32(crc);
 
 retry:
-	pnum = ubi_wl_get_peb(ubi, dtype);
+	pnum = ubi_wl_get_peb(ubi);
 	if (pnum < 0) {
 		err = pnum;
 		goto out_leb_unlock;
@@ -905,7 +901,7 @@
 	}
 
 	if (vol->eba_tbl[lnum] >= 0) {
-		err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 0);
+		err = ubi_wl_put_peb(ubi, vol_id, lnum, vol->eba_tbl[lnum], 0);
 		if (err)
 			goto out_leb_unlock;
 	}
@@ -930,7 +926,7 @@
 		goto out_leb_unlock;
 	}
 
-	err = ubi_wl_put_peb(ubi, pnum, 1);
+	err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
 	if (err || ++tries > UBI_IO_RETRIES) {
 		ubi_ro_mode(ubi);
 		goto out_leb_unlock;
@@ -1171,7 +1167,7 @@
  * print_rsvd_warning - warn about not having enough reserved PEBs.
  * @ubi: UBI device description object
  *
- * This is a helper function for 'ubi_eba_init_scan()' which is called when UBI
+ * This is a helper function for 'ubi_eba_init()' which is called when UBI
  * cannot reserve enough PEBs for bad block handling. This function makes a
  * decision whether we have to print a warning or not. The algorithm is as
  * follows:
@@ -1186,13 +1182,13 @@
  * reported by real users.
  */
 static void print_rsvd_warning(struct ubi_device *ubi,
-			       struct ubi_scan_info *si)
+			       struct ubi_attach_info *ai)
 {
 	/*
 	 * The 1 << 18 (256KiB) number is picked randomly, just a reasonably
 	 * large number to distinguish between newly flashed and used images.
 	 */
-	if (si->max_sqnum > (1 << 18)) {
+	if (ai->max_sqnum > (1 << 18)) {
 		int min = ubi->beb_rsvd_level / 10;
 
 		if (!min)
@@ -1209,19 +1205,19 @@
 }
 
 /**
- * ubi_eba_init_scan - initialize the EBA sub-system using scanning information.
+ * ubi_eba_init - initialize the EBA sub-system using attaching information.
  * @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
  *
  * This function returns zero in case of success and a negative error code in
  * case of failure.
  */
-int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
 {
 	int i, j, err, num_volumes;
-	struct ubi_scan_volume *sv;
+	struct ubi_ainf_volume *av;
 	struct ubi_volume *vol;
-	struct ubi_scan_leb *seb;
+	struct ubi_ainf_peb *aeb;
 	struct rb_node *rb;
 
 	dbg_eba("initialize EBA sub-system");
@@ -1230,7 +1226,7 @@
 	mutex_init(&ubi->alc_mutex);
 	ubi->ltree = RB_ROOT;
 
-	ubi->global_sqnum = si->max_sqnum + 1;
+	ubi->global_sqnum = ai->max_sqnum + 1;
 	num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
 
 	for (i = 0; i < num_volumes; i++) {
@@ -1250,18 +1246,18 @@
 		for (j = 0; j < vol->reserved_pebs; j++)
 			vol->eba_tbl[j] = UBI_LEB_UNMAPPED;
 
-		sv = ubi_scan_find_sv(si, idx2vol_id(ubi, i));
-		if (!sv)
+		av = ubi_find_av(ai, idx2vol_id(ubi, i));
+		if (!av)
 			continue;
 
-		ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
-			if (seb->lnum >= vol->reserved_pebs)
+		ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) {
+			if (aeb->lnum >= vol->reserved_pebs)
 				/*
 				 * This may happen in case of an unclean reboot
 				 * during re-size.
 				 */
-				ubi_scan_move_to_list(sv, seb, &si->erase);
-			vol->eba_tbl[seb->lnum] = seb->pnum;
+				ubi_move_aeb_to_list(av, aeb, &ai->erase);
+			vol->eba_tbl[aeb->lnum] = aeb->pnum;
 		}
 	}
 
@@ -1283,7 +1279,7 @@
 		if (ubi->avail_pebs < ubi->beb_rsvd_level) {
 			/* No enough free physical eraseblocks */
 			ubi->beb_rsvd_pebs = ubi->avail_pebs;
-			print_rsvd_warning(ubi, si);
+			print_rsvd_warning(ubi, ai);
 		} else
 			ubi->beb_rsvd_pebs = ubi->beb_rsvd_level;
 
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index 90b9882..4e44bee 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -227,7 +227,7 @@
 		if (to_write > total_written)
 			to_write = total_written;
 
-		err = ubi_write(gluebi->desc, lnum, buf, offs, to_write);
+		err = ubi_leb_write(gluebi->desc, lnum, buf, offs, to_write);
 		if (err)
 			break;
 
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 43f1a00..a8d5237 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -91,21 +91,15 @@
 #include <linux/slab.h>
 #include "ubi.h"
 
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum);
-static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
-static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
-				 const struct ubi_ec_hdr *ec_hdr);
-static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
-static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
-				  const struct ubi_vid_hdr *vid_hdr);
-#else
-#define paranoid_check_not_bad(ubi, pnum) 0
-#define paranoid_check_peb_ec_hdr(ubi, pnum)  0
-#define paranoid_check_ec_hdr(ubi, pnum, ec_hdr)  0
-#define paranoid_check_peb_vid_hdr(ubi, pnum) 0
-#define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0
-#endif
+static int self_check_not_bad(const struct ubi_device *ubi, int pnum);
+static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
+static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+			     const struct ubi_ec_hdr *ec_hdr);
+static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
+static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+			      const struct ubi_vid_hdr *vid_hdr);
+static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+			    int offset, int len);
 
 /**
  * ubi_io_read - read data from a physical eraseblock.
@@ -142,7 +136,7 @@
 	ubi_assert(offset >= 0 && offset + len <= ubi->peb_size);
 	ubi_assert(len > 0);
 
-	err = paranoid_check_not_bad(ubi, pnum);
+	err = self_check_not_bad(ubi, pnum);
 	if (err)
 		return err;
 
@@ -189,16 +183,16 @@
 		}
 
 		if (retries++ < UBI_IO_RETRIES) {
-			dbg_io("error %d%s while reading %d bytes from PEB "
-			       "%d:%d, read only %zd bytes, retry",
-			       err, errstr, len, pnum, offset, read);
+			ubi_warn("error %d%s while reading %d bytes from PEB "
+				 "%d:%d, read only %zd bytes, retry",
+				 err, errstr, len, pnum, offset, read);
 			yield();
 			goto retry;
 		}
 
 		ubi_err("error %d%s while reading %d bytes from PEB %d:%d, "
 			"read %zd bytes", err, errstr, len, pnum, offset, read);
-		ubi_dbg_dump_stack();
+		dump_stack();
 
 		/*
 		 * The driver should never return -EBADMSG if it failed to read
@@ -257,14 +251,12 @@
 		return -EROFS;
 	}
 
-	/* The below has to be compiled out if paranoid checks are disabled */
-
-	err = paranoid_check_not_bad(ubi, pnum);
+	err = self_check_not_bad(ubi, pnum);
 	if (err)
 		return err;
 
 	/* The area we are writing to has to contain all 0xFF bytes */
-	err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
+	err = ubi_self_check_all_ff(ubi, pnum, offset, len);
 	if (err)
 		return err;
 
@@ -273,18 +265,18 @@
 		 * We write to the data area of the physical eraseblock. Make
 		 * sure it has valid EC and VID headers.
 		 */
-		err = paranoid_check_peb_ec_hdr(ubi, pnum);
+		err = self_check_peb_ec_hdr(ubi, pnum);
 		if (err)
 			return err;
-		err = paranoid_check_peb_vid_hdr(ubi, pnum);
+		err = self_check_peb_vid_hdr(ubi, pnum);
 		if (err)
 			return err;
 	}
 
 	if (ubi_dbg_is_write_failure(ubi)) {
-		dbg_err("cannot write %d bytes to PEB %d:%d "
+		ubi_err("cannot write %d bytes to PEB %d:%d "
 			"(emulated)", len, pnum, offset);
-		ubi_dbg_dump_stack();
+		dump_stack();
 		return -EIO;
 	}
 
@@ -293,13 +285,13 @@
 	if (err) {
 		ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
 			"%zd bytes", err, len, pnum, offset, written);
-		ubi_dbg_dump_stack();
-		ubi_dbg_dump_flash(ubi, pnum, offset, len);
+		dump_stack();
+		ubi_dump_flash(ubi, pnum, offset, len);
 	} else
 		ubi_assert(written == len);
 
 	if (!err) {
-		err = ubi_dbg_check_write(ubi, buf, pnum, offset, len);
+		err = self_check_write(ubi, buf, pnum, offset, len);
 		if (err)
 			return err;
 
@@ -310,7 +302,7 @@
 		offset += len;
 		len = ubi->peb_size - offset;
 		if (len)
-			err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
+			err = ubi_self_check_all_ff(ubi, pnum, offset, len);
 	}
 
 	return err;
@@ -364,13 +356,13 @@
 	err = mtd_erase(ubi->mtd, &ei);
 	if (err) {
 		if (retries++ < UBI_IO_RETRIES) {
-			dbg_io("error %d while erasing PEB %d, retry",
-			       err, pnum);
+			ubi_warn("error %d while erasing PEB %d, retry",
+				 err, pnum);
 			yield();
 			goto retry;
 		}
 		ubi_err("cannot erase PEB %d, error %d", pnum, err);
-		ubi_dbg_dump_stack();
+		dump_stack();
 		return err;
 	}
 
@@ -383,21 +375,21 @@
 
 	if (ei.state == MTD_ERASE_FAILED) {
 		if (retries++ < UBI_IO_RETRIES) {
-			dbg_io("error while erasing PEB %d, retry", pnum);
+			ubi_warn("error while erasing PEB %d, retry", pnum);
 			yield();
 			goto retry;
 		}
 		ubi_err("cannot erase PEB %d", pnum);
-		ubi_dbg_dump_stack();
+		dump_stack();
 		return -EIO;
 	}
 
-	err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size);
+	err = ubi_self_check_all_ff(ubi, pnum, 0, ubi->peb_size);
 	if (err)
 		return err;
 
 	if (ubi_dbg_is_erase_failure(ubi)) {
-		dbg_err("cannot erase PEB %d (emulated)", pnum);
+		ubi_err("cannot erase PEB %d (emulated)", pnum);
 		return -EIO;
 	}
 
@@ -521,8 +513,7 @@
 	 * It is important to first invalidate the EC header, and then the VID
 	 * header. Otherwise a power cut may lead to valid EC header and
 	 * invalid VID header, in which case UBI will treat this PEB as
-	 * corrupted and will try to preserve it, and print scary warnings (see
-	 * the header comment in scan.c for more information).
+	 * corrupted and will try to preserve it, and print scary warnings.
 	 */
 	addr = (loff_t)pnum * ubi->peb_size;
 	err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data);
@@ -563,7 +554,7 @@
 	 */
 	ubi_err("cannot invalidate PEB %d, write returned %d read returned %d",
 		pnum, err, err1);
-	ubi_dbg_dump_flash(ubi, pnum, 0, ubi->peb_size);
+	ubi_dump_flash(ubi, pnum, 0, ubi->peb_size);
 	return -EIO;
 }
 
@@ -589,7 +580,7 @@
 
 	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
 
-	err = paranoid_check_not_bad(ubi, pnum);
+	err = self_check_not_bad(ubi, pnum);
 	if (err != 0)
 		return err;
 
@@ -721,8 +712,8 @@
 
 bad:
 	ubi_err("bad EC header");
-	ubi_dbg_dump_ec_hdr(ec_hdr);
-	ubi_dbg_dump_stack();
+	ubi_dump_ec_hdr(ec_hdr);
+	dump_stack();
 	return 1;
 }
 
@@ -803,7 +794,7 @@
 		if (verbose) {
 			ubi_warn("bad magic number at PEB %d: %08x instead of "
 				 "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
-			ubi_dbg_dump_ec_hdr(ec_hdr);
+			ubi_dump_ec_hdr(ec_hdr);
 		}
 		dbg_bld("bad magic number at PEB %d: %08x instead of "
 			"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
@@ -817,7 +808,7 @@
 		if (verbose) {
 			ubi_warn("bad EC header CRC at PEB %d, calculated "
 				 "%#08x, read %#08x", pnum, crc, hdr_crc);
-			ubi_dbg_dump_ec_hdr(ec_hdr);
+			ubi_dump_ec_hdr(ec_hdr);
 		}
 		dbg_bld("bad EC header CRC at PEB %d, calculated "
 			"%#08x, read %#08x", pnum, crc, hdr_crc);
@@ -874,7 +865,7 @@
 	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
 	ec_hdr->hdr_crc = cpu_to_be32(crc);
 
-	err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+	err = self_check_ec_hdr(ubi, pnum, ec_hdr);
 	if (err)
 		return err;
 
@@ -905,40 +896,40 @@
 	int usable_leb_size = ubi->leb_size - data_pad;
 
 	if (copy_flag != 0 && copy_flag != 1) {
-		dbg_err("bad copy_flag");
+		ubi_err("bad copy_flag");
 		goto bad;
 	}
 
 	if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 ||
 	    data_pad < 0) {
-		dbg_err("negative values");
+		ubi_err("negative values");
 		goto bad;
 	}
 
 	if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) {
-		dbg_err("bad vol_id");
+		ubi_err("bad vol_id");
 		goto bad;
 	}
 
 	if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) {
-		dbg_err("bad compat");
+		ubi_err("bad compat");
 		goto bad;
 	}
 
 	if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE &&
 	    compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE &&
 	    compat != UBI_COMPAT_REJECT) {
-		dbg_err("bad compat");
+		ubi_err("bad compat");
 		goto bad;
 	}
 
 	if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
-		dbg_err("bad vol_type");
+		ubi_err("bad vol_type");
 		goto bad;
 	}
 
 	if (data_pad >= ubi->leb_size / 2) {
-		dbg_err("bad data_pad");
+		ubi_err("bad data_pad");
 		goto bad;
 	}
 
@@ -950,45 +941,45 @@
 		 * mapped logical eraseblocks.
 		 */
 		if (used_ebs == 0) {
-			dbg_err("zero used_ebs");
+			ubi_err("zero used_ebs");
 			goto bad;
 		}
 		if (data_size == 0) {
-			dbg_err("zero data_size");
+			ubi_err("zero data_size");
 			goto bad;
 		}
 		if (lnum < used_ebs - 1) {
 			if (data_size != usable_leb_size) {
-				dbg_err("bad data_size");
+				ubi_err("bad data_size");
 				goto bad;
 			}
 		} else if (lnum == used_ebs - 1) {
 			if (data_size == 0) {
-				dbg_err("bad data_size at last LEB");
+				ubi_err("bad data_size at last LEB");
 				goto bad;
 			}
 		} else {
-			dbg_err("too high lnum");
+			ubi_err("too high lnum");
 			goto bad;
 		}
 	} else {
 		if (copy_flag == 0) {
 			if (data_crc != 0) {
-				dbg_err("non-zero data CRC");
+				ubi_err("non-zero data CRC");
 				goto bad;
 			}
 			if (data_size != 0) {
-				dbg_err("non-zero data_size");
+				ubi_err("non-zero data_size");
 				goto bad;
 			}
 		} else {
 			if (data_size == 0) {
-				dbg_err("zero data_size of copy");
+				ubi_err("zero data_size of copy");
 				goto bad;
 			}
 		}
 		if (used_ebs != 0) {
-			dbg_err("bad used_ebs");
+			ubi_err("bad used_ebs");
 			goto bad;
 		}
 	}
@@ -997,8 +988,8 @@
 
 bad:
 	ubi_err("bad VID header");
-	ubi_dbg_dump_vid_hdr(vid_hdr);
-	ubi_dbg_dump_stack();
+	ubi_dump_vid_hdr(vid_hdr);
+	dump_stack();
 	return 1;
 }
 
@@ -1054,7 +1045,7 @@
 		if (verbose) {
 			ubi_warn("bad magic number at PEB %d: %08x instead of "
 				 "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
-			ubi_dbg_dump_vid_hdr(vid_hdr);
+			ubi_dump_vid_hdr(vid_hdr);
 		}
 		dbg_bld("bad magic number at PEB %d: %08x instead of "
 			"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
@@ -1068,7 +1059,7 @@
 		if (verbose) {
 			ubi_warn("bad CRC at PEB %d, calculated %#08x, "
 				 "read %#08x", pnum, crc, hdr_crc);
-			ubi_dbg_dump_vid_hdr(vid_hdr);
+			ubi_dump_vid_hdr(vid_hdr);
 		}
 		dbg_bld("bad CRC at PEB %d, calculated %#08x, "
 			"read %#08x", pnum, crc, hdr_crc);
@@ -1112,7 +1103,7 @@
 	dbg_io("write VID header to PEB %d", pnum);
 	ubi_assert(pnum >= 0 &&  pnum < ubi->peb_count);
 
-	err = paranoid_check_peb_ec_hdr(ubi, pnum);
+	err = self_check_peb_ec_hdr(ubi, pnum);
 	if (err)
 		return err;
 
@@ -1121,7 +1112,7 @@
 	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
 	vid_hdr->hdr_crc = cpu_to_be32(crc);
 
-	err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+	err = self_check_vid_hdr(ubi, pnum, vid_hdr);
 	if (err)
 		return err;
 
@@ -1131,17 +1122,15 @@
 	return err;
 }
 
-#ifdef CONFIG_MTD_UBI_DEBUG
-
 /**
- * paranoid_check_not_bad - ensure that a physical eraseblock is not bad.
+ * self_check_not_bad - ensure that a physical eraseblock is not bad.
  * @ubi: UBI device description object
  * @pnum: physical eraseblock number to check
  *
  * This function returns zero if the physical eraseblock is good, %-EINVAL if
  * it is bad and a negative error code if an error occurred.
  */
-static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
+static int self_check_not_bad(const struct ubi_device *ubi, int pnum)
 {
 	int err;
 
@@ -1152,13 +1141,13 @@
 	if (!err)
 		return err;
 
-	ubi_err("paranoid check failed for PEB %d", pnum);
-	ubi_dbg_dump_stack();
+	ubi_err("self-check failed for PEB %d", pnum);
+	dump_stack();
 	return err > 0 ? -EINVAL : err;
 }
 
 /**
- * paranoid_check_ec_hdr - check if an erase counter header is all right.
+ * self_check_ec_hdr - check if an erase counter header is all right.
  * @ubi: UBI device description object
  * @pnum: physical eraseblock number the erase counter header belongs to
  * @ec_hdr: the erase counter header to check
@@ -1166,8 +1155,8 @@
  * This function returns zero if the erase counter header contains valid
  * values, and %-EINVAL if not.
  */
-static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
-				 const struct ubi_ec_hdr *ec_hdr)
+static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+			     const struct ubi_ec_hdr *ec_hdr)
 {
 	int err;
 	uint32_t magic;
@@ -1184,27 +1173,27 @@
 
 	err = validate_ec_hdr(ubi, ec_hdr);
 	if (err) {
-		ubi_err("paranoid check failed for PEB %d", pnum);
+		ubi_err("self-check failed for PEB %d", pnum);
 		goto fail;
 	}
 
 	return 0;
 
 fail:
-	ubi_dbg_dump_ec_hdr(ec_hdr);
-	ubi_dbg_dump_stack();
+	ubi_dump_ec_hdr(ec_hdr);
+	dump_stack();
 	return -EINVAL;
 }
 
 /**
- * paranoid_check_peb_ec_hdr - check erase counter header.
+ * self_check_peb_ec_hdr - check erase counter header.
  * @ubi: UBI device description object
  * @pnum: the physical eraseblock number to check
  *
  * This function returns zero if the erase counter header is all right and and
  * a negative error code if not or if an error occurred.
  */
-static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
+static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
 {
 	int err;
 	uint32_t crc, hdr_crc;
@@ -1225,14 +1214,14 @@
 	hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
 	if (hdr_crc != crc) {
 		ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
-		ubi_err("paranoid check failed for PEB %d", pnum);
-		ubi_dbg_dump_ec_hdr(ec_hdr);
-		ubi_dbg_dump_stack();
+		ubi_err("self-check failed for PEB %d", pnum);
+		ubi_dump_ec_hdr(ec_hdr);
+		dump_stack();
 		err = -EINVAL;
 		goto exit;
 	}
 
-	err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+	err = self_check_ec_hdr(ubi, pnum, ec_hdr);
 
 exit:
 	kfree(ec_hdr);
@@ -1240,7 +1229,7 @@
 }
 
 /**
- * paranoid_check_vid_hdr - check that a volume identifier header is all right.
+ * self_check_vid_hdr - check that a volume identifier header is all right.
  * @ubi: UBI device description object
  * @pnum: physical eraseblock number the volume identifier header belongs to
  * @vid_hdr: the volume identifier header to check
@@ -1248,8 +1237,8 @@
  * This function returns zero if the volume identifier header is all right, and
  * %-EINVAL if not.
  */
-static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
-				  const struct ubi_vid_hdr *vid_hdr)
+static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+			      const struct ubi_vid_hdr *vid_hdr)
 {
 	int err;
 	uint32_t magic;
@@ -1266,29 +1255,29 @@
 
 	err = validate_vid_hdr(ubi, vid_hdr);
 	if (err) {
-		ubi_err("paranoid check failed for PEB %d", pnum);
+		ubi_err("self-check failed for PEB %d", pnum);
 		goto fail;
 	}
 
 	return err;
 
 fail:
-	ubi_err("paranoid check failed for PEB %d", pnum);
-	ubi_dbg_dump_vid_hdr(vid_hdr);
-	ubi_dbg_dump_stack();
+	ubi_err("self-check failed for PEB %d", pnum);
+	ubi_dump_vid_hdr(vid_hdr);
+	dump_stack();
 	return -EINVAL;
 
 }
 
 /**
- * paranoid_check_peb_vid_hdr - check volume identifier header.
+ * self_check_peb_vid_hdr - check volume identifier header.
  * @ubi: UBI device description object
  * @pnum: the physical eraseblock number to check
  *
  * This function returns zero if the volume identifier header is all right,
  * and a negative error code if not or if an error occurred.
  */
-static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
+static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
 {
 	int err;
 	uint32_t crc, hdr_crc;
@@ -1313,14 +1302,14 @@
 	if (hdr_crc != crc) {
 		ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
 			"read %#08x", pnum, crc, hdr_crc);
-		ubi_err("paranoid check failed for PEB %d", pnum);
-		ubi_dbg_dump_vid_hdr(vid_hdr);
-		ubi_dbg_dump_stack();
+		ubi_err("self-check failed for PEB %d", pnum);
+		ubi_dump_vid_hdr(vid_hdr);
+		dump_stack();
 		err = -EINVAL;
 		goto exit;
 	}
 
-	err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+	err = self_check_vid_hdr(ubi, pnum, vid_hdr);
 
 exit:
 	ubi_free_vid_hdr(ubi, vid_hdr);
@@ -1328,7 +1317,7 @@
 }
 
 /**
- * ubi_dbg_check_write - make sure write succeeded.
+ * self_check_write - make sure write succeeded.
  * @ubi: UBI device description object
  * @buf: buffer with data which were written
  * @pnum: physical eraseblock number the data were written to
@@ -1339,8 +1328,8 @@
  * the original data buffer - the data have to match. Returns zero if the data
  * match and a negative error code if not or in case of failure.
  */
-int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
-			int offset, int len)
+static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+			    int offset, int len)
 {
 	int err, i;
 	size_t read;
@@ -1368,7 +1357,7 @@
 		if (c == c1)
 			continue;
 
-		ubi_err("paranoid check failed for PEB %d:%d, len %d",
+		ubi_err("self-check failed for PEB %d:%d, len %d",
 			pnum, offset, len);
 		ubi_msg("data differ at position %d", i);
 		dump_len = max_t(int, 128, len - i);
@@ -1380,7 +1369,7 @@
 			i, i + dump_len);
 		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
 			       buf1 + i, dump_len, 1);
-		ubi_dbg_dump_stack();
+		dump_stack();
 		err = -EINVAL;
 		goto out_free;
 	}
@@ -1394,7 +1383,7 @@
 }
 
 /**
- * ubi_dbg_check_all_ff - check that a region of flash is empty.
+ * ubi_self_check_all_ff - check that a region of flash is empty.
  * @ubi: UBI device description object
  * @pnum: the physical eraseblock number to check
  * @offset: the starting offset within the physical eraseblock to check
@@ -1404,7 +1393,7 @@
  * @offset of the physical eraseblock @pnum, and a negative error code if not
  * or if an error occurred.
  */
-int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
+int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
 {
 	size_t read;
 	int err;
@@ -1438,14 +1427,12 @@
 	return 0;
 
 fail:
-	ubi_err("paranoid check failed for PEB %d", pnum);
+	ubi_err("self-check failed for PEB %d", pnum);
 	ubi_msg("hex dump of the %d-%d region", offset, offset + len);
 	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
 	err = -EINVAL;
 error:
-	ubi_dbg_dump_stack();
+	dump_stack();
 	vfree(buf);
 	return err;
 }
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 9fdb353..3aac1ac 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -221,7 +221,7 @@
 	kfree(desc);
 out_put_ubi:
 	ubi_put_device(ubi);
-	dbg_err("cannot open device %d, volume %d, error %d",
+	ubi_err("cannot open device %d, volume %d, error %d",
 		ubi_num, vol_id, err);
 	return ERR_PTR(err);
 }
@@ -426,11 +426,9 @@
  * @buf: data to write
  * @offset: offset within the logical eraseblock where to write
  * @len: how many bytes to write
- * @dtype: expected data type
  *
  * This function writes @len bytes of data from @buf to offset @offset of
- * logical eraseblock @lnum. The @dtype argument describes expected lifetime of
- * the data.
+ * logical eraseblock @lnum.
  *
  * This function takes care of physical eraseblock write failures. If write to
  * the physical eraseblock write operation fails, the logical eraseblock is
@@ -447,7 +445,7 @@
  * returns immediately with %-EBADF code.
  */
 int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
-		  int offset, int len, int dtype)
+		  int offset, int len)
 {
 	struct ubi_volume *vol = desc->vol;
 	struct ubi_device *ubi = vol->ubi;
@@ -466,17 +464,13 @@
 	    offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1))
 		return -EINVAL;
 
-	if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
-	    dtype != UBI_UNKNOWN)
-		return -EINVAL;
-
 	if (vol->upd_marker)
 		return -EBADF;
 
 	if (len == 0)
 		return 0;
 
-	return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype);
+	return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len);
 }
 EXPORT_SYMBOL_GPL(ubi_leb_write);
 
@@ -486,7 +480,6 @@
  * @lnum: logical eraseblock number to change
  * @buf: data to write
  * @len: how many bytes to write
- * @dtype: expected data type
  *
  * This function changes the contents of a logical eraseblock atomically. @buf
  * has to contain new logical eraseblock data, and @len - the length of the
@@ -497,7 +490,7 @@
  * code in case of failure.
  */
 int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
-		   int len, int dtype)
+		   int len)
 {
 	struct ubi_volume *vol = desc->vol;
 	struct ubi_device *ubi = vol->ubi;
@@ -515,17 +508,13 @@
 	    len > vol->usable_leb_size || len & (ubi->min_io_size - 1))
 		return -EINVAL;
 
-	if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
-	    dtype != UBI_UNKNOWN)
-		return -EINVAL;
-
 	if (vol->upd_marker)
 		return -EBADF;
 
 	if (len == 0)
 		return 0;
 
-	return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype);
+	return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len);
 }
 EXPORT_SYMBOL_GPL(ubi_leb_change);
 
@@ -562,7 +551,7 @@
 	if (err)
 		return err;
 
-	return ubi_wl_flush(ubi);
+	return ubi_wl_flush(ubi, vol->vol_id, lnum);
 }
 EXPORT_SYMBOL_GPL(ubi_leb_erase);
 
@@ -626,7 +615,6 @@
  * ubi_leb_map - map logical eraseblock to a physical eraseblock.
  * @desc: volume descriptor
  * @lnum: logical eraseblock number
- * @dtype: expected data type
  *
  * This function maps an un-mapped logical eraseblock @lnum to a physical
  * eraseblock. This means, that after a successful invocation of this
@@ -639,7 +627,7 @@
  * eraseblock is already mapped, and other negative error codes in case of
  * other failures.
  */
-int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum)
 {
 	struct ubi_volume *vol = desc->vol;
 	struct ubi_device *ubi = vol->ubi;
@@ -652,17 +640,13 @@
 	if (lnum < 0 || lnum >= vol->reserved_pebs)
 		return -EINVAL;
 
-	if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
-	    dtype != UBI_UNKNOWN)
-		return -EINVAL;
-
 	if (vol->upd_marker)
 		return -EBADF;
 
 	if (vol->eba_tbl[lnum] >= 0)
 		return -EBADMSG;
 
-	return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+	return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0);
 }
 EXPORT_SYMBOL_GPL(ubi_leb_map);
 
@@ -720,6 +704,33 @@
 }
 EXPORT_SYMBOL_GPL(ubi_sync);
 
+/**
+ * ubi_flush - flush UBI work queue.
+ * @ubi_num: UBI device to flush work queue
+ * @vol_id: volume id to flush for
+ * @lnum: logical eraseblock number to flush for
+ *
+ * This function executes all pending works for a particular volume id / logical
+ * eraseblock number pair. If either value is set to %UBI_ALL, then it acts as
+ * a wildcard for all of the corresponding volume numbers or logical
+ * eraseblock numbers. It returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubi_flush(int ubi_num, int vol_id, int lnum)
+{
+	struct ubi_device *ubi;
+	int err = 0;
+
+	ubi = ubi_get_device(ubi_num);
+	if (!ubi)
+		return -ENODEV;
+
+	err = ubi_wl_flush(ubi, vol_id, lnum);
+	ubi_put_device(ubi);
+	return err;
+}
+EXPORT_SYMBOL_GPL(ubi_flush);
+
 BLOCKING_NOTIFIER_HEAD(ubi_notifiers);
 
 /**
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
deleted file mode 100644
index 12c43b4..0000000
--- a/drivers/mtd/ubi/scan.c
+++ /dev/null
@@ -1,1605 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006
- *
- * 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
- *
- * Author: Artem Bityutskiy (Битюцкий Артём)
- */
-
-/*
- * UBI scanning sub-system.
- *
- * This sub-system is responsible for scanning the flash media, checking UBI
- * headers and providing complete information about the UBI flash image.
- *
- * The scanning information is represented by a &struct ubi_scan_info' object.
- * Information about found volumes is represented by &struct ubi_scan_volume
- * objects which are kept in volume RB-tree with root at the @volumes field.
- * The RB-tree is indexed by the volume ID.
- *
- * Scanned logical eraseblocks are represented by &struct ubi_scan_leb objects.
- * These objects are kept in per-volume RB-trees with the root at the
- * corresponding &struct ubi_scan_volume object. To put it differently, we keep
- * an RB-tree of per-volume objects and each of these objects is the root of
- * RB-tree of per-eraseblock objects.
- *
- * Corrupted physical eraseblocks are put to the @corr list, free physical
- * eraseblocks are put to the @free list and the physical eraseblock to be
- * erased are put to the @erase list.
- *
- * About corruptions
- * ~~~~~~~~~~~~~~~~~
- *
- * UBI protects EC and VID headers with CRC-32 checksums, so it can detect
- * whether the headers are corrupted or not. Sometimes UBI also protects the
- * data with CRC-32, e.g., when it executes the atomic LEB change operation, or
- * when it moves the contents of a PEB for wear-leveling purposes.
- *
- * UBI tries to distinguish between 2 types of corruptions.
- *
- * 1. Corruptions caused by power cuts. These are expected corruptions and UBI
- * tries to handle them gracefully, without printing too many warnings and
- * error messages. The idea is that we do not lose important data in these case
- * - we may lose only the data which was being written to the media just before
- * the power cut happened, and the upper layers (e.g., UBIFS) are supposed to
- * handle such data losses (e.g., by using the FS journal).
- *
- * When UBI detects a corruption (CRC-32 mismatch) in a PEB, and it looks like
- * the reason is a power cut, UBI puts this PEB to the @erase list, and all
- * PEBs in the @erase list are scheduled for erasure later.
- *
- * 2. Unexpected corruptions which are not caused by power cuts. During
- * scanning, such PEBs are put to the @corr list and UBI preserves them.
- * Obviously, this lessens the amount of available PEBs, and if at some  point
- * UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly informs
- * about such PEBs every time the MTD device is attached.
- *
- * However, it is difficult to reliably distinguish between these types of
- * corruptions and UBI's strategy is as follows. UBI assumes corruption type 2
- * if the VID header is corrupted and the data area does not contain all 0xFFs,
- * and there were no bit-flips or integrity errors while reading the data area.
- * Otherwise UBI assumes corruption type 1. So the decision criteria are as
- * follows.
- *   o If the data area contains only 0xFFs, there is no data, and it is safe
- *     to just erase this PEB - this is corruption type 1.
- *   o If the data area has bit-flips or data integrity errors (ECC errors on
- *     NAND), it is probably a PEB which was being erased when power cut
- *     happened, so this is corruption type 1. However, this is just a guess,
- *     which might be wrong.
- *   o Otherwise this it corruption type 2.
- */
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/crc32.h>
-#include <linux/math64.h>
-#include <linux/random.h>
-#include "ubi.h"
-
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
-#else
-#define paranoid_check_si(ubi, si) 0
-#endif
-
-/* Temporary variables used during scanning */
-static struct ubi_ec_hdr *ech;
-static struct ubi_vid_hdr *vidh;
-
-/**
- * add_to_list - add physical eraseblock to a list.
- * @si: scanning information
- * @pnum: physical eraseblock number to add
- * @ec: erase counter of the physical eraseblock
- * @to_head: if not zero, add to the head of the list
- * @list: the list to add to
- *
- * This function adds physical eraseblock @pnum to free, erase, or alien lists.
- * If @to_head is not zero, PEB will be added to the head of the list, which
- * basically means it will be processed first later. E.g., we add corrupted
- * PEBs (corrupted due to power cuts) to the head of the erase list to make
- * sure we erase them first and get rid of corruptions ASAP. This function
- * returns zero in case of success and a negative error code in case of
- * failure.
- */
-static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, int to_head,
-		       struct list_head *list)
-{
-	struct ubi_scan_leb *seb;
-
-	if (list == &si->free) {
-		dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
-	} else if (list == &si->erase) {
-		dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
-	} else if (list == &si->alien) {
-		dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
-		si->alien_peb_count += 1;
-	} else
-		BUG();
-
-	seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
-	if (!seb)
-		return -ENOMEM;
-
-	seb->pnum = pnum;
-	seb->ec = ec;
-	if (to_head)
-		list_add(&seb->u.list, list);
-	else
-		list_add_tail(&seb->u.list, list);
-	return 0;
-}
-
-/**
- * add_corrupted - add a corrupted physical eraseblock.
- * @si: scanning information
- * @pnum: physical eraseblock number to add
- * @ec: erase counter of the physical eraseblock
- *
- * This function adds corrupted physical eraseblock @pnum to the 'corr' list.
- * The corruption was presumably not caused by a power cut. Returns zero in
- * case of success and a negative error code in case of failure.
- */
-static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec)
-{
-	struct ubi_scan_leb *seb;
-
-	dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
-
-	seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
-	if (!seb)
-		return -ENOMEM;
-
-	si->corr_peb_count += 1;
-	seb->pnum = pnum;
-	seb->ec = ec;
-	list_add(&seb->u.list, &si->corr);
-	return 0;
-}
-
-/**
- * validate_vid_hdr - check volume identifier header.
- * @vid_hdr: the volume identifier header to check
- * @sv: information about the volume this logical eraseblock belongs to
- * @pnum: physical eraseblock number the VID header came from
- *
- * This function checks that data stored in @vid_hdr is consistent. Returns
- * non-zero if an inconsistency was found and zero if not.
- *
- * Note, UBI does sanity check of everything it reads from the flash media.
- * Most of the checks are done in the I/O sub-system. Here we check that the
- * information in the VID header is consistent to the information in other VID
- * headers of the same volume.
- */
-static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
-			    const struct ubi_scan_volume *sv, int pnum)
-{
-	int vol_type = vid_hdr->vol_type;
-	int vol_id = be32_to_cpu(vid_hdr->vol_id);
-	int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
-	int data_pad = be32_to_cpu(vid_hdr->data_pad);
-
-	if (sv->leb_count != 0) {
-		int sv_vol_type;
-
-		/*
-		 * This is not the first logical eraseblock belonging to this
-		 * volume. Ensure that the data in its VID header is consistent
-		 * to the data in previous logical eraseblock headers.
-		 */
-
-		if (vol_id != sv->vol_id) {
-			dbg_err("inconsistent vol_id");
-			goto bad;
-		}
-
-		if (sv->vol_type == UBI_STATIC_VOLUME)
-			sv_vol_type = UBI_VID_STATIC;
-		else
-			sv_vol_type = UBI_VID_DYNAMIC;
-
-		if (vol_type != sv_vol_type) {
-			dbg_err("inconsistent vol_type");
-			goto bad;
-		}
-
-		if (used_ebs != sv->used_ebs) {
-			dbg_err("inconsistent used_ebs");
-			goto bad;
-		}
-
-		if (data_pad != sv->data_pad) {
-			dbg_err("inconsistent data_pad");
-			goto bad;
-		}
-	}
-
-	return 0;
-
-bad:
-	ubi_err("inconsistent VID header at PEB %d", pnum);
-	ubi_dbg_dump_vid_hdr(vid_hdr);
-	ubi_dbg_dump_sv(sv);
-	return -EINVAL;
-}
-
-/**
- * add_volume - add volume to the scanning information.
- * @si: scanning information
- * @vol_id: ID of the volume to add
- * @pnum: physical eraseblock number
- * @vid_hdr: volume identifier header
- *
- * If the volume corresponding to the @vid_hdr logical eraseblock is already
- * present in the scanning information, this function does nothing. Otherwise
- * it adds corresponding volume to the scanning information. Returns a pointer
- * to the scanning volume object in case of success and a negative error code
- * in case of failure.
- */
-static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
-					  int pnum,
-					  const struct ubi_vid_hdr *vid_hdr)
-{
-	struct ubi_scan_volume *sv;
-	struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
-
-	ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
-
-	/* Walk the volume RB-tree to look if this volume is already present */
-	while (*p) {
-		parent = *p;
-		sv = rb_entry(parent, struct ubi_scan_volume, rb);
-
-		if (vol_id == sv->vol_id)
-			return sv;
-
-		if (vol_id > sv->vol_id)
-			p = &(*p)->rb_left;
-		else
-			p = &(*p)->rb_right;
-	}
-
-	/* The volume is absent - add it */
-	sv = kmalloc(sizeof(struct ubi_scan_volume), GFP_KERNEL);
-	if (!sv)
-		return ERR_PTR(-ENOMEM);
-
-	sv->highest_lnum = sv->leb_count = 0;
-	sv->vol_id = vol_id;
-	sv->root = RB_ROOT;
-	sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
-	sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
-	sv->compat = vid_hdr->compat;
-	sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
-							    : UBI_STATIC_VOLUME;
-	if (vol_id > si->highest_vol_id)
-		si->highest_vol_id = vol_id;
-
-	rb_link_node(&sv->rb, parent, p);
-	rb_insert_color(&sv->rb, &si->volumes);
-	si->vols_found += 1;
-	dbg_bld("added volume %d", vol_id);
-	return sv;
-}
-
-/**
- * compare_lebs - find out which logical eraseblock is newer.
- * @ubi: UBI device description object
- * @seb: first logical eraseblock to compare
- * @pnum: physical eraseblock number of the second logical eraseblock to
- * compare
- * @vid_hdr: volume identifier header of the second logical eraseblock
- *
- * This function compares 2 copies of a LEB and informs which one is newer. In
- * case of success this function returns a positive value, in case of failure, a
- * negative error code is returned. The success return codes use the following
- * bits:
- *     o bit 0 is cleared: the first PEB (described by @seb) is newer than the
- *       second PEB (described by @pnum and @vid_hdr);
- *     o bit 0 is set: the second PEB is newer;
- *     o bit 1 is cleared: no bit-flips were detected in the newer LEB;
- *     o bit 1 is set: bit-flips were detected in the newer LEB;
- *     o bit 2 is cleared: the older LEB is not corrupted;
- *     o bit 2 is set: the older LEB is corrupted.
- */
-static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
-			int pnum, const struct ubi_vid_hdr *vid_hdr)
-{
-	void *buf;
-	int len, err, second_is_newer, bitflips = 0, corrupted = 0;
-	uint32_t data_crc, crc;
-	struct ubi_vid_hdr *vh = NULL;
-	unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
-
-	if (sqnum2 == seb->sqnum) {
-		/*
-		 * This must be a really ancient UBI image which has been
-		 * created before sequence numbers support has been added. At
-		 * that times we used 32-bit LEB versions stored in logical
-		 * eraseblocks. That was before UBI got into mainline. We do not
-		 * support these images anymore. Well, those images still work,
-		 * but only if no unclean reboots happened.
-		 */
-		ubi_err("unsupported on-flash UBI format\n");
-		return -EINVAL;
-	}
-
-	/* Obviously the LEB with lower sequence counter is older */
-	second_is_newer = !!(sqnum2 > seb->sqnum);
-
-	/*
-	 * Now we know which copy is newer. If the copy flag of the PEB with
-	 * newer version is not set, then we just return, otherwise we have to
-	 * check data CRC. For the second PEB we already have the VID header,
-	 * for the first one - we'll need to re-read it from flash.
-	 *
-	 * Note: this may be optimized so that we wouldn't read twice.
-	 */
-
-	if (second_is_newer) {
-		if (!vid_hdr->copy_flag) {
-			/* It is not a copy, so it is newer */
-			dbg_bld("second PEB %d is newer, copy_flag is unset",
-				pnum);
-			return 1;
-		}
-	} else {
-		if (!seb->copy_flag) {
-			/* It is not a copy, so it is newer */
-			dbg_bld("first PEB %d is newer, copy_flag is unset",
-				pnum);
-			return bitflips << 1;
-		}
-
-		vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
-		if (!vh)
-			return -ENOMEM;
-
-		pnum = seb->pnum;
-		err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
-		if (err) {
-			if (err == UBI_IO_BITFLIPS)
-				bitflips = 1;
-			else {
-				dbg_err("VID of PEB %d header is bad, but it "
-					"was OK earlier, err %d", pnum, err);
-				if (err > 0)
-					err = -EIO;
-
-				goto out_free_vidh;
-			}
-		}
-
-		vid_hdr = vh;
-	}
-
-	/* Read the data of the copy and check the CRC */
-
-	len = be32_to_cpu(vid_hdr->data_size);
-	buf = vmalloc(len);
-	if (!buf) {
-		err = -ENOMEM;
-		goto out_free_vidh;
-	}
-
-	err = ubi_io_read_data(ubi, buf, pnum, 0, len);
-	if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
-		goto out_free_buf;
-
-	data_crc = be32_to_cpu(vid_hdr->data_crc);
-	crc = crc32(UBI_CRC32_INIT, buf, len);
-	if (crc != data_crc) {
-		dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
-			pnum, crc, data_crc);
-		corrupted = 1;
-		bitflips = 0;
-		second_is_newer = !second_is_newer;
-	} else {
-		dbg_bld("PEB %d CRC is OK", pnum);
-		bitflips = !!err;
-	}
-
-	vfree(buf);
-	ubi_free_vid_hdr(ubi, vh);
-
-	if (second_is_newer)
-		dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
-	else
-		dbg_bld("first PEB %d is newer, copy_flag is set", pnum);
-
-	return second_is_newer | (bitflips << 1) | (corrupted << 2);
-
-out_free_buf:
-	vfree(buf);
-out_free_vidh:
-	ubi_free_vid_hdr(ubi, vh);
-	return err;
-}
-
-/**
- * ubi_scan_add_used - add physical eraseblock to the scanning information.
- * @ubi: UBI device description object
- * @si: scanning information
- * @pnum: the physical eraseblock number
- * @ec: erase counter
- * @vid_hdr: the volume identifier header
- * @bitflips: if bit-flips were detected when this physical eraseblock was read
- *
- * This function adds information about a used physical eraseblock to the
- * 'used' tree of the corresponding volume. The function is rather complex
- * because it has to handle cases when this is not the first physical
- * eraseblock belonging to the same logical eraseblock, and the newer one has
- * to be picked, while the older one has to be dropped. This function returns
- * zero in case of success and a negative error code in case of failure.
- */
-int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
-		      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
-		      int bitflips)
-{
-	int err, vol_id, lnum;
-	unsigned long long sqnum;
-	struct ubi_scan_volume *sv;
-	struct ubi_scan_leb *seb;
-	struct rb_node **p, *parent = NULL;
-
-	vol_id = be32_to_cpu(vid_hdr->vol_id);
-	lnum = be32_to_cpu(vid_hdr->lnum);
-	sqnum = be64_to_cpu(vid_hdr->sqnum);
-
-	dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, bitflips %d",
-		pnum, vol_id, lnum, ec, sqnum, bitflips);
-
-	sv = add_volume(si, vol_id, pnum, vid_hdr);
-	if (IS_ERR(sv))
-		return PTR_ERR(sv);
-
-	if (si->max_sqnum < sqnum)
-		si->max_sqnum = sqnum;
-
-	/*
-	 * Walk the RB-tree of logical eraseblocks of volume @vol_id to look
-	 * if this is the first instance of this logical eraseblock or not.
-	 */
-	p = &sv->root.rb_node;
-	while (*p) {
-		int cmp_res;
-
-		parent = *p;
-		seb = rb_entry(parent, struct ubi_scan_leb, u.rb);
-		if (lnum != seb->lnum) {
-			if (lnum < seb->lnum)
-				p = &(*p)->rb_left;
-			else
-				p = &(*p)->rb_right;
-			continue;
-		}
-
-		/*
-		 * There is already a physical eraseblock describing the same
-		 * logical eraseblock present.
-		 */
-
-		dbg_bld("this LEB already exists: PEB %d, sqnum %llu, "
-			"EC %d", seb->pnum, seb->sqnum, seb->ec);
-
-		/*
-		 * Make sure that the logical eraseblocks have different
-		 * sequence numbers. Otherwise the image is bad.
-		 *
-		 * However, if the sequence number is zero, we assume it must
-		 * be an ancient UBI image from the era when UBI did not have
-		 * sequence numbers. We still can attach these images, unless
-		 * there is a need to distinguish between old and new
-		 * eraseblocks, in which case we'll refuse the image in
-		 * 'compare_lebs()'. In other words, we attach old clean
-		 * images, but refuse attaching old images with duplicated
-		 * logical eraseblocks because there was an unclean reboot.
-		 */
-		if (seb->sqnum == sqnum && sqnum != 0) {
-			ubi_err("two LEBs with same sequence number %llu",
-				sqnum);
-			ubi_dbg_dump_seb(seb, 0);
-			ubi_dbg_dump_vid_hdr(vid_hdr);
-			return -EINVAL;
-		}
-
-		/*
-		 * Now we have to drop the older one and preserve the newer
-		 * one.
-		 */
-		cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr);
-		if (cmp_res < 0)
-			return cmp_res;
-
-		if (cmp_res & 1) {
-			/*
-			 * This logical eraseblock is newer than the one
-			 * found earlier.
-			 */
-			err = validate_vid_hdr(vid_hdr, sv, pnum);
-			if (err)
-				return err;
-
-			err = add_to_list(si, seb->pnum, seb->ec, cmp_res & 4,
-					  &si->erase);
-			if (err)
-				return err;
-
-			seb->ec = ec;
-			seb->pnum = pnum;
-			seb->scrub = ((cmp_res & 2) || bitflips);
-			seb->copy_flag = vid_hdr->copy_flag;
-			seb->sqnum = sqnum;
-
-			if (sv->highest_lnum == lnum)
-				sv->last_data_size =
-					be32_to_cpu(vid_hdr->data_size);
-
-			return 0;
-		} else {
-			/*
-			 * This logical eraseblock is older than the one found
-			 * previously.
-			 */
-			return add_to_list(si, pnum, ec, cmp_res & 4,
-					   &si->erase);
-		}
-	}
-
-	/*
-	 * We've met this logical eraseblock for the first time, add it to the
-	 * scanning information.
-	 */
-
-	err = validate_vid_hdr(vid_hdr, sv, pnum);
-	if (err)
-		return err;
-
-	seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
-	if (!seb)
-		return -ENOMEM;
-
-	seb->ec = ec;
-	seb->pnum = pnum;
-	seb->lnum = lnum;
-	seb->scrub = bitflips;
-	seb->copy_flag = vid_hdr->copy_flag;
-	seb->sqnum = sqnum;
-
-	if (sv->highest_lnum <= lnum) {
-		sv->highest_lnum = lnum;
-		sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
-	}
-
-	sv->leb_count += 1;
-	rb_link_node(&seb->u.rb, parent, p);
-	rb_insert_color(&seb->u.rb, &sv->root);
-	return 0;
-}
-
-/**
- * ubi_scan_find_sv - find volume in the scanning information.
- * @si: scanning information
- * @vol_id: the requested volume ID
- *
- * This function returns a pointer to the volume description or %NULL if there
- * are no data about this volume in the scanning information.
- */
-struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
-					 int vol_id)
-{
-	struct ubi_scan_volume *sv;
-	struct rb_node *p = si->volumes.rb_node;
-
-	while (p) {
-		sv = rb_entry(p, struct ubi_scan_volume, rb);
-
-		if (vol_id == sv->vol_id)
-			return sv;
-
-		if (vol_id > sv->vol_id)
-			p = p->rb_left;
-		else
-			p = p->rb_right;
-	}
-
-	return NULL;
-}
-
-/**
- * ubi_scan_find_seb - find LEB in the volume scanning information.
- * @sv: a pointer to the volume scanning information
- * @lnum: the requested logical eraseblock
- *
- * This function returns a pointer to the scanning logical eraseblock or %NULL
- * if there are no data about it in the scanning volume information.
- */
-struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
-				       int lnum)
-{
-	struct ubi_scan_leb *seb;
-	struct rb_node *p = sv->root.rb_node;
-
-	while (p) {
-		seb = rb_entry(p, struct ubi_scan_leb, u.rb);
-
-		if (lnum == seb->lnum)
-			return seb;
-
-		if (lnum > seb->lnum)
-			p = p->rb_left;
-		else
-			p = p->rb_right;
-	}
-
-	return NULL;
-}
-
-/**
- * ubi_scan_rm_volume - delete scanning information about a volume.
- * @si: scanning information
- * @sv: the volume scanning information to delete
- */
-void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
-{
-	struct rb_node *rb;
-	struct ubi_scan_leb *seb;
-
-	dbg_bld("remove scanning information about volume %d", sv->vol_id);
-
-	while ((rb = rb_first(&sv->root))) {
-		seb = rb_entry(rb, struct ubi_scan_leb, u.rb);
-		rb_erase(&seb->u.rb, &sv->root);
-		list_add_tail(&seb->u.list, &si->erase);
-	}
-
-	rb_erase(&sv->rb, &si->volumes);
-	kfree(sv);
-	si->vols_found -= 1;
-}
-
-/**
- * ubi_scan_erase_peb - erase a physical eraseblock.
- * @ubi: UBI device description object
- * @si: scanning information
- * @pnum: physical eraseblock number to erase;
- * @ec: erase counter value to write (%UBI_SCAN_UNKNOWN_EC if it is unknown)
- *
- * This function erases physical eraseblock 'pnum', and writes the erase
- * counter header to it. This function should only be used on UBI device
- * initialization stages, when the EBA sub-system had not been yet initialized.
- * This function returns zero in case of success and a negative error code in
- * case of failure.
- */
-int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
-		       int pnum, int ec)
-{
-	int err;
-	struct ubi_ec_hdr *ec_hdr;
-
-	if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
-		/*
-		 * Erase counter overflow. Upgrade UBI and use 64-bit
-		 * erase counters internally.
-		 */
-		ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec);
-		return -EINVAL;
-	}
-
-	ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
-	if (!ec_hdr)
-		return -ENOMEM;
-
-	ec_hdr->ec = cpu_to_be64(ec);
-
-	err = ubi_io_sync_erase(ubi, pnum, 0);
-	if (err < 0)
-		goto out_free;
-
-	err = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr);
-
-out_free:
-	kfree(ec_hdr);
-	return err;
-}
-
-/**
- * ubi_scan_get_free_peb - get a free physical eraseblock.
- * @ubi: UBI device description object
- * @si: scanning information
- *
- * This function returns a free physical eraseblock. It is supposed to be
- * called on the UBI initialization stages when the wear-leveling sub-system is
- * not initialized yet. This function picks a physical eraseblocks from one of
- * the lists, writes the EC header if it is needed, and removes it from the
- * list.
- *
- * This function returns scanning physical eraseblock information in case of
- * success and an error code in case of failure.
- */
-struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
-					   struct ubi_scan_info *si)
-{
-	int err = 0;
-	struct ubi_scan_leb *seb, *tmp_seb;
-
-	if (!list_empty(&si->free)) {
-		seb = list_entry(si->free.next, struct ubi_scan_leb, u.list);
-		list_del(&seb->u.list);
-		dbg_bld("return free PEB %d, EC %d", seb->pnum, seb->ec);
-		return seb;
-	}
-
-	/*
-	 * We try to erase the first physical eraseblock from the erase list
-	 * and pick it if we succeed, or try to erase the next one if not. And
-	 * so forth. We don't want to take care about bad eraseblocks here -
-	 * they'll be handled later.
-	 */
-	list_for_each_entry_safe(seb, tmp_seb, &si->erase, u.list) {
-		if (seb->ec == UBI_SCAN_UNKNOWN_EC)
-			seb->ec = si->mean_ec;
-
-		err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1);
-		if (err)
-			continue;
-
-		seb->ec += 1;
-		list_del(&seb->u.list);
-		dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec);
-		return seb;
-	}
-
-	ubi_err("no free eraseblocks");
-	return ERR_PTR(-ENOSPC);
-}
-
-/**
- * check_corruption - check the data area of PEB.
- * @ubi: UBI device description object
- * @vid_hrd: the (corrupted) VID header of this PEB
- * @pnum: the physical eraseblock number to check
- *
- * This is a helper function which is used to distinguish between VID header
- * corruptions caused by power cuts and other reasons. If the PEB contains only
- * 0xFF bytes in the data area, the VID header is most probably corrupted
- * because of a power cut (%0 is returned in this case). Otherwise, it was
- * probably corrupted for some other reasons (%1 is returned in this case). A
- * negative error code is returned if a read error occurred.
- *
- * If the corruption reason was a power cut, UBI can safely erase this PEB.
- * Otherwise, it should preserve it to avoid possibly destroying important
- * information.
- */
-static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
-			    int pnum)
-{
-	int err;
-
-	mutex_lock(&ubi->buf_mutex);
-	memset(ubi->peb_buf, 0x00, ubi->leb_size);
-
-	err = ubi_io_read(ubi, ubi->peb_buf, pnum, ubi->leb_start,
-			  ubi->leb_size);
-	if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
-		/*
-		 * Bit-flips or integrity errors while reading the data area.
-		 * It is difficult to say for sure what type of corruption is
-		 * this, but presumably a power cut happened while this PEB was
-		 * erased, so it became unstable and corrupted, and should be
-		 * erased.
-		 */
-		err = 0;
-		goto out_unlock;
-	}
-
-	if (err)
-		goto out_unlock;
-
-	if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size))
-		goto out_unlock;
-
-	ubi_err("PEB %d contains corrupted VID header, and the data does not "
-		"contain all 0xFF, this may be a non-UBI PEB or a severe VID "
-		"header corruption which requires manual inspection", pnum);
-	ubi_dbg_dump_vid_hdr(vid_hdr);
-	dbg_msg("hexdump of PEB %d offset %d, length %d",
-		pnum, ubi->leb_start, ubi->leb_size);
-	ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
-			       ubi->peb_buf, ubi->leb_size, 1);
-	err = 1;
-
-out_unlock:
-	mutex_unlock(&ubi->buf_mutex);
-	return err;
-}
-
-/**
- * process_eb - read, check UBI headers, and add them to scanning information.
- * @ubi: UBI device description object
- * @si: scanning information
- * @pnum: the physical eraseblock number
- *
- * This function returns a zero if the physical eraseblock was successfully
- * handled and a negative error code in case of failure.
- */
-static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
-		      int pnum)
-{
-	long long uninitialized_var(ec);
-	int err, bitflips = 0, vol_id, ec_err = 0;
-
-	dbg_bld("scan PEB %d", pnum);
-
-	/* Skip bad physical eraseblocks */
-	err = ubi_io_is_bad(ubi, pnum);
-	if (err < 0)
-		return err;
-	else if (err) {
-		/*
-		 * FIXME: this is actually duty of the I/O sub-system to
-		 * initialize this, but MTD does not provide enough
-		 * information.
-		 */
-		si->bad_peb_count += 1;
-		return 0;
-	}
-
-	err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
-	if (err < 0)
-		return err;
-	switch (err) {
-	case 0:
-		break;
-	case UBI_IO_BITFLIPS:
-		bitflips = 1;
-		break;
-	case UBI_IO_FF:
-		si->empty_peb_count += 1;
-		return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 0,
-				   &si->erase);
-	case UBI_IO_FF_BITFLIPS:
-		si->empty_peb_count += 1;
-		return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 1,
-				   &si->erase);
-	case UBI_IO_BAD_HDR_EBADMSG:
-	case UBI_IO_BAD_HDR:
-		/*
-		 * We have to also look at the VID header, possibly it is not
-		 * corrupted. Set %bitflips flag in order to make this PEB be
-		 * moved and EC be re-created.
-		 */
-		ec_err = err;
-		ec = UBI_SCAN_UNKNOWN_EC;
-		bitflips = 1;
-		break;
-	default:
-		ubi_err("'ubi_io_read_ec_hdr()' returned unknown code %d", err);
-		return -EINVAL;
-	}
-
-	if (!ec_err) {
-		int image_seq;
-
-		/* Make sure UBI version is OK */
-		if (ech->version != UBI_VERSION) {
-			ubi_err("this UBI version is %d, image version is %d",
-				UBI_VERSION, (int)ech->version);
-			return -EINVAL;
-		}
-
-		ec = be64_to_cpu(ech->ec);
-		if (ec > UBI_MAX_ERASECOUNTER) {
-			/*
-			 * Erase counter overflow. The EC headers have 64 bits
-			 * reserved, but we anyway make use of only 31 bit
-			 * values, as this seems to be enough for any existing
-			 * flash. Upgrade UBI and use 64-bit erase counters
-			 * internally.
-			 */
-			ubi_err("erase counter overflow, max is %d",
-				UBI_MAX_ERASECOUNTER);
-			ubi_dbg_dump_ec_hdr(ech);
-			return -EINVAL;
-		}
-
-		/*
-		 * Make sure that all PEBs have the same image sequence number.
-		 * This allows us to detect situations when users flash UBI
-		 * images incorrectly, so that the flash has the new UBI image
-		 * and leftovers from the old one. This feature was added
-		 * relatively recently, and the sequence number was always
-		 * zero, because old UBI implementations always set it to zero.
-		 * For this reasons, we do not panic if some PEBs have zero
-		 * sequence number, while other PEBs have non-zero sequence
-		 * number.
-		 */
-		image_seq = be32_to_cpu(ech->image_seq);
-		if (!ubi->image_seq && image_seq)
-			ubi->image_seq = image_seq;
-		if (ubi->image_seq && image_seq &&
-		    ubi->image_seq != image_seq) {
-			ubi_err("bad image sequence number %d in PEB %d, "
-				"expected %d", image_seq, pnum, ubi->image_seq);
-			ubi_dbg_dump_ec_hdr(ech);
-			return -EINVAL;
-		}
-	}
-
-	/* OK, we've done with the EC header, let's look at the VID header */
-
-	err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);
-	if (err < 0)
-		return err;
-	switch (err) {
-	case 0:
-		break;
-	case UBI_IO_BITFLIPS:
-		bitflips = 1;
-		break;
-	case UBI_IO_BAD_HDR_EBADMSG:
-		if (ec_err == UBI_IO_BAD_HDR_EBADMSG)
-			/*
-			 * Both EC and VID headers are corrupted and were read
-			 * with data integrity error, probably this is a bad
-			 * PEB, bit it is not marked as bad yet. This may also
-			 * be a result of power cut during erasure.
-			 */
-			si->maybe_bad_peb_count += 1;
-	case UBI_IO_BAD_HDR:
-		if (ec_err)
-			/*
-			 * Both headers are corrupted. There is a possibility
-			 * that this a valid UBI PEB which has corresponding
-			 * LEB, but the headers are corrupted. However, it is
-			 * impossible to distinguish it from a PEB which just
-			 * contains garbage because of a power cut during erase
-			 * operation. So we just schedule this PEB for erasure.
-			 *
-			 * Besides, in case of NOR flash, we deliberately
-			 * corrupt both headers because NOR flash erasure is
-			 * slow and can start from the end.
-			 */
-			err = 0;
-		else
-			/*
-			 * The EC was OK, but the VID header is corrupted. We
-			 * have to check what is in the data area.
-			 */
-			err = check_corruption(ubi, vidh, pnum);
-
-		if (err < 0)
-			return err;
-		else if (!err)
-			/* This corruption is caused by a power cut */
-			err = add_to_list(si, pnum, ec, 1, &si->erase);
-		else
-			/* This is an unexpected corruption */
-			err = add_corrupted(si, pnum, ec);
-		if (err)
-			return err;
-		goto adjust_mean_ec;
-	case UBI_IO_FF_BITFLIPS:
-		err = add_to_list(si, pnum, ec, 1, &si->erase);
-		if (err)
-			return err;
-		goto adjust_mean_ec;
-	case UBI_IO_FF:
-		if (ec_err)
-			err = add_to_list(si, pnum, ec, 1, &si->erase);
-		else
-			err = add_to_list(si, pnum, ec, 0, &si->free);
-		if (err)
-			return err;
-		goto adjust_mean_ec;
-	default:
-		ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d",
-			err);
-		return -EINVAL;
-	}
-
-	vol_id = be32_to_cpu(vidh->vol_id);
-	if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
-		int lnum = be32_to_cpu(vidh->lnum);
-
-		/* Unsupported internal volume */
-		switch (vidh->compat) {
-		case UBI_COMPAT_DELETE:
-			ubi_msg("\"delete\" compatible internal volume %d:%d"
-				" found, will remove it", vol_id, lnum);
-			err = add_to_list(si, pnum, ec, 1, &si->erase);
-			if (err)
-				return err;
-			return 0;
-
-		case UBI_COMPAT_RO:
-			ubi_msg("read-only compatible internal volume %d:%d"
-				" found, switch to read-only mode",
-				vol_id, lnum);
-			ubi->ro_mode = 1;
-			break;
-
-		case UBI_COMPAT_PRESERVE:
-			ubi_msg("\"preserve\" compatible internal volume %d:%d"
-				" found", vol_id, lnum);
-			err = add_to_list(si, pnum, ec, 0, &si->alien);
-			if (err)
-				return err;
-			return 0;
-
-		case UBI_COMPAT_REJECT:
-			ubi_err("incompatible internal volume %d:%d found",
-				vol_id, lnum);
-			return -EINVAL;
-		}
-	}
-
-	if (ec_err)
-		ubi_warn("valid VID header but corrupted EC header at PEB %d",
-			 pnum);
-	err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
-	if (err)
-		return err;
-
-adjust_mean_ec:
-	if (!ec_err) {
-		si->ec_sum += ec;
-		si->ec_count += 1;
-		if (ec > si->max_ec)
-			si->max_ec = ec;
-		if (ec < si->min_ec)
-			si->min_ec = ec;
-	}
-
-	return 0;
-}
-
-/**
- * check_what_we_have - check what PEB were found by scanning.
- * @ubi: UBI device description object
- * @si: scanning information
- *
- * This is a helper function which takes a look what PEBs were found by
- * scanning, and decides whether the flash is empty and should be formatted and
- * whether there are too many corrupted PEBs and we should not attach this
- * MTD device. Returns zero if we should proceed with attaching the MTD device,
- * and %-EINVAL if we should not.
- */
-static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
-{
-	struct ubi_scan_leb *seb;
-	int max_corr, peb_count;
-
-	peb_count = ubi->peb_count - si->bad_peb_count - si->alien_peb_count;
-	max_corr = peb_count / 20 ?: 8;
-
-	/*
-	 * Few corrupted PEBs is not a problem and may be just a result of
-	 * unclean reboots. However, many of them may indicate some problems
-	 * with the flash HW or driver.
-	 */
-	if (si->corr_peb_count) {
-		ubi_err("%d PEBs are corrupted and preserved",
-			si->corr_peb_count);
-		printk(KERN_ERR "Corrupted PEBs are:");
-		list_for_each_entry(seb, &si->corr, u.list)
-			printk(KERN_CONT " %d", seb->pnum);
-		printk(KERN_CONT "\n");
-
-		/*
-		 * If too many PEBs are corrupted, we refuse attaching,
-		 * otherwise, only print a warning.
-		 */
-		if (si->corr_peb_count >= max_corr) {
-			ubi_err("too many corrupted PEBs, refusing");
-			return -EINVAL;
-		}
-	}
-
-	if (si->empty_peb_count + si->maybe_bad_peb_count == peb_count) {
-		/*
-		 * All PEBs are empty, or almost all - a couple PEBs look like
-		 * they may be bad PEBs which were not marked as bad yet.
-		 *
-		 * This piece of code basically tries to distinguish between
-		 * the following situations:
-		 *
-		 * 1. Flash is empty, but there are few bad PEBs, which are not
-		 *    marked as bad so far, and which were read with error. We
-		 *    want to go ahead and format this flash. While formatting,
-		 *    the faulty PEBs will probably be marked as bad.
-		 *
-		 * 2. Flash contains non-UBI data and we do not want to format
-		 *    it and destroy possibly important information.
-		 */
-		if (si->maybe_bad_peb_count <= 2) {
-			si->is_empty = 1;
-			ubi_msg("empty MTD device detected");
-			get_random_bytes(&ubi->image_seq,
-					 sizeof(ubi->image_seq));
-		} else {
-			ubi_err("MTD device is not UBI-formatted and possibly "
-				"contains non-UBI data - refusing it");
-			return -EINVAL;
-		}
-
-	}
-
-	return 0;
-}
-
-/**
- * ubi_scan - scan an MTD device.
- * @ubi: UBI device description object
- *
- * This function does full scanning of an MTD device and returns complete
- * information about it. In case of failure, an error code is returned.
- */
-struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
-{
-	int err, pnum;
-	struct rb_node *rb1, *rb2;
-	struct ubi_scan_volume *sv;
-	struct ubi_scan_leb *seb;
-	struct ubi_scan_info *si;
-
-	si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL);
-	if (!si)
-		return ERR_PTR(-ENOMEM);
-
-	INIT_LIST_HEAD(&si->corr);
-	INIT_LIST_HEAD(&si->free);
-	INIT_LIST_HEAD(&si->erase);
-	INIT_LIST_HEAD(&si->alien);
-	si->volumes = RB_ROOT;
-
-	err = -ENOMEM;
-	si->scan_leb_slab = kmem_cache_create("ubi_scan_leb_slab",
-					      sizeof(struct ubi_scan_leb),
-					      0, 0, NULL);
-	if (!si->scan_leb_slab)
-		goto out_si;
-
-	ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
-	if (!ech)
-		goto out_si;
-
-	vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
-	if (!vidh)
-		goto out_ech;
-
-	for (pnum = 0; pnum < ubi->peb_count; pnum++) {
-		cond_resched();
-
-		dbg_gen("process PEB %d", pnum);
-		err = process_eb(ubi, si, pnum);
-		if (err < 0)
-			goto out_vidh;
-	}
-
-	dbg_msg("scanning is finished");
-
-	/* Calculate mean erase counter */
-	if (si->ec_count)
-		si->mean_ec = div_u64(si->ec_sum, si->ec_count);
-
-	err = check_what_we_have(ubi, si);
-	if (err)
-		goto out_vidh;
-
-	/*
-	 * In case of unknown erase counter we use the mean erase counter
-	 * value.
-	 */
-	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
-		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
-			if (seb->ec == UBI_SCAN_UNKNOWN_EC)
-				seb->ec = si->mean_ec;
-	}
-
-	list_for_each_entry(seb, &si->free, u.list) {
-		if (seb->ec == UBI_SCAN_UNKNOWN_EC)
-			seb->ec = si->mean_ec;
-	}
-
-	list_for_each_entry(seb, &si->corr, u.list)
-		if (seb->ec == UBI_SCAN_UNKNOWN_EC)
-			seb->ec = si->mean_ec;
-
-	list_for_each_entry(seb, &si->erase, u.list)
-		if (seb->ec == UBI_SCAN_UNKNOWN_EC)
-			seb->ec = si->mean_ec;
-
-	err = paranoid_check_si(ubi, si);
-	if (err)
-		goto out_vidh;
-
-	ubi_free_vid_hdr(ubi, vidh);
-	kfree(ech);
-
-	return si;
-
-out_vidh:
-	ubi_free_vid_hdr(ubi, vidh);
-out_ech:
-	kfree(ech);
-out_si:
-	ubi_scan_destroy_si(si);
-	return ERR_PTR(err);
-}
-
-/**
- * destroy_sv - free the scanning volume information
- * @sv: scanning volume information
- * @si: scanning information
- *
- * This function destroys the volume RB-tree (@sv->root) and the scanning
- * volume information.
- */
-static void destroy_sv(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
-{
-	struct ubi_scan_leb *seb;
-	struct rb_node *this = sv->root.rb_node;
-
-	while (this) {
-		if (this->rb_left)
-			this = this->rb_left;
-		else if (this->rb_right)
-			this = this->rb_right;
-		else {
-			seb = rb_entry(this, struct ubi_scan_leb, u.rb);
-			this = rb_parent(this);
-			if (this) {
-				if (this->rb_left == &seb->u.rb)
-					this->rb_left = NULL;
-				else
-					this->rb_right = NULL;
-			}
-
-			kmem_cache_free(si->scan_leb_slab, seb);
-		}
-	}
-	kfree(sv);
-}
-
-/**
- * ubi_scan_destroy_si - destroy scanning information.
- * @si: scanning information
- */
-void ubi_scan_destroy_si(struct ubi_scan_info *si)
-{
-	struct ubi_scan_leb *seb, *seb_tmp;
-	struct ubi_scan_volume *sv;
-	struct rb_node *rb;
-
-	list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) {
-		list_del(&seb->u.list);
-		kmem_cache_free(si->scan_leb_slab, seb);
-	}
-	list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) {
-		list_del(&seb->u.list);
-		kmem_cache_free(si->scan_leb_slab, seb);
-	}
-	list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) {
-		list_del(&seb->u.list);
-		kmem_cache_free(si->scan_leb_slab, seb);
-	}
-	list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
-		list_del(&seb->u.list);
-		kmem_cache_free(si->scan_leb_slab, seb);
-	}
-
-	/* Destroy the volume RB-tree */
-	rb = si->volumes.rb_node;
-	while (rb) {
-		if (rb->rb_left)
-			rb = rb->rb_left;
-		else if (rb->rb_right)
-			rb = rb->rb_right;
-		else {
-			sv = rb_entry(rb, struct ubi_scan_volume, rb);
-
-			rb = rb_parent(rb);
-			if (rb) {
-				if (rb->rb_left == &sv->rb)
-					rb->rb_left = NULL;
-				else
-					rb->rb_right = NULL;
-			}
-
-			destroy_sv(si, sv);
-		}
-	}
-
-	if (si->scan_leb_slab)
-		kmem_cache_destroy(si->scan_leb_slab);
-
-	kfree(si);
-}
-
-#ifdef CONFIG_MTD_UBI_DEBUG
-
-/**
- * paranoid_check_si - check the scanning information.
- * @ubi: UBI device description object
- * @si: scanning information
- *
- * This function returns zero if the scanning information is all right, and a
- * negative error code if not or if an error occurred.
- */
-static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
-{
-	int pnum, err, vols_found = 0;
-	struct rb_node *rb1, *rb2;
-	struct ubi_scan_volume *sv;
-	struct ubi_scan_leb *seb, *last_seb;
-	uint8_t *buf;
-
-	if (!ubi->dbg->chk_gen)
-		return 0;
-
-	/*
-	 * At first, check that scanning information is OK.
-	 */
-	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
-		int leb_count = 0;
-
-		cond_resched();
-
-		vols_found += 1;
-
-		if (si->is_empty) {
-			ubi_err("bad is_empty flag");
-			goto bad_sv;
-		}
-
-		if (sv->vol_id < 0 || sv->highest_lnum < 0 ||
-		    sv->leb_count < 0 || sv->vol_type < 0 || sv->used_ebs < 0 ||
-		    sv->data_pad < 0 || sv->last_data_size < 0) {
-			ubi_err("negative values");
-			goto bad_sv;
-		}
-
-		if (sv->vol_id >= UBI_MAX_VOLUMES &&
-		    sv->vol_id < UBI_INTERNAL_VOL_START) {
-			ubi_err("bad vol_id");
-			goto bad_sv;
-		}
-
-		if (sv->vol_id > si->highest_vol_id) {
-			ubi_err("highest_vol_id is %d, but vol_id %d is there",
-				si->highest_vol_id, sv->vol_id);
-			goto out;
-		}
-
-		if (sv->vol_type != UBI_DYNAMIC_VOLUME &&
-		    sv->vol_type != UBI_STATIC_VOLUME) {
-			ubi_err("bad vol_type");
-			goto bad_sv;
-		}
-
-		if (sv->data_pad > ubi->leb_size / 2) {
-			ubi_err("bad data_pad");
-			goto bad_sv;
-		}
-
-		last_seb = NULL;
-		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
-			cond_resched();
-
-			last_seb = seb;
-			leb_count += 1;
-
-			if (seb->pnum < 0 || seb->ec < 0) {
-				ubi_err("negative values");
-				goto bad_seb;
-			}
-
-			if (seb->ec < si->min_ec) {
-				ubi_err("bad si->min_ec (%d), %d found",
-					si->min_ec, seb->ec);
-				goto bad_seb;
-			}
-
-			if (seb->ec > si->max_ec) {
-				ubi_err("bad si->max_ec (%d), %d found",
-					si->max_ec, seb->ec);
-				goto bad_seb;
-			}
-
-			if (seb->pnum >= ubi->peb_count) {
-				ubi_err("too high PEB number %d, total PEBs %d",
-					seb->pnum, ubi->peb_count);
-				goto bad_seb;
-			}
-
-			if (sv->vol_type == UBI_STATIC_VOLUME) {
-				if (seb->lnum >= sv->used_ebs) {
-					ubi_err("bad lnum or used_ebs");
-					goto bad_seb;
-				}
-			} else {
-				if (sv->used_ebs != 0) {
-					ubi_err("non-zero used_ebs");
-					goto bad_seb;
-				}
-			}
-
-			if (seb->lnum > sv->highest_lnum) {
-				ubi_err("incorrect highest_lnum or lnum");
-				goto bad_seb;
-			}
-		}
-
-		if (sv->leb_count != leb_count) {
-			ubi_err("bad leb_count, %d objects in the tree",
-				leb_count);
-			goto bad_sv;
-		}
-
-		if (!last_seb)
-			continue;
-
-		seb = last_seb;
-
-		if (seb->lnum != sv->highest_lnum) {
-			ubi_err("bad highest_lnum");
-			goto bad_seb;
-		}
-	}
-
-	if (vols_found != si->vols_found) {
-		ubi_err("bad si->vols_found %d, should be %d",
-			si->vols_found, vols_found);
-		goto out;
-	}
-
-	/* Check that scanning information is correct */
-	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
-		last_seb = NULL;
-		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
-			int vol_type;
-
-			cond_resched();
-
-			last_seb = seb;
-
-			err = ubi_io_read_vid_hdr(ubi, seb->pnum, vidh, 1);
-			if (err && err != UBI_IO_BITFLIPS) {
-				ubi_err("VID header is not OK (%d)", err);
-				if (err > 0)
-					err = -EIO;
-				return err;
-			}
-
-			vol_type = vidh->vol_type == UBI_VID_DYNAMIC ?
-				   UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
-			if (sv->vol_type != vol_type) {
-				ubi_err("bad vol_type");
-				goto bad_vid_hdr;
-			}
-
-			if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
-				ubi_err("bad sqnum %llu", seb->sqnum);
-				goto bad_vid_hdr;
-			}
-
-			if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
-				ubi_err("bad vol_id %d", sv->vol_id);
-				goto bad_vid_hdr;
-			}
-
-			if (sv->compat != vidh->compat) {
-				ubi_err("bad compat %d", vidh->compat);
-				goto bad_vid_hdr;
-			}
-
-			if (seb->lnum != be32_to_cpu(vidh->lnum)) {
-				ubi_err("bad lnum %d", seb->lnum);
-				goto bad_vid_hdr;
-			}
-
-			if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
-				ubi_err("bad used_ebs %d", sv->used_ebs);
-				goto bad_vid_hdr;
-			}
-
-			if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
-				ubi_err("bad data_pad %d", sv->data_pad);
-				goto bad_vid_hdr;
-			}
-		}
-
-		if (!last_seb)
-			continue;
-
-		if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
-			ubi_err("bad highest_lnum %d", sv->highest_lnum);
-			goto bad_vid_hdr;
-		}
-
-		if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
-			ubi_err("bad last_data_size %d", sv->last_data_size);
-			goto bad_vid_hdr;
-		}
-	}
-
-	/*
-	 * Make sure that all the physical eraseblocks are in one of the lists
-	 * or trees.
-	 */
-	buf = kzalloc(ubi->peb_count, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	for (pnum = 0; pnum < ubi->peb_count; pnum++) {
-		err = ubi_io_is_bad(ubi, pnum);
-		if (err < 0) {
-			kfree(buf);
-			return err;
-		} else if (err)
-			buf[pnum] = 1;
-	}
-
-	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb)
-		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
-			buf[seb->pnum] = 1;
-
-	list_for_each_entry(seb, &si->free, u.list)
-		buf[seb->pnum] = 1;
-
-	list_for_each_entry(seb, &si->corr, u.list)
-		buf[seb->pnum] = 1;
-
-	list_for_each_entry(seb, &si->erase, u.list)
-		buf[seb->pnum] = 1;
-
-	list_for_each_entry(seb, &si->alien, u.list)
-		buf[seb->pnum] = 1;
-
-	err = 0;
-	for (pnum = 0; pnum < ubi->peb_count; pnum++)
-		if (!buf[pnum]) {
-			ubi_err("PEB %d is not referred", pnum);
-			err = 1;
-		}
-
-	kfree(buf);
-	if (err)
-		goto out;
-	return 0;
-
-bad_seb:
-	ubi_err("bad scanning information about LEB %d", seb->lnum);
-	ubi_dbg_dump_seb(seb, 0);
-	ubi_dbg_dump_sv(sv);
-	goto out;
-
-bad_sv:
-	ubi_err("bad scanning information about volume %d", sv->vol_id);
-	ubi_dbg_dump_sv(sv);
-	goto out;
-
-bad_vid_hdr:
-	ubi_err("bad scanning information about volume %d", sv->vol_id);
-	ubi_dbg_dump_sv(sv);
-	ubi_dbg_dump_vid_hdr(vidh);
-
-out:
-	ubi_dbg_dump_stack();
-	return -EINVAL;
-}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
deleted file mode 100644
index d48aef1..0000000
--- a/drivers/mtd/ubi/scan.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006
- *
- * 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
- *
- * Author: Artem Bityutskiy (Битюцкий Артём)
- */
-
-#ifndef __UBI_SCAN_H__
-#define __UBI_SCAN_H__
-
-/* The erase counter value for this physical eraseblock is unknown */
-#define UBI_SCAN_UNKNOWN_EC (-1)
-
-/**
- * struct ubi_scan_leb - scanning information about a physical eraseblock.
- * @ec: erase counter (%UBI_SCAN_UNKNOWN_EC if it is unknown)
- * @pnum: physical eraseblock number
- * @lnum: logical eraseblock number
- * @scrub: if this physical eraseblock needs scrubbing
- * @copy_flag: this LEB is a copy (@copy_flag is set in VID header of this LEB)
- * @sqnum: sequence number
- * @u: unions RB-tree or @list links
- * @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects
- * @u.list: link in one of the eraseblock lists
- *
- * One object of this type is allocated for each physical eraseblock during
- * scanning.
- */
-struct ubi_scan_leb {
-	int ec;
-	int pnum;
-	int lnum;
-	unsigned int scrub:1;
-	unsigned int copy_flag:1;
-	unsigned long long sqnum;
-	union {
-		struct rb_node rb;
-		struct list_head list;
-	} u;
-};
-
-/**
- * struct ubi_scan_volume - scanning information about a volume.
- * @vol_id: volume ID
- * @highest_lnum: highest logical eraseblock number in this volume
- * @leb_count: number of logical eraseblocks in this volume
- * @vol_type: volume type
- * @used_ebs: number of used logical eraseblocks in this volume (only for
- *            static volumes)
- * @last_data_size: amount of data in the last logical eraseblock of this
- *                  volume (always equivalent to the usable logical eraseblock
- *                  size in case of dynamic volumes)
- * @data_pad: how many bytes at the end of logical eraseblocks of this volume
- *            are not used (due to volume alignment)
- * @compat: compatibility flags of this volume
- * @rb: link in the volume RB-tree
- * @root: root of the RB-tree containing all the eraseblock belonging to this
- *        volume (&struct ubi_scan_leb objects)
- *
- * One object of this type is allocated for each volume during scanning.
- */
-struct ubi_scan_volume {
-	int vol_id;
-	int highest_lnum;
-	int leb_count;
-	int vol_type;
-	int used_ebs;
-	int last_data_size;
-	int data_pad;
-	int compat;
-	struct rb_node rb;
-	struct rb_root root;
-};
-
-/**
- * struct ubi_scan_info - UBI scanning information.
- * @volumes: root of the volume RB-tree
- * @corr: list of corrupted physical eraseblocks
- * @free: list of free physical eraseblocks
- * @erase: list of physical eraseblocks which have to be erased
- * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
- *         those belonging to "preserve"-compatible internal volumes)
- * @corr_peb_count: count of PEBs in the @corr list
- * @empty_peb_count: count of PEBs which are presumably empty (contain only
- *                   0xFF bytes)
- * @alien_peb_count: count of PEBs in the @alien list
- * @bad_peb_count: count of bad physical eraseblocks
- * @maybe_bad_peb_count: count of bad physical eraseblocks which are not marked
- *                       as bad yet, but which look like bad
- * @vols_found: number of volumes found during scanning
- * @highest_vol_id: highest volume ID
- * @is_empty: flag indicating whether the MTD device is empty or not
- * @min_ec: lowest erase counter value
- * @max_ec: highest erase counter value
- * @max_sqnum: highest sequence number value
- * @mean_ec: mean erase counter value
- * @ec_sum: a temporary variable used when calculating @mean_ec
- * @ec_count: a temporary variable used when calculating @mean_ec
- * @scan_leb_slab: slab cache for &struct ubi_scan_leb objects
- *
- * This data structure contains the result of scanning and may be used by other
- * UBI sub-systems to build final UBI data structures, further error-recovery
- * and so on.
- */
-struct ubi_scan_info {
-	struct rb_root volumes;
-	struct list_head corr;
-	struct list_head free;
-	struct list_head erase;
-	struct list_head alien;
-	int corr_peb_count;
-	int empty_peb_count;
-	int alien_peb_count;
-	int bad_peb_count;
-	int maybe_bad_peb_count;
-	int vols_found;
-	int highest_vol_id;
-	int is_empty;
-	int min_ec;
-	int max_ec;
-	unsigned long long max_sqnum;
-	int mean_ec;
-	uint64_t ec_sum;
-	int ec_count;
-	struct kmem_cache *scan_leb_slab;
-};
-
-struct ubi_device;
-struct ubi_vid_hdr;
-
-/*
- * ubi_scan_move_to_list - move a PEB from the volume tree to a list.
- *
- * @sv: volume scanning information
- * @seb: scanning eraseblock information
- * @list: the list to move to
- */
-static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
-					 struct ubi_scan_leb *seb,
-					 struct list_head *list)
-{
-		rb_erase(&seb->u.rb, &sv->root);
-		list_add_tail(&seb->u.list, list);
-}
-
-int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
-		      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
-		      int bitflips);
-struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
-					 int vol_id);
-struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
-				       int lnum);
-void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv);
-struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
-					   struct ubi_scan_info *si);
-int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
-		       int pnum, int ec);
-struct ubi_scan_info *ubi_scan(struct ubi_device *ubi);
-void ubi_scan_destroy_si(struct ubi_scan_info *si);
-
-#endif /* !__UBI_SCAN_H__ */
diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
index 6fb8ec2..468ffbc 100644
--- a/drivers/mtd/ubi/ubi-media.h
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -149,10 +149,10 @@
  * The @image_seq field is used to validate a UBI image that has been prepared
  * for a UBI device. The @image_seq value can be any value, but it must be the
  * same on all eraseblocks. UBI will ensure that all new erase counter headers
- * also contain this value, and will check the value when scanning at start-up.
+ * also contain this value, and will check the value when attaching the flash.
  * One way to make use of @image_seq is to increase its value by one every time
  * an image is flashed over an existing image, then, if the flashing does not
- * complete, UBI will detect the error when scanning.
+ * complete, UBI will detect the error when attaching the media.
  */
 struct ubi_ec_hdr {
 	__be32  magic;
@@ -298,8 +298,8 @@
 #define UBI_INT_VOL_COUNT 1
 
 /*
- * Starting ID of internal volumes. There is reserved room for 4096 internal
- * volumes.
+ * Starting ID of internal volumes: 0x7fffefff.
+ * There is reserved room for 4096 internal volumes.
  */
 #define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
 
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index b162790..a1a81c9 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -43,7 +43,6 @@
 #include <asm/pgtable.h>
 
 #include "ubi-media.h"
-#include "scan.h"
 
 /* Maximum number of supported UBI devices */
 #define UBI_MAX_DEVICES 32
@@ -66,7 +65,10 @@
 /* Background thread name pattern */
 #define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
 
-/* This marker in the EBA table means that the LEB is um-mapped */
+/*
+ * This marker in the EBA table means that the LEB is um-mapped.
+ * NOTE! It has to have the same value as %UBI_ALL.
+ */
 #define UBI_LEB_UNMAPPED -1
 
 /*
@@ -82,6 +84,9 @@
  */
 #define UBI_PROT_QUEUE_LEN 10
 
+/* The volume ID/LEB number/erase counter is unknown */
+#define UBI_UNKNOWN -1
+
 /*
  * Error codes returned by the I/O sub-system.
  *
@@ -222,8 +227,6 @@
  * @upd_ebs: how many eraseblocks are expected to be updated
  * @ch_lnum: LEB number which is being changing by the atomic LEB change
  *           operation
- * @ch_dtype: data persistency type which is being changing by the atomic LEB
- *            change operation
  * @upd_bytes: how many bytes are expected to be received for volume update or
  *             atomic LEB change
  * @upd_received: how many bytes were already received for volume update or
@@ -270,7 +273,6 @@
 
 	int upd_ebs;
 	int ch_lnum;
-	int ch_dtype;
 	long long upd_bytes;
 	long long upd_received;
 	void *upd_buf;
@@ -477,6 +479,124 @@
 	struct ubi_debug_info *dbg;
 };
 
+/**
+ * struct ubi_ainf_peb - attach information about a physical eraseblock.
+ * @ec: erase counter (%UBI_UNKNOWN if it is unknown)
+ * @pnum: physical eraseblock number
+ * @vol_id: ID of the volume this LEB belongs to
+ * @lnum: logical eraseblock number
+ * @scrub: if this physical eraseblock needs scrubbing
+ * @copy_flag: this LEB is a copy (@copy_flag is set in VID header of this LEB)
+ * @sqnum: sequence number
+ * @u: unions RB-tree or @list links
+ * @u.rb: link in the per-volume RB-tree of &struct ubi_ainf_peb objects
+ * @u.list: link in one of the eraseblock lists
+ *
+ * One object of this type is allocated for each physical eraseblock when
+ * attaching an MTD device. Note, if this PEB does not belong to any LEB /
+ * volume, the @vol_id and @lnum fields are initialized to %UBI_UNKNOWN.
+ */
+struct ubi_ainf_peb {
+	int ec;
+	int pnum;
+	int vol_id;
+	int lnum;
+	unsigned int scrub:1;
+	unsigned int copy_flag:1;
+	unsigned long long sqnum;
+	union {
+		struct rb_node rb;
+		struct list_head list;
+	} u;
+};
+
+/**
+ * struct ubi_ainf_volume - attaching information about a volume.
+ * @vol_id: volume ID
+ * @highest_lnum: highest logical eraseblock number in this volume
+ * @leb_count: number of logical eraseblocks in this volume
+ * @vol_type: volume type
+ * @used_ebs: number of used logical eraseblocks in this volume (only for
+ *            static volumes)
+ * @last_data_size: amount of data in the last logical eraseblock of this
+ *                  volume (always equivalent to the usable logical eraseblock
+ *                  size in case of dynamic volumes)
+ * @data_pad: how many bytes at the end of logical eraseblocks of this volume
+ *            are not used (due to volume alignment)
+ * @compat: compatibility flags of this volume
+ * @rb: link in the volume RB-tree
+ * @root: root of the RB-tree containing all the eraseblock belonging to this
+ *        volume (&struct ubi_ainf_peb objects)
+ *
+ * One object of this type is allocated for each volume when attaching an MTD
+ * device.
+ */
+struct ubi_ainf_volume {
+	int vol_id;
+	int highest_lnum;
+	int leb_count;
+	int vol_type;
+	int used_ebs;
+	int last_data_size;
+	int data_pad;
+	int compat;
+	struct rb_node rb;
+	struct rb_root root;
+};
+
+/**
+ * struct ubi_attach_info - MTD device attaching information.
+ * @volumes: root of the volume RB-tree
+ * @corr: list of corrupted physical eraseblocks
+ * @free: list of free physical eraseblocks
+ * @erase: list of physical eraseblocks which have to be erased
+ * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
+ *         those belonging to "preserve"-compatible internal volumes)
+ * @corr_peb_count: count of PEBs in the @corr list
+ * @empty_peb_count: count of PEBs which are presumably empty (contain only
+ *                   0xFF bytes)
+ * @alien_peb_count: count of PEBs in the @alien list
+ * @bad_peb_count: count of bad physical eraseblocks
+ * @maybe_bad_peb_count: count of bad physical eraseblocks which are not marked
+ *                       as bad yet, but which look like bad
+ * @vols_found: number of volumes found
+ * @highest_vol_id: highest volume ID
+ * @is_empty: flag indicating whether the MTD device is empty or not
+ * @min_ec: lowest erase counter value
+ * @max_ec: highest erase counter value
+ * @max_sqnum: highest sequence number value
+ * @mean_ec: mean erase counter value
+ * @ec_sum: a temporary variable used when calculating @mean_ec
+ * @ec_count: a temporary variable used when calculating @mean_ec
+ * @aeb_slab_cache: slab cache for &struct ubi_ainf_peb objects
+ *
+ * This data structure contains the result of attaching an MTD device and may
+ * be used by other UBI sub-systems to build final UBI data structures, further
+ * error-recovery and so on.
+ */
+struct ubi_attach_info {
+	struct rb_root volumes;
+	struct list_head corr;
+	struct list_head free;
+	struct list_head erase;
+	struct list_head alien;
+	int corr_peb_count;
+	int empty_peb_count;
+	int alien_peb_count;
+	int bad_peb_count;
+	int maybe_bad_peb_count;
+	int vols_found;
+	int highest_vol_id;
+	int is_empty;
+	int min_ec;
+	int max_ec;
+	unsigned long long max_sqnum;
+	int mean_ec;
+	uint64_t ec_sum;
+	int ec_count;
+	struct kmem_cache *aeb_slab_cache;
+};
+
 #include "debug.h"
 
 extern struct kmem_cache *ubi_wl_entry_slab;
@@ -487,12 +607,23 @@
 extern struct mutex ubi_devices_mutex;
 extern struct blocking_notifier_head ubi_notifiers;
 
+/* scan.c */
+int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
+		  int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips);
+struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai,
+				    int vol_id);
+void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av);
+struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
+				       struct ubi_attach_info *ai);
+int ubi_attach(struct ubi_device *ubi);
+void ubi_destroy_ai(struct ubi_attach_info *ai);
+
 /* vtbl.c */
 int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
 			   struct ubi_vtbl_record *vtbl_rec);
 int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
 			    struct list_head *rename_list);
-int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si);
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai);
 
 /* vmt.c */
 int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req);
@@ -525,22 +656,22 @@
 int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 		     void *buf, int offset, int len, int check);
 int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
-		      const void *buf, int offset, int len, int dtype);
+		      const void *buf, int offset, int len);
 int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
-			 int lnum, const void *buf, int len, int dtype,
-			 int used_ebs);
+			 int lnum, const void *buf, int len, int used_ebs);
 int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
-			      int lnum, const void *buf, int len, int dtype);
+			      int lnum, const void *buf, int len);
 int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
 		     struct ubi_vid_hdr *vid_hdr);
-int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
 
 /* wl.c */
-int ubi_wl_get_peb(struct ubi_device *ubi, int dtype);
-int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture);
-int ubi_wl_flush(struct ubi_device *ubi);
+int ubi_wl_get_peb(struct ubi_device *ubi);
+int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
+		   int pnum, int torture);
+int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum);
 int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
-int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
 void ubi_wl_close(struct ubi_device *ubi);
 int ubi_thread(void *u);
 
@@ -573,6 +704,7 @@
 int ubi_notify_all(struct ubi_device *ubi, int ntype,
 		   struct notifier_block *nb);
 int ubi_enumerate_volumes(struct notifier_block *nb);
+void ubi_free_internal_volumes(struct ubi_device *ubi);
 
 /* kapi.c */
 void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di);
@@ -593,6 +725,21 @@
 	     rb = rb_next(rb),                                               \
 	     pos = (rb ? container_of(rb, typeof(*pos), member) : NULL))
 
+/*
+ * ubi_move_aeb_to_list - move a PEB from the volume tree to a list.
+ *
+ * @av: volume attaching information
+ * @aeb: attaching eraseblock information
+ * @list: the list to move to
+ */
+static inline void ubi_move_aeb_to_list(struct ubi_ainf_volume *av,
+					 struct ubi_ainf_peb *aeb,
+					 struct list_head *list)
+{
+		rb_erase(&aeb->u.rb, &av->root);
+		list_add_tail(&aeb->u.list, list);
+}
+
 /**
  * ubi_zalloc_vid_hdr - allocate a volume identifier header object.
  * @ubi: UBI device description object
@@ -667,7 +814,7 @@
 	if (!ubi->ro_mode) {
 		ubi->ro_mode = 1;
 		ubi_warn("switch to read-only mode");
-		ubi_dbg_dump_stack();
+		dump_stack();
 	}
 }
 
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 425bf5a..9f2ebd8 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -147,7 +147,7 @@
 	}
 
 	if (bytes == 0) {
-		err = ubi_wl_flush(ubi);
+		err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
 		if (err)
 			return err;
 
@@ -186,14 +186,12 @@
 	dbg_gen("start changing LEB %d:%d, %u bytes",
 		vol->vol_id, req->lnum, req->bytes);
 	if (req->bytes == 0)
-		return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0,
-						 req->dtype);
+		return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0);
 
 	vol->upd_bytes = req->bytes;
 	vol->upd_received = 0;
 	vol->changing_leb = 1;
 	vol->ch_lnum = req->lnum;
-	vol->ch_dtype = req->dtype;
 
 	vol->upd_buf = vmalloc(req->bytes);
 	if (!vol->upd_buf)
@@ -246,8 +244,7 @@
 			return 0;
 		}
 
-		err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len,
-					UBI_UNKNOWN);
+		err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len);
 	} else {
 		/*
 		 * When writing static volume, and this is the last logical
@@ -259,8 +256,7 @@
 		 * contain zeros, not random trash.
 		 */
 		memset(buf + len, 0, vol->usable_leb_size - len);
-		err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len,
-					   UBI_UNKNOWN, used_ebs);
+		err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, used_ebs);
 	}
 
 	return err;
@@ -365,7 +361,7 @@
 
 	ubi_assert(vol->upd_received <= vol->upd_bytes);
 	if (vol->upd_received == vol->upd_bytes) {
-		err = ubi_wl_flush(ubi);
+		err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
 		if (err)
 			return err;
 		/* The update is finished, clear the update marker */
@@ -421,7 +417,7 @@
 		       len - vol->upd_bytes);
 		len = ubi_calc_data_len(ubi, vol->upd_buf, len);
 		err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
-						vol->upd_buf, len, UBI_UNKNOWN);
+						vol->upd_buf, len);
 		if (err)
 			return err;
 	}
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 863835f..0669cff 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -29,11 +29,7 @@
 #include <linux/export.h>
 #include "ubi.h"
 
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_volumes(struct ubi_device *ubi);
-#else
-#define paranoid_check_volumes(ubi) 0
-#endif
+static int self_check_volumes(struct ubi_device *ubi);
 
 static ssize_t vol_attribute_show(struct device *dev,
 				  struct device_attribute *attr, char *buf);
@@ -227,7 +223,7 @@
 			}
 
 		if (vol_id == UBI_VOL_NUM_AUTO) {
-			dbg_err("out of volume IDs");
+			ubi_err("out of volume IDs");
 			err = -ENFILE;
 			goto out_unlock;
 		}
@@ -241,7 +237,7 @@
 	/* Ensure that this volume does not exist */
 	err = -EEXIST;
 	if (ubi->volumes[vol_id]) {
-		dbg_err("volume %d already exists", vol_id);
+		ubi_err("volume %d already exists", vol_id);
 		goto out_unlock;
 	}
 
@@ -250,7 +246,7 @@
 		if (ubi->volumes[i] &&
 		    ubi->volumes[i]->name_len == req->name_len &&
 		    !strcmp(ubi->volumes[i]->name, req->name)) {
-			dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
+			ubi_err("volume \"%s\" exists (ID %d)", req->name, i);
 			goto out_unlock;
 		}
 
@@ -261,9 +257,9 @@
 
 	/* Reserve physical eraseblocks */
 	if (vol->reserved_pebs > ubi->avail_pebs) {
-		dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
+		ubi_err("not enough PEBs, only %d available", ubi->avail_pebs);
 		if (ubi->corr_peb_count)
-			dbg_err("%d PEBs are corrupted and not used",
+			ubi_err("%d PEBs are corrupted and not used",
 				ubi->corr_peb_count);
 		err = -ENOSPC;
 		goto out_unlock;
@@ -284,7 +280,7 @@
 	 * Finish all pending erases because there may be some LEBs belonging
 	 * to the same volume ID.
 	 */
-	err = ubi_wl_flush(ubi);
+	err = ubi_wl_flush(ubi, vol_id, UBI_ALL);
 	if (err)
 		goto out_acc;
 
@@ -360,8 +356,7 @@
 	spin_unlock(&ubi->volumes_lock);
 
 	ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
-	if (paranoid_check_volumes(ubi))
-		dbg_err("check failed while creating volume %d", vol_id);
+	self_check_volumes(ubi);
 	return err;
 
 out_sysfs:
@@ -461,8 +456,8 @@
 	spin_unlock(&ubi->volumes_lock);
 
 	ubi_volume_notify(ubi, vol, UBI_VOLUME_REMOVED);
-	if (!no_vtbl && paranoid_check_volumes(ubi))
-		dbg_err("check failed while removing volume %d", vol_id);
+	if (!no_vtbl)
+		self_check_volumes(ubi);
 
 	return err;
 
@@ -500,7 +495,7 @@
 
 	if (vol->vol_type == UBI_STATIC_VOLUME &&
 	    reserved_pebs < vol->used_ebs) {
-		dbg_err("too small size %d, %d LEBs contain data",
+		ubi_err("too small size %d, %d LEBs contain data",
 			reserved_pebs, vol->used_ebs);
 		return -EINVAL;
 	}
@@ -529,10 +524,10 @@
 	if (pebs > 0) {
 		spin_lock(&ubi->volumes_lock);
 		if (pebs > ubi->avail_pebs) {
-			dbg_err("not enough PEBs: requested %d, available %d",
+			ubi_err("not enough PEBs: requested %d, available %d",
 				pebs, ubi->avail_pebs);
 			if (ubi->corr_peb_count)
-				dbg_err("%d PEBs are corrupted and not used",
+				ubi_err("%d PEBs are corrupted and not used",
 					ubi->corr_peb_count);
 			spin_unlock(&ubi->volumes_lock);
 			err = -ENOSPC;
@@ -588,8 +583,7 @@
 	}
 
 	ubi_volume_notify(ubi, vol, UBI_VOLUME_RESIZED);
-	if (paranoid_check_volumes(ubi))
-		dbg_err("check failed while re-sizing volume %d", vol_id);
+	self_check_volumes(ubi);
 	return err;
 
 out_acc:
@@ -638,8 +632,8 @@
 		}
 	}
 
-	if (!err && paranoid_check_volumes(ubi))
-		;
+	if (!err)
+		self_check_volumes(ubi);
 	return err;
 }
 
@@ -686,8 +680,7 @@
 		return err;
 	}
 
-	if (paranoid_check_volumes(ubi))
-		dbg_err("check failed while adding volume %d", vol_id);
+	self_check_volumes(ubi);
 	return err;
 
 out_cdev:
@@ -712,16 +705,14 @@
 	volume_sysfs_close(vol);
 }
 
-#ifdef CONFIG_MTD_UBI_DEBUG
-
 /**
- * paranoid_check_volume - check volume information.
+ * self_check_volume - check volume information.
  * @ubi: UBI device description object
  * @vol_id: volume ID
  *
  * Returns zero if volume is all right and a a negative error code if not.
  */
-static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)
+static int self_check_volume(struct ubi_device *ubi, int vol_id)
 {
 	int idx = vol_id2idx(ubi, vol_id);
 	int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
@@ -771,7 +762,7 @@
 	}
 
 	if (vol->upd_marker && vol->corrupted) {
-		dbg_err("update marker and corrupted simultaneously");
+		ubi_err("update marker and corrupted simultaneously");
 		goto fail;
 	}
 
@@ -853,22 +844,22 @@
 	return 0;
 
 fail:
-	ubi_err("paranoid check failed for volume %d", vol_id);
+	ubi_err("self-check failed for volume %d", vol_id);
 	if (vol)
-		ubi_dbg_dump_vol_info(vol);
-	ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+		ubi_dump_vol_info(vol);
+	ubi_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
 	dump_stack();
 	spin_unlock(&ubi->volumes_lock);
 	return -EINVAL;
 }
 
 /**
- * paranoid_check_volumes - check information about all volumes.
+ * self_check_volumes - check information about all volumes.
  * @ubi: UBI device description object
  *
  * Returns zero if volumes are all right and a a negative error code if not.
  */
-static int paranoid_check_volumes(struct ubi_device *ubi)
+static int self_check_volumes(struct ubi_device *ubi)
 {
 	int i, err = 0;
 
@@ -876,11 +867,10 @@
 		return 0;
 
 	for (i = 0; i < ubi->vtbl_slots; i++) {
-		err = paranoid_check_volume(ubi, i);
+		err = self_check_volume(ubi, i);
 		if (err)
 			break;
 	}
 
 	return err;
 }
-#endif
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 17cec0c..437bc19 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -37,16 +37,15 @@
  * LEB 1. This scheme guarantees recoverability from unclean reboots.
  *
  * In this UBI implementation the on-flash volume table does not contain any
- * information about how many data static volumes contain. This information may
- * be found from the scanning data.
+ * information about how much data static volumes contain.
  *
  * But it would still be beneficial to store this information in the volume
  * table. For example, suppose we have a static volume X, and all its physical
  * eraseblocks became bad for some reasons. Suppose we are attaching the
- * corresponding MTD device, the scanning has found no logical eraseblocks
+ * corresponding MTD device, for some reason we find no logical eraseblocks
  * corresponding to the volume X. According to the volume table volume X does
  * exist. So we don't know whether it is just empty or all its physical
- * eraseblocks went bad. So we cannot alarm the user about this corruption.
+ * eraseblocks went bad. So we cannot alarm the user properly.
  *
  * The volume table also stores so-called "update marker", which is used for
  * volume updates. Before updating the volume, the update marker is set, and
@@ -62,11 +61,7 @@
 #include <asm/div64.h>
 #include "ubi.h"
 
-#ifdef CONFIG_MTD_UBI_DEBUG
-static void paranoid_vtbl_check(const struct ubi_device *ubi);
-#else
-#define paranoid_vtbl_check(ubi)
-#endif
+static void self_vtbl_check(const struct ubi_device *ubi);
 
 /* Empty volume table record */
 static struct ubi_vtbl_record empty_vtbl_record;
@@ -106,12 +101,12 @@
 			return err;
 
 		err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
-					ubi->vtbl_size, UBI_LONGTERM);
+					ubi->vtbl_size);
 		if (err)
 			return err;
 	}
 
-	paranoid_vtbl_check(ubi);
+	self_vtbl_check(ubi);
 	return 0;
 }
 
@@ -158,7 +153,7 @@
 			return err;
 
 		err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
-					ubi->vtbl_size, UBI_LONGTERM);
+					ubi->vtbl_size);
 		if (err)
 			return err;
 	}
@@ -197,7 +192,7 @@
 		if (be32_to_cpu(vtbl[i].crc) != crc) {
 			ubi_err("bad CRC at record %u: %#08x, not %#08x",
 				 i, crc, be32_to_cpu(vtbl[i].crc));
-			ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+			ubi_dump_vtbl_record(&vtbl[i], i);
 			return 1;
 		}
 
@@ -229,7 +224,7 @@
 
 		n = ubi->leb_size % alignment;
 		if (data_pad != n) {
-			dbg_err("bad data_pad, has to be %d", n);
+			ubi_err("bad data_pad, has to be %d", n);
 			err = 6;
 			goto bad;
 		}
@@ -245,7 +240,7 @@
 		}
 
 		if (reserved_pebs > ubi->good_peb_count) {
-			dbg_err("too large reserved_pebs %d, good PEBs %d",
+			ubi_err("too large reserved_pebs %d, good PEBs %d",
 				reserved_pebs, ubi->good_peb_count);
 			err = 9;
 			goto bad;
@@ -277,8 +272,8 @@
 			    !strncmp(vtbl[i].name, vtbl[n].name, len1)) {
 				ubi_err("volumes %d and %d have the same name"
 					" \"%s\"", i, n, vtbl[i].name);
-				ubi_dbg_dump_vtbl_record(&vtbl[i], i);
-				ubi_dbg_dump_vtbl_record(&vtbl[n], n);
+				ubi_dump_vtbl_record(&vtbl[i], i);
+				ubi_dump_vtbl_record(&vtbl[n], n);
 				return -EINVAL;
 			}
 		}
@@ -288,26 +283,26 @@
 
 bad:
 	ubi_err("volume table check failed: record %d, error %d", i, err);
-	ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+	ubi_dump_vtbl_record(&vtbl[i], i);
 	return -EINVAL;
 }
 
 /**
  * create_vtbl - create a copy of volume table.
  * @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
  * @copy: number of the volume table copy
  * @vtbl: contents of the volume table
  *
  * This function returns zero in case of success and a negative error code in
  * case of failure.
  */
-static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
+static int create_vtbl(struct ubi_device *ubi, struct ubi_attach_info *ai,
 		       int copy, void *vtbl)
 {
 	int err, tries = 0;
 	struct ubi_vid_hdr *vid_hdr;
-	struct ubi_scan_leb *new_seb;
+	struct ubi_ainf_peb *new_aeb;
 
 	ubi_msg("create volume table (copy #%d)", copy + 1);
 
@@ -316,9 +311,9 @@
 		return -ENOMEM;
 
 retry:
-	new_seb = ubi_scan_get_free_peb(ubi, si);
-	if (IS_ERR(new_seb)) {
-		err = PTR_ERR(new_seb);
+	new_aeb = ubi_early_get_peb(ubi, ai);
+	if (IS_ERR(new_aeb)) {
+		err = PTR_ERR(new_aeb);
 		goto out_free;
 	}
 
@@ -328,25 +323,24 @@
 	vid_hdr->data_size = vid_hdr->used_ebs =
 			     vid_hdr->data_pad = cpu_to_be32(0);
 	vid_hdr->lnum = cpu_to_be32(copy);
-	vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+	vid_hdr->sqnum = cpu_to_be64(++ai->max_sqnum);
 
 	/* The EC header is already there, write the VID header */
-	err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
+	err = ubi_io_write_vid_hdr(ubi, new_aeb->pnum, vid_hdr);
 	if (err)
 		goto write_error;
 
 	/* Write the layout volume contents */
-	err = ubi_io_write_data(ubi, vtbl, new_seb->pnum, 0, ubi->vtbl_size);
+	err = ubi_io_write_data(ubi, vtbl, new_aeb->pnum, 0, ubi->vtbl_size);
 	if (err)
 		goto write_error;
 
 	/*
-	 * And add it to the scanning information. Don't delete the old version
-	 * of this LEB as it will be deleted and freed in 'ubi_scan_add_used()'.
+	 * And add it to the attaching information. Don't delete the old version
+	 * of this LEB as it will be deleted and freed in 'ubi_add_to_av()'.
 	 */
-	err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec,
-				vid_hdr, 0);
-	kfree(new_seb);
+	err = ubi_add_to_av(ubi, ai, new_aeb->pnum, new_aeb->ec, vid_hdr, 0);
+	kfree(new_aeb);
 	ubi_free_vid_hdr(ubi, vid_hdr);
 	return err;
 
@@ -356,10 +350,10 @@
 		 * Probably this physical eraseblock went bad, try to pick
 		 * another one.
 		 */
-		list_add(&new_seb->u.list, &si->erase);
+		list_add(&new_aeb->u.list, &ai->erase);
 		goto retry;
 	}
-	kfree(new_seb);
+	kfree(new_aeb);
 out_free:
 	ubi_free_vid_hdr(ubi, vid_hdr);
 	return err;
@@ -369,20 +363,20 @@
 /**
  * process_lvol - process the layout volume.
  * @ubi: UBI device description object
- * @si: scanning information
- * @sv: layout volume scanning information
+ * @ai: attaching information
+ * @av: layout volume attaching information
  *
  * This function is responsible for reading the layout volume, ensuring it is
  * not corrupted, and recovering from corruptions if needed. Returns volume
  * table in case of success and a negative error code in case of failure.
  */
 static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
-					    struct ubi_scan_info *si,
-					    struct ubi_scan_volume *sv)
+					    struct ubi_attach_info *ai,
+					    struct ubi_ainf_volume *av)
 {
 	int err;
 	struct rb_node *rb;
-	struct ubi_scan_leb *seb;
+	struct ubi_ainf_peb *aeb;
 	struct ubi_vtbl_record *leb[UBI_LAYOUT_VOLUME_EBS] = { NULL, NULL };
 	int leb_corrupted[UBI_LAYOUT_VOLUME_EBS] = {1, 1};
 
@@ -414,14 +408,14 @@
 	dbg_gen("check layout volume");
 
 	/* Read both LEB 0 and LEB 1 into memory */
-	ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
-		leb[seb->lnum] = vzalloc(ubi->vtbl_size);
-		if (!leb[seb->lnum]) {
+	ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) {
+		leb[aeb->lnum] = vzalloc(ubi->vtbl_size);
+		if (!leb[aeb->lnum]) {
 			err = -ENOMEM;
 			goto out_free;
 		}
 
-		err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
+		err = ubi_io_read_data(ubi, leb[aeb->lnum], aeb->pnum, 0,
 				       ubi->vtbl_size);
 		if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err))
 			/*
@@ -429,12 +423,12 @@
 			 * uncorrectable ECC error, but we have our own CRC and
 			 * the data will be checked later. If the data is OK,
 			 * the PEB will be scrubbed (because we set
-			 * seb->scrub). If the data is not OK, the contents of
+			 * aeb->scrub). If the data is not OK, the contents of
 			 * the PEB will be recovered from the second copy, and
-			 * seb->scrub will be cleared in
-			 * 'ubi_scan_add_used()'.
+			 * aeb->scrub will be cleared in
+			 * 'ubi_add_to_av()'.
 			 */
-			seb->scrub = 1;
+			aeb->scrub = 1;
 		else if (err)
 			goto out_free;
 	}
@@ -453,7 +447,7 @@
 						  ubi->vtbl_size);
 		if (leb_corrupted[1]) {
 			ubi_warn("volume table copy #2 is corrupted");
-			err = create_vtbl(ubi, si, 1, leb[0]);
+			err = create_vtbl(ubi, ai, 1, leb[0]);
 			if (err)
 				goto out_free;
 			ubi_msg("volume table was restored");
@@ -476,7 +470,7 @@
 		}
 
 		ubi_warn("volume table copy #1 is corrupted");
-		err = create_vtbl(ubi, si, 0, leb[1]);
+		err = create_vtbl(ubi, ai, 0, leb[1]);
 		if (err)
 			goto out_free;
 		ubi_msg("volume table was restored");
@@ -494,13 +488,13 @@
 /**
  * create_empty_lvol - create empty layout volume.
  * @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
  *
  * This function returns volume table contents in case of success and a
  * negative error code in case of failure.
  */
 static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
-						 struct ubi_scan_info *si)
+						 struct ubi_attach_info *ai)
 {
 	int i;
 	struct ubi_vtbl_record *vtbl;
@@ -515,7 +509,7 @@
 	for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
 		int err;
 
-		err = create_vtbl(ubi, si, i, vtbl);
+		err = create_vtbl(ubi, ai, i, vtbl);
 		if (err) {
 			vfree(vtbl);
 			return ERR_PTR(err);
@@ -528,18 +522,19 @@
 /**
  * init_volumes - initialize volume information for existing volumes.
  * @ubi: UBI device description object
- * @si: scanning information
+ * @ai: scanning information
  * @vtbl: volume table
  *
  * This function allocates volume description objects for existing volumes.
  * Returns zero in case of success and a negative error code in case of
  * failure.
  */
-static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
+static int init_volumes(struct ubi_device *ubi,
+			const struct ubi_attach_info *ai,
 			const struct ubi_vtbl_record *vtbl)
 {
 	int i, reserved_pebs = 0;
-	struct ubi_scan_volume *sv;
+	struct ubi_ainf_volume *av;
 	struct ubi_volume *vol;
 
 	for (i = 0; i < ubi->vtbl_slots; i++) {
@@ -595,8 +590,8 @@
 		}
 
 		/* Static volumes only */
-		sv = ubi_scan_find_sv(si, i);
-		if (!sv) {
+		av = ubi_find_av(ai, i);
+		if (!av) {
 			/*
 			 * No eraseblocks belonging to this volume found. We
 			 * don't actually know whether this static volume is
@@ -608,22 +603,22 @@
 			continue;
 		}
 
-		if (sv->leb_count != sv->used_ebs) {
+		if (av->leb_count != av->used_ebs) {
 			/*
 			 * We found a static volume which misses several
 			 * eraseblocks. Treat it as corrupted.
 			 */
 			ubi_warn("static volume %d misses %d LEBs - corrupted",
-				 sv->vol_id, sv->used_ebs - sv->leb_count);
+				 av->vol_id, av->used_ebs - av->leb_count);
 			vol->corrupted = 1;
 			continue;
 		}
 
-		vol->used_ebs = sv->used_ebs;
+		vol->used_ebs = av->used_ebs;
 		vol->used_bytes =
 			(long long)(vol->used_ebs - 1) * vol->usable_leb_size;
-		vol->used_bytes += sv->last_data_size;
-		vol->last_eb_bytes = sv->last_data_size;
+		vol->used_bytes += av->last_data_size;
+		vol->last_eb_bytes = av->last_data_size;
 	}
 
 	/* And add the layout volume */
@@ -664,105 +659,104 @@
 }
 
 /**
- * check_sv - check volume scanning information.
+ * check_av - check volume attaching information.
  * @vol: UBI volume description object
- * @sv: volume scanning information
+ * @av: volume attaching information
  *
- * This function returns zero if the volume scanning information is consistent
+ * This function returns zero if the volume attaching information is consistent
  * to the data read from the volume tabla, and %-EINVAL if not.
  */
-static int check_sv(const struct ubi_volume *vol,
-		    const struct ubi_scan_volume *sv)
+static int check_av(const struct ubi_volume *vol,
+		    const struct ubi_ainf_volume *av)
 {
 	int err;
 
-	if (sv->highest_lnum >= vol->reserved_pebs) {
+	if (av->highest_lnum >= vol->reserved_pebs) {
 		err = 1;
 		goto bad;
 	}
-	if (sv->leb_count > vol->reserved_pebs) {
+	if (av->leb_count > vol->reserved_pebs) {
 		err = 2;
 		goto bad;
 	}
-	if (sv->vol_type != vol->vol_type) {
+	if (av->vol_type != vol->vol_type) {
 		err = 3;
 		goto bad;
 	}
-	if (sv->used_ebs > vol->reserved_pebs) {
+	if (av->used_ebs > vol->reserved_pebs) {
 		err = 4;
 		goto bad;
 	}
-	if (sv->data_pad != vol->data_pad) {
+	if (av->data_pad != vol->data_pad) {
 		err = 5;
 		goto bad;
 	}
 	return 0;
 
 bad:
-	ubi_err("bad scanning information, error %d", err);
-	ubi_dbg_dump_sv(sv);
-	ubi_dbg_dump_vol_info(vol);
+	ubi_err("bad attaching information, error %d", err);
+	ubi_dump_av(av);
+	ubi_dump_vol_info(vol);
 	return -EINVAL;
 }
 
 /**
- * check_scanning_info - check that scanning information.
+ * check_attaching_info - check that attaching information.
  * @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
  *
  * Even though we protect on-flash data by CRC checksums, we still don't trust
- * the media. This function ensures that scanning information is consistent to
- * the information read from the volume table. Returns zero if the scanning
+ * the media. This function ensures that attaching information is consistent to
+ * the information read from the volume table. Returns zero if the attaching
  * information is OK and %-EINVAL if it is not.
  */
-static int check_scanning_info(const struct ubi_device *ubi,
-			       struct ubi_scan_info *si)
+static int check_attaching_info(const struct ubi_device *ubi,
+			       struct ubi_attach_info *ai)
 {
 	int err, i;
-	struct ubi_scan_volume *sv;
+	struct ubi_ainf_volume *av;
 	struct ubi_volume *vol;
 
-	if (si->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
-		ubi_err("scanning found %d volumes, maximum is %d + %d",
-			si->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
+	if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
+		ubi_err("found %d volumes while attaching, maximum is %d + %d",
+			ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
 		return -EINVAL;
 	}
 
-	if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
-	    si->highest_vol_id < UBI_INTERNAL_VOL_START) {
-		ubi_err("too large volume ID %d found by scanning",
-			si->highest_vol_id);
+	if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
+	    ai->highest_vol_id < UBI_INTERNAL_VOL_START) {
+		ubi_err("too large volume ID %d found", ai->highest_vol_id);
 		return -EINVAL;
 	}
 
 	for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
 		cond_resched();
 
-		sv = ubi_scan_find_sv(si, i);
+		av = ubi_find_av(ai, i);
 		vol = ubi->volumes[i];
 		if (!vol) {
-			if (sv)
-				ubi_scan_rm_volume(si, sv);
+			if (av)
+				ubi_remove_av(ai, av);
 			continue;
 		}
 
 		if (vol->reserved_pebs == 0) {
 			ubi_assert(i < ubi->vtbl_slots);
 
-			if (!sv)
+			if (!av)
 				continue;
 
 			/*
-			 * During scanning we found a volume which does not
+			 * During attaching we found a volume which does not
 			 * exist according to the information in the volume
 			 * table. This must have happened due to an unclean
 			 * reboot while the volume was being removed. Discard
 			 * these eraseblocks.
 			 */
-			ubi_msg("finish volume %d removal", sv->vol_id);
-			ubi_scan_rm_volume(si, sv);
-		} else if (sv) {
-			err = check_sv(vol, sv);
+			ubi_msg("finish volume %d removal", av->vol_id);
+			ubi_remove_av(ai, av);
+		} else if (av) {
+			err = check_av(vol, av);
 			if (err)
 				return err;
 		}
@@ -774,16 +768,16 @@
 /**
  * ubi_read_volume_table - read the volume table.
  * @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
  *
  * This function reads volume table, checks it, recover from errors if needed,
  * or creates it if needed. Returns zero in case of success and a negative
  * error code in case of failure.
  */
-int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai)
 {
 	int i, err;
-	struct ubi_scan_volume *sv;
+	struct ubi_ainf_volume *av;
 
 	empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
 
@@ -798,8 +792,8 @@
 	ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE;
 	ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size);
 
-	sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
-	if (!sv) {
+	av = ubi_find_av(ai, UBI_LAYOUT_VOLUME_ID);
+	if (!av) {
 		/*
 		 * No logical eraseblocks belonging to the layout volume were
 		 * found. This could mean that the flash is just empty. In
@@ -808,8 +802,8 @@
 		 * But if flash is not empty this must be a corruption or the
 		 * MTD device just contains garbage.
 		 */
-		if (si->is_empty) {
-			ubi->vtbl = create_empty_lvol(ubi, si);
+		if (ai->is_empty) {
+			ubi->vtbl = create_empty_lvol(ubi, ai);
 			if (IS_ERR(ubi->vtbl))
 				return PTR_ERR(ubi->vtbl);
 		} else {
@@ -817,14 +811,14 @@
 			return -EINVAL;
 		}
 	} else {
-		if (sv->leb_count > UBI_LAYOUT_VOLUME_EBS) {
+		if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) {
 			/* This must not happen with proper UBI images */
-			dbg_err("too many LEBs (%d) in layout volume",
-				sv->leb_count);
+			ubi_err("too many LEBs (%d) in layout volume",
+				av->leb_count);
 			return -EINVAL;
 		}
 
-		ubi->vtbl = process_lvol(ubi, si, sv);
+		ubi->vtbl = process_lvol(ubi, ai, av);
 		if (IS_ERR(ubi->vtbl))
 			return PTR_ERR(ubi->vtbl);
 	}
@@ -835,15 +829,15 @@
 	 * The layout volume is OK, initialize the corresponding in-RAM data
 	 * structures.
 	 */
-	err = init_volumes(ubi, si, ubi->vtbl);
+	err = init_volumes(ubi, ai, ubi->vtbl);
 	if (err)
 		goto out_free;
 
 	/*
-	 * Make sure that the scanning information is consistent to the
+	 * Make sure that the attaching information is consistent to the
 	 * information stored in the volume table.
 	 */
-	err = check_scanning_info(ubi, si);
+	err = check_attaching_info(ubi, ai);
 	if (err)
 		goto out_free;
 
@@ -858,21 +852,17 @@
 	return err;
 }
 
-#ifdef CONFIG_MTD_UBI_DEBUG
-
 /**
- * paranoid_vtbl_check - check volume table.
+ * self_vtbl_check - check volume table.
  * @ubi: UBI device description object
  */
-static void paranoid_vtbl_check(const struct ubi_device *ubi)
+static void self_vtbl_check(const struct ubi_device *ubi)
 {
 	if (!ubi->dbg->chk_gen)
 		return;
 
 	if (vtbl_check(ubi, ubi->vtbl)) {
-		ubi_err("paranoid check failed");
+		ubi_err("self-check failed");
 		BUG();
 	}
 }
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 7c1a9bf..9df100a 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -41,12 +41,6 @@
  * physical eraseblocks with low erase counter to free physical eraseblocks
  * with high erase counter.
  *
- * The 'ubi_wl_get_peb()' function accepts data type hints which help to pick
- * an "optimal" physical eraseblock. For example, when it is known that the
- * physical eraseblock will be "put" soon because it contains short-term data,
- * the WL sub-system may pick a free physical eraseblock with low erase
- * counter, and so forth.
- *
  * If the WL sub-system fails to erase a physical eraseblock, it marks it as
  * bad.
  *
@@ -70,8 +64,7 @@
  *    to the user; instead, we first want to let users fill them up with data;
  *
  *  o there is a chance that the user will put the physical eraseblock very
- *    soon, so it makes sense not to move it for some time, but wait; this is
- *    especially important in case of "short term" physical eraseblocks.
+ *    soon, so it makes sense not to move it for some time, but wait.
  *
  * Physical eraseblocks stay protected only for limited time. But the "time" is
  * measured in erase cycles in this case. This is implemented with help of the
@@ -147,6 +140,8 @@
  * @list: a link in the list of pending works
  * @func: worker function
  * @e: physical eraseblock to erase
+ * @vol_id: the volume ID on which this erasure is being performed
+ * @lnum: the logical eraseblock number
  * @torture: if the physical eraseblock has to be tortured
  *
  * The @func pointer points to the worker function. If the @cancel argument is
@@ -159,21 +154,16 @@
 	int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel);
 	/* The below fields are only relevant to erasure works */
 	struct ubi_wl_entry *e;
+	int vol_id;
+	int lnum;
 	int torture;
 };
 
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
-static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
-				     struct ubi_wl_entry *e,
-				     struct rb_root *root);
-static int paranoid_check_in_pq(const struct ubi_device *ubi,
-				struct ubi_wl_entry *e);
-#else
-#define paranoid_check_ec(ubi, pnum, ec) 0
-#define paranoid_check_in_wl_tree(ubi, e, root)
-#define paranoid_check_in_pq(ubi, e) 0
-#endif
+static int self_check_ec(struct ubi_device *ubi, int pnum, int ec);
+static int self_check_in_wl_tree(const struct ubi_device *ubi,
+				 struct ubi_wl_entry *e, struct rb_root *root);
+static int self_check_in_pq(const struct ubi_device *ubi,
+			    struct ubi_wl_entry *e);
 
 /**
  * wl_tree_add - add a wear-leveling entry to a WL RB-tree.
@@ -383,19 +373,15 @@
 /**
  * ubi_wl_get_peb - get a physical eraseblock.
  * @ubi: UBI device description object
- * @dtype: type of data which will be stored in this physical eraseblock
  *
  * This function returns a physical eraseblock in case of success and a
  * negative error code in case of failure. Might sleep.
  */
-int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
+int ubi_wl_get_peb(struct ubi_device *ubi)
 {
 	int err;
 	struct ubi_wl_entry *e, *first, *last;
 
-	ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
-		   dtype == UBI_UNKNOWN);
-
 retry:
 	spin_lock(&ubi->wl_lock);
 	if (!ubi->free.rb_node) {
@@ -413,45 +399,15 @@
 		goto retry;
 	}
 
-	switch (dtype) {
-	case UBI_LONGTERM:
-		/*
-		 * For long term data we pick a physical eraseblock with high
-		 * erase counter. But the highest erase counter we can pick is
-		 * bounded by the the lowest erase counter plus
-		 * %WL_FREE_MAX_DIFF.
-		 */
-		e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
-		break;
-	case UBI_UNKNOWN:
-		/*
-		 * For unknown data we pick a physical eraseblock with medium
-		 * erase counter. But we by no means can pick a physical
-		 * eraseblock with erase counter greater or equivalent than the
-		 * lowest erase counter plus %WL_FREE_MAX_DIFF/2.
-		 */
-		first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry,
-					u.rb);
-		last = rb_entry(rb_last(&ubi->free), struct ubi_wl_entry, u.rb);
+	first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, u.rb);
+	last = rb_entry(rb_last(&ubi->free), struct ubi_wl_entry, u.rb);
 
-		if (last->ec - first->ec < WL_FREE_MAX_DIFF)
-			e = rb_entry(ubi->free.rb_node,
-					struct ubi_wl_entry, u.rb);
-		else
-			e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
-		break;
-	case UBI_SHORTTERM:
-		/*
-		 * For short term data we pick a physical eraseblock with the
-		 * lowest erase counter as we expect it will be erased soon.
-		 */
-		e = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, u.rb);
-		break;
-	default:
-		BUG();
-	}
+	if (last->ec - first->ec < WL_FREE_MAX_DIFF)
+		e = rb_entry(ubi->free.rb_node, struct ubi_wl_entry, u.rb);
+	else
+		e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
 
-	paranoid_check_in_wl_tree(ubi, e, &ubi->free);
+	self_check_in_wl_tree(ubi, e, &ubi->free);
 
 	/*
 	 * Move the physical eraseblock to the protection queue where it will
@@ -462,8 +418,8 @@
 	prot_queue_add(ubi, e);
 	spin_unlock(&ubi->wl_lock);
 
-	err = ubi_dbg_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
-				   ubi->peb_size - ubi->vid_hdr_aloffset);
+	err = ubi_self_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
+				    ubi->peb_size - ubi->vid_hdr_aloffset);
 	if (err) {
 		ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
 		return err;
@@ -488,7 +444,7 @@
 	if (!e)
 		return -ENODEV;
 
-	if (paranoid_check_in_pq(ubi, e))
+	if (self_check_in_pq(ubi, e))
 		return -ENODEV;
 
 	list_del(&e->u.list);
@@ -514,7 +470,7 @@
 
 	dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec);
 
-	err = paranoid_check_ec(ubi, e->pnum, e->ec);
+	err = self_check_ec(ubi, e->pnum, e->ec);
 	if (err)
 		return -EINVAL;
 
@@ -627,13 +583,15 @@
  * schedule_erase - schedule an erase work.
  * @ubi: UBI device description object
  * @e: the WL entry of the physical eraseblock to erase
+ * @vol_id: the volume ID that last used this PEB
+ * @lnum: the last used logical eraseblock number for the PEB
  * @torture: if the physical eraseblock has to be tortured
  *
  * This function returns zero in case of success and a %-ENOMEM in case of
  * failure.
  */
 static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
-			  int torture)
+			  int vol_id, int lnum, int torture)
 {
 	struct ubi_work *wl_wrk;
 
@@ -646,6 +604,8 @@
 
 	wl_wrk->func = &erase_worker;
 	wl_wrk->e = e;
+	wl_wrk->vol_id = vol_id;
+	wl_wrk->lnum = lnum;
 	wl_wrk->torture = torture;
 
 	schedule_ubi_work(ubi, wl_wrk);
@@ -714,7 +674,7 @@
 			       e1->ec, e2->ec);
 			goto out_cancel;
 		}
-		paranoid_check_in_wl_tree(ubi, e1, &ubi->used);
+		self_check_in_wl_tree(ubi, e1, &ubi->used);
 		rb_erase(&e1->u.rb, &ubi->used);
 		dbg_wl("move PEB %d EC %d to PEB %d EC %d",
 		       e1->pnum, e1->ec, e2->pnum, e2->ec);
@@ -723,12 +683,12 @@
 		scrubbing = 1;
 		e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, u.rb);
 		e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
-		paranoid_check_in_wl_tree(ubi, e1, &ubi->scrub);
+		self_check_in_wl_tree(ubi, e1, &ubi->scrub);
 		rb_erase(&e1->u.rb, &ubi->scrub);
 		dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
 	}
 
-	paranoid_check_in_wl_tree(ubi, e2, &ubi->free);
+	self_check_in_wl_tree(ubi, e2, &ubi->free);
 	rb_erase(&e2->u.rb, &ubi->free);
 	ubi->move_from = e1;
 	ubi->move_to = e2;
@@ -846,7 +806,7 @@
 	ubi->move_to_put = ubi->wl_scheduled = 0;
 	spin_unlock(&ubi->wl_lock);
 
-	err = schedule_erase(ubi, e1, 0);
+	err = schedule_erase(ubi, e1, vol_id, lnum, 0);
 	if (err) {
 		kmem_cache_free(ubi_wl_entry_slab, e1);
 		if (e2)
@@ -861,7 +821,7 @@
 		 */
 		dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase",
 		       e2->pnum, vol_id, lnum);
-		err = schedule_erase(ubi, e2, 0);
+		err = schedule_erase(ubi, e2, vol_id, lnum, 0);
 		if (err) {
 			kmem_cache_free(ubi_wl_entry_slab, e2);
 			goto out_ro;
@@ -900,7 +860,7 @@
 	spin_unlock(&ubi->wl_lock);
 
 	ubi_free_vid_hdr(ubi, vid_hdr);
-	err = schedule_erase(ubi, e2, torture);
+	err = schedule_erase(ubi, e2, vol_id, lnum, torture);
 	if (err) {
 		kmem_cache_free(ubi_wl_entry_slab, e2);
 		goto out_ro;
@@ -1019,6 +979,8 @@
 {
 	struct ubi_wl_entry *e = wl_wrk->e;
 	int pnum = e->pnum, err, need;
+	int vol_id = wl_wrk->vol_id;
+	int lnum = wl_wrk->lnum;
 
 	if (cancel) {
 		dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1027,7 +989,8 @@
 		return 0;
 	}
 
-	dbg_wl("erase PEB %d EC %d", pnum, e->ec);
+	dbg_wl("erase PEB %d EC %d LEB %d:%d",
+	       pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum);
 
 	err = sync_erase(ubi, e, wl_wrk->torture);
 	if (!err) {
@@ -1057,7 +1020,7 @@
 		int err1;
 
 		/* Re-schedule the LEB for erasure */
-		err1 = schedule_erase(ubi, e, 0);
+		err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
 		if (err1) {
 			err = err1;
 			goto out_ro;
@@ -1125,6 +1088,8 @@
 /**
  * ubi_wl_put_peb - return a PEB to the wear-leveling sub-system.
  * @ubi: UBI device description object
+ * @vol_id: the volume ID that last used this PEB
+ * @lnum: the last used logical eraseblock number for the PEB
  * @pnum: physical eraseblock to return
  * @torture: if this physical eraseblock has to be tortured
  *
@@ -1133,7 +1098,8 @@
  * occurred to this @pnum and it has to be tested. This function returns zero
  * in case of success, and a negative error code in case of failure.
  */
-int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
+int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
+		   int pnum, int torture)
 {
 	int err;
 	struct ubi_wl_entry *e;
@@ -1175,13 +1141,13 @@
 		return 0;
 	} else {
 		if (in_wl_tree(e, &ubi->used)) {
-			paranoid_check_in_wl_tree(ubi, e, &ubi->used);
+			self_check_in_wl_tree(ubi, e, &ubi->used);
 			rb_erase(&e->u.rb, &ubi->used);
 		} else if (in_wl_tree(e, &ubi->scrub)) {
-			paranoid_check_in_wl_tree(ubi, e, &ubi->scrub);
+			self_check_in_wl_tree(ubi, e, &ubi->scrub);
 			rb_erase(&e->u.rb, &ubi->scrub);
 		} else if (in_wl_tree(e, &ubi->erroneous)) {
-			paranoid_check_in_wl_tree(ubi, e, &ubi->erroneous);
+			self_check_in_wl_tree(ubi, e, &ubi->erroneous);
 			rb_erase(&e->u.rb, &ubi->erroneous);
 			ubi->erroneous_peb_count -= 1;
 			ubi_assert(ubi->erroneous_peb_count >= 0);
@@ -1199,7 +1165,7 @@
 	}
 	spin_unlock(&ubi->wl_lock);
 
-	err = schedule_erase(ubi, e, torture);
+	err = schedule_erase(ubi, e, vol_id, lnum, torture);
 	if (err) {
 		spin_lock(&ubi->wl_lock);
 		wl_tree_add(e, &ubi->used);
@@ -1248,7 +1214,7 @@
 	}
 
 	if (in_wl_tree(e, &ubi->used)) {
-		paranoid_check_in_wl_tree(ubi, e, &ubi->used);
+		self_check_in_wl_tree(ubi, e, &ubi->used);
 		rb_erase(&e->u.rb, &ubi->used);
 	} else {
 		int err;
@@ -1275,44 +1241,55 @@
 /**
  * ubi_wl_flush - flush all pending works.
  * @ubi: UBI device description object
+ * @vol_id: the volume id to flush for
+ * @lnum: the logical eraseblock number to flush for
  *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function executes all pending works for a particular volume id /
+ * logical eraseblock number pair. If either value is set to %UBI_ALL, then it
+ * acts as a wildcard for all of the corresponding volume numbers or logical
+ * eraseblock numbers. It returns zero in case of success and a negative error
+ * code in case of failure.
  */
-int ubi_wl_flush(struct ubi_device *ubi)
+int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum)
 {
-	int err;
+	int err = 0;
+	int found = 1;
 
 	/*
 	 * Erase while the pending works queue is not empty, but not more than
 	 * the number of currently pending works.
 	 */
-	dbg_wl("flush (%d pending works)", ubi->works_count);
-	while (ubi->works_count) {
-		err = do_work(ubi);
-		if (err)
-			return err;
-	}
+	dbg_wl("flush pending work for LEB %d:%d (%d pending works)",
+	       vol_id, lnum, ubi->works_count);
 
-	/*
-	 * Make sure all the works which have been done in parallel are
-	 * finished.
-	 */
 	down_write(&ubi->work_sem);
-	up_write(&ubi->work_sem);
+	while (found) {
+		struct ubi_work *wrk;
+		found = 0;
 
-	/*
-	 * And in case last was the WL worker and it canceled the LEB
-	 * movement, flush again.
-	 */
-	while (ubi->works_count) {
-		dbg_wl("flush more (%d pending works)", ubi->works_count);
-		err = do_work(ubi);
-		if (err)
-			return err;
+		spin_lock(&ubi->wl_lock);
+		list_for_each_entry(wrk, &ubi->works, list) {
+			if ((vol_id == UBI_ALL || wrk->vol_id == vol_id) &&
+			    (lnum == UBI_ALL || wrk->lnum == lnum)) {
+				list_del(&wrk->list);
+				ubi->works_count -= 1;
+				ubi_assert(ubi->works_count >= 0);
+				spin_unlock(&ubi->wl_lock);
+
+				err = wrk->func(ubi, wrk, 0);
+				if (err)
+					goto out;
+				spin_lock(&ubi->wl_lock);
+				found = 1;
+				break;
+			}
+		}
+		spin_unlock(&ubi->wl_lock);
 	}
 
-	return 0;
+out:
+	up_write(&ubi->work_sem);
+	return err;
 }
 
 /**
@@ -1421,26 +1398,26 @@
 }
 
 /**
- * ubi_wl_init_scan - initialize the WL sub-system using scanning information.
+ * ubi_wl_init - initialize the WL sub-system using attaching information.
  * @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
  *
  * This function returns zero in case of success, and a negative error code in
  * case of failure.
  */
-int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
 {
 	int err, i;
 	struct rb_node *rb1, *rb2;
-	struct ubi_scan_volume *sv;
-	struct ubi_scan_leb *seb, *tmp;
+	struct ubi_ainf_volume *av;
+	struct ubi_ainf_peb *aeb, *tmp;
 	struct ubi_wl_entry *e;
 
 	ubi->used = ubi->erroneous = ubi->free = ubi->scrub = RB_ROOT;
 	spin_lock_init(&ubi->wl_lock);
 	mutex_init(&ubi->move_mutex);
 	init_rwsem(&ubi->work_sem);
-	ubi->max_ec = si->max_ec;
+	ubi->max_ec = ai->max_ec;
 	INIT_LIST_HEAD(&ubi->works);
 
 	sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num);
@@ -1454,48 +1431,48 @@
 		INIT_LIST_HEAD(&ubi->pq[i]);
 	ubi->pq_head = 0;
 
-	list_for_each_entry_safe(seb, tmp, &si->erase, u.list) {
+	list_for_each_entry_safe(aeb, tmp, &ai->erase, u.list) {
 		cond_resched();
 
 		e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
 		if (!e)
 			goto out_free;
 
-		e->pnum = seb->pnum;
-		e->ec = seb->ec;
+		e->pnum = aeb->pnum;
+		e->ec = aeb->ec;
 		ubi->lookuptbl[e->pnum] = e;
-		if (schedule_erase(ubi, e, 0)) {
+		if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
 			kmem_cache_free(ubi_wl_entry_slab, e);
 			goto out_free;
 		}
 	}
 
-	list_for_each_entry(seb, &si->free, u.list) {
+	list_for_each_entry(aeb, &ai->free, u.list) {
 		cond_resched();
 
 		e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
 		if (!e)
 			goto out_free;
 
-		e->pnum = seb->pnum;
-		e->ec = seb->ec;
+		e->pnum = aeb->pnum;
+		e->ec = aeb->ec;
 		ubi_assert(e->ec >= 0);
 		wl_tree_add(e, &ubi->free);
 		ubi->lookuptbl[e->pnum] = e;
 	}
 
-	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
-		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+	ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+		ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
 			cond_resched();
 
 			e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
 			if (!e)
 				goto out_free;
 
-			e->pnum = seb->pnum;
-			e->ec = seb->ec;
+			e->pnum = aeb->pnum;
+			e->ec = aeb->ec;
 			ubi->lookuptbl[e->pnum] = e;
-			if (!seb->scrub) {
+			if (!aeb->scrub) {
 				dbg_wl("add PEB %d EC %d to the used tree",
 				       e->pnum, e->ec);
 				wl_tree_add(e, &ubi->used);
@@ -1567,10 +1544,8 @@
 	kfree(ubi->lookuptbl);
 }
 
-#ifdef CONFIG_MTD_UBI_DEBUG
-
 /**
- * paranoid_check_ec - make sure that the erase counter of a PEB is correct.
+ * self_check_ec - make sure that the erase counter of a PEB is correct.
  * @ubi: UBI device description object
  * @pnum: the physical eraseblock number to check
  * @ec: the erase counter to check
@@ -1579,7 +1554,7 @@
  * is equivalent to @ec, and a negative error code if not or if an error
  * occurred.
  */
-static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
+static int self_check_ec(struct ubi_device *ubi, int pnum, int ec)
 {
 	int err;
 	long long read_ec;
@@ -1601,9 +1576,9 @@
 
 	read_ec = be64_to_cpu(ec_hdr->ec);
 	if (ec != read_ec) {
-		ubi_err("paranoid check failed for PEB %d", pnum);
+		ubi_err("self-check failed for PEB %d", pnum);
 		ubi_err("read EC is %lld, should be %d", read_ec, ec);
-		ubi_dbg_dump_stack();
+		dump_stack();
 		err = 1;
 	} else
 		err = 0;
@@ -1614,7 +1589,7 @@
 }
 
 /**
- * paranoid_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
+ * self_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
  * @ubi: UBI device description object
  * @e: the wear-leveling entry to check
  * @root: the root of the tree
@@ -1622,9 +1597,8 @@
  * This function returns zero if @e is in the @root RB-tree and %-EINVAL if it
  * is not.
  */
-static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
-				     struct ubi_wl_entry *e,
-				     struct rb_root *root)
+static int self_check_in_wl_tree(const struct ubi_device *ubi,
+				 struct ubi_wl_entry *e, struct rb_root *root)
 {
 	if (!ubi->dbg->chk_gen)
 		return 0;
@@ -1632,22 +1606,22 @@
 	if (in_wl_tree(e, root))
 		return 0;
 
-	ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ",
+	ubi_err("self-check failed for PEB %d, EC %d, RB-tree %p ",
 		e->pnum, e->ec, root);
-	ubi_dbg_dump_stack();
+	dump_stack();
 	return -EINVAL;
 }
 
 /**
- * paranoid_check_in_pq - check if wear-leveling entry is in the protection
+ * self_check_in_pq - check if wear-leveling entry is in the protection
  *                        queue.
  * @ubi: UBI device description object
  * @e: the wear-leveling entry to check
  *
  * This function returns zero if @e is in @ubi->pq and %-EINVAL if it is not.
  */
-static int paranoid_check_in_pq(const struct ubi_device *ubi,
-				struct ubi_wl_entry *e)
+static int self_check_in_pq(const struct ubi_device *ubi,
+			    struct ubi_wl_entry *e)
 {
 	struct ubi_wl_entry *p;
 	int i;
@@ -1660,10 +1634,8 @@
 			if (p == e)
 				return 0;
 
-	ubi_err("paranoid check failed for PEB %d, EC %d, Protect queue",
+	ubi_err("self-check failed for PEB %d, EC %d, Protect queue",
 		e->pnum, e->ec);
-	ubi_dbg_dump_stack();
+	dump_stack();
 	return -EINVAL;
 }
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 1efb083..38c0690 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -35,6 +35,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 
 #define DRV_NAME			"flexcan"
 
@@ -927,11 +928,16 @@
 	struct flexcan_priv *priv;
 	struct resource *mem;
 	struct clk *clk = NULL;
+	struct pinctrl *pinctrl;
 	void __iomem *base;
 	resource_size_t mem_size;
 	int err, irq;
 	u32 clock_freq = 0;
 
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl))
+		return PTR_ERR(pinctrl);
+
 	if (pdev->dev.of_node) {
 		const u32 *clock_freq_p;
 
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index b60d6c5..03df9a8 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -75,7 +75,7 @@
 	tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
 	depends on PCI
 	---help---
-	  This driver is for the the PCIcanx and PCIcan cards (1, 2 or
+	  This driver is for the PCIcanx and PCIcan cards (1, 2 or
 	  4 channel) from Kvaser (http://www.kvaser.com).
 
 config CAN_PLX_PCI
diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c
index 1234a14..b153666 100644
--- a/drivers/net/ethernet/3com/typhoon.c
+++ b/drivers/net/ethernet/3com/typhoon.c
@@ -2549,8 +2549,7 @@
 static void __exit
 typhoon_cleanup(void)
 {
-	if (typhoon_fw)
-		release_firmware(typhoon_fw);
+	release_firmware(typhoon_fw);
 	pci_unregister_driver(&typhoon_driver);
 }
 
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index d55df32..edeeb51 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -15883,8 +15883,7 @@
 	if (dev) {
 		struct tg3 *tp = netdev_priv(dev);
 
-		if (tp->fw)
-			release_firmware(tp->fw);
+		release_firmware(tp->fw);
 
 		tg3_reset_task_cancel(tp);
 
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 25c4e7f..67cd2ed 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -3520,9 +3520,7 @@
 bnad_module_exit(void)
 {
 	pci_unregister_driver(&bnad_pci_driver);
-
-	if (bfi_fw)
-		release_firmware(bfi_fw);
+	release_firmware(bfi_fw);
 }
 
 module_init(bnad_module_init);
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 7fa0227..8f2cf8c 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -48,6 +48,7 @@
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/of_net.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <asm/cacheflush.h>
 
@@ -1543,6 +1544,7 @@
 	struct resource *r;
 	const struct of_device_id *of_id;
 	static int dev_id;
+	struct pinctrl *pinctrl;
 
 	of_id = of_match_device(fec_dt_ids, &pdev->dev);
 	if (of_id)
@@ -1610,6 +1612,12 @@
 		}
 	}
 
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		goto failed_pin;
+	}
+
 	fep->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(fep->clk)) {
 		ret = PTR_ERR(fep->clk);
@@ -1640,6 +1648,7 @@
 failed_init:
 	clk_disable_unprepare(fep->clk);
 	clk_put(fep->clk);
+failed_pin:
 failed_clk:
 	for (i = 0; i < FEC_IRQ_NUM; i++) {
 		irq = platform_get_irq(pdev, i);
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index d3469d8..8d2666f 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -40,6 +40,7 @@
 #include <linux/skbuff.h>
 #include <linux/phy.h>
 #include <linux/dma-mapping.h>
+#include <linux/of.h>
 #include <linux/of_net.h>
 #include <linux/types.h>
 
@@ -340,13 +341,17 @@
  */
 #define LPC_POWERDOWN_MACAHB			(1 << 31)
 
-/* Upon the upcoming introduction of device tree usage in LPC32xx,
- * lpc_phy_interface_mode() and use_iram_for_net() will be extended with a
- * device parameter for access to device tree information at runtime, instead
- * of defining the values at compile time
- */
-static inline phy_interface_t lpc_phy_interface_mode(void)
+static phy_interface_t lpc_phy_interface_mode(struct device *dev)
 {
+	if (dev && dev->of_node) {
+		const char *mode = of_get_property(dev->of_node,
+						   "phy-mode", NULL);
+		if (mode && !strcmp(mode, "mii"))
+			return PHY_INTERFACE_MODE_MII;
+		return PHY_INTERFACE_MODE_RMII;
+	}
+
+	/* non-DT */
 #ifdef CONFIG_ARCH_LPC32XX_MII_SUPPORT
 	return PHY_INTERFACE_MODE_MII;
 #else
@@ -354,12 +359,16 @@
 #endif
 }
 
-static inline int use_iram_for_net(void)
+static bool use_iram_for_net(struct device *dev)
 {
+	if (dev && dev->of_node)
+		return of_property_read_bool(dev->of_node, "use-iram");
+
+	/* non-DT */
 #ifdef CONFIG_ARCH_LPC32XX_IRAM_FOR_NET
-	return 1;
+	return true;
 #else
-	return 0;
+	return false;
 #endif
 }
 
@@ -664,7 +673,7 @@
 	       LPC_ENET_CLRT(pldat->net_base));
 	writel(LPC_IPGR_LOAD_PART2(0x12), LPC_ENET_IPGR(pldat->net_base));
 
-	if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII)
+	if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
 		writel(LPC_COMMAND_PASSRUNTFRAME,
 		       LPC_ENET_COMMAND(pldat->net_base));
 	else {
@@ -804,12 +813,13 @@
 	}
 
 	/* Attach to the PHY */
-	if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII)
+	if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
 		netdev_info(ndev, "using MII interface\n");
 	else
 		netdev_info(ndev, "using RMII interface\n");
 	phydev = phy_connect(ndev, dev_name(&phydev->dev),
-		&lpc_handle_link_change, 0, lpc_phy_interface_mode());
+			     &lpc_handle_link_change, 0,
+			     lpc_phy_interface_mode(&pldat->pdev->dev));
 
 	if (IS_ERR(phydev)) {
 		netdev_err(ndev, "Could not attach to PHY\n");
@@ -843,7 +853,7 @@
 	}
 
 	/* Setup MII mode */
-	if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII)
+	if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
 		writel(LPC_COMMAND_PASSRUNTFRAME,
 		       LPC_ENET_COMMAND(pldat->net_base));
 	else {
@@ -1315,18 +1325,26 @@
 static int lpc_eth_drv_probe(struct platform_device *pdev)
 {
 	struct resource *res;
-	struct resource *dma_res;
 	struct net_device *ndev;
 	struct netdata_local *pldat;
 	struct phy_device *phydev;
 	dma_addr_t dma_handle;
 	int irq, ret;
+	u32 tmp;
+
+	/* Setup network interface for RMII or MII mode */
+	tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL);
+	tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK;
+	if (lpc_phy_interface_mode(&pdev->dev) == PHY_INTERFACE_MODE_MII)
+		tmp |= LPC32XX_CLKPWR_MACCTRL_USE_MII_PINS;
+	else
+		tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS;
+	__raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL);
 
 	/* Get platform resources */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	irq = platform_get_irq(pdev, 0);
-	if ((!res) || (!dma_res) || (irq < 0) || (irq >= NR_IRQS)) {
+	if ((!res) || (irq < 0) || (irq >= NR_IRQS)) {
 		dev_err(&pdev->dev, "error getting resources.\n");
 		ret = -ENXIO;
 		goto err_exit;
@@ -1389,17 +1407,19 @@
 		sizeof(struct txrx_desc_t) + sizeof(struct rx_status_t));
 	pldat->dma_buff_base_v = 0;
 
-	if (use_iram_for_net()) {
-		dma_handle = dma_res->start;
+	if (use_iram_for_net(&pldat->pdev->dev)) {
+		dma_handle = LPC32XX_IRAM_BASE;
 		if (pldat->dma_buff_size <= lpc32xx_return_iram_size())
 			pldat->dma_buff_base_v =
-				io_p2v(dma_res->start);
+				io_p2v(LPC32XX_IRAM_BASE);
 		else
 			netdev_err(ndev,
 				"IRAM not big enough for net buffers, using SDRAM instead.\n");
 	}
 
 	if (pldat->dma_buff_base_v == 0) {
+		pldat->pdev->dev.coherent_dma_mask = 0xFFFFFFFF;
+		pldat->pdev->dev.dma_mask = &pldat->pdev->dev.coherent_dma_mask;
 		pldat->dma_buff_size = PAGE_ALIGN(pldat->dma_buff_size);
 
 		/* Allocate a chunk of memory for the DMA ethernet buffers
@@ -1488,7 +1508,7 @@
 	platform_set_drvdata(pdev, NULL);
 	unregister_netdev(ndev);
 err_out_dma_unmap:
-	if (!use_iram_for_net() ||
+	if (!use_iram_for_net(&pldat->pdev->dev) ||
 	    pldat->dma_buff_size > lpc32xx_return_iram_size())
 		dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size,
 				  pldat->dma_buff_base_v,
@@ -1515,7 +1535,7 @@
 	unregister_netdev(ndev);
 	platform_set_drvdata(pdev, NULL);
 
-	if (!use_iram_for_net() ||
+	if (!use_iram_for_net(&pldat->pdev->dev) ||
 	    pldat->dma_buff_size > lpc32xx_return_iram_size())
 		dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size,
 				  pldat->dma_buff_base_v,
@@ -1584,6 +1604,14 @@
 }
 #endif
 
+#ifdef CONFIG_OF
+static const struct of_device_id lpc_eth_match[] = {
+	{ .compatible = "nxp,lpc-eth" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, lpc_eth_match);
+#endif
+
 static struct platform_driver lpc_eth_driver = {
 	.probe		= lpc_eth_drv_probe,
 	.remove		= __devexit_p(lpc_eth_drv_remove),
@@ -1593,6 +1621,7 @@
 #endif
 	.driver		= {
 		.name	= MODNAME,
+		.of_match_table = of_match_ptr(lpc_eth_match),
 	},
 };
 
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
index 0d725dc..8694124 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
@@ -1260,8 +1260,7 @@
 void
 netxen_release_firmware(struct netxen_adapter *adapter)
 {
-	if (adapter->fw)
-		release_firmware(adapter->fw);
+	release_firmware(adapter->fw);
 	adapter->fw = NULL;
 }
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index d32cf0d..799fd40 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -1321,8 +1321,7 @@
 void
 qlcnic_release_firmware(struct qlcnic_adapter *adapter)
 {
-	if (adapter->fw)
-		release_firmware(adapter->fw);
+	release_firmware(adapter->fw);
 	adapter->fw = NULL;
 }
 
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 4f74b97..00b4f56 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -6051,7 +6051,7 @@
 	pm_runtime_get_sync(&pdev->dev);
 
 	/*
-	 * Rx and Tx desscriptors needs 256 bytes alignment.
+	 * Rx and Tx descriptors needs 256 bytes alignment.
 	 * dma_alloc_coherent provides more.
 	 */
 	tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c
index 8e9fda0..2ed3ab4 100644
--- a/drivers/net/ethernet/s6gmac.c
+++ b/drivers/net/ethernet/s6gmac.c
@@ -1,7 +1,7 @@
 /*
  * Ethernet driver for S6105 on chip network device
  * (c)2008 emlix GmbH http://www.emlix.com
- * Authors:	Oskar Schirmer <os@emlix.com>
+ * Authors:	Oskar Schirmer <oskar@scara.com>
  *		Daniel Gloeckner <dg@emlix.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -1070,4 +1070,4 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("S6105 on chip Ethernet driver");
-MODULE_AUTHOR("Oskar Schirmer <os@emlix.com>");
+MODULE_AUTHOR("Oskar Schirmer <oskar@scara.com>");
diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c
index 8846516..447a693 100644
--- a/drivers/net/ethernet/tehuti/tehuti.c
+++ b/drivers/net/ethernet/tehuti/tehuti.c
@@ -341,8 +341,8 @@
 out:
 	if (master)
 		WRITE_REG(priv, regINIT_SEMAPHORE, 1);
-	if (fw)
-		release_firmware(fw);
+
+	release_firmware(fw);
 
 	if (rc) {
 		netdev_err(priv->ndev, "firmware loading failed\n");
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 3575844..5952054 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -211,8 +211,8 @@
 	  kingsun-sir.
 
 config EP7211_DONGLE
-	tristate "EP7211 I/R support"
-	depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL
+	tristate "Cirrus Logic clps711x I/R support"
+	depends on IRTTY_SIR && ARCH_CLPS711X && IRDA && EXPERIMENTAL
 	help
 	  Say Y here if you want to build support for the Cirrus logic
 	  EP7211 chipset's infrared module.
@@ -316,7 +316,7 @@
 	tristate "Alchemy IrDA SIR/FIR"
 	depends on IRDA && MIPS_ALCHEMY
 	help
-	  Say Y/M here to build suppor the the IrDA peripheral on the
+	  Say Y/M here to build support the IrDA peripheral on the
 	  Alchemy Au1000 and Au1100 SoCs.
 	  Say M to build a module; it will be called au1k_ir.ko
 
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 72f687b..f9a86bd 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1671,7 +1671,7 @@
 
 	/* Is this really necessary? (no, except maybe for broken devices) */
 	if (usb_reset_configuration (dev) < 0) {
-		err("reset_configuration failed");
+		dev_err(&intf->dev, "reset_configuration failed\n");
 		ret = -EIO;
 		goto err_out_3;
 	}
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index 79aebee..7b48338 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -134,14 +134,16 @@
 
 	/* in process of stopping, just drop data */
 	if (!netif_running(kingsun->netdev)) {
-		err("kingsun_send_irq: Network not running!");
+		dev_err(&kingsun->usbdev->dev,
+			"kingsun_send_irq: Network not running!\n");
 		return;
 	}
 
 	/* unlink, shutdown, unplug, other nasties */
 	if (urb->status != 0) {
-		err("kingsun_send_irq: urb asynchronously failed - %d",
-		    urb->status);
+		dev_err(&kingsun->usbdev->dev,
+			"kingsun_send_irq: urb asynchronously failed - %d\n",
+			urb->status);
 	}
 	netif_wake_queue(netdev);
 }
@@ -177,7 +179,8 @@
 		kingsun, 1);
 
 	if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
-		err("kingsun_hard_xmit: failed tx_urb submit: %d", ret);
+		dev_err(&kingsun->usbdev->dev,
+			"kingsun_hard_xmit: failed tx_urb submit: %d\n", ret);
 		switch (ret) {
 		case -ENODEV:
 		case -EPIPE:
@@ -211,8 +214,9 @@
 
 	/* unlink, shutdown, unplug, other nasties */
 	if (urb->status != 0) {
-		err("kingsun_rcv_irq: urb asynchronously failed - %d",
-		    urb->status);
+		dev_err(&kingsun->usbdev->dev,
+			"kingsun_rcv_irq: urb asynchronously failed - %d\n",
+			urb->status);
 		kingsun->receiving = 0;
 		return;
 	}
@@ -238,8 +242,9 @@
 				? 1 : 0;
 		}
 	} else if (urb->actual_length > 0) {
-		err("%s(): Unexpected response length, expected %d got %d",
-		    __func__, kingsun->max_rx, urb->actual_length);
+		dev_err(&kingsun->usbdev->dev,
+			"%s(): Unexpected response length, expected %d got %d\n",
+			__func__, kingsun->max_rx, urb->actual_length);
 	}
 	/* This urb has already been filled in kingsun_net_open */
 	ret = usb_submit_urb(urb, GFP_ATOMIC);
@@ -286,7 +291,7 @@
 	sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
 	kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
 	if (!kingsun->irlap) {
-		err("kingsun-sir: irlap_open failed");
+		dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
 		goto free_mem;
 	}
 
@@ -298,7 +303,8 @@
 	kingsun->rx_urb->status = 0;
 	err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
 	if (err) {
-		err("kingsun-sir: first urb-submit failed: %d", err);
+		dev_err(&kingsun->usbdev->dev,
+			"first urb-submit failed: %d\n", err);
 		goto close_irlap;
 	}
 
@@ -446,13 +452,15 @@
 	 */
 	interface = intf->cur_altsetting;
 	if (interface->desc.bNumEndpoints != 2) {
-		err("kingsun-sir: expected 2 endpoints, found %d",
-		    interface->desc.bNumEndpoints);
+		dev_err(&intf->dev,
+			"kingsun-sir: expected 2 endpoints, found %d\n",
+			interface->desc.bNumEndpoints);
 		return -ENODEV;
 	}
 	endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
 	if (!usb_endpoint_is_int_in(endpoint)) {
-		err("kingsun-sir: endpoint 0 is not interrupt IN");
+		dev_err(&intf->dev,
+			"kingsun-sir: endpoint 0 is not interrupt IN\n");
 		return -ENODEV;
 	}
 
@@ -460,14 +468,16 @@
 	pipe = usb_rcvintpipe(dev, ep_in);
 	maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 	if (maxp_in > 255 || maxp_in <= 1) {
-		err("%s: endpoint 0 has max packet size %d not in range",
-		    __FILE__, maxp_in);
+		dev_err(&intf->dev,
+			"endpoint 0 has max packet size %d not in range\n",
+			maxp_in);
 		return -ENODEV;
 	}
 
 	endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
 	if (!usb_endpoint_is_int_out(endpoint)) {
-		err("kingsun-sir: endpoint 1 is not interrupt OUT");
+		dev_err(&intf->dev,
+			"kingsun-sir: endpoint 1 is not interrupt OUT\n");
 		return -ENODEV;
 	}
 
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index abe689d..824e2a9 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -247,8 +247,9 @@
 {
 	/* unlink, shutdown, unplug, other nasties */
 	if (urb->status != 0) {
-		err("ks959_speed_irq: urb asynchronously failed - %d",
-		    urb->status);
+		dev_err(&urb->dev->dev,
+			"ks959_speed_irq: urb asynchronously failed - %d\n",
+			urb->status);
 	}
 }
 
@@ -332,14 +333,16 @@
 
 	/* in process of stopping, just drop data */
 	if (!netif_running(kingsun->netdev)) {
-		err("ks959_send_irq: Network not running!");
+		dev_err(&kingsun->usbdev->dev,
+			"ks959_send_irq: Network not running!\n");
 		return;
 	}
 
 	/* unlink, shutdown, unplug, other nasties */
 	if (urb->status != 0) {
-		err("ks959_send_irq: urb asynchronously failed - %d",
-		    urb->status);
+		dev_err(&kingsun->usbdev->dev,
+			"ks959_send_irq: urb asynchronously failed - %d\n",
+			urb->status);
 		return;
 	}
 
@@ -358,8 +361,9 @@
 		if (kingsun->tx_buf_clear_used > 0) {
 			/* There is more data to be sent */
 			if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
-				err("ks959_send_irq: failed tx_urb submit: %d",
-				    ret);
+				dev_err(&kingsun->usbdev->dev,
+					"ks959_send_irq: failed tx_urb submit: %d\n",
+					ret);
 				switch (ret) {
 				case -ENODEV:
 				case -EPIPE:
@@ -407,7 +411,8 @@
 	kingsun->tx_buf_clear_used = wraplen;
 
 	if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
-		err("ks959_hard_xmit: failed tx_urb submit: %d", ret);
+		dev_err(&kingsun->usbdev->dev,
+			"ks959_hard_xmit: failed tx_urb submit: %d\n", ret);
 		switch (ret) {
 		case -ENODEV:
 		case -EPIPE:
@@ -442,8 +447,9 @@
 
 	/* unlink, shutdown, unplug, other nasties */
 	if (urb->status != 0) {
-		err("kingsun_rcv_irq: urb asynchronously failed - %d",
-		    urb->status);
+		dev_err(&kingsun->usbdev->dev,
+			"kingsun_rcv_irq: urb asynchronously failed - %d\n",
+			urb->status);
 		kingsun->receiving = 0;
 		return;
 	}
@@ -536,7 +542,7 @@
 	sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
 	kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
 	if (!kingsun->irlap) {
-		err("ks959-sir: irlap_open failed");
+		dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
 		goto free_mem;
 	}
 
@@ -549,7 +555,8 @@
 	kingsun->rx_urb->status = 0;
 	err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
 	if (err) {
-		err("ks959-sir: first urb-submit failed: %d", err);
+		dev_err(&kingsun->usbdev->dev,
+			"first urb-submit failed: %d\n", err);
 		goto close_irlap;
 	}
 
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
index f8c0108..5a278ab 100644
--- a/drivers/net/irda/ksdazzle-sir.c
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -168,10 +168,10 @@
 static void ksdazzle_speed_irq(struct urb *urb)
 {
 	/* unlink, shutdown, unplug, other nasties */
-	if (urb->status != 0) {
-		err("ksdazzle_speed_irq: urb asynchronously failed - %d",
-		    urb->status);
-	}
+	if (urb->status != 0)
+		dev_err(&urb->dev->dev,
+			"ksdazzle_speed_irq: urb asynchronously failed - %d\n",
+			urb->status);
 }
 
 /* Send a control request to change speed of the dongle */
@@ -245,14 +245,16 @@
 
 	/* in process of stopping, just drop data */
 	if (!netif_running(kingsun->netdev)) {
-		err("ksdazzle_send_irq: Network not running!");
+		dev_err(&kingsun->usbdev->dev,
+			"ksdazzle_send_irq: Network not running!\n");
 		return;
 	}
 
 	/* unlink, shutdown, unplug, other nasties */
 	if (urb->status != 0) {
-		err("ksdazzle_send_irq: urb asynchronously failed - %d",
-		    urb->status);
+		dev_err(&kingsun->usbdev->dev,
+			"ksdazzle_send_irq: urb asynchronously failed - %d\n",
+			urb->status);
 		return;
 	}
 
@@ -271,7 +273,9 @@
 		if (kingsun->tx_buf_clear_used > 0) {
 			/* There is more data to be sent */
 			if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
-				err("ksdazzle_send_irq: failed tx_urb submit: %d", ret);
+				dev_err(&kingsun->usbdev->dev,
+					"ksdazzle_send_irq: failed tx_urb submit: %d\n",
+					ret);
 				switch (ret) {
 				case -ENODEV:
 				case -EPIPE:
@@ -320,7 +324,8 @@
 	kingsun->tx_buf_clear_used = wraplen;
 
 	if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
-		err("ksdazzle_hard_xmit: failed tx_urb submit: %d", ret);
+		dev_err(&kingsun->usbdev->dev,
+			"ksdazzle_hard_xmit: failed tx_urb submit: %d\n", ret);
 		switch (ret) {
 		case -ENODEV:
 		case -EPIPE:
@@ -355,8 +360,9 @@
 
 	/* unlink, shutdown, unplug, other nasties */
 	if (urb->status != 0) {
-		err("ksdazzle_rcv_irq: urb asynchronously failed - %d",
-		    urb->status);
+		dev_err(&kingsun->usbdev->dev,
+			"ksdazzle_rcv_irq: urb asynchronously failed - %d\n",
+			urb->status);
 		kingsun->receiving = 0;
 		return;
 	}
@@ -430,7 +436,7 @@
 	sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
 	kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
 	if (!kingsun->irlap) {
-		err("ksdazzle-sir: irlap_open failed");
+		dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
 		goto free_mem;
 	}
 
@@ -442,7 +448,7 @@
 	kingsun->rx_urb->status = 0;
 	err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
 	if (err) {
-		err("ksdazzle-sir: first urb-submit failed: %d", err);
+		dev_err(&kingsun->usbdev->dev, "first urb-submit failed: %d\n", err);
 		goto close_irlap;
 	}
 
@@ -590,13 +596,14 @@
 	 */
 	interface = intf->cur_altsetting;
 	if (interface->desc.bNumEndpoints != 2) {
-		err("ksdazzle: expected 2 endpoints, found %d",
-		    interface->desc.bNumEndpoints);
+		dev_err(&intf->dev, "ksdazzle: expected 2 endpoints, found %d\n",
+			interface->desc.bNumEndpoints);
 		return -ENODEV;
 	}
 	endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
 	if (!usb_endpoint_is_int_in(endpoint)) {
-		err("ksdazzle: endpoint 0 is not interrupt IN");
+		dev_err(&intf->dev,
+			"ksdazzle: endpoint 0 is not interrupt IN\n");
 		return -ENODEV;
 	}
 
@@ -604,13 +611,16 @@
 	pipe = usb_rcvintpipe(dev, ep_in);
 	maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 	if (maxp_in > 255 || maxp_in <= 1) {
-		err("ksdazzle: endpoint 0 has max packet size %d not in range [2..255]", maxp_in);
+		dev_err(&intf->dev,
+			"ksdazzle: endpoint 0 has max packet size %d not in range [2..255]\n",
+			maxp_in);
 		return -ENODEV;
 	}
 
 	endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
 	if (!usb_endpoint_is_int_out(endpoint)) {
-		err("ksdazzle: endpoint 1 is not interrupt OUT");
+		dev_err(&intf->dev,
+			"ksdazzle: endpoint 1 is not interrupt OUT\n");
 		return -ENODEV;
 	}
 
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index e6e59a0..876e709 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -904,7 +904,7 @@
 	sprintf(hwname, "usb#%d", stir->usbdev->devnum);
 	stir->irlap = irlap_open(netdev, &stir->qos, hwname);
 	if (!stir->irlap) {
-		err("stir4200: irlap_open failed");
+		dev_err(&stir->usbdev->dev, "irlap_open failed\n");
 		goto err_out5;
 	}
 
@@ -913,7 +913,7 @@
 				   "%s", stir->netdev->name);
         if (IS_ERR(stir->thread)) {
                 err = PTR_ERR(stir->thread);
-		err("stir4200: unable to start kernel thread");
+		dev_err(&stir->usbdev->dev, "unable to start kernel thread\n");
 		goto err_out6;
 	}
 
@@ -1042,7 +1042,7 @@
 
 	ret = usb_reset_configuration(dev);
 	if (ret != 0) {
-		err("stir4200: usb reset configuration failed");
+		dev_err(&intf->dev, "usb reset configuration failed\n");
 		goto err_out2;
 	}
 
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 42b5151..71e2b05 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1647,6 +1647,7 @@
 	.resume =	usbnet_resume,
 	.disconnect =	usbnet_disconnect,
 	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(asix_driver);
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 182cfb4..26c5beb 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -338,16 +338,18 @@
 		} else {
 			catc->rx_urb->dev = catc->usbdev;
 			if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) {
-				err("submit(rx_urb) status %d", res);
+				dev_err(&catc->usbdev->dev,
+					"submit(rx_urb) status %d\n", res);
 			}
 		} 
 	}
 resubmit:
 	res = usb_submit_urb (urb, GFP_ATOMIC);
 	if (res)
-		err ("can't resubmit intr, %s-%s, status %d",
-				catc->usbdev->bus->bus_name,
-				catc->usbdev->devpath, res);
+		dev_err(&catc->usbdev->dev,
+			"can't resubmit intr, %s-%s, status %d\n",
+			catc->usbdev->bus->bus_name,
+			catc->usbdev->devpath, res);
 }
 
 /*
@@ -366,7 +368,8 @@
 	catc->tx_urb->dev = catc->usbdev;
 
 	if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0)
-		err("submit(tx_urb), status %d", status);
+		dev_err(&catc->usbdev->dev, "submit(tx_urb), status %d\n",
+			status);
 
 	catc->tx_idx = !catc->tx_idx;
 	catc->tx_ptr = 0;
@@ -496,7 +499,8 @@
 		memcpy(catc->ctrl_buf, q->buf, q->len);
 
 	if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC)))
-		err("submit(ctrl_urb) status %d", status);
+		dev_err(&catc->usbdev->dev, "submit(ctrl_urb) status %d\n",
+			status);
 }
 
 static void catc_ctrl_done(struct urb *urb)
@@ -555,7 +559,7 @@
 	catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1);
 
 	if (catc->ctrl_head == catc->ctrl_tail) {
-		err("ctrl queue full");
+		dev_err(&catc->usbdev->dev, "ctrl queue full\n");
 		catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);
 		retval = -1;
 	}
@@ -714,7 +718,8 @@
 
 	catc->irq_urb->dev = catc->usbdev;
 	if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) {
-		err("submit(irq_urb) status %d", status);
+		dev_err(&catc->usbdev->dev, "submit(irq_urb) status %d\n",
+			status);
 		return -1;
 	}
 
@@ -769,7 +774,7 @@
 
 	if (usb_set_interface(usbdev,
 			intf->altsetting->desc.bInterfaceNumber, 1)) {
-                err("Can't set altsetting 1.");
+                dev_err(&intf->dev, "Can't set altsetting 1.\n");
 		return -EIO;
 	}
 
@@ -799,7 +804,7 @@
 	catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if ((!catc->ctrl_urb) || (!catc->tx_urb) || 
 	    (!catc->rx_urb) || (!catc->irq_urb)) {
-		err("No free urbs available.");
+		dev_err(&intf->dev, "No free urbs available.\n");
 		usb_free_urb(catc->ctrl_urb);
 		usb_free_urb(catc->tx_urb);
 		usb_free_urb(catc->rx_urb);
@@ -947,6 +952,7 @@
 	.probe =	catc_probe,
 	.disconnect =	catc_disconnect,
 	.id_table =	catc_id_table,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(catc_driver);
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index 3e41b00..d848d4d 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -457,6 +457,7 @@
 	.probe =	usbpn_probe,
 	.disconnect =	usbpn_disconnect,
 	.id_table =	usbpn_ids,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(usbpn_driver);
diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c
index 685a4e2..434d5af 100644
--- a/drivers/net/usb/cdc_eem.c
+++ b/drivers/net/usb/cdc_eem.c
@@ -368,6 +368,7 @@
 	.disconnect =	usbnet_disconnect,
 	.suspend =	usbnet_suspend,
 	.resume =	usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(eem_driver);
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index fffee6a..a03de71 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -705,6 +705,7 @@
 	.resume =	usbnet_resume,
 	.reset_resume =	usbnet_resume,
 	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(cdc_driver);
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 7adc9f6..4b9513f 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1212,6 +1212,7 @@
 	.resume = usbnet_resume,
 	.reset_resume =	usbnet_resume,
 	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 static const struct ethtool_ops cdc_ncm_ethtool_ops = {
diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c
index b403d93..0d1fe89 100644
--- a/drivers/net/usb/cdc_subset.c
+++ b/drivers/net/usb/cdc_subset.c
@@ -336,6 +336,7 @@
 	.resume =	usbnet_resume,
 	.disconnect =	usbnet_disconnect,
 	.id_table =	products,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(cdc_subset_driver);
diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c
index 0e05313..49ab45e 100644
--- a/drivers/net/usb/cx82310_eth.c
+++ b/drivers/net/usb/cx82310_eth.c
@@ -327,6 +327,7 @@
 	.disconnect	= usbnet_disconnect,
 	.suspend	= usbnet_suspend,
 	.resume		= usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(cx82310_driver);
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index b972263..e0433ce 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -670,6 +670,7 @@
 	.disconnect = usbnet_disconnect,
 	.suspend = usbnet_suspend,
 	.resume = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(dm9601_driver);
diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c
index 38266bd..db3c802 100644
--- a/drivers/net/usb/gl620a.c
+++ b/drivers/net/usb/gl620a.c
@@ -225,6 +225,7 @@
 	.disconnect =	usbnet_disconnect,
 	.suspend =	usbnet_suspend,
 	.resume =	usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(gl620a_driver);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 2d2a688..62f30b4 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -106,13 +106,6 @@
 
 #define MAX_RX_URBS			2
 
-static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty)
-{
-	if (tty)
-		return tty->driver_data;
-	return NULL;
-}
-
 /*****************************************************************************/
 /* Debugging functions                                                       */
 /*****************************************************************************/
@@ -255,9 +248,8 @@
 	u8 dtr_state;
 	unsigned tx_urb_used:1;
 
+	struct tty_port port;
 	/* from usb_serial_port */
-	struct tty_struct *tty;
-	int open_count;
 	spinlock_t serial_lock;
 
 	int (*write_data) (struct hso_serial *serial);
@@ -1114,7 +1106,7 @@
 static void _hso_serial_set_termios(struct tty_struct *tty,
 				    struct ktermios *old)
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	struct ktermios *termios;
 
 	if (!serial) {
@@ -1190,7 +1182,7 @@
 	struct urb *urb;
 
 	urb = serial->rx_urb[0];
-	if (serial->open_count > 0) {
+	if (serial->port.count > 0) {
 		count = put_rxbuf_data(urb, serial);
 		if (count == -1)
 			return;
@@ -1226,7 +1218,7 @@
 	DUMP1(urb->transfer_buffer, urb->actual_length);
 
 	/* Anyone listening? */
-	if (serial->open_count == 0)
+	if (serial->port.count == 0)
 		return;
 
 	if (status == 0) {
@@ -1268,7 +1260,7 @@
 
 static	void hso_unthrottle(struct tty_struct *tty)
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 
 	tasklet_hi_schedule(&serial->unthrottle_tasklet);
 }
@@ -1304,15 +1296,12 @@
 	kref_get(&serial->parent->ref);
 
 	/* setup */
-	spin_lock_irq(&serial->serial_lock);
 	tty->driver_data = serial;
-	tty_kref_put(serial->tty);
-	serial->tty = tty_kref_get(tty);
-	spin_unlock_irq(&serial->serial_lock);
+	tty_port_tty_set(&serial->port, tty);
 
 	/* check for port already opened, if not set the termios */
-	serial->open_count++;
-	if (serial->open_count == 1) {
+	serial->port.count++;
+	if (serial->port.count == 1) {
 		serial->rx_state = RX_IDLE;
 		/* Force default termio settings */
 		_hso_serial_set_termios(tty, NULL);
@@ -1324,7 +1313,7 @@
 		result = hso_start_serial_device(serial->parent, GFP_KERNEL);
 		if (result) {
 			hso_stop_serial_device(serial->parent);
-			serial->open_count--;
+			serial->port.count--;
 			kref_put(&serial->parent->ref, hso_serial_ref_free);
 		}
 	} else {
@@ -1361,17 +1350,11 @@
 
 	/* reset the rts and dtr */
 	/* do the actual close */
-	serial->open_count--;
+	serial->port.count--;
 
-	if (serial->open_count <= 0) {
-		serial->open_count = 0;
-		spin_lock_irq(&serial->serial_lock);
-		if (serial->tty == tty) {
-			serial->tty->driver_data = NULL;
-			serial->tty = NULL;
-			tty_kref_put(tty);
-		}
-		spin_unlock_irq(&serial->serial_lock);
+	if (serial->port.count <= 0) {
+		serial->port.count = 0;
+		tty_port_tty_set(&serial->port, NULL);
 		if (!usb_gone)
 			hso_stop_serial_device(serial->parent);
 		tasklet_kill(&serial->unthrottle_tasklet);
@@ -1390,7 +1373,7 @@
 static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
 			    int count)
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	int space, tx_bytes;
 	unsigned long flags;
 
@@ -1422,7 +1405,7 @@
 /* how much room is there for writing */
 static int hso_serial_write_room(struct tty_struct *tty)
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	int room;
 	unsigned long flags;
 
@@ -1437,7 +1420,7 @@
 /* setup the term */
 static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	unsigned long flags;
 
 	if (old)
@@ -1446,7 +1429,7 @@
 
 	/* the actual setup */
 	spin_lock_irqsave(&serial->serial_lock, flags);
-	if (serial->open_count)
+	if (serial->port.count)
 		_hso_serial_set_termios(tty, old);
 	else
 		tty->termios = old;
@@ -1458,7 +1441,7 @@
 /* how many characters in the buffer */
 static int hso_serial_chars_in_buffer(struct tty_struct *tty)
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	int chars;
 	unsigned long flags;
 
@@ -1629,7 +1612,7 @@
 		  struct serial_icounter_struct *icount)
 {
 	struct uart_icount cnow;
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	struct hso_tiocmget  *tiocmget = serial->tiocmget;
 
 	memset(icount, 0, sizeof(struct serial_icounter_struct));
@@ -1659,7 +1642,7 @@
 static int hso_serial_tiocmget(struct tty_struct *tty)
 {
 	int retval;
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	struct hso_tiocmget  *tiocmget;
 	u16 UART_state_bitmap;
 
@@ -1693,7 +1676,7 @@
 	int val = 0;
 	unsigned long flags;
 	int if_num;
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 
 	/* sanity check */
 	if (!serial) {
@@ -1733,7 +1716,7 @@
 static int hso_serial_ioctl(struct tty_struct *tty,
 			    unsigned int cmd, unsigned long arg)
 {
-	struct hso_serial *serial =  get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	int ret = 0;
 	D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
 
@@ -1905,7 +1888,7 @@
 				D1("Pending read interrupt on port %d\n", i);
 				spin_lock(&serial->serial_lock);
 				if (serial->rx_state == RX_IDLE &&
-					serial->open_count > 0) {
+					serial->port.count > 0) {
 					/* Setup and send a ctrl req read on
 					 * port i */
 					if (!serial->rx_urb_filled[0]) {
@@ -1954,14 +1937,13 @@
 
 	spin_lock(&serial->serial_lock);
 	serial->tx_urb_used = 0;
-	tty = tty_kref_get(serial->tty);
 	spin_unlock(&serial->serial_lock);
 	if (status) {
 		handle_usb_error(status, __func__, serial->parent);
-		tty_kref_put(tty);
 		return;
 	}
 	hso_put_activity(serial->parent);
+	tty = tty_port_tty_get(&serial->port);
 	if (tty) {
 		tty_wakeup(tty);
 		tty_kref_put(tty);
@@ -2001,7 +1983,6 @@
 	struct hso_serial *serial = urb->context;
 	struct usb_ctrlrequest *req;
 	int status = urb->status;
-	struct tty_struct *tty;
 
 	/* sanity check */
 	if (!serial)
@@ -2009,11 +1990,9 @@
 
 	spin_lock(&serial->serial_lock);
 	serial->tx_urb_used = 0;
-	tty = tty_kref_get(serial->tty);
 	spin_unlock(&serial->serial_lock);
 	if (status) {
 		handle_usb_error(status, __func__, serial->parent);
-		tty_kref_put(tty);
 		return;
 	}
 
@@ -2031,13 +2010,15 @@
 		put_rxbuf_data_and_resubmit_ctrl_urb(serial);
 		spin_unlock(&serial->serial_lock);
 	} else {
+		struct tty_struct *tty = tty_port_tty_get(&serial->port);
 		hso_put_activity(serial->parent);
-		if (tty)
+		if (tty) {
 			tty_wakeup(tty);
+			tty_kref_put(tty);
+		}
 		/* response to a write command */
 		hso_kick_transmit(serial);
 	}
-	tty_kref_put(tty);
 }
 
 /* handle RX data for serial port */
@@ -2053,8 +2034,7 @@
 		return -2;
 	}
 
-	/* All callers to put_rxbuf_data hold serial_lock */
-	tty = tty_kref_get(serial->tty);
+	tty = tty_port_tty_get(&serial->port);
 
 	/* Push data to tty */
 	if (tty) {
@@ -2074,12 +2054,12 @@
 			write_length_remaining -= curr_write_len;
 			tty_flip_buffer_push(tty);
 		}
+		tty_kref_put(tty);
 	}
 	if (write_length_remaining == 0) {
 		serial->curr_rx_urb_offset = 0;
 		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
 	}
-	tty_kref_put(tty);
 	return write_length_remaining;
 }
 
@@ -2320,6 +2300,7 @@
 	serial->minor = minor;
 	serial->magic = HSO_SERIAL_MAGIC;
 	spin_lock_init(&serial->serial_lock);
+	tty_port_init(&serial->port);
 	serial->num_rx_urbs = num_urbs;
 
 	/* RX, allocate urb and initialize */
@@ -3098,7 +3079,7 @@
 	/* Start all serial ports */
 	for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
 		if (serial_table[i] && (serial_table[i]->interface == iface)) {
-			if (dev2ser(serial_table[i])->open_count) {
+			if (dev2ser(serial_table[i])->port.count) {
 				result =
 				    hso_start_serial_device(serial_table[i], GFP_NOIO);
 				hso_kick_transmit(dev2ser(serial_table[i]));
@@ -3172,13 +3153,12 @@
 		if (serial_table[i] &&
 		    (serial_table[i]->interface == interface)) {
 			hso_dev = dev2ser(serial_table[i]);
-			spin_lock_irq(&hso_dev->serial_lock);
-			tty = tty_kref_get(hso_dev->tty);
-			spin_unlock_irq(&hso_dev->serial_lock);
-			if (tty)
+			tty = tty_port_tty_get(&hso_dev->port);
+			if (tty) {
 				tty_hangup(tty);
+				tty_kref_put(tty);
+			}
 			mutex_lock(&hso_dev->parent->mutex);
-			tty_kref_put(tty);
 			hso_dev->parent->usb_gone = 1;
 			mutex_unlock(&hso_dev->parent->mutex);
 			kref_put(&serial_table[i]->ref, hso_serial_ref_free);
@@ -3291,6 +3271,7 @@
 	.resume = hso_resume,
 	.reset_resume = hso_resume,
 	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 static int __init hso_init(void)
@@ -3312,7 +3293,6 @@
 		return -ENOMEM;
 
 	/* fill in all needed values */
-	tty_drv->magic = TTY_DRIVER_MAGIC;
 	tty_drv->driver_name = driver_name;
 	tty_drv->name = tty_filename;
 
@@ -3333,7 +3313,7 @@
 	if (result) {
 		printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
 			__func__, result);
-		return result;
+		goto err_free_tty;
 	}
 
 	/* register this module as an usb driver */
@@ -3341,13 +3321,16 @@
 	if (result) {
 		printk(KERN_ERR "Could not register hso driver? error: %d\n",
 			result);
-		/* cleanup serial interface */
-		tty_unregister_driver(tty_drv);
-		return result;
+		goto err_unreg_tty;
 	}
 
 	/* done */
 	return 0;
+err_unreg_tty:
+	tty_unregister_driver(tty_drv);
+err_free_tty:
+	put_tty_driver(tty_drv);
+	return result;
 }
 
 static void __exit hso_exit(void)
@@ -3355,6 +3338,7 @@
 	printk(KERN_INFO "hso: unloaded\n");
 
 	tty_unregister_driver(tty_drv);
+	put_tty_driver(tty_drv);
 	/* deregister the usb driver */
 	usb_deregister(&hso_driver);
 }
diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c
index 12a22a4..8de6417 100644
--- a/drivers/net/usb/int51x1.c
+++ b/drivers/net/usb/int51x1.c
@@ -236,6 +236,7 @@
 	.disconnect = usbnet_disconnect,
 	.suspend    = usbnet_suspend,
 	.resume     = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(int51x1_driver);
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index dd78c4c..964031e 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -209,7 +209,8 @@
 	case 0:
 		break;
 	default:
-		err("%s: urb status: %d", __func__, status);
+		dev_err(&dev->intf->dev, "%s: urb status: %d\n",
+			__func__, status);
 		return;
 	}
 
@@ -222,7 +223,8 @@
 
 	skb = dev_alloc_skb(len);
 	if (!skb) {
-		err("%s: dev_alloc_skb: -ENOMEM", __func__);
+		dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n",
+			__func__);
 		dev->net->stats.rx_dropped++;
 		return;
 	}
@@ -251,7 +253,8 @@
 	    status != -ENOENT &&
 	    status != -ECONNRESET &&
 	    status != -ESHUTDOWN)
-		err("%s: urb status: %d", __func__, status);
+		dev_err(&dev->intf->dev, "%s: urb status: %d\n",
+		__func__, status);
 
 	dev_kfree_skb_irq(dev->tx_skb);
 	netif_wake_queue(dev->net);
@@ -271,7 +274,8 @@
 			dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE,
 			IPHETH_CTRL_TIMEOUT);
 	if (retval < 0) {
-		err("%s: usb_control_msg: %d", __func__, retval);
+		dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
+			__func__, retval);
 		return retval;
 	}
 
@@ -308,9 +312,11 @@
 				 IPHETH_CTRL_BUF_SIZE,
 				 IPHETH_CTRL_TIMEOUT);
 	if (retval < 0) {
-		err("%s: usb_control_msg: %d", __func__, retval);
+		dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
+			__func__, retval);
 	} else if (retval < ETH_ALEN) {
-		err("%s: usb_control_msg: short packet: %d bytes",
+		dev_err(&dev->intf->dev,
+			"%s: usb_control_msg: short packet: %d bytes\n",
 			__func__, retval);
 		retval = -EINVAL;
 	} else {
@@ -335,7 +341,8 @@
 
 	retval = usb_submit_urb(dev->rx_urb, mem_flags);
 	if (retval)
-		err("%s: usb_submit_urb: %d", __func__, retval);
+		dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
+			__func__, retval);
 	return retval;
 }
 
@@ -396,7 +403,8 @@
 
 	retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC);
 	if (retval) {
-		err("%s: usb_submit_urb: %d", __func__, retval);
+		dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
+			__func__, retval);
 		dev->net->stats.tx_errors++;
 		dev_kfree_skb_irq(skb);
 	} else {
@@ -414,7 +422,7 @@
 {
 	struct ipheth_device *dev = netdev_priv(net);
 
-	err("%s: TX timeout", __func__);
+	dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__);
 	dev->net->stats.tx_errors++;
 	usb_unlink_urb(dev->tx_urb);
 }
@@ -464,7 +472,7 @@
 	hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
 	if (hintf == NULL) {
 		retval = -ENODEV;
-		err("Unable to find alternate settings interface");
+		dev_err(&intf->dev, "Unable to find alternate settings interface\n");
 		goto err_endpoints;
 	}
 
@@ -477,7 +485,7 @@
 	}
 	if (!(dev->bulk_in && dev->bulk_out)) {
 		retval = -ENODEV;
-		err("Unable to find endpoints");
+		dev_err(&intf->dev, "Unable to find endpoints\n");
 		goto err_endpoints;
 	}
 
@@ -495,7 +503,7 @@
 
 	retval = ipheth_alloc_urbs(dev);
 	if (retval) {
-		err("error allocating urbs: %d", retval);
+		dev_err(&intf->dev, "error allocating urbs: %d\n", retval);
 		goto err_alloc_urbs;
 	}
 
@@ -506,7 +514,7 @@
 
 	retval = register_netdev(netdev);
 	if (retval) {
-		err("error registering netdev: %d", retval);
+		dev_err(&intf->dev, "error registering netdev: %d\n", retval);
 		retval = -EIO;
 		goto err_register_netdev;
 	}
@@ -546,6 +554,7 @@
 	.probe =	ipheth_probe,
 	.disconnect =	ipheth_disconnect,
 	.id_table =	ipheth_table,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(ipheth_driver);
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
index 7562649..92c49e0 100644
--- a/drivers/net/usb/kalmia.c
+++ b/drivers/net/usb/kalmia.c
@@ -372,7 +372,8 @@
 	.probe = usbnet_probe,
 	.disconnect = usbnet_disconnect,
 	.suspend = usbnet_suspend,
-	.resume = usbnet_resume
+	.resume = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(kalmia_driver);
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index df2a2cf..d8ad552 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -179,6 +179,7 @@
 	.resume =	kaweth_resume,
 	.id_table =     usb_klsi_table,
 	.supports_autosuspend =	1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 typedef __u8 eth_addr_t[6];
@@ -400,12 +401,13 @@
 
 	ret = request_firmware(&fw, fwname, &kaweth->dev->dev);
 	if (ret) {
-		err("Firmware request failed\n");
+		dev_err(&kaweth->intf->dev, "Firmware request failed\n");
 		return ret;
 	}
 
 	if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
-		err("Firmware too big: %zu", fw->size);
+		dev_err(&kaweth->intf->dev, "Firmware too big: %zu\n",
+			fw->size);
 		release_firmware(fw);
 		return -ENOSPC;
 	}
@@ -501,9 +503,10 @@
 	}
 
 	if (status)
-		err ("can't resubmit intr, %s-%s, status %d",
-				kaweth->dev->bus->bus_name,
-				kaweth->dev->devpath, status);
+		dev_err(&kaweth->intf->dev,
+			"can't resubmit intr, %s-%s, status %d\n",
+			kaweth->dev->bus->bus_name,
+			kaweth->dev->devpath, status);
 }
 
 static void int_callback(struct urb *u)
@@ -576,7 +579,8 @@
 			kaweth->suspend_lowmem_rx = 1;
 			schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
 		}
-		err("resubmitting rx_urb %d failed", result);
+		dev_err(&kaweth->intf->dev, "resubmitting rx_urb %d failed\n",
+			result);
 	} else {
 		kaweth->suspend_lowmem_rx = 0;
 	}
@@ -634,20 +638,21 @@
 	spin_unlock(&kaweth->device_lock);
 
 	if(status && status != -EREMOTEIO && count != 1) {
-		err("%s RX status: %d count: %d packet_len: %d",
-                           net->name,
-			   status,
-			   count,
-			   (int)pkt_len);
+		dev_err(&kaweth->intf->dev,
+			"%s RX status: %d count: %d packet_len: %d\n",
+			net->name, status, count, (int)pkt_len);
 		kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
                 return;
 	}
 
 	if(kaweth->net && (count > 2)) {
 		if(pkt_len > (count - 2)) {
-			err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
-			err("Packet len & 2047: %x", pkt_len & 2047);
-			err("Count 2: %x", count2);
+			dev_err(&kaweth->intf->dev,
+				"Packet length too long for USB frame (pkt_len: %x, count: %x)\n",
+				pkt_len, count);
+			dev_err(&kaweth->intf->dev, "Packet len & 2047: %x\n",
+				pkt_len & 2047);
+			dev_err(&kaweth->intf->dev, "Count 2: %x\n", count2);
 		        kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
                         return;
                 }
@@ -686,7 +691,7 @@
 
 	res = usb_autopm_get_interface(kaweth->intf);
 	if (res) {
-		err("Interface cannot be resumed.");
+		dev_err(&kaweth->intf->dev, "Interface cannot be resumed.\n");
 		return -EIO;
 	}
 	res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
@@ -907,7 +912,8 @@
 				KAWETH_CONTROL_TIMEOUT);
 
 	if(result < 0) {
-		err("Failed to set Rx mode: %d", result);
+		dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n",
+			result);
 	}
 	else {
 		dbg("Set Rx mode to %d", packet_filter_bitmap);
@@ -1045,7 +1051,8 @@
 						      "kaweth/new_code.bin",
 						      100,
 						      2)) < 0) {
-			err("Error downloading firmware (%d)", result);
+			dev_err(&intf->dev, "Error downloading firmware (%d)\n",
+				result);
 			goto err_fw;
 		}
 
@@ -1053,7 +1060,9 @@
 						      "kaweth/new_code_fix.bin",
 						      100,
 						      3)) < 0) {
-			err("Error downloading firmware fix (%d)", result);
+			dev_err(&intf->dev,
+				"Error downloading firmware fix (%d)\n",
+				result);
 			goto err_fw;
 		}
 
@@ -1061,7 +1070,9 @@
 						      "kaweth/trigger_code.bin",
 						      126,
 						      2)) < 0) {
-			err("Error downloading trigger code (%d)", result);
+			dev_err(&intf->dev,
+				"Error downloading trigger code (%d)\n",
+				result);
 			goto err_fw;
 
 		}
@@ -1070,13 +1081,14 @@
 						      "kaweth/trigger_code_fix.bin",
 						      126,
 						      3)) < 0) {
-			err("Error downloading trigger code fix (%d)", result);
+			dev_err(&intf->dev, "Error downloading trigger code fix (%d)\n", result);
 			goto err_fw;
 		}
 
 
 		if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
-			err("Error triggering firmware (%d)", result);
+			dev_err(&intf->dev, "Error triggering firmware (%d)\n",
+				result);
 			goto err_fw;
 		}
 
@@ -1091,7 +1103,7 @@
 	result = kaweth_read_configuration(kaweth);
 
 	if(result < 0) {
-		err("Error reading configuration (%d), no net device created", result);
+		dev_err(&intf->dev, "Error reading configuration (%d), no net device created\n", result);
 		goto err_free_netdev;
 	}
 
@@ -1103,7 +1115,7 @@
 	if(!memcmp(&kaweth->configuration.hw_addr,
                    &bcast_addr,
 		   sizeof(bcast_addr))) {
-		err("Firmware not functioning properly, no net device created");
+		dev_err(&intf->dev, "Firmware not functioning properly, no net device created\n");
 		goto err_free_netdev;
 	}
 
@@ -1113,7 +1125,7 @@
 	}
 
 	if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
-		err("Error setting SOFS wait");
+		dev_err(&intf->dev, "Error setting SOFS wait\n");
 		goto err_free_netdev;
 	}
 
@@ -1123,7 +1135,7 @@
                                            KAWETH_PACKET_FILTER_MULTICAST);
 
 	if(result < 0) {
-		err("Error setting receive filter");
+		dev_err(&intf->dev, "Error setting receive filter\n");
 		goto err_free_netdev;
 	}
 
@@ -1175,7 +1187,7 @@
 
 	SET_NETDEV_DEV(netdev, &intf->dev);
 	if (register_netdev(netdev) != 0) {
-		err("Error registering netdev.");
+		dev_err(&intf->dev, "Error registering netdev.\n");
 		goto err_intfdata;
 	}
 
diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c
index 45a981f..808d650 100644
--- a/drivers/net/usb/lg-vl600.c
+++ b/drivers/net/usb/lg-vl600.c
@@ -344,6 +344,7 @@
 	.disconnect	= usbnet_disconnect,
 	.suspend	= usbnet_suspend,
 	.resume		= usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(lg_vl600_driver);
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index c434b6b..add1064 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -690,6 +690,7 @@
 	.suspend = usbnet_suspend,
 	.resume = usbnet_resume,
 	.reset_resume = mcs7830_reset_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(mcs7830_driver);
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
index 83f965c..28c4d51 100644
--- a/drivers/net/usb/net1080.c
+++ b/drivers/net/usb/net1080.c
@@ -587,6 +587,7 @@
 	.disconnect =	usbnet_disconnect,
 	.suspend =	usbnet_suspend,
 	.resume =	usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(net1080_driver);
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 7523930..7023220 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1489,6 +1489,7 @@
 	.id_table = pegasus_ids,
 	.suspend = pegasus_suspend,
 	.resume = pegasus_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 static void __init parse_id(char *id)
diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c
index b2b035e..4584b9a 100644
--- a/drivers/net/usb/plusb.c
+++ b/drivers/net/usb/plusb.c
@@ -152,6 +152,7 @@
 	.disconnect =	usbnet_disconnect,
 	.suspend =	usbnet_suspend,
 	.resume =	usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(plusb_driver);
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 63cfd0b..380dbea 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -560,6 +560,7 @@
 	.resume		      =	qmi_wwan_resume,
 	.reset_resume         = qmi_wwan_resume,
 	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 static int __init qmi_wwan_init(void)
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 0d746b3..4a433583 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -638,6 +638,7 @@
 	.disconnect =	usbnet_disconnect,
 	.suspend =	usbnet_suspend,
 	.resume =	usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(rndis_driver);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index d363b31..0e2c92e 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -203,7 +203,8 @@
 	if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) {
 		if (ret == -ENODEV)
 			netif_device_detach(dev->netdev);
-		err("control request submission failed: %d", ret);
+		dev_err(&dev->udev->dev,
+			"control request submission failed: %d\n", ret);
 	} else
 		set_bit(RX_REG_SET, &dev->flags);
 
@@ -516,9 +517,9 @@
 	if (res == -ENODEV)
 		netif_device_detach(dev->netdev);
 	else if (res)
-		err ("can't resubmit intr, %s-%s/input0, status %d",
-				dev->udev->bus->bus_name,
-				dev->udev->devpath, res);
+		dev_err(&dev->udev->dev,
+			"can't resubmit intr, %s-%s/input0, status %d\n",
+			dev->udev->bus->bus_name, dev->udev->devpath, res);
 }
 
 static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
@@ -890,11 +891,11 @@
 	dev->intr_interval = 100;	/* 100ms */
 
 	if (!alloc_all_urbs(dev)) {
-		err("out of memory");
+		dev_err(&intf->dev, "out of memory\n");
 		goto out;
 	}
 	if (!rtl8150_reset(dev)) {
-		err("couldn't reset the device");
+		dev_err(&intf->dev, "couldn't reset the device\n");
 		goto out1;
 	}
 	fill_skb_pool(dev);
@@ -903,7 +904,7 @@
 	usb_set_intfdata(intf, dev);
 	SET_NETDEV_DEV(netdev, &intf->dev);
 	if (register_netdev(netdev) != 0) {
-		err("couldn't register the device");
+		dev_err(&intf->dev, "couldn't register the device\n");
 		goto out2;
 	}
 
@@ -947,7 +948,8 @@
 	.disconnect	= rtl8150_disconnect,
 	.id_table	= rtl8150_table,
 	.suspend	= rtl8150_suspend,
-	.resume		= rtl8150_resume
+	.resume		= rtl8150_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(rtl8150_driver);
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index b59cf20..3faef56 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -982,6 +982,7 @@
 	.suspend = usbnet_suspend,
 	.resume = usbnet_resume,
 	.no_dynamic_id = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(sierra_net_driver);
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index fb1a087..1c6e515 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1254,6 +1254,7 @@
 	.suspend	= usbnet_suspend,
 	.resume		= usbnet_resume,
 	.disconnect	= usbnet_disconnect,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(smsc75xx_driver);
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 94ae669..b1112e7 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1297,6 +1297,7 @@
 	.suspend	= usbnet_suspend,
 	.resume		= usbnet_resume,
 	.disconnect	= usbnet_disconnect,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(smsc95xx_driver);
diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c
index 34db195..35c9030 100644
--- a/drivers/net/usb/zaurus.c
+++ b/drivers/net/usb/zaurus.c
@@ -377,6 +377,7 @@
 	.disconnect =	usbnet_disconnect,
 	.suspend =	usbnet_suspend,
 	.resume =	usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(zaurus_driver);
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index d70ede7..d58431e9 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -203,37 +203,6 @@
 
 	  You should never need this option, say N.
 
-config PC300
-	tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
-	depends on HDLC && PCI && BROKEN
-	---help---
-	  This driver is broken because of struct tty_driver change.
-
-	  Driver for the Cyclades-PC300 synchronous communication boards.
-
-	  These boards provide synchronous serial interfaces to your
-	  Linux box (interfaces currently available are RS-232/V.35, X.21 and
-	  T1/E1). If you wish to support Multilink PPP, please select the
-	  option later and read the file README.mlppp provided by PC300
-	  package.
-
-	  To compile this as a module, choose M here: the module
-	  will be called pc300.
-
-	  If unsure, say N.
-
-config PC300_MLPPP
-	bool "Cyclades-PC300 MLPPP support"
-	depends on PC300 && PPP_MULTILINK && PPP_SYNC_TTY && HDLC_PPP
-	help
-	  Multilink PPP over the PC300 synchronous communication boards.
-
-comment "Cyclades-PC300 MLPPP support is disabled."
-	depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
-
-comment "Refer to the file README.mlppp, provided by PC300 package."
-	depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
-
 config PC300TOO
 	tristate "Cyclades PC300 RSV/X21 alternative support"
 	depends on HDLC && PCI
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 19d14bc..eac709b 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -17,10 +17,6 @@
 obj-$(CONFIG_HDLC_PPP)		+= hdlc_ppp.o
 obj-$(CONFIG_HDLC_X25)		+= hdlc_x25.o
 
-pc300-y				:= pc300_drv.o
-pc300-$(CONFIG_PC300_MLPPP)	+= pc300_tty.o
-pc300-objs			:= $(pc300-y)
-
 obj-$(CONFIG_HOSTESS_SV11)	+= z85230.o	hostess_sv11.o
 obj-$(CONFIG_SEALEVEL_4021)	+= z85230.o	sealevel.o
 obj-$(CONFIG_COSA)		+= cosa.o
@@ -35,7 +31,6 @@
 obj-$(CONFIG_CYCLADES_SYNC)	+= cycx_drv.o cyclomx.o
 obj-$(CONFIG_LAPBETHER)		+= lapbether.o
 obj-$(CONFIG_SBNI)		+= sbni.o
-obj-$(CONFIG_PC300)		+= pc300.o
 obj-$(CONFIG_N2)		+= n2.o
 obj-$(CONFIG_C101)		+= c101.o
 obj-$(CONFIG_WANXL)		+= wanxl.o
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 3df0146..efc162e 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1955,7 +1955,7 @@
 	ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
 
 	if (ret < 0) {
-		err("CMD_SCAN failed: %d", ret);
+		wiphy_err(priv->hw->wiphy, "CMD_SCAN failed: %d\n", ret);
 		goto exit;
 	}
 
@@ -2486,6 +2486,7 @@
 	.probe = at76_probe,
 	.disconnect = at76_disconnect,
 	.id_table = dev_table,
+	.disable_hub_initiated_lpm = 1,
 };
 
 static int __init at76_mod_init(void)
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index dfbbe9e..3740c3d 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -1191,6 +1191,7 @@
 	.disconnect = ath6kl_usb_remove,
 	.id_table = ath6kl_usb_ids,
 	.supports_autosuspend = true,
+	.disable_hub_initiated_lpm = 1,
 };
 
 static int ath6kl_usb_init(void)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index f67cd95..aa327ad 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -1358,6 +1358,7 @@
 #endif
 	.id_table = ath9k_hif_usb_ids,
 	.soft_unbind = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 int ath9k_hif_usb_init(void)
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index 89821e4..888152c 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -1159,6 +1159,7 @@
 	.resume = carl9170_usb_resume,
 	.reset_resume = carl9170_usb_resume,
 #endif /* CONFIG_PM */
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(carl9170_driver);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 1d67ecf..c5a34ff 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -1596,7 +1596,8 @@
 	.id_table = brcmf_usb_devid_table,
 	.suspend = brcmf_usb_suspend,
 	.resume = brcmf_usb_resume,
-	.supports_autosuspend = 1
+	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 void brcmf_usb_exit(void)
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 75403e6..cd3b0d4 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -1011,6 +1011,7 @@
 	.suspend = if_usb_suspend,
 	.resume = if_usb_resume,
 	.reset_resume = if_usb_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(if_usb_driver);
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index 7ced130..19a5a92 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -920,6 +920,7 @@
 	.id_table = if_usb_table,
 	.suspend = if_usb_suspend,
 	.resume = if_usb_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(if_usb_driver);
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index f634d45..7f53cea2 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -1752,6 +1752,7 @@
 	.probe = ezusb_probe,
 	.disconnect = ezusb_disconnect,
 	.id_table = ezusb_table,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(orinoco_driver);
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index e1eac83..7f207b6 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -1140,6 +1140,7 @@
 	.reset_resume = p54u_resume,
 #endif /* CONFIG_PM */
 	.soft_unbind = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(p54u_driver);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index f11953b..2e9e6af 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -3751,6 +3751,7 @@
 	.disconnect =	usbnet_disconnect,
 	.suspend =	usbnet_suspend,
 	.resume =	usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(rndis_wlan_driver);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index c88fd3e..669aecd 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1980,6 +1980,7 @@
 	.disconnect	= rt2x00usb_disconnect,
 	.suspend	= rt2x00usb_suspend,
 	.resume		= rt2x00usb_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(rt2500usb_driver);
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 5601302..bf78317 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1302,6 +1302,7 @@
 	.disconnect	= rt2x00usb_disconnect,
 	.suspend	= rt2x00usb_suspend,
 	.resume		= rt2x00usb_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(rt2800usb_driver);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 1551366..77ccbbc 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2527,6 +2527,7 @@
 	.disconnect	= rt2x00usb_disconnect,
 	.suspend	= rt2x00usb_suspend,
 	.resume		= rt2x00usb_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(rt73usb_driver);
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index d811496..4fb1ca1 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -1663,6 +1663,7 @@
 	.id_table	= rtl8187_table,
 	.probe		= rtl8187_probe,
 	.disconnect	= __devexit_p(rtl8187_disconnect),
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(rtl8187_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 7737fb0..d228358 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -373,6 +373,7 @@
 #ifdef CONFIG_AUTOSUSPEND
 	.supports_autosuspend = 1,
 #endif
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(rtl8192cu_driver);
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index a66b93b..48273dd 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -1905,6 +1905,7 @@
 	.id_table = zd1201_table,
 	.suspend = zd1201_suspend,
 	.resume = zd1201_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(zd1201_usb);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index f766b3e..af83c43 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -1542,6 +1542,7 @@
 	.disconnect	= disconnect,
 	.pre_reset	= pre_reset,
 	.post_reset	= post_reset,
+	.disable_hub_initiated_lpm = 1,
 };
 
 struct workqueue_struct *zd_workqueue;
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 66d96f1..7e262a6 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -1,4 +1,5 @@
 
+#include <linux/device.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index e3b76d4..5003458 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -348,7 +348,7 @@
 		BUG();
 		return -1;
 	}
-	printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n",
+	printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %pf\n",
 		pci_name(pcidev),
 		pcidev->vendor, pcidev->device,
 		__builtin_return_address(0));
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index 8bef6d6..ee78e0e 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -48,23 +48,6 @@
 	return ciaa.prb;
 }
 
-#if 0
-static unsigned char control_pc_to_amiga(unsigned char control)
-{
-	unsigned char ret = 0;
-
-	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
-		;
-	if (control & PARPORT_CONTROL_INIT) /* INITP */
-		/* reset connected to cpu reset pin */;
-	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
-		/* Not connected */;
-	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
-		/* Handled only directly by hardware */;
-	return ret;
-}
-#endif
-
 static unsigned char control_amiga_to_pc(unsigned char control)
 {
 	return PARPORT_CONTROL_SELECT |
@@ -95,25 +78,6 @@
 	return old;
 }
 
-#if 0 /* currently unused */
-static unsigned char status_pc_to_amiga(unsigned char status)
-{
-	unsigned char ret = 1;
-
-	if (status & PARPORT_STATUS_BUSY) /* Busy */
-		ret &= ~1;
-	if (status & PARPORT_STATUS_ACK) /* Ack */
-		/* handled in hardware */;
-	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
-		ret |= 2;
-	if (status & PARPORT_STATUS_SELECT) /* select */
-		ret |= 4;
-	if (status & PARPORT_STATUS_ERROR) /* error */
-		/* not connected */;
-	return ret;
-}
-#endif
-
 static unsigned char status_amiga_to_pc(unsigned char status)
 {
 	unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c
index 0b28fcc..7ad59ac 100644
--- a/drivers/parport/parport_atari.c
+++ b/drivers/parport/parport_atari.c
@@ -130,15 +130,6 @@
 static void
 parport_atari_data_reverse(struct parport *p)
 {
-#if 0 /* too dangerous, can kill sound chip */
-	unsigned long flags;
-
-	local_irq_save(flags);
-	/* Soundchip port B as input. */
-	sound_ym.rd_data_reg_sel = 7;
-	sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~0x40;
-	local_irq_restore(flags);
-#endif
 }
 
 static struct parport_operations parport_atari_ops = {
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index 1c0c642..7578d79 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -147,25 +147,6 @@
 	return old;
 }
 
-#if 0 /* currently unused */
-static unsigned char status_pc_to_mfc3(unsigned char status)
-{
-	unsigned char ret = 1;
-
-	if (status & PARPORT_STATUS_BUSY) /* Busy */
-		ret &= ~1;
-	if (status & PARPORT_STATUS_ACK) /* Ack */
-		ret |= 8;
-	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
-		ret |= 2;
-	if (status & PARPORT_STATUS_SELECT) /* select */
-		ret |= 4;
-	if (status & PARPORT_STATUS_ERROR) /* error */
-		ret |= 16;
-	return ret;
-}
-#endif
-
 static unsigned char status_mfc3_to_pc(unsigned char status)
 {
 	unsigned char ret = PARPORT_STATUS_BUSY;
@@ -184,14 +165,6 @@
 	return ret;
 }
 
-#if 0 /* currently unused */
-static void mfc3_write_status( struct parport *p, unsigned char status)
-{
-DPRINTK(KERN_DEBUG "write_status %02x\n",status);
-	pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
-}
-#endif
-
 static unsigned char mfc3_read_status(struct parport *p)
 {
 	unsigned char status;
@@ -201,14 +174,6 @@
 	return status;
 }
 
-#if 0 /* currently unused */
-static void mfc3_change_mode( struct parport *p, int m)
-{
-	/* XXX: This port only has one mode, and I am
-	not sure about the corresponding PC-style mode*/
-}
-#endif
-
 static int use_cnt = 0;
 
 static irqreturn_t mfc3_interrupt(int irq, void *dev_id)
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 0cb64f5..5abffe5 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -197,54 +197,6 @@
 	ECR_WRITE(p, oecr);
 	return 0;
 }
-
-#ifdef CONFIG_PARPORT_1284
-/* Find FIFO lossage; FIFO is reset */
-#if 0
-static int get_fifo_residue(struct parport *p)
-{
-	int residue;
-	int cnfga;
-	const struct parport_pc_private *priv = p->physport->private_data;
-
-	/* Adjust for the contents of the FIFO. */
-	for (residue = priv->fifo_depth; ; residue--) {
-		if (inb(ECONTROL(p)) & 0x2)
-				/* Full up. */
-			break;
-
-		outb(0, FIFO(p));
-	}
-
-	printk(KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
-		residue);
-
-	/* Reset the FIFO. */
-	frob_set_mode(p, ECR_PS2);
-
-	/* Now change to config mode and clean up. FIXME */
-	frob_set_mode(p, ECR_CNF);
-	cnfga = inb(CONFIGA(p));
-	printk(KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
-
-	if (!(cnfga & (1<<2))) {
-		printk(KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
-		residue++;
-	}
-
-	/* Don't care about partial PWords until support is added for
-	 * PWord != 1 byte. */
-
-	/* Back to PS2 mode. */
-	frob_set_mode(p, ECR_PS2);
-
-	DPRINTK(KERN_DEBUG
-	     "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n",
-							inb(ECONTROL(p)));
-	return residue;
-}
-#endif  /*  0 */
-#endif /* IEEE 1284 support */
 #endif /* FIFO support */
 
 /*
@@ -940,234 +892,6 @@
 
 	return written;
 }
-
-#if 0
-static size_t parport_pc_ecp_read_block_pio(struct parport *port,
-					     void *buf, size_t length,
-					     int flags)
-{
-	size_t left = length;
-	size_t fifofull;
-	int r;
-	const int fifo = FIFO(port);
-	const struct parport_pc_private *priv = port->physport->private_data;
-	const int fifo_depth = priv->fifo_depth;
-	char *bufp = buf;
-
-	port = port->physport;
-	DPRINTK(KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
-	dump_parport_state("enter fcn", port);
-
-	/* Special case: a timeout of zero means we cannot call schedule().
-	 * Also if O_NONBLOCK is set then use the default implementation. */
-	if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
-		return parport_ieee1284_ecp_read_data(port, buf,
-						       length, flags);
-
-	if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) {
-		/* If the peripheral is allowed to send RLE compressed
-		 * data, it is possible for a byte to expand to 128
-		 * bytes in the FIFO. */
-		fifofull = 128;
-	} else {
-		fifofull = fifo_depth;
-	}
-
-	/* If the caller wants less than a full FIFO's worth of data,
-	 * go through software emulation.  Otherwise we may have to throw
-	 * away data. */
-	if (length < fifofull)
-		return parport_ieee1284_ecp_read_data(port, buf,
-						       length, flags);
-
-	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
-		/* change to reverse-idle phase (must be in forward-idle) */
-
-		/* Event 38: Set nAutoFd low (also make sure nStrobe is high) */
-		parport_frob_control(port,
-				      PARPORT_CONTROL_AUTOFD
-				      | PARPORT_CONTROL_STROBE,
-				      PARPORT_CONTROL_AUTOFD);
-		parport_pc_data_reverse(port); /* Must be in PS2 mode */
-		udelay(5);
-		/* Event 39: Set nInit low to initiate bus reversal */
-		parport_frob_control(port,
-				      PARPORT_CONTROL_INIT,
-				      0);
-		/* Event 40: Wait for  nAckReverse (PError) to go low */
-		r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0);
-		if (r) {
-			printk(KERN_DEBUG "%s: PE timeout Event 40 (%d) "
-				"in ecp_read_block_pio\n", port->name, r);
-			return 0;
-		}
-	}
-
-	/* Set up ECP FIFO mode.*/
-/*	parport_pc_frob_control(port,
-				 PARPORT_CONTROL_STROBE |
-				 PARPORT_CONTROL_AUTOFD,
-				 PARPORT_CONTROL_AUTOFD); */
-	r = change_mode(port, ECR_ECP); /* ECP FIFO */
-	if (r)
-		printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n",
-								port->name);
-
-	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
-
-	/* the first byte must be collected manually */
-	dump_parport_state("pre 43", port);
-	/* Event 43: Wait for nAck to go low */
-	r = parport_wait_peripheral(port, PARPORT_STATUS_ACK, 0);
-	if (r) {
-		/* timed out while reading -- no data */
-		printk(KERN_DEBUG "PIO read timed out (initial byte)\n");
-		goto out_no_data;
-	}
-	/* read byte */
-	*bufp++ = inb(DATA(port));
-	left--;
-	dump_parport_state("43-44", port);
-	/* Event 44: nAutoFd (HostAck) goes high to acknowledge */
-	parport_pc_frob_control(port,
-				 PARPORT_CONTROL_AUTOFD,
-				 0);
-	dump_parport_state("pre 45", port);
-	/* Event 45: Wait for nAck to go high */
-	/* r = parport_wait_peripheral(port, PARPORT_STATUS_ACK,
-						PARPORT_STATUS_ACK); */
-	dump_parport_state("post 45", port);
-	r = 0;
-	if (r) {
-		/* timed out while waiting for peripheral to respond to ack */
-		printk(KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n");
-
-		/* keep hold of the byte we've got already */
-		goto out_no_data;
-	}
-	/* Event 46: nAutoFd (HostAck) goes low to accept more data */
-	parport_pc_frob_control(port,
-				 PARPORT_CONTROL_AUTOFD,
-				 PARPORT_CONTROL_AUTOFD);
-
-
-	dump_parport_state("rev idle", port);
-	/* Do the transfer. */
-	while (left > fifofull) {
-		int ret;
-		unsigned long expire = jiffies + port->cad->timeout;
-		unsigned char ecrval = inb(ECONTROL(port));
-
-		if (need_resched() && time_before(jiffies, expire))
-			/* Can't yield the port. */
-			schedule();
-
-		/* At this point, the FIFO may already be full. In
-		 * that case ECP is already holding back the
-		 * peripheral (assuming proper design) with a delayed
-		 * handshake.  Work fast to avoid a peripheral
-		 * timeout.  */
-
-		if (ecrval & 0x01) {
-			/* FIFO is empty. Wait for interrupt. */
-			dump_parport_state("FIFO empty", port);
-
-			/* Anyone else waiting for the port? */
-			if (port->waithead) {
-				printk(KERN_DEBUG "Somebody wants the port\n");
-				break;
-			}
-
-			/* Clear serviceIntr */
-			ECR_WRITE(port, ecrval & ~(1<<2));
-false_alarm:
-			dump_parport_state("waiting", port);
-			ret = parport_wait_event(port, HZ);
-			DPRINTK(KERN_DEBUG "parport_wait_event returned %d\n",
-									ret);
-			if (ret < 0)
-				break;
-			ret = 0;
-			if (!time_before(jiffies, expire)) {
-				/* Timed out. */
-				dump_parport_state("timeout", port);
-				printk(KERN_DEBUG "PIO read timed out\n");
-				break;
-			}
-			ecrval = inb(ECONTROL(port));
-			if (!(ecrval & (1<<2))) {
-				if (need_resched() &&
-				    time_before(jiffies, expire)) {
-					schedule();
-				}
-				goto false_alarm;
-			}
-
-			/* Depending on how the FIFO threshold was
-			 * set, how long interrupt service took, and
-			 * how fast the peripheral is, we might be
-			 * lucky and have a just filled FIFO. */
-			continue;
-		}
-
-		if (ecrval & 0x02) {
-			/* FIFO is full. */
-			dump_parport_state("FIFO full", port);
-			insb(fifo, bufp, fifo_depth);
-			bufp += fifo_depth;
-			left -= fifo_depth;
-			continue;
-		}
-
-		DPRINTK(KERN_DEBUG
-		  "*** ecp_read_block_pio: reading one byte from the FIFO\n");
-
-		/* FIFO not filled.  We will cycle this loop for a while
-		 * and either the peripheral will fill it faster,
-		 * tripping a fast empty with insb, or we empty it. */
-		*bufp++ = inb(fifo);
-		left--;
-	}
-
-	/* scoop up anything left in the FIFO */
-	while (left && !(inb(ECONTROL(port) & 0x01))) {
-		*bufp++ = inb(fifo);
-		left--;
-	}
-
-	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
-	dump_parport_state("rev idle2", port);
-
-out_no_data:
-
-	/* Go to forward idle mode to shut the peripheral up (event 47). */
-	parport_frob_control(port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
-
-	/* event 49: PError goes high */
-	r = parport_wait_peripheral(port,
-				     PARPORT_STATUS_PAPEROUT,
-				     PARPORT_STATUS_PAPEROUT);
-	if (r) {
-		printk(KERN_DEBUG
-			"%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n",
-			port->name, r);
-	}
-
-	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
-	/* Finish up. */
-	{
-		int lost = get_fifo_residue(port);
-		if (lost)
-			/* Shouldn't happen with compliant peripherals. */
-			printk(KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n",
-				port->name, lost);
-	}
-
-	dump_parport_state("fwd idle", port);
-	return length - left;
-}
-#endif  /*  0  */
 #endif /* IEEE 1284 support */
 #endif /* Allowed to use FIFO/DMA */
 
@@ -2351,7 +2075,7 @@
 
 	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
 	if (p->base_hi && priv->ecr)
-		printk(" (0x%lx)", p->base_hi);
+		printk(KERN_CONT " (0x%lx)", p->base_hi);
 	if (p->irq == PARPORT_IRQ_AUTO) {
 		p->irq = PARPORT_IRQ_NONE;
 		parport_irq_probe(p);
@@ -2362,7 +2086,7 @@
 		p->irq = PARPORT_IRQ_NONE;
 	}
 	if (p->irq != PARPORT_IRQ_NONE) {
-		printk(", irq %d", p->irq);
+		printk(KERN_CONT ", irq %d", p->irq);
 		priv->ctr_writable |= 0x10;
 
 		if (p->dma == PARPORT_DMA_AUTO) {
@@ -2386,21 +2110,21 @@
 		/* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */
 #endif /* IEEE 1284 support */
 		if (p->dma != PARPORT_DMA_NONE) {
-			printk(", dma %d", p->dma);
+			printk(KERN_CONT ", dma %d", p->dma);
 			p->modes |= PARPORT_MODE_DMA;
 		} else
-			printk(", using FIFO");
+			printk(KERN_CONT ", using FIFO");
 	} else
 		/* We can't use the DMA channel after all. */
 		p->dma = PARPORT_DMA_NONE;
 #endif /* Allowed to use FIFO/DMA */
 
-	printk(" [");
+	printk(KERN_CONT " [");
 
 #define printmode(x) \
 	{\
 		if (p->modes & PARPORT_MODE_##x) {\
-			printk("%s%s", f ? "," : "", #x);\
+			printk(KERN_CONT "%s%s", f ? "," : "", #x);\
 			f++;\
 		} \
 	}
@@ -2416,9 +2140,9 @@
 	}
 #undef printmode
 #ifndef CONFIG_PARPORT_1284
-	printk("(,...)");
+	printk(KERN_CONT "(,...)");
 #endif /* CONFIG_PARPORT_1284 */
-	printk("]\n");
+	printk(KERN_CONT "]\n");
 	if (probedirq != PARPORT_IRQ_NONE)
 		printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq);
 
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 9390a53..983a2d2 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -82,27 +82,6 @@
 	return sbus_readb(&regs->p_dr);
 }
 
-#if 0
-static void control_pc_to_sunbpp(struct parport *p, unsigned char status)
-{
-	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
-	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
-	unsigned char value_or = sbus_readb(&regs->p_or);
-
-	if (status & PARPORT_CONTROL_STROBE) 
-		value_tcr |= P_TCR_DS;
-	if (status & PARPORT_CONTROL_AUTOFD) 
-		value_or |= P_OR_AFXN;
-	if (status & PARPORT_CONTROL_INIT) 
-		value_or |= P_OR_INIT;
-	if (status & PARPORT_CONTROL_SELECT) 
-		value_or |= P_OR_SLCT_IN;
-
-	sbus_writeb(value_or, &regs->p_or);
-	sbus_writeb(value_tcr, &regs->p_tcr);
-}
-#endif
-
 static unsigned char status_sunbpp_to_pc(struct parport *p)
 {
 	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index bba3ab2..8fd255f 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -217,7 +217,7 @@
 		    || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
 		    || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
 		    || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
-		    || MACH_COLIBRI320)
+		    || MACH_COLIBRI320 || MACH_H4700)
 	select PCMCIA_SA1111 if ARCH_LUBBOCK && SA1111
 	select PCMCIA_SOC_COMMON
 	help
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 47525de..7745b51 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -69,6 +69,7 @@
 pxa2xx-obj-$(CONFIG_MACH_BALLOON3)		+= pxa2xx_balloon3.o
 pxa2xx-obj-$(CONFIG_MACH_COLIBRI)		+= pxa2xx_colibri.o
 pxa2xx-obj-$(CONFIG_MACH_COLIBRI320)		+= pxa2xx_colibri.o
+pxa2xx-obj-$(CONFIG_MACH_H4700)			+= pxa2xx_hx4700.o
 
 obj-$(CONFIG_PCMCIA_PXA2XX)			+= pxa2xx_base.o $(pxa2xx-obj-y)
 
diff --git a/drivers/pcmcia/pxa2xx_hx4700.c b/drivers/pcmcia/pxa2xx_hx4700.c
new file mode 100644
index 0000000..7dfef3e
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_hx4700.c
@@ -0,0 +1,121 @@
+/*
+ *  Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.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/platform_device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+
+#include <asm/mach-types.h>
+#include <mach/hx4700.h>
+
+#include "soc_common.h"
+
+static struct gpio gpios[] = {
+	{ GPIO114_HX4700_CF_RESET,    GPIOF_OUT_INIT_LOW,   "CF reset"        },
+	{ EGPIO4_CF_3V3_ON,           GPIOF_OUT_INIT_LOW,   "CF 3.3V enable"  },
+};
+
+static int hx4700_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	ret = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+	if (ret)
+		goto out;
+
+	/*
+	 * IRQ type must be set before soc_pcmcia_hw_init() calls request_irq().
+	 * The asic3 default IRQ type is level trigger low level detect, exactly
+	 * the the signal present on GPIOD4_CF_nCD when a CF card is inserted.
+	 * If the IRQ type is not changed, the asic3 interrupt handler will loop
+	 * repeatedly because it is unable to clear the level trigger interrupt.
+	 */
+	irq_set_irq_type(gpio_to_irq(GPIOD4_CF_nCD), IRQ_TYPE_EDGE_BOTH);
+
+	skt->stat[SOC_STAT_CD].gpio = GPIOD4_CF_nCD;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
+	skt->stat[SOC_STAT_RDY].gpio = GPIO60_HX4700_CF_RNB;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
+
+out:
+	return ret;
+}
+
+static void hx4700_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free_array(gpios, ARRAY_SIZE(gpios));
+}
+
+static void hx4700_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+	struct pcmcia_state *state)
+{
+	state->vs_3v = 1;
+	state->vs_Xv = 0;
+}
+
+static int hx4700_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+	const socket_state_t *state)
+{
+	switch (state->Vcc) {
+	case 0:
+		gpio_set_value(EGPIO4_CF_3V3_ON, 0);
+		break;
+	case 33:
+		gpio_set_value(EGPIO4_CF_3V3_ON, 1);
+		break;
+	default:
+		printk(KERN_ERR "pcmcia: Unsupported Vcc: %d\n", state->Vcc);
+		return -EINVAL;
+	}
+
+	gpio_set_value(GPIO114_HX4700_CF_RESET, (state->flags & SS_RESET) != 0);
+
+	return 0;
+}
+
+static struct pcmcia_low_level hx4700_pcmcia_ops = {
+	.owner          = THIS_MODULE,
+	.nr             = 1,
+	.hw_init        = hx4700_pcmcia_hw_init,
+	.hw_shutdown    = hx4700_pcmcia_hw_shutdown,
+	.socket_state   = hx4700_pcmcia_socket_state,
+	.configure_socket = hx4700_pcmcia_configure_socket,
+};
+
+static struct platform_device *hx4700_pcmcia_device;
+
+static int __init hx4700_pcmcia_init(void)
+{
+	struct platform_device *pdev;
+
+	if (!machine_is_h4700())
+		return -ENODEV;
+
+	pdev = platform_device_register_data(NULL, "pxa2xx-pcmcia", -1,
+		&hx4700_pcmcia_ops, sizeof(hx4700_pcmcia_ops));
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	hx4700_pcmcia_device = pdev;
+
+	return 0;
+}
+
+static void __exit hx4700_pcmcia_exit(void)
+{
+	platform_device_unregister(hx4700_pcmcia_device);
+}
+
+module_init(hx4700_pcmcia_init);
+module_exit(hx4700_pcmcia_exit);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("HP iPAQ hx4700 PCMCIA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 91c1f64..c6e6ae0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -80,6 +80,16 @@
 	select PINCONF
 	select PINCTRL_MXS
 
+config PINCTRL_NOMADIK
+	bool "Nomadik pin controller driver"
+	depends on ARCH_U8500 || ARCH_NOMADIK
+	select PINMUX
+	select PINCONF
+
+config PINCTRL_DB8500
+	bool "DB8500 pin controller driver"
+	depends on PINCTRL_NOMADIK && ARCH_U8500
+
 config PINCTRL_PXA168
 	bool "PXA168 pin controller driver"
 	depends on ARCH_MMP
@@ -127,6 +137,8 @@
 	  COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
 	  ports of 8 GPIO pins each.
 
+source "drivers/pinctrl/spear/Kconfig"
+
 endmenu
 
 endif
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 515e32f..8c07437 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -18,6 +18,8 @@
 obj-$(CONFIG_PINCTRL_MXS)	+= pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)	+= pinctrl-imx23.o
 obj-$(CONFIG_PINCTRL_IMX28)	+= pinctrl-imx28.o
+obj-$(CONFIG_PINCTRL_NOMADIK)	+= pinctrl-nomadik.o
+obj-$(CONFIG_PINCTRL_DB8500)	+= pinctrl-nomadik-db8500.o
 obj-$(CONFIG_PINCTRL_PXA168)	+= pinctrl-pxa168.o
 obj-$(CONFIG_PINCTRL_PXA910)	+= pinctrl-pxa910.o
 obj-$(CONFIG_PINCTRL_SIRF)	+= pinctrl-sirf.o
@@ -26,3 +28,5 @@
 obj-$(CONFIG_PINCTRL_TEGRA30)	+= pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_U300)	+= pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)	+= pinctrl-coh901.o
+
+obj-$(CONFIG_PLAT_SPEAR)	+= spear/
diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c
new file mode 100644
index 0000000..8b20222
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c
@@ -0,0 +1,857 @@
+#include <linux/kernel.h>
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-nomadik.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define _GPIO(offset)		(offset)
+
+#define DB8500_PIN_AJ5		_GPIO(0)
+#define DB8500_PIN_AJ3		_GPIO(1)
+#define DB8500_PIN_AH4		_GPIO(2)
+#define DB8500_PIN_AH3		_GPIO(3)
+#define DB8500_PIN_AH6		_GPIO(4)
+#define DB8500_PIN_AG6		_GPIO(5)
+#define DB8500_PIN_AF6		_GPIO(6)
+#define DB8500_PIN_AG5		_GPIO(7)
+#define DB8500_PIN_AD5		_GPIO(8)
+#define DB8500_PIN_AE4		_GPIO(9)
+#define DB8500_PIN_AF5		_GPIO(10)
+#define DB8500_PIN_AG4		_GPIO(11)
+#define DB8500_PIN_AC4		_GPIO(12)
+#define DB8500_PIN_AF3		_GPIO(13)
+#define DB8500_PIN_AE3		_GPIO(14)
+#define DB8500_PIN_AC3		_GPIO(15)
+#define DB8500_PIN_AD3		_GPIO(16)
+#define DB8500_PIN_AD4		_GPIO(17)
+#define DB8500_PIN_AC2		_GPIO(18)
+#define DB8500_PIN_AC1		_GPIO(19)
+#define DB8500_PIN_AB4		_GPIO(20)
+#define DB8500_PIN_AB3		_GPIO(21)
+#define DB8500_PIN_AA3		_GPIO(22)
+#define DB8500_PIN_AA4		_GPIO(23)
+#define DB8500_PIN_AB2		_GPIO(24)
+#define DB8500_PIN_Y4		_GPIO(25)
+#define DB8500_PIN_Y2		_GPIO(26)
+#define DB8500_PIN_AA2		_GPIO(27)
+#define DB8500_PIN_AA1		_GPIO(28)
+#define DB8500_PIN_W2		_GPIO(29)
+#define DB8500_PIN_W3		_GPIO(30)
+#define DB8500_PIN_V3		_GPIO(31)
+#define DB8500_PIN_V2		_GPIO(32)
+#define DB8500_PIN_AF2		_GPIO(33)
+#define DB8500_PIN_AE1		_GPIO(34)
+#define DB8500_PIN_AE2		_GPIO(35)
+#define DB8500_PIN_AG2		_GPIO(36)
+/* Hole */
+#define DB8500_PIN_F3		_GPIO(64)
+#define DB8500_PIN_F1		_GPIO(65)
+#define DB8500_PIN_G3		_GPIO(66)
+#define DB8500_PIN_G2		_GPIO(67)
+#define DB8500_PIN_E1		_GPIO(68)
+#define DB8500_PIN_E2		_GPIO(69)
+#define DB8500_PIN_G5		_GPIO(70)
+#define DB8500_PIN_G4		_GPIO(71)
+#define DB8500_PIN_H4		_GPIO(72)
+#define DB8500_PIN_H3		_GPIO(73)
+#define DB8500_PIN_J3		_GPIO(74)
+#define DB8500_PIN_H2		_GPIO(75)
+#define DB8500_PIN_J2		_GPIO(76)
+#define DB8500_PIN_H1		_GPIO(77)
+#define DB8500_PIN_F4		_GPIO(78)
+#define DB8500_PIN_E3		_GPIO(79)
+#define DB8500_PIN_E4		_GPIO(80)
+#define DB8500_PIN_D2		_GPIO(81)
+#define DB8500_PIN_C1		_GPIO(82)
+#define DB8500_PIN_D3		_GPIO(83)
+#define DB8500_PIN_C2		_GPIO(84)
+#define DB8500_PIN_D5		_GPIO(85)
+#define DB8500_PIN_C6		_GPIO(86)
+#define DB8500_PIN_B3		_GPIO(87)
+#define DB8500_PIN_C4		_GPIO(88)
+#define DB8500_PIN_E6		_GPIO(89)
+#define DB8500_PIN_A3		_GPIO(90)
+#define DB8500_PIN_B6		_GPIO(91)
+#define DB8500_PIN_D6		_GPIO(92)
+#define DB8500_PIN_B7		_GPIO(93)
+#define DB8500_PIN_D7		_GPIO(94)
+#define DB8500_PIN_E8		_GPIO(95)
+#define DB8500_PIN_D8		_GPIO(96)
+#define DB8500_PIN_D9		_GPIO(97)
+/* Hole */
+#define DB8500_PIN_A5		_GPIO(128)
+#define DB8500_PIN_B4		_GPIO(129)
+#define DB8500_PIN_C8		_GPIO(130)
+#define DB8500_PIN_A12		_GPIO(131)
+#define DB8500_PIN_C10		_GPIO(132)
+#define DB8500_PIN_B10		_GPIO(133)
+#define DB8500_PIN_B9		_GPIO(134)
+#define DB8500_PIN_A9		_GPIO(135)
+#define DB8500_PIN_C7		_GPIO(136)
+#define DB8500_PIN_A7		_GPIO(137)
+#define DB8500_PIN_C5		_GPIO(138)
+#define DB8500_PIN_C9		_GPIO(139)
+#define DB8500_PIN_B11		_GPIO(140)
+#define DB8500_PIN_C12		_GPIO(141)
+#define DB8500_PIN_C11		_GPIO(142)
+#define DB8500_PIN_D12		_GPIO(143)
+#define DB8500_PIN_B13		_GPIO(144)
+#define DB8500_PIN_C13		_GPIO(145)
+#define DB8500_PIN_D13		_GPIO(146)
+#define DB8500_PIN_C15		_GPIO(147)
+#define DB8500_PIN_B16		_GPIO(148)
+#define DB8500_PIN_B14		_GPIO(149)
+#define DB8500_PIN_C14		_GPIO(150)
+#define DB8500_PIN_D17		_GPIO(151)
+#define DB8500_PIN_D16		_GPIO(152)
+#define DB8500_PIN_B17		_GPIO(153)
+#define DB8500_PIN_C16		_GPIO(154)
+#define DB8500_PIN_C19		_GPIO(155)
+#define DB8500_PIN_C17		_GPIO(156)
+#define DB8500_PIN_A18		_GPIO(157)
+#define DB8500_PIN_C18		_GPIO(158)
+#define DB8500_PIN_B19		_GPIO(159)
+#define DB8500_PIN_B20		_GPIO(160)
+#define DB8500_PIN_D21		_GPIO(161)
+#define DB8500_PIN_D20		_GPIO(162)
+#define DB8500_PIN_C20		_GPIO(163)
+#define DB8500_PIN_B21		_GPIO(164)
+#define DB8500_PIN_C21		_GPIO(165)
+#define DB8500_PIN_A22		_GPIO(166)
+#define DB8500_PIN_B24		_GPIO(167)
+#define DB8500_PIN_C22		_GPIO(168)
+#define DB8500_PIN_D22		_GPIO(169)
+#define DB8500_PIN_C23		_GPIO(170)
+#define DB8500_PIN_D23		_GPIO(171)
+/* Hole */
+#define DB8500_PIN_AJ27		_GPIO(192)
+#define DB8500_PIN_AH27		_GPIO(193)
+#define DB8500_PIN_AF27		_GPIO(194)
+#define DB8500_PIN_AG28		_GPIO(195)
+#define DB8500_PIN_AG26		_GPIO(196)
+#define DB8500_PIN_AH24		_GPIO(197)
+#define DB8500_PIN_AG25		_GPIO(198)
+#define DB8500_PIN_AH23		_GPIO(199)
+#define DB8500_PIN_AH26		_GPIO(200)
+#define DB8500_PIN_AF24		_GPIO(201)
+#define DB8500_PIN_AF25		_GPIO(202)
+#define DB8500_PIN_AE23		_GPIO(203)
+#define DB8500_PIN_AF23		_GPIO(204)
+#define DB8500_PIN_AG23		_GPIO(205)
+#define DB8500_PIN_AG24		_GPIO(206)
+#define DB8500_PIN_AJ23		_GPIO(207)
+#define DB8500_PIN_AH16		_GPIO(208)
+#define DB8500_PIN_AG15		_GPIO(209)
+#define DB8500_PIN_AJ15		_GPIO(210)
+#define DB8500_PIN_AG14		_GPIO(211)
+#define DB8500_PIN_AF13		_GPIO(212)
+#define DB8500_PIN_AG13		_GPIO(213)
+#define DB8500_PIN_AH15		_GPIO(214)
+#define DB8500_PIN_AH13		_GPIO(215)
+#define DB8500_PIN_AG12		_GPIO(216)
+#define DB8500_PIN_AH12		_GPIO(217)
+#define DB8500_PIN_AH11		_GPIO(218)
+#define DB8500_PIN_AG10		_GPIO(219)
+#define DB8500_PIN_AH10		_GPIO(220)
+#define DB8500_PIN_AJ11		_GPIO(221)
+#define DB8500_PIN_AJ9		_GPIO(222)
+#define DB8500_PIN_AH9		_GPIO(223)
+#define DB8500_PIN_AG9		_GPIO(224)
+#define DB8500_PIN_AG8		_GPIO(225)
+#define DB8500_PIN_AF8		_GPIO(226)
+#define DB8500_PIN_AH7		_GPIO(227)
+#define DB8500_PIN_AJ6		_GPIO(228)
+#define DB8500_PIN_AG7		_GPIO(229)
+#define DB8500_PIN_AF7		_GPIO(230)
+/* Hole */
+#define DB8500_PIN_AF28		_GPIO(256)
+#define DB8500_PIN_AE29		_GPIO(257)
+#define DB8500_PIN_AD29		_GPIO(258)
+#define DB8500_PIN_AC29		_GPIO(259)
+#define DB8500_PIN_AD28		_GPIO(260)
+#define DB8500_PIN_AD26		_GPIO(261)
+#define DB8500_PIN_AE26		_GPIO(262)
+#define DB8500_PIN_AG29		_GPIO(263)
+#define DB8500_PIN_AE27		_GPIO(264)
+#define DB8500_PIN_AD27		_GPIO(265)
+#define DB8500_PIN_AC28		_GPIO(266)
+#define DB8500_PIN_AC27		_GPIO(267)
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc nmk_db8500_pins[] = {
+	PINCTRL_PIN(DB8500_PIN_AJ5, "GPIO0_AJ5"),
+	PINCTRL_PIN(DB8500_PIN_AJ3, "GPIO1_AJ3"),
+	PINCTRL_PIN(DB8500_PIN_AH4, "GPIO2_AH4"),
+	PINCTRL_PIN(DB8500_PIN_AH3, "GPIO3_AH3"),
+	PINCTRL_PIN(DB8500_PIN_AH6, "GPIO4_AH6"),
+	PINCTRL_PIN(DB8500_PIN_AG6, "GPIO5_AG6"),
+	PINCTRL_PIN(DB8500_PIN_AF6, "GPIO6_AF6"),
+	PINCTRL_PIN(DB8500_PIN_AG5, "GPIO7_AG5"),
+	PINCTRL_PIN(DB8500_PIN_AD5, "GPIO8_AD5"),
+	PINCTRL_PIN(DB8500_PIN_AE4, "GPIO9_AE4"),
+	PINCTRL_PIN(DB8500_PIN_AF5, "GPIO10_AF5"),
+	PINCTRL_PIN(DB8500_PIN_AG4, "GPIO11_AG4"),
+	PINCTRL_PIN(DB8500_PIN_AC4, "GPIO12_AC4"),
+	PINCTRL_PIN(DB8500_PIN_AF3, "GPIO13_AF3"),
+	PINCTRL_PIN(DB8500_PIN_AE3, "GPIO14_AE3"),
+	PINCTRL_PIN(DB8500_PIN_AC3, "GPIO15_AC3"),
+	PINCTRL_PIN(DB8500_PIN_AD3, "GPIO16_AD3"),
+	PINCTRL_PIN(DB8500_PIN_AD4, "GPIO17_AD4"),
+	PINCTRL_PIN(DB8500_PIN_AC2, "GPIO18_AC2"),
+	PINCTRL_PIN(DB8500_PIN_AC1, "GPIO19_AC1"),
+	PINCTRL_PIN(DB8500_PIN_AB4, "GPIO20_AB4"),
+	PINCTRL_PIN(DB8500_PIN_AB3, "GPIO21_AB3"),
+	PINCTRL_PIN(DB8500_PIN_AA3, "GPIO22_AA3"),
+	PINCTRL_PIN(DB8500_PIN_AA4, "GPIO23_AA4"),
+	PINCTRL_PIN(DB8500_PIN_AB2, "GPIO24_AB2"),
+	PINCTRL_PIN(DB8500_PIN_Y4, "GPIO25_Y4"),
+	PINCTRL_PIN(DB8500_PIN_Y2, "GPIO26_Y2"),
+	PINCTRL_PIN(DB8500_PIN_AA2, "GPIO27_AA2"),
+	PINCTRL_PIN(DB8500_PIN_AA1, "GPIO28_AA1"),
+	PINCTRL_PIN(DB8500_PIN_W2, "GPIO29_W2"),
+	PINCTRL_PIN(DB8500_PIN_W3, "GPIO30_W3"),
+	PINCTRL_PIN(DB8500_PIN_V3, "GPIO31_V3"),
+	PINCTRL_PIN(DB8500_PIN_V2, "GPIO32_V2"),
+	PINCTRL_PIN(DB8500_PIN_AF2, "GPIO33_AF2"),
+	PINCTRL_PIN(DB8500_PIN_AE1, "GPIO34_AE1"),
+	PINCTRL_PIN(DB8500_PIN_AE2, "GPIO35_AE2"),
+	PINCTRL_PIN(DB8500_PIN_AG2, "GPIO36_AG2"),
+	/* Hole */
+	PINCTRL_PIN(DB8500_PIN_F3, "GPIO64_F3"),
+	PINCTRL_PIN(DB8500_PIN_F1, "GPIO65_F1"),
+	PINCTRL_PIN(DB8500_PIN_G3, "GPIO66_G3"),
+	PINCTRL_PIN(DB8500_PIN_G2, "GPIO67_G2"),
+	PINCTRL_PIN(DB8500_PIN_E1, "GPIO68_E1"),
+	PINCTRL_PIN(DB8500_PIN_E2, "GPIO69_E2"),
+	PINCTRL_PIN(DB8500_PIN_G5, "GPIO70_G5"),
+	PINCTRL_PIN(DB8500_PIN_G4, "GPIO71_G4"),
+	PINCTRL_PIN(DB8500_PIN_H4, "GPIO72_H4"),
+	PINCTRL_PIN(DB8500_PIN_H3, "GPIO73_H3"),
+	PINCTRL_PIN(DB8500_PIN_J3, "GPIO74_J3"),
+	PINCTRL_PIN(DB8500_PIN_H2, "GPIO75_H2"),
+	PINCTRL_PIN(DB8500_PIN_J2, "GPIO76_J2"),
+	PINCTRL_PIN(DB8500_PIN_H1, "GPIO77_H1"),
+	PINCTRL_PIN(DB8500_PIN_F4, "GPIO78_F4"),
+	PINCTRL_PIN(DB8500_PIN_E3, "GPIO79_E3"),
+	PINCTRL_PIN(DB8500_PIN_E4, "GPIO80_E4"),
+	PINCTRL_PIN(DB8500_PIN_D2, "GPIO81_D2"),
+	PINCTRL_PIN(DB8500_PIN_C1, "GPIO82_C1"),
+	PINCTRL_PIN(DB8500_PIN_D3, "GPIO83_D3"),
+	PINCTRL_PIN(DB8500_PIN_C2, "GPIO84_C2"),
+	PINCTRL_PIN(DB8500_PIN_D5, "GPIO85_D5"),
+	PINCTRL_PIN(DB8500_PIN_C6, "GPIO86_C6"),
+	PINCTRL_PIN(DB8500_PIN_B3, "GPIO87_B3"),
+	PINCTRL_PIN(DB8500_PIN_C4, "GPIO88_C4"),
+	PINCTRL_PIN(DB8500_PIN_E6, "GPIO89_E6"),
+	PINCTRL_PIN(DB8500_PIN_A3, "GPIO90_A3"),
+	PINCTRL_PIN(DB8500_PIN_B6, "GPIO91_B6"),
+	PINCTRL_PIN(DB8500_PIN_D6, "GPIO92_D6"),
+	PINCTRL_PIN(DB8500_PIN_B7, "GPIO93_B7"),
+	PINCTRL_PIN(DB8500_PIN_D7, "GPIO94_D7"),
+	PINCTRL_PIN(DB8500_PIN_E8, "GPIO95_E8"),
+	PINCTRL_PIN(DB8500_PIN_D8, "GPIO96_D8"),
+	PINCTRL_PIN(DB8500_PIN_D9, "GPIO97_D9"),
+	/* Hole */
+	PINCTRL_PIN(DB8500_PIN_A5, "GPIO128_A5"),
+	PINCTRL_PIN(DB8500_PIN_B4, "GPIO129_B4"),
+	PINCTRL_PIN(DB8500_PIN_C8, "GPIO130_C8"),
+	PINCTRL_PIN(DB8500_PIN_A12, "GPIO131_A12"),
+	PINCTRL_PIN(DB8500_PIN_C10, "GPIO132_C10"),
+	PINCTRL_PIN(DB8500_PIN_B10, "GPIO133_B10"),
+	PINCTRL_PIN(DB8500_PIN_B9, "GPIO134_B9"),
+	PINCTRL_PIN(DB8500_PIN_A9, "GPIO135_A9"),
+	PINCTRL_PIN(DB8500_PIN_C7, "GPIO136_C7"),
+	PINCTRL_PIN(DB8500_PIN_A7, "GPIO137_A7"),
+	PINCTRL_PIN(DB8500_PIN_C5, "GPIO138_C5"),
+	PINCTRL_PIN(DB8500_PIN_C9, "GPIO139_C9"),
+	PINCTRL_PIN(DB8500_PIN_B11, "GPIO140_B11"),
+	PINCTRL_PIN(DB8500_PIN_C12, "GPIO141_C12"),
+	PINCTRL_PIN(DB8500_PIN_C11, "GPIO142_C11"),
+	PINCTRL_PIN(DB8500_PIN_D12, "GPIO143_D12"),
+	PINCTRL_PIN(DB8500_PIN_B13, "GPIO144_B13"),
+	PINCTRL_PIN(DB8500_PIN_C13, "GPIO145_C13"),
+	PINCTRL_PIN(DB8500_PIN_D13, "GPIO146_D13"),
+	PINCTRL_PIN(DB8500_PIN_C15, "GPIO147_C15"),
+	PINCTRL_PIN(DB8500_PIN_B16, "GPIO148_B16"),
+	PINCTRL_PIN(DB8500_PIN_B14, "GPIO149_B14"),
+	PINCTRL_PIN(DB8500_PIN_C14, "GPIO150_C14"),
+	PINCTRL_PIN(DB8500_PIN_D17, "GPIO151_D17"),
+	PINCTRL_PIN(DB8500_PIN_D16, "GPIO152_D16"),
+	PINCTRL_PIN(DB8500_PIN_B17, "GPIO153_B17"),
+	PINCTRL_PIN(DB8500_PIN_C16, "GPIO154_C16"),
+	PINCTRL_PIN(DB8500_PIN_C19, "GPIO155_C19"),
+	PINCTRL_PIN(DB8500_PIN_C17, "GPIO156_C17"),
+	PINCTRL_PIN(DB8500_PIN_A18, "GPIO157_A18"),
+	PINCTRL_PIN(DB8500_PIN_C18, "GPIO158_C18"),
+	PINCTRL_PIN(DB8500_PIN_B19, "GPIO159_B19"),
+	PINCTRL_PIN(DB8500_PIN_B20, "GPIO160_B20"),
+	PINCTRL_PIN(DB8500_PIN_D21, "GPIO161_D21"),
+	PINCTRL_PIN(DB8500_PIN_D20, "GPIO162_D20"),
+	PINCTRL_PIN(DB8500_PIN_C20, "GPIO163_C20"),
+	PINCTRL_PIN(DB8500_PIN_B21, "GPIO164_B21"),
+	PINCTRL_PIN(DB8500_PIN_C21, "GPIO165_C21"),
+	PINCTRL_PIN(DB8500_PIN_A22, "GPIO166_A22"),
+	PINCTRL_PIN(DB8500_PIN_B24, "GPIO167_B24"),
+	PINCTRL_PIN(DB8500_PIN_C22, "GPIO168_C22"),
+	PINCTRL_PIN(DB8500_PIN_D22, "GPIO169_D22"),
+	PINCTRL_PIN(DB8500_PIN_C23, "GPIO170_C23"),
+	PINCTRL_PIN(DB8500_PIN_D23, "GPIO171_D23"),
+	/* Hole */
+	PINCTRL_PIN(DB8500_PIN_AJ27, "GPIO192_AJ27"),
+	PINCTRL_PIN(DB8500_PIN_AH27, "GPIO193_AH27"),
+	PINCTRL_PIN(DB8500_PIN_AF27, "GPIO194_AF27"),
+	PINCTRL_PIN(DB8500_PIN_AG28, "GPIO195_AG28"),
+	PINCTRL_PIN(DB8500_PIN_AG26, "GPIO196_AG26"),
+	PINCTRL_PIN(DB8500_PIN_AH24, "GPIO197_AH24"),
+	PINCTRL_PIN(DB8500_PIN_AG25, "GPIO198_AG25"),
+	PINCTRL_PIN(DB8500_PIN_AH23, "GPIO199_AH23"),
+	PINCTRL_PIN(DB8500_PIN_AH26, "GPIO200_AH26"),
+	PINCTRL_PIN(DB8500_PIN_AF24, "GPIO201_AF24"),
+	PINCTRL_PIN(DB8500_PIN_AF25, "GPIO202_AF25"),
+	PINCTRL_PIN(DB8500_PIN_AE23, "GPIO203_AE23"),
+	PINCTRL_PIN(DB8500_PIN_AF23, "GPIO204_AF23"),
+	PINCTRL_PIN(DB8500_PIN_AG23, "GPIO205_AG23"),
+	PINCTRL_PIN(DB8500_PIN_AG24, "GPIO206_AG24"),
+	PINCTRL_PIN(DB8500_PIN_AJ23, "GPIO207_AJ23"),
+	PINCTRL_PIN(DB8500_PIN_AH16, "GPIO208_AH16"),
+	PINCTRL_PIN(DB8500_PIN_AG15, "GPIO209_AG15"),
+	PINCTRL_PIN(DB8500_PIN_AJ15, "GPIO210_AJ15"),
+	PINCTRL_PIN(DB8500_PIN_AG14, "GPIO211_AG14"),
+	PINCTRL_PIN(DB8500_PIN_AF13, "GPIO212_AF13"),
+	PINCTRL_PIN(DB8500_PIN_AG13, "GPIO213_AG13"),
+	PINCTRL_PIN(DB8500_PIN_AH15, "GPIO214_AH15"),
+	PINCTRL_PIN(DB8500_PIN_AH13, "GPIO215_AH13"),
+	PINCTRL_PIN(DB8500_PIN_AG12, "GPIO216_AG12"),
+	PINCTRL_PIN(DB8500_PIN_AH12, "GPIO217_AH12"),
+	PINCTRL_PIN(DB8500_PIN_AH11, "GPIO218_AH11"),
+	PINCTRL_PIN(DB8500_PIN_AG10, "GPIO219_AG10"),
+	PINCTRL_PIN(DB8500_PIN_AH10, "GPIO220_AH10"),
+	PINCTRL_PIN(DB8500_PIN_AJ11, "GPIO221_AJ11"),
+	PINCTRL_PIN(DB8500_PIN_AJ9, "GPIO222_AJ9"),
+	PINCTRL_PIN(DB8500_PIN_AH9, "GPIO223_AH9"),
+	PINCTRL_PIN(DB8500_PIN_AG9, "GPIO224_AG9"),
+	PINCTRL_PIN(DB8500_PIN_AG8, "GPIO225_AG8"),
+	PINCTRL_PIN(DB8500_PIN_AF8, "GPIO226_AF8"),
+	PINCTRL_PIN(DB8500_PIN_AH7, "GPIO227_AH7"),
+	PINCTRL_PIN(DB8500_PIN_AJ6, "GPIO228_AJ6"),
+	PINCTRL_PIN(DB8500_PIN_AG7, "GPIO229_AG7"),
+	PINCTRL_PIN(DB8500_PIN_AF7, "GPIO230_AF7"),
+	/* Hole */
+	PINCTRL_PIN(DB8500_PIN_AF28, "GPIO256_AF28"),
+	PINCTRL_PIN(DB8500_PIN_AE29, "GPIO257_AE29"),
+	PINCTRL_PIN(DB8500_PIN_AD29, "GPIO258_AD29"),
+	PINCTRL_PIN(DB8500_PIN_AC29, "GPIO259_AC29"),
+	PINCTRL_PIN(DB8500_PIN_AD28, "GPIO260_AD28"),
+	PINCTRL_PIN(DB8500_PIN_AD26, "GPIO261_AD26"),
+	PINCTRL_PIN(DB8500_PIN_AE26, "GPIO262_AE26"),
+	PINCTRL_PIN(DB8500_PIN_AG29, "GPIO263_AG29"),
+	PINCTRL_PIN(DB8500_PIN_AE27, "GPIO264_AE27"),
+	PINCTRL_PIN(DB8500_PIN_AD27, "GPIO265_AD27"),
+	PINCTRL_PIN(DB8500_PIN_AC28, "GPIO266_AC28"),
+	PINCTRL_PIN(DB8500_PIN_AC27, "GPIO267_AC27"),
+};
+
+#define DB8500_GPIO_RANGE(a, b, c) { .name = "DB8500", .id = a, .base = b, \
+			.pin_base = b, .npins = c }
+
+/*
+ * This matches the 32-pin gpio chips registered by the GPIO portion. This
+ * cannot be const since we assign the struct gpio_chip * pointer at runtime.
+ */
+static struct pinctrl_gpio_range nmk_db8500_ranges[] = {
+	DB8500_GPIO_RANGE(0, 0, 32),
+	DB8500_GPIO_RANGE(1, 32, 5),
+	DB8500_GPIO_RANGE(2, 64, 32),
+	DB8500_GPIO_RANGE(3, 96, 2),
+	DB8500_GPIO_RANGE(4, 128, 32),
+	DB8500_GPIO_RANGE(5, 160, 12),
+	DB8500_GPIO_RANGE(6, 192, 32),
+	DB8500_GPIO_RANGE(7, 224, 7),
+	DB8500_GPIO_RANGE(8, 256, 12),
+};
+
+/*
+ * Read the pin group names like this:
+ * u0_a_1    = first groups of pins for uart0 on alt function a
+ * i2c2_b_2  = second group of pins for i2c2 on alt function b
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* Altfunction A column */
+static const unsigned u0_a_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3,
+					DB8500_PIN_AH4, DB8500_PIN_AH3 };
+static const unsigned u1rxtx_a_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 };
+static const unsigned u1ctsrts_a_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 };
+/* Image processor I2C line, this is driven by image processor firmware */
+static const unsigned ipi2c_a_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 };
+static const unsigned ipi2c_a_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 };
+/* MSP0 can only be on these pins, but TXD and RXD can be flipped */
+static const unsigned msp0txrx_a_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 };
+static const unsigned msp0tfstck_a_1_pins[] = { DB8500_PIN_AF3, DB8500_PIN_AE3 };
+static const unsigned msp0rfsrck_a_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 };
+/* Basic pins of the MMC/SD card 0 interface */
+static const unsigned mc0_a_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1,
+	DB8500_PIN_AB4, DB8500_PIN_AA3, DB8500_PIN_AA4, DB8500_PIN_AB2,
+	DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+/* Often only 4 bits are used, then these are not needed (only used for MMC) */
+static const unsigned mc0_dat47_a_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3,
+	DB8500_PIN_V3, DB8500_PIN_V2};
+static const unsigned mc0dat31dir_a_1_pins[] = { DB8500_PIN_AB3 };
+/* MSP1 can only be on these pins, but TXD and RXD can be flipped */
+static const unsigned msp1txrx_a_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 };
+static const unsigned msp1_a_1_pins[] = { DB8500_PIN_AE1, DB8500_PIN_AE2 };
+/* LCD interface */
+static const unsigned lcdb_a_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
+					  DB8500_PIN_G3, DB8500_PIN_G2 };
+static const unsigned lcdvsi0_a_1_pins[] = { DB8500_PIN_E1 };
+static const unsigned lcdvsi1_a_1_pins[] = { DB8500_PIN_E2 };
+static const unsigned lcd_d0_d7_a_1_pins[] = {
+	DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3,
+	DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1 };
+/* D8 thru D11 often used as TVOUT lines */
+static const unsigned lcd_d8_d11_a_1_pins[] = { DB8500_PIN_F4,
+	DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2 };
+static const unsigned lcd_d12_d23_a_1_pins[] = {
+	DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5,
+	DB8500_PIN_C6, DB8500_PIN_B3, DB8500_PIN_C4, DB8500_PIN_E6,
+	DB8500_PIN_A3, DB8500_PIN_B6, DB8500_PIN_D6, DB8500_PIN_B7 };
+static const unsigned kp_a_1_pins[] = { DB8500_PIN_D7, DB8500_PIN_E8,
+	DB8500_PIN_D8, DB8500_PIN_D9 };
+static const unsigned kpskaskb_a_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16 };
+static const unsigned kp_a_2_pins[] = {
+	DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+	DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+	DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+	DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+/* MC2 has 8 data lines and no direction control, so only for (e)MMC */
+static const unsigned mc2_a_1_pins[] = { DB8500_PIN_A5, DB8500_PIN_B4,
+	DB8500_PIN_C8, DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10,
+	DB8500_PIN_B9, DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7,
+	DB8500_PIN_C5 };
+static const unsigned ssp1_a_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11,
+					  DB8500_PIN_C12, DB8500_PIN_C11 };
+static const unsigned ssp0_a_1_pins[] = { DB8500_PIN_D12, DB8500_PIN_B13,
+					  DB8500_PIN_C13, DB8500_PIN_D13 };
+static const unsigned i2c0_a_1_pins[] = { DB8500_PIN_C15, DB8500_PIN_B16 };
+/*
+ * Image processor GPIO pins are named "ipgpio" and have their own
+ * numberspace
+ */
+static const unsigned ipgpio0_a_1_pins[] = { DB8500_PIN_B14 };
+static const unsigned ipgpio1_a_1_pins[] = { DB8500_PIN_C14 };
+/* Three modem pins named RF_PURn, MODEM_STATE and MODEM_PWREN */
+static const unsigned modem_a_1_pins[] = { DB8500_PIN_D22, DB8500_PIN_C23,
+					   DB8500_PIN_D23 };
+/*
+ * This MSP cannot switch RX and TX, SCK in a separate group since this
+ * seems to be optional.
+ */
+static const unsigned msp2sck_a_1_pins[] = { DB8500_PIN_AJ27 };
+static const unsigned msp2_a_1_pins[] = { DB8500_PIN_AH27, DB8500_PIN_AF27,
+					  DB8500_PIN_AG28, DB8500_PIN_AG26 };
+static const unsigned mc4_a_1_pins[] = { DB8500_PIN_AH24, DB8500_PIN_AG25,
+	DB8500_PIN_AH23, DB8500_PIN_AH26, DB8500_PIN_AF24, DB8500_PIN_AF25,
+	DB8500_PIN_AE23, DB8500_PIN_AF23, DB8500_PIN_AG23, DB8500_PIN_AG24,
+	DB8500_PIN_AJ23 };
+/* MC1 has only 4 data pins, designed for SD or SDIO exclusively */
+static const unsigned mc1_a_1_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AG15,
+	DB8500_PIN_AJ15, DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13,
+	DB8500_PIN_AH15 };
+static const unsigned mc1dir_a_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
+	DB8500_PIN_AH12, DB8500_PIN_AH11 };
+static const unsigned hsir_a_1_pins[] = { DB8500_PIN_AG10, DB8500_PIN_AH10 };
+static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ11, DB8500_PIN_AJ9,
+	DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 };
+static const unsigned clkout_a_1_pins[] = { DB8500_PIN_AH7, DB8500_PIN_AJ6 };
+static const unsigned clkout_a_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
+static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29,
+	DB8500_PIN_AD29, DB8500_PIN_AC29, DB8500_PIN_AD28, DB8500_PIN_AD26,
+	DB8500_PIN_AE26, DB8500_PIN_AG29, DB8500_PIN_AE27, DB8500_PIN_AD27,
+	DB8500_PIN_AC28, DB8500_PIN_AC27 };
+
+/* Altfunction B column */
+static const unsigned trig_b_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3 };
+static const unsigned i2c4_b_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 };
+static const unsigned i2c1_b_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 };
+static const unsigned i2c2_b_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 };
+static const unsigned i2c2_b_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 };
+static const unsigned msp0txrx_b_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 };
+static const unsigned i2c1_b_2_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 };
+/* Just RX and TX for UART2 */
+static const unsigned u2rxtx_b_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1 };
+static const unsigned uartmodtx_b_1_pins[] = { DB8500_PIN_AB4 };
+static const unsigned msp0sck_b_1_pins[] = { DB8500_PIN_AB3 };
+static const unsigned uartmodrx_b_1_pins[] = { DB8500_PIN_AA3 };
+static const unsigned stmmod_b_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4,
+	DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned uartmodrx_b_2_pins[] = { DB8500_PIN_AB2 };
+static const unsigned spi3_b_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3,
+					  DB8500_PIN_V3, DB8500_PIN_V2 };
+static const unsigned msp1txrx_b_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 };
+static const unsigned kp_b_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
+	DB8500_PIN_G3, DB8500_PIN_G2, DB8500_PIN_E1, DB8500_PIN_E2,
+	DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3,
+	DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1,
+	DB8500_PIN_F4, DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2,
+	DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5 };
+static const unsigned sm_b_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
+	DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
+	DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8,
+	DB8500_PIN_D9, DB8500_PIN_A5, DB8500_PIN_B4, DB8500_PIN_C8,
+	DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10, DB8500_PIN_B9,
+	DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7, DB8500_PIN_C5,
+	DB8500_PIN_C9, DB8500_PIN_B14 };
+/* This chip select pin can be "ps0" in alt B so have it separately */
+static const unsigned smcs0_b_1_pins[] = { DB8500_PIN_E8 };
+static const unsigned ipgpio7_b_1_pins[] = { DB8500_PIN_B11 };
+static const unsigned ipgpio2_b_1_pins[] = { DB8500_PIN_C12 };
+static const unsigned ipgpio3_b_1_pins[] = { DB8500_PIN_C11 };
+static const unsigned lcdaclk_b_1_pins[] = { DB8500_PIN_C14 };
+static const unsigned lcda_b_1_pins[] = { DB8500_PIN_D22,
+	DB8500_PIN_C23, DB8500_PIN_D23 };
+static const unsigned lcd_b_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
+	DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+	DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+	DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+	DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+static const unsigned ddrtrig_b_1_pins[] = { DB8500_PIN_AJ27 };
+static const unsigned pwl_b_1_pins[] = { DB8500_PIN_AF25 };
+static const unsigned spi1_b_1_pins[] = { DB8500_PIN_AG15, DB8500_PIN_AF13,
+					  DB8500_PIN_AG13, DB8500_PIN_AH15 };
+static const unsigned mc3_b_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
+	DB8500_PIN_AH12, DB8500_PIN_AH11, DB8500_PIN_AG10, DB8500_PIN_AH10,
+	DB8500_PIN_AJ11, DB8500_PIN_AJ9, DB8500_PIN_AH9, DB8500_PIN_AG9,
+	DB8500_PIN_AG8 };
+static const unsigned pwl_b_2_pins[] = { DB8500_PIN_AF8 };
+static const unsigned pwl_b_3_pins[] = { DB8500_PIN_AG7 };
+static const unsigned pwl_b_4_pins[] = { DB8500_PIN_AF7 };
+
+/* Altfunction C column */
+static const unsigned ipjtag_c_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3,
+	DB8500_PIN_AH4, DB8500_PIN_AH3, DB8500_PIN_AH6 };
+static const unsigned ipgpio6_c_1_pins[] = { DB8500_PIN_AG6 };
+static const unsigned ipgpio0_c_1_pins[] = { DB8500_PIN_AF6 };
+static const unsigned ipgpio1_c_1_pins[] = { DB8500_PIN_AG5 };
+static const unsigned ipgpio3_c_1_pins[] = { DB8500_PIN_AF5 };
+static const unsigned ipgpio2_c_1_pins[] = { DB8500_PIN_AG4 };
+static const unsigned slim0_c_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 };
+/* Optional 4-bit Memory Stick interface */
+static const unsigned ms_c_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1,
+	DB8500_PIN_AB3, DB8500_PIN_AA3, DB8500_PIN_AA4, DB8500_PIN_AB2,
+	DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned iptrigout_c_1_pins[] = { DB8500_PIN_AB4 };
+static const unsigned u2rxtx_c_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3 };
+static const unsigned u2ctsrts_c_1_pins[] = { DB8500_PIN_V3, DB8500_PIN_V2 };
+static const unsigned u0_c_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AE1,
+					DB8500_PIN_AE2, DB8500_PIN_AG2 };
+static const unsigned ipgpio4_c_1_pins[] = { DB8500_PIN_F3 };
+static const unsigned ipgpio5_c_1_pins[] = { DB8500_PIN_F1 };
+static const unsigned ipgpio6_c_2_pins[] = { DB8500_PIN_G3 };
+static const unsigned ipgpio7_c_1_pins[] = { DB8500_PIN_G2 };
+static const unsigned smcleale_c_1_pins[] = { DB8500_PIN_E1, DB8500_PIN_E2 };
+static const unsigned stmape_c_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+	DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 };
+static const unsigned u2rxtx_c_2_pins[] = { DB8500_PIN_H2, DB8500_PIN_J2 };
+static const unsigned ipgpio2_c_2_pins[] = { DB8500_PIN_F4 };
+static const unsigned ipgpio3_c_2_pins[] = { DB8500_PIN_E3 };
+static const unsigned ipgpio4_c_2_pins[] = { DB8500_PIN_E4 };
+static const unsigned ipgpio5_c_2_pins[] = { DB8500_PIN_D2 };
+static const unsigned mc5_c_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
+	DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
+	DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8,
+	DB8500_PIN_D9 };
+static const unsigned mc2rstn_c_1_pins[] = { DB8500_PIN_C8 };
+static const unsigned kp_c_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11,
+	DB8500_PIN_C12, DB8500_PIN_C11, DB8500_PIN_D17, DB8500_PIN_D16,
+	DB8500_PIN_C23, DB8500_PIN_D23 };
+static const unsigned smps1_c_1_pins[] = { DB8500_PIN_B14 };
+static const unsigned u2rxtx_c_3_pins[] = { DB8500_PIN_B17, DB8500_PIN_C16 };
+static const unsigned stmape_c_2_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17,
+	DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 };
+static const unsigned uartmodrx_c_1_pins[] = { DB8500_PIN_D21 };
+static const unsigned uartmodtx_c_1_pins[] = { DB8500_PIN_D20 };
+static const unsigned stmmod_c_1_pins[] = { DB8500_PIN_C20, DB8500_PIN_B21,
+	DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24 };
+static const unsigned usbsim_c_1_pins[] = { DB8500_PIN_D22 };
+static const unsigned mc4rstn_c_1_pins[] = { DB8500_PIN_AF25 };
+static const unsigned clkout_c_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12 };
+static const unsigned i2c3_c_1_pins[] = { DB8500_PIN_AG12, DB8500_PIN_AH11 };
+static const unsigned spi0_c_1_pins[] = { DB8500_PIN_AH10, DB8500_PIN_AH9,
+					  DB8500_PIN_AG9, DB8500_PIN_AG8 };
+static const unsigned usbsim_c_2_pins[] = { DB8500_PIN_AF8 };
+static const unsigned i2c3_c_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
+
+/* Other C1 column */
+static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
+	DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
+	DB8500_PIN_D6, DB8500_PIN_B7 };
+static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
+	DB8500_PIN_AH12, DB8500_PIN_AH11 };
+
+#define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins,		\
+			.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct nmk_pingroup nmk_db8500_groups[] = {
+	/* Altfunction A column */
+	DB8500_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(u1rxtx_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(u1ctsrts_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(ipi2c_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(ipi2c_a_2, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(msp0txrx_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(msp0tfstck_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(msp0rfsrck_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(mc0_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(msp1txrx_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(msp1_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(lcdb_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(lcdvsi0_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(lcdvsi1_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(lcd_d0_d7_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(lcd_d8_d11_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(lcd_d12_d23_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(kp_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(mc2_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(ssp1_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(ssp0_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(msp2_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(mc1_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A),
+	DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A),
+	/* Altfunction B column */
+	DB8500_PIN_GROUP(trig_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(i2c4_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(i2c1_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(i2c2_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(i2c2_b_2, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(msp0txrx_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(i2c1_b_2, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(u2rxtx_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(uartmodtx_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(msp0sck_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(uartmodrx_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(stmmod_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(uartmodrx_b_2, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(spi3_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(msp1txrx_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(kp_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(sm_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(smcs0_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(ipgpio7_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(ipgpio2_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(ipgpio3_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(lcdaclk_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(lcda_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(lcd_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(ddrtrig_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(pwl_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(spi1_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(mc3_b_1, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(pwl_b_2, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(pwl_b_3, NMK_GPIO_ALT_B),
+	DB8500_PIN_GROUP(pwl_b_4, NMK_GPIO_ALT_B),
+	/* Altfunction C column */
+	DB8500_PIN_GROUP(ipjtag_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio0_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio1_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio3_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio2_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(slim0_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ms_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(iptrigout_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(u2rxtx_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(u2ctsrts_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(u0_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio4_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio5_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio7_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(smcleale_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(stmape_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(u2rxtx_c_2, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio2_c_2, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio3_c_2, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio4_c_2, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(ipgpio5_c_2, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(mc5_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(mc2rstn_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(kp_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(smps1_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(u2rxtx_c_3, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(stmape_c_2, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(uartmodrx_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(uartmodtx_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(stmmod_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(usbsim_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(clkout_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C),
+	/* Other alt C1 column, these are still configured as alt C */
+	DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C),
+	DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define DB8500_FUNC_GROUPS(a, b...)	   \
+static const char * const a##_groups[] = { b };
+
+DB8500_FUNC_GROUPS(u0, "u0_a_1", "u0_c_1");
+DB8500_FUNC_GROUPS(u1, "u1rxtx_a_1", "u1ctsrts_a_1");
+/*
+ * UART2 can be muxed out with just RX/TX in four places, CTS+RTS is however
+ * only available on two pins in alternative function C
+ */
+DB8500_FUNC_GROUPS(u2, "u2rxtx_b_1", "u2rxtx_c_1", "u2ctsrts_c_1",
+		   "u2rxtx_c_2", "u2rxtx_c_3");
+DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2");
+/*
+ * MSP0 can only be on a certain set of pins, but the TX/RX pins can be
+ * switched around by selecting the altfunction A or B. The SCK pin is
+ * only available on the altfunction B.
+ */
+DB8500_FUNC_GROUPS(msp0, "msp0txrx_a_1", "msp0tfstck_a_1", "msp0rfstck_a_1",
+		   "msp0txrx_b_1", "msp0sck_b_1");
+DB8500_FUNC_GROUPS(mc0, "mc0_a_1");
+/* MSP0 can swap RX/TX like MSP0 but has no SCK pin available */
+DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1");
+DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1");
+DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1",
+	"lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1");
+DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_c_1", "kp_oc1_1");
+DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1");
+DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1");
+DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1");
+DB8500_FUNC_GROUPS(i2c0, "i2c0_a_1");
+/* The image processor has 8 GPIO pins that can be muxed out */
+DB8500_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio1_a_1", "ipgpio7_b_1",
+	"ipgpio2_b_1", "ipgpio3_b_1", "ipgpio6_c_1", "ipgpio0_c_1",
+	"ipgpio1_c_1", "ipgpio3_c_1", "ipgpio2_c_1", "ipgpio4_c_1",
+	"ipgpio5_c_1", "ipgpio6_c_2", "ipgpio7_c_1", "ipgpio2_c_2",
+	"ipgpio3_c_2", "ipgpio4_c_2", "ipgpio5_c_2");
+/* MSP2 can not invert the RX/TX pins but has the optional SCK pin */
+DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1");
+DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1");
+DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1dir_a_1");
+DB8500_FUNC_GROUPS(hsi, "hsir1_a_1", "hsit1_a_1");
+DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1");
+DB8500_FUNC_GROUPS(usb, "usb_a_1");
+DB8500_FUNC_GROUPS(trig, "trig_b_1");
+DB8500_FUNC_GROUPS(i2c4, "i2c4_b_1");
+DB8500_FUNC_GROUPS(i2c1, "i2c1_b_1", "i2c1_b_2");
+DB8500_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2");
+/*
+ * The modem UART can output its RX and TX pins in some different places,
+ * so select one of each.
+ */
+DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2",
+		   "uartmodrx_c_1", "uartmod_tx_c_1");
+DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1");
+DB8500_FUNC_GROUPS(spi3, "spi3_b_1");
+/* Select between CS0 on alt B or PS1 on alt C */
+DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcleale_c_1", "smps1_c_1");
+DB8500_FUNC_GROUPS(lcda, "lcdaclk_b_1", "lcda_b_1");
+DB8500_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1");
+DB8500_FUNC_GROUPS(pwl, "pwl_b_1", "pwl_b_2", "pwl_b_3", "pwl_b_4");
+DB8500_FUNC_GROUPS(spi1, "spi1_b_1");
+DB8500_FUNC_GROUPS(mc3, "mc3_b_1");
+DB8500_FUNC_GROUPS(ipjtag, "ipjtag_c_1");
+DB8500_FUNC_GROUPS(slim0, "slim0_c_1");
+DB8500_FUNC_GROUPS(ms, "ms_c_1");
+DB8500_FUNC_GROUPS(iptrigout, "iptrigout_c_1");
+DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2");
+DB8500_FUNC_GROUPS(mc5, "mc5_c_1");
+DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2");
+DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2");
+DB8500_FUNC_GROUPS(spi0, "spi0_c_1");
+DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1");
+
+#define FUNCTION(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+static const struct nmk_function nmk_db8500_functions[] = {
+	FUNCTION(u0),
+	FUNCTION(u1),
+	FUNCTION(u2),
+	FUNCTION(ipi2c),
+	FUNCTION(msp0),
+	FUNCTION(mc0),
+	FUNCTION(msp1),
+	FUNCTION(lcdb),
+	FUNCTION(lcd),
+	FUNCTION(kp),
+	FUNCTION(mc2),
+	FUNCTION(ssp1),
+	FUNCTION(ssp0),
+	FUNCTION(i2c0),
+	FUNCTION(ipgpio),
+	FUNCTION(msp2),
+	FUNCTION(mc4),
+	FUNCTION(mc1),
+	FUNCTION(hsi),
+	FUNCTION(clkout),
+	FUNCTION(usb),
+	FUNCTION(trig),
+	FUNCTION(i2c4),
+	FUNCTION(i2c1),
+	FUNCTION(i2c2),
+	FUNCTION(uartmod),
+	FUNCTION(stmmod),
+	FUNCTION(spi3),
+	FUNCTION(sm),
+	FUNCTION(lcda),
+	FUNCTION(ddrtrig),
+	FUNCTION(pwl),
+	FUNCTION(spi1),
+	FUNCTION(mc3),
+	FUNCTION(ipjtag),
+	FUNCTION(slim0),
+	FUNCTION(ms),
+	FUNCTION(iptrigout),
+	FUNCTION(stmape),
+	FUNCTION(mc5),
+	FUNCTION(usbsim),
+	FUNCTION(i2c3),
+	FUNCTION(spi0),
+	FUNCTION(spi2),
+};
+
+static const struct nmk_pinctrl_soc_data nmk_db8500_soc = {
+	.gpio_ranges = nmk_db8500_ranges,
+	.gpio_num_ranges = ARRAY_SIZE(nmk_db8500_ranges),
+	.pins = nmk_db8500_pins,
+	.npins = ARRAY_SIZE(nmk_db8500_pins),
+	.functions = nmk_db8500_functions,
+	.nfunctions = ARRAY_SIZE(nmk_db8500_functions),
+	.groups = nmk_db8500_groups,
+	.ngroups = ARRAY_SIZE(nmk_db8500_groups),
+};
+
+void __devinit
+nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
+{
+	*soc = &nmk_db8500_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
new file mode 100644
index 0000000..b8e01c3
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -0,0 +1,1780 @@
+/*
+ * Generic GPIO driver for logic cells found in the Nomadik SoC
+ *
+ * Copyright (C) 2008,2009 STMicroelectronics
+ * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
+ *   Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
+ * Copyright (C) 2011 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * 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/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/slab.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+/* Since we request GPIOs from ourself */
+#include <linux/pinctrl/consumer.h>
+
+#include <asm/mach/irq.h>
+
+#include <plat/pincfg.h>
+#include <plat/gpio-nomadik.h>
+
+#include "pinctrl-nomadik.h"
+
+/*
+ * The GPIO module in the Nomadik family of Systems-on-Chip is an
+ * AMBA device, managing 32 pins and alternate functions.  The logic block
+ * is currently used in the Nomadik and ux500.
+ *
+ * Symbols in this file are called "nmk_gpio" for "nomadik gpio"
+ */
+
+#define NMK_GPIO_PER_CHIP	32
+
+struct nmk_gpio_chip {
+	struct gpio_chip chip;
+	struct irq_domain *domain;
+	void __iomem *addr;
+	struct clk *clk;
+	unsigned int bank;
+	unsigned int parent_irq;
+	int secondary_parent_irq;
+	u32 (*get_secondary_status)(unsigned int bank);
+	void (*set_ioforce)(bool enable);
+	spinlock_t lock;
+	bool sleepmode;
+	/* Keep track of configured edges */
+	u32 edge_rising;
+	u32 edge_falling;
+	u32 real_wake;
+	u32 rwimsc;
+	u32 fwimsc;
+	u32 rimsc;
+	u32 fimsc;
+	u32 pull_up;
+	u32 lowemi;
+};
+
+struct nmk_pinctrl {
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+	const struct nmk_pinctrl_soc_data *soc;
+};
+
+static struct nmk_gpio_chip *
+nmk_gpio_chips[DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP)];
+
+static DEFINE_SPINLOCK(nmk_gpio_slpm_lock);
+
+#define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips)
+
+static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip,
+				unsigned offset, int gpio_mode)
+{
+	u32 bit = 1 << offset;
+	u32 afunc, bfunc;
+
+	afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit;
+	bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit;
+	if (gpio_mode & NMK_GPIO_ALT_A)
+		afunc |= bit;
+	if (gpio_mode & NMK_GPIO_ALT_B)
+		bfunc |= bit;
+	writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA);
+	writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB);
+}
+
+static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip,
+				unsigned offset, enum nmk_gpio_slpm mode)
+{
+	u32 bit = 1 << offset;
+	u32 slpm;
+
+	slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC);
+	if (mode == NMK_GPIO_SLPM_NOCHANGE)
+		slpm |= bit;
+	else
+		slpm &= ~bit;
+	writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC);
+}
+
+static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
+				unsigned offset, enum nmk_gpio_pull pull)
+{
+	u32 bit = 1 << offset;
+	u32 pdis;
+
+	pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS);
+	if (pull == NMK_GPIO_PULL_NONE) {
+		pdis |= bit;
+		nmk_chip->pull_up &= ~bit;
+	} else {
+		pdis &= ~bit;
+	}
+
+	writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS);
+
+	if (pull == NMK_GPIO_PULL_UP) {
+		nmk_chip->pull_up |= bit;
+		writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
+	} else if (pull == NMK_GPIO_PULL_DOWN) {
+		nmk_chip->pull_up &= ~bit;
+		writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
+	}
+}
+
+static void __nmk_gpio_set_lowemi(struct nmk_gpio_chip *nmk_chip,
+				  unsigned offset, bool lowemi)
+{
+	u32 bit = BIT(offset);
+	bool enabled = nmk_chip->lowemi & bit;
+
+	if (lowemi == enabled)
+		return;
+
+	if (lowemi)
+		nmk_chip->lowemi |= bit;
+	else
+		nmk_chip->lowemi &= ~bit;
+
+	writel_relaxed(nmk_chip->lowemi,
+		       nmk_chip->addr + NMK_GPIO_LOWEMI);
+}
+
+static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
+				  unsigned offset)
+{
+	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
+}
+
+static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip,
+				  unsigned offset, int val)
+{
+	if (val)
+		writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS);
+	else
+		writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC);
+}
+
+static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
+				  unsigned offset, int val)
+{
+	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
+	__nmk_gpio_set_output(nmk_chip, offset, val);
+}
+
+static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip,
+				     unsigned offset, int gpio_mode,
+				     bool glitch)
+{
+	u32 rwimsc = nmk_chip->rwimsc;
+	u32 fwimsc = nmk_chip->fwimsc;
+
+	if (glitch && nmk_chip->set_ioforce) {
+		u32 bit = BIT(offset);
+
+		/* Prevent spurious wakeups */
+		writel(rwimsc & ~bit, nmk_chip->addr + NMK_GPIO_RWIMSC);
+		writel(fwimsc & ~bit, nmk_chip->addr + NMK_GPIO_FWIMSC);
+
+		nmk_chip->set_ioforce(true);
+	}
+
+	__nmk_gpio_set_mode(nmk_chip, offset, gpio_mode);
+
+	if (glitch && nmk_chip->set_ioforce) {
+		nmk_chip->set_ioforce(false);
+
+		writel(rwimsc, nmk_chip->addr + NMK_GPIO_RWIMSC);
+		writel(fwimsc, nmk_chip->addr + NMK_GPIO_FWIMSC);
+	}
+}
+
+static void
+nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
+{
+	u32 falling = nmk_chip->fimsc & BIT(offset);
+	u32 rising = nmk_chip->rimsc & BIT(offset);
+	int gpio = nmk_chip->chip.base + offset;
+	int irq = NOMADIK_GPIO_TO_IRQ(gpio);
+	struct irq_data *d = irq_get_irq_data(irq);
+
+	if (!rising && !falling)
+		return;
+
+	if (!d || !irqd_irq_disabled(d))
+		return;
+
+	if (rising) {
+		nmk_chip->rimsc &= ~BIT(offset);
+		writel_relaxed(nmk_chip->rimsc,
+			       nmk_chip->addr + NMK_GPIO_RIMSC);
+	}
+
+	if (falling) {
+		nmk_chip->fimsc &= ~BIT(offset);
+		writel_relaxed(nmk_chip->fimsc,
+			       nmk_chip->addr + NMK_GPIO_FIMSC);
+	}
+
+	dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio);
+}
+
+static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
+			     pin_cfg_t cfg, bool sleep, unsigned int *slpmregs)
+{
+	static const char *afnames[] = {
+		[NMK_GPIO_ALT_GPIO]	= "GPIO",
+		[NMK_GPIO_ALT_A]	= "A",
+		[NMK_GPIO_ALT_B]	= "B",
+		[NMK_GPIO_ALT_C]	= "C"
+	};
+	static const char *pullnames[] = {
+		[NMK_GPIO_PULL_NONE]	= "none",
+		[NMK_GPIO_PULL_UP]	= "up",
+		[NMK_GPIO_PULL_DOWN]	= "down",
+		[3] /* illegal */	= "??"
+	};
+	static const char *slpmnames[] = {
+		[NMK_GPIO_SLPM_INPUT]		= "input/wakeup",
+		[NMK_GPIO_SLPM_NOCHANGE]	= "no-change/no-wakeup",
+	};
+
+	int pin = PIN_NUM(cfg);
+	int pull = PIN_PULL(cfg);
+	int af = PIN_ALT(cfg);
+	int slpm = PIN_SLPM(cfg);
+	int output = PIN_DIR(cfg);
+	int val = PIN_VAL(cfg);
+	bool glitch = af == NMK_GPIO_ALT_C;
+
+	dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n",
+		pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
+		output ? "output " : "input",
+		output ? (val ? "high" : "low") : "");
+
+	if (sleep) {
+		int slpm_pull = PIN_SLPM_PULL(cfg);
+		int slpm_output = PIN_SLPM_DIR(cfg);
+		int slpm_val = PIN_SLPM_VAL(cfg);
+
+		af = NMK_GPIO_ALT_GPIO;
+
+		/*
+		 * The SLPM_* values are normal values + 1 to allow zero to
+		 * mean "same as normal".
+		 */
+		if (slpm_pull)
+			pull = slpm_pull - 1;
+		if (slpm_output)
+			output = slpm_output - 1;
+		if (slpm_val)
+			val = slpm_val - 1;
+
+		dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
+			pin,
+			slpm_pull ? pullnames[pull] : "same",
+			slpm_output ? (output ? "output" : "input") : "same",
+			slpm_val ? (val ? "high" : "low") : "same");
+	}
+
+	if (output)
+		__nmk_gpio_make_output(nmk_chip, offset, val);
+	else {
+		__nmk_gpio_make_input(nmk_chip, offset);
+		__nmk_gpio_set_pull(nmk_chip, offset, pull);
+	}
+
+	__nmk_gpio_set_lowemi(nmk_chip, offset, PIN_LOWEMI(cfg));
+
+	/*
+	 * If the pin is switching to altfunc, and there was an interrupt
+	 * installed on it which has been lazy disabled, actually mask the
+	 * interrupt to prevent spurious interrupts that would occur while the
+	 * pin is under control of the peripheral.  Only SKE does this.
+	 */
+	if (af != NMK_GPIO_ALT_GPIO)
+		nmk_gpio_disable_lazy_irq(nmk_chip, offset);
+
+	/*
+	 * If we've backed up the SLPM registers (glitch workaround), modify
+	 * the backups since they will be restored.
+	 */
+	if (slpmregs) {
+		if (slpm == NMK_GPIO_SLPM_NOCHANGE)
+			slpmregs[nmk_chip->bank] |= BIT(offset);
+		else
+			slpmregs[nmk_chip->bank] &= ~BIT(offset);
+	} else
+		__nmk_gpio_set_slpm(nmk_chip, offset, slpm);
+
+	__nmk_gpio_set_mode_safe(nmk_chip, offset, af, glitch);
+}
+
+/*
+ * Safe sequence used to switch IOs between GPIO and Alternate-C mode:
+ *  - Save SLPM registers
+ *  - Set SLPM=0 for the IOs you want to switch and others to 1
+ *  - Configure the GPIO registers for the IOs that are being switched
+ *  - Set IOFORCE=1
+ *  - Modify the AFLSA/B registers for the IOs that are being switched
+ *  - Set IOFORCE=0
+ *  - Restore SLPM registers
+ *  - Any spurious wake up event during switch sequence to be ignored and
+ *    cleared
+ */
+static void nmk_gpio_glitch_slpm_init(unsigned int *slpm)
+{
+	int i;
+
+	for (i = 0; i < NUM_BANKS; i++) {
+		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+		unsigned int temp = slpm[i];
+
+		if (!chip)
+			break;
+
+		clk_enable(chip->clk);
+
+		slpm[i] = readl(chip->addr + NMK_GPIO_SLPC);
+		writel(temp, chip->addr + NMK_GPIO_SLPC);
+	}
+}
+
+static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm)
+{
+	int i;
+
+	for (i = 0; i < NUM_BANKS; i++) {
+		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+		if (!chip)
+			break;
+
+		writel(slpm[i], chip->addr + NMK_GPIO_SLPC);
+
+		clk_disable(chip->clk);
+	}
+}
+
+static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
+{
+	static unsigned int slpm[NUM_BANKS];
+	unsigned long flags;
+	bool glitch = false;
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < num; i++) {
+		if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) {
+			glitch = true;
+			break;
+		}
+	}
+
+	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+
+	if (glitch) {
+		memset(slpm, 0xff, sizeof(slpm));
+
+		for (i = 0; i < num; i++) {
+			int pin = PIN_NUM(cfgs[i]);
+			int offset = pin % NMK_GPIO_PER_CHIP;
+
+			if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C)
+				slpm[pin / NMK_GPIO_PER_CHIP] &= ~BIT(offset);
+		}
+
+		nmk_gpio_glitch_slpm_init(slpm);
+	}
+
+	for (i = 0; i < num; i++) {
+		struct nmk_gpio_chip *nmk_chip;
+		int pin = PIN_NUM(cfgs[i]);
+
+		nmk_chip = nmk_gpio_chips[pin / NMK_GPIO_PER_CHIP];
+		if (!nmk_chip) {
+			ret = -EINVAL;
+			break;
+		}
+
+		clk_enable(nmk_chip->clk);
+		spin_lock(&nmk_chip->lock);
+		__nmk_config_pin(nmk_chip, pin % NMK_GPIO_PER_CHIP,
+				 cfgs[i], sleep, glitch ? slpm : NULL);
+		spin_unlock(&nmk_chip->lock);
+		clk_disable(nmk_chip->clk);
+	}
+
+	if (glitch)
+		nmk_gpio_glitch_slpm_restore(slpm);
+
+	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+
+	return ret;
+}
+
+/**
+ * nmk_config_pin - configure a pin's mux attributes
+ * @cfg: pin confguration
+ *
+ * Configures a pin's mode (alternate function or GPIO), its pull up status,
+ * and its sleep mode based on the specified configuration.  The @cfg is
+ * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
+ * are constructed using, and can be further enhanced with, the macros in
+ * plat/pincfg.h.
+ *
+ * If a pin's mode is set to GPIO, it is configured as an input to avoid
+ * side-effects.  The gpio can be manipulated later using standard GPIO API
+ * calls.
+ */
+int nmk_config_pin(pin_cfg_t cfg, bool sleep)
+{
+	return __nmk_config_pins(&cfg, 1, sleep);
+}
+EXPORT_SYMBOL(nmk_config_pin);
+
+/**
+ * nmk_config_pins - configure several pins at once
+ * @cfgs: array of pin configurations
+ * @num: number of elments in the array
+ *
+ * Configures several pins using nmk_config_pin().  Refer to that function for
+ * further information.
+ */
+int nmk_config_pins(pin_cfg_t *cfgs, int num)
+{
+	return __nmk_config_pins(cfgs, num, false);
+}
+EXPORT_SYMBOL(nmk_config_pins);
+
+int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num)
+{
+	return __nmk_config_pins(cfgs, num, true);
+}
+EXPORT_SYMBOL(nmk_config_pins_sleep);
+
+/**
+ * nmk_gpio_set_slpm() - configure the sleep mode of a pin
+ * @gpio: pin number
+ * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE,
+ *
+ * This register is actually in the pinmux layer, not the GPIO block itself.
+ * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP
+ * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code).
+ * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is
+ * HIGH, overriding the normal setting defined by GPIO_AFSELx registers.
+ * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit),
+ * the GPIOs return to the normal setting defined by GPIO_AFSELx registers.
+ *
+ * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO
+ * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is
+ * entered) regardless of the altfunction selected. Also wake-up detection is
+ * ENABLED.
+ *
+ * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains
+ * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS
+ * (for altfunction GPIO) or respective on-chip peripherals (for other
+ * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED.
+ *
+ * Note that enable_irq_wake() will automatically enable wakeup detection.
+ */
+int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
+{
+	struct nmk_gpio_chip *nmk_chip;
+	unsigned long flags;
+
+	nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
+	if (!nmk_chip)
+		return -EINVAL;
+
+	clk_enable(nmk_chip->clk);
+	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+	spin_lock(&nmk_chip->lock);
+
+	__nmk_gpio_set_slpm(nmk_chip, gpio % NMK_GPIO_PER_CHIP, mode);
+
+	spin_unlock(&nmk_chip->lock);
+	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+	clk_disable(nmk_chip->clk);
+
+	return 0;
+}
+
+/**
+ * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio
+ * @gpio: pin number
+ * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE
+ *
+ * Enables/disables pull up/down on a specified pin.  This only takes effect if
+ * the pin is configured as an input (either explicitly or by the alternate
+ * function).
+ *
+ * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
+ * configured as an input.  Otherwise, due to the way the controller registers
+ * work, this function will change the value output on the pin.
+ */
+int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
+{
+	struct nmk_gpio_chip *nmk_chip;
+	unsigned long flags;
+
+	nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
+	if (!nmk_chip)
+		return -EINVAL;
+
+	clk_enable(nmk_chip->clk);
+	spin_lock_irqsave(&nmk_chip->lock, flags);
+	__nmk_gpio_set_pull(nmk_chip, gpio % NMK_GPIO_PER_CHIP, pull);
+	spin_unlock_irqrestore(&nmk_chip->lock, flags);
+	clk_disable(nmk_chip->clk);
+
+	return 0;
+}
+
+/* Mode functions */
+/**
+ * nmk_gpio_set_mode() - set the mux mode of a gpio pin
+ * @gpio: pin number
+ * @gpio_mode: one of NMK_GPIO_ALT_GPIO, NMK_GPIO_ALT_A,
+ *	       NMK_GPIO_ALT_B, and NMK_GPIO_ALT_C
+ *
+ * Sets the mode of the specified pin to one of the alternate functions or
+ * plain GPIO.
+ */
+int nmk_gpio_set_mode(int gpio, int gpio_mode)
+{
+	struct nmk_gpio_chip *nmk_chip;
+	unsigned long flags;
+
+	nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
+	if (!nmk_chip)
+		return -EINVAL;
+
+	clk_enable(nmk_chip->clk);
+	spin_lock_irqsave(&nmk_chip->lock, flags);
+	__nmk_gpio_set_mode(nmk_chip, gpio % NMK_GPIO_PER_CHIP, gpio_mode);
+	spin_unlock_irqrestore(&nmk_chip->lock, flags);
+	clk_disable(nmk_chip->clk);
+
+	return 0;
+}
+EXPORT_SYMBOL(nmk_gpio_set_mode);
+
+int nmk_gpio_get_mode(int gpio)
+{
+	struct nmk_gpio_chip *nmk_chip;
+	u32 afunc, bfunc, bit;
+
+	nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
+	if (!nmk_chip)
+		return -EINVAL;
+
+	bit = 1 << (gpio % NMK_GPIO_PER_CHIP);
+
+	clk_enable(nmk_chip->clk);
+
+	afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit;
+	bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit;
+
+	clk_disable(nmk_chip->clk);
+
+	return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0);
+}
+EXPORT_SYMBOL(nmk_gpio_get_mode);
+
+
+/* IRQ functions */
+static inline int nmk_gpio_get_bitmask(int gpio)
+{
+	return 1 << (gpio % NMK_GPIO_PER_CHIP);
+}
+
+static void nmk_gpio_irq_ack(struct irq_data *d)
+{
+	struct nmk_gpio_chip *nmk_chip;
+
+	nmk_chip = irq_data_get_irq_chip_data(d);
+	if (!nmk_chip)
+		return;
+
+	clk_enable(nmk_chip->clk);
+	writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
+	clk_disable(nmk_chip->clk);
+}
+
+enum nmk_gpio_irq_type {
+	NORMAL,
+	WAKE,
+};
+
+static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
+				  int gpio, enum nmk_gpio_irq_type which,
+				  bool enable)
+{
+	u32 bitmask = nmk_gpio_get_bitmask(gpio);
+	u32 *rimscval;
+	u32 *fimscval;
+	u32 rimscreg;
+	u32 fimscreg;
+
+	if (which == NORMAL) {
+		rimscreg = NMK_GPIO_RIMSC;
+		fimscreg = NMK_GPIO_FIMSC;
+		rimscval = &nmk_chip->rimsc;
+		fimscval = &nmk_chip->fimsc;
+	} else  {
+		rimscreg = NMK_GPIO_RWIMSC;
+		fimscreg = NMK_GPIO_FWIMSC;
+		rimscval = &nmk_chip->rwimsc;
+		fimscval = &nmk_chip->fwimsc;
+	}
+
+	/* we must individually set/clear the two edges */
+	if (nmk_chip->edge_rising & bitmask) {
+		if (enable)
+			*rimscval |= bitmask;
+		else
+			*rimscval &= ~bitmask;
+		writel(*rimscval, nmk_chip->addr + rimscreg);
+	}
+	if (nmk_chip->edge_falling & bitmask) {
+		if (enable)
+			*fimscval |= bitmask;
+		else
+			*fimscval &= ~bitmask;
+		writel(*fimscval, nmk_chip->addr + fimscreg);
+	}
+}
+
+static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
+				int gpio, bool on)
+{
+	/*
+	 * Ensure WAKEUP_ENABLE is on.  No need to disable it if wakeup is
+	 * disabled, since setting SLPM to 1 increases power consumption, and
+	 * wakeup is anyhow controlled by the RIMSC and FIMSC registers.
+	 */
+	if (nmk_chip->sleepmode && on) {
+		__nmk_gpio_set_slpm(nmk_chip, gpio % nmk_chip->chip.base,
+				    NMK_GPIO_SLPM_WAKEUP_ENABLE);
+	}
+
+	__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
+}
+
+static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
+{
+	struct nmk_gpio_chip *nmk_chip;
+	unsigned long flags;
+	u32 bitmask;
+
+	nmk_chip = irq_data_get_irq_chip_data(d);
+	bitmask = nmk_gpio_get_bitmask(d->hwirq);
+	if (!nmk_chip)
+		return -EINVAL;
+
+	clk_enable(nmk_chip->clk);
+	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+	spin_lock(&nmk_chip->lock);
+
+	__nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, enable);
+
+	if (!(nmk_chip->real_wake & bitmask))
+		__nmk_gpio_set_wake(nmk_chip, d->hwirq, enable);
+
+	spin_unlock(&nmk_chip->lock);
+	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+	clk_disable(nmk_chip->clk);
+
+	return 0;
+}
+
+static void nmk_gpio_irq_mask(struct irq_data *d)
+{
+	nmk_gpio_irq_maskunmask(d, false);
+}
+
+static void nmk_gpio_irq_unmask(struct irq_data *d)
+{
+	nmk_gpio_irq_maskunmask(d, true);
+}
+
+static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	struct nmk_gpio_chip *nmk_chip;
+	unsigned long flags;
+	u32 bitmask;
+
+	nmk_chip = irq_data_get_irq_chip_data(d);
+	if (!nmk_chip)
+		return -EINVAL;
+	bitmask = nmk_gpio_get_bitmask(d->hwirq);
+
+	clk_enable(nmk_chip->clk);
+	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+	spin_lock(&nmk_chip->lock);
+
+	if (irqd_irq_disabled(d))
+		__nmk_gpio_set_wake(nmk_chip, d->hwirq, on);
+
+	if (on)
+		nmk_chip->real_wake |= bitmask;
+	else
+		nmk_chip->real_wake &= ~bitmask;
+
+	spin_unlock(&nmk_chip->lock);
+	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+	clk_disable(nmk_chip->clk);
+
+	return 0;
+}
+
+static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+	bool enabled = !irqd_irq_disabled(d);
+	bool wake = irqd_is_wakeup_set(d);
+	struct nmk_gpio_chip *nmk_chip;
+	unsigned long flags;
+	u32 bitmask;
+
+	nmk_chip = irq_data_get_irq_chip_data(d);
+	bitmask = nmk_gpio_get_bitmask(d->hwirq);
+	if (!nmk_chip)
+		return -EINVAL;
+	if (type & IRQ_TYPE_LEVEL_HIGH)
+		return -EINVAL;
+	if (type & IRQ_TYPE_LEVEL_LOW)
+		return -EINVAL;
+
+	clk_enable(nmk_chip->clk);
+	spin_lock_irqsave(&nmk_chip->lock, flags);
+
+	if (enabled)
+		__nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, false);
+
+	if (enabled || wake)
+		__nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, false);
+
+	nmk_chip->edge_rising &= ~bitmask;
+	if (type & IRQ_TYPE_EDGE_RISING)
+		nmk_chip->edge_rising |= bitmask;
+
+	nmk_chip->edge_falling &= ~bitmask;
+	if (type & IRQ_TYPE_EDGE_FALLING)
+		nmk_chip->edge_falling |= bitmask;
+
+	if (enabled)
+		__nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, true);
+
+	if (enabled || wake)
+		__nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, true);
+
+	spin_unlock_irqrestore(&nmk_chip->lock, flags);
+	clk_disable(nmk_chip->clk);
+
+	return 0;
+}
+
+static unsigned int nmk_gpio_irq_startup(struct irq_data *d)
+{
+	struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
+
+	clk_enable(nmk_chip->clk);
+	nmk_gpio_irq_unmask(d);
+	return 0;
+}
+
+static void nmk_gpio_irq_shutdown(struct irq_data *d)
+{
+	struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
+
+	nmk_gpio_irq_mask(d);
+	clk_disable(nmk_chip->clk);
+}
+
+static struct irq_chip nmk_gpio_irq_chip = {
+	.name		= "Nomadik-GPIO",
+	.irq_ack	= nmk_gpio_irq_ack,
+	.irq_mask	= nmk_gpio_irq_mask,
+	.irq_unmask	= nmk_gpio_irq_unmask,
+	.irq_set_type	= nmk_gpio_irq_set_type,
+	.irq_set_wake	= nmk_gpio_irq_set_wake,
+	.irq_startup	= nmk_gpio_irq_startup,
+	.irq_shutdown	= nmk_gpio_irq_shutdown,
+};
+
+static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
+				   u32 status)
+{
+	struct nmk_gpio_chip *nmk_chip;
+	struct irq_chip *host_chip = irq_get_chip(irq);
+	unsigned int first_irq;
+
+	chained_irq_enter(host_chip, desc);
+
+	nmk_chip = irq_get_handler_data(irq);
+	first_irq = nmk_chip->domain->revmap_data.legacy.first_irq;
+	while (status) {
+		int bit = __ffs(status);
+
+		generic_handle_irq(first_irq + bit);
+		status &= ~BIT(bit);
+	}
+
+	chained_irq_exit(host_chip, desc);
+}
+
+static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
+	u32 status;
+
+	clk_enable(nmk_chip->clk);
+	status = readl(nmk_chip->addr + NMK_GPIO_IS);
+	clk_disable(nmk_chip->clk);
+
+	__nmk_gpio_irq_handler(irq, desc, status);
+}
+
+static void nmk_gpio_secondary_irq_handler(unsigned int irq,
+					   struct irq_desc *desc)
+{
+	struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
+	u32 status = nmk_chip->get_secondary_status(nmk_chip->bank);
+
+	__nmk_gpio_irq_handler(irq, desc, status);
+}
+
+static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
+{
+	irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
+	irq_set_handler_data(nmk_chip->parent_irq, nmk_chip);
+
+	if (nmk_chip->secondary_parent_irq >= 0) {
+		irq_set_chained_handler(nmk_chip->secondary_parent_irq,
+					nmk_gpio_secondary_irq_handler);
+		irq_set_handler_data(nmk_chip->secondary_parent_irq, nmk_chip);
+	}
+
+	return 0;
+}
+
+/* I/O Functions */
+
+static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	/*
+	 * Map back to global GPIO space and request muxing, the direction
+	 * parameter does not matter for this controller.
+	 */
+	int gpio = chip->base + offset;
+
+	return pinctrl_request_gpio(gpio);
+}
+
+static void nmk_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	pinctrl_free_gpio(gpio);
+}
+
+static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct nmk_gpio_chip *nmk_chip =
+		container_of(chip, struct nmk_gpio_chip, chip);
+
+	clk_enable(nmk_chip->clk);
+
+	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
+
+	clk_disable(nmk_chip->clk);
+
+	return 0;
+}
+
+static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct nmk_gpio_chip *nmk_chip =
+		container_of(chip, struct nmk_gpio_chip, chip);
+	u32 bit = 1 << offset;
+	int value;
+
+	clk_enable(nmk_chip->clk);
+
+	value = (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
+
+	clk_disable(nmk_chip->clk);
+
+	return value;
+}
+
+static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
+				int val)
+{
+	struct nmk_gpio_chip *nmk_chip =
+		container_of(chip, struct nmk_gpio_chip, chip);
+
+	clk_enable(nmk_chip->clk);
+
+	__nmk_gpio_set_output(nmk_chip, offset, val);
+
+	clk_disable(nmk_chip->clk);
+}
+
+static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
+				int val)
+{
+	struct nmk_gpio_chip *nmk_chip =
+		container_of(chip, struct nmk_gpio_chip, chip);
+
+	clk_enable(nmk_chip->clk);
+
+	__nmk_gpio_make_output(nmk_chip, offset, val);
+
+	clk_disable(nmk_chip->clk);
+
+	return 0;
+}
+
+static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct nmk_gpio_chip *nmk_chip =
+		container_of(chip, struct nmk_gpio_chip, chip);
+
+	return irq_find_mapping(nmk_chip->domain, offset);
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
+				  unsigned offset, unsigned gpio)
+{
+	const char *label = gpiochip_is_requested(chip, offset);
+	struct nmk_gpio_chip *nmk_chip =
+		container_of(chip, struct nmk_gpio_chip, chip);
+	int mode;
+	bool is_out;
+	bool pull;
+	u32 bit = 1 << offset;
+	const char *modes[] = {
+		[NMK_GPIO_ALT_GPIO]	= "gpio",
+		[NMK_GPIO_ALT_A]	= "altA",
+		[NMK_GPIO_ALT_B]	= "altB",
+		[NMK_GPIO_ALT_C]	= "altC",
+	};
+
+	clk_enable(nmk_chip->clk);
+	is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit);
+	pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
+	mode = nmk_gpio_get_mode(gpio);
+
+	seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
+		   gpio, label ?: "(none)",
+		   is_out ? "out" : "in ",
+		   chip->get
+		   ? (chip->get(chip, offset) ? "hi" : "lo")
+		   : "?  ",
+		   (mode < 0) ? "unknown" : modes[mode],
+		   pull ? "pull" : "none");
+
+	if (label && !is_out) {
+		int		irq = gpio_to_irq(gpio);
+		struct irq_desc	*desc = irq_to_desc(irq);
+
+		/* This races with request_irq(), set_irq_type(),
+		 * and set_irq_wake() ... but those are "rare".
+		 */
+		if (irq >= 0 && desc->action) {
+			char *trigger;
+			u32 bitmask = nmk_gpio_get_bitmask(gpio);
+
+			if (nmk_chip->edge_rising & bitmask)
+				trigger = "edge-rising";
+			else if (nmk_chip->edge_falling & bitmask)
+				trigger = "edge-falling";
+			else
+				trigger = "edge-undefined";
+
+			seq_printf(s, " irq-%d %s%s",
+				   irq, trigger,
+				   irqd_is_wakeup_set(&desc->irq_data)
+				   ? " wakeup" : "");
+		}
+	}
+	clk_disable(nmk_chip->clk);
+}
+
+static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+	unsigned		i;
+	unsigned		gpio = chip->base;
+
+	for (i = 0; i < chip->ngpio; i++, gpio++) {
+		nmk_gpio_dbg_show_one(s, chip, i, gpio);
+		seq_printf(s, "\n");
+	}
+}
+
+#else
+static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
+					 struct gpio_chip *chip,
+					 unsigned offset, unsigned gpio)
+{
+}
+#define nmk_gpio_dbg_show	NULL
+#endif
+
+/* This structure is replicated for each GPIO block allocated at probe time */
+static struct gpio_chip nmk_gpio_template = {
+	.request		= nmk_gpio_request,
+	.free			= nmk_gpio_free,
+	.direction_input	= nmk_gpio_make_input,
+	.get			= nmk_gpio_get_input,
+	.direction_output	= nmk_gpio_make_output,
+	.set			= nmk_gpio_set_output,
+	.to_irq			= nmk_gpio_to_irq,
+	.dbg_show		= nmk_gpio_dbg_show,
+	.can_sleep		= 0,
+};
+
+void nmk_gpio_clocks_enable(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_BANKS; i++) {
+		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+		if (!chip)
+			continue;
+
+		clk_enable(chip->clk);
+	}
+}
+
+void nmk_gpio_clocks_disable(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_BANKS; i++) {
+		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+		if (!chip)
+			continue;
+
+		clk_disable(chip->clk);
+	}
+}
+
+/*
+ * Called from the suspend/resume path to only keep the real wakeup interrupts
+ * (those that have had set_irq_wake() called on them) as wakeup interrupts,
+ * and not the rest of the interrupts which we needed to have as wakeups for
+ * cpuidle.
+ *
+ * PM ops are not used since this needs to be done at the end, after all the
+ * other drivers are done with their suspend callbacks.
+ */
+void nmk_gpio_wakeups_suspend(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_BANKS; i++) {
+		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+		if (!chip)
+			break;
+
+		clk_enable(chip->clk);
+
+		writel(chip->rwimsc & chip->real_wake,
+		       chip->addr + NMK_GPIO_RWIMSC);
+		writel(chip->fwimsc & chip->real_wake,
+		       chip->addr + NMK_GPIO_FWIMSC);
+
+		clk_disable(chip->clk);
+	}
+}
+
+void nmk_gpio_wakeups_resume(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_BANKS; i++) {
+		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+		if (!chip)
+			break;
+
+		clk_enable(chip->clk);
+
+		writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
+		writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
+
+		clk_disable(chip->clk);
+	}
+}
+
+/*
+ * Read the pull up/pull down status.
+ * A bit set in 'pull_up' means that pull up
+ * is selected if pull is enabled in PDIS register.
+ * Note: only pull up/down set via this driver can
+ * be detected due to HW limitations.
+ */
+void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
+{
+	if (gpio_bank < NUM_BANKS) {
+		struct nmk_gpio_chip *chip = nmk_gpio_chips[gpio_bank];
+
+		if (!chip)
+			return;
+
+		*pull_up = chip->pull_up;
+	}
+}
+
+int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+			  irq_hw_number_t hwirq)
+{
+	struct nmk_gpio_chip *nmk_chip = d->host_data;
+
+	if (!nmk_chip)
+		return -EINVAL;
+
+	irq_set_chip_and_handler(irq, &nmk_gpio_irq_chip, handle_edge_irq);
+	set_irq_flags(irq, IRQF_VALID);
+	irq_set_chip_data(irq, nmk_chip);
+	irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
+
+	return 0;
+}
+
+const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
+	.map = nmk_gpio_irq_map,
+	.xlate = irq_domain_xlate_twocell,
+};
+
+static int __devinit nmk_gpio_probe(struct platform_device *dev)
+{
+	struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
+	struct device_node *np = dev->dev.of_node;
+	struct nmk_gpio_chip *nmk_chip;
+	struct gpio_chip *chip;
+	struct resource *res;
+	struct clk *clk;
+	int secondary_irq;
+	void __iomem *base;
+	int irq;
+	int ret;
+
+	if (!pdata && !np) {
+		dev_err(&dev->dev, "No platform data or device tree found\n");
+		return -ENODEV;
+	}
+
+	if (np) {
+		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+
+		if (of_get_property(np, "supports-sleepmode", NULL))
+			pdata->supports_sleepmode = true;
+
+		if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
+			dev_err(&dev->dev, "gpio-bank property not found\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP;
+		pdata->num_gpio   = NMK_GPIO_PER_CHIP;
+	}
+
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENOENT;
+		goto out;
+	}
+
+	irq = platform_get_irq(dev, 0);
+	if (irq < 0) {
+		ret = irq;
+		goto out;
+	}
+
+	secondary_irq = platform_get_irq(dev, 1);
+	if (secondary_irq >= 0 && !pdata->get_secondary_status) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (request_mem_region(res->start, resource_size(res),
+			       dev_name(&dev->dev)) == NULL) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	base = ioremap(res->start, resource_size(res));
+	if (!base) {
+		ret = -ENOMEM;
+		goto out_release;
+	}
+
+	clk = clk_get(&dev->dev, NULL);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		goto out_unmap;
+	}
+
+	nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
+	if (!nmk_chip) {
+		ret = -ENOMEM;
+		goto out_clk;
+	}
+
+	/*
+	 * The virt address in nmk_chip->addr is in the nomadik register space,
+	 * so we can simply convert the resource address, without remapping
+	 */
+	nmk_chip->bank = dev->id;
+	nmk_chip->clk = clk;
+	nmk_chip->addr = base;
+	nmk_chip->chip = nmk_gpio_template;
+	nmk_chip->parent_irq = irq;
+	nmk_chip->secondary_parent_irq = secondary_irq;
+	nmk_chip->get_secondary_status = pdata->get_secondary_status;
+	nmk_chip->set_ioforce = pdata->set_ioforce;
+	nmk_chip->sleepmode = pdata->supports_sleepmode;
+	spin_lock_init(&nmk_chip->lock);
+
+	chip = &nmk_chip->chip;
+	chip->base = pdata->first_gpio;
+	chip->ngpio = pdata->num_gpio;
+	chip->label = pdata->name ?: dev_name(&dev->dev);
+	chip->dev = &dev->dev;
+	chip->owner = THIS_MODULE;
+
+	clk_enable(nmk_chip->clk);
+	nmk_chip->lowemi = readl_relaxed(nmk_chip->addr + NMK_GPIO_LOWEMI);
+	clk_disable(nmk_chip->clk);
+
+#ifdef CONFIG_OF_GPIO
+	chip->of_node = np;
+#endif
+
+	ret = gpiochip_add(&nmk_chip->chip);
+	if (ret)
+		goto out_free;
+
+	BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips));
+
+	nmk_gpio_chips[nmk_chip->bank] = nmk_chip;
+
+	platform_set_drvdata(dev, nmk_chip);
+
+	nmk_chip->domain = irq_domain_add_legacy(np, NMK_GPIO_PER_CHIP,
+						NOMADIK_GPIO_TO_IRQ(pdata->first_gpio),
+						0, &nmk_gpio_irq_simple_ops, nmk_chip);
+	if (!nmk_chip->domain) {
+		pr_err("%s: Failed to create irqdomain\n", np->full_name);
+		ret = -ENOSYS;
+		goto out_free;
+	}
+
+	nmk_gpio_init_irq(nmk_chip);
+
+	dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
+
+	return 0;
+
+out_free:
+	kfree(nmk_chip);
+out_clk:
+	clk_disable(clk);
+	clk_put(clk);
+out_unmap:
+	iounmap(base);
+out_release:
+	release_mem_region(res->start, resource_size(res));
+out:
+	dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret,
+		  pdata->first_gpio, pdata->first_gpio+31);
+	if (np)
+		kfree(pdata);
+
+	return ret;
+}
+
+static int nmk_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+	return npct->soc->ngroups;
+}
+
+static const char *nmk_get_group_name(struct pinctrl_dev *pctldev,
+				       unsigned selector)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+	return npct->soc->groups[selector].name;
+}
+
+static int nmk_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+			      const unsigned **pins,
+			      unsigned *num_pins)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = npct->soc->groups[selector].pins;
+	*num_pins = npct->soc->groups[selector].npins;
+	return 0;
+}
+
+static struct pinctrl_gpio_range *
+nmk_match_gpio_range(struct pinctrl_dev *pctldev, unsigned offset)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+	int i;
+
+	for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
+		struct pinctrl_gpio_range *range;
+
+		range = &npct->soc->gpio_ranges[i];
+		if (offset >= range->pin_base &&
+		    offset <= (range->pin_base + range->npins - 1))
+			return range;
+	}
+	return NULL;
+}
+
+static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+		   unsigned offset)
+{
+	struct pinctrl_gpio_range *range;
+	struct gpio_chip *chip;
+
+	range = nmk_match_gpio_range(pctldev, offset);
+	if (!range || !range->gc) {
+		seq_printf(s, "invalid pin offset");
+		return;
+	}
+	chip = range->gc;
+	nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset);
+}
+
+static struct pinctrl_ops nmk_pinctrl_ops = {
+	.get_groups_count = nmk_get_groups_cnt,
+	.get_group_name = nmk_get_group_name,
+	.get_group_pins = nmk_get_group_pins,
+	.pin_dbg_show = nmk_pin_dbg_show,
+};
+
+static int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+	return npct->soc->nfunctions;
+}
+
+static const char *nmk_pmx_get_func_name(struct pinctrl_dev *pctldev,
+					 unsigned function)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+	return npct->soc->functions[function].name;
+}
+
+static int nmk_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+				   unsigned function,
+				   const char * const **groups,
+				   unsigned * const num_groups)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = npct->soc->functions[function].groups;
+	*num_groups = npct->soc->functions[function].ngroups;
+
+	return 0;
+}
+
+static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
+			  unsigned group)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+	const struct nmk_pingroup *g;
+	static unsigned int slpm[NUM_BANKS];
+	unsigned long flags;
+	bool glitch;
+	int ret = -EINVAL;
+	int i;
+
+	g = &npct->soc->groups[group];
+
+	if (g->altsetting < 0)
+		return -EINVAL;
+
+	dev_dbg(npct->dev, "enable group %s, %u pins\n", g->name, g->npins);
+
+	/* Handle this special glitch on altfunction C */
+	glitch = (g->altsetting == NMK_GPIO_ALT_C);
+
+	if (glitch) {
+		spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+
+		/* Initially don't put any pins to sleep when switching */
+		memset(slpm, 0xff, sizeof(slpm));
+
+		/*
+		 * Then mask the pins that need to be sleeping now when we're
+		 * switching to the ALT C function.
+		 */
+		for (i = 0; i < g->npins; i++)
+			slpm[g->pins[i] / NMK_GPIO_PER_CHIP] &= ~BIT(g->pins[i]);
+		nmk_gpio_glitch_slpm_init(slpm);
+	}
+
+	for (i = 0; i < g->npins; i++) {
+		struct pinctrl_gpio_range *range;
+		struct nmk_gpio_chip *nmk_chip;
+		struct gpio_chip *chip;
+		unsigned bit;
+
+		range = nmk_match_gpio_range(pctldev, g->pins[i]);
+		if (!range) {
+			dev_err(npct->dev,
+				"invalid pin offset %d in group %s at index %d\n",
+				g->pins[i], g->name, i);
+			goto out_glitch;
+		}
+		if (!range->gc) {
+			dev_err(npct->dev, "GPIO chip missing in range for pin offset %d in group %s at index %d\n",
+				g->pins[i], g->name, i);
+			goto out_glitch;
+		}
+		chip = range->gc;
+		nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+		dev_dbg(npct->dev, "setting pin %d to altsetting %d\n", g->pins[i], g->altsetting);
+
+		clk_enable(nmk_chip->clk);
+		bit = g->pins[i] % NMK_GPIO_PER_CHIP;
+		/*
+		 * If the pin is switching to altfunc, and there was an
+		 * interrupt installed on it which has been lazy disabled,
+		 * actually mask the interrupt to prevent spurious interrupts
+		 * that would occur while the pin is under control of the
+		 * peripheral. Only SKE does this.
+		 */
+		nmk_gpio_disable_lazy_irq(nmk_chip, bit);
+
+		__nmk_gpio_set_mode_safe(nmk_chip, bit, g->altsetting, glitch);
+		clk_disable(nmk_chip->clk);
+	}
+
+	/* When all pins are successfully reconfigured we get here */
+	ret = 0;
+
+out_glitch:
+	if (glitch) {
+		nmk_gpio_glitch_slpm_restore(slpm);
+		spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+	}
+
+	return ret;
+}
+
+static void nmk_pmx_disable(struct pinctrl_dev *pctldev,
+			    unsigned function, unsigned group)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+	const struct nmk_pingroup *g;
+
+	g = &npct->soc->groups[group];
+
+	if (g->altsetting < 0)
+		return;
+
+	/* Poke out the mux, set the pin to some default state? */
+	dev_dbg(npct->dev, "disable group %s, %u pins\n", g->name, g->npins);
+}
+
+int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
+			    struct pinctrl_gpio_range *range,
+			    unsigned offset)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+	struct nmk_gpio_chip *nmk_chip;
+	struct gpio_chip *chip;
+	unsigned bit;
+
+	if (!range) {
+		dev_err(npct->dev, "invalid range\n");
+		return -EINVAL;
+	}
+	if (!range->gc) {
+		dev_err(npct->dev, "missing GPIO chip in range\n");
+		return -EINVAL;
+	}
+	chip = range->gc;
+	nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+
+	dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
+
+	clk_enable(nmk_chip->clk);
+	bit = offset % NMK_GPIO_PER_CHIP;
+	/* There is no glitch when converting any pin to GPIO */
+	__nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
+	clk_disable(nmk_chip->clk);
+
+	return 0;
+}
+
+void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
+			   struct pinctrl_gpio_range *range,
+			   unsigned offset)
+{
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+	dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset);
+	/* Set the pin to some default state, GPIO is usually default */
+}
+
+static struct pinmux_ops nmk_pinmux_ops = {
+	.get_functions_count = nmk_pmx_get_funcs_cnt,
+	.get_function_name = nmk_pmx_get_func_name,
+	.get_function_groups = nmk_pmx_get_func_groups,
+	.enable = nmk_pmx_enable,
+	.disable = nmk_pmx_disable,
+	.gpio_request_enable = nmk_gpio_request_enable,
+	.gpio_disable_free = nmk_gpio_disable_free,
+};
+
+int nmk_pin_config_get(struct pinctrl_dev *pctldev,
+		       unsigned pin,
+		       unsigned long *config)
+{
+	/* Not implemented */
+	return -EINVAL;
+}
+
+int nmk_pin_config_set(struct pinctrl_dev *pctldev,
+		       unsigned pin,
+		       unsigned long config)
+{
+	static const char *pullnames[] = {
+		[NMK_GPIO_PULL_NONE]	= "none",
+		[NMK_GPIO_PULL_UP]	= "up",
+		[NMK_GPIO_PULL_DOWN]	= "down",
+		[3] /* illegal */	= "??"
+	};
+	static const char *slpmnames[] = {
+		[NMK_GPIO_SLPM_INPUT]		= "input/wakeup",
+		[NMK_GPIO_SLPM_NOCHANGE]	= "no-change/no-wakeup",
+	};
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+	struct nmk_gpio_chip *nmk_chip;
+	struct pinctrl_gpio_range *range;
+	struct gpio_chip *chip;
+	unsigned bit;
+
+	/*
+	 * The pin config contains pin number and altfunction fields, here
+	 * we just ignore that part. It's being handled by the framework and
+	 * pinmux callback respectively.
+	 */
+	pin_cfg_t cfg = (pin_cfg_t) config;
+	int pull = PIN_PULL(cfg);
+	int slpm = PIN_SLPM(cfg);
+	int output = PIN_DIR(cfg);
+	int val = PIN_VAL(cfg);
+	bool lowemi = PIN_LOWEMI(cfg);
+	bool gpiomode = PIN_GPIOMODE(cfg);
+	bool sleep = PIN_SLEEPMODE(cfg);
+
+	range = nmk_match_gpio_range(pctldev, pin);
+	if (!range) {
+		dev_err(npct->dev, "invalid pin offset %d\n", pin);
+		return -EINVAL;
+	}
+	if (!range->gc) {
+		dev_err(npct->dev, "GPIO chip missing in range for pin %d\n",
+			pin);
+		return -EINVAL;
+	}
+	chip = range->gc;
+	nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+
+	if (sleep) {
+		int slpm_pull = PIN_SLPM_PULL(cfg);
+		int slpm_output = PIN_SLPM_DIR(cfg);
+		int slpm_val = PIN_SLPM_VAL(cfg);
+
+		/* All pins go into GPIO mode at sleep */
+		gpiomode = true;
+
+		/*
+		 * The SLPM_* values are normal values + 1 to allow zero to
+		 * mean "same as normal".
+		 */
+		if (slpm_pull)
+			pull = slpm_pull - 1;
+		if (slpm_output)
+			output = slpm_output - 1;
+		if (slpm_val)
+			val = slpm_val - 1;
+
+		dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
+			pin,
+			slpm_pull ? pullnames[pull] : "same",
+			slpm_output ? (output ? "output" : "input") : "same",
+			slpm_val ? (val ? "high" : "low") : "same");
+	}
+
+	dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
+		pin, cfg, pullnames[pull], slpmnames[slpm],
+		output ? "output " : "input",
+		output ? (val ? "high" : "low") : "",
+		lowemi ? "on" : "off" );
+
+	clk_enable(nmk_chip->clk);
+	bit = pin % NMK_GPIO_PER_CHIP;
+	if (gpiomode)
+		/* No glitch when going to GPIO mode */
+		__nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
+	if (output)
+		__nmk_gpio_make_output(nmk_chip, bit, val);
+	else {
+		__nmk_gpio_make_input(nmk_chip, bit);
+		__nmk_gpio_set_pull(nmk_chip, bit, pull);
+	}
+	/* TODO: isn't this only applicable on output pins? */
+	__nmk_gpio_set_lowemi(nmk_chip, bit, lowemi);
+
+	__nmk_gpio_set_slpm(nmk_chip, bit, slpm);
+	clk_disable(nmk_chip->clk);
+	return 0;
+}
+
+static struct pinconf_ops nmk_pinconf_ops = {
+	.pin_config_get = nmk_pin_config_get,
+	.pin_config_set = nmk_pin_config_set,
+};
+
+static struct pinctrl_desc nmk_pinctrl_desc = {
+	.name = "pinctrl-nomadik",
+	.pctlops = &nmk_pinctrl_ops,
+	.pmxops = &nmk_pinmux_ops,
+	.confops = &nmk_pinconf_ops,
+	.owner = THIS_MODULE,
+};
+
+static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *platid = platform_get_device_id(pdev);
+	struct nmk_pinctrl *npct;
+	int i;
+
+	npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL);
+	if (!npct)
+		return -ENOMEM;
+
+	/* Poke in other ASIC variants here */
+	if (platid->driver_data == PINCTRL_NMK_DB8500)
+		nmk_pinctrl_db8500_init(&npct->soc);
+
+	/*
+	 * We need all the GPIO drivers to probe FIRST, or we will not be able
+	 * to obtain references to the struct gpio_chip * for them, and we
+	 * need this to proceed.
+	 */
+	for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
+		if (!nmk_gpio_chips[i]) {
+			dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
+			devm_kfree(&pdev->dev, npct);
+			return -EPROBE_DEFER;
+		}
+		npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip;
+	}
+
+	nmk_pinctrl_desc.pins = npct->soc->pins;
+	nmk_pinctrl_desc.npins = npct->soc->npins;
+	npct->dev = &pdev->dev;
+	npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct);
+	if (!npct->pctl) {
+		dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n");
+		return -EINVAL;
+	}
+
+	/* We will handle a range of GPIO pins */
+	for (i = 0; i < npct->soc->gpio_num_ranges; i++)
+		pinctrl_add_gpio_range(npct->pctl, &npct->soc->gpio_ranges[i]);
+
+	platform_set_drvdata(pdev, npct);
+	dev_info(&pdev->dev, "initialized Nomadik pin control driver\n");
+
+	return 0;
+}
+
+static const struct of_device_id nmk_gpio_match[] = {
+	{ .compatible = "st,nomadik-gpio", },
+	{}
+};
+
+static struct platform_driver nmk_gpio_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "gpio",
+		.of_match_table = nmk_gpio_match,
+	},
+	.probe = nmk_gpio_probe,
+};
+
+static const struct platform_device_id nmk_pinctrl_id[] = {
+	{ "pinctrl-stn8815", PINCTRL_NMK_STN8815 },
+	{ "pinctrl-db8500", PINCTRL_NMK_DB8500 },
+};
+
+static struct platform_driver nmk_pinctrl_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "pinctrl-nomadik",
+	},
+	.probe = nmk_pinctrl_probe,
+	.id_table = nmk_pinctrl_id,
+};
+
+static int __init nmk_gpio_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&nmk_gpio_driver);
+	if (ret)
+		return ret;
+	return platform_driver_register(&nmk_pinctrl_driver);
+}
+
+core_initcall(nmk_gpio_init);
+
+MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini");
+MODULE_DESCRIPTION("Nomadik GPIO Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h
new file mode 100644
index 0000000..bc91aed
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-nomadik.h
@@ -0,0 +1,77 @@
+#ifndef PINCTRL_PINCTRL_NOMADIK_H
+#define PINCTRL_PINCTRL_NOMADIK_H
+
+#include <plat/gpio-nomadik.h>
+
+/* Package definitions */
+#define PINCTRL_NMK_STN8815	0
+#define PINCTRL_NMK_DB8500	1
+
+/**
+ * struct nmk_function - Nomadik pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct nmk_function {
+	const char *name;
+	const char * const *groups;
+	unsigned ngroups;
+};
+
+/**
+ * struct nmk_pingroup - describes a Nomadik pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ *	from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ *	elements in .pins so we can iterate over that array
+ * @altsetting: the altsetting to apply to all pins in this group to
+ *	configure them to be used by a function
+ */
+struct nmk_pingroup {
+	const char *name;
+	const unsigned int *pins;
+	const unsigned npins;
+	int altsetting;
+};
+
+/**
+ * struct nmk_pinctrl_soc_data - Nomadik pin controller per-SoC configuration
+ * @gpio_ranges: An array of GPIO ranges for this SoC
+ * @gpio_num_ranges: The number of GPIO ranges for this SoC
+ * @pins:	An array describing all pins the pin controller affects.
+ *		All pins which are also GPIOs must be listed first within the
+ *		array, and be numbered identically to the GPIO controller's
+ *		numbering.
+ * @npins:	The number of entries in @pins.
+ * @functions:	The functions supported on this SoC.
+ * @nfunction:	The number of entries in @functions.
+ * @groups:	An array describing all pin groups the pin SoC supports.
+ * @ngroups:	The number of entries in @groups.
+ */
+struct nmk_pinctrl_soc_data {
+	struct pinctrl_gpio_range *gpio_ranges;
+	unsigned gpio_num_ranges;
+	const struct pinctrl_pin_desc *pins;
+	unsigned npins;
+	const struct nmk_function *functions;
+	unsigned nfunctions;
+	const struct nmk_pingroup *groups;
+	unsigned ngroups;
+};
+
+#ifdef CONFIG_PINCTRL_DB8500
+
+void nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#endif /* PINCTRL_PINCTRL_NOMADIK_H */
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 2c98fba..b693486 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -1,7 +1,7 @@
 /*
  * Driver for the NVIDIA Tegra pinmux
  *
- * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
  *
  * Derived from code:
  * Copyright (C) 2010 Google, Inc.
@@ -22,7 +22,8 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
 #include <linux/pinctrl/machine.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
@@ -31,10 +32,9 @@
 
 #include <mach/pinconf-tegra.h>
 
+#include "core.h"
 #include "pinctrl-tegra.h"
 
-#define DRIVER_NAME "tegra-pinmux-disabled"
-
 struct tegra_pmx {
 	struct device *dev;
 	struct pinctrl_dev *pctl;
@@ -83,15 +83,18 @@
 	return 0;
 }
 
+#ifdef CONFIG_DEBUG_FS
 static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
 				       struct seq_file *s,
 				       unsigned offset)
 {
-	seq_printf(s, " " DRIVER_NAME);
+	seq_printf(s, " %s", dev_name(pctldev->dev));
 }
+#endif
 
-static int reserve_map(struct pinctrl_map **map, unsigned *reserved_maps,
-		       unsigned *num_maps, unsigned reserve)
+static int reserve_map(struct device *dev, struct pinctrl_map **map,
+		       unsigned *reserved_maps, unsigned *num_maps,
+		       unsigned reserve)
 {
 	unsigned old_num = *reserved_maps;
 	unsigned new_num = *num_maps + reserve;
@@ -101,8 +104,10 @@
 		return 0;
 
 	new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
-	if (!new_map)
+	if (!new_map) {
+		dev_err(dev, "krealloc(map) failed\n");
 		return -ENOMEM;
+	}
 
 	memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
 
@@ -116,7 +121,7 @@
 		       unsigned *num_maps, const char *group,
 		       const char *function)
 {
-	if (*num_maps == *reserved_maps)
+	if (WARN_ON(*num_maps == *reserved_maps))
 		return -ENOSPC;
 
 	(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
@@ -127,19 +132,22 @@
 	return 0;
 }
 
-static int add_map_configs(struct pinctrl_map **map, unsigned *reserved_maps,
-			   unsigned *num_maps, const char *group,
-			   unsigned long *configs, unsigned num_configs)
+static int add_map_configs(struct device *dev, struct pinctrl_map **map,
+			   unsigned *reserved_maps, unsigned *num_maps,
+			   const char *group, unsigned long *configs,
+			   unsigned num_configs)
 {
 	unsigned long *dup_configs;
 
-	if (*num_maps == *reserved_maps)
+	if (WARN_ON(*num_maps == *reserved_maps))
 		return -ENOSPC;
 
 	dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
 			      GFP_KERNEL);
-	if (!dup_configs)
+	if (!dup_configs) {
+		dev_err(dev, "kmemdup(configs) failed\n");
 		return -ENOMEM;
+	}
 
 	(*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
 	(*map)[*num_maps].data.configs.group_or_pin = group;
@@ -150,8 +158,8 @@
 	return 0;
 }
 
-static int add_config(unsigned long **configs, unsigned *num_configs,
-		      unsigned long config)
+static int add_config(struct device *dev, unsigned long **configs,
+		      unsigned *num_configs, unsigned long config)
 {
 	unsigned old_num = *num_configs;
 	unsigned new_num = old_num + 1;
@@ -159,8 +167,10 @@
 
 	new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
 			       GFP_KERNEL);
-	if (!new_configs)
+	if (!new_configs) {
+		dev_err(dev, "krealloc(configs) failed\n");
 		return -ENOMEM;
+	}
 
 	new_configs[old_num] = config;
 
@@ -201,7 +211,8 @@
 	{"nvidia,slew-rate-rising",	TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
 };
 
-int tegra_pinctrl_dt_subnode_to_map(struct device_node *np,
+int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
+				    struct device_node *np,
 				    struct pinctrl_map **map,
 				    unsigned *reserved_maps,
 				    unsigned *num_maps)
@@ -217,16 +228,25 @@
 	const char *group;
 
 	ret = of_property_read_string(np, "nvidia,function", &function);
-	if (ret < 0)
+	if (ret < 0) {
+		/* EINVAL=missing, which is fine since it's optional */
+		if (ret != -EINVAL)
+			dev_err(dev,
+				"could not parse property nvidia,function\n");
 		function = NULL;
+	}
 
 	for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
 		ret = of_property_read_u32(np, cfg_params[i].property, &val);
 		if (!ret) {
 			config = TEGRA_PINCONF_PACK(cfg_params[i].param, val);
-			ret = add_config(&configs, &num_configs, config);
+			ret = add_config(dev, &configs, &num_configs, config);
 			if (ret < 0)
 				goto exit;
+		/* EINVAL=missing, which is fine since it's optional */
+		} else if (ret != -EINVAL) {
+			dev_err(dev, "could not parse property %s\n",
+				cfg_params[i].property);
 		}
 	}
 
@@ -236,11 +256,13 @@
 	if (num_configs)
 		reserve++;
 	ret = of_property_count_strings(np, "nvidia,pins");
-	if (ret < 0)
+	if (ret < 0) {
+		dev_err(dev, "could not parse property nvidia,pins\n");
 		goto exit;
+	}
 	reserve *= ret;
 
-	ret = reserve_map(map, reserved_maps, num_maps, reserve);
+	ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
 	if (ret < 0)
 		goto exit;
 
@@ -253,8 +275,9 @@
 		}
 
 		if (num_configs) {
-			ret = add_map_configs(map, reserved_maps, num_maps,
-					      group, configs, num_configs);
+			ret = add_map_configs(dev, map, reserved_maps,
+					      num_maps, group, configs,
+					      num_configs);
 			if (ret < 0)
 				goto exit;
 		}
@@ -280,8 +303,8 @@
 	*num_maps = 0;
 
 	for_each_child_of_node(np_config, np) {
-		ret = tegra_pinctrl_dt_subnode_to_map(np, map, &reserved_maps,
-						      num_maps);
+		ret = tegra_pinctrl_dt_subnode_to_map(pctldev->dev, np, map,
+						      &reserved_maps, num_maps);
 		if (ret < 0) {
 			tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps);
 			return ret;
@@ -295,7 +318,9 @@
 	.get_groups_count = tegra_pinctrl_get_groups_count,
 	.get_group_name = tegra_pinctrl_get_group_name,
 	.get_group_pins = tegra_pinctrl_get_group_pins,
+#ifdef CONFIG_DEBUG_FS
 	.pin_dbg_show = tegra_pinctrl_pin_dbg_show,
+#endif
 	.dt_node_to_map = tegra_pinctrl_dt_node_to_map,
 	.dt_free_map = tegra_pinctrl_dt_free_map,
 };
@@ -338,14 +363,14 @@
 
 	g = &pmx->soc->groups[group];
 
-	if (g->mux_reg < 0)
+	if (WARN_ON(g->mux_reg < 0))
 		return -EINVAL;
 
 	for (i = 0; i < ARRAY_SIZE(g->funcs); i++) {
 		if (g->funcs[i] == function)
 			break;
 	}
-	if (i == ARRAY_SIZE(g->funcs))
+	if (WARN_ON(i == ARRAY_SIZE(g->funcs)))
 		return -EINVAL;
 
 	val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
@@ -365,7 +390,7 @@
 
 	g = &pmx->soc->groups[group];
 
-	if (g->mux_reg < 0)
+	if (WARN_ON(g->mux_reg < 0))
 		return;
 
 	val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
@@ -385,6 +410,7 @@
 static int tegra_pinconf_reg(struct tegra_pmx *pmx,
 			     const struct tegra_pingroup *g,
 			     enum tegra_pinconf_param param,
+			     bool report_err,
 			     s8 *bank, s16 *reg, s8 *bit, s8 *width)
 {
 	switch (param) {
@@ -472,9 +498,10 @@
 	}
 
 	if (*reg < 0) {
-		dev_err(pmx->dev,
-			"Config param %04x not supported on group %s\n",
-			param, g->name);
+		if (report_err)
+			dev_err(pmx->dev,
+				"Config param %04x not supported on group %s\n",
+				param, g->name);
 		return -ENOTSUPP;
 	}
 
@@ -484,12 +511,14 @@
 static int tegra_pinconf_get(struct pinctrl_dev *pctldev,
 			     unsigned pin, unsigned long *config)
 {
+	dev_err(pctldev->dev, "pin_config_get op not supported\n");
 	return -ENOTSUPP;
 }
 
 static int tegra_pinconf_set(struct pinctrl_dev *pctldev,
 			     unsigned pin, unsigned long config)
 {
+	dev_err(pctldev->dev, "pin_config_set op not supported\n");
 	return -ENOTSUPP;
 }
 
@@ -507,7 +536,8 @@
 
 	g = &pmx->soc->groups[group];
 
-	ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+	ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
+				&width);
 	if (ret < 0)
 		return ret;
 
@@ -534,7 +564,8 @@
 
 	g = &pmx->soc->groups[group];
 
-	ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+	ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
+				&width);
 	if (ret < 0)
 		return ret;
 
@@ -542,8 +573,10 @@
 
 	/* LOCK can't be cleared */
 	if (param == TEGRA_PINCONF_PARAM_LOCK) {
-		if ((val & BIT(bit)) && !arg)
+		if ((val & BIT(bit)) && !arg) {
+			dev_err(pctldev->dev, "LOCK bit cannot be cleared\n");
 			return -EINVAL;
+		}
 	}
 
 	/* Special-case Boolean values; allow any non-zero as true */
@@ -552,8 +585,12 @@
 
 	/* Range-check user-supplied value */
 	mask = (1 << width) - 1;
-	if (arg & ~mask)
+	if (arg & ~mask) {
+		dev_err(pctldev->dev,
+			"config %lx: %x too big for %d bit register\n",
+			config, arg, width);
 		return -EINVAL;
+	}
 
 	/* Update register */
 	val &= ~(mask << bit);
@@ -563,23 +600,78 @@
 	return 0;
 }
 
+#ifdef CONFIG_DEBUG_FS
 static void tegra_pinconf_dbg_show(struct pinctrl_dev *pctldev,
 				   struct seq_file *s, unsigned offset)
 {
 }
 
-static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
-					 struct seq_file *s, unsigned selector)
+static const char *strip_prefix(const char *s)
 {
+	const char *comma = strchr(s, ',');
+	if (!comma)
+		return s;
+
+	return comma + 1;
 }
 
+static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+					 struct seq_file *s, unsigned group)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+	const struct tegra_pingroup *g;
+	int i, ret;
+	s8 bank, bit, width;
+	s16 reg;
+	u32 val;
+
+	g = &pmx->soc->groups[group];
+
+	for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
+		ret = tegra_pinconf_reg(pmx, g, cfg_params[i].param, false,
+					&bank, &reg, &bit, &width);
+		if (ret < 0)
+			continue;
+
+		val = pmx_readl(pmx, bank, reg);
+		val >>= bit;
+		val &= (1 << width) - 1;
+
+		seq_printf(s, "\n\t%s=%u",
+			   strip_prefix(cfg_params[i].property), val);
+	}
+}
+
+static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
+					  struct seq_file *s,
+					  unsigned long config)
+{
+	enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config);
+	u16 arg = TEGRA_PINCONF_UNPACK_ARG(config);
+	const char *pname = "unknown";
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
+		if (cfg_params[i].param == param) {
+			pname = cfg_params[i].property;
+			break;
+		}
+	}
+
+	seq_printf(s, "%s=%d", strip_prefix(pname), arg);
+}
+#endif
+
 struct pinconf_ops tegra_pinconf_ops = {
 	.pin_config_get = tegra_pinconf_get,
 	.pin_config_set = tegra_pinconf_set,
 	.pin_config_group_get = tegra_pinconf_group_get,
 	.pin_config_group_set = tegra_pinconf_group_set,
+#ifdef CONFIG_DEBUG_FS
 	.pin_config_dbg_show = tegra_pinconf_dbg_show,
 	.pin_config_group_dbg_show = tegra_pinconf_group_dbg_show,
+	.pin_config_config_dbg_show = tegra_pinconf_config_dbg_show,
+#endif
 };
 
 static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = {
@@ -589,60 +681,29 @@
 };
 
 static struct pinctrl_desc tegra_pinctrl_desc = {
-	.name = DRIVER_NAME,
 	.pctlops = &tegra_pinctrl_ops,
 	.pmxops = &tegra_pinmux_ops,
 	.confops = &tegra_pinconf_ops,
 	.owner = THIS_MODULE,
 };
 
-static struct of_device_id tegra_pinctrl_of_match[] __devinitdata = {
-#ifdef CONFIG_PINCTRL_TEGRA20
-	{
-		.compatible = "nvidia,tegra20-pinmux-disabled",
-		.data = tegra20_pinctrl_init,
-	},
-#endif
-#ifdef CONFIG_PINCTRL_TEGRA30
-	{
-		.compatible = "nvidia,tegra30-pinmux-disabled",
-		.data = tegra30_pinctrl_init,
-	},
-#endif
-	{},
-};
-
-static int __devinit tegra_pinctrl_probe(struct platform_device *pdev)
+int __devinit tegra_pinctrl_probe(struct platform_device *pdev,
+			const struct tegra_pinctrl_soc_data *soc_data)
 {
-	const struct of_device_id *match;
-	tegra_pinctrl_soc_initf initf = NULL;
 	struct tegra_pmx *pmx;
 	struct resource *res;
 	int i;
 
-	match = of_match_device(tegra_pinctrl_of_match, &pdev->dev);
-	if (match)
-		initf = (tegra_pinctrl_soc_initf)match->data;
-#ifdef CONFIG_PINCTRL_TEGRA20
-	if (!initf)
-		initf = tegra20_pinctrl_init;
-#endif
-	if (!initf) {
-		dev_err(&pdev->dev,
-			"Could not determine SoC-specific init func\n");
-		return -EINVAL;
-	}
-
 	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
 	if (!pmx) {
 		dev_err(&pdev->dev, "Can't alloc tegra_pmx\n");
 		return -ENOMEM;
 	}
 	pmx->dev = &pdev->dev;
-
-	(*initf)(&pmx->soc);
+	pmx->soc = soc_data;
 
 	tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios;
+	tegra_pinctrl_desc.name = dev_name(&pdev->dev);
 	tegra_pinctrl_desc.pins = pmx->soc->pins;
 	tegra_pinctrl_desc.npins = pmx->soc->npins;
 
@@ -697,8 +758,9 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(tegra_pinctrl_probe);
 
-static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
+int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
 {
 	struct tegra_pmx *pmx = platform_get_drvdata(pdev);
 
@@ -707,30 +769,4 @@
 
 	return 0;
 }
-
-static struct platform_driver tegra_pinctrl_driver = {
-	.driver = {
-		.name = DRIVER_NAME,
-		.owner = THIS_MODULE,
-		.of_match_table = tegra_pinctrl_of_match,
-	},
-	.probe = tegra_pinctrl_probe,
-	.remove = __devexit_p(tegra_pinctrl_remove),
-};
-
-static int __init tegra_pinctrl_init(void)
-{
-	return platform_driver_register(&tegra_pinctrl_driver);
-}
-arch_initcall(tegra_pinctrl_init);
-
-static void __exit tegra_pinctrl_exit(void)
-{
-	platform_driver_unregister(&tegra_pinctrl_driver);
-}
-module_exit(tegra_pinctrl_exit);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("NVIDIA Tegra pinctrl driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, tegra_pinctrl_of_match);
+EXPORT_SYMBOL_GPL(tegra_pinctrl_remove);
diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/pinctrl-tegra.h
index 782c795..705c007 100644
--- a/drivers/pinctrl/pinctrl-tegra.h
+++ b/drivers/pinctrl/pinctrl-tegra.h
@@ -139,25 +139,8 @@
 	unsigned ngroups;
 };
 
-/**
- * tegra_pinctrl_soc_initf() - Retrieve pin controller details for a SoC.
- * @soc_data:	This pointer must be updated to point at a struct containing
- *		details of the SoC.
- */
-typedef void (*tegra_pinctrl_soc_initf)(
-			const struct tegra_pinctrl_soc_data **soc_data);
-
-/**
- * tegra20_pinctrl_init() - Retrieve pin controller details for Tegra20
- * @soc_data:	This pointer will be updated to point at a struct containing
- *		details of Tegra20's pin controller.
- */
-void tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
-/**
- * tegra30_pinctrl_init() - Retrieve pin controller details for Tegra20
- * @soc_data:	This pointer will be updated to point at a struct containing
- *		details of Tegra30's pin controller.
- */
-void tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
+int tegra_pinctrl_probe(struct platform_device *pdev,
+			const struct tegra_pinctrl_soc_data *soc_data);
+int tegra_pinctrl_remove(struct platform_device *pdev);
 
 #endif
diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c
index f69ff96..a74f9a5 100644
--- a/drivers/pinctrl/pinctrl-tegra20.c
+++ b/drivers/pinctrl/pinctrl-tegra20.c
@@ -1,7 +1,7 @@
 /*
  * Pinctrl data for the NVIDIA Tegra20 pinmux
  *
- * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
  *
  * Derived from code:
  * Copyright (C) 2010 Google, Inc.
@@ -17,6 +17,8 @@
  * more details.
  */
 
+#include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
@@ -2854,7 +2856,39 @@
 	.ngroups = ARRAY_SIZE(tegra20_groups),
 };
 
-void __devinit tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc)
+static int __devinit tegra20_pinctrl_probe(struct platform_device *pdev)
 {
-	*soc = &tegra20_pinctrl;
+	return tegra_pinctrl_probe(pdev, &tegra20_pinctrl);
 }
+
+static struct of_device_id tegra20_pinctrl_of_match[] __devinitdata = {
+	{ .compatible = "nvidia,tegra20-pinmux", },
+	{ },
+};
+
+static struct platform_driver tegra20_pinctrl_driver = {
+	.driver = {
+		.name = "tegra20-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = tegra20_pinctrl_of_match,
+	},
+	.probe = tegra20_pinctrl_probe,
+	.remove = __devexit_p(tegra_pinctrl_remove),
+};
+
+static int __init tegra20_pinctrl_init(void)
+{
+	return platform_driver_register(&tegra20_pinctrl_driver);
+}
+arch_initcall(tegra20_pinctrl_init);
+
+static void __exit tegra20_pinctrl_exit(void)
+{
+	platform_driver_unregister(&tegra20_pinctrl_driver);
+}
+module_exit(tegra20_pinctrl_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra20 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, tegra20_pinctrl_of_match);
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c
index 4d7571d..0386fdf 100644
--- a/drivers/pinctrl/pinctrl-tegra30.c
+++ b/drivers/pinctrl/pinctrl-tegra30.c
@@ -1,7 +1,7 @@
 /*
  * Pinctrl data for the NVIDIA Tegra30 pinmux
  *
- * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -13,6 +13,8 @@
  * more details.
  */
 
+#include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
@@ -3720,7 +3722,39 @@
 	.ngroups = ARRAY_SIZE(tegra30_groups),
 };
 
-void __devinit tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc)
+static int __devinit tegra30_pinctrl_probe(struct platform_device *pdev)
 {
-	*soc = &tegra30_pinctrl;
+	return tegra_pinctrl_probe(pdev, &tegra30_pinctrl);
 }
+
+static struct of_device_id tegra30_pinctrl_of_match[] __devinitdata = {
+	{ .compatible = "nvidia,tegra30-pinmux", },
+	{ },
+};
+
+static struct platform_driver tegra30_pinctrl_driver = {
+	.driver = {
+		.name = "tegra30-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = tegra30_pinctrl_of_match,
+	},
+	.probe = tegra30_pinctrl_probe,
+	.remove = __devexit_p(tegra_pinctrl_remove),
+};
+
+static int __init tegra30_pinctrl_init(void)
+{
+	return platform_driver_register(&tegra30_pinctrl_driver);
+}
+arch_initcall(tegra30_pinctrl_init);
+
+static void __exit tegra30_pinctrl_exit(void)
+{
+	platform_driver_unregister(&tegra30_pinctrl_driver);
+}
+module_exit(tegra30_pinctrl_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra30 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig
new file mode 100644
index 0000000..6a2596b
--- /dev/null
+++ b/drivers/pinctrl/spear/Kconfig
@@ -0,0 +1,34 @@
+#
+# ST Microelectronics SPEAr PINCTRL drivers
+#
+
+if PLAT_SPEAR
+
+config PINCTRL_SPEAR
+	bool
+	depends on OF
+	select PINMUX
+	help
+	  This enables pin control drivers for SPEAr Platform
+
+config PINCTRL_SPEAR3XX
+	bool
+	depends on ARCH_SPEAR3XX
+	select PINCTRL_SPEAR
+
+config PINCTRL_SPEAR300
+	bool "ST Microelectronics SPEAr300 SoC pin controller driver"
+	depends on MACH_SPEAR300
+	select PINCTRL_SPEAR3XX
+
+config PINCTRL_SPEAR310
+	bool "ST Microelectronics SPEAr310 SoC pin controller driver"
+	depends on MACH_SPEAR310
+	select PINCTRL_SPEAR3XX
+
+config PINCTRL_SPEAR320
+	bool "ST Microelectronics SPEAr320 SoC pin controller driver"
+	depends on MACH_SPEAR320
+	select PINCTRL_SPEAR3XX
+
+endif
diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile
new file mode 100644
index 0000000..15dcb85
--- /dev/null
+++ b/drivers/pinctrl/spear/Makefile
@@ -0,0 +1,7 @@
+# SPEAr pinmux support
+
+obj-$(CONFIG_PINCTRL_SPEAR)	+= pinctrl-spear.o
+obj-$(CONFIG_PINCTRL_SPEAR3XX)	+= pinctrl-spear3xx.o
+obj-$(CONFIG_PINCTRL_SPEAR300)	+= pinctrl-spear300.o
+obj-$(CONFIG_PINCTRL_SPEAR310)	+= pinctrl-spear310.o
+obj-$(CONFIG_PINCTRL_SPEAR320)	+= pinctrl-spear320.o
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
new file mode 100644
index 0000000..5ae50aa
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -0,0 +1,354 @@
+/*
+ * Driver for the ST Microelectronics SPEAr pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * Inspired from:
+ * - U300 Pinctl drivers
+ * - Tegra Pinctl drivers
+ *
+ * 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/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pinctrl-spear.h"
+
+#define DRIVER_NAME "spear-pinmux"
+
+static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg)
+{
+	return readl_relaxed(pmx->vbase + reg);
+}
+
+static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
+{
+	writel_relaxed(val, pmx->vbase + reg);
+}
+
+static int set_mode(struct spear_pmx *pmx, int mode)
+{
+	struct spear_pmx_mode *pmx_mode = NULL;
+	int i;
+	u32 val;
+
+	if (!pmx->machdata->pmx_modes || !pmx->machdata->npmx_modes)
+		return -EINVAL;
+
+	for (i = 0; i < pmx->machdata->npmx_modes; i++) {
+		if (pmx->machdata->pmx_modes[i]->mode == (1 << mode)) {
+			pmx_mode = pmx->machdata->pmx_modes[i];
+			break;
+		}
+	}
+
+	if (!pmx_mode)
+		return -EINVAL;
+
+	val = pmx_readl(pmx, pmx_mode->reg);
+	val &= ~pmx_mode->mask;
+	val |= pmx_mode->val;
+	pmx_writel(pmx, val, pmx_mode->reg);
+
+	pmx->machdata->mode = pmx_mode->mode;
+	dev_info(pmx->dev, "Configured Mode: %s with id: %x\n\n",
+			pmx_mode->name ? pmx_mode->name : "no_name",
+			pmx_mode->reg);
+
+	return 0;
+}
+
+void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
+{
+	struct spear_pingroup *pgroup;
+	struct spear_modemux *modemux;
+	int i, j, group;
+
+	for (group = 0; group < machdata->ngroups; group++) {
+		pgroup = machdata->groups[group];
+
+		for (i = 0; i < pgroup->nmodemuxs; i++) {
+			modemux = &pgroup->modemuxs[i];
+
+			for (j = 0; j < modemux->nmuxregs; j++)
+				if (modemux->muxregs[j].reg == 0xFFFF)
+					modemux->muxregs[j].reg = reg;
+		}
+	}
+}
+
+static int spear_pinctrl_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	return pmx->machdata->ngroups;
+}
+
+static const char *spear_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+		unsigned group)
+{
+	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	return pmx->machdata->groups[group]->name;
+}
+
+static int spear_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+		unsigned group, const unsigned **pins, unsigned *num_pins)
+{
+	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = pmx->machdata->groups[group]->pins;
+	*num_pins = pmx->machdata->groups[group]->npins;
+
+	return 0;
+}
+
+static void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+		struct seq_file *s, unsigned offset)
+{
+	seq_printf(s, " " DRIVER_NAME);
+}
+
+int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+				 struct device_node *np_config,
+				 struct pinctrl_map **map, unsigned *num_maps)
+{
+	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+	struct device_node *np;
+	struct property *prop;
+	const char *function, *group;
+	int ret, index = 0, count = 0;
+
+	/* calculate number of maps required */
+	for_each_child_of_node(np_config, np) {
+		ret = of_property_read_string(np, "st,function", &function);
+		if (ret < 0)
+			return ret;
+
+		ret = of_property_count_strings(np, "st,pins");
+		if (ret < 0)
+			return ret;
+
+		count += ret;
+	}
+
+	if (!count) {
+		dev_err(pmx->dev, "No child nodes passed via DT\n");
+		return -ENODEV;
+	}
+
+	*map = kzalloc(sizeof(**map) * count, GFP_KERNEL);
+	if (!*map)
+		return -ENOMEM;
+
+	for_each_child_of_node(np_config, np) {
+		of_property_read_string(np, "st,function", &function);
+		of_property_for_each_string(np, "st,pins", prop, group) {
+			(*map)[index].type = PIN_MAP_TYPE_MUX_GROUP;
+			(*map)[index].data.mux.group = group;
+			(*map)[index].data.mux.function = function;
+			index++;
+		}
+	}
+
+	*num_maps = count;
+
+	return 0;
+}
+
+void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+		struct pinctrl_map *map, unsigned num_maps)
+{
+	kfree(map);
+}
+
+static struct pinctrl_ops spear_pinctrl_ops = {
+	.get_groups_count = spear_pinctrl_get_groups_cnt,
+	.get_group_name = spear_pinctrl_get_group_name,
+	.get_group_pins = spear_pinctrl_get_group_pins,
+	.pin_dbg_show = spear_pinctrl_pin_dbg_show,
+	.dt_node_to_map = spear_pinctrl_dt_node_to_map,
+	.dt_free_map = spear_pinctrl_dt_free_map,
+};
+
+static int spear_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	return pmx->machdata->nfunctions;
+}
+
+static const char *spear_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+		unsigned function)
+{
+	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	return pmx->machdata->functions[function]->name;
+}
+
+static int spear_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+		unsigned function, const char *const **groups,
+		unsigned * const ngroups)
+{
+	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pmx->machdata->functions[function]->groups;
+	*ngroups = pmx->machdata->functions[function]->ngroups;
+
+	return 0;
+}
+
+static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
+		unsigned function, unsigned group, bool enable)
+{
+	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+	const struct spear_pingroup *pgroup;
+	const struct spear_modemux *modemux;
+	struct spear_muxreg *muxreg;
+	u32 val, temp;
+	int i, j;
+	bool found = false;
+
+	pgroup = pmx->machdata->groups[group];
+
+	for (i = 0; i < pgroup->nmodemuxs; i++) {
+		modemux = &pgroup->modemuxs[i];
+
+		/* SoC have any modes */
+		if (pmx->machdata->modes_supported) {
+			if (!(pmx->machdata->mode & modemux->modes))
+				continue;
+		}
+
+		found = true;
+		for (j = 0; j < modemux->nmuxregs; j++) {
+			muxreg = &modemux->muxregs[j];
+
+			val = pmx_readl(pmx, muxreg->reg);
+			val &= ~muxreg->mask;
+
+			if (enable)
+				temp = muxreg->val;
+			else
+				temp = ~muxreg->val;
+
+			val |= temp;
+			pmx_writel(pmx, val, muxreg->reg);
+		}
+	}
+
+	if (!found) {
+		dev_err(pmx->dev, "pinmux group: %s not supported\n",
+				pgroup->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int spear_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
+		unsigned group)
+{
+	return spear_pinctrl_endisable(pctldev, function, group, true);
+}
+
+static void spear_pinctrl_disable(struct pinctrl_dev *pctldev,
+		unsigned function, unsigned group)
+{
+	spear_pinctrl_endisable(pctldev, function, group, false);
+}
+
+static struct pinmux_ops spear_pinmux_ops = {
+	.get_functions_count = spear_pinctrl_get_funcs_count,
+	.get_function_name = spear_pinctrl_get_func_name,
+	.get_function_groups = spear_pinctrl_get_func_groups,
+	.enable = spear_pinctrl_enable,
+	.disable = spear_pinctrl_disable,
+};
+
+static struct pinctrl_desc spear_pinctrl_desc = {
+	.name = DRIVER_NAME,
+	.pctlops = &spear_pinctrl_ops,
+	.pmxops = &spear_pinmux_ops,
+	.owner = THIS_MODULE,
+};
+
+int __devinit spear_pinctrl_probe(struct platform_device *pdev,
+		struct spear_pinctrl_machdata *machdata)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
+	struct spear_pmx *pmx;
+
+	if (!machdata)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
+	if (!pmx) {
+		dev_err(&pdev->dev, "Can't alloc spear_pmx\n");
+		return -ENOMEM;
+	}
+
+	pmx->vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!pmx->vbase) {
+		dev_err(&pdev->dev, "Couldn't ioremap at index 0\n");
+		return -ENODEV;
+	}
+
+	pmx->dev = &pdev->dev;
+	pmx->machdata = machdata;
+
+	/* configure mode, if supported by SoC */
+	if (machdata->modes_supported) {
+		int mode = 0;
+
+		if (of_property_read_u32(np, "st,pinmux-mode", &mode)) {
+			dev_err(&pdev->dev, "OF: pinmux mode not passed\n");
+			return -EINVAL;
+		}
+
+		if (set_mode(pmx, mode)) {
+			dev_err(&pdev->dev, "OF: Couldn't configure mode: %x\n",
+					mode);
+			return -EINVAL;
+		}
+	}
+
+	platform_set_drvdata(pdev, pmx);
+
+	spear_pinctrl_desc.pins = machdata->pins;
+	spear_pinctrl_desc.npins = machdata->npins;
+
+	pmx->pctl = pinctrl_register(&spear_pinctrl_desc, &pdev->dev, pmx);
+	if (IS_ERR(pmx->pctl)) {
+		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+		return PTR_ERR(pmx->pctl);
+	}
+
+	return 0;
+}
+
+int __devexit spear_pinctrl_remove(struct platform_device *pdev)
+{
+	struct spear_pmx *pmx = platform_get_drvdata(pdev);
+
+	pinctrl_unregister(pmx->pctl);
+
+	return 0;
+}
diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h
new file mode 100644
index 0000000..47a6b5b
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear.h
@@ -0,0 +1,142 @@
+/*
+ * Driver header file for the ST Microelectronics SPEAr pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * 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 __PINMUX_SPEAR_H__
+#define __PINMUX_SPEAR_H__
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/types.h>
+
+struct platform_device;
+struct device;
+
+/**
+ * struct spear_pmx_mode - SPEAr pmx mode
+ * @name: name of pmx mode
+ * @mode: mode id
+ * @reg: register for configuring this mode
+ * @mask: mask of this mode in reg
+ * @val: val to be configured at reg after doing (val & mask)
+ */
+struct spear_pmx_mode {
+	const char *const name;
+	u16 mode;
+	u16 reg;
+	u16 mask;
+	u32 val;
+};
+
+/**
+ * struct spear_muxreg - SPEAr mux reg configuration
+ * @reg: register offset
+ * @mask: mask bits
+ * @val: val to be written on mask bits
+ */
+struct spear_muxreg {
+	u16 reg;
+	u32 mask;
+	u32 val;
+};
+
+/**
+ * struct spear_modemux - SPEAr mode mux configuration
+ * @modes: mode ids supported by this group of muxregs
+ * @nmuxregs: number of muxreg configurations to be done for modes
+ * @muxregs: array of muxreg configurations to be done for modes
+ */
+struct spear_modemux {
+	u16 modes;
+	u8 nmuxregs;
+	struct spear_muxreg *muxregs;
+};
+
+/**
+ * struct spear_pingroup - SPEAr pin group configurations
+ * @name: name of pin group
+ * @pins: array containing pin numbers
+ * @npins: size of pins array
+ * @modemuxs: array of modemux configurations for this pin group
+ * @nmodemuxs: size of array modemuxs
+ *
+ * A representation of a group of pins in the SPEAr pin controller. Each group
+ * allows some parameter or parameters to be configured.
+ */
+struct spear_pingroup {
+	const char *name;
+	const unsigned *pins;
+	unsigned npins;
+	struct spear_modemux *modemuxs;
+	unsigned nmodemuxs;
+};
+
+/**
+ * struct spear_function - SPEAr pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct spear_function {
+	const char *name;
+	const char *const *groups;
+	unsigned ngroups;
+};
+
+/**
+ * struct spear_pinctrl_machdata - SPEAr pin controller machine driver
+ *	configuration
+ * @pins: An array describing all pins the pin controller affects.
+ *	All pins which are also GPIOs must be listed first within the *array,
+ *	and be numbered identically to the GPIO controller's *numbering.
+ * @npins: The numbmer of entries in @pins.
+ * @functions: An array describing all mux functions the SoC supports.
+ * @nfunctions: The numbmer of entries in @functions.
+ * @groups: An array describing all pin groups the pin SoC supports.
+ * @ngroups: The numbmer of entries in @groups.
+ *
+ * @modes_supported: Does SoC support modes
+ * @mode: mode configured from probe
+ * @pmx_modes: array of modes supported by SoC
+ * @npmx_modes: number of entries in pmx_modes.
+ */
+struct spear_pinctrl_machdata {
+	const struct pinctrl_pin_desc *pins;
+	unsigned npins;
+	struct spear_function **functions;
+	unsigned nfunctions;
+	struct spear_pingroup **groups;
+	unsigned ngroups;
+
+	bool modes_supported;
+	u16 mode;
+	struct spear_pmx_mode **pmx_modes;
+	unsigned npmx_modes;
+};
+
+/**
+ * struct spear_pmx - SPEAr pinctrl mux
+ * @dev: pointer to struct dev of platform_device registered
+ * @pctl: pointer to struct pinctrl_dev
+ * @machdata: pointer to SoC or machine specific structure
+ * @vbase: virtual base address of pinmux controller
+ */
+struct spear_pmx {
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+	struct spear_pinctrl_machdata *machdata;
+	void __iomem *vbase;
+};
+
+/* exported routines */
+void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg);
+int __devinit spear_pinctrl_probe(struct platform_device *pdev,
+		struct spear_pinctrl_machdata *machdata);
+int __devexit spear_pinctrl_remove(struct platform_device *pdev);
+#endif /* __PINMUX_SPEAR_H__ */
diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c
new file mode 100644
index 0000000..9c82a35
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear300.c
@@ -0,0 +1,708 @@
+/*
+ * Driver for the ST Microelectronics SPEAr300 pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * 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/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "pinctrl-spear3xx.h"
+
+#define DRIVER_NAME "spear300-pinmux"
+
+/* addresses */
+#define PMX_CONFIG_REG			0x00
+#define MODE_CONFIG_REG			0x04
+
+/* modes */
+#define NAND_MODE			(1 << 0)
+#define NOR_MODE			(1 << 1)
+#define PHOTO_FRAME_MODE		(1 << 2)
+#define LEND_IP_PHONE_MODE		(1 << 3)
+#define HEND_IP_PHONE_MODE		(1 << 4)
+#define LEND_WIFI_PHONE_MODE		(1 << 5)
+#define HEND_WIFI_PHONE_MODE		(1 << 6)
+#define ATA_PABX_WI2S_MODE		(1 << 7)
+#define ATA_PABX_I2S_MODE		(1 << 8)
+#define CAML_LCDW_MODE			(1 << 9)
+#define CAMU_LCD_MODE			(1 << 10)
+#define CAMU_WLCD_MODE			(1 << 11)
+#define CAML_LCD_MODE			(1 << 12)
+
+static struct spear_pmx_mode pmx_mode_nand = {
+	.name = "nand",
+	.mode = NAND_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x00,
+};
+
+static struct spear_pmx_mode pmx_mode_nor = {
+	.name = "nor",
+	.mode = NOR_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x01,
+};
+
+static struct spear_pmx_mode pmx_mode_photo_frame = {
+	.name = "photo frame mode",
+	.mode = PHOTO_FRAME_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x02,
+};
+
+static struct spear_pmx_mode pmx_mode_lend_ip_phone = {
+	.name = "lend ip phone mode",
+	.mode = LEND_IP_PHONE_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x03,
+};
+
+static struct spear_pmx_mode pmx_mode_hend_ip_phone = {
+	.name = "hend ip phone mode",
+	.mode = HEND_IP_PHONE_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x04,
+};
+
+static struct spear_pmx_mode pmx_mode_lend_wifi_phone = {
+	.name = "lend wifi phone mode",
+	.mode = LEND_WIFI_PHONE_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x05,
+};
+
+static struct spear_pmx_mode pmx_mode_hend_wifi_phone = {
+	.name = "hend wifi phone mode",
+	.mode = HEND_WIFI_PHONE_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x06,
+};
+
+static struct spear_pmx_mode pmx_mode_ata_pabx_wi2s = {
+	.name = "ata pabx wi2s mode",
+	.mode = ATA_PABX_WI2S_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x07,
+};
+
+static struct spear_pmx_mode pmx_mode_ata_pabx_i2s = {
+	.name = "ata pabx i2s mode",
+	.mode = ATA_PABX_I2S_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x08,
+};
+
+static struct spear_pmx_mode pmx_mode_caml_lcdw = {
+	.name = "caml lcdw mode",
+	.mode = CAML_LCDW_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x0C,
+};
+
+static struct spear_pmx_mode pmx_mode_camu_lcd = {
+	.name = "camu lcd mode",
+	.mode = CAMU_LCD_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x0D,
+};
+
+static struct spear_pmx_mode pmx_mode_camu_wlcd = {
+	.name = "camu wlcd mode",
+	.mode = CAMU_WLCD_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0xE,
+};
+
+static struct spear_pmx_mode pmx_mode_caml_lcd = {
+	.name = "caml lcd mode",
+	.mode = CAML_LCD_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x0000000F,
+	.val = 0x0F,
+};
+
+static struct spear_pmx_mode *spear300_pmx_modes[] = {
+	&pmx_mode_nand,
+	&pmx_mode_nor,
+	&pmx_mode_photo_frame,
+	&pmx_mode_lend_ip_phone,
+	&pmx_mode_hend_ip_phone,
+	&pmx_mode_lend_wifi_phone,
+	&pmx_mode_hend_wifi_phone,
+	&pmx_mode_ata_pabx_wi2s,
+	&pmx_mode_ata_pabx_i2s,
+	&pmx_mode_caml_lcdw,
+	&pmx_mode_camu_lcd,
+	&pmx_mode_camu_wlcd,
+	&pmx_mode_caml_lcd,
+};
+
+/* fsmc_2chips_pins */
+static const unsigned fsmc_2chips_pins[] = { 1, 97 };
+static struct spear_muxreg fsmc_2chips_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_FIRDA_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux fsmc_2chips_modemux[] = {
+	{
+		.modes = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
+			ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
+		.muxregs = fsmc_2chips_muxreg,
+		.nmuxregs = ARRAY_SIZE(fsmc_2chips_muxreg),
+	},
+};
+
+static struct spear_pingroup fsmc_2chips_pingroup = {
+	.name = "fsmc_2chips_grp",
+	.pins = fsmc_2chips_pins,
+	.npins = ARRAY_SIZE(fsmc_2chips_pins),
+	.modemuxs = fsmc_2chips_modemux,
+	.nmodemuxs = ARRAY_SIZE(fsmc_2chips_modemux),
+};
+
+/* fsmc_4chips_pins */
+static const unsigned fsmc_4chips_pins[] = { 1, 2, 3, 97 };
+static struct spear_muxreg fsmc_4chips_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_FIRDA_MASK | PMX_UART0_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux fsmc_4chips_modemux[] = {
+	{
+		.modes = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
+			ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
+		.muxregs = fsmc_4chips_muxreg,
+		.nmuxregs = ARRAY_SIZE(fsmc_4chips_muxreg),
+	},
+};
+
+static struct spear_pingroup fsmc_4chips_pingroup = {
+	.name = "fsmc_4chips_grp",
+	.pins = fsmc_4chips_pins,
+	.npins = ARRAY_SIZE(fsmc_4chips_pins),
+	.modemuxs = fsmc_4chips_modemux,
+	.nmodemuxs = ARRAY_SIZE(fsmc_4chips_modemux),
+};
+
+static const char *const fsmc_grps[] = { "fsmc_2chips_grp", "fsmc_4chips_grp"
+};
+static struct spear_function fsmc_function = {
+	.name = "fsmc",
+	.groups = fsmc_grps,
+	.ngroups = ARRAY_SIZE(fsmc_grps),
+};
+
+/* clcd_lcdmode_pins */
+static const unsigned clcd_lcdmode_pins[] = { 49, 50 };
+static struct spear_muxreg clcd_lcdmode_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux clcd_lcdmode_modemux[] = {
+	{
+		.modes = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE |
+			CAMU_LCD_MODE | CAML_LCD_MODE,
+		.muxregs = clcd_lcdmode_muxreg,
+		.nmuxregs = ARRAY_SIZE(clcd_lcdmode_muxreg),
+	},
+};
+
+static struct spear_pingroup clcd_lcdmode_pingroup = {
+	.name = "clcd_lcdmode_grp",
+	.pins = clcd_lcdmode_pins,
+	.npins = ARRAY_SIZE(clcd_lcdmode_pins),
+	.modemuxs = clcd_lcdmode_modemux,
+	.nmodemuxs = ARRAY_SIZE(clcd_lcdmode_modemux),
+};
+
+/* clcd_pfmode_pins */
+static const unsigned clcd_pfmode_pins[] = { 47, 48, 49, 50 };
+static struct spear_muxreg clcd_pfmode_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_2_3_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux clcd_pfmode_modemux[] = {
+	{
+		.modes = PHOTO_FRAME_MODE,
+		.muxregs = clcd_pfmode_muxreg,
+		.nmuxregs = ARRAY_SIZE(clcd_pfmode_muxreg),
+	},
+};
+
+static struct spear_pingroup clcd_pfmode_pingroup = {
+	.name = "clcd_pfmode_grp",
+	.pins = clcd_pfmode_pins,
+	.npins = ARRAY_SIZE(clcd_pfmode_pins),
+	.modemuxs = clcd_pfmode_modemux,
+	.nmodemuxs = ARRAY_SIZE(clcd_pfmode_modemux),
+};
+
+static const char *const clcd_grps[] = { "clcd_lcdmode_grp", "clcd_pfmode_grp"
+};
+static struct spear_function clcd_function = {
+	.name = "clcd",
+	.groups = clcd_grps,
+	.ngroups = ARRAY_SIZE(clcd_grps),
+};
+
+/* tdm_pins */
+static const unsigned tdm_pins[] = { 34, 35, 36, 37, 38 };
+static struct spear_muxreg tdm_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux tdm_modemux[] = {
+	{
+		.modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
+			HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE
+			| HEND_WIFI_PHONE_MODE | ATA_PABX_WI2S_MODE
+			| ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
+			| CAMU_WLCD_MODE | CAML_LCD_MODE,
+		.muxregs = tdm_muxreg,
+		.nmuxregs = ARRAY_SIZE(tdm_muxreg),
+	},
+};
+
+static struct spear_pingroup tdm_pingroup = {
+	.name = "tdm_grp",
+	.pins = tdm_pins,
+	.npins = ARRAY_SIZE(tdm_pins),
+	.modemuxs = tdm_modemux,
+	.nmodemuxs = ARRAY_SIZE(tdm_modemux),
+};
+
+static const char *const tdm_grps[] = { "tdm_grp" };
+static struct spear_function tdm_function = {
+	.name = "tdm",
+	.groups = tdm_grps,
+	.ngroups = ARRAY_SIZE(tdm_grps),
+};
+
+/* i2c_clk_pins */
+static const unsigned i2c_clk_pins[] = { 45, 46, 47, 48 };
+static struct spear_muxreg i2c_clk_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux i2c_clk_modemux[] = {
+	{
+		.modes = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE |
+			LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
+			ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE | CAML_LCDW_MODE
+			| CAML_LCD_MODE,
+		.muxregs = i2c_clk_muxreg,
+		.nmuxregs = ARRAY_SIZE(i2c_clk_muxreg),
+	},
+};
+
+static struct spear_pingroup i2c_clk_pingroup = {
+	.name = "i2c_clk_grp_grp",
+	.pins = i2c_clk_pins,
+	.npins = ARRAY_SIZE(i2c_clk_pins),
+	.modemuxs = i2c_clk_modemux,
+	.nmodemuxs = ARRAY_SIZE(i2c_clk_modemux),
+};
+
+static const char *const i2c_grps[] = { "i2c_clk_grp" };
+static struct spear_function i2c_function = {
+	.name = "i2c1",
+	.groups = i2c_grps,
+	.ngroups = ARRAY_SIZE(i2c_grps),
+};
+
+/* caml_pins */
+static const unsigned caml_pins[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 };
+static struct spear_muxreg caml_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux caml_modemux[] = {
+	{
+		.modes = CAML_LCDW_MODE | CAML_LCD_MODE,
+		.muxregs = caml_muxreg,
+		.nmuxregs = ARRAY_SIZE(caml_muxreg),
+	},
+};
+
+static struct spear_pingroup caml_pingroup = {
+	.name = "caml_grp",
+	.pins = caml_pins,
+	.npins = ARRAY_SIZE(caml_pins),
+	.modemuxs = caml_modemux,
+	.nmodemuxs = ARRAY_SIZE(caml_modemux),
+};
+
+/* camu_pins */
+static const unsigned camu_pins[] = { 16, 17, 18, 19, 20, 21, 45, 46, 47, 48 };
+static struct spear_muxreg camu_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK | PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux camu_modemux[] = {
+	{
+		.modes = CAMU_LCD_MODE | CAMU_WLCD_MODE,
+		.muxregs = camu_muxreg,
+		.nmuxregs = ARRAY_SIZE(camu_muxreg),
+	},
+};
+
+static struct spear_pingroup camu_pingroup = {
+	.name = "camu_grp",
+	.pins = camu_pins,
+	.npins = ARRAY_SIZE(camu_pins),
+	.modemuxs = camu_modemux,
+	.nmodemuxs = ARRAY_SIZE(camu_modemux),
+};
+
+static const char *const cam_grps[] = { "caml_grp", "camu_grp" };
+static struct spear_function cam_function = {
+	.name = "cam",
+	.groups = cam_grps,
+	.ngroups = ARRAY_SIZE(cam_grps),
+};
+
+/* dac_pins */
+static const unsigned dac_pins[] = { 43, 44 };
+static struct spear_muxreg dac_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux dac_modemux[] = {
+	{
+		.modes = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
+			| CAMU_WLCD_MODE | CAML_LCD_MODE,
+		.muxregs = dac_muxreg,
+		.nmuxregs = ARRAY_SIZE(dac_muxreg),
+	},
+};
+
+static struct spear_pingroup dac_pingroup = {
+	.name = "dac_grp",
+	.pins = dac_pins,
+	.npins = ARRAY_SIZE(dac_pins),
+	.modemuxs = dac_modemux,
+	.nmodemuxs = ARRAY_SIZE(dac_modemux),
+};
+
+static const char *const dac_grps[] = { "dac_grp" };
+static struct spear_function dac_function = {
+	.name = "dac",
+	.groups = dac_grps,
+	.ngroups = ARRAY_SIZE(dac_grps),
+};
+
+/* i2s_pins */
+static const unsigned i2s_pins[] = { 39, 40, 41, 42 };
+static struct spear_muxreg i2s_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux i2s_modemux[] = {
+	{
+		.modes = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE
+			| LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
+			ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
+			| CAMU_WLCD_MODE | CAML_LCD_MODE,
+		.muxregs = i2s_muxreg,
+		.nmuxregs = ARRAY_SIZE(i2s_muxreg),
+	},
+};
+
+static struct spear_pingroup i2s_pingroup = {
+	.name = "i2s_grp",
+	.pins = i2s_pins,
+	.npins = ARRAY_SIZE(i2s_pins),
+	.modemuxs = i2s_modemux,
+	.nmodemuxs = ARRAY_SIZE(i2s_modemux),
+};
+
+static const char *const i2s_grps[] = { "i2s_grp" };
+static struct spear_function i2s_function = {
+	.name = "i2s",
+	.groups = i2s_grps,
+	.ngroups = ARRAY_SIZE(i2s_grps),
+};
+
+/* sdhci_4bit_pins */
+static const unsigned sdhci_4bit_pins[] = { 28, 29, 30, 31, 32, 33 };
+static struct spear_muxreg sdhci_4bit_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
+			PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
+			PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux sdhci_4bit_modemux[] = {
+	{
+		.modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
+			HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
+			HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
+			CAMU_WLCD_MODE | CAML_LCD_MODE | ATA_PABX_WI2S_MODE,
+		.muxregs = sdhci_4bit_muxreg,
+		.nmuxregs = ARRAY_SIZE(sdhci_4bit_muxreg),
+	},
+};
+
+static struct spear_pingroup sdhci_4bit_pingroup = {
+	.name = "sdhci_4bit_grp",
+	.pins = sdhci_4bit_pins,
+	.npins = ARRAY_SIZE(sdhci_4bit_pins),
+	.modemuxs = sdhci_4bit_modemux,
+	.nmodemuxs = ARRAY_SIZE(sdhci_4bit_modemux),
+};
+
+/* sdhci_8bit_pins */
+static const unsigned sdhci_8bit_pins[] = { 24, 25, 26, 27, 28, 29, 30, 31, 32,
+	33 };
+static struct spear_muxreg sdhci_8bit_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
+			PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
+			PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK | PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux sdhci_8bit_modemux[] = {
+	{
+		.modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
+			HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
+			HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
+			CAMU_WLCD_MODE | CAML_LCD_MODE,
+		.muxregs = sdhci_8bit_muxreg,
+		.nmuxregs = ARRAY_SIZE(sdhci_8bit_muxreg),
+	},
+};
+
+static struct spear_pingroup sdhci_8bit_pingroup = {
+	.name = "sdhci_8bit_grp",
+	.pins = sdhci_8bit_pins,
+	.npins = ARRAY_SIZE(sdhci_8bit_pins),
+	.modemuxs = sdhci_8bit_modemux,
+	.nmodemuxs = ARRAY_SIZE(sdhci_8bit_modemux),
+};
+
+static const char *const sdhci_grps[] = { "sdhci_4bit_grp", "sdhci_8bit_grp" };
+static struct spear_function sdhci_function = {
+	.name = "sdhci",
+	.groups = sdhci_grps,
+	.ngroups = ARRAY_SIZE(sdhci_grps),
+};
+
+/* gpio1_0_to_3_pins */
+static const unsigned gpio1_0_to_3_pins[] = { 39, 40, 41, 42 };
+static struct spear_muxreg gpio1_0_to_3_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux gpio1_0_to_3_modemux[] = {
+	{
+		.modes = PHOTO_FRAME_MODE,
+		.muxregs = gpio1_0_to_3_muxreg,
+		.nmuxregs = ARRAY_SIZE(gpio1_0_to_3_muxreg),
+	},
+};
+
+static struct spear_pingroup gpio1_0_to_3_pingroup = {
+	.name = "gpio1_0_to_3_grp",
+	.pins = gpio1_0_to_3_pins,
+	.npins = ARRAY_SIZE(gpio1_0_to_3_pins),
+	.modemuxs = gpio1_0_to_3_modemux,
+	.nmodemuxs = ARRAY_SIZE(gpio1_0_to_3_modemux),
+};
+
+/* gpio1_4_to_7_pins */
+static const unsigned gpio1_4_to_7_pins[] = { 43, 44, 45, 46 };
+
+static struct spear_muxreg gpio1_4_to_7_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux gpio1_4_to_7_modemux[] = {
+	{
+		.modes = PHOTO_FRAME_MODE,
+		.muxregs = gpio1_4_to_7_muxreg,
+		.nmuxregs = ARRAY_SIZE(gpio1_4_to_7_muxreg),
+	},
+};
+
+static struct spear_pingroup gpio1_4_to_7_pingroup = {
+	.name = "gpio1_4_to_7_grp",
+	.pins = gpio1_4_to_7_pins,
+	.npins = ARRAY_SIZE(gpio1_4_to_7_pins),
+	.modemuxs = gpio1_4_to_7_modemux,
+	.nmodemuxs = ARRAY_SIZE(gpio1_4_to_7_modemux),
+};
+
+static const char *const gpio1_grps[] = { "gpio1_0_to_3_grp", "gpio1_4_to_7_grp"
+};
+static struct spear_function gpio1_function = {
+	.name = "gpio1",
+	.groups = gpio1_grps,
+	.ngroups = ARRAY_SIZE(gpio1_grps),
+};
+
+/* pingroups */
+static struct spear_pingroup *spear300_pingroups[] = {
+	SPEAR3XX_COMMON_PINGROUPS,
+	&fsmc_2chips_pingroup,
+	&fsmc_4chips_pingroup,
+	&clcd_lcdmode_pingroup,
+	&clcd_pfmode_pingroup,
+	&tdm_pingroup,
+	&i2c_clk_pingroup,
+	&caml_pingroup,
+	&camu_pingroup,
+	&dac_pingroup,
+	&i2s_pingroup,
+	&sdhci_4bit_pingroup,
+	&sdhci_8bit_pingroup,
+	&gpio1_0_to_3_pingroup,
+	&gpio1_4_to_7_pingroup,
+};
+
+/* functions */
+static struct spear_function *spear300_functions[] = {
+	SPEAR3XX_COMMON_FUNCTIONS,
+	&fsmc_function,
+	&clcd_function,
+	&tdm_function,
+	&i2c_function,
+	&cam_function,
+	&dac_function,
+	&i2s_function,
+	&sdhci_function,
+	&gpio1_function,
+};
+
+static struct of_device_id spear300_pinctrl_of_match[] __devinitdata = {
+	{
+		.compatible = "st,spear300-pinmux",
+	},
+	{},
+};
+
+static int __devinit spear300_pinctrl_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	spear3xx_machdata.groups = spear300_pingroups;
+	spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups);
+	spear3xx_machdata.functions = spear300_functions;
+	spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions);
+
+	spear3xx_machdata.modes_supported = true;
+	spear3xx_machdata.pmx_modes = spear300_pmx_modes;
+	spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear300_pmx_modes);
+
+	pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+
+	ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int __devexit spear300_pinctrl_remove(struct platform_device *pdev)
+{
+	return spear_pinctrl_remove(pdev);
+}
+
+static struct platform_driver spear300_pinctrl_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = spear300_pinctrl_of_match,
+	},
+	.probe = spear300_pinctrl_probe,
+	.remove = __devexit_p(spear300_pinctrl_remove),
+};
+
+static int __init spear300_pinctrl_init(void)
+{
+	return platform_driver_register(&spear300_pinctrl_driver);
+}
+arch_initcall(spear300_pinctrl_init);
+
+static void __exit spear300_pinctrl_exit(void)
+{
+	platform_driver_unregister(&spear300_pinctrl_driver);
+}
+module_exit(spear300_pinctrl_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_DESCRIPTION("ST Microelectronics SPEAr300 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, spear300_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c
new file mode 100644
index 0000000..1a97076
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear310.c
@@ -0,0 +1,431 @@
+/*
+ * Driver for the ST Microelectronics SPEAr310 pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * 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/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "pinctrl-spear3xx.h"
+
+#define DRIVER_NAME "spear310-pinmux"
+
+/* addresses */
+#define PMX_CONFIG_REG			0x08
+
+/* emi_cs_0_to_5_pins */
+static const unsigned emi_cs_0_to_5_pins[] = { 45, 46, 47, 48, 49, 50 };
+static struct spear_muxreg emi_cs_0_to_5_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux emi_cs_0_to_5_modemux[] = {
+	{
+		.muxregs = emi_cs_0_to_5_muxreg,
+		.nmuxregs = ARRAY_SIZE(emi_cs_0_to_5_muxreg),
+	},
+};
+
+static struct spear_pingroup emi_cs_0_to_5_pingroup = {
+	.name = "emi_cs_0_to_5_grp",
+	.pins = emi_cs_0_to_5_pins,
+	.npins = ARRAY_SIZE(emi_cs_0_to_5_pins),
+	.modemuxs = emi_cs_0_to_5_modemux,
+	.nmodemuxs = ARRAY_SIZE(emi_cs_0_to_5_modemux),
+};
+
+static const char *const emi_cs_0_to_5_grps[] = { "emi_cs_0_to_5_grp" };
+static struct spear_function emi_cs_0_to_5_function = {
+	.name = "emi",
+	.groups = emi_cs_0_to_5_grps,
+	.ngroups = ARRAY_SIZE(emi_cs_0_to_5_grps),
+};
+
+/* uart1_pins */
+static const unsigned uart1_pins[] = { 0, 1 };
+static struct spear_muxreg uart1_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_FIRDA_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux uart1_modemux[] = {
+	{
+		.muxregs = uart1_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart1_muxreg),
+	},
+};
+
+static struct spear_pingroup uart1_pingroup = {
+	.name = "uart1_grp",
+	.pins = uart1_pins,
+	.npins = ARRAY_SIZE(uart1_pins),
+	.modemuxs = uart1_modemux,
+	.nmodemuxs = ARRAY_SIZE(uart1_modemux),
+};
+
+static const char *const uart1_grps[] = { "uart1_grp" };
+static struct spear_function uart1_function = {
+	.name = "uart1",
+	.groups = uart1_grps,
+	.ngroups = ARRAY_SIZE(uart1_grps),
+};
+
+/* uart2_pins */
+static const unsigned uart2_pins[] = { 43, 44 };
+static struct spear_muxreg uart2_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux uart2_modemux[] = {
+	{
+		.muxregs = uart2_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart2_muxreg),
+	},
+};
+
+static struct spear_pingroup uart2_pingroup = {
+	.name = "uart2_grp",
+	.pins = uart2_pins,
+	.npins = ARRAY_SIZE(uart2_pins),
+	.modemuxs = uart2_modemux,
+	.nmodemuxs = ARRAY_SIZE(uart2_modemux),
+};
+
+static const char *const uart2_grps[] = { "uart2_grp" };
+static struct spear_function uart2_function = {
+	.name = "uart2",
+	.groups = uart2_grps,
+	.ngroups = ARRAY_SIZE(uart2_grps),
+};
+
+/* uart3_pins */
+static const unsigned uart3_pins[] = { 37, 38 };
+static struct spear_muxreg uart3_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux uart3_modemux[] = {
+	{
+		.muxregs = uart3_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart3_muxreg),
+	},
+};
+
+static struct spear_pingroup uart3_pingroup = {
+	.name = "uart3_grp",
+	.pins = uart3_pins,
+	.npins = ARRAY_SIZE(uart3_pins),
+	.modemuxs = uart3_modemux,
+	.nmodemuxs = ARRAY_SIZE(uart3_modemux),
+};
+
+static const char *const uart3_grps[] = { "uart3_grp" };
+static struct spear_function uart3_function = {
+	.name = "uart3",
+	.groups = uart3_grps,
+	.ngroups = ARRAY_SIZE(uart3_grps),
+};
+
+/* uart4_pins */
+static const unsigned uart4_pins[] = { 39, 40 };
+static struct spear_muxreg uart4_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux uart4_modemux[] = {
+	{
+		.muxregs = uart4_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart4_muxreg),
+	},
+};
+
+static struct spear_pingroup uart4_pingroup = {
+	.name = "uart4_grp",
+	.pins = uart4_pins,
+	.npins = ARRAY_SIZE(uart4_pins),
+	.modemuxs = uart4_modemux,
+	.nmodemuxs = ARRAY_SIZE(uart4_modemux),
+};
+
+static const char *const uart4_grps[] = { "uart4_grp" };
+static struct spear_function uart4_function = {
+	.name = "uart4",
+	.groups = uart4_grps,
+	.ngroups = ARRAY_SIZE(uart4_grps),
+};
+
+/* uart5_pins */
+static const unsigned uart5_pins[] = { 41, 42 };
+static struct spear_muxreg uart5_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux uart5_modemux[] = {
+	{
+		.muxregs = uart5_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart5_muxreg),
+	},
+};
+
+static struct spear_pingroup uart5_pingroup = {
+	.name = "uart5_grp",
+	.pins = uart5_pins,
+	.npins = ARRAY_SIZE(uart5_pins),
+	.modemuxs = uart5_modemux,
+	.nmodemuxs = ARRAY_SIZE(uart5_modemux),
+};
+
+static const char *const uart5_grps[] = { "uart5_grp" };
+static struct spear_function uart5_function = {
+	.name = "uart5",
+	.groups = uart5_grps,
+	.ngroups = ARRAY_SIZE(uart5_grps),
+};
+
+/* fsmc_pins */
+static const unsigned fsmc_pins[] = { 34, 35, 36 };
+static struct spear_muxreg fsmc_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_CS_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux fsmc_modemux[] = {
+	{
+		.muxregs = fsmc_muxreg,
+		.nmuxregs = ARRAY_SIZE(fsmc_muxreg),
+	},
+};
+
+static struct spear_pingroup fsmc_pingroup = {
+	.name = "fsmc_grp",
+	.pins = fsmc_pins,
+	.npins = ARRAY_SIZE(fsmc_pins),
+	.modemuxs = fsmc_modemux,
+	.nmodemuxs = ARRAY_SIZE(fsmc_modemux),
+};
+
+static const char *const fsmc_grps[] = { "fsmc_grp" };
+static struct spear_function fsmc_function = {
+	.name = "fsmc",
+	.groups = fsmc_grps,
+	.ngroups = ARRAY_SIZE(fsmc_grps),
+};
+
+/* rs485_0_pins */
+static const unsigned rs485_0_pins[] = { 19, 20, 21, 22, 23 };
+static struct spear_muxreg rs485_0_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux rs485_0_modemux[] = {
+	{
+		.muxregs = rs485_0_muxreg,
+		.nmuxregs = ARRAY_SIZE(rs485_0_muxreg),
+	},
+};
+
+static struct spear_pingroup rs485_0_pingroup = {
+	.name = "rs485_0_grp",
+	.pins = rs485_0_pins,
+	.npins = ARRAY_SIZE(rs485_0_pins),
+	.modemuxs = rs485_0_modemux,
+	.nmodemuxs = ARRAY_SIZE(rs485_0_modemux),
+};
+
+static const char *const rs485_0_grps[] = { "rs485_0" };
+static struct spear_function rs485_0_function = {
+	.name = "rs485_0",
+	.groups = rs485_0_grps,
+	.ngroups = ARRAY_SIZE(rs485_0_grps),
+};
+
+/* rs485_1_pins */
+static const unsigned rs485_1_pins[] = { 14, 15, 16, 17, 18 };
+static struct spear_muxreg rs485_1_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux rs485_1_modemux[] = {
+	{
+		.muxregs = rs485_1_muxreg,
+		.nmuxregs = ARRAY_SIZE(rs485_1_muxreg),
+	},
+};
+
+static struct spear_pingroup rs485_1_pingroup = {
+	.name = "rs485_1_grp",
+	.pins = rs485_1_pins,
+	.npins = ARRAY_SIZE(rs485_1_pins),
+	.modemuxs = rs485_1_modemux,
+	.nmodemuxs = ARRAY_SIZE(rs485_1_modemux),
+};
+
+static const char *const rs485_1_grps[] = { "rs485_1" };
+static struct spear_function rs485_1_function = {
+	.name = "rs485_1",
+	.groups = rs485_1_grps,
+	.ngroups = ARRAY_SIZE(rs485_1_grps),
+};
+
+/* tdm_pins */
+static const unsigned tdm_pins[] = { 10, 11, 12, 13 };
+static struct spear_muxreg tdm_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_modemux tdm_modemux[] = {
+	{
+		.muxregs = tdm_muxreg,
+		.nmuxregs = ARRAY_SIZE(tdm_muxreg),
+	},
+};
+
+static struct spear_pingroup tdm_pingroup = {
+	.name = "tdm_grp",
+	.pins = tdm_pins,
+	.npins = ARRAY_SIZE(tdm_pins),
+	.modemuxs = tdm_modemux,
+	.nmodemuxs = ARRAY_SIZE(tdm_modemux),
+};
+
+static const char *const tdm_grps[] = { "tdm_grp" };
+static struct spear_function tdm_function = {
+	.name = "tdm",
+	.groups = tdm_grps,
+	.ngroups = ARRAY_SIZE(tdm_grps),
+};
+
+/* pingroups */
+static struct spear_pingroup *spear310_pingroups[] = {
+	SPEAR3XX_COMMON_PINGROUPS,
+	&emi_cs_0_to_5_pingroup,
+	&uart1_pingroup,
+	&uart2_pingroup,
+	&uart3_pingroup,
+	&uart4_pingroup,
+	&uart5_pingroup,
+	&fsmc_pingroup,
+	&rs485_0_pingroup,
+	&rs485_1_pingroup,
+	&tdm_pingroup,
+};
+
+/* functions */
+static struct spear_function *spear310_functions[] = {
+	SPEAR3XX_COMMON_FUNCTIONS,
+	&emi_cs_0_to_5_function,
+	&uart1_function,
+	&uart2_function,
+	&uart3_function,
+	&uart4_function,
+	&uart5_function,
+	&fsmc_function,
+	&rs485_0_function,
+	&rs485_1_function,
+	&tdm_function,
+};
+
+static struct of_device_id spear310_pinctrl_of_match[] __devinitdata = {
+	{
+		.compatible = "st,spear310-pinmux",
+	},
+	{},
+};
+
+static int __devinit spear310_pinctrl_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	spear3xx_machdata.groups = spear310_pingroups;
+	spear3xx_machdata.ngroups = ARRAY_SIZE(spear310_pingroups);
+	spear3xx_machdata.functions = spear310_functions;
+	spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions);
+
+	pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+
+	spear3xx_machdata.modes_supported = false;
+
+	ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int __devexit spear310_pinctrl_remove(struct platform_device *pdev)
+{
+	return spear_pinctrl_remove(pdev);
+}
+
+static struct platform_driver spear310_pinctrl_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = spear310_pinctrl_of_match,
+	},
+	.probe = spear310_pinctrl_probe,
+	.remove = __devexit_p(spear310_pinctrl_remove),
+};
+
+static int __init spear310_pinctrl_init(void)
+{
+	return platform_driver_register(&spear310_pinctrl_driver);
+}
+arch_initcall(spear310_pinctrl_init);
+
+static void __exit spear310_pinctrl_exit(void)
+{
+	platform_driver_unregister(&spear310_pinctrl_driver);
+}
+module_exit(spear310_pinctrl_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_DESCRIPTION("ST Microelectronics SPEAr310 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, SPEAr310_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c
new file mode 100644
index 0000000..de726e6
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear320.c
@@ -0,0 +1,3468 @@
+/*
+ * Driver for the ST Microelectronics SPEAr320 pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * 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/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "pinctrl-spear3xx.h"
+
+#define DRIVER_NAME "spear320-pinmux"
+
+/* addresses */
+#define PMX_CONFIG_REG			0x0C
+#define MODE_CONFIG_REG			0x10
+#define MODE_EXT_CONFIG_REG		0x18
+
+/* modes */
+#define AUTO_NET_SMII_MODE	(1 << 0)
+#define AUTO_NET_MII_MODE	(1 << 1)
+#define AUTO_EXP_MODE		(1 << 2)
+#define SMALL_PRINTERS_MODE	(1 << 3)
+#define EXTENDED_MODE		(1 << 4)
+
+static struct spear_pmx_mode pmx_mode_auto_net_smii = {
+	.name = "Automation Networking SMII mode",
+	.mode = AUTO_NET_SMII_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x00000007,
+	.val = 0x0,
+};
+
+static struct spear_pmx_mode pmx_mode_auto_net_mii = {
+	.name = "Automation Networking MII mode",
+	.mode = AUTO_NET_MII_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x00000007,
+	.val = 0x1,
+};
+
+static struct spear_pmx_mode pmx_mode_auto_exp = {
+	.name = "Automation Expanded mode",
+	.mode = AUTO_EXP_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x00000007,
+	.val = 0x2,
+};
+
+static struct spear_pmx_mode pmx_mode_small_printers = {
+	.name = "Small Printers mode",
+	.mode = SMALL_PRINTERS_MODE,
+	.reg = MODE_CONFIG_REG,
+	.mask = 0x00000007,
+	.val = 0x3,
+};
+
+static struct spear_pmx_mode pmx_mode_extended = {
+	.name = "extended mode",
+	.mode = EXTENDED_MODE,
+	.reg = MODE_EXT_CONFIG_REG,
+	.mask = 0x00000001,
+	.val = 0x1,
+};
+
+static struct spear_pmx_mode *spear320_pmx_modes[] = {
+	&pmx_mode_auto_net_smii,
+	&pmx_mode_auto_net_mii,
+	&pmx_mode_auto_exp,
+	&pmx_mode_small_printers,
+	&pmx_mode_extended,
+};
+
+/* Extended mode registers and their offsets */
+#define EXT_CTRL_REG				0x0018
+	#define MII_MDIO_MASK			(1 << 4)
+	#define MII_MDIO_10_11_VAL		0
+	#define MII_MDIO_81_VAL			(1 << 4)
+	#define EMI_FSMC_DYNAMIC_MUX_MASK	(1 << 5)
+	#define MAC_MODE_MII			0
+	#define MAC_MODE_RMII			1
+	#define MAC_MODE_SMII			2
+	#define MAC_MODE_SS_SMII		3
+	#define MAC_MODE_MASK			0x3
+	#define MAC1_MODE_SHIFT			16
+	#define MAC2_MODE_SHIFT			18
+
+#define IP_SEL_PAD_0_9_REG			0x00A4
+	#define PMX_PL_0_1_MASK			(0x3F << 0)
+	#define PMX_UART2_PL_0_1_VAL		0x0
+	#define PMX_I2C2_PL_0_1_VAL		(0x4 | (0x4 << 3))
+
+	#define PMX_PL_2_3_MASK			(0x3F << 6)
+	#define PMX_I2C2_PL_2_3_VAL		0x0
+	#define PMX_UART6_PL_2_3_VAL		((0x1 << 6) | (0x1 << 9))
+	#define PMX_UART1_ENH_PL_2_3_VAL	((0x4 << 6) | (0x4 << 9))
+
+	#define PMX_PL_4_5_MASK			(0x3F << 12)
+	#define PMX_UART5_PL_4_5_VAL		((0x1 << 12) | (0x1 << 15))
+	#define PMX_UART1_ENH_PL_4_5_VAL	((0x4 << 12) | (0x4 << 15))
+	#define PMX_PL_5_MASK			(0x7 << 15)
+	#define PMX_TOUCH_Y_PL_5_VAL		0x0
+
+	#define PMX_PL_6_7_MASK			(0x3F << 18)
+	#define PMX_PL_6_MASK			(0x7 << 18)
+	#define PMX_PL_7_MASK			(0x7 << 21)
+	#define PMX_UART4_PL_6_7_VAL		((0x1 << 18) | (0x1 << 21))
+	#define PMX_PWM_3_PL_6_VAL		(0x2 << 18)
+	#define PMX_PWM_2_PL_7_VAL		(0x2 << 21)
+	#define PMX_UART1_ENH_PL_6_7_VAL	((0x4 << 18) | (0x4 << 21))
+
+	#define PMX_PL_8_9_MASK			(0x3F << 24)
+	#define PMX_UART3_PL_8_9_VAL		((0x1 << 24) | (0x1 << 27))
+	#define PMX_PWM_0_1_PL_8_9_VAL		((0x2 << 24) | (0x2 << 27))
+	#define PMX_I2C1_PL_8_9_VAL		((0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_10_19_REG			0x00A8
+	#define PMX_PL_10_11_MASK		(0x3F << 0)
+	#define PMX_SMII_PL_10_11_VAL		0
+	#define PMX_RMII_PL_10_11_VAL		((0x4 << 0) | (0x4 << 3))
+
+	#define PMX_PL_12_MASK			(0x7 << 6)
+	#define PMX_PWM3_PL_12_VAL		0
+	#define PMX_SDHCI_CD_PL_12_VAL		(0x4 << 6)
+
+	#define PMX_PL_13_14_MASK		(0x3F << 9)
+	#define PMX_PL_13_MASK			(0x7 << 9)
+	#define PMX_PL_14_MASK			(0x7 << 12)
+	#define PMX_SSP2_PL_13_14_15_16_VAL	0
+	#define PMX_UART4_PL_13_14_VAL		((0x1 << 9) | (0x1 << 12))
+	#define PMX_RMII_PL_13_14_VAL		((0x4 << 9) | (0x4 << 12))
+	#define PMX_PWM2_PL_13_VAL		(0x2 << 9)
+	#define PMX_PWM1_PL_14_VAL		(0x2 << 12)
+
+	#define PMX_PL_15_MASK			(0x7 << 15)
+	#define PMX_PWM0_PL_15_VAL		(0x2 << 15)
+	#define PMX_PL_15_16_MASK		(0x3F << 15)
+	#define PMX_UART3_PL_15_16_VAL		((0x1 << 15) | (0x1 << 18))
+	#define PMX_RMII_PL_15_16_VAL		((0x4 << 15) | (0x4 << 18))
+
+	#define PMX_PL_17_18_MASK		(0x3F << 21)
+	#define PMX_SSP1_PL_17_18_19_20_VAL	0
+	#define PMX_RMII_PL_17_18_VAL		((0x4 << 21) | (0x4 << 24))
+
+	#define PMX_PL_19_MASK			(0x7 << 27)
+	#define PMX_I2C2_PL_19_VAL		(0x1 << 27)
+	#define PMX_RMII_PL_19_VAL		(0x4 << 27)
+
+#define IP_SEL_PAD_20_29_REG			0x00AC
+	#define PMX_PL_20_MASK			(0x7 << 0)
+	#define PMX_I2C2_PL_20_VAL		(0x1 << 0)
+	#define PMX_RMII_PL_20_VAL		(0x4 << 0)
+
+	#define PMX_PL_21_TO_27_MASK		(0x1FFFFF << 3)
+	#define PMX_SMII_PL_21_TO_27_VAL	0
+	#define PMX_RMII_PL_21_TO_27_VAL	((0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12) | (0x4 << 15) | (0x4 << 18) | (0x4 << 21))
+
+	#define PMX_PL_28_29_MASK		(0x3F << 24)
+	#define PMX_PL_28_MASK			(0x7 << 24)
+	#define PMX_PL_29_MASK			(0x7 << 27)
+	#define PMX_UART1_PL_28_29_VAL		0
+	#define PMX_PWM_3_PL_28_VAL		(0x4 << 24)
+	#define PMX_PWM_2_PL_29_VAL		(0x4 << 27)
+
+#define IP_SEL_PAD_30_39_REG			0x00B0
+	#define PMX_PL_30_31_MASK		(0x3F << 0)
+	#define PMX_CAN1_PL_30_31_VAL		(0)
+	#define PMX_PL_30_MASK			(0x7 << 0)
+	#define PMX_PL_31_MASK			(0x7 << 3)
+	#define PMX_PWM1_EXT_PL_30_VAL		(0x4 << 0)
+	#define PMX_PWM0_EXT_PL_31_VAL		(0x4 << 3)
+	#define PMX_UART1_ENH_PL_31_VAL		(0x3 << 3)
+
+	#define PMX_PL_32_33_MASK		(0x3F << 6)
+	#define PMX_CAN0_PL_32_33_VAL		0
+	#define PMX_UART1_ENH_PL_32_33_VAL	((0x3 << 6) | (0x3 << 9))
+	#define PMX_SSP2_PL_32_33_VAL		((0x4 << 6) | (0x4 << 9))
+
+	#define PMX_PL_34_MASK			(0x7 << 12)
+	#define PMX_PWM2_PL_34_VAL		0
+	#define PMX_UART1_ENH_PL_34_VAL		(0x2 << 12)
+	#define PMX_SSP2_PL_34_VAL		(0x4 << 12)
+
+	#define PMX_PL_35_MASK			(0x7 << 15)
+	#define PMX_I2S_REF_CLK_PL_35_VAL	0
+	#define PMX_UART1_ENH_PL_35_VAL		(0x2 << 15)
+	#define PMX_SSP2_PL_35_VAL		(0x4 << 15)
+
+	#define PMX_PL_36_MASK			(0x7 << 18)
+	#define PMX_TOUCH_X_PL_36_VAL		0
+	#define PMX_UART1_ENH_PL_36_VAL		(0x2 << 18)
+	#define PMX_SSP1_PL_36_VAL		(0x4 << 18)
+
+	#define PMX_PL_37_38_MASK		(0x3F << 21)
+	#define PMX_PWM0_1_PL_37_38_VAL		0
+	#define PMX_UART5_PL_37_38_VAL		((0x2 << 21) | (0x2 << 24))
+	#define PMX_SSP1_PL_37_38_VAL		((0x4 << 21) | (0x4 << 24))
+
+	#define PMX_PL_39_MASK			(0x7 << 27)
+	#define PMX_I2S_PL_39_VAL		0
+	#define PMX_UART4_PL_39_VAL		(0x2 << 27)
+	#define PMX_SSP1_PL_39_VAL		(0x4 << 27)
+
+#define IP_SEL_PAD_40_49_REG			0x00B4
+	#define PMX_PL_40_MASK			(0x7 << 0)
+	#define PMX_I2S_PL_40_VAL		0
+	#define PMX_UART4_PL_40_VAL		(0x2 << 0)
+	#define PMX_PWM3_PL_40_VAL		(0x4 << 0)
+
+	#define PMX_PL_41_42_MASK		(0x3F << 3)
+	#define PMX_PL_41_MASK			(0x7 << 3)
+	#define PMX_PL_42_MASK			(0x7 << 6)
+	#define PMX_I2S_PL_41_42_VAL		0
+	#define PMX_UART3_PL_41_42_VAL		((0x2 << 3) | (0x2 << 6))
+	#define PMX_PWM2_PL_41_VAL		(0x4 << 3)
+	#define PMX_PWM1_PL_42_VAL		(0x4 << 6)
+
+	#define PMX_PL_43_MASK			(0x7 << 9)
+	#define PMX_SDHCI_PL_43_VAL		0
+	#define PMX_UART1_ENH_PL_43_VAL		(0x2 << 9)
+	#define PMX_PWM0_PL_43_VAL		(0x4 << 9)
+
+	#define PMX_PL_44_45_MASK		(0x3F << 12)
+	#define PMX_SDHCI_PL_44_45_VAL	0
+	#define PMX_UART1_ENH_PL_44_45_VAL	((0x2 << 12) | (0x2 << 15))
+	#define PMX_SSP2_PL_44_45_VAL		((0x4 << 12) | (0x4 << 15))
+
+	#define PMX_PL_46_47_MASK		(0x3F << 18)
+	#define PMX_SDHCI_PL_46_47_VAL	0
+	#define PMX_FSMC_EMI_PL_46_47_VAL	((0x2 << 18) | (0x2 << 21))
+	#define PMX_SSP2_PL_46_47_VAL		((0x4 << 18) | (0x4 << 21))
+
+	#define PMX_PL_48_49_MASK		(0x3F << 24)
+	#define PMX_SDHCI_PL_48_49_VAL	0
+	#define PMX_FSMC_EMI_PL_48_49_VAL	((0x2 << 24) | (0x2 << 27))
+	#define PMX_SSP1_PL_48_49_VAL		((0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_50_59_REG			0x00B8
+	#define PMX_PL_50_51_MASK		(0x3F << 0)
+	#define PMX_EMI_PL_50_51_VAL		((0x2 << 0) | (0x2 << 3))
+	#define PMX_SSP1_PL_50_51_VAL		((0x4 << 0) | (0x4 << 3))
+	#define PMX_PL_50_MASK			(0x7 << 0)
+	#define PMX_PL_51_MASK			(0x7 << 3)
+	#define PMX_SDHCI_PL_50_VAL		0
+	#define PMX_SDHCI_CD_PL_51_VAL		0
+
+	#define PMX_PL_52_53_MASK		(0x3F << 6)
+	#define PMX_FSMC_PL_52_53_VAL		0
+	#define PMX_EMI_PL_52_53_VAL		((0x2 << 6) | (0x2 << 9))
+	#define PMX_UART3_PL_52_53_VAL		((0x4 << 6) | (0x4 << 9))
+
+	#define PMX_PL_54_55_56_MASK		(0x1FF << 12)
+	#define PMX_FSMC_EMI_PL_54_55_56_VAL	((0x2 << 12) | (0x2 << 15) | (0x2 << 18))
+
+	#define PMX_PL_57_MASK			(0x7 << 21)
+	#define PMX_FSMC_PL_57_VAL		0
+	#define PMX_PWM3_PL_57_VAL		(0x4 << 21)
+
+	#define PMX_PL_58_59_MASK		(0x3F << 24)
+	#define PMX_PL_58_MASK			(0x7 << 24)
+	#define PMX_PL_59_MASK			(0x7 << 27)
+	#define PMX_FSMC_EMI_PL_58_59_VAL	((0x2 << 24) | (0x2 << 27))
+	#define PMX_PWM2_PL_58_VAL		(0x4 << 24)
+	#define PMX_PWM1_PL_59_VAL		(0x4 << 27)
+
+#define IP_SEL_PAD_60_69_REG			0x00BC
+	#define PMX_PL_60_MASK			(0x7 << 0)
+	#define PMX_FSMC_PL_60_VAL		0
+	#define PMX_PWM0_PL_60_VAL		(0x4 << 0)
+
+	#define PMX_PL_61_TO_64_MASK		(0xFFF << 3)
+	#define PMX_FSMC_PL_61_TO_64_VAL	((0x2 << 3) | (0x2 << 6) | (0x2 << 9) | (0x2 << 12))
+	#define PMX_SSP2_PL_61_TO_64_VAL	((0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12))
+
+	#define PMX_PL_65_TO_68_MASK		(0xFFF << 15)
+	#define PMX_FSMC_PL_65_TO_68_VAL	((0x2 << 15) | (0x2 << 18) | (0x2 << 21) | (0x2 << 24))
+	#define PMX_SSP1_PL_65_TO_68_VAL	((0x4 << 15) | (0x4 << 18) | (0x4 << 21) | (0x4 << 24))
+
+	#define PMX_PL_69_MASK			(0x7 << 27)
+	#define PMX_CLCD_PL_69_VAL		(0)
+	#define PMX_EMI_PL_69_VAL		(0x2 << 27)
+	#define PMX_SPP_PL_69_VAL		(0x3 << 27)
+	#define PMX_UART5_PL_69_VAL		(0x4 << 27)
+
+#define IP_SEL_PAD_70_79_REG			0x00C0
+	#define PMX_PL_70_MASK			(0x7 << 0)
+	#define PMX_CLCD_PL_70_VAL		(0)
+	#define PMX_FSMC_EMI_PL_70_VAL		(0x2 << 0)
+	#define PMX_SPP_PL_70_VAL		(0x3 << 0)
+	#define PMX_UART5_PL_70_VAL		(0x4 << 0)
+
+	#define PMX_PL_71_72_MASK		(0x3F << 3)
+	#define PMX_CLCD_PL_71_72_VAL		(0)
+	#define PMX_FSMC_EMI_PL_71_72_VAL	((0x2 << 3) | (0x2 << 6))
+	#define PMX_SPP_PL_71_72_VAL		((0x3 << 3) | (0x3 << 6))
+	#define PMX_UART4_PL_71_72_VAL		((0x4 << 3) | (0x4 << 6))
+
+	#define PMX_PL_73_MASK			(0x7 << 9)
+	#define PMX_CLCD_PL_73_VAL		(0)
+	#define PMX_FSMC_EMI_PL_73_VAL		(0x2 << 9)
+	#define PMX_SPP_PL_73_VAL		(0x3 << 9)
+	#define PMX_UART3_PL_73_VAL		(0x4 << 9)
+
+	#define PMX_PL_74_MASK			(0x7 << 12)
+	#define PMX_CLCD_PL_74_VAL		(0)
+	#define PMX_EMI_PL_74_VAL		(0x2 << 12)
+	#define PMX_SPP_PL_74_VAL		(0x3 << 12)
+	#define PMX_UART3_PL_74_VAL		(0x4 << 12)
+
+	#define PMX_PL_75_76_MASK		(0x3F << 15)
+	#define PMX_CLCD_PL_75_76_VAL		(0)
+	#define PMX_EMI_PL_75_76_VAL		((0x2 << 15) | (0x2 << 18))
+	#define PMX_SPP_PL_75_76_VAL		((0x3 << 15) | (0x3 << 18))
+	#define PMX_I2C2_PL_75_76_VAL		((0x4 << 15) | (0x4 << 18))
+
+	#define PMX_PL_77_78_79_MASK		(0x1FF << 21)
+	#define PMX_CLCD_PL_77_78_79_VAL	(0)
+	#define PMX_EMI_PL_77_78_79_VAL		((0x2 << 21) | (0x2 << 24) | (0x2 << 27))
+	#define PMX_SPP_PL_77_78_79_VAL		((0x3 << 21) | (0x3 << 24) | (0x3 << 27))
+	#define PMX_RS485_PL_77_78_79_VAL	((0x4 << 21) | (0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_80_89_REG			0x00C4
+	#define PMX_PL_80_TO_85_MASK		(0x3FFFF << 0)
+	#define PMX_CLCD_PL_80_TO_85_VAL	0
+	#define PMX_MII2_PL_80_TO_85_VAL	((0x1 << 0) | (0x1 << 3) | (0x1 << 6) | (0x1 << 9) | (0x1 << 12) | (0x1 << 15))
+	#define PMX_EMI_PL_80_TO_85_VAL		((0x2 << 0) | (0x2 << 3) | (0x2 << 6) | (0x2 << 9) | (0x2 << 12) | (0x2 << 15))
+	#define PMX_SPP_PL_80_TO_85_VAL		((0x3 << 0) | (0x3 << 3) | (0x3 << 6) | (0x3 << 9) | (0x3 << 12) | (0x3 << 15))
+	#define PMX_UART1_ENH_PL_80_TO_85_VAL	((0x4 << 0) | (0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12) | (0x4 << 15))
+
+	#define PMX_PL_86_87_MASK		(0x3F << 18)
+	#define PMX_PL_86_MASK			(0x7 << 18)
+	#define PMX_PL_87_MASK			(0x7 << 21)
+	#define PMX_CLCD_PL_86_87_VAL		0
+	#define PMX_MII2_PL_86_87_VAL		((0x1 << 18) | (0x1 << 21))
+	#define PMX_EMI_PL_86_87_VAL		((0x2 << 18) | (0x2 << 21))
+	#define PMX_PWM3_PL_86_VAL		(0x4 << 18)
+	#define PMX_PWM2_PL_87_VAL		(0x4 << 21)
+
+	#define PMX_PL_88_89_MASK		(0x3F << 24)
+	#define PMX_CLCD_PL_88_89_VAL		0
+	#define PMX_MII2_PL_88_89_VAL		((0x1 << 24) | (0x1 << 27))
+	#define PMX_EMI_PL_88_89_VAL		((0x2 << 24) | (0x2 << 27))
+	#define PMX_UART6_PL_88_89_VAL		((0x3 << 24) | (0x3 << 27))
+	#define PMX_PWM0_1_PL_88_89_VAL		((0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_90_99_REG			0x00C8
+	#define PMX_PL_90_91_MASK		(0x3F << 0)
+	#define PMX_CLCD_PL_90_91_VAL		0
+	#define PMX_MII2_PL_90_91_VAL		((0x1 << 0) | (0x1 << 3))
+	#define PMX_EMI1_PL_90_91_VAL		((0x2 << 0) | (0x2 << 3))
+	#define PMX_UART5_PL_90_91_VAL		((0x3 << 0) | (0x3 << 3))
+	#define PMX_SSP2_PL_90_91_VAL		((0x4 << 0) | (0x4 << 3))
+
+	#define PMX_PL_92_93_MASK		(0x3F << 6)
+	#define PMX_CLCD_PL_92_93_VAL		0
+	#define PMX_MII2_PL_92_93_VAL		((0x1 << 6) | (0x1 << 9))
+	#define PMX_EMI1_PL_92_93_VAL		((0x2 << 6) | (0x2 << 9))
+	#define PMX_UART4_PL_92_93_VAL		((0x3 << 6) | (0x3 << 9))
+	#define PMX_SSP2_PL_92_93_VAL		((0x4 << 6) | (0x4 << 9))
+
+	#define PMX_PL_94_95_MASK		(0x3F << 12)
+	#define PMX_CLCD_PL_94_95_VAL		0
+	#define PMX_MII2_PL_94_95_VAL		((0x1 << 12) | (0x1 << 15))
+	#define PMX_EMI1_PL_94_95_VAL		((0x2 << 12) | (0x2 << 15))
+	#define PMX_UART3_PL_94_95_VAL		((0x3 << 12) | (0x3 << 15))
+	#define PMX_SSP1_PL_94_95_VAL		((0x4 << 12) | (0x4 << 15))
+
+	#define PMX_PL_96_97_MASK		(0x3F << 18)
+	#define PMX_CLCD_PL_96_97_VAL		0
+	#define PMX_MII2_PL_96_97_VAL		((0x1 << 18) | (0x1 << 21))
+	#define PMX_EMI1_PL_96_97_VAL		((0x2 << 18) | (0x2 << 21))
+	#define PMX_I2C2_PL_96_97_VAL		((0x3 << 18) | (0x3 << 21))
+	#define PMX_SSP1_PL_96_97_VAL		((0x4 << 18) | (0x4 << 21))
+
+	#define PMX_PL_98_MASK			(0x7 << 24)
+	#define PMX_CLCD_PL_98_VAL		0
+	#define PMX_I2C1_PL_98_VAL		(0x2 << 24)
+	#define PMX_UART3_PL_98_VAL		(0x4 << 24)
+
+	#define PMX_PL_99_MASK			(0x7 << 27)
+	#define PMX_SDHCI_PL_99_VAL		0
+	#define PMX_I2C1_PL_99_VAL		(0x2 << 27)
+	#define PMX_UART3_PL_99_VAL		(0x4 << 27)
+
+#define IP_SEL_MIX_PAD_REG			0x00CC
+	#define PMX_PL_100_101_MASK		(0x3F << 0)
+	#define PMX_SDHCI_PL_100_101_VAL	0
+	#define PMX_UART4_PL_100_101_VAL	((0x4 << 0) | (0x4 << 3))
+
+	#define PMX_SSP1_PORT_SEL_MASK		(0x7 << 8)
+	#define PMX_SSP1_PORT_94_TO_97_VAL	0
+	#define PMX_SSP1_PORT_65_TO_68_VAL	(0x1 << 8)
+	#define PMX_SSP1_PORT_48_TO_51_VAL	(0x2 << 8)
+	#define PMX_SSP1_PORT_36_TO_39_VAL	(0x3 << 8)
+	#define PMX_SSP1_PORT_17_TO_20_VAL	(0x4 << 8)
+
+	#define PMX_SSP2_PORT_SEL_MASK		(0x7 << 11)
+	#define PMX_SSP2_PORT_90_TO_93_VAL	0
+	#define PMX_SSP2_PORT_61_TO_64_VAL	(0x1 << 11)
+	#define PMX_SSP2_PORT_44_TO_47_VAL	(0x2 << 11)
+	#define PMX_SSP2_PORT_32_TO_35_VAL	(0x3 << 11)
+	#define PMX_SSP2_PORT_13_TO_16_VAL	(0x4 << 11)
+
+	#define PMX_UART1_ENH_PORT_SEL_MASK		(0x3 << 14)
+	#define PMX_UART1_ENH_PORT_81_TO_85_VAL		0
+	#define PMX_UART1_ENH_PORT_44_45_34_36_VAL	(0x1 << 14)
+	#define PMX_UART1_ENH_PORT_32_TO_34_36_VAL	(0x2 << 14)
+	#define PMX_UART1_ENH_PORT_3_TO_5_7_VAL		(0x3 << 14)
+
+	#define PMX_UART3_PORT_SEL_MASK		(0x7 << 16)
+	#define PMX_UART3_PORT_94_VAL		0
+	#define PMX_UART3_PORT_73_VAL		(0x1 << 16)
+	#define PMX_UART3_PORT_52_VAL		(0x2 << 16)
+	#define PMX_UART3_PORT_41_VAL		(0x3 << 16)
+	#define PMX_UART3_PORT_15_VAL		(0x4 << 16)
+	#define PMX_UART3_PORT_8_VAL		(0x5 << 16)
+	#define PMX_UART3_PORT_99_VAL		(0x6 << 16)
+
+	#define PMX_UART4_PORT_SEL_MASK		(0x7 << 19)
+	#define PMX_UART4_PORT_92_VAL		0
+	#define PMX_UART4_PORT_71_VAL		(0x1 << 19)
+	#define PMX_UART4_PORT_39_VAL		(0x2 << 19)
+	#define PMX_UART4_PORT_13_VAL		(0x3 << 19)
+	#define PMX_UART4_PORT_6_VAL		(0x4 << 19)
+	#define PMX_UART4_PORT_101_VAL		(0x5 << 19)
+
+	#define PMX_UART5_PORT_SEL_MASK		(0x3 << 22)
+	#define PMX_UART5_PORT_90_VAL		0
+	#define PMX_UART5_PORT_69_VAL		(0x1 << 22)
+	#define PMX_UART5_PORT_37_VAL		(0x2 << 22)
+	#define PMX_UART5_PORT_4_VAL		(0x3 << 22)
+
+	#define PMX_UART6_PORT_SEL_MASK		(0x1 << 24)
+	#define PMX_UART6_PORT_88_VAL		0
+	#define PMX_UART6_PORT_2_VAL		(0x1 << 24)
+
+	#define PMX_I2C1_PORT_SEL_MASK		(0x1 << 25)
+	#define PMX_I2C1_PORT_8_9_VAL		0
+	#define PMX_I2C1_PORT_98_99_VAL		(0x1 << 25)
+
+	#define PMX_I2C2_PORT_SEL_MASK		(0x3 << 26)
+	#define PMX_I2C2_PORT_96_97_VAL		0
+	#define PMX_I2C2_PORT_75_76_VAL		(0x1 << 26)
+	#define PMX_I2C2_PORT_19_20_VAL		(0x2 << 26)
+	#define PMX_I2C2_PORT_2_3_VAL		(0x3 << 26)
+	#define PMX_I2C2_PORT_0_1_VAL		(0x4 << 26)
+
+	#define PMX_SDHCI_CD_PORT_SEL_MASK	(0x1 << 29)
+	#define PMX_SDHCI_CD_PORT_12_VAL	0
+	#define PMX_SDHCI_CD_PORT_51_VAL	(0x1 << 29)
+
+/* Pad multiplexing for CLCD device */
+static const unsigned clcd_pins[] = { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+	79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+	97 };
+static struct spear_muxreg clcd_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_60_69_REG,
+		.mask = PMX_PL_69_MASK,
+		.val = PMX_CLCD_PL_69_VAL,
+	}, {
+		.reg = IP_SEL_PAD_70_79_REG,
+		.mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK |
+			PMX_PL_74_MASK | PMX_PL_75_76_MASK |
+			PMX_PL_77_78_79_MASK,
+		.val = PMX_CLCD_PL_70_VAL | PMX_CLCD_PL_71_72_VAL |
+			PMX_CLCD_PL_73_VAL | PMX_CLCD_PL_74_VAL |
+			PMX_CLCD_PL_75_76_VAL | PMX_CLCD_PL_77_78_79_VAL,
+	}, {
+		.reg = IP_SEL_PAD_80_89_REG,
+		.mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK |
+			PMX_PL_88_89_MASK,
+		.val = PMX_CLCD_PL_80_TO_85_VAL | PMX_CLCD_PL_86_87_VAL |
+			PMX_CLCD_PL_88_89_VAL,
+	}, {
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK |
+			PMX_PL_94_95_MASK | PMX_PL_96_97_MASK | PMX_PL_98_MASK,
+		.val = PMX_CLCD_PL_90_91_VAL | PMX_CLCD_PL_92_93_VAL |
+			PMX_CLCD_PL_94_95_VAL | PMX_CLCD_PL_96_97_VAL |
+			PMX_CLCD_PL_98_VAL,
+	},
+};
+
+static struct spear_modemux clcd_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = clcd_muxreg,
+		.nmuxregs = ARRAY_SIZE(clcd_muxreg),
+	},
+};
+
+static struct spear_pingroup clcd_pingroup = {
+	.name = "clcd_grp",
+	.pins = clcd_pins,
+	.npins = ARRAY_SIZE(clcd_pins),
+	.modemuxs = clcd_modemux,
+	.nmodemuxs = ARRAY_SIZE(clcd_modemux),
+};
+
+static const char *const clcd_grps[] = { "clcd_grp" };
+static struct spear_function clcd_function = {
+	.name = "clcd",
+	.groups = clcd_grps,
+	.ngroups = ARRAY_SIZE(clcd_grps),
+};
+
+/* Pad multiplexing for EMI (Parallel NOR flash) device */
+static const unsigned emi_pins[] = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+	57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+	75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+	93, 94, 95, 96, 97 };
+static struct spear_muxreg emi_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg emi_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_46_47_MASK | PMX_PL_48_49_MASK,
+		.val = PMX_FSMC_EMI_PL_46_47_VAL | PMX_FSMC_EMI_PL_48_49_VAL,
+	}, {
+		.reg = IP_SEL_PAD_50_59_REG,
+		.mask = PMX_PL_50_51_MASK | PMX_PL_52_53_MASK |
+			PMX_PL_54_55_56_MASK | PMX_PL_58_59_MASK,
+		.val = PMX_EMI_PL_50_51_VAL | PMX_EMI_PL_52_53_VAL |
+			PMX_FSMC_EMI_PL_54_55_56_VAL |
+			PMX_FSMC_EMI_PL_58_59_VAL,
+	}, {
+		.reg = IP_SEL_PAD_60_69_REG,
+		.mask = PMX_PL_69_MASK,
+		.val = PMX_EMI_PL_69_VAL,
+	}, {
+		.reg = IP_SEL_PAD_70_79_REG,
+		.mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK |
+			PMX_PL_74_MASK | PMX_PL_75_76_MASK |
+			PMX_PL_77_78_79_MASK,
+		.val = PMX_FSMC_EMI_PL_70_VAL | PMX_FSMC_EMI_PL_71_72_VAL |
+			PMX_FSMC_EMI_PL_73_VAL | PMX_EMI_PL_74_VAL |
+			PMX_EMI_PL_75_76_VAL | PMX_EMI_PL_77_78_79_VAL,
+	}, {
+		.reg = IP_SEL_PAD_80_89_REG,
+		.mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK |
+			PMX_PL_88_89_MASK,
+		.val = PMX_EMI_PL_80_TO_85_VAL | PMX_EMI_PL_86_87_VAL |
+			PMX_EMI_PL_88_89_VAL,
+	}, {
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK |
+			PMX_PL_94_95_MASK | PMX_PL_96_97_MASK,
+		.val = PMX_EMI1_PL_90_91_VAL | PMX_EMI1_PL_92_93_VAL |
+			PMX_EMI1_PL_94_95_VAL | PMX_EMI1_PL_96_97_VAL,
+	}, {
+		.reg = EXT_CTRL_REG,
+		.mask = EMI_FSMC_DYNAMIC_MUX_MASK,
+		.val = EMI_FSMC_DYNAMIC_MUX_MASK,
+	},
+};
+
+static struct spear_modemux emi_modemux[] = {
+	{
+		.modes = AUTO_EXP_MODE | EXTENDED_MODE,
+		.muxregs = emi_muxreg,
+		.nmuxregs = ARRAY_SIZE(emi_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = emi_ext_muxreg,
+		.nmuxregs = ARRAY_SIZE(emi_ext_muxreg),
+	},
+};
+
+static struct spear_pingroup emi_pingroup = {
+	.name = "emi_grp",
+	.pins = emi_pins,
+	.npins = ARRAY_SIZE(emi_pins),
+	.modemuxs = emi_modemux,
+	.nmodemuxs = ARRAY_SIZE(emi_modemux),
+};
+
+static const char *const emi_grps[] = { "emi_grp" };
+static struct spear_function emi_function = {
+	.name = "emi",
+	.groups = emi_grps,
+	.ngroups = ARRAY_SIZE(emi_grps),
+};
+
+/* Pad multiplexing for FSMC (NAND flash) device */
+static const unsigned fsmc_8bit_pins[] = { 52, 53, 54, 55, 56, 57, 58, 59, 60,
+	61, 62, 63, 64, 65, 66, 67, 68 };
+static struct spear_muxreg fsmc_8bit_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_50_59_REG,
+		.mask = PMX_PL_52_53_MASK | PMX_PL_54_55_56_MASK |
+			PMX_PL_57_MASK | PMX_PL_58_59_MASK,
+		.val = PMX_FSMC_PL_52_53_VAL | PMX_FSMC_EMI_PL_54_55_56_VAL |
+			PMX_FSMC_PL_57_VAL | PMX_FSMC_EMI_PL_58_59_VAL,
+	}, {
+		.reg = IP_SEL_PAD_60_69_REG,
+		.mask = PMX_PL_60_MASK | PMX_PL_61_TO_64_MASK |
+			PMX_PL_65_TO_68_MASK,
+		.val = PMX_FSMC_PL_60_VAL | PMX_FSMC_PL_61_TO_64_VAL |
+			PMX_FSMC_PL_65_TO_68_VAL,
+	}, {
+		.reg = EXT_CTRL_REG,
+		.mask = EMI_FSMC_DYNAMIC_MUX_MASK,
+		.val = EMI_FSMC_DYNAMIC_MUX_MASK,
+	},
+};
+
+static struct spear_modemux fsmc_8bit_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = fsmc_8bit_muxreg,
+		.nmuxregs = ARRAY_SIZE(fsmc_8bit_muxreg),
+	},
+};
+
+static struct spear_pingroup fsmc_8bit_pingroup = {
+	.name = "fsmc_8bit_grp",
+	.pins = fsmc_8bit_pins,
+	.npins = ARRAY_SIZE(fsmc_8bit_pins),
+	.modemuxs = fsmc_8bit_modemux,
+	.nmodemuxs = ARRAY_SIZE(fsmc_8bit_modemux),
+};
+
+static const unsigned fsmc_16bit_pins[] = { 46, 47, 48, 49, 52, 53, 54, 55, 56,
+	57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73 };
+static struct spear_muxreg fsmc_16bit_autoexp_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg fsmc_16bit_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_46_47_MASK | PMX_PL_48_49_MASK,
+		.val = PMX_FSMC_EMI_PL_46_47_VAL | PMX_FSMC_EMI_PL_48_49_VAL,
+	}, {
+		.reg = IP_SEL_PAD_70_79_REG,
+		.mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK,
+		.val = PMX_FSMC_EMI_PL_70_VAL | PMX_FSMC_EMI_PL_71_72_VAL |
+			PMX_FSMC_EMI_PL_73_VAL,
+	}
+};
+
+static struct spear_modemux fsmc_16bit_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = fsmc_8bit_muxreg,
+		.nmuxregs = ARRAY_SIZE(fsmc_8bit_muxreg),
+	}, {
+		.modes = AUTO_EXP_MODE | EXTENDED_MODE,
+		.muxregs = fsmc_16bit_autoexp_muxreg,
+		.nmuxregs = ARRAY_SIZE(fsmc_16bit_autoexp_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = fsmc_16bit_muxreg,
+		.nmuxregs = ARRAY_SIZE(fsmc_16bit_muxreg),
+	},
+};
+
+static struct spear_pingroup fsmc_16bit_pingroup = {
+	.name = "fsmc_16bit_grp",
+	.pins = fsmc_16bit_pins,
+	.npins = ARRAY_SIZE(fsmc_16bit_pins),
+	.modemuxs = fsmc_16bit_modemux,
+	.nmodemuxs = ARRAY_SIZE(fsmc_16bit_modemux),
+};
+
+static const char *const fsmc_grps[] = { "fsmc_8bit_grp", "fsmc_16bit_grp" };
+static struct spear_function fsmc_function = {
+	.name = "fsmc",
+	.groups = fsmc_grps,
+	.ngroups = ARRAY_SIZE(fsmc_grps),
+};
+
+/* Pad multiplexing for SPP device */
+static const unsigned spp_pins[] = { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+	80, 81, 82, 83, 84, 85 };
+static struct spear_muxreg spp_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_60_69_REG,
+		.mask = PMX_PL_69_MASK,
+		.val = PMX_SPP_PL_69_VAL,
+	}, {
+		.reg = IP_SEL_PAD_70_79_REG,
+		.mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK |
+			PMX_PL_74_MASK | PMX_PL_75_76_MASK |
+			PMX_PL_77_78_79_MASK,
+		.val = PMX_SPP_PL_70_VAL | PMX_SPP_PL_71_72_VAL |
+			PMX_SPP_PL_73_VAL | PMX_SPP_PL_74_VAL |
+			PMX_SPP_PL_75_76_VAL | PMX_SPP_PL_77_78_79_VAL,
+	}, {
+		.reg = IP_SEL_PAD_80_89_REG,
+		.mask = PMX_PL_80_TO_85_MASK,
+		.val = PMX_SPP_PL_80_TO_85_VAL,
+	},
+};
+
+static struct spear_modemux spp_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = spp_muxreg,
+		.nmuxregs = ARRAY_SIZE(spp_muxreg),
+	},
+};
+
+static struct spear_pingroup spp_pingroup = {
+	.name = "spp_grp",
+	.pins = spp_pins,
+	.npins = ARRAY_SIZE(spp_pins),
+	.modemuxs = spp_modemux,
+	.nmodemuxs = ARRAY_SIZE(spp_modemux),
+};
+
+static const char *const spp_grps[] = { "spp_grp" };
+static struct spear_function spp_function = {
+	.name = "spp",
+	.groups = spp_grps,
+	.ngroups = ARRAY_SIZE(spp_grps),
+};
+
+/* Pad multiplexing for SDHCI device */
+static const unsigned sdhci_led_pins[] = { 34 };
+static struct spear_muxreg sdhci_led_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_CS_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg sdhci_led_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_34_MASK,
+		.val = PMX_PWM2_PL_34_VAL,
+	},
+};
+
+static struct spear_modemux sdhci_led_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+		.muxregs = sdhci_led_muxreg,
+		.nmuxregs = ARRAY_SIZE(sdhci_led_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = sdhci_led_ext_muxreg,
+		.nmuxregs = ARRAY_SIZE(sdhci_led_ext_muxreg),
+	},
+};
+
+static struct spear_pingroup sdhci_led_pingroup = {
+	.name = "sdhci_led_grp",
+	.pins = sdhci_led_pins,
+	.npins = ARRAY_SIZE(sdhci_led_pins),
+	.modemuxs = sdhci_led_modemux,
+	.nmodemuxs = ARRAY_SIZE(sdhci_led_modemux),
+};
+
+static const unsigned sdhci_cd_12_pins[] = { 12, 43, 44, 45, 46, 47, 48, 49,
+	50};
+static const unsigned sdhci_cd_51_pins[] = { 43, 44, 45, 46, 47, 48, 49, 50, 51
+};
+static struct spear_muxreg sdhci_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg sdhci_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK | PMX_PL_46_47_MASK |
+			PMX_PL_48_49_MASK,
+		.val = PMX_SDHCI_PL_43_VAL | PMX_SDHCI_PL_44_45_VAL |
+			PMX_SDHCI_PL_46_47_VAL | PMX_SDHCI_PL_48_49_VAL,
+	}, {
+		.reg = IP_SEL_PAD_50_59_REG,
+		.mask = PMX_PL_50_MASK,
+		.val = PMX_SDHCI_PL_50_VAL,
+	}, {
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_99_MASK,
+		.val = PMX_SDHCI_PL_99_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_PL_100_101_MASK,
+		.val = PMX_SDHCI_PL_100_101_VAL,
+	},
+};
+
+static struct spear_muxreg sdhci_cd_12_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_12_MASK,
+		.val = PMX_SDHCI_CD_PL_12_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SDHCI_CD_PORT_SEL_MASK,
+		.val = PMX_SDHCI_CD_PORT_12_VAL,
+	},
+};
+
+static struct spear_muxreg sdhci_cd_51_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_50_59_REG,
+		.mask = PMX_PL_51_MASK,
+		.val = PMX_SDHCI_CD_PL_51_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SDHCI_CD_PORT_SEL_MASK,
+		.val = PMX_SDHCI_CD_PORT_51_VAL,
+	},
+};
+
+#define pmx_sdhci_common_modemux					\
+	{								\
+		.modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE |	\
+			SMALL_PRINTERS_MODE | EXTENDED_MODE,		\
+		.muxregs = sdhci_muxreg,				\
+		.nmuxregs = ARRAY_SIZE(sdhci_muxreg),			\
+	}, {								\
+		.modes = EXTENDED_MODE,					\
+		.muxregs = sdhci_ext_muxreg,				\
+		.nmuxregs = ARRAY_SIZE(sdhci_ext_muxreg),		\
+	}
+
+static struct spear_modemux sdhci_modemux[][3] = {
+	{
+		/* select pin 12 for cd */
+		pmx_sdhci_common_modemux,
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = sdhci_cd_12_muxreg,
+			.nmuxregs = ARRAY_SIZE(sdhci_cd_12_muxreg),
+		},
+	}, {
+		/* select pin 51 for cd */
+		pmx_sdhci_common_modemux,
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = sdhci_cd_51_muxreg,
+			.nmuxregs = ARRAY_SIZE(sdhci_cd_51_muxreg),
+		},
+	}
+};
+
+static struct spear_pingroup sdhci_pingroup[] = {
+	{
+		.name = "sdhci_cd_12_grp",
+		.pins = sdhci_cd_12_pins,
+		.npins = ARRAY_SIZE(sdhci_cd_12_pins),
+		.modemuxs = sdhci_modemux[0],
+		.nmodemuxs = ARRAY_SIZE(sdhci_modemux[0]),
+	}, {
+		.name = "sdhci_cd_51_grp",
+		.pins = sdhci_cd_51_pins,
+		.npins = ARRAY_SIZE(sdhci_cd_51_pins),
+		.modemuxs = sdhci_modemux[1],
+		.nmodemuxs = ARRAY_SIZE(sdhci_modemux[1]),
+	},
+};
+
+static const char *const sdhci_grps[] = { "sdhci_cd_12_grp", "sdhci_cd_51_grp",
+	"sdhci_led_grp" };
+
+static struct spear_function sdhci_function = {
+	.name = "sdhci",
+	.groups = sdhci_grps,
+	.ngroups = ARRAY_SIZE(sdhci_grps),
+};
+
+/* Pad multiplexing for I2S device */
+static const unsigned i2s_pins[] = { 35, 39, 40, 41, 42 };
+static struct spear_muxreg i2s_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_CS_MASK,
+		.val = 0,
+	}, {
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg i2s_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_35_MASK | PMX_PL_39_MASK,
+		.val = PMX_I2S_REF_CLK_PL_35_VAL | PMX_I2S_PL_39_VAL,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_40_MASK | PMX_PL_41_42_MASK,
+		.val = PMX_I2S_PL_40_VAL | PMX_I2S_PL_41_42_VAL,
+	},
+};
+
+static struct spear_modemux i2s_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+		.muxregs = i2s_muxreg,
+		.nmuxregs = ARRAY_SIZE(i2s_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = i2s_ext_muxreg,
+		.nmuxregs = ARRAY_SIZE(i2s_ext_muxreg),
+	},
+};
+
+static struct spear_pingroup i2s_pingroup = {
+	.name = "i2s_grp",
+	.pins = i2s_pins,
+	.npins = ARRAY_SIZE(i2s_pins),
+	.modemuxs = i2s_modemux,
+	.nmodemuxs = ARRAY_SIZE(i2s_modemux),
+};
+
+static const char *const i2s_grps[] = { "i2s_grp" };
+static struct spear_function i2s_function = {
+	.name = "i2s",
+	.groups = i2s_grps,
+	.ngroups = ARRAY_SIZE(i2s_grps),
+};
+
+/* Pad multiplexing for UART1 device */
+static const unsigned uart1_pins[] = { 28, 29 };
+static struct spear_muxreg uart1_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg uart1_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_20_29_REG,
+		.mask = PMX_PL_28_29_MASK,
+		.val = PMX_UART1_PL_28_29_VAL,
+	},
+};
+
+static struct spear_modemux uart1_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+			| SMALL_PRINTERS_MODE | EXTENDED_MODE,
+		.muxregs = uart1_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart1_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = uart1_ext_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart1_ext_muxreg),
+	},
+};
+
+static struct spear_pingroup uart1_pingroup = {
+	.name = "uart1_grp",
+	.pins = uart1_pins,
+	.npins = ARRAY_SIZE(uart1_pins),
+	.modemuxs = uart1_modemux,
+	.nmodemuxs = ARRAY_SIZE(uart1_modemux),
+};
+
+static const char *const uart1_grps[] = { "uart1_grp" };
+static struct spear_function uart1_function = {
+	.name = "uart1",
+	.groups = uart1_grps,
+	.ngroups = ARRAY_SIZE(uart1_grps),
+};
+
+/* Pad multiplexing for UART1 Modem device */
+static const unsigned uart1_modem_2_to_7_pins[] = { 2, 3, 4, 5, 6, 7 };
+static const unsigned uart1_modem_31_to_36_pins[] = { 31, 32, 33, 34, 35, 36 };
+static const unsigned uart1_modem_34_to_45_pins[] = { 34, 35, 36, 43, 44, 45 };
+static const unsigned uart1_modem_80_to_85_pins[] = { 80, 81, 82, 83, 84, 85 };
+
+static struct spear_muxreg uart1_modem_ext_2_to_7_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MASK | PMX_I2C_MASK | PMX_SSP_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_2_3_MASK | PMX_PL_6_7_MASK,
+		.val = PMX_UART1_ENH_PL_2_3_VAL | PMX_UART1_ENH_PL_4_5_VAL |
+			PMX_UART1_ENH_PL_6_7_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART1_ENH_PORT_SEL_MASK,
+		.val = PMX_UART1_ENH_PORT_3_TO_5_7_VAL,
+	},
+};
+
+static struct spear_muxreg uart1_modem_31_to_36_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_GPIO_PIN3_MASK | PMX_GPIO_PIN4_MASK |
+			PMX_GPIO_PIN5_MASK | PMX_SSP_CS_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg uart1_modem_ext_31_to_36_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_31_MASK | PMX_PL_32_33_MASK | PMX_PL_34_MASK |
+			PMX_PL_35_MASK | PMX_PL_36_MASK,
+		.val = PMX_UART1_ENH_PL_31_VAL | PMX_UART1_ENH_PL_32_33_VAL |
+			PMX_UART1_ENH_PL_34_VAL | PMX_UART1_ENH_PL_35_VAL |
+			PMX_UART1_ENH_PL_36_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART1_ENH_PORT_SEL_MASK,
+		.val = PMX_UART1_ENH_PORT_32_TO_34_36_VAL,
+	},
+};
+
+static struct spear_muxreg uart1_modem_34_to_45_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK |
+			PMX_SSP_CS_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg uart1_modem_ext_34_to_45_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_34_MASK | PMX_PL_35_MASK | PMX_PL_36_MASK,
+		.val = PMX_UART1_ENH_PL_34_VAL | PMX_UART1_ENH_PL_35_VAL |
+			PMX_UART1_ENH_PL_36_VAL,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK,
+		.val = PMX_UART1_ENH_PL_43_VAL | PMX_UART1_ENH_PL_44_45_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART1_ENH_PORT_SEL_MASK,
+		.val = PMX_UART1_ENH_PORT_44_45_34_36_VAL,
+	},
+};
+
+static struct spear_muxreg uart1_modem_ext_80_to_85_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_80_89_REG,
+		.mask = PMX_PL_80_TO_85_MASK,
+		.val = PMX_UART1_ENH_PL_80_TO_85_VAL,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK,
+		.val = PMX_UART1_ENH_PL_43_VAL | PMX_UART1_ENH_PL_44_45_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART1_ENH_PORT_SEL_MASK,
+		.val = PMX_UART1_ENH_PORT_81_TO_85_VAL,
+	},
+};
+
+static struct spear_modemux uart1_modem_2_to_7_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = uart1_modem_ext_2_to_7_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart1_modem_ext_2_to_7_muxreg),
+	},
+};
+
+static struct spear_modemux uart1_modem_31_to_36_modemux[] = {
+	{
+		.modes = SMALL_PRINTERS_MODE | EXTENDED_MODE,
+		.muxregs = uart1_modem_31_to_36_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart1_modem_31_to_36_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = uart1_modem_ext_31_to_36_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart1_modem_ext_31_to_36_muxreg),
+	},
+};
+
+static struct spear_modemux uart1_modem_34_to_45_modemux[] = {
+	{
+		.modes = AUTO_EXP_MODE | EXTENDED_MODE,
+		.muxregs = uart1_modem_34_to_45_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart1_modem_34_to_45_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = uart1_modem_ext_34_to_45_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart1_modem_ext_34_to_45_muxreg),
+	},
+};
+
+static struct spear_modemux uart1_modem_80_to_85_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = uart1_modem_ext_80_to_85_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart1_modem_ext_80_to_85_muxreg),
+	},
+};
+
+static struct spear_pingroup uart1_modem_pingroup[] = {
+	{
+		.name = "uart1_modem_2_to_7_grp",
+		.pins = uart1_modem_2_to_7_pins,
+		.npins = ARRAY_SIZE(uart1_modem_2_to_7_pins),
+		.modemuxs = uart1_modem_2_to_7_modemux,
+		.nmodemuxs = ARRAY_SIZE(uart1_modem_2_to_7_modemux),
+	}, {
+		.name = "uart1_modem_31_to_36_grp",
+		.pins = uart1_modem_31_to_36_pins,
+		.npins = ARRAY_SIZE(uart1_modem_31_to_36_pins),
+		.modemuxs = uart1_modem_31_to_36_modemux,
+		.nmodemuxs = ARRAY_SIZE(uart1_modem_31_to_36_modemux),
+	}, {
+		.name = "uart1_modem_34_to_45_grp",
+		.pins = uart1_modem_34_to_45_pins,
+		.npins = ARRAY_SIZE(uart1_modem_34_to_45_pins),
+		.modemuxs = uart1_modem_34_to_45_modemux,
+		.nmodemuxs = ARRAY_SIZE(uart1_modem_34_to_45_modemux),
+	}, {
+		.name = "uart1_modem_80_to_85_grp",
+		.pins = uart1_modem_80_to_85_pins,
+		.npins = ARRAY_SIZE(uart1_modem_80_to_85_pins),
+		.modemuxs = uart1_modem_80_to_85_modemux,
+		.nmodemuxs = ARRAY_SIZE(uart1_modem_80_to_85_modemux),
+	},
+};
+
+static const char *const uart1_modem_grps[] = { "uart1_modem_2_to_7_grp",
+	"uart1_modem_31_to_36_grp", "uart1_modem_34_to_45_grp",
+	"uart1_modem_80_to_85_grp" };
+static struct spear_function uart1_modem_function = {
+	.name = "uart1_modem",
+	.groups = uart1_modem_grps,
+	.ngroups = ARRAY_SIZE(uart1_modem_grps),
+};
+
+/* Pad multiplexing for UART2 device */
+static const unsigned uart2_pins[] = { 0, 1 };
+static struct spear_muxreg uart2_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_FIRDA_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg uart2_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_0_1_MASK,
+		.val = PMX_UART2_PL_0_1_VAL,
+	},
+};
+
+static struct spear_modemux uart2_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+			| SMALL_PRINTERS_MODE | EXTENDED_MODE,
+		.muxregs = uart2_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart2_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = uart2_ext_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart2_ext_muxreg),
+	},
+};
+
+static struct spear_pingroup uart2_pingroup = {
+	.name = "uart2_grp",
+	.pins = uart2_pins,
+	.npins = ARRAY_SIZE(uart2_pins),
+	.modemuxs = uart2_modemux,
+	.nmodemuxs = ARRAY_SIZE(uart2_modemux),
+};
+
+static const char *const uart2_grps[] = { "uart2_grp" };
+static struct spear_function uart2_function = {
+	.name = "uart2",
+	.groups = uart2_grps,
+	.ngroups = ARRAY_SIZE(uart2_grps),
+};
+
+/* Pad multiplexing for uart3 device */
+static const unsigned uart3_pins[][2] = { { 8, 9 }, { 15, 16 }, { 41, 42 },
+	{ 52, 53 }, { 73, 74 }, { 94, 95 }, { 98, 99 } };
+
+static struct spear_muxreg uart3_ext_8_9_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_8_9_MASK,
+		.val = PMX_UART3_PL_8_9_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART3_PORT_SEL_MASK,
+		.val = PMX_UART3_PORT_8_VAL,
+	},
+};
+
+static struct spear_muxreg uart3_ext_15_16_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_15_16_MASK,
+		.val = PMX_UART3_PL_15_16_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART3_PORT_SEL_MASK,
+		.val = PMX_UART3_PORT_15_VAL,
+	},
+};
+
+static struct spear_muxreg uart3_ext_41_42_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_41_42_MASK,
+		.val = PMX_UART3_PL_41_42_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART3_PORT_SEL_MASK,
+		.val = PMX_UART3_PORT_41_VAL,
+	},
+};
+
+static struct spear_muxreg uart3_ext_52_53_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_50_59_REG,
+		.mask = PMX_PL_52_53_MASK,
+		.val = PMX_UART3_PL_52_53_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART3_PORT_SEL_MASK,
+		.val = PMX_UART3_PORT_52_VAL,
+	},
+};
+
+static struct spear_muxreg uart3_ext_73_74_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_70_79_REG,
+		.mask = PMX_PL_73_MASK | PMX_PL_74_MASK,
+		.val = PMX_UART3_PL_73_VAL | PMX_UART3_PL_74_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART3_PORT_SEL_MASK,
+		.val = PMX_UART3_PORT_73_VAL,
+	},
+};
+
+static struct spear_muxreg uart3_ext_94_95_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_94_95_MASK,
+		.val = PMX_UART3_PL_94_95_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART3_PORT_SEL_MASK,
+		.val = PMX_UART3_PORT_94_VAL,
+	},
+};
+
+static struct spear_muxreg uart3_ext_98_99_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_98_MASK | PMX_PL_99_MASK,
+		.val = PMX_UART3_PL_98_VAL | PMX_UART3_PL_99_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART3_PORT_SEL_MASK,
+		.val = PMX_UART3_PORT_99_VAL,
+	},
+};
+
+static struct spear_modemux uart3_modemux[][1] = {
+	{
+		/* Select signals on pins 8_9 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart3_ext_8_9_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart3_ext_8_9_muxreg),
+		},
+	}, {
+		/* Select signals on pins 15_16 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart3_ext_15_16_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart3_ext_15_16_muxreg),
+		},
+	}, {
+		/* Select signals on pins 41_42 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart3_ext_41_42_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart3_ext_41_42_muxreg),
+		},
+	}, {
+		/* Select signals on pins 52_53 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart3_ext_52_53_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart3_ext_52_53_muxreg),
+		},
+	}, {
+		/* Select signals on pins 73_74 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart3_ext_73_74_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart3_ext_73_74_muxreg),
+		},
+	}, {
+		/* Select signals on pins 94_95 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart3_ext_94_95_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart3_ext_94_95_muxreg),
+		},
+	}, {
+		/* Select signals on pins 98_99 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart3_ext_98_99_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart3_ext_98_99_muxreg),
+		},
+	},
+};
+
+static struct spear_pingroup uart3_pingroup[] = {
+	{
+		.name = "uart3_8_9_grp",
+		.pins = uart3_pins[0],
+		.npins = ARRAY_SIZE(uart3_pins[0]),
+		.modemuxs = uart3_modemux[0],
+		.nmodemuxs = ARRAY_SIZE(uart3_modemux[0]),
+	}, {
+		.name = "uart3_15_16_grp",
+		.pins = uart3_pins[1],
+		.npins = ARRAY_SIZE(uart3_pins[1]),
+		.modemuxs = uart3_modemux[1],
+		.nmodemuxs = ARRAY_SIZE(uart3_modemux[1]),
+	}, {
+		.name = "uart3_41_42_grp",
+		.pins = uart3_pins[2],
+		.npins = ARRAY_SIZE(uart3_pins[2]),
+		.modemuxs = uart3_modemux[2],
+		.nmodemuxs = ARRAY_SIZE(uart3_modemux[2]),
+	}, {
+		.name = "uart3_52_53_grp",
+		.pins = uart3_pins[3],
+		.npins = ARRAY_SIZE(uart3_pins[3]),
+		.modemuxs = uart3_modemux[3],
+		.nmodemuxs = ARRAY_SIZE(uart3_modemux[3]),
+	}, {
+		.name = "uart3_73_74_grp",
+		.pins = uart3_pins[4],
+		.npins = ARRAY_SIZE(uart3_pins[4]),
+		.modemuxs = uart3_modemux[4],
+		.nmodemuxs = ARRAY_SIZE(uart3_modemux[4]),
+	}, {
+		.name = "uart3_94_95_grp",
+		.pins = uart3_pins[5],
+		.npins = ARRAY_SIZE(uart3_pins[5]),
+		.modemuxs = uart3_modemux[5],
+		.nmodemuxs = ARRAY_SIZE(uart3_modemux[5]),
+	}, {
+		.name = "uart3_98_99_grp",
+		.pins = uart3_pins[6],
+		.npins = ARRAY_SIZE(uart3_pins[6]),
+		.modemuxs = uart3_modemux[6],
+		.nmodemuxs = ARRAY_SIZE(uart3_modemux[6]),
+	},
+};
+
+static const char *const uart3_grps[] = { "uart3_8_9_grp", "uart3_15_16_grp",
+	"uart3_41_42_grp", "uart3_52_53_grp", "uart3_73_74_grp",
+	"uart3_94_95_grp", "uart3_98_99_grp" };
+
+static struct spear_function uart3_function = {
+	.name = "uart3",
+	.groups = uart3_grps,
+	.ngroups = ARRAY_SIZE(uart3_grps),
+};
+
+/* Pad multiplexing for uart4 device */
+static const unsigned uart4_pins[][2] = { { 6, 7 }, { 13, 14 }, { 39, 40 },
+	{ 71, 72 }, { 92, 93 }, { 100, 101 } };
+
+static struct spear_muxreg uart4_ext_6_7_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_6_7_MASK,
+		.val = PMX_UART4_PL_6_7_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART4_PORT_SEL_MASK,
+		.val = PMX_UART4_PORT_6_VAL,
+	},
+};
+
+static struct spear_muxreg uart4_ext_13_14_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_13_14_MASK,
+		.val = PMX_UART4_PL_13_14_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART4_PORT_SEL_MASK,
+		.val = PMX_UART4_PORT_13_VAL,
+	},
+};
+
+static struct spear_muxreg uart4_ext_39_40_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_39_MASK,
+		.val = PMX_UART4_PL_39_VAL,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_40_MASK,
+		.val = PMX_UART4_PL_40_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART4_PORT_SEL_MASK,
+		.val = PMX_UART4_PORT_39_VAL,
+	},
+};
+
+static struct spear_muxreg uart4_ext_71_72_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_70_79_REG,
+		.mask = PMX_PL_71_72_MASK,
+		.val = PMX_UART4_PL_71_72_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART4_PORT_SEL_MASK,
+		.val = PMX_UART4_PORT_71_VAL,
+	},
+};
+
+static struct spear_muxreg uart4_ext_92_93_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_92_93_MASK,
+		.val = PMX_UART4_PL_92_93_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART4_PORT_SEL_MASK,
+		.val = PMX_UART4_PORT_92_VAL,
+	},
+};
+
+static struct spear_muxreg uart4_ext_100_101_muxreg[] = {
+	{
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_PL_100_101_MASK |
+			PMX_UART4_PORT_SEL_MASK,
+		.val = PMX_UART4_PL_100_101_VAL |
+			PMX_UART4_PORT_101_VAL,
+	},
+};
+
+static struct spear_modemux uart4_modemux[][1] = {
+	{
+		/* Select signals on pins 6_7 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart4_ext_6_7_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart4_ext_6_7_muxreg),
+		},
+	}, {
+		/* Select signals on pins 13_14 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart4_ext_13_14_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart4_ext_13_14_muxreg),
+		},
+	}, {
+		/* Select signals on pins 39_40 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart4_ext_39_40_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart4_ext_39_40_muxreg),
+		},
+	}, {
+		/* Select signals on pins 71_72 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart4_ext_71_72_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart4_ext_71_72_muxreg),
+		},
+	}, {
+		/* Select signals on pins 92_93 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart4_ext_92_93_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart4_ext_92_93_muxreg),
+		},
+	}, {
+		/* Select signals on pins 100_101_ */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart4_ext_100_101_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart4_ext_100_101_muxreg),
+		},
+	},
+};
+
+static struct spear_pingroup uart4_pingroup[] = {
+	{
+		.name = "uart4_6_7_grp",
+		.pins = uart4_pins[0],
+		.npins = ARRAY_SIZE(uart4_pins[0]),
+		.modemuxs = uart4_modemux[0],
+		.nmodemuxs = ARRAY_SIZE(uart4_modemux[0]),
+	}, {
+		.name = "uart4_13_14_grp",
+		.pins = uart4_pins[1],
+		.npins = ARRAY_SIZE(uart4_pins[1]),
+		.modemuxs = uart4_modemux[1],
+		.nmodemuxs = ARRAY_SIZE(uart4_modemux[1]),
+	}, {
+		.name = "uart4_39_40_grp",
+		.pins = uart4_pins[2],
+		.npins = ARRAY_SIZE(uart4_pins[2]),
+		.modemuxs = uart4_modemux[2],
+		.nmodemuxs = ARRAY_SIZE(uart4_modemux[2]),
+	}, {
+		.name = "uart4_71_72_grp",
+		.pins = uart4_pins[3],
+		.npins = ARRAY_SIZE(uart4_pins[3]),
+		.modemuxs = uart4_modemux[3],
+		.nmodemuxs = ARRAY_SIZE(uart4_modemux[3]),
+	}, {
+		.name = "uart4_92_93_grp",
+		.pins = uart4_pins[4],
+		.npins = ARRAY_SIZE(uart4_pins[4]),
+		.modemuxs = uart4_modemux[4],
+		.nmodemuxs = ARRAY_SIZE(uart4_modemux[4]),
+	}, {
+		.name = "uart4_100_101_grp",
+		.pins = uart4_pins[5],
+		.npins = ARRAY_SIZE(uart4_pins[5]),
+		.modemuxs = uart4_modemux[5],
+		.nmodemuxs = ARRAY_SIZE(uart4_modemux[5]),
+	},
+};
+
+static const char *const uart4_grps[] = { "uart4_6_7_grp", "uart4_13_14_grp",
+	"uart4_39_40_grp", "uart4_71_72_grp", "uart4_92_93_grp",
+	"uart4_100_101_grp" };
+
+static struct spear_function uart4_function = {
+	.name = "uart4",
+	.groups = uart4_grps,
+	.ngroups = ARRAY_SIZE(uart4_grps),
+};
+
+/* Pad multiplexing for uart5 device */
+static const unsigned uart5_pins[][2] = { { 4, 5 }, { 37, 38 }, { 69, 70 },
+	{ 90, 91 } };
+
+static struct spear_muxreg uart5_ext_4_5_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_I2C_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_4_5_MASK,
+		.val = PMX_UART5_PL_4_5_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART5_PORT_SEL_MASK,
+		.val = PMX_UART5_PORT_4_VAL,
+	},
+};
+
+static struct spear_muxreg uart5_ext_37_38_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_37_38_MASK,
+		.val = PMX_UART5_PL_37_38_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART5_PORT_SEL_MASK,
+		.val = PMX_UART5_PORT_37_VAL,
+	},
+};
+
+static struct spear_muxreg uart5_ext_69_70_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_60_69_REG,
+		.mask = PMX_PL_69_MASK,
+		.val = PMX_UART5_PL_69_VAL,
+	}, {
+		.reg = IP_SEL_PAD_70_79_REG,
+		.mask = PMX_PL_70_MASK,
+		.val = PMX_UART5_PL_70_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART5_PORT_SEL_MASK,
+		.val = PMX_UART5_PORT_69_VAL,
+	},
+};
+
+static struct spear_muxreg uart5_ext_90_91_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_90_91_MASK,
+		.val = PMX_UART5_PL_90_91_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART5_PORT_SEL_MASK,
+		.val = PMX_UART5_PORT_90_VAL,
+	},
+};
+
+static struct spear_modemux uart5_modemux[][1] = {
+	{
+		/* Select signals on pins 4_5 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart5_ext_4_5_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart5_ext_4_5_muxreg),
+		},
+	}, {
+		/* Select signals on pins 37_38 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart5_ext_37_38_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart5_ext_37_38_muxreg),
+		},
+	}, {
+		/* Select signals on pins 69_70 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart5_ext_69_70_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart5_ext_69_70_muxreg),
+		},
+	}, {
+		/* Select signals on pins 90_91 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart5_ext_90_91_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart5_ext_90_91_muxreg),
+		},
+	},
+};
+
+static struct spear_pingroup uart5_pingroup[] = {
+	{
+		.name = "uart5_4_5_grp",
+		.pins = uart5_pins[0],
+		.npins = ARRAY_SIZE(uart5_pins[0]),
+		.modemuxs = uart5_modemux[0],
+		.nmodemuxs = ARRAY_SIZE(uart5_modemux[0]),
+	}, {
+		.name = "uart5_37_38_grp",
+		.pins = uart5_pins[1],
+		.npins = ARRAY_SIZE(uart5_pins[1]),
+		.modemuxs = uart5_modemux[1],
+		.nmodemuxs = ARRAY_SIZE(uart5_modemux[1]),
+	}, {
+		.name = "uart5_69_70_grp",
+		.pins = uart5_pins[2],
+		.npins = ARRAY_SIZE(uart5_pins[2]),
+		.modemuxs = uart5_modemux[2],
+		.nmodemuxs = ARRAY_SIZE(uart5_modemux[2]),
+	}, {
+		.name = "uart5_90_91_grp",
+		.pins = uart5_pins[3],
+		.npins = ARRAY_SIZE(uart5_pins[3]),
+		.modemuxs = uart5_modemux[3],
+		.nmodemuxs = ARRAY_SIZE(uart5_modemux[3]),
+	},
+};
+
+static const char *const uart5_grps[] = { "uart5_4_5_grp", "uart5_37_38_grp",
+	"uart5_69_70_grp", "uart5_90_91_grp" };
+static struct spear_function uart5_function = {
+	.name = "uart5",
+	.groups = uart5_grps,
+	.ngroups = ARRAY_SIZE(uart5_grps),
+};
+
+/* Pad multiplexing for uart6 device */
+static const unsigned uart6_pins[][2] = { { 2, 3 }, { 88, 89 } };
+static struct spear_muxreg uart6_ext_2_3_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_2_3_MASK,
+		.val = PMX_UART6_PL_2_3_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART6_PORT_SEL_MASK,
+		.val = PMX_UART6_PORT_2_VAL,
+	},
+};
+
+static struct spear_muxreg uart6_ext_88_89_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_80_89_REG,
+		.mask = PMX_PL_88_89_MASK,
+		.val = PMX_UART6_PL_88_89_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_UART6_PORT_SEL_MASK,
+		.val = PMX_UART6_PORT_88_VAL,
+	},
+};
+
+static struct spear_modemux uart6_modemux[][1] = {
+	{
+		/* Select signals on pins 2_3 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart6_ext_2_3_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart6_ext_2_3_muxreg),
+		},
+	}, {
+		/* Select signals on pins 88_89 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = uart6_ext_88_89_muxreg,
+			.nmuxregs = ARRAY_SIZE(uart6_ext_88_89_muxreg),
+		},
+	},
+};
+
+static struct spear_pingroup uart6_pingroup[] = {
+	{
+		.name = "uart6_2_3_grp",
+		.pins = uart6_pins[0],
+		.npins = ARRAY_SIZE(uart6_pins[0]),
+		.modemuxs = uart6_modemux[0],
+		.nmodemuxs = ARRAY_SIZE(uart6_modemux[0]),
+	}, {
+		.name = "uart6_88_89_grp",
+		.pins = uart6_pins[1],
+		.npins = ARRAY_SIZE(uart6_pins[1]),
+		.modemuxs = uart6_modemux[1],
+		.nmodemuxs = ARRAY_SIZE(uart6_modemux[1]),
+	},
+};
+
+static const char *const uart6_grps[] = { "uart6_2_3_grp", "uart6_88_89_grp" };
+static struct spear_function uart6_function = {
+	.name = "uart6",
+	.groups = uart6_grps,
+	.ngroups = ARRAY_SIZE(uart6_grps),
+};
+
+/* UART - RS485 pmx */
+static const unsigned rs485_pins[] = { 77, 78, 79 };
+static struct spear_muxreg rs485_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_70_79_REG,
+		.mask = PMX_PL_77_78_79_MASK,
+		.val = PMX_RS485_PL_77_78_79_VAL,
+	},
+};
+
+static struct spear_modemux rs485_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = rs485_muxreg,
+		.nmuxregs = ARRAY_SIZE(rs485_muxreg),
+	},
+};
+
+static struct spear_pingroup rs485_pingroup = {
+	.name = "rs485_grp",
+	.pins = rs485_pins,
+	.npins = ARRAY_SIZE(rs485_pins),
+	.modemuxs = rs485_modemux,
+	.nmodemuxs = ARRAY_SIZE(rs485_modemux),
+};
+
+static const char *const rs485_grps[] = { "rs485_grp" };
+static struct spear_function rs485_function = {
+	.name = "rs485",
+	.groups = rs485_grps,
+	.ngroups = ARRAY_SIZE(rs485_grps),
+};
+
+/* Pad multiplexing for Touchscreen device */
+static const unsigned touchscreen_pins[] = { 5, 36 };
+static struct spear_muxreg touchscreen_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_I2C_MASK | PMX_SSP_CS_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg touchscreen_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_5_MASK,
+		.val = PMX_TOUCH_Y_PL_5_VAL,
+	}, {
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_36_MASK,
+		.val = PMX_TOUCH_X_PL_36_VAL,
+	},
+};
+
+static struct spear_modemux touchscreen_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | EXTENDED_MODE,
+		.muxregs = touchscreen_muxreg,
+		.nmuxregs = ARRAY_SIZE(touchscreen_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = touchscreen_ext_muxreg,
+		.nmuxregs = ARRAY_SIZE(touchscreen_ext_muxreg),
+	},
+};
+
+static struct spear_pingroup touchscreen_pingroup = {
+	.name = "touchscreen_grp",
+	.pins = touchscreen_pins,
+	.npins = ARRAY_SIZE(touchscreen_pins),
+	.modemuxs = touchscreen_modemux,
+	.nmodemuxs = ARRAY_SIZE(touchscreen_modemux),
+};
+
+static const char *const touchscreen_grps[] = { "touchscreen_grp" };
+static struct spear_function touchscreen_function = {
+	.name = "touchscreen",
+	.groups = touchscreen_grps,
+	.ngroups = ARRAY_SIZE(touchscreen_grps),
+};
+
+/* Pad multiplexing for CAN device */
+static const unsigned can0_pins[] = { 32, 33 };
+static struct spear_muxreg can0_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg can0_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_32_33_MASK,
+		.val = PMX_CAN0_PL_32_33_VAL,
+	},
+};
+
+static struct spear_modemux can0_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+			| EXTENDED_MODE,
+		.muxregs = can0_muxreg,
+		.nmuxregs = ARRAY_SIZE(can0_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = can0_ext_muxreg,
+		.nmuxregs = ARRAY_SIZE(can0_ext_muxreg),
+	},
+};
+
+static struct spear_pingroup can0_pingroup = {
+	.name = "can0_grp",
+	.pins = can0_pins,
+	.npins = ARRAY_SIZE(can0_pins),
+	.modemuxs = can0_modemux,
+	.nmodemuxs = ARRAY_SIZE(can0_modemux),
+};
+
+static const char *const can0_grps[] = { "can0_grp" };
+static struct spear_function can0_function = {
+	.name = "can0",
+	.groups = can0_grps,
+	.ngroups = ARRAY_SIZE(can0_grps),
+};
+
+static const unsigned can1_pins[] = { 30, 31 };
+static struct spear_muxreg can1_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg can1_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_30_31_MASK,
+		.val = PMX_CAN1_PL_30_31_VAL,
+	},
+};
+
+static struct spear_modemux can1_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+			| EXTENDED_MODE,
+		.muxregs = can1_muxreg,
+		.nmuxregs = ARRAY_SIZE(can1_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = can1_ext_muxreg,
+		.nmuxregs = ARRAY_SIZE(can1_ext_muxreg),
+	},
+};
+
+static struct spear_pingroup can1_pingroup = {
+	.name = "can1_grp",
+	.pins = can1_pins,
+	.npins = ARRAY_SIZE(can1_pins),
+	.modemuxs = can1_modemux,
+	.nmodemuxs = ARRAY_SIZE(can1_modemux),
+};
+
+static const char *const can1_grps[] = { "can1_grp" };
+static struct spear_function can1_function = {
+	.name = "can1",
+	.groups = can1_grps,
+	.ngroups = ARRAY_SIZE(can1_grps),
+};
+
+/* Pad multiplexing for PWM0_1 device */
+static const unsigned pwm0_1_pins[][2] = { { 37, 38 }, { 14, 15 }, { 8, 9 },
+	{ 30, 31 }, { 42, 43 }, { 59, 60 }, { 88, 89 } };
+
+static struct spear_muxreg pwm0_1_pin_8_9_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_8_9_MASK,
+		.val = PMX_PWM_0_1_PL_8_9_VAL,
+	},
+};
+
+static struct spear_muxreg pwm0_1_autoexpsmallpri_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg pwm0_1_pin_14_15_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_14_MASK | PMX_PL_15_MASK,
+		.val = PMX_PWM1_PL_14_VAL | PMX_PWM0_PL_15_VAL,
+	},
+};
+
+static struct spear_muxreg pwm0_1_pin_30_31_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_30_MASK | PMX_PL_31_MASK,
+		.val = PMX_PWM1_EXT_PL_30_VAL | PMX_PWM0_EXT_PL_31_VAL,
+	},
+};
+
+static struct spear_muxreg pwm0_1_net_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg pwm0_1_pin_37_38_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_37_38_MASK,
+		.val = PMX_PWM0_1_PL_37_38_VAL,
+	},
+};
+
+static struct spear_muxreg pwm0_1_pin_42_43_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK | PMX_TIMER_0_1_MASK ,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_42_MASK | PMX_PL_43_MASK,
+		.val = PMX_PWM1_PL_42_VAL |
+			PMX_PWM0_PL_43_VAL,
+	},
+};
+
+static struct spear_muxreg pwm0_1_pin_59_60_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_50_59_REG,
+		.mask = PMX_PL_59_MASK,
+		.val = PMX_PWM1_PL_59_VAL,
+	}, {
+		.reg = IP_SEL_PAD_60_69_REG,
+		.mask = PMX_PL_60_MASK,
+		.val = PMX_PWM0_PL_60_VAL,
+	},
+};
+
+static struct spear_muxreg pwm0_1_pin_88_89_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_80_89_REG,
+		.mask = PMX_PL_88_89_MASK,
+		.val = PMX_PWM0_1_PL_88_89_VAL,
+	},
+};
+
+static struct spear_modemux pwm0_1_pin_8_9_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm0_1_pin_8_9_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm0_1_pin_8_9_muxreg),
+	},
+};
+
+static struct spear_modemux pwm0_1_pin_14_15_modemux[] = {
+	{
+		.modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+		.muxregs = pwm0_1_autoexpsmallpri_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm0_1_autoexpsmallpri_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm0_1_pin_14_15_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm0_1_pin_14_15_muxreg),
+	},
+};
+
+static struct spear_modemux pwm0_1_pin_30_31_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm0_1_pin_30_31_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm0_1_pin_30_31_muxreg),
+	},
+};
+
+static struct spear_modemux pwm0_1_pin_37_38_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+		.muxregs = pwm0_1_net_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm0_1_net_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm0_1_pin_37_38_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm0_1_pin_37_38_muxreg),
+	},
+};
+
+static struct spear_modemux pwm0_1_pin_42_43_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm0_1_pin_42_43_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm0_1_pin_42_43_muxreg),
+	},
+};
+
+static struct spear_modemux pwm0_1_pin_59_60_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm0_1_pin_59_60_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm0_1_pin_59_60_muxreg),
+	},
+};
+
+static struct spear_modemux pwm0_1_pin_88_89_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm0_1_pin_88_89_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm0_1_pin_88_89_muxreg),
+	},
+};
+
+static struct spear_pingroup pwm0_1_pingroup[] = {
+	{
+		.name = "pwm0_1_pin_8_9_grp",
+		.pins = pwm0_1_pins[0],
+		.npins = ARRAY_SIZE(pwm0_1_pins[0]),
+		.modemuxs = pwm0_1_pin_8_9_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm0_1_pin_8_9_modemux),
+	}, {
+		.name = "pwm0_1_pin_14_15_grp",
+		.pins = pwm0_1_pins[1],
+		.npins = ARRAY_SIZE(pwm0_1_pins[1]),
+		.modemuxs = pwm0_1_pin_14_15_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm0_1_pin_14_15_modemux),
+	}, {
+		.name = "pwm0_1_pin_30_31_grp",
+		.pins = pwm0_1_pins[2],
+		.npins = ARRAY_SIZE(pwm0_1_pins[2]),
+		.modemuxs = pwm0_1_pin_30_31_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm0_1_pin_30_31_modemux),
+	}, {
+		.name = "pwm0_1_pin_37_38_grp",
+		.pins = pwm0_1_pins[3],
+		.npins = ARRAY_SIZE(pwm0_1_pins[3]),
+		.modemuxs = pwm0_1_pin_37_38_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm0_1_pin_37_38_modemux),
+	}, {
+		.name = "pwm0_1_pin_42_43_grp",
+		.pins = pwm0_1_pins[4],
+		.npins = ARRAY_SIZE(pwm0_1_pins[4]),
+		.modemuxs = pwm0_1_pin_42_43_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm0_1_pin_42_43_modemux),
+	}, {
+		.name = "pwm0_1_pin_59_60_grp",
+		.pins = pwm0_1_pins[5],
+		.npins = ARRAY_SIZE(pwm0_1_pins[5]),
+		.modemuxs = pwm0_1_pin_59_60_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm0_1_pin_59_60_modemux),
+	}, {
+		.name = "pwm0_1_pin_88_89_grp",
+		.pins = pwm0_1_pins[6],
+		.npins = ARRAY_SIZE(pwm0_1_pins[6]),
+		.modemuxs = pwm0_1_pin_88_89_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm0_1_pin_88_89_modemux),
+	},
+};
+
+static const char *const pwm0_1_grps[] = { "pwm0_1_pin_8_9_grp",
+	"pwm0_1_pin_14_15_grp", "pwm0_1_pin_30_31_grp", "pwm0_1_pin_37_38_grp",
+	"pwm0_1_pin_42_43_grp", "pwm0_1_pin_59_60_grp", "pwm0_1_pin_88_89_grp"
+};
+
+static struct spear_function pwm0_1_function = {
+	.name = "pwm0_1",
+	.groups = pwm0_1_grps,
+	.ngroups = ARRAY_SIZE(pwm0_1_grps),
+};
+
+/* Pad multiplexing for PWM2 device */
+static const unsigned pwm2_pins[][1] = { { 7 }, { 13 }, { 29 }, { 34 }, { 41 },
+	{ 58 }, { 87 } };
+static struct spear_muxreg pwm2_net_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_CS_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg pwm2_pin_7_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_7_MASK,
+		.val = PMX_PWM_2_PL_7_VAL,
+	},
+};
+
+static struct spear_muxreg pwm2_autoexpsmallpri_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg pwm2_pin_13_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_13_MASK,
+		.val = PMX_PWM2_PL_13_VAL,
+	},
+};
+
+static struct spear_muxreg pwm2_pin_29_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_GPIO_PIN1_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_20_29_REG,
+		.mask = PMX_PL_29_MASK,
+		.val = PMX_PWM_2_PL_29_VAL,
+	},
+};
+
+static struct spear_muxreg pwm2_pin_34_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_CS_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_34_MASK,
+		.val = PMX_PWM2_PL_34_VAL,
+	},
+};
+
+static struct spear_muxreg pwm2_pin_41_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_41_MASK,
+		.val = PMX_PWM2_PL_41_VAL,
+	},
+};
+
+static struct spear_muxreg pwm2_pin_58_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_50_59_REG,
+		.mask = PMX_PL_58_MASK,
+		.val = PMX_PWM2_PL_58_VAL,
+	},
+};
+
+static struct spear_muxreg pwm2_pin_87_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_80_89_REG,
+		.mask = PMX_PL_87_MASK,
+		.val = PMX_PWM2_PL_87_VAL,
+	},
+};
+
+static struct spear_modemux pwm2_pin_7_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+		.muxregs = pwm2_net_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm2_net_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm2_pin_7_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm2_pin_7_muxreg),
+	},
+};
+static struct spear_modemux pwm2_pin_13_modemux[] = {
+	{
+		.modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+		.muxregs = pwm2_autoexpsmallpri_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm2_autoexpsmallpri_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm2_pin_13_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm2_pin_13_muxreg),
+	},
+};
+static struct spear_modemux pwm2_pin_29_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm2_pin_29_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm2_pin_29_muxreg),
+	},
+};
+static struct spear_modemux pwm2_pin_34_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm2_pin_34_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm2_pin_34_muxreg),
+	},
+};
+
+static struct spear_modemux pwm2_pin_41_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm2_pin_41_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm2_pin_41_muxreg),
+	},
+};
+
+static struct spear_modemux pwm2_pin_58_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm2_pin_58_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm2_pin_58_muxreg),
+	},
+};
+
+static struct spear_modemux pwm2_pin_87_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm2_pin_87_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm2_pin_87_muxreg),
+	},
+};
+
+static struct spear_pingroup pwm2_pingroup[] = {
+	{
+		.name = "pwm2_pin_7_grp",
+		.pins = pwm2_pins[0],
+		.npins = ARRAY_SIZE(pwm2_pins[0]),
+		.modemuxs = pwm2_pin_7_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm2_pin_7_modemux),
+	}, {
+		.name = "pwm2_pin_13_grp",
+		.pins = pwm2_pins[1],
+		.npins = ARRAY_SIZE(pwm2_pins[1]),
+		.modemuxs = pwm2_pin_13_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm2_pin_13_modemux),
+	}, {
+		.name = "pwm2_pin_29_grp",
+		.pins = pwm2_pins[2],
+		.npins = ARRAY_SIZE(pwm2_pins[2]),
+		.modemuxs = pwm2_pin_29_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm2_pin_29_modemux),
+	}, {
+		.name = "pwm2_pin_34_grp",
+		.pins = pwm2_pins[3],
+		.npins = ARRAY_SIZE(pwm2_pins[3]),
+		.modemuxs = pwm2_pin_34_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm2_pin_34_modemux),
+	}, {
+		.name = "pwm2_pin_41_grp",
+		.pins = pwm2_pins[4],
+		.npins = ARRAY_SIZE(pwm2_pins[4]),
+		.modemuxs = pwm2_pin_41_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm2_pin_41_modemux),
+	}, {
+		.name = "pwm2_pin_58_grp",
+		.pins = pwm2_pins[5],
+		.npins = ARRAY_SIZE(pwm2_pins[5]),
+		.modemuxs = pwm2_pin_58_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm2_pin_58_modemux),
+	}, {
+		.name = "pwm2_pin_87_grp",
+		.pins = pwm2_pins[6],
+		.npins = ARRAY_SIZE(pwm2_pins[6]),
+		.modemuxs = pwm2_pin_87_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm2_pin_87_modemux),
+	},
+};
+
+static const char *const pwm2_grps[] = { "pwm2_pin_7_grp", "pwm2_pin_13_grp",
+	"pwm2_pin_29_grp", "pwm2_pin_34_grp", "pwm2_pin_41_grp",
+	"pwm2_pin_58_grp", "pwm2_pin_87_grp" };
+static struct spear_function pwm2_function = {
+	.name = "pwm2",
+	.groups = pwm2_grps,
+	.ngroups = ARRAY_SIZE(pwm2_grps),
+};
+
+/* Pad multiplexing for PWM3 device */
+static const unsigned pwm3_pins[][1] = { { 6 }, { 12 }, { 28 }, { 40 }, { 57 },
+	{ 86 } };
+static struct spear_muxreg pwm3_pin_6_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_6_MASK,
+		.val = PMX_PWM_3_PL_6_VAL,
+	},
+};
+
+static struct spear_muxreg pwm3_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg pwm3_pin_12_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_12_MASK,
+		.val = PMX_PWM3_PL_12_VAL,
+	},
+};
+
+static struct spear_muxreg pwm3_pin_28_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_GPIO_PIN0_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_20_29_REG,
+		.mask = PMX_PL_28_MASK,
+		.val = PMX_PWM_3_PL_28_VAL,
+	},
+};
+
+static struct spear_muxreg pwm3_pin_40_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_40_MASK,
+		.val = PMX_PWM3_PL_40_VAL,
+	},
+};
+
+static struct spear_muxreg pwm3_pin_57_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_50_59_REG,
+		.mask = PMX_PL_57_MASK,
+		.val = PMX_PWM3_PL_57_VAL,
+	},
+};
+
+static struct spear_muxreg pwm3_pin_86_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_80_89_REG,
+		.mask = PMX_PL_86_MASK,
+		.val = PMX_PWM3_PL_86_VAL,
+	},
+};
+
+static struct spear_modemux pwm3_pin_6_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm3_pin_6_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm3_pin_6_muxreg),
+	},
+};
+
+static struct spear_modemux pwm3_pin_12_modemux[] = {
+	{
+		.modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE |
+			AUTO_NET_SMII_MODE | EXTENDED_MODE,
+		.muxregs = pwm3_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm3_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm3_pin_12_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm3_pin_12_muxreg),
+	},
+};
+
+static struct spear_modemux pwm3_pin_28_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm3_pin_28_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm3_pin_28_muxreg),
+	},
+};
+
+static struct spear_modemux pwm3_pin_40_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm3_pin_40_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm3_pin_40_muxreg),
+	},
+};
+
+static struct spear_modemux pwm3_pin_57_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm3_pin_57_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm3_pin_57_muxreg),
+	},
+};
+
+static struct spear_modemux pwm3_pin_86_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = pwm3_pin_86_muxreg,
+		.nmuxregs = ARRAY_SIZE(pwm3_pin_86_muxreg),
+	},
+};
+
+static struct spear_pingroup pwm3_pingroup[] = {
+	{
+		.name = "pwm3_pin_6_grp",
+		.pins = pwm3_pins[0],
+		.npins = ARRAY_SIZE(pwm3_pins[0]),
+		.modemuxs = pwm3_pin_6_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm3_pin_6_modemux),
+	}, {
+		.name = "pwm3_pin_12_grp",
+		.pins = pwm3_pins[1],
+		.npins = ARRAY_SIZE(pwm3_pins[1]),
+		.modemuxs = pwm3_pin_12_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm3_pin_12_modemux),
+	}, {
+		.name = "pwm3_pin_28_grp",
+		.pins = pwm3_pins[2],
+		.npins = ARRAY_SIZE(pwm3_pins[2]),
+		.modemuxs = pwm3_pin_28_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm3_pin_28_modemux),
+	}, {
+		.name = "pwm3_pin_40_grp",
+		.pins = pwm3_pins[3],
+		.npins = ARRAY_SIZE(pwm3_pins[3]),
+		.modemuxs = pwm3_pin_40_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm3_pin_40_modemux),
+	}, {
+		.name = "pwm3_pin_57_grp",
+		.pins = pwm3_pins[4],
+		.npins = ARRAY_SIZE(pwm3_pins[4]),
+		.modemuxs = pwm3_pin_57_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm3_pin_57_modemux),
+	}, {
+		.name = "pwm3_pin_86_grp",
+		.pins = pwm3_pins[5],
+		.npins = ARRAY_SIZE(pwm3_pins[5]),
+		.modemuxs = pwm3_pin_86_modemux,
+		.nmodemuxs = ARRAY_SIZE(pwm3_pin_86_modemux),
+	},
+};
+
+static const char *const pwm3_grps[] = { "pwm3_pin_6_grp", "pwm3_pin_12_grp",
+	"pwm3_pin_28_grp", "pwm3_pin_40_grp", "pwm3_pin_57_grp",
+	"pwm3_pin_86_grp" };
+static struct spear_function pwm3_function = {
+	.name = "pwm3",
+	.groups = pwm3_grps,
+	.ngroups = ARRAY_SIZE(pwm3_grps),
+};
+
+/* Pad multiplexing for SSP1 device */
+static const unsigned ssp1_pins[][2] = { { 17, 20 }, { 36, 39 }, { 48, 51 },
+	{ 65, 68 }, { 94, 97 } };
+static struct spear_muxreg ssp1_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg ssp1_ext_17_20_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_17_18_MASK | PMX_PL_19_MASK,
+		.val = PMX_SSP1_PL_17_18_19_20_VAL,
+	}, {
+		.reg = IP_SEL_PAD_20_29_REG,
+		.mask = PMX_PL_20_MASK,
+		.val = PMX_SSP1_PL_17_18_19_20_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP1_PORT_SEL_MASK,
+		.val = PMX_SSP1_PORT_17_TO_20_VAL,
+	},
+};
+
+static struct spear_muxreg ssp1_ext_36_39_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_36_MASK | PMX_PL_37_38_MASK | PMX_PL_39_MASK,
+		.val = PMX_SSP1_PL_36_VAL | PMX_SSP1_PL_37_38_VAL |
+			PMX_SSP1_PL_39_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP1_PORT_SEL_MASK,
+		.val = PMX_SSP1_PORT_36_TO_39_VAL,
+	},
+};
+
+static struct spear_muxreg ssp1_ext_48_51_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_48_49_MASK,
+		.val = PMX_SSP1_PL_48_49_VAL,
+	}, {
+		.reg = IP_SEL_PAD_50_59_REG,
+		.mask = PMX_PL_50_51_MASK,
+		.val = PMX_SSP1_PL_50_51_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP1_PORT_SEL_MASK,
+		.val = PMX_SSP1_PORT_48_TO_51_VAL,
+	},
+};
+
+static struct spear_muxreg ssp1_ext_65_68_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_60_69_REG,
+		.mask = PMX_PL_65_TO_68_MASK,
+		.val = PMX_SSP1_PL_65_TO_68_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP1_PORT_SEL_MASK,
+		.val = PMX_SSP1_PORT_65_TO_68_VAL,
+	},
+};
+
+static struct spear_muxreg ssp1_ext_94_97_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_94_95_MASK | PMX_PL_96_97_MASK,
+		.val = PMX_SSP1_PL_94_95_VAL | PMX_SSP1_PL_96_97_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP1_PORT_SEL_MASK,
+		.val = PMX_SSP1_PORT_94_TO_97_VAL,
+	},
+};
+
+static struct spear_modemux ssp1_17_20_modemux[] = {
+	{
+		.modes = SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE |
+			EXTENDED_MODE,
+		.muxregs = ssp1_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp1_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp1_ext_17_20_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp1_ext_17_20_muxreg),
+	},
+};
+
+static struct spear_modemux ssp1_36_39_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp1_ext_36_39_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp1_ext_36_39_muxreg),
+	},
+};
+
+static struct spear_modemux ssp1_48_51_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp1_ext_48_51_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp1_ext_48_51_muxreg),
+	},
+};
+static struct spear_modemux ssp1_65_68_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp1_ext_65_68_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp1_ext_65_68_muxreg),
+	},
+};
+
+static struct spear_modemux ssp1_94_97_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp1_ext_94_97_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp1_ext_94_97_muxreg),
+	},
+};
+
+static struct spear_pingroup ssp1_pingroup[] = {
+	{
+		.name = "ssp1_17_20_grp",
+		.pins = ssp1_pins[0],
+		.npins = ARRAY_SIZE(ssp1_pins[0]),
+		.modemuxs = ssp1_17_20_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp1_17_20_modemux),
+	}, {
+		.name = "ssp1_36_39_grp",
+		.pins = ssp1_pins[1],
+		.npins = ARRAY_SIZE(ssp1_pins[1]),
+		.modemuxs = ssp1_36_39_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp1_36_39_modemux),
+	}, {
+		.name = "ssp1_48_51_grp",
+		.pins = ssp1_pins[2],
+		.npins = ARRAY_SIZE(ssp1_pins[2]),
+		.modemuxs = ssp1_48_51_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp1_48_51_modemux),
+	}, {
+		.name = "ssp1_65_68_grp",
+		.pins = ssp1_pins[3],
+		.npins = ARRAY_SIZE(ssp1_pins[3]),
+		.modemuxs = ssp1_65_68_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp1_65_68_modemux),
+	}, {
+		.name = "ssp1_94_97_grp",
+		.pins = ssp1_pins[4],
+		.npins = ARRAY_SIZE(ssp1_pins[4]),
+		.modemuxs = ssp1_94_97_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp1_94_97_modemux),
+	},
+};
+
+static const char *const ssp1_grps[] = { "ssp1_17_20_grp", "ssp1_36_39_grp",
+	"ssp1_48_51_grp", "ssp1_65_68_grp", "ssp1_94_97_grp"
+};
+static struct spear_function ssp1_function = {
+	.name = "ssp1",
+	.groups = ssp1_grps,
+	.ngroups = ARRAY_SIZE(ssp1_grps),
+};
+
+/* Pad multiplexing for SSP2 device */
+static const unsigned ssp2_pins[][2] = { { 13, 16 }, { 32, 35 }, { 44, 47 },
+	{ 61, 64 }, { 90, 93 } };
+static struct spear_muxreg ssp2_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg ssp2_ext_13_16_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_13_14_MASK | PMX_PL_15_16_MASK,
+		.val = PMX_SSP2_PL_13_14_15_16_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP2_PORT_SEL_MASK,
+		.val = PMX_SSP2_PORT_13_TO_16_VAL,
+	},
+};
+
+static struct spear_muxreg ssp2_ext_32_35_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_CS_MASK | PMX_GPIO_PIN4_MASK |
+			PMX_GPIO_PIN5_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_30_39_REG,
+		.mask = PMX_PL_32_33_MASK | PMX_PL_34_MASK | PMX_PL_35_MASK,
+		.val = PMX_SSP2_PL_32_33_VAL | PMX_SSP2_PL_34_VAL |
+			PMX_SSP2_PL_35_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP2_PORT_SEL_MASK,
+		.val = PMX_SSP2_PORT_32_TO_35_VAL,
+	},
+};
+
+static struct spear_muxreg ssp2_ext_44_47_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_40_49_REG,
+		.mask = PMX_PL_44_45_MASK | PMX_PL_46_47_MASK,
+		.val = PMX_SSP2_PL_44_45_VAL | PMX_SSP2_PL_46_47_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP2_PORT_SEL_MASK,
+		.val = PMX_SSP2_PORT_44_TO_47_VAL,
+	},
+};
+
+static struct spear_muxreg ssp2_ext_61_64_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_60_69_REG,
+		.mask = PMX_PL_61_TO_64_MASK,
+		.val = PMX_SSP2_PL_61_TO_64_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP2_PORT_SEL_MASK,
+		.val = PMX_SSP2_PORT_61_TO_64_VAL,
+	},
+};
+
+static struct spear_muxreg ssp2_ext_90_93_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK,
+		.val = PMX_SSP2_PL_90_91_VAL | PMX_SSP2_PL_92_93_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_SSP2_PORT_SEL_MASK,
+		.val = PMX_SSP2_PORT_90_TO_93_VAL,
+	},
+};
+
+static struct spear_modemux ssp2_13_16_modemux[] = {
+	{
+		.modes = AUTO_NET_SMII_MODE | EXTENDED_MODE,
+		.muxregs = ssp2_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp2_muxreg),
+	}, {
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp2_ext_13_16_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp2_ext_13_16_muxreg),
+	},
+};
+
+static struct spear_modemux ssp2_32_35_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp2_ext_32_35_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp2_ext_32_35_muxreg),
+	},
+};
+
+static struct spear_modemux ssp2_44_47_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp2_ext_44_47_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp2_ext_44_47_muxreg),
+	},
+};
+
+static struct spear_modemux ssp2_61_64_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp2_ext_61_64_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp2_ext_61_64_muxreg),
+	},
+};
+
+static struct spear_modemux ssp2_90_93_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = ssp2_ext_90_93_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp2_ext_90_93_muxreg),
+	},
+};
+
+static struct spear_pingroup ssp2_pingroup[] = {
+	{
+		.name = "ssp2_13_16_grp",
+		.pins = ssp2_pins[0],
+		.npins = ARRAY_SIZE(ssp2_pins[0]),
+		.modemuxs = ssp2_13_16_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp2_13_16_modemux),
+	}, {
+		.name = "ssp2_32_35_grp",
+		.pins = ssp2_pins[1],
+		.npins = ARRAY_SIZE(ssp2_pins[1]),
+		.modemuxs = ssp2_32_35_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp2_32_35_modemux),
+	}, {
+		.name = "ssp2_44_47_grp",
+		.pins = ssp2_pins[2],
+		.npins = ARRAY_SIZE(ssp2_pins[2]),
+		.modemuxs = ssp2_44_47_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp2_44_47_modemux),
+	}, {
+		.name = "ssp2_61_64_grp",
+		.pins = ssp2_pins[3],
+		.npins = ARRAY_SIZE(ssp2_pins[3]),
+		.modemuxs = ssp2_61_64_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp2_61_64_modemux),
+	}, {
+		.name = "ssp2_90_93_grp",
+		.pins = ssp2_pins[4],
+		.npins = ARRAY_SIZE(ssp2_pins[4]),
+		.modemuxs = ssp2_90_93_modemux,
+		.nmodemuxs = ARRAY_SIZE(ssp2_90_93_modemux),
+	},
+};
+
+static const char *const ssp2_grps[] = { "ssp2_13_16_grp", "ssp2_32_35_grp",
+	"ssp2_44_47_grp", "ssp2_61_64_grp", "ssp2_90_93_grp" };
+static struct spear_function ssp2_function = {
+	.name = "ssp2",
+	.groups = ssp2_grps,
+	.ngroups = ARRAY_SIZE(ssp2_grps),
+};
+
+/* Pad multiplexing for cadence mii2 as mii device */
+static const unsigned mii2_pins[] = { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+	90, 91, 92, 93, 94, 95, 96, 97 };
+static struct spear_muxreg mii2_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_80_89_REG,
+		.mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK |
+			PMX_PL_88_89_MASK,
+		.val = PMX_MII2_PL_80_TO_85_VAL | PMX_MII2_PL_86_87_VAL |
+			PMX_MII2_PL_88_89_VAL,
+	}, {
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK |
+			PMX_PL_94_95_MASK | PMX_PL_96_97_MASK,
+		.val = PMX_MII2_PL_90_91_VAL | PMX_MII2_PL_92_93_VAL |
+			PMX_MII2_PL_94_95_VAL | PMX_MII2_PL_96_97_VAL,
+	}, {
+		.reg = EXT_CTRL_REG,
+		.mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) |
+			(MAC_MODE_MASK << MAC1_MODE_SHIFT) |
+			MII_MDIO_MASK,
+		.val = (MAC_MODE_MII << MAC2_MODE_SHIFT) |
+			(MAC_MODE_MII << MAC1_MODE_SHIFT) |
+			MII_MDIO_81_VAL,
+	},
+};
+
+static struct spear_modemux mii2_modemux[] = {
+	{
+		.modes = EXTENDED_MODE,
+		.muxregs = mii2_muxreg,
+		.nmuxregs = ARRAY_SIZE(mii2_muxreg),
+	},
+};
+
+static struct spear_pingroup mii2_pingroup = {
+	.name = "mii2_grp",
+	.pins = mii2_pins,
+	.npins = ARRAY_SIZE(mii2_pins),
+	.modemuxs = mii2_modemux,
+	.nmodemuxs = ARRAY_SIZE(mii2_modemux),
+};
+
+static const char *const mii2_grps[] = { "mii2_grp" };
+static struct spear_function mii2_function = {
+	.name = "mii2",
+	.groups = mii2_grps,
+	.ngroups = ARRAY_SIZE(mii2_grps),
+};
+
+/* Pad multiplexing for cadence mii 1_2 as smii or rmii device */
+static const unsigned smii0_1_pins[] = { 10, 11, 13, 14, 15, 16, 17, 18, 19, 20,
+	21, 22, 23, 24, 25, 26, 27 };
+static const unsigned rmii0_1_pins[] = { 10, 11, 21, 22, 23, 24, 25, 26, 27 };
+static struct spear_muxreg mii0_1_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	},
+};
+
+static struct spear_muxreg smii0_1_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_10_11_MASK,
+		.val = PMX_SMII_PL_10_11_VAL,
+	}, {
+		.reg = IP_SEL_PAD_20_29_REG,
+		.mask = PMX_PL_21_TO_27_MASK,
+		.val = PMX_SMII_PL_21_TO_27_VAL,
+	}, {
+		.reg = EXT_CTRL_REG,
+		.mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) |
+			(MAC_MODE_MASK << MAC1_MODE_SHIFT) |
+			MII_MDIO_MASK,
+		.val = (MAC_MODE_SMII << MAC2_MODE_SHIFT)
+			| (MAC_MODE_SMII << MAC1_MODE_SHIFT)
+			| MII_MDIO_10_11_VAL,
+	},
+};
+
+static struct spear_muxreg rmii0_1_ext_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_10_11_MASK | PMX_PL_13_14_MASK |
+			PMX_PL_15_16_MASK | PMX_PL_17_18_MASK | PMX_PL_19_MASK,
+		.val = PMX_RMII_PL_10_11_VAL | PMX_RMII_PL_13_14_VAL |
+			PMX_RMII_PL_15_16_VAL | PMX_RMII_PL_17_18_VAL |
+			PMX_RMII_PL_19_VAL,
+	}, {
+		.reg = IP_SEL_PAD_20_29_REG,
+		.mask = PMX_PL_20_MASK | PMX_PL_21_TO_27_MASK,
+		.val = PMX_RMII_PL_20_VAL | PMX_RMII_PL_21_TO_27_VAL,
+	}, {
+		.reg = EXT_CTRL_REG,
+		.mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) |
+			(MAC_MODE_MASK << MAC1_MODE_SHIFT) |
+			MII_MDIO_MASK,
+		.val = (MAC_MODE_RMII << MAC2_MODE_SHIFT)
+			| (MAC_MODE_RMII << MAC1_MODE_SHIFT)
+			| MII_MDIO_10_11_VAL,
+	},
+};
+
+static struct spear_modemux mii0_1_modemux[][2] = {
+	{
+		/* configure as smii */
+		{
+			.modes = AUTO_NET_SMII_MODE | AUTO_EXP_MODE |
+				SMALL_PRINTERS_MODE | EXTENDED_MODE,
+			.muxregs = mii0_1_muxreg,
+			.nmuxregs = ARRAY_SIZE(mii0_1_muxreg),
+		}, {
+			.modes = EXTENDED_MODE,
+			.muxregs = smii0_1_ext_muxreg,
+			.nmuxregs = ARRAY_SIZE(smii0_1_ext_muxreg),
+		},
+	}, {
+		/* configure as rmii */
+		{
+			.modes = AUTO_NET_SMII_MODE | AUTO_EXP_MODE |
+				SMALL_PRINTERS_MODE | EXTENDED_MODE,
+			.muxregs = mii0_1_muxreg,
+			.nmuxregs = ARRAY_SIZE(mii0_1_muxreg),
+		}, {
+			.modes = EXTENDED_MODE,
+			.muxregs = rmii0_1_ext_muxreg,
+			.nmuxregs = ARRAY_SIZE(rmii0_1_ext_muxreg),
+		},
+	},
+};
+
+static struct spear_pingroup mii0_1_pingroup[] = {
+	{
+		.name = "smii0_1_grp",
+		.pins = smii0_1_pins,
+		.npins = ARRAY_SIZE(smii0_1_pins),
+		.modemuxs = mii0_1_modemux[0],
+		.nmodemuxs = ARRAY_SIZE(mii0_1_modemux[0]),
+	}, {
+		.name = "rmii0_1_grp",
+		.pins = rmii0_1_pins,
+		.npins = ARRAY_SIZE(rmii0_1_pins),
+		.modemuxs = mii0_1_modemux[1],
+		.nmodemuxs = ARRAY_SIZE(mii0_1_modemux[1]),
+	},
+};
+
+static const char *const mii0_1_grps[] = { "smii0_1_grp", "rmii0_1_grp" };
+static struct spear_function mii0_1_function = {
+	.name = "mii0_1",
+	.groups = mii0_1_grps,
+	.ngroups = ARRAY_SIZE(mii0_1_grps),
+};
+
+/* Pad multiplexing for i2c1 device */
+static const unsigned i2c1_pins[][2] = { { 8, 9 }, { 98, 99 } };
+static struct spear_muxreg i2c1_ext_8_9_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_SSP_CS_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_8_9_MASK,
+		.val = PMX_I2C1_PL_8_9_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_I2C1_PORT_SEL_MASK,
+		.val = PMX_I2C1_PORT_8_9_VAL,
+	},
+};
+
+static struct spear_muxreg i2c1_ext_98_99_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_98_MASK | PMX_PL_99_MASK,
+		.val = PMX_I2C1_PL_98_VAL | PMX_I2C1_PL_99_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_I2C1_PORT_SEL_MASK,
+		.val = PMX_I2C1_PORT_98_99_VAL,
+	},
+};
+
+static struct spear_modemux i2c1_modemux[][1] = {
+	{
+		/* Select signals on pins 8-9 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = i2c1_ext_8_9_muxreg,
+			.nmuxregs = ARRAY_SIZE(i2c1_ext_8_9_muxreg),
+		},
+	}, {
+		/* Select signals on pins 98-99 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = i2c1_ext_98_99_muxreg,
+			.nmuxregs = ARRAY_SIZE(i2c1_ext_98_99_muxreg),
+		},
+	},
+};
+
+static struct spear_pingroup i2c1_pingroup[] = {
+	{
+		.name = "i2c1_8_9_grp",
+		.pins = i2c1_pins[0],
+		.npins = ARRAY_SIZE(i2c1_pins[0]),
+		.modemuxs = i2c1_modemux[0],
+		.nmodemuxs = ARRAY_SIZE(i2c1_modemux[0]),
+	}, {
+		.name = "i2c1_98_99_grp",
+		.pins = i2c1_pins[1],
+		.npins = ARRAY_SIZE(i2c1_pins[1]),
+		.modemuxs = i2c1_modemux[1],
+		.nmodemuxs = ARRAY_SIZE(i2c1_modemux[1]),
+	},
+};
+
+static const char *const i2c1_grps[] = { "i2c1_8_9_grp", "i2c1_98_99_grp" };
+static struct spear_function i2c1_function = {
+	.name = "i2c1",
+	.groups = i2c1_grps,
+	.ngroups = ARRAY_SIZE(i2c1_grps),
+};
+
+/* Pad multiplexing for i2c2 device */
+static const unsigned i2c2_pins[][2] = { { 0, 1 }, { 2, 3 }, { 19, 20 },
+	{ 75, 76 }, { 96, 97 } };
+static struct spear_muxreg i2c2_ext_0_1_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_FIRDA_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_0_1_MASK,
+		.val = PMX_I2C2_PL_0_1_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_I2C2_PORT_SEL_MASK,
+		.val = PMX_I2C2_PORT_0_1_VAL,
+	},
+};
+
+static struct spear_muxreg i2c2_ext_2_3_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_UART0_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_0_9_REG,
+		.mask = PMX_PL_2_3_MASK,
+		.val = PMX_I2C2_PL_2_3_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_I2C2_PORT_SEL_MASK,
+		.val = PMX_I2C2_PORT_2_3_VAL,
+	},
+};
+
+static struct spear_muxreg i2c2_ext_19_20_muxreg[] = {
+	{
+		.reg = PMX_CONFIG_REG,
+		.mask = PMX_MII_MASK,
+		.val = 0,
+	}, {
+		.reg = IP_SEL_PAD_10_19_REG,
+		.mask = PMX_PL_19_MASK,
+		.val = PMX_I2C2_PL_19_VAL,
+	}, {
+		.reg = IP_SEL_PAD_20_29_REG,
+		.mask = PMX_PL_20_MASK,
+		.val = PMX_I2C2_PL_20_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_I2C2_PORT_SEL_MASK,
+		.val = PMX_I2C2_PORT_19_20_VAL,
+	},
+};
+
+static struct spear_muxreg i2c2_ext_75_76_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_70_79_REG,
+		.mask = PMX_PL_75_76_MASK,
+		.val = PMX_I2C2_PL_75_76_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_I2C2_PORT_SEL_MASK,
+		.val = PMX_I2C2_PORT_75_76_VAL,
+	},
+};
+
+static struct spear_muxreg i2c2_ext_96_97_muxreg[] = {
+	{
+		.reg = IP_SEL_PAD_90_99_REG,
+		.mask = PMX_PL_96_97_MASK,
+		.val = PMX_I2C2_PL_96_97_VAL,
+	}, {
+		.reg = IP_SEL_MIX_PAD_REG,
+		.mask = PMX_I2C2_PORT_SEL_MASK,
+		.val = PMX_I2C2_PORT_96_97_VAL,
+	},
+};
+
+static struct spear_modemux i2c2_modemux[][1] = {
+	{
+		/* Select signals on pins 0_1 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = i2c2_ext_0_1_muxreg,
+			.nmuxregs = ARRAY_SIZE(i2c2_ext_0_1_muxreg),
+		},
+	}, {
+		/* Select signals on pins 2_3 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = i2c2_ext_2_3_muxreg,
+			.nmuxregs = ARRAY_SIZE(i2c2_ext_2_3_muxreg),
+		},
+	}, {
+		/* Select signals on pins 19_20 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = i2c2_ext_19_20_muxreg,
+			.nmuxregs = ARRAY_SIZE(i2c2_ext_19_20_muxreg),
+		},
+	}, {
+		/* Select signals on pins 75_76 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = i2c2_ext_75_76_muxreg,
+			.nmuxregs = ARRAY_SIZE(i2c2_ext_75_76_muxreg),
+		},
+	}, {
+		/* Select signals on pins 96_97 */
+		{
+			.modes = EXTENDED_MODE,
+			.muxregs = i2c2_ext_96_97_muxreg,
+			.nmuxregs = ARRAY_SIZE(i2c2_ext_96_97_muxreg),
+		},
+	},
+};
+
+static struct spear_pingroup i2c2_pingroup[] = {
+	{
+		.name = "i2c2_0_1_grp",
+		.pins = i2c2_pins[0],
+		.npins = ARRAY_SIZE(i2c2_pins[0]),
+		.modemuxs = i2c2_modemux[0],
+		.nmodemuxs = ARRAY_SIZE(i2c2_modemux[0]),
+	}, {
+		.name = "i2c2_2_3_grp",
+		.pins = i2c2_pins[1],
+		.npins = ARRAY_SIZE(i2c2_pins[1]),
+		.modemuxs = i2c2_modemux[1],
+		.nmodemuxs = ARRAY_SIZE(i2c2_modemux[1]),
+	}, {
+		.name = "i2c2_19_20_grp",
+		.pins = i2c2_pins[2],
+		.npins = ARRAY_SIZE(i2c2_pins[2]),
+		.modemuxs = i2c2_modemux[2],
+		.nmodemuxs = ARRAY_SIZE(i2c2_modemux[2]),
+	}, {
+		.name = "i2c2_75_76_grp",
+		.pins = i2c2_pins[3],
+		.npins = ARRAY_SIZE(i2c2_pins[3]),
+		.modemuxs = i2c2_modemux[3],
+		.nmodemuxs = ARRAY_SIZE(i2c2_modemux[3]),
+	}, {
+		.name = "i2c2_96_97_grp",
+		.pins = i2c2_pins[4],
+		.npins = ARRAY_SIZE(i2c2_pins[4]),
+		.modemuxs = i2c2_modemux[4],
+		.nmodemuxs = ARRAY_SIZE(i2c2_modemux[4]),
+	},
+};
+
+static const char *const i2c2_grps[] = { "i2c2_0_1_grp", "i2c2_2_3_grp",
+	"i2c2_19_20_grp", "i2c2_75_76_grp", "i2c2_96_97_grp" };
+static struct spear_function i2c2_function = {
+	.name = "i2c2",
+	.groups = i2c2_grps,
+	.ngroups = ARRAY_SIZE(i2c2_grps),
+};
+
+/* pingroups */
+static struct spear_pingroup *spear320_pingroups[] = {
+	SPEAR3XX_COMMON_PINGROUPS,
+	&clcd_pingroup,
+	&emi_pingroup,
+	&fsmc_8bit_pingroup,
+	&fsmc_16bit_pingroup,
+	&spp_pingroup,
+	&sdhci_led_pingroup,
+	&sdhci_pingroup[0],
+	&sdhci_pingroup[1],
+	&i2s_pingroup,
+	&uart1_pingroup,
+	&uart1_modem_pingroup[0],
+	&uart1_modem_pingroup[1],
+	&uart1_modem_pingroup[2],
+	&uart1_modem_pingroup[3],
+	&uart2_pingroup,
+	&uart3_pingroup[0],
+	&uart3_pingroup[1],
+	&uart3_pingroup[2],
+	&uart3_pingroup[3],
+	&uart3_pingroup[4],
+	&uart3_pingroup[5],
+	&uart3_pingroup[6],
+	&uart4_pingroup[0],
+	&uart4_pingroup[1],
+	&uart4_pingroup[2],
+	&uart4_pingroup[3],
+	&uart4_pingroup[4],
+	&uart4_pingroup[5],
+	&uart5_pingroup[0],
+	&uart5_pingroup[1],
+	&uart5_pingroup[2],
+	&uart5_pingroup[3],
+	&uart6_pingroup[0],
+	&uart6_pingroup[1],
+	&rs485_pingroup,
+	&touchscreen_pingroup,
+	&can0_pingroup,
+	&can1_pingroup,
+	&pwm0_1_pingroup[0],
+	&pwm0_1_pingroup[1],
+	&pwm0_1_pingroup[2],
+	&pwm0_1_pingroup[3],
+	&pwm0_1_pingroup[4],
+	&pwm0_1_pingroup[5],
+	&pwm0_1_pingroup[6],
+	&pwm2_pingroup[0],
+	&pwm2_pingroup[1],
+	&pwm2_pingroup[2],
+	&pwm2_pingroup[3],
+	&pwm2_pingroup[4],
+	&pwm2_pingroup[5],
+	&pwm2_pingroup[6],
+	&pwm3_pingroup[0],
+	&pwm3_pingroup[1],
+	&pwm3_pingroup[2],
+	&pwm3_pingroup[3],
+	&pwm3_pingroup[4],
+	&pwm3_pingroup[5],
+	&ssp1_pingroup[0],
+	&ssp1_pingroup[1],
+	&ssp1_pingroup[2],
+	&ssp1_pingroup[3],
+	&ssp1_pingroup[4],
+	&ssp2_pingroup[0],
+	&ssp2_pingroup[1],
+	&ssp2_pingroup[2],
+	&ssp2_pingroup[3],
+	&ssp2_pingroup[4],
+	&mii2_pingroup,
+	&mii0_1_pingroup[0],
+	&mii0_1_pingroup[1],
+	&i2c1_pingroup[0],
+	&i2c1_pingroup[1],
+	&i2c2_pingroup[0],
+	&i2c2_pingroup[1],
+	&i2c2_pingroup[2],
+	&i2c2_pingroup[3],
+	&i2c2_pingroup[4],
+};
+
+/* functions */
+static struct spear_function *spear320_functions[] = {
+	SPEAR3XX_COMMON_FUNCTIONS,
+	&clcd_function,
+	&emi_function,
+	&fsmc_function,
+	&spp_function,
+	&sdhci_function,
+	&i2s_function,
+	&uart1_function,
+	&uart1_modem_function,
+	&uart2_function,
+	&uart3_function,
+	&uart4_function,
+	&uart5_function,
+	&uart6_function,
+	&rs485_function,
+	&touchscreen_function,
+	&can0_function,
+	&can1_function,
+	&pwm0_1_function,
+	&pwm2_function,
+	&pwm3_function,
+	&ssp1_function,
+	&ssp2_function,
+	&mii2_function,
+	&mii0_1_function,
+	&i2c1_function,
+	&i2c2_function,
+};
+
+static struct of_device_id spear320_pinctrl_of_match[] __devinitdata = {
+	{
+		.compatible = "st,spear320-pinmux",
+	},
+	{},
+};
+
+static int __devinit spear320_pinctrl_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	spear3xx_machdata.groups = spear320_pingroups;
+	spear3xx_machdata.ngroups = ARRAY_SIZE(spear320_pingroups);
+	spear3xx_machdata.functions = spear320_functions;
+	spear3xx_machdata.nfunctions = ARRAY_SIZE(spear320_functions);
+
+	spear3xx_machdata.modes_supported = true;
+	spear3xx_machdata.pmx_modes = spear320_pmx_modes;
+	spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes);
+
+	pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+
+	ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int __devexit spear320_pinctrl_remove(struct platform_device *pdev)
+{
+	return spear_pinctrl_remove(pdev);
+}
+
+static struct platform_driver spear320_pinctrl_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = spear320_pinctrl_of_match,
+	},
+	.probe = spear320_pinctrl_probe,
+	.remove = __devexit_p(spear320_pinctrl_remove),
+};
+
+static int __init spear320_pinctrl_init(void)
+{
+	return platform_driver_register(&spear320_pinctrl_driver);
+}
+arch_initcall(spear320_pinctrl_init);
+
+static void __exit spear320_pinctrl_exit(void)
+{
+	platform_driver_unregister(&spear320_pinctrl_driver);
+}
+module_exit(spear320_pinctrl_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_DESCRIPTION("ST Microelectronics SPEAr320 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, spear320_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c
new file mode 100644
index 0000000..832049a
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c
@@ -0,0 +1,588 @@
+/*
+ * Driver for the ST Microelectronics SPEAr3xx pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * 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/pinctrl/pinctrl.h>
+
+#include "pinctrl-spear3xx.h"
+
+/* pins */
+static const struct pinctrl_pin_desc spear3xx_pins[] = {
+	PINCTRL_PIN(0, "PLGPIO0"),
+	PINCTRL_PIN(1, "PLGPIO1"),
+	PINCTRL_PIN(2, "PLGPIO2"),
+	PINCTRL_PIN(3, "PLGPIO3"),
+	PINCTRL_PIN(4, "PLGPIO4"),
+	PINCTRL_PIN(5, "PLGPIO5"),
+	PINCTRL_PIN(6, "PLGPIO6"),
+	PINCTRL_PIN(7, "PLGPIO7"),
+	PINCTRL_PIN(8, "PLGPIO8"),
+	PINCTRL_PIN(9, "PLGPIO9"),
+	PINCTRL_PIN(10, "PLGPIO10"),
+	PINCTRL_PIN(11, "PLGPIO11"),
+	PINCTRL_PIN(12, "PLGPIO12"),
+	PINCTRL_PIN(13, "PLGPIO13"),
+	PINCTRL_PIN(14, "PLGPIO14"),
+	PINCTRL_PIN(15, "PLGPIO15"),
+	PINCTRL_PIN(16, "PLGPIO16"),
+	PINCTRL_PIN(17, "PLGPIO17"),
+	PINCTRL_PIN(18, "PLGPIO18"),
+	PINCTRL_PIN(19, "PLGPIO19"),
+	PINCTRL_PIN(20, "PLGPIO20"),
+	PINCTRL_PIN(21, "PLGPIO21"),
+	PINCTRL_PIN(22, "PLGPIO22"),
+	PINCTRL_PIN(23, "PLGPIO23"),
+	PINCTRL_PIN(24, "PLGPIO24"),
+	PINCTRL_PIN(25, "PLGPIO25"),
+	PINCTRL_PIN(26, "PLGPIO26"),
+	PINCTRL_PIN(27, "PLGPIO27"),
+	PINCTRL_PIN(28, "PLGPIO28"),
+	PINCTRL_PIN(29, "PLGPIO29"),
+	PINCTRL_PIN(30, "PLGPIO30"),
+	PINCTRL_PIN(31, "PLGPIO31"),
+	PINCTRL_PIN(32, "PLGPIO32"),
+	PINCTRL_PIN(33, "PLGPIO33"),
+	PINCTRL_PIN(34, "PLGPIO34"),
+	PINCTRL_PIN(35, "PLGPIO35"),
+	PINCTRL_PIN(36, "PLGPIO36"),
+	PINCTRL_PIN(37, "PLGPIO37"),
+	PINCTRL_PIN(38, "PLGPIO38"),
+	PINCTRL_PIN(39, "PLGPIO39"),
+	PINCTRL_PIN(40, "PLGPIO40"),
+	PINCTRL_PIN(41, "PLGPIO41"),
+	PINCTRL_PIN(42, "PLGPIO42"),
+	PINCTRL_PIN(43, "PLGPIO43"),
+	PINCTRL_PIN(44, "PLGPIO44"),
+	PINCTRL_PIN(45, "PLGPIO45"),
+	PINCTRL_PIN(46, "PLGPIO46"),
+	PINCTRL_PIN(47, "PLGPIO47"),
+	PINCTRL_PIN(48, "PLGPIO48"),
+	PINCTRL_PIN(49, "PLGPIO49"),
+	PINCTRL_PIN(50, "PLGPIO50"),
+	PINCTRL_PIN(51, "PLGPIO51"),
+	PINCTRL_PIN(52, "PLGPIO52"),
+	PINCTRL_PIN(53, "PLGPIO53"),
+	PINCTRL_PIN(54, "PLGPIO54"),
+	PINCTRL_PIN(55, "PLGPIO55"),
+	PINCTRL_PIN(56, "PLGPIO56"),
+	PINCTRL_PIN(57, "PLGPIO57"),
+	PINCTRL_PIN(58, "PLGPIO58"),
+	PINCTRL_PIN(59, "PLGPIO59"),
+	PINCTRL_PIN(60, "PLGPIO60"),
+	PINCTRL_PIN(61, "PLGPIO61"),
+	PINCTRL_PIN(62, "PLGPIO62"),
+	PINCTRL_PIN(63, "PLGPIO63"),
+	PINCTRL_PIN(64, "PLGPIO64"),
+	PINCTRL_PIN(65, "PLGPIO65"),
+	PINCTRL_PIN(66, "PLGPIO66"),
+	PINCTRL_PIN(67, "PLGPIO67"),
+	PINCTRL_PIN(68, "PLGPIO68"),
+	PINCTRL_PIN(69, "PLGPIO69"),
+	PINCTRL_PIN(70, "PLGPIO70"),
+	PINCTRL_PIN(71, "PLGPIO71"),
+	PINCTRL_PIN(72, "PLGPIO72"),
+	PINCTRL_PIN(73, "PLGPIO73"),
+	PINCTRL_PIN(74, "PLGPIO74"),
+	PINCTRL_PIN(75, "PLGPIO75"),
+	PINCTRL_PIN(76, "PLGPIO76"),
+	PINCTRL_PIN(77, "PLGPIO77"),
+	PINCTRL_PIN(78, "PLGPIO78"),
+	PINCTRL_PIN(79, "PLGPIO79"),
+	PINCTRL_PIN(80, "PLGPIO80"),
+	PINCTRL_PIN(81, "PLGPIO81"),
+	PINCTRL_PIN(82, "PLGPIO82"),
+	PINCTRL_PIN(83, "PLGPIO83"),
+	PINCTRL_PIN(84, "PLGPIO84"),
+	PINCTRL_PIN(85, "PLGPIO85"),
+	PINCTRL_PIN(86, "PLGPIO86"),
+	PINCTRL_PIN(87, "PLGPIO87"),
+	PINCTRL_PIN(88, "PLGPIO88"),
+	PINCTRL_PIN(89, "PLGPIO89"),
+	PINCTRL_PIN(90, "PLGPIO90"),
+	PINCTRL_PIN(91, "PLGPIO91"),
+	PINCTRL_PIN(92, "PLGPIO92"),
+	PINCTRL_PIN(93, "PLGPIO93"),
+	PINCTRL_PIN(94, "PLGPIO94"),
+	PINCTRL_PIN(95, "PLGPIO95"),
+	PINCTRL_PIN(96, "PLGPIO96"),
+	PINCTRL_PIN(97, "PLGPIO97"),
+	PINCTRL_PIN(98, "PLGPIO98"),
+	PINCTRL_PIN(99, "PLGPIO99"),
+	PINCTRL_PIN(100, "PLGPIO100"),
+	PINCTRL_PIN(101, "PLGPIO101"),
+};
+
+/* firda_pins */
+static const unsigned firda_pins[] = { 0, 1 };
+static struct spear_muxreg firda_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_FIRDA_MASK,
+		.val = PMX_FIRDA_MASK,
+	},
+};
+
+static struct spear_modemux firda_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = firda_muxreg,
+		.nmuxregs = ARRAY_SIZE(firda_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_firda_pingroup = {
+	.name = "firda_grp",
+	.pins = firda_pins,
+	.npins = ARRAY_SIZE(firda_pins),
+	.modemuxs = firda_modemux,
+	.nmodemuxs = ARRAY_SIZE(firda_modemux),
+};
+
+static const char *const firda_grps[] = { "firda_grp" };
+struct spear_function spear3xx_firda_function = {
+	.name = "firda",
+	.groups = firda_grps,
+	.ngroups = ARRAY_SIZE(firda_grps),
+};
+
+/* i2c_pins */
+static const unsigned i2c_pins[] = { 4, 5 };
+static struct spear_muxreg i2c_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_I2C_MASK,
+		.val = PMX_I2C_MASK,
+	},
+};
+
+static struct spear_modemux i2c_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = i2c_muxreg,
+		.nmuxregs = ARRAY_SIZE(i2c_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_i2c_pingroup = {
+	.name = "i2c0_grp",
+	.pins = i2c_pins,
+	.npins = ARRAY_SIZE(i2c_pins),
+	.modemuxs = i2c_modemux,
+	.nmodemuxs = ARRAY_SIZE(i2c_modemux),
+};
+
+static const char *const i2c_grps[] = { "i2c0_grp" };
+struct spear_function spear3xx_i2c_function = {
+	.name = "i2c0",
+	.groups = i2c_grps,
+	.ngroups = ARRAY_SIZE(i2c_grps),
+};
+
+/* ssp_cs_pins */
+static const unsigned ssp_cs_pins[] = { 34, 35, 36 };
+static struct spear_muxreg ssp_cs_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_SSP_CS_MASK,
+		.val = PMX_SSP_CS_MASK,
+	},
+};
+
+static struct spear_modemux ssp_cs_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = ssp_cs_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp_cs_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_ssp_cs_pingroup = {
+	.name = "ssp_cs_grp",
+	.pins = ssp_cs_pins,
+	.npins = ARRAY_SIZE(ssp_cs_pins),
+	.modemuxs = ssp_cs_modemux,
+	.nmodemuxs = ARRAY_SIZE(ssp_cs_modemux),
+};
+
+static const char *const ssp_cs_grps[] = { "ssp_cs_grp" };
+struct spear_function spear3xx_ssp_cs_function = {
+	.name = "ssp_cs",
+	.groups = ssp_cs_grps,
+	.ngroups = ARRAY_SIZE(ssp_cs_grps),
+};
+
+/* ssp_pins */
+static const unsigned ssp_pins[] = { 6, 7, 8, 9 };
+static struct spear_muxreg ssp_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_SSP_MASK,
+		.val = PMX_SSP_MASK,
+	},
+};
+
+static struct spear_modemux ssp_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = ssp_muxreg,
+		.nmuxregs = ARRAY_SIZE(ssp_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_ssp_pingroup = {
+	.name = "ssp0_grp",
+	.pins = ssp_pins,
+	.npins = ARRAY_SIZE(ssp_pins),
+	.modemuxs = ssp_modemux,
+	.nmodemuxs = ARRAY_SIZE(ssp_modemux),
+};
+
+static const char *const ssp_grps[] = { "ssp0_grp" };
+struct spear_function spear3xx_ssp_function = {
+	.name = "ssp0",
+	.groups = ssp_grps,
+	.ngroups = ARRAY_SIZE(ssp_grps),
+};
+
+/* mii_pins */
+static const unsigned mii_pins[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+	21, 22, 23, 24, 25, 26, 27 };
+static struct spear_muxreg mii_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_MII_MASK,
+		.val = PMX_MII_MASK,
+	},
+};
+
+static struct spear_modemux mii_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = mii_muxreg,
+		.nmuxregs = ARRAY_SIZE(mii_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_mii_pingroup = {
+	.name = "mii0_grp",
+	.pins = mii_pins,
+	.npins = ARRAY_SIZE(mii_pins),
+	.modemuxs = mii_modemux,
+	.nmodemuxs = ARRAY_SIZE(mii_modemux),
+};
+
+static const char *const mii_grps[] = { "mii0_grp" };
+struct spear_function spear3xx_mii_function = {
+	.name = "mii0",
+	.groups = mii_grps,
+	.ngroups = ARRAY_SIZE(mii_grps),
+};
+
+/* gpio0_pin0_pins */
+static const unsigned gpio0_pin0_pins[] = { 28 };
+static struct spear_muxreg gpio0_pin0_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_GPIO_PIN0_MASK,
+		.val = PMX_GPIO_PIN0_MASK,
+	},
+};
+
+static struct spear_modemux gpio0_pin0_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = gpio0_pin0_muxreg,
+		.nmuxregs = ARRAY_SIZE(gpio0_pin0_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_gpio0_pin0_pingroup = {
+	.name = "gpio0_pin0_grp",
+	.pins = gpio0_pin0_pins,
+	.npins = ARRAY_SIZE(gpio0_pin0_pins),
+	.modemuxs = gpio0_pin0_modemux,
+	.nmodemuxs = ARRAY_SIZE(gpio0_pin0_modemux),
+};
+
+/* gpio0_pin1_pins */
+static const unsigned gpio0_pin1_pins[] = { 29 };
+static struct spear_muxreg gpio0_pin1_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_GPIO_PIN1_MASK,
+		.val = PMX_GPIO_PIN1_MASK,
+	},
+};
+
+static struct spear_modemux gpio0_pin1_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = gpio0_pin1_muxreg,
+		.nmuxregs = ARRAY_SIZE(gpio0_pin1_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_gpio0_pin1_pingroup = {
+	.name = "gpio0_pin1_grp",
+	.pins = gpio0_pin1_pins,
+	.npins = ARRAY_SIZE(gpio0_pin1_pins),
+	.modemuxs = gpio0_pin1_modemux,
+	.nmodemuxs = ARRAY_SIZE(gpio0_pin1_modemux),
+};
+
+/* gpio0_pin2_pins */
+static const unsigned gpio0_pin2_pins[] = { 30 };
+static struct spear_muxreg gpio0_pin2_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_GPIO_PIN2_MASK,
+		.val = PMX_GPIO_PIN2_MASK,
+	},
+};
+
+static struct spear_modemux gpio0_pin2_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = gpio0_pin2_muxreg,
+		.nmuxregs = ARRAY_SIZE(gpio0_pin2_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_gpio0_pin2_pingroup = {
+	.name = "gpio0_pin2_grp",
+	.pins = gpio0_pin2_pins,
+	.npins = ARRAY_SIZE(gpio0_pin2_pins),
+	.modemuxs = gpio0_pin2_modemux,
+	.nmodemuxs = ARRAY_SIZE(gpio0_pin2_modemux),
+};
+
+/* gpio0_pin3_pins */
+static const unsigned gpio0_pin3_pins[] = { 31 };
+static struct spear_muxreg gpio0_pin3_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_GPIO_PIN3_MASK,
+		.val = PMX_GPIO_PIN3_MASK,
+	},
+};
+
+static struct spear_modemux gpio0_pin3_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = gpio0_pin3_muxreg,
+		.nmuxregs = ARRAY_SIZE(gpio0_pin3_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_gpio0_pin3_pingroup = {
+	.name = "gpio0_pin3_grp",
+	.pins = gpio0_pin3_pins,
+	.npins = ARRAY_SIZE(gpio0_pin3_pins),
+	.modemuxs = gpio0_pin3_modemux,
+	.nmodemuxs = ARRAY_SIZE(gpio0_pin3_modemux),
+};
+
+/* gpio0_pin4_pins */
+static const unsigned gpio0_pin4_pins[] = { 32 };
+static struct spear_muxreg gpio0_pin4_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_GPIO_PIN4_MASK,
+		.val = PMX_GPIO_PIN4_MASK,
+	},
+};
+
+static struct spear_modemux gpio0_pin4_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = gpio0_pin4_muxreg,
+		.nmuxregs = ARRAY_SIZE(gpio0_pin4_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_gpio0_pin4_pingroup = {
+	.name = "gpio0_pin4_grp",
+	.pins = gpio0_pin4_pins,
+	.npins = ARRAY_SIZE(gpio0_pin4_pins),
+	.modemuxs = gpio0_pin4_modemux,
+	.nmodemuxs = ARRAY_SIZE(gpio0_pin4_modemux),
+};
+
+/* gpio0_pin5_pins */
+static const unsigned gpio0_pin5_pins[] = { 33 };
+static struct spear_muxreg gpio0_pin5_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_GPIO_PIN5_MASK,
+		.val = PMX_GPIO_PIN5_MASK,
+	},
+};
+
+static struct spear_modemux gpio0_pin5_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = gpio0_pin5_muxreg,
+		.nmuxregs = ARRAY_SIZE(gpio0_pin5_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_gpio0_pin5_pingroup = {
+	.name = "gpio0_pin5_grp",
+	.pins = gpio0_pin5_pins,
+	.npins = ARRAY_SIZE(gpio0_pin5_pins),
+	.modemuxs = gpio0_pin5_modemux,
+	.nmodemuxs = ARRAY_SIZE(gpio0_pin5_modemux),
+};
+
+static const char *const gpio0_grps[] = { "gpio0_pin0_grp", "gpio0_pin1_grp",
+	"gpio0_pin2_grp", "gpio0_pin3_grp", "gpio0_pin4_grp", "gpio0_pin5_grp",
+};
+struct spear_function spear3xx_gpio0_function = {
+	.name = "gpio0",
+	.groups = gpio0_grps,
+	.ngroups = ARRAY_SIZE(gpio0_grps),
+};
+
+/* uart0_ext_pins */
+static const unsigned uart0_ext_pins[] = { 37, 38, 39, 40, 41, 42 };
+static struct spear_muxreg uart0_ext_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_UART0_MODEM_MASK,
+		.val = PMX_UART0_MODEM_MASK,
+	},
+};
+
+static struct spear_modemux uart0_ext_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = uart0_ext_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart0_ext_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_uart0_ext_pingroup = {
+	.name = "uart0_ext_grp",
+	.pins = uart0_ext_pins,
+	.npins = ARRAY_SIZE(uart0_ext_pins),
+	.modemuxs = uart0_ext_modemux,
+	.nmodemuxs = ARRAY_SIZE(uart0_ext_modemux),
+};
+
+static const char *const uart0_ext_grps[] = { "uart0_ext_grp" };
+struct spear_function spear3xx_uart0_ext_function = {
+	.name = "uart0_ext",
+	.groups = uart0_ext_grps,
+	.ngroups = ARRAY_SIZE(uart0_ext_grps),
+};
+
+/* uart0_pins */
+static const unsigned uart0_pins[] = { 2, 3 };
+static struct spear_muxreg uart0_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_UART0_MASK,
+		.val = PMX_UART0_MASK,
+	},
+};
+
+static struct spear_modemux uart0_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = uart0_muxreg,
+		.nmuxregs = ARRAY_SIZE(uart0_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_uart0_pingroup = {
+	.name = "uart0_grp",
+	.pins = uart0_pins,
+	.npins = ARRAY_SIZE(uart0_pins),
+	.modemuxs = uart0_modemux,
+	.nmodemuxs = ARRAY_SIZE(uart0_modemux),
+};
+
+static const char *const uart0_grps[] = { "uart0_grp" };
+struct spear_function spear3xx_uart0_function = {
+	.name = "uart0",
+	.groups = uart0_grps,
+	.ngroups = ARRAY_SIZE(uart0_grps),
+};
+
+/* timer_0_1_pins */
+static const unsigned timer_0_1_pins[] = { 43, 44, 47, 48 };
+static struct spear_muxreg timer_0_1_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_TIMER_0_1_MASK,
+		.val = PMX_TIMER_0_1_MASK,
+	},
+};
+
+static struct spear_modemux timer_0_1_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = timer_0_1_muxreg,
+		.nmuxregs = ARRAY_SIZE(timer_0_1_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_timer_0_1_pingroup = {
+	.name = "timer_0_1_grp",
+	.pins = timer_0_1_pins,
+	.npins = ARRAY_SIZE(timer_0_1_pins),
+	.modemuxs = timer_0_1_modemux,
+	.nmodemuxs = ARRAY_SIZE(timer_0_1_modemux),
+};
+
+static const char *const timer_0_1_grps[] = { "timer_0_1_grp" };
+struct spear_function spear3xx_timer_0_1_function = {
+	.name = "timer_0_1",
+	.groups = timer_0_1_grps,
+	.ngroups = ARRAY_SIZE(timer_0_1_grps),
+};
+
+/* timer_2_3_pins */
+static const unsigned timer_2_3_pins[] = { 45, 46, 49, 50 };
+static struct spear_muxreg timer_2_3_muxreg[] = {
+	{
+		.reg = -1,
+		.mask = PMX_TIMER_2_3_MASK,
+		.val = PMX_TIMER_2_3_MASK,
+	},
+};
+
+static struct spear_modemux timer_2_3_modemux[] = {
+	{
+		.modes = ~0,
+		.muxregs = timer_2_3_muxreg,
+		.nmuxregs = ARRAY_SIZE(timer_2_3_muxreg),
+	},
+};
+
+struct spear_pingroup spear3xx_timer_2_3_pingroup = {
+	.name = "timer_2_3_grp",
+	.pins = timer_2_3_pins,
+	.npins = ARRAY_SIZE(timer_2_3_pins),
+	.modemuxs = timer_2_3_modemux,
+	.nmodemuxs = ARRAY_SIZE(timer_2_3_modemux),
+};
+
+static const char *const timer_2_3_grps[] = { "timer_2_3_grp" };
+struct spear_function spear3xx_timer_2_3_function = {
+	.name = "timer_2_3",
+	.groups = timer_2_3_grps,
+	.ngroups = ARRAY_SIZE(timer_2_3_grps),
+};
+
+struct spear_pinctrl_machdata spear3xx_machdata = {
+	.pins = spear3xx_pins,
+	.npins = ARRAY_SIZE(spear3xx_pins),
+};
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.h b/drivers/pinctrl/spear/pinctrl-spear3xx.h
new file mode 100644
index 0000000..5d5fdd8
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.h
@@ -0,0 +1,92 @@
+/*
+ * Header file for the ST Microelectronics SPEAr3xx pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * 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 __PINMUX_SPEAR3XX_H__
+#define __PINMUX_SPEAR3XX_H__
+
+#include "pinctrl-spear.h"
+
+/* pad mux declarations */
+#define PMX_FIRDA_MASK		(1 << 14)
+#define PMX_I2C_MASK		(1 << 13)
+#define PMX_SSP_CS_MASK		(1 << 12)
+#define PMX_SSP_MASK		(1 << 11)
+#define PMX_MII_MASK		(1 << 10)
+#define PMX_GPIO_PIN0_MASK	(1 << 9)
+#define PMX_GPIO_PIN1_MASK	(1 << 8)
+#define PMX_GPIO_PIN2_MASK	(1 << 7)
+#define PMX_GPIO_PIN3_MASK	(1 << 6)
+#define PMX_GPIO_PIN4_MASK	(1 << 5)
+#define PMX_GPIO_PIN5_MASK	(1 << 4)
+#define PMX_UART0_MODEM_MASK	(1 << 3)
+#define PMX_UART0_MASK		(1 << 2)
+#define PMX_TIMER_2_3_MASK	(1 << 1)
+#define PMX_TIMER_0_1_MASK	(1 << 0)
+
+extern struct spear_pingroup spear3xx_firda_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin0_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin1_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin2_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin3_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin4_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin5_pingroup;
+extern struct spear_pingroup spear3xx_i2c_pingroup;
+extern struct spear_pingroup spear3xx_mii_pingroup;
+extern struct spear_pingroup spear3xx_ssp_cs_pingroup;
+extern struct spear_pingroup spear3xx_ssp_pingroup;
+extern struct spear_pingroup spear3xx_timer_0_1_pingroup;
+extern struct spear_pingroup spear3xx_timer_2_3_pingroup;
+extern struct spear_pingroup spear3xx_uart0_ext_pingroup;
+extern struct spear_pingroup spear3xx_uart0_pingroup;
+
+#define SPEAR3XX_COMMON_PINGROUPS		\
+	&spear3xx_firda_pingroup,		\
+	&spear3xx_gpio0_pin0_pingroup,		\
+	&spear3xx_gpio0_pin1_pingroup,		\
+	&spear3xx_gpio0_pin2_pingroup,		\
+	&spear3xx_gpio0_pin3_pingroup,		\
+	&spear3xx_gpio0_pin4_pingroup,		\
+	&spear3xx_gpio0_pin5_pingroup,		\
+	&spear3xx_i2c_pingroup,			\
+	&spear3xx_mii_pingroup,			\
+	&spear3xx_ssp_cs_pingroup,		\
+	&spear3xx_ssp_pingroup,			\
+	&spear3xx_timer_0_1_pingroup,		\
+	&spear3xx_timer_2_3_pingroup,		\
+	&spear3xx_uart0_ext_pingroup,		\
+	&spear3xx_uart0_pingroup
+
+extern struct spear_function spear3xx_firda_function;
+extern struct spear_function spear3xx_gpio0_function;
+extern struct spear_function spear3xx_i2c_function;
+extern struct spear_function spear3xx_mii_function;
+extern struct spear_function spear3xx_ssp_cs_function;
+extern struct spear_function spear3xx_ssp_function;
+extern struct spear_function spear3xx_timer_0_1_function;
+extern struct spear_function spear3xx_timer_2_3_function;
+extern struct spear_function spear3xx_uart0_ext_function;
+extern struct spear_function spear3xx_uart0_function;
+
+#define SPEAR3XX_COMMON_FUNCTIONS		\
+	&spear3xx_firda_function,		\
+	&spear3xx_gpio0_function,		\
+	&spear3xx_i2c_function,			\
+	&spear3xx_mii_function,			\
+	&spear3xx_ssp_cs_function,		\
+	&spear3xx_ssp_function,			\
+	&spear3xx_timer_0_1_function,		\
+	&spear3xx_timer_2_3_function,		\
+	&spear3xx_uart0_ext_function,		\
+	&spear3xx_uart0_function
+
+extern struct spear_pinctrl_machdata spear3xx_machdata;
+
+#endif /* __PINMUX_SPEAR3XX_H__ */
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 6b26666..c4c1a54 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -1,7 +1,7 @@
 /*-*-linux-c-*-*/
 
 /*
-  Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+  Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
   Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
   Copyright (C) 2008 Tony Vroon <tony@linx.net>
   Based on earlier work:
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 222ccd8..f5d6d37 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -451,7 +451,7 @@
 }
 
 /*
- * Return the battery Voltage in milivolts
+ * Return the battery Voltage in millivolts
  * Or < 0 if something fails.
  */
 static int bq27x00_battery_voltage(struct bq27x00_device_info *di,
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index a409fa0..93d0a8b 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -338,7 +338,7 @@
 	mutex_unlock(&ps3av->mutex);
 	return 0;
 
-      err:
+err:
 	mutex_unlock(&ps3av->mutex);
 	printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
 	return res;
@@ -477,7 +477,6 @@
 
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_set_audio_mode);
 
 static int ps3av_set_videomode(void)
@@ -501,7 +500,7 @@
 
 	video_mode = &video_mode_table[id & PS3AV_MODE_MASK];
 
-	avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO;	/* num of head */
+	avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
 	avb_param.num_of_audio_pkt = 0;
 	avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi +
 					ps3av->av_hw_conf.num_of_avmulti;
@@ -521,7 +520,7 @@
 #ifndef PS3AV_HDMI_YUV
 		if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
 		    ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
-			av_video_cs = RGB8;	/* use RGB for HDMI */
+			av_video_cs = RGB8; /* use RGB for HDMI */
 #endif
 		len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
 						 ps3av->av_port[i],
@@ -590,8 +589,8 @@
 #define SHIFT_VESA	8
 
 static const struct {
-	unsigned mask : 19;
-	unsigned id :  4;
+	unsigned mask:19;
+	unsigned id:4;
 } ps3av_preferred_modes[] = {
 	{ PS3AV_RESBIT_WUXGA      << SHIFT_VESA, PS3AV_MODE_WUXGA   },
 	{ PS3AV_RESBIT_1920x1080P << SHIFT_60,   PS3AV_MODE_1080P60 },
@@ -667,7 +666,8 @@
 	return id;
 }
 
-static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info)
+static void ps3av_monitor_info_dump(
+	const struct ps3av_pkt_av_get_monitor_info *monitor_info)
 {
 	const struct ps3av_info_monitor *info = &monitor_info->info;
 	const struct ps3av_info_audio *audio = info->audio;
@@ -717,8 +717,8 @@
 
 	/* audio block */
 	for (i = 0; i < info->num_of_audio_block; i++) {
-		pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: "
-			 "%02x\n",
+		pr_debug(
+			"audio[%d] type: %02x max_ch: %02x fs: %02x sbit: %02x\n",
 			 i, audio->type, audio->max_num_of_ch, audio->fs,
 			 audio->sbit);
 		audio++;
@@ -870,21 +870,18 @@
 
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
 
 int ps3av_get_auto_mode(void)
 {
 	return ps3av_auto_videomode(&ps3av->av_hw_conf);
 }
-
 EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
 
 int ps3av_get_mode(void)
 {
 	return ps3av ? ps3av->ps3av_mode : 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_get_mode);
 
 /* get resolution by video_mode */
@@ -902,7 +899,6 @@
 	*yres = video_mode_table[id].y;
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_video_mode2res);
 
 /* mute */
@@ -911,7 +907,6 @@
 	return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON
 					    : PS3AV_CMD_MUTE_OFF);
 }
-
 EXPORT_SYMBOL_GPL(ps3av_video_mute);
 
 /* mute analog output only */
@@ -935,7 +930,6 @@
 	return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
 					 : PS3AV_CMD_MUTE_OFF);
 }
-
 EXPORT_SYMBOL_GPL(ps3av_audio_mute);
 
 static int __devinit ps3av_probe(struct ps3_system_bus_device *dev)
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 5648dad..ffdf712 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -70,7 +70,7 @@
 	  using the SO_TIMESTAMPING API.
 
 	  In order for this to work, your MAC driver must also
-	  implement the skb_tx_timetamp() function.
+	  implement the skb_tx_timestamp() function.
 
 config PTP_1588_CLOCK_PCH
 	tristate "Intel PCH EG20T as PTP clock"
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 8dc3d93..4e01a42 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -31,54 +31,54 @@
 			TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 |		\
 			TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
 
-/* supported VIO voltages in milivolts */
+/* supported VIO voltages in millivolts */
 static const u16 VIO_VSEL_table[] = {
 	1500, 1800, 2500, 3300,
 };
 
 /* VSEL tables for TPS65910 specific LDOs and dcdc's */
 
-/* supported VDD3 voltages in milivolts */
+/* supported VDD3 voltages in millivolts */
 static const u16 VDD3_VSEL_table[] = {
 	5000,
 };
 
-/* supported VDIG1 voltages in milivolts */
+/* supported VDIG1 voltages in millivolts */
 static const u16 VDIG1_VSEL_table[] = {
 	1200, 1500, 1800, 2700,
 };
 
-/* supported VDIG2 voltages in milivolts */
+/* supported VDIG2 voltages in millivolts */
 static const u16 VDIG2_VSEL_table[] = {
 	1000, 1100, 1200, 1800,
 };
 
-/* supported VPLL voltages in milivolts */
+/* supported VPLL voltages in millivolts */
 static const u16 VPLL_VSEL_table[] = {
 	1000, 1100, 1800, 2500,
 };
 
-/* supported VDAC voltages in milivolts */
+/* supported VDAC voltages in millivolts */
 static const u16 VDAC_VSEL_table[] = {
 	1800, 2600, 2800, 2850,
 };
 
-/* supported VAUX1 voltages in milivolts */
+/* supported VAUX1 voltages in millivolts */
 static const u16 VAUX1_VSEL_table[] = {
 	1800, 2500, 2800, 2850,
 };
 
-/* supported VAUX2 voltages in milivolts */
+/* supported VAUX2 voltages in millivolts */
 static const u16 VAUX2_VSEL_table[] = {
 	1800, 2800, 2900, 3300,
 };
 
-/* supported VAUX33 voltages in milivolts */
+/* supported VAUX33 voltages in millivolts */
 static const u16 VAUX33_VSEL_table[] = {
 	1800, 2000, 2800, 3300,
 };
 
-/* supported VMMC voltages in milivolts */
+/* supported VMMC voltages in millivolts */
 static const u16 VMMC_VSEL_table[] = {
 	1800, 2800, 3000, 3300,
 };
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index e756a0d..d6f8ada 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1105,8 +1105,7 @@
 		goto out;
 
 out:
-	if (fw)
-		release_firmware(fw);
+	release_firmware(fw);
 	/* allow rproc_unregister() contexts, if any, to proceed */
 	complete_all(&rproc->firmware_loading_complete);
 }
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8c8377d..4161bfe 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -838,7 +838,7 @@
 
 config RTC_DRV_AT91RM9200
 	tristate "AT91RM9200 or some AT91SAM9 RTC"
-	depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+	depends on ARCH_AT91
 	help
 	  Driver for the internal RTC (Realtime Clock) module found on
 	  Atmel AT91RM9200's and some  AT91SAM9 chips. On AT91SAM9 chips
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 4f9f1dc..6c0116d 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/err.h>
 #include <linux/reboot.h>
+#include <linux/serial.h> /* ASYNC_* flags */
 #include <linux/slab.h>
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
@@ -44,14 +45,11 @@
 #define RAW3215_TIMEOUT	    HZ/10     /* time for delayed output */
 
 #define RAW3215_FIXED	    1	      /* 3215 console device is not be freed */
-#define RAW3215_ACTIVE	    2	      /* set if the device is in use */
 #define RAW3215_WORKING	    4	      /* set if a request is being worked on */
 #define RAW3215_THROTTLED   8	      /* set if reading is disabled */
 #define RAW3215_STOPPED	    16	      /* set if writing is disabled */
-#define RAW3215_CLOSING	    32	      /* set while in close process */
 #define RAW3215_TIMER_RUNS  64	      /* set if the output delay timer is on */
 #define RAW3215_FLUSHING    128	      /* set to flush buffer (no delay) */
-#define RAW3215_FROZEN	    256	      /* set if 3215 is frozen for suspend */
 
 #define TAB_STOP_SIZE	    8	      /* tab stop size */
 
@@ -76,6 +74,7 @@
 } __attribute__ ((aligned(8)));
 
 struct raw3215_info {
+	struct tty_port port;
 	struct ccw_device *cdev;      /* device for tty driver */
 	spinlock_t *lock;	      /* pointer to irq lock */
 	int flags;		      /* state flags */
@@ -84,7 +83,6 @@
 	int head;		      /* first free byte in output buffer */
 	int count;		      /* number of bytes in output buffer */
 	int written;		      /* number of bytes in write requests */
-	struct tty_struct *tty;	      /* pointer to tty structure if present */
 	struct raw3215_req *queued_read; /* pointer to queued read requests */
 	struct raw3215_req *queued_write;/* pointer to queued write requests */
 	struct tasklet_struct tlet;   /* tasklet to invoke tty_wakeup */
@@ -293,7 +291,7 @@
 	if (raw->flags & RAW3215_TIMER_RUNS) {
 		del_timer(&raw->timer);
 		raw->flags &= ~RAW3215_TIMER_RUNS;
-		if (!(raw->flags & RAW3215_FROZEN)) {
+		if (!(raw->port.flags & ASYNC_SUSPENDED)) {
 			raw3215_mk_write_req(raw);
 			raw3215_start_io(raw);
 		}
@@ -309,7 +307,8 @@
  */
 static inline void raw3215_try_io(struct raw3215_info *raw)
 {
-	if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN))
+	if (!(raw->port.flags & ASYNC_INITIALIZED) ||
+			(raw->port.flags & ASYNC_SUSPENDED))
 		return;
 	if (raw->queued_read != NULL)
 		raw3215_start_io(raw);
@@ -324,10 +323,7 @@
 			}
 		} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
 			/* delay small writes */
-			init_timer(&raw->timer);
 			raw->timer.expires = RAW3215_TIMEOUT + jiffies;
-			raw->timer.data = (unsigned long) raw;
-			raw->timer.function = raw3215_timeout;
 			add_timer(&raw->timer);
 			raw->flags |= RAW3215_TIMER_RUNS;
 		}
@@ -340,17 +336,21 @@
 static void raw3215_wakeup(unsigned long data)
 {
 	struct raw3215_info *raw = (struct raw3215_info *) data;
-	tty_wakeup(raw->tty);
+	struct tty_struct *tty;
+
+	tty = tty_port_tty_get(&raw->port);
+	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 /*
  * Try to start the next IO and wake up processes waiting on the tty.
  */
-static void raw3215_next_io(struct raw3215_info *raw)
+static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty)
 {
 	raw3215_mk_write_req(raw);
 	raw3215_try_io(raw);
-	if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
+	if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
 		tasklet_schedule(&raw->tlet);
 }
 
@@ -368,10 +368,11 @@
 
 	raw = dev_get_drvdata(&cdev->dev);
 	req = (struct raw3215_req *) intparm;
+	tty = tty_port_tty_get(&raw->port);
 	cstat = irb->scsw.cmd.cstat;
 	dstat = irb->scsw.cmd.dstat;
 	if (cstat != 0)
-		raw3215_next_io(raw);
+		raw3215_next_io(raw, tty);
 	if (dstat & 0x01) { /* we got a unit exception */
 		dstat &= ~0x01;	 /* we can ignore it */
 	}
@@ -381,13 +382,13 @@
 			break;
 		/* Attention interrupt, someone hit the enter key */
 		raw3215_mk_read_req(raw);
-		raw3215_next_io(raw);
+		raw3215_next_io(raw, tty);
 		break;
 	case 0x08:
 	case 0x0C:
 		/* Channel end interrupt. */
 		if ((raw = req->info) == NULL)
-			return;		     /* That shouldn't happen ... */
+			goto put_tty;	     /* That shouldn't happen ... */
 		if (req->type == RAW3215_READ) {
 			/* store residual count, then wait for device end */
 			req->residual = irb->scsw.cmd.count;
@@ -397,11 +398,10 @@
 	case 0x04:
 		/* Device end interrupt. */
 		if ((raw = req->info) == NULL)
-			return;		     /* That shouldn't happen ... */
-		if (req->type == RAW3215_READ && raw->tty != NULL) {
+			goto put_tty;	     /* That shouldn't happen ... */
+		if (req->type == RAW3215_READ && tty != NULL) {
 			unsigned int cchar;
 
-			tty = raw->tty;
 			count = 160 - req->residual;
 			EBCASC(raw->inbuf, count);
 			cchar = ctrlchar_handle(raw->inbuf, count, tty);
@@ -411,7 +411,7 @@
 
 			case CTRLCHAR_CTRL:
 				tty_insert_flip_char(tty, cchar, TTY_NORMAL);
-				tty_flip_buffer_push(raw->tty);
+				tty_flip_buffer_push(tty);
 				break;
 
 			case CTRLCHAR_NONE:
@@ -424,7 +424,7 @@
 				} else
 					count -= 2;
 				tty_insert_flip_string(tty, raw->inbuf, count);
-				tty_flip_buffer_push(raw->tty);
+				tty_flip_buffer_push(tty);
 				break;
 			}
 		} else if (req->type == RAW3215_WRITE) {
@@ -439,7 +439,7 @@
 		    raw->queued_read == NULL) {
 			wake_up_interruptible(&raw->empty_wait);
 		}
-		raw3215_next_io(raw);
+		raw3215_next_io(raw, tty);
 		break;
 	default:
 		/* Strange interrupt, I'll do my best to clean up */
@@ -451,9 +451,10 @@
 			raw->flags &= ~RAW3215_WORKING;
 			raw3215_free_req(req);
 		}
-		raw3215_next_io(raw);
+		raw3215_next_io(raw, tty);
 	}
-	return;
+put_tty:
+	tty_kref_put(tty);
 }
 
 /*
@@ -487,7 +488,7 @@
 		/* While console is frozen for suspend we have no other
 		 * choice but to drop message from the buffer to make
 		 * room for even more messages. */
-		if (raw->flags & RAW3215_FROZEN) {
+		if (raw->port.flags & ASYNC_SUSPENDED) {
 			raw3215_drop_line(raw);
 			continue;
 		}
@@ -609,10 +610,10 @@
 {
 	unsigned long flags;
 
-	if (raw->flags & RAW3215_ACTIVE)
+	if (raw->port.flags & ASYNC_INITIALIZED)
 		return 0;
 	raw->line_pos = 0;
-	raw->flags |= RAW3215_ACTIVE;
+	raw->port.flags |= ASYNC_INITIALIZED;
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	raw3215_try_io(raw);
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -628,14 +629,15 @@
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 
-	if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED))
+	if (!(raw->port.flags & ASYNC_INITIALIZED) ||
+			(raw->flags & RAW3215_FIXED))
 		return;
 	/* Wait for outstanding requests, then free irq */
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	if ((raw->flags & RAW3215_WORKING) ||
 	    raw->queued_write != NULL ||
 	    raw->queued_read != NULL) {
-		raw->flags |= RAW3215_CLOSING;
+		raw->port.flags |= ASYNC_CLOSING;
 		add_wait_queue(&raw->empty_wait, &wait);
 		set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -643,11 +645,41 @@
 		spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 		remove_wait_queue(&raw->empty_wait, &wait);
 		set_current_state(TASK_RUNNING);
-		raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
+		raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING);
 	}
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 }
 
+static struct raw3215_info *raw3215_alloc_info(void)
+{
+	struct raw3215_info *info;
+
+	info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
+	if (!info)
+		return NULL;
+
+	info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
+	info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
+	if (!info->buffer || !info->inbuf) {
+		kfree(info);
+		return NULL;
+	}
+
+	setup_timer(&info->timer, raw3215_timeout, (unsigned long)info);
+	init_waitqueue_head(&info->empty_wait);
+	tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info);
+	tty_port_init(&info->port);
+
+	return info;
+}
+
+static void raw3215_free_info(struct raw3215_info *raw)
+{
+	kfree(raw->inbuf);
+	kfree(raw->buffer);
+	kfree(raw);
+}
+
 static int raw3215_probe (struct ccw_device *cdev)
 {
 	struct raw3215_info *raw;
@@ -656,11 +688,15 @@
 	/* Console is special. */
 	if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
 		return 0;
-	raw = kmalloc(sizeof(struct raw3215_info) +
-		      RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
+
+	raw = raw3215_alloc_info();
 	if (raw == NULL)
 		return -ENOMEM;
 
+	raw->cdev = cdev;
+	dev_set_drvdata(&cdev->dev, raw);
+	cdev->handler = raw3215_irq;
+
 	spin_lock(&raw3215_device_lock);
 	for (line = 0; line < NR_3215; line++) {
 		if (!raw3215[line]) {
@@ -670,28 +706,10 @@
 	}
 	spin_unlock(&raw3215_device_lock);
 	if (line == NR_3215) {
-		kfree(raw);
+		raw3215_free_info(raw);
 		return -ENODEV;
 	}
 
-	raw->cdev = cdev;
-	raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
-	memset(raw, 0, sizeof(struct raw3215_info));
-	raw->buffer = kmalloc(RAW3215_BUFFER_SIZE,
-				       GFP_KERNEL|GFP_DMA);
-	if (raw->buffer == NULL) {
-		spin_lock(&raw3215_device_lock);
-		raw3215[line] = NULL;
-		spin_unlock(&raw3215_device_lock);
-		kfree(raw);
-		return -ENOMEM;
-	}
-	init_waitqueue_head(&raw->empty_wait);
-	tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
-
-	dev_set_drvdata(&cdev->dev, raw);
-	cdev->handler = raw3215_irq;
-
 	return 0;
 }
 
@@ -703,8 +721,7 @@
 	raw = dev_get_drvdata(&cdev->dev);
 	if (raw) {
 		dev_set_drvdata(&cdev->dev, NULL);
-		kfree(raw->buffer);
-		kfree(raw);
+		raw3215_free_info(raw);
 	}
 }
 
@@ -741,7 +758,7 @@
 	raw = dev_get_drvdata(&cdev->dev);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
-	raw->flags |= RAW3215_FROZEN;
+	raw->port.flags |= ASYNC_SUSPENDED;
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 	return 0;
 }
@@ -754,7 +771,7 @@
 	/* Allow I/O again and flush output buffer. */
 	raw = dev_get_drvdata(&cdev->dev);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
-	raw->flags &= ~RAW3215_FROZEN;
+	raw->port.flags &= ~ASYNC_SUSPENDED;
 	raw->flags |= RAW3215_FLUSHING;
 	raw3215_try_io(raw);
 	raw->flags &= ~RAW3215_FLUSHING;
@@ -827,7 +844,7 @@
 	unsigned long flags;
 
 	raw = raw3215[0];  /* console 3215 is the first one */
-	if (raw->flags & RAW3215_FROZEN)
+	if (raw->port.flags & ASYNC_SUSPENDED)
 		/* The console is still frozen for suspend. */
 		if (ccw_device_force_console())
 			/* Forcing didn't work, no panic message .. */
@@ -897,23 +914,16 @@
 	if (IS_ERR(cdev))
 		return -ENODEV;
 
-	raw3215[0] = raw = (struct raw3215_info *)
-		kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
-	raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
-	raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
+	raw3215[0] = raw = raw3215_alloc_info();
 	raw->cdev = cdev;
 	dev_set_drvdata(&cdev->dev, raw);
 	cdev->handler = raw3215_irq;
 
 	raw->flags |= RAW3215_FIXED;
-	init_waitqueue_head(&raw->empty_wait);
-	tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
 
 	/* Request the console irq */
 	if (raw3215_startup(raw) != 0) {
-		kfree(raw->inbuf);
-		kfree(raw->buffer);
-		kfree(raw);
+		raw3215_free_info(raw);
 		raw3215[0] = NULL;
 		return -ENODEV;
 	}
@@ -940,7 +950,7 @@
 		return -ENODEV;
 
 	tty->driver_data = raw;
-	raw->tty = tty;
+	tty_port_tty_set(&raw->port, tty);
 
 	tty->low_latency = 0;  /* don't use bottom half for pushing chars */
 	/*
@@ -971,7 +981,7 @@
 	raw3215_shutdown(raw);
 	tasklet_kill(&raw->tlet);
 	tty->closing = 0;
-	raw->tty = NULL;
+	tty_port_tty_set(&raw->port, NULL);
 }
 
 /*
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 8065881..7ef9cfd 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -199,7 +199,7 @@
 	if (ch == ' ' || ch == d)
 		return d;
 
-	kbd_put_queue(kbd->tty, d);
+	kbd_put_queue(kbd->port, d);
 	return ch;
 }
 
@@ -221,7 +221,7 @@
 {
 	if (kbd->diacr)
 		value = handle_diacr(kbd, value);
-	kbd_put_queue(kbd->tty, value);
+	kbd_put_queue(kbd->port, value);
 }
 
 /*
@@ -239,7 +239,7 @@
 k_fn(struct kbd_data *kbd, unsigned char value)
 {
 	if (kbd->func_table[value])
-		kbd_puts_queue(kbd->tty, kbd->func_table[value]);
+		kbd_puts_queue(kbd->port, kbd->func_table[value]);
 }
 
 static void
@@ -257,20 +257,20 @@
  * but we need only 16 bits here
  */
 static void
-to_utf8(struct tty_struct *tty, ushort c) 
+to_utf8(struct tty_port *port, ushort c)
 {
 	if (c < 0x80)
 		/*  0******* */
-		kbd_put_queue(tty, c);
+		kbd_put_queue(port, c);
 	else if (c < 0x800) {
 		/* 110***** 10****** */
-		kbd_put_queue(tty, 0xc0 | (c >> 6));
-		kbd_put_queue(tty, 0x80 | (c & 0x3f));
+		kbd_put_queue(port, 0xc0 | (c >> 6));
+		kbd_put_queue(port, 0x80 | (c & 0x3f));
 	} else {
 		/* 1110**** 10****** 10****** */
-		kbd_put_queue(tty, 0xe0 | (c >> 12));
-		kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f));
-		kbd_put_queue(tty, 0x80 | (c & 0x3f));
+		kbd_put_queue(port, 0xe0 | (c >> 12));
+		kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
+		kbd_put_queue(port, 0x80 | (c & 0x3f));
 	}
 }
 
@@ -283,7 +283,7 @@
 	unsigned short keysym;
 	unsigned char type, value;
 
-	if (!kbd || !kbd->tty)
+	if (!kbd)
 		return;
 
 	if (keycode >= 384)
@@ -323,7 +323,7 @@
 #endif
 		(*k_handler[type])(kbd, value);
 	} else
-		to_utf8(kbd->tty, keysym);
+		to_utf8(kbd->port, keysym);
 }
 
 /*
@@ -457,6 +457,7 @@
 
 int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
 {
+	struct tty_struct *tty;
 	void __user *argp;
 	unsigned int ct;
 	int perm;
@@ -467,7 +468,10 @@
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
-	perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
+	tty = tty_port_tty_get(kbd->port);
+	/* FIXME this test is pretty racy */
+	perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG);
+	tty_kref_put(tty);
 	switch (cmd) {
 	case KDGKBTYPE:
 		return put_user(KB_101, (char __user *)argp);
diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h
index 7e736aa..f682f4e 100644
--- a/drivers/s390/char/keyboard.h
+++ b/drivers/s390/char/keyboard.h
@@ -21,7 +21,7 @@
  */
 
 struct kbd_data {
-	struct tty_struct *tty;
+	struct tty_port *port;
 	unsigned short **key_maps;
 	char **func_table;
 	fn_handler_fn **fn_handler;
@@ -42,16 +42,24 @@
  * Helper Functions.
  */
 static inline void
-kbd_put_queue(struct tty_struct *tty, int ch)
+kbd_put_queue(struct tty_port *port, int ch)
 {
+	struct tty_struct *tty = tty_port_tty_get(port);
+	if (!tty)
+		return;
 	tty_insert_flip_char(tty, ch, 0);
 	tty_schedule_flip(tty);
+	tty_kref_put(tty);
 }
 
 static inline void
-kbd_puts_queue(struct tty_struct *tty, char *cp)
+kbd_puts_queue(struct tty_port *port, char *cp)
 {
+	struct tty_struct *tty = tty_port_tty_get(port);
+	if (!tty)
+		return;
 	while (*cp)
 		tty_insert_flip_char(tty, *cp++, 0);
 	tty_schedule_flip(tty);
+	tty_kref_put(tty);
 }
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 40a9d69..e66a75b 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -48,7 +48,7 @@
 /* Timer for delayed output of console messages. */
 static struct timer_list sclp_tty_timer;
 
-static struct tty_struct *sclp_tty;
+static struct tty_port sclp_port;
 static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
 static unsigned short int sclp_tty_chars_count;
 
@@ -64,7 +64,7 @@
 static int
 sclp_tty_open(struct tty_struct *tty, struct file *filp)
 {
-	sclp_tty = tty;
+	tty_port_tty_set(&sclp_port, tty);
 	tty->driver_data = NULL;
 	tty->low_latency = 0;
 	return 0;
@@ -76,7 +76,7 @@
 {
 	if (tty->count > 1)
 		return;
-	sclp_tty = NULL;
+	tty_port_tty_set(&sclp_port, NULL);
 }
 
 /*
@@ -108,6 +108,7 @@
 static void
 sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
 {
+	struct tty_struct *tty;
 	unsigned long flags;
 	void *page;
 
@@ -126,8 +127,10 @@
 		spin_unlock_irqrestore(&sclp_tty_lock, flags);
 	} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
 	/* check if the tty needs a wake up call */
-	if (sclp_tty != NULL) {
-		tty_wakeup(sclp_tty);
+	tty = tty_port_tty_get(&sclp_port);
+	if (tty != NULL) {
+		tty_wakeup(tty);
+		tty_kref_put(tty);
 	}
 }
 
@@ -326,21 +329,22 @@
 static void
 sclp_tty_input(unsigned char* buf, unsigned int count)
 {
+	struct tty_struct *tty = tty_port_tty_get(&sclp_port);
 	unsigned int cchar;
 
 	/*
 	 * If this tty driver is currently closed
 	 * then throw the received input away.
 	 */
-	if (sclp_tty == NULL)
+	if (tty == NULL)
 		return;
-	cchar = ctrlchar_handle(buf, count, sclp_tty);
+	cchar = ctrlchar_handle(buf, count, tty);
 	switch (cchar & CTRLCHAR_MASK) {
 	case CTRLCHAR_SYSRQ:
 		break;
 	case CTRLCHAR_CTRL:
-		tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL);
-		tty_flip_buffer_push(sclp_tty);
+		tty_insert_flip_char(tty, cchar, TTY_NORMAL);
+		tty_flip_buffer_push(tty);
 		break;
 	case CTRLCHAR_NONE:
 		/* send (normal) input to line discipline */
@@ -348,13 +352,14 @@
 		    (strncmp((const char *) buf + count - 2, "^n", 2) &&
 		     strncmp((const char *) buf + count - 2, "\252n", 2))) {
 			/* add the auto \n */
-			tty_insert_flip_string(sclp_tty, buf, count);
-			tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL);
+			tty_insert_flip_string(tty, buf, count);
+			tty_insert_flip_char(tty, '\n', TTY_NORMAL);
 		} else
-			tty_insert_flip_string(sclp_tty, buf, count - 2);
-		tty_flip_buffer_push(sclp_tty);
+			tty_insert_flip_string(tty, buf, count - 2);
+		tty_flip_buffer_push(tty);
 		break;
 	}
+	tty_kref_put(tty);
 }
 
 /*
@@ -543,7 +548,7 @@
 		sclp_tty_tolower = 1;
 	}
 	sclp_tty_chars_count = 0;
-	sclp_tty = NULL;
+	tty_port_init(&sclp_port);
 
 	rc = sclp_register(&sclp_input_event);
 	if (rc) {
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index b635472..edfc0fd 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -34,7 +34,6 @@
 #define SCLP_VT220_DEVICE_NAME		"ttysclp"
 #define SCLP_VT220_CONSOLE_NAME		"ttyS"
 #define SCLP_VT220_CONSOLE_INDEX	1	/* console=ttyS1 */
-#define SCLP_VT220_BUF_SIZE		80
 
 /* Representation of a single write request */
 struct sclp_vt220_request {
@@ -56,8 +55,7 @@
 /* Structures and data needed to register tty driver */
 static struct tty_driver *sclp_vt220_driver;
 
-/* The tty_struct that the kernel associated with us */
-static struct tty_struct *sclp_vt220_tty;
+static struct tty_port sclp_vt220_port;
 
 /* Lock to protect internal data from concurrent access */
 static spinlock_t sclp_vt220_lock;
@@ -116,6 +114,7 @@
 static void
 sclp_vt220_process_queue(struct sclp_vt220_request *request)
 {
+	struct tty_struct *tty;
 	unsigned long flags;
 	void *page;
 
@@ -141,8 +140,10 @@
 	if (request == NULL && sclp_vt220_flush_later)
 		sclp_vt220_emit_current();
 	/* Check if the tty needs a wake up call */
-	if (sclp_vt220_tty != NULL) {
-		tty_wakeup(sclp_vt220_tty);
+	tty = tty_port_tty_get(&sclp_vt220_port);
+	if (tty) {
+		tty_wakeup(tty);
+		tty_kref_put(tty);
 	}
 }
 
@@ -460,11 +461,12 @@
 static void
 sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
 {
+	struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
 	char *buffer;
 	unsigned int count;
 
 	/* Ignore input if device is not open */
-	if (sclp_vt220_tty == NULL)
+	if (tty == NULL)
 		return;
 
 	buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
@@ -478,10 +480,11 @@
 		/* Send input to line discipline */
 		buffer++;
 		count--;
-		tty_insert_flip_string(sclp_vt220_tty, buffer, count);
-		tty_flip_buffer_push(sclp_vt220_tty);
+		tty_insert_flip_string(tty, buffer, count);
+		tty_flip_buffer_push(tty);
 		break;
 	}
+	tty_kref_put(tty);
 }
 
 /*
@@ -491,10 +494,7 @@
 sclp_vt220_open(struct tty_struct *tty, struct file *filp)
 {
 	if (tty->count == 1) {
-		sclp_vt220_tty = tty;
-		tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);
-		if (tty->driver_data == NULL)
-			return -ENOMEM;
+		tty_port_tty_set(&sclp_vt220_port, tty);
 		tty->low_latency = 0;
 		if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
 			tty->winsize.ws_row = 24;
@@ -510,11 +510,8 @@
 static void
 sclp_vt220_close(struct tty_struct *tty, struct file *filp)
 {
-	if (tty->count == 1) {
-		sclp_vt220_tty = NULL;
-		kfree(tty->driver_data);
-		tty->driver_data = NULL;
-	}
+	if (tty->count == 1)
+		tty_port_tty_set(&sclp_vt220_port, NULL);
 }
 
 /*
@@ -635,9 +632,9 @@
 	INIT_LIST_HEAD(&sclp_vt220_empty);
 	INIT_LIST_HEAD(&sclp_vt220_outqueue);
 	init_timer(&sclp_vt220_timer);
+	tty_port_init(&sclp_vt220_port);
 	sclp_vt220_current_request = NULL;
 	sclp_vt220_buffered_chars = 0;
-	sclp_vt220_tty = NULL;
 	sclp_vt220_flush_later = 0;
 
 	/* Allocate pages for output buffering */
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index b43445a..10ec690 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -61,7 +61,7 @@
  */
 struct tty3270 {
 	struct raw3270_view view;
-	struct tty_struct *tty;		/* Pointer to tty structure */
+	struct tty_port port;
 	void **freemem_pages;		/* Array of pages used for freemem. */
 	struct list_head freemem;	/* List of free memory for strings. */
 
@@ -324,9 +324,8 @@
 static void
 tty3270_write_callback(struct raw3270_request *rq, void *data)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
 
-	tp = (struct tty3270 *) rq->view;
 	if (rq->rc != 0) {
 		/* Write wasn't successful. Refresh all. */
 		tp->update_flags = TTY_UPDATE_ALL;
@@ -450,10 +449,9 @@
 static void
 tty3270_rcl_backward(struct kbd_data *kbd)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 	struct string *s;
 
-	tp = kbd->tty->driver_data;
 	spin_lock_bh(&tp->view.lock);
 	if (tp->inattr == TF_INPUT) {
 		if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
@@ -478,9 +476,8 @@
 static void
 tty3270_exit_tty(struct kbd_data *kbd)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 
-	tp = kbd->tty->driver_data;
 	raw3270_deactivate_view(&tp->view);
 }
 
@@ -490,10 +487,9 @@
 static void
 tty3270_scroll_forward(struct kbd_data *kbd)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 	int nr_up;
 
-	tp = kbd->tty->driver_data;
 	spin_lock_bh(&tp->view.lock);
 	nr_up = tp->nr_up - tp->view.rows + 2;
 	if (nr_up < 0)
@@ -513,10 +509,9 @@
 static void
 tty3270_scroll_backward(struct kbd_data *kbd)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 	int nr_up;
 
-	tp = kbd->tty->driver_data;
 	spin_lock_bh(&tp->view.lock);
 	nr_up = tp->nr_up + tp->view.rows - 2;
 	if (nr_up + tp->view.rows - 2 > tp->nr_lines)
@@ -537,11 +532,10 @@
 tty3270_read_tasklet(struct raw3270_request *rrq)
 {
 	static char kreset_data = TW_KR;
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
 	char *input;
 	int len;
 
-	tp = (struct tty3270 *) rrq->view;
 	spin_lock_bh(&tp->view.lock);
 	/*
 	 * Two AID keys are special: For 0x7d (enter) the input line
@@ -577,13 +571,10 @@
 	raw3270_request_add_data(tp->kreset, &kreset_data, 1);
 	raw3270_start(&tp->view, tp->kreset);
 
-	/* Emit input string. */
-	if (tp->tty) {
-		while (len-- > 0)
-			kbd_keycode(tp->kbd, *input++);
-		/* Emit keycode for AID byte. */
-		kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
-	}
+	while (len-- > 0)
+		kbd_keycode(tp->kbd, *input++);
+	/* Emit keycode for AID byte. */
+	kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
 
 	raw3270_request_reset(rrq);
 	xchg(&tp->read, rrq);
@@ -596,9 +587,10 @@
 static void
 tty3270_read_callback(struct raw3270_request *rq, void *data)
 {
+	struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
 	raw3270_get_view(rq->view);
 	/* Schedule tasklet to pass input to tty. */
-	tasklet_schedule(&((struct tty3270 *) rq->view)->readlet);
+	tasklet_schedule(&tp->readlet);
 }
 
 /*
@@ -635,9 +627,8 @@
 static int
 tty3270_activate(struct raw3270_view *view)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(view, struct tty3270, view);
 
-	tp = (struct tty3270 *) view;
 	tp->update_flags = TTY_UPDATE_ALL;
 	tty3270_set_timer(tp, 1);
 	return 0;
@@ -646,9 +637,8 @@
 static void
 tty3270_deactivate(struct raw3270_view *view)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(view, struct tty3270, view);
 
-	tp = (struct tty3270 *) view;
 	del_timer(&tp->timer);
 }
 
@@ -690,6 +680,17 @@
 	if (!tp->freemem_pages)
 		goto out_tp;
 	INIT_LIST_HEAD(&tp->freemem);
+	INIT_LIST_HEAD(&tp->lines);
+	INIT_LIST_HEAD(&tp->update);
+	INIT_LIST_HEAD(&tp->rcl_lines);
+	tp->rcl_max = 20;
+	tty_port_init(&tp->port);
+	setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
+		    (unsigned long) tp);
+	tasklet_init(&tp->readlet,
+		     (void (*)(unsigned long)) tty3270_read_tasklet,
+		     (unsigned long) tp->read);
+
 	for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
 		tp->freemem_pages[pages] = (void *)
 			__get_free_pages(GFP_KERNEL|GFP_DMA, 0);
@@ -794,16 +795,15 @@
 static void
 tty3270_release(struct raw3270_view *view)
 {
-	struct tty3270 *tp;
-	struct tty_struct *tty;
+	struct tty3270 *tp = container_of(view, struct tty3270, view);
+	struct tty_struct *tty = tty_port_tty_get(&tp->port);
 
-	tp = (struct tty3270 *) view;
-	tty = tp->tty;
 	if (tty) {
 		tty->driver_data = NULL;
-		tp->tty = tp->kbd->tty = NULL;
+		tty_port_tty_set(&tp->port, NULL);
 		tty_hangup(tty);
 		raw3270_put_view(&tp->view);
+		tty_kref_put(tty);
 	}
 }
 
@@ -813,8 +813,9 @@
 static void
 tty3270_free(struct raw3270_view *view)
 {
-	tty3270_free_screen((struct tty3270 *) view);
-	tty3270_free_view((struct tty3270 *) view);
+	struct tty3270 *tp = container_of(view, struct tty3270, view);
+	tty3270_free_screen(tp);
+	tty3270_free_view(tp);
 }
 
 /*
@@ -823,14 +824,13 @@
 static void
 tty3270_del_views(void)
 {
-	struct tty3270 *tp;
 	int i;
 
 	for (i = 0; i < tty3270_max_index; i++) {
-		tp = (struct tty3270 *)
+		struct raw3270_view *view =
 			raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
-		if (!IS_ERR(tp))
-			raw3270_del_view(&tp->view);
+		if (!IS_ERR(view))
+			raw3270_del_view(view);
 	}
 }
 
@@ -848,22 +848,23 @@
 static int
 tty3270_open(struct tty_struct *tty, struct file * filp)
 {
+	struct raw3270_view *view;
 	struct tty3270 *tp;
 	int i, rc;
 
 	if (tty->count > 1)
 		return 0;
 	/* Check if the tty3270 is already there. */
-	tp = (struct tty3270 *)
-		raw3270_find_view(&tty3270_fn,
+	view = raw3270_find_view(&tty3270_fn,
 				  tty->index + RAW3270_FIRSTMINOR);
-	if (!IS_ERR(tp)) {
+	if (!IS_ERR(view)) {
+		tp = container_of(view, struct tty3270, view);
 		tty->driver_data = tp;
 		tty->winsize.ws_row = tp->view.rows - 2;
 		tty->winsize.ws_col = tp->view.cols;
 		tty->low_latency = 0;
-		tp->tty = tty;
-		tp->kbd->tty = tty;
+		/* why to reassign? */
+		tty_port_tty_set(&tp->port, tty);
 		tp->inattr = TF_INPUT;
 		return 0;
 	}
@@ -871,7 +872,7 @@
 		tty3270_max_index = tty->index + 1;
 
 	/* Quick exit if there is no device for tty->index. */
-	if (PTR_ERR(tp) == -ENODEV)
+	if (PTR_ERR(view) == -ENODEV)
 		return -ENODEV;
 
 	/* Allocate tty3270 structure on first open. */
@@ -879,16 +880,6 @@
 	if (IS_ERR(tp))
 		return PTR_ERR(tp);
 
-	INIT_LIST_HEAD(&tp->lines);
-	INIT_LIST_HEAD(&tp->update);
-	INIT_LIST_HEAD(&tp->rcl_lines);
-	tp->rcl_max = 20;
-	setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
-		    (unsigned long) tp);
-	tasklet_init(&tp->readlet, 
-		     (void (*)(unsigned long)) tty3270_read_tasklet,
-		     (unsigned long) tp->read);
-
 	rc = raw3270_add_view(&tp->view, &tty3270_fn,
 			      tty->index + RAW3270_FIRSTMINOR);
 	if (rc) {
@@ -903,7 +894,7 @@
 		return rc;
 	}
 
-	tp->tty = tty;
+	tty_port_tty_set(&tp->port, tty);
 	tty->low_latency = 0;
 	tty->driver_data = tp;
 	tty->winsize.ws_row = tp->view.rows - 2;
@@ -917,7 +908,7 @@
 	for (i = 0; i < tp->view.rows - 2; i++)
 		tty3270_blank_line(tp);
 
-	tp->kbd->tty = tty;
+	tp->kbd->port = &tp->port;
 	tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
 	tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
 	tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
@@ -935,14 +926,13 @@
 static void
 tty3270_close(struct tty_struct *tty, struct file * filp)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = tty->driver_data;
 
 	if (tty->count > 1)
 		return;
-	tp = (struct tty3270 *) tty->driver_data;
 	if (tp) {
 		tty->driver_data = NULL;
-		tp->tty = tp->kbd->tty = NULL;
+		tty_port_tty_set(&tp->port, NULL);
 		raw3270_put_view(&tp->view);
 	}
 }
@@ -1391,7 +1381,7 @@
 			tty3270_lf(tp);
 			break;
 		case 'Z':		/* Respond ID. */
-			kbd_puts_queue(tp->tty, "\033[?6c");
+			kbd_puts_queue(&tp->port, "\033[?6c");
 			break;
 		case '7':		/* Save cursor position. */
 			tp->saved_cx = tp->cx;
@@ -1437,11 +1427,11 @@
 	tp->esc_state = ESnormal;
 	if (ch == 'n' && !tp->esc_ques) {
 		if (tp->esc_par[0] == 5)		/* Status report. */
-			kbd_puts_queue(tp->tty, "\033[0n");
+			kbd_puts_queue(&tp->port, "\033[0n");
 		else if (tp->esc_par[0] == 6) {	/* Cursor report. */
 			char buf[40];
 			sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
-			kbd_puts_queue(tp->tty, buf);
+			kbd_puts_queue(&tp->port, buf);
 		}
 		return;
 	}
@@ -1513,12 +1503,13 @@
  * String write routine for 3270 ttys
  */
 static void
-tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count)
+tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
+		const unsigned char *buf, int count)
 {
 	int i_msg, i;
 
 	spin_lock_bh(&tp->view.lock);
-	for (i_msg = 0; !tp->tty->stopped && i_msg < count; i_msg++) {
+	for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {
 		if (tp->esc_state != 0) {
 			/* Continue escape sequence. */
 			tty3270_escape_sequence(tp, buf[i_msg]);
@@ -1595,10 +1586,10 @@
 	if (!tp)
 		return 0;
 	if (tp->char_count > 0) {
-		tty3270_do_write(tp, tp->char_buf, tp->char_count);
+		tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
 		tp->char_count = 0;
 	}
-	tty3270_do_write(tp, buf, count);
+	tty3270_do_write(tp, tty, buf, count);
 	return count;
 }
 
@@ -1629,7 +1620,7 @@
 	if (!tp)
 		return;
 	if (tp->char_count > 0) {
-		tty3270_do_write(tp, tp->char_buf, tp->char_count);
+		tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
 		tp->char_count = 0;
 	}
 }
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index bea04e5..e955978 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -808,19 +808,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called fdomain.
 
-config SCSI_FD_MCS
-	tristate "Future Domain MCS-600/700 SCSI support"
-	depends on MCA_LEGACY && SCSI
-	---help---
-	  This is support for Future Domain MCS 600/700 MCA SCSI adapters.
-	  Some PS/2 computers are equipped with IBM Fast SCSI Adapter/A which
-	  is identical to the MCS 700 and hence also supported by this driver.
-	  This driver also supports the Reply SB16/SCSI card (the SCSI part).
-	  It supports multiple adapters in the same system.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called fd_mcs.
-
 config SCSI_GDTH
 	tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
 	depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API
@@ -890,76 +877,6 @@
 	  not detect your card.  See the file
 	  <file:Documentation/scsi/g_NCR5380.txt> for details.
 
-config SCSI_IBMMCA
-	tristate "IBMMCA SCSI support"
-	depends on MCA && SCSI
-	---help---
-	  This is support for the IBM SCSI adapter found in many of the PS/2
-	  series computers.  These machines have an MCA bus, so you need to
-	  answer Y to "MCA support" as well and read
-	  <file:Documentation/mca.txt>.
-
-	  If the adapter isn't found during boot (a common problem for models
-	  56, 57, 76, and 77) you'll need to use the 'ibmmcascsi=<pun>' kernel
-	  option, where <pun> is the id of the SCSI subsystem (usually 7, but
-	  if that doesn't work check your reference diskette).  Owners of
-	  model 95 with a LED-matrix-display can in addition activate some
-	  activity info like under OS/2, but more informative, by setting
-	  'ibmmcascsi=display' as an additional kernel parameter.  Try "man
-	  bootparam" or see the documentation of your boot loader about how to
-	  pass options to the kernel.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ibmmca.
-
-config IBMMCA_SCSI_ORDER_STANDARD
-	bool "Standard SCSI-order"
-	depends on SCSI_IBMMCA
-	---help---
-	  In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks
-	  are assigned to the drive letters, starting with the lowest SCSI-id
-	  (physical number -- pun) to be drive C:, as seen from DOS and
-	  similar operating systems. When looking into papers describing the
-	  ANSI-SCSI-standard, this assignment of drives appears to be wrong.
-	  The SCSI-standard follows a hardware-hierarchy which says that id 7
-	  has the highest priority and id 0 the lowest. Therefore, the host
-	  adapters are still today everywhere placed as SCSI-id 7 by default.
-	  In the SCSI-standard, the drive letters express the priority of the
-	  disk. C: should be the hard disk, or a partition on it, with the
-	  highest priority. This must therefore be the disk with the highest
-	  SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the
-	  original definition of the SCSI-standard as also industrial- and
-	  process-control-machines, like VME-CPUs running under realtime-OSes
-	  (e.g. LynxOS, OS9) do.
-
-	  If you like to run Linux on your MCA-machine with the same
-	  assignment of hard disks as seen from e.g. DOS or OS/2 on your
-	  machine, which is in addition conformant to the SCSI-standard, you
-	  must say Y here. This is also necessary for MCA-Linux users who want
-	  to keep downward compatibility to older releases of the
-	  IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than
-	  June 1997).
-
-	  If you like to have the lowest SCSI-id assigned as drive C:, as
-	  modern SCSI-BIOSes do, which does not conform to the standard, but
-	  is widespread and common in the PC-world of today, you must say N
-	  here. If unsure, say Y.
-
-config IBMMCA_SCSI_DEV_RESET
-	bool "Reset SCSI-devices at boottime"
-	depends on SCSI_IBMMCA
-	---help---
-	  By default, SCSI-devices are reset when the machine is powered on.
-	  However, some devices exist, like special-control-devices,
-	  SCSI-CNC-machines, SCSI-printer or scanners of older type, that do
-	  not reset when switched on. If you say Y here, each device connected
-	  to your SCSI-bus will be issued a reset-command after it has been
-	  probed, while the kernel is booting. This may cause problems with
-	  more modern devices, like hard disks, which do not appreciate these
-	  reset commands, and can cause your system to hang. So say Y only if
-	  you know that one of your older devices needs it; N is the safe
-	  answer.
-
 config SCSI_IPS
 	tristate "IBM ServeRAID support"
 	depends on PCI && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 8deedea..1a3368b 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -75,7 +75,6 @@
 obj-$(CONFIG_SCSI_PM8001)	+= pm8001/
 obj-$(CONFIG_SCSI_ISCI)		+= isci/
 obj-$(CONFIG_SCSI_IPS)		+= ips.o
-obj-$(CONFIG_SCSI_FD_MCS)	+= fd_mcs.o
 obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
 obj-$(CONFIG_SCSI_IN2000)	+= in2000.o
 obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
@@ -100,7 +99,6 @@
 obj-$(CONFIG_SCSI_ZALON)	+= zalon7xx.o
 obj-$(CONFIG_SCSI_EATA_PIO)	+= eata_pio.o
 obj-$(CONFIG_SCSI_7000FASST)	+= wd7000.o
-obj-$(CONFIG_SCSI_IBMMCA)	+= ibmmca.o
 obj-$(CONFIG_SCSI_EATA)		+= eata.o
 obj-$(CONFIG_SCSI_DC395x)	+= dc395x.o
 obj-$(CONFIG_SCSI_DC390T)	+= tmscsim.o
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index ede91f3..f79c8f9 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -22,7 +22,7 @@
  *        Added module command-line options
  *        19-Jul-99
  *  Modified by Adam Fritzler
- *        Added proper detection of the AHA-1640 (MCA version of AHA-1540)
+ *        Added proper detection of the AHA-1640 (MCA, now deleted)
  */
 
 #include <linux/module.h>
@@ -37,8 +37,6 @@
 #include <linux/spinlock.h>
 #include <linux/isapnp.h>
 #include <linux/blkdev.h>
-#include <linux/mca.h>
-#include <linux/mca-legacy.h>
 #include <linux/slab.h>
 
 #include <asm/dma.h>
@@ -71,7 +69,7 @@
 #define MAXBOARDS 4		/* Increase this and the sizes of the
 				   arrays below, if you need more.. */
 
-/* Boards 3,4 slots are reserved for ISAPnP/MCA scans */
+/* Boards 3,4 slots are reserved for ISAPnP scans */
 
 static unsigned int bases[MAXBOARDS] __initdata = {0x330, 0x334, 0, 0};
 
@@ -1009,66 +1007,6 @@
 #endif
 
 	/*
-	 *	Find MicroChannel cards (AHA1640)
-	 */
-#ifdef CONFIG_MCA_LEGACY
-	if(MCA_bus) {
-		int slot = 0;
-		int pos = 0;
-
-		for (indx = 0; (slot != MCA_NOTFOUND) && (indx < ARRAY_SIZE(bases)); indx++) {
-
-			if (bases[indx])
-				continue;
-
-			/* Detect only AHA-1640 cards -- MCA ID 0F1F */
-			slot = mca_find_unused_adapter(0x0f1f, slot);
-			if (slot == MCA_NOTFOUND)
-				break;
-
-			/* Found one */
-			pos = mca_read_stored_pos(slot, 3);
-
-			/* Decode address */
-			if (pos & 0x80) {
-				if (pos & 0x02) {
-					if (pos & 0x01)
-						bases[indx] = 0x334;
-					else
-						bases[indx] = 0x234;
-				} else {
-					if (pos & 0x01)
-						bases[indx] = 0x134;
-				}
-			} else {
-				if (pos & 0x02) {
-					if (pos & 0x01)
-						bases[indx] = 0x330;
-					else
-						bases[indx] = 0x230;
-				} else {
-					if (pos & 0x01)
-						bases[indx] = 0x130;
-				}
-			}
-
-			/* No need to decode IRQ and Arb level -- those are
-			 * read off the card later.
-			 */
-			printk(KERN_INFO "Found an AHA-1640 in MCA slot %d, I/O 0x%04x\n", slot, bases[indx]);
-
-			mca_set_adapter_name(slot, "Adapter AHA-1640");
-			mca_set_adapter_procfn(slot, NULL, NULL);
-			mca_mark_as_used(slot);
-
-			/* Go on */
-			slot++;
-		}
-
-	}
-#endif
-
-	/*
 	 *	Hunt for ISA Plug'n'Pray Adaptecs (AHA1535)
 	 */
 
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
index 390168f..5fdca93 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.c
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -1228,8 +1228,7 @@
 
 int asd_release_firmware(void)
 {
-	if (sequencer_fw)
-		release_firmware(sequencer_fw);
+	release_firmware(sequencer_fw);
 	return 0;
 }
 
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 394ed9e7..34552bf 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -1000,7 +1000,7 @@
 
 static void esp_schedule_reset(struct esp *esp)
 {
-	esp_log_reset("ESP: esp_schedule_reset() from %p\n",
+	esp_log_reset("ESP: esp_schedule_reset() from %pf\n",
 		      __builtin_return_address(0));
 	esp->flags |= ESP_FLAG_RESETTING;
 	esp_event(esp, ESP_EVENT_RESET);
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
deleted file mode 100644
index 53bfcaa..0000000
--- a/drivers/scsi/fd_mcs.c
+++ /dev/null
@@ -1,1354 +0,0 @@
-/* fd_mcs.c -- Future Domain MCS 600/700 (or IBM OEM) driver
- *
- * FutureDomain MCS-600/700 v0.2 03/11/1998 by ZP Gu (zpg@castle.net)
- *
- * This driver is cloned from fdomain.* to specifically support
- * the Future Domain MCS 600/700 MCA SCSI adapters. Some PS/2s
- * also equipped with IBM Fast SCSI Adapter/A which is an OEM
- * of MCS 700.
- *
- * This driver also supports Reply SB16/SCSI card (the SCSI part).
- *
- * What makes this driver different is that this driver is MCA only
- * and it supports multiple adapters in the same system, IRQ 
- * sharing, some driver statistics, and maps highest SCSI id to sda.
- * All cards are auto-detected.
- *
- * Assumptions: TMC-1800/18C50/18C30, BIOS >= 3.4
- *
- * LILO command-line options:
- *   fd_mcs=<FIFO_COUNT>[,<FIFO_SIZE>]
- *
- * ********************************************************
- * Please see Copyrights/Comments in fdomain.* for credits.
- * Following is from fdomain.c for acknowledgement:
- *
- * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Wed Oct  2 11:10:55 1996 by r.faith@ieee.org
- * Author: Rickard E. Faith, faith@cs.unc.edu
- * Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith
- *
- * $Id: fdomain.c,v 5.45 1996/10/02 15:13:06 root Exp $
-
- * 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, 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.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
-
- **************************************************************************
-
- NOTES ON USER DEFINABLE OPTIONS:
-
- DEBUG: This turns on the printing of various debug information.
-
- ENABLE_PARITY: This turns on SCSI parity checking.  With the current
- driver, all attached devices must support SCSI parity.  If none of your
- devices support parity, then you can probably get the driver to work by
- turning this option off.  I have no way of testing this, however, and it
- would appear that no one ever uses this option.
-
- FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
- 18C30 chip have a 2k cache).  When this many 512 byte blocks are filled by
- the SCSI device, an interrupt will be raised.  Therefore, this could be as
- low as 0, or as high as 16.  Note, however, that values which are too high
- or too low seem to prevent any interrupts from occurring, and thereby lock
- up the machine.  I have found that 2 is a good number, but throughput may
- be increased by changing this value to values which are close to 2.
- Please let me know if you try any different values.
- [*****Now a runtime option*****]
-
- RESELECTION: This is no longer an option, since I gave up trying to
- implement it in version 4.x of this driver.  It did not improve
- performance at all and made the driver unstable (because I never found one
- of the two race conditions which were introduced by the multiple
- outstanding command code).  The instability seems a very high price to pay
- just so that you don't have to wait for the tape to rewind.  If you want
- this feature implemented, send me patches.  I'll be happy to send a copy
- of my (broken) driver to anyone who would like to see a copy.
-
- **************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-#include <linux/mca.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <scsi/scsicam.h>
-#include <linux/mca-legacy.h>
-
-#include <asm/io.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-#define DRIVER_VERSION "v0.2 by ZP Gu<zpg@castle.net>"
-
-/* START OF USER DEFINABLE OPTIONS */
-
-#define DEBUG            0	/* Enable debugging output */
-#define ENABLE_PARITY    1	/* Enable SCSI Parity */
-
-/* END OF USER DEFINABLE OPTIONS */
-
-#if DEBUG
-#define EVERY_ACCESS     0	/* Write a line on every scsi access */
-#define ERRORS_ONLY      1	/* Only write a line if there is an error */
-#define DEBUG_MESSAGES   1	/* Debug MESSAGE IN phase */
-#define DEBUG_ABORT      1	/* Debug abort() routine */
-#define DEBUG_RESET      1	/* Debug reset() routine */
-#define DEBUG_RACE       1	/* Debug interrupt-driven race condition */
-#else
-#define EVERY_ACCESS     0	/* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
-#define ERRORS_ONLY      0
-#define DEBUG_MESSAGES   0
-#define DEBUG_ABORT      0
-#define DEBUG_RESET      0
-#define DEBUG_RACE       0
-#endif
-
-/* Errors are reported on the line, so we don't need to report them again */
-#if EVERY_ACCESS
-#undef ERRORS_ONLY
-#define ERRORS_ONLY      0
-#endif
-
-#if ENABLE_PARITY
-#define PARITY_MASK      0x08
-#else
-#define PARITY_MASK      0x00
-#endif
-
-enum chip_type {
-	unknown = 0x00,
-	tmc1800 = 0x01,
-	tmc18c50 = 0x02,
-	tmc18c30 = 0x03,
-};
-
-enum {
-	in_arbitration = 0x02,
-	in_selection = 0x04,
-	in_other = 0x08,
-	disconnect = 0x10,
-	aborted = 0x20,
-	sent_ident = 0x40,
-};
-
-enum in_port_type {
-	Read_SCSI_Data = 0,
-	SCSI_Status = 1,
-	TMC_Status = 2,
-	FIFO_Status = 3,	/* tmc18c50/tmc18c30 only */
-	Interrupt_Cond = 4,	/* tmc18c50/tmc18c30 only */
-	LSB_ID_Code = 5,
-	MSB_ID_Code = 6,
-	Read_Loopback = 7,
-	SCSI_Data_NoACK = 8,
-	Interrupt_Status = 9,
-	Configuration1 = 10,
-	Configuration2 = 11,	/* tmc18c50/tmc18c30 only */
-	Read_FIFO = 12,
-	FIFO_Data_Count = 14
-};
-
-enum out_port_type {
-	Write_SCSI_Data = 0,
-	SCSI_Cntl = 1,
-	Interrupt_Cntl = 2,
-	SCSI_Mode_Cntl = 3,
-	TMC_Cntl = 4,
-	Memory_Cntl = 5,	/* tmc18c50/tmc18c30 only */
-	Write_Loopback = 7,
-	IO_Control = 11,	/* tmc18c30 only */
-	Write_FIFO = 12
-};
-
-struct fd_hostdata {
-	unsigned long _bios_base;
-	int _bios_major;
-	int _bios_minor;
-	volatile int _in_command;
-	Scsi_Cmnd *_current_SC;
-	enum chip_type _chip;
-	int _adapter_mask;
-	int _fifo_count;	/* Number of 512 byte blocks before INTR */
-
-	char _adapter_name[64];
-#if DEBUG_RACE
-	volatile int _in_interrupt_flag;
-#endif
-
-	int _SCSI_Mode_Cntl_port;
-	int _FIFO_Data_Count_port;
-	int _Interrupt_Cntl_port;
-	int _Interrupt_Status_port;
-	int _Interrupt_Cond_port;
-	int _Read_FIFO_port;
-	int _Read_SCSI_Data_port;
-	int _SCSI_Cntl_port;
-	int _SCSI_Data_NoACK_port;
-	int _SCSI_Status_port;
-	int _TMC_Cntl_port;
-	int _TMC_Status_port;
-	int _Write_FIFO_port;
-	int _Write_SCSI_Data_port;
-
-	int _FIFO_Size;		/* = 0x2000;  8k FIFO for
-				   pre-tmc18c30 chips */
-	/* simple stats */
-	int _Bytes_Read;
-	int _Bytes_Written;
-	int _INTR_Processed;
-};
-
-#define FD_MAX_HOSTS 3		/* enough? */
-
-#define HOSTDATA(shpnt) ((struct fd_hostdata *) shpnt->hostdata)
-#define bios_base             (HOSTDATA(shpnt)->_bios_base)
-#define bios_major            (HOSTDATA(shpnt)->_bios_major)
-#define bios_minor            (HOSTDATA(shpnt)->_bios_minor)
-#define in_command            (HOSTDATA(shpnt)->_in_command)
-#define current_SC            (HOSTDATA(shpnt)->_current_SC)
-#define chip                  (HOSTDATA(shpnt)->_chip)
-#define adapter_mask          (HOSTDATA(shpnt)->_adapter_mask)
-#define FIFO_COUNT            (HOSTDATA(shpnt)->_fifo_count)
-#define adapter_name          (HOSTDATA(shpnt)->_adapter_name)
-#if DEBUG_RACE
-#define in_interrupt_flag     (HOSTDATA(shpnt)->_in_interrupt_flag)
-#endif
-#define SCSI_Mode_Cntl_port   (HOSTDATA(shpnt)->_SCSI_Mode_Cntl_port)
-#define FIFO_Data_Count_port  (HOSTDATA(shpnt)->_FIFO_Data_Count_port)
-#define Interrupt_Cntl_port   (HOSTDATA(shpnt)->_Interrupt_Cntl_port)
-#define Interrupt_Status_port (HOSTDATA(shpnt)->_Interrupt_Status_port)
-#define Interrupt_Cond_port   (HOSTDATA(shpnt)->_Interrupt_Cond_port)
-#define Read_FIFO_port        (HOSTDATA(shpnt)->_Read_FIFO_port)
-#define Read_SCSI_Data_port   (HOSTDATA(shpnt)->_Read_SCSI_Data_port)
-#define SCSI_Cntl_port        (HOSTDATA(shpnt)->_SCSI_Cntl_port)
-#define SCSI_Data_NoACK_port  (HOSTDATA(shpnt)->_SCSI_Data_NoACK_port)
-#define SCSI_Status_port      (HOSTDATA(shpnt)->_SCSI_Status_port)
-#define TMC_Cntl_port         (HOSTDATA(shpnt)->_TMC_Cntl_port)
-#define TMC_Status_port       (HOSTDATA(shpnt)->_TMC_Status_port)
-#define Write_FIFO_port       (HOSTDATA(shpnt)->_Write_FIFO_port)
-#define Write_SCSI_Data_port  (HOSTDATA(shpnt)->_Write_SCSI_Data_port)
-#define FIFO_Size             (HOSTDATA(shpnt)->_FIFO_Size)
-#define Bytes_Read            (HOSTDATA(shpnt)->_Bytes_Read)
-#define Bytes_Written         (HOSTDATA(shpnt)->_Bytes_Written)
-#define INTR_Processed        (HOSTDATA(shpnt)->_INTR_Processed)
-
-struct fd_mcs_adapters_struct {
-	char *name;
-	int id;
-	enum chip_type fd_chip;
-	int fifo_size;
-	int fifo_count;
-};
-
-#define REPLY_ID 0x5137
-
-static struct fd_mcs_adapters_struct fd_mcs_adapters[] = {
-	{"Future Domain SCSI Adapter MCS-700(18C50)",
-	 0x60e9,
-	 tmc18c50,
-	 0x2000,
-	 4},
-	{"Future Domain SCSI Adapter MCS-600/700(TMC-1800)",
-	 0x6127,
-	 tmc1800,
-	 0x2000,
-	 4},
-	{"Reply Sound Blaster/SCSI Adapter",
-	 REPLY_ID,
-	 tmc18c30,
-	 0x800,
-	 2},
-};
-
-#define FD_BRDS ARRAY_SIZE(fd_mcs_adapters)
-
-static irqreturn_t fd_mcs_intr(int irq, void *dev_id);
-
-static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 };
-static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
-static unsigned short interrupts[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
-
-/* host information */
-static int found = 0;
-static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL };
-
-static int user_fifo_count = 0;
-static int user_fifo_size = 0;
-
-#ifndef MODULE
-static int __init fd_mcs_setup(char *str)
-{
-	static int done_setup = 0;
-	int ints[3];
-
-	get_options(str, 3, ints);
-	if (done_setup++ || ints[0] < 1 || ints[0] > 2 || ints[1] < 1 || ints[1] > 16) {
-		printk("fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n");
-		return 0;
-	}
-
-	user_fifo_count = ints[0] >= 1 ? ints[1] : 0;
-	user_fifo_size = ints[0] >= 2 ? ints[2] : 0;
-	return 1;
-}
-
-__setup("fd_mcs=", fd_mcs_setup);
-#endif /* !MODULE */
-
-static void print_banner(struct Scsi_Host *shpnt)
-{
-	printk("scsi%d <fd_mcs>: ", shpnt->host_no);
-
-	if (bios_base) {
-		printk("BIOS at 0x%lX", bios_base);
-	} else {
-		printk("No BIOS");
-	}
-
-	printk(", HostID %d, %s Chip, IRQ %d, IO 0x%lX\n", shpnt->this_id, chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? "TMC-18C30" : (chip == tmc1800 ? "TMC-1800" : "Unknown")), shpnt->irq, shpnt->io_port);
-}
-
-
-static void do_pause(unsigned amount)
-{				/* Pause for amount*10 milliseconds */
-	do {
-		mdelay(10);
-	} while (--amount);
-}
-
-static void fd_mcs_make_bus_idle(struct Scsi_Host *shpnt)
-{
-	outb(0, SCSI_Cntl_port);
-	outb(0, SCSI_Mode_Cntl_port);
-	if (chip == tmc18c50 || chip == tmc18c30)
-		outb(0x21 | PARITY_MASK, TMC_Cntl_port);	/* Clear forced intr. */
-	else
-		outb(0x01 | PARITY_MASK, TMC_Cntl_port);
-}
-
-static int fd_mcs_detect(struct scsi_host_template * tpnt)
-{
-	int loop;
-	struct Scsi_Host *shpnt;
-
-	/* get id, port, bios, irq */
-	int slot;
-	u_char pos2, pos3, pos4;
-	int id, port, irq;
-	unsigned long bios;
-
-	/* if not MCA machine, return */
-	if (!MCA_bus)
-		return 0;
-
-	/* changeable? */
-	id = 7;
-
-	for (loop = 0; loop < FD_BRDS; loop++) {
-		slot = 0;
-		while (MCA_NOTFOUND != (slot = mca_find_adapter(fd_mcs_adapters[loop].id, slot))) {
-
-			/* if we get this far, an adapter has been detected and is
-			   enabled */
-
-			printk(KERN_INFO "scsi  <fd_mcs>: %s at slot %d\n", fd_mcs_adapters[loop].name, slot + 1);
-
-			pos2 = mca_read_stored_pos(slot, 2);
-			pos3 = mca_read_stored_pos(slot, 3);
-			pos4 = mca_read_stored_pos(slot, 4);
-
-			/* ready for next probe */
-			slot++;
-
-			if (fd_mcs_adapters[loop].id == REPLY_ID) {	/* reply card */
-				static int reply_irq[] = { 10, 11, 14, 15 };
-
-				bios = 0;	/* no bios */
-
-				if (pos2 & 0x2)
-					port = ports[pos4 & 0x3];
-				else
-					continue;
-
-				/* can't really disable it, same as irq=10 */
-				irq = reply_irq[((pos4 >> 2) & 0x1) + 2 * ((pos4 >> 4) & 0x1)];
-			} else {
-				bios = addresses[pos2 >> 6];
-				port = ports[(pos2 >> 4) & 0x03];
-				irq = interrupts[(pos2 >> 1) & 0x07];
-			}
-
-			if (irq) {
-				/* claim the slot */
-				mca_set_adapter_name(slot - 1, fd_mcs_adapters[loop].name);
-
-				/* check irq/region */
-				if (request_irq(irq, fd_mcs_intr, IRQF_SHARED, "fd_mcs", hosts)) {
-					printk(KERN_ERR "fd_mcs: interrupt is not available, skipping...\n");
-					continue;
-				}
-
-				/* request I/O region */
-				if (request_region(port, 0x10, "fd_mcs")) {
-					printk(KERN_ERR "fd_mcs: I/O region is already in use, skipping...\n");
-					continue;
-				}
-				/* register */
-				if (!(shpnt = scsi_register(tpnt, sizeof(struct fd_hostdata)))) {
-					printk(KERN_ERR "fd_mcs: scsi_register() failed\n");
-					release_region(port, 0x10);
-					free_irq(irq, hosts);
-					continue;
-				}
-
-
-				/* save name */
-				strcpy(adapter_name, fd_mcs_adapters[loop].name);
-
-				/* chip/fifo */
-				chip = fd_mcs_adapters[loop].fd_chip;
-				/* use boot time value if available */
-				FIFO_COUNT = user_fifo_count ? user_fifo_count : fd_mcs_adapters[loop].fifo_count;
-				FIFO_Size = user_fifo_size ? user_fifo_size : fd_mcs_adapters[loop].fifo_size;
-
-/* FIXME: Do we need to keep this bit of code inside NOT_USED around at all? */
-#ifdef NOT_USED
-				/* *************************************************** */
-				/* Try to toggle 32-bit mode.  This only
-				   works on an 18c30 chip.  (User reports
-				   say this works, so we should switch to
-				   it in the near future.) */
-				outb(0x80, port + IO_Control);
-				if ((inb(port + Configuration2) & 0x80) == 0x80) {
-					outb(0x00, port + IO_Control);
-					if ((inb(port + Configuration2) & 0x80) == 0x00) {
-						chip = tmc18c30;
-						FIFO_Size = 0x800;	/* 2k FIFO */
-
-						printk("FIRST: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
-					}
-				}
-
-				/* That should have worked, but appears to
-				   have problems.  Let's assume it is an
-				   18c30 if the RAM is disabled. */
-
-				if (inb(port + Configuration2) & 0x02) {
-					chip = tmc18c30;
-					FIFO_Size = 0x800;	/* 2k FIFO */
-
-					printk("SECOND: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
-				}
-				/* *************************************************** */
-#endif
-
-				/* IBM/ANSI scsi scan ordering */
-				/* Stick this back in when the scsi.c changes are there */
-				shpnt->reverse_ordering = 1;
-
-
-				/* saving info */
-				hosts[found++] = shpnt;
-
-				shpnt->this_id = id;
-				shpnt->irq = irq;
-				shpnt->io_port = port;
-				shpnt->n_io_port = 0x10;
-
-				/* save */
-				bios_base = bios;
-				adapter_mask = (1 << id);
-
-				/* save more */
-				SCSI_Mode_Cntl_port = port + SCSI_Mode_Cntl;
-				FIFO_Data_Count_port = port + FIFO_Data_Count;
-				Interrupt_Cntl_port = port + Interrupt_Cntl;
-				Interrupt_Status_port = port + Interrupt_Status;
-				Interrupt_Cond_port = port + Interrupt_Cond;
-				Read_FIFO_port = port + Read_FIFO;
-				Read_SCSI_Data_port = port + Read_SCSI_Data;
-				SCSI_Cntl_port = port + SCSI_Cntl;
-				SCSI_Data_NoACK_port = port + SCSI_Data_NoACK;
-				SCSI_Status_port = port + SCSI_Status;
-				TMC_Cntl_port = port + TMC_Cntl;
-				TMC_Status_port = port + TMC_Status;
-				Write_FIFO_port = port + Write_FIFO;
-				Write_SCSI_Data_port = port + Write_SCSI_Data;
-
-				Bytes_Read = 0;
-				Bytes_Written = 0;
-				INTR_Processed = 0;
-
-				/* say something */
-				print_banner(shpnt);
-
-				/* reset */
-				outb(1, SCSI_Cntl_port);
-				do_pause(2);
-				outb(0, SCSI_Cntl_port);
-				do_pause(115);
-				outb(0, SCSI_Mode_Cntl_port);
-				outb(PARITY_MASK, TMC_Cntl_port);
-				/* done reset */
-			}
-		}
-
-		if (found == FD_MAX_HOSTS) {
-			printk("fd_mcs: detecting reached max=%d host adapters.\n", FD_MAX_HOSTS);
-			break;
-		}
-	}
-
-	return found;
-}
-
-static const char *fd_mcs_info(struct Scsi_Host *shpnt)
-{
-	return adapter_name;
-}
-
-static int TOTAL_INTR = 0;
-
-/*
- * inout : decides on the direction of the dataflow and the meaning of the 
- *         variables
- * buffer: If inout==FALSE data is being written to it else read from it
- * *start: If inout==FALSE start of the valid data in the buffer
- * offset: If inout==FALSE offset from the beginning of the imaginary file 
- *         from which we start writing into the buffer
- * length: If inout==FALSE max number of bytes to be written into the buffer 
- *         else number of bytes in the buffer
- */
-static int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
-{
-	int len = 0;
-
-	if (inout)
-		return (-ENOSYS);
-
-	*start = buffer + offset;
-
-	len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION);
-	len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, adapter_name);
-	len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT);
-	len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written);
-
-	if ((len -= offset) <= 0)
-		return 0;
-	if (len > length)
-		len = length;
-	return len;
-}
-
-static int fd_mcs_select(struct Scsi_Host *shpnt, int target)
-{
-	int status;
-	unsigned long timeout;
-
-	outb(0x82, SCSI_Cntl_port);	/* Bus Enable + Select */
-	outb(adapter_mask | (1 << target), SCSI_Data_NoACK_port);
-
-	/* Stop arbitration and enable parity */
-	outb(PARITY_MASK, TMC_Cntl_port);
-
-	timeout = 350;		/* 350mS -- because of timeouts
-				   (was 250mS) */
-
-	do {
-		status = inb(SCSI_Status_port);	/* Read adapter status */
-		if (status & 1) {	/* Busy asserted */
-			/* Enable SCSI Bus (on error, should make bus idle with 0) */
-			outb(0x80, SCSI_Cntl_port);
-			return 0;
-		}
-		udelay(1000);	/* wait one msec */
-	} while (--timeout);
-
-	/* Make bus idle */
-	fd_mcs_make_bus_idle(shpnt);
-#if EVERY_ACCESS
-	if (!target)
-		printk("Selection failed\n");
-#endif
-#if ERRORS_ONLY
-	if (!target) {
-		static int flag = 0;
-
-		if (!flag)	/* Skip first failure for all chips. */
-			++flag;
-		else
-			printk("fd_mcs: Selection failed\n");
-	}
-#endif
-	return 1;
-}
-
-static void my_done(struct Scsi_Host *shpnt, int error)
-{
-	if (in_command) {
-		in_command = 0;
-		outb(0x00, Interrupt_Cntl_port);
-		fd_mcs_make_bus_idle(shpnt);
-		current_SC->result = error;
-		current_SC->scsi_done(current_SC);
-	} else {
-		panic("fd_mcs: my_done() called outside of command\n");
-	}
-#if DEBUG_RACE
-	in_interrupt_flag = 0;
-#endif
-}
-
-/* only my_done needs to be protected  */
-static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
-{
-	unsigned long flags;
-	int status;
-	int done = 0;
-	unsigned data_count, tmp_count;
-
-	int i = 0;
-	struct Scsi_Host *shpnt;
-
-	TOTAL_INTR++;
-
-	/* search for one adapter-response on shared interrupt */
-	while ((shpnt = hosts[i++])) {
-		if ((inb(TMC_Status_port)) & 1)
-			break;
-	}
-
-	/* return if some other device on this IRQ caused the interrupt */
-	if (!shpnt) {
-		return IRQ_NONE;
-	}
-
-	INTR_Processed++;
-
-	outb(0x00, Interrupt_Cntl_port);
-
-	/* Abort calls my_done, so we do nothing here. */
-	if (current_SC->SCp.phase & aborted) {
-#if DEBUG_ABORT
-		printk("Interrupt after abort, ignoring\n");
-#endif
-		/* return IRQ_HANDLED; */
-	}
-#if DEBUG_RACE
-	++in_interrupt_flag;
-#endif
-
-	if (current_SC->SCp.phase & in_arbitration) {
-		status = inb(TMC_Status_port);	/* Read adapter status */
-		if (!(status & 0x02)) {
-#if EVERY_ACCESS
-			printk(" AFAIL ");
-#endif
-			spin_lock_irqsave(shpnt->host_lock, flags);
-			my_done(shpnt, DID_BUS_BUSY << 16);
-			spin_unlock_irqrestore(shpnt->host_lock, flags);
-			return IRQ_HANDLED;
-		}
-		current_SC->SCp.phase = in_selection;
-
-		outb(0x40 | FIFO_COUNT, Interrupt_Cntl_port);
-
-		outb(0x82, SCSI_Cntl_port);	/* Bus Enable + Select */
-		outb(adapter_mask | (1 << scmd_id(current_SC)), SCSI_Data_NoACK_port);
-
-		/* Stop arbitration and enable parity */
-		outb(0x10 | PARITY_MASK, TMC_Cntl_port);
-#if DEBUG_RACE
-		in_interrupt_flag = 0;
-#endif
-		return IRQ_HANDLED;
-	} else if (current_SC->SCp.phase & in_selection) {
-		status = inb(SCSI_Status_port);
-		if (!(status & 0x01)) {
-			/* Try again, for slow devices */
-			if (fd_mcs_select(shpnt, scmd_id(current_SC))) {
-#if EVERY_ACCESS
-				printk(" SFAIL ");
-#endif
-				spin_lock_irqsave(shpnt->host_lock, flags);
-				my_done(shpnt, DID_NO_CONNECT << 16);
-				spin_unlock_irqrestore(shpnt->host_lock, flags);
-				return IRQ_HANDLED;
-			} else {
-#if EVERY_ACCESS
-				printk(" AltSel ");
-#endif
-				/* Stop arbitration and enable parity */
-				outb(0x10 | PARITY_MASK, TMC_Cntl_port);
-			}
-		}
-		current_SC->SCp.phase = in_other;
-		outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
-		outb(0x80, SCSI_Cntl_port);
-#if DEBUG_RACE
-		in_interrupt_flag = 0;
-#endif
-		return IRQ_HANDLED;
-	}
-
-	/* current_SC->SCp.phase == in_other: this is the body of the routine */
-
-	status = inb(SCSI_Status_port);
-
-	if (status & 0x10) {	/* REQ */
-
-		switch (status & 0x0e) {
-
-		case 0x08:	/* COMMAND OUT */
-			outb(current_SC->cmnd[current_SC->SCp.sent_command++], Write_SCSI_Data_port);
-#if EVERY_ACCESS
-			printk("CMD = %x,", current_SC->cmnd[current_SC->SCp.sent_command - 1]);
-#endif
-			break;
-		case 0x00:	/* DATA OUT -- tmc18c50/tmc18c30 only */
-			if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
-				current_SC->SCp.have_data_in = -1;
-				outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
-			}
-			break;
-		case 0x04:	/* DATA IN -- tmc18c50/tmc18c30 only */
-			if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
-				current_SC->SCp.have_data_in = 1;
-				outb(0x90 | PARITY_MASK, TMC_Cntl_port);
-			}
-			break;
-		case 0x0c:	/* STATUS IN */
-			current_SC->SCp.Status = inb(Read_SCSI_Data_port);
-#if EVERY_ACCESS
-			printk("Status = %x, ", current_SC->SCp.Status);
-#endif
-#if ERRORS_ONLY
-			if (current_SC->SCp.Status && current_SC->SCp.Status != 2 && current_SC->SCp.Status != 8) {
-				printk("ERROR fd_mcs: target = %d, command = %x, status = %x\n", current_SC->device->id, current_SC->cmnd[0], current_SC->SCp.Status);
-			}
-#endif
-			break;
-		case 0x0a:	/* MESSAGE OUT */
-			outb(MESSAGE_REJECT, Write_SCSI_Data_port);	/* Reject */
-			break;
-		case 0x0e:	/* MESSAGE IN */
-			current_SC->SCp.Message = inb(Read_SCSI_Data_port);
-#if EVERY_ACCESS
-			printk("Message = %x, ", current_SC->SCp.Message);
-#endif
-			if (!current_SC->SCp.Message)
-				++done;
-#if DEBUG_MESSAGES || EVERY_ACCESS
-			if (current_SC->SCp.Message) {
-				printk("fd_mcs: message = %x\n", current_SC->SCp.Message);
-			}
-#endif
-			break;
-		}
-	}
-
-	if (chip == tmc1800 && !current_SC->SCp.have_data_in && (current_SC->SCp.sent_command >= current_SC->cmd_len)) {
-		/* We have to get the FIFO direction
-		   correct, so I've made a table based
-		   on the SCSI Standard of which commands
-		   appear to require a DATA OUT phase.
-		 */
-		/*
-		   p. 94: Command for all device types
-		   CHANGE DEFINITION            40 DATA OUT
-		   COMPARE                      39 DATA OUT
-		   COPY                         18 DATA OUT
-		   COPY AND VERIFY              3a DATA OUT
-		   INQUIRY                      12 
-		   LOG SELECT                   4c DATA OUT
-		   LOG SENSE                    4d
-		   MODE SELECT (6)              15 DATA OUT
-		   MODE SELECT (10)             55 DATA OUT
-		   MODE SENSE (6)               1a
-		   MODE SENSE (10)              5a
-		   READ BUFFER                  3c
-		   RECEIVE DIAGNOSTIC RESULTS   1c
-		   REQUEST SENSE                03
-		   SEND DIAGNOSTIC              1d DATA OUT
-		   TEST UNIT READY              00
-		   WRITE BUFFER                 3b DATA OUT
-
-		   p.178: Commands for direct-access devices (not listed on p. 94)
-		   FORMAT UNIT                  04 DATA OUT
-		   LOCK-UNLOCK CACHE            36
-		   PRE-FETCH                    34
-		   PREVENT-ALLOW MEDIUM REMOVAL 1e
-		   READ (6)/RECEIVE             08
-		   READ (10)                    3c
-		   READ CAPACITY                25
-		   READ DEFECT DATA (10)        37
-		   READ LONG                    3e
-		   REASSIGN BLOCKS              07 DATA OUT
-		   RELEASE                      17
-		   RESERVE                      16 DATA OUT
-		   REZERO UNIT/REWIND           01
-		   SEARCH DATA EQUAL (10)       31 DATA OUT
-		   SEARCH DATA HIGH (10)        30 DATA OUT
-		   SEARCH DATA LOW (10)         32 DATA OUT
-		   SEEK (6)                     0b
-		   SEEK (10)                    2b
-		   SET LIMITS (10)              33
-		   START STOP UNIT              1b
-		   SYNCHRONIZE CACHE            35
-		   VERIFY (10)                  2f
-		   WRITE (6)/PRINT/SEND         0a DATA OUT
-		   WRITE (10)/SEND              2a DATA OUT
-		   WRITE AND VERIFY (10)        2e DATA OUT
-		   WRITE LONG                   3f DATA OUT
-		   WRITE SAME                   41 DATA OUT ?
-
-		   p. 261: Commands for sequential-access devices (not previously listed)
-		   ERASE                        19
-		   LOAD UNLOAD                  1b
-		   LOCATE                       2b
-		   READ BLOCK LIMITS            05
-		   READ POSITION                34
-		   READ REVERSE                 0f
-		   RECOVER BUFFERED DATA        14
-		   SPACE                        11
-		   WRITE FILEMARKS              10 ?
-
-		   p. 298: Commands for printer devices (not previously listed)
-		   ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
-		   SLEW AND PRINT               0b DATA OUT  -- same as seek
-		   STOP PRINT                   1b
-		   SYNCHRONIZE BUFFER           10
-
-		   p. 315: Commands for processor devices (not previously listed)
-
-		   p. 321: Commands for write-once devices (not previously listed)
-		   MEDIUM SCAN                  38
-		   READ (12)                    a8
-		   SEARCH DATA EQUAL (12)       b1 DATA OUT
-		   SEARCH DATA HIGH (12)        b0 DATA OUT
-		   SEARCH DATA LOW (12)         b2 DATA OUT
-		   SET LIMITS (12)              b3
-		   VERIFY (12)                  af
-		   WRITE (12)                   aa DATA OUT
-		   WRITE AND VERIFY (12)        ae DATA OUT
-
-		   p. 332: Commands for CD-ROM devices (not previously listed)
-		   PAUSE/RESUME                 4b
-		   PLAY AUDIO (10)              45
-		   PLAY AUDIO (12)              a5
-		   PLAY AUDIO MSF               47
-		   PLAY TRACK RELATIVE (10)     49
-		   PLAY TRACK RELATIVE (12)     a9
-		   READ HEADER                  44
-		   READ SUB-CHANNEL             42
-		   READ TOC                     43
-
-		   p. 370: Commands for scanner devices (not previously listed)
-		   GET DATA BUFFER STATUS       34
-		   GET WINDOW                   25
-		   OBJECT POSITION              31
-		   SCAN                         1b
-		   SET WINDOW                   24 DATA OUT
-
-		   p. 391: Commands for optical memory devices (not listed)
-		   ERASE (10)                   2c
-		   ERASE (12)                   ac
-		   MEDIUM SCAN                  38 DATA OUT
-		   READ DEFECT DATA (12)        b7
-		   READ GENERATION              29
-		   READ UPDATED BLOCK           2d
-		   UPDATE BLOCK                 3d DATA OUT
-
-		   p. 419: Commands for medium changer devices (not listed)
-		   EXCHANGE MEDIUM              46
-		   INITIALIZE ELEMENT STATUS    07
-		   MOVE MEDIUM                  a5
-		   POSITION TO ELEMENT          2b
-		   READ ELEMENT STATUS          b8
-		   REQUEST VOL. ELEMENT ADDRESS b5
-		   SEND VOLUME TAG              b6 DATA OUT
-
-		   p. 454: Commands for communications devices (not listed previously)
-		   GET MESSAGE (6)              08
-		   GET MESSAGE (10)             28
-		   GET MESSAGE (12)             a8
-		 */
-
-		switch (current_SC->cmnd[0]) {
-		case CHANGE_DEFINITION:
-		case COMPARE:
-		case COPY:
-		case COPY_VERIFY:
-		case LOG_SELECT:
-		case MODE_SELECT:
-		case MODE_SELECT_10:
-		case SEND_DIAGNOSTIC:
-		case WRITE_BUFFER:
-
-		case FORMAT_UNIT:
-		case REASSIGN_BLOCKS:
-		case RESERVE:
-		case SEARCH_EQUAL:
-		case SEARCH_HIGH:
-		case SEARCH_LOW:
-		case WRITE_6:
-		case WRITE_10:
-		case WRITE_VERIFY:
-		case 0x3f:
-		case 0x41:
-
-		case 0xb1:
-		case 0xb0:
-		case 0xb2:
-		case 0xaa:
-		case 0xae:
-
-		case 0x24:
-
-		case 0x38:
-		case 0x3d:
-
-		case 0xb6:
-
-		case 0xea:	/* alternate number for WRITE LONG */
-
-			current_SC->SCp.have_data_in = -1;
-			outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
-			break;
-
-		case 0x00:
-		default:
-
-			current_SC->SCp.have_data_in = 1;
-			outb(0x90 | PARITY_MASK, TMC_Cntl_port);
-			break;
-		}
-	}
-
-	if (current_SC->SCp.have_data_in == -1) {	/* DATA OUT */
-		while ((data_count = FIFO_Size - inw(FIFO_Data_Count_port)) > 512) {
-#if EVERY_ACCESS
-			printk("DC=%d, ", data_count);
-#endif
-			if (data_count > current_SC->SCp.this_residual)
-				data_count = current_SC->SCp.this_residual;
-			if (data_count > 0) {
-#if EVERY_ACCESS
-				printk("%d OUT, ", data_count);
-#endif
-				if (data_count == 1) {
-					Bytes_Written++;
-
-					outb(*current_SC->SCp.ptr++, Write_FIFO_port);
-					--current_SC->SCp.this_residual;
-				} else {
-					data_count >>= 1;
-					tmp_count = data_count << 1;
-					outsw(Write_FIFO_port, current_SC->SCp.ptr, data_count);
-					current_SC->SCp.ptr += tmp_count;
-					Bytes_Written += tmp_count;
-					current_SC->SCp.this_residual -= tmp_count;
-				}
-			}
-			if (!current_SC->SCp.this_residual) {
-				if (current_SC->SCp.buffers_residual) {
-					--current_SC->SCp.buffers_residual;
-					++current_SC->SCp.buffer;
-					current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
-					current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
-				} else
-					break;
-			}
-		}
-	} else if (current_SC->SCp.have_data_in == 1) {	/* DATA IN */
-		while ((data_count = inw(FIFO_Data_Count_port)) > 0) {
-#if EVERY_ACCESS
-			printk("DC=%d, ", data_count);
-#endif
-			if (data_count > current_SC->SCp.this_residual)
-				data_count = current_SC->SCp.this_residual;
-			if (data_count) {
-#if EVERY_ACCESS
-				printk("%d IN, ", data_count);
-#endif
-				if (data_count == 1) {
-					Bytes_Read++;
-					*current_SC->SCp.ptr++ = inb(Read_FIFO_port);
-					--current_SC->SCp.this_residual;
-				} else {
-					data_count >>= 1;	/* Number of words */
-					tmp_count = data_count << 1;
-					insw(Read_FIFO_port, current_SC->SCp.ptr, data_count);
-					current_SC->SCp.ptr += tmp_count;
-					Bytes_Read += tmp_count;
-					current_SC->SCp.this_residual -= tmp_count;
-				}
-			}
-			if (!current_SC->SCp.this_residual && current_SC->SCp.buffers_residual) {
-				--current_SC->SCp.buffers_residual;
-				++current_SC->SCp.buffer;
-				current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
-				current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
-			}
-		}
-	}
-
-	if (done) {
-#if EVERY_ACCESS
-		printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
-#endif
-
-#if EVERY_ACCESS
-		printk("BEFORE MY_DONE. . .");
-#endif
-		spin_lock_irqsave(shpnt->host_lock, flags);
-		my_done(shpnt, (current_SC->SCp.Status & 0xff)
-			| ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
-		spin_unlock_irqrestore(shpnt->host_lock, flags);
-#if EVERY_ACCESS
-		printk("RETURNING.\n");
-#endif
-
-	} else {
-		if (current_SC->SCp.phase & disconnect) {
-			outb(0xd0 | FIFO_COUNT, Interrupt_Cntl_port);
-			outb(0x00, SCSI_Cntl_port);
-		} else {
-			outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
-		}
-	}
-#if DEBUG_RACE
-	in_interrupt_flag = 0;
-#endif
-	return IRQ_HANDLED;
-}
-
-static int fd_mcs_release(struct Scsi_Host *shpnt)
-{
-	int i, this_host, irq_usage;
-
-	release_region(shpnt->io_port, shpnt->n_io_port);
-
-	this_host = -1;
-	irq_usage = 0;
-	for (i = 0; i < found; i++) {
-		if (shpnt == hosts[i])
-			this_host = i;
-		if (shpnt->irq == hosts[i]->irq)
-			irq_usage++;
-	}
-
-	/* only for the last one */
-	if (1 == irq_usage)
-		free_irq(shpnt->irq, hosts);
-
-	found--;
-
-	for (i = this_host; i < found; i++)
-		hosts[i] = hosts[i + 1];
-
-	hosts[found] = NULL;
-
-	return 0;
-}
-
-static int fd_mcs_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
-{
-	struct Scsi_Host *shpnt = SCpnt->device->host;
-
-	if (in_command) {
-		panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
-	}
-#if EVERY_ACCESS
-	printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
-		SCpnt->target, *(unsigned char *) SCpnt->cmnd,
-		scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
-#endif
-
-	fd_mcs_make_bus_idle(shpnt);
-
-	SCpnt->scsi_done = done;	/* Save this for the done function */
-	current_SC = SCpnt;
-
-	/* Initialize static data */
-
-	if (scsi_bufflen(current_SC)) {
-		current_SC->SCp.buffer = scsi_sglist(current_SC);
-		current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
-		current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
-		current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
-	} else {
-		current_SC->SCp.ptr = NULL;
-		current_SC->SCp.this_residual = 0;
-		current_SC->SCp.buffer = NULL;
-		current_SC->SCp.buffers_residual = 0;
-	}
-
-
-	current_SC->SCp.Status = 0;
-	current_SC->SCp.Message = 0;
-	current_SC->SCp.have_data_in = 0;
-	current_SC->SCp.sent_command = 0;
-	current_SC->SCp.phase = in_arbitration;
-
-	/* Start arbitration */
-	outb(0x00, Interrupt_Cntl_port);
-	outb(0x00, SCSI_Cntl_port);	/* Disable data drivers */
-	outb(adapter_mask, SCSI_Data_NoACK_port);	/* Set our id bit */
-	in_command = 1;
-	outb(0x20, Interrupt_Cntl_port);
-	outb(0x14 | PARITY_MASK, TMC_Cntl_port);	/* Start arbitration */
-
-	return 0;
-}
-
-static DEF_SCSI_QCMD(fd_mcs_queue)
-
-#if DEBUG_ABORT || DEBUG_RESET
-static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
-{
-	unsigned int imr;
-	unsigned int irr;
-	unsigned int isr;
-	struct Scsi_Host *shpnt = SCpnt->host;
-
-	if (!SCpnt || !SCpnt->host) {
-		printk("fd_mcs: cannot provide detailed information\n");
-	}
-
-	printk("%s\n", fd_mcs_info(SCpnt->host));
-	print_banner(SCpnt->host);
-	switch (SCpnt->SCp.phase) {
-	case in_arbitration:
-		printk("arbitration ");
-		break;
-	case in_selection:
-		printk("selection ");
-		break;
-	case in_other:
-		printk("other ");
-		break;
-	default:
-		printk("unknown ");
-		break;
-	}
-
-	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
-		SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd,
-		scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
-	printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
-#if DEBUG_RACE
-	printk("in_interrupt_flag = %d\n", in_interrupt_flag);
-#endif
-
-	imr = (inb(0x0a1) << 8) + inb(0x21);
-	outb(0x0a, 0xa0);
-	irr = inb(0xa0) << 8;
-	outb(0x0a, 0x20);
-	irr += inb(0x20);
-	outb(0x0b, 0xa0);
-	isr = inb(0xa0) << 8;
-	outb(0x0b, 0x20);
-	isr += inb(0x20);
-
-	/* Print out interesting information */
-	printk("IMR = 0x%04x", imr);
-	if (imr & (1 << shpnt->irq))
-		printk(" (masked)");
-	printk(", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr);
-
-	printk("SCSI Status      = 0x%02x\n", inb(SCSI_Status_port));
-	printk("TMC Status       = 0x%02x", inb(TMC_Status_port));
-	if (inb(TMC_Status_port) & 1)
-		printk(" (interrupt)");
-	printk("\n");
-	printk("Interrupt Status = 0x%02x", inb(Interrupt_Status_port));
-	if (inb(Interrupt_Status_port) & 0x08)
-		printk(" (enabled)");
-	printk("\n");
-	if (chip == tmc18c50 || chip == tmc18c30) {
-		printk("FIFO Status      = 0x%02x\n", inb(shpnt->io_port + FIFO_Status));
-		printk("Int. Condition   = 0x%02x\n", inb(shpnt->io_port + Interrupt_Cond));
-	}
-	printk("Configuration 1  = 0x%02x\n", inb(shpnt->io_port + Configuration1));
-	if (chip == tmc18c50 || chip == tmc18c30)
-		printk("Configuration 2  = 0x%02x\n", inb(shpnt->io_port + Configuration2));
-}
-#endif
-
-static int fd_mcs_abort(Scsi_Cmnd * SCpnt)
-{
-	struct Scsi_Host *shpnt = SCpnt->device->host;
-
-	unsigned long flags;
-#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
-	printk("fd_mcs: abort ");
-#endif
-
-	spin_lock_irqsave(shpnt->host_lock, flags);
-	if (!in_command) {
-#if EVERY_ACCESS || ERRORS_ONLY
-		printk(" (not in command)\n");
-#endif
-		spin_unlock_irqrestore(shpnt->host_lock, flags);
-		return FAILED;
-	} else
-		printk("\n");
-
-#if DEBUG_ABORT
-	fd_mcs_print_info(SCpnt);
-#endif
-
-	fd_mcs_make_bus_idle(shpnt);
-
-	current_SC->SCp.phase |= aborted;
-
-	current_SC->result = DID_ABORT << 16;
-
-	/* Aborts are not done well. . . */
-	my_done(shpnt, DID_ABORT << 16);
-
-	spin_unlock_irqrestore(shpnt->host_lock, flags);
-	return SUCCESS;
-}
-
-static int fd_mcs_bus_reset(Scsi_Cmnd * SCpnt) {
-	struct Scsi_Host *shpnt = SCpnt->device->host;
-	unsigned long flags;
-
-#if DEBUG_RESET
-	static int called_once = 0;
-#endif
-
-#if ERRORS_ONLY
-	if (SCpnt)
-		printk("fd_mcs: SCSI Bus Reset\n");
-#endif
-
-#if DEBUG_RESET
-	if (called_once)
-		fd_mcs_print_info(current_SC);
-	called_once = 1;
-#endif
-
-	spin_lock_irqsave(shpnt->host_lock, flags);
-
-	outb(1, SCSI_Cntl_port);
-	do_pause(2);
-	outb(0, SCSI_Cntl_port);
-	do_pause(115);
-	outb(0, SCSI_Mode_Cntl_port);
-	outb(PARITY_MASK, TMC_Cntl_port);
-
-	spin_unlock_irqrestore(shpnt->host_lock, flags);
-
-	/* Unless this is the very first call (i.e., SCPnt == NULL), everything
-	   is probably hosed at this point.  We will, however, try to keep
-	   things going by informing the high-level code that we need help. */
-		return SUCCESS;
-}
-
-#include <scsi/scsi_ioctl.h>
-
-static int fd_mcs_biosparam(struct scsi_device * disk, struct block_device *bdev,
-			    sector_t capacity, int *info_array) 
-{
-	unsigned char *p = scsi_bios_ptable(bdev);
-	int size = capacity;
-
-	/* BIOS >= 3.4 for MCA cards */
-	/* This algorithm was provided by Future Domain (much thanks!). */
-
-	if (p && p[65] == 0xaa && p[64] == 0x55	/* Partition table valid */
-	    && p[4]) {	/* Partition type */
-		/* The partition table layout is as follows:
-
-		   Start: 0x1b3h
-		   Offset: 0 = partition status
-		   1 = starting head
-		   2 = starting sector and cylinder (word, encoded)
-		   4 = partition type
-		   5 = ending head
-		   6 = ending sector and cylinder (word, encoded)
-		   8 = starting absolute sector (double word)
-		   c = number of sectors (double word)
-		   Signature: 0x1fe = 0x55aa
-
-		   So, this algorithm assumes:
-		   1) the first partition table is in use,
-		   2) the data in the first entry is correct, and
-		   3) partitions never divide cylinders
-
-		   Note that (1) may be FALSE for NetBSD (and other BSD flavors),
-		   as well as for Linux.  Note also, that Linux doesn't pay any
-		   attention to the fields that are used by this algorithm -- it
-		   only uses the absolute sector data.  Recent versions of Linux's
-		   fdisk(1) will fill this data in correctly, and forthcoming
-		   versions will check for consistency.
-
-		   Checking for a non-zero partition type is not part of the
-		   Future Domain algorithm, but it seemed to be a reasonable thing
-		   to do, especially in the Linux and BSD worlds. */
-
-		info_array[0] = p[5] + 1;	/* heads */
-		info_array[1] = p[6] & 0x3f;	/* sectors */
-	} else {
-		/* Note that this new method guarantees that there will always be
-		   less than 1024 cylinders on a platter.  This is good for drives
-		   up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
-		if ((unsigned int) size >= 0x7e0000U) 
-		{
-			info_array[0] = 0xff;	/* heads   = 255 */
-			info_array[1] = 0x3f;	/* sectors =  63 */
-		} else if ((unsigned int) size >= 0x200000U) {
-			info_array[0] = 0x80;	/* heads   = 128 */
-			info_array[1] = 0x3f;	/* sectors =  63 */
-		} else {
-			info_array[0] = 0x40;	/* heads   =  64 */
-			info_array[1] = 0x20;	/* sectors =  32 */
-		}
-	}
-	/* For both methods, compute the cylinders */
-	info_array[2] = (unsigned int) size / (info_array[0] * info_array[1]);
-	kfree(p);
-	return 0;
-}
-
-static struct scsi_host_template driver_template = {
-	.proc_name			= "fd_mcs",
-	.proc_info			= fd_mcs_proc_info,
-	.detect				= fd_mcs_detect,
-	.release			= fd_mcs_release,
-	.info				= fd_mcs_info,
-	.queuecommand   		= fd_mcs_queue, 
-	.eh_abort_handler		= fd_mcs_abort,
-	.eh_bus_reset_handler		= fd_mcs_bus_reset,
-	.bios_param     		= fd_mcs_biosparam,
-	.can_queue      		= 1,
-	.this_id        		= 7,
-	.sg_tablesize   		= 64,
-	.cmd_per_lun    		= 1,
-	.use_clustering 		= DISABLE_CLUSTERING,
-};
-#include "scsi_module.c"
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
deleted file mode 100644
index cd09132..0000000
--- a/drivers/scsi/ibmmca.c
+++ /dev/null
@@ -1,2379 +0,0 @@
-/*
- Low Level Linux Driver for the IBM Microchannel SCSI Subsystem for
- Linux Kernel >= 2.4.0.
- Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU
- General Public License. Written by Martin Kolinek, December 1995.
- Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang
- See the file Documentation/scsi/ibmmca.txt for a detailed description
- of this driver, the commandline arguments and the history of its
- development.
- See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest
- updates, info and ADF-files for adapters supported by this driver.
-
- Alan Cox <alan@lxorguk.ukuu.org.uk>
- Updated for Linux 2.5.45 to use the new error handler, cleaned up the
- lock macros and did a few unavoidable locking tweaks, plus one locking
- fix in the irq and completion path.
- 
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mca.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-/* Common forward declarations for all Linux-versions: */
-static int ibmmca_queuecommand (struct Scsi_Host *, struct scsi_cmnd *);
-static int ibmmca_abort (Scsi_Cmnd *);
-static int ibmmca_host_reset (Scsi_Cmnd *);
-static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
-static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout);
-
-
-
-/* current version of this driver-source: */
-#define IBMMCA_SCSI_DRIVER_VERSION "4.0b-ac"
-
-/* driver configuration */
-#define IM_MAX_HOSTS     8	/* maximum number of host adapters */
-#define IM_RESET_DELAY	60	/* seconds allowed for a reset */
-
-/* driver debugging - #undef all for normal operation */
-/* if defined: count interrupts and ignore this special one: */
-#undef	IM_DEBUG_TIMEOUT	//50
-#define TIMEOUT_PUN	0
-#define TIMEOUT_LUN	0
-/* verbose interrupt: */
-#undef IM_DEBUG_INT
-/* verbose queuecommand: */
-#undef IM_DEBUG_CMD
-/* verbose queucommand for specific SCSI-device type: */
-#undef IM_DEBUG_CMD_SPEC_DEV
-/* verbose device probing */
-#undef IM_DEBUG_PROBE
-
-/* device type that shall be displayed on syslog (only during debugging): */
-#define IM_DEBUG_CMD_DEVICE	TYPE_TAPE
-
-/* relative addresses of hardware registers on a subsystem */
-#define IM_CMD_REG(h)	((h)->io_port)	/*Command Interface, (4 bytes long) */
-#define IM_ATTN_REG(h)	((h)->io_port+4)	/*Attention (1 byte) */
-#define IM_CTR_REG(h)	((h)->io_port+5)	/*Basic Control (1 byte) */
-#define IM_INTR_REG(h)	((h)->io_port+6)	/*Interrupt Status (1 byte, r/o) */
-#define IM_STAT_REG(h)	((h)->io_port+7)	/*Basic Status (1 byte, read only) */
-
-/* basic I/O-port of first adapter */
-#define IM_IO_PORT	0x3540
-/* maximum number of hosts that can be found */
-#define IM_N_IO_PORT	8
-
-/*requests going into the upper nibble of the Attention register */
-/*note: the lower nibble specifies the device(0-14), or subsystem(15) */
-#define IM_IMM_CMD	0x10	/*immediate command */
-#define IM_SCB		0x30	/*Subsystem Control Block command */
-#define IM_LONG_SCB	0x40	/*long Subsystem Control Block command */
-#define IM_EOI		0xe0	/*end-of-interrupt request */
-
-/*values for bits 7,1,0 of Basic Control reg. (bits 6-2 reserved) */
-#define IM_HW_RESET	0x80	/*hardware reset */
-#define IM_ENABLE_DMA	0x02	/*enable subsystem's busmaster DMA */
-#define IM_ENABLE_INTR	0x01	/*enable interrupts to the system */
-
-/*to interpret the upper nibble of Interrupt Status register */
-/*note: the lower nibble specifies the device(0-14), or subsystem(15) */
-#define IM_SCB_CMD_COMPLETED			0x10
-#define IM_SCB_CMD_COMPLETED_WITH_RETRIES	0x50
-#define IM_LOOP_SCATTER_BUFFER_FULL		0x60
-#define IM_ADAPTER_HW_FAILURE			0x70
-#define IM_IMMEDIATE_CMD_COMPLETED		0xa0
-#define IM_CMD_COMPLETED_WITH_FAILURE		0xc0
-#define IM_CMD_ERROR				0xe0
-#define IM_SOFTWARE_SEQUENCING_ERROR		0xf0
-
-/*to interpret bits 3-0 of Basic Status register (bits 7-4 reserved) */
-#define IM_CMD_REG_FULL		0x08
-#define IM_CMD_REG_EMPTY	0x04
-#define IM_INTR_REQUEST		0x02
-#define IM_BUSY			0x01
-
-/*immediate commands (word written into low 2 bytes of command reg) */
-#define IM_RESET_IMM_CMD	0x0400
-#define IM_FEATURE_CTR_IMM_CMD	0x040c
-#define IM_DMA_PACING_IMM_CMD	0x040d
-#define IM_ASSIGN_IMM_CMD	0x040e
-#define IM_ABORT_IMM_CMD	0x040f
-#define IM_FORMAT_PREP_IMM_CMD	0x0417
-
-/*SCB (Subsystem Control Block) structure */
-struct im_scb {
-	unsigned short command;	/*command word (read, etc.) */
-	unsigned short enable;	/*enable word, modifies cmd */
-	union {
-		unsigned long log_blk_adr;	/*block address on SCSI device */
-		unsigned char scsi_cmd_length;	/*6,10,12, for other scsi cmd */
-	} u1;
-	unsigned long sys_buf_adr;	/*physical system memory adr */
-	unsigned long sys_buf_length;	/*size of sys mem buffer */
-	unsigned long tsb_adr;	/*Termination Status Block adr */
-	unsigned long scb_chain_adr;	/*optional SCB chain address */
-	union {
-		struct {
-			unsigned short count;	/*block count, on SCSI device */
-			unsigned short length;	/*block length, on SCSI device */
-		} blk;
-		unsigned char scsi_command[12];	/*other scsi command */
-	} u2;
-};
-
-/*structure scatter-gather element (for list of system memory areas) */
-struct im_sge {
-	void *address;
-	unsigned long byte_length;
-};
-
-/*structure returned by a get_pos_info command: */
-struct im_pos_info {
-	unsigned short pos_id;	/* adapter id */
-	unsigned char pos_3a;	/* pos 3 (if pos 6 = 0) */
-	unsigned char pos_2;	/* pos 2 */
-	unsigned char int_level;	/* interrupt level IRQ 11 or 14 */
-	unsigned char pos_4a;	/* pos 4 (if pos 6 = 0) */
-	unsigned short connector_size;	/* MCA connector size: 16 or 32 Bit */
-	unsigned char num_luns;	/* number of supported luns per device */
-	unsigned char num_puns;	/* number of supported puns */
-	unsigned char pacing_factor;	/* pacing factor */
-	unsigned char num_ldns;	/* number of ldns available */
-	unsigned char eoi_off;	/* time EOI and interrupt inactive */
-	unsigned char max_busy;	/* time between reset and busy on */
-	unsigned short cache_stat;	/* ldn cachestat. Bit=1 = not cached */
-	unsigned short retry_stat;	/* retry status of ldns. Bit=1=disabled */
-	unsigned char pos_4b;	/* pos 4 (if pos 6 = 1) */
-	unsigned char pos_3b;	/* pos 3 (if pos 6 = 1) */
-	unsigned char pos_6;	/* pos 6 */
-	unsigned char pos_5;	/* pos 5 */
-	unsigned short max_overlap;	/* maximum overlapping requests */
-	unsigned short num_bus;	/* number of SCSI-busses */
-};
-
-/*values for SCB command word */
-#define IM_NO_SYNCHRONOUS      0x0040	/*flag for any command */
-#define IM_NO_DISCONNECT       0x0080	/*flag for any command */
-#define IM_READ_DATA_CMD       0x1c01
-#define IM_WRITE_DATA_CMD      0x1c02
-#define IM_READ_VERIFY_CMD     0x1c03
-#define IM_WRITE_VERIFY_CMD    0x1c04
-#define IM_REQUEST_SENSE_CMD   0x1c08
-#define IM_READ_CAPACITY_CMD   0x1c09
-#define IM_DEVICE_INQUIRY_CMD  0x1c0b
-#define IM_READ_LOGICAL_CMD    0x1c2a
-#define IM_OTHER_SCSI_CMD_CMD  0x241f
-
-/* unused, but supported, SCB commands */
-#define IM_GET_COMMAND_COMPLETE_STATUS_CMD   0x1c07	/* command status */
-#define IM_GET_POS_INFO_CMD                  0x1c0a	/* returns neat stuff */
-#define IM_READ_PREFETCH_CMD                 0x1c31	/* caching controller only */
-#define IM_FOMAT_UNIT_CMD                    0x1c16	/* format unit */
-#define IM_REASSIGN_BLOCK_CMD                0x1c18	/* in case of error */
-
-/*values to set bits in the enable word of SCB */
-#define IM_READ_CONTROL              0x8000
-#define IM_REPORT_TSB_ONLY_ON_ERROR  0x4000
-#define IM_RETRY_ENABLE              0x2000
-#define IM_POINTER_TO_LIST           0x1000
-#define IM_SUPRESS_EXCEPTION_SHORT   0x0400
-#define IM_BYPASS_BUFFER             0x0200
-#define IM_CHAIN_ON_NO_ERROR         0x0001
-
-/*TSB (Termination Status Block) structure */
-struct im_tsb {
-	unsigned short end_status;
-	unsigned short reserved1;
-	unsigned long residual_byte_count;
-	unsigned long sg_list_element_adr;
-	unsigned short status_length;
-	unsigned char dev_status;
-	unsigned char cmd_status;
-	unsigned char dev_error;
-	unsigned char cmd_error;
-	unsigned short reserved2;
-	unsigned short reserved3;
-	unsigned short low_of_last_scb_adr;
-	unsigned short high_of_last_scb_adr;
-};
-
-/*subsystem uses interrupt request level 14 */
-#define IM_IRQ     14
-/*SCSI-2 F/W may evade to interrupt 11 */
-#define IM_IRQ_FW  11
-
-/* Model 95 has an additional alphanumeric display, which can be used
-   to display SCSI-activities. 8595 models do not have any disk led, which
-   makes this feature quite useful.
-   The regular PS/2 disk led is turned on/off by bits 6,7 of system
-   control port. */
-
-/* LED display-port (actually, last LED on display) */
-#define MOD95_LED_PORT	   0x108
-/* system-control-register of PS/2s with diskindicator */
-#define PS2_SYS_CTR        0x92
-/* activity displaying methods */
-#define LED_DISP           1
-#define LED_ADISP          2
-#define LED_ACTIVITY       4
-/* failed intr */
-#define CMD_FAIL           255
-
-/* The SCSI-ID(!) of the accessed SCSI-device is shown on PS/2-95 machines' LED
-   displays. ldn is no longer displayed here, because the ldn mapping is now 
-   done dynamically and the ldn <-> pun,lun maps can be looked-up at boottime 
-   or during uptime in /proc/scsi/ibmmca/<host_no> in case of trouble, 
-   interest, debugging or just for having fun. The left number gives the
-   host-adapter number and the right shows the accessed SCSI-ID. */
-
-/* display_mode is set by the ibmmcascsi= command line arg */
-static int display_mode = 0;
-/* set default adapter timeout */
-static unsigned int adapter_timeout = 45;
-/* for probing on feature-command: */
-static unsigned int global_command_error_excuse = 0;
-/* global setting by command line for adapter_speed */
-static int global_adapter_speed = 0;	/* full speed by default */
-
-/* Panel / LED on, do it right for F/W addressin, too. adisplay will
- * just ignore ids>7, as the panel has only 7 digits available */
-#define PS2_DISK_LED_ON(ad,id) { if (display_mode & LED_DISP) { if (id>9) \
-    outw((ad+48)|((id+55)<<8), MOD95_LED_PORT ); else \
-    outw((ad+48)|((id+48)<<8), MOD95_LED_PORT ); } else \
-    if (display_mode & LED_ADISP) { if (id<7) outb((char)(id+48),MOD95_LED_PORT+1+id); \
-    outb((char)(ad+48), MOD95_LED_PORT); } \
-    if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
-    outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); }
-
-/* Panel / LED off */
-/* bug fixed, Dec 15, 1997, where | was replaced by & here */
-#define PS2_DISK_LED_OFF() { if (display_mode & LED_DISP) \
-    outw(0x2020, MOD95_LED_PORT ); else if (display_mode & LED_ADISP) { \
-    outl(0x20202020,MOD95_LED_PORT); outl(0x20202020,MOD95_LED_PORT+4); } \
-    if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
-    outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); }
-
-/* types of different supported hardware that goes to hostdata special */
-#define IBM_SCSI2_FW     0
-#define IBM_7568_WCACHE  1
-#define IBM_EXP_UNIT     2
-#define IBM_SCSI_WCACHE  3
-#define IBM_SCSI         4
-#define IBM_INTEGSCSI	 5
-
-/* other special flags for hostdata structure */
-#define FORCED_DETECTION         100
-#define INTEGRATED_SCSI          101
-
-/* List of possible IBM-SCSI-adapters */
-static short ibmmca_id_table[] = {
-	0x8efc,
-	0x8efd,
-	0x8ef8,
-	0x8eff,
-	0x8efe,
-	/* No entry for integrated SCSI, that's part of the register */
-	0
-};
-
-static const char *ibmmca_description[] = {
-	"IBM SCSI-2 F/W Adapter",	/* special = 0 */
-	"IBM 7568 Industrial Computer SCSI Adapter w/Cache",	/* special = 1 */
-	"IBM Expansion Unit SCSI Controller",	/* special = 2 */
-	"IBM SCSI Adapter w/Cache",	/* special = 3 */
-	"IBM SCSI Adapter",	/* special = 4 */
-	"IBM Integrated SCSI Controller", /* special = 5 */
-};
-
-/* Max number of logical devices (can be up from 0 to 14).  15 is the address
-of the adapter itself. */
-#define MAX_LOG_DEV  15
-
-/*local data for a logical device */
-struct logical_device {
-	struct im_scb scb;	/* SCSI-subsystem-control-block structure */
-	struct im_tsb tsb;	/* SCSI command complete status block structure */
-	struct im_sge sge[16];	/* scatter gather list structure */
-	unsigned char buf[256];	/* SCSI command return data buffer */
-	Scsi_Cmnd *cmd;		/* SCSI-command that is currently in progress */
-	int device_type;	/* type of the SCSI-device. See include/scsi/scsi.h
-				   for interpretation of the possible values */
-	int block_length;	/* blocksize of a particular logical SCSI-device */
-	int cache_flag;		/* 1 if this is uncached, 0 if cache is present for ldn */
-	int retry_flag;		/* 1 if adapter retry is disabled, 0 if enabled */
-};
-
-/* statistics of the driver during operations (for proc_info) */
-struct Driver_Statistics {
-	/* SCSI statistics on the adapter */
-	int ldn_access[MAX_LOG_DEV + 1];	/* total accesses on a ldn */
-	int ldn_read_access[MAX_LOG_DEV + 1];	/* total read-access on a ldn */
-	int ldn_write_access[MAX_LOG_DEV + 1];	/* total write-access on a ldn */
-	int ldn_inquiry_access[MAX_LOG_DEV + 1];	/* total inquiries on a ldn */
-	int ldn_modeselect_access[MAX_LOG_DEV + 1];	/* total mode selects on ldn */
-	int scbs;		/* short SCBs queued */
-	int long_scbs;		/* long SCBs queued */
-	int total_accesses;	/* total accesses on all ldns */
-	int total_interrupts;	/* total interrupts (should be
-				   same as total_accesses) */
-	int total_errors;	/* command completed with error */
-	/* dynamical assignment statistics */
-	int total_scsi_devices;	/* number of physical pun,lun */
-	int dyn_flag;		/* flag showing dynamical mode */
-	int dynamical_assignments;	/* number of remappings of ldns */
-	int ldn_assignments[MAX_LOG_DEV + 1];	/* number of remappings of each
-						   ldn */
-};
-
-/* data structure for each host adapter */
-struct ibmmca_hostdata {
-	/* array of logical devices: */
-	struct logical_device _ld[MAX_LOG_DEV + 1];
-	/* array to convert (pun, lun) into logical device number: */
-	unsigned char _get_ldn[16][8];
-	/*array that contains the information about the physical SCSI-devices
-	   attached to this host adapter: */
-	unsigned char _get_scsi[16][8];
-	/* used only when checking logical devices: */
-	int _local_checking_phase_flag;
-	/* report received interrupt: */
-	int _got_interrupt;
-	/* report termination-status of SCSI-command: */
-	int _stat_result;
-	/* reset status (used only when doing reset): */
-	int _reset_status;
-	/* code of the last SCSI command (needed for panic info): */
-	int _last_scsi_command[MAX_LOG_DEV + 1];
-	/* identifier of the last SCSI-command type */
-	int _last_scsi_type[MAX_LOG_DEV + 1];
-	/* last blockcount */
-	int _last_scsi_blockcount[MAX_LOG_DEV + 1];
-	/* last locgical block address */
-	unsigned long _last_scsi_logical_block[MAX_LOG_DEV + 1];
-	/* Counter that points on the next reassignable ldn for dynamical
-	   remapping. The default value is 7, that is the first reassignable
-	   number in the list at boottime: */
-	int _next_ldn;
-	/* Statistics-structure for this IBM-SCSI-host: */
-	struct Driver_Statistics _IBM_DS;
-	/* This hostadapters pos-registers pos2 until pos6 */
-	unsigned int _pos[8];
-	/* assign a special variable, that contains dedicated info about the
-	   adaptertype */
-	int _special;
-	/* connector size on the MCA bus */
-	int _connector_size;
-	/* synchronous SCSI transfer rate bitpattern */
-	int _adapter_speed;
-};
-
-/* macros to access host data structure */
-#define subsystem_pun(h) ((h)->this_id)
-#define subsystem_maxid(h) ((h)->max_id)
-#define ld(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_ld)
-#define get_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_ldn)
-#define get_scsi(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_scsi)
-#define local_checking_phase_flag(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_local_checking_phase_flag)
-#define got_interrupt(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_got_interrupt)
-#define stat_result(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_stat_result)
-#define reset_status(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_reset_status)
-#define last_scsi_command(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_command)
-#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)
-#define last_scsi_blockcount(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_blockcount)
-#define last_scsi_logical_block(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_logical_block)
-#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)
-#define next_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_next_ldn)
-#define IBM_DS(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_IBM_DS)
-#define special(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_special)
-#define subsystem_connector_size(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_connector_size)
-#define adapter_speed(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_adapter_speed)
-#define pos2(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[2])
-#define pos3(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[3])
-#define pos4(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[4])
-#define pos5(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[5])
-#define pos6(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[6])
-
-/* Define a arbitrary number as subsystem-marker-type. This number is, as
-   described in the ANSI-SCSI-standard, not occupied by other device-types. */
-#define TYPE_IBM_SCSI_ADAPTER   0x2F
-
-/* Define 0xFF for no device type, because this type is not defined within
-   the ANSI-SCSI-standard, therefore, it can be used and should not cause any
-   harm. */
-#define TYPE_NO_DEVICE          0xFF
-
-/* define medium-changer. If this is not defined previously, e.g. Linux
-   2.0.x, define this type here. */
-#ifndef TYPE_MEDIUM_CHANGER
-#define TYPE_MEDIUM_CHANGER     0x08
-#endif
-
-/* define possible operations for the immediate_assign command */
-#define SET_LDN        0
-#define REMOVE_LDN     1
-
-/* ldn which is used to probe the SCSI devices */
-#define PROBE_LDN      0
-
-/* reset status flag contents */
-#define IM_RESET_NOT_IN_PROGRESS         0
-#define IM_RESET_IN_PROGRESS             1
-#define IM_RESET_FINISHED_OK             2
-#define IM_RESET_FINISHED_FAIL           3
-#define IM_RESET_NOT_IN_PROGRESS_NO_INT  4
-#define IM_RESET_FINISHED_OK_NO_INT      5
-
-/* define undefined SCSI-command */
-#define NO_SCSI                  0xffff
-
-/*-----------------------------------------------------------------------*/
-
-/* if this is nonzero, ibmmcascsi option has been passed to the kernel */
-static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 };
-
-/* fill module-parameters only, when this define is present.
-   (that is kernel version 2.1.x) */
-#if defined(MODULE)
-static char *boot_options = NULL;
-module_param(boot_options, charp, 0);
-module_param_array(io_port, int, NULL, 0);
-module_param_array(scsi_id, int, NULL, 0);
-
-MODULE_LICENSE("GPL");
-#endif
-/*counter of concurrent disk read/writes, to turn on/off disk led */
-static int disk_rw_in_progress = 0;
-
-static unsigned int pos[8];	/* whole pos register-line for diagnosis */
-/* Taking into account the additions, made by ZP Gu.
- * This selects now the preset value from the configfile and
- * offers the 'normal' commandline option to be accepted */
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-static char ibm_ansi_order = 1;
-#else
-static char ibm_ansi_order = 0;
-#endif
-
-static void issue_cmd(struct Scsi_Host *, unsigned long, unsigned char);
-static void internal_done(Scsi_Cmnd * cmd);
-static void check_devices(struct Scsi_Host *, int);
-static int immediate_assign(struct Scsi_Host *, unsigned int, unsigned int, unsigned int, unsigned int);
-static int immediate_feature(struct Scsi_Host *, unsigned int, unsigned int);
-#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-static int immediate_reset(struct Scsi_Host *, unsigned int);
-#endif
-static int device_inquiry(struct Scsi_Host *, int);
-static int read_capacity(struct Scsi_Host *, int);
-static int get_pos_info(struct Scsi_Host *);
-static char *ti_p(int);
-static char *ti_l(int);
-static char *ibmrate(unsigned int, int);
-static int probe_display(int);
-static int probe_bus_mode(struct Scsi_Host *);
-static int device_exists(struct Scsi_Host *, int, int *, int *);
-static int option_setup(char *);
-/* local functions needed for proc_info */
-static int ldn_access_load(struct Scsi_Host *, int);
-static int ldn_access_total_read_write(struct Scsi_Host *);
-
-static irqreturn_t interrupt_handler(int irq, void *dev_id)
-{
-	unsigned int intr_reg;
-	unsigned int cmd_result;
-	unsigned int ldn;
-	unsigned long flags;
-	Scsi_Cmnd *cmd;
-	int lastSCSI;
-	struct device *dev = dev_id;
-	struct Scsi_Host *shpnt = dev_get_drvdata(dev);
-
-	spin_lock_irqsave(shpnt->host_lock, flags);
-
-	if(!(inb(IM_STAT_REG(shpnt)) & IM_INTR_REQUEST)) {
-		spin_unlock_irqrestore(shpnt->host_lock, flags);
-		return IRQ_NONE;
-	}
-
-	/* the reset-function already did all the job, even ints got
-	   renabled on the subsystem, so just return */
-	if ((reset_status(shpnt) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(shpnt) == IM_RESET_FINISHED_OK_NO_INT)) {
-		reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS;
-		spin_unlock_irqrestore(shpnt->host_lock, flags);
-		return IRQ_HANDLED;
-	}
-
-	/*must wait for attention reg not busy, then send EOI to subsystem */
-	while (1) {
-		if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
-			break;
-		cpu_relax();
-	}
-
-	/*get command result and logical device */
-	intr_reg = (unsigned char) (inb(IM_INTR_REG(shpnt)));
-	cmd_result = intr_reg & 0xf0;
-	ldn = intr_reg & 0x0f;
-	/* get the last_scsi_command here */
-	lastSCSI = last_scsi_command(shpnt)[ldn];
-	outb(IM_EOI | ldn, IM_ATTN_REG(shpnt));
-	
-	/*these should never happen (hw fails, or a local programming bug) */
-	if (!global_command_error_excuse) {
-		switch (cmd_result) {
-			/* Prevent from Ooopsing on error to show the real reason */
-		case IM_ADAPTER_HW_FAILURE:
-		case IM_SOFTWARE_SEQUENCING_ERROR:
-		case IM_CMD_ERROR:
-			printk(KERN_ERR "IBM MCA SCSI: Fatal Subsystem ERROR!\n");
-			printk(KERN_ERR "              Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(shpnt)[ldn].scb.enable);
-			if (ld(shpnt)[ldn].cmd)
-				printk("%ld/%ld,", (long) (scsi_bufflen(ld(shpnt)[ldn].cmd)), (long) (ld(shpnt)[ldn].scb.sys_buf_length));
-			else
-				printk("none,");
-			if (ld(shpnt)[ldn].cmd)
-				printk("Blocksize=%d", ld(shpnt)[ldn].scb.u2.blk.length);
-			else
-				printk("Blocksize=none");
-			printk(", host=%p, ldn=0x%x\n", shpnt, ldn);
-			if (ld(shpnt)[ldn].cmd) {
-				printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(shpnt)[ldn], ld(shpnt)[ldn].scb.u2.blk.count);
-				printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(shpnt)[ldn], ld(shpnt)[ldn].scb.u1.log_blk_adr);
-			}
-			printk(KERN_ERR "Reason given: %s\n", (cmd_result == IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : (cmd_result == IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");
-			/* if errors appear, enter this section to give detailed info */
-			printk(KERN_ERR "IBM MCA SCSI: Subsystem Error-Status follows:\n");
-			printk(KERN_ERR "              Command Type................: %x\n", last_scsi_type(shpnt)[ldn]);
-			printk(KERN_ERR "              Attention Register..........: %x\n", inb(IM_ATTN_REG(shpnt)));
-			printk(KERN_ERR "              Basic Control Register......: %x\n", inb(IM_CTR_REG(shpnt)));
-			printk(KERN_ERR "              Interrupt Status Register...: %x\n", intr_reg);
-			printk(KERN_ERR "              Basic Status Register.......: %x\n", inb(IM_STAT_REG(shpnt)));
-			if ((last_scsi_type(shpnt)[ldn] == IM_SCB) || (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB)) {
-				printk(KERN_ERR "              SCB-Command.................: %x\n", ld(shpnt)[ldn].scb.command);
-				printk(KERN_ERR "              SCB-Enable..................: %x\n", ld(shpnt)[ldn].scb.enable);
-				printk(KERN_ERR "              SCB-logical block address...: %lx\n", ld(shpnt)[ldn].scb.u1.log_blk_adr);
-				printk(KERN_ERR "              SCB-system buffer address...: %lx\n", ld(shpnt)[ldn].scb.sys_buf_adr);
-				printk(KERN_ERR "              SCB-system buffer length....: %lx\n", ld(shpnt)[ldn].scb.sys_buf_length);
-				printk(KERN_ERR "              SCB-tsb address.............: %lx\n", ld(shpnt)[ldn].scb.tsb_adr);
-				printk(KERN_ERR "              SCB-Chain address...........: %lx\n", ld(shpnt)[ldn].scb.scb_chain_adr);
-				printk(KERN_ERR "              SCB-block count.............: %x\n", ld(shpnt)[ldn].scb.u2.blk.count);
-				printk(KERN_ERR "              SCB-block length............: %x\n", ld(shpnt)[ldn].scb.u2.blk.length);
-			}
-			printk(KERN_ERR "              Send this report to the maintainer.\n");
-			panic("IBM MCA SCSI: Fatal error message from the subsystem (0x%X,0x%X)!\n", lastSCSI, cmd_result);
-			break;
-		}
-	} else {
-		/* The command error handling is made silent, but we tell the
-		 * calling function, that there is a reported error from the
-		 * adapter. */
-		switch (cmd_result) {
-		case IM_ADAPTER_HW_FAILURE:
-		case IM_SOFTWARE_SEQUENCING_ERROR:
-		case IM_CMD_ERROR:
-			global_command_error_excuse = CMD_FAIL;
-			break;
-		default:
-			global_command_error_excuse = 0;
-			break;
-		}
-	}
-	/* if no panic appeared, increase the interrupt-counter */
-	IBM_DS(shpnt).total_interrupts++;
-	/*only for local checking phase */
-	if (local_checking_phase_flag(shpnt)) {
-		stat_result(shpnt) = cmd_result;
-		got_interrupt(shpnt) = 1;
-		reset_status(shpnt) = IM_RESET_FINISHED_OK;
-		last_scsi_command(shpnt)[ldn] = NO_SCSI;
-		spin_unlock_irqrestore(shpnt->host_lock, flags);
-		return IRQ_HANDLED;
-	}
-	/* handling of commands coming from upper level of scsi driver */
-	if (last_scsi_type(shpnt)[ldn] == IM_IMM_CMD) {
-		/* verify ldn, and may handle rare reset immediate command */
-		if ((reset_status(shpnt) == IM_RESET_IN_PROGRESS) && (last_scsi_command(shpnt)[ldn] == IM_RESET_IMM_CMD)) {
-			if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
-				disk_rw_in_progress = 0;
-				PS2_DISK_LED_OFF();
-				reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
-			} else {
-				/*reset disk led counter, turn off disk led */
-				disk_rw_in_progress = 0;
-				PS2_DISK_LED_OFF();
-				reset_status(shpnt) = IM_RESET_FINISHED_OK;
-			}
-			stat_result(shpnt) = cmd_result;
-			last_scsi_command(shpnt)[ldn] = NO_SCSI;
-			last_scsi_type(shpnt)[ldn] = 0;
-			spin_unlock_irqrestore(shpnt->host_lock, flags);
-			return IRQ_HANDLED;
-		} else if (last_scsi_command(shpnt)[ldn] == IM_ABORT_IMM_CMD) {
-			/* react on SCSI abort command */
-#ifdef IM_DEBUG_PROBE
-			printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
-#endif
-			disk_rw_in_progress = 0;
-			PS2_DISK_LED_OFF();
-			cmd = ld(shpnt)[ldn].cmd;
-			ld(shpnt)[ldn].cmd = NULL;
-			if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
-				cmd->result = DID_NO_CONNECT << 16;
-			else
-				cmd->result = DID_ABORT << 16;
-			stat_result(shpnt) = cmd_result;
-			last_scsi_command(shpnt)[ldn] = NO_SCSI;
-			last_scsi_type(shpnt)[ldn] = 0;
-			if (cmd->scsi_done)
-				(cmd->scsi_done) (cmd);	/* should be the internal_done */
-			spin_unlock_irqrestore(shpnt->host_lock, flags);
-			return IRQ_HANDLED;
-		} else {
-			disk_rw_in_progress = 0;
-			PS2_DISK_LED_OFF();
-			reset_status(shpnt) = IM_RESET_FINISHED_OK;
-			stat_result(shpnt) = cmd_result;
-			last_scsi_command(shpnt)[ldn] = NO_SCSI;
-			spin_unlock_irqrestore(shpnt->host_lock, flags);
-			return IRQ_HANDLED;
-		}
-	}
-	last_scsi_command(shpnt)[ldn] = NO_SCSI;
-	last_scsi_type(shpnt)[ldn] = 0;
-	cmd = ld(shpnt)[ldn].cmd;
-	ld(shpnt)[ldn].cmd = NULL;
-#ifdef IM_DEBUG_TIMEOUT
-	if (cmd) {
-		if ((cmd->target == TIMEOUT_PUN) && (cmd->device->lun == TIMEOUT_LUN)) {
-			spin_unlock_irqsave(shpnt->host_lock, flags);
-			printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", cmd->target, cmd->device->lun);
-			return IRQ_HANDLED;
-		}
-	}
-#endif
-	/*if no command structure, just return, else clear cmd */
-	if (!cmd)
-	{
-		spin_unlock_irqrestore(shpnt->host_lock, flags);
-		return IRQ_HANDLED;
-	}
-
-#ifdef IM_DEBUG_INT
-	printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(shpnt)[ldn].tsb.dev_status, ld(shpnt)[ldn].tsb.cmd_status, ld(shpnt)[ldn].tsb.dev_error, ld(shpnt)[ldn].tsb.cmd_error);
-#endif
-	/*if this is end of media read/write, may turn off PS/2 disk led */
-	if ((ld(shpnt)[ldn].device_type != TYPE_NO_LUN) && (ld(shpnt)[ldn].device_type != TYPE_NO_DEVICE)) {
-		/* only access this, if there was a valid device addressed */
-		if (--disk_rw_in_progress == 0)
-			PS2_DISK_LED_OFF();
-	}
-
-	/* IBM describes the status-mask to be 0x1e, but this is not conform
-	 * with SCSI-definition, I suppose, the reason for it is that IBM
-	 * adapters do not support CMD_TERMINATED, TASK_SET_FULL and
-	 * ACA_ACTIVE as returning statusbyte information. (ML) */
-	if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
-		cmd->result = (unsigned char) (ld(shpnt)[ldn].tsb.dev_status & 0x1e);
-		IBM_DS(shpnt).total_errors++;
-	} else
-		cmd->result = 0;
-	/* write device status into cmd->result, and call done function */
-	if (lastSCSI == NO_SCSI) {	/* unexpected interrupt :-( */
-		cmd->result |= DID_BAD_INTR << 16;
-		printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n");
-	} else			/* things went right :-) */
-		cmd->result |= DID_OK << 16;
-	if (cmd->scsi_done)
-		(cmd->scsi_done) (cmd);
-	spin_unlock_irqrestore(shpnt->host_lock, flags);
-	return IRQ_HANDLED;
-}
-
-static void issue_cmd(struct Scsi_Host *shpnt, unsigned long cmd_reg,
-		      unsigned char attn_reg)
-{
-	unsigned long flags;
-	/* must wait for attention reg not busy */
-	while (1) {
-		spin_lock_irqsave(shpnt->host_lock, flags);
-		if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
-			break;
-		spin_unlock_irqrestore(shpnt->host_lock, flags);
-	}
-	/* write registers and enable system interrupts */
-	outl(cmd_reg, IM_CMD_REG(shpnt));
-	outb(attn_reg, IM_ATTN_REG(shpnt));
-	spin_unlock_irqrestore(shpnt->host_lock, flags);
-}
-
-static void internal_done(Scsi_Cmnd * cmd)
-{
-	cmd->SCp.Status++;
-	return;
-}
-
-/* SCSI-SCB-command for device_inquiry */
-static int device_inquiry(struct Scsi_Host *shpnt, int ldn)
-{
-	int retr;
-	struct im_scb *scb;
-	struct im_tsb *tsb;
-	unsigned char *buf;
-
-	scb = &(ld(shpnt)[ldn].scb);
-	tsb = &(ld(shpnt)[ldn].tsb);
-	buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
-	ld(shpnt)[ldn].tsb.dev_status = 0;	/* prepare statusblock */
-	for (retr = 0; retr < 3; retr++) {
-		/* fill scb with inquiry command */
-		scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT;
-		scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
-		last_scsi_command(shpnt)[ldn] = IM_DEVICE_INQUIRY_CMD;
-		last_scsi_type(shpnt)[ldn] = IM_SCB;
-		scb->sys_buf_adr = isa_virt_to_bus(buf);
-		scb->sys_buf_length = 255;	/* maximum bufferlength gives max info */
-		scb->tsb_adr = isa_virt_to_bus(tsb);
-		/* issue scb to passed ldn, and busy wait for interrupt */
-		got_interrupt(shpnt) = 0;
-		issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
-		while (!got_interrupt(shpnt))
-			barrier();
-
-		/*if command successful, break */
-		if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
-			return 1;
-	}
-	/*if all three retries failed, return "no device at this ldn" */
-	if (retr >= 3)
-		return 0;
-	else
-		return 1;
-}
-
-static int read_capacity(struct Scsi_Host *shpnt, int ldn)
-{
-	int retr;
-	struct im_scb *scb;
-	struct im_tsb *tsb;
-	unsigned char *buf;
-
-	scb = &(ld(shpnt)[ldn].scb);
-	tsb = &(ld(shpnt)[ldn].tsb);
-	buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
-	ld(shpnt)[ldn].tsb.dev_status = 0;
-	for (retr = 0; retr < 3; retr++) {
-		/*fill scb with read capacity command */
-		scb->command = IM_READ_CAPACITY_CMD;
-		scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
-		last_scsi_command(shpnt)[ldn] = IM_READ_CAPACITY_CMD;
-		last_scsi_type(shpnt)[ldn] = IM_SCB;
-		scb->sys_buf_adr = isa_virt_to_bus(buf);
-		scb->sys_buf_length = 8;
-		scb->tsb_adr = isa_virt_to_bus(tsb);
-		/*issue scb to passed ldn, and busy wait for interrupt */
-		got_interrupt(shpnt) = 0;
-		issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
-		while (!got_interrupt(shpnt))
-			barrier();
-
-		/*if got capacity, get block length and return one device found */
-		if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
-			return 1;
-	}
-	/*if all three retries failed, return "no device at this ldn" */
-	if (retr >= 3)
-		return 0;
-	else
-		return 1;
-}
-
-static int get_pos_info(struct Scsi_Host *shpnt)
-{
-	int retr;
-	struct im_scb *scb;
-	struct im_tsb *tsb;
-	unsigned char *buf;
-
-	scb = &(ld(shpnt)[MAX_LOG_DEV].scb);
-	tsb = &(ld(shpnt)[MAX_LOG_DEV].tsb);
-	buf = (unsigned char *) (&(ld(shpnt)[MAX_LOG_DEV].buf));
-	ld(shpnt)[MAX_LOG_DEV].tsb.dev_status = 0;
-	for (retr = 0; retr < 3; retr++) {
-		/*fill scb with get_pos_info command */
-		scb->command = IM_GET_POS_INFO_CMD;
-		scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
-		last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
-		last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_SCB;
-		scb->sys_buf_adr = isa_virt_to_bus(buf);
-		if (special(shpnt) == IBM_SCSI2_FW)
-			scb->sys_buf_length = 256;	/* get all info from F/W adapter */
-		else
-			scb->sys_buf_length = 18;	/* get exactly 18 bytes for other SCSI */
-		scb->tsb_adr = isa_virt_to_bus(tsb);
-		/*issue scb to ldn=15, and busy wait for interrupt */
-		got_interrupt(shpnt) = 0;
-		issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
-		
-		/* FIXME: timeout */
-		while (!got_interrupt(shpnt))
-			barrier();
-
-		/*if got POS-stuff, get block length and return one device found */
-		if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
-			return 1;
-	}
-	/* if all three retries failed, return "no device at this ldn" */
-	if (retr >= 3)
-		return 0;
-	else
-		return 1;
-}
-
-/* SCSI-immediate-command for assign. This functions maps/unmaps specific
- ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
- subsystem and for dynamical remapping od ldns. */
-static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun,
-			    unsigned int lun, unsigned int ldn,
-			    unsigned int operation)
-{
-	int retr;
-	unsigned long imm_cmd;
-
-	for (retr = 0; retr < 3; retr++) {
-		/* select mutation level of the SCSI-adapter */
-		switch (special(shpnt)) {
-		case IBM_SCSI2_FW:
-			imm_cmd = (unsigned long) (IM_ASSIGN_IMM_CMD);
-			imm_cmd |= (unsigned long) ((lun & 7) << 24);
-			imm_cmd |= (unsigned long) ((operation & 1) << 23);
-			imm_cmd |= (unsigned long) ((pun & 7) << 20) | ((pun & 8) << 24);
-			imm_cmd |= (unsigned long) ((ldn & 15) << 16);
-			break;
-		default:
-			imm_cmd = inl(IM_CMD_REG(shpnt));
-			imm_cmd &= (unsigned long) (0xF8000000);	/* keep reserved bits */
-			imm_cmd |= (unsigned long) (IM_ASSIGN_IMM_CMD);
-			imm_cmd |= (unsigned long) ((lun & 7) << 24);
-			imm_cmd |= (unsigned long) ((operation & 1) << 23);
-			imm_cmd |= (unsigned long) ((pun & 7) << 20);
-			imm_cmd |= (unsigned long) ((ldn & 15) << 16);
-			break;
-		}
-		last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
-		last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD;
-		got_interrupt(shpnt) = 0;
-		issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
-		while (!got_interrupt(shpnt))
-			barrier();
-
-		/*if command successful, break */
-		if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
-			return 1;
-	}
-	if (retr >= 3)
-		return 0;
-	else
-		return 1;
-}
-
-static int immediate_feature(struct Scsi_Host *shpnt, unsigned int speed, unsigned int timeout)
-{
-	int retr;
-	unsigned long imm_cmd;
-
-	for (retr = 0; retr < 3; retr++) {
-		/* select mutation level of the SCSI-adapter */
-		imm_cmd = IM_FEATURE_CTR_IMM_CMD;
-		imm_cmd |= (unsigned long) ((speed & 0x7) << 29);
-		imm_cmd |= (unsigned long) ((timeout & 0x1fff) << 16);
-		last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
-		last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD;
-		got_interrupt(shpnt) = 0;
-		/* we need to run into command errors in order to probe for the
-		 * right speed! */
-		global_command_error_excuse = 1;
-		issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
-		
-		/* FIXME: timeout */
-		while (!got_interrupt(shpnt))
-			barrier();
-		if (global_command_error_excuse == CMD_FAIL) {
-			global_command_error_excuse = 0;
-			return 2;
-		} else
-			global_command_error_excuse = 0;
-		/*if command successful, break */
-		if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
-			return 1;
-	}
-	if (retr >= 3)
-		return 0;
-	else
-		return 1;
-}
-
-#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-static int immediate_reset(struct Scsi_Host *shpnt, unsigned int ldn)
-{
-	int retries;
-	int ticks;
-	unsigned long imm_command;
-
-	for (retries = 0; retries < 3; retries++) {
-		imm_command = inl(IM_CMD_REG(shpnt));
-		imm_command &= (unsigned long) (0xFFFF0000);	/* keep reserved bits */
-		imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
-		last_scsi_command(shpnt)[ldn] = IM_RESET_IMM_CMD;
-		last_scsi_type(shpnt)[ldn] = IM_IMM_CMD;
-		got_interrupt(shpnt) = 0;
-		reset_status(shpnt) = IM_RESET_IN_PROGRESS;
-		issue_cmd(shpnt, (unsigned long) (imm_command), IM_IMM_CMD | ldn);
-		ticks = IM_RESET_DELAY * HZ;
-		while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks) {
-			udelay((1 + 999 / HZ) * 1000);
-			barrier();
-		}
-		/* if reset did not complete, just complain */
-		if (!ticks) {
-			printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
-			reset_status(shpnt) = IM_RESET_FINISHED_OK;
-			/* did not work, finish */
-			return 1;
-		}
-		/*if command successful, break */
-		if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
-			return 1;
-	}
-	if (retries >= 3)
-		return 0;
-	else
-		return 1;
-}
-#endif
-
-/* type-interpreter for physical device numbers */
-static char *ti_p(int dev)
-{
-	switch (dev) {
-	case TYPE_IBM_SCSI_ADAPTER:
-		return ("A");
-	case TYPE_DISK:
-		return ("D");
-	case TYPE_TAPE:
-		return ("T");
-	case TYPE_PROCESSOR:
-		return ("P");
-	case TYPE_WORM:
-		return ("W");
-	case TYPE_ROM:
-		return ("R");
-	case TYPE_SCANNER:
-		return ("S");
-	case TYPE_MOD:
-		return ("M");
-	case TYPE_MEDIUM_CHANGER:
-		return ("C");
-	case TYPE_NO_LUN:
-		return ("+");	/* show NO_LUN */
-	}
-	return ("-");		/* TYPE_NO_DEVICE and others */
-}
-
-/* interpreter for logical device numbers (ldn) */
-static char *ti_l(int val)
-{
-	const char hex[16] = "0123456789abcdef";
-	static char answer[2];
-
-	answer[1] = (char) (0x0);
-	if (val <= MAX_LOG_DEV)
-		answer[0] = hex[val];
-	else
-		answer[0] = '-';
-	return (char *) &answer;
-}
-
-/* transfers bitpattern of the feature command to values in MHz */
-static char *ibmrate(unsigned int speed, int i)
-{
-	switch (speed) {
-	case 0:
-		return i ? "5.00" : "10.00";
-	case 1:
-		return i ? "4.00" : "8.00";
-	case 2:
-		return i ? "3.33" : "6.66";
-	case 3:
-		return i ? "2.86" : "5.00";
-	case 4:
-		return i ? "2.50" : "4.00";
-	case 5:
-		return i ? "2.22" : "3.10";
-	case 6:
-		return i ? "2.00" : "2.50";
-	case 7:
-		return i ? "1.82" : "2.00";
-	}
-	return "---";
-}
-
-static int probe_display(int what)
-{
-	static int rotator = 0;
-	const char rotor[] = "|/-\\";
-
-	if (!(display_mode & LED_DISP))
-		return 0;
-	if (!what) {
-		outl(0x20202020, MOD95_LED_PORT);
-		outl(0x20202020, MOD95_LED_PORT + 4);
-	} else {
-		outb('S', MOD95_LED_PORT + 7);
-		outb('C', MOD95_LED_PORT + 6);
-		outb('S', MOD95_LED_PORT + 5);
-		outb('I', MOD95_LED_PORT + 4);
-		outb('i', MOD95_LED_PORT + 3);
-		outb('n', MOD95_LED_PORT + 2);
-		outb('i', MOD95_LED_PORT + 1);
-		outb((char) (rotor[rotator]), MOD95_LED_PORT);
-		rotator++;
-		if (rotator > 3)
-			rotator = 0;
-	}
-	return 0;
-}
-
-static int probe_bus_mode(struct Scsi_Host *shpnt)
-{
-	struct im_pos_info *info;
-	int num_bus = 0;
-	int ldn;
-
-	info = (struct im_pos_info *) (&(ld(shpnt)[MAX_LOG_DEV].buf));
-	if (get_pos_info(shpnt)) {
-		if (info->connector_size & 0xf000)
-			subsystem_connector_size(shpnt) = 16;
-		else
-			subsystem_connector_size(shpnt) = 32;
-		num_bus |= (info->pos_4b & 8) >> 3;
-		for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
-			if ((special(shpnt) == IBM_SCSI_WCACHE) || (special(shpnt) == IBM_7568_WCACHE)) {
-				if (!((info->cache_stat >> ldn) & 1))
-					ld(shpnt)[ldn].cache_flag = 0;
-			}
-			if (!((info->retry_stat >> ldn) & 1))
-				ld(shpnt)[ldn].retry_flag = 0;
-		}
-#ifdef IM_DEBUG_PROBE
-		printk("IBM MCA SCSI: SCSI-Cache bits: ");
-		for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
-			printk("%d", ld(shpnt)[ldn].cache_flag);
-		}
-		printk("\nIBM MCA SCSI: SCSI-Retry bits: ");
-		for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
-			printk("%d", ld(shpnt)[ldn].retry_flag);
-		}
-		printk("\n");
-#endif
-	}
-	return num_bus;
-}
-
-/* probing scsi devices */
-static void check_devices(struct Scsi_Host *shpnt, int adaptertype)
-{
-	int id, lun, ldn, ticks;
-	int count_devices;	/* local counter for connected device */
-	int max_pun;
-	int num_bus;
-	int speedrun;		/* local adapter_speed check variable */
-
-	/* assign default values to certain variables */
-	ticks = 0;
-	count_devices = 0;
-	IBM_DS(shpnt).dyn_flag = 0;	/* normally no need for dynamical ldn management */
-	IBM_DS(shpnt).total_errors = 0;	/* set errorcounter to 0 */
-	next_ldn(shpnt) = 7;	/* next ldn to be assigned is 7, because 0-6 is 'hardwired' */
-
-	/* initialize the very important driver-informational arrays/structs */
-	memset(ld(shpnt), 0, sizeof(ld(shpnt)));
-	for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
-		last_scsi_command(shpnt)[ldn] = NO_SCSI;	/* emptify last SCSI-command storage */
-		last_scsi_type(shpnt)[ldn] = 0;
-		ld(shpnt)[ldn].cache_flag = 1;
-		ld(shpnt)[ldn].retry_flag = 1;
-	}
-	memset(get_ldn(shpnt), TYPE_NO_DEVICE, sizeof(get_ldn(shpnt)));	/* this is essential ! */
-	memset(get_scsi(shpnt), TYPE_NO_DEVICE, sizeof(get_scsi(shpnt)));	/* this is essential ! */
-	for (lun = 0; lun < 8; lun++) {
-		/* mark the adapter at its pun on all luns */
-		get_scsi(shpnt)[subsystem_pun(shpnt)][lun] = TYPE_IBM_SCSI_ADAPTER;
-		get_ldn(shpnt)[subsystem_pun(shpnt)][lun] = MAX_LOG_DEV;	/* make sure, the subsystem
-											   ldn is active for all
-											   luns. */
-	}
-	probe_display(0);	/* Supercool display usage during SCSI-probing. */
-	/* This makes sense, when booting without any */
-	/* monitor connected on model XX95. */
-
-	/* STEP 1: */
-	adapter_speed(shpnt) = global_adapter_speed;
-	speedrun = adapter_speed(shpnt);
-	while (immediate_feature(shpnt, speedrun, adapter_timeout) == 2) {
-		probe_display(1);
-		if (speedrun == 7)
-			panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n");
-		speedrun++;
-		if (speedrun > 7)
-			speedrun = 7;
-	}
-	adapter_speed(shpnt) = speedrun;
-	/* Get detailed information about the current adapter, necessary for
-	 * device operations: */
-	num_bus = probe_bus_mode(shpnt);
-
-	/* num_bus contains only valid data for the F/W adapter! */
-	if (adaptertype == IBM_SCSI2_FW) {	/* F/W SCSI adapter: */
-		/* F/W adapter PUN-space extension evaluation: */
-		if (num_bus) {
-			printk(KERN_INFO "IBM MCA SCSI: Separate bus mode (wide-addressing enabled)\n");
-			subsystem_maxid(shpnt) = 16;
-		} else {
-			printk(KERN_INFO "IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n");
-			subsystem_maxid(shpnt) = 8;
-		}
-		printk(KERN_INFO "IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n", ibmrate(speedrun, adaptertype));
-	} else			/* all other IBM SCSI adapters: */
-		printk(KERN_INFO "IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n", ibmrate(speedrun, adaptertype));
-
-	/* assign correct PUN device space */
-	max_pun = subsystem_maxid(shpnt);
-
-#ifdef IM_DEBUG_PROBE
-	printk("IBM MCA SCSI: Current SCSI-host index: %d\n", shpnt);
-	printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
-#else
-	printk(KERN_INFO "IBM MCA SCSI: Dev. Order: %s, Mapping (takes <2min): ", (ibm_ansi_order) ? "ANSI" : "New");
-#endif
-	for (ldn = 0; ldn < MAX_LOG_DEV; ldn++) {
-		probe_display(1);
-#ifdef IM_DEBUG_PROBE
-		printk(".");
-#endif
-		immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN);	/* remove ldn (wherever) */
-	}
-	lun = 0;		/* default lun is 0 */
-#ifndef IM_DEBUG_PROBE
-	printk("cleared,");
-#endif
-	/* STEP 2: */
-#ifdef IM_DEBUG_PROBE
-	printk("\nIBM MCA SCSI: Scanning SCSI-devices.");
-#endif
-	for (id = 0; id < max_pun; id++)
-#ifdef CONFIG_SCSI_MULTI_LUN
-		for (lun = 0; lun < 8; lun++)
-#endif
-		{
-			probe_display(1);
-#ifdef IM_DEBUG_PROBE
-			printk(".");
-#endif
-			if (id != subsystem_pun(shpnt)) {
-				/* if pun is not the adapter: */
-				/* set ldn=0 to pun,lun */
-				immediate_assign(shpnt, id, lun, PROBE_LDN, SET_LDN);
-				if (device_inquiry(shpnt, PROBE_LDN)) {	/* probe device */
-					get_scsi(shpnt)[id][lun] = (unsigned char) (ld(shpnt)[PROBE_LDN].buf[0]);
-					/* entry, even for NO_LUN */
-					if (ld(shpnt)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
-						count_devices++;	/* a existing device is found */
-				}
-				/* remove ldn */
-				immediate_assign(shpnt, id, lun, PROBE_LDN, REMOVE_LDN);
-			}
-		}
-#ifndef IM_DEBUG_PROBE
-	printk("scanned,");
-#endif
-	/* STEP 3: */
-#ifdef IM_DEBUG_PROBE
-	printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
-#endif
-	ldn = 0;
-	lun = 0;
-#ifdef CONFIG_SCSI_MULTI_LUN
-	for (lun = 0; lun < 8 && ldn < MAX_LOG_DEV; lun++)
-#endif
-		for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
-			probe_display(1);
-#ifdef IM_DEBUG_PROBE
-			printk(".");
-#endif
-			if (id != subsystem_pun(shpnt)) {
-				if (get_scsi(shpnt)[id][lun] != TYPE_NO_LUN && get_scsi(shpnt)[id][lun] != TYPE_NO_DEVICE) {
-					/* Only map if accepted type. Always enter for
-					   lun == 0 to get no gaps into ldn-mapping for ldn<7. */
-					immediate_assign(shpnt, id, lun, ldn, SET_LDN);
-					get_ldn(shpnt)[id][lun] = ldn;	/* map ldn */
-					if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) {
-#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-						printk("resetting device at ldn=%x ... ", ldn);
-						immediate_reset(shpnt, ldn);
-#endif
-						ldn++;
-					} else {
-						/* device vanished, probably because we don't know how to
-						 * handle it or because it has problems */
-						if (lun > 0) {
-							/* remove mapping */
-							get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE;
-							immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN);
-						} else
-							ldn++;
-					}
-				} else if (lun == 0) {
-					/* map lun == 0, even if no device exists */
-					immediate_assign(shpnt, id, lun, ldn, SET_LDN);
-					get_ldn(shpnt)[id][lun] = ldn;	/* map ldn */
-					ldn++;
-				}
-			}
-		}
-	/* STEP 4: */
-
-	/* map remaining ldns to non-existing devices */
-	for (lun = 1; lun < 8 && ldn < MAX_LOG_DEV; lun++)
-		for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
-			if (get_scsi(shpnt)[id][lun] == TYPE_NO_LUN || get_scsi(shpnt)[id][lun] == TYPE_NO_DEVICE) {
-				probe_display(1);
-				/* Map remaining ldns only to NON-existing pun,lun
-				   combinations to make sure an inquiry will fail.
-				   For MULTI_LUN, it is needed to avoid adapter autonome
-				   SCSI-remapping. */
-				immediate_assign(shpnt, id, lun, ldn, SET_LDN);
-				get_ldn(shpnt)[id][lun] = ldn;
-				ldn++;
-			}
-		}
-#ifndef IM_DEBUG_PROBE
-	printk("mapped.");
-#endif
-	printk("\n");
-#ifdef IM_DEBUG_PROBE
-	if (ibm_ansi_order)
-		printk("IBM MCA SCSI: Device order: IBM/ANSI (pun=7 is first).\n");
-	else
-		printk("IBM MCA SCSI: Device order: New Industry Standard (pun=0 is first).\n");
-#endif
-
-#ifdef IM_DEBUG_PROBE
-	/* Show the physical and logical mapping during boot. */
-	printk("IBM MCA SCSI: Determined SCSI-device-mapping:\n");
-	printk("    Physical SCSI-Device Map               Logical SCSI-Device Map\n");
-	printk("ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
-	for (id = 0; id < max_pun; id++) {
-		printk("%2d     ", id);
-		for (lun = 0; lun < 8; lun++)
-			printk("%2s ", ti_p(get_scsi(shpnt)[id][lun]));
-		printk("      %2d     ", id);
-		for (lun = 0; lun < 8; lun++)
-			printk("%2s ", ti_l(get_ldn(shpnt)[id][lun]));
-		printk("\n");
-	}
-#endif
-
-	/* assign total number of found SCSI-devices to the statistics struct */
-	IBM_DS(shpnt).total_scsi_devices = count_devices;
-
-	/* decide for output in /proc-filesystem, if the configuration of
-	   SCSI-devices makes dynamical reassignment of devices necessary */
-	if (count_devices >= MAX_LOG_DEV)
-		IBM_DS(shpnt).dyn_flag = 1;	/* dynamical assignment is necessary */
-	else
-		IBM_DS(shpnt).dyn_flag = 0;	/* dynamical assignment is not necessary */
-
-	/* If no SCSI-devices are assigned, return 1 in order to cause message. */
-	if (ldn == 0)
-		printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
-
-	/* reset the counters for statistics on the current adapter */
-	IBM_DS(shpnt).scbs = 0;
-	IBM_DS(shpnt).long_scbs = 0;
-	IBM_DS(shpnt).total_accesses = 0;
-	IBM_DS(shpnt).total_interrupts = 0;
-	IBM_DS(shpnt).dynamical_assignments = 0;
-	memset(IBM_DS(shpnt).ldn_access, 0x0, sizeof(IBM_DS(shpnt).ldn_access));
-	memset(IBM_DS(shpnt).ldn_read_access, 0x0, sizeof(IBM_DS(shpnt).ldn_read_access));
-	memset(IBM_DS(shpnt).ldn_write_access, 0x0, sizeof(IBM_DS(shpnt).ldn_write_access));
-	memset(IBM_DS(shpnt).ldn_inquiry_access, 0x0, sizeof(IBM_DS(shpnt).ldn_inquiry_access));
-	memset(IBM_DS(shpnt).ldn_modeselect_access, 0x0, sizeof(IBM_DS(shpnt).ldn_modeselect_access));
-	memset(IBM_DS(shpnt).ldn_assignments, 0x0, sizeof(IBM_DS(shpnt).ldn_assignments));
-	probe_display(0);
-	return;
-}
-
-static int device_exists(struct Scsi_Host *shpnt, int ldn, int *block_length, int *device_type)
-{
-	unsigned char *buf;
-	/* if no valid device found, return immediately with 0 */
-	if (!(device_inquiry(shpnt, ldn)))
-		return 0;
-	buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
-	if (*buf == TYPE_ROM) {
-		*device_type = TYPE_ROM;
-		*block_length = 2048;	/* (standard blocksize for yellow-/red-book) */
-		return 1;
-	}
-	if (*buf == TYPE_WORM) {
-		*device_type = TYPE_WORM;
-		*block_length = 2048;
-		return 1;
-	}
-	if (*buf == TYPE_DISK) {
-		*device_type = TYPE_DISK;
-		if (read_capacity(shpnt, ldn)) {
-			*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
-			return 1;
-		} else
-			return 0;
-	}
-	if (*buf == TYPE_MOD) {
-		*device_type = TYPE_MOD;
-		if (read_capacity(shpnt, ldn)) {
-			*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
-			return 1;
-		} else
-			return 0;
-	}
-	if (*buf == TYPE_TAPE) {
-		*device_type = TYPE_TAPE;
-		*block_length = 0;	/* not in use (setting by mt and mtst in op.) */
-		return 1;
-	}
-	if (*buf == TYPE_PROCESSOR) {
-		*device_type = TYPE_PROCESSOR;
-		*block_length = 0;	/* they set their stuff on drivers */
-		return 1;
-	}
-	if (*buf == TYPE_SCANNER) {
-		*device_type = TYPE_SCANNER;
-		*block_length = 0;	/* they set their stuff on drivers */
-		return 1;
-	}
-	if (*buf == TYPE_MEDIUM_CHANGER) {
-		*device_type = TYPE_MEDIUM_CHANGER;
-		*block_length = 0;	/* One never knows, what to expect on a medium
-					   changer device. */
-		return 1;
-	}
-	return 0;
-}
-
-static void internal_ibmmca_scsi_setup(char *str, int *ints)
-{
-	int i, j, io_base, id_base;
-	char *token;
-
-	io_base = 0;
-	id_base = 0;
-	if (str) {
-		j = 0;
-		while ((token = strsep(&str, ",")) != NULL) {
-			if (!strcmp(token, "activity"))
-				display_mode |= LED_ACTIVITY;
-			if (!strcmp(token, "display"))
-				display_mode |= LED_DISP;
-			if (!strcmp(token, "adisplay"))
-				display_mode |= LED_ADISP;
-			if (!strcmp(token, "normal"))
-				ibm_ansi_order = 0;
-			if (!strcmp(token, "ansi"))
-				ibm_ansi_order = 1;
-			if (!strcmp(token, "fast"))
-				global_adapter_speed = 0;
-			if (!strcmp(token, "medium"))
-				global_adapter_speed = 4;
-			if (!strcmp(token, "slow"))
-				global_adapter_speed = 7;
-			if ((*token == '-') || (isdigit(*token))) {
-				if (!(j % 2) && (io_base < IM_MAX_HOSTS))
-					io_port[io_base++] = simple_strtoul(token, NULL, 0);
-				if ((j % 2) && (id_base < IM_MAX_HOSTS))
-					scsi_id[id_base++] = simple_strtoul(token, NULL, 0);
-				j++;
-			}
-		}
-	} else if (ints) {
-		for (i = 0; i < IM_MAX_HOSTS && 2 * i + 2 < ints[0]; i++) {
-			io_port[i] = ints[2 * i + 2];
-			scsi_id[i] = ints[2 * i + 2];
-		}
-	}
-	return;
-}
-
-#if 0
- FIXME NEED TO MOVE TO SYSFS
-
-static int ibmmca_getinfo(char *buf, int slot, void *dev_id)
-{
-	struct Scsi_Host *shpnt;
-	int len, speciale, connectore, k;
-	unsigned int pos[8];
-	unsigned long flags;
-	struct Scsi_Host *dev = dev_id;
-
-	spin_lock_irqsave(dev->host_lock, flags);
-
-	shpnt = dev;		/* assign host-structure to local pointer */
-	len = 0;		/* set filled text-buffer index to 0 */
-	/* get the _special contents of the hostdata structure */
-	speciale = ((struct ibmmca_hostdata *) shpnt->hostdata)->_special;
-	connectore = ((struct ibmmca_hostdata *) shpnt->hostdata)->_connector_size;
-	for (k = 2; k < 4; k++)
-		pos[k] = ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k];
-	if (speciale == FORCED_DETECTION) {	/* forced detection */
-		len += sprintf(buf + len,
-			       "Adapter category: forced detected\n" "***************************************\n" "***  Forced detected SCSI Adapter   ***\n" "***  No chip-information available  ***\n" "***************************************\n");
-	} else if (speciale == INTEGRATED_SCSI) {
-		/* if the integrated subsystem has been found automatically: */
-		len += sprintf(buf + len,
-			       "Adapter category: integrated\n" "Chip revision level: %d\n" "Chip status: %s\n" "8 kByte NVRAM status: %s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 1) ? "enabled" : "disabled", (pos[2] & 2) ? "locked" : "accessible");
-	} else if ((speciale >= 0) && (speciale < ARRAY_SIZE(subsys_list))) {
-		/* if the subsystem is a slot adapter */
-		len += sprintf(buf + len, "Adapter category: slot-card\n" "ROM Segment Address: ");
-		if ((pos[2] & 0xf0) == 0xf0)
-			len += sprintf(buf + len, "off\n");
-		else
-			len += sprintf(buf + len, "0x%x\n", ((pos[2] & 0xf0) << 13) + 0xc0000);
-		len += sprintf(buf + len, "Chip status: %s\n", (pos[2] & 1) ? "enabled" : "disabled");
-		len += sprintf(buf + len, "Adapter I/O Offset: 0x%x\n", ((pos[2] & 0x0e) << 2));
-	} else {
-		len += sprintf(buf + len, "Adapter category: unknown\n");
-	}
-	/* common subsystem information to write to the slotn file */
-	len += sprintf(buf + len, "Subsystem PUN: %d\n", shpnt->this_id);
-	len += sprintf(buf + len, "I/O base address range: 0x%x-0x%x\n", (unsigned int) (shpnt->io_port), (unsigned int) (shpnt->io_port + 7));
-	len += sprintf(buf + len, "MCA-slot size: %d bits", connectore);
-	/* Now make sure, the bufferlength is devidable by 4 to avoid
-	 * paging problems of the buffer. */
-	while (len % sizeof(int) != (sizeof(int) - 1))
-		len += sprintf(buf + len, " ");
-	len += sprintf(buf + len, "\n");
-
-	spin_unlock_irqrestore(shpnt->host_lock, flags);
-
-	return len;
-}
-#endif
-
-static struct scsi_host_template ibmmca_driver_template = {
-          .proc_name      = "ibmmca",
-	  .proc_info	  = ibmmca_proc_info,
-          .name           = "IBM SCSI-Subsystem",
-          .queuecommand   = ibmmca_queuecommand,
-	  .eh_abort_handler = ibmmca_abort,
-	  .eh_host_reset_handler = ibmmca_host_reset,
-          .bios_param     = ibmmca_biosparam,
-          .can_queue      = 16,
-          .this_id        = 7,
-          .sg_tablesize   = 16,
-          .cmd_per_lun    = 1,
-          .use_clustering = ENABLE_CLUSTERING,
-};
-
-static int ibmmca_probe(struct device *dev)
-{
-	struct Scsi_Host *shpnt;
-	int port, id, i, j, k, irq, enabled, ret = -EINVAL;
-	struct mca_device *mca_dev = to_mca_device(dev);
-	const char *description = ibmmca_description[mca_dev->index];
-
-	/* First of all, print the version number of the driver. This is
-	 * important to allow better user bugreports in case of already
-	 * having problems with the MCA_bus probing. */
-	printk(KERN_INFO "IBM MCA SCSI: Version %s\n", IBMMCA_SCSI_DRIVER_VERSION);
-	/* The POS2-register of all PS/2 model SCSI-subsystems has the following
-	 * interpretation of bits:
-	 *                             Bit 7 - 4 : Chip Revision ID (Release)
-	 *                             Bit 3 - 2 : Reserved
-	 *                             Bit 1     : 8k NVRAM Disabled
-	 *                             Bit 0     : Chip Enable (EN-Signal)
-	 * The POS3-register is interpreted as follows:
-	 *                             Bit 7 - 5 : SCSI ID
-	 *                             Bit 4     : Reserved = 0
-	 *                             Bit 3 - 0 : Reserved = 0
-	 * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
-	 * Interfaces (1991)").
-	 * In short words, this means, that IBM PS/2 machines only support
-	 * 1 single subsystem by default. The slot-adapters must have another
-	 * configuration on pos2. Here, one has to assume the following
-	 * things for POS2-register:
-	 *                             Bit 7 - 4 : Chip Revision ID (Release)
-	 *                             Bit 3 - 1 : port offset factor
-	 *                             Bit 0     : Chip Enable (EN-Signal)
-	 * As I found a patch here, setting the IO-registers to 0x3540 forced,
-	 * as there was a 0x05 in POS2 on a model 56, I assume, that the
-	 * port 0x3540 must be fix for integrated SCSI-controllers.
-	 * Ok, this discovery leads to the following implementation: (M.Lang) */
-
-	/* first look for the IBM SCSI integrated subsystem on the motherboard */
-	for (j = 0; j < 8; j++)	/* read the pos-information */
-		pos[j] = mca_device_read_pos(mca_dev, j);
-	id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
-	enabled = (pos[2] &0x01);
-	if (!enabled) {
-		printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
-		printk(KERN_WARNING "              SCSI-operations may not work.\n");
-	}
-
-	/* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present, but
-	 * if we ignore the settings of all surrounding pos registers, it is not
-	 * completely sufficient to only check pos2 and pos3. */
-	/* Therefore, now the following if statement is used to
-	 * make sure, we see a real integrated onboard SCSI-interface and no
-	 * internal system information, which gets mapped to some pos registers
-	 * on models 95xx. */
-	if (mca_dev->slot == MCA_INTEGSCSI &&
-	    ((!pos[0] && !pos[1] && pos[2] > 0 &&
-	      pos[3] > 0 && !pos[4] && !pos[5] &&
-	      !pos[6] && !pos[7]) ||
-	     (pos[0] == 0xff && pos[1] == 0xff &&
-	      pos[2] < 0xff && pos[3] < 0xff &&
-	      pos[4] == 0xff && pos[5] == 0xff &&
-	      pos[6] == 0xff && pos[7] == 0xff))) {
-		irq = IM_IRQ;
-		port = IM_IO_PORT;
-	} else {
-		irq = IM_IRQ;
-		port = IM_IO_PORT + ((pos[2] &0x0e) << 2);
-		if ((mca_dev->index == IBM_SCSI2_FW) && (pos[6] != 0)) {
-			printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
-			printk(KERN_ERR "              Impossible to determine adapter PUN!\n");
-			printk(KERN_ERR "              Guessing adapter PUN = 7.\n");
-			id = 7;
-		} else {
-			id = (pos[3] & 0xe0) >> 5;	/* get subsystem PUN */
-			if (mca_dev->index == IBM_SCSI2_FW) {
-				id |= (pos[3] & 0x10) >> 1;	/* get subsystem PUN high-bit
-								 * for F/W adapters */
-			}
-		}
-		if ((mca_dev->index == IBM_SCSI2_FW) &&
-		    (pos[4] & 0x01) && (pos[6] == 0)) {
-			/* IRQ11 is used by SCSI-2 F/W Adapter/A */
-			printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
-			irq = IM_IRQ_FW;
-		}
-	}
-
-
-
-	/* give detailed information on the subsystem. This helps me
-	 * additionally during debugging and analyzing bug-reports. */
-	printk(KERN_INFO "IBM MCA SCSI: %s found, io=0x%x, scsi id=%d,\n",
-	       description, port, id);
-	if (mca_dev->slot == MCA_INTEGSCSI)
-		printk(KERN_INFO "              chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", (pos[2] & 1) ? "enabled." : "disabled.");
-	else {
-		if ((pos[2] & 0xf0) == 0xf0)
-			printk(KERN_DEBUG "              ROM Addr.=off,");
-		else
-			printk(KERN_DEBUG "              ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
-
-		printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
-	}
-
-	/* check I/O region */
-	if (!request_region(port, IM_N_IO_PORT, description)) {
-		printk(KERN_ERR "IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
-		goto out_fail;
-	}
-
-	/* register host */
-	shpnt = scsi_host_alloc(&ibmmca_driver_template,
-				sizeof(struct ibmmca_hostdata));
-	if (!shpnt) {
-		printk(KERN_ERR "IBM MCA SCSI: Unable to register host.\n");
-		goto out_release;
-	}
-
-	dev_set_drvdata(dev, shpnt);
-	if(request_irq(irq, interrupt_handler, IRQF_SHARED, description, dev)) {
-		printk(KERN_ERR "IBM MCA SCSI: failed to request interrupt %d\n", irq);
-		goto out_free_host;
-	}
-
-	/* request I/O region */
-	special(shpnt) = mca_dev->index;	/* important assignment or else crash! */
-	subsystem_connector_size(shpnt) = 0;	/* preset slot-size */
-	shpnt->irq = irq;	/* assign necessary stuff for the adapter */
-	shpnt->io_port = port;
-	shpnt->n_io_port = IM_N_IO_PORT;
-	shpnt->this_id = id;
-	shpnt->max_id = 8;	/* 8 PUNs are default */
-	/* now, the SCSI-subsystem is connected to Linux */
-
-#ifdef IM_DEBUG_PROBE
-	ctrl = (unsigned int) (inb(IM_CTR_REG(found)));	/* get control-register status */
-	printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", ctrl, inb(IM_STAT_REG(found)));
-	printk("IBM MCA SCSI: This adapters' POS-registers: ");
-	for (i = 0; i < 8; i++)
-		printk("%x ", pos[i]);
-	printk("\n");
-#endif
-	reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS;
-
-	for (i = 0; i < 16; i++)	/* reset the tables */
-		for (j = 0; j < 8; j++)
-			get_ldn(shpnt)[i][j] = MAX_LOG_DEV;
-
-	/* check which logical devices exist */
-	/* after this line, local interrupting is possible: */
-	local_checking_phase_flag(shpnt) = 1;
-	check_devices(shpnt, mca_dev->index);	/* call by value, using the global variable hosts */
-	local_checking_phase_flag(shpnt) = 0;
-
-	/* an ibm mca subsystem has been detected */
-
-	for (k = 2; k < 7; k++)
-		((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
-	((struct ibmmca_hostdata *) shpnt->hostdata)->_special = INTEGRATED_SCSI;
-	mca_device_set_name(mca_dev, description);
-	/* FIXME: NEED TO REPLUMB TO SYSFS
-	   mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
-	*/
-	mca_device_set_claim(mca_dev, 1);
-	if (scsi_add_host(shpnt, dev)) {
-		dev_printk(KERN_ERR, dev, "IBM MCA SCSI: scsi_add_host failed\n");
-		goto out_free_host;
-	}
-	scsi_scan_host(shpnt);
-
-	return 0;
- out_free_host:
-	scsi_host_put(shpnt);
- out_release:
-	release_region(port, IM_N_IO_PORT);
- out_fail:
-	return ret;
-}
-
-static int __devexit ibmmca_remove(struct device *dev)
-{
-	struct Scsi_Host *shpnt = dev_get_drvdata(dev);
-	scsi_remove_host(shpnt);
-	release_region(shpnt->io_port, shpnt->n_io_port);
-	free_irq(shpnt->irq, dev);
-	scsi_host_put(shpnt);
-	return 0;
-}
-
-/* The following routine is the SCSI command queue for the midlevel driver */
-static int ibmmca_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-{
-	unsigned int ldn;
-	unsigned int scsi_cmd;
-	struct im_scb *scb;
-	struct Scsi_Host *shpnt;
-	int current_ldn;
-	int id, lun;
-	int target;
-	int max_pun;
-	int i;
-	struct scatterlist *sg;
-
-	shpnt = cmd->device->host;
-
-	max_pun = subsystem_maxid(shpnt);
-	if (ibm_ansi_order) {
-		target = max_pun - 1 - cmd->device->id;
-		if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt)))
-			target--;
-		else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt)))
-			target++;
-	} else
-		target = cmd->device->id;
-
-	/* if (target,lun) is NO LUN or not existing at all, return error */
-	if ((get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_LUN) || (get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_DEVICE)) {
-		cmd->result = DID_NO_CONNECT << 16;
-		if (done)
-			done(cmd);
-		return 0;
-	}
-
-	/*if (target,lun) unassigned, do further checks... */
-	ldn = get_ldn(shpnt)[target][cmd->device->lun];
-	if (ldn >= MAX_LOG_DEV) {	/* on invalid ldn do special stuff */
-		if (ldn > MAX_LOG_DEV) {	/* dynamical remapping if ldn unassigned */
-			current_ldn = next_ldn(shpnt);	/* stop-value for one circle */
-			while (ld(shpnt)[next_ldn(shpnt)].cmd) {	/* search for a occupied, but not in */
-				/* command-processing ldn. */
-				next_ldn(shpnt)++;
-				if (next_ldn(shpnt) >= MAX_LOG_DEV)
-					next_ldn(shpnt) = 7;
-				if (current_ldn == next_ldn(shpnt)) {	/* One circle done ? */
-					/* no non-processing ldn found */
-					scmd_printk(KERN_WARNING, cmd,
-	"IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n"
-	"              On ldn 7-14 SCSI-commands everywhere in progress.\n"
-	"              Reporting DID_NO_CONNECT for device.\n");
-					cmd->result = DID_NO_CONNECT << 16;	/* return no connect */
-					if (done)
-						done(cmd);
-					return 0;
-				}
-			}
-
-			/* unmap non-processing ldn */
-			for (id = 0; id < max_pun; id++)
-				for (lun = 0; lun < 8; lun++) {
-					if (get_ldn(shpnt)[id][lun] == next_ldn(shpnt)) {
-						get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE;
-						get_scsi(shpnt)[id][lun] = TYPE_NO_DEVICE;
-						/* unmap entry */
-					}
-				}
-			/* set reduced interrupt_handler-mode for checking */
-			local_checking_phase_flag(shpnt) = 1;
-			/* map found ldn to pun,lun */
-			get_ldn(shpnt)[target][cmd->device->lun] = next_ldn(shpnt);
-			/* change ldn to the right value, that is now next_ldn */
-			ldn = next_ldn(shpnt);
-			/* unassign all ldns (pun,lun,ldn does not matter for remove) */
-			immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN);
-			/* set only LDN for remapped device */
-			immediate_assign(shpnt, target, cmd->device->lun, ldn, SET_LDN);
-			/* get device information for ld[ldn] */
-			if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) {
-				ld(shpnt)[ldn].cmd = NULL;	/* To prevent panic set 0, because
-								   devices that were not assigned,
-								   should have nothing in progress. */
-				get_scsi(shpnt)[target][cmd->device->lun] = ld(shpnt)[ldn].device_type;
-				/* increase assignment counters for statistics in /proc */
-				IBM_DS(shpnt).dynamical_assignments++;
-				IBM_DS(shpnt).ldn_assignments[ldn]++;
-			} else
-				/* panic here, because a device, found at boottime has
-				   vanished */
-				panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", ldn, target, cmd->device->lun);
-			/* unassign again all ldns (pun,lun,ldn does not matter for remove) */
-			immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN);
-			/* remap all ldns, as written in the pun/lun table */
-			lun = 0;
-#ifdef CONFIG_SCSI_MULTI_LUN
-			for (lun = 0; lun < 8; lun++)
-#endif
-				for (id = 0; id < max_pun; id++) {
-					if (get_ldn(shpnt)[id][lun] <= MAX_LOG_DEV)
-						immediate_assign(shpnt, id, lun, get_ldn(shpnt)[id][lun], SET_LDN);
-				}
-			/* set back to normal interrupt_handling */
-			local_checking_phase_flag(shpnt) = 0;
-#ifdef IM_DEBUG_PROBE
-			/* Information on syslog terminal */
-			printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", ldn, target, cmd->device->lun);
-#endif
-			/* increase next_ldn for next dynamical assignment */
-			next_ldn(shpnt)++;
-			if (next_ldn(shpnt) >= MAX_LOG_DEV)
-				next_ldn(shpnt) = 7;
-		} else {	/* wall against Linux accesses to the subsystem adapter */
-			cmd->result = DID_BAD_TARGET << 16;
-			if (done)
-				done(cmd);
-			return 0;
-		}
-	}
-
-	/*verify there is no command already in progress for this log dev */
-	if (ld(shpnt)[ldn].cmd)
-		panic("IBM MCA SCSI: cmd already in progress for this ldn.\n");
-
-	/*save done in cmd, and save cmd for the interrupt handler */
-	cmd->scsi_done = done;
-	ld(shpnt)[ldn].cmd = cmd;
-
-	/*fill scb information independent of the scsi command */
-	scb = &(ld(shpnt)[ldn].scb);
-	ld(shpnt)[ldn].tsb.dev_status = 0;
-	scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE;
-	scb->tsb_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].tsb));
-	scsi_cmd = cmd->cmnd[0];
-
-	if (scsi_sg_count(cmd)) {
-		BUG_ON(scsi_sg_count(cmd) > 16);
-
-		scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
-			ld(shpnt)[ldn].sge[i].address = (void *) (isa_page_to_bus(sg_page(sg)) + sg->offset);
-			ld(shpnt)[ldn].sge[i].byte_length = sg->length;
-		}
-		scb->enable |= IM_POINTER_TO_LIST;
-		scb->sys_buf_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].sge[0]));
-		scb->sys_buf_length = scsi_sg_count(cmd) * sizeof(struct im_sge);
-	} else {
- 		scb->sys_buf_adr = isa_virt_to_bus(scsi_sglist(cmd));
-		/* recent Linux midlevel SCSI places 1024 byte for inquiry
-		 * command. Far too much for old PS/2 hardware. */
-		switch (scsi_cmd) {
-			/* avoid command errors by setting bufferlengths to
-			 * ANSI-standard. Beware of forcing it to 255,
-			 * this could SEGV the kernel!!! */
-		case INQUIRY:
-		case REQUEST_SENSE:
-		case MODE_SENSE:
-		case MODE_SELECT:
-			if (scsi_bufflen(cmd) > 255)
-				scb->sys_buf_length = 255;
-			else
-				scb->sys_buf_length = scsi_bufflen(cmd);
-			break;
-		case TEST_UNIT_READY:
-			scb->sys_buf_length = 0;
-			break;
-		default:
-			scb->sys_buf_length = scsi_bufflen(cmd);
-			break;
-		}
-	}
-	/*fill scb information dependent on scsi command */
-
-#ifdef IM_DEBUG_CMD
-	printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
-#endif
-
-	/* for specific device-type debugging: */
-#ifdef IM_DEBUG_CMD_SPEC_DEV
-	if (ld(shpnt)[ldn].device_type == IM_DEBUG_CMD_DEVICE)
-		printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", ld(shpnt)[ldn].device_type, scsi_cmd, ldn);
-#endif
-
-	/* for possible panics store current command */
-	last_scsi_command(shpnt)[ldn] = scsi_cmd;
-	last_scsi_type(shpnt)[ldn] = IM_SCB;
-	/* update statistical info */
-	IBM_DS(shpnt).total_accesses++;
-	IBM_DS(shpnt).ldn_access[ldn]++;
-
-	switch (scsi_cmd) {
-	case READ_6:
-	case WRITE_6:
-	case READ_10:
-	case WRITE_10:
-	case READ_12:
-	case WRITE_12:
-		/* Distinguish between disk and other devices. Only disks (that are the
-		   most frequently accessed devices) should be supported by the
-		   IBM-SCSI-Subsystem commands. */
-		switch (ld(shpnt)[ldn].device_type) {
-		case TYPE_DISK:	/* for harddisks enter here ... */
-		case TYPE_MOD:	/* ... try it also for MO-drives (send flames as */
-			/*     you like, if this won't work.) */
-			if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) {
-				/* read command preparations */
-				scb->enable |= IM_READ_CONTROL;
-				IBM_DS(shpnt).ldn_read_access[ldn]++;	/* increase READ-access on ldn stat. */
-				scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT;
-			} else {	/* write command preparations */
-				IBM_DS(shpnt).ldn_write_access[ldn]++;	/* increase write-count on ldn stat. */
-				scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT;
-			}
-			if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) {
-				scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) | (((unsigned) cmd->cmnd[2]) << 8) | ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16);
-				scb->u2.blk.count = (unsigned) cmd->cmnd[4];
-			} else {
-				scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | (((unsigned) cmd->cmnd[4]) << 8) | (((unsigned) cmd->cmnd[3]) << 16) | (((unsigned) cmd->cmnd[2]) << 24);
-				scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | (((unsigned) cmd->cmnd[7]) << 8);
-			}
-			last_scsi_logical_block(shpnt)[ldn] = scb->u1.log_blk_adr;
-			last_scsi_blockcount(shpnt)[ldn] = scb->u2.blk.count;
-			scb->u2.blk.length = ld(shpnt)[ldn].block_length;
-			break;
-			/* for other devices, enter here. Other types are not known by
-			   Linux! TYPE_NO_LUN is forbidden as valid device. */
-		case TYPE_ROM:
-		case TYPE_TAPE:
-		case TYPE_PROCESSOR:
-		case TYPE_WORM:
-		case TYPE_SCANNER:
-		case TYPE_MEDIUM_CHANGER:
-			/* If there is a sequential-device, IBM recommends to use
-			   IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE.
-			   This includes CD-ROM devices, too, due to the partial sequential
-			   read capabilities. */
-			scb->command = IM_OTHER_SCSI_CMD_CMD;
-			if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12)
-				/* enable READ */
-				scb->enable |= IM_READ_CONTROL;
-			scb->enable |= IM_BYPASS_BUFFER;
-			scb->u1.scsi_cmd_length = cmd->cmd_len;
-			memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-			last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
-			/* Read/write on this non-disk devices is also displayworthy,
-			   so flash-up the LED/display. */
-			break;
-		}
-		break;
-	case INQUIRY:
-		IBM_DS(shpnt).ldn_inquiry_access[ldn]++;
-		scb->command = IM_DEVICE_INQUIRY_CMD;
-		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
-		scb->u1.log_blk_adr = 0;
-		break;
-	case TEST_UNIT_READY:
-		scb->command = IM_OTHER_SCSI_CMD_CMD;
-		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
-		scb->u1.log_blk_adr = 0;
-		scb->u1.scsi_cmd_length = 6;
-		memcpy(scb->u2.scsi_command, cmd->cmnd, 6);
-		last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
-		break;
-	case READ_CAPACITY:
-		/* the length of system memory buffer must be exactly 8 bytes */
-		scb->command = IM_READ_CAPACITY_CMD;
-		scb->enable |= IM_READ_CONTROL | IM_BYPASS_BUFFER;
-		if (scb->sys_buf_length > 8)
-			scb->sys_buf_length = 8;
-		break;
-		/* Commands that need read-only-mode (system <- device): */
-	case REQUEST_SENSE:
-		scb->command = IM_REQUEST_SENSE_CMD;
-		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
-		break;
-		/* Commands that need write-only-mode (system -> device): */
-	case MODE_SELECT:
-	case MODE_SELECT_10:
-		IBM_DS(shpnt).ldn_modeselect_access[ldn]++;
-		scb->command = IM_OTHER_SCSI_CMD_CMD;
-		scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;	/*Select needs WRITE-enabled */
-		scb->u1.scsi_cmd_length = cmd->cmd_len;
-		memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-		last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
-		break;
-		/* For other commands, read-only is useful. Most other commands are
-		   running without an input-data-block. */
-	default:
-		scb->command = IM_OTHER_SCSI_CMD_CMD;
-		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
-		scb->u1.scsi_cmd_length = cmd->cmd_len;
-		memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-		last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
-		break;
-	}
-	/*issue scb command, and return */
-	if (++disk_rw_in_progress == 1)
-		PS2_DISK_LED_ON(shpnt->host_no, target);
-
-	if (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB) {
-		issue_cmd(shpnt, isa_virt_to_bus(scb), IM_LONG_SCB | ldn);
-		IBM_DS(shpnt).long_scbs++;
-	} else {
-		issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
-		IBM_DS(shpnt).scbs++;
-	}
-	return 0;
-}
-
-static DEF_SCSI_QCMD(ibmmca_queuecommand)
-
-static int __ibmmca_abort(Scsi_Cmnd * cmd)
-{
-	/* Abort does not work, as the adapter never generates an interrupt on
-	 * whatever situation is simulated, even when really pending commands
-	 * are running on the adapters' hardware ! */
-
-	struct Scsi_Host *shpnt;
-	unsigned int ldn;
-	void (*saved_done) (Scsi_Cmnd *);
-	int target;
-	int max_pun;
-	unsigned long imm_command;
-
-#ifdef IM_DEBUG_PROBE
-	printk("IBM MCA SCSI: Abort subroutine called...\n");
-#endif
-
-	shpnt = cmd->device->host;
-
-	max_pun = subsystem_maxid(shpnt);
-	if (ibm_ansi_order) {
-		target = max_pun - 1 - cmd->device->id;
-		if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt)))
-			target--;
-		else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt)))
-			target++;
-	} else
-		target = cmd->device->id;
-
-	/* get logical device number, and disable system interrupts */
-	printk(KERN_WARNING "IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", target, cmd->device->lun);
-	ldn = get_ldn(shpnt)[target][cmd->device->lun];
-
-	/*if cmd for this ldn has already finished, no need to abort */
-	if (!ld(shpnt)[ldn].cmd) {
-		    return SUCCESS;
-	}
-
-	/* Clear ld.cmd, save done function, install internal done,
-	 * send abort immediate command (this enables sys. interrupts),
-	 * and wait until the interrupt arrives.
-	 */
-	saved_done = cmd->scsi_done;
-	cmd->scsi_done = internal_done;
-	cmd->SCp.Status = 0;
-	last_scsi_command(shpnt)[ldn] = IM_ABORT_IMM_CMD;
-	last_scsi_type(shpnt)[ldn] = IM_IMM_CMD;
-	imm_command = inl(IM_CMD_REG(shpnt));
-	imm_command &= (unsigned long) (0xffff0000);	/* mask reserved stuff */
-	imm_command |= (unsigned long) (IM_ABORT_IMM_CMD);
-	/* must wait for attention reg not busy */
-	/* FIXME - timeout, politeness */
-	while (1) {
-		if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
-			break;
-	}
-	/* write registers and enable system interrupts */
-	outl(imm_command, IM_CMD_REG(shpnt));
-	outb(IM_IMM_CMD | ldn, IM_ATTN_REG(shpnt));
-#ifdef IM_DEBUG_PROBE
-	printk("IBM MCA SCSI: Abort queued to adapter...\n");
-#endif
-	spin_unlock_irq(shpnt->host_lock);
-	while (!cmd->SCp.Status)
-		yield();
-	spin_lock_irq(shpnt->host_lock);
-	cmd->scsi_done = saved_done;
-#ifdef IM_DEBUG_PROBE
-	printk("IBM MCA SCSI: Abort returned with adapter response...\n");
-#endif
-
-	/*if abort went well, call saved done, then return success or error */
-	if (cmd->result == (DID_ABORT << 16)) 
-	{
-		cmd->result |= DID_ABORT << 16;
-		if (cmd->scsi_done)
-			(cmd->scsi_done) (cmd);
-		ld(shpnt)[ldn].cmd = NULL;
-#ifdef IM_DEBUG_PROBE
-		printk("IBM MCA SCSI: Abort finished with success.\n");
-#endif
-		return SUCCESS;
-	} else {
-		cmd->result |= DID_NO_CONNECT << 16;
-		if (cmd->scsi_done)
-			(cmd->scsi_done) (cmd);
-		ld(shpnt)[ldn].cmd = NULL;
-#ifdef IM_DEBUG_PROBE
-		printk("IBM MCA SCSI: Abort failed.\n");
-#endif
-		return FAILED;
-	}
-}
-
-static int ibmmca_abort(Scsi_Cmnd * cmd)
-{
-	struct Scsi_Host *shpnt = cmd->device->host;
-	int rc;
-
-	spin_lock_irq(shpnt->host_lock);
-	rc = __ibmmca_abort(cmd);
-	spin_unlock_irq(shpnt->host_lock);
-
-	return rc;
-}
-
-static int __ibmmca_host_reset(Scsi_Cmnd * cmd)
-{
-	struct Scsi_Host *shpnt;
-	Scsi_Cmnd *cmd_aid;
-	int ticks, i;
-	unsigned long imm_command;
-
-	BUG_ON(cmd == NULL);
-
-	ticks = IM_RESET_DELAY * HZ;
-	shpnt = cmd->device->host;
-
-	if (local_checking_phase_flag(shpnt)) {
-		printk(KERN_WARNING "IBM MCA SCSI: unable to reset while checking devices.\n");
-		return FAILED;
-	}
-
-	/* issue reset immediate command to subsystem, and wait for interrupt */
-	printk("IBM MCA SCSI: resetting all devices.\n");
-	reset_status(shpnt) = IM_RESET_IN_PROGRESS;
-	last_scsi_command(shpnt)[0xf] = IM_RESET_IMM_CMD;
-	last_scsi_type(shpnt)[0xf] = IM_IMM_CMD;
-	imm_command = inl(IM_CMD_REG(shpnt));
-	imm_command &= (unsigned long) (0xffff0000);	/* mask reserved stuff */
-	imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
-	/* must wait for attention reg not busy */
-	while (1) {
-		if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
-			break;
-		spin_unlock_irq(shpnt->host_lock);
-		yield();
-		spin_lock_irq(shpnt->host_lock);
-	}
-	/*write registers and enable system interrupts */
-	outl(imm_command, IM_CMD_REG(shpnt));
-	outb(IM_IMM_CMD | 0xf, IM_ATTN_REG(shpnt));
-	/* wait for interrupt finished or intr_stat register to be set, as the
-	 * interrupt will not be executed, while we are in here! */
-	 
-	/* FIXME: This is really really icky we so want a sleeping version of this ! */
-	while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks && ((inb(IM_INTR_REG(shpnt)) & 0x8f) != 0x8f)) {
-		udelay((1 + 999 / HZ) * 1000);
-		barrier();
-	}
-	/* if reset did not complete, just return an error */
-	if (!ticks) {
-		printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
-		reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
-		return FAILED;
-	}
-
-	if ((inb(IM_INTR_REG(shpnt)) & 0x8f) == 0x8f) {
-		/* analysis done by this routine and not by the intr-routine */
-		if (inb(IM_INTR_REG(shpnt)) == 0xaf)
-			reset_status(shpnt) = IM_RESET_FINISHED_OK_NO_INT;
-		else if (inb(IM_INTR_REG(shpnt)) == 0xcf)
-			reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
-		else		/* failed, 4get it */
-			reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
-		outb(IM_EOI | 0xf, IM_ATTN_REG(shpnt));
-	}
-
-	/* if reset failed, just return an error */
-	if (reset_status(shpnt) == IM_RESET_FINISHED_FAIL) {
-		printk(KERN_ERR "IBM MCA SCSI: reset failed.\n");
-		return FAILED;
-	}
-
-	/* so reset finished ok - call outstanding done's, and return success */
-	printk(KERN_INFO "IBM MCA SCSI: Reset successfully completed.\n");
-	for (i = 0; i < MAX_LOG_DEV; i++) {
-		cmd_aid = ld(shpnt)[i].cmd;
-		if (cmd_aid && cmd_aid->scsi_done) {
-			ld(shpnt)[i].cmd = NULL;
-			cmd_aid->result = DID_RESET << 16;
-		}
-	}
-	return SUCCESS;
-}
-
-static int ibmmca_host_reset(Scsi_Cmnd * cmd)
-{
-	struct Scsi_Host *shpnt = cmd->device->host;
-	int rc;
-
-	spin_lock_irq(shpnt->host_lock);
-	rc = __ibmmca_host_reset(cmd);
-	spin_unlock_irq(shpnt->host_lock);
-
-	return rc;
-}
-
-static int ibmmca_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *info)
-{
-	int size = capacity;
-	info[0] = 64;
-	info[1] = 32;
-	info[2] = size / (info[0] * info[1]);
-	if (info[2] >= 1024) {
-		info[0] = 128;
-		info[1] = 63;
-		info[2] = size / (info[0] * info[1]);
-		if (info[2] >= 1024) {
-			info[0] = 255;
-			info[1] = 63;
-			info[2] = size / (info[0] * info[1]);
-			if (info[2] >= 1024)
-				info[2] = 1023;
-		}
-	}
-	return 0;
-}
-
-/* calculate percentage of total accesses on a ldn */
-static int ldn_access_load(struct Scsi_Host *shpnt, int ldn)
-{
-	if (IBM_DS(shpnt).total_accesses == 0)
-		return (0);
-	if (IBM_DS(shpnt).ldn_access[ldn] == 0)
-		return (0);
-	return (IBM_DS(shpnt).ldn_access[ldn] * 100) / IBM_DS(shpnt).total_accesses;
-}
-
-/* calculate total amount of r/w-accesses */
-static int ldn_access_total_read_write(struct Scsi_Host *shpnt)
-{
-	int a;
-	int i;
-
-	a = 0;
-	for (i = 0; i <= MAX_LOG_DEV; i++)
-		a += IBM_DS(shpnt).ldn_read_access[i] + IBM_DS(shpnt).ldn_write_access[i];
-	return (a);
-}
-
-static int ldn_access_total_inquiry(struct Scsi_Host *shpnt)
-{
-	int a;
-	int i;
-
-	a = 0;
-	for (i = 0; i <= MAX_LOG_DEV; i++)
-		a += IBM_DS(shpnt).ldn_inquiry_access[i];
-	return (a);
-}
-
-static int ldn_access_total_modeselect(struct Scsi_Host *shpnt)
-{
-	int a;
-	int i;
-
-	a = 0;
-	for (i = 0; i <= MAX_LOG_DEV; i++)
-		a += IBM_DS(shpnt).ldn_modeselect_access[i];
-	return (a);
-}
-
-/* routine to display info in the proc-fs-structure (a deluxe feature) */
-static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
-{
-	int len = 0;
-	int i, id, lun;
-	unsigned long flags;
-	int max_pun;
-
-	
-	spin_lock_irqsave(shpnt->host_lock, flags);	/* Check it */
-
-	max_pun = subsystem_maxid(shpnt);
-
-	len += sprintf(buffer + len, "\n             IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", IBMMCA_SCSI_DRIVER_VERSION);
-	len += sprintf(buffer + len, " SCSI Access-Statistics:\n");
-	len += sprintf(buffer + len, "               Device Scanning Order....: %s\n", (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard");
-#ifdef CONFIG_SCSI_MULTI_LUN
-	len += sprintf(buffer + len, "               Multiple LUN probing.....: Yes\n");
-#else
-	len += sprintf(buffer + len, "               Multiple LUN probing.....: No\n");
-#endif
-	len += sprintf(buffer + len, "               This Hostnumber..........: %d\n", shpnt->host_no);
-	len += sprintf(buffer + len, "               Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(shpnt)));
-	len += sprintf(buffer + len, "               (Shared) IRQ.............: %d\n", IM_IRQ);
-	len += sprintf(buffer + len, "               Total Interrupts.........: %d\n", IBM_DS(shpnt).total_interrupts);
-	len += sprintf(buffer + len, "               Total SCSI Accesses......: %d\n", IBM_DS(shpnt).total_accesses);
-	len += sprintf(buffer + len, "               Total short SCBs.........: %d\n", IBM_DS(shpnt).scbs);
-	len += sprintf(buffer + len, "               Total long SCBs..........: %d\n", IBM_DS(shpnt).long_scbs);
-	len += sprintf(buffer + len, "                 Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(shpnt));
-	len += sprintf(buffer + len, "                 Total SCSI Inquiries...: %d\n", ldn_access_total_inquiry(shpnt));
-	len += sprintf(buffer + len, "                 Total SCSI Modeselects.: %d\n", ldn_access_total_modeselect(shpnt));
-	len += sprintf(buffer + len, "                 Total SCSI other cmds..: %d\n", IBM_DS(shpnt).total_accesses - ldn_access_total_read_write(shpnt)
-		       - ldn_access_total_modeselect(shpnt)
-		       - ldn_access_total_inquiry(shpnt));
-	len += sprintf(buffer + len, "               Total SCSI command fails.: %d\n\n", IBM_DS(shpnt).total_errors);
-	len += sprintf(buffer + len, " Logical-Device-Number (LDN) Access-Statistics:\n");
-	len += sprintf(buffer + len, "         LDN | Accesses [%%] |   READ    |   WRITE   | ASSIGNMENTS\n");
-	len += sprintf(buffer + len, "        -----|--------------|-----------|-----------|--------------\n");
-	for (i = 0; i <= MAX_LOG_DEV; i++)
-		len += sprintf(buffer + len, "         %2X  |    %3d       |  %8d |  %8d | %8d\n", i, ldn_access_load(shpnt, i), IBM_DS(shpnt).ldn_read_access[i], IBM_DS(shpnt).ldn_write_access[i], IBM_DS(shpnt).ldn_assignments[i]);
-	len += sprintf(buffer + len, "        -----------------------------------------------------------\n\n");
-	len += sprintf(buffer + len, " Dynamical-LDN-Assignment-Statistics:\n");
-	len += sprintf(buffer + len, "               Number of physical SCSI-devices..: %d (+ Adapter)\n", IBM_DS(shpnt).total_scsi_devices);
-	len += sprintf(buffer + len, "               Dynamical Assignment necessary...: %s\n", IBM_DS(shpnt).dyn_flag ? "Yes" : "No ");
-	len += sprintf(buffer + len, "               Next LDN to be assigned..........: 0x%x\n", next_ldn(shpnt));
-	len += sprintf(buffer + len, "               Dynamical assignments done yet...: %d\n", IBM_DS(shpnt).dynamical_assignments);
-	len += sprintf(buffer + len, "\n Current SCSI-Device-Mapping:\n");
-	len += sprintf(buffer + len, "        Physical SCSI-Device Map               Logical SCSI-Device Map\n");
-	len += sprintf(buffer + len, "    ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
-	for (id = 0; id < max_pun; id++) {
-		len += sprintf(buffer + len, "    %2d     ", id);
-		for (lun = 0; lun < 8; lun++)
-			len += sprintf(buffer + len, "%2s ", ti_p(get_scsi(shpnt)[id][lun]));
-		len += sprintf(buffer + len, "      %2d     ", id);
-		for (lun = 0; lun < 8; lun++)
-			len += sprintf(buffer + len, "%2s ", ti_l(get_ldn(shpnt)[id][lun]));
-		len += sprintf(buffer + len, "\n");
-	}
-
-	len += sprintf(buffer + len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n");
-	len += sprintf(buffer + len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n");
-	len += sprintf(buffer + len, " - = nothing found, nothing assigned or unprobed LUN)\n\n");
-
-	*start = buffer + offset;
-	len -= offset;
-	if (len > length)
-		len = length;
-	spin_unlock_irqrestore(shpnt->host_lock, flags);
-	return len;
-}
-
-static int option_setup(char *str)
-{
-	int ints[IM_MAX_HOSTS];
-	char *cur = str;
-	int i = 1;
-
-	while (cur && isdigit(*cur) && i < IM_MAX_HOSTS) {
-		ints[i++] = simple_strtoul(cur, NULL, 0);
-		if ((cur = strchr(cur, ',')) != NULL)
-			cur++;
-	}
-	ints[0] = i - 1;
-	internal_ibmmca_scsi_setup(cur, ints);
-	return 1;
-}
-
-__setup("ibmmcascsi=", option_setup);
-
-static struct mca_driver ibmmca_driver = {
-	.id_table = ibmmca_id_table,
-	.driver = {
-		.name	= "ibmmca",
-		.bus	= &mca_bus_type,
-		.probe	= ibmmca_probe,
-		.remove	= __devexit_p(ibmmca_remove),
-	},
-};
-
-static int __init ibmmca_init(void)
-{
-#ifdef MODULE
-	/* If the driver is run as module, read from conf.modules or cmd-line */
-	if (boot_options)
-		option_setup(boot_options);
-#endif
-
-	return mca_register_driver_integrated(&ibmmca_driver, MCA_INTEGSCSI);
-}
-
-static void __exit ibmmca_exit(void)
-{
-	mca_unregister_driver(&ibmmca_driver);
-}
-
-module_init(ibmmca_init);
-module_exit(ibmmca_exit);
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 6c6486f..538230b 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -4473,17 +4473,14 @@
 	pci_unregister_driver(&qla1280_pci_driver);
 	/* release any allocated firmware images */
 	for (i = 0; i < QL_NUM_FW_IMAGES; i++) {
-		if (qla1280_fw_tbl[i].fw) {
-			release_firmware(qla1280_fw_tbl[i].fw);
-			qla1280_fw_tbl[i].fw = NULL;
-		}
+		release_firmware(qla1280_fw_tbl[i].fw);
+		qla1280_fw_tbl[i].fw = NULL;
 	}
 }
 
 module_init(qla1280_init);
 module_exit(qla1280_exit);
 
-
 MODULE_AUTHOR("Qlogic & Jes Sorensen");
 MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 7db8033..c9c56a8 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -4122,8 +4122,7 @@
 
 	mutex_lock(&qla_fw_lock);
 	for (idx = 0; idx < FW_BLOBS; idx++)
-		if (qla_fw_blobs[idx].fw)
-			release_firmware(qla_fw_blobs[idx].fw);
+		release_firmware(qla_fw_blobs[idx].fw);
 	mutex_unlock(&qla_fw_lock);
 }
 
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 386f0c5..d0f71e5 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -664,7 +664,7 @@
 }
 
 /**
- * scsi_eh_prep_cmnd  - Save a scsi command info as part of error recory
+ * scsi_eh_prep_cmnd  - Save a scsi command info as part of error recovery
  * @scmd:       SCSI command structure to hijack
  * @ses:        structure to save restore information
  * @cmnd:       CDB to send. Can be NULL if no new cmnd is needed
@@ -739,7 +739,7 @@
 EXPORT_SYMBOL(scsi_eh_prep_cmnd);
 
 /**
- * scsi_eh_restore_cmnd  - Restore a scsi command info as part of error recory
+ * scsi_eh_restore_cmnd  - Restore a scsi command info as part of error recovery
  * @scmd:       SCSI command structure to restore
  * @ses:        saved information from a coresponding call to scsi_eh_prep_cmnd
  *
@@ -762,7 +762,7 @@
 EXPORT_SYMBOL(scsi_eh_restore_cmnd);
 
 /**
- * scsi_send_eh_cmnd  - submit a scsi command as part of error recory
+ * scsi_send_eh_cmnd  - submit a scsi command as part of error recovery
  * @scmd:       SCSI command structure to hijack
  * @cmnd:       CDB to send
  * @cmnd_size:  size in bytes of @cmnd
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 8ac6ce7..a318264 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -17,7 +17,7 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *----------------------------------------------------------------------------
  *
- * MCA card detection code by Trent McNair.
+ * MCA card detection code by Trent McNair. (now deleted)
  * Fixes to not explicitly nul bss data from Xavier Bestel.
  * Some multiboard fixes from Rolf Eike Beer.
  * Auto probing of EISA config space from Trevor Hemsley.
@@ -32,7 +32,6 @@
 #include <linux/blkdev.h>
 #include <linux/device.h>
 #include <linux/init.h>
-#include <linux/mca.h>
 #include <linux/eisa.h>
 #include <linux/interrupt.h>
 #include <scsi/scsi_host.h>
@@ -43,7 +42,7 @@
 #include "53c700.h"
 
 
-/* Must be enough for both EISA and MCA */
+/* Must be enough for EISA */
 #define MAX_SLOTS 8
 static __u8 __initdata id_array[MAX_SLOTS] = { [0 ... MAX_SLOTS-1] = 7 };
 
@@ -89,7 +88,7 @@
 __setup("sim710=", param_setup);
 
 static struct scsi_host_template sim710_driver_template = {
-	.name			= "LSI (Symbios) 710 MCA/EISA",
+	.name			= "LSI (Symbios) 710 EISA",
 	.proc_name		= "sim710",
 	.this_id		= 7,
 	.module			= THIS_MODULE,
@@ -169,114 +168,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_MCA
-
-/* CARD ID 01BB and 01BA use the same pos values */
-#define MCA_01BB_IO_PORTS { 0x0000, 0x0000, 0x0800, 0x0C00, 0x1000, 0x1400, \
-			    0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, \
-			    0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, \
-			    0x4000, 0x4400, 0x4800, 0x4C00, 0x5000  }
-
-#define MCA_01BB_IRQS { 3, 5, 11, 14 }
-
-/* CARD ID 004f */
-#define MCA_004F_IO_PORTS { 0x0000, 0x0200, 0x0300, 0x0400, 0x0500,  0x0600 }
-#define MCA_004F_IRQS { 5, 9, 14 }
-
-static short sim710_mca_id_table[] = { 0x01bb, 0x01ba, 0x004f, 0};
-
-static __init int
-sim710_mca_probe(struct device *dev)
-{
-	struct mca_device *mca_dev = to_mca_device(dev);
-	int slot = mca_dev->slot;
-	int pos[3];
-	unsigned int base;
-	int irq_vector;
-	short id = sim710_mca_id_table[mca_dev->index];
-	static int io_004f_by_pos[] = MCA_004F_IO_PORTS;
-	static int irq_004f_by_pos[] = MCA_004F_IRQS;
-	static int io_01bb_by_pos[] = MCA_01BB_IO_PORTS;
-	static int irq_01bb_by_pos[] = MCA_01BB_IRQS;
-	char *name;
-	int clock;
-
-	pos[0] = mca_device_read_stored_pos(mca_dev, 2);
-	pos[1] = mca_device_read_stored_pos(mca_dev, 3);
-	pos[2] = mca_device_read_stored_pos(mca_dev, 4);
-
-	/*
-	 * 01BB & 01BA port base by bits 7,6,5,4,3,2 in pos[2]
-	 *
-	 *    000000  <disabled>   001010  0x2800
-	 *    000001  <invalid>    001011  0x2C00
-	 *    000010  0x0800       001100  0x3000
-	 *    000011  0x0C00       001101  0x3400
-	 *    000100  0x1000       001110  0x3800
-	 *    000101  0x1400       001111  0x3C00
-	 *    000110  0x1800       010000  0x4000
-	 *    000111  0x1C00       010001  0x4400
-	 *    001000  0x2000       010010  0x4800
-	 *    001001  0x2400       010011  0x4C00
-	 *                         010100  0x5000
-	 *
-	 * 00F4 port base by bits 3,2,1 in pos[0]
-	 *
-	 *    000  <disabled>      001    0x200
-	 *    010  0x300           011    0x400
-	 *    100  0x500           101    0x600
-	 *
-	 * 01BB & 01BA IRQ is specified in pos[0] bits 7 and 6:
-	 *
-	 *    00   3               10   11
-	 *    01   5               11   14
-	 *
-	 * 00F4 IRQ specified by bits 6,5,4 in pos[0]
-	 *
-	 *    100   5              101    9
-	 *    110   14
-	 */
-
-	if (id == 0x01bb || id == 0x01ba) {
-		base = io_01bb_by_pos[(pos[2] & 0xFC) >> 2];
-		irq_vector =
-			irq_01bb_by_pos[((pos[0] & 0xC0) >> 6)];
-
-		clock = 50;
-		if (id == 0x01bb)
-			name = "NCR 3360/3430 SCSI SubSystem";
-		else
-			name = "NCR Dual SIOP SCSI Host Adapter Board";
-	} else if ( id == 0x004f ) {
-		base = io_004f_by_pos[((pos[0] & 0x0E) >> 1)];
-		irq_vector =
-			irq_004f_by_pos[((pos[0] & 0x70) >> 4) - 4];
-		clock = 50;
-		name = "NCR 53c710 SCSI Host Adapter Board";
-	} else {
-		return -ENODEV;
-	}
-	mca_device_set_name(mca_dev, name);
-	mca_device_set_claim(mca_dev, 1);
-	base = mca_device_transform_ioport(mca_dev, base);
-	irq_vector = mca_device_transform_irq(mca_dev, irq_vector);
-
-	return sim710_probe_common(dev, base, irq_vector, clock,
-				   0, id_array[slot]);
-}
-
-static struct mca_driver sim710_mca_driver = {
-	.id_table		= sim710_mca_id_table,
-	.driver = {
-		.name		= "sim710",
-		.bus		= &mca_bus_type,
-		.probe		= sim710_mca_probe,
-		.remove		= __devexit_p(sim710_device_remove),
-	},
-};
-
-#endif /* CONFIG_MCA */
-
 #ifdef CONFIG_EISA
 static struct eisa_device_id sim710_eisa_ids[] = {
 	{ "CPQ4410" },
@@ -344,10 +235,6 @@
 		param_setup(sim710);
 #endif
 
-#ifdef CONFIG_MCA
-	err = mca_register_driver(&sim710_mca_driver);
-#endif
-
 #ifdef CONFIG_EISA
 	err = eisa_driver_register(&sim710_eisa_driver);
 #endif
@@ -361,11 +248,6 @@
 
 static void __exit sim710_exit(void)
 {
-#ifdef CONFIG_MCA
-	if (MCA_bus)
-		mca_unregister_driver(&sim710_mca_driver);
-#endif
-
 #ifdef CONFIG_EISA
 	eisa_driver_unregister(&sim710_eisa_driver);
 #endif
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 91b6d52..f0d015d 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -2,6 +2,7 @@
  * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
  *
  *  Copyright (C) 2010  Magnus Damm
+ *  Copyright (C) 2010 - 2012  Paul Mundt
  *
  * 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
@@ -13,26 +14,44 @@
 #include <linux/io.h>
 #include <linux/sh_clk.h>
 
-static int sh_clk_mstp32_enable(struct clk *clk)
+static unsigned int sh_clk_read(struct clk *clk)
 {
-	iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
-		  clk->mapped_reg);
+	if (clk->flags & CLK_ENABLE_REG_8BIT)
+		return ioread8(clk->mapped_reg);
+	else if (clk->flags & CLK_ENABLE_REG_16BIT)
+		return ioread16(clk->mapped_reg);
+
+	return ioread32(clk->mapped_reg);
+}
+
+static void sh_clk_write(int value, struct clk *clk)
+{
+	if (clk->flags & CLK_ENABLE_REG_8BIT)
+		iowrite8(value, clk->mapped_reg);
+	else if (clk->flags & CLK_ENABLE_REG_16BIT)
+		iowrite16(value, clk->mapped_reg);
+	else
+		iowrite32(value, clk->mapped_reg);
+}
+
+static int sh_clk_mstp_enable(struct clk *clk)
+{
+	sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
 	return 0;
 }
 
-static void sh_clk_mstp32_disable(struct clk *clk)
+static void sh_clk_mstp_disable(struct clk *clk)
 {
-	iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
-		  clk->mapped_reg);
+	sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
 }
 
-static struct sh_clk_ops sh_clk_mstp32_clk_ops = {
-	.enable		= sh_clk_mstp32_enable,
-	.disable	= sh_clk_mstp32_disable,
+static struct sh_clk_ops sh_clk_mstp_clk_ops = {
+	.enable		= sh_clk_mstp_enable,
+	.disable	= sh_clk_mstp_disable,
 	.recalc		= followparent_recalc,
 };
 
-int __init sh_clk_mstp32_register(struct clk *clks, int nr)
+int __init sh_clk_mstp_register(struct clk *clks, int nr)
 {
 	struct clk *clkp;
 	int ret = 0;
@@ -40,7 +59,7 @@
 
 	for (k = 0; !ret && (k < nr); k++) {
 		clkp = clks + k;
-		clkp->ops = &sh_clk_mstp32_clk_ops;
+		clkp->ops = &sh_clk_mstp_clk_ops;
 		ret |= clk_register(clkp);
 	}
 
@@ -72,7 +91,7 @@
 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
 			     table, NULL);
 
-	idx = ioread32(clk->mapped_reg) & 0x003f;
+	idx = sh_clk_read(clk) & 0x003f;
 
 	return clk->freq_table[idx].frequency;
 }
@@ -98,10 +117,10 @@
 	if (ret < 0)
 		return ret;
 
-	value = ioread32(clk->mapped_reg) &
+	value = sh_clk_read(clk) &
 		~(((1 << clk->src_width) - 1) << clk->src_shift);
 
-	iowrite32(value | (i << clk->src_shift), clk->mapped_reg);
+	sh_clk_write(value | (i << clk->src_shift), clk);
 
 	/* Rebuild the frequency table */
 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -119,10 +138,10 @@
 	if (idx < 0)
 		return idx;
 
-	value = ioread32(clk->mapped_reg);
+	value = sh_clk_read(clk);
 	value &= ~0x3f;
 	value |= idx;
-	iowrite32(value, clk->mapped_reg);
+	sh_clk_write(value, clk);
 	return 0;
 }
 
@@ -133,9 +152,9 @@
 
 	ret = sh_clk_div6_set_rate(clk, clk->rate);
 	if (ret == 0) {
-		value = ioread32(clk->mapped_reg);
+		value = sh_clk_read(clk);
 		value &= ~0x100; /* clear stop bit to enable clock */
-		iowrite32(value, clk->mapped_reg);
+		sh_clk_write(value, clk);
 	}
 	return ret;
 }
@@ -144,10 +163,10 @@
 {
 	unsigned long value;
 
-	value = ioread32(clk->mapped_reg);
+	value = sh_clk_read(clk);
 	value |= 0x100; /* stop clock */
 	value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
-	iowrite32(value, clk->mapped_reg);
+	sh_clk_write(value, clk);
 }
 
 static struct sh_clk_ops sh_clk_div6_clk_ops = {
@@ -182,7 +201,7 @@
 		return -EINVAL;
 	}
 
-	val  = (ioread32(clk->mapped_reg) >> clk->src_shift);
+	val  = (sh_clk_read(clk) >> clk->src_shift);
 	val &= (1 << clk->src_width) - 1;
 
 	if (val >= clk->parent_num) {
@@ -252,7 +271,7 @@
 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
 			     table, &clk->arch_flags);
 
-	idx = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0x000f;
+	idx = (sh_clk_read(clk) >> clk->enable_bit) & 0x000f;
 
 	return clk->freq_table[idx].frequency;
 }
@@ -270,15 +289,15 @@
 	 */
 
 	if (parent->flags & CLK_ENABLE_ON_INIT)
-		value = ioread32(clk->mapped_reg) & ~(1 << 7);
+		value = sh_clk_read(clk) & ~(1 << 7);
 	else
-		value = ioread32(clk->mapped_reg) | (1 << 7);
+		value = sh_clk_read(clk) | (1 << 7);
 
 	ret = clk_reparent(clk, parent);
 	if (ret < 0)
 		return ret;
 
-	iowrite32(value, clk->mapped_reg);
+	sh_clk_write(value, clk);
 
 	/* Rebiuld the frequency table */
 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -295,10 +314,10 @@
 	if (idx < 0)
 		return idx;
 
-	value = ioread32(clk->mapped_reg);
+	value = sh_clk_read(clk);
 	value &= ~(0xf << clk->enable_bit);
 	value |= (idx << clk->enable_bit);
-	iowrite32(value, clk->mapped_reg);
+	sh_clk_write(value, clk);
 
 	if (d4t->kick)
 		d4t->kick(clk);
@@ -308,13 +327,13 @@
 
 static int sh_clk_div4_enable(struct clk *clk)
 {
-	iowrite32(ioread32(clk->mapped_reg) & ~(1 << 8), clk->mapped_reg);
+	sh_clk_write(sh_clk_read(clk) & ~(1 << 8), clk);
 	return 0;
 }
 
 static void sh_clk_div4_disable(struct clk *clk)
 {
-	iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
+	sh_clk_write(sh_clk_read(clk) | (1 << 8), clk);
 }
 
 static struct sh_clk_ops sh_clk_div4_clk_ops = {
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
index 5fea1ee..14eb01e 100644
--- a/drivers/sh/intc/dynamic.c
+++ b/drivers/sh/intc/dynamic.c
@@ -55,11 +55,3 @@
 {
 	irq_free_desc(irq);
 }
-
-void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
-{
-	int i;
-
-	for (i = 0; i < nr_vecs; i++)
-		irq_reserve_irq(evt2irq(vectors[i].vect));
-}
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 570f220..69c9a66 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -37,6 +37,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <mach/spi.h>
 
@@ -758,6 +759,7 @@
 	struct spi_master *master;
 	struct spi_imx_data *spi_imx;
 	struct resource *res;
+	struct pinctrl *pinctrl;
 	int i, ret, num_cs;
 
 	if (!np && !mxc_platform_info) {
@@ -845,6 +847,12 @@
 		goto out_iounmap;
 	}
 
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		goto out_free_irq;
+	}
+
 	spi_imx->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(spi_imx->clk)) {
 		dev_err(&pdev->dev, "unable to get clock\n");
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 97d412d..05e33c7 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -24,8 +24,6 @@
 
 if STAGING
 
-source "drivers/staging/serial/Kconfig"
-
 source "drivers/staging/et131x/Kconfig"
 
 source "drivers/staging/slicoss/Kconfig"
@@ -68,14 +66,10 @@
 
 source "drivers/staging/serqt_usb2/Kconfig"
 
-source "drivers/staging/quatech_usb2/Kconfig"
-
 source "drivers/staging/vt6655/Kconfig"
 
 source "drivers/staging/vt6656/Kconfig"
 
-source "drivers/staging/vme/Kconfig"
-
 source "drivers/staging/sep/Kconfig"
 
 source "drivers/staging/iio/Kconfig"
@@ -116,12 +110,12 @@
 
 source "drivers/staging/ste_rmi4/Kconfig"
 
-source "drivers/staging/mei/Kconfig"
-
 source "drivers/staging/nvec/Kconfig"
 
 source "drivers/staging/media/Kconfig"
 
+source "drivers/staging/net/Kconfig"
+
 source "drivers/staging/omapdrm/Kconfig"
 
 source "drivers/staging/android/Kconfig"
@@ -132,4 +126,10 @@
 
 source "drivers/staging/ozwpan/Kconfig"
 
+source "drivers/staging/ccg/Kconfig"
+
+source "drivers/staging/ipack/Kconfig"
+
+source "drivers/staging/gdm72xx/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ffe7d44..a987b3a 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -3,8 +3,8 @@
 # fix for build system bug...
 obj-$(CONFIG_STAGING)		+= staging.o
 
-obj-y				+= serial/
 obj-y				+= media/
+obj-y				+= net/
 obj-$(CONFIG_ET131X)		+= et131x/
 obj-$(CONFIG_SLICOSS)		+= slicoss/
 obj-$(CONFIG_USBIP_CORE)	+= usbip/
@@ -25,11 +25,11 @@
 obj-$(CONFIG_IDE_PHISON)	+= phison/
 obj-$(CONFIG_LINE6_USB)		+= line6/
 obj-$(CONFIG_USB_SERIAL_QUATECH2)	+= serqt_usb2/
-obj-$(CONFIG_USB_SERIAL_QUATECH_USB2)	+= quatech_usb2/
 obj-$(CONFIG_OCTEON_ETHERNET)	+= octeon/
 obj-$(CONFIG_VT6655)		+= vt6655/
 obj-$(CONFIG_VT6656)		+= vt6656/
 obj-$(CONFIG_VME_BUS)		+= vme/
+obj-$(CONFIG_IPACK_BUS)		+= ipack/
 obj-$(CONFIG_DX_SEP)            += sep/
 obj-$(CONFIG_IIO)		+= iio/
 obj-$(CONFIG_ZRAM)		+= zram/
@@ -50,10 +50,11 @@
 obj-$(CONFIG_SPEAKUP)		+= speakup/
 obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)	+= cptm1217/
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)	+= ste_rmi4/
-obj-$(CONFIG_INTEL_MEI)		+= mei/
 obj-$(CONFIG_MFD_NVEC)		+= nvec/
 obj-$(CONFIG_DRM_OMAP)		+= omapdrm/
 obj-$(CONFIG_ANDROID)		+= android/
 obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_RAMSTER)		+= ramster/
 obj-$(CONFIG_USB_WPAN_HCD)	+= ozwpan/
+obj-$(CONFIG_USB_G_CCG)		+= ccg/
+obj-$(CONFIG_WIMAX_GDM72XX)	+= gdm72xx/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index eb1dee2..0e16b59 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -25,17 +25,9 @@
 	tristate "Android log driver"
 	default n
 
-config ANDROID_PERSISTENT_RAM
-	bool
-	depends on HAVE_MEMBLOCK
-	select REED_SOLOMON
-	select REED_SOLOMON_ENC8
-	select REED_SOLOMON_DEC8
-
 config ANDROID_RAM_CONSOLE
 	bool "Android RAM buffer console"
-	depends on !S390 && !UML && HAVE_MEMBLOCK
-	select ANDROID_PERSISTENT_RAM
+	depends on !S390 && !UML && HAVE_MEMBLOCK && PSTORE_RAM=y
 	default n
 
 config ANDROID_TIMED_OUTPUT
@@ -53,33 +45,14 @@
 	---help---
 	  Register processes to be killed when memory is low
 
-source "drivers/staging/android/switch/Kconfig"
-
-config ANDROID_INTF_ALARM
+config ANDROID_INTF_ALARM_DEV
 	bool "Android alarm driver"
 	depends on RTC_CLASS
 	default n
 	help
 	  Provides non-wakeup and rtc backed wakeup alarms based on rtc or
 	  elapsed realtime, and a non-wakeup alarm on the monotonic clock.
-	  Also provides an interface to set the wall time which must be used
-	  for elapsed realtime to work.
-
-config ANDROID_INTF_ALARM_DEV
-	bool "Android alarm device"
-	depends on ANDROID_INTF_ALARM
-	default y
-	help
-	  Exports the alarm interface to user-space.
-
-config ANDROID_ALARM_OLDDRV_COMPAT
-	bool "Android Alarm compatability with old drivers"
-	depends on ANDROID_INTF_ALARM
-	default n
-	help
-	  Provides preprocessor alias to aid compatability with
-	  older out-of-tree drivers that use the Android Alarm
-	  in-kernel API. This will be removed eventually.
+	  Also exports the alarm interface to user-space.
 
 endif # if ANDROID
 
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 9b6c9ed..98711e2 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -1,11 +1,8 @@
 obj-$(CONFIG_ANDROID_BINDER_IPC)	+= binder.o
 obj-$(CONFIG_ASHMEM)			+= ashmem.o
 obj-$(CONFIG_ANDROID_LOGGER)		+= logger.o
-obj-$(CONFIG_ANDROID_PERSISTENT_RAM)	+= persistent_ram.o
 obj-$(CONFIG_ANDROID_RAM_CONSOLE)	+= ram_console.o
 obj-$(CONFIG_ANDROID_TIMED_OUTPUT)	+= timed_output.o
 obj-$(CONFIG_ANDROID_TIMED_GPIO)	+= timed_gpio.o
 obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER)	+= lowmemorykiller.o
-obj-$(CONFIG_ANDROID_SWITCH)		+= switch/
-obj-$(CONFIG_ANDROID_INTF_ALARM)	+= alarm.o
 obj-$(CONFIG_ANDROID_INTF_ALARM_DEV)	+= alarm-dev.o
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
index 03efb34..53ce6ec 100644
--- a/drivers/staging/android/alarm-dev.c
+++ b/drivers/staging/android/alarm-dev.c
@@ -22,19 +22,9 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
+#include <linux/alarmtimer.h>
 #include "android_alarm.h"
 
-/* XXX - Hack out wakelocks, while they are out of tree */
-struct wake_lock {
-	int i;
-};
-#define wake_lock(x)
-#define wake_lock_timeout(x, y)
-#define wake_unlock(x)
-#define WAKE_LOCK_SUSPEND 0
-#define wake_lock_init(x, y, z) ((x)->i = 1)
-#define wake_lock_destroy(x)
-
 #define ANDROID_ALARM_PRINT_INFO (1U << 0)
 #define ANDROID_ALARM_PRINT_IO (1U << 1)
 #define ANDROID_ALARM_PRINT_INT (1U << 2)
@@ -54,19 +44,65 @@
 	ANDROID_ALARM_RTC_WAKEUP_MASK | \
 	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
 
-/* support old usespace code */
+/* support old userspace code */
 #define ANDROID_ALARM_SET_OLD               _IOW('a', 2, time_t) /* set alarm */
 #define ANDROID_ALARM_SET_AND_WAIT_OLD      _IOW('a', 3, time_t)
 
 static int alarm_opened;
 static DEFINE_SPINLOCK(alarm_slock);
-static struct wake_lock alarm_wake_lock;
+static struct wakeup_source alarm_wake_lock;
 static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
 static uint32_t alarm_pending;
 static uint32_t alarm_enabled;
 static uint32_t wait_pending;
 
-static struct android_alarm alarms[ANDROID_ALARM_TYPE_COUNT];
+struct devalarm {
+	union {
+		struct hrtimer hrt;
+		struct alarm alrm;
+	} u;
+	enum android_alarm_type type;
+};
+
+static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT];
+
+
+static int is_wakeup(enum android_alarm_type type)
+{
+	if (type == ANDROID_ALARM_RTC_WAKEUP ||
+			type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP)
+		return 1;
+	return 0;
+}
+
+
+static void devalarm_start(struct devalarm *alrm, ktime_t exp)
+{
+	if (is_wakeup(alrm->type))
+		alarm_start(&alrm->u.alrm, exp);
+	else
+		hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS);
+}
+
+
+static int devalarm_try_to_cancel(struct devalarm *alrm)
+{
+	int ret;
+	if (is_wakeup(alrm->type))
+		ret = alarm_try_to_cancel(&alrm->u.alrm);
+	else
+		ret = hrtimer_try_to_cancel(&alrm->u.hrt);
+	return ret;
+}
+
+static void devalarm_cancel(struct devalarm *alrm)
+{
+	if (is_wakeup(alrm->type))
+		alarm_cancel(&alrm->u.alrm);
+	else
+		hrtimer_cancel(&alrm->u.hrt);
+}
+
 
 static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -75,6 +111,8 @@
 	struct timespec new_alarm_time;
 	struct timespec new_rtc_time;
 	struct timespec tmp_time;
+	struct rtc_time new_rtc_tm;
+	struct rtc_device *rtc_dev;
 	enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
 	uint32_t alarm_type_mask = 1U << alarm_type;
 
@@ -101,11 +139,11 @@
 	case ANDROID_ALARM_CLEAR(0):
 		spin_lock_irqsave(&alarm_slock, flags);
 		pr_alarm(IO, "alarm %d clear\n", alarm_type);
-		android_alarm_try_to_cancel(&alarms[alarm_type]);
+		devalarm_try_to_cancel(&alarms[alarm_type]);
 		if (alarm_pending) {
 			alarm_pending &= ~alarm_type_mask;
 			if (!alarm_pending && !wait_pending)
-				wake_unlock(&alarm_wake_lock);
+				__pm_relax(&alarm_wake_lock);
 		}
 		alarm_enabled &= ~alarm_type_mask;
 		spin_unlock_irqrestore(&alarm_slock, flags);
@@ -132,8 +170,7 @@
 		pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
 			new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
 		alarm_enabled |= alarm_type_mask;
-		android_alarm_start_range(&alarms[alarm_type],
-			timespec_to_ktime(new_alarm_time),
+		devalarm_start(&alarms[alarm_type],
 			timespec_to_ktime(new_alarm_time));
 		spin_unlock_irqrestore(&alarm_slock, flags);
 		if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
@@ -144,7 +181,7 @@
 		spin_lock_irqsave(&alarm_slock, flags);
 		pr_alarm(IO, "alarm wait\n");
 		if (!alarm_pending && wait_pending) {
-			wake_unlock(&alarm_wake_lock);
+			__pm_relax(&alarm_wake_lock);
 			wait_pending = 0;
 		}
 		spin_unlock_irqrestore(&alarm_slock, flags);
@@ -163,7 +200,13 @@
 			rv = -EFAULT;
 			goto err1;
 		}
-		rv = android_alarm_set_rtc(new_rtc_time);
+		rtc_time_to_tm(new_rtc_time.tv_sec, &new_rtc_tm);
+		rtc_dev = alarmtimer_get_rtcdev();
+		rv = do_settimeofday(&new_rtc_time);
+		if (rv < 0)
+			goto err1;
+		if (rtc_dev)
+			rv = rtc_set_time(rtc_dev, &new_rtc_tm);
 		spin_lock_irqsave(&alarm_slock, flags);
 		alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
 		wake_up(&alarm_wait_queue);
@@ -179,8 +222,7 @@
 			break;
 		case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
 		case ANDROID_ALARM_ELAPSED_REALTIME:
-			tmp_time =
-				ktime_to_timespec(alarm_get_elapsed_realtime());
+			get_monotonic_boottime(&tmp_time);
 			break;
 		case ANDROID_ALARM_TYPE_COUNT:
 		case ANDROID_ALARM_SYSTEMTIME:
@@ -224,14 +266,14 @@
 				alarm_enabled &= ~alarm_type_mask;
 			}
 			spin_unlock_irqrestore(&alarm_slock, flags);
-			android_alarm_cancel(&alarms[i]);
+			devalarm_cancel(&alarms[i]);
 			spin_lock_irqsave(&alarm_slock, flags);
 		}
 		if (alarm_pending | wait_pending) {
 			if (alarm_pending)
 				pr_alarm(INFO, "alarm_release: clear "
 					"pending alarms %x\n", alarm_pending);
-			wake_unlock(&alarm_wake_lock);
+			__pm_relax(&alarm_wake_lock);
 			wait_pending = 0;
 			alarm_pending = 0;
 		}
@@ -241,15 +283,15 @@
 	return 0;
 }
 
-static void alarm_triggered(struct android_alarm *alarm)
+static void devalarm_triggered(struct devalarm *alarm)
 {
 	unsigned long flags;
 	uint32_t alarm_type_mask = 1U << alarm->type;
 
-	pr_alarm(INT, "alarm_triggered type %d\n", alarm->type);
+	pr_alarm(INT, "devalarm_triggered type %d\n", alarm->type);
 	spin_lock_irqsave(&alarm_slock, flags);
 	if (alarm_enabled & alarm_type_mask) {
-		wake_lock_timeout(&alarm_wake_lock, 5 * HZ);
+		__pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
 		alarm_enabled &= ~alarm_type_mask;
 		alarm_pending |= alarm_type_mask;
 		wake_up(&alarm_wait_queue);
@@ -257,6 +299,25 @@
 	spin_unlock_irqrestore(&alarm_slock, flags);
 }
 
+
+static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt)
+{
+	struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt);
+
+	devalarm_triggered(devalrm);
+	return HRTIMER_NORESTART;
+}
+
+static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm,
+							ktime_t now)
+{
+	struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm);
+
+	devalarm_triggered(devalrm);
+	return ALARMTIMER_NORESTART;
+}
+
+
 static const struct file_operations alarm_fops = {
 	.owner = THIS_MODULE,
 	.unlocked_ioctl = alarm_ioctl,
@@ -279,17 +340,31 @@
 	if (err)
 		return err;
 
-	for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++)
-		android_alarm_init(&alarms[i], i, alarm_triggered);
-	wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
+	alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,
+			ALARM_REALTIME, devalarm_alarmhandler);
+	hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,
+			CLOCK_REALTIME, HRTIMER_MODE_ABS);
+	alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,
+			ALARM_BOOTTIME, devalarm_alarmhandler);
+	hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,
+			CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
+	hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,
+			CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 
+	for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
+		alarms[i].type = i;
+		if (!is_wakeup(i))
+			alarms[i].u.hrt.function = devalarm_hrthandler;
+	}
+
+	wakeup_source_init(&alarm_wake_lock, "alarm");
 	return 0;
 }
 
 static void  __exit alarm_dev_exit(void)
 {
 	misc_deregister(&alarm_device);
-	wake_lock_destroy(&alarm_wake_lock);
+	wakeup_source_trash(&alarm_wake_lock);
 }
 
 module_init(alarm_dev_init);
diff --git a/drivers/staging/android/alarm.c b/drivers/staging/android/alarm.c
deleted file mode 100644
index c68950b..0000000
--- a/drivers/staging/android/alarm.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/* drivers/rtc/alarm.c
- *
- * Copyright (C) 2007-2009 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/time.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/platform_device.h>
-#include <linux/rtc.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include "android_alarm.h"
-
-/* XXX - Hack out wakelocks, while they are out of tree */
-struct wake_lock {
-	int i;
-};
-#define wake_lock(x)
-#define wake_lock_timeout(x, y)
-#define wake_unlock(x)
-#define WAKE_LOCK_SUSPEND 0
-#define wake_lock_init(x, y, z) ((x)->i = 1)
-#define wake_lock_destroy(x)
-
-#define ANDROID_ALARM_PRINT_ERROR (1U << 0)
-#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
-#define ANDROID_ALARM_PRINT_TSET (1U << 2)
-#define ANDROID_ALARM_PRINT_CALL (1U << 3)
-#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4)
-#define ANDROID_ALARM_PRINT_INT (1U << 5)
-#define ANDROID_ALARM_PRINT_FLOW (1U << 6)
-
-static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \
-			ANDROID_ALARM_PRINT_INIT_STATUS;
-module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#define pr_alarm(debug_level_mask, args...) \
-	do { \
-		if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
-			pr_info(args); \
-		} \
-	} while (0)
-
-#define ANDROID_ALARM_WAKEUP_MASK ( \
-	ANDROID_ALARM_RTC_WAKEUP_MASK | \
-	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
-
-/* support old usespace code */
-#define ANDROID_ALARM_SET_OLD               _IOW('a', 2, time_t) /* set alarm */
-#define ANDROID_ALARM_SET_AND_WAIT_OLD      _IOW('a', 3, time_t)
-
-struct alarm_queue {
-	struct rb_root alarms;
-	struct rb_node *first;
-	struct hrtimer timer;
-	ktime_t delta;
-	bool stopped;
-	ktime_t stopped_time;
-};
-
-static struct rtc_device *alarm_rtc_dev;
-static DEFINE_SPINLOCK(alarm_slock);
-static DEFINE_MUTEX(alarm_setrtc_mutex);
-static struct wake_lock alarm_rtc_wake_lock;
-static struct platform_device *alarm_platform_dev;
-struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
-static bool suspended;
-
-static void update_timer_locked(struct alarm_queue *base, bool head_removed)
-{
-	struct android_alarm *alarm;
-	bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] ||
-			base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
-
-	if (base->stopped) {
-		pr_alarm(FLOW, "changed alarm while setting the wall time\n");
-		return;
-	}
-
-	if (is_wakeup && !suspended && head_removed)
-		wake_unlock(&alarm_rtc_wake_lock);
-
-	if (!base->first)
-		return;
-
-	alarm = container_of(base->first, struct android_alarm, node);
-
-	pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n",
-		alarm->type, alarm->function, ktime_to_ns(alarm->expires));
-
-	if (is_wakeup && suspended) {
-		pr_alarm(FLOW, "changed alarm while suspened\n");
-		wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
-		return;
-	}
-
-	hrtimer_try_to_cancel(&base->timer);
-	base->timer.node.expires = ktime_add(base->delta, alarm->expires);
-	base->timer._softexpires = ktime_add(base->delta, alarm->softexpires);
-	hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS);
-}
-
-static void alarm_enqueue_locked(struct android_alarm *alarm)
-{
-	struct alarm_queue *base = &alarms[alarm->type];
-	struct rb_node **link = &base->alarms.rb_node;
-	struct rb_node *parent = NULL;
-	struct android_alarm *entry;
-	int leftmost = 1;
-	bool was_first = false;
-
-	pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n",
-		alarm->type, alarm->function, ktime_to_ns(alarm->expires));
-
-	if (base->first == &alarm->node) {
-		base->first = rb_next(&alarm->node);
-		was_first = true;
-	}
-	if (!RB_EMPTY_NODE(&alarm->node)) {
-		rb_erase(&alarm->node, &base->alarms);
-		RB_CLEAR_NODE(&alarm->node);
-	}
-
-	while (*link) {
-		parent = *link;
-		entry = rb_entry(parent, struct android_alarm, node);
-		/*
-		* We dont care about collisions. Nodes with
-		* the same expiry time stay together.
-		*/
-		if (alarm->expires.tv64 < entry->expires.tv64) {
-			link = &(*link)->rb_left;
-		} else {
-			link = &(*link)->rb_right;
-			leftmost = 0;
-		}
-	}
-	if (leftmost)
-		base->first = &alarm->node;
-	if (leftmost || was_first)
-		update_timer_locked(base, was_first);
-
-	rb_link_node(&alarm->node, parent, link);
-	rb_insert_color(&alarm->node, &base->alarms);
-}
-
-/**
- * android_alarm_init - initialize an alarm
- * @alarm:	the alarm to be initialized
- * @type:	the alarm type to be used
- * @function:	alarm callback function
- */
-void android_alarm_init(struct android_alarm *alarm,
-	enum android_alarm_type type, void (*function)(struct android_alarm *))
-{
-	RB_CLEAR_NODE(&alarm->node);
-	alarm->type = type;
-	alarm->function = function;
-
-	pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function);
-}
-
-
-/**
- * android_alarm_start_range - (re)start an alarm
- * @alarm:	the alarm to be added
- * @start:	earliest expiry time
- * @end:	expiry time
- */
-void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
-								ktime_t end)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	alarm->softexpires = start;
-	alarm->expires = end;
-	alarm_enqueue_locked(alarm);
-	spin_unlock_irqrestore(&alarm_slock, flags);
-}
-
-/**
- * android_alarm_try_to_cancel - try to deactivate an alarm
- * @alarm:	alarm to stop
- *
- * Returns:
- *  0 when the alarm was not active
- *  1 when the alarm was active
- * -1 when the alarm may currently be excuting the callback function and
- *    cannot be stopped (it may also be inactive)
- */
-int android_alarm_try_to_cancel(struct android_alarm *alarm)
-{
-	struct alarm_queue *base = &alarms[alarm->type];
-	unsigned long flags;
-	bool first = false;
-	int ret = 0;
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	if (!RB_EMPTY_NODE(&alarm->node)) {
-		pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n",
-			alarm->type, alarm->function,
-			ktime_to_ns(alarm->expires));
-		ret = 1;
-		if (base->first == &alarm->node) {
-			base->first = rb_next(&alarm->node);
-			first = true;
-		}
-		rb_erase(&alarm->node, &base->alarms);
-		RB_CLEAR_NODE(&alarm->node);
-		if (first)
-			update_timer_locked(base, true);
-	} else
-		pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n",
-			alarm->type, alarm->function);
-	spin_unlock_irqrestore(&alarm_slock, flags);
-	if (!ret && hrtimer_callback_running(&base->timer))
-		ret = -1;
-	return ret;
-}
-
-/**
- * android_alarm_cancel - cancel an alarm and wait for the handler to finish.
- * @alarm:	the alarm to be cancelled
- *
- * Returns:
- *  0 when the alarm was not active
- *  1 when the alarm was active
- */
-int android_alarm_cancel(struct android_alarm *alarm)
-{
-	for (;;) {
-		int ret = android_alarm_try_to_cancel(alarm);
-		if (ret >= 0)
-			return ret;
-		cpu_relax();
-	}
-}
-
-/**
- * alarm_set_rtc - set the kernel and rtc walltime
- * @new_time:	timespec value containing the new time
- */
-int android_alarm_set_rtc(struct timespec new_time)
-{
-	int i;
-	int ret;
-	unsigned long flags;
-	struct rtc_time rtc_new_rtc_time;
-	struct timespec tmp_time;
-
-	rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time);
-
-	pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n",
-		new_time.tv_sec, new_time.tv_nsec,
-		rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min,
-		rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1,
-		rtc_new_rtc_time.tm_mday,
-		rtc_new_rtc_time.tm_year + 1900);
-
-	mutex_lock(&alarm_setrtc_mutex);
-	spin_lock_irqsave(&alarm_slock, flags);
-	wake_lock(&alarm_rtc_wake_lock);
-	getnstimeofday(&tmp_time);
-	for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
-		hrtimer_try_to_cancel(&alarms[i].timer);
-		alarms[i].stopped = true;
-		alarms[i].stopped_time = timespec_to_ktime(tmp_time);
-	}
-	alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
-		alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
-		ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta,
-			timespec_to_ktime(timespec_sub(tmp_time, new_time)));
-	spin_unlock_irqrestore(&alarm_slock, flags);
-	ret = do_settimeofday(&new_time);
-	spin_lock_irqsave(&alarm_slock, flags);
-	for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
-		alarms[i].stopped = false;
-		update_timer_locked(&alarms[i], false);
-	}
-	spin_unlock_irqrestore(&alarm_slock, flags);
-	if (ret < 0) {
-		pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n");
-		goto err;
-	}
-	if (!alarm_rtc_dev) {
-		pr_alarm(ERROR,
-			"alarm_set_rtc: no RTC, time will be lost on reboot\n");
-		goto err;
-	}
-	ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
-	if (ret < 0)
-		pr_alarm(ERROR, "alarm_set_rtc: "
-			"Failed to set RTC, time will be lost on reboot\n");
-err:
-	wake_unlock(&alarm_rtc_wake_lock);
-	mutex_unlock(&alarm_setrtc_mutex);
-	return ret;
-}
-
-/**
- * alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format
- *
- * returns the time in ktime_t format
- */
-ktime_t alarm_get_elapsed_realtime(void)
-{
-	ktime_t now;
-	unsigned long flags;
-	struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME];
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	now = base->stopped ? base->stopped_time : ktime_get_real();
-	now = ktime_sub(now, base->delta);
-	spin_unlock_irqrestore(&alarm_slock, flags);
-	return now;
-}
-
-static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer)
-{
-	struct alarm_queue *base;
-	struct android_alarm *alarm;
-	unsigned long flags;
-	ktime_t now;
-
-	spin_lock_irqsave(&alarm_slock, flags);
-
-	base = container_of(timer, struct alarm_queue, timer);
-	now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer);
-	now = ktime_sub(now, base->delta);
-
-	pr_alarm(INT, "alarm_timer_triggered type %ld at %lld\n",
-		base - alarms, ktime_to_ns(now));
-
-	while (base->first) {
-		alarm = container_of(base->first, struct android_alarm, node);
-		if (alarm->softexpires.tv64 > now.tv64) {
-			pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n",
-				alarm->function, ktime_to_ns(alarm->expires),
-				ktime_to_ns(alarm->softexpires));
-			break;
-		}
-		base->first = rb_next(&alarm->node);
-		rb_erase(&alarm->node, &base->alarms);
-		RB_CLEAR_NODE(&alarm->node);
-		pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n",
-			alarm->type, alarm->function,
-			ktime_to_ns(alarm->expires),
-			ktime_to_ns(alarm->softexpires));
-		spin_unlock_irqrestore(&alarm_slock, flags);
-		alarm->function(alarm);
-		spin_lock_irqsave(&alarm_slock, flags);
-	}
-	if (!base->first)
-		pr_alarm(FLOW, "no more alarms of type %ld\n", base - alarms);
-	update_timer_locked(base, true);
-	spin_unlock_irqrestore(&alarm_slock, flags);
-	return HRTIMER_NORESTART;
-}
-
-static void alarm_triggered_func(void *p)
-{
-	struct rtc_device *rtc = alarm_rtc_dev;
-	if (!(rtc->irq_data & RTC_AF))
-		return;
-	pr_alarm(INT, "rtc alarm triggered\n");
-	wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
-}
-
-static int alarm_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	int                 err = 0;
-	unsigned long       flags;
-	struct rtc_wkalrm   rtc_alarm;
-	struct rtc_time     rtc_current_rtc_time;
-	unsigned long       rtc_current_time;
-	unsigned long       rtc_alarm_time;
-	struct timespec     rtc_delta;
-	struct timespec     wall_time;
-	struct alarm_queue *wakeup_queue = NULL;
-	struct alarm_queue *tmp_queue = NULL;
-
-	pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event);
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	suspended = true;
-	spin_unlock_irqrestore(&alarm_slock, flags);
-
-	hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
-	hrtimer_cancel(&alarms[
-			ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
-
-	tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
-	if (tmp_queue->first)
-		wakeup_queue = tmp_queue;
-	tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
-	if (tmp_queue->first && (!wakeup_queue ||
-				hrtimer_get_expires(&tmp_queue->timer).tv64 <
-				hrtimer_get_expires(&wakeup_queue->timer).tv64))
-		wakeup_queue = tmp_queue;
-	if (wakeup_queue) {
-		rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
-		getnstimeofday(&wall_time);
-		rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
-		set_normalized_timespec(&rtc_delta,
-					wall_time.tv_sec - rtc_current_time,
-					wall_time.tv_nsec);
-
-		rtc_alarm_time = timespec_sub(ktime_to_timespec(
-			hrtimer_get_expires(&wakeup_queue->timer)),
-			rtc_delta).tv_sec;
-
-		rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time);
-		rtc_alarm.enabled = 1;
-		rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
-		rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
-		rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
-		pr_alarm(SUSPEND,
-			"rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n",
-			rtc_alarm_time, rtc_current_time,
-			rtc_delta.tv_sec, rtc_delta.tv_nsec);
-		if (rtc_current_time + 1 >= rtc_alarm_time) {
-			pr_alarm(SUSPEND, "alarm about to go off\n");
-			memset(&rtc_alarm, 0, sizeof(rtc_alarm));
-			rtc_alarm.enabled = 0;
-			rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
-
-			spin_lock_irqsave(&alarm_slock, flags);
-			suspended = false;
-			wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ);
-			update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP],
-									false);
-			update_timer_locked(&alarms[
-				ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false);
-			err = -EBUSY;
-			spin_unlock_irqrestore(&alarm_slock, flags);
-		}
-	}
-	return err;
-}
-
-static int alarm_resume(struct platform_device *pdev)
-{
-	struct rtc_wkalrm alarm;
-	unsigned long       flags;
-
-	pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);
-
-	memset(&alarm, 0, sizeof(alarm));
-	alarm.enabled = 0;
-	rtc_set_alarm(alarm_rtc_dev, &alarm);
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	suspended = false;
-	update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false);
-	update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP],
-									false);
-	spin_unlock_irqrestore(&alarm_slock, flags);
-
-	return 0;
-}
-
-static struct rtc_task alarm_rtc_task = {
-	.func = alarm_triggered_func
-};
-
-static int rtc_alarm_add_device(struct device *dev,
-				struct class_interface *class_intf)
-{
-	int err;
-	struct rtc_device *rtc = to_rtc_device(dev);
-
-	mutex_lock(&alarm_setrtc_mutex);
-
-	if (alarm_rtc_dev) {
-		err = -EBUSY;
-		goto err1;
-	}
-
-	alarm_platform_dev =
-		platform_device_register_simple("alarm", -1, NULL, 0);
-	if (IS_ERR(alarm_platform_dev)) {
-		err = PTR_ERR(alarm_platform_dev);
-		goto err2;
-	}
-	err = rtc_irq_register(rtc, &alarm_rtc_task);
-	if (err)
-		goto err3;
-	alarm_rtc_dev = rtc;
-	pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name);
-	mutex_unlock(&alarm_setrtc_mutex);
-
-	return 0;
-
-err3:
-	platform_device_unregister(alarm_platform_dev);
-err2:
-err1:
-	mutex_unlock(&alarm_setrtc_mutex);
-	return err;
-}
-
-static void rtc_alarm_remove_device(struct device *dev,
-				    struct class_interface *class_intf)
-{
-	if (dev == &alarm_rtc_dev->dev) {
-		pr_alarm(INIT_STATUS, "lost rtc device for alarms");
-		rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task);
-		platform_device_unregister(alarm_platform_dev);
-		alarm_rtc_dev = NULL;
-	}
-}
-
-static struct class_interface rtc_alarm_interface = {
-	.add_dev = &rtc_alarm_add_device,
-	.remove_dev = &rtc_alarm_remove_device,
-};
-
-static struct platform_driver alarm_driver = {
-	.suspend = alarm_suspend,
-	.resume = alarm_resume,
-	.driver = {
-		.name = "alarm"
-	}
-};
-
-static int __init alarm_late_init(void)
-{
-	unsigned long   flags;
-	struct timespec tmp_time, system_time;
-
-	/* this needs to run after the rtc is read at boot */
-	spin_lock_irqsave(&alarm_slock, flags);
-	/* We read the current rtc and system time so we can later calulate
-	 * elasped realtime to be (boot_systemtime + rtc - boot_rtc) ==
-	 * (rtc - (boot_rtc - boot_systemtime))
-	 */
-	getnstimeofday(&tmp_time);
-	ktime_get_ts(&system_time);
-	alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
-		alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
-			timespec_to_ktime(timespec_sub(tmp_time, system_time));
-
-	spin_unlock_irqrestore(&alarm_slock, flags);
-	return 0;
-}
-
-static int __init alarm_driver_init(void)
-{
-	int err;
-	int i;
-
-	for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
-		hrtimer_init(&alarms[i].timer,
-				CLOCK_REALTIME, HRTIMER_MODE_ABS);
-		alarms[i].timer.function = alarm_timer_triggered;
-	}
-	hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer,
-		     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-	alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered;
-	err = platform_driver_register(&alarm_driver);
-	if (err < 0)
-		goto err1;
-	wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
-	rtc_alarm_interface.class = rtc_class;
-	err = class_interface_register(&rtc_alarm_interface);
-	if (err < 0)
-		goto err2;
-
-	return 0;
-
-err2:
-	wake_lock_destroy(&alarm_rtc_wake_lock);
-	platform_driver_unregister(&alarm_driver);
-err1:
-	return err;
-}
-
-static void  __exit alarm_exit(void)
-{
-	class_interface_unregister(&rtc_alarm_interface);
-	wake_lock_destroy(&alarm_rtc_wake_lock);
-	platform_driver_unregister(&alarm_driver);
-}
-
-late_initcall(alarm_late_init);
-module_init(alarm_driver_init);
-module_exit(alarm_exit);
-
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
index 6eecbde..d0cafd6 100644
--- a/drivers/staging/android/android_alarm.h
+++ b/drivers/staging/android/android_alarm.h
@@ -33,65 +33,6 @@
 	/* ANDROID_ALARM_TIME_CHANGE = 16 */
 };
 
-#ifdef __KERNEL__
-
-#include <linux/ktime.h>
-#include <linux/rbtree.h>
-
-/*
- * The alarm interface is similar to the hrtimer interface but adds support
- * for wakeup from suspend. It also adds an elapsed realtime clock that can
- * be used for periodic timers that need to keep runing while the system is
- * suspended and not be disrupted when the wall time is set.
- */
-
-/**
- * struct alarm - the basic alarm structure
- * @node:	red black tree node for time ordered insertion
- * @type:	alarm type. rtc/elapsed-realtime/systemtime, wakeup/non-wakeup.
- * @softexpires: the absolute earliest expiry time of the alarm.
- * @expires:	the absolute expiry time.
- * @function:	alarm expiry callback function
- *
- * The alarm structure must be initialized by alarm_init()
- *
- */
-
-struct android_alarm {
-	struct rb_node		node;
-	enum android_alarm_type type;
-	ktime_t			softexpires;
-	ktime_t			expires;
-	void			(*function)(struct android_alarm *);
-};
-
-void android_alarm_init(struct android_alarm *alarm,
-	enum android_alarm_type type, void (*function)(struct android_alarm *));
-void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
-								ktime_t end);
-int android_alarm_try_to_cancel(struct android_alarm *alarm);
-int android_alarm_cancel(struct android_alarm *alarm);
-ktime_t alarm_get_elapsed_realtime(void);
-
-/* set rtc while preserving elapsed realtime */
-int android_alarm_set_rtc(const struct timespec ts);
-
-#ifdef CONFIG_ANDROID_ALARM_OLDDRV_COMPAT
-/*
- * Some older drivers depend on the old API,
- * so provide compatability macros for now.
- */
-#define alarm android_alarm
-#define alarm_init(x, y, z) android_alarm_init(x, y, z)
-#define alarm_start_range(x, y, z) android_alarm_start_range(x, y, z)
-#define alarm_try_to_cancel(x) android_alarm_try_to_cancel(x)
-#define alarm_cancel(x) android_alarm_cancel(x)
-#define alarm_set_rtc(x) android_alarm_set_rtc(x)
-#endif
-
-
-#endif
-
 enum android_alarm_return_flags {
 	ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
 	ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 9f1f27e..4511420 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -269,7 +269,7 @@
 	return ret;
 }
 
-static inline unsigned long calc_vm_may_flags(unsigned long prot)
+static inline vm_flags_t calc_vm_may_flags(unsigned long prot)
 {
 	return _calc_vm_trans(prot, PROT_READ,  VM_MAYREAD) |
 	       _calc_vm_trans(prot, PROT_WRITE, VM_MAYWRITE) |
diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h
index 25ab6f2..2f7d195 100644
--- a/drivers/staging/android/binder.h
+++ b/drivers/staging/android/binder.h
@@ -53,17 +53,17 @@
 
 	/* 8 bytes of data. */
 	union {
-		void		*binder;	/* local object */
+		void __user	*binder;	/* local object */
 		signed long	handle;		/* remote object */
 	};
 
 	/* extra data associated with local object */
-	void			*cookie;
+	void __user		*cookie;
 };
 
 /*
  * On 64-bit platforms where user code may run in 32-bits the driver must
- * translate the buffer (and local binder) addresses apropriately.
+ * translate the buffer (and local binder) addresses appropriately.
  */
 
 struct binder_write_read {
@@ -139,9 +139,9 @@
 	union {
 		struct {
 			/* transaction data */
-			const void	*buffer;
+			const void __user	*buffer;
 			/* offsets from buffer to flat_binder_object structs */
-			const void	*offsets;
+			const void __user	*offsets;
 		} ptr;
 		uint8_t	buf[8];
 	} data;
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index ea69b6a..b2e71c6 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -25,6 +25,7 @@
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/vmalloc.h>
 #include "logger.h"
 
 #include <asm/ioctls.h>
@@ -45,8 +46,12 @@
 	size_t			w_off;	/* current write head offset */
 	size_t			head;	/* new readers start here */
 	size_t			size;	/* size of the log */
+	struct list_head	logs;	/* list of log channels (myself)*/
 };
 
+static LIST_HEAD(log_list);
+
+
 /*
  * struct logger_reader - a logging device open for reading
  *
@@ -60,9 +65,9 @@
 };
 
 /* logger_offset - returns index 'n' into the log via (optimized) modulus */
-size_t logger_offset(struct logger_log *log, size_t n)
+static size_t logger_offset(struct logger_log *log, size_t n)
 {
-	return n & (log->size-1);
+	return n & (log->size - 1);
 }
 
 
@@ -348,7 +353,7 @@
  * writev(), and aio_write(). Writes are our fast path, and we try to optimize
  * them above all else.
  */
-ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
 			 unsigned long nr_segs, loff_t ppos)
 {
 	struct logger_log *log = file_get_log(iocb->ki_filp);
@@ -408,7 +413,15 @@
 	return ret;
 }
 
-static struct logger_log *get_log_from_minor(int);
+static struct logger_log *get_log_from_minor(int minor)
+{
+	struct logger_log *log;
+
+	list_for_each_entry(log, &log_list, logs)
+		if (log->misc.minor == minor)
+			return log;
+	return NULL;
+}
 
 /*
  * logger_open - the log's open() file operation
@@ -565,80 +578,84 @@
 };
 
 /*
- * Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which
- * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than
- * LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
+ * Log size must be a power of two, greater than LOGGER_ENTRY_MAX_LEN,
+ * and less than LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
  */
-#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \
-static unsigned char _buf_ ## VAR[SIZE]; \
-static struct logger_log VAR = { \
-	.buffer = _buf_ ## VAR, \
-	.misc = { \
-		.minor = MISC_DYNAMIC_MINOR, \
-		.name = NAME, \
-		.fops = &logger_fops, \
-		.parent = NULL, \
-	}, \
-	.wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \
-	.readers = LIST_HEAD_INIT(VAR .readers), \
-	.mutex = __MUTEX_INITIALIZER(VAR .mutex), \
-	.w_off = 0, \
-	.head = 0, \
-	.size = SIZE, \
-};
-
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 256*1024)
-DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 256*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 256*1024)
-
-static struct logger_log *get_log_from_minor(int minor)
+static int __init create_log(char *log_name, int size)
 {
-	if (log_main.misc.minor == minor)
-		return &log_main;
-	if (log_events.misc.minor == minor)
-		return &log_events;
-	if (log_radio.misc.minor == minor)
-		return &log_radio;
-	if (log_system.misc.minor == minor)
-		return &log_system;
-	return NULL;
-}
+	int ret = 0;
+	struct logger_log *log;
+	unsigned char *buffer;
 
-static int __init init_log(struct logger_log *log)
-{
-	int ret;
+	buffer = vmalloc(size);
+	if (buffer == NULL)
+		return -ENOMEM;
 
+	log = kzalloc(sizeof(struct logger_log), GFP_KERNEL);
+	if (log == NULL) {
+		ret = -ENOMEM;
+		goto out_free_buffer;
+	}
+	log->buffer = buffer;
+
+	log->misc.minor = MISC_DYNAMIC_MINOR;
+	log->misc.name = kstrdup(log_name, GFP_KERNEL);
+	if (log->misc.name == NULL) {
+		ret = -ENOMEM;
+		goto out_free_log;
+	}
+
+	log->misc.fops = &logger_fops;
+	log->misc.parent = NULL;
+
+	init_waitqueue_head(&log->wq);
+	INIT_LIST_HEAD(&log->readers);
+	mutex_init(&log->mutex);
+	log->w_off = 0;
+	log->head = 0;
+	log->size = size;
+
+	INIT_LIST_HEAD(&log->logs);
+	list_add_tail(&log->logs, &log_list);
+
+	/* finally, initialize the misc device for this log */
 	ret = misc_register(&log->misc);
 	if (unlikely(ret)) {
 		printk(KERN_ERR "logger: failed to register misc "
 		       "device for log '%s'!\n", log->misc.name);
-		return ret;
+		goto out_free_log;
 	}
 
 	printk(KERN_INFO "logger: created %luK log '%s'\n",
 	       (unsigned long) log->size >> 10, log->misc.name);
 
 	return 0;
+
+out_free_log:
+	kfree(log);
+
+out_free_buffer:
+	vfree(buffer);
+	return ret;
 }
 
 static int __init logger_init(void)
 {
 	int ret;
 
-	ret = init_log(&log_main);
+	ret = create_log(LOGGER_LOG_MAIN, 256*1024);
 	if (unlikely(ret))
 		goto out;
 
-	ret = init_log(&log_events);
+	ret = create_log(LOGGER_LOG_EVENTS, 256*1024);
 	if (unlikely(ret))
 		goto out;
 
-	ret = init_log(&log_radio);
+	ret = create_log(LOGGER_LOG_RADIO, 256*1024);
 	if (unlikely(ret))
 		goto out;
 
-	ret = init_log(&log_system);
+	ret = create_log(LOGGER_LOG_SYSTEM, 256*1024);
 	if (unlikely(ret))
 		goto out;
 
diff --git a/drivers/staging/android/persistent_ram.c b/drivers/staging/android/persistent_ram.c
deleted file mode 100644
index 8d8c1e3..0000000
--- a/drivers/staging/android/persistent_ram.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * Copyright (C) 2012 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/list.h>
-#include <linux/memblock.h>
-#include <linux/rslib.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include "persistent_ram.h"
-
-struct persistent_ram_buffer {
-	uint32_t    sig;
-	atomic_t    start;
-	atomic_t    size;
-	uint8_t     data[0];
-};
-
-#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
-
-static __initdata LIST_HEAD(persistent_ram_list);
-
-static inline size_t buffer_size(struct persistent_ram_zone *prz)
-{
-	return atomic_read(&prz->buffer->size);
-}
-
-static inline size_t buffer_start(struct persistent_ram_zone *prz)
-{
-	return atomic_read(&prz->buffer->start);
-}
-
-/* increase and wrap the start pointer, returning the old value */
-static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
-{
-	int old;
-	int new;
-
-	do {
-		old = atomic_read(&prz->buffer->start);
-		new = old + a;
-		while (unlikely(new > prz->buffer_size))
-			new -= prz->buffer_size;
-	} while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
-
-	return old;
-}
-
-/* increase the size counter until it hits the max size */
-static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
-{
-	size_t old;
-	size_t new;
-
-	if (atomic_read(&prz->buffer->size) == prz->buffer_size)
-		return;
-
-	do {
-		old = atomic_read(&prz->buffer->size);
-		new = old + a;
-		if (new > prz->buffer_size)
-			new = prz->buffer_size;
-	} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
-}
-
-/* increase the size counter, retuning an error if it hits the max size */
-static inline ssize_t buffer_size_add_clamp(struct persistent_ram_zone *prz,
-	size_t a)
-{
-	size_t old;
-	size_t new;
-
-	do {
-		old = atomic_read(&prz->buffer->size);
-		new = old + a;
-		if (new > prz->buffer_size)
-			return -ENOMEM;
-	} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
-
-	return 0;
-}
-
-static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
-	uint8_t *data, size_t len, uint8_t *ecc)
-{
-	int i;
-	uint16_t par[prz->ecc_size];
-
-	/* Initialize the parity buffer */
-	memset(par, 0, sizeof(par));
-	encode_rs8(prz->rs_decoder, data, len, par, 0);
-	for (i = 0; i < prz->ecc_size; i++)
-		ecc[i] = par[i];
-}
-
-static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
-	void *data, size_t len, uint8_t *ecc)
-{
-	int i;
-	uint16_t par[prz->ecc_size];
-
-	for (i = 0; i < prz->ecc_size; i++)
-		par[i] = ecc[i];
-	return decode_rs8(prz->rs_decoder, data, par, len,
-				NULL, 0, NULL, 0, NULL);
-}
-
-static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
-	unsigned int start, unsigned int count)
-{
-	struct persistent_ram_buffer *buffer = prz->buffer;
-	uint8_t *buffer_end = buffer->data + prz->buffer_size;
-	uint8_t *block;
-	uint8_t *par;
-	int ecc_block_size = prz->ecc_block_size;
-	int ecc_size = prz->ecc_size;
-	int size = prz->ecc_block_size;
-
-	if (!prz->ecc)
-		return;
-
-	block = buffer->data + (start & ~(ecc_block_size - 1));
-	par = prz->par_buffer + (start / ecc_block_size) * prz->ecc_size;
-
-	do {
-		if (block + ecc_block_size > buffer_end)
-			size = buffer_end - block;
-		persistent_ram_encode_rs8(prz, block, size, par);
-		block += ecc_block_size;
-		par += ecc_size;
-	} while (block < buffer->data + start + count);
-}
-
-static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
-{
-	struct persistent_ram_buffer *buffer = prz->buffer;
-
-	if (!prz->ecc)
-		return;
-
-	persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
-				  prz->par_header);
-}
-
-static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
-{
-	struct persistent_ram_buffer *buffer = prz->buffer;
-	uint8_t *block;
-	uint8_t *par;
-
-	if (!prz->ecc)
-		return;
-
-	block = buffer->data;
-	par = prz->par_buffer;
-	while (block < buffer->data + buffer_size(prz)) {
-		int numerr;
-		int size = prz->ecc_block_size;
-		if (block + size > buffer->data + prz->buffer_size)
-			size = buffer->data + prz->buffer_size - block;
-		numerr = persistent_ram_decode_rs8(prz, block, size, par);
-		if (numerr > 0) {
-			pr_devel("persistent_ram: error in block %p, %d\n",
-			       block, numerr);
-			prz->corrected_bytes += numerr;
-		} else if (numerr < 0) {
-			pr_devel("persistent_ram: uncorrectable error in block %p\n",
-				block);
-			prz->bad_blocks++;
-		}
-		block += prz->ecc_block_size;
-		par += prz->ecc_size;
-	}
-}
-
-static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
-	size_t buffer_size)
-{
-	int numerr;
-	struct persistent_ram_buffer *buffer = prz->buffer;
-	int ecc_blocks;
-
-	if (!prz->ecc)
-		return 0;
-
-	prz->ecc_block_size = 128;
-	prz->ecc_size = 16;
-	prz->ecc_symsize = 8;
-	prz->ecc_poly = 0x11d;
-
-	ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
-	prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
-
-	if (prz->buffer_size > buffer_size) {
-		pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
-		       buffer_size, prz->buffer_size);
-		return -EINVAL;
-	}
-
-	prz->par_buffer = buffer->data + prz->buffer_size;
-	prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
-
-	/*
-	 * first consecutive root is 0
-	 * primitive element to generate roots = 1
-	 */
-	prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
-				  prz->ecc_size);
-	if (prz->rs_decoder == NULL) {
-		pr_info("persistent_ram: init_rs failed\n");
-		return -EINVAL;
-	}
-
-	prz->corrected_bytes = 0;
-	prz->bad_blocks = 0;
-
-	numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
-					   prz->par_header);
-	if (numerr > 0) {
-		pr_info("persistent_ram: error in header, %d\n", numerr);
-		prz->corrected_bytes += numerr;
-	} else if (numerr < 0) {
-		pr_info("persistent_ram: uncorrectable error in header\n");
-		prz->bad_blocks++;
-	}
-
-	return 0;
-}
-
-ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
-	char *str, size_t len)
-{
-	ssize_t ret;
-
-	if (prz->corrected_bytes || prz->bad_blocks)
-		ret = snprintf(str, len, ""
-			"\n%d Corrected bytes, %d unrecoverable blocks\n",
-			prz->corrected_bytes, prz->bad_blocks);
-	else
-		ret = snprintf(str, len, "\nNo errors detected\n");
-
-	return ret;
-}
-
-static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
-	const void *s, unsigned int start, unsigned int count)
-{
-	struct persistent_ram_buffer *buffer = prz->buffer;
-	memcpy(buffer->data + start, s, count);
-	persistent_ram_update_ecc(prz, start, count);
-}
-
-static void __init
-persistent_ram_save_old(struct persistent_ram_zone *prz)
-{
-	struct persistent_ram_buffer *buffer = prz->buffer;
-	size_t size = buffer_size(prz);
-	size_t start = buffer_start(prz);
-	char *dest;
-
-	persistent_ram_ecc_old(prz);
-
-	dest = kmalloc(size, GFP_KERNEL);
-	if (dest == NULL) {
-		pr_err("persistent_ram: failed to allocate buffer\n");
-		return;
-	}
-
-	prz->old_log = dest;
-	prz->old_log_size = size;
-	memcpy(prz->old_log, &buffer->data[start], size - start);
-	memcpy(prz->old_log + size - start, &buffer->data[0], start);
-}
-
-int notrace persistent_ram_write(struct persistent_ram_zone *prz,
-	const void *s, unsigned int count)
-{
-	int rem;
-	int c = count;
-	size_t start;
-
-	if (unlikely(c > prz->buffer_size)) {
-		s += c - prz->buffer_size;
-		c = prz->buffer_size;
-	}
-
-	buffer_size_add_clamp(prz, c);
-
-	start = buffer_start_add(prz, c);
-
-	rem = prz->buffer_size - start;
-	if (unlikely(rem < c)) {
-		persistent_ram_update(prz, s, start, rem);
-		s += rem;
-		c -= rem;
-		start = 0;
-	}
-	persistent_ram_update(prz, s, start, c);
-
-	persistent_ram_update_header_ecc(prz);
-
-	return count;
-}
-
-size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
-{
-	return prz->old_log_size;
-}
-
-void *persistent_ram_old(struct persistent_ram_zone *prz)
-{
-	return prz->old_log;
-}
-
-void persistent_ram_free_old(struct persistent_ram_zone *prz)
-{
-	kfree(prz->old_log);
-	prz->old_log = NULL;
-	prz->old_log_size = 0;
-}
-
-static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
-		struct persistent_ram_zone *prz)
-{
-	struct page **pages;
-	phys_addr_t page_start;
-	unsigned int page_count;
-	pgprot_t prot;
-	unsigned int i;
-
-	page_start = start - offset_in_page(start);
-	page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
-
-	prot = pgprot_noncached(PAGE_KERNEL);
-
-	pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
-	if (!pages) {
-		pr_err("%s: Failed to allocate array for %u pages\n", __func__,
-			page_count);
-		return -ENOMEM;
-	}
-
-	for (i = 0; i < page_count; i++) {
-		phys_addr_t addr = page_start + i * PAGE_SIZE;
-		pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
-	}
-	prz->vaddr = vmap(pages, page_count, VM_MAP, prot);
-	kfree(pages);
-	if (!prz->vaddr) {
-		pr_err("%s: Failed to map %u pages\n", __func__, page_count);
-		return -ENOMEM;
-	}
-
-	prz->buffer = prz->vaddr + offset_in_page(start);
-	prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
-
-	return 0;
-}
-
-static int __init persistent_ram_buffer_init(const char *name,
-		struct persistent_ram_zone *prz)
-{
-	int i;
-	struct persistent_ram *ram;
-	struct persistent_ram_descriptor *desc;
-	phys_addr_t start;
-
-	list_for_each_entry(ram, &persistent_ram_list, node) {
-		start = ram->start;
-		for (i = 0; i < ram->num_descs; i++) {
-			desc = &ram->descs[i];
-			if (!strcmp(desc->name, name))
-				return persistent_ram_buffer_map(start,
-						desc->size, prz);
-			start += desc->size;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static  __init
-struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
-{
-	struct persistent_ram_zone *prz;
-	int ret = -ENOMEM;
-
-	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
-	if (!prz) {
-		pr_err("persistent_ram: failed to allocate persistent ram zone\n");
-		goto err;
-	}
-
-	INIT_LIST_HEAD(&prz->node);
-
-	ret = persistent_ram_buffer_init(dev_name(dev), prz);
-	if (ret) {
-		pr_err("persistent_ram: failed to initialize buffer\n");
-		goto err;
-	}
-
-	prz->ecc = ecc;
-	ret = persistent_ram_init_ecc(prz, prz->buffer_size);
-	if (ret)
-		goto err;
-
-	if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
-		if (buffer_size(prz) > prz->buffer_size ||
-		    buffer_start(prz) > buffer_size(prz))
-			pr_info("persistent_ram: found existing invalid buffer,"
-				" size %ld, start %ld\n",
-			       buffer_size(prz), buffer_start(prz));
-		else {
-			pr_info("persistent_ram: found existing buffer,"
-				" size %ld, start %ld\n",
-			       buffer_size(prz), buffer_start(prz));
-			persistent_ram_save_old(prz);
-		}
-	} else {
-		pr_info("persistent_ram: no valid data in buffer"
-			" (sig = 0x%08x)\n", prz->buffer->sig);
-	}
-
-	prz->buffer->sig = PERSISTENT_RAM_SIG;
-	atomic_set(&prz->buffer->start, 0);
-	atomic_set(&prz->buffer->size, 0);
-
-	return prz;
-err:
-	kfree(prz);
-	return ERR_PTR(ret);
-}
-
-struct persistent_ram_zone * __init
-persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
-{
-	return __persistent_ram_init(dev, ecc);
-}
-
-int __init persistent_ram_early_init(struct persistent_ram *ram)
-{
-	int ret;
-
-	ret = memblock_reserve(ram->start, ram->size);
-	if (ret) {
-		pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
-			(long)ram->start, (long)(ram->start + ram->size - 1));
-		return ret;
-	}
-
-	list_add_tail(&ram->node, &persistent_ram_list);
-
-	pr_info("Initialized persistent memory from %08lx-%08lx\n",
-		(long)ram->start, (long)(ram->start + ram->size - 1));
-
-	return 0;
-}
diff --git a/drivers/staging/android/persistent_ram.h b/drivers/staging/android/persistent_ram.h
deleted file mode 100644
index f41e208..0000000
--- a/drivers/staging/android/persistent_ram.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2011 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __LINUX_PERSISTENT_RAM_H__
-#define __LINUX_PERSISTENT_RAM_H__
-
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/types.h>
-
-struct persistent_ram_buffer;
-
-struct persistent_ram_descriptor {
-	const char	*name;
-	phys_addr_t	size;
-};
-
-struct persistent_ram {
-	phys_addr_t	start;
-	phys_addr_t	size;
-
-	int					num_descs;
-	struct persistent_ram_descriptor	*descs;
-
-	struct list_head node;
-};
-
-struct persistent_ram_zone {
-	struct list_head node;
-	void *vaddr;
-	struct persistent_ram_buffer *buffer;
-	size_t buffer_size;
-
-	/* ECC correction */
-	bool ecc;
-	char *par_buffer;
-	char *par_header;
-	struct rs_control *rs_decoder;
-	int corrected_bytes;
-	int bad_blocks;
-	int ecc_block_size;
-	int ecc_size;
-	int ecc_symsize;
-	int ecc_poly;
-
-	char *old_log;
-	size_t old_log_size;
-	size_t old_log_footer_size;
-	bool early;
-};
-
-int persistent_ram_early_init(struct persistent_ram *ram);
-
-struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev,
-		bool ecc);
-
-int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
-	unsigned int count);
-
-size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
-void *persistent_ram_old(struct persistent_ram_zone *prz);
-void persistent_ram_free_old(struct persistent_ram_zone *prz);
-ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
-	char *str, size_t len);
-
-#endif
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index ce140ff..82323bb 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -21,7 +21,7 @@
 #include <linux/string.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
-#include "persistent_ram.h"
+#include <linux/pstore_ram.h>
 #include "ram_console.h"
 
 static struct persistent_ram_zone *ram_console_zone;
diff --git a/drivers/staging/android/switch/Kconfig b/drivers/staging/android/switch/Kconfig
deleted file mode 100644
index 36846f6..0000000
--- a/drivers/staging/android/switch/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-menuconfig ANDROID_SWITCH
-	tristate "Android Switch class support"
-	help
-	  Say Y here to enable Android switch class support. This allows
-	  monitoring switches by userspace via sysfs and uevent.
-
-config ANDROID_SWITCH_GPIO
-	tristate "Android GPIO Switch support"
-	depends on GENERIC_GPIO && ANDROID_SWITCH
-	help
-	  Say Y here to enable GPIO based switch support.
diff --git a/drivers/staging/android/switch/Makefile b/drivers/staging/android/switch/Makefile
deleted file mode 100644
index d76bfdc..0000000
--- a/drivers/staging/android/switch/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# Android Switch Class Driver
-obj-$(CONFIG_ANDROID_SWITCH)		+= switch_class.o
-obj-$(CONFIG_ANDROID_SWITCH_GPIO)	+= switch_gpio.o
-
diff --git a/drivers/staging/android/switch/switch.h b/drivers/staging/android/switch/switch.h
deleted file mode 100644
index 4fcb310..0000000
--- a/drivers/staging/android/switch/switch.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  Switch class driver
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
-*/
-
-#ifndef __LINUX_SWITCH_H__
-#define __LINUX_SWITCH_H__
-
-struct switch_dev {
-	const char	*name;
-	struct device	*dev;
-	int		index;
-	int		state;
-
-	ssize_t	(*print_name)(struct switch_dev *sdev, char *buf);
-	ssize_t	(*print_state)(struct switch_dev *sdev, char *buf);
-};
-
-struct gpio_switch_platform_data {
-	const char *name;
-	unsigned	gpio;
-
-	/* if NULL, switch_dev.name will be printed */
-	const char *name_on;
-	const char *name_off;
-	/* if NULL, "0" or "1" will be printed */
-	const char *state_on;
-	const char *state_off;
-};
-
-extern int switch_dev_register(struct switch_dev *sdev);
-extern void switch_dev_unregister(struct switch_dev *sdev);
-
-static inline int switch_get_state(struct switch_dev *sdev)
-{
-	return sdev->state;
-}
-
-extern void switch_set_state(struct switch_dev *sdev, int state);
-
-#endif /* __LINUX_SWITCH_H__ */
diff --git a/drivers/staging/android/switch/switch_class.c b/drivers/staging/android/switch/switch_class.c
deleted file mode 100644
index 7468044..0000000
--- a/drivers/staging/android/switch/switch_class.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * switch_class.c
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
-*/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include "switch.h"
-
-struct class *switch_class;
-static atomic_t device_count;
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
-		char *buf)
-{
-	struct switch_dev *sdev = (struct switch_dev *)
-		dev_get_drvdata(dev);
-
-	if (sdev->print_state) {
-		int ret = sdev->print_state(sdev, buf);
-		if (ret >= 0)
-			return ret;
-	}
-	return sprintf(buf, "%d\n", sdev->state);
-}
-
-static ssize_t name_show(struct device *dev, struct device_attribute *attr,
-		char *buf)
-{
-	struct switch_dev *sdev = (struct switch_dev *)
-		dev_get_drvdata(dev);
-
-	if (sdev->print_name) {
-		int ret = sdev->print_name(sdev, buf);
-		if (ret >= 0)
-			return ret;
-	}
-	return sprintf(buf, "%s\n", sdev->name);
-}
-
-static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, state_show, NULL);
-static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, name_show, NULL);
-
-void switch_set_state(struct switch_dev *sdev, int state)
-{
-	char name_buf[120];
-	char state_buf[120];
-	char *prop_buf;
-	char *envp[3];
-	int env_offset = 0;
-	int length;
-
-	if (sdev->state != state) {
-		sdev->state = state;
-
-		prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
-		if (prop_buf) {
-			length = name_show(sdev->dev, NULL, prop_buf);
-			if (length > 0) {
-				if (prop_buf[length - 1] == '\n')
-					prop_buf[length - 1] = 0;
-				snprintf(name_buf, sizeof(name_buf),
-					"SWITCH_NAME=%s", prop_buf);
-				envp[env_offset++] = name_buf;
-			}
-			length = state_show(sdev->dev, NULL, prop_buf);
-			if (length > 0) {
-				if (prop_buf[length - 1] == '\n')
-					prop_buf[length - 1] = 0;
-				snprintf(state_buf, sizeof(state_buf),
-					"SWITCH_STATE=%s", prop_buf);
-				envp[env_offset++] = state_buf;
-			}
-			envp[env_offset] = NULL;
-			kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp);
-			free_page((unsigned long)prop_buf);
-		} else {
-			printk(KERN_ERR "out of memory in switch_set_state\n");
-			kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE);
-		}
-	}
-}
-EXPORT_SYMBOL_GPL(switch_set_state);
-
-static int create_switch_class(void)
-{
-	if (!switch_class) {
-		switch_class = class_create(THIS_MODULE, "switch");
-		if (IS_ERR(switch_class))
-			return PTR_ERR(switch_class);
-		atomic_set(&device_count, 0);
-	}
-
-	return 0;
-}
-
-int switch_dev_register(struct switch_dev *sdev)
-{
-	int ret;
-
-	if (!switch_class) {
-		ret = create_switch_class();
-		if (ret < 0)
-			return ret;
-	}
-
-	sdev->index = atomic_inc_return(&device_count);
-	sdev->dev = device_create(switch_class, NULL,
-		MKDEV(0, sdev->index), NULL, sdev->name);
-	if (IS_ERR(sdev->dev))
-		return PTR_ERR(sdev->dev);
-
-	ret = device_create_file(sdev->dev, &dev_attr_state);
-	if (ret < 0)
-		goto err_create_file_1;
-	ret = device_create_file(sdev->dev, &dev_attr_name);
-	if (ret < 0)
-		goto err_create_file_2;
-
-	dev_set_drvdata(sdev->dev, sdev);
-	sdev->state = 0;
-	return 0;
-
-err_create_file_2:
-	device_remove_file(sdev->dev, &dev_attr_state);
-err_create_file_1:
-	device_destroy(switch_class, MKDEV(0, sdev->index));
-	printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(switch_dev_register);
-
-void switch_dev_unregister(struct switch_dev *sdev)
-{
-	device_remove_file(sdev->dev, &dev_attr_name);
-	device_remove_file(sdev->dev, &dev_attr_state);
-	device_destroy(switch_class, MKDEV(0, sdev->index));
-	dev_set_drvdata(sdev->dev, NULL);
-}
-EXPORT_SYMBOL_GPL(switch_dev_unregister);
-
-static int __init switch_class_init(void)
-{
-	return create_switch_class();
-}
-
-static void __exit switch_class_exit(void)
-{
-	class_destroy(switch_class);
-}
-
-module_init(switch_class_init);
-module_exit(switch_class_exit);
-
-MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
-MODULE_DESCRIPTION("Switch class driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/android/switch/switch_gpio.c b/drivers/staging/android/switch/switch_gpio.c
deleted file mode 100644
index 38b2c2f..0000000
--- a/drivers/staging/android/switch/switch_gpio.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * switch_gpio.c
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/gpio.h>
-#include "switch.h"
-
-struct gpio_switch_data {
-	struct switch_dev sdev;
-	unsigned gpio;
-	const char *name_on;
-	const char *name_off;
-	const char *state_on;
-	const char *state_off;
-	int irq;
-	struct work_struct work;
-};
-
-static void gpio_switch_work(struct work_struct *work)
-{
-	int state;
-	struct gpio_switch_data	*data =
-		container_of(work, struct gpio_switch_data, work);
-
-	state = gpio_get_value(data->gpio);
-	switch_set_state(&data->sdev, state);
-}
-
-static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
-{
-	struct gpio_switch_data *switch_data =
-	    (struct gpio_switch_data *)dev_id;
-
-	schedule_work(&switch_data->work);
-	return IRQ_HANDLED;
-}
-
-static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf)
-{
-	struct gpio_switch_data	*switch_data =
-		container_of(sdev, struct gpio_switch_data, sdev);
-	const char *state;
-	if (switch_get_state(sdev))
-		state = switch_data->state_on;
-	else
-		state = switch_data->state_off;
-
-	if (state)
-		return sprintf(buf, "%s\n", state);
-	return -1;
-}
-
-static int gpio_switch_probe(struct platform_device *pdev)
-{
-	struct gpio_switch_platform_data *pdata = pdev->dev.platform_data;
-	struct gpio_switch_data *switch_data;
-	int ret = 0;
-
-	if (!pdata)
-		return -EBUSY;
-
-	switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL);
-	if (!switch_data)
-		return -ENOMEM;
-
-	switch_data->sdev.name = pdata->name;
-	switch_data->gpio = pdata->gpio;
-	switch_data->name_on = pdata->name_on;
-	switch_data->name_off = pdata->name_off;
-	switch_data->state_on = pdata->state_on;
-	switch_data->state_off = pdata->state_off;
-	switch_data->sdev.print_state = switch_gpio_print_state;
-
-	ret = switch_dev_register(&switch_data->sdev);
-	if (ret < 0)
-		goto err_switch_dev_register;
-
-	ret = gpio_request(switch_data->gpio, pdev->name);
-	if (ret < 0)
-		goto err_request_gpio;
-
-	ret = gpio_direction_input(switch_data->gpio);
-	if (ret < 0)
-		goto err_set_gpio_input;
-
-	INIT_WORK(&switch_data->work, gpio_switch_work);
-
-	switch_data->irq = gpio_to_irq(switch_data->gpio);
-	if (switch_data->irq < 0) {
-		ret = switch_data->irq;
-		goto err_detect_irq_num_failed;
-	}
-
-	ret = request_irq(switch_data->irq, gpio_irq_handler,
-			  IRQF_TRIGGER_LOW, pdev->name, switch_data);
-	if (ret < 0)
-		goto err_request_irq;
-
-	/* Perform initial detection */
-	gpio_switch_work(&switch_data->work);
-
-	return 0;
-
-err_request_irq:
-err_detect_irq_num_failed:
-err_set_gpio_input:
-	gpio_free(switch_data->gpio);
-err_request_gpio:
-	switch_dev_unregister(&switch_data->sdev);
-err_switch_dev_register:
-	kfree(switch_data);
-
-	return ret;
-}
-
-static int __devexit gpio_switch_remove(struct platform_device *pdev)
-{
-	struct gpio_switch_data *switch_data = platform_get_drvdata(pdev);
-
-	cancel_work_sync(&switch_data->work);
-	gpio_free(switch_data->gpio);
-	switch_dev_unregister(&switch_data->sdev);
-	kfree(switch_data);
-
-	return 0;
-}
-
-static struct platform_driver gpio_switch_driver = {
-	.probe		= gpio_switch_probe,
-	.remove		= __devexit_p(gpio_switch_remove),
-	.driver		= {
-		.name	= "switch-gpio",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init gpio_switch_init(void)
-{
-	return platform_driver_register(&gpio_switch_driver);
-}
-
-static void __exit gpio_switch_exit(void)
-{
-	platform_driver_unregister(&gpio_switch_driver);
-}
-
-module_init(gpio_switch_init);
-module_exit(gpio_switch_exit);
-
-MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
-MODULE_DESCRIPTION("GPIO Switch driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c
index f373422..38d930c 100644
--- a/drivers/staging/android/timed_output.c
+++ b/drivers/staging/android/timed_output.c
@@ -99,6 +99,7 @@
 
 void timed_output_dev_unregister(struct timed_output_dev *tdev)
 {
+	tdev->enable(tdev, 0);
 	device_remove_file(tdev->dev, &dev_attr_enable);
 	device_destroy(timed_output_class, MKDEV(0, tdev->index));
 	dev_set_drvdata(tdev->dev, NULL);
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
index 83549d9..510d796 100644
--- a/drivers/staging/asus_oled/asus_oled.c
+++ b/drivers/staging/asus_oled/asus_oled.c
@@ -782,20 +782,20 @@
 	oled_class = class_create(THIS_MODULE, ASUS_OLED_UNDERSCORE_NAME);
 
 	if (IS_ERR(oled_class)) {
-		err("Error creating " ASUS_OLED_UNDERSCORE_NAME " class");
+		printk(KERN_ERR "Error creating " ASUS_OLED_UNDERSCORE_NAME " class\n");
 		return PTR_ERR(oled_class);
 	}
 
 	retval = class_create_file(oled_class, &class_attr_version.attr);
 	if (retval) {
-		err("Error creating class version file");
+		printk(KERN_ERR "Error creating class version file\n");
 		goto error;
 	}
 
 	retval = usb_register(&oled_driver);
 
 	if (retval) {
-		err("usb_register failed. Error number %d", retval);
+		printk(KERN_ERR "usb_register failed. Error number %d\n", retval);
 		goto error;
 	}
 
diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h
index 20cca24..aa51d17 100644
--- a/drivers/staging/bcm/Adapter.h
+++ b/drivers/staging/bcm/Adapter.h
@@ -7,168 +7,145 @@
 #define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256
 #include "Debug.h"
 
-struct _LEADER
-{
-	USHORT 	Vcid;
-	USHORT 	PLength;
-	UCHAR  	Status;
+struct _LEADER {
+	USHORT	Vcid;
+	USHORT	PLength;
+	UCHAR	Status;
 	UCHAR	Unused[3];
-}__attribute__((packed));
-typedef struct _LEADER LEADER,*PLEADER;
+} __packed;
+typedef struct _LEADER LEADER, *PLEADER;
 
-struct _PACKETTOSEND
-{
+struct _PACKETTOSEND {
 	LEADER	Leader;
 	UCHAR	ucPayload;
-}__attribute__((packed));
+} __packed;
 typedef struct _PACKETTOSEND PACKETTOSEND, *PPACKETTOSEND;
 
-
-struct _CONTROL_PACKET
-{
+struct _CONTROL_PACKET {
 	PVOID	ControlBuff;
 	UINT	ControlBuffLen;
-	struct _CONTROL_PACKET* next;
-}__attribute__((packed));
-typedef struct _CONTROL_PACKET CONTROL_PACKET,*PCONTROL_PACKET;
+	struct _CONTROL_PACKET *next;
+} __packed;
+typedef struct _CONTROL_PACKET CONTROL_PACKET, *PCONTROL_PACKET;
 
-
-struct link_request
-{
+struct link_request {
 	LEADER	Leader;
 	UCHAR	szData[4];
-}__attribute__((packed));
+} __packed;
 typedef struct link_request LINK_REQUEST, *PLINK_REQUEST;
 
+/* classification extension is added */
+typedef struct _ADD_CONNECTION {
+	ULONG	SrcIpAddressCount;
+	ULONG	SrcIpAddress[MAX_CONNECTIONS];
+	ULONG	SrcIpMask[MAX_CONNECTIONS];
 
-//classification extension is added
-typedef struct _ADD_CONNECTION
-{
-    ULONG 		SrcIpAddressCount;
-    ULONG 		SrcIpAddress[MAX_CONNECTIONS];
-    ULONG 		SrcIpMask[MAX_CONNECTIONS];
+	ULONG	DestIpAddressCount;
+	ULONG	DestIpAddress[MAX_CONNECTIONS];
+	ULONG	DestIpMask[MAX_CONNECTIONS];
 
-    ULONG 		DestIpAddressCount;
-    ULONG 		DestIpAddress[MAX_CONNECTIONS];
-    ULONG 		DestIpMask[MAX_CONNECTIONS];
+	USHORT	SrcPortBegin;
+	USHORT	SrcPortEnd;
 
-    USHORT 		SrcPortBegin;
-    USHORT 		SrcPortEnd;
+	USHORT	DestPortBegin;
+	USHORT	DestPortEnd;
 
-    USHORT 		DestPortBegin;
-    USHORT 		DestPortEnd;
+	UCHAR	SrcTOS;
+	UCHAR	SrcProtocol;
+} ADD_CONNECTION, *PADD_CONNECTION;
 
-    UCHAR 		SrcTOS;
-    UCHAR 		SrcProtocol;
-} ADD_CONNECTION,*PADD_CONNECTION;
+typedef struct _CLASSIFICATION_RULE {
+	UCHAR	ucIPSrcAddrLen;
+	UCHAR	ucIPSrcAddr[32];
+	UCHAR	ucIPDestAddrLen;
+	UCHAR	ucIPDestAddr[32];
+	UCHAR	ucSrcPortRangeLen;
+	UCHAR	ucSrcPortRange[4];
+	UCHAR	ucDestPortRangeLen;
+	UCHAR	ucDestPortRange[4];
+	USHORT	usVcid;
+} CLASSIFICATION_RULE, *PCLASSIFICATION_RULE;
 
-
-typedef struct _CLASSIFICATION_RULE
-{
-	UCHAR		ucIPSrcAddrLen;
-	UCHAR       ucIPSrcAddr[32];
-	UCHAR		ucIPDestAddrLen;
-	UCHAR       ucIPDestAddr[32];
-	UCHAR		ucSrcPortRangeLen;
-	UCHAR		ucSrcPortRange[4];
-	UCHAR		ucDestPortRangeLen;
-	UCHAR		ucDestPortRange[4];
-	USHORT		usVcid;
-} CLASSIFICATION_RULE,*PCLASSIFICATION_RULE;
-
-typedef struct _CLASSIFICATION_ONLY
-{
-    USHORT 		usVcid;
-    ULONG  		DestIpAddress;
-    ULONG  		DestIpMask;
-    USHORT 		usPortLo;
-    USHORT 		usPortHi;
-    BOOLEAN		bIpVersion;
-    UCHAR		ucDestinationAddress[16];
+typedef struct _CLASSIFICATION_ONLY {
+	USHORT	usVcid;
+	ULONG	DestIpAddress;
+	ULONG	DestIpMask;
+	USHORT	usPortLo;
+	USHORT	usPortHi;
+	BOOLEAN	bIpVersion;
+	UCHAR	ucDestinationAddress[16];
 } CLASSIFICATION_ONLY, *PCLASSIFICATION_ONLY;
 
-
 #define MAX_IP_RANGE_LENGTH 4
 #define MAX_PORT_RANGE 4
 #define MAX_PROTOCOL_LENGTH   32
 #define IPV6_ADDRESS_SIZEINBYTES 0x10
 
-typedef union _U_IP_ADDRESS
-{
-    struct
-	{
-		ULONG				ulIpv4Addr[MAX_IP_RANGE_LENGTH];//Source Ip Address Range
-		ULONG               ulIpv4Mask[MAX_IP_RANGE_LENGTH];//Source Ip Mask Address Range
+typedef union _U_IP_ADDRESS {
+	struct {
+		ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH]; /* Source Ip Address Range */
+		ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH]; /* Source Ip Mask Address Range */
 	};
-	struct
-	{
-		ULONG				ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4];//Source Ip Address Range
-		ULONG               ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4];//Source Ip Mask Address Range
-
+	struct {
+		ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Address Range */
+		ULONG ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Mask Address Range */
 	};
-	struct
-	{
-		UCHAR				ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
-		UCHAR				ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
+	struct {
+		UCHAR ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
+		UCHAR ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
 	};
-	struct
-	{
-		UCHAR				ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
-		UCHAR				ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
+	struct {
+		UCHAR ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
+		UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
 	};
-}U_IP_ADDRESS;
+} U_IP_ADDRESS;
 struct _packet_info;
 
-typedef struct _S_HDR_SUPRESSION_CONTEXTINFO
-{
+typedef struct _S_HDR_SUPRESSION_CONTEXTINFO {
+	UCHAR ucaHdrSupressionInBuf[MAX_PHS_LENGTHS]; /* Intermediate buffer to accumulate pkt Header for PHS */
+	UCHAR ucaHdrSupressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; /* Intermediate buffer containing pkt Header after PHS */
+} S_HDR_SUPRESSION_CONTEXTINFO;
 
-	UCHAR      ucaHdrSupressionInBuf[MAX_PHS_LENGTHS]; //Intermediate buffer to accumulate pkt Header for PHS
-	UCHAR      ucaHdrSupressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; //Intermediate buffer containing pkt Header after PHS
-
-}S_HDR_SUPRESSION_CONTEXTINFO;
-
-
-typedef struct _S_CLASSIFIER_RULE
-{
-	ULONG			ulSFID;
-	UCHAR           ucReserved[2];
-	B_UINT16        uiClassifierRuleIndex;
-	BOOLEAN			bUsed;
-	USHORT			usVCID_Value;
-	B_UINT8         u8ClassifierRulePriority; //This field detemines the Classifier Priority
+typedef struct _S_CLASSIFIER_RULE {
+	ULONG		ulSFID;
+	UCHAR		ucReserved[2];
+	B_UINT16	uiClassifierRuleIndex;
+	BOOLEAN		bUsed;
+	USHORT		usVCID_Value;
+	B_UINT8		u8ClassifierRulePriority; /* This field detemines the Classifier Priority */
 	U_IP_ADDRESS	stSrcIpAddress;
-	UCHAR           ucIPSourceAddressLength;//Ip Source Address Length
+	UCHAR		ucIPSourceAddressLength; /* Ip Source Address Length */
 
-	U_IP_ADDRESS    stDestIpAddress;
-    UCHAR           ucIPDestinationAddressLength;//Ip Destination Address Length
-    UCHAR           ucIPTypeOfServiceLength;//Type of service Length
-    UCHAR           ucTosLow;//Tos Low
-    UCHAR           ucTosHigh;//Tos High
-	UCHAR           ucTosMask;//Tos Mask
+	U_IP_ADDRESS	stDestIpAddress;
+	UCHAR		ucIPDestinationAddressLength; /* Ip Destination Address Length */
+	UCHAR		ucIPTypeOfServiceLength; /* Type of service Length */
+	UCHAR		ucTosLow; /* Tos Low */
+	UCHAR		ucTosHigh; /* Tos High */
+	UCHAR		ucTosMask; /* Tos Mask */
 
-    UCHAR           ucProtocolLength;//protocol Length
-    UCHAR           ucProtocol[MAX_PROTOCOL_LENGTH];//protocol Length
-    USHORT			usSrcPortRangeLo[MAX_PORT_RANGE];
-	USHORT			usSrcPortRangeHi[MAX_PORT_RANGE];
-    UCHAR           ucSrcPortRangeLength;
+	UCHAR		ucProtocolLength; /* protocol Length */
+	UCHAR		ucProtocol[MAX_PROTOCOL_LENGTH]; /* protocol Length */
+	USHORT		usSrcPortRangeLo[MAX_PORT_RANGE];
+	USHORT		usSrcPortRangeHi[MAX_PORT_RANGE];
+	UCHAR		ucSrcPortRangeLength;
 
-    USHORT			usDestPortRangeLo[MAX_PORT_RANGE];
-	USHORT			usDestPortRangeHi[MAX_PORT_RANGE];
-    UCHAR           ucDestPortRangeLength;
+	USHORT		usDestPortRangeLo[MAX_PORT_RANGE];
+	USHORT		usDestPortRangeHi[MAX_PORT_RANGE];
+	UCHAR		ucDestPortRangeLength;
 
-	BOOLEAN			bProtocolValid;
-	BOOLEAN			bTOSValid;
-	BOOLEAN			bDestIpValid;
-	BOOLEAN			bSrcIpValid;
+	BOOLEAN		bProtocolValid;
+	BOOLEAN		bTOSValid;
+	BOOLEAN		bDestIpValid;
+	BOOLEAN		bSrcIpValid;
 
-	//For IPv6 Addressing
-	UCHAR			ucDirection;
-	BOOLEAN         bIpv6Protocol;
-	UINT32          u32PHSRuleID;
-	S_PHS_RULE 	    sPhsRule;
-	UCHAR			u8AssociatedPHSI;
+	/* For IPv6 Addressing */
+	UCHAR		ucDirection;
+	BOOLEAN		bIpv6Protocol;
+	UINT32		u32PHSRuleID;
+	S_PHS_RULE	sPhsRule;
+	UCHAR		u8AssociatedPHSI;
 
-	//Classification fields for ETH CS
+	/* Classification fields for ETH CS */
 	UCHAR		ucEthCSSrcMACLen;
 	UCHAR		au8EThCSSrcMAC[MAC_ADDRESS_SIZE];
 	UCHAR		au8EThCSSrcMACMask[MAC_ADDRESS_SIZE];
@@ -180,71 +157,67 @@
 	UCHAR		usUserPriority[2];
 	USHORT		usVLANID;
 	USHORT		usValidityBitMap;
-}S_CLASSIFIER_RULE;
-//typedef struct _S_CLASSIFIER_RULE S_CLASSIFIER_RULE;
+} S_CLASSIFIER_RULE;
+/* typedef struct _S_CLASSIFIER_RULE S_CLASSIFIER_RULE; */
 
-typedef struct _S_FRAGMENTED_PACKET_INFO
-{
-	BOOLEAN				bUsed;
-	ULONG		        ulSrcIpAddress;
-	USHORT 				usIpIdentification;
-	S_CLASSIFIER_RULE 	*pstMatchedClassifierEntry;
-	BOOLEAN				bOutOfOrderFragment;
-}S_FRAGMENTED_PACKET_INFO,*PS_FRAGMENTED_PACKET_INFO;
+typedef struct _S_FRAGMENTED_PACKET_INFO {
+	BOOLEAN			bUsed;
+	ULONG			ulSrcIpAddress;
+	USHORT			usIpIdentification;
+	S_CLASSIFIER_RULE	*pstMatchedClassifierEntry;
+	BOOLEAN			bOutOfOrderFragment;
+} S_FRAGMENTED_PACKET_INFO, *PS_FRAGMENTED_PACKET_INFO;
 
-struct _packet_info
-{
-	//classification extension Rule
-   	ULONG			ulSFID;
-   	USHORT			usVCID_Value;
-	UINT			uiThreshold;
-	// This field determines the priority of the SF Queues
-	B_UINT8     	u8TrafficPriority;
+struct _packet_info {
+	/* classification extension Rule */
+	ULONG		ulSFID;
+	USHORT		usVCID_Value;
+	UINT		uiThreshold;
+	/* This field determines the priority of the SF Queues */
+	B_UINT8		u8TrafficPriority;
 
-	BOOLEAN			bValid;
-   	BOOLEAN     	bActive;
-	BOOLEAN			bActivateRequestSent;
+	BOOLEAN		bValid;
+	BOOLEAN		bActive;
+	BOOLEAN		bActivateRequestSent;
 
-	B_UINT8			u8QueueType;//BE or rtPS
+	B_UINT8		u8QueueType; /* BE or rtPS */
 
-	UINT			uiMaxBucketSize;//maximum size of the bucket for the queue
-	UINT			uiCurrentQueueDepthOnTarget;
-	UINT			uiCurrentBytesOnHost;
-	UINT			uiCurrentPacketsOnHost;
-	UINT			uiDroppedCountBytes;
-	UINT			uiDroppedCountPackets;
-	UINT			uiSentBytes;
-	UINT			uiSentPackets;
-	UINT			uiCurrentDrainRate;
-	UINT			uiThisPeriodSentBytes;
+	UINT		uiMaxBucketSize; /* maximum size of the bucket for the queue */
+	UINT		uiCurrentQueueDepthOnTarget;
+	UINT		uiCurrentBytesOnHost;
+	UINT		uiCurrentPacketsOnHost;
+	UINT		uiDroppedCountBytes;
+	UINT		uiDroppedCountPackets;
+	UINT		uiSentBytes;
+	UINT		uiSentPackets;
+	UINT		uiCurrentDrainRate;
+	UINT		uiThisPeriodSentBytes;
 	LARGE_INTEGER	liDrainCalculated;
-	UINT			uiCurrentTokenCount;
-	LARGE_INTEGER 	liLastUpdateTokenAt;
-	UINT			uiMaxAllowedRate;
-	UINT			NumOfPacketsSent;
-	UCHAR			ucDirection;
-	USHORT			usCID;
+	UINT		uiCurrentTokenCount;
+	LARGE_INTEGER	liLastUpdateTokenAt;
+	UINT		uiMaxAllowedRate;
+	UINT		NumOfPacketsSent;
+	UCHAR		ucDirection;
+	USHORT		usCID;
 	S_MIBS_EXTSERVICEFLOW_PARAMETERS	stMibsExtServiceFlowTable;
-	UINT			uiCurrentRxRate;
-	UINT			uiThisPeriodRxBytes;
-	UINT			uiTotalRxBytes;
-	UINT			uiTotalTxBytes;
-	UINT			uiPendedLast;
-	UCHAR			ucIpVersion;
+	UINT		uiCurrentRxRate;
+	UINT		uiThisPeriodRxBytes;
+	UINT		uiTotalRxBytes;
+	UINT		uiTotalTxBytes;
+	UINT		uiPendedLast;
+	UCHAR		ucIpVersion;
 
-	union
-	{
-		struct
-		{
-			struct sk_buff*	   FirstTxQueue;
-			struct sk_buff*	   LastTxQueue;
+	union {
+		struct {
+			struct sk_buff *FirstTxQueue;
+			struct sk_buff *LastTxQueue;
 		};
-		struct
-		{
-			struct sk_buff*	   ControlHead;
-			struct sk_buff*	   ControlTail;
+		struct {
+			struct sk_buff *ControlHead;
+			struct sk_buff *ControlTail;
 		};
 	};
+
 	BOOLEAN		bProtocolValid;
 	BOOLEAN		bTOSValid;
 	BOOLEAN		bDestIpValid;
@@ -255,226 +228,209 @@
 	BOOLEAN		bAuthorizedSet;
 	BOOLEAN		bClassifierPriority;
 	UCHAR		ucServiceClassName[MAX_CLASS_NAME_LENGTH];
-	BOOLEAN     bHeaderSuppressionEnabled;
+	BOOLEAN		bHeaderSuppressionEnabled;
 	spinlock_t	SFQueueLock;
-	void 		*pstSFIndication;
+	void		*pstSFIndication;
 	struct timeval	stLastUpdateTokenAt;
-	atomic_t 	uiPerSFTxResourceCount;
+	atomic_t	uiPerSFTxResourceCount;
 	UINT		uiMaxLatency;
-	UCHAR 	bIPCSSupport;
-	UCHAR 	bEthCSSupport;
+	UCHAR		bIPCSSupport;
+	UCHAR		bEthCSSupport;
 };
 typedef struct _packet_info PacketInfo;
 
-
-typedef struct _PER_TARANG_DATA
-{
-    struct _PER_TARANG_DATA * next;
-    struct _MINI_ADAPTER * Adapter;
-    struct sk_buff*     RxAppControlHead;
-    struct sk_buff*     RxAppControlTail;
-    volatile INT        AppCtrlQueueLen;
-    BOOLEAN             MacTracingEnabled;
-	BOOLEAN				bApplicationToExit;
-	S_MIBS_DROPPED_APP_CNTRL_MESSAGES stDroppedAppCntrlMsgs;
-	ULONG 				RxCntrlMsgBitMask;
+typedef struct _PER_TARANG_DATA {
+	struct _PER_TARANG_DATA	*next;
+	struct _MINI_ADAPTER	*Adapter;
+	struct sk_buff		*RxAppControlHead;
+	struct sk_buff		*RxAppControlTail;
+	int			AppCtrlQueueLen;
+	BOOLEAN			MacTracingEnabled;
+	BOOLEAN			bApplicationToExit;
+	S_MIBS_DROPPED_APP_CNTRL_MESSAGES	stDroppedAppCntrlMsgs;
+	ULONG			RxCntrlMsgBitMask;
 } PER_TARANG_DATA, *PPER_TARANG_DATA;
 
-
 #ifdef REL_4_1
-typedef struct _TARGET_PARAMS
-{
-      B_UINT32 m_u32CfgVersion;
+typedef struct _TARGET_PARAMS {
+	B_UINT32 m_u32CfgVersion;
 
-      // Scanning Related Params
-      B_UINT32 m_u32CenterFrequency;
-      B_UINT32 m_u32BandAScan;
-      B_UINT32 m_u32BandBScan;
-      B_UINT32 m_u32BandCScan;
+	/* Scanning Related Params */
+	B_UINT32 m_u32CenterFrequency;
+	B_UINT32 m_u32BandAScan;
+	B_UINT32 m_u32BandBScan;
+	B_UINT32 m_u32BandCScan;
 
-      // QoS Params
-      B_UINT32 m_u32minGrantsize;	// size of minimum grant is 0 or 6
-      B_UINT32 m_u32PHSEnable;
+	/* QoS Params */
+	B_UINT32 m_u32minGrantsize;	/* size of minimum grant is 0 or 6 */
+	B_UINT32 m_u32PHSEnable;
 
-      // HO Params
-      B_UINT32 m_u32HoEnable;
-      B_UINT32 m_u32HoReserved1;
-      B_UINT32 m_u32HoReserved2;
+	/* HO Params */
+	B_UINT32 m_u32HoEnable;
+	B_UINT32 m_u32HoReserved1;
+	B_UINT32 m_u32HoReserved2;
 
-	// Power Control Params
-      B_UINT32 m_u32MimoEnable;
-      B_UINT32 m_u32SecurityEnable;
+	/* Power Control Params */
+	B_UINT32 m_u32MimoEnable;
+	B_UINT32 m_u32SecurityEnable;
 	/*
-     * bit 1: 1 Idlemode enable;
-     * bit 2: 1 Sleepmode Enable
-     */
-      B_UINT32 m_u32PowerSavingModesEnable;
-	  /* PowerSaving Mode Options:
-	     bit 0 = 1: CPE mode - to keep pcmcia if alive;
-	     bit 1 = 1: CINR reporing in Idlemode Msg
-	     bit 2 = 1: Default PSC Enable in sleepmode*/
-      B_UINT32 m_u32PowerSavingModeOptions;
+	 * bit 1: 1 Idlemode enable;
+	 * bit 2: 1 Sleepmode Enable
+	 */
+	B_UINT32 m_u32PowerSavingModesEnable;
+	/* PowerSaving Mode Options:
+	 * bit 0 = 1: CPE mode - to keep pcmcia if alive;
+	 * bit 1 = 1: CINR reporing in Idlemode Msg
+	 * bit 2 = 1: Default PSC Enable in sleepmode
+	 */
+	B_UINT32 m_u32PowerSavingModeOptions;
 
-      B_UINT32 m_u32ArqEnable;
+	B_UINT32 m_u32ArqEnable;
 
-      // From Version #3, the HARQ section renamed as general
-      B_UINT32 m_u32HarqEnable;
-       // EEPROM Param Location
-       B_UINT32  m_u32EEPROMFlag;
-       /* BINARY TYPE - 4th MSByte:
-        * Interface Type -  3rd MSByte:
-        * Vendor Type - 2nd MSByte
-        */
-       // Unused - LSByte
-      B_UINT32   m_u32Customize;
-      B_UINT32   m_u32ConfigBW;  /* In Hz */
-      B_UINT32   m_u32ShutDownTimer;
-
-
-      B_UINT32  m_u32RadioParameter;
-      B_UINT32  m_u32PhyParameter1;
-      B_UINT32  m_u32PhyParameter2;
-      B_UINT32  m_u32PhyParameter3;
+	/* From Version #3, the HARQ section renamed as general */
+	B_UINT32 m_u32HarqEnable;
+	/* EEPROM Param Location */
+	B_UINT32 m_u32EEPROMFlag;
+	/* BINARY TYPE - 4th MSByte:
+	 * Interface Type -  3rd MSByte:
+	 * Vendor Type - 2nd MSByte
+	 */
+	/* Unused - LSByte */
+	B_UINT32 m_u32Customize;
+	B_UINT32 m_u32ConfigBW;  /* In Hz */
+	B_UINT32 m_u32ShutDownTimer;
+	B_UINT32 m_u32RadioParameter;
+	B_UINT32 m_u32PhyParameter1;
+	B_UINT32 m_u32PhyParameter2;
+	B_UINT32 m_u32PhyParameter3;
 
 	/* in eval mode only;
-     * lower 16bits = basic cid for testing;
-     * then bit 16 is test cqich,
-     * bit 17  test init rang;
-     * bit 18 test periodic rang
-     * bit 19 is test harq ack/nack
-     */
-    B_UINT32	  m_u32TestOptions;
-
+	 * lower 16bits = basic cid for testing;
+	 * then bit 16 is test cqich,
+	 * bit 17  test init rang;
+	 * bit 18 test periodic rang
+	 * bit 19 is test harq ack/nack
+	 */
+	B_UINT32 m_u32TestOptions;
 	B_UINT32 m_u32MaxMACDataperDLFrame;
 	B_UINT32 m_u32MaxMACDataperULFrame;
-
 	B_UINT32 m_u32Corr2MacFlags;
 
-    //adding driver params.
-    B_UINT32 HostDrvrConfig1;
-    B_UINT32 HostDrvrConfig2;
-    B_UINT32 HostDrvrConfig3;
-    B_UINT32 HostDrvrConfig4;
-    B_UINT32 HostDrvrConfig5;
-    B_UINT32 HostDrvrConfig6;
-    B_UINT32 m_u32SegmentedPUSCenable;
+	/* adding driver params. */
+	B_UINT32 HostDrvrConfig1;
+	B_UINT32 HostDrvrConfig2;
+	B_UINT32 HostDrvrConfig3;
+	B_UINT32 HostDrvrConfig4;
+	B_UINT32 HostDrvrConfig5;
+	B_UINT32 HostDrvrConfig6;
+	B_UINT32 m_u32SegmentedPUSCenable;
 
-	//	BAMC enable - but 4.x does not support this feature
-	//	This is added just to sync 4.x and 5.x CFGs
+	/* BAMC enable - but 4.x does not support this feature
+	 * This is added just to sync 4.x and 5.x CFGs
+	 */
 	B_UINT32 m_u32BandAMCEnable;
 } STARGETPARAMS, *PSTARGETPARAMS;
 #endif
 
-typedef struct _STTARGETDSXBUFFER
-{
-    ULONG ulTargetDsxBuffer;
-    B_UINT16 tid;
-    BOOLEAN valid;
-}STTARGETDSXBUFFER, *PSTTARGETDSXBUFFER;
+typedef struct _STTARGETDSXBUFFER {
+	ULONG		ulTargetDsxBuffer;
+	B_UINT16	tid;
+	BOOLEAN		valid;
+} STTARGETDSXBUFFER, *PSTTARGETDSXBUFFER;
 
-typedef INT (*FP_FLASH_WRITE)(struct _MINI_ADAPTER*,UINT,PVOID);
+typedef int (*FP_FLASH_WRITE)(struct _MINI_ADAPTER *, UINT, PVOID);
 
-typedef INT (*FP_FLASH_WRITE_STATUS)(struct _MINI_ADAPTER*,UINT,PVOID);
+typedef int (*FP_FLASH_WRITE_STATUS)(struct _MINI_ADAPTER *, UINT, PVOID);
 
-/**
-Driver adapter data structure
-*/
-struct _MINI_ADAPTER
-{
-	struct _MINI_ADAPTER *next;
+/*
+ * Driver adapter data structure
+ */
+struct _MINI_ADAPTER {
+	struct _MINI_ADAPTER	*next;
 	struct net_device	*dev;
 	u32			msg_enable;
-
-	CHAR                *caDsxReqResp;
+	CHAR			*caDsxReqResp;
 	atomic_t		ApplicationRunning;
-	volatile INT		CtrlQueueLen;
-	atomic_t            	AppCtrlQueueLen;
-	BOOLEAN             	AppCtrlQueueOverFlow;
+	BOOLEAN			AppCtrlQueueOverFlow;
 	atomic_t		CurrentApplicationCount;
-	atomic_t 		RegisteredApplicationCount;
-	BOOLEAN		  	LinkUpStatus;
-	BOOLEAN		    	TimerActive;
+	atomic_t		RegisteredApplicationCount;
+	BOOLEAN			LinkUpStatus;
+	BOOLEAN			TimerActive;
 	u32			StatisticsPointer;
 	struct sk_buff		*RxControlHead;
 	struct sk_buff		*RxControlTail;
-
 	struct semaphore	RxAppControlQueuelock;
 	struct semaphore	fw_download_sema;
-
-	PPER_TARANG_DATA    pTarangs;
-	spinlock_t			control_queue_lock;
+	PPER_TARANG_DATA	pTarangs;
+	spinlock_t		control_queue_lock;
 	wait_queue_head_t	process_read_wait_queue;
 
-	// the pointer to the first packet we have queued in send
-	// deserialized miniport support variables
-	atomic_t		    TotalPacketCount;
-	atomic_t		    TxPktAvail;
+	/* the pointer to the first packet we have queued in send
+	 * deserialized miniport support variables
+	 */
+	atomic_t		TotalPacketCount;
+	atomic_t		TxPktAvail;
 
-	// this to keep track of the Tx and Rx MailBox Registers.
-	atomic_t		    CurrNumFreeTxDesc;
-	// to keep track the no of byte received
-	USHORT				PrevNumRecvDescs;
-	USHORT				CurrNumRecvDescs;
-	UINT				u32TotalDSD;
-	PacketInfo		    PackInfo[NO_OF_QUEUES];
+	/* this to keep track of the Tx and Rx MailBox Registers. */
+	atomic_t		CurrNumFreeTxDesc;
+	/* to keep track the no of byte received */
+	USHORT			PrevNumRecvDescs;
+	USHORT			CurrNumRecvDescs;
+	UINT			u32TotalDSD;
+	PacketInfo		PackInfo[NO_OF_QUEUES];
 	S_CLASSIFIER_RULE	astClassifierTable[MAX_CLASSIFIERS];
-	BOOLEAN			    TransferMode;
+	BOOLEAN			TransferMode;
 
 	/*************** qos ******************/
-	BOOLEAN			    bETHCSEnabled;
+	BOOLEAN			bETHCSEnabled;
+	ULONG			BEBucketSize;
+	ULONG			rtPSBucketSize;
+	UCHAR			LinkStatus;
+	BOOLEAN			AutoLinkUp;
+	BOOLEAN			AutoSyncup;
 
-	ULONG			    BEBucketSize;
-	ULONG			    rtPSBucketSize;
-	UCHAR			    LinkStatus;
-	BOOLEAN			    AutoLinkUp;
-	BOOLEAN			    AutoSyncup;
+	int			major;
+	int			minor;
+	wait_queue_head_t	tx_packet_wait_queue;
+	wait_queue_head_t	process_rx_cntrlpkt;
+	atomic_t		process_waiting;
+	BOOLEAN			fw_download_done;
 
-	int				major;
-	int				minor;
-	wait_queue_head_t 	tx_packet_wait_queue;
-	wait_queue_head_t 	process_rx_cntrlpkt;
-	atomic_t			process_waiting;
-	BOOLEAN 			fw_download_done;
-
-	char 				*txctlpacket[MAX_CNTRL_PKTS];
-	atomic_t			cntrlpktCnt ;
-	atomic_t			index_app_read_cntrlpkt;
-	atomic_t			index_wr_txcntrlpkt;
-	atomic_t			index_rd_txcntrlpkt;
-	UINT				index_datpkt;
-	struct semaphore 	rdmwrmsync;
+	char			*txctlpacket[MAX_CNTRL_PKTS];
+	atomic_t		cntrlpktCnt ;
+	atomic_t		index_app_read_cntrlpkt;
+	atomic_t		index_wr_txcntrlpkt;
+	atomic_t		index_rd_txcntrlpkt;
+	UINT			index_datpkt;
+	struct semaphore	rdmwrmsync;
 
 	STTARGETDSXBUFFER	astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS];
 	ULONG			ulFreeTargetBufferCnt;
-	ULONG              	ulCurrentTargetBuffer;
-	ULONG              	ulTotalTargetBuffersAvailable;
-
-	unsigned long 		chip_id;
-
-	wait_queue_head_t 	lowpower_mode_wait_queue;
-
+	ULONG			ulCurrentTargetBuffer;
+	ULONG			ulTotalTargetBuffersAvailable;
+	unsigned long		chip_id;
+	wait_queue_head_t	lowpower_mode_wait_queue;
 	BOOLEAN			bFlashBoot;
 	BOOLEAN			bBinDownloaded;
 	BOOLEAN			bCfgDownloaded;
 	BOOLEAN			bSyncUpRequestSent;
 	USHORT			usBestEffortQueueIndex;
-
-	wait_queue_head_t 	ioctl_fw_dnld_wait_queue;
-	BOOLEAN				waiting_to_fw_download_done;
-	pid_t				fw_download_process_pid;
+	wait_queue_head_t	ioctl_fw_dnld_wait_queue;
+	BOOLEAN			waiting_to_fw_download_done;
+	pid_t			fw_download_process_pid;
 	PSTARGETPARAMS		pstargetparams;
-	BOOLEAN				device_removed;
-	BOOLEAN				DeviceAccess;
-	BOOLEAN				bIsAutoCorrectEnabled;
-	BOOLEAN				bDDRInitDone;
-	INT				DDRSetting;
-	ULONG				ulPowerSaveMode;
-	spinlock_t			txtransmitlock;
-	B_UINT8				txtransmit_running;
+	BOOLEAN			device_removed;
+	BOOLEAN			DeviceAccess;
+	BOOLEAN			bIsAutoCorrectEnabled;
+	BOOLEAN			bDDRInitDone;
+	int			DDRSetting;
+	ULONG			ulPowerSaveMode;
+	spinlock_t		txtransmitlock;
+	B_UINT8			txtransmit_running;
 	/* Thread for control packet handling */
-	struct task_struct 	*control_packet_handler;
+	struct task_struct	*control_packet_handler;
 	/* thread for transmitting packets. */
-	struct task_struct 	*transmit_packet_thread;
+	struct task_struct	*transmit_packet_thread;
 
 	/* LED Related Structures */
 	LED_INFO_STRUCT		LEDInfo;
@@ -482,39 +438,38 @@
 	/* Driver State for LED Blinking */
 	LedEventInfo_t		DriverState;
 	/* Interface Specific */
-	PVOID				pvInterfaceAdapter;
-	int (*bcm_file_download)( PVOID,
-                        struct file *,
-                        unsigned int);
-	int (*bcm_file_readback_from_chip)( PVOID,
-                        struct file *,
-                        unsigned int);
-	INT (*interface_rdm)(PVOID,
-			UINT ,
-			PVOID ,
-			INT);
-	INT (*interface_wrm)(PVOID,
-			UINT ,
-			PVOID ,
-			INT);
+	PVOID			pvInterfaceAdapter;
+	int (*bcm_file_download)(PVOID,
+				struct file *,
+				unsigned int);
+	int (*bcm_file_readback_from_chip)(PVOID,
+					struct file *,
+					unsigned int);
+	int (*interface_rdm)(PVOID,
+			UINT,
+			PVOID,
+			int);
+	int (*interface_wrm)(PVOID,
+			UINT,
+			PVOID,
+			int);
 	int (*interface_transmit)(PVOID, PVOID , UINT);
 	BOOLEAN			IdleMode;
 	BOOLEAN			bDregRequestSentInIdleMode;
 	BOOLEAN			bTriedToWakeUpFromlowPowerMode;
 	BOOLEAN			bShutStatus;
 	BOOLEAN			bWakeUpDevice;
-	unsigned int	usIdleModePattern;
-	//BOOLEAN			bTriedToWakeUpFromShutdown;
+	unsigned int		usIdleModePattern;
+	/* BOOLEAN			bTriedToWakeUpFromShutdown; */
 	BOOLEAN			bLinkDownRequested;
-
-	int 			downloadDDR;
-	PHS_DEVICE_EXTENSION stBCMPhsContext;
-	S_HDR_SUPRESSION_CONTEXTINFO	stPhsTxContextInfo;
+	int			downloadDDR;
+	PHS_DEVICE_EXTENSION	stBCMPhsContext;
+	S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo;
 	uint8_t			ucaPHSPktRestoreBuf[2048];
 	uint8_t			bPHSEnabled;
 	BOOLEAN			AutoFirmDld;
-	BOOLEAN         bMipsConfig;
-	BOOLEAN         bDPLLConfig;
+	BOOLEAN			bMipsConfig;
+	BOOLEAN			bDPLLConfig;
 	UINT32			aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
 	UINT32			aRxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
 	S_FRAGMENTED_PACKET_INFO astFragmentedPktClassifierTable[MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES];
@@ -527,108 +482,101 @@
 	BOOLEAN			bStatusWrite;
 	UINT			uiNVMDSDSize;
 	UINT			uiVendorExtnFlag;
-	 //it will always represent chosen DSD at any point of time.
-	 // Generally it is Active DSD but in case of NVM RD/WR it might be different.
+	/* it will always represent chosen DSD at any point of time.
+	 * Generally it is Active DSD but in case of NVM RD/WR it might be different.
+	 */
 	UINT			ulFlashCalStart;
-	ULONG                   ulFlashControlSectionStart;
-	ULONG                   ulFlashWriteSize;
-	ULONG                   ulFlashID;
-	FP_FLASH_WRITE          fpFlashWrite;
-	FP_FLASH_WRITE_STATUS   fpFlashWriteWithStatusCheck;
-
+	ULONG			ulFlashControlSectionStart;
+	ULONG			ulFlashWriteSize;
+	ULONG			ulFlashID;
+	FP_FLASH_WRITE		fpFlashWrite;
+	FP_FLASH_WRITE_STATUS	fpFlashWriteWithStatusCheck;
 
 	struct semaphore	NVMRdmWrmLock;
+	struct device		*pstCreatedClassDevice;
 
-	struct device *pstCreatedClassDevice;
-
-//	BOOLEAN				InterfaceUpStatus;
-	PFLASH2X_CS_INFO psFlash2xCSInfo;
-	PFLASH_CS_INFO psFlashCSInfo ;
+	/*	BOOLEAN				InterfaceUpStatus; */
+	PFLASH2X_CS_INFO	psFlash2xCSInfo;
+	PFLASH_CS_INFO		psFlashCSInfo;
 	PFLASH2X_VENDORSPECIFIC_INFO psFlash2xVendorInfo;
-	UINT uiFlashBaseAdd; //Flash start address
-	UINT uiActiveISOOffset; //Active ISO offset chosen before f/w download
-	FLASH2X_SECTION_VAL eActiveISO; //Active ISO section val
-	FLASH2X_SECTION_VAL eActiveDSD;	//Active DSD val chosen before f/w download
-	UINT uiActiveDSDOffsetAtFwDld;  //For accessing Active DSD chosen before f/w download
-	UINT uiFlashLayoutMajorVersion ;
-	UINT uiFlashLayoutMinorVersion;
-	BOOLEAN bAllDSDWriteAllow ;
-	BOOLEAN bSigCorrupted ;
-	//this should be set who so ever want to change the Headers. after Wrtie it should be reset immediately.
-	BOOLEAN bHeaderChangeAllowed ;
-	INT SelectedChip ;
-	BOOLEAN bEndPointHalted;
-	//while bFlashRawRead will be true, Driver  ignore map lay out and consider flash as of without any map.
-	BOOLEAN bFlashRawRead;
-	BOOLEAN			bPreparingForLowPowerMode ;
-	BOOLEAN bDoSuspend ;
-	UINT syscfgBefFwDld ;
-	BOOLEAN StopAllXaction ;
-	UINT32	liTimeSinceLastNetEntry; //Used to Support extended CAPI requirements from
+	UINT			uiFlashBaseAdd; /* Flash start address */
+	UINT			uiActiveISOOffset; /* Active ISO offset chosen before f/w download */
+	FLASH2X_SECTION_VAL	eActiveISO; /* Active ISO section val */
+	FLASH2X_SECTION_VAL	eActiveDSD;	/* Active DSD val chosen before f/w download */
+	UINT			uiActiveDSDOffsetAtFwDld;  /* For accessing Active DSD chosen before f/w download */
+	UINT			uiFlashLayoutMajorVersion;
+	UINT			uiFlashLayoutMinorVersion;
+	BOOLEAN			bAllDSDWriteAllow;
+	BOOLEAN			bSigCorrupted;
+	/* this should be set who so ever want to change the Headers. after Wrtie it should be reset immediately. */
+	BOOLEAN			bHeaderChangeAllowed;
+	int			SelectedChip;
+	BOOLEAN			bEndPointHalted;
+	/* while bFlashRawRead will be true, Driver  ignore map lay out and consider flash as of without any map. */
+	BOOLEAN			bFlashRawRead;
+	BOOLEAN			bPreparingForLowPowerMode;
+	BOOLEAN			bDoSuspend;
+	UINT			syscfgBefFwDld;
+	BOOLEAN			StopAllXaction;
+	UINT32			liTimeSinceLastNetEntry; /* Used to Support extended CAPI requirements from */
 	struct semaphore	LowPowerModeSync;
-	ULONG	liDrainCalculated;
-	UINT gpioBitMap;
-
-    S_BCM_DEBUG_STATE stDebugState;
-
+	ULONG			liDrainCalculated;
+	UINT			gpioBitMap;
+	S_BCM_DEBUG_STATE	stDebugState;
 };
 typedef struct _MINI_ADAPTER MINI_ADAPTER, *PMINI_ADAPTER;
 
-#define GET_BCM_ADAPTER(net_dev)	netdev_priv(net_dev)
+#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev)
 
 struct _ETH_HEADER_STRUC {
-    UCHAR       au8DestinationAddress[6];
-    UCHAR       au8SourceAddress[6];
-    USHORT      u16Etype;
-}__attribute__((packed));
+	UCHAR	au8DestinationAddress[6];
+	UCHAR	au8SourceAddress[6];
+	USHORT	u16Etype;
+} __packed;
 typedef struct _ETH_HEADER_STRUC ETH_HEADER_STRUC, *PETH_HEADER_STRUC;
 
+typedef struct FirmwareInfo {
+	void	__user *pvMappedFirmwareAddress;
+	ULONG	u32FirmwareLength;
+	ULONG	u32StartingAddress;
+} __packed FIRMWARE_INFO, *PFIRMWARE_INFO;
 
-typedef struct FirmwareInfo
-{
-	void __user *	pvMappedFirmwareAddress;
-	ULONG		u32FirmwareLength;
-	ULONG		u32StartingAddress;
-}__attribute__((packed)) FIRMWARE_INFO, *PFIRMWARE_INFO;
-
-// holds the value of net_device structure..
+/* holds the value of net_device structure.. */
 extern struct net_device *gblpnetdev;
-typedef struct _cntl_pkt{
-	PMINI_ADAPTER 	Adapter;
-	PLEADER 		PLeader;
-}cntl_pkt;
+typedef struct _cntl_pkt {
+	PMINI_ADAPTER	Adapter;
+	PLEADER		PLeader;
+} cntl_pkt;
 typedef LINK_REQUEST CONTROL_MESSAGE;
 
-typedef struct _DDR_SETTING
-{
+typedef struct _DDR_SETTING {
 	UINT ulRegAddress;
 	UINT ulRegValue;
-}DDR_SETTING, *PDDR_SETTING;
+} DDR_SETTING, *PDDR_SETTING;
 typedef DDR_SETTING DDR_SET_NODE, *PDDR_SET_NODE;
-INT
-InitAdapter(PMINI_ADAPTER psAdapter);
+int InitAdapter(PMINI_ADAPTER psAdapter);
 
-// =====================================================================
-// Beceem vendor request codes for EP0
-// =====================================================================
+/* =====================================================================
+ * Beceem vendor request codes for EP0
+ * =====================================================================
+ */
 
-#define BCM_REQUEST_READ  0x2
-#define BCM_REQUEST_WRITE 0x1
-#define EP2_MPS_REG  0x0F0110A0
-#define EP2_MPS 	 0x40
+#define BCM_REQUEST_READ	0x2
+#define BCM_REQUEST_WRITE	0x1
+#define EP2_MPS_REG		0x0F0110A0
+#define EP2_MPS			0x40
 
-#define EP2_CFG_REG  0x0F0110A8
-#define EP2_CFG_INT  0x27
-#define EP2_CFG_BULK 0x25
+#define EP2_CFG_REG	0x0F0110A8
+#define EP2_CFG_INT	0x27
+#define EP2_CFG_BULK	0x25
 
-#define EP4_MPS_REG  0x0F0110F0
-#define EP4_MPS      0x8C
+#define EP4_MPS_REG	0x0F0110F0
+#define EP4_MPS		0x8C
 
-#define EP4_CFG_REG  0x0F0110F8
+#define EP4_CFG_REG	0x0F0110F8
 
-#define ISO_MPS_REG  0x0F0110C8
-#define ISO_MPS      0x00000000
-
+#define ISO_MPS_REG	0x0F0110C8
+#define ISO_MPS		0x00000000
 
 #define EP1 0
 #define EP2 1
@@ -637,12 +585,9 @@
 #define EP5 4
 #define EP6 5
 
-
-typedef enum eInterface_setting
-{
+typedef enum eInterface_setting {
 	DEFAULT_SETTING_0  = 0,
 	ALTERNATE_SETTING_1 = 1,
-}INTERFACE_SETTING;
+} INTERFACE_SETTING;
 
-#endif	//__ADAPTER_H__
-
+#endif	/* __ADAPTER_H__ */
diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c
index 1c7db81..2b46f4d 100644
--- a/drivers/staging/bcm/DDRInit.c
+++ b/drivers/staging/bcm/DDRInit.c
@@ -1115,20 +1115,20 @@
 	    {
 	        case DDR_80_MHZ:
 				psDDRSetting = asT3LP_DDRSetting80MHz;
-                RegCount = (sizeof(asT3LP_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+                RegCount = ARRAY_SIZE(asT3LP_DDRSetting80MHz);
 				RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
                 psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
 			break;
 		    case DDR_100_MHZ:
 				psDDRSetting = asT3LP_DDRSetting100MHz;
-			    RegCount = (sizeof(asT3LP_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+			    RegCount = ARRAY_SIZE(asT3LP_DDRSetting100MHz);
 				RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
                 psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
 			    break;
 		     case DDR_133_MHZ:
 				bOverrideSelfRefresh = TRUE;
 				psDDRSetting = asT3LP_DDRSetting133MHz;
-			    RegCount = (sizeof(asT3LP_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+			    RegCount = ARRAY_SIZE(asT3LP_DDRSetting133MHz);
 				RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
 		        psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
 				break;
@@ -1146,20 +1146,20 @@
 	    {
 	        case DDR_80_MHZ:
 				psDDRSetting = asT3LPB_DDRSetting80MHz;
-                RegCount=(sizeof(asT3LPB_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+                RegCount=ARRAY_SIZE(asT3LPB_DDRSetting80MHz);
 				RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
                 psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
 			break;
 		    case DDR_100_MHZ:
 				psDDRSetting = asT3LPB_DDRSetting100MHz;
-			    RegCount = (sizeof(asT3LPB_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+			    RegCount = ARRAY_SIZE(asT3LPB_DDRSetting100MHz);
 				RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
                 psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
 			    break;
 		     case DDR_133_MHZ:
 				bOverrideSelfRefresh = TRUE;
 				psDDRSetting = asT3LPB_DDRSetting133MHz;
-			    RegCount = (sizeof(asT3LPB_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+			    RegCount = ARRAY_SIZE(asT3LPB_DDRSetting133MHz);
 				RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
 		        psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
 				break;
@@ -1167,7 +1167,7 @@
 			case DDR_160_MHZ:
 					bOverrideSelfRefresh = TRUE;
 					psDDRSetting = asT3LPB_DDRSetting160MHz;
-					RegCount = sizeof(asT3LPB_DDRSetting160MHz)/sizeof(DDR_SET_NODE);
+					RegCount = ARRAY_SIZE(asT3LPB_DDRSetting160MHz);
 					RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ;
 					psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ;
 
@@ -1181,19 +1181,19 @@
 	    {
 	        case DDR_80_MHZ:
 				psDDRSetting = asT3_DDRSetting80MHz;
-                RegCount = (sizeof(asT3_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+                RegCount = ARRAY_SIZE(asT3_DDRSetting80MHz);
 				RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
                 psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
 			break;
 		    case DDR_100_MHZ:
 				psDDRSetting = asT3_DDRSetting100MHz;
-			    RegCount = (sizeof(asT3_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+			    RegCount = ARRAY_SIZE(asT3_DDRSetting100MHz);
 				RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
                 psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
 			    break;
 		     case DDR_133_MHZ:
 				psDDRSetting = asT3_DDRSetting133MHz;
-			    RegCount = (sizeof(asT3_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+			    RegCount = ARRAY_SIZE(asT3_DDRSetting133MHz);
 				RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
 		        psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
 				break;
@@ -1207,20 +1207,20 @@
 		    {
 		        case DDR_80_MHZ:
 					psDDRSetting = asT3B_DDRSetting80MHz;
-                    RegCount = (sizeof(asT3B_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+                    RegCount = ARRAY_SIZE(asT3B_DDRSetting80MHz);
                     RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
                     psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
 			        break;
 		        case DDR_100_MHZ:
 					psDDRSetting = asT3B_DDRSetting100MHz;
-			        RegCount = (sizeof(asT3B_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+			        RegCount = ARRAY_SIZE(asT3B_DDRSetting100MHz);
                     RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
                     psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
 			        break;
 		        case DDR_133_MHZ:
 					bOverrideSelfRefresh = TRUE;
 					psDDRSetting = asT3B_DDRSetting133MHz;
-			        RegCount = (sizeof(asT3B_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+			        RegCount = ARRAY_SIZE(asT3B_DDRSetting133MHz);
 	                RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
 		            psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
 					break;
diff --git a/drivers/staging/bcm/IPv6Protocol.c b/drivers/staging/bcm/IPv6Protocol.c
index 5b4fd37..1da2164 100644
--- a/drivers/staging/bcm/IPv6Protocol.c
+++ b/drivers/staging/bcm/IPv6Protocol.c
@@ -1,51 +1,52 @@
 #include "headers.h"
 
-static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
-static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+	IPV6Header *pstIpv6Header);
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+	IPV6Header *pstIpv6Header);
 static VOID DumpIpv6Header(IPV6Header *pstIpv6Header);
 
-static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader,BOOLEAN *bParseDone,USHORT *pusPayloadLength)
+static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload,
+	UCHAR *pucNextHeader, BOOLEAN *bParseDone, USHORT *pusPayloadLength)
 {
 	UCHAR *pucRetHeaderPtr = NULL;
 	UCHAR *pucPayloadPtr = NULL;
 	USHORT  usNextHeaderOffset = 0 ;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
-	if((NULL == ppucPayload) || (*pusPayloadLength == 0) || (*bParseDone))
-	{
+	if ((ppucPayload == NULL) || (*pusPayloadLength == 0) ||
+		(*bParseDone)) {
 		*bParseDone = TRUE;
 		return NULL;
-
 	}
 
 	pucRetHeaderPtr = *ppucPayload;
 	pucPayloadPtr = *ppucPayload;
 
-	if(!pucRetHeaderPtr || !pucPayloadPtr)
-	{
+	if (!pucRetHeaderPtr || !pucPayloadPtr) {
 		*bParseDone = TRUE;
 		return NULL;
 	}
 
-	//Get the Nextt Header Type
+	/* Get the Nextt Header Type */
 	*bParseDone = FALSE;
 
 
-
-	switch(*pucNextHeader)
-	{
+	switch (*pucNextHeader) {
 	case IPV6HDR_TYPE_HOPBYHOP:
 		{
 
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 HopByHop Header");
-			usNextHeaderOffset+=sizeof(IPV6HopByHopOptionsHeader);
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL, "\nIPv6 HopByHop Header");
+			usNextHeaderOffset += sizeof(IPV6HopByHopOptionsHeader);
 		}
 		break;
 
 	case IPV6HDR_TYPE_ROUTING:
 		{
 			IPV6RoutingHeader *pstIpv6RoutingHeader;
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Routing Header");
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL, "\nIPv6 Routing Header");
 			pstIpv6RoutingHeader = (IPV6RoutingHeader *)pucPayloadPtr;
 			usNextHeaderOffset += sizeof(IPV6RoutingHeader);
 			usNextHeaderOffset += pstIpv6RoutingHeader->ucNumAddresses * IPV6_ADDRESS_SIZEINBYTES;
@@ -54,8 +55,10 @@
 		break;
 	case IPV6HDR_TYPE_FRAGMENTATION:
 		{
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Fragmentation Header");
-			usNextHeaderOffset+= sizeof(IPV6FragmentHeader);
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL,
+					"\nIPv6 Fragmentation Header");
+			usNextHeaderOffset += sizeof(IPV6FragmentHeader);
 
 		}
 		break;
@@ -63,9 +66,11 @@
 		{
 			IPV6DestOptionsHeader *pstIpv6DestOptsHdr = (IPV6DestOptionsHeader *)pucPayloadPtr;
 			int nTotalOptions = pstIpv6DestOptsHdr->ucHdrExtLen;
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 DestOpts Header Header");
-			usNextHeaderOffset+= sizeof(IPV6DestOptionsHeader);
-			usNextHeaderOffset+= nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ;
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL,
+					"\nIPv6 DestOpts Header Header");
+			usNextHeaderOffset += sizeof(IPV6DestOptionsHeader);
+			usNextHeaderOffset += nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ;
 
 		}
 		break;
@@ -73,36 +78,43 @@
 		{
 			IPV6AuthenticationHeader *pstIpv6AuthHdr = (IPV6AuthenticationHeader *)pucPayloadPtr;
 			int nHdrLen = pstIpv6AuthHdr->ucLength;
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Authentication Header");
-			usNextHeaderOffset+= nHdrLen * 4;
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL,
+					"\nIPv6 Authentication Header");
+			usNextHeaderOffset += nHdrLen * 4;
 		}
 		break;
 	case IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD:
 		{
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Encrypted Security Payload Header");
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL,
+					"\nIPv6 Encrypted Security Payload Header");
 			*bParseDone = TRUE;
 
 		}
 		break;
 	case IPV6_ICMP_HDR_TYPE:
 		{
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " ICMP Header");
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL, "\nICMP Header");
 			*bParseDone = TRUE;
 		}
 		break;
 	case TCP_HEADER_TYPE:
 		{
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nTCP Header");
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL, "\nTCP Header");
 			*bParseDone = TRUE;
 		}
 		break;
 	case UDP_HEADER_TYPE:
 		{
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nUDP Header");
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL, "\nUDP Header");
 			*bParseDone = TRUE;
 		}
 		break;
-	default :
+	default:
 		{
 			*bParseDone = TRUE;
 
@@ -112,53 +124,49 @@
 
 	}
 
-	if(*bParseDone == FALSE)
-	{
-		if(*pusPayloadLength <= usNextHeaderOffset)
-		{
+	if (*bParseDone == FALSE) {
+		if (*pusPayloadLength <= usNextHeaderOffset) {
 			*bParseDone = TRUE;
-		}
-		else
-		{
+		} else {
 			*pucNextHeader = *pucPayloadPtr;
-			pucPayloadPtr+=usNextHeaderOffset;
-			(*pusPayloadLength)-=usNextHeaderOffset;
+			pucPayloadPtr += usNextHeaderOffset;
+			(*pusPayloadLength) -= usNextHeaderOffset;
 		}
 
 	}
 
-
-
 	*ppucPayload = pucPayloadPtr;
 	return pucRetHeaderPtr;
 }
 
 
-static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload,USHORT *pusSrcPort,USHORT *pusDestPort,USHORT usPayloadLength,UCHAR ucNextHeader)
+static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort,
+	USHORT *pusDestPort, USHORT usPayloadLength, UCHAR ucNextHeader)
 {
 	UCHAR *pIpv6HdrScanContext = pucPayload;
 	BOOLEAN bDone = FALSE;
-	UCHAR ucHeaderType =0;
+	UCHAR ucHeaderType = 0;
 	UCHAR *pucNextHeader = NULL;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
-	if( !pucPayload || (usPayloadLength == 0))
-	{
+	if (!pucPayload || (usPayloadLength == 0))
 		return 0;
-	}
 
 	*pusSrcPort = *pusDestPort = 0;
 	ucHeaderType = ucNextHeader;
-	while(!bDone)
-	{
-		pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,&ucHeaderType,&bDone,&usPayloadLength);
-		if(bDone)
-		{
-			if((ucHeaderType==TCP_HEADER_TYPE) || (ucHeaderType == UDP_HEADER_TYPE))
-			{
-				 *pusSrcPort=*((PUSHORT)(pucNextHeader));
-				 *pusDestPort=*((PUSHORT)(pucNextHeader+2));
-				 BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nProtocol Ports - Src Port :0x%x Dest Port : 0x%x",ntohs(*pusSrcPort),ntohs(*pusDestPort));
+	while (!bDone) {
+		pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,
+					&ucHeaderType, &bDone, &usPayloadLength);
+		if (bDone) {
+			if ((ucHeaderType == TCP_HEADER_TYPE) ||
+				(ucHeaderType == UDP_HEADER_TYPE)) {
+				*pusSrcPort = *((PUSHORT)(pucNextHeader));
+				*pusDestPort = *((PUSHORT)(pucNextHeader+2));
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+						DBG_LVL_ALL,
+						"\nProtocol Ports - Src Port :0x%x Dest Port : 0x%x",
+						ntohs(*pusSrcPort),
+						ntohs(*pusDestPort));
 			}
 			break;
 
@@ -168,92 +176,111 @@
 }
 
 
-
-USHORT	IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
-					PVOID pcIpHeader, /**<Pointer to the IP Hdr of the packet*/
-					S_CLASSIFIER_RULE *pstClassifierRule )
+/*
+ * Arg 1 PMINI_ADAPTER Adapter is a pointer ot the driver contorl structure
+ * Arg 2 PVOID pcIpHeader is a pointer to the IP header of the packet
+ */
+USHORT	IpVersion6(PMINI_ADAPTER Adapter, PVOID pcIpHeader,
+					S_CLASSIFIER_RULE *pstClassifierRule)
 {
 	USHORT	ushDestPort = 0;
 	USHORT	ushSrcPort = 0;
-	UCHAR   ucNextProtocolAboveIP =0;
+	UCHAR   ucNextProtocolAboveIP = 0;
 	IPV6Header *pstIpv6Header = NULL;
 	BOOLEAN bClassificationSucceed = FALSE;
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "IpVersion6 ==========>\n");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+			DBG_LVL_ALL, "IpVersion6 ==========>\n");
 
 	pstIpv6Header = (IPV6Header *)pcIpHeader;
 
 	DumpIpv6Header(pstIpv6Header);
 
-	//Try to get the next higher layer protocol and the Ports Nos if TCP or UDP
+	/*
+	 * Try to get the next higher layer protocol
+	 * and the Ports Nos if TCP or UDP
+	 */
 	ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader + sizeof(IPV6Header)),
 							&ushSrcPort,
 							&ushDestPort,
 							pstIpv6Header->usPayloadLength,
 							pstIpv6Header->ucNextHeader);
 
-	do
-	{
-		if(0 == pstClassifierRule->ucDirection)
-		{
-			//cannot be processed for classification.
-		   // it is a down link connection
+	do {
+		if (pstClassifierRule->ucDirection == 0) {
+			/*
+			 * cannot be processed for classification.
+			 * it is a down link connection
+			 */
 			break;
 		}
 
-		if(!pstClassifierRule->bIpv6Protocol)
-		{
-			//We are looking for Ipv6 Classifiers . Lets ignore this classifier and try the next one.
+		if (!pstClassifierRule->bIpv6Protocol) {
+			/*
+			 * We are looking for Ipv6 Classifiers
+			 * Lets ignore this classifier and try the next one
+			 */
 			break;
 		}
 
-		bClassificationSucceed=MatchSrcIpv6Address(pstClassifierRule,pstIpv6Header);
-        if(!bClassificationSucceed)
-            break;
+		bClassificationSucceed = MatchSrcIpv6Address(pstClassifierRule,
+								pstIpv6Header);
+		if (!bClassificationSucceed)
+			break;
 
-        bClassificationSucceed=MatchDestIpv6Address(pstClassifierRule,pstIpv6Header);
-        if(!bClassificationSucceed)
-            break;
+		bClassificationSucceed = MatchDestIpv6Address(pstClassifierRule,
+								pstIpv6Header);
+		if (!bClassificationSucceed)
+			break;
 
-		//Match the protocol type.For IPv6 the next protocol at end of Chain of IPv6 prot headers
-		bClassificationSucceed=MatchProtocol(pstClassifierRule,ucNextProtocolAboveIP);
-        if(!bClassificationSucceed)
-            break;
-        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Protocol Matched");
+		/*
+		 * Match the protocol type.
+		 * For IPv6 the next protocol at end of
+		 * Chain of IPv6 prot headers
+		 */
+		bClassificationSucceed = MatchProtocol(pstClassifierRule,
+							ucNextProtocolAboveIP);
+		if (!bClassificationSucceed)
+			break;
 
-		if((ucNextProtocolAboveIP == TCP_HEADER_TYPE) || (ucNextProtocolAboveIP == UDP_HEADER_TYPE))
-		{
-			//Match Src Port
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",ntohs(ushSrcPort));
-			bClassificationSucceed=MatchSrcPort(pstClassifierRule,ntohs(ushSrcPort));
-			if(!bClassificationSucceed)
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+				DBG_LVL_ALL, "\nIPv6 Protocol Matched");
+
+		if ((ucNextProtocolAboveIP == TCP_HEADER_TYPE) ||
+			(ucNextProtocolAboveIP == UDP_HEADER_TYPE)) {
+			/* Match Src Port */
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",
+					ntohs(ushSrcPort));
+			bClassificationSucceed = MatchSrcPort(pstClassifierRule,
+							ntohs(ushSrcPort));
+			if (!bClassificationSucceed)
 				break;
 
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Src Port Matched");
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL, "\nIPv6 Src Port Matched");
 
-			//Match Dest Port
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n",ntohs(ushDestPort));
-			bClassificationSucceed=MatchDestPort(pstClassifierRule,ntohs(ushDestPort));
-			if(!bClassificationSucceed)
+			/* Match Dest Port */
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n",
+					ntohs(ushDestPort));
+			bClassificationSucceed = MatchDestPort(pstClassifierRule,
+							ntohs(ushDestPort));
+			if (!bClassificationSucceed)
 				break;
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Dest Port Matched");
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+					DBG_LVL_ALL, "\nIPv6 Dest Port Matched");
 		}
-	}while(0);
+	} while (0);
 
-	if(TRUE==bClassificationSucceed)
-	{
+	if (bClassificationSucceed == TRUE) {
 		INT iMatchedSFQueueIndex = 0;
-		iMatchedSFQueueIndex = SearchSfid(Adapter,pstClassifierRule->ulSFID);
-		if(iMatchedSFQueueIndex >= NO_OF_QUEUES)
-		{
+		iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
+		if (iMatchedSFQueueIndex >= NO_OF_QUEUES) {
 			bClassificationSucceed = FALSE;
-		}
-		else
-		{
-			if(FALSE == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
-			{
+		} else {
+			if (Adapter->PackInfo[iMatchedSFQueueIndex].bActive == FALSE)
 				bClassificationSucceed = FALSE;
-			}
 		}
 	}
 
@@ -261,52 +288,55 @@
 }
 
 
-static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+	IPV6Header *pstIpv6Header)
 {
-	UINT uiLoopIndex=0;
-	UINT  uiIpv6AddIndex=0;
-	UINT  uiIpv6AddrNoLongWords = 4;
+	UINT uiLoopIndex = 0;
+	UINT uiIpv6AddIndex = 0;
+	UINT uiIpv6AddrNoLongWords = 4;
 	ULONG aulSrcIP[4];
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	/*
-	//This is the no. of Src Addresses ie Range of IP Addresses contained
-	//in the classifier rule for which we need to match
-	*/
+	 * This is the no. of Src Addresses ie Range of IP Addresses contained
+	 * in the classifier rule for which we need to match
+	 */
 	UINT  uiCountIPSrcAddresses = (UINT)pstClassifierRule->ucIPSourceAddressLength;
 
 
-	if(0 == uiCountIPSrcAddresses)
+	if (uiCountIPSrcAddresses == 0)
 		return TRUE;
 
 
-	//First Convert the Ip Address in the packet to Host Endian order
-	for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
-	{
-		aulSrcIP[uiIpv6AddIndex]=ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
-	}
+	/* First Convert the Ip Address in the packet to Host Endian order */
+	for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++)
+		aulSrcIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
 
-	for(uiLoopIndex=0;uiLoopIndex<uiCountIPSrcAddresses;uiLoopIndex+=uiIpv6AddrNoLongWords)
-	{
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Address In Received Packet : \n ");
+	for (uiLoopIndex = 0; uiLoopIndex < uiCountIPSrcAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+				"\n Src Ipv6 Address In Received Packet :\n ");
 		DumpIpv6Address(aulSrcIP);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Mask In Classifier Rule: \n");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+				"\n Src Ipv6 Mask In Classifier Rule:\n");
 		DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex]);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Address In Classifier Rule : \n");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+				"\n Src Ipv6 Address In Classifier Rule :\n");
 		DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex]);
 
-		for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
-		{
-			if((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex])
-				!= pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex])
-			{
-				//Match failed for current Ipv6 Address.Try next Ipv6 Address
+		for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
+			if ((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex])
+				!= pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
+				/*
+				 * Match failed for current Ipv6 Address
+				 * Try next Ipv6 Address
+				 */
 				break;
 			}
 
-			if(uiIpv6AddIndex ==  uiIpv6AddrNoLongWords-1)
-			{
-				//Match Found
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Src Ip Address Matched\n");
+			if (uiIpv6AddIndex ==  uiIpv6AddrNoLongWords-1) {
+				/* Match Found */
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+						DBG_LVL_ALL,
+						"Ipv6 Src Ip Address Matched\n");
 				return TRUE;
 			}
 		}
@@ -314,52 +344,56 @@
 	return FALSE;
 }
 
-static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+	IPV6Header *pstIpv6Header)
 {
-	UINT uiLoopIndex=0;
-	UINT  uiIpv6AddIndex=0;
-	UINT  uiIpv6AddrNoLongWords = 4;
+	UINT uiLoopIndex = 0;
+	UINT uiIpv6AddIndex = 0;
+	UINT uiIpv6AddrNoLongWords = 4;
 	ULONG aulDestIP[4];
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	/*
-	//This is the no. of Destination Addresses ie Range of IP Addresses contained
-	//in the classifier rule for which we need to match
-	*/
+	 * This is the no. of Destination Addresses
+	 * ie Range of IP Addresses contained in the classifier rule
+	 * for which we need to match
+	 */
 	UINT  uiCountIPDestinationAddresses = (UINT)pstClassifierRule->ucIPDestinationAddressLength;
 
 
-	if(0 == uiCountIPDestinationAddresses)
+	if (uiCountIPDestinationAddresses == 0)
 		return TRUE;
 
 
-	//First Convert the Ip Address in the packet to Host Endian order
-	for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
-	{
-		aulDestIP[uiIpv6AddIndex]=ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
-	}
+	/* First Convert the Ip Address in the packet to Host Endian order */
+	for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++)
+		aulDestIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
 
-	for(uiLoopIndex=0;uiLoopIndex<uiCountIPDestinationAddresses;uiLoopIndex+=uiIpv6AddrNoLongWords)
-	{
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Address In Received Packet : \n ");
+	for (uiLoopIndex = 0; uiLoopIndex < uiCountIPDestinationAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+				"\n Destination Ipv6 Address In Received Packet :\n ");
 		DumpIpv6Address(aulDestIP);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Mask In Classifier Rule: \n");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+				"\n Destination Ipv6 Mask In Classifier Rule :\n");
 		DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex]);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Address In Classifier Rule : \n");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+				"\n Destination Ipv6 Address In Classifier Rule :\n");
 		DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex]);
 
-		for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
-		{
-			if((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex])
-				!= pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex])
-			{
-				//Match failed for current Ipv6 Address.Try next Ipv6 Address
+		for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
+			if ((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex])
+				!= pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
+				/*
+				 * Match failed for current Ipv6 Address.
+				 * Try next Ipv6 Address
+				 */
 				break;
 			}
 
-			if(uiIpv6AddIndex ==  uiIpv6AddrNoLongWords-1)
-			{
-				//Match Found
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Destination Ip Address Matched\n");
+			if (uiIpv6AddIndex ==  uiIpv6AddrNoLongWords-1) {
+				/* Match Found */
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+						DBG_LVL_ALL,
+						"Ipv6 Destination Ip Address Matched\n");
 				return TRUE;
 			}
 		}
@@ -371,11 +405,11 @@
 VOID DumpIpv6Address(ULONG *puIpv6Address)
 {
 	UINT uiIpv6AddrNoLongWords = 4;
-	UINT  uiIpv6AddIndex=0;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-	for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
-	{
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, ":%lx",puIpv6Address[uiIpv6AddIndex]);
+	UINT uiIpv6AddIndex = 0;
+	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+				":%lx", puIpv6Address[uiIpv6AddIndex]);
 	}
 
 }
@@ -383,22 +417,35 @@
 static VOID DumpIpv6Header(IPV6Header *pstIpv6Header)
 {
 	UCHAR ucVersion;
-	UCHAR  ucPrio ;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "----Ipv6 Header---");
+	UCHAR ucPrio;
+	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+			"----Ipv6 Header---");
 	ucVersion = pstIpv6Header->ucVersionPrio & 0xf0;
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Version : %x \n",ucVersion);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+			"Version : %x\n", ucVersion);
 	ucPrio = pstIpv6Header->ucVersionPrio & 0x0f;
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Priority : %x \n",ucPrio);
-	//BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Flow Label : %x \n",(pstIpv6Header->ucVersionPrio &0xf0);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Payload Length : %x \n",ntohs(pstIpv6Header->usPayloadLength));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Next Header : %x \n",pstIpv6Header->ucNextHeader);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Hop Limit : %x \n",pstIpv6Header->ucHopLimit);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Src Address :\n");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+			"Priority : %x\n", ucPrio);
+	/*
+	 * BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+	 * "Flow Label : %x\n",(pstIpv6Header->ucVersionPrio &0xf0);
+	 */
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+			"Payload Length : %x\n",
+			ntohs(pstIpv6Header->usPayloadLength));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+			"Next Header : %x\n", pstIpv6Header->ucNextHeader);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+			"Hop Limit : %x\n", pstIpv6Header->ucHopLimit);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+			"Src Address :\n");
 	DumpIpv6Address(pstIpv6Header->ulSrcIpAddress);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Dest Address :\n");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+			"Dest Address :\n");
 	DumpIpv6Address(pstIpv6Header->ulDestIpAddress);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "----Ipv6 Header End---");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+			"----Ipv6 Header End---");
 
 
 }
diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c
index c7725e1..8223a69 100644
--- a/drivers/staging/bcm/Misc.c
+++ b/drivers/staging/bcm/Misc.c
@@ -835,7 +835,7 @@
 	Bcm_kill_all_URBs(psIntfAdapter);
 	/* Reset the UMA-B Device */
 	if (ps_adapter->chip_id >= T3LPB) {
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reseting UMA-B\n");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Resetting UMA-B\n");
 		retval = usb_reset_device(psIntfAdapter->udev);
 		psIntfAdapter->psAdapter->StopAllXaction = FALSE;
 
diff --git a/drivers/staging/ccg/Kconfig b/drivers/staging/ccg/Kconfig
new file mode 100644
index 0000000..ff05e52
--- /dev/null
+++ b/drivers/staging/ccg/Kconfig
@@ -0,0 +1,20 @@
+if USB_GADGET
+
+config USB_G_CCG
+	tristate "Configurable Composite Gadget (STAGING)"
+	depends on STAGING && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM
+	help
+	  The Configurable Composite Gadget supports multiple USB
+	  functions: acm, mass storage, rndis and FunctionFS.
+	  Each function can be configured and enabled/disabled
+	  dynamically from userspace through a sysfs interface.
+
+	  In order to compile this (either as a module or built-in),
+	  "USB Gadget Drivers" and anything under it must not be
+	  selected compiled-in in
+	  Device Drivers->USB Support->USB Gadget Support.
+	  However, you can say "M" there, if you do, the
+	  Configurable Composite Gadget can be compiled "M" only
+	  or not at all.
+
+endif # USB_GADGET
diff --git a/drivers/staging/ccg/Makefile b/drivers/staging/ccg/Makefile
new file mode 100644
index 0000000..693da63
--- /dev/null
+++ b/drivers/staging/ccg/Makefile
@@ -0,0 +1,4 @@
+g_ccg-y				:= ccg.o
+ccflags-y			+= -Idrivers/usb/gadget
+
+obj-$(CONFIG_USB_G_CCG)		+= g_ccg.o
diff --git a/drivers/staging/ccg/TODO b/drivers/staging/ccg/TODO
new file mode 100644
index 0000000..18612fe
--- /dev/null
+++ b/drivers/staging/ccg/TODO
@@ -0,0 +1,6 @@
+TODO:
+	- change configuration interface from sysfs to configfs
+
+Please send patches to Greg Kroah-Hartmann <gregkh@linuxfoundation.org>,
+Andrzej Pietrasiewicz <andrzej.p@samsung.com>, and
+Cc: Mike Lockwood <lockwood@android.com>
diff --git a/drivers/staging/ccg/ccg.c b/drivers/staging/ccg/ccg.c
new file mode 100644
index 0000000..a5b36a9
--- /dev/null
+++ b/drivers/staging/ccg/ccg.c
@@ -0,0 +1,1299 @@
+/*
+ * Configurable Composite Gadget
+ *
+ * Initially contributed as "Android Composite Gdaget" by:
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *         Benoit Goby <benoit@android.com>
+ *
+ * Tailoring it to become a generic Configurable Composite Gadget is
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+
+#include "gadget_chips.h"
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "../../usb/gadget/usbstring.c"
+#include "../../usb/gadget/config.c"
+#include "../../usb/gadget/epautoconf.c"
+#include "../../usb/gadget/composite.c"
+
+#include "../../usb/gadget/f_mass_storage.c"
+#include "../../usb/gadget/u_serial.c"
+#include "../../usb/gadget/f_acm.c"
+#define USB_ETH_RNDIS y
+#include "../../usb/gadget/f_rndis.c"
+#include "../../usb/gadget/rndis.c"
+#include "../../usb/gadget/u_ether.c"
+#include "../../usb/gadget/f_fs.c"
+
+MODULE_AUTHOR("Mike Lockwood, Andrzej Pietrasiewicz");
+MODULE_DESCRIPTION("Configurable Composite USB Gadget");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
+static const char longname[] = "Configurable Composite Gadget";
+
+/* Default vendor and product IDs, overridden by userspace */
+#define VENDOR_ID		0x1d6b /* Linux Foundation */
+#define PRODUCT_ID		0x0107
+#define GFS_MAX_DEVS		10
+
+struct ccg_usb_function {
+	char *name;
+	void *config;
+
+	struct device *dev;
+	char *dev_name;
+	struct device_attribute **attributes;
+
+	/* for ccg_dev.enabled_functions */
+	struct list_head enabled_list;
+
+	/* Optional: initialization during gadget bind */
+	int (*init)(struct ccg_usb_function *, struct usb_composite_dev *);
+	/* Optional: cleanup during gadget unbind */
+	void (*cleanup)(struct ccg_usb_function *);
+
+	int (*bind_config)(struct ccg_usb_function *,
+			   struct usb_configuration *);
+
+	/* Optional: called when the configuration is removed */
+	void (*unbind_config)(struct ccg_usb_function *,
+			      struct usb_configuration *);
+	/* Optional: handle ctrl requests before the device is configured */
+	int (*ctrlrequest)(struct ccg_usb_function *,
+			   struct usb_composite_dev *,
+			   const struct usb_ctrlrequest *);
+};
+
+struct ffs_obj {
+	const char *name;
+	bool mounted;
+	bool desc_ready;
+	bool used;
+	struct ffs_data *ffs_data;
+};
+
+struct ccg_dev {
+	struct ccg_usb_function **functions;
+	struct list_head enabled_functions;
+	struct usb_composite_dev *cdev;
+	struct device *dev;
+
+	bool enabled;
+	struct mutex mutex;
+	bool connected;
+	bool sw_connected;
+	struct work_struct work;
+
+	unsigned int max_func_num;
+	unsigned int func_num;
+	struct ffs_obj ffs_tab[GFS_MAX_DEVS];
+};
+
+static struct class *ccg_class;
+static struct ccg_dev *_ccg_dev;
+static int ccg_bind_config(struct usb_configuration *c);
+static void ccg_unbind_config(struct usb_configuration *c);
+
+static char func_names_buf[256];
+
+static struct usb_device_descriptor device_desc = {
+	.bLength              = sizeof(device_desc),
+	.bDescriptorType      = USB_DT_DEVICE,
+	.bcdUSB               = __constant_cpu_to_le16(0x0200),
+	.bDeviceClass         = USB_CLASS_PER_INTERFACE,
+	.idVendor             = __constant_cpu_to_le16(VENDOR_ID),
+	.idProduct            = __constant_cpu_to_le16(PRODUCT_ID),
+	.bcdDevice            = __constant_cpu_to_le16(0xffff),
+	.bNumConfigurations   = 1,
+};
+
+static struct usb_configuration ccg_config_driver = {
+	.label		= "ccg",
+	.unbind		= ccg_unbind_config,
+	.bConfigurationValue = 1,
+	.bmAttributes	= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+	.bMaxPower	= 0xFA, /* 500ma */
+};
+
+static void ccg_work(struct work_struct *data)
+{
+	struct ccg_dev *dev = container_of(data, struct ccg_dev, work);
+	struct usb_composite_dev *cdev = dev->cdev;
+	static char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
+	static char *connected[2]    = { "USB_STATE=CONNECTED", NULL };
+	static char *configured[2]   = { "USB_STATE=CONFIGURED", NULL };
+	char **uevent_envp = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cdev->lock, flags);
+	if (cdev->config)
+		uevent_envp = configured;
+	else if (dev->connected != dev->sw_connected)
+		uevent_envp = dev->connected ? connected : disconnected;
+	dev->sw_connected = dev->connected;
+	spin_unlock_irqrestore(&cdev->lock, flags);
+
+	if (uevent_envp) {
+		kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
+		pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
+	} else {
+		pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
+			 dev->connected, dev->sw_connected, cdev->config);
+	}
+}
+
+
+/*-------------------------------------------------------------------------*/
+/* Supported functions initialization */
+
+static struct ffs_obj *functionfs_find_dev(struct ccg_dev *dev,
+					   const char *dev_name)
+{
+	int i;
+
+	for (i = 0; i < dev->max_func_num; i++)
+		if (strcmp(dev->ffs_tab[i].name, dev_name) == 0)
+			return &dev->ffs_tab[i];
+
+	return NULL;
+}
+
+static bool functionfs_all_ready(struct ccg_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < dev->max_func_num; i++)
+		if (dev->ffs_tab[i].used && !dev->ffs_tab[i].desc_ready)
+			return false;
+
+	return true;
+}
+
+static int functionfs_ready_callback(struct ffs_data *ffs)
+{
+	struct ffs_obj *ffs_obj;
+	int ret;
+
+	mutex_lock(&_ccg_dev->mutex);
+
+	ffs_obj = ffs->private_data;
+	if (!ffs_obj) {
+		ret = -EINVAL;
+		goto done;
+	}
+	if (WARN_ON(ffs_obj->desc_ready)) {
+		ret = -EBUSY;
+		goto done;
+	}
+	ffs_obj->ffs_data = ffs;
+
+	if (functionfs_all_ready(_ccg_dev)) {
+		ret = -EBUSY;
+		goto done;
+	}
+	ffs_obj->desc_ready = true;
+
+done:
+	mutex_unlock(&_ccg_dev->mutex);
+	return ret;
+}
+
+static void reset_usb(struct ccg_dev *dev)
+{
+	/* Cancel pending control requests */
+	usb_ep_dequeue(dev->cdev->gadget->ep0, dev->cdev->req);
+	usb_remove_config(dev->cdev, &ccg_config_driver);
+	dev->enabled = false;
+	usb_gadget_disconnect(dev->cdev->gadget);
+}
+
+static void functionfs_closed_callback(struct ffs_data *ffs)
+{
+	struct ffs_obj *ffs_obj;
+
+	mutex_lock(&_ccg_dev->mutex);
+
+	ffs_obj = ffs->private_data;
+	if (!ffs_obj)
+		goto done;
+
+	ffs_obj->desc_ready = false;
+
+	if (_ccg_dev->enabled)
+		reset_usb(_ccg_dev);
+
+done:
+	mutex_unlock(&_ccg_dev->mutex);
+}
+
+static void *functionfs_acquire_dev_callback(const char *dev_name)
+{
+	struct ffs_obj *ffs_dev;
+
+	mutex_lock(&_ccg_dev->mutex);
+
+	ffs_dev = functionfs_find_dev(_ccg_dev, dev_name);
+	if (!ffs_dev) {
+		ffs_dev = ERR_PTR(-ENODEV);
+		goto done;
+	}
+
+	if (ffs_dev->mounted) {
+		ffs_dev = ERR_PTR(-EBUSY);
+		goto done;
+	}
+	ffs_dev->mounted = true;
+
+done:
+	mutex_unlock(&_ccg_dev->mutex);
+	return ffs_dev;
+}
+
+static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
+{
+	struct ffs_obj *ffs_dev;
+
+	mutex_lock(&_ccg_dev->mutex);
+
+	ffs_dev = ffs_data->private_data;
+	if (ffs_dev)
+		ffs_dev->mounted = false;
+
+	mutex_unlock(&_ccg_dev->mutex);
+}
+
+static int functionfs_function_init(struct ccg_usb_function *f,
+				struct usb_composite_dev *cdev)
+{
+	return functionfs_init();
+}
+
+static void functionfs_function_cleanup(struct ccg_usb_function *f)
+{
+	functionfs_cleanup();
+}
+
+static int functionfs_function_bind_config(struct ccg_usb_function *f,
+					   struct usb_configuration *c)
+{
+	struct ccg_dev *dev = _ccg_dev;
+	int i, ret;
+
+	for (i = dev->max_func_num; i--; ) {
+		if (!dev->ffs_tab[i].used)
+			continue;
+		ret = functionfs_bind(dev->ffs_tab[i].ffs_data, c->cdev);
+		if (unlikely(ret < 0)) {
+			while (++i < dev->max_func_num)
+				functionfs_unbind(dev->ffs_tab[i].ffs_data);
+			return ret;
+		}
+	}
+
+	for (i = dev->max_func_num; i--; ) {
+		if (!dev->ffs_tab[i].used)
+			continue;
+		ret = functionfs_bind_config(c->cdev, c,
+					     dev->ffs_tab[i].ffs_data);
+		if (unlikely(ret < 0))
+			return ret;
+	}
+
+	return 0;
+}
+
+static void functionfs_function_unbind_config(struct ccg_usb_function *f,
+					      struct usb_configuration *c)
+{
+	struct ccg_dev *dev = _ccg_dev;
+	int i;
+
+	for (i = dev->max_func_num; i--; )
+		if (dev->ffs_tab[i].ffs_data)
+			functionfs_unbind(dev->ffs_tab[i].ffs_data);
+}
+
+static ssize_t functionfs_user_functions_show(struct device *_dev,
+					      struct device_attribute *attr,
+					      char *buf)
+{
+	struct ccg_dev *dev = _ccg_dev;
+	char *buff = buf;
+	int i;
+
+	mutex_lock(&dev->mutex);
+
+	for (i = 0; i < dev->max_func_num; i++)
+		buff += snprintf(buff, PAGE_SIZE + buf - buff, "%s,",
+				 dev->ffs_tab[i].name);
+
+	mutex_unlock(&dev->mutex);
+
+	if (buff != buf)
+		*(buff - 1) = '\n';
+	return buff - buf;
+}
+
+static ssize_t functionfs_user_functions_store(struct device *_dev,
+					       struct device_attribute *attr,
+					       const char *buff, size_t size)
+{
+	struct ccg_dev *dev = _ccg_dev;
+	char *name, *b;
+	ssize_t ret = size;
+	int i;
+
+	buff = skip_spaces(buff);
+	if (!*buff)
+		return -EINVAL;
+
+	mutex_lock(&dev->mutex);
+
+	if (dev->enabled) {
+		ret = -EBUSY;
+		goto end;
+	}
+
+	for (i = 0; i < dev->max_func_num; i++)
+		if (dev->ffs_tab[i].mounted) {
+			ret = -EBUSY;
+			goto end;
+		}
+
+	strlcpy(func_names_buf, buff, sizeof(func_names_buf));
+	b = strim(func_names_buf);
+
+	/* replace the list of functions */
+	dev->max_func_num = 0;
+	while (b) {
+		name = strsep(&b, ",");
+		if (dev->max_func_num == GFS_MAX_DEVS) {
+			ret = -ENOSPC;
+			goto end;
+		}
+		if (functionfs_find_dev(dev, name)) {
+			ret = -EEXIST;
+			continue;
+		}
+		dev->ffs_tab[dev->max_func_num++].name = name;
+	}
+
+end:
+	mutex_unlock(&dev->mutex);
+	return ret;
+}
+
+static DEVICE_ATTR(user_functions, S_IRUGO | S_IWUSR,
+		   functionfs_user_functions_show,
+		   functionfs_user_functions_store);
+
+static ssize_t functionfs_max_user_functions_show(struct device *_dev,
+						  struct device_attribute *attr,
+						  char *buf)
+{
+	return sprintf(buf, "%d", GFS_MAX_DEVS);
+}
+
+static DEVICE_ATTR(max_user_functions, S_IRUGO,
+		   functionfs_max_user_functions_show, NULL);
+
+static struct device_attribute *functionfs_function_attributes[] = {
+	&dev_attr_user_functions,
+	&dev_attr_max_user_functions,
+	NULL
+};
+
+static struct ccg_usb_function functionfs_function = {
+	.name		= "fs",
+	.init		= functionfs_function_init,
+	.cleanup	= functionfs_function_cleanup,
+	.bind_config	= functionfs_function_bind_config,
+	.unbind_config  = functionfs_function_unbind_config,
+	.attributes	= functionfs_function_attributes,
+};
+
+#define MAX_ACM_INSTANCES 4
+struct acm_function_config {
+	int instances;
+};
+
+static int
+acm_function_init(struct ccg_usb_function *f, struct usb_composite_dev *cdev)
+{
+	f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL);
+	if (!f->config)
+		return -ENOMEM;
+
+	return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES);
+}
+
+static void acm_function_cleanup(struct ccg_usb_function *f)
+{
+	gserial_cleanup();
+	kfree(f->config);
+	f->config = NULL;
+}
+
+static int
+acm_function_bind_config(struct ccg_usb_function *f,
+		struct usb_configuration *c)
+{
+	int i;
+	int ret = 0;
+	struct acm_function_config *config = f->config;
+
+	for (i = 0; i < config->instances; i++) {
+		ret = acm_bind_config(c, i);
+		if (ret) {
+			pr_err("Could not bind acm%u config\n", i);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static ssize_t acm_instances_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct acm_function_config *config = f->config;
+	return sprintf(buf, "%d\n", config->instances);
+}
+
+static ssize_t acm_instances_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct acm_function_config *config = f->config;
+	int value;
+	int ret = 0;
+
+	ret = kstrtoint(buf, 10, &value);
+	if (ret)
+		return ret;
+
+	if (value > MAX_ACM_INSTANCES)
+		return -EINVAL;
+
+	config->instances = value;
+
+	return size;
+}
+
+static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show,
+						 acm_instances_store);
+static struct device_attribute *acm_function_attributes[] = {
+	&dev_attr_instances,
+	NULL
+};
+
+static struct ccg_usb_function acm_function = {
+	.name		= "acm",
+	.init		= acm_function_init,
+	.cleanup	= acm_function_cleanup,
+	.bind_config	= acm_function_bind_config,
+	.attributes	= acm_function_attributes,
+};
+
+struct rndis_function_config {
+	u8      ethaddr[ETH_ALEN];
+	u32     vendorID;
+	char	manufacturer[256];
+	/* "Wireless" RNDIS; auto-detected by Windows */
+	bool	wceis;
+};
+
+static int rndis_function_init(struct ccg_usb_function *f,
+			       struct usb_composite_dev *cdev)
+{
+	f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL);
+	if (!f->config)
+		return -ENOMEM;
+	return 0;
+}
+
+static void rndis_function_cleanup(struct ccg_usb_function *f)
+{
+	kfree(f->config);
+	f->config = NULL;
+}
+
+static int rndis_function_bind_config(struct ccg_usb_function *f,
+				      struct usb_configuration *c)
+{
+	int ret;
+	struct rndis_function_config *rndis = f->config;
+
+	if (!rndis) {
+		pr_err("%s: rndis_pdata\n", __func__);
+		return -1;
+	}
+
+	pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+		rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
+		rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
+
+	ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis");
+	if (ret) {
+		pr_err("%s: gether_setup failed\n", __func__);
+		return ret;
+	}
+
+	if (rndis->wceis) {
+		/* "Wireless" RNDIS; auto-detected by Windows */
+		rndis_iad_descriptor.bFunctionClass =
+						USB_CLASS_WIRELESS_CONTROLLER;
+		rndis_iad_descriptor.bFunctionSubClass = 0x01;
+		rndis_iad_descriptor.bFunctionProtocol = 0x03;
+		rndis_control_intf.bInterfaceClass =
+						USB_CLASS_WIRELESS_CONTROLLER;
+		rndis_control_intf.bInterfaceSubClass =	 0x01;
+		rndis_control_intf.bInterfaceProtocol =	 0x03;
+	}
+
+	return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID,
+					   rndis->manufacturer);
+}
+
+static void rndis_function_unbind_config(struct ccg_usb_function *f,
+						struct usb_configuration *c)
+{
+	gether_cleanup();
+}
+
+static ssize_t rndis_manufacturer_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *config = f->config;
+	return sprintf(buf, "%s\n", config->manufacturer);
+}
+
+static ssize_t rndis_manufacturer_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *config = f->config;
+
+	if (size >= sizeof(config->manufacturer))
+		return -EINVAL;
+	memcpy(config->manufacturer, buf, size);
+	config->manufacturer[size] = 0;
+
+	return size;
+}
+
+static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show,
+						    rndis_manufacturer_store);
+
+static ssize_t rndis_wceis_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *config = f->config;
+	return sprintf(buf, "%d\n", config->wceis);
+}
+
+static ssize_t rndis_wceis_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *config = f->config;
+	int value;
+	int ret;
+
+	ret = kstrtoint(buf, 10, &value);
+	if (ret)
+		return ret;
+
+	config->wceis = value;
+
+	return size;
+}
+
+static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show,
+					     rndis_wceis_store);
+
+static ssize_t rndis_ethaddr_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *rndis = f->config;
+	return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
+		rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
+}
+
+static ssize_t rndis_ethaddr_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *rndis = f->config;
+	unsigned char tmp[6];
+
+	if (sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+		   tmp + 0, tmp + 1, tmp + 2, tmp + 3, tmp + 4, tmp + 5) !=
+	    ETH_ALEN)
+		return -EINVAL;
+
+	memcpy(rndis->ethaddr, tmp, ETH_ALEN);
+
+	return ETH_ALEN;
+
+}
+
+static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show,
+					       rndis_ethaddr_store);
+
+static ssize_t rndis_vendorID_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *config = f->config;
+	return sprintf(buf, "%04x\n", config->vendorID);
+}
+
+static ssize_t rndis_vendorID_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct ccg_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *config = f->config;
+	int value;
+	int ret;
+
+	ret = kstrtou32(buf, 16, &value);
+	if (ret)
+		return ret;
+
+	config->vendorID = value;
+
+	return size;
+}
+
+static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show,
+						rndis_vendorID_store);
+
+static struct device_attribute *rndis_function_attributes[] = {
+	&dev_attr_manufacturer,
+	&dev_attr_wceis,
+	&dev_attr_ethaddr,
+	&dev_attr_vendorID,
+	NULL
+};
+
+static struct ccg_usb_function rndis_function = {
+	.name		= "rndis",
+	.init		= rndis_function_init,
+	.cleanup	= rndis_function_cleanup,
+	.bind_config	= rndis_function_bind_config,
+	.unbind_config	= rndis_function_unbind_config,
+	.attributes	= rndis_function_attributes,
+};
+
+static int mass_storage_function_init(struct ccg_usb_function *f,
+					struct usb_composite_dev *cdev)
+{
+	struct fsg_config fsg;
+	struct fsg_common *common;
+	int err;
+
+	memset(&fsg, 0, sizeof fsg);
+	fsg.nluns = 1;
+	fsg.luns[0].removable = 1;
+	fsg.vendor_name = iManufacturer;
+	fsg.product_name = iProduct;
+
+	common = fsg_common_init(NULL, cdev, &fsg);
+	if (IS_ERR(common))
+		return PTR_ERR(common);
+
+	err = sysfs_create_link(&f->dev->kobj,
+				&common->luns[0].dev.kobj,
+				"lun");
+	if (err) {
+		fsg_common_put(common);
+		return err;
+	}
+
+	f->config = common;
+	return 0;
+}
+
+static void mass_storage_function_cleanup(struct ccg_usb_function *f)
+{
+	fsg_common_put(f->config);
+	f->config = NULL;
+}
+
+static int mass_storage_function_bind_config(struct ccg_usb_function *f,
+					     struct usb_configuration *c)
+{
+	struct fsg_common *common = f->config;
+	return fsg_bind_config(c->cdev, c, common);
+}
+
+static struct ccg_usb_function mass_storage_function = {
+	.name		= "mass_storage",
+	.init		= mass_storage_function_init,
+	.cleanup	= mass_storage_function_cleanup,
+	.bind_config	= mass_storage_function_bind_config,
+};
+
+static struct ccg_usb_function *supported_functions[] = {
+	&functionfs_function,
+	&acm_function,
+	&rndis_function,
+	&mass_storage_function,
+	NULL
+};
+
+
+static int ccg_init_functions(struct ccg_usb_function **functions,
+				  struct usb_composite_dev *cdev)
+{
+	struct ccg_dev *dev = _ccg_dev;
+	struct ccg_usb_function *f;
+	struct device_attribute **attrs;
+	struct device_attribute *attr;
+	int err;
+	int index = 0;
+
+	for (; (f = *functions++); index++) {
+		f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name);
+		if (!f->dev_name) {
+			pr_err("%s: Failed to alloc name %s", __func__,
+			       f->name);
+			err = -ENOMEM;
+			goto err_alloc;
+		}
+		f->dev = device_create(ccg_class, dev->dev,
+				MKDEV(0, index), f, f->dev_name);
+		if (IS_ERR(f->dev)) {
+			pr_err("%s: Failed to create dev %s", __func__,
+							f->dev_name);
+			err = PTR_ERR(f->dev);
+			f->dev = NULL;
+			goto err_create;
+		}
+
+		if (f->init) {
+			err = f->init(f, cdev);
+			if (err) {
+				pr_err("%s: Failed to init %s", __func__,
+								f->name);
+				goto err_out;
+			}
+		}
+
+		attrs = f->attributes;
+		if (attrs) {
+			while ((attr = *attrs++) && !err)
+				err = device_create_file(f->dev, attr);
+		}
+		if (err) {
+			pr_err("%s: Failed to create function %s attributes",
+					__func__, f->name);
+			goto err_uninit;
+		}
+	}
+	return 0;
+
+err_uninit:
+	if (f->cleanup)
+		f->cleanup(f);
+err_out:
+	device_destroy(ccg_class, f->dev->devt);
+	f->dev = NULL;
+err_create:
+	kfree(f->dev_name);
+err_alloc:
+	return err;
+}
+
+static void ccg_cleanup_functions(struct ccg_usb_function **functions)
+{
+	struct ccg_usb_function *f;
+
+	while (*functions) {
+		f = *functions++;
+
+		if (f->dev) {
+			if (f->cleanup)
+				f->cleanup(f);
+			device_destroy(ccg_class, f->dev->devt);
+			kfree(f->dev_name);
+		}
+	}
+}
+
+static int ccg_bind_enabled_functions(struct ccg_dev *dev,
+				      struct usb_configuration *c)
+{
+	struct ccg_usb_function *f;
+	int ret;
+
+	list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+		ret = f->bind_config(f, c);
+		if (ret) {
+			pr_err("%s: %s failed", __func__, f->name);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static void ccg_unbind_enabled_functions(struct ccg_dev *dev,
+					 struct usb_configuration *c)
+{
+	struct ccg_usb_function *f;
+
+	list_for_each_entry(f, &dev->enabled_functions, enabled_list)
+		if (f->unbind_config)
+			f->unbind_config(f, c);
+}
+
+static int ccg_enable_function(struct ccg_dev *dev, char *name)
+{
+	struct ccg_usb_function **functions = dev->functions;
+	struct ccg_usb_function *f;
+	while ((f = *functions++)) {
+		if (!strcmp(name, f->name)) {
+			list_add_tail(&f->enabled_list,
+						&dev->enabled_functions);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+/* /sys/class/ccg_usb/ccg%d/ interface */
+
+static ssize_t
+functions_show(struct device *pdev, struct device_attribute *attr, char *buf)
+{
+	struct ccg_dev *dev = dev_get_drvdata(pdev);
+	struct ccg_usb_function *f;
+	char *buff = buf;
+	int i;
+
+	mutex_lock(&dev->mutex);
+
+	list_for_each_entry(f, &dev->enabled_functions, enabled_list)
+		buff += sprintf(buff, "%s,", f->name);
+	for (i = 0; i < dev->max_func_num; i++)
+		if (dev->ffs_tab[i].used)
+			buff += sprintf(buff, "%s", dev->ffs_tab[i].name);
+
+	mutex_unlock(&dev->mutex);
+
+	if (buff != buf)
+		*(buff-1) = '\n';
+	return buff - buf;
+}
+
+static ssize_t
+functions_store(struct device *pdev, struct device_attribute *attr,
+			       const char *buff, size_t size)
+{
+	struct ccg_dev *dev = dev_get_drvdata(pdev);
+	char *name;
+	char buf[256], *b;
+	int err, i;
+	bool functionfs_enabled;
+
+	buff = skip_spaces(buff);
+	if (!*buff)
+		return -EINVAL;
+
+	mutex_lock(&dev->mutex);
+
+	if (dev->enabled) {
+		mutex_unlock(&dev->mutex);
+		return -EBUSY;
+	}
+
+	INIT_LIST_HEAD(&dev->enabled_functions);
+	functionfs_enabled = false;
+	for (i = 0; i < dev->max_func_num; i++)
+		dev->ffs_tab[i].used = false;
+
+	strlcpy(buf, buff, sizeof(buf));
+	b = strim(buf);
+
+	while (b) {
+		struct ffs_obj *user_func;
+
+		name = strsep(&b, ",");
+		/* handle FunctionFS implicitly */
+		if (!strcmp(name, functionfs_function.name)) {
+			pr_err("ccg_usb: Cannot explicitly enable '%s'", name);
+			continue;
+		}
+		user_func = functionfs_find_dev(dev, name);
+		if (user_func)
+			name = functionfs_function.name;
+		err = 0;
+		if (!user_func || !functionfs_enabled)
+			err = ccg_enable_function(dev, name);
+		if (err)
+			pr_err("ccg_usb: Cannot enable '%s'", name);
+		else if (user_func) {
+			user_func->used = true;
+			dev->func_num++;
+			functionfs_enabled = true;
+		}
+	}
+
+	mutex_unlock(&dev->mutex);
+
+	return size;
+}
+
+static ssize_t enable_show(struct device *pdev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ccg_dev *dev = dev_get_drvdata(pdev);
+	return sprintf(buf, "%d\n", dev->enabled);
+}
+
+static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,
+			    const char *buff, size_t size)
+{
+	struct ccg_dev *dev = dev_get_drvdata(pdev);
+	struct usb_composite_dev *cdev = dev->cdev;
+	int enabled = 0;
+
+	mutex_lock(&dev->mutex);
+	sscanf(buff, "%d", &enabled);
+	if (enabled && dev->func_num && !functionfs_all_ready(dev)) {
+		mutex_unlock(&dev->mutex);
+		return -ENODEV;
+	}
+
+	if (enabled && !dev->enabled) {
+		int ret;
+
+		cdev->next_string_id = 0;
+		/*
+		 * Update values in composite driver's copy of
+		 * device descriptor.
+		 */
+		cdev->desc.bDeviceClass = device_desc.bDeviceClass;
+		cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
+		cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
+		cdev->desc.idVendor = idVendor;
+		cdev->desc.idProduct = idProduct;
+		cdev->desc.bcdDevice = bcdDevice;
+
+		usb_add_config(cdev, &ccg_config_driver, ccg_bind_config);
+		dev->enabled = true;
+		ret = usb_gadget_connect(cdev->gadget);
+		if (ret) {
+			dev->enabled = false;
+			usb_remove_config(cdev, &ccg_config_driver);
+		}
+	} else if (!enabled && dev->enabled) {
+		reset_usb(dev);
+	} else {
+		pr_err("ccg_usb: already %s\n",
+			dev->enabled ? "enabled" : "disabled");
+	}
+
+	mutex_unlock(&dev->mutex);
+	return size;
+}
+
+static ssize_t state_show(struct device *pdev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ccg_dev *dev = dev_get_drvdata(pdev);
+	struct usb_composite_dev *cdev = dev->cdev;
+	char *state = "DISCONNECTED";
+	unsigned long flags;
+
+	if (!cdev)
+		goto out;
+
+	spin_lock_irqsave(&cdev->lock, flags);
+	if (cdev->config)
+		state = "CONFIGURED";
+	else if (dev->connected)
+		state = "CONNECTED";
+	spin_unlock_irqrestore(&cdev->lock, flags);
+out:
+	return sprintf(buf, "%s\n", state);
+}
+
+#define DESCRIPTOR_ATTR(field, format_string)				\
+static ssize_t								\
+field ## _show(struct device *dev, struct device_attribute *attr,	\
+		char *buf)						\
+{									\
+	return sprintf(buf, format_string, device_desc.field);		\
+}									\
+static ssize_t								\
+field ## _store(struct device *dev, struct device_attribute *attr,	\
+		const char *buf, size_t size)				\
+{									\
+	int value;							\
+	if (sscanf(buf, format_string, &value) == 1) {			\
+		device_desc.field = value;				\
+		return size;						\
+	}								\
+	return -1;							\
+}									\
+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);
+
+DESCRIPTOR_ATTR(bDeviceClass, "%d\n")
+DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n")
+DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n")
+
+static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show,
+						 functions_store);
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
+static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
+
+static struct device_attribute *ccg_usb_attributes[] = {
+	&dev_attr_bDeviceClass,
+	&dev_attr_bDeviceSubClass,
+	&dev_attr_bDeviceProtocol,
+	&dev_attr_functions,
+	&dev_attr_enable,
+	&dev_attr_state,
+	NULL
+};
+
+/*-------------------------------------------------------------------------*/
+/* Composite driver */
+
+static int ccg_bind_config(struct usb_configuration *c)
+{
+	struct ccg_dev *dev = _ccg_dev;
+	int ret = 0;
+
+	ret = ccg_bind_enabled_functions(dev, c);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void ccg_unbind_config(struct usb_configuration *c)
+{
+	struct ccg_dev *dev = _ccg_dev;
+
+	ccg_unbind_enabled_functions(dev, c);
+
+	usb_ep_autoconfig_reset(dev->cdev->gadget);
+}
+
+static int ccg_bind(struct usb_composite_dev *cdev)
+{
+	struct ccg_dev *dev = _ccg_dev;
+	struct usb_gadget	*gadget = cdev->gadget;
+	int			gcnum, ret;
+
+	/*
+	 * Start disconnected. Userspace will connect the gadget once
+	 * it is done configuring the functions.
+	 */
+	usb_gadget_disconnect(gadget);
+
+	ret = ccg_init_functions(dev->functions, cdev);
+	if (ret)
+		return ret;
+
+	gcnum = usb_gadget_controller_number(gadget);
+	if (gcnum >= 0)
+		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
+	else {
+		pr_warning("%s: controller '%s' not recognized\n",
+			longname, gadget->name);
+		device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+	}
+
+	usb_gadget_set_selfpowered(gadget);
+	dev->cdev = cdev;
+
+	return 0;
+}
+
+static int ccg_usb_unbind(struct usb_composite_dev *cdev)
+{
+	struct ccg_dev *dev = _ccg_dev;
+
+	cancel_work_sync(&dev->work);
+	ccg_cleanup_functions(dev->functions);
+	return 0;
+}
+
+static struct usb_composite_driver ccg_usb_driver = {
+	.name		= "configurable_usb",
+	.dev		= &device_desc,
+	.unbind		= ccg_usb_unbind,
+	.needs_serial	= true,
+	.iManufacturer	= "Linux Foundation",
+	.iProduct	= longname,
+	.iSerialNumber	= "1234567890123456",
+};
+
+static int ccg_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
+{
+	struct ccg_dev		*dev = _ccg_dev;
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	struct usb_request		*req = cdev->req;
+	struct ccg_usb_function	*f;
+	int value = -EOPNOTSUPP;
+	unsigned long flags;
+
+	req->zero = 0;
+	req->complete = composite_setup_complete;
+	req->length = 0;
+	gadget->ep0->driver_data = cdev;
+
+	list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+		if (f->ctrlrequest) {
+			value = f->ctrlrequest(f, cdev, c);
+			if (value >= 0)
+				break;
+		}
+	}
+
+	if (value < 0)
+		value = composite_setup(gadget, c);
+
+	spin_lock_irqsave(&cdev->lock, flags);
+	if (!dev->connected) {
+		dev->connected = 1;
+		schedule_work(&dev->work);
+	} else if (c->bRequest == USB_REQ_SET_CONFIGURATION &&
+						cdev->config) {
+		schedule_work(&dev->work);
+	}
+	spin_unlock_irqrestore(&cdev->lock, flags);
+
+	return value;
+}
+
+static void ccg_disconnect(struct usb_gadget *gadget)
+{
+	struct ccg_dev *dev = _ccg_dev;
+	struct usb_composite_dev *cdev = get_gadget_data(gadget);
+	unsigned long flags;
+
+	composite_disconnect(gadget);
+
+	spin_lock_irqsave(&cdev->lock, flags);
+	dev->connected = 0;
+	schedule_work(&dev->work);
+	spin_unlock_irqrestore(&cdev->lock, flags);
+}
+
+static int ccg_create_device(struct ccg_dev *dev)
+{
+	struct device_attribute **attrs = ccg_usb_attributes;
+	struct device_attribute *attr;
+	int err;
+
+	dev->dev = device_create(ccg_class, NULL, MKDEV(0, 0), NULL, "ccg0");
+	if (IS_ERR(dev->dev))
+		return PTR_ERR(dev->dev);
+
+	dev_set_drvdata(dev->dev, dev);
+
+	while ((attr = *attrs++)) {
+		err = device_create_file(dev->dev, attr);
+		if (err) {
+			device_destroy(ccg_class, dev->dev->devt);
+			return err;
+		}
+	}
+	return 0;
+}
+
+
+static int __init init(void)
+{
+	struct ccg_dev *dev;
+	int err;
+
+	ccg_class = class_create(THIS_MODULE, "ccg_usb");
+	if (IS_ERR(ccg_class))
+		return PTR_ERR(ccg_class);
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->functions = supported_functions;
+	INIT_LIST_HEAD(&dev->enabled_functions);
+	INIT_WORK(&dev->work, ccg_work);
+	mutex_init(&dev->mutex);
+
+	err = ccg_create_device(dev);
+	if (err) {
+		class_destroy(ccg_class);
+		kfree(dev);
+		return err;
+	}
+
+	_ccg_dev = dev;
+
+	/* Override composite driver functions */
+	composite_driver.setup = ccg_setup;
+	composite_driver.disconnect = ccg_disconnect;
+
+	err = usb_composite_probe(&ccg_usb_driver, ccg_bind);
+	if (err) {
+		class_destroy(ccg_class);
+		kfree(dev);
+	}
+
+	return err;
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+	usb_composite_unregister(&ccg_usb_driver);
+	class_destroy(ccg_class);
+	kfree(_ccg_dev);
+	_ccg_dev = NULL;
+}
+module_exit(cleanup);
diff --git a/drivers/staging/ccg/sysfs-class-ccg_usb b/drivers/staging/ccg/sysfs-class-ccg_usb
new file mode 100644
index 0000000..dd12a33
--- /dev/null
+++ b/drivers/staging/ccg/sysfs-class-ccg_usb
@@ -0,0 +1,158 @@
+What:		/sys/class/ccg_usb
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		The ccg_usb/ class subdirectory belongs to ccg
+		USB gadget.
+
+What:		/sys/class/ccg_usb/ccgX
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		The /sys/class/ccg_usb/ccg{0,1,2,3...} class
+		subdirectories correspond to each ccg gadget device;
+		at the time of this writing there is only ccg0 and it
+		represents the ccg gadget.
+
+What:		/sys/class/ccg_usb/ccgX/functions
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		A comma-separated list of USB function names to be activated
+		in this ccg gadget. It includes both the functions provided
+		in-kernel by the ccg gadget and the functions provided from
+		userspace through FunctionFS.
+
+What:		/sys/class/ccg_usb/ccgX/enable
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		A flag activating/deactivating the ccg usb gadget.
+
+What:		/sys/class/ccg_usb/ccgX/state
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		Configurable usb gadget state:
+
+		DISCONNECTED
+		CONNECTED
+		CONFIGURED
+
+What:		/sys/class/ccg_usb/ccgX/f_acm/
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		The /sys/class/ccg_usb/ccgX/f_acm subdirectory
+		corresponds to the gadget's USB CDC serial (ACM) function
+		driver.
+
+What:		/sys/class/ccg_usb/ccgX/f_acm/instances
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		Maximum number of the /dev/ttyGS<X> interface the driver uses.
+
+What:		/sys/class/ccg_usb/ccgX/f_fs
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		The /sys/class/ccg_usb/ccgX/f_fs subdirectory
+		corresponds to the gadget's FunctionFS driver.
+
+What:		/sys/class/ccg_usb/ccgX/f_fs/user_functions
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		A comma-separeted list of USB function names to be supported
+		from userspace. No other userspace FunctionFS functions can
+		be supported than listed here. However, the actual activation
+		of these functions is still done through
+		/sys/class/ccg_usb/ccgX/functions, where it is possible
+		to specify any subset (including maximum and empty) of
+		/sys/class/ccg_usb/ccgX/f_fs/user_functions.
+
+What:		/sys/class/ccg_usb/ccgX/f_fs/max_user_functions
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		Maximum number of USB functions to be supported from userspace.
+
+What:		/sys/class/ccg_usb/ccgX/f_rndis
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		The /sys/class/ccg_usb/ccgX/f_rndis subdirectory
+		corresponds to the gadget's RNDIS driver.
+
+What:		/sys/class/ccg_usb/ccgX/f_rndis/manufacturer
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		RNDIS Ethernet port manufacturer string.
+
+What:		/sys/class/ccg_usb/ccgX/f_rndis/wceis
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		RNDIS Ethernet port wireless flag.
+
+What:		/sys/class/ccg_usb/ccgX/f_rndis/ethaddr
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		RNDIS Ethernet port Ethernet address.
+
+What:		/sys/class/ccg_usb/ccgX/f_rndis/vendorID
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		RNDIS Ethernet port vendor ID.
+
+What:		/sys/class/ccg_usb/ccgX/f_mass_storage
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		The /sys/class/ccg_usb/ccgX/f_mass_storage subdirectory
+		corresponds to the gadget's USB mass storage driver.
+
+What:		/sys/class/ccg_usb/ccgX/f_mass_storage/lun
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		The /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+		subdirectory corresponds to the gadget's USB mass storage
+		driver and its underlying storage.
+
+What:		/sys/class/ccg_usb/ccgX/f_mass_storage/lun
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		The /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+		subdirectory corresponds to the gadget's USB mass storage
+		driver and its underlying storage.
+
+What:		/sys/class/ccg_usb/ccgX/f_mass_storage/lun/file
+Date:		May 2012
+KernelVersion:	3.4
+Contact:	linux-usb@vger.kernel.org
+Description:
+		Gadget's USB mass storage underlying file.
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 12c691d..3bbe3fd 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -1,6 +1,5 @@
 config COMEDI
 	tristate "Data acquisition support (comedi)"
-	default N
 	depends on m
 	depends on BROKEN || FRV || M32R || MN10300 || SUPERH || TILE || X86
 	---help---
@@ -14,10 +13,29 @@
 	  This is an option for use by developers; most people should
 	  say N here. This enables comedi core and driver debugging.
 
+config COMEDI_DEFAULT_BUF_SIZE_KB
+	int "Comedi default initial asynchronous buffer size in KiB"
+	default "2048"
+	depends on COMEDI != n
+	---help---
+	  This is the default asynchronous buffer size which is used for
+	  commands running in the background in kernel space.  This
+	  defaults to 2048 KiB of memory so that a 16 channel card
+	  running at 10 kHz has of 2-4 seconds of buffer.
+
+config COMEDI_DEFAULT_BUF_MAXSIZE_KB
+	int "Comedi default maximum asynchronous buffer size in KiB"
+	default "20480"
+	depends on COMEDI != n
+	---help---
+	  This is the default maximum asynchronous buffer size which can
+	  be requested by a userspace program without root privileges.
+	  This is set to 20480 KiB so that a fast I/O card with 16
+	  channels running at 100 kHz has 2-4 seconds of buffer.
+
 menuconfig COMEDI_MISC_DRIVERS
 	tristate "Comedi misc drivers"
 	depends on COMEDI
-	default N
 	---help---
 	  Enable comedi misc drivers to be built
 
@@ -35,7 +53,6 @@
 config COMEDI_BOND
 	tristate "Device bonding support"
 	depends on COMEDI_KCOMEDILIB
-	default N
 	---help---
 	  Enable support for a driver to 'bond' (merge) multiple subdevices
 	  from multiple devices together as one.
@@ -46,7 +63,6 @@
 config COMEDI_TEST
 	tristate "Fake waveform generator support"
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for the fake waveform generator.
 	  This driver is mainly for testing purposes, but can also be used to
@@ -58,7 +74,6 @@
 
 config COMEDI_PARPORT
 	tristate "Parallel port support"
-	default N
 	---help---
 	  Enable support for the standard parallel port.
 	  A cheap and easy way to get a few more digital I/O lines. Steal
@@ -70,7 +85,6 @@
 
 config COMEDI_SERIAL2002
 	tristate "Driver for serial connected hardware"
-	default N
 	---help---
 	  Enable support for serial connected hardware
 
@@ -79,7 +93,6 @@
 
 config COMEDI_SKEL
 	tristate "Comedi skeleton driver"
-	default N
 	---help---
 	  Build the Skeleton driver, an example for driver writers
 
@@ -91,7 +104,6 @@
 menuconfig COMEDI_ISA_DRIVERS
 	tristate "Comedi ISA and PC/104 drivers"
 	depends on COMEDI && ISA
-	default N
 	---help---
 	  Enable comedi ISA and PC/104 drivers to be built
 
@@ -103,7 +115,6 @@
 
 config COMEDI_ACL7225B
 	tristate "ADlink NuDAQ ACL-7225b and compatibles support"
-	default N
 	---help---
 	  Enable support for ADlink NuDAQ ACL-7225b and compatibles,
 	  ADlink ACL-7225b (acl7225b), ICP P16R16DIO (p16r16dio)
@@ -113,7 +124,6 @@
 
 config COMEDI_PCL711
 	tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support"
-	default N
 	---help---
 	  Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112
 
@@ -123,7 +133,6 @@
 config COMEDI_PCL724
 	tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for Advantech PCL-724, PCL-722, PCL-731 and
 	  ADlink ACL-7122, ACL-7124, PET-48DIO ISA cards
@@ -133,7 +142,6 @@
 
 config COMEDI_PCL725
 	tristate "Advantech PCL-725 and compatible ISA card support"
-	default N
 	---help---
 	  Enable support for Advantech PCL-725 and compatible ISA cards.
 
@@ -142,7 +150,6 @@
 
 config COMEDI_PCL726
 	tristate "Advantech PCL-726 and compatible ISA card support"
-	default N
 	---help---
 	  Enable support for Advantech PCL-726 and compatible ISA cards.
 
@@ -151,7 +158,6 @@
 
 config COMEDI_PCL730
 	tristate "Advantech PCL-730 and ADlink ACL-7130 ISA card support"
-	default N
 	---help---
 	  Enable support for Advantech PCL-730, ICP ISO-730 and ADlink
 	  ACL-7130 ISA cards
@@ -162,7 +168,6 @@
 config COMEDI_PCL812
 	tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink
 	  ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA,
@@ -174,7 +179,6 @@
 config COMEDI_PCL816
 	tristate "Advantech PCL-814 and PCL-816 ISA card support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for Advantech PCL-814 and PCL-816 ISA cards
 
@@ -184,7 +188,6 @@
 config COMEDI_PCL818
 	tristate "Advantech PCL-718 and PCL-818 ISA card support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for Advantech PCL-818 ISA cards
 	  PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718
@@ -195,7 +198,6 @@
 config COMEDI_PCM3724
 	tristate "Advantech PCM-3724 PC/104 card support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for Advantech PCM-3724 PC/104 cards.
 
@@ -204,16 +206,43 @@
 
 config COMEDI_PCM3730
 	tristate "Advantech PCM-3730 and clone PC/104 board support"
-	default N
 	---help---
 	  Enable support for Advantech PCM-3730 and clone PC/104 boards
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called pcm3730.
 
+config COMEDI_AMPLC_DIO200_ISA
+	tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E"
+	select COMEDI_AMPLC_DIO200
+	depends on COMEDI_ISA_DRIVERS
+	---help---
+	  Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and
+	  PC272E ISA DIO boards
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called amplc_dio200.
+
+config COMEDI_AMPLC_PC236_ISA
+	tristate "Amplicon PC36AT DIO board support"
+	select COMEDI_AMPLC_PC236
+	---help---
+	  Enable support for Amplicon PC36AT ISA DIO board.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called amplc_pc236.
+
+config COMEDI_AMPLC_PC263_ISA
+	tristate "Amplicon PC263 relay board support"
+	select COMEDI_AMPLC_PC263
+	---help---
+	  Enable support for Amplicon PC263 ISA relay board.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called amplc_pc263.
+
 config COMEDI_RTI800
 	tristate "Analog Devices RTI-800/815 ISA card support"
-	default N
 	---help---
 	  Enable support for Analog Devices RTI-800/815 ISA cards
 
@@ -222,7 +251,6 @@
 
 config COMEDI_RTI802
 	tristate "Analog Devices RTI-802 ISA card support"
-	default N
 	---help---
 	  Enable support for Analog Devices RTI-802 ISA cards
 
@@ -233,18 +261,29 @@
 	tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
 	select COMEDI_8255
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for Measurement Computing CIO-DAS16/M1 ISA cards.
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called das16m1.
 
+config COMEDI_DAS08_ISA
+	tristate "DAS-08 compatible ISA and PC/104 card support"
+	select COMEDI_DAS08
+	---help---
+	  Enable support for Keithley Metrabyte/ComputerBoards DAS08
+	  and compatible ISA and PC/104 cards:
+	  Keithley Metrabyte/ComputerBoards DAS08, DAS08-PGM, DAS08-PGH,
+	  DAS08-PGL, DAS08-AOH, DAS08-AOL, DAS08-AOM, DAS08/JR-AO,
+	  DAS08/JR-16-AO, PC104-DAS08, DAS08/JR/16.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called das08.
+
 config COMEDI_DAS16
 	tristate "DAS-16 compatible ISA and PC/104 card support"
 	select COMEDI_8255
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for Keithley Metrabyte/ComputerBoards DAS16
 	  and compatible ISA and PC/104 cards:
@@ -261,7 +300,6 @@
 config COMEDI_DAS800
 	tristate "DAS800 and compatible ISA card support"
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for Keithley Metrabyte DAS800 and compatible ISA cards
 	  Keithley Metrabyte DAS-800, DAS-801, DAS-802
@@ -275,7 +313,6 @@
 	tristate "DAS1800 and compatible ISA card support"
 	depends on VIRT_TO_BUS
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for DAS1800 and compatible ISA cards
 	  Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO,
@@ -289,7 +326,6 @@
 
 config COMEDI_DAS6402
 	tristate "DAS6402 and compatible ISA card support"
-	default N
 	---help---
 	  Enable support for DAS6402 and compatible ISA cards
 	  Computerboards, Keithley Metrabyte DAS6402 and compatibles
@@ -299,7 +335,6 @@
 
 config COMEDI_DT2801
 	tristate "Data Translation DT2801 ISA card support"
-	default N
 	---help---
 	  Enable support for Data Translation DT2801 ISA cards
 
@@ -308,7 +343,6 @@
 
 config COMEDI_DT2811
 	tristate "Data Translation DT2811 ISA card support"
-	default N
 	---help---
 	  Enable support for Data Translation DT2811 ISA cards
 
@@ -317,7 +351,6 @@
 
 config COMEDI_DT2814
 	tristate "Data Translation DT2814 ISA card support"
-	default N
 	---help---
 	  Enable support for Data Translation DT2814 ISA cards
 
@@ -326,7 +359,6 @@
 
 config COMEDI_DT2815
 	tristate "Data Translation DT2815 ISA card support"
-	default N
 	---help---
 	  Enable support for Data Translation DT2815 ISA cards
 
@@ -335,7 +367,6 @@
 
 config COMEDI_DT2817
 	tristate "Data Translation DT2817 ISA card support"
-	default N
 	---help---
 	  Enable support for Data Translation DT2817 ISA cards
 
@@ -346,7 +377,6 @@
 	tristate "Data Translation DT2821 series and DT-EZ ISA card support"
 	select COMEDI_FC
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for Data Translation DT2821 series including DT-EZ
 	  DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI,
@@ -358,7 +388,6 @@
 
 config COMEDI_DMM32AT
 	tristate "Diamond Systems MM-32-AT PC/104 board support"
-	default N
 	---help---
 	  Enable support for Diamond Systems MM-32-AT PC/104 boards
 
@@ -367,7 +396,6 @@
 
 config COMEDI_FL512
 	tristate "FL512 ISA card support"
-	default N
 	---help---
 	  Enable support for FL512 ISA card
 
@@ -377,7 +405,6 @@
 config COMEDI_AIO_AIO12_8
 	tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board
 
@@ -386,7 +413,6 @@
 
 config COMEDI_AIO_IIRO_16
 	tristate "I/O Products PC/104 IIRO16 Board support"
-	default N
 	---help---
 	  Enable support for I/O Products PC/104 IIRO16 Relay And Isolated
 	  Input Board
@@ -396,7 +422,6 @@
 
 config COMEDI_C6XDIGIO
 	tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support"
-	default N
 	---help---
 	  Enable support for Mechatronic Systems Inc. C6x_DIGIO DSP daughter
 	  card
@@ -406,7 +431,6 @@
 
 config COMEDI_MPC624
 	tristate "Micro/sys MPC-624 PC/104 board support"
-	default N
 	---help---
 	  Enable support for Micro/sys MPC-624 PC/104 board
 
@@ -415,7 +439,6 @@
 
 config COMEDI_ADQ12B
 	tristate "MicroAxial ADQ12-B data acquisition and control card support"
-	default N
 	---help---
 	  Enable MicroAxial ADQ12-B daq and control card support.
 
@@ -426,7 +449,6 @@
 	tristate "NI AT-A2150 ISA card support"
 	depends on COMEDI_NI_COMMON
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for National Instruments AT-A2150 cards
 
@@ -436,7 +458,6 @@
 config COMEDI_NI_AT_AO
 	tristate "NI AT-AO-6/10 EISA card support"
 	depends on COMEDI_NI_COMMON
-	default N
 	---help---
 	  Enable support for National Instruments AT-AO-6/10 cards
 
@@ -447,7 +468,6 @@
 	tristate "NI AT-MIO E series ISA-PNP card support"
 	depends on ISAPNP && COMEDI_NI_TIO && COMEDI_NI_COMMON
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for National Instruments AT-MIO E series cards
 	  National Instruments AT-MIO-16E-1 (ni_atmio),
@@ -461,7 +481,6 @@
 	tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support"
 	depends on ISAPNP && COMEDI_NI_COMMON
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for National Instruments AT-MIO16/AT-MIO16D cards.
 
@@ -470,7 +489,6 @@
 
 config COMEDI_PCMAD
 	tristate "Winsystems PCM-A/D12 and PCM-A/D16 PC/104 board support"
-	default N
 	---help---
 	  Enable support for Winsystems PCM-A/D12 and PCM-A/D16 PC/104 boards.
 
@@ -479,7 +497,6 @@
 
 config COMEDI_PCMDA12
 	tristate "Winsystems PCM-D/A-12 8-channel AO PC/104 board support"
-	default N
 	---help---
 	  Enable support for Winsystems PCM-D/A-12 8-channel AO PC/104 boards.
 	  Note that the board is not ISA-PNP capable and thus needs the I/O
@@ -490,7 +507,6 @@
 
 config COMEDI_PCMMIO
 	tristate "Winsystems PCM-MIO PC/104 board support"
-	default N
 	---help---
 	  Enable support for Winsystems PCM-MIO multifunction PC/104 boards.
 
@@ -499,7 +515,6 @@
 
 config COMEDI_PCMUIO
 	tristate "Winsystems PCM-UIO48A and PCM-UIO96A PC/104 board support"
-	default N
 	---help---
 	  Enable support for PCM-UIO48A and PCM-UIO96A PC/104 boards.
 
@@ -508,7 +523,6 @@
 
 config COMEDI_MULTIQ3
 	tristate "Quanser Consulting MultiQ-3 ISA card support"
-	default N
 	---help---
 	  Enable support for Quanser Consulting MultiQ-3 ISA cards
 
@@ -517,7 +531,6 @@
 
 config COMEDI_POC
 	tristate "Generic driver for very simple devices"
-	default N
 	---help---
 	  Enable generic support for very simple / POC (Piece of Crap) boards,
 	  Keithley Metrabyte DAC-02 (dac02), Advantech PCL-733 (pcl733) and
@@ -531,7 +544,6 @@
 menuconfig COMEDI_PCI_DRIVERS
 	tristate "Comedi PCI drivers"
 	depends on COMEDI && PCI
-	default N
 	---help---
 	  Enable comedi PCI drivers to be built
 
@@ -544,7 +556,6 @@
 config COMEDI_ADDI_APCI_035
 	tristate "ADDI-DATA APCI_035 support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_035 cards
 
@@ -554,7 +565,6 @@
 config COMEDI_ADDI_APCI_1032
 	tristate "ADDI-DATA APCI_1032 support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_1032 cards
 
@@ -564,7 +574,6 @@
 config COMEDI_ADDI_APCI_1500
 	tristate "ADDI-DATA APCI_1500 support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_1500 cards
 
@@ -574,7 +583,6 @@
 config COMEDI_ADDI_APCI_1516
 	tristate "ADDI-DATA APCI_1516 support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_1516 cards
 
@@ -584,7 +592,6 @@
 config COMEDI_ADDI_APCI_1564
 	tristate "ADDI-DATA APCI_1564 support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_1564 cards
 
@@ -594,7 +601,6 @@
 config COMEDI_ADDI_APCI_16XX
 	tristate "ADDI-DATA APCI_16xx support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_16xx cards
 
@@ -604,7 +610,6 @@
 config COMEDI_ADDI_APCI_2016
 	tristate "ADDI-DATA APCI_2016 support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_2016 cards
 
@@ -614,7 +619,6 @@
 config COMEDI_ADDI_APCI_2032
 	tristate "ADDI-DATA APCI_2032 support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_2032 cards
 
@@ -624,7 +628,6 @@
 config COMEDI_ADDI_APCI_2200
 	tristate "ADDI-DATA APCI_2200 support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_2200 cards
 
@@ -635,7 +638,6 @@
 	tristate "ADDI-DATA APCI_3001 support"
 	depends on VIRT_TO_BUS
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_3001 cards
 
@@ -646,7 +648,6 @@
 	tristate "ADDI-DATA APCI_3520 support"
 	depends on VIRT_TO_BUS
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_3520 cards
 
@@ -656,7 +657,6 @@
 config COMEDI_ADDI_APCI_3501
 	tristate "ADDI-DATA APCI_3501 support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_3501 cards
 
@@ -666,7 +666,6 @@
 config COMEDI_ADDI_APCI_3XXX
 	tristate "ADDI-DATA APCI_3xxx support"
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADDI-DATA APCI_3xxx cards
 
@@ -676,7 +675,6 @@
 config COMEDI_ADL_PCI6208
 	tristate "ADLink PCI-6208A support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for ADLink PCI-6208A cards
 
@@ -685,7 +683,6 @@
 
 config COMEDI_ADL_PCI7230
 	tristate "ADLink PCI-7230 digital io board support"
-	default N
 	---help---
 	  Enable support for ADlink PCI-7230 digital io board support
 
@@ -694,7 +691,6 @@
 
 config COMEDI_ADL_PCI7296
 	tristate "ADLink PCI-7296 96 ch. digital io board support"
-	default N
 	---help---
 	  Enable support for ADlink PCI-7296 96 ch. digital io board support
 
@@ -703,7 +699,6 @@
 
 config COMEDI_ADL_PCI7432
 	tristate "ADLink PCI-7432 64 ch. isolated digital io board support"
-	default N
 	---help---
 	  Enable support for ADlink PCI-7432 64 ch. isolated digital io board
 
@@ -712,7 +707,6 @@
 
 config COMEDI_ADL_PCI8164
 	tristate "ADLink PCI-8164 4 Axes Motion Control board support"
-	default N
 	---help---
 	  Enable support for ADlink PCI-8164 4 Axes Motion Control board
 
@@ -722,7 +716,6 @@
 config COMEDI_ADL_PCI9111
 	tristate "ADLink PCI-9111HR support"
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for ADlink PCI9111 cards
 
@@ -733,7 +726,6 @@
 	tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support"
 	select COMEDI_FC
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards
 
@@ -742,7 +734,6 @@
 
 config COMEDI_ADV_PCI1710
 	tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support"
-	default N
 	---help---
 	  Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
 	  PCI-1713, PCI-1720 and PCI-1731
@@ -752,7 +743,6 @@
 
 config COMEDI_ADV_PCI1723
 	tristate "Advantech PCI-1723 support"
-	default N
 	---help---
 	  Enable support for Advantech PCI-1723 cards
 
@@ -762,7 +752,6 @@
 config COMEDI_ADV_PCI_DIO
 	tristate "Advantech PCI DIO card support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for Advantech PCI DIO cards
 	  PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U,
@@ -772,31 +761,29 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called adv_pci_dio.
 
-config COMEDI_AMPLC_DIO200
-	tristate "Amplicon PC272E and PCI272 DIO board support"
-	select COMEDI_8255
-	default N
+config COMEDI_AMPLC_DIO200_PCI
+	tristate "Amplicon PCI215 and PCI272 DIO board support"
+	select COMEDI_AMPLC_DIO200
 	---help---
-	  Enable support for Amplicon PC272E and PCI272 DIO boards
+	  Enable support for Amplicon PCI215 and PCI272 DIO boards.
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called amplc_dio200.
 
-config COMEDI_AMPLC_PC236
-	tristate "Amplicon PC36AT and PCI236 DIO board support"
-	select COMEDI_8255
-	default N
+config COMEDI_AMPLC_PC236_PCI
+	tristate "Amplicon PCI236 DIO board support"
+	select COMEDI_AMPLC_PC236
 	---help---
-	  Enable support for Amplicon PC36AT and PCI236 DIO boards
+	  Enable support for Amplicon PCI236 DIO board.
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called amplc_pc236.
 
-config COMEDI_AMPLC_PC263
-	tristate "Amplicon PC263 and PCI263 relay board support"
-	default N
+config COMEDI_AMPLC_PC263_PCI
+	tristate "Amplicon PCI263 relay board support"
+	select COMEDI_AMPLC_PC263
 	---help---
-	  Enable support for Amplicon PC263 and PCI263 relay boards
+	  Enable support for Amplicon PCI263 relay board.
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called amplc_pc263.
@@ -804,7 +791,6 @@
 config COMEDI_AMPLC_PCI224
 	tristate "Amplicon PCI224 and PCI234 support"
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for Amplicon PCI224 and PCI234 AO boards
 
@@ -814,7 +800,6 @@
 config COMEDI_AMPLC_PCI230
 	tristate "Amplicon PCI230 and PCI260 support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for Amplicon PCI230 and PCI260 Multifunction I/O
 	  boards
@@ -824,16 +809,23 @@
 
 config COMEDI_CONTEC_PCI_DIO
 	tristate "Contec PIO1616L digital I/O board support"
-	default N
 	---help---
 	  Enable support for the Contec PIO1616L digital I/O board
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called contec_pci_dio.
 
+config COMEDI_DAS08_PCI
+	tristate "DAS-08 PCI support"
+	select COMEDI_DAS08
+	---help---
+	  Enable support for PCI DAS-08 cards.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called das08.
+
 config COMEDI_DT3000
 	tristate "Data Translation DT3000 series support"
-	default N
 	---help---
 	  Enable support for Data Translation DT3000 series
 	  DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and
@@ -844,7 +836,6 @@
 
 config COMEDI_DYNA_PCI10XX
 	tristate "Dynalog PCI DAQ series support"
-	default N
 	---help---
 	  Enable support for Dynalog PCI DAQ series
 	  PCI-1050
@@ -854,7 +845,6 @@
 
 config COMEDI_UNIOXX5
 	tristate "Fastwel UNIOxx-5 analog and digital io board support"
-	default N
 	---help---
 	  Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards
 
@@ -864,7 +854,6 @@
 config COMEDI_GSC_HPDI
 	tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support"
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for General Standards Corporation high speed parallel
 	  digital interface rs485 boards PCI-HPDI32 and PMC-HPDI32.
@@ -875,7 +864,6 @@
 
 config COMEDI_ICP_MULTI
 	tristate "Inova ICP_MULTI support"
-	default N
 	---help---
 	  Enable support for Inova ICP_MULTI card
 
@@ -884,7 +872,6 @@
 
 config COMEDI_II_PCI20KC
 	tristate "Intelligent Instruments PCI-20001C carrier support"
-	default N
 	---help---
 	  Enable support for Intelligent Instruments PCI-20001C carrier
 	  PCI-20001, PCI-20006 and PCI-20341
@@ -895,7 +882,6 @@
 config COMEDI_DAQBOARD2000
 	tristate "IOtech DAQboard/2000 support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for the IOtech DAQboard/2000
 
@@ -904,7 +890,6 @@
 
 config COMEDI_JR3_PCI
 	tristate "JR3/PCI force sensor board support"
-	default N
 	---help---
 	  Enable support for JR3/PCI force sensor boards
 
@@ -913,7 +898,6 @@
 
 config COMEDI_KE_COUNTER
 	tristate "Kolter-Electronic PCI Counter 1 card support"
-	default N
 	---help---
 	  Enable support for Kolter-Electronic PCI Counter 1 cards
 
@@ -924,7 +908,6 @@
 	tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support"
 	select COMEDI_8255
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for ComputerBoards/MeasurementComputing PCI-DAS 64xx,
 	  60xx, and 4020 series with the PLX 9080 PCI controller
@@ -936,7 +919,6 @@
 	tristate "MeasurementComputing PCI-DAS support"
 	select COMEDI_8255
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for ComputerBoards/MeasurementComputing PCI-DAS with
 	  AMCC S5933 PCIcontroller: PCI-DAS1602/16, PCI-DAS1602/16jr,
@@ -949,7 +931,6 @@
 config COMEDI_CB_PCIDDA
 	tristate "MeasurementComputing PCI-DDA series support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for ComputerBoards/MeasurementComputing PCI-DDA
 	  series: PCI-DDA08/12, PCI-DDA04/12, PCI-DDA02/12, PCI-DDA08/16,
@@ -961,7 +942,6 @@
 config COMEDI_CB_PCIDIO
 	tristate "MeasurementComputing PCI-DIO series support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for ComputerBoards/MeasurementComputing PCI-DIO series
 	  PCI-DIO24, PCI-DIO24H and PCI-DIO48H
@@ -972,7 +952,6 @@
 config COMEDI_CB_PCIMDAS
 	tristate "MeasurementComputing PCIM-DAS1602/16 support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for ComputerBoards/MeasurementComputing PCI Migration
 	  series PCIM-DAS1602/16
@@ -983,7 +962,6 @@
 config COMEDI_CB_PCIMDDA
 	tristate "MeasurementComputing PCIM-DDA06-16 support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16
 
@@ -992,7 +970,6 @@
 
 config COMEDI_ME4000
 	tristate "Meilhaus ME-4000 support"
-	default N
 	---help---
 	  Enable support for Meilhaus PCI data acquisition cards
 	  ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is
@@ -1002,7 +979,6 @@
 
 config COMEDI_ME_DAQ
 	tristate "Meilhaus ME-2000i, ME-2600i, ME-3000vm1 support"
-	default N
 	---help---
 	  Enable support for Meilhaus PCI data acquisition cards
 	  ME-2000i, ME-2600i and ME-3000vm1
@@ -1013,7 +989,6 @@
 config COMEDI_NI_6527
 	tristate "NI 6527 support"
 	depends on COMEDI_MITE
-	default N
 	---help---
 	  Enable support for the National Instruments 6527 PCI card
 
@@ -1023,7 +998,6 @@
 config COMEDI_NI_65XX
 	tristate "NI 65xx static dio PCI card support"
 	depends on COMEDI_MITE
-	default N
 	---help---
 	  Enable support for National Instruments 65xx static dio boards.
 	  Supported devices: National Instruments PCI-6509 (ni_65xx),
@@ -1037,7 +1011,6 @@
 config COMEDI_NI_660X
 	tristate "NI 660x counter/timer PCI card support"
 	depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
-	default N
 	---help---
 	  Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602,
 	  PXI-6602 and PXI-6608.
@@ -1048,7 +1021,6 @@
 config COMEDI_NI_670X
 	tristate "NI 670x PCI card support"
 	depends on COMEDI_MITE
-	default N
 	---help---
 	  Enable support for National Instruments PCI-6703 and PCI-6704
 
@@ -1059,7 +1031,6 @@
 	tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support"
 	depends on COMEDI_MITE
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for National Instruments PCI-DIO-32HS, PXI-6533,
 	  PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X,
@@ -1075,7 +1046,6 @@
 	depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
 	select COMEDI_8255
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for National Instruments PCI-MIO-E series and M series
 	  (all boards): PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1,
@@ -1094,7 +1064,6 @@
 config COMEDI_RTD520
 	tristate "Real Time Devices PCI4520/DM7520 support"
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for Real Time Devices PCI4520/DM7520
 
@@ -1103,7 +1072,6 @@
 
 config COMEDI_S526
 	tristate "Sensoray s526 support"
-	default N
 	---help---
 	  Enable support for Sensoray s526
 
@@ -1113,7 +1081,6 @@
 config COMEDI_S626
 	tristate "Sensoray 626 support"
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for Sensoray 626
 
@@ -1122,7 +1089,6 @@
 
 config COMEDI_SSV_DNP
 	tristate "SSV Embedded Systems DIL/Net-PC support"
-	default N
 	---help---
 	  Enable support for SSV Embedded Systems DIL/Net-PC
 
@@ -1134,7 +1100,6 @@
 menuconfig COMEDI_PCMCIA_DRIVERS
 	tristate "Comedi PCMCIA drivers"
 	depends on COMEDI && (PCMCIA || PCCARD)
-	default N
 	---help---
 	  Enable comedi PCMCIA and PCCARD drivers to be built
 
@@ -1146,7 +1111,6 @@
 
 config COMEDI_CB_DAS16_CS
 	tristate "CB DAS16 series PCMCIA support"
-	default N
 	---help---
 	  Enable support for the ComputerBoards/MeasurementComputing PCMCIA
 	  cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16
@@ -1157,7 +1121,6 @@
 config COMEDI_DAS08_CS
 	tristate "CB DAS08 PCMCIA support"
 	select COMEDI_DAS08
-	default N
 	---help---
 	  Enable support for the ComputerBoards/MeasurementComputing DAS-08
 	  PCMCIA card
@@ -1168,7 +1131,6 @@
 config COMEDI_NI_DAQ_700_CS
 	tristate "NI DAQCard-700 PCMCIA support"
 	depends on COMEDI_NI_COMMON
-	default N
 	---help---
 	  Enable support for the National Instruments PCMCIA DAQCard-700 DIO
 
@@ -1179,7 +1141,6 @@
 	tristate "NI DAQ-Card DIO-24 PCMCIA support"
 	depends on COMEDI_NI_COMMON
 	select COMEDI_8255
-	default N
 	---help---
 	  Enable support for the National Instruments PCMCIA DAQ-Card DIO-24
 
@@ -1189,7 +1150,6 @@
 config COMEDI_NI_LABPC_CS
 	tristate "NI DAQCard-1200 PCMCIA support"
 	depends on COMEDI_NI_LABPC
-	default N
 	---help---
 	  Enable support for the National Instruments PCMCIA DAQCard-1200
 
@@ -1201,7 +1161,6 @@
 	depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
 	select COMEDI_8255
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for the National Instruments PCMCIA DAQCard E series
 	  DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E
@@ -1212,7 +1171,6 @@
 
 config COMEDI_QUATECH_DAQP_CS
 	tristate "Quatech DAQP PCMCIA data capture card support"
-	default N
 	---help---
 	  Enable support for the Quatech DAQP PCMCIA data capture cards
 	  DAQP-208 and DAQP-308
@@ -1225,7 +1183,6 @@
 menuconfig COMEDI_USB_DRIVERS
 	tristate "Comedi USB drivers"
 	depends on COMEDI && USB
-	default N
 	---help---
 	  Enable comedi USB drivers to be built
 
@@ -1237,7 +1194,6 @@
 
 config COMEDI_DT9812
 	tristate "DataTranslation DT9812 USB module support"
-	default N
 	---help---
 	  Enable support for the Data Translation DT9812 USB module
 
@@ -1246,7 +1202,6 @@
 
 config COMEDI_USBDUX
 	tristate "ITL USB-DUX-D support"
-	default N
 	---help---
 	  Enable support for the Incite Technology Ltd USB-DUX-D Board
 
@@ -1256,7 +1211,6 @@
 config COMEDI_USBDUXFAST
 	tristate "ITL USB-DUXfast support"
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for the Incite Technology Ltd USB-DUXfast Board
 
@@ -1266,7 +1220,6 @@
 config COMEDI_USBDUXSIGMA
 	tristate "ITL USB-DUXsigma support"
 	select COMEDI_FC
-	default N
 	---help---
 	  Enable support for the Incite Technology Ltd USB-DUXsigma Board
 
@@ -1275,7 +1228,6 @@
 
 config COMEDI_VMK80XX
 	tristate "Velleman VM110/VM140 USB Board support"
-	default N
 	---help---
 	  Build the Velleman USB Board Low-Level Driver supporting the
 	  K8055/K8061 aka VM110/VM140 devices
@@ -1288,7 +1240,6 @@
 menuconfig COMEDI_NI_COMMON
 	tristate "Comedi National Instruments card support"
 	depends on COMEDI
-	default N
 	---help---
 	  Enable comedi support for National Instruments cards.
 	  Modules in this section are used by many comedi NI drivers.
@@ -1302,7 +1253,6 @@
 config COMEDI_MITE
 	tristate "NI Mite PCI interface chip support"
 	depends on PCI
-	default N
 	---help---
 	  Enable support for National Instruments Mite PCI interface chip
 
@@ -1312,7 +1262,6 @@
 config COMEDI_NI_TIO
 	tristate "NI general purpose counter support"
 	depends on COMEDI_MITE
-	default N
 	---help---
 	  Enable support for National Instruments general purpose counters.
 	  This module is not used directly by end-users. Rather, it
@@ -1328,7 +1277,6 @@
 	select COMEDI_8255
 	select COMEDI_FC
 	depends on VIRT_TO_BUS
-	default N
 	---help---
 	  Enable support for National Instruments Lab-PC and compatibles
 	  Lab-PC-1200, Lab-PC-1200AI, Lab-PC+ and PCI-1200.
@@ -1343,7 +1291,6 @@
 config COMEDI_8255
 	tristate "Generic 8255 support"
 	depends on COMEDI
-	default N
 	---help---
 	  Enable generic 8255 support.
 
@@ -1357,24 +1304,9 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called 8255.
 
-config COMEDI_DAS08
-	tristate "DAS-08 compatible support"
-	depends on COMEDI
-	select COMEDI_8255
-	default N
-	---help---
-	  Enable support for DAS08 and compatible ISA, PC/104 and PCI cards.
-
-	  Note that PCMCIA DAS08 cards are not directly supported by this
-	  driver, and need a separate driver as a wrapper.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called das08.
-
 config COMEDI_FC
 	tristate "Comedi shared functions for low-level driver support"
 	depends on COMEDI
-	default N
 	---help---
 	  Enable support for shared functions for low-level drivers.
 	  This module is not used directly by end-users. Rather, it
@@ -1382,3 +1314,22 @@
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called comedi_fc.
+
+config COMEDI_AMPLC_DIO200
+	tristate
+	depends on COMEDI
+	select COMEDI_8255
+
+config COMEDI_AMPLC_PC236
+	tristate
+	depends on COMEDI
+	select COMEDI_8255
+
+config COMEDI_AMPLC_PC263
+	tristate
+	depends on COMEDI
+
+config COMEDI_DAS08
+	tristate
+	depends on COMEDI
+	select COMEDI_8255
diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index 14ea35a..8ea55ae 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -465,7 +465,7 @@
 /* only relevant to kernel modules. */
 
 #define COMEDI_CB_EOS		1	/* end of scan */
-#define COMEDI_CB_EOA		2	/* end of acquisition */
+#define COMEDI_CB_EOA		2	/* end of acquisition/output */
 #define COMEDI_CB_BLOCK		4	/* data has arrived:
 					 * wakes up read() / write() */
 #define COMEDI_CB_EOBUF		8	/* DEPRECATED: end of buffer */
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 9bcf87a..7677657 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -58,14 +58,35 @@
 #ifdef CONFIG_COMEDI_DEBUG
 int comedi_debug;
 EXPORT_SYMBOL(comedi_debug);
-module_param(comedi_debug, int, 0644);
+module_param(comedi_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(comedi_debug,
+		 "enable comedi core and driver debugging if non-zero (default 0)"
+		);
 #endif
 
 bool comedi_autoconfig = 1;
-module_param(comedi_autoconfig, bool, 0444);
+module_param(comedi_autoconfig, bool, S_IRUGO);
+MODULE_PARM_DESC(comedi_autoconfig,
+		 "enable drivers to auto-configure comedi devices (default 1)");
 
 static int comedi_num_legacy_minors;
-module_param(comedi_num_legacy_minors, int, 0444);
+module_param(comedi_num_legacy_minors, int, S_IRUGO);
+MODULE_PARM_DESC(comedi_num_legacy_minors,
+		 "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
+		);
+
+unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
+module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(comedi_default_buf_size_kb,
+		 "default asynchronous buffer size in KiB (default "
+		 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
+
+unsigned int comedi_default_buf_maxsize_kb
+	= CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
+module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
+		 "default maximum size of asynchronous buffer in KiB (default "
+		 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
 
 static DEFINE_SPINLOCK(comedi_file_info_table_lock);
 static struct comedi_device_file_info
@@ -108,15 +129,283 @@
 static int comedi_fasync(int fd, struct file *file, int on);
 
 static int is_device_busy(struct comedi_device *dev);
+
 static int resize_async_buffer(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
-			       struct comedi_async *async, unsigned new_size);
+			       struct comedi_async *async, unsigned new_size)
+{
+	int retval;
 
-/* declarations for sysfs attribute files */
-static struct device_attribute dev_attr_max_read_buffer_kb;
-static struct device_attribute dev_attr_read_buffer_kb;
-static struct device_attribute dev_attr_max_write_buffer_kb;
-static struct device_attribute dev_attr_write_buffer_kb;
+	if (new_size > async->max_bufsize)
+		return -EPERM;
+
+	if (s->busy) {
+		DPRINTK("subdevice is busy, cannot resize buffer\n");
+		return -EBUSY;
+	}
+	if (async->mmap_count) {
+		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
+		return -EBUSY;
+	}
+
+	if (!async->prealloc_buf)
+		return -EINVAL;
+
+	/* make sure buffer is an integral number of pages
+	 * (we round up) */
+	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
+
+	retval = comedi_buf_alloc(dev, s, new_size);
+	if (retval < 0)
+		return retval;
+
+	if (s->buf_change) {
+		retval = s->buf_change(dev, s, new_size);
+		if (retval < 0)
+			return retval;
+	}
+
+	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
+		dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
+	return 0;
+}
+
+/* sysfs attribute files */
+
+static const unsigned bytes_per_kibi = 1024;
+
+static ssize_t show_max_read_buffer_kb(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	ssize_t retval;
+	struct comedi_device_file_info *info = dev_get_drvdata(dev);
+	unsigned max_buffer_size_kb = 0;
+	struct comedi_subdevice *const read_subdevice =
+	    comedi_get_read_subdevice(info);
+
+	mutex_lock(&info->device->mutex);
+	if (read_subdevice &&
+	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
+	    read_subdevice->async) {
+		max_buffer_size_kb = read_subdevice->async->max_bufsize /
+		    bytes_per_kibi;
+	}
+	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
+	mutex_unlock(&info->device->mutex);
+
+	return retval;
+}
+
+static ssize_t store_max_read_buffer_kb(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct comedi_device_file_info *info = dev_get_drvdata(dev);
+	unsigned int new_max_size_kb;
+	unsigned int new_max_size;
+	int ret;
+	struct comedi_subdevice *const read_subdevice =
+	    comedi_get_read_subdevice(info);
+
+	ret = kstrtouint(buf, 10, &new_max_size_kb);
+	if (ret)
+		return ret;
+	if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
+		return -EINVAL;
+	new_max_size = new_max_size_kb * bytes_per_kibi;
+
+	mutex_lock(&info->device->mutex);
+	if (read_subdevice == NULL ||
+	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
+	    read_subdevice->async == NULL) {
+		mutex_unlock(&info->device->mutex);
+		return -EINVAL;
+	}
+	read_subdevice->async->max_bufsize = new_max_size;
+	mutex_unlock(&info->device->mutex);
+
+	return count;
+}
+
+static ssize_t show_read_buffer_kb(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	ssize_t retval;
+	struct comedi_device_file_info *info = dev_get_drvdata(dev);
+	unsigned buffer_size_kb = 0;
+	struct comedi_subdevice *const read_subdevice =
+	    comedi_get_read_subdevice(info);
+
+	mutex_lock(&info->device->mutex);
+	if (read_subdevice &&
+	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
+	    read_subdevice->async) {
+		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
+		    bytes_per_kibi;
+	}
+	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
+	mutex_unlock(&info->device->mutex);
+
+	return retval;
+}
+
+static ssize_t store_read_buffer_kb(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct comedi_device_file_info *info = dev_get_drvdata(dev);
+	unsigned int new_size_kb;
+	unsigned int new_size;
+	int retval;
+	int ret;
+	struct comedi_subdevice *const read_subdevice =
+	    comedi_get_read_subdevice(info);
+
+	ret = kstrtouint(buf, 10, &new_size_kb);
+	if (ret)
+		return ret;
+	if (new_size_kb > (UINT_MAX / bytes_per_kibi))
+		return -EINVAL;
+	new_size = new_size_kb * bytes_per_kibi;
+
+	mutex_lock(&info->device->mutex);
+	if (read_subdevice == NULL ||
+	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
+	    read_subdevice->async == NULL) {
+		mutex_unlock(&info->device->mutex);
+		return -EINVAL;
+	}
+	retval = resize_async_buffer(info->device, read_subdevice,
+				     read_subdevice->async, new_size);
+	mutex_unlock(&info->device->mutex);
+
+	if (retval < 0)
+		return retval;
+	return count;
+}
+
+static ssize_t show_max_write_buffer_kb(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	ssize_t retval;
+	struct comedi_device_file_info *info = dev_get_drvdata(dev);
+	unsigned max_buffer_size_kb = 0;
+	struct comedi_subdevice *const write_subdevice =
+	    comedi_get_write_subdevice(info);
+
+	mutex_lock(&info->device->mutex);
+	if (write_subdevice &&
+	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
+	    write_subdevice->async) {
+		max_buffer_size_kb = write_subdevice->async->max_bufsize /
+		    bytes_per_kibi;
+	}
+	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
+	mutex_unlock(&info->device->mutex);
+
+	return retval;
+}
+
+static ssize_t store_max_write_buffer_kb(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	struct comedi_device_file_info *info = dev_get_drvdata(dev);
+	unsigned int new_max_size_kb;
+	unsigned int new_max_size;
+	int ret;
+	struct comedi_subdevice *const write_subdevice =
+	    comedi_get_write_subdevice(info);
+
+	ret = kstrtouint(buf, 10, &new_max_size_kb);
+	if (ret)
+		return ret;
+	if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
+		return -EINVAL;
+	new_max_size = new_max_size_kb * bytes_per_kibi;
+
+	mutex_lock(&info->device->mutex);
+	if (write_subdevice == NULL ||
+	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
+	    write_subdevice->async == NULL) {
+		mutex_unlock(&info->device->mutex);
+		return -EINVAL;
+	}
+	write_subdevice->async->max_bufsize = new_max_size;
+	mutex_unlock(&info->device->mutex);
+
+	return count;
+}
+
+static ssize_t show_write_buffer_kb(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	ssize_t retval;
+	struct comedi_device_file_info *info = dev_get_drvdata(dev);
+	unsigned buffer_size_kb = 0;
+	struct comedi_subdevice *const write_subdevice =
+	    comedi_get_write_subdevice(info);
+
+	mutex_lock(&info->device->mutex);
+	if (write_subdevice &&
+	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
+	    write_subdevice->async) {
+		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
+		    bytes_per_kibi;
+	}
+	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
+	mutex_unlock(&info->device->mutex);
+
+	return retval;
+}
+
+static ssize_t store_write_buffer_kb(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct comedi_device_file_info *info = dev_get_drvdata(dev);
+	unsigned int new_size_kb;
+	unsigned int new_size;
+	int retval;
+	int ret;
+	struct comedi_subdevice *const write_subdevice =
+	    comedi_get_write_subdevice(info);
+
+	ret = kstrtouint(buf, 10, &new_size_kb);
+	if (ret)
+		return ret;
+	if (new_size_kb > (UINT_MAX / bytes_per_kibi))
+		return -EINVAL;
+	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
+
+	mutex_lock(&info->device->mutex);
+	if (write_subdevice == NULL ||
+	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
+	    write_subdevice->async == NULL) {
+		mutex_unlock(&info->device->mutex);
+		return -EINVAL;
+	}
+	retval = resize_async_buffer(info->device, write_subdevice,
+				     write_subdevice->async, new_size);
+	mutex_unlock(&info->device->mutex);
+
+	if (retval < 0)
+		return retval;
+	return count;
+}
+
+static struct device_attribute comedi_dev_attrs[] = {
+	__ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR,
+		show_max_read_buffer_kb, store_max_read_buffer_kb),
+	__ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
+		show_read_buffer_kb, store_read_buffer_kb),
+	__ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR,
+		show_max_write_buffer_kb, store_max_write_buffer_kb),
+	__ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
+		show_write_buffer_kb, store_write_buffer_kb),
+	__ATTR_NULL
+};
 
 static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
 				  unsigned long arg)
@@ -280,7 +569,7 @@
 	if (ret == 0) {
 		if (!try_module_get(dev->driver->module)) {
 			comedi_device_detach(dev);
-			return -ENOSYS;
+			ret = -ENOSYS;
 		}
 	}
 
@@ -1545,7 +1834,7 @@
 	return retval;
 }
 
-static unsigned int comedi_poll(struct file *file, poll_table * wait)
+static unsigned int comedi_poll(struct file *file, poll_table *wait)
 {
 	unsigned int mask = 0;
 	const unsigned minor = iminor(file->f_dentry->d_inode);
@@ -2054,6 +2343,8 @@
 		return PTR_ERR(comedi_class);
 	}
 
+	comedi_class->dev_attrs = comedi_dev_attrs;
+
 	/* XXX requires /proc interface */
 	comedi_proc_init();
 
@@ -2192,11 +2483,9 @@
 
 int comedi_alloc_board_minor(struct device *hardware_device)
 {
-	unsigned long flags;
 	struct comedi_device_file_info *info;
 	struct device *csdev;
 	unsigned i;
-	int retval;
 
 	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
 	if (info == NULL)
@@ -2206,15 +2495,16 @@
 		kfree(info);
 		return -ENOMEM;
 	}
+	info->hardware_device = hardware_device;
 	comedi_device_init(info->device);
-	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+	spin_lock(&comedi_file_info_table_lock);
 	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
 		if (comedi_file_info_table[i] == NULL) {
 			comedi_file_info_table[i] = info;
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+	spin_unlock(&comedi_file_info_table_lock);
 	if (i == COMEDI_NUM_BOARD_MINORS) {
 		comedi_device_cleanup(info->device);
 		kfree(info->device);
@@ -2230,55 +2520,19 @@
 	if (!IS_ERR(csdev))
 		info->device->class_dev = csdev;
 	dev_set_drvdata(csdev, info);
-	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
-	if (retval) {
-		printk(KERN_ERR
-		       "comedi: "
-		       "failed to create sysfs attribute file \"%s\".\n",
-		       dev_attr_max_read_buffer_kb.attr.name);
-		comedi_free_board_minor(i);
-		return retval;
-	}
-	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
-	if (retval) {
-		printk(KERN_ERR
-		       "comedi: "
-		       "failed to create sysfs attribute file \"%s\".\n",
-		       dev_attr_read_buffer_kb.attr.name);
-		comedi_free_board_minor(i);
-		return retval;
-	}
-	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
-	if (retval) {
-		printk(KERN_ERR
-		       "comedi: "
-		       "failed to create sysfs attribute file \"%s\".\n",
-		       dev_attr_max_write_buffer_kb.attr.name);
-		comedi_free_board_minor(i);
-		return retval;
-	}
-	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
-	if (retval) {
-		printk(KERN_ERR
-		       "comedi: "
-		       "failed to create sysfs attribute file \"%s\".\n",
-		       dev_attr_write_buffer_kb.attr.name);
-		comedi_free_board_minor(i);
-		return retval;
-	}
+
 	return i;
 }
 
 void comedi_free_board_minor(unsigned minor)
 {
-	unsigned long flags;
 	struct comedi_device_file_info *info;
 
 	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
-	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+	spin_lock(&comedi_file_info_table_lock);
 	info = comedi_file_info_table[minor];
 	comedi_file_info_table[minor] = NULL;
-	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+	spin_unlock(&comedi_file_info_table_lock);
 
 	if (info) {
 		struct comedi_device *dev = info->device;
@@ -2294,14 +2548,29 @@
 	}
 }
 
+int comedi_find_board_minor(struct device *hardware_device)
+{
+	int minor;
+	struct comedi_device_file_info *info;
+
+	for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
+		spin_lock(&comedi_file_info_table_lock);
+		info = comedi_file_info_table[minor];
+		if (info && info->hardware_device == hardware_device) {
+			spin_unlock(&comedi_file_info_table_lock);
+			return minor;
+		}
+		spin_unlock(&comedi_file_info_table_lock);
+	}
+	return -ENODEV;
+}
+
 int comedi_alloc_subdevice_minor(struct comedi_device *dev,
 				 struct comedi_subdevice *s)
 {
-	unsigned long flags;
 	struct comedi_device_file_info *info;
 	struct device *csdev;
 	unsigned i;
-	int retval;
 
 	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
 	if (info == NULL)
@@ -2309,14 +2578,14 @@
 	info->device = dev;
 	info->read_subdevice = s;
 	info->write_subdevice = s;
-	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+	spin_lock(&comedi_file_info_table_lock);
 	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
 		if (comedi_file_info_table[i] == NULL) {
 			comedi_file_info_table[i] = info;
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+	spin_unlock(&comedi_file_info_table_lock);
 	if (i == COMEDI_NUM_MINORS) {
 		kfree(info);
 		printk(KERN_ERR
@@ -2331,48 +2600,12 @@
 	if (!IS_ERR(csdev))
 		s->class_dev = csdev;
 	dev_set_drvdata(csdev, info);
-	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
-	if (retval) {
-		printk(KERN_ERR
-		       "comedi: "
-		       "failed to create sysfs attribute file \"%s\".\n",
-		       dev_attr_max_read_buffer_kb.attr.name);
-		comedi_free_subdevice_minor(s);
-		return retval;
-	}
-	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
-	if (retval) {
-		printk(KERN_ERR
-		       "comedi: "
-		       "failed to create sysfs attribute file \"%s\".\n",
-		       dev_attr_read_buffer_kb.attr.name);
-		comedi_free_subdevice_minor(s);
-		return retval;
-	}
-	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
-	if (retval) {
-		printk(KERN_ERR
-		       "comedi: "
-		       "failed to create sysfs attribute file \"%s\".\n",
-		       dev_attr_max_write_buffer_kb.attr.name);
-		comedi_free_subdevice_minor(s);
-		return retval;
-	}
-	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
-	if (retval) {
-		printk(KERN_ERR
-		       "comedi: "
-		       "failed to create sysfs attribute file \"%s\".\n",
-		       dev_attr_write_buffer_kb.attr.name);
-		comedi_free_subdevice_minor(s);
-		return retval;
-	}
+
 	return i;
 }
 
 void comedi_free_subdevice_minor(struct comedi_subdevice *s)
 {
-	unsigned long flags;
 	struct comedi_device_file_info *info;
 
 	if (s == NULL)
@@ -2383,10 +2616,10 @@
 	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
 	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
 
-	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+	spin_lock(&comedi_file_info_table_lock);
 	info = comedi_file_info_table[s->minor];
 	comedi_file_info_table[s->minor] = NULL;
-	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+	spin_unlock(&comedi_file_info_table_lock);
 
 	if (s->class_dev) {
 		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
@@ -2397,310 +2630,12 @@
 
 struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
 {
-	unsigned long flags;
 	struct comedi_device_file_info *info;
 
 	BUG_ON(minor >= COMEDI_NUM_MINORS);
-	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+	spin_lock(&comedi_file_info_table_lock);
 	info = comedi_file_info_table[minor];
-	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+	spin_unlock(&comedi_file_info_table_lock);
 	return info;
 }
 EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
-
-static int resize_async_buffer(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_async *async, unsigned new_size)
-{
-	int retval;
-
-	if (new_size > async->max_bufsize)
-		return -EPERM;
-
-	if (s->busy) {
-		DPRINTK("subdevice is busy, cannot resize buffer\n");
-		return -EBUSY;
-	}
-	if (async->mmap_count) {
-		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
-		return -EBUSY;
-	}
-
-	if (!async->prealloc_buf)
-		return -EINVAL;
-
-	/* make sure buffer is an integral number of pages
-	 * (we round up) */
-	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
-
-	retval = comedi_buf_alloc(dev, s, new_size);
-	if (retval < 0)
-		return retval;
-
-	if (s->buf_change) {
-		retval = s->buf_change(dev, s, new_size);
-		if (retval < 0)
-			return retval;
-	}
-
-	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
-		dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
-	return 0;
-}
-
-/* sysfs attribute files */
-
-static const unsigned bytes_per_kibi = 1024;
-
-static ssize_t show_max_read_buffer_kb(struct device *dev,
-				       struct device_attribute *attr, char *buf)
-{
-	ssize_t retval;
-	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned max_buffer_size_kb = 0;
-	struct comedi_subdevice *const read_subdevice =
-	    comedi_get_read_subdevice(info);
-
-	mutex_lock(&info->device->mutex);
-	if (read_subdevice &&
-	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
-	    read_subdevice->async) {
-		max_buffer_size_kb = read_subdevice->async->max_bufsize /
-		    bytes_per_kibi;
-	}
-	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
-	mutex_unlock(&info->device->mutex);
-
-	return retval;
-}
-
-static ssize_t store_max_read_buffer_kb(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t count)
-{
-	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned int new_max_size_kb;
-	unsigned int new_max_size;
-	int ret;
-	struct comedi_subdevice *const read_subdevice =
-	    comedi_get_read_subdevice(info);
-
-	ret = kstrtouint(buf, 10, &new_max_size_kb);
-	if (ret)
-		return ret;
-	if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
-		return -EINVAL;
-	new_max_size = new_max_size_kb * bytes_per_kibi;
-
-	mutex_lock(&info->device->mutex);
-	if (read_subdevice == NULL ||
-	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
-	    read_subdevice->async == NULL) {
-		mutex_unlock(&info->device->mutex);
-		return -EINVAL;
-	}
-	read_subdevice->async->max_bufsize = new_max_size;
-	mutex_unlock(&info->device->mutex);
-
-	return count;
-}
-
-static struct device_attribute dev_attr_max_read_buffer_kb = {
-	.attr = {
-		 .name = "max_read_buffer_kb",
-		 .mode = S_IRUGO | S_IWUSR},
-	.show = &show_max_read_buffer_kb,
-	.store = &store_max_read_buffer_kb
-};
-
-static ssize_t show_read_buffer_kb(struct device *dev,
-				   struct device_attribute *attr, char *buf)
-{
-	ssize_t retval;
-	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned buffer_size_kb = 0;
-	struct comedi_subdevice *const read_subdevice =
-	    comedi_get_read_subdevice(info);
-
-	mutex_lock(&info->device->mutex);
-	if (read_subdevice &&
-	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
-	    read_subdevice->async) {
-		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
-		    bytes_per_kibi;
-	}
-	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
-	mutex_unlock(&info->device->mutex);
-
-	return retval;
-}
-
-static ssize_t store_read_buffer_kb(struct device *dev,
-				    struct device_attribute *attr,
-				    const char *buf, size_t count)
-{
-	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned int new_size_kb;
-	unsigned int new_size;
-	int retval;
-	int ret;
-	struct comedi_subdevice *const read_subdevice =
-	    comedi_get_read_subdevice(info);
-
-	ret = kstrtouint(buf, 10, &new_size_kb);
-	if (ret)
-		return ret;
-	if (new_size_kb > (UINT_MAX / bytes_per_kibi))
-		return -EINVAL;
-	new_size = new_size_kb * bytes_per_kibi;
-
-	mutex_lock(&info->device->mutex);
-	if (read_subdevice == NULL ||
-	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
-	    read_subdevice->async == NULL) {
-		mutex_unlock(&info->device->mutex);
-		return -EINVAL;
-	}
-	retval = resize_async_buffer(info->device, read_subdevice,
-				     read_subdevice->async, new_size);
-	mutex_unlock(&info->device->mutex);
-
-	if (retval < 0)
-		return retval;
-	return count;
-}
-
-static struct device_attribute dev_attr_read_buffer_kb = {
-	.attr = {
-		 .name = "read_buffer_kb",
-		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
-	.show = &show_read_buffer_kb,
-	.store = &store_read_buffer_kb
-};
-
-static ssize_t show_max_write_buffer_kb(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	ssize_t retval;
-	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned max_buffer_size_kb = 0;
-	struct comedi_subdevice *const write_subdevice =
-	    comedi_get_write_subdevice(info);
-
-	mutex_lock(&info->device->mutex);
-	if (write_subdevice &&
-	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
-	    write_subdevice->async) {
-		max_buffer_size_kb = write_subdevice->async->max_bufsize /
-		    bytes_per_kibi;
-	}
-	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
-	mutex_unlock(&info->device->mutex);
-
-	return retval;
-}
-
-static ssize_t store_max_write_buffer_kb(struct device *dev,
-					 struct device_attribute *attr,
-					 const char *buf, size_t count)
-{
-	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned int new_max_size_kb;
-	unsigned int new_max_size;
-	int ret;
-	struct comedi_subdevice *const write_subdevice =
-	    comedi_get_write_subdevice(info);
-
-	ret = kstrtouint(buf, 10, &new_max_size_kb);
-	if (ret)
-		return ret;
-	if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
-		return -EINVAL;
-	new_max_size = new_max_size_kb * bytes_per_kibi;
-
-	mutex_lock(&info->device->mutex);
-	if (write_subdevice == NULL ||
-	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
-	    write_subdevice->async == NULL) {
-		mutex_unlock(&info->device->mutex);
-		return -EINVAL;
-	}
-	write_subdevice->async->max_bufsize = new_max_size;
-	mutex_unlock(&info->device->mutex);
-
-	return count;
-}
-
-static struct device_attribute dev_attr_max_write_buffer_kb = {
-	.attr = {
-		 .name = "max_write_buffer_kb",
-		 .mode = S_IRUGO | S_IWUSR},
-	.show = &show_max_write_buffer_kb,
-	.store = &store_max_write_buffer_kb
-};
-
-static ssize_t show_write_buffer_kb(struct device *dev,
-				    struct device_attribute *attr, char *buf)
-{
-	ssize_t retval;
-	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned buffer_size_kb = 0;
-	struct comedi_subdevice *const write_subdevice =
-	    comedi_get_write_subdevice(info);
-
-	mutex_lock(&info->device->mutex);
-	if (write_subdevice &&
-	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
-	    write_subdevice->async) {
-		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
-		    bytes_per_kibi;
-	}
-	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
-	mutex_unlock(&info->device->mutex);
-
-	return retval;
-}
-
-static ssize_t store_write_buffer_kb(struct device *dev,
-				     struct device_attribute *attr,
-				     const char *buf, size_t count)
-{
-	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned int new_size_kb;
-	unsigned int new_size;
-	int retval;
-	int ret;
-	struct comedi_subdevice *const write_subdevice =
-	    comedi_get_write_subdevice(info);
-
-	ret = kstrtouint(buf, 10, &new_size_kb);
-	if (ret)
-		return ret;
-	if (new_size_kb > (UINT_MAX / bytes_per_kibi))
-		return -EINVAL;
-	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
-
-	mutex_lock(&info->device->mutex);
-	if (write_subdevice == NULL ||
-	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
-	    write_subdevice->async == NULL) {
-		mutex_unlock(&info->device->mutex);
-		return -EINVAL;
-	}
-	retval = resize_async_buffer(info->device, write_subdevice,
-				     write_subdevice->async, new_size);
-	mutex_unlock(&info->device->mutex);
-
-	if (retval < 0)
-		return retval;
-	return count;
-}
-
-static struct device_attribute dev_attr_write_buffer_kb = {
-	.attr = {
-		 .name = "write_buffer_kb",
-		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
-	.show = &show_write_buffer_kb,
-	.store = &store_write_buffer_kb
-};
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 7a0d4bc..134be93 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -180,13 +180,18 @@
 			unsigned int x);
 };
 
+struct pci_dev;
+struct usb_interface;
+
 struct comedi_driver {
 	struct comedi_driver *next;
 
 	const char *driver_name;
 	struct module *module;
 	int (*attach) (struct comedi_device *, struct comedi_devconfig *);
-	int (*detach) (struct comedi_device *);
+	void (*detach) (struct comedi_device *);
+	int (*attach_pci) (struct comedi_device *, struct pci_dev *);
+	int (*attach_usb) (struct comedi_device *, struct usb_interface *);
 
 	/* number of elements in board_name and board_id arrays */
 	unsigned int num_names;
@@ -230,10 +235,16 @@
 	void (*close) (struct comedi_device *dev);
 };
 
+static inline const void *comedi_board(struct comedi_device *dev)
+{
+	return dev->board_ptr;
+}
+
 struct comedi_device_file_info {
 	struct comedi_device *device;
 	struct comedi_subdevice *read_subdevice;
 	struct comedi_subdevice *write_subdevice;
+	struct device *hardware_device;
 };
 
 #ifdef CONFIG_COMEDI_DEBUG
@@ -287,6 +298,56 @@
 int comedi_driver_register(struct comedi_driver *);
 int comedi_driver_unregister(struct comedi_driver *);
 
+/**
+ * module_comedi_driver() - Helper macro for registering a comedi driver
+ * @__comedi_driver: comedi_driver struct
+ *
+ * Helper macro for comedi drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only use
+ * this macro once, and calling it replaces module_init() and module_exit().
+ */
+#define module_comedi_driver(__comedi_driver) \
+	module_driver(__comedi_driver, comedi_driver_register, \
+			comedi_driver_unregister)
+
+struct pci_driver;
+
+int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *);
+void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *);
+
+/**
+ * module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver
+ * @__comedi_driver: comedi_driver struct
+ * @__pci_driver: pci_driver struct
+ *
+ * Helper macro for comedi PCI drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_pci_driver(__comedi_driver, __pci_driver) \
+	module_driver(__comedi_driver, comedi_pci_driver_register, \
+			comedi_pci_driver_unregister, &(__pci_driver))
+
+struct usb_driver;
+
+int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *);
+void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *);
+
+/**
+ * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver
+ * @__comedi_driver: comedi_driver struct
+ * @__usb_driver: usb_driver struct
+ *
+ * Helper macro for comedi USB drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \
+	module_driver(__comedi_driver, comedi_usb_driver_register, \
+			comedi_usb_driver_unregister, &(__usb_driver))
+
 void init_polling(void);
 void cleanup_polling(void);
 void start_polling(struct comedi_device *);
@@ -456,11 +517,12 @@
 int comedi_alloc_subdevice_minor(struct comedi_device *dev,
 				 struct comedi_subdevice *s);
 void comedi_free_subdevice_minor(struct comedi_subdevice *s);
-int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name);
+int comedi_pci_auto_config(struct pci_dev *pcidev,
+			   struct comedi_driver *driver);
 void comedi_pci_auto_unconfig(struct pci_dev *pcidev);
-struct usb_device;		/* forward declaration */
-int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name);
-void comedi_usb_auto_unconfig(struct usb_device *usbdev);
+int comedi_usb_auto_config(struct usb_interface *intf,
+			   struct comedi_driver *driver);
+void comedi_usb_auto_unconfig(struct usb_interface *intf);
 
 #ifdef CONFIG_COMEDI_PCI_DRIVERS
 #define CONFIG_COMEDI_PCI
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index bf185e2..1c3d638 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -106,6 +106,26 @@
 	__comedi_device_detach(dev);
 }
 
+/* do a little post-config cleanup */
+/* called with module refcount incremented, decrements it */
+static int comedi_device_postconfig(struct comedi_device *dev)
+{
+	int ret = postconfig(dev);
+	module_put(dev->driver->module);
+	if (ret < 0) {
+		__comedi_device_detach(dev);
+		return ret;
+	}
+	if (!dev->board_name) {
+		printk(KERN_WARNING "BUG: dev->board_name=<%p>\n",
+		       dev->board_name);
+		dev->board_name = "BUG";
+	}
+	smp_wmb();
+	dev->attached = 1;
+	return 0;
+}
+
 int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct comedi_driver *driv;
@@ -121,59 +141,36 @@
 		}
 		if (driv->num_names) {
 			dev->board_ptr = comedi_recognize(driv, it->board_name);
-			if (dev->board_ptr == NULL) {
-				module_put(driv->module);
-				continue;
-			}
-		} else {
-			if (strcmp(driv->driver_name, it->board_name)) {
-				module_put(driv->module);
-				continue;
-			}
-		}
-		/* initialize dev->driver here so
-		 * comedi_error() can be called from attach */
-		dev->driver = driv;
-		ret = driv->attach(dev, it);
-		if (ret < 0) {
-			module_put(dev->driver->module);
-			__comedi_device_detach(dev);
-			return ret;
-		}
-		goto attached;
-	}
-
-	/*  recognize has failed if we get here */
-	/*  report valid board names before returning error */
-	for (driv = comedi_drivers; driv; driv = driv->next) {
-		if (!try_module_get(driv->module)) {
-			printk(KERN_INFO
-			       "comedi: failed to increment module count\n");
-			continue;
-		}
-		comedi_report_boards(driv);
+			if (dev->board_ptr)
+				break;
+		} else if (strcmp(driv->driver_name, it->board_name))
+			break;
 		module_put(driv->module);
 	}
-	return -EIO;
-
-attached:
-	/* do a little post-config cleanup */
-	ret = postconfig(dev);
-	module_put(dev->driver->module);
+	if (driv == NULL) {
+		/*  recognize has failed if we get here */
+		/*  report valid board names before returning error */
+		for (driv = comedi_drivers; driv; driv = driv->next) {
+			if (!try_module_get(driv->module)) {
+				printk(KERN_INFO
+				       "comedi: failed to increment module count\n");
+				continue;
+			}
+			comedi_report_boards(driv);
+			module_put(driv->module);
+		}
+		return -EIO;
+	}
+	/* initialize dev->driver here so
+	 * comedi_error() can be called from attach */
+	dev->driver = driv;
+	ret = driv->attach(dev, it);
 	if (ret < 0) {
+		module_put(dev->driver->module);
 		__comedi_device_detach(dev);
 		return ret;
 	}
-
-	if (!dev->board_name) {
-		printk(KERN_WARNING "BUG: dev->board_name=<%p>\n",
-		       dev->board_name);
-		dev->board_name = "BUG";
-	}
-	smp_wmb();
-	dev->attached = 1;
-
-	return 0;
+	return comedi_device_postconfig(dev);
 }
 
 int comedi_driver_register(struct comedi_driver *driver)
@@ -242,6 +239,8 @@
 			s->len_chanlist = 1;
 
 		if (s->do_cmd) {
+			unsigned int buf_size;
+
 			BUG_ON((s->subdev_flags & (SDF_CMD_READ |
 						   SDF_CMD_WRITE)) == 0);
 			BUG_ON(!s->do_cmdtest);
@@ -257,19 +256,20 @@
 			async->subdevice = s;
 			s->async = async;
 
-#define DEFAULT_BUF_MAXSIZE (64*1024)
-#define DEFAULT_BUF_SIZE (64*1024)
-
-			async->max_bufsize = DEFAULT_BUF_MAXSIZE;
+			async->max_bufsize =
+				comedi_default_buf_maxsize_kb * 1024;
+			buf_size = comedi_default_buf_size_kb * 1024;
+			if (buf_size > async->max_bufsize)
+				buf_size = async->max_bufsize;
 
 			async->prealloc_buf = NULL;
 			async->prealloc_bufsz = 0;
-			if (comedi_buf_alloc(dev, s, DEFAULT_BUF_SIZE) < 0) {
+			if (comedi_buf_alloc(dev, s, buf_size) < 0) {
 				printk(KERN_INFO "Buffer allocation failed\n");
 				return -ENOMEM;
 			}
 			if (s->buf_change) {
-				ret = s->buf_change(dev, s, DEFAULT_BUF_SIZE);
+				ret = s->buf_change(dev, s, buf_size);
 				if (ret < 0)
 					return ret;
 			}
@@ -814,67 +814,102 @@
 	async->events = 0;
 }
 
-static int comedi_auto_config(struct device *hardware_device,
-			      const char *board_name, const int *options,
-			      unsigned num_options)
+static int
+comedi_auto_config_helper(struct device *hardware_device,
+			  struct comedi_driver *driver,
+			  int (*attach_wrapper) (struct comedi_device *,
+						 void *), void *context)
 {
-	struct comedi_devconfig it;
 	int minor;
 	struct comedi_device_file_info *dev_file_info;
-	int retval;
-	unsigned *private_data = NULL;
+	struct comedi_device *comedi_dev;
+	int ret;
 
-	if (!comedi_autoconfig) {
-		dev_set_drvdata(hardware_device, NULL);
+	if (!comedi_autoconfig)
 		return 0;
-	}
 
 	minor = comedi_alloc_board_minor(hardware_device);
 	if (minor < 0)
 		return minor;
 
-	private_data = kmalloc(sizeof(unsigned), GFP_KERNEL);
-	if (private_data == NULL) {
-		retval = -ENOMEM;
-		goto cleanup;
-	}
-	*private_data = minor;
-	dev_set_drvdata(hardware_device, private_data);
-
 	dev_file_info = comedi_get_device_file_info(minor);
+	comedi_dev = dev_file_info->device;
+
+	mutex_lock(&comedi_dev->mutex);
+	if (comedi_dev->attached)
+		ret = -EBUSY;
+	else if (!try_module_get(driver->module)) {
+		printk(KERN_INFO "comedi: failed to increment module count\n");
+		ret = -EIO;
+	} else {
+		/* set comedi_dev->driver here for attach wrapper */
+		comedi_dev->driver = driver;
+		ret = (*attach_wrapper)(comedi_dev, context);
+		if (ret < 0) {
+			module_put(driver->module);
+			__comedi_device_detach(comedi_dev);
+		} else {
+			ret = comedi_device_postconfig(comedi_dev);
+		}
+	}
+	mutex_unlock(&comedi_dev->mutex);
+
+	if (ret < 0)
+		comedi_free_board_minor(minor);
+	return ret;
+}
+
+static int comedi_auto_config_wrapper(struct comedi_device *dev, void *context)
+{
+	struct comedi_devconfig *it = context;
+	struct comedi_driver *driv = dev->driver;
+
+	if (driv->num_names) {
+		/* look for generic board entry matching driver name, which
+		 * has already been copied to it->board_name */
+		dev->board_ptr = comedi_recognize(driv, it->board_name);
+		if (dev->board_ptr == NULL) {
+			printk(KERN_WARNING
+			       "comedi: auto config failed to find board entry"
+			       " '%s' for driver '%s'\n", it->board_name,
+			       driv->driver_name);
+			comedi_report_boards(driv);
+			return -EINVAL;
+		}
+	}
+	return driv->attach(dev, it);
+}
+
+static int comedi_auto_config(struct device *hardware_device,
+			      struct comedi_driver *driver, const int *options,
+			      unsigned num_options)
+{
+	struct comedi_devconfig it;
 
 	memset(&it, 0, sizeof(it));
-	strncpy(it.board_name, board_name, COMEDI_NAMELEN);
+	strncpy(it.board_name, driver->driver_name, COMEDI_NAMELEN);
 	it.board_name[COMEDI_NAMELEN - 1] = '\0';
 	BUG_ON(num_options > COMEDI_NDEVCONFOPTS);
 	memcpy(it.options, options, num_options * sizeof(int));
-
-	mutex_lock(&dev_file_info->device->mutex);
-	retval = comedi_device_attach(dev_file_info->device, &it);
-	mutex_unlock(&dev_file_info->device->mutex);
-
-cleanup:
-	if (retval < 0) {
-		kfree(private_data);
-		comedi_free_board_minor(minor);
-	}
-	return retval;
+	return comedi_auto_config_helper(hardware_device, driver,
+					 comedi_auto_config_wrapper, &it);
 }
 
 static void comedi_auto_unconfig(struct device *hardware_device)
 {
-	unsigned *minor = (unsigned *)dev_get_drvdata(hardware_device);
-	if (minor == NULL)
+	int minor;
+
+	if (hardware_device == NULL)
 		return;
-
-	BUG_ON(*minor >= COMEDI_NUM_BOARD_MINORS);
-
-	comedi_free_board_minor(*minor);
-	dev_set_drvdata(hardware_device, NULL);
-	kfree(minor);
+	minor = comedi_find_board_minor(hardware_device);
+	if (minor < 0)
+		return;
+	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
+	comedi_free_board_minor(minor);
 }
 
-int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name)
+static int comedi_old_pci_auto_config(struct pci_dev *pcidev,
+				      struct comedi_driver *driver)
 {
 	int options[2];
 
@@ -883,9 +918,30 @@
 	/*  pci slot */
 	options[1] = PCI_SLOT(pcidev->devfn);
 
-	return comedi_auto_config(&pcidev->dev, board_name,
+	return comedi_auto_config(&pcidev->dev, driver,
 				  options, ARRAY_SIZE(options));
 }
+
+static int comedi_pci_attach_wrapper(struct comedi_device *dev, void *pcidev)
+{
+	return dev->driver->attach_pci(dev, pcidev);
+}
+
+static int comedi_new_pci_auto_config(struct pci_dev *pcidev,
+				      struct comedi_driver *driver)
+{
+	return comedi_auto_config_helper(&pcidev->dev, driver,
+					 comedi_pci_attach_wrapper, pcidev);
+}
+
+int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver)
+{
+
+	if (driver->attach_pci)
+		return comedi_new_pci_auto_config(pcidev, driver);
+	else
+		return comedi_old_pci_auto_config(pcidev, driver);
+}
 EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
 
 void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
@@ -894,16 +950,96 @@
 }
 EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig);
 
-int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name)
+int comedi_pci_driver_register(struct comedi_driver *comedi_driver,
+		struct pci_driver *pci_driver)
 {
-	BUG_ON(usbdev == NULL);
-	return comedi_auto_config(&usbdev->dev, board_name, NULL, 0);
+	int ret;
+
+	ret = comedi_driver_register(comedi_driver);
+	if (ret < 0)
+		return ret;
+
+	/* FIXME: Remove this test after auditing all comedi pci drivers */
+	if (!pci_driver->name)
+		pci_driver->name = comedi_driver->driver_name;
+
+	ret = pci_register_driver(pci_driver);
+	if (ret < 0) {
+		comedi_driver_unregister(comedi_driver);
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_pci_driver_register);
+
+void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver,
+		struct pci_driver *pci_driver)
+{
+	pci_unregister_driver(pci_driver);
+	comedi_driver_unregister(comedi_driver);
+}
+EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister);
+
+static int comedi_old_usb_auto_config(struct usb_interface *intf,
+				      struct comedi_driver *driver)
+{
+	return comedi_auto_config(&intf->dev, driver, NULL, 0);
+}
+
+static int comedi_usb_attach_wrapper(struct comedi_device *dev, void *intf)
+{
+	return dev->driver->attach_usb(dev, intf);
+}
+
+static int comedi_new_usb_auto_config(struct usb_interface *intf,
+				      struct comedi_driver *driver)
+{
+	return comedi_auto_config_helper(&intf->dev, driver,
+					 comedi_usb_attach_wrapper, intf);
+}
+
+int comedi_usb_auto_config(struct usb_interface *intf,
+			   struct comedi_driver *driver)
+{
+	BUG_ON(intf == NULL);
+	if (driver->attach_usb)
+		return comedi_new_usb_auto_config(intf, driver);
+	else
+		return comedi_old_usb_auto_config(intf, driver);
 }
 EXPORT_SYMBOL_GPL(comedi_usb_auto_config);
 
-void comedi_usb_auto_unconfig(struct usb_device *usbdev)
+void comedi_usb_auto_unconfig(struct usb_interface *intf)
 {
-	BUG_ON(usbdev == NULL);
-	comedi_auto_unconfig(&usbdev->dev);
+	BUG_ON(intf == NULL);
+	comedi_auto_unconfig(&intf->dev);
 }
 EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig);
+
+int comedi_usb_driver_register(struct comedi_driver *comedi_driver,
+		struct usb_driver *usb_driver)
+{
+	int ret;
+
+	ret = comedi_driver_register(comedi_driver);
+	if (ret < 0)
+		return ret;
+
+	ret = usb_register(usb_driver);
+	if (ret < 0) {
+		comedi_driver_unregister(comedi_driver);
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_usb_driver_register);
+
+void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver,
+		struct usb_driver *usb_driver)
+{
+	usb_deregister(usb_driver);
+	comedi_driver_unregister(comedi_driver);
+}
+EXPORT_SYMBOL_GPL(comedi_usb_driver_unregister);
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index 6c26ac8..27e39e4 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -107,31 +107,6 @@
 #define CALLBACK_FUNC	(((struct subdev_8255_struct *)s->private)->cb_func)
 #define subdevpriv	((struct subdev_8255_struct *)s->private)
 
-static int dev_8255_attach(struct comedi_device *dev,
-			   struct comedi_devconfig *it);
-static int dev_8255_detach(struct comedi_device *dev);
-static struct comedi_driver driver_8255 = {
-	.driver_name = "8255",
-	.module = THIS_MODULE,
-	.attach = dev_8255_attach,
-	.detach = dev_8255_detach,
-};
-
-static int __init driver_8255_init_module(void)
-{
-	return comedi_driver_register(&driver_8255);
-}
-
-static void __exit driver_8255_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_8255);
-}
-
-module_init(driver_8255_init_module);
-module_exit(driver_8255_cleanup_module);
-
-static void do_config(struct comedi_device *dev, struct comedi_subdevice *s);
-
 void subdev_8255_interrupt(struct comedi_device *dev,
 			   struct comedi_subdevice *s)
 {
@@ -185,6 +160,23 @@
 	return 2;
 }
 
+static void do_config(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+	int config;
+
+	config = CR_CW;
+	/* 1 in io_bits indicates output, 1 in config indicates input */
+	if (!(s->io_bits & 0x0000ff))
+		config |= CR_A_IO;
+	if (!(s->io_bits & 0x00ff00))
+		config |= CR_B_IO;
+	if (!(s->io_bits & 0x0f0000))
+		config |= CR_C_LO_IO;
+	if (!(s->io_bits & 0xf00000))
+		config |= CR_C_HI_IO;
+	CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG);
+}
+
 static int subdev_8255_insn_config(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
 				   struct comedi_insn *insn, unsigned int *data)
@@ -222,23 +214,6 @@
 	return 1;
 }
 
-static void do_config(struct comedi_device *dev, struct comedi_subdevice *s)
-{
-	int config;
-
-	config = CR_CW;
-	/* 1 in io_bits indicates output, 1 in config indicates input */
-	if (!(s->io_bits & 0x0000ff))
-		config |= CR_A_IO;
-	if (!(s->io_bits & 0x00ff00))
-		config |= CR_B_IO;
-	if (!(s->io_bits & 0x0f0000))
-		config |= CR_C_LO_IO;
-	if (!(s->io_bits & 0xf00000))
-		config |= CR_C_HI_IO;
-	CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG);
-}
-
 static int subdev_8255_cmdtest(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_cmd *cmd)
@@ -442,14 +417,12 @@
 	return 0;
 }
 
-static int dev_8255_detach(struct comedi_device *dev)
+static void dev_8255_detach(struct comedi_device *dev)
 {
 	int i;
 	unsigned long iobase;
 	struct comedi_subdevice *s;
 
-	printk(KERN_INFO "comedi%d: 8255: remove\n", dev->minor);
-
 	for (i = 0; i < dev->n_subdevices; i++) {
 		s = dev->subdevices + i;
 		if (s->type != COMEDI_SUBD_UNUSED) {
@@ -458,10 +431,16 @@
 		}
 		subdev_8255_cleanup(dev, s);
 	}
-
-	return 0;
 }
 
+static struct comedi_driver dev_8255_driver = {
+	.driver_name	= "8255",
+	.module		= THIS_MODULE,
+	.attach		= dev_8255_attach,
+	.detach		= dev_8255_detach,
+};
+module_comedi_driver(dev_8255_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c
index 9def225..4e4fc41 100644
--- a/drivers/staging/comedi/drivers/acl7225b.c
+++ b/drivers/staging/comedi/drivers/acl7225b.c
@@ -22,46 +22,13 @@
 #define ACL7225_DI_LO  2	/* Digital input low byte (DI0-DI7) */
 #define ACL7225_DI_HI  3	/* Digital input high byte (DI8-DI15) */
 
-static int acl7225b_attach(struct comedi_device *dev,
-			   struct comedi_devconfig *it);
-static int acl7225b_detach(struct comedi_device *dev);
-
 struct boardtype {
 	const char *name;	/*  driver name */
 	int io_range;		/*  len of I/O space */
 };
 
-static const struct boardtype boardtypes[] = {
-	{"acl7225b", ACL7225_SIZE,},
-	{"p16r16dio", P16R16DIO_SIZE,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
 #define this_board ((const struct boardtype *)dev->board_ptr)
 
-static struct comedi_driver driver_acl7225b = {
-	.driver_name = "acl7225b",
-	.module = THIS_MODULE,
-	.attach = acl7225b_attach,
-	.detach = acl7225b_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct boardtype),
-};
-
-static int __init driver_acl7225b_init_module(void)
-{
-	return comedi_driver_register(&driver_acl7225b);
-}
-
-static void __exit driver_acl7225b_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_acl7225b);
-}
-
-module_init(driver_acl7225b_init_module);
-module_exit(driver_acl7225b_cleanup_module);
-
 static int acl7225b_do_insn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
@@ -152,16 +119,28 @@
 	return 0;
 }
 
-static int acl7225b_detach(struct comedi_device *dev)
+static void acl7225b_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: acl7225b: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, this_board->io_range);
-
-	return 0;
 }
 
+static const struct boardtype boardtypes[] = {
+	{ "acl7225b", ACL7225_SIZE, },
+	{ "p16r16dio", P16R16DIO_SIZE, },
+};
+
+static struct comedi_driver acl7225b_driver = {
+	.driver_name	= "acl7225b",
+	.module		= THIS_MODULE,
+	.attach		= acl7225b_attach,
+	.detach		= acl7225b_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct boardtype),
+};
+module_comedi_driver(acl7225b_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index ca5bd9b8..44aaf83 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -224,2318 +224,1213 @@
 
 static const struct addi_board boardtypes[] = {
 #ifdef CONFIG_APCI_3120
-	{"apci3120",
-			APCI3120_BOARD_VENDOR_ID,
-			0x818D,
-			AMCC_OP_REG_SIZE,
-			APCI3120_ADDRESS_RANGE,
-			8,
-			0,
-			ADDIDATA_NO_EEPROM,
-			NULL,
-			16,
-			8,
-			16,
-			8,
-			0xffff,
-			0x3fff,
-			&range_apci3120_ai,
-			&range_apci3120_ao,
-			4,
-			4,
-			0x0f,
-			0,
-			NULL,
-			1,
-			1,
-			1,
-			10000,
-			100000,
-			v_APCI3120_Interrupt,
-			i_APCI3120_Reset,
-			i_APCI3120_InsnConfigAnalogInput,
-			i_APCI3120_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			i_APCI3120_CommandTestAnalogInput,
-			i_APCI3120_CommandAnalogInput,
-			i_APCI3120_StopCyclicAcquisition,
-			NULL,
-			i_APCI3120_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			i_APCI3120_InsnReadDigitalInput,
-			NULL,
-			i_APCI3120_InsnBitsDigitalInput,
-			i_APCI3120_InsnConfigDigitalOutput,
-			i_APCI3120_InsnWriteDigitalOutput,
-			i_APCI3120_InsnBitsDigitalOutput,
-			NULL,
-			i_APCI3120_InsnConfigTimer,
-			i_APCI3120_InsnWriteTimer,
-			i_APCI3120_InsnReadTimer,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci3120",
+		.i_VendorId		= APCI3120_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x818D,
+		.i_IorangeBase0		= AMCC_OP_REG_SIZE,
+		.i_IorangeBase1		= APCI3120_ADDRESS_RANGE,
+		.i_IorangeBase2		= 8,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_NbrAoChannel		= 8,
+		.i_AiMaxdata		= 0xffff,
+		.i_AoMaxdata		= 0x3fff,
+		.pr_AiRangelist		= &range_apci3120_ai,
+		.pr_AoRangelist		= &range_apci3120_ao,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 0x0f,
+		.i_Dma			= 1,
+		.i_Timer		= 1,
+		.b_AvailableConvertUnit	= 1,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.ui_MinDelaytimeNs	= 100000,
+		.interrupt		= v_APCI3120_Interrupt,
+		.reset			= i_APCI3120_Reset,
+		.ai_config		= i_APCI3120_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3120_InsnReadAnalogInput,
+		.ai_cmdtest		= i_APCI3120_CommandTestAnalogInput,
+		.ai_cmd			= i_APCI3120_CommandAnalogInput,
+		.ai_cancel		= i_APCI3120_StopCyclicAcquisition,
+		.ao_write		= i_APCI3120_InsnWriteAnalogOutput,
+		.di_read		= i_APCI3120_InsnReadDigitalInput,
+		.di_bits		= i_APCI3120_InsnBitsDigitalInput,
+		.do_config		= i_APCI3120_InsnConfigDigitalOutput,
+		.do_write		= i_APCI3120_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3120_InsnBitsDigitalOutput,
+		.timer_config		= i_APCI3120_InsnConfigTimer,
+		.timer_write		= i_APCI3120_InsnWriteTimer,
+		.timer_read		= i_APCI3120_InsnReadTimer,
+	},
 #endif
 #ifdef CONFIG_APCI_1032
-	{"apci1032",
-			APCI1032_BOARD_VENDOR_ID,
-			0x1003,
-			4,
-			APCI1032_ADDRESS_RANGE,
-			0,
-			0,
-			ADDIDATA_EEPROM,
-			ADDIDATA_93C76,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			32,
-			0,
-			0,
-			0,
-			NULL,
-			0,
-			0,
-			0,
-			0,
-			0,
-			v_APCI1032_Interrupt,
-			i_APCI1032_Reset,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI1032_ConfigDigitalInput,
-			i_APCI1032_Read1DigitalInput,
-			NULL,
-			i_APCI1032_ReadMoreDigitalInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci1032",
+		.i_VendorId		= APCI1032_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x1003,
+		.i_IorangeBase0		= 4,
+		.i_IorangeBase1		= APCI1032_ADDRESS_RANGE,
+		.i_PCIEeprom		= ADDIDATA_EEPROM,
+		.pc_EepromChip		= ADDIDATA_93C76,
+		.i_NbrDiChannel		= 32,
+		.interrupt		= v_APCI1032_Interrupt,
+		.reset			= i_APCI1032_Reset,
+		.di_config		= i_APCI1032_ConfigDigitalInput,
+		.di_read		= i_APCI1032_Read1DigitalInput,
+		.di_bits		= i_APCI1032_ReadMoreDigitalInput,
+	},
 #endif
 #ifdef CONFIG_APCI_1516
-	{"apci1516",
-			APCI1516_BOARD_VENDOR_ID,
-			0x1001,
-			128,
-			APCI1516_ADDRESS_RANGE,
-			32,
-			0,
-			ADDIDATA_EEPROM,
-			ADDIDATA_S5920,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			8,
-			8,
-			0,
-			0,
-			NULL,
-			0,
-			1,
-			0,
-			0,
-			0,
-			NULL,
-			i_APCI1516_Reset,
-			NULL, NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI1516_Read1DigitalInput,
-			NULL,
-			i_APCI1516_ReadMoreDigitalInput,
-			i_APCI1516_ConfigDigitalOutput,
-			i_APCI1516_WriteDigitalOutput,
-			i_APCI1516_ReadDigitalOutput,
-			NULL,
-			i_APCI1516_ConfigWatchdog,
-			i_APCI1516_StartStopWriteWatchdog,
-			i_APCI1516_ReadWatchdog,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci1516",
+		.i_VendorId		= APCI1516_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x1001,
+		.i_IorangeBase0		= 128,
+		.i_IorangeBase1		= APCI1516_ADDRESS_RANGE,
+		.i_IorangeBase2		= 32,
+		.i_PCIEeprom		= ADDIDATA_EEPROM,
+		.pc_EepromChip		= ADDIDATA_S5920,
+		.i_NbrDiChannel		= 8,
+		.i_NbrDoChannel		= 8,
+		.i_Timer		= 1,
+		.reset			= i_APCI1516_Reset,
+		.di_read		= i_APCI1516_Read1DigitalInput,
+		.di_bits		= i_APCI1516_ReadMoreDigitalInput,
+		.do_config		= i_APCI1516_ConfigDigitalOutput,
+		.do_write		= i_APCI1516_WriteDigitalOutput,
+		.do_bits		= i_APCI1516_ReadDigitalOutput,
+		.timer_config		= i_APCI1516_ConfigWatchdog,
+		.timer_write		= i_APCI1516_StartStopWriteWatchdog,
+		.timer_read		= i_APCI1516_ReadWatchdog,
+	},
 #endif
 #ifdef CONFIG_APCI_2016
-	{"apci2016",
-			APCI2016_BOARD_VENDOR_ID,
-			0x1002,
-			128,
-			APCI2016_ADDRESS_RANGE,
-			32,
-			0,
-			ADDIDATA_EEPROM,
-			ADDIDATA_S5920,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			0,
-			16,
-			0,
-			0,
-			NULL,
-			0,
-			1,
-			0,
-			0,
-			0,
-			NULL,
-			i_APCI2016_Reset,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI2016_ConfigDigitalOutput,
-			i_APCI2016_WriteDigitalOutput,
-			i_APCI2016_BitsDigitalOutput,
-			NULL,
-			i_APCI2016_ConfigWatchdog,
-			i_APCI2016_StartStopWriteWatchdog,
-			i_APCI2016_ReadWatchdog,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci2016",
+		.i_VendorId		= APCI2016_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x1002,
+		.i_IorangeBase0		= 128,
+		.i_IorangeBase1		= APCI2016_ADDRESS_RANGE,
+		.i_IorangeBase2		= 32,
+		.i_PCIEeprom		= ADDIDATA_EEPROM,
+		.pc_EepromChip		= ADDIDATA_S5920,
+		.i_NbrDoChannel		= 16,
+		.i_Timer		= 1,
+		.reset			= i_APCI2016_Reset,
+		.do_config		= i_APCI2016_ConfigDigitalOutput,
+		.do_write		= i_APCI2016_WriteDigitalOutput,
+		.do_bits		= i_APCI2016_BitsDigitalOutput,
+		.timer_config		= i_APCI2016_ConfigWatchdog,
+		.timer_write		= i_APCI2016_StartStopWriteWatchdog,
+		.timer_read		= i_APCI2016_ReadWatchdog,
+	},
 #endif
 #ifdef CONFIG_APCI_2032
-	{"apci2032",
-			APCI2032_BOARD_VENDOR_ID,
-			0x1004,
-			4,
-			APCI2032_ADDRESS_RANGE,
-			0,
-			0,
-			ADDIDATA_EEPROM,
-			ADDIDATA_93C76,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			0,
-			32,
-			0xffffffff,
-			0,
-			NULL,
-			0,
-			1,
-			0,
-			0,
-			0,
-			v_APCI2032_Interrupt,
-			i_APCI2032_Reset,
-			NULL, NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI2032_ConfigDigitalOutput,
-			i_APCI2032_WriteDigitalOutput,
-			i_APCI2032_ReadDigitalOutput,
-			i_APCI2032_ReadInterruptStatus,
-			i_APCI2032_ConfigWatchdog,
-			i_APCI2032_StartStopWriteWatchdog,
-			i_APCI2032_ReadWatchdog,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci2032",
+		.i_VendorId		= APCI2032_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x1004,
+		.i_IorangeBase0		= 4,
+		.i_IorangeBase1		= APCI2032_ADDRESS_RANGE,
+		.i_PCIEeprom		= ADDIDATA_EEPROM,
+		.pc_EepromChip		= ADDIDATA_93C76,
+		.i_NbrDoChannel		= 32,
+		.i_DoMaxdata		= 0xffffffff,
+		.i_Timer		= 1,
+		.interrupt		= v_APCI2032_Interrupt,
+		.reset			= i_APCI2032_Reset,
+		.do_config		= i_APCI2032_ConfigDigitalOutput,
+		.do_write		= i_APCI2032_WriteDigitalOutput,
+		.do_bits		= i_APCI2032_ReadDigitalOutput,
+		.do_read		= i_APCI2032_ReadInterruptStatus,
+		.timer_config		= i_APCI2032_ConfigWatchdog,
+		.timer_write		= i_APCI2032_StartStopWriteWatchdog,
+		.timer_read		= i_APCI2032_ReadWatchdog,
+	},
 #endif
 #ifdef CONFIG_APCI_2200
-	{"apci2200",
-			APCI2200_BOARD_VENDOR_ID,
-			0x1005,
-			4,
-			APCI2200_ADDRESS_RANGE,
-			0,
-			0,
-			ADDIDATA_EEPROM,
-			ADDIDATA_93C76,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			8,
-			16,
-			0,
-			0,
-			NULL,
-			0,
-			1,
-			0,
-			0,
-			0,
-			NULL,
-			i_APCI2200_Reset,
-			NULL, NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI2200_Read1DigitalInput,
-			NULL,
-			i_APCI2200_ReadMoreDigitalInput,
-			i_APCI2200_ConfigDigitalOutput,
-			i_APCI2200_WriteDigitalOutput,
-			i_APCI2200_ReadDigitalOutput,
-			NULL,
-			i_APCI2200_ConfigWatchdog,
-			i_APCI2200_StartStopWriteWatchdog,
-			i_APCI2200_ReadWatchdog,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci2200",
+		.i_VendorId		= APCI2200_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x1005,
+		.i_IorangeBase0		= 4,
+		.i_IorangeBase1		= APCI2200_ADDRESS_RANGE,
+		.i_PCIEeprom		= ADDIDATA_EEPROM,
+		.pc_EepromChip		= ADDIDATA_93C76,
+		.i_NbrDiChannel		= 8,
+		.i_NbrDoChannel		= 16,
+		.i_Timer		= 1,
+		.reset			= i_APCI2200_Reset,
+		.di_read		= i_APCI2200_Read1DigitalInput,
+		.di_bits		= i_APCI2200_ReadMoreDigitalInput,
+		.do_config		= i_APCI2200_ConfigDigitalOutput,
+		.do_write		= i_APCI2200_WriteDigitalOutput,
+		.do_bits		= i_APCI2200_ReadDigitalOutput,
+		.timer_config		= i_APCI2200_ConfigWatchdog,
+		.timer_write		= i_APCI2200_StartStopWriteWatchdog,
+		.timer_read		= i_APCI2200_ReadWatchdog,
+	},
 #endif
 #ifdef CONFIG_APCI_1564
-	{"apci1564",
-			APCI1564_BOARD_VENDOR_ID,
-			0x1006,
-			128,
-			APCI1564_ADDRESS_RANGE,
-			0,
-			0,
-			ADDIDATA_EEPROM,
-			ADDIDATA_93C76,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			32,
-			32,
-			0xffffffff,
-			0,
-			NULL,
-			0,
-			1,
-			0,
-			0,
-			0,
-			v_APCI1564_Interrupt,
-			i_APCI1564_Reset,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI1564_ConfigDigitalInput,
-			i_APCI1564_Read1DigitalInput,
-			NULL,
-			i_APCI1564_ReadMoreDigitalInput,
-			i_APCI1564_ConfigDigitalOutput,
-			i_APCI1564_WriteDigitalOutput,
-			i_APCI1564_ReadDigitalOutput,
-			i_APCI1564_ReadInterruptStatus,
-			i_APCI1564_ConfigTimerCounterWatchdog,
-			i_APCI1564_StartStopWriteTimerCounterWatchdog,
-			i_APCI1564_ReadTimerCounterWatchdog,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci1564",
+		.i_VendorId		= APCI1564_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x1006,
+		.i_IorangeBase0		= 128,
+		.i_IorangeBase1		= APCI1564_ADDRESS_RANGE,
+		.i_PCIEeprom		= ADDIDATA_EEPROM,
+		.pc_EepromChip		= ADDIDATA_93C76,
+		.i_NbrDiChannel		= 32,
+		.i_NbrDoChannel		= 32,
+		.i_DoMaxdata		= 0xffffffff,
+		.i_Timer		= 1,
+		.interrupt		= v_APCI1564_Interrupt,
+		.reset			= i_APCI1564_Reset,
+		.di_config		= i_APCI1564_ConfigDigitalInput,
+		.di_read		= i_APCI1564_Read1DigitalInput,
+		.di_bits		= i_APCI1564_ReadMoreDigitalInput,
+		.do_config		= i_APCI1564_ConfigDigitalOutput,
+		.do_write		= i_APCI1564_WriteDigitalOutput,
+		.do_bits		= i_APCI1564_ReadDigitalOutput,
+		.do_read		= i_APCI1564_ReadInterruptStatus,
+		.timer_config		= i_APCI1564_ConfigTimerCounterWatchdog,
+		.timer_write		= i_APCI1564_StartStopWriteTimerCounterWatchdog,
+		.timer_read		= i_APCI1564_ReadTimerCounterWatchdog,
+	},
 #endif
 #ifdef CONFIG_APCI_1500
-	{"apci1500",
-			APCI1500_BOARD_VENDOR_ID,
-			0x80fc,
-			128,
-			APCI1500_ADDRESS_RANGE,
-			4,
-			0,
-			ADDIDATA_NO_EEPROM,
-			NULL,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			16,
-			16,
-			0xffff,
-			0,
-			NULL,
-			0,
-			1,
-			0,
-			0,
-			0,
-			v_APCI1500_Interrupt,
-			i_APCI1500_Reset,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI1500_ConfigDigitalInputEvent,
-			i_APCI1500_Initialisation,
-			i_APCI1500_StartStopInputEvent,
-			i_APCI1500_ReadMoreDigitalInput,
-			i_APCI1500_ConfigDigitalOutputErrorInterrupt,
-			i_APCI1500_WriteDigitalOutput,
-			i_APCI1500_ConfigureInterrupt,
-			NULL,
-			i_APCI1500_ConfigCounterTimerWatchdog,
-			i_APCI1500_StartStopTriggerTimerCounterWatchdog,
-			i_APCI1500_ReadInterruptMask,
-			i_APCI1500_ReadCounterTimerWatchdog,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci1500",
+		.i_VendorId		= APCI1500_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x80fc,
+		.i_IorangeBase0		= 128,
+		.i_IorangeBase1		= APCI1500_ADDRESS_RANGE,
+		.i_IorangeBase2		= 4,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.i_NbrDiChannel		= 16,
+		.i_NbrDoChannel		= 16,
+		.i_DoMaxdata		= 0xffff,
+		.i_Timer		= 1,
+		.interrupt		= v_APCI1500_Interrupt,
+		.reset			= i_APCI1500_Reset,
+		.di_config		= i_APCI1500_ConfigDigitalInputEvent,
+		.di_read		= i_APCI1500_Initialisation,
+		.di_write		= i_APCI1500_StartStopInputEvent,
+		.di_bits		= i_APCI1500_ReadMoreDigitalInput,
+		.do_config		= i_APCI1500_ConfigDigitalOutputErrorInterrupt,
+		.do_write		= i_APCI1500_WriteDigitalOutput,
+		.do_bits		= i_APCI1500_ConfigureInterrupt,
+		.timer_config		= i_APCI1500_ConfigCounterTimerWatchdog,
+		.timer_write		= i_APCI1500_StartStopTriggerTimerCounterWatchdog,
+		.timer_read		= i_APCI1500_ReadInterruptMask,
+		.timer_bits		= i_APCI1500_ReadCounterTimerWatchdog,
+	},
 #endif
 #ifdef CONFIG_APCI_3001
-	{"apci3001",
-			APCI3120_BOARD_VENDOR_ID,
-			0x828D,
-			AMCC_OP_REG_SIZE,
-			APCI3120_ADDRESS_RANGE,
-			8,
-			0,
-			ADDIDATA_NO_EEPROM,
-			NULL,
-			16,
-			8,
-			16,
-			0,
-			0xfff,
-			0,
-			&range_apci3120_ai,
-			NULL,
-			4,
-			4,
-			0x0f,
-			0,
-			NULL,
-			1,
-			1,
-			1,
-			10000,
-			100000,
-			v_APCI3120_Interrupt,
-			i_APCI3120_Reset,
-			i_APCI3120_InsnConfigAnalogInput,
-			i_APCI3120_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			i_APCI3120_CommandTestAnalogInput,
-			i_APCI3120_CommandAnalogInput,
-			i_APCI3120_StopCyclicAcquisition,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3120_InsnReadDigitalInput,
-			NULL,
-			i_APCI3120_InsnBitsDigitalInput,
-			i_APCI3120_InsnConfigDigitalOutput,
-			i_APCI3120_InsnWriteDigitalOutput,
-			i_APCI3120_InsnBitsDigitalOutput,
-			NULL,
-			i_APCI3120_InsnConfigTimer,
-			i_APCI3120_InsnWriteTimer,
-			i_APCI3120_InsnReadTimer,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci3001",
+		.i_VendorId		= APCI3120_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x828D,
+		.i_IorangeBase0		= AMCC_OP_REG_SIZE,
+		.i_IorangeBase1		= APCI3120_ADDRESS_RANGE,
+		.i_IorangeBase2		= 8,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_AiMaxdata		= 0xfff,
+		.pr_AiRangelist		= &range_apci3120_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 0x0f,
+		.i_Dma			= 1,
+		.i_Timer		= 1,
+		.b_AvailableConvertUnit	= 1,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.ui_MinDelaytimeNs	= 100000,
+		.interrupt		= v_APCI3120_Interrupt,
+		.reset			= i_APCI3120_Reset,
+		.ai_config		= i_APCI3120_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3120_InsnReadAnalogInput,
+		.ai_cmdtest		= i_APCI3120_CommandTestAnalogInput,
+		.ai_cmd			= i_APCI3120_CommandAnalogInput,
+		.ai_cancel		= i_APCI3120_StopCyclicAcquisition,
+		.di_read		= i_APCI3120_InsnReadDigitalInput,
+		.di_bits		= i_APCI3120_InsnBitsDigitalInput,
+		.do_config		= i_APCI3120_InsnConfigDigitalOutput,
+		.do_write		= i_APCI3120_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3120_InsnBitsDigitalOutput,
+		.timer_config		= i_APCI3120_InsnConfigTimer,
+		.timer_write		= i_APCI3120_InsnWriteTimer,
+		.timer_read		= i_APCI3120_InsnReadTimer,
+	},
 #endif
 #ifdef CONFIG_APCI_3501
-	{"apci3501",
-			APCI3501_BOARD_VENDOR_ID,
-			0x3001,
-			64,
-			APCI3501_ADDRESS_RANGE,
-			0,
-			0,
-			ADDIDATA_EEPROM,
-			ADDIDATA_S5933,
-			0,
-			0,
-			0,
-			8,
-			0,
-			16383,
-			NULL,
-			&range_apci3501_ao,
-			2,
-			2,
-			0x3,
-			0,
-			NULL,
-			0,
-			1,
-			0,
-			0,
-			0,
-			v_APCI3501_Interrupt,
-			i_APCI3501_Reset,
-			NULL, NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3501_ConfigAnalogOutput,
-			i_APCI3501_WriteAnalogOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3501_ReadDigitalInput,
-			i_APCI3501_ConfigDigitalOutput,
-			i_APCI3501_WriteDigitalOutput,
-			i_APCI3501_ReadDigitalOutput,
-			NULL,
-			i_APCI3501_ConfigTimerCounterWatchdog,
-			i_APCI3501_StartStopWriteTimerCounterWatchdog,
-			i_APCI3501_ReadTimerCounterWatchdog,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci3501",
+		.i_VendorId		= APCI3501_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x3001,
+		.i_IorangeBase0		= 64,
+		.i_IorangeBase1		= APCI3501_ADDRESS_RANGE,
+		.i_PCIEeprom		= ADDIDATA_EEPROM,
+		.pc_EepromChip		= ADDIDATA_S5933,
+		.i_AoMaxdata		= 16383,
+		.pr_AoRangelist		= &range_apci3501_ao,
+		.i_NbrDiChannel		= 2,
+		.i_NbrDoChannel		= 2,
+		.i_DoMaxdata		= 0x3,
+		.i_Timer		= 1,
+		.interrupt		= v_APCI3501_Interrupt,
+		.reset			= i_APCI3501_Reset,
+		.ao_config		= i_APCI3501_ConfigAnalogOutput,
+		.ao_write		= i_APCI3501_WriteAnalogOutput,
+		.di_bits		= i_APCI3501_ReadDigitalInput,
+		.do_config		= i_APCI3501_ConfigDigitalOutput,
+		.do_write		= i_APCI3501_WriteDigitalOutput,
+		.do_bits		= i_APCI3501_ReadDigitalOutput,
+		.timer_config		= i_APCI3501_ConfigTimerCounterWatchdog,
+		.timer_write		= i_APCI3501_StartStopWriteTimerCounterWatchdog,
+		.timer_read		= i_APCI3501_ReadTimerCounterWatchdog,
+	},
 #endif
 #ifdef CONFIG_APCI_035
-	{"apci035",
-			APCI035_BOARD_VENDOR_ID,
-			0x0300,
-			127,
-			APCI035_ADDRESS_RANGE,
-			0,
-			0,
-			1,
-			ADDIDATA_S5920,
-			16,
-			8,
-			16,
-			0,
-			0xff,
-			0,
-			&range_apci035_ai,
-			NULL,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			0,
-			1,
-			0,
-			10000,
-			100000,
-			v_APCI035_Interrupt,
-			i_APCI035_Reset,
-			i_APCI035_ConfigAnalogInput,
-			i_APCI035_ReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI035_ConfigTimerWatchdog,
-			i_APCI035_StartStopWriteTimerWatchdog,
-			i_APCI035_ReadTimerWatchdog,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci035",
+		.i_VendorId		= APCI035_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x0300,
+		.i_IorangeBase0		= 127,
+		.i_IorangeBase1		= APCI035_ADDRESS_RANGE,
+		.i_PCIEeprom		= 1,
+		.pc_EepromChip		= ADDIDATA_S5920,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_AiMaxdata		= 0xff,
+		.pr_AiRangelist		= &range_apci035_ai,
+		.i_Timer		= 1,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.ui_MinDelaytimeNs	= 100000,
+		.interrupt		= v_APCI035_Interrupt,
+		.reset			= i_APCI035_Reset,
+		.ai_config		= i_APCI035_ConfigAnalogInput,
+		.ai_read		= i_APCI035_ReadAnalogInput,
+		.timer_config		= i_APCI035_ConfigTimerWatchdog,
+		.timer_write		= i_APCI035_StartStopWriteTimerWatchdog,
+		.timer_read		= i_APCI035_ReadTimerWatchdog,
+	},
 #endif
 #ifdef CONFIG_APCI_3200
-	{"apci3200",
-			APCI3200_BOARD_VENDOR_ID,
-			0x3000,
-			128,
-			256,
-			4,
-			4,
-			ADDIDATA_EEPROM,
-			ADDIDATA_S5920,
-			16,
-			8,
-			16,
-			0,
-			0x3ffff,
-			0,
-			&range_apci3200_ai,
-			NULL,
-			4,
-			4,
-			0,
-			0,
-			NULL,
-			0,
-			0,
-			0,
-			10000,
-			100000,
-			v_APCI3200_Interrupt,
-			i_APCI3200_Reset,
-			i_APCI3200_ConfigAnalogInput,
-			i_APCI3200_ReadAnalogInput,
-			i_APCI3200_InsnWriteReleaseAnalogInput,
-			i_APCI3200_InsnBits_AnalogInput_Test,
-			i_APCI3200_CommandTestAnalogInput,
-			i_APCI3200_CommandAnalogInput,
-			i_APCI3200_StopCyclicAcquisition,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3200_ReadDigitalInput,
-			i_APCI3200_ConfigDigitalOutput,
-			i_APCI3200_WriteDigitalOutput,
-			i_APCI3200_ReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci3200",
+		.i_VendorId		= APCI3200_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x3000,
+		.i_IorangeBase0		= 128,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 4,
+		.i_IorangeBase3		= 4,
+		.i_PCIEeprom		= ADDIDATA_EEPROM,
+		.pc_EepromChip		= ADDIDATA_S5920,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_AiMaxdata		= 0x3ffff,
+		.pr_AiRangelist		= &range_apci3200_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.ui_MinDelaytimeNs	= 100000,
+		.interrupt		= v_APCI3200_Interrupt,
+		.reset			= i_APCI3200_Reset,
+		.ai_config		= i_APCI3200_ConfigAnalogInput,
+		.ai_read		= i_APCI3200_ReadAnalogInput,
+		.ai_write		= i_APCI3200_InsnWriteReleaseAnalogInput,
+		.ai_bits		= i_APCI3200_InsnBits_AnalogInput_Test,
+		.ai_cmdtest		= i_APCI3200_CommandTestAnalogInput,
+		.ai_cmd			= i_APCI3200_CommandAnalogInput,
+		.ai_cancel		= i_APCI3200_StopCyclicAcquisition,
+		.di_bits		= i_APCI3200_ReadDigitalInput,
+		.do_config		= i_APCI3200_ConfigDigitalOutput,
+		.do_write		= i_APCI3200_WriteDigitalOutput,
+		.do_bits		= i_APCI3200_ReadDigitalOutput,
+	},
 #endif
 #ifdef CONFIG_APCI_3300
 	/* Begin JK	.20.10.2004 = APCI-3300 integration */
-	{"apci3300",
-			APCI3200_BOARD_VENDOR_ID,
-			0x3007,
-			128,
-			256,
-			4,
-			4,
-			ADDIDATA_EEPROM,
-			ADDIDATA_S5920,
-			0,
-			8,
-			8,
-			0,
-			0x3ffff,
-			0,
-			&range_apci3300_ai,
-			NULL,
-			4,
-			4,
-			0,
-			0,
-			NULL,
-			0,
-			0,
-			0,
-			10000,
-			100000,
-			v_APCI3200_Interrupt,
-			i_APCI3200_Reset,
-			i_APCI3200_ConfigAnalogInput,
-			i_APCI3200_ReadAnalogInput,
-			i_APCI3200_InsnWriteReleaseAnalogInput,
-			i_APCI3200_InsnBits_AnalogInput_Test,
-			i_APCI3200_CommandTestAnalogInput,
-			i_APCI3200_CommandAnalogInput,
-			i_APCI3200_StopCyclicAcquisition,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3200_ReadDigitalInput,
-			i_APCI3200_ConfigDigitalOutput,
-			i_APCI3200_WriteDigitalOutput,
-			i_APCI3200_ReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci3300",
+		.i_VendorId		= APCI3200_BOARD_VENDOR_ID,
+		.i_DeviceId		= 0x3007,
+		.i_IorangeBase0		= 128,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 4,
+		.i_IorangeBase3		= 4,
+		.i_PCIEeprom		= ADDIDATA_EEPROM,
+		.pc_EepromChip		= ADDIDATA_S5920,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 8,
+		.i_AiMaxdata		= 0x3ffff,
+		.pr_AiRangelist		= &range_apci3300_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.ui_MinDelaytimeNs	= 100000,
+		.interrupt		= v_APCI3200_Interrupt,
+		.reset			= i_APCI3200_Reset,
+		.ai_config		= i_APCI3200_ConfigAnalogInput,
+		.ai_read		= i_APCI3200_ReadAnalogInput,
+		.ai_write		= i_APCI3200_InsnWriteReleaseAnalogInput,
+		.ai_bits		= i_APCI3200_InsnBits_AnalogInput_Test,
+		.ai_cmdtest		= i_APCI3200_CommandTestAnalogInput,
+		.ai_cmd			= i_APCI3200_CommandAnalogInput,
+		.ai_cancel		= i_APCI3200_StopCyclicAcquisition,
+		.di_bits		= i_APCI3200_ReadDigitalInput,
+		.do_config		= i_APCI3200_ConfigDigitalOutput,
+		.do_write		= i_APCI3200_WriteDigitalOutput,
+		.do_bits		= i_APCI3200_ReadDigitalOutput,
+	},
 #endif
 #ifdef CONFIG_APCI_1710
-	{"apci1710", APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID,
-			128,
-			8,
-			256,
-			0,
-			ADDIDATA_NO_EEPROM,
-			NULL,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			0,
-			0,
-			0,
-			0,
-			0,
-			v_APCI1710_Interrupt,
-			i_APCI1710_Reset,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
+	{
+		.pc_DriverName		= "apci1710",
+		.i_VendorId		= APCI1710_BOARD_VENDOR_ID,
+		.i_DeviceId		= APCI1710_BOARD_DEVICE_ID,
+		.i_IorangeBase0		= 128,
+		.i_IorangeBase1		= 8,
+		.i_IorangeBase2		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.interrupt		= v_APCI1710_Interrupt,
+		.reset			= i_APCI1710_Reset,
+	},
 #endif
 #ifdef CONFIG_APCI_16XX
-	{"apci1648",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x1009,
-			128,
-			0,
-			0,
-			0,
-			ADDIDATA_NO_EEPROM,
-			NULL,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			0,
-			0,
-			0,
-			48,
-			&range_apci16xx_ttl,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			i_APCI16XX_Reset,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI16XX_InsnConfigInitTTLIO,
-			i_APCI16XX_InsnBitsReadTTLIO,
-			i_APCI16XX_InsnReadTTLIOAllPortValue,
-		i_APCI16XX_InsnBitsWriteTTLIO},
-
-	{"apci1696",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x100A,
-			128,
-			0,
-			0,
-			0,
-			ADDIDATA_NO_EEPROM,
-			NULL,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			NULL,
-			0,
-			0,
-			0,
-			96,
-			&range_apci16xx_ttl,
-			0,
-			0,
-			0,
-			0,
-			0,
-			NULL,
-			i_APCI16XX_Reset,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI16XX_InsnConfigInitTTLIO,
-			i_APCI16XX_InsnBitsReadTTLIO,
-			i_APCI16XX_InsnReadTTLIOAllPortValue,
-		i_APCI16XX_InsnBitsWriteTTLIO},
+	{
+		.pc_DriverName		= "apci1648",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x1009,
+		.i_IorangeBase0		= 128,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.i_NbrTTLChannel	= 48,
+		.pr_TTLRangelist	= &range_apci16xx_ttl,
+		.reset			= i_APCI16XX_Reset,
+		.ttl_config		= i_APCI16XX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI16XX_InsnBitsReadTTLIO,
+		.ttl_read		= i_APCI16XX_InsnReadTTLIOAllPortValue,
+		.ttl_write		= i_APCI16XX_InsnBitsWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci1696",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x100A,
+		.i_IorangeBase0		= 128,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.i_NbrTTLChannel	= 96,
+		.pr_TTLRangelist	= &range_apci16xx_ttl,
+		.reset			= i_APCI16XX_Reset,
+		.ttl_config		= i_APCI16XX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI16XX_InsnBitsReadTTLIO,
+		.ttl_read		= i_APCI16XX_InsnReadTTLIOAllPortValue,
+		.ttl_write		= i_APCI16XX_InsnBitsWriteTTLIO,
+	},
 #endif
 #ifdef CONFIG_APCI_3XXX
-	{"apci3000-16",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3010,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			16,
-			8,
-			16,
-			0,
-			4095,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3000-8",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x300F,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			8,
-			4,
-			8,
-			0,
-			4095,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3000-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x300E,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			4,
-			2,
-			4,
-			0,
-			4095,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3006-16",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3013,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			16,
-			8,
-			16,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3006-8",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3014,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			8,
-			4,
-			8,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3006-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3015,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			4,
-			2,
-			4,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3010-16",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3016,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			16,
-			8,
-			16,
-			0,
-			4095,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3010-8",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3017,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			8,
-			4,
-			8,
-			0,
-			4095,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3010-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3018,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			4,
-			2,
-			4,
-			0,
-			4095,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3016-16",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3019,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			16,
-			8,
-			16,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3016-8",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x301A,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			8,
-			4,
-			8,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3016-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x301B,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			4,
-			2,
-			4,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3100-16-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x301C,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			16,
-			8,
-			16,
-			4,
-			4095,
-			4095,
-			&range_apci3XXX_ai,
-			&range_apci3XXX_ao,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3100-8-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x301D,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			8,
-			4,
-			8,
-			4,
-			4095,
-			4095,
-			&range_apci3XXX_ai,
-			&range_apci3XXX_ao,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3106-16-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x301E,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			16,
-			8,
-			16,
-			4,
-			65535,
-			4095,
-			&range_apci3XXX_ai,
-			&range_apci3XXX_ao,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3106-8-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x301F,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			8,
-			4,
-			8,
-			4,
-			65535,
-			4095,
-			&range_apci3XXX_ai,
-			&range_apci3XXX_ao,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			10000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3110-16-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3020,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			16,
-			8,
-			16,
-			4,
-			4095,
-			4095,
-			&range_apci3XXX_ai,
-			&range_apci3XXX_ao,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3110-8-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3021,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			8,
-			4,
-			8,
-			4,
-			4095,
-			4095,
-			&range_apci3XXX_ai,
-			&range_apci3XXX_ao,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3116-16-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3022,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			16,
-			8,
-			16,
-			4,
-			65535,
-			4095,
-			&range_apci3XXX_ai,
-			&range_apci3XXX_ao,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3116-8-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3023,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			8,
-			4,
-			8,
-			4,
-			65535,
-			4095,
-			&range_apci3XXX_ai,
-			&range_apci3XXX_ao,
-			4,
-			4,
-			1,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
-
-	{"apci3003",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x300B,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			0,
-			4,
-			4,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			0,
-			NULL,
-			0,
-			0,
-			7,
-			2500,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
-
-	{"apci3002-16",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3002,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			0,
-			16,
-			16,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			0,
-			NULL,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
-
-	{"apci3002-8",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3003,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			0,
-			8,
-			8,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			0,
-			NULL,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
-
-	{"apci3002-4",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3004,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			0,
-			4,
-			4,
-			0,
-			65535,
-			0,
-			&range_apci3XXX_ai,
-			NULL,
-			4,
-			4,
-			1,
-			0,
-			NULL,
-			0,
-			0,
-			6,
-			5000,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			i_APCI3XXX_InsnConfigAnalogInput,
-			i_APCI3XXX_InsnReadAnalogInput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnReadDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnBitsDigitalInput,
-			NULL,
-			i_APCI3XXX_InsnWriteDigitalOutput,
-			i_APCI3XXX_InsnBitsDigitalOutput,
-			i_APCI3XXX_InsnReadDigitalOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-		NULL},
-
-	{"apci3500",
-			PCI_VENDOR_ID_ADDIDATA,
-			0x3024,
-			256,
-			256,
-			256,
-			256,
-			ADDIDATA_NO_EEPROM,
-			ADDIDATA_9054,
-			0,
-			0,
-			0,
-			4,
-			0,
-			4095,
-			NULL,
-			&range_apci3XXX_ao,
-			0,
-			0,
-			0,
-			24,
-			&range_apci3XXX_ttl,
-			0,
-			0,
-			0,
-			0,
-			0,
-			v_APCI3XXX_Interrupt,
-			i_APCI3XXX_Reset,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnWriteAnalogOutput,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			i_APCI3XXX_InsnConfigInitTTLIO,
-			i_APCI3XXX_InsnBitsTTLIO,
-			i_APCI3XXX_InsnReadTTLIO,
-		i_APCI3XXX_InsnWriteTTLIO},
+	{
+		.pc_DriverName		= "apci3000-16",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3010,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_AiMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3000-8",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x300F,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 8,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 8,
+		.i_AiMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3000-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x300E,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 4,
+		.i_NbrAiChannelDiff	= 2,
+		.i_AiChannelList	= 4,
+		.i_AiMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3006-16",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3013,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3006-8",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3014,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 8,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 8,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3006-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3015,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 4,
+		.i_NbrAiChannelDiff	= 2,
+		.i_AiChannelList	= 4,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3010-16",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3016,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_AiMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3010-8",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3017,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 8,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 8,
+		.i_AiMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3010-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3018,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 4,
+		.i_NbrAiChannelDiff	= 2,
+		.i_AiChannelList	= 4,
+		.i_AiMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3016-16",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3019,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3016-8",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x301A,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 8,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 8,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3016-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x301B,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 4,
+		.i_NbrAiChannelDiff	= 2,
+		.i_AiChannelList	= 4,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3100-16-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x301C,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_NbrAoChannel		= 4,
+		.i_AiMaxdata		= 4095,
+		.i_AoMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.pr_AoRangelist		= &range_apci3XXX_ao,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3100-8-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x301D,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 8,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 8,
+		.i_NbrAoChannel		= 4,
+		.i_AiMaxdata		= 4095,
+		.i_AoMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.pr_AoRangelist		= &range_apci3XXX_ao,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3106-16-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x301E,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_NbrAoChannel		= 4,
+		.i_AiMaxdata		= 65535,
+		.i_AoMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.pr_AoRangelist		= &range_apci3XXX_ao,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3106-8-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x301F,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 8,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 8,
+		.i_NbrAoChannel		= 4,
+		.i_AiMaxdata		= 65535,
+		.i_AoMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.pr_AoRangelist		= &range_apci3XXX_ao,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 10000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3110-16-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3020,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_NbrAoChannel		= 4,
+		.i_AiMaxdata		= 4095,
+		.i_AoMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.pr_AoRangelist		= &range_apci3XXX_ao,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3110-8-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3021,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 8,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 8,
+		.i_NbrAoChannel		= 4,
+		.i_AiMaxdata		= 4095,
+		.i_AoMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.pr_AoRangelist		= &range_apci3XXX_ao,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3116-16-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3022,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 16,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 16,
+		.i_NbrAoChannel		= 4,
+		.i_AiMaxdata		= 65535,
+		.i_AoMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.pr_AoRangelist		= &range_apci3XXX_ao,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3116-8-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3023,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannel		= 8,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 8,
+		.i_NbrAoChannel		= 4,
+		.i_AiMaxdata		= 65535,
+		.i_AoMaxdata		= 4095,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.pr_AoRangelist		= &range_apci3XXX_ao,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	}, {
+		.pc_DriverName		= "apci3003",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x300B,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 4,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.b_AvailableConvertUnit	= 7,
+		.ui_MinAcquisitiontimeNs = 2500,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+	}, {
+		.pc_DriverName		= "apci3002-16",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3002,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannelDiff	= 16,
+		.i_AiChannelList	= 16,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+	}, {
+		.pc_DriverName		= "apci3002-8",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3003,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannelDiff	= 8,
+		.i_AiChannelList	= 8,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+	}, {
+		.pc_DriverName		= "apci3002-4",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3004,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAiChannelDiff	= 4,
+		.i_AiChannelList	= 4,
+		.i_AiMaxdata		= 65535,
+		.pr_AiRangelist		= &range_apci3XXX_ai,
+		.i_NbrDiChannel		= 4,
+		.i_NbrDoChannel		= 4,
+		.i_DoMaxdata		= 1,
+		.b_AvailableConvertUnit	= 6,
+		.ui_MinAcquisitiontimeNs = 5000,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
+		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
+		.di_read		= i_APCI3XXX_InsnReadDigitalInput,
+		.di_bits		= i_APCI3XXX_InsnBitsDigitalInput,
+		.do_write		= i_APCI3XXX_InsnWriteDigitalOutput,
+		.do_bits		= i_APCI3XXX_InsnBitsDigitalOutput,
+		.do_read		= i_APCI3XXX_InsnReadDigitalOutput,
+	}, {
+		.pc_DriverName		= "apci3500",
+		.i_VendorId		= PCI_VENDOR_ID_ADDIDATA,
+		.i_DeviceId		= 0x3024,
+		.i_IorangeBase0		= 256,
+		.i_IorangeBase1		= 256,
+		.i_IorangeBase2		= 256,
+		.i_IorangeBase3		= 256,
+		.i_PCIEeprom		= ADDIDATA_NO_EEPROM,
+		.pc_EepromChip		= ADDIDATA_9054,
+		.i_NbrAoChannel		= 4,
+		.i_AoMaxdata		= 4095,
+		.pr_AoRangelist		= &range_apci3XXX_ao,
+		.i_NbrTTLChannel	= 24,
+		.pr_TTLRangelist	= &range_apci3XXX_ttl,
+		.interrupt		= v_APCI3XXX_Interrupt,
+		.reset			= i_APCI3XXX_Reset,
+		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
+		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
+		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
+		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
+		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
+	},
 #endif
 };
 
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct addi_board))
-
 static struct comedi_driver driver_addi = {
 	.driver_name = ADDIDATA_DRIVER_NAME,
 	.module = THIS_MODULE,
 	.attach = i_ADDI_Attach,
 	.detach = i_ADDI_Detach,
-	.num_names = n_boardtypes,
+	.num_names = ARRAY_SIZE(boardtypes),
 	.board_name = &boardtypes[0].pc_DriverName,
 	.offset = sizeof(struct addi_board),
 };
@@ -2543,7 +1438,7 @@
 static int __devinit driver_addi_pci_probe(struct pci_dev *dev,
 					   const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_addi.driver_name);
+	return comedi_pci_auto_config(dev, &driver_addi);
 }
 
 static void __devexit driver_addi_pci_remove(struct pci_dev *dev)
@@ -2821,16 +1716,13 @@
 			/* Set the initialisation flag */
 			devpriv->b_AiInitialisation = 1;
 
-			s->insn_config =
-				this_board->i_hwdrv_InsnConfigAnalogInput;
-			s->insn_read = this_board->i_hwdrv_InsnReadAnalogInput;
-			s->insn_write =
-				this_board->i_hwdrv_InsnWriteAnalogInput;
-			s->insn_bits = this_board->i_hwdrv_InsnBitsAnalogInput;
-			s->do_cmdtest =
-				this_board->i_hwdrv_CommandTestAnalogInput;
-			s->do_cmd = this_board->i_hwdrv_CommandAnalogInput;
-			s->cancel = this_board->i_hwdrv_CancelAnalogInput;
+			s->insn_config = this_board->ai_config;
+			s->insn_read = this_board->ai_read;
+			s->insn_write = this_board->ai_write;
+			s->insn_bits = this_board->ai_bits;
+			s->do_cmdtest = this_board->ai_cmdtest;
+			s->do_cmd = this_board->ai_cmd;
+			s->cancel = this_board->ai_cancel;
 
 		} else {
 			s->type = COMEDI_SUBD_UNUSED;
@@ -2846,10 +1738,8 @@
 			s->len_chanlist =
 				devpriv->s_EeParameters.i_NbrAoChannel;
 			s->range_table = this_board->pr_AoRangelist;
-			s->insn_config =
-				this_board->i_hwdrv_InsnConfigAnalogOutput;
-			s->insn_write =
-				this_board->i_hwdrv_InsnWriteAnalogOutput;
+			s->insn_config = this_board->ao_config;
+			s->insn_write = this_board->ao_write;
 		} else {
 			s->type = COMEDI_SUBD_UNUSED;
 		}
@@ -2864,12 +1754,10 @@
 				devpriv->s_EeParameters.i_NbrDiChannel;
 			s->range_table = &range_digital;
 			s->io_bits = 0;	/* all bits input */
-			s->insn_config =
-				this_board->i_hwdrv_InsnConfigDigitalInput;
-			s->insn_read = this_board->i_hwdrv_InsnReadDigitalInput;
-			s->insn_write =
-				this_board->i_hwdrv_InsnWriteDigitalInput;
-			s->insn_bits = this_board->i_hwdrv_InsnBitsDigitalInput;
+			s->insn_config = this_board->di_config;
+			s->insn_read = this_board->di_read;
+			s->insn_write = this_board->di_write;
+			s->insn_bits = this_board->di_bits;
 		} else {
 			s->type = COMEDI_SUBD_UNUSED;
 		}
@@ -2886,13 +1774,11 @@
 			s->range_table = &range_digital;
 			s->io_bits = 0xf;	/* all bits output */
 
-			s->insn_config = this_board->i_hwdrv_InsnConfigDigitalOutput;	/* for digital output memory.. */
-			s->insn_write =
-				this_board->i_hwdrv_InsnWriteDigitalOutput;
-			s->insn_bits =
-				this_board->i_hwdrv_InsnBitsDigitalOutput;
-			s->insn_read =
-				this_board->i_hwdrv_InsnReadDigitalOutput;
+			/* insn_config - for digital output memory */
+			s->insn_config = this_board->do_config;
+			s->insn_write = this_board->do_write;
+			s->insn_bits = this_board->do_bits;
+			s->insn_read = this_board->do_read;
 		} else {
 			s->type = COMEDI_SUBD_UNUSED;
 		}
@@ -2907,10 +1793,10 @@
 			s->len_chanlist = 1;
 			s->range_table = &range_digital;
 
-			s->insn_write = this_board->i_hwdrv_InsnWriteTimer;
-			s->insn_read = this_board->i_hwdrv_InsnReadTimer;
-			s->insn_config = this_board->i_hwdrv_InsnConfigTimer;
-			s->insn_bits = this_board->i_hwdrv_InsnBitsTimer;
+			s->insn_write = this_board->timer_write;
+			s->insn_read = this_board->timer_read;
+			s->insn_config = this_board->timer_config;
+			s->insn_bits = this_board->timer_bits;
 		} else {
 			s->type = COMEDI_SUBD_UNUSED;
 		}
@@ -2926,10 +1812,10 @@
 			s->io_bits = 0;	/* all bits input */
 			s->len_chanlist = this_board->i_NbrTTLChannel;
 			s->range_table = &range_digital;
-			s->insn_config = this_board->i_hwdr_ConfigInitTTLIO;
-			s->insn_bits = this_board->i_hwdr_ReadTTLIOBits;
-			s->insn_read = this_board->i_hwdr_ReadTTLIOAllPortValue;
-			s->insn_write = this_board->i_hwdr_WriteTTLIOChlOnOff;
+			s->insn_config = this_board->ttl_config;
+			s->insn_bits = this_board->ttl_bits;
+			s->insn_read = this_board->ttl_read;
+			s->insn_write = this_board->ttl_write;
 		} else {
 			s->type = COMEDI_SUBD_UNUSED;
 		}
@@ -2953,50 +1839,22 @@
 	return 0;
 }
 
-/*
-+----------------------------------------------------------------------------+
-| Function name     : static int i_ADDI_Detach(struct comedi_device *dev)           |
-|                                        									 |
-|                                            						         |
-+----------------------------------------------------------------------------+
-| Task              : Deallocates resources of the addi_common driver        |
-|			  Free the DMA buffers, unregister irq.				     |
-|                     										                 |
-+----------------------------------------------------------------------------+
-| Input Parameters  : struct comedi_device *dev									 |
-|                     														 |
-|                                                 					         |
-+----------------------------------------------------------------------------+
-| Return Value      : 0             					                     |
-|                    													     |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_ADDI_Detach(struct comedi_device *dev)
+static void i_ADDI_Detach(struct comedi_device *dev)
 {
-
 	if (dev->private) {
-		if (devpriv->b_ValidDriver) {
+		if (devpriv->b_ValidDriver)
 			i_ADDI_Reset(dev);
-		}
-
-		if (dev->irq) {
+		if (dev->irq)
 			free_irq(dev->irq, dev);
-		}
-
-		if ((this_board->pc_EepromChip == NULL)
-			|| (strcmp(this_board->pc_EepromChip,
-					ADDIDATA_9054) != 0)) {
-			if (devpriv->allocated) {
+		if ((this_board->pc_EepromChip == NULL) ||
+		    (strcmp(this_board->pc_EepromChip, ADDIDATA_9054) != 0)) {
+			if (devpriv->allocated)
 				i_pci_card_free(devpriv->amcc);
-			}
-
 			if (devpriv->ul_DmaBufferVirtual[0]) {
 				free_pages((unsigned long)devpriv->
 					ul_DmaBufferVirtual[0],
 					devpriv->ui_DmaBufferPages[0]);
 			}
-
 			if (devpriv->ul_DmaBufferVirtual[1]) {
 				free_pages((unsigned long)devpriv->
 					ul_DmaBufferVirtual[1],
@@ -3004,20 +1862,14 @@
 			}
 		} else {
 			iounmap(devpriv->dw_AiBase);
-
-			if (devpriv->allocated) {
+			if (devpriv->allocated)
 				i_pci_card_free(devpriv->amcc);
-			}
 		}
-
 		if (pci_list_builded) {
-			/* v_pci_card_list_cleanup(PCI_VENDOR_ID_AMCC); */
 			v_pci_card_list_cleanup(this_board->i_VendorId);
 			pci_list_builded = 0;
 		}
 	}
-
-	return 0;
 }
 
 /*
@@ -3041,7 +1893,7 @@
 static int i_ADDI_Reset(struct comedi_device *dev)
 {
 
-	this_board->i_hwdrv_Reset(dev);
+	this_board->reset(dev);
 	return 0;
 }
 
@@ -3067,7 +1919,7 @@
 static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	this_board->v_hwdrv_Interrupt(irq, d);
+	this_board->interrupt(irq, d);
 	return IRQ_RETVAL(1);
 }
 
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h
index c6980b7..2c3f347 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h
@@ -94,111 +94,72 @@
 	unsigned int ui_MinDelaytimeNs;	/*  Minimum Delay in Nano secs */
 
 	/* interrupt and reset */
-	void (*v_hwdrv_Interrupt)(int irq, void *d);
-	int (*i_hwdrv_Reset)(struct comedi_device *dev);
+	void (*interrupt)(int irq, void *d);
+	int (*reset)(struct comedi_device *);
 
 	/* Subdevice functions */
 
 	/* ANALOG INPUT */
-	int (*i_hwdrv_InsnConfigAnalogInput)(struct comedi_device *dev,
-					     struct comedi_subdevice *s,
-					     struct comedi_insn *insn,
-					     unsigned int *data);
-	int (*i_hwdrv_InsnReadAnalogInput)(struct comedi_device *dev,
-					    struct comedi_subdevice *s,
-					    struct comedi_insn *insn,
-					    unsigned int *data);
-	int (*i_hwdrv_InsnWriteAnalogInput)(struct comedi_device *dev,
-					    struct comedi_subdevice *s,
-					    struct comedi_insn *insn,
-					    unsigned int *data);
-	int (*i_hwdrv_InsnBitsAnalogInput)(struct comedi_device *dev,
-					   struct comedi_subdevice *s,
-					   struct comedi_insn *insn,
-					   unsigned int *data);
-	int (*i_hwdrv_CommandTestAnalogInput)(struct comedi_device *dev,
-					      struct comedi_subdevice *s,
-					      struct comedi_cmd *cmd);
-	int (*i_hwdrv_CommandAnalogInput)(struct comedi_device *dev,
-					  struct comedi_subdevice *s);
-	int (*i_hwdrv_CancelAnalogInput)(struct comedi_device *dev,
-					 struct comedi_subdevice *s);
+	int (*ai_config)(struct comedi_device *, struct comedi_subdevice *,
+			 struct comedi_insn *, unsigned int *);
+	int (*ai_read)(struct comedi_device *, struct comedi_subdevice *,
+		       struct comedi_insn *, unsigned int *);
+	int (*ai_write)(struct comedi_device *, struct comedi_subdevice *,
+			struct comedi_insn *, unsigned int *);
+	int (*ai_bits)(struct comedi_device *, struct comedi_subdevice *,
+		       struct comedi_insn *, unsigned int *);
+	int (*ai_cmdtest)(struct comedi_device *, struct comedi_subdevice *,
+			  struct comedi_cmd *);
+	int (*ai_cmd)(struct comedi_device *, struct comedi_subdevice *);
+	int (*ai_cancel)(struct comedi_device *, struct comedi_subdevice *);
 
 	/* Analog Output */
-	int (*i_hwdrv_InsnConfigAnalogOutput)(struct comedi_device *dev,
-					      struct comedi_subdevice *s,
-					      struct comedi_insn *insn,
-					      unsigned int *data);
-	int (*i_hwdrv_InsnWriteAnalogOutput)(struct comedi_device *dev,
-					     struct comedi_subdevice *s,
-					     struct comedi_insn *insn,
-					     unsigned int *data);
-	int (*i_hwdrv_InsnBitsAnalogOutput)(struct comedi_device *dev,
-					    struct comedi_subdevice *s,
-					    struct comedi_insn *insn,
-					    unsigned int *data);
+	int (*ao_config)(struct comedi_device *, struct comedi_subdevice *,
+			 struct comedi_insn *, unsigned int *);
+	int (*ao_write)(struct comedi_device *, struct comedi_subdevice *,
+			struct comedi_insn *, unsigned int *);
+	int (*ao_bits)(struct comedi_device *, struct comedi_subdevice *,
+		       struct comedi_insn *, unsigned int *);
 
 	/* Digital Input */
-	int (*i_hwdrv_InsnConfigDigitalInput) (struct comedi_device *dev,
-					       struct comedi_subdevice *s,
-					       struct comedi_insn *insn,
-					       unsigned int *data);
-	int (*i_hwdrv_InsnReadDigitalInput) (struct comedi_device *dev,
-					     struct comedi_subdevice *s,
-					     struct comedi_insn *insn,
-					     unsigned int *data);
-	int (*i_hwdrv_InsnWriteDigitalInput) (struct comedi_device *dev,
-					      struct comedi_subdevice *s,
-					      struct comedi_insn *insn,
-					      unsigned int *data);
-	int (*i_hwdrv_InsnBitsDigitalInput) (struct comedi_device *dev,
-					     struct comedi_subdevice *s,
-					     struct comedi_insn *insn,
-					     unsigned int *data);
+	int (*di_config)(struct comedi_device *, struct comedi_subdevice *,
+			 struct comedi_insn *, unsigned int *);
+	int (*di_read)(struct comedi_device *, struct comedi_subdevice *,
+		       struct comedi_insn *, unsigned int *);
+	int (*di_write)(struct comedi_device *, struct comedi_subdevice *,
+			struct comedi_insn *, unsigned int *);
+	int (*di_bits)(struct comedi_device *, struct comedi_subdevice *,
+		       struct comedi_insn *, unsigned int *);
 
 	/* Digital Output */
-	int (*i_hwdrv_InsnConfigDigitalOutput)(struct comedi_device *dev,
-					       struct comedi_subdevice *s,
-					       struct comedi_insn *insn,
-					       unsigned int *data);
-	int (*i_hwdrv_InsnWriteDigitalOutput)(struct comedi_device *dev,
-					      struct comedi_subdevice *s,
-					      struct comedi_insn *insn,
-					      unsigned int *data);
-	int (*i_hwdrv_InsnBitsDigitalOutput)(struct comedi_device *dev,
-					     struct comedi_subdevice *s,
-					     struct comedi_insn *insn,
-					     unsigned int *data);
-	int (*i_hwdrv_InsnReadDigitalOutput)(struct comedi_device *dev,
-					     struct comedi_subdevice *s,
-					     struct comedi_insn *insn,
-					     unsigned int *data);
+	int (*do_config)(struct comedi_device *, struct comedi_subdevice *,
+			 struct comedi_insn *, unsigned int *);
+	int (*do_write)(struct comedi_device *, struct comedi_subdevice *,
+			struct comedi_insn *, unsigned int *);
+	int (*do_bits)(struct comedi_device *, struct comedi_subdevice *,
+		       struct comedi_insn *, unsigned int *);
+	int (*do_read)(struct comedi_device *, struct comedi_subdevice *,
+		       struct comedi_insn *, unsigned int *);
 
 	/* TIMER */
-	int (*i_hwdrv_InsnConfigTimer)(struct comedi_device *dev,
-				       struct comedi_subdevice *s,
-				       struct comedi_insn *insn, unsigned int *data);
-	int (*i_hwdrv_InsnWriteTimer)(struct comedi_device *dev,
-				      struct comedi_subdevice *s, struct comedi_insn *insn,
-				      unsigned int *data);
-	int (*i_hwdrv_InsnReadTimer)(struct comedi_device *dev, struct comedi_subdevice *s,
-				     struct comedi_insn *insn, unsigned int *data);
-	int (*i_hwdrv_InsnBitsTimer)(struct comedi_device *dev, struct comedi_subdevice *s,
-				     struct comedi_insn *insn, unsigned int *data);
+	int (*timer_config)(struct comedi_device *, struct comedi_subdevice *,
+			    struct comedi_insn *, unsigned int *);
+	int (*timer_write)(struct comedi_device *, struct comedi_subdevice *,
+			   struct comedi_insn *, unsigned int *);
+	int (*timer_read)(struct comedi_device *, struct comedi_subdevice *,
+			  struct comedi_insn *, unsigned int *);
+	int (*timer_bits)(struct comedi_device *, struct comedi_subdevice *,
+			  struct comedi_insn *, unsigned int *);
 
 	/* TTL IO */
-	int (*i_hwdr_ConfigInitTTLIO)(struct comedi_device *dev,
-				      struct comedi_subdevice *s, struct comedi_insn *insn,
-				      unsigned int *data);
-	int (*i_hwdr_ReadTTLIOBits)(struct comedi_device *dev, struct comedi_subdevice *s,
-				    struct comedi_insn *insn, unsigned int *data);
-	int (*i_hwdr_ReadTTLIOAllPortValue)(struct comedi_device *dev,
-					    struct comedi_subdevice *s,
-					    struct comedi_insn *insn,
-					    unsigned int *data);
-	int (*i_hwdr_WriteTTLIOChlOnOff)(struct comedi_device *dev,
-					 struct comedi_subdevice *s,
-					 struct comedi_insn *insn, unsigned int *data);
+	int (*ttl_config)(struct comedi_device *, struct comedi_subdevice *,
+			  struct comedi_insn *, unsigned int *);
+	int (*ttl_bits)(struct comedi_device *, struct comedi_subdevice *,
+			struct comedi_insn *, unsigned int *);
+	int (*ttl_read)(struct comedi_device *, struct comedi_subdevice *,
+			struct comedi_insn *, unsigned int *);
+	int (*ttl_write)(struct comedi_device *, struct comedi_subdevice *,
+			 struct comedi_insn *, unsigned int *);
 };
 
 /* MODULE INFO STRUCTURE */
@@ -455,7 +416,7 @@
 
 /* Function declarations */
 static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int i_ADDI_Detach(struct comedi_device *dev);
+static void i_ADDI_Detach(struct comedi_device *dev);
 static int i_ADDI_Reset(struct comedi_device *dev);
 
 static irqreturn_t v_ADDI_Interrupt(int irq, void *d);
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index e886ced..ffe390c 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -156,7 +156,7 @@
 	} else
 		us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000);	/*  nano to useconds */
 
-	/*  this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
+	/*  this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
 
 	/*  Clear software registers */
 	devpriv->b_TimerSelectMode = 0;
@@ -670,7 +670,7 @@
 			/*  mode 1 */
 
 			devpriv->ui_AiTimer0 = cmd->convert_arg;	/*  timer constant in nano seconds */
-			/* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */
+			/* return this_board->ai_cmd(1,dev,s); */
 			return i_APCI3120_CyclicAnalogInput(1, dev, s);
 		}
 
@@ -680,7 +680,7 @@
 		/*  mode 2 */
 		devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
 		devpriv->ui_AiTimer0 = cmd->convert_arg;	/*  variable changed timer2 to timer0 */
-		/* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */
+		/* return this_board->ai_cmd(2,dev,s); */
 		return i_APCI3120_CyclicAnalogInput(2, dev, s);
 	}
 	return -1;
@@ -1922,7 +1922,7 @@
 
 	ui_Timervalue2 = data[1] / 1000;	/*  convert nano seconds  to u seconds */
 
-	/* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */
+	/* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */
 	us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
 
 /*
@@ -2092,7 +2092,7 @@
 			ui_Timervalue2 = 0;
 	}
 
-	/* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */
+	/* this_board->timer_write(dev,data[0],ui_Timervalue2); */
 
 	switch (data[0]) {
 	case APCI3120_START:
@@ -2260,7 +2260,7 @@
 		comedi_error(dev, "\nread:timer2  not configured ");
 	}
 
-	/* this_board->i_hwdrv_InsnReadTimer(dev,data); */
+	/* this_board->timer_read(dev,data); */
 	if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
 
 		/* Read the LOW unsigned short of Timer 2 register */
@@ -2331,7 +2331,7 @@
 
 	ui_Chan = CR_CHAN(insn->chanspec);	/*  channel specified */
 
-	/* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
+	/* this_board->di_read(dev,ui_Chan,data); */
 	if (ui_Chan <= 3) {
 		ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
 
@@ -2379,7 +2379,7 @@
 	*****/
 
 	*data = (ui_TmpValue >> 8) & 0xf;
-	/* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */
+	/* this_board->di_bits(dev,data); */
 	return insn->n;
 }
 
@@ -2595,7 +2595,7 @@
 	ui_Range = CR_RANGE(insn->chanspec);
 	ui_Channel = CR_CHAN(insn->chanspec);
 
-	/* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
+	/* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */
 	if (ui_Range) {		/*  if 1 then unipolar */
 
 		if (data[0] != 0)
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 4fc9e85..de8c68a 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -54,8 +54,6 @@
 #include "../comedidev.h"
 #include "comedi_pci.h"
 
-#define PCI6208_DRIVER_NAME	"adl_pci6208"
-
 /* Board descriptions */
 struct pci6208_board {
 	const char *name;
@@ -85,17 +83,6 @@
 	 }
 };
 
-/* This is used by modprobe to translate PCI IDs to drivers.  Should
- * only be used for PCI and ISA-PnP devices */
-static DEFINE_PCI_DEVICE_TABLE(pci6208_pci_table) = {
-	/* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
-	/* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci6208_pci_table);
-
 /* Will be initialized in pci6208_find device(). */
 #define thisboard ((const struct pci6208_board *)dev->board_ptr)
 
@@ -107,157 +94,6 @@
 
 #define devpriv ((struct pci6208_private *)dev->private)
 
-static int pci6208_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int pci6208_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_pci6208 = {
-	.driver_name = PCI6208_DRIVER_NAME,
-	.module = THIS_MODULE,
-	.attach = pci6208_attach,
-	.detach = pci6208_detach,
-};
-
-static int __devinit driver_pci6208_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, driver_pci6208.driver_name);
-}
-
-static void __devexit driver_pci6208_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_pci6208_pci_driver = {
-	.id_table = pci6208_pci_table,
-	.probe = &driver_pci6208_pci_probe,
-	.remove = __devexit_p(&driver_pci6208_pci_remove)
-};
-
-static int __init driver_pci6208_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_pci6208);
-	if (retval < 0)
-		return retval;
-
-	driver_pci6208_pci_driver.name = (char *)driver_pci6208.driver_name;
-	return pci_register_driver(&driver_pci6208_pci_driver);
-}
-
-static void __exit driver_pci6208_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_pci6208_pci_driver);
-	comedi_driver_unregister(&driver_pci6208);
-}
-
-module_init(driver_pci6208_init_module);
-module_exit(driver_pci6208_cleanup_module);
-
-static int pci6208_find_device(struct comedi_device *dev, int bus, int slot);
-static int
-pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr,
-		  int dev_minor);
-
-/*read/write functions*/
-static int pci6208_ao_winsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int pci6208_ao_rinsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-/* static int pci6208_dio_insn_bits (struct comedi_device *dev,
- *					struct comedi_subdevice *s, */
-/* struct comedi_insn *insn,unsigned int *data); */
-/* static int pci6208_dio_insn_config(struct comedi_device *dev,
- *					struct comedi_subdevice *s, */
-/* struct comedi_insn *insn,unsigned int *data); */
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pci6208_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	int retval;
-	unsigned long io_base;
-
-	printk(KERN_INFO "comedi%d: pci6208: ", dev->minor);
-
-	retval = alloc_private(dev, sizeof(struct pci6208_private));
-	if (retval < 0)
-		return retval;
-
-	retval = pci6208_find_device(dev, it->options[0], it->options[1]);
-	if (retval < 0)
-		return retval;
-
-	retval = pci6208_pci_setup(devpriv->pci_dev, &io_base, dev->minor);
-	if (retval < 0)
-		return retval;
-
-	dev->iobase = io_base;
-	dev->board_name = thisboard->name;
-
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
-
-	s = dev->subdevices + 0;
-	/* analog output subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE;	/* anything else to add here?? */
-	s->n_chan = thisboard->ao_chans;
-	s->maxdata = 0xffff;	/* 16-bit DAC */
-	s->range_table = &range_bipolar10;	/* this needs to be checked. */
-	s->insn_write = pci6208_ao_winsn;
-	s->insn_read = pci6208_ao_rinsn;
-
-	/* s=dev->subdevices+1; */
-	/* digital i/o subdevice */
-	/* s->type=COMEDI_SUBD_DIO; */
-	/* s->subdev_flags=SDF_READABLE|SDF_WRITABLE; */
-	/* s->n_chan=16; */
-	/* s->maxdata=1; */
-	/* s->range_table=&range_digital; */
-	/* s->insn_bits = pci6208_dio_insn_bits; */
-	/* s->insn_config = pci6208_dio_insn_config; */
-
-	printk(KERN_INFO "attached\n");
-
-	return 1;
-}
-
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci6208_detach(struct comedi_device *dev)
-{
-	printk(KERN_INFO "comedi%d: pci6208: remove\n", dev->minor);
-
-	if (devpriv && devpriv->pci_dev) {
-		if (dev->iobase)
-			comedi_pci_disable(devpriv->pci_dev);
-		pci_dev_put(devpriv->pci_dev);
-	}
-
-	return 0;
-}
-
 static int pci6208_ao_winsn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
@@ -410,7 +246,7 @@
 	unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
 
 	/*  Enable PCI device and request regions */
-	if (comedi_pci_enable(pci_dev, PCI6208_DRIVER_NAME) < 0) {
+	if (comedi_pci_enable(pci_dev, "adl_pci6208") < 0) {
 		printk(KERN_ERR "comedi%d: Failed to enable PCI device "
 			"and request regions\n",
 			dev_minor);
@@ -442,6 +278,103 @@
 	return 0;
 }
 
+static int pci6208_attach(struct comedi_device *dev,
+			  struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	int retval;
+	unsigned long io_base;
+
+	printk(KERN_INFO "comedi%d: pci6208: ", dev->minor);
+
+	retval = alloc_private(dev, sizeof(struct pci6208_private));
+	if (retval < 0)
+		return retval;
+
+	retval = pci6208_find_device(dev, it->options[0], it->options[1]);
+	if (retval < 0)
+		return retval;
+
+	retval = pci6208_pci_setup(devpriv->pci_dev, &io_base, dev->minor);
+	if (retval < 0)
+		return retval;
+
+	dev->iobase = io_base;
+	dev->board_name = thisboard->name;
+
+	if (alloc_subdevices(dev, 2) < 0)
+		return -ENOMEM;
+
+	s = dev->subdevices + 0;
+	/* analog output subdevice */
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITABLE;	/* anything else to add here?? */
+	s->n_chan = thisboard->ao_chans;
+	s->maxdata = 0xffff;	/* 16-bit DAC */
+	s->range_table = &range_bipolar10;	/* this needs to be checked. */
+	s->insn_write = pci6208_ao_winsn;
+	s->insn_read = pci6208_ao_rinsn;
+
+	/* s=dev->subdevices+1; */
+	/* digital i/o subdevice */
+	/* s->type=COMEDI_SUBD_DIO; */
+	/* s->subdev_flags=SDF_READABLE|SDF_WRITABLE; */
+	/* s->n_chan=16; */
+	/* s->maxdata=1; */
+	/* s->range_table=&range_digital; */
+	/* s->insn_bits = pci6208_dio_insn_bits; */
+	/* s->insn_config = pci6208_dio_insn_config; */
+
+	printk(KERN_INFO "attached\n");
+
+	return 1;
+}
+
+static void pci6208_detach(struct comedi_device *dev)
+{
+	if (devpriv && devpriv->pci_dev) {
+		if (dev->iobase)
+			comedi_pci_disable(devpriv->pci_dev);
+		pci_dev_put(devpriv->pci_dev);
+	}
+}
+
+static struct comedi_driver adl_pci6208_driver = {
+	.driver_name	= "adl_pci6208",
+	.module		= THIS_MODULE,
+	.attach		= pci6208_attach,
+	.detach		= pci6208_detach,
+};
+
+static int __devinit adl_pci6208_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &adl_pci6208_driver);
+}
+
+static void __devexit adl_pci6208_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+/* This is used by modprobe to translate PCI IDs to drivers.  Should
+ * only be used for PCI and ISA-PnP devices */
+static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = {
+	/* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
+	/* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table);
+
+static struct pci_driver adl_pci6208_pci_driver = {
+	.name		= "adl_pci6208",
+	.id_table	= adl_pci6208_pci_table,
+	.probe		= adl_pci6208_pci_probe,
+	.remove		= __devexit_p(adl_pci6208_pci_remove),
+};
+module_comedi_pci_driver(adl_pci6208_driver, adl_pci6208_pci_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c
index 20d5705..e8053bc 100644
--- a/drivers/staging/comedi/drivers/adl_pci7230.c
+++ b/drivers/staging/comedi/drivers/adl_pci7230.c
@@ -43,13 +43,6 @@
 
 #define PCI_DEVICE_ID_PCI7230 0x7230
 
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table);
-
 struct adl_pci7230_private {
 	int data;
 	struct pci_dev *pci_dev;
@@ -57,27 +50,36 @@
 
 #define devpriv ((struct adl_pci7230_private *)dev->private)
 
-static int adl_pci7230_attach(struct comedi_device *dev,
-	struct comedi_devconfig *it);
-static int adl_pci7230_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci7230 = {
-	.driver_name = "adl_pci7230",
-	.module = THIS_MODULE,
-	.attach = adl_pci7230_attach,
-	.detach = adl_pci7230_detach,
-};
+static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
+	struct comedi_subdevice *s,
+	struct comedi_insn *insn,
+	unsigned int *data)
+{
+	if (insn->n != 2)
+		return -EINVAL;
 
-/* Digital IO */
+	if (data[0]) {
+		s->state &= ~data[0];
+		s->state |= (data[0] & data[1]);
+
+		outl((s->state  << 16) & 0xffffffff, dev->iobase + PCI7230_DO);
+	}
+
+	return 2;
+}
 
 static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
 	struct comedi_subdevice *s,
 	struct comedi_insn *insn,
-	unsigned int *data);
+	unsigned int *data)
+{
+	if (insn->n != 2)
+		return -EINVAL;
 
-static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
-	struct comedi_subdevice *s,
-	struct comedi_insn *insn,
-	unsigned int *data);
+	data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff;
+
+	return 2;
+}
 
 static int adl_pci7230_attach(struct comedi_device *dev,
 	struct comedi_devconfig *it)
@@ -148,89 +150,46 @@
 	return 1;
 }
 
-static int adl_pci7230_detach(struct comedi_device *dev)
+static void adl_pci7230_detach(struct comedi_device *dev)
 {
-	printk(KERN_DEBUG "comedi%d: pci7230: remove\n", dev->minor);
-
 	if (devpriv && devpriv->pci_dev) {
 		if (dev->iobase)
 			comedi_pci_disable(devpriv->pci_dev);
 		pci_dev_put(devpriv->pci_dev);
 	}
-
-	return 0;
 }
 
-static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
-	struct comedi_subdevice *s,
-	struct comedi_insn *insn,
-	unsigned int *data)
+static struct comedi_driver adl_pci7230_driver = {
+	.driver_name	= "adl_pci7230",
+	.module		= THIS_MODULE,
+	.attach		= adl_pci7230_attach,
+	.detach		= adl_pci7230_detach,
+};
+
+static int __devinit adl_pci7230_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= (data[0] & data[1]);
-
-		outl((s->state  << 16) & 0xffffffff, dev->iobase + PCI7230_DO);
-	}
-
-	return 2;
+	return comedi_pci_auto_config(dev, &adl_pci7230_driver);
 }
 
-static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
-	struct comedi_subdevice *s,
-	struct comedi_insn *insn,
-	unsigned int *data)
-{
-	if (insn->n != 2)
-		return -EINVAL;
-
-	data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff;
-
-	return 2;
-}
-
-static int __devinit driver_adl_pci7230_pci_probe(struct pci_dev *dev,
-						  const struct pci_device_id
-						  *ent)
-{
-	return comedi_pci_auto_config(dev, driver_adl_pci7230.driver_name);
-}
-
-static void __devexit driver_adl_pci7230_pci_remove(struct pci_dev *dev)
+static void __devexit adl_pci7230_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_adl_pci7230_pci_driver = {
-	.id_table = adl_pci7230_pci_table,
-	.probe = &driver_adl_pci7230_pci_probe,
-	.remove = __devexit_p(&driver_adl_pci7230_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table);
 
-static int __init driver_adl_pci7230_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_adl_pci7230);
-	if (retval < 0)
-		return retval;
-
-	driver_adl_pci7230_pci_driver.name =
-	    (char *)driver_adl_pci7230.driver_name;
-	return pci_register_driver(&driver_adl_pci7230_pci_driver);
-}
-
-static void __exit driver_adl_pci7230_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_adl_pci7230_pci_driver);
-	comedi_driver_unregister(&driver_adl_pci7230);
-}
-
-module_init(driver_adl_pci7230_init_module);
-module_exit(driver_adl_pci7230_cleanup_module);
+static struct pci_driver adl_pci7230_pci_driver = {
+	.name		= "adl_pci7230",
+	.id_table	= adl_pci7230_pci_table,
+	.probe		= adl_pci7230_pci_probe,
+	.remove		= __devexit_p(adl_pci7230_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7230_driver, adl_pci7230_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c
index 9a232053..b4dae3b 100644
--- a/drivers/staging/comedi/drivers/adl_pci7296.c
+++ b/drivers/staging/comedi/drivers/adl_pci7296.c
@@ -48,13 +48,6 @@
 
 #define PCI_DEVICE_ID_PCI7296 0x7296
 
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table);
-
 struct adl_pci7296_private {
 	int data;
 	struct pci_dev *pci_dev;
@@ -63,16 +56,6 @@
 #define devpriv ((struct adl_pci7296_private *)dev->private)
 
 static int adl_pci7296_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it);
-static int adl_pci7296_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci7296 = {
-	.driver_name = "adl_pci7296",
-	.module = THIS_MODULE,
-	.attach = adl_pci7296_attach,
-	.detach = adl_pci7296_detach,
-};
-
-static int adl_pci7296_attach(struct comedi_device *dev,
 			      struct comedi_devconfig *it)
 {
 	struct pci_dev *pcidev = NULL;
@@ -151,66 +134,52 @@
 	return -EIO;
 }
 
-static int adl_pci7296_detach(struct comedi_device *dev)
+static void adl_pci7296_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor);
-
 	if (devpriv && devpriv->pci_dev) {
 		if (dev->iobase)
 			comedi_pci_disable(devpriv->pci_dev);
 		pci_dev_put(devpriv->pci_dev);
 	}
-	/*  detach four 8255 digital io subdevices */
 	if (dev->subdevices) {
 		subdev_8255_cleanup(dev, dev->subdevices + 0);
 		subdev_8255_cleanup(dev, dev->subdevices + 1);
 		subdev_8255_cleanup(dev, dev->subdevices + 2);
 		subdev_8255_cleanup(dev, dev->subdevices + 3);
-
 	}
-
-	return 0;
 }
 
-static int __devinit driver_adl_pci7296_pci_probe(struct pci_dev *dev,
-						  const struct pci_device_id
-						  *ent)
+static struct comedi_driver adl_pci7296_driver = {
+	.driver_name	= "adl_pci7296",
+	.module		= THIS_MODULE,
+	.attach		= adl_pci7296_attach,
+	.detach		= adl_pci7296_detach,
+};
+
+static int __devinit adl_pci7296_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_adl_pci7296.driver_name);
+	return comedi_pci_auto_config(dev, &adl_pci7296_driver);
 }
 
-static void __devexit driver_adl_pci7296_pci_remove(struct pci_dev *dev)
+static void __devexit adl_pci7296_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_adl_pci7296_pci_driver = {
-	.id_table = adl_pci7296_pci_table,
-	.probe = &driver_adl_pci7296_pci_probe,
-	.remove = __devexit_p(&driver_adl_pci7296_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table);
 
-static int __init driver_adl_pci7296_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_adl_pci7296);
-	if (retval < 0)
-		return retval;
-
-	driver_adl_pci7296_pci_driver.name =
-	    (char *)driver_adl_pci7296.driver_name;
-	return pci_register_driver(&driver_adl_pci7296_pci_driver);
-}
-
-static void __exit driver_adl_pci7296_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_adl_pci7296_pci_driver);
-	comedi_driver_unregister(&driver_adl_pci7296);
-}
-
-module_init(driver_adl_pci7296_init_module);
-module_exit(driver_adl_pci7296_cleanup_module);
+static struct pci_driver adl_pci7296_pci_driver = {
+	.name		= "adl_pci7296",
+	.id_table	= adl_pci7296_pci_table,
+	.probe		= adl_pci7296_pci_probe,
+	.remove		= __devexit_p(adl_pci7296_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7296_driver, adl_pci7296_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c
index 86ee219..9cbfb61 100644
--- a/drivers/staging/comedi/drivers/adl_pci7432.c
+++ b/drivers/staging/comedi/drivers/adl_pci7432.c
@@ -43,13 +43,6 @@
 
 #define PCI_DEVICE_ID_PCI7432 0x7432
 
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table);
-
 struct adl_pci7432_private {
 	int data;
 	struct pci_dev *pci_dev;
@@ -57,29 +50,44 @@
 
 #define devpriv ((struct adl_pci7432_private *)dev->private)
 
-static int adl_pci7432_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it);
-static int adl_pci7432_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci7432 = {
-	.driver_name = "adl_pci7432",
-	.module = THIS_MODULE,
-	.attach = adl_pci7432_attach,
-	.detach = adl_pci7432_detach,
-};
+static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    struct comedi_insn *insn,
+				    unsigned int *data)
+{
+	printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
+	printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
 
-/* Digital IO */
+	if (insn->n != 2)
+		return -EINVAL;
+
+	if (data[0]) {
+		s->state &= ~data[0];
+		s->state |= (data[0] & data[1]);
+
+		printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state,
+		       dev->iobase + PCI7432_DO);
+		outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
+	}
+	return 2;
+}
 
 static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
 				    struct comedi_subdevice *s,
 				    struct comedi_insn *insn,
-				    unsigned int *data);
+				    unsigned int *data)
+{
+	printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
+	printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
 
-static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
-				    struct comedi_subdevice *s,
-				    struct comedi_insn *insn,
-				    unsigned int *data);
+	if (insn->n != 2)
+		return -EINVAL;
 
-/*            */
+	data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
+	printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
+
+	return 2;
+}
 
 static int adl_pci7432_attach(struct comedi_device *dev,
 			      struct comedi_devconfig *it)
@@ -153,97 +161,46 @@
 	return -EIO;
 }
 
-static int adl_pci7432_detach(struct comedi_device *dev)
+static void adl_pci7432_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor);
-
 	if (devpriv && devpriv->pci_dev) {
 		if (dev->iobase)
 			comedi_pci_disable(devpriv->pci_dev);
 		pci_dev_put(devpriv->pci_dev);
 	}
-
-	return 0;
 }
 
-static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
-				    struct comedi_subdevice *s,
-				    struct comedi_insn *insn,
-				    unsigned int *data)
+static struct comedi_driver adl_pci7432_driver = {
+	.driver_name	= "adl_pci7432",
+	.module		= THIS_MODULE,
+	.attach		= adl_pci7432_attach,
+	.detach		= adl_pci7432_detach,
+};
+
+static int __devinit adl_pci7432_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
 {
-	printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
-	printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
-	if (insn->n != 2)
-		return -EINVAL;
-
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= (data[0] & data[1]);
-
-		printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state,
-		       dev->iobase + PCI7432_DO);
-		outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
-	}
-	return 2;
+	return comedi_pci_auto_config(dev, &adl_pci7432_driver);
 }
 
-static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
-				    struct comedi_subdevice *s,
-				    struct comedi_insn *insn,
-				    unsigned int *data)
-{
-	printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
-	printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
-	if (insn->n != 2)
-		return -EINVAL;
-
-	data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
-	printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
-
-	return 2;
-}
-
-static int __devinit driver_adl_pci7432_pci_probe(struct pci_dev *dev,
-						  const struct pci_device_id
-						  *ent)
-{
-	return comedi_pci_auto_config(dev, driver_adl_pci7432.driver_name);
-}
-
-static void __devexit driver_adl_pci7432_pci_remove(struct pci_dev *dev)
+static void __devexit adl_pci7432_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_adl_pci7432_pci_driver = {
-	.id_table = adl_pci7432_pci_table,
-	.probe = &driver_adl_pci7432_pci_probe,
-	.remove = __devexit_p(&driver_adl_pci7432_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table);
 
-static int __init driver_adl_pci7432_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_adl_pci7432);
-	if (retval < 0)
-		return retval;
-
-	driver_adl_pci7432_pci_driver.name =
-	    (char *)driver_adl_pci7432.driver_name;
-	return pci_register_driver(&driver_adl_pci7432_pci_driver);
-}
-
-static void __exit driver_adl_pci7432_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_adl_pci7432_pci_driver);
-	comedi_driver_unregister(&driver_adl_pci7432);
-}
-
-module_init(driver_adl_pci7432_init_module);
-module_exit(driver_adl_pci7432_cleanup_module);
+static struct pci_driver adl_pci7432_pci_driver = {
+	.name		= "adl_pci7432",
+	.id_table	= adl_pci7432_pci_table,
+	.probe		= adl_pci7432_pci_probe,
+	.remove		= __devexit_p(adl_pci7432_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7432_driver, adl_pci7432_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 3b83d65..409ef13a 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -56,13 +56,6 @@
 
 #define PCI_DEVICE_ID_PCI8164 0x8164
 
-static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
-
 struct adl_pci8164_private {
 	int data;
 	struct pci_dev *pci_dev;
@@ -70,159 +63,6 @@
 
 #define devpriv ((struct adl_pci8164_private *)dev->private)
 
-static int adl_pci8164_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it);
-static int adl_pci8164_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci8164 = {
-	.driver_name = "adl_pci8164",
-	.module = THIS_MODULE,
-	.attach = adl_pci8164_attach,
-	.detach = adl_pci8164_detach,
-};
-
-static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
-				      struct comedi_subdevice *s,
-				      struct comedi_insn *insn,
-				      unsigned int *data);
-
-static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
-				      struct comedi_subdevice *s,
-				      struct comedi_insn *insn,
-				      unsigned int *data);
-
-static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
-				      struct comedi_subdevice *s,
-				      struct comedi_insn *insn,
-				      unsigned int *data);
-
-static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
-				      struct comedi_subdevice *s,
-				      struct comedi_insn *insn,
-				      unsigned int *data);
-
-static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
-				      struct comedi_subdevice *s,
-				      struct comedi_insn *insn,
-				      unsigned int *data);
-
-static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
-				      struct comedi_subdevice *s,
-				      struct comedi_insn *insn,
-				      unsigned int *data);
-
-static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
-				       struct comedi_subdevice *s,
-				       struct comedi_insn *insn,
-				       unsigned int *data);
-
-static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
-				       struct comedi_subdevice *s,
-				       struct comedi_insn *insn,
-				       unsigned int *data);
-
-static int adl_pci8164_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev = NULL;
-	struct comedi_subdevice *s;
-	int bus, slot;
-
-	printk(KERN_INFO "comedi: attempt to attach...\n");
-	printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
-
-	dev->board_name = "pci8164";
-	bus = it->options[0];
-	slot = it->options[1];
-
-	if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0)
-		return -ENOMEM;
-
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
-
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
-		    pcidev->device == PCI_DEVICE_ID_PCI8164) {
-			if (bus || slot) {
-				/* requested particular bus/slot */
-				if (pcidev->bus->number != bus
-					|| PCI_SLOT(pcidev->devfn) != slot)
-					continue;
-			}
-			devpriv->pci_dev = pcidev;
-			if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
-				printk(KERN_ERR "comedi%d: Failed to enable "
-				"PCI device and request regions\n", dev->minor);
-				return -EIO;
-			}
-			dev->iobase = pci_resource_start(pcidev, 2);
-			printk(KERN_DEBUG "comedi: base addr %4lx\n",
-				   dev->iobase);
-
-			s = dev->subdevices + 0;
-			s->type = COMEDI_SUBD_PROC;
-			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-			s->n_chan = 4;
-			s->maxdata = 0xffff;
-			s->len_chanlist = 4;
-			/* s->range_table = &range_axis; */
-			s->insn_read = adl_pci8164_insn_read_msts;
-			s->insn_write = adl_pci8164_insn_write_cmd;
-
-			s = dev->subdevices + 1;
-			s->type = COMEDI_SUBD_PROC;
-			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-			s->n_chan = 4;
-			s->maxdata = 0xffff;
-			s->len_chanlist = 4;
-			/* s->range_table = &range_axis; */
-			s->insn_read = adl_pci8164_insn_read_ssts;
-			s->insn_write = adl_pci8164_insn_write_otp;
-
-			s = dev->subdevices + 2;
-			s->type = COMEDI_SUBD_PROC;
-			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-			s->n_chan = 4;
-			s->maxdata = 0xffff;
-			s->len_chanlist = 4;
-			/* s->range_table = &range_axis; */
-			s->insn_read = adl_pci8164_insn_read_buf0;
-			s->insn_write = adl_pci8164_insn_write_buf0;
-
-			s = dev->subdevices + 3;
-			s->type = COMEDI_SUBD_PROC;
-			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-			s->n_chan = 4;
-			s->maxdata = 0xffff;
-			s->len_chanlist = 4;
-			/* s->range_table = &range_axis; */
-			s->insn_read = adl_pci8164_insn_read_buf1;
-			s->insn_write = adl_pci8164_insn_write_buf1;
-
-			printk(KERN_INFO "comedi: attached\n");
-
-			return 1;
-		}
-	}
-
-	printk(KERN_ERR "comedi%d: no supported board found!"
-		   "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot);
-	return -EIO;
-}
-
-static int adl_pci8164_detach(struct comedi_device *dev)
-{
-	printk(KERN_INFO "comedi%d: pci8164: remove\n", dev->minor);
-
-	if (devpriv && devpriv->pci_dev) {
-		if (dev->iobase)
-			comedi_pci_disable(devpriv->pci_dev);
-		pci_dev_put(devpriv->pci_dev);
-	}
-
-	return 0;
-}
-
 /*
  all the read commands are the same except for the addition a constant
  * const to the data for inw()
@@ -384,45 +224,136 @@
 	return 2;
 }
 
-static int __devinit driver_adl_pci8164_pci_probe(struct pci_dev *dev,
-						  const struct pci_device_id
-						  *ent)
+static int adl_pci8164_attach(struct comedi_device *dev,
+			      struct comedi_devconfig *it)
 {
-	return comedi_pci_auto_config(dev, driver_adl_pci8164.driver_name);
+	struct pci_dev *pcidev = NULL;
+	struct comedi_subdevice *s;
+	int bus, slot;
+
+	printk(KERN_INFO "comedi: attempt to attach...\n");
+	printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
+
+	dev->board_name = "pci8164";
+	bus = it->options[0];
+	slot = it->options[1];
+
+	if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0)
+		return -ENOMEM;
+
+	if (alloc_subdevices(dev, 4) < 0)
+		return -ENOMEM;
+
+	for_each_pci_dev(pcidev) {
+		if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
+		    pcidev->device == PCI_DEVICE_ID_PCI8164) {
+			if (bus || slot) {
+				/* requested particular bus/slot */
+				if (pcidev->bus->number != bus
+					|| PCI_SLOT(pcidev->devfn) != slot)
+					continue;
+			}
+			devpriv->pci_dev = pcidev;
+			if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
+				printk(KERN_ERR "comedi%d: Failed to enable "
+				"PCI device and request regions\n", dev->minor);
+				return -EIO;
+			}
+			dev->iobase = pci_resource_start(pcidev, 2);
+			printk(KERN_DEBUG "comedi: base addr %4lx\n",
+				   dev->iobase);
+
+			s = dev->subdevices + 0;
+			s->type = COMEDI_SUBD_PROC;
+			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+			s->n_chan = 4;
+			s->maxdata = 0xffff;
+			s->len_chanlist = 4;
+			/* s->range_table = &range_axis; */
+			s->insn_read = adl_pci8164_insn_read_msts;
+			s->insn_write = adl_pci8164_insn_write_cmd;
+
+			s = dev->subdevices + 1;
+			s->type = COMEDI_SUBD_PROC;
+			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+			s->n_chan = 4;
+			s->maxdata = 0xffff;
+			s->len_chanlist = 4;
+			/* s->range_table = &range_axis; */
+			s->insn_read = adl_pci8164_insn_read_ssts;
+			s->insn_write = adl_pci8164_insn_write_otp;
+
+			s = dev->subdevices + 2;
+			s->type = COMEDI_SUBD_PROC;
+			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+			s->n_chan = 4;
+			s->maxdata = 0xffff;
+			s->len_chanlist = 4;
+			/* s->range_table = &range_axis; */
+			s->insn_read = adl_pci8164_insn_read_buf0;
+			s->insn_write = adl_pci8164_insn_write_buf0;
+
+			s = dev->subdevices + 3;
+			s->type = COMEDI_SUBD_PROC;
+			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+			s->n_chan = 4;
+			s->maxdata = 0xffff;
+			s->len_chanlist = 4;
+			/* s->range_table = &range_axis; */
+			s->insn_read = adl_pci8164_insn_read_buf1;
+			s->insn_write = adl_pci8164_insn_write_buf1;
+
+			printk(KERN_INFO "comedi: attached\n");
+
+			return 1;
+		}
+	}
+
+	printk(KERN_ERR "comedi%d: no supported board found!"
+		   "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot);
+	return -EIO;
 }
 
-static void __devexit driver_adl_pci8164_pci_remove(struct pci_dev *dev)
+static void adl_pci8164_detach(struct comedi_device *dev)
+{
+	if (devpriv && devpriv->pci_dev) {
+		if (dev->iobase)
+			comedi_pci_disable(devpriv->pci_dev);
+		pci_dev_put(devpriv->pci_dev);
+	}
+}
+
+static struct comedi_driver adl_pci8164_driver = {
+	.driver_name	= "adl_pci8164",
+	.module		= THIS_MODULE,
+	.attach		= adl_pci8164_attach,
+	.detach		= adl_pci8164_detach,
+};
+
+static int __devinit adl_pci8164_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &adl_pci8164_driver);
+}
+
+static void __devexit adl_pci8164_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_adl_pci8164_pci_driver = {
-	.id_table = adl_pci8164_pci_table,
-	.probe = &driver_adl_pci8164_pci_probe,
-	.remove = __devexit_p(&driver_adl_pci8164_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
+	{0}
 };
+MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
 
-static int __init driver_adl_pci8164_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_adl_pci8164);
-	if (retval < 0)
-		return retval;
-
-	driver_adl_pci8164_pci_driver.name =
-	    (char *)driver_adl_pci8164.driver_name;
-	return pci_register_driver(&driver_adl_pci8164_pci_driver);
-}
-
-static void __exit driver_adl_pci8164_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_adl_pci8164_pci_driver);
-	comedi_driver_unregister(&driver_adl_pci8164);
-}
-
-module_init(driver_adl_pci8164_init_module);
-module_exit(driver_adl_pci8164_cleanup_module);
+static struct pci_driver adl_pci8164_pci_driver = {
+	.name		= "adl_pci8164",
+	.id_table	= adl_pci8164_pci_table,
+	.probe		= adl_pci8164_pci_probe,
+	.remove		= __devexit_p(adl_pci8164_pci_remove),
+};
+module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index 2a9bd88a..ccfb1a5 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -289,16 +289,6 @@
 			PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \
 	} while (0)
 
-/*  Function prototypes */
-
-static int pci9111_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int pci9111_detach(struct comedi_device *dev);
-static void pci9111_ai_munge(struct comedi_device *dev,
-			     struct comedi_subdevice *s, void *data,
-			     unsigned int num_bytes,
-			     unsigned int start_chan_index);
-
 static const struct comedi_lrange pci9111_hr_ai_range = {
 	5,
 	{
@@ -310,14 +300,6 @@
 	 }
 };
 
-static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
-	/* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
-
 /*  */
 /*  Board specification structure */
 /*  */
@@ -354,51 +336,6 @@
 #define pci9111_board_nbr \
 	(sizeof(pci9111_boards)/sizeof(struct pci9111_board))
 
-static struct comedi_driver pci9111_driver = {
-	.driver_name = PCI9111_DRIVER_NAME,
-	.module = THIS_MODULE,
-	.attach = pci9111_attach,
-	.detach = pci9111_detach,
-};
-
-static int __devinit pci9111_driver_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, pci9111_driver.driver_name);
-}
-
-static void __devexit pci9111_driver_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver pci9111_driver_pci_driver = {
-	.id_table = pci9111_pci_table,
-	.probe = &pci9111_driver_pci_probe,
-	.remove = __devexit_p(&pci9111_driver_pci_remove)
-};
-
-static int __init pci9111_driver_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&pci9111_driver);
-	if (retval < 0)
-		return retval;
-
-	pci9111_driver_pci_driver.name = (char *)pci9111_driver.driver_name;
-	return pci_register_driver(&pci9111_driver_pci_driver);
-}
-
-static void __exit pci9111_driver_cleanup_module(void)
-{
-	pci_unregister_driver(&pci9111_driver_pci_driver);
-	comedi_driver_unregister(&pci9111_driver);
-}
-
-module_init(pci9111_driver_init_module);
-module_exit(pci9111_driver_cleanup_module);
-
 /*  Private data structure */
 
 struct pci9111_private_data {
@@ -1445,31 +1382,54 @@
 	return 0;
 }
 
-/*  Detach */
-
-static int pci9111_detach(struct comedi_device *dev)
+static void pci9111_detach(struct comedi_device *dev)
 {
-	/*  Reset device */
-
 	if (dev->private != NULL) {
 		if (dev_private->is_valid)
 			pci9111_reset(dev);
-
 	}
-	/*  Release previously allocated irq */
-
 	if (dev->irq != 0)
 		free_irq(dev->irq, dev);
-
 	if (dev_private != NULL && dev_private->pci_device != NULL) {
 		if (dev->iobase)
 			comedi_pci_disable(dev_private->pci_device);
 		pci_dev_put(dev_private->pci_device);
 	}
-
-	return 0;
 }
 
+static struct comedi_driver adl_pci9111_driver = {
+	.driver_name	= "adl_pci9111",
+	.module		= THIS_MODULE,
+	.attach		= pci9111_attach,
+	.detach		= pci9111_detach,
+};
+
+static int __devinit pci9111_pci_probe(struct pci_dev *dev,
+				       const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &adl_pci9111_driver);
+}
+
+static void __devexit pci9111_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
+	/* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
+
+static struct pci_driver adl_pci9111_pci_driver = {
+	.name		= "adl_pci9111",
+	.id_table	= pci9111_pci_table,
+	.probe		= pci9111_pci_probe,
+	.remove		= __devexit_p(pci9111_pci_remove),
+};
+module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index f17654e..7864586 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -221,10 +221,6 @@
 					 * of BIP/UNI ranges
 					 */
 
-static int pci9118_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int pci9118_detach(struct comedi_device *dev);
-
 struct boardtype {
 	const char *name;		/* board name */
 	int vendor_id;			/* PCI vendor a device ID of card */
@@ -252,81 +248,6 @@
 
 };
 
-static DEFINE_PCI_DEVICE_TABLE(pci9118_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci9118_pci_table);
-
-static const struct boardtype boardtypes[] = {
-	{"pci9118dg", PCI_VENDOR_ID_AMCC, 0x80d9,
-	 AMCC_OP_REG_SIZE, IORANGE_9118,
-	 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff,
-	 &range_pci9118dg_hr, &range_bipolar10,
-	 3000, 12, 512},
-	{"pci9118hg", PCI_VENDOR_ID_AMCC, 0x80d9,
-	 AMCC_OP_REG_SIZE, IORANGE_9118,
-	 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff,
-	 &range_pci9118hg, &range_bipolar10,
-	 3000, 12, 512},
-	{"pci9118hr", PCI_VENDOR_ID_AMCC, 0x80d9,
-	 AMCC_OP_REG_SIZE, IORANGE_9118,
-	 16, 8, 256, PCI9118_CHANLEN, 2, 0xffff, 0x0fff,
-	 &range_pci9118dg_hr, &range_bipolar10,
-	 10000, 40, 512},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
-
-static struct comedi_driver driver_pci9118 = {
-	.driver_name = "adl_pci9118",
-	.module = THIS_MODULE,
-	.attach = pci9118_attach,
-	.detach = pci9118_detach,
-	.num_names = n_boardtypes,
-	.board_name = &boardtypes[0].name,
-	.offset = sizeof(struct boardtype),
-};
-
-static int __devinit driver_pci9118_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, driver_pci9118.driver_name);
-}
-
-static void __devexit driver_pci9118_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_pci9118_pci_driver = {
-	.id_table = pci9118_pci_table,
-	.probe = &driver_pci9118_pci_probe,
-	.remove = __devexit_p(&driver_pci9118_pci_remove)
-};
-
-static int __init driver_pci9118_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_pci9118);
-	if (retval < 0)
-		return retval;
-
-	driver_pci9118_pci_driver.name = (char *)driver_pci9118.driver_name;
-	return pci_register_driver(&driver_pci9118_pci_driver);
-}
-
-static void __exit driver_pci9118_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_pci9118_pci_driver);
-	comedi_driver_unregister(&driver_pci9118);
-}
-
-module_init(driver_pci9118_init_module);
-module_exit(driver_pci9118_cleanup_module);
-
 struct pci9118_private {
 	unsigned long iobase_a;	/* base+size for AMCC chip */
 	unsigned int master;	/* master capable */
@@ -2190,9 +2111,6 @@
 	return 0;
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
@@ -2435,10 +2353,7 @@
 	return 0;
 }
 
-/*
-==============================================================================
-*/
-static int pci9118_detach(struct comedi_device *dev)
+static void pci9118_detach(struct comedi_device *dev)
 {
 	if (dev->private) {
 		if (devpriv->valid)
@@ -2458,13 +2373,100 @@
 			free_pages((unsigned long)devpriv->dmabuf_virt[1],
 				   devpriv->dmabuf_pages[1]);
 	}
-
-	return 0;
 }
 
-/*
-==============================================================================
-*/
+static const struct boardtype boardtypes[] = {
+	{
+		.name		= "pci9118dg",
+		.vendor_id	= PCI_VENDOR_ID_AMCC,
+		.device_id	= 0x80d9,
+		.iorange_amcc	= AMCC_OP_REG_SIZE,
+		.iorange_9118	= IORANGE_9118,
+		.n_aichan	= 16,
+		.n_aichand	= 8,
+		.mux_aichan	= 256,
+		.n_aichanlist	= PCI9118_CHANLEN,
+		.n_aochan	= 2,
+		.ai_maxdata	= 0x0fff,
+		.ao_maxdata	= 0x0fff,
+		.rangelist_ai	= &range_pci9118dg_hr,
+		.rangelist_ao	= &range_bipolar10,
+		.ai_ns_min	= 3000,
+		.ai_pacer_min	= 12,
+		.half_fifo_size	= 512,
+	}, {
+		.name		= "pci9118hg",
+		.vendor_id	= PCI_VENDOR_ID_AMCC,
+		.device_id	= 0x80d9,
+		.iorange_amcc	= AMCC_OP_REG_SIZE,
+		.iorange_9118	= IORANGE_9118,
+		.n_aichan	= 16,
+		.n_aichand	= 8,
+		.mux_aichan	= 256,
+		.n_aichanlist	= PCI9118_CHANLEN,
+		.n_aochan	= 2,
+		.ai_maxdata	= 0x0fff,
+		.ao_maxdata	= 0x0fff,
+		.rangelist_ai	= &range_pci9118hg,
+		.rangelist_ao	= &range_bipolar10,
+		.ai_ns_min	= 3000,
+		.ai_pacer_min	= 12,
+		.half_fifo_size	= 512,
+	}, {
+		.name		= "pci9118hr",
+		.vendor_id	= PCI_VENDOR_ID_AMCC,
+		.device_id	= 0x80d9,
+		.iorange_amcc	= AMCC_OP_REG_SIZE,
+		.iorange_9118	= IORANGE_9118,
+		.n_aichan	= 16,
+		.n_aichand	= 8,
+		.mux_aichan	= 256,
+		.n_aichanlist	= PCI9118_CHANLEN,
+		.n_aochan	= 2,
+		.ai_maxdata	= 0xffff,
+		.ao_maxdata	= 0x0fff,
+		.rangelist_ai	= &range_pci9118dg_hr,
+		.rangelist_ao	= &range_bipolar10,
+		.ai_ns_min	= 10000,
+		.ai_pacer_min	= 40,
+		.half_fifo_size	= 512,
+	},
+};
+
+static struct comedi_driver adl_pci9118_driver = {
+	.driver_name	= "adl_pci9118",
+	.module		= THIS_MODULE,
+	.attach		= pci9118_attach,
+	.detach		= pci9118_detach,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.board_name	= &boardtypes[0].name,
+	.offset		= sizeof(struct boardtype),
+};
+
+static int __devinit adl_pci9118_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &adl_pci9118_driver);
+}
+
+static void __devexit adl_pci9118_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(adl_pci9118_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, adl_pci9118_pci_table);
+
+static struct pci_driver adl_pci9118_pci_driver = {
+	.name		= "adl_pci9118",
+	.id_table	= adl_pci9118_pci_table,
+	.probe		= adl_pci9118_pci_probe,
+	.remove		= __devexit_p(adl_pci9118_pci_remove),
+};
+module_comedi_pci_driver(adl_pci9118_driver, adl_pci9118_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index 5361f31..7d585a1 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -125,24 +125,6 @@
 	int do_chans;
 };
 
-static const struct adq12b_board adq12b_boards[] = {
-	{
-	 .name = "adq12b",
-	 .ai_se_chans = 16,
-	 .ai_diff_chans = 8,
-	 .ai_bits = 12,
-	 .di_chans = 5,
-	 .do_chans = 8}
-/* potentially, more adq-based deviced will be added */
-/*,
-	.name = "adq12b",
-	.ai_chans = 16,  // this is just for reference, hardcoded again later
-	.ai_bits = 12,
-	.di_chans = 8,
-	.do_chans = 5
-	}*/
-};
-
 #define thisboard ((const struct adq12b_board *)dev->board_ptr)
 
 struct adq12b_private {
@@ -156,41 +138,88 @@
 #define devpriv ((struct adq12b_private *)dev->private)
 
 /*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
+ * "instructions" read/write data in "one-shot" or "software-triggered"
+ * mode.
  */
-static int adq12b_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int adq12b_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_adq12b = {
-	.driver_name = "adq12b",
-	.module = THIS_MODULE,
-	.attach = adq12b_attach,
-	.detach = adq12b_detach,
-	.board_name = &adq12b_boards[0].name,
-	.offset = sizeof(struct adq12b_board),
-	.num_names = ARRAY_SIZE(adq12b_boards),
-};
 
 static int adq12b_ai_rinsn(struct comedi_device *dev,
 			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data);
+			   unsigned int *data)
+{
+	int n, i;
+	int range, channel;
+	unsigned char hi, lo, status;
+
+	/* change channel and range only if it is different from the previous */
+	range = CR_RANGE(insn->chanspec);
+	channel = CR_CHAN(insn->chanspec);
+	if (channel != devpriv->last_channel || range != devpriv->last_range) {
+		outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG);
+		udelay(50);	/* wait for the mux to settle */
+	}
+
+	/* trigger conversion */
+	status = inb(dev->iobase + ADQ12B_ADLOW);
+
+	/* convert n samples */
+	for (n = 0; n < insn->n; n++) {
+
+		/* wait for end of conversion */
+		i = 0;
+		do {
+			/* udelay(1); */
+			status = inb(dev->iobase + ADQ12B_STINR);
+			status = status & ADQ12B_EOC;
+		} while (status == 0 && ++i < TIMEOUT);
+		/* } while (++i < 10); */
+
+		/* read data */
+		hi = inb(dev->iobase + ADQ12B_ADHIG);
+		lo = inb(dev->iobase + ADQ12B_ADLOW);
+
+		/* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n",
+		       channel, range, status,  hi, lo); */
+		data[n] = (hi << 8) | lo;
+
+	}
+
+	/* return the number of samples read/written */
+	return n;
+}
+
 static int adq12b_di_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
+			       struct comedi_insn *insn, unsigned int *data)
+{
+
+	/* only bits 0-4 have information about digital inputs */
+	data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f));
+
+	return 2;
+}
+
 static int adq12b_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
+			       struct comedi_insn *insn, unsigned int *data)
+{
+	int channel;
 
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
+	for (channel = 0; channel < 8; channel++)
+		if (((data[0] >> channel) & 0x01) != 0)
+			outb((((data[1] >> channel) & 0x01) << 3) | channel,
+			     dev->iobase + ADQ12B_OUTBR);
+
+	/* store information to retrieve when asked for reading */
+	if (data[0]) {
+		devpriv->digital_state &= ~data[0];
+		devpriv->digital_state |= (data[0] & data[1]);
+	}
+
+	data[1] = devpriv->digital_state;
+
+	return 2;
+}
+
 static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct comedi_subdevice *s;
@@ -295,125 +324,34 @@
 	return 0;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int adq12b_detach(struct comedi_device *dev)
+static void adq12b_detach(struct comedi_device *dev)
 {
 	if (dev->iobase)
 		release_region(dev->iobase, ADQ12B_SIZE);
-
 	kfree(devpriv);
-
-	printk(KERN_INFO "comedi%d: adq12b: removed\n", dev->minor);
-
-	return 0;
 }
 
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
+static const struct adq12b_board adq12b_boards[] = {
+	{
+		.name		= "adq12b",
+		.ai_se_chans	= 16,
+		.ai_diff_chans	= 8,
+		.ai_bits	= 12,
+		.di_chans	= 5,
+		.do_chans	= 8,
+	},
+};
 
-static int adq12b_ai_rinsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data)
-{
-	int n, i;
-	int range, channel;
-	unsigned char hi, lo, status;
-
-	/* change channel and range only if it is different from the previous */
-	range = CR_RANGE(insn->chanspec);
-	channel = CR_CHAN(insn->chanspec);
-	if (channel != devpriv->last_channel || range != devpriv->last_range) {
-		outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG);
-		udelay(50);	/* wait for the mux to settle */
-	}
-
-	/* trigger conversion */
-	status = inb(dev->iobase + ADQ12B_ADLOW);
-
-	/* convert n samples */
-	for (n = 0; n < insn->n; n++) {
-
-		/* wait for end of conversion */
-		i = 0;
-		do {
-			/* udelay(1); */
-			status = inb(dev->iobase + ADQ12B_STINR);
-			status = status & ADQ12B_EOC;
-		} while (status == 0 && ++i < TIMEOUT);
-		/* } while (++i < 10); */
-
-		/* read data */
-		hi = inb(dev->iobase + ADQ12B_ADHIG);
-		lo = inb(dev->iobase + ADQ12B_ADLOW);
-
-		/* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n",
-		       channel, range, status,  hi, lo); */
-		data[n] = (hi << 8) | lo;
-
-	}
-
-	/* return the number of samples read/written */
-	return n;
-}
-
-static int adq12b_di_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
-{
-
-	/* only bits 0-4 have information about digital inputs */
-	data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f));
-
-	return 2;
-}
-
-static int adq12b_do_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
-{
-	int channel;
-
-	for (channel = 0; channel < 8; channel++)
-		if (((data[0] >> channel) & 0x01) != 0)
-			outb((((data[1] >> channel) & 0x01) << 3) | channel,
-			     dev->iobase + ADQ12B_OUTBR);
-
-	/* store information to retrieve when asked for reading */
-	if (data[0]) {
-		devpriv->digital_state &= ~data[0];
-		devpriv->digital_state |= (data[0] & data[1]);
-	}
-
-	data[1] = devpriv->digital_state;
-
-	return 2;
-}
-
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __init driver_adq12b_init_module(void)
-{
-	return comedi_driver_register(&driver_adq12b);
-}
-
-static void __exit driver_adq12b_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_adq12b);
-}
-
-module_init(driver_adq12b_init_module);
-module_exit(driver_adq12b_cleanup_module);
+static struct comedi_driver adq12b_driver = {
+	.driver_name	= "adq12b",
+	.module		= THIS_MODULE,
+	.attach		= adq12b_attach,
+	.detach		= adq12b_detach,
+	.board_name	= &adq12b_boards[0].name,
+	.offset		= sizeof(struct adq12b_board),
+	.num_names	= ARRAY_SIZE(adq12b_boards),
+};
+module_comedi_driver(adq12b_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index 8318c82..de8c98c 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -191,10 +191,6 @@
 							   }
 };
 
-static int pci1710_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int pci1710_detach(struct comedi_device *dev);
-
 struct boardtype {
 	const char *name;	/*  board name */
 	int device_id;
@@ -216,17 +212,6 @@
 	unsigned int fifo_half_size;	/*  size of FIFO/2 */
 };
 
-static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
-
 static const struct boardtype boardtypes[] = {
 	{"pci1710", 0x1710,
 	 IORANGE_171x, 1, TYPE_PCI171X,
@@ -264,18 +249,6 @@
 	{.name = DRV_NAME},
 };
 
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
-
-static struct comedi_driver driver_pci1710 = {
-	.driver_name = DRV_NAME,
-	.module = THIS_MODULE,
-	.attach = pci1710_attach,
-	.detach = pci1710_detach,
-	.num_names = n_boardtypes,
-	.board_name = &boardtypes[0].name,
-	.offset = sizeof(struct boardtype),
-};
-
 struct pci1710_private {
 	struct pci_dev *pcidev;	/*  ptr to PCI device */
 	char valid;		/*  card is usable */
@@ -676,7 +649,9 @@
 			     s->async->buf_int_count, s->async->buf_int_ptr,
 			     s->async->buf_user_count, s->async->buf_user_ptr);
 			DPRINTK("adv_pci1710 EDBG: EOS2\n");
-			if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) {	/*  all data sampled */
+			if ((!devpriv->neverending_ai) &&
+			    (devpriv->ai_act_scan >= devpriv->ai_scans)) {
+				/*  all data sampled */
 				pci171x_ai_cancel(dev, s);
 				s->async->events |= COMEDI_CB_EOA;
 				comedi_event(dev, s);
@@ -804,8 +779,8 @@
 		irq);
 	if (!dev->attached)	/*  is device attached? */
 		return IRQ_NONE;	/*  no, exit */
-
-	if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))	/*  is this interrupt from our board? */
+	/*  is this interrupt from our board? */
+	if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
 		return IRQ_NONE;	/*  no, exit */
 
 	DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
@@ -814,7 +789,7 @@
 	if (devpriv->ai_et) {	/*  Switch from initial TRIG_EXT to TRIG_xxx. */
 		devpriv->ai_et = 0;
 		devpriv->CntrlReg &= Control_CNT0;
-		devpriv->CntrlReg |= Control_SW;	/*  set software trigger */
+		devpriv->CntrlReg |= Control_SW; /* set software trigger */
 		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
 		devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
 		outb(0, dev->iobase + PCI171x_CLRFIFO);
@@ -865,7 +840,8 @@
 	devpriv->neverending_ai = 0;
 
 	devpriv->CntrlReg &= Control_CNT0;
-	if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {	/*  don't we want wake up every scan?            devpriv->ai_eos=1; */
+	/*  don't we want wake up every scan?  devpriv->ai_eos=1; */
+	if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
 		devpriv->ai_eos = 1;
 	} else {
 		devpriv->CntrlReg |= Control_ONEFH;
@@ -982,13 +958,13 @@
 #ifdef PCI171X_EXTDEBUG
 		pci171x_cmdtest_out(1, cmd);
 #endif
-		DPRINTK
-		    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
-		     err);
+		DPRINTK(
+		"adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
+		err);
 		return 1;
 	}
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* step2: make sure trigger srcs are unique and mutually compatible */
 
 	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
 		cmd->start_src = TRIG_NOW;
@@ -1015,9 +991,9 @@
 #ifdef PCI171X_EXTDEBUG
 		pci171x_cmdtest_out(2, cmd);
 #endif
-		DPRINTK
-		    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
-		     err);
+		DPRINTK(
+		"adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
+		err);
 		return 2;
 	}
 
@@ -1065,9 +1041,9 @@
 #ifdef PCI171X_EXTDEBUG
 		pci171x_cmdtest_out(3, cmd);
 #endif
-		DPRINTK
-		    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
-		     err);
+		DPRINTK(
+		"adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
+		err);
 		return 3;
 	}
 
@@ -1160,48 +1136,41 @@
 		return 0;
 	}
 
-	if (n_chan > 1) {
-		chansegment[0] = chanlist[0];	/*  first channel is every time ok */
-		for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {	/*  build part of chanlist */
-			/*  printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
-			if (chanlist[0] == chanlist[i])
-				break;	/*  we detect loop, this must by finish */
-			if (CR_CHAN(chanlist[i]) & 1)	/*  odd channel cann't by differencial */
-				if (CR_AREF(chanlist[i]) == AREF_DIFF) {
-					comedi_error(dev,
-						     "Odd channel can't be differential input!\n");
-					return 0;
-				}
-			nowmustbechan =
-			    (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
-			if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
-				nowmustbechan = (nowmustbechan + 1) % s->n_chan;
-			if (nowmustbechan != CR_CHAN(chanlist[i])) {	/*  channel list isn't continuous :-( */
-				printk
-				    ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
-				     i, CR_CHAN(chanlist[i]), nowmustbechan,
-				     CR_CHAN(chanlist[0]));
-				return 0;
-			}
-			chansegment[i] = chanlist[i];	/*  well, this is next correct channel in list */
-		}
+	if (n_chan == 1)
+		return 1; /* seglen=1 */
 
-		for (i = 0, segpos = 0; i < n_chan; i++) {	/*  check whole chanlist */
-			/* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
-			if (chanlist[i] != chansegment[i % seglen]) {
-				printk
-				    ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
-				     i, CR_CHAN(chansegment[i]),
-				     CR_RANGE(chansegment[i]),
-				     CR_AREF(chansegment[i]),
-				     CR_CHAN(chanlist[i % seglen]),
-				     CR_RANGE(chanlist[i % seglen]),
-				     CR_AREF(chansegment[i % seglen]));
-				return 0;	/*  chan/gain list is strange */
-			}
+	chansegment[0] = chanlist[0]; /*  first channel is every time ok */
+	for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
+		if (chanlist[0] == chanlist[i])
+			break;	/*  we detected a loop, stop */
+		if ((CR_CHAN(chanlist[i]) & 1) &&
+		    (CR_AREF(chanlist[i]) == AREF_DIFF)) {
+			comedi_error(dev, "Odd channel cannot be differential input!\n");
+			return 0;
 		}
-	} else {
-		seglen = 1;
+		nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
+		if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
+			nowmustbechan = (nowmustbechan + 1) % s->n_chan;
+		if (nowmustbechan != CR_CHAN(chanlist[i])) {
+			printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
+			       i, CR_CHAN(chanlist[i]), nowmustbechan,
+			       CR_CHAN(chanlist[0]));
+			return 0;
+		}
+		chansegment[i] = chanlist[i]; /* next correct channel in list */
+	}
+
+	for (i = 0, segpos = 0; i < n_chan; i++) {
+		if (chanlist[i] != chansegment[i % seglen]) {
+			printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
+			       i, CR_CHAN(chansegment[i]),
+			       CR_RANGE(chansegment[i]),
+			       CR_AREF(chansegment[i]),
+			       CR_CHAN(chanlist[i % seglen]),
+			       CR_RANGE(chanlist[i % seglen]),
+			       CR_AREF(chansegment[i % seglen]));
+			return 0;
+		}
 	}
 	return seglen;
 }
@@ -1221,14 +1190,14 @@
 	DPRINTK("SegLen: %d\n", seglen);
 	for (i = 0; i < seglen; i++) {	/*  store range list to card */
 		chanprog = muxonechan[CR_CHAN(chanlist[i])];
-		outw(chanprog, dev->iobase + PCI171x_MUX);	/* select channel */
+		outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
 		range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
 		if (CR_AREF(chanlist[i]) == AREF_DIFF)
 			range |= 0x0020;
-		outw(range, dev->iobase + PCI171x_RANGE);	/* select gain */
+		outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
 #ifdef PCI171x_PARANOIDCHECK
 		devpriv->act_chanlist[i] =
-		    (CR_CHAN(chanlist[i]) << 12) & 0xf000;
+			(CR_CHAN(chanlist[i]) << 12) & 0xf000;
 #endif
 		DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
 			devpriv->act_chanlist[i]);
@@ -1236,13 +1205,14 @@
 #ifdef PCI171x_PARANOIDCHECK
 	for ( ; i < n_chan; i++) { /* store remainder of channel list */
 		devpriv->act_chanlist[i] =
-		    (CR_CHAN(chanlist[i]) << 12) & 0xf000;
+			(CR_CHAN(chanlist[i]) << 12) & 0xf000;
 	}
 #endif
 
 	devpriv->ai_et_MuxVal =
-	    CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
-	outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);	/* select channel interval to scan */
+		CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
+	/* select channel interval to scan */
+	outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
 	DPRINTK("MUX: %4x L%4x.H%4x\n",
 		CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
 		CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
@@ -1365,9 +1335,6 @@
 	DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
 }
 
-/*
-==============================================================================
-*/
 static int pci1710_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
@@ -1398,13 +1365,13 @@
 	while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
 						PCI_ANY_ID, pcidev))) {
 		if (strcmp(this_board->name, DRV_NAME) == 0) {
-			for (i = 0; i < n_boardtypes; ++i) {
+			for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
 				if (pcidev->device == boardtypes[i].device_id) {
 					board_index = i;
 					break;
 				}
 			}
-			if (i == n_boardtypes)
+			if (i == ARRAY_SIZE(boardtypes))
 				continue;
 		} else {
 			if (pcidev->device != boardtypes[board_index].device_id)
@@ -1584,12 +1551,8 @@
 	return 0;
 }
 
-/*
-==============================================================================
-*/
-static int pci1710_detach(struct comedi_device *dev)
+static void pci1710_detach(struct comedi_device *dev)
 {
-
 	if (dev->private) {
 		if (devpriv->valid)
 			pci1710_reset(dev);
@@ -1598,57 +1561,49 @@
 		if (devpriv->pcidev) {
 			if (dev->iobase)
 				comedi_pci_disable(devpriv->pcidev);
-
 			pci_dev_put(devpriv->pcidev);
 		}
 	}
-
-	return 0;
 }
 
-/*
-==============================================================================
-*/
-static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
+static struct comedi_driver adv_pci1710_driver = {
+	.driver_name	= "adv_pci1710",
+	.module		= THIS_MODULE,
+	.attach		= pci1710_attach,
+	.detach		= pci1710_detach,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.board_name	= &boardtypes[0].name,
+	.offset		= sizeof(struct boardtype),
+};
+
+static int __devinit adv_pci1710_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
+	return comedi_pci_auto_config(dev, &adv_pci1710_driver);
 }
 
-static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
+static void __devexit adv_pci1710_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_pci1710_pci_driver = {
-	.id_table = pci1710_pci_table,
-	.probe = &driver_pci1710_pci_probe,
-	.remove = __devexit_p(&driver_pci1710_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
 
-static int __init driver_pci1710_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_pci1710);
-	if (retval < 0)
-		return retval;
-
-	driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
-	return pci_register_driver(&driver_pci1710_pci_driver);
-}
-
-static void __exit driver_pci1710_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_pci1710_pci_driver);
-	comedi_driver_unregister(&driver_pci1710);
-}
-
-module_init(driver_pci1710_init_module);
-module_exit(driver_pci1710_cleanup_module);
-/*
-==============================================================================
-*/
+static struct pci_driver adv_pci1710_pci_driver = {
+	.name		= "adv_pci1710",
+	.id_table	= adv_pci1710_pci_table,
+	.probe		= adv_pci1710_pci_probe,
+	.remove		= __devexit_p(adv_pci1710_pci_remove),
+};
+module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 29455a8..336addc 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -150,36 +150,6 @@
 	 },
 };
 
-/*
- * This is used by modprobe to translate PCI IDs to drivers.
- * Should only be used for PCI and ISA-PnP devices
- */
-static DEFINE_PCI_DEVICE_TABLE(pci1723_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci1723_pci_table);
-
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pci1723_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int pci1723_detach(struct comedi_device *dev);
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pci1723_board))
-
-static struct comedi_driver driver_pci1723 = {
-	.driver_name = "adv_pci1723",
-	.module = THIS_MODULE,
-	.attach = pci1723_attach,
-	.detach = pci1723_detach,
-};
-
 /* This structure is for data unique to this hardware driver. */
 struct pci1723_private {
 	int valid;		/* card is usable; */
@@ -319,10 +289,6 @@
 	return 2;
 }
 
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a pci1723 board.
- */
 static int pci1723_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
@@ -465,73 +431,50 @@
 	return 0;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci1723_detach(struct comedi_device *dev)
+static void pci1723_detach(struct comedi_device *dev)
 {
-	printk(KERN_ERR "comedi%d: pci1723: remove\n", dev->minor);
-
 	if (dev->private) {
 		if (devpriv->valid)
 			pci1723_reset(dev);
-
 		if (devpriv->pcidev) {
 			if (dev->iobase)
 				comedi_pci_disable(devpriv->pcidev);
 			pci_dev_put(devpriv->pcidev);
 		}
 	}
-
-	return 0;
 }
 
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_pci1723_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
+static struct comedi_driver adv_pci1723_driver = {
+	.driver_name	= "adv_pci1723",
+	.module		= THIS_MODULE,
+	.attach		= pci1723_attach,
+	.detach		= pci1723_detach,
+};
+
+static int __devinit adv_pci1723_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_pci1723.driver_name);
+	return comedi_pci_auto_config(dev, &adv_pci1723_driver);
 }
 
-static void __devexit driver_pci1723_pci_remove(struct pci_dev *dev)
+static void __devexit adv_pci1723_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_pci1723_pci_driver = {
-	.id_table = pci1723_pci_table,
-	.probe = &driver_pci1723_pci_probe,
-	.remove = __devexit_p(&driver_pci1723_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adv_pci1723_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, adv_pci1723_pci_table);
 
-static int __init driver_pci1723_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_pci1723);
-	if (retval < 0)
-		return retval;
-
-	driver_pci1723_pci_driver.name = (char *)driver_pci1723.driver_name;
-	return pci_register_driver(&driver_pci1723_pci_driver);
-}
-
-static void __exit driver_pci1723_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_pci1723_pci_driver);
-	comedi_driver_unregister(&driver_pci1723);
-}
-
-module_init(driver_pci1723_init_module);
-module_exit(driver_pci1723_cleanup_module);
+static struct pci_driver adv_pci1723_pci_driver = {
+	.name		= "adv_pci1723",
+	.id_table	= adv_pci1723_pci_table,
+	.probe		= adv_pci1723_pci_probe,
+	.remove		= __devexit_p(adv_pci1723_pci_remove),
+};
+module_comedi_pci_driver(adv_pci1723_driver, adv_pci1723_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 7af068f..43a32dc 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -237,10 +237,6 @@
 
 #define OMBCMD_RETRY	0x03	/* 3 times try request before error */
 
-static int pci_dio_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int pci_dio_detach(struct comedi_device *dev);
-
 struct diosubd_data {
 	int chans;		/*  num of chans */
 	int addr;		/*  PCI address ofset */
@@ -263,26 +259,6 @@
 	enum hw_io_access io_access;
 };
 
-static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_dio_pci_table);
-
 static const struct dio_boardtype boardtypes[] = {
 	{"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG,
 	 TYPE_PCI1730,
@@ -406,15 +382,6 @@
 	 IO_16b}
 };
 
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dio_boardtype))
-
-static struct comedi_driver driver_pci_dio = {
-	.driver_name = "adv_pci_dio",
-	.module = THIS_MODULE,
-	.attach = pci_dio_attach,
-	.detach = pci_dio_detach
-};
-
 struct pci_dio_private {
 	struct pci_dio_private *prev;	/*  previous private struct */
 	struct pci_dio_private *next;	/*  next private struct */
@@ -1116,9 +1083,6 @@
 	return 1;
 }
 
-/*
-==============================================================================
-*/
 static int pci_dio_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
@@ -1134,7 +1098,7 @@
 
 	for_each_pci_dev(pcidev) {
 		/*  loop through cards supported by this driver */
-		for (i = 0; i < n_boardtypes; ++i) {
+		for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
 			if (boardtypes[i].vendor_id != pcidev->vendor)
 				continue;
 			if (boardtypes[i].device_id != pcidev->device)
@@ -1162,7 +1126,7 @@
 		return -EIO;
 	}
 
-	if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) {
+	if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
 		dev_err(dev->hw_dev, "Error: Can't enable PCI device and request regions!\n");
 		return -EIO;
 	}
@@ -1246,10 +1210,7 @@
 	return 0;
 }
 
-/*
-==============================================================================
-*/
-static int pci_dio_detach(struct comedi_device *dev)
+static void pci_dio_detach(struct comedi_device *dev)
 {
 	int i, j;
 	struct comedi_subdevice *s;
@@ -1258,20 +1219,14 @@
 	if (dev->private) {
 		if (devpriv->valid)
 			pci_dio_reset(dev);
-
-
-		/* This shows the silliness of using this kind of
-		 * scheme for numbering subdevices.  Don't do it.  --ds */
 		subdev = 0;
 		for (i = 0; i < MAX_DI_SUBDEVS; i++) {
 			if (this_board->sdi[i].chans)
 				subdev++;
-
 		}
 		for (i = 0; i < MAX_DO_SUBDEVS; i++) {
 			if (this_board->sdo[i].chans)
 				subdev++;
-
 		}
 		for (i = 0; i < MAX_DIO_SUBDEVG; i++) {
 			for (j = 0; j < this_board->sdio[i].regs; j++) {
@@ -1280,82 +1235,73 @@
 				subdev++;
 			}
 		}
-
 		if (this_board->boardid.chans)
 			subdev++;
-
 		for (i = 0; i < MAX_8254_SUBDEVS; i++)
 			if (this_board->s8254[i].chans)
 				subdev++;
-
 		for (i = 0; i < dev->n_subdevices; i++) {
 			s = dev->subdevices + i;
 			s->private = NULL;
 		}
-
 		if (devpriv->pcidev) {
 			if (dev->iobase)
 				comedi_pci_disable(devpriv->pcidev);
-
 			pci_dev_put(devpriv->pcidev);
 		}
-
 		if (devpriv->prev)
 			devpriv->prev->next = devpriv->next;
 		else
 			pci_priv = devpriv->next;
-
 		if (devpriv->next)
 			devpriv->next->prev = devpriv->prev;
-
 	}
-
-	return 0;
 }
 
-/*
-==============================================================================
-*/
-static int __devinit driver_pci_dio_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
+static struct comedi_driver adv_pci_dio_driver = {
+	.driver_name	= "adv_pci_dio",
+	.module		= THIS_MODULE,
+	.attach		= pci_dio_attach,
+	.detach		= pci_dio_detach
+};
+
+static int __devinit adv_pci_dio_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_pci_dio.driver_name);
+	return comedi_pci_auto_config(dev, &adv_pci_dio_driver);
 }
 
-static void __devexit driver_pci_dio_pci_remove(struct pci_dev *dev)
+static void __devexit adv_pci_dio_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_pci_dio_pci_driver = {
-	.id_table = pci_dio_pci_table,
-	.probe = &driver_pci_dio_pci_probe,
-	.remove = __devexit_p(&driver_pci_dio_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table);
 
-static int __init driver_pci_dio_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_pci_dio);
-	if (retval < 0)
-		return retval;
-
-	driver_pci_dio_pci_driver.name = (char *)driver_pci_dio.driver_name;
-	return pci_register_driver(&driver_pci_dio_pci_driver);
-}
-
-static void __exit driver_pci_dio_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_pci_dio_pci_driver);
-	comedi_driver_unregister(&driver_pci_dio);
-}
-
-module_init(driver_pci_dio_init_module);
-module_exit(driver_pci_dio_cleanup_module);
-/*
-==============================================================================
-*/
+static struct pci_driver adv_pci_dio_pci_driver = {
+	.name		= "adv_pci_dio",
+	.id_table	= adv_pci_dio_pci_table,
+	.probe		= adv_pci_dio_pci_probe,
+	.remove		= __devexit_p(adv_pci_dio_pci_remove),
+};
+module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index b0f98e5..64d82bc 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -209,36 +209,23 @@
 	return 0;
 }
 
-static int aio_aio12_8_detach(struct comedi_device *dev)
+static void aio_aio12_8_detach(struct comedi_device *dev)
 {
 	subdev_8255_cleanup(dev, &dev->subdevices[2]);
 	if (dev->iobase)
 		release_region(dev->iobase, 24);
-	return 0;
 }
 
-static struct comedi_driver driver_aio_aio12_8 = {
-	.driver_name = "aio_aio12_8",
-	.module = THIS_MODULE,
-	.attach = aio_aio12_8_attach,
-	.detach = aio_aio12_8_detach,
-	.board_name = &board_types[0].name,
-	.num_names = 1,
-	.offset = sizeof(struct aio12_8_boardtype),
+static struct comedi_driver aio_aio12_8_driver = {
+	.driver_name	= "aio_aio12_8",
+	.module		= THIS_MODULE,
+	.attach		= aio_aio12_8_attach,
+	.detach		= aio_aio12_8_detach,
+	.board_name	= &board_types[0].name,
+	.num_names	= ARRAY_SIZE(board_types),
+	.offset		= sizeof(struct aio12_8_boardtype),
 };
-
-static int __init driver_aio_aio12_8_init_module(void)
-{
-	return comedi_driver_register(&driver_aio_aio12_8);
-}
-
-static void __exit driver_aio_aio12_8_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_aio_aio12_8);
-}
-
-module_init(driver_aio_aio12_8_init_module);
-module_exit(driver_aio_aio12_8_cleanup_module);
+module_comedi_driver(aio_aio12_8_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 160b0a0..04f6f94 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -67,30 +67,41 @@
 
 #define	devpriv	((struct aio_iiro_16_private *) dev->private)
 
-static int aio_iiro_16_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it);
+static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
+					   struct comedi_subdevice *s,
+					   struct comedi_insn *insn,
+					   unsigned int *data)
+{
+	if (insn->n != 2)
+		return -EINVAL;
 
-static int aio_iiro_16_detach(struct comedi_device *dev);
+	if (data[0]) {
+		s->state &= ~data[0];
+		s->state |= data[0] & data[1];
+		outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
+		outb((s->state >> 8) & 0xff,
+		     dev->iobase + AIO_IIRO_16_RELAY_8_15);
+	}
 
-static struct comedi_driver driver_aio_iiro_16 = {
-	.driver_name = "aio_iiro_16",
-	.module = THIS_MODULE,
-	.attach = aio_iiro_16_attach,
-	.detach = aio_iiro_16_detach,
-	.board_name = &aio_iiro_16_boards[0].name,
-	.offset = sizeof(struct aio_iiro_16_board),
-	.num_names = ARRAY_SIZE(aio_iiro_16_boards),
-};
+	data[1] = s->state;
+
+	return 2;
+}
 
 static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
 					  struct comedi_subdevice *s,
 					  struct comedi_insn *insn,
-					  unsigned int *data);
+					  unsigned int *data)
+{
+	if (insn->n != 2)
+		return -EINVAL;
 
-static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
-					   struct comedi_subdevice *s,
-					   struct comedi_insn *insn,
-					   unsigned int *data);
+	data[1] = 0;
+	data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
+	data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
+
+	return 2;
+}
 
 static int aio_iiro_16_attach(struct comedi_device *dev,
 			      struct comedi_devconfig *it)
@@ -138,64 +149,22 @@
 	return 1;
 }
 
-static int aio_iiro_16_detach(struct comedi_device *dev)
+static void aio_iiro_16_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: aio_iiro_16: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, AIO_IIRO_16_SIZE);
-
-	return 0;
 }
 
-static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
-					   struct comedi_subdevice *s,
-					   struct comedi_insn *insn,
-					   unsigned int *data)
-{
-	if (insn->n != 2)
-		return -EINVAL;
-
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= data[0] & data[1];
-		outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
-		outb((s->state >> 8) & 0xff,
-		     dev->iobase + AIO_IIRO_16_RELAY_8_15);
-	}
-
-	data[1] = s->state;
-
-	return 2;
-}
-
-static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
-					  struct comedi_subdevice *s,
-					  struct comedi_insn *insn,
-					  unsigned int *data)
-{
-	if (insn->n != 2)
-		return -EINVAL;
-
-	data[1] = 0;
-	data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
-	data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
-
-	return 2;
-}
-
-static int __init driver_aio_iiro_16_init_module(void)
-{
-	return comedi_driver_register(&driver_aio_iiro_16);
-}
-
-static void __exit driver_aio_iiro_16_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_aio_iiro_16);
-}
-
-module_init(driver_aio_iiro_16_init_module);
-module_exit(driver_aio_iiro_16_cleanup_module);
+static struct comedi_driver aio_iiro_16_driver = {
+	.driver_name	= "aio_iiro_16",
+	.module		= THIS_MODULE,
+	.attach		= aio_iiro_16_attach,
+	.detach		= aio_iiro_16_detach,
+	.board_name	= &aio_iiro_16_boards[0].name,
+	.offset		= sizeof(struct aio_iiro_16_board),
+	.num_names	= ARRAY_SIZE(aio_iiro_16_boards),
+};
+module_comedi_driver(aio_iiro_16_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index 566cc44..c9c5d97 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -217,6 +217,14 @@
 
 #define DIO200_DRIVER_NAME	"amplc_dio200"
 
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA_MODULE
+#define CONFIG_COMEDI_AMPLC_DIO200_ISA
+#endif
+
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI_MODULE
+#define CONFIG_COMEDI_AMPLC_DIO200_PCI
+#endif
+
 /* PCI IDs */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
@@ -274,10 +282,14 @@
 };
 
 enum dio200_layout {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 	pc212_layout,
 	pc214_layout,
+#endif
 	pc215_layout,
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 	pc218_layout,
+#endif
 	pc272_layout
 };
 
@@ -290,6 +302,7 @@
 };
 
 static const struct dio200_board dio200_boards[] = {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 	{
 	 .name = "pc212e",
 	 .bustype = isa_bustype,
@@ -308,15 +321,6 @@
 	 .model = pc215e_model,
 	 .layout = pc215_layout,
 	 },
-#ifdef CONFIG_COMEDI_PCI
-	{
-	 .name = "pci215",
-	 .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
-	 .bustype = pci_bustype,
-	 .model = pci215_model,
-	 .layout = pc215_layout,
-	 },
-#endif
 	{
 	 .name = "pc218e",
 	 .bustype = isa_bustype,
@@ -329,7 +333,15 @@
 	 .model = pc272e_model,
 	 .layout = pc272_layout,
 	 },
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
+	{
+	 .name = "pci215",
+	 .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
+	 .bustype = pci_bustype,
+	 .model = pci215_model,
+	 .layout = pc215_layout,
+	 },
 	{
 	 .name = "pci272",
 	 .devid = PCI_DEVICE_ID_AMPLICON_PCI272,
@@ -337,8 +349,6 @@
 	 .model = pci272_model,
 	 .layout = pc272_layout,
 	 },
-#endif
-#ifdef CONFIG_COMEDI_PCI
 	{
 	 .name = DIO200_DRIVER_NAME,
 	 .devid = PCI_DEVICE_ID_INVALID,
@@ -367,6 +377,7 @@
 };
 
 static const struct dio200_layout_struct dio200_layouts[] = {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 	[pc212_layout] = {
 			  .n_subdevs = 6,
 			  .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
@@ -385,6 +396,7 @@
 			  .has_int_sce = 0,
 			  .has_clk_gat_sce = 0,
 			  },
+#endif
 	[pc215_layout] = {
 			  .n_subdevs = 5,
 			  .sdtype = {sd_8255, sd_8255, sd_8254,
@@ -394,6 +406,7 @@
 			  .has_int_sce = 1,
 			  .has_clk_gat_sce = 1,
 			  },
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 	[pc218_layout] = {
 			  .n_subdevs = 7,
 			  .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
@@ -405,6 +418,7 @@
 			  .has_int_sce = 1,
 			  .has_clk_gat_sce = 1,
 			  },
+#endif
 	[pc272_layout] = {
 			  .n_subdevs = 4,
 			  .sdtype = {sd_8255, sd_8255, sd_8255,
@@ -419,7 +433,7 @@
  * PCI driver table.
  */
 
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
 static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
@@ -427,7 +441,7 @@
 };
 
 MODULE_DEVICE_TABLE(pci, dio200_pci_table);
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_DIO200_PCI */
 
 /*
  * Useful for shorthand access to the particular board structure
@@ -441,7 +455,7 @@
    feel free to suggest moving the variable to the struct comedi_device struct.
  */
 struct dio200_private {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
 	struct pci_dev *pci_dev;	/* PCI device */
 #endif
 	int intr_sd;
@@ -479,7 +493,7 @@
  */
 static int dio200_attach(struct comedi_device *dev,
 			 struct comedi_devconfig *it);
-static int dio200_detach(struct comedi_device *dev);
+static void dio200_detach(struct comedi_device *dev);
 static struct comedi_driver driver_amplc_dio200 = {
 	.driver_name = DIO200_DRIVER_NAME,
 	.module = THIS_MODULE,
@@ -490,12 +504,12 @@
 	.num_names = ARRAY_SIZE(dio200_boards),
 };
 
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
 static int __devinit driver_amplc_dio200_pci_probe(struct pci_dev *dev,
 						   const struct pci_device_id
 						   *ent)
 {
-	return comedi_pci_auto_config(dev, driver_amplc_dio200.driver_name);
+	return comedi_pci_auto_config(dev, &driver_amplc_dio200);
 }
 
 static void __devexit driver_amplc_dio200_pci_remove(struct pci_dev *dev)
@@ -549,7 +563,7 @@
  * This function looks for a PCI device matching the requested board name,
  * bus and slot.
  */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
 static int
 dio200_find_pci(struct comedi_device *dev, int bus, int slot,
 		struct pci_dev **pci_dev_p)
@@ -611,6 +625,7 @@
  * This function checks and requests an I/O region, reporting an error
  * if there is a conflict.
  */
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 static int
 dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
 {
@@ -621,6 +636,7 @@
 	}
 	return 0;
 }
+#endif
 
 /*
  * 'insn_bits' function for an 'INTERRUPT' subdevice.
@@ -1332,7 +1348,7 @@
 	struct comedi_subdevice *s;
 	unsigned long iobase = 0;
 	unsigned int irq = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
 	struct pci_dev *pci_dev = NULL;
 	int bus = 0, slot = 0;
 #endif
@@ -1354,12 +1370,14 @@
 
 	/* Process options. */
 	switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 	case isa_bustype:
 		iobase = it->options[0];
 		irq = it->options[1];
 		share_irq = 0;
 		break;
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
 	case pci_bustype:
 		bus = it->options[0];
 		slot = it->options[1];
@@ -1382,7 +1400,7 @@
 	devpriv->intr_sd = -1;
 
 	/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
 	if (pci_dev) {
 		ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
 		if (ret < 0) {
@@ -1396,9 +1414,11 @@
 	} else
 #endif
 	{
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 		ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
 		if (ret < 0)
 			return ret;
+#endif
 	}
 	dev->iobase = iobase;
 
@@ -1474,12 +1494,19 @@
 	}
 
 	printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
-	if (thisboard->bustype == isa_bustype) {
+	switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
+	case isa_bustype:
 		printk("(base %#lx) ", iobase);
-	} else {
-#ifdef CONFIG_COMEDI_PCI
-		printk("(pci %s) ", pci_name(pci_dev));
+		break;
 #endif
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
+	case pci_bustype:
+		printk("(pci %s) ", pci_name(pci_dev));
+		break;
+#endif
+	default:
+		break;
 	}
 	if (irq)
 		printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
@@ -1491,22 +1518,11 @@
 	return 1;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int dio200_detach(struct comedi_device *dev)
+static void dio200_detach(struct comedi_device *dev)
 {
 	const struct dio200_layout_struct *layout;
 	unsigned n;
 
-	printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
-	       DIO200_DRIVER_NAME);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->subdevices) {
@@ -1529,7 +1545,7 @@
 		}
 	}
 	if (devpriv) {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
 		if (devpriv->pci_dev) {
 			if (dev->iobase)
 				comedi_pci_disable(devpriv->pci_dev);
@@ -1537,15 +1553,12 @@
 		} else
 #endif
 		{
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 			if (dev->iobase)
 				release_region(dev->iobase, DIO200_IO_SIZE);
+#endif
 		}
 	}
-	if (dev->board_name)
-		printk(KERN_INFO "comedi%d: %s removed\n",
-		       dev->minor, dev->board_name);
-
-	return 0;
 }
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 7972cad..57ba322 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -63,6 +63,14 @@
 
 #define PC236_DRIVER_NAME	"amplc_pc236"
 
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA_MODULE
+#define CONFIG_COMEDI_AMPLC_PC236_ISA
+#endif
+
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI_MODULE
+#define CONFIG_COMEDI_AMPLC_PC236_PCI
+#endif
+
 /* PCI236 PCI configuration register information */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009
@@ -106,13 +114,15 @@
 	enum pc236_model model;
 };
 static const struct pc236_board pc236_boards[] = {
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
 	{
 	 .name = "pc36at",
 	 .fancy_name = "PC36AT",
 	 .bustype = isa_bustype,
 	 .model = pc36at_model,
 	 },
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 	{
 	 .name = "pci236",
 	 .fancy_name = "PCI236",
@@ -120,8 +130,6 @@
 	 .bustype = pci_bustype,
 	 .model = pci236_model,
 	 },
-#endif
-#ifdef CONFIG_COMEDI_PCI
 	{
 	 .name = PC236_DRIVER_NAME,
 	 .fancy_name = PC236_DRIVER_NAME,
@@ -132,14 +140,14 @@
 #endif
 };
 
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) },
 	{0}
 };
 
 MODULE_DEVICE_TABLE(pci, pc236_pci_table);
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_PC236_PCI */
 
 /*
  * Useful for shorthand access to the particular board structure
@@ -151,7 +159,7 @@
    feel free to suggest moving the variable to the struct comedi_device struct.
  */
 struct pc236_private {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 	/* PCI device */
 	struct pci_dev *pci_dev;
 	unsigned long lcr_iobase; /* PLX PCI9052 config registers in PCIBAR1 */
@@ -168,7 +176,7 @@
  * the device code.
  */
 static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int pc236_detach(struct comedi_device *dev);
+static void pc236_detach(struct comedi_device *dev);
 static struct comedi_driver driver_amplc_pc236 = {
 	.driver_name = PC236_DRIVER_NAME,
 	.module = THIS_MODULE,
@@ -179,12 +187,12 @@
 	.num_names = ARRAY_SIZE(pc236_boards),
 };
 
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 static int __devinit driver_amplc_pc236_pci_probe(struct pci_dev *dev,
 						  const struct pci_device_id
 						  *ent)
 {
-	return comedi_pci_auto_config(dev, driver_amplc_pc236.driver_name);
+	return comedi_pci_auto_config(dev, &driver_amplc_pc236);
 }
 
 static void __devexit driver_amplc_pc236_pci_remove(struct pci_dev *dev)
@@ -234,8 +242,10 @@
 module_exit(driver_amplc_pc236_cleanup_module);
 #endif
 
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
 static int pc236_request_region(unsigned minor, unsigned long from,
 				unsigned long extent);
+#endif
 static void pc236_intr_disable(struct comedi_device *dev);
 static void pc236_intr_enable(struct comedi_device *dev);
 static int pc236_intr_check(struct comedi_device *dev);
@@ -255,7 +265,7 @@
  * This function looks for a PCI device matching the requested board name,
  * bus and slot.
  */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 static int
 pc236_find_pci(struct comedi_device *dev, int bus, int slot,
 	       struct pci_dev **pci_dev_p)
@@ -324,7 +334,7 @@
 	struct comedi_subdevice *s;
 	unsigned long iobase = 0;
 	unsigned int irq = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 	struct pci_dev *pci_dev = NULL;
 	int bus = 0, slot = 0;
 #endif
@@ -345,12 +355,14 @@
 	}
 	/* Process options. */
 	switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
 	case isa_bustype:
 		iobase = it->options[0];
 		irq = it->options[1];
 		share_irq = 0;
 		break;
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 	case pci_bustype:
 		bus = it->options[0];
 		slot = it->options[1];
@@ -361,7 +373,7 @@
 			return ret;
 		devpriv->pci_dev = pci_dev;
 		break;
-#endif /* CONFIG_COMEDI_PCI */
+#endif
 	default:
 		printk(KERN_ERR
 		       "comedi%d: %s: BUG! cannot determine board type!\n",
@@ -376,7 +388,7 @@
 	dev->board_name = thisboard->name;
 
 	/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 	if (pci_dev) {
 
 		ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME);
@@ -392,9 +404,11 @@
 	} else
 #endif
 	{
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
 		ret = pc236_request_region(dev->minor, iobase, PC236_IO_SIZE);
 		if (ret < 0)
 			return ret;
+#endif
 	}
 	dev->iobase = iobase;
 
@@ -439,12 +453,19 @@
 		}
 	}
 	printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
-	if (thisboard->bustype == isa_bustype) {
+	switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
+	case isa_bustype:
 		printk("(base %#lx) ", iobase);
-	} else {
-#ifdef CONFIG_COMEDI_PCI
-		printk("(pci %s) ", pci_name(pci_dev));
+		break;
 #endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
+	case pci_bustype:
+		printk("(pci %s) ", pci_name(pci_dev));
+		break;
+#endif
+	default:
+		break;
 	}
 	if (irq)
 		printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
@@ -456,27 +477,16 @@
 	return 1;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pc236_detach(struct comedi_device *dev)
+static void pc236_detach(struct comedi_device *dev)
 {
-	printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
-	       PC236_DRIVER_NAME);
 	if (devpriv)
 		pc236_intr_disable(dev);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 0);
 	if (devpriv) {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 		if (devpriv->pci_dev) {
 			if (dev->iobase)
 				comedi_pci_disable(devpriv->pci_dev);
@@ -484,21 +494,19 @@
 		} else
 #endif
 		{
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
 			if (dev->iobase)
 				release_region(dev->iobase, PC236_IO_SIZE);
+#endif
 		}
 	}
-	if (dev->board_name) {
-		printk(KERN_INFO "comedi%d: %s removed\n",
-		       dev->minor, dev->board_name);
-	}
-	return 0;
 }
 
 /*
  * This function checks and requests an I/O region, reporting an error
  * if there is a conflict.
  */
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
 static int pc236_request_region(unsigned minor, unsigned long from,
 				unsigned long extent)
 {
@@ -509,6 +517,7 @@
 	}
 	return 0;
 }
+#endif
 
 /*
  * This function is called to mark the interrupt as disabled (no command
@@ -521,7 +530,7 @@
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 	devpriv->enable_irq = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 	if (devpriv->lcr_iobase)
 		outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
 #endif
@@ -539,7 +548,7 @@
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 	devpriv->enable_irq = 1;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 	if (devpriv->lcr_iobase)
 		outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
 #endif
@@ -561,7 +570,7 @@
 	spin_lock_irqsave(&dev->spinlock, flags);
 	if (devpriv->enable_irq) {
 		retval = 1;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 		if (devpriv->lcr_iobase) {
 			if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR)
 			     & PLX9052_INTCSR_LI1STAT_MASK)
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 191ac0d..974d745 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -50,6 +50,14 @@
 
 #define PC263_DRIVER_NAME	"amplc_pc263"
 
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA_MODULE
+#define CONFIG_COMEDI_AMPLC_PC263_ISA
+#endif
+
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI_MODULE
+#define CONFIG_COMEDI_AMPLC_PC263_PCI
+#endif
+
 /* PCI263 PCI configuration register information */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
@@ -73,13 +81,15 @@
 	enum pc263_model model;
 };
 static const struct pc263_board pc263_boards[] = {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
 	{
 	 .name = "pc263",
 	 .fancy_name = "PC263",
 	 .bustype = isa_bustype,
 	 .model = pc263_model,
 	 },
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 	{
 	 .name = "pci263",
 	 .fancy_name = "PCI263",
@@ -87,8 +97,6 @@
 	 .bustype = pci_bustype,
 	 .model = pci263_model,
 	 },
-#endif
-#ifdef CONFIG_COMEDI_PCI
 	{
 	 .name = PC263_DRIVER_NAME,
 	 .fancy_name = PC263_DRIVER_NAME,
@@ -99,14 +107,14 @@
 #endif
 };
 
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
 	{0}
 };
 
 MODULE_DEVICE_TABLE(pci, pc263_pci_table);
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */
 
 /*
  * Useful for shorthand access to the particular board structure
@@ -117,14 +125,14 @@
    several hardware drivers keep similar information in this structure,
    feel free to suggest moving the variable to the struct comedi_device struct.
 */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 struct pc263_private {
 	/* PCI device. */
 	struct pci_dev *pci_dev;
 };
 
 #define devpriv ((struct pc263_private *)dev->private)
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */
 
 /*
  * The struct comedi_driver structure tells the Comedi core module
@@ -133,7 +141,7 @@
  * the device code.
  */
 static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int pc263_detach(struct comedi_device *dev);
+static void pc263_detach(struct comedi_device *dev);
 static struct comedi_driver driver_amplc_pc263 = {
 	.driver_name = PC263_DRIVER_NAME,
 	.module = THIS_MODULE,
@@ -144,8 +152,10 @@
 	.num_names = ARRAY_SIZE(pc263_boards),
 };
 
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
 static int pc263_request_region(unsigned minor, unsigned long from,
 				unsigned long extent);
+#endif
 static int pc263_dio_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data);
@@ -157,7 +167,7 @@
  * This function looks for a PCI device matching the requested board name,
  * bus and slot.
  */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 static int
 pc263_find_pci(struct comedi_device *dev, int bus, int slot,
 	       struct pci_dev **pci_dev_p)
@@ -225,7 +235,7 @@
 {
 	struct comedi_subdevice *s;
 	unsigned long iobase = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 	struct pci_dev *pci_dev = NULL;
 	int bus = 0, slot = 0;
 #endif
@@ -237,7 +247,7 @@
  * Allocate the private structure area.  alloc_private() is a
  * convenient macro defined in comedidev.h.
  */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 	ret = alloc_private(dev, sizeof(struct pc263_private));
 	if (ret < 0) {
 		printk(KERN_ERR "comedi%d: error! out of memory!\n",
@@ -247,10 +257,12 @@
 #endif
 	/* Process options. */
 	switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
 	case isa_bustype:
 		iobase = it->options[0];
 		break;
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 	case pci_bustype:
 		bus = it->options[0];
 		slot = it->options[1];
@@ -260,7 +272,7 @@
 			return ret;
 		devpriv->pci_dev = pci_dev;
 		break;
-#endif /* CONFIG_COMEDI_PCI */
+#endif
 	default:
 		printk(KERN_ERR
 		       "comedi%d: %s: BUG! cannot determine board type!\n",
@@ -275,7 +287,7 @@
 	dev->board_name = thisboard->name;
 
 	/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 	if (pci_dev) {
 		ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
 		if (ret < 0) {
@@ -289,9 +301,11 @@
 	} else
 #endif
 	{
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
 		ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE);
 		if (ret < 0)
 			return ret;
+#endif
 	}
 	dev->iobase = iobase;
 
@@ -322,12 +336,18 @@
 	s->state = s->state | (inb(dev->iobase) << 8);
 
 	printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
-	if (thisboard->bustype == isa_bustype) {
+	switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
+	case isa_bustype:
 		printk("(base %#lx) ", iobase);
-	} else {
-#ifdef CONFIG_COMEDI_PCI
-		printk("(pci %s) ", pci_name(pci_dev));
+		break;
 #endif
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
+		printk("(pci %s) ", pci_name(pci_dev));
+		break;
+#endif
+	default:
+		break;
 	}
 
 	printk("attached\n");
@@ -335,23 +355,13 @@
 	return 1;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pc263_detach(struct comedi_device *dev)
+static void pc263_detach(struct comedi_device *dev)
 {
-	printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
-	       PC263_DRIVER_NAME);
-
-#ifdef CONFIG_COMEDI_PCI
-	if (devpriv) {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
+	if (devpriv)
 #endif
-#ifdef CONFIG_COMEDI_PCI
+	{
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 		if (devpriv->pci_dev) {
 			if (dev->iobase)
 				comedi_pci_disable(devpriv->pci_dev);
@@ -359,21 +369,19 @@
 		} else
 #endif
 		{
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
 			if (dev->iobase)
 				release_region(dev->iobase, PC263_IO_SIZE);
+#endif
 		}
 	}
-	if (dev->board_name) {
-		printk(KERN_INFO "comedi%d: %s removed\n",
-		       dev->minor, dev->board_name);
-	}
-	return 0;
 }
 
 /*
  * This function checks and requests an I/O region, reporting an error
  * if there is a conflict.
  */
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
 static int pc263_request_region(unsigned minor, unsigned long from,
 				unsigned long extent)
 {
@@ -384,6 +392,7 @@
 	}
 	return 0;
 }
+#endif
 
 /* DIO devices are slightly special.  Although it is possible to
  * implement the insn_read/insn_write interface, it is much more
@@ -429,12 +438,12 @@
  * A convenient macro that defines init_module() and cleanup_module(),
  * as necessary.
  */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 static int __devinit driver_amplc_pc263_pci_probe(struct pci_dev *dev,
 						  const struct pci_device_id
 						  *ent)
 {
-	return comedi_pci_auto_config(dev, driver_amplc_pc263.driver_name);
+	return comedi_pci_auto_config(dev, &driver_amplc_pc263);
 }
 
 static void __devexit driver_amplc_pc263_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index b278917c..fbf19ca 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -380,18 +380,6 @@
 };
 
 /*
- * PCI driver table.
- */
-
-static DEFINE_PCI_DEVICE_TABLE(pci224_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, pci224_pci_table);
-
-/*
  * Useful for shorthand access to the particular board structure
  */
 #define thisboard ((struct pci224_board *)dev->board_ptr)
@@ -422,65 +410,6 @@
 #define devpriv ((struct pci224_private *)dev->private)
 
 /*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pci224_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pci224_detach(struct comedi_device *dev);
-static struct comedi_driver driver_amplc_pci224 = {
-	.driver_name = DRIVER_NAME,
-	.module = THIS_MODULE,
-	.attach = pci224_attach,
-	.detach = pci224_detach,
-	.board_name = &pci224_boards[0].name,
-	.offset = sizeof(struct pci224_board),
-	.num_names = ARRAY_SIZE(pci224_boards),
-};
-
-static int __devinit driver_amplc_pci224_pci_probe(struct pci_dev *dev,
-						   const struct pci_device_id
-						   *ent)
-{
-	return comedi_pci_auto_config(dev, driver_amplc_pci224.driver_name);
-}
-
-static void __devexit driver_amplc_pci224_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_amplc_pci224_pci_driver = {
-	.id_table = pci224_pci_table,
-	.probe = &driver_amplc_pci224_pci_probe,
-	.remove = __devexit_p(&driver_amplc_pci224_pci_remove)
-};
-
-static int __init driver_amplc_pci224_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_amplc_pci224);
-	if (retval < 0)
-		return retval;
-
-	driver_amplc_pci224_pci_driver.name =
-	    (char *)driver_amplc_pci224.driver_name;
-	return pci_register_driver(&driver_amplc_pci224_pci_driver);
-}
-
-static void __exit driver_amplc_pci224_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_amplc_pci224_pci_driver);
-	comedi_driver_unregister(&driver_amplc_pci224);
-}
-
-module_init(driver_amplc_pci224_init_module);
-module_exit(driver_amplc_pci224_cleanup_module);
-
-/*
  * Called from the 'insn_write' function to perform a single write.
  */
 static void
@@ -1312,6 +1241,20 @@
 }
 
 /*
+ * This function looks for a board matching the supplied PCI device.
+ */
+static const struct pci224_board
+*pci224_find_pci_board(struct pci_dev *pci_dev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pci224_boards); i++)
+		if (pci_dev->device == pci224_boards[i].devid)
+			return &pci224_boards[i];
+	return NULL;
+}
+
+/*
  * This function looks for a PCI device matching the requested board name,
  * bus and slot.
  */
@@ -1336,17 +1279,12 @@
 		}
 		if (thisboard->model == any_model) {
 			/* Match any supported model. */
-			int i;
-
-			for (i = 0; i < ARRAY_SIZE(pci224_boards); i++) {
-				if (pci_dev->device == pci224_boards[i].devid) {
-					/* Change board_ptr to matched board. */
-					dev->board_ptr = &pci224_boards[i];
-					break;
-				}
-			}
-			if (i == ARRAY_SIZE(pci224_boards))
+			const struct pci224_board *board_ptr;
+			board_ptr = pci224_find_pci_board(pci_dev);
+			if (board_ptr == NULL)
 				continue;
+			/* Change board_ptr to matched board. */
+			dev->board_ptr = board_ptr;
 		} else {
 			/* Match specific model name. */
 			if (thisboard->devid != pci_dev->device)
@@ -1370,35 +1308,16 @@
 }
 
 /*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
+ * Common part of attach and attach_pci.
  */
-static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int pci224_attach_common(struct comedi_device *dev,
+				struct pci_dev *pci_dev, int *options)
 {
 	struct comedi_subdevice *s;
-	struct pci_dev *pci_dev;
 	unsigned int irq;
-	int bus = 0, slot = 0;
 	unsigned n;
 	int ret;
 
-	printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME);
-
-	bus = it->options[0];
-	slot = it->options[1];
-	ret = alloc_private(dev, sizeof(struct pci224_private));
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
-		return ret;
-	}
-
-	ret = pci224_find_pci(dev, bus, slot, &pci_dev);
-	if (ret < 0)
-		return ret;
-
 	devpriv->pci_dev = pci_dev;
 	ret = comedi_pci_enable(pci_dev, DRIVER_NAME);
 	if (ret < 0) {
@@ -1483,24 +1402,26 @@
 		if (!s->range_table_list)
 			return -ENOMEM;
 
-		for (n = 2; n < 3 + s->n_chan; n++) {
-			if (it->options[n] < 0 || it->options[n] > 1) {
-				printk(KERN_WARNING "comedi%d: %s: warning! "
-				       "bad options[%u]=%d\n",
-				       dev->minor, DRIVER_NAME, n,
-				       it->options[n]);
+		if (options) {
+			for (n = 2; n < 3 + s->n_chan; n++) {
+				if (options[n] < 0 || options[n] > 1) {
+					printk(KERN_WARNING
+					       "comedi%d: %s: warning! bad options[%u]=%d\n",
+					       dev->minor, DRIVER_NAME, n,
+					       options[n]);
+				}
 			}
 		}
 		for (n = 0; n < s->n_chan; n++) {
-			if (n < COMEDI_NDEVCONFOPTS - 3 &&
-			    it->options[3 + n] == 1) {
-				if (it->options[2] == 1)
+			if (n < COMEDI_NDEVCONFOPTS - 3 && options &&
+			    options[3 + n] == 1) {
+				if (options[2] == 1)
 					range_table_list[n] = &range_pci234_ext;
 				else
 					range_table_list[n] = &range_bipolar5;
 
 			} else {
-				if (it->options[2] == 1) {
+				if (options && options[2] == 1) {
 					range_table_list[n] =
 					    &range_pci234_ext2;
 				} else {
@@ -1511,14 +1432,14 @@
 		devpriv->hwrange = hwrange_pci234;
 	} else {
 		/* PCI224 range options. */
-		if (it->options[2] == 1) {
+		if (options && options[2] == 1) {
 			s->range_table = &range_pci224_external;
 			devpriv->hwrange = hwrange_pci224_external;
 		} else {
-			if (it->options[2] != 0) {
+			if (options && options[2] != 0) {
 				printk(KERN_WARNING "comedi%d: %s: warning! "
 				       "bad options[2]=%d\n",
-				       dev->minor, DRIVER_NAME, it->options[2]);
+				       dev->minor, DRIVER_NAME, options[2]);
 			}
 			s->range_table = &range_pci224_internal;
 			devpriv->hwrange = hwrange_pci224_internal;
@@ -1552,21 +1473,59 @@
 	return 1;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci224_detach(struct comedi_device *dev)
+static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, DRIVER_NAME);
+	struct pci_dev *pci_dev;
+	int bus, slot;
+	int ret;
 
+	printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME);
+
+	bus = it->options[0];
+	slot = it->options[1];
+	ret = alloc_private(dev, sizeof(struct pci224_private));
+	if (ret < 0) {
+		printk(KERN_ERR "comedi%d: error! out of memory!\n",
+		       dev->minor);
+		return ret;
+	}
+
+	ret = pci224_find_pci(dev, bus, slot, &pci_dev);
+	if (ret < 0)
+		return ret;
+
+	return pci224_attach_common(dev, pci_dev, it->options);
+}
+
+static int
+pci224_attach_pci(struct comedi_device *dev, struct pci_dev *pci_dev)
+{
+	int ret;
+
+	printk(KERN_DEBUG "comedi%d: %s: attach_pci %s\n", dev->minor,
+	       DRIVER_NAME, pci_name(pci_dev));
+
+	ret = alloc_private(dev, sizeof(struct pci224_private));
+	if (ret < 0) {
+		printk(KERN_ERR "comedi%d: error! out of memory!\n",
+		       dev->minor);
+		return ret;
+	}
+
+	dev->board_ptr = pci224_find_pci_board(pci_dev);
+	if (dev->board_ptr == NULL) {
+		printk(KERN_ERR
+		       "comedi%d: %s: BUG! cannot determine board type!\n",
+		       dev->minor, DRIVER_NAME);
+		return -EINVAL;
+	}
+	return pci224_attach_common(dev, pci_dev, NULL);
+}
+
+static void pci224_detach(struct comedi_device *dev)
+{
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (dev->subdevices) {
 		struct comedi_subdevice *s;
 
@@ -1581,18 +1540,49 @@
 		if (devpriv->pci_dev) {
 			if (dev->iobase)
 				comedi_pci_disable(devpriv->pci_dev);
-
 			pci_dev_put(devpriv->pci_dev);
 		}
 	}
-	if (dev->board_name) {
-		printk(KERN_INFO "comedi%d: %s removed\n",
-		       dev->minor, dev->board_name);
-	}
-
-	return 0;
 }
 
+static struct comedi_driver amplc_pci224_driver = {
+	.driver_name	= "amplc_pci224",
+	.module		= THIS_MODULE,
+	.attach		= pci224_attach,
+	.detach		= pci224_detach,
+	.attach_pci	= pci224_attach_pci,
+	.board_name	= &pci224_boards[0].name,
+	.offset		= sizeof(struct pci224_board),
+	.num_names	= ARRAY_SIZE(pci224_boards),
+};
+
+static int __devinit amplc_pci224_pci_probe(struct pci_dev *dev,
+						   const struct pci_device_id
+						   *ent)
+{
+	return comedi_pci_auto_config(dev, &amplc_pci224_driver);
+}
+
+static void __devexit amplc_pci224_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(amplc_pci224_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table);
+
+static struct pci_driver amplc_pci224_pci_driver = {
+	.name		= "amplc_pci224",
+	.id_table	= amplc_pci224_pci_table,
+	.probe		= amplc_pci224_pci_probe,
+	.remove		= __devexit_p(amplc_pci224_pci_remove),
+};
+module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 5389795..d4c80b1 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -500,13 +500,6 @@
 	 },
 };
 
-static DEFINE_PCI_DEVICE_TABLE(pci230_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, pci230_pci_table);
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -595,65 +588,6 @@
 /* PCI230 daccon bipolar flag for each analogue output range. */
 static const unsigned char pci230_ao_bipolar[2] = { 0, 1 };
 
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pci230_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pci230_detach(struct comedi_device *dev);
-static struct comedi_driver driver_amplc_pci230 = {
-	.driver_name = "amplc_pci230",
-	.module = THIS_MODULE,
-	.attach = pci230_attach,
-	.detach = pci230_detach,
-	.board_name = &pci230_boards[0].name,
-	.offset = sizeof(pci230_boards[0]),
-	.num_names = ARRAY_SIZE(pci230_boards),
-};
-
-static int __devinit driver_amplc_pci230_pci_probe(struct pci_dev *dev,
-						   const struct pci_device_id
-						   *ent)
-{
-	return comedi_pci_auto_config(dev, driver_amplc_pci230.driver_name);
-}
-
-static void __devexit driver_amplc_pci230_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_amplc_pci230_pci_driver = {
-	.id_table = pci230_pci_table,
-	.probe = &driver_amplc_pci230_pci_probe,
-	.remove = __devexit_p(&driver_amplc_pci230_pci_remove)
-};
-
-static int __init driver_amplc_pci230_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_amplc_pci230);
-	if (retval < 0)
-		return retval;
-
-	driver_amplc_pci230_pci_driver.name =
-	    (char *)driver_amplc_pci230.driver_name;
-	return pci_register_driver(&driver_amplc_pci230_pci_driver);
-}
-
-static void __exit driver_amplc_pci230_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_amplc_pci230_pci_driver);
-	comedi_driver_unregister(&driver_amplc_pci230);
-}
-
-module_init(driver_amplc_pci230_init_module);
-module_exit(driver_amplc_pci230_cleanup_module);
-
 static int pci230_ai_rinsn(struct comedi_device *dev,
 			   struct comedi_subdevice *s, struct comedi_insn *insn,
 			   unsigned int *data);
@@ -1003,35 +937,19 @@
 	return 1;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci230_detach(struct comedi_device *dev)
+static void pci230_detach(struct comedi_device *dev)
 {
-	printk("comedi%d: amplc_pci230: remove\n", dev->minor);
-
 	if (dev->subdevices && thisboard->have_dio)
-		/* Clean up dio subdevice. */
 		subdev_8255_cleanup(dev, dev->subdevices + 2);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (devpriv) {
 		if (devpriv->pci_dev) {
 			if (dev->iobase)
 				comedi_pci_disable(devpriv->pci_dev);
-
 			pci_dev_put(devpriv->pci_dev);
 		}
 	}
-
-	return 0;
 }
 
 static int get_resources(struct comedi_device *dev, unsigned int res_mask,
@@ -3048,6 +2966,42 @@
 	return 0;
 }
 
+static struct comedi_driver amplc_pci230_driver = {
+	.driver_name	= "amplc_pci230",
+	.module		= THIS_MODULE,
+	.attach		= pci230_attach,
+	.detach		= pci230_detach,
+	.board_name	= &pci230_boards[0].name,
+	.offset		= sizeof(pci230_boards[0]),
+	.num_names	= ARRAY_SIZE(pci230_boards),
+};
+
+static int __devinit amplc_pci230_pci_probe(struct pci_dev *dev,
+					    const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &amplc_pci230_driver);
+}
+
+static void __devexit amplc_pci230_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(amplc_pci230_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, amplc_pci230_pci_table);
+
+static struct pci_driver amplc_pci230_pci_driver = {
+	.name		= "amplc_pci230",
+	.id_table	= amplc_pci230_pci_table,
+	.probe		= amplc_pci230_pci_probe,
+	.remove		= __devexit_p(amplc_pci230_pci_remove)
+};
+module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 11cdaf2..fb9951a 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -97,16 +97,6 @@
 
 #define C6XDIGIO_TIME_OUT 20
 
-static int c6xdigio_attach(struct comedi_device *dev,
-			   struct comedi_devconfig *it);
-static int c6xdigio_detach(struct comedi_device *dev);
-struct comedi_driver driver_c6xdigio = {
-	.driver_name = "c6xdigio",
-	.module = THIS_MODULE,
-	.attach = c6xdigio_attach,
-	.detach = c6xdigio_detach,
-};
-
 static void C6X_pwmInit(unsigned long baseAddr)
 {
 	int timeout = 0;
@@ -407,10 +397,6 @@
 
 }
 
-/* static void board_halt(struct comedi_device *dev) { */
-/* C6X_pwmInit(dev->iobase); */
-/* } */
-
 /*
    options[0] - I/O port
    options[1] - irq
@@ -500,36 +486,22 @@
 	return 0;
 }
 
-static int c6xdigio_detach(struct comedi_device *dev)
+static void c6xdigio_detach(struct comedi_device *dev)
 {
-	/* board_halt(dev);  may not need this */
-
-	printk(KERN_DEBUG "comedi%d: c6xdigio: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, C6XDIGIO_SIZE);
-
-	/*  Not using IRQ so I am not sure if I need this */
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	pnp_unregister_driver(&c6xdigio_pnp_driver);
-
-	return 0;
 }
 
-static int __init driver_c6xdigio_init_module(void)
-{
-	return comedi_driver_register(&driver_c6xdigio);
-}
-
-static void __exit driver_c6xdigio_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_c6xdigio);
-}
-
-module_init(driver_c6xdigio_init_module);
-module_exit(driver_c6xdigio_cleanup_module);
+static struct comedi_driver c6xdigio_driver = {
+	.driver_name	= "c6xdigio",
+	.module		= THIS_MODULE,
+	.attach		= c6xdigio_attach,
+	.detach		= c6xdigio_detach,
+};
+module_comedi_driver(c6xdigio_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 49404f4..3515923 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -91,7 +91,7 @@
 
 static int das16cs_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it);
-static int das16cs_detach(struct comedi_device *dev);
+static void das16cs_detach(struct comedi_device *dev);
 static struct comedi_driver driver_das16cs = {
 	.driver_name = "cb_das16_cs",
 	.module = THIS_MODULE,
@@ -255,15 +255,10 @@
 	return 1;
 }
 
-static int das16cs_detach(struct comedi_device *dev)
+static void das16cs_detach(struct comedi_device *dev)
 {
-	dev_dbg(dev->hw_dev, "comedi%d: das16cs: remove\n", dev->minor);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
-
-	return 0;
 }
 
 static irqreturn_t das16cs_interrupt(int irq, void *d)
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 7e4ffcf..ee9e084b 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -405,20 +405,6 @@
 	 },
 };
 
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
-
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -462,22 +448,6 @@
  */
 #define devpriv ((struct cb_pcidas_private *)dev->private)
 
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int cb_pcidas_attach(struct comedi_device *dev,
-			    struct comedi_devconfig *it);
-static int cb_pcidas_detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcidas = {
-	.driver_name = "cb_pcidas",
-	.module = THIS_MODULE,
-	.attach = cb_pcidas_attach,
-	.detach = cb_pcidas_detach,
-};
-
 static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data);
@@ -756,26 +726,12 @@
 	return 1;
 }
 
-/*
- * cb_pcidas_detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int cb_pcidas_detach(struct comedi_device *dev)
+static void cb_pcidas_detach(struct comedi_device *dev)
 {
-
 	if (devpriv) {
 		if (devpriv->s5933_config) {
-			/*  disable and clear interrupts on amcc s5933 */
 			outl(INTCSR_INBOX_INTR_STATUS,
 			     devpriv->s5933_config + AMCC_OP_REG_INTCSR);
-#ifdef CB_PCIDAS_DEBUG
-			dev_dbg(dev->hw_dev, "detaching, incsr is 0x%x\n",
-				inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR));
-#endif
 		}
 	}
 	if (dev->irq)
@@ -787,8 +743,6 @@
 			comedi_pci_disable(devpriv->pci_dev);
 		pci_dev_put(devpriv->pci_dev);
 	}
-
-	return 0;
 }
 
 /*
@@ -1918,47 +1872,44 @@
 	return 0;
 }
 
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev,
-						const struct pci_device_id *ent)
+static struct comedi_driver cb_pcidas_driver = {
+	.driver_name	= "cb_pcidas",
+	.module		= THIS_MODULE,
+	.attach		= cb_pcidas_attach,
+	.detach		= cb_pcidas_detach,
+};
+
+static int __devinit cb_pcidas_pci_probe(struct pci_dev *dev,
+					 const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name);
+	return comedi_pci_auto_config(dev, &cb_pcidas_driver);
 }
 
-static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcidas_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_cb_pcidas_pci_driver = {
-	.id_table = cb_pcidas_pci_table,
-	.probe = &driver_cb_pcidas_pci_probe,
-	.remove = __devexit_p(&driver_cb_pcidas_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
 
-static int __init driver_cb_pcidas_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_cb_pcidas);
-	if (retval < 0)
-		return retval;
-
-	driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name;
-	return pci_register_driver(&driver_cb_pcidas_pci_driver);
-}
-
-static void __exit driver_cb_pcidas_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_cb_pcidas_pci_driver);
-	comedi_driver_unregister(&driver_cb_pcidas);
-}
-
-module_init(driver_cb_pcidas_init_module);
-module_exit(driver_cb_pcidas_cleanup_module);
+static struct pci_driver cb_pcidas_pci_driver = {
+	.name		= "cb_pcidas",
+	.id_table	= cb_pcidas_pci_table,
+	.probe		= cb_pcidas_pci_probe,
+	.remove		= __devexit_p(cb_pcidas_pci_remove)
+};
+module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 915157d..9d0b875 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -1026,31 +1026,6 @@
 #endif
 };
 
-static DEFINE_PCI_DEVICE_TABLE(pcidas64_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pcidas64_pci_table);
-
 static inline struct pcidas64_board *board(const struct comedi_device *dev)
 {
 	return (struct pcidas64_board *)dev->board_ptr;
@@ -1127,21 +1102,6 @@
 	return dev->private;
 }
 
-/*
- * The comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcidas = {
-	.driver_name = "cb_pcidas64",
-	.module = THIS_MODULE,
-	.attach = attach,
-	.detach = detach,
-};
-
 static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 		    struct comedi_insn *insn, unsigned int *data);
 static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -1216,44 +1176,6 @@
 static void load_ao_dma(struct comedi_device *dev,
 			const struct comedi_cmd *cmd);
 
-static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev,
-						const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name);
-}
-
-static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_cb_pcidas_pci_driver = {
-	.id_table = pcidas64_pci_table,
-	.probe = &driver_cb_pcidas_pci_probe,
-	.remove = __devexit_p(&driver_cb_pcidas_pci_remove)
-};
-
-static int __init driver_cb_pcidas_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_cb_pcidas);
-	if (retval < 0)
-		return retval;
-
-	driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name;
-	return pci_register_driver(&driver_cb_pcidas_pci_driver);
-}
-
-static void __exit driver_cb_pcidas_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_cb_pcidas_pci_driver);
-	comedi_driver_unregister(&driver_cb_pcidas);
-}
-
-module_init(driver_cb_pcidas_init_module);
-module_exit(driver_cb_pcidas_cleanup_module);
-
 static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
 				       unsigned int range_index)
 {
@@ -1781,7 +1703,7 @@
 	dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", board(dev)->name,
 		pcidev->bus->number, PCI_SLOT(pcidev->devfn));
 
-	if (comedi_pci_enable(pcidev, driver_cb_pcidas.driver_name)) {
+	if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
 		dev_warn(dev->hw_dev, "failed to enable PCI device and request regions\n");
 		return -EIO;
 	}
@@ -1868,15 +1790,7 @@
 	return 0;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int detach(struct comedi_device *dev)
+static void detach(struct comedi_device *dev)
 {
 	unsigned int i;
 
@@ -1938,8 +1852,6 @@
 	}
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 4);
-
-	return 0;
 }
 
 static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -4315,6 +4227,56 @@
 	i2c_stop(dev);
 }
 
+static struct comedi_driver cb_pcidas64_driver = {
+	.driver_name	= "cb_pcidas64",
+	.module		= THIS_MODULE,
+	.attach		= attach,
+	.detach		= detach,
+};
+
+static int __devinit cb_pcidas64_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &cb_pcidas64_driver);
+}
+
+static void __devexit cb_pcidas64_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, cb_pcidas64_pci_table);
+
+static struct pci_driver cb_pcidas64_pci_driver = {
+	.name		= "cb_pcidas64",
+	.id_table	= cb_pcidas64_pci_table,
+	.probe		= cb_pcidas64_pci_probe,
+	.remove		= __devexit_p(cb_pcidas64_pci_remove),
+};
+module_comedi_pci_driver(cb_pcidas64_driver, cb_pcidas64_pci_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index abba220..25ebca1 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -51,9 +51,12 @@
 #include "comedi_pci.h"
 #include "8255.h"
 
-#define PCI_VENDOR_ID_CB	0x1307	/*  PCI vendor number of ComputerBoards */
+
+/* PCI vendor number of ComputerBoards */
+#define PCI_VENDOR_ID_CB        0x1307
 #define EEPROM_SIZE	128	/*  number of entries in eeprom */
-#define MAX_AO_CHANNELS 8	/*  maximum number of ao channels for supported boards */
+/* maximum number of ao channels for supported boards */
+#define MAX_AO_CHANNELS 8
 
 /* PCI-DDA base addresses */
 #define DIGITALIO_BADRINDEX	2
@@ -94,20 +97,26 @@
 
 #define DACALIBRATION1	4	/*  D/A CALIBRATION REGISTER 1 */
 /* write bits */
-#define	SERIAL_IN_BIT	0x1	/*  serial data input for eeprom, caldacs, reference dac */
+/* serial data input for eeprom, caldacs, reference dac */
+#define SERIAL_IN_BIT   0x1
 #define	CAL_CHANNEL_MASK	(0x7 << 1)
 #define	CAL_CHANNEL_BITS(channel)	(((channel) << 1) & CAL_CHANNEL_MASK)
 /* read bits */
 #define	CAL_COUNTER_MASK	0x1f
-#define	CAL_COUNTER_OVERFLOW_BIT	0x20	/*  calibration counter overflow status bit */
-#define	AO_BELOW_REF_BIT	0x40	/*  analog output is less than reference dac voltage */
+/* calibration counter overflow status bit */
+#define CAL_COUNTER_OVERFLOW_BIT        0x20
+/* analog output is less than reference dac voltage */
+#define AO_BELOW_REF_BIT        0x40
 #define	SERIAL_OUT_BIT	0x80	/*  serial data out, for reading from eeprom */
 
 #define DACALIBRATION2	6	/*  D/A CALIBRATION REGISTER 2 */
 #define	SELECT_EEPROM_BIT	0x1	/*  send serial data in to eeprom */
-#define	DESELECT_REF_DAC_BIT	0x2	/*  don't send serial data to MAX542 reference dac */
-#define	DESELECT_CALDAC_BIT(n)	(0x4 << (n))	/*  don't send serial data to caldac n */
-#define	DUMMY_BIT	0x40	/*  manual says to set this bit with no explanation */
+/* don't send serial data to MAX542 reference dac */
+#define DESELECT_REF_DAC_BIT    0x2
+/* don't send serial data to caldac n */
+#define DESELECT_CALDAC_BIT(n)  (0x4 << (n))
+/* manual says to set this bit with no explanation */
+#define DUMMY_BIT       0x40
 
 #define DADATA	8		/*  FIRST D/A DATA REGISTER (0) */
 
@@ -195,26 +204,17 @@
 	 },
 };
 
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0020) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0021) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0022) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0023) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0024) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0025) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
-
 /*
  * Useful for shorthand access to the particular board structure
  */
 #define thisboard ((const struct cb_pcidda_board *)dev->board_ptr)
 
-/* this structure is for data unique to this hardware driver.  If
-   several hardware drivers keep similar information in this structure,
-   feel free to suggest moving the variable to the struct comedi_device struct.  */
+/*
+ * this structure is for data unique to this hardware driver.  If
+ * several hardware drivers keep similar information in this structure,
+ * feel free to suggest moving the variable to the struct comedi_device
+ * struct.
+ */
 struct cb_pcidda_private {
 	int data;
 
@@ -227,8 +227,10 @@
 	/* unsigned long control_status; */
 	/* unsigned long adc_fifo; */
 
-	unsigned int dac_cal1_bits;	/*  bits last written to da calibration register 1 */
-	unsigned int ao_range[MAX_AO_CHANNELS];	/*  current range settings for output channels */
+	/* bits last written to da calibration register 1 */
+	unsigned int dac_cal1_bits;
+	/* current range settings for output channels */
+	unsigned int ao_range[MAX_AO_CHANNELS];
 	u16 eeprom_data[EEPROM_SIZE];	/*  software copy of board's eeprom */
 };
 
@@ -238,9 +240,6 @@
  */
 #define devpriv ((struct cb_pcidda_private *)dev->private)
 
-static int cb_pcidda_attach(struct comedi_device *dev,
-			    struct comedi_devconfig *it);
-static int cb_pcidda_detach(struct comedi_device *dev);
 /* static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */
 static int cb_pcidda_ao_winsn(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
@@ -259,19 +258,6 @@
 				unsigned int range);
 
 /*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static struct comedi_driver driver_cb_pcidda = {
-	.driver_name = "cb_pcidda",
-	.module = THIS_MODULE,
-	.attach = cb_pcidda_attach,
-	.detach = cb_pcidda_detach,
-};
-
-/*
  * Attach is called by the Comedi core to configure the driver
  * for a particular board.
  */
@@ -377,7 +363,8 @@
 	dev_dbg(dev->hw_dev, "eeprom:\n");
 	for (index = 0; index < EEPROM_SIZE; index++) {
 		devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);
-		dev_dbg(dev->hw_dev, "%i:0x%x\n", index, devpriv->eeprom_data[index]);
+		dev_dbg(dev->hw_dev, "%i:0x%x\n", index,
+			devpriv->eeprom_data[index]);
 	}
 
 	/*  set calibrations dacs */
@@ -387,19 +374,8 @@
 	return 1;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int cb_pcidda_detach(struct comedi_device *dev)
+static void cb_pcidda_detach(struct comedi_device *dev)
 {
-/*
- * Deallocate the I/O ports.
- */
 	if (devpriv) {
 		if (devpriv->pci_dev) {
 			if (devpriv->dac)
@@ -407,13 +383,10 @@
 			pci_dev_put(devpriv->pci_dev);
 		}
 	}
-	/*  cleanup 8255 */
 	if (dev->subdevices) {
 		subdev_8255_cleanup(dev, dev->subdevices + 1);
 		subdev_8255_cleanup(dev, dev->subdevices + 2);
 	}
-
-	return 0;
 }
 
 /*
@@ -484,7 +457,10 @@
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/*
+	 * step 2: make sure trigger sources are unique and mutually
+	 * compatible
+	 */
 
 	/* note that mutual compatibility is not an issue here */
 	if (cmd->scan_begin_src != TRIG_TIMER
@@ -696,8 +672,10 @@
 	unsigned int i;
 	unsigned int cal2_bits;
 	unsigned int value;
-	const int max_num_caldacs = 4;	/*  one caldac for every two dac channels */
-	const int read_instruction = 0x6;	/*  bits to send to tell eeprom we want to read */
+	/* one caldac for every two dac channels */
+	const int max_num_caldacs = 4;
+	/* bits to send to tell eeprom we want to read */
+	const int read_instruction = 0x6;
 	const int instruction_length = 3;
 	const int address_length = 8;
 
@@ -729,9 +707,11 @@
 {
 	unsigned int cal2_bits;
 	unsigned int i;
-	const int num_channel_bits = 3;	/*  caldacs use 3 bit channel specification */
+	/* caldacs use 3 bit channel specification */
+	const int num_channel_bits = 3;
 	const int num_caldac_bits = 8;	/*  8 bit calibration dacs */
-	const int max_num_caldacs = 4;	/*  one caldac for every two dac channels */
+	/* one caldac for every two dac channels */
+	const int max_num_caldacs = 4;
 
 	/* write 3 bit channel */
 	cb_pcidda_serial_out(dev, channel, num_channel_bits);
@@ -790,14 +770,20 @@
 	return 0x7 + 2 * range + 12 * ao_channel;
 }
 
-/* returns eeprom address that provides gain calibration for given ao channel and range */
+/*
+ * returns eeprom address that provides gain calibration for given ao
+ * channel and range
+ */
 static unsigned int gain_eeprom_address(unsigned int ao_channel,
 					unsigned int range)
 {
 	return 0x8 + 2 * range + 12 * ao_channel;
 }
 
-/* returns upper byte of eeprom entry, which gives the coarse adjustment values */
+/*
+ * returns upper byte of eeprom entry, which gives the coarse adjustment
+ * values
+ */
 static unsigned int eeprom_coarse_byte(unsigned int word)
 {
 	return (word >> 8) & 0xff;
@@ -815,7 +801,7 @@
 {
 	unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain;
 
-	/*  remember range so we can tell when we need to readjust calibration */
+	/* remember range so we can tell when we need to readjust calibration */
 	devpriv->ao_range[channel] = range;
 
 	/*  get values from eeprom data */
@@ -843,47 +829,42 @@
 			       fine_gain_channel(channel), fine_gain);
 }
 
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcidda_pci_probe(struct pci_dev *dev,
-						const struct pci_device_id *ent)
+static struct comedi_driver cb_pcidda_driver = {
+	.driver_name	= "cb_pcidda",
+	.module		= THIS_MODULE,
+	.attach		= cb_pcidda_attach,
+	.detach		= cb_pcidda_detach,
+};
+
+static int __devinit cb_pcidda_pci_probe(struct pci_dev *dev,
+					 const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_cb_pcidda.driver_name);
+	return comedi_pci_auto_config(dev, &cb_pcidda_driver);
 }
 
-static void __devexit driver_cb_pcidda_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcidda_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_cb_pcidda_pci_driver = {
-	.id_table = cb_pcidda_pci_table,
-	.probe = &driver_cb_pcidda_pci_probe,
-	.remove = __devexit_p(&driver_cb_pcidda_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0020) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0021) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0022) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0023) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0024) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0025) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
 
-static int __init driver_cb_pcidda_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_cb_pcidda);
-	if (retval < 0)
-		return retval;
-
-	driver_cb_pcidda_pci_driver.name = (char *)driver_cb_pcidda.driver_name;
-	return pci_register_driver(&driver_cb_pcidda_pci_driver);
-}
-
-static void __exit driver_cb_pcidda_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_cb_pcidda_pci_driver);
-	comedi_driver_unregister(&driver_cb_pcidda);
-}
-
-module_init(driver_cb_pcidda_init_module);
-module_exit(driver_cb_pcidda_cleanup_module);
+static struct pci_driver cb_pcidda_pci_driver = {
+	.name		= "cb_pcidda",
+	.id_table	= cb_pcidda_pci_table,
+	.probe		= cb_pcidda_pci_probe,
+	.remove		= __devexit_p(cb_pcidda_pci_remove),
+};
+module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c
index 8f32152..713132c 100644
--- a/drivers/staging/comedi/drivers/cb_pcidio.c
+++ b/drivers/staging/comedi/drivers/cb_pcidio.c
@@ -86,19 +86,6 @@
 	 },
 };
 
-/* This is used by modprobe to translate PCI IDs to drivers.  Should
- * only be used for PCI and ISA-PnP devices */
-/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
- * upstream. */
-static DEFINE_PCI_DEVICE_TABLE(pcidio_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pcidio_pci_table);
-
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -125,59 +112,6 @@
  */
 #define devpriv ((struct pcidio_private *)dev->private)
 
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcidio_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcidio_detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcidio = {
-	.driver_name = "cb_pcidio",
-	.module = THIS_MODULE,
-	.attach = pcidio_attach,
-	.detach = pcidio_detach,
-
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
-
-	/* Most drivers will support multiple types of boards by
-	 * having an array of board structures.  These were defined
-	 * in pcidio_boards[] above.  Note that the element 'name'
-	 * was first in the structure -- Comedi uses this fact to
-	 * extract the name of the board without knowing any details
-	 * about the structure except for its length.
-	 * When a device is attached (by comedi_config), the name
-	 * of the device is given to Comedi, and Comedi tries to
-	 * match it by going through the list of board names.  If
-	 * there is a match, the address of the pointer is put
-	 * into dev->board_ptr and driver->attach() is called.
-	 *
-	 * Note that these are not necessary if you can determine
-	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
-	 * devices are such boards.
-	 */
-
-/* The following fields should NOT be initialized if you are dealing
- * with PCI devices
- *
- *	.board_name = pcidio_boards,
- *	.offset = sizeof(struct pcidio_board),
- *	.num_names = sizeof(pcidio_boards) / sizeof(structpcidio_board),
- */
-
-};
-
-/*------------------------------- FUNCTIONS -----------------------------------*/
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
 static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct pci_dev *pcidev = NULL;
@@ -261,15 +195,7 @@
 	return 1;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcidio_detach(struct comedi_device *dev)
+static void pcidio_detach(struct comedi_device *dev)
 {
 	if (devpriv) {
 		if (devpriv->pci_dev) {
@@ -283,50 +209,41 @@
 		for (i = 0; i < thisboard->n_8255; i++)
 			subdev_8255_cleanup(dev, dev->subdevices + i);
 	}
-	return 0;
 }
 
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcidio_pci_probe(struct pci_dev *dev,
+static struct comedi_driver cb_pcidio_driver = {
+	.driver_name	= "cb_pcidio",
+	.module		= THIS_MODULE,
+	.attach		= pcidio_attach,
+	.detach		= pcidio_detach,
+};
+
+static int __devinit cb_pcidio_pci_probe(struct pci_dev *dev,
 						const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_cb_pcidio.driver_name);
+	return comedi_pci_auto_config(dev, &cb_pcidio_driver);
 }
 
-static void __devexit driver_cb_pcidio_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcidio_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_cb_pcidio_pci_driver = {
-	.id_table = pcidio_pci_table,
-	.probe = &driver_cb_pcidio_pci_probe,
-	.remove = __devexit_p(&driver_cb_pcidio_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidio_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, cb_pcidio_pci_table);
 
-static int __init driver_cb_pcidio_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_cb_pcidio);
-	if (retval < 0)
-		return retval;
-
-	driver_cb_pcidio_pci_driver.name = (char *)driver_cb_pcidio.driver_name;
-	return pci_register_driver(&driver_cb_pcidio_pci_driver);
-}
-
-static void __exit driver_cb_pcidio_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_cb_pcidio_pci_driver);
-	comedi_driver_unregister(&driver_cb_pcidio);
-}
-
-module_init(driver_cb_pcidio_init_module);
-module_exit(driver_cb_pcidio_cleanup_module);
+static struct pci_driver cb_pcidio_pci_driver = {
+	.name		= "cb_pcidio",
+	.id_table	= cb_pcidio_pci_table,
+	.probe		= cb_pcidio_pci_probe,
+	.remove		= __devexit_p(cb_pcidio_pci_remove),
+};
+module_comedi_pci_driver(cb_pcidio_driver, cb_pcidio_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 8ba6942..5f834d0 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -123,15 +123,6 @@
 	 },
 };
 
-/* This is used by modprobe to translate PCI IDs to drivers.  Should
- * only be used for PCI and ISA-PnP devices */
-static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
-
 #define N_BOARDS 1		/*  Max number of boards supported */
 
 /*
@@ -139,9 +130,12 @@
  */
 #define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr)
 
-/* this structure is for data unique to this hardware driver.  If
-   several hardware drivers keep similar information in this structure,
-   feel free to suggest moving the variable to the struct comedi_device struct.  */
+/*
+ * this structure is for data unique to this hardware driver.  If
+ * several hardware drivers keep similar information in this structure,
+ * feel free to suggest moving the variable to the struct comedi_device
+ * struct.
+ */
 struct cb_pcimdas_private {
 	int data;
 
@@ -172,22 +166,6 @@
  */
 #define devpriv ((struct cb_pcimdas_private *)dev->private)
 
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int cb_pcimdas_attach(struct comedi_device *dev,
-			     struct comedi_devconfig *it);
-static int cb_pcimdas_detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcimdas = {
-	.driver_name = "cb_pcimdas",
-	.module = THIS_MODULE,
-	.attach = cb_pcimdas_attach,
-	.detach = cb_pcimdas_detach,
-};
-
 static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data);
@@ -317,7 +295,8 @@
 	s->subdev_flags = SDF_WRITABLE;
 	s->n_chan = thisboard->ao_nchan;
 	s->maxdata = 1 << thisboard->ao_bits;
-	s->range_table = &range_unknown;	/* ranges are hardware settable, but not software readable. */
+	/* ranges are hardware settable, but not software readable. */
+	s->range_table = &range_unknown;
 	s->insn_write = &cb_pcimdas_ao_winsn;
 	s->insn_read = &cb_pcimdas_ao_rinsn;
 
@@ -331,29 +310,8 @@
 	return 1;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int cb_pcimdas_detach(struct comedi_device *dev)
+static void cb_pcimdas_detach(struct comedi_device *dev)
 {
-	if (devpriv) {
-		dev_dbg(dev->hw_dev, "devpriv->BADR0 = 0x%lx\n",
-			devpriv->BADR0);
-		dev_dbg(dev->hw_dev, "devpriv->BADR1 = 0x%lx\n",
-			devpriv->BADR1);
-		dev_dbg(dev->hw_dev, "devpriv->BADR2 = 0x%lx\n",
-			devpriv->BADR2);
-		dev_dbg(dev->hw_dev, "devpriv->BADR3 = 0x%lx\n",
-			devpriv->BADR3);
-		dev_dbg(dev->hw_dev, "devpriv->BADR4 = 0x%lx\n",
-			devpriv->BADR4);
-	}
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (devpriv) {
@@ -363,8 +321,6 @@
 			pci_dev_put(devpriv->pci_dev);
 		}
 	}
-
-	return 0;
 }
 
 /*
@@ -402,7 +358,10 @@
 	outb(0x01, devpriv->BADR3 + 6);	/* set bursting off, conversions on */
 	outb(0x00, devpriv->BADR3 + 7);	/* set range to 10V. UP/BP is controlled by a switch on the board */
 
-	/*  write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan. */
+	/*
+	 * write channel limits to multiplexer, set Low (bits 0-3) and
+	 * High (bits 4-7) channels to chan.
+	 */
 	chanlims = chan | (chan << 4);
 	outb(chanlims, devpriv->BADR3 + 0);
 
@@ -479,49 +438,37 @@
 	return i;
 }
 
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcimdas_pci_probe(struct pci_dev *dev,
-						 const struct pci_device_id
-						 *ent)
+static struct comedi_driver cb_pcimdas_driver = {
+	.driver_name	= "cb_pcimdas",
+	.module		= THIS_MODULE,
+	.attach		= cb_pcimdas_attach,
+	.detach		= cb_pcimdas_detach,
+};
+
+static int __devinit cb_pcimdas_pci_probe(struct pci_dev *dev,
+					  const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_cb_pcimdas.driver_name);
+	return comedi_pci_auto_config(dev, &cb_pcimdas_driver);
 }
 
-static void __devexit driver_cb_pcimdas_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcimdas_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_cb_pcimdas_pci_driver = {
-	.id_table = cb_pcimdas_pci_table,
-	.probe = &driver_cb_pcimdas_pci_probe,
-	.remove = __devexit_p(&driver_cb_pcimdas_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
 
-static int __init driver_cb_pcimdas_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_cb_pcimdas);
-	if (retval < 0)
-		return retval;
-
-	driver_cb_pcimdas_pci_driver.name =
-	    (char *)driver_cb_pcimdas.driver_name;
-	return pci_register_driver(&driver_cb_pcimdas_pci_driver);
-}
-
-static void __exit driver_cb_pcimdas_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_cb_pcimdas_pci_driver);
-	comedi_driver_unregister(&driver_cb_pcimdas);
-}
-
-module_init(driver_cb_pcimdas_init_module);
-module_exit(driver_cb_pcimdas_cleanup_module);
+static struct pci_driver cb_pcimdas_pci_driver = {
+	.name		= "cb_pcimdas",
+	.id_table	= cb_pcimdas_pci_table,
+	.probe		= cb_pcimdas_pci_probe,
+	.remove		= __devexit_p(cb_pcimdas_pci_remove),
+};
+module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 40bddfa..b339685 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -140,17 +140,6 @@
 #define REG_SZ (thisboard->reg_sz)
 #define REGS_BADRINDEX (thisboard->regs_badrindex)
 
-/* This is used by modprobe to translate PCI IDs to drivers.  Should
- * only be used for PCI and ISA-PnP devices */
-/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
- * upstream. */
-static DEFINE_PCI_DEVICE_TABLE(pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, pci_table);
-
 /*
  * this structure is for data unique to this hardware driver.  If
  * several hardware drivers keep similar information in this structure,
@@ -161,7 +150,6 @@
 	unsigned long registers;	/* set by probe */
 	unsigned long dio_registers;
 	char attached_to_8255;	/* boolean */
-	char attached_successfully;	/* boolean */
 	/* would be useful for a PCI device */
 	struct pci_dev *pci_dev;
 
@@ -177,66 +165,6 @@
  */
 #define devpriv ((struct board_private_struct *)dev->private)
 
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int detach(struct comedi_device *dev);
-static struct comedi_driver cb_pcimdda_driver = {
-	.driver_name = "cb_pcimdda",
-	.module = THIS_MODULE,
-	.attach = attach,
-	.detach = detach,
-};
-
-MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
-MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
-		   "series.  Currently only supports PCIM-DDA06-16 (which "
-		   "also happens to be the only board in this series. :) ) ");
-MODULE_LICENSE("GPL");
-static int __devinit cb_pcimdda_driver_pci_probe(struct pci_dev *dev,
-						 const struct pci_device_id
-						 *ent)
-{
-	return comedi_pci_auto_config(dev, cb_pcimdda_driver.driver_name);
-}
-
-static void __devexit cb_pcimdda_driver_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver cb_pcimdda_driver_pci_driver = {
-	.id_table = pci_table,
-	.probe = &cb_pcimdda_driver_pci_probe,
-	.remove = __devexit_p(&cb_pcimdda_driver_pci_remove)
-};
-
-static int __init cb_pcimdda_driver_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&cb_pcimdda_driver);
-	if (retval < 0)
-		return retval;
-
-	cb_pcimdda_driver_pci_driver.name =
-	    (char *)cb_pcimdda_driver.driver_name;
-	return pci_register_driver(&cb_pcimdda_driver_pci_driver);
-}
-
-static void __exit cb_pcimdda_driver_cleanup_module(void)
-{
-	pci_unregister_driver(&cb_pcimdda_driver_pci_driver);
-	comedi_driver_unregister(&cb_pcimdda_driver);
-}
-
-module_init(cb_pcimdda_driver_init_module);
-module_exit(cb_pcimdda_driver_cleanup_module);
-
 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
 		    struct comedi_insn *insn, unsigned int *data);
 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -354,44 +282,24 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	devpriv->attached_successfully = 1;
-
 	printk("attached\n");
 
 	return 1;
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int detach(struct comedi_device *dev)
+static void detach(struct comedi_device *dev)
 {
 	if (devpriv) {
-
 		if (dev->subdevices && devpriv->attached_to_8255) {
-			/* de-register us from the 8255 driver */
 			subdev_8255_cleanup(dev, dev->subdevices + 2);
 			devpriv->attached_to_8255 = 0;
 		}
-
 		if (devpriv->pci_dev) {
 			if (devpriv->registers)
 				comedi_pci_disable(devpriv->pci_dev);
 			pci_dev_put(devpriv->pci_dev);
 		}
-
-		if (devpriv->attached_successfully && thisboard)
-			printk("comedi%d: %s: detached\n", dev->minor,
-			       thisboard->name);
-
 	}
-
-	return 0;
 }
 
 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -515,3 +423,41 @@
 	       "card found at the requested position\n");
 	return -ENODEV;
 }
+
+static struct comedi_driver cb_pcimdda_driver = {
+	.driver_name	= "cb_pcimdda",
+	.module		= THIS_MODULE,
+	.attach		= attach,
+	.detach		= detach,
+};
+
+static int __devinit cb_pcimdda_pci_probe(struct pci_dev *dev,
+					  const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &cb_pcimdda_driver);
+}
+
+static void __devexit cb_pcimdda_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, cb_pcimdda_pci_table);
+
+static struct pci_driver cb_pcimdda_driver_pci_driver = {
+	.name		= "cb_pcimdda",
+	.id_table	= cb_pcimdda_pci_table,
+	.probe		= cb_pcimdda_pci_probe,
+	.remove		= __devexit_p(cb_pcimdda_pci_remove),
+};
+module_comedi_pci_driver(cb_pcimdda_driver, cb_pcimdda_driver_pci_driver);
+
+MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
+MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
+		   "series.  Currently only supports PCIM-DDA06-16 (which "
+		   "also happens to be the only board in this series. :) ) ");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index d8aefb2..29412de 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -60,7 +60,6 @@
 #define MAX_CHANS 256
 
 #define MODULE_NAME "comedi_bond"
-MODULE_LICENSE("GPL");
 #ifndef STR
 #  define STR1(x) #x
 #  define STR(x) STR1(x)
@@ -79,10 +78,6 @@
 	} while (0)
 #define WARNING(x...)  printk(KERN_WARNING MODULE_NAME ": WARNING: "x)
 #define ERROR(x...)  printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x)
-MODULE_AUTHOR("Calin A. Culianu");
-MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
-		   "devices together as one.  In the words of John Lennon: "
-		   "'And the world will live as one...'");
 
 /*
  * Board descriptions for two imaginary boards.  Describing the
@@ -93,12 +88,6 @@
 	const char *name;
 };
 
-static const struct BondingBoard bondingBoards[] = {
-	{
-	 .name = MODULE_NAME,
-	 },
-};
-
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -133,129 +122,6 @@
  */
 #define devpriv ((struct Private *)dev->private)
 
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int bonding_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int bonding_detach(struct comedi_device *dev);
-/** Build Private array of all devices.. */
-static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it);
-static void doDevUnconfig(struct comedi_device *dev);
-/* Ugly implementation of realloc that always copies memory around -- I'm lazy,
- * what can I say?  I like to do wasteful memcopies.. :) */
-static void *Realloc(const void *ptr, size_t len, size_t old_len);
-
-static struct comedi_driver driver_bonding = {
-	.driver_name = MODULE_NAME,
-	.module = THIS_MODULE,
-	.attach = bonding_attach,
-	.detach = bonding_detach,
-	/* It is not necessary to implement the following members if you are
-	 * writing a driver for a ISA PnP or PCI card */
-	/* Most drivers will support multiple types of boards by
-	 * having an array of board structures.  These were defined
-	 * in skel_boards[] above.  Note that the element 'name'
-	 * was first in the structure -- Comedi uses this fact to
-	 * extract the name of the board without knowing any details
-	 * about the structure except for its length.
-	 * When a device is attached (by comedi_config), the name
-	 * of the device is given to Comedi, and Comedi tries to
-	 * match it by going through the list of board names.  If
-	 * there is a match, the address of the pointer is put
-	 * into dev->board_ptr and driver->attach() is called.
-	 *
-	 * Note that these are not necessary if you can determine
-	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
-	 * devices are such boards.
-	 */
-	.board_name = &bondingBoards[0].name,
-	.offset = sizeof(struct BondingBoard),
-	.num_names = ARRAY_SIZE(bondingBoards),
-};
-
-static int bonding_dio_insn_bits(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data);
-static int bonding_dio_insn_config(struct comedi_device *dev,
-				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn,
-				   unsigned int *data);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int bonding_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-
-	LOG_MSG("comedi%d\n", dev->minor);
-
-	/*
-	 * Allocate the private structure area.  alloc_private() is a
-	 * convenient macro defined in comedidev.h.
-	 */
-	if (alloc_private(dev, sizeof(struct Private)) < 0)
-		return -ENOMEM;
-
-	/*
-	 * Setup our bonding from config params.. sets up our Private struct..
-	 */
-	if (!doDevConfig(dev, it))
-		return -EINVAL;
-
-	/*
-	 * Initialize dev->board_name.  Note that we can use the "thisboard"
-	 * macro now, since we just initialized it in the last line.
-	 */
-	dev->board_name = devpriv->name;
-
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 */
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
-
-	s = dev->subdevices + 0;
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = devpriv->nchans;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = bonding_dio_insn_bits;
-	s->insn_config = bonding_dio_insn_config;
-
-	LOG_MSG("attached with %u DIO channels coming from %u different "
-		"subdevices all bonded together.  "
-		"John Lennon would be proud!\n",
-		devpriv->nchans, devpriv->ndevs);
-
-	return 1;
-}
-
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int bonding_detach(struct comedi_device *dev)
-{
-	LOG_MSG("comedi%d: remove\n", dev->minor);
-	doDevUnconfig(dev);
-	return 0;
-}
-
 /* DIO devices are slightly special.  Although it is possible to
  * implement the insn_read/insn_write interface, it is much more
  * useful to applications if you implement the insn_bits interface.
@@ -466,7 +332,57 @@
 	return 1;
 }
 
-static void doDevUnconfig(struct comedi_device *dev)
+static int bonding_attach(struct comedi_device *dev,
+			  struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+
+	LOG_MSG("comedi%d\n", dev->minor);
+
+	/*
+	 * Allocate the private structure area.  alloc_private() is a
+	 * convenient macro defined in comedidev.h.
+	 */
+	if (alloc_private(dev, sizeof(struct Private)) < 0)
+		return -ENOMEM;
+
+	/*
+	 * Setup our bonding from config params.. sets up our Private struct..
+	 */
+	if (!doDevConfig(dev, it))
+		return -EINVAL;
+
+	/*
+	 * Initialize dev->board_name.  Note that we can use the "thisboard"
+	 * macro now, since we just initialized it in the last line.
+	 */
+	dev->board_name = devpriv->name;
+
+	/*
+	 * Allocate the subdevice structures.  alloc_subdevice() is a
+	 * convenient macro defined in comedidev.h.
+	 */
+	if (alloc_subdevices(dev, 1) < 0)
+		return -ENOMEM;
+
+	s = dev->subdevices + 0;
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = devpriv->nchans;
+	s->maxdata = 1;
+	s->range_table = &range_digital;
+	s->insn_bits = bonding_dio_insn_bits;
+	s->insn_config = bonding_dio_insn_config;
+
+	LOG_MSG("attached with %u DIO channels coming from %u different "
+		"subdevices all bonded together.  "
+		"John Lennon would be proud!\n",
+		devpriv->nchans, devpriv->ndevs);
+
+	return 1;
+}
+
+static void bonding_detach(struct comedi_device *dev)
 {
 	unsigned long devs_closed = 0;
 
@@ -490,15 +406,25 @@
 	}
 }
 
-static int __init init(void)
-{
-	return comedi_driver_register(&driver_bonding);
-}
+static const struct BondingBoard bondingBoards[] = {
+	{
+		.name		= "comedi_bond",
+	},
+};
 
-static void __exit cleanup(void)
-{
-	comedi_driver_unregister(&driver_bonding);
-}
+static struct comedi_driver bonding_driver = {
+	.driver_name	= "comedi_bond",
+	.module		= THIS_MODULE,
+	.attach		= bonding_attach,
+	.detach		= bonding_detach,
+	.board_name	= &bondingBoards[0].name,
+	.offset		= sizeof(struct BondingBoard),
+	.num_names	= ARRAY_SIZE(bondingBoards),
+};
+module_comedi_driver(bonding_driver);
 
-module_init(init);
-module_exit(cleanup);
+MODULE_AUTHOR("Calin A. Culianu");
+MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
+		   "devices together as one.  In the words of John Lennon: "
+		   "'And the world will live as one...'");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 21d834d..bff5dcd 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -91,29 +91,6 @@
 #define PARPORT_B 1
 #define PARPORT_C 2
 
-static int parport_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int parport_detach(struct comedi_device *dev);
-static struct comedi_driver driver_parport = {
-	.driver_name = "comedi_parport",
-	.module = THIS_MODULE,
-	.attach = parport_attach,
-	.detach = parport_detach,
-};
-
-static int __init driver_parport_init_module(void)
-{
-	return comedi_driver_register(&driver_parport);
-}
-
-static void __exit driver_parport_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_parport);
-}
-
-module_init(driver_parport_init_module);
-module_exit(driver_parport_cleanup_module);
-
 struct parport_private {
 	unsigned int a_data;
 	unsigned int c_data;
@@ -395,19 +372,22 @@
 	return 1;
 }
 
-static int parport_detach(struct comedi_device *dev)
+static void parport_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: parport: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, PARPORT_SIZE);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
-	return 0;
 }
 
+static struct comedi_driver parport_driver = {
+	.driver_name	= "comedi_parport",
+	.module		= THIS_MODULE,
+	.attach		= parport_attach,
+	.detach		= parport_detach,
+};
+module_comedi_driver(parport_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index a804742..873e374 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -67,15 +67,6 @@
 
 #define N_CHANS 8
 
-static const struct waveform_board waveform_boards[] = {
-	{
-	 .name = "comedi_test",
-	 .ai_chans = N_CHANS,
-	 .ai_bits = 16,
-	 .have_dio = 0,
-	 },
-};
-
 #define thisboard ((const struct waveform_board *)dev->board_ptr)
 
 /* Data unique to this driver */
@@ -94,54 +85,6 @@
 };
 #define devpriv ((struct waveform_private *)dev->private)
 
-static int waveform_attach(struct comedi_device *dev,
-			   struct comedi_devconfig *it);
-static int waveform_detach(struct comedi_device *dev);
-static struct comedi_driver driver_waveform = {
-	.driver_name = "comedi_test",
-	.module = THIS_MODULE,
-	.attach = waveform_attach,
-	.detach = waveform_detach,
-	.board_name = &waveform_boards[0].name,
-	.offset = sizeof(struct waveform_board),
-	.num_names = ARRAY_SIZE(waveform_boards),
-};
-
-static int __init driver_waveform_init_module(void)
-{
-	return comedi_driver_register(&driver_waveform);
-}
-
-static void __exit driver_waveform_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_waveform);
-}
-
-module_init(driver_waveform_init_module);
-module_exit(driver_waveform_cleanup_module);
-
-static int waveform_ai_cmdtest(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_cmd *cmd);
-static int waveform_ai_cmd(struct comedi_device *dev,
-			   struct comedi_subdevice *s);
-static int waveform_ai_cancel(struct comedi_device *dev,
-			      struct comedi_subdevice *s);
-static int waveform_ai_insn_read(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data);
-static int waveform_ao_insn_write(struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data);
-static short fake_sawtooth(struct comedi_device *dev, unsigned int range,
-			   unsigned long current_time);
-static short fake_squarewave(struct comedi_device *dev, unsigned int range,
-			     unsigned long current_time);
-static short fake_flatline(struct comedi_device *dev, unsigned int range,
-			   unsigned long current_time);
-static short fake_waveform(struct comedi_device *dev, unsigned int channel,
-			   unsigned int range, unsigned long current_time);
-
 /* 1000 nanosec in a microsec */
 static const int nano_per_micro = 1000;
 
@@ -154,6 +97,78 @@
 	 }
 };
 
+static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index,
+			   unsigned long current_time)
+{
+	struct comedi_subdevice *s = dev->read_subdev;
+	unsigned int offset = s->maxdata / 2;
+	u64 value;
+	const struct comedi_krange *krange =
+	    &s->range_table->range[range_index];
+	u64 binary_amplitude;
+
+	binary_amplitude = s->maxdata;
+	binary_amplitude *= devpriv->uvolt_amplitude;
+	do_div(binary_amplitude, krange->max - krange->min);
+
+	current_time %= devpriv->usec_period;
+	value = current_time;
+	value *= binary_amplitude * 2;
+	do_div(value, devpriv->usec_period);
+	value -= binary_amplitude;	/* get rid of sawtooth's dc offset */
+
+	return offset + value;
+}
+
+static short fake_squarewave(struct comedi_device *dev,
+			     unsigned int range_index,
+			     unsigned long current_time)
+{
+	struct comedi_subdevice *s = dev->read_subdev;
+	unsigned int offset = s->maxdata / 2;
+	u64 value;
+	const struct comedi_krange *krange =
+	    &s->range_table->range[range_index];
+	current_time %= devpriv->usec_period;
+
+	value = s->maxdata;
+	value *= devpriv->uvolt_amplitude;
+	do_div(value, krange->max - krange->min);
+
+	if (current_time < devpriv->usec_period / 2)
+		value *= -1;
+
+	return offset + value;
+}
+
+static short fake_flatline(struct comedi_device *dev, unsigned int range_index,
+			   unsigned long current_time)
+{
+	return dev->read_subdev->maxdata / 2;
+}
+
+/* generates a different waveform depending on what channel is read */
+static short fake_waveform(struct comedi_device *dev, unsigned int channel,
+			   unsigned int range, unsigned long current_time)
+{
+	enum {
+		SAWTOOTH_CHAN,
+		SQUARE_CHAN,
+	};
+	switch (channel) {
+	case SAWTOOTH_CHAN:
+		return fake_sawtooth(dev, range, current_time);
+		break;
+	case SQUARE_CHAN:
+		return fake_squarewave(dev, range, current_time);
+		break;
+	default:
+		break;
+	}
+
+	return fake_flatline(dev, range, current_time);
+}
+
 /*
    This is the background routine used to generate arbitrary data.
    It should run in the background; therefore it is scheduled by
@@ -217,84 +232,6 @@
 	comedi_event(dev, dev->read_subdev);
 }
 
-static int waveform_attach(struct comedi_device *dev,
-			   struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	int amplitude = it->options[0];
-	int period = it->options[1];
-	int i;
-
-	dev->board_name = thisboard->name;
-
-	if (alloc_private(dev, sizeof(struct waveform_private)) < 0)
-		return -ENOMEM;
-
-	/* set default amplitude and period */
-	if (amplitude <= 0)
-		amplitude = 1000000;	/* 1 volt */
-	if (period <= 0)
-		period = 100000;	/* 0.1 sec */
-
-	devpriv->uvolt_amplitude = amplitude;
-	devpriv->usec_period = period;
-
-	dev->n_subdevices = 2;
-	if (alloc_subdevices(dev, dev->n_subdevices) < 0)
-		return -ENOMEM;
-
-	s = dev->subdevices + 0;
-	dev->read_subdev = s;
-	/* analog input subdevice */
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
-	s->n_chan = thisboard->ai_chans;
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
-	s->range_table = &waveform_ai_ranges;
-	s->len_chanlist = s->n_chan * 2;
-	s->insn_read = waveform_ai_insn_read;
-	s->do_cmd = waveform_ai_cmd;
-	s->do_cmdtest = waveform_ai_cmdtest;
-	s->cancel = waveform_ai_cancel;
-
-	s = dev->subdevices + 1;
-	dev->write_subdev = s;
-	/* analog output subdevice (loopback) */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
-	s->n_chan = thisboard->ai_chans;
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
-	s->range_table = &waveform_ai_ranges;
-	s->len_chanlist = s->n_chan * 2;
-	s->insn_write = waveform_ao_insn_write;
-	s->do_cmd = NULL;
-	s->do_cmdtest = NULL;
-	s->cancel = NULL;
-
-	/* Our default loopback value is just a 0V flatline */
-	for (i = 0; i < s->n_chan; i++)
-		devpriv->ao_loopbacks[i] = s->maxdata / 2;
-
-	init_timer(&(devpriv->timer));
-	devpriv->timer.function = waveform_ai_interrupt;
-	devpriv->timer.data = (unsigned long)dev;
-
-	printk(KERN_INFO "comedi%d: comedi_test: "
-	       "%i microvolt, %li microsecond waveform attached\n", dev->minor,
-	       devpriv->uvolt_amplitude, devpriv->usec_period);
-	return 1;
-}
-
-static int waveform_detach(struct comedi_device *dev)
-{
-	printk("comedi%d: comedi_test: remove\n", dev->minor);
-
-	if (dev->private)
-		waveform_ai_cancel(dev, dev->read_subdev);
-
-	return 0;
-}
-
 static int waveform_ai_cmdtest(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_cmd *cmd)
@@ -465,78 +402,6 @@
 	return 0;
 }
 
-static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index,
-			   unsigned long current_time)
-{
-	struct comedi_subdevice *s = dev->read_subdev;
-	unsigned int offset = s->maxdata / 2;
-	u64 value;
-	const struct comedi_krange *krange =
-	    &s->range_table->range[range_index];
-	u64 binary_amplitude;
-
-	binary_amplitude = s->maxdata;
-	binary_amplitude *= devpriv->uvolt_amplitude;
-	do_div(binary_amplitude, krange->max - krange->min);
-
-	current_time %= devpriv->usec_period;
-	value = current_time;
-	value *= binary_amplitude * 2;
-	do_div(value, devpriv->usec_period);
-	value -= binary_amplitude;	/* get rid of sawtooth's dc offset */
-
-	return offset + value;
-}
-
-static short fake_squarewave(struct comedi_device *dev,
-			     unsigned int range_index,
-			     unsigned long current_time)
-{
-	struct comedi_subdevice *s = dev->read_subdev;
-	unsigned int offset = s->maxdata / 2;
-	u64 value;
-	const struct comedi_krange *krange =
-	    &s->range_table->range[range_index];
-	current_time %= devpriv->usec_period;
-
-	value = s->maxdata;
-	value *= devpriv->uvolt_amplitude;
-	do_div(value, krange->max - krange->min);
-
-	if (current_time < devpriv->usec_period / 2)
-		value *= -1;
-
-	return offset + value;
-}
-
-static short fake_flatline(struct comedi_device *dev, unsigned int range_index,
-			   unsigned long current_time)
-{
-	return dev->read_subdev->maxdata / 2;
-}
-
-/* generates a different waveform depending on what channel is read */
-static short fake_waveform(struct comedi_device *dev, unsigned int channel,
-			   unsigned int range, unsigned long current_time)
-{
-	enum {
-		SAWTOOTH_CHAN,
-		SQUARE_CHAN,
-	};
-	switch (channel) {
-	case SAWTOOTH_CHAN:
-		return fake_sawtooth(dev, range, current_time);
-		break;
-	case SQUARE_CHAN:
-		return fake_squarewave(dev, range, current_time);
-		break;
-	default:
-		break;
-	}
-
-	return fake_flatline(dev, range, current_time);
-}
-
 static int waveform_ai_insn_read(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
@@ -561,6 +426,100 @@
 	return insn->n;
 }
 
+static int waveform_attach(struct comedi_device *dev,
+			   struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	int amplitude = it->options[0];
+	int period = it->options[1];
+	int i;
+
+	dev->board_name = thisboard->name;
+
+	if (alloc_private(dev, sizeof(struct waveform_private)) < 0)
+		return -ENOMEM;
+
+	/* set default amplitude and period */
+	if (amplitude <= 0)
+		amplitude = 1000000;	/* 1 volt */
+	if (period <= 0)
+		period = 100000;	/* 0.1 sec */
+
+	devpriv->uvolt_amplitude = amplitude;
+	devpriv->usec_period = period;
+
+	dev->n_subdevices = 2;
+	if (alloc_subdevices(dev, dev->n_subdevices) < 0)
+		return -ENOMEM;
+
+	s = dev->subdevices + 0;
+	dev->read_subdev = s;
+	/* analog input subdevice */
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
+	s->n_chan = thisboard->ai_chans;
+	s->maxdata = (1 << thisboard->ai_bits) - 1;
+	s->range_table = &waveform_ai_ranges;
+	s->len_chanlist = s->n_chan * 2;
+	s->insn_read = waveform_ai_insn_read;
+	s->do_cmd = waveform_ai_cmd;
+	s->do_cmdtest = waveform_ai_cmdtest;
+	s->cancel = waveform_ai_cancel;
+
+	s = dev->subdevices + 1;
+	dev->write_subdev = s;
+	/* analog output subdevice (loopback) */
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
+	s->n_chan = thisboard->ai_chans;
+	s->maxdata = (1 << thisboard->ai_bits) - 1;
+	s->range_table = &waveform_ai_ranges;
+	s->len_chanlist = s->n_chan * 2;
+	s->insn_write = waveform_ao_insn_write;
+	s->do_cmd = NULL;
+	s->do_cmdtest = NULL;
+	s->cancel = NULL;
+
+	/* Our default loopback value is just a 0V flatline */
+	for (i = 0; i < s->n_chan; i++)
+		devpriv->ao_loopbacks[i] = s->maxdata / 2;
+
+	init_timer(&(devpriv->timer));
+	devpriv->timer.function = waveform_ai_interrupt;
+	devpriv->timer.data = (unsigned long)dev;
+
+	printk(KERN_INFO "comedi%d: comedi_test: "
+	       "%i microvolt, %li microsecond waveform attached\n", dev->minor,
+	       devpriv->uvolt_amplitude, devpriv->usec_period);
+	return 1;
+}
+
+static void waveform_detach(struct comedi_device *dev)
+{
+	if (dev->private)
+		waveform_ai_cancel(dev, dev->read_subdev);
+}
+
+static const struct waveform_board waveform_boards[] = {
+	{
+		.name		= "comedi_test",
+		.ai_chans	= N_CHANS,
+		.ai_bits	= 16,
+		.have_dio	= 0,
+	},
+};
+
+static struct comedi_driver waveform_driver = {
+	.driver_name	= "comedi_test",
+	.module		= THIS_MODULE,
+	.attach		= waveform_attach,
+	.detach		= waveform_detach,
+	.board_name	= &waveform_boards[0].name,
+	.offset		= sizeof(struct waveform_board),
+	.num_names	= ARRAY_SIZE(waveform_boards),
+};
+module_comedi_driver(waveform_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index e3659bd..b8bac80 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -56,13 +56,6 @@
 };
 
 #define PCI_DEVICE_ID_PIO1616L 0x8172
-static DEFINE_PCI_DEVICE_TABLE(contec_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L),
-		.driver_data = PIO1616L },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, contec_pci_table);
 
 #define thisboard ((const struct contec_board *)dev->board_ptr)
 
@@ -75,30 +68,42 @@
 
 #define devpriv ((struct contec_private *)dev->private)
 
-static int contec_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int contec_detach(struct comedi_device *dev);
-static struct comedi_driver driver_contec = {
-	.driver_name = "contec_pci_dio",
-	.module = THIS_MODULE,
-	.attach = contec_attach,
-	.detach = contec_detach,
-};
-
-/* Classic digital IO */
-static int contec_di_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
 static int contec_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
+			       struct comedi_insn *insn, unsigned int *data)
+{
 
-#if 0
-static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_cmd *cmd);
+	dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n");
+	dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
 
-static int contec_ns_to_timer(unsigned int *ns, int round);
-#endif
+	if (insn->n != 2)
+		return -EINVAL;
+
+	if (data[0]) {
+		s->state &= ~data[0];
+		s->state |= data[0] & data[1];
+		dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state,
+			dev->iobase + thisboard->out_offs);
+		outw(s->state, dev->iobase + thisboard->out_offs);
+	}
+	return 2;
+}
+
+static int contec_di_insn_bits(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn, unsigned int *data)
+{
+
+	dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n");
+	dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
+
+	if (insn->n != 2)
+		return -EINVAL;
+
+	data[1] = inw(dev->iobase + thisboard->in_offs);
+
+	return 2;
+}
 
 static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
@@ -164,107 +169,47 @@
 	return -EIO;
 }
 
-static int contec_detach(struct comedi_device *dev)
+static void contec_detach(struct comedi_device *dev)
 {
-	printk("comedi%d: contec: remove\n", dev->minor);
-
 	if (devpriv && devpriv->pci_dev) {
 		if (dev->iobase)
 			comedi_pci_disable(devpriv->pci_dev);
 		pci_dev_put(devpriv->pci_dev);
 	}
-
-	return 0;
 }
 
-#if 0
-static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_cmd *cmd)
+static struct comedi_driver contec_pci_dio_driver = {
+	.driver_name	= "contec_pci_dio",
+	.module		= THIS_MODULE,
+	.attach		= contec_attach,
+	.detach		= contec_detach,
+};
+
+static int __devinit contec_pci_dio_pci_probe(struct pci_dev *dev,
+					      const struct pci_device_id *ent)
 {
-	printk("contec_cmdtest called\n");
-	return 0;
+	return comedi_pci_auto_config(dev, &contec_pci_dio_driver);
 }
 
-static int contec_ns_to_timer(unsigned int *ns, int round)
-{
-	return *ns;
-}
-#endif
-
-static int contec_do_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
-{
-
-	dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n");
-	dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-
-	if (insn->n != 2)
-		return -EINVAL;
-
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= data[0] & data[1];
-		dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state,
-			dev->iobase + thisboard->out_offs);
-		outw(s->state, dev->iobase + thisboard->out_offs);
-	}
-	return 2;
-}
-
-static int contec_di_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
-{
-
-	dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n");
-	dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-
-	if (insn->n != 2)
-		return -EINVAL;
-
-	data[1] = inw(dev->iobase + thisboard->in_offs);
-
-	return 2;
-}
-
-static int __devinit driver_contec_pci_probe(struct pci_dev *dev,
-					     const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, driver_contec.driver_name);
-}
-
-static void __devexit driver_contec_pci_remove(struct pci_dev *dev)
+static void __devexit contec_pci_dio_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_contec_pci_driver = {
-	.id_table = contec_pci_table,
-	.probe = &driver_contec_pci_probe,
-	.remove = __devexit_p(&driver_contec_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L),
+		.driver_data = PIO1616L },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table);
 
-static int __init driver_contec_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_contec);
-	if (retval < 0)
-		return retval;
-
-	driver_contec_pci_driver.name = (char *)driver_contec.driver_name;
-	return pci_register_driver(&driver_contec_pci_driver);
-}
-
-static void __exit driver_contec_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_contec_pci_driver);
-	comedi_driver_unregister(&driver_contec);
-}
-
-module_init(driver_contec_init_module);
-module_exit(driver_contec_cleanup_module);
+static struct pci_driver contec_pci_dio_pci_driver = {
+	.name		= "contec_pci_dio",
+	.id_table	= contec_pci_dio_pci_table,
+	.probe		= contec_pci_dio_pci_probe,
+	.remove		= __devexit_p(contec_pci_dio_pci_remove),
+};
+module_comedi_pci_driver(contec_pci_dio_driver, contec_pci_dio_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index e61c6a8..696b58c 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -301,17 +301,6 @@
 #define DAQBOARD2000_PosRefDacSelect             0x0100
 #define DAQBOARD2000_NegRefDacSelect             0x0000
 
-static int daqboard2000_attach(struct comedi_device *dev,
-			       struct comedi_devconfig *it);
-static int daqboard2000_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_daqboard2000 = {
-	.driver_name = "daqboard2000",
-	.module = THIS_MODULE,
-	.attach = daqboard2000_attach,
-	.detach = daqboard2000_detach,
-};
-
 struct daq200_boardtype {
 	const char *name;
 	int id;
@@ -321,16 +310,8 @@
 	{"ids4", DAQBOARD2000_SUBSYSTEM_IDS4},
 };
 
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct daq200_boardtype))
 #define this_board ((const struct daq200_boardtype *)dev->board_ptr)
 
-static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = {
-	{ PCI_DEVICE(0x1616, 0x0409) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table);
-
 struct daqboard2000_private {
 	enum {
 		card_daqboard_2000
@@ -412,9 +393,12 @@
 	    DAQBOARD2000_AcqResetScanListFifo |
 	    DAQBOARD2000_AcqResetResultsFifo | DAQBOARD2000_AcqResetConfigPipe;
 
-	/* If pacer clock is not set to some high value (> 10 us), we
-	   risk multiple samples to be put into the result FIFO. */
-	fpga->acqPacerClockDivLow = 1000000;	/* 1 second, should be long enough */
+	/*
+	 * If pacer clock is not set to some high value (> 10 us), we
+	 * risk multiple samples to be put into the result FIFO.
+	 */
+	/* 1 second, should be long enough */
+	fpga->acqPacerClockDivLow = 1000000;
 	fpga->acqPacerClockDivHigh = 0;
 
 	gain = CR_RANGE(insn->chanspec);
@@ -761,7 +745,7 @@
 		devpriv->pci_dev = card;
 		id = ((u32) card->
 		      subsystem_device << 16) | card->subsystem_vendor;
-		for (i = 0; i < n_boardtypes; i++) {
+		for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
 			if (boardtypes[i].id == id) {
 				dev_dbg(dev->hw_dev, "%s\n",
 					boardtypes[i].name);
@@ -852,14 +836,12 @@
 	return result;
 }
 
-static int daqboard2000_detach(struct comedi_device *dev)
+static void daqboard2000_detach(struct comedi_device *dev)
 {
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 2);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (devpriv) {
 		if (devpriv->daq)
 			iounmap(devpriv->daq);
@@ -871,48 +853,39 @@
 			pci_dev_put(devpriv->pci_dev);
 		}
 	}
-	return 0;
 }
 
-static int __devinit driver_daqboard2000_pci_probe(struct pci_dev *dev,
-						   const struct pci_device_id
-						   *ent)
+static struct comedi_driver daqboard2000_driver = {
+	.driver_name	= "daqboard2000",
+	.module		= THIS_MODULE,
+	.attach		= daqboard2000_attach,
+	.detach		= daqboard2000_detach,
+};
+
+static int __devinit daqboard2000_pci_probe(struct pci_dev *dev,
+					    const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_daqboard2000.driver_name);
+	return comedi_pci_auto_config(dev, &daqboard2000_driver);
 }
 
-static void __devexit driver_daqboard2000_pci_remove(struct pci_dev *dev)
+static void __devexit daqboard2000_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_daqboard2000_pci_driver = {
-	.id_table = daqboard2000_pci_table,
-	.probe = &driver_daqboard2000_pci_probe,
-	.remove = __devexit_p(&driver_daqboard2000_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = {
+	{ PCI_DEVICE(0x1616, 0x0409) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table);
 
-static int __init driver_daqboard2000_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_daqboard2000);
-	if (retval < 0)
-		return retval;
-
-	driver_daqboard2000_pci_driver.name =
-	    (char *)driver_daqboard2000.driver_name;
-	return pci_register_driver(&driver_daqboard2000_pci_driver);
-}
-
-static void __exit driver_daqboard2000_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_daqboard2000_pci_driver);
-	comedi_driver_unregister(&driver_daqboard2000);
-}
-
-module_init(driver_daqboard2000_init_module);
-module_exit(driver_daqboard2000_cleanup_module);
+static struct pci_driver daqboard2000_pci_driver = {
+	.name		= "daqboard2000",
+	.id_table	= daqboard2000_pci_table,
+	.probe		= daqboard2000_pci_probe,
+	.remove		= __devexit_p(daqboard2000_pci_remove),
+};
+module_comedi_pci_driver(daqboard2000_driver, daqboard2000_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index c2dd0ed..1f31943 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -61,6 +61,20 @@
 
 #define DRV_NAME "das08"
 
+#ifdef CONFIG_COMEDI_DAS08_ISA_MODULE
+#define CONFIG_COMEDI_DAS08_ISA
+#endif
+#ifdef CONFIG_COMEDI_DAS08_PCI_MODULE
+#define CONFIG_COMEDI_DAS08_PCI
+#endif
+#ifdef CONFIG_COMEDI_DAS08_CS_MODULE
+#define CONFIG_COMEDI_DAS08_CS
+#endif
+
+#if defined(CONFIG_COMEDI_DAS08_ISA) || defined(CONFIG_COMEDI_DAS08_PCI)
+#define DO_COMEDI_DRIVER_REGISTER
+#endif
+
 #define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307
 #define PCI_DEVICE_ID_PCIDAS08 0x29
 #define PCIDAS08_SIZE 0x54
@@ -160,6 +174,7 @@
 			  struct comedi_insn *insn, unsigned int *data);
 static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data);
+#ifdef CONFIG_COMEDI_DAS08_ISA
 static int das08jr_di_rbits(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data);
@@ -172,6 +187,7 @@
 static int das08ao_ao_winsn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data);
+#endif
 static void i8254_set_mode_low(unsigned int base, int channel,
 			       unsigned int mode);
 
@@ -253,7 +269,9 @@
 	das08_pgm_gainlist,
 };
 
+#ifdef DO_COMEDI_DRIVER_REGISTER
 static const struct das08_board_struct das08_boards[] = {
+#ifdef CONFIG_COMEDI_DAS08_ISA
 	{
 	 .name = "isa-das08",	/*  cio-das08.pdf */
 	 .bustype = isa,
@@ -395,25 +413,6 @@
 	 .i8254_offset = 0x04,
 	 .iosize = 16,		/*  unchecked */
 	 },
-#ifdef CONFIG_COMEDI_PCI
-	{
-	 .name = "das08",	/*  pci-das08 */
-	 .id = PCI_DEVICE_ID_PCIDAS08,
-	 .bustype = pci,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_bipolar5,
-	 .ai_encoding = das08_encode12,
-	 .ao = NULL,
-	 .ao_nbits = 0,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 0,
-	 .i8254_offset = 4,
-	 .iosize = 8,
-	 },
-#endif
 	{
 	 .name = "pc104-das08",
 	 .bustype = pc104,
@@ -462,9 +461,30 @@
 	 .name = "das08-pga-g2",	/*  a KM board */
 	 },
 #endif
+#endif /* CONFIG_COMEDI_DAS08_ISA */
+#ifdef CONFIG_COMEDI_DAS08_PCI
+	{
+	 .name = "das08",	/*  pci-das08 */
+	 .id = PCI_DEVICE_ID_PCIDAS08,
+	 .bustype = pci,
+	 .ai = das08_ai_rinsn,
+	 .ai_nbits = 12,
+	 .ai_pg = das08_bipolar5,
+	 .ai_encoding = das08_encode12,
+	 .ao = NULL,
+	 .ao_nbits = 0,
+	 .di = das08_di_rbits,
+	 .do_ = das08_do_wbits,
+	 .do_nchan = 4,
+	 .i8255_offset = 0,
+	 .i8254_offset = 4,
+	 .iosize = 8,
+	 },
+#endif /* CONFIG_COMEDI_DAS08_PCI */
 };
+#endif /* DO_COMEDI_DRIVER_REGISTER */
 
-#ifdef CONFIG_COMEDI_PCMCIA
+#ifdef CONFIG_COMEDI_DAS08_CS
 struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = {
 	{
 	 .name = "pcm-das08",
@@ -504,7 +524,7 @@
 };
 #endif
 
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
 static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08) },
 	{0}
@@ -619,6 +639,7 @@
 	return 2;
 }
 
+#ifdef CONFIG_COMEDI_DAS08_ISA
 static int das08jr_di_rbits(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
@@ -628,7 +649,9 @@
 
 	return 2;
 }
+#endif
 
+#ifdef CONFIG_COMEDI_DAS08_ISA
 static int das08jr_do_wbits(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
@@ -643,7 +666,9 @@
 
 	return 2;
 }
+#endif
 
+#ifdef CONFIG_COMEDI_DAS08_ISA
 static int das08jr_ao_winsn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
@@ -672,6 +697,7 @@
 
 	return n;
 }
+#endif
 
 /*
  *
@@ -679,6 +705,7 @@
  * a different method to force an update.
  *
  */
+#ifdef CONFIG_COMEDI_DAS08_ISA
 static int das08ao_ao_winsn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
@@ -707,6 +734,7 @@
 
 	return n;
 }
+#endif
 
 static unsigned int i8254_read_channel_low(unsigned int base, int chan)
 {
@@ -842,6 +870,7 @@
 	return 2;
 }
 
+#ifdef DO_COMEDI_DRIVER_REGISTER
 static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it);
 
 static struct comedi_driver driver_das08 = {
@@ -853,6 +882,7 @@
 	.num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct),
 	.offset = sizeof(struct das08_board_struct),
 };
+#endif
 
 int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
 {
@@ -972,11 +1002,12 @@
 }
 EXPORT_SYMBOL_GPL(das08_common_attach);
 
+#ifdef DO_COMEDI_DRIVER_REGISTER
 static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	int ret;
 	unsigned long iobase;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
 	unsigned long pci_iobase = 0;
 	struct pci_dev *pdev = NULL;
 #endif
@@ -986,9 +1017,9 @@
 		return ret;
 
 	printk(KERN_INFO "comedi%d: das08: ", dev->minor);
+#ifdef CONFIG_COMEDI_DAS08_PCI
 	/*  deal with a pci board */
 	if (thisboard->bustype == pci) {
-#ifdef CONFIG_COMEDI_PCI
 		if (it->options[0] || it->options[1]) {
 			printk("bus %i slot %i ",
 			       it->options[0], it->options[1]);
@@ -1037,32 +1068,26 @@
 		/* Enable local interrupt 1 and pci interrupt */
 		outw(INTR1_ENABLE | PCI_INTR_ENABLE, pci_iobase + INTCSR);
 #endif
-#else /* CONFIG_COMEDI_PCI */
-		printk(KERN_ERR "this driver has not been built with PCI support.\n");
-		return -EINVAL;
-#endif /* CONFIG_COMEDI_PCI */
-	} else {
+	} else
+#endif /* CONFIG_COMEDI_DAS08_PCI */
+	{
 		iobase = it->options[0];
 	}
 	printk(KERN_INFO "\n");
 
 	return das08_common_attach(dev, iobase);
 }
+#endif /* DO_COMEDI_DRIVER_REGISTER */
 
-
-int das08_common_detach(struct comedi_device *dev)
+void das08_common_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: das08: remove\n", dev->minor);
-
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 4);
-
-	/*  deallocate ioports for non-pcmcia, non-pci boards */
 	if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) {
 		if (dev->iobase)
 			release_region(dev->iobase, thisboard->iosize);
 	}
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
 	if (devpriv) {
 		if (devpriv->pdev) {
 			if (devpriv->pci_iobase)
@@ -1072,16 +1097,14 @@
 		}
 	}
 #endif
-
-	return 0;
 }
 EXPORT_SYMBOL_GPL(das08_common_detach);
 
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
 static int __devinit driver_das08_pci_probe(struct pci_dev *dev,
 					    const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_das08.driver_name);
+	return comedi_pci_auto_config(dev, &driver_das08);
 }
 
 static void __devexit driver_das08_pci_remove(struct pci_dev *dev)
@@ -1094,43 +1117,38 @@
 	.probe = &driver_das08_pci_probe,
 	.remove = __devexit_p(&driver_das08_pci_remove)
 };
+#endif /* CONFIG_COMEDI_DAS08_PCI */
 
 static int __init driver_das08_init_module(void)
 {
-	int retval;
+	int retval = 0;
 
+#ifdef DO_COMEDI_DRIVER_REGISTER
 	retval = comedi_driver_register(&driver_das08);
 	if (retval < 0)
 		return retval;
-
-	driver_das08_pci_driver.name = (char *)driver_das08.driver_name;
-	return pci_register_driver(&driver_das08_pci_driver);
-}
-
-static void __exit driver_das08_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_das08_pci_driver);
-	comedi_driver_unregister(&driver_das08);
-}
-
-module_init(driver_das08_init_module);
-module_exit(driver_das08_cleanup_module);
-#else
-static int __init driver_das08_init_module(void)
-{
-	return comedi_driver_register(&driver_das08);
-}
-
-static void __exit driver_das08_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_das08);
-}
-
-module_init(driver_das08_init_module);
-module_exit(driver_das08_cleanup_module);
 #endif
+#ifdef CONFIG_COMEDI_DAS08_PCI
+	driver_das08_pci_driver.name = (char *)driver_das08.driver_name;
+	retval = pci_register_driver(&driver_das08_pci_driver);
+#endif
+	return retval;
+}
 
-#ifdef CONFIG_COMEDI_PCMCIA
+static void __exit driver_das08_cleanup_module(void)
+{
+#ifdef CONFIG_COMEDI_DAS08_PCI
+	pci_unregister_driver(&driver_das08_pci_driver);
+#endif
+#ifdef DO_COMEDI_DRIVER_REGISTER
+	comedi_driver_unregister(&driver_das08);
+#endif
+}
+
+module_init(driver_das08_init_module);
+module_exit(driver_das08_cleanup_module);
+
+#ifdef CONFIG_COMEDI_DAS08_CS
 EXPORT_SYMBOL_GPL(das08_cs_boards);
 #endif
 
diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h
index 2a30d76..0b92f24 100644
--- a/drivers/staging/comedi/drivers/das08.h
+++ b/drivers/staging/comedi/drivers/das08.h
@@ -74,6 +74,6 @@
 extern struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS];
 
 int das08_common_attach(struct comedi_device *dev, unsigned long iobase);
-int das08_common_detach(struct comedi_device *dev);
+void das08_common_detach(struct comedi_device *dev);
 
 #endif /* _DAS08_H */
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index e7905ba..998444c 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -339,38 +339,6 @@
 	unsigned have_byte:1;
 };
 
-static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-
-static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_cmd *cmd);
-static int das16_cmd_exec(struct comedi_device *dev,
-			  struct comedi_subdevice *s);
-static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static void das16_ai_munge(struct comedi_device *dev,
-			   struct comedi_subdevice *s, void *array,
-			   unsigned int num_bytes,
-			   unsigned int start_chan_index);
-
-static void das16_reset(struct comedi_device *dev);
-static irqreturn_t das16_dma_interrupt(int irq, void *d);
-static void das16_timer_interrupt(unsigned long arg);
-static void das16_interrupt(struct comedi_device *dev);
-
-static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
-				    int flags);
-static int das1600_mode_detect(struct comedi_device *dev);
-static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
-						struct comedi_cmd cmd);
-
-static void reg_dump(struct comedi_device *dev);
-
 struct das16_board {
 	const char *name;
 	void *ai;
@@ -389,344 +357,6 @@
 	unsigned int id;
 };
 
-static const struct das16_board das16_boards[] = {
-	{
-	 .name = "das-16",
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 15000,
-	 .ai_pg = das16_pg_none,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x10,
-	 .i8254_offset = 0x0c,
-	 .size = 0x14,
-	 .id = 0x00,
-	 },
-	{
-	 .name = "das-16g",
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 15000,
-	 .ai_pg = das16_pg_none,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x10,
-	 .i8254_offset = 0x0c,
-	 .size = 0x14,
-	 .id = 0x00,
-	 },
-	{
-	 .name = "das-16f",
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 8500,
-	 .ai_pg = das16_pg_none,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x10,
-	 .i8254_offset = 0x0c,
-	 .size = 0x14,
-	 .id = 0x00,
-	 },
-	{
-	 .name = "cio-das16",	/*  cio-das16.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 20000,
-	 .ai_pg = das16_pg_none,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x10,
-	 .i8254_offset = 0x0c,
-	 .size = 0x14,
-	 .id = 0x80,
-	 },
-	{
-	 .name = "cio-das16/f",	/*  das16.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_none,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x10,
-	 .i8254_offset = 0x0c,
-	 .size = 0x14,
-	 .id = 0x80,
-	 },
-	{
-	 .name = "cio-das16/jr",	/*  cio-das16jr.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 7692,
-	 .ai_pg = das16_pg_16jr,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x10,
-	 .id = 0x00,
-	 },
-	{
-	 .name = "pc104-das16jr",	/*  pc104-das16jr_xx.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 3300,
-	 .ai_pg = das16_pg_16jr,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x10,
-	 .id = 0x00,
-	 },
-	{
-	 .name = "cio-das16jr/16",	/*  cio-das16jr_16.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 16,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_16jr_16,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x10,
-	 .id = 0x00,
-	 },
-	{
-	 .name = "pc104-das16jr/16",	/*  pc104-das16jr_xx.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 16,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_16jr_16,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x10,
-	 .id = 0x00,
-	 },
-	{
-	 .name = "das-1201",	/*  4924.pdf (keithley user's manual) */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 20000,
-	 .ai_pg = das16_pg_none,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x400,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0x20,
-	 },
-	{
-	 .name = "das-1202",	/*  4924.pdf (keithley user's manual) */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_none,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x400,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0x20,
-	 },
-	{
-	/*  4919.pdf and 4922.pdf (keithley user's manual) */
-	 .name = "das-1401",
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_1601,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0   /*  4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */
-	 },
-	{
-	/*  4919.pdf and 4922.pdf (keithley user's manual) */
-	 .name = "das-1402",
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_1602,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0   /*  4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */
-	 },
-	{
-	 .name = "das-1601",	/*  4919.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_1601,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x400,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0},
-	{
-	 .name = "das-1602",	/*  4919.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_1602,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x400,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0},
-	{
-	 .name = "cio-das1401/12",	/*  cio-das1400_series.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 6250,
-	 .ai_pg = das16_pg_1601,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0},
-	{
-	 .name = "cio-das1402/12",	/*  cio-das1400_series.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 6250,
-	 .ai_pg = das16_pg_1602,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0},
-	{
-	 .name = "cio-das1402/16",	/*  cio-das1400_series.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 16,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_1602,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0},
-	{
-	 .name = "cio-das1601/12",	/*  cio-das160x-1x.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 6250,
-	 .ai_pg = das16_pg_1601,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x400,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0},
-	{
-	 .name = "cio-das1602/12",	/*  cio-das160x-1x.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_1602,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x400,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0},
-	{
-	 .name = "cio-das1602/16",	/*  cio-das160x-1x.pdf */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 16,
-	 .ai_speed = 10000,
-	 .ai_pg = das16_pg_1602,
-	 .ao = das16_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0x400,
-	 .i8254_offset = 0x0c,
-	 .size = 0x408,
-	 .id = 0xc0},
-	{
-	 .name = "cio-das16/330",	/*  ? */
-	 .ai = das16_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_speed = 3030,
-	 .ai_pg = das16_pg_16jr,
-	 .ao = NULL,
-	 .di = das16_di_rbits,
-	 .do_ = das16_do_wbits,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x0c,
-	 .size = 0x14,
-	 .id = 0xf0},
-#if 0
-	{
-	 .name = "das16/330i",	/*  ? */
-	 },
-	{
-	 .name = "das16/jr/ctr5",	/*  ? */
-	 },
-	{
-	/*  cio-das16_m1_16.pdf, this board is a bit quirky, no dma */
-	 .name = "cio-das16/m1/16",
-	 },
-#endif
-};
-
-static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int das16_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das16 = {
-	.driver_name = "das16",
-	.module = THIS_MODULE,
-	.attach = das16_attach,
-	.detach = das16_detach,
-	.board_name = &das16_boards[0].name,
-	.num_names = ARRAY_SIZE(das16_boards),
-	.offset = sizeof(das16_boards[0]),
-};
-
 #define DAS16_TIMEOUT 1000
 
 /* Period for timer interrupt in jiffies.  It's a function
@@ -926,6 +556,62 @@
 	return 0;
 }
 
+/* utility function that suggests a dma transfer size in bytes */
+static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
+						struct comedi_cmd cmd)
+{
+	unsigned int size;
+	unsigned int freq;
+
+	/* if we are using timer interrupt, we don't care how long it
+	 * will take to complete transfer since it will be interrupted
+	 * by timer interrupt */
+	if (devpriv->timer_mode)
+		return DAS16_DMA_SIZE;
+
+	/* otherwise, we are relying on dma terminal count interrupt,
+	 * so pick a reasonable size */
+	if (cmd.convert_src == TRIG_TIMER)
+		freq = 1000000000 / cmd.convert_arg;
+	else if (cmd.scan_begin_src == TRIG_TIMER)
+		freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len;
+	/*  return some default value */
+	else
+		freq = 0xffffffff;
+
+	if (cmd.flags & TRIG_WAKE_EOS) {
+		size = sample_size * cmd.chanlist_len;
+	} else {
+		/*  make buffer fill in no more than 1/3 second */
+		size = (freq / 3) * sample_size;
+	}
+
+	/*  set a minimum and maximum size allowed */
+	if (size > DAS16_DMA_SIZE)
+		size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size;
+	else if (size < sample_size)
+		size = sample_size;
+
+	if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
+		size = devpriv->adc_byte_count;
+
+	return size;
+}
+
+static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
+				    int rounding_flags)
+{
+	i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1),
+				       &(devpriv->divisor2), &ns,
+				       rounding_flags & TRIG_ROUND_MASK);
+
+	/* Write the values of ctr1 and ctr2 into counters 1 and 2 */
+	i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2);
+	i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2);
+
+	return ns;
+}
+
 static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct comedi_async *async = s->async;
@@ -1170,34 +856,6 @@
 	return i;
 }
 
-static irqreturn_t das16_dma_interrupt(int irq, void *d)
-{
-	int status;
-	struct comedi_device *dev = d;
-
-	status = inb(dev->iobase + DAS16_STATUS);
-
-	if ((status & DAS16_INT) == 0) {
-		DEBUG_PRINT("spurious interrupt\n");
-		return IRQ_NONE;
-	}
-
-	/* clear interrupt */
-	outb(0x00, dev->iobase + DAS16_STATUS);
-	das16_interrupt(dev);
-	return IRQ_HANDLED;
-}
-
-static void das16_timer_interrupt(unsigned long arg)
-{
-	struct comedi_device *dev = (struct comedi_device *)arg;
-
-	das16_interrupt(dev);
-
-	if (devpriv->timer_running)
-		mod_timer(&devpriv->timer, jiffies + timer_period());
-}
-
 /* the pc104-das16jr (at least) has problems if the dma
 	transfer is interrupted in the middle of transferring
 	a 16 bit sample, so this function takes care to get
@@ -1309,18 +967,32 @@
 	cfc_handle_events(dev, s);
 }
 
-static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
-				    int rounding_flags)
+static irqreturn_t das16_dma_interrupt(int irq, void *d)
 {
-	i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1),
-				       &(devpriv->divisor2), &ns,
-				       rounding_flags & TRIG_ROUND_MASK);
+	int status;
+	struct comedi_device *dev = d;
 
-	/* Write the values of ctr1 and ctr2 into counters 1 and 2 */
-	i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2);
-	i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2);
+	status = inb(dev->iobase + DAS16_STATUS);
 
-	return ns;
+	if ((status & DAS16_INT) == 0) {
+		DEBUG_PRINT("spurious interrupt\n");
+		return IRQ_NONE;
+	}
+
+	/* clear interrupt */
+	outb(0x00, dev->iobase + DAS16_STATUS);
+	das16_interrupt(dev);
+	return IRQ_HANDLED;
+}
+
+static void das16_timer_interrupt(unsigned long arg)
+{
+	struct comedi_device *dev = (struct comedi_device *)arg;
+
+	das16_interrupt(dev);
+
+	if (devpriv->timer_running)
+		mod_timer(&devpriv->timer, jiffies + timer_period());
 }
 
 static void reg_dump(struct comedi_device *dev)
@@ -1394,6 +1066,22 @@
 	return 0;
 }
 
+static void das16_ai_munge(struct comedi_device *dev,
+			   struct comedi_subdevice *s, void *array,
+			   unsigned int num_bytes,
+			   unsigned int start_chan_index)
+{
+	unsigned int i, num_samples = num_bytes / sizeof(short);
+	short *data = array;
+
+	for (i = 0; i < num_samples; i++) {
+		data[i] = le16_to_cpu(data[i]);
+		if (thisboard->ai_nbits == 12)
+			data[i] = (data[i] >> 4) & 0xfff;
+
+	}
+}
+
 /*
  *
  * Options list:
@@ -1402,7 +1090,6 @@
  *   2  DMA
  *   3  Clock speed (in MHz)
  */
-
 static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct comedi_subdevice *s;
@@ -1675,15 +1362,11 @@
 	return 0;
 }
 
-static int das16_detach(struct comedi_device *dev)
+static void das16_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: das16: remove\n", dev->minor);
-
 	das16_reset(dev);
-
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 4);
-
 	if (devpriv) {
 		int i;
 		for (i = 0; i < 2; i++) {
@@ -1698,10 +1381,8 @@
 		kfree(devpriv->user_ai_range_table);
 		kfree(devpriv->user_ao_range_table);
 	}
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (dev->iobase) {
 		if (thisboard->size < 0x400) {
 			release_region(dev->iobase, thisboard->size);
@@ -1711,80 +1392,318 @@
 				       thisboard->size & 0x3ff);
 		}
 	}
-
-	return 0;
 }
 
-static int __init driver_das16_init_module(void)
-{
-	return comedi_driver_register(&driver_das16);
-}
+static const struct das16_board das16_boards[] = {
+	{
+		.name		= "das-16",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 15000,
+		.ai_pg		= das16_pg_none,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x10,
+		.i8254_offset	= 0x0c,
+		.size		= 0x14,
+		.id		= 0x00,
+	}, {
+		.name		= "das-16g",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 15000,
+		.ai_pg		= das16_pg_none,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x10,
+		.i8254_offset	= 0x0c,
+		.size		= 0x14,
+		.id		= 0x00,
+	}, {
+		.name		= "das-16f",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 8500,
+		.ai_pg		= das16_pg_none,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x10,
+		.i8254_offset	= 0x0c,
+		.size		= 0x14,
+		.id		= 0x00,
+	}, {
+		.name		= "cio-das16",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 20000,
+		.ai_pg		= das16_pg_none,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x10,
+		.i8254_offset	= 0x0c,
+		.size		= 0x14,
+		.id		= 0x80,
+	}, {
+		.name		= "cio-das16/f",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_none,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x10,
+		.i8254_offset	= 0x0c,
+		.size		= 0x14,
+		.id		= 0x80,
+	}, {
+		.name		= "cio-das16/jr",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 7692,
+		.ai_pg		= das16_pg_16jr,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x10,
+		.id		= 0x00,
+	}, {
+		.name		= "pc104-das16jr",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 3300,
+		.ai_pg		= das16_pg_16jr,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x10,
+		.id		= 0x00,
+	}, {
+		.name		= "cio-das16jr/16",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 16,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_16jr_16,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x10,
+		.id		= 0x00,
+	}, {
+		.name		= "pc104-das16jr/16",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 16,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_16jr_16,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x10,
+		.id		= 0x00,
+	}, {
+		.name		= "das-1201",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 20000,
+		.ai_pg		= das16_pg_none,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x400,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0x20,
+	}, {
+		.name		= "das-1202",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_none,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x400,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0x20,
+	}, {
+		.name		= "das-1401",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1601,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "das-1402",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "das-1601",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1601,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x400,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "das-1602",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x400,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1401/12",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 6250,
+		.ai_pg		= das16_pg_1601,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1402/12",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 6250,
+		.ai_pg		= das16_pg_1602,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1402/16",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 16,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1601/12",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 6250,
+		.ai_pg		= das16_pg_1601,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x400,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1602/12",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x400,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1602/16",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 16,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.ao		= das16_ao_winsn,
+		.ao_nbits	= 12,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0x400,
+		.i8254_offset	= 0x0c,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das16/330",
+		.ai		= das16_ai_rinsn,
+		.ai_nbits	= 12,
+		.ai_speed	= 3030,
+		.ai_pg		= das16_pg_16jr,
+		.ao		= NULL,
+		.di		= das16_di_rbits,
+		.do_		= das16_do_wbits,
+		.i8255_offset	= 0,
+		.i8254_offset	= 0x0c,
+		.size		= 0x14,
+		.id		= 0xf0,
+	},
+};
 
-static void __exit driver_das16_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_das16);
-}
-
-module_init(driver_das16_init_module);
-module_exit(driver_das16_cleanup_module);
-
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
-						struct comedi_cmd cmd)
-{
-	unsigned int size;
-	unsigned int freq;
-
-	/* if we are using timer interrupt, we don't care how long it
-	 * will take to complete transfer since it will be interrupted
-	 * by timer interrupt */
-	if (devpriv->timer_mode)
-		return DAS16_DMA_SIZE;
-
-	/* otherwise, we are relying on dma terminal count interrupt,
-	 * so pick a reasonable size */
-	if (cmd.convert_src == TRIG_TIMER)
-		freq = 1000000000 / cmd.convert_arg;
-	else if (cmd.scan_begin_src == TRIG_TIMER)
-		freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len;
-	/*  return some default value */
-	else
-		freq = 0xffffffff;
-
-	if (cmd.flags & TRIG_WAKE_EOS) {
-		size = sample_size * cmd.chanlist_len;
-	} else {
-		/*  make buffer fill in no more than 1/3 second */
-		size = (freq / 3) * sample_size;
-	}
-
-	/*  set a minimum and maximum size allowed */
-	if (size > DAS16_DMA_SIZE)
-		size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size;
-	else if (size < sample_size)
-		size = sample_size;
-
-	if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
-		size = devpriv->adc_byte_count;
-
-	return size;
-}
-
-static void das16_ai_munge(struct comedi_device *dev,
-			   struct comedi_subdevice *s, void *array,
-			   unsigned int num_bytes,
-			   unsigned int start_chan_index)
-{
-	unsigned int i, num_samples = num_bytes / sizeof(short);
-	short *data = array;
-
-	for (i = 0; i < num_samples; i++) {
-		data[i] = le16_to_cpu(data[i]);
-		if (thisboard->ai_nbits == 12)
-			data[i] = (data[i] >> 4) & 0xfff;
-
-	}
-}
+static struct comedi_driver das16_driver = {
+	.driver_name	= "das16",
+	.module		= THIS_MODULE,
+	.attach		= das16_attach,
+	.detach		= das16_detach,
+	.board_name	= &das16_boards[0].name,
+	.num_names	= ARRAY_SIZE(das16_boards),
+	.offset		= sizeof(das16_boards[0]),
+};
+module_comedi_driver(das16_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 5376e71..d2e1490 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -132,57 +132,11 @@
 	 }
 };
 
-static int das16m1_do_wbits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das16m1_di_rbits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das16m1_ai_rinsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-
-static int das16m1_cmd_test(struct comedi_device *dev,
-			    struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int das16m1_cmd_exec(struct comedi_device *dev,
-			    struct comedi_subdevice *s);
-static int das16m1_cancel(struct comedi_device *dev,
-			  struct comedi_subdevice *s);
-
-static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s);
-static irqreturn_t das16m1_interrupt(int irq, void *d);
-static void das16m1_handler(struct comedi_device *dev, unsigned int status);
-
-static unsigned int das16m1_set_pacer(struct comedi_device *dev,
-				      unsigned int ns, int round_flag);
-
-static int das16m1_irq_bits(unsigned int irq);
-
 struct das16m1_board {
 	const char *name;
 	unsigned int ai_speed;
 };
 
-static const struct das16m1_board das16m1_boards[] = {
-	{
-	 .name = "cio-das16/m1",	/*  CIO-DAS16_M1.pdf */
-	 .ai_speed = 1000,	/*  1MHz max speed */
-	 },
-};
-
-static int das16m1_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int das16m1_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das16m1 = {
-	.driver_name = "das16m1",
-	.module = THIS_MODULE,
-	.attach = das16m1_attach,
-	.detach = das16m1_detach,
-	.board_name = &das16m1_boards[0].name,
-	.num_names = ARRAY_SIZE(das16m1_boards),
-	.offset = sizeof(das16m1_boards[0]),
-};
-
 struct das16m1_private_struct {
 	unsigned int control_state;
 	volatile unsigned int adc_count;	/*  number of samples completed */
@@ -198,24 +152,19 @@
 #define devpriv ((struct das16m1_private_struct *)(dev->private))
 #define thisboard ((const struct das16m1_board *)(dev->board_ptr))
 
-static int __init driver_das16m1_init_module(void)
-{
-	return comedi_driver_register(&driver_das16m1);
-}
-
-static void __exit driver_das16m1_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_das16m1);
-}
-
-module_init(driver_das16m1_init_module);
-module_exit(driver_das16m1_cleanup_module);
-
 static inline short munge_sample(short data)
 {
 	return (data >> 4) & 0xfff;
 }
 
+static void munge_sample_array(short *array, unsigned int num_elements)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_elements; i++)
+		array[i] = munge_sample(array[i]);
+}
+
 static int das16m1_cmd_test(struct comedi_device *dev,
 			    struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
@@ -340,6 +289,25 @@
 	return 0;
 }
 
+/* This function takes a time in nanoseconds and sets the     *
+ * 2 pacer clocks to the closest frequency possible. It also  *
+ * returns the actual sampling period.                        */
+static unsigned int das16m1_set_pacer(struct comedi_device *dev,
+				      unsigned int ns, int rounding_flags)
+{
+	i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1),
+				       &(devpriv->divisor2), &ns,
+				       rounding_flags & TRIG_ROUND_MASK);
+
+	/* Write the values of ctr1 and ctr2 into counters 1 and 2 */
+	i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1,
+		   2);
+	i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2,
+		   2);
+
+	return ns;
+}
+
 static int das16m1_cmd_exec(struct comedi_device *dev,
 			    struct comedi_subdevice *s)
 {
@@ -484,57 +452,6 @@
 	return 2;
 }
 
-static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
-{
-	unsigned long flags;
-	unsigned int status;
-
-	/*  prevent race with interrupt handler */
-	spin_lock_irqsave(&dev->spinlock, flags);
-	status = inb(dev->iobase + DAS16M1_CS);
-	das16m1_handler(dev, status);
-	spin_unlock_irqrestore(&dev->spinlock, flags);
-
-	return s->async->buf_write_count - s->async->buf_read_count;
-}
-
-static irqreturn_t das16m1_interrupt(int irq, void *d)
-{
-	int status;
-	struct comedi_device *dev = d;
-
-	if (dev->attached == 0) {
-		comedi_error(dev, "premature interrupt");
-		return IRQ_HANDLED;
-	}
-	/*  prevent race with comedi_poll() */
-	spin_lock(&dev->spinlock);
-
-	status = inb(dev->iobase + DAS16M1_CS);
-
-	if ((status & (IRQDATA | OVRUN)) == 0) {
-		comedi_error(dev, "spurious interrupt");
-		spin_unlock(&dev->spinlock);
-		return IRQ_NONE;
-	}
-
-	das16m1_handler(dev, status);
-
-	/* clear interrupt */
-	outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
-
-	spin_unlock(&dev->spinlock);
-	return IRQ_HANDLED;
-}
-
-static void munge_sample_array(short *array, unsigned int num_elements)
-{
-	unsigned int i;
-
-	for (i = 0; i < num_elements; i++)
-		array[i] = munge_sample(array[i]);
-}
-
 static void das16m1_handler(struct comedi_device *dev, unsigned int status)
 {
 	struct comedi_subdevice *s;
@@ -596,23 +513,47 @@
 
 }
 
-/* This function takes a time in nanoseconds and sets the     *
- * 2 pacer clocks to the closest frequency possible. It also  *
- * returns the actual sampling period.                        */
-static unsigned int das16m1_set_pacer(struct comedi_device *dev,
-				      unsigned int ns, int rounding_flags)
+static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
 {
-	i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1),
-				       &(devpriv->divisor2), &ns,
-				       rounding_flags & TRIG_ROUND_MASK);
+	unsigned long flags;
+	unsigned int status;
 
-	/* Write the values of ctr1 and ctr2 into counters 1 and 2 */
-	i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1,
-		   2);
-	i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2,
-		   2);
+	/*  prevent race with interrupt handler */
+	spin_lock_irqsave(&dev->spinlock, flags);
+	status = inb(dev->iobase + DAS16M1_CS);
+	das16m1_handler(dev, status);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
 
-	return ns;
+	return s->async->buf_write_count - s->async->buf_read_count;
+}
+
+static irqreturn_t das16m1_interrupt(int irq, void *d)
+{
+	int status;
+	struct comedi_device *dev = d;
+
+	if (dev->attached == 0) {
+		comedi_error(dev, "premature interrupt");
+		return IRQ_HANDLED;
+	}
+	/*  prevent race with comedi_poll() */
+	spin_lock(&dev->spinlock);
+
+	status = inb(dev->iobase + DAS16M1_CS);
+
+	if ((status & (IRQDATA | OVRUN)) == 0) {
+		comedi_error(dev, "spurious interrupt");
+		spin_unlock(&dev->spinlock);
+		return IRQ_NONE;
+	}
+
+	das16m1_handler(dev, status);
+
+	/* clear interrupt */
+	outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
+
+	spin_unlock(&dev->spinlock);
+	return IRQ_HANDLED;
 }
 
 static int das16m1_irq_bits(unsigned int irq)
@@ -656,7 +597,6 @@
  *   0  I/O base
  *   1  IRQ
  */
-
 static int das16m1_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
@@ -673,12 +613,12 @@
 
 	dev->board_name = thisboard->name;
 
-	if (!request_region(iobase, DAS16M1_SIZE, driver_das16m1.driver_name)) {
+	if (!request_region(iobase, DAS16M1_SIZE, dev->driver->driver_name)) {
 		comedi_error(dev, "I/O port conflict\n");
 		return -EIO;
 	}
 	if (!request_region(iobase + DAS16M1_82C55, DAS16M1_SIZE2,
-			    driver_das16m1.driver_name)) {
+			    dev->driver->driver_name)) {
 		release_region(iobase, DAS16M1_SIZE);
 		comedi_error(dev, "I/O port conflict\n");
 		return -EIO;
@@ -690,7 +630,7 @@
 	/*  make sure it is valid */
 	if (das16m1_irq_bits(irq) >= 0) {
 		ret = request_irq(irq, das16m1_interrupt, 0,
-				  driver_das16m1.driver_name, dev);
+				  dev->driver->driver_name, dev);
 		if (ret < 0)
 			return ret;
 		dev->irq = irq;
@@ -763,25 +703,36 @@
 	return 0;
 }
 
-static int das16m1_detach(struct comedi_device *dev)
+static void das16m1_detach(struct comedi_device *dev)
 {
-
-/* das16m1_reset(dev); */
-
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 3);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (dev->iobase) {
 		release_region(dev->iobase, DAS16M1_SIZE);
 		release_region(dev->iobase + DAS16M1_82C55, DAS16M1_SIZE2);
 	}
-
-	return 0;
 }
 
+static const struct das16m1_board das16m1_boards[] = {
+	{
+		.name		= "cio-das16/m1",	/*  CIO-DAS16_M1.pdf */
+		.ai_speed	= 1000,			/*  1MHz max speed */
+	},
+};
+
+static struct comedi_driver das16m1_driver = {
+	.driver_name	= "das16m1",
+	.module		= THIS_MODULE,
+	.attach		= das16m1_attach,
+	.detach		= das16m1_detach,
+	.board_name	= &das16m1_boards[0].name,
+	.num_names	= ARRAY_SIZE(das16m1_boards),
+	.offset		= sizeof(das16m1_boards[0]),
+};
+module_comedi_driver(das16m1_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 99ada5a..2ac3443 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -183,9 +183,6 @@
 	das1802hr, das1802hr_da, das1801hc, das1802hc, das1801ao, das1802ao
 };
 
-static int das1800_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int das1800_detach(struct comedi_device *dev);
 static int das1800_probe(struct comedi_device *dev);
 static int das1800_cancel(struct comedi_device *dev,
 			  struct comedi_subdevice *s);
@@ -518,33 +515,6 @@
 };
 */
 
-static struct comedi_driver driver_das1800 = {
-	.driver_name = "das1800",
-	.module = THIS_MODULE,
-	.attach = das1800_attach,
-	.detach = das1800_detach,
-	.num_names = ARRAY_SIZE(das1800_boards),
-	.board_name = &das1800_boards[0].name,
-	.offset = sizeof(struct das1800_board),
-};
-
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __init driver_das1800_init_module(void)
-{
-	return comedi_driver_register(&driver_das1800);
-}
-
-static void __exit driver_das1800_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_das1800);
-}
-
-module_init(driver_das1800_init_module);
-module_exit(driver_das1800_cleanup_module);
-
 static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
 			    unsigned int dma1)
 {
@@ -579,7 +549,7 @@
 			return -EINVAL;
 			break;
 		}
-		if (request_dma(dma0, driver_das1800.driver_name)) {
+		if (request_dma(dma0, dev->driver->driver_name)) {
 			dev_err(dev->hw_dev, "failed to allocate dma channel %i\n",
 				dma0);
 			return -EINVAL;
@@ -587,7 +557,7 @@
 		devpriv->dma0 = dma0;
 		devpriv->dma_current = dma0;
 		if (dma1) {
-			if (request_dma(dma1, driver_das1800.driver_name)) {
+			if (request_dma(dma1, dev->driver->driver_name)) {
 				dev_err(dev->hw_dev, "failed to allocate dma channel %i\n",
 					dma1);
 				return -EINVAL;
@@ -633,7 +603,7 @@
 		return -ENOMEM;
 
 	printk(KERN_DEBUG "comedi%d: %s: io 0x%lx", dev->minor,
-	       driver_das1800.driver_name, iobase);
+	       dev->driver->driver_name, iobase);
 	if (irq) {
 		printk(KERN_CONT ", irq %u", irq);
 		if (dma0) {
@@ -650,7 +620,7 @@
 	}
 
 	/* check if io addresses are available */
-	if (!request_region(iobase, DAS1800_SIZE, driver_das1800.driver_name)) {
+	if (!request_region(iobase, DAS1800_SIZE, dev->driver->driver_name)) {
 		printk
 		    (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
 		     iobase, iobase + DAS1800_SIZE - 1);
@@ -671,7 +641,7 @@
 	if (thisboard->ao_ability == 2) {
 		iobase2 = iobase + IOBASE2;
 		if (!request_region(iobase2, DAS1800_SIZE,
-				    driver_das1800.driver_name)) {
+				    dev->driver->driver_name)) {
 			printk
 			    (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
 			     iobase2, iobase2 + DAS1800_SIZE - 1);
@@ -683,7 +653,7 @@
 	/* grab our IRQ */
 	if (irq) {
 		if (request_irq(irq, das1800_interrupt, 0,
-				driver_das1800.driver_name, dev)) {
+				dev->driver->driver_name, dev)) {
 			dev_dbg(dev->hw_dev, "unable to allocate irq %u\n",
 				irq);
 			return -EINVAL;
@@ -797,9 +767,8 @@
 	return 0;
 };
 
-static int das1800_detach(struct comedi_device *dev)
+static void das1800_detach(struct comedi_device *dev)
 {
-	/* only free stuff if it has been allocated by _attach */
 	if (dev->iobase)
 		release_region(dev->iobase, DAS1800_SIZE);
 	if (dev->irq)
@@ -814,11 +783,6 @@
 		kfree(devpriv->ai_buf0);
 		kfree(devpriv->ai_buf1);
 	}
-
-	dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
-		driver_das1800.driver_name);
-
-	return 0;
 };
 
 /* probes and checks das-1800 series board type
@@ -1811,6 +1775,17 @@
 	return size;
 }
 
+static struct comedi_driver das1800_driver = {
+	.driver_name	= "das1800",
+	.module		= THIS_MODULE,
+	.attach		= das1800_attach,
+	.detach		= das1800_detach,
+	.num_names	= ARRAY_SIZE(das1800_boards),
+	.board_name	= &das1800_boards[0].name,
+	.offset		= sizeof(struct das1800_board),
+};
+module_comedi_driver(das1800_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index f2568414..881f392 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -99,29 +99,6 @@
 #define	C2 0x80
 #define	RWLH 0x30
 
-static int das6402_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int das6402_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das6402 = {
-	.driver_name = "das6402",
-	.module = THIS_MODULE,
-	.attach = das6402_attach,
-	.detach = das6402_detach,
-};
-
-static int __init driver_das6402_init_module(void)
-{
-	return comedi_driver_register(&driver_das6402);
-}
-
-static void __exit driver_das6402_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_das6402);
-}
-
-module_init(driver_das6402_init_module);
-module_exit(driver_das6402_cleanup_module);
-
 struct das6402_private {
 	int ai_bytes_to_read;
 
@@ -130,7 +107,14 @@
 #define devpriv ((struct das6402_private *)dev->private)
 
 static void das6402_ai_fifo_dregs(struct comedi_device *dev,
-				  struct comedi_subdevice *s);
+				  struct comedi_subdevice *s)
+{
+	while (1) {
+		if (!(inb(dev->iobase + 8) & 0x01))
+			return;
+		comedi_buf_put(s->async, inw(dev->iobase));
+	}
+}
 
 static void das6402_setcounter(struct comedi_device *dev)
 {
@@ -209,16 +193,6 @@
 }
 #endif
 
-static void das6402_ai_fifo_dregs(struct comedi_device *dev,
-				  struct comedi_subdevice *s)
-{
-	while (1) {
-		if (!(inb(dev->iobase + 8) & 0x01))
-			return;
-		comedi_buf_put(s->async, inw(dev->iobase));
-	}
-}
-
 static int das6402_ai_cancel(struct comedi_device *dev,
 			     struct comedi_subdevice *s)
 {
@@ -300,16 +274,6 @@
 	return 0;
 }
 
-static int das6402_detach(struct comedi_device *dev)
-{
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-	if (dev->iobase)
-		release_region(dev->iobase, DAS6402_SIZE);
-
-	return 0;
-}
-
 static int das6402_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
@@ -363,6 +327,22 @@
 	return 0;
 }
 
+static void das6402_detach(struct comedi_device *dev)
+{
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (dev->iobase)
+		release_region(dev->iobase, DAS6402_SIZE);
+}
+
+static struct comedi_driver das6402_driver = {
+	.driver_name	= "das6402",
+	.module		= THIS_MODULE,
+	.attach		= das6402_attach,
+	.detach		= das6402_detach,
+};
+module_comedi_driver(das6402_driver)
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index 6e347b4..a3a54e1 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -245,7 +245,7 @@
 
 static int das800_attach(struct comedi_device *dev,
 			 struct comedi_devconfig *it);
-static int das800_detach(struct comedi_device *dev);
+static void das800_detach(struct comedi_device *dev);
 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
 
 static struct comedi_driver driver_das800 = {
@@ -556,16 +556,12 @@
 	return 0;
 };
 
-static int das800_detach(struct comedi_device *dev)
+static void das800_detach(struct comedi_device *dev)
 {
-	dev_info(dev->hw_dev, "comedi%d: das800: remove\n", dev->minor);
-
-	/* only free stuff if it has been allocated by _attach */
 	if (dev->iobase)
 		release_region(dev->iobase, DAS800_SIZE);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-	return 0;
 };
 
 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 2b4e6e6..8382890 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -224,7 +224,7 @@
  */
 static int dmm32at_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it);
-static int dmm32at_detach(struct comedi_device *dev);
+static void dmm32at_detach(struct comedi_device *dev);
 static struct comedi_driver driver_dmm32at = {
 	.driver_name = "dmm32at",
 	.module = THIS_MODULE,
@@ -450,23 +450,12 @@
 
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int dmm32at_detach(struct comedi_device *dev)
+static void dmm32at_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: dmm32at: remove\n", dev->minor);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->iobase)
 		release_region(dev->iobase, DMM32AT_MEMSIZE);
-
-	return 0;
 }
 
 /*
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index b85c836..625bd61 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -88,29 +88,6 @@
 #define DT2801_STATUS		1
 #define DT2801_CMD		1
 
-static int dt2801_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int dt2801_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2801 = {
-	.driver_name = "dt2801",
-	.module = THIS_MODULE,
-	.attach = dt2801_attach,
-	.detach = dt2801_detach,
-};
-
-static int __init driver_dt2801_init_module(void)
-{
-	return comedi_driver_register(&driver_dt2801);
-}
-
-static void __exit driver_dt2801_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_dt2801);
-}
-
-module_init(driver_dt2801_init_module);
-module_exit(driver_dt2801_cleanup_module);
-
 #if 0
 /* ignore 'defined but not used' warning */
 static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, {
@@ -258,22 +235,6 @@
 
 #define devpriv ((struct dt2801_private *)dev->private)
 
-static int dt2801_ai_insn_read(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int dt2801_ao_insn_read(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int dt2801_ao_insn_write(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-static int dt2801_dio_insn_bits(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-static int dt2801_dio_insn_config(struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data);
-
 /* These are the low-level routines:
    writecommand: write a command to the board
    writedata: write data byte
@@ -503,126 +464,6 @@
 	return &range_unknown;
 }
 
-/*
-   options:
-	[0] - i/o base
-	[1] - unused
-	[2] - a/d 0=differential, 1=single-ended
-	[3] - a/d range 0=[-10,10], 1=[0,10]
-	[4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
-	[5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
-*/
-static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	unsigned long iobase;
-	int board_code, type;
-	int ret = 0;
-	int n_ai_chans;
-
-	iobase = it->options[0];
-	if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) {
-		comedi_error(dev, "I/O port conflict");
-		return -EIO;
-	}
-	dev->iobase = iobase;
-
-	/* do some checking */
-
-	board_code = dt2801_reset(dev);
-
-	/* heh.  if it didn't work, try it again. */
-	if (!board_code)
-		board_code = dt2801_reset(dev);
-
-	for (type = 0; type < ARRAY_SIZE(boardtypes); type++) {
-		if (boardtypes[type].boardcode == board_code)
-			goto havetype;
-	}
-	printk("dt2801: unrecognized board code=0x%02x, contact author\n",
-	       board_code);
-	type = 0;
-
-havetype:
-	dev->board_ptr = boardtypes + type;
-	printk("dt2801: %s at port 0x%lx", boardtype.name, iobase);
-
-	n_ai_chans = probe_number_of_ai_chans(dev);
-	printk(" (ai channels = %d)", n_ai_chans);
-
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
-		goto out;
-
-	ret = alloc_private(dev, sizeof(struct dt2801_private));
-	if (ret < 0)
-		goto out;
-
-	dev->board_name = boardtype.name;
-
-	s = dev->subdevices + 0;
-	/* ai subdevice */
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_GROUND;
-#if 1
-	s->n_chan = n_ai_chans;
-#else
-	if (it->options[2])
-		s->n_chan = boardtype.ad_chan;
-	else
-		s->n_chan = boardtype.ad_chan / 2;
-#endif
-	s->maxdata = (1 << boardtype.adbits) - 1;
-	s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]);
-	s->insn_read = dt2801_ai_insn_read;
-
-	s++;
-	/* ao subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = 2;
-	s->maxdata = (1 << boardtype.dabits) - 1;
-	s->range_table_list = devpriv->dac_range_types;
-	devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
-	devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
-	s->insn_read = dt2801_ao_insn_read;
-	s->insn_write = dt2801_ao_insn_write;
-
-	s++;
-	/* 1st digital subdevice */
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 8;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = dt2801_dio_insn_bits;
-	s->insn_config = dt2801_dio_insn_config;
-
-	s++;
-	/* 2nd digital subdevice */
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 8;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = dt2801_dio_insn_bits;
-	s->insn_config = dt2801_dio_insn_config;
-
-	ret = 0;
-out:
-	printk("\n");
-
-	return ret;
-}
-
-static int dt2801_detach(struct comedi_device *dev)
-{
-	if (dev->iobase)
-		release_region(dev->iobase, DT2801_IOSIZE);
-
-	return 0;
-}
-
 static int dt2801_error(struct comedi_device *dev, int stat)
 {
 	if (stat < 0) {
@@ -740,6 +581,132 @@
 	return 1;
 }
 
+/*
+   options:
+	[0] - i/o base
+	[1] - unused
+	[2] - a/d 0=differential, 1=single-ended
+	[3] - a/d range 0=[-10,10], 1=[0,10]
+	[4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
+	[5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
+*/
+static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	unsigned long iobase;
+	int board_code, type;
+	int ret = 0;
+	int n_ai_chans;
+
+	iobase = it->options[0];
+	if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) {
+		comedi_error(dev, "I/O port conflict");
+		return -EIO;
+	}
+	dev->iobase = iobase;
+
+	/* do some checking */
+
+	board_code = dt2801_reset(dev);
+
+	/* heh.  if it didn't work, try it again. */
+	if (!board_code)
+		board_code = dt2801_reset(dev);
+
+	for (type = 0; type < ARRAY_SIZE(boardtypes); type++) {
+		if (boardtypes[type].boardcode == board_code)
+			goto havetype;
+	}
+	printk("dt2801: unrecognized board code=0x%02x, contact author\n",
+	       board_code);
+	type = 0;
+
+havetype:
+	dev->board_ptr = boardtypes + type;
+	printk("dt2801: %s at port 0x%lx", boardtype.name, iobase);
+
+	n_ai_chans = probe_number_of_ai_chans(dev);
+	printk(" (ai channels = %d)", n_ai_chans);
+
+	ret = alloc_subdevices(dev, 4);
+	if (ret < 0)
+		goto out;
+
+	ret = alloc_private(dev, sizeof(struct dt2801_private));
+	if (ret < 0)
+		goto out;
+
+	dev->board_name = boardtype.name;
+
+	s = dev->subdevices + 0;
+	/* ai subdevice */
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_GROUND;
+#if 1
+	s->n_chan = n_ai_chans;
+#else
+	if (it->options[2])
+		s->n_chan = boardtype.ad_chan;
+	else
+		s->n_chan = boardtype.ad_chan / 2;
+#endif
+	s->maxdata = (1 << boardtype.adbits) - 1;
+	s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]);
+	s->insn_read = dt2801_ai_insn_read;
+
+	s++;
+	/* ao subdevice */
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITABLE;
+	s->n_chan = 2;
+	s->maxdata = (1 << boardtype.dabits) - 1;
+	s->range_table_list = devpriv->dac_range_types;
+	devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
+	devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
+	s->insn_read = dt2801_ao_insn_read;
+	s->insn_write = dt2801_ao_insn_write;
+
+	s++;
+	/* 1st digital subdevice */
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 8;
+	s->maxdata = 1;
+	s->range_table = &range_digital;
+	s->insn_bits = dt2801_dio_insn_bits;
+	s->insn_config = dt2801_dio_insn_config;
+
+	s++;
+	/* 2nd digital subdevice */
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 8;
+	s->maxdata = 1;
+	s->range_table = &range_digital;
+	s->insn_bits = dt2801_dio_insn_bits;
+	s->insn_config = dt2801_dio_insn_config;
+
+	ret = 0;
+out:
+	printk("\n");
+
+	return ret;
+}
+
+static void dt2801_detach(struct comedi_device *dev)
+{
+	if (dev->iobase)
+		release_region(dev->iobase, DT2801_IOSIZE);
+}
+
+static struct comedi_driver dt2801_driver = {
+	.driver_name	= "dt2801",
+	.module		= THIS_MODULE,
+	.attach		= dt2801_attach,
+	.detach		= dt2801_detach,
+};
+module_comedi_driver(dt2801_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 0131d52..106ffea 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -211,61 +211,8 @@
 	const struct comedi_lrange *unip_5;
 };
 
-static const struct dt2811_board boardtypes[] = {
-	{"dt2811-pgh",
-	 &range_dt2811_pgh_ai_5_bipolar,
-	 &range_dt2811_pgh_ai_2_5_bipolar,
-	 &range_dt2811_pgh_ai_5_unipolar,
-	 },
-	{"dt2811-pgl",
-	 &range_dt2811_pgl_ai_5_bipolar,
-	 &range_dt2811_pgl_ai_2_5_bipolar,
-	 &range_dt2811_pgl_ai_5_unipolar,
-	 },
-};
-
 #define this_board ((const struct dt2811_board *)dev->board_ptr)
 
-static int dt2811_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int dt2811_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2811 = {
-	.driver_name = "dt2811",
-	.module = THIS_MODULE,
-	.attach = dt2811_attach,
-	.detach = dt2811_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = ARRAY_SIZE(boardtypes),
-	.offset = sizeof(struct dt2811_board),
-};
-
-static int __init driver_dt2811_init_module(void)
-{
-	return comedi_driver_register(&driver_dt2811);
-}
-
-static void __exit driver_dt2811_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_dt2811);
-}
-
-module_init(driver_dt2811_init_module);
-module_exit(driver_dt2811_cleanup_module);
-
-static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-static int dt2811_ao_insn_read(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int dt2811_di_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int dt2811_do_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-
 enum { card_2811_pgh, card_2811_pgl };
 
 struct dt2811_private {
@@ -317,6 +264,120 @@
 }
 #endif
 
+static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
+			  struct comedi_insn *insn, unsigned int *data)
+{
+	int chan = CR_CHAN(insn->chanspec);
+	int timeout = DT2811_TIMEOUT;
+	int i;
+
+	for (i = 0; i < insn->n; i++) {
+		outb(chan, dev->iobase + DT2811_ADGCR);
+
+		while (timeout
+		       && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
+			timeout--;
+		if (!timeout)
+			return -ETIME;
+
+		data[i] = inb(dev->iobase + DT2811_ADDATLO);
+		data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
+		data[i] &= 0xfff;
+	}
+
+	return i;
+}
+
+#if 0
+/* Wow.  This is code from the Comedi stone age.  But it hasn't been
+ * replaced, so I'll let it stay. */
+int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
+{
+	struct comedi_device *dev = comedi_devices + minor;
+
+	if (adtrig->n < 1)
+		return 0;
+	dev->curadchan = adtrig->chan;
+	switch (dev->i_admode) {
+	case COMEDI_MDEMAND:
+		dev->ntrig = adtrig->n - 1;
+		/* not necessary */
+		/*printk("dt2811: AD soft trigger\n"); */
+		/*outb(DT2811_CLRERROR|DT2811_INTENB,
+			dev->iobase+DT2811_ADCSR); */
+		outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
+		do_gettimeofday(&trigtime);
+		break;
+	case COMEDI_MCONTS:
+		dev->ntrig = adtrig->n;
+		break;
+	}
+
+	return 0;
+}
+#endif
+
+static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
+			  struct comedi_insn *insn, unsigned int *data)
+{
+	int i;
+	int chan;
+
+	chan = CR_CHAN(insn->chanspec);
+
+	for (i = 0; i < insn->n; i++) {
+		outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
+		outb((data[i] >> 8) & 0xff,
+		     dev->iobase + DT2811_DADAT0HI + 2 * chan);
+		devpriv->ao_readback[chan] = data[i];
+	}
+
+	return i;
+}
+
+static int dt2811_ao_insn_read(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn, unsigned int *data)
+{
+	int i;
+	int chan;
+
+	chan = CR_CHAN(insn->chanspec);
+
+	for (i = 0; i < insn->n; i++)
+		data[i] = devpriv->ao_readback[chan];
+
+	return i;
+}
+
+static int dt2811_di_insn_bits(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn, unsigned int *data)
+{
+	if (insn->n != 2)
+		return -EINVAL;
+
+	data[1] = inb(dev->iobase + DT2811_DIO);
+
+	return 2;
+}
+
+static int dt2811_do_insn_bits(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn, unsigned int *data)
+{
+	if (insn->n != 2)
+		return -EINVAL;
+
+	s->state &= ~data[0];
+	s->state |= data[0] & data[1];
+	outb(s->state, dev->iobase + DT2811_DIO);
+
+	data[1] = s->state;
+
+	return 2;
+}
+
 /*
   options[0]   Board base address
   options[1]   IRQ
@@ -337,7 +398,6 @@
 		 1 == bipolar 2.5V  (-2.5V -- +2.5V)
 		 2 == unipolar 5V  (0V -- +5V)
 */
-
 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	/* int i, irq; */
@@ -511,131 +571,38 @@
 	return 0;
 }
 
-static int dt2811_detach(struct comedi_device *dev)
+static void dt2811_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->iobase)
 		release_region(dev->iobase, DT2811_SIZE);
-
-	return 0;
 }
 
-static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data)
-{
-	int chan = CR_CHAN(insn->chanspec);
-	int timeout = DT2811_TIMEOUT;
-	int i;
+static const struct dt2811_board boardtypes[] = {
+	{
+		.name		= "dt2811-pgh",
+		.bip_5		= &range_dt2811_pgh_ai_5_bipolar,
+		.bip_2_5	= &range_dt2811_pgh_ai_2_5_bipolar,
+		.unip_5		= &range_dt2811_pgh_ai_5_unipolar,
+	}, {
+		.name		= "dt2811-pgl",
+		.bip_5		= &range_dt2811_pgl_ai_5_bipolar,
+		.bip_2_5	= &range_dt2811_pgl_ai_2_5_bipolar,
+		.unip_5		= &range_dt2811_pgl_ai_5_unipolar,
+	},
+};
 
-	for (i = 0; i < insn->n; i++) {
-		outb(chan, dev->iobase + DT2811_ADGCR);
-
-		while (timeout
-		       && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
-			timeout--;
-		if (!timeout)
-			return -ETIME;
-
-		data[i] = inb(dev->iobase + DT2811_ADDATLO);
-		data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
-		data[i] &= 0xfff;
-	}
-
-	return i;
-}
-
-#if 0
-/* Wow.  This is code from the Comedi stone age.  But it hasn't been
- * replaced, so I'll let it stay. */
-int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
-{
-	struct comedi_device *dev = comedi_devices + minor;
-
-	if (adtrig->n < 1)
-		return 0;
-	dev->curadchan = adtrig->chan;
-	switch (dev->i_admode) {
-	case COMEDI_MDEMAND:
-		dev->ntrig = adtrig->n - 1;
-		/* not necessary */
-		/*printk("dt2811: AD soft trigger\n"); */
-		/*outb(DT2811_CLRERROR|DT2811_INTENB,
-			dev->iobase+DT2811_ADCSR); */
-		outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
-		do_gettimeofday(&trigtime);
-		break;
-	case COMEDI_MCONTS:
-		dev->ntrig = adtrig->n;
-		break;
-	}
-
-	return 0;
-}
-#endif
-
-static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data)
-{
-	int i;
-	int chan;
-
-	chan = CR_CHAN(insn->chanspec);
-
-	for (i = 0; i < insn->n; i++) {
-		outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
-		outb((data[i] >> 8) & 0xff,
-		     dev->iobase + DT2811_DADAT0HI + 2 * chan);
-		devpriv->ao_readback[chan] = data[i];
-	}
-
-	return i;
-}
-
-static int dt2811_ao_insn_read(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
-{
-	int i;
-	int chan;
-
-	chan = CR_CHAN(insn->chanspec);
-
-	for (i = 0; i < insn->n; i++)
-		data[i] = devpriv->ao_readback[chan];
-
-	return i;
-}
-
-static int dt2811_di_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
-{
-	if (insn->n != 2)
-		return -EINVAL;
-
-	data[1] = inb(dev->iobase + DT2811_DIO);
-
-	return 2;
-}
-
-static int dt2811_do_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
-{
-	if (insn->n != 2)
-		return -EINVAL;
-
-	s->state &= ~data[0];
-	s->state |= data[0] & data[1];
-	outb(s->state, dev->iobase + DT2811_DIO);
-
-	data[1] = s->state;
-
-	return 2;
-}
+static struct comedi_driver dt2811_driver = {
+	.driver_name	= "dt2811",
+	.module		= THIS_MODULE,
+	.attach		= dt2811_attach,
+	.detach		= dt2811_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct dt2811_board),
+};
+module_comedi_driver(dt2811_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index 1c6248c..fa4ade6 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -60,31 +60,6 @@
 #define DT2814_ENB 0x10
 #define DT2814_CHANMASK 0x0f
 
-static int dt2814_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int dt2814_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2814 = {
-	.driver_name = "dt2814",
-	.module = THIS_MODULE,
-	.attach = dt2814_attach,
-	.detach = dt2814_detach,
-};
-
-static int __init driver_dt2814_init_module(void)
-{
-	return comedi_driver_register(&driver_dt2814);
-}
-
-static void __exit driver_dt2814_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_dt2814);
-}
-
-module_init(driver_dt2814_init_module);
-module_exit(driver_dt2814_cleanup_module);
-
-static irqreturn_t dt2814_interrupt(int irq, void *dev);
-
 struct dt2814_private {
 
 	int ntrig;
@@ -260,6 +235,45 @@
 
 }
 
+static irqreturn_t dt2814_interrupt(int irq, void *d)
+{
+	int lo, hi;
+	struct comedi_device *dev = d;
+	struct comedi_subdevice *s;
+	int data;
+
+	if (!dev->attached) {
+		comedi_error(dev, "spurious interrupt");
+		return IRQ_HANDLED;
+	}
+
+	s = dev->subdevices + 0;
+
+	hi = inb(dev->iobase + DT2814_DATA);
+	lo = inb(dev->iobase + DT2814_DATA);
+
+	data = (hi << 4) | (lo >> 4);
+
+	if (!(--devpriv->ntrig)) {
+		int i;
+
+		outb(0, dev->iobase + DT2814_CSR);
+		/* note: turning off timed mode triggers another
+		   sample. */
+
+		for (i = 0; i < DT2814_TIMEOUT; i++) {
+			if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH)
+				break;
+		}
+		inb(dev->iobase + DT2814_DATA);
+		inb(dev->iobase + DT2814_DATA);
+
+		s->async->events |= COMEDI_CB_EOA;
+	}
+	comedi_event(dev, s);
+	return IRQ_HANDLED;
+}
+
 static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	int i, irq;
@@ -347,57 +361,21 @@
 	return 0;
 }
 
-static int dt2814_detach(struct comedi_device *dev)
+static void dt2814_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: dt2814: remove\n", dev->minor);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (dev->iobase)
 		release_region(dev->iobase, DT2814_SIZE);
-
-	return 0;
 }
 
-static irqreturn_t dt2814_interrupt(int irq, void *d)
-{
-	int lo, hi;
-	struct comedi_device *dev = d;
-	struct comedi_subdevice *s;
-	int data;
-
-	if (!dev->attached) {
-		comedi_error(dev, "spurious interrupt");
-		return IRQ_HANDLED;
-	}
-
-	s = dev->subdevices + 0;
-
-	hi = inb(dev->iobase + DT2814_DATA);
-	lo = inb(dev->iobase + DT2814_DATA);
-
-	data = (hi << 4) | (lo >> 4);
-
-	if (!(--devpriv->ntrig)) {
-		int i;
-
-		outb(0, dev->iobase + DT2814_CSR);
-		/* note: turning off timed mode triggers another
-		   sample. */
-
-		for (i = 0; i < DT2814_TIMEOUT; i++) {
-			if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH)
-				break;
-		}
-		inb(dev->iobase + DT2814_DATA);
-		inb(dev->iobase + DT2814_DATA);
-
-		s->async->events |= COMEDI_CB_EOA;
-	}
-	comedi_event(dev, s);
-	return IRQ_HANDLED;
-}
+static struct comedi_driver dt2814_driver = {
+	.driver_name	= "dt2814",
+	.module		= THIS_MODULE,
+	.attach		= dt2814_attach,
+	.detach		= dt2814_detach,
+};
+module_comedi_driver(dt2814_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index 4155da4..bbab712 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -72,31 +72,6 @@
 #define DT2815_DATA 0
 #define DT2815_STATUS 1
 
-static int dt2815_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int dt2815_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2815 = {
-	.driver_name = "dt2815",
-	.module = THIS_MODULE,
-	.attach = dt2815_attach,
-	.detach = dt2815_detach,
-};
-
-static int __init driver_dt2815_init_module(void)
-{
-	return comedi_driver_register(&driver_dt2815);
-}
-
-static void __exit driver_dt2815_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_dt2815);
-}
-
-module_init(driver_dt2815_init_module);
-module_exit(driver_dt2815_cleanup_module);
-
-static void dt2815_free_resources(struct comedi_device *dev);
-
 struct dt2815_private {
 
 	const struct comedi_lrange *range_type_list[8];
@@ -252,20 +227,19 @@
 	return 0;
 }
 
-static void dt2815_free_resources(struct comedi_device *dev)
+static void dt2815_detach(struct comedi_device *dev)
 {
 	if (dev->iobase)
 		release_region(dev->iobase, DT2815_SIZE);
 }
 
-static int dt2815_detach(struct comedi_device *dev)
-{
-	printk(KERN_INFO "comedi%d: dt2815: remove\n", dev->minor);
-
-	dt2815_free_resources(dev);
-
-	return 0;
-}
+static struct comedi_driver dt2815_driver = {
+	.driver_name	= "dt2815",
+	.module		= THIS_MODULE,
+	.attach		= dt2815_attach,
+	.detach		= dt2815_detach,
+};
+module_comedi_driver(dt2815_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c
index 99c1584..1ee10e7b 100644
--- a/drivers/staging/comedi/drivers/dt2817.c
+++ b/drivers/staging/comedi/drivers/dt2817.c
@@ -47,29 +47,6 @@
 #define DT2817_CR 0
 #define DT2817_DATA 1
 
-static int dt2817_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int dt2817_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2817 = {
-	.driver_name = "dt2817",
-	.module = THIS_MODULE,
-	.attach = dt2817_attach,
-	.detach = dt2817_detach,
-};
-
-static int __init driver_dt2817_init_module(void)
-{
-	return comedi_driver_register(&driver_dt2817);
-}
-
-static void __exit driver_dt2817_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_dt2817);
-}
-
-module_init(driver_dt2817_init_module);
-module_exit(driver_dt2817_cleanup_module);
-
 static int dt2817_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
@@ -182,16 +159,20 @@
 	return 0;
 }
 
-static int dt2817_detach(struct comedi_device *dev)
+static void dt2817_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: dt2817: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, DT2817_SIZE);
-
-	return 0;
 }
 
+static struct comedi_driver dt2817_driver = {
+	.driver_name	= "dt2817",
+	.module		= THIS_MODULE,
+	.attach		= dt2817_attach,
+	.detach		= dt2817_detach,
+};
+module_comedi_driver(dt2817_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 95ebc26..736d8fa 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -221,136 +221,6 @@
 	int dabits;
 };
 
-static const struct dt282x_board boardtypes[] = {
-	{.name = "dt2821",
-	 .adbits = 12,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 20000,
-	 .ispgl = 0,
-	 .dachan = 2,
-	 .dabits = 12,
-	 },
-	{.name = "dt2821-f",
-	 .adbits = 12,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 6500,
-	 .ispgl = 0,
-	 .dachan = 2,
-	 .dabits = 12,
-	 },
-	{.name = "dt2821-g",
-	 .adbits = 12,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 4000,
-	 .ispgl = 0,
-	 .dachan = 2,
-	 .dabits = 12,
-	 },
-	{.name = "dt2823",
-	 .adbits = 16,
-	 .adchan_se = 0,
-	 .adchan_di = 4,
-	 .ai_speed = 10000,
-	 .ispgl = 0,
-	 .dachan = 2,
-	 .dabits = 16,
-	 },
-	{.name = "dt2824-pgh",
-	 .adbits = 12,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 20000,
-	 .ispgl = 0,
-	 .dachan = 0,
-	 .dabits = 0,
-	 },
-	{.name = "dt2824-pgl",
-	 .adbits = 12,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 20000,
-	 .ispgl = 1,
-	 .dachan = 0,
-	 .dabits = 0,
-	 },
-	{.name = "dt2825",
-	 .adbits = 12,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 20000,
-	 .ispgl = 1,
-	 .dachan = 2,
-	 .dabits = 12,
-	 },
-	{.name = "dt2827",
-	 .adbits = 16,
-	 .adchan_se = 0,
-	 .adchan_di = 4,
-	 .ai_speed = 10000,
-	 .ispgl = 0,
-	 .dachan = 2,
-	 .dabits = 12,
-	 },
-	{.name = "dt2828",
-	 .adbits = 12,
-	 .adchan_se = 4,
-	 .adchan_di = 0,
-	 .ai_speed = 10000,
-	 .ispgl = 0,
-	 .dachan = 2,
-	 .dabits = 12,
-	 },
-	{.name = "dt2829",
-	 .adbits = 16,
-	 .adchan_se = 8,
-	 .adchan_di = 0,
-	 .ai_speed = 33250,
-	 .ispgl = 0,
-	 .dachan = 2,
-	 .dabits = 16,
-	 },
-	{.name = "dt21-ez",
-	 .adbits = 12,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 10000,
-	 .ispgl = 0,
-	 .dachan = 2,
-	 .dabits = 12,
-	 },
-	{.name = "dt23-ez",
-	 .adbits = 16,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 10000,
-	 .ispgl = 0,
-	 .dachan = 0,
-	 .dabits = 0,
-	 },
-	{.name = "dt24-ez",
-	 .adbits = 12,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 10000,
-	 .ispgl = 0,
-	 .dachan = 0,
-	 .dabits = 0,
-	 },
-	{.name = "dt24-ez-pgl",
-	 .adbits = 12,
-	 .adchan_se = 16,
-	 .adchan_di = 8,
-	 .ai_speed = 10000,
-	 .ispgl = 1,
-	 .dachan = 0,
-	 .dabits = 0,
-	 },
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dt282x_board))
 #define this_board ((const struct dt282x_board *)dev->board_ptr)
 
 struct dt282x_private {
@@ -411,33 +281,6 @@
 			b					\
 	} while (0)
 
-static int dt282x_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int dt282x_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt282x = {
-	.driver_name = "dt282x",
-	.module = THIS_MODULE,
-	.attach = dt282x_attach,
-	.detach = dt282x_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct dt282x_board),
-};
-
-static int __init driver_dt282x_init_module(void)
-{
-	return comedi_driver_register(&driver_dt282x);
-}
-
-static void __exit driver_dt282x_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_dt282x);
-}
-
-module_init(driver_dt282x_init_module);
-module_exit(driver_dt282x_cleanup_module);
-
-static void free_resources(struct comedi_device *dev);
 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
 static int dt282x_ai_cancel(struct comedi_device *dev,
@@ -1271,6 +1114,52 @@
 	opt_ai_range, opt_ao0_range, opt_ao1_range,	/* range */
 };
 
+static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
+{
+	int ret;
+
+	devpriv->usedma = 0;
+
+	if (!dma1 && !dma2) {
+		printk(KERN_ERR " (no dma)");
+		return 0;
+	}
+
+	if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
+		return -EINVAL;
+
+	if (dma2 < dma1) {
+		int i;
+		i = dma1;
+		dma1 = dma2;
+		dma2 = i;
+	}
+
+	ret = request_dma(dma1, "dt282x A");
+	if (ret)
+		return -EBUSY;
+	devpriv->dma[0].chan = dma1;
+
+	ret = request_dma(dma2, "dt282x B");
+	if (ret)
+		return -EBUSY;
+	devpriv->dma[1].chan = dma2;
+
+	devpriv->dma_maxsize = PAGE_SIZE;
+	devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+	devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+	if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
+		printk(KERN_ERR " can't get DMA memory");
+		return -ENOMEM;
+	}
+
+	printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
+
+	devpriv->usedma = 1;
+
+	return 0;
+}
+
 /*
    options:
    0	i/o base
@@ -1442,7 +1331,7 @@
 	return 0;
 }
 
-static void free_resources(struct comedi_device *dev)
+static void dt282x_detach(struct comedi_device *dev)
 {
 	if (dev->irq)
 		free_irq(dev->irq, dev);
@@ -1460,60 +1349,146 @@
 	}
 }
 
-static int dt282x_detach(struct comedi_device *dev)
-{
-	printk(KERN_INFO "comedi%d: dt282x: remove\n", dev->minor);
+static const struct dt282x_board boardtypes[] = {
+	{
+		.name		= "dt2821",
+		.adbits		= 12,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 20000,
+		.ispgl		= 0,
+		.dachan		= 2,
+		.dabits		= 12,
+	}, {
+		.name		= "dt2821-f",
+		.adbits		= 12,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 6500,
+		.ispgl		= 0,
+		.dachan		= 2,
+		.dabits		= 12,
+	}, {
+		.name		= "dt2821-g",
+		.adbits		= 12,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 4000,
+		.ispgl		= 0,
+		.dachan		= 2,
+		.dabits		= 12,
+	}, {
+		.name		= "dt2823",
+		.adbits		= 16,
+		.adchan_se	= 0,
+		.adchan_di	= 4,
+		.ai_speed	= 10000,
+		.ispgl		= 0,
+		.dachan		= 2,
+		.dabits		= 16,
+	}, {
+		.name		= "dt2824-pgh",
+		.adbits		= 12,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 20000,
+		.ispgl		= 0,
+		.dachan		= 0,
+		.dabits		= 0,
+	}, {
+		.name		= "dt2824-pgl",
+		.adbits		= 12,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 20000,
+		.ispgl		= 1,
+		.dachan		= 0,
+		.dabits		= 0,
+	}, {
+		.name		= "dt2825",
+		.adbits		= 12,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 20000,
+		.ispgl		= 1,
+		.dachan		= 2,
+		.dabits		= 12,
+	}, {
+		.name		= "dt2827",
+		.adbits		= 16,
+		.adchan_se	= 0,
+		.adchan_di	= 4,
+		.ai_speed	= 10000,
+		.ispgl		= 0,
+		.dachan		= 2,
+		.dabits		= 12,
+	}, {
+		.name		= "dt2828",
+		.adbits		= 12,
+		.adchan_se	= 4,
+		.adchan_di	= 0,
+		.ai_speed	= 10000,
+		.ispgl		= 0,
+		.dachan		= 2,
+		.dabits		= 12,
+	}, {
+		.name		= "dt2829",
+		.adbits		= 16,
+		.adchan_se	= 8,
+		.adchan_di	= 0,
+		.ai_speed	= 33250,
+		.ispgl		= 0,
+		.dachan		= 2,
+		.dabits		= 16,
+	}, {
+		.name		= "dt21-ez",
+		.adbits		= 12,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 10000,
+		.ispgl		= 0,
+		.dachan		= 2,
+		.dabits		= 12,
+	}, {
+		.name		= "dt23-ez",
+		.adbits		= 16,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 10000,
+		.ispgl		= 0,
+		.dachan		= 0,
+		.dabits		= 0,
+	}, {
+		.name		= "dt24-ez",
+		.adbits		= 12,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 10000,
+		.ispgl		= 0,
+		.dachan		= 0,
+		.dabits		= 0,
+	}, {
+		.name		= "dt24-ez-pgl",
+		.adbits		= 12,
+		.adchan_se	= 16,
+		.adchan_di	= 8,
+		.ai_speed	= 10000,
+		.ispgl		= 1,
+		.dachan		= 0,
+		.dabits		= 0,
+	},
+};
 
-	free_resources(dev);
-
-	return 0;
-}
-
-static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
-{
-	int ret;
-
-	devpriv->usedma = 0;
-
-	if (!dma1 && !dma2) {
-		printk(KERN_ERR " (no dma)");
-		return 0;
-	}
-
-	if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
-		return -EINVAL;
-
-	if (dma2 < dma1) {
-		int i;
-		i = dma1;
-		dma1 = dma2;
-		dma2 = i;
-	}
-
-	ret = request_dma(dma1, "dt282x A");
-	if (ret)
-		return -EBUSY;
-	devpriv->dma[0].chan = dma1;
-
-	ret = request_dma(dma2, "dt282x B");
-	if (ret)
-		return -EBUSY;
-	devpriv->dma[1].chan = dma2;
-
-	devpriv->dma_maxsize = PAGE_SIZE;
-	devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
-	devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
-	if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
-		printk(KERN_ERR " can't get DMA memory");
-		return -ENOMEM;
-	}
-
-	printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
-
-	devpriv->usedma = 1;
-
-	return 0;
-}
+static struct comedi_driver dt282x_driver = {
+	.driver_name	= "dt282x",
+	.module		= THIS_MODULE,
+	.attach		= dt282x_attach,
+	.detach		= dt282x_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct dt282x_board),
+};
+module_comedi_driver(dt282x_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 0a7979e..0d27326 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -164,19 +164,6 @@
 #define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
 #define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
 
-static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
-
 #define DT3000_SIZE		(4*0x1000)
 
 /* dual-ported RAM location definitions */
@@ -276,54 +263,6 @@
 
 #define devpriv ((struct dt3k_private *)dev->private)
 
-static int dt3000_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int dt3000_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt3000 = {
-	.driver_name = "dt3000",
-	.module = THIS_MODULE,
-	.attach = dt3000_attach,
-	.detach = dt3000_detach,
-};
-
-static int __devinit driver_dt3000_pci_probe(struct pci_dev *dev,
-					     const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, driver_dt3000.driver_name);
-}
-
-static void __devexit driver_dt3000_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_dt3000_pci_driver = {
-	.id_table = dt3k_pci_table,
-	.probe = &driver_dt3000_pci_probe,
-	.remove = __devexit_p(&driver_dt3000_pci_remove)
-};
-
-static int __init driver_dt3000_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_dt3000);
-	if (retval < 0)
-		return retval;
-
-	driver_dt3000_pci_driver.name = (char *)driver_dt3000.driver_name;
-	return pci_register_driver(&driver_dt3000_pci_driver);
-}
-
-static void __exit driver_dt3000_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_dt3000_pci_driver);
-	comedi_driver_unregister(&driver_dt3000);
-}
-
-module_init(driver_dt3000_init_module);
-module_exit(driver_dt3000_cleanup_module);
-
 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
 			       struct comedi_subdevice *s);
 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
@@ -841,7 +780,77 @@
 	return i;
 }
 
-static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
+static int setup_pci(struct comedi_device *dev)
+{
+	resource_size_t addr;
+	int ret;
+
+	ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
+	if (ret < 0)
+		return ret;
+
+	addr = pci_resource_start(devpriv->pci_dev, 0);
+	devpriv->phys_addr = addr;
+	devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
+	if (!devpriv->io_addr)
+		return -ENOMEM;
+#if DEBUG
+	printk("0x%08llx mapped to %p, ",
+	       (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
+#endif
+
+	return 0;
+}
+
+static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
+{
+	int i;
+
+	for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
+	     from != NULL;
+	     from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
+		for (i = 0; i < n_dt3k_boards; i++) {
+			if (from->device == dt3k_boardtypes[i].device_id) {
+				*board = i;
+				return from;
+			}
+		}
+		printk
+		    ("unknown Data Translation PCI device found with device_id=0x%04x\n",
+		     from->device);
+	}
+	*board = -1;
+	return from;
+}
+
+static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
+{
+	int board;
+	int ret;
+	struct pci_dev *pcidev;
+
+	pcidev = NULL;
+	while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
+		if ((bus == 0 && slot == 0) ||
+		    (pcidev->bus->number == bus &&
+		     PCI_SLOT(pcidev->devfn) == slot)) {
+			break;
+		}
+	}
+	devpriv->pci_dev = pcidev;
+
+	if (board >= 0)
+		dev->board_ptr = dt3k_boardtypes + board;
+
+	if (!devpriv->pci_dev)
+		return 0;
+
+	ret = setup_pci(dev);
+	if (ret < 0)
+		return ret;
+
+	return 1;
+}
 
 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
@@ -935,11 +944,10 @@
 	return 0;
 }
 
-static int dt3000_detach(struct comedi_device *dev)
+static void dt3000_detach(struct comedi_device *dev)
 {
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (devpriv) {
 		if (devpriv->pci_dev) {
 			if (devpriv->phys_addr)
@@ -949,85 +957,45 @@
 		if (devpriv->io_addr)
 			iounmap(devpriv->io_addr);
 	}
-	/* XXX */
-
-	return 0;
 }
 
-static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
-static int setup_pci(struct comedi_device *dev);
+static struct comedi_driver dt3000_driver = {
+	.driver_name	= "dt3000",
+	.module		= THIS_MODULE,
+	.attach		= dt3000_attach,
+	.detach		= dt3000_detach,
+};
 
-static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
+static int __devinit dt3000_pci_probe(struct pci_dev *dev,
+				      const struct pci_device_id *ent)
 {
-	int board;
-	int ret;
-	struct pci_dev *pcidev;
-
-	pcidev = NULL;
-	while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
-		if ((bus == 0 && slot == 0) ||
-		    (pcidev->bus->number == bus &&
-		     PCI_SLOT(pcidev->devfn) == slot)) {
-			break;
-		}
-	}
-	devpriv->pci_dev = pcidev;
-
-	if (board >= 0)
-		dev->board_ptr = dt3k_boardtypes + board;
-
-	if (!devpriv->pci_dev)
-		return 0;
-
-	ret = setup_pci(dev);
-	if (ret < 0)
-		return ret;
-
-	return 1;
+	return comedi_pci_auto_config(dev, &dt3000_driver);
 }
 
-static int setup_pci(struct comedi_device *dev)
+static void __devexit dt3000_pci_remove(struct pci_dev *dev)
 {
-	resource_size_t addr;
-	int ret;
-
-	ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
-	if (ret < 0)
-		return ret;
-
-	addr = pci_resource_start(devpriv->pci_dev, 0);
-	devpriv->phys_addr = addr;
-	devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
-	if (!devpriv->io_addr)
-		return -ENOMEM;
-#if DEBUG
-	printk("0x%08llx mapped to %p, ",
-	       (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
-#endif
-
-	return 0;
+	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
-{
-	int i;
+static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
 
-	for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
-	     from != NULL;
-	     from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
-		for (i = 0; i < n_dt3k_boards; i++) {
-			if (from->device == dt3k_boardtypes[i].device_id) {
-				*board = i;
-				return from;
-			}
-		}
-		printk
-		    ("unknown Data Translation PCI device found with device_id=0x%04x\n",
-		     from->device);
-	}
-	*board = -1;
-	return from;
-}
+static struct pci_driver dt3000_pci_driver = {
+	.name		= "dt3000",
+	.id_table	= dt3000_pci_table,
+	.probe		= dt3000_pci_probe,
+	.remove		= __devexit_p(dt3000_pci_remove),
+};
+module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index e86ab58..22cda5c 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -196,7 +196,7 @@
 };
 
 #define DT9812_MAX_NUM_MULTI_BYTE_RDS  \
-    ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8))
+	((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8))
 
 struct dt9812_read_multi {
 	u8 count;
@@ -209,8 +209,8 @@
 };
 
 #define DT9812_MAX_NUM_MULTI_BYTE_WRTS  \
-    ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
-      sizeof(struct dt9812_write_byte))
+	((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
+	 sizeof(struct dt9812_write_byte))
 
 struct dt9812_write_multi {
 	u8 count;
@@ -224,7 +224,8 @@
 };
 
 #define DT9812_MAX_NUM_MULTI_BYTE_RMWS  \
-    ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(struct dt9812_rmw_byte))
+	((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
+	 sizeof(struct dt9812_rmw_byte))
 
 struct dt9812_rmw_multi {
 	u8 count;
@@ -365,7 +366,7 @@
 }
 
 static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count,
-					  u8 * address, u8 * value)
+					  u8 *address, u8 *value)
 {
 	struct dt9812_usb_cmd cmd;
 	int i, count, retval;
@@ -391,8 +392,8 @@
 }
 
 static int dt9812_write_multiple_registers(struct usb_dt9812 *dev,
-					   int reg_count, u8 * address,
-					   u8 * value)
+					   int reg_count, u8 *address,
+					   u8 *value)
 {
 	struct dt9812_usb_cmd cmd;
 	int i, count, retval;
@@ -430,7 +431,7 @@
 	return retval;
 }
 
-static int dt9812_digital_in(struct slot_dt9812 *slot, u8 * bits)
+static int dt9812_digital_in(struct slot_dt9812 *slot, u8 *bits)
 {
 	int result = -ENODEV;
 
@@ -476,7 +477,7 @@
 	return result;
 }
 
-static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 * bits)
+static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 *bits)
 {
 	int result = -ENODEV;
 
@@ -547,12 +548,12 @@
 		rmw->or_value = F020_MASK_ADC0CF_AMP0GN2;
 		break;
 	default:
-		err("Illegal gain %d\n", gain);
+		dev_err(&dev->interface->dev, "Illegal gain %d\n", gain);
 
 	}
 }
 
-static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 * value,
+static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 *value,
 			    enum dt9812_gain gain)
 {
 	struct dt9812_rmw_byte rmw[3];
@@ -619,7 +620,7 @@
 }
 
 static int dt9812_analog_out_shadow(struct slot_dt9812 *slot, int channel,
-				    u16 * value)
+				    u16 *value)
 {
 	int result = -ENODEV;
 
@@ -715,7 +716,7 @@
 	iface_desc = interface->cur_altsetting;
 
 	if (iface_desc->desc.bNumEndpoints != 5) {
-		err("Wrong number of endpints.");
+		dev_err(&interface->dev, "Wrong number of endpoints.\n");
 		retval = -ENODEV;
 		goto error;
 	}
@@ -781,22 +782,22 @@
 	}
 
 	if (dt9812_read_info(dev, 1, &dev->vendor, sizeof(dev->vendor)) != 0) {
-		err("Failed to read vendor.");
+		dev_err(&interface->dev, "Failed to read vendor.\n");
 		retval = -ENODEV;
 		goto error;
 	}
 	if (dt9812_read_info(dev, 3, &dev->product, sizeof(dev->product)) != 0) {
-		err("Failed to read product.");
+		dev_err(&interface->dev, "Failed to read product.\n");
 		retval = -ENODEV;
 		goto error;
 	}
 	if (dt9812_read_info(dev, 5, &dev->device, sizeof(dev->device)) != 0) {
-		err("Failed to read device.");
+		dev_err(&interface->dev, "Failed to read device.\n");
 		retval = -ENODEV;
 		goto error;
 	}
 	if (dt9812_read_info(dev, 7, &dev->serial, sizeof(dev->serial)) != 0) {
-		err("Failed to read serial.");
+		dev_err(&interface->dev, "Failed to read serial.\n");
 		retval = -ENODEV;
 		goto error;
 	}
@@ -1110,9 +1111,9 @@
 	return 0;
 }
 
-static int dt9812_detach(struct comedi_device *dev)
+static void dt9812_detach(struct comedi_device *dev)
 {
-	return 0;
+	/* Nothing to cleanup */
 }
 
 static struct comedi_driver dt9812_comedi_driver = {
@@ -1146,7 +1147,9 @@
 	result = comedi_driver_register(&dt9812_comedi_driver);
 	if (result) {
 		usb_deregister(&dt9812_usb_driver);
-		err("comedi_driver_register failed. Error number %d", result);
+		printk(KERN_ERR KBUILD_MODNAME
+			": comedi_driver_register failed. Error number %d\n",
+			result);
 	}
 
 	return result;
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index da8a2bf..b0cec7b 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -48,17 +48,6 @@
 
 static DEFINE_MUTEX(start_stop_sem);
 
-static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table);
-
-static int dyna_pci10xx_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int dyna_pci10xx_detach(struct comedi_device *dev);
-
 static const struct comedi_lrange range_pci1050_ai = { 3, {
 							  BIP_RANGE(10),
 							  BIP_RANGE(5),
@@ -113,16 +102,6 @@
 	{.name = DRV_NAME},
 };
 
-static struct comedi_driver driver_dyna_pci10xx = {
-	.driver_name = DRV_NAME,
-	.module = THIS_MODULE,
-	.attach = dyna_pci10xx_attach,
-	.detach = dyna_pci10xx_detach,
-	.board_name = &boardtypes[0].name,
-	.offset = sizeof(struct boardtype),
-	.num_names = ARRAY_SIZE(boardtypes),
-};
-
 struct dyna_pci10xx_private {
 	struct pci_dev *pci_dev;	/*  ptr to PCI device */
 	char valid;			/*  card is usable */
@@ -408,54 +387,48 @@
 	return 1;
 }
 
-static int dyna_pci10xx_detach(struct comedi_device *dev)
+static void dyna_pci10xx_detach(struct comedi_device *dev)
 {
 	if (devpriv && devpriv->pci_dev) {
 		comedi_pci_disable(devpriv->pci_dev);
 		mutex_destroy(&devpriv->mutex);
 	}
-
-	return 0;
 }
 
-static int __devinit driver_dyna_pci10xx_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
+static struct comedi_driver dyna_pci10xx_driver = {
+	.driver_name	= "dyna_pci10xx",
+	.module		= THIS_MODULE,
+	.attach		= dyna_pci10xx_attach,
+	.detach		= dyna_pci10xx_detach,
+	.board_name	= &boardtypes[0].name,
+	.offset		= sizeof(struct boardtype),
+	.num_names	= ARRAY_SIZE(boardtypes),
+};
+
+static int __devinit dyna_pci10xx_pci_probe(struct pci_dev *dev,
+					    const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_dyna_pci10xx.driver_name);
+	return comedi_pci_auto_config(dev, &dyna_pci10xx_driver);
 }
 
-static void __devexit driver_dyna_pci10xx_pci_remove(struct pci_dev *dev)
+static void __devexit dyna_pci10xx_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_dyna_pci10xx_pci_driver = {
-	.id_table = dyna_pci10xx_pci_table,
-	.probe = &driver_dyna_pci10xx_pci_probe,
-	.remove = __devexit_p(&driver_dyna_pci10xx_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table);
 
-static int __init driver_dyna_pci10xx_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_dyna_pci10xx);
-	if (retval < 0)
-		return retval;
-
-	driver_dyna_pci10xx_pci_driver.name =
-		(char *)driver_dyna_pci10xx.driver_name;
-	return pci_register_driver(&driver_dyna_pci10xx_pci_driver);
-}
-
-static void __exit driver_dyna_pci10xx_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_dyna_pci10xx_pci_driver);
-	comedi_driver_unregister(&driver_dyna_pci10xx);
-}
-
-module_init(driver_dyna_pci10xx_init_module);
-module_exit(driver_dyna_pci10xx_cleanup_module);
+static struct pci_driver dyna_pci10xx_pci_driver = {
+	.name		= "dyna_pci10xx",
+	.id_table	= dyna_pci10xx_pci_table,
+	.probe		= dyna_pci10xx_pci_probe,
+	.remove		= __devexit_p(dyna_pci10xx_pci_remove),
+};
+module_comedi_pci_driver(dyna_pci10xx_driver, dyna_pci10xx_pci_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Prashant Shah <pshah.mumbai@gmail.com>");
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index 7f49add..d2381445 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -42,38 +42,6 @@
 						      }
 };
 
-static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int fl512_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_fl512 = {
-	.driver_name = "fl512",
-	.module = THIS_MODULE,
-	.attach = fl512_attach,
-	.detach = fl512_detach,
-};
-
-static int __init driver_fl512_init_module(void)
-{
-	return comedi_driver_register(&driver_fl512);
-}
-
-static void __exit driver_fl512_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_fl512);
-}
-
-module_init(driver_fl512_init_module);
-module_exit(driver_fl512_cleanup_module);
-
-static int fl512_ai_insn(struct comedi_device *dev,
-			 struct comedi_subdevice *s, struct comedi_insn *insn,
-			 unsigned int *data);
-static int fl512_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
-			 struct comedi_insn *insn, unsigned int *data);
-static int fl512_ao_insn_readback(struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data);
-
 /*
  * fl512_ai_insn : this is the analog input function
  */
@@ -140,9 +108,6 @@
 	return n;
 }
 
-/*
- * start attach
- */
 static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	unsigned long iobase;
@@ -209,14 +174,20 @@
 	return 1;
 }
 
-static int fl512_detach(struct comedi_device *dev)
+static void fl512_detach(struct comedi_device *dev)
 {
 	if (dev->iobase)
 		release_region(dev->iobase, FL512_SIZE);
-	printk(KERN_INFO "comedi%d: fl512: dummy i detach\n", dev->minor);
-	return 0;
 }
 
+static struct comedi_driver fl512_driver = {
+	.driver_name	= "fl512",
+	.module		= THIS_MODULE,
+	.attach		= fl512_attach,
+	.detach		= fl512_detach,
+};
+module_comedi_driver(fl512_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index bc020de..8aece08 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -53,8 +53,6 @@
 #include "plx9080.h"
 #include "comedi_fc.h"
 
-static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int hpdi_detach(struct comedi_device *dev);
 static void abort_dma(struct comedi_device *dev, unsigned int channel);
 static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
 static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -287,15 +285,6 @@
 #endif
 };
 
-static DEFINE_PCI_DEVICE_TABLE(hpdi_pci_table) = {
-	{
-	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX,
-		    0x2400, 0, 0, 0}, {
-	0}
-};
-
-MODULE_DEVICE_TABLE(pci, hpdi_pci_table);
-
 static inline struct hpdi_board *board(const struct comedi_device *dev)
 {
 	return (struct hpdi_board *)dev->board_ptr;
@@ -338,51 +327,6 @@
 	return dev->private;
 }
 
-static struct comedi_driver driver_hpdi = {
-	.driver_name = "gsc_hpdi",
-	.module = THIS_MODULE,
-	.attach = hpdi_attach,
-	.detach = hpdi_detach,
-};
-
-static int __devinit driver_hpdi_pci_probe(struct pci_dev *dev,
-					   const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, driver_hpdi.driver_name);
-}
-
-static void __devexit driver_hpdi_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_hpdi_pci_driver = {
-	.id_table = hpdi_pci_table,
-	.probe = &driver_hpdi_pci_probe,
-	.remove = __devexit_p(&driver_hpdi_pci_remove)
-};
-
-static int __init driver_hpdi_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_hpdi);
-	if (retval < 0)
-		return retval;
-
-	driver_hpdi_pci_driver.name = (char *)driver_hpdi.driver_name;
-	return pci_register_driver(&driver_hpdi_pci_driver);
-}
-
-static void __exit driver_hpdi_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_hpdi_pci_driver);
-	comedi_driver_unregister(&driver_hpdi);
-}
-
-module_init(driver_hpdi_init_module);
-module_exit(driver_hpdi_cleanup_module);
-
 static int dio_config_insn(struct comedi_device *dev,
 			   struct comedi_subdevice *s, struct comedi_insn *insn,
 			   unsigned int *data)
@@ -645,7 +589,7 @@
 	       "gsc_hpdi: found %s on bus %i, slot %i\n", board(dev)->name,
 	       pcidev->bus->number, PCI_SLOT(pcidev->devfn));
 
-	if (comedi_pci_enable(pcidev, driver_hpdi.driver_name)) {
+	if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
 		printk(KERN_WARNING
 		       " failed enable PCI device and request regions\n");
 		return -EIO;
@@ -679,7 +623,7 @@
 
 	/*  get irq */
 	if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
-			driver_hpdi.driver_name, dev)) {
+			dev->driver->driver_name, dev)) {
 		printk(KERN_WARNING
 		       " unable to allocate irq %u\n", pcidev->irq);
 		return -EINVAL;
@@ -720,12 +664,10 @@
 	return init_hpdi(dev);
 }
 
-static int hpdi_detach(struct comedi_device *dev)
+static void hpdi_detach(struct comedi_device *dev)
 {
 	unsigned int i;
 
-	printk(KERN_WARNING "comedi%d: gsc_hpdi: remove\n", dev->minor);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if ((priv(dev)) && (priv(dev)->hw_dev)) {
@@ -758,7 +700,6 @@
 			comedi_pci_disable(priv(dev)->hw_dev);
 		pci_dev_put(priv(dev)->hw_dev);
 	}
-	return 0;
 }
 
 static int dio_config_block_size(struct comedi_device *dev, unsigned int *data)
@@ -1113,6 +1054,39 @@
 	return 0;
 }
 
+static struct comedi_driver gsc_hpdi_driver = {
+	.driver_name	= "gsc_hpdi",
+	.module		= THIS_MODULE,
+	.attach		= hpdi_attach,
+	.detach		= hpdi_detach,
+};
+
+static int __devinit gsc_hpdi_pci_probe(struct pci_dev *dev,
+					const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &gsc_hpdi_driver);
+}
+
+static void __devexit gsc_hpdi_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(gsc_hpdi_pci_table) = {
+	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX,
+		    0x2400, 0, 0, 0},
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, gsc_hpdi_pci_table);
+
+static struct pci_driver gsc_hpdi_pci_driver = {
+	.name		= "gsc_hpdi",
+	.id_table	= gsc_hpdi_pci_table,
+	.probe		= gsc_hpdi_pci_probe,
+	.remove		= __devexit_p(gsc_hpdi_pci_remove)
+};
+module_comedi_pci_driver(gsc_hpdi_driver, gsc_hpdi_pci_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index 126550f..fdc596f 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -121,15 +121,6 @@
 
 /*
 ==============================================================================
-	Forward declarations
-==============================================================================
-*/
-static int icp_multi_attach(struct comedi_device *dev,
-			    struct comedi_devconfig *it);
-static int icp_multi_detach(struct comedi_device *dev);
-
-/*
-==============================================================================
 	Data & Structure declarations
 ==============================================================================
 */
@@ -154,50 +145,6 @@
 	const struct comedi_lrange *rangelist_ao;	/*  rangelist for D/A */
 };
 
-static const struct boardtype boardtypes[] = {
-	{"icp_multi",		/*  Driver name */
-	 DEVICE_ID,		/*  PCI device ID */
-	 IORANGE_ICP_MULTI,	/*  I/O range length */
-	 1,			/*  1=Card supports interrupts */
-	 TYPE_ICP_MULTI,	/*  Card type = ICP MULTI */
-	 16,			/*  Num of A/D channels */
-	 8,			/*  Num of A/D channels in diff mode */
-	 4,			/*  Num of D/A channels */
-	 16,			/*  Num of digital inputs */
-	 8,			/*  Num of digital outputs */
-	 4,			/*  Num of counters */
-	 0x0fff,		/*  Resolution of A/D */
-	 0x0fff,		/*  Resolution of D/A */
-	 &range_analog,		/*  Rangelist for A/D */
-	 range_codes_analog,	/*  Range codes for programming */
-	 &range_analog},	/*  Rangelist for D/A */
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
-
-static struct comedi_driver driver_icp_multi = {
-	.driver_name = "icp_multi",
-	.module = THIS_MODULE,
-	.attach = icp_multi_attach,
-	.detach = icp_multi_detach,
-	.num_names = n_boardtypes,
-	.board_name = &boardtypes[0].name,
-	.offset = sizeof(struct boardtype),
-};
-
-static int __init driver_icp_multi_init_module(void)
-{
-	return comedi_driver_register(&driver_icp_multi);
-}
-
-static void __exit driver_icp_multi_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_icp_multi);
-}
-
-module_init(driver_icp_multi_init_module);
-module_exit(driver_icp_multi_cleanup_module);
-
 struct icp_multi_private {
 	struct pcilst_struct *card;	/*  pointer to card */
 	char valid;		/*  card is usable */
@@ -222,25 +169,81 @@
 
 /*
 ==============================================================================
-	More forward declarations
+
+Name:	setup_channel_list
+
+Description:
+	This function sets the appropriate channel selection,
+	differential input mode and range bits in the ADC Command/
+	Status register.
+
+Parameters:
+	struct comedi_device *dev	Pointer to current service structure
+	struct comedi_subdevice *s	Pointer to current subdevice structure
+	unsigned int *chanlist	Pointer to packed channel list
+	unsigned int n_chan	Number of channels to scan
+
+Returns:Void
+
 ==============================================================================
 */
-
-#if 0
-static int check_channel_list(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      unsigned int *chanlist, unsigned int n_chan);
-#endif
 static void setup_channel_list(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
-			       unsigned int *chanlist, unsigned int n_chan);
-static int icp_multi_reset(struct comedi_device *dev);
+			       unsigned int *chanlist, unsigned int n_chan)
+{
+	unsigned int i, range, chanprog;
+	unsigned int diff;
 
-/*
-==============================================================================
-	Functions
-==============================================================================
-*/
+#ifdef ICP_MULTI_EXTDEBUG
+	printk(KERN_DEBUG
+	       "icp multi EDBG:  setup_channel_list(...,%d)\n", n_chan);
+#endif
+	devpriv->act_chanlist_len = n_chan;
+	devpriv->act_chanlist_pos = 0;
+
+	for (i = 0; i < n_chan; i++) {
+		/*  Get channel */
+		chanprog = CR_CHAN(chanlist[i]);
+
+		/*  Determine if it is a differential channel (Bit 15  = 1) */
+		if (CR_AREF(chanlist[i]) == AREF_DIFF) {
+			diff = 1;
+			chanprog &= 0x0007;
+		} else {
+			diff = 0;
+			chanprog &= 0x000f;
+		}
+
+		/*  Clear channel, range and input mode bits
+		 *  in A/D command/status register */
+		devpriv->AdcCmdStatus &= 0xf00f;
+
+		/*  Set channel number and differential mode status bit */
+		if (diff) {
+			/*  Set channel number, bits 9-11 & mode, bit 6 */
+			devpriv->AdcCmdStatus |= (chanprog << 9);
+			devpriv->AdcCmdStatus |= ADC_DI;
+		} else
+			/*  Set channel number, bits 8-11 */
+			devpriv->AdcCmdStatus |= (chanprog << 8);
+
+		/*  Get range for current channel */
+		range = this_board->rangecode[CR_RANGE(chanlist[i])];
+		/*  Set range. bits 4-5 */
+		devpriv->AdcCmdStatus |= range;
+
+		/* Output channel, range, mode to ICP Multi */
+		writew(devpriv->AdcCmdStatus,
+		       devpriv->io_addr + ICP_MULTI_ADC_CSR);
+
+#ifdef ICP_MULTI_EXTDEBUG
+		printk(KERN_DEBUG
+		       "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
+		       devpriv->act_chanlist[i]);
+#endif
+	}
+
+}
 
 /*
 ==============================================================================
@@ -764,84 +767,6 @@
 /*
 ==============================================================================
 
-Name:	setup_channel_list
-
-Description:
-	This function sets the appropriate channel selection,
-	differential input mode and range bits in the ADC Command/
-	Status register.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current service structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	unsigned int *chanlist	Pointer to packed channel list
-	unsigned int n_chan	Number of channels to scan
-
-Returns:Void
-
-==============================================================================
-*/
-static void setup_channel_list(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       unsigned int *chanlist, unsigned int n_chan)
-{
-	unsigned int i, range, chanprog;
-	unsigned int diff;
-
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG:  setup_channel_list(...,%d)\n", n_chan);
-#endif
-	devpriv->act_chanlist_len = n_chan;
-	devpriv->act_chanlist_pos = 0;
-
-	for (i = 0; i < n_chan; i++) {
-		/*  Get channel */
-		chanprog = CR_CHAN(chanlist[i]);
-
-		/*  Determine if it is a differential channel (Bit 15  = 1) */
-		if (CR_AREF(chanlist[i]) == AREF_DIFF) {
-			diff = 1;
-			chanprog &= 0x0007;
-		} else {
-			diff = 0;
-			chanprog &= 0x000f;
-		}
-
-		/*  Clear channel, range and input mode bits
-		 *  in A/D command/status register */
-		devpriv->AdcCmdStatus &= 0xf00f;
-
-		/*  Set channel number and differential mode status bit */
-		if (diff) {
-			/*  Set channel number, bits 9-11 & mode, bit 6 */
-			devpriv->AdcCmdStatus |= (chanprog << 9);
-			devpriv->AdcCmdStatus |= ADC_DI;
-		} else
-			/*  Set channel number, bits 8-11 */
-			devpriv->AdcCmdStatus |= (chanprog << 8);
-
-		/*  Get range for current channel */
-		range = this_board->rangecode[CR_RANGE(chanlist[i])];
-		/*  Set range. bits 4-5 */
-		devpriv->AdcCmdStatus |= range;
-
-		/* Output channel, range, mode to ICP Multi */
-		writew(devpriv->AdcCmdStatus,
-		       devpriv->io_addr + ICP_MULTI_ADC_CSR);
-
-#ifdef ICP_MULTI_EXTDEBUG
-		printk(KERN_DEBUG
-		       "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
-		       devpriv->act_chanlist[i]);
-#endif
-	}
-
-}
-
-/*
-==============================================================================
-
 Name:	icp_multi_reset
 
 Description:
@@ -897,23 +822,6 @@
 	return 0;
 }
 
-/*
-==============================================================================
-
-Name:	icp_multi_attach
-
-Description:
-	This function sets up all the appropriate data for the current
-	device.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current device structure
-	struct comedi_devconfig *it	Pointer to current device configuration
-
-Returns:int	0 = success
-
-==============================================================================
-*/
 static int icp_multi_attach(struct comedi_device *dev,
 			    struct comedi_devconfig *it)
 {
@@ -1099,44 +1007,53 @@
 	return 0;
 }
 
-/*
-==============================================================================
-
-Name:	icp_multi_detach
-
-Description:
-	This function releases all the resources used by the current
-	device.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current device structure
-
-Returns:int	0 = success
-
-==============================================================================
-*/
-static int icp_multi_detach(struct comedi_device *dev)
+static void icp_multi_detach(struct comedi_device *dev)
 {
-
 	if (dev->private)
 		if (devpriv->valid)
 			icp_multi_reset(dev);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (dev->private && devpriv->io_addr)
 		iounmap(devpriv->io_addr);
-
 	if (dev->private && devpriv->card)
 		pci_card_free(devpriv->card);
-
 	if (--pci_list_builded == 0)
 		pci_card_list_cleanup(PCI_VENDOR_ID_ICP);
-
-	return 0;
 }
 
+static const struct boardtype boardtypes[] = {
+	{
+		.name		= "icp_multi",
+		.device_id	= DEVICE_ID,
+		.iorange	= IORANGE_ICP_MULTI,
+		.have_irq	= 1,
+		.cardtype	= TYPE_ICP_MULTI,
+		.n_aichan	= 16,
+		.n_aichand	= 8,
+		.n_aochan	= 4,
+		.n_dichan	= 16,
+		.n_dochan	= 8,
+		.n_ctrs		= 4,
+		.ai_maxdata	= 0x0fff,
+		.ao_maxdata	= 0x0fff,
+		.rangelist_ai	= &range_analog,
+		.rangecode	= range_codes_analog,
+		.rangelist_ao	= &range_analog,
+	},
+};
+
+static struct comedi_driver icp_multi_driver = {
+	.driver_name	= "icp_multi",
+	.module		= THIS_MODULE,
+	.attach		= icp_multi_attach,
+	.detach		= icp_multi_detach,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.board_name	= &boardtypes[0].name,
+	.offset		= sizeof(struct boardtype),
+};
+module_comedi_driver(icp_multi_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index e4711ef..f0a579a 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -159,17 +159,6 @@
 #define devpriv ((struct pci20xxx_private *)dev->private)
 #define CHAN (CR_CHAN(it->chanlist[0]))
 
-static int pci20xxx_attach(struct comedi_device *dev,
-			   struct comedi_devconfig *it);
-static int pci20xxx_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_pci20xxx = {
-	.driver_name = "ii_pci20kc",
-	.module = THIS_MODULE,
-	.attach = pci20xxx_attach,
-	.detach = pci20xxx_detach,
-};
-
 static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s,
 			 int opt0, int opt1);
 static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -275,11 +264,9 @@
 	return 1;
 }
 
-static int pci20xxx_detach(struct comedi_device *dev)
+static void pci20xxx_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: pci20xxx: remove\n", dev->minor);
-
-	return 0;
+	/* Nothing to cleanup */
 }
 
 /* pci20006m */
@@ -666,18 +653,13 @@
 }
 #endif
 
-static int __init driver_pci20xxx_init_module(void)
-{
-	return comedi_driver_register(&driver_pci20xxx);
-}
-
-static void __exit driver_pci20xxx_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pci20xxx);
-}
-
-module_init(driver_pci20xxx_init_module);
-module_exit(driver_pci20xxx_cleanup_module);
+static struct comedi_driver pci20xxx_driver = {
+	.driver_name	= "ii_pci20kc",
+	.module		= THIS_MODULE,
+	.attach		= pci20xxx_attach,
+	.detach		= pci20xxx_detach,
+};
+module_comedi_driver(pci20xxx_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 6a79ba1..d536a11 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -59,28 +59,6 @@
 #define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113
 #define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114
 
-static int jr3_pci_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int jr3_pci_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_jr3_pci = {
-	.driver_name = "jr3_pci",
-	.module = THIS_MODULE,
-	.attach = jr3_pci_attach,
-	.detach = jr3_pci_detach,
-};
-
-static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table);
-
 struct jr3_pci_dev_private {
 
 	struct pci_dev *pci_dev;
@@ -948,9 +926,7 @@
 	return result;
 }
 
-MODULE_FIRMWARE("comedi/jr3pci.idm");
-
-static int jr3_pci_detach(struct comedi_device *dev)
+static void jr3_pci_detach(struct comedi_device *dev)
 {
 	int i;
 	struct jr3_pci_dev_private *devpriv = dev->private;
@@ -962,56 +938,52 @@
 			for (i = 0; i < devpriv->n_channels; i++)
 				kfree(dev->subdevices[i].private);
 		}
-
 		if (devpriv->iobase)
 			iounmap((void *)devpriv->iobase);
 		if (devpriv->pci_enabled)
 			comedi_pci_disable(devpriv->pci_dev);
-
 		if (devpriv->pci_dev)
 			pci_dev_put(devpriv->pci_dev);
 	}
-	return 0;
 }
 
-static int __devinit driver_jr3_pci_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
+static struct comedi_driver jr3_pci_driver = {
+	.driver_name	= "jr3_pci",
+	.module		= THIS_MODULE,
+	.attach		= jr3_pci_attach,
+	.detach		= jr3_pci_detach,
+};
+
+static int __devinit jr3_pci_pci_probe(struct pci_dev *dev,
+				       const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_jr3_pci.driver_name);
+	return comedi_pci_auto_config(dev, &jr3_pci_driver);
 }
 
-static void __devexit driver_jr3_pci_pci_remove(struct pci_dev *dev)
+static void __devexit jr3_pci_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_jr3_pci_pci_driver = {
-	.id_table = jr3_pci_pci_table,
-	.probe = &driver_jr3_pci_pci_probe,
-	.remove = __devexit_p(&driver_jr3_pci_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table);
 
-static int __init driver_jr3_pci_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_jr3_pci);
-	if (retval < 0)
-		return retval;
-
-	driver_jr3_pci_pci_driver.name = (char *)driver_jr3_pci.driver_name;
-	return pci_register_driver(&driver_jr3_pci_pci_driver);
-}
-
-static void __exit driver_jr3_pci_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_jr3_pci_pci_driver);
-	comedi_driver_unregister(&driver_jr3_pci);
-}
-
-module_init(driver_jr3_pci_init_module);
-module_exit(driver_jr3_pci_cleanup_module);
+static struct pci_driver jr3_pci_pci_driver = {
+	.name		= "jr3_pci",
+	.id_table	= jr3_pci_pci_table,
+	.probe		= jr3_pci_pci_probe,
+	.remove		= __devexit_p(jr3_pci_pci_remove),
+};
+module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("comedi/jr3pci.idm");
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 4e9e9a0..09d1918 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -46,18 +46,6 @@
 #define PCI_VENDOR_ID_KOLTER    0x1001
 #define CNT_CARD_DEVICE_ID      0x0014
 
-/*-- function prototypes ----------------------------------------------------*/
-
-static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int cnt_detach(struct comedi_device *dev);
-
-static DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, cnt_pci_table);
-
 /*-- board specification structure ------------------------------------------*/
 
 struct cnt_board_struct {
@@ -87,51 +75,6 @@
 
 #define devpriv ((struct cnt_device_private *)dev->private)
 
-static struct comedi_driver cnt_driver = {
-	.driver_name = CNT_DRIVER_NAME,
-	.module = THIS_MODULE,
-	.attach = cnt_attach,
-	.detach = cnt_detach,
-};
-
-static int __devinit cnt_driver_pci_probe(struct pci_dev *dev,
-					  const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, cnt_driver.driver_name);
-}
-
-static void __devexit cnt_driver_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver cnt_driver_pci_driver = {
-	.id_table = cnt_pci_table,
-	.probe = &cnt_driver_pci_probe,
-	.remove = __devexit_p(&cnt_driver_pci_remove)
-};
-
-static int __init cnt_driver_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&cnt_driver);
-	if (retval < 0)
-		return retval;
-
-	cnt_driver_pci_driver.name = (char *)cnt_driver.driver_name;
-	return pci_register_driver(&cnt_driver_pci_driver);
-}
-
-static void __exit cnt_driver_cleanup_module(void)
-{
-	pci_unregister_driver(&cnt_driver_pci_driver);
-	comedi_driver_unregister(&cnt_driver);
-}
-
-module_init(cnt_driver_init_module);
-module_exit(cnt_driver_cleanup_module);
-
 /*-- counter write ----------------------------------------------------------*/
 
 /* This should be used only for resetting the counters; maybe it is better
@@ -181,8 +124,6 @@
 	return 1;
 }
 
-/*-- attach -----------------------------------------------------------------*/
-
 static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct comedi_subdevice *subdevice;
@@ -278,20 +219,47 @@
 	return 0;
 }
 
-/*-- detach -----------------------------------------------------------------*/
-
-static int cnt_detach(struct comedi_device *dev)
+static void cnt_detach(struct comedi_device *dev)
 {
 	if (devpriv && devpriv->pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(devpriv->pcidev);
 		pci_dev_put(devpriv->pcidev);
 	}
-	printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " remove\n",
-	       dev->minor);
-	return 0;
 }
 
+static struct comedi_driver ke_counter_driver = {
+	.driver_name	= "ke_counter",
+	.module		= THIS_MODULE,
+	.attach		= cnt_attach,
+	.detach		= cnt_detach,
+};
+
+static int __devinit ke_counter_pci_probe(struct pci_dev *dev,
+					  const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &ke_counter_driver);
+}
+
+static void __devexit ke_counter_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, ke_counter_pci_table);
+
+static struct pci_driver ke_counter_pci_driver = {
+	.name		= "ke_counter",
+	.id_table	= ke_counter_pci_table,
+	.probe		= ke_counter_pci_probe,
+	.remove		= __devexit_p(ke_counter_pci_remove),
+};
+module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index b0bc6bb..8ca1b546 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -65,30 +65,6 @@
 #include "me4000_fw.h"
 #endif
 
-/*=============================================================================
-  PCI device table.
-  This is used by modprobe to translate PCI IDs to drivers.
-  ===========================================================================*/
-
-static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, me4000_pci_table);
-
 static const struct me4000_board me4000_boards[] = {
 	{"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0} },
 
@@ -113,22 +89,8 @@
 #define ME4000_BOARD_VERSIONS (ARRAY_SIZE(me4000_boards) - 1)
 
 /*-----------------------------------------------------------------------------
-  Comedi function prototypes
-  ---------------------------------------------------------------------------*/
-static int me4000_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int me4000_detach(struct comedi_device *dev);
-static struct comedi_driver driver_me4000 = {
-	.driver_name = "me4000",
-	.module = THIS_MODULE,
-	.attach = me4000_attach,
-	.detach = me4000_detach,
-};
-
-/*-----------------------------------------------------------------------------
   Meilhaus function prototypes
   ---------------------------------------------------------------------------*/
-static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it);
 static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p);
 static int init_board_info(struct comedi_device *dev,
 			   struct pci_dev *pci_dev_p);
@@ -139,76 +101,10 @@
 static int xilinx_download(struct comedi_device *dev);
 static int reset_board(struct comedi_device *dev);
 
-static int me4000_dio_insn_bits(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_dio_insn_config(struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data);
-
-static int cnt_reset(struct comedi_device *dev, unsigned int channel);
-
-static int cnt_config(struct comedi_device *dev,
-		      unsigned int channel, unsigned int mode);
-
-static int me4000_cnt_insn_config(struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_cnt_insn_write(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_cnt_insn_read(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_ai_insn_read(struct comedi_device *dev,
-			       struct comedi_subdevice *subdevice,
-			       struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_ai_cancel(struct comedi_device *dev,
-			    struct comedi_subdevice *s);
-
-static int ai_check_chanlist(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_cmd *cmd);
-
-static int ai_round_cmd_args(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_cmd *cmd,
-			     unsigned int *init_ticks,
-			     unsigned int *scan_ticks,
-			     unsigned int *chan_ticks);
-
-static int ai_prepare(struct comedi_device *dev,
-		      struct comedi_subdevice *s,
-		      struct comedi_cmd *cmd,
-		      unsigned int init_ticks,
-		      unsigned int scan_ticks, unsigned int chan_ticks);
-
 static int ai_write_chanlist(struct comedi_device *dev,
 			     struct comedi_subdevice *s,
 			     struct comedi_cmd *cmd);
 
-static irqreturn_t me4000_ai_isr(int irq, void *dev_id);
-
-static int me4000_ai_do_cmd_test(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_cmd *cmd);
-
-static int me4000_ai_do_cmd(struct comedi_device *dev,
-			    struct comedi_subdevice *s);
-
-static int me4000_ao_insn_write(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_ao_insn_read(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-
 /*-----------------------------------------------------------------------------
   Meilhaus inline functions
   ---------------------------------------------------------------------------*/
@@ -262,130 +158,6 @@
 	 }
 };
 
-static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	int result;
-
-	CALL_PDEBUG("In me4000_attach()\n");
-
-	result = me4000_probe(dev, it);
-	if (result)
-		return result;
-
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.  It relies on
-	 * n_subdevices being set correctly.
-	 */
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
-
-    /*=========================================================================
-      Analog input subdevice
-      ========================================================================*/
-
-	s = dev->subdevices + 0;
-
-	if (thisboard->ai.count) {
-		s->type = COMEDI_SUBD_AI;
-		s->subdev_flags =
-		    SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
-		s->n_chan = thisboard->ai.count;
-		s->maxdata = 0xFFFF;	/*  16 bit ADC */
-		s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
-		s->range_table = &me4000_ai_range;
-		s->insn_read = me4000_ai_insn_read;
-
-		if (info->irq > 0) {
-			if (request_irq(info->irq, me4000_ai_isr,
-					IRQF_SHARED, "ME-4000", dev)) {
-				printk
-				    ("comedi%d: me4000: me4000_attach(): "
-				     "Unable to allocate irq\n", dev->minor);
-			} else {
-				dev->read_subdev = s;
-				s->subdev_flags |= SDF_CMD_READ;
-				s->cancel = me4000_ai_cancel;
-				s->do_cmdtest = me4000_ai_do_cmd_test;
-				s->do_cmd = me4000_ai_do_cmd;
-			}
-		} else {
-			printk(KERN_WARNING
-			       "comedi%d: me4000: me4000_attach(): "
-			       "No interrupt available\n", dev->minor);
-		}
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
-
-    /*=========================================================================
-      Analog output subdevice
-      ========================================================================*/
-
-	s = dev->subdevices + 1;
-
-	if (thisboard->ao.count) {
-		s->type = COMEDI_SUBD_AO;
-		s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND;
-		s->n_chan = thisboard->ao.count;
-		s->maxdata = 0xFFFF;	/*  16 bit DAC */
-		s->range_table = &me4000_ao_range;
-		s->insn_write = me4000_ao_insn_write;
-		s->insn_read = me4000_ao_insn_read;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
-
-    /*=========================================================================
-      Digital I/O subdevice
-      ========================================================================*/
-
-	s = dev->subdevices + 2;
-
-	if (thisboard->dio.count) {
-		s->type = COMEDI_SUBD_DIO;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = thisboard->dio.count * 8;
-		s->maxdata = 1;
-		s->range_table = &range_digital;
-		s->insn_bits = me4000_dio_insn_bits;
-		s->insn_config = me4000_dio_insn_config;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
-
-	/*
-	 * Check for optoisolated ME-4000 version. If one the first
-	 * port is a fixed output port and the second is a fixed input port.
-	 */
-	if (!me4000_inl(dev, info->dio_context.dir_reg)) {
-		s->io_bits |= 0xFF;
-		me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0,
-			    info->dio_context.dir_reg);
-	}
-
-    /*=========================================================================
-      Counter subdevice
-      ========================================================================*/
-
-	s = dev->subdevices + 3;
-
-	if (thisboard->cnt.count) {
-		s->type = COMEDI_SUBD_COUNTER;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = thisboard->cnt.count;
-		s->maxdata = 0xFFFF;	/*  16 bit counters */
-		s->insn_read = me4000_cnt_insn_read;
-		s->insn_write = me4000_cnt_insn_write;
-		s->insn_config = me4000_cnt_insn_config;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
-
-	return 0;
-}
-
 static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct pci_dev *pci_device = NULL;
@@ -920,22 +692,6 @@
 	return 0;
 }
 
-static int me4000_detach(struct comedi_device *dev)
-{
-	CALL_PDEBUG("In me4000_detach()\n");
-
-	if (info) {
-		if (info->pci_dev_p) {
-			reset_board(dev);
-			if (info->plx_regbase)
-				comedi_pci_disable(info->pci_dev_p);
-			pci_dev_put(info->pci_dev_p);
-		}
-	}
-
-	return 0;
-}
-
 /*=============================================================================
   Analog input section
   ===========================================================================*/
@@ -2424,43 +2180,185 @@
 	return 1;
 }
 
-static int __devinit driver_me4000_pci_probe(struct pci_dev *dev,
-					     const struct pci_device_id *ent)
+static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	return comedi_pci_auto_config(dev, driver_me4000.driver_name);
+	struct comedi_subdevice *s;
+	int result;
+
+	CALL_PDEBUG("In me4000_attach()\n");
+
+	result = me4000_probe(dev, it);
+	if (result)
+		return result;
+
+	/*
+	 * Allocate the subdevice structures.  alloc_subdevice() is a
+	 * convenient macro defined in comedidev.h.  It relies on
+	 * n_subdevices being set correctly.
+	 */
+	if (alloc_subdevices(dev, 4) < 0)
+		return -ENOMEM;
+
+    /*=========================================================================
+      Analog input subdevice
+      ========================================================================*/
+
+	s = dev->subdevices + 0;
+
+	if (thisboard->ai.count) {
+		s->type = COMEDI_SUBD_AI;
+		s->subdev_flags =
+		    SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
+		s->n_chan = thisboard->ai.count;
+		s->maxdata = 0xFFFF;	/*  16 bit ADC */
+		s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
+		s->range_table = &me4000_ai_range;
+		s->insn_read = me4000_ai_insn_read;
+
+		if (info->irq > 0) {
+			if (request_irq(info->irq, me4000_ai_isr,
+					IRQF_SHARED, "ME-4000", dev)) {
+				printk
+				    ("comedi%d: me4000: me4000_attach(): "
+				     "Unable to allocate irq\n", dev->minor);
+			} else {
+				dev->read_subdev = s;
+				s->subdev_flags |= SDF_CMD_READ;
+				s->cancel = me4000_ai_cancel;
+				s->do_cmdtest = me4000_ai_do_cmd_test;
+				s->do_cmd = me4000_ai_do_cmd;
+			}
+		} else {
+			printk(KERN_WARNING
+			       "comedi%d: me4000: me4000_attach(): "
+			       "No interrupt available\n", dev->minor);
+		}
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
+	}
+
+    /*=========================================================================
+      Analog output subdevice
+      ========================================================================*/
+
+	s = dev->subdevices + 1;
+
+	if (thisboard->ao.count) {
+		s->type = COMEDI_SUBD_AO;
+		s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND;
+		s->n_chan = thisboard->ao.count;
+		s->maxdata = 0xFFFF;	/*  16 bit DAC */
+		s->range_table = &me4000_ao_range;
+		s->insn_write = me4000_ao_insn_write;
+		s->insn_read = me4000_ao_insn_read;
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
+	}
+
+    /*=========================================================================
+      Digital I/O subdevice
+      ========================================================================*/
+
+	s = dev->subdevices + 2;
+
+	if (thisboard->dio.count) {
+		s->type = COMEDI_SUBD_DIO;
+		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+		s->n_chan = thisboard->dio.count * 8;
+		s->maxdata = 1;
+		s->range_table = &range_digital;
+		s->insn_bits = me4000_dio_insn_bits;
+		s->insn_config = me4000_dio_insn_config;
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
+	}
+
+	/*
+	 * Check for optoisolated ME-4000 version. If one the first
+	 * port is a fixed output port and the second is a fixed input port.
+	 */
+	if (!me4000_inl(dev, info->dio_context.dir_reg)) {
+		s->io_bits |= 0xFF;
+		me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0,
+			    info->dio_context.dir_reg);
+	}
+
+    /*=========================================================================
+      Counter subdevice
+      ========================================================================*/
+
+	s = dev->subdevices + 3;
+
+	if (thisboard->cnt.count) {
+		s->type = COMEDI_SUBD_COUNTER;
+		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+		s->n_chan = thisboard->cnt.count;
+		s->maxdata = 0xFFFF;	/*  16 bit counters */
+		s->insn_read = me4000_cnt_insn_read;
+		s->insn_write = me4000_cnt_insn_write;
+		s->insn_config = me4000_cnt_insn_config;
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
+	}
+
+	return 0;
 }
 
-static void __devexit driver_me4000_pci_remove(struct pci_dev *dev)
+static void me4000_detach(struct comedi_device *dev)
+{
+	if (info) {
+		if (info->pci_dev_p) {
+			reset_board(dev);
+			if (info->plx_regbase)
+				comedi_pci_disable(info->pci_dev_p);
+			pci_dev_put(info->pci_dev_p);
+		}
+	}
+}
+
+static struct comedi_driver me4000_driver = {
+	.driver_name	= "me4000",
+	.module		= THIS_MODULE,
+	.attach		= me4000_attach,
+	.detach		= me4000_detach,
+};
+
+static int __devinit me4000_pci_probe(struct pci_dev *dev,
+				      const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &me4000_driver);
+}
+
+static void __devexit me4000_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_me4000_pci_driver = {
-	.id_table = me4000_pci_table,
-	.probe = &driver_me4000_pci_probe,
-	.remove = __devexit_p(&driver_me4000_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, me4000_pci_table);
 
-static int __init driver_me4000_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_me4000);
-	if (retval < 0)
-		return retval;
-
-	driver_me4000_pci_driver.name = (char *)driver_me4000.driver_name;
-	return pci_register_driver(&driver_me4000_pci_driver);
-}
-
-static void __exit driver_me4000_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_me4000_pci_driver);
-	comedi_driver_unregister(&driver_me4000);
-}
-
-module_init(driver_me4000_init_module);
-module_exit(driver_me4000_cleanup_module);
+static struct pci_driver me4000_pci_driver = {
+	.name		= "me4000",
+	.id_table	= me4000_pci_table,
+	.probe		= me4000_pci_probe,
+	.remove		= __devexit_p(me4000_pci_remove),
+};
+module_comedi_pci_driver(me4000_driver, me4000_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 8b812e4..ffe2512 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -146,10 +146,6 @@
 #define ME_COUNTER_STARTDATA_B		0x0022	/* - | W */
 #define ME_COUNTER_VALUE_B		0x0022	/* R | - */
 
-/* Function prototypes */
-static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int me_detach(struct comedi_device *dev);
-
 static const struct comedi_lrange me2000_ai_range = {
 	8,
 	{
@@ -187,14 +183,6 @@
 	 }
 };
 
-static DEFINE_PCI_DEVICE_TABLE(me_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, me_pci_table);
-
 /* Board specification structure */
 struct me_board {
 	const char *name;	/* driver name */
@@ -247,51 +235,6 @@
 
 #define me_board_nbr (sizeof(me_boards)/sizeof(struct me_board))
 
-static struct comedi_driver me_driver = {
-	.driver_name = ME_DRIVER_NAME,
-	.module = THIS_MODULE,
-	.attach = me_attach,
-	.detach = me_detach,
-};
-
-static int __devinit me_driver_pci_probe(struct pci_dev *dev,
-					 const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, me_driver.driver_name);
-}
-
-static void __devexit me_driver_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver me_driver_pci_driver = {
-	.id_table = me_pci_table,
-	.probe = &me_driver_pci_probe,
-	.remove = __devexit_p(&me_driver_pci_remove)
-};
-
-static int __init me_driver_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&me_driver);
-	if (retval < 0)
-		return retval;
-
-	me_driver_pci_driver.name = (char *)me_driver.driver_name;
-	return pci_register_driver(&me_driver_pci_driver);
-}
-
-static void __exit me_driver_cleanup_module(void)
-{
-	pci_unregister_driver(&me_driver_pci_driver);
-	comedi_driver_unregister(&me_driver);
-}
-
-module_init(me_driver_init_module);
-module_exit(me_driver_cleanup_module);
-
 /* Private data structure */
 struct me_private_data {
 	struct pci_dev *pci_device;
@@ -669,12 +612,6 @@
 	return 0;
 }
 
-/*
- * Attach
- *
- * - Register PCI device
- * - Declare device driver capability
- */
 static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct pci_dev *pci_device = NULL;
@@ -869,8 +806,7 @@
 	return 0;
 }
 
-/* Detach */
-static int me_detach(struct comedi_device *dev)
+static void me_detach(struct comedi_device *dev)
 {
 	if (dev_private) {
 		if (dev_private->me_regbase) {
@@ -882,13 +818,44 @@
 		if (dev_private->pci_device) {
 			if (dev_private->plx_regbase_size)
 				comedi_pci_disable(dev_private->pci_device);
-
 			pci_dev_put(dev_private->pci_device);
 		}
 	}
-	return 0;
 }
 
+static struct comedi_driver me_daq_driver = {
+	.driver_name	= "me_daq",
+	.module		= THIS_MODULE,
+	.attach		= me_attach,
+	.detach		= me_detach,
+};
+
+static int __devinit me_daq_pci_probe(struct pci_dev *dev,
+				      const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &me_daq_driver);
+}
+
+static void __devexit me_daq_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(me_daq_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, me_daq_pci_table);
+
+static struct pci_driver me_daq_pci_driver = {
+	.name		= "me_daq",
+	.id_table	= me_daq_pci_table,
+	.probe		= me_daq_pci_probe,
+	.remove		= __devexit_p(me_daq_pci_remove),
+};
+module_comedi_pci_driver(me_daq_driver, me_daq_pci_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index 999551f..83f1b27 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -66,9 +66,9 @@
 
 	struct pci_dev *pcidev;
 	resource_size_t mite_phys_addr;
-	void *mite_io_addr;
+	void __iomem *mite_io_addr;
 	resource_size_t daq_phys_addr;
-	void *daq_io_addr;
+	void __iomem *daq_io_addr;
 
 	struct mite_channel channels[MAX_MITE_DMA_CHANNELS];
 	short channel_allocated[MAX_MITE_DMA_CHANNELS];
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index dd09a6d..4304e86 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -148,131 +148,6 @@
 	 }
 };
 
-/* -------------------------------------------------------------------------- */
-static int mpc624_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int mpc624_detach(struct comedi_device *dev);
-/* -------------------------------------------------------------------------- */
-static struct comedi_driver driver_mpc624 = {
-	.driver_name = "mpc624",
-	.module = THIS_MODULE,
-	.attach = mpc624_attach,
-	.detach = mpc624_detach
-};
-
-/* -------------------------------------------------------------------------- */
-static int mpc624_ai_rinsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data);
-/* -------------------------------------------------------------------------- */
-static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	unsigned long iobase;
-
-	iobase = it->options[0];
-	printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase);
-	if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) {
-		printk(KERN_ERR "I/O port(s) in use\n");
-		return -EIO;
-	}
-
-	dev->iobase = iobase;
-	dev->board_name = "mpc624";
-
-	/*  Private structure initialization */
-	if (alloc_private(dev, sizeof(struct skel_private)) < 0)
-		return -ENOMEM;
-
-	switch (it->options[1]) {
-	case 0:
-		devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
-		printk(KERN_INFO "3.52 kHz, ");
-		break;
-	case 1:
-		devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz;
-		printk(KERN_INFO "1.76 kHz, ");
-		break;
-	case 2:
-		devpriv->ulConvertionRate = MPC624_SPEED_880_Hz;
-		printk(KERN_INFO "880 Hz, ");
-		break;
-	case 3:
-		devpriv->ulConvertionRate = MPC624_SPEED_440_Hz;
-		printk(KERN_INFO "440 Hz, ");
-		break;
-	case 4:
-		devpriv->ulConvertionRate = MPC624_SPEED_220_Hz;
-		printk(KERN_INFO "220 Hz, ");
-		break;
-	case 5:
-		devpriv->ulConvertionRate = MPC624_SPEED_110_Hz;
-		printk(KERN_INFO "110 Hz, ");
-		break;
-	case 6:
-		devpriv->ulConvertionRate = MPC624_SPEED_55_Hz;
-		printk(KERN_INFO "55 Hz, ");
-		break;
-	case 7:
-		devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz;
-		printk(KERN_INFO "27.5 Hz, ");
-		break;
-	case 8:
-		devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz;
-		printk(KERN_INFO "13.75 Hz, ");
-		break;
-	case 9:
-		devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz;
-		printk(KERN_INFO "6.875 Hz, ");
-		break;
-	default:
-		printk
-		    (KERN_ERR "illegal conversion rate setting!"
-			" Valid numbers are 0..9. Using 9 => 6.875 Hz, ");
-		devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
-	}
-
-	/*  Subdevices structures */
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
-
-	s = dev->subdevices + 0;
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_DIFF;
-	s->n_chan = 8;
-	switch (it->options[1]) {
-	default:
-		s->maxdata = 0x3FFFFFFF;
-		printk(KERN_INFO "30 bit, ");
-	}
-
-	switch (it->options[1]) {
-	case 0:
-		s->range_table = &range_mpc624_bipolar1;
-		printk(KERN_INFO "1.01V]: ");
-		break;
-	default:
-		s->range_table = &range_mpc624_bipolar10;
-		printk(KERN_INFO "10.1V]: ");
-	}
-	s->len_chanlist = 1;
-	s->insn_read = mpc624_ai_rinsn;
-
-	printk(KERN_INFO "attached\n");
-
-	return 1;
-}
-
-static int mpc624_detach(struct comedi_device *dev)
-{
-	printk(KERN_INFO "comedi%d: mpc624: remove\n", dev->minor);
-
-	if (dev->iobase)
-		release_region(dev->iobase, MPC624_SIZE);
-
-	return 0;
-}
-
 /* Timeout 200ms */
 #define TIMEOUT 200
 
@@ -406,18 +281,117 @@
 	return n;
 }
 
-static int __init driver_mpc624_init_module(void)
+static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	return comedi_driver_register(&driver_mpc624);
+	struct comedi_subdevice *s;
+	unsigned long iobase;
+
+	iobase = it->options[0];
+	printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase);
+	if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) {
+		printk(KERN_ERR "I/O port(s) in use\n");
+		return -EIO;
+	}
+
+	dev->iobase = iobase;
+	dev->board_name = "mpc624";
+
+	/*  Private structure initialization */
+	if (alloc_private(dev, sizeof(struct skel_private)) < 0)
+		return -ENOMEM;
+
+	switch (it->options[1]) {
+	case 0:
+		devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
+		printk(KERN_INFO "3.52 kHz, ");
+		break;
+	case 1:
+		devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz;
+		printk(KERN_INFO "1.76 kHz, ");
+		break;
+	case 2:
+		devpriv->ulConvertionRate = MPC624_SPEED_880_Hz;
+		printk(KERN_INFO "880 Hz, ");
+		break;
+	case 3:
+		devpriv->ulConvertionRate = MPC624_SPEED_440_Hz;
+		printk(KERN_INFO "440 Hz, ");
+		break;
+	case 4:
+		devpriv->ulConvertionRate = MPC624_SPEED_220_Hz;
+		printk(KERN_INFO "220 Hz, ");
+		break;
+	case 5:
+		devpriv->ulConvertionRate = MPC624_SPEED_110_Hz;
+		printk(KERN_INFO "110 Hz, ");
+		break;
+	case 6:
+		devpriv->ulConvertionRate = MPC624_SPEED_55_Hz;
+		printk(KERN_INFO "55 Hz, ");
+		break;
+	case 7:
+		devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz;
+		printk(KERN_INFO "27.5 Hz, ");
+		break;
+	case 8:
+		devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz;
+		printk(KERN_INFO "13.75 Hz, ");
+		break;
+	case 9:
+		devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz;
+		printk(KERN_INFO "6.875 Hz, ");
+		break;
+	default:
+		printk
+		    (KERN_ERR "illegal conversion rate setting!"
+			" Valid numbers are 0..9. Using 9 => 6.875 Hz, ");
+		devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
+	}
+
+	/*  Subdevices structures */
+	if (alloc_subdevices(dev, 1) < 0)
+		return -ENOMEM;
+
+	s = dev->subdevices + 0;
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_DIFF;
+	s->n_chan = 8;
+	switch (it->options[1]) {
+	default:
+		s->maxdata = 0x3FFFFFFF;
+		printk(KERN_INFO "30 bit, ");
+	}
+
+	switch (it->options[1]) {
+	case 0:
+		s->range_table = &range_mpc624_bipolar1;
+		printk(KERN_INFO "1.01V]: ");
+		break;
+	default:
+		s->range_table = &range_mpc624_bipolar10;
+		printk(KERN_INFO "10.1V]: ");
+	}
+	s->len_chanlist = 1;
+	s->insn_read = mpc624_ai_rinsn;
+
+	printk(KERN_INFO "attached\n");
+
+	return 1;
 }
 
-static void __exit driver_mpc624_cleanup_module(void)
+static void mpc624_detach(struct comedi_device *dev)
 {
-	comedi_driver_unregister(&driver_mpc624);
+	if (dev->iobase)
+		release_region(dev->iobase, MPC624_SIZE);
 }
 
-module_init(driver_mpc624_init_module);
-module_exit(driver_mpc624_cleanup_module);
+static struct comedi_driver mpc624_driver = {
+	.driver_name	= "mpc624",
+	.module		= THIS_MODULE,
+	.attach		= mpc624_attach,
+	.detach		= mpc624_detach
+};
+module_comedi_driver(mpc624_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/mpc8260cpm.c b/drivers/staging/comedi/drivers/mpc8260cpm.c
index 5f6816a..364470e 100644
--- a/drivers/staging/comedi/drivers/mpc8260cpm.c
+++ b/drivers/staging/comedi/drivers/mpc8260cpm.c
@@ -46,75 +46,6 @@
 
 #define devpriv ((struct mpc8260cpm_private *)dev->private)
 
-static int mpc8260cpm_attach(struct comedi_device *dev,
-			     struct comedi_devconfig *it);
-static int mpc8260cpm_detach(struct comedi_device *dev);
-static struct comedi_driver driver_mpc8260cpm = {
-	.driver_name = "mpc8260cpm",
-	.module = THIS_MODULE,
-	.attach = mpc8260cpm_attach,
-	.detach = mpc8260cpm_detach,
-};
-
-static int __init driver_mpc8260cpm_init_module(void)
-{
-	return comedi_driver_register(&driver_mpc8260cpm);
-}
-
-static void __exit driver_mpc8260cpm_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_mpc8260cpm);
-}
-
-module_init(driver_mpc8260cpm_init_module);
-module_exit(driver_mpc8260cpm_cleanup_module);
-
-static int mpc8260cpm_dio_config(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data);
-static int mpc8260cpm_dio_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-
-static int mpc8260cpm_attach(struct comedi_device *dev,
-			     struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	int i;
-
-	printk("comedi%d: mpc8260cpm: ", dev->minor);
-
-	dev->board_ptr = mpc8260cpm_boards + dev->board;
-
-	dev->board_name = thisboard->name;
-
-	if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0)
-		return -ENOMEM;
-
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
-
-	for (i = 0; i < 4; i++) {
-		s = dev->subdevices + i;
-		s->type = COMEDI_SUBD_DIO;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = 32;
-		s->maxdata = 1;
-		s->range_table = &range_digital;
-		s->insn_config = mpc8260cpm_dio_config;
-		s->insn_bits = mpc8260cpm_dio_bits;
-	}
-
-	return 1;
-}
-
-static int mpc8260cpm_detach(struct comedi_device *dev)
-{
-	printk("comedi%d: mpc8260cpm: remove\n", dev->minor);
-
-	return 0;
-}
-
 static unsigned long *cpm_pdat(int port)
 {
 	switch (port) {
@@ -184,3 +115,48 @@
 
 	return 2;
 }
+
+static int mpc8260cpm_attach(struct comedi_device *dev,
+			     struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	int i;
+
+	printk("comedi%d: mpc8260cpm: ", dev->minor);
+
+	dev->board_ptr = mpc8260cpm_boards + dev->board;
+
+	dev->board_name = thisboard->name;
+
+	if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0)
+		return -ENOMEM;
+
+	if (alloc_subdevices(dev, 4) < 0)
+		return -ENOMEM;
+
+	for (i = 0; i < 4; i++) {
+		s = dev->subdevices + i;
+		s->type = COMEDI_SUBD_DIO;
+		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+		s->n_chan = 32;
+		s->maxdata = 1;
+		s->range_table = &range_digital;
+		s->insn_config = mpc8260cpm_dio_config;
+		s->insn_bits = mpc8260cpm_dio_bits;
+	}
+
+	return 1;
+}
+
+static void mpc8260cpm_detach(struct comedi_device *dev)
+{
+	/* Nothing to cleanup */
+}
+
+static struct comedi_driver mpc8260cpm_driver = {
+	.driver_name	= "mpc8260cpm",
+	.module		= THIS_MODULE,
+	.attach		= mpc8260cpm_attach,
+	.detach		= mpc8260cpm_detach,
+};
+module_comedi_driver(mpc8260cpm_driver);
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index dace902..e951e73 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -83,29 +83,6 @@
 
 #define MULTIQ3_TIMEOUT 30
 
-static int multiq3_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int multiq3_detach(struct comedi_device *dev);
-static struct comedi_driver driver_multiq3 = {
-	.driver_name = "multiq3",
-	.module = THIS_MODULE,
-	.attach = multiq3_attach,
-	.detach = multiq3_detach,
-};
-
-static int __init driver_multiq3_init_module(void)
-{
-	return comedi_driver_register(&driver_multiq3);
-}
-
-static void __exit driver_multiq3_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_multiq3);
-}
-
-module_init(driver_multiq3_init_module);
-module_exit(driver_multiq3_cleanup_module);
-
 struct multiq3_private {
 	unsigned int ao_readback[2];
 };
@@ -338,18 +315,22 @@
 	return 0;
 }
 
-static int multiq3_detach(struct comedi_device *dev)
+static void multiq3_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: multiq3: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, MULTIQ3_SIZE);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
-	return 0;
 }
 
+static struct comedi_driver multiq3_driver = {
+	.driver_name	= "multiq3",
+	.module		= THIS_MODULE,
+	.attach		= multiq3_attach,
+	.detach		= multiq3_detach,
+};
+module_comedi_driver(multiq3_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index 54741c9..b02aa0e 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -78,7 +78,7 @@
 
 static int ni6527_attach(struct comedi_device *dev,
 			 struct comedi_devconfig *it);
-static int ni6527_detach(struct comedi_device *dev);
+static void ni6527_detach(struct comedi_device *dev);
 static struct comedi_driver driver_ni6527 = {
 	.driver_name = "ni6527",
 	.module = THIS_MODULE,
@@ -449,19 +449,15 @@
 	return 0;
 }
 
-static int ni6527_detach(struct comedi_device *dev)
+static void ni6527_detach(struct comedi_device *dev)
 {
 	if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr)
 		writeb(0x00,
 		       devpriv->mite->daq_io_addr + Master_Interrupt_Control);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (devpriv && devpriv->mite)
 		mite_unsetup(devpriv->mite);
-
-	return 0;
 }
 
 static int ni6527_find_device(struct comedi_device *dev, int bus, int slot)
@@ -493,7 +489,7 @@
 static int __devinit driver_ni6527_pci_probe(struct pci_dev *dev,
 					     const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_ni6527.driver_name);
+	return comedi_pci_auto_config(dev, &driver_ni6527);
 }
 
 static void __devexit driver_ni6527_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 403fc09..0d27a93 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -111,7 +111,7 @@
 
 static int ni_65xx_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it);
-static int ni_65xx_detach(struct comedi_device *dev);
+static void ni_65xx_detach(struct comedi_device *dev);
 static struct comedi_driver driver_ni_65xx = {
 	.driver_name = "ni_65xx",
 	.module = THIS_MODULE,
@@ -784,7 +784,7 @@
 	return 0;
 }
 
-static int ni_65xx_detach(struct comedi_device *dev)
+static void ni_65xx_detach(struct comedi_device *dev)
 {
 	if (private(dev) && private(dev)->mite
 	    && private(dev)->mite->daq_io_addr) {
@@ -792,10 +792,8 @@
 		       private(dev)->mite->daq_io_addr +
 		       Master_Interrupt_Control);
 	}
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (private(dev)) {
 		unsigned i;
 		for (i = 0; i < dev->n_subdevices; ++i) {
@@ -805,7 +803,6 @@
 		if (private(dev)->mite)
 			mite_unsetup(private(dev)->mite);
 	}
-	return 0;
 }
 
 static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot)
@@ -837,7 +834,7 @@
 static int __devinit driver_ni_65xx_pci_probe(struct pci_dev *dev,
 					      const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_ni_65xx.driver_name);
+	return comedi_pci_auto_config(dev, &driver_ni_65xx);
 }
 
 static void __devexit driver_ni_65xx_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index 35f3a47..8c40730 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -458,7 +458,7 @@
 
 static int ni_660x_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it);
-static int ni_660x_detach(struct comedi_device *dev);
+static void ni_660x_detach(struct comedi_device *dev);
 static void init_tio_chip(struct comedi_device *dev, int chipset);
 static void ni_660x_select_pfi_output(struct comedi_device *dev,
 				      unsigned pfi_channel,
@@ -474,7 +474,7 @@
 static int __devinit driver_ni_660x_pci_probe(struct pci_dev *dev,
 					      const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_ni_660x.driver_name);
+	return comedi_pci_auto_config(dev, &driver_ni_660x);
 }
 
 static void __devexit driver_ni_660x_pci_remove(struct pci_dev *dev)
@@ -761,7 +761,7 @@
 					  unsigned chip_index, unsigned bits,
 					  enum NI_660x_Register reg)
 {
-	void *const write_address =
+	void __iomem *write_address =
 	    private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
 	    registerData[reg].offset;
 
@@ -784,7 +784,7 @@
 					     unsigned chip_index,
 					     enum NI_660x_Register reg)
 {
-	void *const read_address =
+	void __iomem *read_address =
 	    private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
 	    registerData[reg].offset;
 
@@ -1188,14 +1188,10 @@
 	return 0;
 }
 
-static int ni_660x_detach(struct comedi_device *dev)
+static void ni_660x_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: ni_660x: remove\n", dev->minor);
-
-	/* Free irq */
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (dev->private) {
 		if (private(dev)->counter_dev)
 			ni_gpct_device_destroy(private(dev)->counter_dev);
@@ -1204,7 +1200,6 @@
 			mite_unsetup(private(dev)->mite);
 		}
 	}
-	return 0;
 }
 
 static int
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index d8d91f9..a9cf94f 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -111,7 +111,7 @@
 
 static int ni_670x_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it);
-static int ni_670x_detach(struct comedi_device *dev);
+static void ni_670x_detach(struct comedi_device *dev);
 
 static struct comedi_driver driver_ni_670x = {
 	.driver_name = "ni_670x",
@@ -123,7 +123,7 @@
 static int __devinit driver_ni_670x_pci_probe(struct pci_dev *dev,
 					      const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_ni_670x.driver_name);
+	return comedi_pci_auto_config(dev, &driver_ni_670x);
 }
 
 static void __devexit driver_ni_670x_pci_remove(struct pci_dev *dev)
@@ -249,19 +249,13 @@
 	return 1;
 }
 
-static int ni_670x_detach(struct comedi_device *dev)
+static void ni_670x_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: ni_670x: remove\n", dev->minor);
-
 	kfree(dev->subdevices[0].range_table_list);
-
 	if (dev->private && devpriv->mite)
 		mite_unsetup(devpriv->mite);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
-	return 0;
 }
 
 static int ni_670x_ao_winsn(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index c25e44c..ae896a0 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -171,46 +171,13 @@
 
 #define devpriv ((struct a2150_private *)dev->private)
 
-static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int a2150_detach(struct comedi_device *dev);
 static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
 
-static struct comedi_driver driver_a2150 = {
-	.driver_name = "ni_at_a2150",
-	.module = THIS_MODULE,
-	.attach = a2150_attach,
-	.detach = a2150_detach,
-};
-
-static irqreturn_t a2150_interrupt(int irq, void *d);
-static int a2150_ai_cmdtest(struct comedi_device *dev,
-			    struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
 static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
 			    int flags);
-static int a2150_probe(struct comedi_device *dev);
 static int a2150_set_chanlist(struct comedi_device *dev,
 			      unsigned int start_channel,
 			      unsigned int num_channels);
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __init driver_a2150_init_module(void)
-{
-	return comedi_driver_register(&driver_a2150);
-}
-
-static void __exit driver_a2150_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_a2150);
-}
-
-module_init(driver_a2150_init_module);
-module_exit(driver_a2150_cleanup_module);
-
 #ifdef A2150_DEBUG
 
 static void ni_dump_regs(struct comedi_device *dev)
@@ -331,161 +298,6 @@
 	return IRQ_HANDLED;
 }
 
-/* probes board type, returns offset */
-static int a2150_probe(struct comedi_device *dev)
-{
-	int status = inw(dev->iobase + STATUS_REG);
-	return ID_BITS(status);
-}
-
-static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	unsigned long iobase = it->options[0];
-	unsigned int irq = it->options[1];
-	unsigned int dma = it->options[2];
-	static const int timeout = 2000;
-	int i;
-
-	printk("comedi%d: %s: io 0x%lx", dev->minor, driver_a2150.driver_name,
-	       iobase);
-	if (irq) {
-		printk(", irq %u", irq);
-	} else {
-		printk(", no irq");
-	}
-	if (dma) {
-		printk(", dma %u", dma);
-	} else {
-		printk(", no dma");
-	}
-	printk("\n");
-
-	/* allocate and initialize dev->private */
-	if (alloc_private(dev, sizeof(struct a2150_private)) < 0)
-		return -ENOMEM;
-
-	if (iobase == 0) {
-		printk(" io base address required\n");
-		return -EINVAL;
-	}
-
-	/* check if io addresses are available */
-	if (!request_region(iobase, A2150_SIZE, driver_a2150.driver_name)) {
-		printk(" I/O port conflict\n");
-		return -EIO;
-	}
-	dev->iobase = iobase;
-
-	/* grab our IRQ */
-	if (irq) {
-		/*  check that irq is supported */
-		if (irq < 3 || irq == 8 || irq == 13 || irq > 15) {
-			printk(" invalid irq line %u\n", irq);
-			return -EINVAL;
-		}
-		if (request_irq(irq, a2150_interrupt, 0,
-				driver_a2150.driver_name, dev)) {
-			printk("unable to allocate irq %u\n", irq);
-			return -EINVAL;
-		}
-		devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
-		dev->irq = irq;
-	}
-	/*  initialize dma */
-	if (dma) {
-		if (dma == 4 || dma > 7) {
-			printk(" invalid dma channel %u\n", dma);
-			return -EINVAL;
-		}
-		if (request_dma(dma, driver_a2150.driver_name)) {
-			printk(" failed to allocate dma channel %u\n", dma);
-			return -EINVAL;
-		}
-		devpriv->dma = dma;
-		devpriv->dma_buffer =
-		    kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
-		if (devpriv->dma_buffer == NULL)
-			return -ENOMEM;
-
-		disable_dma(dma);
-		set_dma_mode(dma, DMA_MODE_READ);
-
-		devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
-	}
-
-	dev->board_ptr = a2150_boards + a2150_probe(dev);
-	dev->board_name = thisboard->name;
-
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
-
-	/* analog input subdevice */
-	s = dev->subdevices + 0;
-	dev->read_subdev = s;
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ;
-	s->n_chan = 4;
-	s->len_chanlist = 4;
-	s->maxdata = 0xffff;
-	s->range_table = &range_a2150;
-	s->do_cmd = a2150_ai_cmd;
-	s->do_cmdtest = a2150_ai_cmdtest;
-	s->insn_read = a2150_ai_rinsn;
-	s->cancel = a2150_cancel;
-
-	/* need to do this for software counting of completed conversions, to
-	 * prevent hardware count from stopping acquisition */
-	outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG);
-
-	/*  set card's irq and dma levels */
-	outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
-
-	/*  reset and sync adc clock circuitry */
-	outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG);
-	outw_p(DPD_BIT, dev->iobase + CONFIG_REG);
-	/*  initialize configuration register */
-	devpriv->config_bits = 0;
-	outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
-	/*  wait until offset calibration is done, then enable analog inputs */
-	for (i = 0; i < timeout; i++) {
-		if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0)
-			break;
-		udelay(1000);
-	}
-	if (i == timeout) {
-		printk
-		    (" timed out waiting for offset calibration to complete\n");
-		return -ETIME;
-	}
-	devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT;
-	outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
-
-	return 0;
-};
-
-static int a2150_detach(struct comedi_device *dev)
-{
-	printk("comedi%d: %s: remove\n", dev->minor, driver_a2150.driver_name);
-
-	/* only free stuff if it has been allocated by _attach */
-	if (dev->iobase) {
-		/*  put board in power-down mode */
-		outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
-		release_region(dev->iobase, A2150_SIZE);
-	}
-
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-	if (devpriv) {
-		if (devpriv->dma)
-			free_dma(devpriv->dma);
-		kfree(devpriv->dma_buffer);
-	}
-
-	return 0;
-};
-
 static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	/*  disable dma on card */
@@ -539,7 +351,10 @@
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/*
+	 * step 2: make sure trigger sources are unique and mutually
+	 * compatible
+	 */
 
 	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
 		err++;
@@ -771,7 +586,10 @@
 	/*  start acquisition for soft trigger */
 	outw(0, dev->iobase + FIFO_START_REG);
 
-	/* there is a 35.6 sample delay for data to get through the antialias filter */
+	/*
+	 * there is a 35.6 sample delay for data to get through the
+	 * antialias filter
+	 */
 	for (n = 0; n < filter_delay; n++) {
 		for (i = 0; i < timeout; i++) {
 			if (inw(dev->iobase + STATUS_REG) & FNE_BIT)
@@ -812,8 +630,10 @@
 	return n;
 }
 
-/* sets bits in devpriv->clock_bits to nearest approximation of requested period,
- * adjusts requested period to actual timing. */
+/*
+ * sets bits in devpriv->clock_bits to nearest approximation of requested
+ * period, adjusts requested period to actual timing.
+ */
 static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
 			    int flags)
 {
@@ -920,6 +740,162 @@
 	return 0;
 }
 
+/* probes board type, returns offset */
+static int a2150_probe(struct comedi_device *dev)
+{
+	int status = inw(dev->iobase + STATUS_REG);
+	return ID_BITS(status);
+}
+
+static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	unsigned long iobase = it->options[0];
+	unsigned int irq = it->options[1];
+	unsigned int dma = it->options[2];
+	static const int timeout = 2000;
+	int i;
+
+	printk("comedi%d: %s: io 0x%lx", dev->minor, dev->driver->driver_name,
+	       iobase);
+	if (irq) {
+		printk(", irq %u", irq);
+	} else {
+		printk(", no irq");
+	}
+	if (dma) {
+		printk(", dma %u", dma);
+	} else {
+		printk(", no dma");
+	}
+	printk("\n");
+
+	/* allocate and initialize dev->private */
+	if (alloc_private(dev, sizeof(struct a2150_private)) < 0)
+		return -ENOMEM;
+
+	if (iobase == 0) {
+		printk(" io base address required\n");
+		return -EINVAL;
+	}
+
+	/* check if io addresses are available */
+	if (!request_region(iobase, A2150_SIZE, dev->driver->driver_name)) {
+		printk(" I/O port conflict\n");
+		return -EIO;
+	}
+	dev->iobase = iobase;
+
+	/* grab our IRQ */
+	if (irq) {
+		/*  check that irq is supported */
+		if (irq < 3 || irq == 8 || irq == 13 || irq > 15) {
+			printk(" invalid irq line %u\n", irq);
+			return -EINVAL;
+		}
+		if (request_irq(irq, a2150_interrupt, 0,
+				dev->driver->driver_name, dev)) {
+			printk("unable to allocate irq %u\n", irq);
+			return -EINVAL;
+		}
+		devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
+		dev->irq = irq;
+	}
+	/*  initialize dma */
+	if (dma) {
+		if (dma == 4 || dma > 7) {
+			printk(" invalid dma channel %u\n", dma);
+			return -EINVAL;
+		}
+		if (request_dma(dma, dev->driver->driver_name)) {
+			printk(" failed to allocate dma channel %u\n", dma);
+			return -EINVAL;
+		}
+		devpriv->dma = dma;
+		devpriv->dma_buffer =
+		    kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
+		if (devpriv->dma_buffer == NULL)
+			return -ENOMEM;
+
+		disable_dma(dma);
+		set_dma_mode(dma, DMA_MODE_READ);
+
+		devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
+	}
+
+	dev->board_ptr = a2150_boards + a2150_probe(dev);
+	dev->board_name = thisboard->name;
+
+	if (alloc_subdevices(dev, 1) < 0)
+		return -ENOMEM;
+
+	/* analog input subdevice */
+	s = dev->subdevices + 0;
+	dev->read_subdev = s;
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ;
+	s->n_chan = 4;
+	s->len_chanlist = 4;
+	s->maxdata = 0xffff;
+	s->range_table = &range_a2150;
+	s->do_cmd = a2150_ai_cmd;
+	s->do_cmdtest = a2150_ai_cmdtest;
+	s->insn_read = a2150_ai_rinsn;
+	s->cancel = a2150_cancel;
+
+	/* need to do this for software counting of completed conversions, to
+	 * prevent hardware count from stopping acquisition */
+	outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG);
+
+	/*  set card's irq and dma levels */
+	outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
+
+	/*  reset and sync adc clock circuitry */
+	outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG);
+	outw_p(DPD_BIT, dev->iobase + CONFIG_REG);
+	/*  initialize configuration register */
+	devpriv->config_bits = 0;
+	outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
+	/*  wait until offset calibration is done, then enable analog inputs */
+	for (i = 0; i < timeout; i++) {
+		if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0)
+			break;
+		udelay(1000);
+	}
+	if (i == timeout) {
+		printk
+		    (" timed out waiting for offset calibration to complete\n");
+		return -ETIME;
+	}
+	devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT;
+	outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
+
+	return 0;
+};
+
+static void a2150_detach(struct comedi_device *dev)
+{
+	if (dev->iobase) {
+		outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
+		release_region(dev->iobase, A2150_SIZE);
+	}
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (devpriv) {
+		if (devpriv->dma)
+			free_dma(devpriv->dma);
+		kfree(devpriv->dma_buffer);
+	}
+};
+
+static struct comedi_driver ni_at_a2150_driver = {
+	.driver_name	= "ni_at_a2150",
+	.module		= THIS_MODULE,
+	.attach		= a2150_attach,
+	.detach		= a2150_detach,
+};
+module_comedi_driver(ni_at_a2150_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index 138dcc2..c43dd8a 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -157,17 +157,6 @@
 	int n_ao_chans;
 };
 
-static const struct atao_board atao_boards[] = {
-	{
-	 .name = "ai-ao-6",
-	 .n_ao_chans = 6,
-	 },
-	{
-	 .name = "ai-ao-10",
-	 .n_ao_chans = 10,
-	 },
-};
-
 #define thisboard ((struct atao_board *)dev->board_ptr)
 
 struct atao_private {
@@ -182,133 +171,6 @@
 
 #define devpriv ((struct atao_private *)dev->private)
 
-static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int atao_detach(struct comedi_device *dev);
-static struct comedi_driver driver_atao = {
-	.driver_name = "ni_at_ao",
-	.module = THIS_MODULE,
-	.attach = atao_attach,
-	.detach = atao_detach,
-	.board_name = &atao_boards[0].name,
-	.offset = sizeof(struct atao_board),
-	.num_names = ARRAY_SIZE(atao_boards),
-};
-
-static int __init driver_atao_init_module(void)
-{
-	return comedi_driver_register(&driver_atao);
-}
-
-static void __exit driver_atao_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_atao);
-}
-
-module_init(driver_atao_init_module);
-module_exit(driver_atao_cleanup_module);
-
-static void atao_reset(struct comedi_device *dev);
-
-static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			 struct comedi_insn *insn, unsigned int *data);
-static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			 struct comedi_insn *insn, unsigned int *data);
-static int atao_dio_insn_bits(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data);
-static int atao_dio_insn_config(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-static int atao_calib_insn_read(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-static int atao_calib_insn_write(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data);
-
-static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	unsigned long iobase;
-	int ao_unipolar;
-
-	iobase = it->options[0];
-	if (iobase == 0)
-		iobase = 0x1c0;
-	ao_unipolar = it->options[3];
-
-	printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase);
-
-	if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) {
-		printk(" I/O port conflict\n");
-		return -EIO;
-	}
-	dev->iobase = iobase;
-
-	/* dev->board_ptr = atao_probe(dev); */
-
-	dev->board_name = thisboard->name;
-
-	if (alloc_private(dev, sizeof(struct atao_private)) < 0)
-		return -ENOMEM;
-
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
-
-	s = dev->subdevices + 0;
-	/* analog output subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = thisboard->n_ao_chans;
-	s->maxdata = (1 << 12) - 1;
-	if (ao_unipolar)
-		s->range_table = &range_unipolar10;
-	else
-		s->range_table = &range_bipolar10;
-	s->insn_write = &atao_ao_winsn;
-	s->insn_read = &atao_ao_rinsn;
-
-	s = dev->subdevices + 1;
-	/* digital i/o subdevice */
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 8;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = atao_dio_insn_bits;
-	s->insn_config = atao_dio_insn_config;
-
-	s = dev->subdevices + 2;
-	/* caldac subdevice */
-	s->type = COMEDI_SUBD_CALIB;
-	s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
-	s->n_chan = 21;
-	s->maxdata = 0xff;
-	s->insn_read = atao_calib_insn_read;
-	s->insn_write = atao_calib_insn_write;
-
-	s = dev->subdevices + 3;
-	/* eeprom subdevice */
-	/* s->type=COMEDI_SUBD_EEPROM; */
-	s->type = COMEDI_SUBD_UNUSED;
-
-	atao_reset(dev);
-
-	printk(KERN_INFO "\n");
-
-	return 0;
-}
-
-static int atao_detach(struct comedi_device *dev)
-{
-	printk(KERN_INFO "comedi%d: atao: remove\n", dev->minor);
-
-	if (dev->iobase)
-		release_region(dev->iobase, ATAO_SIZE);
-
-	return 0;
-}
-
 static void atao_reset(struct comedi_device *dev)
 {
 	/* This is the reset sequence described in the manual */
@@ -471,6 +333,106 @@
 	return insn->n;
 }
 
+static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	unsigned long iobase;
+	int ao_unipolar;
+
+	iobase = it->options[0];
+	if (iobase == 0)
+		iobase = 0x1c0;
+	ao_unipolar = it->options[3];
+
+	printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase);
+
+	if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) {
+		printk(" I/O port conflict\n");
+		return -EIO;
+	}
+	dev->iobase = iobase;
+
+	/* dev->board_ptr = atao_probe(dev); */
+
+	dev->board_name = thisboard->name;
+
+	if (alloc_private(dev, sizeof(struct atao_private)) < 0)
+		return -ENOMEM;
+
+	if (alloc_subdevices(dev, 4) < 0)
+		return -ENOMEM;
+
+	s = dev->subdevices + 0;
+	/* analog output subdevice */
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITABLE;
+	s->n_chan = thisboard->n_ao_chans;
+	s->maxdata = (1 << 12) - 1;
+	if (ao_unipolar)
+		s->range_table = &range_unipolar10;
+	else
+		s->range_table = &range_bipolar10;
+	s->insn_write = &atao_ao_winsn;
+	s->insn_read = &atao_ao_rinsn;
+
+	s = dev->subdevices + 1;
+	/* digital i/o subdevice */
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 8;
+	s->maxdata = 1;
+	s->range_table = &range_digital;
+	s->insn_bits = atao_dio_insn_bits;
+	s->insn_config = atao_dio_insn_config;
+
+	s = dev->subdevices + 2;
+	/* caldac subdevice */
+	s->type = COMEDI_SUBD_CALIB;
+	s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
+	s->n_chan = 21;
+	s->maxdata = 0xff;
+	s->insn_read = atao_calib_insn_read;
+	s->insn_write = atao_calib_insn_write;
+
+	s = dev->subdevices + 3;
+	/* eeprom subdevice */
+	/* s->type=COMEDI_SUBD_EEPROM; */
+	s->type = COMEDI_SUBD_UNUSED;
+
+	atao_reset(dev);
+
+	printk(KERN_INFO "\n");
+
+	return 0;
+}
+
+static void atao_detach(struct comedi_device *dev)
+{
+	if (dev->iobase)
+		release_region(dev->iobase, ATAO_SIZE);
+}
+
+static const struct atao_board atao_boards[] = {
+	{
+		.name		= "ai-ao-6",
+		.n_ao_chans	= 6,
+	}, {
+		.name		= "ai-ao-10",
+		.n_ao_chans	= 10,
+	},
+};
+
+static struct comedi_driver ni_at_ao_driver = {
+	.driver_name	= "ni_at_ao",
+	.module		= THIS_MODULE,
+	.attach		= atao_attach,
+	.detach		= atao_detach,
+	.board_name	= &atao_boards[0].name,
+	.offset		= sizeof(struct atao_board),
+	.num_names	= ARRAY_SIZE(atao_boards),
+};
+module_comedi_driver(ni_at_ao_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 647c228..6448373 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -343,49 +343,8 @@
 
 MODULE_DEVICE_TABLE(pnp, device_ids);
 
-static int ni_atmio_attach(struct comedi_device *dev,
-			   struct comedi_devconfig *it);
-static int ni_atmio_detach(struct comedi_device *dev);
-static struct comedi_driver driver_atmio = {
-	.driver_name = "ni_atmio",
-	.module = THIS_MODULE,
-	.attach = ni_atmio_attach,
-	.detach = ni_atmio_detach,
-};
-
-static int __init driver_atmio_init_module(void)
-{
-	return comedi_driver_register(&driver_atmio);
-}
-
-static void __exit driver_atmio_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_atmio);
-}
-
-module_init(driver_atmio_init_module);
-module_exit(driver_atmio_cleanup_module);
-
 #include "ni_mio_common.c"
 
-static int ni_getboardtype(struct comedi_device *dev);
-
-/* clean up allocated resources */
-static int ni_atmio_detach(struct comedi_device *dev)
-{
-	mio_common_detach(dev);
-
-	if (dev->iobase)
-		release_region(dev->iobase, NI_SIZE);
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-
-	if (devpriv->isapnp_dev)
-		pnp_device_detach(devpriv->isapnp_dev);
-
-	return 0;
-}
-
 static int ni_isapnp_find_board(struct pnp_dev **dev)
 {
 	struct pnp_dev *isapnp_dev = NULL;
@@ -424,6 +383,26 @@
 	return 0;
 }
 
+static int ni_getboardtype(struct comedi_device *dev)
+{
+	int device_id = ni_read_eeprom(dev, 511);
+	int i;
+
+	for (i = 0; i < n_ni_boards; i++) {
+		if (ni_boards[i].device_id == device_id)
+			return i;
+
+	}
+	if (device_id == 255)
+		printk(" can't find board\n");
+	 else if (device_id == 0)
+		printk(" EEPROM read error (?) or device not found\n");
+	 else
+		printk(" unknown device ID %d -- contact author\n", device_id);
+
+	return -1;
+}
+
 static int ni_atmio_attach(struct comedi_device *dev,
 			   struct comedi_devconfig *it)
 {
@@ -518,22 +497,21 @@
 	return 0;
 }
 
-static int ni_getboardtype(struct comedi_device *dev)
+static void ni_atmio_detach(struct comedi_device *dev)
 {
-	int device_id = ni_read_eeprom(dev, 511);
-	int i;
-
-	for (i = 0; i < n_ni_boards; i++) {
-		if (ni_boards[i].device_id == device_id)
-			return i;
-
-	}
-	if (device_id == 255)
-		printk(" can't find board\n");
-	 else if (device_id == 0)
-		printk(" EEPROM read error (?) or device not found\n");
-	 else
-		printk(" unknown device ID %d -- contact author\n", device_id);
-
-	return -1;
+	mio_common_detach(dev);
+	if (dev->iobase)
+		release_region(dev->iobase, NI_SIZE);
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (devpriv->isapnp_dev)
+		pnp_device_detach(devpriv->isapnp_dev);
 }
+
+static struct comedi_driver ni_atmio_driver = {
+	.driver_name	= "ni_atmio",
+	.module		= THIS_MODULE,
+	.attach		= ni_atmio_attach,
+	.detach		= ni_atmio_detach,
+};
+module_comedi_driver(ni_atmio_driver);
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index 285b933..4f61453 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -110,60 +110,8 @@
 	int has_8255;
 };
 
-static const struct atmio16_board_t atmio16_boards[] = {
-	{
-	 .name = "atmio16",
-	 .has_8255 = 0,
-	 },
-	{
-	 .name = "atmio16d",
-	 .has_8255 = 1,
-	 },
-};
-
-#define n_atmio16_boards ARRAY_SIZE(atmio16_boards)
-
 #define boardtype ((const struct atmio16_board_t *)dev->board_ptr)
 
-/* function prototypes */
-static int atmio16d_attach(struct comedi_device *dev,
-			   struct comedi_devconfig *it);
-static int atmio16d_detach(struct comedi_device *dev);
-static irqreturn_t atmio16d_interrupt(int irq, void *d);
-static int atmio16d_ai_cmdtest(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_cmd *cmd);
-static int atmio16d_ai_cmd(struct comedi_device *dev,
-			   struct comedi_subdevice *s);
-static int atmio16d_ai_cancel(struct comedi_device *dev,
-			      struct comedi_subdevice *s);
-static void reset_counters(struct comedi_device *dev);
-static void reset_atmio16d(struct comedi_device *dev);
-
-/* main driver struct */
-static struct comedi_driver driver_atmio16d = {
-	.driver_name = "atmio16",
-	.module = THIS_MODULE,
-	.attach = atmio16d_attach,
-	.detach = atmio16d_detach,
-	.board_name = &atmio16_boards[0].name,
-	.num_names = n_atmio16_boards,
-	.offset = sizeof(struct atmio16_board_t),
-};
-
-static int __init driver_atmio16d_init_module(void)
-{
-	return comedi_driver_register(&driver_atmio16d);
-}
-
-static void __exit driver_atmio16d_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_atmio16d);
-}
-
-module_init(driver_atmio16d_init_module);
-module_exit(driver_atmio16d_cleanup_module);
-
 /* range structs */
 static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, {
 								       BIP_RANGE
@@ -881,24 +829,38 @@
 	return 0;
 }
 
-static int atmio16d_detach(struct comedi_device *dev)
+static void atmio16d_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: atmio16d: remove\n", dev->minor);
-
 	if (dev->subdevices && boardtype->has_8255)
 		subdev_8255_cleanup(dev, dev->subdevices + 3);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	reset_atmio16d(dev);
-
 	if (dev->iobase)
 		release_region(dev->iobase, ATMIO16D_SIZE);
-
-	return 0;
 }
 
+static const struct atmio16_board_t atmio16_boards[] = {
+	{
+		.name		= "atmio16",
+		.has_8255	= 0,
+	}, {
+		.name		= "atmio16d",
+		.has_8255	= 1,
+	},
+};
+
+static struct comedi_driver atmio16d_driver = {
+	.driver_name	= "atmio16",
+	.module		= THIS_MODULE,
+	.attach		= atmio16d_attach,
+	.detach		= atmio16d_detach,
+	.board_name	= &atmio16_boards[0].name,
+	.num_names	= ARRAY_SIZE(atmio16_boards),
+	.offset		= sizeof(struct atmio16_board_t),
+};
+module_comedi_driver(atmio16d_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index e242012..75764e8 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -57,7 +57,7 @@
 
 static int dio700_attach(struct comedi_device *dev,
 			 struct comedi_devconfig *it);
-static int dio700_detach(struct comedi_device *dev);
+static void dio700_detach(struct comedi_device *dev);
 
 enum dio700_bustype { pcmcia_bustype };
 
@@ -419,19 +419,14 @@
 	return 0;
 };
 
-static int dio700_detach(struct comedi_device *dev)
+static void dio700_detach(struct comedi_device *dev)
 {
-	printk(KERN_ERR "comedi%d: ni_daq_700: cs-remove\n", dev->minor);
-
 	if (dev->subdevices)
 		subdev_700_cleanup(dev, dev->subdevices + 0);
-
 	if (thisboard->bustype != pcmcia_bustype && dev->iobase)
 		release_region(dev->iobase, DIO700_SIZE);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
-	return 0;
 };
 
 static void dio700_config(struct pcmcia_device *link);
@@ -472,18 +467,12 @@
 
 static void dio700_cs_detach(struct pcmcia_device *link)
 {
-
-	printk(KERN_INFO "ni_daq_700: cs-detach!\n");
-
-	dev_dbg(&link->dev, "dio700_cs_detach\n");
-
 	((struct local_info_t *)link->priv)->stop = 1;
 	dio700_release(link);
 
 	/* This points to the parent struct local_info_t struct */
 	kfree(link->priv);
-
-}				/* dio700_cs_detach */
+}
 
 static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
 				void *priv_data)
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index c0423a8..493a227 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -57,7 +57,7 @@
 #define DIO24_SIZE 4		/*  size of io region used by board */
 
 static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int dio24_detach(struct comedi_device *dev);
+static void dio24_detach(struct comedi_device *dev);
 
 enum dio24_bustype { pcmcia_bustype };
 
@@ -168,19 +168,14 @@
 	return 0;
 };
 
-static int dio24_detach(struct comedi_device *dev)
+static void dio24_detach(struct comedi_device *dev)
 {
-	dev_info(dev->hw_dev, "comedi%d: ni_daq_dio24: remove\n", dev->minor);
-
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 0);
-
 	if (thisboard->bustype != pcmcia_bustype && dev->iobase)
 		release_region(dev->iobase, DIO24_SIZE);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
-	return 0;
 };
 
 static void dio24_config(struct pcmcia_device *link);
@@ -221,18 +216,12 @@
 
 static void dio24_cs_detach(struct pcmcia_device *link)
 {
-
-	printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO - cs-detach!\n");
-
-	dev_dbg(&link->dev, "dio24_cs_detach\n");
-
 	((struct local_info_t *)link->priv)->stop = 1;
 	dio24_release(link);
 
 	/* This points to the parent local_info_t struct */
 	kfree(link->priv);
-
-}				/* dio24_cs_detach */
+}
 
 static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev,
 				void *priv_data)
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 721b2be..5334977 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -805,13 +805,10 @@
 }
 #endif
 
-int labpc_common_detach(struct comedi_device *dev)
+void labpc_common_detach(struct comedi_device *dev)
 {
-	printk(KERN_ERR "comedi%d: ni_labpc: detach\n", dev->minor);
-
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 2);
-
 #ifdef CONFIG_ISA_DMA_API
 	/* only free stuff if it has been allocated by _attach */
 	kfree(devpriv->dma_buffer);
@@ -826,8 +823,6 @@
 	if (devpriv->mite)
 		mite_unsetup(devpriv->mite);
 #endif
-
-	return 0;
 };
 EXPORT_SYMBOL_GPL(labpc_common_detach);
 
@@ -2141,7 +2136,7 @@
 static int __devinit driver_labpc_pci_probe(struct pci_dev *dev,
 					    const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_labpc.driver_name);
+	return comedi_pci_auto_config(dev, &driver_labpc);
 }
 
 static void __devexit driver_labpc_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h
index 422cee5..e052ed3 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.h
+++ b/drivers/staging/comedi/drivers/ni_labpc.h
@@ -103,7 +103,7 @@
 
 int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
 			unsigned int irq, unsigned int dma);
-int labpc_common_detach(struct comedi_device *dev);
+void labpc_common_detach(struct comedi_device *dev);
 
 extern const int labpc_1200_is_unipolar[];
 extern const int labpc_1200_ai_gain_bits[];
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index ff38405..dbb61b6 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -188,21 +188,13 @@
 
 static void labpc_cs_detach(struct pcmcia_device *link)
 {
-	dev_dbg(&link->dev, "labpc_cs_detach\n");
-
-	/*
-	   If the device is currently configured and active, we won't
-	   actually delete it yet.  Instead, it is marked so that when
-	   the release() function is called, that will trigger a proper
-	   detach().
-	 */
 	((struct local_info_t *)link->priv)->stop = 1;
 	labpc_release(link);
 
 	/* This points to the parent local_info_t struct (may be null) */
 	kfree(link->priv);
 
-}				/* labpc_cs_detach */
+}
 
 static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev,
 				void *priv_data)
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index 53ec24bb..b85765d 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -227,7 +227,7 @@
 
 static int mio_cs_attach(struct comedi_device *dev,
 			 struct comedi_devconfig *it);
-static int mio_cs_detach(struct comedi_device *dev);
+static void mio_cs_detach(struct comedi_device *dev);
 static struct comedi_driver driver_ni_mio_cs = {
 	.driver_name = "ni_mio_cs",
 	.module = THIS_MODULE,
@@ -240,18 +240,11 @@
 static int ni_getboardtype(struct comedi_device *dev,
 			   struct pcmcia_device *link);
 
-/* clean up allocated resources */
-/* called when driver is removed */
-static int mio_cs_detach(struct comedi_device *dev)
+static void mio_cs_detach(struct comedi_device *dev)
 {
 	mio_common_detach(dev);
-
-	/* PCMCIA layer frees the IO region */
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
-	return 0;
 }
 
 static void mio_cs_config(struct pcmcia_device *link);
@@ -276,8 +269,6 @@
 
 static void cs_detach(struct pcmcia_device *link)
 {
-	DPRINTK("cs_detach(link=%p)\n", link);
-
 	cs_release(link);
 }
 
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 1df8fcb..37b7008 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -293,18 +293,9 @@
 #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC)
 #endif
 
-static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int nidio_detach(struct comedi_device *dev);
 static int ni_pcidio_cancel(struct comedi_device *dev,
 			    struct comedi_subdevice *s);
 
-static struct comedi_driver driver_pcidio = {
-	.driver_name = "ni_pcidio",
-	.module = THIS_MODULE,
-	.attach = nidio_attach,
-	.detach = nidio_detach,
-};
-
 struct nidio_board {
 
 	int dev_id;
@@ -381,22 +372,6 @@
 #define n_nidio_boards ARRAY_SIZE(nidio_boards)
 #define this_board ((const struct nidio_board *)dev->board_ptr)
 
-static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = {
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800)},
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);
-
 struct nidio96_private {
 	struct mite_struct *mite;
 	int boardtype;
@@ -414,7 +389,6 @@
 static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
 static int ni_pcidio_inttrig(struct comedi_device *dev,
 			     struct comedi_subdevice *s, unsigned int trignum);
-static int nidio_find_device(struct comedi_device *dev, int bus, int slot);
 static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode);
 static int setup_mite_dma(struct comedi_device *dev,
 			  struct comedi_subdevice *s);
@@ -1205,6 +1179,33 @@
 	return 0;
 }
 
+static int nidio_find_device(struct comedi_device *dev, int bus, int slot)
+{
+	struct mite_struct *mite;
+	int i;
+
+	for (mite = mite_devices; mite; mite = mite->next) {
+		if (mite->used)
+			continue;
+		if (bus || slot) {
+			if (bus != mite->pcidev->bus->number ||
+			    slot != PCI_SLOT(mite->pcidev->devfn))
+				continue;
+		}
+		for (i = 0; i < n_nidio_boards; i++) {
+			if (mite_device_id(mite) == nidio_boards[i].dev_id) {
+				dev->board_ptr = nidio_boards + i;
+				devpriv->mite = mite;
+
+				return 0;
+			}
+		}
+	}
+	printk(KERN_WARNING "no device found\n");
+	mite_list_devices();
+	return -EIO;
+}
+
 static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct comedi_subdevice *s;
@@ -1306,7 +1307,7 @@
 	return 0;
 }
 
-static int nidio_detach(struct comedi_device *dev)
+static void nidio_detach(struct comedi_device *dev)
 {
 	int i;
 
@@ -1314,10 +1315,8 @@
 		for (i = 0; i < this_board->n_8255; i++)
 			subdev_8255_cleanup(dev, dev->subdevices + i);
 	}
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (devpriv) {
 		if (devpriv->di_mite_ring) {
 			mite_free_ring(devpriv->di_mite_ring);
@@ -1326,73 +1325,48 @@
 		if (devpriv->mite)
 			mite_unsetup(devpriv->mite);
 	}
-	return 0;
 }
 
-static int nidio_find_device(struct comedi_device *dev, int bus, int slot)
+static struct comedi_driver ni_pcidio_driver = {
+	.driver_name	= "ni_pcidio",
+	.module		= THIS_MODULE,
+	.attach		= nidio_attach,
+	.detach		= nidio_detach,
+};
+
+static int __devinit ni_pcidio_pci_probe(struct pci_dev *dev,
+					 const struct pci_device_id *ent)
 {
-	struct mite_struct *mite;
-	int i;
-
-	for (mite = mite_devices; mite; mite = mite->next) {
-		if (mite->used)
-			continue;
-		if (bus || slot) {
-			if (bus != mite->pcidev->bus->number ||
-			    slot != PCI_SLOT(mite->pcidev->devfn))
-				continue;
-		}
-		for (i = 0; i < n_nidio_boards; i++) {
-			if (mite_device_id(mite) == nidio_boards[i].dev_id) {
-				dev->board_ptr = nidio_boards + i;
-				devpriv->mite = mite;
-
-				return 0;
-			}
-		}
-	}
-	printk(KERN_WARNING "no device found\n");
-	mite_list_devices();
-	return -EIO;
+	return comedi_pci_auto_config(dev, &ni_pcidio_driver);
 }
 
-static int __devinit driver_pcidio_pci_probe(struct pci_dev *dev,
-					     const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, driver_pcidio.driver_name);
-}
-
-static void __devexit driver_pcidio_pci_remove(struct pci_dev *dev)
+static void __devexit ni_pcidio_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_pcidio_pci_driver = {
-	.id_table = ni_pcidio_pci_table,
-	.probe = &driver_pcidio_pci_probe,
-	.remove = __devexit_p(&driver_pcidio_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);
 
-static int __init driver_pcidio_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_pcidio);
-	if (retval < 0)
-		return retval;
-
-	driver_pcidio_pci_driver.name = (char *)driver_pcidio.driver_name;
-	return pci_register_driver(&driver_pcidio_pci_driver);
-}
-
-static void __exit driver_pcidio_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_pcidio_pci_driver);
-	comedi_driver_unregister(&driver_pcidio);
-}
-
-module_init(driver_pcidio_init_module);
-module_exit(driver_pcidio_cleanup_module);
+static struct pci_driver ni_pcidio_pci_driver = {
+	.name		= "ni_pcidio",
+	.id_table	= ni_pcidio_pci_table,
+	.probe		= ni_pcidio_pci_probe,
+	.remove		= __devexit_p(ni_pcidio_pci_remove),
+};
+module_comedi_pci_driver(ni_pcidio_driver, ni_pcidio_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 27baefa..3974c0d 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -129,66 +129,6 @@
 
 #define DRV_NAME "ni_pcimio"
 
-/* The following two tables must be in the same order */
-static DEFINE_PCI_DEVICE_TABLE(ni_pci_table) = {
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d)},
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8)},
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, ni_pci_table);
-
 /* These are not all the possible ao ranges for 628x boards.
  They can do OFFSET +- REFERENCE where OFFSET can be
  0V, 5V, APFI<0,1>, or AO<0...3> and RANGE can
@@ -1250,54 +1190,6 @@
 
 #define n_pcimio_boards ARRAY_SIZE(ni_boards)
 
-static int pcimio_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcimio_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcimio = {
-	.driver_name = DRV_NAME,
-	.module = THIS_MODULE,
-	.attach = pcimio_attach,
-	.detach = pcimio_detach,
-};
-
-static int __devinit driver_pcimio_pci_probe(struct pci_dev *dev,
-					     const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, driver_pcimio.driver_name);
-}
-
-static void __devexit driver_pcimio_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_pcimio_pci_driver = {
-	.id_table = ni_pci_table,
-	.probe = &driver_pcimio_pci_probe,
-	.remove = __devexit_p(&driver_pcimio_pci_remove)
-};
-
-static int __init driver_pcimio_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_pcimio);
-	if (retval < 0)
-		return retval;
-
-	driver_pcimio_pci_driver.name = (char *)driver_pcimio.driver_name;
-	return pci_register_driver(&driver_pcimio_pci_driver);
-}
-
-static void __exit driver_pcimio_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_pcimio_pci_driver);
-	comedi_driver_unregister(&driver_pcimio);
-}
-
-module_init(driver_pcimio_init_module);
-module_exit(driver_pcimio_cleanup_module);
-
 struct ni_private {
 NI_PRIVATE_COMMON};
 #define devpriv ((struct ni_private *)dev->private)
@@ -1681,13 +1573,11 @@
 	ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143);
 }
 
-/* cleans up allocated resources */
-static int pcimio_detach(struct comedi_device *dev)
+static void pcimio_detach(struct comedi_device *dev)
 {
 	mio_common_detach(dev);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (dev->private) {
 		mite_free_ring(devpriv->ai_mite_ring);
 		mite_free_ring(devpriv->ao_mite_ring);
@@ -1697,8 +1587,6 @@
 		if (devpriv->mite)
 			mite_unsetup(devpriv->mite);
 	}
-
-	return 0;
 }
 
 static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -1874,6 +1762,90 @@
 	return 0;
 }
 
+static struct comedi_driver ni_pcimio_driver = {
+	.driver_name	= "ni_pcimio",
+	.module		= THIS_MODULE,
+	.attach		= pcimio_attach,
+	.detach		= pcimio_detach,
+};
+
+static int __devinit ni_pcimio_pci_probe(struct pci_dev *dev,
+					 const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &ni_pcimio_driver);
+}
+
+static void __devexit ni_pcimio_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ni_pcimio_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, ni_pcimio_pci_table);
+
+static struct pci_driver ni_pcimio_pci_driver = {
+	.name		= "ni_pcimio",
+	.id_table	= ni_pcimio_pci_table,
+	.probe		= ni_pcimio_pci_probe,
+	.remove		= __devexit_p(ni_pcimio_pci_remove)
+};
+module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver)
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/staging/comedi/drivers/ni_tio_internal.h
index c4ca537..5e00212 100644
--- a/drivers/staging/comedi/drivers/ni_tio_internal.h
+++ b/drivers/staging/comedi/drivers/ni_tio_internal.h
@@ -362,8 +362,8 @@
 	return 0;
 }
 
-static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(int
-								       counter_index)
+static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(
+	int counter_index)
 {
 	switch (counter_index) {
 	case 0:
@@ -407,8 +407,8 @@
 	return 0;
 }
 
-static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(int
-								  counter_index)
+static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(
+	int counter_index)
 {
 	switch (counter_index) {
 	case 0:
@@ -472,15 +472,22 @@
 	Gi_Index_Phase_LowA_HighB = 0x1 << Gi_Index_Phase_Bitshift,
 	Gi_Index_Phase_HighA_LowB = 0x2 << Gi_Index_Phase_Bitshift,
 	Gi_Index_Phase_HighA_HighB = 0x3 << Gi_Index_Phase_Bitshift,
-	Gi_HW_Arm_Enable_Bit = 0x80,	/* from m-series example code, not documented in 660x register level manual */
-	Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift,	/* from m-series example code, not documented in 660x register level manual */
+	/* from m-series example code, not documented in 660x register level
+	 * manual */
+	Gi_HW_Arm_Enable_Bit = 0x80,
+	/* from m-series example code, not documented in 660x register level
+	 * manual */
+	Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift,
 	Gi_660x_Prescale_X8_Bit = 0x1000,
 	Gi_M_Series_Prescale_X8_Bit = 0x2000,
 	Gi_M_Series_HW_Arm_Select_Mask = 0x1f << Gi_HW_Arm_Select_Shift,
-	/* must be set for clocks over 40MHz, which includes synchronous counting and quadrature modes */
+	/* must be set for clocks over 40MHz, which includes synchronous
+	 * counting and quadrature modes */
 	Gi_660x_Alternate_Sync_Bit = 0x2000,
 	Gi_M_Series_Alternate_Sync_Bit = 0x4000,
-	Gi_660x_Prescale_X2_Bit = 0x4000,	/* from m-series example code, not documented in 660x register level manual */
+	/* from m-series example code, not documented in 660x register level
+	 * manual */
+	Gi_660x_Prescale_X2_Bit = 0x4000,
 	Gi_M_Series_Prescale_X2_Bit = 0x8000,
 };
 
@@ -503,7 +510,8 @@
 	Gi_Level_Gating_Bits = 0x1,
 	Gi_Rising_Edge_Gating_Bits = 0x2,
 	Gi_Falling_Edge_Gating_Bits = 0x3,
-	Gi_Gate_On_Both_Edges_Bit = 0x4,	/* used in conjunction with rising edge gating mode */
+	Gi_Gate_On_Both_Edges_Bit = 0x4,	/* used in conjunction with
+						 * rising edge gating mode */
 	Gi_Trigger_Mode_for_Edge_Gate_Mask = 0x18,
 	Gi_Edge_Gate_Starts_Stops_Bits = 0x0,
 	Gi_Edge_Gate_Stops_Starts_Bits = 0x8,
@@ -686,11 +694,10 @@
 {
 	unsigned bit;
 
-	if (counter_index % 2) {
+	if (counter_index % 2)
 		bit = G1_Gate_Interrupt_Enable_Bit;
-	} else {
+	else
 		bit = G0_Gate_Interrupt_Enable_Bit;
-	}
 	return bit;
 }
 
@@ -748,8 +755,9 @@
 }
 
 /* ni_tio_set_bits( ) is for safely writing to registers whose bits may be
-twiddled in interrupt context, or whose software copy may be read in interrupt context.
-*/
+ * twiddled in interrupt context, or whose software copy may be read in
+ * interrupt context.
+ */
 static inline void ni_tio_set_bits(struct ni_gpct *counter,
 				   enum ni_gpct_register register_index,
 				   unsigned bit_mask, unsigned bit_values)
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index b44386a..2e7753f 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -148,42 +148,8 @@
 	const struct comedi_lrange *ai_range_type;
 };
 
-static const struct pcl711_board boardtypes[] = {
-	{"pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5},
-	{"pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai},
-	{"acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai},
-	{"acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl711_board))
 #define this_board ((const struct pcl711_board *)dev->board_ptr)
 
-static int pcl711_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcl711_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcl711 = {
-	.driver_name = "pcl711",
-	.module = THIS_MODULE,
-	.attach = pcl711_attach,
-	.detach = pcl711_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct pcl711_board),
-};
-
-static int __init driver_pcl711_init_module(void)
-{
-	return comedi_driver_register(&driver_pcl711);
-}
-
-static void __exit driver_pcl711_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcl711);
-}
-
-module_init(driver_pcl711_init_module);
-module_exit(driver_pcl711_cleanup_module);
-
 struct pcl711_private {
 
 	int board;
@@ -513,21 +479,6 @@
 	return 2;
 }
 
-/*  Free any resources that we have claimed  */
-static int pcl711_detach(struct comedi_device *dev)
-{
-	printk(KERN_INFO "comedi%d: pcl711: remove\n", dev->minor);
-
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-
-	if (dev->iobase)
-		release_region(dev->iobase, PCL711_SIZE);
-
-	return 0;
-}
-
-/*  Initialization */
 static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	int ret;
@@ -640,6 +591,32 @@
 	return 0;
 }
 
+static void pcl711_detach(struct comedi_device *dev)
+{
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (dev->iobase)
+		release_region(dev->iobase, PCL711_SIZE);
+}
+
+static const struct pcl711_board boardtypes[] = {
+	{ "pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5 },
+	{ "pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai },
+	{ "acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai },
+	{ "acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai },
+};
+
+static struct comedi_driver pcl711_driver = {
+	.driver_name	= "pcl711",
+	.module		= THIS_MODULE,
+	.attach		= pcl711_attach,
+	.detach		= pcl711_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct pcl711_board),
+};
+module_comedi_driver(pcl711_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index 61b075d..1f66fe1 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -56,10 +56,6 @@
 
 /* #define PCL724_IRQ   1  no IRQ support now */
 
-static int pcl724_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcl724_detach(struct comedi_device *dev);
-
 struct pcl724_board {
 
 	const char *name;	/*  board name */
@@ -71,41 +67,8 @@
 	char is_pet48;
 };
 
-static const struct pcl724_board boardtypes[] = {
-	{"pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,},
-	{"pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0,},
-	{"pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0,},
-	{"acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0,},
-	{"acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,},
-	{"pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl724_board))
 #define this_board ((const struct pcl724_board *)dev->board_ptr)
 
-static struct comedi_driver driver_pcl724 = {
-	.driver_name = "pcl724",
-	.module = THIS_MODULE,
-	.attach = pcl724_attach,
-	.detach = pcl724_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct pcl724_board),
-};
-
-static int __init driver_pcl724_init_module(void)
-{
-	return comedi_driver_register(&driver_pcl724);
-}
-
-static void __exit driver_pcl724_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcl724);
-}
-
-module_init(driver_pcl724_init_module);
-module_exit(driver_pcl724_cleanup_module);
-
 static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
 {
 	unsigned long iobase = arg;
@@ -214,25 +177,39 @@
 	return 0;
 }
 
-static int pcl724_detach(struct comedi_device *dev)
+static void pcl724_detach(struct comedi_device *dev)
 {
 	int i;
 
-	/* printk("comedi%d: pcl724: remove\n",dev->minor); */
-
 	for (i = 0; i < dev->n_subdevices; i++)
 		subdev_8255_cleanup(dev, dev->subdevices + i);
-
 #ifdef PCL724_IRQ
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 #endif
-
 	release_region(dev->iobase, this_board->io_range);
-
-	return 0;
 }
 
+static const struct pcl724_board boardtypes[] = {
+	{ "pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, },
+	{ "pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0, },
+	{ "pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0, },
+	{ "acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0, },
+	{ "acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, },
+	{ "pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1, },
+};
+
+static struct comedi_driver pcl724_driver = {
+	.driver_name	= "pcl724",
+	.module		= THIS_MODULE,
+	.attach		= pcl724_attach,
+	.detach		= pcl724_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct pcl724_board),
+};
+module_comedi_driver(pcl724_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c
index 24b223c..83a6fa5 100644
--- a/drivers/staging/comedi/drivers/pcl725.c
+++ b/drivers/staging/comedi/drivers/pcl725.c
@@ -20,29 +20,6 @@
 #define PCL725_DO 0
 #define PCL725_DI 1
 
-static int pcl725_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcl725_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcl725 = {
-	.driver_name = "pcl725",
-	.module = THIS_MODULE,
-	.attach = pcl725_attach,
-	.detach = pcl725_detach,
-};
-
-static int __init driver_pcl725_init_module(void)
-{
-	return comedi_driver_register(&driver_pcl725);
-}
-
-static void __exit driver_pcl725_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcl725);
-}
-
-module_init(driver_pcl725_init_module);
-module_exit(driver_pcl725_cleanup_module);
-
 static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
@@ -112,16 +89,20 @@
 	return 0;
 }
 
-static int pcl725_detach(struct comedi_device *dev)
+static void pcl725_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: pcl725: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, PCL725_SIZE);
-
-	return 0;
 }
 
+static struct comedi_driver pcl725_driver = {
+	.driver_name	= "pcl725",
+	.module		= THIS_MODULE,
+	.attach		= pcl725_attach,
+	.detach		= pcl725_detach,
+};
+module_comedi_driver(pcl725_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 897cd80..d25c30c 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -111,10 +111,6 @@
 	&range_4_20mA, &range_0_20mA
 };
 
-static int pcl726_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcl726_detach(struct comedi_device *dev);
-
 struct pcl726_board {
 
 	const char *name;	/*  driver name */
@@ -149,32 +145,8 @@
 	 &rangelist_728[0],},
 };
 
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl726_board))
 #define this_board ((const struct pcl726_board *)dev->board_ptr)
 
-static struct comedi_driver driver_pcl726 = {
-	.driver_name = "pcl726",
-	.module = THIS_MODULE,
-	.attach = pcl726_attach,
-	.detach = pcl726_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct pcl726_board),
-};
-
-static int __init driver_pcl726_init_module(void)
-{
-	return comedi_driver_register(&driver_pcl726);
-}
-
-static void __exit driver_pcl726_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcl726);
-}
-
-module_init(driver_pcl726_init_module);
-module_exit(driver_pcl726_cleanup_module);
-
 struct pcl726_private {
 
 	int bipolar[12];
@@ -378,21 +350,27 @@
 	return 0;
 }
 
-static int pcl726_detach(struct comedi_device *dev)
+static void pcl726_detach(struct comedi_device *dev)
 {
-/* printk("comedi%d: pcl726: remove\n",dev->minor); */
-
 #ifdef ACL6126_IRQ
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 #endif
-
 	if (dev->iobase)
 		release_region(dev->iobase, this_board->io_range);
-
-	return 0;
 }
 
+static struct comedi_driver pcl726_driver = {
+	.driver_name	= "pcl726",
+	.module		= THIS_MODULE,
+	.attach		= pcl726_attach,
+	.detach		= pcl726_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct pcl726_board),
+};
+module_comedi_driver(pcl726_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index c9682d6..e11704a 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -26,48 +26,14 @@
 #define PCL730_DIO_LO	2	/* TTL Digital I/O low byte (D0-D7) */
 #define PCL730_DIO_HI	3	/* TTL Digital I/O high byte (D8-D15) */
 
-static int pcl730_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcl730_detach(struct comedi_device *dev);
-
 struct pcl730_board {
 
 	const char *name;	/*  board name */
 	unsigned int io_range;	/*  len of I/O space */
 };
 
-static const struct pcl730_board boardtypes[] = {
-	{"pcl730", PCL730_SIZE,},
-	{"iso730", PCL730_SIZE,},
-	{"acl7130", ACL7130_SIZE,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl730_board))
 #define this_board ((const struct pcl730_board *)dev->board_ptr)
 
-static struct comedi_driver driver_pcl730 = {
-	.driver_name = "pcl730",
-	.module = THIS_MODULE,
-	.attach = pcl730_attach,
-	.detach = pcl730_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct pcl730_board),
-};
-
-static int __init driver_pcl730_init_module(void)
-{
-	return comedi_driver_register(&driver_pcl730);
-}
-
-static void __exit driver_pcl730_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcl730);
-}
-
-module_init(driver_pcl730_init_module);
-module_exit(driver_pcl730_cleanup_module);
-
 static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
@@ -168,16 +134,29 @@
 	return 0;
 }
 
-static int pcl730_detach(struct comedi_device *dev)
+static void pcl730_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: pcl730: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, this_board->io_range);
-
-	return 0;
 }
 
+static const struct pcl730_board boardtypes[] = {
+	{ "pcl730", PCL730_SIZE, },
+	{ "iso730", PCL730_SIZE, },
+	{ "acl7130", ACL7130_SIZE, },
+};
+
+static struct comedi_driver pcl730_driver = {
+	.driver_name	= "pcl730",
+	.module		= THIS_MODULE,
+	.attach		= pcl730_attach,
+	.detach		= pcl730_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct pcl730_board),
+};
+module_comedi_driver(pcl730_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 6fc7464..51f4ca9 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -316,10 +316,6 @@
 							   }
 };
 
-static int pcl812_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcl812_detach(struct comedi_device *dev);
-
 struct pcl812_board {
 
 	const char *name;	/*  board name */
@@ -340,89 +336,8 @@
 	unsigned char haveMPC508;	/*  1=board use MPC508A multiplexor */
 };
 
-static const struct pcl812_board boardtypes[] = {
-	{"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
-	 33000, 500, &range_bipolar10, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-	{"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
-	 33000, 500, &range_pcl812pg_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-	{"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
-	 10000, 500, &range_pcl812pg_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-	{"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
-	 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
-	{"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
-	 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
-	{"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
-	 10000, 500, &range_pcl813b_ai, &range_unipolar5,
-	 0x000c, 0x00, PCLx1x_IORANGE, 0},
-	{"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
-	 10000, 500, &range_pcl813b_ai, NULL,
-	 0x000c, 0x00, PCLx1x_IORANGE, 0},
-	{"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
-	 10000, 500, &range_a821pgh_ai, &range_unipolar5,
-	 0x000c, 0x00, PCLx1x_IORANGE, 0},
-	{"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
-	 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-	{"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
-	 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-	{"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
-	 8000, 500, &range_acl8112dg_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-	{"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
-	 8000, 500, &range_acl8112hg_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-	{"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
-	 0, 0, &range_pcl813b_ai, NULL,
-	 0x0000, 0x00, PCLx1x_IORANGE, 0},
-	{"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
-	 0, 0, &range_pcl813b_ai, NULL,
-	 0x0000, 0x00, PCLx1x_IORANGE, 0},
-	{"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
-	 0, 0, &range_acl8113_1_ai, NULL,
-	 0x0000, 0x00, PCLx1x_IORANGE, 0},
-	{"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
-	 0, 0, &range_iso813_1_ai, NULL,
-	 0x0000, 0x00, PCLx1x_IORANGE, 0},
-	{"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
-	 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
-	{"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
-	 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
-	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl812_board))
 #define this_board ((const struct pcl812_board *)dev->board_ptr)
 
-static struct comedi_driver driver_pcl812 = {
-	.driver_name = "pcl812",
-	.module = THIS_MODULE,
-	.attach = pcl812_attach,
-	.detach = pcl812_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct pcl812_board),
-};
-
-static int __init driver_pcl812_init_module(void)
-{
-	return comedi_driver_register(&driver_pcl812);
-}
-
-static void __exit driver_pcl812_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcl812);
-}
-
-module_init(driver_pcl812_init_module);
-module_exit(driver_pcl812_cleanup_module);
-
 struct pcl812_private {
 
 	unsigned char valid;	/*  =1 device is OK */
@@ -1356,9 +1271,6 @@
 #endif
 }
 
-/*
-==============================================================================
-*/
 static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	int ret, subdev;
@@ -1702,19 +1614,79 @@
 	return 0;
 }
 
-/*
-==============================================================================
- */
-static int pcl812_detach(struct comedi_device *dev)
+static void pcl812_detach(struct comedi_device *dev)
 {
-
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "comedi%d: pcl812: remove\n", dev->minor);
-#endif
 	free_resources(dev);
-	return 0;
 }
 
+static const struct pcl812_board boardtypes[] = {
+	{"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
+	 33000, 500, &range_bipolar10, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+	{"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
+	 33000, 500, &range_pcl812pg_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+	{"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
+	 10000, 500, &range_pcl812pg_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+	{"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+	 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+	{"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+	 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+	{"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
+	 10000, 500, &range_pcl813b_ai, &range_unipolar5,
+	 0x000c, 0x00, PCLx1x_IORANGE, 0},
+	{"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
+	 10000, 500, &range_pcl813b_ai, NULL,
+	 0x000c, 0x00, PCLx1x_IORANGE, 0},
+	{"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
+	 10000, 500, &range_a821pgh_ai, &range_unipolar5,
+	 0x000c, 0x00, PCLx1x_IORANGE, 0},
+	{"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+	 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+	{"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+	 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+	{"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+	 8000, 500, &range_acl8112dg_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+	{"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+	 8000, 500, &range_acl8112hg_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+	{"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
+	 0, 0, &range_pcl813b_ai, NULL,
+	 0x0000, 0x00, PCLx1x_IORANGE, 0},
+	{"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
+	 0, 0, &range_pcl813b_ai, NULL,
+	 0x0000, 0x00, PCLx1x_IORANGE, 0},
+	{"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
+	 0, 0, &range_acl8113_1_ai, NULL,
+	 0x0000, 0x00, PCLx1x_IORANGE, 0},
+	{"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
+	 0, 0, &range_iso813_1_ai, NULL,
+	 0x0000, 0x00, PCLx1x_IORANGE, 0},
+	{"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
+	 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+	{"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
+	 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
+	 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+};
+
+static struct comedi_driver pcl812_driver = {
+	.driver_name	= "pcl812",
+	.module		= THIS_MODULE,
+	.attach		= pcl812_attach,
+	.detach		= pcl812_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct pcl812_board),
+};
+module_comedi_driver(pcl812_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 96cd7ec..cc67b6d 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -125,63 +125,14 @@
 	int i8254_osc_base;	/*  1/frequency of on board oscilator in ns */
 };
 
-static const struct pcl816_board boardtypes[] = {
-	{"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
-	 &range_pcl816, PCLx1x_RANGE,
-	 0x00fc,		/*  IRQ mask */
-	 0x0a,			/*  DMA mask */
-	 0xffff,		/*  16-bit card */
-	 0xffff,		/*  D/A maxdata */
-	 1024,
-	 1,			/*  ao chan list */
-	 100},
-	{"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
-	 &range_pcl816, PCLx1x_RANGE,
-	 0x00fc,
-	 0x0a,
-	 0x3fff,		/* 14 bit card */
-	 0x3fff,
-	 1024,
-	 1,
-	 100},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board))
 #define devpriv ((struct pcl816_private *)dev->private)
 #define this_board ((const struct pcl816_board *)dev->board_ptr)
 
-static int pcl816_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcl816_detach(struct comedi_device *dev);
-
 #ifdef unused
 static int RTC_lock;	/* RTC lock */
 static int RTC_timer_lock;	/* RTC int lock */
 #endif
 
-static struct comedi_driver driver_pcl816 = {
-	.driver_name = "pcl816",
-	.module = THIS_MODULE,
-	.attach = pcl816_attach,
-	.detach = pcl816_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct pcl816_board),
-};
-
-static int __init driver_pcl816_init_module(void)
-{
-	return comedi_driver_register(&driver_pcl816);
-}
-
-static void __exit driver_pcl816_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcl816);
-}
-
-module_init(driver_pcl816_init_module);
-module_exit(driver_pcl816_cleanup_module);
-
 struct pcl816_private {
 
 	unsigned int dma;	/*  used DMA, 0=don't use DMA */
@@ -1075,46 +1026,6 @@
 }
 #endif
 
-/*
-==============================================================================
-  Free any resources that we have claimed
-*/
-static void free_resources(struct comedi_device *dev)
-{
-	/* printk("free_resource()\n"); */
-	if (dev->private) {
-		pcl816_ai_cancel(dev, devpriv->sub_ai);
-		pcl816_reset(dev);
-		if (devpriv->dma)
-			free_dma(devpriv->dma);
-		if (devpriv->dmabuf[0])
-			free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
-		if (devpriv->dmabuf[1])
-			free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
-#ifdef unused
-		if (devpriv->rtc_irq)
-			free_irq(devpriv->rtc_irq, dev);
-		if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
-			if (devpriv->rtc_iobase)
-				release_region(devpriv->rtc_iobase,
-					       devpriv->rtc_iosize);
-		}
-#endif
-	}
-
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-	if (dev->iobase)
-		release_region(dev->iobase, this_board->io_range);
-	/* printk("free_resource() end\n"); */
-}
-
-/*
-==============================================================================
-
-   Initialization
-
-*/
 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	int ret;
@@ -1340,21 +1251,69 @@
 	return 0;
 }
 
-/*
-==============================================================================
-  Removes device
- */
-static int pcl816_detach(struct comedi_device *dev)
+static void pcl816_detach(struct comedi_device *dev)
 {
-	DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);)
-	    free_resources(dev);
+	if (dev->private) {
+		pcl816_ai_cancel(dev, devpriv->sub_ai);
+		pcl816_reset(dev);
+		if (devpriv->dma)
+			free_dma(devpriv->dma);
+		if (devpriv->dmabuf[0])
+			free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+		if (devpriv->dmabuf[1])
+			free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+#ifdef unused
+		if (devpriv->rtc_irq)
+			free_irq(devpriv->rtc_irq, dev);
+		if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
+			if (devpriv->rtc_iobase)
+				release_region(devpriv->rtc_iobase,
+					       devpriv->rtc_iosize);
+		}
+#endif
+	}
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (dev->iobase)
+		release_region(dev->iobase, this_board->io_range);
 #ifdef unused
 	if (devpriv->dma_rtc)
 		RTC_lock--;
 #endif
-	return 0;
 }
 
+static const struct pcl816_board boardtypes[] = {
+	{"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
+	 &range_pcl816, PCLx1x_RANGE,
+	 0x00fc,		/*  IRQ mask */
+	 0x0a,			/*  DMA mask */
+	 0xffff,		/*  16-bit card */
+	 0xffff,		/*  D/A maxdata */
+	 1024,
+	 1,			/*  ao chan list */
+	 100},
+	{"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
+	 &range_pcl816, PCLx1x_RANGE,
+	 0x00fc,
+	 0x0a,
+	 0x3fff,		/* 14 bit card */
+	 0x3fff,
+	 1024,
+	 1,
+	 100},
+};
+
+static struct comedi_driver pcl816_driver = {
+	.driver_name	= "pcl816",
+	.module		= THIS_MODULE,
+	.attach		= pcl816_attach,
+	.detach		= pcl816_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct pcl816_board),
+};
+module_comedi_driver(pcl816_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 7344a53..1406c97 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -247,10 +247,6 @@
 static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
 static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
 
-static int pcl818_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcl818_detach(struct comedi_device *dev);
-
 #ifdef unused
 static int RTC_lock;	/* RTC lock */
 static int RTC_timer_lock;	/* RTC int lock */
@@ -277,56 +273,6 @@
 	int is_818;
 };
 
-static const struct pcl818_board boardtypes[] = {
-	{"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
-	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
-	 0x0a, 0xfff, 0xfff, 0, 1},
-	{"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
-	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
-	 0x0a, 0xfff, 0xfff, 0, 1},
-	{"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
-	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
-	 0x0a, 0xfff, 0xfff, 1, 1},
-	{"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
-	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
-	 0x0a, 0xfff, 0xfff, 1, 1},
-	{"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
-	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
-	 0x0a, 0xfff, 0xfff, 0, 1},
-	{"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
-	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
-	 0x0a, 0xfff, 0xfff, 0, 0},
-	/* pcm3718 */
-	{"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
-	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
-	 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board))
-
-static struct comedi_driver driver_pcl818 = {
-	.driver_name = "pcl818",
-	.module = THIS_MODULE,
-	.attach = pcl818_attach,
-	.detach = pcl818_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct pcl818_board),
-};
-
-static int __init driver_pcl818_init_module(void)
-{
-	return comedi_driver_register(&driver_pcl818);
-}
-
-static void __exit driver_pcl818_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcl818);
-}
-
-module_init(driver_pcl818_init_module);
-module_exit(driver_pcl818_cleanup_module);
-
 struct pcl818_private {
 
 	unsigned int dma;	/*  used DMA, 0=don't use DMA */
@@ -1688,48 +1634,6 @@
 }
 #endif
 
-/*
-==============================================================================
-  Free any resources that we have claimed
-*/
-static void free_resources(struct comedi_device *dev)
-{
-	/* printk("free_resource()\n"); */
-	if (dev->private) {
-		pcl818_ai_cancel(dev, devpriv->sub_ai);
-		pcl818_reset(dev);
-		if (devpriv->dma)
-			free_dma(devpriv->dma);
-		if (devpriv->dmabuf[0])
-			free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
-		if (devpriv->dmabuf[1])
-			free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
-#ifdef unused
-		if (devpriv->rtc_irq)
-			free_irq(devpriv->rtc_irq, dev);
-		if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
-			if (devpriv->rtc_iobase)
-				release_region(devpriv->rtc_iobase,
-					       devpriv->rtc_iosize);
-		}
-		if (devpriv->dma_rtc)
-			RTC_lock--;
-#endif
-	}
-
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-	if (dev->iobase)
-		release_region(dev->iobase, devpriv->io_range);
-	/* printk("free_resource() end\n"); */
-}
-
-/*
-==============================================================================
-
-   Initialization
-
-*/
 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	int ret;
@@ -2020,17 +1924,71 @@
 	return 0;
 }
 
-/*
-==============================================================================
-  Removes device
- */
-static int pcl818_detach(struct comedi_device *dev)
+static void pcl818_detach(struct comedi_device *dev)
 {
-	/*   printk("comedi%d: pcl818: remove\n", dev->minor); */
-	free_resources(dev);
-	return 0;
+	if (dev->private) {
+		pcl818_ai_cancel(dev, devpriv->sub_ai);
+		pcl818_reset(dev);
+		if (devpriv->dma)
+			free_dma(devpriv->dma);
+		if (devpriv->dmabuf[0])
+			free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+		if (devpriv->dmabuf[1])
+			free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+#ifdef unused
+		if (devpriv->rtc_irq)
+			free_irq(devpriv->rtc_irq, dev);
+		if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
+			if (devpriv->rtc_iobase)
+				release_region(devpriv->rtc_iobase,
+					       devpriv->rtc_iosize);
+		}
+		if (devpriv->dma_rtc)
+			RTC_lock--;
+#endif
+	}
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (dev->iobase)
+		release_region(dev->iobase, devpriv->io_range);
 }
 
+static const struct pcl818_board boardtypes[] = {
+	{"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
+	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+	 0x0a, 0xfff, 0xfff, 0, 1},
+	{"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
+	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+	 0x0a, 0xfff, 0xfff, 0, 1},
+	{"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
+	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+	 0x0a, 0xfff, 0xfff, 1, 1},
+	{"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
+	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+	 0x0a, 0xfff, 0xfff, 1, 1},
+	{"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
+	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+	 0x0a, 0xfff, 0xfff, 0, 1},
+	{"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
+	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+	 0x0a, 0xfff, 0xfff, 0, 0},
+	/* pcm3718 */
+	{"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
+	 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+	 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
+};
+
+static struct comedi_driver pcl818_driver = {
+	.driver_name	= "pcl818",
+	.module		= THIS_MODULE,
+	.attach		= pcl818_attach,
+	.detach		= pcl818_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct pcl818_board),
+};
+module_comedi_driver(pcl818_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index f5c0bd1..7492b8f 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -62,10 +62,6 @@
 #define CR_A_MODE(a)	((a)<<5)
 #define CR_CW		0x80
 
-static int pcm3724_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int pcm3724_detach(struct comedi_device *dev);
-
 struct pcm3724_board {
 	const char *name;	/*  driver name */
 	int dio;		/*  num of DIO */
@@ -80,36 +76,8 @@
 	int dio_2;
 };
 
-static const struct pcm3724_board boardtypes[] = {
-	{"pcm3724", 48, 2, 0x00fc, PCM3724_SIZE,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcm3724_board))
 #define this_board ((const struct pcm3724_board *)dev->board_ptr)
 
-static struct comedi_driver driver_pcm3724 = {
-	.driver_name = "pcm3724",
-	.module = THIS_MODULE,
-	.attach = pcm3724_attach,
-	.detach = pcm3724_detach,
-	.board_name = &boardtypes[0].name,
-	.num_names = n_boardtypes,
-	.offset = sizeof(struct pcm3724_board),
-};
-
-static int __init driver_pcm3724_init_module(void)
-{
-	return comedi_driver_register(&driver_pcm3724);
-}
-
-static void __exit driver_pcm3724_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcm3724);
-}
-
-module_init(driver_pcm3724_init_module);
-module_exit(driver_pcm3724_cleanup_module);
-
 /* (setq c-basic-offset 8) */
 
 static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
@@ -305,7 +273,7 @@
 	return 0;
 }
 
-static int pcm3724_detach(struct comedi_device *dev)
+static void pcm3724_detach(struct comedi_device *dev)
 {
 	int i;
 
@@ -315,10 +283,23 @@
 	}
 	if (dev->iobase)
 		release_region(dev->iobase, this_board->io_range);
-
-	return 0;
 }
 
+static const struct pcm3724_board boardtypes[] = {
+	{ "pcm3724", 48, 2, 0x00fc, PCM3724_SIZE, },
+};
+
+static struct comedi_driver pcm3724_driver = {
+	.driver_name	= "pcm3724",
+	.module		= THIS_MODULE,
+	.attach		= pcm3724_attach,
+	.detach		= pcm3724_detach,
+	.board_name	= &boardtypes[0].name,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.offset		= sizeof(struct pcm3724_board),
+};
+module_comedi_driver(pcm3724_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c
index bada6b2..f8d1c64 100644
--- a/drivers/staging/comedi/drivers/pcm3730.c
+++ b/drivers/staging/comedi/drivers/pcm3730.c
@@ -28,29 +28,6 @@
 #define PCM3730_DIB 2
 #define PCM3730_DIC 3
 
-static int pcm3730_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int pcm3730_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcm3730 = {
-	.driver_name = "pcm3730",
-	.module = THIS_MODULE,
-	.attach = pcm3730_attach,
-	.detach = pcm3730_detach,
-};
-
-static int __init driver_pcm3730_init_module(void)
-{
-	return comedi_driver_register(&driver_pcm3730);
-}
-
-static void __exit driver_pcm3730_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcm3730);
-}
-
-module_init(driver_pcm3730_init_module);
-module_exit(driver_pcm3730_cleanup_module);
-
 static int pcm3730_do_insn_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
@@ -156,16 +133,20 @@
 	return 0;
 }
 
-static int pcm3730_detach(struct comedi_device *dev)
+static void pcm3730_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: pcm3730: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, PCM3730_SIZE);
-
-	return 0;
 }
 
+static struct comedi_driver pcm3730_driver = {
+	.driver_name	= "pcm3730",
+	.module		= THIS_MODULE,
+	.attach		= pcm3730_attach,
+	.detach		= pcm3730_detach,
+};
+module_comedi_driver(pcm3730_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index 23b3d77..1ec7d5c 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -57,19 +57,8 @@
 	const char *name;
 	int n_ai_bits;
 };
-static const struct pcmad_board_struct pcmad_boards[] = {
-	{
-	 .name = "pcmad12",
-	 .n_ai_bits = 12,
-	 },
-	{
-	 .name = "pcmad16",
-	 .n_ai_bits = 16,
-	 },
-};
 
 #define this_board ((const struct pcmad_board_struct *)(dev->board_ptr))
-#define n_pcmad_boards ARRAY_SIZE(pcmad_boards)
 
 struct pcmad_priv_struct {
 	int differential;
@@ -77,31 +66,6 @@
 };
 #define devpriv ((struct pcmad_priv_struct *)dev->private)
 
-static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int pcmad_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcmad = {
-	.driver_name = "pcmad",
-	.module = THIS_MODULE,
-	.attach = pcmad_attach,
-	.detach = pcmad_detach,
-	.board_name = &pcmad_boards[0].name,
-	.num_names = n_pcmad_boards,
-	.offset = sizeof(pcmad_boards[0]),
-};
-
-static int __init driver_pcmad_init_module(void)
-{
-	return comedi_driver_register(&driver_pcmad);
-}
-
-static void __exit driver_pcmad_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_pcmad);
-}
-
-module_init(driver_pcmad_init_module);
-module_exit(driver_pcmad_cleanup_module);
-
 #define TIMEOUT	100
 
 static int pcmad_ai_insn_read(struct comedi_device *dev,
@@ -175,19 +139,34 @@
 	return 0;
 }
 
-static int pcmad_detach(struct comedi_device *dev)
+static void pcmad_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: pcmad: remove\n", dev->minor);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
 	if (dev->iobase)
 		release_region(dev->iobase, PCMAD_SIZE);
-
-	return 0;
 }
 
+static const struct pcmad_board_struct pcmad_boards[] = {
+	{
+		.name		= "pcmad12",
+		.n_ai_bits	= 12,
+	}, {
+		.name		= "pcmad16",
+		.n_ai_bits	= 16,
+	},
+};
+static struct comedi_driver pcmad_driver = {
+	.driver_name	= "pcmad",
+	.module		= THIS_MODULE,
+	.attach		= pcmad_attach,
+	.detach		= pcmad_detach,
+	.board_name	= &pcmad_boards[0].name,
+	.num_names	= ARRAY_SIZE(pcmad_boards),
+	.offset		= sizeof(pcmad_boards[0]),
+};
+module_comedi_driver(pcmad_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 0e9ffa2..4786148 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -80,12 +80,6 @@
 	 }
 };
 
-static const struct pcmda12_board pcmda12_boards[] = {
-	{
-	 .name = "pcmda12",
-	 },
-};
-
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -99,137 +93,6 @@
 
 #define devpriv ((struct pcmda12_private *)(dev->private))
 
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcmda12_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int pcmda12_detach(struct comedi_device *dev);
-
-static void zero_chans(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
-	.driver_name = "pcmda12",
-	.module = THIS_MODULE,
-	.attach = pcmda12_attach,
-	.detach = pcmda12_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
-	/* Most drivers will support multiple types of boards by
-	 * having an array of board structures.  These were defined
-	 * in pcmda12_boards[] above.  Note that the element 'name'
-	 * was first in the structure -- Comedi uses this fact to
-	 * extract the name of the board without knowing any details
-	 * about the structure except for its length.
-	 * When a device is attached (by comedi_config), the name
-	 * of the device is given to Comedi, and Comedi tries to
-	 * match it by going through the list of board names.  If
-	 * there is a match, the address of the pointer is put
-	 * into dev->board_ptr and driver->attach() is called.
-	 *
-	 * Note that these are not necessary if you can determine
-	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
-	 * devices are such boards.
-	 */
-	.board_name = &pcmda12_boards[0].name,
-	.offset = sizeof(struct pcmda12_board),
-	.num_names = ARRAY_SIZE(pcmda12_boards),
-};
-
-static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-		    struct comedi_insn *insn, unsigned int *data);
-static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-		    struct comedi_insn *insn, unsigned int *data);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pcmda12_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	unsigned long iobase;
-
-	iobase = it->options[0];
-	printk(KERN_INFO
-	       "comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name,
-	       iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
-
-	if (!request_region(iobase, IOSIZE, driver.driver_name)) {
-		printk("I/O port conflict\n");
-		return -EIO;
-	}
-	dev->iobase = iobase;
-
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
-		printk(KERN_ERR "cannot allocate private data structure\n");
-		return -ENOMEM;
-	}
-
-	devpriv->simultaneous_xfer_mode = it->options[1];
-
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 *
-	 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
-	 * 96-channel version of the board.
-	 */
-	if (alloc_subdevices(dev, 1) < 0) {
-		printk(KERN_ERR "cannot allocate subdevice data structures\n");
-		return -ENOMEM;
-	}
-
-	s = dev->subdevices;
-	s->private = NULL;
-	s->maxdata = (0x1 << BITS) - 1;
-	s->range_table = &pcmda12_ranges;
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = CHANS;
-	s->insn_write = &ao_winsn;
-	s->insn_read = &ao_rinsn;
-
-	zero_chans(dev);	/* clear out all the registers, basically */
-
-	printk(KERN_INFO "attached\n");
-
-	return 1;
-}
-
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcmda12_detach(struct comedi_device *dev)
-{
-	printk(KERN_INFO
-	       "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
-	if (dev->iobase)
-		release_region(dev->iobase, IOSIZE);
-	return 0;
-}
-
 static void zero_chans(struct comedi_device *dev)
 {				/* sets up an
 				   ASIC chip to defaults */
@@ -301,22 +164,91 @@
 	return i;
 }
 
+static int pcmda12_attach(struct comedi_device *dev,
+			  struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	unsigned long iobase;
+
+	iobase = it->options[0];
+	printk(KERN_INFO
+	       "comedi%d: %s: io: %lx %s ", dev->minor, dev->driver->driver_name,
+	       iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
+
+	if (!request_region(iobase, IOSIZE, dev->driver->driver_name)) {
+		printk("I/O port conflict\n");
+		return -EIO;
+	}
+	dev->iobase = iobase;
+
 /*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name.  Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
  */
-static int __init driver_init_module(void)
-{
-	return comedi_driver_register(&driver);
+	dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area.  alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+	if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
+		printk(KERN_ERR "cannot allocate private data structure\n");
+		return -ENOMEM;
+	}
+
+	devpriv->simultaneous_xfer_mode = it->options[1];
+
+	/*
+	 * Allocate the subdevice structures.  alloc_subdevice() is a
+	 * convenient macro defined in comedidev.h.
+	 *
+	 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
+	 * 96-channel version of the board.
+	 */
+	if (alloc_subdevices(dev, 1) < 0) {
+		printk(KERN_ERR "cannot allocate subdevice data structures\n");
+		return -ENOMEM;
+	}
+
+	s = dev->subdevices;
+	s->private = NULL;
+	s->maxdata = (0x1 << BITS) - 1;
+	s->range_table = &pcmda12_ranges;
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = CHANS;
+	s->insn_write = &ao_winsn;
+	s->insn_read = &ao_rinsn;
+
+	zero_chans(dev);	/* clear out all the registers, basically */
+
+	printk(KERN_INFO "attached\n");
+
+	return 1;
 }
 
-static void __exit driver_cleanup_module(void)
+static void pcmda12_detach(struct comedi_device *dev)
 {
-	comedi_driver_unregister(&driver);
+	if (dev->iobase)
+		release_region(dev->iobase, IOSIZE);
 }
 
-module_init(driver_init_module);
-module_exit(driver_cleanup_module);
+static const struct pcmda12_board pcmda12_boards[] = {
+	{
+		.name	= "pcmda12",
+	},
+};
+
+static struct comedi_driver pcmda12_driver = {
+	.driver_name	= "pcmda12",
+	.module		= THIS_MODULE,
+	.attach		= pcmda12_attach,
+	.detach		= pcmda12_detach,
+	.board_name	= &pcmda12_boards[0].name,
+	.offset		= sizeof(struct pcmda12_board),
+	.num_names	= ARRAY_SIZE(pcmda12_boards),
+};
+module_comedi_driver(pcmda12_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index eddac00..efed168 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -145,13 +145,6 @@
 #define PAGE_ENAB 2
 #define PAGE_INT_ID 3
 
-static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *,
-		    struct comedi_insn *, unsigned int *);
-static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *,
-		    struct comedi_insn *, unsigned int *);
-static int ao_winsn(struct comedi_device *, struct comedi_subdevice *,
-		    struct comedi_insn *, unsigned int *);
-
 /*
  * Board descriptions for two imaginary boards.  Describing the
  * boards in this way is optional, and completely driver-dependent.
@@ -190,23 +183,6 @@
 	  RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
 };
 
-static const struct pcmmio_board pcmmio_boards[] = {
-	{
-	 .name = "pcmmio",
-	 .dio_num_asics = 1,
-	 .dio_num_ports = 6,
-	 .total_iosize = 32,
-	 .ai_bits = 16,
-	 .ao_bits = 16,
-	 .n_ai_chans = 16,
-	 .n_ao_chans = 8,
-	 .ai_range_table = &ranges_ai,
-	 .ao_range_table = &ranges_ao,
-	 .ai_rinsn = ai_rinsn,
-	 .ao_rinsn = ao_rinsn,
-	 .ao_winsn = ao_winsn},
-};
-
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -293,312 +269,6 @@
  */
 #define devpriv ((struct pcmmio_private *)dev->private)
 #define subpriv ((struct pcmmio_subdev_private *)s->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcmmio_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcmmio_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
-	.driver_name = "pcmmio",
-	.module = THIS_MODULE,
-	.attach = pcmmio_attach,
-	.detach = pcmmio_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
-	/* Most drivers will support multiple types of boards by
-	 * having an array of board structures.  These were defined
-	 * in pcmmio_boards[] above.  Note that the element 'name'
-	 * was first in the structure -- Comedi uses this fact to
-	 * extract the name of the board without knowing any details
-	 * about the structure except for its length.
-	 * When a device is attached (by comedi_config), the name
-	 * of the device is given to Comedi, and Comedi tries to
-	 * match it by going through the list of board names.  If
-	 * there is a match, the address of the pointer is put
-	 * into dev->board_ptr and driver->attach() is called.
-	 *
-	 * Note that these are not necessary if you can determine
-	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
-	 * devices are such boards.
-	 */
-	.board_name = &pcmmio_boards[0].name,
-	.offset = sizeof(struct pcmmio_board),
-	.num_names = ARRAY_SIZE(pcmmio_boards),
-};
-
-static int pcmmio_dio_insn_bits(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-static int pcmmio_dio_insn_config(struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data);
-
-static irqreturn_t interrupt_pcmmio(int irq, void *d);
-static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
-static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_cmd *cmd);
-
-/* some helper functions to deal with specifics of this device's registers */
-/* sets up/clears ASIC chips to defaults */
-static void init_asics(struct comedi_device *dev);
-static void switch_page(struct comedi_device *dev, int asic, int page);
-#ifdef notused
-static void lock_port(struct comedi_device *dev, int asic, int port);
-static void unlock_port(struct comedi_device *dev, int asic, int port);
-#endif
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
-	    thisasic_chanct = 0;
-	unsigned long iobase;
-	unsigned int irq[MAX_ASICS];
-
-	iobase = it->options[0];
-	irq[0] = it->options[1];
-
-	printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
-			driver.driver_name, iobase);
-
-	dev->iobase = iobase;
-
-	if (!iobase || !request_region(iobase,
-				       thisboard->total_iosize,
-				       driver.driver_name)) {
-		printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
-		return -EIO;
-	}
-
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
-		printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
-				dev->minor);
-		return -ENOMEM;
-	}
-
-	for (asic = 0; asic < MAX_ASICS; ++asic) {
-		devpriv->asics[asic].num = asic;
-		devpriv->asics[asic].iobase =
-		    dev->iobase + 16 + asic * ASIC_IOSIZE;
-		/*
-		 * this gets actually set at the end of this function when we
-		 * request_irqs
-		 */
-		devpriv->asics[asic].irq = 0;
-		spin_lock_init(&devpriv->asics[asic].spinlock);
-	}
-
-	chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
-	n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
-	n_subdevs = n_dio_subdevs + 2;
-	devpriv->sprivs =
-	    kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
-		    GFP_KERNEL);
-	if (!devpriv->sprivs) {
-		printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
-				dev->minor);
-		return -ENOMEM;
-	}
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 *
-	 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
-	 */
-	if (alloc_subdevices(dev, n_subdevs) < 0) {
-		printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
-				dev->minor);
-		return -ENOMEM;
-	}
-
-	/* First, AI */
-	sdev_no = 0;
-	s = dev->subdevices + sdev_no;
-	s->private = devpriv->sprivs + sdev_no;
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
-	s->range_table = thisboard->ai_range_table;
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
-	s->type = COMEDI_SUBD_AI;
-	s->n_chan = thisboard->n_ai_chans;
-	s->len_chanlist = s->n_chan;
-	s->insn_read = thisboard->ai_rinsn;
-	subpriv->iobase = dev->iobase + 0;
-	/* initialize the resource enable register by clearing it */
-	outb(0, subpriv->iobase + 3);
-	outb(0, subpriv->iobase + 4 + 3);
-
-	/* Next, AO */
-	++sdev_no;
-	s = dev->subdevices + sdev_no;
-	s->private = devpriv->sprivs + sdev_no;
-	s->maxdata = (1 << thisboard->ao_bits) - 1;
-	s->range_table = thisboard->ao_range_table;
-	s->subdev_flags = SDF_READABLE;
-	s->type = COMEDI_SUBD_AO;
-	s->n_chan = thisboard->n_ao_chans;
-	s->len_chanlist = s->n_chan;
-	s->insn_read = thisboard->ao_rinsn;
-	s->insn_write = thisboard->ao_winsn;
-	subpriv->iobase = dev->iobase + 8;
-	/* initialize the resource enable register by clearing it */
-	outb(0, subpriv->iobase + 3);
-	outb(0, subpriv->iobase + 4 + 3);
-
-	++sdev_no;
-	port = 0;
-	asic = 0;
-	for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
-		int byte_no;
-
-		s = dev->subdevices + sdev_no;
-		s->private = devpriv->sprivs + sdev_no;
-		s->maxdata = 1;
-		s->range_table = &range_digital;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->type = COMEDI_SUBD_DIO;
-		s->insn_bits = pcmmio_dio_insn_bits;
-		s->insn_config = pcmmio_dio_insn_config;
-		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
-		subpriv->dio.intr.asic = -1;
-		subpriv->dio.intr.first_chan = -1;
-		subpriv->dio.intr.asic_chan = -1;
-		subpriv->dio.intr.num_asic_chans = -1;
-		subpriv->dio.intr.active = 0;
-		s->len_chanlist = 1;
-
-		/* save the ioport address for each 'port' of 8 channels in the
-		   subdevice */
-		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
-			if (port >= PORTS_PER_ASIC) {
-				port = 0;
-				++asic;
-				thisasic_chanct = 0;
-			}
-			subpriv->iobases[byte_no] =
-			    devpriv->asics[asic].iobase + port;
-
-			if (thisasic_chanct <
-			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
-			    && subpriv->dio.intr.asic < 0) {
-				/*
-				 * this is an interrupt subdevice,
-				 * so setup the struct
-				 */
-				subpriv->dio.intr.asic = asic;
-				subpriv->dio.intr.active = 0;
-				subpriv->dio.intr.stop_count = 0;
-				subpriv->dio.intr.first_chan = byte_no * 8;
-				subpriv->dio.intr.asic_chan = thisasic_chanct;
-				subpriv->dio.intr.num_asic_chans =
-				    s->n_chan - subpriv->dio.intr.first_chan;
-				s->cancel = pcmmio_cancel;
-				s->do_cmd = pcmmio_cmd;
-				s->do_cmdtest = pcmmio_cmdtest;
-				s->len_chanlist =
-				    subpriv->dio.intr.num_asic_chans;
-			}
-			thisasic_chanct += CHANS_PER_PORT;
-		}
-		spin_lock_init(&subpriv->dio.intr.spinlock);
-
-		chans_left -= s->n_chan;
-
-		if (!chans_left) {
-			/*
-			 * reset the asic to our first asic,
-			 * to do intr subdevs
-			 */
-			asic = 0;
-			port = 0;
-		}
-
-	}
-
-	init_asics(dev);	/* clear out all the registers, basically */
-
-	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
-		if (irq[asic]
-		    && request_irq(irq[asic], interrupt_pcmmio,
-				   IRQF_SHARED, thisboard->name, dev)) {
-			int i;
-			/* unroll the allocated irqs.. */
-			for (i = asic - 1; i >= 0; --i) {
-				free_irq(irq[i], dev);
-				devpriv->asics[i].irq = irq[i] = 0;
-			}
-			irq[asic] = 0;
-		}
-		devpriv->asics[asic].irq = irq[asic];
-	}
-
-	dev->irq = irq[0];	/*
-				 * grr.. wish comedi dev struct supported
-				 * multiple irqs..
-				 */
-
-	if (irq[0]) {
-		printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
-		if (thisboard->dio_num_asics == 2 && irq[1])
-			printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
-					dev->minor, irq[1]);
-	} else {
-		printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
-	}
-
-	printk(KERN_INFO "comedi%d: attached\n", dev->minor);
-
-	return 1;
-}
-
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcmmio_detach(struct comedi_device *dev)
-{
-	int i;
-
-	printk(KERN_INFO "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
-	if (dev->iobase)
-		release_region(dev->iobase, thisboard->total_iosize);
-
-	for (i = 0; i < MAX_ASICS; ++i) {
-		if (devpriv && devpriv->asics[i].irq)
-			free_irq(devpriv->asics[i].irq, dev);
-	}
-
-	if (devpriv && devpriv->sprivs)
-		kfree(devpriv->sprivs);
-
-	return 0;
-}
 
 /* DIO devices are slightly special.  Although it is possible to
  * implement the insn_read/insn_write interface, it is much more
@@ -667,7 +337,7 @@
 		}
 #ifdef DAMMIT_ITS_BROKEN
 		/* DEBUG */
-		printk("data_out_byte %02x\n", (unsigned)byte);
+		printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
 #endif
 		/* save the digital input lines for this byte.. */
 		s->state |= ((unsigned int)byte) << offset;
@@ -751,6 +421,21 @@
 	return insn->n;
 }
 
+static void switch_page(struct comedi_device *dev, int asic, int page)
+{
+	if (asic < 0 || asic >= thisboard->dio_num_asics)
+		return;		/* paranoia */
+	if (page < 0 || page >= NUM_PAGES)
+		return;		/* more paranoia */
+
+	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
+	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
+
+	/* now write out the shadow register */
+	outb(devpriv->asics[asic].pagelock,
+	     devpriv->asics[asic].iobase + REG_PAGELOCK);
+}
+
 static void init_asics(struct comedi_device *dev)
 {				/* sets up an
 				   ASIC chip to defaults */
@@ -788,21 +473,6 @@
 	}
 }
 
-static void switch_page(struct comedi_device *dev, int asic, int page)
-{
-	if (asic < 0 || asic >= thisboard->dio_num_asics)
-		return;		/* paranoia */
-	if (page < 0 || page >= NUM_PAGES)
-		return;		/* more paranoia */
-
-	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
-	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
-
-	/* now write out the shadow register */
-	outb(devpriv->asics[asic].pagelock,
-	     devpriv->asics[asic].iobase + REG_PAGELOCK);
-}
-
 #ifdef notused
 static void lock_port(struct comedi_device *dev, int asic, int port)
 {
@@ -831,6 +501,27 @@
 }
 #endif /* notused */
 
+static void pcmmio_stop_intr(struct comedi_device *dev,
+			     struct comedi_subdevice *s)
+{
+	int nports, firstport, asic, port;
+
+	asic = subpriv->dio.intr.asic;
+	if (asic < 0)
+		return;		/* not an interrupt subdev */
+
+	subpriv->dio.intr.enabled_mask = 0;
+	subpriv->dio.intr.active = 0;
+	s->async->inttrig = 0;
+	nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
+	firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
+	switch_page(dev, asic, PAGE_ENAB);
+	for (port = firstport; port < firstport + nports; ++port) {
+		/* disable all intrs for this subdev.. */
+		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
+	}
+}
+
 static irqreturn_t interrupt_pcmmio(int irq, void *d)
 {
 	int asic, got1 = 0;
@@ -991,27 +682,6 @@
 	return IRQ_HANDLED;
 }
 
-static void pcmmio_stop_intr(struct comedi_device *dev,
-			     struct comedi_subdevice *s)
-{
-	int nports, firstport, asic, port;
-
-	asic = subpriv->dio.intr.asic;
-	if (asic < 0)
-		return;		/* not an interrupt subdev */
-
-	subpriv->dio.intr.enabled_mask = 0;
-	subpriv->dio.intr.active = 0;
-	s->async->inttrig = 0;
-	nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
-	firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
-	switch_page(dev, asic, PAGE_ENAB);
-	for (port = firstport; port < firstport + nports; ++port) {
-		/* disable all intrs for this subdev.. */
-		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
-	}
-}
-
 static int pcmmio_start_intr(struct comedi_device *dev,
 			     struct comedi_subdevice *s)
 {
@@ -1340,22 +1010,261 @@
 	return n;
 }
 
+static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
+	    thisasic_chanct = 0;
+	unsigned long iobase;
+	unsigned int irq[MAX_ASICS];
+
+	iobase = it->options[0];
+	irq[0] = it->options[1];
+
+	printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
+			dev->driver->driver_name, iobase);
+
+	dev->iobase = iobase;
+
+	if (!iobase || !request_region(iobase,
+				       thisboard->total_iosize,
+				       dev->driver->driver_name)) {
+		printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
+		return -EIO;
+	}
+
 /*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name.  Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
  */
-static int __init driver_init_module(void)
-{
-	return comedi_driver_register(&driver);
+	dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area.  alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+	if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
+		printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
+				dev->minor);
+		return -ENOMEM;
+	}
+
+	for (asic = 0; asic < MAX_ASICS; ++asic) {
+		devpriv->asics[asic].num = asic;
+		devpriv->asics[asic].iobase =
+		    dev->iobase + 16 + asic * ASIC_IOSIZE;
+		/*
+		 * this gets actually set at the end of this function when we
+		 * request_irqs
+		 */
+		devpriv->asics[asic].irq = 0;
+		spin_lock_init(&devpriv->asics[asic].spinlock);
+	}
+
+	chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
+	n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
+	n_subdevs = n_dio_subdevs + 2;
+	devpriv->sprivs =
+	    kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
+		    GFP_KERNEL);
+	if (!devpriv->sprivs) {
+		printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
+				dev->minor);
+		return -ENOMEM;
+	}
+	/*
+	 * Allocate the subdevice structures.  alloc_subdevice() is a
+	 * convenient macro defined in comedidev.h.
+	 *
+	 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
+	 */
+	if (alloc_subdevices(dev, n_subdevs) < 0) {
+		printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
+				dev->minor);
+		return -ENOMEM;
+	}
+
+	/* First, AI */
+	sdev_no = 0;
+	s = dev->subdevices + sdev_no;
+	s->private = devpriv->sprivs + sdev_no;
+	s->maxdata = (1 << thisboard->ai_bits) - 1;
+	s->range_table = thisboard->ai_range_table;
+	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
+	s->type = COMEDI_SUBD_AI;
+	s->n_chan = thisboard->n_ai_chans;
+	s->len_chanlist = s->n_chan;
+	s->insn_read = thisboard->ai_rinsn;
+	subpriv->iobase = dev->iobase + 0;
+	/* initialize the resource enable register by clearing it */
+	outb(0, subpriv->iobase + 3);
+	outb(0, subpriv->iobase + 4 + 3);
+
+	/* Next, AO */
+	++sdev_no;
+	s = dev->subdevices + sdev_no;
+	s->private = devpriv->sprivs + sdev_no;
+	s->maxdata = (1 << thisboard->ao_bits) - 1;
+	s->range_table = thisboard->ao_range_table;
+	s->subdev_flags = SDF_READABLE;
+	s->type = COMEDI_SUBD_AO;
+	s->n_chan = thisboard->n_ao_chans;
+	s->len_chanlist = s->n_chan;
+	s->insn_read = thisboard->ao_rinsn;
+	s->insn_write = thisboard->ao_winsn;
+	subpriv->iobase = dev->iobase + 8;
+	/* initialize the resource enable register by clearing it */
+	outb(0, subpriv->iobase + 3);
+	outb(0, subpriv->iobase + 4 + 3);
+
+	++sdev_no;
+	port = 0;
+	asic = 0;
+	for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
+		int byte_no;
+
+		s = dev->subdevices + sdev_no;
+		s->private = devpriv->sprivs + sdev_no;
+		s->maxdata = 1;
+		s->range_table = &range_digital;
+		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+		s->type = COMEDI_SUBD_DIO;
+		s->insn_bits = pcmmio_dio_insn_bits;
+		s->insn_config = pcmmio_dio_insn_config;
+		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
+		subpriv->dio.intr.asic = -1;
+		subpriv->dio.intr.first_chan = -1;
+		subpriv->dio.intr.asic_chan = -1;
+		subpriv->dio.intr.num_asic_chans = -1;
+		subpriv->dio.intr.active = 0;
+		s->len_chanlist = 1;
+
+		/* save the ioport address for each 'port' of 8 channels in the
+		   subdevice */
+		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
+			if (port >= PORTS_PER_ASIC) {
+				port = 0;
+				++asic;
+				thisasic_chanct = 0;
+			}
+			subpriv->iobases[byte_no] =
+			    devpriv->asics[asic].iobase + port;
+
+			if (thisasic_chanct <
+			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
+			    && subpriv->dio.intr.asic < 0) {
+				/*
+				 * this is an interrupt subdevice,
+				 * so setup the struct
+				 */
+				subpriv->dio.intr.asic = asic;
+				subpriv->dio.intr.active = 0;
+				subpriv->dio.intr.stop_count = 0;
+				subpriv->dio.intr.first_chan = byte_no * 8;
+				subpriv->dio.intr.asic_chan = thisasic_chanct;
+				subpriv->dio.intr.num_asic_chans =
+				    s->n_chan - subpriv->dio.intr.first_chan;
+				s->cancel = pcmmio_cancel;
+				s->do_cmd = pcmmio_cmd;
+				s->do_cmdtest = pcmmio_cmdtest;
+				s->len_chanlist =
+				    subpriv->dio.intr.num_asic_chans;
+			}
+			thisasic_chanct += CHANS_PER_PORT;
+		}
+		spin_lock_init(&subpriv->dio.intr.spinlock);
+
+		chans_left -= s->n_chan;
+
+		if (!chans_left) {
+			/*
+			 * reset the asic to our first asic,
+			 * to do intr subdevs
+			 */
+			asic = 0;
+			port = 0;
+		}
+
+	}
+
+	init_asics(dev);	/* clear out all the registers, basically */
+
+	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
+		if (irq[asic]
+		    && request_irq(irq[asic], interrupt_pcmmio,
+				   IRQF_SHARED, thisboard->name, dev)) {
+			int i;
+			/* unroll the allocated irqs.. */
+			for (i = asic - 1; i >= 0; --i) {
+				free_irq(irq[i], dev);
+				devpriv->asics[i].irq = irq[i] = 0;
+			}
+			irq[asic] = 0;
+		}
+		devpriv->asics[asic].irq = irq[asic];
+	}
+
+	dev->irq = irq[0];	/*
+				 * grr.. wish comedi dev struct supported
+				 * multiple irqs..
+				 */
+
+	if (irq[0]) {
+		printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
+		if (thisboard->dio_num_asics == 2 && irq[1])
+			printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
+					dev->minor, irq[1]);
+	} else {
+		printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
+	}
+
+	printk(KERN_INFO "comedi%d: attached\n", dev->minor);
+
+	return 1;
 }
 
-static void __exit driver_cleanup_module(void)
+static void pcmmio_detach(struct comedi_device *dev)
 {
-	comedi_driver_unregister(&driver);
+	int i;
+
+	if (dev->iobase)
+		release_region(dev->iobase, thisboard->total_iosize);
+	for (i = 0; i < MAX_ASICS; ++i) {
+		if (devpriv && devpriv->asics[i].irq)
+			free_irq(devpriv->asics[i].irq, dev);
+	}
+	if (devpriv && devpriv->sprivs)
+		kfree(devpriv->sprivs);
 }
 
-module_init(driver_init_module);
-module_exit(driver_cleanup_module);
+static const struct pcmmio_board pcmmio_boards[] = {
+	{
+		.name		= "pcmmio",
+		.dio_num_asics	= 1,
+		.dio_num_ports	= 6,
+		.total_iosize	= 32,
+		.ai_bits	= 16,
+		.ao_bits	= 16,
+		.n_ai_chans	= 16,
+		.n_ao_chans	= 8,
+		.ai_range_table	= &ranges_ai,
+		.ao_range_table	= &ranges_ao,
+		.ai_rinsn	= ai_rinsn,
+		.ao_rinsn	= ao_rinsn,
+		.ao_winsn	= ao_winsn
+	},
+};
+
+static struct comedi_driver pcmmio_driver = {
+	.driver_name	= "pcmmio",
+	.module		= THIS_MODULE,
+	.attach		= pcmmio_attach,
+	.detach		= pcmmio_detach,
+	.board_name	= &pcmmio_boards[0].name,
+	.offset		= sizeof(struct pcmmio_board),
+	.num_names	= ARRAY_SIZE(pcmmio_boards),
+};
+module_comedi_driver(pcmmio_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 661ba2e..623381d5 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -155,19 +155,6 @@
 	const int num_ports;
 };
 
-static const struct pcmuio_board pcmuio_boards[] = {
-	{
-	 .name = "pcmuio48",
-	 .num_asics = 1,
-	 .num_ports = 6,
-	 },
-	{
-	 .name = "pcmuio96",
-	 .num_asics = 2,
-	 .num_ports = 12,
-	 },
-};
-
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -218,262 +205,6 @@
  */
 #define devpriv ((struct pcmuio_private *)dev->private)
 #define subpriv ((struct pcmuio_subdev_private *)s->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcmuio_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int pcmuio_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
-	.driver_name = "pcmuio",
-	.module = THIS_MODULE,
-	.attach = pcmuio_attach,
-	.detach = pcmuio_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
-	/* Most drivers will support multiple types of boards by
-	 * having an array of board structures.  These were defined
-	 * in pcmuio_boards[] above.  Note that the element 'name'
-	 * was first in the structure -- Comedi uses this fact to
-	 * extract the name of the board without knowing any details
-	 * about the structure except for its length.
-	 * When a device is attached (by comedi_config), the name
-	 * of the device is given to Comedi, and Comedi tries to
-	 * match it by going through the list of board names.  If
-	 * there is a match, the address of the pointer is put
-	 * into dev->board_ptr and driver->attach() is called.
-	 *
-	 * Note that these are not necessary if you can determine
-	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
-	 * devices are such boards.
-	 */
-	.board_name = &pcmuio_boards[0].name,
-	.offset = sizeof(struct pcmuio_board),
-	.num_names = ARRAY_SIZE(pcmuio_boards),
-};
-
-static int pcmuio_dio_insn_bits(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-static int pcmuio_dio_insn_config(struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data);
-
-static irqreturn_t interrupt_pcmuio(int irq, void *d);
-static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
-static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_cmd *cmd);
-
-/* some helper functions to deal with specifics of this device's registers */
-static void init_asics(struct comedi_device *dev);	/* sets up/clears ASIC chips to defaults */
-static void switch_page(struct comedi_device *dev, int asic, int page);
-#ifdef notused
-static void lock_port(struct comedi_device *dev, int asic, int port);
-static void unlock_port(struct comedi_device *dev, int asic, int port);
-#endif
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
-	unsigned long iobase;
-	unsigned int irq[MAX_ASICS];
-
-	iobase = it->options[0];
-	irq[0] = it->options[1];
-	irq[1] = it->options[2];
-
-	dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
-		driver.driver_name, iobase);
-
-	dev->iobase = iobase;
-
-	if (!iobase || !request_region(iobase,
-				       thisboard->num_asics * ASIC_IOSIZE,
-				       driver.driver_name)) {
-		dev_err(dev->hw_dev, "I/O port conflict\n");
-		return -EIO;
-	}
-
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
-		dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
-		return -ENOMEM;
-	}
-
-	for (asic = 0; asic < MAX_ASICS; ++asic) {
-		devpriv->asics[asic].num = asic;
-		devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
-		devpriv->asics[asic].irq = 0;	/* this gets actually set at the end of
-						   this function when we
-						   request_irqs */
-		spin_lock_init(&devpriv->asics[asic].spinlock);
-	}
-
-	chans_left = CHANS_PER_ASIC * thisboard->num_asics;
-	n_subdevs = CALC_N_SUBDEVS(chans_left);
-	devpriv->sprivs =
-	    kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
-		    GFP_KERNEL);
-	if (!devpriv->sprivs) {
-		dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
-		return -ENOMEM;
-	}
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 *
-	 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
-	 * 96-channel version of the board.
-	 */
-	if (alloc_subdevices(dev, n_subdevs) < 0) {
-		dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
-		return -ENOMEM;
-	}
-
-	port = 0;
-	asic = 0;
-	for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
-		int byte_no;
-
-		s = dev->subdevices + sdev_no;
-		s->private = devpriv->sprivs + sdev_no;
-		s->maxdata = 1;
-		s->range_table = &range_digital;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->type = COMEDI_SUBD_DIO;
-		s->insn_bits = pcmuio_dio_insn_bits;
-		s->insn_config = pcmuio_dio_insn_config;
-		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
-		subpriv->intr.asic = -1;
-		subpriv->intr.first_chan = -1;
-		subpriv->intr.asic_chan = -1;
-		subpriv->intr.num_asic_chans = -1;
-		subpriv->intr.active = 0;
-		s->len_chanlist = 1;
-
-		/* save the ioport address for each 'port' of 8 channels in the
-		   subdevice */
-		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
-			if (port >= PORTS_PER_ASIC) {
-				port = 0;
-				++asic;
-				thisasic_chanct = 0;
-			}
-			subpriv->iobases[byte_no] =
-			    devpriv->asics[asic].iobase + port;
-
-			if (thisasic_chanct <
-			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
-			    && subpriv->intr.asic < 0) {
-				/* this is an interrupt subdevice, so setup the struct */
-				subpriv->intr.asic = asic;
-				subpriv->intr.active = 0;
-				subpriv->intr.stop_count = 0;
-				subpriv->intr.first_chan = byte_no * 8;
-				subpriv->intr.asic_chan = thisasic_chanct;
-				subpriv->intr.num_asic_chans =
-				    s->n_chan - subpriv->intr.first_chan;
-				dev->read_subdev = s;
-				s->subdev_flags |= SDF_CMD_READ;
-				s->cancel = pcmuio_cancel;
-				s->do_cmd = pcmuio_cmd;
-				s->do_cmdtest = pcmuio_cmdtest;
-				s->len_chanlist = subpriv->intr.num_asic_chans;
-			}
-			thisasic_chanct += CHANS_PER_PORT;
-		}
-		spin_lock_init(&subpriv->intr.spinlock);
-
-		chans_left -= s->n_chan;
-
-		if (!chans_left) {
-			asic = 0;	/* reset the asic to our first asic, to do intr subdevs */
-			port = 0;
-		}
-
-	}
-
-	init_asics(dev);	/* clear out all the registers, basically */
-
-	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
-		if (irq[asic]
-		    && request_irq(irq[asic], interrupt_pcmuio,
-				   IRQF_SHARED, thisboard->name, dev)) {
-			int i;
-			/* unroll the allocated irqs.. */
-			for (i = asic - 1; i >= 0; --i) {
-				free_irq(irq[i], dev);
-				devpriv->asics[i].irq = irq[i] = 0;
-			}
-			irq[asic] = 0;
-		}
-		devpriv->asics[asic].irq = irq[asic];
-	}
-
-	dev->irq = irq[0];	/* grr.. wish comedi dev struct supported multiple
-				   irqs.. */
-
-	if (irq[0]) {
-		dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
-		if (irq[1] && thisboard->num_asics == 2)
-			dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
-	} else {
-		dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
-	}
-
-
-	return 1;
-}
-
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcmuio_detach(struct comedi_device *dev)
-{
-	int i;
-
-	dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
-		driver.driver_name);
-	if (dev->iobase)
-		release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
-
-	for (i = 0; i < MAX_ASICS; ++i) {
-		if (devpriv->asics[i].irq)
-			free_irq(devpriv->asics[i].irq, dev);
-	}
-
-	if (devpriv && devpriv->sprivs)
-		kfree(devpriv->sprivs);
-
-	return 0;
-}
 
 /* DIO devices are slightly special.  Although it is possible to
  * implement the insn_read/insn_write interface, it is much more
@@ -621,6 +352,21 @@
 	return insn->n;
 }
 
+static void switch_page(struct comedi_device *dev, int asic, int page)
+{
+	if (asic < 0 || asic >= thisboard->num_asics)
+		return;		/* paranoia */
+	if (page < 0 || page >= NUM_PAGES)
+		return;		/* more paranoia */
+
+	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
+	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
+
+	/* now write out the shadow register */
+	outb(devpriv->asics[asic].pagelock,
+	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
+}
+
 static void init_asics(struct comedi_device *dev)
 {				/* sets up an
 				   ASIC chip to defaults */
@@ -658,21 +404,6 @@
 	}
 }
 
-static void switch_page(struct comedi_device *dev, int asic, int page)
-{
-	if (asic < 0 || asic >= thisboard->num_asics)
-		return;		/* paranoia */
-	if (page < 0 || page >= NUM_PAGES)
-		return;		/* more paranoia */
-
-	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
-	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
-
-	/* now write out the shadow register */
-	outb(devpriv->asics[asic].pagelock,
-	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
-}
-
 #ifdef notused
 static void lock_port(struct comedi_device *dev, int asic, int port)
 {
@@ -700,6 +431,27 @@
 }
 #endif /* notused */
 
+static void pcmuio_stop_intr(struct comedi_device *dev,
+			     struct comedi_subdevice *s)
+{
+	int nports, firstport, asic, port;
+
+	asic = subpriv->intr.asic;
+	if (asic < 0)
+		return;		/* not an interrupt subdev */
+
+	subpriv->intr.enabled_mask = 0;
+	subpriv->intr.active = 0;
+	s->async->inttrig = 0;
+	nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
+	firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
+	switch_page(dev, asic, PAGE_ENAB);
+	for (port = firstport; port < firstport + nports; ++port) {
+		/* disable all intrs for this subdev.. */
+		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
+	}
+}
+
 static irqreturn_t interrupt_pcmuio(int irq, void *d)
 {
 	int asic, got1 = 0;
@@ -852,27 +604,6 @@
 	return IRQ_HANDLED;
 }
 
-static void pcmuio_stop_intr(struct comedi_device *dev,
-			     struct comedi_subdevice *s)
-{
-	int nports, firstport, asic, port;
-
-	asic = subpriv->intr.asic;
-	if (asic < 0)
-		return;		/* not an interrupt subdev */
-
-	subpriv->intr.enabled_mask = 0;
-	subpriv->intr.active = 0;
-	s->async->inttrig = 0;
-	nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
-	firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
-	switch_page(dev, asic, PAGE_ENAB);
-	for (port = firstport; port < firstport + nports; ++port) {
-		/* disable all intrs for this subdev.. */
-		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
-	}
-}
-
 static int pcmuio_start_intr(struct comedi_device *dev,
 			     struct comedi_subdevice *s)
 {
@@ -1014,22 +745,205 @@
 	return comedi_pcm_cmdtest(dev, s, cmd);
 }
 
+static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
+	unsigned long iobase;
+	unsigned int irq[MAX_ASICS];
+
+	iobase = it->options[0];
+	irq[0] = it->options[1];
+	irq[1] = it->options[2];
+
+	dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
+		dev->driver->driver_name, iobase);
+
+	dev->iobase = iobase;
+
+	if (!iobase || !request_region(iobase,
+				       thisboard->num_asics * ASIC_IOSIZE,
+				       dev->driver->driver_name)) {
+		dev_err(dev->hw_dev, "I/O port conflict\n");
+		return -EIO;
+	}
+
 /*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name.  Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
  */
-static int __init driver_init_module(void)
-{
-	return comedi_driver_register(&driver);
+	dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area.  alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+	if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
+		dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
+		return -ENOMEM;
+	}
+
+	for (asic = 0; asic < MAX_ASICS; ++asic) {
+		devpriv->asics[asic].num = asic;
+		devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
+		devpriv->asics[asic].irq = 0;	/* this gets actually set at the end of
+						   this function when we
+						   request_irqs */
+		spin_lock_init(&devpriv->asics[asic].spinlock);
+	}
+
+	chans_left = CHANS_PER_ASIC * thisboard->num_asics;
+	n_subdevs = CALC_N_SUBDEVS(chans_left);
+	devpriv->sprivs =
+	    kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
+		    GFP_KERNEL);
+	if (!devpriv->sprivs) {
+		dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
+		return -ENOMEM;
+	}
+	/*
+	 * Allocate the subdevice structures.  alloc_subdevice() is a
+	 * convenient macro defined in comedidev.h.
+	 *
+	 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
+	 * 96-channel version of the board.
+	 */
+	if (alloc_subdevices(dev, n_subdevs) < 0) {
+		dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
+		return -ENOMEM;
+	}
+
+	port = 0;
+	asic = 0;
+	for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
+		int byte_no;
+
+		s = dev->subdevices + sdev_no;
+		s->private = devpriv->sprivs + sdev_no;
+		s->maxdata = 1;
+		s->range_table = &range_digital;
+		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+		s->type = COMEDI_SUBD_DIO;
+		s->insn_bits = pcmuio_dio_insn_bits;
+		s->insn_config = pcmuio_dio_insn_config;
+		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
+		subpriv->intr.asic = -1;
+		subpriv->intr.first_chan = -1;
+		subpriv->intr.asic_chan = -1;
+		subpriv->intr.num_asic_chans = -1;
+		subpriv->intr.active = 0;
+		s->len_chanlist = 1;
+
+		/* save the ioport address for each 'port' of 8 channels in the
+		   subdevice */
+		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
+			if (port >= PORTS_PER_ASIC) {
+				port = 0;
+				++asic;
+				thisasic_chanct = 0;
+			}
+			subpriv->iobases[byte_no] =
+			    devpriv->asics[asic].iobase + port;
+
+			if (thisasic_chanct <
+			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
+			    && subpriv->intr.asic < 0) {
+				/* this is an interrupt subdevice, so setup the struct */
+				subpriv->intr.asic = asic;
+				subpriv->intr.active = 0;
+				subpriv->intr.stop_count = 0;
+				subpriv->intr.first_chan = byte_no * 8;
+				subpriv->intr.asic_chan = thisasic_chanct;
+				subpriv->intr.num_asic_chans =
+				    s->n_chan - subpriv->intr.first_chan;
+				dev->read_subdev = s;
+				s->subdev_flags |= SDF_CMD_READ;
+				s->cancel = pcmuio_cancel;
+				s->do_cmd = pcmuio_cmd;
+				s->do_cmdtest = pcmuio_cmdtest;
+				s->len_chanlist = subpriv->intr.num_asic_chans;
+			}
+			thisasic_chanct += CHANS_PER_PORT;
+		}
+		spin_lock_init(&subpriv->intr.spinlock);
+
+		chans_left -= s->n_chan;
+
+		if (!chans_left) {
+			asic = 0;	/* reset the asic to our first asic, to do intr subdevs */
+			port = 0;
+		}
+
+	}
+
+	init_asics(dev);	/* clear out all the registers, basically */
+
+	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
+		if (irq[asic]
+		    && request_irq(irq[asic], interrupt_pcmuio,
+				   IRQF_SHARED, thisboard->name, dev)) {
+			int i;
+			/* unroll the allocated irqs.. */
+			for (i = asic - 1; i >= 0; --i) {
+				free_irq(irq[i], dev);
+				devpriv->asics[i].irq = irq[i] = 0;
+			}
+			irq[asic] = 0;
+		}
+		devpriv->asics[asic].irq = irq[asic];
+	}
+
+	dev->irq = irq[0];	/* grr.. wish comedi dev struct supported multiple
+				   irqs.. */
+
+	if (irq[0]) {
+		dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
+		if (irq[1] && thisboard->num_asics == 2)
+			dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
+	} else {
+		dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
+	}
+
+
+	return 1;
 }
 
-static void __exit driver_cleanup_module(void)
+static void pcmuio_detach(struct comedi_device *dev)
 {
-	comedi_driver_unregister(&driver);
+	int i;
+
+	if (dev->iobase)
+		release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
+	for (i = 0; i < MAX_ASICS; ++i) {
+		if (devpriv->asics[i].irq)
+			free_irq(devpriv->asics[i].irq, dev);
+	}
+	if (devpriv && devpriv->sprivs)
+		kfree(devpriv->sprivs);
 }
 
-module_init(driver_init_module);
-module_exit(driver_cleanup_module);
+static const struct pcmuio_board pcmuio_boards[] = {
+	{
+		.name		= "pcmuio48",
+		.num_asics	= 1,
+		.num_ports	= 6,
+	}, {
+		.name		= "pcmuio96",
+		.num_asics	= 2,
+		.num_ports	= 12,
+	},
+};
+
+static struct comedi_driver pcmuio_driver = {
+	.driver_name	= "pcmuio",
+	.module		= THIS_MODULE,
+	.attach		= pcmuio_attach,
+	.detach		= pcmuio_detach,
+	.board_name	= &pcmuio_boards[0].name,
+	.offset		= sizeof(struct pcmuio_board),
+	.num_names	= ARRAY_SIZE(pcmuio_boards),
+};
+module_comedi_driver(pcmuio_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index 831a576..e712048 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -41,20 +41,6 @@
 
 #include <linux/ioport.h>
 
-static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int poc_detach(struct comedi_device *dev);
-static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
-			 struct comedi_insn *insn, unsigned int *data);
-
-static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-static int pcl733_insn_bits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int pcl734_insn_bits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-
 struct boarddef_struct {
 	const char *name;
 	unsigned int iosize;
@@ -70,108 +56,9 @@
 			 struct comedi_insn *, unsigned int *);
 	const struct comedi_lrange *range;
 };
-static const struct boarddef_struct boards[] = {
-	{
-	 .name = "dac02",
-	 .iosize = 8,
-	 /*      .setup = dac02_setup, */
-	 .type = COMEDI_SUBD_AO,
-	 .n_chan = 2,
-	 .n_bits = 12,
-	 .winsn = dac02_ao_winsn,
-	 .rinsn = readback_insn,
-	 .range = &range_unknown,
-	 },
-	{
-	 .name = "pcl733",
-	 .iosize = 4,
-	 .type = COMEDI_SUBD_DI,
-	 .n_chan = 32,
-	 .n_bits = 1,
-	 .insnbits = pcl733_insn_bits,
-	 .range = &range_digital,
-	 },
-	{
-	 .name = "pcl734",
-	 .iosize = 4,
-	 .type = COMEDI_SUBD_DO,
-	 .n_chan = 32,
-	 .n_bits = 1,
-	 .insnbits = pcl734_insn_bits,
-	 .range = &range_digital,
-	 },
-};
 
-#define n_boards ARRAY_SIZE(boards)
 #define this_board ((const struct boarddef_struct *)dev->board_ptr)
 
-static struct comedi_driver driver_poc = {
-	.driver_name = "poc",
-	.module = THIS_MODULE,
-	.attach = poc_attach,
-	.detach = poc_detach,
-	.board_name = &boards[0].name,
-	.num_names = n_boards,
-	.offset = sizeof(boards[0]),
-};
-
-static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	unsigned long iobase;
-	unsigned int iosize;
-
-	iobase = it->options[0];
-	printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
-	       this_board->name, iobase);
-
-	dev->board_name = this_board->name;
-
-	if (iobase == 0) {
-		printk(KERN_ERR "io base address required\n");
-		return -EINVAL;
-	}
-
-	iosize = this_board->iosize;
-	/* check if io addresses are available */
-	if (!request_region(iobase, iosize, "dac02")) {
-		printk(KERN_ERR "I/O port conflict: failed to allocate ports "
-			"0x%lx to 0x%lx\n", iobase, iobase + iosize - 1);
-		return -EIO;
-	}
-	dev->iobase = iobase;
-
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
-	if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0)
-		return -ENOMEM;
-
-	/* analog output subdevice */
-	s = dev->subdevices + 0;
-	s->type = this_board->type;
-	s->n_chan = this_board->n_chan;
-	s->maxdata = (1 << this_board->n_bits) - 1;
-	s->range_table = this_board->range;
-	s->insn_write = this_board->winsn;
-	s->insn_read = this_board->rinsn;
-	s->insn_bits = this_board->insnbits;
-	if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
-		s->subdev_flags = SDF_WRITABLE;
-
-	return 0;
-}
-
-static int poc_detach(struct comedi_device *dev)
-{
-	/* only free stuff if it has been allocated by _attach */
-	if (dev->iobase)
-		release_region(dev->iobase, this_board->iosize);
-
-	printk(KERN_INFO "comedi%d: dac02: remove\n", dev->minor);
-
-	return 0;
-}
-
 static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 			 struct comedi_insn *insn, unsigned int *data)
 {
@@ -248,18 +135,98 @@
 	return 2;
 }
 
-static int __init driver_poc_init_module(void)
+static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	return comedi_driver_register(&driver_poc);
+	struct comedi_subdevice *s;
+	unsigned long iobase;
+	unsigned int iosize;
+
+	iobase = it->options[0];
+	printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
+	       this_board->name, iobase);
+
+	dev->board_name = this_board->name;
+
+	if (iobase == 0) {
+		printk(KERN_ERR "io base address required\n");
+		return -EINVAL;
+	}
+
+	iosize = this_board->iosize;
+	/* check if io addresses are available */
+	if (!request_region(iobase, iosize, "dac02")) {
+		printk(KERN_ERR "I/O port conflict: failed to allocate ports "
+			"0x%lx to 0x%lx\n", iobase, iobase + iosize - 1);
+		return -EIO;
+	}
+	dev->iobase = iobase;
+
+	if (alloc_subdevices(dev, 1) < 0)
+		return -ENOMEM;
+	if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0)
+		return -ENOMEM;
+
+	/* analog output subdevice */
+	s = dev->subdevices + 0;
+	s->type = this_board->type;
+	s->n_chan = this_board->n_chan;
+	s->maxdata = (1 << this_board->n_bits) - 1;
+	s->range_table = this_board->range;
+	s->insn_write = this_board->winsn;
+	s->insn_read = this_board->rinsn;
+	s->insn_bits = this_board->insnbits;
+	if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
+		s->subdev_flags = SDF_WRITABLE;
+
+	return 0;
 }
 
-static void __exit driver_poc_cleanup_module(void)
+static void poc_detach(struct comedi_device *dev)
 {
-	comedi_driver_unregister(&driver_poc);
+	if (dev->iobase)
+		release_region(dev->iobase, this_board->iosize);
 }
 
-module_init(driver_poc_init_module);
-module_exit(driver_poc_cleanup_module);
+static const struct boarddef_struct boards[] = {
+	{
+		.name		= "dac02",
+		.iosize		= 8,
+		/* .setup	= dac02_setup, */
+		.type		= COMEDI_SUBD_AO,
+		.n_chan		= 2,
+		.n_bits		= 12,
+		.winsn		= dac02_ao_winsn,
+		.rinsn		= readback_insn,
+		.range		= &range_unknown,
+	}, {
+		.name		= "pcl733",
+		.iosize		= 4,
+		.type		= COMEDI_SUBD_DI,
+		.n_chan		= 32,
+		.n_bits		= 1,
+		.insnbits	= pcl733_insn_bits,
+		.range		= &range_digital,
+	}, {
+		.name		= "pcl734",
+		.iosize		= 4,
+		.type		= COMEDI_SUBD_DO,
+		.n_chan		= 32,
+		.n_bits		= 1,
+		.insnbits	= pcl734_insn_bits,
+		.range		= &range_digital,
+	},
+};
+
+static struct comedi_driver poc_driver = {
+	.driver_name	= "poc",
+	.module		= THIS_MODULE,
+	.attach		= poc_attach,
+	.detach		= poc_detach,
+	.board_name	= &boards[0].name,
+	.num_names	= ARRAY_SIZE(boards),
+	.offset		= sizeof(boards[0]),
+};
+module_comedi_driver(poc_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index e0bb734..2f130b3 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -181,7 +181,7 @@
 /* comedi interface code */
 
 static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int daqp_detach(struct comedi_device *dev);
+static void daqp_detach(struct comedi_device *dev);
 static struct comedi_driver driver_daqp = {
 	.driver_name = "quatech_daqp_cs",
 	.module = THIS_MODULE,
@@ -922,15 +922,9 @@
 	return 1;
 }
 
-/* daqp_detach (called from comedi_comdig) does nothing. If the PCMCIA
- * card is removed, daqp_cs_detach() is called by the pcmcia subsystem.
- */
-
-static int daqp_detach(struct comedi_device *dev)
+static void daqp_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: detaching daqp\n", dev->minor);
-
-	return 0;
+	/* Nothing to cleanup */
 }
 
 /*====================================================================
@@ -1010,8 +1004,6 @@
 {
 	struct local_info_t *dev = link->priv;
 
-	dev_dbg(&link->dev, "daqp_cs_detach\n");
-
 	dev->stop = 1;
 	daqp_cs_release(link);
 
@@ -1019,7 +1011,7 @@
 	dev_table[dev->table_index] = NULL;
 	kfree(dev);
 
-}				/* daqp_cs_detach */
+}
 
 static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data)
 {
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 1384419..1678a0c 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -328,14 +328,6 @@
 	 },
 };
 
-static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
-
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -347,13 +339,13 @@
 */
 struct rtdPrivate {
 	/* memory mapped board structures */
-	void *las0;
-	void *las1;
-	void *lcfg;
+	void __iomem *las0;
+	void __iomem *las1;
+	void __iomem *lcfg;
 
 	unsigned long intCount;	/* interrupt count */
 	long aiCount;		/* total transfer size (samples) */
-	int transCount;		/* # to tranfer data. 0->1/2FIFO */
+	int transCount;		/* # to transfer data. 0->1/2FIFO */
 	int flags;		/* flag event modes */
 
 	/* PCI device info */
@@ -377,8 +369,11 @@
 	u8 utcCtrl[4];		/* crtl mode for 3 utc + read back */
 	u8 dioStatus;		/* could be read back (dio0Ctrl) */
 #ifdef USE_DMA
-	/* Always DMA 1/2 FIFO.  Buffer (dmaBuff?) is (at least) twice that size.
-	   After transferring, interrupt processes 1/2 FIFO and passes to comedi */
+	/*
+	 * Always DMA 1/2 FIFO.  Buffer (dmaBuff?) is (at least) twice that
+	 * size.  After transferring, interrupt processes 1/2 FIFO and
+	 * passes to comedi
+	 */
 	s16 dma0Offset;		/* current processing offset (0, 1/2) */
 	uint16_t *dma0Buff[DMA_CHAIN_COUNT];	/* DMA buffers (for ADC) */
 	dma_addr_t dma0BuffPhysAddr[DMA_CHAIN_COUNT];	/* physical addresses */
@@ -581,7 +576,8 @@
 
 /* User output N source select (write only) */
 #define RtdUsrOutSource(dev, n, v) \
-	writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : LAS0_UOUT1_SELECT))
+	writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : \
+				LAS0_UOUT1_SELECT))
 
 /* Digital IO */
 #define RtdDio0Read(dev) \
@@ -608,7 +604,8 @@
 /* Write one data value (sign + 12bit + marker bits) */
 /* Note: matches what DMA would put.  Actual value << 3 */
 #define RtdDacFifoPut(dev, n, v) \
-	writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO))
+	writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : \
+				LAS1_DAC2_FIFO))
 
 /* Start single DAC conversion */
 #define RtdDacUpdate(dev, n) \
@@ -625,7 +622,8 @@
 
 /* Reset DAC FIFO */
 #define RtdDacClearFifo(dev, n) \
-	writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : LAS0_DAC2_RESET))
+	writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : \
+				LAS0_DAC2_RESET))
 
 /* Set source for DMA 0 (write only, shadow?) */
 #define RtdDma0Source(dev, n) \
@@ -705,22 +703,6 @@
 #define RtdDma1Status(dev) \
 	readb(devpriv->lcfg+LCFG_DMACSR1)
 
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attac/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int rtd_detach(struct comedi_device *dev);
-
-static struct comedi_driver rtd520Driver = {
-	.driver_name = DRV_NAME,
-	.module = THIS_MODULE,
-	.attach = rtd_attach,
-	.detach = rtd_detach,
-};
-
 static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 			struct comedi_insn *insn, unsigned int *data);
 static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -737,7 +719,10 @@
 			  struct comedi_cmd *cmd);
 static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
 static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-/* static int rtd_ai_poll (struct comedi_device *dev,struct comedi_subdevice *s); */
+/*
+ * static int rtd_ai_poll(struct comedi_device *dev,
+ *			  struct comedi_subdevice *s);
+ */
 static int rtd_ns_to_timer(unsigned int *ns, int roundMode);
 static irqreturn_t rtd_interrupt(int irq, void *d);
 static int rtd520_probe_fifo_depth(struct comedi_device *dev);
@@ -857,7 +842,9 @@
 			DPRINTK("rtd520: PCI latency = %d\n", pci_latency);
 		}
 
-		/* Undocumented EPLD version (doesn't match RTD driver results) */
+		/*
+		 * Undocumented EPLD version (doesn't match RTD driver results)
+		 */
 		/*DPRINTK ("rtd520: Reading epld from %p\n",
 		   devpriv->las0+0);
 		   epld_version = readl (devpriv->las0+0);
@@ -970,9 +957,11 @@
 #ifdef USE_DMA
 	if (dev->irq > 0) {
 		printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT);
-		/* The PLX9080 has 2 DMA controllers, but there could be 4 sources:
-		   ADC, digital, DAC1, and DAC2.  Since only the ADC supports cmd mode
-		   right now, this isn't an issue (yet) */
+		/*
+		 * The PLX9080 has 2 DMA controllers, but there could be
+		 * 4 sources: ADC, digital, DAC1, and DAC2.  Since only the
+		 * ADC supports cmd mode right now, this isn't an issue (yet)
+		 */
 		devpriv->dma0Offset = 0;
 
 		for (index = 0; index < DMA_CHAIN_COUNT; index++) {
@@ -988,10 +977,14 @@
 			}
 			/*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n",
 			   index,
-			   devpriv->dma0Buff[index], devpriv->dma0BuffPhysAddr[index]); */
+			   devpriv->dma0Buff[index],
+			   devpriv->dma0BuffPhysAddr[index]); */
 		}
 
-		/* setup DMA descriptor ring (use cpu_to_le32 for byte ordering?) */
+		/*
+		 * setup DMA descriptor ring (use cpu_to_le32 for byte
+		 * ordering?)
+		 */
 		devpriv->dma0Chain =
 		    pci_alloc_consistent(devpriv->pci_dev,
 					 sizeof(struct plx_dma_desc) *
@@ -1088,30 +1081,12 @@
 #endif
 }
 
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int rtd_detach(struct comedi_device *dev)
+static void rtd_detach(struct comedi_device *dev)
 {
 #ifdef USE_DMA
 	int index;
 #endif
 
-	DPRINTK("comedi%d: rtd520: removing (%ld ints)\n",
-		dev->minor, (devpriv ? devpriv->intCount : 0L));
-	if (devpriv && devpriv->lcfg) {
-		DPRINTK
-		    ("(int status 0x%x, overrun status 0x%x, fifo status 0x%x)...\n",
-		     0xffff & RtdInterruptStatus(dev),
-		     0xffff & RtdInterruptOverrunStatus(dev),
-		     (0xffff & RtdFifoStatus(dev)) ^ 0x6666);
-	}
-
 	if (devpriv) {
 		/* Shut down any board ops by resetting it */
 #ifdef USE_DMA
@@ -1148,37 +1123,24 @@
 			devpriv->dma0Chain = NULL;
 		}
 #endif /* USE_DMA */
-
-		/* release IRQ */
 		if (dev->irq) {
-			/* disable interrupt controller */
 			RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
 					     & ~(ICS_PLIE | ICS_DMA0_E |
 						 ICS_DMA1_E));
 			free_irq(dev->irq, dev);
 		}
-
-		/* release all regions that were allocated */
 		if (devpriv->las0)
 			iounmap(devpriv->las0);
-
 		if (devpriv->las1)
 			iounmap(devpriv->las1);
-
 		if (devpriv->lcfg)
 			iounmap(devpriv->lcfg);
-
 		if (devpriv->pci_dev) {
 			if (devpriv->got_regions)
 				comedi_pci_disable(devpriv->pci_dev);
-
 			pci_dev_put(devpriv->pci_dev);
 		}
 	}
-
-	printk(KERN_INFO "comedi%d: rtd520: removed.\n", dev->minor);
-
-	return 0;
 }
 
 /*
@@ -1278,7 +1240,8 @@
 		}
 	}
 	if (i == limit) {
-		printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n", DRV_NAME);
+		printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n",
+		       DRV_NAME);
 		return -EIO;
 	}
 	RtdAdcClearFifo(dev);
@@ -1378,9 +1341,10 @@
 		d = RtdAdcFifoGet(dev);	/* get 2s comp value */
 
 		d = d >> 3;	/* low 3 bits are marker lines */
-		if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan))
-			sample = d + 2048;	/* convert to comedi unsigned data */
-		else
+		if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
+			/* convert to comedi unsigned data */
+			sample = d + 2048;
+		} else
 			sample = d;
 
 		if (!comedi_buf_put(s->async, sample))
@@ -1406,9 +1370,10 @@
 		}
 
 		d = d >> 3;	/* low 3 bits are marker lines */
-		if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan))
-			sample = d + 2048;	/* convert to comedi unsigned data */
-		else
+		if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
+			/* convert to comedi unsigned data */
+			sample = d + 2048;
+		} else
 			sample = d;
 
 		if (!comedi_buf_put(s->async, sample))
@@ -1525,7 +1490,9 @@
 	comedi_buf_memcpy_to(s->async, 0, dp, n);
 	comedi_buf_write_free(s->async, n);
 
-	/* always at least 1 scan -- 1/2 FIFO is larger than our max scan list */
+	/*
+	 * always at least 1 scan -- 1/2 FIFO is larger than our max scan list
+	 */
 	s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
 
 	if (++devpriv->dma0Offset >= DMA_CHAIN_COUNT) {	/* next buffer */
@@ -1989,7 +1956,7 @@
 			    (TRANS_TARGET_PERIOD * cmd->chanlist_len) /
 			    cmd->scan_begin_arg;
 			if (devpriv->transCount < cmd->chanlist_len) {
-				/* tranfer after each scan (and avoid 0) */
+				/* transfer after each scan (and avoid 0) */
 				devpriv->transCount = cmd->chanlist_len;
 			} else {	/* make a multiple of scan length */
 				devpriv->transCount =
@@ -2005,12 +1972,12 @@
 			devpriv->transCount = 0;
 			devpriv->flags &= ~SEND_EOS;
 		} else {
-			/* interrupt for each tranfer */
+			/* interrupt for each transfer */
 			RtdAboutCounter(dev, devpriv->transCount - 1);
 		}
 
 		DPRINTK
-		    ("rtd520: scanLen=%d tranferCount=%d fifoLen=%d\n  scanTime(ns)=%d flags=0x%x\n",
+		    ("rtd520: scanLen=%d transferCount=%d fifoLen=%d\n  scanTime(ns)=%d flags=0x%x\n",
 		     cmd->chanlist_len, devpriv->transCount, devpriv->fifoLen,
 		     cmd->scan_begin_arg, devpriv->flags);
 	} else {		/* unknown timing, just use 1/2 FIFO */
@@ -2348,47 +2315,38 @@
 	return 1;
 }
 
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit rtd520Driver_pci_probe(struct pci_dev *dev,
-					    const struct pci_device_id *ent)
+static struct comedi_driver rtd520_driver = {
+	.driver_name	= "rtd520",
+	.module		= THIS_MODULE,
+	.attach		= rtd_attach,
+	.detach		= rtd_detach,
+};
+
+static int __devinit rtd520_pci_probe(struct pci_dev *dev,
+				      const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, rtd520Driver.driver_name);
+	return comedi_pci_auto_config(dev, &rtd520_driver);
 }
 
-static void __devexit rtd520Driver_pci_remove(struct pci_dev *dev)
+static void __devexit rtd520_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver rtd520Driver_pci_driver = {
-	.id_table = rtd520_pci_table,
-	.probe = &rtd520Driver_pci_probe,
-	.remove = __devexit_p(&rtd520Driver_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) },
+	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
 
-static int __init rtd520Driver_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&rtd520Driver);
-	if (retval < 0)
-		return retval;
-
-	rtd520Driver_pci_driver.name = (char *)rtd520Driver.driver_name;
-	return pci_register_driver(&rtd520Driver_pci_driver);
-}
-
-static void __exit rtd520Driver_cleanup_module(void)
-{
-	pci_unregister_driver(&rtd520Driver_pci_driver);
-	comedi_driver_unregister(&rtd520Driver);
-}
-
-module_init(rtd520Driver_init_module);
-module_exit(rtd520Driver_cleanup_module);
+static struct pci_driver rtd520_pci_driver = {
+	.name		= "rtd520",
+	.id_table	= rtd520_pci_table,
+	.probe		= rtd520_pci_probe,
+	.remove		= __devexit_p(rtd520_pci_remove),
+};
+module_comedi_pci_driver(rtd520_driver, rtd520_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index 72042b8..f0eb52a 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -138,39 +138,8 @@
 	int has_ao;
 };
 
-static const struct rti800_board boardtypes[] = {
-	{"rti800", 0},
-	{"rti815", 1},
-};
-
 #define this_board ((const struct rti800_board *)dev->board_ptr)
 
-static int rti800_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int rti800_detach(struct comedi_device *dev);
-static struct comedi_driver driver_rti800 = {
-	.driver_name = "rti800",
-	.module = THIS_MODULE,
-	.attach = rti800_attach,
-	.detach = rti800_detach,
-	.num_names = ARRAY_SIZE(boardtypes),
-	.board_name = &boardtypes[0].name,
-	.offset = sizeof(struct rti800_board),
-};
-
-static int __init driver_rti800_init_module(void)
-{
-	return comedi_driver_register(&driver_rti800);
-}
-
-static void __exit driver_rti800_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_rti800);
-}
-
-module_init(driver_rti800_init_module);
-module_exit(driver_rti800_cleanup_module);
-
 static irqreturn_t rti800_interrupt(int irq, void *dev);
 
 struct rti800_private {
@@ -474,19 +443,30 @@
 	return 0;
 }
 
-static int rti800_detach(struct comedi_device *dev)
+static void rti800_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: rti800: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, RTI800_SIZE);
-
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-
-	return 0;
 }
 
+static const struct rti800_board boardtypes[] = {
+	{ "rti800", 0 },
+	{ "rti815", 1 },
+};
+
+static struct comedi_driver rti800_driver = {
+	.driver_name	= "rti800",
+	.module		= THIS_MODULE,
+	.attach		= rti800_attach,
+	.detach		= rti800_detach,
+	.num_names	= ARRAY_SIZE(boardtypes),
+	.board_name	= &boardtypes[0].name,
+	.offset		= sizeof(struct rti800_board),
+};
+module_comedi_driver(rti800_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index f59cb11..09da5c2 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -47,29 +47,6 @@
 #define RTI802_DATALOW 1
 #define RTI802_DATAHIGH 2
 
-static int rti802_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static int rti802_detach(struct comedi_device *dev);
-static struct comedi_driver driver_rti802 = {
-	.driver_name = "rti802",
-	.module = THIS_MODULE,
-	.attach = rti802_attach,
-	.detach = rti802_detach,
-};
-
-static int __init driver_rti802_init_module(void)
-{
-	return comedi_driver_register(&driver_rti802);
-}
-
-static void __exit driver_rti802_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_rti802);
-}
-
-module_init(driver_rti802_init_module);
-module_exit(driver_rti802_cleanup_module);
-
 struct rti802_private {
 	enum {
 		dac_2comp, dac_straight
@@ -152,16 +129,20 @@
 	return 0;
 }
 
-static int rti802_detach(struct comedi_device *dev)
+static void rti802_detach(struct comedi_device *dev)
 {
-	printk(KERN_INFO "comedi%d: rti802: remove\n", dev->minor);
-
 	if (dev->iobase)
 		release_region(dev->iobase, RTI802_SIZE);
-
-	return 0;
 }
 
+static struct comedi_driver rti802_driver = {
+	.driver_name	= "rti802",
+	.module		= THIS_MODULE,
+	.attach		= rti802_attach,
+	.detach		= rti802_detach,
+};
+module_comedi_driver(rti802_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 2b34dae..7a56434 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -230,287 +230,6 @@
  */
 #define devpriv ((struct s526_private *)dev->private)
 
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int s526_detach(struct comedi_device *dev);
-static struct comedi_driver driver_s526 = {
-	.driver_name = "s526",
-	.module = THIS_MODULE,
-	.attach = s526_attach,
-	.detach = s526_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
-	/* Most drivers will support multiple types of boards by
-	 * having an array of board structures.  These were defined
-	 * in s526_boards[] above.  Note that the element 'name'
-	 * was first in the structure -- Comedi uses this fact to
-	 * extract the name of the board without knowing any details
-	 * about the structure except for its length.
-	 * When a device is attached (by comedi_config), the name
-	 * of the device is given to Comedi, and Comedi tries to
-	 * match it by going through the list of board names.  If
-	 * there is a match, the address of the pointer is put
-	 * into dev->board_ptr and driver->attach() is called.
-	 *
-	 * Note that these are not necessary if you can determine
-	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
-	 * devices are such boards.
-	 */
-	.board_name = &s526_boards[0].name,
-	.offset = sizeof(struct s526_board),
-	.num_names = ARRAY_SIZE(s526_boards),
-};
-
-static int s526_gpct_rinsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data);
-static int s526_gpct_insn_config(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data);
-static int s526_gpct_winsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data);
-static int s526_ai_insn_config(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			 struct comedi_insn *insn, unsigned int *data);
-static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			 struct comedi_insn *insn, unsigned int *data);
-static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			 struct comedi_insn *insn, unsigned int *data);
-static int s526_dio_insn_bits(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data);
-static int s526_dio_insn_config(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	int iobase;
-	int i, n;
-/* short value; */
-/* int subdev_channel = 0; */
-	union cmReg cmReg;
-
-	printk(KERN_INFO "comedi%d: s526: ", dev->minor);
-
-	iobase = it->options[0];
-	if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
-		comedi_error(dev, "I/O port conflict");
-		return -EIO;
-	}
-	dev->iobase = iobase;
-
-	printk("iobase=0x%lx\n", dev->iobase);
-
-	/*** make it a little quieter, exw, 8/29/06
-	for (i = 0; i < S526_NUM_PORTS; i++) {
-		printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]),
-				inw(ADDR_REG(s526_ports[i])));
-	}
-	***/
-
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_ptr = &s526_boards[0];
-
-	dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_private(dev, sizeof(struct s526_private)) < 0)
-		return -ENOMEM;
-
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	dev->n_subdevices = 4;
-	if (alloc_subdevices(dev, dev->n_subdevices) < 0)
-		return -ENOMEM;
-
-	s = dev->subdevices + 0;
-	/* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
-	s->type = COMEDI_SUBD_COUNTER;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
-	/* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
-	s->n_chan = thisboard->gpct_chans;
-	s->maxdata = 0x00ffffff;	/* 24 bit counter */
-	s->insn_read = s526_gpct_rinsn;
-	s->insn_config = s526_gpct_insn_config;
-	s->insn_write = s526_gpct_winsn;
-
-	/* Command are not implemented yet, however they are necessary to
-	   allocate the necessary memory for the comedi_async struct (used
-	   to trigger the GPCT in case of pulsegenerator function */
-	/* s->do_cmd = s526_gpct_cmd; */
-	/* s->do_cmdtest = s526_gpct_cmdtest; */
-	/* s->cancel = s526_gpct_cancel; */
-
-	s = dev->subdevices + 1;
-	/* dev->read_subdev=s; */
-	/* analog input subdevice */
-	s->type = COMEDI_SUBD_AI;
-	/* we support differential */
-	s->subdev_flags = SDF_READABLE | SDF_DIFF;
-	/* channels 0 to 7 are the regular differential inputs */
-	/* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
-	s->n_chan = 10;
-	s->maxdata = 0xffff;
-	s->range_table = &range_bipolar10;
-	s->len_chanlist = 16;	/* This is the maximum chanlist length that
-				   the board can handle */
-	s->insn_read = s526_ai_rinsn;
-	s->insn_config = s526_ai_insn_config;
-
-	s = dev->subdevices + 2;
-	/* analog output subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = 4;
-	s->maxdata = 0xffff;
-	s->range_table = &range_bipolar10;
-	s->insn_write = s526_ao_winsn;
-	s->insn_read = s526_ao_rinsn;
-
-	s = dev->subdevices + 3;
-	/* digital i/o subdevice */
-	if (thisboard->have_dio) {
-		s->type = COMEDI_SUBD_DIO;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = 8;
-		s->maxdata = 1;
-		s->range_table = &range_digital;
-		s->insn_bits = s526_dio_insn_bits;
-		s->insn_config = s526_dio_insn_config;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
-
-	printk(KERN_INFO "attached\n");
-
-	return 1;
-
-#if 0
-	/*  Example of Counter Application */
-	/* One-shot (software trigger) */
-	cmReg.reg.coutSource = 0;	/*  out RCAP */
-	cmReg.reg.coutPolarity = 1;	/*  Polarity inverted */
-	cmReg.reg.autoLoadResetRcap = 1;/*  Auto load 0:disabled, 1:enabled */
-	cmReg.reg.hwCtEnableSource = 3;	/*  NOT RCAP */
-	cmReg.reg.ctEnableCtrl = 2;	/*  Hardware */
-	cmReg.reg.clockSource = 2;	/*  Internal */
-	cmReg.reg.countDir = 1;	/*  Down */
-	cmReg.reg.countDirCtrl = 1;	/*  Software */
-	cmReg.reg.outputRegLatchCtrl = 0;	/*  latch on read */
-	cmReg.reg.preloadRegSel = 0;	/*  PR0 */
-	cmReg.reg.reserved = 0;
-
-	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
-
-	outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
-	outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
-
-	/*  Reset the counter */
-	outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
-	/*  Load the counter from PR0 */
-	outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
-	/*  Reset RCAP (fires one-shot) */
-	outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
-
-#else
-
-	/*  Set Counter Mode Register */
-	cmReg.reg.coutSource = 0;	/*  out RCAP */
-	cmReg.reg.coutPolarity = 0;	/*  Polarity inverted */
-	cmReg.reg.autoLoadResetRcap = 0;	/*  Auto load disabled */
-	cmReg.reg.hwCtEnableSource = 2;	/*  NOT RCAP */
-	cmReg.reg.ctEnableCtrl = 1;	/*  1: Software,  >1 : Hardware */
-	cmReg.reg.clockSource = 3;	/*  x4 */
-	cmReg.reg.countDir = 0;	/*  up */
-	cmReg.reg.countDirCtrl = 0;	/*  quadrature */
-	cmReg.reg.outputRegLatchCtrl = 0;	/*  latch on read */
-	cmReg.reg.preloadRegSel = 0;	/*  PR0 */
-	cmReg.reg.reserved = 0;
-
-	n = 0;
-	printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
-		cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
-	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
-	udelay(1000);
-	printk(KERN_INFO "Read back mode reg=0x%04x\n",
-		inw(ADDR_CHAN_REG(REG_C0M, n)));
-
-	/*  Load the pre-load register high word */
-/* value = (short) (0x55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */
-
-	/*  Load the pre-load register low word */
-/* value = (short)(0xaa55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */
-
-	/*  Write the Counter Control Register */
-/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */
-
-	/*  Reset the counter if it is software preload */
-	if (cmReg.reg.autoLoadResetRcap == 0) {
-		/*  Reset the counter */
-		outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
-		/*  Load the counter from PR0 */
-		outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
-	}
-
-	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
-	udelay(1000);
-	printk(KERN_INFO "Read back mode reg=0x%04x\n",
-			inw(ADDR_CHAN_REG(REG_C0M, n)));
-
-#endif
-	printk(KERN_INFO "Current registres:\n");
-
-	for (i = 0; i < S526_NUM_PORTS; i++) {
-		printk(KERN_INFO "0x%02lx: 0x%04x\n",
-			ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
-	}
-	return 1;
-}
-
-/*
- * _detach is called to deconfigure a device.  It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach().  dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int s526_detach(struct comedi_device *dev)
-{
-	printk(KERN_INFO "comedi%d: s526: remove\n", dev->minor);
-
-	if (dev->iobase > 0)
-		release_region(dev->iobase, S526_IOSIZE);
-
-	return 0;
-}
-
 static int s526_gpct_rinsn(struct comedi_device *dev,
 			   struct comedi_subdevice *s, struct comedi_insn *insn,
 			   unsigned int *data)
@@ -1023,22 +742,218 @@
 	return 1;
 }
 
+static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+	int iobase;
+	int i, n;
+/* short value; */
+/* int subdev_channel = 0; */
+	union cmReg cmReg;
+
+	printk(KERN_INFO "comedi%d: s526: ", dev->minor);
+
+	iobase = it->options[0];
+	if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
+		comedi_error(dev, "I/O port conflict");
+		return -EIO;
+	}
+	dev->iobase = iobase;
+
+	printk("iobase=0x%lx\n", dev->iobase);
+
+	/*** make it a little quieter, exw, 8/29/06
+	for (i = 0; i < S526_NUM_PORTS; i++) {
+		printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]),
+				inw(ADDR_REG(s526_ports[i])));
+	}
+	***/
+
 /*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name.  Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
  */
-static int __init driver_s526_init_module(void)
-{
-	return comedi_driver_register(&driver_s526);
+	dev->board_ptr = &s526_boards[0];
+
+	dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area.  alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+	if (alloc_private(dev, sizeof(struct s526_private)) < 0)
+		return -ENOMEM;
+
+/*
+ * Allocate the subdevice structures.  alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ */
+	dev->n_subdevices = 4;
+	if (alloc_subdevices(dev, dev->n_subdevices) < 0)
+		return -ENOMEM;
+
+	s = dev->subdevices + 0;
+	/* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
+	s->type = COMEDI_SUBD_COUNTER;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
+	/* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
+	s->n_chan = thisboard->gpct_chans;
+	s->maxdata = 0x00ffffff;	/* 24 bit counter */
+	s->insn_read = s526_gpct_rinsn;
+	s->insn_config = s526_gpct_insn_config;
+	s->insn_write = s526_gpct_winsn;
+
+	/* Command are not implemented yet, however they are necessary to
+	   allocate the necessary memory for the comedi_async struct (used
+	   to trigger the GPCT in case of pulsegenerator function */
+	/* s->do_cmd = s526_gpct_cmd; */
+	/* s->do_cmdtest = s526_gpct_cmdtest; */
+	/* s->cancel = s526_gpct_cancel; */
+
+	s = dev->subdevices + 1;
+	/* dev->read_subdev=s; */
+	/* analog input subdevice */
+	s->type = COMEDI_SUBD_AI;
+	/* we support differential */
+	s->subdev_flags = SDF_READABLE | SDF_DIFF;
+	/* channels 0 to 7 are the regular differential inputs */
+	/* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
+	s->n_chan = 10;
+	s->maxdata = 0xffff;
+	s->range_table = &range_bipolar10;
+	s->len_chanlist = 16;	/* This is the maximum chanlist length that
+				   the board can handle */
+	s->insn_read = s526_ai_rinsn;
+	s->insn_config = s526_ai_insn_config;
+
+	s = dev->subdevices + 2;
+	/* analog output subdevice */
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITABLE;
+	s->n_chan = 4;
+	s->maxdata = 0xffff;
+	s->range_table = &range_bipolar10;
+	s->insn_write = s526_ao_winsn;
+	s->insn_read = s526_ao_rinsn;
+
+	s = dev->subdevices + 3;
+	/* digital i/o subdevice */
+	if (thisboard->have_dio) {
+		s->type = COMEDI_SUBD_DIO;
+		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+		s->n_chan = 8;
+		s->maxdata = 1;
+		s->range_table = &range_digital;
+		s->insn_bits = s526_dio_insn_bits;
+		s->insn_config = s526_dio_insn_config;
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
+	}
+
+	printk(KERN_INFO "attached\n");
+
+	return 1;
+
+#if 0
+	/*  Example of Counter Application */
+	/* One-shot (software trigger) */
+	cmReg.reg.coutSource = 0;	/*  out RCAP */
+	cmReg.reg.coutPolarity = 1;	/*  Polarity inverted */
+	cmReg.reg.autoLoadResetRcap = 1;/*  Auto load 0:disabled, 1:enabled */
+	cmReg.reg.hwCtEnableSource = 3;	/*  NOT RCAP */
+	cmReg.reg.ctEnableCtrl = 2;	/*  Hardware */
+	cmReg.reg.clockSource = 2;	/*  Internal */
+	cmReg.reg.countDir = 1;	/*  Down */
+	cmReg.reg.countDirCtrl = 1;	/*  Software */
+	cmReg.reg.outputRegLatchCtrl = 0;	/*  latch on read */
+	cmReg.reg.preloadRegSel = 0;	/*  PR0 */
+	cmReg.reg.reserved = 0;
+
+	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+
+	outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+	outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+
+	/*  Reset the counter */
+	outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+	/*  Load the counter from PR0 */
+	outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+	/*  Reset RCAP (fires one-shot) */
+	outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+
+#else
+
+	/*  Set Counter Mode Register */
+	cmReg.reg.coutSource = 0;	/*  out RCAP */
+	cmReg.reg.coutPolarity = 0;	/*  Polarity inverted */
+	cmReg.reg.autoLoadResetRcap = 0;	/*  Auto load disabled */
+	cmReg.reg.hwCtEnableSource = 2;	/*  NOT RCAP */
+	cmReg.reg.ctEnableCtrl = 1;	/*  1: Software,  >1 : Hardware */
+	cmReg.reg.clockSource = 3;	/*  x4 */
+	cmReg.reg.countDir = 0;	/*  up */
+	cmReg.reg.countDirCtrl = 0;	/*  quadrature */
+	cmReg.reg.outputRegLatchCtrl = 0;	/*  latch on read */
+	cmReg.reg.preloadRegSel = 0;	/*  PR0 */
+	cmReg.reg.reserved = 0;
+
+	n = 0;
+	printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
+		cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
+	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
+	udelay(1000);
+	printk(KERN_INFO "Read back mode reg=0x%04x\n",
+		inw(ADDR_CHAN_REG(REG_C0M, n)));
+
+	/*  Load the pre-load register high word */
+/* value = (short) (0x55); */
+/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */
+
+	/*  Load the pre-load register low word */
+/* value = (short)(0xaa55); */
+/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */
+
+	/*  Write the Counter Control Register */
+/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */
+
+	/*  Reset the counter if it is software preload */
+	if (cmReg.reg.autoLoadResetRcap == 0) {
+		/*  Reset the counter */
+		outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
+		/*  Load the counter from PR0 */
+		outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
+	}
+
+	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
+	udelay(1000);
+	printk(KERN_INFO "Read back mode reg=0x%04x\n",
+			inw(ADDR_CHAN_REG(REG_C0M, n)));
+
+#endif
+	printk(KERN_INFO "Current registres:\n");
+
+	for (i = 0; i < S526_NUM_PORTS; i++) {
+		printk(KERN_INFO "0x%02lx: 0x%04x\n",
+			ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
+	}
+	return 1;
 }
 
-static void __exit driver_s526_cleanup_module(void)
+static void s526_detach(struct comedi_device *dev)
 {
-	comedi_driver_unregister(&driver_s526);
+	if (dev->iobase > 0)
+		release_region(dev->iobase, S526_IOSIZE);
 }
 
-module_init(driver_s526_init_module);
-module_exit(driver_s526_cleanup_module);
+static struct comedi_driver s526_driver = {
+	.driver_name	= "s526",
+	.module		= THIS_MODULE,
+	.attach		= s526_attach,
+	.detach		= s526_detach,
+	.board_name	= &s526_boards[0].name,
+	.offset		= sizeof(struct s526_board),
+	.num_names	= ARRAY_SIZE(s526_boards),
+};
+module_comedi_driver(s526_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 23fc64b..7beb8f6 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -79,12 +79,17 @@
 #include "comedi_fc.h"
 #include "s626.h"
 
-MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>");
-MODULE_DESCRIPTION("Sensoray 626 Comedi driver module");
-MODULE_LICENSE("GPL");
+#define PCI_VENDOR_ID_S626 0x1131
+#define PCI_DEVICE_ID_S626 0x7146
+#define PCI_SUBVENDOR_ID_S626 0x6000
+#define PCI_SUBDEVICE_ID_S626 0x0272
 
 struct s626_board {
 	const char *name;
+	int vendor_id;
+	int device_id;
+	int subvendor_id;
+	int subdevice_id;
 	int ai_chans;
 	int ai_bits;
 	int ao_chans;
@@ -97,6 +102,10 @@
 static const struct s626_board s626_boards[] = {
 	{
 	 .name = "s626",
+	 .vendor_id = PCI_VENDOR_ID_S626,
+	 .device_id = PCI_DEVICE_ID_S626,
+	 .subvendor_id = PCI_SUBVENDOR_ID_S626,
+	 .subdevice_id = PCI_SUBDEVICE_ID_S626,
 	 .ai_chans = S626_ADC_CHANNELS,
 	 .ai_bits = 14,
 	 .ao_chans = S626_DAC_CHANNELS,
@@ -108,30 +117,6 @@
 };
 
 #define thisboard ((const struct s626_board *)dev->board_ptr)
-#define PCI_VENDOR_ID_S626 0x1131
-#define PCI_DEVICE_ID_S626 0x7146
-
-/*
- * For devices with vendor:device id == 0x1131:0x7146 you must specify
- * also subvendor:subdevice ids, because otherwise it will conflict with
- * Philips SAA7146 media/dvb based cards.
- */
-static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
-	{PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 0x6000, 0x0272, 0, 0, 0},
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, s626_pci_table);
-
-static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int s626_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_s626 = {
-	.driver_name = "s626",
-	.module = THIS_MODULE,
-	.attach = s626_attach,
-	.detach = s626_detach,
-};
 
 struct s626_private {
 	struct pci_dev *pdev;
@@ -224,44 +209,6 @@
 #define devpriv ((struct s626_private *)dev->private)
 #define diopriv ((struct dio_private *)s->private)
 
-static int __devinit driver_s626_pci_probe(struct pci_dev *dev,
-					   const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, driver_s626.driver_name);
-}
-
-static void __devexit driver_s626_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_s626_pci_driver = {
-	.id_table = s626_pci_table,
-	.probe = &driver_s626_pci_probe,
-	.remove = __devexit_p(&driver_s626_pci_remove)
-};
-
-static int __init driver_s626_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_s626);
-	if (retval < 0)
-		return retval;
-
-	driver_s626_pci_driver.name = (char *)driver_s626.driver_name;
-	return pci_register_driver(&driver_s626_pci_driver);
-}
-
-static void __exit driver_s626_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_s626_pci_driver);
-	comedi_driver_unregister(&driver_s626);
-}
-
-module_init(driver_s626_init_module);
-module_exit(driver_s626_cleanup_module);
-
 /* ioctl routines */
 static int s626_ai_insn_config(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
@@ -554,17 +501,17 @@
 	resource_size_t resourceStart;
 	dma_addr_t appdma;
 	struct comedi_subdevice *s;
-	const struct pci_device_id *ids;
 	struct pci_dev *pdev = NULL;
 
 	if (alloc_private(dev, sizeof(struct s626_private)) < 0)
 		return -ENOMEM;
 
-	for (i = 0; i < (ARRAY_SIZE(s626_pci_table) - 1) && !pdev; i++) {
-		ids = &s626_pci_table[i];
+	for (i = 0; i < ARRAY_SIZE(s626_boards) && !pdev; i++) {
 		do {
-			pdev = pci_get_subsys(ids->vendor, ids->device,
-					      ids->subvendor, ids->subdevice,
+			pdev = pci_get_subsys(s626_boards[i].vendor_id,
+					      s626_boards[i].device_id,
+					      s626_boards[i].subvendor_id,
+					      s626_boards[i].subdevice_id,
 					      pdev);
 
 			if ((it->options[0] || it->options[1]) && pdev) {
@@ -1365,7 +1312,7 @@
 	return IRQ_HANDLED;
 }
 
-static int s626_detach(struct comedi_device *dev)
+static void s626_detach(struct comedi_device *dev)
 {
 	if (devpriv) {
 		/* stop ai_command */
@@ -1389,20 +1336,14 @@
 
 		if (dev->irq)
 			free_irq(dev->irq, dev);
-
 		if (devpriv->base_addr)
 			iounmap(devpriv->base_addr);
-
 		if (devpriv->pdev) {
 			if (devpriv->got_regions)
 				comedi_pci_disable(devpriv->pdev);
 			pci_dev_put(devpriv->pdev);
 		}
 	}
-
-	DEBUG("s626_detach: S626 detached!\n");
-
-	return 0;
 }
 
 /*
@@ -3367,3 +3308,45 @@
 	DEBUG("CountersInit: counters initialized\n");
 
 }
+
+static struct comedi_driver s626_driver = {
+	.driver_name	= "s626",
+	.module		= THIS_MODULE,
+	.attach		= s626_attach,
+	.detach		= s626_detach,
+};
+
+static int __devinit s626_pci_probe(struct pci_dev *dev,
+				    const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &s626_driver);
+}
+
+static void __devexit s626_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+/*
+ * For devices with vendor:device id == 0x1131:0x7146 you must specify
+ * also subvendor:subdevice ids, because otherwise it will conflict with
+ * Philips SAA7146 media/dvb based cards.
+ */
+static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
+	{ PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626,
+		PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, 0, 0, 0 },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, s626_pci_table);
+
+static struct pci_driver s626_pci_driver = {
+	.name		= "s626",
+	.id_table	= s626_pci_table,
+	.probe		= s626_pci_probe,
+	.remove		= __devexit_p(s626_pci_remove),
+};
+module_comedi_pci_driver(s626_driver, s626_pci_driver);
+
+MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>");
+MODULE_DESCRIPTION("Sensoray 626 Comedi driver module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index d880c2f..6342bc5 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -43,20 +43,10 @@
 #include <linux/serial.h>
 #include <linux/poll.h>
 
-/*
- * Board descriptions for two imaginary boards.  Describing the
- * boards in this way is optional, and completely driver-dependent.
- * Some drivers use arrays such as this, other do not.
- */
 struct serial2002_board {
 	const char *name;
 };
 
-static const struct serial2002_board serial2002_boards[] = {
-	{
-	 .name = "serial2002"}
-};
-
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -89,35 +79,6 @@
  */
 #define devpriv ((struct serial2002_private *)dev->private)
 
-static int serial2002_attach(struct comedi_device *dev,
-			     struct comedi_devconfig *it);
-static int serial2002_detach(struct comedi_device *dev);
-struct comedi_driver driver_serial2002 = {
-	.driver_name = "serial2002",
-	.module = THIS_MODULE,
-	.attach = serial2002_attach,
-	.detach = serial2002_detach,
-	.board_name = &serial2002_boards[0].name,
-	.offset = sizeof(struct serial2002_board),
-	.num_names = ARRAY_SIZE(serial2002_boards),
-};
-
-static int serial2002_di_rinsn(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int serial2002_do_winsn(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int serial2002_ai_rinsn(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int serial2002_ao_winsn(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int serial2002_ao_rinsn(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-
 struct serial_data {
 	enum { is_invalid, is_digital, is_channel } kind;
 	int index;
@@ -887,32 +848,34 @@
 	return 1;
 }
 
-static int serial2002_detach(struct comedi_device *dev)
+static void serial2002_detach(struct comedi_device *dev)
 {
 	struct comedi_subdevice *s;
 	int i;
 
-	dev_dbg(dev->hw_dev, "comedi%d: remove\n", dev->minor);
 	for (i = 0; i < 5; i++) {
 		s = &dev->subdevices[i];
 		kfree(s->maxdata_list);
 		kfree(s->range_table_list);
 	}
-	return 0;
 }
 
-static int __init driver_serial2002_init_module(void)
-{
-	return comedi_driver_register(&driver_serial2002);
-}
+static const struct serial2002_board serial2002_boards[] = {
+	{
+		.name	= "serial2002"
+	},
+};
 
-static void __exit driver_serial2002_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_serial2002);
-}
-
-module_init(driver_serial2002_init_module);
-module_exit(driver_serial2002_cleanup_module);
+static struct comedi_driver serial2002_driver = {
+	.driver_name	= "serial2002",
+	.module		= THIS_MODULE,
+	.attach		= serial2002_attach,
+	.detach		= serial2002_detach,
+	.board_name	= &serial2002_boards[0].name,
+	.offset		= sizeof(struct serial2002_board),
+	.num_names	= ARRAY_SIZE(serial2002_boards),
+};
+module_comedi_driver(serial2002_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index ed69008..7d13ffa 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -156,7 +156,7 @@
  * the device code.
  */
 static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int skel_detach(struct comedi_device *dev);
+static void skel_detach(struct comedi_device *dev);
 static struct comedi_driver driver_skel = {
 	.driver_name = "dummy",
 	.module = THIS_MODULE,
@@ -295,11 +295,8 @@
  * allocated by _attach().  dev->private and dev->subdevices are
  * deallocated automatically by the core.
  */
-static int skel_detach(struct comedi_device *dev)
+static void skel_detach(struct comedi_device *dev)
 {
-	pr_info("comedi%d: skel: remove\n", dev->minor);
-
-	return 0;
 }
 
 /*
@@ -623,7 +620,7 @@
 static int __devinit driver_skel_pci_probe(struct pci_dev *dev,
 					   const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, driver_skel.driver_name);
+	return comedi_pci_auto_config(dev, &driver_skel);
 }
 
 static void __devexit driver_skel_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index 526de2e..16c4f5a 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -59,16 +59,6 @@
 	int have_dio;
 };
 
-/* We only support one DNP 'board' variant at the moment */
-static const struct dnp_board dnp_boards[] = {
-{
-	 .name = "dnp-1486",
-	 .ai_chans = 16,
-	 .ai_bits = 12,
-	 .have_dio = 1,
-	 },
-};
-
 /* Useful for shorthand access to the particular board structure ----------- */
 #define thisboard ((const struct dnp_board *)dev->board_ptr)
 
@@ -81,136 +71,6 @@
 #define devpriv ((dnp_private *)dev->private)
 
 /* ------------------------------------------------------------------------- */
-/* The struct comedi_driver structure tells the Comedi core module which     */
-/* functions to call to configure/deconfigure (attach/detach) the board, and */
-/* also about the kernel module that contains the device code.               */
-/*                                                                           */
-/* In the following section we define the API of this driver.                */
-/* ------------------------------------------------------------------------- */
-
-static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int dnp_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_dnp = {
-	.driver_name = "ssv_dnp",
-	.module = THIS_MODULE,
-	.attach = dnp_attach,
-	.detach = dnp_detach,
-	.board_name = &dnp_boards[0].name,
-	/* only necessary for non-PnP devs   */
-	.offset = sizeof(struct dnp_board),   /* like ISA-PnP, PCI or PCMCIA */
-	.num_names = ARRAY_SIZE(dnp_boards),
-};
-
-static int __init driver_dnp_init_module(void)
-{
-	return comedi_driver_register(&driver_dnp);
-}
-
-static void __exit driver_dnp_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_dnp);
-}
-
-module_init(driver_dnp_init_module);
-module_exit(driver_dnp_cleanup_module);
-
-static int dnp_dio_insn_bits(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn, unsigned int *data);
-
-static int dnp_dio_insn_config(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-
-/* ------------------------------------------------------------------------- */
-/* Attach is called by comedi core to configure the driver for a particular  */
-/* board. If you specified a board_name array in the driver structure,       */
-/* dev->board_ptr contains that address.                                     */
-/* ------------------------------------------------------------------------- */
-
-static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-
-	struct comedi_subdevice *s;
-
-	printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
-
-	/* Autoprobing: this should find out which board we have. Currently  */
-	/* only the 1486 board is supported and autoprobing is not           */
-	/* implemented :-)                                                   */
-	/* dev->board_ptr = dnp_probe(dev); */
-
-	/* Initialize the name of the board.                                 */
-	/* We can use the "thisboard" macro now.                             */
-	dev->board_name = thisboard->name;
-
-	/* Allocate the private structure area. alloc_private() is a         */
-	/* convenient macro defined in comedidev.h.                          */
-	if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0)
-		return -ENOMEM;
-
-	/* Allocate the subdevice structures. alloc_subdevice() is a         */
-	/* convenient macro defined in comedidev.h.                          */
-
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
-
-	s = dev->subdevices + 0;
-	/* digital i/o subdevice                                             */
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 20;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = dnp_dio_insn_bits;
-	s->insn_config = dnp_dio_insn_config;
-
-	printk("attached\n");
-
-	/* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always
-	 * allocated for the primary 8259, so we don't need to allocate them
-	 * ourselves. */
-
-	/* configure all ports as input (default)                            */
-	outb(PAMR, CSCIR);
-	outb(0x00, CSCDR);
-	outb(PBMR, CSCIR);
-	outb(0x00, CSCDR);
-	outb(PCMR, CSCIR);
-	outb((inb(CSCDR) & 0xAA), CSCDR);
-
-	return 1;
-
-}
-
-/* ------------------------------------------------------------------------- */
-/* detach is called to deconfigure a device. It should deallocate the        */
-/* resources. This function is also called when _attach() fails, so it       */
-/* should be careful not to release resources that were not necessarily      */
-/* allocated by _attach(). dev->private and dev->subdevices are              */
-/* deallocated automatically by the core.                                    */
-/* ------------------------------------------------------------------------- */
-
-static int dnp_detach(struct comedi_device *dev)
-{
-
-	/* configure all ports as input (default)                            */
-	outb(PAMR, CSCIR);
-	outb(0x00, CSCDR);
-	outb(PBMR, CSCIR);
-	outb(0x00, CSCDR);
-	outb(PCMR, CSCIR);
-	outb((inb(CSCDR) & 0xAA), CSCDR);
-
-	/* announce that we are finished                                     */
-	printk(KERN_INFO "comedi%d: dnp: remove\n", dev->minor);
-
-	return 0;
-
-}
-
-/* ------------------------------------------------------------------------- */
 /* The insn_bits interface allows packed reading/writing of DIO channels.    */
 /* The comedi core can convert between insn_bits and insn_read/write, so you */
 /* are able to use these instructions as well.                               */
@@ -326,6 +186,89 @@
 
 }
 
+static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	struct comedi_subdevice *s;
+
+	printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
+
+	/* Autoprobing: this should find out which board we have. Currently  */
+	/* only the 1486 board is supported and autoprobing is not           */
+	/* implemented :-)                                                   */
+	/* dev->board_ptr = dnp_probe(dev); */
+
+	/* Initialize the name of the board.                                 */
+	/* We can use the "thisboard" macro now.                             */
+	dev->board_name = thisboard->name;
+
+	/* Allocate the private structure area. alloc_private() is a         */
+	/* convenient macro defined in comedidev.h.                          */
+	if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0)
+		return -ENOMEM;
+
+	/* Allocate the subdevice structures. alloc_subdevice() is a         */
+	/* convenient macro defined in comedidev.h.                          */
+
+	if (alloc_subdevices(dev, 1) < 0)
+		return -ENOMEM;
+
+	s = dev->subdevices + 0;
+	/* digital i/o subdevice                                             */
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 20;
+	s->maxdata = 1;
+	s->range_table = &range_digital;
+	s->insn_bits = dnp_dio_insn_bits;
+	s->insn_config = dnp_dio_insn_config;
+
+	printk("attached\n");
+
+	/* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always
+	 * allocated for the primary 8259, so we don't need to allocate them
+	 * ourselves. */
+
+	/* configure all ports as input (default)                            */
+	outb(PAMR, CSCIR);
+	outb(0x00, CSCDR);
+	outb(PBMR, CSCIR);
+	outb(0x00, CSCDR);
+	outb(PCMR, CSCIR);
+	outb((inb(CSCDR) & 0xAA), CSCDR);
+
+	return 1;
+}
+
+static void dnp_detach(struct comedi_device *dev)
+{
+	outb(PAMR, CSCIR);
+	outb(0x00, CSCDR);
+	outb(PBMR, CSCIR);
+	outb(0x00, CSCDR);
+	outb(PCMR, CSCIR);
+	outb((inb(CSCDR) & 0xAA), CSCDR);
+}
+
+static const struct dnp_board dnp_boards[] = {
+	{
+		.name		= "dnp-1486",
+		.ai_chans	= 16,
+		.ai_bits	= 12,
+		.have_dio	= 1,
+	},
+};
+
+static struct comedi_driver dnp_driver = {
+	.driver_name	= "ssv_dnp",
+	.module		= THIS_MODULE,
+	.attach		= dnp_attach,
+	.detach		= dnp_detach,
+	.board_name	= &dnp_boards[0].name,
+	.offset		= sizeof(struct dnp_board),
+	.num_names	= ARRAY_SIZE(dnp_boards),
+};
+module_comedi_driver(dnp_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index f45824f..d5f1f22 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -83,96 +83,188 @@
 	unsigned char usp_prev_cn_val[3];	/* previous channel value */
 };
 
-static int unioxx5_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static int unioxx5_subdev_write(struct comedi_device *dev,
-				struct comedi_subdevice *subdev,
-				struct comedi_insn *insn, unsigned int *data);
-static int unioxx5_subdev_read(struct comedi_device *dev,
-			       struct comedi_subdevice *subdev,
-			       struct comedi_insn *insn, unsigned int *data);
-static int unioxx5_insn_config(struct comedi_device *dev,
-			       struct comedi_subdevice *subdev,
-			       struct comedi_insn *insn, unsigned int *data);
-static int unioxx5_detach(struct comedi_device *dev);
-static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
-				 int subdev_iobase, int minor);
-static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
-				   unsigned int *data, int channel, int minor);
-static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
-				  unsigned int *data, int channel, int minor);
-/* static void __unioxx5_digital_config(struct unioxx5_subd_priv* usp, int mode); */
-static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
-				  unsigned int *data, int channel, int minor);
-static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
-				 unsigned int *data, int channel, int minor);
-static int __unioxx5_define_chan_offset(int chan_num);
-static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel);
-
-static struct comedi_driver unioxx5_driver = {
-	.driver_name = DRIVER_NAME,
-	.module = THIS_MODULE,
-	.attach = unioxx5_attach,
-	.detach = unioxx5_detach
-};
-
-static int __init unioxx5_driver_init_module(void)
+static int __unioxx5_define_chan_offset(int chan_num)
 {
-	return comedi_driver_register(&unioxx5_driver);
-}
 
-static void __exit unioxx5_driver_cleanup_module(void)
-{
-	comedi_driver_unregister(&unioxx5_driver);
-}
-
-module_init(unioxx5_driver_init_module);
-module_exit(unioxx5_driver_cleanup_module);
-
-static int unioxx5_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
-{
-	int iobase, i, n_subd;
-	int id, num, ba;
-
-	iobase = it->options[0];
-
-	dev->board_name = DRIVER_NAME;
-	dev->iobase = iobase;
-	iobase += UNIOXX5_SUBDEV_BASE;
-
-	/* defining number of subdevices and getting they types (it must be 'g01')  */
-	for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) {
-		id = inb(ba + 0xE);
-		num = inb(ba + 0xF);
-
-		if (id != 'g' || num != 1)
-			continue;
-
-		n_subd++;
-	}
-
-	/* unioxx5 can has from two to four subdevices */
-	if (n_subd < 2) {
-		printk(KERN_ERR
-		       "your card must has at least 2 'g01' subdevices\n");
+	if (chan_num < 0 || chan_num > 23)
 		return -1;
+
+	return (chan_num >> 3) + 1;
+}
+
+#if 0				/* not used? */
+static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode)
+{
+	int i, mask;
+
+	mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00;
+	printk("COMEDI: mode = %d\n", mask);
+
+	outb(1, usp->usp_iobase + 0);
+
+	for (i = 0; i < 3; i++)
+		outb(mask, usp->usp_iobase + i);
+
+	outb(0, usp->usp_iobase + 0);
+}
+#endif
+
+/* configure channels for analog i/o (even to output, odd to input) */
+static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel)
+{
+	int chan_a, chan_b, conf, channel_offset;
+
+	channel_offset = __unioxx5_define_chan_offset(channel);
+	conf = usp->usp_prev_cn_val[channel_offset - 1];
+	chan_a = chan_b = 1;
+
+	/* setting channel A and channel B mask */
+	if (channel % 2 == 0) {
+		chan_a <<= channel & 0x07;
+		chan_b <<= (channel + 1) & 0x07;
+	} else {
+		chan_a <<= (channel - 1) & 0x07;
+		chan_b <<= channel & 0x07;
 	}
 
-	if (alloc_subdevices(dev, n_subd) < 0) {
-		printk(KERN_ERR "out of memory\n");
-		return -ENOMEM;
+	conf |= chan_a;		/* even channel ot output */
+	conf &= ~chan_b;	/* odd channel to input */
+
+	outb(1, usp->usp_iobase + 0);
+	outb(conf, usp->usp_iobase + channel_offset);
+	outb(0, usp->usp_iobase + 0);
+
+	usp->usp_prev_cn_val[channel_offset - 1] = conf;
+}
+
+static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
+				  unsigned int *data, int channel, int minor)
+{
+	int channel_offset, mask = 1 << (channel & 0x07);
+
+	channel_offset = __unioxx5_define_chan_offset(channel);
+	if (channel_offset < 0) {
+		printk(KERN_ERR
+		       "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
+		       minor, channel);
+		return 0;
 	}
 
-	/* initializing each of for same subdevices */
-	for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) {
-		if (__unioxx5_subdev_init(&dev->subdevices[i], iobase,
-					  dev->minor) < 0)
-			return -1;
+	*data = inb(usp->usp_iobase + channel_offset);
+	*data &= mask;
+
+	/* correct the read value to 0 or 1 */
+	if (channel_offset > 1)
+		channel -= 2 << channel_offset;
+	*data >>= channel;
+	return 1;
+}
+
+static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
+				 unsigned int *data, int channel, int minor)
+{
+	int module_no, read_ch;
+	char control;
+
+	module_no = channel / 2;
+	read_ch = channel % 2;	/* depend on type of channel (A or B) */
+
+	/* defining if given module can work on input */
+	if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) {
+		printk(KERN_ERR
+		       "comedi%d: module in position %d with id 0x%02x is for output only",
+		       minor, module_no, usp->usp_module_type[module_no]);
+		return 0;
 	}
 
-	printk(KERN_INFO "attached\n");
-	return 0;
+	__unioxx5_analog_config(usp, channel);
+	/* sends module number to card(1 .. 12) */
+	outb(module_no + 1, usp->usp_iobase + 5);
+	outb('V', usp->usp_iobase + 6);	/* sends to module (V)erify command */
+	control = inb(usp->usp_iobase);	/* get control register byte */
+
+	/* waits while reading four bytes will be allowed */
+	while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA))
+		;
+
+	/* if four bytes readding error occurs - return 0(false) */
+	if ((control & Rx4CA_ERR_MASK)) {
+		printk("COMEDI: 4 bytes error\n");
+		return 0;
+	}
+
+	if (read_ch)
+		*data = inw(usp->usp_iobase + 6);	/* channel B */
+	else
+		*data = inw(usp->usp_iobase + 4);	/* channel A */
+
+	return 1;
+}
+
+static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
+				   unsigned int *data, int channel, int minor)
+{
+	int channel_offset, val;
+	int mask = 1 << (channel & 0x07);
+
+	channel_offset = __unioxx5_define_chan_offset(channel);
+	if (channel_offset < 0) {
+		printk(KERN_ERR
+		       "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
+		       minor, channel);
+		return 0;
+	}
+
+	/* getting previous written value */
+	val = usp->usp_prev_wr_val[channel_offset - 1];
+
+	if (*data)
+		val |= mask;
+	else
+		val &= ~mask;
+
+	outb(val, usp->usp_iobase + channel_offset);
+	/* saving new written value */
+	usp->usp_prev_wr_val[channel_offset - 1] = val;
+
+	return 1;
+}
+
+static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
+				  unsigned int *data, int channel, int minor)
+{
+	int module, i;
+
+	module = channel / 2;	/* definig module number(0 .. 11) */
+	i = (channel % 2) << 1;	/* depends on type of channel (A or B) */
+
+	/* defining if given module can work on output */
+	if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) {
+		printk(KERN_ERR
+		       "comedi%d: module in position %d with id 0x%0x is for input only!\n",
+		       minor, module, usp->usp_module_type[module]);
+		return 0;
+	}
+
+	__unioxx5_analog_config(usp, channel);
+	/* saving minor byte */
+	usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF);
+	/* saving major byte */
+	usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8);
+
+	/* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */
+	/* sending module number to card(1 .. 12) */
+	outb(module + 1, usp->usp_iobase + 5);
+	outb('W', usp->usp_iobase + 6);	/* sends (W)rite command to module */
+
+	/* sending for bytes to module(one byte per cycle iteration) */
+	for (i = 0; i < 4; i++) {
+		while (!((inb(usp->usp_iobase + 0)) & TxBE))
+			;	/* waits while writting will be allowed */
+		outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6);
+	}
+
+	return 1;
 }
 
 static int unioxx5_subdev_read(struct comedi_device *dev,
@@ -275,22 +367,6 @@
 	return 0;
 }
 
-static int unioxx5_detach(struct comedi_device *dev)
-{
-	int i;
-	struct comedi_subdevice *subdev;
-	struct unioxx5_subd_priv *usp;
-
-	for (i = 0; i < dev->n_subdevices; i++) {
-		subdev = &dev->subdevices[i];
-		usp = subdev->private;
-		release_region(usp->usp_iobase, UNIOXX5_SIZE);
-		kfree(subdev->private);
-	}
-
-	return 0;
-}
-
 /* initializing subdevice with given address */
 static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
 				 int subdev_iobase, int minor)
@@ -362,197 +438,74 @@
 	return 0;
 }
 
-static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
-				   unsigned int *data, int channel, int minor)
+static int unioxx5_attach(struct comedi_device *dev,
+			  struct comedi_devconfig *it)
 {
-	int channel_offset, val;
-	int mask = 1 << (channel & 0x07);
+	int iobase, i, n_subd;
+	int id, num, ba;
 
-	channel_offset = __unioxx5_define_chan_offset(channel);
-	if (channel_offset < 0) {
+	iobase = it->options[0];
+
+	dev->board_name = DRIVER_NAME;
+	dev->iobase = iobase;
+	iobase += UNIOXX5_SUBDEV_BASE;
+
+	/* defining number of subdevices and getting they types (it must be 'g01')  */
+	for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) {
+		id = inb(ba + 0xE);
+		num = inb(ba + 0xF);
+
+		if (id != 'g' || num != 1)
+			continue;
+
+		n_subd++;
+	}
+
+	/* unioxx5 can has from two to four subdevices */
+	if (n_subd < 2) {
 		printk(KERN_ERR
-		       "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
-		       minor, channel);
-		return 0;
-	}
-
-	/* getting previous written value */
-	val = usp->usp_prev_wr_val[channel_offset - 1];
-
-	if (*data)
-		val |= mask;
-	else
-		val &= ~mask;
-
-	outb(val, usp->usp_iobase + channel_offset);
-	/* saving new written value */
-	usp->usp_prev_wr_val[channel_offset - 1] = val;
-
-	return 1;
-}
-
-/* function for digital reading */
-static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
-				  unsigned int *data, int channel, int minor)
-{
-	int channel_offset, mask = 1 << (channel & 0x07);
-
-	channel_offset = __unioxx5_define_chan_offset(channel);
-	if (channel_offset < 0) {
-		printk(KERN_ERR
-		       "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
-		       minor, channel);
-		return 0;
-	}
-
-	*data = inb(usp->usp_iobase + channel_offset);
-	*data &= mask;
-
-	if (channel_offset > 1)
-		channel -= 2 << channel_offset;	/* this operation is created for correct readed value to 0 or 1 */
-	*data >>= channel;
-	return 1;
-}
-
-#if 0				/* not used? */
-static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode)
-{
-	int i, mask;
-
-	mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00;
-	printk("COMEDI: mode = %d\n", mask);
-
-	outb(1, usp->usp_iobase + 0);
-
-	for (i = 0; i < 3; i++)
-		outb(mask, usp->usp_iobase + i);
-
-	outb(0, usp->usp_iobase + 0);
-}
-#endif
-
-static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
-				  unsigned int *data, int channel, int minor)
-{
-	int module, i;
-
-	module = channel / 2;	/* definig module number(0 .. 11) */
-	i = (channel % 2) << 1;	/* depends on type of channel (A or B) */
-
-	/* defining if given module can work on output */
-	if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) {
-		printk(KERN_ERR
-		       "comedi%d: module in position %d with id 0x%0x is for input only!\n",
-		       minor, module, usp->usp_module_type[module]);
-		return 0;
-	}
-
-	__unioxx5_analog_config(usp, channel);
-	/* saving minor byte */
-	usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF);
-	/* saving major byte */
-	usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8);
-
-	/* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */
-	/* sending module number to card(1 .. 12) */
-	outb(module + 1, usp->usp_iobase + 5);
-	outb('W', usp->usp_iobase + 6);	/* sends (W)rite command to module */
-
-	/* sending for bytes to module(one byte per cycle iteration) */
-	for (i = 0; i < 4; i++) {
-		while (!((inb(usp->usp_iobase + 0)) & TxBE))
-			;	/* waits while writting will be allowed */
-		outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6);
-	}
-
-	return 1;
-}
-
-static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
-				 unsigned int *data, int channel, int minor)
-{
-	int module_no, read_ch;
-	char control;
-
-	module_no = channel / 2;
-	read_ch = channel % 2;	/* depend on type of channel (A or B) */
-
-	/* defining if given module can work on input */
-	if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) {
-		printk(KERN_ERR
-		       "comedi%d: module in position %d with id 0x%02x is for output only",
-		       minor, module_no, usp->usp_module_type[module_no]);
-		return 0;
-	}
-
-	__unioxx5_analog_config(usp, channel);
-	/* sends module number to card(1 .. 12) */
-	outb(module_no + 1, usp->usp_iobase + 5);
-	outb('V', usp->usp_iobase + 6);	/* sends to module (V)erify command */
-	control = inb(usp->usp_iobase);	/* get control register byte */
-
-	/* waits while reading four bytes will be allowed */
-	while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA))
-		;
-
-	/* if four bytes readding error occurs - return 0(false) */
-	if ((control & Rx4CA_ERR_MASK)) {
-		printk("COMEDI: 4 bytes error\n");
-		return 0;
-	}
-
-	if (read_ch)
-		*data = inw(usp->usp_iobase + 6);	/* channel B */
-	else
-		*data = inw(usp->usp_iobase + 4);	/* channel A */
-
-	return 1;
-}
-
-/* configure channels for analog i/o (even to output, odd to input) */
-static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel)
-{
-	int chan_a, chan_b, conf, channel_offset;
-
-	channel_offset = __unioxx5_define_chan_offset(channel);
-	conf = usp->usp_prev_cn_val[channel_offset - 1];
-	chan_a = chan_b = 1;
-
-	/* setting channel A and channel B mask */
-	if (channel % 2 == 0) {
-		chan_a <<= channel & 0x07;
-		chan_b <<= (channel + 1) & 0x07;
-	} else {
-		chan_a <<= (channel - 1) & 0x07;
-		chan_b <<= channel & 0x07;
-	}
-
-	conf |= chan_a;		/* even channel ot output */
-	conf &= ~chan_b;	/* odd channel to input */
-
-	outb(1, usp->usp_iobase + 0);
-	outb(conf, usp->usp_iobase + channel_offset);
-	outb(0, usp->usp_iobase + 0);
-
-	usp->usp_prev_cn_val[channel_offset - 1] = conf;
-}
-
-/*                                                    *\
- * this function defines if the given channel number  *
- * enters in default numeric interspace(from 0 to 23) *
- * and it returns address offset for usage needed     *
- * channel.                                           *
-\*                                                    */
-
-static int __unioxx5_define_chan_offset(int chan_num)
-{
-
-	if (chan_num < 0 || chan_num > 23)
+		       "your card must has at least 2 'g01' subdevices\n");
 		return -1;
+	}
 
-	return (chan_num >> 3) + 1;
+	if (alloc_subdevices(dev, n_subd) < 0) {
+		printk(KERN_ERR "out of memory\n");
+		return -ENOMEM;
+	}
+
+	/* initializing each of for same subdevices */
+	for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) {
+		if (__unioxx5_subdev_init(&dev->subdevices[i], iobase,
+					  dev->minor) < 0)
+			return -1;
+	}
+
+	printk(KERN_INFO "attached\n");
+	return 0;
 }
 
+static void unioxx5_detach(struct comedi_device *dev)
+{
+	int i;
+	struct comedi_subdevice *subdev;
+	struct unioxx5_subd_priv *usp;
+
+	for (i = 0; i < dev->n_subdevices; i++) {
+		subdev = &dev->subdevices[i];
+		usp = subdev->private;
+		release_region(usp->usp_iobase, UNIOXX5_SIZE);
+		kfree(subdev->private);
+	}
+}
+
+static struct comedi_driver unioxx5_driver = {
+	.driver_name	= DRIVER_NAME,
+	.module		= THIS_MODULE,
+	.attach		= unioxx5_attach,
+	.detach		= unioxx5_detach,
+};
+module_comedi_driver(unioxx5_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index bf62e0d..13d9fd3 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -317,6 +317,8 @@
 
 static DEFINE_SEMAPHORE(start_stop_sem);
 
+static struct comedi_driver driver_usbdux;	/* see below for initializer */
+
 /*
  * Stops the data acquision
  * It should be safe to call this function from any context
@@ -2304,11 +2306,11 @@
 						     void *context)
 {
 	struct usbduxsub *usbduxsub_tmp = context;
-	struct usb_device *usbdev = usbduxsub_tmp->usbdev;
+	struct usb_interface *uinterf = usbduxsub_tmp->interface;
 	int ret;
 
 	if (fw == NULL) {
-		dev_err(&usbdev->dev,
+		dev_err(&uinterf->dev,
 			"Firmware complete handler without firmware!\n");
 		return;
 	}
@@ -2320,11 +2322,11 @@
 	ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size);
 
 	if (ret) {
-		dev_err(&usbdev->dev,
+		dev_err(&uinterf->dev,
 			"Could not upload firmware (err=%d)\n", ret);
 		goto out;
 	}
-	comedi_usb_auto_config(usbdev, BOARDNAME);
+	comedi_usb_auto_config(uinterf, &driver_usbdux);
  out:
 	release_firmware(fw);
 }
@@ -2606,7 +2608,7 @@
 		dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n");
 		return;
 	}
-	comedi_usb_auto_unconfig(udev);
+	comedi_usb_auto_unconfig(intf);
 	down(&start_stop_sem);
 	down(&usbduxsub_tmp->sem);
 	tidy_up(usbduxsub_tmp);
@@ -2615,46 +2617,21 @@
 	dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n");
 }
 
-/* is called when comedi-config is called */
-static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+/* common part of attach and attach_usb */
+static int usbdux_attach_common(struct comedi_device *dev,
+				struct usbduxsub *udev,
+				void *aux_data, int aux_len)
 {
 	int ret;
-	int index;
-	int i;
-	struct usbduxsub *udev;
-
 	struct comedi_subdevice *s = NULL;
-	dev->private = NULL;
 
-	down(&start_stop_sem);
-	/* find a valid device which has been detected by the probe function of
-	 * the usb */
-	index = -1;
-	for (i = 0; i < NUMUSBDUX; i++) {
-		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
-			index = i;
-			break;
-		}
-	}
-
-	if (index < 0) {
-		printk(KERN_ERR "comedi%d: usbdux: error: attach failed, no "
-		       "usbdux devs connected to the usb bus.\n", dev->minor);
-		up(&start_stop_sem);
-		return -ENODEV;
-	}
-
-	udev = &usbduxsub[index];
 	down(&udev->sem);
 	/* pointer back to the corresponding comedi device */
 	udev->comedidev = dev;
 
 	/* trying to upload the firmware into the chip */
-	if (comedi_aux_data(it->options, 0) &&
-	    it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
-		firmwareUpload(udev, comedi_aux_data(it->options, 0),
-			       it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
-	}
+	if (aux_data)
+		firmwareUpload(udev, aux_data, aux_len);
 
 	dev->board_name = BOARDNAME;
 
@@ -2673,13 +2650,9 @@
 		dev_err(&udev->interface->dev,
 			"comedi%d: error alloc space for subdev\n", dev->minor);
 		up(&udev->sem);
-		up(&start_stop_sem);
 		return ret;
 	}
 
-	dev_info(&udev->interface->dev,
-		 "comedi%d: usb-device %d is attached to comedi.\n",
-		 dev->minor, index);
 	/* private structure is also simply the usb-structure */
 	dev->private = udev;
 
@@ -2776,44 +2749,91 @@
 
 	up(&udev->sem);
 
-	up(&start_stop_sem);
-
 	dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
 		 dev->minor);
 
 	return 0;
 }
 
-static int usbdux_detach(struct comedi_device *dev)
+/* is called when comedi-config is called */
+static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	struct usbduxsub *usbduxsub_tmp;
+	int ret;
+	int index;
+	int i;
+	void *aux_data;
+	int aux_len;
 
-	if (!dev) {
-		printk(KERN_ERR
-		       "comedi?: usbdux: detach without dev variable...\n");
-		return -EFAULT;
-	}
-
-	usbduxsub_tmp = dev->private;
-	if (!usbduxsub_tmp) {
-		printk(KERN_ERR
-		       "comedi?: usbdux: detach without ptr to usbduxsub[]\n");
-		return -EFAULT;
-	}
-
-	dev_dbg(&usbduxsub_tmp->interface->dev, "comedi%d: detach usb device\n",
-		dev->minor);
-
-	down(&usbduxsub_tmp->sem);
-	/* Don't allow detach to free the private structure */
-	/* It's one entry of of usbduxsub[] */
 	dev->private = NULL;
-	usbduxsub_tmp->attached = 0;
-	usbduxsub_tmp->comedidev = NULL;
-	dev_dbg(&usbduxsub_tmp->interface->dev,
-		"comedi%d: detach: successfully removed\n", dev->minor);
-	up(&usbduxsub_tmp->sem);
-	return 0;
+
+	aux_data = comedi_aux_data(it->options, 0);
+	aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
+	if (aux_data == NULL)
+		aux_len = 0;
+	else if (aux_len == 0)
+		aux_data = NULL;
+
+	down(&start_stop_sem);
+	/* find a valid device which has been detected by the probe function of
+	 * the usb */
+	index = -1;
+	for (i = 0; i < NUMUSBDUX; i++) {
+		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
+			index = i;
+			break;
+		}
+	}
+
+	if (index < 0) {
+		printk(KERN_ERR
+		       "comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n",
+		       dev->minor);
+		ret = -ENODEV;
+	} else
+		ret = usbdux_attach_common(dev, &usbduxsub[index],
+					   aux_data, aux_len);
+	up(&start_stop_sem);
+	return ret;
+}
+
+/* is called from comedi_usb_auto_config() */
+static int usbdux_attach_usb(struct comedi_device *dev,
+			     struct usb_interface *uinterf)
+{
+	int ret;
+	struct usbduxsub *this_usbduxsub;
+
+	dev->private = NULL;
+
+	down(&start_stop_sem);
+	this_usbduxsub = usb_get_intfdata(uinterf);
+	if (!this_usbduxsub || !this_usbduxsub->probed) {
+		printk(KERN_ERR
+		       "comedi%d: usbdux: error: attach_usb failed, not connected\n",
+		       dev->minor);
+		ret = -ENODEV;
+	} else if (this_usbduxsub->attached) {
+		printk(KERN_ERR
+		       "comedi%d: usbdux: error: attach_usb failed, already attached\n",
+		       dev->minor);
+		ret = -ENODEV;
+	} else
+		ret = usbdux_attach_common(dev, this_usbduxsub, NULL, 0);
+	up(&start_stop_sem);
+	return ret;
+}
+
+static void usbdux_detach(struct comedi_device *dev)
+{
+	struct usbduxsub *usb = dev->private;
+
+	if (usb) {
+		down(&usb->sem);
+		dev->private = NULL;
+		usb->attached = 0;
+		usb->comedidev = NULL;
+		up(&usb->sem);
+	}
 }
 
 /* main driver struct */
@@ -2822,6 +2842,7 @@
 	.module = THIS_MODULE,
 	.attach = usbdux_attach,
 	.detach = usbdux_detach,
+	.attach_usb = usbdux_attach_usb,
 };
 
 /* Table with the USB-devices: just now only testing IDs */
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 2a8e725..7b1d21a 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -201,6 +201,8 @@
 
 static DEFINE_SEMAPHORE(start_stop_sem);
 
+static struct comedi_driver driver_usbduxfast;	/* see below for initializer */
+
 /*
  * bulk transfers to usbduxfast
  */
@@ -453,14 +455,15 @@
 	/* 7f92 to zero */
 	local_transfer_buffer[0] = 0;
 	/* bRequest, "Firmware" */
-	ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
-				VENDOR_DIR_OUT,	/* bmRequestType */
-				USBDUXFASTSUB_CPUCS,	/* Value */
-				0x0000,	/* Index */
-				/* address of the transfer buffer */
-				local_transfer_buffer,
-				1,	/* Length */
-				EZTIMEOUT);	/* Timeout */
+	ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0),
+			      USBDUXFASTSUB_FIRMWARE,
+			      VENDOR_DIR_OUT,	  /* bmRequestType */
+			      USBDUXFASTSUB_CPUCS,    /* Value */
+			      0x0000,	/* Index */
+			      /* address of the transfer buffer */
+			      local_transfer_buffer,
+			      1,      /* Length */
+			      EZTIMEOUT);    /* Timeout */
 	if (ret < 0) {
 		printk("comedi_: usbduxfast_: control msg failed (start)\n");
 		return ret;
@@ -477,7 +480,8 @@
 	/* 7f92 to one */
 	local_transfer_buffer[0] = 1;
 	/* bRequest, "Firmware" */
-	ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
+	ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0),
+			      USBDUXFASTSUB_FIRMWARE,
 			      VENDOR_DIR_OUT,	/* bmRequestType */
 			      USBDUXFASTSUB_CPUCS,	/* Value */
 			      0x0000,	/* Index */
@@ -504,14 +508,15 @@
 	       startAddr, local_transfer_buffer[0]);
 #endif
 	/* brequest, firmware */
-	ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
-				VENDOR_DIR_OUT,	/* bmRequestType */
-				startAddr,	/* value */
-				0x0000,	/* index */
-				/* our local safe buffer */
-				local_transfer_buffer,
-				len,	/* length */
-				EZTIMEOUT);	/* timeout */
+	ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0),
+			      USBDUXFASTSUB_FIRMWARE,
+			      VENDOR_DIR_OUT,	/* bmRequestType */
+			      startAddr,	/* value */
+			      0x0000,	 /* index */
+			      /* our local safe buffer */
+			      local_transfer_buffer,
+			      len,	/* length */
+			      EZTIMEOUT);      /* timeout */
 
 #ifdef CONFIG_COMEDI_DEBUG
 	printk(KERN_DEBUG "comedi_: usbduxfast: result=%d\n", ret);
@@ -1440,7 +1445,7 @@
 							 *fw, void *context)
 {
 	struct usbduxfastsub_s *usbduxfastsub_tmp = context;
-	struct usb_device *usbdev = usbduxfastsub_tmp->usbdev;
+	struct usb_interface *uinterf = usbduxfastsub_tmp->interface;
 	int ret;
 
 	if (fw == NULL)
@@ -1453,12 +1458,12 @@
 	ret = firmwareUpload(usbduxfastsub_tmp, fw->data, fw->size);
 
 	if (ret) {
-		dev_err(&usbdev->dev,
+		dev_err(&uinterf->dev,
 			"Could not upload firmware (err=%d)\n", ret);
 		goto out;
 	}
 
-	comedi_usb_auto_config(usbdev, BOARDNAME);
+	comedi_usb_auto_config(uinterf, &driver_usbduxfast);
  out:
 	release_firmware(fw);
 }
@@ -1606,7 +1611,7 @@
 		return;
 	}
 
-	comedi_usb_auto_unconfig(udev);
+	comedi_usb_auto_unconfig(intf);
 
 	down(&start_stop_sem);
 	down(&udfs->sem);
@@ -1721,43 +1726,19 @@
 	return 0;
 }
 
-static int usbduxfast_detach(struct comedi_device *dev)
+static void usbduxfast_detach(struct comedi_device *dev)
 {
-	struct usbduxfastsub_s *udfs;
+	struct usbduxfastsub_s *usb = dev->private;
 
-	if (!dev) {
-		printk(KERN_ERR "comedi?: usbduxfast: detach without dev "
-		       "variable...\n");
-		return -EFAULT;
+	if (usb) {
+		down(&usb->sem);
+		down(&start_stop_sem);
+		dev->private = NULL;
+		usb->attached = 0;
+		usb->comedidev = NULL;
+		up(&start_stop_sem);
+		up(&usb->sem);
 	}
-#ifdef CONFIG_COMEDI_DEBUG
-	printk(KERN_DEBUG "comedi%d: usbduxfast: detach usb device\n",
-	       dev->minor);
-#endif
-
-	udfs = dev->private;
-	if (!udfs) {
-		printk(KERN_ERR "comedi?: usbduxfast: detach without ptr to "
-		       "usbduxfastsub[]\n");
-		return -EFAULT;
-	}
-
-	down(&udfs->sem);
-	down(&start_stop_sem);
-	/*
-	 * Don't allow detach to free the private structure
-	 * It's one entry of of usbduxfastsub[]
-	 */
-	dev->private = NULL;
-	udfs->attached = 0;
-	udfs->comedidev = NULL;
-#ifdef CONFIG_COMEDI_DEBUG
-	printk(KERN_DEBUG "comedi%d: usbduxfast: detach: successfully "
-	       "removed\n", dev->minor);
-#endif
-	up(&start_stop_sem);
-	up(&udfs->sem);
-	return 0;
 }
 
 /*
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index 63c9b6d..465afbd 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -267,6 +267,8 @@
 
 static DEFINE_SEMAPHORE(start_stop_sem);
 
+static struct comedi_driver driver_usbduxsigma;	/* see below for initializer */
+
 /*
  * Stops the data acquision
  * It should be safe to call this function from any context
@@ -2312,11 +2314,11 @@
 						     void *context)
 {
 	struct usbduxsub *usbduxsub_tmp = context;
-	struct usb_device *usbdev = usbduxsub_tmp->usbdev;
+	struct usb_interface *uinterf = usbduxsub_tmp->interface;
 	int ret;
 
 	if (fw == NULL) {
-		dev_err(&usbdev->dev,
+		dev_err(&uinterf->dev,
 			"Firmware complete handler without firmware!\n");
 		return;
 	}
@@ -2328,11 +2330,11 @@
 	ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size);
 
 	if (ret) {
-		dev_err(&usbdev->dev,
+		dev_err(&uinterf->dev,
 			"Could not upload firmware (err=%d)\n", ret);
 		goto out;
 	}
-	comedi_usb_auto_config(usbdev, BOARDNAME);
+	comedi_usb_auto_config(uinterf, &driver_usbduxsigma);
 out:
 	release_firmware(fw);
 }
@@ -2623,7 +2625,7 @@
 	if (usbduxsub_tmp->ao_cmd_running)
 		/* we are still running a command */
 		usbdux_ao_stop(usbduxsub_tmp, 1);
-	comedi_usb_auto_unconfig(udev);
+	comedi_usb_auto_unconfig(intf);
 	down(&start_stop_sem);
 	down(&usbduxsub_tmp->sem);
 	tidy_up(usbduxsub_tmp);
@@ -2799,37 +2801,17 @@
 	return 0;
 }
 
-static int usbduxsigma_detach(struct comedi_device *dev)
+static void usbduxsigma_detach(struct comedi_device *dev)
 {
-	struct usbduxsub *usbduxsub_tmp;
+	struct usbduxsub *usb = dev->private;
 
-	if (!dev) {
-		printk(KERN_ERR
-		       "comedi? usbduxsigma detach: dev=NULL\n");
-		return -EFAULT;
+	if (usb) {
+		down(&usb->sem);
+		dev->private = NULL;
+		usb->attached = 0;
+		usb->comedidev = NULL;
+		up(&usb->sem);
 	}
-
-	usbduxsub_tmp = dev->private;
-	if (!usbduxsub_tmp) {
-		printk(KERN_ERR
-		       "comedi?: usbduxsigma detach: private=NULL\n");
-		return -EFAULT;
-	}
-
-	dev_dbg(&usbduxsub_tmp->interface->dev,
-		"comedi%d: detach usb device\n",
-		dev->minor);
-
-	down(&usbduxsub_tmp->sem);
-	/* Don't allow detach to free the private structure */
-	/* It's one entry of of usbduxsub[] */
-	dev->private = NULL;
-	usbduxsub_tmp->attached = 0;
-	usbduxsub_tmp->comedidev = NULL;
-	dev_info(&usbduxsub_tmp->interface->dev,
-		"comedi%d: successfully detached.\n", dev->minor);
-	up(&usbduxsub_tmp->sem);
-	return 0;
 }
 
 /* main driver struct */
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index 3d13ca6e1..baee8d7 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -151,27 +151,12 @@
 #define URB_RCV_FLAG            (1 << 0)
 #define URB_SND_FLAG            (1 << 1)
 
-#define CONFIG_VMK80XX_DEBUG
-#undef CONFIG_VMK80XX_DEBUG
-
-#ifdef CONFIG_VMK80XX_DEBUG
-static int dbgvm = 1;
-#else
-static int dbgvm;
-#endif
-
 #ifdef CONFIG_COMEDI_DEBUG
 static int dbgcm = 1;
 #else
 static int dbgcm;
 #endif
 
-#define dbgvm(fmt, arg...)                     \
-do {                                           \
-	if (dbgvm)                             \
-		printk(KERN_DEBUG fmt, ##arg); \
-} while (0)
-
 #define dbgcm(fmt, arg...)                     \
 do {                                           \
 	if (dbgcm)                             \
@@ -247,13 +232,13 @@
 
 static DEFINE_MUTEX(glb_mutex);
 
+static struct comedi_driver driver_vmk80xx;	/* see below for initializer */
+
 static void vmk80xx_tx_callback(struct urb *urb)
 {
 	struct vmk80xx_usb *dev = urb->context;
 	int stat = urb->status;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	if (stat && !(stat == -ENOENT
 		      || stat == -ECONNRESET || stat == -ESHUTDOWN))
 		dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
@@ -272,8 +257,6 @@
 	struct vmk80xx_usb *dev = urb->context;
 	int stat = urb->status;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	switch (stat) {
 	case 0:
 		break;
@@ -295,7 +278,9 @@
 		if (!usb_submit_urb(urb, GFP_KERNEL))
 			goto exit;
 
-		err("comedi#: vmk80xx: %s - submit urb failed\n", __func__);
+		dev_err(&urb->dev->dev,
+			"comedi#: vmk80xx: %s - submit urb failed\n",
+			__func__);
 
 		usb_unanchor_urb(urb);
 	}
@@ -312,8 +297,6 @@
 	unsigned char tx[1];
 	unsigned char rx[2];
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
 	rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
 
@@ -338,8 +321,6 @@
 	unsigned char rx[64];
 	int cnt;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
 	rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
 
@@ -367,8 +348,6 @@
 	int ival;
 	size_t size;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb)
 		return -ENOMEM;
@@ -406,8 +385,6 @@
 	void (*callback) (struct urb *);
 	int ival;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	if (flag & URB_RCV_FLAG) {
 		rx_addr = dev->ep_rx->bEndpointAddress;
 		pipe = usb_rcvintpipe(dev->udev, rx_addr);
@@ -435,8 +412,6 @@
 	unsigned int rx_pipe;
 	size_t size;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	set_bit(TRANS_IN_BUSY, &dev->flags);
 	set_bit(TRANS_OUT_BUSY, &dev->flags);
 
@@ -464,8 +439,6 @@
 	struct urb *urb;
 	int retval;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	if (!dev->intf)
 		return -ENODEV;
 
@@ -512,8 +485,6 @@
 	struct urb *urb;
 	int retval;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	if (!dev->intf)
 		return -ENODEV;
 
@@ -588,8 +559,6 @@
 	int reg[2];
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_IN);
 	if (n)
 		return n;
@@ -641,8 +610,6 @@
 	int reg;
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_OUT);
 	if (n)
 		return n;
@@ -686,8 +653,6 @@
 	int reg;
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_IN);
 	if (n)
 		return n;
@@ -720,8 +685,6 @@
 	int reg;
 	int retval;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	retval = rudimentary_check(dev, DIR_IN);
 	if (retval)
 		return retval;
@@ -766,8 +729,6 @@
 	int inp;
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_IN);
 	if (n)
 		return n;
@@ -813,8 +774,6 @@
 	int cmd;
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_OUT);
 	if (n)
 		return n;
@@ -861,8 +820,6 @@
 	int reg;
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_IN);
 	if (n)
 		return n;
@@ -895,8 +852,6 @@
 	int dir, reg, cmd;
 	int retval;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	dir = 0;
 
 	if (data[0])
@@ -962,8 +917,6 @@
 	int reg[2];
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_IN);
 	if (n)
 		return n;
@@ -1012,18 +965,16 @@
 	int reg;
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_OUT);
 	if (n)
 		return n;
 
-	down(&dev->limit_sem);
-
 	insn_cmd = data[0];
 	if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
 		return -EINVAL;
 
+	down(&dev->limit_sem);
+
 	chan = CR_CHAN(insn->chanspec);
 
 	if (dev->board.model == VMK8055_MODEL) {
@@ -1060,8 +1011,6 @@
 	int cmd;
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_OUT);
 	if (n)
 		return n;
@@ -1106,8 +1055,6 @@
 	int reg[2];
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_IN);
 	if (n)
 		return n;
@@ -1141,8 +1088,6 @@
 	int cmd;
 	int n;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	n = rudimentary_check(dev, DIR_OUT);
 	if (n)
 		return n;
@@ -1191,8 +1136,6 @@
 	struct comedi_subdevice *s;
 	int minor;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	mutex_lock(&glb_mutex);
 
 	for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
@@ -1307,34 +1250,16 @@
 	return 0;
 }
 
-static int vmk80xx_detach(struct comedi_device *cdev)
+static void vmk80xx_detach(struct comedi_device *dev)
 {
-	struct vmk80xx_usb *dev;
-	int minor;
+	struct vmk80xx_usb *usb = dev->private;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
-	if (!cdev)
-		return -EFAULT;
-
-	dev = cdev->private;
-	if (!dev)
-		return -EFAULT;
-
-	down(&dev->limit_sem);
-
-	cdev->private = NULL;
-	dev->attached = 0;
-
-	minor = cdev->minor;
-
-	printk(KERN_INFO
-	       "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n",
-	       minor, dev->count, dev->board.name);
-
-	up(&dev->limit_sem);
-
-	return 0;
+	if (usb) {
+		down(&usb->limit_sem);
+		dev->private = NULL;
+		usb->attached = 0;
+		up(&usb->limit_sem);
+	}
 }
 
 static int vmk80xx_probe(struct usb_interface *intf,
@@ -1346,8 +1271,6 @@
 	struct usb_endpoint_descriptor *ep_desc;
 	size_t size;
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	mutex_lock(&glb_mutex);
 
 	for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
@@ -1482,7 +1405,7 @@
 
 	mutex_unlock(&glb_mutex);
 
-	comedi_usb_auto_config(dev->udev, BOARDNAME);
+	comedi_usb_auto_config(intf, &driver_vmk80xx);
 
 	return 0;
 error:
@@ -1495,12 +1418,10 @@
 {
 	struct vmk80xx_usb *dev = usb_get_intfdata(intf);
 
-	dbgvm("vmk80xx: %s\n", __func__);
-
 	if (!dev)
 		return;
 
-	comedi_usb_auto_unconfig(dev->udev);
+	comedi_usb_auto_unconfig(intf);
 
 	mutex_lock(&glb_mutex);
 	down(&dev->limit_sem);
diff --git a/drivers/staging/comedi/internal.h b/drivers/staging/comedi/internal.h
index 434ce34..7ed20a0 100644
--- a/drivers/staging/comedi/internal.h
+++ b/drivers/staging/comedi/internal.h
@@ -1,5 +1,5 @@
 /*
- * various internal comedi functions
+ * various internal comedi stuff
  */
 int do_rangeinfo_ioctl(struct comedi_device *dev,
 		       struct comedi_rangeinfo __user *arg);
@@ -7,6 +7,10 @@
 	       struct comedi_insn *insn, unsigned int *data);
 int comedi_alloc_board_minor(struct device *hardware_device);
 void comedi_free_board_minor(unsigned minor);
+int comedi_find_board_minor(struct device *hardware_device);
 void comedi_reset_async_buf(struct comedi_async *async);
 int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
 		     unsigned long new_size);
+
+extern unsigned int comedi_default_buf_size_kb;
+extern unsigned int comedi_default_buf_maxsize_kb;
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 886f565..5b11c5e 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -1710,7 +1710,8 @@
 		return value;
 }
 
-static int et131x_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 value)
+static int et131x_mdio_write(struct mii_bus *bus, int phy_addr,
+			     int reg, u16 value)
 {
 	struct net_device *netdev = bus->priv;
 	struct et131x_adapter *adapter = netdev_priv(netdev);
@@ -4013,7 +4014,7 @@
 		dev_err(&pdev->dev, "Missing PCIe capabilities\n");
 		goto err_out;
 	}
-		
+
 	/* Let's set up the PORT LOGIC Register.  First we need to know what
 	 * the max_payload_size is
 	 */
@@ -4060,7 +4061,7 @@
 		goto err_out;
 	}
 
-	ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | ( 0x04 << 12);
+	ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | (0x04 << 12);
 
 	if (pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl)) {
 		dev_err(&pdev->dev,
@@ -4824,7 +4825,8 @@
 	adapter->error_timer.data = (unsigned long)adapter;
 	add_timer(&adapter->error_timer);
 
-	result = request_irq(irq, et131x_isr, IRQF_SHARED, netdev->name, netdev);
+	result = request_irq(irq, et131x_isr,
+			     IRQF_SHARED, netdev->name, netdev);
 	if (result) {
 		dev_err(&pdev->dev, "could not register IRQ %d\n", irq);
 		return result;
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
index 3bf0f40e..acbb2cc 100644
--- a/drivers/staging/frontier/alphatrack.c
+++ b/drivers/staging/frontier/alphatrack.c
@@ -333,8 +333,8 @@
 	interface = usb_find_interface(&usb_alphatrack_driver, subminor);
 
 	if (!interface) {
-		err("%s - error, can't find device for minor %d\n",
-		    __func__, subminor);
+		printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+		       __func__, subminor);
 		retval = -ENODEV;
 		goto unlock_disconnect_exit;
 	}
@@ -494,7 +494,8 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->intf == NULL) {
 		retval = -ENODEV;
-		err("No device or device unplugged %d\n", retval);
+		printk(KERN_ERR "%s: No device or device unplugged %d\n",
+		       __func__, retval);
 		goto unlock_exit;
 	}
 
@@ -564,7 +565,8 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->intf == NULL) {
 		retval = -ENODEV;
-		err("No device or device unplugged %d\n", retval);
+		printk(KERN_ERR "%s: No device or device unplugged %d\n",
+		       __func__, retval);
 		goto unlock_exit;
 	}
 
@@ -599,7 +601,7 @@
 	}
 
 	if (dev->interrupt_out_endpoint == NULL) {
-		err("Endpoint should not be be null!\n");
+		dev_err(&dev->intf->dev, "Endpoint should not be be null!\n");
 		goto unlock_exit;
 	}
 
@@ -619,7 +621,8 @@
 	retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
 	if (retval) {
 		dev->interrupt_out_busy = 0;
-		err("Couldn't submit interrupt_out_urb %d\n", retval);
+		dev_err(&dev->intf->dev,
+			"Couldn't submit interrupt_out_urb %d\n", retval);
 		atomic_dec(&dev->writes_pending);
 		goto unlock_exit;
 	}
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index 29e99bb..376706f 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -353,7 +353,7 @@
 	interface = usb_find_interface(&usb_tranzport_driver, subminor);
 
 	if (!interface) {
-		err("%s - error, can't find device for minor %d\n",
+		printk(KERN_ERR "%s - error, can't find device for minor %d\n",
 			__func__, subminor);
 		retval = -ENODEV;
 		goto unlock_disconnect_exit;
@@ -517,9 +517,11 @@
 		goto exit;
 	}
 
-	/* verify that the device wasn't unplugged */ if (dev->intf == NULL) {
+	/* verify that the device wasn't unplugged */
+	if (dev->intf == NULL) {
 		retval = -ENODEV;
-		err("No device or device unplugged %d\n", retval);
+		printk(KERN_ERR "%s: No device or device unplugged %d\n",
+			__func__, retval);
 		goto unlock_exit;
 	}
 
@@ -691,7 +693,8 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->intf == NULL) {
 		retval = -ENODEV;
-		err("No device or device unplugged %d\n", retval);
+		printk(KERN_ERR "%s: No device or device unplugged %d\n",
+			__func__, retval);
 		goto unlock_exit;
 	}
 
@@ -726,7 +729,7 @@
 	}
 
 	if (dev->interrupt_out_endpoint == NULL) {
-		err("Endpoint should not be be null!\n");
+		dev_err(&dev->intf->dev, "Endpoint should not be be null!\n");
 		goto unlock_exit;
 	}
 
@@ -746,7 +749,8 @@
 	retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
 	if (retval) {
 		dev->interrupt_out_busy = 0;
-		err("Couldn't submit interrupt_out_urb %d\n", retval);
+		dev_err(&dev->intf->dev,
+			"Couldn't submit interrupt_out_urb %d\n", retval);
 		goto unlock_exit;
 	}
 	retval = bytes_to_write;
diff --git a/drivers/staging/gdm72xx/Kconfig b/drivers/staging/gdm72xx/Kconfig
new file mode 100644
index 0000000..3c18efe
--- /dev/null
+++ b/drivers/staging/gdm72xx/Kconfig
@@ -0,0 +1,46 @@
+#
+# GCT GDM72xx WiMAX driver configuration
+#
+
+menuconfig WIMAX_GDM72XX
+	tristate "GCT GDM72xx WiMAX support"
+	depends on NET
+	help
+	  Support for the GCT GDM72xx WiMAX chip
+
+if WIMAX_GDM72XX
+
+config WIMAX_GDM72XX_QOS
+	bool "Enable QoS support"
+	default n
+
+config WIMAX_GDM72XX_K_MODE
+	bool "Enable K mode"
+	default n
+
+config WIMAX_GDM72XX_WIMAX2
+	bool "Enable WIMAX2 support"
+	default n
+
+choice
+	prompt "Select interface"
+
+config WIMAX_GDM72XX_USB
+	bool "USB interface"
+	depends on USB
+
+config WIMAX_GDM72XX_SDIO
+	bool "SDIO interface"
+	depends on MMC
+
+endchoice
+
+if WIMAX_GDM72XX_USB
+
+config WIMAX_GDM72XX_USB_PM
+	bool "Enable power managerment support"
+	depends on USB_SUSPEND
+
+endif # WIMAX_GDM72XX_USB
+
+endif # WIMAX_GDM72XX
diff --git a/drivers/staging/gdm72xx/Makefile b/drivers/staging/gdm72xx/Makefile
new file mode 100644
index 0000000..35da7b9
--- /dev/null
+++ b/drivers/staging/gdm72xx/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_WIMAX_GDM72XX) := gdmwm.o
+
+gdmwm-y += gdm_wimax.o netlink_k.o
+gdmwm-$(CONFIG_WIMAX_GDM72XX_QOS) += gdm_qos.o
+gdmwm-$(CONFIG_WIMAX_GDM72XX_SDIO) += gdm_sdio.o sdio_boot.o
+gdmwm-$(CONFIG_WIMAX_GDM72XX_USB) += gdm_usb.o usb_boot.o
diff --git a/drivers/staging/gdm72xx/TODO b/drivers/staging/gdm72xx/TODO
new file mode 100644
index 0000000..30ac01a
--- /dev/null
+++ b/drivers/staging/gdm72xx/TODO
@@ -0,0 +1,5 @@
+TODO:
+- Replace kernel_thread with kthread in gdm_usb.c
+- Replace hard-coded firmware paths with request_firmware in
+  sdio_boot.c and usb_boot.c
+- Clean up coding style to meet kernel standard.
diff --git a/drivers/staging/gdm72xx/gdm_qos.c b/drivers/staging/gdm72xx/gdm_qos.c
new file mode 100644
index 0000000..0217680
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_qos.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <asm/byteorder.h>
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_ether.h>
+
+#include "gdm_wimax.h"
+#include "hci.h"
+#include "gdm_qos.h"
+
+#define B2H(x)		__be16_to_cpu(x)
+
+#undef dprintk
+#define dprintk(fmt, args ...) printk(KERN_DEBUG "[QoS] " fmt, ## args)
+#undef wprintk
+#define wprintk(fmt, args ...) \
+	printk(KERN_WARNING "[QoS WARNING] " fmt, ## args)
+#undef eprintk
+#define eprintk(fmt, args ...) printk(KERN_ERR "[QoS ERROR] " fmt, ## args)
+
+
+#define MAX_FREE_LIST_CNT		32
+static struct {
+	struct list_head head;
+	int cnt;
+	spinlock_t lock;
+} qos_free_list;
+
+static void init_qos_entry_list(void)
+{
+	qos_free_list.cnt = 0;
+	INIT_LIST_HEAD(&qos_free_list.head);
+	spin_lock_init(&qos_free_list.lock);
+}
+
+static void *alloc_qos_entry(void)
+{
+	struct qos_entry_s *entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qos_free_list.lock, flags);
+	if (qos_free_list.cnt) {
+		entry = list_entry(qos_free_list.head.prev, struct qos_entry_s,
+					list);
+		list_del(&entry->list);
+		qos_free_list.cnt--;
+		spin_unlock_irqrestore(&qos_free_list.lock, flags);
+		return entry;
+	}
+	spin_unlock_irqrestore(&qos_free_list.lock, flags);
+
+	entry = kmalloc(sizeof(struct qos_entry_s), GFP_ATOMIC);
+	return entry;
+}
+
+static void free_qos_entry(void *entry)
+{
+	struct qos_entry_s *qentry = (struct qos_entry_s *) entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qos_free_list.lock, flags);
+	if (qos_free_list.cnt < MAX_FREE_LIST_CNT) {
+		list_add(&qentry->list, &qos_free_list.head);
+		qos_free_list.cnt++;
+		spin_unlock_irqrestore(&qos_free_list.lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&qos_free_list.lock, flags);
+
+	kfree(entry);
+}
+
+static void free_qos_entry_list(struct list_head *free_list)
+{
+	struct qos_entry_s *entry, *n;
+	int total_free = 0;
+
+	list_for_each_entry_safe(entry, n, free_list, list) {
+		list_del(&entry->list);
+		kfree(entry);
+		total_free++;
+	}
+
+	dprintk("%s: total_free_cnt=%d\n", __func__, total_free);
+}
+
+void gdm_qos_init(void *nic_ptr)
+{
+	struct nic *nic = nic_ptr;
+	struct qos_cb_s *qcb = &nic->qos;
+	int i;
+
+	for (i = 0 ; i < QOS_MAX; i++) {
+		INIT_LIST_HEAD(&qcb->qos_list[i]);
+		qcb->csr[i].QoSBufCount = 0;
+		qcb->csr[i].Enabled = 0;
+	}
+
+	qcb->qos_list_cnt = 0;
+	qcb->qos_null_idx = QOS_MAX-1;
+	qcb->qos_limit_size = 255;
+
+	spin_lock_init(&qcb->qos_lock);
+
+	init_qos_entry_list();
+}
+
+void gdm_qos_release_list(void *nic_ptr)
+{
+	struct nic *nic = nic_ptr;
+	struct qos_cb_s *qcb = &nic->qos;
+	unsigned long flags;
+	struct qos_entry_s *entry, *n;
+	struct list_head free_list;
+	int i;
+
+	INIT_LIST_HEAD(&free_list);
+
+	spin_lock_irqsave(&qcb->qos_lock, flags);
+
+	for (i = 0; i < QOS_MAX; i++) {
+		qcb->csr[i].QoSBufCount = 0;
+		qcb->csr[i].Enabled = 0;
+	}
+
+	qcb->qos_list_cnt = 0;
+	qcb->qos_null_idx = QOS_MAX-1;
+
+	for (i = 0; i < QOS_MAX; i++) {
+		list_for_each_entry_safe(entry, n, &qcb->qos_list[i], list) {
+			list_move_tail(&entry->list, &free_list);
+		}
+	}
+	spin_unlock_irqrestore(&qcb->qos_lock, flags);
+	free_qos_entry_list(&free_list);
+}
+
+static u32 chk_ipv4_rule(struct gdm_wimax_csr_s *csr, u8 *Stream, u8 *port)
+{
+	int i;
+
+	if (csr->ClassifierRuleEnable&IPTYPEOFSERVICE) {
+		if (((Stream[1] & csr->IPToSMask) < csr->IPToSLow) ||
+		((Stream[1] & csr->IPToSMask) > csr->IPToSHigh))
+			return 1;
+	}
+
+	if (csr->ClassifierRuleEnable&PROTOCOL) {
+		if (Stream[9] != csr->Protocol)
+			return 1;
+	}
+
+	if (csr->ClassifierRuleEnable&IPMASKEDSRCADDRESS) {
+		for (i = 0; i < 4; i++) {
+			if ((Stream[12 + i] & csr->IPSrcAddrMask[i]) !=
+			(csr->IPSrcAddr[i] & csr->IPSrcAddrMask[i]))
+				return 1;
+		}
+	}
+
+	if (csr->ClassifierRuleEnable&IPMASKEDDSTADDRESS) {
+		for (i = 0; i < 4; i++) {
+			if ((Stream[16 + i] & csr->IPDstAddrMask[i]) !=
+			(csr->IPDstAddr[i] & csr->IPDstAddrMask[i]))
+				return 1;
+		}
+	}
+
+	if (csr->ClassifierRuleEnable&PROTOCOLSRCPORTRANGE) {
+		i = ((port[0]<<8)&0xff00)+port[1];
+		if ((i < csr->SrcPortLow) || (i > csr->SrcPortHigh))
+			return 1;
+	}
+
+	if (csr->ClassifierRuleEnable&PROTOCOLDSTPORTRANGE) {
+		i = ((port[2]<<8)&0xff00)+port[3];
+		if ((i < csr->DstPortLow) || (i > csr->DstPortHigh))
+			return 1;
+	}
+
+	return 0;
+}
+
+static u32 get_qos_index(struct nic *nic, u8* iph, u8* tcpudph)
+{
+	u32	IP_Ver, Header_Len, i;
+	struct qos_cb_s *qcb = &nic->qos;
+
+	if (iph == NULL || tcpudph == NULL)
+		return -1;
+
+	IP_Ver = (iph[0]>>4)&0xf;
+	Header_Len = iph[0]&0xf;
+
+	if (IP_Ver == 4) {
+		for (i = 0; i < QOS_MAX; i++) {
+			if (qcb->csr[i].Enabled) {
+				if (qcb->csr[i].ClassifierRuleEnable) {
+					if (chk_ipv4_rule(&qcb->csr[i], iph,
+					tcpudph) == 0)
+						return i;
+				}
+			}
+		}
+	}
+
+	return -1;
+}
+
+static u32 extract_qos_list(struct nic *nic, struct list_head *head)
+{
+	struct qos_cb_s *qcb = &nic->qos;
+	struct qos_entry_s *entry;
+	int i;
+
+	INIT_LIST_HEAD(head);
+
+	for (i = 0; i < QOS_MAX; i++) {
+		if (qcb->csr[i].Enabled) {
+			if (qcb->csr[i].QoSBufCount < qcb->qos_limit_size) {
+				if (!list_empty(&qcb->qos_list[i])) {
+					entry = list_entry(
+					qcb->qos_list[i].prev,
+					struct qos_entry_s, list);
+					list_move_tail(&entry->list, head);
+					qcb->csr[i].QoSBufCount++;
+
+					if (!list_empty(&qcb->qos_list[i]))
+						wprintk("QoS Index(%d) "
+							"is piled!!\n", i);
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void send_qos_list(struct nic *nic, struct list_head *head)
+{
+	struct qos_entry_s *entry, *n;
+
+	list_for_each_entry_safe(entry, n, head, list) {
+		list_del(&entry->list);
+		free_qos_entry(entry);
+		gdm_wimax_send_tx(entry->skb, entry->dev);
+	}
+}
+
+int gdm_qos_send_hci_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+	struct nic *nic = netdev_priv(dev);
+	int index;
+	struct qos_cb_s *qcb = &nic->qos;
+	unsigned long flags;
+	struct ethhdr *ethh = (struct ethhdr *) (skb->data + HCI_HEADER_SIZE);
+	struct iphdr *iph = (struct iphdr *) ((char *) ethh + ETH_HLEN);
+	struct tcphdr *tcph;
+	struct qos_entry_s *entry = NULL;
+	struct list_head send_list;
+	int ret = 0;
+
+	tcph = (struct tcphdr *) iph + iph->ihl*4;
+
+	if (B2H(ethh->h_proto) == ETH_P_IP) {
+		if (qcb->qos_list_cnt && !qos_free_list.cnt) {
+			entry = alloc_qos_entry();
+			entry->skb = skb;
+			entry->dev = dev;
+			dprintk("qcb->qos_list_cnt=%d\n", qcb->qos_list_cnt);
+		}
+
+		spin_lock_irqsave(&qcb->qos_lock, flags);
+		if (qcb->qos_list_cnt) {
+			index = get_qos_index(nic, (u8 *)iph, (u8 *) tcph);
+			if (index == -1)
+				index = qcb->qos_null_idx;
+
+			if (!entry) {
+				entry = alloc_qos_entry();
+				entry->skb = skb;
+				entry->dev = dev;
+			}
+
+			list_add_tail(&entry->list, &qcb->qos_list[index]);
+			extract_qos_list(nic, &send_list);
+			spin_unlock_irqrestore(&qcb->qos_lock, flags);
+			send_qos_list(nic, &send_list);
+			goto out;
+		}
+		spin_unlock_irqrestore(&qcb->qos_lock, flags);
+		if (entry)
+			free_qos_entry(entry);
+	}
+
+	ret = gdm_wimax_send_tx(skb, dev);
+out:
+	return ret;
+}
+
+static u32 get_csr(struct qos_cb_s *qcb, u32 SFID, int mode)
+{
+	int i;
+
+	for (i = 0; i < qcb->qos_list_cnt; i++) {
+		if (qcb->csr[i].SFID == SFID)
+			return i;
+	}
+
+	if (mode) {
+		for (i = 0; i < QOS_MAX; i++) {
+			if (qcb->csr[i].Enabled == 0) {
+				qcb->csr[i].Enabled = 1;
+				qcb->qos_list_cnt++;
+				return i;
+			}
+		}
+	}
+	return -1;
+}
+
+#define QOS_CHANGE_DEL	0xFC
+#define QOS_ADD		0xFD
+#define QOS_REPORT	0xFE
+
+void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
+{
+	struct nic *nic = nic_ptr;
+	u32 i, SFID, index, pos;
+	u8 subCmdEvt;
+	u8 len;
+	struct qos_cb_s *qcb = &nic->qos;
+	struct qos_entry_s *entry, *n;
+	struct list_head send_list;
+	struct list_head free_list;
+	unsigned long flags;
+
+	subCmdEvt = (u8)buf[4];
+
+	if (subCmdEvt == QOS_REPORT) {
+		len = (u8)buf[5];
+
+		spin_lock_irqsave(&qcb->qos_lock, flags);
+		for (i = 0; i < qcb->qos_list_cnt; i++) {
+			SFID = ((buf[(i*5)+6]<<24)&0xff000000);
+			SFID += ((buf[(i*5)+7]<<16)&0xff0000);
+			SFID += ((buf[(i*5)+8]<<8)&0xff00);
+			SFID += (buf[(i*5)+9]);
+			index = get_csr(qcb, SFID, 0);
+			if (index == -1) {
+				spin_unlock_irqrestore(&qcb->qos_lock, flags);
+				eprintk("QoS ERROR: No SF\n");
+				return;
+			}
+			qcb->csr[index].QoSBufCount = buf[(i*5)+10];
+		}
+
+		extract_qos_list(nic, &send_list);
+		spin_unlock_irqrestore(&qcb->qos_lock, flags);
+		send_qos_list(nic, &send_list);
+		return;
+	} else if (subCmdEvt == QOS_ADD) {
+		pos = 5;
+		len = (u8)buf[pos++];
+
+		SFID = ((buf[pos++]<<24)&0xff000000);
+		SFID += ((buf[pos++]<<16)&0xff0000);
+		SFID += ((buf[pos++]<<8)&0xff00);
+		SFID += (buf[pos++]);
+
+		index = get_csr(qcb, SFID, 1);
+		if (index == -1) {
+			eprintk("QoS ERROR: csr Update Error\n");
+			return;
+		}
+
+		dprintk("QOS_ADD SFID = 0x%x, index=%d\n", SFID, index);
+
+		spin_lock_irqsave(&qcb->qos_lock, flags);
+		qcb->csr[index].SFID = SFID;
+		qcb->csr[index].ClassifierRuleEnable = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].ClassifierRuleEnable += buf[pos++];
+		if (qcb->csr[index].ClassifierRuleEnable == 0)
+			qcb->qos_null_idx = index;
+		qcb->csr[index].IPToSMask = buf[pos++];
+		qcb->csr[index].IPToSLow = buf[pos++];
+		qcb->csr[index].IPToSHigh = buf[pos++];
+		qcb->csr[index].Protocol = buf[pos++];
+		qcb->csr[index].IPSrcAddrMask[0] = buf[pos++];
+		qcb->csr[index].IPSrcAddrMask[1] = buf[pos++];
+		qcb->csr[index].IPSrcAddrMask[2] = buf[pos++];
+		qcb->csr[index].IPSrcAddrMask[3] = buf[pos++];
+		qcb->csr[index].IPSrcAddr[0] = buf[pos++];
+		qcb->csr[index].IPSrcAddr[1] = buf[pos++];
+		qcb->csr[index].IPSrcAddr[2] = buf[pos++];
+		qcb->csr[index].IPSrcAddr[3] = buf[pos++];
+		qcb->csr[index].IPDstAddrMask[0] = buf[pos++];
+		qcb->csr[index].IPDstAddrMask[1] = buf[pos++];
+		qcb->csr[index].IPDstAddrMask[2] = buf[pos++];
+		qcb->csr[index].IPDstAddrMask[3] = buf[pos++];
+		qcb->csr[index].IPDstAddr[0] = buf[pos++];
+		qcb->csr[index].IPDstAddr[1] = buf[pos++];
+		qcb->csr[index].IPDstAddr[2] = buf[pos++];
+		qcb->csr[index].IPDstAddr[3] = buf[pos++];
+		qcb->csr[index].SrcPortLow = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].SrcPortLow += buf[pos++];
+		qcb->csr[index].SrcPortHigh = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].SrcPortHigh += buf[pos++];
+		qcb->csr[index].DstPortLow = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].DstPortLow += buf[pos++];
+		qcb->csr[index].DstPortHigh = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].DstPortHigh += buf[pos++];
+
+		qcb->qos_limit_size = 254/qcb->qos_list_cnt;
+		spin_unlock_irqrestore(&qcb->qos_lock, flags);
+	} else if (subCmdEvt == QOS_CHANGE_DEL) {
+		pos = 5;
+		len = (u8)buf[pos++];
+		SFID = ((buf[pos++]<<24)&0xff000000);
+		SFID += ((buf[pos++]<<16)&0xff0000);
+		SFID += ((buf[pos++]<<8)&0xff00);
+		SFID += (buf[pos++]);
+		index = get_csr(qcb, SFID, 1);
+		if (index == -1) {
+			eprintk("QoS ERROR: Wrong index(%d)\n", index);
+			return;
+		}
+
+		dprintk("QOS_CHANGE_DEL SFID = 0x%x, index=%d\n", SFID, index);
+
+		INIT_LIST_HEAD(&free_list);
+
+		spin_lock_irqsave(&qcb->qos_lock, flags);
+		qcb->csr[index].Enabled = 0;
+		qcb->qos_list_cnt--;
+		qcb->qos_limit_size = 254/qcb->qos_list_cnt;
+
+		list_for_each_entry_safe(entry, n, &qcb->qos_list[index],
+					list) {
+			list_move_tail(&entry->list, &free_list);
+		}
+		spin_unlock_irqrestore(&qcb->qos_lock, flags);
+		free_qos_entry_list(&free_list);
+	}
+}
diff --git a/drivers/staging/gdm72xx/gdm_qos.h b/drivers/staging/gdm72xx/gdm_qos.h
new file mode 100644
index 0000000..33f2bd4
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_qos.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#if !defined(GDM_QOS_H_20090403)
+#define GDM_QOS_H_20090403
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+
+#define BOOLEAN	u8
+
+#define QOS_MAX						16
+#define IPTYPEOFSERVICE				0x8000
+#define	PROTOCOL				0x4000
+#define	IPMASKEDSRCADDRESS			0x2000
+#define	IPMASKEDDSTADDRESS			0x1000
+#define	PROTOCOLSRCPORTRANGE		0x800
+#define	PROTOCOLDSTPORTRANGE		0x400
+#define	DSTMACADDR					0x200
+#define	SRCMACADDR					0x100
+#define	ETHERTYPE					0x80
+#define	IEEE802_1DUSERPRIORITY		0x40
+#define	IEEE802_1QVLANID			0x10
+
+struct gdm_wimax_csr_s {
+	/*	union{
+		U16 all;
+		struct _CS_CLASSIFIER_RULE_ENABLE{
+			IPTypeOfService:1,
+			Protocol:1,
+			IPMaskedSrcAddress:1,
+			IPMaskedDstAddress:1,
+			ProtocolSrcPortRange:1,
+			ProtocolDstPortRange:1,
+			DstMacAddr:1,
+			SrcMacAddr:1,
+			Ethertype:1,
+			IEEE802_1DUserPriority:1,
+			IEEE802_1QVLANID:1,
+			Reserved:5;
+		} fields;
+	} */
+	BOOLEAN		Enabled;
+	u32			SFID;
+	u8			QoSBufCount;
+	u16		ClassifierRuleEnable;
+	u8			IPToSLow;
+	u8			IPToSHigh;
+	u8			IPToSMask;
+	u8			Protocol;
+	u8			IPSrcAddr[16];
+	u8			IPSrcAddrMask[16];
+	u8			IPDstAddr[16];
+	u8			IPDstAddrMask[16];
+	u16		SrcPortLow;
+	u16		SrcPortHigh;
+	u16		DstPortLow;
+	u16		DstPortHigh;
+};
+
+struct qos_entry_s {
+	struct list_head list;
+	struct sk_buff *skb;
+	struct net_device *dev;
+
+};
+
+struct qos_cb_s {
+	struct list_head	qos_list[QOS_MAX];
+	u32			qos_list_cnt;
+	u32			qos_null_idx;
+	struct gdm_wimax_csr_s	csr[QOS_MAX];
+	spinlock_t	qos_lock;
+	u32			qos_limit_size;
+};
+
+void gdm_qos_init(void *nic_ptr);
+void gdm_qos_release_list(void *nic_ptr);
+int gdm_qos_send_hci_pkt(struct sk_buff *skb, struct net_device *dev);
+void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size);
+
+#endif
diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c
new file mode 100644
index 0000000..e1a3dd2
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_sdio.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include "gdm_sdio.h"
+#include "gdm_wimax.h"
+#include "sdio_boot.h"
+#include "hci.h"
+
+#define TYPE_A_HEADER_SIZE	4
+#define TYPE_A_LOOKAHEAD_SIZE	16
+
+#define MAX_NR_RX_BUF	4
+
+#define SDU_TX_BUF_SIZE	2048
+#define TX_BUF_SIZE		2048
+#define TX_CHUNK_SIZE	(2048 - TYPE_A_HEADER_SIZE)
+#define RX_BUF_SIZE		(25*1024)
+
+#define TX_HZ	2000
+#define TX_INTERVAL	(1000000/TX_HZ)
+
+/*#define DEBUG*/
+
+static int init_sdio(struct sdiowm_dev *sdev);
+static void release_sdio(struct sdiowm_dev *sdev);
+
+#ifdef DEBUG
+static void hexdump(char *title, u8 *data, int len)
+{
+	int i;
+
+	printk(KERN_DEBUG "%s: length = %d\n", title, len);
+	for (i = 0; i < len; i++) {
+		printk(KERN_DEBUG "%02x ", data[i]);
+		if ((i & 0xf) == 0xf)
+			printk(KERN_DEBUG "\n");
+	}
+	printk(KERN_DEBUG "\n");
+}
+#endif
+
+static struct sdio_tx *alloc_tx_struct(struct tx_cxt *tx)
+{
+	struct sdio_tx *t = NULL;
+
+	t = kmalloc(sizeof(*t), GFP_ATOMIC);
+	if (t == NULL)
+		goto out;
+
+	memset(t, 0, sizeof(*t));
+
+	t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC);
+	if (t->buf == NULL)
+		goto out;
+
+	t->tx_cxt = tx;
+
+	return t;
+out:
+	if (t) {
+		kfree(t->buf);
+		kfree(t);
+	}
+	return NULL;
+}
+
+static void free_tx_struct(struct sdio_tx *t)
+{
+	if (t) {
+		kfree(t->buf);
+		kfree(t);
+	}
+}
+
+static struct sdio_rx *alloc_rx_struct(struct rx_cxt *rx)
+{
+	struct sdio_rx *r = NULL;
+
+	r = kmalloc(sizeof(*r), GFP_ATOMIC);
+	if (r == NULL)
+		goto out;
+
+	memset(r, 0, sizeof(*r));
+
+	r->rx_cxt = rx;
+
+	return r;
+out:
+	kfree(r);
+	return NULL;
+}
+
+static void free_rx_struct(struct sdio_rx *r)
+{
+	kfree(r);
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct sdio_tx *get_tx_struct(struct tx_cxt *tx, int *no_spc)
+{
+	struct sdio_tx *t;
+
+	if (list_empty(&tx->free_list))
+		return NULL;
+
+	t = list_entry(tx->free_list.prev, struct sdio_tx, list);
+	list_del(&t->list);
+
+	*no_spc = list_empty(&tx->free_list) ? 1 : 0;
+
+	return t;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_tx_struct(struct tx_cxt *tx, struct sdio_tx *t)
+{
+	list_add_tail(&t->list, &tx->free_list);
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct sdio_rx *get_rx_struct(struct rx_cxt *rx)
+{
+	struct sdio_rx *r;
+
+	if (list_empty(&rx->free_list))
+		return NULL;
+
+	r = list_entry(rx->free_list.prev, struct sdio_rx, list);
+	list_del(&r->list);
+
+	return r;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_rx_struct(struct rx_cxt *rx, struct sdio_rx *r)
+{
+	list_add_tail(&r->list, &rx->free_list);
+}
+
+static int init_sdio(struct sdiowm_dev *sdev)
+{
+	int ret = 0, i;
+	struct tx_cxt	*tx = &sdev->tx;
+	struct rx_cxt	*rx = &sdev->rx;
+	struct sdio_tx	*t;
+	struct sdio_rx	*r;
+
+	INIT_LIST_HEAD(&tx->free_list);
+	INIT_LIST_HEAD(&tx->sdu_list);
+	INIT_LIST_HEAD(&tx->hci_list);
+
+	spin_lock_init(&tx->lock);
+
+	tx->sdu_buf = kmalloc(SDU_TX_BUF_SIZE, GFP_KERNEL);
+	if (tx->sdu_buf == NULL) {
+		printk(KERN_ERR "Failed to allocate SDU tx buffer.\n");
+		goto fail;
+	}
+
+	for (i = 0; i < MAX_NR_SDU_BUF; i++) {
+		t = alloc_tx_struct(tx);
+		if (t == NULL) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		list_add(&t->list, &tx->free_list);
+	}
+
+	INIT_LIST_HEAD(&rx->free_list);
+	INIT_LIST_HEAD(&rx->req_list);
+
+	spin_lock_init(&rx->lock);
+
+	for (i = 0; i < MAX_NR_RX_BUF; i++) {
+		r = alloc_rx_struct(rx);
+		if (r == NULL) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		list_add(&r->list, &rx->free_list);
+	}
+
+	rx->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
+	if (rx->rx_buf == NULL) {
+		printk(KERN_ERR "Failed to allocate rx buffer.\n");
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	release_sdio(sdev);
+	return ret;
+}
+
+static void release_sdio(struct sdiowm_dev *sdev)
+{
+	struct tx_cxt	*tx = &sdev->tx;
+	struct rx_cxt	*rx = &sdev->rx;
+	struct sdio_tx	*t, *t_next;
+	struct sdio_rx	*r, *r_next;
+
+	kfree(tx->sdu_buf);
+
+	list_for_each_entry_safe(t, t_next, &tx->free_list, list) {
+		list_del(&t->list);
+		free_tx_struct(t);
+	}
+
+	list_for_each_entry_safe(t, t_next, &tx->sdu_list, list) {
+		list_del(&t->list);
+		free_tx_struct(t);
+	}
+
+	list_for_each_entry_safe(t, t_next, &tx->hci_list, list) {
+		list_del(&t->list);
+		free_tx_struct(t);
+	}
+
+	kfree(rx->rx_buf);
+
+	list_for_each_entry_safe(r, r_next, &rx->free_list, list) {
+		list_del(&r->list);
+		free_rx_struct(r);
+	}
+
+	list_for_each_entry_safe(r, r_next, &rx->req_list, list) {
+		list_del(&r->list);
+		free_rx_struct(r);
+	}
+}
+
+static void send_sdio_pkt(struct sdio_func *func, u8 *data, int len)
+{
+	int n, blocks, ret, remain;
+
+	sdio_claim_host(func);
+
+	blocks = len / func->cur_blksize;
+	n = blocks * func->cur_blksize;
+	if (blocks) {
+		ret = sdio_memcpy_toio(func, 0, data, n);
+		if (ret < 0) {
+			if (ret != -ENOMEDIUM)
+				printk(KERN_ERR "gdmwms: %s error: ret = %d\n",
+					__func__, ret);
+			goto end_io;
+		}
+	}
+
+	remain = len - n;
+	remain = (remain + 3) & ~3;
+
+	if (remain) {
+		ret = sdio_memcpy_toio(func, 0, data + n, remain);
+		if (ret < 0) {
+			if (ret != -ENOMEDIUM)
+				printk(KERN_ERR "gdmwms: %s error: ret = %d\n",
+					__func__, ret);
+			goto end_io;
+		}
+	}
+
+end_io:
+	sdio_release_host(func);
+}
+
+static void send_sdu(struct sdio_func *func, struct tx_cxt *tx)
+{
+	struct list_head *l, *next;
+	struct hci_s *hci;
+	struct sdio_tx *t;
+	int pos, len, i, estlen, aggr_num = 0, aggr_len;
+	u8 *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tx->lock, flags);
+
+	pos = TYPE_A_HEADER_SIZE + HCI_HEADER_SIZE;
+	list_for_each_entry(t, &tx->sdu_list, list) {
+		estlen = ((t->len + 3) & ~3) + 4;
+		if ((pos + estlen) > SDU_TX_BUF_SIZE)
+			break;
+
+		aggr_num++;
+		memcpy(tx->sdu_buf + pos, t->buf, t->len);
+		memset(tx->sdu_buf + pos + t->len, 0, estlen - t->len);
+		pos += estlen;
+	}
+	aggr_len = pos;
+
+	hci = (struct hci_s *)(tx->sdu_buf + TYPE_A_HEADER_SIZE);
+	hci->cmd_evt = H2B(WIMAX_TX_SDU_AGGR);
+	hci->length = H2B(aggr_len - TYPE_A_HEADER_SIZE - HCI_HEADER_SIZE);
+
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+#ifdef DEBUG
+	hexdump("sdio_send", tx->sdu_buf + TYPE_A_HEADER_SIZE,
+		aggr_len - TYPE_A_HEADER_SIZE);
+#endif
+
+	for (pos = TYPE_A_HEADER_SIZE; pos < aggr_len; pos += TX_CHUNK_SIZE) {
+		len = aggr_len - pos;
+		len = len > TX_CHUNK_SIZE ? TX_CHUNK_SIZE : len;
+		buf = tx->sdu_buf + pos - TYPE_A_HEADER_SIZE;
+
+		buf[0] = len & 0xff;
+		buf[1] = (len >> 8) & 0xff;
+		buf[2] = (len >> 16) & 0xff;
+		buf[3] = (pos + len) >= aggr_len ? 0 : 1;
+		send_sdio_pkt(func, buf, len + TYPE_A_HEADER_SIZE);
+	}
+
+	spin_lock_irqsave(&tx->lock, flags);
+
+	for (l = tx->sdu_list.next, i = 0; i < aggr_num; i++, l = next) {
+		next = l->next;
+		t = list_entry(l, struct sdio_tx, list);
+		if (t->callback)
+			t->callback(t->cb_data);
+
+		list_del(l);
+		put_tx_struct(t->tx_cxt, t);
+	}
+
+	do_gettimeofday(&tx->sdu_stamp);
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static void send_hci(struct sdio_func *func, struct tx_cxt *tx,
+			struct sdio_tx *t)
+{
+	unsigned long flags;
+
+#ifdef DEBUG
+	hexdump("sdio_send", t->buf + TYPE_A_HEADER_SIZE,
+		t->len - TYPE_A_HEADER_SIZE);
+#endif
+	send_sdio_pkt(func, t->buf, t->len);
+
+	spin_lock_irqsave(&tx->lock, flags);
+	if (t->callback)
+		t->callback(t->cb_data);
+	free_tx_struct(t);
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static void do_tx(struct work_struct *work)
+{
+	struct sdiowm_dev *sdev = container_of(work, struct sdiowm_dev, ws);
+	struct sdio_func *func = sdev->func;
+	struct tx_cxt *tx = &sdev->tx;
+	struct sdio_tx *t = NULL;
+	struct timeval now, *before;
+	int is_sdu = 0;
+	long diff;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	if (!tx->can_send) {
+		spin_unlock_irqrestore(&tx->lock, flags);
+		return;
+	}
+
+	if (!list_empty(&tx->hci_list)) {
+		t = list_entry(tx->hci_list.next, struct sdio_tx, list);
+		list_del(&t->list);
+		is_sdu = 0;
+	} else if (!tx->stop_sdu_tx && !list_empty(&tx->sdu_list)) {
+		do_gettimeofday(&now);
+		before = &tx->sdu_stamp;
+
+		diff = (now.tv_sec - before->tv_sec) * 1000000 +
+			(now.tv_usec - before->tv_usec);
+		if (diff >= 0 && diff < TX_INTERVAL) {
+			schedule_work(&sdev->ws);
+			spin_unlock_irqrestore(&tx->lock, flags);
+			return;
+		}
+		is_sdu = 1;
+	}
+
+	if (!is_sdu && t == NULL) {
+		spin_unlock_irqrestore(&tx->lock, flags);
+		return;
+	}
+
+	tx->can_send = 0;
+
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	if (is_sdu)
+		send_sdu(func, tx);
+	else
+		send_hci(func, tx, t);
+}
+
+static int gdm_sdio_send(void *priv_dev, void *data, int len,
+			void (*cb)(void *data), void *cb_data)
+{
+	struct sdiowm_dev *sdev = priv_dev;
+	struct tx_cxt *tx = &sdev->tx;
+	struct sdio_tx *t;
+	u8 *pkt = data;
+	int no_spc = 0;
+	u16 cmd_evt;
+	unsigned long flags;
+
+	BUG_ON(len > TX_BUF_SIZE - TYPE_A_HEADER_SIZE);
+
+	spin_lock_irqsave(&tx->lock, flags);
+
+	cmd_evt = (pkt[0] << 8) | pkt[1];
+	if (cmd_evt == WIMAX_TX_SDU) {
+		t = get_tx_struct(tx, &no_spc);
+		if (t == NULL) {
+			/* This case must not happen. */
+			spin_unlock_irqrestore(&tx->lock, flags);
+			return -ENOSPC;
+		}
+		list_add_tail(&t->list, &tx->sdu_list);
+
+		memcpy(t->buf, data, len);
+
+		t->len = len;
+		t->callback = cb;
+		t->cb_data = cb_data;
+	} else {
+		t = alloc_tx_struct(tx);
+		if (t == NULL) {
+			spin_unlock_irqrestore(&tx->lock, flags);
+			return -ENOMEM;
+		}
+		list_add_tail(&t->list, &tx->hci_list);
+
+		t->buf[0] = len & 0xff;
+		t->buf[1] = (len >> 8) & 0xff;
+		t->buf[2] = (len >> 16) & 0xff;
+		t->buf[3] = 2;
+		memcpy(t->buf + TYPE_A_HEADER_SIZE, data, len);
+
+		t->len = len + TYPE_A_HEADER_SIZE;
+		t->callback = cb;
+		t->cb_data = cb_data;
+	}
+
+	if (tx->can_send)
+		schedule_work(&sdev->ws);
+
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	if (no_spc)
+		return -ENOSPC;
+
+	return 0;
+}
+
+/*
+ * Handle the HCI, WIMAX_SDU_TX_FLOW.
+ */
+static int control_sdu_tx_flow(struct sdiowm_dev *sdev, u8 *hci_data, int len)
+{
+	struct tx_cxt *tx = &sdev->tx;
+	u16 cmd_evt;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tx->lock, flags);
+
+	cmd_evt = (hci_data[0] << 8) | (hci_data[1]);
+	if (cmd_evt != WIMAX_SDU_TX_FLOW)
+		goto out;
+
+	if (hci_data[4] == 0) {
+#ifdef DEBUG
+		printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n");
+#endif
+		tx->stop_sdu_tx = 1;
+	} else if (hci_data[4] == 1) {
+#ifdef DEBUG
+		printk(KERN_DEBUG "WIMAX ==> START SDU TX\n");
+#endif
+		tx->stop_sdu_tx = 0;
+		if (tx->can_send)
+			schedule_work(&sdev->ws);
+		/*
+		 * If free buffer for sdu tx doesn't exist, then tx queue
+		 * should not be woken. For this reason, don't pass the command,
+		 * START_SDU_TX.
+		 */
+		if (list_empty(&tx->free_list))
+			len = 0;
+	}
+
+out:
+	spin_unlock_irqrestore(&tx->lock, flags);
+	return len;
+}
+
+static void gdm_sdio_irq(struct sdio_func *func)
+{
+	struct phy_dev *phy_dev = sdio_get_drvdata(func);
+	struct sdiowm_dev *sdev = phy_dev->priv_dev;
+	struct tx_cxt *tx = &sdev->tx;
+	struct rx_cxt *rx = &sdev->rx;
+	struct sdio_rx *r;
+	unsigned long flags;
+	u8 val, hdr[TYPE_A_LOOKAHEAD_SIZE], *buf;
+	u32 len, blocks, n;
+	int ret, remain;
+
+	/* Check interrupt */
+	val = sdio_readb(func, 0x13, &ret);
+	if (val & 0x01)
+		sdio_writeb(func, 0x01, 0x13, &ret);	/* clear interrupt */
+	else
+		return;
+
+	ret = sdio_memcpy_fromio(func, hdr, 0x0, TYPE_A_LOOKAHEAD_SIZE);
+	if (ret) {
+		printk(KERN_ERR "Cannot read from function %d\n", func->num);
+		goto done;
+	}
+
+	len = (hdr[2] << 16) | (hdr[1] << 8) | hdr[0];
+	if (len > (RX_BUF_SIZE - TYPE_A_HEADER_SIZE)) {
+		printk(KERN_ERR "Too big Type-A size: %d\n", len);
+		goto done;
+	}
+
+	if (hdr[3] == 1) {	/* Ack */
+#ifdef DEBUG
+		u32 *ack_seq = (u32 *)&hdr[4];
+#endif
+		spin_lock_irqsave(&tx->lock, flags);
+		tx->can_send = 1;
+
+		if (!list_empty(&tx->sdu_list) || !list_empty(&tx->hci_list))
+			schedule_work(&sdev->ws);
+		spin_unlock_irqrestore(&tx->lock, flags);
+#ifdef DEBUG
+		printk(KERN_DEBUG "Ack... %0x\n", ntohl(*ack_seq));
+#endif
+		goto done;
+	}
+
+	memcpy(rx->rx_buf, hdr + TYPE_A_HEADER_SIZE,
+			TYPE_A_LOOKAHEAD_SIZE - TYPE_A_HEADER_SIZE);
+
+	buf = rx->rx_buf + TYPE_A_LOOKAHEAD_SIZE - TYPE_A_HEADER_SIZE;
+	remain = len - TYPE_A_LOOKAHEAD_SIZE + TYPE_A_HEADER_SIZE;
+	if (remain <= 0)
+		goto end_io;
+
+	blocks = remain / func->cur_blksize;
+
+	if (blocks) {
+		n = blocks * func->cur_blksize;
+		ret = sdio_memcpy_fromio(func, buf, 0x0, n);
+		if (ret) {
+			printk(KERN_ERR "Cannot read from function %d\n",
+				func->num);
+			goto done;
+		}
+		buf += n;
+		remain -= n;
+	}
+
+	if (remain) {
+		ret = sdio_memcpy_fromio(func, buf, 0x0, remain);
+		if (ret) {
+			printk(KERN_ERR "Cannot read from function %d\n",
+				func->num);
+			goto done;
+		}
+	}
+
+end_io:
+#ifdef DEBUG
+	hexdump("sdio_receive", rx->rx_buf, len);
+#endif
+	len = control_sdu_tx_flow(sdev, rx->rx_buf, len);
+
+	spin_lock_irqsave(&rx->lock, flags);
+
+	if (!list_empty(&rx->req_list)) {
+		r = list_entry(rx->req_list.next, struct sdio_rx, list);
+		spin_unlock_irqrestore(&rx->lock, flags);
+		if (r->callback)
+			r->callback(r->cb_data, rx->rx_buf, len);
+		spin_lock_irqsave(&rx->lock, flags);
+		list_del(&r->list);
+		put_rx_struct(rx, r);
+	}
+
+	spin_unlock_irqrestore(&rx->lock, flags);
+
+done:
+	sdio_writeb(func, 0x00, 0x10, &ret);	/* PCRRT */
+	if (!phy_dev->netdev)
+		register_wimax_device(phy_dev, &func->dev);
+}
+
+static int gdm_sdio_receive(void *priv_dev,
+				void (*cb)(void *cb_data, void *data, int len),
+				void *cb_data)
+{
+	struct sdiowm_dev *sdev = priv_dev;
+	struct rx_cxt *rx = &sdev->rx;
+	struct sdio_rx *r;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rx->lock, flags);
+	r = get_rx_struct(rx);
+	if (r == NULL) {
+		spin_unlock_irqrestore(&rx->lock, flags);
+		return -ENOMEM;
+	}
+
+	r->callback = cb;
+	r->cb_data = cb_data;
+
+	list_add_tail(&r->list, &rx->req_list);
+	spin_unlock_irqrestore(&rx->lock, flags);
+
+	return 0;
+}
+
+static int sdio_wimax_probe(struct sdio_func *func,
+				const struct sdio_device_id *id)
+{
+	int ret;
+	struct phy_dev *phy_dev = NULL;
+	struct sdiowm_dev *sdev = NULL;
+
+	printk(KERN_INFO "Found GDM SDIO VID = 0x%04x PID = 0x%04x...\n",
+			func->vendor, func->device);
+	printk(KERN_INFO "GCT WiMax driver version %s\n", DRIVER_VERSION);
+
+	sdio_claim_host(func);
+	sdio_enable_func(func);
+	sdio_claim_irq(func, gdm_sdio_irq);
+
+	ret = sdio_boot(func);
+	if (ret)
+		return ret;
+
+	phy_dev = kmalloc(sizeof(*phy_dev), GFP_KERNEL);
+	if (phy_dev == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	sdev = kmalloc(sizeof(*sdev), GFP_KERNEL);
+	if (sdev == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(phy_dev, 0, sizeof(*phy_dev));
+	memset(sdev, 0, sizeof(*sdev));
+
+	phy_dev->priv_dev = (void *)sdev;
+	phy_dev->send_func = gdm_sdio_send;
+	phy_dev->rcv_func = gdm_sdio_receive;
+
+	ret = init_sdio(sdev);
+	if (sdev < 0)
+		goto out;
+
+	sdev->func = func;
+
+	sdio_writeb(func, 1, 0x14, &ret);	/* Enable interrupt */
+	sdio_release_host(func);
+
+	INIT_WORK(&sdev->ws, do_tx);
+
+	sdio_set_drvdata(func, phy_dev);
+out:
+	if (ret) {
+		kfree(phy_dev);
+		kfree(sdev);
+	}
+
+	return ret;
+}
+
+static void sdio_wimax_remove(struct sdio_func *func)
+{
+	struct phy_dev *phy_dev = sdio_get_drvdata(func);
+	struct sdiowm_dev *sdev = phy_dev->priv_dev;
+
+	if (phy_dev->netdev)
+		unregister_wimax_device(phy_dev);
+	sdio_claim_host(func);
+	sdio_release_irq(func);
+	sdio_disable_func(func);
+	sdio_release_host(func);
+	release_sdio(sdev);
+
+	kfree(sdev);
+	kfree(phy_dev);
+}
+
+static const struct sdio_device_id sdio_wimax_ids[] = {
+	{ SDIO_DEVICE(0x0296, 0x5347) },
+	{0}
+};
+
+MODULE_DEVICE_TABLE(sdio, sdio_wimax_ids);
+
+static struct sdio_driver sdio_wimax_driver = {
+	.probe		= sdio_wimax_probe,
+	.remove		= sdio_wimax_remove,
+	.name		= "sdio_wimax",
+	.id_table	= sdio_wimax_ids,
+};
+
+static int __init sdio_gdm_wimax_init(void)
+{
+	return sdio_register_driver(&sdio_wimax_driver);
+}
+
+static void __exit sdio_gdm_wimax_exit(void)
+{
+	sdio_unregister_driver(&sdio_wimax_driver);
+}
+
+module_init(sdio_gdm_wimax_init);
+module_exit(sdio_gdm_wimax_exit);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("GCT WiMax SDIO Device Driver");
+MODULE_AUTHOR("Ethan Park");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm72xx/gdm_sdio.h b/drivers/staging/gdm72xx/gdm_sdio.h
new file mode 100644
index 0000000..216e98f
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_sdio.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __GDM_SDIO_H__
+#define __GDM_SDIO_H__
+
+#include <linux/types.h>
+#include <linux/time.h>
+
+#define MAX_NR_SDU_BUF  64
+
+struct sdio_tx {
+	struct list_head	list;
+	struct tx_cxt		*tx_cxt;
+
+	u8	*buf;
+	int	len;
+
+	void (*callback)(void *cb_data);
+	void *cb_data;
+};
+
+struct tx_cxt {
+	struct list_head	free_list;
+	struct list_head	sdu_list;
+	struct list_head	hci_list;
+	struct timeval		sdu_stamp;
+
+	u8	*sdu_buf;
+
+	spinlock_t			lock;
+	int	can_send;
+	int stop_sdu_tx;
+};
+
+struct sdio_rx {
+	struct list_head	list;
+	struct rx_cxt		*rx_cxt;
+
+	void (*callback)(void *cb_data, void *data, int len);
+	void *cb_data;
+};
+
+struct rx_cxt {
+	struct list_head	free_list;
+	struct list_head	req_list;
+
+	u8		*rx_buf;
+
+	spinlock_t			lock;
+};
+
+struct sdiowm_dev {
+	struct sdio_func	*func;
+
+	struct tx_cxt	tx;
+	struct rx_cxt	rx;
+
+	struct work_struct	ws;
+};
+
+#endif /* __GDM_SDIO_H__ */
diff --git a/drivers/staging/gdm72xx/gdm_usb.c b/drivers/staging/gdm72xx/gdm_usb.c
new file mode 100644
index 0000000..1e9dc0d
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_usb.c
@@ -0,0 +1,798 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <asm/byteorder.h>
+
+#include "gdm_usb.h"
+#include "gdm_wimax.h"
+#include "usb_boot.h"
+#include "hci.h"
+
+#include "usb_ids.h"
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+#define TX_BUF_SIZE	2048
+#if defined(CONFIG_WIMAX_GDM72XX_WIMAX2)
+#define RX_BUF_SIZE	(128*1024)	/* For packet aggregation */
+#else
+#define RX_BUF_SIZE	2048
+#endif
+
+#define GDM7205_PADDING		256
+
+#define H2B(x)		__cpu_to_be16(x)
+#define B2H(x)		__be16_to_cpu(x)
+#define DB2H(x)		__be32_to_cpu(x)
+
+#define DOWNLOAD_CONF_VALUE		0x21
+
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+
+static DECLARE_WAIT_QUEUE_HEAD(k_wait);
+static LIST_HEAD(k_list);
+static DEFINE_SPINLOCK(k_lock);
+static int k_mode_stop;
+
+#define K_WAIT_TIME	(2 * HZ / 100)
+
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+
+static int init_usb(struct usbwm_dev *udev);
+static void release_usb(struct usbwm_dev *udev);
+
+/*#define DEBUG */
+#ifdef DEBUG
+static void hexdump(char *title, u8 *data, int len)
+{
+	int i;
+
+	printk(KERN_DEBUG "%s: length = %d\n", title, len);
+	for (i = 0; i < len; i++) {
+		printk(KERN_DEBUG "%02x ", data[i]);
+		if ((i & 0xf) == 0xf)
+			printk(KERN_DEBUG "\n");
+	}
+	printk(KERN_DEBUG "\n");
+}
+#endif
+
+static struct usb_tx *alloc_tx_struct(struct tx_cxt *tx)
+{
+	struct usb_tx *t = NULL;
+
+	t = kmalloc(sizeof(*t), GFP_ATOMIC);
+	if (t == NULL)
+		goto out;
+
+	memset(t, 0, sizeof(*t));
+
+	t->urb = usb_alloc_urb(0, GFP_ATOMIC);
+	t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC);
+	if (t->urb == NULL || t->buf == NULL)
+		goto out;
+
+	t->tx_cxt = tx;
+
+	return t;
+out:
+	if (t) {
+		usb_free_urb(t->urb);
+		kfree(t->buf);
+		kfree(t);
+	}
+	return NULL;
+}
+
+static void free_tx_struct(struct usb_tx *t)
+{
+	if (t) {
+		usb_free_urb(t->urb);
+		kfree(t->buf);
+		kfree(t);
+	}
+}
+
+static struct usb_rx *alloc_rx_struct(struct rx_cxt *rx)
+{
+	struct usb_rx *r = NULL;
+
+	r = kmalloc(sizeof(*r), GFP_ATOMIC);
+	if (r == NULL)
+		goto out;
+
+	memset(r, 0, sizeof(*r));
+
+	r->urb = usb_alloc_urb(0, GFP_ATOMIC);
+	r->buf = kmalloc(RX_BUF_SIZE, GFP_ATOMIC);
+	if (r->urb == NULL || r->buf == NULL)
+		goto out;
+
+	r->rx_cxt = rx;
+	return r;
+out:
+	if (r) {
+		usb_free_urb(r->urb);
+		kfree(r->buf);
+		kfree(r);
+	}
+	return NULL;
+}
+
+static void free_rx_struct(struct usb_rx *r)
+{
+	if (r) {
+		usb_free_urb(r->urb);
+		kfree(r->buf);
+		kfree(r);
+	}
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct usb_tx *get_tx_struct(struct tx_cxt *tx, int *no_spc)
+{
+	struct usb_tx *t;
+
+	if (list_empty(&tx->free_list)) {
+		*no_spc = 1;
+		return NULL;
+	}
+
+	t = list_entry(tx->free_list.next, struct usb_tx, list);
+	list_del(&t->list);
+
+	*no_spc = list_empty(&tx->free_list) ? 1 : 0;
+
+	return t;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_tx_struct(struct tx_cxt *tx, struct usb_tx *t)
+{
+	list_add_tail(&t->list, &tx->free_list);
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct usb_rx *get_rx_struct(struct rx_cxt *rx)
+{
+	struct usb_rx *r;
+
+	if (list_empty(&rx->free_list)) {
+		r = alloc_rx_struct(rx);
+		if (r == NULL)
+			return NULL;
+
+		list_add(&r->list, &rx->free_list);
+	}
+
+	r = list_entry(rx->free_list.next, struct usb_rx, list);
+	list_del(&r->list);
+	list_add_tail(&r->list, &rx->used_list);
+
+	return r;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r)
+{
+	list_del(&r->list);
+	list_add(&r->list, &rx->free_list);
+}
+
+static int init_usb(struct usbwm_dev *udev)
+{
+	int ret = 0, i;
+	struct tx_cxt	*tx = &udev->tx;
+	struct rx_cxt	*rx = &udev->rx;
+	struct usb_tx	*t;
+	struct usb_rx	*r;
+
+	INIT_LIST_HEAD(&tx->free_list);
+	INIT_LIST_HEAD(&tx->sdu_list);
+	INIT_LIST_HEAD(&tx->hci_list);
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+	INIT_LIST_HEAD(&tx->pending_list);
+#endif
+
+	INIT_LIST_HEAD(&rx->free_list);
+	INIT_LIST_HEAD(&rx->used_list);
+
+	spin_lock_init(&tx->lock);
+	spin_lock_init(&rx->lock);
+
+	for (i = 0; i < MAX_NR_SDU_BUF; i++) {
+		t = alloc_tx_struct(tx);
+		if (t == NULL) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		list_add(&t->list, &tx->free_list);
+	}
+
+	r = alloc_rx_struct(rx);
+	if (r == NULL) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	list_add(&r->list, &rx->free_list);
+	return ret;
+
+fail:
+	release_usb(udev);
+	return ret;
+}
+
+static void release_usb(struct usbwm_dev *udev)
+{
+	struct tx_cxt	*tx = &udev->tx;
+	struct rx_cxt	*rx = &udev->rx;
+	struct usb_tx	*t, *t_next;
+	struct usb_rx	*r, *r_next;
+
+	list_for_each_entry_safe(t, t_next, &tx->sdu_list, list) {
+		list_del(&t->list);
+		free_tx_struct(t);
+	}
+
+	list_for_each_entry_safe(t, t_next, &tx->hci_list, list) {
+		list_del(&t->list);
+		free_tx_struct(t);
+	}
+
+	list_for_each_entry_safe(t, t_next, &tx->free_list, list) {
+		list_del(&t->list);
+		free_tx_struct(t);
+	}
+
+	list_for_each_entry_safe(r, r_next, &rx->free_list, list) {
+		list_del(&r->list);
+		free_rx_struct(r);
+	}
+
+	list_for_each_entry_safe(r, r_next, &rx->used_list, list) {
+		list_del(&r->list);
+		free_rx_struct(r);
+	}
+}
+
+static void gdm_usb_send_complete(struct urb *urb)
+{
+	struct usb_tx *t = urb->context;
+	struct tx_cxt *tx = t->tx_cxt;
+	u8 *pkt = t->buf;
+	u16 cmd_evt;
+	unsigned long flags;
+
+	/* Completion by usb_unlink_urb */
+	if (urb->status == -ECONNRESET)
+		return;
+
+	spin_lock_irqsave(&tx->lock, flags);
+
+	if (t->callback)
+		t->callback(t->cb_data);
+
+	/* Delete from sdu list or hci list. */
+	list_del(&t->list);
+
+	cmd_evt = (pkt[0] << 8) | pkt[1];
+	if (cmd_evt == WIMAX_TX_SDU)
+		put_tx_struct(tx, t);
+	else
+		free_tx_struct(t);
+
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static int gdm_usb_send(void *priv_dev, void *data, int len,
+			void (*cb)(void *data), void *cb_data)
+{
+	struct usbwm_dev *udev = priv_dev;
+	struct usb_device *usbdev = udev->usbdev;
+	struct tx_cxt *tx = &udev->tx;
+	struct usb_tx *t;
+	int padding = udev->padding;
+	int no_spc = 0, ret;
+	u8 *pkt = data;
+	u16 cmd_evt;
+	unsigned long flags;
+
+	if (!udev->usbdev) {
+		printk(KERN_ERR "%s: No such device\n", __func__);
+		return -ENODEV;
+	}
+
+	BUG_ON(len > TX_BUF_SIZE - padding - 1);
+
+	spin_lock_irqsave(&tx->lock, flags);
+
+	cmd_evt = (pkt[0] << 8) | pkt[1];
+	if (cmd_evt == WIMAX_TX_SDU) {
+		t = get_tx_struct(tx, &no_spc);
+		if (t == NULL) {
+			/* This case must not happen. */
+			spin_unlock_irqrestore(&tx->lock, flags);
+			return -ENOSPC;
+		}
+		list_add_tail(&t->list, &tx->sdu_list);
+	} else {
+		t = alloc_tx_struct(tx);
+		if (t == NULL) {
+			spin_unlock_irqrestore(&tx->lock, flags);
+			return -ENOMEM;
+		}
+		list_add_tail(&t->list, &tx->hci_list);
+	}
+
+	memcpy(t->buf + padding, data, len);
+	t->callback = cb;
+	t->cb_data = cb_data;
+
+	/*
+	 * In some cases, USB Module of WiMax is blocked when data size is
+	 * the multiple of 512. So, increment length by one in that case.
+	 */
+	if ((len % 512) == 0)
+		len++;
+
+	usb_fill_bulk_urb(t->urb,
+			usbdev,
+			usb_sndbulkpipe(usbdev, 1),
+			t->buf,
+			len + padding,
+			gdm_usb_send_complete,
+			t);
+
+#ifdef DEBUG
+	hexdump("usb_send", t->buf, len + padding);
+#endif
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+	if (usbdev->state & USB_STATE_SUSPENDED) {
+		list_add_tail(&t->p_list, &tx->pending_list);
+		schedule_work(&udev->pm_ws);
+		goto out;
+	}
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+	if (udev->bw_switch) {
+		list_add_tail(&t->p_list, &tx->pending_list);
+		goto out;
+	} else if (cmd_evt == WIMAX_SCAN) {
+		struct rx_cxt *rx;
+		struct usb_rx *r;
+
+		rx = &udev->rx;
+
+		list_for_each_entry(r, &rx->used_list, list)
+			usb_unlink_urb(r->urb);
+		udev->bw_switch = 1;
+
+		spin_lock(&k_lock);
+		list_add_tail(&udev->list, &k_list);
+		spin_unlock(&k_lock);
+
+		wake_up(&k_wait);
+	}
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+
+	ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+	if (ret)
+		goto send_fail;
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+	usb_mark_last_busy(usbdev);
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+out:
+#endif
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	if (no_spc)
+		return -ENOSPC;
+
+	return 0;
+
+send_fail:
+	t->callback = NULL;
+	gdm_usb_send_complete(t->urb);
+	spin_unlock_irqrestore(&tx->lock, flags);
+	return ret;
+}
+
+static void gdm_usb_rcv_complete(struct urb *urb)
+{
+	struct usb_rx *r = urb->context;
+	struct rx_cxt *rx = r->rx_cxt;
+	struct usbwm_dev *udev = container_of(r->rx_cxt, struct usbwm_dev, rx);
+	struct tx_cxt *tx = &udev->tx;
+	struct usb_tx *t;
+	u16 cmd_evt;
+	unsigned long flags;
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+	struct usb_device *dev = urb->dev;
+#endif
+
+	/* Completion by usb_unlink_urb */
+	if (urb->status == -ECONNRESET)
+		return;
+
+	spin_lock_irqsave(&tx->lock, flags);
+
+	if (!urb->status) {
+		cmd_evt = (r->buf[0] << 8) | (r->buf[1]);
+#ifdef DEBUG
+		hexdump("usb_receive", r->buf, urb->actual_length);
+#endif
+		if (cmd_evt == WIMAX_SDU_TX_FLOW) {
+			if (r->buf[4] == 0) {
+#ifdef DEBUG
+				printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n");
+#endif
+				list_for_each_entry(t, &tx->sdu_list, list)
+					usb_unlink_urb(t->urb);
+			} else if (r->buf[4] == 1) {
+#ifdef DEBUG
+				printk(KERN_DEBUG "WIMAX ==> START SDU TX\n");
+#endif
+				list_for_each_entry(t, &tx->sdu_list, list) {
+					usb_submit_urb(t->urb, GFP_ATOMIC);
+				}
+				/*
+				 * If free buffer for sdu tx doesn't
+				 * exist, then tx queue should not be
+				 * woken. For this reason, don't pass
+				 * the command, START_SDU_TX.
+				 */
+				if (list_empty(&tx->free_list))
+					urb->actual_length = 0;
+			}
+		}
+	}
+
+	if (!urb->status && r->callback)
+		r->callback(r->cb_data, r->buf, urb->actual_length);
+
+	spin_lock(&rx->lock);
+	put_rx_struct(rx, r);
+	spin_unlock(&rx->lock);
+
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+	usb_mark_last_busy(dev);
+#endif
+}
+
+static int gdm_usb_receive(void *priv_dev,
+			void (*cb)(void *cb_data, void *data, int len),
+			void *cb_data)
+{
+	struct usbwm_dev *udev = priv_dev;
+	struct usb_device *usbdev = udev->usbdev;
+	struct rx_cxt *rx = &udev->rx;
+	struct usb_rx *r;
+	unsigned long flags;
+
+	if (!udev->usbdev) {
+		printk(KERN_ERR "%s: No such device\n", __func__);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&rx->lock, flags);
+	r = get_rx_struct(rx);
+	spin_unlock_irqrestore(&rx->lock, flags);
+
+	if (r == NULL)
+		return -ENOMEM;
+
+	r->callback = cb;
+	r->cb_data = cb_data;
+
+	usb_fill_bulk_urb(r->urb,
+			usbdev,
+			usb_rcvbulkpipe(usbdev, 0x82),
+			r->buf,
+			RX_BUF_SIZE,
+			gdm_usb_rcv_complete,
+			r);
+
+	return usb_submit_urb(r->urb, GFP_ATOMIC);
+}
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+static void do_pm_control(struct work_struct *work)
+{
+	struct usbwm_dev *udev = container_of(work, struct usbwm_dev, pm_ws);
+	struct tx_cxt *tx = &udev->tx;
+	int ret;
+	unsigned long flags;
+
+	ret = usb_autopm_get_interface(udev->intf);
+	if (!ret)
+		usb_autopm_put_interface(udev->intf);
+
+	spin_lock_irqsave(&tx->lock, flags);
+	if (!(udev->usbdev->state & USB_STATE_SUSPENDED)
+		&& (!list_empty(&tx->hci_list) || !list_empty(&tx->sdu_list))) {
+		struct usb_tx *t, *temp;
+
+		list_for_each_entry_safe(t, temp, &tx->pending_list, p_list) {
+			list_del(&t->p_list);
+			ret =  usb_submit_urb(t->urb, GFP_ATOMIC);
+
+			if (ret) {
+				t->callback = NULL;
+				gdm_usb_send_complete(t->urb);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+static int gdm_usb_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	int ret = 0;
+	u8 bConfigurationValue;
+	struct phy_dev *phy_dev = NULL;
+	struct usbwm_dev *udev = NULL;
+	u16 idVendor, idProduct, bcdDevice;
+
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+
+	usb_get_dev(usbdev);
+	bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue;
+
+	/*USB description is set up with Little-Endian*/
+	idVendor = L2H(usbdev->descriptor.idVendor);
+	idProduct = L2H(usbdev->descriptor.idProduct);
+	bcdDevice = L2H(usbdev->descriptor.bcdDevice);
+
+	printk(KERN_INFO "Found GDM USB VID = 0x%04x PID = 0x%04x...\n",
+		idVendor, idProduct);
+	printk(KERN_INFO "GCT WiMax driver version %s\n", DRIVER_VERSION);
+
+
+	if (idProduct == EMERGENCY_PID) {
+		ret = usb_emergency(usbdev);
+		goto out;
+	}
+
+	/* Support for EEPROM bootloader */
+	if (bConfigurationValue == DOWNLOAD_CONF_VALUE ||
+		idProduct & B_DOWNLOAD) {
+		ret = usb_boot(usbdev, bcdDevice);
+		goto out;
+	}
+
+	phy_dev = kmalloc(sizeof(*phy_dev), GFP_KERNEL);
+	if (phy_dev == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	udev = kmalloc(sizeof(*udev), GFP_KERNEL);
+	if (udev == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(phy_dev, 0, sizeof(*phy_dev));
+	memset(udev, 0, sizeof(*udev));
+
+	if (idProduct == 0x7205 || idProduct == 0x7206)
+		udev->padding = GDM7205_PADDING;
+	else
+		udev->padding = 0;
+
+	phy_dev->priv_dev = (void *)udev;
+	phy_dev->send_func = gdm_usb_send;
+	phy_dev->rcv_func = gdm_usb_receive;
+
+	ret = init_usb(udev);
+	if (ret < 0)
+		goto out;
+
+	udev->usbdev = usbdev;
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+	udev->intf = intf;
+
+	intf->needs_remote_wakeup = 1;
+	device_init_wakeup(&intf->dev, 1);
+
+	pm_runtime_set_autosuspend_delay(&usbdev->dev, 10 * 1000); /* msec */
+
+	INIT_WORK(&udev->pm_ws, do_pm_control);
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+	ret = register_wimax_device(phy_dev, &intf->dev);
+
+out:
+	if (ret) {
+		kfree(phy_dev);
+		kfree(udev);
+	}
+	usb_set_intfdata(intf, phy_dev);
+	return ret;
+}
+
+static void gdm_usb_disconnect(struct usb_interface *intf)
+{
+	u8 bConfigurationValue;
+	struct phy_dev *phy_dev;
+	struct usbwm_dev *udev;
+	u16 idProduct;
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+
+	bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue;
+	phy_dev = usb_get_intfdata(intf);
+
+	/*USB description is set up with Little-Endian*/
+	idProduct = L2H(usbdev->descriptor.idProduct);
+
+	if (idProduct != EMERGENCY_PID &&
+			bConfigurationValue != DOWNLOAD_CONF_VALUE &&
+			(idProduct & B_DOWNLOAD) == 0) {
+		udev = phy_dev->priv_dev;
+		udev->usbdev = NULL;
+
+		unregister_wimax_device(phy_dev);
+		release_usb(udev);
+		kfree(udev);
+		kfree(phy_dev);
+	}
+
+	usb_put_dev(usbdev);
+}
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+static int gdm_suspend(struct usb_interface *intf, pm_message_t pm_msg)
+{
+	struct phy_dev *phy_dev;
+	struct usbwm_dev *udev;
+	struct rx_cxt *rx;
+	struct usb_rx *r;
+
+	phy_dev = usb_get_intfdata(intf);
+	udev = phy_dev->priv_dev;
+	rx = &udev->rx;
+
+	list_for_each_entry(r, &rx->used_list, list)
+		usb_unlink_urb(r->urb);
+
+	return 0;
+}
+
+static int gdm_resume(struct usb_interface *intf)
+{
+	struct phy_dev *phy_dev;
+	struct usbwm_dev *udev;
+	struct rx_cxt *rx;
+	struct usb_rx *r;
+
+	phy_dev = usb_get_intfdata(intf);
+	udev = phy_dev->priv_dev;
+	rx = &udev->rx;
+
+	list_for_each_entry(r, &rx->used_list, list)
+		usb_submit_urb(r->urb, GFP_ATOMIC);
+
+	return 0;
+}
+
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+static int k_mode_thread(void *arg)
+{
+	struct usbwm_dev *udev;
+	struct tx_cxt *tx;
+	struct rx_cxt *rx;
+	struct usb_tx *t, *temp;
+	struct usb_rx *r;
+	unsigned long flags, flags2, expire;
+	int ret;
+
+	daemonize("k_mode_wimax");
+
+	while (!k_mode_stop) {
+
+		spin_lock_irqsave(&k_lock, flags2);
+		while (!list_empty(&k_list)) {
+
+			udev = list_entry(k_list.next, struct usbwm_dev, list);
+			tx = &udev->tx;
+			rx = &udev->rx;
+
+			list_del(&udev->list);
+			spin_unlock_irqrestore(&k_lock, flags2);
+
+			expire = jiffies + K_WAIT_TIME;
+			while (jiffies < expire)
+				schedule_timeout(K_WAIT_TIME);
+
+			list_for_each_entry(r, &rx->used_list, list)
+				usb_submit_urb(r->urb, GFP_ATOMIC);
+
+			spin_lock_irqsave(&tx->lock, flags);
+
+			list_for_each_entry_safe(t, temp, &tx->pending_list,
+						p_list) {
+				list_del(&t->p_list);
+				ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+
+				if (ret) {
+					t->callback = NULL;
+					gdm_usb_send_complete(t->urb);
+				}
+			}
+
+			udev->bw_switch = 0;
+			spin_unlock_irqrestore(&tx->lock, flags);
+
+			spin_lock_irqsave(&k_lock, flags2);
+		}
+		spin_unlock_irqrestore(&k_lock, flags2);
+
+		interruptible_sleep_on(&k_wait);
+	}
+	return 0;
+}
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+
+static struct usb_driver gdm_usb_driver = {
+	.name = "gdm_wimax",
+	.probe = gdm_usb_probe,
+	.disconnect = gdm_usb_disconnect,
+	.id_table = id_table,
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+	.supports_autosuspend = 1,
+	.suspend = gdm_suspend,
+	.resume = gdm_resume,
+	.reset_resume = gdm_resume,
+#endif
+};
+
+static int __init usb_gdm_wimax_init(void)
+{
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+	kernel_thread(k_mode_thread, NULL, CLONE_KERNEL);
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+	return usb_register(&gdm_usb_driver);
+}
+
+static void __exit usb_gdm_wimax_exit(void)
+{
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+	k_mode_stop = 1;
+	wake_up(&k_wait);
+#endif
+	usb_deregister(&gdm_usb_driver);
+}
+
+module_init(usb_gdm_wimax_init);
+module_exit(usb_gdm_wimax_exit);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("GCT WiMax Device Driver");
+MODULE_AUTHOR("Ethan Park");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm72xx/gdm_usb.h b/drivers/staging/gdm72xx/gdm_usb.h
new file mode 100644
index 0000000..ecb891f
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_usb.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __GDM_USB_H__
+#define __GDM_USB_H__
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+
+#define B_DIFF_DL_DRV		(1<<4)
+#define B_DOWNLOAD			(1 << 5)
+#define MAX_NR_SDU_BUF		64
+
+struct usb_tx {
+	struct list_head	list;
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+	struct list_head	p_list;
+#endif
+	struct tx_cxt		*tx_cxt;
+
+	struct urb	*urb;
+	u8			*buf;
+
+	void (*callback)(void *cb_data);
+	void *cb_data;
+};
+
+struct tx_cxt {
+	struct list_head	free_list;
+	struct list_head	sdu_list;
+	struct list_head	hci_list;
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+	struct list_head	pending_list;
+#endif
+
+	spinlock_t			lock;
+};
+
+struct usb_rx {
+	struct list_head	list;
+	struct rx_cxt		*rx_cxt;
+
+	struct urb	*urb;
+	u8			*buf;
+
+	void (*callback)(void *cb_data, void *data, int len);
+	void *cb_data;
+};
+
+struct rx_cxt {
+	struct list_head	free_list;
+	struct list_head	used_list;
+	spinlock_t			lock;
+};
+
+struct usbwm_dev {
+	struct usb_device	*usbdev;
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+	struct work_struct	pm_ws;
+
+	struct usb_interface	*intf;
+#endif
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+	int bw_switch;
+	struct list_head	list;
+#endif
+
+	struct tx_cxt	tx;
+	struct rx_cxt	rx;
+
+	int padding;
+};
+
+#endif /* __GDM_USB_H__ */
diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c
new file mode 100644
index 0000000..f1936b9
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_wimax.c
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <asm/byteorder.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+
+#include "gdm_wimax.h"
+#include "hci.h"
+#include "wm_ioctl.h"
+#include "netlink_k.h"
+
+#define gdm_wimax_send(n, d, l)	\
+	(n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, NULL, NULL)
+#define gdm_wimax_send_with_cb(n, d, l, c, b)	\
+	(n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, c, b)
+#define gdm_wimax_rcv_with_cb(n, c, b)	\
+	(n->phy_dev->rcv_func)(n->phy_dev->priv_dev, c, b)
+
+#define EVT_MAX_SIZE	2048
+
+struct evt_entry {
+	struct list_head list;
+	struct net_device *dev;
+	char evt_data[EVT_MAX_SIZE];
+	int	 size;
+};
+
+static void __gdm_wimax_event_send(struct work_struct *work);
+static inline struct evt_entry *alloc_event_entry(void);
+static inline void free_event_entry(struct evt_entry *e);
+static struct evt_entry *get_event_entry(void);
+static void put_event_entry(struct evt_entry *e);
+
+static struct {
+	int ref_cnt;
+	struct sock *sock;
+	struct list_head evtq;
+	spinlock_t evt_lock;
+
+	struct list_head freeq;
+	struct work_struct ws;
+} wm_event;
+
+static u8 gdm_wimax_macaddr[6] = {0x00, 0x0a, 0x3b, 0xf0, 0x01, 0x30};
+
+static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm);
+static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up);
+
+#if defined(DEBUG_SDU)
+static void printk_hex(u8 *buf, u32 size)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+		if (i && i % 16 == 0)
+			printk(KERN_DEBUG "\n%02x ", *buf++);
+		else
+			printk(KERN_DEBUG "%02x ", *buf++);
+	}
+
+	printk(KERN_DEBUG "\n");
+}
+
+static const char *get_protocol_name(u16 protocol)
+{
+	static char buf[32];
+	const char *name = "-";
+
+	switch (protocol) {
+	case ETH_P_ARP:
+		name = "ARP";
+		break;
+	case ETH_P_IP:
+		name = "IP";
+		break;
+	case ETH_P_IPV6:
+		name = "IPv6";
+		break;
+	}
+
+	sprintf(buf, "0x%04x(%s)", protocol, name);
+	return buf;
+}
+
+static const char *get_ip_protocol_name(u8 ip_protocol)
+{
+	static char buf[32];
+	const char *name = "-";
+
+	switch (ip_protocol) {
+	case IPPROTO_TCP:
+		name = "TCP";
+		break;
+	case IPPROTO_UDP:
+		name = "UDP";
+		break;
+	case IPPROTO_ICMP:
+		name = "ICMP";
+		break;
+	}
+
+	sprintf(buf, "%u(%s)", ip_protocol, name);
+	return buf;
+}
+
+static const char *get_port_name(u16 port)
+{
+	static char buf[32];
+	const char *name = "-";
+
+	switch (port) {
+	case 67:
+		name = "DHCP-Server";
+		break;
+	case 68:
+		name = "DHCP-Client";
+		break;
+	case 69:
+		name = "TFTP";
+		break;
+	}
+
+	sprintf(buf, "%u(%s)", port, name);
+	return buf;
+}
+
+static void dump_eth_packet(const char *title, u8 *data, int len)
+{
+	struct iphdr *ih = NULL;
+	struct udphdr *uh = NULL;
+	u16 protocol = 0;
+	u8 ip_protocol = 0;
+	u16 port = 0;
+
+	protocol = (data[12]<<8) | data[13];
+	ih = (struct iphdr *) (data+ETH_HLEN);
+
+	if (protocol == ETH_P_IP) {
+		uh = (struct udphdr *) ((char *)ih + sizeof(struct iphdr));
+		ip_protocol = ih->protocol;
+		port = ntohs(uh->dest);
+	} else if (protocol == ETH_P_IPV6) {
+		struct ipv6hdr *i6h = (struct ipv6hdr *) data;
+		uh = (struct udphdr *) ((char *)i6h + sizeof(struct ipv6hdr));
+		ip_protocol = i6h->nexthdr;
+		port = ntohs(uh->dest);
+	}
+
+	printk(KERN_DEBUG "[%s] len=%d, %s, %s, %s\n",
+		title, len,
+		get_protocol_name(protocol),
+		get_ip_protocol_name(ip_protocol),
+		get_port_name(port));
+
+	#if 1
+	if (!(data[0] == 0xff && data[1] == 0xff)) {
+		if (protocol == ETH_P_IP) {
+			printk(KERN_DEBUG "     src=%u.%u.%u.%u\n",
+				NIPQUAD(ih->saddr));
+		} else if (protocol == ETH_P_IPV6) {
+			#ifdef NIP6
+			printk(KERN_DEBUG "     src=%x:%x:%x:%x:%x:%x:%x:%x\n",
+				NIP6(ih->saddr));
+			#else
+			printk(KERN_DEBUG "     src=%pI6\n", &ih->saddr);
+			#endif
+		}
+	}
+	#endif
+
+	#if (DUMP_PACKET & DUMP_SDU_ALL)
+	printk_hex(data, len);
+	#else
+		#if (DUMP_PACKET & DUMP_SDU_ARP)
+		if (protocol == ETH_P_ARP)
+			printk_hex(data, len);
+		#endif
+		#if (DUMP_PACKET & DUMP_SDU_IP)
+		if (protocol == ETH_P_IP || protocol == ETH_P_IPV6)
+			printk_hex(data, len);
+		#else
+			#if (DUMP_PACKET & DUMP_SDU_IP_TCP)
+			if (ip_protocol == IPPROTO_TCP)
+				printk_hex(data, len);
+			#endif
+			#if (DUMP_PACKET & DUMP_SDU_IP_UDP)
+			if (ip_protocol == IPPROTO_UDP)
+				printk_hex(data, len);
+			#endif
+			#if (DUMP_PACKET & DUMP_SDU_IP_ICMP)
+			if (ip_protocol == IPPROTO_ICMP)
+				printk_hex(data, len);
+			#endif
+		#endif
+	#endif
+}
+#endif
+
+
+static inline int gdm_wimax_header(struct sk_buff **pskb)
+{
+	u16 buf[HCI_HEADER_SIZE / sizeof(u16)];
+	struct sk_buff *skb = *pskb;
+	int ret = 0;
+
+	if (unlikely(skb_headroom(skb) < HCI_HEADER_SIZE)) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_realloc_headroom(skb, HCI_HEADER_SIZE);
+		if (skb2 == NULL)
+			return -ENOMEM;
+		if (skb->sk)
+			skb_set_owner_w(skb2, skb->sk);
+		kfree_skb(skb);
+		skb = skb2;
+	}
+
+	skb_push(skb, HCI_HEADER_SIZE);
+	buf[0] = H2B(WIMAX_TX_SDU);
+	buf[1] = H2B(skb->len - HCI_HEADER_SIZE);
+	memcpy(skb->data, buf, HCI_HEADER_SIZE);
+
+	*pskb = skb;
+	return ret;
+}
+
+static void gdm_wimax_event_rcv(struct net_device *dev, u16 type, void *msg,
+				int len)
+{
+	struct nic *nic = netdev_priv(dev);
+
+	#if defined(DEBUG_HCI)
+	u8 *buf = (u8 *) msg;
+	u16 hci_cmd =  (buf[0]<<8) | buf[1];
+	u16 hci_len = (buf[2]<<8) | buf[3];
+	printk(KERN_DEBUG "H=>D: 0x%04x(%d)\n", hci_cmd, hci_len);
+	#endif
+
+	gdm_wimax_send(nic, msg, len);
+}
+
+static int gdm_wimax_event_init(void)
+{
+	if (wm_event.ref_cnt == 0) {
+		wm_event.sock = netlink_init(NETLINK_WIMAX,
+						gdm_wimax_event_rcv);
+		INIT_LIST_HEAD(&wm_event.evtq);
+		INIT_LIST_HEAD(&wm_event.freeq);
+		INIT_WORK(&wm_event.ws, __gdm_wimax_event_send);
+		spin_lock_init(&wm_event.evt_lock);
+	}
+
+	if (wm_event.sock) {
+		wm_event.ref_cnt++;
+		return 0;
+	}
+
+	printk(KERN_ERR "Creating WiMax Event netlink is failed\n");
+	return -1;
+}
+
+static void gdm_wimax_event_exit(void)
+{
+	if (wm_event.sock && --wm_event.ref_cnt == 0) {
+		struct evt_entry *e, *temp;
+		unsigned long flags;
+
+		spin_lock_irqsave(&wm_event.evt_lock, flags);
+
+		list_for_each_entry_safe(e, temp, &wm_event.evtq, list) {
+			list_del(&e->list);
+			free_event_entry(e);
+		}
+		list_for_each_entry_safe(e, temp, &wm_event.freeq, list) {
+			list_del(&e->list);
+			free_event_entry(e);
+		}
+
+		spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+		netlink_exit(wm_event.sock);
+		wm_event.sock = NULL;
+	}
+}
+
+static inline struct evt_entry *alloc_event_entry(void)
+{
+	return kmalloc(sizeof(struct evt_entry), GFP_ATOMIC);
+}
+
+static inline void free_event_entry(struct evt_entry *e)
+{
+	kfree(e);
+}
+
+static struct evt_entry *get_event_entry(void)
+{
+	struct evt_entry *e;
+
+	if (list_empty(&wm_event.freeq))
+		e = alloc_event_entry();
+	else {
+		e = list_entry(wm_event.freeq.next, struct evt_entry, list);
+		list_del(&e->list);
+	}
+
+	return e;
+}
+
+static void put_event_entry(struct evt_entry *e)
+{
+	BUG_ON(!e);
+
+	list_add_tail(&e->list, &wm_event.freeq);
+}
+
+static void __gdm_wimax_event_send(struct work_struct *work)
+{
+	int idx;
+	unsigned long flags;
+	struct evt_entry *e;
+
+	spin_lock_irqsave(&wm_event.evt_lock, flags);
+
+	while (!list_empty(&wm_event.evtq)) {
+		e = list_entry(wm_event.evtq.next, struct evt_entry, list);
+		spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+
+		sscanf(e->dev->name, "wm%d", &idx);
+		netlink_send(wm_event.sock, idx, 0, e->evt_data, e->size);
+
+		spin_lock_irqsave(&wm_event.evt_lock, flags);
+		list_del(&e->list);
+		put_event_entry(e);
+	}
+
+	spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+}
+
+static int gdm_wimax_event_send(struct net_device *dev, char *buf, int size)
+{
+	struct evt_entry *e;
+	unsigned long flags;
+
+	#if defined(DEBUG_HCI)
+	u16 hci_cmd =  ((u8)buf[0]<<8) | (u8)buf[1];
+	u16 hci_len = ((u8)buf[2]<<8) | (u8)buf[3];
+	printk(KERN_DEBUG "D=>H: 0x%04x(%d)\n", hci_cmd, hci_len);
+	#endif
+
+	spin_lock_irqsave(&wm_event.evt_lock, flags);
+
+	e = get_event_entry();
+	if (!e) {
+		printk(KERN_ERR "%s: No memory for event\n", __func__);
+		spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+		return -ENOMEM;
+	}
+
+	e->dev = dev;
+	e->size = size;
+	memcpy(e->evt_data, buf, size);
+
+	list_add_tail(&e->list, &wm_event.evtq);
+	spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+
+	schedule_work(&wm_event.ws);
+
+	return 0;
+}
+
+static void tx_complete(void *arg)
+{
+	struct nic *nic = arg;
+
+	if (netif_queue_stopped(nic->netdev))
+		netif_wake_queue(nic->netdev);
+}
+
+int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	int ret = 0;
+	struct nic *nic = netdev_priv(dev);
+
+	ret = gdm_wimax_send_with_cb(nic, skb->data, skb->len, tx_complete,
+					nic);
+	if (ret == -ENOSPC) {
+		netif_stop_queue(dev);
+		ret = 0;
+	}
+
+	if (ret) {
+		skb_pull(skb, HCI_HEADER_SIZE);
+		return ret;
+	}
+
+	nic->stats.tx_packets++;
+	nic->stats.tx_bytes += skb->len - HCI_HEADER_SIZE;
+	kfree_skb(skb);
+	return ret;
+}
+
+static int gdm_wimax_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	int ret = 0;
+	struct nic *nic = netdev_priv(dev);
+	struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+	#if defined(DEBUG_SDU)
+	dump_eth_packet("TX", skb->data, skb->len);
+	#endif
+
+	ret = gdm_wimax_header(&skb);
+	if (ret < 0) {
+		skb_pull(skb, HCI_HEADER_SIZE);
+		return ret;
+	}
+
+	#if !defined(LOOPBACK_TEST)
+	if (!fsm)
+		printk(KERN_ERR "ASSERTION ERROR: fsm is NULL!!\n");
+	else if (fsm->m_status != M_CONNECTED) {
+		printk(KERN_EMERG "ASSERTION ERROR: Device is NOT ready. status=%d\n",
+			fsm->m_status);
+		kfree_skb(skb);
+		return 0;
+	}
+	#endif
+
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+	ret = gdm_qos_send_hci_pkt(skb, dev);
+#else
+	ret = gdm_wimax_send_tx(skb, dev);
+#endif
+	return ret;
+}
+
+static int gdm_wimax_set_config(struct net_device *dev, struct ifmap *map)
+{
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	return 0;
+}
+
+static void __gdm_wimax_set_mac_addr(struct net_device *dev, char *mac_addr)
+{
+	u16 hci_pkt_buf[32 / sizeof(u16)];
+	u8 *pkt = (u8 *) &hci_pkt_buf[0];
+	struct nic *nic = netdev_priv(dev);
+
+	/* Since dev is registered as a ethernet device,
+	 * ether_setup has made dev->addr_len to be ETH_ALEN
+	 */
+	memcpy(dev->dev_addr, mac_addr, dev->addr_len);
+
+	/* Let lower layer know of this change by sending
+	 * SetInformation(MAC Address)
+	 */
+	hci_pkt_buf[0] = H2B(WIMAX_SET_INFO);	/* cmd_evt */
+	hci_pkt_buf[1] = H2B(8);			/* size */
+	pkt[4] = 0; /* T */
+	pkt[5] = 6; /* L */
+	memcpy(pkt + 6, mac_addr, dev->addr_len); /* V */
+
+	gdm_wimax_send(nic, pkt, HCI_HEADER_SIZE + 8);
+}
+
+/* A driver function */
+static int gdm_wimax_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	__gdm_wimax_set_mac_addr(dev, addr->sa_data);
+
+	return 0;
+}
+
+static struct net_device_stats *gdm_wimax_stats(struct net_device *dev)
+{
+	struct nic *nic = netdev_priv(dev);
+
+	return &nic->stats;
+}
+
+static int gdm_wimax_open(struct net_device *dev)
+{
+	struct nic *nic = netdev_priv(dev);
+	struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+	netif_start_queue(dev);
+
+	if (fsm && fsm->m_status != M_INIT)
+		gdm_wimax_ind_if_updown(dev, 1);
+	return 0;
+}
+
+static int gdm_wimax_close(struct net_device *dev)
+{
+	struct nic *nic = netdev_priv(dev);
+	struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+	netif_stop_queue(dev);
+
+	if (fsm && fsm->m_status != M_INIT)
+		gdm_wimax_ind_if_updown(dev, 0);
+	return 0;
+}
+
+static void kdelete(void **buf)
+{
+	if (buf && *buf) {
+		kfree(*buf);
+		*buf = NULL;
+	}
+}
+
+static int gdm_wimax_ioctl_get_data(struct data_s *dst, struct data_s *src)
+{
+	int size;
+
+	size = dst->size < src->size ? dst->size : src->size;
+
+	dst->size = size;
+	if (src->size) {
+		if (!dst->buf)
+			return -EINVAL;
+		if (copy_to_user(dst->buf, src->buf, size))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static int gdm_wimax_ioctl_set_data(struct data_s *dst, struct data_s *src)
+{
+	if (!src->size) {
+		dst->size = 0;
+		return 0;
+	}
+
+	if (!src->buf)
+		return -EINVAL;
+
+	if (!(dst->buf && dst->size == src->size)) {
+		kdelete(&dst->buf);
+		dst->buf = kmalloc(src->size, GFP_KERNEL);
+		if (dst->buf == NULL)
+			return -ENOMEM;
+	}
+
+	if (copy_from_user(dst->buf, src->buf, src->size)) {
+		kdelete(&dst->buf);
+		return -EFAULT;
+	}
+	dst->size = src->size;
+	return 0;
+}
+
+static void gdm_wimax_cleanup_ioctl(struct net_device *dev)
+{
+	struct nic *nic = netdev_priv(dev);
+	int i;
+
+	for (i = 0; i < SIOC_DATA_MAX; i++)
+		kdelete(&nic->sdk_data[i].buf);
+}
+
+static void gdm_update_fsm(struct net_device *dev, struct fsm_s *new_fsm)
+{
+	struct nic *nic = netdev_priv(dev);
+	struct fsm_s *cur_fsm =
+		(struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+	if (!cur_fsm)
+		return;
+
+	if (cur_fsm->m_status != new_fsm->m_status ||
+		cur_fsm->c_status != new_fsm->c_status) {
+		if (new_fsm->m_status == M_CONNECTED)
+			netif_carrier_on(dev);
+		else if (cur_fsm->m_status == M_CONNECTED) {
+			netif_carrier_off(dev);
+			#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+			gdm_qos_release_list(nic);
+			#endif
+		}
+		gdm_wimax_ind_fsm_update(dev, new_fsm);
+	}
+}
+
+static int gdm_wimax_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct wm_req_s *req = (struct wm_req_s *) ifr;
+	struct nic *nic = netdev_priv(dev);
+	int ret;
+
+	if (cmd != SIOCWMIOCTL)
+		return -EOPNOTSUPP;
+
+	switch (req->cmd) {
+	case SIOCG_DATA:
+	case SIOCS_DATA:
+		if (req->data_id >= SIOC_DATA_MAX) {
+			printk(KERN_ERR
+				"%s error: data-index(%d) is invalid!!\n",
+				__func__, req->data_id);
+			return -EOPNOTSUPP;
+		}
+		if (req->cmd == SIOCG_DATA) {
+			ret = gdm_wimax_ioctl_get_data(&req->data,
+						&nic->sdk_data[req->data_id]);
+			if (ret < 0)
+				return ret;
+		} else if (req->cmd == SIOCS_DATA) {
+			if (req->data_id == SIOC_DATA_FSM) {
+				/*NOTE: gdm_update_fsm should be called
+				before gdm_wimax_ioctl_set_data is called*/
+				gdm_update_fsm(dev,
+						(struct fsm_s *) req->data.buf);
+			}
+			ret = gdm_wimax_ioctl_set_data(
+				&nic->sdk_data[req->data_id], &req->data);
+			if (ret < 0)
+				return ret;
+		}
+		break;
+	default:
+		printk(KERN_ERR "%s: %x unknown ioctl\n", __func__, cmd);
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static void gdm_wimax_prepare_device(struct net_device *dev)
+{
+	struct nic *nic = netdev_priv(dev);
+	u16 buf[32 / sizeof(u16)];
+	struct hci_s *hci = (struct hci_s *) buf;
+	u16 len = 0;
+	u32 val = 0;
+
+	#define BIT_MULTI_CS	0
+	#define BIT_WIMAX		1
+	#define BIT_QOS			2
+	#define BIT_AGGREGATION	3
+
+	/* GetInformation mac address */
+	len = 0;
+	hci->cmd_evt = H2B(WIMAX_GET_INFO);
+	hci->data[len++] = TLV_T(T_MAC_ADDRESS);
+	hci->length = H2B(len);
+	gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len);
+
+	val = (1<<BIT_WIMAX) | (1<<BIT_MULTI_CS);
+	#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+	val |= (1<<BIT_QOS);
+	#endif
+	#if defined(CONFIG_WIMAX_GDM72XX_WIMAX2)
+	val |= (1<<BIT_AGGREGATION);
+	#endif
+
+	/* Set capability */
+	len = 0;
+	hci->cmd_evt = H2B(WIMAX_SET_INFO);
+	hci->data[len++] = TLV_T(T_CAPABILITY);
+	hci->data[len++] = TLV_L(T_CAPABILITY);
+	val = DH2B(val);
+	memcpy(&hci->data[len], &val, TLV_L(T_CAPABILITY));
+	len += TLV_L(T_CAPABILITY);
+	hci->length = H2B(len);
+	gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len);
+
+	printk(KERN_INFO "GDM WiMax Set CAPABILITY: 0x%08X\n", DB2H(val));
+}
+
+static int gdm_wimax_hci_get_tlv(u8 *buf, u8 *T, u16 *L, u8 **V)
+{
+	#define __U82U16(b) ((u16)((u8 *)(b))[0] | ((u16)((u8 *)(b))[1] << 8))
+	int next_pos;
+
+	*T = buf[0];
+	if (buf[1] == 0x82) {
+		*L = B2H(__U82U16(&buf[2]));
+		next_pos = 1/*type*/+3/*len*/;
+	} else {
+		*L = buf[1];
+		next_pos = 1/*type*/+1/*len*/;
+	}
+	*V = &buf[next_pos];
+
+	next_pos += *L/*length of val*/;
+	return next_pos;
+}
+
+static int gdm_wimax_get_prepared_info(struct net_device *dev, char *buf,
+					int len)
+{
+	u8 T, *V;
+	u16 L;
+	u16 cmd_evt, cmd_len;
+	int pos = HCI_HEADER_SIZE;
+
+	cmd_evt = B2H(*(u16 *)&buf[0]);
+	cmd_len = B2H(*(u16 *)&buf[2]);
+
+	if (len < cmd_len + HCI_HEADER_SIZE) {
+		printk(KERN_ERR "%s: invalid length [%d/%d]\n", __func__,
+			cmd_len + HCI_HEADER_SIZE, len);
+		return -1;
+	}
+
+	if (cmd_evt == WIMAX_GET_INFO_RESULT) {
+		if (cmd_len < 2) {
+			printk(KERN_ERR "%s: len is too short [%x/%d]\n",
+				__func__, cmd_evt, len);
+			return -1;
+		}
+
+		pos += gdm_wimax_hci_get_tlv(&buf[pos], &T, &L, &V);
+		if (T == TLV_T(T_MAC_ADDRESS)) {
+			if (L != dev->addr_len) {
+				printk(KERN_ERR
+					"%s Invalid inofrmation result T/L "
+					"[%x/%d]\n", __func__, T, L);
+				return -1;
+			}
+			printk(KERN_INFO
+				"MAC change [%02x:%02x:%02x:%02x:%02x:%02x]"
+				"->[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+				dev->dev_addr[0], dev->dev_addr[1],
+				dev->dev_addr[2], dev->dev_addr[3],
+				dev->dev_addr[4], dev->dev_addr[5],
+				V[0], V[1], V[2], V[3], V[4], V[5]);
+			memcpy(dev->dev_addr, V, dev->addr_len);
+			return 1;
+		}
+	}
+
+	gdm_wimax_event_send(dev, buf, len);
+	return 0;
+}
+
+static void gdm_wimax_netif_rx(struct net_device *dev, char *buf, int len)
+{
+	struct nic *nic = netdev_priv(dev);
+	struct sk_buff *skb;
+	int ret;
+
+	#if defined(DEBUG_SDU)
+	dump_eth_packet("RX", buf, len);
+	#endif
+
+	skb = dev_alloc_skb(len + 2);
+	if (!skb) {
+		printk(KERN_ERR "%s: dev_alloc_skb failed!\n", __func__);
+		return;
+	}
+	skb_reserve(skb, 2);
+
+	nic->stats.rx_packets++;
+	nic->stats.rx_bytes += len;
+
+	memcpy(skb_put(skb, len), buf, len);
+
+	skb->dev = dev;
+	skb->protocol = eth_type_trans(skb, dev); /* what will happen? */
+
+	ret = in_interrupt() ? netif_rx(skb) : netif_rx_ni(skb);
+	if (ret == NET_RX_DROP)
+		printk(KERN_ERR "%s skb dropped\n", __func__);
+}
+
+static void gdm_wimax_transmit_aggr_pkt(struct net_device *dev, char *buf,
+					int len)
+{
+	#define HCI_PADDING_BYTE	4
+	#define HCI_RESERVED_BYTE	4
+	struct hci_s *hci;
+	int length;
+
+	while (len > 0) {
+		hci = (struct hci_s *) buf;
+
+		if (B2H(hci->cmd_evt) != WIMAX_RX_SDU) {
+			printk(KERN_ERR "Wrong cmd_evt(0x%04X)\n",
+				B2H(hci->cmd_evt));
+			break;
+		}
+
+		length = B2H(hci->length);
+		gdm_wimax_netif_rx(dev, hci->data, length);
+
+		if (length & 0x3) {
+			/* Add padding size */
+			length += HCI_PADDING_BYTE - (length & 0x3);
+		}
+
+		length += HCI_HEADER_SIZE + HCI_RESERVED_BYTE;
+		len -= length;
+		buf += length;
+	}
+}
+
+static void gdm_wimax_transmit_pkt(struct net_device *dev, char *buf, int len)
+{
+	#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+	struct nic *nic = netdev_priv(dev);
+	#endif
+	u16 cmd_evt, cmd_len;
+
+	/* This code is added for certain rx packet to be ignored. */
+	if (len == 0)
+		return;
+
+	cmd_evt = B2H(*(u16 *)&buf[0]);
+	cmd_len = B2H(*(u16 *)&buf[2]);
+
+	if (len < cmd_len + HCI_HEADER_SIZE) {
+		if (len)
+			printk(KERN_ERR "%s: invalid length [%d/%d]\n",
+				__func__, cmd_len + HCI_HEADER_SIZE, len);
+		return;
+	}
+
+	switch (cmd_evt) {
+	case WIMAX_RX_SDU_AGGR:
+		gdm_wimax_transmit_aggr_pkt(dev, &buf[HCI_HEADER_SIZE],
+						cmd_len);
+		break;
+	case WIMAX_RX_SDU:
+		gdm_wimax_netif_rx(dev, &buf[HCI_HEADER_SIZE], cmd_len);
+		break;
+	#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+	case WIMAX_EVT_MODEM_REPORT:
+		gdm_recv_qos_hci_packet(nic, buf, len);
+		break;
+	#endif
+	case WIMAX_SDU_TX_FLOW:
+		if (buf[4] == 0) {
+			if (!netif_queue_stopped(dev))
+				netif_stop_queue(dev);
+		} else if (buf[4] == 1) {
+			if (netif_queue_stopped(dev))
+				netif_wake_queue(dev);
+		}
+		break;
+	default:
+		gdm_wimax_event_send(dev, buf, len);
+		break;
+	}
+}
+
+static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm)
+{
+	u16 buf[32 / sizeof(u16)];
+	u8 *hci_pkt_buf = (u8 *)&buf[0];
+
+	/* Indicate updating fsm */
+	buf[0] = H2B(WIMAX_FSM_UPDATE);
+	buf[1] = H2B(sizeof(struct fsm_s));
+	memcpy(&hci_pkt_buf[HCI_HEADER_SIZE], fsm, sizeof(struct fsm_s));
+
+	gdm_wimax_event_send(dev, hci_pkt_buf,
+				HCI_HEADER_SIZE + sizeof(struct fsm_s));
+}
+
+static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up)
+{
+	u16 buf[32 / sizeof(u16)];
+	struct hci_s *hci = (struct hci_s *) buf;
+	unsigned char up_down;
+
+	up_down = if_up ? WIMAX_IF_UP : WIMAX_IF_DOWN;
+
+	/* Indicate updating fsm */
+	hci->cmd_evt = H2B(WIMAX_IF_UPDOWN);
+	hci->length = H2B(sizeof(up_down));
+	hci->data[0] = up_down;
+
+	gdm_wimax_event_send(dev, (char *)hci, HCI_HEADER_SIZE+sizeof(up_down));
+}
+
+static void rx_complete(void *arg, void *data, int len)
+{
+	struct nic *nic = arg;
+
+	gdm_wimax_transmit_pkt(nic->netdev, data, len);
+	gdm_wimax_rcv_with_cb(nic, rx_complete, nic);
+}
+
+static void prepare_rx_complete(void *arg, void *data, int len)
+{
+	struct nic *nic = arg;
+	int ret;
+
+	ret = gdm_wimax_get_prepared_info(nic->netdev, data, len);
+	if (ret == 1)
+		gdm_wimax_rcv_with_cb(nic, rx_complete, nic);
+	else {
+		if (ret < 0)
+			printk(KERN_ERR "get_prepared_info failed(%d)\n", ret);
+		gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic);
+		#if 0
+		/* Re-prepare WiMax device */
+		gdm_wimax_prepare_device(nic->netdev);
+		#endif
+	}
+}
+
+static void start_rx_proc(struct nic *nic)
+{
+	gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic);
+}
+
+static struct net_device_ops gdm_netdev_ops = {
+	.ndo_open				= gdm_wimax_open,
+	.ndo_stop				= gdm_wimax_close,
+	.ndo_set_config			= gdm_wimax_set_config,
+	.ndo_start_xmit			= gdm_wimax_tx,
+	.ndo_get_stats			= gdm_wimax_stats,
+	.ndo_set_mac_address	= gdm_wimax_set_mac_addr,
+	.ndo_do_ioctl			= gdm_wimax_ioctl,
+};
+
+int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev)
+{
+	struct nic *nic = NULL;
+	struct net_device *dev;
+	int ret;
+
+	dev = (struct net_device *)alloc_netdev(sizeof(*nic),
+						"wm%d", ether_setup);
+
+	if (dev == NULL) {
+		printk(KERN_ERR "alloc_etherdev failed\n");
+		return -ENOMEM;
+	}
+
+	SET_NETDEV_DEV(dev, pdev);
+	dev->mtu = 1400;
+	dev->netdev_ops = &gdm_netdev_ops;
+	dev->flags &= ~IFF_MULTICAST;
+	memcpy(dev->dev_addr, gdm_wimax_macaddr, sizeof(gdm_wimax_macaddr));
+
+	nic = netdev_priv(dev);
+	memset(nic, 0, sizeof(*nic));
+
+	nic->netdev = dev;
+	nic->phy_dev = phy_dev;
+	phy_dev->netdev = dev;
+
+	/* event socket init */
+	ret = gdm_wimax_event_init();
+	if (ret < 0) {
+		printk(KERN_ERR "Cannot create event.\n");
+		goto cleanup;
+	}
+
+	ret = register_netdev(dev);
+	if (ret)
+		goto cleanup;
+
+	#if defined(LOOPBACK_TEST)
+	netif_start_queue(dev);
+	netif_carrier_on(dev);
+	#else
+	netif_carrier_off(dev);
+	#endif
+
+#ifdef CONFIG_WIMAX_GDM72XX_QOS
+	gdm_qos_init(nic);
+#endif
+
+	start_rx_proc(nic);
+
+	/* Prepare WiMax device */
+	gdm_wimax_prepare_device(dev);
+
+	return 0;
+
+cleanup:
+	printk(KERN_ERR "register_netdev failed\n");
+	free_netdev(dev);
+	return ret;
+}
+
+void unregister_wimax_device(struct phy_dev *phy_dev)
+{
+	struct nic *nic = netdev_priv(phy_dev->netdev);
+	struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+	if (fsm)
+		fsm->m_status = M_INIT;
+	unregister_netdev(nic->netdev);
+
+	gdm_wimax_event_exit();
+
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+	gdm_qos_release_list(nic);
+#endif
+
+	gdm_wimax_cleanup_ioctl(phy_dev->netdev);
+
+	free_netdev(nic->netdev);
+}
diff --git a/drivers/staging/gdm72xx/gdm_wimax.h b/drivers/staging/gdm72xx/gdm_wimax.h
new file mode 100644
index 0000000..023e649
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_wimax.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __GDM_WIMAX_H__
+#define __GDM_WIMAX_H__
+
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include "wm_ioctl.h"
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+#include "gdm_qos.h"
+#endif
+
+#define DRIVER_VERSION		"3.2.3"
+
+/*#define ETH_P_IP	0x0800 */
+/*#define ETH_P_ARP	0x0806 */
+/*#define ETH_P_IPV6	0x86DD */
+
+#define H2L(x)		__cpu_to_le16(x)
+#define L2H(x)		__le16_to_cpu(x)
+#define DH2L(x)		__cpu_to_le32(x)
+#define DL2H(x)		__le32_to_cpu(x)
+
+#define H2B(x)		__cpu_to_be16(x)
+#define B2H(x)		__be16_to_cpu(x)
+#define DH2B(x)		__cpu_to_be32(x)
+#define DB2H(x)		__be32_to_cpu(x)
+
+struct phy_dev {
+	void	*priv_dev;
+	struct net_device	*netdev;
+
+	int	(*send_func)(void *priv_dev, void *data, int len,
+			void (*cb)(void *cb_data), void *cb_data);
+	int	(*rcv_func)(void *priv_dev,
+			void (*cb)(void *cb_data, void *data, int len),
+			void *cb_data);
+};
+
+struct nic {
+	struct net_device	*netdev;
+	struct phy_dev		*phy_dev;
+
+	struct net_device_stats	stats;
+
+	struct data_s	sdk_data[SIOC_DATA_MAX];
+
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+	struct qos_cb_s	qos;
+#endif
+
+};
+
+
+#if 0
+#define dprintk(fmt, args ...)	printk(KERN_DEBUG " [GDM] " fmt, ## args)
+#else
+#define dprintk(...)
+#endif
+
+/*#define DEBUG_SDU */
+#if defined(DEBUG_SDU)
+#define DUMP_SDU_ALL		(1<<0)
+#define DUMP_SDU_ARP		(1<<1)
+#define DUMP_SDU_IP			(1<<2)
+#define DUMP_SDU_IP_TCP		(1<<8)
+#define DUMP_SDU_IP_UDP		(1<<9)
+#define DUMP_SDU_IP_ICMP	(1<<10)
+#define DUMP_PACKET			(DUMP_SDU_ALL)
+#endif
+
+/*#define DEBUG_HCI */
+
+/*#define LOOPBACK_TEST */
+
+extern int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev);
+extern int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev);
+extern void unregister_wimax_device(struct phy_dev *phy_dev);
+
+#endif
diff --git a/drivers/staging/gdm72xx/hci.h b/drivers/staging/gdm72xx/hci.h
new file mode 100644
index 0000000..0e06766
--- /dev/null
+++ b/drivers/staging/gdm72xx/hci.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef HCI_H_20080801
+#define HCI_H_20080801
+
+#define HCI_HEADER_SIZE		4
+#define HCI_VALUE_OFFS		(HCI_HEADER_SIZE)
+#define HCI_MAX_PACKET		2048
+#define HCI_MAX_PARAM		(HCI_MAX_PACKET-HCI_HEADER_SIZE)
+#define HCI_MAX_TLV			32
+
+/* CMD-EVT */
+
+/* Category 0 */
+#define WIMAX_RESET				0x0000
+#define WIMAX_SET_INFO			0x0001
+#define WIMAX_GET_INFO			0x0002
+#define WIMAX_GET_INFO_RESULT	0x8003
+#define WIMAX_RADIO_OFF			0x0004
+#define WIMAX_RADIO_ON			0x0006
+#define WIMAX_WIMAX_RESET		0x0007	/* Is this still here */
+
+/* Category 1 */
+#define WIMAX_NET_ENTRY			0x0100
+#define WIMAX_NET_DISCONN		0x0102
+#define WIMAX_ENTER_SLEEP		0x0103
+#define WIMAX_EXIT_SLEEP		0x0104
+#define WIMAX_ENTER_IDLE		0x0105
+#define WIMAX_EXIT_IDLE			0x0106
+#define WIMAX_MODE_CHANGE		0x8108
+#define WIMAX_HANDOVER			0x8109	/* obsolete */
+
+#define WIMAX_SCAN				0x010d
+#define WIMAX_SCAN_COMPLETE		0x810e
+#define WIMAX_SCAN_RESULT		0x810f
+
+#define WIMAX_CONNECT			0x0110
+#define WIMAX_CONNECT_START		0x8111
+#define WIMAX_CONNECT_COMPLETE	0x8112
+#define WIMAX_ASSOC_START		0x8113
+#define WIMAX_ASSOC_COMPLETE	0x8114
+#define WIMAX_DISCONN_IND		0x8115
+#define WIMAX_ENTRY_IND			0x8116
+#define WIMAX_HO_START			0x8117
+#define WIMAX_HO_COMPLETE		0x8118
+#define WIMAX_RADIO_STATE_IND	0x8119
+#define WIMAX_IP_RENEW_IND		0x811a
+
+#define WIMAX_DISCOVER_NSP			0x011d
+#define WIMAX_DISCOVER_NSP_RESULT	0x811e
+
+#define WIMAX_SDU_TX_FLOW		0x8125
+
+/* Category 2 */
+#define WIMAX_TX_EAP		0x0200
+#define WIMAX_RX_EAP		0x8201
+#define WIMAX_TX_SDU		0x0202
+#define WIMAX_RX_SDU		0x8203
+#define WIMAX_RX_SDU_AGGR	0x8204
+#define WIMAX_TX_SDU_AGGR	0x0205
+
+/* Category 3 */
+#define WIMAX_DM_CMD				0x030a
+#define WIMAX_DM_RSP				0x830b
+
+#define WIMAX_CLI_CMD				0x030c
+#define WIMAX_CLI_RSP				0x830d
+
+#define WIMAX_DL_IMAGE				0x0310
+#define WIMAX_DL_IMAGE_STATUS		0x8311
+#define WIMAX_UL_IMAGE				0x0312
+#define WIMAX_UL_IMAGE_RESULT		0x8313
+#define WIMAX_UL_IMAGE_STATUS		0x0314
+
+#define WIMAX_EVT_MODEM_REPORT		0x8325
+
+/* Category 0xF */
+#define WIMAX_FSM_UPDATE			0x8F01
+#define WIMAX_IF_UPDOWN				0x8F02
+	#define WIMAX_IF_UP				1
+	#define WIMAX_IF_DOWN			2
+
+/* WIMAX mode */
+#define W_NULL				0
+#define W_STANDBY			1
+#define W_OOZ				2
+#define W_AWAKE				3
+#define W_IDLE				4
+#define W_SLEEP				5
+#define W_WAIT				6
+
+#define W_NET_ENTRY_RNG		0x80
+#define W_NET_ENTRY_SBC		0x81
+#define W_NET_ENTRY_PKM		0x82
+#define W_NET_ENTRY_REG		0x83
+#define W_NET_ENTRY_DSX		0x84
+
+#define W_NET_ENTRY_RNG_FAIL	0x1100100
+#define W_NET_ENTRY_SBC_FAIL	0x1100200
+#define W_NET_ENTRY_PKM_FAIL	0x1102000
+#define W_NET_ENTRY_REG_FAIL	0x1103000
+#define W_NET_ENTRY_DSX_FAIL	0x1104000
+
+/* Scan Type */
+#define W_SCAN_ALL_CHANNEL				0
+#define W_SCAN_ALL_SUBSCRIPTION			1
+#define W_SCAN_SPECIFIED_SUBSCRIPTION	2
+
+/*
+ * TLV
+ *
+ * [31:31] indicates the type is composite.
+ * [30:16] is the length of the type. 0 length means length is variable.
+ * [15:0] is the actual type.
+ *
+ */
+#define TLV_L(x)		(((x) >> 16) & 0xff)
+#define TLV_T(x)			((x) & 0xff)
+#define TLV_COMPOSITE(x)	((x) >> 31)
+
+/* GENERAL */
+#define T_MAC_ADDRESS			(0x00	| (6 << 16))
+#define T_BSID				(0x01	| (6 << 16))
+#define T_MSK				(0x02	| (64 << 16))
+#define T_RSSI_THRSHLD			(0x03	| (1 << 16))
+#define T_FREQUENCY			(0x04	| (4 << 16))
+#define T_CONN_CS_TYPE			(0x05	| (1 << 16))
+#define T_HOST_IP_VER			(0x06	| (1 << 16))
+#define T_STBY_SCAN_INTERVAL		(0x07	| (4  << 16))
+#define T_OOZ_SCAN_INTERVAL		(0x08	| (4 << 16))
+#define T_IMEI				(0x09	| (8 << 16))
+#define T_PID				(0x0a	| (12 << 16))
+
+#define T_CAPABILITY			(0x1a	| (4 << 16))
+#define T_RELEASE_NUMBER		(0x1b	| (4 << 16))
+#define T_DRIVER_REVISION		(0x1c	| (4 << 16))
+#define T_FW_REVISION			(0x1d	| (4 << 16))
+#define T_MAC_HW_REVISION		(0x1e	| (4 << 16))
+#define T_PHY_HW_REVISION		(0x1f	| (4 << 16))
+
+/* HANDOVER */
+#define T_SCAN_INTERVAL		(0x20	| (1 << 16))
+
+#define T_RSC_RETAIN_TIME		(0x2f	| (2 << 16))
+
+/* SLEEP */
+#define T_TYPE1_ISW			(0x40	| (1 << 16))
+
+#define T_SLP_START_TO			(0x4a	| (2 << 16))
+
+/* IDLE */
+#define T_IDLE_MODE_TO			(0x50	| (2 << 16))
+
+#define T_IDLE_START_TO		(0x54	| (2 << 16))
+
+/* MONITOR */
+#define T_RSSI				(0x60	| (1 << 16))
+#define T_CINR				(0x61	| (1 << 16))
+#define T_TX_POWER			(0x6a   | (1 << 16))
+#define T_CUR_FREQ			(0x7f	| (4 << 16))
+
+
+/* WIMAX */
+#define T_MAX_SUBSCRIPTION		(0xa1	| (1 << 16))
+#define T_MAX_SF			(0xa2	| (1 << 16))
+#define T_PHY_TYPE			(0xa3	| (1 << 16))
+#define T_PKM				(0xa4	| (1 << 16))
+#define T_AUTH_POLICY			(0xa5	| (1 << 16))
+#define T_CS_TYPE			(0xa6	| (2 << 16))
+#define T_VENDOR_NAME			(0xa7	| (0 << 16))
+#define T_MOD_NAME			(0xa8	| (0 << 16))
+#define T_PACKET_FILTER		(0xa9	| (1 << 16))
+#define T_NSP_CHANGE_COUNT		(0xaa	| (4 << 16))
+#define T_RADIO_STATE			(0xab	| (1 << 16))
+#define T_URI_CONTACT_TYPE		(0xac	| (1 << 16))
+#define T_URI_TEXT			(0xad	| (0 << 16))
+#define T_URI				(0xae	| (0 << 16))
+#define T_ENABLE_AUTH			(0xaf	| (1 << 16))
+#define T_TIMEOUT			(0xb0   | (2 << 16))
+#define T_RUN_MODE			(0xb1	| (1 << 16))
+#define T_OMADMT_VER			(0xb2	| (4 << 16))
+/* This is measured in seconds from 00:00:00 GMT January 1, 1970. */
+#define T_RTC_TIME			(0xb3	| (4 << 16))
+#define T_CERT_STATUS			(0xb4	| (4 << 16))
+#define T_CERT_MASK			(0xb5	| (4 << 16))
+#define T_EMSK				(0xb6	| (64 << 16))
+
+/* Subscription TLV */
+#define T_SUBSCRIPTION_LIST		(0xd1	| (0 << 16) | (1 << 31))
+#define T_H_NSPID			(0xd2	| (3 << 16))
+#define T_NSP_NAME			(0xd3	| (0 << 16))
+#define T_SUBSCRIPTION_NAME		(0xd4	| (0 << 16))
+#define T_SUBSCRIPTION_FLAG		(0xd5	| (2 << 16))
+#define T_V_NSPID			(0xd6	| (3 << 16))
+#define T_NAP_ID			(0xd7	| (3 << 16))
+#define T_PREAMBLES			(0xd8	| (15 << 16))
+#define T_BW				(0xd9	| (4 << 16))
+#define T_FFTSIZE			(0xda	| (4 << 16))
+#define T_DUPLEX_MODE			(0xdb	| (4 << 16))
+
+struct hci_s {
+	unsigned short cmd_evt;
+	unsigned short length;
+	unsigned char  data[0];
+} __packed;
+
+#endif
diff --git a/drivers/staging/gdm72xx/netlink_k.c b/drivers/staging/gdm72xx/netlink_k.c
new file mode 100644
index 0000000..292af0f
--- /dev/null
+++ b/drivers/staging/gdm72xx/netlink_k.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/netlink.h>
+#include <asm/byteorder.h>
+#include <net/sock.h>
+
+#if !defined(NLMSG_HDRLEN)
+#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#endif
+
+#define ND_MAX_GROUP			30
+#define ND_IFINDEX_LEN			sizeof(int)
+#define ND_NLMSG_SPACE(len)		(NLMSG_SPACE(len) + ND_IFINDEX_LEN)
+#define ND_NLMSG_DATA(nlh) \
+	((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN))
+#define ND_NLMSG_S_LEN(len)		(len+ND_IFINDEX_LEN)
+#define ND_NLMSG_R_LEN(nlh)		(nlh->nlmsg_len-ND_IFINDEX_LEN)
+#define ND_NLMSG_IFIDX(nlh)		NLMSG_DATA(nlh)
+#define ND_MAX_MSG_LEN			8096
+
+#if defined(DEFINE_MUTEX)
+static DEFINE_MUTEX(netlink_mutex);
+#else
+static struct semaphore netlink_mutex;
+#define mutex_lock(x)		down(x)
+#define mutex_unlock(x)		up(x)
+#endif
+
+static void (*rcv_cb)(struct net_device *dev, u16 type, void *msg, int len);
+
+static void netlink_rcv_cb(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+	struct net_device *dev;
+	u32 mlen;
+	void *msg;
+	int ifindex;
+
+	if (skb->len >= NLMSG_SPACE(0)) {
+		nlh = (struct nlmsghdr *)skb->data;
+
+		if (skb->len < nlh->nlmsg_len ||
+		nlh->nlmsg_len > ND_MAX_MSG_LEN) {
+			printk(KERN_ERR "Invalid length (%d,%d)\n", skb->len,
+				nlh->nlmsg_len);
+			return;
+		}
+
+		memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN);
+		msg = ND_NLMSG_DATA(nlh);
+		mlen = ND_NLMSG_R_LEN(nlh);
+
+		if (rcv_cb) {
+			dev = dev_get_by_index(&init_net, ifindex);
+			if (dev) {
+				rcv_cb(dev, nlh->nlmsg_type, msg, mlen);
+				dev_put(dev);
+			} else
+				printk(KERN_ERR "dev_get_by_index(%d) "
+					"is not found.\n", ifindex);
+		} else
+			printk(KERN_ERR "Unregistered Callback\n");
+	}
+}
+
+static void netlink_rcv(struct sk_buff *skb)
+{
+	mutex_lock(&netlink_mutex);
+	netlink_rcv_cb(skb);
+	mutex_unlock(&netlink_mutex);
+}
+
+struct sock *netlink_init(int unit, void (*cb)(struct net_device *dev, u16 type,
+						void *msg, int len))
+{
+	struct sock *sock;
+
+#if !defined(DEFINE_MUTEX)
+	init_MUTEX(&netlink_mutex);
+#endif
+
+	sock = netlink_kernel_create(&init_net, unit, 0, netlink_rcv, NULL,
+					THIS_MODULE);
+
+	if (sock)
+		rcv_cb = cb;
+
+	return sock;
+}
+
+void netlink_exit(struct sock *sock)
+{
+	sock_release(sock->sk_socket);
+}
+
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
+{
+	static u32 seq;
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh;
+	int ret = 0;
+
+	if (group > ND_MAX_GROUP) {
+		printk(KERN_ERR "Group %d is invalied.\n", group);
+		printk(KERN_ERR "Valid group is 0 ~ %d.\n", ND_MAX_GROUP);
+		return -EINVAL;
+	}
+
+	skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_ERR "netlink_broadcast ret=%d\n", ret);
+		return -ENOMEM;
+	}
+
+	seq++;
+	nlh = NLMSG_PUT(skb, 0, seq, type, len);
+	memcpy(NLMSG_DATA(nlh), msg, len);
+
+	NETLINK_CB(skb).pid = 0;
+	NETLINK_CB(skb).dst_group = 0;
+
+	ret = netlink_broadcast(sock, skb, 0, group+1, GFP_ATOMIC);
+
+	if (!ret)
+		return len;
+	else {
+		if (ret != -ESRCH) {
+			printk(KERN_ERR "netlink_broadcast g=%d, t=%d, l=%d, r=%d\n",
+				group, type, len, ret);
+		}
+		ret = 0;
+	}
+
+nlmsg_failure:
+	return ret;
+}
diff --git a/drivers/staging/gdm72xx/netlink_k.h b/drivers/staging/gdm72xx/netlink_k.h
new file mode 100644
index 0000000..1dffaa6
--- /dev/null
+++ b/drivers/staging/gdm72xx/netlink_k.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#if !defined(NETLINK_H_20081202)
+#define NETLINK_H_20081202
+#include <linux/netdevice.h>
+#include <net/sock.h>
+
+struct sock *netlink_init(int unit,
+	void (*cb)(struct net_device *dev, u16 type, void *msg, int len));
+void netlink_exit(struct sock *sock);
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len);
+
+#endif
diff --git a/drivers/staging/gdm72xx/sdio_boot.c b/drivers/staging/gdm72xx/sdio_boot.c
new file mode 100644
index 0000000..6ff4dc3
--- /dev/null
+++ b/drivers/staging/gdm72xx/sdio_boot.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "gdm_sdio.h"
+
+#define TYPE_A_HEADER_SIZE	4
+#define TYPE_A_LOOKAHEAD_SIZE   16
+#define YMEM0_SIZE			0x8000	/* 32kbytes */
+#define DOWNLOAD_SIZE		(YMEM0_SIZE - TYPE_A_HEADER_SIZE)
+
+#define KRN_PATH	"/lib/firmware/gdm72xx/gdmskrn.bin"
+#define RFS_PATH	"/lib/firmware/gdm72xx/gdmsrfs.bin"
+
+static u8 *tx_buf;
+
+static int ack_ready(struct sdio_func *func)
+{
+	unsigned long start = jiffies;
+	u8 val;
+	int ret;
+
+	while ((jiffies - start) < HZ) {
+		val = sdio_readb(func, 0x13, &ret);
+		if (val & 0x01)
+			return 1;
+		schedule();
+	}
+
+	return 0;
+}
+
+static int download_image(struct sdio_func *func, char *img_name)
+{
+	int ret = 0, len, size, pno;
+	struct file *filp = NULL;
+	struct inode *inode = NULL;
+	u8 *buf = tx_buf;
+	loff_t pos = 0;
+
+	filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
+	if (IS_ERR(filp)) {
+		printk(KERN_ERR "Can't find %s.\n", img_name);
+		return -ENOENT;
+	}
+
+	if (filp->f_dentry)
+		inode = filp->f_dentry->d_inode;
+	if (!inode || !S_ISREG(inode->i_mode)) {
+		printk(KERN_ERR "Invalid file type: %s\n", img_name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	size = i_size_read(inode->i_mapping->host);
+	if (size <= 0) {
+		printk(KERN_ERR "Unable to find file size: %s\n", img_name);
+		ret = size;
+		goto out;
+	}
+
+	pno = 0;
+	while ((len = filp->f_op->read(filp, buf + TYPE_A_HEADER_SIZE,
+					DOWNLOAD_SIZE, &pos))) {
+		if (len < 0) {
+			ret = -1;
+			goto out;
+		}
+
+		buf[0] = len & 0xff;
+		buf[1] = (len >> 8) & 0xff;
+		buf[2] = (len >> 16) & 0xff;
+
+		if (pos >= size)	/* The last packet */
+			buf[3] = 2;
+		else
+			buf[3] = 0;
+
+		ret = sdio_memcpy_toio(func, 0, buf, len + TYPE_A_HEADER_SIZE);
+		if (ret < 0) {
+			printk(KERN_ERR "gdmwm: send image error: "
+				"packet number = %d ret = %d\n", pno, ret);
+			goto out;
+		}
+		if (buf[3] == 2)	/* The last packet */
+			break;
+		if (!ack_ready(func)) {
+			ret = -EIO;
+			printk(KERN_ERR "gdmwm: Ack is not ready.\n");
+			goto out;
+		}
+		ret = sdio_memcpy_fromio(func, buf, 0, TYPE_A_LOOKAHEAD_SIZE);
+		if (ret < 0) {
+			printk(KERN_ERR "gdmwm: receive ack error: "
+				"packet number = %d ret = %d\n", pno, ret);
+			goto out;
+		}
+		sdio_writeb(func, 0x01, 0x13, &ret);
+		sdio_writeb(func, 0x00, 0x10, &ret);	/* PCRRT */
+
+		pno++;
+	}
+out:
+	filp_close(filp, current->files);
+	return ret;
+}
+
+int sdio_boot(struct sdio_func *func)
+{
+	static mm_segment_t fs;
+	int ret;
+
+	tx_buf = kmalloc(YMEM0_SIZE, GFP_KERNEL);
+	if (tx_buf == NULL) {
+		printk(KERN_ERR "Error: kmalloc: %s %d\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	fs = get_fs();
+	set_fs(get_ds());
+
+	ret = download_image(func, KRN_PATH);
+	if (ret)
+		goto restore_fs;
+	printk(KERN_INFO "GCT: Kernel download success.\n");
+
+	ret = download_image(func, RFS_PATH);
+	if (ret)
+		goto restore_fs;
+	printk(KERN_INFO "GCT: Filesystem download success.\n");
+
+restore_fs:
+	set_fs(fs);
+	kfree(tx_buf);
+	return ret;
+}
diff --git a/drivers/staging/gdm72xx/sdio_boot.h b/drivers/staging/gdm72xx/sdio_boot.h
new file mode 100644
index 0000000..373ac28
--- /dev/null
+++ b/drivers/staging/gdm72xx/sdio_boot.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SDIO_BOOT_H__
+#define __SDIO_BOOT_H__
+
+struct sdio_func;
+
+extern int sdio_boot(struct sdio_func *func);
+
+#endif /* __SDIO_BOOT_H__ */
diff --git a/drivers/staging/gdm72xx/usb_boot.c b/drivers/staging/gdm72xx/usb_boot.c
new file mode 100644
index 0000000..5a0e030
--- /dev/null
+++ b/drivers/staging/gdm72xx/usb_boot.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include "gdm_usb.h"
+#include "usb_boot.h"
+
+#define DN_KERNEL_MAGIC_NUMBER		0x10760001
+#define DN_ROOTFS_MAGIC_NUMBER		0x10760002
+
+#define DOWNLOAD_SIZE	1024
+
+#define DH2B(x)		__cpu_to_be32(x)
+#define DL2H(x)		__le32_to_cpu(x)
+
+#define MIN(a, b)	((a) > (b) ? (b) : (a))
+
+#define MAX_IMG_CNT		16
+#define UIMG_PATH		"/lib/firmware/gdm72xx/gdmuimg.bin"
+#define KERN_PATH		"/lib/firmware/gdm72xx/zImage"
+#define FS_PATH			"/lib/firmware/gdm72xx/ramdisk.jffs2"
+
+struct dn_header {
+	u32	magic_num;
+	u32	file_size;
+};
+
+struct img_header {
+	u32		magic_code;
+	u32		count;
+	u32		len;
+	u32		offset[MAX_IMG_CNT];
+	char	hostname[32];
+	char	date[32];
+};
+
+struct fw_info {
+	u32		id;
+	u32		len;
+	u32		kernel_len;
+	u32		rootfs_len;
+	u32		kernel_offset;
+	u32		rootfs_offset;
+	u32		fw_ver;
+	u32		mac_ver;
+	char	hostname[32];
+	char	userid[16];
+	char	date[32];
+	char	user_desc[128];
+};
+
+static void array_le32_to_cpu(u32 *arr, int num)
+{
+	int i;
+	for (i = 0; i < num; i++, arr++)
+		*arr = DL2H(*arr);
+}
+
+static u8 *tx_buf;
+
+static int gdm_wibro_send(struct usb_device *usbdev, void *data, int len)
+{
+	int ret;
+	int actual;
+
+	ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), data, len,
+			&actual, 1000);
+
+	if (ret < 0) {
+		printk(KERN_ERR "Error : usb_bulk_msg ( result = %d )\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int gdm_wibro_recv(struct usb_device *usbdev, void *data, int len)
+{
+	int ret;
+	int actual;
+
+	ret = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), data, len,
+			&actual, 5000);
+
+	if (ret < 0) {
+		printk(KERN_ERR "Error : usb_bulk_msg(recv) ( result = %d )\n",
+			ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int download_image(struct usb_device *usbdev, struct file *filp,
+				loff_t *pos, u32 img_len, u32 magic_num)
+{
+	struct dn_header h;
+	int ret = 0;
+	u32 size;
+	int len, readn;
+
+	size = (img_len + DOWNLOAD_SIZE - 1) & ~(DOWNLOAD_SIZE - 1);
+	h.magic_num = DH2B(magic_num);
+	h.file_size = DH2B(size);
+
+	ret = gdm_wibro_send(usbdev, &h, sizeof(h));
+	if (ret < 0)
+		goto out;
+
+	readn = 0;
+	while ((len = filp->f_op->read(filp, tx_buf, DOWNLOAD_SIZE, pos))) {
+
+		if (len < 0) {
+			ret = -1;
+			goto out;
+		}
+		readn += len;
+
+		ret = gdm_wibro_send(usbdev, tx_buf, DOWNLOAD_SIZE);
+		if (ret < 0)
+			goto out;
+		if (readn >= img_len)
+			break;
+	}
+
+	if (readn < img_len) {
+		printk(KERN_ERR "gdmwm: Cannot read to the requested size. "
+			"Read = %d Requested = %d\n", readn, img_len);
+		ret = -EIO;
+	}
+out:
+
+	return ret;
+}
+
+int usb_boot(struct usb_device *usbdev, u16 pid)
+{
+	int i, ret = 0;
+	struct file *filp = NULL;
+	struct inode *inode = NULL;
+	static mm_segment_t fs;
+	struct img_header hdr;
+	struct fw_info fw_info;
+	loff_t pos = 0;
+	char *img_name = UIMG_PATH;
+	int len;
+
+	tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL);
+	if (tx_buf == NULL) {
+		printk(KERN_ERR "Error: kmalloc\n");
+		return -ENOMEM;
+	}
+
+	fs = get_fs();
+	set_fs(get_ds());
+
+	filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
+	if (IS_ERR(filp)) {
+		printk(KERN_ERR "Can't find %s.\n", img_name);
+		set_fs(fs);
+		ret = -ENOENT;
+		goto restore_fs;
+	}
+
+	if (filp->f_dentry)
+		inode = filp->f_dentry->d_inode;
+	if (!inode || !S_ISREG(inode->i_mode)) {
+		printk(KERN_ERR "Invalid file type: %s\n", img_name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	len = filp->f_op->read(filp, (u8 *)&hdr, sizeof(hdr), &pos);
+	if (len != sizeof(hdr)) {
+		printk(KERN_ERR "gdmwm: Cannot read the image info.\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	array_le32_to_cpu((u32 *)&hdr, 19);
+#if 0
+	if (hdr.magic_code != 0x10767fff) {
+		printk(KERN_ERR "gdmwm: Invalid magic code 0x%08x\n",
+			hdr.magic_code);
+		ret = -EINVAL;
+		goto out;
+	}
+#endif
+	if (hdr.count > MAX_IMG_CNT) {
+		printk(KERN_ERR "gdmwm: Too many images. %d\n", hdr.count);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	for (i = 0; i < hdr.count; i++) {
+		if (hdr.offset[i] > hdr.len) {
+			printk(KERN_ERR "gdmwm: Invalid offset. "
+				"Entry = %d Offset = 0x%08x "
+				"Image length = 0x%08x\n",
+				i, hdr.offset[i], hdr.len);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		pos = hdr.offset[i];
+		len = filp->f_op->read(filp, (u8 *)&fw_info, sizeof(fw_info),
+					&pos);
+		if (len != sizeof(fw_info)) {
+			printk(KERN_ERR "gdmwm: Cannot read the FW info.\n");
+			ret = -EIO;
+			goto out;
+		}
+
+		array_le32_to_cpu((u32 *)&fw_info, 8);
+#if 0
+		if ((fw_info.id & 0xfffff000) != 0x10767000) {
+			printk(KERN_ERR "gdmwm: Invalid FW id. 0x%08x\n",
+				fw_info.id);
+			ret = -EIO;
+			goto out;
+		}
+#endif
+
+		if ((fw_info.id & 0xffff) != pid)
+			continue;
+
+		pos = hdr.offset[i] + fw_info.kernel_offset;
+		ret = download_image(usbdev, filp, &pos, fw_info.kernel_len,
+				DN_KERNEL_MAGIC_NUMBER);
+		if (ret < 0)
+			goto out;
+		printk(KERN_INFO "GCT: Kernel download success.\n");
+
+		pos = hdr.offset[i] + fw_info.rootfs_offset;
+		ret = download_image(usbdev, filp, &pos, fw_info.rootfs_len,
+				DN_ROOTFS_MAGIC_NUMBER);
+		if (ret < 0)
+			goto out;
+		printk(KERN_INFO "GCT: Filesystem download success.\n");
+
+		break;
+	}
+
+	if (i == hdr.count) {
+		printk(KERN_ERR "Firmware for gsk%x is not installed.\n", pid);
+		ret = -EINVAL;
+	}
+out:
+	filp_close(filp, current->files);
+
+restore_fs:
+	set_fs(fs);
+	kfree(tx_buf);
+	return ret;
+}
+
+/*#define GDM7205_PADDING		256 */
+#define DOWNLOAD_CHUCK			2048
+#define KERNEL_TYPE_STRING		"linux"
+#define FS_TYPE_STRING			"rootfs"
+
+static int em_wait_ack(struct usb_device *usbdev, int send_zlp)
+{
+	int ack;
+	int ret = -1;
+
+	if (send_zlp) {
+		/*Send ZLP*/
+		ret = gdm_wibro_send(usbdev, NULL, 0);
+		if (ret < 0)
+			goto out;
+	}
+
+	/*Wait for ACK*/
+	ret = gdm_wibro_recv(usbdev, &ack, sizeof(ack));
+	if (ret < 0)
+		goto out;
+out:
+	return ret;
+}
+
+static int em_download_image(struct usb_device *usbdev, char *path,
+				char *type_string)
+{
+	struct file *filp;
+	struct inode *inode;
+	static mm_segment_t fs;
+	char *buf = NULL;
+	loff_t pos = 0;
+	int ret = 0;
+	int len, readn = 0;
+	#if defined(GDM7205_PADDING)
+	const int pad_size = GDM7205_PADDING;
+	#else
+	const int pad_size = 0;
+	#endif
+
+	fs = get_fs();
+	set_fs(get_ds());
+
+	filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0);
+	if (IS_ERR(filp)) {
+		printk(KERN_ERR "Can't find %s.\n", path);
+		set_fs(fs);
+		ret = -ENOENT;
+		goto restore_fs;
+	}
+
+	if (filp->f_dentry) {
+		inode = filp->f_dentry->d_inode;
+		if (!inode || !S_ISREG(inode->i_mode)) {
+			printk(KERN_ERR "Invalid file type: %s\n", path);
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	buf = kmalloc(DOWNLOAD_CHUCK + pad_size, GFP_KERNEL);
+	if (buf == NULL) {
+		printk(KERN_ERR "Error: kmalloc\n");
+		return -ENOMEM;
+	}
+
+	strcpy(buf+pad_size, type_string);
+	ret = gdm_wibro_send(usbdev, buf, strlen(type_string)+pad_size);
+	if (ret < 0)
+		goto out;
+
+	while ((len = filp->f_op->read(filp, buf+pad_size, DOWNLOAD_CHUCK,
+					&pos))) {
+		if (len < 0) {
+			ret = -1;
+			goto out;
+		}
+		readn += len;
+
+		ret = gdm_wibro_send(usbdev, buf, len+pad_size);
+		if (ret < 0)
+			goto out;
+
+		ret = em_wait_ack(usbdev, ((len+pad_size) % 512 == 0));
+		if (ret < 0)
+			goto out;
+	}
+
+	ret = em_wait_ack(usbdev, 1);
+	if (ret < 0)
+		goto out;
+
+out:
+	filp_close(filp, current->files);
+
+restore_fs:
+	set_fs(fs);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static int em_fw_reset(struct usb_device *usbdev)
+{
+	int ret;
+
+	/*Send ZLP*/
+	ret = gdm_wibro_send(usbdev, NULL, 0);
+	return ret;
+}
+
+int usb_emergency(struct usb_device *usbdev)
+{
+	int ret;
+
+	ret = em_download_image(usbdev, KERN_PATH, KERNEL_TYPE_STRING);
+	if (ret < 0)
+		goto out;
+	printk(KERN_INFO "GCT Emergency: Kernel download success.\n");
+
+	ret = em_download_image(usbdev, FS_PATH, FS_TYPE_STRING);
+	if (ret < 0)
+		goto out;
+	printk(KERN_INFO "GCT Emergency: Filesystem download success.\n");
+
+	ret = em_fw_reset(usbdev);
+out:
+	return ret;
+}
diff --git a/drivers/staging/gdm72xx/usb_boot.h b/drivers/staging/gdm72xx/usb_boot.h
new file mode 100644
index 0000000..c715cd3
--- /dev/null
+++ b/drivers/staging/gdm72xx/usb_boot.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __USB_BOOT_H__
+#define __USB_BOOT_H__
+
+struct usb_device;
+
+extern int usb_boot(struct usb_device *usbdev, u16 pid);
+extern int usb_emergency(struct usb_device *usbdev);
+
+#endif /* __USB_BOOT_H__ */
diff --git a/drivers/staging/gdm72xx/usb_ids.h b/drivers/staging/gdm72xx/usb_ids.h
new file mode 100644
index 0000000..b34616b
--- /dev/null
+++ b/drivers/staging/gdm72xx/usb_ids.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __USB_IDS_H__
+#define __USB_IDS_H__
+
+/*You can replace vendor-ID as yours.*/
+#define GCT_VID			0x1076
+
+/*You can replace product-ID as yours.*/
+#define GCT_PID1			0x7e00
+#define GCT_PID2			0x7f00
+
+#define USB_DEVICE_ID_MATCH_DEVICE_INTERFACE	\
+	(USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_CLASS)
+
+#define USB_DEVICE_INTF(vend, prod, intf)	\
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE_INTERFACE,	\
+	.idVendor = (vend), .idProduct = (prod), .bInterfaceClass = (intf)
+
+#define EMERGENCY_PID		0x720f
+#define BL_PID_MASK			0xffc0
+
+#define USB_DEVICE_BOOTLOADER(vid, pid)	\
+	{USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD)},	\
+	{USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD|B_DIFF_DL_DRV)}
+
+#define USB_DEVICE_CDC_DATA(vid, pid)	\
+	{USB_DEVICE_INTF((vid), (pid), USB_CLASS_CDC_DATA)}
+
+static const struct usb_device_id id_table[] = {
+	USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID1),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x1),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x2),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x3),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x4),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x5),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x6),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x7),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x8),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x9),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xa),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xb),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xc),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xd),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xe),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xf),
+
+	USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID2),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x1),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x2),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x3),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x4),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x5),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x6),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x7),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x8),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x9),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xa),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xb),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xc),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xd),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xe),
+	USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xf),
+
+	{USB_DEVICE(GCT_VID, EMERGENCY_PID)},
+	{ }
+};
+
+#endif /* __USB_IDS_H__ */
diff --git a/drivers/staging/gdm72xx/wm_ioctl.h b/drivers/staging/gdm72xx/wm_ioctl.h
new file mode 100644
index 0000000..9f46e06
--- /dev/null
+++ b/drivers/staging/gdm72xx/wm_ioctl.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#if !defined(WM_IOCTL_H_20080714)
+#define WM_IOCTL_H_20080714
+#if !defined(__KERNEL__)
+#include <net/if.h>
+#endif
+
+#define NETLINK_WIMAX	31
+
+#define SIOCWMIOCTL			SIOCDEVPRIVATE
+
+#define SIOCG_DATA			0x8D10
+#define SIOCS_DATA			0x8D11
+
+enum {
+	SIOC_DATA_FSM,
+	SIOC_DATA_NETLIST,
+	SIOC_DATA_CONNNSP,
+	SIOC_DATA_CONNCOMP,
+	SIOC_DATA_PROFILEID,
+
+	SIOC_DATA_END
+};
+
+#define SIOC_DATA_MAX			16
+
+/* FSM */
+enum {
+	M_INIT = 0,
+	M_OPEN_OFF,
+	M_OPEN_ON,
+	M_SCAN,
+	M_CONNECTING,
+	M_CONNECTED,
+	M_FSM_END,
+
+	C_INIT = 0,
+	C_CONNSTART,
+	C_ASSOCSTART,
+	C_RNG,
+	C_SBC,
+	C_AUTH,
+	C_REG,
+	C_DSX,
+	C_ASSOCCOMPLETE,
+	C_CONNCOMPLETE,
+	C_FSM_END,
+
+	D_INIT = 0,
+	D_READY,
+	D_LISTEN,
+	D_IPACQUISITION,
+
+	END_FSM
+};
+
+struct fsm_s {
+	int		m_status;	/*main status*/
+	int		c_status;	/*connection status*/
+	int		d_status;	/*oma-dm status*/
+};
+
+struct data_s {
+	int		size;
+	void	*buf;
+};
+
+struct wm_req_s {
+	union {
+		char	ifrn_name[IFNAMSIZ];
+	} ifr_ifrn;
+
+	unsigned short	cmd;
+
+	unsigned short	data_id;
+	struct data_s	data;
+
+/* NOTE: sizeof(struct wm_req_s) must be less than sizeof(struct ifreq). */
+};
+
+#ifndef ifr_name
+#define ifr_name	ifr_ifrn.ifrn_name
+#endif
+
+#endif
diff --git a/drivers/staging/iio/Documentation/device.txt b/drivers/staging/iio/Documentation/device.txt
index 8926f24..0338c7c 100644
--- a/drivers/staging/iio/Documentation/device.txt
+++ b/drivers/staging/iio/Documentation/device.txt
@@ -8,7 +8,7 @@
 
 First allocate one using:
 
-struct iio_dev *indio_dev = iio_allocate_device(sizeof(struct chip_state));
+struct iio_dev *indio_dev = iio_device_alloc(sizeof(struct chip_state));
 where chip_state is a structure of local state data for this instance of
 the chip.
 
@@ -78,4 +78,4 @@
 gets confused)
 
 On remove, iio_device_unregister(indio_dev) will remove the device from
-the core, and iio_free_device will clean up.
+the core, and iio_device_free will clean up.
diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c
index 69a05b9..bf55335 100644
--- a/drivers/staging/iio/Documentation/generic_buffer.c
+++ b/drivers/staging/iio/Documentation/generic_buffer.c
@@ -60,9 +60,9 @@
 	/* First swap if incorrect endian */
 
 	if (info->be)
-		input = be16toh((uint_16t)input);
+		input = be16toh((uint16_t)input);
 	else
-		input = le16toh((uint_16t)input);
+		input = le16toh((uint16_t)input);
 
 	/* shift before conversion to avoid sign extension
 	   of left aligned data */
diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c
index 0d21a27..2227584 100644
--- a/drivers/staging/iio/Documentation/iio_event_monitor.c
+++ b/drivers/staging/iio/Documentation/iio_event_monitor.c
@@ -27,7 +27,7 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include "iio_utils.h"
-#include "../events.h"
+#include <linux/iio/events.h>
 
 static const char * const iio_chan_type_name_spec[] = {
 	[IIO_VOLTAGE] = "voltage",
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583 b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
new file mode 100755
index 0000000..470f7ad
--- /dev/null
+++ b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
@@ -0,0 +1,6 @@
+What:		/sys/bus/iio/devices/device[n]/in_illuminance0_calibrate
+KernelVersion:	2.6.37
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This property causes an internal calibration of the als gain trim
+		value which is later used in calculating illuminance in lux.
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
new file mode 100755
index 0000000..b2798b2
--- /dev/null
+++ b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
@@ -0,0 +1,13 @@
+What:		/sys/bus/iio/devices/device[n]/in_illuminance0_calibrate
+KernelVersion:	3.3-rc1
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Causes an internal calibration of the als gain trim
+		value which is later used in calculating illuminance in lux.
+
+What:		/sys/bus/iio/devices/device[n]/in_proximity0_calibrate
+KernelVersion:	3.3-rc1
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Causes a recalculation and adjustment to the
+		proximity_thresh_rising_value.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio
deleted file mode 100644
index 46a995d..0000000
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio
+++ /dev/null
@@ -1,741 +0,0 @@
-What:		/sys/bus/iio/devices/iio:deviceX
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Hardware chip or device accessed by one communication port.
-		Corresponds to a grouping of sensor channels. X is the IIO
-		index of the device.
-
-What:		/sys/bus/iio/devices/triggerX
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		An event driven driver of data capture to an in kernel buffer.
-		May be provided by a device driver that also has an IIO device
-		based on hardware generated events (e.g. data ready) or
-		provided by a separate driver for other hardware (e.g.
-		periodic timer, GPIO or high resolution timer).
-		Contains trigger type specific elements. These do not
-		generalize well and hence are not documented in this file.
-		X is the IIO index of the trigger.
-
-What:		/sys/bus/iio/devices/iio:deviceX/buffer
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Directory of attributes relating to the buffer for the device.
-
-What:		/sys/bus/iio/devices/iio:deviceX/name
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Description of the physical chip / device for device X.
-		Typically a part number.
-
-What:		/sys/bus/iio/devices/iio:deviceX/sampling_frequency
-What:		/sys/bus/iio/devices/iio:deviceX/buffer/sampling_frequency
-What:		/sys/bus/iio/devices/triggerX/sampling_frequency
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Some devices have internal clocks.  This parameter sets the
-		resulting sampling frequency.  In many devices this
-		parameter has an effect on input filters etc rather than
-		simply controlling when the input is sampled.  As this
-		effects datardy triggers, hardware buffers and the sysfs
-		direct access interfaces, it may be found in any of the
-		relevant directories.  If it effects all of the above
-		then it is to be found in the base device directory.
-
-What:		/sys/bus/iio/devices/iio:deviceX/sampling_frequency_available
-What:		/sys/.../iio:deviceX/buffer/sampling_frequency_available
-What:		/sys/bus/iio/devices/triggerX/sampling_frequency_available
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		When the internal sampling clock can only take a small
-		discrete set of values, this file lists those available.
-
-What:		/sys/bus/iio/devices/iio:deviceX/oversampling_ratio
-KernelVersion:	2.6.38
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Hardware dependent ADC oversampling. Controls the sampling ratio
-		of the digital filter if available.
-
-What:		/sys/bus/iio/devices/iio:deviceX/oversampling_ratio_available
-KernelVersion:	2.6.38
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Hardware dependent values supported by the oversampling filter.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Raw (unscaled no bias removal etc) voltage measurement from
-		channel Y. In special cases where the channel does not
-		correspond to externally available input one of the named
-		versions may be used. The number must always be specified and
-		unique to allow association with event codes. Units after
-		application of scale and offset are microvolts.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_raw
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Raw (unscaled) differential voltage measurement equivalent to
-		channel Y - channel Z where these channel numbers apply to the
-		physically equivalent inputs when non differential readings are
-		separately available. In differential only parts, then all that
-		is required is a consistent labeling.  Units after application
-		of scale and offset are microvolts.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw
-KernelVersion:	3.2
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Raw capacitance measurement from channel Y. Units after
-		application of scale and offset are nanofarads.
-
-What:		/sys/.../iio:deviceX/in_capacitanceY-in_capacitanceZ_raw
-KernelVersion:	3.2
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Raw differential capacitance measurement equivalent to
-		channel Y - channel Z where these channel numbers apply to the
-		physically equivalent inputs when non differential readings are
-		separately available. In differential only parts, then all that
-		is required is a consistent labeling.  Units after application
-		of scale and offset are nanofarads..
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_temp_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_tempX_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_temp_x_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_temp_y_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_temp_z_raw
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Raw (unscaled no bias removal etc) temperature measurement.
-		It an axis is specified it generally means that the temperature
-		sensor is associated with one part of a compound device (e.g.
-		a gyroscope axis). Units after application of scale and offset
-		are milli degrees Celsuis.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_tempX_input
-KernelVersion:	2.6.38
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Scaled temperature measurement in milli degrees Celsius.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_x_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_raw
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Acceleration in direction x, y or z (may be arbitrarily assigned
-		but should match other such assignments on device).
-		Has all of the equivalent parameters as per voltageY. Units
-		after application of scale and offset are m/s^2.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_x_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_y_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_z_raw
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Angular velocity about axis x, y or z (may be arbitrarily
-		assigned) Data converted by application of offset then scale to
-		radians per second. Has all the equivalent parameters as
-		per voltageY. Units after application of scale and offset are
-		radians per second.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_incli_x_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_incli_y_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_incli_z_raw
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Inclination raw reading about axis x, y or z (may be
-		arbitrarily assigned). Data converted by application of offset
-		and scale to Degrees.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_magn_z_raw
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Magnetic field along axis x, y or z (may be arbitrarily
-		assigned).  Data converted by application of offset
-		then scale to Gauss.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_x_peak_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_peak_raw
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_peak_raw
-KernelVersion:	2.6.36
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Highest value since some reset condition.  These
-		attributes allow access to this and are otherwise
-		the direct equivalent of the <type>Y[_name]_raw attributes.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_xyz_squared_peak_raw
-KernelVersion:	2.6.36
-Contact:	linux-iio@vger.kernel.org
-Description:
-		A computed peak value based on the sum squared magnitude of
-		the underlying value in the specified directions.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_offset
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_x_offset
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
-What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
-What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_offset
-What:		/sys/bus/iio/devices/iio:deviceX/in_tempY_offset
-What:		/sys/bus/iio/devices/iio:deviceX/in_temp_offset
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		If known for a device, offset to be added to <type>[Y]_raw prior
-		to scaling by <type>[Y]_scale in order to obtain value in the
-		<type> units as specified in <type>[y]_raw documentation.
-		Not present if the offset is always 0 or unknown. If Y or
-		axis <x|y|z> is not present, then the offset applies to all
-		in channels of <type>.
-		May be writable if a variable offset can be applied on the
-		device. Note that this is different to calibbias which
-		is for devices (or drivers) that apply offsets to compensate
-		for variation between different instances of the part, typically
-		adjusted by using some hardware supported calibration procedure.
-		Calibbias is applied internally, offset is applied in userspace
-		to the _raw output.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
-What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
-What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_scale
-What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
-What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
-What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
-What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
-What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
-What:		/sys/bus/iio/devices/iio:deviceX/in_magn_z_scale
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		If known for a device, scale to be applied to <type>Y[_name]_raw
-		post addition of <type>[Y][_name]_offset in order to obtain the
-		measured value in <type> units as specified in
-		<type>[Y][_name]_raw documentation..  If shared across all in
-		channels then Y and <x|y|z> are not present and the value is
-		called <type>[Y][_name]_scale. The peak modifier means this
-		value is applied to <type>Y[_name]_peak_raw values.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_x_calibbias
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_calibbias
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias
-What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias
-What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias
-What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Hardware applied calibration offset. (assumed to fix production
-		inaccuracies).
-
-What		/sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
-What		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
-What		/sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
-What		/sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
-What		/sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
-What		/sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
-What		/sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale
-What		/sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale
-What		/sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Hardware applied calibration scale factor. (assumed to fix
-		production inaccuracies).  If shared across all channels,
-		<type>_calibscale is used.
-
-What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
-What:		/sys/.../iio:deviceX/in_voltageX_scale_available
-What:		/sys/.../iio:deviceX/in_voltage-voltage_scale_available
-What:		/sys/.../iio:deviceX/out_voltageX_scale_available
-What:		/sys/.../iio:deviceX/in_capacitance_scale_available
-KernelVersion:	2.635
-Contact:	linux-iio@vger.kernel.org
-Description:
-		If a discrete set of scale values are available, they
-		are listed in this attribute.
-
-What:		/sys/.../in_accel_filter_low_pass_3db_frequency
-What:		/sys/.../in_magn_filter_low_pass_3db_frequency
-What:		/sys/.../in_anglvel_filter_low_pass_3db_frequency
-KernelVersion:	3.2
-Contact:	linux-iio@vger.kernel.org
-Description:
-		If a known or controllable low pass filter is applied
-		to the underlying data channel, then this parameter
-		gives the 3dB frequency of the filter in Hz.
-
-What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_raw
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Raw (unscaled, no bias etc.) output voltage for
-		channel Y.  The number must always be specified and
-		unique if the output corresponds to a single channel.
-
-What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY&Z_raw
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Raw (unscaled, no bias etc.) output voltage for an aggregate of
-		channel Y, channel Z, etc.  This interface is available in cases
-		where a single output sets the value for multiple channels
-		simultaneously.
-
-What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown_mode
-What:		/sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown_mode
-KernelVersion:	2.6.38
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Specifies the output powerdown mode.
-		DAC output stage is disconnected from the amplifier and
-		1kohm_to_gnd: connected to ground via an 1kOhm resistor
-		100kohm_to_gnd: connected to ground via an 100kOhm resistor
-		three_state: left floating
-		For a list of available output power down options read
-		outX_powerdown_mode_available. If Y is not present the
-		mode is shared across all outputs.
-
-What:		/sys/.../iio:deviceX/out_votlageY_powerdown_mode_available
-What:		/sys/.../iio:deviceX/out_voltage_powerdown_mode_available
-KernelVersion:	2.6.38
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Lists all available output power down modes.
-		If Y is not present the mode is shared across all outputs.
-
-What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown
-What:		/sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown
-KernelVersion:	2.6.38
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Writing 1 causes output Y to enter the power down mode specified
-		by the corresponding outY_powerdown_mode. Clearing returns to
-		normal operation. Y may be suppressed if all outputs are
-		controlled together.
-
-What:		/sys/bus/iio/devices/iio:deviceX/events
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Configuration of which hardware generated events are passed up
-		to user-space.
-
-What:		/sys/.../iio:deviceX/events/in_accel_x_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_x_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_accel_y_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_y_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_accel_z_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_z_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_x_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_x_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_y_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_y_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_z_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_z_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_magn_x_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_magn_x_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_magn_y_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_magn_y_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_magn_z_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_magn_z_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en
-What:		/sys/.../iio:deviceX/events/in_tempY_thresh_rising_en
-What:		/sys/.../iio:deviceX/events/in_tempY_thresh_falling_en
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Event generated when channel passes a threshold in the specified
-		(_rising|_falling) direction. If the direction is not specified,
-		then either the device will report an event which ever direction
-		a single threshold value is passed in (e.g.
-		<type>[Y][_name]_<raw|input>_thresh_value) or
-		<type>[Y][_name]_<raw|input>_thresh_rising_value and
-		<type>[Y][_name]_<raw|input>_thresh_falling_value may take
-		different values, but the device can only enable both thresholds
-		or neither.
-		Note the driver will assume the last p events requested are
-		to be enabled where p is however many it supports (which may
-		vary depending on the exact set requested. So if you want to be
-		sure you have set what you think you have, check the contents of
-		these attributes after everything is configured. Drivers may
-		have to buffer any parameters so that they are consistent when
-		a given event type is enabled a future point (and not those for
-		whatever event was previously enabled).
-
-What:		/sys/.../iio:deviceX/events/in_accel_x_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_x_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_accel_y_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_y_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_accel_z_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_z_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_x_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_x_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_y_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_y_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_z_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_anglvel_z_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_magn_x_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_magn_x_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_magn_y_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_magn_y_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_magn_z_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_magn_z_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_voltageY_supply_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_voltageY_supply_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_voltageY_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_voltageY_roc_falling_en
-What:		/sys/.../iio:deviceX/events/in_tempY_roc_rising_en
-What:		/sys/.../iio:deviceX/events/in_tempY_roc_falling_en
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Event generated when channel passes a threshold on the rate of
-		change (1st differential) in the specified (_rising|_falling)
-		direction. If the direction is not specified, then either the
-		device will report an event which ever direction a single
-		threshold value is passed in (e.g.
-		<type>[Y][_name]_<raw|input>_roc_value) or
-		<type>[Y][_name]_<raw|input>_roc_rising_value and
-		<type>[Y][_name]_<raw|input>_roc_falling_value may take
-		different values, but the device can only enable both rate of
-		change thresholds or neither.
-		Note the driver will assume the last p events requested are
-		to be enabled where p is however many it supports (which may
-		vary depending on the exact set requested. So if you want to be
-		sure you have set what you think you have, check the contents of
-		these attributes after everything is configured. Drivers may
-		have to buffer any parameters so that they are consistent when
-		a given event type is enabled a future point (and not those for
-		whatever event was previously enabled).
-
-What:		/sys/.../events/in_accel_x_raw_thresh_rising_value
-What:		/sys/.../events/in_accel_x_raw_thresh_falling_value
-What:		/sys/.../events/in_accel_y_raw_thresh_rising_value
-What:		/sys/.../events/in_accel_y_raw_thresh_falling_value
-What:		/sys/.../events/in_accel_z_raw_thresh_rising_value
-What:		/sys/.../events/in_accel_z_raw_thresh_falling_value
-What:		/sys/.../events/in_anglvel_x_raw_thresh_rising_value
-What:		/sys/.../events/in_anglvel_x_raw_thresh_falling_value
-What:		/sys/.../events/in_anglvel_y_raw_thresh_rising_value
-What:		/sys/.../events/in_anglvel_y_raw_thresh_falling_value
-What:		/sys/.../events/in_anglvel_z_raw_thresh_rising_value
-What:		/sys/.../events/in_anglvel_z_raw_thresh_falling_value
-What:		/sys/.../events/in_magn_x_raw_thresh_rising_value
-What:		/sys/.../events/in_magn_x_raw_thresh_falling_value
-What:		/sys/.../events/in_magn_y_raw_thresh_rising_value
-What:		/sys/.../events/in_magn_y_raw_thresh_falling_value
-What:		/sys/.../events/in_magn_z_raw_thresh_rising_value
-What:		/sys/.../events/in_magn_z_raw_thresh_falling_value
-What:		/sys/.../events/in_voltageY_supply_raw_thresh_rising_value
-What:		/sys/.../events/in_voltageY_supply_raw_thresh_falling_value
-What:		/sys/.../events/in_voltageY_raw_thresh_falling_value
-What:		/sys/.../events/in_voltageY_raw_thresh_falling_value
-What:		/sys/.../events/in_tempY_raw_thresh_falling_value
-What:		/sys/.../events/in_tempY_raw_thresh_falling_value
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Specifies the value of threshold that the device is comparing
-		against for the events enabled by
-		<type>Y[_name]_thresh[_rising|falling]_en.
-		If separate attributes exist for the two directions, but
-		direction is not specified for this attribute, then a single
-		threshold value applies to both directions.
-		The raw or input element of the name indicates whether the
-		value is in raw device units or in processed units (as _raw
-		and _input do on sysfs direct channel read attributes).
-
-What:		/sys/.../events/in_accel_x_raw_roc_rising_value
-What:		/sys/.../events/in_accel_x_raw_roc_falling_value
-What:		/sys/.../events/in_accel_y_raw_roc_rising_value
-What:		/sys/.../events/in_accel_y_raw_roc_falling_value
-What:		/sys/.../events/in_accel_z_raw_roc_rising_value
-What:		/sys/.../events/in_accel_z_raw_roc_falling_value
-What:		/sys/.../events/in_anglvel_x_raw_roc_rising_value
-What:		/sys/.../events/in_anglvel_x_raw_roc_falling_value
-What:		/sys/.../events/in_anglvel_y_raw_roc_rising_value
-What:		/sys/.../events/in_anglvel_y_raw_roc_falling_value
-What:		/sys/.../events/in_anglvel_z_raw_roc_rising_value
-What:		/sys/.../events/in_anglvel_z_raw_roc_falling_value
-What:		/sys/.../events/in_magn_x_raw_roc_rising_value
-What:		/sys/.../events/in_magn_x_raw_roc_falling_value
-What:		/sys/.../events/in_magn_y_raw_roc_rising_value
-What:		/sys/.../events/in_magn_y_raw_roc_falling_value
-What:		/sys/.../events/in_magn_z_raw_roc_rising_value
-What:		/sys/.../events/in_magn_z_raw_roc_falling_value
-What:		/sys/.../events/in_voltageY_supply_raw_roc_rising_value
-What:		/sys/.../events/in_voltageY_supply_raw_roc_falling_value
-What:		/sys/.../events/in_voltageY_raw_roc_falling_value
-What:		/sys/.../events/in_voltageY_raw_roc_falling_value
-What:		/sys/.../events/in_tempY_raw_roc_falling_value
-What:		/sys/.../events/in_tempY_raw_roc_falling_value
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Specifies the value of rate of change threshold that the
-		device is comparing against for the events enabled by
-		<type>[Y][_name]_roc[_rising|falling]_en.
-		If separate attributes exist for the two directions,
-		but direction is not specified for this attribute,
-		then a single threshold value applies to both directions.
-		The raw or input element of the name indicates whether the
-		value is in raw device units or in processed units (as _raw
-		and _input do on sysfs direct channel read attributes).
-
-What:		/sys/.../events/in_accel_x_thresh_rising_period
-What:		/sys/.../events/in_accel_x_thresh_falling_period
-hat:		/sys/.../events/in_accel_x_roc_rising_period
-What:		/sys/.../events/in_accel_x_roc_falling_period
-What:		/sys/.../events/in_accel_y_thresh_rising_period
-What:		/sys/.../events/in_accel_y_thresh_falling_period
-What:		/sys/.../events/in_accel_y_roc_rising_period
-What:		/sys/.../events/in_accel_y_roc_falling_period
-What:		/sys/.../events/in_accel_z_thresh_rising_period
-What:		/sys/.../events/in_accel_z_thresh_falling_period
-What:		/sys/.../events/in_accel_z_roc_rising_period
-What:		/sys/.../events/in_accel_z_roc_falling_period
-What:		/sys/.../events/in_anglvel_x_thresh_rising_period
-What:		/sys/.../events/in_anglvel_x_thresh_falling_period
-What:		/sys/.../events/in_anglvel_x_roc_rising_period
-What:		/sys/.../events/in_anglvel_x_roc_falling_period
-What:		/sys/.../events/in_anglvel_y_thresh_rising_period
-What:		/sys/.../events/in_anglvel_y_thresh_falling_period
-What:		/sys/.../events/in_anglvel_y_roc_rising_period
-What:		/sys/.../events/in_anglvel_y_roc_falling_period
-What:		/sys/.../events/in_anglvel_z_thresh_rising_period
-What:		/sys/.../events/in_anglvel_z_thresh_falling_period
-What:		/sys/.../events/in_anglvel_z_roc_rising_period
-What:		/sys/.../events/in_anglvel_z_roc_falling_period
-What:		/sys/.../events/in_magn_x_thresh_rising_period
-What:		/sys/.../events/in_magn_x_thresh_falling_period
-What:		/sys/.../events/in_magn_x_roc_rising_period
-What:		/sys/.../events/in_magn_x_roc_falling_period
-What:		/sys/.../events/in_magn_y_thresh_rising_period
-What:		/sys/.../events/in_magn_y_thresh_falling_period
-What:		/sys/.../events/in_magn_y_roc_rising_period
-What:		/sys/.../events/in_magn_y_roc_falling_period
-What:		/sys/.../events/in_magn_z_thresh_rising_period
-What:		/sys/.../events/in_magn_z_thresh_falling_period
-What:		/sys/.../events/in_magn_z_roc_rising_period
-What:		/sys/.../events/in_magn_z_roc_falling_period
-What:		/sys/.../events/in_voltageY_supply_thresh_rising_period
-What:		/sys/.../events/in_voltageY_supply_thresh_falling_period
-What:		/sys/.../events/in_voltageY_supply_roc_rising_period
-What:		/sys/.../events/in_voltageY_supply_roc_falling_period
-What:		/sys/.../events/in_voltageY_thresh_rising_period
-What:		/sys/.../events/in_voltageY_thresh_falling_period
-What:		/sys/.../events/in_voltageY_roc_rising_period
-What:		/sys/.../events/in_voltageY_roc_falling_period
-What:		/sys/.../events/in_tempY_thresh_rising_period
-What:		/sys/.../events/in_tempY_thresh_falling_period
-What:		/sys/.../events/in_tempY_roc_rising_period
-What:		/sys/.../events/in_tempY_roc_falling_period
-What:		/sys/.../events/in_accel_x&y&z_mag_falling_period
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Period of time (in seconds) for which the condition must be
-		met before an event is generated. If direction is not
-		specified then this period applies to both directions.
-
-What:		/sys/.../iio:deviceX/events/in_accel_mag_en
-What:		/sys/.../iio:deviceX/events/in_accel_mag_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_mag_falling_en
-What:		/sys/.../iio:deviceX/events/in_accel_x_mag_en
-What:		/sys/.../iio:deviceX/events/in_accel_x_mag_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_x_mag_falling_en
-What:		/sys/.../iio:deviceX/events/in_accel_y_mag_en
-What:		/sys/.../iio:deviceX/events/in_accel_y_mag_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_y_mag_falling_en
-What:		/sys/.../iio:deviceX/events/in_accel_z_mag_en
-What:		/sys/.../iio:deviceX/events/in_accel_z_mag_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_z_mag_falling_en
-What:		/sys/.../iio:deviceX/events/in_accel_x&y&z_mag_rising_en
-What:		/sys/.../iio:deviceX/events/in_accel_x&y&z_mag_falling_en
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Similar to in_accel_x_thresh[_rising|_falling]_en, but here the
-		magnitude of the channel is compared to the threshold, not its
-		signed value.
-
-What:		/sys/.../events/in_accel_raw_mag_value
-What:		/sys/.../events/in_accel_x_raw_mag_rising_value
-What:		/sys/.../events/in_accel_y_raw_mag_rising_value
-What:		/sys/.../events/in_accel_z_raw_mag_rising_value
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		The value to which the magnitude of the channel is compared. If
-		number or direction is not specified, applies to all channels of
-		this type.
-
-What:		/sys/bus/iio/devices/iio:deviceX/trigger/current_trigger
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		The name of the trigger source being used, as per string given
-		in /sys/class/iio/triggerY/name.
-
-What:		/sys/bus/iio/devices/iio:deviceX/buffer/length
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Number of scans contained by the buffer.
-
-What:		/sys/bus/iio/devices/iio:deviceX/buffer/bytes_per_datum
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Bytes per scan.  Due to alignment fun, the scan may be larger
-		than implied directly by the scan_element parameters.
-
-What:		/sys/bus/iio/devices/iio:deviceX/buffer/enable
-KernelVersion:	2.6.35
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Actually start the buffer capture up.  Will start trigger
-		if first device and appropriate.
-
-What:		/sys/bus/iio/devices/iio:deviceX/buffer/scan_elements
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Directory containing interfaces for elements that will be
-		captured for a single triggered sample set in the buffer.
-
-What:		/sys/.../buffer/scan_elements/in_accel_x_en
-What:		/sys/.../buffer/scan_elements/in_accel_y_en
-What:		/sys/.../buffer/scan_elements/in_accel_z_en
-What:		/sys/.../buffer/scan_elements/in_anglvel_x_en
-What:		/sys/.../buffer/scan_elements/in_anglvel_y_en
-What:		/sys/.../buffer/scan_elements/in_anglvel_z_en
-What:		/sys/.../buffer/scan_elements/in_magn_x_en
-What:		/sys/.../buffer/scan_elements/in_magn_y_en
-What:		/sys/.../buffer/scan_elements/in_magn_z_en
-What:		/sys/.../buffer/scan_elements/in_timestamp_en
-What:		/sys/.../buffer/scan_elements/in_voltageY_supply_en
-What:		/sys/.../buffer/scan_elements/in_voltageY_en
-What:		/sys/.../buffer/scan_elements/in_voltageY-voltageZ_en
-What:		/sys/.../buffer/scan_elements/in_incli_x_en
-What:		/sys/.../buffer/scan_elements/in_incli_y_en
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Scan element control for triggered data capture.
-
-What:		/sys/.../buffer/scan_elements/in_accel_type
-What:		/sys/.../buffer/scan_elements/in_anglvel_type
-What:		/sys/.../buffer/scan_elements/in_magn_type
-What:		/sys/.../buffer/scan_elements/in_incli_type
-What:		/sys/.../buffer/scan_elements/in_voltageY_type
-What:		/sys/.../buffer/scan_elements/in_voltage-in_type
-What:		/sys/.../buffer/scan_elements/in_voltageY_supply_type
-What:		/sys/.../buffer/scan_elements/in_timestamp_type
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Description of the scan element data storage within the buffer
-		and hence the form in which it is read from user-space.
-		Form is [be|le]:[s|u]bits/storagebits[>>shift].
-		be or le specifies big or little endian. s or u specifies if
-		signed (2's complement) or unsigned. bits is the number of bits
-		of data and storagebits is the space (after padding) that it
-		occupies in the buffer. shift if specified, is the shift that
-		needs to be applied prior to masking out unused bits. Some
-		devices put their data in the middle of the transferred elements
-		with additional information on both sides.  Note that some
-		devices will have additional information in the unused bits
-		so to get a clean value, the bits value must be used to mask
-		the buffer output value appropriately.  The storagebits value
-		also specifies the data alignment.  So s48/64>>2 will be a
-		signed 48 bit integer stored in a 64 bit location aligned to
-		a a64 bit boundary. To obtain the clean value, shift right 2
-		and apply a mask to zero the top 16 bits of the result.
-		For other storage combinations this attribute will be extended
-		appropriately.
-
-What:		/sys/.../buffer/scan_elements/in_accel_type_available
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		If the type parameter can take one of a small set of values,
-		this attribute lists them.
-
-What:		/sys/.../buffer/scan_elements/in_voltageY_index
-What:		/sys/.../buffer/scan_elements/in_voltageY_supply_index
-What:		/sys/.../buffer/scan_elements/in_accel_x_index
-What:		/sys/.../buffer/scan_elements/in_accel_y_index
-What:		/sys/.../buffer/scan_elements/in_accel_z_index
-What:		/sys/.../buffer/scan_elements/in_anglvel_x_index
-What:		/sys/.../buffer/scan_elements/in_anglvel_y_index
-What:		/sys/.../buffer/scan_elements/in_anglvel_z_index
-What:		/sys/.../buffer/scan_elements/in_magn_x_index
-What:		/sys/.../buffer/scan_elements/in_magn_y_index
-What:		/sys/.../buffer/scan_elements/in_magn_z_index
-What:		/sys/.../buffer/scan_elements/in_incli_x_index
-What:		/sys/.../buffer/scan_elements/in_incli_y_index
-What:		/sys/.../buffer/scan_elements/in_timestamp_index
-KernelVersion:	2.6.37
-Contact:	linux-iio@vger.kernel.org
-Description:
-		A single positive integer specifying the position of this
-		scan element in the buffer. Note these are not dependent on
-		what is enabled and may not be contiguous. Thus for user-space
-		to establish the full layout these must be used in conjunction
-		with all _en attributes to establish which channels are present,
-		and the relevant _type attributes to establish the data storage
-		format.
-
-What:		/sys/.../iio:deviceX/in_anglvel_z_quadrature_correction_raw
-KernelVersion:	2.6.38
-Contact:	linux-iio@vger.kernel.org
-Description:
-		This attribute is used to read the amount of quadrature error
-		present in the device at a given time.
-
-What:		/sys/.../iio:deviceX/ac_excitation_en
-KernelVersion:	3.1.0
-Contact:	linux-iio@vger.kernel.org
-Description:
-		This attribute, if available, is used to enable the AC
-		excitation mode found on some converters. In ac excitation mode,
-		the polarity of the excitation voltage is reversed on
-		alternate cycles, to eliminate DC errors.
-
-What:		/sys/.../iio:deviceX/bridge_switch_en
-KernelVersion:	3.1.0
-Contact:	linux-iio@vger.kernel.org
-Description:
-		This attribute, if available, is used to close or open the
-		bridge power down switch found on some converters.
-		In bridge applications, such as strain gauges and load cells,
-		the bridge itself consumes the majority of the current in the
-		system. To minimize the current consumption of the system,
-		the bridge can be disconnected (when it is not being used
-		using the bridge_switch_en attribute.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192 b/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192
new file mode 100644
index 0000000..1c35c50
--- /dev/null
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192
@@ -0,0 +1,20 @@
+What:		/sys/.../iio:deviceX/ac_excitation_en
+KernelVersion:	3.1.0
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute, if available, is used to enable the AC
+		excitation mode found on some converters. In ac excitation mode,
+		the polarity of the excitation voltage is reversed on
+		alternate cycles, to eliminate DC errors.
+
+What:		/sys/.../iio:deviceX/bridge_switch_en
+KernelVersion:	3.1.0
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute, if available, is used to close or open the
+		bridge power down switch found on some converters.
+		In bridge applications, such as strain gauges and load cells,
+		the bridge itself consumes the majority of the current in the
+		system. To minimize the current consumption of the system,
+		the bridge can be disconnected (when it is not being used
+		using the bridge_switch_en attribute.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-dds b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
index ffdd547..ee8c509 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
@@ -1,83 +1,86 @@
 
-What:		/sys/bus/iio/devices/.../ddsX_freqY
+What:		/sys/bus/iio/devices/.../out_altvoltageX_frequencyY
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
 		Stores frequency into tuning word Y.
-		There will be more than one ddsX_freqY file, which allows for
-		pin controlled FSK Frequency Shift Keying
-		(ddsX_pincontrol_freq_en is active) or the user can control
-		the desired active tuning word by writing Y to the
-		ddsX_freqsymbol file.
+		There will be more than one out_altvoltageX_frequencyY file,
+		which allows for pin controlled FSK Frequency Shift Keying
+		(out_altvoltageX_pincontrol_frequency_en is active) or the user
+		can control the desired active tuning word by writing Y to the
+		out_altvoltageX_frequencysymbol file.
 
-What:		/sys/bus/iio/devices/.../ddsX_freqY_scale
+What:		/sys/bus/iio/devices/.../out_altvoltageX_frequencyY_scale
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
-		Scale to be applied to ddsX_freqY in order to obtain the
-		desired value in Hz. If shared across all frequency registers
-		Y is not present. It is also possible X is not present if
-		shared across all channels.
+		Scale to be applied to out_altvoltageX_frequencyY in order to
+		obtain the desired value in Hz. If shared across all frequency
+		registers Y is not present. It is also possible X is not present
+		if shared across all channels.
 
-What:		/sys/bus/iio/devices/.../ddsX_freqsymbol
+What:		/sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
 		Specifies the active output frequency tuning word. The value
-		corresponds to the Y in ddsX_freqY. To exit this mode the user
-		can write ddsX_pincontrol_freq_en or ddsX_out_enable file.
+		corresponds to the Y in out_altvoltageX_frequencyY.
+		To exit this mode the user can write
+		out_altvoltageX_pincontrol_frequency_en or
+		out_altvoltageX_out_enable file.
 
-What:		/sys/bus/iio/devices/.../ddsX_phaseY
+What:		/sys/bus/iio/devices/.../out_altvoltageX_phaseY
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
 		Stores phase into Y.
-		There will be more than one ddsX_phaseY file, which allows for
-		pin controlled PSK Phase Shift Keying
-		(ddsX_pincontrol_phase_en is active) or the user can
+		There will be more than one out_altvoltageX_phaseY file, which
+		allows for pin controlled PSK Phase Shift Keying
+		(out_altvoltageX_pincontrol_phase_en is active) or the user can
 		control the desired phase Y which is added to the phase
-		accumulator output by writing Y to the en_phase file.
+		accumulator output by writing Y to the phase_en file.
 
-What:		/sys/bus/iio/devices/.../ddsX_phaseY_scale
+What:		/sys/bus/iio/devices/.../out_altvoltageX_phaseY_scale
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
-		Scale to be applied to ddsX_phaseY in order to obtain the
-		desired value in rad. If shared across all phase registers
+		Scale to be applied to out_altvoltageX_phaseY in order to obtain
+		the desired value in rad. If shared across all phase registers
 		Y is not present. It is also possible X is not present if
 		shared across all channels.
 
-What:		/sys/bus/iio/devices/.../ddsX_phasesymbol
+What:		/sys/bus/iio/devices/.../out_altvoltageX_phasesymbol
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
 		Specifies the active phase Y which is added to the phase
 		accumulator output. The value corresponds to the Y in
-		ddsX_phaseY. To exit this mode the user can write
-		ddsX_pincontrol_phase_en or disable file.
+		out_altvoltageX_phaseY. To exit this mode the user can write
+		out_altvoltageX_pincontrol_phase_en or disable file.
 
-What:		/sys/bus/iio/devices/.../ddsX_pincontrol_en
-What:		/sys/bus/iio/devices/.../ddsX_pincontrol_freq_en
-What:		/sys/bus/iio/devices/.../ddsX_pincontrol_phase_en
+What:		/sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en
+What:		/sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en
+What:		/sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
-		ddsX_pincontrol_en: Both, the active frequency and phase is
-		controlled by the respective phase and frequency control inputs.
-		In case the device in question allows to independent controls,
-		then there are dedicated files (ddsX_pincontrol_freq_en,
-		ddsX_pincontrol_phase_en).
+		out_altvoltageX_pincontrol_en: Both, the active frequency and
+		phase is controlled by the respective phase and frequency
+		control inputs. In case the device in features independent
+		controls, then there are dedicated files
+		(out_altvoltageX_pincontrol_frequency_en,
+		out_altvoltageX_pincontrol_phase_en).
 
-What:		/sys/bus/iio/devices/.../ddsX_out_enable
-What:		/sys/bus/iio/devices/.../ddsX_outY_enable
+What:		/sys/bus/iio/devices/.../out_altvoltageX_out_enable
+What:		/sys/bus/iio/devices/.../out_altvoltageX_outY_enable
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
-		ddsX_outY_enable controls signal generation on output Y of
-		channel X. Y may be suppressed if all channels are
+		out_altvoltageX_outY_enable controls signal generation on
+		output Y of channel X. Y may be suppressed if all channels are
 		controlled together.
 
-What:		/sys/bus/iio/devices/.../ddsX_outY_wavetype
+What:		/sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -86,7 +89,7 @@
 		For a list of available output waveform options read
 		available_output_modes.
 
-What:		/sys/bus/iio/devices/.../ddsX_outY_wavetype_available
+What:		/sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
index edbf470..715c74d 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio-light
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
@@ -26,7 +26,7 @@
 		Hardware dependent list of possible values supported for the
 		adc_resolution of the given sensor.
 
-What:		/sys/bus/iio/devices/device[n]/illuminance0[_input|_raw]
+What:		/sys/bus/iio/devices/device[n]/in_illuminance0[_input|_raw]
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -45,7 +45,7 @@
 		do this calculation manually by reading the infrared sensor
 		value and doing the negation in sw.
 
-What:		/sys/bus/iio/devices/device[n]/proximity[_input|_raw]
+What:		/sys/bus/iio/devices/device[n]/in_proximity[_input|_raw]
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -63,23 +63,22 @@
 		and if expressed in SI units, should include _input. If this
 		value is not in SI units, then it should include _raw.
 
-What:		/sys/bus/iio/devices/device[n]/illuminance0_target
+What:		/sys/bus/iio/devices/device[n]/in_illuminance0_target
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
 		This property gets/sets the last known external
 		lux measurement used in/for calibration.
 
-What:		/sys/bus/iio/devices/device[n]/illuminance0_integration_time
+What:		/sys/bus/iio/devices/device[n]/in_illuminance0_integration_time
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
 		This property gets/sets the sensors ADC analog integration time.
 
-What:		/sys/bus/iio/devices/device[n]/illuminance0_calibscale
+What:		/sys/bus/iio/devices/device[n]/in_illuminance0_lux_table
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
-		Hardware or software applied calibration scale factor assumed
-		to account for attenuation due to industrial design (glass
-		filters or aperture holes).
+		This property gets/sets the table of coefficients
+		used in calculating illuminance in lux.
diff --git a/drivers/staging/iio/Documentation/trigger.txt b/drivers/staging/iio/Documentation/trigger.txt
index fc2012e..75cc37f 100644
--- a/drivers/staging/iio/Documentation/trigger.txt
+++ b/drivers/staging/iio/Documentation/trigger.txt
@@ -5,7 +5,7 @@
 such triggers are registered with the core in the same way as
 stand-alone triggers.
 
-struct iio_trig *trig = iio_allocate_trigger("<trigger format string>", ...);
+struct iio_trig *trig = iio_trigger_alloc("<trigger format string>", ...);
 
 allocates a trigger structure.  The key elements to then fill in within
 a driver are:
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index fe1586718..3c8e5ec 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -1,16 +1,9 @@
 #
 # Industrial I/O subsytem configuration
 #
+menu "IIO staging drivers"
+	depends on IIO
 
-menuconfig IIO
-	tristate "Industrial I/O support"
-	depends on GENERIC_HARDIRQS
-	help
-	  The industrial I/O subsystem provides a unified framework for
-	  drivers for many different types of embedded sensors using a
-	  number of different physical interfaces (i2c, spi, etc). See
-	  drivers/staging/iio/Documentation for more information.
-if IIO
 config IIO_ST_HWMON
 	tristate "Hwmon driver that uses channels specified via iio maps"
 	depends on HWMON
@@ -19,12 +12,6 @@
 	  map allows IIO devices to provide  basic hwmon functionality
 	  for those channels specified in the map.
 
-config IIO_BUFFER
-	bool "Enable buffer support within IIO"
-	help
-	  Provide core support for various buffer based data
-	  acquisition methods.
-
 if IIO_BUFFER
 
 config IIO_SW_RING
@@ -36,39 +23,14 @@
 	  with the intention that some devices would be able to write
 	  in interrupt context.
 
-config IIO_KFIFO_BUF
-	select IIO_TRIGGER
-	tristate "Industrial I/O buffering based on kfifo"
-	help
-	  A simple fifo based on kfifo.  Use this if you want a fifo
-	  rather than a ring buffer. Note that this currently provides
-	  no buffer events so it is up to userspace to work out how
-	  often to read from the buffer.
-
 endif # IIO_BUFFER
 
-config IIO_TRIGGER
-	boolean "Enable triggered sampling support"
-	help
-	  Provides IIO core support for triggers.  Currently these
-	  are used to initialize capture of samples to push into
-	  ring buffers.  The triggers are effectively a 'capture
-	  data now' interrupt.
-
-config IIO_CONSUMERS_PER_TRIGGER
-       int "Maximum number of consumers per trigger"
-       depends on IIO_TRIGGER
-       default "2"
-       help
-	This value controls the maximum number of consumers that a
-	given trigger may handle. Default is 2.
-
 source "drivers/staging/iio/accel/Kconfig"
 source "drivers/staging/iio/adc/Kconfig"
 source "drivers/staging/iio/addac/Kconfig"
 source "drivers/staging/iio/cdc/Kconfig"
 source "drivers/staging/iio/dac/Kconfig"
-source "drivers/staging/iio/dds/Kconfig"
+source "drivers/staging/iio/frequency/Kconfig"
 source "drivers/staging/iio/gyro/Kconfig"
 source "drivers/staging/iio/impedance-analyzer/Kconfig"
 source "drivers/staging/iio/imu/Kconfig"
@@ -104,4 +66,4 @@
 
 endif # IIO_SIMPLE_DUMMY
 
-endif # IIO
+endmenu
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index 5075291..6a46d5a 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -2,13 +2,7 @@
 # Makefile for the industrial I/O core.
 #
 
-obj-$(CONFIG_IIO) += industrialio.o
-industrialio-y := industrialio-core.o industrialio-event.o inkern.o
-industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
-industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
-
 obj-$(CONFIG_IIO_SW_RING) += ring_sw.o
-obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
 
 obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o
 iio_dummy-y := iio_simple_dummy.o
@@ -24,7 +18,7 @@
 obj-y += addac/
 obj-y += cdc/
 obj-y += dac/
-obj-y += dds/
+obj-y += frequency/
 obj-y += gyro/
 obj-y += impedance-analyzer/
 obj-y += imu/
diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO
index d1ad35e..cf3f948 100644
--- a/drivers/staging/iio/TODO
+++ b/drivers/staging/iio/TODO
@@ -67,7 +67,7 @@
 
 Documentation
 1) Lots of cleanup and expansion.
-2) Some device require indvidual docs.
+2) Some device require individual docs.
 
 Contact: Jonathan Cameron <jic23@cam.ac.uk>.
 Mailing list: linux-iio@vger.kernel.org
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
index d439e45..02b3409 100644
--- a/drivers/staging/iio/accel/adis16201_core.c
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -15,9 +15,9 @@
 #include <linux/sysfs.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 #include "adis16201.h"
 
@@ -171,7 +171,7 @@
 	ret = strtobool(buf, &res);
 	if (ret || !res)
 		return ret;
-	return adis16201_reset(dev_get_drvdata(dev));
+	return adis16201_reset(dev_to_iio_dev(dev));
 }
 
 int adis16201_set_irq(struct iio_dev *indio_dev, bool enable)
@@ -298,7 +298,7 @@
 	s16 val16;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		addr = adis16201_addresses[chan->address][0];
 		ret = adis16201_spi_read_reg_16(indio_dev, addr, &val16);
@@ -406,39 +406,104 @@
 }
 
 static struct iio_chan_spec adis16201_channels[] = {
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
+	{
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "supply",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 in_supply, ADIS16201_SCAN_SUPPLY,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
+		.address = in_supply,
+		.scan_index = ADIS16201_SCAN_SUPPLY,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
 		 IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
-		 temp, ADIS16201_SCAN_TEMP,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
+		.address = temp,
+		.scan_index = ADIS16201_SCAN_TEMP,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 accel_x, ADIS16201_SCAN_ACC_X,
-		 IIO_ST('s', 14, 16, 0), 0),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
+		.address = accel_x,
+		.scan_index = ADIS16201_SCAN_ACC_X,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 accel_y, ADIS16201_SCAN_ACC_Y,
-		 IIO_ST('s', 14, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
+		.address = accel_y,
+		.scan_index = ADIS16201_SCAN_ACC_Y,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 1,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 in_aux, ADIS16201_SCAN_AUX_ADC,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X,
+		.address = in_aux,
+		.scan_index = ADIS16201_SCAN_AUX_ADC,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_INCLI,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 incli_x, ADIS16201_SCAN_INCLI_X,
-		 IIO_ST('s', 14, 16, 0), 0),
-	IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y,
+		.address = incli_x,
+		.scan_index = ADIS16201_SCAN_INCLI_X,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_INCLI,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 incli_y, ADIS16201_SCAN_INCLI_Y,
-		 IIO_ST('s', 14, 16, 0), 0),
+		.address = incli_y,
+		.scan_index = ADIS16201_SCAN_INCLI_Y,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	},
 	IIO_CHAN_SOFT_TIMESTAMP(7)
 };
 
@@ -467,7 +532,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -522,7 +587,7 @@
 error_unreg_ring_funcs:
 	adis16201_unconfigure_ring(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -535,7 +600,7 @@
 	adis16201_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	adis16201_unconfigure_ring(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
index 97f9e6b..247602a 100644
--- a/drivers/staging/iio/accel/adis16201_ring.c
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -5,9 +5,9 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
 #include "adis16201.h"
 
 
@@ -66,9 +66,8 @@
 
 	int i = 0;
 	s16 *data;
-	size_t datasize = ring->access->get_bytes_per_datum(ring);
 
-	data = kmalloc(datasize, GFP_KERNEL);
+	data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (data == NULL) {
 		dev_err(&st->us->dev, "memory alloc failed in ring bh");
 		return -ENOMEM;
@@ -81,7 +80,7 @@
 			data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
 
 	/* Guaranteed to be aligned with 8 byte boundary */
-	if (ring->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
 	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16201_trigger.c b/drivers/staging/iio/accel/adis16201_trigger.c
index bce505e..96fdabb 100644
--- a/drivers/staging/iio/accel/adis16201_trigger.c
+++ b/drivers/staging/iio/accel/adis16201_trigger.c
@@ -3,8 +3,8 @@
 #include <linux/spi/spi.h>
 #include <linux/export.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 #include "adis16201.h"
 
 /**
@@ -29,7 +29,7 @@
 	int ret;
 	struct adis16201_state *st = iio_priv(indio_dev);
 
-	st->trig = iio_allocate_trigger("adis16201-dev%d", indio_dev->id);
+	st->trig = iio_trigger_alloc("adis16201-dev%d", indio_dev->id);
 	if (st->trig == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -56,7 +56,7 @@
 error_free_irq:
 	free_irq(st->us->irq, st->trig);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -67,5 +67,5 @@
 
 	iio_trigger_unregister(state->trig);
 	free_irq(state->us->irq, state->trig);
-	iio_free_trigger(state->trig);
+	iio_trigger_free(state->trig);
 }
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
index 1a5140f..15d46bf 100644
--- a/drivers/staging/iio/accel/adis16203_core.c
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -15,9 +15,9 @@
 #include <linux/sysfs.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 #include "adis16203.h"
 
@@ -182,7 +182,7 @@
 		struct device_attribute *attr,
 		const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	if (len < 1)
 		return -EINVAL;
 	switch (buf[0]) {
@@ -305,7 +305,7 @@
 	u8 addr;
 	s16 val16;
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		addr = adis16203_addresses[chan->address][0];
 		ret = adis16203_spi_read_reg_16(indio_dev, addr, &val16);
@@ -372,29 +372,75 @@
 }
 
 static struct iio_chan_spec adis16203_channels[] = {
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 in_supply, ADIS16203_SCAN_SUPPLY,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 in_aux, ADIS16203_SCAN_AUX_ADC,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
-		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 incli_x, ADIS16203_SCAN_INCLI_X,
-		 IIO_ST('s', 14, 16, 0), 0),
-	/* Fixme: Not what it appears to be - see data sheet */
-	IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 incli_y, ADIS16203_SCAN_INCLI_Y,
-		 IIO_ST('s', 14, 16, 0), 0),
-	IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
-		 IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
-		 temp, ADIS16203_SCAN_TEMP,
-		 IIO_ST('u', 12, 16, 0), 0),
+	{
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "supply",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = in_supply,
+		.scan_index = ADIS16203_SCAN_SUPPLY,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 1,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = in_aux,
+		.scan_index = ADIS16203_SCAN_AUX_ADC,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_INCLI,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+		.address = incli_x,
+		.scan_index = ADIS16203_SCAN_INCLI_X,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, { /* Fixme: Not what it appears to be - see data sheet */
+		.type = IIO_INCLI,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = incli_y,
+		.scan_index = ADIS16203_SCAN_INCLI_Y,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+		.address = temp,
+		.scan_index = ADIS16203_SCAN_TEMP,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	},
 	IIO_CHAN_SOFT_TIMESTAMP(5),
 };
 
@@ -423,7 +469,7 @@
 	struct adis16203_state *st;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -477,7 +523,7 @@
 error_unreg_ring_funcs:
 	adis16203_unconfigure_ring(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -490,7 +536,7 @@
 	adis16203_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	adis16203_unconfigure_ring(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
index 6a8963d..7bbd2c2 100644
--- a/drivers/staging/iio/accel/adis16203_ring.c
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -5,20 +5,19 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
 #include "adis16203.h"
 
 /**
  * adis16203_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
  * @rx: somewhere to pass back the value read
  **/
-static int adis16203_read_ring_data(struct device *dev, u8 *rx)
+static int adis16203_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct adis16203_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfers[ADIS16203_OUTPUTS + 1];
 	int ret;
@@ -66,22 +65,21 @@
 
 	int i = 0;
 	s16 *data;
-	size_t datasize = ring->access->get_bytes_per_datum(ring);
 
-	data = kmalloc(datasize, GFP_KERNEL);
+	data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (data == NULL) {
 		dev_err(&st->us->dev, "memory alloc failed in ring bh");
 		return -ENOMEM;
 	}
 
 	if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
-	    adis16203_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+	    adis16203_read_ring_data(indio_dev, st->rx) >= 0)
 		for (; i < bitmap_weight(indio_dev->active_scan_mask,
 					 indio_dev->masklength); i++)
 			data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
 
 	/* Guaranteed to be aligned with 8 byte boundary */
-	if (ring->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
 	ring->access->store_to(ring,
diff --git a/drivers/staging/iio/accel/adis16203_trigger.c b/drivers/staging/iio/accel/adis16203_trigger.c
index 24bcb8e..b8a0407 100644
--- a/drivers/staging/iio/accel/adis16203_trigger.c
+++ b/drivers/staging/iio/accel/adis16203_trigger.c
@@ -3,8 +3,8 @@
 #include <linux/spi/spi.h>
 #include <linux/export.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 #include "adis16203.h"
 
 /**
@@ -29,7 +29,7 @@
 	int ret;
 	struct adis16203_state *st = iio_priv(indio_dev);
 
-	st->trig = iio_allocate_trigger("adis16203-dev%d", indio_dev->id);
+	st->trig = iio_trigger_alloc("adis16203-dev%d", indio_dev->id);
 	if (st->trig == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -58,7 +58,7 @@
 error_free_irq:
 	free_irq(st->us->irq, st->trig);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -69,5 +69,5 @@
 
 	iio_trigger_unregister(st->trig);
 	free_irq(st->us->irq, st->trig);
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 }
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
index fa89364..ac9d95e 100644
--- a/drivers/staging/iio/accel/adis16204_core.c
+++ b/drivers/staging/iio/accel/adis16204_core.c
@@ -18,9 +18,9 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 #include "adis16204.h"
 
@@ -173,7 +173,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	s16 val = 0;
 	ssize_t ret;
@@ -211,7 +211,7 @@
 		struct device_attribute *attr,
 		const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 
 	if (len < 1)
 		return -EINVAL;
@@ -342,7 +342,7 @@
 	int addrind;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		addr = adis16204_addresses[chan->address][0];
 		ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16);
@@ -444,31 +444,78 @@
 }
 
 static struct iio_chan_spec adis16204_channels[] = {
-	IIO_CHAN(IIO_VOLTAGE, 0, 0, 0, "supply", 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 in_supply, ADIS16204_SCAN_SUPPLY,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 in_aux, ADIS16204_SCAN_AUX_ADC,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
-		 IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
-		 temp, ADIS16204_SCAN_TEMP,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
-		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
-		 IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
-		 accel_x, ADIS16204_SCAN_ACC_X,
-		 IIO_ST('s', 14, 16, 0), 0),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
-		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
-		 IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
-		 accel_y, ADIS16204_SCAN_ACC_Y,
-		 IIO_ST('s', 14, 16, 0), 0),
+	{
+		.type = IIO_VOLTAGE,
+		.indexed = 1, /* Note was not previously indexed */
+		.channel = 0,
+		.extend_name = "supply",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = in_supply,
+		.scan_index = ADIS16204_SCAN_SUPPLY,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 1,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = in_aux,
+		.scan_index = ADIS16204_SCAN_AUX_ADC,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+		.address = temp,
+		.scan_index = ADIS16204_SCAN_TEMP,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
+		.address = accel_x,
+		.scan_index = ADIS16204_SCAN_ACC_X,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
+		.address = accel_y,
+		.scan_index = ADIS16204_SCAN_ACC_Y,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	},
 	IIO_CHAN_SOFT_TIMESTAMP(5),
 };
 
@@ -498,7 +545,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -551,7 +598,7 @@
 error_unreg_ring_funcs:
 	adis16204_unconfigure_ring(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -564,7 +611,7 @@
 	adis16204_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	adis16204_unconfigure_ring(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
index 5c8ab73..f73518b 100644
--- a/drivers/staging/iio/accel/adis16204_ring.c
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -5,20 +5,19 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
 #include "adis16204.h"
 
 /**
  * adis16204_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
  * @rx: somewhere to pass back the value read
  **/
-static int adis16204_read_ring_data(struct device *dev, u8 *rx)
+static int adis16204_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct adis16204_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfers[ADIS16204_OUTPUTS + 1];
 	int ret;
@@ -63,22 +62,21 @@
 	struct iio_buffer *ring = indio_dev->buffer;
 	int i = 0;
 	s16 *data;
-	size_t datasize = ring->access->get_bytes_per_datum(ring);
 
-	data = kmalloc(datasize, GFP_KERNEL);
+	data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (data == NULL) {
 		dev_err(&st->us->dev, "memory alloc failed in ring bh");
 		return -ENOMEM;
 	}
 
 	if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
-	    adis16204_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+	    adis16204_read_ring_data(indio_dev, st->rx) >= 0)
 		for (; i < bitmap_weight(indio_dev->active_scan_mask,
 					 indio_dev->masklength); i++)
 			data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
 
 	/* Guaranteed to be aligned with 8 byte boundary */
-	if (ring->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
 	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16204_trigger.c b/drivers/staging/iio/accel/adis16204_trigger.c
index 6e542af..408a168 100644
--- a/drivers/staging/iio/accel/adis16204_trigger.c
+++ b/drivers/staging/iio/accel/adis16204_trigger.c
@@ -3,8 +3,8 @@
 #include <linux/spi/spi.h>
 #include <linux/export.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 #include "adis16204.h"
 
 /**
@@ -29,7 +29,7 @@
 	int ret;
 	struct adis16204_state *st = iio_priv(indio_dev);
 
-	st->trig = iio_allocate_trigger("adis16204-dev%d", indio_dev->id);
+	st->trig = iio_trigger_alloc("adis16204-dev%d", indio_dev->id);
 	if (st->trig == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -58,7 +58,7 @@
 error_free_irq:
 	free_irq(st->us->irq, st->trig);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -69,5 +69,5 @@
 
 	iio_trigger_unregister(state->trig);
 	free_irq(state->us->irq, state->trig);
-	iio_free_trigger(state->trig);
+	iio_trigger_free(state->trig);
 }
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index a98715f..f6fd0d3 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -16,9 +16,9 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 #include "adis16209.h"
 
@@ -157,7 +157,7 @@
 		struct device_attribute *attr,
 		const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 
 	if (len < 1)
 		return -EINVAL;
@@ -331,7 +331,7 @@
 	s16 val16;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		addr = adis16209_addresses[chan->address][0];
 		ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16);
@@ -408,41 +408,114 @@
 }
 
 static struct iio_chan_spec adis16209_channels[] = {
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 in_supply, ADIS16209_SCAN_SUPPLY,
-		 IIO_ST('u', 14, 16, 0), 0),
-	IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
-		 IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
-		 temp, ADIS16209_SCAN_TEMP,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
-		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 accel_x, ADIS16209_SCAN_ACC_X,
-		 IIO_ST('s', 14, 16, 0), 0),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
-		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 accel_y, ADIS16209_SCAN_ACC_Y,
-		 IIO_ST('s', 14, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 in_aux, ADIS16209_SCAN_AUX_ADC,
-		 IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 incli_x, ADIS16209_SCAN_INCLI_X,
-		 IIO_ST('s', 14, 16, 0), 0),
-	IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 incli_y, ADIS16209_SCAN_INCLI_Y,
-		 IIO_ST('s', 14, 16, 0), 0),
-	IIO_CHAN(IIO_ROT, 0, 1, 0, NULL, 0, IIO_MOD_X,
-		    0,
-		    rot, ADIS16209_SCAN_ROT,
-		    IIO_ST('s', 14, 16, 0), 0),
+	{
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "supply",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = in_supply,
+		.scan_index = ADIS16209_SCAN_SUPPLY,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_TEMP,
+		.indexed = 0,
+		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+		.address = temp,
+		.scan_index = ADIS16209_SCAN_TEMP,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+		.address = accel_x,
+		.scan_index = ADIS16209_SCAN_ACC_X,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+		.address = accel_y,
+		.scan_index = ADIS16209_SCAN_ACC_Y,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 1,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = in_aux,
+		.scan_index = ADIS16209_SCAN_AUX_ADC,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_INCLI,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = incli_x,
+		.scan_index = ADIS16209_SCAN_INCLI_X,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_INCLI,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = incli_y,
+		.scan_index = ADIS16209_SCAN_INCLI_Y,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ROT,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+		.address = rot,
+		.scan_index = ADIS16209_SCAN_ROT,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	},
 	IIO_CHAN_SOFT_TIMESTAMP(8)
 };
 
@@ -471,7 +544,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -524,7 +597,7 @@
 error_unreg_ring_funcs:
 	adis16209_unconfigure_ring(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -539,7 +612,7 @@
 	adis16209_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	adis16209_unconfigure_ring(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index 57254b6b..0906075 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -5,20 +5,19 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
 #include "adis16209.h"
 
 /**
  * adis16209_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
  * @rx: somewhere to pass back the value read
  **/
-static int adis16209_read_ring_data(struct device *dev, u8 *rx)
+static int adis16209_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct adis16209_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfers[ADIS16209_OUTPUTS + 1];
 	int ret;
@@ -61,25 +60,23 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adis16209_state *st = iio_priv(indio_dev);
 	struct iio_buffer *ring = indio_dev->buffer;
-
 	int i = 0;
 	s16 *data;
-	size_t datasize = ring->access->get_bytes_per_datum(ring);
 
-	data = kmalloc(datasize , GFP_KERNEL);
+	data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (data == NULL) {
 		dev_err(&st->us->dev, "memory alloc failed in ring bh");
 		return -ENOMEM;
 	}
 
 	if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
-	    adis16209_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+	    adis16209_read_ring_data(indio_dev, st->rx) >= 0)
 		for (; i < bitmap_weight(indio_dev->active_scan_mask,
 					 indio_dev->masklength); i++)
 			data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
 
 	/* Guaranteed to be aligned with 8 byte boundary */
-	if (ring->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
 	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16209_trigger.c b/drivers/staging/iio/accel/adis16209_trigger.c
index c5d82c1..2ad93dc 100644
--- a/drivers/staging/iio/accel/adis16209_trigger.c
+++ b/drivers/staging/iio/accel/adis16209_trigger.c
@@ -3,8 +3,8 @@
 #include <linux/spi/spi.h>
 #include <linux/export.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 #include "adis16209.h"
 
 /**
@@ -38,7 +38,7 @@
 	int ret;
 	struct adis16209_state *st = iio_priv(indio_dev);
 
-	st->trig = iio_allocate_trigger("adis16209-dev%d", indio_dev->id);
+	st->trig = iio_trigger_alloc("adis16209-dev%d", indio_dev->id);
 	if (st->trig == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -66,7 +66,7 @@
 error_free_irq:
 	free_irq(st->us->irq, st->trig);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -77,5 +77,5 @@
 
 	iio_trigger_unregister(st->trig);
 	free_irq(st->us->irq, st->trig);
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 }
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index 51a852d..6a9ac89 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -15,8 +15,8 @@
 #include <linux/sysfs.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #include "adis16220.h"
 
@@ -145,7 +145,7 @@
 		char *buf)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	ssize_t ret;
 	s16 val = 0;
 
@@ -164,7 +164,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int ret;
 	u16 val;
@@ -208,7 +208,7 @@
 		struct device_attribute *attr,
 		const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	bool val;
 	int ret;
 
@@ -228,7 +228,7 @@
 		struct device_attribute *attr,
 		const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	bool val;
 	int ret;
 
@@ -393,7 +393,7 @@
 					size_t count)
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 
 	return adis16220_capture_buffer_read(indio_dev, buf,
 					off, count,
@@ -415,7 +415,7 @@
 				size_t count)
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 
 	return adis16220_capture_buffer_read(indio_dev, buf,
 					off, count,
@@ -437,7 +437,7 @@
 				size_t count)
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 
 	return adis16220_capture_buffer_read(indio_dev, buf,
 					off, count,
@@ -507,7 +507,7 @@
 	u8 bits;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		addrind = 0;
 		break;
 	case IIO_CHAN_INFO_OFFSET:
@@ -575,11 +575,13 @@
 		.indexed = 1,
 		.channel = 0,
 		.extend_name = "supply",
-		.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = in_supply,
 	}, {
 		.type = IIO_ACCEL,
-		.info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 			     IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
 			     IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
 		.address = accel,
@@ -587,20 +589,23 @@
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 			     IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = temp,
 	}, {
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 1,
-		.info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 			     IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = in_1,
 	}, {
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 2,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = in_2,
 	}
 };
@@ -629,7 +634,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -680,7 +685,7 @@
 error_unregister_dev:
 	iio_device_unregister(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -695,7 +700,7 @@
 	sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
 	sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
 	iio_device_unregister(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index 17f77fe..8b15eae 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -19,9 +19,9 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 #include "adis16240.h"
 
@@ -154,7 +154,7 @@
 		char *buf,
 		unsigned bits)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	int ret;
 	s16 val = 0;
 	unsigned shift = 16 - bits;
@@ -177,7 +177,7 @@
 		char *buf)
 {
 	ssize_t ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 
 	/* Take the iio_dev status lock */
 	mutex_lock(&indio_dev->mlock);
@@ -203,7 +203,7 @@
 		struct device_attribute *attr,
 		const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 
 	if (len < 1)
 		return -EINVAL;
@@ -365,7 +365,7 @@
 	s16 val16;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		addr = adis16240_addresses[chan->address][0];
 		ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
@@ -468,33 +468,88 @@
 }
 
 static struct iio_chan_spec adis16240_channels[] = {
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 in_supply, ADIS16240_SCAN_SUPPLY,
-		 IIO_ST('u', 10, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
-		 0,
-		 in_aux, ADIS16240_SCAN_AUX_ADC,
-		 IIO_ST('u', 10, 16, 0), 0),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
-		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 accel_x, ADIS16240_SCAN_ACC_X,
-		 IIO_ST('s', 10, 16, 0), 0),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
-		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 accel_y, ADIS16240_SCAN_ACC_Y,
-		 IIO_ST('s', 10, 16, 0), 0),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT |
-		 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		 accel_z, ADIS16240_SCAN_ACC_Z,
-		 IIO_ST('s', 10, 16, 0), 0),
-	IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 temp, ADIS16240_SCAN_TEMP,
-		 IIO_ST('u', 10, 16, 0), 0),
+	{
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "supply",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = in_supply,
+		.scan_index = ADIS16240_SCAN_SUPPLY,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 10,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 1,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+		.address = in_aux,
+		.scan_index = ADIS16240_SCAN_AUX_ADC,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 10,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+		.address = accel_x,
+		.scan_index = ADIS16240_SCAN_ACC_X,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 10,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+		.address = accel_y,
+		.scan_index = ADIS16240_SCAN_ACC_Y,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 10,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Z,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+		.address = accel_z,
+		.scan_index = ADIS16240_SCAN_ACC_Z,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 10,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = temp,
+		.scan_index = ADIS16240_SCAN_TEMP,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 10,
+			.storagebits = 16,
+		},
+	},
 	IIO_CHAN_SOFT_TIMESTAMP(6)
 };
 
@@ -523,7 +578,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -576,7 +631,7 @@
 error_unreg_ring_funcs:
 	adis16240_unconfigure_ring(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -592,7 +647,7 @@
 	adis16240_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	adis16240_unconfigure_ring(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index 43ba84e..86a2a47 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -5,20 +5,19 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
 #include "adis16240.h"
 
 /**
  * adis16240_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
  * @rx: somewhere to pass back the value read
  **/
-static int adis16240_read_ring_data(struct device *dev, u8 *rx)
+static int adis16240_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct adis16240_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfers[ADIS16240_OUTPUTS + 1];
 	int ret;
@@ -61,22 +60,21 @@
 
 	int i = 0;
 	s16 *data;
-	size_t datasize = ring->access->get_bytes_per_datum(ring);
 
-	data = kmalloc(datasize, GFP_KERNEL);
+	data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (data == NULL) {
 		dev_err(&st->us->dev, "memory alloc failed in ring bh");
 		return -ENOMEM;
 	}
 
 	if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
-	    adis16240_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+	    adis16240_read_ring_data(indio_dev, st->rx) >= 0)
 		for (; i < bitmap_weight(indio_dev->active_scan_mask,
 					 indio_dev->masklength); i++)
 			data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
 
 	/* Guaranteed to be aligned with 8 byte boundary */
-	if (ring->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
 	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16240_trigger.c b/drivers/staging/iio/accel/adis16240_trigger.c
index 8e0ce56..fa90a22 100644
--- a/drivers/staging/iio/accel/adis16240_trigger.c
+++ b/drivers/staging/iio/accel/adis16240_trigger.c
@@ -3,8 +3,8 @@
 #include <linux/spi/spi.h>
 #include <linux/export.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 #include "adis16240.h"
 
 /**
@@ -38,7 +38,7 @@
 	int ret;
 	struct adis16240_state *st = iio_priv(indio_dev);
 
-	st->trig = iio_allocate_trigger("adis16240-dev%d", indio_dev->id);
+	st->trig = iio_trigger_alloc("adis16240-dev%d", indio_dev->id);
 	if (st->trig == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -67,7 +67,7 @@
 error_free_irq:
 	free_irq(st->us->irq, st->trig);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -78,5 +78,5 @@
 
 	iio_trigger_unregister(st->trig);
 	free_irq(st->us->irq, st->trig);
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 }
diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c
index d13d721..8cf7cd9 100644
--- a/drivers/staging/iio/accel/kxsd9.c
+++ b/drivers/staging/iio/accel/kxsd9.c
@@ -23,8 +23,8 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #define KXSD9_REG_X		0x00
 #define KXSD9_REG_Y		0x02
@@ -158,7 +158,7 @@
 	struct kxsd9_state *st = iio_priv(indio_dev);
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		ret = kxsd9_read(indio_dev, chan->address);
 		if (ret < 0)
 			goto error_ret;
@@ -181,7 +181,8 @@
 		.type = IIO_ACCEL,					\
 		.modified = 1,						\
 		.channel2 = IIO_MOD_##axis,				\
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,		\
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,			\
 		.address = KXSD9_REG_##axis,				\
 	}
 
@@ -189,6 +190,7 @@
 	KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
 	{
 		.type = IIO_VOLTAGE,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.indexed = 1,
 		.address = KXSD9_REG_AUX,
 	}
@@ -226,7 +228,7 @@
 	struct kxsd9_state *st;
 	int ret = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -254,7 +256,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -262,7 +264,7 @@
 static int __devexit kxsd9_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index 376da51..9d26348 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -23,10 +23,10 @@
 #include <linux/sysfs.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
 
 #include "lis3l02dq.h"
 
@@ -257,7 +257,7 @@
 	u8 reg;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		/* Take the iio_dev status lock */
 		mutex_lock(&indio_dev->mlock);
 		if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
@@ -297,7 +297,7 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	int ret, len = 0;
 	s8 t;
 	ret = lis3l02dq_spi_read_reg_8(indio_dev,
@@ -328,7 +328,7 @@
 					 const char *buf,
 					 size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	unsigned long val;
 	int ret;
 	u8 t;
@@ -513,7 +513,8 @@
 }
 
 #define LIS3L02DQ_INFO_MASK				\
-	(IIO_CHAN_INFO_SCALE_SHARED_BIT |		\
+	(IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+	 IIO_CHAN_INFO_SCALE_SHARED_BIT |		\
 	 IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |	\
 	 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT)
 
@@ -521,13 +522,26 @@
 	(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |	\
 	 IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
 
+#define LIS3L02DQ_CHAN(index, mod)				\
+	{							\
+		.type = IIO_ACCEL,				\
+		.modified = 1,					\
+		.channel2 = mod,				\
+		.info_mask =  LIS3L02DQ_INFO_MASK,		\
+		.address = index,				\
+		.scan_index = index,				\
+		.scan_type = {					\
+			.sign = 's',				\
+			.realbits = 12,				\
+			.storagebits = 16,			\
+		},						\
+		.event_mask = LIS3L02DQ_EVENT_MASK,		\
+	 }
+
 static struct iio_chan_spec lis3l02dq_channels[] = {
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, LIS3L02DQ_INFO_MASK,
-		 0, 0, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, LIS3L02DQ_INFO_MASK,
-		 1, 1, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, LIS3L02DQ_INFO_MASK,
-		 2, 2, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK),
+	LIS3L02DQ_CHAN(0, IIO_MOD_X),
+	LIS3L02DQ_CHAN(1, IIO_MOD_Y),
+	LIS3L02DQ_CHAN(2, IIO_MOD_Z),
 	IIO_CHAN_SOFT_TIMESTAMP(3)
 };
 
@@ -666,7 +680,7 @@
 	struct lis3l02dq_state *st;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_allocate_device(sizeof *st);
+	indio_dev = iio_device_alloc(sizeof *st);
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -724,7 +738,7 @@
 	return 0;
 
 error_remove_trigger:
-	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+	if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)))
 		lis3l02dq_remove_trigger(indio_dev);
 error_free_interrupt:
 	if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
@@ -734,7 +748,7 @@
 error_unreg_buffer_funcs:
 	lis3l02dq_unconfigure_buffer(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -789,7 +803,7 @@
 	iio_buffer_unregister(indio_dev);
 	lis3l02dq_unconfigure_buffer(indio_dev);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 err_ret:
 	return ret;
 }
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 0fc3973..51b00df 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -6,11 +6,11 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "../ring_sw.h"
-#include "../kfifo_buf.h"
-#include "../trigger.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
 #include "lis3l02dq.h"
 
 /**
@@ -137,9 +137,9 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct iio_buffer *buffer = indio_dev->buffer;
 	int len = 0;
-	size_t datasize = buffer->access->get_bytes_per_datum(buffer);
-	char *data = kmalloc(datasize, GFP_KERNEL);
+	char *data;
 
+	data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (data == NULL) {
 		dev_err(indio_dev->dev.parent,
 			"memory alloc failed in buffer bh");
@@ -150,7 +150,7 @@
 		len = lis3l02dq_get_buffer_element(indio_dev, data);
 
 	  /* Guaranteed to be aligned with 8 byte boundary */
-	if (buffer->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		*(s64 *)(((phys_addr_t)data + len
 				+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
 			= pf->timestamp;
@@ -163,12 +163,11 @@
 
 /* Caller responsible for locking as necessary. */
 static int
-__lis3l02dq_write_data_ready_config(struct device *dev, bool state)
+__lis3l02dq_write_data_ready_config(struct iio_dev *indio_dev, bool state)
 {
 	int ret;
 	u8 valold;
 	bool currentlyset;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct lis3l02dq_state *st = iio_priv(indio_dev);
 
 /* Get the current event mask register */
@@ -236,7 +235,7 @@
 	int ret = 0;
 	u8 t;
 
-	__lis3l02dq_write_data_ready_config(&indio_dev->dev, state);
+	__lis3l02dq_write_data_ready_config(indio_dev, state);
 	if (state == false) {
 		/*
 		 * A possible quirk with the handler is currently worked around
@@ -286,7 +285,7 @@
 	int ret;
 	struct lis3l02dq_state *st = iio_priv(indio_dev);
 
-	st->trig = iio_allocate_trigger("lis3l02dq-dev%d", indio_dev->id);
+	st->trig = iio_trigger_alloc("lis3l02dq-dev%d", indio_dev->id);
 	if (!st->trig) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -302,7 +301,7 @@
 	return 0;
 
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -312,7 +311,7 @@
 	struct lis3l02dq_state *st = iio_priv(indio_dev);
 
 	iio_trigger_unregister(st->trig);
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 }
 
 void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev)
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index 49764fb..6ec5c20 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -18,10 +18,10 @@
 #include <linux/spi/spi.h>
 #include <linux/sysfs.h>
 #include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
 
 #include "sca3000.h"
 
@@ -241,7 +241,7 @@
 static int sca3000_check_status(struct device *dev)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->lock);
@@ -268,7 +268,7 @@
 				char *buf)
 {
 	int len = 0, ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->lock);
@@ -296,7 +296,7 @@
 					 struct device_attribute *attr,
 					 char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	int len = 0;
 
@@ -328,7 +328,7 @@
 			      struct device_attribute *attr,
 			      char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	int len = 0, ret;
 
@@ -379,7 +379,7 @@
 			       const char *buf,
 			       size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	int ret;
 	u8 mask = 0x03;
@@ -429,17 +429,31 @@
 static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0);
 
 #define SCA3000_INFO_MASK			\
-	IIO_CHAN_INFO_SCALE_SHARED_BIT
+	IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT
 #define SCA3000_EVENT_MASK					\
 	(IIO_EV_BIT(IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING))
 
+#define SCA3000_CHAN(index, mod)				\
+	{							\
+		.type = IIO_ACCEL,				\
+		.modified = 1,					\
+		.channel2 = mod,				\
+		.info_mask = SCA3000_INFO_MASK,			\
+		.address = index,				\
+		.scan_index = index,				\
+		.scan_type = {					\
+			.sign = 's',				\
+			.realbits = 11,				\
+			.storagebits = 16,			\
+			.shift = 5,				\
+		},						\
+		.event_mask = SCA3000_EVENT_MASK,		\
+	 }
+
 static struct iio_chan_spec sca3000_channels[] = {
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, SCA3000_INFO_MASK,
-		 0, 0, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, SCA3000_INFO_MASK,
-		 1, 1, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK),
-	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, SCA3000_INFO_MASK,
-		 2, 2, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK),
+	SCA3000_CHAN(0, IIO_MOD_X),
+	SCA3000_CHAN(1, IIO_MOD_Y),
+	SCA3000_CHAN(2, IIO_MOD_Z),
 };
 
 static u8 sca3000_addresses[3][3] = {
@@ -462,7 +476,7 @@
 	u8 address;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&st->lock);
 		if (st->mo_det_use_count) {
 			mutex_unlock(&st->lock);
@@ -503,7 +517,7 @@
 			     struct device_attribute *attr,
 			     char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	int len = 0, ret, val;
 
@@ -574,7 +588,7 @@
 			       struct device_attribute *attr,
 			       char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	int ret, len = 0, base_freq = 0, val;
 
@@ -616,7 +630,7 @@
 			      const char *buf,
 			      size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	int ret, base_freq = 0;
 	int ctrlval;
@@ -676,7 +690,7 @@
 				 struct device_attribute *attr,
 				 char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	int ret;
 	int val;
@@ -897,7 +911,7 @@
 					    char *buf)
 {
 	int ret, len;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	int val;
 
@@ -925,7 +939,7 @@
 					  const char *buf,
 					  size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	long val;
 	int ret;
@@ -1131,7 +1145,7 @@
 	struct sca3000_state *st;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -1195,7 +1209,7 @@
 error_unregister_dev:
 	iio_device_unregister(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 error_ret:
 	return ret;
@@ -1233,7 +1247,7 @@
 	iio_device_unregister(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	sca3000_unconfigure_ring(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
index 6b824a1..b7e1a002 100644
--- a/drivers/staging/iio/accel/sca3000_ring.c
+++ b/drivers/staging/iio/accel/sca3000_ring.c
@@ -18,9 +18,9 @@
 #include <linux/sched.h>
 #include <linux/poll.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 #include "../ring_hw.h"
 #include "sca3000.h"
 
@@ -157,7 +157,7 @@
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int ret, val;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->lock);
@@ -178,7 +178,7 @@
 				      const char *buf,
 				      size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	long val;
@@ -219,7 +219,7 @@
 					 struct device_attribute *attr,
 					 char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct sca3000_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "0.%06d\n", 4*st->info->scale);
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 592eabd..2490dd2 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -25,7 +25,7 @@
 	depends on GPIOLIB
 	select IIO_BUFFER
 	select IIO_TRIGGER
-	select IIO_SW_RING
+	select IIO_KFIFO_BUF
 	help
 	  Say yes here to build support for Analog Devices:
 	  ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
@@ -63,7 +63,7 @@
 	bool "Analog Devices AD799x: use ring buffer"
 	depends on AD799X
 	select IIO_BUFFER
-	select IIO_SW_RING
+	select IIO_KFIFO_BUF
 	help
 	  Say yes here to include ring buffer support in the AD799X
 	  ADC driver.
@@ -72,7 +72,7 @@
 	tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver"
 	depends on SPI
 	select IIO_BUFFER
-	select IIO_SW_RING
+	select IIO_KFIFO_BUF
 	select IIO_TRIGGER
 	help
 	  Say yes here to build support for Analog Devices
@@ -87,7 +87,7 @@
 	tristate "Analog Devices AD7887 ADC driver"
 	depends on SPI
 	select IIO_BUFFER
-	select IIO_SW_RING
+	select IIO_KFIFO_BUF
 	select IIO_TRIGGER
 	help
 	  Say yes here to build support for Analog Devices
@@ -113,7 +113,7 @@
 	tristate "Analog Devices AD7792 AD7793 ADC driver"
 	depends on SPI
 	select IIO_BUFFER
-	select IIO_SW_RING
+	select IIO_KFIFO_BUF
 	select IIO_TRIGGER
 	help
 	  Say yes here to build support for Analog Devices
@@ -135,7 +135,7 @@
 	tristate "Analog Devices AD7190 AD7192 AD7195 ADC driver"
 	depends on SPI
 	select IIO_BUFFER
-	select IIO_SW_RING
+	select IIO_KFIFO_BUF
 	select IIO_TRIGGER
 	help
 	  Say yes here to build support for Analog Devices AD7190,
@@ -195,11 +195,20 @@
 
 config LPC32XX_ADC
 	tristate "NXP LPC32XX ADC"
-	depends on ARCH_LPC32XX && !TOUCHSCREEN_LPC32XX
+	depends on ARCH_LPC32XX
 	help
 	  Say yes here to build support for the integrated ADC inside the
 	  LPC32XX SoC. Note that this feature uses the same hardware as the
-	  touchscreen driver, so you can only select one of the two drivers
-	  (lpc32xx_adc or lpc32xx_ts). Provides direct access via sysfs.
+	  touchscreen driver, so you should either select only one of the two
+	  drivers (lpc32xx_adc or lpc32xx_ts) or, in the OpenFirmware case,
+	  activate only one via device tree selection.  Provides direct access
+	  via sysfs.
+
+config SPEAR_ADC
+	tristate "ST SPEAr ADC"
+	depends on PLAT_SPEAR
+	help
+	  Say yes here to build support for the integrated ADC inside the
+	  ST SPEAr SoC. Provides direct access via sysfs.
 
 endmenu
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index f83ab95..14e98b6 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -38,3 +38,4 @@
 obj-$(CONFIG_ADT7410) += adt7410.o
 obj-$(CONFIG_AD7280) += ad7280a.o
 obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
+obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 9fd6d63..5eaeaf1 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -1,7 +1,7 @@
 /*
  * AD7190 AD7192 AD7195 SPI ADC driver
  *
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
  *
  * Licensed under the GPL-2.
  */
@@ -17,12 +17,12 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
 
 #include "ad7192.h"
 
@@ -456,31 +456,19 @@
 static int ad7192_ring_preenable(struct iio_dev *indio_dev)
 {
 	struct ad7192_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
-	size_t d_size;
 	unsigned channel;
+	int ret;
 
 	if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
 		return -EINVAL;
 
+	ret = iio_sw_buffer_preenable(indio_dev);
+	if (ret < 0)
+		return ret;
+
 	channel = find_first_bit(indio_dev->active_scan_mask,
 				 indio_dev->masklength);
 
-	d_size = bitmap_weight(indio_dev->active_scan_mask,
-			       indio_dev->masklength) *
-		 indio_dev->channels[0].scan_type.storagebits / 8;
-
-	if (ring->scan_timestamp) {
-		d_size += sizeof(s64);
-
-		if (d_size % sizeof(s64))
-			d_size += sizeof(s64) - (d_size % sizeof(s64));
-	}
-
-	if (indio_dev->buffer->access->set_bytes_per_datum)
-		indio_dev->buffer->access->
-			set_bytes_per_datum(indio_dev->buffer, d_size);
-
 	st->mode  = (st->mode & ~AD7192_MODE_SEL(-1)) |
 		    AD7192_MODE_SEL(AD7192_MODE_CONT);
 	st->conf  = (st->conf & ~AD7192_CONF_CHAN(-1)) |
@@ -533,7 +521,7 @@
 				  indio_dev->channels[0].scan_type.realbits/8);
 
 	/* Guaranteed to be aligned with 8 byte boundary */
-	if (ring->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		dat64[1] = pf->timestamp;
 
 	ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
@@ -556,7 +544,7 @@
 {
 	int ret;
 
-	indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
 	if (!indio_dev->buffer) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -569,7 +557,7 @@
 						 indio_dev->id);
 	if (indio_dev->pollfunc == NULL) {
 		ret = -ENOMEM;
-		goto error_deallocate_sw_rb;
+		goto error_deallocate_kfifo;
 	}
 
 	/* Ring buffer functions - here trigger setup related */
@@ -579,8 +567,8 @@
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
 	return 0;
 
-error_deallocate_sw_rb:
-	iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+	iio_kfifo_free(indio_dev->buffer);
 error_ret:
 	return ret;
 }
@@ -588,7 +576,7 @@
 static void ad7192_ring_cleanup(struct iio_dev *indio_dev)
 {
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_sw_rb_free(indio_dev->buffer);
+	iio_kfifo_free(indio_dev->buffer);
 }
 
 /**
@@ -616,7 +604,7 @@
 	struct ad7192_state *st = iio_priv(indio_dev);
 	int ret;
 
-	st->trig = iio_allocate_trigger("%s-dev%d",
+	st->trig = iio_trigger_alloc("%s-dev%d",
 					spi_get_device_id(st->spi)->name,
 					indio_dev->id);
 	if (st->trig == NULL) {
@@ -649,7 +637,7 @@
 error_free_irq:
 	free_irq(st->spi->irq, indio_dev);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -660,14 +648,14 @@
 
 	iio_trigger_unregister(st->trig);
 	free_irq(st->spi->irq, indio_dev);
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 }
 
 static ssize_t ad7192_read_frequency(struct device *dev,
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7192_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", st->mclk /
@@ -679,7 +667,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7192_state *st = iio_priv(indio_dev);
 	unsigned long lval;
 	int div, ret;
@@ -718,7 +706,7 @@
 static ssize_t ad7192_show_scale_available(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7192_state *st = iio_priv(indio_dev);
 	int i, len = 0;
 
@@ -742,7 +730,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7192_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX));
@@ -752,7 +740,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7192_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW));
@@ -763,7 +751,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7192_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int ret;
@@ -849,7 +837,7 @@
 	bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR);
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		if (iio_buffer_enabled(indio_dev))
 			ret = -EBUSY;
@@ -981,7 +969,8 @@
 	  .extend_name = _name,						\
 	  .channel = _chan,						\
 	  .channel2 = _chan2,						\
-	  .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,		\
+	  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |			\
+	  IIO_CHAN_INFO_SCALE_SHARED_BIT,				\
 	  .address = _address,						\
 	  .scan_index = _si,						\
 	  .scan_type =  IIO_ST('s', 24, 32, 0)}
@@ -990,7 +979,8 @@
 	{ .type = IIO_VOLTAGE,						\
 	  .indexed = 1,							\
 	  .channel = _chan,						\
-	  .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,		\
+	  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |			\
+	  IIO_CHAN_INFO_SCALE_SHARED_BIT,				\
 	  .address = _address,						\
 	  .scan_index = _si,						\
 	  .scan_type =  IIO_ST('s', 24, 32, 0)}
@@ -999,7 +989,8 @@
 	{ .type = IIO_TEMP,						\
 	  .indexed = 1,							\
 	  .channel = _chan,						\
-	  .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
+	  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |			\
+	  IIO_CHAN_INFO_SCALE_SEPARATE_BIT,				\
 	  .address = _address,						\
 	  .scan_index = _si,						\
 	  .scan_type =  IIO_ST('s', 24, 32, 0)}
@@ -1033,7 +1024,7 @@
 		return -ENODEV;
 	}
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -1114,7 +1105,7 @@
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
index 7dbd681..cfc39a7 100644
--- a/drivers/staging/iio/adc/ad7280a.c
+++ b/drivers/staging/iio/adc/ad7280a.c
@@ -16,9 +16,9 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 
 #include "ad7280a.h"
 
@@ -384,7 +384,7 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7280_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -398,7 +398,7 @@
 					 const char *buf,
 					 size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7280_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	bool readin;
@@ -429,7 +429,7 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7280_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int ret;
@@ -453,7 +453,7 @@
 					 const char *buf,
 					 size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7280_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	unsigned long val;
@@ -508,6 +508,7 @@
 			}
 			st->channels[cnt].indexed = 1;
 			st->channels[cnt].info_mask =
+				IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 				IIO_CHAN_INFO_SCALE_SHARED_BIT;
 			st->channels[cnt].address =
 				AD7280A_DEVADDR(dev) << 8 | ch;
@@ -524,7 +525,9 @@
 	st->channels[cnt].channel2 = dev * 6;
 	st->channels[cnt].address = AD7280A_ALL_CELLS;
 	st->channels[cnt].indexed = 1;
-	st->channels[cnt].info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT;
+	st->channels[cnt].info_mask =
+		IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT;
 	st->channels[cnt].scan_index = cnt;
 	st->channels[cnt].scan_type.sign = 'u';
 	st->channels[cnt].scan_type.realbits = 32;
@@ -596,7 +599,7 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7280_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	unsigned val;
@@ -626,7 +629,7 @@
 					 const char *buf,
 					 size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7280_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -788,7 +791,7 @@
 	int ret;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		if (chan->address == AD7280A_ALL_CELLS)
 			ret = ad7280_read_all_channels(st, st->scan_cnt, NULL);
@@ -836,7 +839,7 @@
 	int ret;
 	const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890};
 	const unsigned short nAVG[4] = {1, 2, 4, 8};
-	struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
 
 	if (indio_dev == NULL)
 		return -ENOMEM;
@@ -942,7 +945,7 @@
 	kfree(st->channels);
 
 error_free_device:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -961,7 +964,7 @@
 
 	kfree(st->channels);
 	kfree(st->iio_attr);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c
index 81d6b61..029b39c 100644
--- a/drivers/staging/iio/adc/ad7291.c
+++ b/drivers/staging/iio/adc/ad7291.c
@@ -17,9 +17,9 @@
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 
 /*
  * Simplified handling
@@ -132,7 +132,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7291_chip_info *chip = iio_priv(indio_dev);
 
 	return ad7291_i2c_write(chip, AD7291_COMMAND,
@@ -214,7 +214,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7291_chip_info *chip = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	u16 data;
@@ -232,7 +232,7 @@
 				      const char *buf,
 				      size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7291_chip_info *chip = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	u16 data;
@@ -461,7 +461,7 @@
 	s16 signval;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		switch (chan->type) {
 		case IIO_VOLTAGE:
 			mutex_lock(&chip->state_lock);
@@ -536,7 +536,8 @@
 #define AD7291_VOLTAGE_CHAN(_chan)					\
 {									\
 	.type = IIO_VOLTAGE,						\
-	.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,			\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |			\
+	IIO_CHAN_INFO_SCALE_SHARED_BIT,					\
 	.indexed = 1,							\
 	.channel = _chan,						\
 	.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)|\
@@ -554,7 +555,8 @@
 	AD7291_VOLTAGE_CHAN(7),
 	{
 		.type = IIO_TEMP,
-		.info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+				IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT |
 				IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.indexed = 1,
 		.channel = 0,
@@ -585,7 +587,7 @@
 	struct iio_dev *indio_dev;
 	int ret = 0, voltage_uv = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -667,7 +669,7 @@
 	if (!IS_ERR(chip->reg))
 		regulator_put(chip->reg);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -687,7 +689,7 @@
 		regulator_put(chip->reg);
 	}
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7298.h b/drivers/staging/iio/adc/ad7298.h
index a0e5dea..5051a7e 100644
--- a/drivers/staging/iio/adc/ad7298.h
+++ b/drivers/staging/iio/adc/ad7298.h
@@ -38,7 +38,6 @@
 struct ad7298_state {
 	struct spi_device		*spi;
 	struct regulator		*reg;
-	size_t				d_size;
 	u16				int_vref_mv;
 	unsigned			ext_ref;
 	struct spi_transfer		ring_xfer[10];
diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c
index 8dd6aa9..c90f2b3 100644
--- a/drivers/staging/iio/adc/ad7298_core.c
+++ b/drivers/staging/iio/adc/ad7298_core.c
@@ -16,40 +16,51 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 #include "ad7298.h"
 
+#define AD7298_V_CHAN(index)						\
+	{								\
+		.type = IIO_VOLTAGE,					\
+		.indexed = 1,						\
+		.channel = index,					\
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,				\
+		.address = index,					\
+		.scan_index = index,					\
+		.scan_type = {						\
+			.sign = 'u',					\
+			.realbits = 12,					\
+			.storagebits = 16,				\
+		},							\
+	}
+
 static struct iio_chan_spec ad7298_channels[] = {
-	IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 9, AD7298_CH_TEMP, IIO_ST('s', 32, 32, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 0, 0, IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 1, 1, IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 2, 0,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 2, 2, IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 3, 0,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 3, 3, IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 4, 0,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 4, 4, IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 5, 0,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 5, 5, IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 6, 0,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 6, 6, IIO_ST('u', 12, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 7, 0,
-		 IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		 7, 7, IIO_ST('u', 12, 16, 0), 0),
+	{
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = 9,
+		.scan_index = AD7298_CH_TEMP,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 32,
+			.storagebits = 32,
+		},
+	},
+	AD7298_V_CHAN(0),
+	AD7298_V_CHAN(1),
+	AD7298_V_CHAN(2),
+	AD7298_V_CHAN(3),
+	AD7298_V_CHAN(4),
+	AD7298_V_CHAN(5),
+	AD7298_V_CHAN(6),
+	AD7298_V_CHAN(7),
 	IIO_CHAN_SOFT_TIMESTAMP(8),
 };
 
@@ -121,7 +132,7 @@
 	unsigned int scale_uv;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
 			ret = -EBUSY;
@@ -168,7 +179,7 @@
 	struct ad7298_platform_data *pdata = spi->dev.platform_data;
 	struct ad7298_state *st;
 	int ret;
-	struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
 
 	if (indio_dev == NULL)
 		return -ENOMEM;
@@ -241,7 +252,7 @@
 error_put_reg:
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -258,7 +269,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index feeb0ee..908a3e5 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -1,7 +1,7 @@
 /*
  * AD7298 SPI ADC driver
  *
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
  *
  * Licensed under the GPL-2.
  */
@@ -11,10 +11,10 @@
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
 
 #include "ad7298.h"
 
@@ -28,25 +28,17 @@
 static int ad7298_ring_preenable(struct iio_dev *indio_dev)
 {
 	struct ad7298_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
-	size_t d_size;
 	int i, m;
 	unsigned short command;
-	int scan_count = bitmap_weight(indio_dev->active_scan_mask,
-				       indio_dev->masklength);
-	d_size = scan_count * (AD7298_STORAGE_BITS / 8);
+	int scan_count, ret;
 
-	if (ring->scan_timestamp) {
-		d_size += sizeof(s64);
+	ret = iio_sw_buffer_preenable(indio_dev);
+	if (ret < 0)
+		return ret;
 
-		if (d_size % sizeof(s64))
-			d_size += sizeof(s64) - (d_size % sizeof(s64));
-	}
-
-	if (ring->access->set_bytes_per_datum)
-		ring->access->set_bytes_per_datum(ring, d_size);
-
-	st->d_size = d_size;
+	/* Now compute overall size */
+	scan_count = bitmap_weight(indio_dev->active_scan_mask,
+				   indio_dev->masklength);
 
 	command = AD7298_WRITE | st->ext_ref;
 
@@ -100,9 +92,9 @@
 	if (b_sent)
 		return b_sent;
 
-	if (ring->scan_timestamp) {
+	if (indio_dev->scan_timestamp) {
 		time_ns = iio_get_time_ns();
-		memcpy((u8 *)buf + st->d_size - sizeof(s64),
+		memcpy((u8 *)buf + indio_dev->scan_bytes - sizeof(s64),
 			&time_ns, sizeof(time_ns));
 	}
 
@@ -126,7 +118,7 @@
 {
 	int ret;
 
-	indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
 	if (!indio_dev->buffer) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -140,7 +132,7 @@
 
 	if (indio_dev->pollfunc == NULL) {
 		ret = -ENOMEM;
-		goto error_deallocate_sw_rb;
+		goto error_deallocate_kfifo;
 	}
 
 	/* Ring buffer functions - here trigger setup related */
@@ -151,8 +143,8 @@
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
 	return 0;
 
-error_deallocate_sw_rb:
-	iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+	iio_kfifo_free(indio_dev->buffer);
 error_ret:
 	return ret;
 }
@@ -160,5 +152,5 @@
 void ad7298_ring_cleanup(struct iio_dev *indio_dev)
 {
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_sw_rb_free(indio_dev->buffer);
+	iio_kfifo_free(indio_dev->buffer);
 }
diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h
index 27f696c..b1dd931 100644
--- a/drivers/staging/iio/adc/ad7476.h
+++ b/drivers/staging/iio/adc/ad7476.h
@@ -27,7 +27,6 @@
 	struct spi_device		*spi;
 	const struct ad7476_chip_info	*chip_info;
 	struct regulator		*reg;
-	size_t				d_size;
 	u16				int_vref_mv;
 	struct spi_transfer		xfer;
 	struct spi_message		msg;
diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c
index 0c064d1..be1c260 100644
--- a/drivers/staging/iio/adc/ad7476_core.c
+++ b/drivers/staging/iio/adc/ad7476_core.c
@@ -15,9 +15,9 @@
 #include <linux/err.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 #include "ad7476.h"
 
@@ -43,7 +43,7 @@
 	unsigned int scale_uv;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		if (iio_buffer_enabled(indio_dev))
 			ret = -EBUSY;
@@ -66,53 +66,51 @@
 	return -EINVAL;
 }
 
+#define AD7476_CHAN(bits)					\
+	{							\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+	IIO_CHAN_INFO_SCALE_SHARED_BIT,				\
+	.scan_type = {						\
+		.sign = 'u',					\
+		.realbits = bits,				\
+		.storagebits = 16,				\
+		.shift = 12 - bits,				\
+	},							\
+}
+
 static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
 	[ID_AD7466] = {
-		.channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-				       IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				       0, 0, IIO_ST('u', 12, 16, 0), 0),
+		.channel[0] = AD7476_CHAN(12),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 	},
 	[ID_AD7467] = {
-		.channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-				       IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				       0, 0, IIO_ST('u', 10, 16, 2), 0),
+		.channel[0] = AD7476_CHAN(10),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 	},
 	[ID_AD7468] = {
-		.channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1 , 0, NULL, 0, 0,
-				       IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				       0, 0, IIO_ST('u', 8, 16, 4), 0),
+		.channel[0] = AD7476_CHAN(8),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 	},
 	[ID_AD7475] = {
-		.channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-				       IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				       0, 0, IIO_ST('u', 12, 16, 0), 0),
+		.channel[0] = AD7476_CHAN(12),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 	},
 	[ID_AD7476] = {
-		.channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-				       IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				       0, 0, IIO_ST('u', 12, 16, 0), 0),
+		.channel[0] = AD7476_CHAN(12),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 	},
 	[ID_AD7477] = {
-		.channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-				       IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				       0, 0, IIO_ST('u', 10, 16, 2), 0),
+		.channel[0] = AD7476_CHAN(10),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 	},
 	[ID_AD7478] = {
-		.channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-				       IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				       0, 0, IIO_ST('u', 8, 16, 4), 0),
+		.channel[0] = AD7476_CHAN(8),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 	},
 	[ID_AD7495] = {
-		.channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-				       IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				       0, 0, IIO_ST('u', 12, 16, 0), 0),
+		.channel[0] = AD7476_CHAN(12),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 		.int_vref_mv = 2500,
 	},
@@ -130,7 +128,7 @@
 	struct iio_dev *indio_dev;
 	int ret, voltage_uv = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -200,7 +198,7 @@
 error_put_reg:
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 error_ret:
 	return ret;
@@ -218,7 +216,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
index d6af6c0..383611b 100644
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ b/drivers/staging/iio/adc/ad7476_ring.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Analog Devices Inc.
+ * Copyright 2010-2012 Analog Devices Inc.
  * Copyright (C) 2008 Jonathan Cameron
  *
  * Licensed under the GPL-2 or later.
@@ -13,43 +13,13 @@
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
 
 #include "ad7476.h"
 
-/**
- * ad7476_ring_preenable() setup the parameters of the ring before enabling
- *
- * The complex nature of the setting of the number of bytes per datum is due
- * to this driver currently ensuring that the timestamp is stored at an 8
- * byte boundary.
- **/
-static int ad7476_ring_preenable(struct iio_dev *indio_dev)
-{
-	struct ad7476_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
-
-	st->d_size = bitmap_weight(indio_dev->active_scan_mask,
-				   indio_dev->masklength) *
-		st->chip_info->channel[0].scan_type.storagebits / 8;
-
-	if (ring->scan_timestamp) {
-		st->d_size += sizeof(s64);
-
-		if (st->d_size % sizeof(s64))
-			st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
-	}
-
-	if (indio_dev->buffer->access->set_bytes_per_datum)
-		indio_dev->buffer->access->
-			set_bytes_per_datum(indio_dev->buffer, st->d_size);
-
-	return 0;
-}
-
 static irqreturn_t ad7476_trigger_handler(int irq, void  *p)
 {
 	struct iio_poll_func *pf = p;
@@ -59,7 +29,7 @@
 	__u8 *rxbuf;
 	int b_sent;
 
-	rxbuf = kzalloc(st->d_size, GFP_KERNEL);
+	rxbuf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (rxbuf == NULL)
 		return -ENOMEM;
 
@@ -70,8 +40,8 @@
 
 	time_ns = iio_get_time_ns();
 
-	if (indio_dev->buffer->scan_timestamp)
-		memcpy(rxbuf + st->d_size - sizeof(s64),
+	if (indio_dev->scan_timestamp)
+		memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
 			&time_ns, sizeof(time_ns));
 
 	indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns);
@@ -83,7 +53,7 @@
 }
 
 static const struct iio_buffer_setup_ops ad7476_ring_setup_ops = {
-	.preenable = &ad7476_ring_preenable,
+	.preenable = &iio_sw_buffer_preenable,
 	.postenable = &iio_triggered_buffer_postenable,
 	.predisable = &iio_triggered_buffer_predisable,
 };
@@ -93,7 +63,7 @@
 	struct ad7476_state *st = iio_priv(indio_dev);
 	int ret = 0;
 
-	indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
 	if (!indio_dev->buffer) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -108,7 +78,7 @@
 				     indio_dev->id);
 	if (indio_dev->pollfunc == NULL) {
 		ret = -ENOMEM;
-		goto error_deallocate_sw_rb;
+		goto error_deallocate_kfifo;
 	}
 
 	/* Ring buffer functions - here trigger setup related */
@@ -119,8 +89,8 @@
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
 	return 0;
 
-error_deallocate_sw_rb:
-	iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+	iio_kfifo_free(indio_dev->buffer);
 error_ret:
 	return ret;
 }
@@ -128,5 +98,5 @@
 void ad7476_ring_cleanup(struct iio_dev *indio_dev)
 {
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_sw_rb_free(indio_dev->buffer);
+	iio_kfifo_free(indio_dev->buffer);
 }
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
index 97e8d3d..10ab6dc 100644
--- a/drivers/staging/iio/adc/ad7606_core.c
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -18,9 +18,9 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 #include "ad7606.h"
 
@@ -88,7 +88,7 @@
 	unsigned int scale_uv;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		if (iio_buffer_enabled(indio_dev))
 			ret = -EBUSY;
@@ -113,7 +113,7 @@
 static ssize_t ad7606_show_range(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7606_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%u\n", st->range);
@@ -122,7 +122,7 @@
 static ssize_t ad7606_store_range(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7606_state *st = iio_priv(indio_dev);
 	unsigned long lval;
 
@@ -147,7 +147,7 @@
 static ssize_t ad7606_show_oversampling_ratio(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7606_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%u\n", st->oversampling);
@@ -168,7 +168,7 @@
 static ssize_t ad7606_store_oversampling_ratio(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7606_state *st = iio_priv(indio_dev);
 	unsigned long lval;
 	int ret;
@@ -229,14 +229,15 @@
 	.attrs = ad7606_attributes_range,
 };
 
-#define AD7606_CHANNEL(num)				\
-	{						\
-		.type = IIO_VOLTAGE,			\
-		.indexed = 1,				\
-		.channel = num,				\
-		.address = num,				\
-		.scan_index = num,			\
-		.scan_type = IIO_ST('s', 16, 16, 0),	\
+#define AD7606_CHANNEL(num)					\
+	{							\
+		.type = IIO_VOLTAGE,				\
+		.indexed = 1,					\
+		.channel = num,					\
+		.address = num,					\
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,	\
+		.scan_index = num,				\
+		.scan_type = IIO_ST('s', 16, 16, 0),		\
 	}
 
 static struct iio_chan_spec ad7606_8_channels[] = {
@@ -460,7 +461,7 @@
 	struct ad7606_platform_data *pdata = dev->platform_data;
 	struct ad7606_state *st;
 	int ret;
-	struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
 
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
@@ -559,7 +560,7 @@
 error_put_reg:
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ERR_PTR(ret);
 }
@@ -579,7 +580,7 @@
 	}
 
 	ad7606_free_gpios(st);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c
index bb152a8..a53faaf 100644
--- a/drivers/staging/iio/adc/ad7606_par.c
+++ b/drivers/staging/iio/adc/ad7606_par.c
@@ -12,7 +12,7 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "ad7606.h"
 
 static int ad7606_par16_read_block(struct device *dev,
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index 1ef9fbc..24ce8fc 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
  *
  * Licensed under the GPL-2.
  *
@@ -11,10 +11,10 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
 
 #include "ad7606.h"
 
@@ -51,8 +51,7 @@
 	__u8 *buf;
 	int ret;
 
-	buf = kzalloc(ring->access->get_bytes_per_datum(ring),
-		      GFP_KERNEL);
+	buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (buf == NULL)
 		return;
 
@@ -82,9 +81,8 @@
 
 	time_ns = iio_get_time_ns();
 
-	if (ring->scan_timestamp)
-		*((s64 *)(buf + ring->access->get_bytes_per_datum(ring) -
-			  sizeof(s64))) = time_ns;
+	if (indio_dev->scan_timestamp)
+		*((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns;
 
 	ring->access->store_to(indio_dev->buffer, buf, time_ns);
 done:
@@ -104,7 +102,7 @@
 	struct ad7606_state *st = iio_priv(indio_dev);
 	int ret;
 
-	indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
 	if (!indio_dev->buffer) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -119,13 +117,13 @@
 						 indio_dev->id);
 	if (indio_dev->pollfunc == NULL) {
 		ret = -ENOMEM;
-		goto error_deallocate_sw_rb;
+		goto error_deallocate_kfifo;
 	}
 
 	/* Ring buffer functions - here trigger setup related */
 
 	indio_dev->setup_ops = &ad7606_ring_setup_ops;
-	indio_dev->buffer->scan_timestamp = true ;
+	indio_dev->buffer->scan_timestamp = true;
 
 	INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring);
 
@@ -133,8 +131,8 @@
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
 	return 0;
 
-error_deallocate_sw_rb:
-	iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+	iio_kfifo_free(indio_dev->buffer);
 error_ret:
 	return ret;
 }
@@ -142,5 +140,5 @@
 void ad7606_ring_cleanup(struct iio_dev *indio_dev)
 {
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_sw_rb_free(indio_dev->buffer);
+	iio_kfifo_free(indio_dev->buffer);
 }
diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c
index 237f1c4..099d347 100644
--- a/drivers/staging/iio/adc/ad7606_spi.c
+++ b/drivers/staging/iio/adc/ad7606_spi.c
@@ -11,7 +11,7 @@
 #include <linux/types.h>
 #include <linux/err.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "ad7606.h"
 
 #define MAX_SPI_FREQ_HZ		23500000	/* VDRIVE above 4.75 V */
diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c
index a13e58c..1ece2ac 100644
--- a/drivers/staging/iio/adc/ad7780.c
+++ b/drivers/staging/iio/adc/ad7780.c
@@ -18,8 +18,8 @@
 #include <linux/gpio.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #include "ad7780.h"
 
@@ -94,7 +94,7 @@
 	unsigned long scale_uv;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		ret = ad7780_read(st, &smpl);
 		mutex_unlock(&indio_dev->mlock);
@@ -126,14 +126,34 @@
 
 static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
 	[ID_AD7780] = {
-		.channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-				    IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				    0, 0, IIO_ST('s', 24, 32, 8), 0),
+		.channel = {
+			.type = IIO_VOLTAGE,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.scan_type = {
+				.sign = 's',
+				.realbits = 24,
+				.storagebits = 32,
+				.shift = 8,
+			},
+		},
 	},
 	[ID_AD7781] = {
-		.channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
-				    IIO_CHAN_INFO_SCALE_SHARED_BIT,
-				    0, 0, IIO_ST('s', 20, 32, 12), 0),
+		.channel = {
+			.type = IIO_VOLTAGE,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.scan_type = {
+				.sign = 's',
+				.realbits = 20,
+				.storagebits = 32,
+				.shift = 12,
+			},
+		},
 	},
 };
 
@@ -167,7 +187,7 @@
 		return -ENODEV;
 	}
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -245,7 +265,7 @@
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -262,7 +282,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c
index 84ecde1..b36556f 100644
--- a/drivers/staging/iio/adc/ad7793.c
+++ b/drivers/staging/iio/adc/ad7793.c
@@ -1,7 +1,7 @@
 /*
  * AD7792/AD7793 SPI ADC driver
  *
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
  *
  * Licensed under the GPL-2.
  */
@@ -18,12 +18,12 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
 
 #include "ad7793.h"
 
@@ -319,31 +319,18 @@
 static int ad7793_ring_preenable(struct iio_dev *indio_dev)
 {
 	struct ad7793_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
-	size_t d_size;
 	unsigned channel;
+	int ret;
 
 	if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
 		return -EINVAL;
+	ret = iio_sw_buffer_preenable(indio_dev);
+	if (ret < 0)
+		return ret;
 
 	channel = find_first_bit(indio_dev->active_scan_mask,
 				 indio_dev->masklength);
 
-	d_size = bitmap_weight(indio_dev->active_scan_mask,
-			       indio_dev->masklength) *
-		indio_dev->channels[0].scan_type.storagebits / 8;
-
-	if (ring->scan_timestamp) {
-		d_size += sizeof(s64);
-
-		if (d_size % sizeof(s64))
-			d_size += sizeof(s64) - (d_size % sizeof(s64));
-	}
-
-	if (indio_dev->buffer->access->set_bytes_per_datum)
-		indio_dev->buffer->access->
-			set_bytes_per_datum(indio_dev->buffer, d_size);
-
 	st->mode  = (st->mode & ~AD7793_MODE_SEL(-1)) |
 		    AD7793_MODE_SEL(AD7793_MODE_CONT);
 	st->conf  = (st->conf & ~AD7793_CONF_CHAN(-1)) |
@@ -399,7 +386,7 @@
 				  indio_dev->channels[0].scan_type.realbits/8);
 
 	/* Guaranteed to be aligned with 8 byte boundary */
-	if (ring->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		dat64[1] = pf->timestamp;
 
 	ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
@@ -422,7 +409,7 @@
 {
 	int ret;
 
-	indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
 	if (!indio_dev->buffer) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -435,7 +422,7 @@
 						 indio_dev->id);
 	if (indio_dev->pollfunc == NULL) {
 		ret = -ENOMEM;
-		goto error_deallocate_sw_rb;
+		goto error_deallocate_kfifo;
 	}
 
 	/* Ring buffer functions - here trigger setup related */
@@ -445,8 +432,8 @@
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
 	return 0;
 
-error_deallocate_sw_rb:
-	iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+	iio_kfifo_free(indio_dev->buffer);
 error_ret:
 	return ret;
 }
@@ -454,7 +441,7 @@
 static void ad7793_ring_cleanup(struct iio_dev *indio_dev)
 {
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_sw_rb_free(indio_dev->buffer);
+	iio_kfifo_free(indio_dev->buffer);
 }
 
 /**
@@ -482,7 +469,7 @@
 	struct ad7793_state *st = iio_priv(indio_dev);
 	int ret;
 
-	st->trig = iio_allocate_trigger("%s-dev%d",
+	st->trig = iio_trigger_alloc("%s-dev%d",
 					spi_get_device_id(st->spi)->name,
 					indio_dev->id);
 	if (st->trig == NULL) {
@@ -516,7 +503,7 @@
 error_free_irq:
 	free_irq(st->spi->irq, indio_dev);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -527,7 +514,7 @@
 
 	iio_trigger_unregister(st->trig);
 	free_irq(st->spi->irq, indio_dev);
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 }
 
 static const u16 sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, 33, 19,
@@ -537,7 +524,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7793_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n",
@@ -549,7 +536,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7793_state *st = iio_priv(indio_dev);
 	long lval;
 	int i, ret;
@@ -591,7 +578,7 @@
 static ssize_t ad7793_show_scale_available(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7793_state *st = iio_priv(indio_dev);
 	int i, len = 0;
 
@@ -630,7 +617,7 @@
 	bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR);
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		if (iio_buffer_enabled(indio_dev))
 			ret = -EBUSY;
@@ -760,7 +747,8 @@
 			.channel = 0,
 			.channel2 = 0,
 			.address = AD7793_CH_AIN1P_AIN1M,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.scan_index = 0,
 			.scan_type = IIO_ST('s', 24, 32, 0)
 		},
@@ -771,7 +759,8 @@
 			.channel = 1,
 			.channel2 = 1,
 			.address = AD7793_CH_AIN2P_AIN2M,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.scan_index = 1,
 			.scan_type = IIO_ST('s', 24, 32, 0)
 		},
@@ -782,7 +771,8 @@
 			.channel = 2,
 			.channel2 = 2,
 			.address = AD7793_CH_AIN3P_AIN3M,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.scan_index = 2,
 			.scan_type = IIO_ST('s', 24, 32, 0)
 		},
@@ -794,7 +784,8 @@
 			.channel = 2,
 			.channel2 = 2,
 			.address = AD7793_CH_AIN1M_AIN1M,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.scan_index = 2,
 			.scan_type = IIO_ST('s', 24, 32, 0)
 		},
@@ -803,7 +794,8 @@
 			.indexed = 1,
 			.channel = 0,
 			.address = AD7793_CH_TEMP,
-			.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 			.scan_index = 4,
 			.scan_type = IIO_ST('s', 24, 32, 0),
 		},
@@ -813,7 +805,8 @@
 			.indexed = 1,
 			.channel = 4,
 			.address = AD7793_CH_AVDD_MONITOR,
-			.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 			.scan_index = 5,
 			.scan_type = IIO_ST('s', 24, 32, 0),
 		},
@@ -827,7 +820,8 @@
 			.channel = 0,
 			.channel2 = 0,
 			.address = AD7793_CH_AIN1P_AIN1M,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.scan_index = 0,
 			.scan_type = IIO_ST('s', 16, 32, 0)
 		},
@@ -838,7 +832,8 @@
 			.channel = 1,
 			.channel2 = 1,
 			.address = AD7793_CH_AIN2P_AIN2M,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.scan_index = 1,
 			.scan_type = IIO_ST('s', 16, 32, 0)
 		},
@@ -849,7 +844,8 @@
 			.channel = 2,
 			.channel2 = 2,
 			.address = AD7793_CH_AIN3P_AIN3M,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.scan_index = 2,
 			.scan_type = IIO_ST('s', 16, 32, 0)
 		},
@@ -861,7 +857,8 @@
 			.channel = 2,
 			.channel2 = 2,
 			.address = AD7793_CH_AIN1M_AIN1M,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.scan_index = 2,
 			.scan_type = IIO_ST('s', 16, 32, 0)
 		},
@@ -870,7 +867,8 @@
 			.indexed = 1,
 			.channel = 0,
 			.address = AD7793_CH_TEMP,
-			.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 			.scan_index = 4,
 			.scan_type = IIO_ST('s', 16, 32, 0),
 		},
@@ -880,7 +878,8 @@
 			.indexed = 1,
 			.channel = 4,
 			.address = AD7793_CH_AVDD_MONITOR,
-			.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 			.scan_index = 5,
 			.scan_type = IIO_ST('s', 16, 32, 0),
 		},
@@ -905,7 +904,7 @@
 		return -ENODEV;
 	}
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -989,7 +988,7 @@
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -1009,7 +1008,7 @@
 		regulator_put(st->reg);
 	}
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
index 52b720e..5356b09 100644
--- a/drivers/staging/iio/adc/ad7816.c
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -16,9 +16,9 @@
 #include <linux/spi/spi.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 
 /*
  * AD7816 config masks
@@ -113,7 +113,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7816_chip_info *chip = iio_priv(indio_dev);
 
 	if (chip->mode)
@@ -127,7 +127,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7816_chip_info *chip = iio_priv(indio_dev);
 
 	if (strcmp(buf, "full")) {
@@ -159,7 +159,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7816_chip_info *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", chip->channel_id);
@@ -170,7 +170,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7816_chip_info *chip = iio_priv(indio_dev);
 	unsigned long data;
 	int ret;
@@ -208,7 +208,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7816_chip_info *chip = iio_priv(indio_dev);
 	u16 data;
 	s8 value;
@@ -263,7 +263,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7816_chip_info *chip = iio_priv(indio_dev);
 	int value;
 
@@ -284,7 +284,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7816_chip_info *chip = iio_priv(indio_dev);
 	long value;
 	u8 data;
@@ -354,7 +354,7 @@
 		return -EINVAL;
 	}
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -426,7 +426,7 @@
 error_free_gpio_rdwr:
 	gpio_free(chip->rdwr_pin);
 error_free_device:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -443,7 +443,7 @@
 	gpio_free(chip->busy_pin);
 	gpio_free(chip->convert_pin);
 	gpio_free(chip->rdwr_pin);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h
index bc53b65..2e09e54 100644
--- a/drivers/staging/iio/adc/ad7887.h
+++ b/drivers/staging/iio/adc/ad7887.h
@@ -63,7 +63,6 @@
 	struct spi_device		*spi;
 	const struct ad7887_chip_info	*chip_info;
 	struct regulator		*reg;
-	size_t				d_size;
 	u16				int_vref_mv;
 	struct spi_transfer		xfer[4];
 	struct spi_message		msg[3];
diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c
index e9bbc3e..7186074 100644
--- a/drivers/staging/iio/adc/ad7887_core.c
+++ b/drivers/staging/iio/adc/ad7887_core.c
@@ -15,9 +15,9 @@
 #include <linux/err.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 
 #include "ad7887.h"
@@ -42,7 +42,7 @@
 	unsigned int scale_uv;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		if (iio_buffer_enabled(indio_dev))
 			ret = -EBUSY;
@@ -75,7 +75,8 @@
 			.type = IIO_VOLTAGE,
 			.indexed = 1,
 			.channel = 1,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.address = 1,
 			.scan_index = 1,
 			.scan_type = IIO_ST('u', 12, 16, 0),
@@ -84,7 +85,8 @@
 			.type = IIO_VOLTAGE,
 			.indexed = 1,
 			.channel = 0,
-			.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT,
 			.address = 0,
 			.scan_index = 0,
 			.scan_type = IIO_ST('u', 12, 16, 0),
@@ -104,7 +106,7 @@
 	struct ad7887_platform_data *pdata = spi->dev.platform_data;
 	struct ad7887_state *st;
 	int ret, voltage_uv = 0;
-	struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
 
 	if (indio_dev == NULL)
 		return -ENOMEM;
@@ -220,7 +222,7 @@
 error_put_reg:
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -237,7 +239,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index d180907..fd91384 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2011 Analog Devices Inc.
+ * Copyright 2010-2012 Analog Devices Inc.
  * Copyright (C) 2008 Jonathan Cameron
  *
  * Licensed under the GPL-2.
@@ -12,10 +12,10 @@
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
 
 #include "ad7887.h"
 
@@ -29,22 +29,11 @@
 static int ad7887_ring_preenable(struct iio_dev *indio_dev)
 {
 	struct ad7887_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
+	int ret;
 
-	st->d_size = bitmap_weight(indio_dev->active_scan_mask,
-				   indio_dev->masklength) *
-		st->chip_info->channel[0].scan_type.storagebits / 8;
-
-	if (ring->scan_timestamp) {
-		st->d_size += sizeof(s64);
-
-		if (st->d_size % sizeof(s64))
-			st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
-	}
-
-	if (indio_dev->buffer->access->set_bytes_per_datum)
-		indio_dev->buffer->access->
-			set_bytes_per_datum(indio_dev->buffer, st->d_size);
+	ret = iio_sw_buffer_preenable(indio_dev);
+	if (ret < 0)
+		return ret;
 
 	/* We know this is a single long so can 'cheat' */
 	switch (*indio_dev->active_scan_mask) {
@@ -83,7 +72,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ad7887_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
 	s64 time_ns;
 	__u8 *buf;
 	int b_sent;
@@ -92,7 +80,7 @@
 					   indio_dev->masklength) *
 		st->chip_info->channel[0].scan_type.storagebits / 8;
 
-	buf = kzalloc(st->d_size, GFP_KERNEL);
+	buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (buf == NULL)
 		return -ENOMEM;
 
@@ -103,8 +91,8 @@
 	time_ns = iio_get_time_ns();
 
 	memcpy(buf, st->data, bytes);
-	if (ring->scan_timestamp)
-		memcpy(buf + st->d_size - sizeof(s64),
+	if (indio_dev->scan_timestamp)
+		memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
 		       &time_ns, sizeof(time_ns));
 
 	indio_dev->buffer->access->store_to(indio_dev->buffer, buf, time_ns);
@@ -126,7 +114,7 @@
 {
 	int ret;
 
-	indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
 	if (!indio_dev->buffer) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -139,7 +127,7 @@
 						 indio_dev->id);
 	if (indio_dev->pollfunc == NULL) {
 		ret = -ENOMEM;
-		goto error_deallocate_sw_rb;
+		goto error_deallocate_kfifo;
 	}
 	/* Ring buffer functions - here trigger setup related */
 	indio_dev->setup_ops = &ad7887_ring_setup_ops;
@@ -148,8 +136,8 @@
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
 	return 0;
 
-error_deallocate_sw_rb:
-	iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+	iio_kfifo_free(indio_dev->buffer);
 error_ret:
 	return ret;
 }
@@ -157,5 +145,5 @@
 void ad7887_ring_cleanup(struct iio_dev *indio_dev)
 {
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_sw_rb_free(indio_dev->buffer);
+	iio_kfifo_free(indio_dev->buffer);
 }
diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h
index 356f690a..99f8abe 100644
--- a/drivers/staging/iio/adc/ad799x.h
+++ b/drivers/staging/iio/adc/ad799x.h
@@ -104,7 +104,6 @@
 struct ad799x_state {
 	struct i2c_client		*client;
 	const struct ad799x_chip_info	*chip_info;
-	size_t				d_size;
 	struct iio_trigger		*trig;
 	struct regulator		*reg;
 	u16				int_vref_mv;
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
index a845866..80e0c6e 100644
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -33,10 +33,10 @@
 #include <linux/err.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
 
 #include "ad799x.h"
 
@@ -148,7 +148,7 @@
 	unsigned int scale_uv;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		if (iio_buffer_enabled(indio_dev))
 			ret = -EBUSY;
@@ -182,7 +182,7 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad799x_state *st = iio_priv(indio_dev);
 
 	int ret;
@@ -201,7 +201,7 @@
 					 const char *buf,
 					 size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad799x_state *st = iio_priv(indio_dev);
 
 	long val;
@@ -294,7 +294,7 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad799x_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -312,7 +312,7 @@
 					 const char *buf,
 					 size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad799x_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -454,6 +454,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 0,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 0,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 			},
@@ -461,6 +462,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 1,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 1,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 			},
@@ -468,6 +470,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 2,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 2,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 			},
@@ -475,6 +478,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 3,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 3,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 			},
@@ -490,6 +494,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 0,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 0,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 			},
@@ -497,6 +502,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 1,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 1,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 			},
@@ -504,6 +510,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 2,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 2,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 			},
@@ -511,6 +518,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 3,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 3,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 			},
@@ -526,6 +534,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 0,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 0,
 				.scan_type = IIO_ST('u', 8, 16, 4),
 			},
@@ -533,6 +542,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 1,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 1,
 				.scan_type = IIO_ST('u', 8, 16, 4),
 			},
@@ -540,6 +550,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 2,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 2,
 				.scan_type = IIO_ST('u', 8, 16, 4),
 			},
@@ -547,6 +558,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 3,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 3,
 				.scan_type = IIO_ST('u', 8, 16, 4),
 			},
@@ -562,6 +574,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 0,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 0,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -570,6 +583,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 1,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 1,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -587,6 +601,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 0,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 0,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 				.event_mask = AD799X_EV_MASK,
@@ -596,6 +611,7 @@
 				.indexed = 1,
 				.channel = 1,
 				.scan_index = 1,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 				.event_mask = AD799X_EV_MASK,
 			},
@@ -603,6 +619,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 2,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 2,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 				.event_mask = AD799X_EV_MASK,
@@ -611,6 +628,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 3,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 3,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 				.event_mask = AD799X_EV_MASK,
@@ -628,6 +646,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 0,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 0,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -636,6 +655,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 1,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 1,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -644,6 +664,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 2,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 2,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -652,6 +673,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 3,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 3,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -669,6 +691,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 0,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 0,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 				.event_mask = AD799X_EV_MASK,
@@ -677,6 +700,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 1,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 1,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 				.event_mask = AD799X_EV_MASK,
@@ -685,6 +709,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 2,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 2,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 				.event_mask = AD799X_EV_MASK,
@@ -693,6 +718,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 3,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 3,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 				.event_mask = AD799X_EV_MASK,
@@ -701,6 +727,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 4,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 4,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 			},
@@ -708,6 +735,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 5,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 5,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 			},
@@ -715,6 +743,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 6,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 6,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 			},
@@ -722,6 +751,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 7,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 7,
 				.scan_type = IIO_ST('u', 10, 16, 2),
 			},
@@ -738,6 +768,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 0,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 0,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -746,6 +777,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 1,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 1,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -754,6 +786,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 2,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 2,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -762,6 +795,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 3,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 3,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 				.event_mask = AD799X_EV_MASK,
@@ -770,6 +804,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 4,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 4,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 			},
@@ -777,6 +812,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 5,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 5,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 			},
@@ -784,6 +820,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 6,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 6,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 			},
@@ -791,6 +828,7 @@
 				.type = IIO_VOLTAGE,
 				.indexed = 1,
 				.channel = 7,
+				.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 				.scan_index = 7,
 				.scan_type = IIO_ST('u', 12, 16, 0),
 			},
@@ -809,7 +847,7 @@
 	int ret;
 	struct ad799x_platform_data *pdata = client->dev.platform_data;
 	struct ad799x_state *st;
-	struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
 
 	if (indio_dev == NULL)
 		return -ENOMEM;
@@ -882,7 +920,7 @@
 error_put_reg:
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -902,7 +940,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 069765c..1c7ff44 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ * Copyright (C) 2010-2012 Michael Hennerich, Analog Devices Inc.
  * Copyright (C) 2008-2010 Jonathan Cameron
  *
  * This program is free software; you can redistribute it and/or modify
@@ -16,10 +16,10 @@
 #include <linux/i2c.h>
 #include <linux/bitops.h>
 
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
 
 #include "ad799x.h"
 
@@ -32,9 +32,7 @@
  **/
 static int ad799x_ring_preenable(struct iio_dev *indio_dev)
 {
-	struct iio_buffer *ring = indio_dev->buffer;
 	struct ad799x_state *st = iio_priv(indio_dev);
-
 	/*
 	 * Need to figure out the current mode based upon the requested
 	 * scan mask in iio_dev
@@ -43,21 +41,7 @@
 	if (st->id == ad7997 || st->id == ad7998)
 		ad7997_8_set_scan_mode(st, *indio_dev->active_scan_mask);
 
-	st->d_size = bitmap_weight(indio_dev->active_scan_mask,
-				   indio_dev->masklength) * 2;
-
-	if (ring->scan_timestamp) {
-		st->d_size += sizeof(s64);
-
-		if (st->d_size % sizeof(s64))
-			st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
-	}
-
-	if (indio_dev->buffer->access->set_bytes_per_datum)
-		indio_dev->buffer->access->
-			set_bytes_per_datum(indio_dev->buffer, st->d_size);
-
-	return 0;
+	return iio_sw_buffer_preenable(indio_dev);
 }
 
 /**
@@ -78,7 +62,7 @@
 	int b_sent;
 	u8 cmd;
 
-	rxbuf = kmalloc(st->d_size, GFP_KERNEL);
+	rxbuf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (rxbuf == NULL)
 		goto out;
 
@@ -111,8 +95,8 @@
 
 	time_ns = iio_get_time_ns();
 
-	if (ring->scan_timestamp)
-		memcpy(rxbuf + st->d_size - sizeof(s64),
+	if (indio_dev->scan_timestamp)
+		memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
 			&time_ns, sizeof(time_ns));
 
 	ring->access->store_to(indio_dev->buffer, rxbuf, time_ns);
@@ -136,7 +120,7 @@
 {
 	int ret = 0;
 
-	indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
 	if (!indio_dev->buffer) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -150,7 +134,7 @@
 						 indio_dev->id);
 	if (indio_dev->pollfunc == NULL) {
 		ret = -ENOMEM;
-		goto error_deallocate_sw_rb;
+		goto error_deallocate_kfifo;
 	}
 
 	/* Ring buffer functions - here trigger setup related */
@@ -161,8 +145,8 @@
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
 	return 0;
 
-error_deallocate_sw_rb:
-	iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+	iio_kfifo_free(indio_dev->buffer);
 error_ret:
 	return ret;
 }
@@ -170,5 +154,5 @@
 void ad799x_ring_cleanup(struct iio_dev *indio_dev)
 {
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_sw_rb_free(indio_dev->buffer);
+	iio_kfifo_free(indio_dev->buffer);
 }
diff --git a/drivers/staging/iio/adc/adt7310.c b/drivers/staging/iio/adc/adt7310.c
index caf57c1..e5f1ed7f 100644
--- a/drivers/staging/iio/adc/adt7310.c
+++ b/drivers/staging/iio/adc/adt7310.c
@@ -15,9 +15,9 @@
 #include <linux/spi/spi.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 /*
  * ADT7310 registers definition
  */
@@ -175,7 +175,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	u8 config;
 
@@ -198,7 +198,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	u16 config;
 	int ret;
@@ -242,7 +242,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	int ret;
 	int bits;
@@ -264,7 +264,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	unsigned long data;
 	u16 config;
@@ -300,7 +300,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	u8 id;
 	int ret;
@@ -350,7 +350,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	u8 status;
 	u16 data;
@@ -424,7 +424,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	int ret;
 
@@ -443,7 +443,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	u16 config;
 	int ret;
@@ -476,7 +476,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	int ret;
 
@@ -492,7 +492,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	unsigned long data;
 	int ret;
@@ -522,7 +522,7 @@
 		u8 bound_reg,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	u16 data;
 	int ret;
@@ -540,7 +540,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	long tmp1, tmp2;
 	u16 data;
@@ -660,7 +660,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	int ret;
 	u8 t_hyst;
@@ -677,7 +677,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7310_chip_info *chip = iio_priv(dev_info);
 	int ret;
 	unsigned long data;
@@ -753,7 +753,7 @@
 	unsigned long *adt7310_platform_data = spi_dev->dev.platform_data;
 	unsigned long irq_flags;
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -833,7 +833,7 @@
 error_unreg_ct_irq:
 	free_irq(spi_dev->irq, indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -849,7 +849,7 @@
 		free_irq(adt7310_platform_data[0], indio_dev);
 	if (spi_dev->irq)
 		free_irq(spi_dev->irq, indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c
index dff3e8c..917b692 100644
--- a/drivers/staging/iio/adc/adt7410.c
+++ b/drivers/staging/iio/adc/adt7410.c
@@ -15,9 +15,9 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 
 /*
  * ADT7410 registers definition
@@ -144,7 +144,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	u8 config;
 
@@ -167,7 +167,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	u16 config;
 	int ret;
@@ -211,7 +211,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	int ret;
 	int bits;
@@ -233,7 +233,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	unsigned long data;
 	u16 config;
@@ -269,7 +269,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	u8 id;
 	int ret;
@@ -319,7 +319,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	u8 status;
 	u16 data;
@@ -392,7 +392,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	int ret;
 
@@ -411,7 +411,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	u16 config;
 	int ret;
@@ -444,7 +444,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	int ret;
 
@@ -460,7 +460,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	unsigned long data;
 	int ret;
@@ -490,7 +490,7 @@
 		u8 bound_reg,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	u16 data;
 	int ret;
@@ -508,7 +508,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	long tmp1, tmp2;
 	u16 data;
@@ -628,7 +628,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	int ret;
 	u8 t_hyst;
@@ -645,7 +645,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7410_chip_info *chip = iio_priv(dev_info);
 	int ret;
 	unsigned long data;
@@ -721,7 +721,7 @@
 	int ret = 0;
 	unsigned long *adt7410_platform_data = client->dev.platform_data;
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -797,7 +797,7 @@
 error_unreg_ct_irq:
 	free_irq(client->irq, indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -812,7 +812,7 @@
 		free_irq(adt7410_platform_data[0], indio_dev);
 	if (client->irq)
 		free_irq(client->irq, indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c
index dfc9033..9690306 100644
--- a/drivers/staging/iio/adc/lpc32xx_adc.c
+++ b/drivers/staging/iio/adc/lpc32xx_adc.c
@@ -30,9 +30,10 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/completion.h>
+#include <linux/of.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 /*
  * LPC32XX registers definitions
@@ -73,7 +74,7 @@
 {
 	struct lpc32xx_adc_info *info = iio_priv(indio_dev);
 
-	if (mask == 0) {
+	if (mask == IIO_CHAN_INFO_RAW) {
 		mutex_lock(&indio_dev->mlock);
 		clk_enable(info->clk);
 		/* Measurement setup */
@@ -98,12 +99,13 @@
 	.driver_module = THIS_MODULE,
 };
 
-#define LPC32XX_ADC_CHANNEL(_index) {		\
-	.type = IIO_VOLTAGE,			\
-	.indexed = 1,				\
-	.channel = _index,			\
-	.address = AD_IN * _index,		\
-	.scan_index = _index,			\
+#define LPC32XX_ADC_CHANNEL(_index) {			\
+	.type = IIO_VOLTAGE,				\
+	.indexed = 1,					\
+	.channel = _index,				\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,	\
+	.address = AD_IN * _index,			\
+	.scan_index = _index,				\
 }
 
 static struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
@@ -139,7 +141,7 @@
 		goto errout1;
 	}
 
-	iodev = iio_allocate_device(sizeof(struct lpc32xx_adc_info));
+	iodev = iio_device_alloc(sizeof(struct lpc32xx_adc_info));
 	if (!iodev) {
 		dev_err(&pdev->dev, "failed allocating iio device\n");
 		retval = -ENOMEM;
@@ -200,7 +202,7 @@
 errout3:
 	iounmap(info->adc_base);
 errout2:
-	iio_free_device(iodev);
+	iio_device_free(iodev);
 errout1:
 	return retval;
 }
@@ -216,17 +218,26 @@
 	platform_set_drvdata(pdev, NULL);
 	clk_put(info->clk);
 	iounmap(info->adc_base);
-	iio_free_device(iodev);
+	iio_device_free(iodev);
 
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id lpc32xx_adc_match[] = {
+	{ .compatible = "nxp,lpc3220-adc" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_adc_match);
+#endif
+
 static struct platform_driver lpc32xx_adc_driver = {
 	.probe		= lpc32xx_adc_probe,
 	.remove		= __devexit_p(lpc32xx_adc_remove),
 	.driver		= {
 		.name	= MOD_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(lpc32xx_adc_match),
 	},
 };
 
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index cf3e2ca..6799ce2 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -32,10 +32,11 @@
 #include <linux/err.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/driver.h>
 
 #include "max1363.h"
 
@@ -248,7 +249,7 @@
 	struct max1363_state *st = iio_priv(indio_dev);
 	int ret;
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		ret = max1363_read_single_chan(indio_dev, chan, val, m);
 		if (ret < 0)
 			return ret;
@@ -281,7 +282,8 @@
 #define MAX1363_EV_M						\
 	(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)	\
 	 | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
-#define MAX1363_INFO_MASK IIO_CHAN_INFO_SCALE_SHARED_BIT
+#define MAX1363_INFO_MASK (IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+			   IIO_CHAN_INFO_SCALE_SHARED_BIT)
 #define MAX1363_CHAN_U(num, addr, si, bits, evmask)			\
 	{								\
 		.type = IIO_VOLTAGE,					\
@@ -497,7 +499,7 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct max1363_state *st = iio_priv(dev_get_drvdata(dev));
+	struct max1363_state *st = iio_priv(dev_to_iio_dev(dev));
 	return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]);
 }
 
@@ -506,7 +508,7 @@
 					const char *buf,
 					size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct max1363_state *st = iio_priv(indio_dev);
 	int i, ret;
 	unsigned long val;
@@ -830,6 +832,7 @@
 static const struct iio_info max1238_info = {
 	.read_raw = &max1363_read_raw,
 	.driver_module = THIS_MODULE,
+	.update_scan_mode = &max1363_update_scan_mode,
 };
 
 static const struct iio_info max1363_info = {
@@ -1284,11 +1287,14 @@
 	if (ret)
 		goto error_put_reg;
 
-	indio_dev = iio_allocate_device(sizeof(struct max1363_state));
+	indio_dev = iio_device_alloc(sizeof(struct max1363_state));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_disable_reg;
 	}
+	ret = iio_map_array_register(indio_dev, client->dev.platform_data);
+	if (ret < 0)
+		goto error_free_device;
 	st = iio_priv(indio_dev);
 	st->reg = reg;
 	/* this is only used for device removal purposes */
@@ -1299,7 +1305,7 @@
 
 	ret = max1363_alloc_scan_masks(indio_dev);
 	if (ret)
-		goto error_free_device;
+		goto error_unregister_map;
 
 	/* Estabilish that the iio_dev is a child of the i2c device */
 	indio_dev->dev.parent = &client->dev;
@@ -1349,8 +1355,10 @@
 	max1363_ring_cleanup(indio_dev);
 error_free_available_scan_masks:
 	kfree(indio_dev->available_scan_masks);
+error_unregister_map:
+	iio_map_array_unregister(indio_dev, client->dev.platform_data);
 error_free_device:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_disable_reg:
 	regulator_disable(reg);
 error_put_reg:
@@ -1375,7 +1383,8 @@
 		regulator_disable(reg);
 		regulator_put(reg);
 	}
-	iio_free_device(indio_dev);
+	iio_map_array_unregister(indio_dev, client->dev.platform_data);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index d0a60a3..b302013 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -14,10 +14,10 @@
 #include <linux/i2c.h>
 #include <linux/bitops.h>
 
-#include "../iio.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
 #include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
 
 #include "max1363.h"
 
@@ -54,7 +54,7 @@
 		d_size = numvals*2;
 	else
 		d_size = numvals;
-	if (indio_dev->buffer->scan_timestamp) {
+	if (indio_dev->scan_timestamp) {
 		d_size += sizeof(s64);
 		if (d_size % sizeof(s64))
 			d_size += sizeof(s64) - (d_size % sizeof(s64));
@@ -78,7 +78,7 @@
 
 	time_ns = iio_get_time_ns();
 
-	if (indio_dev->buffer->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
 	iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns);
 
diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c
new file mode 100644
index 0000000..64d630e
--- /dev/null
+++ b/drivers/staging/iio/adc/spear_adc.c
@@ -0,0 +1,448 @@
+/*
+ * ST SPEAr ADC driver
+ *
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/*
+ * SPEAR registers definitions
+ */
+
+#define SCAN_RATE_LO(x)		((x) & 0xFFFF)
+#define SCAN_RATE_HI(x)		(((x) >> 0x10) & 0xFFFF)
+#define CLK_LOW(x)		(((x) & 0xf) << 0)
+#define CLK_HIGH(x)		(((x) & 0xf) << 4)
+
+/* Bit definitions for SPEAR_ADC_STATUS */
+#define START_CONVERSION	(1 << 0)
+#define CHANNEL_NUM(x)		((x) << 1)
+#define ADC_ENABLE		(1 << 4)
+#define AVG_SAMPLE(x)		((x) << 5)
+#define VREF_INTERNAL		(1 << 9)
+
+#define DATA_MASK		0x03ff
+#define DATA_BITS		10
+
+#define MOD_NAME "spear-adc"
+
+#define ADC_CHANNEL_NUM		8
+
+#define CLK_MIN			2500000
+#define CLK_MAX			20000000
+
+struct adc_regs_spear3xx {
+	u32 status;
+	u32 average;
+	u32 scan_rate;
+	u32 clk;	/* Not avail for 1340 & 1310 */
+	u32 ch_ctrl[ADC_CHANNEL_NUM];
+	u32 ch_data[ADC_CHANNEL_NUM];
+};
+
+struct chan_data {
+	u32 lsb;
+	u32 msb;
+};
+
+struct adc_regs_spear6xx {
+	u32 status;
+	u32 pad[2];
+	u32 clk;
+	u32 ch_ctrl[ADC_CHANNEL_NUM];
+	struct chan_data ch_data[ADC_CHANNEL_NUM];
+	u32 scan_rate_lo;
+	u32 scan_rate_hi;
+	struct chan_data average;
+};
+
+struct spear_adc_info {
+	struct device_node *np;
+	struct adc_regs_spear3xx __iomem *adc_base_spear3xx;
+	struct adc_regs_spear6xx __iomem *adc_base_spear6xx;
+	struct clk *clk;
+	struct completion completion;
+	u32 current_clk;
+	u32 sampling_freq;
+	u32 avg_samples;
+	u32 vref_external;
+	u32 value;
+};
+
+/*
+ * Functions to access some SPEAr ADC register. Abstracted into
+ * static inline functions, because of different register offsets
+ * on different SoC variants (SPEAr300 vs SPEAr600 etc).
+ */
+static void spear_adc_set_status(struct spear_adc_info *info, u32 val)
+{
+	__raw_writel(val, &info->adc_base_spear6xx->status);
+}
+
+static void spear_adc_set_clk(struct spear_adc_info *info, u32 val)
+{
+	u32 clk_high, clk_low, count;
+	u32 apb_clk = clk_get_rate(info->clk);
+
+	count = (apb_clk + val - 1) / val;
+	clk_low = count / 2;
+	clk_high = count - clk_low;
+	info->current_clk = apb_clk / count;
+
+	__raw_writel(CLK_LOW(clk_low) | CLK_HIGH(clk_high),
+		     &info->adc_base_spear6xx->clk);
+}
+
+static void spear_adc_set_ctrl(struct spear_adc_info *info, int n,
+			       u32 val)
+{
+	__raw_writel(val, &info->adc_base_spear6xx->ch_ctrl[n]);
+}
+
+static u32 spear_adc_get_average(struct spear_adc_info *info)
+{
+	if (of_device_is_compatible(info->np, "st,spear600-adc")) {
+		return __raw_readl(&info->adc_base_spear6xx->average.msb) &
+			DATA_MASK;
+	} else {
+		return __raw_readl(&info->adc_base_spear3xx->average) &
+			DATA_MASK;
+	}
+}
+
+static void spear_adc_set_scanrate(struct spear_adc_info *info, u32 rate)
+{
+	if (of_device_is_compatible(info->np, "st,spear600-adc")) {
+		__raw_writel(SCAN_RATE_LO(rate),
+			     &info->adc_base_spear6xx->scan_rate_lo);
+		__raw_writel(SCAN_RATE_HI(rate),
+			     &info->adc_base_spear6xx->scan_rate_hi);
+	} else {
+		__raw_writel(rate, &info->adc_base_spear3xx->scan_rate);
+	}
+}
+
+static int spear_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan,
+			  int *val,
+			  int *val2,
+			  long mask)
+{
+	struct spear_adc_info *info = iio_priv(indio_dev);
+	u32 scale_mv;
+	u32 status;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&indio_dev->mlock);
+
+		status = CHANNEL_NUM(chan->channel) |
+			AVG_SAMPLE(info->avg_samples) |
+			START_CONVERSION | ADC_ENABLE;
+		if (info->vref_external == 0)
+			status |= VREF_INTERNAL;
+
+		spear_adc_set_status(info, status);
+		wait_for_completion(&info->completion); /* set by ISR */
+		*val = info->value;
+
+		mutex_unlock(&indio_dev->mlock);
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		scale_mv = (info->vref_external * 1000) >> DATA_BITS;
+		*val =  scale_mv / 1000;
+		*val2 = (scale_mv % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+
+	return -EINVAL;
+}
+
+#define SPEAR_ADC_CHAN(idx) {				\
+	.type = IIO_VOLTAGE,				\
+	.indexed = 1,					\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+	IIO_CHAN_INFO_SCALE_SHARED_BIT,			\
+	.channel = idx,					\
+	.scan_type = {					\
+		.sign = 'u',				\
+		.storagebits = 16,			\
+	},						\
+}
+
+static struct iio_chan_spec spear_adc_iio_channels[] = {
+	SPEAR_ADC_CHAN(0),
+	SPEAR_ADC_CHAN(1),
+	SPEAR_ADC_CHAN(2),
+	SPEAR_ADC_CHAN(3),
+	SPEAR_ADC_CHAN(4),
+	SPEAR_ADC_CHAN(5),
+	SPEAR_ADC_CHAN(6),
+	SPEAR_ADC_CHAN(7),
+};
+
+static irqreturn_t spear_adc_isr(int irq, void *dev_id)
+{
+	struct spear_adc_info *info = (struct spear_adc_info *)dev_id;
+
+	/* Read value to clear IRQ */
+	info->value = spear_adc_get_average(info);
+	complete(&info->completion);
+
+	return IRQ_HANDLED;
+}
+
+static int spear_adc_configure(struct spear_adc_info *info)
+{
+	int i;
+
+	/* Reset ADC core */
+	spear_adc_set_status(info, 0);
+	__raw_writel(0, &info->adc_base_spear6xx->clk);
+	for (i = 0; i < 8; i++)
+		spear_adc_set_ctrl(info, i, 0);
+	spear_adc_set_scanrate(info, 0);
+
+	spear_adc_set_clk(info, info->sampling_freq);
+
+	return 0;
+}
+
+static ssize_t spear_adc_read_frequency(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct spear_adc_info *info = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", info->current_clk);
+}
+
+static ssize_t spear_adc_write_frequency(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf,
+					 size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct spear_adc_info *info = iio_priv(indio_dev);
+	u32 clk_high, clk_low, count;
+	u32 apb_clk = clk_get_rate(info->clk);
+	unsigned long lval;
+	int ret;
+
+	ret = kstrtoul(buf, 10, &lval);
+	if (ret)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+
+	if ((lval < CLK_MIN) || (lval > CLK_MAX)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	count = (apb_clk + lval - 1) / lval;
+	clk_low = count / 2;
+	clk_high = count - clk_low;
+	info->current_clk = apb_clk / count;
+	spear_adc_set_clk(info, lval);
+
+out:
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+			      spear_adc_read_frequency,
+			      spear_adc_write_frequency);
+
+static struct attribute *spear_attributes[] = {
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group spear_attribute_group = {
+	.attrs = spear_attributes,
+};
+
+static const struct iio_info spear_adc_iio_info = {
+	.read_raw = &spear_read_raw,
+	.attrs = &spear_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit spear_adc_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct spear_adc_info *info;
+	struct iio_dev *iodev = NULL;
+	int ret = -ENODEV;
+	int irq;
+
+	iodev = iio_device_alloc(sizeof(struct spear_adc_info));
+	if (!iodev) {
+		dev_err(dev, "failed allocating iio device\n");
+		ret = -ENOMEM;
+		goto errout1;
+	}
+
+	info = iio_priv(iodev);
+	info->np = np;
+
+	/*
+	 * SPEAr600 has a different register layout than other SPEAr SoC's
+	 * (e.g. SPEAr3xx). Let's provide two register base addresses
+	 * to support multi-arch kernels.
+	 */
+	info->adc_base_spear6xx = of_iomap(np, 0);
+	if (!info->adc_base_spear6xx) {
+		dev_err(dev, "failed mapping memory\n");
+		ret = -ENOMEM;
+		goto errout2;
+	}
+	info->adc_base_spear3xx =
+		(struct adc_regs_spear3xx *)info->adc_base_spear6xx;
+
+	info->clk = clk_get(dev, NULL);
+	if (IS_ERR(info->clk)) {
+		dev_err(dev, "failed getting clock\n");
+		goto errout3;
+	}
+
+	ret = clk_prepare(info->clk);
+	if (ret) {
+		dev_err(dev, "failed preparing clock\n");
+		goto errout4;
+	}
+
+	ret = clk_enable(info->clk);
+	if (ret) {
+		dev_err(dev, "failed enabling clock\n");
+		goto errout5;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if ((irq < 0) || (irq >= NR_IRQS)) {
+		dev_err(dev, "failed getting interrupt resource\n");
+		ret = -EINVAL;
+		goto errout6;
+	}
+
+	ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info);
+	if (ret < 0) {
+		dev_err(dev, "failed requesting interrupt\n");
+		goto errout6;
+	}
+
+	if (of_property_read_u32(np, "sampling-frequency",
+				 &info->sampling_freq)) {
+		dev_err(dev, "sampling-frequency missing in DT\n");
+		ret = -EINVAL;
+		goto errout6;
+	}
+
+	/*
+	 * Optional avg_samples defaults to 0, resulting in single data
+	 * conversion
+	 */
+	of_property_read_u32(np, "average-samples", &info->avg_samples);
+
+	/*
+	 * Optional vref_external defaults to 0, resulting in internal vref
+	 * selection
+	 */
+	of_property_read_u32(np, "vref-external", &info->vref_external);
+
+	spear_adc_configure(info);
+
+	platform_set_drvdata(pdev, iodev);
+
+	init_completion(&info->completion);
+
+	iodev->name = MOD_NAME;
+	iodev->dev.parent = dev;
+	iodev->info = &spear_adc_iio_info;
+	iodev->modes = INDIO_DIRECT_MODE;
+	iodev->channels = spear_adc_iio_channels;
+	iodev->num_channels = ARRAY_SIZE(spear_adc_iio_channels);
+
+	ret = iio_device_register(iodev);
+	if (ret)
+		goto errout6;
+
+	dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq);
+
+	return 0;
+
+errout6:
+	clk_disable(info->clk);
+errout5:
+	clk_unprepare(info->clk);
+errout4:
+	clk_put(info->clk);
+errout3:
+	iounmap(info->adc_base_spear6xx);
+errout2:
+	iio_device_free(iodev);
+errout1:
+	return ret;
+}
+
+static int __devexit spear_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *iodev = platform_get_drvdata(pdev);
+	struct spear_adc_info *info = iio_priv(iodev);
+
+	iio_device_unregister(iodev);
+	platform_set_drvdata(pdev, NULL);
+	clk_disable(info->clk);
+	clk_unprepare(info->clk);
+	clk_put(info->clk);
+	iounmap(info->adc_base_spear6xx);
+	iio_device_free(iodev);
+
+	return 0;
+}
+
+static const struct of_device_id spear_adc_dt_ids[] = {
+	{ .compatible = "st,spear600-adc", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spear_adc_dt_ids);
+
+static struct platform_driver spear_adc_driver = {
+	.probe		= spear_adc_probe,
+	.remove		= __devexit_p(spear_adc_remove),
+	.driver		= {
+		.name	= MOD_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(spear_adc_dt_ids),
+	},
+};
+
+module_platform_driver(spear_adc_driver);
+
+MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
+MODULE_DESCRIPTION("SPEAr ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index fd6a454..8fb014a 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -19,9 +19,9 @@
 #include <linux/rtc.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../events.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/events.h>
+#include <linux/iio/sysfs.h>
 #include "adt7316.h"
 
 /*
@@ -220,7 +220,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_EN));
@@ -252,7 +252,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	int enable;
 
@@ -276,7 +276,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
@@ -290,7 +290,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config1;
 	int ret;
@@ -320,7 +320,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if (chip->config2 & ADT7316_AD_SINGLE_CH_MODE)
@@ -334,7 +334,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config2;
 	int ret;
@@ -370,7 +370,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
@@ -409,7 +409,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config2;
 	unsigned long data = 0;
@@ -455,7 +455,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
@@ -477,7 +477,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "%d\n",
@@ -489,7 +489,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config2;
 	int ret;
@@ -516,7 +516,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "%d\n",
@@ -528,7 +528,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config2;
 	int ret;
@@ -557,7 +557,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config2;
 	int ret;
@@ -580,7 +580,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_PD));
@@ -591,7 +591,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config1;
 	int ret;
@@ -618,7 +618,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "%d\n", !!(chip->config3 & ADT7316_ADCLK_22_5));
@@ -629,7 +629,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config3;
 	int ret;
@@ -656,7 +656,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) {
@@ -674,7 +674,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config3;
 	int ret;
@@ -708,7 +708,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
@@ -723,7 +723,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config3;
 	int ret;
@@ -755,7 +755,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "%d\n",
@@ -767,7 +767,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config3;
 	int ret;
@@ -794,7 +794,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "%d\n",
@@ -806,7 +806,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config3;
 	int ret;
@@ -833,7 +833,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "0x%x\n",
@@ -845,7 +845,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 dac_config;
 	unsigned long data = 0;
@@ -876,7 +876,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
@@ -900,7 +900,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 dac_config;
 	unsigned long data;
@@ -934,7 +934,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)
@@ -955,7 +955,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 ldac_config;
 	unsigned long data;
@@ -994,7 +994,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@@ -1009,7 +1009,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 dac_config;
 	int ret;
@@ -1039,7 +1039,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@@ -1054,7 +1054,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 dac_config;
 	int ret;
@@ -1084,7 +1084,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@@ -1101,7 +1101,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 ldac_config;
 	unsigned long data;
@@ -1220,7 +1220,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf);
@@ -1231,7 +1231,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf);
@@ -1243,7 +1243,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf);
@@ -1256,7 +1256,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf);
@@ -1267,7 +1267,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf);
@@ -1278,7 +1278,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf);
@@ -1330,7 +1330,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf);
@@ -1341,7 +1341,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len);
@@ -1355,7 +1355,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf);
@@ -1366,7 +1366,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len);
@@ -1380,7 +1380,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_temp_offset(chip,
@@ -1392,7 +1392,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_store_temp_offset(chip,
@@ -1407,7 +1407,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_temp_offset(chip,
@@ -1419,7 +1419,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_store_temp_offset(chip,
@@ -1504,7 +1504,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_DAC(chip, 0, buf);
@@ -1515,7 +1515,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_store_DAC(chip, 0, buf, len);
@@ -1528,7 +1528,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_DAC(chip, 1, buf);
@@ -1539,7 +1539,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_store_DAC(chip, 1, buf, len);
@@ -1552,7 +1552,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_DAC(chip, 2, buf);
@@ -1563,7 +1563,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_store_DAC(chip, 2, buf, len);
@@ -1576,7 +1576,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_show_DAC(chip, 3, buf);
@@ -1587,7 +1587,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return adt7316_store_DAC(chip, 3, buf, len);
@@ -1600,7 +1600,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 id;
 	int ret;
@@ -1618,7 +1618,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 id;
 	int ret;
@@ -1637,7 +1637,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 rev;
 	int ret;
@@ -1655,7 +1655,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 stat;
 	int ret;
@@ -1841,7 +1841,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "0x%x\n", chip->int_mask);
@@ -1855,7 +1855,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	unsigned long data;
 	int ret;
@@ -1895,7 +1895,7 @@
 		char *buf)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 val;
 	int data;
@@ -1926,7 +1926,7 @@
 		size_t len)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	long data;
 	u8 val;
@@ -1965,7 +1965,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_INT_EN));
@@ -1976,7 +1976,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *dev_info = dev_get_drvdata(dev);
+	struct iio_dev *dev_info = dev_to_iio_dev(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 	u8 config1;
 	int ret;
@@ -2133,7 +2133,7 @@
 	unsigned short *adt7316_platform_data = dev->platform_data;
 	int ret = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -2210,7 +2210,7 @@
 error_unreg_irq:
 	free_irq(chip->bus.irq, indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -2224,7 +2224,7 @@
 	iio_device_unregister(indio_dev);
 	if (chip->bus.irq)
 		free_irq(chip->bus.irq, indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/buffer.h b/drivers/staging/iio/buffer.h
deleted file mode 100644
index df2046d..0000000
--- a/drivers/staging/iio/buffer.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/* The industrial I/O core - generic buffer interfaces.
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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 _IIO_BUFFER_GENERIC_H_
-#define _IIO_BUFFER_GENERIC_H_
-#include <linux/sysfs.h>
-#include "iio.h"
-
-#ifdef CONFIG_IIO_BUFFER
-
-struct iio_buffer;
-
-/**
- * struct iio_buffer_access_funcs - access functions for buffers.
- * @store_to:		actually store stuff to the buffer
- * @read_first_n:	try to get a specified number of bytes (must exist)
- * @request_update:	if a parameter change has been marked, update underlying
- *			storage.
- * @get_bytes_per_datum:get current bytes per datum
- * @set_bytes_per_datum:set number of bytes per datum
- * @get_length:		get number of datums in buffer
- * @set_length:		set number of datums in buffer
- *
- * The purpose of this structure is to make the buffer element
- * modular as event for a given driver, different usecases may require
- * different buffer designs (space efficiency vs speed for example).
- *
- * It is worth noting that a given buffer implementation may only support a
- * small proportion of these functions.  The core code 'should' cope fine with
- * any of them not existing.
- **/
-struct iio_buffer_access_funcs {
-	int (*store_to)(struct iio_buffer *buffer, u8 *data, s64 timestamp);
-	int (*read_first_n)(struct iio_buffer *buffer,
-			    size_t n,
-			    char __user *buf);
-
-	int (*request_update)(struct iio_buffer *buffer);
-
-	int (*get_bytes_per_datum)(struct iio_buffer *buffer);
-	int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
-	int (*get_length)(struct iio_buffer *buffer);
-	int (*set_length)(struct iio_buffer *buffer, int length);
-};
-
-/**
- * struct iio_buffer - general buffer structure
- * @length:		[DEVICE] number of datums in buffer
- * @bytes_per_datum:	[DEVICE] size of individual datum including timestamp
- * @scan_el_attrs:	[DRIVER] control of scan elements if that scan mode
- *			control method is used
- * @scan_mask:		[INTERN] bitmask used in masking scan mode elements
- * @scan_index_timestamp:[INTERN] cache of the index to the timestamp
- * @scan_timestamp:	[INTERN] does the scan mode include a timestamp
- * @access:		[DRIVER] buffer access functions associated with the
- *			implementation.
- * @scan_el_dev_attr_list:[INTERN] list of scan element related attributes.
- * @scan_el_group:	[DRIVER] attribute group for those attributes not
- *			created from the iio_chan_info array.
- * @pollq:		[INTERN] wait queue to allow for polling on the buffer.
- * @stufftoread:	[INTERN] flag to indicate new data.
- * @demux_list:		[INTERN] list of operations required to demux the scan.
- * @demux_bounce:	[INTERN] buffer for doing gather from incoming scan.
- **/
-struct iio_buffer {
-	int					length;
-	int					bytes_per_datum;
-	struct attribute_group			*scan_el_attrs;
-	long					*scan_mask;
-	bool					scan_timestamp;
-	unsigned				scan_index_timestamp;
-	const struct iio_buffer_access_funcs	*access;
-	struct list_head			scan_el_dev_attr_list;
-	struct attribute_group			scan_el_group;
-	wait_queue_head_t			pollq;
-	bool					stufftoread;
-	const struct attribute_group *attrs;
-	struct list_head			demux_list;
-	unsigned char				*demux_bounce;
-};
-
-/**
- * iio_buffer_init() - Initialize the buffer structure
- * @buffer: buffer to be initialized
- **/
-void iio_buffer_init(struct iio_buffer *buffer);
-
-/**
- * __iio_update_buffer() - update common elements of buffers
- * @buffer:		buffer that is the event source
- * @bytes_per_datum:	size of individual datum including timestamp
- * @length:		number of datums in buffer
- **/
-static inline void __iio_update_buffer(struct iio_buffer *buffer,
-				       int bytes_per_datum, int length)
-{
-	buffer->bytes_per_datum = bytes_per_datum;
-	buffer->length = length;
-}
-
-int iio_scan_mask_query(struct iio_dev *indio_dev,
-			struct iio_buffer *buffer, int bit);
-
-/**
- * iio_scan_mask_set() - set particular bit in the scan mask
- * @buffer: the buffer whose scan mask we are interested in
- * @bit: the bit to be set.
- **/
-int iio_scan_mask_set(struct iio_dev *indio_dev,
-		      struct iio_buffer *buffer, int bit);
-
-/**
- * iio_push_to_buffer() - push to a registered buffer.
- * @buffer:		IIO buffer structure for device
- * @scan:		Full scan.
- * @timestamp:
- */
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
-		       s64 timestamp);
-
-int iio_update_demux(struct iio_dev *indio_dev);
-
-/**
- * iio_buffer_register() - register the buffer with IIO core
- * @indio_dev: device with the buffer to be registered
- **/
-int iio_buffer_register(struct iio_dev *indio_dev,
-			const struct iio_chan_spec *channels,
-			int num_channels);
-
-/**
- * iio_buffer_unregister() - unregister the buffer from IIO core
- * @indio_dev: the device with the buffer to be unregistered
- **/
-void iio_buffer_unregister(struct iio_dev *indio_dev);
-
-/**
- * iio_buffer_read_length() - attr func to get number of datums in the buffer
- **/
-ssize_t iio_buffer_read_length(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf);
-/**
- * iio_buffer_write_length() - attr func to set number of datums in the buffer
- **/
-ssize_t iio_buffer_write_length(struct device *dev,
-			      struct device_attribute *attr,
-			      const char *buf,
-			      size_t len);
-/**
- * iio_buffer_store_enable() - attr to turn the buffer on
- **/
-ssize_t iio_buffer_store_enable(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf,
-				size_t len);
-/**
- * iio_buffer_show_enable() - attr to see if the buffer is on
- **/
-ssize_t iio_buffer_show_enable(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf);
-#define IIO_BUFFER_LENGTH_ATTR DEVICE_ATTR(length, S_IRUGO | S_IWUSR,	\
-					   iio_buffer_read_length,	\
-					   iio_buffer_write_length)
-
-#define IIO_BUFFER_ENABLE_ATTR DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,	\
-					   iio_buffer_show_enable,	\
-					   iio_buffer_store_enable)
-
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev);
-
-#else /* CONFIG_IIO_BUFFER */
-
-static inline int iio_buffer_register(struct iio_dev *indio_dev,
-					   struct iio_chan_spec *channels,
-					   int num_channels)
-{
-	return 0;
-}
-
-static inline void iio_buffer_unregister(struct iio_dev *indio_dev)
-{};
-
-#endif /* CONFIG_IIO_BUFFER */
-
-#endif /* _IIO_BUFFER_GENERIC_H_ */
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index e4a08dc..a16d1a2 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -13,9 +13,9 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 /*
  * AD7150 registers definition
  */
@@ -104,7 +104,7 @@
 	struct ad7150_chip_info *chip = iio_priv(indio_dev);
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		ret = i2c_smbus_read_word_data(chip->client,
 					ad7150_addresses[chan->channel][0]);
 		if (ret < 0)
@@ -341,7 +341,7 @@
 				   struct device_attribute *attr,
 				   char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7150_chip_info *chip = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	u8 value;
@@ -370,7 +370,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7150_chip_info *chip = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
@@ -429,7 +429,8 @@
 		.type = IIO_CAPACITANCE,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
 		.event_mask =
 		IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
 		IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
@@ -441,7 +442,8 @@
 		.type = IIO_CAPACITANCE,
 		.indexed = 1,
 		.channel = 1,
-		.info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
 		.event_mask =
 		IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
 		IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
@@ -556,7 +558,7 @@
 	struct ad7150_chip_info *chip;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -619,7 +621,7 @@
 	if (client->irq)
 		free_irq(client->irq, indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -635,7 +637,7 @@
 	if (client->dev.platform_data)
 		free_irq(*(unsigned int *)client->dev.platform_data, indio_dev);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c
index fdb83c3..98c3015 100644
--- a/drivers/staging/iio/cdc/ad7152.c
+++ b/drivers/staging/iio/cdc/ad7152.c
@@ -15,8 +15,8 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 /*
  * TODO: Check compliance of calibbias with abi (units)
@@ -97,7 +97,7 @@
 					 size_t len,
 					 u8 regval)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7152_chip_info *chip = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	bool doit;
@@ -169,7 +169,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7152_chip_info *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n",
@@ -181,7 +181,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7152_chip_info *chip = iio_priv(indio_dev);
 	u8 data;
 	int ret, i;
@@ -329,7 +329,7 @@
 	mutex_lock(&indio_dev->mlock);
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		/* First set whether in differential mode */
 
 		regval = chip->setup[chan->channel];
@@ -436,7 +436,8 @@
 		.type = IIO_CAPACITANCE,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 	}, {
@@ -445,14 +446,16 @@
 		.indexed = 1,
 		.channel = 0,
 		.channel2 = 2,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 	}, {
 		.type = IIO_CAPACITANCE,
 		.indexed = 1,
 		.channel = 1,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 	}, {
@@ -461,7 +464,8 @@
 		.indexed = 1,
 		.channel = 1,
 		.channel2 = 3,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 	}
@@ -477,7 +481,7 @@
 	struct ad7152_chip_info *chip;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -509,7 +513,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -519,7 +523,7 @@
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
 	iio_device_unregister(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index 40b8512..754e11e 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -16,8 +16,8 @@
 #include <linux/module.h>
 #include <linux/stat.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #include "ad7746.h"
 
@@ -123,7 +123,8 @@
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
 		.address = AD7746_REG_VT_DATA_HIGH << 8 |
 			AD7746_VTSETUP_VTMD_EXT_VIN,
 	},
@@ -132,7 +133,8 @@
 		.indexed = 1,
 		.channel = 1,
 		.extend_name = "supply",
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
 		.address = AD7746_REG_VT_DATA_HIGH << 8 |
 			AD7746_VTSETUP_VTMD_VDD_MON,
 	},
@@ -140,7 +142,7 @@
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 0,
-		.processed_val = IIO_PROCESSED,
+		.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
 		.address = AD7746_REG_VT_DATA_HIGH << 8 |
 			AD7746_VTSETUP_VTMD_INT_TEMP,
 	},
@@ -148,7 +150,7 @@
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 1,
-		.processed_val = IIO_PROCESSED,
+		.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
 		.address = AD7746_REG_VT_DATA_HIGH << 8 |
 			AD7746_VTSETUP_VTMD_EXT_TEMP,
 	},
@@ -156,7 +158,8 @@
 		.type = IIO_CAPACITANCE,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
 		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -168,7 +171,8 @@
 		.indexed = 1,
 		.channel = 0,
 		.channel2 = 2,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
 		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -179,7 +183,8 @@
 		.type = IIO_CAPACITANCE,
 		.indexed = 1,
 		.channel = 1,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
 		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -192,7 +197,8 @@
 		.indexed = 1,
 		.channel = 1,
 		.channel2 = 3,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
 		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -280,7 +286,7 @@
 					 size_t len,
 					 u8 regval)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7746_chip_info *chip = iio_priv(indio_dev);
 	bool doit;
 	int ret, timeout = 10;
@@ -319,7 +325,7 @@
 					 const char *buf,
 					 size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	int ret = ad7746_select_channel(indio_dev,
 			      &ad7746_channels[to_iio_dev_attr(attr)->address]);
 	if (ret < 0)
@@ -334,7 +340,7 @@
 				       const char *buf,
 				       size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	int ret = ad7746_select_channel(indio_dev,
 			      &ad7746_channels[to_iio_dev_attr(attr)->address]);
 	if (ret < 0)
@@ -359,7 +365,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7746_chip_info *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", ad7746_cap_filter_rate_table[
@@ -371,7 +377,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7746_chip_info *chip = iio_priv(indio_dev);
 	u8 data;
 	int ret, i;
@@ -399,7 +405,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7746_chip_info *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", ad7746_vt_filter_rate_table[
@@ -411,7 +417,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7746_chip_info *chip = iio_priv(indio_dev);
 	u8 data;
 	int ret, i;
@@ -572,7 +578,8 @@
 	mutex_lock(&indio_dev->mlock);
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_PROCESSED:
 		ret = ad7746_select_channel(indio_dev, chan);
 		if (ret < 0)
 			goto out;
@@ -696,7 +703,7 @@
 	int ret = 0;
 	unsigned char regval = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -756,7 +763,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -766,7 +773,7 @@
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
 	iio_device_unregister(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/consumer.h b/drivers/staging/iio/consumer.h
deleted file mode 100644
index 36a060c..0000000
--- a/drivers/staging/iio/consumer.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Industrial I/O in kernel consumer interface
- *
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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 _IIO_INKERN_CONSUMER_H_
-#define _IIO_INKERN_CONSUMER_H
-#include "types.h"
-
-struct iio_dev;
-struct iio_chan_spec;
-
-/**
- * struct iio_channel - everything needed for a consumer to use a channel
- * @indio_dev:		Device on which the channel exists.
- * @channel:		Full description of the channel.
- */
-struct iio_channel {
-	struct iio_dev *indio_dev;
-	const struct iio_chan_spec *channel;
-};
-
-/**
- * iio_channel_get() - get description of all that is needed to access channel.
- * @name:		Unique name of the device as provided in the iio_map
- *			with which the desired provider to consumer mapping
- *			was registered.
- * @consumer_channel:	Unique name to identify the channel on the consumer
- *			side. This typically describes the channels use within
- *			the consumer. E.g. 'battery_voltage'
- */
-struct iio_channel *iio_st_channel_get(const char *name,
-				       const char *consumer_channel);
-
-/**
- * iio_st_channel_release() - release channels obtained via iio_st_channel_get
- * @chan:		The channel to be released.
- */
-void iio_st_channel_release(struct iio_channel *chan);
-
-/**
- * iio_st_channel_get_all() - get all channels associated with a client
- * @name:		name of consumer device.
- *
- * Returns an array of iio_channel structures terminated with one with
- * null iio_dev pointer.
- * This function is used by fairly generic consumers to get all the
- * channels registered as having this consumer.
- */
-struct iio_channel *iio_st_channel_get_all(const char *name);
-
-/**
- * iio_st_channel_release_all() - reverse iio_st_get_all
- * @chan:		Array of channels to be released.
- */
-void iio_st_channel_release_all(struct iio_channel *chan);
-
-/**
- * iio_st_read_channel_raw() - read from a given channel
- * @channel:		The channel being queried.
- * @val:		Value read back.
- *
- * Note raw reads from iio channels are in adc counts and hence
- * scale will need to be applied if standard units required.
- */
-int iio_st_read_channel_raw(struct iio_channel *chan,
-			    int *val);
-
-/**
- * iio_st_get_channel_type() - get the type of a channel
- * @channel:		The channel being queried.
- * @type:		The type of the channel.
- *
- * returns the enum iio_chan_type of the channel
- */
-int iio_st_get_channel_type(struct iio_channel *channel,
-			    enum iio_chan_type *type);
-
-/**
- * iio_st_read_channel_scale() - read the scale value for a channel
- * @channel:		The channel being queried.
- * @val:		First part of value read back.
- * @val2:		Second part of value read back.
- *
- * Note returns a description of what is in val and val2, such
- * as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val
- * + val2/1e6
- */
-int iio_st_read_channel_scale(struct iio_channel *chan, int *val,
-			      int *val2);
-
-#endif
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig
index a57803a..a626f03 100644
--- a/drivers/staging/iio/dac/Kconfig
+++ b/drivers/staging/iio/dac/Kconfig
@@ -56,12 +56,12 @@
 	  AD5664R converters (DAC). This driver uses the common SPI interface.
 
 config AD5446
-	tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5542A/12A DAC SPI driver"
+	tristate "Analog Devices AD5446 and similar single channel DACs driver"
 	depends on SPI
 	help
 	  Say yes here to build support for Analog Devices AD5444, AD5446,
-	  AD5512A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, AD5621,
-	  AD5640, AD5660, AD5662 DACs.
+	  AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620,
+	  AD5621, AD5640, AD5660, AD5662 DACs.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad5446.
diff --git a/drivers/staging/iio/dac/ad5064.c b/drivers/staging/iio/dac/ad5064.c
index 06b1627..047148a 100644
--- a/drivers/staging/iio/dac/ad5064.c
+++ b/drivers/staging/iio/dac/ad5064.c
@@ -16,8 +16,8 @@
 #include <linux/sysfs.h>
 #include <linux/regulator/consumer.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "dac.h"
 
 #define AD5064_MAX_DAC_CHANNELS			8
@@ -144,14 +144,14 @@
 };
 
 static ssize_t ad5064_read_powerdown_mode_available(struct iio_dev *indio_dev,
-	const struct iio_chan_spec *chan, char *buf)
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
 {
 	return sprintf(buf, "%s %s %s\n", ad5064_powerdown_modes[1],
 		ad5064_powerdown_modes[2], ad5064_powerdown_modes[3]);
 }
 
 static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev,
-	const struct iio_chan_spec *chan, char *buf)
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
 {
 	struct ad5064_state *st = iio_priv(indio_dev);
 
@@ -160,7 +160,8 @@
 }
 
 static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev,
-	const struct iio_chan_spec *chan, const char *buf, size_t len)
+	uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	size_t len)
 {
 	struct ad5064_state *st = iio_priv(indio_dev);
 	unsigned int mode, i;
@@ -187,7 +188,7 @@
 }
 
 static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
-	const struct iio_chan_spec *chan, char *buf)
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
 {
 	struct ad5064_state *st = iio_priv(indio_dev);
 
@@ -195,7 +196,8 @@
 }
 
 static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
-	const struct iio_chan_spec *chan, const char *buf, size_t len)
+	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	 size_t len)
 {
 	struct ad5064_state *st = iio_priv(indio_dev);
 	bool pwr_down;
@@ -235,7 +237,7 @@
 	int scale_uv;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		*val = st->dac_cache[chan->channel];
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
@@ -260,7 +262,7 @@
 	int ret;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		if (val > (1 << chan->scan_type.realbits) || val < 0)
 			return -EINVAL;
 
@@ -308,7 +310,8 @@
 	.indexed = 1,						\
 	.output = 1,						\
 	.channel = (chan),					\
-	.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,	\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+	IIO_CHAN_INFO_SCALE_SEPARATE_BIT,			\
 	.address = AD5064_ADDR_DAC(chan),			\
 	.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)),	\
 	.ext_info = ad5064_ext_info,				\
@@ -442,7 +445,7 @@
 	unsigned int i;
 	int ret;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL)
 		return  -ENOMEM;
 
@@ -499,7 +502,7 @@
 	if (!st->use_internal_vref)
 		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
 error_free:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -517,7 +520,7 @@
 		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
 	}
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dac/ad5360.c b/drivers/staging/iio/dac/ad5360.c
index cec3693..38660ef 100644
--- a/drivers/staging/iio/dac/ad5360.c
+++ b/drivers/staging/iio/dac/ad5360.c
@@ -16,8 +16,8 @@
 #include <linux/sysfs.h>
 #include <linux/regulator/consumer.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "dac.h"
 
 #define AD5360_CMD(x)				((x) << 22)
@@ -103,7 +103,8 @@
 	.type = IIO_VOLTAGE,					\
 	.indexed = 1,						\
 	.output = 1,						\
-	.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |	\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |		\
 		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |		\
 		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |	\
 		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,	\
@@ -250,7 +251,7 @@
 					   struct device_attribute *attr,
 					   char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5360_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN));
@@ -278,7 +279,7 @@
 static ssize_t ad5360_write_dac_powerdown(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	bool pwr_down;
 	int ret;
 
@@ -319,7 +320,7 @@
 	unsigned int ofs_index;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		if (val >= max_val || val < 0)
 			return -EINVAL;
 
@@ -376,7 +377,7 @@
 	int ret;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		ret = ad5360_read(indio_dev, AD5360_READBACK_X1A,
 			chan->address);
 		if (ret < 0)
@@ -464,7 +465,7 @@
 	unsigned int i;
 	int ret;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		dev_err(&spi->dev, "Failed to allocate iio device\n");
 		return  -ENOMEM;
@@ -519,7 +520,7 @@
 error_free_channels:
 	kfree(indio_dev->channels);
 error_free:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -536,7 +537,7 @@
 	regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
 	regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dac/ad5380.c b/drivers/staging/iio/dac/ad5380.c
index 4c50716..370d284 100644
--- a/drivers/staging/iio/dac/ad5380.c
+++ b/drivers/staging/iio/dac/ad5380.c
@@ -18,8 +18,8 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "dac.h"
 
 
@@ -85,7 +85,8 @@
 	.type = IIO_VOLTAGE,					\
 	.indexed = 1,						\
 	.output = 1,						\
-	.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |		\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |		\
 		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
 		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,		\
 	.scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits))	\
@@ -167,7 +168,7 @@
 static ssize_t ad5380_read_dac_powerdown(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5380_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", st->pwr_down);
@@ -176,7 +177,7 @@
 static ssize_t ad5380_write_dac_powerdown(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5380_state *st = iio_priv(indio_dev);
 	bool pwr_down;
 	int ret;
@@ -212,7 +213,7 @@
 static ssize_t ad5380_read_powerdown_mode(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5380_state *st = iio_priv(indio_dev);
 	unsigned int mode;
 	int ret;
@@ -229,7 +230,7 @@
 static ssize_t ad5380_write_powerdown_mode(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5380_state *st = iio_priv(indio_dev);
 	unsigned int i;
 	int ret;
@@ -292,7 +293,7 @@
 	struct ad5380_state *st = iio_priv(indio_dev);
 
 	switch (info) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 	case IIO_CHAN_INFO_CALIBSCALE:
 		if (val >= max_val || val < 0)
 			return -EINVAL;
@@ -322,7 +323,7 @@
 	int ret;
 
 	switch (info) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 	case IIO_CHAN_INFO_CALIBSCALE:
 		ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info),
 					val);
@@ -388,7 +389,7 @@
 	unsigned int ctrl = 0;
 	int ret;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		dev_err(dev, "Failed to allocate iio device\n");
 		ret = -ENOMEM;
@@ -454,7 +455,7 @@
 
 	kfree(indio_dev->channels);
 error_free:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_regmap_exit:
 	regmap_exit(regmap);
 
@@ -476,7 +477,7 @@
 	}
 
 	regmap_exit(st->regmap);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dac/ad5421.c b/drivers/staging/iio/dac/ad5421.c
index 0b040b2..ffbd4c2 100644
--- a/drivers/staging/iio/dac/ad5421.c
+++ b/drivers/staging/iio/dac/ad5421.c
@@ -16,9 +16,9 @@
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 #include "dac.h"
 #include "ad5421.h"
 
@@ -87,7 +87,8 @@
 		.indexed = 1,
 		.output = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT |
 			IIO_CHAN_INFO_OFFSET_SHARED_BIT |
 			IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
 			IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
@@ -304,7 +305,7 @@
 		return -EINVAL;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
 		if (ret < 0)
 			return ret;
@@ -340,7 +341,7 @@
 	const unsigned int max_val = 1 << 16;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		if (val >= max_val || val < 0)
 			return -EINVAL;
 
@@ -456,7 +457,7 @@
 	struct ad5421_state *st;
 	int ret;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		dev_err(&spi->dev, "Failed to allocate iio device\n");
 		return  -ENOMEM;
@@ -511,7 +512,7 @@
 	if (spi->irq)
 		free_irq(spi->irq, indio_dev);
 error_free:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -523,7 +524,7 @@
 	iio_device_unregister(indio_dev);
 	if (spi->irq)
 		free_irq(spi->irq, indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c
index 633ffbb..daa65b3 100644
--- a/drivers/staging/iio/dac/ad5446.c
+++ b/drivers/staging/iio/dac/ad5446.c
@@ -18,229 +18,212 @@
 #include <linux/err.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "dac.h"
 
 #include "ad5446.h"
 
-static void ad5446_store_sample(struct ad5446_state *st, unsigned val)
+static int ad5446_write(struct ad5446_state *st, unsigned val)
 {
-	st->data.d16 = cpu_to_be16(AD5446_LOAD | val);
+	__be16 data = cpu_to_be16(val);
+	return spi_write(st->spi, &data, sizeof(data));
 }
 
-static void ad5542_store_sample(struct ad5446_state *st, unsigned val)
+static int ad5660_write(struct ad5446_state *st, unsigned val)
 {
-	st->data.d16 = cpu_to_be16(val);
+	uint8_t data[3];
+
+	data[0] = (val >> 16) & 0xFF;
+	data[1] = (val >> 8) & 0xFF;
+	data[2] = val & 0xFF;
+
+	return spi_write(st->spi, data, sizeof(data));
 }
 
-static void ad5620_store_sample(struct ad5446_state *st, unsigned val)
+static const char * const ad5446_powerdown_modes[] = {
+	"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"
+};
+
+static ssize_t ad5446_read_powerdown_mode_available(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
 {
-	st->data.d16 = cpu_to_be16(AD5620_LOAD | val);
+	return sprintf(buf, "%s %s %s\n", ad5446_powerdown_modes[1],
+		ad5446_powerdown_modes[2], ad5446_powerdown_modes[3]);
 }
 
-static void ad5660_store_sample(struct ad5446_state *st, unsigned val)
+static ssize_t ad5446_write_powerdown_mode(struct iio_dev *indio_dev,
+					    uintptr_t private,
+					    const struct iio_chan_spec *chan,
+					    const char *buf, size_t len)
 {
-	val |= AD5660_LOAD;
-	st->data.d24[0] = (val >> 16) & 0xFF;
-	st->data.d24[1] = (val >> 8) & 0xFF;
-	st->data.d24[2] = val & 0xFF;
-}
-
-static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode)
-{
-	st->data.d16 = cpu_to_be16(mode << 14);
-}
-
-static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode)
-{
-	unsigned val = mode << 16;
-
-	st->data.d24[0] = (val >> 16) & 0xFF;
-	st->data.d24[1] = (val >> 8) & 0xFF;
-	st->data.d24[2] = val & 0xFF;
-}
-
-static ssize_t ad5446_write_powerdown_mode(struct device *dev,
-				       struct device_attribute *attr,
-				       const char *buf, size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct ad5446_state *st = iio_priv(indio_dev);
+	int i;
 
-	if (sysfs_streq(buf, "1kohm_to_gnd"))
-		st->pwr_down_mode = MODE_PWRDWN_1k;
-	else if (sysfs_streq(buf, "100kohm_to_gnd"))
-		st->pwr_down_mode = MODE_PWRDWN_100k;
-	else if (sysfs_streq(buf, "three_state"))
-		st->pwr_down_mode = MODE_PWRDWN_TRISTATE;
-	else
+	for (i = 1; i < ARRAY_SIZE(ad5446_powerdown_modes); i++) {
+		if (sysfs_streq(buf, ad5446_powerdown_modes[i])) {
+			st->pwr_down_mode = i;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(ad5446_powerdown_modes))
 		return -EINVAL;
 
 	return len;
 }
 
-static ssize_t ad5446_read_powerdown_mode(struct device *dev,
-				      struct device_attribute *attr, char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad5446_state *st = iio_priv(indio_dev);
-
-	char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
-
-	return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
-}
-
-static ssize_t ad5446_read_dac_powerdown(struct device *dev,
-					   struct device_attribute *attr,
+static ssize_t ad5446_read_powerdown_mode(struct iio_dev *indio_dev,
+					   uintptr_t private,
+					   const struct iio_chan_spec *chan,
 					   char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%s\n", ad5446_powerdown_modes[st->pwr_down_mode]);
+}
+
+static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev,
+					   uintptr_t private,
+					   const struct iio_chan_spec *chan,
+					   char *buf)
+{
 	struct ad5446_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", st->pwr_down);
 }
 
-static ssize_t ad5446_write_dac_powerdown(struct device *dev,
-					    struct device_attribute *attr,
+static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
+					    uintptr_t private,
+					    const struct iio_chan_spec *chan,
 					    const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct ad5446_state *st = iio_priv(indio_dev);
-	unsigned long readin;
+	unsigned int shift;
+	unsigned int val;
+	bool powerdown;
 	int ret;
 
-	ret = strict_strtol(buf, 10, &readin);
+	ret = strtobool(buf, &powerdown);
 	if (ret)
 		return ret;
 
-	if (readin > 1)
-		ret = -EINVAL;
-
 	mutex_lock(&indio_dev->mlock);
-	st->pwr_down = readin;
+	st->pwr_down = powerdown;
 
-	if (st->pwr_down)
-		st->chip_info->store_pwr_down(st, st->pwr_down_mode);
-	else
-		st->chip_info->store_sample(st, st->cached_val);
+	if (st->pwr_down) {
+		shift = chan->scan_type.realbits + chan->scan_type.shift;
+		val = st->pwr_down_mode << shift;
+	} else {
+		val = st->cached_val;
+	}
 
-	ret = spi_sync(st->spi, &st->msg);
+	ret = st->chip_info->write(st, val);
 	mutex_unlock(&indio_dev->mlock);
 
 	return ret ? ret : len;
 }
 
-static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR,
-			ad5446_read_powerdown_mode,
-			ad5446_write_powerdown_mode, 0);
-
-static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
-			"1kohm_to_gnd 100kohm_to_gnd three_state");
-
-static IIO_DEVICE_ATTR(out_voltage0_powerdown, S_IRUGO | S_IWUSR,
-			ad5446_read_dac_powerdown,
-			ad5446_write_dac_powerdown, 0);
-
-static struct attribute *ad5446_attributes[] = {
-	&iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
-	&iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
-	NULL,
+static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = {
+	{
+		.name = "powerdown",
+		.read = ad5446_read_dac_powerdown,
+		.write = ad5446_write_dac_powerdown,
+	}, {
+		.name = "powerdown_mode",
+		.read = ad5446_read_powerdown_mode,
+		.write = ad5446_write_powerdown_mode,
+	}, {
+		.name = "powerdown_mode_available",
+		.shared = true,
+		.read = ad5446_read_powerdown_mode_available,
+	},
+	{ },
 };
 
-static const struct attribute_group ad5446_attribute_group = {
-	.attrs = ad5446_attributes,
-};
-
-#define AD5446_CHANNEL(bits, storage, shift) { \
+#define _AD5446_CHANNEL(bits, storage, shift, ext) { \
 	.type = IIO_VOLTAGE, \
 	.indexed = 1, \
 	.output = 1, \
 	.channel = 0, \
-	.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
-	.scan_type = IIO_ST('u', (bits), (storage), (shift)) \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+	IIO_CHAN_INFO_SCALE_SHARED_BIT,	\
+	.scan_type = IIO_ST('u', (bits), (storage), (shift)), \
+	.ext_info = (ext), \
 }
 
+#define AD5446_CHANNEL(bits, storage, shift) \
+	_AD5446_CHANNEL(bits, storage, shift, NULL)
+
+#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
+	_AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown)
+
 static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
 	[ID_AD5444] = {
 		.channel = AD5446_CHANNEL(12, 16, 2),
-		.store_sample = ad5446_store_sample,
+		.write = ad5446_write,
 	},
 	[ID_AD5446] = {
 		.channel = AD5446_CHANNEL(14, 16, 0),
-		.store_sample = ad5446_store_sample,
+		.write = ad5446_write,
 	},
 	[ID_AD5541A] = {
 		.channel = AD5446_CHANNEL(16, 16, 0),
-		.store_sample = ad5542_store_sample,
-	},
-	[ID_AD5542A] = {
-		.channel = AD5446_CHANNEL(16, 16, 0),
-		.store_sample = ad5542_store_sample,
-	},
-	[ID_AD5543] = {
-		.channel = AD5446_CHANNEL(16, 16, 0),
-		.store_sample = ad5542_store_sample,
+		.write = ad5446_write,
 	},
 	[ID_AD5512A] = {
 		.channel = AD5446_CHANNEL(12, 16, 4),
-		.store_sample = ad5542_store_sample,
+		.write = ad5446_write,
 	},
 	[ID_AD5553] = {
 		.channel = AD5446_CHANNEL(14, 16, 0),
-		.store_sample = ad5542_store_sample,
+		.write = ad5446_write,
 	},
 	[ID_AD5601] = {
-		.channel = AD5446_CHANNEL(8, 16, 6),
-		.store_sample = ad5542_store_sample,
-		.store_pwr_down = ad5620_store_pwr_down,
+		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
+		.write = ad5446_write,
 	},
 	[ID_AD5611] = {
-		.channel = AD5446_CHANNEL(10, 16, 4),
-		.store_sample = ad5542_store_sample,
-		.store_pwr_down = ad5620_store_pwr_down,
+		.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
+		.write = ad5446_write,
 	},
 	[ID_AD5621] = {
-		.channel = AD5446_CHANNEL(12, 16, 2),
-		.store_sample = ad5542_store_sample,
-		.store_pwr_down = ad5620_store_pwr_down,
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+		.write = ad5446_write,
 	},
 	[ID_AD5620_2500] = {
-		.channel = AD5446_CHANNEL(12, 16, 2),
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
 		.int_vref_mv = 2500,
-		.store_sample = ad5620_store_sample,
-		.store_pwr_down = ad5620_store_pwr_down,
+		.write = ad5446_write,
 	},
 	[ID_AD5620_1250] = {
-		.channel = AD5446_CHANNEL(12, 16, 2),
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
 		.int_vref_mv = 1250,
-		.store_sample = ad5620_store_sample,
-		.store_pwr_down = ad5620_store_pwr_down,
+		.write = ad5446_write,
 	},
 	[ID_AD5640_2500] = {
-		.channel = AD5446_CHANNEL(14, 16, 0),
+		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
 		.int_vref_mv = 2500,
-		.store_sample = ad5620_store_sample,
-		.store_pwr_down = ad5620_store_pwr_down,
+		.write = ad5446_write,
 	},
 	[ID_AD5640_1250] = {
-		.channel = AD5446_CHANNEL(14, 16, 0),
+		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
 		.int_vref_mv = 1250,
-		.store_sample = ad5620_store_sample,
-		.store_pwr_down = ad5620_store_pwr_down,
+		.write = ad5446_write,
 	},
 	[ID_AD5660_2500] = {
-		.channel = AD5446_CHANNEL(16, 16, 0),
+		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
 		.int_vref_mv = 2500,
-		.store_sample = ad5660_store_sample,
-		.store_pwr_down = ad5660_store_pwr_down,
+		.write = ad5660_write,
 	},
 	[ID_AD5660_1250] = {
-		.channel = AD5446_CHANNEL(16, 16, 0),
+		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
 		.int_vref_mv = 1250,
-		.store_sample = ad5660_store_sample,
-		.store_pwr_down = ad5660_store_pwr_down,
+		.write = ad5660_write,
+	},
+	[ID_AD5662] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+		.write = ad5660_write,
 	},
 };
 
@@ -254,6 +237,9 @@
 	unsigned long scale_uv;
 
 	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		*val = st->cached_val;
+		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
 		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
 		*val =  scale_uv / 1000;
@@ -271,18 +257,18 @@
 			       long mask)
 {
 	struct ad5446_state *st = iio_priv(indio_dev);
-	int ret;
+	int ret = 0;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		if (val >= (1 << chan->scan_type.realbits) || val < 0)
 			return -EINVAL;
 
 		val <<= chan->scan_type.shift;
 		mutex_lock(&indio_dev->mlock);
 		st->cached_val = val;
-		st->chip_info->store_sample(st, val);
-		ret = spi_sync(st->spi, &st->msg);
+		if (!st->pwr_down)
+			ret = st->chip_info->write(st, val);
 		mutex_unlock(&indio_dev->mlock);
 		break;
 	default:
@@ -295,13 +281,6 @@
 static const struct iio_info ad5446_info = {
 	.read_raw = ad5446_read_raw,
 	.write_raw = ad5446_write_raw,
-	.attrs = &ad5446_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static const struct iio_info ad5446_info_no_pwr_down = {
-	.read_raw = ad5446_read_raw,
-	.write_raw = ad5446_write_raw,
 	.driver_module = THIS_MODULE,
 };
 
@@ -321,7 +300,7 @@
 		voltage_uv = regulator_get_voltage(reg);
 	}
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_disable_reg;
@@ -337,38 +316,17 @@
 	/* Establish that the iio_dev is a child of the spi device */
 	indio_dev->dev.parent = &spi->dev;
 	indio_dev->name = spi_get_device_id(spi)->name;
-	if (st->chip_info->store_pwr_down)
-		indio_dev->info = &ad5446_info;
-	else
-		indio_dev->info = &ad5446_info_no_pwr_down;
+	indio_dev->info = &ad5446_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = &st->chip_info->channel;
 	indio_dev->num_channels = 1;
 
-	/* Setup default message */
-
-	st->xfer.tx_buf = &st->data;
-	st->xfer.len = st->chip_info->channel.scan_type.storagebits / 8;
-
-	spi_message_init(&st->msg);
-	spi_message_add_tail(&st->xfer, &st->msg);
-
-	switch (spi_get_device_id(spi)->driver_data) {
-	case ID_AD5620_2500:
-	case ID_AD5620_1250:
-	case ID_AD5640_2500:
-	case ID_AD5640_1250:
-	case ID_AD5660_2500:
-	case ID_AD5660_1250:
+	if (st->chip_info->int_vref_mv)
 		st->vref_mv = st->chip_info->int_vref_mv;
-		break;
-	default:
-		if (voltage_uv)
-			st->vref_mv = voltage_uv / 1000;
-		else
-			dev_warn(&spi->dev,
-				 "reference voltage unspecified\n");
-	}
+	else if (voltage_uv)
+		st->vref_mv = voltage_uv / 1000;
+	else
+		dev_warn(&spi->dev, "reference voltage unspecified\n");
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
@@ -377,7 +335,7 @@
 	return 0;
 
 error_free_device:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_disable_reg:
 	if (!IS_ERR(reg))
 		regulator_disable(reg);
@@ -398,7 +356,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
@@ -408,8 +366,8 @@
 	{"ad5446", ID_AD5446},
 	{"ad5512a", ID_AD5512A},
 	{"ad5541a", ID_AD5541A},
-	{"ad5542a", ID_AD5542A},
-	{"ad5543", ID_AD5543},
+	{"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
+	{"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
 	{"ad5553", ID_AD5553},
 	{"ad5601", ID_AD5601},
 	{"ad5611", ID_AD5611},
@@ -420,6 +378,7 @@
 	{"ad5640-1250", ID_AD5640_1250},
 	{"ad5660-2500", ID_AD5660_2500},
 	{"ad5660-1250", ID_AD5660_1250},
+	{"ad5662", ID_AD5662},
 	{}
 };
 MODULE_DEVICE_TABLE(spi, ad5446_id);
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h
index 4ea3476..dfd68ce 100644
--- a/drivers/staging/iio/dac/ad5446.h
+++ b/drivers/staging/iio/dac/ad5446.h
@@ -34,43 +34,30 @@
  * @spi:		spi_device
  * @chip_info:		chip model specific constants, available modes etc
  * @reg:		supply regulator
- * @poll_work:		bottom half of polling interrupt handler
  * @vref_mv:		actual reference voltage used
- * @xfer:		default spi transfer
- * @msg:		default spi message
- * @data:		spi transmit buffer
  */
 
 struct ad5446_state {
 	struct spi_device		*spi;
 	const struct ad5446_chip_info	*chip_info;
 	struct regulator		*reg;
-	struct work_struct		poll_work;
 	unsigned short			vref_mv;
 	unsigned			cached_val;
 	unsigned			pwr_down_mode;
 	unsigned			pwr_down;
-	struct spi_transfer		xfer;
-	struct spi_message		msg;
-	union {
-		unsigned short		d16;
-		unsigned char		d24[3];
-	} data;
 };
 
 /**
  * struct ad5446_chip_info - chip specific information
  * @channel:		channel spec for the DAC
  * @int_vref_mv:	AD5620/40/60: the internal reference voltage
- * @store_sample:	chip specific helper function to store the datum
- * @store_sample:	chip specific helper function to store the powerpown cmd
+ * @write:		chip specific helper function to write to the register
  */
 
 struct ad5446_chip_info {
 	struct iio_chan_spec	channel;
 	u16			int_vref_mv;
-	void (*store_sample)	(struct ad5446_state *st, unsigned val);
-	void (*store_pwr_down)	(struct ad5446_state *st, unsigned mode);
+	int			(*write)(struct ad5446_state *st, unsigned val);
 };
 
 /**
@@ -85,8 +72,6 @@
 	ID_AD5444,
 	ID_AD5446,
 	ID_AD5541A,
-	ID_AD5542A,
-	ID_AD5543,
 	ID_AD5512A,
 	ID_AD5553,
 	ID_AD5601,
@@ -98,6 +83,7 @@
 	ID_AD5640_1250,
 	ID_AD5660_2500,
 	ID_AD5660_1250,
+	ID_AD5662,
 };
 
 #endif /* IIO_DAC_AD5446_H_ */
diff --git a/drivers/staging/iio/dac/ad5504.c b/drivers/staging/iio/dac/ad5504.c
index bc17205..019cf15 100644
--- a/drivers/staging/iio/dac/ad5504.c
+++ b/drivers/staging/iio/dac/ad5504.c
@@ -16,9 +16,9 @@
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 #include "dac.h"
 #include "ad5504.h"
 
@@ -27,7 +27,8 @@
 	.indexed = 1, \
 	.output = 1, \
 	.channel = (_chan), \
-	.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+		     IIO_CHAN_INFO_SCALE_SHARED_BIT, \
 	.address = AD5504_ADDR_DAC(_chan), \
 	.scan_type = IIO_ST('u', 12, 16, 0), \
 }
@@ -81,7 +82,7 @@
 	int ret;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		ret = ad5504_spi_read(st->spi, chan->address);
 		if (ret < 0)
 			return ret;
@@ -109,7 +110,7 @@
 	int ret;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		if (val >= (1 << chan->scan_type.realbits) || val < 0)
 			return -EINVAL;
 
@@ -124,7 +125,7 @@
 static ssize_t ad5504_read_powerdown_mode(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5504_state *st = iio_priv(indio_dev);
 
 	const char mode[][14] = {"20kohm_to_gnd", "three_state"};
@@ -136,7 +137,7 @@
 				       struct device_attribute *attr,
 				       const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5504_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -154,7 +155,7 @@
 					   struct device_attribute *attr,
 					   char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5504_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -168,7 +169,7 @@
 {
 	long readin;
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5504_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -287,7 +288,7 @@
 	struct regulator *reg;
 	int ret, voltage_uv = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -350,7 +351,7 @@
 	if (!IS_ERR(reg))
 		regulator_put(reg);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -368,7 +369,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c
index 10c7484..42ff644 100644
--- a/drivers/staging/iio/dac/ad5624r_spi.c
+++ b/drivers/staging/iio/dac/ad5624r_spi.c
@@ -16,8 +16,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "dac.h"
 #include "ad5624r.h"
 
@@ -26,7 +26,8 @@
 	.indexed = 1, \
 	.output = 1, \
 	.channel = (_chan), \
-	.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+		     IIO_CHAN_INFO_SCALE_SHARED_BIT, \
 	.address = (_chan), \
 	.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
 }
@@ -122,7 +123,7 @@
 	int ret;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		if (val >= (1 << chan->scan_type.realbits) || val < 0)
 			return -EINVAL;
 
@@ -140,7 +141,7 @@
 static ssize_t ad5624r_read_powerdown_mode(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5624r_state *st = iio_priv(indio_dev);
 
 	char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
@@ -152,7 +153,7 @@
 				       struct device_attribute *attr,
 				       const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5624r_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -172,7 +173,7 @@
 					   struct device_attribute *attr,
 					   char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5624r_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -186,7 +187,7 @@
 {
 	long readin;
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5624r_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -255,7 +256,7 @@
 	struct iio_dev *indio_dev;
 	int ret, voltage_uv = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -305,7 +306,7 @@
 error_put_reg:
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 
 	return ret;
@@ -321,7 +322,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c
index 2415a6e..c1e903e 100644
--- a/drivers/staging/iio/dac/ad5686.c
+++ b/drivers/staging/iio/dac/ad5686.c
@@ -16,8 +16,8 @@
 #include <linux/sysfs.h>
 #include <linux/regulator/consumer.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "dac.h"
 
 #define AD5686_DAC_CHANNELS			4
@@ -98,7 +98,8 @@
 		.indexed = 1,					\
 		.output = 1,					\
 		.channel = chan,				\
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,	\
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,			\
 		.address = AD5686_ADDR_DAC(chan),			\
 		.scan_type = IIO_ST('u', bits, 16, shift)	\
 }
@@ -172,7 +173,7 @@
 static ssize_t ad5686_read_powerdown_mode(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5686_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -186,7 +187,7 @@
 				       struct device_attribute *attr,
 				       const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5686_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	unsigned mode;
@@ -210,7 +211,7 @@
 					   struct device_attribute *attr,
 					   char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5686_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -224,7 +225,7 @@
 {
 	bool readin;
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5686_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -296,7 +297,7 @@
 	int ret;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		ret = ad5686_spi_read(st, chan->address);
 		mutex_unlock(&indio_dev->mlock);
@@ -326,7 +327,7 @@
 	int ret;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		if (val > (1 << chan->scan_type.realbits) || val < 0)
 			return -EINVAL;
 
@@ -358,7 +359,7 @@
 	struct iio_dev *indio_dev;
 	int ret, regdone = 0, voltage_uv = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL)
 		return  -ENOMEM;
 
@@ -410,7 +411,7 @@
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -425,7 +426,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dac/ad5764.c b/drivers/staging/iio/dac/ad5764.c
index f73a730..03dbd93 100644
--- a/drivers/staging/iio/dac/ad5764.c
+++ b/drivers/staging/iio/dac/ad5764.c
@@ -16,8 +16,8 @@
 #include <linux/sysfs.h>
 #include <linux/regulator/consumer.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "dac.h"
 
 #define AD5764_REG_SF_NOP			0x0
@@ -79,7 +79,8 @@
 	.output = 1,						\
 	.channel = (_chan),					\
 	.address = (_chan),					\
-	.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |		\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_OFFSET_SHARED_BIT |		\
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |		\
 		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
 		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,		\
@@ -188,7 +189,7 @@
 	unsigned int reg;
 
 	switch (info) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		if (val >= max_val || val < 0)
 			return -EINVAL;
 		val <<= chan->scan_type.shift;
@@ -228,7 +229,7 @@
 	int ret;
 
 	switch (info) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		reg = AD5764_REG_DATA(chan->address);
 		ret = ad5764_read(indio_dev, reg, val);
 		if (ret < 0)
@@ -280,7 +281,7 @@
 	struct ad5764_state *st;
 	int ret;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		dev_err(&spi->dev, "Failed to allocate iio device\n");
 		return -ENOMEM;
@@ -335,7 +336,7 @@
 	if (st->chip_info->int_vref == 0)
 		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
 error_free:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -352,7 +353,7 @@
 		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
 	}
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dac/ad5791.c b/drivers/staging/iio/dac/ad5791.c
index ac45636..13d8b5b 100644
--- a/drivers/staging/iio/dac/ad5791.c
+++ b/drivers/staging/iio/dac/ad5791.c
@@ -17,8 +17,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "dac.h"
 #include "ad5791.h"
 
@@ -78,7 +78,8 @@
 	.indexed = 1,					\
 	.address = AD5791_ADDR_DAC0,			\
 	.channel = 0,					\
-	.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |	\
 		IIO_CHAN_INFO_OFFSET_SHARED_BIT,	\
 	.scan_type = IIO_ST('u', bits, 24, shift)	\
 }
@@ -93,7 +94,7 @@
 static ssize_t ad5791_read_powerdown_mode(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5791_state *st = iio_priv(indio_dev);
 
 	const char mode[][14] = {"6kohm_to_gnd", "three_state"};
@@ -105,7 +106,7 @@
 				       struct device_attribute *attr,
 				       const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5791_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -123,7 +124,7 @@
 					   struct device_attribute *attr,
 					   char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5791_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", st->pwr_down);
@@ -135,7 +136,7 @@
 {
 	long readin;
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5791_state *st = iio_priv(indio_dev);
 
 	ret = strict_strtol(buf, 10, &readin);
@@ -231,7 +232,7 @@
 	int ret;
 
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		ret = ad5791_spi_read(st->spi, chan->address, val);
 		if (ret)
 			return ret;
@@ -263,7 +264,7 @@
 	struct ad5791_state *st = iio_priv(indio_dev);
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		val &= AD5791_RES_MASK(chan->scan_type.realbits);
 		val <<= chan->scan_type.shift;
 
@@ -288,7 +289,7 @@
 	struct ad5791_state *st;
 	int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -368,7 +369,7 @@
 error_put_reg_pos:
 	if (!IS_ERR(st->reg_vdd))
 		regulator_put(st->reg_vdd);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 
 	return ret;
@@ -389,7 +390,7 @@
 		regulator_disable(st->reg_vss);
 		regulator_put(st->reg_vss);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c
index 41483c7..5287cad 100644
--- a/drivers/staging/iio/dac/max517.c
+++ b/drivers/staging/iio/dac/max517.c
@@ -25,8 +25,8 @@
 #include <linux/i2c.h>
 #include <linux/err.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "dac.h"
 
 #include "max517.h"
@@ -59,7 +59,7 @@
 				 struct device_attribute *attr,
 				 const char *buf, size_t count, int channel)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct max517_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
 	u8 outbuf[4]; /* 1x or 2x command + value */
@@ -128,7 +128,7 @@
 				struct device_attribute *attr,
 				char *buf, int channel)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct max517_data *data = iio_priv(indio_dev);
 	/* Corresponds to Vref / 2^(bits) */
 	unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8;
@@ -218,7 +218,7 @@
 	struct max517_platform_data *platform_data = client->dev.platform_data;
 	int err;
 
-	indio_dev = iio_allocate_device(sizeof(*data));
+	indio_dev = iio_device_alloc(sizeof(*data));
 	if (indio_dev == NULL) {
 		err = -ENOMEM;
 		goto exit;
@@ -257,14 +257,15 @@
 	return 0;
 
 exit_free_device:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 exit:
 	return err;
 }
 
 static int max517_remove(struct i2c_client *client)
 {
-	iio_free_device(i2c_get_clientdata(client));
+	iio_device_unregister(i2c_get_clientdata(client));
+	iio_device_free(i2c_get_clientdata(client));
 
 	return 0;
 }
diff --git a/drivers/staging/iio/dds/ad5930.c b/drivers/staging/iio/dds/ad5930.c
deleted file mode 100644
index 9c32d1b..0000000
--- a/drivers/staging/iio/dds/ad5930.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Driver for ADI Direct Digital Synthesis ad5930
- *
- * Copyright (c) 2010-2010 Analog Devices 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.
- *
- */
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-
-#define DRV_NAME "ad5930"
-
-#define value_mask (u16)0xf000
-#define addr_shift 12
-
-/* Register format: 4 bits addr + 12 bits value */
-struct ad5903_config {
-	u16 control;
-	u16 incnum;
-	u16 frqdelt[2];
-	u16 incitvl;
-	u16 buritvl;
-	u16 strtfrq[2];
-};
-
-struct ad5930_state {
-	struct mutex lock;
-	struct spi_device *sdev;
-};
-
-static ssize_t ad5930_set_parameter(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf,
-					size_t len)
-{
-	struct spi_message msg;
-	struct spi_transfer xfer;
-	int ret;
-	struct ad5903_config *config = (struct ad5903_config *)buf;
-	struct iio_dev *idev = dev_get_drvdata(dev);
-	struct ad5930_state *st = iio_priv(idev);
-
-	config->control = (config->control & ~value_mask);
-	config->incnum = (config->control & ~value_mask) | (1 << addr_shift);
-	config->frqdelt[0] = (config->control & ~value_mask) | (2 << addr_shift);
-	config->frqdelt[1] = (config->control & ~value_mask) | 3 << addr_shift;
-	config->incitvl = (config->control & ~value_mask) | 4 << addr_shift;
-	config->buritvl = (config->control & ~value_mask) | 8 << addr_shift;
-	config->strtfrq[0] = (config->control & ~value_mask) | 0xc << addr_shift;
-	config->strtfrq[1] = (config->control & ~value_mask) | 0xd << addr_shift;
-
-	xfer.len = len;
-	xfer.tx_buf = config;
-	mutex_lock(&st->lock);
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-error_ret:
-	mutex_unlock(&st->lock);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0);
-
-static struct attribute *ad5930_attributes[] = {
-	&iio_dev_attr_dds.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad5930_attribute_group = {
-	.attrs = ad5930_attributes,
-};
-
-static const struct iio_info ad5930_info = {
-	.attrs = &ad5930_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad5930_probe(struct spi_device *spi)
-{
-	struct ad5930_state *st;
-	struct iio_dev *idev;
-	int ret = 0;
-
-	idev = iio_allocate_device(sizeof(*st));
-	if (idev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	spi_set_drvdata(spi, idev);
-	st = iio_priv(idev);
-
-	mutex_init(&st->lock);
-	st->sdev = spi;
-	idev->dev.parent = &spi->dev;
-	idev->info = &ad5930_info;
-	idev->modes = INDIO_DIRECT_MODE;
-
-	ret = iio_device_register(idev);
-	if (ret)
-		goto error_free_dev;
-	spi->max_speed_hz = 2000000;
-	spi->mode = SPI_MODE_3;
-	spi->bits_per_word = 16;
-	spi_setup(spi);
-
-	return 0;
-
-error_free_dev:
-	iio_free_device(idev);
-error_ret:
-	return ret;
-}
-
-static int __devexit ad5930_remove(struct spi_device *spi)
-{
-	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
-
-	return 0;
-}
-
-static struct spi_driver ad5930_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = ad5930_probe,
-	.remove = __devexit_p(ad5930_remove),
-};
-module_spi_driver(ad5930_driver);
-
-MODULE_AUTHOR("Cliff Cai");
-MODULE_DESCRIPTION("Analog Devices ad5930 driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c
deleted file mode 100644
index 2ccf25d..0000000
--- a/drivers/staging/iio/dds/ad9832.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * AD9832 SPI DDS driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/spi/spi.h>
-#include <linux/regulator/consumer.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <asm/div64.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-#include "dds.h"
-
-#include "ad9832.h"
-
-static unsigned long ad9832_calc_freqreg(unsigned long mclk, unsigned long fout)
-{
-	unsigned long long freqreg = (u64) fout *
-				     (u64) ((u64) 1L << AD9832_FREQ_BITS);
-	do_div(freqreg, mclk);
-	return freqreg;
-}
-
-static int ad9832_write_frequency(struct ad9832_state *st,
-				  unsigned addr, unsigned long fout)
-{
-	unsigned long regval;
-
-	if (fout > (st->mclk / 2))
-		return -EINVAL;
-
-	regval = ad9832_calc_freqreg(st->mclk, fout);
-
-	st->freq_data[0] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
-					(addr << ADD_SHIFT) |
-					((regval >> 24) & 0xFF));
-	st->freq_data[1] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) |
-					((addr - 1) << ADD_SHIFT) |
-					((regval >> 16) & 0xFF));
-	st->freq_data[2] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
-					((addr - 2) << ADD_SHIFT) |
-					((regval >> 8) & 0xFF));
-	st->freq_data[3] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) |
-					((addr - 3) << ADD_SHIFT) |
-					((regval >> 0) & 0xFF));
-
-	return spi_sync(st->spi, &st->freq_msg);
-}
-
-static int ad9832_write_phase(struct ad9832_state *st,
-				  unsigned long addr, unsigned long phase)
-{
-	if (phase > (1 << AD9832_PHASE_BITS))
-		return -EINVAL;
-
-	st->phase_data[0] = cpu_to_be16((AD9832_CMD_PHA8BITSW << CMD_SHIFT) |
-					(addr << ADD_SHIFT) |
-					((phase >> 8) & 0xFF));
-	st->phase_data[1] = cpu_to_be16((AD9832_CMD_PHA16BITSW << CMD_SHIFT) |
-					((addr - 1) << ADD_SHIFT) |
-					(phase & 0xFF));
-
-	return spi_sync(st->spi, &st->phase_msg);
-}
-
-static ssize_t ad9832_write(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad9832_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int ret;
-	long val;
-
-	ret = strict_strtoul(buf, 10, &val);
-	if (ret)
-		goto error_ret;
-
-	mutex_lock(&indio_dev->mlock);
-	switch ((u32) this_attr->address) {
-	case AD9832_FREQ0HM:
-	case AD9832_FREQ1HM:
-		ret = ad9832_write_frequency(st, this_attr->address, val);
-		break;
-	case AD9832_PHASE0H:
-	case AD9832_PHASE1H:
-	case AD9832_PHASE2H:
-	case AD9832_PHASE3H:
-		ret = ad9832_write_phase(st, this_attr->address, val);
-		break;
-	case AD9832_PINCTRL_EN:
-		if (val)
-			st->ctrl_ss &= ~AD9832_SELSRC;
-		else
-			st->ctrl_ss |= AD9832_SELSRC;
-		st->data = cpu_to_be16((AD9832_CMD_SYNCSELSRC << CMD_SHIFT) |
-					st->ctrl_ss);
-		ret = spi_sync(st->spi, &st->msg);
-		break;
-	case AD9832_FREQ_SYM:
-		if (val == 1)
-			st->ctrl_fp |= AD9832_FREQ;
-		else if (val == 0)
-			st->ctrl_fp &= ~AD9832_FREQ;
-		else {
-			ret = -EINVAL;
-			break;
-		}
-		st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) |
-					st->ctrl_fp);
-		ret = spi_sync(st->spi, &st->msg);
-		break;
-	case AD9832_PHASE_SYM:
-		if (val < 0 || val > 3) {
-			ret = -EINVAL;
-			break;
-		}
-
-		st->ctrl_fp &= ~AD9832_PHASE(3);
-		st->ctrl_fp |= AD9832_PHASE(val);
-
-		st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) |
-					st->ctrl_fp);
-		ret = spi_sync(st->spi, &st->msg);
-		break;
-	case AD9832_OUTPUT_EN:
-		if (val)
-			st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP |
-					AD9832_CLR);
-		else
-			st->ctrl_src |= AD9832_RESET;
-
-		st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
-					st->ctrl_src);
-		ret = spi_sync(st->spi, &st->msg);
-		break;
-	default:
-		ret = -ENODEV;
-	}
-	mutex_unlock(&indio_dev->mlock);
-
-error_ret:
-	return ret ? ret : len;
-}
-
-/**
- * see dds.h for further information
- */
-
-static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ0HM);
-static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_FREQ1HM);
-static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ_SYM);
-static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
-
-static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_PHASE0H);
-static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_PHASE1H);
-static IIO_DEV_ATTR_PHASE(0, 2, S_IWUSR, NULL, ad9832_write, AD9832_PHASE2H);
-static IIO_DEV_ATTR_PHASE(0, 3, S_IWUSR, NULL, ad9832_write, AD9832_PHASE3H);
-static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL,
-				ad9832_write, AD9832_PHASE_SYM);
-static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
-
-static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL,
-				ad9832_write, AD9832_PINCTRL_EN);
-static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL,
-				ad9832_write, AD9832_OUTPUT_EN);
-
-static struct attribute *ad9832_attributes[] = {
-	&iio_dev_attr_dds0_freq0.dev_attr.attr,
-	&iio_dev_attr_dds0_freq1.dev_attr.attr,
-	&iio_const_attr_dds0_freq_scale.dev_attr.attr,
-	&iio_dev_attr_dds0_phase0.dev_attr.attr,
-	&iio_dev_attr_dds0_phase1.dev_attr.attr,
-	&iio_dev_attr_dds0_phase2.dev_attr.attr,
-	&iio_dev_attr_dds0_phase3.dev_attr.attr,
-	&iio_const_attr_dds0_phase_scale.dev_attr.attr,
-	&iio_dev_attr_dds0_pincontrol_en.dev_attr.attr,
-	&iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
-	&iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
-	&iio_dev_attr_dds0_out_enable.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad9832_attribute_group = {
-	.attrs = ad9832_attributes,
-};
-
-static const struct iio_info ad9832_info = {
-	.attrs = &ad9832_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad9832_probe(struct spi_device *spi)
-{
-	struct ad9832_platform_data *pdata = spi->dev.platform_data;
-	struct iio_dev *indio_dev;
-	struct ad9832_state *st;
-	struct regulator *reg;
-	int ret;
-
-	if (!pdata) {
-		dev_dbg(&spi->dev, "no platform data?\n");
-		return -ENODEV;
-	}
-
-	reg = regulator_get(&spi->dev, "vcc");
-	if (!IS_ERR(reg)) {
-		ret = regulator_enable(reg);
-		if (ret)
-			goto error_put_reg;
-	}
-
-	indio_dev = iio_allocate_device(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_disable_reg;
-	}
-	spi_set_drvdata(spi, indio_dev);
-	st = iio_priv(indio_dev);
-	st->reg = reg;
-	st->mclk = pdata->mclk;
-	st->spi = spi;
-
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad9832_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-
-	/* Setup default messages */
-
-	st->xfer.tx_buf = &st->data;
-	st->xfer.len = 2;
-
-	spi_message_init(&st->msg);
-	spi_message_add_tail(&st->xfer, &st->msg);
-
-	st->freq_xfer[0].tx_buf = &st->freq_data[0];
-	st->freq_xfer[0].len = 2;
-	st->freq_xfer[0].cs_change = 1;
-	st->freq_xfer[1].tx_buf = &st->freq_data[1];
-	st->freq_xfer[1].len = 2;
-	st->freq_xfer[1].cs_change = 1;
-	st->freq_xfer[2].tx_buf = &st->freq_data[2];
-	st->freq_xfer[2].len = 2;
-	st->freq_xfer[2].cs_change = 1;
-	st->freq_xfer[3].tx_buf = &st->freq_data[3];
-	st->freq_xfer[3].len = 2;
-
-	spi_message_init(&st->freq_msg);
-	spi_message_add_tail(&st->freq_xfer[0], &st->freq_msg);
-	spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg);
-	spi_message_add_tail(&st->freq_xfer[2], &st->freq_msg);
-	spi_message_add_tail(&st->freq_xfer[3], &st->freq_msg);
-
-	st->phase_xfer[0].tx_buf = &st->phase_data[0];
-	st->phase_xfer[0].len = 2;
-	st->phase_xfer[0].cs_change = 1;
-	st->phase_xfer[1].tx_buf = &st->phase_data[1];
-	st->phase_xfer[1].len = 2;
-
-	spi_message_init(&st->phase_msg);
-	spi_message_add_tail(&st->phase_xfer[0], &st->phase_msg);
-	spi_message_add_tail(&st->phase_xfer[1], &st->phase_msg);
-
-	st->ctrl_src = AD9832_SLEEP | AD9832_RESET | AD9832_CLR;
-	st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
-					st->ctrl_src);
-	ret = spi_sync(st->spi, &st->msg);
-	if (ret) {
-		dev_err(&spi->dev, "device init failed\n");
-		goto error_free_device;
-	}
-
-	ret = ad9832_write_frequency(st, AD9832_FREQ0HM, pdata->freq0);
-	if (ret)
-		goto error_free_device;
-
-	ret = ad9832_write_frequency(st, AD9832_FREQ1HM, pdata->freq1);
-	if (ret)
-		goto error_free_device;
-
-	ret = ad9832_write_phase(st, AD9832_PHASE0H, pdata->phase0);
-	if (ret)
-		goto error_free_device;
-
-	ret = ad9832_write_phase(st, AD9832_PHASE1H, pdata->phase1);
-	if (ret)
-		goto error_free_device;
-
-	ret = ad9832_write_phase(st, AD9832_PHASE2H, pdata->phase2);
-	if (ret)
-		goto error_free_device;
-
-	ret = ad9832_write_phase(st, AD9832_PHASE3H, pdata->phase3);
-	if (ret)
-		goto error_free_device;
-
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_free_device;
-
-	return 0;
-
-error_free_device:
-	iio_free_device(indio_dev);
-error_disable_reg:
-	if (!IS_ERR(reg))
-		regulator_disable(reg);
-error_put_reg:
-	if (!IS_ERR(reg))
-		regulator_put(reg);
-
-	return ret;
-}
-
-static int __devexit ad9832_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad9832_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg)) {
-		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_free_device(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad9832_id[] = {
-	{"ad9832", 0},
-	{"ad9835", 0},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad9832_id);
-
-static struct spi_driver ad9832_driver = {
-	.driver = {
-		.name	= "ad9832",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= ad9832_probe,
-	.remove		= __devexit_p(ad9832_remove),
-	.id_table	= ad9832_id,
-};
-module_spi_driver(ad9832_driver);
-
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Analog Devices AD9832/AD9835 DDS");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9834.c b/drivers/staging/iio/dds/ad9834.c
deleted file mode 100644
index 38a2de0..0000000
--- a/drivers/staging/iio/dds/ad9834.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * AD9833/AD9834/AD9837/AD9838 SPI DDS driver
- *
- * Copyright 2010-2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/spi/spi.h>
-#include <linux/regulator/consumer.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <asm/div64.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-#include "dds.h"
-
-#include "ad9834.h"
-
-static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout)
-{
-	unsigned long long freqreg = (u64) fout * (u64) (1 << AD9834_FREQ_BITS);
-	do_div(freqreg, mclk);
-	return freqreg;
-}
-
-static int ad9834_write_frequency(struct ad9834_state *st,
-				  unsigned long addr, unsigned long fout)
-{
-	unsigned long regval;
-
-	if (fout > (st->mclk / 2))
-		return -EINVAL;
-
-	regval = ad9834_calc_freqreg(st->mclk, fout);
-
-	st->freq_data[0] = cpu_to_be16(addr | (regval &
-				       RES_MASK(AD9834_FREQ_BITS / 2)));
-	st->freq_data[1] = cpu_to_be16(addr | ((regval >>
-				       (AD9834_FREQ_BITS / 2)) &
-				       RES_MASK(AD9834_FREQ_BITS / 2)));
-
-	return spi_sync(st->spi, &st->freq_msg);
-}
-
-static int ad9834_write_phase(struct ad9834_state *st,
-				  unsigned long addr, unsigned long phase)
-{
-	if (phase > (1 << AD9834_PHASE_BITS))
-		return -EINVAL;
-	st->data = cpu_to_be16(addr | phase);
-
-	return spi_sync(st->spi, &st->msg);
-}
-
-static ssize_t ad9834_write(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad9834_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int ret;
-	long val;
-
-	ret = strict_strtoul(buf, 10, &val);
-	if (ret)
-		goto error_ret;
-
-	mutex_lock(&indio_dev->mlock);
-	switch ((u32) this_attr->address) {
-	case AD9834_REG_FREQ0:
-	case AD9834_REG_FREQ1:
-		ret = ad9834_write_frequency(st, this_attr->address, val);
-		break;
-	case AD9834_REG_PHASE0:
-	case AD9834_REG_PHASE1:
-		ret = ad9834_write_phase(st, this_attr->address, val);
-		break;
-	case AD9834_OPBITEN:
-		if (st->control & AD9834_MODE) {
-			ret = -EINVAL;  /* AD9843 reserved mode */
-			break;
-		}
-
-		if (val)
-			st->control |= AD9834_OPBITEN;
-		else
-			st->control &= ~AD9834_OPBITEN;
-
-		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
-		ret = spi_sync(st->spi, &st->msg);
-		break;
-	case AD9834_PIN_SW:
-		if (val)
-			st->control |= AD9834_PIN_SW;
-		else
-			st->control &= ~AD9834_PIN_SW;
-		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
-		ret = spi_sync(st->spi, &st->msg);
-		break;
-	case AD9834_FSEL:
-	case AD9834_PSEL:
-		if (val == 0)
-			st->control &= ~(this_attr->address | AD9834_PIN_SW);
-		else if (val == 1) {
-			st->control |= this_attr->address;
-			st->control &= ~AD9834_PIN_SW;
-		} else {
-			ret = -EINVAL;
-			break;
-		}
-		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
-		ret = spi_sync(st->spi, &st->msg);
-		break;
-	case AD9834_RESET:
-		if (val)
-			st->control &= ~AD9834_RESET;
-		else
-			st->control |= AD9834_RESET;
-
-		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
-		ret = spi_sync(st->spi, &st->msg);
-		break;
-	default:
-		ret = -ENODEV;
-	}
-	mutex_unlock(&indio_dev->mlock);
-
-error_ret:
-	return ret ? ret : len;
-}
-
-static ssize_t ad9834_store_wavetype(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf,
-				 size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad9834_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int ret = 0;
-	bool is_ad9833_7 = (st->devid == ID_AD9833) || (st->devid == ID_AD9837);
-
-	mutex_lock(&indio_dev->mlock);
-
-	switch ((u32) this_attr->address) {
-	case 0:
-		if (sysfs_streq(buf, "sine")) {
-			st->control &= ~AD9834_MODE;
-			if (is_ad9833_7)
-				st->control &= ~AD9834_OPBITEN;
-		} else if (sysfs_streq(buf, "triangle")) {
-			if (is_ad9833_7) {
-				st->control &= ~AD9834_OPBITEN;
-				st->control |= AD9834_MODE;
-			} else if (st->control & AD9834_OPBITEN) {
-				ret = -EINVAL;	/* AD9843 reserved mode */
-			} else {
-				st->control |= AD9834_MODE;
-			}
-		} else if (is_ad9833_7 && sysfs_streq(buf, "square")) {
-			st->control &= ~AD9834_MODE;
-			st->control |= AD9834_OPBITEN;
-		} else {
-			ret = -EINVAL;
-		}
-
-		break;
-	case 1:
-		if (sysfs_streq(buf, "square") &&
-			!(st->control & AD9834_MODE)) {
-			st->control &= ~AD9834_MODE;
-			st->control |= AD9834_OPBITEN;
-		} else {
-			ret = -EINVAL;
-		}
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	if (!ret) {
-		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
-		ret = spi_sync(st->spi, &st->msg);
-	}
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret ? ret : len;
-}
-
-static ssize_t ad9834_show_out0_wavetype_available(struct device *dev,
-						struct device_attribute *attr,
-						char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad9834_state *st = iio_priv(indio_dev);
-	char *str;
-
-	if ((st->devid == ID_AD9833) || (st->devid == ID_AD9837))
-		str = "sine triangle square";
-	else if (st->control & AD9834_OPBITEN)
-		str = "sine";
-	else
-		str = "sine triangle";
-
-	return sprintf(buf, "%s\n", str);
-}
-
-
-static IIO_DEVICE_ATTR(dds0_out0_wavetype_available, S_IRUGO,
-		       ad9834_show_out0_wavetype_available, NULL, 0);
-
-static ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
-						struct device_attribute *attr,
-						char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad9834_state *st = iio_priv(indio_dev);
-	char *str;
-
-	if (st->control & AD9834_MODE)
-		str = "";
-	else
-		str = "square";
-
-	return sprintf(buf, "%s\n", str);
-}
-
-static IIO_DEVICE_ATTR(dds0_out1_wavetype_available, S_IRUGO,
-		       ad9834_show_out1_wavetype_available, NULL, 0);
-
-/**
- * see dds.h for further information
- */
-
-static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ0);
-static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ1);
-static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_FSEL);
-static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
-
-static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE0);
-static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE1);
-static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_PSEL);
-static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
-
-static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL,
-	ad9834_write, AD9834_PIN_SW);
-static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, ad9834_write, AD9834_RESET);
-static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, S_IWUSR, NULL,
-	ad9834_write, AD9834_OPBITEN);
-static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0);
-static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1);
-
-static struct attribute *ad9834_attributes[] = {
-	&iio_dev_attr_dds0_freq0.dev_attr.attr,
-	&iio_dev_attr_dds0_freq1.dev_attr.attr,
-	&iio_const_attr_dds0_freq_scale.dev_attr.attr,
-	&iio_dev_attr_dds0_phase0.dev_attr.attr,
-	&iio_dev_attr_dds0_phase1.dev_attr.attr,
-	&iio_const_attr_dds0_phase_scale.dev_attr.attr,
-	&iio_dev_attr_dds0_pincontrol_en.dev_attr.attr,
-	&iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
-	&iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
-	&iio_dev_attr_dds0_out_enable.dev_attr.attr,
-	&iio_dev_attr_dds0_out1_enable.dev_attr.attr,
-	&iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
-	&iio_dev_attr_dds0_out1_wavetype.dev_attr.attr,
-	&iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
-	&iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr,
-	NULL,
-};
-
-static struct attribute *ad9833_attributes[] = {
-	&iio_dev_attr_dds0_freq0.dev_attr.attr,
-	&iio_dev_attr_dds0_freq1.dev_attr.attr,
-	&iio_const_attr_dds0_freq_scale.dev_attr.attr,
-	&iio_dev_attr_dds0_phase0.dev_attr.attr,
-	&iio_dev_attr_dds0_phase1.dev_attr.attr,
-	&iio_const_attr_dds0_phase_scale.dev_attr.attr,
-	&iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
-	&iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
-	&iio_dev_attr_dds0_out_enable.dev_attr.attr,
-	&iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
-	&iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad9834_attribute_group = {
-	.attrs = ad9834_attributes,
-};
-
-static const struct attribute_group ad9833_attribute_group = {
-	.attrs = ad9833_attributes,
-};
-
-static const struct iio_info ad9834_info = {
-	.attrs = &ad9834_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static const struct iio_info ad9833_info = {
-	.attrs = &ad9833_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad9834_probe(struct spi_device *spi)
-{
-	struct ad9834_platform_data *pdata = spi->dev.platform_data;
-	struct ad9834_state *st;
-	struct iio_dev *indio_dev;
-	struct regulator *reg;
-	int ret;
-
-	if (!pdata) {
-		dev_dbg(&spi->dev, "no platform data?\n");
-		return -ENODEV;
-	}
-
-	reg = regulator_get(&spi->dev, "vcc");
-	if (!IS_ERR(reg)) {
-		ret = regulator_enable(reg);
-		if (ret)
-			goto error_put_reg;
-	}
-
-	indio_dev = iio_allocate_device(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_disable_reg;
-	}
-	spi_set_drvdata(spi, indio_dev);
-	st = iio_priv(indio_dev);
-	st->mclk = pdata->mclk;
-	st->spi = spi;
-	st->devid = spi_get_device_id(spi)->driver_data;
-	st->reg = reg;
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	switch (st->devid) {
-	case ID_AD9833:
-	case ID_AD9837:
-		indio_dev->info = &ad9833_info;
-		break;
-	default:
-		indio_dev->info = &ad9834_info;
-		break;
-	}
-	indio_dev->modes = INDIO_DIRECT_MODE;
-
-	/* Setup default messages */
-
-	st->xfer.tx_buf = &st->data;
-	st->xfer.len = 2;
-
-	spi_message_init(&st->msg);
-	spi_message_add_tail(&st->xfer, &st->msg);
-
-	st->freq_xfer[0].tx_buf = &st->freq_data[0];
-	st->freq_xfer[0].len = 2;
-	st->freq_xfer[0].cs_change = 1;
-	st->freq_xfer[1].tx_buf = &st->freq_data[1];
-	st->freq_xfer[1].len = 2;
-
-	spi_message_init(&st->freq_msg);
-	spi_message_add_tail(&st->freq_xfer[0], &st->freq_msg);
-	spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg);
-
-	st->control = AD9834_B28 | AD9834_RESET;
-
-	if (!pdata->en_div2)
-		st->control |= AD9834_DIV2;
-
-	if (!pdata->en_signbit_msb_out && (st->devid == ID_AD9834))
-		st->control |= AD9834_SIGN_PIB;
-
-	st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
-	ret = spi_sync(st->spi, &st->msg);
-	if (ret) {
-		dev_err(&spi->dev, "device init failed\n");
-		goto error_free_device;
-	}
-
-	ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0);
-	if (ret)
-		goto error_free_device;
-
-	ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1);
-	if (ret)
-		goto error_free_device;
-
-	ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0);
-	if (ret)
-		goto error_free_device;
-
-	ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1);
-	if (ret)
-		goto error_free_device;
-
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_free_device;
-
-	return 0;
-
-error_free_device:
-	iio_free_device(indio_dev);
-error_disable_reg:
-	if (!IS_ERR(reg))
-		regulator_disable(reg);
-error_put_reg:
-	if (!IS_ERR(reg))
-		regulator_put(reg);
-	return ret;
-}
-
-static int __devexit ad9834_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad9834_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg)) {
-		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_free_device(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad9834_id[] = {
-	{"ad9833", ID_AD9833},
-	{"ad9834", ID_AD9834},
-	{"ad9837", ID_AD9837},
-	{"ad9838", ID_AD9838},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad9834_id);
-
-static struct spi_driver ad9834_driver = {
-	.driver = {
-		.name	= "ad9834",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= ad9834_probe,
-	.remove		= __devexit_p(ad9834_remove),
-	.id_table	= ad9834_id,
-};
-module_spi_driver(ad9834_driver);
-
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Analog Devices AD9833/AD9834/AD9837/AD9838 DDS");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9850.c b/drivers/staging/iio/dds/ad9850.c
deleted file mode 100644
index f4f731b..0000000
--- a/drivers/staging/iio/dds/ad9850.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Driver for ADI Direct Digital Synthesis ad9850
- *
- * Copyright (c) 2010-2010 Analog Devices 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.
- *
- */
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-
-#define DRV_NAME "ad9850"
-
-#define value_mask (u16)0xf000
-#define addr_shift 12
-
-/* Register format: 4 bits addr + 12 bits value */
-struct ad9850_config {
-	u8 control[5];
-};
-
-struct ad9850_state {
-	struct mutex lock;
-	struct spi_device *sdev;
-};
-
-static ssize_t ad9850_set_parameter(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf,
-					size_t len)
-{
-	struct spi_message msg;
-	struct spi_transfer xfer;
-	int ret;
-	struct ad9850_config *config = (struct ad9850_config *)buf;
-	struct iio_dev *idev = dev_get_drvdata(dev);
-	struct ad9850_state *st = iio_priv(idev);
-
-	xfer.len = len;
-	xfer.tx_buf = config;
-	mutex_lock(&st->lock);
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-error_ret:
-	mutex_unlock(&st->lock);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9850_set_parameter, 0);
-
-static struct attribute *ad9850_attributes[] = {
-	&iio_dev_attr_dds.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad9850_attribute_group = {
-	.attrs = ad9850_attributes,
-};
-
-static const struct iio_info ad9850_info = {
-	.attrs = &ad9850_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad9850_probe(struct spi_device *spi)
-{
-	struct ad9850_state *st;
-	struct iio_dev *idev;
-	int ret = 0;
-
-	idev = iio_allocate_device(sizeof(*st));
-	if (idev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	spi_set_drvdata(spi, idev);
-	st = iio_priv(idev);
-	mutex_init(&st->lock);
-	st->sdev = spi;
-
-	idev->dev.parent = &spi->dev;
-	idev->info = &ad9850_info;
-	idev->modes = INDIO_DIRECT_MODE;
-
-	ret = iio_device_register(idev);
-	if (ret)
-		goto error_free_dev;
-	spi->max_speed_hz = 2000000;
-	spi->mode = SPI_MODE_3;
-	spi->bits_per_word = 16;
-	spi_setup(spi);
-
-	return 0;
-
-error_free_dev:
-	iio_free_device(idev);
-error_ret:
-	return ret;
-}
-
-static int __devexit ad9850_remove(struct spi_device *spi)
-{
-	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
-
-	return 0;
-}
-
-static struct spi_driver ad9850_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = ad9850_probe,
-	.remove = __devexit_p(ad9850_remove),
-};
-module_spi_driver(ad9850_driver);
-
-MODULE_AUTHOR("Cliff Cai");
-MODULE_DESCRIPTION("Analog Devices ad9850 driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/dds/ad9852.c
deleted file mode 100644
index 554266c..0000000
--- a/drivers/staging/iio/dds/ad9852.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Driver for ADI Direct Digital Synthesis ad9852
- *
- * Copyright (c) 2010 Analog Devices 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.
- *
- */
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-
-#define DRV_NAME "ad9852"
-
-#define addr_phaad1 0x0
-#define addr_phaad2 0x1
-#define addr_fretu1 0x2
-#define addr_fretu2 0x3
-#define addr_delfre 0x4
-#define addr_updclk 0x5
-#define addr_ramclk 0x6
-#define addr_contrl 0x7
-#define addr_optskm 0x8
-#define addr_optskr 0xa
-#define addr_dacctl 0xb
-
-#define COMPPD		(1 << 4)
-#define REFMULT2	(1 << 2)
-#define BYPPLL		(1 << 5)
-#define PLLRANG		(1 << 6)
-#define IEUPCLK		(1)
-#define OSKEN		(1 << 5)
-
-#define read_bit	(1 << 7)
-
-/* Register format: 1 byte addr + value */
-struct ad9852_config {
-	u8 phajst0[3];
-	u8 phajst1[3];
-	u8 fretun1[6];
-	u8 fretun2[6];
-	u8 dltafre[6];
-	u8 updtclk[5];
-	u8 ramprat[4];
-	u8 control[5];
-	u8 outpskm[3];
-	u8 outpskr[2];
-	u8 daccntl[3];
-};
-
-struct ad9852_state {
-	struct mutex lock;
-	struct spi_device *sdev;
-};
-
-static ssize_t ad9852_set_parameter(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf,
-					size_t len)
-{
-	struct spi_message msg;
-	struct spi_transfer xfer;
-	int ret;
-	struct ad9852_config *config = (struct ad9852_config *)buf;
-	struct iio_dev *idev = dev_get_drvdata(dev);
-	struct ad9852_state *st = iio_priv(idev);
-
-	xfer.len = 3;
-	xfer.tx_buf = &config->phajst0[0];
-	mutex_lock(&st->lock);
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 3;
-	xfer.tx_buf = &config->phajst1[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 6;
-	xfer.tx_buf = &config->fretun1[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 6;
-	xfer.tx_buf = &config->fretun2[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 6;
-	xfer.tx_buf = &config->dltafre[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 5;
-	xfer.tx_buf = &config->updtclk[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 4;
-	xfer.tx_buf = &config->ramprat[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 5;
-	xfer.tx_buf = &config->control[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 3;
-	xfer.tx_buf = &config->outpskm[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 2;
-	xfer.tx_buf = &config->outpskr[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 3;
-	xfer.tx_buf = &config->daccntl[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-error_ret:
-	mutex_unlock(&st->lock);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0);
-
-static void ad9852_init(struct ad9852_state *st)
-{
-	struct spi_message msg;
-	struct spi_transfer xfer;
-	int ret;
-	u8 config[5];
-
-	config[0] = addr_contrl;
-	config[1] = COMPPD;
-	config[2] = REFMULT2 | BYPPLL | PLLRANG;
-	config[3] = IEUPCLK;
-	config[4] = OSKEN;
-
-	mutex_lock(&st->lock);
-
-	xfer.len = 5;
-	xfer.tx_buf = &config;
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-error_ret:
-	mutex_unlock(&st->lock);
-
-
-
-}
-
-static struct attribute *ad9852_attributes[] = {
-	&iio_dev_attr_dds.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad9852_attribute_group = {
-	.attrs = ad9852_attributes,
-};
-
-static const struct iio_info ad9852_info = {
-	.attrs = &ad9852_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad9852_probe(struct spi_device *spi)
-{
-	struct ad9852_state *st;
-	struct iio_dev *idev;
-	int ret = 0;
-
-	idev = iio_allocate_device(sizeof(*st));
-	if (idev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	st = iio_priv(idev);
-	spi_set_drvdata(spi, idev);
-	mutex_init(&st->lock);
-	st->sdev = spi;
-
-	idev->dev.parent = &spi->dev;
-	idev->info = &ad9852_info;
-	idev->modes = INDIO_DIRECT_MODE;
-
-	ret = iio_device_register(idev);
-	if (ret)
-		goto error_free_dev;
-	spi->max_speed_hz = 2000000;
-	spi->mode = SPI_MODE_3;
-	spi->bits_per_word = 8;
-	spi_setup(spi);
-	ad9852_init(st);
-
-	return 0;
-
-error_free_dev:
-	iio_free_device(idev);
-
-error_ret:
-	return ret;
-}
-
-static int __devexit ad9852_remove(struct spi_device *spi)
-{
-	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
-
-	return 0;
-}
-
-static struct spi_driver ad9852_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = ad9852_probe,
-	.remove = __devexit_p(ad9852_remove),
-};
-module_spi_driver(ad9852_driver);
-
-MODULE_AUTHOR("Cliff Cai");
-MODULE_DESCRIPTION("Analog Devices ad9852 driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/dds/ad9910.c
deleted file mode 100644
index 3985766..0000000
--- a/drivers/staging/iio/dds/ad9910.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Driver for ADI Direct Digital Synthesis ad9910
- *
- * Copyright (c) 2010 Analog Devices 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.
- *
- */
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-
-#define DRV_NAME "ad9910"
-
-#define CFR1 0x0
-#define CFR2 0x1
-#define CFR3 0x2
-
-#define AUXDAC 0x3
-#define IOUPD 0x4
-#define FTW 0x7
-#define POW 0x8
-#define ASF 0x9
-#define MULTC 0x0A
-#define DIG_RAMPL 0x0B
-#define DIG_RAMPS 0x0C
-#define DIG_RAMPR 0x0D
-#define SIN_TONEP0 0x0E
-#define SIN_TONEP1 0x0F
-#define SIN_TONEP2 0x10
-#define SIN_TONEP3 0x11
-#define SIN_TONEP4 0x12
-#define SIN_TONEP5 0x13
-#define SIN_TONEP6 0x14
-#define SIN_TONEP7 0x15
-
-#define RAM_ENABLE	(1 << 7)
-
-#define MANUAL_OSK	(1 << 7)
-#define INVSIC		(1 << 6)
-#define DDS_SINEOP	(1)
-
-#define AUTO_OSK	(1)
-#define OSKEN		(1 << 1)
-#define LOAD_ARR	(1 << 2)
-#define CLR_PHA		(1 << 3)
-#define CLR_DIG		(1 << 4)
-#define ACLR_PHA	(1 << 5)
-#define ACLR_DIG	(1 << 6)
-#define LOAD_LRR	(1 << 7)
-
-#define LSB_FST		(1)
-#define SDIO_IPT	(1 << 1)
-#define EXT_PWD		(1 << 3)
-#define ADAC_PWD	(1 << 4)
-#define REFCLK_PWD	(1 << 5)
-#define DAC_PWD		(1 << 6)
-#define DIG_PWD		(1 << 7)
-
-#define ENA_AMP		(1)
-#define READ_FTW	(1)
-#define DIGR_LOW	(1 << 1)
-#define DIGR_HIGH	(1 << 2)
-#define DIGR_ENA	(1 << 3)
-#define SYNCCLK_ENA	(1 << 6)
-#define ITER_IOUPD	(1 << 7)
-
-#define TX_ENA		(1 << 1)
-#define PDCLK_INV	(1 << 2)
-#define PDCLK_ENB	(1 << 3)
-
-#define PARA_ENA	(1 << 4)
-#define SYNC_DIS	(1 << 5)
-#define DATA_ASS	(1 << 6)
-#define MATCH_ENA	(1 << 7)
-
-#define PLL_ENA		(1)
-#define PFD_RST		(1 << 2)
-#define REFCLK_RST	(1 << 6)
-#define REFCLK_BYP	(1 << 7)
-
-/* Register format: 1 byte addr + value */
-struct ad9910_config {
-	u8 auxdac[5];
-	u8 ioupd[5];
-	u8 ftw[5];
-	u8 pow[3];
-	u8 asf[5];
-	u8 multc[5];
-	u8 dig_rampl[9];
-	u8 dig_ramps[9];
-	u8 dig_rampr[5];
-	u8 sin_tonep0[9];
-	u8 sin_tonep1[9];
-	u8 sin_tonep2[9];
-	u8 sin_tonep3[9];
-	u8 sin_tonep4[9];
-	u8 sin_tonep5[9];
-	u8 sin_tonep6[9];
-	u8 sin_tonep7[9];
-};
-
-struct ad9910_state {
-	struct mutex lock;
-	struct spi_device *sdev;
-};
-
-static ssize_t ad9910_set_parameter(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf,
-					size_t len)
-{
-	struct spi_message msg;
-	struct spi_transfer xfer;
-	int ret;
-	struct ad9910_config *config = (struct ad9910_config *)buf;
-	struct iio_dev *idev = dev_get_drvdata(dev);
-	struct ad9910_state *st = iio_priv(idev);
-
-	xfer.len = 5;
-	xfer.tx_buf = &config->auxdac[0];
-	mutex_lock(&st->lock);
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 5;
-	xfer.tx_buf = &config->ioupd[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 5;
-	xfer.tx_buf = &config->ftw[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 3;
-	xfer.tx_buf = &config->pow[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 5;
-	xfer.tx_buf = &config->asf[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 5;
-	xfer.tx_buf = &config->multc[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 9;
-	xfer.tx_buf = &config->dig_rampl[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 9;
-	xfer.tx_buf = &config->dig_ramps[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 5;
-	xfer.tx_buf = &config->dig_rampr[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 9;
-	xfer.tx_buf = &config->sin_tonep0[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 9;
-	xfer.tx_buf = &config->sin_tonep1[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 9;
-	xfer.tx_buf = &config->sin_tonep2[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-	xfer.len = 9;
-	xfer.tx_buf = &config->sin_tonep3[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 9;
-	xfer.tx_buf = &config->sin_tonep4[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 9;
-	xfer.tx_buf = &config->sin_tonep5[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 9;
-	xfer.tx_buf = &config->sin_tonep6[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 9;
-	xfer.tx_buf = &config->sin_tonep7[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-error_ret:
-	mutex_unlock(&st->lock);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0);
-
-static void ad9910_init(struct ad9910_state *st)
-{
-	struct spi_message msg;
-	struct spi_transfer xfer;
-	int ret;
-	u8 cfr[5];
-
-	cfr[0] = CFR1;
-	cfr[1] = 0;
-	cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP;
-	cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR;
-	cfr[4] = 0;
-
-	mutex_lock(&st->lock);
-
-	xfer.len = 5;
-	xfer.tx_buf = &cfr;
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	cfr[0] = CFR2;
-	cfr[1] = ENA_AMP;
-	cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD;
-	cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB;
-	cfr[4] = PARA_ENA;
-
-	xfer.len = 5;
-	xfer.tx_buf = &cfr;
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	cfr[0] = CFR3;
-	cfr[1] = PLL_ENA;
-	cfr[2] = 0;
-	cfr[3] = REFCLK_RST | REFCLK_BYP;
-	cfr[4] = 0;
-
-	xfer.len = 5;
-	xfer.tx_buf = &cfr;
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-error_ret:
-	mutex_unlock(&st->lock);
-
-
-
-}
-
-static struct attribute *ad9910_attributes[] = {
-	&iio_dev_attr_dds.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad9910_attribute_group = {
-	.attrs = ad9910_attributes,
-};
-
-static const struct iio_info ad9910_info = {
-	.attrs = &ad9910_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad9910_probe(struct spi_device *spi)
-{
-	struct ad9910_state *st;
-	struct iio_dev *idev;
-	int ret = 0;
-
-	idev = iio_allocate_device(sizeof(*st));
-	if (idev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	spi_set_drvdata(spi, idev);
-	st = iio_priv(idev);
-	mutex_init(&st->lock);
-	st->sdev = spi;
-
-	idev->dev.parent = &spi->dev;
-	idev->info = &ad9910_info;
-	idev->modes = INDIO_DIRECT_MODE;
-
-	ret = iio_device_register(idev);
-	if (ret)
-		goto error_free_dev;
-	spi->max_speed_hz = 2000000;
-	spi->mode = SPI_MODE_3;
-	spi->bits_per_word = 8;
-	spi_setup(spi);
-	ad9910_init(st);
-	return 0;
-
-error_free_dev:
-	iio_free_device(idev);
-error_ret:
-	return ret;
-}
-
-static int __devexit ad9910_remove(struct spi_device *spi)
-{
-	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
-
-	return 0;
-}
-
-static struct spi_driver ad9910_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = ad9910_probe,
-	.remove = __devexit_p(ad9910_remove),
-};
-module_spi_driver(ad9910_driver);
-
-MODULE_AUTHOR("Cliff Cai");
-MODULE_DESCRIPTION("Analog Devices ad9910 driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/dds/ad9951.c
deleted file mode 100644
index 4d15004..0000000
--- a/drivers/staging/iio/dds/ad9951.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Driver for ADI Direct Digital Synthesis ad9951
- *
- * Copyright (c) 2010 Analog Devices 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.
- *
- */
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-
-#define DRV_NAME "ad9951"
-
-#define CFR1 0x0
-#define CFR2 0x1
-
-#define AUTO_OSK	(1)
-#define OSKEN		(1 << 1)
-#define LOAD_ARR	(1 << 2)
-
-#define AUTO_SYNC	(1 << 7)
-
-#define LSB_FST		(1)
-#define SDIO_IPT	(1 << 1)
-#define CLR_PHA		(1 << 2)
-#define SINE_OPT	(1 << 4)
-#define ACLR_PHA	(1 << 5)
-
-#define VCO_RANGE	(1 << 2)
-
-#define CRS_OPT		(1 << 1)
-#define HMANU_SYNC	(1 << 2)
-#define HSPD_SYNC	(1 << 3)
-
-/* Register format: 1 byte addr + value */
-struct ad9951_config {
-	u8 asf[3];
-	u8 arr[2];
-	u8 ftw0[5];
-	u8 ftw1[3];
-};
-
-struct ad9951_state {
-	struct mutex lock;
-	struct spi_device *sdev;
-};
-
-static ssize_t ad9951_set_parameter(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf,
-					size_t len)
-{
-	struct spi_message msg;
-	struct spi_transfer xfer;
-	int ret;
-	struct ad9951_config *config = (struct ad9951_config *)buf;
-	struct iio_dev *idev = dev_get_drvdata(dev);
-	struct ad9951_state *st = iio_priv(idev);
-
-	xfer.len = 3;
-	xfer.tx_buf = &config->asf[0];
-	mutex_lock(&st->lock);
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 2;
-	xfer.tx_buf = &config->arr[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 5;
-	xfer.tx_buf = &config->ftw0[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	xfer.len = 3;
-	xfer.tx_buf = &config->ftw1[0];
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-error_ret:
-	mutex_unlock(&st->lock);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0);
-
-static void ad9951_init(struct ad9951_state *st)
-{
-	struct spi_message msg;
-	struct spi_transfer xfer;
-	int ret;
-	u8 cfr[5];
-
-	cfr[0] = CFR1;
-	cfr[1] = 0;
-	cfr[2] = LSB_FST | CLR_PHA | SINE_OPT | ACLR_PHA;
-	cfr[3] = AUTO_OSK | OSKEN | LOAD_ARR;
-	cfr[4] = 0;
-
-	mutex_lock(&st->lock);
-
-	xfer.len = 5;
-	xfer.tx_buf = &cfr;
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-	cfr[0] = CFR2;
-	cfr[1] = VCO_RANGE;
-	cfr[2] = HSPD_SYNC;
-	cfr[3] = 0;
-
-	xfer.len = 4;
-	xfer.tx_buf = &cfr;
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
-	ret = spi_sync(st->sdev, &msg);
-	if (ret)
-		goto error_ret;
-
-error_ret:
-	mutex_unlock(&st->lock);
-
-
-
-}
-
-static struct attribute *ad9951_attributes[] = {
-	&iio_dev_attr_dds.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad9951_attribute_group = {
-	.attrs = ad9951_attributes,
-};
-
-static const struct iio_info ad9951_info = {
-	.attrs = &ad9951_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad9951_probe(struct spi_device *spi)
-{
-	struct ad9951_state *st;
-	struct iio_dev *idev;
-	int ret = 0;
-
-	idev = iio_allocate_device(sizeof(*st));
-	if (idev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	spi_set_drvdata(spi, idev);
-	st = iio_priv(idev);
-	mutex_init(&st->lock);
-	st->sdev = spi;
-
-	idev->dev.parent = &spi->dev;
-
-	idev->info = &ad9951_info;
-	idev->modes = INDIO_DIRECT_MODE;
-
-	ret = iio_device_register(idev);
-	if (ret)
-		goto error_free_dev;
-	spi->max_speed_hz = 2000000;
-	spi->mode = SPI_MODE_3;
-	spi->bits_per_word = 8;
-	spi_setup(spi);
-	ad9951_init(st);
-	return 0;
-
-error_free_dev:
-	iio_free_device(idev);
-
-error_ret:
-	return ret;
-}
-
-static int __devexit ad9951_remove(struct spi_device *spi)
-{
-	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
-
-	return 0;
-}
-
-static struct spi_driver ad9951_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = ad9951_probe,
-	.remove = __devexit_p(ad9951_remove),
-};
-module_spi_driver(ad9951_driver);
-
-MODULE_AUTHOR("Cliff Cai");
-MODULE_DESCRIPTION("Analog Devices ad9951 driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/dds/dds.h b/drivers/staging/iio/dds/dds.h
deleted file mode 100644
index d8ac3a9..0000000
--- a/drivers/staging/iio/dds/dds.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * dds.h - sysfs attributes associated with DDS devices
- *
- * Copyright (c) 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-/**
- * /sys/bus/iio/devices/.../ddsX_freqY
- */
-
-#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr)	\
-	IIO_DEVICE_ATTR(dds##_channel##_freq##_num,			\
-			_mode, _show, _store, _addr)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_freqY_scale
- */
-
-#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string)			\
-	IIO_CONST_ATTR(dds##_channel##_freq_scale, _string)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_freqsymbol
- */
-
-#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr)	\
-	IIO_DEVICE_ATTR(dds##_channel##_freqsymbol,			\
-			_mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_phaseY
- */
-
-#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr)	\
-	IIO_DEVICE_ATTR(dds##_channel##_phase##_num,			\
-			_mode, _show, _store, _addr)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_phaseY_scale
- */
-
-#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string)			\
-	IIO_CONST_ATTR(dds##_channel##_phase_scale, _string)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_phasesymbol
- */
-
-#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr)	\
-	IIO_DEVICE_ATTR(dds##_channel##_phasesymbol,			\
-			_mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_pincontrol_en
- */
-
-#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\
-	IIO_DEVICE_ATTR(dds##_channel##_pincontrol_en,			\
-			_mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en
- */
-
-#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\
-	IIO_DEVICE_ATTR(dds##_channel##_pincontrol_freq_en,		\
-			_mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en
- */
-
-#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\
-	IIO_DEVICE_ATTR(dds##_channel##_pincontrol_phase_en,		\
-			_mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_out_enable
- */
-
-#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr)	\
-	IIO_DEVICE_ATTR(dds##_channel##_out_enable,			\
-			_mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_outY_enable
- */
-
-#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output,			\
-			_mode, _show, _store, _addr)			\
-	IIO_DEVICE_ATTR(dds##_channel##_out##_output##_enable,		\
-			_mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_outY_wavetype
- */
-
-#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr)	\
-	IIO_DEVICE_ATTR(dds##_channel##_out##_output##_wavetype,	\
-			S_IWUSR, NULL, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_outY_wavetype_available
- */
-
-#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\
-	IIO_CONST_ATTR(dds##_channel##_out##_output##_wavetype_available,\
-			_modes);
diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h
deleted file mode 100644
index c25f0e3..0000000
--- a/drivers/staging/iio/events.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* The industrial I/O - event passing to userspace
- *
- * Copyright (c) 2008-2011 Jonathan Cameron
- *
- * 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 _IIO_EVENTS_H_
-#define _IIO_EVENTS_H_
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-#include "types.h"
-
-/**
- * struct iio_event_data - The actual event being pushed to userspace
- * @id:		event identifier
- * @timestamp:	best estimate of time of event occurrence (often from
- *		the interrupt handler)
- */
-struct iio_event_data {
-	__u64	id;
-	__s64	timestamp;
-};
-
-#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int)
-
-enum iio_event_type {
-	IIO_EV_TYPE_THRESH,
-	IIO_EV_TYPE_MAG,
-	IIO_EV_TYPE_ROC,
-	IIO_EV_TYPE_THRESH_ADAPTIVE,
-	IIO_EV_TYPE_MAG_ADAPTIVE,
-};
-
-enum iio_event_direction {
-	IIO_EV_DIR_EITHER,
-	IIO_EV_DIR_RISING,
-	IIO_EV_DIR_FALLING,
-};
-
-/**
- * IIO_EVENT_CODE() - create event identifier
- * @chan_type:	Type of the channel. Should be one of enum iio_chan_type.
- * @diff:	Whether the event is for an differential channel or not.
- * @modifier:	Modifier for the channel. Should be one of enum iio_modifier.
- * @direction:	Direction of the event. One of enum iio_event_direction.
- * @type:	Type of the event. Should be one enum iio_event_type.
- * @chan:	Channel number for non-differential channels.
- * @chan1:	First channel number for differential channels.
- * @chan2:	Second channel number for differential channels.
- */
-
-#define IIO_EVENT_CODE(chan_type, diff, modifier, direction,		\
-		       type, chan, chan1, chan2)			\
-	(((u64)type << 56) | ((u64)diff << 55) |			\
-	 ((u64)direction << 48) | ((u64)modifier << 40) |		\
-	 ((u64)chan_type << 32) | (((u16)chan2) << 16) | ((u16)chan1) | \
-	 ((u16)chan))
-
-
-#define IIO_EV_DIR_MAX 4
-#define IIO_EV_BIT(type, direction)			\
-	(1 << (type*IIO_EV_DIR_MAX + direction))
-
-/**
- * IIO_MOD_EVENT_CODE() - create event identifier for modified channels
- * @chan_type:	Type of the channel. Should be one of enum iio_chan_type.
- * @number:	Channel number.
- * @modifier:	Modifier for the channel. Should be one of enum iio_modifier.
- * @type:	Type of the event. Should be one enum iio_event_type.
- * @direction:	Direction of the event. One of enum iio_event_direction.
- */
-
-#define IIO_MOD_EVENT_CODE(chan_type, number, modifier,		\
-			   type, direction)				\
-	IIO_EVENT_CODE(chan_type, 0, modifier, direction, type, number, 0, 0)
-
-/**
- * IIO_UNMOD_EVENT_CODE() - create event identifier for unmodified channels
- * @chan_type:	Type of the channel. Should be one of enum iio_chan_type.
- * @number:	Channel number.
- * @type:	Type of the event. Should be one enum iio_event_type.
- * @direction:	Direction of the event. One of enum iio_event_direction.
- */
-
-#define IIO_UNMOD_EVENT_CODE(chan_type, number, type, direction)	\
-	IIO_EVENT_CODE(chan_type, 0, 0, direction, type, number, 0, 0)
-
-#define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF)
-
-#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0xCF)
-
-#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF)
-
-/* Event code number extraction depends on which type of event we have.
- * Perhaps review this function in the future*/
-#define IIO_EVENT_CODE_EXTRACT_CHAN(mask) ((__s16)(mask & 0xFFFF))
-#define IIO_EVENT_CODE_EXTRACT_CHAN2(mask) ((__s16)(((mask) >> 16) & 0xFFFF))
-
-#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF)
-#define IIO_EVENT_CODE_EXTRACT_DIFF(mask) (((mask) >> 55) & 0x1)
-
-#endif
diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/frequency/Kconfig
similarity index 100%
rename from drivers/staging/iio/dds/Kconfig
rename to drivers/staging/iio/frequency/Kconfig
diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/frequency/Makefile
similarity index 100%
rename from drivers/staging/iio/dds/Makefile
rename to drivers/staging/iio/frequency/Makefile
diff --git a/drivers/staging/iio/frequency/ad5930.c b/drivers/staging/iio/frequency/ad5930.c
new file mode 100644
index 0000000..2d541d0
--- /dev/null
+++ b/drivers/staging/iio/frequency/ad5930.c
@@ -0,0 +1,151 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad5930
+ *
+ * Copyright (c) 2010-2010 Analog Devices 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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DRV_NAME "ad5930"
+
+#define value_mask (u16)0xf000
+#define addr_shift 12
+
+/* Register format: 4 bits addr + 12 bits value */
+struct ad5903_config {
+	u16 control;
+	u16 incnum;
+	u16 frqdelt[2];
+	u16 incitvl;
+	u16 buritvl;
+	u16 strtfrq[2];
+};
+
+struct ad5930_state {
+	struct mutex lock;
+	struct spi_device *sdev;
+};
+
+static ssize_t ad5930_set_parameter(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf,
+					size_t len)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer;
+	int ret;
+	struct ad5903_config *config = (struct ad5903_config *)buf;
+	struct iio_dev *idev = dev_to_iio_dev(dev);
+	struct ad5930_state *st = iio_priv(idev);
+
+	config->control = (config->control & ~value_mask);
+	config->incnum = (config->control & ~value_mask) | (1 << addr_shift);
+	config->frqdelt[0] = (config->control & ~value_mask) | (2 << addr_shift);
+	config->frqdelt[1] = (config->control & ~value_mask) | 3 << addr_shift;
+	config->incitvl = (config->control & ~value_mask) | 4 << addr_shift;
+	config->buritvl = (config->control & ~value_mask) | 8 << addr_shift;
+	config->strtfrq[0] = (config->control & ~value_mask) | 0xc << addr_shift;
+	config->strtfrq[1] = (config->control & ~value_mask) | 0xd << addr_shift;
+
+	xfer.len = len;
+	xfer.tx_buf = config;
+	mutex_lock(&st->lock);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+error_ret:
+	mutex_unlock(&st->lock);
+
+	return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0);
+
+static struct attribute *ad5930_attributes[] = {
+	&iio_dev_attr_dds.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad5930_attribute_group = {
+	.attrs = ad5930_attributes,
+};
+
+static const struct iio_info ad5930_info = {
+	.attrs = &ad5930_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad5930_probe(struct spi_device *spi)
+{
+	struct ad5930_state *st;
+	struct iio_dev *idev;
+	int ret = 0;
+
+	idev = iio_device_alloc(sizeof(*st));
+	if (idev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	spi_set_drvdata(spi, idev);
+	st = iio_priv(idev);
+
+	mutex_init(&st->lock);
+	st->sdev = spi;
+	idev->dev.parent = &spi->dev;
+	idev->info = &ad5930_info;
+	idev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_device_register(idev);
+	if (ret)
+		goto error_free_dev;
+	spi->max_speed_hz = 2000000;
+	spi->mode = SPI_MODE_3;
+	spi->bits_per_word = 16;
+	spi_setup(spi);
+
+	return 0;
+
+error_free_dev:
+	iio_device_free(idev);
+error_ret:
+	return ret;
+}
+
+static int __devexit ad5930_remove(struct spi_device *spi)
+{
+	iio_device_unregister(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
+
+	return 0;
+}
+
+static struct spi_driver ad5930_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = ad5930_probe,
+	.remove = __devexit_p(ad5930_remove),
+};
+module_spi_driver(ad5930_driver);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad5930 driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
new file mode 100644
index 0000000..fed3940
--- /dev/null
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -0,0 +1,362 @@
+/*
+ * AD9832 SPI DDS driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <asm/div64.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include "dds.h"
+
+#include "ad9832.h"
+
+static unsigned long ad9832_calc_freqreg(unsigned long mclk, unsigned long fout)
+{
+	unsigned long long freqreg = (u64) fout *
+				     (u64) ((u64) 1L << AD9832_FREQ_BITS);
+	do_div(freqreg, mclk);
+	return freqreg;
+}
+
+static int ad9832_write_frequency(struct ad9832_state *st,
+				  unsigned addr, unsigned long fout)
+{
+	unsigned long regval;
+
+	if (fout > (st->mclk / 2))
+		return -EINVAL;
+
+	regval = ad9832_calc_freqreg(st->mclk, fout);
+
+	st->freq_data[0] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
+					(addr << ADD_SHIFT) |
+					((regval >> 24) & 0xFF));
+	st->freq_data[1] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) |
+					((addr - 1) << ADD_SHIFT) |
+					((regval >> 16) & 0xFF));
+	st->freq_data[2] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
+					((addr - 2) << ADD_SHIFT) |
+					((regval >> 8) & 0xFF));
+	st->freq_data[3] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) |
+					((addr - 3) << ADD_SHIFT) |
+					((regval >> 0) & 0xFF));
+
+	return spi_sync(st->spi, &st->freq_msg);
+}
+
+static int ad9832_write_phase(struct ad9832_state *st,
+				  unsigned long addr, unsigned long phase)
+{
+	if (phase > (1 << AD9832_PHASE_BITS))
+		return -EINVAL;
+
+	st->phase_data[0] = cpu_to_be16((AD9832_CMD_PHA8BITSW << CMD_SHIFT) |
+					(addr << ADD_SHIFT) |
+					((phase >> 8) & 0xFF));
+	st->phase_data[1] = cpu_to_be16((AD9832_CMD_PHA16BITSW << CMD_SHIFT) |
+					((addr - 1) << ADD_SHIFT) |
+					(phase & 0xFF));
+
+	return spi_sync(st->spi, &st->phase_msg);
+}
+
+static ssize_t ad9832_write(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ad9832_state *st = iio_priv(indio_dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int ret;
+	long val;
+
+	ret = strict_strtoul(buf, 10, &val);
+	if (ret)
+		goto error_ret;
+
+	mutex_lock(&indio_dev->mlock);
+	switch ((u32) this_attr->address) {
+	case AD9832_FREQ0HM:
+	case AD9832_FREQ1HM:
+		ret = ad9832_write_frequency(st, this_attr->address, val);
+		break;
+	case AD9832_PHASE0H:
+	case AD9832_PHASE1H:
+	case AD9832_PHASE2H:
+	case AD9832_PHASE3H:
+		ret = ad9832_write_phase(st, this_attr->address, val);
+		break;
+	case AD9832_PINCTRL_EN:
+		if (val)
+			st->ctrl_ss &= ~AD9832_SELSRC;
+		else
+			st->ctrl_ss |= AD9832_SELSRC;
+		st->data = cpu_to_be16((AD9832_CMD_SYNCSELSRC << CMD_SHIFT) |
+					st->ctrl_ss);
+		ret = spi_sync(st->spi, &st->msg);
+		break;
+	case AD9832_FREQ_SYM:
+		if (val == 1)
+			st->ctrl_fp |= AD9832_FREQ;
+		else if (val == 0)
+			st->ctrl_fp &= ~AD9832_FREQ;
+		else {
+			ret = -EINVAL;
+			break;
+		}
+		st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) |
+					st->ctrl_fp);
+		ret = spi_sync(st->spi, &st->msg);
+		break;
+	case AD9832_PHASE_SYM:
+		if (val < 0 || val > 3) {
+			ret = -EINVAL;
+			break;
+		}
+
+		st->ctrl_fp &= ~AD9832_PHASE(3);
+		st->ctrl_fp |= AD9832_PHASE(val);
+
+		st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) |
+					st->ctrl_fp);
+		ret = spi_sync(st->spi, &st->msg);
+		break;
+	case AD9832_OUTPUT_EN:
+		if (val)
+			st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP |
+					AD9832_CLR);
+		else
+			st->ctrl_src |= AD9832_RESET;
+
+		st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
+					st->ctrl_src);
+		ret = spi_sync(st->spi, &st->msg);
+		break;
+	default:
+		ret = -ENODEV;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+error_ret:
+	return ret ? ret : len;
+}
+
+/**
+ * see dds.h for further information
+ */
+
+static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ0HM);
+static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_FREQ1HM);
+static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ_SYM);
+static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
+
+static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_PHASE0H);
+static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_PHASE1H);
+static IIO_DEV_ATTR_PHASE(0, 2, S_IWUSR, NULL, ad9832_write, AD9832_PHASE2H);
+static IIO_DEV_ATTR_PHASE(0, 3, S_IWUSR, NULL, ad9832_write, AD9832_PHASE3H);
+static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL,
+				ad9832_write, AD9832_PHASE_SYM);
+static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
+
+static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL,
+				ad9832_write, AD9832_PINCTRL_EN);
+static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL,
+				ad9832_write, AD9832_OUTPUT_EN);
+
+static struct attribute *ad9832_attributes[] = {
+	&iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr,
+	&iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phase2.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phase3.dev_attr.attr,
+	&iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_pincontrol_en.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad9832_attribute_group = {
+	.attrs = ad9832_attributes,
+};
+
+static const struct iio_info ad9832_info = {
+	.attrs = &ad9832_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad9832_probe(struct spi_device *spi)
+{
+	struct ad9832_platform_data *pdata = spi->dev.platform_data;
+	struct iio_dev *indio_dev;
+	struct ad9832_state *st;
+	struct regulator *reg;
+	int ret;
+
+	if (!pdata) {
+		dev_dbg(&spi->dev, "no platform data?\n");
+		return -ENODEV;
+	}
+
+	reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(reg)) {
+		ret = regulator_enable(reg);
+		if (ret)
+			goto error_put_reg;
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_disable_reg;
+	}
+	spi_set_drvdata(spi, indio_dev);
+	st = iio_priv(indio_dev);
+	st->reg = reg;
+	st->mclk = pdata->mclk;
+	st->spi = spi;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad9832_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	/* Setup default messages */
+
+	st->xfer.tx_buf = &st->data;
+	st->xfer.len = 2;
+
+	spi_message_init(&st->msg);
+	spi_message_add_tail(&st->xfer, &st->msg);
+
+	st->freq_xfer[0].tx_buf = &st->freq_data[0];
+	st->freq_xfer[0].len = 2;
+	st->freq_xfer[0].cs_change = 1;
+	st->freq_xfer[1].tx_buf = &st->freq_data[1];
+	st->freq_xfer[1].len = 2;
+	st->freq_xfer[1].cs_change = 1;
+	st->freq_xfer[2].tx_buf = &st->freq_data[2];
+	st->freq_xfer[2].len = 2;
+	st->freq_xfer[2].cs_change = 1;
+	st->freq_xfer[3].tx_buf = &st->freq_data[3];
+	st->freq_xfer[3].len = 2;
+
+	spi_message_init(&st->freq_msg);
+	spi_message_add_tail(&st->freq_xfer[0], &st->freq_msg);
+	spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg);
+	spi_message_add_tail(&st->freq_xfer[2], &st->freq_msg);
+	spi_message_add_tail(&st->freq_xfer[3], &st->freq_msg);
+
+	st->phase_xfer[0].tx_buf = &st->phase_data[0];
+	st->phase_xfer[0].len = 2;
+	st->phase_xfer[0].cs_change = 1;
+	st->phase_xfer[1].tx_buf = &st->phase_data[1];
+	st->phase_xfer[1].len = 2;
+
+	spi_message_init(&st->phase_msg);
+	spi_message_add_tail(&st->phase_xfer[0], &st->phase_msg);
+	spi_message_add_tail(&st->phase_xfer[1], &st->phase_msg);
+
+	st->ctrl_src = AD9832_SLEEP | AD9832_RESET | AD9832_CLR;
+	st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
+					st->ctrl_src);
+	ret = spi_sync(st->spi, &st->msg);
+	if (ret) {
+		dev_err(&spi->dev, "device init failed\n");
+		goto error_free_device;
+	}
+
+	ret = ad9832_write_frequency(st, AD9832_FREQ0HM, pdata->freq0);
+	if (ret)
+		goto error_free_device;
+
+	ret = ad9832_write_frequency(st, AD9832_FREQ1HM, pdata->freq1);
+	if (ret)
+		goto error_free_device;
+
+	ret = ad9832_write_phase(st, AD9832_PHASE0H, pdata->phase0);
+	if (ret)
+		goto error_free_device;
+
+	ret = ad9832_write_phase(st, AD9832_PHASE1H, pdata->phase1);
+	if (ret)
+		goto error_free_device;
+
+	ret = ad9832_write_phase(st, AD9832_PHASE2H, pdata->phase2);
+	if (ret)
+		goto error_free_device;
+
+	ret = ad9832_write_phase(st, AD9832_PHASE3H, pdata->phase3);
+	if (ret)
+		goto error_free_device;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_free_device;
+
+	return 0;
+
+error_free_device:
+	iio_device_free(indio_dev);
+error_disable_reg:
+	if (!IS_ERR(reg))
+		regulator_disable(reg);
+error_put_reg:
+	if (!IS_ERR(reg))
+		regulator_put(reg);
+
+	return ret;
+}
+
+static int __devexit ad9832_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad9832_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad9832_id[] = {
+	{"ad9832", 0},
+	{"ad9835", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad9832_id);
+
+static struct spi_driver ad9832_driver = {
+	.driver = {
+		.name	= "ad9832",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad9832_probe,
+	.remove		= __devexit_p(ad9832_remove),
+	.id_table	= ad9832_id,
+};
+module_spi_driver(ad9832_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD9832/AD9835 DDS");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9832.h b/drivers/staging/iio/frequency/ad9832.h
similarity index 100%
rename from drivers/staging/iio/dds/ad9832.h
rename to drivers/staging/iio/frequency/ad9832.h
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
new file mode 100644
index 0000000..1b2dc74
--- /dev/null
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -0,0 +1,464 @@
+/*
+ * AD9833/AD9834/AD9837/AD9838 SPI DDS driver
+ *
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <asm/div64.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include "dds.h"
+
+#include "ad9834.h"
+
+static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout)
+{
+	unsigned long long freqreg = (u64) fout * (u64) (1 << AD9834_FREQ_BITS);
+	do_div(freqreg, mclk);
+	return freqreg;
+}
+
+static int ad9834_write_frequency(struct ad9834_state *st,
+				  unsigned long addr, unsigned long fout)
+{
+	unsigned long regval;
+
+	if (fout > (st->mclk / 2))
+		return -EINVAL;
+
+	regval = ad9834_calc_freqreg(st->mclk, fout);
+
+	st->freq_data[0] = cpu_to_be16(addr | (regval &
+				       RES_MASK(AD9834_FREQ_BITS / 2)));
+	st->freq_data[1] = cpu_to_be16(addr | ((regval >>
+				       (AD9834_FREQ_BITS / 2)) &
+				       RES_MASK(AD9834_FREQ_BITS / 2)));
+
+	return spi_sync(st->spi, &st->freq_msg);
+}
+
+static int ad9834_write_phase(struct ad9834_state *st,
+				  unsigned long addr, unsigned long phase)
+{
+	if (phase > (1 << AD9834_PHASE_BITS))
+		return -EINVAL;
+	st->data = cpu_to_be16(addr | phase);
+
+	return spi_sync(st->spi, &st->msg);
+}
+
+static ssize_t ad9834_write(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ad9834_state *st = iio_priv(indio_dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int ret;
+	long val;
+
+	ret = strict_strtoul(buf, 10, &val);
+	if (ret)
+		goto error_ret;
+
+	mutex_lock(&indio_dev->mlock);
+	switch ((u32) this_attr->address) {
+	case AD9834_REG_FREQ0:
+	case AD9834_REG_FREQ1:
+		ret = ad9834_write_frequency(st, this_attr->address, val);
+		break;
+	case AD9834_REG_PHASE0:
+	case AD9834_REG_PHASE1:
+		ret = ad9834_write_phase(st, this_attr->address, val);
+		break;
+	case AD9834_OPBITEN:
+		if (st->control & AD9834_MODE) {
+			ret = -EINVAL;  /* AD9843 reserved mode */
+			break;
+		}
+
+		if (val)
+			st->control |= AD9834_OPBITEN;
+		else
+			st->control &= ~AD9834_OPBITEN;
+
+		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+		ret = spi_sync(st->spi, &st->msg);
+		break;
+	case AD9834_PIN_SW:
+		if (val)
+			st->control |= AD9834_PIN_SW;
+		else
+			st->control &= ~AD9834_PIN_SW;
+		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+		ret = spi_sync(st->spi, &st->msg);
+		break;
+	case AD9834_FSEL:
+	case AD9834_PSEL:
+		if (val == 0)
+			st->control &= ~(this_attr->address | AD9834_PIN_SW);
+		else if (val == 1) {
+			st->control |= this_attr->address;
+			st->control &= ~AD9834_PIN_SW;
+		} else {
+			ret = -EINVAL;
+			break;
+		}
+		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+		ret = spi_sync(st->spi, &st->msg);
+		break;
+	case AD9834_RESET:
+		if (val)
+			st->control &= ~AD9834_RESET;
+		else
+			st->control |= AD9834_RESET;
+
+		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+		ret = spi_sync(st->spi, &st->msg);
+		break;
+	default:
+		ret = -ENODEV;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+error_ret:
+	return ret ? ret : len;
+}
+
+static ssize_t ad9834_store_wavetype(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf,
+				 size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ad9834_state *st = iio_priv(indio_dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int ret = 0;
+	bool is_ad9833_7 = (st->devid == ID_AD9833) || (st->devid == ID_AD9837);
+
+	mutex_lock(&indio_dev->mlock);
+
+	switch ((u32) this_attr->address) {
+	case 0:
+		if (sysfs_streq(buf, "sine")) {
+			st->control &= ~AD9834_MODE;
+			if (is_ad9833_7)
+				st->control &= ~AD9834_OPBITEN;
+		} else if (sysfs_streq(buf, "triangle")) {
+			if (is_ad9833_7) {
+				st->control &= ~AD9834_OPBITEN;
+				st->control |= AD9834_MODE;
+			} else if (st->control & AD9834_OPBITEN) {
+				ret = -EINVAL;	/* AD9843 reserved mode */
+			} else {
+				st->control |= AD9834_MODE;
+			}
+		} else if (is_ad9833_7 && sysfs_streq(buf, "square")) {
+			st->control &= ~AD9834_MODE;
+			st->control |= AD9834_OPBITEN;
+		} else {
+			ret = -EINVAL;
+		}
+
+		break;
+	case 1:
+		if (sysfs_streq(buf, "square") &&
+			!(st->control & AD9834_MODE)) {
+			st->control &= ~AD9834_MODE;
+			st->control |= AD9834_OPBITEN;
+		} else {
+			ret = -EINVAL;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (!ret) {
+		st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+		ret = spi_sync(st->spi, &st->msg);
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+static ssize_t ad9834_show_out0_wavetype_available(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ad9834_state *st = iio_priv(indio_dev);
+	char *str;
+
+	if ((st->devid == ID_AD9833) || (st->devid == ID_AD9837))
+		str = "sine triangle square";
+	else if (st->control & AD9834_OPBITEN)
+		str = "sine";
+	else
+		str = "sine triangle";
+
+	return sprintf(buf, "%s\n", str);
+}
+
+
+static IIO_DEVICE_ATTR(out_altvoltage0_out0_wavetype_available, S_IRUGO,
+		       ad9834_show_out0_wavetype_available, NULL, 0);
+
+static ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ad9834_state *st = iio_priv(indio_dev);
+	char *str;
+
+	if (st->control & AD9834_MODE)
+		str = "";
+	else
+		str = "square";
+
+	return sprintf(buf, "%s\n", str);
+}
+
+static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, S_IRUGO,
+		       ad9834_show_out1_wavetype_available, NULL, 0);
+
+/**
+ * see dds.h for further information
+ */
+
+static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ0);
+static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ1);
+static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_FSEL);
+static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
+
+static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE0);
+static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE1);
+static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_PSEL);
+static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
+
+static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL,
+	ad9834_write, AD9834_PIN_SW);
+static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, ad9834_write, AD9834_RESET);
+static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, S_IWUSR, NULL,
+	ad9834_write, AD9834_OPBITEN);
+static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0);
+static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1);
+
+static struct attribute *ad9834_attributes[] = {
+	&iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr,
+	&iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr,
+	&iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_pincontrol_en.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out1_enable.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out0_wavetype.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out1_wavetype.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out0_wavetype_available.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out1_wavetype_available.dev_attr.attr,
+	NULL,
+};
+
+static struct attribute *ad9833_attributes[] = {
+	&iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr,
+	&iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr,
+	&iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out0_wavetype.dev_attr.attr,
+	&iio_dev_attr_out_altvoltage0_out0_wavetype_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad9834_attribute_group = {
+	.attrs = ad9834_attributes,
+};
+
+static const struct attribute_group ad9833_attribute_group = {
+	.attrs = ad9833_attributes,
+};
+
+static const struct iio_info ad9834_info = {
+	.attrs = &ad9834_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_info ad9833_info = {
+	.attrs = &ad9833_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad9834_probe(struct spi_device *spi)
+{
+	struct ad9834_platform_data *pdata = spi->dev.platform_data;
+	struct ad9834_state *st;
+	struct iio_dev *indio_dev;
+	struct regulator *reg;
+	int ret;
+
+	if (!pdata) {
+		dev_dbg(&spi->dev, "no platform data?\n");
+		return -ENODEV;
+	}
+
+	reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(reg)) {
+		ret = regulator_enable(reg);
+		if (ret)
+			goto error_put_reg;
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_disable_reg;
+	}
+	spi_set_drvdata(spi, indio_dev);
+	st = iio_priv(indio_dev);
+	st->mclk = pdata->mclk;
+	st->spi = spi;
+	st->devid = spi_get_device_id(spi)->driver_data;
+	st->reg = reg;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	switch (st->devid) {
+	case ID_AD9833:
+	case ID_AD9837:
+		indio_dev->info = &ad9833_info;
+		break;
+	default:
+		indio_dev->info = &ad9834_info;
+		break;
+	}
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	/* Setup default messages */
+
+	st->xfer.tx_buf = &st->data;
+	st->xfer.len = 2;
+
+	spi_message_init(&st->msg);
+	spi_message_add_tail(&st->xfer, &st->msg);
+
+	st->freq_xfer[0].tx_buf = &st->freq_data[0];
+	st->freq_xfer[0].len = 2;
+	st->freq_xfer[0].cs_change = 1;
+	st->freq_xfer[1].tx_buf = &st->freq_data[1];
+	st->freq_xfer[1].len = 2;
+
+	spi_message_init(&st->freq_msg);
+	spi_message_add_tail(&st->freq_xfer[0], &st->freq_msg);
+	spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg);
+
+	st->control = AD9834_B28 | AD9834_RESET;
+
+	if (!pdata->en_div2)
+		st->control |= AD9834_DIV2;
+
+	if (!pdata->en_signbit_msb_out && (st->devid == ID_AD9834))
+		st->control |= AD9834_SIGN_PIB;
+
+	st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+	ret = spi_sync(st->spi, &st->msg);
+	if (ret) {
+		dev_err(&spi->dev, "device init failed\n");
+		goto error_free_device;
+	}
+
+	ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0);
+	if (ret)
+		goto error_free_device;
+
+	ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1);
+	if (ret)
+		goto error_free_device;
+
+	ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0);
+	if (ret)
+		goto error_free_device;
+
+	ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1);
+	if (ret)
+		goto error_free_device;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_free_device;
+
+	return 0;
+
+error_free_device:
+	iio_device_free(indio_dev);
+error_disable_reg:
+	if (!IS_ERR(reg))
+		regulator_disable(reg);
+error_put_reg:
+	if (!IS_ERR(reg))
+		regulator_put(reg);
+	return ret;
+}
+
+static int __devexit ad9834_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad9834_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad9834_id[] = {
+	{"ad9833", ID_AD9833},
+	{"ad9834", ID_AD9834},
+	{"ad9837", ID_AD9837},
+	{"ad9838", ID_AD9838},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad9834_id);
+
+static struct spi_driver ad9834_driver = {
+	.driver = {
+		.name	= "ad9834",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad9834_probe,
+	.remove		= __devexit_p(ad9834_remove),
+	.id_table	= ad9834_id,
+};
+module_spi_driver(ad9834_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD9833/AD9834/AD9837/AD9838 DDS");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9834.h b/drivers/staging/iio/frequency/ad9834.h
similarity index 100%
rename from drivers/staging/iio/dds/ad9834.h
rename to drivers/staging/iio/frequency/ad9834.h
diff --git a/drivers/staging/iio/frequency/ad9850.c b/drivers/staging/iio/frequency/ad9850.c
new file mode 100644
index 0000000..74abee0
--- /dev/null
+++ b/drivers/staging/iio/frequency/ad9850.c
@@ -0,0 +1,137 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9850
+ *
+ * Copyright (c) 2010-2010 Analog Devices 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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DRV_NAME "ad9850"
+
+#define value_mask (u16)0xf000
+#define addr_shift 12
+
+/* Register format: 4 bits addr + 12 bits value */
+struct ad9850_config {
+	u8 control[5];
+};
+
+struct ad9850_state {
+	struct mutex lock;
+	struct spi_device *sdev;
+};
+
+static ssize_t ad9850_set_parameter(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf,
+					size_t len)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer;
+	int ret;
+	struct ad9850_config *config = (struct ad9850_config *)buf;
+	struct iio_dev *idev = dev_to_iio_dev(dev);
+	struct ad9850_state *st = iio_priv(idev);
+
+	xfer.len = len;
+	xfer.tx_buf = config;
+	mutex_lock(&st->lock);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+error_ret:
+	mutex_unlock(&st->lock);
+
+	return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9850_set_parameter, 0);
+
+static struct attribute *ad9850_attributes[] = {
+	&iio_dev_attr_dds.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad9850_attribute_group = {
+	.attrs = ad9850_attributes,
+};
+
+static const struct iio_info ad9850_info = {
+	.attrs = &ad9850_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad9850_probe(struct spi_device *spi)
+{
+	struct ad9850_state *st;
+	struct iio_dev *idev;
+	int ret = 0;
+
+	idev = iio_device_alloc(sizeof(*st));
+	if (idev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	spi_set_drvdata(spi, idev);
+	st = iio_priv(idev);
+	mutex_init(&st->lock);
+	st->sdev = spi;
+
+	idev->dev.parent = &spi->dev;
+	idev->info = &ad9850_info;
+	idev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_device_register(idev);
+	if (ret)
+		goto error_free_dev;
+	spi->max_speed_hz = 2000000;
+	spi->mode = SPI_MODE_3;
+	spi->bits_per_word = 16;
+	spi_setup(spi);
+
+	return 0;
+
+error_free_dev:
+	iio_device_free(idev);
+error_ret:
+	return ret;
+}
+
+static int __devexit ad9850_remove(struct spi_device *spi)
+{
+	iio_device_unregister(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
+
+	return 0;
+}
+
+static struct spi_driver ad9850_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = ad9850_probe,
+	.remove = __devexit_p(ad9850_remove),
+};
+module_spi_driver(ad9850_driver);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9850 driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/frequency/ad9852.c b/drivers/staging/iio/frequency/ad9852.c
new file mode 100644
index 0000000..fd9d14a
--- /dev/null
+++ b/drivers/staging/iio/frequency/ad9852.c
@@ -0,0 +1,288 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9852
+ *
+ * Copyright (c) 2010 Analog Devices 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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DRV_NAME "ad9852"
+
+#define addr_phaad1 0x0
+#define addr_phaad2 0x1
+#define addr_fretu1 0x2
+#define addr_fretu2 0x3
+#define addr_delfre 0x4
+#define addr_updclk 0x5
+#define addr_ramclk 0x6
+#define addr_contrl 0x7
+#define addr_optskm 0x8
+#define addr_optskr 0xa
+#define addr_dacctl 0xb
+
+#define COMPPD		(1 << 4)
+#define REFMULT2	(1 << 2)
+#define BYPPLL		(1 << 5)
+#define PLLRANG		(1 << 6)
+#define IEUPCLK		(1)
+#define OSKEN		(1 << 5)
+
+#define read_bit	(1 << 7)
+
+/* Register format: 1 byte addr + value */
+struct ad9852_config {
+	u8 phajst0[3];
+	u8 phajst1[3];
+	u8 fretun1[6];
+	u8 fretun2[6];
+	u8 dltafre[6];
+	u8 updtclk[5];
+	u8 ramprat[4];
+	u8 control[5];
+	u8 outpskm[3];
+	u8 outpskr[2];
+	u8 daccntl[3];
+};
+
+struct ad9852_state {
+	struct mutex lock;
+	struct spi_device *sdev;
+};
+
+static ssize_t ad9852_set_parameter(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf,
+					size_t len)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer;
+	int ret;
+	struct ad9852_config *config = (struct ad9852_config *)buf;
+	struct iio_dev *idev = dev_to_iio_dev(dev);
+	struct ad9852_state *st = iio_priv(idev);
+
+	xfer.len = 3;
+	xfer.tx_buf = &config->phajst0[0];
+	mutex_lock(&st->lock);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 3;
+	xfer.tx_buf = &config->phajst1[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 6;
+	xfer.tx_buf = &config->fretun1[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 6;
+	xfer.tx_buf = &config->fretun2[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 6;
+	xfer.tx_buf = &config->dltafre[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 5;
+	xfer.tx_buf = &config->updtclk[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 4;
+	xfer.tx_buf = &config->ramprat[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 5;
+	xfer.tx_buf = &config->control[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 3;
+	xfer.tx_buf = &config->outpskm[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 2;
+	xfer.tx_buf = &config->outpskr[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 3;
+	xfer.tx_buf = &config->daccntl[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+error_ret:
+	mutex_unlock(&st->lock);
+
+	return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0);
+
+static void ad9852_init(struct ad9852_state *st)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer;
+	int ret;
+	u8 config[5];
+
+	config[0] = addr_contrl;
+	config[1] = COMPPD;
+	config[2] = REFMULT2 | BYPPLL | PLLRANG;
+	config[3] = IEUPCLK;
+	config[4] = OSKEN;
+
+	mutex_lock(&st->lock);
+
+	xfer.len = 5;
+	xfer.tx_buf = &config;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+error_ret:
+	mutex_unlock(&st->lock);
+
+
+
+}
+
+static struct attribute *ad9852_attributes[] = {
+	&iio_dev_attr_dds.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad9852_attribute_group = {
+	.attrs = ad9852_attributes,
+};
+
+static const struct iio_info ad9852_info = {
+	.attrs = &ad9852_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad9852_probe(struct spi_device *spi)
+{
+	struct ad9852_state *st;
+	struct iio_dev *idev;
+	int ret = 0;
+
+	idev = iio_device_alloc(sizeof(*st));
+	if (idev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	st = iio_priv(idev);
+	spi_set_drvdata(spi, idev);
+	mutex_init(&st->lock);
+	st->sdev = spi;
+
+	idev->dev.parent = &spi->dev;
+	idev->info = &ad9852_info;
+	idev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_device_register(idev);
+	if (ret)
+		goto error_free_dev;
+	spi->max_speed_hz = 2000000;
+	spi->mode = SPI_MODE_3;
+	spi->bits_per_word = 8;
+	spi_setup(spi);
+	ad9852_init(st);
+
+	return 0;
+
+error_free_dev:
+	iio_device_free(idev);
+
+error_ret:
+	return ret;
+}
+
+static int __devexit ad9852_remove(struct spi_device *spi)
+{
+	iio_device_unregister(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
+
+	return 0;
+}
+
+static struct spi_driver ad9852_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = ad9852_probe,
+	.remove = __devexit_p(ad9852_remove),
+};
+module_spi_driver(ad9852_driver);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9852 driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/frequency/ad9910.c b/drivers/staging/iio/frequency/ad9910.c
new file mode 100644
index 0000000..5a7ba30
--- /dev/null
+++ b/drivers/staging/iio/frequency/ad9910.c
@@ -0,0 +1,421 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9910
+ *
+ * Copyright (c) 2010 Analog Devices 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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DRV_NAME "ad9910"
+
+#define CFR1 0x0
+#define CFR2 0x1
+#define CFR3 0x2
+
+#define AUXDAC 0x3
+#define IOUPD 0x4
+#define FTW 0x7
+#define POW 0x8
+#define ASF 0x9
+#define MULTC 0x0A
+#define DIG_RAMPL 0x0B
+#define DIG_RAMPS 0x0C
+#define DIG_RAMPR 0x0D
+#define SIN_TONEP0 0x0E
+#define SIN_TONEP1 0x0F
+#define SIN_TONEP2 0x10
+#define SIN_TONEP3 0x11
+#define SIN_TONEP4 0x12
+#define SIN_TONEP5 0x13
+#define SIN_TONEP6 0x14
+#define SIN_TONEP7 0x15
+
+#define RAM_ENABLE	(1 << 7)
+
+#define MANUAL_OSK	(1 << 7)
+#define INVSIC		(1 << 6)
+#define DDS_SINEOP	(1)
+
+#define AUTO_OSK	(1)
+#define OSKEN		(1 << 1)
+#define LOAD_ARR	(1 << 2)
+#define CLR_PHA		(1 << 3)
+#define CLR_DIG		(1 << 4)
+#define ACLR_PHA	(1 << 5)
+#define ACLR_DIG	(1 << 6)
+#define LOAD_LRR	(1 << 7)
+
+#define LSB_FST		(1)
+#define SDIO_IPT	(1 << 1)
+#define EXT_PWD		(1 << 3)
+#define ADAC_PWD	(1 << 4)
+#define REFCLK_PWD	(1 << 5)
+#define DAC_PWD		(1 << 6)
+#define DIG_PWD		(1 << 7)
+
+#define ENA_AMP		(1)
+#define READ_FTW	(1)
+#define DIGR_LOW	(1 << 1)
+#define DIGR_HIGH	(1 << 2)
+#define DIGR_ENA	(1 << 3)
+#define SYNCCLK_ENA	(1 << 6)
+#define ITER_IOUPD	(1 << 7)
+
+#define TX_ENA		(1 << 1)
+#define PDCLK_INV	(1 << 2)
+#define PDCLK_ENB	(1 << 3)
+
+#define PARA_ENA	(1 << 4)
+#define SYNC_DIS	(1 << 5)
+#define DATA_ASS	(1 << 6)
+#define MATCH_ENA	(1 << 7)
+
+#define PLL_ENA		(1)
+#define PFD_RST		(1 << 2)
+#define REFCLK_RST	(1 << 6)
+#define REFCLK_BYP	(1 << 7)
+
+/* Register format: 1 byte addr + value */
+struct ad9910_config {
+	u8 auxdac[5];
+	u8 ioupd[5];
+	u8 ftw[5];
+	u8 pow[3];
+	u8 asf[5];
+	u8 multc[5];
+	u8 dig_rampl[9];
+	u8 dig_ramps[9];
+	u8 dig_rampr[5];
+	u8 sin_tonep0[9];
+	u8 sin_tonep1[9];
+	u8 sin_tonep2[9];
+	u8 sin_tonep3[9];
+	u8 sin_tonep4[9];
+	u8 sin_tonep5[9];
+	u8 sin_tonep6[9];
+	u8 sin_tonep7[9];
+};
+
+struct ad9910_state {
+	struct mutex lock;
+	struct spi_device *sdev;
+};
+
+static ssize_t ad9910_set_parameter(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf,
+					size_t len)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer;
+	int ret;
+	struct ad9910_config *config = (struct ad9910_config *)buf;
+	struct iio_dev *idev = dev_to_iio_dev(dev);
+	struct ad9910_state *st = iio_priv(idev);
+
+	xfer.len = 5;
+	xfer.tx_buf = &config->auxdac[0];
+	mutex_lock(&st->lock);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 5;
+	xfer.tx_buf = &config->ioupd[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 5;
+	xfer.tx_buf = &config->ftw[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 3;
+	xfer.tx_buf = &config->pow[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 5;
+	xfer.tx_buf = &config->asf[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 5;
+	xfer.tx_buf = &config->multc[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 9;
+	xfer.tx_buf = &config->dig_rampl[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 9;
+	xfer.tx_buf = &config->dig_ramps[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 5;
+	xfer.tx_buf = &config->dig_rampr[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 9;
+	xfer.tx_buf = &config->sin_tonep0[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 9;
+	xfer.tx_buf = &config->sin_tonep1[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 9;
+	xfer.tx_buf = &config->sin_tonep2[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+	xfer.len = 9;
+	xfer.tx_buf = &config->sin_tonep3[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 9;
+	xfer.tx_buf = &config->sin_tonep4[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 9;
+	xfer.tx_buf = &config->sin_tonep5[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 9;
+	xfer.tx_buf = &config->sin_tonep6[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 9;
+	xfer.tx_buf = &config->sin_tonep7[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+error_ret:
+	mutex_unlock(&st->lock);
+
+	return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0);
+
+static void ad9910_init(struct ad9910_state *st)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer;
+	int ret;
+	u8 cfr[5];
+
+	cfr[0] = CFR1;
+	cfr[1] = 0;
+	cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP;
+	cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR;
+	cfr[4] = 0;
+
+	mutex_lock(&st->lock);
+
+	xfer.len = 5;
+	xfer.tx_buf = &cfr;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	cfr[0] = CFR2;
+	cfr[1] = ENA_AMP;
+	cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD;
+	cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB;
+	cfr[4] = PARA_ENA;
+
+	xfer.len = 5;
+	xfer.tx_buf = &cfr;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	cfr[0] = CFR3;
+	cfr[1] = PLL_ENA;
+	cfr[2] = 0;
+	cfr[3] = REFCLK_RST | REFCLK_BYP;
+	cfr[4] = 0;
+
+	xfer.len = 5;
+	xfer.tx_buf = &cfr;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+error_ret:
+	mutex_unlock(&st->lock);
+
+
+
+}
+
+static struct attribute *ad9910_attributes[] = {
+	&iio_dev_attr_dds.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad9910_attribute_group = {
+	.attrs = ad9910_attributes,
+};
+
+static const struct iio_info ad9910_info = {
+	.attrs = &ad9910_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad9910_probe(struct spi_device *spi)
+{
+	struct ad9910_state *st;
+	struct iio_dev *idev;
+	int ret = 0;
+
+	idev = iio_device_alloc(sizeof(*st));
+	if (idev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	spi_set_drvdata(spi, idev);
+	st = iio_priv(idev);
+	mutex_init(&st->lock);
+	st->sdev = spi;
+
+	idev->dev.parent = &spi->dev;
+	idev->info = &ad9910_info;
+	idev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_device_register(idev);
+	if (ret)
+		goto error_free_dev;
+	spi->max_speed_hz = 2000000;
+	spi->mode = SPI_MODE_3;
+	spi->bits_per_word = 8;
+	spi_setup(spi);
+	ad9910_init(st);
+	return 0;
+
+error_free_dev:
+	iio_device_free(idev);
+error_ret:
+	return ret;
+}
+
+static int __devexit ad9910_remove(struct spi_device *spi)
+{
+	iio_device_unregister(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
+
+	return 0;
+}
+
+static struct spi_driver ad9910_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = ad9910_probe,
+	.remove = __devexit_p(ad9910_remove),
+};
+module_spi_driver(ad9910_driver);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9910 driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/frequency/ad9951.c b/drivers/staging/iio/frequency/ad9951.c
new file mode 100644
index 0000000..ba6f49f
--- /dev/null
+++ b/drivers/staging/iio/frequency/ad9951.c
@@ -0,0 +1,232 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9951
+ *
+ * Copyright (c) 2010 Analog Devices 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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DRV_NAME "ad9951"
+
+#define CFR1 0x0
+#define CFR2 0x1
+
+#define AUTO_OSK	(1)
+#define OSKEN		(1 << 1)
+#define LOAD_ARR	(1 << 2)
+
+#define AUTO_SYNC	(1 << 7)
+
+#define LSB_FST		(1)
+#define SDIO_IPT	(1 << 1)
+#define CLR_PHA		(1 << 2)
+#define SINE_OPT	(1 << 4)
+#define ACLR_PHA	(1 << 5)
+
+#define VCO_RANGE	(1 << 2)
+
+#define CRS_OPT		(1 << 1)
+#define HMANU_SYNC	(1 << 2)
+#define HSPD_SYNC	(1 << 3)
+
+/* Register format: 1 byte addr + value */
+struct ad9951_config {
+	u8 asf[3];
+	u8 arr[2];
+	u8 ftw0[5];
+	u8 ftw1[3];
+};
+
+struct ad9951_state {
+	struct mutex lock;
+	struct spi_device *sdev;
+};
+
+static ssize_t ad9951_set_parameter(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf,
+					size_t len)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer;
+	int ret;
+	struct ad9951_config *config = (struct ad9951_config *)buf;
+	struct iio_dev *idev = dev_to_iio_dev(dev);
+	struct ad9951_state *st = iio_priv(idev);
+
+	xfer.len = 3;
+	xfer.tx_buf = &config->asf[0];
+	mutex_lock(&st->lock);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 2;
+	xfer.tx_buf = &config->arr[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 5;
+	xfer.tx_buf = &config->ftw0[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	xfer.len = 3;
+	xfer.tx_buf = &config->ftw1[0];
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+error_ret:
+	mutex_unlock(&st->lock);
+
+	return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0);
+
+static void ad9951_init(struct ad9951_state *st)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer;
+	int ret;
+	u8 cfr[5];
+
+	cfr[0] = CFR1;
+	cfr[1] = 0;
+	cfr[2] = LSB_FST | CLR_PHA | SINE_OPT | ACLR_PHA;
+	cfr[3] = AUTO_OSK | OSKEN | LOAD_ARR;
+	cfr[4] = 0;
+
+	mutex_lock(&st->lock);
+
+	xfer.len = 5;
+	xfer.tx_buf = &cfr;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+	cfr[0] = CFR2;
+	cfr[1] = VCO_RANGE;
+	cfr[2] = HSPD_SYNC;
+	cfr[3] = 0;
+
+	xfer.len = 4;
+	xfer.tx_buf = &cfr;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->sdev, &msg);
+	if (ret)
+		goto error_ret;
+
+error_ret:
+	mutex_unlock(&st->lock);
+
+
+
+}
+
+static struct attribute *ad9951_attributes[] = {
+	&iio_dev_attr_dds.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad9951_attribute_group = {
+	.attrs = ad9951_attributes,
+};
+
+static const struct iio_info ad9951_info = {
+	.attrs = &ad9951_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad9951_probe(struct spi_device *spi)
+{
+	struct ad9951_state *st;
+	struct iio_dev *idev;
+	int ret = 0;
+
+	idev = iio_device_alloc(sizeof(*st));
+	if (idev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	spi_set_drvdata(spi, idev);
+	st = iio_priv(idev);
+	mutex_init(&st->lock);
+	st->sdev = spi;
+
+	idev->dev.parent = &spi->dev;
+
+	idev->info = &ad9951_info;
+	idev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_device_register(idev);
+	if (ret)
+		goto error_free_dev;
+	spi->max_speed_hz = 2000000;
+	spi->mode = SPI_MODE_3;
+	spi->bits_per_word = 8;
+	spi_setup(spi);
+	ad9951_init(st);
+	return 0;
+
+error_free_dev:
+	iio_device_free(idev);
+
+error_ret:
+	return ret;
+}
+
+static int __devexit ad9951_remove(struct spi_device *spi)
+{
+	iio_device_unregister(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
+
+	return 0;
+}
+
+static struct spi_driver ad9951_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = ad9951_probe,
+	.remove = __devexit_p(ad9951_remove),
+};
+module_spi_driver(ad9951_driver);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9951 driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:" DRV_NAME);
diff --git a/drivers/staging/iio/frequency/dds.h b/drivers/staging/iio/frequency/dds.h
new file mode 100644
index 0000000..c3342f6
--- /dev/null
+++ b/drivers/staging/iio/frequency/dds.h
@@ -0,0 +1,110 @@
+/*
+ * dds.h - sysfs attributes associated with DDS devices
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY
+ */
+
+#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr)	\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequency##_num,	\
+			_mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY_scale
+ */
+
+#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string)			\
+	IIO_CONST_ATTR(out_altvoltage##_channel##_frequency_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol
+ */
+
+#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr)	\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequencysymbol,	\
+			_mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_phaseY
+ */
+
+#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr)	\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_phase##_num,		\
+			_mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_phaseY_scale
+ */
+
+#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string)			\
+	IIO_CONST_ATTR(out_altvoltage##_channel##_phase_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_phasesymbol
+ */
+
+#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr)	\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_phasesymbol,		\
+			_mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_en,	\
+			_mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_frequency_en,\
+			_mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_phase_en,	\
+			_mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_out_enable
+ */
+
+#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr)	\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_out_enable,		\
+			_mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_outY_enable
+ */
+
+#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output,			\
+			_mode, _show, _store, _addr)			\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_enable,\
+			_mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype
+ */
+
+#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr)	\
+	IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_wavetype,\
+			S_IWUSR, NULL, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available
+ */
+
+#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\
+	IIO_CONST_ATTR(							\
+	out_altvoltage##_channel##_out##_output##_wavetype_available, _modes);
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
index 02cc234..9931e206 100644
--- a/drivers/staging/iio/gyro/adis16060_core.c
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -15,8 +15,8 @@
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #define ADIS16060_GYRO		0x20 /* Measure Angular Rate (Gyro) */
 #define ADIS16060_TEMP_OUT	0x10 /* Measure Temperature */
@@ -85,7 +85,7 @@
 	int ret;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		/* Take the iio_dev status lock */
 		mutex_lock(&indio_dev->mlock);
 		ret = adis16060_spi_write(indio_dev, chan->address);
@@ -120,22 +120,26 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = ADIS16060_GYRO,
 	}, {
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = ADIS16060_AIN1,
 	}, {
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 1,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = ADIS16060_AIN2,
 	}, {
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = ADIS16060_TEMP_OUT,
 	}
@@ -148,7 +152,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -174,7 +178,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -183,7 +187,7 @@
 static int adis16060_r_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
 
 	return 0;
 }
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c
index 1815490..11f1dcc 100644
--- a/drivers/staging/iio/gyro/adis16080_core.c
+++ b/drivers/staging/iio/gyro/adis16080_core.c
@@ -14,8 +14,8 @@
 #include <linux/sysfs.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #define ADIS16080_DIN_GYRO   (0 << 10) /* Gyroscope output */
 #define ADIS16080_DIN_TEMP   (1 << 10) /* Temperature output */
@@ -87,7 +87,7 @@
 
 	mutex_lock(&indio_dev->mlock);
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		ret = adis16080_spi_write(indio_dev,
 					  chan->address |
 					  ADIS16080_DIN_WRITE);
@@ -110,21 +110,25 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = ADIS16080_DIN_GYRO,
 	}, {
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = ADIS16080_DIN_AIN1,
 	}, {
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 1,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = ADIS16080_DIN_AIN2,
 	}, {
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = ADIS16080_DIN_TEMP,
 	}
 };
@@ -141,7 +145,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -167,7 +171,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -176,7 +180,7 @@
 static int adis16080_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
 
 	return 0;
 }
diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c
index 947eb86..bf61cd0 100644
--- a/drivers/staging/iio/gyro/adis16130_core.c
+++ b/drivers/staging/iio/gyro/adis16130_core.c
@@ -16,8 +16,8 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #define ADIS16130_CON         0x0
 #define ADIS16130_CON_RD      (1 << 6)
@@ -100,11 +100,13 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = ADIS16130_RATEDATA,
 	}, {
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.address = ADIS16130_TEMPDATA,
 	}
 };
@@ -121,7 +123,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -145,7 +147,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 error_ret:
 	return ret;
@@ -155,7 +157,7 @@
 static int adis16130_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
 
 	return 0;
 }
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index 8f6af47..ec765f9 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -18,9 +18,9 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 
 #include "adis16260.h"
 
@@ -149,7 +149,7 @@
 						  struct device_attribute *attr,
 						  char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct adis16260_state *st = iio_priv(indio_dev);
 	if (spi_get_device_id(st->us)->driver_data)
 		return sprintf(buf, "%s\n", "0.129 ~ 256");
@@ -161,7 +161,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct adis16260_state *st = iio_priv(indio_dev);
 	int ret, len = 0;
 	u16 t;
@@ -186,7 +186,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct adis16260_state *st = iio_priv(indio_dev);
 	long val;
 	int ret;
@@ -237,7 +237,7 @@
 		struct device_attribute *attr,
 		const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	if (len < 1)
 		return -EINVAL;
 	switch (buf[0]) {
@@ -389,30 +389,76 @@
 };
 #define ADIS16260_GYRO_CHANNEL_SET(axis, mod)				\
 	struct iio_chan_spec adis16260_channels_##axis[] = {		\
-		IIO_CHAN(IIO_ANGL_VEL, 1, 0, 0, NULL, 0, mod,		\
-			 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |	\
-			 IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |	\
-			 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
-			 gyro, ADIS16260_SCAN_GYRO,			\
-			 IIO_ST('s', 14, 16, 0), 0),			\
-		IIO_CHAN(IIO_ANGL, 1, 0, 0, NULL, 0, mod,		\
-			 0,						\
-			 angle, ADIS16260_SCAN_ANGL,			\
-			 IIO_ST('u', 14, 16, 0), 0),			\
-		IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,			\
-			 IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |		\
-			 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
-			 temp, ADIS16260_SCAN_TEMP,			\
-			 IIO_ST('u', 12, 16, 0), 0),			\
-		IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,		\
-			 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
-			 in_supply, ADIS16260_SCAN_SUPPLY,		\
-			 IIO_ST('u', 12, 16, 0), 0),			\
-		IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,		\
-			 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
-			 in_aux, ADIS16260_SCAN_AUX_ADC,		\
-			 IIO_ST('u', 12, 16, 0), 0),			\
-		IIO_CHAN_SOFT_TIMESTAMP(5)				\
+		{							\
+			.type = IIO_ANGL_VEL,				\
+			.modified = 1,					\
+			.channel2 = mod,				\
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+			IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |		\
+			IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
+			.address = gyro,				\
+			.scan_index = ADIS16260_SCAN_GYRO,		\
+			.scan_type = {					\
+				.sign = 's',				\
+				.realbits = 14,				\
+				.storagebits = 16,			\
+			},						\
+		}, {							\
+			.type = IIO_ANGL,				\
+			.modified = 1,					\
+			.channel2 = mod,				\
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,	\
+			.address = angle,				\
+			.scan_index = ADIS16260_SCAN_ANGL,		\
+			.scan_type = {					\
+				.sign = 'u',				\
+				.realbits = 14,				\
+				.storagebits = 16,			\
+			},						\
+		}, {							\
+			.type = IIO_TEMP,				\
+			.indexed = 1,					\
+			.channel = 0,					\
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+			IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |		\
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
+			.address = temp,				\
+			.scan_index = ADIS16260_SCAN_TEMP,		\
+			.scan_type = {					\
+				.sign = 'u',				\
+				.realbits = 12,				\
+				.storagebits = 16,			\
+			},						\
+		}, {							\
+			.type = IIO_VOLTAGE,				\
+			.indexed = 1,					\
+			.channel = 0,					\
+			.extend_name = "supply",			\
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
+			.address = in_supply,				\
+			.scan_index = ADIS16260_SCAN_SUPPLY,		\
+			.scan_type = {					\
+				.sign = 'u',				\
+				.realbits = 12,				\
+				.storagebits = 16,			\
+			},						\
+		}, {							\
+			.type = IIO_VOLTAGE,				\
+			.indexed = 1,					\
+			.channel = 1,					\
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
+			.address = in_aux,				\
+			.scan_index = ADIS16260_SCAN_AUX_ADC,		\
+			.scan_type = {					\
+				.sign = 'u',				\
+				.realbits = 12,				\
+				.storagebits = 16,			\
+			},						\
+		},							\
+		IIO_CHAN_SOFT_TIMESTAMP(5),				\
 	}
 
 static const ADIS16260_GYRO_CHANNEL_SET(x, IIO_MOD_X);
@@ -440,7 +486,7 @@
 	s16 val16;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		addr = adis16260_addresses[chan->address][0];
 		ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16);
@@ -581,7 +627,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -666,7 +712,7 @@
 error_unreg_ring_funcs:
 	adis16260_unconfigure_ring(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -687,7 +733,7 @@
 	adis16260_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	adis16260_unconfigure_ring(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 err_ret:
 	return ret;
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index 711f151..0fe2d9d 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -5,20 +5,19 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
 #include "adis16260.h"
 
 /**
  * adis16260_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
  * @rx: somewhere to pass back the value read
  **/
-static int adis16260_read_ring_data(struct device *dev, u8 *rx)
+static int adis16260_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct adis16260_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfers[ADIS16260_OUTPUTS + 1];
 	int ret;
@@ -66,22 +65,21 @@
 	struct iio_buffer *ring = indio_dev->buffer;
 	int i = 0;
 	s16 *data;
-	size_t datasize = ring->access->get_bytes_per_datum(ring);
 
-	data = kmalloc(datasize , GFP_KERNEL);
+	data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (data == NULL) {
 		dev_err(&st->us->dev, "memory alloc failed in ring bh");
 		return -ENOMEM;
 	}
 
 	if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
-	    adis16260_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+	    adis16260_read_ring_data(indio_dev, st->rx) >= 0)
 		for (; i < bitmap_weight(indio_dev->active_scan_mask,
 					 indio_dev->masklength); i++)
 			data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
 
 	/* Guaranteed to be aligned with 8 byte boundary */
-	if (ring->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
 	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/gyro/adis16260_trigger.c b/drivers/staging/iio/gyro/adis16260_trigger.c
index 8299cd1..034559e 100644
--- a/drivers/staging/iio/gyro/adis16260_trigger.c
+++ b/drivers/staging/iio/gyro/adis16260_trigger.c
@@ -3,8 +3,8 @@
 #include <linux/spi/spi.h>
 #include <linux/export.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 #include "adis16260.h"
 
 /**
@@ -29,7 +29,7 @@
 	int ret;
 	struct adis16260_state *st = iio_priv(indio_dev);
 
-	st->trig = iio_allocate_trigger("%s-dev%d",
+	st->trig = iio_trigger_alloc("%s-dev%d",
 					spi_get_device_id(st->us)->name,
 					indio_dev->id);
 	if (st->trig == NULL) {
@@ -60,7 +60,7 @@
 error_free_irq:
 	free_irq(st->us->irq, st->trig);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -71,5 +71,5 @@
 
 	iio_trigger_unregister(st->trig);
 	free_irq(st->us->irq, st->trig);
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 }
diff --git a/drivers/staging/iio/gyro/adxrs450.h b/drivers/staging/iio/gyro/adxrs450.h
index af0c870..f8cf21f 100644
--- a/drivers/staging/iio/gyro/adxrs450.h
+++ b/drivers/staging/iio/gyro/adxrs450.h
@@ -49,7 +49,7 @@
  * @us:			actual spi_device
  * @buf_lock:		mutex to protect tx and rx
  * @tx:			transmit buffer
- * @rx:			recieve buffer
+ * @rx:			receive buffer
  **/
 struct adxrs450_state {
 	struct spi_device	*us;
diff --git a/drivers/staging/iio/gyro/adxrs450_core.c b/drivers/staging/iio/gyro/adxrs450_core.c
index 15e2496..6513119 100644
--- a/drivers/staging/iio/gyro/adxrs450_core.c
+++ b/drivers/staging/iio/gyro/adxrs450_core.c
@@ -18,8 +18,8 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #include "adxrs450.h"
 
@@ -265,7 +265,7 @@
 	s16 t;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		switch (chan->type) {
 		case IIO_ANGL_VEL:
 			ret = adxrs450_spi_sensor_data(indio_dev, &t);
@@ -329,14 +329,16 @@
 			.type = IIO_ANGL_VEL,
 			.modified = 1,
 			.channel2 = IIO_MOD_Z,
-			.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 			IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT |
 			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		}, {
 			.type = IIO_TEMP,
 			.indexed = 1,
 			.channel = 0,
-			.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		}
 	},
 	[ID_ADXRS453] = {
@@ -344,13 +346,15 @@
 			.type = IIO_ANGL_VEL,
 			.modified = 1,
 			.channel2 = IIO_MOD_Z,
-			.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
 			IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT,
 		}, {
 			.type = IIO_TEMP,
 			.indexed = 1,
 			.channel = 0,
-			.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		}
 	},
 };
@@ -368,7 +372,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -399,7 +403,7 @@
 error_initial:
 	iio_device_unregister(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 error_ret:
 	return ret;
@@ -408,7 +412,7 @@
 static int adxrs450_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
 
 	return 0;
 }
diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h
deleted file mode 100644
index b9cd454..0000000
--- a/drivers/staging/iio/iio.h
+++ /dev/null
@@ -1,471 +0,0 @@
-
-/* The industrial I/O core
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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 _INDUSTRIAL_IO_H_
-#define _INDUSTRIAL_IO_H_
-
-#include <linux/device.h>
-#include <linux/cdev.h>
-#include "types.h"
-/* IIO TODO LIST */
-/*
- * Provide means of adjusting timer accuracy.
- * Currently assumes nano seconds.
- */
-
-enum iio_data_type {
-	IIO_RAW,
-	IIO_PROCESSED,
-};
-
-/* Could add the raw attributes as well - allowing buffer only devices */
-enum iio_chan_info_enum {
-	/* 0 is reserved for raw attributes */
-	IIO_CHAN_INFO_SCALE = 1,
-	IIO_CHAN_INFO_OFFSET,
-	IIO_CHAN_INFO_CALIBSCALE,
-	IIO_CHAN_INFO_CALIBBIAS,
-	IIO_CHAN_INFO_PEAK,
-	IIO_CHAN_INFO_PEAK_SCALE,
-	IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
-	IIO_CHAN_INFO_AVERAGE_RAW,
-	IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY,
-};
-
-#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2)
-#define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1)
-
-#define IIO_CHAN_INFO_SCALE_SEPARATE_BIT		\
-	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SCALE)
-#define IIO_CHAN_INFO_SCALE_SHARED_BIT			\
-	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SCALE)
-#define IIO_CHAN_INFO_OFFSET_SEPARATE_BIT			\
-	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_OFFSET)
-#define IIO_CHAN_INFO_OFFSET_SHARED_BIT			\
-	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_OFFSET)
-#define IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT			\
-	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBSCALE)
-#define IIO_CHAN_INFO_CALIBSCALE_SHARED_BIT			\
-	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBSCALE)
-#define IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT			\
-	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBBIAS)
-#define IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT			\
-	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBBIAS)
-#define IIO_CHAN_INFO_PEAK_SEPARATE_BIT			\
-	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAK)
-#define IIO_CHAN_INFO_PEAK_SHARED_BIT			\
-	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAK)
-#define IIO_CHAN_INFO_PEAKSCALE_SEPARATE_BIT			\
-	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAKSCALE)
-#define IIO_CHAN_INFO_PEAKSCALE_SHARED_BIT			\
-	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAKSCALE)
-#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT	\
-	IIO_CHAN_INFO_SEPARATE_BIT(				\
-		IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
-#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED_BIT	\
-	IIO_CHAN_INFO_SHARED_BIT(				\
-		IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
-#define IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT			\
-	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
-#define IIO_CHAN_INFO_AVERAGE_RAW_SHARED_BIT			\
-	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
-#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT \
-	IIO_CHAN_INFO_SHARED_BIT(			       \
-		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
-#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT \
-	IIO_CHAN_INFO_SEPARATE_BIT(			       \
-		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
-
-enum iio_endian {
-	IIO_CPU,
-	IIO_BE,
-	IIO_LE,
-};
-
-struct iio_chan_spec;
-struct iio_dev;
-
-/**
- * struct iio_chan_spec_ext_info - Extended channel info attribute
- * @name:	Info attribute name
- * @shared:	Whether this attribute is shared between all channels.
- * @read:	Read callback for this info attribute, may be NULL.
- * @write:	Write callback for this info attribute, may be NULL.
- */
-struct iio_chan_spec_ext_info {
-	const char *name;
-	bool shared;
-	ssize_t (*read)(struct iio_dev *, struct iio_chan_spec const *,
-			char *buf);
-	ssize_t (*write)(struct iio_dev *, struct iio_chan_spec const *,
-			const char *buf, size_t len);
-};
-
-/**
- * struct iio_chan_spec - specification of a single channel
- * @type:		What type of measurement is the channel making.
- * @channel:		What number or name do we wish to assign the channel.
- * @channel2:		If there is a second number for a differential
- *			channel then this is it. If modified is set then the
- *			value here specifies the modifier.
- * @address:		Driver specific identifier.
- * @scan_index:	Monotonic index to give ordering in scans when read
- *			from a buffer.
- * @scan_type:		Sign:		's' or 'u' to specify signed or unsigned
- *			realbits:	Number of valid bits of data
- *			storage_bits:	Realbits + padding
- *			shift:		Shift right by this before masking out
- *					realbits.
- *			endianness:	little or big endian
- * @info_mask:		What information is to be exported about this channel.
- *			This includes calibbias, scale etc.
- * @event_mask:	What events can this channel produce.
- * @ext_info:		Array of extended info attributes for this channel.
- *			The array is NULL terminated, the last element should
- *			have it's name field set to NULL.
- * @extend_name:	Allows labeling of channel attributes with an
- *			informative name. Note this has no effect codes etc,
- *			unlike modifiers.
- * @datasheet_name:	A name used in in kernel mapping of channels. It should
- *			correspond to the first name that the channel is referred
- *			to by in the datasheet (e.g. IND), or the nearest
- *			possible compound name (e.g. IND-INC).
- * @processed_val:	Flag to specify the data access attribute should be
- *			*_input rather than *_raw.
- * @modified:		Does a modifier apply to this channel. What these are
- *			depends on the channel type.  Modifier is set in
- *			channel2. Examples are IIO_MOD_X for axial sensors about
- *			the 'x' axis.
- * @indexed:		Specify the channel has a numerical index. If not,
- *			the value in channel will be suppressed for attribute
- *			but not for event codes. Typically set it to 0 when
- *			the index is false.
- * @differential:	Channel is differential.
- */
-struct iio_chan_spec {
-	enum iio_chan_type	type;
-	int			channel;
-	int			channel2;
-	unsigned long		address;
-	int			scan_index;
-	struct {
-		char	sign;
-		u8	realbits;
-		u8	storagebits;
-		u8	shift;
-		enum iio_endian endianness;
-	} scan_type;
-	long			info_mask;
-	long			event_mask;
-	const struct iio_chan_spec_ext_info *ext_info;
-	char			*extend_name;
-	const char		*datasheet_name;
-	unsigned		processed_val:1;
-	unsigned		modified:1;
-	unsigned		indexed:1;
-	unsigned		output:1;
-	unsigned		differential:1;
-};
-
-#define IIO_ST(si, rb, sb, sh)						\
-	{ .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
-
-/* Macro assumes input channels */
-#define IIO_CHAN(_type, _mod, _indexed, _proc, _name, _chan, _chan2, \
-		 _inf_mask, _address, _si, _stype, _event_mask)		\
-	{ .type = _type,						\
-	  .output = 0,							\
-	  .modified = _mod,						\
-	  .indexed = _indexed,						\
-	  .processed_val = _proc,					\
-	  .extend_name = _name,						\
-	  .channel = _chan,						\
-	  .channel2 = _chan2,						\
-	  .info_mask = _inf_mask,					\
-	  .address = _address,						\
-	  .scan_index = _si,						\
-	  .scan_type = _stype,						\
-	  .event_mask = _event_mask }
-
-#define IIO_CHAN_SOFT_TIMESTAMP(_si)					\
-	{ .type = IIO_TIMESTAMP, .channel = -1,				\
-			.scan_index = _si, .scan_type = IIO_ST('s', 64, 64, 0) }
-
-/**
- * iio_get_time_ns() - utility function to get a time stamp for events etc
- **/
-static inline s64 iio_get_time_ns(void)
-{
-	struct timespec ts;
-	/*
-	 * calls getnstimeofday.
-	 * If hrtimers then up to ns accurate, if not microsecond.
-	 */
-	ktime_get_real_ts(&ts);
-
-	return timespec_to_ns(&ts);
-}
-
-/* Device operating modes */
-#define INDIO_DIRECT_MODE		0x01
-#define INDIO_BUFFER_TRIGGERED		0x02
-#define INDIO_BUFFER_HARDWARE		0x08
-
-#define INDIO_ALL_BUFFER_MODES					\
-	(INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE)
-
-struct iio_trigger; /* forward declaration */
-struct iio_dev;
-
-/**
- * struct iio_info - constant information about device
- * @driver_module:	module structure used to ensure correct
- *			ownership of chrdevs etc
- * @event_attrs:	event control attributes
- * @attrs:		general purpose device attributes
- * @read_raw:		function to request a value from the device.
- *			mask specifies which value. Note 0 means a reading of
- *			the channel in question.  Return value will specify the
- *			type of value returned by the device. val and val2 will
- *			contain the elements making up the returned value.
- * @write_raw:		function to write a value to the device.
- *			Parameters are the same as for read_raw.
- * @write_raw_get_fmt:	callback function to query the expected
- *			format/precision. If not set by the driver, write_raw
- *			returns IIO_VAL_INT_PLUS_MICRO.
- * @read_event_config:	find out if the event is enabled.
- * @write_event_config:	set if the event is enabled.
- * @read_event_value:	read a value associated with the event. Meaning
- *			is event dependant. event_code specifies which event.
- * @write_event_value:	write the value associated with the event.
- *			Meaning is event dependent.
- * @validate_trigger:	function to validate the trigger when the
- *			current trigger gets changed.
- **/
-struct iio_info {
-	struct module			*driver_module;
-	struct attribute_group		*event_attrs;
-	const struct attribute_group	*attrs;
-
-	int (*read_raw)(struct iio_dev *indio_dev,
-			struct iio_chan_spec const *chan,
-			int *val,
-			int *val2,
-			long mask);
-
-	int (*write_raw)(struct iio_dev *indio_dev,
-			 struct iio_chan_spec const *chan,
-			 int val,
-			 int val2,
-			 long mask);
-
-	int (*write_raw_get_fmt)(struct iio_dev *indio_dev,
-			 struct iio_chan_spec const *chan,
-			 long mask);
-
-	int (*read_event_config)(struct iio_dev *indio_dev,
-				 u64 event_code);
-
-	int (*write_event_config)(struct iio_dev *indio_dev,
-				  u64 event_code,
-				  int state);
-
-	int (*read_event_value)(struct iio_dev *indio_dev,
-				u64 event_code,
-				int *val);
-	int (*write_event_value)(struct iio_dev *indio_dev,
-				 u64 event_code,
-				 int val);
-	int (*validate_trigger)(struct iio_dev *indio_dev,
-				struct iio_trigger *trig);
-	int (*update_scan_mode)(struct iio_dev *indio_dev,
-				const unsigned long *scan_mask);
-	int (*debugfs_reg_access)(struct iio_dev *indio_dev,
-				  unsigned reg, unsigned writeval,
-				  unsigned *readval);
-};
-
-/**
- * struct iio_buffer_setup_ops - buffer setup related callbacks
- * @preenable:		[DRIVER] function to run prior to marking buffer enabled
- * @postenable:		[DRIVER] function to run after marking buffer enabled
- * @predisable:		[DRIVER] function to run prior to marking buffer
- *			disabled
- * @postdisable:	[DRIVER] function to run after marking buffer disabled
- */
-struct iio_buffer_setup_ops {
-	int				(*preenable)(struct iio_dev *);
-	int				(*postenable)(struct iio_dev *);
-	int				(*predisable)(struct iio_dev *);
-	int				(*postdisable)(struct iio_dev *);
-};
-
-/**
- * struct iio_dev - industrial I/O device
- * @id:			[INTERN] used to identify device internally
- * @modes:		[DRIVER] operating modes supported by device
- * @currentmode:	[DRIVER] current operating mode
- * @dev:		[DRIVER] device structure, should be assigned a parent
- *			and owner
- * @event_interface:	[INTERN] event chrdevs associated with interrupt lines
- * @buffer:		[DRIVER] any buffer present
- * @mlock:		[INTERN] lock used to prevent simultaneous device state
- *			changes
- * @available_scan_masks: [DRIVER] optional array of allowed bitmasks
- * @masklength:		[INTERN] the length of the mask established from
- *			channels
- * @active_scan_mask:	[INTERN] union of all scan masks requested by buffers
- * @trig:		[INTERN] current device trigger (buffer modes)
- * @pollfunc:		[DRIVER] function run on trigger being received
- * @channels:		[DRIVER] channel specification structure table
- * @num_channels:	[DRIVER] number of chanels specified in @channels.
- * @channel_attr_list:	[INTERN] keep track of automatically created channel
- *			attributes
- * @chan_attr_group:	[INTERN] group for all attrs in base directory
- * @name:		[DRIVER] name of the device.
- * @info:		[DRIVER] callbacks and constant info from driver
- * @info_exist_lock:	[INTERN] lock to prevent use during removal
- * @chrdev:		[INTERN] associated character device
- * @groups:		[INTERN] attribute groups
- * @groupcounter:	[INTERN] index of next attribute group
- * @flags:		[INTERN] file ops related flags including busy flag.
- * @debugfs_dentry:	[INTERN] device specific debugfs dentry.
- * @cached_reg_addr:	[INTERN] cached register address for debugfs reads.
- */
-struct iio_dev {
-	int				id;
-
-	int				modes;
-	int				currentmode;
-	struct device			dev;
-
-	struct iio_event_interface	*event_interface;
-
-	struct iio_buffer		*buffer;
-	struct mutex			mlock;
-
-	const unsigned long		*available_scan_masks;
-	unsigned			masklength;
-	const unsigned long		*active_scan_mask;
-	struct iio_trigger		*trig;
-	struct iio_poll_func		*pollfunc;
-
-	struct iio_chan_spec const	*channels;
-	int				num_channels;
-
-	struct list_head		channel_attr_list;
-	struct attribute_group		chan_attr_group;
-	const char			*name;
-	const struct iio_info		*info;
-	struct mutex			info_exist_lock;
-	const struct iio_buffer_setup_ops	*setup_ops;
-	struct cdev			chrdev;
-#define IIO_MAX_GROUPS 6
-	const struct attribute_group	*groups[IIO_MAX_GROUPS + 1];
-	int				groupcounter;
-
-	unsigned long			flags;
-#if defined(CONFIG_DEBUG_FS)
-	struct dentry			*debugfs_dentry;
-	unsigned			cached_reg_addr;
-#endif
-};
-
-/**
- * iio_find_channel_from_si() - get channel from its scan index
- * @indio_dev:		device
- * @si:			scan index to match
- */
-const struct iio_chan_spec
-*iio_find_channel_from_si(struct iio_dev *indio_dev, int si);
-
-/**
- * iio_device_register() - register a device with the IIO subsystem
- * @indio_dev:		Device structure filled by the device driver
- **/
-int iio_device_register(struct iio_dev *indio_dev);
-
-/**
- * iio_device_unregister() - unregister a device from the IIO subsystem
- * @indio_dev:		Device structure representing the device.
- **/
-void iio_device_unregister(struct iio_dev *indio_dev);
-
-/**
- * iio_push_event() - try to add event to the list for userspace reading
- * @indio_dev:		IIO device structure
- * @ev_code:		What event
- * @timestamp:		When the event occurred
- **/
-int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp);
-
-extern struct bus_type iio_bus_type;
-
-/**
- * iio_put_device() - reference counted deallocation of struct device
- * @dev: the iio_device containing the device
- **/
-static inline void iio_put_device(struct iio_dev *indio_dev)
-{
-	if (indio_dev)
-		put_device(&indio_dev->dev);
-};
-
-/* Can we make this smaller? */
-#define IIO_ALIGN L1_CACHE_BYTES
-/**
- * iio_allocate_device() - allocate an iio_dev from a driver
- * @sizeof_priv: Space to allocate for private structure.
- **/
-struct iio_dev *iio_allocate_device(int sizeof_priv);
-
-static inline void *iio_priv(const struct iio_dev *indio_dev)
-{
-	return (char *)indio_dev + ALIGN(sizeof(struct iio_dev), IIO_ALIGN);
-}
-
-static inline struct iio_dev *iio_priv_to_dev(void *priv)
-{
-	return (struct iio_dev *)((char *)priv -
-				  ALIGN(sizeof(struct iio_dev), IIO_ALIGN));
-}
-
-/**
- * iio_free_device() - free an iio_dev from a driver
- * @dev: the iio_dev associated with the device
- **/
-void iio_free_device(struct iio_dev *indio_dev);
-
-/**
- * iio_buffer_enabled() - helper function to test if the buffer is enabled
- * @indio_dev:		IIO device info structure for device
- **/
-static inline bool iio_buffer_enabled(struct iio_dev *indio_dev)
-{
-	return indio_dev->currentmode
-		& (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE);
-};
-
-/**
- * iio_get_debugfs_dentry() - helper function to get the debugfs_dentry
- * @indio_dev:		IIO device info structure for device
- **/
-#if defined(CONFIG_DEBUG_FS)
-static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
-{
-	return indio_dev->debugfs_dentry;
-};
-#else
-static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
-{
-	return NULL;
-};
-#endif
-
-#endif /* _INDUSTRIAL_IO_H_ */
diff --git a/drivers/staging/iio/iio_core.h b/drivers/staging/iio/iio_core.h
deleted file mode 100644
index c9dfcba..0000000
--- a/drivers/staging/iio/iio_core.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* The industrial I/O core function defs.
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
- *
- * These definitions are meant for use only within the IIO core, not individual
- * drivers.
- */
-
-#ifndef _IIO_CORE_H_
-#define _IIO_CORE_H_
-
-int __iio_add_chan_devattr(const char *postfix,
-			   struct iio_chan_spec const *chan,
-			   ssize_t (*func)(struct device *dev,
-					   struct device_attribute *attr,
-					   char *buf),
-			   ssize_t (*writefunc)(struct device *dev,
-						struct device_attribute *attr,
-						const char *buf,
-						size_t len),
-			   u64 mask,
-			   bool generic,
-			   struct device *dev,
-			   struct list_head *attr_list);
-
-/* Event interface flags */
-#define IIO_BUSY_BIT_POS 1
-
-#ifdef CONFIG_IIO_BUFFER
-struct poll_table_struct;
-
-unsigned int iio_buffer_poll(struct file *filp,
-			     struct poll_table_struct *wait);
-ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
-				      size_t n, loff_t *f_ps);
-
-
-#define iio_buffer_poll_addr (&iio_buffer_poll)
-#define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer)
-
-#else
-
-#define iio_buffer_poll_addr NULL
-#define iio_buffer_read_first_n_outer_addr NULL
-
-#endif
-
-int iio_device_register_eventset(struct iio_dev *indio_dev);
-void iio_device_unregister_eventset(struct iio_dev *indio_dev);
-int iio_event_getfd(struct iio_dev *indio_dev);
-
-#endif
diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c
index f39f346..0cd4fe9 100644
--- a/drivers/staging/iio/iio_dummy_evgen.c
+++ b/drivers/staging/iio/iio_dummy_evgen.c
@@ -22,8 +22,8 @@
 #include <linux/sysfs.h>
 
 #include "iio_dummy_evgen.h"
-#include "iio.h"
-#include "sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 /* Fiddly bit of faking and irq without hardware */
 #define IIO_EVENTGEN_NO 10
diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/staging/iio/iio_hwmon.c
index a603a5f..b03554f 100644
--- a/drivers/staging/iio/iio_hwmon.c
+++ b/drivers/staging/iio/iio_hwmon.c
@@ -14,8 +14,8 @@
 #include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
-#include "consumer.h"
-#include "types.h"
+#include <linux/iio/consumer.h>
+#include <linux/iio/types.h>
 
 /**
  * struct iio_hwmon_state - device instance state
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c
index e3a9457..3104119 100644
--- a/drivers/staging/iio/iio_simple_dummy.c
+++ b/drivers/staging/iio/iio_simple_dummy.c
@@ -19,10 +19,10 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
-#include "iio.h"
-#include "sysfs.h"
-#include "events.h"
-#include "buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
 #include "iio_simple_dummy.h"
 
 /*
@@ -73,6 +73,12 @@
 		/* What other information is available? */
 		.info_mask =
 		/*
+		 * in_voltage0_raw
+		 * Raw (unscaled no bias removal etc) measurement
+		 * from the device.
+		 */
+		IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		/*
 		 * in_voltage0_offset
 		 * Offset for userspace to apply prior to scale
 		 * when converting to standard units (microvolts)
@@ -114,6 +120,12 @@
 		.channel2 = 2,
 		.info_mask =
 		/*
+		 * in_voltage1-voltage2_raw
+		 * Raw (unscaled no bias removal etc) measurement
+		 * from the device.
+		 */
+		IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		/*
 		 * in_voltage-voltage_scale
 		 * Shared version of scale - shared by differential
 		 * input channels of type IIO_VOLTAGE.
@@ -135,6 +147,7 @@
 		.channel = 3,
 		.channel2 = 4,
 		.info_mask =
+		IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT,
 		.scan_index = diffvoltage3m4,
 		.scan_type = {
@@ -154,6 +167,7 @@
 		/* Channel 2 is use for modifiers */
 		.channel2 = IIO_MOD_X,
 		.info_mask =
+		IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		/*
 		 * Internal bias correction value. Applied
 		 * by the hardware or driver prior to userspace
@@ -177,6 +191,7 @@
 	/* DAC channel out_voltage0_raw */
 	{
 		.type = IIO_VOLTAGE,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.output = 1,
 		.indexed = 1,
 		.channel = 0,
@@ -203,7 +218,7 @@
 
 	mutex_lock(&st->lock);
 	switch (mask) {
-	case 0: /* magic value - channel value read */
+	case IIO_CHAN_INFO_RAW: /* magic value - channel value read */
 		switch (chan->type) {
 		case IIO_VOLTAGE:
 			if (chan->output) {
@@ -290,7 +305,7 @@
 	struct iio_dummy_state *st = iio_priv(indio_dev);
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		if (chan->output == 0)
 			return -EINVAL;
 
@@ -377,7 +392,7 @@
 	 * It also has a region (accessed by iio_priv()
 	 * for chip specific state information.
 	 */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -455,9 +470,7 @@
 error_unregister_events:
 	iio_simple_dummy_events_unregister(indio_dev);
 error_free_device:
-	/* Note free device should only be called, before registration
-	 * has succeeded. */
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -494,7 +507,7 @@
 		goto error_ret;
 
 	/* Free all structures */
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 error_ret:
 	return ret;
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index bb4daf7..fdfc8739 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -18,9 +18,9 @@
 #include <linux/irq.h>
 #include <linux/bitmap.h>
 
-#include "iio.h"
-#include "trigger_consumer.h"
-#include "kfifo_buf.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/kfifo_buf.h>
 
 #include "iio_simple_dummy.h"
 
@@ -37,7 +37,7 @@
  * @irq: the interrupt number
  * @p: private data - always a pointer to the poll func.
  *
- * This is the guts of buffered capture. On a trigger event occuring,
+ * This is the guts of buffered capture. On a trigger event occurring,
  * if the pollfunc is attached then this handler is called as a threaded
  * interrupt (and hence may sleep). It is responsible for grabbing data
  * from the device and pushing it into the associated buffer.
@@ -48,12 +48,9 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct iio_buffer *buffer = indio_dev->buffer;
 	int len = 0;
-	/*
-	 * The datasize is obtained from the buffer. It was stored when
-	 * the preenable setup function was called.
-	 */
-	size_t datasize = buffer->access->get_bytes_per_datum(buffer);
-	u16 *data = kmalloc(datasize, GFP_KERNEL);
+	u16 *data;
+
+	data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 
@@ -64,7 +61,7 @@
 		 *   up a fast read.  The capture will consist of all of them.
 		 *   Hence we just call the grab data function and fill the
 		 *   buffer without processing.
-		 * sofware scans: can be considered to be random access
+		 * software scans: can be considered to be random access
 		 *   so efficient reading is just a case of minimal bus
 		 *   transactions.
 		 * software culled hardware scans:
@@ -87,7 +84,7 @@
 		}
 	}
 	/* Store a timestampe at an 8 byte boundary */
-	if (buffer->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		*(s64 *)(((phys_addr_t)data + len
 				+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
 			= iio_get_time_ns();
diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c
index 449c7a5..317b774 100644
--- a/drivers/staging/iio/iio_simple_dummy_events.c
+++ b/drivers/staging/iio/iio_simple_dummy_events.c
@@ -12,9 +12,9 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 
-#include "iio.h"
-#include "sysfs.h"
-#include "events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 #include "iio_simple_dummy.h"
 
 /* Evgen 'fakes' interrupt events for this example */
@@ -122,7 +122,7 @@
  * @private: pointer to device instance state.
  *
  * This handler is responsible for querying the device to find out what
- * event occured and for then pushing that event towards userspace.
+ * event occurred and for then pushing that event towards userspace.
  * Here only one event occurs so we push that directly on with locally
  * grabbed timestamp.
  */
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index cd82b56..a8e51bc 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -19,9 +19,9 @@
 #include <linux/module.h>
 #include <asm/div64.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 #include "../ring_sw.h"
 
 #include "ad5933.h"
@@ -109,15 +109,46 @@
 };
 
 static struct iio_chan_spec ad5933_channels[] = {
-	IIO_CHAN(IIO_TEMP, 0, 1, 1, NULL, 0, 0, 0,
-		 0, AD5933_REG_TEMP_DATA, IIO_ST('s', 14, 16, 0), 0),
-	/* Ring Channels */
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "real_raw", 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 AD5933_REG_REAL_DATA, 0, IIO_ST('s', 16, 16, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "imag_raw", 0, 0,
-		 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		 AD5933_REG_IMAG_DATA, 1, IIO_ST('s', 16, 16, 0), 0),
+	{
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+		.address = AD5933_REG_TEMP_DATA,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 14,
+			.storagebits = 16,
+		},
+	}, { /* Ring Channels */
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "real_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = AD5933_REG_REAL_DATA,
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+		},
+	}, {
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "imag_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.address = AD5933_REG_IMAG_DATA,
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+		},
+	},
 };
 
 static int ad5933_i2c_write(struct i2c_client *client,
@@ -260,7 +291,7 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5933_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int ret;
@@ -289,7 +320,7 @@
 					 const char *buf,
 					 size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5933_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	long val;
@@ -323,7 +354,7 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5933_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int ret = 0, len = 0;
@@ -366,7 +397,7 @@
 					 const char *buf,
 					 size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad5933_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	long val;
@@ -495,7 +526,8 @@
 
 	mutex_lock(&indio_dev->mlock);
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_PROCESSED:
 		if (iio_buffer_enabled(indio_dev)) {
 			ret = -EBUSY;
 			goto out;
@@ -537,19 +569,14 @@
 static int ad5933_ring_preenable(struct iio_dev *indio_dev)
 {
 	struct ad5933_state *st = iio_priv(indio_dev);
-	size_t d_size;
 	int ret;
 
 	if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
 		return -EINVAL;
 
-	d_size = bitmap_weight(indio_dev->active_scan_mask,
-			       indio_dev->masklength) *
-		 ad5933_channels[1].scan_type.storagebits / 8;
-
-	if (indio_dev->buffer->access->set_bytes_per_datum)
-		indio_dev->buffer->access->
-			set_bytes_per_datum(indio_dev->buffer, d_size);
+	ret = iio_sw_buffer_preenable(indio_dev);
+	if (ret < 0)
+		return ret;
 
 	ret = ad5933_reset(st);
 	if (ret < 0)
@@ -678,7 +705,7 @@
 	int ret, voltage_uv = 0;
 	struct ad5933_platform_data *pdata = client->dev.platform_data;
 	struct ad5933_state *st;
-	struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -757,7 +784,7 @@
 	if (!IS_ERR(st->reg))
 		regulator_put(st->reg);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -774,7 +801,7 @@
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
 	}
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c
index e73ad78..1f6bd85 100644
--- a/drivers/staging/iio/imu/adis16400_core.c
+++ b/drivers/staging/iio/imu/adis16400_core.c
@@ -26,9 +26,9 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 #include "adis16400.h"
 
 enum adis16400_chip_variant {
@@ -179,7 +179,7 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	int ret, len = 0;
 	ret = adis16400_get_freq(indio_dev);
 	if (ret < 0)
@@ -225,7 +225,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct adis16400_state *st = iio_priv(indio_dev);
 	long val;
 	int ret;
@@ -279,7 +279,7 @@
 	if (ret < 0)
 		return ret;
 	if (val) {
-		ret = adis16400_reset(dev_get_drvdata(dev));
+		ret = adis16400_reset(dev_to_iio_dev(dev));
 		if (ret < 0)
 			return ret;
 	}
@@ -545,7 +545,7 @@
 	s16 val16;
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&indio_dev->mlock);
 		ret = adis16400_spi_read_reg_16(indio_dev,
 				adis16400_addresses[chan->address][0],
@@ -635,7 +635,8 @@
 		.indexed = 1,
 		.channel = 0,
 		.extend_name = "supply",
-		.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = in_supply,
 		.scan_index = ADIS16400_SCAN_SUPPLY,
 		.scan_type = IIO_ST('u', 14, 16, 0)
@@ -643,7 +644,8 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_x,
@@ -653,7 +655,8 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Y,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_y,
@@ -663,7 +666,8 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_z,
@@ -673,7 +677,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_x,
@@ -683,7 +688,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Y,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_y,
@@ -693,7 +699,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_z,
@@ -703,7 +710,8 @@
 		.type = IIO_MAGN,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = magn_x,
 		.scan_index = ADIS16400_SCAN_MAGN_X,
@@ -712,7 +720,8 @@
 		.type = IIO_MAGN,
 		.modified = 1,
 		.channel2 = IIO_MOD_Y,
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = magn_y,
 		.scan_index = ADIS16400_SCAN_MAGN_Y,
@@ -721,7 +730,8 @@
 		.type = IIO_MAGN,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = magn_z,
 		.scan_index = ADIS16400_SCAN_MAGN_Z,
@@ -730,7 +740,8 @@
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = temp,
 		.scan_index = ADIS16400_SCAN_TEMP,
@@ -739,7 +750,8 @@
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 1,
-		.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = in1,
 		.scan_index = ADIS16400_SCAN_ADC_0,
 		.scan_type = IIO_ST('s', 12, 16, 0),
@@ -753,7 +765,8 @@
 		.indexed = 1,
 		.channel = 0,
 		.extend_name = "supply",
-		.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = in_supply,
 		.scan_index = ADIS16400_SCAN_SUPPLY,
 		.scan_type = IIO_ST('u', 12, 16, 0)
@@ -761,7 +774,8 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_x,
@@ -771,7 +785,8 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Y,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_y,
@@ -781,17 +796,19 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_z,
 		.scan_index = ADIS16400_SCAN_GYRO_Z,
 		.scan_type = IIO_ST('s', 14, 16, 0),
 	}, {
-	.type = IIO_ACCEL,
+		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_x,
@@ -801,7 +818,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Y,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_y,
@@ -811,7 +829,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_z,
@@ -822,7 +841,8 @@
 		.indexed = 1,
 		.channel = 0,
 		.extend_name = "x",
-		.info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = temp0,
@@ -833,7 +853,8 @@
 		.indexed = 1,
 		.channel = 1,
 		.extend_name = "y",
-		.info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = temp1,
@@ -844,7 +865,8 @@
 		.indexed = 1,
 		.channel = 2,
 		.extend_name = "z",
-		.info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = temp2,
 		.scan_index = ADIS16350_SCAN_TEMP_Z,
@@ -853,7 +875,8 @@
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 1,
-		.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = in1,
 		.scan_index = ADIS16350_SCAN_ADC_0,
 		.scan_type = IIO_ST('s', 12, 16, 0),
@@ -867,7 +890,8 @@
 		.indexed = 1,
 		.channel = 0,
 		.extend_name = "supply",
-		.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = in_supply,
 		.scan_index = ADIS16400_SCAN_SUPPLY,
 		.scan_type = IIO_ST('u', 12, 16, 0)
@@ -875,7 +899,8 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_x,
@@ -885,7 +910,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_x,
@@ -895,7 +921,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Y,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_y,
@@ -905,7 +932,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_z,
@@ -915,7 +943,8 @@
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = temp,
 		.scan_index = ADIS16400_SCAN_TEMP,
@@ -924,7 +953,8 @@
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
 		.channel = 1,
-		.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
 		.address = in1,
 		.scan_index = ADIS16350_SCAN_ADC_0,
 		.scan_type = IIO_ST('s', 12, 16, 0),
@@ -932,7 +962,8 @@
 		.type = IIO_INCLI,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
 		.address = incli_x,
 		.scan_index = ADIS16300_SCAN_INCLI_X,
 		.scan_type = IIO_ST('s', 13, 16, 0),
@@ -940,7 +971,8 @@
 		.type = IIO_INCLI,
 		.modified = 1,
 		.channel2 = IIO_MOD_Y,
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
 		.address = incli_y,
 		.scan_index = ADIS16300_SCAN_INCLI_Y,
 		.scan_type = IIO_ST('s', 13, 16, 0),
@@ -953,7 +985,8 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_x,
@@ -963,7 +996,8 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Y,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_y,
@@ -973,7 +1007,8 @@
 		.type = IIO_ANGL_VEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = gyro_z,
@@ -983,7 +1018,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_X,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_x,
@@ -993,7 +1029,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Y,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_y,
@@ -1003,7 +1040,8 @@
 		.type = IIO_ACCEL,
 		.modified = 1,
 		.channel2 = IIO_MOD_Z,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT |
 		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
 		.address = accel_z,
@@ -1013,7 +1051,8 @@
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT,
 		.address = accel_z,
 		.scan_index = ADIS16400_SCAN_ACC_Z,
@@ -1122,7 +1161,7 @@
 {
 	int ret;
 	struct adis16400_state *st;
-	struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret =  -ENOMEM;
 		goto error_ret;
@@ -1172,14 +1211,14 @@
 	return 0;
 
 error_remove_trigger:
-	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+	if (spi->irq)
 		adis16400_remove_trigger(indio_dev);
 error_uninitialize_ring:
 	iio_buffer_unregister(indio_dev);
 error_unreg_ring_funcs:
 	adis16400_unconfigure_ring(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -1198,7 +1237,7 @@
 	adis16400_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	adis16400_unconfigure_ring(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index 8daa038..809e2c4 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -6,20 +6,19 @@
 #include <linux/bitops.h>
 #include <linux/export.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
 #include "adis16400.h"
 
 /**
  * adis16400_spi_read_burst() - read all data registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
  * @rx: somewhere to pass back the value read (min size is 24 bytes)
  **/
-static int adis16400_spi_read_burst(struct device *dev, u8 *rx)
+static int adis16400_spi_read_burst(struct iio_dev *indio_dev, u8 *rx)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct adis16400_state *st = iio_priv(indio_dev);
 	u32 old_speed_hz = st->us->max_speed_hz;
 	int ret;
@@ -71,9 +70,8 @@
 	cpu_to_be16(ADIS16400_READ_REG(ADIS16400_AUX_ADC)),
 };
 
-static int adis16350_spi_read_all(struct device *dev, u8 *rx)
+static int adis16350_spi_read_all(struct iio_dev *indio_dev, u8 *rx)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct adis16400_state *st = iio_priv(indio_dev);
 
 	struct spi_message msg;
@@ -119,12 +117,12 @@
 	struct iio_buffer *ring = indio_dev->buffer;
 	int i = 0, j, ret = 0;
 	s16 *data;
-	size_t datasize = ring->access->get_bytes_per_datum(ring);
+
 	/* Asumption that long is enough for maximum channels */
 	unsigned long mask = *indio_dev->active_scan_mask;
 	int scan_count = bitmap_weight(indio_dev->active_scan_mask,
 				       indio_dev->masklength);
-	data = kmalloc(datasize , GFP_KERNEL);
+	data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 	if (data == NULL) {
 		dev_err(&st->us->dev, "memory alloc failed in ring bh");
 		return -ENOMEM;
@@ -132,13 +130,13 @@
 
 	if (scan_count) {
 		if (st->variant->flags & ADIS16400_NO_BURST) {
-			ret = adis16350_spi_read_all(&indio_dev->dev, st->rx);
+			ret = adis16350_spi_read_all(indio_dev, st->rx);
 			if (ret < 0)
 				goto err;
 			for (; i < scan_count; i++)
 				data[i]	= *(s16 *)(st->rx + i*2);
 		} else {
-			ret = adis16400_spi_read_burst(&indio_dev->dev, st->rx);
+			ret = adis16400_spi_read_burst(indio_dev, st->rx);
 			if (ret < 0)
 				goto err;
 			for (; i < scan_count; i++) {
diff --git a/drivers/staging/iio/imu/adis16400_trigger.c b/drivers/staging/iio/imu/adis16400_trigger.c
index 5bf0007..42a678e 100644
--- a/drivers/staging/iio/imu/adis16400_trigger.c
+++ b/drivers/staging/iio/imu/adis16400_trigger.c
@@ -3,8 +3,8 @@
 #include <linux/spi/spi.h>
 #include <linux/export.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 #include "adis16400.h"
 
 /**
@@ -29,7 +29,7 @@
 	int ret;
 	struct adis16400_state *st = iio_priv(indio_dev);
 
-	st->trig = iio_allocate_trigger("%s-dev%d",
+	st->trig = iio_trigger_alloc("%s-dev%d",
 					indio_dev->name,
 					indio_dev->id);
 	if (st->trig == NULL) {
@@ -59,7 +59,7 @@
 error_free_irq:
 	free_irq(st->us->irq, st->trig);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -70,5 +70,5 @@
 
 	iio_trigger_unregister(st->trig);
 	free_irq(st->us->irq, st->trig);
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 }
diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c
deleted file mode 100644
index 386ba76..0000000
--- a/drivers/staging/iio/industrialio-buffer.c
+++ /dev/null
@@ -1,734 +0,0 @@
-/* The industrial I/O core
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
- *
- * Handling of buffer allocation / resizing.
- *
- *
- * Things to look at here.
- * - Better memory allocation techniques?
- * - Alternative access techniques?
- */
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-
-#include "iio.h"
-#include "iio_core.h"
-#include "sysfs.h"
-#include "buffer.h"
-
-static const char * const iio_endian_prefix[] = {
-	[IIO_BE] = "be",
-	[IIO_LE] = "le",
-};
-
-/**
- * iio_buffer_read_first_n_outer() - chrdev read for buffer access
- *
- * This function relies on all buffer implementations having an
- * iio_buffer as their first element.
- **/
-ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
-				      size_t n, loff_t *f_ps)
-{
-	struct iio_dev *indio_dev = filp->private_data;
-	struct iio_buffer *rb = indio_dev->buffer;
-
-	if (!rb || !rb->access->read_first_n)
-		return -EINVAL;
-	return rb->access->read_first_n(rb, n, buf);
-}
-
-/**
- * iio_buffer_poll() - poll the buffer to find out if it has data
- */
-unsigned int iio_buffer_poll(struct file *filp,
-			     struct poll_table_struct *wait)
-{
-	struct iio_dev *indio_dev = filp->private_data;
-	struct iio_buffer *rb = indio_dev->buffer;
-
-	poll_wait(filp, &rb->pollq, wait);
-	if (rb->stufftoread)
-		return POLLIN | POLLRDNORM;
-	/* need a way of knowing if there may be enough data... */
-	return 0;
-}
-
-void iio_buffer_init(struct iio_buffer *buffer)
-{
-	INIT_LIST_HEAD(&buffer->demux_list);
-	init_waitqueue_head(&buffer->pollq);
-}
-EXPORT_SYMBOL(iio_buffer_init);
-
-static ssize_t iio_show_scan_index(struct device *dev,
-				   struct device_attribute *attr,
-				   char *buf)
-{
-	return sprintf(buf, "%u\n", to_iio_dev_attr(attr)->c->scan_index);
-}
-
-static ssize_t iio_show_fixed_type(struct device *dev,
-				   struct device_attribute *attr,
-				   char *buf)
-{
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	u8 type = this_attr->c->scan_type.endianness;
-
-	if (type == IIO_CPU) {
-#ifdef __LITTLE_ENDIAN
-		type = IIO_LE;
-#else
-		type = IIO_BE;
-#endif
-	}
-	return sprintf(buf, "%s:%c%d/%d>>%u\n",
-		       iio_endian_prefix[type],
-		       this_attr->c->scan_type.sign,
-		       this_attr->c->scan_type.realbits,
-		       this_attr->c->scan_type.storagebits,
-		       this_attr->c->scan_type.shift);
-}
-
-static ssize_t iio_scan_el_show(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
-{
-	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-
-	ret = test_bit(to_iio_dev_attr(attr)->address,
-		       indio_dev->buffer->scan_mask);
-
-	return sprintf(buf, "%d\n", ret);
-}
-
-static int iio_scan_mask_clear(struct iio_buffer *buffer, int bit)
-{
-	clear_bit(bit, buffer->scan_mask);
-	return 0;
-}
-
-static ssize_t iio_scan_el_store(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf,
-				 size_t len)
-{
-	int ret = 0;
-	bool state;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_buffer *buffer = indio_dev->buffer;
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-	state = !(buf[0] == '0');
-	mutex_lock(&indio_dev->mlock);
-	if (iio_buffer_enabled(indio_dev)) {
-		ret = -EBUSY;
-		goto error_ret;
-	}
-	ret = iio_scan_mask_query(indio_dev, buffer, this_attr->address);
-	if (ret < 0)
-		goto error_ret;
-	if (!state && ret) {
-		ret = iio_scan_mask_clear(buffer, this_attr->address);
-		if (ret)
-			goto error_ret;
-	} else if (state && !ret) {
-		ret = iio_scan_mask_set(indio_dev, buffer, this_attr->address);
-		if (ret)
-			goto error_ret;
-	}
-
-error_ret:
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret < 0 ? ret : len;
-
-}
-
-static ssize_t iio_scan_el_ts_show(struct device *dev,
-				   struct device_attribute *attr,
-				   char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	return sprintf(buf, "%d\n", indio_dev->buffer->scan_timestamp);
-}
-
-static ssize_t iio_scan_el_ts_store(struct device *dev,
-				    struct device_attribute *attr,
-				    const char *buf,
-				    size_t len)
-{
-	int ret = 0;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	bool state;
-
-	state = !(buf[0] == '0');
-	mutex_lock(&indio_dev->mlock);
-	if (iio_buffer_enabled(indio_dev)) {
-		ret = -EBUSY;
-		goto error_ret;
-	}
-	indio_dev->buffer->scan_timestamp = state;
-error_ret:
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret ? ret : len;
-}
-
-static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
-					const struct iio_chan_spec *chan)
-{
-	int ret, attrcount = 0;
-	struct iio_buffer *buffer = indio_dev->buffer;
-
-	ret = __iio_add_chan_devattr("index",
-				     chan,
-				     &iio_show_scan_index,
-				     NULL,
-				     0,
-				     0,
-				     &indio_dev->dev,
-				     &buffer->scan_el_dev_attr_list);
-	if (ret)
-		goto error_ret;
-	attrcount++;
-	ret = __iio_add_chan_devattr("type",
-				     chan,
-				     &iio_show_fixed_type,
-				     NULL,
-				     0,
-				     0,
-				     &indio_dev->dev,
-				     &buffer->scan_el_dev_attr_list);
-	if (ret)
-		goto error_ret;
-	attrcount++;
-	if (chan->type != IIO_TIMESTAMP)
-		ret = __iio_add_chan_devattr("en",
-					     chan,
-					     &iio_scan_el_show,
-					     &iio_scan_el_store,
-					     chan->scan_index,
-					     0,
-					     &indio_dev->dev,
-					     &buffer->scan_el_dev_attr_list);
-	else
-		ret = __iio_add_chan_devattr("en",
-					     chan,
-					     &iio_scan_el_ts_show,
-					     &iio_scan_el_ts_store,
-					     chan->scan_index,
-					     0,
-					     &indio_dev->dev,
-					     &buffer->scan_el_dev_attr_list);
-	attrcount++;
-	ret = attrcount;
-error_ret:
-	return ret;
-}
-
-static void iio_buffer_remove_and_free_scan_dev_attr(struct iio_dev *indio_dev,
-						     struct iio_dev_attr *p)
-{
-	kfree(p->dev_attr.attr.name);
-	kfree(p);
-}
-
-static void __iio_buffer_attr_cleanup(struct iio_dev *indio_dev)
-{
-	struct iio_dev_attr *p, *n;
-	struct iio_buffer *buffer = indio_dev->buffer;
-
-	list_for_each_entry_safe(p, n,
-				 &buffer->scan_el_dev_attr_list, l)
-		iio_buffer_remove_and_free_scan_dev_attr(indio_dev, p);
-}
-
-static const char * const iio_scan_elements_group_name = "scan_elements";
-
-int iio_buffer_register(struct iio_dev *indio_dev,
-			const struct iio_chan_spec *channels,
-			int num_channels)
-{
-	struct iio_dev_attr *p;
-	struct attribute **attr;
-	struct iio_buffer *buffer = indio_dev->buffer;
-	int ret, i, attrn, attrcount, attrcount_orig = 0;
-
-	if (buffer->attrs)
-		indio_dev->groups[indio_dev->groupcounter++] = buffer->attrs;
-
-	if (buffer->scan_el_attrs != NULL) {
-		attr = buffer->scan_el_attrs->attrs;
-		while (*attr++ != NULL)
-			attrcount_orig++;
-	}
-	attrcount = attrcount_orig;
-	INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
-	if (channels) {
-		/* new magic */
-		for (i = 0; i < num_channels; i++) {
-			/* Establish necessary mask length */
-			if (channels[i].scan_index >
-			    (int)indio_dev->masklength - 1)
-				indio_dev->masklength
-					= indio_dev->channels[i].scan_index + 1;
-
-			ret = iio_buffer_add_channel_sysfs(indio_dev,
-							 &channels[i]);
-			if (ret < 0)
-				goto error_cleanup_dynamic;
-			attrcount += ret;
-			if (channels[i].type == IIO_TIMESTAMP)
-				buffer->scan_index_timestamp =
-					channels[i].scan_index;
-		}
-		if (indio_dev->masklength && buffer->scan_mask == NULL) {
-			buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
-						    sizeof(*buffer->scan_mask),
-						    GFP_KERNEL);
-			if (buffer->scan_mask == NULL) {
-				ret = -ENOMEM;
-				goto error_cleanup_dynamic;
-			}
-		}
-	}
-
-	buffer->scan_el_group.name = iio_scan_elements_group_name;
-
-	buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
-					      sizeof(buffer->scan_el_group.attrs[0]),
-					      GFP_KERNEL);
-	if (buffer->scan_el_group.attrs == NULL) {
-		ret = -ENOMEM;
-		goto error_free_scan_mask;
-	}
-	if (buffer->scan_el_attrs)
-		memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs,
-		       sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig);
-	attrn = attrcount_orig;
-
-	list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
-		buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
-	indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
-
-	return 0;
-
-error_free_scan_mask:
-	kfree(buffer->scan_mask);
-error_cleanup_dynamic:
-	__iio_buffer_attr_cleanup(indio_dev);
-
-	return ret;
-}
-EXPORT_SYMBOL(iio_buffer_register);
-
-void iio_buffer_unregister(struct iio_dev *indio_dev)
-{
-	kfree(indio_dev->buffer->scan_mask);
-	kfree(indio_dev->buffer->scan_el_group.attrs);
-	__iio_buffer_attr_cleanup(indio_dev);
-}
-EXPORT_SYMBOL(iio_buffer_unregister);
-
-ssize_t iio_buffer_read_length(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_buffer *buffer = indio_dev->buffer;
-
-	if (buffer->access->get_length)
-		return sprintf(buf, "%d\n",
-			       buffer->access->get_length(buffer));
-
-	return 0;
-}
-EXPORT_SYMBOL(iio_buffer_read_length);
-
-ssize_t iio_buffer_write_length(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf,
-				size_t len)
-{
-	int ret;
-	ulong val;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_buffer *buffer = indio_dev->buffer;
-
-	ret = strict_strtoul(buf, 10, &val);
-	if (ret)
-		return ret;
-
-	if (buffer->access->get_length)
-		if (val == buffer->access->get_length(buffer))
-			return len;
-
-	mutex_lock(&indio_dev->mlock);
-	if (iio_buffer_enabled(indio_dev)) {
-		ret = -EBUSY;
-	} else {
-		if (buffer->access->set_length)
-			buffer->access->set_length(buffer, val);
-		ret = 0;
-	}
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret ? ret : len;
-}
-EXPORT_SYMBOL(iio_buffer_write_length);
-
-ssize_t iio_buffer_store_enable(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf,
-				size_t len)
-{
-	int ret;
-	bool requested_state, current_state;
-	int previous_mode;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_buffer *buffer = indio_dev->buffer;
-
-	mutex_lock(&indio_dev->mlock);
-	previous_mode = indio_dev->currentmode;
-	requested_state = !(buf[0] == '0');
-	current_state = iio_buffer_enabled(indio_dev);
-	if (current_state == requested_state) {
-		printk(KERN_INFO "iio-buffer, current state requested again\n");
-		goto done;
-	}
-	if (requested_state) {
-		if (indio_dev->setup_ops->preenable) {
-			ret = indio_dev->setup_ops->preenable(indio_dev);
-			if (ret) {
-				printk(KERN_ERR
-				       "Buffer not started:"
-				       "buffer preenable failed\n");
-				goto error_ret;
-			}
-		}
-		if (buffer->access->request_update) {
-			ret = buffer->access->request_update(buffer);
-			if (ret) {
-				printk(KERN_INFO
-				       "Buffer not started:"
-				       "buffer parameter update failed\n");
-				goto error_ret;
-			}
-		}
-		/* Definitely possible for devices to support both of these.*/
-		if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
-			if (!indio_dev->trig) {
-				printk(KERN_INFO
-				       "Buffer not started: no trigger\n");
-				ret = -EINVAL;
-				goto error_ret;
-			}
-			indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
-		} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE)
-			indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
-		else { /* should never be reached */
-			ret = -EINVAL;
-			goto error_ret;
-		}
-
-		if (indio_dev->setup_ops->postenable) {
-			ret = indio_dev->setup_ops->postenable(indio_dev);
-			if (ret) {
-				printk(KERN_INFO
-				       "Buffer not started:"
-				       "postenable failed\n");
-				indio_dev->currentmode = previous_mode;
-				if (indio_dev->setup_ops->postdisable)
-					indio_dev->setup_ops->
-						postdisable(indio_dev);
-				goto error_ret;
-			}
-		}
-	} else {
-		if (indio_dev->setup_ops->predisable) {
-			ret = indio_dev->setup_ops->predisable(indio_dev);
-			if (ret)
-				goto error_ret;
-		}
-		indio_dev->currentmode = INDIO_DIRECT_MODE;
-		if (indio_dev->setup_ops->postdisable) {
-			ret = indio_dev->setup_ops->postdisable(indio_dev);
-			if (ret)
-				goto error_ret;
-		}
-	}
-done:
-	mutex_unlock(&indio_dev->mlock);
-	return len;
-
-error_ret:
-	mutex_unlock(&indio_dev->mlock);
-	return ret;
-}
-EXPORT_SYMBOL(iio_buffer_store_enable);
-
-ssize_t iio_buffer_show_enable(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
-}
-EXPORT_SYMBOL(iio_buffer_show_enable);
-
-/* note NULL used as error indicator as it doesn't make sense. */
-static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
-					  unsigned int masklength,
-					  const unsigned long *mask)
-{
-	if (bitmap_empty(mask, masklength))
-		return NULL;
-	while (*av_masks) {
-		if (bitmap_subset(mask, av_masks, masklength))
-			return av_masks;
-		av_masks += BITS_TO_LONGS(masklength);
-	}
-	return NULL;
-}
-
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
-{
-	struct iio_buffer *buffer = indio_dev->buffer;
-	const struct iio_chan_spec *ch;
-	unsigned bytes = 0;
-	int length, i;
-	dev_dbg(&indio_dev->dev, "%s\n", __func__);
-
-	/* How much space will the demuxed element take? */
-	for_each_set_bit(i, buffer->scan_mask,
-			 indio_dev->masklength) {
-		ch = iio_find_channel_from_si(indio_dev, i);
-		length = ch->scan_type.storagebits/8;
-		bytes = ALIGN(bytes, length);
-		bytes += length;
-	}
-	if (buffer->scan_timestamp) {
-		ch = iio_find_channel_from_si(indio_dev,
-					      buffer->scan_index_timestamp);
-		length = ch->scan_type.storagebits/8;
-		bytes = ALIGN(bytes, length);
-		bytes += length;
-	}
-	buffer->access->set_bytes_per_datum(buffer, bytes);
-
-	/* What scan mask do we actually have ?*/
-	if (indio_dev->available_scan_masks)
-		indio_dev->active_scan_mask =
-			iio_scan_mask_match(indio_dev->available_scan_masks,
-					    indio_dev->masklength,
-					    buffer->scan_mask);
-	else
-		indio_dev->active_scan_mask = buffer->scan_mask;
-	iio_update_demux(indio_dev);
-
-	if (indio_dev->info->update_scan_mode)
-		return indio_dev->info
-			->update_scan_mode(indio_dev,
-					   indio_dev->active_scan_mask);
-	return 0;
-}
-EXPORT_SYMBOL(iio_sw_buffer_preenable);
-
-/**
- * iio_scan_mask_set() - set particular bit in the scan mask
- * @buffer: the buffer whose scan mask we are interested in
- * @bit: the bit to be set.
- **/
-int iio_scan_mask_set(struct iio_dev *indio_dev,
-		      struct iio_buffer *buffer, int bit)
-{
-	const unsigned long *mask;
-	unsigned long *trialmask;
-
-	trialmask = kmalloc(sizeof(*trialmask)*
-			    BITS_TO_LONGS(indio_dev->masklength),
-			    GFP_KERNEL);
-
-	if (trialmask == NULL)
-		return -ENOMEM;
-	if (!indio_dev->masklength) {
-		WARN_ON("trying to set scanmask prior to registering buffer\n");
-		kfree(trialmask);
-		return -EINVAL;
-	}
-	bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
-	set_bit(bit, trialmask);
-
-	if (indio_dev->available_scan_masks) {
-		mask = iio_scan_mask_match(indio_dev->available_scan_masks,
-					   indio_dev->masklength,
-					   trialmask);
-		if (!mask) {
-			kfree(trialmask);
-			return -EINVAL;
-		}
-	}
-	bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
-
-	kfree(trialmask);
-
-	return 0;
-};
-EXPORT_SYMBOL_GPL(iio_scan_mask_set);
-
-int iio_scan_mask_query(struct iio_dev *indio_dev,
-			struct iio_buffer *buffer, int bit)
-{
-	if (bit > indio_dev->masklength)
-		return -EINVAL;
-
-	if (!buffer->scan_mask)
-		return 0;
-
-	return test_bit(bit, buffer->scan_mask);
-};
-EXPORT_SYMBOL_GPL(iio_scan_mask_query);
-
-/**
- * struct iio_demux_table() - table describing demux memcpy ops
- * @from:	index to copy from
- * @to:	index to copy to
- * @length:	how many bytes to copy
- * @l:		list head used for management
- */
-struct iio_demux_table {
-	unsigned from;
-	unsigned to;
-	unsigned length;
-	struct list_head l;
-};
-
-static unsigned char *iio_demux(struct iio_buffer *buffer,
-				 unsigned char *datain)
-{
-	struct iio_demux_table *t;
-
-	if (list_empty(&buffer->demux_list))
-		return datain;
-	list_for_each_entry(t, &buffer->demux_list, l)
-		memcpy(buffer->demux_bounce + t->to,
-		       datain + t->from, t->length);
-
-	return buffer->demux_bounce;
-}
-
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
-		       s64 timestamp)
-{
-	unsigned char *dataout = iio_demux(buffer, data);
-
-	return buffer->access->store_to(buffer, dataout, timestamp);
-}
-EXPORT_SYMBOL_GPL(iio_push_to_buffer);
-
-int iio_update_demux(struct iio_dev *indio_dev)
-{
-	const struct iio_chan_spec *ch;
-	struct iio_buffer *buffer = indio_dev->buffer;
-	int ret, in_ind = -1, out_ind, length;
-	unsigned in_loc = 0, out_loc = 0;
-	struct iio_demux_table *p, *q;
-
-	/* Clear out any old demux */
-	list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
-		list_del(&p->l);
-		kfree(p);
-	}
-	kfree(buffer->demux_bounce);
-	buffer->demux_bounce = NULL;
-
-	/* First work out which scan mode we will actually have */
-	if (bitmap_equal(indio_dev->active_scan_mask,
-			 buffer->scan_mask,
-			 indio_dev->masklength))
-		return 0;
-
-	/* Now we have the two masks, work from least sig and build up sizes */
-	for_each_set_bit(out_ind,
-			 indio_dev->active_scan_mask,
-			 indio_dev->masklength) {
-		in_ind = find_next_bit(indio_dev->active_scan_mask,
-				       indio_dev->masklength,
-				       in_ind + 1);
-		while (in_ind != out_ind) {
-			in_ind = find_next_bit(indio_dev->active_scan_mask,
-					       indio_dev->masklength,
-					       in_ind + 1);
-			ch = iio_find_channel_from_si(indio_dev, in_ind);
-			length = ch->scan_type.storagebits/8;
-			/* Make sure we are aligned */
-			in_loc += length;
-			if (in_loc % length)
-				in_loc += length - in_loc % length;
-		}
-		p = kmalloc(sizeof(*p), GFP_KERNEL);
-		if (p == NULL) {
-			ret = -ENOMEM;
-			goto error_clear_mux_table;
-		}
-		ch = iio_find_channel_from_si(indio_dev, in_ind);
-		length = ch->scan_type.storagebits/8;
-		if (out_loc % length)
-			out_loc += length - out_loc % length;
-		if (in_loc % length)
-			in_loc += length - in_loc % length;
-		p->from = in_loc;
-		p->to = out_loc;
-		p->length = length;
-		list_add_tail(&p->l, &buffer->demux_list);
-		out_loc += length;
-		in_loc += length;
-	}
-	/* Relies on scan_timestamp being last */
-	if (buffer->scan_timestamp) {
-		p = kmalloc(sizeof(*p), GFP_KERNEL);
-		if (p == NULL) {
-			ret = -ENOMEM;
-			goto error_clear_mux_table;
-		}
-		ch = iio_find_channel_from_si(indio_dev,
-			buffer->scan_index_timestamp);
-		length = ch->scan_type.storagebits/8;
-		if (out_loc % length)
-			out_loc += length - out_loc % length;
-		if (in_loc % length)
-			in_loc += length - in_loc % length;
-		p->from = in_loc;
-		p->to = out_loc;
-		p->length = length;
-		list_add_tail(&p->l, &buffer->demux_list);
-		out_loc += length;
-		in_loc += length;
-	}
-	buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL);
-	if (buffer->demux_bounce == NULL) {
-		ret = -ENOMEM;
-		goto error_clear_mux_table;
-	}
-	return 0;
-
-error_clear_mux_table:
-	list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
-		list_del(&p->l);
-		kfree(p);
-	}
-	return ret;
-}
-EXPORT_SYMBOL_GPL(iio_update_demux);
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
deleted file mode 100644
index d303bfb..0000000
--- a/drivers/staging/iio/industrialio-core.c
+++ /dev/null
@@ -1,927 +0,0 @@
-/* The industrial I/O core
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
- *
- * Based on elements of hwmon and input subsystems.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/idr.h>
-#include <linux/kdev_t.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/cdev.h>
-#include <linux/slab.h>
-#include <linux/anon_inodes.h>
-#include <linux/debugfs.h>
-#include "iio.h"
-#include "iio_core.h"
-#include "iio_core_trigger.h"
-#include "sysfs.h"
-#include "events.h"
-
-/* IDA to assign each registered device a unique id*/
-static DEFINE_IDA(iio_ida);
-
-static dev_t iio_devt;
-
-#define IIO_DEV_MAX 256
-struct bus_type iio_bus_type = {
-	.name = "iio",
-};
-EXPORT_SYMBOL(iio_bus_type);
-
-static struct dentry *iio_debugfs_dentry;
-
-static const char * const iio_data_type_name[] = {
-	[IIO_RAW] = "raw",
-	[IIO_PROCESSED] = "input",
-};
-
-static const char * const iio_direction[] = {
-	[0] = "in",
-	[1] = "out",
-};
-
-static const char * const iio_chan_type_name_spec[] = {
-	[IIO_VOLTAGE] = "voltage",
-	[IIO_CURRENT] = "current",
-	[IIO_POWER] = "power",
-	[IIO_ACCEL] = "accel",
-	[IIO_ANGL_VEL] = "anglvel",
-	[IIO_MAGN] = "magn",
-	[IIO_LIGHT] = "illuminance",
-	[IIO_INTENSITY] = "intensity",
-	[IIO_PROXIMITY] = "proximity",
-	[IIO_TEMP] = "temp",
-	[IIO_INCLI] = "incli",
-	[IIO_ROT] = "rot",
-	[IIO_ANGL] = "angl",
-	[IIO_TIMESTAMP] = "timestamp",
-	[IIO_CAPACITANCE] = "capacitance",
-};
-
-static const char * const iio_modifier_names[] = {
-	[IIO_MOD_X] = "x",
-	[IIO_MOD_Y] = "y",
-	[IIO_MOD_Z] = "z",
-	[IIO_MOD_LIGHT_BOTH] = "both",
-	[IIO_MOD_LIGHT_IR] = "ir",
-};
-
-/* relies on pairs of these shared then separate */
-static const char * const iio_chan_info_postfix[] = {
-	[IIO_CHAN_INFO_SCALE] = "scale",
-	[IIO_CHAN_INFO_OFFSET] = "offset",
-	[IIO_CHAN_INFO_CALIBSCALE] = "calibscale",
-	[IIO_CHAN_INFO_CALIBBIAS] = "calibbias",
-	[IIO_CHAN_INFO_PEAK] = "peak_raw",
-	[IIO_CHAN_INFO_PEAK_SCALE] = "peak_scale",
-	[IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW] = "quadrature_correction_raw",
-	[IIO_CHAN_INFO_AVERAGE_RAW] = "mean_raw",
-	[IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY]
-	= "filter_low_pass_3db_frequency",
-};
-
-const struct iio_chan_spec
-*iio_find_channel_from_si(struct iio_dev *indio_dev, int si)
-{
-	int i;
-
-	for (i = 0; i < indio_dev->num_channels; i++)
-		if (indio_dev->channels[i].scan_index == si)
-			return &indio_dev->channels[i];
-	return NULL;
-}
-
-/* This turns up an awful lot */
-ssize_t iio_read_const_attr(struct device *dev,
-			    struct device_attribute *attr,
-			    char *buf)
-{
-	return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string);
-}
-EXPORT_SYMBOL(iio_read_const_attr);
-
-static int __init iio_init(void)
-{
-	int ret;
-
-	/* Register sysfs bus */
-	ret  = bus_register(&iio_bus_type);
-	if (ret < 0) {
-		printk(KERN_ERR
-		       "%s could not register bus type\n",
-			__FILE__);
-		goto error_nothing;
-	}
-
-	ret = alloc_chrdev_region(&iio_devt, 0, IIO_DEV_MAX, "iio");
-	if (ret < 0) {
-		printk(KERN_ERR "%s: failed to allocate char dev region\n",
-		       __FILE__);
-		goto error_unregister_bus_type;
-	}
-
-	iio_debugfs_dentry = debugfs_create_dir("iio", NULL);
-
-	return 0;
-
-error_unregister_bus_type:
-	bus_unregister(&iio_bus_type);
-error_nothing:
-	return ret;
-}
-
-static void __exit iio_exit(void)
-{
-	if (iio_devt)
-		unregister_chrdev_region(iio_devt, IIO_DEV_MAX);
-	bus_unregister(&iio_bus_type);
-	debugfs_remove(iio_debugfs_dentry);
-}
-
-#if defined(CONFIG_DEBUG_FS)
-static int iio_debugfs_open(struct inode *inode, struct file *file)
-{
-	if (inode->i_private)
-		file->private_data = inode->i_private;
-
-	return 0;
-}
-
-static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf,
-			      size_t count, loff_t *ppos)
-{
-	struct iio_dev *indio_dev = file->private_data;
-	char buf[20];
-	unsigned val = 0;
-	ssize_t len;
-	int ret;
-
-	ret = indio_dev->info->debugfs_reg_access(indio_dev,
-						  indio_dev->cached_reg_addr,
-						  0, &val);
-	if (ret)
-		dev_err(indio_dev->dev.parent, "%s: read failed\n", __func__);
-
-	len = snprintf(buf, sizeof(buf), "0x%X\n", val);
-
-	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
-}
-
-static ssize_t iio_debugfs_write_reg(struct file *file,
-		     const char __user *userbuf, size_t count, loff_t *ppos)
-{
-	struct iio_dev *indio_dev = file->private_data;
-	unsigned reg, val;
-	char buf[80];
-	int ret;
-
-	count = min_t(size_t, count, (sizeof(buf)-1));
-	if (copy_from_user(buf, userbuf, count))
-		return -EFAULT;
-
-	buf[count] = 0;
-
-	ret = sscanf(buf, "%i %i", &reg, &val);
-
-	switch (ret) {
-	case 1:
-		indio_dev->cached_reg_addr = reg;
-		break;
-	case 2:
-		indio_dev->cached_reg_addr = reg;
-		ret = indio_dev->info->debugfs_reg_access(indio_dev, reg,
-							  val, NULL);
-		if (ret) {
-			dev_err(indio_dev->dev.parent, "%s: write failed\n",
-				__func__);
-			return ret;
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return count;
-}
-
-static const struct file_operations iio_debugfs_reg_fops = {
-	.open = iio_debugfs_open,
-	.read = iio_debugfs_read_reg,
-	.write = iio_debugfs_write_reg,
-};
-
-static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
-{
-	debugfs_remove_recursive(indio_dev->debugfs_dentry);
-}
-
-static int iio_device_register_debugfs(struct iio_dev *indio_dev)
-{
-	struct dentry *d;
-
-	if (indio_dev->info->debugfs_reg_access == NULL)
-		return 0;
-
-	if (IS_ERR(iio_debugfs_dentry))
-		return 0;
-
-	indio_dev->debugfs_dentry =
-		debugfs_create_dir(dev_name(&indio_dev->dev),
-				   iio_debugfs_dentry);
-	if (IS_ERR(indio_dev->debugfs_dentry))
-		return PTR_ERR(indio_dev->debugfs_dentry);
-
-	if (indio_dev->debugfs_dentry == NULL) {
-		dev_warn(indio_dev->dev.parent,
-			 "Failed to create debugfs directory\n");
-		return -EFAULT;
-	}
-
-	d = debugfs_create_file("direct_reg_access", 0644,
-				indio_dev->debugfs_dentry,
-				indio_dev, &iio_debugfs_reg_fops);
-	if (!d) {
-		iio_device_unregister_debugfs(indio_dev);
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-#else
-static int iio_device_register_debugfs(struct iio_dev *indio_dev)
-{
-	return 0;
-}
-
-static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
-{
-}
-#endif /* CONFIG_DEBUG_FS */
-
-static ssize_t iio_read_channel_ext_info(struct device *dev,
-				     struct device_attribute *attr,
-				     char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	const struct iio_chan_spec_ext_info *ext_info;
-
-	ext_info = &this_attr->c->ext_info[this_attr->address];
-
-	return ext_info->read(indio_dev, this_attr->c, buf);
-}
-
-static ssize_t iio_write_channel_ext_info(struct device *dev,
-				     struct device_attribute *attr,
-				     const char *buf,
-					 size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	const struct iio_chan_spec_ext_info *ext_info;
-
-	ext_info = &this_attr->c->ext_info[this_attr->address];
-
-	return ext_info->write(indio_dev, this_attr->c, buf, len);
-}
-
-static ssize_t iio_read_channel_info(struct device *dev,
-				     struct device_attribute *attr,
-				     char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int val, val2;
-	int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
-					    &val, &val2, this_attr->address);
-
-	if (ret < 0)
-		return ret;
-
-	if (ret == IIO_VAL_INT)
-		return sprintf(buf, "%d\n", val);
-	else if (ret == IIO_VAL_INT_PLUS_MICRO) {
-		if (val2 < 0)
-			return sprintf(buf, "-%d.%06u\n", val, -val2);
-		else
-			return sprintf(buf, "%d.%06u\n", val, val2);
-	} else if (ret == IIO_VAL_INT_PLUS_NANO) {
-		if (val2 < 0)
-			return sprintf(buf, "-%d.%09u\n", val, -val2);
-		else
-			return sprintf(buf, "%d.%09u\n", val, val2);
-	} else
-		return 0;
-}
-
-static ssize_t iio_write_channel_info(struct device *dev,
-				      struct device_attribute *attr,
-				      const char *buf,
-				      size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int ret, integer = 0, fract = 0, fract_mult = 100000;
-	bool integer_part = true, negative = false;
-
-	/* Assumes decimal - precision based on number of digits */
-	if (!indio_dev->info->write_raw)
-		return -EINVAL;
-
-	if (indio_dev->info->write_raw_get_fmt)
-		switch (indio_dev->info->write_raw_get_fmt(indio_dev,
-			this_attr->c, this_attr->address)) {
-		case IIO_VAL_INT_PLUS_MICRO:
-			fract_mult = 100000;
-			break;
-		case IIO_VAL_INT_PLUS_NANO:
-			fract_mult = 100000000;
-			break;
-		default:
-			return -EINVAL;
-		}
-
-	if (buf[0] == '-') {
-		negative = true;
-		buf++;
-	}
-
-	while (*buf) {
-		if ('0' <= *buf && *buf <= '9') {
-			if (integer_part)
-				integer = integer*10 + *buf - '0';
-			else {
-				fract += fract_mult*(*buf - '0');
-				if (fract_mult == 1)
-					break;
-				fract_mult /= 10;
-			}
-		} else if (*buf == '\n') {
-			if (*(buf + 1) == '\0')
-				break;
-			else
-				return -EINVAL;
-		} else if (*buf == '.') {
-			integer_part = false;
-		} else {
-			return -EINVAL;
-		}
-		buf++;
-	}
-	if (negative) {
-		if (integer)
-			integer = -integer;
-		else
-			fract = -fract;
-	}
-
-	ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
-					 integer, fract, this_attr->address);
-	if (ret)
-		return ret;
-
-	return len;
-}
-
-static
-int __iio_device_attr_init(struct device_attribute *dev_attr,
-			   const char *postfix,
-			   struct iio_chan_spec const *chan,
-			   ssize_t (*readfunc)(struct device *dev,
-					       struct device_attribute *attr,
-					       char *buf),
-			   ssize_t (*writefunc)(struct device *dev,
-						struct device_attribute *attr,
-						const char *buf,
-						size_t len),
-			   bool generic)
-{
-	int ret;
-	char *name_format, *full_postfix;
-	sysfs_attr_init(&dev_attr->attr);
-
-	/* Build up postfix of <extend_name>_<modifier>_postfix */
-	if (chan->modified && !generic) {
-		if (chan->extend_name)
-			full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
-						 iio_modifier_names[chan
-								    ->channel2],
-						 chan->extend_name,
-						 postfix);
-		else
-			full_postfix = kasprintf(GFP_KERNEL, "%s_%s",
-						 iio_modifier_names[chan
-								    ->channel2],
-						 postfix);
-	} else {
-		if (chan->extend_name == NULL)
-			full_postfix = kstrdup(postfix, GFP_KERNEL);
-		else
-			full_postfix = kasprintf(GFP_KERNEL,
-						 "%s_%s",
-						 chan->extend_name,
-						 postfix);
-	}
-	if (full_postfix == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	if (chan->differential) { /* Differential can not have modifier */
-		if (generic)
-			name_format
-				= kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
-					    iio_direction[chan->output],
-					    iio_chan_type_name_spec[chan->type],
-					    iio_chan_type_name_spec[chan->type],
-					    full_postfix);
-		else if (chan->indexed)
-			name_format
-				= kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s",
-					    iio_direction[chan->output],
-					    iio_chan_type_name_spec[chan->type],
-					    chan->channel,
-					    iio_chan_type_name_spec[chan->type],
-					    chan->channel2,
-					    full_postfix);
-		else {
-			WARN_ON("Differential channels must be indexed\n");
-			ret = -EINVAL;
-			goto error_free_full_postfix;
-		}
-	} else { /* Single ended */
-		if (generic)
-			name_format
-				= kasprintf(GFP_KERNEL, "%s_%s_%s",
-					    iio_direction[chan->output],
-					    iio_chan_type_name_spec[chan->type],
-					    full_postfix);
-		else if (chan->indexed)
-			name_format
-				= kasprintf(GFP_KERNEL, "%s_%s%d_%s",
-					    iio_direction[chan->output],
-					    iio_chan_type_name_spec[chan->type],
-					    chan->channel,
-					    full_postfix);
-		else
-			name_format
-				= kasprintf(GFP_KERNEL, "%s_%s_%s",
-					    iio_direction[chan->output],
-					    iio_chan_type_name_spec[chan->type],
-					    full_postfix);
-	}
-	if (name_format == NULL) {
-		ret = -ENOMEM;
-		goto error_free_full_postfix;
-	}
-	dev_attr->attr.name = kasprintf(GFP_KERNEL,
-					name_format,
-					chan->channel,
-					chan->channel2);
-	if (dev_attr->attr.name == NULL) {
-		ret = -ENOMEM;
-		goto error_free_name_format;
-	}
-
-	if (readfunc) {
-		dev_attr->attr.mode |= S_IRUGO;
-		dev_attr->show = readfunc;
-	}
-
-	if (writefunc) {
-		dev_attr->attr.mode |= S_IWUSR;
-		dev_attr->store = writefunc;
-	}
-	kfree(name_format);
-	kfree(full_postfix);
-
-	return 0;
-
-error_free_name_format:
-	kfree(name_format);
-error_free_full_postfix:
-	kfree(full_postfix);
-error_ret:
-	return ret;
-}
-
-static void __iio_device_attr_deinit(struct device_attribute *dev_attr)
-{
-	kfree(dev_attr->attr.name);
-}
-
-int __iio_add_chan_devattr(const char *postfix,
-			   struct iio_chan_spec const *chan,
-			   ssize_t (*readfunc)(struct device *dev,
-					       struct device_attribute *attr,
-					       char *buf),
-			   ssize_t (*writefunc)(struct device *dev,
-						struct device_attribute *attr,
-						const char *buf,
-						size_t len),
-			   u64 mask,
-			   bool generic,
-			   struct device *dev,
-			   struct list_head *attr_list)
-{
-	int ret;
-	struct iio_dev_attr *iio_attr, *t;
-
-	iio_attr = kzalloc(sizeof *iio_attr, GFP_KERNEL);
-	if (iio_attr == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	ret = __iio_device_attr_init(&iio_attr->dev_attr,
-				     postfix, chan,
-				     readfunc, writefunc, generic);
-	if (ret)
-		goto error_iio_dev_attr_free;
-	iio_attr->c = chan;
-	iio_attr->address = mask;
-	list_for_each_entry(t, attr_list, l)
-		if (strcmp(t->dev_attr.attr.name,
-			   iio_attr->dev_attr.attr.name) == 0) {
-			if (!generic)
-				dev_err(dev, "tried to double register : %s\n",
-					t->dev_attr.attr.name);
-			ret = -EBUSY;
-			goto error_device_attr_deinit;
-		}
-	list_add(&iio_attr->l, attr_list);
-
-	return 0;
-
-error_device_attr_deinit:
-	__iio_device_attr_deinit(&iio_attr->dev_attr);
-error_iio_dev_attr_free:
-	kfree(iio_attr);
-error_ret:
-	return ret;
-}
-
-static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
-					struct iio_chan_spec const *chan)
-{
-	int ret, i, attrcount = 0;
-	const struct iio_chan_spec_ext_info *ext_info;
-
-	if (chan->channel < 0)
-		return 0;
-
-	ret = __iio_add_chan_devattr(iio_data_type_name[chan->processed_val],
-				     chan,
-				     &iio_read_channel_info,
-				     (chan->output ?
-				      &iio_write_channel_info : NULL),
-				     0,
-				     0,
-				     &indio_dev->dev,
-				     &indio_dev->channel_attr_list);
-	if (ret)
-		goto error_ret;
-	attrcount++;
-
-	for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) {
-		ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
-					     chan,
-					     &iio_read_channel_info,
-					     &iio_write_channel_info,
-					     i/2,
-					     !(i%2),
-					     &indio_dev->dev,
-					     &indio_dev->channel_attr_list);
-		if (ret == -EBUSY && (i%2 == 0)) {
-			ret = 0;
-			continue;
-		}
-		if (ret < 0)
-			goto error_ret;
-		attrcount++;
-	}
-
-	if (chan->ext_info) {
-		unsigned int i = 0;
-		for (ext_info = chan->ext_info; ext_info->name; ext_info++) {
-			ret = __iio_add_chan_devattr(ext_info->name,
-					chan,
-					ext_info->read ?
-					    &iio_read_channel_ext_info : NULL,
-					ext_info->write ?
-					    &iio_write_channel_ext_info : NULL,
-					i,
-					ext_info->shared,
-					&indio_dev->dev,
-					&indio_dev->channel_attr_list);
-			i++;
-			if (ret == -EBUSY && ext_info->shared)
-				continue;
-
-			if (ret)
-				goto error_ret;
-
-			attrcount++;
-		}
-	}
-
-	ret = attrcount;
-error_ret:
-	return ret;
-}
-
-static void iio_device_remove_and_free_read_attr(struct iio_dev *indio_dev,
-						 struct iio_dev_attr *p)
-{
-	kfree(p->dev_attr.attr.name);
-	kfree(p);
-}
-
-static ssize_t iio_show_dev_name(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	return sprintf(buf, "%s\n", indio_dev->name);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
-
-static int iio_device_register_sysfs(struct iio_dev *indio_dev)
-{
-	int i, ret = 0, attrcount, attrn, attrcount_orig = 0;
-	struct iio_dev_attr *p, *n;
-	struct attribute **attr;
-
-	/* First count elements in any existing group */
-	if (indio_dev->info->attrs) {
-		attr = indio_dev->info->attrs->attrs;
-		while (*attr++ != NULL)
-			attrcount_orig++;
-	}
-	attrcount = attrcount_orig;
-	/*
-	 * New channel registration method - relies on the fact a group does
-	 * not need to be initialized if it is name is NULL.
-	 */
-	INIT_LIST_HEAD(&indio_dev->channel_attr_list);
-	if (indio_dev->channels)
-		for (i = 0; i < indio_dev->num_channels; i++) {
-			ret = iio_device_add_channel_sysfs(indio_dev,
-							   &indio_dev
-							   ->channels[i]);
-			if (ret < 0)
-				goto error_clear_attrs;
-			attrcount += ret;
-		}
-
-	if (indio_dev->name)
-		attrcount++;
-
-	indio_dev->chan_attr_group.attrs = kcalloc(attrcount + 1,
-						   sizeof(indio_dev->chan_attr_group.attrs[0]),
-						   GFP_KERNEL);
-	if (indio_dev->chan_attr_group.attrs == NULL) {
-		ret = -ENOMEM;
-		goto error_clear_attrs;
-	}
-	/* Copy across original attributes */
-	if (indio_dev->info->attrs)
-		memcpy(indio_dev->chan_attr_group.attrs,
-		       indio_dev->info->attrs->attrs,
-		       sizeof(indio_dev->chan_attr_group.attrs[0])
-		       *attrcount_orig);
-	attrn = attrcount_orig;
-	/* Add all elements from the list. */
-	list_for_each_entry(p, &indio_dev->channel_attr_list, l)
-		indio_dev->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr;
-	if (indio_dev->name)
-		indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr;
-
-	indio_dev->groups[indio_dev->groupcounter++] =
-		&indio_dev->chan_attr_group;
-
-	return 0;
-
-error_clear_attrs:
-	list_for_each_entry_safe(p, n,
-				 &indio_dev->channel_attr_list, l) {
-		list_del(&p->l);
-		iio_device_remove_and_free_read_attr(indio_dev, p);
-	}
-
-	return ret;
-}
-
-static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
-{
-
-	struct iio_dev_attr *p, *n;
-
-	list_for_each_entry_safe(p, n, &indio_dev->channel_attr_list, l) {
-		list_del(&p->l);
-		iio_device_remove_and_free_read_attr(indio_dev, p);
-	}
-	kfree(indio_dev->chan_attr_group.attrs);
-}
-
-static void iio_dev_release(struct device *device)
-{
-	struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev);
-	cdev_del(&indio_dev->chrdev);
-	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
-		iio_device_unregister_trigger_consumer(indio_dev);
-	iio_device_unregister_eventset(indio_dev);
-	iio_device_unregister_sysfs(indio_dev);
-	iio_device_unregister_debugfs(indio_dev);
-}
-
-static struct device_type iio_dev_type = {
-	.name = "iio_device",
-	.release = iio_dev_release,
-};
-
-struct iio_dev *iio_allocate_device(int sizeof_priv)
-{
-	struct iio_dev *dev;
-	size_t alloc_size;
-
-	alloc_size = sizeof(struct iio_dev);
-	if (sizeof_priv) {
-		alloc_size = ALIGN(alloc_size, IIO_ALIGN);
-		alloc_size += sizeof_priv;
-	}
-	/* ensure 32-byte alignment of whole construct ? */
-	alloc_size += IIO_ALIGN - 1;
-
-	dev = kzalloc(alloc_size, GFP_KERNEL);
-
-	if (dev) {
-		dev->dev.groups = dev->groups;
-		dev->dev.type = &iio_dev_type;
-		dev->dev.bus = &iio_bus_type;
-		device_initialize(&dev->dev);
-		dev_set_drvdata(&dev->dev, (void *)dev);
-		mutex_init(&dev->mlock);
-		mutex_init(&dev->info_exist_lock);
-
-		dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
-		if (dev->id < 0) {
-			/* cannot use a dev_err as the name isn't available */
-			printk(KERN_ERR "Failed to get id\n");
-			kfree(dev);
-			return NULL;
-		}
-		dev_set_name(&dev->dev, "iio:device%d", dev->id);
-	}
-
-	return dev;
-}
-EXPORT_SYMBOL(iio_allocate_device);
-
-void iio_free_device(struct iio_dev *dev)
-{
-	if (dev) {
-		ida_simple_remove(&iio_ida, dev->id);
-		kfree(dev);
-	}
-}
-EXPORT_SYMBOL(iio_free_device);
-
-/**
- * iio_chrdev_open() - chrdev file open for buffer access and ioctls
- **/
-static int iio_chrdev_open(struct inode *inode, struct file *filp)
-{
-	struct iio_dev *indio_dev = container_of(inode->i_cdev,
-						struct iio_dev, chrdev);
-
-	if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags))
-		return -EBUSY;
-
-	filp->private_data = indio_dev;
-
-	return 0;
-}
-
-/**
- * iio_chrdev_release() - chrdev file close buffer access and ioctls
- **/
-static int iio_chrdev_release(struct inode *inode, struct file *filp)
-{
-	struct iio_dev *indio_dev = container_of(inode->i_cdev,
-						struct iio_dev, chrdev);
-	clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
-	return 0;
-}
-
-/* Somewhat of a cross file organization violation - ioctls here are actually
- * event related */
-static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
-	struct iio_dev *indio_dev = filp->private_data;
-	int __user *ip = (int __user *)arg;
-	int fd;
-
-	if (cmd == IIO_GET_EVENT_FD_IOCTL) {
-		fd = iio_event_getfd(indio_dev);
-		if (copy_to_user(ip, &fd, sizeof(fd)))
-			return -EFAULT;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static const struct file_operations iio_buffer_fileops = {
-	.read = iio_buffer_read_first_n_outer_addr,
-	.release = iio_chrdev_release,
-	.open = iio_chrdev_open,
-	.poll = iio_buffer_poll_addr,
-	.owner = THIS_MODULE,
-	.llseek = noop_llseek,
-	.unlocked_ioctl = iio_ioctl,
-	.compat_ioctl = iio_ioctl,
-};
-
-static const struct iio_buffer_setup_ops noop_ring_setup_ops;
-
-int iio_device_register(struct iio_dev *indio_dev)
-{
-	int ret;
-
-	/* configure elements for the chrdev */
-	indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
-
-	ret = iio_device_register_debugfs(indio_dev);
-	if (ret) {
-		dev_err(indio_dev->dev.parent,
-			"Failed to register debugfs interfaces\n");
-		goto error_ret;
-	}
-	ret = iio_device_register_sysfs(indio_dev);
-	if (ret) {
-		dev_err(indio_dev->dev.parent,
-			"Failed to register sysfs interfaces\n");
-		goto error_unreg_debugfs;
-	}
-	ret = iio_device_register_eventset(indio_dev);
-	if (ret) {
-		dev_err(indio_dev->dev.parent,
-			"Failed to register event set\n");
-		goto error_free_sysfs;
-	}
-	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
-		iio_device_register_trigger_consumer(indio_dev);
-
-	if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&
-		indio_dev->setup_ops == NULL)
-		indio_dev->setup_ops = &noop_ring_setup_ops;
-
-	ret = device_add(&indio_dev->dev);
-	if (ret < 0)
-		goto error_unreg_eventset;
-	cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
-	indio_dev->chrdev.owner = indio_dev->info->driver_module;
-	ret = cdev_add(&indio_dev->chrdev, indio_dev->dev.devt, 1);
-	if (ret < 0)
-		goto error_del_device;
-	return 0;
-
-error_del_device:
-	device_del(&indio_dev->dev);
-error_unreg_eventset:
-	iio_device_unregister_eventset(indio_dev);
-error_free_sysfs:
-	iio_device_unregister_sysfs(indio_dev);
-error_unreg_debugfs:
-	iio_device_unregister_debugfs(indio_dev);
-error_ret:
-	return ret;
-}
-EXPORT_SYMBOL(iio_device_register);
-
-void iio_device_unregister(struct iio_dev *indio_dev)
-{
-	mutex_lock(&indio_dev->info_exist_lock);
-	indio_dev->info = NULL;
-	mutex_unlock(&indio_dev->info_exist_lock);
-	device_unregister(&indio_dev->dev);
-}
-EXPORT_SYMBOL(iio_device_unregister);
-subsys_initcall(iio_init);
-module_exit(iio_exit);
-
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
-MODULE_DESCRIPTION("Industrial I/O core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/industrialio-event.c b/drivers/staging/iio/industrialio-event.c
deleted file mode 100644
index 5fdf739..0000000
--- a/drivers/staging/iio/industrialio-event.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/* Industrial I/O event handling
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
- *
- * Based on elements of hwmon and input subsystems.
- */
-
-#include <linux/anon_inodes.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/kfifo.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/wait.h>
-#include "iio.h"
-#include "iio_core.h"
-#include "sysfs.h"
-#include "events.h"
-
-/**
- * struct iio_event_interface - chrdev interface for an event line
- * @wait:		wait queue to allow blocking reads of events
- * @det_events:		list of detected events
- * @dev_attr_list:	list of event interface sysfs attribute
- * @flags:		file operations related flags including busy flag.
- * @group:		event interface sysfs attribute group
- */
-struct iio_event_interface {
-	wait_queue_head_t	wait;
-	DECLARE_KFIFO(det_events, struct iio_event_data, 16);
-
-	struct list_head	dev_attr_list;
-	unsigned long		flags;
-	struct attribute_group	group;
-};
-
-int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
-{
-	struct iio_event_interface *ev_int = indio_dev->event_interface;
-	struct iio_event_data ev;
-	int copied;
-
-	/* Does anyone care? */
-	spin_lock(&ev_int->wait.lock);
-	if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
-
-		ev.id = ev_code;
-		ev.timestamp = timestamp;
-
-		copied = kfifo_put(&ev_int->det_events, &ev);
-		if (copied != 0)
-			wake_up_locked_poll(&ev_int->wait, POLLIN);
-	}
-	spin_unlock(&ev_int->wait.lock);
-
-	return 0;
-}
-EXPORT_SYMBOL(iio_push_event);
-
-/**
- * iio_event_poll() - poll the event queue to find out if it has data
- */
-static unsigned int iio_event_poll(struct file *filep,
-			     struct poll_table_struct *wait)
-{
-	struct iio_event_interface *ev_int = filep->private_data;
-	unsigned int events = 0;
-
-	poll_wait(filep, &ev_int->wait, wait);
-
-	spin_lock(&ev_int->wait.lock);
-	if (!kfifo_is_empty(&ev_int->det_events))
-		events = POLLIN | POLLRDNORM;
-	spin_unlock(&ev_int->wait.lock);
-
-	return events;
-}
-
-static ssize_t iio_event_chrdev_read(struct file *filep,
-				     char __user *buf,
-				     size_t count,
-				     loff_t *f_ps)
-{
-	struct iio_event_interface *ev_int = filep->private_data;
-	unsigned int copied;
-	int ret;
-
-	if (count < sizeof(struct iio_event_data))
-		return -EINVAL;
-
-	spin_lock(&ev_int->wait.lock);
-	if (kfifo_is_empty(&ev_int->det_events)) {
-		if (filep->f_flags & O_NONBLOCK) {
-			ret = -EAGAIN;
-			goto error_unlock;
-		}
-		/* Blocking on device; waiting for something to be there */
-		ret = wait_event_interruptible_locked(ev_int->wait,
-					!kfifo_is_empty(&ev_int->det_events));
-		if (ret)
-			goto error_unlock;
-		/* Single access device so no one else can get the data */
-	}
-
-	ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
-
-error_unlock:
-	spin_unlock(&ev_int->wait.lock);
-
-	return ret ? ret : copied;
-}
-
-static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
-{
-	struct iio_event_interface *ev_int = filep->private_data;
-
-	spin_lock(&ev_int->wait.lock);
-	__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
-	/*
-	 * In order to maintain a clean state for reopening,
-	 * clear out any awaiting events. The mask will prevent
-	 * any new __iio_push_event calls running.
-	 */
-	kfifo_reset_out(&ev_int->det_events);
-	spin_unlock(&ev_int->wait.lock);
-
-	return 0;
-}
-
-static const struct file_operations iio_event_chrdev_fileops = {
-	.read =  iio_event_chrdev_read,
-	.poll =  iio_event_poll,
-	.release = iio_event_chrdev_release,
-	.owner = THIS_MODULE,
-	.llseek = noop_llseek,
-};
-
-int iio_event_getfd(struct iio_dev *indio_dev)
-{
-	struct iio_event_interface *ev_int = indio_dev->event_interface;
-	int fd;
-
-	if (ev_int == NULL)
-		return -ENODEV;
-
-	spin_lock(&ev_int->wait.lock);
-	if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
-		spin_unlock(&ev_int->wait.lock);
-		return -EBUSY;
-	}
-	spin_unlock(&ev_int->wait.lock);
-	fd = anon_inode_getfd("iio:event",
-				&iio_event_chrdev_fileops, ev_int, O_RDONLY);
-	if (fd < 0) {
-		spin_lock(&ev_int->wait.lock);
-		__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
-		spin_unlock(&ev_int->wait.lock);
-	}
-	return fd;
-}
-
-static const char * const iio_ev_type_text[] = {
-	[IIO_EV_TYPE_THRESH] = "thresh",
-	[IIO_EV_TYPE_MAG] = "mag",
-	[IIO_EV_TYPE_ROC] = "roc",
-	[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
-	[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
-};
-
-static const char * const iio_ev_dir_text[] = {
-	[IIO_EV_DIR_EITHER] = "either",
-	[IIO_EV_DIR_RISING] = "rising",
-	[IIO_EV_DIR_FALLING] = "falling"
-};
-
-static ssize_t iio_ev_state_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf,
-				  size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int ret;
-	bool val;
-
-	ret = strtobool(buf, &val);
-	if (ret < 0)
-		return ret;
-
-	ret = indio_dev->info->write_event_config(indio_dev,
-						  this_attr->address,
-						  val);
-	return (ret < 0) ? ret : len;
-}
-
-static ssize_t iio_ev_state_show(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int val = indio_dev->info->read_event_config(indio_dev,
-						     this_attr->address);
-
-	if (val < 0)
-		return val;
-	else
-		return sprintf(buf, "%d\n", val);
-}
-
-static ssize_t iio_ev_value_show(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int val, ret;
-
-	ret = indio_dev->info->read_event_value(indio_dev,
-						this_attr->address, &val);
-	if (ret < 0)
-		return ret;
-
-	return sprintf(buf, "%d\n", val);
-}
-
-static ssize_t iio_ev_value_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf,
-				  size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	unsigned long val;
-	int ret;
-
-	if (!indio_dev->info->write_event_value)
-		return -EINVAL;
-
-	ret = strict_strtoul(buf, 10, &val);
-	if (ret)
-		return ret;
-
-	ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
-						 val);
-	if (ret < 0)
-		return ret;
-
-	return len;
-}
-
-static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
-				      struct iio_chan_spec const *chan)
-{
-	int ret = 0, i, attrcount = 0;
-	u64 mask = 0;
-	char *postfix;
-	if (!chan->event_mask)
-		return 0;
-
-	for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
-		postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
-				    iio_ev_type_text[i/IIO_EV_DIR_MAX],
-				    iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
-		if (postfix == NULL) {
-			ret = -ENOMEM;
-			goto error_ret;
-		}
-		if (chan->modified)
-			mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
-						  i/IIO_EV_DIR_MAX,
-						  i%IIO_EV_DIR_MAX);
-		else if (chan->differential)
-			mask = IIO_EVENT_CODE(chan->type,
-					      0, 0,
-					      i%IIO_EV_DIR_MAX,
-					      i/IIO_EV_DIR_MAX,
-					      0,
-					      chan->channel,
-					      chan->channel2);
-		else
-			mask = IIO_UNMOD_EVENT_CODE(chan->type,
-						    chan->channel,
-						    i/IIO_EV_DIR_MAX,
-						    i%IIO_EV_DIR_MAX);
-
-		ret = __iio_add_chan_devattr(postfix,
-					     chan,
-					     &iio_ev_state_show,
-					     iio_ev_state_store,
-					     mask,
-					     0,
-					     &indio_dev->dev,
-					     &indio_dev->event_interface->
-					     dev_attr_list);
-		kfree(postfix);
-		if (ret)
-			goto error_ret;
-		attrcount++;
-		postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
-				    iio_ev_type_text[i/IIO_EV_DIR_MAX],
-				    iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
-		if (postfix == NULL) {
-			ret = -ENOMEM;
-			goto error_ret;
-		}
-		ret = __iio_add_chan_devattr(postfix, chan,
-					     iio_ev_value_show,
-					     iio_ev_value_store,
-					     mask,
-					     0,
-					     &indio_dev->dev,
-					     &indio_dev->event_interface->
-					     dev_attr_list);
-		kfree(postfix);
-		if (ret)
-			goto error_ret;
-		attrcount++;
-	}
-	ret = attrcount;
-error_ret:
-	return ret;
-}
-
-static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev)
-{
-	struct iio_dev_attr *p, *n;
-	list_for_each_entry_safe(p, n,
-				 &indio_dev->event_interface->
-				 dev_attr_list, l) {
-		kfree(p->dev_attr.attr.name);
-		kfree(p);
-	}
-}
-
-static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
-{
-	int j, ret, attrcount = 0;
-
-	INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
-	/* Dynically created from the channels array */
-	for (j = 0; j < indio_dev->num_channels; j++) {
-		ret = iio_device_add_event_sysfs(indio_dev,
-						 &indio_dev->channels[j]);
-		if (ret < 0)
-			goto error_clear_attrs;
-		attrcount += ret;
-	}
-	return attrcount;
-
-error_clear_attrs:
-	__iio_remove_event_config_attrs(indio_dev);
-
-	return ret;
-}
-
-static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
-{
-	int j;
-
-	for (j = 0; j < indio_dev->num_channels; j++)
-		if (indio_dev->channels[j].event_mask != 0)
-			return true;
-	return false;
-}
-
-static void iio_setup_ev_int(struct iio_event_interface *ev_int)
-{
-	INIT_KFIFO(ev_int->det_events);
-	init_waitqueue_head(&ev_int->wait);
-}
-
-static const char *iio_event_group_name = "events";
-int iio_device_register_eventset(struct iio_dev *indio_dev)
-{
-	struct iio_dev_attr *p;
-	int ret = 0, attrcount_orig = 0, attrcount, attrn;
-	struct attribute **attr;
-
-	if (!(indio_dev->info->event_attrs ||
-	      iio_check_for_dynamic_events(indio_dev)))
-		return 0;
-
-	indio_dev->event_interface =
-		kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
-	if (indio_dev->event_interface == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	iio_setup_ev_int(indio_dev->event_interface);
-	if (indio_dev->info->event_attrs != NULL) {
-		attr = indio_dev->info->event_attrs->attrs;
-		while (*attr++ != NULL)
-			attrcount_orig++;
-	}
-	attrcount = attrcount_orig;
-	if (indio_dev->channels) {
-		ret = __iio_add_event_config_attrs(indio_dev);
-		if (ret < 0)
-			goto error_free_setup_event_lines;
-		attrcount += ret;
-	}
-
-	indio_dev->event_interface->group.name = iio_event_group_name;
-	indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1,
-							  sizeof(indio_dev->event_interface->group.attrs[0]),
-							  GFP_KERNEL);
-	if (indio_dev->event_interface->group.attrs == NULL) {
-		ret = -ENOMEM;
-		goto error_free_setup_event_lines;
-	}
-	if (indio_dev->info->event_attrs)
-		memcpy(indio_dev->event_interface->group.attrs,
-		       indio_dev->info->event_attrs->attrs,
-		       sizeof(indio_dev->event_interface->group.attrs[0])
-		       *attrcount_orig);
-	attrn = attrcount_orig;
-	/* Add all elements from the list. */
-	list_for_each_entry(p,
-			    &indio_dev->event_interface->dev_attr_list,
-			    l)
-		indio_dev->event_interface->group.attrs[attrn++] =
-			&p->dev_attr.attr;
-	indio_dev->groups[indio_dev->groupcounter++] =
-		&indio_dev->event_interface->group;
-
-	return 0;
-
-error_free_setup_event_lines:
-	__iio_remove_event_config_attrs(indio_dev);
-	kfree(indio_dev->event_interface);
-error_ret:
-
-	return ret;
-}
-
-void iio_device_unregister_eventset(struct iio_dev *indio_dev)
-{
-	if (indio_dev->event_interface == NULL)
-		return;
-	__iio_remove_event_config_attrs(indio_dev);
-	kfree(indio_dev->event_interface->group.attrs);
-	kfree(indio_dev->event_interface);
-}
diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/staging/iio/industrialio-trigger.c
deleted file mode 100644
index 47ecadd..0000000
--- a/drivers/staging/iio/industrialio-trigger.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/* The industrial I/O core, trigger handling functions
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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/idr.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-
-#include "iio.h"
-#include "trigger.h"
-#include "iio_core.h"
-#include "iio_core_trigger.h"
-#include "trigger_consumer.h"
-
-/* RFC - Question of approach
- * Make the common case (single sensor single trigger)
- * simple by starting trigger capture from when first sensors
- * is added.
- *
- * Complex simultaneous start requires use of 'hold' functionality
- * of the trigger. (not implemented)
- *
- * Any other suggestions?
- */
-
-static DEFINE_IDA(iio_trigger_ida);
-
-/* Single list of all available triggers */
-static LIST_HEAD(iio_trigger_list);
-static DEFINE_MUTEX(iio_trigger_list_lock);
-
-/**
- * iio_trigger_read_name() - retrieve useful identifying name
- **/
-static ssize_t iio_trigger_read_name(struct device *dev,
-				     struct device_attribute *attr,
-				     char *buf)
-{
-	struct iio_trigger *trig = dev_get_drvdata(dev);
-	return sprintf(buf, "%s\n", trig->name);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
-
-/**
- * iio_trigger_register_sysfs() - create a device for this trigger
- * @trig_info:	the trigger
- *
- * Also adds any control attribute registered by the trigger driver
- **/
-static int iio_trigger_register_sysfs(struct iio_trigger *trig_info)
-{
-	return sysfs_add_file_to_group(&trig_info->dev.kobj,
-				       &dev_attr_name.attr,
-				       NULL);
-}
-
-static void iio_trigger_unregister_sysfs(struct iio_trigger *trig_info)
-{
-	sysfs_remove_file_from_group(&trig_info->dev.kobj,
-					   &dev_attr_name.attr,
-					   NULL);
-}
-
-int iio_trigger_register(struct iio_trigger *trig_info)
-{
-	int ret;
-
-	trig_info->id = ida_simple_get(&iio_trigger_ida, 0, 0, GFP_KERNEL);
-	if (trig_info->id < 0) {
-		ret = trig_info->id;
-		goto error_ret;
-	}
-	/* Set the name used for the sysfs directory etc */
-	dev_set_name(&trig_info->dev, "trigger%ld",
-		     (unsigned long) trig_info->id);
-
-	ret = device_add(&trig_info->dev);
-	if (ret)
-		goto error_unregister_id;
-
-	ret = iio_trigger_register_sysfs(trig_info);
-	if (ret)
-		goto error_device_del;
-
-	/* Add to list of available triggers held by the IIO core */
-	mutex_lock(&iio_trigger_list_lock);
-	list_add_tail(&trig_info->list, &iio_trigger_list);
-	mutex_unlock(&iio_trigger_list_lock);
-
-	return 0;
-
-error_device_del:
-	device_del(&trig_info->dev);
-error_unregister_id:
-	ida_simple_remove(&iio_trigger_ida, trig_info->id);
-error_ret:
-	return ret;
-}
-EXPORT_SYMBOL(iio_trigger_register);
-
-void iio_trigger_unregister(struct iio_trigger *trig_info)
-{
-	mutex_lock(&iio_trigger_list_lock);
-	list_del(&trig_info->list);
-	mutex_unlock(&iio_trigger_list_lock);
-
-	iio_trigger_unregister_sysfs(trig_info);
-	ida_simple_remove(&iio_trigger_ida, trig_info->id);
-	/* Possible issue in here */
-	device_unregister(&trig_info->dev);
-}
-EXPORT_SYMBOL(iio_trigger_unregister);
-
-static struct iio_trigger *iio_trigger_find_by_name(const char *name,
-						    size_t len)
-{
-	struct iio_trigger *trig = NULL, *iter;
-
-	mutex_lock(&iio_trigger_list_lock);
-	list_for_each_entry(iter, &iio_trigger_list, list)
-		if (sysfs_streq(iter->name, name)) {
-			trig = iter;
-			break;
-		}
-	mutex_unlock(&iio_trigger_list_lock);
-
-	return trig;
-}
-
-void iio_trigger_poll(struct iio_trigger *trig, s64 time)
-{
-	int i;
-	if (!trig->use_count)
-		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
-			if (trig->subirqs[i].enabled) {
-				trig->use_count++;
-				generic_handle_irq(trig->subirq_base + i);
-			}
-}
-EXPORT_SYMBOL(iio_trigger_poll);
-
-irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private)
-{
-	iio_trigger_poll(private, iio_get_time_ns());
-	return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll);
-
-void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time)
-{
-	int i;
-	if (!trig->use_count)
-		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
-			if (trig->subirqs[i].enabled) {
-				trig->use_count++;
-				handle_nested_irq(trig->subirq_base + i);
-			}
-}
-EXPORT_SYMBOL(iio_trigger_poll_chained);
-
-void iio_trigger_notify_done(struct iio_trigger *trig)
-{
-	trig->use_count--;
-	if (trig->use_count == 0 && trig->ops && trig->ops->try_reenable)
-		if (trig->ops->try_reenable(trig))
-			/* Missed and interrupt so launch new poll now */
-			iio_trigger_poll(trig, 0);
-}
-EXPORT_SYMBOL(iio_trigger_notify_done);
-
-/* Trigger Consumer related functions */
-static int iio_trigger_get_irq(struct iio_trigger *trig)
-{
-	int ret;
-	mutex_lock(&trig->pool_lock);
-	ret = bitmap_find_free_region(trig->pool,
-				      CONFIG_IIO_CONSUMERS_PER_TRIGGER,
-				      ilog2(1));
-	mutex_unlock(&trig->pool_lock);
-	if (ret >= 0)
-		ret += trig->subirq_base;
-
-	return ret;
-}
-
-static void iio_trigger_put_irq(struct iio_trigger *trig, int irq)
-{
-	mutex_lock(&trig->pool_lock);
-	clear_bit(irq - trig->subirq_base, trig->pool);
-	mutex_unlock(&trig->pool_lock);
-}
-
-/* Complexity in here.  With certain triggers (datardy) an acknowledgement
- * may be needed if the pollfuncs do not include the data read for the
- * triggering device.
- * This is not currently handled.  Alternative of not enabling trigger unless
- * the relevant function is in there may be the best option.
- */
-/* Worth protecting against double additions?*/
-static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
-					struct iio_poll_func *pf)
-{
-	int ret = 0;
-	bool notinuse
-		= bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
-
-	/* Prevent the module being removed whilst attached to a trigger */
-	__module_get(pf->indio_dev->info->driver_module);
-	pf->irq = iio_trigger_get_irq(trig);
-	ret = request_threaded_irq(pf->irq, pf->h, pf->thread,
-				   pf->type, pf->name,
-				   pf);
-	if (ret < 0) {
-		module_put(pf->indio_dev->info->driver_module);
-		return ret;
-	}
-
-	if (trig->ops && trig->ops->set_trigger_state && notinuse) {
-		ret = trig->ops->set_trigger_state(trig, true);
-		if (ret < 0)
-			module_put(pf->indio_dev->info->driver_module);
-	}
-
-	return ret;
-}
-
-static int iio_trigger_dettach_poll_func(struct iio_trigger *trig,
-					 struct iio_poll_func *pf)
-{
-	int ret = 0;
-	bool no_other_users
-		= (bitmap_weight(trig->pool,
-				 CONFIG_IIO_CONSUMERS_PER_TRIGGER)
-		   == 1);
-	if (trig->ops && trig->ops->set_trigger_state && no_other_users) {
-		ret = trig->ops->set_trigger_state(trig, false);
-		if (ret)
-			goto error_ret;
-	}
-	iio_trigger_put_irq(trig, pf->irq);
-	free_irq(pf->irq, pf);
-	module_put(pf->indio_dev->info->driver_module);
-
-error_ret:
-	return ret;
-}
-
-irqreturn_t iio_pollfunc_store_time(int irq, void *p)
-{
-	struct iio_poll_func *pf = p;
-	pf->timestamp = iio_get_time_ns();
-	return IRQ_WAKE_THREAD;
-}
-EXPORT_SYMBOL(iio_pollfunc_store_time);
-
-struct iio_poll_func
-*iio_alloc_pollfunc(irqreturn_t (*h)(int irq, void *p),
-		    irqreturn_t (*thread)(int irq, void *p),
-		    int type,
-		    struct iio_dev *indio_dev,
-		    const char *fmt,
-		    ...)
-{
-	va_list vargs;
-	struct iio_poll_func *pf;
-
-	pf = kmalloc(sizeof *pf, GFP_KERNEL);
-	if (pf == NULL)
-		return NULL;
-	va_start(vargs, fmt);
-	pf->name = kvasprintf(GFP_KERNEL, fmt, vargs);
-	va_end(vargs);
-	if (pf->name == NULL) {
-		kfree(pf);
-		return NULL;
-	}
-	pf->h = h;
-	pf->thread = thread;
-	pf->type = type;
-	pf->indio_dev = indio_dev;
-
-	return pf;
-}
-EXPORT_SYMBOL_GPL(iio_alloc_pollfunc);
-
-void iio_dealloc_pollfunc(struct iio_poll_func *pf)
-{
-	kfree(pf->name);
-	kfree(pf);
-}
-EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc);
-
-/**
- * iio_trigger_read_current() - trigger consumer sysfs query which trigger
- *
- * For trigger consumers the current_trigger interface allows the trigger
- * used by the device to be queried.
- **/
-static ssize_t iio_trigger_read_current(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-
-	if (indio_dev->trig)
-		return sprintf(buf, "%s\n", indio_dev->trig->name);
-	return 0;
-}
-
-/**
- * iio_trigger_write_current() trigger consumer sysfs set current trigger
- *
- * For trigger consumers the current_trigger interface allows the trigger
- * used for this device to be specified at run time based on the triggers
- * name.
- **/
-static ssize_t iio_trigger_write_current(struct device *dev,
-					 struct device_attribute *attr,
-					 const char *buf,
-					 size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_trigger *oldtrig = indio_dev->trig;
-	struct iio_trigger *trig;
-	int ret;
-
-	mutex_lock(&indio_dev->mlock);
-	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
-		mutex_unlock(&indio_dev->mlock);
-		return -EBUSY;
-	}
-	mutex_unlock(&indio_dev->mlock);
-
-	trig = iio_trigger_find_by_name(buf, len);
-	if (oldtrig == trig)
-		return len;
-
-	if (trig && indio_dev->info->validate_trigger) {
-		ret = indio_dev->info->validate_trigger(indio_dev, trig);
-		if (ret)
-			return ret;
-	}
-
-	if (trig && trig->ops && trig->ops->validate_device) {
-		ret = trig->ops->validate_device(trig, indio_dev);
-		if (ret)
-			return ret;
-	}
-
-	indio_dev->trig = trig;
-
-	if (oldtrig && indio_dev->trig != oldtrig)
-		iio_put_trigger(oldtrig);
-	if (indio_dev->trig)
-		iio_get_trigger(indio_dev->trig);
-
-	return len;
-}
-
-static DEVICE_ATTR(current_trigger, S_IRUGO | S_IWUSR,
-		   iio_trigger_read_current,
-		   iio_trigger_write_current);
-
-static struct attribute *iio_trigger_consumer_attrs[] = {
-	&dev_attr_current_trigger.attr,
-	NULL,
-};
-
-static const struct attribute_group iio_trigger_consumer_attr_group = {
-	.name = "trigger",
-	.attrs = iio_trigger_consumer_attrs,
-};
-
-static void iio_trig_release(struct device *device)
-{
-	struct iio_trigger *trig = to_iio_trigger(device);
-	int i;
-
-	if (trig->subirq_base) {
-		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
-			irq_modify_status(trig->subirq_base + i,
-					  IRQ_NOAUTOEN,
-					  IRQ_NOREQUEST | IRQ_NOPROBE);
-			irq_set_chip(trig->subirq_base + i,
-				     NULL);
-			irq_set_handler(trig->subirq_base + i,
-					NULL);
-		}
-
-		irq_free_descs(trig->subirq_base,
-			       CONFIG_IIO_CONSUMERS_PER_TRIGGER);
-	}
-	kfree(trig->name);
-	kfree(trig);
-}
-
-static struct device_type iio_trig_type = {
-	.release = iio_trig_release,
-};
-
-static void iio_trig_subirqmask(struct irq_data *d)
-{
-	struct irq_chip *chip = irq_data_get_irq_chip(d);
-	struct iio_trigger *trig
-		= container_of(chip,
-			       struct iio_trigger, subirq_chip);
-	trig->subirqs[d->irq - trig->subirq_base].enabled = false;
-}
-
-static void iio_trig_subirqunmask(struct irq_data *d)
-{
-	struct irq_chip *chip = irq_data_get_irq_chip(d);
-	struct iio_trigger *trig
-		= container_of(chip,
-			       struct iio_trigger, subirq_chip);
-	trig->subirqs[d->irq - trig->subirq_base].enabled = true;
-}
-
-struct iio_trigger *iio_allocate_trigger(const char *fmt, ...)
-{
-	va_list vargs;
-	struct iio_trigger *trig;
-	trig = kzalloc(sizeof *trig, GFP_KERNEL);
-	if (trig) {
-		int i;
-		trig->dev.type = &iio_trig_type;
-		trig->dev.bus = &iio_bus_type;
-		device_initialize(&trig->dev);
-		dev_set_drvdata(&trig->dev, (void *)trig);
-
-		mutex_init(&trig->pool_lock);
-		trig->subirq_base
-			= irq_alloc_descs(-1, 0,
-					  CONFIG_IIO_CONSUMERS_PER_TRIGGER,
-					  0);
-		if (trig->subirq_base < 0) {
-			kfree(trig);
-			return NULL;
-		}
-		va_start(vargs, fmt);
-		trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
-		va_end(vargs);
-		if (trig->name == NULL) {
-			irq_free_descs(trig->subirq_base,
-				       CONFIG_IIO_CONSUMERS_PER_TRIGGER);
-			kfree(trig);
-			return NULL;
-		}
-		trig->subirq_chip.name = trig->name;
-		trig->subirq_chip.irq_mask = &iio_trig_subirqmask;
-		trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask;
-		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
-			irq_set_chip(trig->subirq_base + i,
-				     &trig->subirq_chip);
-			irq_set_handler(trig->subirq_base + i,
-					&handle_simple_irq);
-			irq_modify_status(trig->subirq_base + i,
-					  IRQ_NOREQUEST | IRQ_NOAUTOEN,
-					  IRQ_NOPROBE);
-		}
-		get_device(&trig->dev);
-	}
-	return trig;
-}
-EXPORT_SYMBOL(iio_allocate_trigger);
-
-void iio_free_trigger(struct iio_trigger *trig)
-{
-	if (trig)
-		put_device(&trig->dev);
-}
-EXPORT_SYMBOL(iio_free_trigger);
-
-void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
-{
-	indio_dev->groups[indio_dev->groupcounter++] =
-		&iio_trigger_consumer_attr_group;
-}
-
-void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
-{
-	/* Clean up and associated but not attached triggers references */
-	if (indio_dev->trig)
-		iio_put_trigger(indio_dev->trig);
-}
-
-int iio_triggered_buffer_postenable(struct iio_dev *indio_dev)
-{
-	return iio_trigger_attach_poll_func(indio_dev->trig,
-					    indio_dev->pollfunc);
-}
-EXPORT_SYMBOL(iio_triggered_buffer_postenable);
-
-int iio_triggered_buffer_predisable(struct iio_dev *indio_dev)
-{
-	return iio_trigger_dettach_poll_func(indio_dev->trig,
-					     indio_dev->pollfunc);
-}
-EXPORT_SYMBOL(iio_triggered_buffer_predisable);
diff --git a/drivers/staging/iio/inkern.c b/drivers/staging/iio/inkern.c
deleted file mode 100644
index ef07a02..0000000
--- a/drivers/staging/iio/inkern.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/* The industrial I/O core in kernel channel mapping
- *
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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/err.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include "iio.h"
-#include "iio_core.h"
-#include "machine.h"
-#include "driver.h"
-#include "consumer.h"
-
-struct iio_map_internal {
-	struct iio_dev *indio_dev;
-	struct iio_map *map;
-	struct list_head l;
-};
-
-static LIST_HEAD(iio_map_list);
-static DEFINE_MUTEX(iio_map_list_lock);
-
-int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps)
-{
-	int i = 0, ret = 0;
-	struct iio_map_internal *mapi;
-
-	if (maps == NULL)
-		return 0;
-
-	mutex_lock(&iio_map_list_lock);
-	while (maps[i].consumer_dev_name != NULL) {
-		mapi = kzalloc(sizeof(*mapi), GFP_KERNEL);
-		if (mapi == NULL) {
-			ret = -ENOMEM;
-			goto error_ret;
-		}
-		mapi->map = &maps[i];
-		mapi->indio_dev = indio_dev;
-		list_add(&mapi->l, &iio_map_list);
-		i++;
-	}
-error_ret:
-	mutex_unlock(&iio_map_list_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(iio_map_array_register);
-
-
-/* Assumes the exact same array (e.g. memory locations)
- * used at unregistration as used at registration rather than
- * more complex checking of contents.
- */
-int iio_map_array_unregister(struct iio_dev *indio_dev,
-			     struct iio_map *maps)
-{
-	int i = 0, ret = 0;
-	bool found_it;
-	struct iio_map_internal *mapi;
-
-	if (maps == NULL)
-		return 0;
-
-	mutex_lock(&iio_map_list_lock);
-	while (maps[i].consumer_dev_name != NULL) {
-		found_it = false;
-		list_for_each_entry(mapi, &iio_map_list, l)
-			if (&maps[i] == mapi->map) {
-				list_del(&mapi->l);
-				kfree(mapi);
-				found_it = true;
-				break;
-			}
-		if (found_it == false) {
-			ret = -ENODEV;
-			goto error_ret;
-		}
-		i++;
-	}
-error_ret:
-	mutex_unlock(&iio_map_list_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(iio_map_array_unregister);
-
-static const struct iio_chan_spec
-*iio_chan_spec_from_name(const struct iio_dev *indio_dev,
-			 const char *name)
-{
-	int i;
-	const struct iio_chan_spec *chan = NULL;
-
-	for (i = 0; i < indio_dev->num_channels; i++)
-		if (indio_dev->channels[i].datasheet_name &&
-		    strcmp(name, indio_dev->channels[i].datasheet_name) == 0) {
-			chan = &indio_dev->channels[i];
-			break;
-		}
-	return chan;
-}
-
-
-struct iio_channel *iio_st_channel_get(const char *name,
-				       const char *channel_name)
-{
-	struct iio_map_internal *c_i = NULL, *c = NULL;
-	struct iio_channel *channel;
-
-	if (name == NULL && channel_name == NULL)
-		return ERR_PTR(-ENODEV);
-
-	/* first find matching entry the channel map */
-	mutex_lock(&iio_map_list_lock);
-	list_for_each_entry(c_i, &iio_map_list, l) {
-		if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) ||
-		    (channel_name &&
-		     strcmp(channel_name, c_i->map->consumer_channel) != 0))
-			continue;
-		c = c_i;
-		get_device(&c->indio_dev->dev);
-		break;
-	}
-	mutex_unlock(&iio_map_list_lock);
-	if (c == NULL)
-		return ERR_PTR(-ENODEV);
-
-	channel = kmalloc(sizeof(*channel), GFP_KERNEL);
-	if (channel == NULL)
-		return ERR_PTR(-ENOMEM);
-
-	channel->indio_dev = c->indio_dev;
-
-	if (c->map->adc_channel_label)
-		channel->channel =
-			iio_chan_spec_from_name(channel->indio_dev,
-						c->map->adc_channel_label);
-
-	return channel;
-}
-EXPORT_SYMBOL_GPL(iio_st_channel_get);
-
-void iio_st_channel_release(struct iio_channel *channel)
-{
-	put_device(&channel->indio_dev->dev);
-	kfree(channel);
-}
-EXPORT_SYMBOL_GPL(iio_st_channel_release);
-
-struct iio_channel *iio_st_channel_get_all(const char *name)
-{
-	struct iio_channel *chans;
-	struct iio_map_internal *c = NULL;
-	int nummaps = 0;
-	int mapind = 0;
-	int i, ret;
-
-	if (name == NULL)
-		return ERR_PTR(-EINVAL);
-
-	mutex_lock(&iio_map_list_lock);
-	/* first count the matching maps */
-	list_for_each_entry(c, &iio_map_list, l)
-		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
-			continue;
-		else
-			nummaps++;
-
-	if (nummaps == 0) {
-		ret = -ENODEV;
-		goto error_ret;
-	}
-
-	/* NULL terminated array to save passing size */
-	chans = kzalloc(sizeof(*chans)*(nummaps + 1), GFP_KERNEL);
-	if (chans == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	/* for each map fill in the chans element */
-	list_for_each_entry(c, &iio_map_list, l) {
-		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
-			continue;
-		chans[mapind].indio_dev = c->indio_dev;
-		chans[mapind].channel =
-			iio_chan_spec_from_name(chans[mapind].indio_dev,
-						c->map->adc_channel_label);
-		if (chans[mapind].channel == NULL) {
-			ret = -EINVAL;
-			put_device(&chans[mapind].indio_dev->dev);
-			goto error_free_chans;
-		}
-		get_device(&chans[mapind].indio_dev->dev);
-		mapind++;
-	}
-	mutex_unlock(&iio_map_list_lock);
-	if (mapind == 0) {
-		ret = -ENODEV;
-		goto error_free_chans;
-	}
-	return chans;
-
-error_free_chans:
-	for (i = 0; i < nummaps; i++)
-		if (chans[i].indio_dev)
-			put_device(&chans[i].indio_dev->dev);
-	kfree(chans);
-error_ret:
-	mutex_unlock(&iio_map_list_lock);
-
-	return ERR_PTR(ret);
-}
-EXPORT_SYMBOL_GPL(iio_st_channel_get_all);
-
-void iio_st_channel_release_all(struct iio_channel *channels)
-{
-	struct iio_channel *chan = &channels[0];
-
-	while (chan->indio_dev) {
-		put_device(&chan->indio_dev->dev);
-		chan++;
-	}
-	kfree(channels);
-}
-EXPORT_SYMBOL_GPL(iio_st_channel_release_all);
-
-int iio_st_read_channel_raw(struct iio_channel *chan, int *val)
-{
-	int val2, ret;
-
-	mutex_lock(&chan->indio_dev->info_exist_lock);
-	if (chan->indio_dev->info == NULL) {
-		ret = -ENODEV;
-		goto err_unlock;
-	}
-
-	ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
-					      val, &val2, 0);
-err_unlock:
-	mutex_unlock(&chan->indio_dev->info_exist_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(iio_st_read_channel_raw);
-
-int iio_st_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
-{
-	int ret;
-
-	mutex_lock(&chan->indio_dev->info_exist_lock);
-	if (chan->indio_dev->info == NULL) {
-		ret = -ENODEV;
-		goto err_unlock;
-	}
-
-	ret = chan->indio_dev->info->read_raw(chan->indio_dev,
-					      chan->channel,
-					      val, val2,
-					      IIO_CHAN_INFO_SCALE);
-err_unlock:
-	mutex_unlock(&chan->indio_dev->info_exist_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(iio_st_read_channel_scale);
-
-int iio_st_get_channel_type(struct iio_channel *chan,
-			    enum iio_chan_type *type)
-{
-	int ret = 0;
-	/* Need to verify underlying driver has not gone away */
-
-	mutex_lock(&chan->indio_dev->info_exist_lock);
-	if (chan->indio_dev->info == NULL) {
-		ret = -ENODEV;
-		goto err_unlock;
-	}
-
-	*type = chan->channel->type;
-err_unlock:
-	mutex_unlock(&chan->indio_dev->info_exist_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(iio_st_get_channel_type);
diff --git a/drivers/staging/iio/kfifo_buf.c b/drivers/staging/iio/kfifo_buf.c
deleted file mode 100644
index 9f3bd59..0000000
--- a/drivers/staging/iio/kfifo_buf.c
+++ /dev/null
@@ -1,151 +0,0 @@
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/kfifo.h>
-#include <linux/mutex.h>
-
-#include "kfifo_buf.h"
-
-struct iio_kfifo {
-	struct iio_buffer buffer;
-	struct kfifo kf;
-	int update_needed;
-};
-
-#define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer)
-
-static inline int __iio_allocate_kfifo(struct iio_kfifo *buf,
-				int bytes_per_datum, int length)
-{
-	if ((length == 0) || (bytes_per_datum == 0))
-		return -EINVAL;
-
-	__iio_update_buffer(&buf->buffer, bytes_per_datum, length);
-	return kfifo_alloc(&buf->kf, bytes_per_datum*length, GFP_KERNEL);
-}
-
-static int iio_request_update_kfifo(struct iio_buffer *r)
-{
-	int ret = 0;
-	struct iio_kfifo *buf = iio_to_kfifo(r);
-
-	if (!buf->update_needed)
-		goto error_ret;
-	kfifo_free(&buf->kf);
-	ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
-				   buf->buffer.length);
-error_ret:
-	return ret;
-}
-
-static int iio_get_length_kfifo(struct iio_buffer *r)
-{
-	return r->length;
-}
-
-static IIO_BUFFER_ENABLE_ATTR;
-static IIO_BUFFER_LENGTH_ATTR;
-
-static struct attribute *iio_kfifo_attributes[] = {
-	&dev_attr_length.attr,
-	&dev_attr_enable.attr,
-	NULL,
-};
-
-static struct attribute_group iio_kfifo_attribute_group = {
-	.attrs = iio_kfifo_attributes,
-	.name = "buffer",
-};
-
-static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r)
-{
-	return r->bytes_per_datum;
-}
-
-static int iio_mark_update_needed_kfifo(struct iio_buffer *r)
-{
-	struct iio_kfifo *kf = iio_to_kfifo(r);
-	kf->update_needed = true;
-	return 0;
-}
-
-static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd)
-{
-	if (r->bytes_per_datum != bpd) {
-		r->bytes_per_datum = bpd;
-		iio_mark_update_needed_kfifo(r);
-	}
-	return 0;
-}
-
-static int iio_set_length_kfifo(struct iio_buffer *r, int length)
-{
-	if (r->length != length) {
-		r->length = length;
-		iio_mark_update_needed_kfifo(r);
-	}
-	return 0;
-}
-
-static int iio_store_to_kfifo(struct iio_buffer *r,
-			      u8 *data,
-			      s64 timestamp)
-{
-	int ret;
-	struct iio_kfifo *kf = iio_to_kfifo(r);
-	ret = kfifo_in(&kf->kf, data, r->bytes_per_datum);
-	if (ret != r->bytes_per_datum)
-		return -EBUSY;
-	return 0;
-}
-
-static int iio_read_first_n_kfifo(struct iio_buffer *r,
-			   size_t n, char __user *buf)
-{
-	int ret, copied;
-	struct iio_kfifo *kf = iio_to_kfifo(r);
-
-	if (n < r->bytes_per_datum)
-		return -EINVAL;
-
-	n = rounddown(n, r->bytes_per_datum);
-	ret = kfifo_to_user(&kf->kf, buf, n, &copied);
-
-	return copied;
-}
-
-static const struct iio_buffer_access_funcs kfifo_access_funcs = {
-	.store_to = &iio_store_to_kfifo,
-	.read_first_n = &iio_read_first_n_kfifo,
-	.request_update = &iio_request_update_kfifo,
-	.get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo,
-	.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
-	.get_length = &iio_get_length_kfifo,
-	.set_length = &iio_set_length_kfifo,
-};
-
-struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
-{
-	struct iio_kfifo *kf;
-
-	kf = kzalloc(sizeof *kf, GFP_KERNEL);
-	if (!kf)
-		return NULL;
-	kf->update_needed = true;
-	iio_buffer_init(&kf->buffer);
-	kf->buffer.attrs = &iio_kfifo_attribute_group;
-	kf->buffer.access = &kfifo_access_funcs;
-
-	return &kf->buffer;
-}
-EXPORT_SYMBOL(iio_kfifo_allocate);
-
-void iio_kfifo_free(struct iio_buffer *r)
-{
-	kfree(iio_to_kfifo(r));
-}
-EXPORT_SYMBOL(iio_kfifo_free);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/kfifo_buf.h b/drivers/staging/iio/kfifo_buf.h
deleted file mode 100644
index 9f7da01..0000000
--- a/drivers/staging/iio/kfifo_buf.h
+++ /dev/null
@@ -1,8 +0,0 @@
-
-#include <linux/kfifo.h>
-#include "iio.h"
-#include "buffer.h"
-
-struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
-void iio_kfifo_free(struct iio_buffer *r);
-
diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig
index e7e9159..4bed30e 100644
--- a/drivers/staging/iio/light/Kconfig
+++ b/drivers/staging/iio/light/Kconfig
@@ -4,15 +4,26 @@
 menu "Light sensors"
 
 config SENSORS_ISL29018
-        tristate "ISL 29018 light and proximity sensor"
-        depends on I2C
-        default n
-        help
-         If you say yes here you get support for ambient light sensing and
-         proximity infrared sensing from Intersil ISL29018.
-         This driver will provide the measurements of ambient light intensity
-         in lux, proximity infrared sensing and normal infrared sensing.
-         Data from sensor is accessible via sysfs.
+	tristate "ISL 29018 light and proximity sensor"
+	depends on I2C
+	select REGMAP_I2C
+	default n
+	help
+	 If you say yes here you get support for ambient light sensing and
+	 proximity infrared sensing from Intersil ISL29018.
+	 This driver will provide the measurements of ambient light intensity
+	 in lux, proximity infrared sensing and normal infrared sensing.
+	 Data from sensor is accessible via sysfs.
+
+config SENSORS_ISL29028
+	tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	 Provides driver for the Intersil's ISL29028 device.
+	 This driver supports the sysfs interface to get the ALS, IR intensity,
+	 Proximity value via iio. The ISL29028 provides the concurrent sensing
+	 of ambient light and proximity.
 
 config SENSORS_TSL2563
 	tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors"
@@ -31,4 +42,12 @@
 	 Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices.
 	 Access ALS data via iio, sysfs.
 
+config TSL2x7x
+	tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors"
+	depends on I2C
+	help
+	 Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672,
+	 tmd2672, tsl2772, tmd2772 devices.
+	 Provides iio_events and direct access via sysfs.
+
 endmenu
diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile
index 3011fbf..141af1e 100644
--- a/drivers/staging/iio/light/Makefile
+++ b/drivers/staging/iio/light/Makefile
@@ -4,4 +4,6 @@
 
 obj-$(CONFIG_SENSORS_TSL2563)	+= tsl2563.o
 obj-$(CONFIG_SENSORS_ISL29018)	+= isl29018.o
+obj-$(CONFIG_SENSORS_ISL29028)	+= isl29028.o
 obj-$(CONFIG_TSL2583)	+= tsl2583.o
+obj-$(CONFIG_TSL2x7x)	+= tsl2x7x_core.o
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 38ec52b6..0abbf18 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -26,9 +26,11 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
 #define CONVERSION_TIME_MS		100
 
 #define ISL29018_REG_ADD_COMMAND1	0x00
@@ -51,49 +53,22 @@
 
 #define ISL29018_REG_ADD_DATA_LSB	0x02
 #define ISL29018_REG_ADD_DATA_MSB	0x03
-#define ISL29018_MAX_REGS		(ISL29018_REG_ADD_DATA_MSB+1)
 
 #define ISL29018_REG_TEST		0x08
 #define ISL29018_TEST_SHIFT		0
 #define ISL29018_TEST_MASK		(0xFF << ISL29018_TEST_SHIFT)
 
 struct isl29018_chip {
-	struct i2c_client	*client;
+	struct device		*dev;
+	struct regmap		*regmap;
 	struct mutex		lock;
 	unsigned int		lux_scale;
 	unsigned int		range;
 	unsigned int		adc_bit;
 	int			prox_scheme;
-	u8			reg_cache[ISL29018_MAX_REGS];
 };
 
-static int isl29018_write_data(struct i2c_client *client, u8 reg,
-			u8 val, u8 mask, u8 shift)
-{
-	u8 regval = val;
-	int ret;
-	struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client));
-
-	/* don't cache or mask REG_TEST */
-	if (reg < ISL29018_MAX_REGS) {
-		regval = chip->reg_cache[reg];
-		regval &= ~mask;
-		regval |= val << shift;
-	}
-
-	ret = i2c_smbus_write_byte_data(client, reg, regval);
-	if (ret) {
-		dev_err(&client->dev, "Write to device fails status %x\n", ret);
-	} else {
-		/* don't update cache on err */
-		if (reg < ISL29018_MAX_REGS)
-			chip->reg_cache[reg] = regval;
-	}
-
-	return ret;
-}
-
-static int isl29018_set_range(struct i2c_client *client, unsigned long range,
+static int isl29018_set_range(struct isl29018_chip *chip, unsigned long range,
 		unsigned int *new_range)
 {
 	static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000};
@@ -109,11 +84,11 @@
 	if (i >= ARRAY_SIZE(supp_ranges))
 		return -EINVAL;
 
-	return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
-			i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT);
+	return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+			COMMANDII_RANGE_MASK, i << COMMANDII_RANGE_SHIFT);
 }
 
-static int isl29018_set_resolution(struct i2c_client *client,
+static int isl29018_set_resolution(struct isl29018_chip *chip,
 			unsigned long adcbit, unsigned int *conf_adc_bit)
 {
 	static const unsigned long supp_adcbit[] = {16, 12, 8, 4};
@@ -129,48 +104,49 @@
 	if (i >= ARRAY_SIZE(supp_adcbit))
 		return -EINVAL;
 
-	return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
-			i, COMMANDII_RESOLUTION_MASK,
-			COMMANDII_RESOLUTION_SHIFT);
+	return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+			COMMANDII_RESOLUTION_MASK,
+			i << COMMANDII_RESOLUTION_SHIFT);
 }
 
-static int isl29018_read_sensor_input(struct i2c_client *client, int mode)
+static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode)
 {
 	int status;
-	int lsb;
-	int msb;
+	unsigned int lsb;
+	unsigned int msb;
 
 	/* Set mode */
-	status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1,
-			mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT);
+	status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1,
+			mode << COMMMAND1_OPMODE_SHIFT);
 	if (status) {
-		dev_err(&client->dev, "Error in setting operating mode\n");
+		dev_err(chip->dev,
+			"Error in setting operating mode err %d\n", status);
 		return status;
 	}
 	msleep(CONVERSION_TIME_MS);
-	lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB);
-	if (lsb < 0) {
-		dev_err(&client->dev, "Error in reading LSB DATA\n");
-		return lsb;
+	status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb);
+	if (status < 0) {
+		dev_err(chip->dev,
+			"Error in reading LSB DATA with err %d\n", status);
+		return status;
 	}
 
-	msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB);
-	if (msb < 0) {
-		dev_err(&client->dev, "Error in reading MSB DATA\n");
-		return msb;
+	status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb);
+	if (status < 0) {
+		dev_err(chip->dev,
+			"Error in reading MSB DATA with error %d\n", status);
+		return status;
 	}
-	dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
+	dev_vdbg(chip->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
 
 	return (msb << 8) | lsb;
 }
 
-static int isl29018_read_lux(struct i2c_client *client, int *lux)
+static int isl29018_read_lux(struct isl29018_chip *chip, int *lux)
 {
 	int lux_data;
-	struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client));
 
-	lux_data = isl29018_read_sensor_input(client,
-				COMMMAND1_OPMODE_ALS_ONCE);
+	lux_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_ALS_ONCE);
 
 	if (lux_data < 0)
 		return lux_data;
@@ -180,11 +156,11 @@
 	return 0;
 }
 
-static int isl29018_read_ir(struct i2c_client *client, int *ir)
+static int isl29018_read_ir(struct isl29018_chip *chip, int *ir)
 {
 	int ir_data;
 
-	ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE);
+	ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE);
 
 	if (ir_data < 0)
 		return ir_data;
@@ -194,7 +170,7 @@
 	return 0;
 }
 
-static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
+static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme,
 		int *near_ir)
 {
 	int status;
@@ -202,14 +178,15 @@
 	int ir_data = -1;
 
 	/* Do proximity sensing with required scheme */
-	status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
-			scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT);
+	status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+			COMMANDII_SCHEME_MASK,
+			scheme << COMMANDII_SCHEME_SHIFT);
 	if (status) {
-		dev_err(&client->dev, "Error in setting operating mode\n");
+		dev_err(chip->dev, "Error in setting operating mode\n");
 		return status;
 	}
 
-	prox_data = isl29018_read_sensor_input(client,
+	prox_data = isl29018_read_sensor_input(chip,
 					COMMMAND1_OPMODE_PROX_ONCE);
 	if (prox_data < 0)
 		return prox_data;
@@ -219,8 +196,7 @@
 		return 0;
 	}
 
-	ir_data = isl29018_read_sensor_input(client,
-				COMMMAND1_OPMODE_IR_ONCE);
+	ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE);
 
 	if (ir_data < 0)
 		return ir_data;
@@ -238,7 +214,7 @@
 static ssize_t show_range(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct isl29018_chip *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%u\n", chip->range);
@@ -247,9 +223,8 @@
 static ssize_t store_range(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct isl29018_chip *chip = iio_priv(indio_dev);
-	struct i2c_client *client = chip->client;
 	int status;
 	unsigned long lval;
 	unsigned int new_range;
@@ -264,10 +239,11 @@
 	}
 
 	mutex_lock(&chip->lock);
-	status = isl29018_set_range(client, lval, &new_range);
+	status = isl29018_set_range(chip, lval, &new_range);
 	if (status < 0) {
 		mutex_unlock(&chip->lock);
-		dev_err(dev, "Error in setting max range\n");
+		dev_err(dev,
+			"Error in setting max range with err %d\n", status);
 		return status;
 	}
 	chip->range = new_range;
@@ -280,7 +256,7 @@
 static ssize_t show_resolution(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct isl29018_chip *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%u\n", chip->adc_bit);
@@ -289,9 +265,8 @@
 static ssize_t store_resolution(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct isl29018_chip *chip = iio_priv(indio_dev);
-	struct i2c_client *client = chip->client;
 	int status;
 	unsigned long lval;
 	unsigned int new_adc_bit;
@@ -304,7 +279,7 @@
 	}
 
 	mutex_lock(&chip->lock);
-	status = isl29018_set_resolution(client, lval, &new_adc_bit);
+	status = isl29018_set_resolution(chip, lval, &new_adc_bit);
 	if (status < 0) {
 		mutex_unlock(&chip->lock);
 		dev_err(dev, "Error in setting resolution\n");
@@ -320,7 +295,7 @@
 static ssize_t show_prox_infrared_supression(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct isl29018_chip *chip = iio_priv(indio_dev);
 
 	/* return the "proximity scheme" i.e. if the chip does on chip
@@ -331,7 +306,7 @@
 static ssize_t store_prox_infrared_supression(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct isl29018_chip *chip = iio_priv(indio_dev);
 	unsigned long lval;
 
@@ -379,20 +354,20 @@
 {
 	int ret = -EINVAL;
 	struct isl29018_chip *chip = iio_priv(indio_dev);
-	struct i2c_client *client = chip->client;
 
 	mutex_lock(&chip->lock);
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_PROCESSED:
 		switch (chan->type) {
 		case IIO_LIGHT:
-			ret = isl29018_read_lux(client, val);
+			ret = isl29018_read_lux(chip, val);
 			break;
 		case IIO_INTENSITY:
-			ret = isl29018_read_ir(client, val);
+			ret = isl29018_read_ir(chip, val);
 			break;
 		case IIO_PROXIMITY:
-			ret = isl29018_read_proximity_ir(client,
+			ret = isl29018_read_proximity_ir(chip,
 					chip->prox_scheme, val);
 			break;
 		default:
@@ -419,15 +394,17 @@
 		.type = IIO_LIGHT,
 		.indexed = 1,
 		.channel = 0,
-		.processed_val = IIO_PROCESSED,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
 	}, {
 		.type = IIO_INTENSITY,
 		.modified = 1,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 		.channel2 = IIO_MOD_LIGHT_IR,
 	}, {
 		/* Unindexed in current ABI.  But perhaps it should be. */
 		.type = IIO_PROXIMITY,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 	}
 };
 
@@ -456,15 +433,12 @@
 	.attrs = isl29018_attributes,
 };
 
-static int isl29018_chip_init(struct i2c_client *client)
+static int isl29018_chip_init(struct isl29018_chip *chip)
 {
-	struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client));
 	int status;
 	int new_adc_bit;
 	unsigned int new_range;
 
-	memset(chip->reg_cache, 0, sizeof(chip->reg_cache));
-
 	/* Code added per Intersil Application Note 1534:
 	 *     When VDD sinks to approximately 1.8V or below, some of
 	 * the part's registers may change their state. When VDD
@@ -485,10 +459,9 @@
 	 * the same thing EXCEPT the data sheet asks for a 1ms delay after
 	 * writing the CMD1 register.
 	 */
-	status = isl29018_write_data(client, ISL29018_REG_TEST, 0,
-				ISL29018_TEST_MASK, ISL29018_TEST_SHIFT);
+	status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0);
 	if (status < 0) {
-		dev_err(&client->dev, "Failed to clear isl29018 TEST reg."
+		dev_err(chip->dev, "Failed to clear isl29018 TEST reg."
 					"(%d)\n", status);
 		return status;
 	}
@@ -497,10 +470,9 @@
 	 * "Operating Mode" (COMMAND1) register is reprogrammed when
 	 * data is read from the device.
 	 */
-	status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, 0,
-				0xff, 0);
+	status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0);
 	if (status < 0) {
-		dev_err(&client->dev, "Failed to clear isl29018 CMD1 reg."
+		dev_err(chip->dev, "Failed to clear isl29018 CMD1 reg."
 					"(%d)\n", status);
 		return status;
 	}
@@ -508,13 +480,13 @@
 	msleep(1);	/* per data sheet, page 10 */
 
 	/* set defaults */
-	status = isl29018_set_range(client, chip->range, &new_range);
+	status = isl29018_set_range(chip, chip->range, &new_range);
 	if (status < 0) {
-		dev_err(&client->dev, "Init of isl29018 fails\n");
+		dev_err(chip->dev, "Init of isl29018 fails\n");
 		return status;
 	}
 
-	status = isl29018_set_resolution(client, chip->adc_bit,
+	status = isl29018_set_resolution(chip, chip->adc_bit,
 						&new_adc_bit);
 
 	return 0;
@@ -527,6 +499,32 @@
 	.write_raw = &isl29018_write_raw,
 };
 
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ISL29018_REG_ADD_DATA_LSB:
+	case ISL29018_REG_ADD_DATA_MSB:
+	case ISL29018_REG_ADD_COMMAND1:
+	case ISL29018_REG_TEST:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/*
+ * isl29018_regmap_config: regmap configuration.
+ * Use RBTREE mechanism for caching.
+ */
+static const struct regmap_config isl29018_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_reg = is_volatile_reg,
+	.max_register = ISL29018_REG_TEST,
+	.num_reg_defaults_raw = ISL29018_REG_TEST + 1,
+	.cache_type = REGCACHE_RBTREE,
+};
+
 static int __devinit isl29018_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
@@ -534,7 +532,7 @@
 	struct iio_dev *indio_dev;
 	int err;
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		dev_err(&client->dev, "iio allocation fails\n");
 		err = -ENOMEM;
@@ -543,7 +541,7 @@
 	chip = iio_priv(indio_dev);
 
 	i2c_set_clientdata(client, indio_dev);
-	chip->client = client;
+	chip->dev = &client->dev;
 
 	mutex_init(&chip->lock);
 
@@ -551,7 +549,14 @@
 	chip->range = 1000;
 	chip->adc_bit = 16;
 
-	err = isl29018_chip_init(client);
+	chip->regmap = devm_regmap_init_i2c(client, &isl29018_regmap_config);
+	if (IS_ERR(chip->regmap)) {
+		err = PTR_ERR(chip->regmap);
+		dev_err(chip->dev, "regmap initialization failed: %d\n", err);
+		goto exit;
+	}
+
+	err = isl29018_chip_init(chip);
 	if (err)
 		goto exit_iio_free;
 
@@ -569,7 +574,7 @@
 
 	return 0;
 exit_iio_free:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 exit:
 	return err;
 }
@@ -580,7 +585,7 @@
 
 	dev_dbg(&client->dev, "%s()\n", __func__);
 	iio_device_unregister(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
@@ -593,7 +598,7 @@
 MODULE_DEVICE_TABLE(i2c, isl29018_id);
 
 static const struct of_device_id isl29018_of_match[] = {
-	{ .compatible = "invn,isl29018", },
+	{ .compatible = "isil,isl29018", },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, isl29018_of_match);
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
new file mode 100644
index 0000000..33a4c3f
--- /dev/null
+++ b/drivers/staging/iio/light/isl29028.c
@@ -0,0 +1,566 @@
+/*
+ * IIO driver for the light sensor ISL29028.
+ * ISL29028 is Concurrent Ambient Light and Proximity Sensor
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define CONVERSION_TIME_MS		100
+
+#define ISL29028_REG_CONFIGURE		0x01
+
+#define CONFIGURE_ALS_IR_MODE_ALS	0
+#define CONFIGURE_ALS_IR_MODE_IR	BIT(0)
+#define CONFIGURE_ALS_IR_MODE_MASK	BIT(0)
+
+#define CONFIGURE_ALS_RANGE_LOW_LUX	0
+#define CONFIGURE_ALS_RANGE_HIGH_LUX	BIT(1)
+#define CONFIGURE_ALS_RANGE_MASK	BIT(1)
+
+#define CONFIGURE_ALS_DIS		0
+#define CONFIGURE_ALS_EN		BIT(2)
+#define CONFIGURE_ALS_EN_MASK		BIT(2)
+
+#define CONFIGURE_PROX_DRIVE		BIT(3)
+
+#define CONFIGURE_PROX_SLP_SH		4
+#define CONFIGURE_PROX_SLP_MASK		(7 << CONFIGURE_PROX_SLP_SH)
+
+#define CONFIGURE_PROX_EN		BIT(7)
+#define CONFIGURE_PROX_EN_MASK		BIT(7)
+
+#define ISL29028_REG_INTERRUPT		0x02
+
+#define ISL29028_REG_PROX_DATA		0x08
+#define ISL29028_REG_ALSIR_L		0x09
+#define ISL29028_REG_ALSIR_U		0x0A
+
+#define ISL29028_REG_TEST1_MODE		0x0E
+#define ISL29028_REG_TEST2_MODE		0x0F
+
+#define ISL29028_NUM_REGS		(ISL29028_REG_TEST2_MODE + 1)
+
+enum als_ir_mode {
+	MODE_NONE = 0,
+	MODE_ALS,
+	MODE_IR
+};
+
+struct isl29028_chip {
+	struct device		*dev;
+	struct mutex		lock;
+	struct regmap		*regmap;
+
+	unsigned int		prox_sampling;
+	bool			enable_prox;
+
+	int			lux_scale;
+	int			als_ir_mode;
+};
+
+static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
+			unsigned int sampling)
+{
+	static unsigned int prox_period[] = {800, 400, 200, 100, 75, 50, 12, 0};
+	int sel;
+	unsigned int period = DIV_ROUND_UP(1000, sampling);
+
+	for (sel = 0; sel < ARRAY_SIZE(prox_period); ++sel) {
+		if (period >= prox_period[sel])
+			break;
+	}
+	return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+			CONFIGURE_PROX_SLP_MASK, sel << CONFIGURE_PROX_SLP_SH);
+}
+
+static int isl29028_enable_proximity(struct isl29028_chip *chip, bool enable)
+{
+	int ret;
+	int val = 0;
+
+	if (enable)
+		val = CONFIGURE_PROX_EN;
+	ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+			CONFIGURE_PROX_EN_MASK, val);
+	if (ret < 0)
+		return ret;
+
+	/* Wait for conversion to be complete for first sample */
+	mdelay(DIV_ROUND_UP(1000, chip->prox_sampling));
+	return 0;
+}
+
+static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale)
+{
+	int val = (lux_scale == 2000) ? CONFIGURE_ALS_RANGE_HIGH_LUX :
+					CONFIGURE_ALS_RANGE_LOW_LUX;
+
+	return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+		CONFIGURE_ALS_RANGE_MASK, val);
+}
+
+static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
+	enum als_ir_mode mode)
+{
+	int ret = 0;
+
+	switch (mode) {
+	case MODE_ALS:
+		ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+			CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_ALS);
+		if (ret < 0)
+			return ret;
+
+		ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+			CONFIGURE_ALS_RANGE_MASK, CONFIGURE_ALS_RANGE_HIGH_LUX);
+		break;
+
+	case MODE_IR:
+		ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+			CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_IR);
+		break;
+
+	case MODE_NONE:
+		return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+			CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_DIS);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	/* Enable the ALS/IR */
+	ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+			CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_EN);
+	if (ret < 0)
+		return ret;
+
+	/* Need to wait for conversion time if ALS/IR mode enabled */
+	mdelay(CONVERSION_TIME_MS);
+	return 0;
+}
+
+static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
+{
+	unsigned int lsb;
+	unsigned int msb;
+	int ret;
+
+	ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);
+	if (ret < 0) {
+		dev_err(chip->dev,
+			"Error in reading register ALSIR_L err %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);
+	if (ret < 0) {
+		dev_err(chip->dev,
+			"Error in reading register ALSIR_U err %d\n", ret);
+		return ret;
+	}
+
+	*als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF);
+	return 0;
+}
+
+static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox)
+{
+	unsigned int data;
+	int ret;
+
+	ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);
+	if (ret < 0) {
+		dev_err(chip->dev, "Error in reading register %d, error %d\n",
+				ISL29028_REG_PROX_DATA, ret);
+		return ret;
+	}
+	*prox = data;
+	return 0;
+}
+
+static int isl29028_proxim_get(struct isl29028_chip *chip, int *prox_data)
+{
+	int ret;
+
+	if (!chip->enable_prox) {
+		ret = isl29028_enable_proximity(chip, true);
+		if (ret < 0)
+			return ret;
+		chip->enable_prox = true;
+	}
+	return isl29028_read_proxim(chip, prox_data);
+}
+
+static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
+{
+	int ret;
+	int als_ir_data;
+
+	if (chip->als_ir_mode != MODE_ALS) {
+		ret = isl29028_set_als_ir_mode(chip, MODE_ALS);
+		if (ret < 0) {
+			dev_err(chip->dev,
+				"Error in enabling ALS mode err %d\n", ret);
+			return ret;
+		}
+		chip->als_ir_mode = MODE_ALS;
+	}
+
+	ret = isl29028_read_als_ir(chip, &als_ir_data);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * convert als data count to lux.
+	 * if lux_scale = 125,  lux = count * 0.031
+	 * if lux_scale = 2000, lux = count * 0.49
+	 */
+	if (chip->lux_scale == 125)
+		als_ir_data = (als_ir_data * 31) / 1000;
+	else
+		als_ir_data = (als_ir_data * 49) / 100;
+
+	*als_data = als_ir_data;
+	return 0;
+}
+
+static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
+{
+	int ret;
+
+	if (chip->als_ir_mode != MODE_IR) {
+		ret = isl29028_set_als_ir_mode(chip, MODE_IR);
+		if (ret < 0) {
+			dev_err(chip->dev,
+				"Error in enabling IR mode err %d\n", ret);
+			return ret;
+		}
+		chip->als_ir_mode = MODE_IR;
+	}
+	return isl29028_read_als_ir(chip, ir_data);
+}
+
+/* Channel IO */
+static int isl29028_write_raw(struct iio_dev *indio_dev,
+	     struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	struct isl29028_chip *chip = iio_priv(indio_dev);
+	int ret = -EINVAL;
+
+	mutex_lock(&chip->lock);
+	switch (chan->type) {
+	case IIO_PROXIMITY:
+		if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
+			dev_err(chip->dev,
+				"proximity: mask value 0x%08lx not supported\n",
+				mask);
+			break;
+		}
+		if (val < 1 || val > 100) {
+			dev_err(chip->dev,
+				"Samp_freq %d is not in range[1:100]\n", val);
+			break;
+		}
+		ret = isl29028_set_proxim_sampling(chip, val);
+		if (ret < 0) {
+			dev_err(chip->dev,
+				"Setting proximity samp_freq fail, err %d\n",
+				ret);
+			break;
+		}
+		chip->prox_sampling = val;
+		break;
+
+	case IIO_LIGHT:
+		if (mask != IIO_CHAN_INFO_SCALE) {
+			dev_err(chip->dev,
+				"light: mask value 0x%08lx not supported\n",
+				mask);
+			break;
+		}
+		if ((val != 125) && (val != 2000)) {
+			dev_err(chip->dev,
+				"lux scale %d is invalid [125, 2000]\n", val);
+			break;
+		}
+		ret = isl29028_set_als_scale(chip, val);
+		if (ret < 0) {
+			dev_err(chip->dev,
+				"Setting lux scale fail with error %d\n", ret);
+			break;
+		}
+		chip->lux_scale = val;
+		break;
+
+	default:
+		dev_err(chip->dev, "Unsupported channel type\n");
+		break;
+	}
+	mutex_unlock(&chip->lock);
+	return ret;
+}
+
+static int isl29028_read_raw(struct iio_dev *indio_dev,
+	     struct iio_chan_spec const *chan, int *val, int *val2, long mask)
+{
+	struct isl29028_chip *chip = iio_priv(indio_dev);
+	int ret = -EINVAL;
+
+	mutex_lock(&chip->lock);
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_LIGHT:
+			ret = isl29028_als_get(chip, val);
+			break;
+		case IIO_INTENSITY:
+			ret = isl29028_ir_get(chip, val);
+			break;
+		case IIO_PROXIMITY:
+			ret = isl29028_proxim_get(chip, val);
+			break;
+		default:
+			break;
+		}
+		if (ret < 0)
+			break;
+		ret = IIO_VAL_INT;
+		break;
+
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		if (chan->type != IIO_PROXIMITY)
+			break;
+		*val = chip->prox_sampling;
+		ret = IIO_VAL_INT;
+		break;
+
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type != IIO_LIGHT)
+			break;
+		*val = chip->lux_scale;
+		ret = IIO_VAL_INT;
+		break;
+
+	default:
+		dev_err(chip->dev, "mask value 0x%08lx not supported\n", mask);
+		break;
+	}
+	mutex_unlock(&chip->lock);
+	return ret;
+}
+
+static IIO_CONST_ATTR(in_proximity_sampling_frequency_available,
+				"1, 3, 5, 10, 13, 20, 83, 100");
+static IIO_CONST_ATTR(in_illuminance_scale_available, "125, 2000");
+
+#define ISL29028_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
+#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
+static struct attribute *isl29028_attributes[] = {
+	ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available),
+	ISL29028_CONST_ATTR(in_illuminance_scale_available),
+	NULL,
+};
+
+static const struct attribute_group isl29108_group = {
+	.attrs = isl29028_attributes,
+};
+
+static const struct iio_chan_spec isl29028_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT |
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+	}, {
+		.type = IIO_INTENSITY,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+	}, {
+		.type = IIO_PROXIMITY,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SEPARATE_BIT,
+	}
+};
+
+static const struct iio_info isl29028_info = {
+	.attrs = &isl29108_group,
+	.driver_module = THIS_MODULE,
+	.read_raw = &isl29028_read_raw,
+	.write_raw = &isl29028_write_raw,
+};
+
+static int isl29028_chip_init(struct isl29028_chip *chip)
+{
+	int ret;
+
+	chip->enable_prox  = false;
+	chip->prox_sampling = 20;
+	chip->lux_scale = 2000;
+	chip->als_ir_mode = MODE_NONE;
+
+	ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
+	if (ret < 0) {
+		dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+			__func__, ISL29028_REG_TEST1_MODE, ret);
+		return ret;
+	}
+	ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
+	if (ret < 0) {
+		dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+			__func__, ISL29028_REG_TEST2_MODE, ret);
+		return ret;
+	}
+
+	ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
+	if (ret < 0) {
+		dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+			__func__, ISL29028_REG_CONFIGURE, ret);
+		return ret;
+	}
+
+	ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling);
+	if (ret < 0) {
+		dev_err(chip->dev, "%s(): setting the proximity, err = %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	ret = isl29028_set_als_scale(chip, chip->lux_scale);
+	if (ret < 0)
+		dev_err(chip->dev, "%s(): setting als scale failed, err = %d\n",
+			__func__, ret);
+	return ret;
+}
+
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ISL29028_REG_INTERRUPT:
+	case ISL29028_REG_PROX_DATA:
+	case ISL29028_REG_ALSIR_L:
+	case ISL29028_REG_ALSIR_U:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config isl29028_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_reg = is_volatile_reg,
+	.max_register = ISL29028_NUM_REGS - 1,
+	.num_reg_defaults_raw = ISL29028_NUM_REGS,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit isl29028_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct isl29028_chip *chip;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*chip));
+	if (!indio_dev) {
+		dev_err(&client->dev, "iio allocation fails\n");
+		return -ENOMEM;
+	}
+
+	chip = iio_priv(indio_dev);
+
+	i2c_set_clientdata(client, indio_dev);
+	chip->dev = &client->dev;
+	mutex_init(&chip->lock);
+
+	chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);
+	if (IS_ERR(chip->regmap)) {
+		ret = PTR_ERR(chip->regmap);
+		dev_err(chip->dev, "regmap initialization failed: %d\n", ret);
+		goto exit_iio_free;
+	}
+
+	ret = isl29028_chip_init(chip);
+	if (ret < 0) {
+		dev_err(chip->dev, "chip initialization failed: %d\n", ret);
+		goto exit_iio_free;
+	}
+
+	indio_dev->info = &isl29028_info;
+	indio_dev->channels = isl29028_channels;
+	indio_dev->num_channels = ARRAY_SIZE(isl29028_channels);
+	indio_dev->name = id->name;
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(chip->dev, "iio registration fails with error %d\n",
+			ret);
+		goto exit_iio_free;
+	}
+	return 0;
+
+exit_iio_free:
+	iio_device_free(indio_dev);
+	return ret;
+}
+
+static int __devexit isl29028_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	iio_device_free(indio_dev);
+	return 0;
+}
+
+static const struct i2c_device_id isl29028_id[] = {
+	{"isl29028", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, isl29028_id);
+
+static const struct of_device_id isl29028_of_match[] = {
+	{ .compatible = "isil,isl29028", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, isl29028_of_match);
+
+static struct i2c_driver isl29028_driver = {
+	.class	= I2C_CLASS_HWMON,
+	.driver  = {
+		.name = "isl29028",
+		.owner = THIS_MODULE,
+		.of_match_table = isl29028_of_match,
+	},
+	.probe	 = isl29028_probe,
+	.remove  = __devexit_p(isl29028_remove),
+	.id_table = isl29028_id,
+};
+
+module_i2c_driver(isl29028_driver);
+
+MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c
index 546c95a..9d740be 100644
--- a/drivers/staging/iio/light/tsl2563.c
+++ b/drivers/staging/iio/light/tsl2563.c
@@ -35,9 +35,9 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
 #include "tsl2563.h"
 
 /* Use this many bits for fraction part. */
@@ -465,7 +465,7 @@
 {
 	struct tsl2563_chip *chip = iio_priv(indio_dev);
 
-	if (chan->channel == 0)
+	if (chan->channel == IIO_MOD_LIGHT_BOTH)
 		chip->calib0 = calib_from_sysfs(val);
 	else
 		chip->calib1 = calib_from_sysfs(val);
@@ -485,7 +485,8 @@
 
 	mutex_lock(&chip->lock);
 	switch (m) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_PROCESSED:
 		switch (chan->type) {
 		case IIO_LIGHT:
 			ret = tsl2563_get_adc(chip);
@@ -534,12 +535,14 @@
 	{
 		.type = IIO_LIGHT,
 		.indexed = 1,
+		.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
 		.channel = 0,
 	}, {
 		.type = IIO_INTENSITY,
 		.modified = 1,
 		.channel2 = IIO_MOD_LIGHT_BOTH,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
 		.event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH,
 					  IIO_EV_DIR_RISING) |
 			       IIO_EV_BIT(IIO_EV_TYPE_THRESH,
@@ -548,7 +551,8 @@
 		.type = IIO_INTENSITY,
 		.modified = 1,
 		.channel2 = IIO_MOD_LIGHT_IR,
-		.info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
 	}
 };
 
@@ -710,7 +714,7 @@
 	int err = 0;
 	u8 id = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (!indio_dev)
 		return -ENOMEM;
 
@@ -797,7 +801,7 @@
 	if (client->irq)
 		free_irq(client->irq, indio_dev);
 fail1:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 	return err;
 }
 
@@ -818,7 +822,7 @@
 	if (client->irq)
 		free_irq(client->irq, indio_dev);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c
index 8671d98..5e23ad5 100644
--- a/drivers/staging/iio/light/tsl2583.c
+++ b/drivers/staging/iio/light/tsl2583.c
@@ -28,7 +28,7 @@
 #include <linux/unistd.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
 
 #define TSL258X_MAX_DEVICE_REGS		32
 
@@ -483,7 +483,7 @@
 static ssize_t taos_power_state_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", chip->taos_chip_status);
@@ -492,7 +492,7 @@
 static ssize_t taos_power_state_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	unsigned long value;
 
 	if (strict_strtoul(buf, 0, &value))
@@ -509,7 +509,7 @@
 static ssize_t taos_gain_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 	char gain[4] = {0};
 
@@ -534,7 +534,7 @@
 static ssize_t taos_gain_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 	unsigned long value;
 
@@ -571,7 +571,7 @@
 static ssize_t taos_als_time_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", chip->taos_settings.als_time);
@@ -580,7 +580,7 @@
 static ssize_t taos_als_time_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 	unsigned long value;
 
@@ -608,7 +608,7 @@
 static ssize_t taos_als_trim_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim);
@@ -617,7 +617,7 @@
 static ssize_t taos_als_trim_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 	unsigned long value;
 
@@ -633,7 +633,7 @@
 static ssize_t taos_als_cal_target_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 
 	return sprintf(buf, "%d\n", chip->taos_settings.als_cal_target);
@@ -642,7 +642,7 @@
 static ssize_t taos_als_cal_target_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 	unsigned long value;
 
@@ -660,7 +660,7 @@
 {
 	int ret;
 
-	ret = taos_get_lux(dev_get_drvdata(dev));
+	ret = taos_get_lux(dev_to_iio_dev(dev));
 	if (ret < 0)
 		return ret;
 
@@ -670,7 +670,7 @@
 static ssize_t taos_do_calibrate(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	unsigned long value;
 
 	if (strict_strtoul(buf, 0, &value))
@@ -708,7 +708,7 @@
 static ssize_t taos_luxtable_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 	int value[ARRAY_SIZE(taos_device_lux)*3 + 1];
 	int n;
@@ -815,7 +815,7 @@
 		return -EOPNOTSUPP;
 	}
 
-	indio_dev = iio_allocate_device(sizeof(*chip));
+	indio_dev = iio_device_alloc(sizeof(*chip));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		dev_err(&clientp->dev, "iio allocation failed\n");
@@ -879,7 +879,7 @@
 	dev_info(&clientp->dev, "Light sensor found.\n");
 	return 0;
 fail1:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 fail2:
 	return ret;
 }
@@ -926,7 +926,7 @@
 static int __devexit taos_remove(struct i2c_client *client)
 {
 	iio_device_unregister(i2c_get_clientdata(client));
-	iio_free_device(i2c_get_clientdata(client));
+	iio_device_free(i2c_get_clientdata(client));
 
 	return 0;
 }
diff --git a/drivers/staging/iio/light/tsl2x7x.h b/drivers/staging/iio/light/tsl2x7x.h
new file mode 100755
index 0000000..c4acf5f
--- /dev/null
+++ b/drivers/staging/iio/light/tsl2x7x.h
@@ -0,0 +1,100 @@
+/*
+ * Device driver for monitoring ambient light intensity (lux)
+ * and proximity (prox) within the TAOS TSL2X7X family of devices.
+ *
+ * Copyright (c) 2012, TAOS Corporation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA	02110-1301, USA.
+ */
+
+#ifndef __TSL2X7X_H
+#define __TSL2X7X_H
+#include <linux/pm.h>
+
+/* Max number of segments allowable in LUX table */
+#define TSL2X7X_MAX_LUX_TABLE_SIZE		9
+#define MAX_DEFAULT_TABLE_BYTES (sizeof(int) * TSL2X7X_MAX_LUX_TABLE_SIZE)
+
+struct iio_dev;
+
+struct tsl2x7x_lux {
+	unsigned int ratio;
+	unsigned int ch0;
+	unsigned int ch1;
+};
+
+/**
+ * struct tsl2x7x_default_settings - power on defaults unless
+ *                                   overridden by platform data.
+ *  @als_time:              ALS Integration time - multiple of 50mS
+ *  @als_gain:              Index into the ALS gain table.
+ *  @als_gain_trim:         default gain trim to account for
+ *                          aperture effects.
+ *  @wait_time:             Time between PRX and ALS cycles
+ *                          in 2.7 periods
+ *  @prx_time:              5.2ms prox integration time -
+ *                          decrease in 2.7ms periods
+ *  @prx_gain:              Proximity gain index
+ *  @prox_config:           Prox configuration filters.
+ *  @als_cal_target:        Known external ALS reading for
+ *                          calibration.
+ *  @interrupts_en:         Enable/Disable - 0x00 = none, 0x10 = als,
+ *                                           0x20 = prx,  0x30 = bth
+ *  @persistence:           H/W Filters, Number of 'out of limits'
+ *                          ADC readings PRX/ALS.
+ *  @als_thresh_low:        CH0 'low' count to trigger interrupt.
+ *  @als_thresh_high:       CH0 'high' count to trigger interrupt.
+ *  @prox_thres_low:        Low threshold proximity detection.
+ *  @prox_thres_high:       High threshold proximity detection
+ *  @prox_pulse_count:      Number if proximity emitter pulses
+ *  @prox_max_samples_cal:  Used for prox cal.
+ */
+struct tsl2x7x_settings {
+	int als_time;
+	int als_gain;
+	int als_gain_trim;
+	int wait_time;
+	int prx_time;
+	int prox_gain;
+	int prox_config;
+	int als_cal_target;
+	u8  interrupts_en;
+	u8  persistence;
+	int als_thresh_low;
+	int als_thresh_high;
+	int prox_thres_low;
+	int prox_thres_high;
+	int prox_pulse_count;
+	int prox_max_samples_cal;
+};
+
+/**
+ * struct tsl2X7X_platform_data - Platform callback, glass and defaults
+ * @platform_power:            Suspend/resume platform callback
+ * @power_on:                  Power on callback
+ * @power_off:                 Power off callback
+ * @platform_lux_table:        Device specific glass coefficents
+ * @platform_default_settings: Device specific power on defaults
+ *
+ */
+struct tsl2X7X_platform_data {
+	int (*platform_power)(struct device *dev, pm_message_t);
+	int (*power_on)      (struct iio_dev *indio_dev);
+	int (*power_off)     (struct i2c_client *dev);
+	struct tsl2x7x_lux platform_lux_table[TSL2X7X_MAX_LUX_TABLE_SIZE];
+	struct tsl2x7x_settings *platform_default_settings;
+};
+
+#endif /* __TSL2X7X_H */
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
new file mode 100755
index 0000000..c3b05a1
--- /dev/null
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -0,0 +1,2082 @@
+/*
+ * Device driver for monitoring ambient light intensity in (lux)
+ * and proximity detection (prox) within the TAOS TSL2X7X family of devices.
+ *
+ * Copyright (c) 2012, TAOS Corporation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA        02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include "tsl2x7x.h"
+
+/* Cal defs*/
+#define PROX_STAT_CAL        0
+#define PROX_STAT_SAMP       1
+#define MAX_SAMPLES_CAL      200
+
+/* TSL2X7X Device ID */
+#define TRITON_ID    0x00
+#define SWORDFISH_ID 0x30
+#define HALIBUT_ID   0x20
+
+/* Lux calculation constants */
+#define TSL2X7X_LUX_CALC_OVER_FLOW     65535
+
+/* TAOS Register definitions - note:
+ * depending on device, some of these register are not used and the
+ * register address is benign.
+ */
+/* 2X7X register offsets */
+#define TSL2X7X_MAX_CONFIG_REG         16
+
+/* Device Registers and Masks */
+#define TSL2X7X_CNTRL                  0x00
+#define TSL2X7X_ALS_TIME               0X01
+#define TSL2X7X_PRX_TIME               0x02
+#define TSL2X7X_WAIT_TIME              0x03
+#define TSL2X7X_ALS_MINTHRESHLO        0X04
+#define TSL2X7X_ALS_MINTHRESHHI        0X05
+#define TSL2X7X_ALS_MAXTHRESHLO        0X06
+#define TSL2X7X_ALS_MAXTHRESHHI        0X07
+#define TSL2X7X_PRX_MINTHRESHLO        0X08
+#define TSL2X7X_PRX_MINTHRESHHI        0X09
+#define TSL2X7X_PRX_MAXTHRESHLO        0X0A
+#define TSL2X7X_PRX_MAXTHRESHHI        0X0B
+#define TSL2X7X_PERSISTENCE            0x0C
+#define TSL2X7X_PRX_CONFIG             0x0D
+#define TSL2X7X_PRX_COUNT              0x0E
+#define TSL2X7X_GAIN                   0x0F
+#define TSL2X7X_NOTUSED                0x10
+#define TSL2X7X_REVID                  0x11
+#define TSL2X7X_CHIPID                 0x12
+#define TSL2X7X_STATUS                 0x13
+#define TSL2X7X_ALS_CHAN0LO            0x14
+#define TSL2X7X_ALS_CHAN0HI            0x15
+#define TSL2X7X_ALS_CHAN1LO            0x16
+#define TSL2X7X_ALS_CHAN1HI            0x17
+#define TSL2X7X_PRX_LO                 0x18
+#define TSL2X7X_PRX_HI                 0x19
+
+/* tsl2X7X cmd reg masks */
+#define TSL2X7X_CMD_REG                0x80
+#define TSL2X7X_CMD_SPL_FN             0x60
+
+#define TSL2X7X_CMD_PROX_INT_CLR       0X05
+#define TSL2X7X_CMD_ALS_INT_CLR        0x06
+#define TSL2X7X_CMD_PROXALS_INT_CLR    0X07
+
+/* tsl2X7X cntrl reg masks */
+#define TSL2X7X_CNTL_ADC_ENBL          0x02
+#define TSL2X7X_CNTL_PWR_ON            0x01
+
+/* tsl2X7X status reg masks */
+#define TSL2X7X_STA_ADC_VALID          0x01
+#define TSL2X7X_STA_PRX_VALID          0x02
+#define TSL2X7X_STA_ADC_PRX_VALID      (TSL2X7X_STA_ADC_VALID |\
+					TSL2X7X_STA_PRX_VALID)
+#define TSL2X7X_STA_ALS_INTR           0x10
+#define TSL2X7X_STA_PRX_INTR           0x20
+
+/* tsl2X7X cntrl reg masks */
+#define TSL2X7X_CNTL_REG_CLEAR         0x00
+#define TSL2X7X_CNTL_PROX_INT_ENBL     0X20
+#define TSL2X7X_CNTL_ALS_INT_ENBL      0X10
+#define TSL2X7X_CNTL_WAIT_TMR_ENBL     0X08
+#define TSL2X7X_CNTL_PROX_DET_ENBL     0X04
+#define TSL2X7X_CNTL_PWRON             0x01
+#define TSL2X7X_CNTL_ALSPON_ENBL       0x03
+#define TSL2X7X_CNTL_INTALSPON_ENBL    0x13
+#define TSL2X7X_CNTL_PROXPON_ENBL      0x0F
+#define TSL2X7X_CNTL_INTPROXPON_ENBL   0x2F
+
+/*Prox diode to use */
+#define TSL2X7X_DIODE0                 0x10
+#define TSL2X7X_DIODE1                 0x20
+#define TSL2X7X_DIODE_BOTH             0x30
+
+/* LED Power */
+#define TSL2X7X_mA100                  0x00
+#define TSL2X7X_mA50                   0x40
+#define TSL2X7X_mA25                   0x80
+#define TSL2X7X_mA13                   0xD0
+#define TSL2X7X_MAX_TIMER_CNT          (0xFF)
+
+/*Common device IIO EventMask */
+#define TSL2X7X_EVENT_MASK \
+		(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
+		IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)),
+
+#define TSL2X7X_MIN_ITIME 3
+
+/* TAOS txx2x7x Device family members */
+enum {
+	tsl2571,
+	tsl2671,
+	tmd2671,
+	tsl2771,
+	tmd2771,
+	tsl2572,
+	tsl2672,
+	tmd2672,
+	tsl2772,
+	tmd2772
+};
+
+enum {
+	TSL2X7X_CHIP_UNKNOWN = 0,
+	TSL2X7X_CHIP_WORKING = 1,
+	TSL2X7X_CHIP_SUSPENDED = 2
+};
+
+struct tsl2x7x_parse_result {
+	int integer;
+	int fract;
+};
+
+/* Per-device data */
+struct tsl2x7x_als_info {
+	u16 als_ch0;
+	u16 als_ch1;
+	u16 lux;
+};
+
+struct tsl2x7x_prox_stat {
+	int min;
+	int max;
+	int mean;
+	unsigned long stddev;
+};
+
+struct tsl2x7x_chip_info {
+	int chan_table_elements;
+	struct iio_chan_spec		channel[4];
+	const struct iio_info		*info;
+};
+
+struct tsl2X7X_chip {
+	kernel_ulong_t id;
+	struct mutex prox_mutex;
+	struct mutex als_mutex;
+	struct i2c_client *client;
+	u16 prox_data;
+	struct tsl2x7x_als_info als_cur_info;
+	struct tsl2x7x_settings tsl2x7x_settings;
+	struct tsl2X7X_platform_data *pdata;
+	int als_time_scale;
+	int als_saturation;
+	int tsl2x7x_chip_status;
+	u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG];
+	const struct tsl2x7x_chip_info	*chip_info;
+	const struct iio_info *info;
+	s64 event_timestamp;
+	/* This structure is intentionally large to accommodate
+	 * updates via sysfs. */
+	/* Sized to 9 = max 8 segments + 1 termination segment */
+	struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
+};
+
+/* Different devices require different coefficents */
+static const struct tsl2x7x_lux tsl2x71_lux_table[] = {
+	{ 14461,   611,   1211 },
+	{ 18540,   352,    623 },
+	{     0,     0,      0 },
+};
+
+static const struct tsl2x7x_lux tmd2x71_lux_table[] = {
+	{ 11635,   115,    256 },
+	{ 15536,    87,    179 },
+	{     0,     0,      0 },
+};
+
+static const struct tsl2x7x_lux tsl2x72_lux_table[] = {
+	{ 14013,   466,   917 },
+	{ 18222,   310,   552 },
+	{     0,     0,     0 },
+};
+
+static const struct tsl2x7x_lux tmd2x72_lux_table[] = {
+	{ 13218,   130,   262 },
+	{ 17592,   92,    169 },
+	{     0,     0,     0 },
+};
+
+static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
+	[tsl2571] =	tsl2x71_lux_table,
+	[tsl2671] =	tsl2x71_lux_table,
+	[tmd2671] =	tmd2x71_lux_table,
+	[tsl2771] =	tsl2x71_lux_table,
+	[tmd2771] =	tmd2x71_lux_table,
+	[tsl2572] =	tsl2x72_lux_table,
+	[tsl2672] =	tsl2x72_lux_table,
+	[tmd2672] =	tmd2x72_lux_table,
+	[tsl2772] =	tsl2x72_lux_table,
+	[tmd2772] =	tmd2x72_lux_table,
+};
+
+static const struct tsl2x7x_settings tsl2x7x_default_settings = {
+	.als_time = 219, /* 101 ms */
+	.als_gain = 0,
+	.prx_time = 254, /* 5.4 ms */
+	.prox_gain = 1,
+	.wait_time = 245,
+	.prox_config = 0,
+	.als_gain_trim = 1000,
+	.als_cal_target = 150,
+	.als_thresh_low = 200,
+	.als_thresh_high = 256,
+	.persistence = 255,
+	.interrupts_en = 0,
+	.prox_thres_low  = 0,
+	.prox_thres_high = 512,
+	.prox_max_samples_cal = 30,
+	.prox_pulse_count = 8
+};
+
+static const s16 tsl2X7X_als_gainadj[] = {
+	1,
+	8,
+	16,
+	120
+};
+
+static const s16 tsl2X7X_prx_gainadj[] = {
+	1,
+	2,
+	4,
+	8
+};
+
+/* Channel variations */
+enum {
+	ALS,
+	PRX,
+	ALSPRX,
+	PRX2,
+	ALSPRX2,
+};
+
+static const u8 device_channel_config[] = {
+	ALS,
+	PRX,
+	PRX,
+	ALSPRX,
+	ALSPRX,
+	ALS,
+	PRX2,
+	PRX2,
+	ALSPRX2,
+	ALSPRX2
+};
+
+/**
+ * tsl2x7x_parse_buffer() - parse a decimal result from a buffer.
+ * @*buf:                   pointer to char buffer to parse
+ * @*result:                pointer to buffer to contain
+ *                          resulting interger / decimal as ints.
+ *
+ */
+static int
+tsl2x7x_parse_buffer(const char *buf, struct tsl2x7x_parse_result *result)
+{
+	int integer = 0, fract = 0, fract_mult = 100000;
+	bool integer_part = true, negative = false;
+
+	if (buf[0] == '-') {
+		negative = true;
+		buf++;
+	}
+
+	while (*buf) {
+		if ('0' <= *buf && *buf <= '9') {
+			if (integer_part)
+				integer = integer*10 + *buf - '0';
+			else {
+				fract += fract_mult*(*buf - '0');
+				if (fract_mult == 1)
+					break;
+				fract_mult /= 10;
+			}
+		} else if (*buf == '\n') {
+			if (*(buf + 1) == '\0')
+				break;
+			else
+				return -EINVAL;
+		} else if (*buf == '.') {
+			integer_part = false;
+		} else {
+			return -EINVAL;
+		}
+		buf++;
+	}
+	if (negative) {
+		if (integer)
+			integer = -integer;
+		else
+			fract = -fract;
+	}
+
+	result->integer = integer;
+	result->fract = fract;
+
+	return 0;
+}
+
+/**
+ * tsl2x7x_i2c_read() - Read a byte from a register.
+ * @client:	i2c client
+ * @reg:	device register to read from
+ * @*val:	pointer to location to store register contents.
+ *
+ */
+static int
+tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+	int ret = 0;
+
+	/* select register to write */
+	ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg));
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: failed to write register %x\n"
+				, __func__, reg);
+		return ret;
+	}
+
+	/* read the data */
+	ret = i2c_smbus_read_byte(client);
+	if (ret >= 0)
+		*val = (u8)ret;
+	else
+		dev_err(&client->dev, "%s: failed to read register %x\n"
+						, __func__, reg);
+
+	return ret;
+}
+
+/**
+ * tsl2x7x_get_lux() - Reads and calculates current lux value.
+ * @indio_dev:	pointer to IIO device
+ *
+ * The raw ch0 and ch1 values of the ambient light sensed in the last
+ * integration cycle are read from the device.
+ * Time scale factor array values are adjusted based on the integration time.
+ * The raw values are multiplied by a scale factor, and device gain is obtained
+ * using gain index. Limit checks are done next, then the ratio of a multiple
+ * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[]
+ * is then scanned to find the first ratio value that is just above the ratio
+ * we just calculated. The ch0 and ch1 multiplier constants in the array are
+ * then used along with the time scale factor array values, to calculate the
+ * lux.
+ */
+static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
+{
+	u16 ch0, ch1; /* separated ch0/ch1 data from device */
+	u32 lux; /* raw lux calculated from device data */
+	u64 lux64;
+	u32 ratio;
+	u8 buf[4];
+	struct tsl2x7x_lux *p;
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	int i, ret;
+	u32 ch0lux = 0;
+	u32 ch1lux = 0;
+
+	if (mutex_trylock(&chip->als_mutex) == 0)
+		return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
+
+	if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) {
+		/* device is not enabled */
+		dev_err(&chip->client->dev, "%s: device is not enabled\n",
+				__func__);
+		ret = -EBUSY ;
+		goto out_unlock;
+	}
+
+	ret = tsl2x7x_i2c_read(chip->client,
+		(TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]);
+	if (ret < 0) {
+		dev_err(&chip->client->dev,
+			"%s: Failed to read STATUS Reg\n", __func__);
+		goto out_unlock;
+	}
+	/* is data new & valid */
+	if (!(buf[0] & TSL2X7X_STA_ADC_VALID)) {
+		dev_err(&chip->client->dev,
+			"%s: data not valid yet\n", __func__);
+		ret = chip->als_cur_info.lux; /* return LAST VALUE */
+		goto out_unlock;
+	}
+
+	for (i = 0; i < 4; i++) {
+		ret = tsl2x7x_i2c_read(chip->client,
+			(TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i)),
+			&buf[i]);
+		if (ret < 0) {
+			dev_err(&chip->client->dev,
+				"%s: failed to read. err=%x\n", __func__, ret);
+			goto out_unlock;
+		}
+	}
+
+	/* clear any existing interrupt status */
+	ret = i2c_smbus_write_byte(chip->client,
+		(TSL2X7X_CMD_REG |
+				TSL2X7X_CMD_SPL_FN |
+				TSL2X7X_CMD_ALS_INT_CLR));
+	if (ret < 0) {
+		dev_err(&chip->client->dev,
+		"%s: i2c_write_command failed - err = %d\n",
+			__func__, ret);
+		goto out_unlock; /* have no data, so return failure */
+	}
+
+	/* extract ALS/lux data */
+	ch0 = le16_to_cpup((const __le16 *)&buf[0]);
+	ch1 = le16_to_cpup((const __le16 *)&buf[2]);
+
+	chip->als_cur_info.als_ch0 = ch0;
+	chip->als_cur_info.als_ch1 = ch1;
+
+	if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) {
+		lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+		goto return_max;
+	}
+
+	if (ch0 == 0) {
+		/* have no data, so return LAST VALUE */
+		ret = chip->als_cur_info.lux;
+		goto out_unlock;
+	}
+	/* calculate ratio */
+	ratio = (ch1 << 15) / ch0;
+	/* convert to unscaled lux using the pointer to the table */
+	p = (struct tsl2x7x_lux *) chip->tsl2x7x_device_lux;
+	while (p->ratio != 0 && p->ratio < ratio)
+		p++;
+
+	if (p->ratio == 0) {
+		lux = 0;
+	} else {
+		ch0lux = DIV_ROUND_UP((ch0 * p->ch0),
+			tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
+		ch1lux = DIV_ROUND_UP((ch1 * p->ch1),
+			tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
+		lux = ch0lux - ch1lux;
+	}
+
+	/* note: lux is 31 bit max at this point */
+	if (ch1lux > ch0lux) {
+		dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n");
+		ret = chip->als_cur_info.lux;
+		goto out_unlock;
+	}
+
+	/* adjust for active time scale */
+	if (chip->als_time_scale == 0)
+		lux = 0;
+	else
+		lux = (lux + (chip->als_time_scale >> 1)) /
+			chip->als_time_scale;
+
+	/* adjust for active gain scale
+	 * The tsl2x7x_device_lux tables have a factor of 256 built-in.
+	 * User-specified gain provides a multiplier.
+	 * Apply user-specified gain before shifting right to retain precision.
+	 * Use 64 bits to avoid overflow on multiplication.
+	 * Then go back to 32 bits before division to avoid using div_u64().
+	 */
+
+	lux64 = lux;
+	lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim;
+	lux64 >>= 8;
+	lux = lux64;
+	lux = (lux + 500) / 1000;
+
+	if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */
+		lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+
+	/* Update the structure with the latest lux. */
+return_max:
+	chip->als_cur_info.lux = lux;
+	ret = lux;
+
+out_unlock:
+	mutex_unlock(&chip->als_mutex);
+
+	return ret;
+}
+
+/**
+ * tsl2x7x_get_prox() - Reads proximity data registers and updates
+ *                      chip->prox_data.
+ *
+ * @indio_dev:	pointer to IIO device
+ */
+static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
+{
+	int i;
+	int ret;
+	u8 status;
+	u8 chdata[2];
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+	if (mutex_trylock(&chip->prox_mutex) == 0) {
+		dev_err(&chip->client->dev,
+			"%s: Can't get prox mutex\n", __func__);
+		return -EBUSY;
+	}
+
+	ret = tsl2x7x_i2c_read(chip->client,
+		(TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status);
+	if (ret < 0) {
+		dev_err(&chip->client->dev,
+		"%s: i2c err=%d\n", __func__, ret);
+		goto prox_poll_err;
+	}
+
+	switch (chip->id) {
+	case tsl2571:
+	case tsl2671:
+	case tmd2671:
+	case tsl2771:
+	case tmd2771:
+		if (!(status & TSL2X7X_STA_ADC_VALID))
+			goto prox_poll_err;
+	break;
+	case tsl2572:
+	case tsl2672:
+	case tmd2672:
+	case tsl2772:
+	case tmd2772:
+		if (!(status & TSL2X7X_STA_PRX_VALID))
+			goto prox_poll_err;
+	break;
+	}
+
+	for (i = 0; i < 2; i++) {
+		ret = tsl2x7x_i2c_read(chip->client,
+			(TSL2X7X_CMD_REG |
+					(TSL2X7X_PRX_LO + i)), &chdata[i]);
+		if (ret < 0)
+			goto prox_poll_err;
+	}
+
+	chip->prox_data =
+			le16_to_cpup((const __le16 *)&chdata[0]);
+
+prox_poll_err:
+
+	mutex_unlock(&chip->prox_mutex);
+
+	return chip->prox_data;
+}
+
+/**
+ * tsl2x7x_defaults() - Populates the device nominal operating parameters
+ *                      with those provided by a 'platform' data struct or
+ *                      with prefined defaults.
+ *
+ * @chip:               pointer to device structure.
+ */
+static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
+{
+	/* If Operational settings defined elsewhere.. */
+	if (chip->pdata && chip->pdata->platform_default_settings != 0)
+		memcpy(&(chip->tsl2x7x_settings),
+			chip->pdata->platform_default_settings,
+			sizeof(tsl2x7x_default_settings));
+	else
+		memcpy(&(chip->tsl2x7x_settings),
+			&tsl2x7x_default_settings,
+			sizeof(tsl2x7x_default_settings));
+
+	/* Load up the proper lux table. */
+	if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
+		memcpy(chip->tsl2x7x_device_lux,
+			chip->pdata->platform_lux_table,
+			sizeof(chip->pdata->platform_lux_table));
+	else
+		memcpy(chip->tsl2x7x_device_lux,
+		(struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id],
+				MAX_DEFAULT_TABLE_BYTES);
+}
+
+/**
+ * tsl2x7x_als_calibrate() -	Obtain single reading and calculate
+ *                              the als_gain_trim.
+ *
+ * @indio_dev:	pointer to IIO device
+ */
+static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
+{
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	u8 reg_val;
+	int gain_trim_val;
+	int ret;
+	int lux_val;
+
+	ret = i2c_smbus_write_byte(chip->client,
+			(TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+	if (ret < 0) {
+		dev_err(&chip->client->dev,
+		"%s: failed to write CNTRL register, ret=%d\n",
+		__func__, ret);
+		return ret;
+	}
+
+	reg_val = i2c_smbus_read_byte(chip->client);
+	if ((reg_val & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON))
+		!= (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) {
+		dev_err(&chip->client->dev,
+			"%s: failed: ADC not enabled\n", __func__);
+		return -1;
+	}
+
+	ret = i2c_smbus_write_byte(chip->client,
+			(TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+	if (ret < 0) {
+		dev_err(&chip->client->dev,
+			"%s: failed to write ctrl reg: ret=%d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	reg_val = i2c_smbus_read_byte(chip->client);
+	if ((reg_val & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) {
+		dev_err(&chip->client->dev,
+			"%s: failed: STATUS - ADC not valid.\n", __func__);
+		return -ENODATA;
+	}
+
+	lux_val = tsl2x7x_get_lux(indio_dev);
+	if (lux_val < 0) {
+		dev_err(&chip->client->dev,
+		"%s: failed to get lux\n", __func__);
+		return lux_val;
+	}
+
+	gain_trim_val =  (((chip->tsl2x7x_settings.als_cal_target)
+			* chip->tsl2x7x_settings.als_gain_trim) / lux_val);
+	if ((gain_trim_val < 250) || (gain_trim_val > 4000))
+		return -ERANGE;
+
+	chip->tsl2x7x_settings.als_gain_trim = gain_trim_val;
+	dev_info(&chip->client->dev,
+		"%s als_calibrate completed\n", chip->client->name);
+
+	return (int) gain_trim_val;
+}
+
+static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
+{
+	int i;
+	int ret = 0;
+	u8 *dev_reg;
+	u8 utmp;
+	int als_count;
+	int als_time;
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	u8 reg_val = 0;
+
+	if (chip->pdata && chip->pdata->power_on)
+		chip->pdata->power_on(indio_dev);
+
+	/* Non calculated parameters */
+	chip->tsl2x7x_config[TSL2X7X_PRX_TIME] =
+			chip->tsl2x7x_settings.prx_time;
+	chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] =
+			chip->tsl2x7x_settings.wait_time;
+	chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] =
+			chip->tsl2x7x_settings.prox_config;
+
+	chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] =
+		(chip->tsl2x7x_settings.als_thresh_low) & 0xFF;
+	chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] =
+		(chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF;
+	chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] =
+		(chip->tsl2x7x_settings.als_thresh_high) & 0xFF;
+	chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] =
+		(chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF;
+	chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] =
+		chip->tsl2x7x_settings.persistence;
+
+	chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] =
+			chip->tsl2x7x_settings.prox_pulse_count;
+	chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] =
+	chip->tsl2x7x_settings.prox_thres_low;
+	chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] =
+			chip->tsl2x7x_settings.prox_thres_high;
+
+	/* and make sure we're not already on */
+	if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
+		/* if forcing a register update - turn off, then on */
+		dev_info(&chip->client->dev, "device is already enabled\n");
+		return -EINVAL;
+	}
+
+	/* determine als integration regster */
+	als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270;
+	if (als_count == 0)
+		als_count = 1; /* ensure at least one cycle */
+
+	/* convert back to time (encompasses overrides) */
+	als_time = (als_count * 27 + 5) / 10;
+	chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count;
+
+	/* Set the gain based on tsl2x7x_settings struct */
+	chip->tsl2x7x_config[TSL2X7X_GAIN] =
+		(chip->tsl2x7x_settings.als_gain |
+			(TSL2X7X_mA100 | TSL2X7X_DIODE1)
+			| ((chip->tsl2x7x_settings.prox_gain) << 2));
+
+	/* set chip struct re scaling and saturation */
+	chip->als_saturation = als_count * 922; /* 90% of full scale */
+	chip->als_time_scale = (als_time + 25) / 50;
+
+	/* TSL2X7X Specific power-on / adc enable sequence
+	 * Power on the device 1st. */
+	utmp = TSL2X7X_CNTL_PWR_ON;
+	ret = i2c_smbus_write_byte_data(chip->client,
+		TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+	if (ret < 0) {
+		dev_err(&chip->client->dev,
+			"%s: failed on CNTRL reg.\n", __func__);
+		return ret;
+	}
+
+	/* Use the following shadow copy for our delay before enabling ADC.
+	 * Write all the registers. */
+	for (i = 0, dev_reg = chip->tsl2x7x_config;
+			i < TSL2X7X_MAX_CONFIG_REG; i++) {
+		ret = i2c_smbus_write_byte_data(chip->client,
+				TSL2X7X_CMD_REG + i, *dev_reg++);
+		if (ret < 0) {
+			dev_err(&chip->client->dev,
+			"%s: failed on write to reg %d.\n", __func__, i);
+			return ret;
+		}
+	}
+
+	mdelay(3);	/* Power-on settling time */
+
+	/* NOW enable the ADC
+	 * initialize the desired mode of operation */
+	utmp = TSL2X7X_CNTL_PWR_ON |
+			TSL2X7X_CNTL_ADC_ENBL |
+			TSL2X7X_CNTL_PROX_DET_ENBL;
+	ret = i2c_smbus_write_byte_data(chip->client,
+			TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+	if (ret < 0) {
+		dev_err(&chip->client->dev,
+			"%s: failed on 2nd CTRL reg.\n", __func__);
+		return ret;
+	}
+
+	chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
+
+	if (chip->tsl2x7x_settings.interrupts_en != 0) {
+		dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n");
+
+		reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL;
+		if ((chip->tsl2x7x_settings.interrupts_en == 0x20) ||
+			(chip->tsl2x7x_settings.interrupts_en == 0x30))
+			reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
+
+		reg_val |= chip->tsl2x7x_settings.interrupts_en;
+		ret = i2c_smbus_write_byte_data(chip->client,
+			(TSL2X7X_CMD_REG | TSL2X7X_CNTRL), reg_val);
+		if (ret < 0)
+			dev_err(&chip->client->dev,
+				"%s: failed in tsl2x7x_IOCTL_INT_SET.\n",
+				__func__);
+
+		/* Clear out any initial interrupts  */
+		ret = i2c_smbus_write_byte(chip->client,
+			TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+			TSL2X7X_CMD_PROXALS_INT_CLR);
+		if (ret < 0) {
+			dev_err(&chip->client->dev,
+				"%s: Failed to clear Int status\n",
+				__func__);
+		return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int tsl2x7x_chip_off(struct iio_dev *indio_dev)
+{
+	int ret;
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+	/* turn device off */
+	chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
+
+	ret = i2c_smbus_write_byte_data(chip->client,
+		TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00);
+
+	if (chip->pdata && chip->pdata->power_off)
+		chip->pdata->power_off(chip->client);
+
+	return ret;
+}
+
+/**
+ * tsl2x7x_invoke_change
+ * @indio_dev:	pointer to IIO device
+ *
+ * Obtain and lock both ALS and PROX resources,
+ * determine and save device state (On/Off),
+ * cycle device to implement updated parameter,
+ * put device back into proper state, and unlock
+ * resource.
+ */
+static
+int tsl2x7x_invoke_change(struct iio_dev *indio_dev)
+{
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	int device_status = chip->tsl2x7x_chip_status;
+
+	mutex_lock(&chip->als_mutex);
+	mutex_lock(&chip->prox_mutex);
+
+	if (device_status == TSL2X7X_CHIP_WORKING)
+		tsl2x7x_chip_off(indio_dev);
+
+	tsl2x7x_chip_on(indio_dev);
+
+	if (device_status != TSL2X7X_CHIP_WORKING)
+		tsl2x7x_chip_off(indio_dev);
+
+	mutex_unlock(&chip->prox_mutex);
+	mutex_unlock(&chip->als_mutex);
+
+	return 0;
+}
+
+static
+void tsl2x7x_prox_calculate(int *data, int length,
+		struct tsl2x7x_prox_stat *statP)
+{
+	int i;
+	int sample_sum;
+	int tmp;
+
+	if (length == 0)
+		length = 1;
+
+	sample_sum = 0;
+	statP->min = INT_MAX;
+	statP->max = INT_MIN;
+	for (i = 0; i < length; i++) {
+		sample_sum += data[i];
+		statP->min = min(statP->min, data[i]);
+		statP->max = max(statP->max, data[i]);
+	}
+
+	statP->mean = sample_sum / length;
+	sample_sum = 0;
+	for (i = 0; i < length; i++) {
+		tmp = data[i] - statP->mean;
+		sample_sum += tmp * tmp;
+	}
+	statP->stddev = int_sqrt((long)sample_sum)/length;
+}
+
+/**
+ * tsl2x7x_prox_cal() - Calculates std. and sets thresholds.
+ * @indio_dev:	pointer to IIO device
+ *
+ * Calculates a standard deviation based on the samples,
+ * and sets the threshold accordingly.
+ */
+static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
+{
+	int prox_history[MAX_SAMPLES_CAL + 1];
+	int i;
+	struct tsl2x7x_prox_stat prox_stat_data[2];
+	struct tsl2x7x_prox_stat *calP;
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	u8 tmp_irq_settings;
+	u8 current_state = chip->tsl2x7x_chip_status;
+
+	if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) {
+		dev_err(&chip->client->dev,
+			"%s: max prox samples cal is too big: %d\n",
+			__func__, chip->tsl2x7x_settings.prox_max_samples_cal);
+		chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL;
+	}
+
+	/* have to stop to change settings */
+	tsl2x7x_chip_off(indio_dev);
+
+	/* Enable proximity detection save just in case prox not wanted yet*/
+	tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en;
+	chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
+
+	/*turn on device if not already on*/
+	tsl2x7x_chip_on(indio_dev);
+
+	/*gather the samples*/
+	for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) {
+		mdelay(15);
+		tsl2x7x_get_prox(indio_dev);
+		prox_history[i] = chip->prox_data;
+		dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
+			i, chip->prox_data);
+	}
+
+	tsl2x7x_chip_off(indio_dev);
+	calP = &prox_stat_data[PROX_STAT_CAL];
+	tsl2x7x_prox_calculate(prox_history,
+		chip->tsl2x7x_settings.prox_max_samples_cal, calP);
+	chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean;
+
+	dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
+		calP->min, calP->mean, calP->max);
+	dev_info(&chip->client->dev,
+		"%s proximity threshold set to %d\n",
+		chip->client->name, chip->tsl2x7x_settings.prox_thres_high);
+
+	/* back to the way they were */
+	chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings;
+	if (current_state == TSL2X7X_CHIP_WORKING)
+		tsl2x7x_chip_on(indio_dev);
+}
+
+static ssize_t tsl2x7x_power_state_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status);
+}
+
+static ssize_t tsl2x7x_power_state_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	bool value;
+
+	if (strtobool(buf, &value))
+		return -EINVAL;
+
+	if (value)
+		tsl2x7x_chip_on(indio_dev);
+	else
+		tsl2x7x_chip_off(indio_dev);
+
+	return len;
+}
+
+static ssize_t tsl2x7x_gain_available_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+	switch (chip->id) {
+	case tsl2571:
+	case tsl2671:
+	case tmd2671:
+	case tsl2771:
+	case tmd2771:
+		return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128");
+	break;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120");
+}
+
+static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+		return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8");
+}
+
+static ssize_t tsl2x7x_als_time_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+	int y, z;
+
+	y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+	z = y * TSL2X7X_MIN_ITIME;
+	y /= 1000;
+	z %= 1000;
+
+	return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t tsl2x7x_als_time_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	struct tsl2x7x_parse_result result;
+
+	result.integer = 0;
+	result.fract = 0;
+
+	tsl2x7x_parse_buffer(buf, &result);
+
+	result.fract /= 1000;
+	result.fract /= 3;
+	chip->tsl2x7x_settings.als_time =
+			(TSL2X7X_MAX_TIMER_CNT - (u8)result.fract);
+
+	dev_info(&chip->client->dev, "%s: als time = %d",
+		__func__, chip->tsl2x7x_settings.als_time);
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static IIO_CONST_ATTR(in_illuminance0_integration_time_available,
+		".00272 - .696");
+
+static ssize_t tsl2x7x_als_cal_target_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			chip->tsl2x7x_settings.als_cal_target);
+}
+
+static ssize_t tsl2x7x_als_cal_target_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	unsigned long value;
+
+	if (kstrtoul(buf, 0, &value))
+		return -EINVAL;
+
+	if (value)
+		chip->tsl2x7x_settings.als_cal_target = value;
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return len;
+}
+
+/* persistence settings */
+static ssize_t tsl2x7x_als_persistence_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+	int y, z, filter_delay;
+
+	/* Determine integration time */
+	y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+	z = y * TSL2X7X_MIN_ITIME;
+	filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F);
+	y = (filter_delay / 1000);
+	z = (filter_delay % 1000);
+
+	return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t tsl2x7x_als_persistence_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	struct tsl2x7x_parse_result result;
+	int y, z, filter_delay;
+
+	result.integer = 0;
+	result.fract = 0;
+	tsl2x7x_parse_buffer(buf, &result);
+
+	result.fract /= 1000;
+	y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+	z = y * TSL2X7X_MIN_ITIME;
+
+	filter_delay =
+		DIV_ROUND_UP(((result.integer * 1000) + result.fract), z);
+
+	chip->tsl2x7x_settings.persistence &= 0xF0;
+	chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F);
+
+	dev_info(&chip->client->dev, "%s: als persistence = %d",
+		__func__, filter_delay);
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t tsl2x7x_prox_persistence_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+	int y, z, filter_delay;
+
+	/* Determine integration time */
+	y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
+	z = y * TSL2X7X_MIN_ITIME;
+	filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4);
+	y = (filter_delay / 1000);
+	z = (filter_delay % 1000);
+
+	return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t tsl2x7x_prox_persistence_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	struct tsl2x7x_parse_result result;
+	int y, z, filter_delay;
+
+	result.integer = 0;
+	result.fract = 0;
+	tsl2x7x_parse_buffer(buf, &result);
+
+	result.fract /= 1000;
+	y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
+	z = y * TSL2X7X_MIN_ITIME;
+
+	filter_delay =
+		DIV_ROUND_UP(((result.integer * 1000) + result.fract), z);
+
+	chip->tsl2x7x_settings.persistence &= 0x0F;
+	chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0);
+
+	dev_info(&chip->client->dev, "%s: prox persistence = %d",
+		__func__, filter_delay);
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t tsl2x7x_do_calibrate(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	bool value;
+
+	if (strtobool(buf, &value))
+		return -EINVAL;
+
+	if (value)
+		tsl2x7x_als_calibrate(indio_dev);
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return len;
+}
+
+static ssize_t tsl2x7x_luxtable_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+	int i = 0;
+	int offset = 0;
+
+	while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) {
+		offset += snprintf(buf + offset, PAGE_SIZE, "%d,%d,%d,",
+			chip->tsl2x7x_device_lux[i].ratio,
+			chip->tsl2x7x_device_lux[i].ch0,
+			chip->tsl2x7x_device_lux[i].ch1);
+		if (chip->tsl2x7x_device_lux[i].ratio == 0) {
+			/* We just printed the first "0" entry.
+			 * Now get rid of the extra "," and break. */
+			offset--;
+			break;
+		}
+		i++;
+	}
+
+	offset += snprintf(buf + offset, PAGE_SIZE, "\n");
+	return offset;
+}
+
+static ssize_t tsl2x7x_luxtable_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	int value[ARRAY_SIZE(chip->tsl2x7x_device_lux)*3 + 1];
+	int n;
+
+	get_options(buf, ARRAY_SIZE(value), value);
+
+	/* We now have an array of ints starting at value[1], and
+	 * enumerated by value[0].
+	 * We expect each group of three ints is one table entry,
+	 * and the last table entry is all 0.
+	 */
+	n = value[0];
+	if ((n % 3) || n < 6 ||
+			n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) {
+		dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
+		return -EINVAL;
+	}
+
+	if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
+		dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
+		return -EINVAL;
+	}
+
+	if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING)
+		tsl2x7x_chip_off(indio_dev);
+
+	/* Zero out the table */
+	memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux));
+	memcpy(chip->tsl2x7x_device_lux, &value[1], (value[0] * 4));
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return len;
+}
+
+static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	bool value;
+
+	if (strtobool(buf, &value))
+		return -EINVAL;
+
+	if (value)
+		tsl2x7x_prox_cal(indio_dev);
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return len;
+}
+
+static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
+					 u64 event_code)
+{
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	int ret;
+
+	if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY)
+		ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10);
+	else
+		ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20);
+
+	return ret;
+}
+
+static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
+					  u64 event_code,
+					  int val)
+{
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+	if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
+		if (val)
+			chip->tsl2x7x_settings.interrupts_en |= 0x10;
+		else
+			chip->tsl2x7x_settings.interrupts_en &= 0x20;
+	} else {
+		if (val)
+			chip->tsl2x7x_settings.interrupts_en |= 0x20;
+		else
+			chip->tsl2x7x_settings.interrupts_en &= 0x10;
+	}
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return 0;
+}
+
+static int tsl2x7x_write_thresh(struct iio_dev *indio_dev,
+				  u64 event_code,
+				  int val)
+{
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+	if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
+		switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+		case IIO_EV_DIR_RISING:
+			chip->tsl2x7x_settings.als_thresh_high = val;
+			break;
+		case IIO_EV_DIR_FALLING:
+			chip->tsl2x7x_settings.als_thresh_low = val;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+		case IIO_EV_DIR_RISING:
+			chip->tsl2x7x_settings.prox_thres_high = val;
+			break;
+		case IIO_EV_DIR_FALLING:
+			chip->tsl2x7x_settings.prox_thres_low = val;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return 0;
+}
+
+static int tsl2x7x_read_thresh(struct iio_dev *indio_dev,
+			       u64 event_code,
+			       int *val)
+{
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+	if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
+		switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+		case IIO_EV_DIR_RISING:
+			*val = chip->tsl2x7x_settings.als_thresh_high;
+			break;
+		case IIO_EV_DIR_FALLING:
+			*val = chip->tsl2x7x_settings.als_thresh_low;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+		case IIO_EV_DIR_RISING:
+			*val = chip->tsl2x7x_settings.prox_thres_high;
+			break;
+		case IIO_EV_DIR_FALLING:
+			*val = chip->tsl2x7x_settings.prox_thres_low;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val,
+			    int *val2,
+			    long mask)
+{
+	int ret = -EINVAL;
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_LIGHT:
+			tsl2x7x_get_lux(indio_dev);
+			*val = chip->als_cur_info.lux;
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			return -EINVAL;
+			break;
+		}
+		break;
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_INTENSITY:
+			tsl2x7x_get_lux(indio_dev);
+			if (chan->channel == 0)
+				*val = chip->als_cur_info.als_ch0;
+			else
+				*val = chip->als_cur_info.als_ch1;
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_PROXIMITY:
+			tsl2x7x_get_prox(indio_dev);
+			*val = chip->prox_data;
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			return -EINVAL;
+			break;
+		}
+		break;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (chan->type == IIO_LIGHT)
+			*val =
+			tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain];
+		else
+			*val =
+			tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain];
+		ret = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		*val = chip->tsl2x7x_settings.als_gain_trim;
+		ret = IIO_VAL_INT;
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (chan->type == IIO_INTENSITY) {
+			switch (val) {
+			case 1:
+				chip->tsl2x7x_settings.als_gain = 0;
+				break;
+			case 8:
+				chip->tsl2x7x_settings.als_gain = 1;
+				break;
+			case 16:
+				chip->tsl2x7x_settings.als_gain = 2;
+				break;
+			case 120:
+				switch (chip->id) {
+				case tsl2572:
+				case tsl2672:
+				case tmd2672:
+				case tsl2772:
+				case tmd2772:
+					return -EINVAL;
+				break;
+				}
+				chip->tsl2x7x_settings.als_gain = 3;
+				break;
+			case 128:
+				switch (chip->id) {
+				case tsl2571:
+				case tsl2671:
+				case tmd2671:
+				case tsl2771:
+				case tmd2771:
+					return -EINVAL;
+				break;
+				}
+				chip->tsl2x7x_settings.als_gain = 3;
+				break;
+			default:
+				return -EINVAL;
+			}
+		} else {
+			switch (val) {
+			case 1:
+				chip->tsl2x7x_settings.prox_gain = 0;
+				break;
+			case 2:
+				chip->tsl2x7x_settings.prox_gain = 1;
+				break;
+			case 4:
+				chip->tsl2x7x_settings.prox_gain = 2;
+				break;
+			case 8:
+				chip->tsl2x7x_settings.prox_gain = 3;
+				break;
+			default:
+				return -EINVAL;
+			}
+		}
+		break;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		chip->tsl2x7x_settings.als_gain_trim = val;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	tsl2x7x_invoke_change(indio_dev);
+
+	return 0;
+}
+
+static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
+		tsl2x7x_power_state_show, tsl2x7x_power_state_store);
+
+static DEVICE_ATTR(in_proximity0_calibscale_available, S_IRUGO,
+		tsl2x7x_prox_gain_available_show, NULL);
+
+static DEVICE_ATTR(in_illuminance0_calibscale_available, S_IRUGO,
+		tsl2x7x_gain_available_show, NULL);
+
+static DEVICE_ATTR(in_illuminance0_integration_time, S_IRUGO | S_IWUSR,
+		tsl2x7x_als_time_show, tsl2x7x_als_time_store);
+
+static DEVICE_ATTR(in_illuminance0_target_input, S_IRUGO | S_IWUSR,
+		tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store);
+
+static DEVICE_ATTR(in_illuminance0_calibrate, S_IWUSR, NULL,
+		tsl2x7x_do_calibrate);
+
+static DEVICE_ATTR(in_proximity0_calibrate, S_IWUSR, NULL,
+		tsl2x7x_do_prox_calibrate);
+
+static DEVICE_ATTR(in_illuminance0_lux_table, S_IRUGO | S_IWUSR,
+		tsl2x7x_luxtable_show, tsl2x7x_luxtable_store);
+
+static DEVICE_ATTR(in_intensity0_thresh_period, S_IRUGO | S_IWUSR,
+		tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store);
+
+static DEVICE_ATTR(in_proximity0_thresh_period, S_IRUGO | S_IWUSR,
+		tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store);
+
+/* Use the default register values to identify the Taos device */
+static int tsl2x7x_device_id(unsigned char *id, int target)
+{
+	switch (target) {
+	case tsl2571:
+	case tsl2671:
+	case tsl2771:
+		return ((*id & 0xf0) == TRITON_ID);
+	break;
+	case tmd2671:
+	case tmd2771:
+		return ((*id & 0xf0) == HALIBUT_ID);
+	break;
+	case tsl2572:
+	case tsl2672:
+	case tmd2672:
+	case tsl2772:
+	case tmd2772:
+		return ((*id & 0xf0) == SWORDFISH_ID);
+	break;
+	}
+
+	return -EINVAL;
+}
+
+static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	s64 timestamp = iio_get_time_ns();
+	int ret;
+	u8 value;
+
+	value = i2c_smbus_read_byte_data(chip->client,
+		TSL2X7X_CMD_REG | TSL2X7X_STATUS);
+
+	/* What type of interrupt do we need to process */
+	if (value & TSL2X7X_STA_PRX_INTR) {
+		tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */
+		iio_push_event(indio_dev,
+			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
+						    0,
+						    IIO_EV_TYPE_THRESH,
+						    IIO_EV_DIR_EITHER),
+						    timestamp);
+	}
+
+	if (value & TSL2X7X_STA_ALS_INTR) {
+		tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */
+		iio_push_event(indio_dev,
+		       IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+					    0,
+					    IIO_EV_TYPE_THRESH,
+					    IIO_EV_DIR_EITHER),
+					    timestamp);
+	}
+	/* Clear interrupt now that we have handled it. */
+	ret = i2c_smbus_write_byte(chip->client,
+		TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+		TSL2X7X_CMD_PROXALS_INT_CLR);
+	if (ret < 0)
+		dev_err(&chip->client->dev,
+			"%s: Failed to clear irq from event handler. err = %d\n",
+			__func__, ret);
+
+	return IRQ_HANDLED;
+}
+
+static struct attribute *tsl2x7x_ALS_device_attrs[] = {
+	&dev_attr_power_state.attr,
+	&dev_attr_in_illuminance0_calibscale_available.attr,
+	&dev_attr_in_illuminance0_integration_time.attr,
+	&iio_const_attr_in_illuminance0_integration_time_available\
+	.dev_attr.attr,
+	&dev_attr_in_illuminance0_target_input.attr,
+	&dev_attr_in_illuminance0_calibrate.attr,
+	&dev_attr_in_illuminance0_lux_table.attr,
+	NULL
+};
+
+static struct attribute *tsl2x7x_PRX_device_attrs[] = {
+	&dev_attr_power_state.attr,
+	&dev_attr_in_proximity0_calibrate.attr,
+	NULL
+};
+
+static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = {
+	&dev_attr_power_state.attr,
+	&dev_attr_in_illuminance0_calibscale_available.attr,
+	&dev_attr_in_illuminance0_integration_time.attr,
+	&iio_const_attr_in_illuminance0_integration_time_available\
+	.dev_attr.attr,
+	&dev_attr_in_illuminance0_target_input.attr,
+	&dev_attr_in_illuminance0_calibrate.attr,
+	&dev_attr_in_illuminance0_lux_table.attr,
+	&dev_attr_in_proximity0_calibrate.attr,
+	NULL
+};
+
+static struct attribute *tsl2x7x_PRX2_device_attrs[] = {
+	&dev_attr_power_state.attr,
+	&dev_attr_in_proximity0_calibrate.attr,
+	&dev_attr_in_proximity0_calibscale_available.attr,
+	NULL
+};
+
+static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = {
+	&dev_attr_power_state.attr,
+	&dev_attr_in_illuminance0_calibscale_available.attr,
+	&dev_attr_in_illuminance0_integration_time.attr,
+	&iio_const_attr_in_illuminance0_integration_time_available\
+	.dev_attr.attr,
+	&dev_attr_in_illuminance0_target_input.attr,
+	&dev_attr_in_illuminance0_calibrate.attr,
+	&dev_attr_in_illuminance0_lux_table.attr,
+	&dev_attr_in_proximity0_calibrate.attr,
+	&dev_attr_in_proximity0_calibscale_available.attr,
+	NULL
+};
+
+static struct attribute *tsl2X7X_ALS_event_attrs[] = {
+	&dev_attr_in_intensity0_thresh_period.attr,
+	NULL,
+};
+static struct attribute *tsl2X7X_PRX_event_attrs[] = {
+	&dev_attr_in_proximity0_thresh_period.attr,
+	NULL,
+};
+
+static struct attribute *tsl2X7X_ALSPRX_event_attrs[] = {
+	&dev_attr_in_intensity0_thresh_period.attr,
+	&dev_attr_in_proximity0_thresh_period.attr,
+	NULL,
+};
+
+static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = {
+	[ALS] = {
+		.attrs = tsl2x7x_ALS_device_attrs,
+	},
+	[PRX] = {
+		.attrs = tsl2x7x_PRX_device_attrs,
+	},
+	[ALSPRX] = {
+		.attrs = tsl2x7x_ALSPRX_device_attrs,
+	},
+	[PRX2] = {
+		.attrs = tsl2x7x_PRX2_device_attrs,
+	},
+	[ALSPRX2] = {
+		.attrs = tsl2x7x_ALSPRX2_device_attrs,
+	},
+};
+
+static struct attribute_group tsl2X7X_event_attr_group_tbl[] = {
+	[ALS] = {
+		.attrs = tsl2X7X_ALS_event_attrs,
+		.name = "events",
+	},
+	[PRX] = {
+		.attrs = tsl2X7X_PRX_event_attrs,
+		.name = "events",
+	},
+	[ALSPRX] = {
+		.attrs = tsl2X7X_ALSPRX_event_attrs,
+		.name = "events",
+	},
+};
+
+static const struct iio_info tsl2X7X_device_info[] = {
+	[ALS] = {
+		.attrs = &tsl2X7X_device_attr_group_tbl[ALS],
+		.event_attrs = &tsl2X7X_event_attr_group_tbl[ALS],
+		.driver_module = THIS_MODULE,
+		.read_raw = &tsl2x7x_read_raw,
+		.write_raw = &tsl2x7x_write_raw,
+		.read_event_value = &tsl2x7x_read_thresh,
+		.write_event_value = &tsl2x7x_write_thresh,
+		.read_event_config = &tsl2x7x_read_interrupt_config,
+		.write_event_config = &tsl2x7x_write_interrupt_config,
+	},
+	[PRX] = {
+		.attrs = &tsl2X7X_device_attr_group_tbl[PRX],
+		.event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
+		.driver_module = THIS_MODULE,
+		.read_raw = &tsl2x7x_read_raw,
+		.write_raw = &tsl2x7x_write_raw,
+		.read_event_value = &tsl2x7x_read_thresh,
+		.write_event_value = &tsl2x7x_write_thresh,
+		.read_event_config = &tsl2x7x_read_interrupt_config,
+		.write_event_config = &tsl2x7x_write_interrupt_config,
+	},
+	[ALSPRX] = {
+		.attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX],
+		.event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
+		.driver_module = THIS_MODULE,
+		.read_raw = &tsl2x7x_read_raw,
+		.write_raw = &tsl2x7x_write_raw,
+		.read_event_value = &tsl2x7x_read_thresh,
+		.write_event_value = &tsl2x7x_write_thresh,
+		.read_event_config = &tsl2x7x_read_interrupt_config,
+		.write_event_config = &tsl2x7x_write_interrupt_config,
+	},
+	[PRX2] = {
+		.attrs = &tsl2X7X_device_attr_group_tbl[PRX2],
+		.event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
+		.driver_module = THIS_MODULE,
+		.read_raw = &tsl2x7x_read_raw,
+		.write_raw = &tsl2x7x_write_raw,
+		.read_event_value = &tsl2x7x_read_thresh,
+		.write_event_value = &tsl2x7x_write_thresh,
+		.read_event_config = &tsl2x7x_read_interrupt_config,
+		.write_event_config = &tsl2x7x_write_interrupt_config,
+	},
+	[ALSPRX2] = {
+		.attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2],
+		.event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
+		.driver_module = THIS_MODULE,
+		.read_raw = &tsl2x7x_read_raw,
+		.write_raw = &tsl2x7x_write_raw,
+		.read_event_value = &tsl2x7x_read_thresh,
+		.write_event_value = &tsl2x7x_write_thresh,
+		.read_event_config = &tsl2x7x_read_interrupt_config,
+		.write_event_config = &tsl2x7x_write_interrupt_config,
+	},
+};
+
+static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
+	[ALS] = {
+		.channel = {
+			{
+			.type = IIO_LIGHT,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+			}, {
+			.type = IIO_INTENSITY,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+				IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+				IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+			.event_mask = TSL2X7X_EVENT_MASK
+			}, {
+			.type = IIO_INTENSITY,
+			.indexed = 1,
+			.channel = 1,
+			},
+		},
+	.chan_table_elements = 3,
+	.info = &tsl2X7X_device_info[ALS],
+	},
+	[PRX] = {
+		.channel = {
+			{
+			.type = IIO_PROXIMITY,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+			.event_mask = TSL2X7X_EVENT_MASK
+			},
+		},
+	.chan_table_elements = 1,
+	.info = &tsl2X7X_device_info[PRX],
+	},
+	[ALSPRX] = {
+		.channel = {
+			{
+			.type = IIO_LIGHT,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT
+			}, {
+			.type = IIO_INTENSITY,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+				IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+				IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+			.event_mask = TSL2X7X_EVENT_MASK
+			}, {
+			.type = IIO_INTENSITY,
+			.indexed = 1,
+			.channel = 1,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+			}, {
+			.type = IIO_PROXIMITY,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+			.event_mask = TSL2X7X_EVENT_MASK
+			},
+		},
+	.chan_table_elements = 4,
+	.info = &tsl2X7X_device_info[ALSPRX],
+	},
+	[PRX2] = {
+		.channel = {
+			{
+			.type = IIO_PROXIMITY,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+				IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+			.event_mask = TSL2X7X_EVENT_MASK
+			},
+		},
+	.chan_table_elements = 1,
+	.info = &tsl2X7X_device_info[PRX2],
+	},
+	[ALSPRX2] = {
+		.channel = {
+			{
+			.type = IIO_LIGHT,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+			}, {
+			.type = IIO_INTENSITY,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+				IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+				IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+			.event_mask = TSL2X7X_EVENT_MASK
+			}, {
+			.type = IIO_INTENSITY,
+			.indexed = 1,
+			.channel = 1,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+			}, {
+			.type = IIO_PROXIMITY,
+			.indexed = 1,
+			.channel = 0,
+			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+				IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+			.event_mask = TSL2X7X_EVENT_MASK
+			},
+		},
+	.chan_table_elements = 4,
+	.info = &tsl2X7X_device_info[ALSPRX2],
+	},
+};
+
+static int __devinit tsl2x7x_probe(struct i2c_client *clientp,
+	const struct i2c_device_id *id)
+{
+	int ret;
+	unsigned char device_id;
+	struct iio_dev *indio_dev;
+	struct tsl2X7X_chip *chip;
+
+	indio_dev = iio_device_alloc(sizeof(*chip));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	chip = iio_priv(indio_dev);
+	chip->client = clientp;
+	i2c_set_clientdata(clientp, indio_dev);
+
+	ret = tsl2x7x_i2c_read(chip->client,
+		TSL2X7X_CHIPID, &device_id);
+	if (ret < 0)
+		goto fail1;
+
+	if ((!tsl2x7x_device_id(&device_id, id->driver_data)) ||
+		(tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) {
+		dev_info(&chip->client->dev,
+				"%s: i2c device found does not match expected id\n",
+				__func__);
+		goto fail1;
+	}
+
+	ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+	if (ret < 0) {
+		dev_err(&clientp->dev, "%s: write to cmd reg failed. err = %d\n",
+				__func__, ret);
+		goto fail1;
+	}
+
+	/* ALS and PROX functions can be invoked via user space poll
+	 * or H/W interrupt. If busy return last sample. */
+	mutex_init(&chip->als_mutex);
+	mutex_init(&chip->prox_mutex);
+
+	chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN;
+	chip->pdata = clientp->dev.platform_data;
+	chip->id = id->driver_data;
+	chip->chip_info =
+		&tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]];
+
+	indio_dev->info = chip->chip_info->info;
+	indio_dev->dev.parent = &clientp->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->name = chip->client->name;
+	indio_dev->channels = chip->chip_info->channel;
+	indio_dev->num_channels = chip->chip_info->chan_table_elements;
+
+	if (clientp->irq) {
+		ret = request_threaded_irq(clientp->irq,
+					   NULL,
+					   &tsl2x7x_event_handler,
+					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					   "TSL2X7X_event",
+					   indio_dev);
+		if (ret) {
+			dev_err(&clientp->dev,
+				"%s: irq request failed", __func__);
+			goto fail2;
+		}
+	}
+
+	/* Load up the defaults */
+	tsl2x7x_defaults(chip);
+	/* Make sure the chip is on */
+	tsl2x7x_chip_on(indio_dev);
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&clientp->dev,
+			"%s: iio registration failed\n", __func__);
+		goto fail1;
+	}
+
+	dev_info(&clientp->dev, "%s Light sensor found.\n", id->name);
+
+	return 0;
+
+fail1:
+	if (clientp->irq)
+		free_irq(clientp->irq, indio_dev);
+fail2:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int tsl2x7x_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	int ret = 0;
+
+	if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
+		ret = tsl2x7x_chip_off(indio_dev);
+		chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
+	}
+
+	if (chip->pdata && chip->pdata->platform_power) {
+		pm_message_t pmm = {PM_EVENT_SUSPEND};
+		chip->pdata->platform_power(dev, pmm);
+	}
+
+	return ret;
+}
+
+static int tsl2x7x_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+	int ret = 0;
+
+	if (chip->pdata && chip->pdata->platform_power) {
+		pm_message_t pmm = {PM_EVENT_RESUME};
+		chip->pdata->platform_power(dev, pmm);
+	}
+
+	if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED)
+		ret = tsl2x7x_chip_on(indio_dev);
+
+	return ret;
+}
+
+static int __devexit tsl2x7x_remove(struct i2c_client *client)
+{
+	struct tsl2X7X_chip *chip = i2c_get_clientdata(client);
+	struct iio_dev *indio_dev = iio_priv_to_dev(chip);
+
+	tsl2x7x_chip_off(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (client->irq)
+		free_irq(client->irq, chip->client->name);
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct i2c_device_id tsl2x7x_idtable[] = {
+	{ "tsl2571", tsl2571 },
+	{ "tsl2671", tsl2671 },
+	{ "tmd2671", tmd2671 },
+	{ "tsl2771", tsl2771 },
+	{ "tmd2771", tmd2771 },
+	{ "tsl2572", tsl2572 },
+	{ "tsl2672", tsl2672 },
+	{ "tmd2672", tmd2672 },
+	{ "tsl2772", tsl2772 },
+	{ "tmd2772", tmd2772 },
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable);
+
+static const struct dev_pm_ops tsl2x7x_pm_ops = {
+	.suspend = tsl2x7x_suspend,
+	.resume  = tsl2x7x_resume,
+};
+
+/* Driver definition */
+static struct i2c_driver tsl2x7x_driver = {
+	.driver = {
+		.name = "tsl2x7x",
+		.pm = &tsl2x7x_pm_ops,
+	},
+	.id_table = tsl2x7x_idtable,
+	.probe = tsl2x7x_probe,
+	.remove = __devexit_p(tsl2x7x_remove),
+};
+
+module_i2c_driver(tsl2x7x_driver);
+
+MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>");
+MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
index 722c4e1..b9d9325 100644
--- a/drivers/staging/iio/magnetometer/Kconfig
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -15,13 +15,13 @@
 	  will be called ak8975.
 
 config SENSORS_HMC5843
-	tristate "Honeywell HMC5843 3-Axis Magnetometer"
+	tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer"
 	depends on I2C
 	help
-	  Say Y here to add support for the Honeywell HMC 5843 3-Axis
-	  Magnetometer (digital compass).
+	  Say Y here to add support for the Honeywell HMC5843, HMC5883 and
+	  HMC5883L 3-Axis Magnetometer (digital compass).
 
 	  To compile this driver as a module, choose M here: the module
-	  will be called hmc5843
+	  will be called hmc5843.
 
 endmenu
diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c
index ebc2d08..5834e4a 100644
--- a/drivers/staging/iio/magnetometer/ak8975.c
+++ b/drivers/staging/iio/magnetometer/ak8975.c
@@ -30,8 +30,8 @@
 
 #include <linux/gpio.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 /*
  * Register definitions, as well as various shifts and masks to get at the
  * individual fields of the registers.
@@ -242,7 +242,7 @@
 static ssize_t show_mode(struct device *dev, struct device_attribute *devattr,
 			 char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ak8975_data *data = iio_priv(indio_dev);
 
 	return sprintf(buf, "%u\n", data->mode);
@@ -255,7 +255,7 @@
 static ssize_t store_mode(struct device *dev, struct device_attribute *devattr,
 			  const char *buf, size_t count)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ak8975_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
 	bool value;
@@ -431,7 +431,7 @@
 	struct ak8975_data *data = iio_priv(indio_dev);
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		return ak8975_read_axis(indio_dev, chan->address, val);
 	case IIO_CHAN_INFO_SCALE:
 		*val = data->raw_to_gauss[chan->address];
@@ -445,7 +445,8 @@
 		.type = IIO_MAGN,					\
 		.modified = 1,						\
 		.channel2 = IIO_MOD_##axis,				\
-		.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,	\
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+			     IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
 		.address = index,					\
 	}
 
@@ -505,7 +506,7 @@
 	}
 
 	/* Register with IIO */
-	indio_dev = iio_allocate_device(sizeof(*data));
+	indio_dev = iio_device_alloc(sizeof(*data));
 	if (indio_dev == NULL) {
 		err = -ENOMEM;
 		goto exit_gpio;
@@ -536,7 +537,7 @@
 	return 0;
 
 exit_free_iio:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 exit_gpio:
 	if (gpio_is_valid(eoc_gpio))
 		gpio_free(eoc_gpio);
@@ -554,7 +555,7 @@
 	if (gpio_is_valid(data->eoc_gpio))
 		gpio_free(data->eoc_gpio);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
index e00b416..c1fa09f 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -2,6 +2,8 @@
     Author: Shubhrajyoti Datta <shubhrajyoti@ti.com>
     Acknowledgement: Jonathan Cameron <jic23@cam.ac.uk> for valuable inputs.
 
+    Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>.
+
     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
@@ -22,10 +24,8 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/types.h>
-#include "../iio.h"
-#include "../sysfs.h"
-
-#define HMC5843_I2C_ADDRESS			0x1E
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #define HMC5843_CONFIG_REG_A			0x00
 #define HMC5843_CONFIG_REG_B			0x01
@@ -36,110 +36,185 @@
 #define HMC5843_DATA_OUT_Y_LSB_REG		0x06
 #define HMC5843_DATA_OUT_Z_MSB_REG		0x07
 #define HMC5843_DATA_OUT_Z_LSB_REG		0x08
+/* Beware: Y and Z are exchanged on HMC5883 */
+#define HMC5883_DATA_OUT_Z_MSB_REG		0x05
+#define HMC5883_DATA_OUT_Z_LSB_REG		0x06
+#define HMC5883_DATA_OUT_Y_MSB_REG		0x07
+#define HMC5883_DATA_OUT_Y_LSB_REG		0x08
 #define HMC5843_STATUS_REG			0x09
 #define HMC5843_ID_REG_A			0x0A
 #define HMC5843_ID_REG_B			0x0B
 #define HMC5843_ID_REG_C			0x0C
 
-#define HMC5843_ID_REG_LENGTH			0x03
-#define HMC5843_ID_STRING			"H43"
+enum hmc5843_ids {
+	HMC5843_ID,
+	HMC5883_ID,
+	HMC5883L_ID,
+};
 
 /*
- * Range settings in  (+-)Ga
- * */
-#define RANGE_GAIN_OFFSET			0x05
+ * Beware: identification of the HMC5883 is still "H43";
+ * I2C address is also unchanged
+ */
+#define HMC5843_ID_REG_LENGTH			0x03
+#define HMC5843_ID_STRING			"H43"
+#define HMC5843_I2C_ADDRESS			0x1E
 
-#define	RANGE_0_7				0x00
-#define	RANGE_1_0				0x01 /* default */
-#define	RANGE_1_5				0x02
-#define	RANGE_2_0				0x03
-#define	RANGE_3_2				0x04
-#define	RANGE_3_8				0x05
-#define	RANGE_4_5				0x06
-#define	RANGE_6_5				0x07 /* Not recommended */
+/*
+ * Range gain settings in (+-)Ga
+ * Beware: HMC5843 and HMC5883 have different recommended sensor field
+ * ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively
+ */
+#define HMC5843_RANGE_GAIN_OFFSET		0x05
+#define HMC5843_RANGE_GAIN_DEFAULT		0x01
+#define HMC5843_RANGE_GAIN_MAX			0x07
 
 /*
  * Device status
  */
-#define	DATA_READY				0x01
-#define	DATA_OUTPUT_LOCK			0x02
-#define	VOLTAGE_REGULATOR_ENABLED		0x04
+#define HMC5843_DATA_READY			0x01
+#define HMC5843_DATA_OUTPUT_LOCK		0x02
+/* Does not exist on HMC5883, not used */
+#define HMC5843_VOLTAGE_REGULATOR_ENABLED	0x04
 
 /*
  * Mode register configuration
  */
-#define	MODE_CONVERSION_CONTINUOUS		0x00
-#define	MODE_CONVERSION_SINGLE			0x01
-#define	MODE_IDLE				0x02
-#define	MODE_SLEEP				0x03
-
-/* Minimum Data Output Rate in 1/10 Hz  */
-#define RATE_OFFSET				0x02
-#define RATE_BITMASK				0x1C
-#define	RATE_5					0x00
-#define	RATE_10					0x01
-#define	RATE_20					0x02
-#define	RATE_50					0x03
-#define	RATE_100				0x04
-#define	RATE_200				0x05
-#define	RATE_500				0x06
-#define	RATE_NOT_USED				0x07
+#define HMC5843_MODE_CONVERSION_CONTINUOUS	0x00
+#define HMC5843_MODE_CONVERSION_SINGLE		0x01
+#define HMC5843_MODE_IDLE			0x02
+#define HMC5843_MODE_SLEEP			0x03
+#define HMC5843_MODE_MASK			0x03
 
 /*
- * Device Configuration
+ * HMC5843: Minimum data output rate
+ * HMC5883: Typical data output rate
  */
-#define	CONF_NORMAL				0x00
-#define	CONF_POSITIVE_BIAS			0x01
-#define	CONF_NEGATIVE_BIAS			0x02
-#define	CONF_NOT_USED				0x03
-#define	MEAS_CONF_MASK				0x03
+#define HMC5843_RATE_OFFSET			0x02
+#define HMC5843_RATE_BITMASK			0x1C
+#define HMC5843_RATE_NOT_USED			0x07
 
-static int hmc5843_regval_to_nanoscale[] = {
+/*
+ * Device measurement configuration
+ */
+#define HMC5843_MEAS_CONF_NORMAL		0x00
+#define HMC5843_MEAS_CONF_POSITIVE_BIAS		0x01
+#define HMC5843_MEAS_CONF_NEGATIVE_BIAS		0x02
+#define HMC5843_MEAS_CONF_NOT_USED		0x03
+#define HMC5843_MEAS_CONF_MASK			0x03
+
+/*
+ * Scaling factors: 10000000/Gain
+ */
+static const int hmc5843_regval_to_nanoscale[] = {
 	6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
 };
 
-static const int regval_to_input_field_mg[] = {
-	700,
-	1000,
-	1500,
-	2000,
-	3200,
-	3800,
-	4500,
-	6500
+static const int hmc5883_regval_to_nanoscale[] = {
+	7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662
 };
-static const char * const regval_to_samp_freq[] = {
-	"0.5",
-	"1",
-	"2",
-	"5",
-	"10",
-	"20",
-	"50",
+
+static const int hmc5883l_regval_to_nanoscale[] = {
+	7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478
+};
+
+/*
+ * From the HMC5843 datasheet:
+ * Value	| Sensor input field range (Ga)	| Gain (counts/milli-Gauss)
+ * 0		| (+-)0.7			| 1620
+ * 1		| (+-)1.0			| 1300
+ * 2		| (+-)1.5			| 970
+ * 3		| (+-)2.0			| 780
+ * 4		| (+-)3.2			| 530
+ * 5		| (+-)3.8			| 460
+ * 6		| (+-)4.5			| 390
+ * 7		| (+-)6.5			| 280
+ *
+ * From the HMC5883 datasheet:
+ * Value	| Recommended sensor field range (Ga)	| Gain (counts/Gauss)
+ * 0		| (+-)0.9				| 1280
+ * 1		| (+-)1.2				| 1024
+ * 2		| (+-)1.9				| 768
+ * 3		| (+-)2.5				| 614
+ * 4		| (+-)4.0				| 415
+ * 5		| (+-)4.6				| 361
+ * 6		| (+-)5.5				| 307
+ * 7		| (+-)7.9				| 219
+ *
+ * From the HMC5883L datasheet:
+ * Value	| Recommended sensor field range (Ga)	| Gain (LSB/Gauss)
+ * 0		| (+-)0.88				| 1370
+ * 1		| (+-)1.3				| 1090
+ * 2		| (+-)1.9				| 820
+ * 3		| (+-)2.5				| 660
+ * 4		| (+-)4.0				| 440
+ * 5		| (+-)4.7				| 390
+ * 6		| (+-)5.6				| 330
+ * 7		| (+-)8.1				| 230
+ */
+static const int hmc5843_regval_to_input_field_mga[] = {
+	700, 1000, 1500, 2000, 3200, 3800, 4500, 6500
+};
+
+static const int hmc5883_regval_to_input_field_mga[] = {
+	900, 1200, 1900, 2500, 4000, 4600, 5500, 7900
+};
+
+static const int hmc5883l_regval_to_input_field_mga[] = {
+	880, 1300, 1900, 2500, 4000, 4700, 5600, 8100
+};
+
+/*
+ * From the datasheet:
+ * Value	| HMC5843		| HMC5883/HMC5883L
+ *		| Data output rate (Hz)	| Data output rate (Hz)
+ * 0		| 0.5			| 0.75
+ * 1		| 1			| 1.5
+ * 2		| 2			| 3
+ * 3		| 5			| 7.5
+ * 4		| 10 (default)		| 15
+ * 5		| 20			| 30
+ * 6		| 50			| 75
+ * 7		| Not used		| Not used
+ */
+static const char * const hmc5843_regval_to_sample_freq[] = {
+	"0.5", "1", "2", "5", "10", "20", "50",
+};
+
+static const char * const hmc5883_regval_to_sample_freq[] = {
+	"0.75", "1.5", "3", "7.5", "15", "30", "75",
 };
 
 /* Addresses to scan: 0x1E */
 static const unsigned short normal_i2c[] = { HMC5843_I2C_ADDRESS,
-							I2C_CLIENT_END };
+					     I2C_CLIENT_END };
+
+/* Describe chip variants */
+struct hmc5843_chip_info {
+	const struct iio_chan_spec *channels;
+	int num_channels;
+	const char * const *regval_to_sample_freq;
+	const int *regval_to_input_field_mga;
+	const int *regval_to_nanoscale;
+};
 
 /* Each client has this additional data */
 struct hmc5843_data {
 	struct mutex lock;
-	u8		rate;
-	u8		meas_conf;
-	u8		operating_mode;
-	u8		range;
+	u8 rate;
+	u8 meas_conf;
+	u8 operating_mode;
+	u8 range;
+	const struct hmc5843_chip_info *variant;
 };
 
-static void hmc5843_init_client(struct i2c_client *client);
-
+/* The lower two bits contain the current conversion mode */
 static s32 hmc5843_configure(struct i2c_client *client,
 				       u8 operating_mode)
 {
-	/* The lower two bits contain the current conversion mode */
 	return i2c_smbus_write_byte_data(client,
 					HMC5843_MODE_REG,
-					(operating_mode & 0x03));
+					operating_mode & HMC5843_MODE_MASK);
 }
 
 /* Return the measurement value from the specified channel */
@@ -153,7 +228,7 @@
 
 	mutex_lock(&data->lock);
 	result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
-	while (!(result & DATA_READY))
+	while (!(result & HMC5843_DATA_READY))
 		result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
 
 	result = i2c_smbus_read_word_data(client, address);
@@ -161,30 +236,29 @@
 	if (result < 0)
 		return -EINVAL;
 
-	*val	= (s16)swab16((u16)result);
+	*val = (s16)swab16((u16)result);
 	return IIO_VAL_INT;
 }
 
-
 /*
- * From the datasheet
+ * From the datasheet:
  * 0 - Continuous-Conversion Mode: In continuous-conversion mode, the
- * device continuously performs conversions and places the result in the
- * data register.
+ *     device continuously performs conversions and places the result in
+ *     the data register.
  *
- * 1 - Single-Conversion Mode : device performs a single measurement,
- *  sets RDY high and returned to sleep mode
+ * 1 - Single-Conversion Mode : Device performs a single measurement,
+ *     sets RDY high and returns to sleep mode.
  *
- * 2 - Idle Mode :  Device is placed in idle mode.
+ * 2 - Idle Mode : Device is placed in idle mode.
  *
- * 3 - Sleep Mode. Device is placed in sleep mode.
+ * 3 - Sleep Mode : Device is placed in sleep mode.
  *
  */
 static ssize_t hmc5843_show_operating_mode(struct device *dev,
 					struct device_attribute *attr,
 					char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct hmc5843_data *data = iio_priv(indio_dev);
 	return sprintf(buf, "%d\n", data->operating_mode);
 }
@@ -194,21 +268,22 @@
 				const char *buf,
 				size_t count)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
 	struct hmc5843_data *data = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	unsigned long operating_mode = 0;
 	s32 status;
 	int error;
+
 	mutex_lock(&data->lock);
-	error = strict_strtoul(buf, 10, &operating_mode);
+	error = kstrtoul(buf, 10, &operating_mode);
 	if (error) {
 		count = error;
 		goto exit;
 	}
-	dev_dbg(dev, "set Conversion mode to %lu\n", operating_mode);
-	if (operating_mode > MODE_SLEEP) {
+	dev_dbg(dev, "set conversion mode to %lu\n", operating_mode);
+	if (operating_mode > HMC5843_MODE_SLEEP) {
 		count = -EINVAL;
 		goto exit;
 	}
@@ -225,6 +300,7 @@
 	mutex_unlock(&data->lock);
 	return count;
 }
+
 static IIO_DEVICE_ATTR(operating_mode,
 			S_IWUSR | S_IRUGO,
 			hmc5843_show_operating_mode,
@@ -234,25 +310,29 @@
 /*
  * API for setting the measurement configuration to
  * Normal, Positive bias and Negative bias
- * From the datasheet
  *
- * Normal measurement configuration (default): In normal measurement
- * configuration the device follows normal measurement flow. Pins BP and BN
- * are left floating and high impedance.
+ * From the datasheet:
+ * 0 - Normal measurement configuration (default): In normal measurement
+ *     configuration the device follows normal measurement flow. Pins BP
+ *     and BN are left floating and high impedance.
  *
- * Positive bias configuration: In positive bias configuration, a positive
- * current is forced across the resistive load on pins BP and BN.
+ * 1 - Positive bias configuration: In positive bias configuration, a
+ *     positive current is forced across the resistive load on pins BP
+ *     and BN.
  *
- * Negative bias configuration. In negative bias configuration, a negative
- * current is forced across the resistive load on pins BP and BN.
+ * 2 - Negative bias configuration. In negative bias configuration, a
+ *     negative current is forced across the resistive load on pins BP
+ *     and BN.
  *
  */
 static s32 hmc5843_set_meas_conf(struct i2c_client *client,
 				      u8 meas_conf)
 {
-	struct hmc5843_data *data = i2c_get_clientdata(client);
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct hmc5843_data *data = iio_priv(indio_dev);
 	u8 reg_val;
-	reg_val = (meas_conf & MEAS_CONF_MASK) |  (data->rate << RATE_OFFSET);
+	reg_val = (meas_conf & HMC5843_MEAS_CONF_MASK) |
+		(data->rate << HMC5843_RATE_OFFSET);
 	return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val);
 }
 
@@ -260,7 +340,7 @@
 						struct device_attribute *attr,
 						char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct hmc5843_data *data = iio_priv(indio_dev);
 	return sprintf(buf, "%d\n", data->meas_conf);
 }
@@ -270,16 +350,20 @@
 						const char *buf,
 						size_t count)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
-	struct hmc5843_data *data = i2c_get_clientdata(client);
+	struct hmc5843_data *data = iio_priv(indio_dev);
 	unsigned long meas_conf = 0;
-	int error = strict_strtoul(buf, 10, &meas_conf);
+	int error;
+
+	error = kstrtoul(buf, 10, &meas_conf);
 	if (error)
 		return error;
-	mutex_lock(&data->lock);
+	if (meas_conf >= HMC5843_MEAS_CONF_NOT_USED)
+		return -EINVAL;
 
-	dev_dbg(dev, "set mode to %lu\n", meas_conf);
+	mutex_lock(&data->lock);
+	dev_dbg(dev, "set measurement configuration to %lu\n", meas_conf);
 	if (hmc5843_set_meas_conf(client, meas_conf)) {
 		count = -EINVAL;
 		goto exit;
@@ -290,71 +374,85 @@
 	mutex_unlock(&data->lock);
 	return count;
 }
+
 static IIO_DEVICE_ATTR(meas_conf,
 			S_IWUSR | S_IRUGO,
 			hmc5843_show_measurement_configuration,
 			hmc5843_set_measurement_configuration,
 			0);
 
-/*
- * From Datasheet
- * The table shows the minimum data output
- * Value	| Minimum data output rate(Hz)
- * 0		| 0.5
- * 1		| 1
- * 2		| 2
- * 3		| 5
- * 4		| 10 (default)
- * 5		| 20
- * 6		| 50
- * 7		| Not used
- */
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("0.5 1 2 5 10 20 50");
+static ssize_t hmc5843_show_sampling_frequencies_available(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct hmc5843_data *data = iio_priv(indio_dev);
+	ssize_t total_n = 0;
+	int i;
+
+	for (i = 0; i < HMC5843_RATE_NOT_USED; i++) {
+		ssize_t n = sprintf(buf, "%s ", data->variant->regval_to_sample_freq[i]);
+		buf += n;
+		total_n += n;
+	}
+	/* replace trailing space by newline */
+	buf[-1] = '\n';
+
+	return total_n;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_sampling_frequencies_available);
 
 static s32 hmc5843_set_rate(struct i2c_client *client,
 				u8 rate)
 {
-	struct hmc5843_data *data = i2c_get_clientdata(client);
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct hmc5843_data *data = iio_priv(indio_dev);
 	u8 reg_val;
 
-	reg_val = (data->meas_conf) |  (rate << RATE_OFFSET);
-	if (rate >= RATE_NOT_USED) {
+	if (rate >= HMC5843_RATE_NOT_USED) {
 		dev_err(&client->dev,
-			"This data output rate is not supported\n");
+			"data output rate is not supported\n");
 		return -EINVAL;
 	}
+
+	reg_val = data->meas_conf | (rate << HMC5843_RATE_OFFSET);
 	return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val);
 }
 
-static ssize_t set_sampling_frequency(struct device *dev,
+static int hmc5843_check_sampling_frequency(struct hmc5843_data *data,
+						const char *buf)
+{
+	const char * const *samp_freq = data->variant->regval_to_sample_freq;
+	int i;
+
+	for (i = 0; i < HMC5843_RATE_NOT_USED; i++) {
+		if (sysfs_streq(buf, samp_freq[i]))
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static ssize_t hmc5843_set_sampling_frequency(struct device *dev,
 					struct device_attribute *attr,
 					const char *buf, size_t count)
 {
 
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
 	struct hmc5843_data *data = iio_priv(indio_dev);
-	unsigned long rate = 0;
+	int rate;
 
-	if (strncmp(buf, "0.5" , 3) == 0)
-		rate = RATE_5;
-	else if (strncmp(buf, "1" , 1) == 0)
-		rate = RATE_10;
-	else if (strncmp(buf, "2", 1) == 0)
-		rate = RATE_20;
-	else if (strncmp(buf, "5", 1) == 0)
-		rate = RATE_50;
-	else if (strncmp(buf, "10", 2) == 0)
-		rate = RATE_100;
-	else if (strncmp(buf, "20" , 2) == 0)
-		rate = RATE_200;
-	else if (strncmp(buf, "50" , 2) == 0)
-		rate = RATE_500;
-	else
-		return -EINVAL;
+	rate = hmc5843_check_sampling_frequency(data, buf);
+	if (rate < 0) {
+		dev_err(&client->dev,
+			"sampling frequency is not supported\n");
+		return rate;
+	}
 
 	mutex_lock(&data->lock);
-	dev_dbg(dev, "set rate to %lu\n", rate);
+	dev_dbg(dev, "set rate to %d\n", rate);
 	if (hmc5843_set_rate(client, rate)) {
 		count = -EINVAL;
 		goto exit;
@@ -366,89 +464,79 @@
 	return count;
 }
 
-static ssize_t show_sampling_frequency(struct device *dev,
+static ssize_t hmc5843_show_sampling_frequency(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	struct hmc5843_data *data = iio_priv(indio_dev);
 	s32 rate;
 
-	rate = i2c_smbus_read_byte_data(client,  this_attr->address);
+	rate = i2c_smbus_read_byte_data(client, this_attr->address);
 	if (rate < 0)
 		return rate;
-	rate = (rate & RATE_BITMASK) >> RATE_OFFSET;
-	return sprintf(buf, "%s\n", regval_to_samp_freq[rate]);
+	rate = (rate & HMC5843_RATE_BITMASK) >> HMC5843_RATE_OFFSET;
+	return sprintf(buf, "%s\n", data->variant->regval_to_sample_freq[rate]);
 }
+
 static IIO_DEVICE_ATTR(sampling_frequency,
 			S_IWUSR | S_IRUGO,
-			show_sampling_frequency,
-			set_sampling_frequency,
+			hmc5843_show_sampling_frequency,
+			hmc5843_set_sampling_frequency,
 			HMC5843_CONFIG_REG_A);
 
-/*
- * From Datasheet
- *	Nominal gain settings
- * Value	| Sensor Input Field Range(Ga)	| Gain(counts/ milli-gauss)
- *0		|(+-)0.7			|1620
- *1		|(+-)1.0			|1300
- *2		|(+-)1.5			|970
- *3		|(+-)2.0			|780
- *4		|(+-)3.2			|530
- *5		|(+-)3.8			|460
- *6		|(+-)4.5			|390
- *7		|(+-)6.5			|280
- */
-static ssize_t show_range(struct device *dev,
+static ssize_t hmc5843_show_range_gain(struct device *dev,
 				struct device_attribute *attr,
 				char *buf)
 {
 	u8 range;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct hmc5843_data *data = iio_priv(indio_dev);
 
 	range = data->range;
-	return sprintf(buf, "%d\n", regval_to_input_field_mg[range]);
+	return sprintf(buf, "%d\n", data->variant->regval_to_input_field_mga[range]);
 }
 
-static ssize_t set_range(struct device *dev,
+static ssize_t hmc5843_set_range_gain(struct device *dev,
 			struct device_attribute *attr,
 			const char *buf,
 			size_t count)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	struct hmc5843_data *data = iio_priv(indio_dev);
 	unsigned long range = 0;
 	int error;
+
 	mutex_lock(&data->lock);
-	error = strict_strtoul(buf, 10, &range);
+	error = kstrtoul(buf, 10, &range);
 	if (error) {
 		count = error;
 		goto exit;
 	}
 	dev_dbg(dev, "set range to %lu\n", range);
 
-	if (range > RANGE_6_5) {
+	if (range > HMC5843_RANGE_GAIN_MAX) {
 		count = -EINVAL;
 		goto exit;
 	}
 
 	data->range = range;
-	range = range << RANGE_GAIN_OFFSET;
+	range = range << HMC5843_RANGE_GAIN_OFFSET;
 	if (i2c_smbus_write_byte_data(client, this_attr->address, range))
 		count = -EINVAL;
 
 exit:
 	mutex_unlock(&data->lock);
 	return count;
-
 }
+
 static IIO_DEVICE_ATTR(in_magn_range,
 			S_IWUSR | S_IRUGO,
-			show_range,
-			set_range,
+			hmc5843_show_range_gain,
+			hmc5843_set_range_gain,
 			HMC5843_CONFIG_REG_B);
 
 static int hmc5843_read_raw(struct iio_dev *indio_dev,
@@ -459,13 +547,13 @@
 	struct hmc5843_data *data = iio_priv(indio_dev);
 
 	switch (mask) {
-	case 0:
+	case IIO_CHAN_INFO_RAW:
 		return hmc5843_read_measurement(indio_dev,
 						chan->address,
 						val);
 	case IIO_CHAN_INFO_SCALE:
 		*val = 0;
-		*val2 = hmc5843_regval_to_nanoscale[data->range];
+		*val2 = data->variant->regval_to_nanoscale[data->range];
 		return IIO_VAL_INT_PLUS_NANO;
 	};
 	return -EINVAL;
@@ -476,7 +564,8 @@
 		.type = IIO_MAGN,					\
 		.modified = 1,						\
 		.channel2 = IIO_MOD_##axis,				\
-		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,		\
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,		\
 		.address = add						\
 	}
 
@@ -486,12 +575,18 @@
 	HMC5843_CHANNEL(Z, HMC5843_DATA_OUT_Z_MSB_REG),
 };
 
+static const struct iio_chan_spec hmc5883_channels[] = {
+	HMC5843_CHANNEL(X, HMC5843_DATA_OUT_X_MSB_REG),
+	HMC5843_CHANNEL(Y, HMC5883_DATA_OUT_Y_MSB_REG),
+	HMC5843_CHANNEL(Z, HMC5883_DATA_OUT_Z_MSB_REG),
+};
+
 static struct attribute *hmc5843_attributes[] = {
 	&iio_dev_attr_meas_conf.dev_attr.attr,
 	&iio_dev_attr_operating_mode.dev_attr.attr,
 	&iio_dev_attr_sampling_frequency.dev_attr.attr,
 	&iio_dev_attr_in_magn_range.dev_attr.attr,
-	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
 	NULL
 };
 
@@ -499,6 +594,33 @@
 	.attrs = hmc5843_attributes,
 };
 
+static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
+	[HMC5843_ID] = {
+		.channels = hmc5843_channels,
+		.num_channels = ARRAY_SIZE(hmc5843_channels),
+		.regval_to_sample_freq = hmc5843_regval_to_sample_freq,
+		.regval_to_input_field_mga =
+			hmc5843_regval_to_input_field_mga,
+		.regval_to_nanoscale = hmc5843_regval_to_nanoscale,
+	},
+	[HMC5883_ID] = {
+		.channels = hmc5883_channels,
+		.num_channels = ARRAY_SIZE(hmc5883_channels),
+		.regval_to_sample_freq = hmc5883_regval_to_sample_freq,
+		.regval_to_input_field_mga =
+			hmc5883_regval_to_input_field_mga,
+		.regval_to_nanoscale = hmc5883_regval_to_nanoscale,
+	},
+	[HMC5883L_ID] = {
+		.channels = hmc5883_channels,
+		.num_channels = ARRAY_SIZE(hmc5883_channels),
+		.regval_to_sample_freq = hmc5883_regval_to_sample_freq,
+		.regval_to_input_field_mga =
+			hmc5883l_regval_to_input_field_mga,
+		.regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
+	},
+};
+
 static int hmc5843_detect(struct i2c_client *client,
 			  struct i2c_board_info *info)
 {
@@ -518,18 +640,23 @@
 	return 0;
 }
 
-/* Called when we have found a new HMC5843. */
-static void hmc5843_init_client(struct i2c_client *client)
+/* Called when we have found a new HMC58X3 */
+static void hmc5843_init_client(struct i2c_client *client,
+				const struct i2c_device_id *id)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 	struct hmc5843_data *data = iio_priv(indio_dev);
 
+	data->variant = &hmc5843_chip_info_tbl[id->driver_data];
+	indio_dev->channels = data->variant->channels;
+	indio_dev->num_channels = data->variant->num_channels;
 	hmc5843_set_meas_conf(client, data->meas_conf);
 	hmc5843_set_rate(client, data->rate);
 	hmc5843_configure(client, data->operating_mode);
 	i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_B, data->range);
 	mutex_init(&data->lock);
-	pr_info("HMC5843 initialized\n");
+
+	pr_info("%s initialized\n", id->name);
 }
 
 static const struct iio_info hmc5843_info = {
@@ -545,35 +672,34 @@
 	struct iio_dev *indio_dev;
 	int err = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*data));
+	indio_dev = iio_device_alloc(sizeof(*data));
 	if (indio_dev == NULL) {
 		err = -ENOMEM;
 		goto exit;
 	}
-	data = iio_priv(indio_dev);
-	/* default settings at probe */
 
-	data->meas_conf = CONF_NORMAL;
-	data->range = RANGE_1_0;
-	data->operating_mode = MODE_CONVERSION_CONTINUOUS;
+	/* default settings at probe */
+	data = iio_priv(indio_dev);
+	data->meas_conf = HMC5843_MEAS_CONF_NORMAL;
+	data->range = HMC5843_RANGE_GAIN_DEFAULT;
+	data->operating_mode = HMC5843_MODE_CONVERSION_CONTINUOUS;
 
 	i2c_set_clientdata(client, indio_dev);
-
-	/* Initialize the HMC5843 chip */
-	hmc5843_init_client(client);
+	hmc5843_init_client(client, id);
 
 	indio_dev->info = &hmc5843_info;
 	indio_dev->name = id->name;
-	indio_dev->channels = hmc5843_channels;
-	indio_dev->num_channels = ARRAY_SIZE(hmc5843_channels);
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->modes = INDIO_DIRECT_MODE;
+
 	err = iio_device_register(indio_dev);
 	if (err)
 		goto exit_free2;
+
 	return 0;
+
 exit_free2:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 exit:
 	return err;
 }
@@ -584,8 +710,8 @@
 
 	iio_device_unregister(indio_dev);
 	 /*  sleep mode to save power */
-	hmc5843_configure(client, MODE_SLEEP);
-	iio_free_device(indio_dev);
+	hmc5843_configure(client, HMC5843_MODE_SLEEP);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
@@ -593,14 +719,18 @@
 #ifdef CONFIG_PM_SLEEP
 static int hmc5843_suspend(struct device *dev)
 {
-	hmc5843_configure(to_i2c_client(dev), MODE_SLEEP);
+	hmc5843_configure(to_i2c_client(dev), HMC5843_MODE_SLEEP);
 	return 0;
 }
 
 static int hmc5843_resume(struct device *dev)
 {
-	struct hmc5843_data *data = i2c_get_clientdata(to_i2c_client(dev));
-	hmc5843_configure(to_i2c_client(dev), data->operating_mode);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct hmc5843_data *data = iio_priv(indio_dev);
+
+	hmc5843_configure(client, data->operating_mode);
+
 	return 0;
 }
 
@@ -611,7 +741,9 @@
 #endif
 
 static const struct i2c_device_id hmc5843_id[] = {
-	{ "hmc5843", 0 },
+	{ "hmc5843", HMC5843_ID },
+	{ "hmc5883", HMC5883_ID },
+	{ "hmc5883l", HMC5883L_ID },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, hmc5843_id);
@@ -630,5 +762,5 @@
 module_i2c_driver(hmc5843_driver);
 
 MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com");
-MODULE_DESCRIPTION("HMC5843 driver");
+MODULE_DESCRIPTION("HMC5843/5883/5883L driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index 57baac6..f04ece7 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -18,8 +18,8 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "meter.h"
 #include "ade7753.h"
 
@@ -28,7 +28,7 @@
 				   u8 val)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7753_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -46,7 +46,7 @@
 		u16 value)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7753_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -63,7 +63,7 @@
 		u8 reg_address,
 		u8 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7753_state *st = iio_priv(indio_dev);
 	ssize_t ret;
 
@@ -82,7 +82,7 @@
 		u8 reg_address,
 		u16 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7753_state *st = iio_priv(indio_dev);
 	ssize_t ret;
 
@@ -104,7 +104,7 @@
 		u32 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7753_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -416,7 +416,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7753_state *st = iio_priv(indio_dev);
 	unsigned long val;
 	int ret;
@@ -517,7 +517,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -546,7 +546,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 error_ret:
 	return ret;
@@ -564,7 +564,7 @@
 	if (ret)
 		goto err_ret;
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 err_ret:
 	return ret;
 }
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index 8d81c920..6cee28a 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -18,8 +18,8 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "meter.h"
 #include "ade7754.h"
 
@@ -28,7 +28,7 @@
 		u8 val)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7754_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -46,7 +46,7 @@
 		u16 value)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7754_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -63,7 +63,7 @@
 		u8 reg_address,
 		u8 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7754_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -82,7 +82,7 @@
 		u8 reg_address,
 		u16 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7754_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -104,7 +104,7 @@
 		u32 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7754_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -436,7 +436,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7754_state *st = iio_priv(indio_dev);
 	unsigned long val;
 	int ret;
@@ -540,7 +540,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -568,7 +568,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 error_ret:
 	return ret;
@@ -585,7 +585,7 @@
 	if (ret)
 		goto err_ret;
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 err_ret:
 	return ret;
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index dcb2029..96d6114 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -18,9 +18,9 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
 #include "meter.h"
 #include "ade7758.h"
 
@@ -29,7 +29,7 @@
 		u8 val)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -48,7 +48,7 @@
 {
 	int ret;
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfers[] = {
 		{
@@ -77,7 +77,7 @@
 {
 	int ret;
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfers[] = {
 		{
@@ -106,7 +106,7 @@
 		u8 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -149,7 +149,7 @@
 		u16 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -195,7 +195,7 @@
 		u32 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -534,7 +534,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	unsigned long val;
 	int ret;
 	u8 reg, t;
@@ -662,66 +662,217 @@
 };
 
 static struct iio_chan_spec ade7758_channels[] = {
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 0, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE),
-		0, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 0, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT),
-		1, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 0, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR),
-		2, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 0, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR),
-		3, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 0, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR),
-		4, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 1, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE),
-		5, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 1, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT),
-		6, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 1, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR),
-		7, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 1, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR),
-		8, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 1, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR),
-		9, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 2, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE),
-		10, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 2, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT),
-		11, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 2, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR),
-		12, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 2, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR),
-		13, IIO_ST('s', 24, 32, 0), 0),
-	IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 2, 0,
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR),
-		14, IIO_ST('s', 24, 32, 0), 0),
+	{
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_CURRENT,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT),
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_POWER,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "apparent_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR),
+		.scan_index = 2,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_POWER,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "active_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR),
+		.scan_index = 3,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_POWER,
+		.indexed = 1,
+		.channel = 0,
+		.extend_name = "reactive_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR),
+		.scan_index = 4,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 1,
+		.extend_name = "raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE),
+		.scan_index = 5,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_CURRENT,
+		.indexed = 1,
+		.channel = 1,
+		.extend_name = "raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT),
+		.scan_index = 6,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_POWER,
+		.indexed = 1,
+		.channel = 1,
+		.extend_name = "apparent_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR),
+		.scan_index = 7,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_POWER,
+		.indexed = 1,
+		.channel = 1,
+		.extend_name = "active_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR),
+		.scan_index = 8,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_POWER,
+		.indexed = 1,
+		.channel = 1,
+		.extend_name = "reactive_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR),
+		.scan_index = 9,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 2,
+		.extend_name = "raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE),
+		.scan_index = 10,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_CURRENT,
+		.indexed = 1,
+		.channel = 2,
+		.extend_name = "raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT),
+		.scan_index = 11,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_POWER,
+		.indexed = 1,
+		.channel = 2,
+		.extend_name = "apparent_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR),
+		.scan_index = 12,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_POWER,
+		.indexed = 1,
+		.channel = 2,
+		.extend_name = "active_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR),
+		.scan_index = 13,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	}, {
+		.type = IIO_POWER,
+		.indexed = 1,
+		.channel = 2,
+		.extend_name = "reactive_raw",
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			     IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.address = AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR),
+		.scan_index = 14,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+		},
+	},
 	IIO_CHAN_SOFT_TIMESTAMP(15),
 };
 
@@ -734,7 +885,7 @@
 {
 	int i, ret;
 	struct ade7758_state *st;
-	struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
 
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
@@ -800,7 +951,7 @@
 	return 0;
 
 error_remove_trigger:
-	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+	if (spi->irq)
 		ade7758_remove_trigger(indio_dev);
 error_uninitialize_ring:
 	ade7758_uninitialize_ring(indio_dev);
@@ -811,7 +962,7 @@
 error_free_rx:
 	kfree(st->rx);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -833,7 +984,7 @@
 	kfree(st->tx);
 	kfree(st->rx);
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 err_ret:
 	return ret;
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index c45b23b..92159f2 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -12,18 +12,17 @@
 #include <linux/slab.h>
 #include <asm/unaligned.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
 #include "ade7758.h"
 
 /**
  * ade7758_spi_read_burst() - read data registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
  **/
-static int ade7758_spi_read_burst(struct device *dev)
+static int ade7758_spi_read_burst(struct iio_dev *indio_dev)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -68,11 +67,11 @@
 	u32 *dat32 = (u32 *)dat64;
 
 	if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
-		if (ade7758_spi_read_burst(&indio_dev->dev) >= 0)
+		if (ade7758_spi_read_burst(indio_dev) >= 0)
 			*dat32 = get_unaligned_be32(&st->rx_buf[5]) & 0xFFFFFF;
 
 	/* Guaranteed to be aligned with 8 byte boundary */
-	if (ring->scan_timestamp)
+	if (indio_dev->scan_timestamp)
 		dat64[1] = pf->timestamp;
 
 	ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
@@ -92,29 +91,19 @@
 static int ade7758_ring_preenable(struct iio_dev *indio_dev)
 {
 	struct ade7758_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
-	size_t d_size;
 	unsigned channel;
+	int ret;
 
 	if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
 		return -EINVAL;
 
+	ret = iio_sw_buffer_preenable(indio_dev);
+	if (ret < 0)
+		return ret;
+
 	channel = find_first_bit(indio_dev->active_scan_mask,
 				 indio_dev->masklength);
 
-	d_size = st->ade7758_ring_channels[channel].scan_type.storagebits / 8;
-
-	if (ring->scan_timestamp) {
-		d_size += sizeof(s64);
-
-		if (d_size % sizeof(s64))
-			d_size += sizeof(s64) - (d_size % sizeof(s64));
-	}
-
-	if (indio_dev->buffer->access->set_bytes_per_datum)
-		indio_dev->buffer->access->
-			set_bytes_per_datum(indio_dev->buffer, d_size);
-
 	ade7758_write_waveform_type(&indio_dev->dev,
 		st->ade7758_ring_channels[channel].address);
 
diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c
index b6569c7..f9c6a34 100644
--- a/drivers/staging/iio/meter/ade7758_trigger.c
+++ b/drivers/staging/iio/meter/ade7758_trigger.c
@@ -11,8 +11,8 @@
 #include <linux/spi/spi.h>
 #include <linux/export.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 #include "ade7758.h"
 
 /**
@@ -63,7 +63,7 @@
 	struct ade7758_state *st = iio_priv(indio_dev);
 	int ret;
 
-	st->trig = iio_allocate_trigger("%s-dev%d",
+	st->trig = iio_trigger_alloc("%s-dev%d",
 					spi_get_device_id(st->us)->name,
 					indio_dev->id);
 	if (st->trig == NULL) {
@@ -94,7 +94,7 @@
 error_free_irq:
 	free_irq(st->us->irq, st->trig);
 error_free_trig:
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 error_ret:
 	return ret;
 }
@@ -105,5 +105,5 @@
 
 	iio_trigger_unregister(st->trig);
 	free_irq(st->us->irq, st->trig);
-	iio_free_trigger(st->trig);
+	iio_trigger_free(st->trig);
 }
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index 0beab47..b3f7e0fa9 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -18,8 +18,8 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "meter.h"
 #include "ade7759.h"
 
@@ -28,7 +28,7 @@
 		u8 val)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7759_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -46,7 +46,7 @@
 		u16 value)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7759_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -63,7 +63,7 @@
 		u8 reg_address,
 		u8 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7759_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -82,7 +82,7 @@
 		u8 reg_address,
 		u16 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7759_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -104,7 +104,7 @@
 		u64 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7759_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -376,7 +376,7 @@
 		const char *buf,
 		size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7759_state *st = iio_priv(indio_dev);
 	unsigned long val;
 	int ret;
@@ -463,7 +463,7 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -491,7 +491,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -507,7 +507,7 @@
 	if (ret)
 		goto err_ret;
 
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 err_ret:
 	return ret;
diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c
index 1e1faa0..0609046 100644
--- a/drivers/staging/iio/meter/ade7854-i2c.c
+++ b/drivers/staging/iio/meter/ade7854-i2c.c
@@ -12,7 +12,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "ade7854.h"
 
 static int ade7854_i2c_write_reg_8(struct device *dev,
@@ -20,7 +20,7 @@
 		u8 value)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -39,7 +39,7 @@
 		u16 value)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -59,7 +59,7 @@
 		u32 value)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -80,7 +80,7 @@
 		u32 value)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&st->buf_lock);
@@ -101,7 +101,7 @@
 		u16 reg_address,
 		u8 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -127,7 +127,7 @@
 		u16 reg_address,
 		u16 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -153,7 +153,7 @@
 		u16 reg_address,
 		u32 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -179,7 +179,7 @@
 		u16 reg_address,
 		u32 *val)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	int ret;
 
@@ -208,7 +208,7 @@
 	struct ade7854_state *st;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 	st = iio_priv(indio_dev);
@@ -226,7 +226,7 @@
 
 	ret = ade7854_probe(indio_dev, &client->dev);
 	if (ret)
-		iio_free_device(indio_dev);
+		iio_device_free(indio_dev);
 
 	return ret;
 }
diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c
index 8112186..9fb2f8b 100644
--- a/drivers/staging/iio/meter/ade7854-spi.c
+++ b/drivers/staging/iio/meter/ade7854-spi.c
@@ -12,7 +12,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 
-#include "../iio.h"
+#include <linux/iio/iio.h>
 #include "ade7854.h"
 
 static int ade7854_spi_write_reg_8(struct device *dev,
@@ -21,7 +21,7 @@
 {
 	int ret;
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfer = {
 		.tx_buf = st->tx,
@@ -49,7 +49,7 @@
 {
 	int ret;
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfer = {
 		.tx_buf = st->tx,
@@ -78,7 +78,7 @@
 {
 	int ret;
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfer = {
 		.tx_buf = st->tx,
@@ -108,7 +108,7 @@
 {
 	int ret;
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	struct spi_transfer xfer = {
 		.tx_buf = st->tx,
@@ -138,7 +138,7 @@
 		u8 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -180,7 +180,7 @@
 		u16 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -221,7 +221,7 @@
 		u32 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -263,7 +263,7 @@
 		u32 *val)
 {
 	struct spi_message msg;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	int ret;
 	struct spi_transfer xfers[] = {
@@ -306,7 +306,7 @@
 	struct ade7854_state *st;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 	st = iio_priv(indio_dev);
@@ -325,7 +325,7 @@
 
 	ret = ade7854_probe(indio_dev, &spi->dev);
 	if (ret)
-		iio_free_device(indio_dev);
+		iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
index 49c01c5..c642da8 100644
--- a/drivers/staging/iio/meter/ade7854.c
+++ b/drivers/staging/iio/meter/ade7854.c
@@ -17,8 +17,8 @@
 #include <linux/list.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "meter.h"
 #include "ade7854.h"
 
@@ -28,7 +28,7 @@
 {
 	int ret;
 	u8 val = 0;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -45,7 +45,7 @@
 {
 	int ret;
 	u16 val = 0;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -62,7 +62,7 @@
 {
 	int ret;
 	u32 val;
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
@@ -80,7 +80,7 @@
 	int ret;
 	u32 val = 0;
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	ret = st->read_reg_32(dev, this_attr->address, &val);
@@ -96,7 +96,7 @@
 		size_t len)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	int ret;
@@ -117,7 +117,7 @@
 		size_t len)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	int ret;
@@ -138,7 +138,7 @@
 		size_t len)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	int ret;
@@ -159,7 +159,7 @@
 		size_t len)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	int ret;
@@ -176,7 +176,7 @@
 
 static int ade7854_reset(struct device *dev)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 	u16 val;
 
@@ -425,7 +425,7 @@
 
 static int ade7854_set_irq(struct device *dev, bool enable)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7854_state *st = iio_priv(indio_dev);
 
 	int ret;
@@ -581,7 +581,7 @@
 error_unreg_dev:
 	iio_device_unregister(indio_dev);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -590,7 +590,7 @@
 int ade7854_remove(struct iio_dev *indio_dev)
 {
 	iio_device_unregister(indio_dev);
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h
index 6a3db14..23e1b5f4 100644
--- a/drivers/staging/iio/meter/meter.h
+++ b/drivers/staging/iio/meter/meter.h
@@ -1,4 +1,4 @@
-#include "../sysfs.h"
+#include <linux/iio/sysfs.h>
 
 /* metering ic types of attribute */
 
diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c
index d8ce854..8b71eb0 100644
--- a/drivers/staging/iio/resolver/ad2s1200.c
+++ b/drivers/staging/iio/resolver/ad2s1200.c
@@ -19,8 +19,8 @@
 #include <linux/gpio.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 #define DRV_NAME "ad2s1200"
 
@@ -85,10 +85,12 @@
 		.type = IIO_ANGL,
 		.indexed = 1,
 		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 	}, {
 		.type = IIO_ANGL_VEL,
 		.indexed = 1,
 		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 	}
 };
 
@@ -110,7 +112,7 @@
 						DRV_NAME, pins[pn]);
 			goto error_ret;
 		}
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -140,7 +142,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	for (--pn; pn >= 0; pn--)
 		gpio_free(pins[pn]);
@@ -150,7 +152,7 @@
 static int __devexit ad2s1200_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
 
 	return 0;
 }
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index c439fcf..f313859 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -18,8 +18,8 @@
 #include <linux/gpio.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 #include "ad2s1210.h"
 
 #define DRV_NAME "ad2s1210"
@@ -200,7 +200,7 @@
 					const char *buf,
 					size_t len)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	int ret;
 
 	mutex_lock(&st->lock);
@@ -214,7 +214,7 @@
 				    struct device_attribute *attr,
 				    char *buf)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	return sprintf(buf, "%d\n", st->fclkin);
 }
 
@@ -223,7 +223,7 @@
 				     const char *buf,
 				     size_t len)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	unsigned long fclkin;
 	int ret;
 
@@ -252,7 +252,7 @@
 				    struct device_attribute *attr,
 				    char *buf)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	return sprintf(buf, "%d\n", st->fexcit);
 }
 
@@ -260,7 +260,7 @@
 				     struct device_attribute *attr,
 				     const char *buf, size_t len)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	unsigned long fexcit;
 	int ret;
 
@@ -287,7 +287,7 @@
 				     struct device_attribute *attr,
 				     char *buf)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	int ret;
 	mutex_lock(&st->lock);
 	ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL);
@@ -299,7 +299,7 @@
 			struct device_attribute *attr,
 			const char *buf, size_t len)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	unsigned long udata;
 	unsigned char data;
 	int ret;
@@ -345,7 +345,7 @@
 static ssize_t ad2s1210_show_resolution(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	return sprintf(buf, "%d\n", st->resolution);
 }
 
@@ -353,7 +353,7 @@
 			struct device_attribute *attr,
 			const char *buf, size_t len)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	unsigned char data;
 	unsigned long udata;
 	int ret;
@@ -403,7 +403,7 @@
 static ssize_t ad2s1210_show_fault(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	int ret;
 
 	mutex_lock(&st->lock);
@@ -418,7 +418,7 @@
 				    const char *buf,
 				    size_t len)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	int ret;
 
 	mutex_lock(&st->lock);
@@ -441,7 +441,7 @@
 				 struct device_attribute *attr,
 				 char *buf)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
 	int ret;
 
@@ -455,7 +455,7 @@
 static ssize_t ad2s1210_store_reg(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t len)
 {
-	struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
 	unsigned long data;
 	int ret;
 	struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
@@ -580,10 +580,12 @@
 		.type = IIO_ANGL,
 		.indexed = 1,
 		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 	}, {
 		.type = IIO_ANGL_VEL,
 		.indexed = 1,
 		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 	}
 };
 
@@ -688,7 +690,7 @@
 	if (spi->dev.platform_data == NULL)
 		return -EINVAL;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -729,7 +731,7 @@
 error_free_gpios:
 	ad2s1210_free_gpios(st);
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -740,7 +742,7 @@
 
 	iio_device_unregister(indio_dev);
 	ad2s1210_free_gpios(iio_priv(indio_dev));
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c
index 2a86f58..a805722 100644
--- a/drivers/staging/iio/resolver/ad2s90.c
+++ b/drivers/staging/iio/resolver/ad2s90.c
@@ -16,8 +16,8 @@
 #include <linux/sysfs.h>
 #include <linux/module.h>
 
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 struct ad2s90_state {
 	struct mutex lock;
@@ -55,6 +55,7 @@
 	.type = IIO_ANGL,
 	.indexed = 1,
 	.channel = 0,
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
 };
 
 static int __devinit ad2s90_probe(struct spi_device *spi)
@@ -63,7 +64,7 @@
 	struct ad2s90_state *st;
 	int ret = 0;
 
-	indio_dev = iio_allocate_device(sizeof(*st));
+	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -92,7 +93,7 @@
 	return 0;
 
 error_free_dev:
-	iio_free_device(indio_dev);
+	iio_device_free(indio_dev);
 error_ret:
 	return ret;
 }
@@ -100,7 +101,7 @@
 static int __devexit ad2s90_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_free_device(spi_get_drvdata(spi));
+	iio_device_free(spi_get_drvdata(spi));
 
 	return 0;
 }
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index b9945ec..9358c6c 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -15,7 +15,7 @@
 #include <linux/sched.h>
 #include <linux/poll.h>
 #include "ring_sw.h"
-#include "trigger.h"
+#include <linux/iio/trigger.h>
 
 /**
  * struct iio_sw_ring_buffer - software ring buffer
diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h
index 7556e21..a5857aa 100644
--- a/drivers/staging/iio/ring_sw.h
+++ b/drivers/staging/iio/ring_sw.h
@@ -23,7 +23,7 @@
 
 #ifndef _IIO_RING_SW_H_
 #define _IIO_RING_SW_H_
-#include "buffer.h"
+#include <linux/iio/buffer.h>
 
 struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev);
 void iio_sw_rb_free(struct iio_buffer *ring);
diff --git a/drivers/staging/iio/trigger.h b/drivers/staging/iio/trigger.h
deleted file mode 100644
index 1cfca23..0000000
--- a/drivers/staging/iio/trigger.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* The industrial I/O core, trigger handling functions
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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/irq.h>
-#include <linux/module.h>
-
-#ifndef _IIO_TRIGGER_H_
-#define _IIO_TRIGGER_H_
-
-struct iio_subirq {
-	bool enabled;
-};
-
-/**
- * struct iio_trigger_ops - operations structure for an iio_trigger.
- * @owner:		used to monitor usage count of the trigger.
- * @set_trigger_state:	switch on/off the trigger on demand
- * @try_reenable:	function to reenable the trigger when the
- *			use count is zero (may be NULL)
- * @validate_device:	function to validate the device when the
- *			current trigger gets changed.
- *
- * This is typically static const within a driver and shared by
- * instances of a given device.
- **/
-struct iio_trigger_ops {
-	struct module			*owner;
-	int (*set_trigger_state)(struct iio_trigger *trig, bool state);
-	int (*try_reenable)(struct iio_trigger *trig);
-	int (*validate_device)(struct iio_trigger *trig,
-			       struct iio_dev *indio_dev);
-};
-
-
-/**
- * struct iio_trigger - industrial I/O trigger device
- *
- * @id:			[INTERN] unique id number
- * @name:		[DRIVER] unique name
- * @dev:		[DRIVER] associated device (if relevant)
- * @private_data:	[DRIVER] device specific data
- * @list:		[INTERN] used in maintenance of global trigger list
- * @alloc_list:		[DRIVER] used for driver specific trigger list
- * @use_count:		use count for the trigger
- * @subirq_chip:	[INTERN] associate 'virtual' irq chip.
- * @subirq_base:	[INTERN] base number for irqs provided by trigger.
- * @subirqs:		[INTERN] information about the 'child' irqs.
- * @pool:		[INTERN] bitmap of irqs currently in use.
- * @pool_lock:		[INTERN] protection of the irq pool.
- **/
-struct iio_trigger {
-	const struct iio_trigger_ops	*ops;
-	int				id;
-	const char			*name;
-	struct device			dev;
-
-	void				*private_data;
-	struct list_head		list;
-	struct list_head		alloc_list;
-	int use_count;
-
-	struct irq_chip			subirq_chip;
-	int				subirq_base;
-
-	struct iio_subirq subirqs[CONFIG_IIO_CONSUMERS_PER_TRIGGER];
-	unsigned long pool[BITS_TO_LONGS(CONFIG_IIO_CONSUMERS_PER_TRIGGER)];
-	struct mutex			pool_lock;
-};
-
-
-static inline struct iio_trigger *to_iio_trigger(struct device *d)
-{
-	return container_of(d, struct iio_trigger, dev);
-};
-
-static inline void iio_put_trigger(struct iio_trigger *trig)
-{
-	module_put(trig->ops->owner);
-	put_device(&trig->dev);
-};
-
-static inline void iio_get_trigger(struct iio_trigger *trig)
-{
-	get_device(&trig->dev);
-	__module_get(trig->ops->owner);
-};
-
-/**
- * iio_trigger_register() - register a trigger with the IIO core
- * @trig_info:	trigger to be registered
- **/
-int iio_trigger_register(struct iio_trigger *trig_info);
-
-/**
- * iio_trigger_unregister() - unregister a trigger from the core
- * @trig_info:	trigger to be unregistered
- **/
-void iio_trigger_unregister(struct iio_trigger *trig_info);
-
-/**
- * iio_trigger_poll() - called on a trigger occurring
- * @trig: trigger which occurred
- *
- * Typically called in relevant hardware interrupt handler.
- **/
-void iio_trigger_poll(struct iio_trigger *trig, s64 time);
-void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time);
-
-irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private);
-
-__printf(1, 2) struct iio_trigger *iio_allocate_trigger(const char *fmt, ...);
-void iio_free_trigger(struct iio_trigger *trig);
-
-#endif /* _IIO_TRIGGER_H_ */
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
index 665653d..f85734d 100644
--- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -15,8 +15,8 @@
 
 #include <asm/gptimers.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 
 struct bfin_timer {
 	unsigned short id, bit;
@@ -172,7 +172,7 @@
 	st->timer_num = ret;
 	st->t = &iio_bfin_timer_code[st->timer_num];
 
-	st->trig = iio_allocate_trigger("bfintmr%d", st->timer_num);
+	st->trig = iio_trigger_alloc("bfintmr%d", st->timer_num);
 	if (!st->trig) {
 		ret = -ENOMEM;
 		goto out1;
@@ -203,7 +203,7 @@
 out4:
 	iio_trigger_unregister(st->trig);
 out2:
-	iio_put_trigger(st->trig);
+	iio_trigger_put(st->trig);
 out1:
 	kfree(st);
 out:
@@ -217,7 +217,7 @@
 	disable_gptimers(st->t->bit);
 	free_irq(st->irq, st);
 	iio_trigger_unregister(st->trig);
-	iio_put_trigger(st->trig);
+	iio_trigger_put(st->trig);
 	kfree(st);
 
 	return 0;
diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c
index a346594..90b2684 100644
--- a/drivers/staging/iio/trigger/iio-trig-gpio.c
+++ b/drivers/staging/iio/trigger/iio-trig-gpio.c
@@ -22,8 +22,8 @@
 #include <linux/gpio.h>
 #include <linux/slab.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 
 static LIST_HEAD(iio_gpio_trigger_list);
 static DEFINE_MUTEX(iio_gpio_trigger_list_lock);
@@ -72,7 +72,7 @@
 
 		for (irq = irq_res->start; irq <= irq_res->end; irq++) {
 
-			trig = iio_allocate_trigger("irqtrig%d", irq);
+			trig = iio_trigger_alloc("irqtrig%d", irq);
 			if (!trig) {
 				ret = -ENOMEM;
 				goto error_free_completed_registrations;
@@ -114,7 +114,7 @@
 error_free_trig_info:
 	kfree(trig_info);
 error_put_trigger:
-	iio_put_trigger(trig);
+	iio_trigger_put(trig);
 error_free_completed_registrations:
 	/* The rest should have been added to the iio_gpio_trigger_list */
 	list_for_each_entry_safe(trig,
@@ -144,7 +144,7 @@
 		iio_trigger_unregister(trig);
 		free_irq(trig_info->irq, trig);
 		kfree(trig_info);
-		iio_put_trigger(trig);
+		iio_trigger_put(trig);
 	}
 	mutex_unlock(&iio_gpio_trigger_list_lock);
 
diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
index a80cf67..9f2d055 100644
--- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
+++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
@@ -16,8 +16,8 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/rtc.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 
 static LIST_HEAD(iio_prtc_trigger_list);
 static DEFINE_MUTEX(iio_prtc_trigger_list_lock);
@@ -112,7 +112,7 @@
 	for (i = 0;; i++) {
 		if (pdata[i] == NULL)
 			break;
-		trig = iio_allocate_trigger("periodic%s", pdata[i]);
+		trig = iio_trigger_alloc("periodic%s", pdata[i]);
 		if (!trig) {
 			ret = -ENOMEM;
 			goto error_free_completed_registrations;
@@ -152,7 +152,7 @@
 	kfree(trig_info);
 error_put_trigger_and_remove_from_list:
 	list_del(&trig->alloc_list);
-	iio_put_trigger(trig);
+	iio_trigger_put(trig);
 error_free_completed_registrations:
 	list_for_each_entry_safe(trig,
 				 trig2,
diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c
index 174dc65..552763b 100644
--- a/drivers/staging/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c
@@ -11,8 +11,8 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
 
 struct iio_sysfs_trig {
 	struct iio_trigger *trig;
@@ -139,7 +139,7 @@
 		goto out1;
 	}
 	t->id = id;
-	t->trig = iio_allocate_trigger("sysfstrig%d", id);
+	t->trig = iio_trigger_alloc("sysfstrig%d", id);
 	if (!t->trig) {
 		ret = -ENOMEM;
 		goto free_t;
@@ -158,7 +158,7 @@
 	return 0;
 
 out2:
-	iio_put_trigger(t->trig);
+	iio_trigger_put(t->trig);
 free_t:
 	kfree(t);
 out1:
@@ -182,7 +182,7 @@
 	}
 
 	iio_trigger_unregister(t->trig);
-	iio_free_trigger(t->trig);
+	iio_trigger_free(t->trig);
 
 	list_del(&t->l);
 	kfree(t);
diff --git a/drivers/staging/iio/types.h b/drivers/staging/iio/types.h
deleted file mode 100644
index 0c32136..0000000
--- a/drivers/staging/iio/types.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* industrial I/O data types needed both in and out of kernel
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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 _IIO_TYPES_H_
-#define _IIO_TYPES_H_
-
-enum iio_chan_type {
-	/* real channel types */
-	IIO_VOLTAGE,
-	IIO_CURRENT,
-	IIO_POWER,
-	IIO_ACCEL,
-	IIO_ANGL_VEL,
-	IIO_MAGN,
-	IIO_LIGHT,
-	IIO_INTENSITY,
-	IIO_PROXIMITY,
-	IIO_TEMP,
-	IIO_INCLI,
-	IIO_ROT,
-	IIO_ANGL,
-	IIO_TIMESTAMP,
-	IIO_CAPACITANCE,
-};
-
-enum iio_modifier {
-	IIO_NO_MOD,
-	IIO_MOD_X,
-	IIO_MOD_Y,
-	IIO_MOD_Z,
-	IIO_MOD_X_AND_Y,
-	IIO_MOD_X_AND_Z,
-	IIO_MOD_Y_AND_Z,
-	IIO_MOD_X_AND_Y_AND_Z,
-	IIO_MOD_X_OR_Y,
-	IIO_MOD_X_OR_Z,
-	IIO_MOD_Y_OR_Z,
-	IIO_MOD_X_OR_Y_OR_Z,
-	IIO_MOD_LIGHT_BOTH,
-	IIO_MOD_LIGHT_IR,
-};
-
-#define IIO_VAL_INT 1
-#define IIO_VAL_INT_PLUS_MICRO 2
-#define IIO_VAL_INT_PLUS_NANO 3
-
-#endif /* _IIO_TYPES_H_ */
diff --git a/drivers/staging/ipack/Kconfig b/drivers/staging/ipack/Kconfig
new file mode 100644
index 0000000..af32178
--- /dev/null
+++ b/drivers/staging/ipack/Kconfig
@@ -0,0 +1,20 @@
+#
+# IPACK configuration.
+#
+
+menuconfig IPACK_BUS
+	tristate "IndustryPack bus support"
+	---help---
+	  If you say Y here you get support for the IndustryPack Framework
+	  for drivers for many types of boards that support this industrial
+	  bus. The IndustryPack Framework is a virtual bus allowing to
+	  communicate between carrier and mezzanine cards connected through
+	  this bus.
+
+if IPACK_BUS
+
+source "drivers/staging/ipack/bridges/Kconfig"
+
+source "drivers/staging/ipack/devices/Kconfig"
+
+endif # IPACK
diff --git a/drivers/staging/ipack/Makefile b/drivers/staging/ipack/Makefile
new file mode 100644
index 0000000..85ff223
--- /dev/null
+++ b/drivers/staging/ipack/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the IPACK bridge device drivers.
+#
+obj-$(CONFIG_IPACK_BUS)		+= ipack.o
+obj-y				+= devices/
+obj-y				+= bridges/
diff --git a/drivers/staging/ipack/TODO b/drivers/staging/ipack/TODO
new file mode 100644
index 0000000..3a45a53
--- /dev/null
+++ b/drivers/staging/ipack/TODO
@@ -0,0 +1,46 @@
+				TODO
+				====
+Introduction
+============
+
+These drivers add support for IndustryPack devices: carrier and mezzanine
+boards.
+
+The ipack driver is just an abstraction of the bus providing the common
+operations between the two kind of boards.
+
+TODO
+====
+
+TPCI-200
+--------
+
+* It receives the name of the mezzanine plugged in each slot by SYSFS.
+  No autodetection supported yet, because the mezzanine driver could not be
+  loaded at the time that the tpci200 driver loads.
+
+* It has a linked list with the tpci200 devices it is managing. Get rid of it
+  and use driver_for_each_device() instead.
+
+IP-OCTAL
+--------
+
+* It has a linked list which saves the devices it is currently
+  managing. It should use the driver_for_each_device() function. It is not there
+  due to the impossibility of using container_of macro to recover the
+  corresponding "struct ipoctal" because the attribute "struct ipack_device" is
+  a pointer. This code should be refactored.
+
+Ipack
+-----
+
+* The structures and API exported can be improved a lot. For example, the
+  way to unregistering mezzanine devices, doing the mezzanine driver a call to
+  remove_device() to notify the carrier driver, or the opposite with the call to
+  the ipack_driver_ops' remove() function could be improved.
+
+
+Contact
+=======
+
+Contact: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
\ No newline at end of file
diff --git a/drivers/staging/ipack/bridges/Kconfig b/drivers/staging/ipack/bridges/Kconfig
new file mode 100644
index 0000000..97c837e
--- /dev/null
+++ b/drivers/staging/ipack/bridges/Kconfig
@@ -0,0 +1,8 @@
+config BOARD_TPCI200
+	tristate "TEWS TPCI-200 support for IndustryPack bus"
+	depends on IPACK_BUS
+	depends on PCI
+	help
+	  This driver supports the TEWS TPCI200 device for the IndustryPack bus.
+	default n
+
diff --git a/drivers/staging/ipack/bridges/Makefile b/drivers/staging/ipack/bridges/Makefile
new file mode 100644
index 0000000..d8b7645
--- /dev/null
+++ b/drivers/staging/ipack/bridges/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_BOARD_TPCI200) += tpci200.o
diff --git a/drivers/staging/ipack/bridges/tpci200.c b/drivers/staging/ipack/bridges/tpci200.c
new file mode 100644
index 0000000..ad28707
--- /dev/null
+++ b/drivers/staging/ipack/bridges/tpci200.c
@@ -0,0 +1,1141 @@
+/**
+ * tpci200.c
+ *
+ * driver for the TEWS TPCI-200 device
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include "tpci200.h"
+
+static struct ipack_bus_ops tpci200_bus_ops;
+
+/* TPCI200 controls registers */
+static int control_reg[] = {
+	TPCI200_CONTROL_A_REG,
+	TPCI200_CONTROL_B_REG,
+	TPCI200_CONTROL_C_REG,
+	TPCI200_CONTROL_D_REG
+};
+
+/* Linked list to save the registered devices */
+static LIST_HEAD(tpci200_list);
+
+static int tpci200_slot_unregister(struct ipack_device *dev);
+
+static struct tpci200_board *check_slot(struct ipack_device *dev)
+{
+	struct tpci200_board *tpci200;
+	int found = 0;
+
+	if (dev == NULL) {
+		pr_info("Slot doesn't exist.\n");
+		return NULL;
+	}
+
+	list_for_each_entry(tpci200, &tpci200_list, list) {
+		if (tpci200->number == dev->bus_nr) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		pr_err("Carrier not found\n");
+		return NULL;
+	}
+
+	if (dev->slot >= TPCI200_NB_SLOT) {
+		pr_info("Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n",
+			dev->bus_nr, dev->slot, TPCI200_NB_SLOT-1);
+		return NULL;
+	}
+
+	BUG_ON(tpci200->slots == NULL);
+	if (tpci200->slots[dev->slot].dev == NULL) {
+		pr_info("Slot [%d:%d] is not registered !\n", dev->bus_nr,
+			dev->slot);
+		return NULL;
+	}
+
+	return tpci200;
+}
+
+static inline unsigned char __tpci200_read8(void __iomem *address,
+					    unsigned long offset)
+{
+	return ioread8(address + (offset^1));
+}
+
+static inline unsigned short __tpci200_read16(void __iomem *address,
+					      unsigned long offset)
+{
+	return ioread16(address + offset);
+}
+
+static inline unsigned int __tpci200_read32(void __iomem *address,
+					    unsigned long offset)
+{
+	return swahw32(ioread32(address + offset));
+}
+
+static inline void __tpci200_write8(unsigned char value,
+				    void __iomem *address, unsigned long offset)
+{
+	iowrite8(value, address+(offset^1));
+}
+
+static inline void __tpci200_write16(unsigned short value,
+				     void __iomem *address,
+				     unsigned long offset)
+{
+	iowrite16(value, address+offset);
+}
+
+static inline void __tpci200_write32(unsigned int value,
+				     void __iomem *address,
+				     unsigned long offset)
+{
+	iowrite32(swahw32(value), address+offset);
+}
+
+static struct ipack_addr_space *get_slot_address_space(struct ipack_device *dev,
+						       int space)
+{
+	struct ipack_addr_space *addr;
+
+	switch (space) {
+	case IPACK_IO_SPACE:
+		addr = &dev->io_space;
+		break;
+	case IPACK_ID_SPACE:
+		addr = &dev->id_space;
+		break;
+	case IPACK_MEM_SPACE:
+		addr = &dev->mem_space;
+		break;
+	default:
+		pr_err("Slot [%d:%d] space number %d doesn't exist !\n",
+		       dev->bus_nr, dev->slot, space);
+		return NULL;
+		break;
+	}
+
+	if ((addr->size == 0) || (addr->address == NULL)) {
+		pr_err("Error, slot space not mapped !\n");
+		return NULL;
+	}
+
+	return addr;
+}
+
+static int tpci200_read8(struct ipack_device *dev, int space,
+			 unsigned long offset, unsigned char *value)
+{
+	struct ipack_addr_space *addr;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL)
+		return -EINVAL;
+
+	addr = get_slot_address_space(dev, space);
+	if (addr == NULL)
+		return -EINVAL;
+
+	if (offset >= addr->size) {
+		pr_err("Error, slot space offset error !\n");
+		return -EFAULT;
+	}
+
+	*value = __tpci200_read8(addr->address, offset);
+
+	return 0;
+}
+
+static int tpci200_read16(struct ipack_device *dev, int space,
+			  unsigned long offset, unsigned short *value)
+{
+	struct ipack_addr_space *addr;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL)
+		return -EINVAL;
+
+	addr = get_slot_address_space(dev, space);
+	if (addr == NULL)
+		return -EINVAL;
+
+	if ((offset+2) >= addr->size) {
+		pr_err("Error, slot space offset error !\n");
+		return -EFAULT;
+	}
+	*value = __tpci200_read16(addr->address, offset);
+
+	return 0;
+}
+
+static int tpci200_read32(struct ipack_device *dev, int space,
+			  unsigned long offset, unsigned int *value)
+{
+	struct ipack_addr_space *addr;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL)
+		return -EINVAL;
+
+	addr = get_slot_address_space(dev, space);
+	if (addr == NULL)
+		return -EINVAL;
+
+	if ((offset+4) >= addr->size) {
+		pr_err("Error, slot space offset error !\n");
+		return -EFAULT;
+	}
+
+	*value = __tpci200_read32(addr->address, offset);
+
+	return 0;
+}
+
+static int tpci200_write8(struct ipack_device *dev, int space,
+			  unsigned long offset, unsigned char value)
+{
+	struct ipack_addr_space *addr;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL)
+		return -EINVAL;
+
+	addr = get_slot_address_space(dev, space);
+	if (addr == NULL)
+		return -EINVAL;
+
+	if (offset >= addr->size) {
+		pr_err("Error, slot space offset error !\n");
+		return -EFAULT;
+	}
+
+	__tpci200_write8(value, addr->address, offset);
+
+	return 0;
+}
+
+static int tpci200_write16(struct ipack_device *dev, int space,
+			   unsigned long offset, unsigned short value)
+{
+	struct ipack_addr_space *addr;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL)
+		return -EINVAL;
+
+	addr = get_slot_address_space(dev, space);
+	if (addr == NULL)
+		return -EINVAL;
+
+	if ((offset+2) >= addr->size) {
+		pr_err("Error, slot space offset error !\n");
+		return -EFAULT;
+	}
+
+	__tpci200_write16(value, addr->address, offset);
+
+	return 0;
+}
+
+static int tpci200_write32(struct ipack_device *dev, int space,
+			   unsigned long offset, unsigned int value)
+{
+	struct ipack_addr_space *addr;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL)
+		return -EINVAL;
+
+	addr = get_slot_address_space(dev, space);
+	if (addr == NULL)
+		return -EINVAL;
+
+	if ((offset+4) >= addr->size) {
+		pr_err("Error, slot space offset error !\n");
+		return -EFAULT;
+	}
+
+	__tpci200_write32(value, addr->address, offset);
+
+	return 0;
+}
+
+static void tpci200_unregister(struct tpci200_board *tpci200)
+{
+	int i;
+
+	free_irq(tpci200->info->pdev->irq, (void *) tpci200);
+
+	pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
+	pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space);
+	pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space);
+
+	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
+	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
+	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
+
+	pci_disable_device(tpci200->info->pdev);
+	pci_dev_put(tpci200->info->pdev);
+
+	kfree(tpci200->info);
+
+	for (i = 0; i < TPCI200_NB_SLOT; i++) {
+		tpci200->slots[i].io_phys.address = NULL;
+		tpci200->slots[i].io_phys.size = 0;
+		tpci200->slots[i].id_phys.address = NULL;
+		tpci200->slots[i].id_phys.size = 0;
+		tpci200->slots[i].mem_phys.address = NULL;
+		tpci200->slots[i].mem_phys.size = 0;
+	}
+}
+
+static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
+{
+	struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id;
+	int i;
+	unsigned long flags;
+	unsigned short status_reg, reg_value;
+	unsigned short unhandled_ints = 0;
+	irqreturn_t ret = IRQ_NONE;
+
+	spin_lock_irqsave(&tpci200->info->access_lock, flags);
+
+	/* Read status register */
+	status_reg = readw(tpci200->info->interface_regs +
+			   TPCI200_STATUS_REG);
+
+	if (status_reg & TPCI200_SLOT_INT_MASK) {
+		unhandled_ints = status_reg & TPCI200_SLOT_INT_MASK;
+		/* callback to the IRQ handler for the corresponding slot */
+		for (i = 0; i < TPCI200_NB_SLOT; i++) {
+			if ((tpci200->slots[i].irq != NULL) &&
+			    (status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)))) {
+
+				ret = tpci200->slots[i].irq->handler(tpci200->slots[i].irq->arg);
+
+				/* Dummy reads */
+				readw(tpci200->slots[i].dev->io_space.address +
+				      0xC0);
+				readw(tpci200->slots[i].dev->io_space.address +
+				      0xC2);
+
+				unhandled_ints &= ~(((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)));
+			}
+		}
+	}
+	/* Interrupt not handled are disabled */
+	if (unhandled_ints) {
+		for (i = 0; i < TPCI200_NB_SLOT; i++) {
+			if (unhandled_ints & ((TPCI200_INT0_EN | TPCI200_INT1_EN) << (2*i))) {
+				pr_info("No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
+					tpci200->number, i);
+				reg_value = readw(
+					tpci200->info->interface_regs +
+					control_reg[i]);
+				reg_value &=
+					~(TPCI200_INT0_EN | TPCI200_INT1_EN);
+				writew(reg_value,
+				       (tpci200->info->interface_regs +
+					control_reg[i]));
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&tpci200->info->access_lock, flags);
+	return ret;
+}
+
+#ifdef CONFIG_SYSFS
+
+static struct ipack_device *tpci200_slot_register(unsigned int tpci200_number,
+						  unsigned int slot_position)
+{
+	int found = 0;
+	struct ipack_device  *dev;
+	struct tpci200_board *tpci200;
+
+	list_for_each_entry(tpci200, &tpci200_list, list) {
+		if (tpci200->number == tpci200_number) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		pr_err("carrier board not found for the device\n");
+		return NULL;
+	}
+
+	if (slot_position >= TPCI200_NB_SLOT) {
+		pr_info("Slot [%d:%d] doesn't exist!\n", tpci200_number,
+			slot_position);
+		return NULL;
+	}
+
+	if (mutex_lock_interruptible(&tpci200->mutex))
+		return NULL;
+
+	if (tpci200->slots[slot_position].dev != NULL) {
+		pr_err("Slot [%d:%d] already installed !\n", tpci200_number,
+		       slot_position);
+		goto err_unlock;
+	}
+
+	/*
+	 * Give the same IRQ number as the slot number.
+	 * The TPCI200 has assigned his own two IRQ by PCI bus driver
+	 */
+	dev = ipack_device_register(tpci200->info->ipack_bus,
+				    slot_position, slot_position);
+	if (dev == NULL) {
+		pr_info("Slot [%d:%d] Unable to register an ipack device\n",
+			tpci200_number, slot_position);
+		goto err_unlock;
+	}
+
+	tpci200->slots[slot_position].dev = dev;
+	mutex_unlock(&tpci200->mutex);
+	return dev;
+
+err_unlock:
+	mutex_unlock(&tpci200->mutex);
+	return NULL;
+}
+
+static ssize_t tpci200_store_board(struct device *pdev, const char *buf,
+				   size_t count, int slot)
+{
+	struct tpci200_board *card = dev_get_drvdata(pdev);
+	struct ipack_device *dev = card->slots[slot].dev;
+
+	if (dev != NULL)
+		return -EBUSY;
+
+	dev = tpci200_slot_register(card->number, slot);
+	if (dev == NULL)
+		return -ENODEV;
+
+	return count;
+}
+
+static ssize_t tpci200_show_board(struct device *pdev, char *buf, int slot)
+{
+	struct tpci200_board *card = dev_get_drvdata(pdev);
+	struct ipack_device *dev = card->slots[slot].dev;
+
+	if (dev != NULL)
+		return snprintf(buf, PAGE_SIZE, "%s\n", dev_name(&dev->dev));
+	else
+		return snprintf(buf, PAGE_SIZE, "none\n");
+}
+
+static ssize_t tpci200_show_description(struct device *pdev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return snprintf(buf, PAGE_SIZE,
+			"TEWS tpci200 carrier PCI for Industry-pack mezzanines.\n");
+}
+
+static ssize_t tpci200_show_board_slot0(struct device *pdev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return tpci200_show_board(pdev, buf, 0);
+}
+
+static ssize_t tpci200_store_board_slot0(struct device *pdev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	return tpci200_store_board(pdev, buf, count, 0);
+}
+
+static ssize_t tpci200_show_board_slot1(struct device *pdev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return tpci200_show_board(pdev, buf, 1);
+}
+
+static ssize_t tpci200_store_board_slot1(struct device *pdev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	return tpci200_store_board(pdev, buf, count, 1);
+}
+
+static ssize_t tpci200_show_board_slot2(struct device *pdev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return tpci200_show_board(pdev, buf, 2);
+}
+
+static ssize_t tpci200_store_board_slot2(struct device *pdev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	return tpci200_store_board(pdev, buf, count, 2);
+}
+
+
+static ssize_t tpci200_show_board_slot3(struct device *pdev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return tpci200_show_board(pdev, buf, 3);
+}
+
+static ssize_t tpci200_store_board_slot3(struct device *pdev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	return tpci200_store_board(pdev, buf, count, 3);
+}
+
+/* Declaration of the device attributes for the TPCI200 */
+static DEVICE_ATTR(description, S_IRUGO,
+		   tpci200_show_description, NULL);
+static DEVICE_ATTR(board_slot0, S_IRUGO | S_IWUSR,
+		   tpci200_show_board_slot0, tpci200_store_board_slot0);
+static DEVICE_ATTR(board_slot1, S_IRUGO | S_IWUSR,
+		   tpci200_show_board_slot1, tpci200_store_board_slot1);
+static DEVICE_ATTR(board_slot2, S_IRUGO | S_IWUSR,
+		   tpci200_show_board_slot2, tpci200_store_board_slot2);
+static DEVICE_ATTR(board_slot3, S_IRUGO | S_IWUSR,
+		   tpci200_show_board_slot3, tpci200_store_board_slot3);
+
+static struct attribute *tpci200_attrs[] = {
+	&dev_attr_description.attr,
+	&dev_attr_board_slot0.attr,
+	&dev_attr_board_slot1.attr,
+	&dev_attr_board_slot2.attr,
+	&dev_attr_board_slot3.attr,
+	NULL,
+};
+
+static struct attribute_group tpci200_attr_group = {
+	.attrs = tpci200_attrs,
+};
+
+static int tpci200_create_sysfs_files(struct tpci200_board *card)
+{
+	return sysfs_create_group(&card->info->pdev->dev.kobj,
+				  &tpci200_attr_group);
+}
+
+static void tpci200_remove_sysfs_files(struct tpci200_board *card)
+{
+	sysfs_remove_group(&card->info->pdev->dev.kobj, &tpci200_attr_group);
+}
+
+#else
+
+static int tpci200_create_sysfs_files(struct tpci200_board *card)
+{
+	return 0;
+}
+
+static void tpci200_remove_sysfs_files(struct tpci200_board *card)
+{
+}
+
+#endif /* CONFIG_SYSFS */
+
+static int tpci200_register(struct tpci200_board *tpci200)
+{
+	int  i;
+	int res;
+	unsigned long ioidint_base;
+	unsigned long mem_base;
+	unsigned short slot_ctrl;
+
+	if (pci_enable_device(tpci200->info->pdev) < 0)
+		return -ENODEV;
+
+	if (tpci200_create_sysfs_files(tpci200) < 0) {
+		pr_err("failed creating sysfs files\n");
+		res = -EFAULT;
+		goto out_disable_pci;
+	}
+
+	/* Request IP interface register (Bar 2) */
+	res = pci_request_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR,
+				 "Carrier IP interface registers");
+	if (res) {
+		pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !",
+		       tpci200->info->pdev->bus->number,
+		       tpci200->info->pdev->devfn);
+		goto out_remove_sysfs;
+	}
+
+	/* Request IO ID INT space (Bar 3) */
+	res = pci_request_region(tpci200->info->pdev,
+				 TPCI200_IO_ID_INT_SPACES_BAR,
+				 "Carrier IO ID INT space");
+	if (res) {
+		pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !",
+		       tpci200->info->pdev->bus->number,
+		       tpci200->info->pdev->devfn);
+		goto out_release_ip_space;
+	}
+
+	/* Request MEM space (Bar 4) */
+	res = pci_request_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR,
+				 "Carrier MEM space");
+	if (res) {
+		pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!",
+		       tpci200->info->pdev->bus->number,
+		       tpci200->info->pdev->devfn);
+		goto out_release_ioid_int_space;
+	}
+
+	/* Map internal tpci200 driver user space */
+	tpci200->info->interface_regs =
+		ioremap(pci_resource_start(tpci200->info->pdev,
+					   TPCI200_IP_INTERFACE_BAR),
+			TPCI200_IFACE_SIZE);
+	tpci200->info->ioidint_space =
+		ioremap(pci_resource_start(tpci200->info->pdev,
+					   TPCI200_IO_ID_INT_SPACES_BAR),
+			TPCI200_IOIDINT_SIZE);
+	tpci200->info->mem8_space =
+		ioremap(pci_resource_start(tpci200->info->pdev,
+					   TPCI200_MEM8_SPACE_BAR),
+			TPCI200_MEM8_SIZE);
+
+	spin_lock_init(&tpci200->info->access_lock);
+	ioidint_base = pci_resource_start(tpci200->info->pdev,
+					  TPCI200_IO_ID_INT_SPACES_BAR);
+	mem_base = pci_resource_start(tpci200->info->pdev,
+				      TPCI200_MEM8_SPACE_BAR);
+
+	/* Set the default parameters of the slot
+	 * INT0 disabled, level sensitive
+	 * INT1 disabled, level sensitive
+	 * error interrupt disabled
+	 * timeout interrupt disabled
+	 * recover time disabled
+	 * clock rate 8 MHz
+	 */
+	slot_ctrl = 0;
+
+	/* Set all slot physical address space */
+	for (i = 0; i < TPCI200_NB_SLOT; i++) {
+		tpci200->slots[i].io_phys.address =
+			(void __iomem *)ioidint_base +
+			TPCI200_IO_SPACE_OFF + TPCI200_IO_SPACE_GAP*i;
+		tpci200->slots[i].io_phys.size = TPCI200_IO_SPACE_SIZE;
+
+		tpci200->slots[i].id_phys.address =
+			(void __iomem *)ioidint_base +
+			TPCI200_ID_SPACE_OFF + TPCI200_ID_SPACE_GAP*i;
+		tpci200->slots[i].id_phys.size = TPCI200_ID_SPACE_SIZE;
+
+		tpci200->slots[i].mem_phys.address =
+			(void __iomem *)mem_base + TPCI200_MEM8_GAP*i;
+		tpci200->slots[i].mem_phys.size = TPCI200_MEM8_SIZE;
+
+		writew(slot_ctrl, (tpci200->info->interface_regs +
+				   control_reg[i]));
+	}
+
+	res = request_irq(tpci200->info->pdev->irq,
+			  tpci200_interrupt, IRQF_SHARED,
+			  KBUILD_MODNAME, (void *) tpci200);
+	if (res) {
+		pr_err("(bn 0x%X, sn 0x%X) unable to register IRQ !",
+		       tpci200->info->pdev->bus->number,
+		       tpci200->info->pdev->devfn);
+		tpci200_unregister(tpci200);
+		goto out_err;
+	}
+
+	return 0;
+
+out_release_ioid_int_space:
+	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
+out_release_ip_space:
+	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
+out_remove_sysfs:
+	tpci200_remove_sysfs_files(tpci200);
+out_disable_pci:
+	pci_disable_device(tpci200->info->pdev);
+out_err:
+	return res;
+}
+
+static int __tpci200_request_irq(struct tpci200_board *tpci200,
+				 struct ipack_device *dev)
+{
+	unsigned short slot_ctrl;
+
+	/* Set the default parameters of the slot
+	 * INT0 enabled, level sensitive
+	 * INT1 enabled, level sensitive
+	 * error interrupt disabled
+	 * timeout interrupt disabled
+	 * recover time disabled
+	 * clock rate 8 MHz
+	 */
+	slot_ctrl = TPCI200_INT0_EN | TPCI200_INT1_EN;
+	writew(slot_ctrl, (tpci200->info->interface_regs +
+			   control_reg[dev->slot]));
+
+	return 0;
+}
+
+static void __tpci200_free_irq(struct tpci200_board *tpci200,
+			       struct ipack_device *dev)
+{
+	unsigned short slot_ctrl;
+
+	/* Set the default parameters of the slot
+	 * INT0 disabled, level sensitive
+	 * INT1 disabled, level sensitive
+	 * error interrupt disabled
+	 * timeout interrupt disabled
+	 * recover time disabled
+	 * clock rate 8 MHz
+	 */
+	slot_ctrl = 0;
+	writew(slot_ctrl, (tpci200->info->interface_regs +
+			   control_reg[dev->slot]));
+}
+
+static int tpci200_free_irq(struct ipack_device *dev)
+{
+	int res;
+	struct slot_irq *slot_irq;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL) {
+		res = -EINVAL;
+		goto out;
+	}
+
+	if (mutex_lock_interruptible(&tpci200->mutex)) {
+		res = -ERESTARTSYS;
+		goto out;
+	}
+
+	if (tpci200->slots[dev->slot].irq == NULL) {
+		res = -EINVAL;
+		goto out_unlock;
+	}
+
+	__tpci200_free_irq(tpci200, dev);
+	slot_irq = tpci200->slots[dev->slot].irq;
+	tpci200->slots[dev->slot].irq = NULL;
+	kfree(slot_irq);
+
+out_unlock:
+	mutex_unlock(&tpci200->mutex);
+out:
+	return res;
+}
+
+static int tpci200_slot_unmap_space(struct ipack_device *dev, int space)
+{
+	int res;
+	struct ipack_addr_space *virt_addr_space;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL) {
+		res = -EINVAL;
+		goto out;
+	}
+
+	if (mutex_lock_interruptible(&tpci200->mutex)) {
+		res = -ERESTARTSYS;
+		goto out;
+	}
+
+	switch (space) {
+	case IPACK_IO_SPACE:
+		if (dev->io_space.address == NULL) {
+			pr_info("Slot [%d:%d] IO space not mapped !\n",
+				dev->bus_nr, dev->slot);
+			goto out_unlock;
+		}
+		virt_addr_space = &dev->io_space;
+		break;
+	case IPACK_ID_SPACE:
+		if (dev->id_space.address == NULL) {
+			pr_info("Slot [%d:%d] ID space not mapped !\n",
+				dev->bus_nr, dev->slot);
+			goto out_unlock;
+		}
+		virt_addr_space = &dev->id_space;
+		break;
+	case IPACK_MEM_SPACE:
+		if (dev->mem_space.address == NULL) {
+			pr_info("Slot [%d:%d] MEM space not mapped !\n",
+				dev->bus_nr, dev->slot);
+		goto out_unlock;
+		}
+		virt_addr_space = &dev->mem_space;
+		break;
+	default:
+		pr_err("Slot [%d:%d] space number %d doesn't exist !\n",
+		       dev->bus_nr, dev->slot, space);
+		res = -EINVAL;
+		goto out_unlock;
+		break;
+	}
+
+	iounmap(virt_addr_space->address);
+
+	virt_addr_space->address = NULL;
+	virt_addr_space->size = 0;
+out_unlock:
+	mutex_unlock(&tpci200->mutex);
+out:
+	return res;
+}
+
+static int tpci200_slot_unregister(struct ipack_device *dev)
+{
+	struct tpci200_board *tpci200;
+
+	if (dev == NULL)
+		return -ENODEV;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL)
+		return -EINVAL;
+
+	tpci200_free_irq(dev);
+
+	if (mutex_lock_interruptible(&tpci200->mutex))
+		return -ERESTARTSYS;
+
+	ipack_device_unregister(dev);
+	tpci200->slots[dev->slot].dev = NULL;
+	mutex_unlock(&tpci200->mutex);
+
+	return 0;
+}
+
+static int tpci200_slot_map_space(struct ipack_device *dev,
+				  unsigned int memory_size, int space)
+{
+	int res;
+	unsigned int size_to_map;
+	void __iomem *phys_address;
+	struct ipack_addr_space *virt_addr_space;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL) {
+		res = -EINVAL;
+		goto out;
+	}
+
+	if (mutex_lock_interruptible(&tpci200->mutex)) {
+		res = -ERESTARTSYS;
+		goto out;
+	}
+
+	switch (space) {
+	case IPACK_IO_SPACE:
+		if (dev->io_space.address != NULL) {
+			pr_err("Slot [%d:%d] IO space already mapped !\n",
+			       tpci200->number, dev->slot);
+			res = -EINVAL;
+			goto out_unlock;
+		}
+		virt_addr_space = &dev->io_space;
+
+		phys_address = tpci200->slots[dev->slot].io_phys.address;
+		size_to_map = tpci200->slots[dev->slot].io_phys.size;
+		break;
+	case IPACK_ID_SPACE:
+		if (dev->id_space.address != NULL) {
+			pr_err("Slot [%d:%d] ID space already mapped !\n",
+			       tpci200->number, dev->slot);
+			res = -EINVAL;
+			goto out_unlock;
+		}
+		virt_addr_space = &dev->id_space;
+
+		phys_address = tpci200->slots[dev->slot].id_phys.address;
+		size_to_map = tpci200->slots[dev->slot].id_phys.size;
+		break;
+	case IPACK_MEM_SPACE:
+		if (dev->mem_space.address != NULL) {
+			pr_err("Slot [%d:%d] MEM space already mapped !\n",
+			       tpci200->number, dev->slot);
+			res = -EINVAL;
+			goto out_unlock;
+		}
+		virt_addr_space = &dev->mem_space;
+
+		if (memory_size > tpci200->slots[dev->slot].mem_phys.size) {
+			pr_err("Slot [%d:%d] request is 0x%X memory, only 0x%X available !\n",
+			       dev->bus_nr, dev->slot, memory_size,
+			       tpci200->slots[dev->slot].mem_phys.size);
+			res = -EINVAL;
+			goto out_unlock;
+		}
+
+		phys_address = tpci200->slots[dev->slot].mem_phys.address;
+		size_to_map = memory_size;
+		break;
+	default:
+		pr_err("Slot [%d:%d] space %d doesn't exist !\n",
+		       tpci200->number, dev->slot, space);
+		res = -EINVAL;
+		goto out_unlock;
+		break;
+	}
+
+	virt_addr_space->size = size_to_map;
+	virt_addr_space->address =
+		ioremap((unsigned long)phys_address, size_to_map);
+
+out_unlock:
+	mutex_unlock(&tpci200->mutex);
+out:
+	return res;
+}
+
+static int tpci200_request_irq(struct ipack_device *dev, int vector,
+			       int (*handler)(void *), void *arg)
+{
+	int res;
+	struct slot_irq *slot_irq;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL) {
+		res = -EINVAL;
+		goto out;
+	}
+
+	if (mutex_lock_interruptible(&tpci200->mutex)) {
+		res = -ERESTARTSYS;
+		goto out;
+	}
+
+	if (tpci200->slots[dev->slot].irq != NULL) {
+		pr_err("Slot [%d:%d] IRQ already registered !\n", dev->bus_nr,
+		       dev->slot);
+		res = -EINVAL;
+		goto out_unlock;
+	}
+
+	slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL);
+	if (slot_irq == NULL) {
+		pr_err("Slot [%d:%d] unable to allocate memory for IRQ !\n",
+		       dev->bus_nr, dev->slot);
+		res = -ENOMEM;
+		goto out_unlock;
+	}
+
+	/*
+	 * WARNING: Setup Interrupt Vector in the IndustryPack device
+	 * before an IRQ request.
+	 * Read the User Manual of your IndustryPack device to know
+	 * where to write the vector in memory.
+	 */
+	slot_irq->vector = vector;
+	slot_irq->handler = handler;
+	slot_irq->arg = arg;
+	slot_irq->name = dev_name(&dev->dev);
+
+	tpci200->slots[dev->slot].irq = slot_irq;
+	res = __tpci200_request_irq(tpci200, dev);
+
+out_unlock:
+	mutex_unlock(&tpci200->mutex);
+out:
+	return res;
+}
+
+static void tpci200_slot_remove(struct tpci200_slot *slot)
+{
+	if ((slot->dev == NULL) ||
+	    (slot->dev->driver->ops->remove == NULL))
+		return;
+
+	slot->dev->driver->ops->remove(slot->dev);
+}
+
+static void tpci200_uninstall(struct tpci200_board *tpci200)
+{
+	int i;
+
+	for (i = 0; i < TPCI200_NB_SLOT; i++)
+		tpci200_slot_remove(&tpci200->slots[i]);
+
+	tpci200_unregister(tpci200);
+	kfree(tpci200->slots);
+}
+
+static struct ipack_bus_ops tpci200_bus_ops = {
+	.map_space = tpci200_slot_map_space,
+	.unmap_space = tpci200_slot_unmap_space,
+	.request_irq = tpci200_request_irq,
+	.free_irq = tpci200_free_irq,
+	.read8 = tpci200_read8,
+	.read16 = tpci200_read16,
+	.read32 = tpci200_read32,
+	.write8 = tpci200_write8,
+	.write16 = tpci200_write16,
+	.write32 = tpci200_write32,
+	.remove_device = tpci200_slot_unregister,
+};
+
+static int tpci200_install(struct tpci200_board *tpci200)
+{
+	int res;
+
+	tpci200->slots = kzalloc(
+		TPCI200_NB_SLOT * sizeof(struct tpci200_slot), GFP_KERNEL);
+	if (tpci200->slots == NULL) {
+		res = -ENOMEM;
+		goto out_err;
+	}
+
+	res = tpci200_register(tpci200);
+	if (res)
+		goto out_free;
+
+	mutex_init(&tpci200->mutex);
+	return 0;
+
+out_free:
+	kfree(tpci200->slots);
+	tpci200->slots = NULL;
+out_err:
+	return res;
+}
+
+static int tpci200_pciprobe(struct pci_dev *pdev,
+			    const struct pci_device_id *id)
+{
+	int ret;
+	struct tpci200_board *tpci200;
+
+	tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL);
+	if (!tpci200)
+		return -ENOMEM;
+
+	tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL);
+	if (!tpci200->info) {
+		kfree(tpci200);
+		return -ENOMEM;
+	}
+
+	/* Save struct pci_dev pointer */
+	tpci200->info->pdev = pdev;
+	tpci200->info->id_table = (struct pci_device_id *)id;
+
+	/* register the device and initialize it */
+	ret = tpci200_install(tpci200);
+	if (ret) {
+		pr_err("Error during tpci200 install !\n");
+		kfree(tpci200->info);
+		kfree(tpci200);
+		return -ENODEV;
+	}
+
+	/* Register the carrier in the industry pack bus driver */
+	tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev,
+						      TPCI200_NB_SLOT,
+						      &tpci200_bus_ops);
+	if (!tpci200->info->ipack_bus) {
+		pr_err("error registering the carrier on ipack driver\n");
+		tpci200_uninstall(tpci200);
+		kfree(tpci200->info);
+		kfree(tpci200);
+		return -EFAULT;
+	}
+
+	/* save the bus number given by ipack to logging purpose */
+	tpci200->number = tpci200->info->ipack_bus->bus_nr;
+	dev_set_drvdata(&pdev->dev, tpci200);
+	/* add the registered device in an internal linked list */
+	list_add_tail(&tpci200->list, &tpci200_list);
+	return ret;
+}
+
+static void __tpci200_pci_remove(struct tpci200_board *tpci200)
+{
+	tpci200_uninstall(tpci200);
+	tpci200_remove_sysfs_files(tpci200);
+	list_del(&tpci200->list);
+	ipack_bus_unregister(tpci200->info->ipack_bus);
+	kfree(tpci200->info);
+	kfree(tpci200);
+}
+
+static void __devexit tpci200_pci_remove(struct pci_dev *dev)
+{
+	struct tpci200_board *tpci200, *next;
+
+	/* Search the registered device to uninstall it */
+	list_for_each_entry_safe(tpci200, next, &tpci200_list, list) {
+		if (tpci200->info->pdev == dev) {
+			__tpci200_pci_remove(tpci200);
+			break;
+		}
+	}
+}
+
+static struct pci_device_id tpci200_idtable[2] = {
+	{ TPCI200_VENDOR_ID, TPCI200_DEVICE_ID, TPCI200_SUBVENDOR_ID,
+	  TPCI200_SUBDEVICE_ID },
+	{ 0, },
+};
+
+static struct pci_driver tpci200_pci_drv = {
+	.name = "tpci200",
+	.id_table = tpci200_idtable,
+	.probe = tpci200_pciprobe,
+	.remove = __devexit_p(tpci200_pci_remove),
+};
+
+static int __init tpci200_drvr_init_module(void)
+{
+	return pci_register_driver(&tpci200_pci_drv);
+}
+
+static void __exit tpci200_drvr_exit_module(void)
+{
+	struct tpci200_board *tpci200, *next;
+
+	list_for_each_entry_safe(tpci200, next, &tpci200_list, list)
+		__tpci200_pci_remove(tpci200);
+
+	pci_unregister_driver(&tpci200_pci_drv);
+}
+
+MODULE_DESCRIPTION("TEWS TPCI-200 device driver");
+MODULE_LICENSE("GPL");
+module_init(tpci200_drvr_init_module);
+module_exit(tpci200_drvr_exit_module);
diff --git a/drivers/staging/ipack/bridges/tpci200.h b/drivers/staging/ipack/bridges/tpci200.h
new file mode 100644
index 0000000..0b547ee
--- /dev/null
+++ b/drivers/staging/ipack/bridges/tpci200.h
@@ -0,0 +1,162 @@
+/**
+ * tpci200.h
+ *
+ * driver for the carrier TEWS TPCI-200
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#ifndef _TPCI200_H_
+#define _TPCI200_H_
+
+#include <linux/version.h>
+#include <linux/limits.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/swab.h>
+#include <linux/io.h>
+
+#include "../ipack.h"
+
+#define TPCI200_NB_SLOT               0x4
+#define TPCI200_NB_BAR                0x6
+
+#define TPCI200_VENDOR_ID             0x1498
+#define TPCI200_DEVICE_ID             0x30C8
+#define TPCI200_SUBVENDOR_ID          0x1498
+#define TPCI200_SUBDEVICE_ID          0x300A
+
+#define TPCI200_IP_INTERFACE_BAR      2
+#define TPCI200_IO_ID_INT_SPACES_BAR  3
+#define TPCI200_MEM16_SPACE_BAR       4
+#define TPCI200_MEM8_SPACE_BAR        5
+
+#define TPCI200_REVISION_REG          0x00
+#define TPCI200_CONTROL_A_REG         0x02
+#define TPCI200_CONTROL_B_REG         0x04
+#define TPCI200_CONTROL_C_REG         0x06
+#define TPCI200_CONTROL_D_REG         0x08
+#define TPCI200_RESET_REG             0x0A
+#define TPCI200_STATUS_REG            0x0C
+
+#define TPCI200_IFACE_SIZE            0x100
+
+#define TPCI200_IO_SPACE_OFF          0x0000
+#define TPCI200_IO_SPACE_GAP          0x0100
+#define TPCI200_IO_SPACE_SIZE         0x0080
+#define TPCI200_ID_SPACE_OFF          0x0080
+#define TPCI200_ID_SPACE_GAP          0x0100
+#define TPCI200_ID_SPACE_SIZE         0x0040
+#define TPCI200_INT_SPACE_OFF         0x00C0
+#define TPCI200_INT_SPACE_GAP         0x0100
+#define TPCI200_INT_SPACE_SIZE        0x0040
+#define TPCI200_IOIDINT_SIZE          0x0400
+
+#define TPCI200_MEM8_GAP              0x00400000
+#define TPCI200_MEM8_SIZE             0x00400000
+#define TPCI200_MEM16_GAP             0x00800000
+#define TPCI200_MEM16_SIZE            0x00800000
+
+#define TPCI200_INT0_EN               0x0040
+#define TPCI200_INT1_EN               0x0080
+#define TPCI200_INT0_EDGE             0x0010
+#define TPCI200_INT1_EDGE             0x0020
+#define TPCI200_ERR_INT_EN            0x0008
+#define TPCI200_TIME_INT_EN           0x0004
+#define TPCI200_RECOVER_EN            0x0002
+#define TPCI200_CLK32                 0x0001
+
+#define TPCI200_A_RESET               0x0001
+#define TPCI200_B_RESET               0x0002
+#define TPCI200_C_RESET               0x0004
+#define TPCI200_D_RESET               0x0008
+
+#define TPCI200_A_TIMEOUT             0x1000
+#define TPCI200_B_TIMEOUT             0x2000
+#define TPCI200_C_TIMEOUT             0x4000
+#define TPCI200_D_TIMEOUT             0x8000
+
+#define TPCI200_A_ERROR               0x0100
+#define TPCI200_B_ERROR               0x0200
+#define TPCI200_C_ERROR               0x0400
+#define TPCI200_D_ERROR               0x0800
+
+#define TPCI200_A_INT0                0x0001
+#define TPCI200_A_INT1                0x0002
+#define TPCI200_B_INT0                0x0004
+#define TPCI200_B_INT1                0x0008
+#define TPCI200_C_INT0                0x0010
+#define TPCI200_C_INT1                0x0020
+#define TPCI200_D_INT0                0x0040
+#define TPCI200_D_INT1                0x0080
+
+#define TPCI200_SLOT_INT_MASK         0x00FF
+
+#define VME_IOID_SPACE  "IOID"
+#define VME_MEM_SPACE  "MEM"
+
+/**
+ * struct slot_irq - slot IRQ definition.
+ * @vector	Vector number
+ * @handler	Handler called when IRQ arrives
+ * @arg		Handler argument
+ * @name	IRQ name
+ *
+ */
+struct slot_irq {
+	int		vector;
+	int		(*handler)(void *);
+	void		*arg;
+	const char	*name;
+};
+
+/**
+ * struct tpci200_slot - data specific to the tpci200 slot.
+ * @slot_id	Slot identification gived to external interface
+ * @irq		Slot IRQ infos
+ * @io_phys	IO physical base address register of the slot
+ * @id_phys	ID physical base address register of the slot
+ * @mem_phys	MEM physical base address register of the slot
+ *
+ */
+struct tpci200_slot {
+	struct ipack_device	*dev;
+	struct slot_irq		*irq;
+	struct ipack_addr_space io_phys;
+	struct ipack_addr_space id_phys;
+	struct ipack_addr_space mem_phys;
+};
+
+/**
+ * struct tpci200_infos - informations specific of the TPCI200 tpci200.
+ * @pci_dev		PCI device
+ * @interface_regs	Pointer to IP interface space (Bar 2)
+ * @ioidint_space	Pointer to IP ID, IO and INT space (Bar 3)
+ * @mem8_space		Pointer to MEM space (Bar 4)
+ * @access_lock		Mutex lock for simultaneous access
+ *
+ */
+struct tpci200_infos {
+	struct pci_dev			*pdev;
+	struct pci_device_id		*id_table;
+	void __iomem			*interface_regs;
+	void __iomem			*ioidint_space;
+	void __iomem			*mem8_space;
+	spinlock_t			access_lock;
+	struct ipack_bus_device		*ipack_bus;
+};
+struct tpci200_board {
+	struct list_head	list;
+	unsigned int		number;
+	struct mutex		mutex;
+	struct tpci200_slot	*slots;
+	struct tpci200_infos	*info;
+};
+
+#endif /* _TPCI200_H_ */
diff --git a/drivers/staging/ipack/devices/Kconfig b/drivers/staging/ipack/devices/Kconfig
new file mode 100644
index 0000000..39f7188
--- /dev/null
+++ b/drivers/staging/ipack/devices/Kconfig
@@ -0,0 +1,7 @@
+config SERIAL_IPOCTAL
+	tristate "IndustryPack IP-OCTAL uart support"
+	depends on IPACK_BUS
+	help
+	  This driver supports the IPOCTAL serial port device for the IndustryPack bus.
+	default n
+
diff --git a/drivers/staging/ipack/devices/Makefile b/drivers/staging/ipack/devices/Makefile
new file mode 100644
index 0000000..6de18bd
--- /dev/null
+++ b/drivers/staging/ipack/devices/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SERIAL_IPOCTAL) += ipoctal.o
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c
new file mode 100644
index 0000000..29f6fa8
--- /dev/null
+++ b/drivers/staging/ipack/devices/ipoctal.c
@@ -0,0 +1,901 @@
+/**
+ * ipoctal.c
+ *
+ * driver for the GE IP-OCTAL boards
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include "../ipack.h"
+#include "ipoctal.h"
+#include "scc2698.h"
+
+#define IP_OCTAL_MANUFACTURER_ID    0xF0
+#define IP_OCTAL_232_ID             0x22
+#define IP_OCTAL_422_ID             0x2A
+#define IP_OCTAL_485_ID             0x48
+
+#define IP_OCTAL_ID_SPACE_VECTOR    0x41
+#define IP_OCTAL_NB_BLOCKS          4
+
+static struct ipack_driver driver;
+static const struct tty_operations ipoctal_fops;
+
+struct ipoctal {
+	struct list_head		list;
+	struct ipack_device		*dev;
+	unsigned int			board_id;
+	struct scc2698_channel		*chan_regs;
+	struct scc2698_block		*block_regs;
+	struct ipoctal_stats		chan_stats[NR_CHANNELS];
+	char				*buffer[NR_CHANNELS];
+	unsigned int			nb_bytes[NR_CHANNELS];
+	unsigned int			count_wr[NR_CHANNELS];
+	struct ipoctal_config		chan_config[NR_CHANNELS];
+	wait_queue_head_t		queue[NR_CHANNELS];
+	unsigned short			error_flag[NR_CHANNELS];
+	spinlock_t			lock[NR_CHANNELS];
+	unsigned int			pointer_read[NR_CHANNELS];
+	unsigned int			pointer_write[NR_CHANNELS];
+	atomic_t			open[NR_CHANNELS];
+	unsigned char			write;
+	struct tty_port			tty_port[NR_CHANNELS];
+	struct tty_driver		*tty_drv;
+};
+
+/* Linked list to save the registered devices */
+static LIST_HEAD(ipoctal_list);
+
+static inline void ipoctal_write_io_reg(struct ipoctal *ipoctal,
+					unsigned char *dest,
+					unsigned char value)
+{
+	unsigned long offset;
+
+	offset = ((void __iomem *) dest) - ipoctal->dev->io_space.address;
+	ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_IO_SPACE, offset,
+				       value);
+}
+
+static inline void ipoctal_write_cr_cmd(struct ipoctal *ipoctal,
+					unsigned char *dest,
+					unsigned char value)
+{
+	ipoctal_write_io_reg(ipoctal, dest, value);
+}
+
+static inline unsigned char ipoctal_read_io_reg(struct ipoctal *ipoctal,
+						unsigned char *src)
+{
+	unsigned long offset;
+	unsigned char value;
+
+	offset = ((void __iomem *) src) - ipoctal->dev->io_space.address;
+	ipoctal->dev->bus->ops->read8(ipoctal->dev, IPACK_IO_SPACE, offset,
+				      &value);
+	return value;
+}
+
+static struct ipoctal *ipoctal_find_board(struct tty_struct *tty)
+{
+	struct ipoctal *p;
+
+	list_for_each_entry(p, &ipoctal_list, list) {
+		if (tty->driver->major == p->tty_drv->major)
+			return p;
+	}
+
+	return NULL;
+}
+
+static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+	struct ipoctal *ipoctal;
+	int channel = tty->index;
+
+	ipoctal = ipoctal_find_board(tty);
+
+	if (ipoctal == NULL) {
+		pr_err("Device not found. Major %d\n", tty->driver->major);
+		return -ENODEV;
+	}
+
+	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_ENABLE_RX);
+	tty->driver_data = ipoctal;
+
+	return 0;
+}
+
+static int ipoctal_open(struct tty_struct *tty, struct file *file)
+{
+	int channel = tty->index;
+	int res;
+	struct ipoctal *ipoctal;
+
+	ipoctal = ipoctal_find_board(tty);
+
+	if (ipoctal == NULL) {
+		pr_err("Device not found. Major %d\n", tty->driver->major);
+		return -ENODEV;
+	}
+
+	if (atomic_read(&ipoctal->open[channel]))
+		return -EBUSY;
+
+	res = tty_port_open(&ipoctal->tty_port[channel], tty, file);
+	if (res)
+		return res;
+
+	atomic_inc(&ipoctal->open[channel]);
+	return 0;
+}
+
+static void ipoctal_reset_stats(struct ipoctal_stats *stats)
+{
+	stats->tx = 0;
+	stats->rx = 0;
+	stats->rcv_break = 0;
+	stats->framing_err = 0;
+	stats->overrun_err = 0;
+	stats->parity_err = 0;
+}
+
+static void ipoctal_free_channel(struct tty_struct *tty)
+{
+	int channel = tty->index;
+	struct ipoctal *ipoctal = tty->driver_data;
+
+	if (ipoctal == NULL)
+		return;
+
+	ipoctal_reset_stats(&ipoctal->chan_stats[channel]);
+	ipoctal->pointer_read[channel] = 0;
+	ipoctal->pointer_write[channel] = 0;
+	ipoctal->nb_bytes[channel] = 0;
+}
+
+static void ipoctal_close(struct tty_struct *tty, struct file *filp)
+{
+	int channel = tty->index;
+	struct ipoctal *ipoctal = tty->driver_data;
+
+	tty_port_close(&ipoctal->tty_port[channel], tty, filp);
+
+	if (atomic_dec_and_test(&ipoctal->open[channel]))
+		ipoctal_free_channel(tty);
+}
+
+static int ipoctal_get_icount(struct tty_struct *tty,
+			      struct serial_icounter_struct *icount)
+{
+	struct ipoctal *ipoctal = tty->driver_data;
+	int channel = tty->index;
+
+	icount->cts = 0;
+	icount->dsr = 0;
+	icount->rng = 0;
+	icount->dcd = 0;
+	icount->rx = ipoctal->chan_stats[channel].rx;
+	icount->tx = ipoctal->chan_stats[channel].tx;
+	icount->frame = ipoctal->chan_stats[channel].framing_err;
+	icount->parity = ipoctal->chan_stats[channel].parity_err;
+	icount->brk = ipoctal->chan_stats[channel].rcv_break;
+	return 0;
+}
+
+static int ipoctal_irq_handler(void *arg)
+{
+	unsigned int channel;
+	unsigned int block;
+	unsigned char isr;
+	unsigned char sr;
+	unsigned char isr_tx_rdy, isr_rx_rdy;
+	unsigned char value;
+	unsigned char flag;
+	struct tty_struct *tty;
+	struct ipoctal *ipoctal = (struct ipoctal *) arg;
+
+	/* Check all channels */
+	for (channel = 0; channel < NR_CHANNELS; channel++) {
+		/* If there is no client, skip the check */
+		if (!atomic_read(&ipoctal->open[channel]))
+			continue;
+
+		tty = tty_port_tty_get(&ipoctal->tty_port[channel]);
+		if (!tty)
+			continue;
+
+		/*
+		 * The HW is organized in pair of channels.
+		 * See which register we need to read from
+		 */
+		block = channel / 2;
+		isr = ipoctal_read_io_reg(ipoctal,
+					  &ipoctal->block_regs[block].u.r.isr);
+		sr = ipoctal_read_io_reg(ipoctal,
+					 &ipoctal->chan_regs[channel].u.r.sr);
+
+		if ((channel % 2) == 1) {
+			isr_tx_rdy = isr & ISR_TxRDY_B;
+			isr_rx_rdy = isr & ISR_RxRDY_FFULL_B;
+		} else {
+			isr_tx_rdy = isr & ISR_TxRDY_A;
+			isr_rx_rdy = isr & ISR_RxRDY_FFULL_A;
+		}
+
+		/* In case of RS-485, change from TX to RX when finishing TX.
+		 * Half-duplex.
+		 */
+		if ((ipoctal->board_id == IP_OCTAL_485_ID) &&
+		    (sr & SR_TX_EMPTY) &&
+		    (ipoctal->nb_bytes[channel] == 0)) {
+			ipoctal_write_io_reg(ipoctal,
+					     &ipoctal->chan_regs[channel].u.w.cr,
+					     CR_DISABLE_TX);
+			ipoctal_write_cr_cmd(ipoctal,
+					     &ipoctal->chan_regs[channel].u.w.cr,
+					     CR_CMD_NEGATE_RTSN);
+			ipoctal_write_io_reg(ipoctal,
+					     &ipoctal->chan_regs[channel].u.w.cr,
+					     CR_ENABLE_RX);
+			ipoctal->write = 1;
+			wake_up_interruptible(&ipoctal->queue[channel]);
+		}
+
+		/* RX data */
+		if (isr_rx_rdy && (sr & SR_RX_READY)) {
+			value = ipoctal_read_io_reg(ipoctal,
+						    &ipoctal->chan_regs[channel].u.r.rhr);
+			flag = TTY_NORMAL;
+
+			/* Error: count statistics */
+			if (sr & SR_ERROR) {
+				ipoctal_write_cr_cmd(ipoctal,
+						     &ipoctal->chan_regs[channel].u.w.cr,
+						     CR_CMD_RESET_ERR_STATUS);
+
+				if (sr & SR_OVERRUN_ERROR) {
+					ipoctal->error_flag[channel] |= UART_OVERRUN;
+					ipoctal->chan_stats[channel].overrun_err++;
+					/* Overrun doesn't affect the current character*/
+					tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+				}
+				if (sr & SR_PARITY_ERROR) {
+					ipoctal->error_flag[channel] |= UART_PARITY;
+					ipoctal->chan_stats[channel].parity_err++;
+					flag = TTY_PARITY;
+				}
+				if (sr & SR_FRAMING_ERROR) {
+					ipoctal->error_flag[channel] |= UART_FRAMING;
+					ipoctal->chan_stats[channel].framing_err++;
+					flag = TTY_FRAME;
+				}
+				if (sr & SR_RECEIVED_BREAK) {
+					ipoctal->error_flag[channel] |= UART_BREAK;
+					ipoctal->chan_stats[channel].rcv_break++;
+					flag = TTY_BREAK;
+				}
+			}
+
+			tty_insert_flip_char(tty, value, flag);
+		}
+
+		/* TX of each character */
+		if (isr_tx_rdy && (sr & SR_TX_READY)) {
+			unsigned int *pointer_write =
+				&ipoctal->pointer_write[channel];
+
+			if (ipoctal->nb_bytes[channel] <= 0) {
+				ipoctal->nb_bytes[channel] = 0;
+				continue;
+			}
+			spin_lock(&ipoctal->lock[channel]);
+			value = ipoctal->buffer[channel][*pointer_write];
+			ipoctal_write_io_reg(ipoctal,
+					     &ipoctal->chan_regs[channel].u.w.thr,
+					     value);
+			ipoctal->chan_stats[channel].tx++;
+			ipoctal->count_wr[channel]++;
+			(*pointer_write)++;
+			*pointer_write = *pointer_write % PAGE_SIZE;
+			ipoctal->nb_bytes[channel]--;
+			spin_unlock(&ipoctal->lock[channel]);
+
+			if ((ipoctal->nb_bytes[channel] == 0) &&
+			    (waitqueue_active(&ipoctal->queue[channel]))) {
+
+				if (ipoctal->board_id != IP_OCTAL_485_ID) {
+					ipoctal->write = 1;
+					wake_up_interruptible(&ipoctal->queue[channel]);
+				}
+			}
+		}
+
+		tty_flip_buffer_push(tty);
+		tty_kref_put(tty);
+	}
+	return IRQ_HANDLED;
+}
+
+static int ipoctal_check_model(struct ipack_device *dev, unsigned char *id)
+{
+	unsigned char manufacturerID;
+	unsigned char board_id;
+
+	dev->bus->ops->read8(dev, IPACK_ID_SPACE,
+			IPACK_IDPROM_OFFSET_MANUFACTURER_ID, &manufacturerID);
+	if (manufacturerID != IP_OCTAL_MANUFACTURER_ID)
+		return -ENODEV;
+
+	dev->bus->ops->read8(dev, IPACK_ID_SPACE,
+			IPACK_IDPROM_OFFSET_MODEL, (unsigned char *)&board_id);
+
+	switch (board_id) {
+	case IP_OCTAL_232_ID:
+	case IP_OCTAL_422_ID:
+	case IP_OCTAL_485_ID:
+		*id = board_id;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static const struct tty_port_operations ipoctal_tty_port_ops = {
+	.dtr_rts = NULL,
+	.activate = ipoctal_port_activate,
+};
+
+static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
+			     unsigned int slot, unsigned int vector)
+{
+	int res = 0;
+	int i;
+	struct tty_driver *tty;
+	char name[20];
+	unsigned char board_id;
+
+	res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
+						IPACK_ID_SPACE);
+	if (res) {
+		pr_err("Unable to map slot [%d:%d] ID space!\n", bus_nr, slot);
+		return res;
+	}
+
+	res = ipoctal_check_model(ipoctal->dev, &board_id);
+	if (res) {
+		ipoctal->dev->bus->ops->unmap_space(ipoctal->dev,
+						    IPACK_ID_SPACE);
+		goto out_unregister_id_space;
+	}
+	ipoctal->board_id = board_id;
+
+	res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
+						IPACK_IO_SPACE);
+	if (res) {
+		pr_err("Unable to map slot [%d:%d] IO space!\n", bus_nr, slot);
+		goto out_unregister_id_space;
+	}
+
+	res = ipoctal->dev->bus->ops->map_space(ipoctal->dev,
+					   0x8000, IPACK_MEM_SPACE);
+	if (res) {
+		pr_err("Unable to map slot [%d:%d] MEM space!\n", bus_nr, slot);
+		goto out_unregister_io_space;
+	}
+
+	/* Save the virtual address to access the registers easily */
+	ipoctal->chan_regs =
+		(struct scc2698_channel *) ipoctal->dev->io_space.address;
+	ipoctal->block_regs =
+		(struct scc2698_block *) ipoctal->dev->io_space.address;
+
+	/* Disable RX and TX before touching anything */
+	for (i = 0; i < NR_CHANNELS ; i++) {
+		ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
+				     CR_DISABLE_RX | CR_DISABLE_TX);
+	}
+
+	for (i = 0; i < IP_OCTAL_NB_BLOCKS; i++) {
+		ipoctal_write_io_reg(ipoctal,
+				     &ipoctal->block_regs[i].u.w.acr,
+				     ACR_BRG_SET2);
+		ipoctal_write_io_reg(ipoctal,
+				     &ipoctal->block_regs[i].u.w.opcr,
+				     OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN |
+				     OPCR_MPOb_RTSN);
+		ipoctal_write_io_reg(ipoctal,
+				     &ipoctal->block_regs[i].u.w.imr,
+				     IMR_TxRDY_A | IMR_RxRDY_FFULL_A |
+				     IMR_DELTA_BREAK_A | IMR_TxRDY_B |
+				     IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B);
+	}
+
+	/*
+	 * IP-OCTAL has different addresses to copy its IRQ vector.
+	 * Depending of the carrier these addresses are accesible or not.
+	 * More info in the datasheet.
+	 */
+	ipoctal->dev->bus->ops->request_irq(ipoctal->dev, vector,
+				       ipoctal_irq_handler, ipoctal);
+	ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_ID_SPACE, 0, vector);
+
+	/* Register the TTY device */
+
+	/* Each IP-OCTAL channel is a TTY port */
+	tty = alloc_tty_driver(NR_CHANNELS);
+
+	if (!tty) {
+		res = -ENOMEM;
+		goto out_unregister_slot_unmap;
+	}
+
+	/* Fill struct tty_driver with ipoctal data */
+	tty->owner = THIS_MODULE;
+	tty->driver_name = "ipoctal";
+	sprintf(name, "ipoctal.%d.%d.", bus_nr, slot);
+	tty->name = name;
+	tty->major = 0;
+
+	tty->minor_start = 0;
+	tty->type = TTY_DRIVER_TYPE_SERIAL;
+	tty->subtype = SERIAL_TYPE_NORMAL;
+	tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty->init_termios = tty_std_termios;
+	tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	tty->init_termios.c_ispeed = 9600;
+	tty->init_termios.c_ospeed = 9600;
+
+	tty_set_operations(tty, &ipoctal_fops);
+	res = tty_register_driver(tty);
+	if (res) {
+		pr_err("Can't register tty driver.\n");
+		put_tty_driver(tty);
+		goto out_unregister_slot_unmap;
+	}
+
+	/* Save struct tty_driver for use it when uninstalling the device */
+	ipoctal->tty_drv = tty;
+
+	for (i = 0; i < NR_CHANNELS; i++) {
+		tty_port_init(&ipoctal->tty_port[i]);
+		tty_port_alloc_xmit_buf(&ipoctal->tty_port[i]);
+		ipoctal->tty_port[i].ops = &ipoctal_tty_port_ops;
+
+		ipoctal_reset_stats(&ipoctal->chan_stats[i]);
+		ipoctal->nb_bytes[i] = 0;
+		init_waitqueue_head(&ipoctal->queue[i]);
+		ipoctal->error_flag[i] = UART_NOERROR;
+
+		spin_lock_init(&ipoctal->lock[i]);
+		ipoctal->pointer_read[i] = 0;
+		ipoctal->pointer_write[i] = 0;
+		ipoctal->nb_bytes[i] = 0;
+		tty_register_device(tty, i, NULL);
+
+		/*
+		 * Enable again the RX. TX will be enabled when
+		 * there is something to send
+		 */
+		ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
+				     CR_ENABLE_RX);
+	}
+
+	return 0;
+
+out_unregister_slot_unmap:
+	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_ID_SPACE);
+out_unregister_io_space:
+	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_IO_SPACE);
+out_unregister_id_space:
+	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_MEM_SPACE);
+	return res;
+}
+
+static inline int ipoctal_copy_write_buffer(struct ipoctal *ipoctal,
+					    unsigned int channel,
+					    const unsigned char *buf,
+					    int count)
+{
+	unsigned long flags;
+	int i;
+	unsigned int *pointer_read = &ipoctal->pointer_read[channel];
+
+	/* Copy the bytes from the user buffer to the internal one */
+	for (i = 0; i < count; i++) {
+		if (i <= (PAGE_SIZE - ipoctal->nb_bytes[channel])) {
+			spin_lock_irqsave(&ipoctal->lock[channel], flags);
+			ipoctal->tty_port[channel].xmit_buf[*pointer_read] = buf[i];
+			*pointer_read = (*pointer_read + 1) % PAGE_SIZE;
+			ipoctal->nb_bytes[channel]++;
+			spin_unlock_irqrestore(&ipoctal->lock[channel], flags);
+		} else {
+			break;
+		}
+	}
+	return i;
+}
+
+static int ipoctal_write(struct ipoctal *ipoctal, unsigned int channel,
+			 const unsigned char *buf, int count)
+{
+	ipoctal->nb_bytes[channel] = 0;
+	ipoctal->count_wr[channel] = 0;
+
+	ipoctal_copy_write_buffer(ipoctal, channel, buf, count);
+
+	ipoctal->error_flag[channel] = UART_NOERROR;
+
+	/* As the IP-OCTAL 485 only supports half duplex, do it manually */
+	if (ipoctal->board_id == IP_OCTAL_485_ID) {
+		ipoctal_write_io_reg(ipoctal,
+				     &ipoctal->chan_regs[channel].u.w.cr,
+				     CR_DISABLE_RX);
+		ipoctal_write_cr_cmd(ipoctal,
+				     &ipoctal->chan_regs[channel].u.w.cr,
+				     CR_CMD_ASSERT_RTSN);
+	}
+
+	/*
+	 * Send a packet and then disable TX to avoid failure after several send
+	 * operations
+	 */
+	ipoctal_write_io_reg(ipoctal,
+			     &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_ENABLE_TX);
+	wait_event_interruptible(ipoctal->queue[channel], ipoctal->write);
+	ipoctal_write_io_reg(ipoctal,
+			     &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_DISABLE_TX);
+
+	ipoctal->write = 0;
+	return ipoctal->count_wr[channel];
+}
+
+static int ipoctal_write_tty(struct tty_struct *tty,
+			     const unsigned char *buf, int count)
+{
+	unsigned int channel = tty->index;
+	struct ipoctal *ipoctal = tty->driver_data;
+
+	return ipoctal_write(ipoctal, channel, buf, count);
+}
+
+static int ipoctal_write_room(struct tty_struct *tty)
+{
+	int channel = tty->index;
+	struct ipoctal *ipoctal = tty->driver_data;
+
+	return PAGE_SIZE - ipoctal->nb_bytes[channel];
+}
+
+static int ipoctal_chars_in_buffer(struct tty_struct *tty)
+{
+	int channel = tty->index;
+	struct ipoctal *ipoctal = tty->driver_data;
+
+	return ipoctal->nb_bytes[channel];
+}
+
+static void ipoctal_set_termios(struct tty_struct *tty,
+				struct ktermios *old_termios)
+{
+	unsigned int cflag;
+	unsigned char mr1 = 0;
+	unsigned char mr2 = 0;
+	unsigned char csr = 0;
+	unsigned int channel = tty->index;
+	struct ipoctal *ipoctal = tty->driver_data;
+	speed_t baud;
+
+	cflag = tty->termios->c_cflag;
+
+	/* Disable and reset everything before change the setup */
+	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_DISABLE_RX | CR_DISABLE_TX);
+	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_CMD_RESET_RX);
+	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_CMD_RESET_TX);
+	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_CMD_RESET_ERR_STATUS);
+	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_CMD_RESET_MR);
+
+	/* Set Bits per chars */
+	switch (cflag & CSIZE) {
+	case CS6:
+		mr1 |= MR1_CHRL_6_BITS;
+		break;
+	case CS7:
+		mr1 |= MR1_CHRL_7_BITS;
+		break;
+	case CS8:
+	default:
+		mr1 |= MR1_CHRL_8_BITS;
+		/* By default, select CS8 */
+		tty->termios->c_cflag = (cflag & ~CSIZE) | CS8;
+		break;
+	}
+
+	/* Set Parity */
+	if (cflag & PARENB)
+		if (cflag & PARODD)
+			mr1 |= MR1_PARITY_ON | MR1_PARITY_ODD;
+		else
+			mr1 |= MR1_PARITY_ON | MR1_PARITY_EVEN;
+	else
+		mr1 |= MR1_PARITY_OFF;
+
+	/* Mark or space parity is not supported */
+	tty->termios->c_cflag &= ~CMSPAR;
+
+	/* Set stop bits */
+	if (cflag & CSTOPB)
+		mr2 |= MR2_STOP_BITS_LENGTH_2;
+	else
+		mr2 |= MR2_STOP_BITS_LENGTH_1;
+
+	/* Set the flow control */
+	switch (ipoctal->board_id) {
+	case IP_OCTAL_232_ID:
+		if (cflag & CRTSCTS) {
+			mr1 |= MR1_RxRTS_CONTROL_ON;
+			mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_ON;
+			ipoctal->chan_config[channel].flow_control = 1;
+		} else {
+			mr1 |= MR1_RxRTS_CONTROL_OFF;
+			mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
+			ipoctal->chan_config[channel].flow_control = 0;
+		}
+		break;
+	case IP_OCTAL_422_ID:
+		mr1 |= MR1_RxRTS_CONTROL_OFF;
+		mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
+		ipoctal->chan_config[channel].flow_control = 0;
+		break;
+	case IP_OCTAL_485_ID:
+		mr1 |= MR1_RxRTS_CONTROL_OFF;
+		mr2 |= MR2_TxRTS_CONTROL_ON | MR2_CTS_ENABLE_TX_OFF;
+		ipoctal->chan_config[channel].flow_control = 0;
+		break;
+	default:
+		return;
+		break;
+	}
+
+	baud = tty_get_baud_rate(tty);
+	tty_termios_encode_baud_rate(tty->termios, baud, baud);
+
+	/* Set baud rate */
+	switch (tty->termios->c_ospeed) {
+	case 75:
+		csr |= TX_CLK_75 | RX_CLK_75;
+		break;
+	case 110:
+		csr |= TX_CLK_110 | RX_CLK_110;
+		break;
+	case 150:
+		csr |= TX_CLK_150 | RX_CLK_150;
+		break;
+	case 300:
+		csr |= TX_CLK_300 | RX_CLK_300;
+		break;
+	case 600:
+		csr |= TX_CLK_600 | RX_CLK_600;
+		break;
+	case 1200:
+		csr |= TX_CLK_1200 | RX_CLK_1200;
+		break;
+	case 1800:
+		csr |= TX_CLK_1800 | RX_CLK_1800;
+		break;
+	case 2000:
+		csr |= TX_CLK_2000 | RX_CLK_2000;
+		break;
+	case 2400:
+		csr |= TX_CLK_2400 | RX_CLK_2400;
+		break;
+	case 4800:
+		csr |= TX_CLK_4800  | RX_CLK_4800;
+		break;
+	case 9600:
+		csr |= TX_CLK_9600  | RX_CLK_9600;
+		break;
+	case 19200:
+		csr |= TX_CLK_19200 | RX_CLK_19200;
+		break;
+	case 38400:
+	default:
+		csr |= TX_CLK_38400 | RX_CLK_38400;
+		/* In case of default, we establish 38400 bps */
+		tty_termios_encode_baud_rate(tty->termios, 38400, 38400);
+		break;
+	}
+
+	mr1 |= MR1_ERROR_CHAR;
+	mr1 |= MR1_RxINT_RxRDY;
+
+	/* Write the control registers */
+	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr1);
+	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr2);
+	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.csr, csr);
+
+	/* save the setup in the structure */
+	ipoctal->chan_config[channel].baud = tty_get_baud_rate(tty);
+	ipoctal->chan_config[channel].bits_per_char = cflag & CSIZE;
+	ipoctal->chan_config[channel].parity = cflag & PARENB;
+	ipoctal->chan_config[channel].stop_bits = cflag & CSTOPB;
+
+	/* Enable again the RX */
+	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_ENABLE_RX);
+}
+
+static void ipoctal_hangup(struct tty_struct *tty)
+{
+	unsigned long flags;
+	int channel = tty->index;
+	struct ipoctal *ipoctal = tty->driver_data;
+
+	if (ipoctal == NULL)
+		return;
+
+	spin_lock_irqsave(&ipoctal->lock[channel], flags);
+	ipoctal->nb_bytes[channel] = 0;
+	ipoctal->pointer_read[channel] = 0;
+	ipoctal->pointer_write[channel] = 0;
+	spin_unlock_irqrestore(&ipoctal->lock[channel], flags);
+
+	tty_port_hangup(&ipoctal->tty_port[channel]);
+
+	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_DISABLE_RX | CR_DISABLE_TX);
+	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_CMD_RESET_RX);
+	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_CMD_RESET_TX);
+	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_CMD_RESET_ERR_STATUS);
+	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+			     CR_CMD_RESET_MR);
+
+	clear_bit(ASYNCB_INITIALIZED, &ipoctal->tty_port[channel].flags);
+	wake_up_interruptible(&ipoctal->tty_port[channel].open_wait);
+}
+
+static const struct tty_operations ipoctal_fops = {
+	.ioctl =		NULL,
+	.open =			ipoctal_open,
+	.close =		ipoctal_close,
+	.write =		ipoctal_write_tty,
+	.set_termios =		ipoctal_set_termios,
+	.write_room =		ipoctal_write_room,
+	.chars_in_buffer =	ipoctal_chars_in_buffer,
+	.get_icount =		ipoctal_get_icount,
+	.hangup =		ipoctal_hangup,
+};
+
+static int ipoctal_match(struct ipack_device *dev)
+{
+	int res;
+	unsigned char board_id;
+
+	if ((!dev->bus->ops) || (!dev->bus->ops->map_space) ||
+	    (!dev->bus->ops->unmap_space))
+		return 0;
+
+	res = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE);
+	if (res)
+		return 0;
+
+	res = ipoctal_check_model(dev, &board_id);
+	dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE);
+	if (!res)
+		return 1;
+
+	return 0;
+}
+
+static int ipoctal_probe(struct ipack_device *dev)
+{
+	int res;
+	struct ipoctal *ipoctal;
+
+	ipoctal = kzalloc(sizeof(struct ipoctal), GFP_KERNEL);
+	if (ipoctal == NULL)
+		return -ENOMEM;
+
+	ipoctal->dev = dev;
+	res = ipoctal_inst_slot(ipoctal, dev->bus_nr, dev->slot, dev->irq);
+	if (res)
+		goto out_uninst;
+
+	list_add_tail(&ipoctal->list, &ipoctal_list);
+	return 0;
+
+out_uninst:
+	kfree(ipoctal);
+	return res;
+}
+
+static void __ipoctal_remove(struct ipoctal *ipoctal)
+{
+	int i;
+
+	for (i = 0; i < NR_CHANNELS; i++) {
+		tty_unregister_device(ipoctal->tty_drv, i);
+		tty_port_free_xmit_buf(&ipoctal->tty_port[i]);
+	}
+
+	tty_unregister_driver(ipoctal->tty_drv);
+	put_tty_driver(ipoctal->tty_drv);
+
+	/* Tell the carrier board to free all the resources for this device */
+	if (ipoctal->dev->bus->ops->remove_device != NULL)
+		ipoctal->dev->bus->ops->remove_device(ipoctal->dev);
+
+	list_del(&ipoctal->list);
+	kfree(ipoctal);
+}
+
+static void ipoctal_remove(struct ipack_device *device)
+{
+	struct ipoctal *ipoctal, *next;
+
+	list_for_each_entry_safe(ipoctal, next, &ipoctal_list, list) {
+		if (ipoctal->dev == device)
+			__ipoctal_remove(ipoctal);
+	}
+}
+
+static struct ipack_driver_ops ipoctal_drv_ops = {
+	.match = ipoctal_match,
+	.probe = ipoctal_probe,
+	.remove = ipoctal_remove,
+};
+
+static int __init ipoctal_init(void)
+{
+	driver.ops = &ipoctal_drv_ops;
+	return ipack_driver_register(&driver, THIS_MODULE, KBUILD_MODNAME);
+}
+
+static void __exit ipoctal_exit(void)
+{
+	struct ipoctal *p, *next;
+
+	list_for_each_entry_safe(p, next, &ipoctal_list, list)
+		__ipoctal_remove(p);
+
+	ipack_driver_unregister(&driver);
+}
+
+MODULE_DESCRIPTION("IP-Octal 232, 422 and 485 device driver");
+MODULE_LICENSE("GPL");
+
+module_init(ipoctal_init);
+module_exit(ipoctal_exit);
diff --git a/drivers/staging/ipack/devices/ipoctal.h b/drivers/staging/ipack/devices/ipoctal.h
new file mode 100644
index 0000000..266f361
--- /dev/null
+++ b/drivers/staging/ipack/devices/ipoctal.h
@@ -0,0 +1,80 @@
+/**
+ * ipoctal.h
+ *
+ * driver for the IPOCTAL boards
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#ifndef _IPOCTAL_H
+#define _IPOCTAL_H_
+
+#define NR_CHANNELS		8
+#define IPOCTAL_MAX_BOARDS	16
+#define MAX_DEVICES		(NR_CHANNELS * IPOCTAL_MAX_BOARDS)
+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+/**
+ * enum uart_parity_e - UART supported parity.
+ */
+enum uart_parity_e {
+	UART_NONE  = 0,
+	UART_ODD   = 1,
+	UART_EVEN  = 2,
+};
+
+/**
+ * enum uart_error - UART error type
+ *
+ */
+enum uart_error	{
+	UART_NOERROR = 0,      /* No error during transmission */
+	UART_TIMEOUT = 1 << 0, /* Timeout error */
+	UART_OVERRUN = 1 << 1, /* Overrun error */
+	UART_PARITY  = 1 << 2, /* Parity error */
+	UART_FRAMING = 1 << 3, /* Framing error */
+	UART_BREAK   = 1 << 4, /* Received break */
+};
+
+/**
+ * struct ipoctal_config - Serial configuration
+ *
+ * @baud: Baud rate
+ * @stop_bits: Stop bits (1 or 2)
+ * @bits_per_char: data size in bits
+ * @parity
+ * @flow_control: Flow control management (RTS/CTS) (0 disabled, 1 enabled)
+ */
+struct ipoctal_config {
+	unsigned int baud;
+	unsigned int stop_bits;
+	unsigned int bits_per_char;
+	unsigned short parity;
+	unsigned int flow_control;
+};
+
+/**
+ * struct ipoctal_stats -- Stats since last reset
+ *
+ * @tx: Number of transmitted bytes
+ * @rx: Number of received bytes
+ * @overrun: Number of overrun errors
+ * @parity_err: Number of parity errors
+ * @framing_err: Number of framing errors
+ * @rcv_break: Number of break received
+ */
+struct ipoctal_stats {
+	unsigned long tx;
+	unsigned long rx;
+	unsigned long overrun_err;
+	unsigned long parity_err;
+	unsigned long framing_err;
+	unsigned long rcv_break;
+};
+
+#endif /* _IPOCTAL_H_ */
diff --git a/drivers/staging/ipack/devices/scc2698.h b/drivers/staging/ipack/devices/scc2698.h
new file mode 100644
index 0000000..47f6269
--- /dev/null
+++ b/drivers/staging/ipack/devices/scc2698.h
@@ -0,0 +1,228 @@
+/*
+ * scc2698.h
+ *
+ * driver for the IPOCTAL boards
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#ifndef SCC2698_H_
+#define SCC2698_H_
+
+/*
+ * struct scc2698_channel - Channel access to scc2698 IO
+ *
+ * dn value are only spacer.
+ *
+ */
+struct scc2698_channel {
+	union {
+		struct {
+			unsigned char d0, mr;  /* Mode register 1/2*/
+			unsigned char d1, sr;  /* Status register */
+			unsigned char d2, r1;  /* reserved */
+			unsigned char d3, rhr; /* Receive holding register (R) */
+			unsigned char junk[8]; /* other crap for block control */
+		} r; /* Read access */
+		struct {
+			unsigned char d0, mr;  /* Mode register 1/2 */
+			unsigned char d1, csr; /* Clock select register */
+			unsigned char d2, cr;  /* Command register */
+			unsigned char d3, thr; /* Transmit holding register */
+			unsigned char junk[8]; /* other crap for block control */
+		} w; /* Write access */
+	} u;
+};
+
+/*
+ * struct scc2698_block - Block access to scc2698 IO
+ *
+ * The scc2698 contain 4 block.
+ * Each block containt two channel a and b.
+ * dn value are only spacer.
+ *
+ */
+struct scc2698_block {
+	union {
+		struct {
+			unsigned char d0, mra;  /* Mode register 1/2 (a) */
+			unsigned char d1, sra;  /* Status register (a) */
+			unsigned char d2, r1;   /* reserved */
+			unsigned char d3, rhra; /* Receive holding register (a) */
+			unsigned char d4, ipcr; /* Input port change register of block */
+			unsigned char d5, isr;  /* Interrupt status register of block */
+			unsigned char d6, ctur; /* Counter timer upper register of block */
+			unsigned char d7, ctlr; /* Counter timer lower register of block */
+			unsigned char d8, mrb;  /* Mode register 1/2 (b) */
+			unsigned char d9, srb;  /* Status register (b) */
+			unsigned char da, r2;   /* reserved */
+			unsigned char db, rhrb; /* Receive holding register (b) */
+			unsigned char dc, r3;   /* reserved */
+			unsigned char dd, ip;   /* Input port register of block */
+			unsigned char de, ctg;  /* Start counter timer of block */
+			unsigned char df, cts;  /* Stop counter timer of block */
+		} r; /* Read access */
+		struct {
+			unsigned char d0, mra;  /* Mode register 1/2 (a) */
+			unsigned char d1, csra; /* Clock select register (a) */
+			unsigned char d2, cra;  /* Command register (a) */
+			unsigned char d3, thra; /* Transmit holding register (a) */
+			unsigned char d4, acr;  /* Auxiliary control register of block */
+			unsigned char d5, imr;  /* Interrupt mask register of block  */
+			unsigned char d6, ctu;  /* Counter timer upper register of block */
+			unsigned char d7, ctl;  /* Counter timer lower register of block */
+			unsigned char d8, mrb;  /* Mode register 1/2 (b) */
+			unsigned char d9, csrb; /* Clock select register (a) */
+			unsigned char da, crb;  /* Command register (b) */
+			unsigned char db, thrb; /* Transmit holding register (b) */
+			unsigned char dc, r1;   /* reserved */
+			unsigned char dd, opcr; /* Output port configuration register of block */
+			unsigned char de, r2;   /* reserved */
+			unsigned char df, r3;   /* reserved */
+		} w; /* Write access */
+	} u;
+} ;
+
+#define MR1_CHRL_5_BITS             (0x0 << 0)
+#define MR1_CHRL_6_BITS             (0x1 << 0)
+#define MR1_CHRL_7_BITS             (0x2 << 0)
+#define MR1_CHRL_8_BITS             (0x3 << 0)
+#define MR1_PARITY_EVEN             (0x1 << 2)
+#define MR1_PARITY_ODD              (0x0 << 2)
+#define MR1_PARITY_ON               (0x0 << 3)
+#define MR1_PARITY_FORCE            (0x1 << 3)
+#define MR1_PARITY_OFF              (0x2 << 3)
+#define MR1_PARITY_SPECIAL          (0x3 << 3)
+#define MR1_ERROR_CHAR              (0x0 << 5)
+#define MR1_ERROR_BLOCK             (0x1 << 5)
+#define MR1_RxINT_RxRDY             (0x0 << 6)
+#define MR1_RxINT_FFULL             (0x1 << 6)
+#define MR1_RxRTS_CONTROL_ON        (0x1 << 7)
+#define MR1_RxRTS_CONTROL_OFF       (0x0 << 7)
+
+#define MR2_STOP_BITS_LENGTH_1      (0x7 << 0)
+#define MR2_STOP_BITS_LENGTH_2      (0xF << 0)
+#define MR2_CTS_ENABLE_TX_ON        (0x1 << 4)
+#define MR2_CTS_ENABLE_TX_OFF       (0x0 << 4)
+#define MR2_TxRTS_CONTROL_ON        (0x1 << 5)
+#define MR2_TxRTS_CONTROL_OFF       (0x0 << 5)
+#define MR2_CH_MODE_NORMAL          (0x0 << 6)
+#define MR2_CH_MODE_ECHO            (0x1 << 6)
+#define MR2_CH_MODE_LOCAL           (0x2 << 6)
+#define MR2_CH_MODE_REMOTE          (0x3 << 6)
+
+#define CR_ENABLE_RX                (0x1 << 0)
+#define CR_DISABLE_RX               (0x1 << 1)
+#define CR_ENABLE_TX                (0x1 << 2)
+#define CR_DISABLE_TX               (0x1 << 3)
+#define CR_CMD_RESET_MR             (0x1 << 4)
+#define CR_CMD_RESET_RX             (0x2 << 4)
+#define CR_CMD_RESET_TX             (0x3 << 4)
+#define CR_CMD_RESET_ERR_STATUS     (0x4 << 4)
+#define CR_CMD_RESET_BREAK_CHANGE   (0x5 << 4)
+#define CR_CMD_START_BREAK          (0x6 << 4)
+#define CR_CMD_STOP_BREAK           (0x7 << 4)
+#define CR_CMD_ASSERT_RTSN          (0x8 << 4)
+#define CR_CMD_NEGATE_RTSN          (0x9 << 4)
+#define CR_CMD_SET_TIMEOUT_MODE     (0xA << 4)
+#define CR_CMD_DISABLE_TIMEOUT_MODE (0xC << 4)
+
+#define SR_RX_READY                 (0x1 << 0)
+#define SR_FIFO_FULL                (0x1 << 1)
+#define SR_TX_READY                 (0x1 << 2)
+#define SR_TX_EMPTY                 (0x1 << 3)
+#define SR_OVERRUN_ERROR            (0x1 << 4)
+#define SR_PARITY_ERROR             (0x1 << 5)
+#define SR_FRAMING_ERROR            (0x1 << 6)
+#define SR_RECEIVED_BREAK           (0x1 << 7)
+
+#define SR_ERROR                    (0xF0)
+
+#define ACR_DELTA_IP0_IRQ_EN        (0x1 << 0)
+#define ACR_DELTA_IP1_IRQ_EN        (0x1 << 1)
+#define ACR_DELTA_IP2_IRQ_EN        (0x1 << 2)
+#define ACR_DELTA_IP3_IRQ_EN        (0x1 << 3)
+#define ACR_CT_Mask                 (0x7 << 4)
+#define ACR_CExt                    (0x0 << 4)
+#define ACR_CTxCA                   (0x1 << 4)
+#define ACR_CTxCB                   (0x2 << 4)
+#define ACR_CClk16                  (0x3 << 4)
+#define ACR_TExt                    (0x4 << 4)
+#define ACR_TExt16                  (0x5 << 4)
+#define ACR_TClk                    (0x6 << 4)
+#define ACR_TClk16                  (0x7 << 4)
+#define ACR_BRG_SET1                (0x0 << 7)
+#define ACR_BRG_SET2                (0x1 << 7)
+
+#define TX_CLK_75                   (0x0 << 0)
+#define TX_CLK_110                  (0x1 << 0)
+#define TX_CLK_38400                (0x2 << 0)
+#define TX_CLK_150                  (0x3 << 0)
+#define TX_CLK_300                  (0x4 << 0)
+#define TX_CLK_600                  (0x5 << 0)
+#define TX_CLK_1200                 (0x6 << 0)
+#define TX_CLK_2000                 (0x7 << 0)
+#define TX_CLK_2400                 (0x8 << 0)
+#define TX_CLK_4800                 (0x9 << 0)
+#define TX_CLK_1800                 (0xA << 0)
+#define TX_CLK_9600                 (0xB << 0)
+#define TX_CLK_19200                (0xC << 0)
+#define RX_CLK_75                   (0x0 << 4)
+#define RX_CLK_110                  (0x1 << 4)
+#define RX_CLK_38400                (0x2 << 4)
+#define RX_CLK_150                  (0x3 << 4)
+#define RX_CLK_300                  (0x4 << 4)
+#define RX_CLK_600                  (0x5 << 4)
+#define RX_CLK_1200                 (0x6 << 4)
+#define RX_CLK_2000                 (0x7 << 4)
+#define RX_CLK_2400                 (0x8 << 4)
+#define RX_CLK_4800                 (0x9 << 4)
+#define RX_CLK_1800                 (0xA << 4)
+#define RX_CLK_9600                 (0xB << 4)
+#define RX_CLK_19200                (0xC << 4)
+
+#define OPCR_MPOa_RTSN              (0x0 << 0)
+#define OPCR_MPOa_C_TO              (0x1 << 0)
+#define OPCR_MPOa_TxC1X             (0x2 << 0)
+#define OPCR_MPOa_TxC16X            (0x3 << 0)
+#define OPCR_MPOa_RxC1X             (0x4 << 0)
+#define OPCR_MPOa_RxC16X            (0x5 << 0)
+#define OPCR_MPOa_TxRDY             (0x6 << 0)
+#define OPCR_MPOa_RxRDY_FF          (0x7 << 0)
+
+#define OPCR_MPOb_RTSN              (0x0 << 4)
+#define OPCR_MPOb_C_TO              (0x1 << 4)
+#define OPCR_MPOb_TxC1X             (0x2 << 4)
+#define OPCR_MPOb_TxC16X            (0x3 << 4)
+#define OPCR_MPOb_RxC1X             (0x4 << 4)
+#define OPCR_MPOb_RxC16X            (0x5 << 4)
+#define OPCR_MPOb_TxRDY             (0x6 << 4)
+#define OPCR_MPOb_RxRDY_FF          (0x7 << 4)
+
+#define OPCR_MPP_INPUT              (0x0 << 7)
+#define OPCR_MPP_OUTPUT             (0x1 << 7)
+
+#define IMR_TxRDY_A                 (0x1 << 0)
+#define IMR_RxRDY_FFULL_A           (0x1 << 1)
+#define IMR_DELTA_BREAK_A           (0x1 << 2)
+#define IMR_COUNTER_READY           (0x1 << 3)
+#define IMR_TxRDY_B                 (0x1 << 4)
+#define IMR_RxRDY_FFULL_B           (0x1 << 5)
+#define IMR_DELTA_BREAK_B           (0x1 << 6)
+#define IMR_INPUT_PORT_CHANGE       (0x1 << 7)
+
+#define ISR_TxRDY_A                 (0x1 << 0)
+#define ISR_RxRDY_FFULL_A           (0x1 << 1)
+#define ISR_DELTA_BREAK_A           (0x1 << 2)
+#define ISR_COUNTER_READY           (0x1 << 3)
+#define ISR_TxRDY_B                 (0x1 << 4)
+#define ISR_RxRDY_FFULL_B           (0x1 << 5)
+#define ISR_DELTA_BREAK_B           (0x1 << 6)
+#define ISR_INPUT_PORT_CHANGE       (0x1 << 7)
+
+#endif /* SCC2698_H_ */
diff --git a/drivers/staging/ipack/ipack.c b/drivers/staging/ipack/ipack.c
new file mode 100644
index 0000000..2b4fa51
--- /dev/null
+++ b/drivers/staging/ipack/ipack.c
@@ -0,0 +1,205 @@
+/*
+ * Industry-pack bus support functions.
+ *
+ * (C) 2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * (C) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include "ipack.h"
+
+#define to_ipack_dev(device) container_of(device, struct ipack_device, dev)
+#define to_ipack_driver(drv) container_of(drv, struct ipack_driver, driver)
+
+/* used when allocating bus numbers */
+#define IPACK_MAXBUS              64
+
+static DEFINE_MUTEX(ipack_mutex);
+
+struct ipack_busmap {
+	unsigned long busmap[IPACK_MAXBUS / (8*sizeof(unsigned long))];
+};
+static struct ipack_busmap busmap;
+
+static void ipack_device_release(struct device *dev)
+{
+	struct ipack_device *device = to_ipack_dev(dev);
+	kfree(device);
+}
+
+static int ipack_bus_match(struct device *device, struct device_driver *driver)
+{
+	int ret;
+	struct ipack_device *dev = to_ipack_dev(device);
+	struct ipack_driver *drv = to_ipack_driver(driver);
+
+	if ((!drv->ops) || (!drv->ops->match))
+		return -EINVAL;
+
+	ret = drv->ops->match(dev);
+	if (ret)
+		dev->driver = drv;
+
+	return 0;
+}
+
+static int ipack_bus_probe(struct device *device)
+{
+	struct ipack_device *dev = to_ipack_dev(device);
+
+	if (!dev->driver->ops->probe)
+		return -EINVAL;
+
+	return dev->driver->ops->probe(dev);
+}
+
+static int ipack_bus_remove(struct device *device)
+{
+	struct ipack_device *dev = to_ipack_dev(device);
+
+	if (!dev->driver->ops->remove)
+		return -EINVAL;
+
+	dev->driver->ops->remove(dev);
+	return 0;
+}
+
+static struct bus_type ipack_bus_type = {
+	.name  = "ipack",
+	.probe = ipack_bus_probe,
+	.match = ipack_bus_match,
+	.remove = ipack_bus_remove,
+};
+
+static int ipack_assign_bus_number(void)
+{
+	int busnum;
+
+	mutex_lock(&ipack_mutex);
+	busnum = find_next_zero_bit(busmap.busmap, IPACK_MAXBUS, 1);
+
+	if (busnum >= IPACK_MAXBUS) {
+		pr_err("too many buses\n");
+		busnum = -1;
+		goto error_find_busnum;
+	}
+
+	set_bit(busnum, busmap.busmap);
+
+error_find_busnum:
+	mutex_unlock(&ipack_mutex);
+	return busnum;
+}
+
+struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
+					    struct ipack_bus_ops *ops)
+{
+	int bus_nr;
+	struct ipack_bus_device *bus;
+
+	bus = kzalloc(sizeof(struct ipack_bus_device), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+
+	bus_nr = ipack_assign_bus_number();
+	if (bus_nr < 0) {
+		kfree(bus);
+		return NULL;
+	}
+
+	bus->bus_nr = bus_nr;
+	bus->parent = parent;
+	bus->slots = slots;
+	bus->ops = ops;
+	return bus;
+}
+EXPORT_SYMBOL_GPL(ipack_bus_register);
+
+int ipack_bus_unregister(struct ipack_bus_device *bus)
+{
+	mutex_lock(&ipack_mutex);
+	clear_bit(bus->bus_nr, busmap.busmap);
+	mutex_unlock(&ipack_mutex);
+	kfree(bus);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipack_bus_unregister);
+
+int ipack_driver_register(struct ipack_driver *edrv, struct module *owner,
+			  char *name)
+{
+	edrv->driver.owner = owner;
+	edrv->driver.name = name;
+	edrv->driver.bus = &ipack_bus_type;
+	return driver_register(&edrv->driver);
+}
+EXPORT_SYMBOL_GPL(ipack_driver_register);
+
+void ipack_driver_unregister(struct ipack_driver *edrv)
+{
+	driver_unregister(&edrv->driver);
+}
+EXPORT_SYMBOL_GPL(ipack_driver_unregister);
+
+struct ipack_device *ipack_device_register(struct ipack_bus_device *bus,
+					   int slot, int irqv)
+{
+	int ret;
+	struct ipack_device *dev;
+
+	dev = kzalloc(sizeof(struct ipack_device), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	dev->dev.bus = &ipack_bus_type;
+	dev->dev.release = ipack_device_release;
+	dev->dev.parent = bus->parent;
+	dev->slot = slot;
+	dev->bus_nr = bus->bus_nr;
+	dev->irq = irqv;
+	dev->bus = bus;
+	dev_set_name(&dev->dev,
+		     "ipack-dev.%u.%u", dev->bus_nr, dev->slot);
+
+	ret = device_register(&dev->dev);
+	if (ret < 0) {
+		pr_err("error registering the device.\n");
+		dev->driver->ops->remove(dev);
+		kfree(dev);
+		return NULL;
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(ipack_device_register);
+
+void ipack_device_unregister(struct ipack_device *dev)
+{
+	device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(ipack_device_unregister);
+
+static int __init ipack_init(void)
+{
+	return bus_register(&ipack_bus_type);
+}
+
+static void __exit ipack_exit(void)
+{
+	bus_unregister(&ipack_bus_type);
+}
+
+module_init(ipack_init);
+module_exit(ipack_exit);
+
+MODULE_AUTHOR("Samuel Iglesias Gonsalvez <siglesias@igalia.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Industry-pack bus core");
diff --git a/drivers/staging/ipack/ipack.h b/drivers/staging/ipack/ipack.h
new file mode 100644
index 0000000..8bc001e
--- /dev/null
+++ b/drivers/staging/ipack/ipack.h
@@ -0,0 +1,183 @@
+/*
+ * Industry-pack bus.
+ *
+ * (C) 2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * (C) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#include <linux/device.h>
+
+#define IPACK_IDPROM_OFFSET_I			0x01
+#define IPACK_IDPROM_OFFSET_P			0x03
+#define IPACK_IDPROM_OFFSET_A			0x05
+#define IPACK_IDPROM_OFFSET_C			0x07
+#define IPACK_IDPROM_OFFSET_MANUFACTURER_ID	0x09
+#define IPACK_IDPROM_OFFSET_MODEL		0x0B
+#define IPACK_IDPROM_OFFSET_REVISION		0x0D
+#define IPACK_IDPROM_OFFSET_RESERVED		0x0F
+#define IPACK_IDPROM_OFFSET_DRIVER_ID_L		0x11
+#define IPACK_IDPROM_OFFSET_DRIVER_ID_H		0x13
+#define IPACK_IDPROM_OFFSET_NUM_BYTES		0x15
+#define IPACK_IDPROM_OFFSET_CRC			0x17
+
+struct ipack_bus_ops;
+struct ipack_driver;
+
+enum ipack_space {
+	IPACK_IO_SPACE    = 0,
+	IPACK_ID_SPACE    = 1,
+	IPACK_MEM_SPACE   = 2,
+};
+
+/**
+ *	struct ipack_addr_space - Virtual address space mapped for a specified type.
+ *
+ *	@address: virtual address
+ *	@size: size of the mapped space
+ */
+struct ipack_addr_space {
+	void __iomem *address;
+	unsigned int size;
+};
+
+/**
+ *	struct ipack_device
+ *
+ *	@bus_nr: IP bus number where the device is plugged
+ *	@slot: Slot where the device is plugged in the carrier board
+ *	@irq: IRQ vector
+ *	@driver: Pointer to the ipack_driver that manages the device
+ *	@bus: ipack_bus_device where the device is plugged to.
+ *	@id_space: Virtual address to ID space.
+ *	@io_space: Virtual address to IO space.
+ *	@mem_space: Virtual address to MEM space.
+ *	@dev: device in kernel representation.
+ *
+ * Warning: Direct access to mapped memory is possible but the endianness
+ * is not the same with PCI carrier or VME carrier. The endianness is managed
+ * by the carrier board throught bus->ops.
+ */
+struct ipack_device {
+	unsigned int bus_nr;
+	unsigned int slot;
+	unsigned int irq;
+	struct ipack_driver *driver;
+	struct ipack_bus_device *bus;
+	struct ipack_addr_space id_space;
+	struct ipack_addr_space io_space;
+	struct ipack_addr_space mem_space;
+	struct device dev;
+};
+
+/**
+ *	struct ipack_driver_ops -- callbacks to mezzanine driver for installing/removing one device
+ *
+ *	@match: Match function
+ *	@probe: Probe function
+ *	@remove: tell the driver that the carrier board wants to remove one device
+ */
+
+struct ipack_driver_ops {
+	int (*match) (struct ipack_device *dev);
+	int (*probe) (struct ipack_device *dev);
+	void (*remove) (struct ipack_device *dev);
+};
+
+/**
+ *	struct ipack_driver -- Specific data to each ipack board driver
+ *
+ *	@driver: Device driver kernel representation
+ *	@ops: Mezzanine driver operations specific for the ipack bus.
+ */
+struct ipack_driver {
+	struct device_driver driver;
+	struct ipack_driver_ops *ops;
+};
+
+/**
+ *	struct ipack_bus_ops - available operations on a bridge module
+ *
+ *	@map_space: map IP address space
+ *	@unmap_space: unmap IP address space
+ *	@request_irq: request IRQ
+ *	@free_irq: free IRQ
+ *	@read8: read unsigned char
+ *	@read16: read unsigned short
+ *	@read32: read unsigned int
+ *	@write8: read unsigned char
+ *	@write16: read unsigned short
+ *	@write32: read unsigned int
+ *	@remove_device: tell the bridge module that the device has been removed
+ */
+struct ipack_bus_ops {
+	int (*map_space) (struct ipack_device *dev, unsigned int memory_size, int space);
+	int (*unmap_space) (struct ipack_device *dev, int space);
+	int (*request_irq) (struct ipack_device *dev, int vector, int (*handler)(void *), void *arg);
+	int (*free_irq) (struct ipack_device *dev);
+	int (*read8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char *value);
+	int (*read16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short *value);
+	int (*read32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int *value);
+	int (*write8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char value);
+	int (*write16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short value);
+	int (*write32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int value);
+	int (*remove_device) (struct ipack_device *dev);
+};
+
+/**
+ *	struct ipack_bus_device
+ *
+ *	@dev: pointer to carrier device
+ *	@slots: number of slots available
+ *	@bus_nr: ipack bus number
+ *	@ops: bus operations for the mezzanine drivers
+ */
+struct ipack_bus_device {
+	struct device *parent;
+	int slots;
+	int bus_nr;
+	struct ipack_bus_ops *ops;
+};
+
+/**
+ *	ipack_bus_register -- register a new ipack bus
+ *
+ * @parent: pointer to the parent device, if any.
+ * @slots: number of slots available in the bus device.
+ * @ops: bus operations for the mezzanine drivers.
+ *
+ * The carrier board device should call this function to register itself as
+ * available bus device in ipack.
+ */
+struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
+					    struct ipack_bus_ops *ops);
+
+/**
+ *	ipack_bus_unregister -- unregister an ipack bus
+ */
+int ipack_bus_unregister(struct ipack_bus_device *bus);
+
+/**
+ *	ipack_driver_register -- Register a new driver
+ *
+ * Called by a ipack driver to register itself as a driver
+ * that can manage ipack devices.
+ */
+int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, char *name);
+void ipack_driver_unregister(struct ipack_driver *edrv);
+
+/**
+ *	ipack_device_register -- register a new mezzanine device
+ *
+ * @bus: ipack bus device it is plugged to.
+ * @slot: slot position in the bus device.
+ * @irqv: IRQ vector for the mezzanine.
+ *
+ * Register a new ipack device (mezzanine device). The call is done by
+ * the carrier device driver.
+ */
+struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, int slot, int irqv);
+void ipack_device_unregister(struct ipack_device *dev);
diff --git a/drivers/staging/line6/config.h b/drivers/staging/line6/config.h
deleted file mode 100644
index f8a5149..0000000
--- a/drivers/staging/line6/config.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.8.0
- *
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- */
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-
-#ifdef CONFIG_USB_DEBUG
-#define DEBUG 1
-#endif
-
-
-/*
- * Development tools.
- */
-#define DO_DEBUG_MESSAGES    0
-#define DO_DUMP_URB_SEND     DO_DEBUG_MESSAGES
-#define DO_DUMP_URB_RECEIVE  DO_DEBUG_MESSAGES
-#define DO_DUMP_PCM_SEND     0
-#define DO_DUMP_PCM_RECEIVE  0
-#define DO_DUMP_MIDI_SEND    DO_DEBUG_MESSAGES
-#define DO_DUMP_MIDI_RECEIVE DO_DEBUG_MESSAGES
-#define DO_DUMP_ANY          (DO_DUMP_URB_SEND || DO_DUMP_URB_RECEIVE || \
-			      DO_DUMP_PCM_SEND || DO_DUMP_PCM_RECEIVE || \
-			      DO_DUMP_MIDI_SEND || DO_DUMP_MIDI_RECEIVE)
-#define CREATE_RAW_FILE      0
-
-#if DO_DEBUG_MESSAGES
-#define CHECKPOINT printk(KERN_INFO "line6usb: %s (%s:%d)\n", \
-			  __func__, __FILE__, __LINE__)
-#endif
-
-#if DO_DEBUG_MESSAGES
-#define DEBUG_MESSAGES(x) (x)
-#else
-#define DEBUG_MESSAGES(x)
-#endif
-
-
-#endif
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index e8023af..4513f78 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -92,15 +92,10 @@
 	Code to request version of POD, Variax interface
 	(and maybe other devices).
 */
-static const char line6_request_version0[] = {
+static const char line6_request_version[] = {
 	0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
 };
 
-/*
-	Copy of version request code with GFP_KERNEL flag for use in URB.
-*/
-static const char *line6_request_version;
-
 struct usb_line6 *line6_devices[LINE6_MAX_DEVICES];
 
 /**
@@ -336,8 +331,21 @@
 */
 int line6_version_request_async(struct usb_line6 *line6)
 {
-	return line6_send_raw_message_async(line6, line6_request_version,
-					    sizeof(line6_request_version0));
+	char *buffer;
+	int retval;
+
+	buffer = kmalloc(sizeof(line6_request_version), GFP_ATOMIC);
+	if (buffer == NULL) {
+		dev_err(line6->ifcdev, "Out of memory");
+		return -ENOMEM;
+	}
+
+	memcpy(buffer, line6_request_version, sizeof(line6_request_version));
+
+	retval = line6_send_raw_message_async(line6, buffer,
+					      sizeof(line6_request_version));
+	kfree(buffer);
+	return retval;
 }
 
 /*
@@ -1292,69 +1300,7 @@
 	.id_table = line6_id_table,
 };
 
-/*
-	Module initialization.
-*/
-static int __init line6_init(void)
-{
-	int i, retval;
-
-	printk(KERN_INFO "%s driver version %s\n", DRIVER_NAME, DRIVER_VERSION);
-
-	for (i = LINE6_MAX_DEVICES; i--;)
-		line6_devices[i] = NULL;
-
-	retval = usb_register(&line6_driver);
-
-	if (retval) {
-		err("usb_register failed. Error number %d", retval);
-		return retval;
-	}
-
-	line6_request_version = kmalloc(sizeof(line6_request_version0),
-					GFP_KERNEL);
-
-	if (line6_request_version == NULL) {
-		err("Out of memory");
-		return -ENOMEM;
-	}
-
-	memcpy((char *)line6_request_version, line6_request_version0,
-	       sizeof(line6_request_version0));
-
-	return retval;
-}
-
-/*
-	Module cleanup.
-*/
-static void __exit line6_exit(void)
-{
-	int i;
-	struct usb_line6 *line6;
-	struct snd_line6_pcm *line6pcm;
-
-	/* stop all PCM channels */
-	for (i = LINE6_MAX_DEVICES; i--;) {
-		line6 = line6_devices[i];
-
-		if (line6 == NULL)
-			continue;
-
-		line6pcm = line6->line6pcm;
-
-		if (line6pcm == NULL)
-			continue;
-
-		line6_pcm_release(line6pcm, ~0);
-	}
-
-	usb_deregister(&line6_driver);
-	kfree(line6_request_version);
-}
-
-module_init(line6_init);
-module_exit(line6_exit);
+module_usb_driver(line6_driver);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c
index 13d0293..5040729 100644
--- a/drivers/staging/line6/midi.c
+++ b/drivers/staging/line6/midi.c
@@ -406,7 +406,7 @@
 
 	line6midi->line6 = line6;
 
-	switch(line6->product) {
+	switch (line6->product) {
 	case LINE6_DEVID_PODHD300:
 	case LINE6_DEVID_PODHD500:
 		line6midi->midi_mask_transmit = 1;
diff --git a/drivers/staging/line6/midibuf.c b/drivers/staging/line6/midibuf.c
index 7b532e5..836e8c8 100644
--- a/drivers/staging/line6/midibuf.c
+++ b/drivers/staging/line6/midibuf.c
@@ -64,7 +64,7 @@
 
 void line6_midibuf_status(struct MidiBuffer *this)
 {
-	printk(KERN_DEBUG "midibuf size=%d split=%d pos_read=%d pos_write=%d "
+	pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d "
 	       "full=%d command_prev=%02x\n", this->size, this->split,
 	       this->pos_read, this->pos_write, this->full, this->command_prev);
 }
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index 90d2d44..5e319e3 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -99,7 +99,7 @@
 	unsigned long flags_new = flags_old | channels;
 	unsigned long flags_final = flags_old;
 	int err = 0;
-	
+
 	line6pcm->prev_fbuf = NULL;
 
 	if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c
index b754f69..31b624b 100644
--- a/drivers/staging/line6/toneport.c
+++ b/drivers/staging/line6/toneport.c
@@ -168,7 +168,7 @@
 			      cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
 
 	if (ret < 0) {
-		err("send failed (error %d)\n", ret);
+		dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
 		return ret;
 	}
 
diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c
index ea4f992..ac92eaf 100644
--- a/drivers/staging/media/as102/as102_drv.c
+++ b/drivers/staging/media/as102/as102_drv.c
@@ -279,40 +279,8 @@
 	pr_info("Unregistered device %s", as102_dev->name);
 }
 
-static int __init as102_driver_init(void)
-{
-	int ret;
+module_usb_driver(as102_usb_driver);
 
-	/* register this driver with the low level subsystem */
-	ret = usb_register(&as102_usb_driver);
-	if (ret)
-		err("usb_register failed (ret = %d)", ret);
-
-	return ret;
-}
-
-/*
- * Mandatory function : Adds a special section to the module indicating
- * where initialisation function is defined
- */
-module_init(as102_driver_init);
-
-/**
- * as102_driver_exit - as102 driver exit point
- *
- * This function is called when device has to be removed.
- */
-static void __exit as102_driver_exit(void)
-{
-	/* deregister this driver with the low level bus subsystem */
-	usb_deregister(&as102_usb_driver);
-}
-
-/*
- * required function for unload: Adds a special section to the module
- * indicating where unload function is defined
- */
-module_exit(as102_driver_exit);
 /* modinfo details */
 MODULE_DESCRIPTION(DRIVER_FULL_NAME);
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c
index 5917657..9ce8c9d 100644
--- a/drivers/staging/media/as102/as102_fe.c
+++ b/drivers/staging/media/as102/as102_fe.c
@@ -17,8 +17,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#include <linux/version.h>
-
 #include "as102_drv.h"
 #include "as10x_types.h"
 #include "as10x_cmd.h"
diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c
index 1075fb1..b9670ee 100644
--- a/drivers/staging/media/as102/as102_fw.c
+++ b/drivers/staging/media/as102/as102_fw.c
@@ -230,11 +230,8 @@
 	pr_info("%s: firmware: %s loaded with success\n",
 		DRIVER_NAME, fw2);
 error:
-	/* free data buffer */
 	kfree(cmd_buf);
-	/* release firmware if needed */
-	if (firmware != NULL)
-		release_firmware(firmware);
+	release_firmware(firmware);
 
 	LEAVE();
 	return errno;
diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c
index 0f6bfe7..aaf1bc2 100644
--- a/drivers/staging/media/as102/as102_usb_drv.c
+++ b/drivers/staging/media/as102/as102_usb_drv.c
@@ -367,7 +367,7 @@
 	ENTER();
 
 	/* This should never actually happen */
-	if ((sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)) !=
+	if (ARRAY_SIZE(as102_usb_id_table) !=
 	    (sizeof(as102_device_names) / sizeof(const char *))) {
 		pr_err("Device names table invalid size");
 		return -EINVAL;
@@ -375,13 +375,12 @@
 
 	as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
 	if (as102_dev == NULL) {
-		err("%s: kzalloc failed", __func__);
+		dev_err(&intf->dev, "%s: kzalloc failed\n", __func__);
 		return -ENOMEM;
 	}
 
 	/* Assign the user-friendly device name */
-	for (i = 0; i < (sizeof(as102_usb_id_table) /
-			 sizeof(struct usb_device_id)); i++) {
+	for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
 		if (id == &as102_usb_id_table[i]) {
 			as102_dev->name = as102_device_names[i];
 			as102_dev->elna_cfg = as102_elna_cfg[i];
@@ -411,8 +410,9 @@
 	ret = usb_register_dev(intf, &as102_usb_class_driver);
 	if (ret < 0) {
 		/* something prevented us from registering this driver */
-		err("%s: usb_register_dev() failed (errno = %d)",
-		    __func__, ret);
+		dev_err(&intf->dev,
+			"%s: usb_register_dev() failed (errno = %d)\n",
+			__func__, ret);
 		goto failed;
 	}
 
diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h
index fc2884a..1ad1ec5 100644
--- a/drivers/staging/media/as102/as102_usb_drv.h
+++ b/drivers/staging/media/as102/as102_usb_drv.h
@@ -17,8 +17,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#include <linux/version.h>
-
 #ifndef _AS102_USB_DRV_H_
 #define _AS102_USB_DRV_H_
 
diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c
index 262bb94..a73df10 100644
--- a/drivers/staging/media/as102/as10x_cmd.c
+++ b/drivers/staging/media/as102/as10x_cmd.c
@@ -31,7 +31,7 @@
  */
 int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
 {
-	int error;
+	int error = AS10X_CMD_ERROR;
 	struct as10x_cmd_t *pcmd, *prsp;
 
 	ENTER();
@@ -54,8 +54,6 @@
 					    (uint8_t *) prsp,
 					    sizeof(prsp->body.turn_on.rsp) +
 					    HEADER_SIZE);
-	} else {
-		error = AS10X_CMD_ERROR;
 	}
 
 	if (error < 0)
@@ -77,7 +75,7 @@
  */
 int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
 {
-	int error;
+	int error = AS10X_CMD_ERROR;
 	struct as10x_cmd_t *pcmd, *prsp;
 
 	ENTER();
@@ -99,8 +97,6 @@
 			sizeof(pcmd->body.turn_off.req) + HEADER_SIZE,
 			(uint8_t *) prsp,
 			sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE);
-	} else {
-		error = AS10X_CMD_ERROR;
 	}
 
 	if (error < 0)
@@ -124,7 +120,7 @@
 int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
 		       struct as10x_tune_args *ptune)
 {
-	int error;
+	int error = AS10X_CMD_ERROR;
 	struct as10x_cmd_t *preq, *prsp;
 
 	ENTER();
@@ -159,8 +155,6 @@
 					    (uint8_t *) prsp,
 					    sizeof(prsp->body.set_tune.rsp)
 					    + HEADER_SIZE);
-	} else {
-		error = AS10X_CMD_ERROR;
 	}
 
 	if (error < 0)
@@ -184,7 +178,7 @@
 int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
 			      struct as10x_tune_status *pstatus)
 {
-	int error;
+	int error = AS10X_CMD_ERROR;
 	struct as10x_cmd_t  *preq, *prsp;
 
 	ENTER();
@@ -208,8 +202,6 @@
 			sizeof(preq->body.get_tune_status.req) + HEADER_SIZE,
 			(uint8_t *) prsp,
 			sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE);
-	} else {
-		error = AS10X_CMD_ERROR;
 	}
 
 	if (error < 0)
@@ -241,7 +233,7 @@
  */
 int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
 {
-	int error;
+	int error = AS10X_CMD_ERROR;
 	struct as10x_cmd_t *pcmd, *prsp;
 
 	ENTER();
@@ -266,8 +258,6 @@
 					    (uint8_t *) prsp,
 					    sizeof(prsp->body.get_tps.rsp) +
 					    HEADER_SIZE);
-	} else {
-		error = AS10X_CMD_ERROR;
 	}
 
 	if (error < 0)
@@ -305,7 +295,7 @@
 int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
 			      struct as10x_demod_stats *pdemod_stats)
 {
-	int error;
+	int error = AS10X_CMD_ERROR;
 	struct as10x_cmd_t *pcmd, *prsp;
 
 	ENTER();
@@ -330,8 +320,6 @@
 				(uint8_t *) prsp,
 				sizeof(prsp->body.get_demod_stats.rsp)
 				+ HEADER_SIZE);
-	} else {
-		error = AS10X_CMD_ERROR;
 	}
 
 	if (error < 0)
@@ -370,7 +358,7 @@
 int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
 			       uint8_t *is_ready)
 {
-	int error;
+	int error = AS10X_CMD_ERROR;
 	struct as10x_cmd_t *pcmd, *prsp;
 
 	ENTER();
@@ -395,8 +383,6 @@
 					(uint8_t *) prsp,
 					sizeof(prsp->body.get_impulse_rsp.rsp)
 					+ HEADER_SIZE);
-	} else {
-		error = AS10X_CMD_ERROR;
 	}
 
 	if (error < 0)
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c
index 280c84e..c365cdf 100644
--- a/drivers/staging/media/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c
@@ -898,6 +898,10 @@
 	INIT_LIST_HEAD(&pd->dmaq);
 	mutex_init(&pd->mux);
 	pd->vdev->lock = &pd->mux; /* for locking v4l2_file_operations */
+	/* Locking in file operations other than ioctl should be done
+	   by the driver, not the V4L2 core.
+	   This driver needs auditing so that this flag can be removed. */
+	set_bit(V4L2_FL_LOCK_ALL_FOPS, &pd->vdev->flags);
 	spin_lock_init(&pd->lock);
 	pd->csr2 = csr2_init;
 	pd->config = config_init;
diff --git a/drivers/staging/media/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c
index 9413b37..3cee3cd 100644
--- a/drivers/staging/media/easycap/easycap_ioctl.c
+++ b/drivers/staging/media/easycap/easycap_ioctl.c
@@ -26,6 +26,7 @@
 /*****************************************************************************/
 
 #include "easycap.h"
+#include <linux/version.h>
 
 /*--------------------------------------------------------------------------*/
 /*
diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c
index d0fe34a..a1c45e4 100644
--- a/drivers/staging/media/easycap/easycap_main.c
+++ b/drivers/staging/media/easycap/easycap_main.c
@@ -700,214 +700,7 @@
 	JOM(4, "ending successfully\n");
 	return 0;
 }
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/*****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS
- *  PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect().
- *
- *  BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO
- *  peasycap->pusb_device IS NO LONGER VALID.
- */
-/*---------------------------------------------------------------------------*/
-static void easycap_delete(struct kref *pkref)
-{
-	struct easycap *peasycap;
-	struct data_urb *pdata_urb;
-	struct list_head *plist_head, *plist_next;
-	int k, m, gone, kd;
-	int allocation_video_urb;
-	int allocation_video_page;
-	int allocation_video_struct;
-	int allocation_audio_urb;
-	int allocation_audio_page;
-	int allocation_audio_struct;
-	int registered_video, registered_audio;
 
-	peasycap = container_of(pkref, struct easycap, kref);
-	if (!peasycap) {
-		SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
-		return;
-	}
-	kd = easycap_isdongle(peasycap);
-/*---------------------------------------------------------------------------*/
-/*
- *  FREE VIDEO.
- */
-/*---------------------------------------------------------------------------*/
-	if (peasycap->purb_video_head) {
-		m = 0;
-		list_for_each(plist_head, peasycap->purb_video_head) {
-			pdata_urb = list_entry(plist_head,
-						struct data_urb, list_head);
-			if (pdata_urb && pdata_urb->purb) {
-				usb_free_urb(pdata_urb->purb);
-				pdata_urb->purb = NULL;
-				peasycap->allocation_video_urb--;
-				m++;
-			}
-		}
-
-		JOM(4, "%i video urbs freed\n", m);
-/*---------------------------------------------------------------------------*/
-		JOM(4, "freeing video data_urb structures.\n");
-		m = 0;
-		list_for_each_safe(plist_head, plist_next,
-					peasycap->purb_video_head) {
-			pdata_urb = list_entry(plist_head,
-						struct data_urb, list_head);
-			if (pdata_urb) {
-				peasycap->allocation_video_struct -=
-						sizeof(struct data_urb);
-				kfree(pdata_urb);
-				m++;
-			}
-		}
-		JOM(4, "%i video data_urb structures freed\n", m);
-		JOM(4, "setting peasycap->purb_video_head=NULL\n");
-		peasycap->purb_video_head = NULL;
-	}
-/*---------------------------------------------------------------------------*/
-	JOM(4, "freeing video isoc buffers.\n");
-	m = 0;
-	for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY;  k++) {
-		if (peasycap->video_isoc_buffer[k].pgo) {
-			free_pages((unsigned long)
-				   peasycap->video_isoc_buffer[k].pgo,
-					VIDEO_ISOC_ORDER);
-			peasycap->video_isoc_buffer[k].pgo = NULL;
-			peasycap->allocation_video_page -=
-						BIT(VIDEO_ISOC_ORDER);
-			m++;
-		}
-	}
-	JOM(4, "isoc video buffers freed: %i pages\n",
-			m * (0x01 << VIDEO_ISOC_ORDER));
-/*---------------------------------------------------------------------------*/
-	JOM(4, "freeing video field buffers.\n");
-	gone = 0;
-	for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
-		for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
-			if (peasycap->field_buffer[k][m].pgo) {
-				free_page((unsigned long)
-					  peasycap->field_buffer[k][m].pgo);
-				peasycap->field_buffer[k][m].pgo = NULL;
-				peasycap->allocation_video_page -= 1;
-				gone++;
-			}
-		}
-	}
-	JOM(4, "video field buffers freed: %i pages\n", gone);
-/*---------------------------------------------------------------------------*/
-	JOM(4, "freeing video frame buffers.\n");
-	gone = 0;
-	for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
-		for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
-			if (peasycap->frame_buffer[k][m].pgo) {
-				free_page((unsigned long)
-					  peasycap->frame_buffer[k][m].pgo);
-				peasycap->frame_buffer[k][m].pgo = NULL;
-				peasycap->allocation_video_page -= 1;
-				gone++;
-			}
-		}
-	}
-	JOM(4, "video frame buffers freed: %i pages\n", gone);
-/*---------------------------------------------------------------------------*/
-/*
- *  FREE AUDIO.
- */
-/*---------------------------------------------------------------------------*/
-	if (peasycap->purb_audio_head) {
-		JOM(4, "freeing audio urbs\n");
-		m = 0;
-		list_for_each(plist_head, (peasycap->purb_audio_head)) {
-			pdata_urb = list_entry(plist_head,
-					struct data_urb, list_head);
-			if (pdata_urb && pdata_urb->purb) {
-				usb_free_urb(pdata_urb->purb);
-				pdata_urb->purb = NULL;
-				peasycap->allocation_audio_urb--;
-				m++;
-			}
-		}
-		JOM(4, "%i audio urbs freed\n", m);
-/*---------------------------------------------------------------------------*/
-		JOM(4, "freeing audio data_urb structures.\n");
-		m = 0;
-		list_for_each_safe(plist_head, plist_next,
-					peasycap->purb_audio_head) {
-			pdata_urb = list_entry(plist_head,
-					struct data_urb, list_head);
-			if (pdata_urb) {
-				peasycap->allocation_audio_struct -=
-							sizeof(struct data_urb);
-				kfree(pdata_urb);
-				m++;
-			}
-		}
-		JOM(4, "%i audio data_urb structures freed\n", m);
-		JOM(4, "setting peasycap->purb_audio_head=NULL\n");
-		peasycap->purb_audio_head = NULL;
-	}
-/*---------------------------------------------------------------------------*/
-	JOM(4, "freeing audio isoc buffers.\n");
-	m = 0;
-	for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
-		if (peasycap->audio_isoc_buffer[k].pgo) {
-			free_pages((unsigned long)
-					(peasycap->audio_isoc_buffer[k].pgo),
-					AUDIO_ISOC_ORDER);
-			peasycap->audio_isoc_buffer[k].pgo = NULL;
-			peasycap->allocation_audio_page -=
-					BIT(AUDIO_ISOC_ORDER);
-			m++;
-		}
-	}
-	JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
-					m * (0x01 << AUDIO_ISOC_ORDER));
-/*---------------------------------------------------------------------------*/
-	JOM(4, "freeing easycap structure.\n");
-	allocation_video_urb    = peasycap->allocation_video_urb;
-	allocation_video_page   = peasycap->allocation_video_page;
-	allocation_video_struct = peasycap->allocation_video_struct;
-	registered_video        = peasycap->registered_video;
-	allocation_audio_urb    = peasycap->allocation_audio_urb;
-	allocation_audio_page   = peasycap->allocation_audio_page;
-	allocation_audio_struct = peasycap->allocation_audio_struct;
-	registered_audio        = peasycap->registered_audio;
-
-	if (0 <= kd && DONGLE_MANY > kd) {
-		if (mutex_lock_interruptible(&mutex_dongle)) {
-			SAY("ERROR: cannot down mutex_dongle\n");
-		} else {
-			JOM(4, "locked mutex_dongle\n");
-			easycapdc60_dongle[kd].peasycap = NULL;
-			mutex_unlock(&mutex_dongle);
-			JOM(4, "unlocked mutex_dongle\n");
-			JOT(4, "   null-->dongle[%i].peasycap\n", kd);
-			allocation_video_struct -= sizeof(struct easycap);
-		}
-	} else {
-		SAY("ERROR: cannot purge dongle[].peasycap");
-	}
-
-	kfree(peasycap);
-
-/*---------------------------------------------------------------------------*/
-	SAY("%8i=video urbs    after all deletions\n", allocation_video_urb);
-	SAY("%8i=video pages   after all deletions\n", allocation_video_page);
-	SAY("%8i=video structs after all deletions\n", allocation_video_struct);
-	SAY("%8i=video devices after all deletions\n", registered_video);
-	SAY("%8i=audio urbs    after all deletions\n", allocation_audio_urb);
-	SAY("%8i=audio pages   after all deletions\n", allocation_audio_page);
-	SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
-	SAY("%8i=audio devices after all deletions\n", registered_audio);
-
-	JOT(4, "ending.\n");
-	return;
-}
 /*****************************************************************************/
 static unsigned int easycap_poll(struct file *file, poll_table *wait)
 {
@@ -2842,6 +2635,813 @@
 	return;
 }
 
+static struct easycap *alloc_easycap(u8 bInterfaceNumber)
+{
+	struct easycap *peasycap;
+	int i;
+
+	peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
+	if (!peasycap) {
+		SAY("ERROR: Could not allocate peasycap\n");
+		return NULL;
+	}
+
+	if (mutex_lock_interruptible(&mutex_dongle)) {
+		SAY("ERROR: cannot lock mutex_dongle\n");
+		kfree(peasycap);
+		return NULL;
+	}
+
+	/* Find a free dongle in easycapdc60_dongle array */
+	for (i = 0; i < DONGLE_MANY; i++) {
+
+		if ((!easycapdc60_dongle[i].peasycap) &&
+		    (!mutex_is_locked(&easycapdc60_dongle[i].mutex_video)) &&
+		    (!mutex_is_locked(&easycapdc60_dongle[i].mutex_audio))) {
+
+			easycapdc60_dongle[i].peasycap = peasycap;
+			peasycap->isdongle = i;
+			JOM(8, "intf[%i]: peasycap-->easycap"
+				"_dongle[%i].peasycap\n",
+				bInterfaceNumber, i);
+			break;
+		}
+	}
+
+	mutex_unlock(&mutex_dongle);
+
+	if (i >= DONGLE_MANY) {
+		SAM("ERROR: too many dongles\n");
+		kfree(peasycap);
+		return NULL;
+	}
+
+	return peasycap;
+}
+
+static void free_easycap(struct easycap *peasycap)
+{
+	int allocation_video_urb;
+	int allocation_video_page;
+	int allocation_video_struct;
+	int allocation_audio_urb;
+	int allocation_audio_page;
+	int allocation_audio_struct;
+	int registered_video, registered_audio;
+	int kd;
+
+	JOM(4, "freeing easycap structure.\n");
+	allocation_video_urb    = peasycap->allocation_video_urb;
+	allocation_video_page   = peasycap->allocation_video_page;
+	allocation_video_struct = peasycap->allocation_video_struct;
+	registered_video        = peasycap->registered_video;
+	allocation_audio_urb    = peasycap->allocation_audio_urb;
+	allocation_audio_page   = peasycap->allocation_audio_page;
+	allocation_audio_struct = peasycap->allocation_audio_struct;
+	registered_audio        = peasycap->registered_audio;
+
+	kd = easycap_isdongle(peasycap);
+	if (0 <= kd && DONGLE_MANY > kd) {
+		if (mutex_lock_interruptible(&mutex_dongle)) {
+			SAY("ERROR: cannot down mutex_dongle\n");
+		} else {
+			JOM(4, "locked mutex_dongle\n");
+			easycapdc60_dongle[kd].peasycap = NULL;
+			mutex_unlock(&mutex_dongle);
+			JOM(4, "unlocked mutex_dongle\n");
+			JOT(4, "   null-->dongle[%i].peasycap\n", kd);
+			allocation_video_struct -= sizeof(struct easycap);
+		}
+	} else {
+		SAY("ERROR: cannot purge dongle[].peasycap");
+	}
+
+	/* Free device structure */
+	kfree(peasycap);
+
+	SAY("%8i=video urbs    after all deletions\n", allocation_video_urb);
+	SAY("%8i=video pages   after all deletions\n", allocation_video_page);
+	SAY("%8i=video structs after all deletions\n", allocation_video_struct);
+	SAY("%8i=video devices after all deletions\n", registered_video);
+	SAY("%8i=audio urbs    after all deletions\n", allocation_audio_urb);
+	SAY("%8i=audio pages   after all deletions\n", allocation_audio_page);
+	SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
+	SAY("%8i=audio devices after all deletions\n", registered_audio);
+}
+
+/*
+ * FIXME: Identify the appropriate pointer peasycap for interfaces
+ * 1 and 2. The address of peasycap->pusb_device is reluctantly used
+ * for this purpose.
+ */
+static struct easycap *get_easycap(struct usb_device *usbdev,
+				   u8 bInterfaceNumber)
+{
+	int i;
+	struct easycap *peasycap;
+
+	for (i = 0; i < DONGLE_MANY; i++) {
+		if (easycapdc60_dongle[i].peasycap->pusb_device == usbdev) {
+			peasycap = easycapdc60_dongle[i].peasycap;
+			JOT(8, "intf[%i]: dongle[%i].peasycap\n",
+					bInterfaceNumber, i);
+			break;
+		}
+	}
+	if (i >= DONGLE_MANY) {
+		SAY("ERROR: peasycap is unknown when probing interface %i\n",
+			bInterfaceNumber);
+		return NULL;
+	}
+	if (!peasycap) {
+		SAY("ERROR: peasycap is NULL when probing interface %i\n",
+			bInterfaceNumber);
+		return NULL;
+	}
+
+	return peasycap;
+}
+
+static void init_easycap(struct easycap *peasycap,
+			 struct usb_device *usbdev,
+			 struct usb_interface *intf,
+			 u8 bInterfaceNumber)
+{
+	/* Save usb_device and usb_interface */
+	peasycap->pusb_device = usbdev;
+	peasycap->pusb_interface = intf;
+
+	peasycap->minor = -1;
+	kref_init(&peasycap->kref);
+	JOM(8, "intf[%i]: after kref_init(..._video) "
+		"%i=peasycap->kref.refcount.counter\n",
+		bInterfaceNumber, peasycap->kref.refcount.counter);
+
+	/* module params */
+	peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
+
+	init_waitqueue_head(&peasycap->wq_video);
+	init_waitqueue_head(&peasycap->wq_audio);
+	init_waitqueue_head(&peasycap->wq_trigger);
+
+	peasycap->allocation_video_struct = sizeof(struct easycap);
+
+	peasycap->microphone = false;
+
+	peasycap->video_interface = -1;
+	peasycap->video_altsetting_on = -1;
+	peasycap->video_altsetting_off = -1;
+	peasycap->video_endpointnumber = -1;
+	peasycap->video_isoc_maxframesize = -1;
+	peasycap->video_isoc_buffer_size = -1;
+
+	peasycap->audio_interface = -1;
+	peasycap->audio_altsetting_on = -1;
+	peasycap->audio_altsetting_off = -1;
+	peasycap->audio_endpointnumber = -1;
+	peasycap->audio_isoc_maxframesize = -1;
+	peasycap->audio_isoc_buffer_size = -1;
+
+	peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
+
+	peasycap->ntsc = easycap_ntsc;
+	JOM(8, "defaulting initially to %s\n",
+		easycap_ntsc ? "NTSC" : "PAL");
+}
+
+static int populate_inputset(struct easycap *peasycap)
+{
+	struct inputset *inputset;
+	struct easycap_format *peasycap_format;
+	struct v4l2_pix_format *pix;
+	int m, i, k, mask, fmtidx;
+	s32 value;
+
+	inputset = peasycap->inputset;
+
+	fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
+
+	m = 0;
+	mask = 0;
+	for (i = 0; easycap_standard[i].mask != 0xffff; i++) {
+		if (fmtidx == easycap_standard[i].v4l2_standard.index) {
+			m++;
+			for (k = 0; k < INPUT_MANY; k++)
+				inputset[k].standard_offset = i;
+			mask = easycap_standard[i].mask;
+		}
+	}
+
+	if (m != 1) {
+		SAM("ERROR: inputset->standard_offset unpopulated, %i=m\n", m);
+		return -ENOENT;
+	}
+
+	peasycap_format = &easycap_format[0];
+	m = 0;
+	for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
+		pix = &peasycap_format->v4l2_format.fmt.pix;
+		if (((peasycap_format->mask & 0x0F) == (mask & 0x0F))
+			&& pix->field == V4L2_FIELD_NONE
+			&& pix->pixelformat == V4L2_PIX_FMT_UYVY
+			&& pix->width  == 640 && pix->height == 480) {
+			m++;
+			for (k = 0; k < INPUT_MANY; k++)
+				inputset[k].format_offset = i;
+			break;
+		}
+		peasycap_format++;
+	}
+	if (m != 1) {
+		SAM("ERROR: inputset[]->format_offset unpopulated\n");
+		return -ENOENT;
+	}
+
+	m = 0;
+	for (i = 0; easycap_control[i].id != 0xffffffff; i++) {
+		value = easycap_control[i].default_value;
+		if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
+			m++;
+			for (k = 0; k < INPUT_MANY; k++)
+				inputset[k].brightness = value;
+		} else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
+			m++;
+			for (k = 0; k < INPUT_MANY; k++)
+				inputset[k].contrast = value;
+		} else if (V4L2_CID_SATURATION == easycap_control[i].id) {
+			m++;
+			for (k = 0; k < INPUT_MANY; k++)
+				inputset[k].saturation = value;
+		} else if (V4L2_CID_HUE == easycap_control[i].id) {
+			m++;
+			for (k = 0; k < INPUT_MANY; k++)
+				inputset[k].hue = value;
+		}
+	}
+
+	if (m != 4) {
+		SAM("ERROR: inputset[]->brightness underpopulated\n");
+		return -ENOENT;
+	}
+
+	for (k = 0; k < INPUT_MANY; k++)
+		inputset[k].input = k;
+	JOM(4, "populated inputset[]\n");
+
+	return 0;
+}
+
+static int alloc_framebuffers(struct easycap *peasycap)
+{
+	int i, j;
+	void *pbuf;
+
+	JOM(4, "allocating %i frame buffers of size %li\n",
+			FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
+	JOM(4, ".... each scattered over %li pages\n",
+			FRAME_BUFFER_SIZE/PAGE_SIZE);
+
+	for (i = 0; i < FRAME_BUFFER_MANY; i++) {
+		for (j = 0; j < FRAME_BUFFER_SIZE/PAGE_SIZE; j++) {
+			if (peasycap->frame_buffer[i][j].pgo)
+				SAM("attempting to reallocate framebuffers\n");
+			else {
+				pbuf = (void *)__get_free_page(GFP_KERNEL);
+				if (!pbuf) {
+					SAM("ERROR: Could not allocate "
+					"framebuffer %i page %i\n", i, j);
+					return -ENOMEM;
+				}
+				peasycap->allocation_video_page += 1;
+				peasycap->frame_buffer[i][j].pgo = pbuf;
+			}
+			peasycap->frame_buffer[i][j].pto =
+			    peasycap->frame_buffer[i][j].pgo;
+		}
+	}
+
+	peasycap->frame_fill = 0;
+	peasycap->frame_read = 0;
+	JOM(4, "allocation of frame buffers done: %i pages\n", i*j);
+
+	return 0;
+}
+
+static void free_framebuffers(struct easycap *peasycap)
+{
+	int k, m, gone;
+
+	JOM(4, "freeing video frame buffers.\n");
+	gone = 0;
+	for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
+		for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
+			if (peasycap->frame_buffer[k][m].pgo) {
+				free_page((unsigned long)
+					peasycap->frame_buffer[k][m].pgo);
+				peasycap->frame_buffer[k][m].pgo = NULL;
+				peasycap->allocation_video_page -= 1;
+				gone++;
+			}
+		}
+	}
+	JOM(4, "video frame buffers freed: %i pages\n", gone);
+}
+
+static int alloc_fieldbuffers(struct easycap *peasycap)
+{
+	int i, j;
+	void *pbuf;
+
+	JOM(4, "allocating %i field buffers of size %li\n",
+			FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
+	JOM(4, ".... each scattered over %li pages\n",
+			FIELD_BUFFER_SIZE/PAGE_SIZE);
+
+	for (i = 0; i < FIELD_BUFFER_MANY; i++) {
+		for (j = 0; j < FIELD_BUFFER_SIZE/PAGE_SIZE; j++) {
+			if (peasycap->field_buffer[i][j].pgo) {
+				SAM("ERROR: attempting to reallocate "
+					"fieldbuffers\n");
+			} else {
+				pbuf = (void *) __get_free_page(GFP_KERNEL);
+				if (!pbuf) {
+					SAM("ERROR: Could not allocate "
+					"fieldbuffer %i page %i\n", i, j);
+					return -ENOMEM;
+				}
+				peasycap->allocation_video_page += 1;
+				peasycap->field_buffer[i][j].pgo = pbuf;
+			}
+			peasycap->field_buffer[i][j].pto =
+				peasycap->field_buffer[i][j].pgo;
+		}
+		/* TODO: Hardcoded 0x0200 meaning? */
+		peasycap->field_buffer[i][0].kount = 0x0200;
+	}
+	peasycap->field_fill = 0;
+	peasycap->field_page = 0;
+	peasycap->field_read = 0;
+	JOM(4, "allocation of field buffers done:  %i pages\n", i*j);
+
+	return 0;
+}
+
+static void free_fieldbuffers(struct easycap *peasycap)
+{
+	int k, m, gone;
+
+	JOM(4, "freeing video field buffers.\n");
+	gone = 0;
+	for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
+		for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
+			if (peasycap->field_buffer[k][m].pgo) {
+				free_page((unsigned long)
+					  peasycap->field_buffer[k][m].pgo);
+				peasycap->field_buffer[k][m].pgo = NULL;
+				peasycap->allocation_video_page -= 1;
+				gone++;
+			}
+		}
+	}
+	JOM(4, "video field buffers freed: %i pages\n", gone);
+}
+
+static int alloc_isocbuffers(struct easycap *peasycap)
+{
+	int i;
+	void *pbuf;
+
+	JOM(4, "allocating %i isoc video buffers of size %i\n",
+			VIDEO_ISOC_BUFFER_MANY,
+			peasycap->video_isoc_buffer_size);
+	JOM(4, ".... each occupying contiguous memory pages\n");
+
+	for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
+		pbuf = (void *)__get_free_pages(GFP_KERNEL,
+				VIDEO_ISOC_ORDER);
+		if (!pbuf) {
+			SAM("ERROR: Could not allocate isoc "
+				"video buffer %i\n", i);
+			return -ENOMEM;
+		}
+		peasycap->allocation_video_page += BIT(VIDEO_ISOC_ORDER);
+
+		peasycap->video_isoc_buffer[i].pgo = pbuf;
+		peasycap->video_isoc_buffer[i].pto =
+			pbuf + peasycap->video_isoc_buffer_size;
+		peasycap->video_isoc_buffer[i].kount = i;
+	}
+	JOM(4, "allocation of isoc video buffers done: %i pages\n",
+			i * (0x01 << VIDEO_ISOC_ORDER));
+	return 0;
+}
+
+static void free_isocbuffers(struct easycap *peasycap)
+{
+	int k, m;
+
+	JOM(4, "freeing video isoc buffers.\n");
+	m = 0;
+	for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY;  k++) {
+		if (peasycap->video_isoc_buffer[k].pgo) {
+			free_pages((unsigned long)
+				   peasycap->video_isoc_buffer[k].pgo,
+					VIDEO_ISOC_ORDER);
+			peasycap->video_isoc_buffer[k].pgo = NULL;
+			peasycap->allocation_video_page -=
+						BIT(VIDEO_ISOC_ORDER);
+			m++;
+		}
+	}
+	JOM(4, "isoc video buffers freed: %i pages\n",
+			m * (0x01 << VIDEO_ISOC_ORDER));
+}
+
+static int create_video_urbs(struct easycap *peasycap)
+{
+	struct urb *purb;
+	struct data_urb *pdata_urb;
+	int i, j;
+
+	JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
+	JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
+			peasycap->video_isoc_framesperdesc);
+	JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
+			peasycap->video_isoc_maxframesize);
+	JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
+			peasycap->video_isoc_buffer_size);
+
+	for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
+		purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
+				GFP_KERNEL);
+		if (!purb) {
+			SAM("ERROR: usb_alloc_urb returned NULL for buffer "
+				"%i\n", i);
+			return -ENOMEM;
+		}
+
+		peasycap->allocation_video_urb += 1;
+		pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+		if (!pdata_urb) {
+			SAM("ERROR: Could not allocate struct data_urb.\n");
+			return -ENOMEM;
+		}
+
+		peasycap->allocation_video_struct +=
+			sizeof(struct data_urb);
+
+		pdata_urb->purb = purb;
+		pdata_urb->isbuf = i;
+		pdata_urb->length = 0;
+		list_add_tail(&(pdata_urb->list_head),
+				peasycap->purb_video_head);
+
+		if (!i) {
+			JOM(4, "initializing video urbs thus:\n");
+			JOM(4, "  purb->interval = 1;\n");
+			JOM(4, "  purb->dev = peasycap->pusb_device;\n");
+			JOM(4, "  purb->pipe = usb_rcvisocpipe"
+					"(peasycap->pusb_device,%i);\n",
+					peasycap->video_endpointnumber);
+			JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
+			JOM(4, "  purb->transfer_buffer = peasycap->"
+					"video_isoc_buffer[.].pgo;\n");
+			JOM(4, "  purb->transfer_buffer_length = %i;\n",
+					peasycap->video_isoc_buffer_size);
+			JOM(4, "  purb->complete = easycap_complete;\n");
+			JOM(4, "  purb->context = peasycap;\n");
+			JOM(4, "  purb->start_frame = 0;\n");
+			JOM(4, "  purb->number_of_packets = %i;\n",
+					peasycap->video_isoc_framesperdesc);
+			JOM(4, "  for (j = 0; j < %i; j++)\n",
+					peasycap->video_isoc_framesperdesc);
+			JOM(4, "    {\n");
+			JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
+					peasycap->video_isoc_maxframesize);
+			JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
+					peasycap->video_isoc_maxframesize);
+			JOM(4, "    }\n");
+		}
+
+		purb->interval = 1;
+		purb->dev = peasycap->pusb_device;
+		purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
+				peasycap->video_endpointnumber);
+
+		purb->transfer_flags = URB_ISO_ASAP;
+		purb->transfer_buffer = peasycap->video_isoc_buffer[i].pgo;
+		purb->transfer_buffer_length =
+			peasycap->video_isoc_buffer_size;
+
+		purb->complete = easycap_complete;
+		purb->context = peasycap;
+		purb->start_frame = 0;
+		purb->number_of_packets = peasycap->video_isoc_framesperdesc;
+
+		for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
+			purb->iso_frame_desc[j].offset =
+				j * peasycap->video_isoc_maxframesize;
+			purb->iso_frame_desc[j].length =
+				peasycap->video_isoc_maxframesize;
+		}
+	}
+	JOM(4, "allocation of %i struct urb done.\n", i);
+	return 0;
+}
+
+static void free_video_urbs(struct easycap *peasycap)
+{
+	struct list_head *plist_head, *plist_next;
+	struct data_urb *pdata_urb;
+	int m;
+
+	if (peasycap->purb_video_head) {
+		m = 0;
+		list_for_each(plist_head, peasycap->purb_video_head) {
+			pdata_urb = list_entry(plist_head,
+					struct data_urb, list_head);
+			if (pdata_urb && pdata_urb->purb) {
+				usb_free_urb(pdata_urb->purb);
+				pdata_urb->purb = NULL;
+				peasycap->allocation_video_urb--;
+				m++;
+			}
+		}
+
+		JOM(4, "%i video urbs freed\n", m);
+		JOM(4, "freeing video data_urb structures.\n");
+		m = 0;
+		list_for_each_safe(plist_head, plist_next,
+					peasycap->purb_video_head) {
+			pdata_urb = list_entry(plist_head,
+					struct data_urb, list_head);
+			if (pdata_urb) {
+				peasycap->allocation_video_struct -=
+					sizeof(struct data_urb);
+				kfree(pdata_urb);
+				m++;
+			}
+		}
+		JOM(4, "%i video data_urb structures freed\n", m);
+		JOM(4, "setting peasycap->purb_video_head=NULL\n");
+		peasycap->purb_video_head = NULL;
+	}
+}
+
+static int alloc_audio_buffers(struct easycap *peasycap)
+{
+	void *pbuf;
+	int k;
+
+	JOM(4, "allocating %i isoc audio buffers of size %i\n",
+		AUDIO_ISOC_BUFFER_MANY,
+		peasycap->audio_isoc_buffer_size);
+	JOM(4, ".... each occupying contiguous memory pages\n");
+
+	for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
+		pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER);
+		if (!pbuf) {
+			SAM("ERROR: Could not allocate isoc audio buffer %i\n",
+			    k);
+				return -ENOMEM;
+		}
+		peasycap->allocation_audio_page += BIT(AUDIO_ISOC_ORDER);
+
+		peasycap->audio_isoc_buffer[k].pgo = pbuf;
+		peasycap->audio_isoc_buffer[k].pto =
+			pbuf + peasycap->audio_isoc_buffer_size;
+		peasycap->audio_isoc_buffer[k].kount = k;
+	}
+
+	JOM(4, "allocation of isoc audio buffers done.\n");
+	return 0;
+}
+
+static void free_audio_buffers(struct easycap *peasycap)
+{
+	int k, m;
+
+	JOM(4, "freeing audio isoc buffers.\n");
+	m = 0;
+	for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
+		if (peasycap->audio_isoc_buffer[k].pgo) {
+			free_pages((unsigned long)
+					(peasycap->audio_isoc_buffer[k].pgo),
+					AUDIO_ISOC_ORDER);
+			peasycap->audio_isoc_buffer[k].pgo = NULL;
+			peasycap->allocation_audio_page -=
+					BIT(AUDIO_ISOC_ORDER);
+			m++;
+		}
+	}
+	JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
+					m * (0x01 << AUDIO_ISOC_ORDER));
+}
+
+static int create_audio_urbs(struct easycap *peasycap)
+{
+	struct urb *purb;
+	struct data_urb *pdata_urb;
+	int k, j;
+
+	JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
+	JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
+		peasycap->audio_isoc_framesperdesc);
+	JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
+		peasycap->audio_isoc_maxframesize);
+	JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
+		peasycap->audio_isoc_buffer_size);
+
+	for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY; k++) {
+		purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
+				     GFP_KERNEL);
+		if (!purb) {
+			SAM("ERROR: usb_alloc_urb returned NULL for buffer "
+			     "%i\n", k);
+			return -ENOMEM;
+		}
+		peasycap->allocation_audio_urb += 1 ;
+		pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+		if (!pdata_urb) {
+			usb_free_urb(purb);
+			SAM("ERROR: Could not allocate struct data_urb.\n");
+			return -ENOMEM;
+		}
+		peasycap->allocation_audio_struct +=
+			sizeof(struct data_urb);
+
+		pdata_urb->purb = purb;
+		pdata_urb->isbuf = k;
+		pdata_urb->length = 0;
+		list_add_tail(&(pdata_urb->list_head),
+				peasycap->purb_audio_head);
+
+		if (!k) {
+			JOM(4, "initializing audio urbs thus:\n");
+			JOM(4, "  purb->interval = 1;\n");
+			JOM(4, "  purb->dev = peasycap->pusb_device;\n");
+			JOM(4, "  purb->pipe = usb_rcvisocpipe(peasycap->"
+				"pusb_device,%i);\n",
+				peasycap->audio_endpointnumber);
+			JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
+			JOM(4, "  purb->transfer_buffer = "
+				"peasycap->audio_isoc_buffer[.].pgo;\n");
+			JOM(4, "  purb->transfer_buffer_length = %i;\n",
+				peasycap->audio_isoc_buffer_size);
+			JOM(4, "  purb->complete = easycap_alsa_complete;\n");
+			JOM(4, "  purb->context = peasycap;\n");
+			JOM(4, "  purb->start_frame = 0;\n");
+			JOM(4, "  purb->number_of_packets = %i;\n",
+				peasycap->audio_isoc_framesperdesc);
+			JOM(4, "  for (j = 0; j < %i; j++)\n",
+				peasycap->audio_isoc_framesperdesc);
+			JOM(4, "    {\n");
+			JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
+				peasycap->audio_isoc_maxframesize);
+			JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
+				peasycap->audio_isoc_maxframesize);
+			JOM(4, "    }\n");
+		}
+
+		purb->interval = 1;
+		purb->dev = peasycap->pusb_device;
+		purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
+					     peasycap->audio_endpointnumber);
+		purb->transfer_flags = URB_ISO_ASAP;
+		purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
+		purb->transfer_buffer_length =
+			peasycap->audio_isoc_buffer_size;
+		purb->complete = easycap_alsa_complete;
+		purb->context = peasycap;
+		purb->start_frame = 0;
+		purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
+		for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
+			purb->iso_frame_desc[j].offset =
+				j * peasycap->audio_isoc_maxframesize;
+			purb->iso_frame_desc[j].length =
+				peasycap->audio_isoc_maxframesize;
+		}
+	}
+	JOM(4, "allocation of %i struct urb done.\n", k);
+	return 0;
+}
+
+static void free_audio_urbs(struct easycap *peasycap)
+{
+	struct list_head *plist_head, *plist_next;
+	struct data_urb *pdata_urb;
+	int m;
+
+	if (peasycap->purb_audio_head) {
+		JOM(4, "freeing audio urbs\n");
+		m = 0;
+		list_for_each(plist_head, (peasycap->purb_audio_head)) {
+			pdata_urb = list_entry(plist_head,
+					struct data_urb, list_head);
+			if (pdata_urb && pdata_urb->purb) {
+				usb_free_urb(pdata_urb->purb);
+				pdata_urb->purb = NULL;
+				peasycap->allocation_audio_urb--;
+				m++;
+			}
+		}
+		JOM(4, "%i audio urbs freed\n", m);
+		JOM(4, "freeing audio data_urb structures.\n");
+		m = 0;
+		list_for_each_safe(plist_head, plist_next,
+					peasycap->purb_audio_head) {
+			pdata_urb = list_entry(plist_head,
+					struct data_urb, list_head);
+			if (pdata_urb) {
+				peasycap->allocation_audio_struct -=
+							sizeof(struct data_urb);
+				kfree(pdata_urb);
+				m++;
+			}
+		}
+		JOM(4, "%i audio data_urb structures freed\n", m);
+		JOM(4, "setting peasycap->purb_audio_head=NULL\n");
+		peasycap->purb_audio_head = NULL;
+	}
+}
+
+static void config_easycap(struct easycap *peasycap,
+			   u8 bInterfaceNumber,
+			   u8 bInterfaceClass,
+			   u8 bInterfaceSubClass)
+{
+	if ((USB_CLASS_VIDEO == bInterfaceClass) ||
+	    (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
+		if (-1 == peasycap->video_interface) {
+			peasycap->video_interface = bInterfaceNumber;
+			JOM(4, "setting peasycap->video_interface=%i\n",
+				peasycap->video_interface);
+		} else {
+			if (peasycap->video_interface != bInterfaceNumber) {
+				SAM("ERROR: attempting to reset "
+				    "peasycap->video_interface\n");
+				SAM("...... continuing with "
+				    "%i=peasycap->video_interface\n",
+				    peasycap->video_interface);
+			}
+		}
+	} else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
+		   (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) {
+		if (-1 == peasycap->audio_interface) {
+			peasycap->audio_interface = bInterfaceNumber;
+			JOM(4, "setting peasycap->audio_interface=%i\n",
+				peasycap->audio_interface);
+		} else {
+			if (peasycap->audio_interface != bInterfaceNumber) {
+				SAM("ERROR: attempting to reset "
+				    "peasycap->audio_interface\n");
+				SAM("...... continuing with "
+				    "%i=peasycap->audio_interface\n",
+				    peasycap->audio_interface);
+			}
+		}
+	}
+}
+
+/*
+ * This function is called from within easycap_usb_disconnect() and is
+ * protected by semaphores set and cleared by easycap_usb_disconnect().
+ * By this stage the device has already been physically unplugged,
+ * so peasycap->pusb_device is no longer valid.
+ */
+static void easycap_delete(struct kref *pkref)
+{
+	struct easycap *peasycap;
+
+	peasycap = container_of(pkref, struct easycap, kref);
+	if (!peasycap) {
+		SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
+		return;
+	}
+
+	/* Free video urbs */
+	free_video_urbs(peasycap);
+
+	/* Free video isoc buffers */
+	free_isocbuffers(peasycap);
+
+	/* Free video field buffers */
+	free_fieldbuffers(peasycap);
+
+	/* Free video frame buffers */
+	free_framebuffers(peasycap);
+
+	/* Free audio urbs */
+	free_audio_urbs(peasycap);
+
+	/* Free audio isoc buffers */
+	free_audio_buffers(peasycap);
+
+	free_easycap(peasycap);
+
+	JOT(4, "ending.\n");
+}
+
 static const struct v4l2_file_operations v4l2_fops = {
 	.owner		= THIS_MODULE,
 	.open		= easycap_open_noinode,
@@ -2850,6 +3450,36 @@
 	.mmap		= easycap_mmap,
 };
 
+static int easycap_register_video(struct easycap *peasycap)
+{
+	/*
+	 * FIXME: This is believed to be harmless,
+	 * but may well be unnecessary or wrong.
+	 */
+	peasycap->video_device.v4l2_dev = NULL;
+
+	strcpy(&peasycap->video_device.name[0], "easycapdc60");
+	peasycap->video_device.fops = &v4l2_fops;
+	peasycap->video_device.minor = -1;
+	peasycap->video_device.release = (void *)(&videodev_release);
+
+	video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
+
+	if (0 != (video_register_device(&(peasycap->video_device),
+					VFL_TYPE_GRABBER, -1))) {
+		videodev_release(&(peasycap->video_device));
+		return -ENODEV;
+	}
+
+	peasycap->registered_video++;
+
+	SAM("registered with videodev: %i=minor\n",
+	    peasycap->video_device.minor);
+	    peasycap->minor = peasycap->video_device.minor;
+
+	return 0;
+}
+
 /*
  * When the device is plugged, this function is called three times,
  * one for each interface.
@@ -2861,24 +3491,15 @@
 	struct usb_host_interface *alt;
 	struct usb_endpoint_descriptor *ep;
 	struct usb_interface_descriptor *interface;
-	struct urb *purb;
 	struct easycap *peasycap;
-	int ndong;
-	struct data_urb *pdata_urb;
-	int i, j, k, m, rc;
+	int i, j, rc;
 	u8 bInterfaceNumber;
 	u8 bInterfaceClass;
 	u8 bInterfaceSubClass;
-	void *pbuf;
 	int okalt[8], isokalt;
 	int okepn[8];
 	int okmps[8];
 	int maxpacketsize;
-	u16 mask;
-	s32 value;
-	struct easycap_format *peasycap_format;
-	int fmtidx;
-	struct inputset *inputset;
 
 	usbdev = interface_to_usbdev(intf);
 
@@ -2916,76 +3537,16 @@
 	 * interfaces 1 and 2 are probed.
 	 */
 	if (0 == bInterfaceNumber) {
-		peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
-		if (!peasycap) {
-			SAY("ERROR: Could not allocate peasycap\n");
+		/*
+		 * Alloc structure and save it in a free slot in
+		 * easycapdc60_dongle array
+		 */
+		peasycap = alloc_easycap(bInterfaceNumber);
+		if (!peasycap)
 			return -ENOMEM;
-		}
 
-		/* Perform urgent initializations */
-		peasycap->minor = -1;
-		kref_init(&peasycap->kref);
-		JOM(8, "intf[%i]: after kref_init(..._video) "
-				"%i=peasycap->kref.refcount.counter\n",
-				bInterfaceNumber, peasycap->kref.refcount.counter);
-
-		/* module params */
-		peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
-
-		init_waitqueue_head(&peasycap->wq_video);
-		init_waitqueue_head(&peasycap->wq_audio);
-		init_waitqueue_head(&peasycap->wq_trigger);
-
-		if (mutex_lock_interruptible(&mutex_dongle)) {
-			SAY("ERROR: cannot down mutex_dongle\n");
-			return -ERESTARTSYS;
-		}
-
-		for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
-			if ((!easycapdc60_dongle[ndong].peasycap) &&
-					(!mutex_is_locked(&easycapdc60_dongle
-						[ndong].mutex_video)) &&
-					(!mutex_is_locked(&easycapdc60_dongle
-						[ndong].mutex_audio))) {
-				easycapdc60_dongle[ndong].peasycap = peasycap;
-				peasycap->isdongle = ndong;
-				JOM(8, "intf[%i]: peasycap-->easycap"
-						"_dongle[%i].peasycap\n",
-						bInterfaceNumber, ndong);
-				break;
-			}
-		}
-
-		if (DONGLE_MANY <= ndong) {
-			SAM("ERROR: too many dongles\n");
-			mutex_unlock(&mutex_dongle);
-			return -ENOMEM;
-		}
-		mutex_unlock(&mutex_dongle);
-
-		peasycap->allocation_video_struct = sizeof(struct easycap);
-
-		/* and further initialize the structure */
-		peasycap->pusb_device = usbdev;
-		peasycap->pusb_interface = intf;
-
-		peasycap->microphone = false;
-
-		peasycap->video_interface = -1;
-		peasycap->video_altsetting_on = -1;
-		peasycap->video_altsetting_off = -1;
-		peasycap->video_endpointnumber = -1;
-		peasycap->video_isoc_maxframesize = -1;
-		peasycap->video_isoc_buffer_size = -1;
-
-		peasycap->audio_interface = -1;
-		peasycap->audio_altsetting_on = -1;
-		peasycap->audio_altsetting_off = -1;
-		peasycap->audio_endpointnumber = -1;
-		peasycap->audio_isoc_maxframesize = -1;
-		peasycap->audio_isoc_buffer_size = -1;
-
-		peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
+		/* Perform basic struct initialization */
+		init_easycap(peasycap, usbdev, intf, bInterfaceNumber);
 
 		/* Dynamically fill in the available formats */
 		rc = easycap_video_fillin_formats();
@@ -2996,136 +3557,19 @@
 		JOM(4, "%i formats available\n", rc);
 
 		/* Populate easycap.inputset[] */
-		inputset = peasycap->inputset;
-		fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
-		m = 0;
-		mask = 0;
-		for (i = 0; 0xFFFF != easycap_standard[i].mask; i++) {
-			if (fmtidx == easycap_standard[i].v4l2_standard.index) {
-				m++;
-				for (k = 0; k < INPUT_MANY; k++)
-					inputset[k].standard_offset = i;
-
-				mask = easycap_standard[i].mask;
-			}
-		}
-		if (1 != m) {
-			SAM("ERROR: "
-			    "inputset->standard_offset unpopulated, %i=m\n", m);
-			return -ENOENT;
-		}
-
-		peasycap_format = &easycap_format[0];
-		m = 0;
-		for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
-			struct v4l2_pix_format *pix =
-				&peasycap_format->v4l2_format.fmt.pix;
-			if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) &&
-			    pix->field == V4L2_FIELD_NONE &&
-			    pix->pixelformat == V4L2_PIX_FMT_UYVY &&
-			    pix->width  == 640 && pix->height == 480) {
-				m++;
-				for (k = 0; k < INPUT_MANY; k++)
-					inputset[k].format_offset = i;
-				break;
-			}
-			peasycap_format++;
-		}
-		if (1 != m) {
-			SAM("ERROR: inputset[]->format_offset unpopulated\n");
-			return -ENOENT;
-		}
-
-		m = 0;
-		for (i = 0; 0xFFFFFFFF != easycap_control[i].id; i++) {
-			value = easycap_control[i].default_value;
-			if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
-				m++;
-				for (k = 0; k < INPUT_MANY; k++)
-					inputset[k].brightness = value;
-			} else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
-				m++;
-				for (k = 0; k < INPUT_MANY; k++)
-					inputset[k].contrast = value;
-			} else if (V4L2_CID_SATURATION == easycap_control[i].id) {
-				m++;
-				for (k = 0; k < INPUT_MANY; k++)
-					inputset[k].saturation = value;
-			} else if (V4L2_CID_HUE == easycap_control[i].id) {
-				m++;
-				for (k = 0; k < INPUT_MANY; k++)
-					inputset[k].hue = value;
-			}
-		}
-
-		if (4 != m) {
-			SAM("ERROR: inputset[]->brightness underpopulated\n");
-			return -ENOENT;
-		}
-		for (k = 0; k < INPUT_MANY; k++)
-			inputset[k].input = k;
-		JOM(4, "populated inputset[]\n");
+		rc = populate_inputset(peasycap);
+		if (rc < 0)
+			return rc;
 		JOM(4, "finished initialization\n");
 	} else {
-
-		/*
-		 * FIXME: Identify the appropriate pointer
-		 * peasycap for interfaces 1 and 2.
-		 * The address of peasycap->pusb_device
-		 * is reluctantly used for this purpose.
-		 */
-		for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
-			if (usbdev == easycapdc60_dongle[ndong].peasycap->
-									pusb_device) {
-				peasycap = easycapdc60_dongle[ndong].peasycap;
-				JOT(8, "intf[%i]: dongle[%i].peasycap\n",
-						bInterfaceNumber, ndong);
-				break;
-			}
-		}
-		if (DONGLE_MANY <= ndong) {
-			SAY("ERROR: peasycap is unknown when probing interface %i\n",
-								bInterfaceNumber);
+		peasycap = get_easycap(usbdev, bInterfaceNumber);
+		if (!peasycap)
 			return -ENODEV;
-		}
-		if (!peasycap) {
-			SAY("ERROR: peasycap is NULL when probing interface %i\n",
-								bInterfaceNumber);
-			return -ENODEV;
-		}
 	}
 
-	if ((USB_CLASS_VIDEO == bInterfaceClass) ||
-	    (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
-		if (-1 == peasycap->video_interface) {
-			peasycap->video_interface = bInterfaceNumber;
-			JOM(4, "setting peasycap->video_interface=%i\n",
-							peasycap->video_interface);
-		} else {
-			if (peasycap->video_interface != bInterfaceNumber) {
-				SAM("ERROR: attempting to reset "
-						"peasycap->video_interface\n");
-				SAM("...... continuing with "
-						"%i=peasycap->video_interface\n",
-						peasycap->video_interface);
-			}
-		}
-	} else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
-		   (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) {
-		if (-1 == peasycap->audio_interface) {
-			peasycap->audio_interface = bInterfaceNumber;
-			JOM(4, "setting peasycap->audio_interface=%i\n",
-							 peasycap->audio_interface);
-		} else {
-			if (peasycap->audio_interface != bInterfaceNumber) {
-				SAM("ERROR: attempting to reset "
-						"peasycap->audio_interface\n");
-				SAM("...... continuing with "
-						"%i=peasycap->audio_interface\n",
-						peasycap->audio_interface);
-			}
-		}
-	}
+	config_easycap(peasycap, bInterfaceNumber,
+				 bInterfaceClass,
+				 bInterfaceSubClass);
 
 	/*
 	 * Investigate all altsettings. This is done in detail
@@ -3368,173 +3812,23 @@
 		 */
 		INIT_LIST_HEAD(&(peasycap->urb_video_head));
 		peasycap->purb_video_head = &(peasycap->urb_video_head);
-		JOM(4, "allocating %i frame buffers of size %li\n",
-				FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
-		JOM(4, ".... each scattered over %li pages\n",
-							FRAME_BUFFER_SIZE/PAGE_SIZE);
 
-		for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
-			for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
-				if (peasycap->frame_buffer[k][m].pgo)
-					SAM("attempting to reallocate frame "
-									" buffers\n");
-				else {
-					pbuf = (void *)__get_free_page(GFP_KERNEL);
-					if (!pbuf) {
-						SAM("ERROR: Could not allocate frame "
-							"buffer %i page %i\n", k, m);
-						return -ENOMEM;
-					}
+		rc = alloc_framebuffers(peasycap);
+		if (rc < 0)
+			return rc;
 
-					peasycap->allocation_video_page += 1;
-					peasycap->frame_buffer[k][m].pgo = pbuf;
-				}
-				peasycap->frame_buffer[k][m].pto =
-						peasycap->frame_buffer[k][m].pgo;
-			}
-		}
+		rc = alloc_fieldbuffers(peasycap);
+		if (rc < 0)
+			return rc;
 
-		peasycap->frame_fill = 0;
-		peasycap->frame_read = 0;
-		JOM(4, "allocation of frame buffers done:  %i pages\n", k *
-									m);
-		JOM(4, "allocating %i field buffers of size %li\n",
-				FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
-		JOM(4, ".... each scattered over %li pages\n",
-						FIELD_BUFFER_SIZE/PAGE_SIZE);
+		rc = alloc_isocbuffers(peasycap);
+		if (rc < 0)
+			return rc;
 
-		for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
-			for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
-				if (peasycap->field_buffer[k][m].pgo) {
-					SAM("ERROR: attempting to reallocate "
-								"field buffers\n");
-				} else {
-					pbuf = (void *) __get_free_page(GFP_KERNEL);
-					if (!pbuf) {
-						SAM("ERROR: Could not allocate field"
-							" buffer %i page %i\n", k, m);
-						return -ENOMEM;
-					}
-
-					peasycap->allocation_video_page += 1;
-					peasycap->field_buffer[k][m].pgo = pbuf;
-				}
-				peasycap->field_buffer[k][m].pto =
-						peasycap->field_buffer[k][m].pgo;
-			}
-			peasycap->field_buffer[k][0].kount = 0x0200;
-		}
-		peasycap->field_fill = 0;
-		peasycap->field_page = 0;
-		peasycap->field_read = 0;
-		JOM(4, "allocation of field buffers done:  %i pages\n", k *
-									m);
-		JOM(4, "allocating %i isoc video buffers of size %i\n",
-						VIDEO_ISOC_BUFFER_MANY,
-						peasycap->video_isoc_buffer_size);
-		JOM(4, ".... each occupying contiguous memory pages\n");
-
-		for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY; k++) {
-			pbuf = (void *)__get_free_pages(GFP_KERNEL,
-							VIDEO_ISOC_ORDER);
-			if (!pbuf) {
-				SAM("ERROR: Could not allocate isoc video buffer "
-									"%i\n", k);
-				return -ENOMEM;
-			}
-			peasycap->allocation_video_page +=
-						BIT(VIDEO_ISOC_ORDER);
-
-			peasycap->video_isoc_buffer[k].pgo = pbuf;
-			peasycap->video_isoc_buffer[k].pto =
-				pbuf + peasycap->video_isoc_buffer_size;
-			peasycap->video_isoc_buffer[k].kount = k;
-		}
-		JOM(4, "allocation of isoc video buffers done: %i pages\n",
-						k * (0x01 << VIDEO_ISOC_ORDER));
-
-		/* Allocate and initialize multiple struct usb */
-		JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
-		JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
-						peasycap->video_isoc_framesperdesc);
-		JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
-						peasycap->video_isoc_maxframesize);
-		JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
-						peasycap->video_isoc_buffer_size);
-
-		for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY; k++) {
-			purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
-									GFP_KERNEL);
-			if (!purb) {
-				SAM("ERROR: usb_alloc_urb returned NULL for buffer "
-									"%i\n", k);
-				return -ENOMEM;
-			}
-
-			peasycap->allocation_video_urb += 1;
-			pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
-			if (!pdata_urb) {
-				SAM("ERROR: Could not allocate struct data_urb.\n");
-				return -ENOMEM;
-			}
-
-			peasycap->allocation_video_struct +=
-							sizeof(struct data_urb);
-
-			pdata_urb->purb = purb;
-			pdata_urb->isbuf = k;
-			pdata_urb->length = 0;
-			list_add_tail(&(pdata_urb->list_head),
-							peasycap->purb_video_head);
-
-			/* Initialize allocated urbs */
-			if (!k) {
-				JOM(4, "initializing video urbs thus:\n");
-				JOM(4, "  purb->interval = 1;\n");
-				JOM(4, "  purb->dev = peasycap->pusb_device;\n");
-				JOM(4, "  purb->pipe = usb_rcvisocpipe"
-						"(peasycap->pusb_device,%i);\n",
-						peasycap->video_endpointnumber);
-				JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
-				JOM(4, "  purb->transfer_buffer = peasycap->"
-						"video_isoc_buffer[.].pgo;\n");
-				JOM(4, "  purb->transfer_buffer_length = %i;\n",
-						peasycap->video_isoc_buffer_size);
-				JOM(4, "  purb->complete = easycap_complete;\n");
-				JOM(4, "  purb->context = peasycap;\n");
-				JOM(4, "  purb->start_frame = 0;\n");
-				JOM(4, "  purb->number_of_packets = %i;\n",
-						peasycap->video_isoc_framesperdesc);
-				JOM(4, "  for (j = 0; j < %i; j++)\n",
-						peasycap->video_isoc_framesperdesc);
-				JOM(4, "    {\n");
-				JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
-						peasycap->video_isoc_maxframesize);
-				JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
-						peasycap->video_isoc_maxframesize);
-				JOM(4, "    }\n");
-			}
-
-			purb->interval = 1;
-			purb->dev = peasycap->pusb_device;
-			purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
-						peasycap->video_endpointnumber);
-			purb->transfer_flags = URB_ISO_ASAP;
-			purb->transfer_buffer = peasycap->video_isoc_buffer[k].pgo;
-			purb->transfer_buffer_length =
-						peasycap->video_isoc_buffer_size;
-			purb->complete = easycap_complete;
-			purb->context = peasycap;
-			purb->start_frame = 0;
-			purb->number_of_packets = peasycap->video_isoc_framesperdesc;
-			for (j = 0;  j < peasycap->video_isoc_framesperdesc; j++) {
-				purb->iso_frame_desc[j].offset = j *
-						peasycap->video_isoc_maxframesize;
-				purb->iso_frame_desc[j].length =
-						peasycap->video_isoc_maxframesize;
-			}
-		}
-		JOM(4, "allocation of %i struct urb done.\n", k);
+		/* Allocate and initialize video urbs */
+		rc = create_video_urbs(peasycap);
+		if (rc < 0)
+			return rc;
 
 		/* Save pointer peasycap in this interface */
 		usb_set_intfdata(intf, peasycap);
@@ -3545,9 +3839,6 @@
 		 * because some udev rules triggers easycap_open()
 		 * immediately after registration, causing a clash.
 		 */
-		peasycap->ntsc = easycap_ntsc;
-		JOM(8, "defaulting initially to %s\n",
-			easycap_ntsc ? "NTSC" : "PAL");
 		rc = reset(peasycap);
 		if (rc) {
 			SAM("ERROR: reset() rc = %i\n", rc);
@@ -3562,32 +3853,12 @@
 		JOM(4, "registered device instance: %s\n",
 			peasycap->v4l2_device.name);
 
-		/*
-		 * FIXME: This is believed to be harmless,
-		 * but may well be unnecessary or wrong.
-		 */
-		peasycap->video_device.v4l2_dev = NULL;
-
-
-		strcpy(&peasycap->video_device.name[0], "easycapdc60");
-		peasycap->video_device.fops = &v4l2_fops;
-		peasycap->video_device.minor = -1;
-		peasycap->video_device.release = (void *)(&videodev_release);
-
-		video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
-
-		if (0 != (video_register_device(&(peasycap->video_device),
-							VFL_TYPE_GRABBER, -1))) {
-			err("Not able to register with videodev");
-			videodev_release(&(peasycap->video_device));
+		rc = easycap_register_video(peasycap);
+		if (rc < 0) {
+			dev_err(&intf->dev,
+				"Not able to register with videodev\n");
 			return -ENODEV;
 		}
-
-		peasycap->registered_video++;
-		SAM("registered with videodev: %i=minor\n",
-						peasycap->video_device.minor);
-		peasycap->minor = peasycap->video_device.minor;
-
 		break;
 	}
 	/* 1: Audio control */
@@ -3710,109 +3981,14 @@
 		INIT_LIST_HEAD(&(peasycap->urb_audio_head));
 		peasycap->purb_audio_head = &(peasycap->urb_audio_head);
 
-		JOM(4, "allocating %i isoc audio buffers of size %i\n",
-			AUDIO_ISOC_BUFFER_MANY,
-			peasycap->audio_isoc_buffer_size);
-		JOM(4, ".... each occupying contiguous memory pages\n");
-
-		for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
-			pbuf = (void *)__get_free_pages(GFP_KERNEL,
-							AUDIO_ISOC_ORDER);
-			if (!pbuf) {
-				SAM("ERROR: Could not allocate isoc audio buffer "
-								"%i\n", k);
-				return -ENOMEM;
-			}
-			peasycap->allocation_audio_page +=
-						BIT(AUDIO_ISOC_ORDER);
-
-			peasycap->audio_isoc_buffer[k].pgo = pbuf;
-			peasycap->audio_isoc_buffer[k].pto = pbuf +
-			peasycap->audio_isoc_buffer_size;
-			peasycap->audio_isoc_buffer[k].kount = k;
-		}
-		JOM(4, "allocation of isoc audio buffers done.\n");
+		alloc_audio_buffers(peasycap);
+		if (rc < 0)
+			return rc;
 
 		/* Allocate and initialize urbs */
-		JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
-		JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
-					peasycap->audio_isoc_framesperdesc);
-		JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
-					peasycap->audio_isoc_maxframesize);
-		JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
-					peasycap->audio_isoc_buffer_size);
-
-		for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY; k++) {
-			purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
-								GFP_KERNEL);
-			if (!purb) {
-				SAM("ERROR: usb_alloc_urb returned NULL for buffer "
-								"%i\n", k);
-				return -ENOMEM;
-			}
-			peasycap->allocation_audio_urb += 1 ;
-			pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
-			if (!pdata_urb) {
-				usb_free_urb(purb);
-				SAM("ERROR: Could not allocate struct data_urb.\n");
-				return -ENOMEM;
-			}
-			peasycap->allocation_audio_struct +=
-						sizeof(struct data_urb);
-
-			pdata_urb->purb = purb;
-			pdata_urb->isbuf = k;
-			pdata_urb->length = 0;
-			list_add_tail(&(pdata_urb->list_head),
-							peasycap->purb_audio_head);
-
-			if (!k) {
-				JOM(4, "initializing audio urbs thus:\n");
-				JOM(4, "  purb->interval = 1;\n");
-				JOM(4, "  purb->dev = peasycap->pusb_device;\n");
-				JOM(4, "  purb->pipe = usb_rcvisocpipe(peasycap->"
-						"pusb_device,%i);\n",
-						peasycap->audio_endpointnumber);
-				JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
-				JOM(4, "  purb->transfer_buffer = "
-					"peasycap->audio_isoc_buffer[.].pgo;\n");
-				JOM(4, "  purb->transfer_buffer_length = %i;\n",
-					peasycap->audio_isoc_buffer_size);
-				JOM(4, "  purb->complete = easycap_alsa_complete;\n");
-				JOM(4, "  purb->context = peasycap;\n");
-				JOM(4, "  purb->start_frame = 0;\n");
-				JOM(4, "  purb->number_of_packets = %i;\n",
-						peasycap->audio_isoc_framesperdesc);
-				JOM(4, "  for (j = 0; j < %i; j++)\n",
-						peasycap->audio_isoc_framesperdesc);
-				JOM(4, "    {\n");
-				JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
-					peasycap->audio_isoc_maxframesize);
-				JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
-					peasycap->audio_isoc_maxframesize);
-				JOM(4, "    }\n");
-			}
-
-			purb->interval = 1;
-			purb->dev = peasycap->pusb_device;
-			purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
-						peasycap->audio_endpointnumber);
-			purb->transfer_flags = URB_ISO_ASAP;
-			purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
-			purb->transfer_buffer_length =
-						peasycap->audio_isoc_buffer_size;
-			purb->complete = easycap_alsa_complete;
-			purb->context = peasycap;
-			purb->start_frame = 0;
-			purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
-			for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
-				purb->iso_frame_desc[j].offset = j *
-						peasycap->audio_isoc_maxframesize;
-				purb->iso_frame_desc[j].length =
-						peasycap->audio_isoc_maxframesize;
-			}
-		}
-		JOM(4, "allocation of %i struct urb done.\n", k);
+		rc = create_audio_urbs(peasycap);
+		if (rc < 0)
+			return rc;
 
 		/* Save pointer peasycap in this interface */
 		usb_set_intfdata(intf, peasycap);
@@ -3822,7 +3998,8 @@
 
 		rc = easycap_alsa_probe(peasycap);
 		if (rc) {
-			err("easycap_alsa_probe() rc = %i\n", rc);
+			dev_err(&intf->dev, "easycap_alsa_probe() rc = %i\n",
+				rc);
 			return -ENODEV;
 		}
 
@@ -3841,15 +4018,13 @@
 	SAM("ends successfully for interface %i\n", bInterfaceNumber);
 	return 0;
 }
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
+
 /*
- *  WHEN THIS FUNCTION IS CALLED THE EasyCAP HAS ALREADY BEEN PHYSICALLY
- *  UNPLUGGED.  HENCE peasycap->pusb_device IS NO LONGER VALID.
- *
- *  THIS FUNCTION AFFECTS ALSA.  BEWARE.
+ * When this function is called the device has already been
+ * physically unplugged.
+ * Hence, peasycap->pusb_device is no longer valid.
+ * This function affects alsa.
  */
-/*---------------------------------------------------------------------------*/
 static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
 {
 	struct usb_host_interface *pusb_host_interface;
@@ -3874,6 +4049,7 @@
 	minor = pusb_interface->minor;
 	JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
 
+	/* There is nothing to do for Interface Number 1 */
 	if (1 == bInterfaceNumber)
 		return;
 
@@ -3882,11 +4058,8 @@
 		SAY("ERROR: peasycap is NULL\n");
 		return;
 	}
-/*---------------------------------------------------------------------------*/
-/*
- *  IF THE WAIT QUEUES ARE NOT CLEARED A DEADLOCK IS POSSIBLE.  BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
+
+	/* If the waitqueues are not cleared a deadlock is possible */
 	peasycap->video_eof = 1;
 	peasycap->audio_eof = 1;
 	wake_up_interruptible(&(peasycap->wq_video));
@@ -3902,15 +4075,14 @@
 	default:
 		break;
 	}
-/*--------------------------------------------------------------------------*/
-/*
- *  DEREGISTER
- *
- *  THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO
- *  IOCTL ARE ALL UNLOCKED.  IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN
- *  AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING.  BEWARE.
- */
-/*--------------------------------------------------------------------------*/
+
+	/*
+	 * Deregister
+	 * This procedure will block until easycap_poll(),
+	 * video and audio ioctl are all unlocked.
+	 * If this is not done an oops can occur when an easycap
+	 * is unplugged while the urbs are running.
+	 */
 	kd = easycap_isdongle(peasycap);
 	switch (bInterfaceNumber) {
 	case 0: {
@@ -3927,7 +4099,6 @@
 		} else {
 			SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
 		}
-/*---------------------------------------------------------------------------*/
 		if (!peasycap->v4l2_device.name[0]) {
 			SAM("ERROR: peasycap->v4l2_device.name is empty\n");
 			if (0 <= kd && DONGLE_MANY > kd)
@@ -3943,7 +4114,6 @@
 		JOM(4, "intf[%i]: video_unregister_device() minor=%i\n",
 				bInterfaceNumber, minor);
 		peasycap->registered_video--;
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
 
 		if (0 <= kd && DONGLE_MANY > kd) {
 			mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
@@ -3979,12 +4149,12 @@
 	default:
 		break;
 	}
-/*---------------------------------------------------------------------------*/
-/*
- *  CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
- *  (ALSO WHEN ALSA HAS BEEN IN USE)
- */
-/*---------------------------------------------------------------------------*/
+
+	/*
+	 * If no remaining references to peasycap,
+	 * call easycap_delete.
+	 * (Also when alsa has been in use)
+	 */
 	if (!peasycap->kref.refcount.counter) {
 		SAM("ERROR: peasycap->kref.refcount.counter is zero "
 							"so cannot call kref_put()\n");
@@ -4019,17 +4189,11 @@
 		mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
 		JOT(4, "unlocked dongle[%i].mutex_video\n", kd);
 	}
-/*---------------------------------------------------------------------------*/
 	JOM(4, "ends\n");
 	return;
 }
-/*****************************************************************************/
 
-/*---------------------------------------------------------------------------*/
-/*
- *  PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO
- */
-/*---------------------------------------------------------------------------*/
+/* Devices supported by this driver */
 static struct usb_device_id easycap_usb_device_id_table[] = {
 	{USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID)},
 	{ }
@@ -4064,14 +4228,11 @@
 
 	return rc;
 }
-/*****************************************************************************/
+
 static void __exit easycap_module_exit(void)
 {
 	usb_deregister(&easycap_usb_driver);
 }
-/*****************************************************************************/
 
 module_init(easycap_module_init);
 module_exit(easycap_module_exit);
-
-/*****************************************************************************/
diff --git a/drivers/staging/media/go7007/README b/drivers/staging/media/go7007/README
index 48f4476..aeba132 100644
--- a/drivers/staging/media/go7007/README
+++ b/drivers/staging/media/go7007/README
@@ -6,6 +6,6 @@
 	- testing?
 	- handle churn in v4l layer.
 
-Please send patchs to Greg Kroah-Hartman <greg@kroah.com> and Cc: Ross
+Please send patches to Greg Kroah-Hartman <greg@linuxfoundation.org> and Cc: Ross
 Cohen <rcohen@snurgle.org> as well.
 
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
index 3ef4cd8..c184ad3 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/staging/media/go7007/go7007-v4l2.c
@@ -76,7 +76,6 @@
 
 static int go7007_streamoff(struct go7007 *go)
 {
-	int retval = -EINVAL;
 	unsigned long flags;
 
 	mutex_lock(&go->hw_lock);
@@ -87,7 +86,6 @@
 		abort_queued(go);
 		spin_unlock_irqrestore(&go->spinlock, flags);
 		go7007_reset_encoder(go);
-		retval = 0;
 	}
 	mutex_unlock(&go->hw_lock);
 	return 0;
diff --git a/drivers/staging/media/go7007/go7007.txt b/drivers/staging/media/go7007/go7007.txt
index 9db1f39..fcb3e23 100644
--- a/drivers/staging/media/go7007/go7007.txt
+++ b/drivers/staging/media/go7007/go7007.txt
@@ -87,7 +87,6 @@
 	CONFIG_SOUND             - Sound card support
 	CONFIG_SND               - Advanced Linux Sound Architecture
 	CONFIG_USB               - Support for Host-side USB
-	CONFIG_USB_DEVICEFS      - USB device filesystem
 	CONFIG_USB_EHCI_HCD      - EHCI HCD (USB 2.0) support
 
 Additionally, to use the example application, the following options need to
diff --git a/drivers/staging/media/go7007/s2250-loader.c b/drivers/staging/media/go7007/s2250-loader.c
index 4e13251..f1bd159 100644
--- a/drivers/staging/media/go7007/s2250-loader.c
+++ b/drivers/staging/media/go7007/s2250-loader.c
@@ -160,32 +160,10 @@
 	.id_table	= s2250loader_ids,
 };
 
-static int __init s2250loader_init(void)
-{
-	int r;
-	unsigned i = 0;
-
-	for (i = 0; i < MAX_DEVICES; i++)
-		s2250_dev_table[i] = NULL;
-
-	r = usb_register(&s2250loader_driver);
-	if (r) {
-		printk(KERN_ERR "usb_register failed. Error number %d\n", r);
-		return -1;
-	}
-
-	printk(KERN_INFO "s2250loader_init: driver registered\n");
-	return 0;
-}
-module_init(s2250loader_init);
-
-static void __exit s2250loader_cleanup(void)
-{
-	printk(KERN_INFO "s2250loader_cleanup\n");
-	usb_deregister(&s2250loader_driver);
-}
-module_exit(s2250loader_cleanup);
+module_usb_driver(s2250loader_driver);
 
 MODULE_AUTHOR("");
 MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251");
 MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE(S2250_LOADER_FIRMWARE);
+MODULE_FIRMWARE(S2250_FIRMWARE);
diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c
index 5f7f8cd..2944fde 100644
--- a/drivers/staging/media/lirc/lirc_imon.c
+++ b/drivers/staging/media/lirc/lirc_imon.c
@@ -70,10 +70,6 @@
 static int ir_open(void *data);
 static void ir_close(void *data);
 
-/* Driver init/exit prototypes */
-static int __init imon_init(void);
-static void __exit imon_exit(void);
-
 /*** G L O B A L S ***/
 #define IMON_DATA_BUF_SZ	35
 
@@ -209,8 +205,9 @@
 
 	retval = lirc_unregister_driver(minor);
 	if (retval)
-		err("%s: unable to deregister from lirc(%d)",
-			__func__, retval);
+		printk(KERN_ERR KBUILD_MODNAME
+		       ": %s: unable to deregister from lirc(%d)",
+		       __func__, retval);
 	else
 		printk(KERN_INFO MOD_NAME ": Deregistered iMON driver "
 		       "(minor:%d)\n", minor);
@@ -234,16 +231,18 @@
 	subminor = iminor(inode);
 	interface = usb_find_interface(&imon_driver, subminor);
 	if (!interface) {
-		err("%s: could not find interface for minor %d",
-		    __func__, subminor);
+		printk(KERN_ERR KBUILD_MODNAME
+		       ": %s: could not find interface for minor %d\n",
+		       __func__, subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
 	context = usb_get_intfdata(interface);
 
 	if (!context) {
-		err("%s: no context found for minor %d",
-					__func__, subminor);
+		dev_err(&interface->dev,
+			"%s: no context found for minor %d\n",
+			__func__, subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
@@ -251,10 +250,12 @@
 	mutex_lock(&context->ctx_lock);
 
 	if (!context->display) {
-		err("%s: display not supported by device", __func__);
+		dev_err(&interface->dev,
+			"%s: display not supported by device\n", __func__);
 		retval = -ENODEV;
 	} else if (context->display_isopen) {
-		err("%s: display port is already open", __func__);
+		dev_err(&interface->dev,
+			"%s: display port is already open\n", __func__);
 		retval = -EBUSY;
 	} else {
 		context->display_isopen = 1;
@@ -281,17 +282,20 @@
 	context = file->private_data;
 
 	if (!context) {
-		err("%s: no context for device", __func__);
+		printk(KERN_ERR KBUILD_MODNAME
+		       "%s: no context for device\n", __func__);
 		return -ENODEV;
 	}
 
 	mutex_lock(&context->ctx_lock);
 
 	if (!context->display) {
-		err("%s: display not supported by device", __func__);
+		dev_err(&context->usbdev->dev,
+			"%s: display not supported by device\n", __func__);
 		retval = -ENODEV;
 	} else if (!context->display_isopen) {
-		err("%s: display is not open", __func__);
+		dev_err(&context->usbdev->dev,
+			"%s: display is not open\n", __func__);
 		retval = -EIO;
 	} else {
 		context->display_isopen = 0;
@@ -340,19 +344,23 @@
 	retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
 	if (retval) {
 		atomic_set(&(context->tx.busy), 0);
-		err("%s: error submitting urb(%d)", __func__, retval);
+		dev_err(&context->usbdev->dev,
+			"%s: error submitting urb(%d)\n", __func__, retval);
 	} else {
 		/* Wait for transmission to complete (or abort) */
 		mutex_unlock(&context->ctx_lock);
 		retval = wait_for_completion_interruptible(
 				&context->tx.finished);
 		if (retval)
-			err("%s: task interrupted", __func__);
+			dev_err(&context->usbdev->dev,
+				"%s: task interrupted\n", __func__);
 		mutex_lock(&context->ctx_lock);
 
 		retval = context->tx.status;
 		if (retval)
-			err("%s: packet tx failed (%d)", __func__, retval);
+			dev_err(&context->usbdev->dev,
+				"%s: packet tx failed (%d)\n",
+				__func__, retval);
 	}
 
 	return retval;
@@ -383,20 +391,23 @@
 
 	context = file->private_data;
 	if (!context) {
-		err("%s: no context for device", __func__);
+		printk(KERN_ERR KBUILD_MODNAME
+		       "%s: no context for device\n", __func__);
 		return -ENODEV;
 	}
 
 	mutex_lock(&context->ctx_lock);
 
 	if (!context->dev_present) {
-		err("%s: no iMON device present", __func__);
+		dev_err(&context->usbdev->dev,
+			"%s: no iMON device present\n", __func__);
 		retval = -ENODEV;
 		goto exit;
 	}
 
 	if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
-		err("%s: invalid payload size", __func__);
+		dev_err(&context->usbdev->dev,
+			"%s: invalid payload size\n", __func__);
 		retval = -EINVAL;
 		goto exit;
 	}
@@ -425,8 +436,9 @@
 
 		retval = send_packet(context);
 		if (retval) {
-			err("%s: send packet failed for packet #%d",
-					__func__, seq/2);
+			dev_err(&context->usbdev->dev,
+				"%s: send packet failed for packet #%d\n",
+				__func__, seq/2);
 			goto exit;
 		} else {
 			seq += 2;
@@ -441,7 +453,8 @@
 		context->usb_tx_buf[7] = (unsigned char) seq;
 		retval = send_packet(context);
 		if (retval)
-			err("%s: send packet failed for packet #%d",
+			dev_err(&context->usbdev->dev,
+				"%s: send packet failed for packet #%d\n",
 					__func__, seq/2);
 	}
 
@@ -508,7 +521,8 @@
 
 	context = (struct imon_context *)data;
 	if (!context) {
-		err("%s: no context for device", __func__);
+		printk(KERN_ERR KBUILD_MODNAME
+		       "%s: no context for device\n", __func__);
 		return;
 	}
 
@@ -732,7 +746,7 @@
 
 	context = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
 	if (!context) {
-		err("%s: kzalloc failed for context", __func__);
+		dev_err(dev, "%s: kzalloc failed for context\n", __func__);
 		alloc_status = 1;
 		goto alloc_status_switch;
 	}
@@ -797,7 +811,7 @@
 
 	/* Input endpoint is mandatory */
 	if (!ir_ep_found) {
-		err("%s: no valid input (IR) endpoint found.", __func__);
+		dev_err(dev, "%s: no valid input (IR) endpoint found.\n", __func__);
 		retval = -ENODEV;
 		alloc_status = 2;
 		goto alloc_status_switch;
@@ -814,30 +828,30 @@
 
 	driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
 	if (!driver) {
-		err("%s: kzalloc failed for lirc_driver", __func__);
+		dev_err(dev, "%s: kzalloc failed for lirc_driver\n", __func__);
 		alloc_status = 2;
 		goto alloc_status_switch;
 	}
 	rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
 	if (!rbuf) {
-		err("%s: kmalloc failed for lirc_buffer", __func__);
+		dev_err(dev, "%s: kmalloc failed for lirc_buffer\n", __func__);
 		alloc_status = 3;
 		goto alloc_status_switch;
 	}
 	if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
-		err("%s: lirc_buffer_init failed", __func__);
+		dev_err(dev, "%s: lirc_buffer_init failed\n", __func__);
 		alloc_status = 4;
 		goto alloc_status_switch;
 	}
 	rx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!rx_urb) {
-		err("%s: usb_alloc_urb failed for IR urb", __func__);
+		dev_err(dev, "%s: usb_alloc_urb failed for IR urb\n", __func__);
 		alloc_status = 5;
 		goto alloc_status_switch;
 	}
 	tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!tx_urb) {
-		err("%s: usb_alloc_urb failed for display urb",
+		dev_err(dev, "%s: usb_alloc_urb failed for display urb\n",
 		    __func__);
 		alloc_status = 6;
 		goto alloc_status_switch;
@@ -865,7 +879,7 @@
 
 	lirc_minor = lirc_register_driver(driver);
 	if (lirc_minor < 0) {
-		err("%s: lirc_register_driver failed", __func__);
+		dev_err(dev, "%s: lirc_register_driver failed\n", __func__);
 		alloc_status = 7;
 		goto unlock;
 	} else
@@ -900,8 +914,8 @@
 	retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
 
 	if (retval) {
-		err("%s: usb_submit_urb failed for intf0 (%d)",
-		    __func__, retval);
+		dev_err(dev, "%s: usb_submit_urb failed for intf0 (%d)\n",
+			__func__, retval);
 		mutex_unlock(&context->ctx_lock);
 		goto exit;
 	}
diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c
index 7442104..f4e4d90 100644
--- a/drivers/staging/media/lirc/lirc_sasem.c
+++ b/drivers/staging/media/lirc/lirc_sasem.c
@@ -80,10 +80,6 @@
 static int ir_open(void *data);
 static void ir_close(void *data);
 
-/* Driver init/exit prototypes */
-static int __init sasem_init(void);
-static void __exit sasem_exit(void);
-
 /*** G L O B A L S ***/
 #define SASEM_DATA_BUF_SZ	32
 
@@ -185,7 +181,7 @@
 
 	retval = lirc_unregister_driver(minor);
 	if (retval)
-		err("%s: unable to deregister from lirc (%d)",
+		printk(KERN_ERR "%s: unable to deregister from lirc (%d)\n",
 			__func__, retval);
 	else
 		printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n",
@@ -210,16 +206,18 @@
 	subminor = iminor(inode);
 	interface = usb_find_interface(&sasem_driver, subminor);
 	if (!interface) {
-		err("%s: could not find interface for minor %d",
-		    __func__, subminor);
+		printk(KERN_ERR KBUILD_MODNAME
+		       ": %s: could not find interface for minor %d\n",
+		       __func__, subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
 	context = usb_get_intfdata(interface);
 
 	if (!context) {
-		err("%s: no context found for minor %d",
-					__func__, subminor);
+		dev_err(&interface->dev,
+			"%s: no context found for minor %d\n",
+			__func__, subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
@@ -227,12 +225,13 @@
 	mutex_lock(&context->ctx_lock);
 
 	if (context->vfd_isopen) {
-		err("%s: VFD port is already open", __func__);
+		dev_err(&interface->dev,
+			"%s: VFD port is already open", __func__);
 		retval = -EBUSY;
 	} else {
 		context->vfd_isopen = 1;
 		file->private_data = context;
-		printk(KERN_INFO "VFD port opened\n");
+		dev_info(&interface->dev, "VFD port opened\n");
 	}
 
 	mutex_unlock(&context->ctx_lock);
@@ -253,7 +252,8 @@
 	context = (struct sasem_context *) file->private_data;
 
 	if (!context) {
-		err("%s: no context for device", __func__);
+		printk(KERN_ERR KBUILD_MODNAME
+		       ": %s: no context for device\n", __func__);
 		return -ENODEV;
 	}
 
@@ -287,14 +287,15 @@
 	context = (struct sasem_context *) file->private_data;
 
 	if (!context) {
-		err("%s: no context for device", __func__);
+		printk(KERN_ERR KBUILD_MODNAME
+		       ": %s: no context for device\n", __func__);
 		return -ENODEV;
 	}
 
 	mutex_lock(&context->ctx_lock);
 
 	if (!context->vfd_isopen) {
-		err("%s: VFD is not open", __func__);
+		dev_err(&context->dev->dev, "%s: VFD is not open\n", __func__);
 		retval = -EIO;
 	} else {
 		context->vfd_isopen = 0;
@@ -339,7 +340,8 @@
 	retval =  usb_submit_urb(context->tx_urb, GFP_KERNEL);
 	if (retval) {
 		atomic_set(&(context->tx.busy), 0);
-		err("%s: error submitting urb (%d)", __func__, retval);
+		dev_err(&context->dev->dev, "%s: error submitting urb (%d)\n",
+			__func__, retval);
 	} else {
 		/* Wait for transmission to complete (or abort) */
 		mutex_unlock(&context->ctx_lock);
@@ -348,7 +350,9 @@
 
 		retval = context->tx.status;
 		if (retval)
-			err("%s: packet tx failed (%d)", __func__, retval);
+			dev_err(&context->dev->dev,
+				"%s: packet tx failed (%d)\n",
+				__func__, retval);
 	}
 
 	return retval;
@@ -369,20 +373,23 @@
 
 	context = (struct sasem_context *) file->private_data;
 	if (!context) {
-		err("%s: no context for device", __func__);
+		printk(KERN_ERR KBUILD_MODNAME
+		       ": %s: no context for device\n", __func__);
 		return -ENODEV;
 	}
 
 	mutex_lock(&context->ctx_lock);
 
 	if (!context->dev_present) {
-		err("%s: no Sasem device present", __func__);
+		printk(KERN_ERR KBUILD_MODNAME
+		       ": %s: no Sasem device present\n", __func__);
 		retval = -ENODEV;
 		goto exit;
 	}
 
 	if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
-		err("%s: invalid payload size", __func__);
+		dev_err(&context->dev->dev, "%s: invalid payload size\n",
+			__func__);
 		retval = -EINVAL;
 		goto exit;
 	}
@@ -440,9 +447,9 @@
 		}
 		retval = send_packet(context);
 		if (retval) {
-
-			err("%s: send packet failed for packet #%d",
-					__func__, i);
+			dev_err(&context->dev->dev,
+				"%s: send packet failed for packet #%d\n",
+				__func__, i);
 			goto exit;
 		}
 	}
@@ -492,7 +499,8 @@
 	mutex_lock(&context->ctx_lock);
 
 	if (context->ir_isopen) {
-		err("%s: IR port is already open", __func__);
+		dev_err(&context->dev->dev, "%s: IR port is already open\n",
+			__func__);
 		retval = -EBUSY;
 		goto exit;
 	}
@@ -506,8 +514,9 @@
 	retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
 
 	if (retval)
-		err("%s: usb_submit_urb failed for ir_open (%d)",
-		    __func__, retval);
+		dev_err(&context->dev->dev,
+			"%s: usb_submit_urb failed for ir_open (%d)\n",
+			__func__, retval);
 	else {
 		context->ir_isopen = 1;
 		printk(KERN_INFO "IR port opened\n");
@@ -529,7 +538,8 @@
 
 	context = (struct sasem_context *)data;
 	if (!context) {
-		err("%s: no context for device", __func__);
+		printk(KERN_ERR KBUILD_MODNAME
+		       ": %s: no context for device\n", __func__);
 		return;
 	}
 
@@ -687,7 +697,7 @@
 	struct sasem_context *context = NULL;
 	int i;
 
-	printk(KERN_INFO "%s: found Sasem device\n", __func__);
+	dev_info(&interface->dev, "%s: found Sasem device\n", __func__);
 
 
 	dev = usb_get_dev(interface_to_usbdev(interface));
@@ -719,8 +729,8 @@
 			rx_endpoint = ep;
 			ir_ep_found = 1;
 			if (debug)
-				printk(KERN_INFO "%s: found IR endpoint\n",
-				       __func__);
+				dev_info(&interface->dev,
+					"%s: found IR endpoint\n", __func__);
 
 		} else if (!vfd_ep_found &&
 			ep_dir == USB_DIR_OUT &&
@@ -729,22 +739,23 @@
 			tx_endpoint = ep;
 			vfd_ep_found = 1;
 			if (debug)
-				printk(KERN_INFO "%s: found VFD endpoint\n",
-				       __func__);
+				dev_info(&interface->dev,
+					"%s: found VFD endpoint\n", __func__);
 		}
 	}
 
 	/* Input endpoint is mandatory */
 	if (!ir_ep_found) {
-
-		err("%s: no valid input (IR) endpoint found.", __func__);
+		dev_err(&interface->dev,
+			"%s: no valid input (IR) endpoint found.\n", __func__);
 		retval = -ENODEV;
 		goto exit;
 	}
 
 	if (!vfd_ep_found)
-		printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n",
-		       __func__);
+		dev_info(&interface->dev,
+			"%s: no valid output (VFD) endpoint found.\n",
+			__func__);
 
 
 	/* Allocate memory */
@@ -752,38 +763,44 @@
 
 	context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
 	if (!context) {
-		err("%s: kzalloc failed for context", __func__);
+		dev_err(&interface->dev,
+			"%s: kzalloc failed for context\n", __func__);
 		alloc_status = 1;
 		goto alloc_status_switch;
 	}
 	driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
 	if (!driver) {
-		err("%s: kzalloc failed for lirc_driver", __func__);
+		dev_err(&interface->dev,
+			"%s: kzalloc failed for lirc_driver\n", __func__);
 		alloc_status = 2;
 		goto alloc_status_switch;
 	}
 	rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
 	if (!rbuf) {
-		err("%s: kmalloc failed for lirc_buffer", __func__);
+		dev_err(&interface->dev,
+			"%s: kmalloc failed for lirc_buffer\n", __func__);
 		alloc_status = 3;
 		goto alloc_status_switch;
 	}
 	if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
-		err("%s: lirc_buffer_init failed", __func__);
+		dev_err(&interface->dev,
+			"%s: lirc_buffer_init failed\n", __func__);
 		alloc_status = 4;
 		goto alloc_status_switch;
 	}
 	rx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!rx_urb) {
-		err("%s: usb_alloc_urb failed for IR urb", __func__);
+		dev_err(&interface->dev,
+			"%s: usb_alloc_urb failed for IR urb\n", __func__);
 		alloc_status = 5;
 		goto alloc_status_switch;
 	}
 	if (vfd_ep_found) {
 		tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 		if (!tx_urb) {
-			err("%s: usb_alloc_urb failed for VFD urb",
-			    __func__);
+			dev_err(&interface->dev,
+				"%s: usb_alloc_urb failed for VFD urb",
+				__func__);
 			alloc_status = 6;
 			goto alloc_status_switch;
 		}
@@ -807,7 +824,8 @@
 
 	lirc_minor = lirc_register_driver(driver);
 	if (lirc_minor < 0) {
-		err("%s: lirc_register_driver failed", __func__);
+		dev_err(&interface->dev,
+			"%s: lirc_register_driver failed\n", __func__);
 		alloc_status = 7;
 		retval = lirc_minor;
 		goto unlock;
diff --git a/drivers/staging/media/lirc/lirc_ttusbir.c b/drivers/staging/media/lirc/lirc_ttusbir.c
index 7950887..3bb865c 100644
--- a/drivers/staging/media/lirc/lirc_ttusbir.c
+++ b/drivers/staging/media/lirc/lirc_ttusbir.c
@@ -113,8 +113,9 @@
 	for (i = 0; i < num_urbs; i++) {
 		retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
 		if (retval) {
-			err("%s: usb_submit_urb failed on urb %d",
-			    __func__, i);
+			dev_err(&ttusbir->interf->dev,
+				"%s: usb_submit_urb failed on urb %d\n",
+				__func__, i);
 			return retval;
 		}
 	}
@@ -278,7 +279,7 @@
 	if (ttusbir->alt_setting != -1)
 		DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
 	else {
-		err("Could not find alternate setting\n");
+		dev_err(&intf->dev, "Could not find alternate setting\n");
 		kfree(ttusbir);
 		return -EINVAL;
 	}
@@ -291,7 +292,7 @@
 
 	/* Register as a LIRC driver */
 	if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) {
-		err("Could not get memory for LIRC data buffer\n");
+		dev_err(&intf->dev, "Could not get memory for LIRC data buffer\n");
 		usb_set_intfdata(intf, NULL);
 		kfree(ttusbir);
 		return -ENOMEM;
@@ -310,7 +311,7 @@
 	ttusbir->driver.features = LIRC_CAN_REC_MODE2;
 	ttusbir->minor = lirc_register_driver(&ttusbir->driver);
 	if (ttusbir->minor < 0) {
-		err("Error registering as LIRC driver\n");
+		dev_err(&intf->dev, "Error registering as LIRC driver\n");
 		usb_set_intfdata(intf, NULL);
 		lirc_buffer_free(&ttusbir->rbuf);
 		kfree(ttusbir);
@@ -321,7 +322,7 @@
 	for (i = 0; i < num_urbs; i++) {
 		ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
 		if (!ttusbir->urb[i]) {
-			err("Could not allocate memory for the URB\n");
+			dev_err(&intf->dev, "Could not allocate memory for the URB\n");
 			for (j = i - 1; j >= 0; j--)
 				kfree(ttusbir->urb[j]);
 			lirc_buffer_free(&ttusbir->rbuf);
diff --git a/drivers/staging/mei/TODO b/drivers/staging/mei/TODO
deleted file mode 100644
index fc26601..0000000
--- a/drivers/staging/mei/TODO
+++ /dev/null
@@ -1,10 +0,0 @@
-TODO:
-	- Cleanup and split the timer function
-Upon Unstaging:
-	- move mei.h to include/linux/mei.h
-	- Documentation/ioctl/ioctl-number.txt
-	- move mei.txt under Documentation/mei/
-	- move mei-amt-version.c under Documentation/mei
-	- add hostprogs-y for mei-amt-version.c
-	- drop mei_version.h
-	- Updated MAINTAINERS
diff --git a/drivers/staging/mei/init.c b/drivers/staging/mei/init.c
deleted file mode 100644
index eab711f..0000000
--- a/drivers/staging/mei/init.c
+++ /dev/null
@@ -1,735 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, 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.
- *
- */
-
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-
-#include "mei_dev.h"
-#include "hw.h"
-#include "interface.h"
-#include "mei.h"
-
-const uuid_le mei_amthi_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
-						0xa8, 0x46, 0xe0, 0xff, 0x65,
-						0x81, 0x4c);
-
-/**
- * mei_io_list_init - Sets up a queue list.
- *
- * @list: An instance io list structure
- * @dev: the device structure
- */
-void mei_io_list_init(struct mei_io_list *list)
-{
-	/* initialize our queue list */
-	INIT_LIST_HEAD(&list->mei_cb.cb_list);
-}
-
-/**
- * mei_io_list_flush - removes list entry belonging to cl.
- *
- * @list:  An instance of our list structure
- * @cl: private data of the file object
- */
-void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl)
-{
-	struct mei_cl_cb *pos;
-	struct mei_cl_cb *next;
-
-	list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) {
-		if (pos->file_private) {
-			struct mei_cl *cl_tmp;
-			cl_tmp = (struct mei_cl *)pos->file_private;
-			if (mei_cl_cmp_id(cl, cl_tmp))
-				list_del(&pos->cb_list);
-		}
-	}
-}
-/**
- * mei_cl_flush_queues - flushes queue lists belonging to cl.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- */
-int mei_cl_flush_queues(struct mei_cl *cl)
-{
-	if (!cl || !cl->dev)
-		return -EINVAL;
-
-	dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
-	mei_io_list_flush(&cl->dev->read_list, cl);
-	mei_io_list_flush(&cl->dev->write_list, cl);
-	mei_io_list_flush(&cl->dev->write_waiting_list, cl);
-	mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
-	mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
-	mei_io_list_flush(&cl->dev->amthi_cmd_list, cl);
-	mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl);
-	return 0;
-}
-
-
-
-/**
- * mei_reset_iamthif_params - initializes mei device iamthif
- *
- * @dev: the device structure
- */
-static void mei_reset_iamthif_params(struct mei_device *dev)
-{
-	/* reset iamthif parameters. */
-	dev->iamthif_current_cb = NULL;
-	dev->iamthif_msg_buf_size = 0;
-	dev->iamthif_msg_buf_index = 0;
-	dev->iamthif_canceled = false;
-	dev->iamthif_ioctl = false;
-	dev->iamthif_state = MEI_IAMTHIF_IDLE;
-	dev->iamthif_timer = 0;
-}
-
-/**
- * init_mei_device - allocates and initializes the mei device structure
- *
- * @pdev: The pci device structure
- *
- * returns The mei_device_device pointer on success, NULL on failure.
- */
-struct mei_device *mei_device_init(struct pci_dev *pdev)
-{
-	struct mei_device *dev;
-
-	dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL);
-	if (!dev)
-		return NULL;
-
-	/* setup our list array */
-	INIT_LIST_HEAD(&dev->file_list);
-	INIT_LIST_HEAD(&dev->wd_cl.link);
-	INIT_LIST_HEAD(&dev->iamthif_cl.link);
-	mutex_init(&dev->device_lock);
-	init_waitqueue_head(&dev->wait_recvd_msg);
-	init_waitqueue_head(&dev->wait_stop_wd);
-	dev->mei_state = MEI_INITIALIZING;
-	dev->iamthif_state = MEI_IAMTHIF_IDLE;
-	dev->wd_interface_reg = false;
-
-
-	mei_io_list_init(&dev->read_list);
-	mei_io_list_init(&dev->write_list);
-	mei_io_list_init(&dev->write_waiting_list);
-	mei_io_list_init(&dev->ctrl_wr_list);
-	mei_io_list_init(&dev->ctrl_rd_list);
-	mei_io_list_init(&dev->amthi_cmd_list);
-	mei_io_list_init(&dev->amthi_read_complete_list);
-	dev->pdev = pdev;
-	return dev;
-}
-
-/**
- * mei_hw_init - initializes host and fw to start work.
- *
- * @dev: the device structure
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_hw_init(struct mei_device *dev)
-{
-	int err = 0;
-	int ret;
-
-	mutex_lock(&dev->device_lock);
-
-	dev->host_hw_state = mei_hcsr_read(dev);
-	dev->me_hw_state = mei_mecsr_read(dev);
-	dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n",
-	    dev->host_hw_state, dev->me_hw_state);
-
-	/* acknowledge interrupt and stop interupts */
-	if ((dev->host_hw_state & H_IS) == H_IS)
-		mei_reg_write(dev, H_CSR, dev->host_hw_state);
-
-	dev->recvd_msg = false;
-	dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
-
-	mei_reset(dev, 1);
-
-	dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
-	    dev->host_hw_state, dev->me_hw_state);
-
-	/* wait for ME to turn on ME_RDY */
-	if (!dev->recvd_msg) {
-		mutex_unlock(&dev->device_lock);
-		err = wait_event_interruptible_timeout(dev->wait_recvd_msg,
-			dev->recvd_msg, MEI_INTEROP_TIMEOUT);
-		mutex_lock(&dev->device_lock);
-	}
-
-	if (err <= 0 && !dev->recvd_msg) {
-		dev->mei_state = MEI_DISABLED;
-		dev_dbg(&dev->pdev->dev,
-			"wait_event_interruptible_timeout failed"
-			"on wait for ME to turn on ME_RDY.\n");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
-	      ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
-		dev->mei_state = MEI_DISABLED;
-		dev_dbg(&dev->pdev->dev,
-			"host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
-			dev->host_hw_state, dev->me_hw_state);
-
-		if (!(dev->host_hw_state & H_RDY))
-			dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n");
-
-		if (!(dev->me_hw_state & ME_RDY_HRA))
-			dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
-
-		printk(KERN_ERR "mei: link layer initialization failed.\n");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	if (dev->version.major_version != HBM_MAJOR_VERSION ||
-	    dev->version.minor_version != HBM_MINOR_VERSION) {
-		dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	dev->recvd_msg = false;
-	dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
-	    dev->host_hw_state, dev->me_hw_state);
-	dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n");
-	dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
-	dev_dbg(&dev->pdev->dev, "MEI  start success.\n");
-	ret = 0;
-
-out:
-	mutex_unlock(&dev->device_lock);
-	return ret;
-}
-
-/**
- * mei_hw_reset - resets fw via mei csr register.
- *
- * @dev: the device structure
- * @interrupts_enabled: if interrupt should be enabled after reset.
- */
-static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled)
-{
-	dev->host_hw_state |= (H_RST | H_IG);
-
-	if (interrupts_enabled)
-		mei_enable_interrupts(dev);
-	else
-		mei_disable_interrupts(dev);
-}
-
-/**
- * mei_reset - resets host and fw.
- *
- * @dev: the device structure
- * @interrupts_enabled: if interrupt should be enabled after reset.
- */
-void mei_reset(struct mei_device *dev, int interrupts_enabled)
-{
-	struct mei_cl *cl_pos = NULL;
-	struct mei_cl *cl_next = NULL;
-	struct mei_cl_cb *cb_pos = NULL;
-	struct mei_cl_cb *cb_next = NULL;
-	bool unexpected;
-
-	if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
-		dev->need_reset = true;
-		return;
-	}
-
-	unexpected = (dev->mei_state != MEI_INITIALIZING &&
-			dev->mei_state != MEI_DISABLED &&
-			dev->mei_state != MEI_POWER_DOWN &&
-			dev->mei_state != MEI_POWER_UP);
-
-	dev->host_hw_state = mei_hcsr_read(dev);
-
-	dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n",
-	    dev->host_hw_state);
-
-	mei_hw_reset(dev, interrupts_enabled);
-
-	dev->host_hw_state &= ~H_RST;
-	dev->host_hw_state |= H_IG;
-
-	mei_hcsr_set(dev);
-
-	dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n",
-	    dev->host_hw_state);
-
-	dev->need_reset = false;
-
-	if (dev->mei_state != MEI_INITIALIZING) {
-		if (dev->mei_state != MEI_DISABLED &&
-		    dev->mei_state != MEI_POWER_DOWN)
-			dev->mei_state = MEI_RESETING;
-
-		list_for_each_entry_safe(cl_pos,
-				cl_next, &dev->file_list, link) {
-			cl_pos->state = MEI_FILE_DISCONNECTED;
-			cl_pos->mei_flow_ctrl_creds = 0;
-			cl_pos->read_cb = NULL;
-			cl_pos->timer_count = 0;
-		}
-		/* remove entry if already in list */
-		dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n");
-		mei_remove_client_from_file_list(dev,
-				dev->wd_cl.host_client_id);
-
-		mei_remove_client_from_file_list(dev,
-				dev->iamthif_cl.host_client_id);
-
-		mei_reset_iamthif_params(dev);
-		dev->wd_due_counter = 0;
-		dev->extra_write_index = 0;
-	}
-
-	dev->me_clients_num = 0;
-	dev->rd_msg_hdr = 0;
-	dev->stop = false;
-	dev->wd_pending = false;
-
-	/* update the state of the registers after reset */
-	dev->host_hw_state = mei_hcsr_read(dev);
-	dev->me_hw_state = mei_mecsr_read(dev);
-
-	dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
-	    dev->host_hw_state, dev->me_hw_state);
-
-	if (unexpected)
-		dev_warn(&dev->pdev->dev, "unexpected reset.\n");
-
-	/* Wake up all readings so they can be interrupted */
-	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-		if (waitqueue_active(&cl_pos->rx_wait)) {
-			dev_dbg(&dev->pdev->dev, "Waking up client!\n");
-			wake_up_interruptible(&cl_pos->rx_wait);
-		}
-	}
-	/* remove all waiting requests */
-	list_for_each_entry_safe(cb_pos, cb_next,
-			&dev->write_list.mei_cb.cb_list, cb_list) {
-		list_del(&cb_pos->cb_list);
-		mei_free_cb_private(cb_pos);
-	}
-}
-
-
-
-/**
- * host_start_message - mei host sends start message.
- *
- * @dev: the device structure
- *
- * returns none.
- */
-void mei_host_start_message(struct mei_device *dev)
-{
-	struct mei_msg_hdr *mei_hdr;
-	struct hbm_host_version_request *host_start_req;
-
-	/* host start message */
-	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-	mei_hdr->host_addr = 0;
-	mei_hdr->me_addr = 0;
-	mei_hdr->length = sizeof(struct hbm_host_version_request);
-	mei_hdr->msg_complete = 1;
-	mei_hdr->reserved = 0;
-
-	host_start_req =
-	    (struct hbm_host_version_request *) &dev->wr_msg_buf[1];
-	memset(host_start_req, 0, sizeof(struct hbm_host_version_request));
-	host_start_req->hbm_cmd = HOST_START_REQ_CMD;
-	host_start_req->host_version.major_version = HBM_MAJOR_VERSION;
-	host_start_req->host_version.minor_version = HBM_MINOR_VERSION;
-	dev->recvd_msg = false;
-	if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
-				       mei_hdr->length)) {
-		dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
-		dev->mei_state = MEI_RESETING;
-		mei_reset(dev, 1);
-	}
-	dev->init_clients_state = MEI_START_MESSAGE;
-	dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
-	return ;
-}
-
-/**
- * host_enum_clients_message - host sends enumeration client request message.
- *
- * @dev: the device structure
- *
- * returns none.
- */
-void mei_host_enum_clients_message(struct mei_device *dev)
-{
-	struct mei_msg_hdr *mei_hdr;
-	struct hbm_host_enum_request *host_enum_req;
-	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-	/* enumerate clients */
-	mei_hdr->host_addr = 0;
-	mei_hdr->me_addr = 0;
-	mei_hdr->length = sizeof(struct hbm_host_enum_request);
-	mei_hdr->msg_complete = 1;
-	mei_hdr->reserved = 0;
-
-	host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
-	memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request));
-	host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
-	if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
-				mei_hdr->length)) {
-		dev->mei_state = MEI_RESETING;
-		dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
-		mei_reset(dev, 1);
-	}
-	dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
-	dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
-	return;
-}
-
-
-/**
- * allocate_me_clients_storage - allocates storage for me clients
- *
- * @dev: the device structure
- *
- * returns none.
- */
-void mei_allocate_me_clients_storage(struct mei_device *dev)
-{
-	struct mei_me_client *clients;
-	int b;
-
-	/* count how many ME clients we have */
-	for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
-		dev->me_clients_num++;
-
-	if (dev->me_clients_num <= 0)
-		return ;
-
-
-	if (dev->me_clients != NULL) {
-		kfree(dev->me_clients);
-		dev->me_clients = NULL;
-	}
-	dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
-		dev->me_clients_num * sizeof(struct mei_me_client));
-	/* allocate storage for ME clients representation */
-	clients = kcalloc(dev->me_clients_num,
-			sizeof(struct mei_me_client), GFP_KERNEL);
-	if (!clients) {
-		dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
-		dev->mei_state = MEI_RESETING;
-		mei_reset(dev, 1);
-		return ;
-	}
-	dev->me_clients = clients;
-	return ;
-}
-/**
- * host_client_properties - reads properties for client
- *
- * @dev: the device structure
- *
- * returns:
- * 	< 0 - Error.
- *  = 0 - no more clients.
- *  = 1 - still have clients to send properties request.
- */
-int mei_host_client_properties(struct mei_device *dev)
-{
-	struct mei_msg_hdr *mei_header;
-	struct hbm_props_request *host_cli_req;
-	int b;
-	u8 client_num = dev->me_client_presentation_num;
-
-	b = dev->me_client_index;
-	b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b);
-	if (b < MEI_CLIENTS_MAX) {
-		dev->me_clients[client_num].client_id = b;
-		dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
-		mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
-		mei_header->host_addr = 0;
-		mei_header->me_addr = 0;
-		mei_header->length = sizeof(struct hbm_props_request);
-		mei_header->msg_complete = 1;
-		mei_header->reserved = 0;
-
-		host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1];
-
-		memset(host_cli_req, 0, sizeof(struct hbm_props_request));
-
-		host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
-		host_cli_req->address = b;
-
-		if (mei_write_message(dev, mei_header,
-				(unsigned char *)host_cli_req,
-				mei_header->length)) {
-			dev->mei_state = MEI_RESETING;
-			dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
-			mei_reset(dev, 1);
-			return -EIO;
-		}
-
-		dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
-		dev->me_client_index = b;
-		return 1;
-	}
-
-	return 0;
-}
-
-/**
- * mei_init_file_private - initializes private file structure.
- *
- * @priv: private file structure to be initialized
- * @file: the file structure
- */
-void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
-{
-	memset(priv, 0, sizeof(struct mei_cl));
-	init_waitqueue_head(&priv->wait);
-	init_waitqueue_head(&priv->rx_wait);
-	init_waitqueue_head(&priv->tx_wait);
-	INIT_LIST_HEAD(&priv->link);
-	priv->reading_state = MEI_IDLE;
-	priv->writing_state = MEI_IDLE;
-	priv->dev = dev;
-}
-
-int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
-{
-	int i, res = -1;
-
-	for (i = 0; i < dev->me_clients_num; ++i)
-		if (uuid_le_cmp(cuuid,
-				dev->me_clients[i].props.protocol_name) == 0) {
-			res = i;
-			break;
-		}
-
-	return res;
-}
-
-
-/**
- * mei_find_me_client_update_filext - searches for ME client guid
- *                       sets client_id in mei_file_private if found
- * @dev: the device structure
- * @priv: private file structure to set client_id in
- * @cguid: searched guid of ME client
- * @client_id: id of host client to be set in file private structure
- *
- * returns ME client index
- */
-u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
-				const uuid_le *cguid, u8 client_id)
-{
-	int i;
-
-	if (!dev || !priv || !cguid)
-		return 0;
-
-	/* check for valid client id */
-	i = mei_find_me_client_index(dev, *cguid);
-	if (i >= 0) {
-		priv->me_client_id = dev->me_clients[i].client_id;
-		priv->state = MEI_FILE_CONNECTING;
-		priv->host_client_id = client_id;
-
-		list_add_tail(&priv->link, &dev->file_list);
-		return (u8)i;
-	}
-
-	return 0;
-}
-
-/**
- * host_init_iamthif - mei initialization iamthif client.
- *
- * @dev: the device structure
- *
- */
-void mei_host_init_iamthif(struct mei_device *dev)
-{
-	u8 i;
-	unsigned char *msg_buf;
-
-	mei_cl_init(&dev->iamthif_cl, dev);
-	dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
-
-	/* find ME amthi client */
-	i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl,
-			    &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
-	if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
-		dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
-		return;
-	}
-
-	/* Assign iamthif_mtu to the value received from ME  */
-
-	dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
-	dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
-			dev->me_clients[i].props.max_msg_length);
-
-	kfree(dev->iamthif_msg_buf);
-	dev->iamthif_msg_buf = NULL;
-
-	/* allocate storage for ME message buffer */
-	msg_buf = kcalloc(dev->iamthif_mtu,
-			sizeof(unsigned char), GFP_KERNEL);
-	if (!msg_buf) {
-		dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n");
-		return;
-	}
-
-	dev->iamthif_msg_buf = msg_buf;
-
-	if (mei_connect(dev, &dev->iamthif_cl)) {
-		dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n");
-		dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
-		dev->iamthif_cl.host_client_id = 0;
-	} else {
-		dev->iamthif_cl.timer_count = CONNECT_TIMEOUT;
-	}
-}
-
-/**
- * mei_alloc_file_private - allocates a private file structure and sets it up.
- * @file: the file structure
- *
- * returns  The allocated file or NULL on failure
- */
-struct mei_cl *mei_cl_allocate(struct mei_device *dev)
-{
-	struct mei_cl *cl;
-
-	cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
-	if (!cl)
-		return NULL;
-
-	mei_cl_init(cl, dev);
-
-	return cl;
-}
-
-
-
-/**
- * mei_disconnect_host_client - sends disconnect message to fw from host client.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * Locking: called under "dev->device_lock" lock
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
-{
-	int rets, err;
-	long timeout = 15;	/* 15 seconds */
-	struct mei_cl_cb *cb;
-
-	if (!dev || !cl)
-		return -ENODEV;
-
-	if (cl->state != MEI_FILE_DISCONNECTING)
-		return 0;
-
-	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
-	if (!cb)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&cb->cb_list);
-	cb->file_private = cl;
-	cb->major_file_operations = MEI_CLOSE;
-	if (dev->mei_host_buffer_is_empty) {
-		dev->mei_host_buffer_is_empty = false;
-		if (mei_disconnect(dev, cl)) {
-			rets = -ENODEV;
-			dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n");
-			goto free;
-		}
-		mdelay(10); /* Wait for hardware disconnection ready */
-		list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list);
-	} else {
-		dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
-		list_add_tail(&cb->cb_list,
-				&dev->ctrl_wr_list.mei_cb.cb_list);
-	}
-	mutex_unlock(&dev->device_lock);
-
-	err = wait_event_timeout(dev->wait_recvd_msg,
-		 (MEI_FILE_DISCONNECTED == cl->state),
-		 timeout * HZ);
-
-	mutex_lock(&dev->device_lock);
-	if (MEI_FILE_DISCONNECTED == cl->state) {
-		rets = 0;
-		dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
-	} else {
-		rets = -ENODEV;
-		if (MEI_FILE_DISCONNECTED != cl->state)
-			dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
-
-		if (err)
-			dev_dbg(&dev->pdev->dev,
-					"wait failed disconnect err=%08x\n",
-					err);
-
-		dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
-	}
-
-	mei_io_list_flush(&dev->ctrl_rd_list, cl);
-	mei_io_list_flush(&dev->ctrl_wr_list, cl);
-free:
-	mei_free_cb_private(cb);
-	return rets;
-}
-
-/**
- * mei_remove_client_from_file_list -
- *	removes file private data from device file list
- *
- * @dev: the device structure
- * @host_client_id: host client id to be removed
- */
-void mei_remove_client_from_file_list(struct mei_device *dev,
-				       u8 host_client_id)
-{
-	struct mei_cl *cl_pos = NULL;
-	struct mei_cl *cl_next = NULL;
-	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-		if (host_client_id == cl_pos->host_client_id) {
-			dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
-					cl_pos->host_client_id,
-					cl_pos->me_client_id);
-			list_del_init(&cl_pos->link);
-			break;
-		}
-	}
-}
diff --git a/drivers/staging/mei/interface.c b/drivers/staging/mei/interface.c
deleted file mode 100644
index 9a2cfaf..0000000
--- a/drivers/staging/mei/interface.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, 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.
- *
- */
-
-#include <linux/pci.h>
-#include "mei_dev.h"
-#include "mei.h"
-#include "interface.h"
-
-
-
-/**
- * mei_set_csr_register - writes H_CSR register to the mei device,
- * and ignores the H_IS bit for it is write-one-to-zero.
- *
- * @dev: the device structure
- */
-void mei_hcsr_set(struct mei_device *dev)
-{
-	if ((dev->host_hw_state & H_IS) == H_IS)
-		dev->host_hw_state &= ~H_IS;
-	mei_reg_write(dev, H_CSR, dev->host_hw_state);
-	dev->host_hw_state = mei_hcsr_read(dev);
-}
-
-/**
- * mei_csr_enable_interrupts - enables mei device interrupts
- *
- * @dev: the device structure
- */
-void mei_enable_interrupts(struct mei_device *dev)
-{
-	dev->host_hw_state |= H_IE;
-	mei_hcsr_set(dev);
-}
-
-/**
- * mei_csr_disable_interrupts - disables mei device interrupts
- *
- * @dev: the device structure
- */
-void mei_disable_interrupts(struct mei_device *dev)
-{
-	dev->host_hw_state &= ~H_IE;
-	mei_hcsr_set(dev);
-}
-
-/**
- * _host_get_filled_slots - gets number of device filled buffer slots
- *
- * @device: the device structure
- *
- * returns number of filled slots
- */
-static unsigned char _host_get_filled_slots(const struct mei_device *dev)
-{
-	char read_ptr, write_ptr;
-
-	read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8);
-	write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16);
-
-	return (unsigned char) (write_ptr - read_ptr);
-}
-
-/**
- * mei_host_buffer_is_empty - checks if host buffer is empty.
- *
- * @dev: the device structure
- *
- * returns 1 if empty, 0 - otherwise.
- */
-int mei_host_buffer_is_empty(struct mei_device *dev)
-{
-	unsigned char filled_slots;
-
-	dev->host_hw_state = mei_hcsr_read(dev);
-	filled_slots = _host_get_filled_slots(dev);
-
-	if (filled_slots == 0)
-		return 1;
-
-	return 0;
-}
-
-/**
- * mei_count_empty_write_slots - counts write empty slots.
- *
- * @dev: the device structure
- *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
- */
-int mei_count_empty_write_slots(struct mei_device *dev)
-{
-	unsigned char buffer_depth, filled_slots, empty_slots;
-
-	dev->host_hw_state = mei_hcsr_read(dev);
-	buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
-	filled_slots = _host_get_filled_slots(dev);
-	empty_slots = buffer_depth - filled_slots;
-
-	/* check for overflow */
-	if (filled_slots > buffer_depth)
-		return -EOVERFLOW;
-
-	return empty_slots;
-}
-
-/**
- * mei_write_message - writes a message to mei device.
- *
- * @dev: the device structure
- * @header: header of message
- * @write_buffer: message buffer will be written
- * @write_length: message size will be written
- *
- * This function returns -EIO if write has failed
- */
-int mei_write_message(struct mei_device *dev,
-		      struct mei_msg_hdr *header,
-		      unsigned char *write_buffer,
-		      unsigned long write_length)
-{
-	u32 temp_msg = 0;
-	unsigned long bytes_written = 0;
-	unsigned char buffer_depth, filled_slots, empty_slots;
-	unsigned long dw_to_write;
-
-	dev->host_hw_state = mei_hcsr_read(dev);
-
-	dev_dbg(&dev->pdev->dev,
-			"host_hw_state = 0x%08x.\n",
-			dev->host_hw_state);
-
-	dev_dbg(&dev->pdev->dev,
-			"mei_write_message header=%08x.\n",
-			*((u32 *) header));
-
-	buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
-	filled_slots = _host_get_filled_slots(dev);
-	empty_slots = buffer_depth - filled_slots;
-	dev_dbg(&dev->pdev->dev,
-			"filled = %hu, empty = %hu.\n",
-			filled_slots, empty_slots);
-
-	dw_to_write = ((write_length + 3) / 4);
-
-	if (dw_to_write > empty_slots)
-		return -EIO;
-
-	mei_reg_write(dev, H_CB_WW, *((u32 *) header));
-
-	while (write_length >= 4) {
-		mei_reg_write(dev, H_CB_WW,
-				*(u32 *) (write_buffer + bytes_written));
-		bytes_written += 4;
-		write_length -= 4;
-	}
-
-	if (write_length > 0) {
-		memcpy(&temp_msg, &write_buffer[bytes_written], write_length);
-		mei_reg_write(dev, H_CB_WW, temp_msg);
-	}
-
-	dev->host_hw_state |= H_IG;
-	mei_hcsr_set(dev);
-	dev->me_hw_state = mei_mecsr_read(dev);
-	if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
-		return -EIO;
-
-	return 0;
-}
-
-/**
- * mei_count_full_read_slots - counts read full slots.
- *
- * @dev: the device structure
- *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
- */
-int mei_count_full_read_slots(struct mei_device *dev)
-{
-	char read_ptr, write_ptr;
-	unsigned char buffer_depth, filled_slots;
-
-	dev->me_hw_state = mei_mecsr_read(dev);
-	buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24);
-	read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8);
-	write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16);
-	filled_slots = (unsigned char) (write_ptr - read_ptr);
-
-	/* check for overflow */
-	if (filled_slots > buffer_depth)
-		return -EOVERFLOW;
-
-	dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
-	return (int)filled_slots;
-}
-
-/**
- * mei_read_slots - reads a message from mei device.
- *
- * @dev: the device structure
- * @buffer: message buffer will be written
- * @buffer_length: message size will be read
- */
-void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
-		    unsigned long buffer_length)
-{
-	u32 *reg_buf = (u32 *)buffer;
-
-	for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
-		*reg_buf++ = mei_mecbrw_read(dev);
-
-	if (buffer_length > 0) {
-		u32 reg = mei_mecbrw_read(dev);
-		memcpy(reg_buf, &reg, buffer_length);
-	}
-
-	dev->host_hw_state |= H_IG;
-	mei_hcsr_set(dev);
-}
-
-/**
- * mei_flow_ctrl_creds - checks flow_control credentials.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
- *	-ENOENT if mei_cl is not present
- *	-EINVAL if single_recv_buf == 0
- */
-int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
-{
-	int i;
-
-	if (!dev->me_clients_num)
-		return 0;
-
-	if (cl->mei_flow_ctrl_creds > 0)
-		return 1;
-
-	for (i = 0; i < dev->me_clients_num; i++) {
-		struct mei_me_client  *me_cl = &dev->me_clients[i];
-		if (me_cl->client_id == cl->me_client_id) {
-			if (me_cl->mei_flow_ctrl_creds) {
-				if (WARN_ON(me_cl->props.single_recv_buf == 0))
-					return -EINVAL;
-				return 1;
-			} else {
-				return 0;
-			}
-		}
-	}
-	return -ENOENT;
-}
-
-/**
- * mei_flow_ctrl_reduce - reduces flow_control.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- * @returns
- *	0 on success
- *	-ENOENT when me client is not found
- *	-EINVAL when ctrl credits are <= 0
- */
-int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
-{
-	int i;
-
-	if (!dev->me_clients_num)
-		return -ENOENT;
-
-	for (i = 0; i < dev->me_clients_num; i++) {
-		struct mei_me_client  *me_cl = &dev->me_clients[i];
-		if (me_cl->client_id == cl->me_client_id) {
-			if (me_cl->props.single_recv_buf != 0) {
-				if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
-					return -EINVAL;
-				dev->me_clients[i].mei_flow_ctrl_creds--;
-			} else {
-				if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
-					return -EINVAL;
-				cl->mei_flow_ctrl_creds--;
-			}
-			return 0;
-		}
-	}
-	return -ENOENT;
-}
-
-/**
- * mei_send_flow_control - sends flow control to fw.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * This function returns -EIO on write failure
- */
-int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
-{
-	struct mei_msg_hdr *mei_hdr;
-	struct hbm_flow_control *mei_flow_control;
-
-	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-	mei_hdr->host_addr = 0;
-	mei_hdr->me_addr = 0;
-	mei_hdr->length = sizeof(struct hbm_flow_control);
-	mei_hdr->msg_complete = 1;
-	mei_hdr->reserved = 0;
-
-	mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
-	memset(mei_flow_control, 0, sizeof(*mei_flow_control));
-	mei_flow_control->host_addr = cl->host_client_id;
-	mei_flow_control->me_addr = cl->me_client_id;
-	mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD;
-	memset(mei_flow_control->reserved, 0,
-			sizeof(mei_flow_control->reserved));
-	dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
-		cl->host_client_id, cl->me_client_id);
-
-	return mei_write_message(dev, mei_hdr,
-				(unsigned char *) mei_flow_control,
-				sizeof(struct hbm_flow_control));
-}
-
-/**
- * mei_other_client_is_connecting - checks if other
- *    client with the same client id is connected.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * returns 1 if other client is connected, 0 - otherwise.
- */
-int mei_other_client_is_connecting(struct mei_device *dev,
-				struct mei_cl *cl)
-{
-	struct mei_cl *cl_pos = NULL;
-	struct mei_cl *cl_next = NULL;
-
-	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-		if ((cl_pos->state == MEI_FILE_CONNECTING) &&
-			(cl_pos != cl) &&
-			cl->me_client_id == cl_pos->me_client_id)
-			return 1;
-
-	}
-	return 0;
-}
-
-/**
- * mei_disconnect - sends disconnect message to fw.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * This function returns -EIO on write failure
- */
-int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
-{
-	struct mei_msg_hdr *mei_hdr;
-	struct hbm_client_disconnect_request *mei_cli_disconnect;
-
-	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-	mei_hdr->host_addr = 0;
-	mei_hdr->me_addr = 0;
-	mei_hdr->length = sizeof(struct hbm_client_disconnect_request);
-	mei_hdr->msg_complete = 1;
-	mei_hdr->reserved = 0;
-
-	mei_cli_disconnect =
-	    (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1];
-	memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect));
-	mei_cli_disconnect->host_addr = cl->host_client_id;
-	mei_cli_disconnect->me_addr = cl->me_client_id;
-	mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD;
-	mei_cli_disconnect->reserved[0] = 0;
-
-	return mei_write_message(dev, mei_hdr,
-				(unsigned char *) mei_cli_disconnect,
-				sizeof(struct hbm_client_disconnect_request));
-}
-
-/**
- * mei_connect - sends connect message to fw.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * This function returns -EIO on write failure
- */
-int mei_connect(struct mei_device *dev, struct mei_cl *cl)
-{
-	struct mei_msg_hdr *mei_hdr;
-	struct hbm_client_connect_request *mei_cli_connect;
-
-	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-	mei_hdr->host_addr = 0;
-	mei_hdr->me_addr = 0;
-	mei_hdr->length = sizeof(struct hbm_client_connect_request);
-	mei_hdr->msg_complete = 1;
-	mei_hdr->reserved = 0;
-
-	mei_cli_connect =
-	    (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
-	mei_cli_connect->host_addr = cl->host_client_id;
-	mei_cli_connect->me_addr = cl->me_client_id;
-	mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD;
-	mei_cli_connect->reserved = 0;
-
-	return mei_write_message(dev, mei_hdr,
-				(unsigned char *) mei_cli_connect,
-				sizeof(struct hbm_client_connect_request));
-}
diff --git a/drivers/staging/mei/interface.h b/drivers/staging/mei/interface.h
deleted file mode 100644
index fb90c6f..0000000
--- a/drivers/staging/mei/interface.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, 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.
- *
- */
-
-
-
-#ifndef _MEI_INTERFACE_H_
-#define _MEI_INTERFACE_H_
-
-#include "mei.h"
-#include "mei_dev.h"
-
-
-#define AMT_WD_DEFAULT_TIMEOUT 120	/* seconds */
-#define AMT_WD_MIN_TIMEOUT 120	/* seconds */
-#define AMT_WD_MAX_TIMEOUT 65535	/* seconds */
-
-#define MEI_WATCHDOG_DATA_SIZE         16
-#define MEI_START_WD_DATA_SIZE         20
-#define MEI_WD_PARAMS_SIZE             4
-
-
-void mei_read_slots(struct mei_device *dev,
-		     unsigned char *buffer,
-		     unsigned long buffer_length);
-
-int mei_write_message(struct mei_device *dev,
-			     struct mei_msg_hdr *header,
-			     unsigned char *write_buffer,
-			     unsigned long write_length);
-
-int mei_host_buffer_is_empty(struct mei_device *dev);
-
-int mei_count_full_read_slots(struct mei_device *dev);
-
-int mei_count_empty_write_slots(struct mei_device *dev);
-
-int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
-
-int mei_wd_send(struct mei_device *dev);
-int mei_wd_stop(struct mei_device *dev, bool preserve);
-bool mei_wd_host_init(struct mei_device *dev);
-void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout);
-/*
- * mei_watchdog_register  - Registering watchdog interface
- *   once we got connection to the WD Client
- * @dev - mei device
- */
-void mei_watchdog_register(struct mei_device *dev);
-/*
- * mei_watchdog_unregister  - Unregistering watchdog interface
- * @dev - mei device
- */
-void mei_watchdog_unregister(struct mei_device *dev);
-
-int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl);
-
-int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl);
-
-int mei_disconnect(struct mei_device *dev, struct mei_cl *cl);
-int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl);
-int mei_connect(struct mei_device *dev, struct mei_cl *cl);
-
-#endif /* _MEI_INTERFACE_H_ */
diff --git a/drivers/staging/mei/interrupt.c b/drivers/staging/mei/interrupt.c
deleted file mode 100644
index 2007d24..0000000
--- a/drivers/staging/mei/interrupt.c
+++ /dev/null
@@ -1,1590 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, 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.
- *
- */
-
-
-#include <linux/pci.h>
-#include <linux/kthread.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/jiffies.h>
-
-#include "mei_dev.h"
-#include "mei.h"
-#include "hw.h"
-#include "interface.h"
-
-
-/**
- * mei_interrupt_quick_handler - The ISR of the MEI device
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * returns irqreturn_t
- */
-irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
-{
-	struct mei_device *dev = (struct mei_device *) dev_id;
-	u32 csr_reg = mei_hcsr_read(dev);
-
-	if ((csr_reg & H_IS) != H_IS)
-		return IRQ_NONE;
-
-	/* clear H_IS bit in H_CSR */
-	mei_reg_write(dev, H_CSR, csr_reg);
-
-	return IRQ_WAKE_THREAD;
-}
-
-/**
- * _mei_cmpl - processes completed operation.
- *
- * @cl: private data of the file object.
- * @cb_pos: callback block.
- */
-static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
-{
-	if (cb_pos->major_file_operations == MEI_WRITE) {
-		mei_free_cb_private(cb_pos);
-		cb_pos = NULL;
-		cl->writing_state = MEI_WRITE_COMPLETE;
-		if (waitqueue_active(&cl->tx_wait))
-			wake_up_interruptible(&cl->tx_wait);
-
-	} else if (cb_pos->major_file_operations == MEI_READ &&
-			MEI_READING == cl->reading_state) {
-		cl->reading_state = MEI_READ_COMPLETE;
-		if (waitqueue_active(&cl->rx_wait))
-			wake_up_interruptible(&cl->rx_wait);
-
-	}
-}
-
-/**
- * _mei_cmpl_iamthif - processes completed iamthif operation.
- *
- * @dev: the device structure.
- * @cb_pos: callback block.
- */
-static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos)
-{
-	if (dev->iamthif_canceled != 1) {
-		dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
-		dev->iamthif_stall_timer = 0;
-		memcpy(cb_pos->response_buffer.data,
-				dev->iamthif_msg_buf,
-				dev->iamthif_msg_buf_index);
-		list_add_tail(&cb_pos->cb_list,
-				&dev->amthi_read_complete_list.mei_cb.cb_list);
-		dev_dbg(&dev->pdev->dev, "amthi read completed.\n");
-		dev->iamthif_timer = jiffies;
-		dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
-				dev->iamthif_timer);
-	} else {
-		mei_run_next_iamthif_cmd(dev);
-	}
-
-	dev_dbg(&dev->pdev->dev, "completing amthi call back.\n");
-	wake_up_interruptible(&dev->iamthif_cl.wait);
-}
-
-
-/**
- * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to
- * handle the read amthi message data processing.
- *
- * @complete_list: An instance of our list structure
- * @dev: the device structure
- * @mei_hdr: header of amthi message
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list,
-		struct mei_device *dev,
-		struct mei_msg_hdr *mei_hdr)
-{
-	struct mei_cl *cl;
-	struct mei_cl_cb *cb;
-	unsigned char *buffer;
-
-	BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
-	BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
-
-	buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
-	BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
-
-	mei_read_slots(dev, buffer, mei_hdr->length);
-
-	dev->iamthif_msg_buf_index += mei_hdr->length;
-
-	if (!mei_hdr->msg_complete)
-		return 0;
-
-	dev_dbg(&dev->pdev->dev,
-			"amthi_message_buffer_index =%d\n",
-			mei_hdr->length);
-
-	dev_dbg(&dev->pdev->dev, "completed amthi read.\n ");
-	if (!dev->iamthif_current_cb)
-		return -ENODEV;
-
-	cb = dev->iamthif_current_cb;
-	dev->iamthif_current_cb = NULL;
-
-	cl = (struct mei_cl *)cb->file_private;
-	if (!cl)
-		return -ENODEV;
-
-	dev->iamthif_stall_timer = 0;
-	cb->information =	dev->iamthif_msg_buf_index;
-	cb->read_time = jiffies;
-	if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) {
-		/* found the iamthif cb */
-		dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n ");
-		dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n ");
-		list_add_tail(&cb->cb_list,
-						&complete_list->mei_cb.cb_list);
-	}
-	return 0;
-}
-
-/**
- * _mei_irq_thread_state_ok - checks if mei header matches file private data
- *
- * @cl: private data of the file object
- * @mei_hdr: header of mei client message
- *
- * returns !=0 if matches, 0 if no match.
- */
-static int _mei_irq_thread_state_ok(struct mei_cl *cl,
-				struct mei_msg_hdr *mei_hdr)
-{
-	return (cl->host_client_id == mei_hdr->host_addr &&
-		cl->me_client_id == mei_hdr->me_addr &&
-		cl->state == MEI_FILE_CONNECTED &&
-		MEI_READ_COMPLETE != cl->reading_state);
-}
-
-/**
- * mei_irq_thread_read_client_message - bottom half read routine after ISR to
- * handle the read mei client message data processing.
- *
- * @complete_list: An instance of our list structure
- * @dev: the device structure
- * @mei_hdr: header of mei client message
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
-		struct mei_device *dev,
-		struct mei_msg_hdr *mei_hdr)
-{
-	struct mei_cl *cl;
-	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
-	unsigned char *buffer = NULL;
-
-	dev_dbg(&dev->pdev->dev, "start client msg\n");
-	if (list_empty(&dev->read_list.mei_cb.cb_list))
-		goto quit;
-
-	list_for_each_entry_safe(cb_pos, cb_next,
-			&dev->read_list.mei_cb.cb_list, cb_list) {
-		cl = (struct mei_cl *)cb_pos->file_private;
-		if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
-			cl->reading_state = MEI_READING;
-			buffer = cb_pos->response_buffer.data + cb_pos->information;
-
-			if (cb_pos->response_buffer.size <
-					mei_hdr->length + cb_pos->information) {
-				dev_dbg(&dev->pdev->dev, "message overflow.\n");
-				list_del(&cb_pos->cb_list);
-				return -ENOMEM;
-			}
-			if (buffer)
-				mei_read_slots(dev, buffer, mei_hdr->length);
-
-			cb_pos->information += mei_hdr->length;
-			if (mei_hdr->msg_complete) {
-				cl->status = 0;
-				list_del(&cb_pos->cb_list);
-				dev_dbg(&dev->pdev->dev,
-					"completed read host client = %d,"
-					"ME client = %d, "
-					"data length = %lu\n",
-					cl->host_client_id,
-					cl->me_client_id,
-					cb_pos->information);
-
-				*(cb_pos->response_buffer.data +
-					cb_pos->information) = '\0';
-				dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n",
-					cb_pos->response_buffer.data);
-				list_add_tail(&cb_pos->cb_list,
-					&complete_list->mei_cb.cb_list);
-			}
-
-			break;
-		}
-
-	}
-
-quit:
-	dev_dbg(&dev->pdev->dev, "message read\n");
-	if (!buffer) {
-		mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
-		dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
-				*(u32 *) dev->rd_msg_buf);
-	}
-
-	return 0;
-}
-
-/**
- * _mei_irq_thread_iamthif_read - prepares to read iamthif data.
- *
- * @dev: the device structure.
- * @slots: free slots.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots)
-{
-
-	if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
-			+ sizeof(struct hbm_flow_control))) {
-		return -EMSGSIZE;
-	}
-	*slots -= (sizeof(struct mei_msg_hdr) +
-				sizeof(struct hbm_flow_control) + 3) / 4;
-	if (mei_send_flow_control(dev, &dev->iamthif_cl)) {
-		dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
-		return -EIO;
-	}
-
-	dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
-	dev->iamthif_state = MEI_IAMTHIF_READING;
-	dev->iamthif_flow_control_pending = false;
-	dev->iamthif_msg_buf_index = 0;
-	dev->iamthif_msg_buf_size = 0;
-	dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
-	dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
-	return 0;
-}
-
-/**
- * _mei_irq_thread_close - processes close related operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
-				struct mei_cl_cb *cb_pos,
-				struct mei_cl *cl,
-				struct mei_io_list *cmpl_list)
-{
-	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-			sizeof(struct hbm_client_disconnect_request))) {
-		*slots -= (sizeof(struct mei_msg_hdr) +
-			sizeof(struct hbm_client_disconnect_request) + 3) / 4;
-
-		if (mei_disconnect(dev, cl)) {
-			cl->status = 0;
-			cb_pos->information = 0;
-			list_move_tail(&cb_pos->cb_list,
-					&cmpl_list->mei_cb.cb_list);
-			return -EMSGSIZE;
-		} else {
-			cl->state = MEI_FILE_DISCONNECTING;
-			cl->status = 0;
-			cb_pos->information = 0;
-			list_move_tail(&cb_pos->cb_list,
-					&dev->ctrl_rd_list.mei_cb.cb_list);
-			cl->timer_count = MEI_CONNECT_TIMEOUT;
-		}
-	} else {
-		/* return the cancel routine */
-		return -EBADMSG;
-	}
-
-	return 0;
-}
-
-/**
- * is_treat_specially_client - checks if the message belongs
- * to the file private data.
- *
- * @cl: private data of the file object
- * @rs: connect response bus message
- *
- */
-static bool is_treat_specially_client(struct mei_cl *cl,
-		struct hbm_client_connect_response *rs)
-{
-
-	if (cl->host_client_id == rs->host_addr &&
-	    cl->me_client_id == rs->me_addr) {
-		if (!rs->status) {
-			cl->state = MEI_FILE_CONNECTED;
-			cl->status = 0;
-
-		} else {
-			cl->state = MEI_FILE_DISCONNECTED;
-			cl->status = -ENODEV;
-		}
-		cl->timer_count = 0;
-
-		return true;
-	}
-	return false;
-}
-
-/**
- * mei_client_connect_response - connects to response irq routine
- *
- * @dev: the device structure
- * @rs: connect response bus message
- */
-static void mei_client_connect_response(struct mei_device *dev,
-		struct hbm_client_connect_response *rs)
-{
-
-	struct mei_cl *cl;
-	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
-
-	dev_dbg(&dev->pdev->dev,
-			"connect_response:\n"
-			"ME Client = %d\n"
-			"Host Client = %d\n"
-			"Status = %d\n",
-			rs->me_addr,
-			rs->host_addr,
-			rs->status);
-
-	/* if WD or iamthif client treat specially */
-
-	if (is_treat_specially_client(&(dev->wd_cl), rs)) {
-		dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
-		mei_watchdog_register(dev);
-
-		/* next step in the state maching */
-		mei_host_init_iamthif(dev);
-		return;
-	}
-
-	if (is_treat_specially_client(&(dev->iamthif_cl), rs)) {
-		dev->iamthif_state = MEI_IAMTHIF_IDLE;
-		return;
-	}
-	list_for_each_entry_safe(cb_pos, cb_next,
-				&dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
-
-		cl = (struct mei_cl *)cb_pos->file_private;
-		if (!cl) {
-			list_del(&cb_pos->cb_list);
-			return;
-		}
-		if (MEI_IOCTL == cb_pos->major_file_operations) {
-			if (is_treat_specially_client(cl, rs)) {
-				list_del(&cb_pos->cb_list);
-				cl->status = 0;
-				cl->timer_count = 0;
-				break;
-			}
-		}
-	}
-}
-
-/**
- * mei_client_disconnect_response - disconnects from response irq routine
- *
- * @dev: the device structure
- * @rs: disconnect response bus message
- */
-static void mei_client_disconnect_response(struct mei_device *dev,
-					struct hbm_client_connect_response *rs)
-{
-	struct mei_cl *cl;
-	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
-
-	dev_dbg(&dev->pdev->dev,
-			"disconnect_response:\n"
-			"ME Client = %d\n"
-			"Host Client = %d\n"
-			"Status = %d\n",
-			rs->me_addr,
-			rs->host_addr,
-			rs->status);
-
-	list_for_each_entry_safe(cb_pos, cb_next,
-			&dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
-		cl = (struct mei_cl *)cb_pos->file_private;
-
-		if (!cl) {
-			list_del(&cb_pos->cb_list);
-			return;
-		}
-
-		dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
-		if (cl->host_client_id == rs->host_addr &&
-		    cl->me_client_id == rs->me_addr) {
-
-			list_del(&cb_pos->cb_list);
-			if (!rs->status)
-				cl->state = MEI_FILE_DISCONNECTED;
-
-			cl->status = 0;
-			cl->timer_count = 0;
-			break;
-		}
-	}
-}
-
-/**
- * same_flow_addr - tells if they have the same address.
- *
- * @file: private data of the file object.
- * @flow: flow control.
- *
- * returns  !=0, same; 0,not.
- */
-static int same_flow_addr(struct mei_cl *cl, struct hbm_flow_control *flow)
-{
-	return (cl->host_client_id == flow->host_addr &&
-		cl->me_client_id == flow->me_addr);
-}
-
-/**
- * add_single_flow_creds - adds single buffer credentials.
- *
- * @file: private data ot the file object.
- * @flow: flow control.
- */
-static void add_single_flow_creds(struct mei_device *dev,
-				  struct hbm_flow_control *flow)
-{
-	struct mei_me_client *client;
-	int i;
-
-	for (i = 0; i < dev->me_clients_num; i++) {
-		client = &dev->me_clients[i];
-		if (client && flow->me_addr == client->client_id) {
-			if (client->props.single_recv_buf) {
-				client->mei_flow_ctrl_creds++;
-				dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
-				    flow->me_addr);
-				dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
-				    client->mei_flow_ctrl_creds);
-			} else {
-				BUG();	/* error in flow control */
-			}
-		}
-	}
-}
-
-/**
- * mei_client_flow_control_response - flow control response irq routine
- *
- * @dev: the device structure
- * @flow_control: flow control response bus message
- */
-static void mei_client_flow_control_response(struct mei_device *dev,
-		struct hbm_flow_control *flow_control)
-{
-	struct mei_cl *cl_pos = NULL;
-	struct mei_cl *cl_next = NULL;
-
-	if (!flow_control->host_addr) {
-		/* single receive buffer */
-		add_single_flow_creds(dev, flow_control);
-	} else {
-		/* normal connection */
-		list_for_each_entry_safe(cl_pos, cl_next,
-				&dev->file_list, link) {
-			dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in file_list\n");
-
-			dev_dbg(&dev->pdev->dev, "cl of host client %d ME client %d.\n",
-			    cl_pos->host_client_id,
-			    cl_pos->me_client_id);
-			dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
-			    flow_control->host_addr,
-			    flow_control->me_addr);
-			if (same_flow_addr(cl_pos, flow_control)) {
-				dev_dbg(&dev->pdev->dev, "recv ctrl msg for host  %d ME %d.\n",
-				    flow_control->host_addr,
-				    flow_control->me_addr);
-				cl_pos->mei_flow_ctrl_creds++;
-				dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
-				    cl_pos->mei_flow_ctrl_creds);
-				break;
-			}
-		}
-	}
-}
-
-/**
- * same_disconn_addr - tells if they have the same address
- *
- * @file: private data of the file object.
- * @disconn: disconnection request.
- *
- * returns !=0, same; 0,not.
- */
-static int same_disconn_addr(struct mei_cl *cl,
-			     struct hbm_client_disconnect_request *disconn)
-{
-	return (cl->host_client_id == disconn->host_addr &&
-		cl->me_client_id == disconn->me_addr);
-}
-
-/**
- * mei_client_disconnect_request - disconnects from request irq routine
- *
- * @dev: the device structure.
- * @disconnect_req: disconnect request bus message.
- */
-static void mei_client_disconnect_request(struct mei_device *dev,
-		struct hbm_client_disconnect_request *disconnect_req)
-{
-	struct mei_msg_hdr *mei_hdr;
-	struct hbm_client_connect_response *disconnect_res;
-	struct mei_cl *cl_pos = NULL;
-	struct mei_cl *cl_next = NULL;
-
-	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-		if (same_disconn_addr(cl_pos, disconnect_req)) {
-			dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
-					disconnect_req->host_addr,
-					disconnect_req->me_addr);
-			cl_pos->state = MEI_FILE_DISCONNECTED;
-			cl_pos->timer_count = 0;
-			if (cl_pos == &dev->wd_cl) {
-				dev->wd_due_counter = 0;
-				dev->wd_pending = false;
-			} else if (cl_pos == &dev->iamthif_cl)
-				dev->iamthif_timer = 0;
-
-			/* prepare disconnect response */
-			mei_hdr =
-				(struct mei_msg_hdr *) &dev->ext_msg_buf[0];
-			mei_hdr->host_addr = 0;
-			mei_hdr->me_addr = 0;
-			mei_hdr->length =
-				sizeof(struct hbm_client_connect_response);
-			mei_hdr->msg_complete = 1;
-			mei_hdr->reserved = 0;
-
-			disconnect_res =
-				(struct hbm_client_connect_response *)
-				&dev->ext_msg_buf[1];
-			disconnect_res->host_addr = cl_pos->host_client_id;
-			disconnect_res->me_addr = cl_pos->me_client_id;
-			disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
-			disconnect_res->status = 0;
-			dev->extra_write_index = 2;
-			break;
-		}
-	}
-}
-
-
-/**
- * mei_irq_thread_read_bus_message - bottom half read routine after ISR to
- * handle the read bus message cmd processing.
- *
- * @dev: the device structure
- * @mei_hdr: header of bus message
- */
-static void mei_irq_thread_read_bus_message(struct mei_device *dev,
-		struct mei_msg_hdr *mei_hdr)
-{
-	struct mei_bus_message *mei_msg;
-	struct hbm_host_version_response *version_res;
-	struct hbm_client_connect_response *connect_res;
-	struct hbm_client_connect_response *disconnect_res;
-	struct hbm_flow_control *flow_control;
-	struct hbm_props_response *props_res;
-	struct hbm_host_enum_response *enum_res;
-	struct hbm_client_disconnect_request *disconnect_req;
-	struct hbm_host_stop_request *host_stop_req;
-	int res;
-
-
-	/* read the message to our buffer */
-	BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
-	mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
-	mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
-
-	switch (mei_msg->hbm_cmd) {
-	case HOST_START_RES_CMD:
-		version_res = (struct hbm_host_version_response *) mei_msg;
-		if (version_res->host_version_supported) {
-			dev->version.major_version = HBM_MAJOR_VERSION;
-			dev->version.minor_version = HBM_MINOR_VERSION;
-			if (dev->mei_state == MEI_INIT_CLIENTS &&
-			    dev->init_clients_state == MEI_START_MESSAGE) {
-				dev->init_clients_timer = 0;
-				mei_host_enum_clients_message(dev);
-			} else {
-				dev->recvd_msg = false;
-				dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
-				mei_reset(dev, 1);
-				return;
-			}
-		} else {
-			dev->version = version_res->me_max_version;
-			/* send stop message */
-			mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
-			mei_hdr->host_addr = 0;
-			mei_hdr->me_addr = 0;
-			mei_hdr->length = sizeof(struct hbm_host_stop_request);
-			mei_hdr->msg_complete = 1;
-			mei_hdr->reserved = 0;
-
-			host_stop_req = (struct hbm_host_stop_request *)
-							&dev->wr_msg_buf[1];
-
-			memset(host_stop_req,
-					0,
-					sizeof(struct hbm_host_stop_request));
-			host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
-			host_stop_req->reason = DRIVER_STOP_REQUEST;
-			mei_write_message(dev, mei_hdr,
-					   (unsigned char *) (host_stop_req),
-					   mei_hdr->length);
-			dev_dbg(&dev->pdev->dev, "version mismatch.\n");
-			return;
-		}
-
-		dev->recvd_msg = true;
-		dev_dbg(&dev->pdev->dev, "host start response message received.\n");
-		break;
-
-	case CLIENT_CONNECT_RES_CMD:
-		connect_res =
-			(struct hbm_client_connect_response *) mei_msg;
-		mei_client_connect_response(dev, connect_res);
-		dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
-		wake_up(&dev->wait_recvd_msg);
-		break;
-
-	case CLIENT_DISCONNECT_RES_CMD:
-		disconnect_res =
-			(struct hbm_client_connect_response *) mei_msg;
-		mei_client_disconnect_response(dev, disconnect_res);
-		dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
-		wake_up(&dev->wait_recvd_msg);
-		break;
-
-	case MEI_FLOW_CONTROL_CMD:
-		flow_control = (struct hbm_flow_control *) mei_msg;
-		mei_client_flow_control_response(dev, flow_control);
-		dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
-		break;
-
-	case HOST_CLIENT_PROPERTIES_RES_CMD:
-		props_res = (struct hbm_props_response *)mei_msg;
-		if (props_res->status || !dev->me_clients) {
-			dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
-			mei_reset(dev, 1);
-			return;
-		}
-		if (dev->me_clients[dev->me_client_presentation_num]
-					.client_id == props_res->address) {
-
-			dev->me_clients[dev->me_client_presentation_num].props
-						= props_res->client_properties;
-
-			if (dev->mei_state == MEI_INIT_CLIENTS &&
-			    dev->init_clients_state ==
-					MEI_CLIENT_PROPERTIES_MESSAGE) {
-				dev->me_client_index++;
-				dev->me_client_presentation_num++;
-
-				/** Send Client Properties request **/
-				res = mei_host_client_properties(dev);
-				if (res < 0) {
-					dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed");
-					return;
-				} else if (!res) {
-					/*
-					 * No more clients to send to.
-					 * Clear Map for indicating now ME clients
-					 * with associated host client
-					 */
-					bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
-					dev->open_handle_count = 0;
-
-					/*
-					 * Reserving the first three client IDs
-					 * Client Id 0 - Reserved for MEI Bus Message communications
-					 * Client Id 1 - Reserved for Watchdog
-					 * Client ID 2 - Reserved for AMTHI
-					 */
-					bitmap_set(dev->host_clients_map, 0, 3);
-					dev->mei_state = MEI_ENABLED;
-
-					/* if wd initialization fails, initialization the AMTHI client,
-					 * otherwise the AMTHI client will be initialized after the WD client connect response
-					 * will be received
-					 */
-					if (mei_wd_host_init(dev))
-						mei_host_init_iamthif(dev);
-				}
-
-			} else {
-				dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message");
-				mei_reset(dev, 1);
-				return;
-			}
-		} else {
-			dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n");
-			mei_reset(dev, 1);
-			return;
-		}
-		break;
-
-	case HOST_ENUM_RES_CMD:
-		enum_res = (struct hbm_host_enum_response *) mei_msg;
-		memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
-		if (dev->mei_state == MEI_INIT_CLIENTS &&
-		    dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
-				dev->init_clients_timer = 0;
-				dev->me_client_presentation_num = 0;
-				dev->me_client_index = 0;
-				mei_allocate_me_clients_storage(dev);
-				dev->init_clients_state =
-					MEI_CLIENT_PROPERTIES_MESSAGE;
-				mei_host_client_properties(dev);
-		} else {
-			dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
-			mei_reset(dev, 1);
-			return;
-		}
-		break;
-
-	case HOST_STOP_RES_CMD:
-		dev->mei_state = MEI_DISABLED;
-		dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
-		mei_reset(dev, 1);
-		break;
-
-	case CLIENT_DISCONNECT_REQ_CMD:
-		/* search for client */
-		disconnect_req =
-			(struct hbm_client_disconnect_request *) mei_msg;
-		mei_client_disconnect_request(dev, disconnect_req);
-		break;
-
-	case ME_STOP_REQ_CMD:
-		/* prepare stop request */
-		mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
-		mei_hdr->host_addr = 0;
-		mei_hdr->me_addr = 0;
-		mei_hdr->length = sizeof(struct hbm_host_stop_request);
-		mei_hdr->msg_complete = 1;
-		mei_hdr->reserved = 0;
-		host_stop_req =
-			(struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
-		memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request));
-		host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
-		host_stop_req->reason = DRIVER_STOP_REQUEST;
-		host_stop_req->reserved[0] = 0;
-		host_stop_req->reserved[1] = 0;
-		dev->extra_write_index = 2;
-		break;
-
-	default:
-		BUG();
-		break;
-
-	}
-}
-
-
-/**
- * _mei_hb_read - processes read related operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_read(struct mei_device *dev,	s32 *slots,
-			struct mei_cl_cb *cb_pos,
-			struct mei_cl *cl,
-			struct mei_io_list *cmpl_list)
-{
-	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-			sizeof(struct hbm_flow_control))) {
-		/* return the cancel routine */
-		list_del(&cb_pos->cb_list);
-		return -EBADMSG;
-	}
-
-	*slots -= (sizeof(struct mei_msg_hdr) +
-			sizeof(struct hbm_flow_control) + 3) / 4;
-	if (mei_send_flow_control(dev, cl)) {
-		cl->status = -ENODEV;
-		cb_pos->information = 0;
-		list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list);
-		return -ENODEV;
-	}
-	list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list);
-
-	return 0;
-}
-
-
-/**
- * _mei_irq_thread_ioctl - processes ioctl related operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
-			struct mei_cl_cb *cb_pos,
-			struct mei_cl *cl,
-			struct mei_io_list *cmpl_list)
-{
-	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-			sizeof(struct hbm_client_connect_request))) {
-		cl->state = MEI_FILE_CONNECTING;
-		*slots -= (sizeof(struct mei_msg_hdr) +
-			sizeof(struct hbm_client_connect_request) + 3) / 4;
-		if (mei_connect(dev, cl)) {
-			cl->status = -ENODEV;
-			cb_pos->information = 0;
-			list_del(&cb_pos->cb_list);
-			return -ENODEV;
-		} else {
-			list_move_tail(&cb_pos->cb_list,
-				&dev->ctrl_rd_list.mei_cb.cb_list);
-			cl->timer_count = MEI_CONNECT_TIMEOUT;
-		}
-	} else {
-		/* return the cancel routine */
-		list_del(&cb_pos->cb_list);
-		return -EBADMSG;
-	}
-
-	return 0;
-}
-
-/**
- * _mei_irq_thread_cmpl - processes completed and no-iamthif operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_cmpl(struct mei_device *dev,	s32 *slots,
-			struct mei_cl_cb *cb_pos,
-			struct mei_cl *cl,
-			struct mei_io_list *cmpl_list)
-{
-	struct mei_msg_hdr *mei_hdr;
-
-	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-			(cb_pos->request_buffer.size -
-			cb_pos->information))) {
-		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-		mei_hdr->host_addr = cl->host_client_id;
-		mei_hdr->me_addr = cl->me_client_id;
-		mei_hdr->length = cb_pos->request_buffer.size -
-					cb_pos->information;
-		mei_hdr->msg_complete = 1;
-		mei_hdr->reserved = 0;
-		dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d"
-			"mei_hdr->msg_complete = %d\n",
-				cb_pos->request_buffer.size,
-				mei_hdr->msg_complete);
-		dev_dbg(&dev->pdev->dev, "cb_pos->information  =%lu\n",
-				cb_pos->information);
-		dev_dbg(&dev->pdev->dev, "mei_hdr->length  =%d\n",
-				mei_hdr->length);
-		*slots -= (sizeof(struct mei_msg_hdr) +
-				mei_hdr->length + 3) / 4;
-		if (mei_write_message(dev, mei_hdr,
-				(unsigned char *)
-				(cb_pos->request_buffer.data +
-				cb_pos->information),
-				mei_hdr->length)) {
-			cl->status = -ENODEV;
-			list_move_tail(&cb_pos->cb_list,
-				&cmpl_list->mei_cb.cb_list);
-			return -ENODEV;
-		} else {
-			if (mei_flow_ctrl_reduce(dev, cl))
-				return -ENODEV;
-			cl->status = 0;
-			cb_pos->information += mei_hdr->length;
-			list_move_tail(&cb_pos->cb_list,
-				&dev->write_waiting_list.mei_cb.cb_list);
-		}
-	} else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
-		/* buffer is still empty */
-		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-		mei_hdr->host_addr = cl->host_client_id;
-		mei_hdr->me_addr = cl->me_client_id;
-		mei_hdr->length =
-			(*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
-		mei_hdr->msg_complete = 0;
-		mei_hdr->reserved = 0;
-
-		(*slots) -= (sizeof(struct mei_msg_hdr) +
-				mei_hdr->length + 3) / 4;
-		if (mei_write_message(dev, mei_hdr,
-					(unsigned char *)
-					(cb_pos->request_buffer.data +
-					cb_pos->information),
-					mei_hdr->length)) {
-			cl->status = -ENODEV;
-			list_move_tail(&cb_pos->cb_list,
-				&cmpl_list->mei_cb.cb_list);
-			return -ENODEV;
-		} else {
-			cb_pos->information += mei_hdr->length;
-			dev_dbg(&dev->pdev->dev,
-					"cb_pos->request_buffer.size =%d"
-					" mei_hdr->msg_complete = %d\n",
-					cb_pos->request_buffer.size,
-					mei_hdr->msg_complete);
-			dev_dbg(&dev->pdev->dev, "cb_pos->information  =%lu\n",
-					cb_pos->information);
-			dev_dbg(&dev->pdev->dev, "mei_hdr->length  =%d\n",
-					mei_hdr->length);
-		}
-		return -EMSGSIZE;
-	} else {
-		return -EBADMSG;
-	}
-
-	return 0;
-}
-
-/**
- * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots,
-			struct mei_cl_cb *cb_pos,
-			struct mei_cl *cl,
-			struct mei_io_list *cmpl_list)
-{
-	struct mei_msg_hdr *mei_hdr;
-
-	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-			dev->iamthif_msg_buf_size -
-			dev->iamthif_msg_buf_index)) {
-		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-		mei_hdr->host_addr = cl->host_client_id;
-		mei_hdr->me_addr = cl->me_client_id;
-		mei_hdr->length = dev->iamthif_msg_buf_size -
-			dev->iamthif_msg_buf_index;
-		mei_hdr->msg_complete = 1;
-		mei_hdr->reserved = 0;
-
-		*slots -= (sizeof(struct mei_msg_hdr) +
-				mei_hdr->length + 3) / 4;
-
-		if (mei_write_message(dev, mei_hdr,
-					(dev->iamthif_msg_buf +
-					dev->iamthif_msg_buf_index),
-					mei_hdr->length)) {
-			dev->iamthif_state = MEI_IAMTHIF_IDLE;
-			cl->status = -ENODEV;
-			list_del(&cb_pos->cb_list);
-			return -ENODEV;
-		} else {
-			if (mei_flow_ctrl_reduce(dev, cl))
-				return -ENODEV;
-			dev->iamthif_msg_buf_index += mei_hdr->length;
-			cb_pos->information = dev->iamthif_msg_buf_index;
-			cl->status = 0;
-			dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
-			dev->iamthif_flow_control_pending = true;
-			/* save iamthif cb sent to amthi client */
-			dev->iamthif_current_cb = cb_pos;
-			list_move_tail(&cb_pos->cb_list,
-				&dev->write_waiting_list.mei_cb.cb_list);
-
-		}
-	} else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
-			/* buffer is still empty */
-		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-		mei_hdr->host_addr = cl->host_client_id;
-		mei_hdr->me_addr = cl->me_client_id;
-		mei_hdr->length =
-			(*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
-		mei_hdr->msg_complete = 0;
-		mei_hdr->reserved = 0;
-
-		*slots -= (sizeof(struct mei_msg_hdr) +
-				mei_hdr->length + 3) / 4;
-
-		if (mei_write_message(dev, mei_hdr,
-					(dev->iamthif_msg_buf +
-					dev->iamthif_msg_buf_index),
-					mei_hdr->length)) {
-			cl->status = -ENODEV;
-			list_del(&cb_pos->cb_list);
-		} else {
-			dev->iamthif_msg_buf_index += mei_hdr->length;
-		}
-		return -EMSGSIZE;
-	} else {
-		return -EBADMSG;
-	}
-
-	return 0;
-}
-
-/**
- * mei_irq_thread_read_handler - bottom half read routine after ISR to
- * handle the read processing.
- *
- * @cmpl_list: An instance of our list structure
- * @dev: the device structure
- * @slots: slots to read.
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list,
-		struct mei_device *dev,
-		s32 *slots)
-{
-	struct mei_msg_hdr *mei_hdr;
-	struct mei_cl *cl_pos = NULL;
-	struct mei_cl *cl_next = NULL;
-	int ret = 0;
-
-	if (!dev->rd_msg_hdr) {
-		dev->rd_msg_hdr = mei_mecbrw_read(dev);
-		dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
-		(*slots)--;
-		dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
-	}
-	mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
-	dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length);
-
-	if (mei_hdr->reserved || !dev->rd_msg_hdr) {
-		dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
-		ret = -EBADMSG;
-		goto end;
-	}
-
-	if (mei_hdr->host_addr || mei_hdr->me_addr) {
-		list_for_each_entry_safe(cl_pos, cl_next,
-					&dev->file_list, link) {
-			dev_dbg(&dev->pdev->dev,
-					"list_for_each_entry_safe read host"
-					" client = %d, ME client = %d\n",
-					cl_pos->host_client_id,
-					cl_pos->me_client_id);
-			if (cl_pos->host_client_id == mei_hdr->host_addr &&
-			    cl_pos->me_client_id == mei_hdr->me_addr)
-				break;
-		}
-
-		if (&cl_pos->link == &dev->file_list) {
-			dev_dbg(&dev->pdev->dev, "corrupted message header\n");
-			ret = -EBADMSG;
-			goto end;
-		}
-	}
-	if (((*slots) * sizeof(u32)) < mei_hdr->length) {
-		dev_dbg(&dev->pdev->dev,
-				"we can't read the message slots =%08x.\n",
-				*slots);
-		/* we can't read the message */
-		ret = -ERANGE;
-		goto end;
-	}
-
-	/* decide where to read the message too */
-	if (!mei_hdr->host_addr) {
-		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
-		mei_irq_thread_read_bus_message(dev, mei_hdr);
-		dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
-	} else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
-		   (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
-		   (dev->iamthif_state == MEI_IAMTHIF_READING)) {
-		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
-		dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
-				mei_hdr->length);
-		ret = mei_irq_thread_read_amthi_message(cmpl_list,
-							dev, mei_hdr);
-		if (ret)
-			goto end;
-
-	} else {
-		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
-		ret = mei_irq_thread_read_client_message(cmpl_list,
-							 dev, mei_hdr);
-		if (ret)
-			goto end;
-
-	}
-
-	/* reset the number of slots and header */
-	*slots = mei_count_full_read_slots(dev);
-	dev->rd_msg_hdr = 0;
-
-	if (*slots == -EOVERFLOW) {
-		/* overflow - reset */
-		dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
-		/* set the event since message has been read */
-		ret = -ERANGE;
-		goto end;
-	}
-end:
-	return ret;
-}
-
-
-/**
- * mei_irq_thread_write_handler - bottom half write routine after
- * ISR to handle the write processing.
- *
- * @cmpl_list: An instance of our list structure
- * @dev: the device structure
- * @slots: slots to write.
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
-		struct mei_device *dev,
-		s32 *slots)
-{
-
-	struct mei_cl *cl;
-	struct mei_cl_cb *pos = NULL, *next = NULL;
-	struct mei_io_list *list;
-	int ret;
-
-	if (!mei_host_buffer_is_empty(dev)) {
-		dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
-		return 0;
-	}
-	*slots = mei_count_empty_write_slots(dev);
-	/* complete all waiting for write CB */
-	dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
-
-	list = &dev->write_waiting_list;
-	list_for_each_entry_safe(pos, next,
-			&list->mei_cb.cb_list, cb_list) {
-		cl = (struct mei_cl *)pos->file_private;
-		if (cl == NULL)
-			continue;
-
-		cl->status = 0;
-		list_del(&pos->cb_list);
-		if (MEI_WRITING == cl->writing_state &&
-		   (pos->major_file_operations == MEI_WRITE) &&
-		   (cl != &dev->iamthif_cl)) {
-			dev_dbg(&dev->pdev->dev,
-				"MEI WRITE COMPLETE\n");
-			cl->writing_state = MEI_WRITE_COMPLETE;
-			list_add_tail(&pos->cb_list,
-				&cmpl_list->mei_cb.cb_list);
-		}
-		if (cl == &dev->iamthif_cl) {
-			dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n");
-			if (dev->iamthif_flow_control_pending) {
-				ret = _mei_irq_thread_iamthif_read(
-						dev, slots);
-				if (ret)
-					return ret;
-			}
-		}
-	}
-
-	if (dev->stop && !dev->wd_pending) {
-		dev->wd_stopped = true;
-		wake_up_interruptible(&dev->wait_stop_wd);
-		return 0;
-	}
-
-	if (dev->extra_write_index) {
-		dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n",
-				dev->extra_write_index);
-		mei_write_message(dev,
-				(struct mei_msg_hdr *) &dev->ext_msg_buf[0],
-				(unsigned char *) &dev->ext_msg_buf[1],
-				(dev->extra_write_index - 1) * sizeof(u32));
-		*slots -= dev->extra_write_index;
-		dev->extra_write_index = 0;
-	}
-	if (dev->mei_state == MEI_ENABLED) {
-		if (dev->wd_pending &&
-			mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
-			if (mei_wd_send(dev))
-				dev_dbg(&dev->pdev->dev, "wd send failed.\n");
-			else
-				if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
-					return -ENODEV;
-
-			dev->wd_pending = false;
-
-			if (dev->wd_timeout) {
-				*slots -= (sizeof(struct mei_msg_hdr) +
-					 MEI_START_WD_DATA_SIZE + 3) / 4;
-				dev->wd_due_counter = 2;
-			} else {
-				*slots -= (sizeof(struct mei_msg_hdr) +
-					 MEI_WD_PARAMS_SIZE + 3) / 4;
-				dev->wd_due_counter = 0;
-			}
-
-		}
-	}
-	if (dev->stop)
-		return -ENODEV;
-
-	/* complete control write list CB */
-	dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
-	list_for_each_entry_safe(pos, next,
-				&dev->ctrl_wr_list.mei_cb.cb_list, cb_list) {
-		cl = (struct mei_cl *) pos->file_private;
-		if (!cl) {
-			list_del(&pos->cb_list);
-			return -ENODEV;
-		}
-		switch (pos->major_file_operations) {
-		case MEI_CLOSE:
-			/* send disconnect message */
-			ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list);
-			if (ret)
-				return ret;
-
-			break;
-		case MEI_READ:
-			/* send flow control message */
-			ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list);
-			if (ret)
-				return ret;
-
-			break;
-		case MEI_IOCTL:
-			/* connect message */
-			if (mei_other_client_is_connecting(dev, cl))
-				continue;
-			ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list);
-			if (ret)
-				return ret;
-
-			break;
-
-		default:
-			BUG();
-		}
-
-	}
-	/* complete  write list CB */
-	dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
-	list_for_each_entry_safe(pos, next,
-			&dev->write_list.mei_cb.cb_list, cb_list) {
-		cl = (struct mei_cl *)pos->file_private;
-		if (cl == NULL)
-			continue;
-
-		if (cl != &dev->iamthif_cl) {
-			if (!mei_flow_ctrl_creds(dev, cl)) {
-				dev_dbg(&dev->pdev->dev,
-					"No flow control"
-				    " credentials for client"
-				    " %d, not sending.\n",
-				    cl->host_client_id);
-				continue;
-			}
-			ret = _mei_irq_thread_cmpl(dev, slots,
-					    pos,
-					    cl, cmpl_list);
-			if (ret)
-				return ret;
-
-		} else if (cl == &dev->iamthif_cl) {
-			/* IAMTHIF IOCTL */
-			dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n");
-			if (!mei_flow_ctrl_creds(dev, cl)) {
-				dev_dbg(&dev->pdev->dev,
-					"No flow control"
-				    " credentials for amthi"
-				    " client %d.\n",
-				    cl->host_client_id);
-				continue;
-			}
-			ret = _mei_irq_thread_cmpl_iamthif(dev,
-						slots,
-						pos,
-						cl,
-						cmpl_list);
-			if (ret)
-				return ret;
-
-		}
-
-	}
-	return 0;
-}
-
-
-
-/**
- * mei_timer - timer function.
- *
- * @work: pointer to the work_struct structure
- *
- * NOTE: This function is called by timer interrupt work
- */
-void mei_timer(struct work_struct *work)
-{
-	unsigned long timeout;
-	struct mei_cl *cl_pos = NULL;
-	struct mei_cl *cl_next = NULL;
-	struct list_head *amthi_complete_list = NULL;
-	struct mei_cl_cb  *cb_pos = NULL;
-	struct mei_cl_cb  *cb_next = NULL;
-
-	struct mei_device *dev = container_of(work,
-					struct mei_device, timer_work.work);
-
-
-	mutex_lock(&dev->device_lock);
-	if (dev->mei_state != MEI_ENABLED) {
-		if (dev->mei_state == MEI_INIT_CLIENTS) {
-			if (dev->init_clients_timer) {
-				if (--dev->init_clients_timer == 0) {
-					dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
-						dev->init_clients_state);
-					mei_reset(dev, 1);
-				}
-			}
-		}
-		goto out;
-	}
-	/*** connect/disconnect timeouts ***/
-	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-		if (cl_pos->timer_count) {
-			if (--cl_pos->timer_count == 0) {
-				dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
-				mei_reset(dev, 1);
-				goto out;
-			}
-		}
-	}
-
-	if (dev->iamthif_stall_timer) {
-		if (--dev->iamthif_stall_timer == 0) {
-			dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
-			mei_reset(dev, 1);
-			dev->iamthif_msg_buf_size = 0;
-			dev->iamthif_msg_buf_index = 0;
-			dev->iamthif_canceled = false;
-			dev->iamthif_ioctl = true;
-			dev->iamthif_state = MEI_IAMTHIF_IDLE;
-			dev->iamthif_timer = 0;
-
-			if (dev->iamthif_current_cb)
-				mei_free_cb_private(dev->iamthif_current_cb);
-
-			dev->iamthif_file_object = NULL;
-			dev->iamthif_current_cb = NULL;
-			mei_run_next_iamthif_cmd(dev);
-		}
-	}
-
-	if (dev->iamthif_timer) {
-
-		timeout = dev->iamthif_timer +
-				msecs_to_jiffies(IAMTHIF_READ_TIMER);
-
-		dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
-				dev->iamthif_timer);
-		dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
-		dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
-		if (time_after(jiffies, timeout)) {
-			/*
-			 * User didn't read the AMTHI data on time (15sec)
-			 * freeing AMTHI for other requests
-			 */
-
-			dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
-
-			amthi_complete_list = &dev->amthi_read_complete_list.
-					mei_cb.cb_list;
-
-			list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) {
-
-				cl_pos = cb_pos->file_object->private_data;
-
-				/* Finding the AMTHI entry. */
-				if (cl_pos == &dev->iamthif_cl)
-					list_del(&cb_pos->cb_list);
-			}
-			if (dev->iamthif_current_cb)
-				mei_free_cb_private(dev->iamthif_current_cb);
-
-			dev->iamthif_file_object->private_data = NULL;
-			dev->iamthif_file_object = NULL;
-			dev->iamthif_current_cb = NULL;
-			dev->iamthif_timer = 0;
-			mei_run_next_iamthif_cmd(dev);
-
-		}
-	}
-out:
-	schedule_delayed_work(&dev->timer_work, 2 * HZ);
-	mutex_unlock(&dev->device_lock);
-}
-
-/**
- *  mei_interrupt_thread_handler - function called after ISR to handle the interrupt
- * processing.
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * returns irqreturn_t
- *
- */
-irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
-{
-	struct mei_device *dev = (struct mei_device *) dev_id;
-	struct mei_io_list complete_list;
-	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
-	struct mei_cl *cl;
-	s32 slots;
-	int rets;
-	bool  bus_message_received;
-
-
-	dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
-	/* initialize our complete list */
-	mutex_lock(&dev->device_lock);
-	mei_io_list_init(&complete_list);
-	dev->host_hw_state = mei_hcsr_read(dev);
-
-	/* Ack the interrupt here
-	 * In case of MSI we don't go through the quick handler */
-	if (pci_dev_msi_enabled(dev->pdev))
-		mei_reg_write(dev, H_CSR, dev->host_hw_state);
-
-	dev->me_hw_state = mei_mecsr_read(dev);
-
-	/* check if ME wants a reset */
-	if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
-	    dev->mei_state != MEI_RESETING &&
-	    dev->mei_state != MEI_INITIALIZING) {
-		dev_dbg(&dev->pdev->dev, "FW not ready.\n");
-		mei_reset(dev, 1);
-		mutex_unlock(&dev->device_lock);
-		return IRQ_HANDLED;
-	}
-
-	/*  check if we need to start the dev */
-	if ((dev->host_hw_state & H_RDY) == 0) {
-		if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
-			dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
-			dev->host_hw_state |= (H_IE | H_IG | H_RDY);
-			mei_hcsr_set(dev);
-			dev->mei_state = MEI_INIT_CLIENTS;
-			dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
-			/* link is established
-			 * start sending messages.
-			 */
-			mei_host_start_message(dev);
-			mutex_unlock(&dev->device_lock);
-			return IRQ_HANDLED;
-		} else {
-			dev_dbg(&dev->pdev->dev, "FW not ready.\n");
-			mutex_unlock(&dev->device_lock);
-			return IRQ_HANDLED;
-		}
-	}
-	/* check slots available for reading */
-	slots = mei_count_full_read_slots(dev);
-	dev_dbg(&dev->pdev->dev, "slots =%08x  extra_write_index =%08x.\n",
-		slots, dev->extra_write_index);
-	while (slots > 0 && !dev->extra_write_index) {
-		dev_dbg(&dev->pdev->dev, "slots =%08x  extra_write_index =%08x.\n",
-				slots, dev->extra_write_index);
-		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
-		rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
-		if (rets)
-			goto end;
-	}
-	rets = mei_irq_thread_write_handler(&complete_list, dev, &slots);
-end:
-	dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
-	dev->host_hw_state = mei_hcsr_read(dev);
-	dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
-
-	bus_message_received = false;
-	if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
-		dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
-		bus_message_received = true;
-	}
-	mutex_unlock(&dev->device_lock);
-	if (bus_message_received) {
-		dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
-		wake_up_interruptible(&dev->wait_recvd_msg);
-		bus_message_received = false;
-	}
-	if (list_empty(&complete_list.mei_cb.cb_list))
-		return IRQ_HANDLED;
-
-
-	list_for_each_entry_safe(cb_pos, cb_next,
-			&complete_list.mei_cb.cb_list, cb_list) {
-		cl = (struct mei_cl *)cb_pos->file_private;
-		list_del(&cb_pos->cb_list);
-		if (cl) {
-			if (cl != &dev->iamthif_cl) {
-				dev_dbg(&dev->pdev->dev, "completing call back.\n");
-				_mei_cmpl(cl, cb_pos);
-				cb_pos = NULL;
-			} else if (cl == &dev->iamthif_cl) {
-				_mei_cmpl_iamthif(dev, cb_pos);
-			}
-		}
-	}
-	return IRQ_HANDLED;
-}
diff --git a/drivers/staging/mei/iorw.c b/drivers/staging/mei/iorw.c
deleted file mode 100644
index 0a80dc4..0000000
--- a/drivers/staging/mei/iorw.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, 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.
- *
- */
-
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/aio.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioctl.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/uuid.h>
-#include <linux/jiffies.h>
-#include <linux/uaccess.h>
-
-
-#include "mei_dev.h"
-#include "hw.h"
-#include "mei.h"
-#include "interface.h"
-
-
-
-/**
- * mei_ioctl_connect_client - the connect to fw client IOCTL function
- *
- * @dev: the device structure
- * @data: IOCTL connect data, input and output parameters
- * @file: private data of the file object
- *
- * Locking: called under "dev->device_lock" lock
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_ioctl_connect_client(struct file *file,
-			struct mei_connect_client_data *data)
-{
-	struct mei_device *dev;
-	struct mei_cl_cb *cb;
-	struct mei_client *client;
-	struct mei_cl *cl;
-	struct mei_cl *cl_pos = NULL;
-	struct mei_cl *cl_next = NULL;
-	long timeout = CONNECT_TIMEOUT;
-	int i;
-	int err;
-	int rets;
-
-	cl = file->private_data;
-	if (WARN_ON(!cl || !cl->dev))
-		return -ENODEV;
-
-	dev = cl->dev;
-
-	dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n");
-
-
-	/* buffered ioctl cb */
-	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
-	if (!cb) {
-		rets = -ENOMEM;
-		goto end;
-	}
-	INIT_LIST_HEAD(&cb->cb_list);
-
-	cb->major_file_operations = MEI_IOCTL;
-
-	if (dev->mei_state != MEI_ENABLED) {
-		rets = -ENODEV;
-		goto end;
-	}
-	if (cl->state != MEI_FILE_INITIALIZING &&
-	    cl->state != MEI_FILE_DISCONNECTED) {
-		rets = -EBUSY;
-		goto end;
-	}
-
-	/* find ME client we're trying to connect to */
-	i = mei_find_me_client_index(dev, data->in_client_uuid);
-	if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
-		cl->me_client_id = dev->me_clients[i].client_id;
-		cl->state = MEI_FILE_CONNECTING;
-	}
-
-	dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
-			cl->me_client_id);
-	dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
-			dev->me_clients[i].props.protocol_version);
-	dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
-			dev->me_clients[i].props.max_msg_length);
-
-	/* if we're connecting to amthi client then we will use the
-	 * existing connection
-	 */
-	if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
-		dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
-		if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
-			rets = -ENODEV;
-			goto end;
-		}
-		clear_bit(cl->host_client_id, dev->host_clients_map);
-		list_for_each_entry_safe(cl_pos, cl_next,
-					 &dev->file_list, link) {
-			if (mei_cl_cmp_id(cl, cl_pos)) {
-				dev_dbg(&dev->pdev->dev,
-					"remove file private data node host"
-				    " client = %d, ME client = %d.\n",
-				    cl_pos->host_client_id,
-				    cl_pos->me_client_id);
-				list_del(&cl_pos->link);
-			}
-
-		}
-		dev_dbg(&dev->pdev->dev, "free file private data memory.\n");
-		kfree(cl);
-
-		cl = NULL;
-		file->private_data = &dev->iamthif_cl;
-
-		client = &data->out_client_properties;
-		client->max_msg_length =
-			dev->me_clients[i].props.max_msg_length;
-		client->protocol_version =
-			dev->me_clients[i].props.protocol_version;
-		rets = dev->iamthif_cl.status;
-
-		goto end;
-	}
-
-	if (cl->state != MEI_FILE_CONNECTING) {
-		rets = -ENODEV;
-		goto end;
-	}
-
-
-	/* prepare the output buffer */
-	client = &data->out_client_properties;
-	client->max_msg_length = dev->me_clients[i].props.max_msg_length;
-	client->protocol_version = dev->me_clients[i].props.protocol_version;
-	dev_dbg(&dev->pdev->dev, "Can connect?\n");
-	if (dev->mei_host_buffer_is_empty
-	    && !mei_other_client_is_connecting(dev, cl)) {
-		dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
-		dev->mei_host_buffer_is_empty = false;
-		if (mei_connect(dev, cl)) {
-			dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
-			rets = -ENODEV;
-			goto end;
-		} else {
-			dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n");
-			cl->timer_count = MEI_CONNECT_TIMEOUT;
-			cb->file_private = cl;
-			list_add_tail(&cb->cb_list,
-				      &dev->ctrl_rd_list.mei_cb.
-				      cb_list);
-		}
-
-
-	} else {
-		dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n");
-		cb->file_private = cl;
-		dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n");
-		list_add_tail(&cb->cb_list,
-			      &dev->ctrl_wr_list.mei_cb.cb_list);
-	}
-	mutex_unlock(&dev->device_lock);
-	err = wait_event_timeout(dev->wait_recvd_msg,
-			(MEI_FILE_CONNECTED == cl->state ||
-			 MEI_FILE_DISCONNECTED == cl->state),
-			timeout * HZ);
-
-	mutex_lock(&dev->device_lock);
-	if (MEI_FILE_CONNECTED == cl->state) {
-		dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n");
-		rets = cl->status;
-		goto end;
-	} else {
-		dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n",
-		    cl->state);
-		if (!err) {
-			dev_dbg(&dev->pdev->dev,
-				"wait_event_interruptible_timeout failed on client"
-				" connect message fw response message.\n");
-		}
-		rets = -EFAULT;
-
-		mei_io_list_flush(&dev->ctrl_rd_list, cl);
-		mei_io_list_flush(&dev->ctrl_wr_list, cl);
-		goto end;
-	}
-	rets = 0;
-end:
-	dev_dbg(&dev->pdev->dev, "free connect cb memory.");
-	kfree(cb);
-	return rets;
-}
-
-/**
- * find_amthi_read_list_entry - finds a amthilist entry for current file
- *
- * @dev: the device structure
- * @file: pointer to file object
- *
- * returns   returned a list entry on success, NULL on failure.
- */
-struct mei_cl_cb *find_amthi_read_list_entry(
-		struct mei_device *dev,
-		struct file *file)
-{
-	struct mei_cl *cl_temp;
-	struct mei_cl_cb *pos = NULL;
-	struct mei_cl_cb *next = NULL;
-
-	list_for_each_entry_safe(pos, next,
-	    &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) {
-		cl_temp = (struct mei_cl *)pos->file_private;
-		if (cl_temp && cl_temp == &dev->iamthif_cl &&
-			pos->file_object == file)
-			return pos;
-	}
-	return NULL;
-}
-
-/**
- * amthi_read - read data from AMTHI client
- *
- * @dev: the device structure
- * @if_num:  minor number
- * @file: pointer to file object
- * @*ubuf: pointer to user data in user space
- * @length: data length to read
- * @offset: data read offset
- *
- * Locking: called under "dev->device_lock" lock
- *
- * returns
- *  returned data length on success,
- *  zero if no data to read,
- *  negative on failure.
- */
-int amthi_read(struct mei_device *dev, struct file *file,
-	       char __user *ubuf, size_t length, loff_t *offset)
-{
-	int rets;
-	int wait_ret;
-	struct mei_cl_cb *cb = NULL;
-	struct mei_cl *cl = file->private_data;
-	unsigned long timeout;
-	int i;
-
-	/* Only Posible if we are in timeout */
-	if (!cl || cl != &dev->iamthif_cl) {
-		dev_dbg(&dev->pdev->dev, "bad file ext.\n");
-		return -ETIMEDOUT;
-	}
-
-	for (i = 0; i < dev->me_clients_num; i++) {
-		if (dev->me_clients[i].client_id ==
-		    dev->iamthif_cl.me_client_id)
-			break;
-	}
-
-	if (i == dev->me_clients_num) {
-		dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
-		return -ENODEV;
-	}
-	if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id))
-		return -ENODEV;
-
-	dev_dbg(&dev->pdev->dev, "checking amthi data\n");
-	cb = find_amthi_read_list_entry(dev, file);
-
-	/* Check for if we can block or not*/
-	if (cb == NULL && file->f_flags & O_NONBLOCK)
-		return -EAGAIN;
-
-
-	dev_dbg(&dev->pdev->dev, "waiting for amthi data\n");
-	while (cb == NULL) {
-		/* unlock the Mutex */
-		mutex_unlock(&dev->device_lock);
-
-		wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
-			(cb = find_amthi_read_list_entry(dev, file)));
-
-		if (wait_ret)
-			return -ERESTARTSYS;
-
-		dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
-
-		/* Locking again the Mutex */
-		mutex_lock(&dev->device_lock);
-	}
-
-
-	dev_dbg(&dev->pdev->dev, "Got amthi data\n");
-	dev->iamthif_timer = 0;
-
-	if (cb) {
-		timeout = cb->read_time +
-					msecs_to_jiffies(IAMTHIF_READ_TIMER);
-		dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
-				timeout);
-
-		if  (time_after(jiffies, timeout)) {
-			dev_dbg(&dev->pdev->dev, "amthi Time out\n");
-			/* 15 sec for the message has expired */
-			list_del(&cb->cb_list);
-			rets = -ETIMEDOUT;
-			goto free;
-		}
-	}
-	/* if the whole message will fit remove it from the list */
-	if (cb->information >= *offset && length >= (cb->information - *offset))
-		list_del(&cb->cb_list);
-	else if (cb->information > 0 && cb->information <= *offset) {
-		/* end of the message has been reached */
-		list_del(&cb->cb_list);
-		rets = 0;
-		goto free;
-	}
-		/* else means that not full buffer will be read and do not
-		 * remove message from deletion list
-		 */
-
-	dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n",
-	    cb->response_buffer.size);
-	dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n",
-	    cb->information);
-
-	/* length is being turncated to PAGE_SIZE, however,
-	 * the information may be longer */
-	length = min_t(size_t, length, (cb->information - *offset));
-
-	if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
-		rets = -EFAULT;
-	else {
-		rets = length;
-		if ((*offset + length) < cb->information) {
-			*offset += length;
-			goto out;
-		}
-	}
-free:
-	dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n");
-	*offset = 0;
-	mei_free_cb_private(cb);
-out:
-	return rets;
-}
-
-/**
- * mei_start_read - the start read client message function.
- *
- * @dev: the device structure
- * @if_num:  minor number
- * @cl: private data of the file object
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
-{
-	struct mei_cl_cb *cb;
-	int rets = 0;
-	int i;
-
-	if (cl->state != MEI_FILE_CONNECTED)
-		return -ENODEV;
-
-	if (dev->mei_state != MEI_ENABLED)
-		return -ENODEV;
-
-	dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
-	if (cl->read_pending || cl->read_cb) {
-		dev_dbg(&dev->pdev->dev, "read is pending.\n");
-		return -EBUSY;
-	}
-
-	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
-	if (!cb)
-		return -ENOMEM;
-
-	dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
-		cl->host_client_id, cl->me_client_id);
-
-	for (i = 0; i < dev->me_clients_num; i++) {
-		if (dev->me_clients[i].client_id == cl->me_client_id)
-			break;
-
-	}
-
-	if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-		rets = -ENODEV;
-		goto unlock;
-	}
-
-	if (i == dev->me_clients_num) {
-		rets = -ENODEV;
-		goto unlock;
-	}
-
-	cb->response_buffer.size = dev->me_clients[i].props.max_msg_length;
-	cb->response_buffer.data =
-			kmalloc(cb->response_buffer.size, GFP_KERNEL);
-	if (!cb->response_buffer.data) {
-		rets = -ENOMEM;
-		goto unlock;
-	}
-	dev_dbg(&dev->pdev->dev, "allocation call back data success.\n");
-	cb->major_file_operations = MEI_READ;
-	/* make sure information is zero before we start */
-	cb->information = 0;
-	cb->file_private = (void *) cl;
-	cl->read_cb = cb;
-	if (dev->mei_host_buffer_is_empty) {
-		dev->mei_host_buffer_is_empty = false;
-		if (mei_send_flow_control(dev, cl)) {
-			rets = -ENODEV;
-			goto unlock;
-		}
-		list_add_tail(&cb->cb_list, &dev->read_list.mei_cb.cb_list);
-	} else {
-		list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list);
-	}
-	return rets;
-unlock:
-	mei_free_cb_private(cb);
-	return rets;
-}
-
-/**
- * amthi_write - write iamthif data to amthi client
- *
- * @dev: the device structure
- * @cb: mei call back struct
- *
- * returns 0 on success, <0 on failure.
- */
-int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
-{
-	struct mei_msg_hdr mei_hdr;
-	int ret;
-
-	if (!dev || !cb)
-		return -ENODEV;
-
-	dev_dbg(&dev->pdev->dev, "write data to amthi client.\n");
-
-	dev->iamthif_state = MEI_IAMTHIF_WRITING;
-	dev->iamthif_current_cb = cb;
-	dev->iamthif_file_object = cb->file_object;
-	dev->iamthif_canceled = false;
-	dev->iamthif_ioctl = true;
-	dev->iamthif_msg_buf_size = cb->request_buffer.size;
-	memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
-	       cb->request_buffer.size);
-
-	ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl);
-	if (ret < 0)
-		return ret;
-
-	if (ret && dev->mei_host_buffer_is_empty) {
-		ret = 0;
-		dev->mei_host_buffer_is_empty = false;
-		if (cb->request_buffer.size >
-			(((dev->host_hw_state & H_CBD) >> 24) * sizeof(u32))
-				-sizeof(struct mei_msg_hdr)) {
-			mei_hdr.length =
-			    (((dev->host_hw_state & H_CBD) >> 24) *
-			    sizeof(u32)) - sizeof(struct mei_msg_hdr);
-			mei_hdr.msg_complete = 0;
-		} else {
-			mei_hdr.length = cb->request_buffer.size;
-			mei_hdr.msg_complete = 1;
-		}
-
-		mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
-		mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
-		mei_hdr.reserved = 0;
-		dev->iamthif_msg_buf_index += mei_hdr.length;
-		if (mei_write_message(dev, &mei_hdr,
-					(unsigned char *)(dev->iamthif_msg_buf),
-					mei_hdr.length))
-			return -ENODEV;
-
-		if (mei_hdr.msg_complete) {
-			if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl))
-				return -ENODEV;
-			dev->iamthif_flow_control_pending = true;
-			dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
-			dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n");
-			dev->iamthif_current_cb = cb;
-			dev->iamthif_file_object = cb->file_object;
-			list_add_tail(&cb->cb_list,
-				      &dev->write_waiting_list.mei_cb.cb_list);
-		} else {
-			dev_dbg(&dev->pdev->dev, "message does not complete, "
-					"so add amthi cb to write list.\n");
-			list_add_tail(&cb->cb_list,
-				      &dev->write_list.mei_cb.cb_list);
-		}
-	} else {
-		if (!(dev->mei_host_buffer_is_empty))
-			dev_dbg(&dev->pdev->dev, "host buffer is not empty");
-
-		dev_dbg(&dev->pdev->dev, "No flow control credentials, "
-				"so add iamthif cb to write list.\n");
-		list_add_tail(&cb->cb_list, &dev->write_list.mei_cb.cb_list);
-	}
-	return 0;
-}
-
-/**
- * iamthif_ioctl_send_msg - send cmd data to amthi client
- *
- * @dev: the device structure
- *
- * returns 0 on success, <0 on failure.
- */
-void mei_run_next_iamthif_cmd(struct mei_device *dev)
-{
-	struct mei_cl *cl_tmp;
-	struct mei_cl_cb *pos = NULL;
-	struct mei_cl_cb *next = NULL;
-	int status;
-
-	if (!dev)
-		return;
-
-	dev->iamthif_msg_buf_size = 0;
-	dev->iamthif_msg_buf_index = 0;
-	dev->iamthif_canceled = false;
-	dev->iamthif_ioctl = true;
-	dev->iamthif_state = MEI_IAMTHIF_IDLE;
-	dev->iamthif_timer = 0;
-	dev->iamthif_file_object = NULL;
-
-	dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n");
-
-	list_for_each_entry_safe(pos, next,
-			&dev->amthi_cmd_list.mei_cb.cb_list, cb_list) {
-		list_del(&pos->cb_list);
-		cl_tmp = (struct mei_cl *)pos->file_private;
-
-		if (cl_tmp && cl_tmp == &dev->iamthif_cl) {
-			status = amthi_write(dev, pos);
-			if (status) {
-				dev_dbg(&dev->pdev->dev,
-					"amthi write failed status = %d\n",
-						status);
-				return;
-			}
-			break;
-		}
-	}
-}
-
-/**
- * mei_free_cb_private - free mei_cb_private related memory
- *
- * @cb: mei callback struct
- */
-void mei_free_cb_private(struct mei_cl_cb *cb)
-{
-	if (cb == NULL)
-		return;
-
-	kfree(cb->request_buffer.data);
-	kfree(cb->response_buffer.data);
-	kfree(cb);
-}
diff --git a/drivers/staging/mei/main.c b/drivers/staging/mei/main.c
deleted file mode 100644
index 7c9321f..0000000
--- a/drivers/staging/mei/main.c
+++ /dev/null
@@ -1,1237 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, 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.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/aio.h>
-#include <linux/pci.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/ioctl.h>
-#include <linux/cdev.h>
-#include <linux/sched.h>
-#include <linux/uuid.h>
-#include <linux/compat.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/miscdevice.h>
-
-#include "mei_dev.h"
-#include "mei.h"
-#include "interface.h"
-
-
-#define MEI_READ_TIMEOUT 45
-#define MEI_DRIVER_NAME	"mei"
-#define MEI_DEV_NAME "mei"
-
-/*
- *  mei driver strings
- */
-static char mei_driver_name[] = MEI_DRIVER_NAME;
-static const char mei_driver_string[] = "Intel(R) Management Engine Interface";
-
-/* The device pointer */
-/* Currently this driver works as long as there is only a single AMT device. */
-struct pci_dev *mei_device;
-
-/* mei_pci_tbl - PCI Device ID Table */
-static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
-
-	/* required last entry */
-	{0, }
-};
-
-MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
-
-static DEFINE_MUTEX(mei_mutex);
-
-
-/**
- * mei_clear_list - removes all callbacks associated with file
- *		from mei_cb_list
- *
- * @dev: device structure.
- * @file: file structure
- * @mei_cb_list: callbacks list
- *
- * mei_clear_list is called to clear resources associated with file
- * when application calls close function or Ctrl-C was pressed
- *
- * returns true if callback removed from the list, false otherwise
- */
-static bool mei_clear_list(struct mei_device *dev,
-		struct file *file, struct list_head *mei_cb_list)
-{
-	struct mei_cl_cb *cb_pos = NULL;
-	struct mei_cl_cb *cb_next = NULL;
-	struct file *file_temp;
-	bool removed = false;
-
-	/* list all list member */
-	list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) {
-		file_temp = (struct file *)cb_pos->file_object;
-		/* check if list member associated with a file */
-		if (file_temp == file) {
-			/* remove member from the list */
-			list_del(&cb_pos->cb_list);
-			/* check if cb equal to current iamthif cb */
-			if (dev->iamthif_current_cb == cb_pos) {
-				dev->iamthif_current_cb = NULL;
-				/* send flow control to iamthif client */
-				mei_send_flow_control(dev, &dev->iamthif_cl);
-			}
-			/* free all allocated buffers */
-			mei_free_cb_private(cb_pos);
-			cb_pos = NULL;
-			removed = true;
-		}
-	}
-	return removed;
-}
-
-/**
- * mei_clear_lists - removes all callbacks associated with file
- *
- * @dev: device structure
- * @file: file structure
- *
- * mei_clear_lists is called to clear resources associated with file
- * when application calls close function or Ctrl-C was pressed
- *
- * returns true if callback removed from the list, false otherwise
- */
-static bool mei_clear_lists(struct mei_device *dev, struct file *file)
-{
-	bool removed = false;
-
-	/* remove callbacks associated with a file */
-	mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list);
-	if (mei_clear_list(dev, file,
-			    &dev->amthi_read_complete_list.mei_cb.cb_list))
-		removed = true;
-
-	mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list);
-
-	if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list))
-		removed = true;
-
-	if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list))
-		removed = true;
-
-	if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list))
-		removed = true;
-
-	/* check if iamthif_current_cb not NULL */
-	if (dev->iamthif_current_cb && !removed) {
-		/* check file and iamthif current cb association */
-		if (dev->iamthif_current_cb->file_object == file) {
-			/* remove cb */
-			mei_free_cb_private(dev->iamthif_current_cb);
-			dev->iamthif_current_cb = NULL;
-			removed = true;
-		}
-	}
-	return removed;
-}
-/**
- * find_read_list_entry - find read list entry
- *
- * @dev: device structure
- * @file: pointer to file structure
- *
- * returns cb on success, NULL on error
- */
-static struct mei_cl_cb *find_read_list_entry(
-		struct mei_device *dev,
-		struct mei_cl *cl)
-{
-	struct mei_cl_cb *pos = NULL;
-	struct mei_cl_cb *next = NULL;
-
-	dev_dbg(&dev->pdev->dev, "remove read_list CB\n");
-	list_for_each_entry_safe(pos, next,
-			&dev->read_list.mei_cb.cb_list, cb_list) {
-		struct mei_cl *cl_temp;
-		cl_temp = (struct mei_cl *)pos->file_private;
-
-		if (mei_cl_cmp_id(cl, cl_temp))
-			return pos;
-	}
-	return NULL;
-}
-
-/**
- * mei_open - the open function
- *
- * @inode: pointer to inode structure
- * @file: pointer to file structure
- *
- * returns 0 on success, <0 on error
- */
-static int mei_open(struct inode *inode, struct file *file)
-{
-	struct mei_cl *cl;
-	struct mei_device *dev;
-	unsigned long cl_id;
-	int err;
-
-	err = -ENODEV;
-	if (!mei_device)
-		goto out;
-
-	dev = pci_get_drvdata(mei_device);
-	if (!dev)
-		goto out;
-
-	mutex_lock(&dev->device_lock);
-	err = -ENOMEM;
-	cl = mei_cl_allocate(dev);
-	if (!cl)
-		goto out_unlock;
-
-	err = -ENODEV;
-	if (dev->mei_state != MEI_ENABLED) {
-		dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED  mei_state= %d\n",
-		    dev->mei_state);
-		goto out_unlock;
-	}
-	err = -EMFILE;
-	if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT)
-		goto out_unlock;
-
-	cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
-	if (cl_id >= MEI_CLIENTS_MAX)
-		goto out_unlock;
-
-	cl->host_client_id  = cl_id;
-
-	dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id);
-
-	dev->open_handle_count++;
-
-	list_add_tail(&cl->link, &dev->file_list);
-
-	set_bit(cl->host_client_id, dev->host_clients_map);
-	cl->state = MEI_FILE_INITIALIZING;
-	cl->sm_state = 0;
-
-	file->private_data = cl;
-	mutex_unlock(&dev->device_lock);
-
-	return nonseekable_open(inode, file);
-
-out_unlock:
-	mutex_unlock(&dev->device_lock);
-	kfree(cl);
-out:
-	return err;
-}
-
-/**
- * mei_release - the release function
- *
- * @inode: pointer to inode structure
- * @file: pointer to file structure
- *
- * returns 0 on success, <0 on error
- */
-static int mei_release(struct inode *inode, struct file *file)
-{
-	struct mei_cl *cl = file->private_data;
-	struct mei_cl_cb *cb;
-	struct mei_device *dev;
-	int rets = 0;
-
-	if (WARN_ON(!cl || !cl->dev))
-		return -ENODEV;
-
-	dev = cl->dev;
-
-	mutex_lock(&dev->device_lock);
-	if (cl != &dev->iamthif_cl) {
-		if (cl->state == MEI_FILE_CONNECTED) {
-			cl->state = MEI_FILE_DISCONNECTING;
-			dev_dbg(&dev->pdev->dev,
-				"disconnecting client host client = %d, "
-			    "ME client = %d\n",
-			    cl->host_client_id,
-			    cl->me_client_id);
-			rets = mei_disconnect_host_client(dev, cl);
-		}
-		mei_cl_flush_queues(cl);
-		dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
-		    cl->host_client_id,
-		    cl->me_client_id);
-
-		if (dev->open_handle_count > 0) {
-			clear_bit(cl->host_client_id, dev->host_clients_map);
-			dev->open_handle_count--;
-		}
-		mei_remove_client_from_file_list(dev, cl->host_client_id);
-
-		/* free read cb */
-		cb = NULL;
-		if (cl->read_cb) {
-			cb = find_read_list_entry(dev, cl);
-			/* Remove entry from read list */
-			if (cb)
-				list_del(&cb->cb_list);
-
-			cb = cl->read_cb;
-			cl->read_cb = NULL;
-		}
-
-		file->private_data = NULL;
-
-		if (cb) {
-			mei_free_cb_private(cb);
-			cb = NULL;
-		}
-
-		kfree(cl);
-	} else {
-		if (dev->open_handle_count > 0)
-			dev->open_handle_count--;
-
-		if (dev->iamthif_file_object == file &&
-		    dev->iamthif_state != MEI_IAMTHIF_IDLE) {
-
-			dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n",
-			    dev->iamthif_state);
-			dev->iamthif_canceled = true;
-			if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
-				dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n");
-				mei_run_next_iamthif_cmd(dev);
-			}
-		}
-
-		if (mei_clear_lists(dev, file))
-			dev->iamthif_state = MEI_IAMTHIF_IDLE;
-
-	}
-	mutex_unlock(&dev->device_lock);
-	return rets;
-}
-
-
-/**
- * mei_read - the read function.
- *
- * @file: pointer to file structure
- * @ubuf: pointer to user buffer
- * @length: buffer length
- * @offset: data offset in buffer
- *
- * returns >=0 data length on success , <0 on error
- */
-static ssize_t mei_read(struct file *file, char __user *ubuf,
-			size_t length, loff_t *offset)
-{
-	struct mei_cl *cl = file->private_data;
-	struct mei_cl_cb *cb_pos = NULL;
-	struct mei_cl_cb *cb = NULL;
-	struct mei_device *dev;
-	int i;
-	int rets;
-	int err;
-
-
-	if (WARN_ON(!cl || !cl->dev))
-		return -ENODEV;
-
-	dev = cl->dev;
-
-	mutex_lock(&dev->device_lock);
-	if (dev->mei_state != MEI_ENABLED) {
-		rets = -ENODEV;
-		goto out;
-	}
-
-	if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
-		/* Do not allow to read watchdog client */
-		i = mei_find_me_client_index(dev, mei_wd_guid);
-		if (i >= 0) {
-			struct mei_me_client *me_client = &dev->me_clients[i];
-
-			if (cl->me_client_id == me_client->client_id) {
-				rets = -EBADF;
-				goto out;
-			}
-		}
-	} else {
-		cl->sm_state &= ~MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
-	}
-
-	if (cl == &dev->iamthif_cl) {
-		rets = amthi_read(dev, file, ubuf, length, offset);
-		goto out;
-	}
-
-	if (cl->read_cb && cl->read_cb->information > *offset) {
-		cb = cl->read_cb;
-		goto copy_buffer;
-	} else if (cl->read_cb && cl->read_cb->information > 0 &&
-		   cl->read_cb->information <= *offset) {
-		cb = cl->read_cb;
-		rets = 0;
-		goto free;
-	} else if ((!cl->read_cb || !cl->read_cb->information) &&
-		    *offset > 0) {
-		/*Offset needs to be cleaned for contiguous reads*/
-		*offset = 0;
-		rets = 0;
-		goto out;
-	}
-
-	err = mei_start_read(dev, cl);
-	if (err && err != -EBUSY) {
-		dev_dbg(&dev->pdev->dev,
-			"mei start read failure with status = %d\n", err);
-		rets = err;
-		goto out;
-	}
-
-	if (MEI_READ_COMPLETE != cl->reading_state &&
-			!waitqueue_active(&cl->rx_wait)) {
-		if (file->f_flags & O_NONBLOCK) {
-			rets = -EAGAIN;
-			goto out;
-		}
-
-		mutex_unlock(&dev->device_lock);
-
-		if (wait_event_interruptible(cl->rx_wait,
-			(MEI_READ_COMPLETE == cl->reading_state ||
-			 MEI_FILE_INITIALIZING == cl->state ||
-			 MEI_FILE_DISCONNECTED == cl->state ||
-			 MEI_FILE_DISCONNECTING == cl->state))) {
-			if (signal_pending(current))
-				return -EINTR;
-			return -ERESTARTSYS;
-		}
-
-		mutex_lock(&dev->device_lock);
-		if (MEI_FILE_INITIALIZING == cl->state ||
-		    MEI_FILE_DISCONNECTED == cl->state ||
-		    MEI_FILE_DISCONNECTING == cl->state) {
-			rets = -EBUSY;
-			goto out;
-		}
-	}
-
-	cb = cl->read_cb;
-
-	if (!cb) {
-		rets = -ENODEV;
-		goto out;
-	}
-	if (cl->reading_state != MEI_READ_COMPLETE) {
-		rets = 0;
-		goto out;
-	}
-	/* now copy the data to user space */
-copy_buffer:
-	dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n",
-	    cb->response_buffer.size);
-	dev_dbg(&dev->pdev->dev, "cb->information - %lu\n",
-	    cb->information);
-	if (length == 0 || ubuf == NULL || *offset > cb->information) {
-		rets = -EMSGSIZE;
-		goto free;
-	}
-
-	/* length is being truncated to PAGE_SIZE, however, */
-	/* information size may be longer */
-	length = min_t(size_t, length, (cb->information - *offset));
-
-	if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
-		rets = -EFAULT;
-		goto free;
-	}
-
-	rets = length;
-	*offset += length;
-	if ((unsigned long)*offset < cb->information)
-		goto out;
-
-free:
-	cb_pos = find_read_list_entry(dev, cl);
-	/* Remove entry from read list */
-	if (cb_pos)
-		list_del(&cb_pos->cb_list);
-	mei_free_cb_private(cb);
-	cl->reading_state = MEI_IDLE;
-	cl->read_cb = NULL;
-	cl->read_pending = 0;
-out:
-	dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets);
-	mutex_unlock(&dev->device_lock);
-	return rets;
-}
-
-/**
- * mei_write - the write function.
- *
- * @file: pointer to file structure
- * @ubuf: pointer to user buffer
- * @length: buffer length
- * @offset: data offset in buffer
- *
- * returns >=0 data length on success , <0 on error
- */
-static ssize_t mei_write(struct file *file, const char __user *ubuf,
-			 size_t length, loff_t *offset)
-{
-	struct mei_cl *cl = file->private_data;
-	struct mei_cl_cb *write_cb = NULL;
-	struct mei_msg_hdr mei_hdr;
-	struct mei_device *dev;
-	unsigned long timeout = 0;
-	int rets;
-	int i;
-
-	if (WARN_ON(!cl || !cl->dev))
-		return -ENODEV;
-
-	dev = cl->dev;
-
-	mutex_lock(&dev->device_lock);
-
-	if (dev->mei_state != MEI_ENABLED) {
-		mutex_unlock(&dev->device_lock);
-		return -ENODEV;
-	}
-
-	if (cl == &dev->iamthif_cl) {
-		write_cb = find_amthi_read_list_entry(dev, file);
-
-		if (write_cb) {
-			timeout = write_cb->read_time +
-					msecs_to_jiffies(IAMTHIF_READ_TIMER);
-
-			if (time_after(jiffies, timeout) ||
-				 cl->reading_state == MEI_READ_COMPLETE) {
-					*offset = 0;
-					list_del(&write_cb->cb_list);
-					mei_free_cb_private(write_cb);
-					write_cb = NULL;
-			}
-		}
-	}
-
-	/* free entry used in read */
-	if (cl->reading_state == MEI_READ_COMPLETE) {
-		*offset = 0;
-		write_cb = find_read_list_entry(dev, cl);
-		if (write_cb) {
-			list_del(&write_cb->cb_list);
-			mei_free_cb_private(write_cb);
-			write_cb = NULL;
-			cl->reading_state = MEI_IDLE;
-			cl->read_cb = NULL;
-			cl->read_pending = 0;
-		}
-	} else if (cl->reading_state == MEI_IDLE && !cl->read_pending)
-		*offset = 0;
-
-
-	write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
-	if (!write_cb) {
-		mutex_unlock(&dev->device_lock);
-		return -ENOMEM;
-	}
-
-	write_cb->file_object = file;
-	write_cb->file_private = cl;
-	write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
-	rets = -ENOMEM;
-	if (!write_cb->request_buffer.data)
-		goto unlock_dev;
-
-	dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length);
-
-	rets = -EFAULT;
-	if (copy_from_user(write_cb->request_buffer.data, ubuf, length))
-		goto unlock_dev;
-
-	cl->sm_state = 0;
-	if (length == 4 &&
-	    ((memcmp(mei_wd_state_independence_msg[0],
-				 write_cb->request_buffer.data, 4) == 0) ||
-	     (memcmp(mei_wd_state_independence_msg[1],
-				 write_cb->request_buffer.data, 4) == 0) ||
-	     (memcmp(mei_wd_state_independence_msg[2],
-				 write_cb->request_buffer.data, 4) == 0)))
-		cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
-
-	INIT_LIST_HEAD(&write_cb->cb_list);
-	if (cl == &dev->iamthif_cl) {
-		write_cb->response_buffer.data =
-		    kmalloc(dev->iamthif_mtu, GFP_KERNEL);
-		if (!write_cb->response_buffer.data) {
-			rets = -ENOMEM;
-			goto unlock_dev;
-		}
-		if (dev->mei_state != MEI_ENABLED) {
-			rets = -ENODEV;
-			goto unlock_dev;
-		}
-		for (i = 0; i < dev->me_clients_num; i++) {
-			if (dev->me_clients[i].client_id ==
-				dev->iamthif_cl.me_client_id)
-				break;
-		}
-
-		if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-			rets = -ENODEV;
-			goto unlock_dev;
-		}
-		if (i == dev->me_clients_num ||
-		    (dev->me_clients[i].client_id !=
-		      dev->iamthif_cl.me_client_id)) {
-			rets = -ENODEV;
-			goto unlock_dev;
-		} else if (length > dev->me_clients[i].props.max_msg_length ||
-			   length <= 0) {
-			rets = -EMSGSIZE;
-			goto unlock_dev;
-		}
-
-		write_cb->response_buffer.size = dev->iamthif_mtu;
-		write_cb->major_file_operations = MEI_IOCTL;
-		write_cb->information = 0;
-		write_cb->request_buffer.size = length;
-		if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
-			rets = -ENODEV;
-			goto unlock_dev;
-		}
-
-		if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) ||
-				dev->iamthif_state != MEI_IAMTHIF_IDLE) {
-			dev_dbg(&dev->pdev->dev, "amthi_state = %d\n",
-					(int) dev->iamthif_state);
-			dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n");
-			list_add_tail(&write_cb->cb_list,
-					&dev->amthi_cmd_list.mei_cb.cb_list);
-			rets = length;
-		} else {
-			dev_dbg(&dev->pdev->dev, "call amthi write\n");
-			rets = amthi_write(dev, write_cb);
-
-			if (rets) {
-				dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n",
-				    rets);
-				goto unlock_dev;
-			}
-			rets = length;
-		}
-		mutex_unlock(&dev->device_lock);
-		return rets;
-	}
-
-	write_cb->major_file_operations = MEI_WRITE;
-	/* make sure information is zero before we start */
-
-	write_cb->information = 0;
-	write_cb->request_buffer.size = length;
-
-	dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n",
-	    cl->host_client_id, cl->me_client_id);
-	if (cl->state != MEI_FILE_CONNECTED) {
-		rets = -ENODEV;
-		dev_dbg(&dev->pdev->dev, "host client = %d,  is not connected to ME client = %d",
-		    cl->host_client_id,
-		    cl->me_client_id);
-		goto unlock_dev;
-	}
-	for (i = 0; i < dev->me_clients_num; i++) {
-		if (dev->me_clients[i].client_id ==
-		    cl->me_client_id)
-			break;
-	}
-	if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-		rets = -ENODEV;
-		goto unlock_dev;
-	}
-	if (i == dev->me_clients_num) {
-		rets = -ENODEV;
-		goto unlock_dev;
-	}
-	if (length > dev->me_clients[i].props.max_msg_length || length <= 0) {
-		rets = -EINVAL;
-		goto unlock_dev;
-	}
-	write_cb->file_private = cl;
-
-	rets = mei_flow_ctrl_creds(dev, cl);
-	if (rets < 0)
-		goto unlock_dev;
-
-	if (rets && dev->mei_host_buffer_is_empty) {
-		rets = 0;
-		dev->mei_host_buffer_is_empty = false;
-		if (length > ((((dev->host_hw_state & H_CBD) >> 24) *
-			sizeof(u32)) - sizeof(struct mei_msg_hdr))) {
-
-			mei_hdr.length =
-				(((dev->host_hw_state & H_CBD) >> 24) *
-				sizeof(u32)) -
-				sizeof(struct mei_msg_hdr);
-			mei_hdr.msg_complete = 0;
-		} else {
-			mei_hdr.length = length;
-			mei_hdr.msg_complete = 1;
-		}
-		mei_hdr.host_addr = cl->host_client_id;
-		mei_hdr.me_addr = cl->me_client_id;
-		mei_hdr.reserved = 0;
-		dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n",
-		    *((u32 *) &mei_hdr));
-		if (mei_write_message(dev, &mei_hdr,
-			(unsigned char *) (write_cb->request_buffer.data),
-			mei_hdr.length)) {
-			rets = -ENODEV;
-			goto unlock_dev;
-		}
-		cl->writing_state = MEI_WRITING;
-		write_cb->information = mei_hdr.length;
-		if (mei_hdr.msg_complete) {
-			if (mei_flow_ctrl_reduce(dev, cl)) {
-				rets = -ENODEV;
-				goto unlock_dev;
-			}
-			list_add_tail(&write_cb->cb_list,
-				      &dev->write_waiting_list.mei_cb.cb_list);
-		} else {
-			list_add_tail(&write_cb->cb_list,
-				      &dev->write_list.mei_cb.cb_list);
-		}
-
-	} else {
-
-		write_cb->information = 0;
-		cl->writing_state = MEI_WRITING;
-		list_add_tail(&write_cb->cb_list,
-			      &dev->write_list.mei_cb.cb_list);
-	}
-	mutex_unlock(&dev->device_lock);
-	return length;
-
-unlock_dev:
-	mutex_unlock(&dev->device_lock);
-	mei_free_cb_private(write_cb);
-	return rets;
-}
-
-
-/**
- * mei_ioctl - the IOCTL function
- *
- * @file: pointer to file structure
- * @cmd: ioctl command
- * @data: pointer to mei message structure
- *
- * returns 0 on success , <0 on error
- */
-static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
-{
-	struct mei_device *dev;
-	struct mei_cl *cl = file->private_data;
-	struct mei_connect_client_data *connect_data = NULL;
-	int rets;
-
-	if (cmd != IOCTL_MEI_CONNECT_CLIENT)
-		return -EINVAL;
-
-	if (WARN_ON(!cl || !cl->dev))
-		return -ENODEV;
-
-	dev = cl->dev;
-
-	dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
-
-	mutex_lock(&dev->device_lock);
-	if (dev->mei_state != MEI_ENABLED) {
-		rets = -ENODEV;
-		goto out;
-	}
-
-	dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
-
-	connect_data = kzalloc(sizeof(struct mei_connect_client_data),
-							GFP_KERNEL);
-	if (!connect_data) {
-		rets = -ENOMEM;
-		goto out;
-	}
-	dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
-	if (copy_from_user(connect_data, (char __user *)data,
-				sizeof(struct mei_connect_client_data))) {
-		dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
-		rets = -EFAULT;
-		goto out;
-	}
-	rets = mei_ioctl_connect_client(file, connect_data);
-
-	/* if all is ok, copying the data back to user. */
-	if (rets)
-		goto out;
-
-	dev_dbg(&dev->pdev->dev, "copy connect data to user\n");
-	if (copy_to_user((char __user *)data, connect_data,
-				sizeof(struct mei_connect_client_data))) {
-		dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
-		rets = -EFAULT;
-		goto out;
-	}
-
-out:
-	kfree(connect_data);
-	mutex_unlock(&dev->device_lock);
-	return rets;
-}
-
-/**
- * mei_compat_ioctl - the compat IOCTL function
- *
- * @file: pointer to file structure
- * @cmd: ioctl command
- * @data: pointer to mei message structure
- *
- * returns 0 on success , <0 on error
- */
-#ifdef CONFIG_COMPAT
-static long mei_compat_ioctl(struct file *file,
-			unsigned int cmd, unsigned long data)
-{
-	return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data));
-}
-#endif
-
-
-/**
- * mei_poll - the poll function
- *
- * @file: pointer to file structure
- * @wait: pointer to poll_table structure
- *
- * returns poll mask
- */
-static unsigned int mei_poll(struct file *file, poll_table *wait)
-{
-	struct mei_cl *cl = file->private_data;
-	struct mei_device *dev;
-	unsigned int mask = 0;
-
-	if (WARN_ON(!cl || !cl->dev))
-		return mask;
-
-	dev = cl->dev;
-
-	mutex_lock(&dev->device_lock);
-
-	if (dev->mei_state != MEI_ENABLED)
-		goto out;
-
-
-	if (cl == &dev->iamthif_cl) {
-		mutex_unlock(&dev->device_lock);
-		poll_wait(file, &dev->iamthif_cl.wait, wait);
-		mutex_lock(&dev->device_lock);
-		if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
-			dev->iamthif_file_object == file) {
-			mask |= (POLLIN | POLLRDNORM);
-			dev_dbg(&dev->pdev->dev, "run next amthi cb\n");
-			mei_run_next_iamthif_cmd(dev);
-		}
-		goto out;
-	}
-
-	mutex_unlock(&dev->device_lock);
-	poll_wait(file, &cl->tx_wait, wait);
-	mutex_lock(&dev->device_lock);
-	if (MEI_WRITE_COMPLETE == cl->writing_state)
-		mask |= (POLLIN | POLLRDNORM);
-
-out:
-	mutex_unlock(&dev->device_lock);
-	return mask;
-}
-
-/*
- * file operations structure will be used for mei char device.
- */
-static const struct file_operations mei_fops = {
-	.owner = THIS_MODULE,
-	.read = mei_read,
-	.unlocked_ioctl = mei_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl = mei_compat_ioctl,
-#endif
-	.open = mei_open,
-	.release = mei_release,
-	.write = mei_write,
-	.poll = mei_poll,
-	.llseek = no_llseek
-};
-
-
-/*
- * Misc Device Struct
- */
-static struct miscdevice  mei_misc_device = {
-		.name = MEI_DRIVER_NAME,
-		.fops = &mei_fops,
-		.minor = MISC_DYNAMIC_MINOR,
-};
-
-/**
- * mei_probe - Device Initialization Routine
- *
- * @pdev: PCI device structure
- * @ent: entry in kcs_pci_tbl
- *
- * returns 0 on success, <0 on failure.
- */
-static int __devinit mei_probe(struct pci_dev *pdev,
-				const struct pci_device_id *ent)
-{
-	struct mei_device *dev;
-	int err;
-
-	mutex_lock(&mei_mutex);
-	if (mei_device) {
-		err = -EEXIST;
-		goto end;
-	}
-	/* enable pci dev */
-	err = pci_enable_device(pdev);
-	if (err) {
-		printk(KERN_ERR "mei: Failed to enable pci device.\n");
-		goto end;
-	}
-	/* set PCI host mastering  */
-	pci_set_master(pdev);
-	/* pci request regions for mei driver */
-	err = pci_request_regions(pdev, mei_driver_name);
-	if (err) {
-		printk(KERN_ERR "mei: Failed to get pci regions.\n");
-		goto disable_device;
-	}
-	/* allocates and initializes the mei dev structure */
-	dev = mei_device_init(pdev);
-	if (!dev) {
-		err = -ENOMEM;
-		goto release_regions;
-	}
-	/* mapping  IO device memory */
-	dev->mem_addr = pci_iomap(pdev, 0, 0);
-	if (!dev->mem_addr) {
-		printk(KERN_ERR "mei: mapping I/O device memory failure.\n");
-		err = -ENOMEM;
-		goto free_device;
-	}
-	pci_enable_msi(pdev);
-
-	 /* request and enable interrupt */
-	if (pci_dev_msi_enabled(pdev))
-		err = request_threaded_irq(pdev->irq,
-			NULL,
-			mei_interrupt_thread_handler,
-			0, mei_driver_name, dev);
-	else
-		err = request_threaded_irq(pdev->irq,
-			mei_interrupt_quick_handler,
-			mei_interrupt_thread_handler,
-			IRQF_SHARED, mei_driver_name, dev);
-
-	if (err) {
-		printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n",
-		       pdev->irq);
-		goto unmap_memory;
-	}
-	INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
-	if (mei_hw_init(dev)) {
-		printk(KERN_ERR "mei: Init hw failure.\n");
-		err = -ENODEV;
-		goto release_irq;
-	}
-
-	err = misc_register(&mei_misc_device);
-	if (err)
-		goto release_irq;
-
-	mei_device = pdev;
-	pci_set_drvdata(pdev, dev);
-
-
-	schedule_delayed_work(&dev->timer_work, HZ);
-
-	mutex_unlock(&mei_mutex);
-
-	pr_debug("mei: Driver initialization successful.\n");
-
-	return 0;
-
-release_irq:
-	/* disable interrupts */
-	dev->host_hw_state = mei_hcsr_read(dev);
-	mei_disable_interrupts(dev);
-	flush_scheduled_work();
-	free_irq(pdev->irq, dev);
-	pci_disable_msi(pdev);
-unmap_memory:
-	pci_iounmap(pdev, dev->mem_addr);
-free_device:
-	kfree(dev);
-release_regions:
-	pci_release_regions(pdev);
-disable_device:
-	pci_disable_device(pdev);
-end:
-	mutex_unlock(&mei_mutex);
-	printk(KERN_ERR "mei: Driver initialization failed.\n");
-	return err;
-}
-
-/**
- * mei_remove - Device Removal Routine
- *
- * @pdev: PCI device structure
- *
- * mei_remove is called by the PCI subsystem to alert the driver
- * that it should release a PCI device.
- */
-static void __devexit mei_remove(struct pci_dev *pdev)
-{
-	struct mei_device *dev;
-
-	if (mei_device != pdev)
-		return;
-
-	dev = pci_get_drvdata(pdev);
-	if (!dev)
-		return;
-
-	mutex_lock(&dev->device_lock);
-
-	mei_wd_stop(dev, false);
-
-	mei_device = NULL;
-
-	if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
-		dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
-		mei_disconnect_host_client(dev, &dev->iamthif_cl);
-	}
-	if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
-		dev->wd_cl.state = MEI_FILE_DISCONNECTING;
-		mei_disconnect_host_client(dev, &dev->wd_cl);
-	}
-
-	/* Unregistering watchdog device */
-	mei_watchdog_unregister(dev);
-
-	/* remove entry if already in list */
-	dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
-	mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id);
-	mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id);
-
-	dev->iamthif_current_cb = NULL;
-	dev->me_clients_num = 0;
-
-	mutex_unlock(&dev->device_lock);
-
-	flush_scheduled_work();
-
-	/* disable interrupts */
-	mei_disable_interrupts(dev);
-
-	free_irq(pdev->irq, dev);
-	pci_disable_msi(pdev);
-	pci_set_drvdata(pdev, NULL);
-
-	if (dev->mem_addr)
-		pci_iounmap(pdev, dev->mem_addr);
-
-	kfree(dev);
-
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-}
-#ifdef CONFIG_PM
-static int mei_pci_suspend(struct device *device)
-{
-	struct pci_dev *pdev = to_pci_dev(device);
-	struct mei_device *dev = pci_get_drvdata(pdev);
-	int err;
-
-	if (!dev)
-		return -ENODEV;
-	mutex_lock(&dev->device_lock);
-	/* Stop watchdog if exists */
-	err = mei_wd_stop(dev, true);
-	/* Set new mei state */
-	if (dev->mei_state == MEI_ENABLED ||
-	    dev->mei_state == MEI_RECOVERING_FROM_RESET) {
-		dev->mei_state = MEI_POWER_DOWN;
-		mei_reset(dev, 0);
-	}
-	mutex_unlock(&dev->device_lock);
-
-	free_irq(pdev->irq, dev);
-	pci_disable_msi(pdev);
-
-	return err;
-}
-
-static int mei_pci_resume(struct device *device)
-{
-	struct pci_dev *pdev = to_pci_dev(device);
-	struct mei_device *dev;
-	int err;
-
-	dev = pci_get_drvdata(pdev);
-	if (!dev)
-		return -ENODEV;
-
-	pci_enable_msi(pdev);
-
-	/* request and enable interrupt */
-	if (pci_dev_msi_enabled(pdev))
-		err = request_threaded_irq(pdev->irq,
-			NULL,
-			mei_interrupt_thread_handler,
-			0, mei_driver_name, dev);
-	else
-		err = request_threaded_irq(pdev->irq,
-			mei_interrupt_quick_handler,
-			mei_interrupt_thread_handler,
-			IRQF_SHARED, mei_driver_name, dev);
-
-	if (err) {
-		printk(KERN_ERR "mei: Request_irq failure. irq = %d\n",
-		       pdev->irq);
-		return err;
-	}
-
-	mutex_lock(&dev->device_lock);
-	dev->mei_state = MEI_POWER_UP;
-	mei_reset(dev, 1);
-	mutex_unlock(&dev->device_lock);
-
-	/* Start timer if stopped in suspend */
-	schedule_delayed_work(&dev->timer_work, HZ);
-
-	return err;
-}
-static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
-#define MEI_PM_OPS	(&mei_pm_ops)
-#else
-#define MEI_PM_OPS	NULL
-#endif /* CONFIG_PM */
-/*
- *  PCI driver structure
- */
-static struct pci_driver mei_driver = {
-	.name = mei_driver_name,
-	.id_table = mei_pci_tbl,
-	.probe = mei_probe,
-	.remove = __devexit_p(mei_remove),
-	.shutdown = __devexit_p(mei_remove),
-	.driver.pm = MEI_PM_OPS,
-};
-
-/**
- * mei_init_module - Driver Registration Routine
- *
- * mei_init_module is the first routine called when the driver is
- * loaded. All it does is to register with the PCI subsystem.
- *
- * returns 0 on success, <0 on failure.
- */
-static int __init mei_init_module(void)
-{
-	int ret;
-
-	pr_debug("mei: %s\n", mei_driver_string);
-	/* init pci module */
-	ret = pci_register_driver(&mei_driver);
-	if (ret < 0)
-		printk(KERN_ERR "mei: Error registering driver.\n");
-
-	return ret;
-}
-
-module_init(mei_init_module);
-
-/**
- * mei_exit_module - Driver Exit Cleanup Routine
- *
- * mei_exit_module is called just before the driver is removed
- * from memory.
- */
-static void __exit mei_exit_module(void)
-{
-	misc_deregister(&mei_misc_device);
-	pci_unregister_driver(&mei_driver);
-
-	pr_debug("mei: Driver unloaded successfully.\n");
-}
-
-module_exit(mei_exit_module);
-
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/mei/mei-amt-version.c b/drivers/staging/mei/mei-amt-version.c
deleted file mode 100644
index ac2a507..0000000
--- a/drivers/staging/mei/mei-amt-version.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/******************************************************************************
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Intel MEI Interface Header
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- *	Intel Corporation.
- *	linux-mei@linux.intel.com
- *	http://www.intel.com
- *
- * BSD LICENSE
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <bits/wordsize.h>
-#include "mei.h"
-
-/*****************************************************************************
- * Intel Management Engine Interface
- *****************************************************************************/
-
-#define mei_msg(_me, fmt, ARGS...) do {         \
-	if (_me->verbose)                       \
-		fprintf(stderr, fmt, ##ARGS);	\
-} while (0)
-
-#define mei_err(_me, fmt, ARGS...) do {         \
-	fprintf(stderr, "Error: " fmt, ##ARGS); \
-} while (0)
-
-struct mei {
-	uuid_le guid;
-	bool initialized;
-	bool verbose;
-	unsigned int buf_size;
-	unsigned char prot_ver;
-	int fd;
-};
-
-static void mei_deinit(struct mei *cl)
-{
-	if (cl->fd != -1)
-		close(cl->fd);
-	cl->fd = -1;
-	cl->buf_size = 0;
-	cl->prot_ver = 0;
-	cl->initialized = false;
-}
-
-static bool mei_init(struct mei *me, const uuid_le *guid,
-		unsigned char req_protocol_version, bool verbose)
-{
-	int result;
-	struct mei_client *cl;
-	struct mei_connect_client_data data;
-
-	mei_deinit(me);
-
-	me->verbose = verbose;
-
-	me->fd = open("/dev/mei", O_RDWR);
-	if (me->fd == -1) {
-		mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
-		goto err;
-	}
-	memcpy(&me->guid, guid, sizeof(*guid));
-	memset(&data, 0, sizeof(data));
-	me->initialized = true;
-
-	memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
-	result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
-	if (result) {
-		mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
-		goto err;
-	}
-	cl = &data.out_client_properties;
-	mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
-	mei_msg(me, "protocol_version %d\n", cl->protocol_version);
-
-	if ((req_protocol_version > 0) &&
-	     (cl->protocol_version != req_protocol_version)) {
-		mei_err(me, "Intel MEI protocol version not supported\n");
-		goto err;
-	}
-
-	me->buf_size = cl->max_msg_length;
-	me->prot_ver = cl->protocol_version;
-
-	return true;
-err:
-	mei_deinit(me);
-	return false;
-}
-
-static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
-			ssize_t len, unsigned long timeout)
-{
-	ssize_t rc;
-
-	mei_msg(me, "call read length = %zd\n", len);
-
-	rc = read(me->fd, buffer, len);
-	if (rc < 0) {
-		mei_err(me, "read failed with status %zd %s\n",
-				rc, strerror(errno));
-		mei_deinit(me);
-	} else {
-		mei_msg(me, "read succeeded with result %zd\n", rc);
-	}
-	return rc;
-}
-
-static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
-			ssize_t len, unsigned long timeout)
-{
-	struct timeval tv;
-	ssize_t written;
-	ssize_t rc;
-	fd_set set;
-
-	tv.tv_sec = timeout / 1000;
-	tv.tv_usec = (timeout % 1000) * 1000000;
-
-	mei_msg(me, "call write length = %zd\n", len);
-
-	written = write(me->fd, buffer, len);
-	if (written < 0) {
-		rc = -errno;
-		mei_err(me, "write failed with status %zd %s\n",
-			written, strerror(errno));
-		goto out;
-	}
-
-	FD_ZERO(&set);
-	FD_SET(me->fd, &set);
-	rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
-	if (rc > 0 && FD_ISSET(me->fd, &set)) {
-		mei_msg(me, "write success\n");
-	} else if (rc == 0) {
-		mei_err(me, "write failed on timeout with status\n");
-		goto out;
-	} else { /* rc < 0 */
-		mei_err(me, "write failed on select with status %zd\n", rc);
-		goto out;
-	}
-
-	rc = written;
-out:
-	if (rc < 0)
-		mei_deinit(me);
-
-	return rc;
-}
-
-/***************************************************************************
- * Intel Advanced Management Technolgy ME Client
- ***************************************************************************/
-
-#define AMT_MAJOR_VERSION 1
-#define AMT_MINOR_VERSION 1
-
-#define AMT_STATUS_SUCCESS                0x0
-#define AMT_STATUS_INTERNAL_ERROR         0x1
-#define AMT_STATUS_NOT_READY              0x2
-#define AMT_STATUS_INVALID_AMT_MODE       0x3
-#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
-
-#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE  0x4000
-#define AMT_STATUS_SDK_RESOURCES      0x1004
-
-
-#define AMT_BIOS_VERSION_LEN   65
-#define AMT_VERSIONS_NUMBER    50
-#define AMT_UNICODE_STRING_LEN 20
-
-struct amt_unicode_string {
-	uint16_t length;
-	char string[AMT_UNICODE_STRING_LEN];
-} __attribute__((packed));
-
-struct amt_version_type {
-	struct amt_unicode_string description;
-	struct amt_unicode_string version;
-} __attribute__((packed));
-
-struct amt_version {
-	uint8_t major;
-	uint8_t minor;
-} __attribute__((packed));
-
-struct amt_code_versions {
-	uint8_t bios[AMT_BIOS_VERSION_LEN];
-	uint32_t count;
-	struct amt_version_type versions[AMT_VERSIONS_NUMBER];
-} __attribute__((packed));
-
-/***************************************************************************
- * Intel Advanced Management Technolgy Host Interface
- ***************************************************************************/
-
-struct amt_host_if_msg_header {
-	struct amt_version version;
-	uint16_t _reserved;
-	uint32_t command;
-	uint32_t length;
-} __attribute__((packed));
-
-struct amt_host_if_resp_header {
-	struct amt_host_if_msg_header header;
-	uint32_t status;
-	unsigned char data[0];
-} __attribute__((packed));
-
-const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,  \
-				0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
-
-#define AMT_HOST_IF_CODE_VERSIONS_REQUEST  0x0400001A
-#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
-
-const struct amt_host_if_msg_header CODE_VERSION_REQ = {
-	.version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
-	._reserved = 0,
-	.command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
-	.length = 0
-};
-
-
-struct amt_host_if {
-	struct mei mei_cl;
-	unsigned long send_timeout;
-	bool initialized;
-};
-
-
-static bool amt_host_if_init(struct amt_host_if *acmd,
-		      unsigned long send_timeout, bool verbose)
-{
-	acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
-	acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
-	return acmd->initialized;
-}
-
-static void amt_host_if_deinit(struct amt_host_if *acmd)
-{
-	mei_deinit(&acmd->mei_cl);
-	acmd->initialized = false;
-}
-
-static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
-{
-	uint32_t status = AMT_STATUS_SUCCESS;
-	struct amt_code_versions *code_ver;
-	size_t code_ver_len;
-	uint32_t ver_type_cnt;
-	uint32_t len;
-	uint32_t i;
-
-	code_ver = (struct amt_code_versions *)resp->data;
-	/* length - sizeof(status) */
-	code_ver_len = resp->header.length - sizeof(uint32_t);
-	ver_type_cnt = code_ver_len -
-			sizeof(code_ver->bios) -
-			sizeof(code_ver->count);
-	if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
-		status = AMT_STATUS_INTERNAL_ERROR;
-		goto out;
-	}
-
-	for (i = 0; i < code_ver->count; i++) {
-		len = code_ver->versions[i].description.length;
-
-		if (len > AMT_UNICODE_STRING_LEN) {
-			status = AMT_STATUS_INTERNAL_ERROR;
-			goto out;
-		}
-
-		len = code_ver->versions[i].version.length;
-		if (code_ver->versions[i].version.string[len] != '\0' ||
-		    len != strlen(code_ver->versions[i].version.string)) {
-			status = AMT_STATUS_INTERNAL_ERROR;
-			goto out;
-		}
-	}
-out:
-	return status;
-}
-
-static uint32_t amt_verify_response_header(uint32_t command,
-				const struct amt_host_if_msg_header *resp_hdr,
-				uint32_t response_size)
-{
-	if (response_size < sizeof(struct amt_host_if_resp_header)) {
-		return AMT_STATUS_INTERNAL_ERROR;
-	} else if (response_size != (resp_hdr->length +
-				sizeof(struct amt_host_if_msg_header))) {
-		return AMT_STATUS_INTERNAL_ERROR;
-	} else if (resp_hdr->command != command) {
-		return AMT_STATUS_INTERNAL_ERROR;
-	} else if (resp_hdr->_reserved != 0) {
-		return AMT_STATUS_INTERNAL_ERROR;
-	} else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
-		   resp_hdr->version.minor < AMT_MINOR_VERSION) {
-		return AMT_STATUS_INTERNAL_ERROR;
-	}
-	return AMT_STATUS_SUCCESS;
-}
-
-static uint32_t amt_host_if_call(struct amt_host_if *acmd,
-			const unsigned char *command, ssize_t command_sz,
-			uint8_t **read_buf, uint32_t rcmd,
-			unsigned int expected_sz)
-{
-	uint32_t in_buf_sz;
-	uint32_t out_buf_sz;
-	ssize_t written;
-	uint32_t status;
-	struct amt_host_if_resp_header *msg_hdr;
-
-	in_buf_sz = acmd->mei_cl.buf_size;
-	*read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
-	if (*read_buf == NULL)
-		return AMT_STATUS_SDK_RESOURCES;
-	memset(*read_buf, 0, in_buf_sz);
-	msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
-
-	written = mei_send_msg(&acmd->mei_cl,
-				command, command_sz, acmd->send_timeout);
-	if (written != command_sz)
-		return AMT_STATUS_INTERNAL_ERROR;
-
-	out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
-	if (out_buf_sz <= 0)
-		return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
-
-	status = msg_hdr->status;
-	if (status != AMT_STATUS_SUCCESS)
-		return status;
-
-	status = amt_verify_response_header(rcmd,
-				&msg_hdr->header, out_buf_sz);
-	if (status != AMT_STATUS_SUCCESS)
-		return status;
-
-	if (expected_sz && expected_sz != out_buf_sz)
-		return AMT_STATUS_INTERNAL_ERROR;
-
-	return AMT_STATUS_SUCCESS;
-}
-
-
-static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
-			       struct amt_code_versions *versions)
-{
-	struct amt_host_if_resp_header *response = NULL;
-	uint32_t status;
-
-	status = amt_host_if_call(cmd,
-			(const unsigned char *)&CODE_VERSION_REQ,
-			sizeof(CODE_VERSION_REQ),
-			(uint8_t **)&response,
-			AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
-
-	if (status != AMT_STATUS_SUCCESS)
-		goto out;
-
-	status = amt_verify_code_versions(response);
-	if (status != AMT_STATUS_SUCCESS)
-		goto out;
-
-	memcpy(versions, response->data, sizeof(struct amt_code_versions));
-out:
-	if (response != NULL)
-		free(response);
-
-	return status;
-}
-
-/************************** end of amt_host_if_command ***********************/
-int main(int argc, char **argv)
-{
-	struct amt_code_versions ver;
-	struct amt_host_if acmd;
-	unsigned int i;
-	uint32_t status;
-	int ret;
-	bool verbose;
-
-	verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
-
-	if (!amt_host_if_init(&acmd, 5000, verbose)) {
-		ret = 1;
-		goto out;
-	}
-
-	status = amt_get_code_versions(&acmd, &ver);
-
-	amt_host_if_deinit(&acmd);
-
-	switch (status) {
-	case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
-		printf("Intel AMT: DISABLED\n");
-		ret = 0;
-		break;
-	case AMT_STATUS_SUCCESS:
-		printf("Intel AMT: ENABLED\n");
-		for (i = 0; i < ver.count; i++) {
-			printf("%s:\t%s\n", ver.versions[i].description.string,
-				ver.versions[i].version.string);
-		}
-		ret = 0;
-		break;
-	default:
-		printf("An error has occurred\n");
-		ret = 1;
-		break;
-	}
-
-out:
-	return ret;
-}
diff --git a/drivers/staging/mei/mei_dev.h b/drivers/staging/mei/mei_dev.h
deleted file mode 100644
index 10b1b4e..0000000
--- a/drivers/staging/mei/mei_dev.h
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, 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.
- *
- */
-
-#ifndef _MEI_DEV_H_
-#define _MEI_DEV_H_
-
-#include <linux/types.h>
-#include <linux/watchdog.h>
-#include "mei.h"
-#include "hw.h"
-
-/*
- * watch dog definition
- */
-#define MEI_WATCHDOG_DATA_SIZE         16
-#define MEI_START_WD_DATA_SIZE         20
-#define MEI_WD_PARAMS_SIZE             4
-#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT       (1 << 0)
-
-#define MEI_RD_MSG_BUF_SIZE           (128 * sizeof(u32))
-
-/*
- * MEI PCI Device object
- */
-extern struct pci_dev *mei_device;
-
-
-/*
- * AMTHI Client UUID
- */
-extern const uuid_le mei_amthi_guid;
-
-/*
- * Watchdog Client UUID
- */
-extern const uuid_le mei_wd_guid;
-
-/*
- * Watchdog independence state message
- */
-extern const u8 mei_wd_state_independence_msg[3][4];
-
-/*
- * Number of File descriptors/handles
- * that can be opened to the driver.
- *
- * Limit to 253: 255 Total Clients
- * minus internal client for AMTHI
- * minus internal client for Watchdog
- */
-#define  MEI_MAX_OPEN_HANDLE_COUNT	253
-
-/*
- * Number of Maximum MEI Clients
- */
-#define MEI_CLIENTS_MAX 255
-
-/* File state */
-enum file_state {
-	MEI_FILE_INITIALIZING = 0,
-	MEI_FILE_CONNECTING,
-	MEI_FILE_CONNECTED,
-	MEI_FILE_DISCONNECTING,
-	MEI_FILE_DISCONNECTED
-};
-
-/* MEI device states */
-enum mei_states {
-	MEI_INITIALIZING = 0,
-	MEI_INIT_CLIENTS,
-	MEI_ENABLED,
-	MEI_RESETING,
-	MEI_DISABLED,
-	MEI_RECOVERING_FROM_RESET,
-	MEI_POWER_DOWN,
-	MEI_POWER_UP
-};
-
-/* init clients states*/
-enum mei_init_clients_states {
-	MEI_START_MESSAGE = 0,
-	MEI_ENUM_CLIENTS_MESSAGE,
-	MEI_CLIENT_PROPERTIES_MESSAGE
-};
-
-enum iamthif_states {
-	MEI_IAMTHIF_IDLE,
-	MEI_IAMTHIF_WRITING,
-	MEI_IAMTHIF_FLOW_CONTROL,
-	MEI_IAMTHIF_READING,
-	MEI_IAMTHIF_READ_COMPLETE
-};
-
-enum mei_file_transaction_states {
-	MEI_IDLE,
-	MEI_WRITING,
-	MEI_WRITE_COMPLETE,
-	MEI_FLOW_CONTROL,
-	MEI_READING,
-	MEI_READ_COMPLETE
-};
-
-/* MEI CB */
-enum mei_cb_major_types {
-	MEI_READ = 0,
-	MEI_WRITE,
-	MEI_IOCTL,
-	MEI_OPEN,
-	MEI_CLOSE
-};
-
-/*
- * Intel MEI message data struct
- */
-struct mei_message_data {
-	u32 size;
-	unsigned char *data;
-} __packed;
-
-
-struct mei_cl_cb {
-	struct list_head cb_list;
-	enum mei_cb_major_types major_file_operations;
-	void *file_private;
-	struct mei_message_data request_buffer;
-	struct mei_message_data response_buffer;
-	unsigned long information;
-	unsigned long read_time;
-	struct file *file_object;
-};
-
-/* MEI client instance carried as file->pirvate_data*/
-struct mei_cl {
-	struct list_head link;
-	struct mei_device *dev;
-	enum file_state state;
-	wait_queue_head_t tx_wait;
-	wait_queue_head_t rx_wait;
-	wait_queue_head_t wait;
-	int read_pending;
-	int status;
-	/* ID of client connected */
-	u8 host_client_id;
-	u8 me_client_id;
-	u8 mei_flow_ctrl_creds;
-	u8 timer_count;
-	enum mei_file_transaction_states reading_state;
-	enum mei_file_transaction_states writing_state;
-	int sm_state;
-	struct mei_cl_cb *read_cb;
-};
-
-struct mei_io_list {
-	struct mei_cl_cb mei_cb;
-};
-
-/* MEI private device struct */
-struct mei_device {
-	struct pci_dev *pdev;	/* pointer to pci device struct */
-	/*
-	 * lists of queues
-	 */
-	 /* array of pointers to aio lists */
-	struct mei_io_list read_list;		/* driver read queue */
-	struct mei_io_list write_list;		/* driver write queue */
-	struct mei_io_list write_waiting_list;	/* write waiting queue */
-	struct mei_io_list ctrl_wr_list;	/* managed write IOCTL list */
-	struct mei_io_list ctrl_rd_list;	/* managed read IOCTL list */
-	struct mei_io_list amthi_cmd_list;	/* amthi list for cmd waiting */
-
-	/* driver managed amthi list for reading completed amthi cmd data */
-	struct mei_io_list amthi_read_complete_list;
-	/*
-	 * list of files
-	 */
-	struct list_head file_list;
-	long open_handle_count;
-	/*
-	 * memory of device
-	 */
-	unsigned int mem_base;
-	unsigned int mem_length;
-	void __iomem *mem_addr;
-	/*
-	 * lock for the device
-	 */
-	struct mutex device_lock; /* device lock */
-	struct delayed_work timer_work;	/* MEI timer delayed work (timeouts) */
-	bool recvd_msg;
-	/*
-	 * hw states of host and fw(ME)
-	 */
-	u32 host_hw_state;
-	u32 me_hw_state;
-	/*
-	 * waiting queue for receive message from FW
-	 */
-	wait_queue_head_t wait_recvd_msg;
-	wait_queue_head_t wait_stop_wd;
-
-	/*
-	 * mei device  states
-	 */
-	enum mei_states mei_state;
-	enum mei_init_clients_states init_clients_state;
-	u16 init_clients_timer;
-	bool stop;
-	bool need_reset;
-
-	u32 extra_write_index;
-	unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];	/* control messages */
-	u32 wr_msg_buf[128];	/* used for control messages */
-	u32 ext_msg_buf[8];	/* for control responses */
-	u32 rd_msg_hdr;
-
-	struct hbm_version version;
-
-	struct mei_me_client *me_clients; /* Note: memory has to be allocated */
-	DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
-	DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
-	u8 me_clients_num;
-	u8 me_client_presentation_num;
-	u8 me_client_index;
-	bool mei_host_buffer_is_empty;
-
-	struct mei_cl wd_cl;
-	bool wd_pending;
-	bool wd_stopped;
-	bool wd_bypass;	/* if false, don't refresh watchdog ME client */
-	u16 wd_timeout;	/* seconds ((wd_data[1] << 8) + wd_data[0]) */
-	u16 wd_due_counter;
-	unsigned char wd_data[MEI_START_WD_DATA_SIZE];
-
-
-
-	struct file *iamthif_file_object;
-	struct mei_cl iamthif_cl;
-	struct mei_cl_cb *iamthif_current_cb;
-	int iamthif_mtu;
-	unsigned long iamthif_timer;
-	u32 iamthif_stall_timer;
-	unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */
-	u32 iamthif_msg_buf_size;
-	u32 iamthif_msg_buf_index;
-	enum iamthif_states iamthif_state;
-	bool iamthif_flow_control_pending;
-	bool iamthif_ioctl;
-	bool iamthif_canceled;
-
-	bool wd_interface_reg;
-};
-
-
-/*
- * mei init function prototypes
- */
-struct mei_device *mei_device_init(struct pci_dev *pdev);
-void mei_reset(struct mei_device *dev, int interrupts);
-int mei_hw_init(struct mei_device *dev);
-int mei_task_initialize_clients(void *data);
-int mei_initialize_clients(struct mei_device *dev);
-int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl);
-void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id);
-void mei_host_init_iamthif(struct mei_device *dev);
-void mei_allocate_me_clients_storage(struct mei_device *dev);
-
-
-u8 mei_find_me_client_update_filext(struct mei_device *dev,
-				struct mei_cl *priv,
-				const uuid_le *cguid, u8 client_id);
-
-/*
- * MEI IO List Functions
- */
-void mei_io_list_init(struct mei_io_list *list);
-void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl);
-
-/*
- * MEI ME Client Functions
- */
-
-struct mei_cl *mei_cl_allocate(struct mei_device *dev);
-void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
-int mei_cl_flush_queues(struct mei_cl *cl);
-/**
- * mei_cl_cmp_id - tells if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns true  - if ids are the same and not NULL
- */
-static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
-				const struct mei_cl *cl2)
-{
-	return cl1 && cl2 &&
-		(cl1->host_client_id == cl2->host_client_id) &&
-		(cl1->me_client_id == cl2->me_client_id);
-}
-
-
-
-/*
- * MEI Host Client Functions
- */
-void mei_host_start_message(struct mei_device *dev);
-void mei_host_enum_clients_message(struct mei_device *dev);
-int mei_host_client_properties(struct mei_device *dev);
-
-/*
- *  MEI interrupt functions prototype
- */
-irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id);
-irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id);
-void mei_timer(struct work_struct *work);
-
-/*
- *  MEI input output function prototype
- */
-int mei_ioctl_connect_client(struct file *file,
-			struct mei_connect_client_data *data);
-
-int mei_start_read(struct mei_device *dev, struct mei_cl *cl);
-
-int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb);
-
-int amthi_read(struct mei_device *dev, struct file *file,
-	      char __user *ubuf, size_t length, loff_t *offset);
-
-struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev,
-						struct file *file);
-
-void mei_run_next_iamthif_cmd(struct mei_device *dev);
-
-void mei_free_cb_private(struct mei_cl_cb *priv_cb);
-
-int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
-
-/*
- * Register Access Function
- */
-
-/**
- * mei_reg_read - Reads 32bit data from the mei device
- *
- * @dev: the device structure
- * @offset: offset from which to read the data
- *
- * returns register value (u32)
- */
-static inline u32 mei_reg_read(struct mei_device *dev, unsigned long offset)
-{
-	return ioread32(dev->mem_addr + offset);
-}
-
-/**
- * mei_reg_write - Writes 32bit data to the mei device
- *
- * @dev: the device structure
- * @offset: offset from which to write the data
- * @value: register value to write (u32)
- */
-static inline void mei_reg_write(struct mei_device *dev,
-				unsigned long offset, u32 value)
-{
-	iowrite32(value, dev->mem_addr + offset);
-}
-
-/**
- * mei_hcsr_read - Reads 32bit data from the host CSR
- *
- * @dev: the device structure
- *
- * returns the byte read.
- */
-static inline u32 mei_hcsr_read(struct mei_device *dev)
-{
-	return mei_reg_read(dev, H_CSR);
-}
-
-/**
- * mei_mecsr_read - Reads 32bit data from the ME CSR
- *
- * @dev: the device structure
- *
- * returns ME_CSR_HA register value (u32)
- */
-static inline u32 mei_mecsr_read(struct mei_device *dev)
-{
-	return mei_reg_read(dev, ME_CSR_HA);
-}
-
-/**
- * get_me_cb_rw - Reads 32bit data from the mei ME_CB_RW register
- *
- * @dev: the device structure
- *
- * returns ME_CB_RW register value (u32)
- */
-static inline u32 mei_mecbrw_read(struct mei_device *dev)
-{
-	return mei_reg_read(dev, ME_CB_RW);
-}
-
-
-/*
- * mei interface function prototypes
- */
-void mei_hcsr_set(struct mei_device *dev);
-void mei_csr_clear_his(struct mei_device *dev);
-
-void mei_enable_interrupts(struct mei_device *dev);
-void mei_disable_interrupts(struct mei_device *dev);
-
-#endif
diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c
deleted file mode 100644
index cf4c29d..0000000
--- a/drivers/staging/mei/wd.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, 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.
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/watchdog.h>
-
-#include "mei_dev.h"
-#include "hw.h"
-#include "interface.h"
-#include "mei.h"
-
-static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
-static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
-
-const u8 mei_wd_state_independence_msg[3][4] = {
-	{0x05, 0x02, 0x51, 0x10},
-	{0x05, 0x02, 0x52, 0x10},
-	{0x07, 0x02, 0x01, 0x10}
-};
-
-/*
- * AMT Watchdog Device
- */
-#define INTEL_AMT_WATCHDOG_ID "INTCAMT"
-
-/* UUIDs for AMT F/W clients */
-const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
-						0x9D, 0xA9, 0x15, 0x14, 0xCB,
-						0x32, 0xAB);
-
-void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
-{
-	dev_dbg(&dev->pdev->dev, "timeout=%d.\n", timeout);
-	memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
-	memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE,
-			&timeout, sizeof(u16));
-}
-
-/**
- * host_init_wd - mei initialization wd.
- *
- * @dev: the device structure
- */
-bool mei_wd_host_init(struct mei_device *dev)
-{
-	bool ret = false;
-
-	mei_cl_init(&dev->wd_cl, dev);
-
-	/* look for WD client and connect to it */
-	dev->wd_cl.state = MEI_FILE_DISCONNECTED;
-	dev->wd_timeout = AMT_WD_DEFAULT_TIMEOUT;
-
-	/* find ME WD client */
-	mei_find_me_client_update_filext(dev, &dev->wd_cl,
-				&mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
-
-	dev_dbg(&dev->pdev->dev, "check wd_cl\n");
-	if (MEI_FILE_CONNECTING == dev->wd_cl.state) {
-		if (mei_connect(dev, &dev->wd_cl)) {
-			dev_dbg(&dev->pdev->dev, "Failed to connect to WD client\n");
-			dev->wd_cl.state = MEI_FILE_DISCONNECTED;
-			dev->wd_cl.host_client_id = 0;
-			ret = false;
-			goto end;
-		} else {
-			dev->wd_cl.timer_count = CONNECT_TIMEOUT;
-		}
-	} else {
-		dev_dbg(&dev->pdev->dev, "Failed to find WD client\n");
-		ret = false;
-		goto end;
-	}
-
-end:
-	return ret;
-}
-
-/**
- * mei_wd_send - sends watch dog message to fw.
- *
- * @dev: the device structure
- *
- * returns 0 if success,
- *	-EIO when message send fails
- *	-EINVAL when invalid message is to be sent
- */
-int mei_wd_send(struct mei_device *dev)
-{
-	struct mei_msg_hdr *mei_hdr;
-
-	mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-	mei_hdr->host_addr = dev->wd_cl.host_client_id;
-	mei_hdr->me_addr = dev->wd_cl.me_client_id;
-	mei_hdr->msg_complete = 1;
-	mei_hdr->reserved = 0;
-
-	if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE))
-		mei_hdr->length = MEI_START_WD_DATA_SIZE;
-	else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE))
-		mei_hdr->length = MEI_WD_PARAMS_SIZE;
-	else
-		return -EINVAL;
-
-	return mei_write_message(dev, mei_hdr, dev->wd_data, mei_hdr->length);
-}
-
-/**
- * mei_wd_stop - sends watchdog stop message to fw.
- *
- * @dev: the device structure
- * @preserve: indicate if to keep the timeout value
- *
- * returns 0 if success,
- *	-EIO when message send fails
- *	-EINVAL when invalid message is to be sent
- */
-int mei_wd_stop(struct mei_device *dev, bool preserve)
-{
-	int ret;
-	u16 wd_timeout = dev->wd_timeout;
-
-	cancel_delayed_work(&dev->timer_work);
-	if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
-		return 0;
-
-	dev->wd_timeout = 0;
-	dev->wd_due_counter = 0;
-	memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
-	dev->stop = true;
-
-	ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
-	if (ret < 0)
-		goto out;
-
-	if (ret && dev->mei_host_buffer_is_empty) {
-		ret = 0;
-		dev->mei_host_buffer_is_empty = false;
-
-		if (!mei_wd_send(dev)) {
-			ret = mei_flow_ctrl_reduce(dev, &dev->wd_cl);
-			if (ret)
-				goto out;
-		} else {
-			dev_dbg(&dev->pdev->dev, "send stop WD failed\n");
-		}
-
-		dev->wd_pending = false;
-	} else {
-		dev->wd_pending = true;
-	}
-	dev->wd_stopped = false;
-	mutex_unlock(&dev->device_lock);
-
-	ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
-					dev->wd_stopped, 10 * HZ);
-	mutex_lock(&dev->device_lock);
-	if (dev->wd_stopped) {
-		dev_dbg(&dev->pdev->dev, "stop wd complete ret=%d.\n", ret);
-		ret = 0;
-	} else {
-		if (!ret)
-			ret = -ETIMEDOUT;
-		dev_warn(&dev->pdev->dev,
-			"stop wd failed to complete ret=%d.\n", ret);
-	}
-
-	if (preserve)
-		dev->wd_timeout = wd_timeout;
-
-out:
-	return ret;
-}
-
-/*
- * mei_wd_ops_start - wd start command from the watchdog core.
- *
- * @wd_dev - watchdog device struct
- *
- * returns 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_start(struct watchdog_device *wd_dev)
-{
-	int err = -ENODEV;
-	struct mei_device *dev;
-
-	dev = pci_get_drvdata(mei_device);
-	if (!dev)
-		return -ENODEV;
-
-	mutex_lock(&dev->device_lock);
-
-	if (dev->mei_state != MEI_ENABLED) {
-		dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED  mei_state= %d\n",
-		    dev->mei_state);
-		goto end_unlock;
-	}
-
-	if (dev->wd_cl.state != MEI_FILE_CONNECTED)	{
-		dev_dbg(&dev->pdev->dev, "MEI Driver is not connected to Watchdog Client\n");
-		goto end_unlock;
-	}
-
-	mei_wd_set_start_timeout(dev, dev->wd_timeout);
-
-	err = 0;
-end_unlock:
-	mutex_unlock(&dev->device_lock);
-	return err;
-}
-
-/*
- * mei_wd_ops_stop -  wd stop command from the watchdog core.
- *
- * @wd_dev - watchdog device struct
- *
- * returns 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
-{
-	struct mei_device *dev;
-	dev = pci_get_drvdata(mei_device);
-
-	if (!dev)
-		return -ENODEV;
-
-	mutex_lock(&dev->device_lock);
-	mei_wd_stop(dev, false);
-	mutex_unlock(&dev->device_lock);
-
-	return 0;
-}
-
-/*
- * mei_wd_ops_ping - wd ping command from the watchdog core.
- *
- * @wd_dev - watchdog device struct
- *
- * returns 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
-{
-	int ret = 0;
-	struct mei_device *dev;
-	dev = pci_get_drvdata(mei_device);
-
-	if (!dev)
-		return -ENODEV;
-
-	mutex_lock(&dev->device_lock);
-
-	if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
-		dev_dbg(&dev->pdev->dev, "wd is not connected.\n");
-		ret = -ENODEV;
-		goto end;
-	}
-
-	/* Check if we can send the ping to HW*/
-	if (dev->mei_host_buffer_is_empty &&
-		mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
-
-		dev->mei_host_buffer_is_empty = false;
-		dev_dbg(&dev->pdev->dev, "sending watchdog ping\n");
-
-		if (mei_wd_send(dev)) {
-			dev_dbg(&dev->pdev->dev, "wd send failed.\n");
-			ret = -EIO;
-			goto end;
-		}
-
-		if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) {
-			dev_dbg(&dev->pdev->dev, "mei_flow_ctrl_reduce() failed.\n");
-			ret = -EIO;
-			goto end;
-		}
-
-	} else {
-		dev->wd_pending = true;
-	}
-
-end:
-	mutex_unlock(&dev->device_lock);
-	return ret;
-}
-
-/*
- * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core.
- *
- * @wd_dev - watchdog device struct
- * @timeout - timeout value to set
- *
- * returns 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
-{
-	struct mei_device *dev;
-	dev = pci_get_drvdata(mei_device);
-
-	if (!dev)
-		return -ENODEV;
-
-	/* Check Timeout value */
-	if (timeout < AMT_WD_MIN_TIMEOUT || timeout > AMT_WD_MAX_TIMEOUT)
-		return -EINVAL;
-
-	mutex_lock(&dev->device_lock);
-
-	dev->wd_timeout = timeout;
-	wd_dev->timeout = timeout;
-	mei_wd_set_start_timeout(dev, dev->wd_timeout);
-
-	mutex_unlock(&dev->device_lock);
-
-	return 0;
-}
-
-/*
- * Watchdog Device structs
- */
-static const struct watchdog_ops wd_ops = {
-		.owner = THIS_MODULE,
-		.start = mei_wd_ops_start,
-		.stop = mei_wd_ops_stop,
-		.ping = mei_wd_ops_ping,
-		.set_timeout = mei_wd_ops_set_timeout,
-};
-static const struct watchdog_info wd_info = {
-		.identity = INTEL_AMT_WATCHDOG_ID,
-		.options = WDIOF_KEEPALIVEPING,
-};
-
-struct watchdog_device amt_wd_dev = {
-		.info = &wd_info,
-		.ops = &wd_ops,
-		.timeout = AMT_WD_DEFAULT_TIMEOUT,
-		.min_timeout = AMT_WD_MIN_TIMEOUT,
-		.max_timeout = AMT_WD_MAX_TIMEOUT,
-};
-
-
-void  mei_watchdog_register(struct mei_device *dev)
-{
-	dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", dev->wd_timeout);
-
-	dev->wd_due_counter = !!dev->wd_timeout;
-
-	if (watchdog_register_device(&amt_wd_dev)) {
-		dev_err(&dev->pdev->dev, "unable to register watchdog device.\n");
-		dev->wd_interface_reg = false;
-	} else {
-		dev_dbg(&dev->pdev->dev, "successfully register watchdog interface.\n");
-		dev->wd_interface_reg = true;
-	}
-}
-
-void mei_watchdog_unregister(struct mei_device *dev)
-{
-	if (dev->wd_interface_reg)
-		watchdog_unregister_device(&amt_wd_dev);
-	dev->wd_interface_reg = false;
-}
-
diff --git a/drivers/staging/net/Kconfig b/drivers/staging/net/Kconfig
new file mode 100644
index 0000000..a64e56b
--- /dev/null
+++ b/drivers/staging/net/Kconfig
@@ -0,0 +1,38 @@
+if NETDEVICES
+
+if WAN
+
+config PC300
+	tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
+	depends on HDLC && PCI && BROKEN
+	---help---
+	  This driver is broken because of struct tty_driver change.
+
+	  Driver for the Cyclades-PC300 synchronous communication boards.
+
+	  These boards provide synchronous serial interfaces to your
+	  Linux box (interfaces currently available are RS-232/V.35, X.21 and
+	  T1/E1). If you wish to support Multilink PPP, please select the
+	  option later and read the file README.mlppp provided by PC300
+	  package.
+
+	  To compile this as a module, choose M here: the module
+	  will be called pc300.
+
+	  If unsure, say N.
+
+config PC300_MLPPP
+	bool "Cyclades-PC300 MLPPP support"
+	depends on PC300 && PPP_MULTILINK && PPP_SYNC_TTY && HDLC_PPP
+	help
+	  Multilink PPP over the PC300 synchronous communication boards.
+
+comment "Cyclades-PC300 MLPPP support is disabled."
+	depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
+
+comment "Refer to the file README.mlppp, provided by PC300 package."
+	depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
+
+endif # WAN
+
+endif # NETDEVICES
diff --git a/drivers/staging/net/Makefile b/drivers/staging/net/Makefile
new file mode 100644
index 0000000..0799c43
--- /dev/null
+++ b/drivers/staging/net/Makefile
@@ -0,0 +1,5 @@
+pc300-y				:= pc300_drv.o
+pc300-$(CONFIG_PC300_MLPPP)	+= pc300_tty.o
+pc300-objs			:= $(pc300-y)
+
+obj-$(CONFIG_PC300)		+= pc300.o
diff --git a/drivers/staging/net/TODO b/drivers/staging/net/TODO
new file mode 100644
index 0000000..e3446f2
--- /dev/null
+++ b/drivers/staging/net/TODO
@@ -0,0 +1,5 @@
+PC300
+The driver is very broken and cannot work with the current TTY layer. It is
+inevitable to convert it to the new TTY API.
+
+If no one steps in to adopt the driver, it will be removed in the 3.7 release.
diff --git a/drivers/net/wan/pc300-falc-lh.h b/drivers/staging/net/pc300-falc-lh.h
similarity index 100%
rename from drivers/net/wan/pc300-falc-lh.h
rename to drivers/staging/net/pc300-falc-lh.h
diff --git a/drivers/net/wan/pc300.h b/drivers/staging/net/pc300.h
similarity index 100%
rename from drivers/net/wan/pc300.h
rename to drivers/staging/net/pc300.h
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/staging/net/pc300_drv.c
similarity index 100%
rename from drivers/net/wan/pc300_drv.c
rename to drivers/staging/net/pc300_drv.c
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/staging/net/pc300_tty.c
similarity index 100%
rename from drivers/net/wan/pc300_tty.c
rename to drivers/staging/net/pc300_tty.c
diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h
index a4c17b0..ba6ed8f 100644
--- a/drivers/staging/nvec/nvec.h
+++ b/drivers/staging/nvec/nvec.h
@@ -42,7 +42,7 @@
  * enum nvec_event_size - The size of an event message
  * @NVEC_2BYTES: The message has one command byte and one data byte
  * @NVEC_3BYTES: The message has one command byte and two data bytes
- * @NVEC_VAR_SIZE: The message has one command byte, one count byte, and as
+ * @NVEC_VAR_SIZE: The message has one command byte, one count byte, and has
  *                 up to as many bytes as the number in the count byte. The
  *                 maximum is 32
  *
diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c
index d91751f..34afc16 100644
--- a/drivers/staging/octeon/ethernet-rx.c
+++ b/drivers/staging/octeon/ethernet-rx.c
@@ -163,7 +163,7 @@
 		/*
 		 * We received a packet with either an alignment error
 		 * or a FCS error. This may be signalling that we are
-		 * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK}
+		 * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK]
 		 * off. If this is the case we need to parse the
 		 * packet to determine if we can remove a non spec
 		 * preamble and generate a correct packet.
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
index 5877b2c..5631dd9 100644
--- a/drivers/staging/octeon/ethernet-tx.c
+++ b/drivers/staging/octeon/ethernet-tx.c
@@ -62,7 +62,7 @@
  * You can define GET_SKBUFF_QOS() to override how the skbuff output
  * function determines which output queue is used. The default
  * implementation always uses the base queue for the port. If, for
- * example, you wanted to use the skb->priority fieid, define
+ * example, you wanted to use the skb->priority field, define
  * GET_SKBUFF_QOS as: #define GET_SKBUFF_QOS(skb) ((skb)->priority)
  */
 #ifndef GET_SKBUFF_QOS
@@ -165,8 +165,8 @@
 #endif
 
 	/*
-	 * Prefetch the private data structure.  It is larger that one
-	 * cache line.
+	 * Prefetch the private data structure.  It is larger than the
+	 * one cache line.
 	 */
 	prefetch(priv);
 
@@ -291,8 +291,8 @@
 	 * See if we can put this skb in the FPA pool. Any strange
 	 * behavior from the Linux networking stack will most likely
 	 * be caused by a bug in the following code. If some field is
-	 * in use by the network stack and get carried over when a
-	 * buffer is reused, bad thing may happen.  If in doubt and
+	 * in use by the network stack and gets carried over when a
+	 * buffer is reused, bad things may happen.  If in doubt and
 	 * you dont need the absolute best performance, disable the
 	 * define REUSE_SKBUFFS_WITHOUT_FREE. The reuse of buffers has
 	 * shown a 25% increase in performance under some loads.
diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h
index 144fb99..2da5ce1 100644
--- a/drivers/staging/octeon/ethernet-util.h
+++ b/drivers/staging/octeon/ethernet-util.h
@@ -38,7 +38,7 @@
 }
 
 /**
- * INTERFACE - convert IPD port to locgical interface
+ * INTERFACE - convert IPD port to logical interface
  * @ipd_port: Port to check
  *
  * Returns Logical interface
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 60cba81..18f7a79 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -357,7 +357,7 @@
 			/* Force accept multicast packets */
 			control.s.mcst = 2;
 		else
-			/* Force reject multicat packets */
+			/* Force reject multicast packets */
 			control.s.mcst = 1;
 
 		if (dev->flags & IFF_PROMISC)
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 3d91993..992275c 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -71,8 +71,8 @@
 
 	ver = dcon_read(dcon, DCON_REG_ID);
 	if ((ver >> 8) != 0xDC) {
-		printk(KERN_ERR "olpc-dcon:  DCON ID not 0xDCxx: 0x%04x "
-				"instead.\n", ver);
+		printk(KERN_ERR "olpc-dcon:  DCON ID not 0xDCxx: 0x%04x instead.\n",
+			ver);
 		rc = -ENXIO;
 		goto err;
 	}
@@ -134,10 +134,10 @@
 power_up:
 	if (is_powered_down) {
 		x = 1;
-		x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
+		x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
 		if (x) {
-			printk(KERN_WARNING "olpc-dcon:  unable to force dcon "
-					"to power up: %d!\n", x);
+			printk(KERN_WARNING "olpc-dcon:  unable to force dcon to power up: %d!\n",
+				x);
 			return x;
 		}
 		msleep(10); /* we'll be conservative */
@@ -150,11 +150,10 @@
 		x = dcon_read(dcon, DCON_REG_ID);
 	}
 	if (x < 0) {
-		printk(KERN_ERR "olpc-dcon:  unable to stabilize dcon's "
-				"smbus, reasserting power and praying.\n");
+		printk(KERN_ERR "olpc-dcon:  unable to stabilize dcon's smbus, reasserting power and praying.\n");
 		BUG_ON(olpc_board_at_least(olpc_board(0xc2)));
 		x = 0;
-		olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
+		olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
 		msleep(100);
 		is_powered_down = 1;
 		goto power_up;	/* argh, stupid hardware.. */
@@ -220,10 +219,10 @@
 
 	if (sleep) {
 		x = 0;
-		x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
+		x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
 		if (x)
-			printk(KERN_WARNING "olpc-dcon:  unable to force dcon "
-					"to power down: %d!\n", x);
+			printk(KERN_WARNING "olpc-dcon:  unable to force dcon to power down: %d!\n",
+				x);
 		else
 			dcon->asleep = sleep;
 	} else {
@@ -232,8 +231,8 @@
 			dcon->disp_mode |= MODE_BL_ENABLE;
 		x = dcon_bus_stabilize(dcon, 1);
 		if (x)
-			printk(KERN_WARNING "olpc-dcon:  unable to reinit dcon"
-					" hardware: %d!\n", x);
+			printk(KERN_WARNING "olpc-dcon:  unable to reinit dcon hardware: %d!\n",
+				x);
 		else
 			dcon->asleep = sleep;
 
@@ -304,7 +303,7 @@
 
 	switch (source) {
 	case DCON_SOURCE_CPU:
-		printk("dcon_source_switch to CPU\n");
+		printk(KERN_INFO "dcon_source_switch to CPU\n");
 		/* Enable the scanline interrupt bit */
 		if (dcon_write(dcon, DCON_REG_MODE,
 				dcon->disp_mode | MODE_SCAN_INT))
@@ -599,7 +598,7 @@
 	struct fb_event *evdata = data;
 	struct dcon_priv *dcon = container_of(self, struct dcon_priv,
 			fbevent_nb);
-	int *blank = (int *) evdata->data;
+	int *blank = (int *)evdata->data;
 	if (((event != FB_EVENT_BLANK) && (event != FB_EVENT_CONBLANK)) ||
 			dcon->ignore_fb_events)
 		return 0;
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
index cb6ce0c..c87fdfa 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
@@ -116,7 +116,7 @@
 	cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS);
 	cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_STS);
 
-	/* FIXME:  Clear the posiitive status as well, just to be sure */
+	/* FIXME:  Clear the positive status as well, just to be sure */
 	cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_POSITIVE_EDGE_STS);
 	cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_POSITIVE_EDGE_STS);
 
diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile
index d9cdc12..1ca0e00 100644
--- a/drivers/staging/omapdrm/Makefile
+++ b/drivers/staging/omapdrm/Makefile
@@ -13,6 +13,7 @@
 	omap_fb.o \
 	omap_fbdev.o \
 	omap_gem.o \
+	omap_gem_dmabuf.o \
 	omap_dmm_tiler.o \
 	tcm-sita.o
 
diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c
index 1ecb6a7..9d83060 100644
--- a/drivers/staging/omapdrm/omap_dmm_tiler.c
+++ b/drivers/staging/omapdrm/omap_dmm_tiler.c
@@ -347,7 +347,7 @@
 	ret = tcm_reserve_2d(containers[fmt], w, h, align, &block->area);
 	if (ret) {
 		kfree(block);
-		return 0;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	/* add to allocation list */
@@ -371,7 +371,7 @@
 	if (tcm_reserve_1d(containers[TILFMT_PAGE], num_pages,
 				&block->area)) {
 		kfree(block);
-		return 0;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	spin_lock(&omap_dmm->list_lock);
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 620b8d5..0d2acca 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -746,7 +746,7 @@
 
 static struct drm_driver omap_drm_driver = {
 		.driver_features =
-				DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM,
+				DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
 		.load = dev_load,
 		.unload = dev_unload,
 		.open = dev_open,
@@ -766,6 +766,10 @@
 		.debugfs_init = omap_debugfs_init,
 		.debugfs_cleanup = omap_debugfs_cleanup,
 #endif
+		.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+		.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+		.gem_prime_export = omap_gem_prime_export,
+		.gem_prime_import = omap_gem_prime_import,
 		.gem_init_object = omap_gem_init_object,
 		.gem_free_object = omap_gem_free_object,
 		.gem_vm_ops = &omap_gem_vm_ops,
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index b7e0f07..f238d57 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -138,6 +138,8 @@
 int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
 		struct drm_mode_create_dumb *args);
 int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+int omap_gem_mmap_obj(struct drm_gem_object *obj,
+		struct vm_area_struct *vma);
 int omap_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int omap_gem_op_start(struct drm_gem_object *obj, enum omap_gem_op op);
 int omap_gem_op_finish(struct drm_gem_object *obj, enum omap_gem_op op);
@@ -145,12 +147,24 @@
 int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
 		void (*fxn)(void *arg), void *arg);
 int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll);
+void omap_gem_cpu_sync(struct drm_gem_object *obj, int pgoff);
+void omap_gem_dma_sync(struct drm_gem_object *obj,
+		enum dma_data_direction dir);
 int omap_gem_get_paddr(struct drm_gem_object *obj,
 		dma_addr_t *paddr, bool remap);
 int omap_gem_put_paddr(struct drm_gem_object *obj);
+int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages,
+		bool remap);
+int omap_gem_put_pages(struct drm_gem_object *obj);
+uint32_t omap_gem_flags(struct drm_gem_object *obj);
 uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj);
 size_t omap_gem_mmap_size(struct drm_gem_object *obj);
 
+struct dma_buf * omap_gem_prime_export(struct drm_device *dev,
+		struct drm_gem_object *obj, int flags);
+struct drm_gem_object * omap_gem_prime_import(struct drm_device *dev,
+		struct dma_buf *buffer);
+
 static inline int align_pitch(int pitch, int width, int bpp)
 {
 	int bytespp = (bpp + 7) / 8;
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 04b235b..74260f0 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -167,7 +167,7 @@
 }
 
 /* Call for unpin 'a' (if not NULL), and pin 'b' (if not NULL).  Although
- * buffers to unpin are just just pushed to the unpin fifo so that the
+ * buffers to unpin are just pushed to the unpin fifo so that the
  * caller can defer unpin until vblank.
  *
  * Note if this fails (ie. something went very wrong!), all buffers are
@@ -197,8 +197,11 @@
 			pa->paddr = 0;
 		}
 
-		if (pb && !ret)
+		if (pb && !ret) {
 			ret = omap_gem_get_paddr(pb->bo, &pb->paddr, true);
+			if (!ret)
+				omap_gem_dma_sync(pb->bo, DMA_TO_DEVICE);
+		}
 	}
 
 	if (ret) {
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c
index 921f058..3a0d035 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -207,13 +207,27 @@
 	return obj->filp != NULL;
 }
 
+/**
+ * shmem buffers that are mapped cached can simulate coherency via using
+ * page faulting to keep track of dirty pages
+ */
+static inline bool is_cached_coherent(struct drm_gem_object *obj)
+{
+	struct omap_gem_object *omap_obj = to_omap_bo(obj);
+	return is_shmem(obj) &&
+		((omap_obj->flags & OMAP_BO_CACHE_MASK) == OMAP_BO_CACHED);
+}
+
 static DEFINE_SPINLOCK(sync_lock);
 
 /** ensure backing pages are allocated */
 static int omap_gem_attach_pages(struct drm_gem_object *obj)
 {
+	struct drm_device *dev = obj->dev;
 	struct omap_gem_object *omap_obj = to_omap_bo(obj);
 	struct page **pages;
+	int i, npages = obj->size >> PAGE_SHIFT;
+	dma_addr_t *addrs;
 
 	WARN_ON(omap_obj->pages);
 
@@ -231,16 +245,18 @@
 	 * DSS, GPU, etc. are not cache coherent:
 	 */
 	if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) {
-		int i, npages = obj->size >> PAGE_SHIFT;
-		dma_addr_t *addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL);
+		addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL);
 		for (i = 0; i < npages; i++) {
-			addrs[i] = dma_map_page(obj->dev->dev, pages[i],
+			addrs[i] = dma_map_page(dev->dev, pages[i],
 					0, PAGE_SIZE, DMA_BIDIRECTIONAL);
 		}
-		omap_obj->addrs = addrs;
+	} else {
+		addrs = kzalloc(npages * sizeof(addrs), GFP_KERNEL);
 	}
 
+	omap_obj->addrs = addrs;
 	omap_obj->pages = pages;
+
 	return 0;
 }
 
@@ -258,14 +274,21 @@
 			dma_unmap_page(obj->dev->dev, omap_obj->addrs[i],
 					PAGE_SIZE, DMA_BIDIRECTIONAL);
 		}
-		kfree(omap_obj->addrs);
-		omap_obj->addrs = NULL;
 	}
 
+	kfree(omap_obj->addrs);
+	omap_obj->addrs = NULL;
+
 	_drm_gem_put_pages(obj, omap_obj->pages, true, false);
 	omap_obj->pages = NULL;
 }
 
+/* get buffer flags */
+uint32_t omap_gem_flags(struct drm_gem_object *obj)
+{
+	return to_omap_bo(obj)->flags;
+}
+
 /** get mmap offset */
 static uint64_t mmap_offset(struct drm_gem_object *obj)
 {
@@ -330,6 +353,7 @@
 			vma->vm_start) >> PAGE_SHIFT;
 
 	if (omap_obj->pages) {
+		omap_gem_cpu_sync(obj, pgoff);
 		pfn = page_to_pfn(omap_obj->pages[pgoff]);
 	} else {
 		BUG_ON(!(omap_obj->flags & OMAP_BO_DMA));
@@ -504,7 +528,6 @@
 /** We override mainly to fix up some of the vm mapping flags.. */
 int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 {
-	struct omap_gem_object *omap_obj;
 	int ret;
 
 	ret = drm_gem_mmap(filp, vma);
@@ -513,8 +536,13 @@
 		return ret;
 	}
 
-	/* after drm_gem_mmap(), it is safe to access the obj */
-	omap_obj = to_omap_bo(vma->vm_private_data);
+	return omap_gem_mmap_obj(vma->vm_private_data, vma);
+}
+
+int omap_gem_mmap_obj(struct drm_gem_object *obj,
+		struct vm_area_struct *vma)
+{
+	struct omap_gem_object *omap_obj = to_omap_bo(obj);
 
 	vma->vm_flags &= ~VM_PFNMAP;
 	vma->vm_flags |= VM_MIXEDMAP;
@@ -524,12 +552,31 @@
 	} else if (omap_obj->flags & OMAP_BO_UNCACHED) {
 		vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags));
 	} else {
+		/*
+		 * We do have some private objects, at least for scanout buffers
+		 * on hardware without DMM/TILER.  But these are allocated write-
+		 * combine
+		 */
+		if (WARN_ON(!obj->filp))
+			return -EINVAL;
+
+		/*
+		 * Shunt off cached objs to shmem file so they have their own
+		 * address_space (so unmap_mapping_range does what we want,
+		 * in particular in the case of mmap'd dmabufs)
+		 */
+		fput(vma->vm_file);
+		get_file(obj->filp);
+		vma->vm_pgoff = 0;
+		vma->vm_file  = obj->filp;
+
 		vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
 	}
 
-	return ret;
+	return 0;
 }
 
+
 /**
  * omap_gem_dumb_create	-	create a dumb buffer
  * @drm_file: our client file
@@ -639,6 +686,48 @@
 	return ret;
 }
 
+/* Sync the buffer for CPU access.. note pages should already be
+ * attached, ie. omap_gem_get_pages()
+ */
+void omap_gem_cpu_sync(struct drm_gem_object *obj, int pgoff)
+{
+	struct drm_device *dev = obj->dev;
+	struct omap_gem_object *omap_obj = to_omap_bo(obj);
+
+	if (is_cached_coherent(obj) && omap_obj->addrs[pgoff]) {
+		dma_unmap_page(dev->dev, omap_obj->addrs[pgoff],
+				PAGE_SIZE, DMA_BIDIRECTIONAL);
+		omap_obj->addrs[pgoff] = 0;
+	}
+}
+
+/* sync the buffer for DMA access */
+void omap_gem_dma_sync(struct drm_gem_object *obj,
+		enum dma_data_direction dir)
+{
+	struct drm_device *dev = obj->dev;
+	struct omap_gem_object *omap_obj = to_omap_bo(obj);
+
+	if (is_cached_coherent(obj)) {
+		int i, npages = obj->size >> PAGE_SHIFT;
+		struct page **pages = omap_obj->pages;
+		bool dirty = false;
+
+		for (i = 0; i < npages; i++) {
+			if (!omap_obj->addrs[i]) {
+				omap_obj->addrs[i] = dma_map_page(dev->dev, pages[i], 0,
+						PAGE_SIZE, DMA_BIDIRECTIONAL);
+				dirty = true;
+			}
+		}
+
+		if (dirty) {
+			unmap_mapping_range(obj->filp->f_mapping, 0,
+					omap_gem_mmap_size(obj), 1);
+		}
+	}
+}
+
 /* Get physical address for DMA.. if 'remap' is true, and the buffer is not
  * already contiguous, remap it to pin in physically contiguous memory.. (ie.
  * map in TILER)
@@ -703,6 +792,7 @@
 		*paddr = omap_obj->paddr;
 	} else {
 		ret = -EINVAL;
+		goto fail;
 	}
 
 fail:
@@ -764,9 +854,27 @@
 	return 0;
 }
 
-int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages)
+/* if !remap, and we don't have pages backing, then fail, rather than
+ * increasing the pin count (which we don't really do yet anyways,
+ * because we don't support swapping pages back out).  And 'remap'
+ * might not be quite the right name, but I wanted to keep it working
+ * similarly to omap_gem_get_paddr().  Note though that mutex is not
+ * aquired if !remap (because this can be called in atomic ctxt),
+ * but probably omap_gem_get_paddr() should be changed to work in the
+ * same way.  If !remap, a matching omap_gem_put_pages() call is not
+ * required (and should not be made).
+ */
+int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages,
+		bool remap)
 {
 	int ret;
+	if (!remap) {
+		struct omap_gem_object *omap_obj = to_omap_bo(obj);
+		if (!omap_obj->pages)
+			return -ENOMEM;
+		*pages = omap_obj->pages;
+		return 0;
+	}
 	mutex_lock(&obj->dev->struct_mutex);
 	ret = get_pages(obj, pages);
 	mutex_unlock(&obj->dev->struct_mutex);
diff --git a/drivers/staging/omapdrm/omap_gem_dmabuf.c b/drivers/staging/omapdrm/omap_gem_dmabuf.c
new file mode 100644
index 0000000..42728e0
--- /dev/null
+++ b/drivers/staging/omapdrm/omap_gem_dmabuf.c
@@ -0,0 +1,220 @@
+/*
+ * drivers/staging/omapdrm/omap_gem_dmabuf.c
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Rob Clark <rob.clark@linaro.org>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "omap_drv.h"
+
+#include <linux/dma-buf.h>
+
+static struct sg_table *omap_gem_map_dma_buf(
+		struct dma_buf_attachment *attachment,
+		enum dma_data_direction dir)
+{
+	struct drm_gem_object *obj = attachment->dmabuf->priv;
+	struct sg_table *sg;
+	dma_addr_t paddr;
+	int ret;
+
+	sg = kzalloc(sizeof(*sg), GFP_KERNEL);
+	if (!sg)
+		return ERR_PTR(-ENOMEM);
+
+	/* camera, etc, need physically contiguous.. but we need a
+	 * better way to know this..
+	 */
+	ret = omap_gem_get_paddr(obj, &paddr, true);
+	if (ret)
+		goto out;
+
+	ret = sg_alloc_table(sg, 1, GFP_KERNEL);
+	if (ret)
+		goto out;
+
+	sg_init_table(sg->sgl, 1);
+	sg_dma_len(sg->sgl) = obj->size;
+	sg_set_page(sg->sgl, pfn_to_page(PFN_DOWN(paddr)), obj->size, 0);
+	sg_dma_address(sg->sgl) = paddr;
+
+	/* this should be after _get_paddr() to ensure we have pages attached */
+	omap_gem_dma_sync(obj, dir);
+
+out:
+	if (ret)
+		return ERR_PTR(ret);
+	return sg;
+}
+
+static void omap_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
+		struct sg_table *sg, enum dma_data_direction dir)
+{
+	struct drm_gem_object *obj = attachment->dmabuf->priv;
+	omap_gem_put_paddr(obj);
+	sg_free_table(sg);
+	kfree(sg);
+}
+
+static void omap_gem_dmabuf_release(struct dma_buf *buffer)
+{
+	struct drm_gem_object *obj = buffer->priv;
+	/* release reference that was taken when dmabuf was exported
+	 * in omap_gem_prime_set()..
+	 */
+	drm_gem_object_unreference_unlocked(obj);
+}
+
+
+static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer,
+		size_t start, size_t len, enum dma_data_direction dir)
+{
+	struct drm_gem_object *obj = buffer->priv;
+	struct page **pages;
+	if (omap_gem_flags(obj) & OMAP_BO_TILED) {
+		/* TODO we would need to pin at least part of the buffer to
+		 * get de-tiled view.  For now just reject it.
+		 */
+		return -ENOMEM;
+	}
+	/* make sure we have the pages: */
+	return omap_gem_get_pages(obj, &pages, true);
+}
+
+static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer,
+		size_t start, size_t len, enum dma_data_direction dir)
+{
+	struct drm_gem_object *obj = buffer->priv;
+	omap_gem_put_pages(obj);
+}
+
+
+static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer,
+		unsigned long page_num)
+{
+	struct drm_gem_object *obj = buffer->priv;
+	struct page **pages;
+	omap_gem_get_pages(obj, &pages, false);
+	omap_gem_cpu_sync(obj, page_num);
+	return kmap_atomic(pages[page_num]);
+}
+
+static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer,
+		unsigned long page_num, void *addr)
+{
+	kunmap_atomic(addr);
+}
+
+static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer,
+		unsigned long page_num)
+{
+	struct drm_gem_object *obj = buffer->priv;
+	struct page **pages;
+	omap_gem_get_pages(obj, &pages, false);
+	omap_gem_cpu_sync(obj, page_num);
+	return kmap(pages[page_num]);
+}
+
+static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer,
+		unsigned long page_num, void *addr)
+{
+	struct drm_gem_object *obj = buffer->priv;
+	struct page **pages;
+	omap_gem_get_pages(obj, &pages, false);
+	kunmap(pages[page_num]);
+}
+
+/*
+ * TODO maybe we can split up drm_gem_mmap to avoid duplicating
+ * some here.. or at least have a drm_dmabuf_mmap helper.
+ */
+static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
+		struct vm_area_struct *vma)
+{
+	struct drm_gem_object *obj = buffer->priv;
+	int ret = 0;
+
+	if (WARN_ON(!obj->filp))
+		return -EINVAL;
+
+	/* Check for valid size. */
+	if (omap_gem_mmap_size(obj) < vma->vm_end - vma->vm_start) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	if (!obj->dev->driver->gem_vm_ops) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
+	vma->vm_ops = obj->dev->driver->gem_vm_ops;
+	vma->vm_private_data = obj;
+	vma->vm_page_prot =  pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+
+	/* Take a ref for this mapping of the object, so that the fault
+	 * handler can dereference the mmap offset's pointer to the object.
+	 * This reference is cleaned up by the corresponding vm_close
+	 * (which should happen whether the vma was created by this call, or
+	 * by a vm_open due to mremap or partial unmap or whatever).
+	 */
+	vma->vm_ops->open(vma);
+
+out_unlock:
+
+	return omap_gem_mmap_obj(obj, vma);
+}
+
+struct dma_buf_ops omap_dmabuf_ops = {
+		.map_dma_buf = omap_gem_map_dma_buf,
+		.unmap_dma_buf = omap_gem_unmap_dma_buf,
+		.release = omap_gem_dmabuf_release,
+		.begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
+		.end_cpu_access = omap_gem_dmabuf_end_cpu_access,
+		.kmap_atomic = omap_gem_dmabuf_kmap_atomic,
+		.kunmap_atomic = omap_gem_dmabuf_kunmap_atomic,
+		.kmap = omap_gem_dmabuf_kmap,
+		.kunmap = omap_gem_dmabuf_kunmap,
+		.mmap = omap_gem_dmabuf_mmap,
+};
+
+struct dma_buf * omap_gem_prime_export(struct drm_device *dev,
+		struct drm_gem_object *obj, int flags)
+{
+	return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, 0600);
+}
+
+struct drm_gem_object * omap_gem_prime_import(struct drm_device *dev,
+		struct dma_buf *buffer)
+{
+	struct drm_gem_object *obj;
+
+	/* is this one of own objects? */
+	if (buffer->ops == &omap_dmabuf_ops) {
+		obj = buffer->priv;
+		/* is it from our device? */
+		if (obj->dev == dev) {
+			drm_gem_object_reference(obj);
+			return obj;
+		}
+	}
+
+	/*
+	 * TODO add support for importing buffers from other devices..
+	 * for now we don't need this but would be nice to add eventually
+	 */
+	return ERR_PTR(-EINVAL);
+}
diff --git a/drivers/staging/omapdrm/tcm-sita.c b/drivers/staging/omapdrm/tcm-sita.c
index 10d5ac3..efb6095 100644
--- a/drivers/staging/omapdrm/tcm-sita.c
+++ b/drivers/staging/omapdrm/tcm-sita.c
@@ -200,7 +200,7 @@
  *
  * @param w	width
  * @param h	height
- * @param area	pointer to the area that will be populated with the reesrved
+ * @param area	pointer to the area that will be populated with the reserved
  *		area
  *
  * @return 0 on success, non-0 error value on failure.
diff --git a/drivers/staging/ozwpan/README b/drivers/staging/ozwpan/README
index bb1a69b..7c055ec 100644
--- a/drivers/staging/ozwpan/README
+++ b/drivers/staging/ozwpan/README
@@ -9,7 +9,7 @@
 
 To operate the driver must be bound to a suitable network interface. This can
 be done when the module is loaded (specifying the name of the network interface
-as a paramter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
+as a parameter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
 loading using an ioctl call. See the ozappif.h file and the ioctls
 OZ_IOCTL_ADD_BINDING and OZ_IOCTL_REMOVE_BINDING.
 
diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h
index af02732..1b59b07 100644
--- a/drivers/staging/ozwpan/ozappif.h
+++ b/drivers/staging/ozwpan/ozappif.h
@@ -11,13 +11,13 @@
 #define OZ_IOCTL_MAGIC	0xf4
 
 struct oz_mac_addr {
-	unsigned char a[6];
+	__u8 a[6];
 };
 
 #define OZ_MAX_PDS	8
 
 struct oz_pd_list {
-	int count;
+	__u32 count;
 	struct oz_mac_addr addr[OZ_MAX_PDS];
 };
 
@@ -27,18 +27,10 @@
 	char name[OZ_MAX_BINDING_LEN];
 };
 
-struct oz_test {
-	int action;
-};
-
 #define OZ_IOCTL_GET_PD_LIST	_IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list)
 #define OZ_IOCTL_SET_ACTIVE_PD	_IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr)
 #define OZ_IOCTL_GET_ACTIVE_PD	_IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr)
-#define OZ_IOCTL_CLEAR_EVENTS	_IO(OZ_IOCTL_MAGIC, 3)
-#define OZ_IOCTL_GET_EVENTS	_IOR(OZ_IOCTL_MAGIC, 4, struct oz_evtlist)
 #define OZ_IOCTL_ADD_BINDING	_IOW(OZ_IOCTL_MAGIC, 5, struct oz_binding_info)
-#define OZ_IOCTL_TEST		_IOWR(OZ_IOCTL_MAGIC, 6, struct oz_test)
-#define OZ_IOCTL_SET_EVENT_MASK	_IOW(OZ_IOCTL_MAGIC, 7, unsigned long)
 #define OZ_IOCTL_REMOVE_BINDING	_IOW(OZ_IOCTL_MAGIC, 8, struct oz_binding_info)
 #define OZ_IOCTL_MAX		9
 
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 1c380d6..27325f7 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -41,9 +41,6 @@
 };
 /*------------------------------------------------------------------------------
  */
-int g_taction;
-/*------------------------------------------------------------------------------
- */
 static struct oz_cdev g_cdev;
 /*------------------------------------------------------------------------------
  * Context: process and softirq
@@ -276,20 +273,6 @@
 				return -EFAULT;
 		}
 		break;
-#ifdef WANT_EVENT_TRACE
-	case OZ_IOCTL_CLEAR_EVENTS:
-		oz_events_clear();
-		break;
-	case OZ_IOCTL_GET_EVENTS:
-		rc = oz_events_copy((void __user *)arg);
-		break;
-	case OZ_IOCTL_SET_EVENT_MASK:
-		if (copy_from_user(&g_evt_mask, (void __user *)arg,
-			sizeof(unsigned long))) {
-			return -EFAULT;
-		}
-		break;
-#endif /* WANT_EVENT_TRACE */
 	case OZ_IOCTL_ADD_BINDING:
 	case OZ_IOCTL_REMOVE_BINDING: {
 			struct oz_binding_info b;
diff --git a/drivers/staging/ozwpan/ozevent.c b/drivers/staging/ozwpan/ozevent.c
index 73703d3..7f66b4f 100644
--- a/drivers/staging/ozwpan/ozevent.c
+++ b/drivers/staging/ozwpan/ozevent.c
@@ -5,29 +5,46 @@
  */
 #include "ozconfig.h"
 #ifdef WANT_EVENT_TRACE
+#include <linux/module.h>
+#include <linux/debugfs.h>
 #include <linux/jiffies.h>
 #include <linux/uaccess.h>
 #include "oztrace.h"
 #include "ozevent.h"
+#include "ozappif.h"
 /*------------------------------------------------------------------------------
+ * Although the event mask is logically part of the oz_evtdev structure, it is
+ * needed outside of this file so define it seperately to avoid the need to
+ * export definition of struct oz_evtdev.
  */
-unsigned long g_evt_mask = 0xffffffff;
+u32 g_evt_mask;
 /*------------------------------------------------------------------------------
  */
 #define OZ_MAX_EVTS	2048	/* Must be power of 2 */
-DEFINE_SPINLOCK(g_eventlock);
-static int g_evt_in;
-static int g_evt_out;
-static int g_missed_events;
-static struct oz_event g_events[OZ_MAX_EVTS];
+struct oz_evtdev {
+	struct dentry *root_dir;
+	int evt_in;
+	int evt_out;
+	int missed_events;
+	int present;
+	atomic_t users;
+	spinlock_t lock;
+	struct oz_event evts[OZ_MAX_EVTS];
+};
+
+static struct oz_evtdev g_evtdev;
+
 /*------------------------------------------------------------------------------
  * Context: process
  */
 void oz_event_init(void)
 {
+	/* Because g_evtdev is static external all fields initally zero so no
+	 * need to reinitialised those.
+	 */
 	oz_trace("Event tracing initialized\n");
-	g_evt_in = g_evt_out = 0;
-	g_missed_events = 0;
+	spin_lock_init(&g_evtdev.lock);
+	atomic_set(&g_evtdev.users, 0);
 }
 /*------------------------------------------------------------------------------
  * Context: process
@@ -43,74 +60,136 @@
 {
 	unsigned long irqstate;
 	int ix;
-	spin_lock_irqsave(&g_eventlock, irqstate);
-	ix = (g_evt_in + 1) & (OZ_MAX_EVTS - 1);
-	if (ix != g_evt_out) {
-		struct oz_event *e = &g_events[g_evt_in];
+	spin_lock_irqsave(&g_evtdev.lock, irqstate);
+	ix = (g_evtdev.evt_in + 1) & (OZ_MAX_EVTS - 1);
+	if (ix != g_evtdev.evt_out) {
+		struct oz_event *e = &g_evtdev.evts[g_evtdev.evt_in];
 		e->jiffies = jiffies;
 		e->evt = evt;
 		e->ctx1 = ctx1;
 		e->ctx2 = ctx2;
-		e->ctx3 = ctx3;
+		e->ctx3 = (__u32)(unsigned long)ctx3;
 		e->ctx4 = ctx4;
-		g_evt_in = ix;
+		g_evtdev.evt_in = ix;
 	} else {
-		g_missed_events++;
+		g_evtdev.missed_events++;
 	}
-	spin_unlock_irqrestore(&g_eventlock, irqstate);
+	spin_unlock_irqrestore(&g_evtdev.lock, irqstate);
 }
 /*------------------------------------------------------------------------------
  * Context: process
  */
-int oz_events_copy(struct oz_evtlist __user *lst)
+static void oz_events_clear(struct oz_evtdev *dev)
 {
-	int first;
-	int ix;
-	struct hdr {
-		int count;
-		int missed;
-	} hdr;
-	ix = g_evt_out;
-	hdr.count = g_evt_in - ix;
-	if (hdr.count < 0)
-		hdr.count += OZ_MAX_EVTS;
-	if (hdr.count > OZ_EVT_LIST_SZ)
-		hdr.count = OZ_EVT_LIST_SZ;
-	hdr.missed = g_missed_events;
-	g_missed_events = 0;
-	if (copy_to_user((void __user *)lst, &hdr, sizeof(hdr)))
-		return -EFAULT;
-	first = OZ_MAX_EVTS - ix;
-	if (first > hdr.count)
-		first = hdr.count;
-	if (first) {
-		int sz = first*sizeof(struct oz_event);
-		void __user *p = (void __user *)lst->evts;
-		if (copy_to_user(p, &g_events[ix], sz))
-			return -EFAULT;
-		if (hdr.count > first) {
-			p = (void __user *)&lst->evts[first];
-			sz = (hdr.count-first)*sizeof(struct oz_event);
-			if (copy_to_user(p, g_events, sz))
-				return -EFAULT;
-		}
+	unsigned long irqstate;
+	oz_trace("Clearing events\n");
+	spin_lock_irqsave(&dev->lock, irqstate);
+	dev->evt_in = dev->evt_out = 0;
+	dev->missed_events = 0;
+	spin_unlock_irqrestore(&dev->lock, irqstate);
+}
+#ifdef CONFIG_DEBUG_FS
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_events_open(struct inode *inode, struct file *filp)
+{
+	oz_trace("oz_evt_open()\n");
+	oz_trace("Open flags: 0x%x\n", filp->f_flags);
+	if (atomic_add_return(1, &g_evtdev.users) == 1) {
+		oz_events_clear(&g_evtdev);
+		return nonseekable_open(inode, filp);
+	} else {
+		atomic_dec(&g_evtdev.users);
+		return -EBUSY;
 	}
-	ix += hdr.count;
-	if (ix >= OZ_MAX_EVTS)
-		ix -= OZ_MAX_EVTS;
-	g_evt_out = ix;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_events_release(struct inode *inode, struct file *filp)
+{
+	oz_events_clear(&g_evtdev);
+	atomic_dec(&g_evtdev.users);
+	g_evt_mask = 0;
+	oz_trace("oz_evt_release()\n");
 	return 0;
 }
 /*------------------------------------------------------------------------------
  * Context: process
  */
-void oz_events_clear(void)
+ssize_t oz_events_read(struct file *filp, char __user *buf, size_t count,
+		loff_t *fpos)
 {
-	unsigned long irqstate;
-	spin_lock_irqsave(&g_eventlock, irqstate);
-	g_evt_in = g_evt_out = 0;
-	g_missed_events = 0;
-	spin_unlock_irqrestore(&g_eventlock, irqstate);
-}
-#endif /* WANT_EVENT_TRACE */
+	struct oz_evtdev *dev = &g_evtdev;
+	int rc = 0;
+	int nb_evts = count / sizeof(struct oz_event);
+	int n;
+	int sz;
 
+	n = dev->evt_in - dev->evt_out;
+	if (n < 0)
+		n += OZ_MAX_EVTS;
+	if (nb_evts > n)
+		nb_evts = n;
+	if (nb_evts == 0)
+		goto out;
+	n = OZ_MAX_EVTS - dev->evt_out;
+	if (n > nb_evts)
+		n = nb_evts;
+	sz = n * sizeof(struct oz_event);
+	if (copy_to_user(buf, &dev->evts[dev->evt_out], sz)) {
+		rc = -EFAULT;
+		goto out;
+	}
+	if (n == nb_evts)
+		goto out2;
+	n = nb_evts - n;
+	if (copy_to_user(buf + sz, dev->evts, n * sizeof(struct oz_event))) {
+		rc = -EFAULT;
+		goto out;
+	}
+out2:
+	dev->evt_out = (dev->evt_out + nb_evts) & (OZ_MAX_EVTS - 1);
+	rc = nb_evts * sizeof(struct oz_event);
+out:
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ */
+const struct file_operations oz_events_fops = {
+	.owner =	THIS_MODULE,
+	.open =		oz_events_open,
+	.release =	oz_events_release,
+	.read =		oz_events_read,
+};
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_debugfs_init(void)
+{
+	struct dentry *parent;
+
+	parent = debugfs_create_dir("ozwpan", NULL);
+	if (parent  == NULL) {
+		oz_trace("Failed to create debugfs directory ozmo\n");
+		return;
+	} else {
+		g_evtdev.root_dir = parent;
+		if (debugfs_create_file("events", S_IRUSR, parent, NULL,
+						&oz_events_fops) == NULL)
+			oz_trace("Failed to create file ozmo/events\n");
+		if (debugfs_create_x32("event_mask", S_IRUSR | S_IWUSR, parent,
+							&g_evt_mask) == NULL)
+			oz_trace("Failed to create file ozmo/event_mask\n");
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_debugfs_remove(void)
+{
+	debugfs_remove_recursive(g_evtdev.root_dir);
+}
+#endif /* CONFIG_DEBUG_FS */
+#endif /* WANT_EVENT_TRACE */
diff --git a/drivers/staging/ozwpan/ozevent.h b/drivers/staging/ozwpan/ozevent.h
index f033d01..32f6f98 100644
--- a/drivers/staging/ozwpan/ozevent.h
+++ b/drivers/staging/ozwpan/ozevent.h
@@ -9,23 +9,24 @@
 #include "ozeventdef.h"
 
 #ifdef WANT_EVENT_TRACE
-extern unsigned long g_evt_mask;
+extern u32 g_evt_mask;
 void oz_event_init(void);
 void oz_event_term(void);
 void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4);
+void oz_debugfs_init(void);
+void oz_debugfs_remove(void);
 #define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4) \
 	do { \
 		if ((1<<(__evt)) & g_evt_mask) \
 			oz_event_log2(__evt, __ctx1, __ctx2, __ctx3, __ctx4); \
 	} while (0)
-int oz_events_copy(struct oz_evtlist __user *lst);
-void oz_events_clear(void);
+
 #else
 #define oz_event_init()
 #define oz_event_term()
 #define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4)
-#define oz_events_copy(__lst)
-#define oz_events_clear()
+#define oz_debugfs_init()
+#define oz_debugfs_remove()
 #endif /* WANT_EVENT_TRACE */
 
 #endif /* _OZEVENT_H */
diff --git a/drivers/staging/ozwpan/ozeventdef.h b/drivers/staging/ozwpan/ozeventdef.h
index a880288..4b93898 100644
--- a/drivers/staging/ozwpan/ozeventdef.h
+++ b/drivers/staging/ozwpan/ozeventdef.h
@@ -29,19 +29,12 @@
 #define OZ_EVT_DEBUG		20
 
 struct oz_event {
-	unsigned long jiffies;
-	unsigned char evt;
-	unsigned char ctx1;
-	unsigned short ctx2;
-	void *ctx3;
-	unsigned ctx4;
-};
-
-#define OZ_EVT_LIST_SZ	64
-struct oz_evtlist {
-	int count;
-	int missed;
-	struct oz_event evts[OZ_EVT_LIST_SZ];
+	__u32 jiffies;
+	__u8 evt;
+	__u8 ctx1;
+	__u16 ctx2;
+	__u32 ctx3;
+	__u32 ctx4;
 };
 
 #endif /* _OZEVENTDEF_H */
diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c
index 750b14e..251f07c 100644
--- a/drivers/staging/ozwpan/ozhcd.c
+++ b/drivers/staging/ozwpan/ozhcd.c
@@ -1416,7 +1416,7 @@
 			oz_trace("USB_REQ_SET_CONFIGURATION - req\n");
 			break;
 		case USB_REQ_GET_CONFIGURATION:
-			/* We short curcuit this case and reply directly since
+			/* We short circuit this case and reply directly since
 			 * we have the selected configuration number cached.
 			 */
 			oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
@@ -1432,7 +1432,7 @@
 			}
 			break;
 		case USB_REQ_GET_INTERFACE:
-			/* We short curcuit this case and reply directly since
+			/* We short circuit this case and reply directly since
 			 * we have the selected interface alternative cached.
 			 */
 			oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
@@ -1463,7 +1463,7 @@
 			rc = -ENOMEM;
 		} else {
 			/* Note: we are queuing the request after we have
-			 * submitted it to be tranmitted. If the request were
+			 * submitted it to be transmitted. If the request were
 			 * to complete before we queued it then it would not
 			 * be found in the queue. It seems impossible for
 			 * this to happen but if it did the request would
diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c
index aaf2ccc..7579645 100644
--- a/drivers/staging/ozwpan/ozmain.c
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -33,6 +33,9 @@
 	oz_protocol_init(g_net_dev);
 	oz_app_enable(OZ_APPID_USB, 1);
 	oz_apps_init();
+#ifdef CONFIG_DEBUG_FS
+	oz_debugfs_init();
+#endif
 	return 0;
 }
 /*------------------------------------------------------------------------------
@@ -44,6 +47,9 @@
 	oz_apps_term();
 	oz_cdev_deregister();
 	oz_event_term();
+#ifdef CONFIG_DEBUG_FS
+	oz_debugfs_remove();
+#endif
 }
 /*------------------------------------------------------------------------------
  */
@@ -53,6 +59,6 @@
 
 MODULE_AUTHOR("Chris Kelly");
 MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
-MODULE_VERSION("1.0.8");
+MODULE_VERSION("1.0.9");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/staging/ozwpan/ozusbsvc.c b/drivers/staging/ozwpan/ozusbsvc.c
index 9e74f96..8fa7f25 100644
--- a/drivers/staging/ozwpan/ozusbsvc.c
+++ b/drivers/staging/ozwpan/ozusbsvc.c
@@ -7,7 +7,7 @@
  * The implementation of this service is split into two parts the first of which
  * is protocol independent and the second contains protocol specific details.
  * This split is to allow alternative protocols to be defined.
- * The implemenation of this service uses ozhcd.c to implement a USB HCD.
+ * The implementation of this service uses ozhcd.c to implement a USB HCD.
  * -----------------------------------------------------------------------------
  */
 #include <linux/init.h>
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 6183573..7365089 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -754,7 +754,7 @@
 	if (lcd_bl_pin == PIN_NONE)
 		return;
 
-	/* The backlight is activated by seting the AUTOFEED line to +5V  */
+	/* The backlight is activated by setting the AUTOFEED line to +5V  */
 	spin_lock(&pprt_lock);
 	bits.bl = on;
 	panel_set_bits();
diff --git a/drivers/staging/quatech_usb2/Kconfig b/drivers/staging/quatech_usb2/Kconfig
deleted file mode 100644
index 1494f42..0000000
--- a/drivers/staging/quatech_usb2/Kconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-config USB_SERIAL_QUATECH_USB2
-	tristate "USB Quatech xSU2-[14]00 USB Serial Driver"
-	depends on USB_SERIAL
-	help
-	  Say Y here if you want to use a Quatech USB2.0 to serial adaptor. This
-	  driver supports the SSU2-100, DSU2-100, DSU2-400, QSU2-100, QSU2-400,
-	  ESU2-400 and ESU2-100 USB2.0 to RS232 / 485 / 422 serial adaptors.
-
-	  Some hardware has an incorrect product string and announces itself as
-	  ESU-100 (which uses the serqt driver) even though it is an ESU2-100.
-	  Check the label on the bottom of your device.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called quatech_usb2 .
-
diff --git a/drivers/staging/quatech_usb2/Makefile b/drivers/staging/quatech_usb2/Makefile
deleted file mode 100644
index bcd1f89..0000000
--- a/drivers/staging/quatech_usb2/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_USB_SERIAL_QUATECH_USB2)		+= quatech_usb2.o
diff --git a/drivers/staging/quatech_usb2/TODO b/drivers/staging/quatech_usb2/TODO
deleted file mode 100644
index 67f61db..0000000
--- a/drivers/staging/quatech_usb2/TODO
+++ /dev/null
@@ -1,8 +0,0 @@
-Incomplete list of things that this driver does not yet implement completely or
-at all. some of these may not be possible to implement because the hardware
-support does not exist. Others may be possible, but the magic control codes to
-make them happen are unknown, and some may just need the driver support to
-implement them writing.
-
-* Mark/Space parity is not implemented (reported back correctly)
-* IXANY flow control mode is not implemented (flag ignored completely)
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c
deleted file mode 100644
index bb977e0..0000000
--- a/drivers/staging/quatech_usb2/quatech_usb2.c
+++ /dev/null
@@ -1,1976 +0,0 @@
-/*
- * Driver for Quatech Inc USB2.0 to serial adaptors. Largely unrelated to the
- * serqt_usb driver, based on a re-write of the vendor supplied serqt_usb2 code,
- * which is unrelated to the serqt_usb2 in the staging kernel
- */
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static bool debug;
-
-/* Version Information */
-#define DRIVER_VERSION "v2.00"
-#define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc"
-#define DRIVER_DESC "Quatech USB 2.0 to Serial Driver"
-
-/* vendor and device IDs */
-#define	USB_VENDOR_ID_QUATECH 0x061d	/* Quatech VID */
-#define QUATECH_SSU2_100 0xC120		/* RS232 single port */
-#define QUATECH_DSU2_100 0xC140		/* RS232 dual port */
-#define QUATECH_DSU2_400 0xC150		/* RS232/422/485 dual port */
-#define QUATECH_QSU2_100 0xC160		/* RS232 four port */
-#define QUATECH_QSU2_400 0xC170		/* RS232/422/485 four port */
-#define QUATECH_ESU2_100 0xC1A0		/* RS232 eight port */
-#define QUATECH_ESU2_400 0xC180		/* RS232/422/485 eight port */
-
-/* magic numbers go here, when we find out which ones are needed */
-
-#define QU2BOXPWRON 0x8000		/* magic number to turn FPGA power on */
-#define QU2BOX232 0x40			/* RS232 mode on MEI devices */
-#define QU2BOXSPD9600 0x60		/* set speed to 9600 baud */
-#define QT2_FIFO_DEPTH 1024			/* size of hardware fifos */
-#define QT2_TX_HEADER_LENGTH	5
-/* length of the header sent to the box with each write URB */
-
-/* directions for USB transfers */
-#define USBD_TRANSFER_DIRECTION_IN    0xc0
-#define USBD_TRANSFER_DIRECTION_OUT   0x40
-
-/* special Quatech command IDs. These are pushed down the
- USB control pipe to get the box on the end to do things */
-#define QT_SET_GET_DEVICE		0xc2
-#define QT_OPEN_CLOSE_CHANNEL		0xca
-/*#define QT_GET_SET_PREBUF_TRIG_LVL	0xcc
-#define QT_SET_ATF			0xcd*/
-#define QT2_GET_SET_REGISTER			0xc0
-#define QT2_GET_SET_UART			0xc1
-#define QT2_HW_FLOW_CONTROL_MASK		0xc5
-#define QT2_SW_FLOW_CONTROL_MASK		0xc6
-#define QT2_SW_FLOW_CONTROL_DISABLE		0xc7
-#define QT2_BREAK_CONTROL			0xc8
-#define QT2_STOP_RECEIVE			0xe0
-#define QT2_FLUSH_DEVICE			0xc4
-#define QT2_GET_SET_QMCR			0xe1
-
-/* sorts of flush we can do on */
-#define QT2_FLUSH_RX			0x00
-#define QT2_FLUSH_TX			0x01
-
-/* port setting constants, used to set up serial port speeds, flow
- * control and so on */
-#define QT2_SERIAL_MCR_DTR	0x01
-#define QT2_SERIAL_MCR_RTS	0x02
-#define QT2_SERIAL_MCR_LOOP	0x10
-
-#define QT2_SERIAL_MSR_CTS	0x10
-#define QT2_SERIAL_MSR_CD	0x80
-#define QT2_SERIAL_MSR_RI	0x40
-#define QT2_SERIAL_MSR_DSR	0x20
-#define QT2_SERIAL_MSR_MASK	0xf0
-
-#define QT2_SERIAL_8_DATA	0x03
-#define QT2_SERIAL_7_DATA	0x02
-#define QT2_SERIAL_6_DATA	0x01
-#define QT2_SERIAL_5_DATA	0x00
-
-#define QT2_SERIAL_ODD_PARITY	0x08
-#define QT2_SERIAL_EVEN_PARITY	0x18
-#define QT2_SERIAL_TWO_STOPB	0x04
-#define QT2_SERIAL_ONE_STOPB	0x00
-
-#define QT2_MAX_BAUD_RATE	921600
-#define QT2_MAX_BAUD_REMAINDER	4608
-
-#define QT2_SERIAL_LSR_OE	0x02
-#define QT2_SERIAL_LSR_PE	0x04
-#define QT2_SERIAL_LSR_FE	0x08
-#define QT2_SERIAL_LSR_BI	0x10
-
-/* value of Line Status Register when UART has completed
- * emptying data out on the line */
-#define QT2_LSR_TEMT     0x40
-
-/* register numbers on each UART, for use with  qt2_box_[get|set]_register*/
-#define  QT2_XMT_HOLD_REGISTER          0x00
-#define  QT2_XVR_BUFFER_REGISTER        0x00
-#define  QT2_FIFO_CONTROL_REGISTER      0x02
-#define  QT2_LINE_CONTROL_REGISTER      0x03
-#define  QT2_MODEM_CONTROL_REGISTER     0x04
-#define  QT2_LINE_STATUS_REGISTER       0x05
-#define  QT2_MODEM_STATUS_REGISTER      0x06
-
-/* handy macros for doing escape sequence parsing on data reads */
-#define THISCHAR	((unsigned char *)(urb->transfer_buffer))[i]
-#define NEXTCHAR	((unsigned char *)(urb->transfer_buffer))[i + 1]
-#define THIRDCHAR	((unsigned char *)(urb->transfer_buffer))[i + 2]
-#define FOURTHCHAR	((unsigned char *)(urb->transfer_buffer))[i + 3]
-#define FIFTHCHAR	((unsigned char *)(urb->transfer_buffer))[i + 4]
-
-static const struct usb_device_id quausb2_id_table[] = {
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)},
-	{}	/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, quausb2_id_table);
-
-/* custom structures we need go here */
-static struct usb_driver quausb2_usb_driver = {
-	.name = "quatech-usb2-serial",
-	.probe = usb_serial_probe,
-	.disconnect = usb_serial_disconnect,
-	.id_table = quausb2_id_table,
-};
-
-/**
- * quatech2_port: Structure in which to keep all the messy stuff that this
- * driver needs alongside the usb_serial_port structure
- * @read_urb_busy: Flag indicating that port->read_urb is in use
- * @close_pending: flag indicating that this port is in the process of
- * being closed (and so no new reads / writes should be started).
- * @shadowLSR: Last received state of the line status register, holds the
- * value of the line status flags from the port
- * @shadowMSR: Last received state of the modem status register, holds
- * the value of the modem status received from the port
- * @rcv_flush: Flag indicating that a receive flush has occurred on
- * the hardware.
- * @xmit_flush: Flag indicating that a transmit flush has been processed by
- * the hardware.
- * @tx_pending_bytes: Number of bytes waiting to be sent. This total
- * includes the size (excluding header) of URBs that have been submitted but
- * have not yet been sent to to the device, and bytes that have been sent out
- * of the port but not yet reported sent by the "xmit_empty" messages (which
- * indicate the number of bytes sent each time they are received, despite the
- * misleading name).
- * - Starts at zero when port is initialised.
- * - is incremented by the size of the data to be written (no headers)
- * each time a write urb is dispatched.
- * - is decremented each time a "transmit empty" message is received
- * by the driver in the data stream.
- * @lock: Mutex to lock access to this structure when we need to ensure that
- * races don't occur to access bits of it.
- * @open_count: The number of uses of the port currently having
- * it open, i.e. the reference count.
- */
-struct quatech2_port {
-	int	magic;
-	bool	read_urb_busy;
-	bool	close_pending;
-	__u8	shadowLSR;
-	__u8	shadowMSR;
-	bool	rcv_flush;
-	bool	xmit_flush;
-	int	tx_pending_bytes;
-	struct mutex modelock;
-	int	open_count;
-
-	char	active;		/* someone has this device open */
-	unsigned char		*xfer_to_tty_buffer;
-	wait_queue_head_t	wait;
-	__u8	shadowLCR;	/* last LCR value received */
-	__u8	shadowMCR;	/* last MCR value received */
-	char	RxHolding;
-	struct semaphore	pend_xmit_sem;	/* locks this structure */
-	spinlock_t lock;
-};
-
-/**
- * Structure to hold device-wide internal status information
- * @param ReadBulkStopped The last bulk read attempt ended in tears
- * @param open_ports The number of serial ports currently in use on the box
- * @param current_port Pointer to the serial port structure of the port which
- * the read stream is currently directed to. Escape sequences in the read
- * stream will change this around as data arrives from different ports on the
- * box
- * @buffer_size: The max size buffer each URB can take, used to set the size of
- * the buffers allocated for writing to each port on the device (we need to
- * store this because it is known only to the endpoint, but used each time a
- * port is opened and a new buffer is allocated.
- */
-struct quatech2_dev {
-	bool	ReadBulkStopped;
-	char	open_ports;
-	struct usb_serial_port *current_port;
-	int	buffer_size;
-};
-
-/* structure which holds line and modem status flags */
-struct qt2_status_data {
-	__u8 line_status;
-	__u8 modem_status;
-};
-
-/* Function prototypes */
-static int qt2_boxpoweron(struct usb_serial *serial);
-static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number,
-			__u8 QMCR_Value);
-static int port_paranoia_check(struct usb_serial_port *port,
-			const char *function);
-static int serial_paranoia_check(struct usb_serial *serial,
-			 const char *function);
-static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port
-			*port);
-static inline void qt2_set_port_private(struct usb_serial_port *port,
-			struct quatech2_port *data);
-static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial
-			*serial);
-static inline void qt2_set_dev_private(struct usb_serial *serial,
-			struct quatech2_dev *data);
-static int qt2_openboxchannel(struct usb_serial *serial, __u16
-			Uart_Number, struct qt2_status_data *pDeviceData);
-static int qt2_closeboxchannel(struct usb_serial *serial, __u16
-			Uart_Number);
-static int qt2_conf_uart(struct usb_serial *serial,  unsigned short Uart_Number,
-			 unsigned short divisor, unsigned char LCR);
-static void qt2_read_bulk_callback(struct urb *urb);
-static void qt2_write_bulk_callback(struct urb *urb);
-static void qt2_process_line_status(struct usb_serial_port *port,
-			      unsigned char LineStatus);
-static void qt2_process_modem_status(struct usb_serial_port *port,
-			       unsigned char ModemStatus);
-static void qt2_process_xmit_empty(struct usb_serial_port *port,
-	unsigned char fourth_char, unsigned char fifth_char);
-static void qt2_process_port_change(struct usb_serial_port *port,
-			      unsigned char New_Current_Port);
-static void qt2_process_rcv_flush(struct usb_serial_port *port);
-static void qt2_process_xmit_flush(struct usb_serial_port *port);
-static void qt2_process_rx_char(struct usb_serial_port *port,
-				unsigned char data);
-static int qt2_box_get_register(struct usb_serial *serial,
-		unsigned char uart_number, unsigned short register_num,
-		__u8 *pValue);
-static int qt2_box_set_register(struct usb_serial *serial,
-		unsigned short Uart_Number, unsigned short Register_Num,
-		unsigned short Value);
-static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number,
-		unsigned short default_divisor, unsigned char default_LCR);
-static int qt2_boxsethw_flowctl(struct usb_serial *serial,
-		unsigned int UartNumber, bool bSet);
-static int qt2_boxsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber,
-		unsigned char stop_char,  unsigned char start_char);
-static int qt2_boxunsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber);
-static int qt2_boxstoprx(struct usb_serial *serial, unsigned short uart_number,
-			 unsigned short stop);
-
-/* implementation functions, roughly in order of use, are here */
-static int qt2_calc_num_ports(struct usb_serial *serial)
-{
-	int num_ports;
-	int flag_as_400;
-	switch (serial->dev->descriptor.idProduct) {
-	case QUATECH_SSU2_100:
-		num_ports = 1;
-		break;
-
-	case QUATECH_DSU2_400:
-		flag_as_400 = true;
-	case QUATECH_DSU2_100:
-		num_ports = 2;
-	break;
-
-	case QUATECH_QSU2_400:
-		flag_as_400 = true;
-	case QUATECH_QSU2_100:
-		num_ports = 4;
-	break;
-
-	case QUATECH_ESU2_400:
-		flag_as_400 = true;
-	case QUATECH_ESU2_100:
-		num_ports = 8;
-	break;
-	default:
-	num_ports = 1;
-	break;
-	}
-	return num_ports;
-}
-
-static int qt2_attach(struct usb_serial *serial)
-{
-	struct usb_serial_port *port;
-	struct quatech2_port *qt2_port;	/* port-specific private data pointer */
-	struct quatech2_dev  *qt2_dev;	/* dev-specific private data pointer */
-	int i;
-	/* stuff for storing endpoint addresses now */
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_host_interface *iface_desc;
-	struct usb_serial_port *port0;	/* first port structure on device */
-
-	/* check how many endpoints there are on the device, for
-	 * sanity's sake */
-	dbg("%s(): Endpoints: %d bulk in, %d bulk out, %d interrupt in",
-			__func__, serial->num_bulk_in,
-			serial->num_bulk_out, serial->num_interrupt_in);
-	if ((serial->num_bulk_in != 1) || (serial->num_bulk_out != 1)) {
-		dbg("Device has wrong number of bulk endpoints!");
-		return -ENODEV;
-	}
-	iface_desc = serial->interface->cur_altsetting;
-
-	/* Set up per-device private data, storing extra data alongside
-	 * struct usb_serial */
-	qt2_dev = kzalloc(sizeof(*qt2_dev), GFP_KERNEL);
-	if (!qt2_dev) {
-		dbg("%s: kmalloc for quatech2_dev failed!",
-		    __func__);
-		return -ENOMEM;
-	}
-	qt2_dev->open_ports = 0;	/* no ports open */
-	qt2_set_dev_private(serial, qt2_dev);	/* store private data */
-
-	/* Now setup per port private data, which replaces all the things
-	 * that quatech added to standard kernel structures in their driver */
-	for (i = 0; i < serial->num_ports; i++) {
-		port = serial->port[i];
-		qt2_port = kzalloc(sizeof(*qt2_port), GFP_KERNEL);
-		if (!qt2_port) {
-			dbg("%s: kmalloc for quatech2_port (%d) failed!.",
-			    __func__, i);
-			return -ENOMEM;
-		}
-		/* initialise stuff in the structure */
-		qt2_port->open_count = 0;	/* port is not open */
-		spin_lock_init(&qt2_port->lock);
-		mutex_init(&qt2_port->modelock);
-		qt2_set_port_private(port, qt2_port);
-	}
-
-	/* gain access to port[0]'s structure because we want to store
-	 * device-level stuff in it */
-	if (serial_paranoia_check(serial, __func__))
-		return -ENODEV;
-	port0 = serial->port[0]; /* get the first port's device structure */
-
-	/* print endpoint addresses so we can check them later
-	 * by hand */
-	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
-		endpoint = &iface_desc->endpoint[i].desc;
-		if ((endpoint->bEndpointAddress & 0x80) &&
-			((endpoint->bmAttributes & 3) == 0x02)) {
-			/* we found a bulk in endpoint */
-			dbg("found bulk in at %#.2x",
-				endpoint->bEndpointAddress);
-		}
-
-		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
-			((endpoint->bmAttributes & 3) == 0x02)) {
-			/* we found a bulk out endpoint */
-			dbg("found bulk out at %#.2x",
-				endpoint->bEndpointAddress);
-			qt2_dev->buffer_size = endpoint->wMaxPacketSize;
-			/* max size of URB needs recording for the device */
-		}
-	}	/* end printing endpoint addresses */
-
-	/* switch on power to the hardware */
-	if (qt2_boxpoweron(serial) < 0) {
-		dbg("qt2_boxpoweron() failed");
-		goto startup_error;
-	}
-	/* set all ports to RS232 mode */
-	for (i = 0; i < serial->num_ports; ++i) {
-		if (qt2_boxsetQMCR(serial, i, QU2BOX232) < 0) {
-			dbg("qt2_boxsetQMCR() on port %d failed",
-				i);
-			goto startup_error;
-		}
-	}
-
-	return 0;
-
-startup_error:
-	for (i = 0; i < serial->num_ports; i++) {
-		port = serial->port[i];
-		qt2_port = qt2_get_port_private(port);
-		kfree(qt2_port);
-		qt2_set_port_private(port, NULL);
-	}
-	qt2_dev = qt2_get_dev_private(serial);
-	kfree(qt2_dev);
-	qt2_set_dev_private(serial, NULL);
-
-	dbg("Exit fail %s\n", __func__);
-	return -EIO;
-}
-
-static void qt2_release(struct usb_serial *serial)
-{
-	struct usb_serial_port *port;
-	struct quatech2_port *qt_port;
-	int i;
-
-	dbg("enterting %s", __func__);
-
-	for (i = 0; i < serial->num_ports; i++) {
-		port = serial->port[i];
-		if (!port)
-			continue;
-
-		qt_port = usb_get_serial_port_data(port);
-		kfree(qt_port);
-		usb_set_serial_port_data(port, NULL);
-	}
-}
-/* This function is called once per serial port on the device, when
- * that port is opened by a userspace application.
- * The tty_struct and the usb_serial_port belong to this port,
- * i.e. there are multiple ones for a multi-port device.
- * However the usb_serial_port structure has a back-pointer
- * to the parent usb_serial structure which belongs to the device,
- * so we can access either the device-wide information or
- * any other port's information (because there are also forward
- * pointers) via that pointer.
- * This is most helpful if the device shares resources (e.g. end
- * points) between different ports
- */
-int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
-{
-	struct usb_serial *serial;	/* device structure */
-	struct usb_serial_port *port0;	/* first port structure on device */
-	struct quatech2_port *port_extra;       /* extra data for this port */
-	struct quatech2_port *port0_extra;	/* extra data for first port */
-	struct quatech2_dev *dev_extra;		/* extra data for the device */
-	struct qt2_status_data ChannelData;
-	unsigned short default_divisor = QU2BOXSPD9600;
-	unsigned char  default_LCR = QT2_SERIAL_8_DATA;
-	int status;
-	int result;
-
-	if (port_paranoia_check(port, __func__))
-		return -ENODEV;
-
-	dbg("%s(): port %d", __func__, port->number);
-
-	serial = port->serial;	/* get the parent device structure */
-	if (serial_paranoia_check(serial, __func__)) {
-		dbg("usb_serial struct failed sanity check");
-		return -ENODEV;
-	}
-	dev_extra = qt2_get_dev_private(serial);
-	/* get the device private data */
-	if (dev_extra == NULL) {
-		dbg("device extra data pointer is null");
-		return -ENODEV;
-	}
-	port0 = serial->port[0]; /* get the first port's device structure */
-	if (port_paranoia_check(port0, __func__)) {
-		dbg("port0 usb_serial_port struct failed sanity check");
-		return -ENODEV;
-	}
-
-	port_extra = qt2_get_port_private(port);
-	port0_extra = qt2_get_port_private(port0);
-	if (port_extra == NULL || port0_extra == NULL) {
-		dbg("failed to get private data for port or port0");
-		return -ENODEV;
-	}
-
-	/* FIXME: are these needed?  Does it even do anything useful? */
-	/* get the modem and line status values from the UART */
-	status = qt2_openboxchannel(serial, port->number,
-			&ChannelData);
-	if (status < 0) {
-		dbg("qt2_openboxchannel on channel %d failed",
-		    port->number);
-		return status;
-	}
-	port_extra->shadowLSR = ChannelData.line_status &
-			(QT2_SERIAL_LSR_OE | QT2_SERIAL_LSR_PE |
-			QT2_SERIAL_LSR_FE | QT2_SERIAL_LSR_BI);
-	port_extra->shadowMSR = ChannelData.modem_status &
-			(QT2_SERIAL_MSR_CTS | QT2_SERIAL_MSR_DSR |
-			QT2_SERIAL_MSR_RI | QT2_SERIAL_MSR_CD);
-
-/*	port_extra->fifo_empty_flag = true;*/
-	dbg("qt2_openboxchannel on channel %d completed.",
-	    port->number);
-
-	/* Set Baud rate to default and turn off flow control here */
-	status = qt2_conf_uart(serial, port->number, default_divisor,
-				default_LCR);
-	if (status < 0) {
-		dbg("qt2_conf_uart() failed on channel %d",
-		    port->number);
-		return status;
-	}
-	dbg("qt2_conf_uart() completed on channel %d",
-		port->number);
-
-	/*
-	 * At this point we will need some end points to make further progress.
-	 * Handlily, the correct endpoint addresses have been filled out into
-	 * the usb_serial_port structure for us by the driver core, so we
-	 * already have access to them.
-	 * As there is only one bulk in and one bulk out end-point, these are in
-	 * port[0]'s structure, and the rest are uninitialised. Handily,
-	 * when we do a write to a port, we will use the same endpoint
-	 * regardless of the port, with a 5-byte header added on to
-	 * tell the box which port it should eventually come out of, so we only
-	 * need the one set of endpoints. We will have one URB per port for
-	 * writing, so that multiple ports can be writing at once.
-	 * Finally we need a bulk in URB to use for background reads from the
-	 * device, which will deal with uplink data from the box to host.
-	 */
-	dbg("port0 bulk in endpoint is %#.2x", port0->bulk_in_endpointAddress);
-	dbg("port0 bulk out endpoint is %#.2x",
-		port0->bulk_out_endpointAddress);
-
-	/* set up write_urb for bulk out transfers on this port. The USB
-	 * serial framework will have allocated a blank URB, buffer etc for
-	 * port0 when it put the endpoints there, but not for any of the other
-	 * ports on the device because there are no more endpoints. Thus we
-	 * have to allocate our own URBs for ports 1-7
-	 */
-	if (port->write_urb == NULL) {
-		dbg("port->write_urb == NULL, allocating one");
-		port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!port->write_urb) {
-			err("Allocating write URB failed");
-			return -ENOMEM;
-		}
-		/* buffer same size as port0 */
-		port->bulk_out_size = dev_extra->buffer_size;
-		port->bulk_out_buffer = kmalloc(port->bulk_out_size,
-						GFP_KERNEL);
-		if (!port->bulk_out_buffer) {
-			err("Couldn't allocate bulk_out_buffer");
-			return -ENOMEM;
-		}
-	}
-	if (serial->dev == NULL)
-		dbg("serial->dev == NULL");
-	dbg("port->bulk_out_size is %d", port->bulk_out_size);
-
-	usb_fill_bulk_urb(port->write_urb, serial->dev,
-			usb_sndbulkpipe(serial->dev,
-			port0->bulk_out_endpointAddress),
-			port->bulk_out_buffer,
-			port->bulk_out_size,
-			qt2_write_bulk_callback,
-			port);
-	port_extra->tx_pending_bytes = 0;
-
-	if (dev_extra->open_ports == 0) {
-		/* this is first port to be opened, so need the read URB
-		 * initialised for bulk in transfers (this is shared amongst
-		 * all the ports on the device) */
-		usb_fill_bulk_urb(port0->read_urb, serial->dev,
-			usb_rcvbulkpipe(serial->dev,
-			port0->bulk_in_endpointAddress),
-			port0->bulk_in_buffer,
-			port0->bulk_in_size,
-			qt2_read_bulk_callback, serial);
-		dbg("port0 bulk in URB initialised");
-
-		/* submit URB, i.e. start reading from device (async) */
-		dev_extra->ReadBulkStopped = false;
-		port_extra->read_urb_busy = true;
-		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (result) {
-			dev_err(&port->dev,
-				 "%s(): Error %d submitting bulk in urb",
-				__func__, result);
-			port_extra->read_urb_busy = false;
-			dev_extra->ReadBulkStopped = true;
-		}
-
-		/* When the first port is opened, initialise the value of
-		 * current_port in dev_extra to this port, so it is set
-		 * to something. Once the box sends data it will send the
-		 * relevant escape sequences to get it to the right port anyway
-		 */
-		dev_extra->current_port = port;
-	}
-
-	/* initialize our wait queues */
-	init_waitqueue_head(&port_extra->wait);
-	/* increment the count of openings of this port by one */
-	port_extra->open_count++;
-
-	/* remember to store dev_extra, port_extra and port0_extra back again at
-	 * end !*/
-	qt2_set_port_private(port, port_extra);
-	qt2_set_port_private(serial->port[0], port0_extra);
-	qt2_set_dev_private(serial, dev_extra);
-
-	dev_extra->open_ports++; /* one more port opened */
-
-	return 0;
-}
-
-/* called when a port is closed by userspace. It won't be called, however,
- * until calls to chars_in_buffer() reveal that the port has completed
- * sending buffered data, and there is nothing else to do. Thus we don't have
- * to rely on forcing data through in this function. */
-/* Setting close_pending should keep new data from being written out,
- * once all the data in the enpoint buffers is moved out we won't get
- * any more. */
-/* BoxStopReceive would keep any more data from coming from a given
- * port, but isn't called by the vendor driver, although their comments
- * mention it. Should it be used here to stop the inbound data
- * flow?
- */
-static void qt2_close(struct usb_serial_port *port)
-{
-	/* time out value for flush loops */
-	unsigned long jift;
-	struct quatech2_port *port_extra;	/* extra data for this port */
-	struct usb_serial *serial;	/* device structure */
-	struct quatech2_dev *dev_extra; /* extra data for the device */
-	__u8  lsr_value = 0;	/* value of Line Status Register */
-	int status;	/* result of last USB comms function */
-
-	dbg("%s(): port %d", __func__, port->number);
-	serial = port->serial;	/* get the parent device structure */
-	dev_extra = qt2_get_dev_private(serial);
-	/* get the device private data */
-	port_extra = qt2_get_port_private(port); /* port private data */
-
-	/* we can now (and only now) stop reading data */
-	port_extra->close_pending = true;
-	dbg("%s(): port_extra->close_pending = true", __func__);
-	/* although the USB side is now empty, the UART itself may
-	 * still be pushing characters out over the line, so we have to
-	 * wait testing the actual line status until the lines change
-	 * indicating that the data is done transferring. */
-	/* FIXME: slow this polling down so it doesn't run the USB bus flat out
-	 * if it actually has to spend any time in this loop (which it normally
-	 * doesn't because the buffer is nearly empty) */
-	jift = jiffies + (10 * HZ);	/* 10 sec timeout */
-	do {
-		status = qt2_box_get_register(serial, port->number,
-			QT2_LINE_STATUS_REGISTER, &lsr_value);
-		if (status < 0) {
-			dbg("%s(): qt2_box_get_register failed", __func__);
-			break;
-		}
-		if ((lsr_value & QT2_LSR_TEMT)) {
-			dbg("UART done sending");
-			break;
-		}
-		schedule();
-	} while (jiffies <= jift);
-
-	status = qt2_closeboxchannel(serial, port->number);
-	if (status < 0)
-		dbg("%s(): port %d qt2_box_open_close_channel failed",
-			__func__, port->number);
-	/* to avoid leaking URBs, we should now free the write_urb for this
-	 * port and set the pointer to null so that next time the port is opened
-	 * a new URB is allocated. This avoids leaking URBs when the device is
-	 * removed */
-	usb_free_urb(port->write_urb);
-	kfree(port->bulk_out_buffer);
-	port->bulk_out_buffer = NULL;
-	port->bulk_out_size = 0;
-
-	/* decrement the count of openings of this port by one */
-	port_extra->open_count--;
-	/* one less overall open as well */
-	dev_extra->open_ports--;
-	dbg("%s(): Exit, dev_extra->open_ports  = %d", __func__,
-		dev_extra->open_ports);
-}
-
-/**
- * qt2_write - write bytes from the tty layer out to the USB device.
- * @buf: The data to be written, size at least count.
- * @count: The number of bytes requested for transmission.
- * @return The number of bytes actually accepted for transmission to the device.
- */
-static int qt2_write(struct tty_struct *tty, struct usb_serial_port *port,
-		const unsigned char *buf, int count)
-{
-	struct usb_serial *serial;	/* parent device struct */
-	__u8 header_array[5];	/* header used to direct writes to the correct
-	port on the device */
-	struct quatech2_port *port_extra;	/* extra data for this port */
-	int result;
-
-	serial = port->serial; /* get the parent device of the port */
-	port_extra = qt2_get_port_private(port); /* port extra info */
-	if (serial == NULL)
-		return -ENODEV;
-	dbg("%s(): port %d, requested to write %d bytes, %d already pending",
-		__func__, port->number, count, port_extra->tx_pending_bytes);
-
-	if (count <= 0)	{
-		dbg("%s(): write request of <= 0 bytes", __func__);
-		return 0;	/* no bytes written */
-	}
-
-	/* check if the write urb is already in use, i.e. data already being
-	 * sent to this port */
-	if ((port->write_urb->status == -EINPROGRESS)) {
-		/* Fifo hasn't been emptied since last write to this port */
-		dbg("%s(): already writing, port->write_urb->status == "
-			"-EINPROGRESS", __func__);
-		/* schedule_work(&port->work); commented in vendor driver */
-		return 0;
-	} else if (port_extra->tx_pending_bytes >= QT2_FIFO_DEPTH) {
-		/* buffer is full (==). > should not occur, but would indicate
-		 * that an overflow had occurred */
-		dbg("%s(): port transmit buffer is full!", __func__);
-		/* schedule_work(&port->work); commented in vendor driver */
-		return 0;
-	}
-
-	/* We must fill the first 5 bytes of anything we sent with a transmit
-	 * header which directes the data to the correct port. The maximum
-	 * size we can send out in one URB is port->bulk_out_size, which caps
-	 * the number of bytes of real data we can send in each write. As the
-	 * semantics of write allow us to write less than we were give, we cap
-	 * the maximum we will ever write to the device as 5 bytes less than
-	 * one URB's worth, by reducing the value of the count argument
-	 * appropriately*/
-	if (count > port->bulk_out_size - QT2_TX_HEADER_LENGTH) {
-		count = port->bulk_out_size - QT2_TX_HEADER_LENGTH;
-		dbg("%s(): write request bigger than urb, only accepting "
-			"%d bytes", __func__, count);
-	}
-	/* we must also ensure that the FIFO at the other end can cope with the
-	 * URB we send it, otherwise it will have problems. As above, we can
-	 * restrict the write size by just shrinking count.*/
-	if (count > (QT2_FIFO_DEPTH - port_extra->tx_pending_bytes)) {
-		count = QT2_FIFO_DEPTH - port_extra->tx_pending_bytes;
-		dbg("%s(): not enough room in buffer, only accepting %d bytes",
-			__func__, count);
-	}
-	/* now build the header for transmission */
-	header_array[0] = 0x1b;
-	header_array[1] = 0x1b;
-	header_array[2] = (__u8)port->number;
-	header_array[3] = (__u8)count;
-	header_array[4] = (__u8)count >> 8;
-	/* copy header into URB */
-	memcpy(port->write_urb->transfer_buffer, header_array,
-		QT2_TX_HEADER_LENGTH);
-	/* and actual data to write */
-	memcpy(port->write_urb->transfer_buffer + 5, buf, count);
-
-	dbg("%s(): first data byte to send = %#.2x", __func__, *buf);
-
-	/* set up our urb */
-	usb_fill_bulk_urb(port->write_urb, serial->dev,
-			usb_sndbulkpipe(serial->dev,
-			port->bulk_out_endpointAddress),
-			port->write_urb->transfer_buffer, count + 5,
-			(qt2_write_bulk_callback), port);
-	/* send the data out the bulk port */
-	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-	if (result) {
-		/* error couldn't submit urb */
-		result = 0;	/* return 0 as nothing got written */
-		dbg("%s(): failed submitting write urb, error %d",
-			__func__, result);
-	} else {
-		port_extra->tx_pending_bytes += count;
-		result = count;	/* return number of bytes written, i.e. count */
-		dbg("%s(): submitted write urb, wrote %d bytes, "
-			"total pending bytes %d",
-			__func__, result, port_extra->tx_pending_bytes);
-	}
-	return result;
-}
-
-/* This is used by the next layer up to know how much space is available
- * in the buffer on the device. It is used on a device closure to avoid
- * calling close() until the buffer is reported to be empty.
- * The returned value must never go down by more than the number of bytes
- * written for correct behaviour further up the driver stack, i.e. if I call
- * it, then write 6 bytes, then call again I should get 6 less, or possibly
- * only 5 less if one was written in the meantime, etc. I should never get 7
- * less (or any bigger number) because I only wrote 6 bytes.
- */
-static int qt2_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-		/* parent usb_serial_port pointer */
-	struct quatech2_port *port_extra;	/* extra data for this port */
-	int room = 0;
-	port_extra = qt2_get_port_private(port);
-
-	if (port_extra->close_pending == true) {
-		dbg("%s(): port_extra->close_pending == true", __func__);
-		return -ENODEV;
-	}
-	/* Q: how many bytes would a write() call actually succeed in writing
-	 * if it happened now?
-	 * A: one QT2_FIFO_DEPTH, less the number of bytes waiting to be sent
-	 * out of the port, unless this is more than the size of the
-	 * write_urb output buffer less the header, which is the maximum
-	 * size write we can do.
-
-	 * Most of the implementation of this is done when writes to the device
-	 * are started or terminate. When we send a write to the device, we
-	 * reduce the free space count by the size of the dispatched write.
-	 * When a "transmit empty" message comes back up the USB read stream,
-	 * we decrement the count by the number of bytes reported sent, thus
-	 * keeping track of the difference between sent and received bytes.
-	 */
-
-	room = (QT2_FIFO_DEPTH - port_extra->tx_pending_bytes);
-	/* space in FIFO */
-	if (room > port->bulk_out_size - QT2_TX_HEADER_LENGTH)
-		room = port->bulk_out_size - QT2_TX_HEADER_LENGTH;
-	/* if more than the URB can hold, then cap to that limit */
-
-	dbg("%s(): port %d: write room is %d", __func__, port->number, room);
-	return room;
-}
-
-static int qt2_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	/* parent usb_serial_port pointer */
-	struct quatech2_port *port_extra;	/* extra data for this port */
-	port_extra = qt2_get_port_private(port);
-
-	dbg("%s(): port %d: chars_in_buffer = %d", __func__,
-		port->number, port_extra->tx_pending_bytes);
-	return port_extra->tx_pending_bytes;
-}
-
-/* called when userspace does an ioctl() on the device. Note that
- * TIOCMGET and TIOCMSET are filtered off to their own methods before they get
- * here, so we don't have to handle them.
- */
-static int qt2_ioctl(struct tty_struct *tty,
-		     unsigned int cmd, unsigned long arg)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct usb_serial *serial = port->serial;
-	__u8 mcr_value;	/* Modem Control Register value */
-	__u8 msr_value; /* Modem Status Register value */
-	unsigned short prev_msr_value; /* Previous value of Modem Status
-	 * Register used to implement waiting for a line status change to
-	 * occur */
-	struct quatech2_port *port_extra;	/* extra data for this port */
-	DECLARE_WAITQUEUE(wait, current);
-	/* Declare a wait queue named "wait" */
-
-	unsigned int value;
-	unsigned int UartNumber;
-
-	if (serial == NULL)
-		return -ENODEV;
-	UartNumber = tty->index - serial->minor;
-	port_extra = qt2_get_port_private(port);
-
-	dbg("%s(): port %d, UartNumber %d, tty =0x%p", __func__,
-	    port->number, UartNumber, tty);
-
-	if (cmd == TIOCMBIS || cmd == TIOCMBIC) {
-		if (qt2_box_get_register(port->serial, UartNumber,
-			QT2_MODEM_CONTROL_REGISTER, &mcr_value) < 0)
-			return -ESPIPE;
-		if (copy_from_user(&value, (unsigned int *)arg,
-			sizeof(value)))
-			return -EFAULT;
-
-		switch (cmd) {
-		case TIOCMBIS:
-			if (value & TIOCM_RTS)
-				mcr_value |= QT2_SERIAL_MCR_RTS;
-			if (value & TIOCM_DTR)
-				mcr_value |= QT2_SERIAL_MCR_DTR;
-			if (value & TIOCM_LOOP)
-				mcr_value |= QT2_SERIAL_MCR_LOOP;
-		break;
-		case TIOCMBIC:
-			if (value & TIOCM_RTS)
-				mcr_value &= ~QT2_SERIAL_MCR_RTS;
-			if (value & TIOCM_DTR)
-				mcr_value &= ~QT2_SERIAL_MCR_DTR;
-			if (value & TIOCM_LOOP)
-				mcr_value &= ~QT2_SERIAL_MCR_LOOP;
-		break;
-		default:
-		break;
-		}	/* end of local switch on cmd */
-		if (qt2_box_set_register(port->serial,  UartNumber,
-		    QT2_MODEM_CONTROL_REGISTER, mcr_value) < 0) {
-			return -ESPIPE;
-		} else {
-			port_extra->shadowMCR = mcr_value;
-			return 0;
-		}
-	} else if (cmd == TIOCMIWAIT) {
-		dbg("%s() port %d, cmd == TIOCMIWAIT enter",
-			__func__, port->number);
-		prev_msr_value = port_extra->shadowMSR  & QT2_SERIAL_MSR_MASK;
-		barrier();
-		__set_current_state(TASK_INTERRUPTIBLE);
-		while (1) {
-			add_wait_queue(&port_extra->wait, &wait);
-			schedule();
-			dbg("%s(): port %d, cmd == TIOCMIWAIT here\n",
-				__func__, port->number);
-			remove_wait_queue(&port_extra->wait, &wait);
-			/* see if a signal woke us up */
-			if (signal_pending(current))
-				return -ERESTARTSYS;
-			set_current_state(TASK_INTERRUPTIBLE);
-			msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK;
-			if (msr_value == prev_msr_value) {
-				__set_current_state(TASK_RUNNING);
-				return -EIO;  /* no change - error */
-			}
-			if ((arg & TIOCM_RNG &&
-				((prev_msr_value & QT2_SERIAL_MSR_RI) ==
-					(msr_value & QT2_SERIAL_MSR_RI))) ||
-				(arg & TIOCM_DSR &&
-				((prev_msr_value & QT2_SERIAL_MSR_DSR) ==
-					(msr_value & QT2_SERIAL_MSR_DSR))) ||
-				(arg & TIOCM_CD &&
-				((prev_msr_value & QT2_SERIAL_MSR_CD) ==
-					(msr_value & QT2_SERIAL_MSR_CD))) ||
-				(arg & TIOCM_CTS &&
-				((prev_msr_value & QT2_SERIAL_MSR_CTS) ==
-					(msr_value & QT2_SERIAL_MSR_CTS)))) {
-				__set_current_state(TASK_RUNNING);
-				return 0;
-			}
-		} /* end inifinite while */
-		/* FIXME: This while loop needs a way to break out if the device
-		 * is disconnected while a process is waiting for the MSR to
-		 * change, because once it's disconnected, it isn't going to
-		 * change state ... */
-	} else {
-		/* any other ioctls we don't know about come here */
-		dbg("%s(): No ioctl for that one. port = %d", __func__,
-			port->number);
-		return -ENOIOCTLCMD;
-	}
-}
-
-/* Called when the user wishes to change the port settings using the termios
- * userspace interface */
-static void qt2_set_termios(struct tty_struct *tty,
-	struct usb_serial_port *port, struct ktermios *old_termios)
-{
-	struct usb_serial *serial; /* parent serial device */
-	int baud, divisor, remainder;
-	unsigned char LCR_change_to = 0;
-	int status;
-	__u16 UartNumber;
-
-	dbg("%s(): port %d", __func__, port->number);
-
-	serial = port->serial;
-
-	UartNumber = port->number;
-
-	if (old_termios && !tty_termios_hw_change(old_termios, tty->termios))
-		return;
-
-	switch (tty->termios->c_cflag) {
-	case CS5:
-		LCR_change_to |= QT2_SERIAL_5_DATA;
-		break;
-	case CS6:
-		LCR_change_to |= QT2_SERIAL_6_DATA;
-		break;
-	case CS7:
-		LCR_change_to |= QT2_SERIAL_7_DATA;
-		break;
-	default:
-	case CS8:
-		LCR_change_to |= QT2_SERIAL_8_DATA;
-		break;
-	}
-
-	/* Parity stuff */
-	if (tty->termios->c_cflag & PARENB) {
-		if (tty->termios->c_cflag & PARODD)
-			LCR_change_to |= QT2_SERIAL_ODD_PARITY;
-		else
-			LCR_change_to |= QT2_SERIAL_EVEN_PARITY;
-	}
-	/* Because LCR_change_to is initialised to zero, we don't have to worry
-	 * about the case where PARENB is not set or clearing bits, because by
-	 * default all of them are cleared, turning parity off.
-	 * as we don't support mark/space parity, we should clear the
-	 * mark/space parity bit in c_cflag, so the caller can tell we have
-	 * ignored the request */
-	tty->termios->c_cflag &= ~CMSPAR;
-
-	if (tty->termios->c_cflag & CSTOPB)
-		LCR_change_to |= QT2_SERIAL_TWO_STOPB;
-	else
-		LCR_change_to |= QT2_SERIAL_ONE_STOPB;
-
-	/* Thats the LCR stuff, next we need to work out the divisor as the
-	 * LCR and the divisor are set together */
-	baud = tty_get_baud_rate(tty);
-	if (!baud) {
-		/* pick a default, any default... */
-		baud = 9600;
-	}
-	dbg("%s(): got baud = %d", __func__, baud);
-
-	divisor = QT2_MAX_BAUD_RATE / baud;
-	remainder = QT2_MAX_BAUD_RATE % baud;
-	/* Round to nearest divisor */
-	if (((remainder * 2) >= baud) && (baud != 110))
-		divisor++;
-	dbg("%s(): setting divisor = %d, QT2_MAX_BAUD_RATE = %d , LCR = %#.2x",
-	      __func__, divisor, QT2_MAX_BAUD_RATE, LCR_change_to);
-
-	status = qt2_boxsetuart(serial, UartNumber, (unsigned short) divisor,
-			    LCR_change_to);
-	if (status < 0)	{
-		dbg("qt2_boxsetuart() failed");
-		return;
-	} else {
-		/* now encode the baud rate we actually set, which may be
-		 * different to the request */
-		baud = QT2_MAX_BAUD_RATE / divisor;
-		tty_encode_baud_rate(tty, baud, baud);
-	}
-
-	/* Now determine flow control */
-	if (tty->termios->c_cflag & CRTSCTS) {
-		dbg("%s(): Enabling HW flow control port %d", __func__,
-		      port->number);
-		/* Enable  RTS/CTS flow control */
-		status = qt2_boxsethw_flowctl(serial, UartNumber, true);
-		if (status < 0) {
-			dbg("qt2_boxsethw_flowctl() failed");
-			return;
-		}
-	} else {
-		/* Disable RTS/CTS flow control */
-		dbg("%s(): disabling HW flow control port %d", __func__,
-			port->number);
-		status = qt2_boxsethw_flowctl(serial, UartNumber, false);
-		if (status < 0)	{
-			dbg("qt2_boxsethw_flowctl failed");
-			return;
-		}
-	}
-	/* if we are implementing XON/XOFF, set the start and stop character
-	 * in the device */
-	if (I_IXOFF(tty) || I_IXON(tty)) {
-		unsigned char stop_char  = STOP_CHAR(tty);
-		unsigned char start_char = START_CHAR(tty);
-		status = qt2_boxsetsw_flowctl(serial, UartNumber, stop_char,
-				start_char);
-		if (status < 0)
-			dbg("qt2_boxsetsw_flowctl (enabled) failed");
-	} else {
-		/* disable SW flow control */
-		status = qt2_boxunsetsw_flowctl(serial, UartNumber);
-		if (status < 0)
-			dbg("qt2_boxunsetsw_flowctl (disabling) failed");
-	}
-}
-
-static int qt2_tiocmget(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct usb_serial *serial = port->serial;
-
-	__u8 mcr_value;	/* Modem Control Register value */
-	__u8 msr_value;	/* Modem Status Register value */
-	unsigned int result = 0;
-	int status;
-	unsigned int UartNumber;
-
-	if (serial == NULL)
-		return -ENODEV;
-
-	dbg("%s(): port %d, tty =0x%p", __func__, port->number, tty);
-	UartNumber = tty->index - serial->minor;
-	dbg("UartNumber is %d", UartNumber);
-
-	status = qt2_box_get_register(port->serial, UartNumber,
-			QT2_MODEM_CONTROL_REGISTER,	&mcr_value);
-	if (status >= 0) {
-		status = qt2_box_get_register(port->serial,  UartNumber,
-				QT2_MODEM_STATUS_REGISTER, &msr_value);
-	}
-	if (status >= 0) {
-		result = ((mcr_value & QT2_SERIAL_MCR_DTR) ? TIOCM_DTR : 0)
-				/*DTR set */
-			| ((mcr_value & QT2_SERIAL_MCR_RTS)  ? TIOCM_RTS : 0)
-				/*RTS set */
-			| ((msr_value & QT2_SERIAL_MSR_CTS)  ? TIOCM_CTS : 0)
-				/* CTS set */
-			| ((msr_value & QT2_SERIAL_MSR_CD)  ? TIOCM_CAR : 0)
-				/*Carrier detect set */
-			| ((msr_value & QT2_SERIAL_MSR_RI)  ? TIOCM_RI : 0)
-				/* Ring indicator set */
-			| ((msr_value & QT2_SERIAL_MSR_DSR)  ? TIOCM_DSR : 0);
-				/* DSR set */
-		return result;
-	} else {
-		return -ESPIPE;
-	}
-}
-
-static int qt2_tiocmset(struct tty_struct *tty,
-		       unsigned int set, unsigned int clear)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct usb_serial *serial = port->serial;
-	__u8 mcr_value;	/* Modem Control Register value */
-	int status;
-	unsigned int UartNumber;
-
-	if (serial == NULL)
-		return -ENODEV;
-
-	UartNumber = tty->index - serial->minor;
-	dbg("%s(): port %d, UartNumber %d", __func__, port->number, UartNumber);
-
-	status = qt2_box_get_register(port->serial, UartNumber,
-			QT2_MODEM_CONTROL_REGISTER, &mcr_value);
-	if (status < 0)
-		return -ESPIPE;
-
-	/* Turn off RTS, DTR and loopback, then only turn on what was asked
-	 * for */
-	mcr_value &= ~(QT2_SERIAL_MCR_RTS | QT2_SERIAL_MCR_DTR |
-			QT2_SERIAL_MCR_LOOP);
-	if (set & TIOCM_RTS)
-		mcr_value |= QT2_SERIAL_MCR_RTS;
-	if (set & TIOCM_DTR)
-		mcr_value |= QT2_SERIAL_MCR_DTR;
-	if (set & TIOCM_LOOP)
-		mcr_value |= QT2_SERIAL_MCR_LOOP;
-
-	status = qt2_box_set_register(port->serial, UartNumber,
-			QT2_MODEM_CONTROL_REGISTER, mcr_value);
-	if (status < 0)
-		return -ESPIPE;
-	else
-		return 0;
-}
-
-/** qt2_break - Turn BREAK on and off on the UARTs
- */
-static void qt2_break(struct tty_struct *tty, int break_state)
-{
-	struct usb_serial_port *port = tty->driver_data; /* parent port */
-	struct usb_serial *serial = port->serial;	/* parent device */
-	struct quatech2_port *port_extra;	/* extra data for this port */
-	__u16 break_value;
-	unsigned int result;
-
-	port_extra = qt2_get_port_private(port);
-	if (!serial) {
-		dbg("%s(): port %d: no serial object", __func__, port->number);
-		return;
-	}
-
-	if (break_state == -1)
-		break_value = 1;
-	else
-		break_value = 0;
-	dbg("%s(): port %d, break_value %d", __func__, port->number,
-		break_value);
-
-	mutex_lock(&port_extra->modelock);
-	if (!port_extra->open_count) {
-		dbg("%s(): port not open", __func__);
-		goto exit;
-	}
-
-	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				QT2_BREAK_CONTROL, 0x40, break_value,
-				port->number, NULL, 0, 300);
-exit:
-	mutex_unlock(&port_extra->modelock);
-	dbg("%s(): exit port %d", __func__, port->number);
-
-}
-/**
- * qt2_throttle: - stop reading new data from the port
- */
-static void qt2_throttle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct usb_serial *serial = port->serial;
-	struct quatech2_port *port_extra;	/* extra data for this port */
-	dbg("%s(): port %d", __func__, port->number);
-
-	port_extra = qt2_get_port_private(port);
-	if (!serial) {
-		dbg("%s(): enter port %d no serial object", __func__,
-		      port->number);
-		return;
-	}
-
-	mutex_lock(&port_extra->modelock);	/* lock structure */
-	if (!port_extra->open_count) {
-		dbg("%s(): port not open", __func__);
-		goto exit;
-	}
-	/* Send command to box to stop receiving stuff. This will stop this
-	 * particular UART from filling the endpoint - in the multiport case the
-	 * FPGA UART will handle any flow control implemented, but for the single
-	 * port it's handed differently and we just quit submitting urbs
-	 */
-	if (serial->dev->descriptor.idProduct != QUATECH_SSU2_100)
-		qt2_boxstoprx(serial, port->number, 1);
-
-	port->throttled = 1;
-exit:
-	mutex_unlock(&port_extra->modelock);
-	dbg("%s(): port %d: setting port->throttled", __func__, port->number);
-	return;
-}
-
-/**
- * qt2_unthrottle: - start receiving data through the port again after being
- * throttled
- */
-static void qt2_unthrottle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct usb_serial *serial = port->serial;
-	struct quatech2_port *port_extra;	/* extra data for this port */
-	struct usb_serial_port *port0;	/* first port structure on device */
-	struct quatech2_dev *dev_extra;		/* extra data for the device */
-
-	if (!serial) {
-		dbg("%s() enter port %d no serial object!", __func__,
-			port->number);
-		return;
-	}
-	dbg("%s(): enter port %d", __func__, port->number);
-	dev_extra = qt2_get_dev_private(serial);
-	port_extra = qt2_get_port_private(port);
-	port0 = serial->port[0]; /* get the first port's device structure */
-
-	mutex_lock(&port_extra->modelock);
-	if (!port_extra->open_count) {
-		dbg("%s(): port %d not open", __func__, port->number);
-		goto exit;
-	}
-
-	if (port->throttled != 0) {
-		dbg("%s(): port %d: unsetting port->throttled", __func__,
-		    port->number);
-		port->throttled = 0;
-		/* Send command to box to start receiving stuff */
-		if (serial->dev->descriptor.idProduct != QUATECH_SSU2_100) {
-			qt2_boxstoprx(serial,  port->number, 0);
-		} else if (dev_extra->ReadBulkStopped == true) {
-			usb_fill_bulk_urb(port0->read_urb, serial->dev,
-				usb_rcvbulkpipe(serial->dev,
-				port0->bulk_in_endpointAddress),
-				port0->bulk_in_buffer,
-				port0->bulk_in_size,
-				qt2_read_bulk_callback,
-				serial);
-		}
-	}
-exit:
-	mutex_unlock(&port_extra->modelock);
-	dbg("%s(): exit port %d", __func__, port->number);
-	return;
-}
-
-/* internal, private helper functions for the driver */
-
-/* Power up the FPGA in the box to get it working */
-static int qt2_boxpoweron(struct usb_serial *serial)
-{
-	int result;
-	__u8  Direcion;
-	unsigned int pipe;
-	Direcion = USBD_TRANSFER_DIRECTION_OUT;
-	pipe = usb_rcvctrlpipe(serial->dev, 0);
-	result = usb_control_msg(serial->dev, pipe, QT_SET_GET_DEVICE,
-				Direcion, QU2BOXPWRON, 0x00, NULL, 0x00,
-				5000);
-	return result;
-}
-
-/*
- * qt2_boxsetQMCR Issue a QT2_GET_SET_QMCR vendor-spcific request on the
- * default control pipe. If successful return the number of bytes written,
- * otherwise return a negative error number of the problem.
- */
-static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number,
-			  __u8 QMCR_Value)
-{
-	int result;
-	__u16 PortSettings;
-
-	PortSettings = (__u16)(QMCR_Value);
-
-	dbg("%s(): Port = %d, PortSettings = 0x%x", __func__,
-			Uart_Number, PortSettings);
-
-	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				QT2_GET_SET_QMCR, 0x40, PortSettings,
-				(__u16)Uart_Number, NULL, 0, 5000);
-	return result;
-}
-
-static int port_paranoia_check(struct usb_serial_port *port,
-			       const char *function)
-{
-	if (!port) {
-		dbg("%s - port == NULL", function);
-		return -1;
-	}
-	if (!port->serial) {
-		dbg("%s - port->serial == NULL\n", function);
-		return -1;
-	}
-	return 0;
-}
-
-static int serial_paranoia_check(struct usb_serial *serial,
-				 const char *function)
-{
-	if (!serial) {
-		dbg("%s - serial == NULL\n", function);
-		return -1;
-	}
-
-	if (!serial->type) {
-		dbg("%s - serial->type == NULL!", function);
-		return -1;
-	}
-
-	return 0;
-}
-
-static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port
-		*port)
-{
-	return (struct quatech2_port *)usb_get_serial_port_data(port);
-}
-
-static inline void qt2_set_port_private(struct usb_serial_port *port,
-		struct quatech2_port *data)
-{
-	usb_set_serial_port_data(port, (void *)data);
-}
-
-static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial
-		*serial)
-{
-	return (struct quatech2_dev *)usb_get_serial_data(serial);
-}
-static inline void qt2_set_dev_private(struct usb_serial *serial,
-		struct quatech2_dev *data)
-{
-	usb_set_serial_data(serial, (void *)data);
-}
-
-static int qt2_openboxchannel(struct usb_serial *serial, __u16
-		Uart_Number, struct qt2_status_data *status)
-{
-	int result;
-	__u16 length;
-	__u8  Direcion;
-	unsigned int pipe;
-	length = sizeof(struct qt2_status_data);
-	Direcion = USBD_TRANSFER_DIRECTION_IN;
-	pipe = usb_rcvctrlpipe(serial->dev, 0);
-	result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL,
-			Direcion, 0x00, Uart_Number, status, length, 5000);
-	return result;
-}
-static int qt2_closeboxchannel(struct usb_serial *serial, __u16 Uart_Number)
-{
-	int result;
-	__u8  direcion;
-	unsigned int pipe;
-	direcion = USBD_TRANSFER_DIRECTION_OUT;
-	pipe = usb_sndctrlpipe(serial->dev, 0);
-	result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL,
-		  direcion, 0, Uart_Number, NULL, 0, 5000);
-	return result;
-}
-
-/* qt2_conf_uart Issue a SET_UART vendor-spcific request on the default
- * control pipe. If successful sets baud rate divisor and LCR value
- */
-static int qt2_conf_uart(struct usb_serial *serial,  unsigned short Uart_Number,
-		      unsigned short divisor, unsigned char LCR)
-{
-	int result;
-	unsigned short UartNumandLCR;
-
-	UartNumandLCR = (LCR << 8) + Uart_Number;
-
-	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				QT2_GET_SET_UART, 0x40, divisor, UartNumandLCR,
-				NULL, 0, 300);
-	return result;
-}
-
-/** @brief Callback for asynchronous submission of read URBs on bulk in
- * endpoints
- *
- * Registered in qt2_open_port(), used to deal with incomming data
- * from the box.
- */
-static void qt2_read_bulk_callback(struct urb *urb)
-{
-	/* Get the device pointer (struct usb_serial) back out of the URB */
-	struct usb_serial *serial = urb->context;
-	/* get the extra struct for the device */
-	struct quatech2_dev *dev_extra = qt2_get_dev_private(serial);
-	/* Get first port structure from the device */
-	struct usb_serial_port *port0 = serial->port[0];
-	/* Get the currently active port structure from serial struct */
-	struct usb_serial_port *active = dev_extra->current_port;
-	/* get the extra struct for port 0 */
-	struct quatech2_port *port0_extra = qt2_get_port_private(port0);
-	/* and for the currently active port */
-	struct quatech2_port *active_extra = qt2_get_port_private(active);
-	/* When we finally get to doing some tty stuff, we will need this */
-	struct tty_struct *tty_st;
-	unsigned int RxCount;	/* the length of the data to process */
-	unsigned int i;	/* loop counter over the data to process */
-	int result;	/* return value cache variable */
-	bool escapeflag;	/* flag set to true if this loop iteration is
-				 * parsing an escape sequence, rather than
-				 * ordinary data */
-	dbg("%s(): callback running, active port is %d", __func__,
-		active->number);
-
-	if (urb->status) {
-		/* read didn't go well */
-		dev_extra->ReadBulkStopped = true;
-		dbg("%s(): nonzero bulk read status received: %d",
-			__func__, urb->status);
-		return;
-	}
-
-	/* inline port_sofrint() here */
-	if (port_paranoia_check(port0, __func__) != 0) {
-		dbg("%s - port_paranoia_check on port0 failed, exiting\n",
-__func__);
-		return;
-	}
-	if (port_paranoia_check(active, __func__) != 0) {
-		dbg("%s - port_paranoia_check on current_port "
-			"failed, exiting", __func__);
-		return;
-	}
-
-/* This single callback function has to do for all the ports on
- * the device. Data being read up the USB can contain certain
- * escape sequences which are used to communicate out-of-band
- * information from the serial port in-band over the USB.
- * These escapes include sending modem and flow control line
- * status, and switching the port. The concept of a "Current Port"
- * is used, which is where data is going until a port change
- * escape seqence is received. This Current Port is kept between
- * callbacks so that when this function enters we know which the
- * currently active port is and can get to work right away without
- * the box having to send repeat escape sequences (anyway, how
- * would it know to do so?).
- */
-
-	if (active_extra->close_pending == true) {
-		/* We are closing , stop reading */
-		dbg("%s - (active->close_pending == true", __func__);
-		if (dev_extra->open_ports <= 0) {
-			/* If this is the only port left open - stop the
-			 * bulk read */
-			dev_extra->ReadBulkStopped = true;
-			dbg("%s - (ReadBulkStopped == true;", __func__);
-			return;
-		}
-	}
-
-	/*
-	 * RxHolding is asserted by throttle, if we assert it, we're not
-	 * receiving any more characters and let the box handle the flow
-	 * control
-	 */
-	if ((port0_extra->RxHolding == true) &&
-		    (serial->dev->descriptor.idProduct == QUATECH_SSU2_100)) {
-		/* single port device, input is already stopped, so we don't
-		 * need any more input data */
-		dev_extra->ReadBulkStopped = true;
-		return;
-	}
-	/* finally, we are in a situation where we might consider the data
-	 * that is contained within the URB, and what to do about it.
-	 * This is likely to involved communicating up to the TTY layer, so
-	 * we will need to get hold of the tty for the port we are currently
-	 * dealing with */
-
-	/* active is a usb_serial_port. It has a member port which is a
-	 * tty_port. From this we get a tty_struct pointer which is what we
-	 * actually wanted, and keep it on tty_st */
-	tty_st = tty_port_tty_get(&active->port);
-	if (!tty_st) {
-		dbg("%s - bad tty pointer - exiting", __func__);
-		return;
-	}
-	RxCount = urb->actual_length;	/* grab length of data handy */
-
-	if (RxCount) {
-		/* skip all this if no data to process */
-		for (i = 0; i < RxCount ; ++i) {
-			/* Look ahead code here -works on several bytes at onc*/
-			if ((i <= (RxCount - 3)) && (THISCHAR == 0x1b)
-				&& (NEXTCHAR == 0x1b)) {
-				/* we are in an escape sequence, type
-				 * determined by the 3rd char */
-				escapeflag = false;
-				switch (THIRDCHAR) {
-				case 0x00:
-					/* Line status change 4th byte must
-					 * follow */
-					if (i > (RxCount - 4)) {
-						dbg("Illegal escape sequences "
-						"in received data");
-						break;
-					}
-					qt2_process_line_status(active,
-						FOURTHCHAR);
-					i += 3;
-					escapeflag = true;
-					break;
-				case 0x01:
-					/* Modem status status change 4th byte
-					 * must follow */
-					if (i > (RxCount - 4)) {
-						dbg("Illegal escape sequences "
-						"in received data");
-						break;
-					}
-					qt2_process_modem_status(active,
-						FOURTHCHAR);
-					i += 3;
-					escapeflag = true;
-					break;
-				case 0x02:
-					/* xmit hold empty 4th byte
-					 * must follow */
-					if (i > (RxCount - 4)) {
-						dbg("Illegal escape sequences "
-						"in received data");
-						break;
-					}
-					qt2_process_xmit_empty(active,
-						FOURTHCHAR, FIFTHCHAR);
-					i += 4;
-					escapeflag = true;
-					break;
-				case 0x03:
-					/* Port number change 4th byte
-					 * must follow */
-					if (i > (RxCount - 4)) {
-						dbg("Illegal escape sequences "
-						"in received data");
-						break;
-					}
-					/* Port change. If port open push
-					 * current data up to tty layer */
-					if (active_extra->open_count > 0)
-						tty_flip_buffer_push(tty_st);
-
-					dbg("Port Change: new port = %d",
-						FOURTHCHAR);
-					qt2_process_port_change(active,
-						FOURTHCHAR);
-					i += 3;
-					escapeflag = true;
-					/* having changed port, the pointers for
-					 * the currently active port are all out
-					 * of date and need updating */
-					active = dev_extra->current_port;
-					active_extra =
-						qt2_get_port_private(active);
-					tty_st = tty_port_tty_get(
-						&active->port);
-					break;
-				case 0x04:
-					/* Recv flush 3rd byte must
-					 * follow */
-					if (i > (RxCount - 3)) {
-						dbg("Illegal escape sequences "
-							"in received data");
-						break;
-					}
-					qt2_process_rcv_flush(active);
-					i += 2;
-					escapeflag = true;
-					break;
-				case 0x05:
-					/* xmit flush 3rd byte must follow */
-					if (i > (RxCount - 3)) {
-						dbg("Illegal escape sequences "
-						"in received data");
-						break;
-					}
-					qt2_process_xmit_flush(active);
-					i += 2;
-					escapeflag = true;
-					break;
-				case 0xff:
-					dbg("No status sequence");
-					qt2_process_rx_char(active, THISCHAR);
-					qt2_process_rx_char(active, NEXTCHAR);
-					i += 2;
-					break;
-				default:
-					qt2_process_rx_char(active, THISCHAR);
-					i += 1;
-					break;
-				} /*end switch*/
-				if (escapeflag == true)
-					continue;
-				/* if we did an escape char, we don't need
-				 * to mess around pushing data through the
-				 * tty layer, and can go round again */
-			} /*endif*/
-			if (tty_st && urb->actual_length) {
-				tty_buffer_request_room(tty_st, 1);
-				tty_insert_flip_string(tty_st, &(
-						(unsigned char *)
-						(urb->transfer_buffer)
-					)[i], 1);
-			}
-		} /*endfor*/
-		tty_flip_buffer_push(tty_st);
-	} /*endif*/
-
-	/* at this point we have complete dealing with the data for this
-	 * callback. All we have to do now is to start the async read process
-	 * back off again. */
-
-	usb_fill_bulk_urb(port0->read_urb, serial->dev,
-		usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
-		port0->bulk_in_buffer, port0->bulk_in_size,
-		qt2_read_bulk_callback, serial);
-	result = usb_submit_urb(port0->read_urb, GFP_ATOMIC);
-	if (result) {
-		dbg("%s(): failed resubmitting read urb, error %d",
-			__func__, result);
-	} else {
-		dbg("%s() successfully resubmitted read urb", __func__);
-		if (tty_st && RxCount) {
-			/* if some inbound data was processed, then
-			 * we need to push that through the tty layer
-			 */
-			tty_flip_buffer_push(tty_st);
-			tty_schedule_flip(tty_st);
-		}
-	}
-
-	/* cribbed from serqt_usb2 driver, but not sure which work needs
-	 * scheduling - port0 or currently active port? */
-	/* schedule_work(&port->work); */
-	dbg("%s() completed", __func__);
-	return;
-}
-
-/** @brief Callback for asynchronous submission of write URBs on bulk in
- * endpoints
- *
- * Registered in qt2_write(), used to deal with outgoing data
- * to the box.
- */
-static void qt2_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial = port->serial;
-	dbg("%s(): port %d", __func__, port->number);
-	if (!serial) {
-		dbg("%s(): bad serial pointer, exiting", __func__);
-		return;
-	}
-	if (urb->status) {
-		dbg("%s(): nonzero write bulk status received: %d",
-			__func__, urb->status);
-		return;
-	}
-	/* FIXME What is supposed to be going on here?
-	 * does this actually do anything useful, and should it?
-	 */
-	/*port_softint((void *) serial); commented in vendor driver */
-	schedule_work(&port->work);
-	dbg("%s(): port %d exit", __func__, port->number);
-	return;
-}
-
-static void qt2_process_line_status(struct usb_serial_port *port,
-	unsigned char LineStatus)
-{
-	/* obtain the private structure for the port */
-	struct quatech2_port *port_extra = qt2_get_port_private(port);
-	port_extra->shadowLSR = LineStatus & (QT2_SERIAL_LSR_OE |
-		QT2_SERIAL_LSR_PE | QT2_SERIAL_LSR_FE | QT2_SERIAL_LSR_BI);
-}
-static void qt2_process_modem_status(struct usb_serial_port *port,
-	unsigned char ModemStatus)
-{
-	/* obtain the private structure for the port */
-	struct quatech2_port *port_extra = qt2_get_port_private(port);
-	port_extra->shadowMSR = ModemStatus;
-	wake_up_interruptible(&port_extra->wait);
-	/* this wakes up the otherwise indefinitely waiting code for
-	 * the TIOCMIWAIT ioctl, so that it can notice that
-	 * port_extra->shadowMSR has changed and the ioctl needs to return.
-	 */
-}
-
-static void qt2_process_xmit_empty(struct usb_serial_port *port,
-	unsigned char fourth_char, unsigned char fifth_char)
-{
-	int byte_count;
-	/* obtain the private structure for the port */
-	struct quatech2_port *port_extra = qt2_get_port_private(port);
-
-	byte_count = (int)(fifth_char * 16);
-	byte_count +=  (int)fourth_char;
-	/* byte_count indicates how many bytes the device has written out. This
-	 * message appears to occur regularly, and is used in the vendor driver
-	 * to keep track of the fill state of the port transmit buffer */
-	port_extra->tx_pending_bytes -= byte_count;
-	/* reduce the stored data queue length by the known number of bytes
-	 * sent */
-	dbg("port %d: %d bytes reported sent, %d still pending", port->number,
-			byte_count, port_extra->tx_pending_bytes);
-
-	/*port_extra->xmit_fifo_room_bytes = FIFO_DEPTH; ???*/
-}
-
-static void qt2_process_port_change(struct usb_serial_port *port,
-	unsigned char New_Current_Port)
-{
-	/* obtain the parent usb serial device structure */
-	struct usb_serial *serial = port->serial;
-	/* obtain the private structure for the device */
-	struct quatech2_dev *dev_extra = qt2_get_dev_private(serial);
-	dev_extra->current_port = serial->port[New_Current_Port];
-	/* what should I do with this? commented out in upstream
-	 * driver */
-	/*schedule_work(&port->work);*/
-}
-
-static void qt2_process_rcv_flush(struct usb_serial_port *port)
-{
-	/* obtain the private structure for the port */
-	struct quatech2_port *port_extra = qt2_get_port_private(port);
-	port_extra->rcv_flush = true;
-}
-static void qt2_process_xmit_flush(struct usb_serial_port *port)
-{
-	/* obtain the private structure for the port */
-	struct quatech2_port *port_extra = qt2_get_port_private(port);
-	port_extra->xmit_flush = true;
-}
-
-static void qt2_process_rx_char(struct usb_serial_port *port,
-	unsigned char data)
-{
-	/* get the tty_struct for this port */
-	struct tty_struct *tty = tty_port_tty_get(&(port->port));
-	/* get the URB with the data in to push */
-	struct urb *urb = port->serial->port[0]->read_urb;
-
-	if (tty && urb->actual_length) {
-		tty_buffer_request_room(tty, 1);
-		tty_insert_flip_string(tty, &data, 1);
-		/* should this be commented out here? */
-		/*tty_flip_buffer_push(tty);*/
-	}
-}
-
-/** @brief Retrieve the value of a register from the device
- *
- * Issues a GET_REGISTER vendor-spcific request over the USB control
- * pipe to obtain a value back from a specific register on a specific
- * UART
- * @param serial Serial device handle to access the device through
- * @param uart_number Which UART the value is wanted from
- * @param register_num Which register to read the value from
- * @param pValue Pointer to somewhere to put the retrieved value
- */
-static int qt2_box_get_register(struct usb_serial *serial,
-		unsigned char uart_number, unsigned short register_num,
-		__u8 *pValue)
-{
-	int result;
-	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-			QT2_GET_SET_REGISTER, 0xC0, register_num,
-			uart_number, (void *)pValue, sizeof(*pValue), 300);
-	return result;
-}
-
-/** qt2_box_set_register
- * Issue a SET_REGISTER vendor-specific request on the default control pipe
- */
-static int qt2_box_set_register(struct usb_serial *serial,
-		unsigned short Uart_Number, unsigned short Register_Num,
-		unsigned short Value)
-{
-	int result;
-	unsigned short reg_and_byte;
-
-	reg_and_byte = Value;
-	reg_and_byte = reg_and_byte << 8;
-	reg_and_byte = reg_and_byte + Register_Num;
-
-	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			QT2_GET_SET_REGISTER, 0x40, reg_and_byte,
-			Uart_Number, NULL, 0, 300);
-	return result;
-}
-
-/** qt2_boxsetuart - Issue a SET_UART vendor-spcific request on the default
- * control pipe. If successful sets baud rate divisor and LCR value.
- */
-static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number,
-		unsigned short default_divisor, unsigned char default_LCR)
-{
-	unsigned short UartNumandLCR;
-
-	UartNumandLCR = (default_LCR << 8) + Uart_Number;
-
-	return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			QT2_GET_SET_UART, 0x40, default_divisor, UartNumandLCR,
-			NULL, 0, 300);
-}
-
-/** qt2_boxsethw_flowctl - Turn hardware (RTS/CTS) flow control on and off for
- * a hardware UART.
- */
-static int qt2_boxsethw_flowctl(struct usb_serial *serial,
-		unsigned int UartNumber, bool bSet)
-{
-	__u8 MCR_Value = 0;
-	__u8 MSR_Value = 0;
-	__u16 MOUT_Value = 0;
-
-	if (bSet == true) {
-		MCR_Value =  QT2_SERIAL_MCR_RTS;
-		/* flow control, box will clear RTS line to prevent remote
-		 * device from transmitting more chars */
-	} else {
-		/* no flow control to remote device */
-		MCR_Value =  0;
-	}
-	MOUT_Value = MCR_Value << 8;
-
-	if (bSet == true) {
-		MSR_Value = QT2_SERIAL_MSR_CTS;
-		/* flow control on, box will inhibit tx data if CTS line is
-		 * asserted */
-	} else {
-		/* Box will not inhibit tx data due to CTS line */
-		MSR_Value = 0;
-	}
-	MOUT_Value |= MSR_Value;
-	return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			QT2_HW_FLOW_CONTROL_MASK, 0x40, MOUT_Value, UartNumber,
-			NULL, 0, 300);
-}
-
-/** qt2_boxsetsw_flowctl - Turn software (XON/XOFF) flow control on for
- * a hardware UART, and set the XON and XOFF characters.
- */
-static int qt2_boxsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber,
-			unsigned char stop_char,  unsigned char start_char)
-{
-	__u16 nSWflowout;
-
-	nSWflowout = start_char << 8;
-	nSWflowout = (unsigned short)stop_char;
-	return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			QT2_SW_FLOW_CONTROL_MASK, 0x40, nSWflowout, UartNumber,
-			NULL, 0, 300);
-}
-
-/** qt2_boxunsetsw_flowctl - Turn software (XON/XOFF) flow control off for
- * a hardware UART.
- */
-static int qt2_boxunsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber)
-{
-	return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			QT2_SW_FLOW_CONTROL_DISABLE, 0x40, 0, UartNumber, NULL,
-			0, 300);
-}
-
-/**
- * qt2_boxstoprx - Start and stop reception of data by the FPGA UART in
- * response to requests from the tty layer
- * @serial: pointer to the usb_serial structure for the parent device
- * @uart_number: which UART on the device we are addressing
- * @stop: Whether to start or stop data reception. Set to 1 to stop data being
- * received, and to 0 to start it being received.
- */
-static int qt2_boxstoprx(struct usb_serial *serial, unsigned short uart_number,
-		unsigned short stop)
-{
-	return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-		QT2_STOP_RECEIVE, 0x40, stop, uart_number, NULL, 0, 300);
-}
-
-
-/*
- * last things in file: stuff to register this driver into the generic
- * USB serial framework.
- */
-
-static struct usb_serial_driver quatech2_device = {
-	.driver = {
-		.owner = THIS_MODULE,
-		.name = "quatech_usb2",
-	},
-	.description = DRIVER_DESC,
-	.id_table = quausb2_id_table,
-	.num_ports = 8,
-	.open = qt2_open,
-	.close = qt2_close,
-	.write = qt2_write,
-	.write_room = qt2_write_room,
-	.chars_in_buffer = qt2_chars_in_buffer,
-	.throttle = qt2_throttle,
-	.unthrottle = qt2_unthrottle,
-	.calc_num_ports = qt2_calc_num_ports,
-	.ioctl = qt2_ioctl,
-	.set_termios = qt2_set_termios,
-	.break_ctl = qt2_break,
-	.tiocmget = qt2_tiocmget,
-	.tiocmset = qt2_tiocmset,
-	.attach = qt2_attach,
-	.release = qt2_release,
-	.read_bulk_callback = qt2_read_bulk_callback,
-	.write_bulk_callback = qt2_write_bulk_callback,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-	&quatech2_device, NULL
-};
-
-module_usb_serial_driver(quausb2_usb_driver, serial_drivers);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/ramster/Kconfig b/drivers/staging/ramster/Kconfig
index 4af1f8d..8349887 100644
--- a/drivers/staging/ramster/Kconfig
+++ b/drivers/staging/ramster/Kconfig
@@ -1,6 +1,6 @@
 config RAMSTER
 	bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
-	depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM
+	depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM && NET
 	select LZO_COMPRESS
 	select LZO_DECOMPRESS
 	default n
diff --git a/drivers/staging/ramster/cluster/tcp.c b/drivers/staging/ramster/cluster/tcp.c
index b9721c1..d0a07d7 100644
--- a/drivers/staging/ramster/cluster/tcp.c
+++ b/drivers/staging/ramster/cluster/tcp.c
@@ -111,7 +111,7 @@
  * r2net_wq.  teardown detaches the callbacks before destroying the workqueue.
  * quorum work is queued as sock containers are shutdown.. stop_listening
  * tears down all the node's sock containers, preventing future shutdowns
- * and queued quroum work, before canceling delayed quorum work and
+ * and queued quorum work, before canceling delayed quorum work and
  * destroying the work queue.
  */
 static struct workqueue_struct *r2net_wq;
@@ -660,7 +660,7 @@
 
 /*
  * we register callbacks so we can queue work on events before calling
- * the original callbacks.  our callbacks our careful to test user_data
+ * the original callbacks.  our callbacks are careful to test user_data
  * to discover when they've reaced with r2net_unregister_callbacks().
  */
 static void r2net_register_callbacks(struct sock *sk,
diff --git a/drivers/staging/ramster/xvmalloc.c b/drivers/staging/ramster/xvmalloc.c
index 93ba8e9..44ceb0b 100644
--- a/drivers/staging/ramster/xvmalloc.c
+++ b/drivers/staging/ramster/xvmalloc.c
@@ -132,7 +132,7 @@
 	if (!pool->flbitmap)
 		return 0;
 
-	/* Get freelist index correspoding to this size */
+	/* Get freelist index corresponding to this size */
 	slindex = get_index(size);
 	slbitmap = pool->slbitmap[slindex / BITS_PER_LONG];
 	slbitstart = slindex % BITS_PER_LONG;
diff --git a/drivers/staging/ramster/zcache-main.c b/drivers/staging/ramster/zcache-main.c
index 68b2e05..4e7ef0e 100644
--- a/drivers/staging/ramster/zcache-main.c
+++ b/drivers/staging/ramster/zcache-main.c
@@ -1331,7 +1331,7 @@
  * when that limit is reached, further puts will be rejected (until
  * some pages have been flushed).  Note that, due to compression,
  * this number may exceed 100; it defaults to 75 and we set an
- * arbitary limit of 150.  A poor choice will almost certainly result
+ * arbitrary limit of 150.  A poor choice will almost certainly result
  * in OOM's, so this value should only be changed prudently.
  */
 static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj,
@@ -2004,7 +2004,7 @@
  * Called by the message handler after a (still compressed) page has been
  * fetched from the remote machine in response to an "is_remote" tmem_get
  * or persistent tmem_localify.  For a tmem_get, "extra" is the address of
- * the page that is to be filled to succesfully resolve the tmem_get; for
+ * the page that is to be filled to successfully resolve the tmem_get; for
  * a (persistent) tmem_localify, "extra" is NULL (as the data is placed only
  * in the local zcache).  "data" points to "size" bytes of (compressed) data
  * passed in the message.  In the case of a persistent remote get, if
@@ -2095,7 +2095,7 @@
 /*
  * Called on a remote persistent tmem_get to attempt to preallocate
  * local storage for the data contained in the remote persistent page.
- * If succesfully preallocated, returns the pampd, marked as remote and
+ * If successfully preallocated, returns the pampd, marked as remote and
  * in_transit.  Else returns NULL.  Note that the appropriate tmem data
  * structure must be locked.
  */
diff --git a/drivers/staging/rtl8187se/Makefile b/drivers/staging/rtl8187se/Makefile
index 72db504..91d1aa2 100644
--- a/drivers/staging/rtl8187se/Makefile
+++ b/drivers/staging/rtl8187se/Makefile
@@ -10,7 +10,7 @@
 ccflags-y += -DSW_DIG
 ccflags-y += -DRATE_ADAPT
 
-#enable it for legacy power save, disable it for leisure  power save
+#enable it for legacy power save, disable it for leisure power save
 ccflags-y += -DENABLE_LPS
 
 
diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.c b/drivers/staging/rtl8187se/ieee80211/dot11d.c
index 309bb8b..0e93eb0 100644
--- a/drivers/staging/rtl8187se/ieee80211/dot11d.c
+++ b/drivers/staging/rtl8187se/ieee80211/dot11d.c
@@ -55,7 +55,7 @@
 
 //
 //	Description:
-//		Update country IE from Beacon or Probe Resopnse
+//		Update country IE from Beacon or Probe Response
 //		and configure PHY for operation in the regulatory domain.
 //
 //	TODO:
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index 40dd715..b94c48b 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -834,7 +834,7 @@
 	/* the association procedure is sending AUTH request*/
 	IEEE80211_ASSOCIATING_AUTHENTICATING,
 
-	/* the association procedure has successfully authentcated
+	/* the association procedure has successfully authenticated
 	 * and is sending association request
 	 */
 	IEEE80211_ASSOCIATING_AUTHENTICATED,
@@ -934,7 +934,7 @@
 			   * with RX of broad/multicast frames */
 
 	/* Fragmentation structures */
-	// each streaming contain a entry
+	/* each stream contains an entry */
 	struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN];
 	unsigned int frag_next_idx[17];
 	u16 fts; /* Fragmentation Threshold */
@@ -972,7 +972,7 @@
 
 	int rate;       /* current rate */
 	int basic_rate;
-	//FIXME: pleace callback, see if redundant with softmac_features
+	//FIXME: please callback, see if redundant with softmac_features
 	short active_scan;
 
 	/* this contains flags for selectively enable softmac support */
@@ -1106,7 +1106,7 @@
 
 	/* used instead of hard_start_xmit (not softmac_hard_start_xmit)
 	 * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
-	 * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
+	 * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
 	 * then also management frames are sent via this callback.
 	 * This function can't sleep.
 	 */
@@ -1124,7 +1124,7 @@
 
 	/* ask to the driver to retune the radio .
 	 * This function can sleep. the driver should ensure
-	 * the radio has been swithced before return.
+	 * the radio has been switched before return.
 	 */
 	void (*set_chan)(struct net_device *dev,short ch);
 
@@ -1135,7 +1135,7 @@
 	 * The syncro version is similar to the start_scan but
 	 * does not return until all channels has been scanned.
 	 * this is called in user context and should sleep,
-	 * it is called in a work_queue when swithcing to ad-hoc mode
+	 * it is called in a work_queue when switching to ad-hoc mode
 	 * or in behalf of iwlist scan when the card is associated
 	 * and root user ask for a scan.
 	 * the function stop_scan should stop both the syncro and
@@ -1196,7 +1196,7 @@
 /* Generate probe requests */
 #define IEEE_SOFTMAC_PROBERQ (1<<4)
 
-/* Generate respones to probe requests */
+/* Generate response to probe requests */
 #define IEEE_SOFTMAC_PROBERS (1<<5)
 
 /* The ieee802.11 stack will manages the netif queue
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index 26bacb9..8173240 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -42,7 +42,7 @@
 	return net->capability & WLAN_CAPABILITY_SHORT_SLOT;
 }
 
-/* returns the total length needed for pleacing the RATE MFIE
+/* returns the total length needed for placing the RATE MFIE
  * tag and the EXTENDED RATE MFIE tag if needed.
  * It encludes two bytes per tag for the tag itself and its len
  */
@@ -60,7 +60,7 @@
 	return rate_len;
 }
 
-/* pleace the MFIE rate, tag to the memory (double) poined.
+/* place the MFIE rate, tag to the memory (double) poised.
  * Then it updates the pointer so that
  * it points after the new MFIE tag added.
  */
@@ -467,7 +467,7 @@
 		 *    So we switch to IEEE80211_LINKED_SCANNING to remember
 		 *    that we are still logically linked (not interested in
 		 *    new network events, despite for updating the net list,
-		 *    but we are temporarly 'unlinked' as the driver shall
+		 *    but we are temporarily 'unlinked' as the driver shall
 		 *    not filter RX frames and the channel is changing.
 		 * So the only situation in witch are interested is to check
 		 * if the state become LINKED because of the #1 situation
@@ -530,7 +530,7 @@
                  *    So we switch to IEEE80211_LINKED_SCANNING to remember
                  *    that we are still logically linked (not interested in
                  *    new network events, despite for updating the net list,
-                 *    but we are temporarly 'unlinked' as the driver shall
+                 *    but we are temporarily 'unlinked' as the driver shall
                  *    not filter RX frames and the channel is changing.
                  * So the only situation in witch are interested is to check
                  * if the state become LINKED because of the #1 situation
@@ -1140,7 +1140,7 @@
 
 	ieee->associate_seq++;
 
-	/* don't scan, and avoid to have the RX path possibily
+	/* don't scan, and avoid to have the RX path possibly
 	 * try again to associate. Even do not react to AUTH or
 	 * ASSOC response. Just wait for the retry wq to be scheduled.
 	 * Here we will check if there are good nets to associate
@@ -1346,14 +1346,14 @@
 		//printk("apset=%d apmatch=%d ssidset=%d ssidbroad=%d ssidmatch=%d\n",apset,apmatch,ssidset,ssidbroad,ssidmatch);
 
 		if (	/* if the user set the AP check if match.
-			 * if the network does not broadcast essid we check the user supplyed ANY essid
+			 * if the network does not broadcast essid we check the user supplied ANY essid
 			 * if the network does broadcast and the user does not set essid it is OK
 			 * if the network does broadcast and the user did set essid chech if essid match
 			 */
 				( apset && apmatch &&
 				  ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) ||
 				/* if the ap is not set, check that the user set the bssid
-				 * and the network does bradcast and that those two bssid matches
+				 * and the network does broadcast and that those two bssid matches
 				 */
 				(!apset && ssidset && ssidbroad && ssidmatch)
 		   ){
@@ -1821,7 +1821,7 @@
 
 					while (left >= sizeof(struct ieee80211_info_element_hdr)) {
 						if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) {
-							printk(KERN_WARNING "[re]associate reeponse error!");
+							printk(KERN_WARNING "[re]associate response error!");
 							return 1;
 						}
 						switch (info_element->id) {
@@ -1905,7 +1905,7 @@
 							}
 						}else{
 							ieee->softmac_stats.rx_auth_rs_err++;
-							IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode);
+							IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x",errcode);
 							ieee80211_associate_abort(ieee);
 						}
 
@@ -2184,15 +2184,15 @@
 
 	if(ieee->state == IEEE80211_NOLINK)
 		ieee->current_network.channel = 10;
-	/* if not then the state is not linked. Maybe the user swithced to
+	/* if not then the state is not linked. Maybe the user switched to
 	 * ad-hoc mode just after being in monitor mode, or just after
 	 * being very few time in managed mode (so the card have had no
 	 * time to scan all the chans..) or we have just run up the iface
 	 * after setting ad-hoc mode. So we have to give another try..
 	 * Here, in ibss mode, should be safe to do this without extra care
-	 * (in bss mode we had to make sure no-one tryed to associate when
+	 * (in bss mode we had to make sure no-one tried to associate when
 	 * we had just checked the ieee->state and we was going to start the
-	 * scan) beacause in ibss mode the ieee80211_new_net function, when
+	 * scan) because in ibss mode the ieee80211_new_net function, when
 	 * finds a good net, just set the ieee->state to IEEE80211_LINKED,
 	 * so, at worst, we waste a bit of time to initiate an unneeded syncro
 	 * scan, that will stop at the first round because it sees the state
@@ -2342,7 +2342,7 @@
 		goto exit;
 	/* until we do not set the state to IEEE80211_NOLINK
 	* there are no possibility to have someone else trying
-	* to start an association procdure (we get here with
+	* to start an association procedure (we get here with
 	* ieee->state = IEEE80211_ASSOCIATING).
 	* When we set the state to IEEE80211_NOLINK it is possible
 	* that the RX path run an attempt to associate, but
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
index e46ff2f..5d20490 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
@@ -362,7 +362,7 @@
 		ieee80211_stop_protocol(ieee);
 
 	/* this is just to be sure that the GET wx callback
-	 * has consisten infos. not needed otherwise
+	 * has consistent infos. not needed otherwise
 	 */
 	spin_lock_irqsave(&ieee->lock, flags);
 
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
index 552115c..89ed86e 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -328,7 +328,7 @@
 	//printk(KERN_WARNING "upper layer packet!\n");
 	spin_lock_irqsave(&ieee->lock, flags);
 
-	/* If there is no driver handler to take the TXB, dont' bother
+	/* If there is no driver handler to take the TXB, don't bother
 	 * creating it... */
 	if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))||
 	   ((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) {
@@ -413,10 +413,7 @@
 
 		/* Determine fragmentation size based on destination (multicast
 		* and broadcast are not fragmented) */
-//		if (is_multicast_ether_addr(dest) ||
-//		is_broadcast_ether_addr(dest)) {
-		if (is_multicast_ether_addr(header.addr1) ||
-		is_broadcast_ether_addr(header.addr1)) {
+		if (is_multicast_ether_addr(header.addr1)) {
 			frag_size = MAX_FRAG_THRESHOLD;
 			qos_ctl = QOS_CTL_NOTCONTAIN_ACK;
 		}
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
index ca414a9..c7917b2 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
@@ -363,7 +363,7 @@
 				       (*crypt)->priv);
 		sec.flags |= (1 << key);
 		/* This ensures a key will be activated if no key is
-		 * explicitely set */
+		 * explicitly set */
 		if (key == sec.active_key)
 			sec.flags |= SEC_ACTIVE_KEY;
 		ieee->tx_keyidx = key;//by wb 080312
diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h
index a2c46ae..2682afb 100644
--- a/drivers/staging/rtl8187se/r8180.h
+++ b/drivers/staging/rtl8187se/r8180.h
@@ -11,7 +11,7 @@
 
    Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
 
-   We want to tanks the Authors of those projects and the Ndiswrapper
+   We want to thanks the Authors of those projects and the Ndiswrapper
    project Authors.
 */
 
@@ -514,12 +514,12 @@
 	bool bDefaultAntenna1;
 	u8 SignalStrength;
 	long Stats_SignalStrength;
-	long LastSignalStrengthInPercent; // In percentange, used for smoothing, e.g. Moving Average.
+	long LastSignalStrengthInPercent; // In percentage, used for smoothing, e.g. Moving Average.
 	u8	 SignalQuality; // in 0-100 index.
 	long Stats_SignalQuality;
 	long RecvSignalPower; // in dBm.
 	long Stats_RecvSignalPower;
-	u8	 LastRxPktAntenna;	// +by amy 080312 Antenn which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25.
+	u8	 LastRxPktAntenna;	// +by amy 080312 Antenna which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25.
 	u32 AdRxOkCnt;
 	long AdRxSignalStrength;
 	u8 CurrAntennaIndex;			// Index to current Antenna (both Tx and Rx).
@@ -530,7 +530,7 @@
 	long AdRxSsThreshold;			// Signal strength threshold to switch antenna.
 	long AdMaxRxSsThreshold;			// Max value of AdRxSsThreshold.
 	bool bAdSwitchedChecking;		// TRUE if we shall shall check Rx signal strength for last time switching antenna.
-	long AdRxSsBeforeSwitched;		// Rx signal strength before we swithed antenna.
+	long AdRxSsBeforeSwitched;		// Rx signal strength before we switched antenna.
 	struct timer_list SwAntennaDiversityTimer;
 //by amy for antenna
 //{by amy 080312
@@ -553,7 +553,7 @@
 	bool				bDigMechanism; // TRUE if DIG is enabled, FALSE ow.
 	bool				bRegHighPowerMechanism; // For High Power Mechanism. 061010, by rcnjko.
 	u32					FalseAlarmRegValue;
-	u8					RegDigOfdmFaUpTh; // Upper threhold of OFDM false alarm, which is used in DIG.
+	u8					RegDigOfdmFaUpTh; // Upper threshold of OFDM false alarm, which is used in DIG.
 	u8					DIG_NumberFallbackVote;
 	u8					DIG_NumberUpgradeVote;
 	// For HW antenna diversity, added by Roger, 2008.01.30.
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 4fe52f6..fd22b75 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -1329,7 +1329,7 @@
 }
 
 /*
- * For Netgear case, they want good-looking singal strength.
+ * For Netgear case, they want good-looking signal strength.
  */
 long NetgearSignalStrengthTranslate(long LastSS, long CurrSS)
 {
@@ -1380,7 +1380,7 @@
 
 /*
  * Perform signal smoothing for dynamic mechanism.
- * This is different with PerformSignalSmoothing8185 in smoothing fomula.
+ * This is different with PerformSignalSmoothing8185 in smoothing formula.
  * No dramatic adjustion is apply because dynamic mechanism need some degree
  * of correctness. Ported from 8187B.
  */
@@ -1535,7 +1535,7 @@
 			/* HW is probably passing several buggy frames
 			* without FD or LD flag set.
 			* Throw this garbage away to prevent skb
-			* memory exausting
+			* memory exhausting
 			*/
 			if (!priv->rx_skb_complete)
 				dev_kfree_skb_any(priv->rx_skb);
@@ -1648,14 +1648,14 @@
 			priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
 			priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6;
 
-		/* Figure out which antenna that received the lasted packet. */
+		/* Figure out which antenna that received the last packet. */
 			priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
 			SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
 		}
 
 		if (first) {
 			if (!priv->rx_skb_complete) {
-				/* seems that HW sometimes fails to reiceve and
+				/* seems that HW sometimes fails to receive and
 				   doesn't provide the last descriptor */
 				dev_kfree_skb_any(priv->rx_skb);
 				priv->stats.rxnolast++;
@@ -1672,7 +1672,7 @@
 			priv->rx_skb_complete = 0;
 			priv->rx_skb->dev = dev;
 		} else {
-			/* if we are here we should  have already RXed
+			/* if we are here we should have already RXed
 			* the first frame.
 			* If we get here and the skb is not allocated then
 			* we have just throw out garbage (skb not allocated)
@@ -1821,15 +1821,15 @@
 /*
  * This is a rough attempt to TX a frame
  * This is called by the ieee 80211 stack to TX management frames.
- * If the ring is full packet are dropped (for data frame the queue
+ * If the ring is full packets are dropped (for data frame the queue
  * is stopped before this can happen). For this reason it is better
  * if the descriptors are larger than the largest management frame
- * we intend to TX: i'm unsure what the HW does if it will not found
+ * we intend to TX: i'm unsure what the HW does if it will not find
  * the last fragment of a frame because it has been dropped...
  * Since queues for Management and Data frames are different we
  * might use a different lock than tx_lock (for example mgmt_tx_lock)
  */
-/* these function may loops if invoked with 0 descriptors or 0 len buffer */
+/* these function may loop if invoked with 0 descriptors or 0 len buffer */
 int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
@@ -2003,8 +2003,7 @@
 	}
 
 		memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
-		if (is_multicast_ether_addr(dest) ||
-				is_broadcast_ether_addr(dest)) {
+		if (is_multicast_ether_addr(dest)) {
 			Duration = 0;
 			RtsDur = 0;
 			bRTSEnable = 0;
@@ -2378,7 +2377,7 @@
 				u8		u1bAIFS;
 				u32		u4bAcParam;
 				pAcParam = (PAC_PARAM)(&AcParam);
-				/* Retrive paramters to udpate. */
+				/* Retrieve paramters to update. */
 				u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
 				u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
 					      (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
@@ -2414,7 +2413,7 @@
 			u8		u1bAIFS;
 			u32		u4bAcParam;
 
-			/* Retrive paramters to udpate. */
+			/* Retrieve paramters to update. */
 			eACI = pAcParam->f.AciAifsn.f.ACI;
 			/* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
 			u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
@@ -2700,7 +2699,7 @@
 	priv->bTxPowerTrack = false;
 	priv->ThermalMeter = 0;
 	priv->FalseAlarmRegValue = 0;
-	priv->RegDigOfdmFaUpTh = 0xc; /* Upper threhold of OFDM false alarm, which is used in DIG. */
+	priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */
 	priv->DIG_NumberFallbackVote = 0;
 	priv->DIG_NumberUpgradeVote = 0;
 	priv->LastSignalStrengthInPercent = 0;
@@ -2896,7 +2895,7 @@
 		priv->chtxpwr_ofdm[i+1] = (word & 0xff00) >> 8;
 	}
 
-	/* 3Read crystal calibtration and thermal meter indication on 87SE. */
+	/* 3Read crystal calibration and thermal meter indication on 87SE. */
 	eeprom_93cx6_read(&eeprom, EEPROM_RSV>>1, &tmpu16);
 
 	/* Crystal calibration for Xin and Xout resp. */
@@ -3140,7 +3139,7 @@
 
 	/*
 	 * The following is very strange. seems to be that 1 means test mode,
-	 * but we need to acknolwledges the nic when a packet is ready
+	 * but we need to acknowledges the nic when a packet is ready
 	 * although we set it to 0
 	 */
 
@@ -3971,7 +3970,7 @@
 	}
 
 	if (inta == 0xffff) {
-		/* HW disappared */
+		/* HW disappeared */
 		spin_unlock_irqrestore(&priv->irq_th_lock, flags);
 		return IRQ_HANDLED;
 	}
diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c
index 4d7a595..b8f2ba0 100644
--- a/drivers/staging/rtl8187se/r8180_dm.c
+++ b/drivers/staging/rtl8187se/r8180_dm.c
@@ -2,7 +2,7 @@
 #include "r8180_hw.h"
 #include "r8180_93cx6.h"
 
- /*	Return TRUE if we shall perform High Power Mecahnism, FALSE otherwise. */
+ /*	Return TRUE if we shall perform High Power Mechanism, FALSE otherwise. */
 #define RATE_ADAPTIVE_TIMER_PERIOD      300
 
 bool CheckHighPower(struct net_device *dev)
@@ -105,7 +105,7 @@
 
 
 /*
- *	Return TRUE if we shall perform DIG Mecahnism, FALSE otherwise.
+ *	Return TRUE if we shall perform DIG Mechanism, FALSE otherwise.
  */
 bool CheckDig(struct net_device *dev)
 {
@@ -507,7 +507,7 @@
 	 *		and retry rate.
 	 * (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated
 	 *		situation, Initial Gain Update is upon on DIG mechanism except CCK rate.
-	 * (4) Add the mehanism of trying to upgrade tx rate.
+	 * (4) Add the mechanism of trying to upgrade tx rate.
 	 * (5) Record the information of upping tx rate to avoid trying upping tx rate constantly.
 	 *
 	 */
@@ -528,7 +528,7 @@
 	if (priv->bTryuping == true) {
 		/* 2 For Test Upgrading mechanism
 		 * Note:
-		 *	Sometimes the throughput is upon on the capability bwtween the AP and NIC,
+		 *	Sometimes the throughput is upon on the capability between the AP and NIC,
 		 *	thus the low data rate does not improve the performance.
 		 *	We randomly upgrade the data rate and check if the retry rate is improved.
 		 */
@@ -704,7 +704,7 @@
 
 			/* 
 			 * The difference in throughput between 48Mbps and 36Mbps is 8M.
-			 * So, we must be carefully in this rate scale. Isaiah 2008-02-15.
+			 * So, we must be careful in this rate scale. Isaiah 2008-02-15.
 			 */
 			if (((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) &&
 				(priv->FailTxRateCount > 2))
@@ -1009,7 +1009,7 @@
 			if (priv->AdCheckPeriod > priv->AdMaxCheckPeriod)
 				priv->AdCheckPeriod = priv->AdMaxCheckPeriod;
 
-			/* Wrong deceision => switch back. */
+			/* Wrong decision => switch back. */
 			SwitchAntenna(dev);
 		} else {
 		/* Rx Signal Strength is improved. */
@@ -1057,7 +1057,7 @@
 		}
 		/*
 		 * <Roger_Notes> We evaluate Rx signal strength ONLY when default antenna
-		 * didn't changed by HW evaluation.
+		 * didn't change by HW evaluation.
 		 * 2008.02.27.
 		 *
 		 * [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05
@@ -1098,7 +1098,7 @@
 	priv->AdAuxAntennaRxOkCnt = 0;
 }
 
- /*	Return TRUE if we shall perform Tx Power Tracking Mecahnism, FALSE otherwise. */
+ /*	Return TRUE if we shall perform Tx Power Tracking Mechanism, FALSE otherwise. */
 bool CheckTxPwrTracking(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
index ee5b867..d28c1d9 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c
+++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
@@ -190,7 +190,7 @@
 		write_phy_cck(dev, 0x44 + i, power);
 	}
 
-	/* FIXME Is this delay really needeed ? */
+	/* FIXME Is this delay really needed ? */
 	force_pci_posting(dev);
 	mdelay(1);
 
@@ -479,7 +479,7 @@
 
 	/*
 	 * TRUE if we want to use a default implementation.
-	 * We shall set it to FALSE when we have exact translation formular
+	 * We shall set it to FALSE when we have exact translation formula
 	 * for target IC. 070622, by rcnjko.
 	 */
 	if (bUseDefault) {
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index 303ec69..46ee6f4 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -13,7 +13,7 @@
 
 	Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
 
-	We want to tanks the Authors of those projects and the Ndiswrapper
+	We want to thanks the Authors of those projects and the Ndiswrapper
 	project Authors.
 */
 
@@ -1181,7 +1181,7 @@
 		r8180_wx_set_wap,			/* SIOCSIWAP */
 		r8180_wx_get_wap,			/* SIOCGIWAP */
 		r8180_wx_set_mlme,			/* SIOCSIWMLME*/
-		dummy,					/* SIOCGIWAPLIST -- depricated */
+		dummy,					/* SIOCGIWAPLIST -- deprecated */
 		r8180_wx_set_scan,			/* SIOCSIWSCAN */
 		r8180_wx_get_scan,			/* SIOCGIWSCAN */
 		r8180_wx_set_essid,			/* SIOCSIWESSID */
@@ -1369,7 +1369,7 @@
 			(dst->capability & WLAN_CAPABILITY_BSS)));
 }
 
-/* WB modefied to show signal to GUI on 18-01-2008 */
+/* WB modified to show signal to GUI on 18-01-2008 */
 static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev)
 {
 	struct r8180_priv *priv = ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8187se/r8180_wx.h b/drivers/staging/rtl8187se/r8180_wx.h
index 735d03d..4081914 100644
--- a/drivers/staging/rtl8187se/r8180_wx.h
+++ b/drivers/staging/rtl8187se/r8180_wx.h
@@ -7,7 +7,7 @@
 	Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
 	Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
 
-	We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
+	We want to thanks the Authors of such projects and the Ndiswrapper project Authors.
 */
 
 /* this file (will) contains wireless extension handlers*/
diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c
index 4b0b830..9144957 100644
--- a/drivers/staging/rtl8187se/r8185b_init.c
+++ b/drivers/staging/rtl8187se/r8185b_init.c
@@ -1,22 +1,22 @@
-/*++
-Copyright (c) Realtek Semiconductor Corp. All rights reserved.
-
-Module Name:
-	r8185b_init.c
-
-Abstract:
-	Hardware Initialization and Hardware IO for RTL8185B
-
-Major Change History:
-	When		Who				What
-	----------	---------------		-------------------------------
-	2006-11-15    Xiong		Created
-
-Notes:
-	This file is ported from RTL8185B Windows driver.
-
-
---*/
+/*
+ * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Module Name:
+ *	r8185b_init.c
+ *
+ * Abstract:
+ *	Hardware Initialization and Hardware IO for RTL8185B
+ *
+ * Major Change History:
+ *	When		Who				What
+ *	----------	---------------		-------------------------------
+ *	2006-11-15	Xiong			Created
+ *
+ * Notes:
+ *	This file is ported from RTL8185B Windows driver.
+ *
+ *
+ */
 
 /*--------------------------Include File------------------------------------*/
 #include <linux/spinlock.h>
@@ -25,155 +25,134 @@
 #include "r8180_rtl8225.h" /* RTL8225 Radio frontend */
 #include "r8180_93cx6.h"   /* Card EEPROM */
 #include "r8180_wx.h"
-
 #include "ieee80211/dot11d.h"
-
-
 /* #define CONFIG_RTL8180_IO_MAP */
-
 #define TC_3W_POLL_MAX_TRY_CNT 5
+
 static u8 MAC_REG_TABLE[][2] =	{
-                        /*PAGA 0:	*/
-						/* 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185()	*/
-						/* 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185().					*/
-						/* 0x1F0~0x1F8  set in MacConfig_85BASIC()												*/
-						{0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42},
-						{0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03},
-						{0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03},
-						{0x94, 0x0F}, {0x95, 0x32},
-						{0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00},
-						{0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32},
-						{0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4},
-						{0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00},
-						{0xff, 0x00},
+	/*PAGA 0:	*/
+	/* 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185() */
+	/* 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). */
+	/* 0x1F0~0x1F8  set in MacConfig_85BASIC() */
+	{0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42},
+	{0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03},
+	{0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03},
+	{0x94, 0x0F}, {0x95, 0x32},
+	{0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00},
+	{0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32},
+	{0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4},
+	{0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00},
+	{0xff, 0x00},
 
-						/*PAGE 1:	*/
-						/* For Flextronics system Logo PCIHCT failure:	*/
-				/* 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1	*/
-						{0x5e, 0x01},
-						{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24},
-						{0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF},
-						{0x82, 0xFF}, {0x83, 0x03},
-						{0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, /* lzm add 080826 */
-						{0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22},/* lzm add 080826 */
-						{0xe2, 0x00},
+	/*PAGE 1: */
+	/* For Flextronics system Logo PCIHCT failure: */
+	/* 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1 */
+	{0x5e, 0x01},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24},
+	{0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF},
+	{0x82, 0xFF}, {0x83, 0x03},
+	{0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, /* lzm add 080826 */
+	{0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22}, /* lzm add 080826 */
+	{0xe2, 0x00},
 
 
-						/* PAGE 2: */
-						{0x5e, 0x02},
-						{0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5},
-						{0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff},
-						{0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08},
-						{0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f},
-						{0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f},
-						{0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff},
-						{0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00},
+	/* PAGE 2: */
+	{0x5e, 0x02},
+	{0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5},
+	{0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff},
+	{0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08},
+	{0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f},
+	{0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f},
+	{0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff},
+	{0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00},
 
-						/* PAGA 0: */
-						{0x5e, 0x00}, {0x9f, 0x03}
-			};
-
-
-static u8  ZEBRA_AGC[]	=	{
-			0,
-			0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72,
-			0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62,
-			0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07,
-			0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16,
-			0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e,
-			0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
-			0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
-			};
-
-static u32 ZEBRA_RF_RX_GAIN_TABLE[]	=	{
-			0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6,
-			0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057,
-			0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3,
-			0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3,
-			0x0183, 0x0163, 0x0143, 0x0123, 0x0103
+	/* PAGA 0: */
+	{0x5e, 0x00}, {0x9f, 0x03}
 	};
 
-static u8 OFDM_CONFIG[]	=	{
-			/* OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX				*/
-			/* OFDM reg0x3C[4]=1'b1: Enable RX power saving mode					*/
-			/* ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test	*/
 
-			/* 0x00	*/
-			0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50,
-			0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00,
-			/* 0x10	*/
-			0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26,
-			0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB,
-			/* 0x20	*/
-			0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00,
-			0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00,
-			/* 0x30	*/
-			0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e,
-			0xD8, 0x3C, 0x7B, 0x10, 0x10
-		};
+static u8  ZEBRA_AGC[] = {
+	0,
+	0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72,
+	0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62,
+	0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07,
+	0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16,
+	0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e,
+	0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+	0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
+	};
 
-/*	---------------------------------------------------------------
-	*	Hardware IO
-	*	the code is ported from Windows source code
-	----------------------------------------------------------------*/
+static u32 ZEBRA_RF_RX_GAIN_TABLE[] = {
+	0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6,
+	0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057,
+	0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3,
+	0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3,
+	0x0183, 0x0163, 0x0143, 0x0123, 0x0103
+	};
 
-void
-PlatformIOWrite1Byte(
-	struct net_device *dev,
-	u32		offset,
-	u8		data
-	)
+static u8 OFDM_CONFIG[]	= {
+	/* OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX */
+	/* OFDM reg0x3C[4]=1'b1: Enable RX power saving mode */
+	/* ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test */
+	/* 0x00	*/
+	0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50,
+	0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00,
+	/* 0x10	*/
+	0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26,
+	0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB,
+	/* 0x20	*/
+	0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00,
+	0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00,
+	/* 0x30	*/
+	0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e,
+	0xD8, 0x3C, 0x7B, 0x10, 0x10
+	};
+
+	/*---------------------------------------------------------------
+	 *	Hardware IO
+	 *	the code is ported from Windows source code
+	 *---------------------------------------------------------------
+	 */
+
+void PlatformIOWrite1Byte(struct net_device *dev, u32 offset, u8 data)
 {
 	write_nic_byte(dev, offset, data);
-	read_nic_byte(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko.	*/
-
+	read_nic_byte(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
 }
 
-void
-PlatformIOWrite2Byte(
-	struct net_device *dev,
-	u32		offset,
-	u16		data
-	)
+void PlatformIOWrite2Byte(struct net_device *dev, u32 offset, u16 data)
 {
 	write_nic_word(dev, offset, data);
 	read_nic_word(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
-
-
 }
+
 u8 PlatformIORead1Byte(struct net_device *dev, u32 offset);
 
-void
-PlatformIOWrite4Byte(
-	struct net_device *dev,
-	u32		offset,
-	u32		data
-	)
+void PlatformIOWrite4Byte(struct net_device *dev, u32 offset, u32 data)
 {
-/* {by amy 080312 */
-if (offset == PhyAddr)	{
-/* For Base Band configuration. */
+	if (offset == PhyAddr) {
+	/* For Base Band configuration. */
 		unsigned char	cmdByte;
 		unsigned long	dataBytes;
 		unsigned char	idx;
-		u8	u1bTmp;
+		u8		u1bTmp;
 
 		cmdByte = (u8)(data & 0x000000ff);
 		dataBytes = data>>8;
 
 		/*
-			071010, rcnjko:
-			The critical section is only BB read/write race condition.
-			Assumption:
-			1. We assume NO one will access BB at DIRQL, otherwise, system will crash for
-			acquiring the spinlock in such context.
-			2. PlatformIOWrite4Byte() MUST NOT be recursive.
-		*/
-/*		NdisAcquireSpinLock( &(pDevice->IoSpinLock) );	*/
+		 *	071010, rcnjko:
+		 *	The critical section is only BB read/write race condition.
+		 *	Assumption:
+		 *	1. We assume NO one will access BB at DIRQL, otherwise, system will crash for
+		 *	acquiring the spinlock in such context.
+		 *	2. PlatformIOWrite4Byte() MUST NOT be recursive.
+		 */
+		/* NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); */
 
-		for (idx = 0; idx < 30; idx++)	{ 
-		/* Make sure command bit is clear before access it.	*/
+		for (idx = 0; idx < 30; idx++) {
+		/* Make sure command bit is clear before access it. */
 			u1bTmp = PlatformIORead1Byte(dev, PhyAddr);
 			if ((u1bTmp & BIT7) == 0)
 				break;
@@ -186,20 +165,14 @@
 
 		write_nic_byte(dev, offset, cmdByte);
 
-/*		NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); */
-	}
-/* by amy 080312} */
-	else	{
+		/* NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); */
+	} else {
 		write_nic_dword(dev, offset, data);
 		read_nic_dword(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
 	}
 }
 
-u8
-PlatformIORead1Byte(
-	struct net_device *dev,
-	u32		offset
-	)
+u8 PlatformIORead1Byte(struct net_device *dev, u32 offset)
 {
 	u8	data = 0;
 
@@ -209,11 +182,7 @@
 	return data;
 }
 
-u16
-PlatformIORead2Byte(
-	struct net_device *dev,
-	u32		offset
-	)
+u16 PlatformIORead2Byte(struct net_device *dev, u32 offset)
 {
 	u16	data = 0;
 
@@ -223,11 +192,7 @@
 	return data;
 }
 
-u32
-PlatformIORead4Byte(
-	struct net_device *dev,
-	u32		offset
-	)
+u32 PlatformIORead4Byte(struct net_device *dev, u32 offset)
 {
 	u32	data = 0;
 
@@ -242,22 +207,19 @@
 	write_nic_word(dev, RFPinsEnable, 0x1bff);
 }
 
-static int
-HwHSSIThreeWire(
-	struct net_device *dev,
-	u8			*pDataBuf,
-	u8			nDataBufBitCnt,
-	int			bSI,
-	int			bWrite
-	)
+static int HwHSSIThreeWire(struct net_device *dev,
+			   u8 *pDataBuf,
+			   u8 nDataBufBitCnt,
+			   int bSI,
+			   int bWrite)
 {
 	int	bResult = 1;
 	u8	TryCnt;
 	u8	u1bTmp;
 
-	do	{
+	do {
 		/* Check if WE and RE are cleared. */
-		for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++)	{
+		for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
 			u1bTmp = read_nic_byte(dev, SW_3W_CMD1);
 			if ((u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0)
 				break;
@@ -275,15 +237,15 @@
 		u1bTmp = read_nic_byte(dev, RF_SW_CONFIG);
 
 		if (bSI)
-			u1bTmp |=   RF_SW_CFG_SI;   /* reg08[1]=1 Serial Interface(SI)	*/
+			u1bTmp |=   RF_SW_CFG_SI; /* reg08[1]=1 Serial Interface(SI) */
 
 		else
-			u1bTmp &= ~RF_SW_CFG_SI;  /* reg08[1]=0 Parallel Interface(PI)	*/
+			u1bTmp &= ~RF_SW_CFG_SI; /* reg08[1]=0 Parallel Interface(PI) */
 
 
 		write_nic_byte(dev, RF_SW_CONFIG, u1bTmp);
 
-		if (bSI)	{
+		if (bSI) {
 			/* jong: HW SI read must set reg84[3]=0. */
 			u1bTmp = read_nic_byte(dev, RFPinsSelect);
 			u1bTmp &= ~BIT3;
@@ -291,14 +253,14 @@
 		}
 		/*  Fill up data buffer for write operation. */
 
-		if (bWrite)	{
-			if (nDataBufBitCnt == 16)	{
+		if (bWrite) {
+			if (nDataBufBitCnt == 16) {
 				write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf));
-			}	else if (nDataBufBitCnt == 64)	{
+			} else if (nDataBufBitCnt == 64) {
 			/* RTL8187S shouldn't enter this case */
 				write_nic_dword(dev, SW_3W_DB0, *((u32 *)pDataBuf));
 				write_nic_dword(dev, SW_3W_DB1, *((u32 *)(pDataBuf + 4)));
-			}	else	{
+			} else {
 				int idx;
 				int ByteCnt = nDataBufBitCnt / 8;
 								/* printk("%d\n",nDataBufBitCnt); */
@@ -324,11 +286,11 @@
 					write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx));
 
 			}
-		}	else	{	/* read */
-			if (bSI)	{
-				/* SI - reg274[3:0] : RF register's Address	*/
+		} else {	/* read */
+			if (bSI) {
+				/* SI - reg274[3:0] : RF register's Address */
 				write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf));
-			}	else	{
+			} else {
 				/*  PI - reg274[15:12] : RF register's Address */
 				write_nic_word(dev, SW_3W_DB0, (*((u16 *)pDataBuf)) << 12);
 			}
@@ -343,7 +305,7 @@
 
 
 		/* Check if DONE is set. */
-		for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++)	{
+		for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
 			u1bTmp = read_nic_byte(dev, SW_3W_CMD1);
 			if ((u1bTmp & SW_3W_CMD1_DONE) != 0)
 				break;
@@ -353,12 +315,12 @@
 
 		write_nic_byte(dev, SW_3W_CMD1, 0);
 
-		/* Read back data for read operation.	*/
-		if (bWrite == 0)	{
-			if (bSI)		{
+		/* Read back data for read operation. */
+		if (bWrite == 0) {
+			if (bSI) {
 				/* Serial Interface : reg363_362[11:0] */
 				*((u16 *)pDataBuf) = read_nic_word(dev, SI_DATA_READ) ;
-			}	else	{
+			} else {
 				/* Parallel Interface : reg361_360[11:0] */
 				*((u16 *)pDataBuf) = read_nic_word(dev, PI_DATA_READ);
 			}
@@ -366,13 +328,12 @@
 			*((u16 *)pDataBuf) &= 0x0FFF;
 		}
 
-	}	while (0);
+	} while (0);
 
 	return bResult;
 }
 
-void
-RF_WriteReg(struct net_device *dev, u8 offset, u32 data)
+void RF_WriteReg(struct net_device *dev, u8 offset, u32 data)
 {
 	u32 data2Write;
 	u8 len;
@@ -400,11 +361,7 @@
 
 
 /* by Owen on 04/07/14 for writing BB register successfully */
-void
-WriteBBPortUchar(
-	struct net_device *dev,
-	u32		Data
-	)
+void WriteBBPortUchar(struct net_device *dev, u32 Data)
 {
 	/* u8	TimeoutCounter; */
 	u8	RegisterContent;
@@ -421,11 +378,7 @@
 	}
 }
 
-u8
-ReadBBPortUchar(
-	struct net_device *dev,
-	u32		addr
-	)
+u8 ReadBBPortUchar(struct net_device *dev, u32 addr)
 {
 	/*u8	TimeoutCounter; */
 	u8	RegisterContent;
@@ -435,66 +388,62 @@
 
 	return RegisterContent;
 }
-/* {by amy 080312 */
 /*
-	Description:
-	Perform Antenna settings with antenna diversity on 87SE.
-		Created by Roger, 2008.01.25.
-*/
-bool
-SetAntennaConfig87SE(
-	struct net_device *dev,
-	u8			DefaultAnt,		/* 0: Main, 1: Aux.			*/
-	bool		bAntDiversity	/* 1:Enable, 0: Disable.	*/
-)
+ *	Description:
+ *	Perform Antenna settings with antenna diversity on 87SE.
+ *		Created by Roger, 2008.01.25.
+ */
+bool SetAntennaConfig87SE(struct net_device *dev,
+			  u8   DefaultAnt, /* 0: Main, 1: Aux. */
+			  bool bAntDiversity) /* 1:Enable, 0: Disable. */
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 	bool   bAntennaSwitched = true;
 
 	/* printk("SetAntennaConfig87SE(): DefaultAnt(%d), bAntDiversity(%d)\n", DefaultAnt, bAntDiversity); */
 
-	/* Threshold for antenna diversity.	*/
+	/* Threshold for antenna diversity. */
 	write_phy_cck(dev, 0x0c, 0x09); /* Reg0c : 09 */
 
-	if (bAntDiversity)	{	/*	Enable Antenna Diversity.	*/
-		if (DefaultAnt == 1)	{	/* aux antenna			*/
+	if (bAntDiversity) {	/*	Enable Antenna Diversity. */
+		if (DefaultAnt == 1) {	/* aux antenna */
 
-			/* Mac register, aux antenna	*/
+			/* Mac register, aux antenna */
 			write_nic_byte(dev, ANTSEL, 0x00);
 
-			/* Config CCK RX antenna.		*/
+			/* Config CCK RX antenna. */
 			write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */
 			write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */
 
-			/* Config OFDM RX antenna.	*/
-			write_phy_ofdm(dev, 0x0D, 0x54);	/* Reg0d : 54	*/
-			write_phy_ofdm(dev, 0x18, 0xb2);	/* Reg18 : b2		*/
-		}	else	{	/*  use main antenna	*/
-			/* Mac register, main antenna		*/
+			/* Config OFDM RX antenna. */
+			write_phy_ofdm(dev, 0x0D, 0x54);	/* Reg0d : 54 */
+			write_phy_ofdm(dev, 0x18, 0xb2);	/* Reg18 : b2 */
+		} else { /*  use main antenna */
+			/* Mac register, main antenna */
 			write_nic_byte(dev, ANTSEL, 0x03);
-			/* base band				*/
-			/*  Config CCK RX antenna.	*/
-			write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b	*/
-			write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7	*/
+			/* base band */
+			/*  Config CCK RX antenna. */
+			write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */
+			write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */
 
 			/* Config OFDM RX antenna. */
 			write_phy_ofdm(dev, 0x0d, 0x5c);  /* Reg0d : 5c	*/
 			write_phy_ofdm(dev, 0x18, 0xb2);  /* Reg18 : b2	*/
 		}
-	}	else	{
+	} else {
 		/* Disable Antenna Diversity. */
-		if (DefaultAnt == 1)	{	/* aux Antenna */
+		if (DefaultAnt == 1) { /* aux Antenna */
 			/* Mac register, aux antenna */
 			write_nic_byte(dev, ANTSEL, 0x00);
 
 			/* Config CCK RX antenna. */
-			write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb	*/
-			write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47	*/
+			write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */
+			write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */
 
 			/* Config OFDM RX antenna. */
-			write_phy_ofdm(dev, 0x0D, 0x54);	/* Reg0d : 54	*/
-			write_phy_ofdm(dev, 0x18, 0x32);	/* Reg18 : 32	*/
-		}	else	{	/* main Antenna */
+			write_phy_ofdm(dev, 0x0D, 0x54);	/* Reg0d : 54 */
+			write_phy_ofdm(dev, 0x18, 0x32);	/* Reg18 : 32 */
+		} else { /* main Antenna */
 			/* Mac register, main antenna */
 			write_nic_byte(dev, ANTSEL, 0x03);
 
@@ -502,25 +451,22 @@
 			write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */
 			write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */
 
-			/* Config OFDM RX antenna.		*/
-			write_phy_ofdm(dev, 0x0D, 0x5c);	/* Reg0d : 5c	*/
-			write_phy_ofdm(dev, 0x18, 0x32);	/*Reg18 : 32	*/
+			/* Config OFDM RX antenna. */
+			write_phy_ofdm(dev, 0x0D, 0x5c); /* Reg0d : 5c */
+			write_phy_ofdm(dev, 0x18, 0x32); /*Reg18 : 32 */
 		}
 	}
 	priv->CurrAntennaIndex = DefaultAnt; /* Update default settings. */
 	return	bAntennaSwitched;
 }
-/* by amy 080312 */
 /*
----------------------------------------------------------------
-	*	Hardware Initialization.
-	*	the code is ported from Windows source code
-----------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ *		Hardware Initialization.
+ *		the code is ported from Windows source code
+ *--------------------------------------------------------------
+ */
 
-void
-ZEBRA_Config_85BASIC_HardCode(
-	struct net_device *dev
-	)
+void ZEBRA_Config_85BASIC_HardCode(struct net_device *dev)
 {
 
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
@@ -532,163 +478,151 @@
 
 
 /*
-=============================================================================
-	87S_PCIE :: RADIOCFG.TXT
-=============================================================================
-*/
+ *===========================================================================
+ *	87S_PCIE :: RADIOCFG.TXT
+ *===========================================================================
+ */
 
 
 	/* Page1 : reg16-reg30 */
-	RF_WriteReg(dev, 0x00, 0x013f);			mdelay(1); /* switch to page1 */
-	u4bRF23 = RF_ReadReg(dev, 0x08);			mdelay(1);
-	u4bRF24 = RF_ReadReg(dev, 0x09);			mdelay(1);
+	RF_WriteReg(dev, 0x00, 0x013f);		mdelay(1); /* switch to page1 */
+	u4bRF23 = RF_ReadReg(dev, 0x08);	mdelay(1);
+	u4bRF24 = RF_ReadReg(dev, 0x09);	mdelay(1);
 
 	if (u4bRF23 == 0x818 && u4bRF24 == 0x70C) {
 		d_cut = 1;
 		printk(KERN_INFO "rtl8187se: card type changed from C- to D-cut\n");
 	}
 
-	/* Page0 : reg0-reg15	*/
+	/* Page0 : reg0-reg15 */
 
-	RF_WriteReg(dev, 0x00, 0x009f);			mdelay(1);/* 1	*/
-
-	RF_WriteReg(dev, 0x01, 0x06e0);			mdelay(1);
-
-	RF_WriteReg(dev, 0x02, 0x004d);			mdelay(1);/* 2	*/
-
-	RF_WriteReg(dev, 0x03, 0x07f1);			mdelay(1);/* 3	*/
-
-	RF_WriteReg(dev, 0x04, 0x0975);			mdelay(1);
-	RF_WriteReg(dev, 0x05, 0x0c72);			mdelay(1);
-	RF_WriteReg(dev, 0x06, 0x0ae6);			mdelay(1);
-	RF_WriteReg(dev, 0x07, 0x00ca);			mdelay(1);
-	RF_WriteReg(dev, 0x08, 0x0e1c);			mdelay(1);
-	RF_WriteReg(dev, 0x09, 0x02f0);			mdelay(1);
-	RF_WriteReg(dev, 0x0a, 0x09d0);			mdelay(1);
-	RF_WriteReg(dev, 0x0b, 0x01ba);			mdelay(1);
-	RF_WriteReg(dev, 0x0c, 0x0640);			mdelay(1);
-	RF_WriteReg(dev, 0x0d, 0x08df);			mdelay(1);
-	RF_WriteReg(dev, 0x0e, 0x0020);			mdelay(1);
-	RF_WriteReg(dev, 0x0f, 0x0990);			mdelay(1);
-
+	RF_WriteReg(dev, 0x00, 0x009f);		mdelay(1);/* 1	*/
+	RF_WriteReg(dev, 0x01, 0x06e0);		mdelay(1);
+	RF_WriteReg(dev, 0x02, 0x004d);		mdelay(1);/* 2	*/
+	RF_WriteReg(dev, 0x03, 0x07f1);		mdelay(1);/* 3	*/
+	RF_WriteReg(dev, 0x04, 0x0975);		mdelay(1);
+	RF_WriteReg(dev, 0x05, 0x0c72);		mdelay(1);
+	RF_WriteReg(dev, 0x06, 0x0ae6);		mdelay(1);
+	RF_WriteReg(dev, 0x07, 0x00ca);		mdelay(1);
+	RF_WriteReg(dev, 0x08, 0x0e1c);		mdelay(1);
+	RF_WriteReg(dev, 0x09, 0x02f0);		mdelay(1);
+	RF_WriteReg(dev, 0x0a, 0x09d0);		mdelay(1);
+	RF_WriteReg(dev, 0x0b, 0x01ba);		mdelay(1);
+	RF_WriteReg(dev, 0x0c, 0x0640);		mdelay(1);
+	RF_WriteReg(dev, 0x0d, 0x08df);		mdelay(1);
+	RF_WriteReg(dev, 0x0e, 0x0020);		mdelay(1);
+	RF_WriteReg(dev, 0x0f, 0x0990);		mdelay(1);
 
 	/*  Page1 : reg16-reg30 */
-	RF_WriteReg(dev, 0x00, 0x013f);			mdelay(1);
-
-	RF_WriteReg(dev, 0x03, 0x0806);			mdelay(1);
-
-	RF_WriteReg(dev, 0x04, 0x03a7);			mdelay(1);
-	RF_WriteReg(dev, 0x05, 0x059b);			mdelay(1);
-	RF_WriteReg(dev, 0x06, 0x0081);			mdelay(1);
-
-
-	RF_WriteReg(dev, 0x07, 0x01A0);			mdelay(1);
+	RF_WriteReg(dev, 0x00, 0x013f);		mdelay(1);
+	RF_WriteReg(dev, 0x03, 0x0806);		mdelay(1);
+	RF_WriteReg(dev, 0x04, 0x03a7);		mdelay(1);
+	RF_WriteReg(dev, 0x05, 0x059b);		mdelay(1);
+	RF_WriteReg(dev, 0x06, 0x0081);		mdelay(1);
+	RF_WriteReg(dev, 0x07, 0x01A0);		mdelay(1);
 /* Don't write RF23/RF24 to make a difference between 87S C cut and D cut. asked by SD3 stevenl. */
-	RF_WriteReg(dev, 0x0a, 0x0001);			mdelay(1);
-	RF_WriteReg(dev, 0x0b, 0x0418);			mdelay(1);
+	RF_WriteReg(dev, 0x0a, 0x0001);		mdelay(1);
+	RF_WriteReg(dev, 0x0b, 0x0418);		mdelay(1);
 
 	if (d_cut) {
-		RF_WriteReg(dev, 0x0c, 0x0fbe);			mdelay(1);
-		RF_WriteReg(dev, 0x0d, 0x0008);			mdelay(1);
-		RF_WriteReg(dev, 0x0e, 0x0807);			mdelay(1); /* RX LO buffer */
-	}	else	{
-		RF_WriteReg(dev, 0x0c, 0x0fbe);			mdelay(1);
-		RF_WriteReg(dev, 0x0d, 0x0008);			mdelay(1);
-		RF_WriteReg(dev, 0x0e, 0x0806);			mdelay(1); /* RX LO buffer */
+		RF_WriteReg(dev, 0x0c, 0x0fbe);		mdelay(1);
+		RF_WriteReg(dev, 0x0d, 0x0008);		mdelay(1);
+		RF_WriteReg(dev, 0x0e, 0x0807);		mdelay(1); /* RX LO buffer */
+	} else {
+		RF_WriteReg(dev, 0x0c, 0x0fbe);		mdelay(1);
+		RF_WriteReg(dev, 0x0d, 0x0008);		mdelay(1);
+		RF_WriteReg(dev, 0x0e, 0x0806);		mdelay(1); /* RX LO buffer */
 	}
 
-	RF_WriteReg(dev, 0x0f, 0x0acc);			mdelay(1);
+	RF_WriteReg(dev, 0x0f, 0x0acc);		mdelay(1);
+	RF_WriteReg(dev, 0x00, 0x01d7);		mdelay(1); /* 6 */
+	RF_WriteReg(dev, 0x03, 0x0e00);		mdelay(1);
+	RF_WriteReg(dev, 0x04, 0x0e50);		mdelay(1);
 
-	RF_WriteReg(dev, 0x00, 0x01d7);			mdelay(1); /* 6 */
-
-	RF_WriteReg(dev, 0x03, 0x0e00);			mdelay(1);
-	RF_WriteReg(dev, 0x04, 0x0e50);			mdelay(1);
-	for (i = 0; i <= 36; i++)	{
-		RF_WriteReg(dev, 0x01, i);                     mdelay(1);
+	for (i = 0; i <= 36; i++) {
+		RF_WriteReg(dev, 0x01, i);		mdelay(1);
 		RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1);
 	}
 
-	RF_WriteReg(dev, 0x05, 0x0203);			mdelay(1);	/* 203, 343	*/
-	RF_WriteReg(dev, 0x06, 0x0200);			mdelay(1);	/* 400		*/
+	RF_WriteReg(dev, 0x05, 0x0203);		mdelay(1); /* 203, 343 */
+	RF_WriteReg(dev, 0x06, 0x0200);		mdelay(1); /* 400 */
+	RF_WriteReg(dev, 0x00, 0x0137);		mdelay(1); /* switch to reg16-reg30, and HSSI disable 137 */
+	mdelay(10); /* Deay 10 ms. */		/* 0xfd */
 
-	RF_WriteReg(dev, 0x00, 0x0137);			mdelay(1);	/* switch to reg16-reg30, and HSSI disable 137	*/
-	mdelay(10);		/* Deay 10 ms.	*/	/* 0xfd */
+	RF_WriteReg(dev, 0x0d, 0x0008);		mdelay(1); /* Z4 synthesizer loop filter setting, 392 */
+	mdelay(10); /* Deay 10 ms. */		/* 0xfd */
 
-	RF_WriteReg(dev, 0x0d, 0x0008);			mdelay(1);	/* Z4 synthesizer loop filter setting, 392		*/
-	mdelay(10);		/* Deay 10 ms.	*/	/* 0xfd */
+	RF_WriteReg(dev, 0x00, 0x0037);		mdelay(1); /* switch to reg0-reg15, and HSSI disable */
+	mdelay(10); /* Deay 10 ms. */		/* 0xfd	*/
 
-	RF_WriteReg(dev, 0x00, 0x0037);			mdelay(1);	/* switch to reg0-reg15, and HSSI disable		*/
-	mdelay(10);		/* Deay 10 ms.	*/	/* 0xfd	*/
+	RF_WriteReg(dev, 0x04, 0x0160);		mdelay(1); /* CBC on, Tx Rx disable, High gain */
+	mdelay(10); /* Deay 10 ms. */		/* 0xfd	*/
 
-	RF_WriteReg(dev, 0x04, 0x0160);			mdelay(1);	/* CBC on, Tx Rx disable, High gain				*/
-	mdelay(10);		/* Deay 10 ms.	*/	/* 0xfd	*/
+	RF_WriteReg(dev, 0x07, 0x0080);		mdelay(1); /* Z4 setted channel 1 */
+	mdelay(10); /* Deay 10 ms. */		/* 0xfd	*/
 
-	RF_WriteReg(dev, 0x07, 0x0080);			mdelay(1);	/* Z4 setted channel 1							*/
-	mdelay(10);		/* Deay 10 ms.	*/	/* 0xfd	*/
+	RF_WriteReg(dev, 0x02, 0x088D);		mdelay(1); /* LC calibration */
+	mdelay(200); /* Deay 200 ms. */		/* 0xfd	*/
+	mdelay(10);  /* Deay 10 ms. */		/* 0xfd	*/
+	mdelay(10);  /* Deay 10 ms. */		/* 0xfd	*/
 
-	RF_WriteReg(dev, 0x02, 0x088D);			mdelay(1);	/* LC calibration								*/
-	mdelay(200);	/* Deay 200 ms.	*/	/* 0xfd	*/
-	mdelay(10);		/* Deay 10 ms.	*/	/* 0xfd	*/
-	mdelay(10);		/* Deay 10 ms.	*/	/* 0xfd	*/
+	RF_WriteReg(dev, 0x00, 0x0137);		mdelay(1); /* switch to reg16-reg30 137, and HSSI disable 137 */
+	mdelay(10); /* Deay 10 ms. */		/* 0xfd	*/
 
-	RF_WriteReg(dev, 0x00, 0x0137);			mdelay(1);	/* switch to reg16-reg30 137, and HSSI disable 137	*/
-	mdelay(10);		/* Deay 10 ms.	*/	/* 0xfd	*/
-
-	RF_WriteReg(dev, 0x07, 0x0000);			mdelay(1);
-	RF_WriteReg(dev, 0x07, 0x0180);			mdelay(1);
-	RF_WriteReg(dev, 0x07, 0x0220);			mdelay(1);
-	RF_WriteReg(dev, 0x07, 0x03E0);			mdelay(1);
+	RF_WriteReg(dev, 0x07, 0x0000);		mdelay(1);
+	RF_WriteReg(dev, 0x07, 0x0180);		mdelay(1);
+	RF_WriteReg(dev, 0x07, 0x0220);		mdelay(1);
+	RF_WriteReg(dev, 0x07, 0x03E0);		mdelay(1);
 
 	/* DAC calibration off 20070702	*/
-	RF_WriteReg(dev, 0x06, 0x00c1);			mdelay(1);
-	RF_WriteReg(dev, 0x0a, 0x0001);			mdelay(1);
-/* {by amy 080312 */
+	RF_WriteReg(dev, 0x06, 0x00c1);		mdelay(1);
+	RF_WriteReg(dev, 0x0a, 0x0001);		mdelay(1);
 	/* For crystal calibration, added by Roger, 2007.12.11. */
-	if (priv->bXtalCalibration)	{	/* reg 30.	*/
-	 /* enable crystal calibration.
-			RF Reg[30], (1)Xin:[12:9], Xout:[8:5],  addr[4:0].
-			(2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0
-			(3)RF signal on/off when calibration[13], default: on, set BIT13=0.
-			So we should minus 4 BITs offset.		*/
-		RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9);			mdelay(1);
+	if (priv->bXtalCalibration) { /* reg 30.	*/
+	 /*
+ 	  *  enable crystal calibration.
+	  *		RF Reg[30], (1)Xin:[12:9], Xout:[8:5],  addr[4:0].
+	  *		(2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0
+	  *		(3)RF signal on/off when calibration[13], default: on, set BIT13=0.
+	  *		So we should minus 4 BITs offset. 
+	  */
+		RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9); mdelay(1);
 		printk("ZEBRA_Config_85BASIC_HardCode(): (%02x)\n",
-				(priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9);
-	}	else	{
+		      (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9);
+	} else {
 		/* using default value. Xin=6, Xout=6.	*/
-		RF_WriteReg(dev, 0x0f, 0x0acc);			mdelay(1);
+		RF_WriteReg(dev, 0x0f, 0x0acc);		mdelay(1);
 	}
-/* by amy 080312 */
 
-	RF_WriteReg(dev, 0x00, 0x00bf);			mdelay(1); /* switch to reg0-reg15, and HSSI enable	*/
-	RF_WriteReg(dev, 0x0d, 0x08df);			mdelay(1); /* Rx BB start calibration, 00c//+edward	*/
-	RF_WriteReg(dev, 0x02, 0x004d);			mdelay(1); /* temperature meter off					*/
-	RF_WriteReg(dev, 0x04, 0x0975);			mdelay(1); /* Rx mode								*/
+	RF_WriteReg(dev, 0x00, 0x00bf);		mdelay(1); /* switch to reg0-reg15, and HSSI enable */
+	RF_WriteReg(dev, 0x0d, 0x08df);		mdelay(1); /* Rx BB start calibration, 00c//+edward */
+	RF_WriteReg(dev, 0x02, 0x004d);		mdelay(1); /* temperature meter off */
+	RF_WriteReg(dev, 0x04, 0x0975);		mdelay(1); /* Rx mode */
 	mdelay(10);	/* Deay 10 ms.*/	/* 0xfe	*/
 	mdelay(10);	/* Deay 10 ms.*/	/* 0xfe	*/
 	mdelay(10);	/* Deay 10 ms.*/	/* 0xfe	*/
-	RF_WriteReg(dev, 0x00, 0x0197);			mdelay(1); /* Rx mode*/	/*+edward	*/
-	RF_WriteReg(dev, 0x05, 0x05ab);			mdelay(1); /* Rx mode*/	/*+edward	*/
-	RF_WriteReg(dev, 0x00, 0x009f);			mdelay(1); /* Rx mode*/	/*+edward	*/
-
-	RF_WriteReg(dev, 0x01, 0x0000);			mdelay(1); /* Rx mode*/	/*+edward	*/
-	RF_WriteReg(dev, 0x02, 0x0000);			mdelay(1); /* Rx mode*/	/*+edward	*/
-	/* power save parameters.	*/
+	RF_WriteReg(dev, 0x00, 0x0197);		mdelay(1); /* Rx mode*/	/*+edward */
+	RF_WriteReg(dev, 0x05, 0x05ab);		mdelay(1); /* Rx mode*/	/*+edward */
+	RF_WriteReg(dev, 0x00, 0x009f);		mdelay(1); /* Rx mode*/	/*+edward */
+	RF_WriteReg(dev, 0x01, 0x0000);		mdelay(1); /* Rx mode*/	/*+edward */
+	RF_WriteReg(dev, 0x02, 0x0000);		mdelay(1); /* Rx mode*/	/*+edward */
+	/* power save parameters. */
 	u1b24E = read_nic_byte(dev, 0x24E);
 	write_nic_byte(dev, 0x24E, (u1b24E & (~(BIT5|BIT6))));
 
 	/*=============================================================================
-
-	=============================================================================
-	CCKCONF.TXT
-	=============================================================================
-	*/
-	/*	[POWER SAVE] Power Saving Parameters by jong. 2007-11-27
-		CCK reg0x00[7]=1'b1 :power saving for TX (default)
-		CCK reg0x00[6]=1'b1: power saving for RX (default)
-		CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation.
-		CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1
-		CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0
-	*/
+	 *
+	 *===========================================================================
+	 * CCKCONF.TXT
+	 *===========================================================================
+	 *
+	 *	[POWER SAVE] Power Saving Parameters by jong. 2007-11-27
+	 *	CCK reg0x00[7]=1'b1 :power saving for TX (default)
+	 *	CCK reg0x00[6]=1'b1: power saving for RX (default)
+	 *	CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation.
+	 *	CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1
+	 *	CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0
+	 */
 
 	write_phy_cck(dev, 0x00, 0xc8);
 	write_phy_cck(dev, 0x06, 0x1c);
@@ -697,7 +631,7 @@
 	write_phy_cck(dev, 0x2f, 0x06);
 	write_phy_cck(dev, 0x01, 0x46);
 
-	/* power control	*/
+	/* power control */
 	write_nic_byte(dev, CCK_TXAGC, 0x10);
 	write_nic_byte(dev, OFDM_TXAGC, 0x1B);
 	write_nic_byte(dev, ANTSEL, 0x03);
@@ -705,14 +639,14 @@
 
 
 	/*
-	=============================================================================
-		AGC.txt
-	=============================================================================
-	*/
+	 *===========================================================================
+	 *	AGC.txt
+	 *===========================================================================
+	 */
 
 	write_phy_ofdm(dev, 0x00, 0x12);
 
-	for (i = 0; i < 128; i++)	{
+	for (i = 0; i < 128; i++) {
 
 		data = ZEBRA_AGC[i+1];
 		data = data << 8;
@@ -730,49 +664,43 @@
 	PlatformIOWrite4Byte(dev, PhyAddr, 0x00001080);	/* Annie, 2006-05-05 */
 
 	/*
-	=============================================================================
+	 *===========================================================================
+	 *
+	 *===========================================================================
+	 * OFDMCONF.TXT
+	 *===========================================================================
+	 */
 
-	=============================================================================
-	OFDMCONF.TXT
-	=============================================================================
-	*/
-
-	for (i = 0; i < 60; i++)	{
+	for (i = 0; i < 60; i++) {
 		u4bRegOffset = i;
 		u4bRegValue = OFDM_CONFIG[i];
 
 		WriteBBPortUchar(dev,
-						(0x00000080 |
-						(u4bRegOffset & 0x7f) |
-						((u4bRegValue & 0xff) << 8)));
+				(0x00000080 |
+				(u4bRegOffset & 0x7f) |
+				((u4bRegValue & 0xff) << 8)));
 	}
 
 	/*
-	=============================================================================
-	by amy for antenna
-	=============================================================================
-	*/
-/* {by amy 080312 */
+	 *===========================================================================
+	 * by amy for antenna
+	 *===========================================================================
+	 */
 	/* Config Sw/Hw  Combinational Antenna Diversity. Added by Roger, 2008.02.26.	*/
 	SetAntennaConfig87SE(dev, priv->bDefaultAntenna1, priv->bSwAntennaDiverity);
-/* by amy 080312} */
-/* by amy for antenna */
 }
 
 
-void
-UpdateInitialGain(
-	struct net_device *dev
-	)
+void UpdateInitialGain(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 
 	/* lzm add 080826 */
-	if (priv->eRFPowerState != eRfOn)	{
+	if (priv->eRFPowerState != eRfOn) {
 		/*	Don't access BB/RF under disable PLL situation.
-			RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n"));
-			Back to the original state
-		*/
+		 *	RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n"));
+		 *	Back to the original state
+		 */
 		priv->InitialGain = priv->InitialGainBackUp;
 		return;
 	}
@@ -826,7 +754,7 @@
 		write_phy_ofdm(dev, 0x05, 0xfc);	mdelay(1);
 		break;
 
-	default:	/* MP */
+	default: /* MP */
 		write_phy_ofdm(dev, 0x17, 0x26);	mdelay(1);
 		write_phy_ofdm(dev, 0x24, 0x86);	mdelay(1);
 		write_phy_ofdm(dev, 0x05, 0xfa);	mdelay(1);
@@ -834,14 +762,11 @@
 	}
 }
 /*
-	Description:
-		Tx Power tracking mechanism routine on 87SE.
-	Created by Roger, 2007.12.11.
-*/
-void
-InitTxPwrTracking87SE(
-	struct net_device *dev
-)
+ *	Description:
+ *		Tx Power tracking mechanism routine on 87SE.
+ *	Created by Roger, 2007.12.11.
+ */
+void InitTxPwrTracking87SE(struct net_device *dev)
 {
 	u32	u4bRfReg;
 
@@ -851,49 +776,41 @@
 	RF_WriteReg(dev, 0x02, u4bRfReg|PWR_METER_EN);			mdelay(1);
 }
 
-void
-PhyConfig8185(
-	struct net_device *dev
-	)
+void PhyConfig8185(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 		write_nic_dword(dev, RCR, priv->ReceiveConfig);
 	   priv->RFProgType = read_nic_byte(dev, CONFIG4) & 0x03;
 	/*  RF config */
 	ZEBRA_Config_85BASIC_HardCode(dev);
-/* {by amy 080312 */
 	/* Set default initial gain state to 4, approved by SD3 DZ, by Bruce, 2007-06-06. */
-	if (priv->bDigMechanism)	{
+	if (priv->bDigMechanism) {
 		if (priv->InitialGain == 0)
 			priv->InitialGain = 4;
 	}
 
 	/*
-		Enable thermal meter indication to implement TxPower tracking on 87SE.
-		We initialize thermal meter here to avoid unsuccessful configuration.
-		Added by Roger, 2007.12.11.
-	*/
+	 *	Enable thermal meter indication to implement TxPower tracking on 87SE.
+	 *	We initialize thermal meter here to avoid unsuccessful configuration.
+	 *	Added by Roger, 2007.12.11.
+	 */
 	if (priv->bTxPowerTrack)
 		InitTxPwrTracking87SE(dev);
 
-/* by amy 080312} */
 	priv->InitialGainBackUp = priv->InitialGain;
 	UpdateInitialGain(dev);
 
 	return;
 }
 
-void
-HwConfigureRTL8185(
-		struct net_device *dev
-		)
+void HwConfigureRTL8185(struct net_device *dev)
 {
 	/* RTL8185_TODO: Determine Retrylimit, TxAGC, AutoRateFallback control. */
-	u8		bUNIVERSAL_CONTROL_RL = 0;
-	u8		bUNIVERSAL_CONTROL_AGC = 1;
-	u8		bUNIVERSAL_CONTROL_ANT = 1;
-	u8		bAUTO_RATE_FALLBACK_CTL = 1;
-	u8		val8;
+	u8 bUNIVERSAL_CONTROL_RL = 0;
+	u8 bUNIVERSAL_CONTROL_AGC = 1;
+	u8 bUNIVERSAL_CONTROL_ANT = 1;
+	u8 bAUTO_RATE_FALLBACK_CTL = 1;
+	u8 val8;
 	write_nic_word(dev, BRSR, 0x0fff);
 	/* Retry limit */
 	val8 = read_nic_byte(dev, CW_CONF);
@@ -907,24 +824,24 @@
 
 	/* Tx AGC */
 	val8 = read_nic_byte(dev, TXAGC_CTL);
-	if (bUNIVERSAL_CONTROL_AGC)	{
+	if (bUNIVERSAL_CONTROL_AGC) {
 		write_nic_byte(dev, CCK_TXAGC, 128);
 		write_nic_byte(dev, OFDM_TXAGC, 128);
 		val8 = val8 & 0xfe;
-	}	else	{
+	} else {
 		val8 = val8 | 0x01 ;
 	}
 
 
 	write_nic_byte(dev, TXAGC_CTL, val8);
 
-	/* Tx Antenna including Feedback control	*/
+	/* Tx Antenna including Feedback control */
 	val8 = read_nic_byte(dev, TXAGC_CTL);
 
-	if (bUNIVERSAL_CONTROL_ANT)	{
+	if (bUNIVERSAL_CONTROL_ANT) {
 		write_nic_byte(dev, ANTSEL, 0x00);
 		val8 = val8 & 0xfd;
-	}	else	{
+	} else {
 		val8 = val8 & (val8|0x02); /* xiong-2006-11-15 */
 	}
 
@@ -933,7 +850,7 @@
 	/* Auto Rate fallback control	*/
 	val8 = read_nic_byte(dev, RATE_FALLBACK);
 	val8 &= 0x7c;
-	if (bAUTO_RATE_FALLBACK_CTL)	{
+	if (bAUTO_RATE_FALLBACK_CTL) {
 		val8 |= RATE_FALLBACK_CTL_ENABLE | RATE_FALLBACK_CTL_AUTO_STEP1;
 
 		/* <RJ_TODO_8185B> We shall set up the ARFR according to user's setting. */
@@ -942,40 +859,34 @@
 	write_nic_byte(dev, RATE_FALLBACK, val8);
 }
 
-static void
-MacConfig_85BASIC_HardCode(
-	struct net_device *dev)
+static void MacConfig_85BASIC_HardCode(struct net_device *dev)
 {
 	/*
-	============================================================================
-	MACREG.TXT
-	============================================================================
-	*/
-	int			nLinesRead = 0;
-
-	u32	u4bRegOffset, u4bRegValue, u4bPageIndex = 0;
-	int	i;
+	 *==========================================================================
+	 * MACREG.TXT
+	 *==========================================================================
+	 */
+	int nLinesRead = 0;
+	u32 u4bRegOffset, u4bRegValue, u4bPageIndex = 0;
+	int i;
 
 	nLinesRead = sizeof(MAC_REG_TABLE)/2;
 
-	for (i = 0; i < nLinesRead; i++)	{	/* nLinesRead=101 */
+	for (i = 0; i < nLinesRead; i++) { /* nLinesRead=101 */
 		u4bRegOffset = MAC_REG_TABLE[i][0];
 		u4bRegValue = MAC_REG_TABLE[i][1];
 
 				if (u4bRegOffset == 0x5e)
 					u4bPageIndex = u4bRegValue;
-
 				else
-						u4bRegOffset |= (u4bPageIndex << 8);
+					u4bRegOffset |= (u4bPageIndex << 8);
 
 		write_nic_byte(dev, u4bRegOffset, (u8)u4bRegValue);
 	}
 	/* ============================================================================ */
 }
 
-static void
-MacConfig_85BASIC(
-	struct net_device *dev)
+static void MacConfig_85BASIC(struct net_device *dev)
 {
 
 	u8			u1DA;
@@ -994,18 +905,18 @@
 	PlatformIOWrite4Byte(dev, 0x1F4, 0x00000000);
 	PlatformIOWrite1Byte(dev, 0x1F8, 0x00);
 
-	/* Asked for by SD3 CM Lin, 2006.06.27, by rcnjko.	*/
-	/* power save parameter based on "87SE power save parameters 20071127.doc", as follow.	*/
+	/* Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. */
+	/* power save parameter based on "87SE power save parameters 20071127.doc", as follow. */
 
 	/* Enable DA10 TX power saving */
 	u1DA = read_nic_byte(dev, PHYPR);
 	write_nic_byte(dev, PHYPR, (u1DA | BIT2));
 
-	/* POWER:	*/
+	/* POWER: */
 	write_nic_word(dev, 0x360, 0x1000);
 	write_nic_word(dev, 0x362, 0x1000);
 
-	/* AFE.		*/
+	/* AFE. */
 	write_nic_word(dev, 0x370, 0x0560);
 	write_nic_word(dev, 0x372, 0x0560);
 	write_nic_word(dev, 0x374, 0x0DA4);
@@ -1013,54 +924,48 @@
 	write_nic_word(dev, 0x378, 0x0560);
 	write_nic_word(dev, 0x37A, 0x0560);
 	write_nic_word(dev, 0x37C, 0x00EC);
-	write_nic_word(dev, 0x37E, 0x00EC);	/*+edward	*/
+	write_nic_word(dev, 0x37E, 0x00EC); /* +edward */
 	write_nic_byte(dev, 0x24E, 0x01);
 }
 
-u8
-GetSupportedWirelessMode8185(
-	struct net_device *dev
-)
+u8 GetSupportedWirelessMode8185(struct net_device *dev)
 {
-	u8			btSupportedWirelessMode = 0;
+	u8 btSupportedWirelessMode = 0;
 
 	btSupportedWirelessMode = (WIRELESS_MODE_B | WIRELESS_MODE_G);
 	return btSupportedWirelessMode;
 }
 
-void
-ActUpdateChannelAccessSetting(
-	struct net_device *dev,
-	WIRELESS_MODE			WirelessMode,
-	PCHANNEL_ACCESS_SETTING	ChnlAccessSetting
-	)
+void ActUpdateChannelAccessSetting(struct net_device *dev,
+				   WIRELESS_MODE WirelessMode,
+				   PCHANNEL_ACCESS_SETTING ChnlAccessSetting)
 {
-	struct r8180_priv *priv = ieee80211_priv(dev);
-	struct ieee80211_device *ieee = priv->ieee80211;
+	struct		r8180_priv *priv = ieee80211_priv(dev);
+	struct		ieee80211_device *ieee = priv->ieee80211;
 	AC_CODING	eACI;
 	AC_PARAM	AcParam;
-	u8	bFollowLegacySetting = 0;
-	u8   u1bAIFS;
+	u8		bFollowLegacySetting = 0;
+	u8		u1bAIFS;
 
 	/*
-		<RJ_TODO_8185B>
-		TODO: We still don't know how to set up these registers, just follow WMAC to
-		verify 8185B FPAG.
-
-		<RJ_TODO_8185B>
-		Jong said CWmin/CWmax register are not functional in 8185B,
-		so we shall fill channel access realted register into AC parameter registers,
-		even in nQBss.
-	*/
+	 *	<RJ_TODO_8185B>
+	 *	TODO: We still don't know how to set up these registers, just follow WMAC to
+	 *	verify 8185B FPAG.
+	 *
+	 *	<RJ_TODO_8185B>
+	 *	Jong said CWmin/CWmax register are not functional in 8185B,
+	 *	so we shall fill channel access realted register into AC parameter registers,
+	 *	even in nQBss.
+	 */
 	ChnlAccessSetting->SIFS_Timer = 0x22; /* Suggested by Jong, 2005.12.08. */
-	ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko.			*/
-	ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko.			*/
-	ChnlAccessSetting->EIFS_Timer = 0x5B; /* Suggested by wcchu, it is the default value of EIFS register, 2005.12.08.	*/
-	ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko.			*/
-	ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko.			*/
+	ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko. */
+	ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko. */
+	ChnlAccessSetting->EIFS_Timer = 0x5B; /* Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. */
+	ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko. */
+	ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko. */
 
 	write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer);
-	write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer);	/* Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. */
+	write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); /* Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. */
 
 	u1bAIFS = aSifsTime + (2 * ChnlAccessSetting->SlotTimeTimer);
 
@@ -1074,17 +979,17 @@
 	}
 
 	/* this setting is copied from rtl8187B.  xiong-2006-11-13 */
-	if (bFollowLegacySetting)	{
+	if (bFollowLegacySetting) {
 
 		/*
-			Follow 802.11 seeting to AC parameter, all AC shall use the same parameter.
-			2005.12.01, by rcnjko.
-		*/
+		 *	Follow 802.11 seeting to AC parameter, all AC shall use the same parameter.
+		 *	2005.12.01, by rcnjko.
+		 */
 		AcParam.longData = 0;
 		AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS.	*/
 		AcParam.f.AciAifsn.f.ACM = 0;
-		AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; /*	Follow 802.11 CWmin.	*/
-		AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; /*	Follow 802.11 CWmax.	*/
+		AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; /* Follow 802.11 CWmin. */
+		AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; /* Follow 802.11 CWmax. */
 		AcParam.f.TXOPLimit = 0;
 
 		/* lzm reserved 080826 */
@@ -1095,7 +1000,7 @@
 		if (ieee->iw_mode == IW_MODE_ADHOC)
 			AcParam.f.TXOPLimit = 0x0020;
 
-		for (eACI = 0; eACI < AC_MAX; eACI++)	{
+		for (eACI = 0; eACI < AC_MAX; eACI++) {
 			AcParam.f.AciAifsn.f.ACI = (u8)eACI;
 			{
 				PAC_PARAM	pAcParam = (PAC_PARAM)(&AcParam);
@@ -1103,7 +1008,7 @@
 				u8		u1bAIFS;
 				u32		u4bAcParam;
 
-				/*  Retrive paramters to udpate. */
+				/*  Retrieve paramters to update. */
 				eACI = pAcParam->f.AciAifsn.f.ACI;
 				u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime;
 				u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET)	|
@@ -1111,7 +1016,7 @@
 						(((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET)	|
 						(((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
 
-				switch (eACI)	{
+				switch (eACI) {
 				case AC1_BK:
 					/* write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); */
 					break;
@@ -1133,47 +1038,46 @@
 					break;
 				}
 
-				/* Cehck ACM bit.	*/
+				/* Cehck ACM bit. */
 				/* If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13.	*/
 				{
 					PACI_AIFSN	pAciAifsn = (PACI_AIFSN)(&pAcParam->f.AciAifsn);
 					AC_CODING	eACI = pAciAifsn->f.ACI;
 
-					/*modified Joseph				*/
-					/*for 8187B AsynIORead issue	*/
+					/*for 8187B AsynIORead issue */
 					u8	AcmCtrl = 0;
-					if (pAciAifsn->f.ACM)	{
+					if (pAciAifsn->f.ACM) {
 						/* ACM bit is 1. */
-						switch (eACI)	{
+						switch (eACI) {
 						case AC0_BE:
-							AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN);	/* or 0x21 */
+							AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); /* or 0x21 */
 							break;
 
 						case AC2_VI:
-							AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN);	/* or 0x42	*/
+							AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); /* or 0x42 */
 							break;
 
 						case AC3_VO:
-							AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN);	/* or 0x84 */
+							AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); /* or 0x84 */
 							break;
 
 						default:
 							DMESGW("SetHwReg8185(): [HW_VAR_ACM_CTRL] ACM set failed: eACI is %d\n", eACI);
 							break;
 						}
-					}	else	{
+					} else {
 						/* ACM bit is 0. */
-						switch (eACI)	{
+						switch (eACI) {
 						case AC0_BE:
-							AcmCtrl &= ((~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN));	/* and 0xDE */
+							AcmCtrl &= ((~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xDE */
 							break;
 
 						case AC2_VI:
-							AcmCtrl &= ((~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN));	/* and 0xBD */
+							AcmCtrl &= ((~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xBD */
 							break;
 
 						case AC3_VO:
-							AcmCtrl &= ((~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN));	/* and 0x7B */
+							AcmCtrl &= ((~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0x7B */
 							break;
 
 						default:
@@ -1187,53 +1091,51 @@
 	}
 }
 
-void
-ActSetWirelessMode8185(
-	struct net_device *dev,
-	u8				btWirelessMode
-	)
+void ActSetWirelessMode8185(struct net_device *dev, u8 btWirelessMode)
 {
-	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
-	struct ieee80211_device *ieee = priv->ieee80211;
+	struct  r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+	struct  ieee80211_device *ieee = priv->ieee80211;
 	u8	btSupportedWirelessMode = GetSupportedWirelessMode8185(dev);
 
 	if ((btWirelessMode & btSupportedWirelessMode) == 0)	{
-		/* Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko.	*/
+		/* Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. */
 		DMESGW("ActSetWirelessMode8185(): WirelessMode(%d) is not supported (%d)!\n",
 			btWirelessMode, btSupportedWirelessMode);
 		return;
 	}
 
-	/* 1. Assign wireless mode to swtich if necessary.	*/
-	if (btWirelessMode == WIRELESS_MODE_AUTO)	{
-		if ((btSupportedWirelessMode & WIRELESS_MODE_A))	{
+	/* 1. Assign wireless mode to switch if necessary. */
+	if (btWirelessMode == WIRELESS_MODE_AUTO) {
+		if ((btSupportedWirelessMode & WIRELESS_MODE_A)) {
 			btWirelessMode = WIRELESS_MODE_A;
-		}	else if (btSupportedWirelessMode & WIRELESS_MODE_G)	{
+		} else if (btSupportedWirelessMode & WIRELESS_MODE_G) {
 				btWirelessMode = WIRELESS_MODE_G;
 
-		}	else if ((btSupportedWirelessMode & WIRELESS_MODE_B))	{
+		} else if ((btSupportedWirelessMode & WIRELESS_MODE_B))	{
 				btWirelessMode = WIRELESS_MODE_B;
-		}	else	{
-				DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n",
-						btSupportedWirelessMode);
-				btWirelessMode = WIRELESS_MODE_B;
+		} else {
+			DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n",
+			       btSupportedWirelessMode);
+			btWirelessMode = WIRELESS_MODE_B;
 		}
 	}
 
-	/* 2. Swtich band: RF or BB specific actions,
+	/* 
+ 	 * 2. Swtich band: RF or BB specific actions,
 	 * for example, refresh tables in omc8255, or change initial gain if necessary.
 	 * Nothing to do for Zebra to switch band.
-	 * Update current wireless mode if we swtich to specified band successfully. */
+	 * Update current wireless mode if we switch to specified band successfully. 
+	 */
 
 	ieee->mode = (WIRELESS_MODE)btWirelessMode;
 
-	/* 3. Change related setting.	*/
-	if( ieee->mode == WIRELESS_MODE_A )	{
+	/* 3. Change related setting. */
+	if( ieee->mode == WIRELESS_MODE_A ) {
 		DMESG("WIRELESS_MODE_A\n");
-	}	else if( ieee->mode == WIRELESS_MODE_B )	{
-			DMESG("WIRELESS_MODE_B\n");
-	}	else if( ieee->mode == WIRELESS_MODE_G )	{
-			DMESG("WIRELESS_MODE_G\n");
+	} else if( ieee->mode == WIRELESS_MODE_B ) {
+		DMESG("WIRELESS_MODE_B\n");
+	} else if( ieee->mode == WIRELESS_MODE_G ) {
+		DMESG("WIRELESS_MODE_G\n");
 	}
 	ActUpdateChannelAccessSetting( dev, ieee->mode, &priv->ChannelAccessSetting);
 }
@@ -1245,22 +1147,16 @@
 	priv->irq_enabled = 1;
 	write_nic_dword(dev, IMR, priv->IntrMask);
 }
-/* by amy for power save */
-void
-DrvIFIndicateDisassociation(
-	struct net_device *dev,
-	u16			reason
-	)
+
+void DrvIFIndicateDisassociation(struct net_device *dev, u16 reason)
 {
 		/* nothing is needed after disassociation request. */
-	}
-void
-MgntDisconnectIBSS(
-	struct net_device *dev
-)
+}
+
+void MgntDisconnectIBSS(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
-	u8			i;
+	u8 i;
 
 	DrvIFIndicateDisassociation(dev, unspec_reason);
 
@@ -1271,166 +1167,143 @@
 
 	priv->ieee80211->state = IEEE80211_NOLINK;
 	/*
-		Stop Beacon.
-
-		Vista add a Adhoc profile, HW radio off until OID_DOT11_RESET_REQUEST
-		Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck.
-		Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send.
-
-		Disable Beacon Queue Own bit, suggested by jong	*/
+	 *	Stop Beacon.
+	 *
+	 *	Vista add a Adhoc profile, HW radio off until OID_DOT11_RESET_REQUEST
+	 *	Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck.
+	 *	Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send.
+	 *
+	 *	Disable Beacon Queue Own bit, suggested by jong	
+	 */
 	ieee80211_stop_send_beacons(priv->ieee80211);
 
 	priv->ieee80211->link_change(dev);
 	notify_wx_assoc_event(priv->ieee80211);
 }
-void
-MlmeDisassociateRequest(
-	struct net_device *dev,
-	u8 *asSta,
-	u8	asRsn
-	)
+
+void MlmeDisassociateRequest(struct net_device *dev, u8 *asSta, u8 asRsn)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 	u8 i;
 
 	SendDisassociation(priv->ieee80211, asSta, asRsn);
 
-	if (memcmp(priv->ieee80211->current_network.bssid, asSta, 6) == 0)	{
-		/*ShuChen TODO: change media status.			*/
-		/*ShuChen TODO: What to do when disassociate.	*/
+	if (memcmp(priv->ieee80211->current_network.bssid, asSta, 6) == 0) {
+		/* ShuChen TODO: change media status. */
+		/* ShuChen TODO: What to do when disassociate. */
 		DrvIFIndicateDisassociation(dev, unspec_reason);
 
-
-
 		for (i = 0; i < 6; i++)
 			priv->ieee80211->current_network.bssid[i] = 0x22;
 
 		ieee80211_disassociate(priv->ieee80211);
 	}
-
 }
 
-void
-MgntDisconnectAP(
-	struct net_device *dev,
-	u8			asRsn
-)
+void MgntDisconnectAP(struct net_device *dev, u8 asRsn)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 
 	/*
-	Commented out by rcnjko, 2005.01.27:
-	I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE().
-
-		2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success
-
-		In WPA WPA2 need to Clear all key ... because new key will set after new handshaking.
-		2004.10.11, by rcnjko. */
+	 * Commented out by rcnjko, 2005.01.27:
+	 * I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE().
+	 *
+	 *	2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success
+	 *
+	 *	In WPA WPA2 need to Clear all key ... because new key will set after new handshaking.
+	 *	2004.10.11, by rcnjko. 
+	 */
 	MlmeDisassociateRequest(dev, priv->ieee80211->current_network.bssid, asRsn);
 
 	priv->ieee80211->state = IEEE80211_NOLINK;
 }
-bool
-MgntDisconnect(
-	struct net_device *dev,
-	u8			asRsn
-)
+
+bool MgntDisconnect(struct net_device *dev, u8 asRsn)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 	/*
-		Schedule an workitem to wake up for ps mode, 070109, by rcnjko.
-	*/
+	 *	Schedule an workitem to wake up for ps mode, 070109, by rcnjko.
+	 */
 
 	if (IS_DOT11D_ENABLE(priv->ieee80211))
 		Dot11d_Reset(priv->ieee80211);
-	/* In adhoc mode, update beacon frame.	*/
+	/* In adhoc mode, update beacon frame. */
 	if (priv->ieee80211->state == IEEE80211_LINKED)	{
 		if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
 			MgntDisconnectIBSS(dev);
 
-		if (priv->ieee80211->iw_mode == IW_MODE_INFRA)	{
-			/*	We clear key here instead of MgntDisconnectAP() because that
-				MgntActSet_802_11_DISASSOCIATE() is an interface called by OS,
-				e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is
-				used to handle disassociation related things to AP, e.g. send Disassoc
-				frame to AP.  2005.01.27, by rcnjko.	*/
+		if (priv->ieee80211->iw_mode == IW_MODE_INFRA) {
+			/*
+ 			 * 	We clear key here instead of MgntDisconnectAP() because that
+			 *	MgntActSet_802_11_DISASSOCIATE() is an interface called by OS,
+			 *	e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is
+			 *	used to handle disassociation related things to AP, e.g. send Disassoc
+			 *	frame to AP.  2005.01.27, by rcnjko. 
+			 */
 			MgntDisconnectAP(dev, asRsn);
 		}
-		/* Inidicate Disconnect, 2005.02.23, by rcnjko.	*/
+		/* Indicate Disconnect, 2005.02.23, by rcnjko.	*/
 	}
 	return true;
 }
 /*
-	Description:
-		Chang RF Power State.
-		Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE.
-
-	Assumption:
-		PASSIVE LEVEL.
-*/
-bool
-SetRFPowerState(
-	struct net_device *dev,
-	RT_RF_POWER_STATE	eRFPowerState
-	)
+ *	Description:
+ *		Chang RF Power State.
+ *		Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE.
+ *
+ *	Assumption:
+ *		PASSIVE LEVEL.
+ */
+bool SetRFPowerState(struct net_device *dev, RT_RF_POWER_STATE eRFPowerState)
 {
-	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
-	bool			bResult = false;
+	struct	r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+	bool	bResult = false;
 
 	if (eRFPowerState == priv->eRFPowerState)
 		return bResult;
 
-	 bResult = SetZebraRFPowerState8185(dev, eRFPowerState);
+	bResult = SetZebraRFPowerState8185(dev, eRFPowerState);
 
 	return bResult;
 }
-void
-HalEnableRx8185Dummy(
-	struct net_device *dev
-	)
-{
-}
-void
-HalDisableRx8185Dummy(
-	struct net_device *dev
-	)
+
+void HalEnableRx8185Dummy(struct net_device *dev)
 {
 }
 
-bool
-MgntActSet_RF_State(
-	struct net_device *dev,
-	RT_RF_POWER_STATE	StateToSet,
-	u32	ChangeSource
-	)
+void HalDisableRx8185Dummy(struct net_device *dev)
 {
-	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
-	bool				bActionAllowed = false;
-	bool				bConnectBySSID = false;
-	RT_RF_POWER_STATE	rtState;
-	u16				RFWaitCounter = 0;
+}
+
+bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet, u32 ChangeSource)
+{
+	struct	r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+	bool	bActionAllowed = false;
+	bool	bConnectBySSID = false;
+	RT_RF_POWER_STATE rtState;
+	u16	RFWaitCounter = 0;
 	unsigned long flag;
 	/*
-		Prevent the race condition of RF state change. By Bruce, 2007-11-28.
-		Only one thread can change the RF state at one time, and others should wait to be executed.
-	*/
-	while (true)	{
+	 *	Prevent the race condition of RF state change. By Bruce, 2007-11-28.
+	 *	Only one thread can change the RF state at one time, and others should wait to be executed.
+	 */
+	while (true) {
 		spin_lock_irqsave(&priv->rf_ps_lock, flag);
-		if (priv->RFChangeInProgress)	{
+		if (priv->RFChangeInProgress) {
 			spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
 			/*  Set RF after the previous action is done.	*/
-			while (priv->RFChangeInProgress)	{
+			while (priv->RFChangeInProgress) {
 				RFWaitCounter++;
 				udelay(1000); /* 1 ms	*/
 
-				/* Wait too long, return FALSE to avoid to be stuck here.	*/
-				if (RFWaitCounter > 1000)	{	/* 1sec	*/
+				/* Wait too long, return FALSE to avoid to be stuck here. */
+				if (RFWaitCounter > 1000) { /* 1sec */
 					printk("MgntActSet_RF_State(): Wait too long to set RF\n");
-					/* TODO: Reset RF state?	*/
+					/* TODO: Reset RF state? */
 					return false;
 				}
 			}
-		}	else	{
+		} else {
 			priv->RFChangeInProgress = true;
 			spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
 			break;
@@ -1438,12 +1311,12 @@
 	}
 	rtState = priv->eRFPowerState;
 
-	switch (StateToSet)	{
+	switch (StateToSet) {
 	case eRfOn:
 		/*
-			Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or
-			the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02.
-		*/
+		 *	Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or
+		 *	the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02.
+		 */
 		priv->RfOffReason &= (~ChangeSource);
 
 		if (!priv->RfOffReason)	{
@@ -1453,25 +1326,24 @@
 			if (rtState == eRfOff && ChangeSource >= RF_CHANGE_BY_HW && !priv->bInHctTest)
 				bConnectBySSID = true;
 
-		}	else
-				;
+		} else
+			;
 		break;
 
 	case eRfOff:
-		 /* 070125, rcnjko: we always keep connected in AP mode.	*/
+		 /* 070125, rcnjko: we always keep connected in AP mode. */
 
-			if (priv->RfOffReason > RF_CHANGE_BY_IPS)	{
-				/*
-					060808, Annie:
-					Disconnect to current BSS when radio off. Asked by QuanTa.
-
-					Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(),
-					because we do NOT need to set ssid to dummy ones.
-				*/
-				MgntDisconnect(dev, disas_lv_ss);
-
-				/* Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI.	*/
-			}
+		if (priv->RfOffReason > RF_CHANGE_BY_IPS) {
+			/*
+			 *	060808, Annie:
+			 *	Disconnect to current BSS when radio off. Asked by QuanTa.
+			 *
+			 *	Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(),
+			 *	because we do NOT need to set ssid to dummy ones.
+			 */
+			MgntDisconnect(dev, disas_lv_ss);
+			/* Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. */
+		}
 
 		priv->RfOffReason |= ChangeSource;
 		bActionAllowed = true;
@@ -1484,14 +1356,14 @@
 		break;
 	}
 
-	if (bActionAllowed)	{
-				/* Config HW to the specified mode.	*/
+	if (bActionAllowed) {
+		/* Config HW to the specified mode. */
 		SetRFPowerState(dev, StateToSet);
 
 		/* Turn on RF.	*/
-		if (StateToSet == eRfOn)		{
+		if (StateToSet == eRfOn) {
 			HalEnableRx8185Dummy(dev);
-			if (bConnectBySSID)	{
+			if (bConnectBySSID) {
 				/* by amy not supported	*/
 			}
 		}
@@ -1507,69 +1379,61 @@
 	spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
 	return bActionAllowed;
 }
-void
-InactivePowerSave(
-	struct net_device *dev
-	)
+
+void InactivePowerSave(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 	/*
-		This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem
-		is really scheduled.
-		The old code, sets this flag before scheduling the IPS workitem and however, at the same time the
-		previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing
-		blocks the IPS procedure of switching RF.
-	*/
+	 *	This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem
+	 *	is really scheduled.
+	 *	The old code, sets this flag before scheduling the IPS workitem and however, at the same time the
+	 *	previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing
+	 *	blocks the IPS procedure of switching RF.
+	 */
 	priv->bSwRfProcessing = true;
 
 	MgntActSet_RF_State(dev, priv->eInactivePowerState, RF_CHANGE_BY_IPS);
 
 	/*
-		To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20.
-	*/
+	 *	To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20.
+	 */
 
 	priv->bSwRfProcessing = false;
 }
 
 /*
-	Description:
-		Enter the inactive power save mode. RF will be off
-*/
-void
-IPSEnter(
-	struct net_device *dev
-	)
+ *	Description:
+ *		Enter the inactive power save mode. RF will be off
+ */
+void IPSEnter(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 	RT_RF_POWER_STATE rtState;
-	if (priv->bInactivePs)	{
+	if (priv->bInactivePs) {
 		rtState = priv->eRFPowerState;
 
 		/*
-			Do not enter IPS in the following conditions:
-			(1) RF is already OFF or Sleep
-			(2) bSwRfProcessing (indicates the IPS is still under going)
-			(3) Connectted (only disconnected can trigger IPS)
-			(4) IBSS (send Beacon)
-			(5) AP mode (send Beacon)
-		*/
+		 *	Do not enter IPS in the following conditions:
+		 *	(1) RF is already OFF or Sleep
+		 *	(2) bSwRfProcessing (indicates the IPS is still under going)
+		 *	(3) Connected (only disconnected can trigger IPS)
+		 *	(4) IBSS (send Beacon)
+		 *	(5) AP mode (send Beacon)
+		 */
 		if (rtState == eRfOn && !priv->bSwRfProcessing
-			&& (priv->ieee80211->state != IEEE80211_LINKED))	{
+			&& (priv->ieee80211->state != IEEE80211_LINKED)) {
 			priv->eInactivePowerState = eRfOff;
 			InactivePowerSave(dev);
 		}
 	}
 }
-void
-IPSLeave(
-	struct net_device *dev
-	)
+void IPSLeave(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 	RT_RF_POWER_STATE rtState;
-	if (priv->bInactivePs)	{
+	if (priv->bInactivePs) {
 		rtState = priv->eRFPowerState;
-		if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS)	{
+		if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) {
 			priv->eInactivePowerState = eRfOn;
 			InactivePowerSave(dev);
 		}
@@ -1582,8 +1446,8 @@
 	struct ieee80211_device *ieee = priv->ieee80211;
 
 	u8 SupportedWirelessMode;
-	u8			InitWirelessMode;
-	u8			bInvalidWirelessMode = 0;
+	u8 InitWirelessMode;
+	u8 bInvalidWirelessMode = 0;
 	u8 tmpu8;
 	u8 btCR9346;
 	u8 TmpU1b;
@@ -1598,89 +1462,89 @@
 	HwConfigureRTL8185(dev);
 	write_nic_dword(dev, MAC0, ((u32 *)dev->dev_addr)[0]);
 	write_nic_word(dev, MAC4, ((u32 *)dev->dev_addr)[1] & 0xffff);
-	write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3);	/* default network type to 'No	Link'	*/
+	write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); /* default network type to 'No Link' */
 	write_nic_word(dev, BcnItv, 100);
 	write_nic_word(dev, AtimWnd, 2);
 	PlatformIOWrite2Byte(dev, FEMR, 0xFFFF);
 	write_nic_byte(dev, WPA_CONFIG, 0);
 	MacConfig_85BASIC(dev);
-	/*	Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko.	*/
-	/*	BT_DEMO_BOARD type	*/
+	/* Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. */
+	/* BT_DEMO_BOARD type */
 	PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x569a);
 
 	/*
-	-----------------------------------------------------------------------------
-		Set up PHY related.
-	-----------------------------------------------------------------------------
-	*/
-	/* Enable Config3.PARAM_En to revise AnaaParm.	*/
-	write_nic_byte(dev, CR9346, 0xc0);	/* enable config register write */
+	 *---------------------------------------------------------------------------
+	 *	Set up PHY related.
+	 *---------------------------------------------------------------------------
+	 */
+	/* Enable Config3.PARAM_En to revise AnaaParm. */
+	write_nic_byte(dev, CR9346, 0xc0); /* enable config register write */
 	tmpu8 = read_nic_byte(dev, CONFIG3);
 	write_nic_byte(dev, CONFIG3, (tmpu8 | CONFIG3_PARM_En));
-	/* Turn on Analog power.	*/
-	/* Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko.	*/
+	/* Turn on Analog power. */
+	/* Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. */
 	write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON);
 	write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON);
 	write_nic_word(dev, ANAPARAM3, 0x0010);
 
 	write_nic_byte(dev, CONFIG3, tmpu8);
 	write_nic_byte(dev, CR9346, 0x00);
-	/* enable EEM0 and EEM1 in 9346CR			*/
+	/* enable EEM0 and EEM1 in 9346CR */
 	btCR9346 = read_nic_byte(dev, CR9346);
 	write_nic_byte(dev, CR9346, (btCR9346 | 0xC0));
 
-	/* B cut use LED1 to control HW RF on/off	*/
+	/* B cut use LED1 to control HW RF on/off */
 	TmpU1b = read_nic_byte(dev, CONFIG5);
 	TmpU1b = TmpU1b & ~BIT3;
 	write_nic_byte(dev, CONFIG5, TmpU1b);
 
-	/* disable EEM0 and EEM1 in 9346CR	*/
+	/* disable EEM0 and EEM1 in 9346CR */
 	btCR9346 &= ~(0xC0);
 	write_nic_byte(dev, CR9346, btCR9346);
 
-	/* Enable Led (suggested by Jong)	*/
-	/* B-cut RF Radio on/off  5e[3]=0	*/
+	/* Enable Led (suggested by Jong) */
+	/* B-cut RF Radio on/off  5e[3]=0 */
 	btPSR = read_nic_byte(dev, PSR);
 	write_nic_byte(dev, PSR, (btPSR | BIT3));
-	/* setup initial timing for RFE.	*/
+	/* setup initial timing for RFE. */
 	write_nic_word(dev, RFPinsOutput, 0x0480);
 	SetOutputEnableOfRfPins(dev);
 	write_nic_word(dev, RFPinsSelect, 0x2488);
 
-	/* PHY config.	*/
+	/* PHY config. */
 	PhyConfig8185(dev);
 
 	/*
-		We assume RegWirelessMode has already been initialized before,
-		however, we has to validate the wireless mode here and provide a
-		reasonable initialized value if necessary. 2005.01.13, by rcnjko.
-	*/
+	 *	We assume RegWirelessMode has already been initialized before,
+	 *	however, we has to validate the wireless mode here and provide a
+	 *	reasonable initialized value if necessary. 2005.01.13, by rcnjko.
+	 */
 	SupportedWirelessMode = GetSupportedWirelessMode8185(dev);
 	if ((ieee->mode != WIRELESS_MODE_B) &&
 		(ieee->mode != WIRELESS_MODE_G) &&
 		(ieee->mode != WIRELESS_MODE_A) &&
-		(ieee->mode != WIRELESS_MODE_AUTO))	{
-		/* It should be one of B, G, A, or AUTO.	*/
+		(ieee->mode != WIRELESS_MODE_AUTO)) {
+		/* It should be one of B, G, A, or AUTO. */
 		bInvalidWirelessMode = 1;
-	}	else	{
-	/* One of B, G, A, or AUTO.	*/
-		/* Check if the wireless mode is supported by RF.	*/
+	} else {
+	/* One of B, G, A, or AUTO. */
+		/* Check if the wireless mode is supported by RF. */
 		if	((ieee->mode != WIRELESS_MODE_AUTO) &&
-			(ieee->mode & SupportedWirelessMode) == 0)	{
+			(ieee->mode & SupportedWirelessMode) == 0) {
 			bInvalidWirelessMode = 1;
 		}
 	}
 
-	if (bInvalidWirelessMode || ieee->mode == WIRELESS_MODE_AUTO)	{
-		/* Auto or other invalid value.				*/
-		/* Assigne a wireless mode to initialize.	*/
-		if ((SupportedWirelessMode & WIRELESS_MODE_A))	{
+	if (bInvalidWirelessMode || ieee->mode == WIRELESS_MODE_AUTO) {
+		/* Auto or other invalid value. */
+		/* Assigne a wireless mode to initialize. */
+		if ((SupportedWirelessMode & WIRELESS_MODE_A)) {
 			InitWirelessMode = WIRELESS_MODE_A;
-		}	else if ((SupportedWirelessMode & WIRELESS_MODE_G))	{
+		} else if ((SupportedWirelessMode & WIRELESS_MODE_G)) {
 			InitWirelessMode = WIRELESS_MODE_G;
-		}	else if ((SupportedWirelessMode & WIRELESS_MODE_B))	{
+		} else if ((SupportedWirelessMode & WIRELESS_MODE_B)) {
 			InitWirelessMode = WIRELESS_MODE_B;
-		}	else	{
+		} else {
 			DMESGW("InitializeAdapter8185(): No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n",
 				 SupportedWirelessMode);
 			InitWirelessMode = WIRELESS_MODE_B;
@@ -1690,24 +1554,21 @@
 		if (bInvalidWirelessMode)
 			ieee->mode = (WIRELESS_MODE)InitWirelessMode;
 
-	}	else	{
-	/* One of B, G, A.	*/
+	} else {
+	/* One of B, G, A. */
 		InitWirelessMode = ieee->mode;
 	}
-/* by amy for power save	*/
 	priv->eRFPowerState = eRfOff;
 	priv->RfOffReason = 0;
 	{
 		MgntActSet_RF_State(dev, eRfOn, 0);
 	}
 		/*
-			If inactive power mode is enabled, disable rf while in disconnected state.
-		*/
+		 *	If inactive power mode is enabled, disable rf while in disconnected state.
+		 */
 	if (priv->bInactivePs)
 		MgntActSet_RF_State(dev , eRfOff, RF_CHANGE_BY_IPS);
 
-/* by amy for power save	*/
-
 	ActSetWirelessMode8185(dev, (u8)(InitWirelessMode));
 
 	/* ----------------------------------------------------------------------------- */
@@ -1715,7 +1576,7 @@
 	rtl8185b_irq_enable(dev);
 
 	netif_start_queue(dev);
-	}
+}
 
 void rtl8185b_rx_enable(struct net_device *dev)
 {
@@ -1728,7 +1589,7 @@
 		DMESG("NIC in promisc mode");
 
 	if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || \
-	   dev->flags & IFF_PROMISC)	{
+	   dev->flags & IFF_PROMISC) {
 		priv->ReceiveConfig = priv->ReceiveConfig & (~RCR_APM);
 		priv->ReceiveConfig = priv->ReceiveConfig | RCR_AAP;
 	}
diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig
index f87e211..4602a47 100644
--- a/drivers/staging/rtl8192e/Kconfig
+++ b/drivers/staging/rtl8192e/Kconfig
@@ -14,6 +14,7 @@
 config RTLLIB_CRYPTO_CCMP
 	tristate "Support for rtllib CCMP crypto"
 	depends on RTLLIB
+	select CRYPTO_AES
 	default y
 	---help---
 	  CCMP crypto driver for rtllib.
@@ -23,6 +24,8 @@
 config RTLLIB_CRYPTO_TKIP
 	tristate "Support for rtllib TKIP crypto"
 	depends on RTLLIB
+	select CRYPTO_ARC4
+	select CRYPTO_MICHAEL_MIC
 	default y
 	---help---
 	  TKIP crypto driver for rtllib.
@@ -31,6 +34,7 @@
 
 config RTLLIB_CRYPTO_WEP
 	tristate "Support for rtllib WEP crypto"
+	select CRYPTO_ARC4
 	depends on RTLLIB
 	default y
 	---help---
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
index 58d044e..ea91744 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
@@ -342,7 +342,6 @@
 u32 cmpk_message_handle_rx(struct net_device *dev,
 			   struct rtllib_rx_stats *pstats)
 {
-	struct r8192_priv *priv = rtllib_priv(dev);
 	int			total_length;
 	u8			cmd_length, exe_cnt = 0;
 	u8			element_id;
@@ -409,8 +408,6 @@
 			return 1;
 		}
 
-		priv->stats.rxcmdpkt[element_id]++;
-
 		total_length -= cmd_length;
 		pcmd_buff    += cmd_length;
 	}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
index 3771985..b526fa4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
@@ -216,7 +216,7 @@
 		break;
 	default:
 		rt_status = false;
-		RT_TRACE(COMP_FIRMWARE, "Unknown firware status");
+		RT_TRACE(COMP_FIRMWARE, "Unknown firmware status");
 		break;
 	}
 
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
index 3e705ef..9676c59 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
@@ -689,7 +689,7 @@
 	case RF_8258:
 		break;
 	default:
-		RT_TRACE(COMP_ERR, "unknown rf chip in funtion %s()\n",
+		RT_TRACE(COMP_ERR, "unknown rf chip in function %s()\n",
 			 __func__);
 		break;
 	}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h b/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h
index d5de279..970298b 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h
+++ b/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h
@@ -306,7 +306,7 @@
 #define bRFStart                  	0x0000f000
 #define bBBStart                  	0x000000f0
 #define bBBCCKStart               	0x0000000f
-/* Reg)x814 */
+/* Reg x814 */
 #define bPAEnd                    	0xf
 #define bTREnd                    	0x0f000000
 #define bRFEnd                    	0x000f0000
@@ -844,7 +844,7 @@
 #define bRTL8258_RxLPFBW          0xc00
 #define bRTL8258_RSSILPFBW        0xc0
 
-/* byte endable for sb_write */
+/* byte enable for sb_write */
 #define bByte0                    0x1
 #define bByte1                    0x2
 #define bByte2                    0x4
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
index 71adb6b..4f602b2 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -1025,7 +1025,7 @@
 			break;
 		}
 		RT_TRACE(COMP_DBG, "===>%s():RF is in progress, need to wait "
-			 "until rf chang is done.\n", __func__);
+			 "until rf change is done.\n", __func__);
 		mdelay(1);
 		RFInProgressTimeOut++;
 		spin_lock_irqsave(&priv->rf_ps_lock, flags);
@@ -1211,7 +1211,7 @@
 	priv->AcmControl = 0;
 	priv->pFirmware = vzalloc(sizeof(struct rt_firmware));
 	if (!priv->pFirmware)
-		printk(KERN_ERR "rtl8193e: Unable to allocate space "
+		printk(KERN_ERR "rtl8192e: Unable to allocate space "
 		       "for firmware\n");
 
 	skb_queue_head_init(&priv->rx_queue);
@@ -2024,10 +2024,10 @@
 	stype = WLAN_FC_GET_STYPE(fc);
 	pda_addr = header->addr1;
 
-	if (is_multicast_ether_addr(pda_addr))
-		multi_addr = true;
-	else if (is_broadcast_ether_addr(pda_addr))
+	if (is_broadcast_ether_addr(pda_addr))
 		broad_addr = true;
+	else if (is_multicast_ether_addr(pda_addr))
+		multi_addr = true;
 	else
 		uni_addr = true;
 
@@ -2358,8 +2358,7 @@
 				stats.RxBufShift);
 			skb_trim(skb, skb->len - 4/*sCrcLng*/);
 			rtllib_hdr = (struct rtllib_hdr_1addr *)skb->data;
-			if (!is_broadcast_ether_addr(rtllib_hdr->addr1) &&
-			!is_multicast_ether_addr(rtllib_hdr->addr1)) {
+			if (!is_multicast_ether_addr(rtllib_hdr->addr1)) {
 				/* unicast packet */
 				unicast_packet = true;
 			}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
index 2a2519c..320d5fc 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
@@ -353,7 +353,6 @@
 	unsigned long rxrdu;
 	unsigned long rxok;
 	unsigned long rxframgment;
-	unsigned long rxcmdpkt[8];
 	unsigned long rxurberr;
 	unsigned long rxstaterr;
 	unsigned long rxdatacrcerr;
@@ -944,7 +943,7 @@
 	bool		bfsync_processing;
 	u32		rate_record;
 	u32		rateCountDiffRecord;
-	u32		ContiuneDiffCount;
+	u32		ContinueDiffCount;
 	bool		bswitch_fsync;
 	u8		framesync;
 	u32		framesyncC34;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index f026b71..481b1e4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -493,7 +493,7 @@
 
 				if (priv->bResetInProgress) {
 					RT_TRACE(COMP_POWER_TRACKING,
-						 "we are in slient reset progress, so return\n");
+						 "we are in silent reset progress, so return\n");
 					write_nic_byte(dev, Pw_Track_Flag, 0);
 					write_nic_byte(dev, FW_Busy_Flag, 0);
 					return;
@@ -2615,22 +2615,22 @@
 				      rate_count_diff;
 			if (DiffNum >=
 			    priv->rtllib->fsync_seconddiff_ratethreshold)
-				priv->ContiuneDiffCount++;
+				priv->ContinueDiffCount++;
 			else
-				priv->ContiuneDiffCount = 0;
+				priv->ContinueDiffCount = 0;
 
-			if (priv->ContiuneDiffCount >= 2) {
+			if (priv->ContinueDiffCount >= 2) {
 				bSwitchFromCountDiff = true;
-				priv->ContiuneDiffCount = 0;
+				priv->ContinueDiffCount = 0;
 			}
 		} else {
-			priv->ContiuneDiffCount = 0;
+			priv->ContinueDiffCount = 0;
 		}
 
 		if (rate_count_diff <=
 		    priv->rtllib->fsync_firstdiff_ratethreshold) {
 			bSwitchFromCountDiff = true;
-			priv->ContiuneDiffCount = 0;
+			priv->ContinueDiffCount = 0;
 		}
 		priv->rate_record = rate_count;
 		priv->rateCountDiffRecord = rate_count_diff;
@@ -2677,10 +2677,10 @@
 			write_nic_byte(dev, 0xC36, 0x5c);
 			write_nic_byte(dev, 0xC3e, 0x96);
 		}
-		priv->ContiuneDiffCount = 0;
+		priv->ContinueDiffCount = 0;
 		write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
 	}
-	RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount);
+	RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount);
 	RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d "
 		 "bSwitchFsync %d\n", priv->rate_record, rate_count,
 		 rate_count_diff, priv->bswitch_fsync);
@@ -2723,7 +2723,7 @@
 		write_nic_byte(dev, 0xC3e, 0x96);
 	}
 
-	priv->ContiuneDiffCount = 0;
+	priv->ContinueDiffCount = 0;
 	write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
 }
 
@@ -2735,7 +2735,7 @@
 
 	RT_TRACE(COMP_HALDM, "%s\n", __func__);
 	priv->rate_record = 0;
-	priv->ContiuneDiffCount = 0;
+	priv->ContinueDiffCount = 0;
 	priv->rateCountDiffRecord = 0;
 	priv->bswitch_fsync  = false;
 
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
index 4e93669..778d7ba 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
@@ -1322,9 +1322,9 @@
 
 struct iw_handler_def  r8192_wx_handlers_def = {
 	.standard = r8192_wx_handlers,
-	.num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler),
+	.num_standard = ARRAY_SIZE(r8192_wx_handlers),
 	.private = r8192_private_handler,
-	.num_private = sizeof(r8192_private_handler) / sizeof(iw_handler),
+	.num_private = ARRAY_SIZE(r8192_private_handler),
 	.num_private_args = sizeof(r8192_private_args) /
 			    sizeof(struct iw_priv_args),
 	.get_wireless_stats = r8192_get_wireless_stats,
diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c
index 711a096..658e875 100644
--- a/drivers/staging/rtl8192e/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_TSProc.c
@@ -310,7 +310,7 @@
 	   u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs)
 {
 	u8	UP = 0;
-	if (is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr)) {
+	if (is_multicast_ether_addr(Addr)) {
 		RTLLIB_DEBUG(RTLLIB_DL_ERR, "ERR! get TS for Broadcast or "
 			     "Multicast\n");
 		return false;
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
index e26aec8..d7460ae 100644
--- a/drivers/staging/rtl8192e/rtllib.h
+++ b/drivers/staging/rtl8192e/rtllib.h
@@ -169,7 +169,7 @@
 
 	u8 nStuckCount;
 
-	/* Tx Firmware Relaged flags (10-11)*/
+	/* Tx Firmware Related flags (10-11)*/
 	u8 bCTSEnable:1;
 	u8 bRTSEnable:1;
 	u8 bUseShortGI:1;
@@ -1690,7 +1690,7 @@
 	/* the association procedure is sending AUTH request*/
 	RTLLIB_ASSOCIATING_AUTHENTICATING,
 
-	/* the association procedure has successfully authentcated
+	/* the association procedure has successfully authenticated
 	 * and is sending association request
 	 */
 	RTLLIB_ASSOCIATING_AUTHENTICATED,
@@ -2409,7 +2409,7 @@
 
 	/* used instead of hard_start_xmit (not softmac_hard_start_xmit)
 	 * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
-	 * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
+	 * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
 	 * then also management frames are sent via this callback.
 	 * This function can't sleep.
 	 */
@@ -2422,12 +2422,12 @@
 	 */
 	void (*data_hard_stop)(struct net_device *dev);
 
-	/* OK this is complementar to data_poll_hard_stop */
+	/* OK this is complementing to data_poll_hard_stop */
 	void (*data_hard_resume)(struct net_device *dev);
 
 	/* ask to the driver to retune the radio .
 	 * This function can sleep. the driver should ensure
-	 * the radio has been swithced before return.
+	 * the radio has been switched before return.
 	 */
 	void (*set_chan)(struct net_device *dev, short ch);
 
@@ -2438,7 +2438,7 @@
 	 * The syncro version is similar to the start_scan but
 	 * does not return until all channels has been scanned.
 	 * this is called in user context and should sleep,
-	 * it is called in a work_queue when swithcing to ad-hoc mode
+	 * it is called in a work_queue when switching to ad-hoc mode
 	 * or in behalf of iwlist scan when the card is associated
 	 * and root user ask for a scan.
 	 * the fucntion stop_scan should stop both the syncro and
@@ -2481,7 +2481,7 @@
 				     struct rtllib_network *network);
 
 
-	/* check whether Tx hw resouce available */
+	/* check whether Tx hw resource available */
 	short (*check_nic_enough_desc)(struct net_device *dev, int queue_index);
 	short (*get_nic_desc_num)(struct net_device *dev, int queue_index);
 	void (*SetBWModeHandler)(struct net_device *dev,
@@ -2543,10 +2543,10 @@
 /* Generate probe requests */
 #define IEEE_SOFTMAC_PROBERQ (1<<4)
 
-/* Generate respones to probe requests */
+/* Generate response to probe requests */
 #define IEEE_SOFTMAC_PROBERS (1<<5)
 
-/* The ieee802.11 stack will manages the netif queue
+/* The ieee802.11 stack will manage the netif queue
  * wake/stop for the driver, taking care of 802.11
  * fragmentation. See softmac.c for details. */
 #define IEEE_SOFTMAC_TX_QUEUE (1<<7)
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index 13979b5..8b8a5c6 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -496,7 +496,7 @@
 				memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN);
 			}
 
-			/* Indicat the packets to upper layer */
+			/* Indicate the packets to upper layer */
 			if (sub_skb) {
 				stats->rx_packets++;
 				stats->rx_bytes += sub_skb->len;
@@ -1000,7 +1000,7 @@
 			return -1;
 
 		/* {broad,multi}cast packets to our BSS go through */
-		if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst)) {
+		if (is_multicast_ether_addr(dst)) {
 			if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN))
 				return -1;
 		}
@@ -1233,7 +1233,7 @@
 			if (is_multicast_ether_addr(dst))
 				ieee->stats.multicast++;
 
-			/* Indicat the packets to upper layer */
+			/* Indicate the packets to upper layer */
 			memset(sub_skb->cb, 0, sizeof(sub_skb->cb));
 			sub_skb->protocol = eth_type_trans(sub_skb, dev);
 			sub_skb->dev = dev;
@@ -1269,7 +1269,7 @@
 	sc = le16_to_cpu(hdr->seq_ctl);
 
 	/*Filter pkt not to me*/
-	multicast = is_multicast_ether_addr(hdr->addr1)|is_broadcast_ether_addr(hdr->addr1);
+	multicast = is_multicast_ether_addr(hdr->addr1);
 	unicast = !multicast;
 	if (unicast && (compare_ether_addr(dev->dev_addr, hdr->addr1) != 0)) {
 		if (ieee->bNetPromiscuousMode)
@@ -1350,7 +1350,7 @@
 	/* Get TS for Rx Reorder  */
 	hdr = (struct rtllib_hdr_4addr *) skb->data;
 	if (ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data)
-		&& !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1)
+		&& !is_multicast_ether_addr(hdr->addr1)
 		&& (!bToOtherSTA)) {
 		TID = Frame_QoSTID(skb->data);
 		SeqNum = WLAN_GET_SEQ_SEQ(sc);
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index c5a15db..a21b4d9 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -31,7 +31,7 @@
 	return net->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME;
 }
 
-/* returns the total length needed for pleacing the RATE MFIE
+/* returns the total length needed for placing the RATE MFIE
  * tag and the EXTENDED RATE MFIE tag if needed.
  * It encludes two bytes per tag for the tag itself and its len
  */
@@ -49,7 +49,7 @@
 	return rate_len;
 }
 
-/* pleace the MFIE rate, tag to the memory (double) poined.
+/* place the MFIE rate, tag to the memory (double) pointed.
  * Then it updates the pointer so that
  * it points after the new MFIE tag added.
  */
@@ -557,7 +557,7 @@
 		 *    new network events, despite for updating the net list,
 		 *    but we are temporarly 'unlinked' as the driver shall
 		 *    not filter RX frames and the channel is changing.
-		 * So the only situation in witch are interested is to check
+		 * So the only situation in which are interested is to check
 		 * if the state become LINKED because of the #1 situation
 		 */
 
@@ -1681,7 +1681,7 @@
 
 		/* if the user set the AP check if match.
 		 * if the network does not broadcast essid we check the
-		 *	 user supplyed ANY essid
+		 *	 user supplied ANY essid
 		 * if the network does broadcast and the user does not set
 		 *	 essid it is OK
 		 * if the network does broadcast and the user did set essid
@@ -2444,16 +2444,16 @@
 
 /* following are for a simplier TX queue management.
  * Instead of using netif_[stop/wake]_queue the driver
- * will uses these two function (plus a reset one), that
- * will internally uses the kernel netif_* and takes
+ * will use these two functions (plus a reset one), that
+ * will internally use the kernel netif_* and takes
  * care of the ieee802.11 fragmentation.
  * So the driver receives a fragment per time and might
- * call the stop function when it want without take care
- * to have enought room to TX an entire packet.
- * This might be useful if each fragment need it's own
+ * call the stop function when it wants to not
+ * have enough room to TX an entire packet.
+ * This might be useful if each fragment needs it's own
  * descriptor, thus just keep a total free memory > than
- * the max fragmentation treshold is not enought.. If the
- * ieee802.11 stack passed a TXB struct then you needed
+ * the max fragmentation threshold is not enough.. If the
+ * ieee802.11 stack passed a TXB struct then you need
  * to keep N free descriptors where
  * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD
  * In this way you need just one and the 802.11 stack
@@ -2696,15 +2696,15 @@
 	rtllib_softmac_check_all_nets(ieee);
 
 
-	/* if not then the state is not linked. Maybe the user swithced to
+	/* if not then the state is not linked. Maybe the user switched to
 	 * ad-hoc mode just after being in monitor mode, or just after
 	 * being very few time in managed mode (so the card have had no
 	 * time to scan all the chans..) or we have just run up the iface
 	 * after setting ad-hoc mode. So we have to give another try..
 	 * Here, in ibss mode, should be safe to do this without extra care
-	 * (in bss mode we had to make sure no-one tryed to associate when
+	 * (in bss mode we had to make sure no-one tried to associate when
 	 * we had just checked the ieee->state and we was going to start the
-	 * scan) beacause in ibss mode the rtllib_new_net function, when
+	 * scan) because in ibss mode the rtllib_new_net function, when
 	 * finds a good net, just set the ieee->state to RTLLIB_LINKED,
 	 * so, at worst, we waste a bit of time to initiate an unneeded syncro
 	 * scan, that will stop at the first round because it sees the state
@@ -2819,7 +2819,7 @@
 
 	/* ensure no-one start an associating process (thus setting
 	 * the ieee->state to rtllib_ASSOCIATING) while we
-	 * have just cheked it and we are going to enable scan.
+	 * have just checked it and we are going to enable scan.
 	 * The rtllib_new_net function is always called with
 	 * lock held (from both rtllib_softmac_check_all_nets and
 	 * the rx path), so we cannot be in the middle of such function
@@ -2872,7 +2872,7 @@
 
 	/* until we do not set the state to RTLLIB_NOLINK
 	* there are no possibility to have someone else trying
-	* to start an association procdure (we get here with
+	* to start an association procedure (we get here with
 	* ieee->state = RTLLIB_ASSOCIATING).
 	* When we set the state to RTLLIB_NOLINK it is possible
 	* that the RX path run an attempt to associate, but
@@ -3679,8 +3679,7 @@
 
 	RemovePeerTS(rtllib, asSta);
 
-
-	if (memcpy(rtllib->current_network.bssid, asSta, 6) == NULL) {
+	if (memcmp(rtllib->current_network.bssid, asSta, 6) == 0) {
 		rtllib->state = RTLLIB_NOLINK;
 
 		for (i = 0; i < 6; i++)
diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
index 1523bc7..1bb6b52e 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
@@ -479,7 +479,7 @@
 
 
 	/* this is just to be sure that the GET wx callback
-	 * has consisten infos. not needed otherwise
+	 * has consistent infos. not needed otherwise
 	 */
 	spin_lock_irqsave(&ieee->lock, flags);
 
@@ -575,7 +575,7 @@
 	if ((!ieee->sta_wake_up) ||
 	    (!ieee->enter_sleep_state) ||
 	    (!ieee->ps_is_queue_empty)) {
-		RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tryied to be use "
+		RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tried to be use "
 			     "but driver missed a callback\n\n", __func__);
 		return -1;
 	}
diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c
index f451bfc..42900ee 100644
--- a/drivers/staging/rtl8192e/rtllib_tx.c
+++ b/drivers/staging/rtl8192e/rtllib_tx.c
@@ -59,7 +59,7 @@
 802.11 Data Frame
 
 
-802.11 frame_contorl for data frames - 2 bytes
+802.11 frame_control for data frames - 2 bytes
      ,-----------------------------------------------------------------------------------------.
 bits | 0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  a  |  b  |  c  |  d  |  e   |
      |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------|
@@ -296,8 +296,7 @@
 		return;
 	if (!IsQoSDataFrame(skb->data))
 		return;
-	if (is_multicast_ether_addr(hdr->addr1) ||
-	    is_broadcast_ether_addr(hdr->addr1))
+	if (is_multicast_ether_addr(hdr->addr1))
 		return;
 
 	if (tcb_desc->bdhcp || ieee->CntAfterLink < 2)
@@ -515,7 +514,7 @@
 {
 	u16 seqnum = 0;
 
-	if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst))
+	if (is_multicast_ether_addr(dst))
 		return 0;
 	if (IsQoSDataFrame(skb->data)) {
 		struct tx_ts_record *pTS = NULL;
@@ -576,7 +575,7 @@
 
 	spin_lock_irqsave(&ieee->lock, flags);
 
-	/* If there is no driver handler to take the TXB, dont' bother
+	/* If there is no driver handler to take the TXB, don't bother
 	 * creating it... */
 	if ((!ieee->hard_start_xmit && !(ieee->softmac_features &
 	   IEEE_SOFTMAC_TX_QUEUE)) ||
@@ -698,8 +697,7 @@
 			       ETH_ALEN);
 		}
 
-		bIsMulticast = is_broadcast_ether_addr(header.addr1) ||
-			       is_multicast_ether_addr(header.addr1);
+		bIsMulticast = is_multicast_ether_addr(header.addr1);
 
 		header.frame_ctl = cpu_to_le16(fc);
 
@@ -738,7 +736,7 @@
 		   (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS))
 			bytes_per_frag -= RTLLIB_FCS_LEN;
 
-		/* Each fragment may need to have room for encryptiong
+		/* Each fragment may need to have room for encrypting
 		 * pre/postfix */
 		if (encrypt) {
 			bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c
index c27ff7e..c7e8d4d8 100644
--- a/drivers/staging/rtl8192e/rtllib_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_wx.c
@@ -88,7 +88,7 @@
 	}
 	/* Add the protocol name */
 	iwe.cmd = SIOCGIWNAME;
-	for (i = 0; i < (sizeof(rtllib_modes)/sizeof(rtllib_modes[0])); i++) {
+	for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) {
 		if (network->mode&(1<<i)) {
 			sprintf(pname, rtllib_modes[i].mode_string,
 				rtllib_modes[i].mode_size);
@@ -408,7 +408,7 @@
 				       (*crypt)->priv);
 		sec.flags |= (1 << key);
 		/* This ensures a key will be activated if no key is
-		 * explicitely set */
+		 * explicitly set */
 		if (key == sec.active_key)
 			sec.flags |= SEC_ACTIVE_KEY;
 		ieee->crypt_info.tx_keyidx = key;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
index e3d47bc..82d4bf6 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
@@ -161,7 +161,7 @@
 	if (ieee->pHTInfo == NULL)
 	{
 		IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n");
-		return NULL;
+		goto failed;
 	}
 	HTUpdateDefaultSetting(ieee);
 	HTInitializeHTInfo(ieee); //may move to other place.
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index be2a28c..e3cf7a4 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -671,7 +671,7 @@
 		index = 1;
 	} else {
 		/* Current packet is going to be inserted into pending list.*/
-		//IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to orderd list\n",__FUNCTION__);
+		//IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to ordered list\n",__FUNCTION__);
 		if(!list_empty(&ieee->RxReorder_Unused_List)) {
 			pReorderEntry = (PRX_REORDER_ENTRY)list_entry(ieee->RxReorder_Unused_List.next,RX_REORDER_ENTRY,List);
 			list_del_init(&pReorderEntry->List);
@@ -1285,7 +1285,7 @@
 */
 //added by amy for reorder
 	if(ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data)
-		&& !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1))
+		&& !is_multicast_ether_addr(hdr->addr1))
 	{
 		TID = Frame_QoSTID(skb->data);
 		SeqNum = WLAN_GET_SEQ_SEQ(sc);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index c2ab5fa..f6ff8cf 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -2062,7 +2062,7 @@
 							}
 						}else{
 							ieee->softmac_stats.rx_auth_rs_err++;
-							IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode);
+							IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x",errcode);
 							ieee80211_associate_abort(ieee);
 						}
 
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index 59c45a5..3f5ceeb 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -314,7 +314,7 @@
 	if (!IsQoSDataFrame(skb->data))
 		return;
 
-	if (is_multicast_ether_addr(hdr->addr1) || is_broadcast_ether_addr(hdr->addr1))
+	if (is_multicast_ether_addr(hdr->addr1))
 		return;
 	//check packet and mode later
 #ifdef TO_DO_LIST
@@ -575,7 +575,7 @@
 
 void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u8* dst)
 {
-	if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst))
+	if (is_multicast_ether_addr(dst))
 		return;
 	if (IsQoSDataFrame(skb->data)) //we deal qos data only
 	{
@@ -693,8 +693,7 @@
 
 		/* Determine fragmentation size based on destination (multicast
 		* and broadcast are not fragmented) */
-		if (is_multicast_ether_addr(header.addr1) ||
-		is_broadcast_ether_addr(header.addr1)) {
+		if (is_multicast_ether_addr(header.addr1)) {
 			frag_size = MAX_FRAG_THRESHOLD;
 			qos_ctl |= QOS_CTL_NOTCONTAIN_ACK;
 		}
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index 957ce4e..06a9824 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -350,7 +350,7 @@
 	// We do not build any TS for Broadcast or Multicast stream.
 	// So reject these kinds of search here.
 	//
-	if(is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr))
+	if (is_multicast_ether_addr(Addr))
 	{
 		IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
 		return false;
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c
index 8878cfe..3c515b7 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.c
+++ b/drivers/staging/rtl8192u/r8180_93cx6.c
@@ -14,7 +14,7 @@
 
    Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
 
-   We want to tanks the Authors of those projects and the Ndiswrapper
+   We want to thank the Authors of those projects and the Ndiswrapper
    project Authors.
 */
 
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.h b/drivers/staging/rtl8192u/r8180_93cx6.h
index fb3ac97..5cea51e 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.h
+++ b/drivers/staging/rtl8192u/r8180_93cx6.h
@@ -7,7 +7,7 @@
 	Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
 	Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
 
-	We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
+	We want to thank the Authors of such projects and the Ndiswrapper project Authors.
 */
 
 /*This files contains card eeprom (93c46 or 93c56) programming routines*/
diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h
index 9b81f26..57e3383 100644
--- a/drivers/staging/rtl8192u/r8192U.h
+++ b/drivers/staging/rtl8192u/r8192U.h
@@ -11,7 +11,7 @@
 
    Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
 
-   We want to tanks the Authors of those projects and the Ndiswrapper
+   We want to thank the Authors of those projects and the Ndiswrapper
    project Authors.
 */
 
@@ -98,7 +98,7 @@
 #define COMP_INIT				BIT2		// during driver initialization / halt / reset.
 
 
-#define COMP_RECV				BIT3		// Reveive part data path.
+#define COMP_RECV				BIT3		// Receive data path.
 #define COMP_SEND				BIT4		// Send part path.
 #define COMP_IO					BIT5		// I/O Related. Added by Annie, 2006-03-02.
 #define COMP_POWER				BIT6		// 802.11 Power Save mode or System/Device Power state related.
@@ -322,7 +322,7 @@
         u8		TxSubCarrier:2;         // This is used for legacy OFDM rate only.
         u8		STBC:2;
         u8		AllowAggregation:1;
-        u8		RtsHT:1;                //Interpre RtsRate field as high throughput data rate
+        u8		RtsHT:1;                //Interpret RtsRate field as high throughput data rate
         u8		RtsShort:1;             //Short PLCP for CCK, or short GI for 11n MCS
         u8		RtsBandwidth:1;         // This is used for HT MCS rate only.
         u8		RtsSubcarrier:2;        // This is used for legacy OFDM rate only.
@@ -610,7 +610,6 @@
 //	unsigned long rxnopointer;
 	unsigned long rxok;
 	unsigned long rxframgment;
-	unsigned long rxcmdpkt[4];		//08/05/08 amy rx cmd element txfeedback/bcn report/cfg set/query
 	unsigned long rxurberr;
 	unsigned long rxstaterr;
 	unsigned long received_rate_histogram[4][32];	//0: Total, 1:OK, 2:CRC, 3:ICV, 2007 07 03 cosa
@@ -1117,7 +1116,7 @@
 	bool bfsync_processing;	// 500ms Fsync timer is active or not
 	u32 	rate_record;
 	u32 	rateCountDiffRecord;
-	u32	ContiuneDiffCount;
+	u32	ContinueDiffCount;
 	bool bswitch_fsync;
 
 	u8	framesync;
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 9c00865..5981d66 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -203,7 +203,7 @@
 		{
 			Dot11d_Init(ieee);
 			ieee->bGlobalDomain = false;
-			//acturally 8225 & 8256 rf chip only support B,G,24N mode
+			//actually 8225 & 8256 rf chips only support B,G,24N mode
 			if ((priv->rf_chip == RF_8225) || (priv->rf_chip == RF_8256))
 			{
 				min_chan = 1;
@@ -1103,7 +1103,7 @@
 }
 
 
-/* The protype of rx_isr has changed since one verion of Linux Kernel */
+/* The prototype of rx_isr has changed since one version of Linux Kernel */
 static void rtl8192_rx_isr(struct urb *urb)
 {
 	struct sk_buff *skb = (struct sk_buff *) urb->context;
@@ -1476,7 +1476,7 @@
 	if(tcb_desc->queue_index != TXCMD_QUEUE) {
 		if(tx_urb->status == 0) {
 			dev->trans_start = jiffies;
-			// As act as station mode, destion shall be  unicast address.
+			// Act as station mode, destination shall be unicast address.
 			//priv->ieee80211->stats.tx_bytes+=(skb->len - priv->ieee80211->tx_headroom);
 			//priv->ieee80211->stats.tx_packets++;
 			priv->stats.txoktotal++;
@@ -1522,13 +1522,13 @@
 			else if ((skb_queue_len(&priv->ieee80211->skb_drv_aggQ[queue_index])!= 0)&&\
 				(!(priv->ieee80211->queue_stop))) {
 				// Tx Driver Aggregation process
-				/* The driver will aggregation the packets according to the following stets
+				/* The driver will aggregation the packets according to the following stats
 				 * 1. check whether there's tx irq available, for it's a completion return
 				 *    function, it should contain enough tx irq;
-				 * 2. check pakcet type;
+				 * 2. check packet type;
 				 * 3. initialize sendlist, check whether the to-be send packet no greater than 1
-				 * 4. aggregation the packets, and fill firmware info and tx desc to it, etc.
-				 * 5. check whehter the packet could be sent, otherwise just insert to wait head
+				 * 4. aggregates the packets, and fill firmware info and tx desc into it, etc.
+				 * 5. check whether the packet could be sent, otherwise just insert into wait head
 				 * */
 				skb = skb_dequeue(&priv->ieee80211->skb_drv_aggQ[queue_index]);
 				if(!check_nic_enough_desc(dev, queue_index)) {
@@ -2447,7 +2447,7 @@
 	return 0;
 }
 
-/* handle manage frame frame beacon and probe response */
+/* handle and manage frame from beacon and probe response */
 static int rtl8192_handle_beacon(struct net_device * dev,
 			      struct ieee80211_beacon * beacon,
 			      struct ieee80211_network * network)
@@ -2625,7 +2625,7 @@
 void rtl8192_refresh_supportrate(struct r8192_priv* priv)
 {
 	struct ieee80211_device* ieee = priv->ieee80211;
-	//we donot consider set support rate for ABG mode, only HT MCS rate is set here.
+	//we do not consider set support rate for ABG mode, only HT MCS rate is set here.
 	if (ieee->mode == WIRELESS_MODE_N_24G || ieee->mode == WIRELESS_MODE_N_5G)
 	{
 		memcpy(ieee->Regdot11HTOperationalRateSet, ieee->RegHTSuppRateSet, 16);
@@ -2780,10 +2780,10 @@
 	priv->TransmitConfig =
 	//	TCR_DurProcMode |	//for RTL8185B, duration setting by HW
 	//?	TCR_DISReqQsize |
-		(TCR_MXDMA_2048<<TCR_MXDMA_OFFSET)|  // Max DMA Burst Size per Tx DMA Burst, 7: reservied.
+		(TCR_MXDMA_2048<<TCR_MXDMA_OFFSET)|  // Max DMA Burst Size per Tx DMA Burst, 7: reserved.
 		(priv->ShortRetryLimit<<TCR_SRL_OFFSET)|	// Short retry limit
 		(priv->LongRetryLimit<<TCR_LRL_OFFSET) |	// Long retry limit
-		(false ? TCR_SAT: 0);	// FALSE: HW provies PLCP length and LENGEXT, TURE: SW proiveds them
+		(false ? TCR_SAT: 0);	// FALSE: HW provides PLCP length and LENGEXT, TRUE: SW provides them
 #ifdef TO_DO_LIST
 	if(Adapter->bInHctTest)
 		pHalData->ReceiveConfig	=	pHalData->CSMethod |
@@ -3437,7 +3437,7 @@
 		{ // User disable RF via registry.
 			RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter819xUsb(): Turn off RF for RegRfOff ----------\n"));
 			MgntActSet_RF_State(Adapter, eRfOff, RF_CHANGE_BY_SW);
-			// Those action will be discard in MgntActSet_RF_State because off the same state
+			// Those actions will be discard in MgntActSet_RF_State because of the same state
 			for(eRFPath = 0; eRFPath <pHalData->NumTotalRFPath; eRFPath++)
 				PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0);
 		}
@@ -3458,7 +3458,7 @@
 		if(pHalData->eRFPowerState == eRfOff)
 		{
 			MgntActSet_RF_State(Adapter, eRfOff, pMgntInfo->RfOffReason);
-			// Those action will be discard in MgntActSet_RF_State because off the same state
+			// Those actions will be discard in MgntActSet_RF_State because of the same state
 			for(eRFPath = 0; eRFPath <pHalData->NumTotalRFPath; eRFPath++)
 				PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0);
 		}
@@ -3586,7 +3586,7 @@
 	//unsigned long flags;
 
 	//
-	// Decide Stuch threshold according to current power save mode
+	// Decide such threshold according to current power save mode
 	//
 
 //     RT_TRACE(COMP_RESET, " ==> TxCheckStuck()\n");
@@ -3745,7 +3745,7 @@
 
 		// Driver should not check RX stuck in IBSS mode because it is required to
 		// set Check BSSID in order to send beacon, however, if check BSSID is
-		// set, STA cannot hear any packet a all. Emily, 2008.04.12
+		// set, STA cannot hear any packet at all. Emily, 2008.04.12
 		RxResetType = RxCheckStuck(dev);
 	}
 	if(TxResetType==RESET_TYPE_NORMAL || RxResetType==RESET_TYPE_NORMAL)
@@ -3962,7 +3962,7 @@
 		up(&priv->wx_sem);
 		RT_TRACE(COMP_RESET,"%s():<==========down process is finished\n",__FUNCTION__);
 	//rtl8192_irq_disable(dev);
-		RT_TRACE(COMP_RESET,"%s():===========>start to up the driver\n",__FUNCTION__);
+		RT_TRACE(COMP_RESET,"%s():===========>start up the driver\n",__FUNCTION__);
 		reset_status = _rtl8192_up(dev);
 
 		RT_TRACE(COMP_RESET,"%s():<===========up process is finished\n",__FUNCTION__);
@@ -4155,7 +4155,7 @@
 void watch_dog_timer_callback(unsigned long data)
 {
 	struct r8192_priv *priv = ieee80211_priv((struct net_device *) data);
-	//printk("===============>watch_dog  timer\n");
+	//printk("===============>watch_dog timer\n");
 	queue_delayed_work(priv->priv_wq,&priv->watch_dog_wq, 0);
 	mod_timer(&priv->watch_dog_timer, jiffies + MSECS(IEEE80211_WATCH_DOG_TIME));
 }
@@ -4170,7 +4170,7 @@
 	init_status = rtl8192_adapter_start(dev);
 	if(!init_status)
 	{
-		RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization is failed!\n", __FUNCTION__);
+		RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization failed!\n", __FUNCTION__);
 		priv->up=priv->ieee80211->ieee_up = 0;
 		return -EAGAIN;
 	}
@@ -4256,7 +4256,7 @@
 		skb_queue_purge(&priv->ieee80211->skb_drv_aggQ [i]);
 	}
 
-	//as cancel_delayed_work will del work->timer, so if work is not definedas struct delayed_work, it will corrupt
+	//as cancel_delayed_work will del work->timer, so if work is not defined as struct delayed_work, it will corrupt
 //	flush_scheduled_work();
 	rtl8192_cancel_deferred_work(priv);
 	deinit_hal_dm(dev);
@@ -4516,7 +4516,7 @@
 
 /**
  * Function:     UpdateRxPktTimeStamp
- * Overview:     Recored down the TSF time stamp when receiving a packet
+ * Overview:     Record the TSF time stamp when receiving a packet
  *
  * Input:
  *       PADAPTER        Adapter
@@ -4556,10 +4556,10 @@
 }
 
 
-/* 2008/01/22 MH We can not delcare RSSI/EVM total value of sliding window to
+/* 2008/01/22 MH We can not declare RSSI/EVM total value of sliding window to
     be a local static. Otherwise, it may increase when we return from S3/S4. The
-    value will be kept in memory or disk. We must delcare the value in adapter
-    and it will be reinitialized when return from S3/S4. */
+    value will be kept in memory or disk. Declare the value in the adaptor
+    and it will be reinitialized when returned from S3/S4. */
 void rtl8192_process_phyinfo(struct r8192_priv * priv,u8* buffer, struct ieee80211_rx_stats * pprevious_stats, struct ieee80211_rx_stats * pcurrent_stats)
 {
 	bool bcheck = false;
@@ -5091,8 +5091,8 @@
 			tmp_rxevm =	pofdm_buf->rxevm_X[i];
 			rx_evmX = (char)(tmp_rxevm);
 
-			// Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment
-			// fill most significant bit to "zero" when doing shifting operation which may change a negative
+			// Do not use shift operation like "rx_evmX >>= 1" because the compiler of free build environment
+			// will set the most significant bit to "zero" when doing shifting operation which may change a negative
 			// value to positive one, then the dbm value (which is supposed to be negative)  is not correct anymore.
 			rx_evmX /= 2;	//dbm
 
@@ -5171,7 +5171,7 @@
 	type = WLAN_FC_GET_TYPE(fc);
 	praddr = hdr->addr1;
 
-	/* Check if the received packet is acceptabe. */
+	/* Check if the received packet is acceptable. */
 	bpacket_match_bssid = ((IEEE80211_FTYPE_CTL != type) &&
 							(eqMacAddr(priv->ieee80211->current_network.bssid,  (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3))
 								 && (!pstats->bHwError) && (!pstats->bCRC)&& (!pstats->bICV));
@@ -5211,7 +5211,7 @@
 
 /**
 * Function:	UpdateReceivedRateHistogramStatistics
-* Overview:	Recored down the received data rate
+* Overview:	Record the received data rate
 *
 * Input:
 * 	struct net_device *dev
@@ -5401,7 +5401,7 @@
 	}
 
 #ifdef USB_RX_AGGREGATION_SUPPORT
-	/* for the rx aggregated sub frame, the redundant space truelly contained in the packet */
+	/* for the rx aggregated sub frame, the redundant space truly contained in the packet */
 	if(bIsRxAggrSubframe) {
 		skb_pull(skb, 8);
 	}
@@ -5480,7 +5480,7 @@
 			PacketShiftBytes = GetRxPacketShiftBytes819xUsb(&stats, false);
 		}
 #endif
-		/* Process the MPDU recevied */
+		/* Process the MPDU received */
 		skb_trim(skb, skb->len - 4/*sCrcLng*/);
 
 		rx_pkt_len = skb->len;
@@ -5538,7 +5538,7 @@
 				if(PacketLength > agg_skb->len) {
 					break;
 				}
-				/* Process the MPDU recevied */
+				/* Process the MPDU received */
 				skb = dev_alloc_skb(PacketLength);
 				memcpy(skb_put(skb,PacketLength),agg_skb->data, PacketLength);
 				skb_trim(skb, skb->len - 4/*sCrcLng*/);
diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
index 2dde9fa..cd8dc85 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.c
+++ b/drivers/staging/rtl8192u/r8192U_dm.c
@@ -38,7 +38,7 @@
 /*------------------------Define global variable-----------------------------*/
 // Debug variable ?
 dig_t	dm_digtable;
-// Store current shoftware write register content for MAC PHY.
+// Store current software write register content for MAC PHY.
 u8		dm_shadow[16][256] = {{0}};
 // For Dynamic Rx Path Selection by Signal Strength
 DRxPathSel	DM_RxPathSelTable;
@@ -119,7 +119,7 @@
 static	void	dm_cs_ratio(struct net_device *dev);
 
 static	void dm_init_ctstoself(struct net_device *dev);
-// DM --> EDCA turboe mode control
+// DM --> EDCA turbo mode control
 static	void	dm_check_edca_turbo(struct net_device *dev);
 
 // DM --> HW RF control
@@ -348,7 +348,7 @@
  *
  * Revised History:
  *	When		Who		Remark
- *	05/26/08	amy 	Create version 0 proting from windows code.
+ *	05/26/08	amy 	Create version 0 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
 static void dm_check_rate_adaptive(struct net_device * dev)
@@ -543,7 +543,7 @@
 	0x5a400169,	// 3, +3db
 	0x50800142,	// 4, +2db
 	0x47c0011f,	// 5, +1db
-	0x40000100,	// 6, +0db ===> default, upper for higher temprature, lower for low temprature
+	0x40000100,	// 6, +0db ===> default, upper for higher temperature, lower for low temperature
 	0x390000e4,	// 7, -1db
 	0x32c000cb,	// 8, -2db
 	0x2d4000b5,	// 9, -3db
@@ -678,7 +678,7 @@
 		{
 			write_nic_byte(dev, 0x1ba, 0);
 			viviflag = FALSE;
-			RT_TRACE(COMP_POWER_TRACKING, "we filted this data\n");
+			RT_TRACE(COMP_POWER_TRACKING, "we filtered the data\n");
 			for(k = 0;k < 5; k++)
 				tmp_report[k] = 0;
 			break;
@@ -864,14 +864,14 @@
 	RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d \n", tmpRegA);
 	if(tmpRegA < 3 || tmpRegA > 13)
 		return;
-	if(tmpRegA >= 12)	// if over 12, TP will be bad when high temprature
+	if(tmpRegA >= 12)	// if over 12, TP will be bad when high temperature
 		tmpRegA = 12;
 	RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d \n", tmpRegA);
 	priv->ThermalMeter[0] = ThermalMeterVal;	//We use fixed value by Bryant's suggestion
 	priv->ThermalMeter[1] = ThermalMeterVal;	//We use fixed value by Bryant's suggestion
 
-	//Get current RF-A temprature index
-	if(priv->ThermalMeter[0] >= (u8)tmpRegA)	//lower temprature
+	//Get current RF-A temperature index
+	if(priv->ThermalMeter[0] >= (u8)tmpRegA)	//lower temperature
 	{
 		tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0]-(u8)tmpRegA);
 		tmpCCK40Mindex = tmpCCK20Mindex - 6;
@@ -885,7 +885,7 @@
 	else
 	{
 		tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]);
-		if(tmpval >= 6)								// higher temprature
+		if(tmpval >= 6)								// higher temperature
 			tmpOFDMindex = tmpCCK20Mindex = 0;		// max to +6dB
 		else
 			tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval;
@@ -1457,9 +1457,9 @@
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
-	// Tx Power tracking by Theremal Meter require Firmware R/W 3-wire. This mechanism
+	// Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
 	// can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
-	// 3-wire by driver cause RF goes into wrong state.
+	// 3-wire by driver causes RF to go into a wrong state.
 	if(priv->ieee80211->FwRWRF)
 		priv->btxpower_tracking = TRUE;
 	else
@@ -1520,7 +1520,7 @@
 
 	if(!TM_Trigger)
 	{
-		//Attention!! You have to wirte all 12bits data to RF, or it may cause RF to crash
+		//Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
 		//actually write reg0x02 bit1=0, then bit1=1.
 		//DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n");
 		rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
@@ -1744,7 +1744,7 @@
 			write_nic_dword(dev, RATR0, ratr_value);
 			write_nic_byte(dev, UFWP, 1);
 	}
-	//Resore TX Power Tracking Index
+	//Restore TX Power Tracking Index
 	if(priv->btxpower_trackingInit && priv->btxpower_tracking){
 		dm_txpower_reset_recovery(dev);
 	}
@@ -2031,7 +2031,7 @@
 	dm_digtable.dbg_mode = DM_DBG_OFF;	//off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig
 	dm_digtable.dig_algorithm_switch = 0;
 
-	/* 2007/10/04 MH Define init gain threshol. */
+	/* 2007/10/04 MH Define init gain threshold. */
 	dm_digtable.dig_state		= DM_STA_DIG_MAX;
 	dm_digtable.dig_highpwr_state	= DM_STA_DIG_MAX;
 	dm_digtable.initialgain_lowerbound_state = false;
@@ -2097,7 +2097,7 @@
 		return;
 
 	//DbgPrint("Dig by Sw Rssi \n");
-	if(dm_digtable.dig_algorithm_switch)	// if swithed algorithm, we have to disable FW Dig.
+	if(dm_digtable.dig_algorithm_switch)	// if switched algorithm, we have to disable FW Dig.
 		fw_dig = 0;
 	if(fw_dig <= 3)	// execute several times to make sure the FW Dig is disabled
 	{// FW DIG Off
@@ -2160,8 +2160,8 @@
 	/*DbgPrint("DIG Check\n\r RSSI=%d LOW=%d HIGH=%d STATE=%d",
 	pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh,
 	DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/
-	/* 1. When RSSI decrease, We have to judge if it is smaller than a treshold
-		  and then execute below step. */
+	/* 1. When RSSI decrease, We have to judge if it is smaller than a threshold
+		  and then execute the step below. */
 	if ((priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh))
 	{
 		/* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters
@@ -2220,8 +2220,8 @@
 
 	}
 
-	/* 2. When RSSI increase, We have to judge if it is larger than a treshold
-		  and then execute below step.  */
+	/* 2. When RSSI increase, We have to judge if it is larger than a threshold
+		  and then execute the step below.  */
 	if ((priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) )
 	{
 		u8 reset_flag = 0;
@@ -2329,7 +2329,7 @@
 	}
 
 	/* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
-		  it is larger than a treshold and then execute below step.  */
+		  it is larger than a threshold and then execute the step below.  */
 	// 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
 	if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh)
 	{
@@ -2841,8 +2841,8 @@
 {
 	//struct r8192_priv *priv = ieee80211_priv(dev);
 
-	// Walk around for DTM test, we will not enable HW - radio on/off because r/w
-	// page 1 register before Lextra bus is enabled cause system fails when resuming
+	// Work around for DTM test, we will not enable HW - radio on/off because r/w
+	// page 1 register before extra bus is enabled causing system failures when resuming
 	// from S4. 20080218, Emily
 
 	// Stop to execute workitem to prevent S3/S4 bug.
@@ -3377,30 +3377,30 @@
 		{
 
 			u32 DiffNum = priv->rateCountDiffRecord - rate_count_diff;
-			// Contiune count
+			// Continue count
 			if(DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold)
-				priv->ContiuneDiffCount++;
+				priv->ContinueDiffCount++;
 			else
-				priv->ContiuneDiffCount = 0;
+				priv->ContinueDiffCount = 0;
 
-			// Contiune count over
-			if(priv->ContiuneDiffCount >=2)
+			// Continue count over
+			if(priv->ContinueDiffCount >=2)
 			{
 				bSwitchFromCountDiff = true;
-				priv->ContiuneDiffCount = 0;
+				priv->ContinueDiffCount = 0;
 			}
 		}
 		else
 		{
-			// Stop contiune count
-			priv->ContiuneDiffCount = 0;
+			// Stop the continued count
+			priv->ContinueDiffCount = 0;
 		}
 
 		//If Count diff <= FsyncRateCountThreshold
 		if(rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold)
 		{
 			bSwitchFromCountDiff = true;
-			priv->ContiuneDiffCount = 0;
+			priv->ContinueDiffCount = 0;
 		}
 		priv->rate_record = rate_count;
 		priv->rateCountDiffRecord = rate_count_diff;
@@ -3468,14 +3468,14 @@
 		#endif
 			write_nic_byte(dev, 0xC3e, 0x96);
 		}
-		priv->ContiuneDiffCount = 0;
+		priv->ContinueDiffCount = 0;
 	#ifdef RTL8190P
 		write_nic_dword(dev, rOFDM0_RxDetector2, 0x164052cd);
 	#else
 		write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
 	#endif
 	}
-	RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount);
+	RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount);
 	RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync);
 }
 
@@ -3507,7 +3507,7 @@
 		write_nic_byte(dev, 0xC3e, 0x96);
 	}
 
-	priv->ContiuneDiffCount = 0;
+	priv->ContinueDiffCount = 0;
 #ifndef RTL8190P
 	write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
 #endif
@@ -3523,8 +3523,8 @@
 	RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__);
 	// Initial rate record to zero, start to record.
 	priv->rate_record = 0;
-	// Initial contiune diff count to zero, start to record.
-	priv->ContiuneDiffCount = 0;
+	// Initialize continue diff count to zero, start to record.
+	priv->ContinueDiffCount = 0;
 	priv->rateCountDiffRecord = 0;
 	priv->bswitch_fsync  = false;
 
@@ -3875,7 +3875,7 @@
 
 	// If we test chariot, we should stop the TX command ?
 	// Because 92E will always silent reset when we send tx command. We use register
-	// 0x1e0(byte) to botify driver.
+	// 0x1e0(byte) to notify driver.
 	write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb);
 	return;
 	tx_cmd.Op		= TXCMD_SET_RX_RSSI;
diff --git a/drivers/staging/rtl8192u/r8192U_hw.h b/drivers/staging/rtl8192u/r8192U_hw.h
index e89aaf7..1bfe871 100644
--- a/drivers/staging/rtl8192u/r8192U_hw.h
+++ b/drivers/staging/rtl8192u/r8192U_hw.h
@@ -10,7 +10,7 @@
 	Parts of this driver are based on the Intel Pro Wireless
 	2100 GPL driver.
 
-	We want to tanks the Authors of those projects
+	We want to thank the Authors of those projects
 	and the Ndiswrapper project Authors.
 */
 
diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c
index f6408f9..71f2d23 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.c
+++ b/drivers/staging/rtl8192u/r8192U_wx.c
@@ -13,7 +13,7 @@
 
    Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
 
-   We want to tanks the Authors of those projects and the Ndiswrapper
+   We want to thank the Authors of those projects and the Ndiswrapper
    project Authors.
 */
 
@@ -256,7 +256,7 @@
 	//count the length of input ssid
 	for(name_len=0 ; ((char*)wrqu->data.pointer)[name_len]!='\0' ; name_len++);
 
-	//search for the correspoding info which is received
+	//search for the corresponding info which is received
 	list_for_each_entry(target, &ieee->network_list, list) {
 		if ( (target->ssid_len == name_len) &&
 		     (strncmp(target->ssid, (char*)wrqu->data.pointer, name_len)==0)){
@@ -419,7 +419,7 @@
 	range->max_qual.updated = 7; /* Updated all three */
 
 	range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
-	/* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+	/* TODO: Find real 'good' to 'bad' threshold value for RSSI */
 	range->avg_qual.level = 20 + -98;
 	range->avg_qual.noise = 0;
 	range->avg_qual.updated = 7; /* Updated all three */
@@ -1047,7 +1047,7 @@
 #else
 	 NULL,
 #endif
-	dummy,                     /* SIOCGIWAPLIST -- depricated */
+	dummy,                     /* SIOCGIWAPLIST -- deprecated */
 	r8192_wx_set_scan,        /* SIOCSIWSCAN */
 	r8192_wx_get_scan,        /* SIOCGIWSCAN */
 	r8192_wx_set_essid,       /* SIOCSIWESSID */
@@ -1211,9 +1211,9 @@
 
 struct iw_handler_def  r8192_wx_handlers_def={
 	.standard = r8192_wx_handlers,
-	.num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler),
+	.num_standard = ARRAY_SIZE(r8192_wx_handlers),
 	.private = r8192_private_handler,
-	.num_private = sizeof(r8192_private_handler) / sizeof(iw_handler),
+	.num_private = ARRAY_SIZE(r8192_private_handler),
 	.num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args),
 #if WIRELESS_EXT >= 17
 	.get_wireless_stats = r8192_get_wireless_stats,
diff --git a/drivers/staging/rtl8192u/r8192U_wx.h b/drivers/staging/rtl8192u/r8192U_wx.h
index f4cf280..9f6b105 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.h
+++ b/drivers/staging/rtl8192u/r8192U_wx.h
@@ -7,7 +7,7 @@
 	Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
 	Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
 
-	We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
+	We want to thank the Authors of such projects and the Ndiswrapper project Authors.
 */
 
 /* this file (will) contains wireless extension handlers*/
diff --git a/drivers/staging/rtl8192u/r819xU_HTType.h b/drivers/staging/rtl8192u/r819xU_HTType.h
index 2ac4216..e07f8b1 100644
--- a/drivers/staging/rtl8192u/r819xU_HTType.h
+++ b/drivers/staging/rtl8192u/r819xU_HTType.h
@@ -211,7 +211,7 @@
 	u8				bEnableHT;
 	u8				bCurrentHTSupport;
 
-	u8				bRegBW40MHz;				// Tx 40MHz channel capablity
+	u8				bRegBW40MHz;				// Tx 40MHz channel capability
 	u8				bCurBW40MHz;				// Tx 40MHz channel capability
 
 	u8				bRegShortGI40MHz;			// Tx Short GI for 40Mhz
diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
index 0cb28c7..a8a6dc2 100644
--- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c
+++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
@@ -157,7 +157,7 @@
 		seg_ptr = skb_put(skb, buffer_len);
 		/*
 		 * Transform from little endian to big endian
-		 * and pending  zero
+		 * and pending zero
 		 */
 		memcpy(seg_ptr,codevirtualaddress,buffer_len);
 		tcb_desc->txbuf_size= (u16)buffer_len;
@@ -697,7 +697,6 @@
 	struct ieee80211_rx_stats *pstats)
 {
 //	u32			debug_level = DBG_LOUD;
-	struct r8192_priv *priv = ieee80211_priv(dev);
 	int			total_length;
 	u8			cmd_length, exe_cnt = 0;
 	u8			element_id;
@@ -719,15 +718,15 @@
 	/* 2. Read virtual address from RFD. */
 	pcmd_buff = pstats->virtual_address;
 
-	/* 3. Read command pakcet element id and length. */
+	/* 3. Read command packet element id and length. */
 	element_id = pcmd_buff[0];
 	/*RT_TRACE(COMP_SEND, DebugLevel,
 			("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
 
-	/* 4. Check every received command packet conent according to different
+	/* 4. Check every received command packet content according to different
 	      element type. Because FW may aggregate RX command packet to minimize
 	      transmit time between DRV and FW.*/
-	// Add a counter to prevent to locked in the loop too long
+	// Add a counter to prevent the lock in the loop from being held too long
 	while (total_length > 0 || exe_cnt++ >100)
 	{
 		/* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
@@ -779,9 +778,6 @@
 		// 2007/01/22 MH Add to display tx statistic.
 		//cmpk_DisplayTxStatistic(pAdapter);
 
-		/* 2007/03/09 MH Collect sidderent cmd element pkt num. */
-		priv->stats.rxcmdpkt[element_id]++;
-
 		total_length -= cmd_length;
 		pcmd_buff    += cmd_length;
 	}	/* while (total_length > 0) */
diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c
index 4bb5fff..b12d190 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware.c
+++ b/drivers/staging/rtl8192u/r819xU_firmware.c
@@ -275,11 +275,11 @@
 
 	/*
 	 * Download boot, main, and data image for System reset.
-	 * Download data image for firmware reseta
+	 * Download data image for firmware reset
 	 */
 	for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) {
 		/*
-		 * Open Image file, and map file to contineous memory if open file success.
+		 * Open image file, and map file to continuous memory if open file success.
 		 * or read image file from array. Default load from IMG file
 		 */
 		if(rst_opt == OPT_SYSTEM_RESET) {
diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c
index c4586b0..dd1954d 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.c
+++ b/drivers/staging/rtl8192u/r819xU_phy.c
@@ -40,7 +40,7 @@
  *	     and do register read/write
  *   input:  u32	dwBitMask  //taget bit pos in the addr to be modified
  *  output:  none
- *  return:  u32	return the shift bit bit position of the mask
+ *  return:  u32	return the shift bit position of the mask
  * ****************************************************************************/
 u32 rtl8192_CalculateBitShift(u32 dwBitMask)
 {
@@ -176,7 +176,7 @@
 	rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2,  bLSSIReadEdge, 0x1);
 
 
-	// TODO: we should not delay such a  long time. Ask help from SD3
+	// TODO: we should not delay such a long time. Ask for help from SD3
 	msleep(1);
 
 	ret = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData);
@@ -252,7 +252,7 @@
 		NewOffset = Offset;
 	}
 
-	// Put write addr in [5:0]  and write data in [31:16]
+	// Put write addr in [5:0] and write data in [31:16]
 	DataAndAddr = (Data<<16) | (NewOffset&0x3f);
 
 	// Write Operation
@@ -525,7 +525,7 @@
 }
 
 /******************************************************************************
- *function:  This function do dirty work
+ *function:  This function does dirty work
  *   input:  dev
  *  output:  none
  *  return:  none
@@ -578,7 +578,7 @@
 void rtl8192_InitBBRFRegDef(struct net_device* dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-// RF Interface Sowrtware Control
+// RF Interface Software Control
 	priv->PHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870
 	priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872)
 	priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 LSBs if read 32-bit from 0x874
@@ -602,7 +602,7 @@
 	priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86A (16-bit for 0x86A)
 	priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86C (16-bit for 0x86E)
 
-	//Addr of LSSI. Wirte RF register by driver
+	//Addr of LSSI. Write RF register by driver
 	priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter
 	priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
 	priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter;
@@ -1384,7 +1384,7 @@
 }
 
 /******************************************************************************
- *function:  This function does acturally set channel work
+ *function:  This function does actually set channel work
  *   input:  struct net_device *dev
  *   	     u8 		channel
  *  output:  none
@@ -1425,7 +1425,7 @@
 }
 
 /******************************************************************************
- *function:  This function scheduled actural workitem to set channel
+ *function:  This function scheduled actual work item to set channel
  *   input:  net_device dev
  *   	     u8		channel //channel to set
  *  output:  none
diff --git a/drivers/staging/rtl8192u/r819xU_phyreg.h b/drivers/staging/rtl8192u/r819xU_phyreg.h
index 06b0b53..50f24dc 100644
--- a/drivers/staging/rtl8192u/r819xU_phyreg.h
+++ b/drivers/staging/rtl8192u/r819xU_phyreg.h
@@ -443,7 +443,7 @@
 #define bCCKRxIG                  			0x7f00
 #define bCCKLNAPolarity           		0x800000
 #define bCCKRx1stGain             		0x7f0000
-#define bCCKRFExtend              		0x20000000 //CCK Rx Iinital gain polarity
+#define bCCKRFExtend              		0x20000000 //CCK Rx inital gain polarity
 #define bCCKRxAGCSatLevel        		0x1f000000
 #define bCCKRxAGCSatCount       		0xe0
 #define bCCKRxRFSettle            		0x1f       //AGCsamp_dly
diff --git a/drivers/staging/rtl8712/big_endian.h b/drivers/staging/rtl8712/big_endian.h
deleted file mode 100644
index b16f8ec..0000000
--- a/drivers/staging/rtl8712/big_endian.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_BIG_ENDIAN_H
-#define _LINUX_BYTEORDER_BIG_ENDIAN_H
-
-#ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN 4321
-#endif
-#ifndef __BIG_ENDIAN_BITFIELD
-#define __BIG_ENDIAN_BITFIELD
-#endif
-
-#include "swab.h"
-
-#define __constant_htonl(x) ((__u32)(x))
-#define __constant_ntohl(x) ((__u32)(x))
-#define __constant_htons(x) ((__u16)(x))
-#define __constant_ntohs(x) ((__u16)(x))
-#define __constant_cpu_to_le64(x) ___constant_swab64((x))
-#define __constant_le64_to_cpu(x) ___constant_swab64((x))
-#define __constant_cpu_to_le32(x) ___constant_swab32((x))
-#define __constant_le32_to_cpu(x) ___constant_swab32((x))
-#define __constant_cpu_to_le16(x) ___constant_swab16((x))
-#define __constant_le16_to_cpu(x) ___constant_swab16((x))
-#define __constant_cpu_to_be64(x) ((__u64)(x))
-#define __constant_be64_to_cpu(x) ((__u64)(x))
-#define __constant_cpu_to_be32(x) ((__u32)(x))
-#define __constant_be32_to_cpu(x) ((__u32)(x))
-#define __constant_cpu_to_be16(x) ((__u16)(x))
-#define __constant_be16_to_cpu(x) ((__u16)(x))
-#define __cpu_to_le64(x) __swab64((x))
-#define __le64_to_cpu(x) __swab64((x))
-#define __cpu_to_le32(x) __swab32((x))
-#define __le32_to_cpu(x) __swab32((x))
-#define __cpu_to_le16(x) __swab16((x))
-#define __le16_to_cpu(x) __swab16((x))
-#define __cpu_to_be64(x) ((__u64)(x))
-#define __be64_to_cpu(x) ((__u64)(x))
-#define __cpu_to_be32(x) ((__u32)(x))
-#define __be32_to_cpu(x) ((__u32)(x))
-#define __cpu_to_be16(x) ((__u16)(x))
-#define __be16_to_cpu(x) ((__u16)(x))
-#define __cpu_to_le64p(x) __swab64p((x))
-#define __le64_to_cpup(x) __swab64p((x))
-#define __cpu_to_le32p(x) __swab32p((x))
-#define __le32_to_cpup(x) __swab32p((x))
-#define __cpu_to_le16p(x) __swab16p((x))
-#define __le16_to_cpup(x) __swab16p((x))
-#define __cpu_to_be64p(x) (*(__u64 *)(x))
-#define __be64_to_cpup(x) (*(__u64 *)(x))
-#define __cpu_to_be32p(x) (*(__u32 *)(x))
-#define __be32_to_cpup(x) (*(__u32 *)(x))
-#define __cpu_to_be16p(x) (*(__u16 *)(x))
-#define __be16_to_cpup(x) (*(__u16 *)(x))
-#define __cpu_to_le64s(x) __swab64s((x))
-#define __le64_to_cpus(x) __swab64s((x))
-#define __cpu_to_le32s(x) __swab32s((x))
-#define __le32_to_cpus(x) __swab32s((x))
-#define __cpu_to_le16s(x) __swab16s((x))
-#define __le16_to_cpus(x) __swab16s((x))
-#define __cpu_to_be64s(x) do {} while (0)
-#define __be64_to_cpus(x) do {} while (0)
-#define __cpu_to_be32s(x) do {} while (0)
-#define __be32_to_cpus(x) do {} while (0)
-#define __cpu_to_be16s(x) do {} while (0)
-#define __be16_to_cpus(x) do {} while (0)
-
-#include "generic.h"
-
-#endif /* _LINUX_BYTEORDER_BIG_ENDIAN_H */
-
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index e83665d..62b5566 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -146,7 +146,7 @@
 /**
  * struct _adapter - the main adapter structure for this device.
  *
- * bup: True indicates that the interface is Up.
+ * bup: True indicates that the interface is up.
  */
 struct _adapter {
 	struct	dvobj_priv dvobjpriv;
diff --git a/drivers/staging/rtl8712/generic.h b/drivers/staging/rtl8712/generic.h
deleted file mode 100644
index 8868c9f..0000000
--- a/drivers/staging/rtl8712/generic.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_GENERIC_H
-#define _LINUX_BYTEORDER_GENERIC_H
-
-/*
- * linux/byteorder_generic.h
- * Generic Byte-reordering support
- *
- * Francois-Rene Rideau <fare@tunes.org> 19970707
- *    gathered all the good ideas from all asm-foo/byteorder.h into one file,
- *    cleaned them up.
- *    I hope it is compliant with non-GCC compilers.
- *    I decided to put __BYTEORDER_HAS_U64__ in byteorder.h,
- *    because I wasn't sure it would be ok to put it in types.h
- *    Upgraded it to 2.1.43
- * Francois-Rene Rideau <fare@tunes.org> 19971012
- *    Upgraded it to 2.1.57
- *    to please Linus T., replaced huge #ifdef's between little/big endian
- *    by nestedly #include'd files.
- * Francois-Rene Rideau <fare@tunes.org> 19971205
- *    Made it to 2.1.71; now a facelift:
- *    Put files under include/linux/byteorder/
- *    Split swab from generic support.
- *
- * TODO:
- *   = Regular kernel maintainers could also replace all these manual
- *    byteswap macros that remain, disseminated among drivers,
- *    after some grep or the sources...
- *   = Linus might want to rename all these macros and files to fit his taste,
- *    to fit his personal naming scheme.
- *   = it seems that a few drivers would also appreciate
- *    nybble swapping support...
- *   = every architecture could add their byteswap macro in asm/byteorder.h
- *    see how some architectures already do (i386, alpha, ppc, etc)
- *   = cpu_to_beXX and beXX_to_cpu might some day need to be well
- *    distinguished throughout the kernel. This is not the case currently,
- *    since little endian, big endian, and pdp endian machines needn't it.
- *    But this might be the case for, say, a port of Linux to 20/21 bit
- *    architectures (and F21 Linux addict around?).
- */
-
-/*
- * The following macros are to be defined by <asm/byteorder.h>:
- *
- * Conversion of long and short int between network and host format
- *	ntohl(__u32 x)
- *	ntohs(__u16 x)
- *	htonl(__u32 x)
- *	htons(__u16 x)
- * It seems that some programs (which? where? or perhaps a standard? POSIX?)
- * might like the above to be functions, not macros (why?).
- * if that's true, then detect them, and take measures.
- * Anyway, the measure is: define only ___ntohl as a macro instead,
- * and in a separate file, have
- * unsigned long inline ntohl(x){return ___ntohl(x);}
- *
- * The same for constant arguments
- *	__constant_ntohl(__u32 x)
- *	__constant_ntohs(__u16 x)
- *	__constant_htonl(__u32 x)
- *	__constant_htons(__u16 x)
- *
- * Conversion of XX-bit integers (16- 32- or 64-)
- * between native CPU format and little/big endian format
- * 64-bit stuff only defined for proper architectures
- *	cpu_to_[bl]eXX(__uXX x)
- *	[bl]eXX_to_cpu(__uXX x)
- *
- * The same, but takes a pointer to the value to convert
- *	cpu_to_[bl]eXXp(__uXX x)
- *	[bl]eXX_to_cpup(__uXX x)
- *
- * The same, but change in situ
- *	cpu_to_[bl]eXXs(__uXX x)
- *	[bl]eXX_to_cpus(__uXX x)
- *
- * See asm-foo/byteorder.h for examples of how to provide
- * architecture-optimized versions
- *
- */
-
-
-/*
- * inside the kernel, we can use nicknames;
- * outside of it, we must avoid POSIX namespace pollution...
- */
-#define cpu_to_le64 __cpu_to_le64
-#define le64_to_cpu __le64_to_cpu
-#define cpu_to_le32 __cpu_to_le32
-#define le32_to_cpu __le32_to_cpu
-#define cpu_to_le16 __cpu_to_le16
-#define le16_to_cpu __le16_to_cpu
-#define cpu_to_be64 __cpu_to_be64
-#define be64_to_cpu __be64_to_cpu
-#define cpu_to_be32 __cpu_to_be32
-#define be32_to_cpu __be32_to_cpu
-#define cpu_to_be16 __cpu_to_be16
-#define be16_to_cpu __be16_to_cpu
-#define cpu_to_le64p __cpu_to_le64p
-#define le64_to_cpup __le64_to_cpup
-#define cpu_to_le32p __cpu_to_le32p
-#define le32_to_cpup __le32_to_cpup
-#define cpu_to_le16p __cpu_to_le16p
-#define le16_to_cpup __le16_to_cpup
-#define cpu_to_be64p __cpu_to_be64p
-#define be64_to_cpup __be64_to_cpup
-#define cpu_to_be32p __cpu_to_be32p
-#define be32_to_cpup __be32_to_cpup
-#define cpu_to_be16p __cpu_to_be16p
-#define be16_to_cpup __be16_to_cpup
-#define cpu_to_le64s __cpu_to_le64s
-#define le64_to_cpus __le64_to_cpus
-#define cpu_to_le32s __cpu_to_le32s
-#define le32_to_cpus __le32_to_cpus
-#define cpu_to_le16s __cpu_to_le16s
-#define le16_to_cpus __le16_to_cpus
-#define cpu_to_be64s __cpu_to_be64s
-#define be64_to_cpus __be64_to_cpus
-#define cpu_to_be32s __cpu_to_be32s
-#define be32_to_cpus __be32_to_cpus
-#define cpu_to_be16s __cpu_to_be16s
-#define be16_to_cpus __be16_to_cpus
-
-
-/*
- * Handle ntohl and suches. These have various compatibility
- * issues - like we want to give the prototype even though we
- * also have a macro for them in case some strange program
- * wants to take the address of the thing or something..
- *
- * Note that these used to return a "long" in libc5, even though
- * long is often 64-bit these days.. Thus the casts.
- *
- * They have to be macros in order to do the constant folding
- * correctly - if the argument passed into a inline function
- * it is no longer constant according to gcc..
- */
-
-#undef ntohl
-#undef ntohs
-#undef htonl
-#undef htons
-
-/*
- * Do the prototypes. Somebody might want to take the
- * address or some such sick thing..
- */
-extern __u32			ntohl(__u32);
-extern __u32			htonl(__u32);
-extern unsigned short int	ntohs(unsigned short int);
-extern unsigned short int	htons(unsigned short int);
-
-#endif /* _LINUX_BYTEORDER_GENERIC_H */
-
diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c
index cc893c0..cb9d4cf 100644
--- a/drivers/staging/rtl8712/hal_init.c
+++ b/drivers/staging/rtl8712/hal_init.c
@@ -36,7 +36,6 @@
 
 #include "osdep_service.h"
 #include "drv_types.h"
-#include "rtl871x_byteorder.h"
 #include "usb_osintf.h"
 
 #define FWBUFF_ALIGN_SZ 512
diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h
index 3c0092b..21515c3 100644
--- a/drivers/staging/rtl8712/ieee80211.h
+++ b/drivers/staging/rtl8712/ieee80211.h
@@ -705,7 +705,7 @@
 	IEEE80211_ASSOCIATING_RETRY,
 	/* the association procedure is sending AUTH request*/
 	IEEE80211_ASSOCIATING_AUTHENTICATING,
-	/* the association procedure has successfully authentcated
+	/* the association procedure has successfully authenticated
 	 * and is sending association request
 	 */
 	IEEE80211_ASSOCIATING_AUTHENTICATED,
diff --git a/drivers/staging/rtl8712/if_ether.h b/drivers/staging/rtl8712/if_ether.h
deleted file mode 100644
index 2bbe527..0000000
--- a/drivers/staging/rtl8712/if_ether.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-/*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
- *		Global definitions for the Ethernet IEEE 802.3 interface.
- *
- * Version:	@(#)if_ether.h	1.0.1a	02/08/94
- *
- * Author:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *		Donald Becker, <becker@super.org>
- *		Alan Cox, <alan@redhat.com>
- *		Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
- *
- *		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 _LINUX_IF_ETHER_H
-#define _LINUX_IF_ETHER_H
-
-/*
- *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
- *	and FCS/CRC (frame check sequence).
- */
-
-#define ETH_ALEN	6		/* Octets in one ethernet addr	 */
-#define ETH_HLEN	14		/* Total octets in header.	 */
-#define ETH_ZLEN	60		/* Min. octets in frame sans FCS */
-#define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
-#define ETH_FRAME_LEN	1514		/* Max. octets in frame sans FCS */
-
-/*
- *	These are the defined Ethernet Protocol ID's.
- */
-
-#define ETH_P_LOOP	0x0060		/* Ethernet Loopback packet	*/
-#define ETH_P_PUP	0x0200		/* Xerox PUP packet		*/
-#define ETH_P_PUPAT	0x0201		/* Xerox PUP Addr Trans packet	*/
-#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
-#define ETH_P_X25	0x0805		/* CCITT X.25			*/
-#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
-#define	ETH_P_BPQ	0x08FF		/* G8BPQ AX.25 Ethernet Packet
-					 * [ NOT AN OFFICIAL ID ] */
-#define ETH_P_IEEEPUP	0x0a00		/* Xerox IEEE802.3 PUP packet */
-#define ETH_P_IEEEPUPAT	0x0a01		/* Xerox IEEE802.3 PUP Addr
-					 * Trans packet */
-#define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
-#define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
-#define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
-#define ETH_P_DNA_RT    0x6003          /* DEC DNA Routing              */
-#define ETH_P_LAT       0x6004          /* DEC LAT                      */
-#define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
-#define ETH_P_CUST      0x6006          /* DEC Customer use             */
-#define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
-#define ETH_P_RARP      0x8035		/* Reverse Addr Res packet	*/
-#define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
-#define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
-#define ETH_P_8021Q	0x8100          /* 802.1Q VLAN Extended Header  */
-#define ETH_P_IPX	0x8137		/* IPX over DIX			*/
-#define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
-#define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
-#define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
-#define ETH_P_ATMMPOA	0x884c		/* MultiProtocol Over ATM	*/
-#define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
-					 * over Ethernet
-					 */
-
-/*
- *	Non DIX types. Won't clash for 1500 types.
- */
-
-#define ETH_P_802_3	0x0001		/* Dummy type for 802.3 frames  */
-#define ETH_P_AX25	0x0002		/* Dummy protocol id for AX.25  */
-#define ETH_P_ALL	0x0003		/* Every packet (be careful!!!) */
-#define ETH_P_802_2	0x0004		/* 802.2 frames			*/
-#define ETH_P_SNAP	0x0005		/* Internal only		*/
-#define ETH_P_DDCMP     0x0006          /* DEC DDCMP: Internal only     */
-#define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
-#define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
-#define ETH_P_LOCALTALK 0x0009		/* Localtalk pseudo type	*/
-#define ETH_P_PPPTALK	0x0010		/* Dummy type for Atalk over PPP*/
-#define ETH_P_TR_802_2	0x0011i		/* 802.2 frames			*/
-#define ETH_P_MOBITEX	0x0015		/* Mobitex (kaz@cafe.net)	*/
-#define ETH_P_CONTROL	0x0016		/* Card specific control frames */
-#define ETH_P_IRDA	0x0017		/* Linux-IrDA			*/
-#define ETH_P_ECONET	0x0018		/* Acorn Econet			*/
-
-/*
- *	This is an Ethernet frame header.
- */
-
-struct ethhdr {
-	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
-	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
-	unsigned short	h_proto;		/* packet type ID field	*/
-};
-
-struct _vlan {
-	unsigned short  h_vlan_TCI;	/* Encapsulates priority and VLAN ID*/
-	unsigned short  h_vlan_encapsulated_proto;
-};
-
-
-
-#define get_vlan_id(pvlan) ((ntohs((unsigned short)pvlan->h_vlan_TCI)) & 0xfff)
-#define get_vlan_priority(pvlan) ((ntohs((unsigned short)\
-				 pvlan->h_vlan_TCI)) >> 13)
-#define get_vlan_encap_proto(pvlan) (ntohs((unsigned short)\
-				    pvlan->h_vlan_encapsulated_proto))
-
-
-#endif	/* _LINUX_IF_ETHER_H */
-
diff --git a/drivers/staging/rtl8712/ip.h b/drivers/staging/rtl8712/ip.h
deleted file mode 100644
index f37b0f8..0000000
--- a/drivers/staging/rtl8712/ip.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
- *		Definitions for the IP protocol.
- *
- * Version:	@(#)ip.h	1.0.2	04/28/93
- *
- * Authors:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.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 Free Software Foundation; either version
- *		2 of the License, or (at your option) any later version.
- */
-#ifndef _LINUX_IP_H
-#define _LINUX_IP_H
-
-#include "rtl871x_byteorder.h"
-
-/* SOL_IP socket options */
-
-#define IPTOS_TOS_MASK		0x1E
-#define IPTOS_TOS(tos)		((tos)&IPTOS_TOS_MASK)
-#define	IPTOS_LOWDELAY		0x10
-#define	IPTOS_THROUGHPUT	0x08
-#define	IPTOS_RELIABILITY	0x04
-#define	IPTOS_MINCOST		0x02
-
-#define IPTOS_PREC_MASK		0xE0
-#define IPTOS_PREC(tos)		((tos)&IPTOS_PREC_MASK)
-#define IPTOS_PREC_NETCONTROL           0xe0
-#define IPTOS_PREC_INTERNETCONTROL      0xc0
-#define IPTOS_PREC_CRITIC_ECP           0xa0
-#define IPTOS_PREC_FLASHOVERRIDE        0x80
-#define IPTOS_PREC_FLASH                0x60
-#define IPTOS_PREC_IMMEDIATE            0x40
-#define IPTOS_PREC_PRIORITY             0x20
-#define IPTOS_PREC_ROUTINE              0x00
-
-/* IP options */
-#define IPOPT_COPY		0x80
-#define IPOPT_CLASS_MASK	0x60
-#define IPOPT_NUMBER_MASK	0x1f
-
-#define	IPOPT_COPIED(o)		((o)&IPOPT_COPY)
-#define	IPOPT_CLASS(o)		((o)&IPOPT_CLASS_MASK)
-#define	IPOPT_NUMBER(o)		((o)&IPOPT_NUMBER_MASK)
-
-#define	IPOPT_CONTROL		0x00
-#define	IPOPT_RESERVED1		0x20
-#define	IPOPT_MEASUREMENT	0x40
-#define	IPOPT_RESERVED2		0x60
-
-#define IPOPT_END	(0 | IPOPT_CONTROL)
-#define IPOPT_NOOP	(1 | IPOPT_CONTROL)
-#define IPOPT_SEC	(2 | IPOPT_CONTROL|IPOPT_COPY)
-#define IPOPT_LSRR	(3 | IPOPT_CONTROL|IPOPT_COPY)
-#define IPOPT_TIMESTAMP	(4 | IPOPT_MEASUREMENT)
-#define IPOPT_RR	(7 | IPOPT_CONTROL)
-#define IPOPT_SID	(8 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_SSRR	(9 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_RA	(20 | IPOPT_CONTROL | IPOPT_COPY)
-
-#define IPVERSION	4
-#define MAXTTL		255
-#define IPDEFTTL	64
-
-/* struct timestamp, struct route and MAX_ROUTES are removed.
- *
- * REASONS: it is clear that nobody used them because:
- * - MAX_ROUTES value was wrong.
- * - "struct route" was wrong.
- * - "struct timestamp" had fatally misaligned bitfields and was completely
- *   unusable.
- */
-
-#define IPOPT_OPTVAL 0
-#define IPOPT_OLEN   1
-#define IPOPT_OFFSET 2
-#define IPOPT_MINOFF 4
-#define MAX_IPOPTLEN 40
-#define IPOPT_NOP IPOPT_NOOP
-#define IPOPT_EOL IPOPT_END
-#define IPOPT_TS  IPOPT_TIMESTAMP
-
-#define	IPOPT_TS_TSONLY		0		/* timestamps only */
-#define	IPOPT_TS_TSANDADDR	1		/* timestamps and addresses */
-#define	IPOPT_TS_PRESPEC	3		/* specified modules only */
-
-struct ip_options {
-	__u32		faddr;			/* Saved first hop address */
-	unsigned char	optlen;
-	unsigned char srr;
-	unsigned char rr;
-	unsigned char ts;
-	unsigned char is_setbyuser:1,	/* Set by setsockopt?		      */
-		      is_data:1,	/* Options in __data, rather than skb */
-		      is_strictroute:1, /* Strict source route		      */
-		      srr_is_hit:1,	/* Packet destination addr was our one*/
-		      is_changed:1,	/* IP checksum more not valid	      */
-		      rr_needaddr:1,	/* Need to record addr of outgoing dev*/
-		      ts_needtime:1,	/* Need to record timestamp	      */
-		      ts_needaddr:1;	/* Need to record addr of outgoing dev*/
-	unsigned char router_alert;
-	unsigned char __pad1;
-	unsigned char __pad2;
-	unsigned char __data[0];
-};
-
-#define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
-
-struct iphdr {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u8	ihl:4,
-		version:4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u8	version:4,
-		ihl:4;
-#else
-#error	"Please fix <asm/byteorder.h>"
-#endif
-	__u8	tos;
-	__u16	tot_len;
-	__u16	id;
-	__u16	frag_off;
-	__u8	ttl;
-	__u8	protocol;
-	__u16	check;
-	__u32	saddr;
-	__u32	daddr;
-	/*The options start here. */
-};
-
-#endif	/* _LINUX_IP_H */
-
diff --git a/drivers/staging/rtl8712/little_endian.h b/drivers/staging/rtl8712/little_endian.h
deleted file mode 100644
index cd57d6c..0000000
--- a/drivers/staging/rtl8712/little_endian.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_LITTLE_ENDIAN_H
-#define _LINUX_BYTEORDER_LITTLE_ENDIAN_H
-
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN 1234
-#endif
-#ifndef __LITTLE_ENDIAN_BITFIELD
-#define __LITTLE_ENDIAN_BITFIELD
-#endif
-
-#include "swab.h"
-
-#define __constant_htonl(x) ___constant_swab32((x))
-#define __constant_ntohl(x) ___constant_swab32((x))
-#define __constant_htons(x) ___constant_swab16((x))
-#define __constant_ntohs(x) ___constant_swab16((x))
-#define __constant_cpu_to_le64(x) ((__u64)(x))
-#define __constant_le64_to_cpu(x) ((__u64)(x))
-#define __constant_cpu_to_le32(x) ((__u32)(x))
-#define __constant_le32_to_cpu(x) ((__u32)(x))
-#define __constant_cpu_to_le16(x) ((__u16)(x))
-#define __constant_le16_to_cpu(x) ((__u16)(x))
-#define __constant_cpu_to_be64(x) ___constant_swab64((x))
-#define __constant_be64_to_cpu(x) ___constant_swab64((x))
-#define __constant_cpu_to_be32(x) ___constant_swab32((x))
-#define __constant_be32_to_cpu(x) ___constant_swab32((x))
-#define __constant_cpu_to_be16(x) ___constant_swab16((x))
-#define __constant_be16_to_cpu(x) ___constant_swab16((x))
-#define __cpu_to_le64(x) ((__u64)(x))
-#define __le64_to_cpu(x) ((__u64)(x))
-#define __cpu_to_le32(x) ((__u32)(x))
-#define __le32_to_cpu(x) ((__u32)(x))
-#define __cpu_to_le16(x) ((__u16)(x))
-#define __le16_to_cpu(x) ((__u16)(x))
-#define __cpu_to_be64(x) __swab64((x))
-#define __be64_to_cpu(x) __swab64((x))
-#define __cpu_to_be32(x) __swab32((x))
-#define __be32_to_cpu(x) __swab32((x))
-#define __cpu_to_be16(x) __swab16((x))
-#define __be16_to_cpu(x) __swab16((x))
-#define __cpu_to_le64p(x) (*(__u64 *)(x))
-#define __le64_to_cpup(x) (*(__u64 *)(x))
-#define __cpu_to_le32p(x) (*(__u32 *)(x))
-#define __le32_to_cpup(x) (*(__u32 *)(x))
-#define __cpu_to_le16p(x) (*(__u16 *)(x))
-#define __le16_to_cpup(x) (*(__u16 *)(x))
-#define __cpu_to_be64p(x) __swab64p((x))
-#define __be64_to_cpup(x) __swab64p((x))
-#define __cpu_to_be32p(x) __swab32p((x))
-#define __be32_to_cpup(x) __swab32p((x))
-#define __cpu_to_be16p(x) __swab16p((x))
-#define __be16_to_cpup(x) __swab16p((x))
-#define __cpu_to_le64s(x) do {} while (0)
-#define __le64_to_cpus(x) do {} while (0)
-#define __cpu_to_le32s(x) do {} while (0)
-#define __le32_to_cpus(x) do {} while (0)
-#define __cpu_to_le16s(x) do {} while (0)
-#define __le16_to_cpus(x) do {} while (0)
-#define __cpu_to_be64s(x) __swab64s((x))
-#define __be64_to_cpus(x) __swab64s((x))
-#define __cpu_to_be32s(x) __swab32s((x))
-#define __be32_to_cpus(x) __swab32s((x))
-#define __cpu_to_be16s(x) __swab16s((x))
-#define __be16_to_cpus(x) __swab16s((x))
-
-#include "generic.h"
-
-#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */
-
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index 7bbd53a..448f00d 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -52,7 +52,7 @@
 static int hci = RTL8712_USB;
 static int ampdu_enable = 1;/*for enable tx_ampdu*/
 
-/* The video_mode variable is for vedio mode.*/
+/* The video_mode variable is for video mode.*/
 /* It may be specify when inserting module with video_mode=1 parameter.*/
 static int video_mode = 1;   /* enable video mode*/
 
@@ -248,7 +248,7 @@
 
 void r8712_stop_drv_threads(struct _adapter *padapter)
 {
-	/*Below is to termindate r8712_cmd_thread & event_thread...*/
+	/*Below is to terminate r8712_cmd_thread & event_thread...*/
 	up(&padapter->cmdpriv.cmd_queue_sema);
 	if (padapter->cmdThread)
 		_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema);
diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h
index 9ba6033..f1ccc7e 100644
--- a/drivers/staging/rtl8712/osdep_service.h
+++ b/drivers/staging/rtl8712/osdep_service.h
@@ -29,7 +29,6 @@
 #define _SUCCESS	1
 #define _FAIL		0
 
-#include <linux/version.h>
 #include <linux/spinlock.h>
 
 #include <linux/interrupt.h>
@@ -107,8 +106,6 @@
 	schedule_work(pwork);
 }
 
-#include "rtl871x_byteorder.h"
-
 #ifndef BIT
 	#define BIT(x)	(1 << (x))
 #endif
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c
index 9f6ebc4..088647c 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.c
+++ b/drivers/staging/rtl8712/rtl8712_cmd.c
@@ -50,7 +50,6 @@
 #include "drv_types.h"
 #include "recv_osdep.h"
 #include "mlme_osdep.h"
-#include "rtl871x_byteorder.h"
 #include "rtl871x_ioctl_set.h"
 
 static void check_hw_pbc(struct _adapter *padapter)
@@ -69,7 +68,7 @@
 		 * After trigger PBC, the variable will be set to false */
 		DBG_8712("CheckPbcGPIO - PBC is pressed !!!!\n");
 		/* 0 is the default value and it means the application monitors
-		 * the HW PBC doesn't privde its pid to driver. */
+		 * the HW PBC doesn't provide its pid to driver. */
 		if (padapter->pid == 0)
 			return;
 		kill_pid(find_vpid(padapter->pid), SIGUSR1, 1);
@@ -382,7 +381,7 @@
 			*pcmdbuf = cpu_to_le32((cmdsz & 0x0000ffff) |
 					       (pcmd->cmdcode << 16) |
 					       (pcmdpriv->cmd_seq << 24));
-			pcmdbuf += 2 ; /* 8 bytes aligment */
+			pcmdbuf += 2 ; /* 8 bytes alignment */
 			memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
 			while (check_cmd_fifo(padapter, wr_sz) == _FAIL) {
 				if ((padapter->bDriverStopped == true) ||
@@ -471,7 +470,7 @@
 	pevt_priv->event_seq++;	/* update evt_seq */
 	if (pevt_priv->event_seq > 127)
 		pevt_priv->event_seq = 0;
-	peventbuf = peventbuf + 2; /* move to event content, 8 bytes aligment */
+	peventbuf = peventbuf + 2; /* move to event content, 8 bytes alignment */
 	if (peventbuf) {
 		event_callback = wlanevents[evt_code].event_callback;
 		if (event_callback)
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h
index 766a646..039ab3e 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.h
+++ b/drivers/staging/rtl8712/rtl8712_cmd.h
@@ -121,7 +121,7 @@
 	GEN_CMD_CODE(_GetCurDataRate) ,
 
 	GEN_CMD_CODE(_GetTxRetrycnt),  /* to record times that Tx retry to
-					* transmmit packet after association
+					* transmit packet after association
 					*/
 	GEN_CMD_CODE(_GetRxRetrycnt),  /* to record total number of the
 					* received frame with ReTry bit set in
diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c
index b08e9a2..377fca9 100644
--- a/drivers/staging/rtl8712/rtl8712_efuse.c
+++ b/drivers/staging/rtl8712/rtl8712_efuse.c
@@ -417,7 +417,7 @@
 		} else { /* write header fail */
 			bResult = false;
 			if (0xFF == efuse_data)
-				return bResult; /* not thing damaged. */
+				return bResult; /* nothing damaged. */
 			/* call rescue procedure */
 			if (fix_header(padapter, efuse_data, efuse_addr) ==
 			    false)
diff --git a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
index 884a821..138ea45 100644
--- a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
@@ -70,7 +70,7 @@
 #define		GPIOSEL_BT	2	/* BT_coex*/
 #define		GPIOSEL_WLANDBG	3	/* WLANDBG*/
 #define		GPIOSEL_GPIO_MASK	(~(BIT(0)|BIT(1)))
-/* HW Readio OFF switch (GPIO BIT) */
+/* HW Radio OFF switch (GPIO BIT) */
 #define		HAL_8192S_HW_GPIO_OFF_BIT	BIT(3)
 #define		HAL_8192S_HW_GPIO_OFF_MASK	0xF7
 #define		HAL_8192S_HW_GPIO_WPS_BIT	BIT(4)
diff --git a/drivers/staging/rtl8712/rtl8712_hal.h b/drivers/staging/rtl8712/rtl8712_hal.h
index d19865a..4c51fa3 100644
--- a/drivers/staging/rtl8712/rtl8712_hal.h
+++ b/drivers/staging/rtl8712/rtl8712_hal.h
@@ -83,7 +83,7 @@
 	unsigned char rfintfs;    /* 0:SWSI, 1:HWSI, 2:HWPI*/
 	unsigned char def_nettype;
 	unsigned char turboMode;
-	unsigned char lowPowerMode;/* 0: noral mode, 1: low power mode*/
+	unsigned char lowPowerMode;/* 0: normal mode, 1: low power mode*/
 	/*--- long word 2 ----*/
 	unsigned char lbk_mode; /*0x00: normal, 0x03: MACLBK, 0x01: PHYLBK*/
 	unsigned char mp_mode; /* 1: for MP use, 0: for normal driver */
@@ -123,7 +123,7 @@
 	unsigned char rsvd053;
 };
 
-struct fw_hdr {/*8-byte alinment required*/
+struct fw_hdr {/*8-byte alignment required*/
 	unsigned short	signature;
 	unsigned short	version;	/*0x8000 ~ 0x8FFF for FPGA version,
 					 *0x0000 ~ 0x7FFF for ASIC version,*/
diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c
index bac56e5..c9eb4b7 100644
--- a/drivers/staging/rtl8712/rtl8712_led.c
+++ b/drivers/staging/rtl8712/rtl8712_led.c
@@ -60,7 +60,7 @@
 			     * the # of times to blink is depend on time
 			     * for scanning. */
 	LED_NO_LINK_BLINK = 7, /* LED is blinking during no link state. */
-	LED_BLINK_StartToBlink = 8,/* Customzied for Sercomm Printer
+	LED_BLINK_StartToBlink = 8,/* Customized for Sercomm Printer
 				    * Server case */
 	LED_BLINK_WPS = 9,	/* LED is blinkg during WPS communication */
 	LED_TXRX_BLINK = 10,
@@ -826,7 +826,7 @@
 {
 	struct LED_871x  *pLed = (struct LED_871x *)data;
 
-	/* This fixed the crash problem on Fedora 12 when trying to do thei
+	/* This fixed the crash problem on Fedora 12 when trying to do the
 	 * insmod;ifconfig up;rmmod commands. */
 	if ((pLed->padapter->bSurpriseRemoved == true) ||
 	    (pLed->padapter->bDriverStopped == true))
@@ -836,7 +836,7 @@
 
 /*	Description:
  *		Callback function of LED BlinkWorkItem.
- *		We dispatch acture LED blink action according to LedStrategy.
+ *		We dispatch actual LED blink action according to LedStrategy.
  */
 static void BlinkWorkItemCallback(struct work_struct *work)
 {
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index fa6dc9c..8e82ce2 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -28,12 +28,13 @@
 
 #define _RTL8712_RECV_C_
 
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+
 #include "osdep_service.h"
 #include "drv_types.h"
 #include "recv_osdep.h"
 #include "mlme_osdep.h"
-#include "ip.h"
-#include "if_ether.h"
 #include "ethernet.h"
 #include "usb_ops.h"
 #include "wifi.h"
@@ -459,7 +460,7 @@
 		cmd_seq = (u8)((le32_to_cpu(voffset) >> 24) & 0x7f);
 		eid = (u8)((le32_to_cpu(voffset) >> 16) & 0xff);
 		r8712_event_handle(padapter, (uint *)poffset);
-		poffset += (cmd_len + 8);/*8 bytes aligment*/
+		poffset += (cmd_len + 8);/*8 bytes alignment*/
 	} while (le32_to_cpu(voffset) & BIT(31));
 
 }
@@ -603,7 +604,7 @@
 		}
 	}
 	spin_lock_irqsave(&ppending_recvframe_queue->lock, irql);
-	/*s2. check if winstart_b(indicate_seq) needs to been updated*/
+	/*s2. check if winstart_b(indicate_seq) needs to be updated*/
 	if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num))
 		goto _err_exit;
 	/*s3. Insert all packet into Reorder Queue to maintain its ordering.*/
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index 6933319..3d23514 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -30,7 +30,6 @@
 
 #include "osdep_service.h"
 #include "drv_types.h"
-#include "rtl871x_byteorder.h"
 #include "wifi.h"
 #include "osdep_intf.h"
 #include "usb_ops.h"
diff --git a/drivers/staging/rtl8712/rtl871x_byteorder.h b/drivers/staging/rtl8712/rtl871x_byteorder.h
deleted file mode 100644
index bd3703b..0000000
--- a/drivers/staging/rtl8712/rtl871x_byteorder.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
- ******************************************************************************/
-#ifndef _RTL871X_BYTEORDER_H_
-#define _RTL871X_BYTEORDER_H_
-
-#if defined(__LITTLE_ENDIAN)
-#  include "little_endian.h"
-#elif defined(__BIG_ENDIAN)
-#  include "big_endian.h"
-#else
-#  error "Must be LITTLE/BIG Endian Host"
-#endif
-
-#endif /* _RTL871X_BYTEORDER_H_ */
-
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c
index d77388b..659683e 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.c
+++ b/drivers/staging/rtl8712/rtl871x_cmd.c
@@ -50,7 +50,6 @@
 #include "drv_types.h"
 #include "recv_osdep.h"
 #include "mlme_osdep.h"
-#include "rtl871x_byteorder.h"
 
 /*
 Caller and the r8712_cmd_thread can protect cmd_q by spin_lock.
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h
index 757ebf7..9d93189 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.h
+++ b/drivers/staging/rtl8712/rtl871x_cmd.h
@@ -720,7 +720,7 @@
  * Result:
  * 0x00: success
  * 0x01: success, and check Response.
- * 0x02: cmd ignored due to duplicated sequcne number
+ * 0x02: cmd ignored due to duplicated sequence number
  * 0x03: cmd dropped due to invalid cmd code
  * 0x04: reserved.
  */
diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h
index d3d8727..dc23395 100644
--- a/drivers/staging/rtl8712/rtl871x_io.h
+++ b/drivers/staging/rtl8712/rtl871x_io.h
@@ -117,7 +117,7 @@
 	u32	command;
 	u32	status;
 	u8	*pbuf;
-	void (*_async_io_callback)(struct _adapter *padater,
+	void (*_async_io_callback)(struct _adapter *padapter,
 				   struct io_req *pio_req, u8 *cnxt);
 	u8 *cnxt;
 };
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index ef35bc29..35e781f 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -43,7 +43,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/io.h>
 #include <linux/semaphore.h>
 #include <net/iw_handler.h>
@@ -242,7 +241,7 @@
 	/* Add frequency/channel */
 	iwe.cmd = SIOCGIWFREQ;
 	{
-		/*  check legel index */
+		/*  check legal index */
 		u8 dsconfig = pnetwork->network.Configuration.DSConfig;
 		if (dsconfig >= 1 && dsconfig <= sizeof(
 		    ieee80211_wlan_frequencies) / sizeof(long))
@@ -810,11 +809,11 @@
 
 /*
 	There are the BSSID information in the bssid.sa_data array.
-	If cmd is IW_PMKSA_FLUSH, it means the wpa_suppplicant wants to clear
-	 all the PMKID information. If cmd is IW_PMKSA_ADD, it means the
-	  wpa_supplicant wants to add a PMKID/BSSID to driver.
+	If cmd is IW_PMKSA_FLUSH, it means the wpa_supplicant wants to clear
+	all the PMKID information. If cmd is IW_PMKSA_ADD, it means the
+	wpa_supplicant wants to add a PMKID/BSSID to driver.
 	If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to
-	  remove a PMKID/BSSID from driver.
+	remove a PMKID/BSSID from driver.
 */
 	if (pPMK == NULL)
 		return -EINVAL;
@@ -924,7 +923,7 @@
 	range->max_qual.noise = 100;
 	range->max_qual.updated = 7; /* Updated all three */
 	range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
-	/* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+	/* TODO: Find real 'good' to 'bad' threshold value for RSSI */
 	range->avg_qual.level = 20 + -98;
 	range->avg_qual.noise = 0;
 	range->avg_qual.updated = 7; /* Updated all three */
@@ -1071,7 +1070,7 @@
  * MAC# of a preferred Access Point.
  * Currently, the request comes via Wireless Extensions' SIOCSIWAP ioctl.
  *
- * For this operation to succeed, there is no need for the interface to be Up.
+ * For this operation to succeed, there is no need for the interface to be up.
  *
  */
 static int r8711_wx_set_wap(struct net_device *dev,
@@ -2389,10 +2388,10 @@
 
 struct iw_handler_def r871x_handlers_def = {
 	.standard = r8711_handlers,
-	.num_standard = sizeof(r8711_handlers) / sizeof(iw_handler),
+	.num_standard = ARRAY_SIZE(r8711_handlers),
 	.private = r8711_private_handler,
 	.private_args = (struct iw_priv_args *)r8711_private_args,
-	.num_private = sizeof(r8711_private_handler) / sizeof(iw_handler),
+	.num_private = ARRAY_SIZE(r8711_private_handler),
 	.num_private_args = sizeof(r8711_private_args) /
 			    sizeof(struct iw_priv_args),
 	.get_wireless_stats = r871x_get_wireless_stats
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
index fb29b42..f352b32 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_set.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
@@ -264,7 +264,7 @@
 		    (*pold_state == Ndis802_11Infrastructure) ||
 		    (*pold_state == Ndis802_11IBSS)) {
 			/* will clr Linked_state before this function,
-			 * we must have chked whether issue dis-assoc_cmd or
+			 * we must have checked whether issue dis-assoc_cmd or
 			 * not */
 			r8712_ind_disconnect(padapter);
 		}
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index 4277d03..dc7adc1 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -137,7 +137,7 @@
 
 /*
 	return the wlan_network with the matching addr
-	Shall be calle under atomic context...
+	Shall be called under atomic context...
 	to avoid possible racing condition...
 */
 static struct wlan_network *_r8712_find_network(struct  __queue *scanned_queue,
@@ -255,7 +255,7 @@
 /*
 	return the wlan_network with the matching addr
 
-	Shall be calle under atomic context...
+	Shall be called under atomic context...
 	to avoid possible racing condition...
 */
 static struct wlan_network *r8712_find_network(struct  __queue *scanned_queue,
@@ -1037,7 +1037,7 @@
  *	 and the WiFi client will drop the data with seq number 0.
  *	So, the 8712 firmware has to inform driver with receiving the
  *	 ADDBA-Req frame so that the driver can reset the
- *	sequence value of Rx reorder contorl.
+ *	sequence value of Rx reorder control.
  */
 void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf)
 {
@@ -1775,7 +1775,7 @@
 		phtpriv->rx_ampdu_maxlen = max_ampdu_sz;
 	}
 	/* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info
-	 * if A-MPDU Rx is enabled, reseting rx_ordering_ctrl
+	 * if A-MPDU Rx is enabled, resetting rx_ordering_ctrl
 	 * wstart_b(indicate_seq) to default value=0xffff
 	 * todo: check if AP can send A-MPDU packets
 	 */
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h
index 71ca013..42bd0bf 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.h
+++ b/drivers/staging/rtl8712/rtl871x_mlme.h
@@ -69,8 +69,8 @@
 like ISR/Call-Back functions, the OID handlers, and even timer functions.
 Each _queue has its own locks, already.
 Other items are protected by mlme_priv.lock.
-To avoid possible dead lock, any thread trying to modifiying mlme_priv
-SHALL not lock up more than one locks at a time!
+To avoid possible dead lock, any thread trying to modify mlme_priv
+SHALL not lock up more than one lock at a time!
 */
 
 #define traffic_threshold	10
@@ -132,7 +132,7 @@
  * therefore set it to be the critical section...
  *
  * ### NOTE:#### (!!!!)
- * TAKE CARE THAT BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock
+ * TAKE CARE BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock
  */
 static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state)
 {
diff --git a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
index 23532a7..8e25862 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
+++ b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
@@ -184,7 +184,7 @@
 
 /*RxIQ DC offset, Rx digital filter, DC notch filter */
 #define	rOFDM0_XARxAFE			0xc10
-#define	rOFDM0_XARxIQImbalance		0xc14  /* RxIQ imblance matrix */
+#define	rOFDM0_XARxIQImbalance		0xc14  /* RxIQ imbalance matrix */
 #define	rOFDM0_XBRxAFE			0xc18
 #define	rOFDM0_XBRxIQImbalance		0xc1c
 #define	rOFDM0_XCRxAFE			0xc20
@@ -603,7 +603,7 @@
 #define	bCCKRxIG		0x7f00
 #define	bCCKLNAPolarity		0x800000
 #define	bCCKRx1stGain		0x7f0000
-#define	bCCKRFExtend		0x20000000 /* CCK Rx Iinital gain polarity */
+#define	bCCKRFExtend		0x20000000 /* CCK Rx inital gain polarity */
 #define	bCCKRxAGCSatLevel	0x1f000000
 #define	bCCKRxAGCSatCount       0xe0
 #define	bCCKRxRFSettle          0x1f       /* AGCsamp_dly */
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index 5b03b40..c9d1743 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -28,15 +28,15 @@
 
 #define _RTL871X_RECV_C_
 
+#include <linux/ip.h>
 #include <linux/slab.h>
+#include <linux/if_ether.h>
 #include <linux/kmemleak.h>
 
 #include "osdep_service.h"
 #include "drv_types.h"
 #include "recv_osdep.h"
 #include "mlme_osdep.h"
-#include "ip.h"
-#include "if_ether.h"
 #include "ethernet.h"
 #include "usb_ops.h"
 #include "wifi.h"
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index aa57e77..78f570b 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -30,7 +30,6 @@
 
 #include "osdep_service.h"
 #include "drv_types.h"
-#include "rtl871x_byteorder.h"
 #include "wifi.h"
 #include "osdep_intf.h"
 #include "usb_ops.h"
@@ -72,7 +71,7 @@
 	memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv));
 	spin_lock_init(&pxmitpriv->lock);
 	/*
-	Please insert all the queue initializaiton using _init_queue below
+	Please insert all the queue initialization using _init_queue below
 	*/
 	pxmitpriv->adapter = padapter;
 	_init_queue(&pxmitpriv->be_pending);
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h
index 638b79b..ee90698 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.h
+++ b/drivers/staging/rtl8712/rtl871x_xmit.h
@@ -119,7 +119,7 @@
 
 	u8	priority;
 	u8	encrypt;	/* when 0 indicate no encrypt. when non-zero,
-				 * indicate the encrypt algorith*/
+				 * indicate the encrypt algorithm*/
 	u8	iv_len;
 	u8	icv_len;
 	unsigned char iv[8];
diff --git a/drivers/staging/rtl8712/swab.h b/drivers/staging/rtl8712/swab.h
deleted file mode 100644
index f1278182..0000000
--- a/drivers/staging/rtl8712/swab.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_SWAB_H
-#define _LINUX_BYTEORDER_SWAB_H
-
-#ifndef __u16
- #define __u16 unsigned short
-#endif
-
-#ifndef __u32
- #define __u32 unsigned int
-#endif
-
-#ifndef __u8
- #define __u8 unsigned char
-#endif
-
-#ifndef __u64
- #define __u64 unsigned long long
-#endif
-
-
-static inline __u16  ___swab16(__u16 x)
-{
-	__u16 __x = x;
-	return (__u16)(
-		(((__u16)(__x) & (__u16)0x00ffU) << 8) |
-		(((__u16)(__x) & (__u16)0xff00U) >> 8));
-
-}
-
-static inline __u32  ___swab32(__u32 x)
-{
-	__u32 __x = (x);
-	return (__u32)(
-		(((__u32)(__x) & (__u32)0x000000ffUL) << 24) |
-		(((__u32)(__x) & (__u32)0x0000ff00UL) <<  8) |
-		(((__u32)(__x) & (__u32)0x00ff0000UL) >>  8) |
-		(((__u32)(__x) & (__u32)0xff000000UL) >> 24));
-}
-
-static inline __u64  ___swab64(__u64 x)
-{
-	__u64 __x = (x);
-
-	return (__u64)( \
-		(__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \
-		(__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \
-		(__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \
-		(__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) <<  8) | \
-		(__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >>  8) | \
-		(__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
-		(__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \
-		(__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56));
-}
-
-#ifndef __arch__swab16
-static inline __u16 __arch__swab16(__u16 x)
-{
-	return ___swab16(x);
-}
-
-#endif
-
-#ifndef __arch__swab32
-static inline __u32 __arch__swab32(__u32 x)
-{
-	__u32 __tmp = (x) ;
-	return ___swab32(__tmp);
-}
-#endif
-
-#ifndef __arch__swab64
-
-static inline __u64 __arch__swab64(__u64 x)
-{
-	__u64 __tmp = (x) ;
-	return ___swab64(__tmp);
-}
-
-
-#endif
-
-#define __swab16(x) __fswab16(x)
-#define __swab32(x) __fswab32(x)
-#define __swab64(x) __fswab64(x)
-
-static inline const __u16 __fswab16(__u16 x)
-{
-	return __arch__swab16(x);
-}
-static inline const __u32 __fswab32(__u32 x)
-{
-	return __arch__swab32(x);
-}
-
-#define swab16 __swab16
-#define swab32 __swab32
-#define swab64 __swab64
-#define swab16p __swab16p
-#define swab32p __swab32p
-#define swab64p __swab64p
-#define swab16s __swab16s
-#define swab32s __swab32s
-#define swab64s __swab64s
-
-#endif /* _LINUX_BYTEORDER_SWAB_H */
-
diff --git a/drivers/staging/rtl8712/usb_halinit.c b/drivers/staging/rtl8712/usb_halinit.c
index 46287c1..b4ae11a 100644
--- a/drivers/staging/rtl8712/usb_halinit.c
+++ b/drivers/staging/rtl8712/usb_halinit.c
@@ -141,7 +141,7 @@
 		/* Enable AFE PLL Macro Block */
 		val8 = r8712_read8(padapter, AFE_PLL_CTRL);
 		r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
-		/* Attatch AFE PLL to MACTOP/BB/PCIe Digital */
+		/* Attach AFE PLL to MACTOP/BB/PCIe Digital */
 		val8 = r8712_read8(padapter, SYS_ISO_CTRL);
 		r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
 		/* Switch to 40M clock */
@@ -234,7 +234,7 @@
 		udelay(500);
 		r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
 		udelay(500);
-		/* Attatch AFE PLL to MACTOP/BB/PCIe Digital */
+		/* Attach AFE PLL to MACTOP/BB/PCIe Digital */
 		val8 = r8712_read8(padapter, SYS_ISO_CTRL);
 		r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
 		/* Switch to 40M clock */
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index e419b4f..9bd18e2 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -621,30 +621,28 @@
 	struct usb_device *udev = interface_to_usbdev(pusb_intf);
 
 	usb_set_intfdata(pusb_intf, NULL);
-	if (padapter) {
-		if (padapter->fw_found)
-			release_firmware(padapter->fw);
-		/* never exit with a firmware callback pending */
-		wait_for_completion(&padapter->rtl8712_fw_ready);
-		if (drvpriv.drv_registered == true)
-			padapter->bSurpriseRemoved = true;
-		if (pnetdev != NULL) {
-			/* will call netdev_close() */
-			unregister_netdev(pnetdev);
-		}
-		flush_scheduled_work();
-		udelay(1);
-		/*Stop driver mlme relation timer */
-		if (padapter->fw_found)
-			r8712_stop_drv_timers(padapter);
-		r871x_dev_unload(padapter);
-		r8712_free_drv_sw(padapter);
+	if (padapter->fw_found)
+		release_firmware(padapter->fw);
+	/* never exit with a firmware callback pending */
+	wait_for_completion(&padapter->rtl8712_fw_ready);
+	if (drvpriv.drv_registered == true)
+		padapter->bSurpriseRemoved = true;
+	if (pnetdev != NULL) {
+		/* will call netdev_close() */
+		unregister_netdev(pnetdev);
 	}
+	flush_scheduled_work();
+	udelay(1);
+	/*Stop driver mlme relation timer */
+	if (padapter->fw_found)
+		r8712_stop_drv_timers(padapter);
+	r871x_dev_unload(padapter);
+	r8712_free_drv_sw(padapter);
 	usb_set_intfdata(pusb_intf, NULL);
 	/* decrease the reference count of the usb device structure
 	 * when disconnect */
 	usb_put_dev(udev);
-	/* If we didn't unplug usb dongle and remove/insert modlue, driver
+	/* If we didn't unplug usb dongle and remove/insert module, driver
 	 * fails on sitesurvey for the first time when device is up.
 	 * Reset usb port for sitesurvey fail issue. */
 	if (udev->state != USB_STATE_NOTATTACHED)
diff --git a/drivers/staging/rtl8712/usb_ops.c b/drivers/staging/rtl8712/usb_ops.c
index 5a8b0eb..c03508d 100644
--- a/drivers/staging/rtl8712/usb_ops.c
+++ b/drivers/staging/rtl8712/usb_ops.c
@@ -33,7 +33,6 @@
 #include "osdep_intf.h"
 #include "usb_ops.h"
 #include "recv_osdep.h"
-#include "rtl871x_byteorder.h"
 
 static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
 {
diff --git a/drivers/staging/rtl8712/wifi.h b/drivers/staging/rtl8712/wifi.h
index 277398c..793443e 100644
--- a/drivers/staging/rtl8712/wifi.h
+++ b/drivers/staging/rtl8712/wifi.h
@@ -26,7 +26,6 @@
 #ifndef _WIFI_H_
 #define _WIFI_H_
 
-#include "rtl871x_byteorder.h"
 #include <linux/compiler.h>
 
 #ifdef BIT
diff --git a/drivers/staging/rtl8712/xmit_linux.c b/drivers/staging/rtl8712/xmit_linux.c
index c970362..65542cb 100644
--- a/drivers/staging/rtl8712/xmit_linux.c
+++ b/drivers/staging/rtl8712/xmit_linux.c
@@ -29,14 +29,12 @@
 #define _XMIT_OSDEP_C_
 
 #include <linux/usb.h>
+#include <linux/ip.h>
+#include <linux/if_ether.h>
 
 #include "osdep_service.h"
 #include "drv_types.h"
 
-
-#include "if_ether.h"
-#include "ip.h"
-#include "rtl871x_byteorder.h"
 #include "wifi.h"
 #include "mlme_osdep.h"
 #include "xmit_osdep.h"
diff --git a/drivers/staging/rts5139/ms.c b/drivers/staging/rts5139/ms.c
index b0e9071..6eef33b 100644
--- a/drivers/staging/rts5139/ms.c
+++ b/drivers/staging/rts5139/ms.c
@@ -2680,7 +2680,7 @@
 	return STATUS_SUCCESS;
 }
 
-void mspro_stop_seq_mode(struct rts51x_chip *chip)
+static void mspro_stop_seq_mode(struct rts51x_chip *chip)
 {
 	struct ms_info *ms_card = &(chip->ms_card);
 	int retval;
@@ -3149,7 +3149,7 @@
 		TRACE_RET(chip, STATUS_FAIL);
 
 	sec_cnt = chip->rsp_buf[0];
-	RTS51X_DEBUGP("%d pages need be trasferred, %d pages remained\n",
+	RTS51X_DEBUGP("%d pages need be transferred, %d pages remained\n",
 		       (int)page_cnt, (int)sec_cnt);
 	page_addr = start_page + (page_cnt - sec_cnt);
 
@@ -3864,7 +3864,7 @@
 	log_blk = (u16) (start_sector >> ms_card->block_shift);
 	start_page = (u8) (start_sector & ms_card->page_off);
 
-	for (seg_no = 0; seg_no < sizeof(ms_start_idx) / 2; seg_no++) {
+	for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; seg_no++) {
 		if (log_blk < ms_start_idx[seg_no + 1])
 			break;
 	}
@@ -4020,7 +4020,8 @@
 
 		log_blk++;
 
-		for (seg_no = 0; seg_no < sizeof(ms_start_idx) / 2; seg_no++) {
+		for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1;
+				seg_no++) {
 			if (log_blk < ms_start_idx[seg_no + 1])
 				break;
 		}
@@ -4134,7 +4135,7 @@
 	}
 }
 
-int ms_power_off_card3v3(struct rts51x_chip *chip)
+static int ms_power_off_card3v3(struct rts51x_chip *chip)
 {
 	int retval;
 
diff --git a/drivers/staging/rts5139/ms.h b/drivers/staging/rts5139/ms.h
index 3ce1dc9..0321d06 100644
--- a/drivers/staging/rts5139/ms.h
+++ b/drivers/staging/rts5139/ms.h
@@ -234,7 +234,6 @@
 void mspro_polling_format_status(struct rts51x_chip *chip);
 void mspro_format_sense(struct rts51x_chip *chip, unsigned int lun);
 
-void mspro_stop_seq_mode(struct rts51x_chip *chip);
 int reset_ms_card(struct rts51x_chip *chip);
 int ms_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
 	  u16 sector_cnt);
@@ -242,7 +241,6 @@
 		 int short_data_len, int quick_format);
 void ms_free_l2p_tbl(struct rts51x_chip *chip);
 void ms_cleanup_work(struct rts51x_chip *chip);
-int ms_power_off_card3v3(struct rts51x_chip *chip);
 int release_ms_card(struct rts51x_chip *chip);
 int ms_delay_write(struct rts51x_chip *chip);
 
diff --git a/drivers/staging/rts5139/ms_mg.c b/drivers/staging/rts5139/ms_mg.c
index 154b523..057d96c 100644
--- a/drivers/staging/rts5139/ms_mg.c
+++ b/drivers/staging/rts5139/ms_mg.c
@@ -38,7 +38,7 @@
 
 #ifdef SUPPORT_MAGIC_GATE
 
-int mg_check_int_error(struct rts51x_chip *chip)
+static int mg_check_int_error(struct rts51x_chip *chip)
 {
 	u8 value;
 
@@ -444,7 +444,7 @@
   *
   * Since the extra 4 bytes data is just only a prefix to original data
   * that read from medium, so that the 4-byte data pushed into Ring buffer
-  * precedes data tramsinssion from medium to Ring buffer by DMA mechanisim
+  * precedes data transmission from medium to Ring buffer by DMA mechanism
   * in order to get maximum performance and minimum code size simultaneously.
   */
 int mg_get_ICV(struct scsi_cmnd *srb, struct rts51x_chip *chip)
diff --git a/drivers/staging/rts5139/rts51x.c b/drivers/staging/rts5139/rts51x.c
index 2b9f785..c3fe7dd 100644
--- a/drivers/staging/rts5139/rts51x.c
+++ b/drivers/staging/rts5139/rts51x.c
@@ -56,12 +56,6 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRIVER_VERSION);
 
-#ifdef SCSI_SCAN_DELAY
-static unsigned int delay_use = 5;
-module_param(delay_use, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
-#endif
-
 static int auto_delink_en;
 module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
@@ -114,7 +108,7 @@
 	usb_autopm_get_interface(intf);
 }
 
-void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
+static void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
 {
 	RTS51X_DEBUGP("Ready to enter SS state\n");
 	usb_autopm_enable(chip->usb->pusb_intf);
@@ -207,7 +201,7 @@
 
 #else /* CONFIG_PM */
 
-void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
+static void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
 {
 }
 
@@ -364,11 +358,6 @@
 {
 	struct rts51x_chip *chip = (struct rts51x_chip *)__chip;
 
-#ifdef SCSI_SCAN_DELAY
-	/* Wait until SCSI scan finished */
-	wait_timeout((delay_use + 5) * HZ);
-#endif
-
 	for (;;) {
 		wait_timeout(POLLING_INTERVAL);
 
@@ -432,38 +421,6 @@
 	return 0;
 }
 
-#ifdef SCSI_SCAN_DELAY
-/* Thread to carry out delayed SCSI-device scanning */
-static int rts51x_scan_thread(void *__chip)
-{
-	struct rts51x_chip *chip = (struct rts51x_chip *)__chip;
-
-	printk(KERN_DEBUG
-	       "rts51x: device found at %d\n", chip->usb->pusb_dev->devnum);
-
-	set_freezable();
-	/* Wait for the timeout to expire or for a disconnect */
-	if (delay_use > 0) {
-		printk(KERN_DEBUG "rts51x: waiting for device "
-		       "to settle before scanning\n");
-		wait_event_freezable_timeout(chip->usb->delay_wait,
-					     test_bit(FLIDX_DONT_SCAN,
-						      &chip->usb->dflags),
-					     delay_use * HZ);
-	}
-
-	/* If the device is still connected, perform the scanning */
-	if (!test_bit(FLIDX_DONT_SCAN, &chip->usb->dflags)) {
-		scsi_scan_host(rts51x_to_host(chip));
-		printk(KERN_DEBUG "rts51x: device scan complete\n");
-
-		/* Should we unbind if no devices were detected? */
-	}
-
-	complete_and_exit(&chip->usb->scanning_done, 0);
-}
-#endif
-
 /* Associate our private data with the USB device */
 static int associate_dev(struct rts51x_chip *chip, struct usb_interface *intf)
 {
@@ -521,7 +478,6 @@
 {
 	struct rts51x_option *option = &(chip->option);
 
-	option->led_blink_speed = 7;
 	option->mspro_formatter_enable = 1;
 
 	option->fpga_sd_sdr104_clk = CLK_100;
@@ -549,7 +505,6 @@
 
 	option->ss_en = ss_en;
 	option->ss_delay = ss_delay;
-	option->needs_remote_wakeup = needs_remote_wakeup;
 
 	option->auto_delink_en = auto_delink_en;
 
@@ -561,10 +516,7 @@
 	option->rts5129_D3318_off_enable = 0;
 	option->sd20_pad_drive = 0;
 	option->reset_or_rw_fail_set_pad_drive = 1;
-	option->rcc_fail_flag = 0;
-	option->rcc_bug_fix_en = 1;
 	option->debounce_num = 2;
-	option->polling_time = 100;
 	option->led_toggle_interval = 6;
 	option->xd_rwn_step = 0;
 	option->sd_send_status_en = 0;
@@ -737,15 +689,6 @@
 	if (rts51x->pusb_dev->state == USB_STATE_NOTATTACHED)
 		set_bit(FLIDX_DISCONNECTING, &rts51x->dflags);
 
-#ifdef SCSI_SCAN_DELAY
-	/* Prevent SCSI-scanning (if it hasn't started yet)
-	 * and wait for the SCSI-scanning thread to stop.
-	 */
-	set_bit(FLIDX_DONT_SCAN, &rts51x->dflags);
-	wake_up(&rts51x->delay_wait);
-	wait_for_completion(&rts51x->scanning_done);
-#endif
-
 	/* Removing the host will perform an orderly shutdown: caches
 	 * synchronized, disks spun down, etc.
 	 */
@@ -757,9 +700,6 @@
 	scsi_lock(host);
 	set_bit(FLIDX_DISCONNECTING, &rts51x->dflags);
 	scsi_unlock(host);
-#ifdef SCSI_SCAN_DELAY
-	wake_up(&rts51x->delay_wait);
-#endif
 }
 
 /* Second stage of disconnect processing: deallocate all resources */
@@ -818,10 +758,6 @@
 	init_completion(&rts51x->control_exit);
 	init_completion(&rts51x->polling_exit);
 	init_completion(&(rts51x->notify));
-#ifdef SCSI_SCAN_DELAY
-	init_waitqueue_head(&rts51x->delay_wait);
-	init_completion(&rts51x->scanning_done);
-#endif
 
 	chip->usb = rts51x;
 
@@ -855,22 +791,7 @@
 		printk(KERN_WARNING RTS51X_TIP "Unable to add the scsi host\n");
 		goto BadDevice;
 	}
-#ifdef SCSI_SCAN_DELAY
-	/* Start up the thread for delayed SCSI-device scanning */
-	th = kthread_create(rts51x_scan_thread, chip, RTS51X_SCAN_THREAD);
-	if (IS_ERR(th)) {
-		printk(KERN_WARNING RTS51X_TIP
-		       "Unable to start the device-scanning thread\n");
-		complete(&rts51x->scanning_done);
-		quiesce_and_remove_host(chip);
-		result = PTR_ERR(th);
-		goto BadDevice;
-	}
-
-	wake_up_process(th);
-#else
 	scsi_scan_host(rts51x_to_host(chip));
-#endif
 
 	/* Start up our polling thread */
 	th = kthread_run(rts51x_polling_thread, chip, RTS51X_POLLING_THREAD);
diff --git a/drivers/staging/rts5139/rts51x.h b/drivers/staging/rts5139/rts51x.h
index b2c5839..ecc0109 100644
--- a/drivers/staging/rts5139/rts51x.h
+++ b/drivers/staging/rts5139/rts51x.h
@@ -47,11 +47,9 @@
 #define RTS51X_DESC		"Realtek RTS5139/29 USB card reader driver"
 #define RTS51X_NAME		"rts5139"
 #define RTS51X_CTL_THREAD	"rts5139-control"
-#define RTS51X_SCAN_THREAD	"rts5139-scan"
 #define RTS51X_POLLING_THREAD	"rts5139-polling"
 
 #define POLLING_IN_THREAD
-/* #define SCSI_SCAN_DELAY */
 #define SUPPORT_FILE_OP
 
 #define wait_timeout_x(task_state, msecs)	\
@@ -66,8 +64,6 @@
 
 /* Size of the DMA-mapped I/O buffer */
 #define RTS51X_IOBUF_SIZE	1024
-/* Size of the autosense data buffer */
-#define RTS51X_SENSE_SIZE	18
 
 /* Dynamic bitflag definitions (dflags): used in set_bit() etc. */
 #define FLIDX_URB_ACTIVE	0	/* current_urb is in use    */
@@ -76,7 +72,6 @@
 #define FLIDX_DISCONNECTING	3	/* disconnect in progress   */
 #define FLIDX_RESETTING		4	/* device reset in progress */
 #define FLIDX_TIMED_OUT		5	/* SCSI midlayer timed out  */
-#define FLIDX_DONT_SCAN		6	/* don't scan (disconnect)  */
 
 struct rts51x_chip;
 
@@ -116,10 +111,6 @@
 	struct completion control_exit;	/* control thread exit     */
 	struct completion polling_exit;	/* polling thread exit     */
 	struct completion notify;	/* thread begin/end        */
-#ifdef SCSI_SCAN_DELAY
-	wait_queue_head_t delay_wait;	/* wait during scan, reset */
-	struct completion scanning_done;	/* wait for scan thread    */
-#endif
 };
 
 extern struct usb_driver rts51x_driver;
@@ -188,7 +179,6 @@
 
 /* General routines provided by the usb-storage standard core */
 #ifdef CONFIG_PM
-void rts51x_try_to_enter_ss(struct rts51x_chip *chip);
 void rts51x_try_to_exit_ss(struct rts51x_chip *chip);
 int rts51x_suspend(struct usb_interface *iface, pm_message_t message);
 int rts51x_resume(struct usb_interface *iface);
diff --git a/drivers/staging/rts5139/rts51x_card.c b/drivers/staging/rts5139/rts51x_card.c
index 424a845..4192c3b 100644
--- a/drivers/staging/rts5139/rts51x_card.c
+++ b/drivers/staging/rts5139/rts51x_card.c
@@ -37,7 +37,6 @@
 #include "rts51x_chip.h"
 #include "rts51x_card.h"
 #include "rts51x_transport.h"
-#include "rts51x_sys.h"
 #include "xd.h"
 #include "sd.h"
 #include "ms.h"
@@ -94,7 +93,7 @@
 		ms_cleanup_work(chip);
 }
 
-void do_reset_xd_card(struct rts51x_chip *chip)
+static void do_reset_xd_card(struct rts51x_chip *chip)
 {
 	int retval;
 
@@ -148,7 +147,7 @@
 	}
 }
 
-void do_reset_ms_card(struct rts51x_chip *chip)
+static void do_reset_ms_card(struct rts51x_chip *chip)
 {
 	int retval;
 
@@ -175,7 +174,7 @@
 	}
 }
 
-void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
+static void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
 		      u8 *need_release)
 {
 	int retval;
@@ -191,7 +190,6 @@
 		goto Exit_Debounce;
 
 	if (chip->card_exist) {
-		rts51x_clear_start_time(chip);
 		retval = rts51x_read_register(chip, CARD_INT_PEND, &value);
 		if (retval != STATUS_SUCCESS) {
 			rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH,
@@ -214,17 +212,11 @@
 		}
 	} else {
 		if (chip->card_status & XD_CD) {
-			rts51x_clear_start_time(chip);
 			reset_map |= XD_CARD;
 		} else if (chip->card_status & SD_CD) {
-			rts51x_clear_start_time(chip);
 			reset_map |= SD_CARD;
 		} else if (chip->card_status & MS_CD) {
-			rts51x_clear_start_time(chip);
 			reset_map |= MS_CARD;
-		} else {
-			if (rts51x_check_start_time(chip))
-				rts51x_set_start_time(chip);
 		}
 	}
 
@@ -709,7 +701,7 @@
 	return 0;
 }
 
-int card_share_mode(struct rts51x_chip *chip, int card)
+static int card_share_mode(struct rts51x_chip *chip, int card)
 {
 	u8 value;
 
@@ -823,22 +815,6 @@
 	return STATUS_SUCCESS;
 }
 
-int disable_card_clock(struct rts51x_chip *chip, u8 card)
-{
-	u8 clk_en = 0;
-
-	if (card & XD_CARD)
-		clk_en |= XD_CLK_EN;
-	if (card & SD_CARD)
-		clk_en |= SD_CLK_EN;
-	if (card & MS_CARD)
-		clk_en |= MS_CLK_EN;
-
-	RTS51X_WRITE_REG(chip, CARD_CLK_EN, clk_en, 0);
-
-	return STATUS_SUCCESS;
-}
-
 int card_power_on(struct rts51x_chip *chip, u8 card)
 {
 	u8 mask, val1, val2;
@@ -851,16 +827,7 @@
 	if ((card == SD_CARD) || (card == XD_CARD)) {
 		RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask | LDO3318_PWR_MASK,
 				 val1 | LDO_SUSPEND);
-		/* RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
-				LDO3318_PWR_MASK, LDO_SUSPEND); */
 	}
-	/* else if(card==XD_CARD)
-	{
-		RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
-			mask|LDO3318_PWR_MASK, val1|LDO_SUSPEND);
-		//RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
-		//	LDO3318_PWR_MASK, LDO_SUSPEND);
-	} */
 	else {
 #endif
 		RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val1);
@@ -879,17 +846,6 @@
 	return STATUS_SUCCESS;
 }
 
-int card_power_off(struct rts51x_chip *chip, u8 card)
-{
-	u8 mask, val;
-
-	mask = POWER_MASK;
-	val = POWER_OFF;
-	RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val);
-
-	return STATUS_SUCCESS;
-}
-
 int monitor_card_cd(struct rts51x_chip *chip, u8 card)
 {
 	int retval;
diff --git a/drivers/staging/rts5139/rts51x_card.h b/drivers/staging/rts5139/rts51x_card.h
index ac3c1e7..c5c03cc 100644
--- a/drivers/staging/rts5139/rts51x_card.h
+++ b/drivers/staging/rts5139/rts51x_card.h
@@ -204,13 +204,7 @@
 
 /* LDO_POWER_CFG */
 #define TUNE_SD18_MASK			0x1C
-#define TUNE_SD18_1V7			0x00
 #define TUNE_SD18_1V8			(0x01 << 2)
-#define TUNE_SD18_1V9			(0x02 << 2)
-#define TUNE_SD18_2V0			(0x03 << 2)
-#define TUNE_SD18_2V7			(0x04 << 2)
-#define TUNE_SD18_2V8			(0x05 << 2)
-#define TUNE_SD18_2V9			(0x06 << 2)
 #define TUNE_SD18_3V3			(0x07 << 2)
 
 /* XD_CP_WAITTIME */
@@ -744,9 +738,7 @@
 int monitor_card_cd(struct rts51x_chip *chip, u8 card);
 
 void do_remaining_work(struct rts51x_chip *chip);
-void do_reset_xd_card(struct rts51x_chip *chip);
 void do_reset_sd_card(struct rts51x_chip *chip);
-void do_reset_ms_card(struct rts51x_chip *chip);
 void rts51x_init_cards(struct rts51x_chip *chip);
 void rts51x_release_cards(struct rts51x_chip *chip);
 int switch_ssc_clock(struct rts51x_chip *chip, int clk);
@@ -754,15 +746,12 @@
 int card_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 sec_addr,
 	    u16 sec_cnt);
 u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun);
-int card_share_mode(struct rts51x_chip *chip, int card);
 int rts51x_select_card(struct rts51x_chip *chip, int card);
 void eject_card(struct rts51x_chip *chip, unsigned int lun);
 void trans_dma_enable(enum dma_data_direction dir, struct rts51x_chip *chip,
 		      u32 byte_cnt, u8 pack_size);
 int enable_card_clock(struct rts51x_chip *chip, u8 card);
-int disable_card_clock(struct rts51x_chip *chip, u8 card);
 int card_power_on(struct rts51x_chip *chip, u8 card);
-int card_power_off(struct rts51x_chip *chip, u8 card);
 int toggle_gpio(struct rts51x_chip *chip, u8 gpio);
 int turn_on_led(struct rts51x_chip *chip, u8 gpio);
 int turn_off_led(struct rts51x_chip *chip, u8 gpio);
diff --git a/drivers/staging/rts5139/rts51x_chip.c b/drivers/staging/rts5139/rts51x_chip.c
index b3e0bb2..db88d7a 100644
--- a/drivers/staging/rts5139/rts51x_chip.c
+++ b/drivers/staging/rts5139/rts51x_chip.c
@@ -34,7 +34,6 @@
 #include "rts51x_chip.h"
 #include "rts51x_card.h"
 #include "rts51x_transport.h"
-#include "rts51x_sys.h"
 #include "xd.h"
 #include "ms.h"
 #include "sd.h"
@@ -79,20 +78,18 @@
 				      chip->option.sd20_pad_drive);
 		if (chip->rts5179)
 			rts51x_write_register(chip, CARD_PULL_CTL5, 0x03, 0x01);
-		if (!chip->option.ww_enable) {
-			if (CHECK_PKG(chip, LQFP48)) {
-				rts51x_write_register(chip, CARD_PULL_CTL3,
-						      0x80, 0x80);
-				rts51x_write_register(chip, CARD_PULL_CTL6,
-						      0xf0, 0xA0);
-			} else {
-				rts51x_write_register(chip, CARD_PULL_CTL1,
-						      0x30, 0x20);
-				rts51x_write_register(chip, CARD_PULL_CTL3,
-						      0x80, 0x80);
-				rts51x_write_register(chip, CARD_PULL_CTL6,
-						      0x0c, 0x08);
-			}
+		if (CHECK_PKG(chip, LQFP48)) {
+			rts51x_write_register(chip, CARD_PULL_CTL3,
+					      0x80, 0x80);
+			rts51x_write_register(chip, CARD_PULL_CTL6,
+					      0xf0, 0xA0);
+		} else {
+			rts51x_write_register(chip, CARD_PULL_CTL1,
+					      0x30, 0x20);
+			rts51x_write_register(chip, CARD_PULL_CTL3,
+					      0x80, 0x80);
+			rts51x_write_register(chip, CARD_PULL_CTL6,
+					      0x0c, 0x08);
 		}
 	}
 	if (chip->option.sd_ctl & SUPPORT_UHS50_MMC44) {
@@ -121,12 +118,6 @@
 
 	/* GPIO OE */
 	rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO, GPIO_OE, GPIO_OE);
-#ifdef LED_AUTO_BLINK
-	/* LED autoblink */
-	rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_AUTO_BLINK,
-		       BLINK_ENABLE | BLINK_SPEED_MASK,
-		       BLINK_ENABLE | chip->option.led_blink_speed);
-#endif
 	rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DMA1_CTL,
 		       EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL);
 
@@ -144,7 +135,6 @@
 		card_power_on(chip, SD_CARD | MS_CARD | XD_CARD);
 		wait_timeout(10);
 	}
-	rts51x_clear_start_time(chip);
 
 	return STATUS_SUCCESS;
 }
@@ -164,12 +154,6 @@
 	chip->card_ejected = 0;
 
 	chip->lun2card[0] = XD_CARD | SD_CARD | MS_CARD;
-#if 0
-	chip->option.sdr50_tx_phase = 0x01;
-	chip->option.sdr50_rx_phase = 0x05;
-	chip->option.ddr50_tx_phase = 0x09;
-	chip->option.ddr50_rx_phase = 0x06; /* add for debug */
-#endif
 #ifdef CLOSE_SSC_POWER
 	rts51x_write_register(chip, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
 	udelay(100);
@@ -178,9 +162,6 @@
 	RTS51X_SET_STAT(chip, STAT_RUN);
 
 	RTS51X_READ_REG(chip, HW_VERSION, &val);
-	if ((val & 0x0f) >= 2)
-		chip->option.rcc_bug_fix_en = 0;
-	RTS51X_DEBUGP("rcc bug fix enable:%d\n", chip->option.rcc_bug_fix_en);
 	RTS51X_DEBUGP("HW_VERSION: 0x%x\n", val);
 	if (val & FPGA_VER) {
 		chip->asic_code = 0;
@@ -237,7 +218,6 @@
 	return STATUS_SUCCESS;
 }
 
-#ifndef LED_AUTO_BLINK
 static inline void rts51x_blink_led(struct rts51x_chip *chip)
 {
 	/* Read/Write */
@@ -251,20 +231,6 @@
 		}
 	}
 }
-#endif
-
-int rts51x_check_start_time(struct rts51x_chip *chip)
-{
-	return 0;
-}
-
-void rts51x_set_start_time(struct rts51x_chip *chip)
-{
-}
-
-void rts51x_clear_start_time(struct rts51x_chip *chip)
-{
-}
 
 static void rts51x_auto_delink_cmd(struct rts51x_chip *chip)
 {
@@ -287,7 +253,6 @@
 			chip->option.delink_delay * 2) {
 		if (chip->auto_delink_counter ==
 		    chip->option.delink_delay) {
-			clear_first_install_mark(chip);
 			if (chip->card_exist) {
 				/* False card */
 				if (!chip->card_ejected) {
@@ -321,91 +286,13 @@
 }
 #else
 /* some of called funcs are not implemented, so comment it out */
-#if 0
-/* using precise time as delink time */
-static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip)
-{
-	int retvalue = 0;
-
-	retvalue = rts51x_get_card_status(chip, &chip->card_status);
-	/* get card CD status success and card CD not exist,
-	 * then check whether delink */
-	if ((retvalue == STATUS_SUCCESS)
-	    && (!(chip->card_status & (SD_CD | MS_CD | XD_CD)))) {
-		if (rts51x_count_delink_time(chip) >=
-		    chip->option.delink_delay) {
-			clear_first_install_mark(chip);
-			RTS51X_DEBUGP("No card inserted, do delink\n");
-			/* sangdy2010-05-17:disable because there is error
-			 * after SSC clock closed and card power
-			 * has been closed before */
-			/* rts51x_write_register(chip, CARD_PWR_CTL,
-					DV3318_AUTO_PWR_OFF, 0); */
-			rts51x_auto_delink_cmd(chip);
-	}
-	/* card CD exist and not ready, then do force delink */
-	if ((retvalue == STATUS_SUCCESS)
-	    && (chip->card_status & (SD_CD | MS_CD | XD_CD))) {
-		/* if card is not ejected or safely remove,
-		 * then do force delink */
-		if (!chip->card_ejected) {
-			/* sangdy2010-11-16:polling at least 2 cycles
-			 * then do force delink for card may force delink
-			 * if card is extracted and insert quickly
-			 * after ready. */
-			if (chip->auto_delink_counter > 1) {
-				if (rts51x_count_delink_time(chip) >
-				    chip->option.delink_delay * 2) {
-					RTS51X_DEBUGP("Try to do force"
-							"delink\n");
-					rts51x_auto_delink_force_cmd(chip);
-				}
-			}
-		}
-	}
-	chip->auto_delink_counter++;
-}
-#else
-static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip)
-{
-}
-#endif
-
 static void rts51x_auto_delink(struct rts51x_chip *chip)
 {
-	rts51x_auto_delink_precise_time(chip);
 }
 #endif
 
 void rts51x_polling_func(struct rts51x_chip *chip)
 {
-#ifdef SUPPORT_SD_LOCK
-	struct sd_info *sd_card = &(chip->sd_card);
-
-	if (sd_card->sd_erase_status) {
-		if (chip->card_exist & SD_CARD) {
-			u8 val;
-			rts51x_read_register(chip, SD_BUS_STAT, &val);
-			if (val & SD_DAT0_STATUS) {
-				/* Erase completed */
-				sd_card->sd_erase_status = SD_NOT_ERASE;
-				sd_card->sd_lock_notify = 1;
-
-				/* SD card should be reinited,
-				 * so we release it here. */
-				sd_cleanup_work(chip);
-				release_sd_card(chip);
-				chip->card_ready &= ~SD_CARD;
-				chip->card_exist &= ~SD_CARD;
-				chip->rw_card[chip->card2lun[SD_CARD]] = NULL;
-				clear_bit(chip->card2lun[SD_CARD],
-					  &(chip->lun_mc));
-			}
-		} else {
-			sd_card->sd_erase_status = SD_NOT_ERASE;
-		}
-	}
-#endif
 
 	rts51x_init_cards(chip);
 
@@ -431,9 +318,7 @@
 		if (!RTS51X_CHK_STAT(chip, STAT_IDLE)) {
 			RTS51X_DEBUGP("Idle state!\n");
 			RTS51X_SET_STAT(chip, STAT_IDLE);
-#ifndef LED_AUTO_BLINK
 			chip->led_toggle_counter = 0;
-#endif
 			/* Idle state, turn off LED
 			 * to reduce power consumption */
 			if (chip->option.led_always_on
@@ -467,9 +352,7 @@
 
 	switch (RTS51X_GET_STAT(chip)) {
 	case STAT_RUN:
-#ifndef LED_AUTO_BLINK
 		rts51x_blink_led(chip);
-#endif
 		do_remaining_work(chip);
 		break;
 
@@ -484,7 +367,6 @@
 		rts51x_auto_delink(chip);
 	} else {
 		chip->auto_delink_counter = 0;
-		rts51x_clear_start_time(chip);
 	}
 }
 
@@ -831,7 +713,7 @@
 	chip->cur_clk = 0;
 	chip->card_exist = 0;
 	chip->cur_card = 0;
-	if (chip->asic_code && !chip->option.ww_enable) {
+	if (chip->asic_code) {
 		if (CHECK_PKG(chip, LQFP48)) {
 			rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x00);
 			rts51x_write_register(chip, CARD_PULL_CTL6, 0xf0, 0x50);
@@ -863,16 +745,6 @@
 		rts51x_write_register(chip, CLK_DIV, CLK_CHANGE, 0x00);
 	}
 #endif
-#if 0
-	if (chip->option.ss_en && RTS51X_CHK_STAT(chip, STAT_SS)) {
-		rts51x_try_to_exit_ss(chip);
-		wait_timeout(100);
-		rts51x_init_chip(chip);
-		rts51x_init_cards(chip);
-	}
-
-	RTS51X_SET_STAT(chip, STAT_RUN);
-#endif
 }
 
 #ifdef _MSG_TRACE
@@ -1017,24 +889,6 @@
 				status[0x0F] = 0x00;
 		}
 	}
-#ifdef SUPPORT_SD_LOCK
-	/* SD Lock/Unlock */
-	if (card == SD_CARD) {
-		status[0x17] = 0x80;
-		if (sd_card->sd_erase_status)
-			status[0x17] |= 0x01; /* Under erasing */
-		if (sd_card->sd_lock_status & SD_LOCKED) {
-			status[0x17] |= 0x02; /* Locked */
-			status[0x07] |= 0x40; /* Read protected */
-		}
-		if (sd_card->sd_lock_status & SD_PWD_EXIST)
-			status[0x17] |= 0x04; /* Contain PWD */
-	} else {
-		status[0x17] = 0x00;
-	}
-
-	RTS51X_DEBUGP("status[0x17] = 0x%x\n", status[0x17]);
-#endif
 
 	/* Function 0
 	 * Support Magic Gate, CPRM and PhyRegister R/W */
@@ -1044,12 +898,6 @@
 	 * Support OC LUN status & WP LUN status */
 	status[0x1A] = 0x28;
 
-	/* Function 7 */
-#ifdef SUPPORT_SD_LOCK
-	/* Support SD Lock/Unlock */
-	status[0x1F] = 0x01;
-#endif
-
 	/* Function 2
 	 * Support OC LUN status & WP LUN status */
 	status[0x1A] = 0x28;
diff --git a/drivers/staging/rts5139/rts51x_chip.h b/drivers/staging/rts5139/rts51x_chip.h
index 13fc2a4..6d395b6 100644
--- a/drivers/staging/rts5139/rts51x_chip.h
+++ b/drivers/staging/rts5139/rts51x_chip.h
@@ -39,12 +39,7 @@
 #define SUPPORT_CPRM
 #define SUPPORT_MAGIC_GATE
 #define SUPPORT_MSXC
-/* #define LED_AUTO_BLINK */
-
-/* { wwang, 2010-07-26
- * Add support for SD lock/unlock */
-/* #define SUPPORT_SD_LOCK */
-/* } wwang, 2010-07-26 */
+#define USING_POLLING_CYCLE_DELINK
 
 #ifdef SUPPORT_MAGIC_GA
 /* Using NORMAL_WRITE instead of AUTO_WRITE to set ICVTE */
@@ -63,7 +58,6 @@
 #define SUPPORT_OCP
 
 #define MS_SPEEDUP
-/* #define XD_SPEEDUP */
 
 #define SD_XD_IO_FOLLOW_PWR
 
@@ -81,7 +75,6 @@
 
 #define MAX_ALLOWED_LUN_CNT	8
 #define CMD_BUF_LEN		1024
-#define RSP_BUF_LEN		1024
 #define POLLING_INTERVAL	50	/* 50ms */
 
 #define XD_FREE_TABLE_CNT	1200
@@ -128,8 +121,6 @@
 #endif
 
 #define STATUS_FAIL		1
-#define STATUS_READ_FAIL	2
-#define STATUS_WRITE_FAIL	3
 #define STATUS_TIMEDOUT		4
 #define STATUS_NOMEM		5
 #define STATUS_TRANS_SHORT	6
@@ -139,8 +130,6 @@
 
 #define IDLE_MAX_COUNT		10
 #define POLLING_WAIT_CNT	1
-#define DELINK_DELAY		100
-#define LED_TOGGLE_INTERVAL	6
 #define LED_GPIO		0
 
 /* package */
@@ -157,8 +146,6 @@
 #define TRANSPORT_GOOD		0
 /* Transport good, command failed */
 #define TRANSPORT_FAILED	1
-/* Command failed, no auto-sense */
-#define TRANSPORT_NO_SENSE	2
 /* Transport bad (i.e. device dead) */
 #define TRANSPORT_ERROR		3
 
@@ -195,7 +182,6 @@
 #define	SENSE_TYPE_MEDIA_INVALID_CMD_FIELD		6
 #define	SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR		7
 #define	SENSE_TYPE_MEDIA_WRITE_ERR			8
-#define SENSE_TYPE_FORMAT_IN_PROGRESS			9
 #define SENSE_TYPE_FORMAT_CMD_FAILED			10
 #ifdef SUPPORT_MAGIC_GATE
 /* COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED */
@@ -207,83 +193,27 @@
 /* WRITE ERROR */
 #define SENSE_TYPE_MG_WRITE_ERR				0x0e
 #endif
-#ifdef SUPPORT_SD_LOCK
-/* FOR Locked SD card */
-#define SENSE_TYPE_MEDIA_READ_FORBIDDEN			0x10
-#endif
 
 /*---- sense key ----*/
-#define ILI                     0x20	/* ILI bit is on                    */
-
-#define NO_SENSE                0x00	/* not exist sense key              */
-#define RECOVER_ERR             0x01	/* Target/Logical unit is recoverd  */
-#define NOT_READY               0x02	/* Logical unit is not ready        */
-#define MEDIA_ERR               0x03	/* medium/data error                */
-#define HARDWARE_ERR            0x04	/* hardware error                   */
 #define ILGAL_REQ               0x05	/* CDB/parameter/identify msg error */
-#define UNIT_ATTENTION          0x06	/* unit attention condition occur   */
-#define DAT_PRTCT               0x07	/* read/write is desable            */
-#define BLNC_CHK                0x08	/* find blank/DOF in read           */
-					/* write to unblank area            */
-#define CPY_ABRT                0x0a	/* Copy/Compare/Copy&Verify illgal  */
-#define ABRT_CMD                0x0b	/* Target make the command in error */
-#define EQUAL                   0x0c	/* Search Data end with Equal       */
-#define VLM_OVRFLW              0x0d	/* Some data are left in buffer     */
-#define MISCMP                  0x0e	/* find inequality                  */
 
 /*-----------------------------------
     SENSE_DATA
 -----------------------------------*/
-/*---- valid ----*/
-#define SENSE_VALID             0x80	/* Sense data is valid as SCSI2     */
-#define SENSE_INVALID           0x00	/* Sense data is invalid as SCSI2   */
 
 /*---- error code ----*/
 #define CUR_ERR                 0x70	/* current error                    */
-#define DEF_ERR                 0x71	/* specific command error           */
 
 /*---- sense key Infomation ----*/
-#define SNSKEYINFO_LEN          3	/* length of sense key infomation   */
 
 #define SKSV                    0x80
 #define CDB_ILLEGAL             0x40
-#define DAT_ILLEGAL             0x00
-#define BPV                     0x08
-#define BIT_ILLEGAL0            0	/* bit0 is illegal                  */
-#define BIT_ILLEGAL1            1	/* bit1 is illegal                  */
-#define BIT_ILLEGAL2            2	/* bit2 is illegal                  */
-#define BIT_ILLEGAL3            3	/* bit3 is illegal                  */
-#define BIT_ILLEGAL4            4	/* bit4 is illegal                  */
-#define BIT_ILLEGAL5            5	/* bit5 is illegal                  */
-#define BIT_ILLEGAL6            6	/* bit6 is illegal                  */
-#define BIT_ILLEGAL7            7	/* bit7 is illegal                  */
 
 /*---- ASC ----*/
-#define ASC_NO_INFO             0x00
-#define ASC_MISCMP              0x1d
 #define ASC_INVLD_CDB           0x24
-#define ASC_INVLD_PARA          0x26
-#define ASC_LU_NOT_READY	0x04
-#define ASC_WRITE_ERR           0x0c
-#define ASC_READ_ERR            0x11
-#define ASC_LOAD_EJCT_ERR       0x53
-#define	ASC_MEDIA_NOT_PRESENT	0x3A
-#define	ASC_MEDIA_CHANGED	0x28
-#define	ASC_MEDIA_IN_PROCESS	0x04
-#define	ASC_WRITE_PROTECT	0x27
-#define ASC_LUN_NOT_SUPPORTED	0x25
 
 /*---- ASQC ----*/
-#define ASCQ_NO_INFO            0x00
-#define	ASCQ_MEDIA_IN_PROCESS	0x01
-#define ASCQ_MISCMP             0x00
 #define ASCQ_INVLD_CDB          0x00
-#define ASCQ_INVLD_PARA         0x02
-#define ASCQ_LU_NOT_READY	0x02
-#define ASCQ_WRITE_ERR          0x02
-#define ASCQ_READ_ERR           0x00
-#define ASCQ_LOAD_EJCT_ERR      0x00
-#define	ASCQ_WRITE_PROTECT	0x00
 
 struct sense_data_t {
 	unsigned char err_code;	/* error code */
@@ -296,13 +226,13 @@
 	unsigned char seg_no;	/* segment No.                      */
 	unsigned char sense_key;	/* byte5 : ILI                      */
 	/* bit3-0 : sense key              */
-	unsigned char info[4];	/* infomation                       */
+	unsigned char info[4];	/* information                       */
 	unsigned char ad_sense_len;	/* additional sense data length     */
-	unsigned char cmd_info[4];	/* command specific infomation      */
+	unsigned char cmd_info[4];	/* command specific information      */
 	unsigned char asc;	/* ASC                              */
 	unsigned char ascq;	/* ASCQ                             */
 	unsigned char rfu;	/* FRU                              */
-	unsigned char sns_key_info[3];	/* sense key specific infomation    */
+	unsigned char sns_key_info[3];	/* sense key specific information    */
 };
 
 /* sd_ctl bit map */
@@ -323,8 +253,6 @@
 #define SUPPORT_UHS50_MMC44		0x40
 
 struct rts51x_option {
-	u8 led_blink_speed;
-
 	int mspro_formatter_enable;
 
 	/* card clock expected by user for fpga platform */
@@ -368,8 +296,6 @@
 	int ss_en;
 	/* Interval to enter SS from IDLE state (second) */
 	int ss_delay;
-	int needs_remote_wakeup;
-	u8 ww_enable;	/* sangdy2010-08-03:add for remote wakeup */
 
 	/* Enable SSC clock */
 	int ssc_en;
@@ -392,10 +318,7 @@
 	/*if reset or rw fail,then set SD20 pad drive again */
 	u8 reset_or_rw_fail_set_pad_drive;
 
-	u8 rcc_fail_flag;	/* add to indicate whether rcc bug happen */
-	u8 rcc_bug_fix_en;	/* if set,then support fixing rcc bug */
 	u8 debounce_num;	/* debounce number */
-	int polling_time;	/* polling delay time */
 	u8 led_toggle_interval;	/* used to control led toggle speed */
 	int xd_rwn_step;
 	u8 sd_send_status_en;
@@ -405,7 +328,7 @@
 	u8 ddr50_rx_phase;
 	u8 sdr50_tx_phase;
 	u8 sdr50_rx_phase;
-	/* used to enable select sdr50 tx phase according to  proportion. */
+	/* used to enable select sdr50 tx phase according to proportion. */
 	u8 sdr50_phase_sel;
 	u8 ms_errreg_fix;
 	u8 reset_mmc_first;
@@ -614,11 +537,6 @@
 	u8 sd_reset_fail;	/* sangdy2010-07-01 */
 	u8 sd_send_status_en;
 
-#ifdef SUPPORT_SD_LOCK
-	u8 sd_lock_status;
-	u8 sd_erase_status;
-	u8 sd_lock_notify;
-#endif
 };
 
 #define MODE_512_SEQ		0x01
@@ -720,9 +638,8 @@
 	struct scsi_cmnd *srb;
 	struct sense_data_t sense_buffer[MAX_ALLOWED_LUN_CNT];
 
-#ifndef LED_AUTO_BLINK
 	int led_toggle_counter;
-#endif
+
 	int ss_counter;
 	int idle_counter;
 	int auto_delink_counter;
diff --git a/drivers/staging/rts5139/rts51x_fop.c b/drivers/staging/rts5139/rts51x_fop.c
index 6eaebb6..ef893c8 100644
--- a/drivers/staging/rts5139/rts51x_fop.c
+++ b/drivers/staging/rts5139/rts51x_fop.c
@@ -234,12 +234,7 @@
 	return 0;
 }
 
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */
-int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-		 unsigned long arg)
-#else
 long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-#endif
 {
 	struct rts51x_chip *chip;
 	struct sd_direct_cmnd cmnd;
diff --git a/drivers/staging/rts5139/rts51x_fop.h b/drivers/staging/rts5139/rts51x_fop.h
index 94d75f0..eb45acf 100644
--- a/drivers/staging/rts5139/rts51x_fop.h
+++ b/drivers/staging/rts5139/rts51x_fop.h
@@ -50,12 +50,7 @@
 		    loff_t *f_pos);
 ssize_t rts51x_write(struct file *filp, const char __user *buf, size_t count,
 		     loff_t *f_pos);
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */
-int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-		 unsigned long arg);
-#else
 long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
-#endif
 
 #endif
 
diff --git a/drivers/staging/rts5139/rts51x_scsi.c b/drivers/staging/rts5139/rts51x_scsi.c
index 87c9cdc..e07a1f4 100644
--- a/drivers/staging/rts5139/rts51x_scsi.c
+++ b/drivers/staging/rts5139/rts51x_scsi.c
@@ -40,7 +40,6 @@
 #include "rts51x_scsi.h"
 #include "rts51x_card.h"
 #include "rts51x_transport.h"
-#include "rts51x_sys.h"
 #include "sd_cprm.h"
 #include "ms_mg.h"
 #include "trace.h"
@@ -370,10 +369,6 @@
 			       ASC_INVLD_CDB, ASCQ_INVLD_CDB, CDB_ILLEGAL, 1);
 		break;
 
-	case SENSE_TYPE_FORMAT_IN_PROGRESS:
-		set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, 0, 0);
-		break;
-
 	case SENSE_TYPE_FORMAT_CMD_FAILED:
 		set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x31, 0x01, 0, 0);
 		break;
@@ -396,12 +391,6 @@
 		break;
 #endif
 
-#ifdef SUPPORT_SD_LOCK
-	case SENSE_TYPE_MEDIA_READ_FORBIDDEN:
-		set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x11, 0x13, 0, 0);
-		break;
-#endif
-
 	case SENSE_TYPE_NO_SENSE:
 	default:
 		set_sense_data(chip, lun, CUR_ERR, 0, 0, 0, 0, 0, 0);
@@ -448,20 +437,6 @@
 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
 		return TRANSPORT_FAILED;
 	}
-#ifdef SUPPORT_SD_LOCK
-	if (get_lun_card(chip, SCSI_LUN(srb)) == SD_CARD) {
-		struct sd_info *sd_card = &(chip->sd_card);
-		if (sd_card->sd_lock_notify) {
-			sd_card->sd_lock_notify = 0;
-			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
-			return TRANSPORT_FAILED;
-		} else if (sd_card->sd_lock_status & SD_LOCKED) {
-			set_sense_type(chip, lun,
-				       SENSE_TYPE_MEDIA_READ_FORBIDDEN);
-			return TRANSPORT_FAILED;
-		}
-	}
-#endif
 
 	return TRANSPORT_GOOD;
 }
@@ -797,9 +772,6 @@
 
 static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip)
 {
-#ifdef SUPPORT_SD_LOCK
-	struct sd_info *sd_card = &(chip->sd_card);
-#endif
 	unsigned int lun = SCSI_LUN(srb);
 	int retval;
 	u32 start_sec;
@@ -819,25 +791,6 @@
 	rts51x_prepare_run(chip);
 	RTS51X_SET_STAT(chip, STAT_RUN);
 
-#ifdef SUPPORT_SD_LOCK
-	if (sd_card->sd_erase_status) {
-		/* Accessing to any card is forbidden
-		 * until the erase procedure of SD is completed */
-		RTS51X_DEBUGP("SD card being erased!\n");
-		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_READ_FORBIDDEN);
-		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
-
-	if (get_lun_card(chip, lun) == SD_CARD) {
-		if (sd_card->sd_lock_status & SD_LOCKED) {
-			RTS51X_DEBUGP("SD card locked!\n");
-			set_sense_type(chip, lun,
-				       SENSE_TYPE_MEDIA_READ_FORBIDDEN);
-			TRACE_RET(chip, TRANSPORT_FAILED);
-		}
-	}
-#endif
-
 	if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10)) {
 		start_sec =
 		    ((u32) srb->cmnd[2] << 24) |
@@ -883,20 +836,12 @@
 
 	retval = card_rw(srb, chip, start_sec, sec_cnt);
 	if (retval != STATUS_SUCCESS) {
-#if 0
-		if (chip->need_release & chip->lun2card[lun]) {
-			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
-		} else {
-#endif
 		if (srb->sc_data_direction == DMA_FROM_DEVICE) {
 			set_sense_type(chip, lun,
 				       SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
 		}
-#if 0
-		}
-#endif
 		TRACE_RET(chip, TRANSPORT_FAILED);
 	}
 
@@ -1516,7 +1461,7 @@
 }
 
 #ifdef SUPPORT_PCGL_1P18
-int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+static int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip)
 {
 	struct ms_info *ms_card = &(chip->ms_card);
 	unsigned int lun = SCSI_LUN(srb);
@@ -1677,7 +1622,7 @@
 #endif
 
 #ifdef SUPPORT_MAGIC_GATE
-int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+static int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
 {
 	struct ms_info *ms_card = &(chip->ms_card);
 	unsigned int lun = SCSI_LUN(srb);
@@ -1764,7 +1709,7 @@
 	return TRANSPORT_GOOD;
 }
 
-int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+static int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
 {
 	struct ms_info *ms_card = &(chip->ms_card);
 	unsigned int lun = SCSI_LUN(srb);
@@ -1871,30 +1816,10 @@
 
 int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip)
 {
-#ifdef SUPPORT_SD_LOCK
-	struct sd_info *sd_card = &(chip->sd_card);
-#endif
 	struct ms_info *ms_card = &(chip->ms_card);
 	unsigned int lun = SCSI_LUN(srb);
 	int result = TRANSPORT_GOOD;
 
-#ifdef SUPPORT_SD_LOCK
-	if (sd_card->sd_erase_status) {
-		/* Block all SCSI command except for REQUEST_SENSE
-		 * and rs_ppstatus */
-		if (!
-		    ((srb->cmnd[0] == VENDOR_CMND)
-		     && (srb->cmnd[1] == SCSI_APP_CMD)
-		     && (srb->cmnd[2] == GET_DEV_STATUS))
-		    && (srb->cmnd[0] != REQUEST_SENSE)) {
-			/* Logical Unit Not Ready Format in Progress */
-			set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04,
-				       0, 0);
-			TRACE_RET(chip, TRANSPORT_FAILED);
-		}
-	}
-#endif
-
 	if ((get_lun_card(chip, lun) == MS_CARD) &&
 	    (ms_card->format_status == FORMAT_IN_PROGRESS)) {
 		if ((srb->cmnd[0] != REQUEST_SENSE)
@@ -1994,11 +1919,6 @@
  * Host functions
  ***********************************************************************/
 
-const char *host_info(struct Scsi_Host *host)
-{
-	return "SCSI emulation for RTS51xx USB driver-based card reader";
-}
-
 int slave_alloc(struct scsi_device *sdev)
 {
 	/*
@@ -2111,14 +2031,7 @@
 	return 0;
 }
 
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */
-int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *))
-{
-	return queuecommand_lck(srb, done);
-}
-#else
 DEF_SCSI_QCMD(queuecommand)
-#endif
 /***********************************************************************
  * Error handling functions
  ***********************************************************************/
diff --git a/drivers/staging/rts5139/rts51x_scsi.h b/drivers/staging/rts5139/rts51x_scsi.h
index 3a8ca06..060d2c2 100644
--- a/drivers/staging/rts5139/rts51x_scsi.h
+++ b/drivers/staging/rts5139/rts51x_scsi.h
@@ -145,16 +145,11 @@
 struct scsi_device;
 struct scsi_cmnd;
 
-const char *host_info(struct Scsi_Host *host);
 int slave_alloc(struct scsi_device *sdev);
 int slave_configure(struct scsi_device *sdev);
 int proc_info(struct Scsi_Host *host, char *buffer,
 	      char **start, off_t offset, int length, int inout);
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */
-int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *));
-#else
 int queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
-#endif
 int command_abort(struct scsi_cmnd *srb);
 int device_reset(struct scsi_cmnd *srb);
 int bus_reset(struct scsi_cmnd *srb);
diff --git a/drivers/staging/rts5139/rts51x_sys.h b/drivers/staging/rts5139/rts51x_sys.h
deleted file mode 100644
index b09cd34..0000000
--- a/drivers/staging/rts5139/rts51x_sys.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Driver for Realtek USB RTS51xx card reader
- * Header file
- *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, 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/>.
- *
- * Author:
- *   wwang (wei_wang@realsil.com.cn)
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
- * Maintainer:
- *   Edwin Rong (edwin_rong@realsil.com.cn)
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
- */
-
-#ifndef __RTS51X_SYS_H
-#define __RTS51X_SYS_H
-
-#include "rts51x.h"
-#include "rts51x_chip.h"
-#include "rts51x_card.h"
-
-#define USING_POLLING_CYCLE_DELINK
-
-extern int  rts51x_check_start_time(struct rts51x_chip *chip);
-extern void rts51x_set_start_time(struct rts51x_chip *chip);
-extern void rts51x_clear_start_time(struct rts51x_chip *chip);
-
-/* typedef dma_addr_t ULONG_PTR; */
-
-static inline void rts51x_reset_detected_cards(struct rts51x_chip *chip)
-{
-/*      rts51x_reset_cards(chip); */
-}
-
-static inline void clear_first_install_mark(struct rts51x_chip *chip)
-{
-}
-
-void rts51x_enter_ss(struct rts51x_chip *chip);
-void rts51x_exit_ss(struct rts51x_chip *chip);
-
-#endif /* __RTS51X_SYS_H */
diff --git a/drivers/staging/rts5139/rts51x_transport.c b/drivers/staging/rts5139/rts51x_transport.c
index da9c83b..89e4d80 100644
--- a/drivers/staging/rts5139/rts51x_transport.c
+++ b/drivers/staging/rts5139/rts51x_transport.c
@@ -120,7 +120,7 @@
 	return cnt;
 }
 
-unsigned int rts51x_access_xfer_buf(unsigned char *buffer,
+static unsigned int rts51x_access_xfer_buf(unsigned char *buffer,
 				    unsigned int buflen, struct scsi_cmnd *srb,
 				    struct scatterlist **sgptr,
 				    unsigned int *offset, enum xfer_buf_dir dir)
@@ -252,6 +252,8 @@
 	return status;
 }
 
+static int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe);
+
 /*
  * Interpret the results of a URB transfer
  */
@@ -359,7 +361,7 @@
 				    rts51x->current_urb->actual_length);
 }
 
-int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe)
+static int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe)
 {
 	int result;
 	int endp = usb_pipeendpoint(pipe);
@@ -378,11 +380,6 @@
 	return STATUS_SUCCESS;
 }
 
-int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe)
-{
-	return rts51x_clear_halt(chip, pipe);
-}
-
 static void rts51x_sg_clean(struct usb_sg_request *io)
 {
 	if (io->urbs) {
@@ -391,226 +388,17 @@
 		kfree(io->urbs);
 		io->urbs = NULL;
 	}
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) */
-	if (io->dev->dev.dma_mask != NULL)
-		usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
-				    io->sg, io->nents);
-#endif
 	io->dev = NULL;
 }
-#if 0
-static void rts51x_sg_complete(struct urb *urb)
-{
-	struct usb_sg_request *io = urb->context;
-	int status = urb->status;
 
-	spin_lock(&io->lock);
-
-	/* In 2.5 we require hcds' endpoint queues not to progress after fault
-	* reports, until the completion callback (this!) returns.  That lets
-	* device driver code (like this routine) unlink queued urbs first,
-	* if it needs to, since the HC won't work on them at all.  So it's
-	* not possible for page N+1 to overwrite page N, and so on.
-	*
-	* That's only for "hard" faults; "soft" faults (unlinks) sometimes
-	* complete before the HCD can get requests away from hardware,
-	* though never during cleanup after a hard fault.
-	*/
-	if (io->status
-		&& (io->status != -ECONNRESET
-		|| status != -ECONNRESET)
-		&& urb->actual_length) {
-			dev_err(io->dev->bus->controller,
-				"dev %s ep%d%s scatterlist error %d/%d\n",
-				io->dev->devpath,
-				usb_endpoint_num(&urb->ep->desc),
-				usb_urb_dir_in(urb) ? "in" : "out",
-				status, io->status);
-			/* BUG (); */
-	}
-
-	if (io->status == 0 && status && status != -ECONNRESET) {
-		int i, found, retval;
-
-		io->status = status;
-
-		/* the previous urbs, and this one, completed already.
-		* unlink pending urbs so they won't rx/tx bad data.
-		* careful: unlink can sometimes be synchronous...
-		*/
-		spin_unlock(&io->lock);
-		for (i = 0, found = 0; i < io->entries; i++) {
-			if (!io->urbs[i] || !io->urbs[i]->dev)
-				continue;
-			if (found) {
-				retval = usb_unlink_urb(io->urbs[i]);
-				if (retval != -EINPROGRESS &&
-					retval != -ENODEV &&
-					retval != -EBUSY)
-					dev_err(&io->dev->dev,
-						"%s, unlink --> %d\n",
-						__func__, retval);
-			} else if (urb == io->urbs[i])
-				found = 1;
-		}
-		spin_lock(&io->lock);
-	}
-	urb->dev = NULL;
-
-	/* on the last completion, signal usb_sg_wait() */
-	io->bytes += urb->actual_length;
-	io->count--;
-	if (!io->count)
-		complete(&io->complete);
-
-	spin_unlock(&io->lock);
-}
-
-/* This function is ported from usb_sg_init, which can transfer
- * sg list partially */
-int rts51x_sg_init_partial(struct usb_sg_request *io, struct usb_device *dev,
-	unsigned pipe, unsigned period, void *buf, struct scatterlist **sgptr,
-	unsigned int *offset, int nents, size_t length, gfp_t mem_flags)
-{
-	int i;
-	int urb_flags;
-	int dma;
-	struct scatterlist *sg = *sgptr, *first_sg;
-
-	first_sg = (struct scatterlist *)buf;
-	if (!sg)
-		sg = first_sg;
-
-	if (!io || !dev || !sg
-		|| usb_pipecontrol(pipe)
-		|| usb_pipeisoc(pipe)
-		|| (nents <= 0))
-		return -EINVAL;
-
-	spin_lock_init(&io->lock);
-	io->dev = dev;
-	io->pipe = pipe;
-	io->sg = first_sg;  /* used by unmap */
-	io->nents = nents;
-
-	RTS51X_DEBUGP("Before map, sg address: 0x%x\n", (unsigned int)sg);
-	RTS51X_DEBUGP("Before map, dev address: 0x%x\n", (unsigned int)dev);
-
-	/* not all host controllers use DMA (like the mainstream pci ones);
-	* they can use PIO (sl811) or be software over another transport.
-	*/
-	dma = (dev->dev.dma_mask != NULL);
-	if (dma) {
-		/* map the whole sg list, because here we only know the
-		 * total nents */
-		io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
-		first_sg, nents);
-	} else {
-		io->entries = nents;
-	}
-
-	/* initialize all the urbs we'll use */
-	if (io->entries <= 0)
-		return io->entries;
-
-	io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
-	if (!io->urbs)
-		goto nomem;
-
-	urb_flags = URB_NO_INTERRUPT;
-	if (dma)
-		urb_flags |= URB_NO_TRANSFER_DMA_MAP;
-	if (usb_pipein(pipe))
-		urb_flags |= URB_SHORT_NOT_OK;
-
-	RTS51X_DEBUGP("io->entries = %d\n", io->entries);
-
-	for (i = 0; (sg != NULL) && (length > 0); i++) {
-		unsigned len;
-
-		RTS51X_DEBUGP("sg address: 0x%x\n", (unsigned int)sg);
-		RTS51X_DEBUGP("length = %d, *offset = %d\n", length, *offset);
-
-		io->urbs[i] = usb_alloc_urb(0, mem_flags);
-		if (!io->urbs[i]) {
-			io->entries = i;
-			goto nomem;
-		}
-
-		io->urbs[i]->dev = NULL;
-		io->urbs[i]->pipe = pipe;
-		io->urbs[i]->interval = period;
-		io->urbs[i]->transfer_flags = urb_flags;
-
-		io->urbs[i]->complete = rts51x_sg_complete;
-		io->urbs[i]->context = io;
-
-		if (dma) {
-			io->urbs[i]->transfer_dma =
-				sg_dma_address(sg) + *offset;
-			len = sg_dma_len(sg) - *offset;
-			io->urbs[i]->transfer_buffer = NULL;
-			RTS51X_DEBUGP(" -- sg entry dma length = %d\n",
-						sg_dma_len(sg));
-		} else {
-			/* hc may use _only_ transfer_buffer */
-			io->urbs[i]->transfer_buffer = sg_virt(sg) + *offset;
-			len = sg->length - *offset;
-			RTS51X_DEBUGP(" -- sg entry length = %d\n",
-						sg->length);
-		}
-
-		if (length >= len) {
-			*offset = 0;
-			io->urbs[i]->transfer_buffer_length = len;
-			length -= len;
-			sg = sg_next(sg);
-		} else {
-			*offset += length;
-			io->urbs[i]->transfer_buffer_length = length;
-			length = 0;
-		}
-		if (length == 0)
-			io->entries = i + 1;
-#if 0
-		if (length) {
-			len = min_t(unsigned, len, length);
-			length -= len;
-			if (length == 0) {
-				io->entries = i + 1;
-				*offset += len;
-			} else {
-				*offset = 0;
-			}
-		}
-#endif
-	}
-	RTS51X_DEBUGP("In %s, urb count: %d\n", __func__, i);
-	io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
-
-	RTS51X_DEBUGP("sg address stored in sgptr: 0x%x\n", (unsigned int)sg);
-	*sgptr = sg;
-
-	/* transaction state */
-	io->count = io->entries;
-	io->status = 0;
-	io->bytes = 0;
-	init_completion(&io->complete);
-	return 0;
-
-nomem:
-	rts51x_sg_clean(io);
-	return -ENOMEM;
-}
-#endif
-int rts51x_sg_init(struct usb_sg_request *io, struct usb_device *dev,
+static int rts51x_sg_init(struct usb_sg_request *io, struct usb_device *dev,
 		   unsigned pipe, unsigned period, struct scatterlist *sg,
 		   int nents, size_t length, gfp_t mem_flags)
 {
 	return usb_sg_init(io, dev, pipe, period, sg, nents, length, mem_flags);
 }
 
-int rts51x_sg_wait(struct usb_sg_request *io, int timeout)
+static int rts51x_sg_wait(struct usb_sg_request *io, int timeout)
 {
 	long timeleft;
 	int i;
@@ -630,7 +418,7 @@
 		 */
 		spin_unlock_irq(&io->lock);
 		switch (retval) {
-			/* maybe we retrying will recover */
+			/* maybe the retry will recover */
 		case -ENXIO:	/* hc didn't queue this one */
 		case -EAGAIN:
 		case -ENOMEM:
@@ -740,56 +528,9 @@
 	return interpret_urb_result(chip, pipe, length, result,
 				    chip->usb->current_sg.bytes);
 }
-#if 0
-static int rts51x_bulk_transfer_sglist_partial(struct rts51x_chip *chip,
-		unsigned int pipe, void *buf, struct scatterlist **sgptr,
-		unsigned int *offset, int num_sg, unsigned int length,
-		unsigned int *act_len, int timeout)
-{
-	int result;
 
-	/* don't submit s-g requests during abort processing */
-	if (test_bit(FLIDX_ABORTING, &chip->usb->dflags))
-		TRACE_RET(chip, STATUS_ERROR);
-
-	/* initialize the scatter-gather request block */
-	RTS51X_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__,
-			length, num_sg);
-	result = rts51x_sg_init_partial(&chip->usb->current_sg,
-			chip->usb->pusb_dev, pipe, 0, buf, sgptr, offset,
-			num_sg, length, GFP_NOIO);
-	if (result) {
-		RTS51X_DEBUGP("rts51x_sg_init_partial returned %d\n", result);
-		TRACE_RET(chip, STATUS_ERROR);
-	}
-
-	/* since the block has been initialized successfully, it's now
-	 * okay to cancel it */
-	set_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
-
-	/* did an abort occur during the submission? */
-	if (test_bit(FLIDX_ABORTING, &chip->usb->dflags)) {
-
-		/* cancel the request, if it hasn't been cancelled already */
-		if (test_and_clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags)) {
-			RTS51X_DEBUGP("-- cancelling sg request\n");
-			usb_sg_cancel(&chip->usb->current_sg);
-		}
-	}
-
-	/* wait for the completion of the transfer */
-	result = rts51x_sg_wait(&chip->usb->current_sg, timeout);
-
-	clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
-
-	/* result = us->current_sg.status; */
-	if (act_len)
-		*act_len = chip->usb->current_sg.bytes;
-	return interpret_urb_result(chip, pipe, length, result,
-		chip->usb->current_sg.bytes);
-}
-#endif
-int rts51x_bulk_transfer_buf(struct rts51x_chip *chip, unsigned int pipe,
+static int rts51x_bulk_transfer_buf(struct rts51x_chip *chip,
+			     unsigned int pipe,
 			     void *buf, unsigned int length,
 			     unsigned int *act_len, int timeout)
 {
@@ -860,11 +601,6 @@
 		}
 
 		kfree(tmp_buf);
-#if 0
-		result = rts51x_bulk_transfer_sglist_partial(chip, pipe, buf,
-					(struct scatterlist **)ptr, offset,
-					use_sg, len, act_len, timeout);
-#endif
 	} else {
 		unsigned int step = 0;
 		if (offset)
diff --git a/drivers/staging/rts5139/rts51x_transport.h b/drivers/staging/rts5139/rts51x_transport.h
index 9dd556e..024f115 100644
--- a/drivers/staging/rts5139/rts51x_transport.h
+++ b/drivers/staging/rts5139/rts51x_transport.h
@@ -40,11 +40,6 @@
 				  unsigned int buflen, void *sglist,
 				  void **sgptr, unsigned int *offset,
 				  enum xfer_buf_dir dir);
-unsigned int rts51x_access_xfer_buf(unsigned char *buffer, unsigned int buflen,
-				    struct scsi_cmnd *srb,
-				    struct scatterlist **sgptr,
-				    unsigned int *offset,
-				    enum xfer_buf_dir dir);
 void rts51x_set_xfer_buf(unsigned char *buffer, unsigned int buflen,
 			 struct scsi_cmnd *srb);
 void rts51x_get_xfer_buf(unsigned char *buffer, unsigned int buflen,
@@ -53,7 +48,6 @@
 int rts51x_ctrl_transfer(struct rts51x_chip *chip, unsigned int pipe,
 			 u8 request, u8 requesttype, u16 value, u16 index,
 			 void *data, u16 size, int timeout);
-int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe);
 int rts51x_transfer_data(struct rts51x_chip *chip, unsigned int pipe,
 			 void *buf, unsigned int len, int use_sg,
 			 unsigned int *act_len, int timeout);
@@ -62,12 +56,6 @@
 				 unsigned int len, int use_sg,
 				 unsigned int *act_len, int timeout);
 
-/* whichPipe:
- * 0: bulk in pipe
- * 1: bulk out pipe
- * 2: intr  in pipe */
-int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe);
-
 #ifndef POLLING_IN_THREAD
 int rts51x_start_epc_transfer(struct rts51x_chip *chip);
 void rts51x_cancel_epc_transfer(struct rts51x_chip *chip);
diff --git a/drivers/staging/rts5139/sd.c b/drivers/staging/rts5139/sd.c
index d5dd2f9..b739f26 100644
--- a/drivers/staging/rts5139/sd.c
+++ b/drivers/staging/rts5139/sd.c
@@ -246,12 +246,7 @@
 				if (buf[1] & 0x80)
 					TRACE_RET(chip, STATUS_FAIL);
 			}
-#ifdef SUPPORT_SD_LOCK
-			/* exclude bit25 CARD_IS_LOCKED */
-			if (buf[1] & 0x7D) {
-#else
 			if (buf[1] & 0x7F) {
-#endif
 				RTS51X_DEBUGP("buf[1]: 0x%02x\n", buf[1]);
 				TRACE_RET(chip, STATUS_FAIL);
 			}
@@ -709,37 +704,7 @@
 	return STATUS_SUCCESS;
 }
 
-#ifdef SUPPORT_SD_LOCK
-int sd_update_lock_status(struct rts51x_chip *chip)
-{
-	struct sd_info *sd_card = &(chip->sd_card);
-	int retval;
-	u8 rsp[5];
-
-	retval =
-	    sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
-				SD_RSP_TYPE_R1, rsp, 5);
-	if (retval != STATUS_SUCCESS)
-		TRACE_RET(chip, STATUS_FAIL);
-
-	if (rsp[1] & 0x02)
-		sd_card->sd_lock_status |= SD_LOCKED;
-	else
-		sd_card->sd_lock_status &= ~SD_LOCKED;
-
-	RTS51X_DEBUGP("sd_card->sd_lock_status = 0x%x\n",
-		       sd_card->sd_lock_status);
-
-	if (rsp[1] & 0x01) {
-		/* LOCK_UNLOCK_FAILED */
-		TRACE_RET(chip, STATUS_FAIL);
-	}
-
-	return STATUS_SUCCESS;
-}
-#endif
-
-int sd_wait_currentstate_dataready(struct rts51x_chip *chip, u8 statechk,
+static int sd_wait_currentstate_dataready(struct rts51x_chip *chip, u8 statechk,
 				   u8 rdychk, u16 pollingcnt)
 {
 	struct sd_info *sd_card = &(chip->sd_card);
@@ -1197,15 +1162,6 @@
 	RTS51X_DEBUGP("SD_FUNC_GROUP_1: func_to_switch = 0x%02x",
 		       func_to_switch);
 
-#ifdef SUPPORT_SD_LOCK
-	if ((sd_card->sd_lock_status & SD_SDR_RST)
-	    && (DDR50_SUPPORT == func_to_switch)
-	    && (sd_card->func_group1_mask & SDR50_SUPPORT_MASK)) {
-		func_to_switch = SDR50_SUPPORT;
-		RTS51X_DEBUGP("Using SDR50 instead of DDR50 for SD Lock\n");
-	}
-#endif
-
 	if (func_to_switch) {
 		retval =
 		    sd_check_switch(chip, SD_FUNC_GROUP_1, func_to_switch,
@@ -1562,7 +1518,7 @@
 	}
 
 Search_Finish:
-	RTS51X_DEBUGP("Final choosen phase: %d\n", final_phase);
+	RTS51X_DEBUGP("Final chosen phase: %d\n", final_phase);
 	return final_phase;
 }
 
@@ -2024,10 +1980,6 @@
 	k = 0;
 	hi_cap_flow = 0;
 	support_1v8 = 0;
-#ifdef SUPPORT_SD_LOCK
-	if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON)
-		goto SD_UNLOCK_ENTRY;
-#endif
 
 	retval = sd_prepare_reset(chip);
 	if (retval != STATUS_SUCCESS)
@@ -2182,7 +2134,7 @@
 	sd_card->sd_addr += (u32) rsp[2] << 16;
 
 	/* Get CSD register for Calculating Timing,Capacity,
-	 * Check CSD to determaine as if this is the SD ROM card */
+	 * Check CSD to determine as if this is the SD ROM card */
 	retval = sd_check_csd(chip, 1);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, retval);
@@ -2190,20 +2142,6 @@
 	retval = sd_select_card(chip, 1);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, retval);
-#ifdef SUPPORT_SD_LOCK
-SD_UNLOCK_ENTRY:
-	/* Get SD lock status */
-	retval = sd_update_lock_status(chip);
-	if (retval != STATUS_SUCCESS)
-		TRACE_RET(chip, STATUS_FAIL);
-
-	if (sd_card->sd_lock_status & SD_LOCKED) {
-		sd_card->sd_lock_status |= (SD_LOCK_1BIT_MODE | SD_PWD_EXIST);
-		return STATUS_SUCCESS;
-	} else if (!(sd_card->sd_lock_status & SD_UNLOCK_POW_ON)) {
-		sd_card->sd_lock_status &= ~SD_PWD_EXIST;
-	}
-#endif
 
 	/* ACMD42 */
 	retval =
@@ -2294,10 +2232,6 @@
 		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, retval);
 	}
-#ifdef SUPPORT_SD_LOCK
-	/* clear 1 bit mode status */
-	sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
-#endif
 
 	if (CHK_SD30_SPEED(sd_card)) {
 		rts51x_write_register(chip, SD30_DRIVE_SEL, SD30_DRIVE_MASK,
@@ -2380,19 +2314,6 @@
 
 	chip->card_bus_width[chip->card2lun[SD_CARD]] = 4;
 
-#ifdef SUPPORT_SD_LOCK
-	if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
-		rts51x_init_cmd(chip);
-
-		rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02);
-		rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00);
-
-		retval = rts51x_send_cmd(chip, MODE_C, 100);
-		if (retval != STATUS_SUCCESS)
-			TRACE_RET(chip, retval);
-	}
-#endif
-
 	return STATUS_SUCCESS;
 }
 
@@ -2587,17 +2508,10 @@
 		sd_card->capacity =
 		    ((u32) buf[5] << 24) | ((u32) buf[4] << 16) |
 		    ((u32) buf[3] << 8) | ((u32) buf[2]);
-#ifdef SUPPORT_SD_LOCK
-	if (!(sd_card->sd_lock_status & SD_SDR_RST) && CHECK_UHS50(chip))
-		card_type_mask = 0x07;
-	else
-		card_type_mask = 0x03;
-#else
 	if (CHECK_UHS50(chip))
 		card_type_mask = 0x07;
 	else
 		card_type_mask = 0x03;
-#endif
 
 	card_type = buf[1] & card_type_mask;
 	if (card_type) {
@@ -2626,15 +2540,9 @@
 	if (mmc_test_switch_bus(chip, MMC_8BIT_BUS) == STATUS_SUCCESS) {
 		SET_MMC_8BIT(sd_card);
 		chip->card_bus_width[chip->card2lun[SD_CARD]] = 8;
-#ifdef SUPPORT_SD_LOCK
-		sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
-#endif
 	} else if (mmc_test_switch_bus(chip, MMC_4BIT_BUS) == STATUS_SUCCESS) {
 		SET_MMC_4BIT(sd_card);
 		chip->card_bus_width[chip->card2lun[SD_CARD]] = 4;
-#ifdef SUPPORT_SD_LOCK
-		sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
-#endif
 	} else {
 		CLR_MMC_8BIT(sd_card);
 		CLR_MMC_4BIT(sd_card);
@@ -2652,11 +2560,6 @@
 	u8 change_to_ddr52 = 1;
 	u8 cmd[5];
 
-#ifdef SUPPORT_SD_LOCK
-	if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON)
-		goto MMC_UNLOCK_ENTRY;
-#endif
-
 MMC_DDR_FAIL:
 
 	retval = sd_prepare_reset(chip);
@@ -2745,7 +2648,7 @@
 		TRACE_RET(chip, retval);
 
 	/* Get CSD register for Calculating Timing,Capacity
-	 * Check CSD to determaine as if this is the SD ROM card */
+	 * Check CSD to determine as if this is the SD ROM card */
 	retval = sd_check_csd(chip, 1);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, retval);
@@ -2763,13 +2666,6 @@
 				0);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, retval);
-#ifdef SUPPORT_SD_LOCK
-MMC_UNLOCK_ENTRY:
-	/* Get SD lock status */
-	retval = sd_update_lock_status(chip);
-	if (retval != STATUS_SUCCESS)
-		TRACE_RET(chip, STATUS_FAIL);
-#endif
 
 	RTS51X_WRITE_REG(chip, SD_CFG1, SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
 
@@ -2842,18 +2738,6 @@
 			}
 		}
 	}
-#ifdef SUPPORT_SD_LOCK
-	if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
-		rts51x_init_cmd(chip);
-
-		rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02);
-		rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00);
-
-		retval = rts51x_send_cmd(chip, MODE_C, 100);
-		if (retval != STATUS_SUCCESS)
-			TRACE_RET(chip, retval);
-	}
-#endif
 
 	retval = rts51x_get_card_status(chip, &(chip->card_status));
 	if (retval != STATUS_SUCCESS)
@@ -2879,11 +2763,6 @@
 	sd_card->capacity = 0;
 	sd_card->sd_switch_fail = 0;
 
-#ifdef SUPPORT_SD_LOCK
-	sd_card->sd_lock_status = 0;
-	sd_card->sd_erase_status = 0;
-#endif
-
 	sd_clear_reset_fail(chip);
 	enable_card_clock(chip, SD_CARD);
 
@@ -3006,7 +2885,7 @@
 	TRACE_RET(chip, STATUS_FAIL);
 }
 
-void sd_stop_seq_mode(struct rts51x_chip *chip)
+static void sd_stop_seq_mode(struct rts51x_chip *chip)
 {
 	struct sd_info *sd_card = &(chip->sd_card);
 	int retval;
@@ -3300,7 +3179,7 @@
 	}
 }
 
-inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip)
+static inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip)
 {
 	rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0);
 
@@ -3322,7 +3201,7 @@
 	}
 }
 
-int sd_power_off_card3v3(struct rts51x_chip *chip)
+static int sd_power_off_card3v3(struct rts51x_chip *chip)
 {
 	int retval;
 
@@ -3346,17 +3225,12 @@
 	struct sd_info *sd_card = &(chip->sd_card);
 	int retval;
 
-	RTS51X_DEBUGP("elease_sd_card\n");
+	RTS51X_DEBUGP("release_sd_card\n");
 
 	chip->card_ready &= ~SD_CARD;
 	chip->card_fail &= ~SD_CARD;
 	chip->card_wp &= ~SD_CARD;
 
-#ifdef SUPPORT_SD_LOCK
-	sd_card->sd_lock_status = 0;
-	sd_card->sd_erase_status = 0;
-#endif
-
 	memset(sd_card->raw_csd, 0, 16);
 	memset(sd_card->raw_scr, 0, 8);
 
diff --git a/drivers/staging/rts5139/sd.h b/drivers/staging/rts5139/sd.h
index 0805edc..de155d8 100644
--- a/drivers/staging/rts5139/sd.h
+++ b/drivers/staging/rts5139/sd.h
@@ -141,29 +141,6 @@
 #define	SWITCH_MODE_ERR	  0x06
 #define	SWITCH_PASS	  0x07
 
-#ifdef SUPPORT_SD_LOCK
-/* CMD42 Parameter */
-#define SD_ERASE		0x08
-#define SD_LOCK			0x04
-#define SD_UNLOCK		0x00
-#define SD_CLR_PWD		0x02
-#define SD_SET_PWD		0x01
-
-#define SD_PWD_LEN		0x10
-
-/* SD lock unlock Status */
-#define SD_LOCKED		0x80	/* Global lock status */
-#define SD_LOCK_1BIT_MODE	0x40 /**/
-#define SD_PWD_EXIST		0x20
-#define SD_UNLOCK_POW_ON	0x01 /**/
-#define SD_SDR_RST		0x02 /* Reset SD30 card with current DDR mode to SDR mode. */
-/* g_bySDEraseStatus */
-#define SD_NOT_ERASE		0x00
-#define SD_UNDER_ERASING	0x01
-#define SD_COMPLETE_ERASE	0x02
-/* SD_RW FAIL status */
-#define SD_RW_FORBIDDEN		0x0F	/* read/write is forbidden (SD card)  */
-#endif
 /* Function Group Definition */
 /* Function Group 1 */
 #define	HS_SUPPORT			0x01
@@ -282,17 +259,11 @@
 int sd_select_card(struct rts51x_chip *chip, int select);
 int reset_sd_card(struct rts51x_chip *chip);
 int sd_switch_clock(struct rts51x_chip *chip);
-void sd_stop_seq_mode(struct rts51x_chip *chip);
 int sd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
 	  u16 sector_cnt);
 void sd_cleanup_work(struct rts51x_chip *chip);
-int sd_power_off_card3v3(struct rts51x_chip *chip);
 int release_sd_card(struct rts51x_chip *chip);
 
-#ifdef SUPPORT_SD_LOCK
-int sd_update_lock_status(struct rts51x_chip *chip);
-#endif
-
 #ifdef SUPPORT_CPRM
 extern int reset_sd(struct rts51x_chip *chip);
 extern int sd_check_data0_status(struct rts51x_chip *chip);
diff --git a/drivers/staging/rts5139/sd_cprm.c b/drivers/staging/rts5139/sd_cprm.c
index d5969d9..f8c6071 100644
--- a/drivers/staging/rts5139/sd_cprm.c
+++ b/drivers/staging/rts5139/sd_cprm.c
@@ -77,12 +77,7 @@
 	return STATUS_SUCCESS;
 }
 
-int soft_reset_sd_card(struct rts51x_chip *chip)
-{
-	return reset_sd(chip);
-}
-
-int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx,
+static int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx,
 			    u32 arg, u8 rsp_type, u8 *rsp, int rsp_len,
 			    int special_check)
 {
@@ -206,11 +201,7 @@
 			if (buf[1] & 0x80)
 				TRACE_RET(chip, STATUS_FAIL);
 		}
-#ifdef SUPPORT_SD_LOCK
-		if (buf[1] & 0x7D) {
-#else
 		if (buf[1] & 0x7F) {
-#endif
 			TRACE_RET(chip, STATUS_FAIL);
 		}
 		if (buf[2] & 0xF8)
@@ -233,7 +224,7 @@
 	return STATUS_SUCCESS;
 }
 
-int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type)
+static int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type)
 {
 	int retval, rsp_len;
 	u16 reg_addr;
@@ -305,26 +296,8 @@
 	retval = sd_switch_clock(chip);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-#ifdef SUPPORT_SD_LOCK
-	if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
-		if (CHK_MMC_8BIT(sd_card)) {
-			retval =
-			    rts51x_write_register(chip, SD_CFG1, 0x03,
-						  SD_BUS_WIDTH_8);
-			if (retval != STATUS_SUCCESS)
-				TRACE_RET(chip, TRANSPORT_FAILED);
-		} else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
-			retval =
-			    rts51x_write_register(chip, SD_CFG1, 0x03,
-						  SD_BUS_WIDTH_4);
-			if (retval != STATUS_SUCCESS)
-				TRACE_RET(chip, TRANSPORT_FAILED);
-		}
-	}
-#else
 	/* Set H/W SD/MMC Bus Width */
 	rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-#endif
 
 	if (standby) {
 		retval = sd_select_card(chip, 0);
@@ -350,12 +323,6 @@
 		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
 	}
-#ifdef SUPPORT_SD_LOCK
-	/* Get SD lock status */
-	retval = sd_update_lock_status(chip);
-	if (retval != STATUS_SUCCESS)
-		TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
-#endif
 
 	return TRANSPORT_GOOD;
 
@@ -399,21 +366,7 @@
 	retval = sd_switch_clock(chip);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-#ifdef SUPPORT_SD_LOCK
-	if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
-		if (CHK_MMC_8BIT(sd_card))
-			bus_width = SD_BUS_WIDTH_8;
-		else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card))
-			bus_width = SD_BUS_WIDTH_4;
-		else
-			bus_width = SD_BUS_WIDTH_1;
-	} else {
-		bus_width = SD_BUS_WIDTH_4;
-	}
-	RTS51X_DEBUGP("bus_width = %d\n", bus_width);
-#else
 	bus_width = SD_BUS_WIDTH_4;
-#endif
 
 	if (data_len < 512) {
 		retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
@@ -599,11 +552,6 @@
 	int cmd13_checkbit = 0, write_err = 0;
 	u8 rsp_type;
 	u32 i;
-#ifdef SUPPORT_SD_LOCK
-	int lock_cmd_fail = 0;
-	u8 sd_lock_state = 0;
-	u8 lock_cmd_type = 0;
-#endif
 
 	if (sd_card->pre_cmd_err) {
 		sd_card->pre_cmd_err = 0;
@@ -614,12 +562,6 @@
 	retval = sd_switch_clock(chip);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-#ifdef SUPPORT_SD_LOCK
-	if (cmd_idx == LOCK_UNLOCK) {
-		sd_lock_state = sd_card->sd_lock_status;
-		sd_lock_state &= SD_LOCKED;
-	}
-#endif
 
 	retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len);
 	if (retval != STATUS_SUCCESS) {
@@ -631,25 +573,7 @@
 	retval = sd_switch_clock(chip);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-#ifdef SUPPORT_SD_LOCK
-	if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
-		if (CHK_MMC_8BIT(sd_card)) {
-			retval =
-			    rts51x_write_register(chip, SD_CFG1, 0x03,
-						  SD_BUS_WIDTH_8);
-			if (retval != STATUS_SUCCESS)
-				TRACE_RET(chip, TRANSPORT_FAILED);
-		} else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
-			retval =
-			    rts51x_write_register(chip, SD_CFG1, 0x03,
-						  SD_BUS_WIDTH_4);
-			if (retval != STATUS_SUCCESS)
-				TRACE_RET(chip, TRANSPORT_FAILED);
-		}
-	}
-#else
 	rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-#endif
 
 	if (data_len < 512) {
 		retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
@@ -692,10 +616,6 @@
 		else
 			memcpy(buf, data_buf, data_len);
 
-#ifdef SUPPORT_SD_LOCK
-		if (cmd_idx == LOCK_UNLOCK)
-			lock_cmd_type = buf[0] & 0x0F;
-#endif
 
 		if (data_len > 256) {
 			rts51x_init_cmd(chip);
@@ -802,29 +722,6 @@
 				      SD_STOP | SD_CLR_ERR);
 		TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
 	}
-#ifdef SUPPORT_SD_LOCK
-	if (cmd_idx == LOCK_UNLOCK) {
-		if (lock_cmd_type == SD_ERASE) {
-			sd_card->sd_erase_status = SD_UNDER_ERASING;
-			scsi_set_resid(srb, 0);
-			return TRANSPORT_GOOD;
-		}
-
-		rts51x_init_cmd(chip);
-		rts51x_add_cmd(chip, CHECK_REG_CMD, SD_BUS_STAT, SD_DAT0_STATUS,
-			       SD_DAT0_STATUS);
-		retval = rts51x_send_cmd(chip, MODE_CR, 250);
-		if (retval != STATUS_SUCCESS)
-			TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-		rts51x_get_rsp(chip, 1, 200); /* Don't care return value */
-
-		retval = sd_update_lock_status(chip);
-		if (retval != STATUS_SUCCESS) {
-			RTS51X_DEBUGP("Lock command fail!\n");
-			lock_cmd_fail = 1;
-		}
-	}
-#endif /* SUPPORT_SD_LOCK */
 
 	if (standby) {
 		retval = sd_select_card(chip, 1);
@@ -865,51 +762,6 @@
 	}
 	if (retval != STATUS_SUCCESS)
 		TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-#ifdef SUPPORT_SD_LOCK
-	if (cmd_idx == LOCK_UNLOCK) {
-		if (!lock_cmd_fail) {
-			RTS51X_DEBUGP("lock_cmd_type = 0x%x\n",
-				       lock_cmd_type);
-			if (lock_cmd_type & SD_CLR_PWD)
-				sd_card->sd_lock_status &= ~SD_PWD_EXIST;
-			if (lock_cmd_type & SD_SET_PWD)
-				sd_card->sd_lock_status |= SD_PWD_EXIST;
-		}
-
-		RTS51X_DEBUGP("sd_lock_state = 0x%x,"
-				"sd_card->sd_lock_status = 0x%x\n",
-				sd_lock_state, sd_card->sd_lock_status);
-		if (sd_lock_state ^ (sd_card->sd_lock_status & SD_LOCKED)) {
-			sd_card->sd_lock_notify = 1;
-			if (sd_lock_state) {
-				if (sd_card->sd_lock_status &
-						SD_LOCK_1BIT_MODE) {
-					sd_card->sd_lock_status |=
-					    (SD_UNLOCK_POW_ON | SD_SDR_RST);
-					if (CHK_SD(sd_card)) {
-						retval = reset_sd(chip);
-						if (retval != STATUS_SUCCESS) {
-							sd_card->sd_lock_status
-							&= ~(SD_UNLOCK_POW_ON |
-							      SD_SDR_RST);
-							TRACE_GOTO(chip,
-								   SD_Execute_Write_Cmd_Failed);
-						}
-					}
-
-					sd_card->sd_lock_status &=
-					    ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
-				}
-			}
-		}
-	}
-
-	if (lock_cmd_fail) {
-		scsi_set_resid(srb, 0);
-		set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
-		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
-#endif /* SUPPORT_SD_LOCK */
 
 	return TRANSPORT_GOOD;
 
@@ -1173,30 +1025,18 @@
 	switch (srb->cmnd[1] & 0x0F) {
 	case 0:
 		/* SD Card Power Off -> ON and Initialization */
-#ifdef SUPPORT_SD_LOCK
-		if (0x64 == srb->cmnd[9]) {
-			/* Command Mode */
-			sd_card->sd_lock_status |= SD_SDR_RST;
-		}
-#endif /* SUPPORT_SD_LOCK */
 		retval = reset_sd_card(chip);
 		if (retval != STATUS_SUCCESS) {
-#ifdef SUPPORT_SD_LOCK
-			sd_card->sd_lock_status &= ~SD_SDR_RST;
-#endif
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
 			sd_card->pre_cmd_err = 1;
 			TRACE_RET(chip, TRANSPORT_FAILED);
 		}
-#ifdef SUPPORT_SD_LOCK
-		sd_card->sd_lock_status &= ~SD_SDR_RST;
-#endif
 		break;
 
 	case 1:
 		/* reset CMD(CMD0) and Initialization
 		 * (without SD Card Power Off -> ON) */
-		retval = soft_reset_sd_card(chip);
+		retval = reset_sd(chip);
 		if (retval != STATUS_SUCCESS) {
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
 			sd_card->pre_cmd_err = 1;
diff --git a/drivers/staging/rts5139/xd.c b/drivers/staging/rts5139/xd.c
index 5820605..58f8ba2 100644
--- a/drivers/staging/rts5139/xd.c
+++ b/drivers/staging/rts5139/xd.c
@@ -47,13 +47,6 @@
 	xd_card->err_code = err_code;
 }
 
-static inline int xd_check_err_code(struct rts51x_chip *chip, u8 err_code)
-{
-	struct xd_info *xd_card = &(chip->xd_card);
-
-	return (xd_card->err_code == err_code);
-}
-
 static int xd_set_init_para(struct rts51x_chip *chip)
 {
 	struct xd_info *xd_card = &(chip->xd_card);
@@ -862,6 +855,8 @@
 	zone->l2p_table[log_off] = phy_off;
 }
 
+static int xd_delay_write(struct rts51x_chip *chip);
+
 static u32 xd_get_l2p_tbl(struct rts51x_chip *chip, int zone_no, u16 log_off)
 {
 	struct xd_info *xd_card = &(chip->xd_card);
@@ -1182,91 +1177,6 @@
 	return STATUS_SUCCESS;
 }
 
-#ifdef XD_SPEEDUP
-static int xd_auto_copy_page(struct rts51x_chip *chip,
-			     u32 old_blk, u32 new_blk,
-			     u8 start_page, u8 end_page)
-{
-	struct xd_info *xd_card = &(chip->xd_card);
-	u32 old_page, new_page;
-	int retval;
-	u8 page_count;
-
-	RTS51X_DEBUGP("Auto copy page from block 0x%x to block 0x%x\n",
-		       old_blk, new_blk);
-
-	if (start_page > end_page)
-		TRACE_RET(chip, STATUS_FAIL);
-
-	page_count = end_page - start_page;
-
-	if ((old_blk == BLK_NOT_FOUND) || (new_blk == BLK_NOT_FOUND))
-		TRACE_RET(chip, STATUS_FAIL);
-
-	old_page = (old_blk << xd_card->block_shift) + start_page;
-	new_page = (new_blk << xd_card->block_shift) + start_page;
-
-	XD_CLR_BAD_NEWBLK(xd_card);
-
-	rts51x_init_cmd(chip);
-
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WAITTIME, 0x03, WAIT_FF);
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_PAGELEN, 0xFF, page_count);
-
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR0, 0xFF, 0);
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR1, 0xFF,
-		       (u8) old_page);
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR2, 0xFF,
-		       (u8) (old_page >> 8));
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR3, 0xFF,
-		       (u8) (old_page >> 16));
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR4, 0xFF, 0);
-
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR0, 0xFF, 0);
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR1, 0xFF,
-		       (u8) new_page);
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR2, 0xFF,
-		       (u8) (new_page >> 8));
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR3, 0xFF,
-		       (u8) (new_page >> 16));
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR4, 0xFF, 0);
-
-	rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
-		       PINGPONG_BUFFER);
-
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG,
-		       XD_BA_TRANSFORM | XD_ADDR_MASK, 0 | xd_card->addr_cycle);
-
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS,
-		       XD_AUTO_CHK_DATA_STATUS, 0);
-	rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
-		       XD_TRANSFER_START | XD_COPY_PAGES);
-	rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
-		       XD_TRANSFER_END);
-
-	retval = rts51x_send_cmd(chip, MODE_CR, 100);
-	if (retval != STATUS_SUCCESS) {
-		rts51x_clear_xd_error(chip);
-		TRACE_GOTO(chip, Copy_Fail);
-	}
-
-	retval = rts51x_get_rsp(chip, 1, 800);
-	if (retval != STATUS_SUCCESS) {
-		rts51x_clear_xd_error(chip);
-		TRACE_GOTO(chip, Copy_Fail);
-	}
-
-	return STATUS_SUCCESS;
-
-Copy_Fail:
-	retval = xd_copy_page(chip, old_blk, new_blk, start_page, end_page);
-	if (retval != STATUS_SUCCESS)
-		TRACE_RET(chip, retval);
-
-	return STATUS_SUCCESS;
-}
-#endif
-
 static int xd_reset_cmd(struct rts51x_chip *chip)
 {
 	int retval;
@@ -1686,15 +1596,9 @@
 			XD_CLR_BAD_OLDBLK(xd_card);
 			TRACE_RET(chip, STATUS_FAIL);
 		}
-#ifdef XD_SPEEDUP
-		retval =
-		    xd_auto_copy_page(chip, phy_blk, new_blk, 0,
-				      xd_card->page_off + 1);
-#else
 		retval =
 		    xd_copy_page(chip, phy_blk, new_blk, 0,
 				 xd_card->page_off + 1);
-#endif
 		if (retval != STATUS_SUCCESS) {
 			if (!XD_CHK_BAD_NEWBLK(xd_card)) {
 				retval = xd_erase_block(chip, new_blk);
@@ -1741,13 +1645,8 @@
 			TRACE_RET(chip, STATUS_FAIL);
 		}
 	} else {
-#ifdef XD_SPEEDUP
-		retval = xd_auto_copy_page(chip, old_blk, new_blk,
-					   page_off, xd_card->page_off + 1);
-#else
 		retval = xd_copy_page(chip, old_blk, new_blk,
 				      page_off, xd_card->page_off + 1);
-#endif
 		if (retval != STATUS_SUCCESS) {
 			if (!XD_CHK_BAD_NEWBLK(xd_card)) {
 				retval = xd_erase_block(chip, new_blk);
@@ -1789,11 +1688,7 @@
 				old_blk, new_blk, log_blk, (int)page_off);
 
 	if (page_off) {
-#ifdef XD_SPEEDUP
-		retval = xd_auto_copy_page(chip, old_blk, new_blk, 0, page_off);
-#else
 		retval = xd_copy_page(chip, old_blk, new_blk, 0, page_off);
-#endif
 		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, retval);
 	}
@@ -1922,7 +1817,7 @@
 	TRACE_RET(chip, STATUS_FAIL);
 }
 
-int xd_delay_write(struct rts51x_chip *chip)
+static int xd_delay_write(struct rts51x_chip *chip)
 {
 	struct xd_info *xd_card = &(chip->xd_card);
 	struct xd_delay_write_tag *delay_write = &(xd_card->delay_write);
@@ -1999,18 +1894,11 @@
 		    (start_page > delay_write->pageoff)) {
 			delay_write->delay_write_flag = 0;
 			if (delay_write->old_phyblock != BLK_NOT_FOUND) {
-#ifdef XD_SPEEDUP
-				retval = xd_auto_copy_page(chip,
-					delay_write->old_phyblock,
-					delay_write->new_phyblock,
-					delay_write->pageoff, start_page);
-#else
 				retval = xd_copy_page(chip,
 						      delay_write->old_phyblock,
 						      delay_write->new_phyblock,
 						      delay_write->pageoff,
 						      start_page);
-#endif
 				if (retval != STATUS_SUCCESS) {
 					set_sense_type(chip, lun,
 						SENSE_TYPE_MEDIA_WRITE_ERR);
@@ -2198,7 +2086,7 @@
 	}
 }
 
-int xd_power_off_card3v3(struct rts51x_chip *chip)
+static int xd_power_off_card3v3(struct rts51x_chip *chip)
 {
 	int retval;
 
@@ -2232,7 +2120,7 @@
 	struct xd_info *xd_card = &(chip->xd_card);
 	int retval;
 
-	RTS51X_DEBUGP("elease_xd_card\n");
+	RTS51X_DEBUGP("release_xd_card\n");
 
 	chip->card_ready &= ~XD_CARD;
 	chip->card_fail &= ~XD_CARD;
diff --git a/drivers/staging/rts5139/xd.h b/drivers/staging/rts5139/xd.h
index fa69590..55e4205 100644
--- a/drivers/staging/rts5139/xd.h
+++ b/drivers/staging/rts5139/xd.h
@@ -182,12 +182,10 @@
 #define	CIS1_9			(256 + 9)
 
 int reset_xd_card(struct rts51x_chip *chip);
-int xd_delay_write(struct rts51x_chip *chip);
 int xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
 	  u16 sector_cnt);
 void xd_free_l2p_tbl(struct rts51x_chip *chip);
 void xd_cleanup_work(struct rts51x_chip *chip);
-int xd_power_off_card3v3(struct rts51x_chip *chip);
 int release_xd_card(struct rts51x_chip *chip);
 
 #endif /* __RTS51X_XD_H */
diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c
index f9a4498..0bf6d95 100644
--- a/drivers/staging/rts_pstor/ms.c
+++ b/drivers/staging/rts_pstor/ms.c
@@ -4136,7 +4136,7 @@
 #else
 	retval = ms_transfer_data(chip, MS_TM_AUTO_WRITE, PRO_WRITE_LONG_DATA,
 				2, WAIT_INT, 0, 0, buf + 4, 1024);
-	if ((retval != STATUS_SUCCESS) || check_ms_err(chip) {
+	if ((retval != STATUS_SUCCESS) || check_ms_err(chip)) {
 		rtsx_clear_ms_error(chip);
 		if (ms_card->mg_auth == 0) {
 			if ((buf[5] & 0xC0) != 0) {
diff --git a/drivers/staging/rts_pstor/rtsx_transport.c b/drivers/staging/rts_pstor/rtsx_transport.c
index 9b2e5c9..54a4742 100644
--- a/drivers/staging/rts_pstor/rtsx_transport.c
+++ b/drivers/staging/rts_pstor/rtsx_transport.c
@@ -130,7 +130,7 @@
 /* Store the contents of buffer into srb's transfer buffer and set the
 * SCSI residue. */
 void rtsx_stor_set_xfer_buf(unsigned char *buffer,
-       unsigned int buflen, struct scsi_cmnd *srb)
+	unsigned int buflen, struct scsi_cmnd *srb)
 {
 	unsigned int index = 0, offset = 0;
 
@@ -141,7 +141,7 @@
 }
 
 void rtsx_stor_get_xfer_buf(unsigned char *buffer,
-       unsigned int buflen, struct scsi_cmnd *srb)
+	unsigned int buflen, struct scsi_cmnd *srb)
 {
 	unsigned int index = 0, offset = 0;
 
diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h
index fa7c0d0..9d9fc7c 100644
--- a/drivers/staging/sep/sep_driver_config.h
+++ b/drivers/staging/sep/sep_driver_config.h
@@ -68,11 +68,11 @@
 #define SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE		16
 
 /* flag that signifies tah the lock is
-currently held by the proccess (struct file) */
+currently held by the process (struct file) */
 #define SEP_DRIVER_OWN_LOCK_FLAG                        1
 
 /* flag that signifies tah the lock is currently NOT
-held by the proccess (struct file) */
+held by the process (struct file) */
 #define SEP_DRIVER_DISOWN_LOCK_FLAG                     0
 
 /* indicates whether driver has mapped/unmapped shared area */
@@ -280,7 +280,7 @@
 
 /*
  * Used to limit number of concurrent processes
- * allowed to allocte dynamic buffers in fastcall
+ * allowed to allocate dynamic buffers in fastcall
  * interface.
  */
 #define SEP_DOUBLEBUF_USERS_LIMIT		3
diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c
index f1701bc..df1d13e 100644
--- a/drivers/staging/sep/sep_main.c
+++ b/drivers/staging/sep/sep_main.c
@@ -786,7 +786,7 @@
 		"[PID%d] poll: send_ct is %lx reply ct is %lx\n",
 			current->pid, sep->send_ct, sep->reply_ct);
 
-	/* Check if error occured during poll */
+	/* Check if error occurred during poll */
 	retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
 	if ((retval2 != 0x0) && (retval2 != 0x8)) {
 		dev_dbg(&sep->pdev->dev, "[PID%d] poll; poll error %x\n",
@@ -1160,7 +1160,7 @@
 
 	/* Put mapped kernel sg into kernel resource array */
 
-	/* Set output params acording to the in_out flag */
+	/* Set output params according to the in_out flag */
 	if (in_out_flag == SEP_DRIVER_IN_FLAG) {
 		*lli_array_ptr = lli_array;
 		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages =
@@ -1358,7 +1358,7 @@
 			lli_array[num_pages - 1].block_size);
 	}
 
-	/* Set output params acording to the in_out flag */
+	/* Set output params according to the in_out flag */
 	if (in_out_flag == SEP_DRIVER_IN_FLAG) {
 		*lli_array_ptr = lli_array;
 		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages =
@@ -2038,7 +2038,7 @@
 
 		/*
 		 * If this is not the last table -
-		 * then allign it to the block size
+		 * then align it to the block size
 		 */
 		if (!last_table_flag)
 			table_data_size =
@@ -3033,7 +3033,7 @@
  * @cmd: command
  * @arg: pointer to argument structure
  *
- * Implement the ioctl methods availble on the SEP device.
+ * Implement the ioctl methods available on the SEP device.
  */
 static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
@@ -4460,7 +4460,7 @@
  * @sep_pm_runtime_resume:	resume- no communication with cpu & main memory
  * @sep_pm_runtime_suspend:	suspend- no communication with cpu & main memory
  * @sep_pci_suspend:		suspend - main memory is still ON
- * @sep_pci_resume:		resume - main meory is still ON
+ * @sep_pci_resume:		resume - main memory is still ON
  */
 static const struct dev_pm_ops sep_pm = {
 	.runtime_resume = sep_pm_runtime_resume,
diff --git a/drivers/staging/serial/68360serial.c b/drivers/staging/serial/68360serial.c
deleted file mode 100644
index daf0b1d..0000000
--- a/drivers/staging/serial/68360serial.c
+++ /dev/null
@@ -1,2979 +0,0 @@
-/*
- *  UART driver for 68360 CPM SCC or SMC
- *  Copyright (c) 2000 D. Jeff Dionne <jeff@uclinux.org>,
- *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.ca>
- *  Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
- *
- * I used the serial.c driver as the framework for this driver.
- * Give credit to those guys.
- * The original code was written for the MBX860 board.  I tried to make
- * it generic, but there may be some assumptions in the structures that
- * have to be fixed later.
- * To save porting time, I did not bother to change any object names
- * that are not accessed outside of this file.
- * It still needs lots of work........When it was easy, I included code
- * to support the SCCs, but this has never been tested, nor is it complete.
- * Only the SCCs support modem control, so that is not complete either.
- *
- * This module exports the following rs232 io functions:
- *
- *	int rs_360_init(void);
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serialP.h> 
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-#include <asm/m68360.h>
-#include <asm/commproc.h>
-
- 
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern void set_debug_traps(void);
-extern int  kgdb_output_string (const char* s, unsigned int count);
-#endif
-
-
-/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */
-#include <linux/console.h>
-#include <linux/jiffies.h>
-
-/* this defines the index into rs_table for the port to use
- */
-#ifndef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT	1 /* ie SMC2 - note USE_SMC2 must be defined */
-#endif
-/* #endif */
-
-#if 0
-/* SCC2 for console
- */
-#undef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT	2
-#endif
-
-
-#define TX_WAKEUP	ASYNC_SHARE_IRQ
-
-static char *serial_name = "CPM UART driver";
-static char *serial_version = "0.03";
-
-static struct tty_driver *serial_driver;
-int serial_console_setup(struct console *co, char *options);
-
-/*
- * Serial driver configuration section.  Here are the various options:
- */
-#define SERIAL_PARANOIA_CHECK
-#define CONFIG_SERIAL_NOPAUSE_IO
-#define SERIAL_DO_RESTART
-
-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-
-#define _INLINE_ inline
-  
-#define DBG_CNT(s)
-
-/* We overload some of the items in the data structure to meet our
- * needs.  For example, the port address is the CPM parameter ram
- * offset for the SCC or SMC.  The maximum number of ports is 4 SCCs and
- * 2 SMCs.  The "hub6" field is used to indicate the channel number, with
- * a flag indicating SCC or SMC, and the number is used as an index into
- * the CPM parameter area for this device.
- * The "type" field is currently set to 0, for PORT_UNKNOWN.  It is
- * not currently used.  I should probably use it to indicate the port
- * type of SMC or SCC.
- * The SMCs do not support any modem control signals.
- */
-#define smc_scc_num	hub6
-#define NUM_IS_SCC	((int)0x00010000)
-#define PORT_NUM(P)	((P) & 0x0000ffff)
-
-
-#if defined (CONFIG_UCQUICC)
-
-volatile extern void *_periph_base;
-/* sipex transceiver
- *   mode bits for       are on pins
- *
- *    SCC2                d16..19
- *    SCC3                d20..23
- *    SCC4                d24..27
- */
-#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1)))
-
-static uint sipex_mode_bits = 0x00000000;
-
-#endif
-
-/* There is no `serial_state' defined back here in 2.0.
- * Try to get by with serial_struct
- */
-/* #define serial_state serial_struct */
-
-/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few
- * extras: */
-
-#if 0
-struct async_icount_24 {
-	__u32   cts, dsr, rng, dcd, tx, rx;
-	__u32   frame, parity, overrun, brk;
-	__u32   buf_overrun;
-} icount;
-#endif
-
-#if 0
-
-struct serial_state {
-        int     magic;
-        int     baud_base;
-        unsigned long   port;
-        int     irq;
-        int     flags;
-        int     hub6;
-        int     type;
-        int     line;
-        int     revision;       /* Chip revision (950) */
-        int     xmit_fifo_size;
-        int     custom_divisor;
-        int     count;
-        u8      *iomem_base;
-        u16     iomem_reg_shift;
-        unsigned short  close_delay;
-        unsigned short  closing_wait; /* time to wait before closing */
-        struct async_icount_24     icount; 
-        int     io_type;
-        struct async_struct *info;
-};
-#endif
-
-#define SSTATE_MAGIC 0x5302
-
-
-
-/* SMC2 is sometimes used for low performance TDM interfaces.  Define
- * this as 1 if you want SMC2 as a serial port UART managed by this driver.
- * Define this as 0 if you wish to use SMC2 for something else.
- */
-#define USE_SMC2 1
-
-#if 0
-/* Define SCC to ttySx mapping. */
-#define SCC_NUM_BASE	(USE_SMC2 + 1)	/* SCC base tty "number" */
-
-/* Define which SCC is the first one to use for a serial port.  These
- * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
- * for Ethernet, and the first available SCC for serial UART is SCC2.
- * NOTE:  IF YOU CHANGE THIS, you have to change the PROFF_xxx and
- * interrupt vectors in the table below to match.
- */
-#define SCC_IDX_BASE	1	/* table index */
-#endif
-
-
-/* Processors other than the 860 only get SMCs configured by default.
- * Either they don't have SCCs or they are allocated somewhere else.
- * Of course, there are now 860s without some SCCs, so we will need to
- * address that someday.
- * The Embedded Planet Multimedia I/O cards use TDM interfaces to the
- * stereo codec parts, and we use SMC2 to help support that.
- */
-static struct serial_state rs_table[] = {
-/*  type   line   PORT           IRQ       FLAGS  smc_scc_num (F.K.A. hub6) */
-	{  0,     0, PRSLOT_SMC1, CPMVEC_SMC1,   0,    0 }    /* SMC1 ttyS0 */
-#if USE_SMC2
-	,{ 0,     0, PRSLOT_SMC2, CPMVEC_SMC2,   0,    1 }     /* SMC2 ttyS1 */
-#endif
-
-#if defined(CONFIG_SERIAL_68360_SCC)
-	,{ 0,     0, PRSLOT_SCC2, CPMVEC_SCC2,   0, (NUM_IS_SCC | 1) }    /* SCC2 ttyS2 */
-	,{ 0,     0, PRSLOT_SCC3, CPMVEC_SCC3,   0, (NUM_IS_SCC | 2) }    /* SCC3 ttyS3 */
-	,{ 0,     0, PRSLOT_SCC4, CPMVEC_SCC4,   0, (NUM_IS_SCC | 3) }    /* SCC4 ttyS4 */
-#endif
-};
-
-#define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
-
-/* The number of buffer descriptors and their sizes.
- */
-#define RX_NUM_FIFO	4
-#define RX_BUF_SIZE	32
-#define TX_NUM_FIFO	4
-#define TX_BUF_SIZE	32
-
-#define CONSOLE_NUM_FIFO 2
-#define CONSOLE_BUF_SIZE 4
-
-char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE];
-
-/* The async_struct in serial.h does not really give us what we
- * need, so define our own here.
- */
-typedef struct serial_info {
-	int			magic;
-	int			flags;
-
-	struct serial_state	*state;
- 	/* struct serial_struct	*state; */
- 	/* struct async_struct	*state; */
-	
-	struct tty_struct 	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			timeout;
-	int			line;
-	int			x_char;	/* xon/xoff character */
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
-	unsigned long		event;
-	unsigned long		last_active;
-	int			blocked_open; /* # of blocked opens */
-	struct work_struct	tqueue;
-	struct work_struct	tqueue_hangup;
- 	wait_queue_head_t	open_wait; 
- 	wait_queue_head_t	close_wait; 
-
-	
-/* CPM Buffer Descriptor pointers.
-	*/
-	QUICC_BD			*rx_bd_base;
-	QUICC_BD			*rx_cur;
-	QUICC_BD			*tx_bd_base;
-	QUICC_BD			*tx_cur;
-} ser_info_t;
-
-
-/* since kmalloc_init() does not get called until much after this initialization: */
-static ser_info_t  quicc_ser_info[NR_PORTS];
-static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE];
-static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE];
-
-static void change_speed(ser_info_t *info);
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static inline int serial_paranoia_check(ser_info_t *info,
-					char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-	static const char *badmagic =
-		"Warning: bad magic number for serial struct (%s) in %s\n";
-	static const char *badinfo =
-		"Warning: null async_struct for (%s) in %s\n";
-
-	if (!info) {
-		printk(badinfo, name, routine);
-		return 1;
-	}
-	if (info->magic != SERIAL_MAGIC) {
-		printk(badmagic, name, routine);
-		return 1;
-	}
-#endif
-	return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts,
- * indexed by the termio value.  The generic CPM functions are responsible
- * for setting and assigning baud rate generators for us.
- */
-static int baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-
-/* This sucks. There is a better way: */
-#if defined(CONFIG_CONSOLE_9600)
-  #define CONSOLE_BAUDRATE 9600
-#elif defined(CONFIG_CONSOLE_19200)
-  #define CONSOLE_BAUDRATE 19200
-#elif defined(CONFIG_CONSOLE_115200)
-  #define CONSOLE_BAUDRATE 115200
-#else
-  #warning "console baud rate undefined"
-  #define CONSOLE_BAUDRATE 9600
-#endif
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_360_stop(struct tty_struct *tty)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	int	idx;
-	unsigned long flags;
- 	volatile struct scc_regs *sccp;
- 	volatile struct smc_regs *smcp;
-
-	if (serial_paranoia_check(info, tty->name, "rs_stop"))
-		return;
-	
-	local_irq_save(flags);
-	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
-		sccp = &pquicc->scc_regs[idx];
-		sccp->scc_sccm &= ~UART_SCCM_TX;
-	} else {
-		/* smcp = &cpmp->cp_smc[idx]; */
-		smcp = &pquicc->smc_regs[idx];
-		smcp->smc_smcm &= ~SMCM_TX;
-	}
-	local_irq_restore(flags);
-}
-
-
-static void rs_360_start(struct tty_struct *tty)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	int	idx;
-	unsigned long flags;
-	volatile struct scc_regs *sccp;
-	volatile struct smc_regs *smcp;
-
-	if (serial_paranoia_check(info, tty->name, "rs_stop"))
-		return;
-	
-	local_irq_save(flags);
-	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
-		sccp = &pquicc->scc_regs[idx];
-		sccp->scc_sccm |= UART_SCCM_TX;
-	} else {
-		smcp = &pquicc->smc_regs[idx];
-		smcp->smc_smcm |= SMCM_TX;
-	}
-	local_irq_restore(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- * 
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-static _INLINE_ void receive_chars(ser_info_t *info)
-{
-	struct tty_struct *tty = info->port.tty;
-	unsigned char ch, flag, *cp;
-	/*int	ignored = 0;*/
-	int	i;
-	ushort	status;
-	 struct	async_icount *icount; 
-	/* struct	async_icount_24 *icount; */
-	volatile QUICC_BD	*bdp;
-
-	icount = &info->state->icount;
-
-	/* Just loop through the closed BDs and copy the characters into
-	 * the buffer.
-	 */
-	bdp = info->rx_cur;
-	for (;;) {
-		if (bdp->status & BD_SC_EMPTY)	/* If this one is empty */
-			break;			/*   we are all done */
-
-		/* The read status mask tell us what we should do with
-		 * incoming characters, especially if errors occur.
-		 * One special case is the use of BD_SC_EMPTY.  If
-		 * this is not set, we are supposed to be ignoring
-		 * inputs.  In this case, just mark the buffer empty and
-		 * continue.
-		 */
-		if (!(info->read_status_mask & BD_SC_EMPTY)) {
-			bdp->status |= BD_SC_EMPTY;
-			bdp->status &=
-				~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
-			if (bdp->status & BD_SC_WRAP)
-				bdp = info->rx_bd_base;
-			else
-				bdp++;
-			continue;
-		}
-
-		/* Get the number of characters and the buffer pointer.
-		*/
-		i = bdp->length;
-		/* cp = (unsigned char *)__va(bdp->buf); */
-		cp = (char *)bdp->buf;
-		status = bdp->status;
-
-		while (i-- > 0) {
-			ch = *cp++;
-			icount->rx++;
-
-#ifdef SERIAL_DEBUG_INTR
-			printk("DR%02x:%02x...", ch, status);
-#endif
-			flag = TTY_NORMAL;
-
-			if (status & (BD_SC_BR | BD_SC_FR |
-				       BD_SC_PR | BD_SC_OV)) {
-				/*
-				 * For statistics only
-				 */
-				if (status & BD_SC_BR)
-					icount->brk++;
-				else if (status & BD_SC_PR)
-					icount->parity++;
-				else if (status & BD_SC_FR)
-					icount->frame++;
-				if (status & BD_SC_OV)
-					icount->overrun++;
-
-				/*
-				 * Now check to see if character should be
-				 * ignored, and mask off conditions which
-				 * should be ignored.
-				if (status & info->ignore_status_mask) {
-					if (++ignored > 100)
-						break;
-					continue;
-				}
-				 */
-				status &= info->read_status_mask;
-		
-				if (status & (BD_SC_BR)) {
-#ifdef SERIAL_DEBUG_INTR
-					printk("handling break....");
-#endif
-					*tty->flip.flag_buf_ptr = TTY_BREAK;
-					if (info->flags & ASYNC_SAK)
-						do_SAK(tty);
-				} else if (status & BD_SC_PR)
-					flag = TTY_PARITY;
-				else if (status & BD_SC_FR)
-					flag = TTY_FRAME;
-			}
-			tty_insert_flip_char(tty, ch, flag);
-			if (status & BD_SC_OV)
-				/*
-				 * Overrun is special, since it's
-				 * reported immediately, and doesn't
-				 * affect the current character
-				 */
-				tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
-
-		/* This BD is ready to be used again.  Clear status.
-		 * Get next BD.
-		 */
-		bdp->status |= BD_SC_EMPTY;
-		bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
-		if (bdp->status & BD_SC_WRAP)
-			bdp = info->rx_bd_base;
-		else
-			bdp++;
-	}
-
-	info->rx_cur = (QUICC_BD *)bdp;
-
-	tty_schedule_flip(tty);
-}
-
-static _INLINE_ void receive_break(ser_info_t *info)
-{
-	struct tty_struct *tty = info->port.tty;
-
-	info->state->icount.brk++;
-	/* Check to see if there is room in the tty buffer for
-	 * the break.  If not, we exit now, losing the break.  FIXME
-	 */
-	tty_insert_flip_char(tty, 0, TTY_BREAK);
-	tty_schedule_flip(tty);
-}
-
-static _INLINE_ void transmit_chars(ser_info_t *info)
-{
-
-	if ((info->flags & TX_WAKEUP) ||
-	    (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
-		schedule_work(&info->tqueue);
-	}
-
-#ifdef SERIAL_DEBUG_INTR
-	printk("THRE...");
-#endif
-}
-
-#ifdef notdef
-	/* I need to do this for the SCCs, so it is left as a reminder.
-	*/
-static _INLINE_ void check_modem_status(struct async_struct *info)
-{
-	int	status;
-	/* struct	async_icount *icount; */
-	struct	async_icount_24 *icount;
-	
-	status = serial_in(info, UART_MSR);
-
-	if (status & UART_MSR_ANY_DELTA) {
-		icount = &info->state->icount;
-		/* update input line counters */
-		if (status & UART_MSR_TERI)
-			icount->rng++;
-		if (status & UART_MSR_DDSR)
-			icount->dsr++;
-		if (status & UART_MSR_DDCD) {
-			icount->dcd++;
-#ifdef CONFIG_HARD_PPS
-			if ((info->flags & ASYNC_HARDPPS_CD) &&
-			    (status & UART_MSR_DCD))
-				hardpps();
-#endif
-		}
-		if (status & UART_MSR_DCTS)
-			icount->cts++;
-		wake_up_interruptible(&info->delta_msr_wait);
-	}
-
-	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
-		printk("ttys%d CD now %s...", info->line,
-		       (status & UART_MSR_DCD) ? "on" : "off");
-#endif		
-		if (status & UART_MSR_DCD)
-			wake_up_interruptible(&info->open_wait);
-		else {
-#ifdef SERIAL_DEBUG_OPEN
-			printk("scheduling hangup...");
-#endif
-			queue_task(&info->tqueue_hangup,
-					   &tq_scheduler);
-		}
-	}
-	if (info->flags & ASYNC_CTS_FLOW) {
-		if (info->port.tty->hw_stopped) {
-			if (status & UART_MSR_CTS) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-				printk("CTS tx start...");
-#endif
-				info->port.tty->hw_stopped = 0;
-				info->IER |= UART_IER_THRI;
-				serial_out(info, UART_IER, info->IER);
-				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-				return;
-			}
-		} else {
-			if (!(status & UART_MSR_CTS)) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-				printk("CTS tx stop...");
-#endif
-				info->port.tty->hw_stopped = 1;
-				info->IER &= ~UART_IER_THRI;
-				serial_out(info, UART_IER, info->IER);
-			}
-		}
-	}
-}
-#endif
-
-/*
- * This is the serial driver's interrupt routine for a single port
- */
-/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
-static void rs_360_interrupt(int vec, void *dev_id)
-{
-	u_char	events;
-	int	idx;
-	ser_info_t *info;
-	volatile struct smc_regs *smcp;
-	volatile struct scc_regs *sccp;
-	
-	info = dev_id;
-
-	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
-		sccp = &pquicc->scc_regs[idx];
-		events = sccp->scc_scce;
-		if (events & SCCM_RX)
-			receive_chars(info);
-		if (events & SCCM_TX)
-			transmit_chars(info);
-		sccp->scc_scce = events;
-	} else {
-		smcp = &pquicc->smc_regs[idx];
-		events = smcp->smc_smce;
-		if (events & SMCM_BRKE)
-			receive_break(info);
-		if (events & SMCM_RX)
-			receive_chars(info);
-		if (events & SMCM_TX)
-			transmit_chars(info);
-		smcp->smc_smce = events;
-	}
-	
-#ifdef SERIAL_DEBUG_INTR
-	printk("rs_interrupt_single(%d, %x)...",
-					info->state->smc_scc_num, events);
-#endif
-#ifdef modem_control
-	check_modem_status(info);
-#endif
-	info->last_active = jiffies;
-#ifdef SERIAL_DEBUG_INTR
-	printk("end.\n");
-#endif
-}
-
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-
-static void do_softint(void *private_)
-{
-	ser_info_t	*info = (ser_info_t *) private_;
-	struct tty_struct	*tty;
-	
-	tty = info->port.tty;
-	if (!tty)
-		return;
-
-	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-		tty_wakeup(tty);
-}
-
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- * 	serial interrupt routine -> (scheduler tqueue) ->
- * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
- * 
- */
-static void do_serial_hangup(void *private_)
-{
-	struct async_struct	*info = (struct async_struct *) private_;
-	struct tty_struct	*tty;
-	
-	tty = info->port.tty;
-	if (!tty)
-		return;
-
-	tty_hangup(tty);
-}
-
-
-static int startup(ser_info_t *info)
-{
-	unsigned long flags;
-	int	retval=0;
-	int	idx;
-	/*struct serial_state *state = info->state;*/
-	volatile struct smc_regs *smcp;
-	volatile struct scc_regs *sccp;
-	volatile struct smc_uart_pram	*up;
-	volatile struct uart_pram	    *scup;
-
-
-	local_irq_save(flags);
-
-	if (info->flags & ASYNC_INITIALIZED) {
-		goto errout;
-	}
-
-#ifdef maybe
-	if (!state->port || !state->type) {
-		if (info->port.tty)
-			set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-		goto errout;
-	}
-#endif
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttys%d (irq %d)...", info->line, state->irq);
-#endif
-
-
-#ifdef modem_control
-	info->MCR = 0;
-	if (info->port.tty->termios->c_cflag & CBAUD)
-		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#endif
-	
-	if (info->port.tty)
-		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-	/*
-	 * and set the speed of the serial port
-	 */
-	change_speed(info);
-
-	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
-		sccp = &pquicc->scc_regs[idx];
-		scup = &pquicc->pram[info->state->port].scc.pscc.u;
-
-		scup->mrblr = RX_BUF_SIZE;
-		scup->max_idl = RX_BUF_SIZE;
-
-		sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
-		sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
-	} else {
-		smcp = &pquicc->smc_regs[idx];
-
-		/* Enable interrupts and I/O.
-		*/
-		smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
-		smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
-
-		/* We can tune the buffer length and idle characters
-		 * to take advantage of the entire incoming buffer size.
-		 * If mrblr is something other than 1, maxidl has to be
-		 * non-zero or we never get an interrupt.  The maxidl
-		 * is the number of character times we wait after reception
-		 * of the last character before we decide no more characters
-		 * are coming.
-		 */
-		/* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */
-		/* holy unionized structures, Batman: */
-		up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
-		up->mrblr = RX_BUF_SIZE;
-		up->max_idl = RX_BUF_SIZE;
-
-		up->brkcr = 1;	/* number of break chars */
-	}
-
-	info->flags |= ASYNC_INITIALIZED;
-	local_irq_restore(flags);
-	return 0;
-	
-errout:
-	local_irq_restore(flags);
-	return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(ser_info_t *info)
-{
-	unsigned long	flags;
-	struct serial_state *state;
-	int		idx;
-	volatile struct smc_regs	*smcp;
-	volatile struct scc_regs	*sccp;
-
-	if (!(info->flags & ASYNC_INITIALIZED))
-		return;
-
-	state = info->state;
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("Shutting down serial port %d (irq %d)....", info->line,
-	       state->irq);
-#endif
-	
-	local_irq_save(flags);
-
-	idx = PORT_NUM(state->smc_scc_num);
-	if (state->smc_scc_num & NUM_IS_SCC) {
-		sccp = &pquicc->scc_regs[idx];
-		sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#ifdef CONFIG_SERIAL_CONSOLE
-		/* We can't disable the transmitter if this is the
-		 * system console.
-		 */
-		if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
-		sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
-	} else {
-		smcp = &pquicc->smc_regs[idx];
-
-		/* Disable interrupts and I/O.
-		 */
-		smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
-#ifdef CONFIG_SERIAL_CONSOLE
-		/* We can't disable the transmitter if this is the
-		 * system console.
-		 */
-		if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
-			smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-	}
-	
-	if (info->port.tty)
-		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-	info->flags &= ~ASYNC_INITIALIZED;
-	local_irq_restore(flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(ser_info_t *info)
-{
-	int	baud_rate;
-	unsigned cflag, cval, scval, prev_mode;
-	int	i, bits, sbits, idx;
-	unsigned long	flags;
-	struct serial_state *state;
-	volatile struct smc_regs	*smcp;
-	volatile struct scc_regs	*sccp;
-
-	if (!info->port.tty || !info->port.tty->termios)
-		return;
-	cflag = info->port.tty->termios->c_cflag;
-
-	state = info->state;
-
-	/* Character length programmed into the mode register is the
-	 * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
-	 * 1 or 2 stop bits, minus 1.
-	 * The value 'bits' counts this for us.
-	 */
-	cval = 0;
-	scval = 0;
-
-	/* byte size and parity */
-	switch (cflag & CSIZE) {
-	      case CS5: bits = 5; break;
-	      case CS6: bits = 6; break;
-	      case CS7: bits = 7; break;
-	      case CS8: bits = 8; break;
-	      /* Never happens, but GCC is too dumb to figure it out */
-	      default:  bits = 8; break;
-	}
-	sbits = bits - 5;
-
-	if (cflag & CSTOPB) {
-		cval |= SMCMR_SL;	/* Two stops */
-		scval |= SCU_PMSR_SL;
-		bits++;
-	}
-	if (cflag & PARENB) {
-		cval |= SMCMR_PEN;
-		scval |= SCU_PMSR_PEN;
-		bits++;
-	}
-	if (!(cflag & PARODD)) {
-		cval |= SMCMR_PM_EVEN;
-		scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
-	}
-
-	/* Determine divisor based on baud rate */
-	i = cflag & CBAUD;
-	if (i >= (sizeof(baud_table)/sizeof(int)))
-		baud_rate = 9600;
-	else
-		baud_rate = baud_table[i];
-
-	info->timeout = (TX_BUF_SIZE*HZ*bits);
-	info->timeout += HZ/50;		/* Add .02 seconds of slop */
-
-#ifdef modem_control
-	/* CTS flow control flag and modem status interrupts */
-	info->IER &= ~UART_IER_MSI;
-	if (info->flags & ASYNC_HARDPPS_CD)
-		info->IER |= UART_IER_MSI;
-	if (cflag & CRTSCTS) {
-		info->flags |= ASYNC_CTS_FLOW;
-		info->IER |= UART_IER_MSI;
-	} else
-		info->flags &= ~ASYNC_CTS_FLOW;
-	if (cflag & CLOCAL)
-		info->flags &= ~ASYNC_CHECK_CD;
-	else {
-		info->flags |= ASYNC_CHECK_CD;
-		info->IER |= UART_IER_MSI;
-	}
-	serial_out(info, UART_IER, info->IER);
-#endif
-
-	/*
-	 * Set up parity check flag
-	 */
-	info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
-	if (I_INPCK(info->port.tty))
-		info->read_status_mask |= BD_SC_FR | BD_SC_PR;
-	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
-		info->read_status_mask |= BD_SC_BR;
-	
-	/*
-	 * Characters to ignore
-	 */
-	info->ignore_status_mask = 0;
-	if (I_IGNPAR(info->port.tty))
-		info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
-	if (I_IGNBRK(info->port.tty)) {
-		info->ignore_status_mask |= BD_SC_BR;
-		/*
-		 * If we're ignore parity and break indicators, ignore 
-		 * overruns too.  (For real raw support).
-		 */
-		if (I_IGNPAR(info->port.tty))
-			info->ignore_status_mask |= BD_SC_OV;
-	}
-	/*
-	 * !!! ignore all characters if CREAD is not set
-	 */
-	if ((cflag & CREAD) == 0)
-	 info->read_status_mask &= ~BD_SC_EMPTY;
-	 local_irq_save(flags);
-
-	 /* Start bit has not been added (so don't, because we would just
-	  * subtract it later), and we need to add one for the number of
-	  * stops bits (there is always at least one).
-	  */
-	 bits++;
-	 idx = PORT_NUM(state->smc_scc_num);
-	 if (state->smc_scc_num & NUM_IS_SCC) {
-         sccp = &pquicc->scc_regs[idx];
-         sccp->scc_psmr = (sbits << 12) | scval;
-     } else {
-         smcp = &pquicc->smc_regs[idx];
-
-		/* Set the mode register.  We want to keep a copy of the
-		 * enables, because we want to put them back if they were
-		 * present.
-		 */
-		prev_mode = smcp->smc_smcmr;
-		smcp->smc_smcmr = smcr_mk_clen(bits) | cval |  SMCMR_SM_UART;
-		smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
-	}
-
-	m360_cpm_setbrg((state - rs_table), baud_rate);
-
-	local_irq_restore(flags);
-}
-
-static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	volatile QUICC_BD	*bdp;
-
-	if (serial_paranoia_check(info, tty->name, "rs_put_char"))
-		return 0;
-
-	if (!tty)
-		return 0;
-
-	bdp = info->tx_cur;
-	while (bdp->status & BD_SC_READY);
-
-	/* *((char *)__va(bdp->buf)) = ch; */
-	*((char *)bdp->buf) = ch;
-	bdp->length = 1;
-	bdp->status |= BD_SC_READY;
-
-	/* Get next BD.
-	*/
-	if (bdp->status & BD_SC_WRAP)
-		bdp = info->tx_bd_base;
-	else
-		bdp++;
-
-	info->tx_cur = (QUICC_BD *)bdp;
-	return 1;
-
-}
-
-static int rs_360_write(struct tty_struct * tty,
-		    const unsigned char *buf, int count)
-{
-	int	c, ret = 0;
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	volatile QUICC_BD *bdp;
-
-#ifdef CONFIG_KGDB
-	/* Try to let stub handle output. Returns true if it did. */ 
-	if (kgdb_output_string(buf, count))
-		return ret;
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "rs_write"))
-		return 0;
-
-	if (!tty) 
-		return 0;
-
-	bdp = info->tx_cur;
-
-	while (1) {
-		c = min(count, TX_BUF_SIZE);
-
-		if (c <= 0)
-			break;
-
-		if (bdp->status & BD_SC_READY) {
-			info->flags |= TX_WAKEUP;
-			break;
-		}
-
-		/* memcpy(__va(bdp->buf), buf, c); */
-		memcpy((void *)bdp->buf, buf, c);
-
-		bdp->length = c;
-		bdp->status |= BD_SC_READY;
-
-		buf += c;
-		count -= c;
-		ret += c;
-
-		/* Get next BD.
-		*/
-		if (bdp->status & BD_SC_WRAP)
-			bdp = info->tx_bd_base;
-		else
-			bdp++;
-		info->tx_cur = (QUICC_BD *)bdp;
-	}
-	return ret;
-}
-
-static int rs_360_write_room(struct tty_struct *tty)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	int	ret;
-
-	if (serial_paranoia_check(info, tty->name, "rs_write_room"))
-		return 0;
-
-	if ((info->tx_cur->status & BD_SC_READY) == 0) {
-		info->flags &= ~TX_WAKEUP;
-		ret = TX_BUF_SIZE;
-	}
-	else {
-		info->flags |= TX_WAKEUP;
-		ret = 0;
-	}
-	return ret;
-}
-
-/* I could track this with transmit counters....maybe later.
-*/
-static int rs_360_chars_in_buffer(struct tty_struct *tty)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-				
-	if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-		return 0;
-	return 0;
-}
-
-static void rs_360_flush_buffer(struct tty_struct *tty)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-				
-	if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-		return;
-
-	/* There is nothing to "flush", whatever we gave the CPM
-	 * is on its way out.
-	 */
-	tty_wakeup(tty);
-	info->flags &= ~TX_WAKEUP;
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void rs_360_send_xchar(struct tty_struct *tty, char ch)
-{
-	volatile QUICC_BD	*bdp;
-
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-
-	if (serial_paranoia_check(info, tty->name, "rs_send_char"))
-		return;
-
-	bdp = info->tx_cur;
-	while (bdp->status & BD_SC_READY);
-
-	/* *((char *)__va(bdp->buf)) = ch; */
-	*((char *)bdp->buf) = ch;
-	bdp->length = 1;
-	bdp->status |= BD_SC_READY;
-
-	/* Get next BD.
-	*/
-	if (bdp->status & BD_SC_WRAP)
-		bdp = info->tx_bd_base;
-	else
-		bdp++;
-
-	info->tx_cur = (QUICC_BD *)bdp;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_360_throttle(struct tty_struct * tty)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-	
-	printk("throttle %s: %d....\n", _tty_name(tty, buf),
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-		return;
-	
-	if (I_IXOFF(tty))
-		rs_360_send_xchar(tty, STOP_CHAR(tty));
-
-#ifdef modem_control
-	if (tty->termios->c_cflag & CRTSCTS)
-		info->MCR &= ~UART_MCR_RTS;
-
-	local_irq_disable();
-	serial_out(info, UART_MCR, info->MCR);
-	local_irq_enable();
-#endif
-}
-
-static void rs_360_unthrottle(struct tty_struct * tty)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-	
-	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-		return;
-	
-	if (I_IXOFF(tty)) {
-		if (info->x_char)
-			info->x_char = 0;
-		else
-			rs_360_send_xchar(tty, START_CHAR(tty));
-	}
-#ifdef modem_control
-	if (tty->termios->c_cflag & CRTSCTS)
-		info->MCR |= UART_MCR_RTS;
-	local_irq_disable();
-	serial_out(info, UART_MCR, info->MCR);
-	local_irq_enable();
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-#ifdef maybe
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * 	    is emptied.  On bus types like RS485, the transmitter must
- * 	    release the bus after transmitting. This must be done when
- * 	    the transmit shift register is empty, not be done when the
- * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct async_struct * info, unsigned int *value)
-{
-	unsigned char status;
-	unsigned int result;
-
-	local_irq_disable();
-	status = serial_in(info, UART_LSR);
-	local_irq_enable();
-	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-	return put_user(result,value);
-}
-#endif
-
-static int rs_360_tiocmget(struct tty_struct *tty)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	unsigned int result = 0;
-#ifdef modem_control
-	unsigned char control, status;
-
-	if (serial_paranoia_check(info, tty->name, __func__))
-		return -ENODEV;
-
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-
-	control = info->MCR;
-	local_irq_disable();
-	status = serial_in(info, UART_MSR);
-	local_irq_enable();
-	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
-		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
-#ifdef TIOCM_OUT1
-		| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
-		| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
-#endif
-		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
-		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
-		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
-		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
-#endif
-	return result;
-}
-
-static int rs_360_tiocmset(struct tty_struct *tty,
-			   unsigned int set, unsigned int clear)
-{
-#ifdef modem_control
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
- 	unsigned int arg;
-
-	if (serial_paranoia_check(info, tty->name, __func__))
-		return -ENODEV;
-
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-	/* FIXME: locking on info->mcr */
- 	if (set & TIOCM_RTS)
- 		info->mcr |= UART_MCR_RTS;
- 	if (set & TIOCM_DTR)
- 		info->mcr |= UART_MCR_DTR;
-	if (clear & TIOCM_RTS)
-		info->MCR &= ~UART_MCR_RTS;
-	if (clear & TIOCM_DTR)
-		info->MCR &= ~UART_MCR_DTR;
-
-#ifdef TIOCM_OUT1
-	if (set & TIOCM_OUT1)
-		info->MCR |= UART_MCR_OUT1;
-	if (set & TIOCM_OUT2)
-		info->MCR |= UART_MCR_OUT2;
-	if (clear & TIOCM_OUT1)
-		info->MCR &= ~UART_MCR_OUT1;
-	if (clear & TIOCM_OUT2)
-		info->MCR &= ~UART_MCR_OUT2;
-#endif
-
-	local_irq_disable();
-	serial_out(info, UART_MCR, info->MCR);
-	local_irq_enable();
-#endif
-	return 0;
-}
-
-/* Sending a break is a two step process on the SMC/SCC.  It is accomplished
- * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
- * command.  We take advantage of the begin/end functions to make this
- * happen.
- */
-static ushort	smc_chan_map[] = {
-	CPM_CR_CH_SMC1,
-	CPM_CR_CH_SMC2
-};
-
-static ushort	scc_chan_map[] = {
-	CPM_CR_CH_SCC1,
-	CPM_CR_CH_SCC2,
-	CPM_CR_CH_SCC3,
-	CPM_CR_CH_SCC4
-};
-
-static void begin_break(ser_info_t *info)
-{
-	volatile QUICC *cp;
-	ushort	chan;
-	int     idx;
-
-	cp = pquicc;
-
-	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC)
-		chan = scc_chan_map[idx];
-	else
-		chan = smc_chan_map[idx];
-
-	cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
-	while (cp->cp_cr & CPM_CR_FLG);
-}
-
-static void end_break(ser_info_t *info)
-{
-	volatile QUICC *cp;
-	ushort	chan;
-	int idx;
-
-	cp = pquicc;
-
-	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC)
-		chan = scc_chan_map[idx];
-	else
-		chan = smc_chan_map[idx];
-
-	cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
-	while (cp->cp_cr & CPM_CR_FLG);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(ser_info_t *info, unsigned int duration)
-{
-#ifdef SERIAL_DEBUG_SEND_BREAK
-	printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
-#endif
-	begin_break(info);
-	msleep_interruptible(duration);
-	end_break(info);
-#ifdef SERIAL_DEBUG_SEND_BREAK
-	printk("done jiffies=%lu\n", jiffies);
-#endif
-}
-
-
-/*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- *     RI where only 0->1 is counted.
- */
-static int rs_360_get_icount(struct tty_struct *tty,
-				struct serial_icounter_struct *icount)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	struct async_icount cnow;
-
-	local_irq_disable();
-	cnow = info->state->icount;
-	local_irq_enable();
-
-	icount->cts = cnow.cts;
-	icount->dsr = cnow.dsr;
-	icount->rng = cnow.rng;
-	icount->dcd = cnow.dcd;
-
-	return 0;
-}
-
-static int rs_360_ioctl(struct tty_struct *tty,
-		    unsigned int cmd, unsigned long arg)
-{
-	int error;
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	int retval;
-	struct async_icount cnow; 
-	/* struct async_icount_24 cnow;*/ 	/* kernel counter temps */
-	struct serial_icounter_struct *p_cuser;	/* user space */
-
-	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-		return -ENODEV;
-
-	if (cmd != TIOCMIWAIT) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
-		    return -EIO;
-	}
-	
-	switch (cmd) {
-		case TCSBRK:	/* SVID version: non-zero arg --> no break */
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			tty_wait_until_sent(tty, 0);
-			if (signal_pending(current))
-				return -EINTR;
-			if (!arg) {
-				send_break(info, 250);	/* 1/4 second */
-				if (signal_pending(current))
-					return -EINTR;
-			}
-			return 0;
-		case TCSBRKP:	/* support for POSIX tcsendbreak() */
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			tty_wait_until_sent(tty, 0);
-			if (signal_pending(current))
-				return -EINTR;
-			send_break(info, arg ? arg*100 : 250);
-			if (signal_pending(current))
-				return -EINTR;
-			return 0;
-		case TIOCSBRK:
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			tty_wait_until_sent(tty, 0);
-			begin_break(info);
-			return 0;
-		case TIOCCBRK:
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			end_break(info);
-			return 0;
-#ifdef maybe
-		case TIOCSERGETLSR: /* Get line status register */
-			return get_lsr_info(info, (unsigned int *) arg);
-#endif
-		/*
-		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-		 * - mask passed in arg for lines of interest
- 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-		 * Caller should use TIOCGICOUNT to see which one it was
-		 */
-		 case TIOCMIWAIT:
-#ifdef modem_control
-			local_irq_disable();
-			/* note the counters on entry */
-			cprev = info->state->icount;
-			local_irq_enable();
-			while (1) {
-				interruptible_sleep_on(&info->delta_msr_wait);
-				/* see if a signal did it */
-				if (signal_pending(current))
-					return -ERESTARTSYS;
-				local_irq_disable();
-				cnow = info->state->icount; /* atomic copy */
-				local_irq_enable();
-				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
-				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-					return -EIO; /* no change => error */
-				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
-					return 0;
-				}
-				cprev = cnow;
-			}
-			/* NOTREACHED */
-#else
-			return 0;
-#endif
-
-
-		default:
-			return -ENOIOCTLCMD;
-		}
-	return 0;
-}
-
-/* FIX UP modem control here someday......
-*/
-static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-
-	change_speed(info);
-
-#ifdef modem_control
-	/* Handle transition to B0 status */
-	if ((old_termios->c_cflag & CBAUD) &&
-	    !(tty->termios->c_cflag & CBAUD)) {
-		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-		local_irq_disable();
-		serial_out(info, UART_MCR, info->MCR);
-		local_irq_enable();
-	}
-	
-	/* Handle transition away from B0 status */
-	if (!(old_termios->c_cflag & CBAUD) &&
-	    (tty->termios->c_cflag & CBAUD)) {
-		info->MCR |= UART_MCR_DTR;
-		if (!tty->hw_stopped ||
-		    !(tty->termios->c_cflag & CRTSCTS)) {
-			info->MCR |= UART_MCR_RTS;
-		}
-		local_irq_disable();
-		serial_out(info, UART_MCR, info->MCR);
-		local_irq_enable();
-	}
-	
-	/* Handle turning off CRTSCTS */
-	if ((old_termios->c_cflag & CRTSCTS) &&
-	    !(tty->termios->c_cflag & CRTSCTS)) {
-		tty->hw_stopped = 0;
-		rs_360_start(tty);
-	}
-#endif
-
-#if 0
-	/*
-	 * No need to wake up processes in open wait, since they
-	 * sample the CLOCAL flag once, and don't recheck it.
-	 * XXX  It's not clear whether the current behavior is correct
-	 * or not.  Hence, this may change.....
-	 */
-	if (!(old_termios->c_cflag & CLOCAL) &&
-	    (tty->termios->c_cflag & CLOCAL))
-		wake_up_interruptible(&info->open_wait);
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_360_close(struct tty_struct *tty, struct file * filp)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	/* struct async_state *state; */
-	struct serial_state *state;
-	unsigned long	flags;
-	int		idx;
-	volatile struct smc_regs	*smcp;
-	volatile struct scc_regs	*sccp;
-
-	if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-		return;
-
-	state = info->state;
-	
-	local_irq_save(flags);
-	
-	if (tty_hung_up_p(filp)) {
-		DBG_CNT("before DEC-hung");
-		local_irq_restore(flags);
-		return;
-	}
-	
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_close ttys%d, count = %d\n", info->line, state->count);
-#endif
-	if ((tty->count == 1) && (state->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  state->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * serial port won't be shutdown.
-		 */
-		printk("rs_close: bad serial port count; tty->count is 1, "
-		       "state->count is %d\n", state->count);
-		state->count = 1;
-	}
-	if (--state->count < 0) {
-		printk("rs_close: bad serial port count for ttys%d: %d\n",
-		       info->line, state->count);
-		state->count = 0;
-	}
-	if (state->count) {
-		DBG_CNT("before DEC-2");
-		local_irq_restore(flags);
-		return;
-	}
-	info->flags |= ASYNC_CLOSING;
-	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
-	 * the line discipline to only process XON/XOFF characters.
-	 */
-	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
-	/*
-	 * At this point we stop accepting input.  To do this, we
-	 * disable the receive line status interrupts, and tell the
-	 * interrupt driver to stop checking the data ready bit in the
-	 * line status register.
-	 */
-	info->read_status_mask &= ~BD_SC_EMPTY;
-	if (info->flags & ASYNC_INITIALIZED) {
-
-		idx = PORT_NUM(info->state->smc_scc_num);
-		if (info->state->smc_scc_num & NUM_IS_SCC) {
-			sccp = &pquicc->scc_regs[idx];
-			sccp->scc_sccm &= ~UART_SCCM_RX;
-			sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR;
-		} else {
-			smcp = &pquicc->smc_regs[idx];
-			smcp->smc_smcm &= ~SMCM_RX;
-			smcp->smc_smcmr &= ~SMCMR_REN;
-		}
-		/*
-		 * Before we drop DTR, make sure the UART transmitter
-		 * has completely drained; this is especially
-		 * important if there is a transmit FIFO!
-		 */
-		rs_360_wait_until_sent(tty, info->timeout);
-	}
-	shutdown(info);
-	rs_360_flush_buffer(tty);
-	tty_ldisc_flush(tty);		
-	tty->closing = 0;
-	info->event = 0;
-	info->port.tty = NULL;
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
-		}
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
-	local_irq_restore(flags);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	unsigned long orig_jiffies, char_time;
-	/*int lsr;*/
-	volatile QUICC_BD *bdp;
-	
-	if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
-		return;
-
-#ifdef maybe
-	if (info->state->type == PORT_UNKNOWN)
-		return;
-#endif
-
-	orig_jiffies = jiffies;
-	/*
-	 * Set the check interval to be 1/5 of the estimated time to
-	 * send a single character, and make it at least 1.  The check
-	 * interval should also be less than the timeout.
-	 * 
-	 * Note: we have to use pretty tight timings here to satisfy
-	 * the NIST-PCTS.
-	 */
-	char_time = 1;
-	if (timeout)
-		char_time = min(char_time, (unsigned long)timeout);
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
-	printk("jiff=%lu...", jiffies);
-#endif
-
-	/* We go through the loop at least once because we can't tell
-	 * exactly when the last character exits the shifter.  There can
-	 * be at least two characters waiting to be sent after the buffers
-	 * are empty.
-	 */
-	do {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
-/*		current->counter = 0;	 make us low-priority */
-		msleep_interruptible(jiffies_to_msecs(char_time));
-		if (signal_pending(current))
-			break;
-		if (timeout && (time_after(jiffies, orig_jiffies + timeout)))
-			break;
-		/* The 'tx_cur' is really the next buffer to send.  We
-		 * have to back up to the previous BD and wait for it
-		 * to go.  This isn't perfect, because all this indicates
-		 * is the buffer is available.  There are still characters
-		 * in the CPM FIFO.
-		 */
-		bdp = info->tx_cur;
-		if (bdp == info->tx_bd_base)
-			bdp += (TX_NUM_FIFO-1);
-		else
-			bdp--;
-	} while (bdp->status & BD_SC_READY);
-	current->state = TASK_RUNNING;
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_360_hangup(struct tty_struct *tty)
-{
-	ser_info_t *info = (ser_info_t *)tty->driver_data;
-	struct serial_state *state = info->state;
-	
-	if (serial_paranoia_check(info, tty->name, "rs_hangup"))
-		return;
-
-	state = info->state;
-	
-	rs_360_flush_buffer(tty);
-	shutdown(info);
-	info->event = 0;
-	state->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->port.tty = NULL;
-	wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-			   ser_info_t *info)
-{
-#ifdef DO_THIS_LATER
-	DECLARE_WAITQUEUE(wait, current);
-#endif
-	struct serial_state *state = info->state;
-	int		retval;
-	int		do_clocal = 0;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		if (info->flags & ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/*
-	 * If non-blocking mode is set, or the port is not enabled,
-	 * then make the check up front and then exit.
-	 * If this is an SMC port, we don't have modem control to wait
-	 * for, so just get out here.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR)) ||
-	    !(info->state->smc_scc_num & NUM_IS_SCC)) {
-		info->flags |= ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
-	
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, state->count is dropped by one, so that
-	 * rs_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-#ifdef DO_THIS_LATER
-	add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready before block: ttys%d, count = %d\n",
-	       state->line, state->count);
-#endif
-	local_irq_disable();
-	if (!tty_hung_up_p(filp)) 
-		state->count--;
-	local_irq_enable();
-	info->blocked_open++;
-	while (1) {
-		local_irq_disable();
-		if (tty->termios->c_cflag & CBAUD)
-			serial_out(info, UART_MCR,
-				   serial_inp(info, UART_MCR) |
-				   (UART_MCR_DTR | UART_MCR_RTS));
-		local_irq_enable();
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-			if (info->flags & ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;	
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & ASYNC_CLOSING) &&
-		    (do_clocal || (serial_in(info, UART_MSR) &
-				   UART_MSR_DCD)))
-			break;
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-#ifdef SERIAL_DEBUG_OPEN
-		printk("block_til_ready blocking: ttys%d, count = %d\n",
-		       info->line, state->count);
-#endif
-		tty_unlock();
-		schedule();
-		tty_lock();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		state->count++;
-	info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready after blocking: ttys%d, count = %d\n",
-	       info->line, state->count);
-#endif
-#endif /* DO_THIS_LATER */
-	if (retval)
-		return retval;
-	info->flags |= ASYNC_NORMAL_ACTIVE;
-	return 0;
-}
-
-static int get_async_struct(int line, ser_info_t **ret_info)
-{
-	struct serial_state *sstate;
-
-	sstate = rs_table + line;
-	if (sstate->info) {
-		sstate->count++;
-		*ret_info = (ser_info_t *)sstate->info;
-		return 0;
-	}
-	else {
-		return -ENOMEM;
-	}
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_360_open(struct tty_struct *tty, struct file * filp)
-{
-	ser_info_t	*info;
-	int 		retval, line;
-
-	line = tty->index;
-	if ((line < 0) || (line >= NR_PORTS))
-		return -ENODEV;
-	retval = get_async_struct(line, &info);
-	if (retval)
-		return retval;
-	if (serial_paranoia_check(info, tty->name, "rs_open"))
-		return -ENODEV;
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open %s, count = %d\n", tty->name, info->state->count);
-#endif
-	tty->driver_data = info;
-	info->port.tty = tty;
-
-	/*
-	 * Start up serial port
-	 */
-	retval = startup(info);
-	if (retval)
-		return retval;
-
-	retval = block_til_ready(tty, filp, info);
-	if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-		printk("rs_open returning after block_til_ready with %d\n",
-		       retval);
-#endif
-		return retval;
-	}
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open %s successful...", tty->name);
-#endif
-	return 0;
-}
-
-/*
- * /proc fs routines....
- */
-
-static inline int line_info(char *buf, struct serial_state *state)
-{
-#ifdef notdef
-	struct async_struct *info = state->info, scr_info;
-	char	stat_buf[30], control, status;
-#endif
-	int	ret;
-
-	ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
-		      state->line,
-		      (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
-		      (unsigned int)(state->port), state->irq);
-
-	if (!state->port || (state->type == PORT_UNKNOWN)) {
-		ret += sprintf(buf+ret, "\n");
-		return ret;
-	}
-
-#ifdef notdef
-	/*
-	 * Figure out the current RS-232 lines
-	 */
-	if (!info) {
-		info = &scr_info;	/* This is just for serial_{in,out} */
-
-		info->magic = SERIAL_MAGIC;
-		info->port = state->port;
-		info->flags = state->flags;
-		info->quot = 0;
-		info->port.tty = NULL;
-	}
-	local_irq_disable();
-	status = serial_in(info, UART_MSR);
-	control = info ? info->MCR : serial_in(info, UART_MCR);
-	local_irq_enable();
-	
-	stat_buf[0] = 0;
-	stat_buf[1] = 0;
-	if (control & UART_MCR_RTS)
-		strcat(stat_buf, "|RTS");
-	if (status & UART_MSR_CTS)
-		strcat(stat_buf, "|CTS");
-	if (control & UART_MCR_DTR)
-		strcat(stat_buf, "|DTR");
-	if (status & UART_MSR_DSR)
-		strcat(stat_buf, "|DSR");
-	if (status & UART_MSR_DCD)
-		strcat(stat_buf, "|CD");
-	if (status & UART_MSR_RI)
-		strcat(stat_buf, "|RI");
-
-	if (info->quot) {
-		ret += sprintf(buf+ret, " baud:%d",
-			       state->baud_base / info->quot);
-	}
-
-	ret += sprintf(buf+ret, " tx:%d rx:%d",
-		      state->icount.tx, state->icount.rx);
-
-	if (state->icount.frame)
-		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
-	
-	if (state->icount.parity)
-		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
-	
-	if (state->icount.brk)
-		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);	
-
-	if (state->icount.overrun)
-		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
-
-	/*
-	 * Last thing is the RS-232 status lines
-	 */
-	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-#endif
-	return ret;
-}
-
-int rs_360_read_proc(char *page, char **start, off_t off, int count,
-		 int *eof, void *data)
-{
-	int i, len = 0;
-	off_t	begin = 0;
-
-	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
-	for (i = 0; i < NR_PORTS && len < 4000; i++) {
-		len += line_info(page + len, &rs_table[i]);
-		if (len+begin > off+count)
-			goto done;
-		if (len+begin < off) {
-			begin += len;
-			len = 0;
-		}
-	}
-	*eof = 1;
-done:
-	if (off >= len+begin)
-		return 0;
-	*start = page + (begin-off);
-	return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/*
- * ---------------------------------------------------------------------
- * rs_init() and friends
- *
- * rs_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static _INLINE_ void show_serial_version(void)
-{
- 	printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
-}
-
-
-/*
- * The serial console driver used during boot.  Note that these names
- * clash with those found in "serial.c", so we currently can't support
- * the 16xxx uarts and these at the same time.  I will fix this to become
- * an indirect function call from tty_io.c (or something).
- */
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/*
- * Print a string to the serial port trying not to disturb any possible
- * real use of the port...
- */
-static void my_console_write(int idx, const char *s,
-				unsigned count)
-{
-	struct		serial_state	*ser;
-	ser_info_t		*info;
-	unsigned		i;
-	QUICC_BD		*bdp, *bdbase;
-	volatile struct smc_uart_pram	*up;
-	volatile	u_char		*cp;
-
-	ser = rs_table + idx;
-
-
-	/* If the port has been initialized for general use, we have
-	 * to use the buffer descriptors allocated there.  Otherwise,
-	 * we simply use the single buffer allocated.
-	 */
-	if ((info = (ser_info_t *)ser->info) != NULL) {
-		bdp = info->tx_cur;
-		bdbase = info->tx_bd_base;
-	}
-	else {
-		/* Pointer to UART in parameter ram.
-		*/
-		/* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
-		up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
-		/* Get the address of the host memory buffer.
-		 */
-		bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
-	}
-
-	/*
-	 * We need to gracefully shut down the transmitter, disable
-	 * interrupts, then send our bytes out.
-	 */
-
-	/*
-	 * Now, do each character.  This is not as bad as it looks
-	 * since this is a holding FIFO and not a transmitting FIFO.
-	 * We could add the complexity of filling the entire transmit
-	 * buffer, but we would just wait longer between accesses......
-	 */
-	for (i = 0; i < count; i++, s++) {
-		/* Wait for transmitter fifo to empty.
-		 * Ready indicates output is ready, and xmt is doing
-		 * that, not that it is ready for us to send.
-		 */
-		while (bdp->status & BD_SC_READY);
-
-		/* Send the character out.
-		 */
-		cp = bdp->buf;
-		*cp = *s;
-		
-		bdp->length = 1;
-		bdp->status |= BD_SC_READY;
-
-		if (bdp->status & BD_SC_WRAP)
-			bdp = bdbase;
-		else
-			bdp++;
-
-		/* if a LF, also do CR... */
-		if (*s == 10) {
-			while (bdp->status & BD_SC_READY);
-			/* cp = __va(bdp->buf); */
-			cp = bdp->buf;
-			*cp = 13;
-			bdp->length = 1;
-			bdp->status |= BD_SC_READY;
-
-			if (bdp->status & BD_SC_WRAP) {
-				bdp = bdbase;
-			}
-			else {
-				bdp++;
-			}
-		}
-	}
-
-	/*
-	 * Finally, Wait for transmitter & holding register to empty
-	 *  and restore the IER
-	 */
-	while (bdp->status & BD_SC_READY);
-
-	if (info)
-		info->tx_cur = (QUICC_BD *)bdp;
-}
-
-static void serial_console_write(struct console *c, const char *s,
-				unsigned count)
-{
-#ifdef CONFIG_KGDB
-	/* Try to let stub handle output. Returns true if it did. */ 
-	if (kgdb_output_string(s, count))
-		return;
-#endif
-	my_console_write(c->index, s, count);
-}
-
-
-
-/*void console_print_68360(const char *p)
-{
-	const char *cp = p;
-	int i;
-
-	for (i=0;cp[i]!=0;i++);
-
-	serial_console_write (p, i);
-
-	//Comment this if you want to have a strict interrupt-driven output
-	//rs_fair_output();
-
-	return;
-}*/
-
-
-
-
-
-
-#ifdef CONFIG_XMON
-int
-xmon_360_write(const char *s, unsigned count)
-{
-	my_console_write(0, s, count);
-	return(count);
-}
-#endif
-
-#ifdef CONFIG_KGDB
-void
-putDebugChar(char ch)
-{
-	my_console_write(0, &ch, 1);
-}
-#endif
-
-/*
- * Receive character from the serial port.  This only works well
- * before the port is initialized for real use.
- */
-static int my_console_wait_key(int idx, int xmon, char *obuf)
-{
-	struct serial_state		*ser;
-	u_char			c, *cp;
-	ser_info_t		*info;
-	QUICC_BD		*bdp;
-	volatile struct smc_uart_pram	*up;
-	int				i;
-
-	ser = rs_table + idx;
-
-	/* Get the address of the host memory buffer.
-	 * If the port has been initialized for general use, we must
-	 * use information from the port structure.
-	 */
-	if ((info = (ser_info_t *)ser->info))
-		bdp = info->rx_cur;
-	else
-		/* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */
-		bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
-
-	/* Pointer to UART in parameter ram.
-	 */
-	/* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
-	up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
-	/*
-	 * We need to gracefully shut down the receiver, disable
-	 * interrupts, then read the input.
-	 * XMON just wants a poll.  If no character, return -1, else
-	 * return the character.
-	 */
-	if (!xmon) {
-		while (bdp->status & BD_SC_EMPTY);
-	}
-	else {
-		if (bdp->status & BD_SC_EMPTY)
-			return -1;
-	}
-
-	cp = (char *)bdp->buf;
-
-	if (obuf) {
-		i = c = bdp->length;
-		while (i-- > 0)
-			*obuf++ = *cp++;
-	}
-	else {
-		c = *cp;
-	}
-	bdp->status |= BD_SC_EMPTY;
-
-	if (info) {
-		if (bdp->status & BD_SC_WRAP) {
-			bdp = info->rx_bd_base;
-		}
-		else {
-			bdp++;
-		}
-		info->rx_cur = (QUICC_BD *)bdp;
-	}
-
-	return((int)c);
-}
-
-static int serial_console_wait_key(struct console *co)
-{
-	return(my_console_wait_key(co->index, 0, NULL));
-}
-
-#ifdef CONFIG_XMON
-int
-xmon_360_read_poll(void)
-{
-	return(my_console_wait_key(0, 1, NULL));
-}
-
-int
-xmon_360_read_char(void)
-{
-	return(my_console_wait_key(0, 0, NULL));
-}
-#endif
-
-#ifdef CONFIG_KGDB
-static char kgdb_buf[RX_BUF_SIZE], *kgdp;
-static int kgdb_chars;
-
-unsigned char
-getDebugChar(void)
-{
-	if (kgdb_chars <= 0) {
-		kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);
-		kgdp = kgdb_buf;
-	}
-	kgdb_chars--;
-
-	return(*kgdp++);
-}
-
-void kgdb_interruptible(int state)
-{
-}
-void kgdb_map_scc(void)
-{
-	struct		serial_state *ser;
-	uint		mem_addr;
-	volatile	QUICC_BD		*bdp;
-	volatile	smc_uart_t	*up;
-
-	cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
-
-	/* To avoid data cache CPM DMA coherency problems, allocate a
-	 * buffer in the CPM DPRAM.  This will work until the CPM and
-	 * serial ports are initialized.  At that time a memory buffer
-	 * will be allocated.
-	 * The port is already initialized from the boot procedure, all
-	 * we do here is give it a different buffer and make it a FIFO.
-	 */
-
-	ser = rs_table;
-
-	/* Right now, assume we are using SMCs.
-	*/
-	up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
-
-	/* Allocate space for an input FIFO, plus a few bytes for output.
-	 * Allocate bytes to maintain word alignment.
-	 */
-	mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
-
-	/* Set the physical address of the host memory buffers in
-	 * the buffer descriptors.
-	 */
-	bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase];
-	bdp->buf = mem_addr;
-
-	bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase];
-	bdp->buf = mem_addr+RX_BUF_SIZE;
-
-	up->smc_mrblr = RX_BUF_SIZE;		/* receive buffer length */
-	up->smc_maxidl = RX_BUF_SIZE;
-}
-#endif
-
-static struct tty_struct *serial_console_device(struct console *c, int *index)
-{
-	*index = c->index;
-	return serial_driver;
-}
-
-
-struct console sercons = {
- 	.name		= "ttyS",
- 	.write		= serial_console_write,
- 	.device		= serial_console_device,
- 	.wait_key	= serial_console_wait_key,
- 	.setup		= serial_console_setup,
- 	.flags		= CON_PRINTBUFFER,
- 	.index		= CONFIG_SERIAL_CONSOLE_PORT, 
-};
-
-
-
-/*
- *	Register console.
- */
-long console_360_init(long kmem_start, long kmem_end)
-{
-	register_console(&sercons);
-	/*register_console (console_print_68360); - 2.0.38 only required a write
-      function pointer. */
-	return kmem_start;
-}
-
-#endif
-
-/* Index in baud rate table of the default console baud rate.
-*/
-static	int	baud_idx;
-
-static const struct tty_operations rs_360_ops = {
-	.owner = THIS_MODULE,
-	.open = rs_360_open,
-	.close = rs_360_close,
-	.write = rs_360_write,
-	.put_char = rs_360_put_char,
-	.write_room = rs_360_write_room,
-	.chars_in_buffer = rs_360_chars_in_buffer,
-	.flush_buffer = rs_360_flush_buffer,
-	.ioctl = rs_360_ioctl,
-	.throttle = rs_360_throttle,
-	.unthrottle = rs_360_unthrottle,
-	/* .send_xchar = rs_360_send_xchar, */
-	.set_termios = rs_360_set_termios,
-	.stop = rs_360_stop,
-	.start = rs_360_start,
-	.hangup = rs_360_hangup,
-	/* .wait_until_sent = rs_360_wait_until_sent, */
-	/* .read_proc = rs_360_read_proc, */
-	.tiocmget = rs_360_tiocmget,
-	.tiocmset = rs_360_tiocmset,
-	.get_icount = rs_360_get_icount,
-};
-
-static int __init rs_360_init(void)
-{
-	struct serial_state * state;
-	ser_info_t	*info;
-	void       *mem_addr;
-	uint 		dp_addr, iobits;
-	int		    i, j, idx;
-	ushort		chan;
-	QUICC_BD	*bdp;
-	volatile	QUICC		*cp;
-	volatile	struct smc_regs	*sp;
-	volatile	struct smc_uart_pram	*up;
-	volatile	struct scc_regs	*scp;
-	volatile	struct uart_pram	*sup;
-	/* volatile	immap_t		*immap; */
-	
-	serial_driver = alloc_tty_driver(NR_PORTS);
-	if (!serial_driver)
-		return -1;
-
-	show_serial_version();
-
-	serial_driver->name = "ttyS";
-	serial_driver->major = TTY_MAJOR;
-	serial_driver->minor_start = 64;
-	serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-	serial_driver->subtype = SERIAL_TYPE_NORMAL;
-	serial_driver->init_termios = tty_std_termios;
-	serial_driver->init_termios.c_cflag =
-		baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
-	serial_driver->flags = TTY_DRIVER_REAL_RAW;
-	tty_set_operations(serial_driver, &rs_360_ops);
-	
-	if (tty_register_driver(serial_driver))
-		panic("Couldn't register serial driver\n");
-
-	cp = pquicc;	/* Get pointer to Communication Processor */
-	/* immap = (immap_t *)IMAP_ADDR; */	/* and to internal registers */
-
-
-	/* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
-	 */
-	/* The "standard" configuration through the 860.
-	*/
-/* 	immap->im_ioport.iop_papar |= 0x00fc; */
-/* 	immap->im_ioport.iop_padir &= ~0x00fc; */
-/* 	immap->im_ioport.iop_paodr &= ~0x00fc; */
-	cp->pio_papar |= 0x00fc;
-	cp->pio_padir &= ~0x00fc;
-	/* cp->pio_paodr &= ~0x00fc; */
-
-
-	/* Since we don't yet do modem control, connect the port C pins
-	 * as general purpose I/O.  This will assert CTS and CD for the
-	 * SCC ports.
-	 */
-	/* FIXME: see 360um p.7-365 and 860um p.34-12 
-	 * I can't make sense of these bits - mleslie*/
-/* 	immap->im_ioport.iop_pcdir |= 0x03c6; */
-/* 	immap->im_ioport.iop_pcpar &= ~0x03c6; */
-
-/* 	cp->pio_pcdir |= 0x03c6; */
-/* 	cp->pio_pcpar &= ~0x03c6; */
-
-
-
-	/* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and
-	 * BRG4 to SCC3.
-	 */
-	cp->si_sicr &= ~0x00ffff00;
-	cp->si_sicr |=  0x001b1200;
-
-#ifdef CONFIG_PP04
-	/* Frequentis PP04 forced to RS-232 until we know better.
-	 * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.
-	 */
-	immap->im_ioport.iop_pcdir |= 0x000c;
-	immap->im_ioport.iop_pcpar &= ~0x000c;
-	immap->im_ioport.iop_pcdat &= ~0x000c;
-
-	/* This enables the TX driver.
-	*/
-	cp->cp_pbpar &= ~0x6000;
-	cp->cp_pbdat &= ~0x6000;
-#endif
-
-	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
-		state->magic = SSTATE_MAGIC;
-		state->line = i;
-		state->type = PORT_UNKNOWN;
-		state->custom_divisor = 0;
-		state->close_delay = 5*HZ/10;
-		state->closing_wait = 30*HZ;
-		state->icount.cts = state->icount.dsr = 
-			state->icount.rng = state->icount.dcd = 0;
-		state->icount.rx = state->icount.tx = 0;
-		state->icount.frame = state->icount.parity = 0;
-		state->icount.overrun = state->icount.brk = 0;
-		printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n",
-		       i, (unsigned int)(state->irq),
-		       (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
-
-#ifdef CONFIG_SERIAL_CONSOLE
-		/* If we just printed the message on the console port, and
-		 * we are about to initialize it for general use, we have
-		 * to wait a couple of character times for the CR/NL to
-		 * make it out of the transmit buffer.
-		 */
-		if (i == CONFIG_SERIAL_CONSOLE_PORT)
-			mdelay(8);
-
-
-/* 		idx = PORT_NUM(info->state->smc_scc_num); */
-/* 		if (info->state->smc_scc_num & NUM_IS_SCC) */
-/* 			chan = scc_chan_map[idx]; */
-/* 		else */
-/* 			chan = smc_chan_map[idx]; */
-
-/* 		cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */
-/* 		while (cp->cp_cr & CPM_CR_FLG); */
-
-#endif
-		/* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */
-		info = &quicc_ser_info[i];
-		if (info) {
-			memset (info, 0, sizeof(ser_info_t));
-			info->magic = SERIAL_MAGIC;
-			info->line = i;
-			info->flags = state->flags;
-			INIT_WORK(&info->tqueue, do_softint, info);
-			INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
-			init_waitqueue_head(&info->open_wait);
-			init_waitqueue_head(&info->close_wait);
-			info->state = state;
-			state->info = (struct async_struct *)info;
-
-			/* We need to allocate a transmit and receive buffer
-			 * descriptors from dual port ram, and a character
-			 * buffer area from host mem.
-			 */
-			dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO);
-
-			/* Allocate space for FIFOs in the host memory.
-			 *  (for now this is from a static array of buffers :(
-			 */
-			/* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */
-			/* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */
-			mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE];
-
-			/* Set the physical address of the host memory
-			 * buffers in the buffer descriptors, and the
-			 * virtual address for us to work with.
-			 */
-			bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
-			info->rx_cur = info->rx_bd_base = bdp;
-
-			/* initialize rx buffer descriptors */
-			for (j=0; j<(RX_NUM_FIFO-1); j++) {
-				bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
-				bdp->status = BD_SC_EMPTY | BD_SC_INTRPT;
-				mem_addr += RX_BUF_SIZE;
-				bdp++;
-			}
-			bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
-			bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
-
-
-			idx = PORT_NUM(info->state->smc_scc_num);
-			if (info->state->smc_scc_num & NUM_IS_SCC) {
-
-#if defined (CONFIG_UCQUICC) && 1
-				/* set the transceiver mode to RS232 */
-				sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */
-				sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02);
-				*(uint *)_periph_base = sipex_mode_bits;
-				/* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */
-#endif
-			}
-
-			dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO);
-
-			/* Allocate space for FIFOs in the host memory.
-			*/
-			/* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */
-			/* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */
-			mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE];
-
-			/* Set the physical address of the host memory
-			 * buffers in the buffer descriptors, and the
-			 * virtual address for us to work with.
-			 */
-			/* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
-			bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
-			info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp;
-
-			/* initialize tx buffer descriptors */
-			for (j=0; j<(TX_NUM_FIFO-1); j++) {
-				bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
-				bdp->status = BD_SC_INTRPT;
-				mem_addr += TX_BUF_SIZE;
-				bdp++;
-			}
-			bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
-			bdp->status = (BD_SC_WRAP | BD_SC_INTRPT);
-
-			if (info->state->smc_scc_num & NUM_IS_SCC) {
-				scp = &pquicc->scc_regs[idx];
-				sup = &pquicc->pram[info->state->port].scc.pscc.u;
-				sup->rbase = dp_addr;
-				sup->tbase = dp_addr;
-
-				/* Set up the uart parameters in the
-				 * parameter ram.
-				 */
-				sup->rfcr = SMC_EB;
-				sup->tfcr = SMC_EB;
-
-				/* Set this to 1 for now, so we get single
-				 * character interrupts.  Using idle character
-				 * time requires some additional tuning.
-				 */
-				sup->mrblr = 1;
-				sup->max_idl = 0;
-				sup->brkcr = 1;
-				sup->parec = 0;
-				sup->frmer = 0;
-				sup->nosec = 0;
-				sup->brkec = 0;
-				sup->uaddr1 = 0;
-				sup->uaddr2 = 0;
-				sup->toseq = 0;
-				{
-					int i;
-					for (i=0;i<8;i++)
-						sup->cc[i] = 0x8000;
-				}
-				sup->rccm = 0xc0ff;
-
-				/* Send the CPM an initialize command.
-				*/
-				chan = scc_chan_map[idx];
-
-				/* execute the INIT RX & TX PARAMS command for this channel. */
-				cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-				while (cp->cp_cr & CPM_CR_FLG);
-
-				/* Set UART mode, 8 bit, no parity, one stop.
-				 * Enable receive and transmit.
-				 */
-				scp->scc_gsmr.w.high = 0;
-				scp->scc_gsmr.w.low = 
-					(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
-				/* Disable all interrupts and clear all pending
-				 * events.
-				 */
-				scp->scc_sccm = 0;
-				scp->scc_scce = 0xffff;
-				scp->scc_dsr = 0x7e7e;
-				scp->scc_psmr = 0x3000;
-
-				/* If the port is the console, enable Rx and Tx.
-				*/
-#ifdef CONFIG_SERIAL_CONSOLE
-				if (i == CONFIG_SERIAL_CONSOLE_PORT)
-					scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#endif
-			}
-			else {
-				/* Configure SMCs Tx/Rx instead of port B
-				 * parallel I/O.
-				 */
-				up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-				up->rbase = dp_addr;
-
-				iobits = 0xc0 << (idx * 4);
-				cp->pip_pbpar |= iobits;
-				cp->pip_pbdir &= ~iobits;
-				cp->pip_pbodr &= ~iobits;
-
-
-				/* Connect the baud rate generator to the
-				 * SMC based upon index in rs_table.  Also
-				 * make sure it is connected to NMSI.
-				 */
-				cp->si_simode &= ~(0xffff << (idx * 16));
-				cp->si_simode |= (i << ((idx * 16) + 12));
-
-				up->tbase = dp_addr;
-
-				/* Set up the uart parameters in the
-				 * parameter ram.
-				 */
-				up->rfcr = SMC_EB;
-				up->tfcr = SMC_EB;
-
-				/* Set this to 1 for now, so we get single
-				 * character interrupts.  Using idle character
-				 * time requires some additional tuning.
-				 */
-				up->mrblr = 1;
-				up->max_idl = 0;
-				up->brkcr = 1;
-
-				/* Send the CPM an initialize command.
-				*/
-				chan = smc_chan_map[idx];
-
-				cp->cp_cr = mk_cr_cmd(chan,
-									  CPM_CR_INIT_TRX) | CPM_CR_FLG;
-#ifdef CONFIG_SERIAL_CONSOLE
-				if (i == CONFIG_SERIAL_CONSOLE_PORT)
-					printk("");
-#endif
-				while (cp->cp_cr & CPM_CR_FLG);
-
-				/* Set UART mode, 8 bit, no parity, one stop.
-				 * Enable receive and transmit.
-				 */
-				sp = &cp->smc_regs[idx];
-				sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
-
-				/* Disable all interrupts and clear all pending
-				 * events.
-				 */
-				sp->smc_smcm = 0;
-				sp->smc_smce = 0xff;
-
-				/* If the port is the console, enable Rx and Tx.
-				*/
-#ifdef CONFIG_SERIAL_CONSOLE
-				if (i == CONFIG_SERIAL_CONSOLE_PORT)
-					sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
-#endif
-			}
-
-			/* Install interrupt handler.
-			*/
-			/* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info);  */
-			/*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */
-			request_irq(state->irq, rs_360_interrupt, 0, "ttyS",
-				    (void *)info);
-
-			/* Set up the baud rate generator.
-			*/
-			m360_cpm_setbrg(i, baud_table[baud_idx]);
-
-		}
-	}
-
-	return 0;
-}
-module_init(rs_360_init);
-
-/* This must always be called before the rs_360_init() function, otherwise
- * it blows away the port control information.
- */
-//static int __init serial_console_setup( struct console *co, char *options)
-int serial_console_setup( struct console *co, char *options)
-{
-	struct		serial_state	*ser;
-	uint		mem_addr, dp_addr, bidx, idx, iobits;
-	ushort		chan;
-	QUICC_BD	*bdp;
-	volatile	QUICC			*cp;
-	volatile	struct smc_regs	*sp;
-	volatile	struct scc_regs	*scp;
-	volatile	struct smc_uart_pram	*up;
-	volatile	struct uart_pram		*sup;
-
-/* mleslie TODO:
- * add something to the 68k bootloader to store a desired initial console baud rate */
-
-/* 	bd_t						*bd; */ /* a board info struct used by EPPC-bug */
-/* 	bd = (bd_t *)__res; */
-
- 	for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
-	 /* if (bd->bi_baudrate == baud_table[bidx]) */
- 		if (CONSOLE_BAUDRATE == baud_table[bidx])
-			break;
-
-	/* co->cflag = CREAD|CLOCAL|bidx|CS8; */
-	baud_idx = bidx;
-
-	ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
-
-	cp = pquicc;	/* Get pointer to Communication Processor */
-
-	idx = PORT_NUM(ser->smc_scc_num);
-	if (ser->smc_scc_num & NUM_IS_SCC) {
-
-		/* TODO: need to set up SCC pin assignment etc. here */
-		
-	}
-	else {
-		iobits = 0xc0 << (idx * 4);
-		cp->pip_pbpar |= iobits;
-		cp->pip_pbdir &= ~iobits;
-		cp->pip_pbodr &= ~iobits;
-
-		/* Connect the baud rate generator to the
-		 * SMC based upon index in rs_table.  Also
-		 * make sure it is connected to NMSI.
-		 */
-		cp->si_simode &= ~(0xffff << (idx * 16));
-		cp->si_simode |= (idx << ((idx * 16) + 12));
-	}
-
-	/* When we get here, the CPM has been reset, so we need
-	 * to configure the port.
-	 * We need to allocate a transmit and receive buffer descriptor
-	 * from dual port ram, and a character buffer area from host mem.
-	 */
-
-	/* Allocate space for two buffer descriptors in the DP ram.
-	*/
-	dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO);
-
-	/* Allocate space for two 2 byte FIFOs in the host memory.
-	 */
-	/* mem_addr = m360_cpm_hostalloc(8); */
-	mem_addr = (uint)console_fifos;
-
-
-	/* Set the physical address of the host memory buffers in
-	 * the buffer descriptors.
-	 */
-	/* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
-	bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
-	bdp->buf = (char *)mem_addr;
-	(bdp+1)->buf = (char *)(mem_addr+4);
-
-	/* For the receive, set empty and wrap.
-	 * For transmit, set wrap.
-	 */
-	bdp->status = BD_SC_EMPTY | BD_SC_WRAP;
-	(bdp+1)->status = BD_SC_WRAP;
-
-	/* Set up the uart parameters in the parameter ram.
-	 */
-	if (ser->smc_scc_num & NUM_IS_SCC) {
-		scp = &cp->scc_regs[idx];
-		/* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */
-		sup = &pquicc->pram[ser->port].scc.pscc.u;
-
-		sup->rbase = dp_addr;
-		sup->tbase = dp_addr + sizeof(QUICC_BD);
-
-		/* Set up the uart parameters in the
-		 * parameter ram.
-		 */
-		sup->rfcr = SMC_EB;
-		sup->tfcr = SMC_EB;
-
-		/* Set this to 1 for now, so we get single
-		 * character interrupts.  Using idle character
-		 * time requires some additional tuning.
-		 */
-		sup->mrblr = 1;
-		sup->max_idl = 0;
-		sup->brkcr = 1;
-		sup->parec = 0;
-		sup->frmer = 0;
-		sup->nosec = 0;
-		sup->brkec = 0;
-		sup->uaddr1 = 0;
-		sup->uaddr2 = 0;
-		sup->toseq = 0;
-		{
-			int i;
-			for (i=0;i<8;i++)
-				sup->cc[i] = 0x8000;
-		}
-		sup->rccm = 0xc0ff;
-
-		/* Send the CPM an initialize command.
-		*/
-		chan = scc_chan_map[idx];
-
-		cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-		while (cp->cp_cr & CPM_CR_FLG);
-
-		/* Set UART mode, 8 bit, no parity, one stop.
-		 * Enable receive and transmit.
-		 */
-		scp->scc_gsmr.w.high = 0;
-		scp->scc_gsmr.w.low = 
-			(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
-		/* Disable all interrupts and clear all pending
-		 * events.
-		 */
-		scp->scc_sccm = 0;
-		scp->scc_scce = 0xffff;
-		scp->scc_dsr = 0x7e7e;
-		scp->scc_psmr = 0x3000;
-
-		scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
-	}
-	else {
-		/* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */
-		up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
-		up->rbase = dp_addr;	/* Base of receive buffer desc. */
-		up->tbase = dp_addr+sizeof(QUICC_BD);	/* Base of xmt buffer desc. */
-		up->rfcr = SMC_EB;
-		up->tfcr = SMC_EB;
-
-		/* Set this to 1 for now, so we get single character interrupts.
-		*/
-		up->mrblr = 1;		/* receive buffer length */
-		up->max_idl = 0;		/* wait forever for next char */
-
-		/* Send the CPM an initialize command.
-		*/
-		chan = smc_chan_map[idx];
-		cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-		while (cp->cp_cr & CPM_CR_FLG);
-
-		/* Set UART mode, 8 bit, no parity, one stop.
-		 * Enable receive and transmit.
-		 */
-		sp = &cp->smc_regs[idx];
-		sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
-
-		/* And finally, enable Rx and Tx.
-		*/
-		sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
-	}
-
-	/* Set up the baud rate generator.
-	*/
-	/* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */
-	m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE);
-
-	return 0;
-}
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/staging/serial/Kconfig b/drivers/staging/serial/Kconfig
deleted file mode 100644
index 9489688..0000000
--- a/drivers/staging/serial/Kconfig
+++ /dev/null
@@ -1,16 +0,0 @@
-config SERIAL_68360_SMC
-	bool "68360 SMC uart support"
-	depends on M68360
-	help
-	  This driver supports the SMC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360_SCC
-	bool "68360 SCC uart support"
-	depends on M68360
-	help
-	  This driver supports the SCC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360
-	bool
-	depends on SERIAL_68360_SMC || SERIAL_68360_SCC
-	default y
diff --git a/drivers/staging/serial/Makefile b/drivers/staging/serial/Makefile
deleted file mode 100644
index 37a6a0b3..0000000
--- a/drivers/staging/serial/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_SERIAL_68360) += 68360serial.o
diff --git a/drivers/staging/serial/TODO b/drivers/staging/serial/TODO
deleted file mode 100644
index a19cda8..0000000
--- a/drivers/staging/serial/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
-These are a few serial drivers that either do not build, or do not work if they
-do build, or if they seem to work, are for obsolete hardware, or are full of
-unfixable races and no one uses them anymore.
-
-If no one steps up to adopt any of these drivers, they will be removed
-in the 3.4 release.
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index ae1d815..43045db 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -41,13 +41,6 @@
 #define QUATECH_HSU200B	0xC0B1	/* HSU200B */
 #define QUATECH_HSU200C	0xC0B2	/* HSU200C */
 #define QUATECH_HSU200D	0xC0B3	/* HSU200D */
-#define QUATECH_SSU100_2  0xC120	/* SSU100_2 */
-#define QUATECH_DSU100_2  0xC140	/* DSU100_2 */
-#define QUATECH_DSU400_2  0xC150	/* DSU400_2 */
-#define QUATECH_QSU100_2  0xC160	/* QSU100_2 */
-#define QUATECH_QSU400_2  0xC170	/* QSU400_2 */
-#define QUATECH_ESU400_2  0xC180	/* ESU400_2 */
-#define QUATECH_ESU100_2  0xC1A0	/* ESU100_2 */
 
 #define QT_SET_GET_DEVICE           0xc2
 #define QT_OPEN_CLOSE_CHANNEL       0xca
@@ -125,7 +118,7 @@
 #define MODEM_CTRL          0x40
 #define RS232_MODE          0x00
 
-static const struct usb_device_id serqt_id_table[] = {
+static const struct usb_device_id id_table[] = {
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU200)},
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100)},
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU200)},
@@ -143,17 +136,9 @@
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200B)},
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200C)},
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200D)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100_2)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100_2)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU400_2)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU100_2)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU400_2)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU400_2)},
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU100_2)},
 	{}			/* Terminating entry */
 };
-
-MODULE_DEVICE_TABLE(usb, serqt_id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
 
 struct qt_get_device_data {
 	__u8 porta;
@@ -195,13 +180,6 @@
 	char closePending;
 };
 
-static struct usb_driver serqt_usb_driver = {
-	.name = "quatech-usb-serial",
-	.probe = usb_serial_probe,
-	.disconnect = usb_serial_disconnect,
-	.id_table = serqt_id_table,
-};
-
 static int port_paranoia_check(struct usb_serial_port *port,
 			       const char *function)
 {
@@ -304,8 +282,6 @@
 
 	quatech_port = urb->context;
 
-	dbg("%s - port %d\n", __func__, quatech_port->port_num);
-
 	tty = tty_port_tty_get(&quatech_port->port->port);
 
 	if (tty)
@@ -351,7 +327,6 @@
 	/* index = MINOR(port->tty->device) - serial->minor; */
 	index = tty->index - serial->minor;
 
-	dbg("%s - port %d\n", __func__, port->number);
 	dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
 
 	if (port_paranoia_check(port, __func__) != 0) {
@@ -726,8 +701,6 @@
 	int i;
 	int status;
 
-	dbg("enterting %s", __func__);
-
 	/* Now setup per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
@@ -855,8 +828,6 @@
 	struct quatech_port *qt_port;
 	int i;
 
-	dbg("enterting %s", __func__);
-
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
 		if (!port)
@@ -882,8 +853,6 @@
 	if (port_paranoia_check(port, __func__))
 		return -ENODEV;
 
-	dbg("%s - port %d\n", __func__, port->number);
-
 	serial = port->serial;
 
 	if (serial_paranoia_check(serial, __func__))
@@ -1006,8 +975,6 @@
 
 	serial = get_usb_serial(port, __func__);
 
-	dbg("%s - port %d\n", __func__, port->number);
-
 	if (serial->num_bulk_out) {
 		if (port->write_urb->status == -EINPROGRESS)
 			chars = port->write_urb->transfer_buffer_length;
@@ -1054,8 +1021,6 @@
 	unsigned int index;
 	status = 0;
 
-	dbg("%s - port %d\n", __func__, port->number);
-
 	tty = tty_port_tty_get(&port->port);
 	index = tty->index - serial->minor;
 
@@ -1109,8 +1074,6 @@
 	if (serial == NULL)
 		return -ENODEV;
 
-	dbg("%s - port %d\n", __func__, port->number);
-
 	if (count == 0) {
 		dbg("%s - write request of 0 bytes\n", __func__);
 		return 0;
@@ -1173,8 +1136,6 @@
 
 	mutex_lock(&qt_port->lock);
 
-	dbg("%s - port %d\n", __func__, port->number);
-
 	if (serial->num_bulk_out) {
 		if (port->write_urb->status != -EINPROGRESS)
 			retval = port->bulk_out_size;
@@ -1241,8 +1202,6 @@
 	int baud, divisor, remainder;
 	int status;
 
-	dbg("%s", __func__);
-
 	index = tty->index - port->serial->minor;
 
 	switch (cflag) {
@@ -1365,8 +1324,6 @@
 
 	mutex_lock(&qt_port->lock);
 
-	dbg("%s - port %d\n", __func__, port->number);
-
 	result =
 	    usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			    QT_BREAK_CONTROL, 0x40, onoff, index, NULL, 0, 300);
@@ -1385,8 +1342,6 @@
 	int status;
 	unsigned int index;
 
-	dbg("%s - port %d, tty =0x%p\n", __func__, port->number, tty);
-
 	index = tty->index - serial->minor;
 	status =
 	    BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
@@ -1426,8 +1381,6 @@
 	int status;
 	unsigned int index;
 
-	dbg("%s - port %d\n", __func__, port->number);
-
 	index = tty->index - serial->minor;
 	status =
 	    BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
@@ -1461,18 +1414,11 @@
 	struct quatech_port *qt_port = qt_get_port_private(port);
 	int retval = -ENODEV;
 
-	dbg("In %s\n", __func__);
-
 	if (!serial)
 		return -ENODEV;
 
 	mutex_lock(&qt_port->lock);
-
-	dbg("%s - port %d\n", __func__, port->number);
-	dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
-
 	retval = qt_real_tiocmget(tty, port, serial);
-
 	mutex_unlock(&qt_port->lock);
 	return retval;
 }
@@ -1486,18 +1432,11 @@
 	struct quatech_port *qt_port = qt_get_port_private(port);
 	int retval = -ENODEV;
 
-	dbg("In %s\n", __func__);
-
 	if (!serial)
 		return -ENODEV;
 
 	mutex_lock(&qt_port->lock);
-
-	dbg("%s - port %d\n", __func__, port->number);
-	dbg("%s - qt_port->RxHolding = %d\n", __func__, qt_port->RxHolding);
-
 	retval = qt_real_tiocmset(tty, port, serial, set);
-
 	mutex_unlock(&qt_port->lock);
 	return retval;
 }
@@ -1508,8 +1447,6 @@
 	struct usb_serial *serial = get_usb_serial(port, __func__);
 	struct quatech_port *qt_port;
 
-	dbg("%s - port %d\n", __func__, port->number);
-
 	if (!serial)
 		return;
 
@@ -1519,7 +1456,6 @@
 
 	/* pass on to the driver specific version of this function */
 	qt_port->RxHolding = 1;
-	dbg("%s - port->RxHolding = 1\n", __func__);
 
 	mutex_unlock(&qt_port->lock);
 	return;
@@ -1539,8 +1475,6 @@
 
 	mutex_lock(&qt_port->lock);
 
-	dbg("%s - port %d\n", __func__, port->number);
-
 	if (qt_port->RxHolding == 1) {
 		dbg("%s -qt_port->RxHolding == 1\n", __func__);
 
@@ -1559,8 +1493,9 @@
 					  qt_read_bulk_callback, port);
 			result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 			if (result)
-				err("%s - failed restarting read urb, error %d",
-				    __func__, result);
+				dev_err(&port->dev,
+					"%s - failed restarting read urb, error %d\n",
+					__func__, result);
 		}
 	}
 	mutex_unlock(&qt_port->lock);
@@ -1589,7 +1524,7 @@
 		   .name = "serqt",
 		   },
 	.description = DRIVER_DESC,
-	.id_table = serqt_id_table,
+	.id_table = id_table,
 	.num_ports = 8,
 	.open = qt_open,
 	.close = qt_close,
@@ -1612,7 +1547,7 @@
 	&quatech_device, NULL
 };
 
-module_usb_serial_driver(serqt_usb_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index 83c582e..746c4cd5 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -2,31 +2,19 @@
  * Silicon Motion SM7XX frame buffer device
  *
  * Copyright (C) 2006 Silicon Motion Technology Corp.
- * Authors: Ge Wang, gewang@siliconmotion.com
- *	    Boyod boyod.yang@siliconmotion.com.cn
+ * Authors:  Ge Wang, gewang@siliconmotion.com
+ *	     Boyod boyod.yang@siliconmotion.com.cn
  *
  * Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ * Author:   Wu Zhangjin, wuzhangjin@gmail.com
  *
  * Copyright (C) 2011 Igalia, S.L.
- * Author: Javier M. Mellid <jmunhoz@igalia.com>
+ * Author:   Javier M. Mellid <jmunhoz@igalia.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.
+ * 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.
  *
- * Version 0.10.26192.21.01
- *	- Add PowerPC/Big endian support
- *	- Verified on 2.6.19.2
- *	Boyod.yang <boyod.yang@siliconmotion.com.cn>
- *
- * Version 0.09.2621.00.01
- *	- Only support Linux Kernel's version 2.6.21
- *	Boyod.yang <boyod.yang@siliconmotion.com.cn>
- *
- * Version 0.09
- *	- Only support Linux Kernel's version 2.6.12
- *	Boyod.yang <boyod.yang@siliconmotion.com.cn>
  */
 
 #include <linux/io.h>
@@ -45,40 +33,19 @@
 
 #include "smtcfb.h"
 
-#ifdef DEBUG
-#define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg)
-#else
-#define smdbg(format, arg...)
-#endif
-
 struct screen_info smtc_screen_info;
 
 /*
 * Private structure
 */
 struct smtcfb_info {
-	/*
-	 * The following is a pointer to be passed into the
-	 * functions below.  The modules outside the main
-	 * voyager.c driver have no knowledge as to what
-	 * is within this structure.
-	 */
 	struct fb_info fb;
-	struct display_switch *dispsw;
-	struct pci_dev *dev;
-	signed int currcon;
-
+	struct pci_dev *pdev;
 	struct {
 		u8 red, green, blue;
 	} palette[NR_RGB];
-
 	u_int palette_size;
-};
 
-struct par_info {
-	/*
-	 * Hardware
-	 */
 	u16 chipID;
 	unsigned char __iomem *m_pMMIO;
 	char __iomem *m_pLFB;
@@ -121,15 +88,6 @@
 char __iomem *smtc_VRAMBaseAddress;	/* video memory starting address */
 
 static u32 colreg[17];
-static struct par_info hw;	/* hardware information */
-
-u16 smtc_ChipIDs[] = {
-	0x710,
-	0x712,
-	0x720
-};
-
-#define numSMTCchipIDs ARRAY_SIZE(smtc_ChipIDs)
 
 static struct fb_var_screeninfo smtcfb_var = {
 	.xres           = 1024,
@@ -154,30 +112,29 @@
 	.accel          = FB_ACCEL_SMI_LYNX,
 };
 
-static void sm712_set_timing(struct smtcfb_info *sfb,
-			     struct par_info *ppar_info)
+static void sm712_set_timing(struct smtcfb_info *sfb)
 {
 	int i = 0, j = 0;
 	u32 m_nScreenStride;
 
-	smdbg("\nppar_info->width = %d ppar_info->height = %d"
-			"sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n",
-			ppar_info->width, ppar_info->height,
-			sfb->fb.var.bits_per_pixel, ppar_info->hz);
+	dev_dbg(&sfb->pdev->dev,
+		"sfb->width=%d sfb->height=%d "
+		"sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
+		sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
 
 	for (j = 0; j < numVGAModes; j++) {
-		if (VGAMode[j].mmSizeX == ppar_info->width &&
-		    VGAMode[j].mmSizeY == ppar_info->height &&
+		if (VGAMode[j].mmSizeX == sfb->width &&
+		    VGAMode[j].mmSizeY == sfb->height &&
 		    VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
-		    VGAMode[j].hz == ppar_info->hz) {
+		    VGAMode[j].hz == sfb->hz) {
 
-			smdbg("\nVGAMode[j].mmSizeX  = %d VGAMode[j].mmSizeY ="
-					"%d VGAMode[j].bpp = %d"
-					"VGAMode[j].hz=%d\n",
-					VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
-					VGAMode[j].bpp, VGAMode[j].hz);
+			dev_dbg(&sfb->pdev->dev,
+				"VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d "
+				"VGAMode[j].bpp=%d VGAMode[j].hz=%d\n",
+				VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
+				VGAMode[j].bpp, VGAMode[j].hz);
 
-			smdbg("VGAMode index=%d\n", j);
+			dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j);
 
 			smtc_mmiowb(0x0, 0x3c6);
 
@@ -238,37 +195,37 @@
 	smtc_mmiowb(0x67, 0x3c2);
 
 	/* set VPR registers */
-	writel(0x0, ppar_info->m_pVPR + 0x0C);
-	writel(0x0, ppar_info->m_pVPR + 0x40);
+	writel(0x0, sfb->m_pVPR + 0x0C);
+	writel(0x0, sfb->m_pVPR + 0x40);
 
 	/* set data width */
 	m_nScreenStride =
-		(ppar_info->width * sfb->fb.var.bits_per_pixel) / 64;
+		(sfb->width * sfb->fb.var.bits_per_pixel) / 64;
 	switch (sfb->fb.var.bits_per_pixel) {
 	case 8:
-		writel(0x0, ppar_info->m_pVPR + 0x0);
+		writel(0x0, sfb->m_pVPR + 0x0);
 		break;
 	case 16:
-		writel(0x00020000, ppar_info->m_pVPR + 0x0);
+		writel(0x00020000, sfb->m_pVPR + 0x0);
 		break;
 	case 24:
-		writel(0x00040000, ppar_info->m_pVPR + 0x0);
+		writel(0x00040000, sfb->m_pVPR + 0x0);
 		break;
 	case 32:
-		writel(0x00030000, ppar_info->m_pVPR + 0x0);
+		writel(0x00030000, sfb->m_pVPR + 0x0);
 		break;
 	}
 	writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
-	       ppar_info->m_pVPR + 0x10);
+	       sfb->m_pVPR + 0x10);
 
 }
 
 static void sm712_setpalette(int regno, unsigned red, unsigned green,
 			     unsigned blue, struct fb_info *info)
 {
-	struct par_info *cur_par = (struct par_info *)info->par;
+	struct smtcfb_info *sfb = info->par;
 
-	if (cur_par->BaseAddressInVRAM)
+	if (sfb->BaseAddressInVRAM)
 		/*
 		 * second display palette for dual head. Enable CRT RAM, 6-bit
 		 * RAM
@@ -283,14 +240,13 @@
 	smtc_mmiowb(blue >> 10, dac_val);
 }
 
-static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info
-		*ppar_info)
+static void smtc_set_timing(struct smtcfb_info *sfb)
 {
-	switch (ppar_info->chipID) {
+	switch (sfb->chipID) {
 	case 0x710:
 	case 0x712:
 	case 0x720:
-		sm712_set_timing(sfb, ppar_info);
+		sm712_set_timing(sfb);
 		break;
 	}
 }
@@ -310,7 +266,7 @@
 	return chan << bf->offset;
 }
 
-static int cfb_blank(int blank_mode, struct fb_info *info)
+static int smtc_blank(int blank_mode, struct fb_info *info)
 {
 	/* clear DPMS setting */
 	switch (blank_mode) {
@@ -660,10 +616,10 @@
 		break;
 	}
 
-	hw.width = sfb->fb.var.xres;
-	hw.height = sfb->fb.var.yres;
-	hw.hz = 60;
-	smtc_set_timing(sfb, &hw);
+	sfb->width = sfb->fb.var.xres;
+	sfb->height = sfb->fb.var.yres;
+	sfb->hz = 60;
+	smtc_set_timing(sfb);
 }
 
 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -697,7 +653,7 @@
 	.fb_check_var = smtc_check_var,
 	.fb_set_par   = smtc_set_par,
 	.fb_setcolreg = smtc_setcolreg,
-	.fb_blank     = cfb_blank,
+	.fb_blank     = smtc_blank,
 	.fb_fillrect  = cfb_fillrect,
 	.fb_imageblit = cfb_imageblit,
 	.fb_copyarea  = cfb_copyarea,
@@ -710,8 +666,7 @@
 /*
  * Alloc struct smtcfb_info and assign the default value
  */
-static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
-							char *name)
+static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev, char *name)
 {
 	struct smtcfb_info *sfb;
 
@@ -720,8 +675,7 @@
 	if (!sfb)
 		return NULL;
 
-	sfb->currcon = -1;
-	sfb->dev = dev;
+	sfb->pdev = pdev;
 
 	/*** Init sfb->fb with default value ***/
 	sfb->fb.flags = FBINFO_FLAG_DEFAULT;
@@ -745,7 +699,9 @@
 	/* text mode acceleration */
 	sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
 	sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
-	sfb->fb.par = &hw;
+
+	sfb->fb.par = sfb;
+
 	sfb->fb.pseudo_palette = colreg;
 
 	return sfb;
@@ -766,17 +722,17 @@
  */
 
 static int smtc_map_smem(struct smtcfb_info *sfb,
-		struct pci_dev *dev, u_long smem_len)
+		struct pci_dev *pdev, u_long smem_len)
 {
 	if (sfb->fb.var.bits_per_pixel == 32) {
 #ifdef __BIG_ENDIAN
-		sfb->fb.fix.smem_start = pci_resource_start(dev, 0)
+		sfb->fb.fix.smem_start = pci_resource_start(pdev, 0)
 			+ 0x800000;
 #else
-		sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+		sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
 #endif
 	} else {
-		sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+		sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
 	}
 
 	sfb->fb.fix.smem_len = smem_len;
@@ -784,8 +740,8 @@
 	sfb->fb.screen_base = smtc_VRAMBaseAddress;
 
 	if (!sfb->fb.screen_base) {
-		printk(KERN_ERR "%s: unable to map screen memory\n",
-				sfb->fb.fix.id);
+		dev_err(&pdev->dev,
+			"%s: unable to map screen memory\n", sfb->fb.fix.id);
 		return -ENOMEM;
 	}
 
@@ -831,16 +787,14 @@
 {
 	int index;
 
-	if (!options || !*options) {
-		smdbg("\n No vga parameter\n");
+	if (!options || !*options)
 		return -EINVAL;
-	}
 
 	smtc_screen_info.lfb_width = 0;
 	smtc_screen_info.lfb_height = 0;
 	smtc_screen_info.lfb_depth = 0;
 
-	smdbg("\nsm712vga_setup = %s\n", options);
+	pr_debug("sm712vga_setup = %s\n", options);
 
 	for (index = 0;
 	     index < ARRAY_SIZE(vesa_mode);
@@ -858,10 +812,6 @@
 }
 __setup("vga=", sm712vga_setup);
 
-/* Jason (08/13/2009)
- * Original init function changed to probe method to be used by pci_drv
- * process used to detect chips replaced with kernel process in pci_drv
- */
 static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
 				   const struct pci_device_id *ent)
 {
@@ -871,23 +821,20 @@
 	int err;
 	unsigned long pFramebufferPhysical;
 
-	printk(KERN_INFO
-		"Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n");
+	dev_info(&pdev->dev, "Silicon Motion display driver.");
 
 	err = pci_enable_device(pdev);	/* enable SMTC chip */
 	if (err)
 		return err;
 
-	hw.chipID = ent->device;
-	sprintf(name, "sm%Xfb", hw.chipID);
-
 	sfb = smtc_alloc_fb_info(pdev, name);
 
 	if (!sfb)
 		goto failed_free;
-	/* Jason (08/13/2009)
-	 * Store fb_info to be further used when suspending and resuming
-	 */
+
+	sfb->chipID = ent->device;
+	sprintf(name, "sm%Xfb", sfb->chipID);
+
 	pci_set_drvdata(pdev, sfb);
 
 	sm7xx_init_hw();
@@ -910,37 +857,37 @@
 #endif
 	/* Map address and memory detection */
 	pFramebufferPhysical = pci_resource_start(pdev, 0);
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID);
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chipRevID);
 
-	switch (hw.chipID) {
+	switch (sfb->chipID) {
 	case 0x710:
 	case 0x712:
 		sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
 		sfb->fb.fix.mmio_len = 0x00400000;
 		smem_size = SM712_VIDEOMEMORYSIZE;
 #ifdef __BIG_ENDIAN
-		hw.m_pLFB = (smtc_VRAMBaseAddress =
+		sfb->m_pLFB = (smtc_VRAMBaseAddress =
 		    ioremap(pFramebufferPhysical, 0x00c00000));
 #else
-		hw.m_pLFB = (smtc_VRAMBaseAddress =
+		sfb->m_pLFB = (smtc_VRAMBaseAddress =
 		    ioremap(pFramebufferPhysical, 0x00800000));
 #endif
-		hw.m_pMMIO = (smtc_RegBaseAddress =
+		sfb->m_pMMIO = (smtc_RegBaseAddress =
 		    smtc_VRAMBaseAddress + 0x00700000);
-		hw.m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
-		hw.m_pVPR = hw.m_pLFB + 0x0040c000;
+		sfb->m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
+		sfb->m_pVPR = sfb->m_pLFB + 0x0040c000;
 #ifdef __BIG_ENDIAN
 		if (sfb->fb.var.bits_per_pixel == 32) {
 			smtc_VRAMBaseAddress += 0x800000;
-			hw.m_pLFB += 0x800000;
-			printk(KERN_INFO
-				"\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n",
-					smtc_VRAMBaseAddress, hw.m_pLFB);
+			sfb->m_pLFB += 0x800000;
+			dev_info(&pdev->dev,
+				 "smtc_VRAMBaseAddress=%p sfb->m_pLFB=%p",
+				  smtc_VRAMBaseAddress, sfb->m_pLFB);
 		}
 #endif
 		if (!smtc_RegBaseAddress) {
-			printk(KERN_ERR
-				"%s: unable to map memory mapped IO\n",
+			dev_err(&pdev->dev,
+				"%s: unable to map memory mapped IO!",
 				sfb->fb.fix.id);
 			err = -ENOMEM;
 			goto failed_fb;
@@ -962,20 +909,20 @@
 		sfb->fb.fix.mmio_start = pFramebufferPhysical;
 		sfb->fb.fix.mmio_len = 0x00200000;
 		smem_size = SM722_VIDEOMEMORYSIZE;
-		hw.m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
-		hw.m_pLFB = (smtc_VRAMBaseAddress =
-		    hw.m_pDPR + 0x00200000);
-		hw.m_pMMIO = (smtc_RegBaseAddress =
-		    hw.m_pDPR + 0x000c0000);
-		hw.m_pVPR = hw.m_pDPR + 0x800;
+		sfb->m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
+		sfb->m_pLFB = (smtc_VRAMBaseAddress =
+		    sfb->m_pDPR + 0x00200000);
+		sfb->m_pMMIO = (smtc_RegBaseAddress =
+		    sfb->m_pDPR + 0x000c0000);
+		sfb->m_pVPR = sfb->m_pDPR + 0x800;
 
 		smtc_seqw(0x62, 0xff);
 		smtc_seqw(0x6a, 0x0d);
 		smtc_seqw(0x6b, 0x02);
 		break;
 	default:
-		printk(KERN_ERR
-		"No valid Silicon Motion display chip was detected!\n");
+		dev_err(&pdev->dev,
+			"No valid Silicon Motion display chip was detected!");
 
 		goto failed_fb;
 	}
@@ -992,22 +939,21 @@
 
 	smtcfb_setmode(sfb);
 	/* Primary display starting from 0 position */
-	hw.BaseAddressInVRAM = 0;
-	sfb->fb.par = &hw;
+	sfb->BaseAddressInVRAM = 0;
 
 	err = register_framebuffer(&sfb->fb);
 	if (err < 0)
 		goto failed;
 
-	printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode"
-			"%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID,
-			sfb->fb.var.xres, sfb->fb.var.yres,
-			sfb->fb.var.bits_per_pixel);
+	dev_info(&pdev->dev,
+		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
+		 sfb->chipID, sfb->chipRevID, sfb->fb.var.xres,
+		 sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
 
 	return 0;
 
 failed:
-	printk(KERN_ERR "Silicon Motion, Inc.  primary display init fail\n");
+	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
 
 	smtc_unmap_smem(sfb);
 	smtc_unmap_mmio(sfb);
@@ -1021,7 +967,6 @@
 }
 
 
-/* Jason (08/11/2009) PCI_DRV wrapper essential structs */
 static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
 	{ PCI_DEVICE(0x126f, 0x710), },
 	{ PCI_DEVICE(0x126f, 0x712), },
@@ -1030,9 +975,6 @@
 };
 
 
-/* Jason (08/14/2009)
- * do some clean up when the driver module is removed
- */
 static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
 {
 	struct smtcfb_info *sfb;
@@ -1078,7 +1020,7 @@
 
 	/* reinit hardware */
 	sm7xx_init_hw();
-	switch (hw.chipID) {
+	switch (sfb->chipID) {
 	case 0x710:
 	case 0x712:
 		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
diff --git a/drivers/staging/sm7xx/smtcfb.h b/drivers/staging/sm7xx/smtcfb.h
index ab95af2..43d86f8 100644
--- a/drivers/staging/sm7xx/smtcfb.h
+++ b/drivers/staging/sm7xx/smtcfb.h
@@ -13,19 +13,11 @@
  *  more details.
  */
 
-#define SMTC_LINUX_FB_VERSION	"version 0.11.2619.21.01 July 27, 2008"
-
 #define NR_PALETTE        256
 #define NR_RGB            2
 
 #define FB_ACCEL_SMI_LYNX 88
 
-#ifdef __BIG_ENDIAN
-#define PC_VGA            0
-#else
-#define PC_VGA            1
-#endif
-
 #define SCREEN_X_RES      1024
 #define SCREEN_Y_RES      600
 #define SCREEN_BPP        16
diff --git a/drivers/staging/telephony/ixj.c b/drivers/staging/telephony/ixj.c
index f960279..fd7757a 100644
--- a/drivers/staging/telephony/ixj.c
+++ b/drivers/staging/telephony/ixj.c
@@ -19,20 +19,20 @@
  *                  David W. Erhart, <derhart@quicknet.net>
  *                  John Sellers, <jsellers@quicknet.net>
  *                  Mike Preston, <mpreston@quicknet.net>
- *    
+ *
  * Fixes:           David Huggins-Daines, <dhd@cepstral.com>
  *                  Fabio Ferrari, <fabio.ferrari@digitro.com.br>
  *                  Artis Kugevics, <artis@mt.lv>
  *                  Daniele Bellucci, <bellucda@tiscali.it>
  *
- * More information about the hardware related to this driver can be found  
+ * More information about the hardware related to this driver can be found
  * at our website:    http://www.quicknet.net
  *
  * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR
  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET
  * TECHNOLOGIES, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *    
+ *
  * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
@@ -317,7 +317,7 @@
 /*
  *	Allocate a free IXJ device
  */
- 
+
 static IXJ *ixj_alloc()
 {
 	for(cnt=0; cnt<IXJMAX; cnt++)
@@ -366,7 +366,7 @@
 /*
  *	Allocate a free IXJ device
  */
- 
+
 static IXJ *ixj_alloc(void)
 {
 	int cnt;
@@ -1084,7 +1084,7 @@
 							printk(KERN_INFO "IXJ /dev/phone%d Next Ring Cadence state at %u min %ld - %ld - max %ld\n", j->board,
 						j->cadence_f[4].on3, j->cadence_f[4].on3min, j->cadence_f[4].on3dot, j->cadence_f[4].on3max);
 							break;
-						case 6:	
+						case 6:
 							printk(KERN_INFO "IXJ /dev/phone%d Next Ring Cadence state at %u min %ld - %ld - max %ld\n", j->board,
 						j->cadence_f[4].off3, j->cadence_f[4].off3min, j->cadence_f[4].off3dot, j->cadence_f[4].off3max);
 							break;
@@ -1109,7 +1109,7 @@
 				}
 				j->pstn_ring_stop = j->pstn_ring_int = 0;
 				daa_set_mode(j, SOP_PU_SLEEP);
-			} 
+			}
 			outb_p(j->pld_scrw.byte, j->XILINXbase);
 			if (j->pstn_cid_intr && time_after(jiffies, j->pstn_cid_received + hertz)) {
 				ixj_daa_cid_read(j);
@@ -1133,7 +1133,7 @@
 							printk("IXJ DAA possible wink /dev/phone%d %ld\n", j->board, jiffies);
 						}
 						j->pstn_winkstart = jiffies;
-					} 
+					}
 				} else {
 					if (j->pstn_winkstart) {
 						if(ixjdebug & 0x0008) {
@@ -1524,7 +1524,7 @@
 /*********************************************************************
 *  GPIO Pins are configured as follows on the Quicknet Internet
 *  PhoneJACK Telephony Cards
-* 
+*
 * POTS Select        GPIO_6=0 GPIO_7=0
 * Mic/Speaker Select GPIO_6=0 GPIO_7=1
 * Handset Select     GPIO_6=1 GPIO_7=0
@@ -1932,7 +1932,7 @@
 			if(fOffHook != j->p_hook) {
 				if(!j->checkwait) {
 					j->checkwait = jiffies;
-				} 
+				}
 				if(time_before(jiffies, j->checkwait + 2)) {
 					fOffHook ^= 1;
 				} else {
@@ -2342,8 +2342,8 @@
 		j->ixj_signals[cnt] = SIGIO;
 
 	/* Set the excetion signal enable flags */
-	j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring = 
-	j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 = 
+	j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
+	j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
 	j->ex_sig.bits.f3 = j->ex_sig.bits.fc0 = j->ex_sig.bits.fc1 = j->ex_sig.bits.fc2 = j->ex_sig.bits.fc3 = 1;
 
 	file_p->private_data = NULL;
@@ -2506,7 +2506,7 @@
 					j->cadence_f[cnt].on1, j->cadence_f[cnt].on1min, j->cadence_f[cnt].on1dot, j->cadence_f[cnt].on1max);
 						break;
 					case 2:
-						printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off1min, 
+						printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off1min,
 															j->cadence_f[cnt].off1max);
 						break;
 					case 3:
@@ -2521,12 +2521,12 @@
 						printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].on3min,
 															j->cadence_f[cnt].on3max);
 						break;
-					case 6:	
+					case 6:
 						printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off3min,
 															j->cadence_f[cnt].off3max);
 						break;
 				}
-			} 
+			}
 		}
 		if (j->cadence_f[cnt].state == 7) {
 			j->cadence_f[cnt].state = 0;
@@ -2656,37 +2656,37 @@
 {
 	static unsigned char table_ulaw2alaw[] =
 	{
-		0x2A, 0x2B, 0x28, 0x29, 0x2E, 0x2F, 0x2C, 0x2D, 
-		0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 
-		0x3A, 0x3B, 0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D, 
-		0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 
-		0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02, 
-		0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1A, 
-		0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12, 
-		0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6B, 
-		0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63, 
-		0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7B, 0x79, 
-		0x7E, 0x7F, 0x7C, 0x7D, 0x72, 0x73, 0x70, 0x71, 
-		0x76, 0x77, 0x74, 0x75, 0x4B, 0x49, 0x4F, 0x4D, 
-		0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45, 
-		0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 0x5C, 0x5D, 
-		0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 
-		0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xD5, 
-		0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD, 
-		0xA2, 0xA3, 0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5, 
-		0xBA, 0xBB, 0xB8, 0xB9, 0xBE, 0xBF, 0xBC, 0xBD, 
-		0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 0xB4, 0xB5, 
-		0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, 0x82, 
-		0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9A, 
-		0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, 0x92, 
-		0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xEB, 
-		0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, 0xE2, 0xE3, 
-		0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, 0xFB, 0xF9, 
-		0xFE, 0xFF, 0xFC, 0xFD, 0xF2, 0xF3, 0xF0, 0xF1, 
-		0xF6, 0xF7, 0xF4, 0xF5, 0xCB, 0xC9, 0xCF, 0xCD, 
-		0xC2, 0xC3, 0xC0, 0xC1, 0xC6, 0xC7, 0xC4, 0xC5, 
-		0xDA, 0xDB, 0xD8, 0xD9, 0xDE, 0xDF, 0xDC, 0xDD, 
-		0xD2, 0xD2, 0xD3, 0xD3, 0xD0, 0xD0, 0xD1, 0xD1, 
+		0x2A, 0x2B, 0x28, 0x29, 0x2E, 0x2F, 0x2C, 0x2D,
+		0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
+		0x3A, 0x3B, 0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D,
+		0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
+		0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02,
+		0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1A,
+		0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12,
+		0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6B,
+		0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63,
+		0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7B, 0x79,
+		0x7E, 0x7F, 0x7C, 0x7D, 0x72, 0x73, 0x70, 0x71,
+		0x76, 0x77, 0x74, 0x75, 0x4B, 0x49, 0x4F, 0x4D,
+		0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
+		0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 0x5C, 0x5D,
+		0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
+		0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xD5,
+		0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD,
+		0xA2, 0xA3, 0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5,
+		0xBA, 0xBB, 0xB8, 0xB9, 0xBE, 0xBF, 0xBC, 0xBD,
+		0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 0xB4, 0xB5,
+		0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, 0x82,
+		0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9A,
+		0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, 0x92,
+		0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xEB,
+		0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, 0xE2, 0xE3,
+		0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, 0xFB, 0xF9,
+		0xFE, 0xFF, 0xFC, 0xFD, 0xF2, 0xF3, 0xF0, 0xF1,
+		0xF6, 0xF7, 0xF4, 0xF5, 0xCB, 0xC9, 0xCF, 0xCD,
+		0xC2, 0xC3, 0xC0, 0xC1, 0xC6, 0xC7, 0xC4, 0xC5,
+		0xDA, 0xDB, 0xD8, 0xD9, 0xDE, 0xDF, 0xDC, 0xDD,
+		0xD2, 0xD2, 0xD3, 0xD3, 0xD0, 0xD0, 0xD1, 0xD1,
 		0xD6, 0xD6, 0xD7, 0xD7, 0xD4, 0xD4, 0xD5, 0xD5
 	};
 
@@ -2701,37 +2701,37 @@
 {
 	static unsigned char table_alaw2ulaw[] =
 	{
-		0x29, 0x2A, 0x27, 0x28, 0x2D, 0x2E, 0x2B, 0x2C, 
-		0x21, 0x22, 0x1F, 0x20, 0x25, 0x26, 0x23, 0x24, 
-		0x39, 0x3A, 0x37, 0x38, 0x3D, 0x3E, 0x3B, 0x3C, 
-		0x31, 0x32, 0x2F, 0x30, 0x35, 0x36, 0x33, 0x34, 
-		0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 
-		0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 
-		0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 
-		0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 
-		0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 
-		0x5D, 0x5D, 0x5C, 0x5C, 0x5F, 0x5F, 0x5E, 0x5E, 
-		0x74, 0x76, 0x70, 0x72, 0x7C, 0x7E, 0x78, 0x7A, 
-		0x6A, 0x6B, 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 
-		0x48, 0x49, 0x46, 0x47, 0x4C, 0x4D, 0x4A, 0x4B, 
-		0x40, 0x41, 0x3F, 0x3F, 0x44, 0x45, 0x42, 0x43, 
-		0x56, 0x57, 0x54, 0x55, 0x5A, 0x5B, 0x58, 0x59, 
-		0x4F, 0x4F, 0x4E, 0x4E, 0x52, 0x53, 0x50, 0x51, 
-		0xA9, 0xAA, 0xA7, 0xA8, 0xAD, 0xAE, 0xAB, 0xAC, 
-		0xA1, 0xA2, 0x9F, 0xA0, 0xA5, 0xA6, 0xA3, 0xA4, 
-		0xB9, 0xBA, 0xB7, 0xB8, 0xBD, 0xBE, 0xBB, 0xBC, 
-		0xB1, 0xB2, 0xAF, 0xB0, 0xB5, 0xB6, 0xB3, 0xB4, 
-		0x8A, 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, 
-		0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 
-		0x9A, 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, 
-		0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 
-		0xE2, 0xE3, 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, 
-		0xDD, 0xDD, 0xDC, 0xDC, 0xDF, 0xDF, 0xDE, 0xDE, 
-		0xF4, 0xF6, 0xF0, 0xF2, 0xFC, 0xFE, 0xF8, 0xFA, 
-		0xEA, 0xEB, 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, 
-		0xC8, 0xC9, 0xC6, 0xC7, 0xCC, 0xCD, 0xCA, 0xCB, 
-		0xC0, 0xC1, 0xBF, 0xBF, 0xC4, 0xC5, 0xC2, 0xC3, 
-		0xD6, 0xD7, 0xD4, 0xD5, 0xDA, 0xDB, 0xD8, 0xD9, 
+		0x29, 0x2A, 0x27, 0x28, 0x2D, 0x2E, 0x2B, 0x2C,
+		0x21, 0x22, 0x1F, 0x20, 0x25, 0x26, 0x23, 0x24,
+		0x39, 0x3A, 0x37, 0x38, 0x3D, 0x3E, 0x3B, 0x3C,
+		0x31, 0x32, 0x2F, 0x30, 0x35, 0x36, 0x33, 0x34,
+		0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D,
+		0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
+		0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D,
+		0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
+		0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
+		0x5D, 0x5D, 0x5C, 0x5C, 0x5F, 0x5F, 0x5E, 0x5E,
+		0x74, 0x76, 0x70, 0x72, 0x7C, 0x7E, 0x78, 0x7A,
+		0x6A, 0x6B, 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D,
+		0x48, 0x49, 0x46, 0x47, 0x4C, 0x4D, 0x4A, 0x4B,
+		0x40, 0x41, 0x3F, 0x3F, 0x44, 0x45, 0x42, 0x43,
+		0x56, 0x57, 0x54, 0x55, 0x5A, 0x5B, 0x58, 0x59,
+		0x4F, 0x4F, 0x4E, 0x4E, 0x52, 0x53, 0x50, 0x51,
+		0xA9, 0xAA, 0xA7, 0xA8, 0xAD, 0xAE, 0xAB, 0xAC,
+		0xA1, 0xA2, 0x9F, 0xA0, 0xA5, 0xA6, 0xA3, 0xA4,
+		0xB9, 0xBA, 0xB7, 0xB8, 0xBD, 0xBE, 0xBB, 0xBC,
+		0xB1, 0xB2, 0xAF, 0xB0, 0xB5, 0xB6, 0xB3, 0xB4,
+		0x8A, 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D,
+		0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
+		0x9A, 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D,
+		0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
+		0xE2, 0xE3, 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5,
+		0xDD, 0xDD, 0xDC, 0xDC, 0xDF, 0xDF, 0xDE, 0xDE,
+		0xF4, 0xF6, 0xF0, 0xF2, 0xFC, 0xFE, 0xF8, 0xFA,
+		0xEA, 0xEB, 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED,
+		0xC8, 0xC9, 0xC6, 0xC7, 0xCC, 0xCD, 0xCA, 0xCB,
+		0xC0, 0xC1, 0xBF, 0xBF, 0xC4, 0xC5, 0xC2, 0xC3,
+		0xD6, 0xD7, 0xD4, 0xD5, 0xDA, 0xDB, 0xD8, 0xD9,
 		0xCF, 0xCF, 0xCE, 0xCE, 0xD2, 0xD3, 0xD0, 0xD1
 	};
 
@@ -3090,7 +3090,7 @@
 
 static void ixj_pad_fsk(IXJ *j, int pad)
 {
-	int cnt; 
+	int cnt;
 
 	for (cnt = 0; cnt < pad; cnt++) {
 		if(j->fskdcnt < (j->fsksize - 1))
@@ -3474,7 +3474,7 @@
 			ixj_post_cid(j);
 		}
 		/* This may seem rude, but if we just played one frame of FSK data for CallerID
-		   and there is real audio data in the buffer, we need to throw it away because 
+		   and there is real audio data in the buffer, we need to throw it away because
 		   we just used it's time slot */
 		if (j->write_buffer_rp > j->write_buffer_wp) {
 			j->write_buffer_rp += j->cid_play_frame_size * 2;
@@ -3486,7 +3486,7 @@
 
 			wake_up_interruptible(&j->poll_q);	/* Wake any blocked selects */
 		}
-	} else if (j->write_buffer && j->write_buffers_empty < 1) { 
+	} else if (j->write_buffer && j->write_buffers_empty < 1) {
 		if (j->write_buffer_wp > j->write_buffer_rp) {
 			frame_count =
 			    (j->write_buffer_wp - j->write_buffer_rp) / (j->play_frame_size * 2);
@@ -4150,7 +4150,7 @@
 
 			ixj_WriteDSPCommand(0xCF97, j);	/* Set AGC Enable */
 			ixj_WriteDSPCommand(0x0000, j);	/* to off */
-			
+
 			break;
 
 		case AEC_MED:
@@ -4161,7 +4161,7 @@
 
 			ixj_WriteDSPCommand(0xCF97, j);	/* Set AGC Enable */
 			ixj_WriteDSPCommand(0x0000, j);	/* to off */
-			
+
 			break;
 
 		case AEC_HIGH:
@@ -4172,7 +4172,7 @@
 
 			ixj_WriteDSPCommand(0xCF97, j);	/* Set AGC Enable */
 			ixj_WriteDSPCommand(0x0000, j);	/* to off */
-			
+
 			break;
 
 		case AEC_AGC:
@@ -4197,28 +4197,28 @@
 			/* Now we can set the AGC initial parameters and turn it on */
 			ixj_WriteDSPCommand(0xCF90, j);	/* Set AGC Minimum gain */
 			ixj_WriteDSPCommand(0x0020, j);	/* to 0.125 (-18dB) */
-	
+
 			ixj_WriteDSPCommand(0xCF91, j);	/* Set AGC Maximum gain */
 			ixj_WriteDSPCommand(0x1000, j);	/* to 16 (24dB) */
-			
+
 			ixj_WriteDSPCommand(0xCF92, j);	/* Set AGC start gain */
 			ixj_WriteDSPCommand(0x0800, j);	/* to 8 (+18dB) */
-		
+
 			ixj_WriteDSPCommand(0xCF93, j);	/* Set AGC hold time */
 			ixj_WriteDSPCommand(0x1F40, j);	/* to 2 seconds (units are 250us) */
-			
+
 			ixj_WriteDSPCommand(0xCF94, j);	/* Set AGC Attack Time Constant */
 			ixj_WriteDSPCommand(0x0005, j);	/* to 8ms */
-			
+
 			ixj_WriteDSPCommand(0xCF95, j);	/* Set AGC Decay Time Constant */
 			ixj_WriteDSPCommand(0x000D, j);	/* to 4096ms */
-			
+
 			ixj_WriteDSPCommand(0xCF96, j);	/* Set AGC Attack Threshold */
 			ixj_WriteDSPCommand(0x1200, j);	/* to 25% */
-			
+
 			ixj_WriteDSPCommand(0xCF97, j);	/* Set AGC Enable */
 			ixj_WriteDSPCommand(0x0001, j);	/* to on */
-			
+
 			break;
 
 		case AEC_AUTO:
@@ -4495,7 +4495,7 @@
 		return -ENOMEM;
 	}
 /*	j->write_buffers_empty = 2; */
-	j->write_buffers_empty = 1; 
+	j->write_buffers_empty = 1;
 	j->write_buffer_size = j->play_frame_size * 2;
 	j->write_buffer_end = j->write_buffer + j->play_frame_size * 2;
 	j->write_buffer_rp = j->write_buffer_wp = j->write_buffer;
@@ -6465,9 +6465,9 @@
 		ixj_ringback(j);
 		break;
 	case PHONE_WINK:
-		if(j->cardtype == QTI_PHONEJACK) 
+		if(j->cardtype == QTI_PHONEJACK)
 			retval = -1;
-		else 
+		else
 			retval = ixj_wink(j);
 		break;
 	case PHONE_CPT_STOP:
@@ -6553,7 +6553,7 @@
 		ixj_write_vmwi(j, arg);
 		break;
 	case IXJCTL_CID:
-		if (copy_to_user(argp, &j->cid, sizeof(PHONE_CID))) 
+		if (copy_to_user(argp, &j->cid, sizeof(PHONE_CID)))
 			retval = -EFAULT;
 		j->ex.bits.caller_id = 0;
 		break;
@@ -6575,13 +6575,13 @@
 		break;
 	case PHONE_CAPABILITIES_LIST:
 		add_caps(j);
-		if (copy_to_user(argp, j->caplist, sizeof(struct phone_capability) * j->caps)) 
+		if (copy_to_user(argp, j->caplist, sizeof(struct phone_capability) * j->caps))
 			retval = -EFAULT;
 		break;
 	case PHONE_CAPABILITIES_CHECK:
 		{
 			struct phone_capability cap;
-			if (copy_from_user(&cap, argp, sizeof(cap))) 
+			if (copy_from_user(&cap, argp, sizeof(cap)))
 				retval = -EFAULT;
 			else {
 				add_caps(j);
@@ -6597,13 +6597,13 @@
 		j->ex.bits.pstn_ring = 0;
 		break;
 	case IXJCTL_SET_FILTER:
-		if (copy_from_user(&jf, argp, sizeof(jf))) 
+		if (copy_from_user(&jf, argp, sizeof(jf)))
 			retval = -EFAULT;
 		else
 			retval = ixj_init_filter(j, &jf);
 		break;
 	case IXJCTL_SET_FILTER_RAW:
-		if (copy_from_user(&jfr, argp, sizeof(jfr))) 
+		if (copy_from_user(&jfr, argp, sizeof(jfr)))
 			retval = -EFAULT;
 		else
 			retval = ixj_init_filter_raw(j, &jfr);
@@ -6638,9 +6638,9 @@
 				raise *= 2;
 			}
 			if(j->sigdef.signal)
-				j->ex_sig.bytes |= raise; 
+				j->ex_sig.bytes |= raise;
 			else
-				j->ex_sig.bytes &= (raise^0xffff); 
+				j->ex_sig.bytes &= (raise^0xffff);
 		}
 		break;
 	case IXJCTL_INTERCOM_STOP:
@@ -7040,9 +7040,9 @@
 
 	/* initialise the DTMF prescale to a sensible value */
 	if (j->cardtype == QTI_LINEJACK) {
-		set_dtmf_prescale(j, 0x10); 
+		set_dtmf_prescale(j, 0x10);
 	} else {
-		set_dtmf_prescale(j, 0x40); 
+		set_dtmf_prescale(j, 0x40);
 	}
 	set_play_volume(j, 0x100);
 	set_rec_volume(j, 0x100);
@@ -7095,15 +7095,15 @@
 		j->ixj_signals[cnt] = SIGIO;
 
 	/* Set the excetion signal enable flags */
-	j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring = 
-	j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 = 
+	j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
+	j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
 	j->ex_sig.bits.f3 = j->ex_sig.bits.fc0 = j->ex_sig.bits.fc1 = j->ex_sig.bits.fc2 = j->ex_sig.bits.fc3 = 1;
 #ifdef IXJ_DYN_ALLOC
 	j->fskdata = NULL;
 #endif
 	j->fskdcnt = 0;
 	j->cidcw_wait = 0;
- 
+
 	/* Register with the Telephony for Linux subsystem */
 	j->p.f_op = &ixj_fops;
 	j->p.open = ixj_open;
@@ -7118,7 +7118,7 @@
 /*
  *	Exported service for pcmcia card handling
  */
- 
+
 IXJ *ixj_pcmcia_probe(unsigned long dsp, unsigned long xilinx)
 {
 	IXJ *j = ixj_alloc();
@@ -7320,7 +7320,7 @@
 			len += sprintf(buf + len, "\nRec volume 0x%x", get_rec_volume(j));
 			len += sprintf(buf + len, "\nPlay volume 0x%x", get_play_volume(j));
 			len += sprintf(buf + len, "\nDTMF prescale 0x%x", get_dtmf_prescale(j));
-			
+
 			len += sprintf(buf + len, "\nHook state %d", j->hookstate); /* j->r_hook);	*/
 
 			if (j->cardtype == QTI_LINEJACK) {
@@ -7417,7 +7417,7 @@
                         len += sprintf(buf + len, "\nPControl Wait Fails %ld", j->pcontrolwaitfail);
                         len += sprintf(buf + len, "\nIs Control Ready Checks %ld", j->iscontrolready);
                         len += sprintf(buf + len, "\nIs Control Ready Check failures %ld", j->iscontrolreadyfail);
- 
+
 #endif
 			len += sprintf(buf + len, "\n");
 		}
@@ -7608,7 +7608,7 @@
 }
 
 static int __init ixj_probe_isapnp(int *cnt)
-{               
+{
 	int probe = 0;
 	int func = 0x110;
         struct pnp_dev *dev = NULL, *old_dev = NULL;
@@ -7686,7 +7686,7 @@
 	}
 	return probe;
 }
-                        
+
 static int __init ixj_probe_isa(int *cnt)
 {
 	int i, probe;
@@ -7713,7 +7713,7 @@
 
 static int __init ixj_probe_pci(int *cnt)
 {
-	struct pci_dev *pci = NULL;   
+	struct pci_dev *pci = NULL;
 	int i, probe = 0;
 	IXJ *j = NULL;
 
@@ -7745,7 +7745,7 @@
 static int __init ixj_init(void)
 {
 	int cnt = 0;
-	int probe = 0;   
+	int probe = 0;
 
 	cnt = 0;
 
@@ -7887,7 +7887,7 @@
 /*	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x2D; */
 /*	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0x62; */
 /*	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x2D; */
-	/* Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 */ 
+	/* Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 */
 /*	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x2D; */
 /*	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x62; */
 /*	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6; */
diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c
index 9b50b5b..c51f651 100644
--- a/drivers/staging/tidspbridge/core/io_sm.c
+++ b/drivers/staging/tidspbridge/core/io_sm.c
@@ -2212,7 +2212,7 @@
 
 		if (status) {
 			pr_debug(
-			"%s: Failed to read dll_module stuct for 0x%x.\n",
+			"%s: Failed to read dll_module struct for 0x%x.\n",
 			__func__, module_dsp_addr);
 			break;
 		}
diff --git a/drivers/staging/tidspbridge/core/ue_deh.c b/drivers/staging/tidspbridge/core/ue_deh.c
index 006ffd7..3d28b23 100644
--- a/drivers/staging/tidspbridge/core/ue_deh.c
+++ b/drivers/staging/tidspbridge/core/ue_deh.c
@@ -215,7 +215,7 @@
 	case DSP_MMUFAULT: return "DSP_MMUFAULT"; break;
 	case DSP_PWRERROR: return "DSP_PWRERROR"; break;
 	case DSP_WDTOVERFLOW: return "DSP_WDTOVERFLOW"; break;
-	default: return "unkown event"; break;
+	default: return "unknown event"; break;
 	}
 }
 
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index fa870e3..92ced35 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -113,8 +113,8 @@
 
 		spin_unlock(&sdev->ud.lock);
 
-		sdev->ud.tcp_rx = kthread_run(stub_rx_loop, &sdev->ud, "stub_rx");
-		sdev->ud.tcp_tx = kthread_run(stub_tx_loop, &sdev->ud, "stub_tx");
+		sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud, "stub_rx");
+		sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud, "stub_tx");
 
 		spin_lock(&sdev->ud.lock);
 		sdev->ud.status = SDEV_ST_USED;
@@ -187,10 +187,10 @@
 	}
 
 	/* 1. stop threads */
-	if (ud->tcp_rx && !task_is_dead(ud->tcp_rx))
-		kthread_stop(ud->tcp_rx);
-	if (ud->tcp_tx && !task_is_dead(ud->tcp_tx))
-		kthread_stop(ud->tcp_tx);
+	if (ud->tcp_rx)
+		kthread_stop_put(ud->tcp_rx);
+	if (ud->tcp_tx)
+		kthread_stop_put(ud->tcp_tx);
 
 	/*
 	 * 2. close the socket
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
index c7b888c..5d89c0f 100644
--- a/drivers/staging/usbip/usbip_common.h
+++ b/drivers/staging/usbip/usbip_common.h
@@ -292,6 +292,23 @@
 	} eh_ops;
 };
 
+#define kthread_get_run(threadfn, data, namefmt, ...)			   \
+({									   \
+	struct task_struct *__k						   \
+		= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
+	if (!IS_ERR(__k)) {						   \
+		get_task_struct(__k);					   \
+		wake_up_process(__k);					   \
+	}								   \
+	__k;								   \
+})
+
+#define kthread_stop_put(k)		\
+	do {				\
+		kthread_stop(k);	\
+		put_task_struct(k);	\
+	} while (0)
+
 /* usbip_common.c */
 void usbip_dump_urb(struct urb *purb);
 void usbip_dump_header(struct usbip_header *pdu);
diff --git a/drivers/staging/usbip/usbip_protocol.txt b/drivers/staging/usbip/usbip_protocol.txt
index 0f10208..16b6fe2 100644
--- a/drivers/staging/usbip/usbip_protocol.txt
+++ b/drivers/staging/usbip/usbip_protocol.txt
@@ -27,7 +27,7 @@
 of them. First the client opens a TCP/IP connection towards the server and
 sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the
 import was successful the TCP/IP connection remains open and will be used
-to trasfer the URB traffic between the client and the server. The client may
+to transfer the URB traffic between the client and the server. The client may
 send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and
 USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the
 server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively.
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
index 2697877..0958ba5 100644
--- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
@@ -59,7 +59,10 @@
 
 
 	/* skip a header line */
-	c = strchr(value, '\n') + 1;
+	c = strchr(value, '\n');
+	if (!c)
+		return -1;
+	c++;
 
 	while (*c != '\0') {
 		int port, status, speed, devid;
@@ -109,7 +112,10 @@
 
 
 		/* go to the next line */
-		c = strchr(c, '\n') + 1;
+		c = strchr(c, '\n');
+		if (!c)
+			break;
+		c++;
 	}
 
 	dbg("exit");
@@ -264,11 +270,17 @@
 	    attr_status->method, attr_status->value);
 
 	/* skip a header line */
-	c = strchr(attr_status->value, '\n') + 1;
+	c = strchr(attr_status->value, '\n');
+	if (!c)
+		return 0;
+	c++;
 
 	while (*c != '\0') {
 		/* go to the next line */
-		c = strchr(c, '\n') + 1;
+		c = strchr(c, '\n');
+		if (!c)
+			return nports;
+		c++;
 		nports += 1;
 	}
 
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index dca9bf1..f708cba 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -821,10 +821,10 @@
 	}
 
 	/* kill threads related to this sdev, if v.c. exists */
-	if (vdev->ud.tcp_rx && !task_is_dead(vdev->ud.tcp_rx))
-		kthread_stop(vdev->ud.tcp_rx);
-	if (vdev->ud.tcp_tx && !task_is_dead(vdev->ud.tcp_tx))
-		kthread_stop(vdev->ud.tcp_tx);
+	if (vdev->ud.tcp_rx)
+		kthread_stop_put(vdev->ud.tcp_rx);
+	if (vdev->ud.tcp_tx)
+		kthread_stop_put(vdev->ud.tcp_tx);
 
 	pr_info("stop threads\n");
 
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index f5fba732..f0eaf04f 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -162,7 +162,7 @@
 		 * already received the result of its submit result and gave
 		 * back the URB.
 		 */
-		pr_info("the urb (seqnum %d) was already given backed\n",
+		pr_info("the urb (seqnum %d) was already given back\n",
 			pdu->base.seqnum);
 	} else {
 		usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
index 0cd039b..7ce9c2f 100644
--- a/drivers/staging/usbip/vhci_sysfs.c
+++ b/drivers/staging/usbip/vhci_sysfs.c
@@ -222,8 +222,8 @@
 	spin_unlock(&the_controller->lock);
 	/* end the lock */
 
-	vdev->ud.tcp_rx = kthread_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
-	vdev->ud.tcp_tx = kthread_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
+	vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
+	vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
 
 	rh_port_connect(rhport, speed);
 
diff --git a/drivers/staging/vme/Kconfig b/drivers/staging/vme/Kconfig
deleted file mode 100644
index 6411ae5..0000000
--- a/drivers/staging/vme/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# VME configuration.
-#
-
-menuconfig VME_BUS
-	tristate "VME bridge support"
-	depends on PCI
-	---help---
-	  If you say Y here you get support for the VME bridge Framework.
-
-if VME_BUS
-
-source "drivers/staging/vme/bridges/Kconfig"
-
-source "drivers/staging/vme/devices/Kconfig"
-
-source "drivers/staging/vme/boards/Kconfig"
-
-endif # VME
diff --git a/drivers/staging/vme/Makefile b/drivers/staging/vme/Makefile
index b4ea3f8..accdb72 100644
--- a/drivers/staging/vme/Makefile
+++ b/drivers/staging/vme/Makefile
@@ -1,8 +1 @@
-#
-# Makefile for the VME bridge device drivers.
-#
-obj-$(CONFIG_VME_BUS)		+= vme.o
-
-obj-y				+= bridges/
 obj-y				+= devices/
-obj-y				+= boards/
diff --git a/drivers/staging/vme/TODO b/drivers/staging/vme/TODO
deleted file mode 100644
index 79f0033..0000000
--- a/drivers/staging/vme/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-				TODO
-				====
-
-- Add one or more device drivers which use the VME framework.
-
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c
deleted file mode 100644
index 515b8b8..0000000
--- a/drivers/staging/vme/bridges/vme_ca91cx42.c
+++ /dev/null
@@ -1,1959 +0,0 @@
-/*
- * Support for the Tundra Universe I/II VME-PCI Bridge Chips
- *
- * Author: Martyn Welch <martyn.welch@ge.com>
- * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
- *
- * Based on work by Tom Armistead and Ajit Prem
- * Copyright 2004 Motorola Inc.
- *
- * Derived from ca91c042.c by Michael Wyrick
- *
- * 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/mm.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/poll.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-
-#include "../vme.h"
-#include "../vme_bridge.h"
-#include "vme_ca91cx42.h"
-
-static int __init ca91cx42_init(void);
-static int ca91cx42_probe(struct pci_dev *, const struct pci_device_id *);
-static void ca91cx42_remove(struct pci_dev *);
-static void __exit ca91cx42_exit(void);
-
-/* Module parameters */
-static int geoid;
-
-static const char driver_name[] = "vme_ca91cx42";
-
-static DEFINE_PCI_DEVICE_TABLE(ca91cx42_ids) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C142) },
-	{ },
-};
-
-static struct pci_driver ca91cx42_driver = {
-	.name = driver_name,
-	.id_table = ca91cx42_ids,
-	.probe = ca91cx42_probe,
-	.remove = ca91cx42_remove,
-};
-
-static u32 ca91cx42_DMA_irqhandler(struct ca91cx42_driver *bridge)
-{
-	wake_up(&bridge->dma_queue);
-
-	return CA91CX42_LINT_DMA;
-}
-
-static u32 ca91cx42_LM_irqhandler(struct ca91cx42_driver *bridge, u32 stat)
-{
-	int i;
-	u32 serviced = 0;
-
-	for (i = 0; i < 4; i++) {
-		if (stat & CA91CX42_LINT_LM[i]) {
-			/* We only enable interrupts if the callback is set */
-			bridge->lm_callback[i](i);
-			serviced |= CA91CX42_LINT_LM[i];
-		}
-	}
-
-	return serviced;
-}
-
-/* XXX This needs to be split into 4 queues */
-static u32 ca91cx42_MB_irqhandler(struct ca91cx42_driver *bridge, int mbox_mask)
-{
-	wake_up(&bridge->mbox_queue);
-
-	return CA91CX42_LINT_MBOX;
-}
-
-static u32 ca91cx42_IACK_irqhandler(struct ca91cx42_driver *bridge)
-{
-	wake_up(&bridge->iack_queue);
-
-	return CA91CX42_LINT_SW_IACK;
-}
-
-static u32 ca91cx42_VERR_irqhandler(struct vme_bridge *ca91cx42_bridge)
-{
-	int val;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	val = ioread32(bridge->base + DGCS);
-
-	if (!(val & 0x00000800)) {
-		dev_err(ca91cx42_bridge->parent, "ca91cx42_VERR_irqhandler DMA "
-			"Read Error DGCS=%08X\n", val);
-	}
-
-	return CA91CX42_LINT_VERR;
-}
-
-static u32 ca91cx42_LERR_irqhandler(struct vme_bridge *ca91cx42_bridge)
-{
-	int val;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	val = ioread32(bridge->base + DGCS);
-
-	if (!(val & 0x00000800))
-		dev_err(ca91cx42_bridge->parent, "ca91cx42_LERR_irqhandler DMA "
-			"Read Error DGCS=%08X\n", val);
-
-	return CA91CX42_LINT_LERR;
-}
-
-
-static u32 ca91cx42_VIRQ_irqhandler(struct vme_bridge *ca91cx42_bridge,
-	int stat)
-{
-	int vec, i, serviced = 0;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-
-	for (i = 7; i > 0; i--) {
-		if (stat & (1 << i)) {
-			vec = ioread32(bridge->base +
-				CA91CX42_V_STATID[i]) & 0xff;
-
-			vme_irq_handler(ca91cx42_bridge, i, vec);
-
-			serviced |= (1 << i);
-		}
-	}
-
-	return serviced;
-}
-
-static irqreturn_t ca91cx42_irqhandler(int irq, void *ptr)
-{
-	u32 stat, enable, serviced = 0;
-	struct vme_bridge *ca91cx42_bridge;
-	struct ca91cx42_driver *bridge;
-
-	ca91cx42_bridge = ptr;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	enable = ioread32(bridge->base + LINT_EN);
-	stat = ioread32(bridge->base + LINT_STAT);
-
-	/* Only look at unmasked interrupts */
-	stat &= enable;
-
-	if (unlikely(!stat))
-		return IRQ_NONE;
-
-	if (stat & CA91CX42_LINT_DMA)
-		serviced |= ca91cx42_DMA_irqhandler(bridge);
-	if (stat & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 |
-			CA91CX42_LINT_LM3))
-		serviced |= ca91cx42_LM_irqhandler(bridge, stat);
-	if (stat & CA91CX42_LINT_MBOX)
-		serviced |= ca91cx42_MB_irqhandler(bridge, stat);
-	if (stat & CA91CX42_LINT_SW_IACK)
-		serviced |= ca91cx42_IACK_irqhandler(bridge);
-	if (stat & CA91CX42_LINT_VERR)
-		serviced |= ca91cx42_VERR_irqhandler(ca91cx42_bridge);
-	if (stat & CA91CX42_LINT_LERR)
-		serviced |= ca91cx42_LERR_irqhandler(ca91cx42_bridge);
-	if (stat & (CA91CX42_LINT_VIRQ1 | CA91CX42_LINT_VIRQ2 |
-			CA91CX42_LINT_VIRQ3 | CA91CX42_LINT_VIRQ4 |
-			CA91CX42_LINT_VIRQ5 | CA91CX42_LINT_VIRQ6 |
-			CA91CX42_LINT_VIRQ7))
-		serviced |= ca91cx42_VIRQ_irqhandler(ca91cx42_bridge, stat);
-
-	/* Clear serviced interrupts */
-	iowrite32(serviced, bridge->base + LINT_STAT);
-
-	return IRQ_HANDLED;
-}
-
-static int ca91cx42_irq_init(struct vme_bridge *ca91cx42_bridge)
-{
-	int result, tmp;
-	struct pci_dev *pdev;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	/* Need pdev */
-	pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
-
-	/* Initialise list for VME bus errors */
-	INIT_LIST_HEAD(&ca91cx42_bridge->vme_errors);
-
-	mutex_init(&ca91cx42_bridge->irq_mtx);
-
-	/* Disable interrupts from PCI to VME */
-	iowrite32(0, bridge->base + VINT_EN);
-
-	/* Disable PCI interrupts */
-	iowrite32(0, bridge->base + LINT_EN);
-	/* Clear Any Pending PCI Interrupts */
-	iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
-
-	result = request_irq(pdev->irq, ca91cx42_irqhandler, IRQF_SHARED,
-			driver_name, ca91cx42_bridge);
-	if (result) {
-		dev_err(&pdev->dev, "Can't get assigned pci irq vector %02X\n",
-		       pdev->irq);
-		return result;
-	}
-
-	/* Ensure all interrupts are mapped to PCI Interrupt 0 */
-	iowrite32(0, bridge->base + LINT_MAP0);
-	iowrite32(0, bridge->base + LINT_MAP1);
-	iowrite32(0, bridge->base + LINT_MAP2);
-
-	/* Enable DMA, mailbox & LM Interrupts */
-	tmp = CA91CX42_LINT_MBOX3 | CA91CX42_LINT_MBOX2 | CA91CX42_LINT_MBOX1 |
-		CA91CX42_LINT_MBOX0 | CA91CX42_LINT_SW_IACK |
-		CA91CX42_LINT_VERR | CA91CX42_LINT_LERR | CA91CX42_LINT_DMA;
-
-	iowrite32(tmp, bridge->base + LINT_EN);
-
-	return 0;
-}
-
-static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge,
-	struct pci_dev *pdev)
-{
-	/* Disable interrupts from PCI to VME */
-	iowrite32(0, bridge->base + VINT_EN);
-
-	/* Disable PCI interrupts */
-	iowrite32(0, bridge->base + LINT_EN);
-	/* Clear Any Pending PCI Interrupts */
-	iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
-
-	free_irq(pdev->irq, pdev);
-}
-
-static int ca91cx42_iack_received(struct ca91cx42_driver *bridge, int level)
-{
-	u32 tmp;
-
-	tmp = ioread32(bridge->base + LINT_STAT);
-
-	if (tmp & (1 << level))
-		return 0;
-	else
-		return 1;
-}
-
-/*
- * Set up an VME interrupt
- */
-static void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level,
-	int state, int sync)
-
-{
-	struct pci_dev *pdev;
-	u32 tmp;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	/* Enable IRQ level */
-	tmp = ioread32(bridge->base + LINT_EN);
-
-	if (state == 0)
-		tmp &= ~CA91CX42_LINT_VIRQ[level];
-	else
-		tmp |= CA91CX42_LINT_VIRQ[level];
-
-	iowrite32(tmp, bridge->base + LINT_EN);
-
-	if ((state == 0) && (sync != 0)) {
-		pdev = container_of(ca91cx42_bridge->parent, struct pci_dev,
-			dev);
-
-		synchronize_irq(pdev->irq);
-	}
-}
-
-static int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level,
-	int statid)
-{
-	u32 tmp;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	/* Universe can only generate even vectors */
-	if (statid & 1)
-		return -EINVAL;
-
-	mutex_lock(&bridge->vme_int);
-
-	tmp = ioread32(bridge->base + VINT_EN);
-
-	/* Set Status/ID */
-	iowrite32(statid << 24, bridge->base + STATID);
-
-	/* Assert VMEbus IRQ */
-	tmp = tmp | (1 << (level + 24));
-	iowrite32(tmp, bridge->base + VINT_EN);
-
-	/* Wait for IACK */
-	wait_event_interruptible(bridge->iack_queue,
-				 ca91cx42_iack_received(bridge, level));
-
-	/* Return interrupt to low state */
-	tmp = ioread32(bridge->base + VINT_EN);
-	tmp = tmp & ~(1 << (level + 24));
-	iowrite32(tmp, bridge->base + VINT_EN);
-
-	mutex_unlock(&bridge->vme_int);
-
-	return 0;
-}
-
-static int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
-	unsigned long long vme_base, unsigned long long size,
-	dma_addr_t pci_base, u32 aspace, u32 cycle)
-{
-	unsigned int i, addr = 0, granularity;
-	unsigned int temp_ctl = 0;
-	unsigned int vme_bound, pci_offset;
-	struct vme_bridge *ca91cx42_bridge;
-	struct ca91cx42_driver *bridge;
-
-	ca91cx42_bridge = image->parent;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	i = image->number;
-
-	switch (aspace) {
-	case VME_A16:
-		addr |= CA91CX42_VSI_CTL_VAS_A16;
-		break;
-	case VME_A24:
-		addr |= CA91CX42_VSI_CTL_VAS_A24;
-		break;
-	case VME_A32:
-		addr |= CA91CX42_VSI_CTL_VAS_A32;
-		break;
-	case VME_USER1:
-		addr |= CA91CX42_VSI_CTL_VAS_USER1;
-		break;
-	case VME_USER2:
-		addr |= CA91CX42_VSI_CTL_VAS_USER2;
-		break;
-	case VME_A64:
-	case VME_CRCSR:
-	case VME_USER3:
-	case VME_USER4:
-	default:
-		dev_err(ca91cx42_bridge->parent, "Invalid address space\n");
-		return -EINVAL;
-		break;
-	}
-
-	/*
-	 * Bound address is a valid address for the window, adjust
-	 * accordingly
-	 */
-	vme_bound = vme_base + size;
-	pci_offset = pci_base - vme_base;
-
-	if ((i == 0) || (i == 4))
-		granularity = 0x1000;
-	else
-		granularity = 0x10000;
-
-	if (vme_base & (granularity - 1)) {
-		dev_err(ca91cx42_bridge->parent, "Invalid VME base "
-			"alignment\n");
-		return -EINVAL;
-	}
-	if (vme_bound & (granularity - 1)) {
-		dev_err(ca91cx42_bridge->parent, "Invalid VME bound "
-			"alignment\n");
-		return -EINVAL;
-	}
-	if (pci_offset & (granularity - 1)) {
-		dev_err(ca91cx42_bridge->parent, "Invalid PCI Offset "
-			"alignment\n");
-		return -EINVAL;
-	}
-
-	/* Disable while we are mucking around */
-	temp_ctl = ioread32(bridge->base + CA91CX42_VSI_CTL[i]);
-	temp_ctl &= ~CA91CX42_VSI_CTL_EN;
-	iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]);
-
-	/* Setup mapping */
-	iowrite32(vme_base, bridge->base + CA91CX42_VSI_BS[i]);
-	iowrite32(vme_bound, bridge->base + CA91CX42_VSI_BD[i]);
-	iowrite32(pci_offset, bridge->base + CA91CX42_VSI_TO[i]);
-
-	/* Setup address space */
-	temp_ctl &= ~CA91CX42_VSI_CTL_VAS_M;
-	temp_ctl |= addr;
-
-	/* Setup cycle types */
-	temp_ctl &= ~(CA91CX42_VSI_CTL_PGM_M | CA91CX42_VSI_CTL_SUPER_M);
-	if (cycle & VME_SUPER)
-		temp_ctl |= CA91CX42_VSI_CTL_SUPER_SUPR;
-	if (cycle & VME_USER)
-		temp_ctl |= CA91CX42_VSI_CTL_SUPER_NPRIV;
-	if (cycle & VME_PROG)
-		temp_ctl |= CA91CX42_VSI_CTL_PGM_PGM;
-	if (cycle & VME_DATA)
-		temp_ctl |= CA91CX42_VSI_CTL_PGM_DATA;
-
-	/* Write ctl reg without enable */
-	iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]);
-
-	if (enabled)
-		temp_ctl |= CA91CX42_VSI_CTL_EN;
-
-	iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]);
-
-	return 0;
-}
-
-static int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled,
-	unsigned long long *vme_base, unsigned long long *size,
-	dma_addr_t *pci_base, u32 *aspace, u32 *cycle)
-{
-	unsigned int i, granularity = 0, ctl = 0;
-	unsigned long long vme_bound, pci_offset;
-	struct ca91cx42_driver *bridge;
-
-	bridge = image->parent->driver_priv;
-
-	i = image->number;
-
-	if ((i == 0) || (i == 4))
-		granularity = 0x1000;
-	else
-		granularity = 0x10000;
-
-	/* Read Registers */
-	ctl = ioread32(bridge->base + CA91CX42_VSI_CTL[i]);
-
-	*vme_base = ioread32(bridge->base + CA91CX42_VSI_BS[i]);
-	vme_bound = ioread32(bridge->base + CA91CX42_VSI_BD[i]);
-	pci_offset = ioread32(bridge->base + CA91CX42_VSI_TO[i]);
-
-	*pci_base = (dma_addr_t)vme_base + pci_offset;
-	*size = (unsigned long long)((vme_bound - *vme_base) + granularity);
-
-	*enabled = 0;
-	*aspace = 0;
-	*cycle = 0;
-
-	if (ctl & CA91CX42_VSI_CTL_EN)
-		*enabled = 1;
-
-	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A16)
-		*aspace = VME_A16;
-	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A24)
-		*aspace = VME_A24;
-	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A32)
-		*aspace = VME_A32;
-	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_USER1)
-		*aspace = VME_USER1;
-	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_USER2)
-		*aspace = VME_USER2;
-
-	if (ctl & CA91CX42_VSI_CTL_SUPER_SUPR)
-		*cycle |= VME_SUPER;
-	if (ctl & CA91CX42_VSI_CTL_SUPER_NPRIV)
-		*cycle |= VME_USER;
-	if (ctl & CA91CX42_VSI_CTL_PGM_PGM)
-		*cycle |= VME_PROG;
-	if (ctl & CA91CX42_VSI_CTL_PGM_DATA)
-		*cycle |= VME_DATA;
-
-	return 0;
-}
-
-/*
- * Allocate and map PCI Resource
- */
-static int ca91cx42_alloc_resource(struct vme_master_resource *image,
-	unsigned long long size)
-{
-	unsigned long long existing_size;
-	int retval = 0;
-	struct pci_dev *pdev;
-	struct vme_bridge *ca91cx42_bridge;
-
-	ca91cx42_bridge = image->parent;
-
-	/* Find pci_dev container of dev */
-	if (ca91cx42_bridge->parent == NULL) {
-		dev_err(ca91cx42_bridge->parent, "Dev entry NULL\n");
-		return -EINVAL;
-	}
-	pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
-
-	existing_size = (unsigned long long)(image->bus_resource.end -
-		image->bus_resource.start);
-
-	/* If the existing size is OK, return */
-	if (existing_size == (size - 1))
-		return 0;
-
-	if (existing_size != 0) {
-		iounmap(image->kern_base);
-		image->kern_base = NULL;
-		kfree(image->bus_resource.name);
-		release_resource(&image->bus_resource);
-		memset(&image->bus_resource, 0, sizeof(struct resource));
-	}
-
-	if (image->bus_resource.name == NULL) {
-		image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC);
-		if (image->bus_resource.name == NULL) {
-			dev_err(ca91cx42_bridge->parent, "Unable to allocate "
-				"memory for resource name\n");
-			retval = -ENOMEM;
-			goto err_name;
-		}
-	}
-
-	sprintf((char *)image->bus_resource.name, "%s.%d",
-		ca91cx42_bridge->name, image->number);
-
-	image->bus_resource.start = 0;
-	image->bus_resource.end = (unsigned long)size;
-	image->bus_resource.flags = IORESOURCE_MEM;
-
-	retval = pci_bus_alloc_resource(pdev->bus,
-		&image->bus_resource, size, size, PCIBIOS_MIN_MEM,
-		0, NULL, NULL);
-	if (retval) {
-		dev_err(ca91cx42_bridge->parent, "Failed to allocate mem "
-			"resource for window %d size 0x%lx start 0x%lx\n",
-			image->number, (unsigned long)size,
-			(unsigned long)image->bus_resource.start);
-		goto err_resource;
-	}
-
-	image->kern_base = ioremap_nocache(
-		image->bus_resource.start, size);
-	if (image->kern_base == NULL) {
-		dev_err(ca91cx42_bridge->parent, "Failed to remap resource\n");
-		retval = -ENOMEM;
-		goto err_remap;
-	}
-
-	return 0;
-
-err_remap:
-	release_resource(&image->bus_resource);
-err_resource:
-	kfree(image->bus_resource.name);
-	memset(&image->bus_resource, 0, sizeof(struct resource));
-err_name:
-	return retval;
-}
-
-/*
- * Free and unmap PCI Resource
- */
-static void ca91cx42_free_resource(struct vme_master_resource *image)
-{
-	iounmap(image->kern_base);
-	image->kern_base = NULL;
-	release_resource(&image->bus_resource);
-	kfree(image->bus_resource.name);
-	memset(&image->bus_resource, 0, sizeof(struct resource));
-}
-
-
-static int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
-	unsigned long long vme_base, unsigned long long size, u32 aspace,
-	u32 cycle, u32 dwidth)
-{
-	int retval = 0;
-	unsigned int i, granularity = 0;
-	unsigned int temp_ctl = 0;
-	unsigned long long pci_bound, vme_offset, pci_base;
-	struct vme_bridge *ca91cx42_bridge;
-	struct ca91cx42_driver *bridge;
-
-	ca91cx42_bridge = image->parent;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	i = image->number;
-
-	if ((i == 0) || (i == 4))
-		granularity = 0x1000;
-	else
-		granularity = 0x10000;
-
-	/* Verify input data */
-	if (vme_base & (granularity - 1)) {
-		dev_err(ca91cx42_bridge->parent, "Invalid VME Window "
-			"alignment\n");
-		retval = -EINVAL;
-		goto err_window;
-	}
-	if (size & (granularity - 1)) {
-		dev_err(ca91cx42_bridge->parent, "Invalid VME Window "
-			"alignment\n");
-		retval = -EINVAL;
-		goto err_window;
-	}
-
-	spin_lock(&image->lock);
-
-	/*
-	 * Let's allocate the resource here rather than further up the stack as
-	 * it avoids pushing loads of bus dependent stuff up the stack
-	 */
-	retval = ca91cx42_alloc_resource(image, size);
-	if (retval) {
-		spin_unlock(&image->lock);
-		dev_err(ca91cx42_bridge->parent, "Unable to allocate memory "
-			"for resource name\n");
-		retval = -ENOMEM;
-		goto err_res;
-	}
-
-	pci_base = (unsigned long long)image->bus_resource.start;
-
-	/*
-	 * Bound address is a valid address for the window, adjust
-	 * according to window granularity.
-	 */
-	pci_bound = pci_base + size;
-	vme_offset = vme_base - pci_base;
-
-	/* Disable while we are mucking around */
-	temp_ctl = ioread32(bridge->base + CA91CX42_LSI_CTL[i]);
-	temp_ctl &= ~CA91CX42_LSI_CTL_EN;
-	iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
-
-	/* Setup cycle types */
-	temp_ctl &= ~CA91CX42_LSI_CTL_VCT_M;
-	if (cycle & VME_BLT)
-		temp_ctl |= CA91CX42_LSI_CTL_VCT_BLT;
-	if (cycle & VME_MBLT)
-		temp_ctl |= CA91CX42_LSI_CTL_VCT_MBLT;
-
-	/* Setup data width */
-	temp_ctl &= ~CA91CX42_LSI_CTL_VDW_M;
-	switch (dwidth) {
-	case VME_D8:
-		temp_ctl |= CA91CX42_LSI_CTL_VDW_D8;
-		break;
-	case VME_D16:
-		temp_ctl |= CA91CX42_LSI_CTL_VDW_D16;
-		break;
-	case VME_D32:
-		temp_ctl |= CA91CX42_LSI_CTL_VDW_D32;
-		break;
-	case VME_D64:
-		temp_ctl |= CA91CX42_LSI_CTL_VDW_D64;
-		break;
-	default:
-		spin_unlock(&image->lock);
-		dev_err(ca91cx42_bridge->parent, "Invalid data width\n");
-		retval = -EINVAL;
-		goto err_dwidth;
-		break;
-	}
-
-	/* Setup address space */
-	temp_ctl &= ~CA91CX42_LSI_CTL_VAS_M;
-	switch (aspace) {
-	case VME_A16:
-		temp_ctl |= CA91CX42_LSI_CTL_VAS_A16;
-		break;
-	case VME_A24:
-		temp_ctl |= CA91CX42_LSI_CTL_VAS_A24;
-		break;
-	case VME_A32:
-		temp_ctl |= CA91CX42_LSI_CTL_VAS_A32;
-		break;
-	case VME_CRCSR:
-		temp_ctl |= CA91CX42_LSI_CTL_VAS_CRCSR;
-		break;
-	case VME_USER1:
-		temp_ctl |= CA91CX42_LSI_CTL_VAS_USER1;
-		break;
-	case VME_USER2:
-		temp_ctl |= CA91CX42_LSI_CTL_VAS_USER2;
-		break;
-	case VME_A64:
-	case VME_USER3:
-	case VME_USER4:
-	default:
-		spin_unlock(&image->lock);
-		dev_err(ca91cx42_bridge->parent, "Invalid address space\n");
-		retval = -EINVAL;
-		goto err_aspace;
-		break;
-	}
-
-	temp_ctl &= ~(CA91CX42_LSI_CTL_PGM_M | CA91CX42_LSI_CTL_SUPER_M);
-	if (cycle & VME_SUPER)
-		temp_ctl |= CA91CX42_LSI_CTL_SUPER_SUPR;
-	if (cycle & VME_PROG)
-		temp_ctl |= CA91CX42_LSI_CTL_PGM_PGM;
-
-	/* Setup mapping */
-	iowrite32(pci_base, bridge->base + CA91CX42_LSI_BS[i]);
-	iowrite32(pci_bound, bridge->base + CA91CX42_LSI_BD[i]);
-	iowrite32(vme_offset, bridge->base + CA91CX42_LSI_TO[i]);
-
-	/* Write ctl reg without enable */
-	iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
-
-	if (enabled)
-		temp_ctl |= CA91CX42_LSI_CTL_EN;
-
-	iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
-
-	spin_unlock(&image->lock);
-	return 0;
-
-err_aspace:
-err_dwidth:
-	ca91cx42_free_resource(image);
-err_res:
-err_window:
-	return retval;
-}
-
-static int __ca91cx42_master_get(struct vme_master_resource *image,
-	int *enabled, unsigned long long *vme_base, unsigned long long *size,
-	u32 *aspace, u32 *cycle, u32 *dwidth)
-{
-	unsigned int i, ctl;
-	unsigned long long pci_base, pci_bound, vme_offset;
-	struct ca91cx42_driver *bridge;
-
-	bridge = image->parent->driver_priv;
-
-	i = image->number;
-
-	ctl = ioread32(bridge->base + CA91CX42_LSI_CTL[i]);
-
-	pci_base = ioread32(bridge->base + CA91CX42_LSI_BS[i]);
-	vme_offset = ioread32(bridge->base + CA91CX42_LSI_TO[i]);
-	pci_bound = ioread32(bridge->base + CA91CX42_LSI_BD[i]);
-
-	*vme_base = pci_base + vme_offset;
-	*size = (unsigned long long)(pci_bound - pci_base);
-
-	*enabled = 0;
-	*aspace = 0;
-	*cycle = 0;
-	*dwidth = 0;
-
-	if (ctl & CA91CX42_LSI_CTL_EN)
-		*enabled = 1;
-
-	/* Setup address space */
-	switch (ctl & CA91CX42_LSI_CTL_VAS_M) {
-	case CA91CX42_LSI_CTL_VAS_A16:
-		*aspace = VME_A16;
-		break;
-	case CA91CX42_LSI_CTL_VAS_A24:
-		*aspace = VME_A24;
-		break;
-	case CA91CX42_LSI_CTL_VAS_A32:
-		*aspace = VME_A32;
-		break;
-	case CA91CX42_LSI_CTL_VAS_CRCSR:
-		*aspace = VME_CRCSR;
-		break;
-	case CA91CX42_LSI_CTL_VAS_USER1:
-		*aspace = VME_USER1;
-		break;
-	case CA91CX42_LSI_CTL_VAS_USER2:
-		*aspace = VME_USER2;
-		break;
-	}
-
-	/* XXX Not sure howto check for MBLT */
-	/* Setup cycle types */
-	if (ctl & CA91CX42_LSI_CTL_VCT_BLT)
-		*cycle |= VME_BLT;
-	else
-		*cycle |= VME_SCT;
-
-	if (ctl & CA91CX42_LSI_CTL_SUPER_SUPR)
-		*cycle |= VME_SUPER;
-	else
-		*cycle |= VME_USER;
-
-	if (ctl & CA91CX42_LSI_CTL_PGM_PGM)
-		*cycle = VME_PROG;
-	else
-		*cycle = VME_DATA;
-
-	/* Setup data width */
-	switch (ctl & CA91CX42_LSI_CTL_VDW_M) {
-	case CA91CX42_LSI_CTL_VDW_D8:
-		*dwidth = VME_D8;
-		break;
-	case CA91CX42_LSI_CTL_VDW_D16:
-		*dwidth = VME_D16;
-		break;
-	case CA91CX42_LSI_CTL_VDW_D32:
-		*dwidth = VME_D32;
-		break;
-	case CA91CX42_LSI_CTL_VDW_D64:
-		*dwidth = VME_D64;
-		break;
-	}
-
-	return 0;
-}
-
-static int ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
-	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
-	u32 *cycle, u32 *dwidth)
-{
-	int retval;
-
-	spin_lock(&image->lock);
-
-	retval = __ca91cx42_master_get(image, enabled, vme_base, size, aspace,
-		cycle, dwidth);
-
-	spin_unlock(&image->lock);
-
-	return retval;
-}
-
-static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
-	void *buf, size_t count, loff_t offset)
-{
-	ssize_t retval;
-	void *addr = image->kern_base + offset;
-	unsigned int done = 0;
-	unsigned int count32;
-
-	if (count == 0)
-		return 0;
-
-	spin_lock(&image->lock);
-
-	/* The following code handles VME address alignment problem
-	 * in order to assure the maximal data width cycle.
-	 * We cannot use memcpy_xxx directly here because it
-	 * may cut data transfer in 8-bits cycles, thus making
-	 * D16 cycle impossible.
-	 * From the other hand, the bridge itself assures that
-	 * maximal configured data cycle is used and splits it
-	 * automatically for non-aligned addresses.
-	 */
-	if ((uintptr_t)addr & 0x1) {
-		*(u8 *)buf = ioread8(addr);
-		done += 1;
-		if (done == count)
-			goto out;
-	}
-	if ((uintptr_t)addr & 0x2) {
-		if ((count - done) < 2) {
-			*(u8 *)(buf + done) = ioread8(addr + done);
-			done += 1;
-			goto out;
-		} else {
-			*(u16 *)(buf + done) = ioread16(addr + done);
-			done += 2;
-		}
-	}
-
-	count32 = (count - done) & ~0x3;
-	if (count32 > 0) {
-		memcpy_fromio(buf + done, addr + done, (unsigned int)count);
-		done += count32;
-	}
-
-	if ((count - done) & 0x2) {
-		*(u16 *)(buf + done) = ioread16(addr + done);
-		done += 2;
-	}
-	if ((count - done) & 0x1) {
-		*(u8 *)(buf + done) = ioread8(addr + done);
-		done += 1;
-	}
-out:
-	retval = count;
-	spin_unlock(&image->lock);
-
-	return retval;
-}
-
-static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
-	void *buf, size_t count, loff_t offset)
-{
-	ssize_t retval;
-	void *addr = image->kern_base + offset;
-	unsigned int done = 0;
-	unsigned int count32;
-
-	if (count == 0)
-		return 0;
-
-	spin_lock(&image->lock);
-
-	/* Here we apply for the same strategy we do in master_read
-	 * function in order to assure D16 cycle when required.
-	 */
-	if ((uintptr_t)addr & 0x1) {
-		iowrite8(*(u8 *)buf, addr);
-		done += 1;
-		if (done == count)
-			goto out;
-	}
-	if ((uintptr_t)addr & 0x2) {
-		if ((count - done) < 2) {
-			iowrite8(*(u8 *)(buf + done), addr + done);
-			done += 1;
-			goto out;
-		} else {
-			iowrite16(*(u16 *)(buf + done), addr + done);
-			done += 2;
-		}
-	}
-
-	count32 = (count - done) & ~0x3;
-	if (count32 > 0) {
-		memcpy_toio(addr + done, buf + done, count32);
-		done += count32;
-	}
-
-	if ((count - done) & 0x2) {
-		iowrite16(*(u16 *)(buf + done), addr + done);
-		done += 2;
-	}
-	if ((count - done) & 0x1) {
-		iowrite8(*(u8 *)(buf + done), addr + done);
-		done += 1;
-	}
-out:
-	retval = count;
-
-	spin_unlock(&image->lock);
-
-	return retval;
-}
-
-static unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
-	unsigned int mask, unsigned int compare, unsigned int swap,
-	loff_t offset)
-{
-	u32 result;
-	uintptr_t pci_addr;
-	int i;
-	struct ca91cx42_driver *bridge;
-	struct device *dev;
-
-	bridge = image->parent->driver_priv;
-	dev = image->parent->parent;
-
-	/* Find the PCI address that maps to the desired VME address */
-	i = image->number;
-
-	/* Locking as we can only do one of these at a time */
-	mutex_lock(&bridge->vme_rmw);
-
-	/* Lock image */
-	spin_lock(&image->lock);
-
-	pci_addr = (uintptr_t)image->kern_base + offset;
-
-	/* Address must be 4-byte aligned */
-	if (pci_addr & 0x3) {
-		dev_err(dev, "RMW Address not 4-byte aligned\n");
-		result = -EINVAL;
-		goto out;
-	}
-
-	/* Ensure RMW Disabled whilst configuring */
-	iowrite32(0, bridge->base + SCYC_CTL);
-
-	/* Configure registers */
-	iowrite32(mask, bridge->base + SCYC_EN);
-	iowrite32(compare, bridge->base + SCYC_CMP);
-	iowrite32(swap, bridge->base + SCYC_SWP);
-	iowrite32(pci_addr, bridge->base + SCYC_ADDR);
-
-	/* Enable RMW */
-	iowrite32(CA91CX42_SCYC_CTL_CYC_RMW, bridge->base + SCYC_CTL);
-
-	/* Kick process off with a read to the required address. */
-	result = ioread32(image->kern_base + offset);
-
-	/* Disable RMW */
-	iowrite32(0, bridge->base + SCYC_CTL);
-
-out:
-	spin_unlock(&image->lock);
-
-	mutex_unlock(&bridge->vme_rmw);
-
-	return result;
-}
-
-static int ca91cx42_dma_list_add(struct vme_dma_list *list,
-	struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
-{
-	struct ca91cx42_dma_entry *entry, *prev;
-	struct vme_dma_pci *pci_attr;
-	struct vme_dma_vme *vme_attr;
-	dma_addr_t desc_ptr;
-	int retval = 0;
-	struct device *dev;
-
-	dev = list->parent->parent->parent;
-
-	/* XXX descriptor must be aligned on 64-bit boundaries */
-	entry = kmalloc(sizeof(struct ca91cx42_dma_entry), GFP_KERNEL);
-	if (entry == NULL) {
-		dev_err(dev, "Failed to allocate memory for dma resource "
-			"structure\n");
-		retval = -ENOMEM;
-		goto err_mem;
-	}
-
-	/* Test descriptor alignment */
-	if ((unsigned long)&entry->descriptor & CA91CX42_DCPP_M) {
-		dev_err(dev, "Descriptor not aligned to 16 byte boundary as "
-			"required: %p\n", &entry->descriptor);
-		retval = -EINVAL;
-		goto err_align;
-	}
-
-	memset(&entry->descriptor, 0, sizeof(struct ca91cx42_dma_descriptor));
-
-	if (dest->type == VME_DMA_VME) {
-		entry->descriptor.dctl |= CA91CX42_DCTL_L2V;
-		vme_attr = dest->private;
-		pci_attr = src->private;
-	} else {
-		vme_attr = src->private;
-		pci_attr = dest->private;
-	}
-
-	/* Check we can do fulfill required attributes */
-	if ((vme_attr->aspace & ~(VME_A16 | VME_A24 | VME_A32 | VME_USER1 |
-		VME_USER2)) != 0) {
-
-		dev_err(dev, "Unsupported cycle type\n");
-		retval = -EINVAL;
-		goto err_aspace;
-	}
-
-	if ((vme_attr->cycle & ~(VME_SCT | VME_BLT | VME_SUPER | VME_USER |
-		VME_PROG | VME_DATA)) != 0) {
-
-		dev_err(dev, "Unsupported cycle type\n");
-		retval = -EINVAL;
-		goto err_cycle;
-	}
-
-	/* Check to see if we can fulfill source and destination */
-	if (!(((src->type == VME_DMA_PCI) && (dest->type == VME_DMA_VME)) ||
-		((src->type == VME_DMA_VME) && (dest->type == VME_DMA_PCI)))) {
-
-		dev_err(dev, "Cannot perform transfer with this "
-			"source-destination combination\n");
-		retval = -EINVAL;
-		goto err_direct;
-	}
-
-	/* Setup cycle types */
-	if (vme_attr->cycle & VME_BLT)
-		entry->descriptor.dctl |= CA91CX42_DCTL_VCT_BLT;
-
-	/* Setup data width */
-	switch (vme_attr->dwidth) {
-	case VME_D8:
-		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D8;
-		break;
-	case VME_D16:
-		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D16;
-		break;
-	case VME_D32:
-		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D32;
-		break;
-	case VME_D64:
-		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D64;
-		break;
-	default:
-		dev_err(dev, "Invalid data width\n");
-		return -EINVAL;
-	}
-
-	/* Setup address space */
-	switch (vme_attr->aspace) {
-	case VME_A16:
-		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A16;
-		break;
-	case VME_A24:
-		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A24;
-		break;
-	case VME_A32:
-		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A32;
-		break;
-	case VME_USER1:
-		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER1;
-		break;
-	case VME_USER2:
-		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER2;
-		break;
-	default:
-		dev_err(dev, "Invalid address space\n");
-		return -EINVAL;
-		break;
-	}
-
-	if (vme_attr->cycle & VME_SUPER)
-		entry->descriptor.dctl |= CA91CX42_DCTL_SUPER_SUPR;
-	if (vme_attr->cycle & VME_PROG)
-		entry->descriptor.dctl |= CA91CX42_DCTL_PGM_PGM;
-
-	entry->descriptor.dtbc = count;
-	entry->descriptor.dla = pci_attr->address;
-	entry->descriptor.dva = vme_attr->address;
-	entry->descriptor.dcpp = CA91CX42_DCPP_NULL;
-
-	/* Add to list */
-	list_add_tail(&entry->list, &list->entries);
-
-	/* Fill out previous descriptors "Next Address" */
-	if (entry->list.prev != &list->entries) {
-		prev = list_entry(entry->list.prev, struct ca91cx42_dma_entry,
-			list);
-		/* We need the bus address for the pointer */
-		desc_ptr = virt_to_bus(&entry->descriptor);
-		prev->descriptor.dcpp = desc_ptr & ~CA91CX42_DCPP_M;
-	}
-
-	return 0;
-
-err_cycle:
-err_aspace:
-err_direct:
-err_align:
-	kfree(entry);
-err_mem:
-	return retval;
-}
-
-static int ca91cx42_dma_busy(struct vme_bridge *ca91cx42_bridge)
-{
-	u32 tmp;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	tmp = ioread32(bridge->base + DGCS);
-
-	if (tmp & CA91CX42_DGCS_ACT)
-		return 0;
-	else
-		return 1;
-}
-
-static int ca91cx42_dma_list_exec(struct vme_dma_list *list)
-{
-	struct vme_dma_resource *ctrlr;
-	struct ca91cx42_dma_entry *entry;
-	int retval = 0;
-	dma_addr_t bus_addr;
-	u32 val;
-	struct device *dev;
-	struct ca91cx42_driver *bridge;
-
-	ctrlr = list->parent;
-
-	bridge = ctrlr->parent->driver_priv;
-	dev = ctrlr->parent->parent;
-
-	mutex_lock(&ctrlr->mtx);
-
-	if (!(list_empty(&ctrlr->running))) {
-		/*
-		 * XXX We have an active DMA transfer and currently haven't
-		 *     sorted out the mechanism for "pending" DMA transfers.
-		 *     Return busy.
-		 */
-		/* Need to add to pending here */
-		mutex_unlock(&ctrlr->mtx);
-		return -EBUSY;
-	} else {
-		list_add(&list->list, &ctrlr->running);
-	}
-
-	/* Get first bus address and write into registers */
-	entry = list_first_entry(&list->entries, struct ca91cx42_dma_entry,
-		list);
-
-	bus_addr = virt_to_bus(&entry->descriptor);
-
-	mutex_unlock(&ctrlr->mtx);
-
-	iowrite32(0, bridge->base + DTBC);
-	iowrite32(bus_addr & ~CA91CX42_DCPP_M, bridge->base + DCPP);
-
-	/* Start the operation */
-	val = ioread32(bridge->base + DGCS);
-
-	/* XXX Could set VMEbus On and Off Counters here */
-	val &= (CA91CX42_DGCS_VON_M | CA91CX42_DGCS_VOFF_M);
-
-	val |= (CA91CX42_DGCS_CHAIN | CA91CX42_DGCS_STOP | CA91CX42_DGCS_HALT |
-		CA91CX42_DGCS_DONE | CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR |
-		CA91CX42_DGCS_PERR);
-
-	iowrite32(val, bridge->base + DGCS);
-
-	val |= CA91CX42_DGCS_GO;
-
-	iowrite32(val, bridge->base + DGCS);
-
-	wait_event_interruptible(bridge->dma_queue,
-		ca91cx42_dma_busy(ctrlr->parent));
-
-	/*
-	 * Read status register, this register is valid until we kick off a
-	 * new transfer.
-	 */
-	val = ioread32(bridge->base + DGCS);
-
-	if (val & (CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR |
-		CA91CX42_DGCS_PERR)) {
-
-		dev_err(dev, "ca91c042: DMA Error. DGCS=%08X\n", val);
-		val = ioread32(bridge->base + DCTL);
-	}
-
-	/* Remove list from running list */
-	mutex_lock(&ctrlr->mtx);
-	list_del(&list->list);
-	mutex_unlock(&ctrlr->mtx);
-
-	return retval;
-
-}
-
-static int ca91cx42_dma_list_empty(struct vme_dma_list *list)
-{
-	struct list_head *pos, *temp;
-	struct ca91cx42_dma_entry *entry;
-
-	/* detach and free each entry */
-	list_for_each_safe(pos, temp, &list->entries) {
-		list_del(pos);
-		entry = list_entry(pos, struct ca91cx42_dma_entry, list);
-		kfree(entry);
-	}
-
-	return 0;
-}
-
-/*
- * All 4 location monitors reside at the same base - this is therefore a
- * system wide configuration.
- *
- * This does not enable the LM monitor - that should be done when the first
- * callback is attached and disabled when the last callback is removed.
- */
-static int ca91cx42_lm_set(struct vme_lm_resource *lm,
-	unsigned long long lm_base, u32 aspace, u32 cycle)
-{
-	u32 temp_base, lm_ctl = 0;
-	int i;
-	struct ca91cx42_driver *bridge;
-	struct device *dev;
-
-	bridge = lm->parent->driver_priv;
-	dev = lm->parent->parent;
-
-	/* Check the alignment of the location monitor */
-	temp_base = (u32)lm_base;
-	if (temp_base & 0xffff) {
-		dev_err(dev, "Location monitor must be aligned to 64KB "
-			"boundary");
-		return -EINVAL;
-	}
-
-	mutex_lock(&lm->mtx);
-
-	/* If we already have a callback attached, we can't move it! */
-	for (i = 0; i < lm->monitors; i++) {
-		if (bridge->lm_callback[i] != NULL) {
-			mutex_unlock(&lm->mtx);
-			dev_err(dev, "Location monitor callback attached, "
-				"can't reset\n");
-			return -EBUSY;
-		}
-	}
-
-	switch (aspace) {
-	case VME_A16:
-		lm_ctl |= CA91CX42_LM_CTL_AS_A16;
-		break;
-	case VME_A24:
-		lm_ctl |= CA91CX42_LM_CTL_AS_A24;
-		break;
-	case VME_A32:
-		lm_ctl |= CA91CX42_LM_CTL_AS_A32;
-		break;
-	default:
-		mutex_unlock(&lm->mtx);
-		dev_err(dev, "Invalid address space\n");
-		return -EINVAL;
-		break;
-	}
-
-	if (cycle & VME_SUPER)
-		lm_ctl |= CA91CX42_LM_CTL_SUPR;
-	if (cycle & VME_USER)
-		lm_ctl |= CA91CX42_LM_CTL_NPRIV;
-	if (cycle & VME_PROG)
-		lm_ctl |= CA91CX42_LM_CTL_PGM;
-	if (cycle & VME_DATA)
-		lm_ctl |= CA91CX42_LM_CTL_DATA;
-
-	iowrite32(lm_base, bridge->base + LM_BS);
-	iowrite32(lm_ctl, bridge->base + LM_CTL);
-
-	mutex_unlock(&lm->mtx);
-
-	return 0;
-}
-
-/* Get configuration of the callback monitor and return whether it is enabled
- * or disabled.
- */
-static int ca91cx42_lm_get(struct vme_lm_resource *lm,
-	unsigned long long *lm_base, u32 *aspace, u32 *cycle)
-{
-	u32 lm_ctl, enabled = 0;
-	struct ca91cx42_driver *bridge;
-
-	bridge = lm->parent->driver_priv;
-
-	mutex_lock(&lm->mtx);
-
-	*lm_base = (unsigned long long)ioread32(bridge->base + LM_BS);
-	lm_ctl = ioread32(bridge->base + LM_CTL);
-
-	if (lm_ctl & CA91CX42_LM_CTL_EN)
-		enabled = 1;
-
-	if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A16)
-		*aspace = VME_A16;
-	if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A24)
-		*aspace = VME_A24;
-	if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A32)
-		*aspace = VME_A32;
-
-	*cycle = 0;
-	if (lm_ctl & CA91CX42_LM_CTL_SUPR)
-		*cycle |= VME_SUPER;
-	if (lm_ctl & CA91CX42_LM_CTL_NPRIV)
-		*cycle |= VME_USER;
-	if (lm_ctl & CA91CX42_LM_CTL_PGM)
-		*cycle |= VME_PROG;
-	if (lm_ctl & CA91CX42_LM_CTL_DATA)
-		*cycle |= VME_DATA;
-
-	mutex_unlock(&lm->mtx);
-
-	return enabled;
-}
-
-/*
- * Attach a callback to a specific location monitor.
- *
- * Callback will be passed the monitor triggered.
- */
-static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
-	void (*callback)(int))
-{
-	u32 lm_ctl, tmp;
-	struct ca91cx42_driver *bridge;
-	struct device *dev;
-
-	bridge = lm->parent->driver_priv;
-	dev = lm->parent->parent;
-
-	mutex_lock(&lm->mtx);
-
-	/* Ensure that the location monitor is configured - need PGM or DATA */
-	lm_ctl = ioread32(bridge->base + LM_CTL);
-	if ((lm_ctl & (CA91CX42_LM_CTL_PGM | CA91CX42_LM_CTL_DATA)) == 0) {
-		mutex_unlock(&lm->mtx);
-		dev_err(dev, "Location monitor not properly configured\n");
-		return -EINVAL;
-	}
-
-	/* Check that a callback isn't already attached */
-	if (bridge->lm_callback[monitor] != NULL) {
-		mutex_unlock(&lm->mtx);
-		dev_err(dev, "Existing callback attached\n");
-		return -EBUSY;
-	}
-
-	/* Attach callback */
-	bridge->lm_callback[monitor] = callback;
-
-	/* Enable Location Monitor interrupt */
-	tmp = ioread32(bridge->base + LINT_EN);
-	tmp |= CA91CX42_LINT_LM[monitor];
-	iowrite32(tmp, bridge->base + LINT_EN);
-
-	/* Ensure that global Location Monitor Enable set */
-	if ((lm_ctl & CA91CX42_LM_CTL_EN) == 0) {
-		lm_ctl |= CA91CX42_LM_CTL_EN;
-		iowrite32(lm_ctl, bridge->base + LM_CTL);
-	}
-
-	mutex_unlock(&lm->mtx);
-
-	return 0;
-}
-
-/*
- * Detach a callback function forn a specific location monitor.
- */
-static int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor)
-{
-	u32 tmp;
-	struct ca91cx42_driver *bridge;
-
-	bridge = lm->parent->driver_priv;
-
-	mutex_lock(&lm->mtx);
-
-	/* Disable Location Monitor and ensure previous interrupts are clear */
-	tmp = ioread32(bridge->base + LINT_EN);
-	tmp &= ~CA91CX42_LINT_LM[monitor];
-	iowrite32(tmp, bridge->base + LINT_EN);
-
-	iowrite32(CA91CX42_LINT_LM[monitor],
-		 bridge->base + LINT_STAT);
-
-	/* Detach callback */
-	bridge->lm_callback[monitor] = NULL;
-
-	/* If all location monitors disabled, disable global Location Monitor */
-	if ((tmp & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 |
-			CA91CX42_LINT_LM3)) == 0) {
-		tmp = ioread32(bridge->base + LM_CTL);
-		tmp &= ~CA91CX42_LM_CTL_EN;
-		iowrite32(tmp, bridge->base + LM_CTL);
-	}
-
-	mutex_unlock(&lm->mtx);
-
-	return 0;
-}
-
-static int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge)
-{
-	u32 slot = 0;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	if (!geoid) {
-		slot = ioread32(bridge->base + VCSR_BS);
-		slot = ((slot & CA91CX42_VCSR_BS_SLOT_M) >> 27);
-	} else
-		slot = geoid;
-
-	return (int)slot;
-
-}
-
-void *ca91cx42_alloc_consistent(struct device *parent, size_t size,
-	dma_addr_t *dma)
-{
-	struct pci_dev *pdev;
-
-	/* Find pci_dev container of dev */
-	pdev = container_of(parent, struct pci_dev, dev);
-
-	return pci_alloc_consistent(pdev, size, dma);
-}
-
-void ca91cx42_free_consistent(struct device *parent, size_t size, void *vaddr,
-	dma_addr_t dma)
-{
-	struct pci_dev *pdev;
-
-	/* Find pci_dev container of dev */
-	pdev = container_of(parent, struct pci_dev, dev);
-
-	pci_free_consistent(pdev, size, vaddr, dma);
-}
-
-static int __init ca91cx42_init(void)
-{
-	return pci_register_driver(&ca91cx42_driver);
-}
-
-/*
- * Configure CR/CSR space
- *
- * Access to the CR/CSR can be configured at power-up. The location of the
- * CR/CSR registers in the CR/CSR address space is determined by the boards
- * Auto-ID or Geographic address. This function ensures that the window is
- * enabled at an offset consistent with the boards geopgraphic address.
- */
-static int ca91cx42_crcsr_init(struct vme_bridge *ca91cx42_bridge,
-	struct pci_dev *pdev)
-{
-	unsigned int crcsr_addr;
-	int tmp, slot;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	slot = ca91cx42_slot_get(ca91cx42_bridge);
-
-	/* Write CSR Base Address if slot ID is supplied as a module param */
-	if (geoid)
-		iowrite32(geoid << 27, bridge->base + VCSR_BS);
-
-	dev_info(&pdev->dev, "CR/CSR Offset: %d\n", slot);
-	if (slot == 0) {
-		dev_err(&pdev->dev, "Slot number is unset, not configuring "
-			"CR/CSR space\n");
-		return -EINVAL;
-	}
-
-	/* Allocate mem for CR/CSR image */
-	bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
-		&bridge->crcsr_bus);
-	if (bridge->crcsr_kernel == NULL) {
-		dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR "
-			"image\n");
-		return -ENOMEM;
-	}
-
-	memset(bridge->crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
-
-	crcsr_addr = slot * (512 * 1024);
-	iowrite32(bridge->crcsr_bus - crcsr_addr, bridge->base + VCSR_TO);
-
-	tmp = ioread32(bridge->base + VCSR_CTL);
-	tmp |= CA91CX42_VCSR_CTL_EN;
-	iowrite32(tmp, bridge->base + VCSR_CTL);
-
-	return 0;
-}
-
-static void ca91cx42_crcsr_exit(struct vme_bridge *ca91cx42_bridge,
-	struct pci_dev *pdev)
-{
-	u32 tmp;
-	struct ca91cx42_driver *bridge;
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-	/* Turn off CR/CSR space */
-	tmp = ioread32(bridge->base + VCSR_CTL);
-	tmp &= ~CA91CX42_VCSR_CTL_EN;
-	iowrite32(tmp, bridge->base + VCSR_CTL);
-
-	/* Free image */
-	iowrite32(0, bridge->base + VCSR_TO);
-
-	pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, bridge->crcsr_kernel,
-		bridge->crcsr_bus);
-}
-
-static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	int retval, i;
-	u32 data;
-	struct list_head *pos = NULL;
-	struct vme_bridge *ca91cx42_bridge;
-	struct ca91cx42_driver *ca91cx42_device;
-	struct vme_master_resource *master_image;
-	struct vme_slave_resource *slave_image;
-	struct vme_dma_resource *dma_ctrlr;
-	struct vme_lm_resource *lm;
-
-	/* We want to support more than one of each bridge so we need to
-	 * dynamically allocate the bridge structure
-	 */
-	ca91cx42_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL);
-
-	if (ca91cx42_bridge == NULL) {
-		dev_err(&pdev->dev, "Failed to allocate memory for device "
-			"structure\n");
-		retval = -ENOMEM;
-		goto err_struct;
-	}
-
-	ca91cx42_device = kzalloc(sizeof(struct ca91cx42_driver), GFP_KERNEL);
-
-	if (ca91cx42_device == NULL) {
-		dev_err(&pdev->dev, "Failed to allocate memory for device "
-			"structure\n");
-		retval = -ENOMEM;
-		goto err_driver;
-	}
-
-	ca91cx42_bridge->driver_priv = ca91cx42_device;
-
-	/* Enable the device */
-	retval = pci_enable_device(pdev);
-	if (retval) {
-		dev_err(&pdev->dev, "Unable to enable device\n");
-		goto err_enable;
-	}
-
-	/* Map Registers */
-	retval = pci_request_regions(pdev, driver_name);
-	if (retval) {
-		dev_err(&pdev->dev, "Unable to reserve resources\n");
-		goto err_resource;
-	}
-
-	/* map registers in BAR 0 */
-	ca91cx42_device->base = ioremap_nocache(pci_resource_start(pdev, 0),
-		4096);
-	if (!ca91cx42_device->base) {
-		dev_err(&pdev->dev, "Unable to remap CRG region\n");
-		retval = -EIO;
-		goto err_remap;
-	}
-
-	/* Check to see if the mapping worked out */
-	data = ioread32(ca91cx42_device->base + CA91CX42_PCI_ID) & 0x0000FFFF;
-	if (data != PCI_VENDOR_ID_TUNDRA) {
-		dev_err(&pdev->dev, "PCI_ID check failed\n");
-		retval = -EIO;
-		goto err_test;
-	}
-
-	/* Initialize wait queues & mutual exclusion flags */
-	init_waitqueue_head(&ca91cx42_device->dma_queue);
-	init_waitqueue_head(&ca91cx42_device->iack_queue);
-	mutex_init(&ca91cx42_device->vme_int);
-	mutex_init(&ca91cx42_device->vme_rmw);
-
-	ca91cx42_bridge->parent = &pdev->dev;
-	strcpy(ca91cx42_bridge->name, driver_name);
-
-	/* Setup IRQ */
-	retval = ca91cx42_irq_init(ca91cx42_bridge);
-	if (retval != 0) {
-		dev_err(&pdev->dev, "Chip Initialization failed.\n");
-		goto err_irq;
-	}
-
-	/* Add master windows to list */
-	INIT_LIST_HEAD(&ca91cx42_bridge->master_resources);
-	for (i = 0; i < CA91C142_MAX_MASTER; i++) {
-		master_image = kmalloc(sizeof(struct vme_master_resource),
-			GFP_KERNEL);
-		if (master_image == NULL) {
-			dev_err(&pdev->dev, "Failed to allocate memory for "
-			"master resource structure\n");
-			retval = -ENOMEM;
-			goto err_master;
-		}
-		master_image->parent = ca91cx42_bridge;
-		spin_lock_init(&master_image->lock);
-		master_image->locked = 0;
-		master_image->number = i;
-		master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
-			VME_CRCSR | VME_USER1 | VME_USER2;
-		master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
-			VME_SUPER | VME_USER | VME_PROG | VME_DATA;
-		master_image->width_attr = VME_D8 | VME_D16 | VME_D32 | VME_D64;
-		memset(&master_image->bus_resource, 0,
-			sizeof(struct resource));
-		master_image->kern_base  = NULL;
-		list_add_tail(&master_image->list,
-			&ca91cx42_bridge->master_resources);
-	}
-
-	/* Add slave windows to list */
-	INIT_LIST_HEAD(&ca91cx42_bridge->slave_resources);
-	for (i = 0; i < CA91C142_MAX_SLAVE; i++) {
-		slave_image = kmalloc(sizeof(struct vme_slave_resource),
-			GFP_KERNEL);
-		if (slave_image == NULL) {
-			dev_err(&pdev->dev, "Failed to allocate memory for "
-			"slave resource structure\n");
-			retval = -ENOMEM;
-			goto err_slave;
-		}
-		slave_image->parent = ca91cx42_bridge;
-		mutex_init(&slave_image->mtx);
-		slave_image->locked = 0;
-		slave_image->number = i;
-		slave_image->address_attr = VME_A24 | VME_A32 | VME_USER1 |
-			VME_USER2;
-
-		/* Only windows 0 and 4 support A16 */
-		if (i == 0 || i == 4)
-			slave_image->address_attr |= VME_A16;
-
-		slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
-			VME_SUPER | VME_USER | VME_PROG | VME_DATA;
-		list_add_tail(&slave_image->list,
-			&ca91cx42_bridge->slave_resources);
-	}
-
-	/* Add dma engines to list */
-	INIT_LIST_HEAD(&ca91cx42_bridge->dma_resources);
-	for (i = 0; i < CA91C142_MAX_DMA; i++) {
-		dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource),
-			GFP_KERNEL);
-		if (dma_ctrlr == NULL) {
-			dev_err(&pdev->dev, "Failed to allocate memory for "
-			"dma resource structure\n");
-			retval = -ENOMEM;
-			goto err_dma;
-		}
-		dma_ctrlr->parent = ca91cx42_bridge;
-		mutex_init(&dma_ctrlr->mtx);
-		dma_ctrlr->locked = 0;
-		dma_ctrlr->number = i;
-		dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
-			VME_DMA_MEM_TO_VME;
-		INIT_LIST_HEAD(&dma_ctrlr->pending);
-		INIT_LIST_HEAD(&dma_ctrlr->running);
-		list_add_tail(&dma_ctrlr->list,
-			&ca91cx42_bridge->dma_resources);
-	}
-
-	/* Add location monitor to list */
-	INIT_LIST_HEAD(&ca91cx42_bridge->lm_resources);
-	lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
-	if (lm == NULL) {
-		dev_err(&pdev->dev, "Failed to allocate memory for "
-		"location monitor resource structure\n");
-		retval = -ENOMEM;
-		goto err_lm;
-	}
-	lm->parent = ca91cx42_bridge;
-	mutex_init(&lm->mtx);
-	lm->locked = 0;
-	lm->number = 1;
-	lm->monitors = 4;
-	list_add_tail(&lm->list, &ca91cx42_bridge->lm_resources);
-
-	ca91cx42_bridge->slave_get = ca91cx42_slave_get;
-	ca91cx42_bridge->slave_set = ca91cx42_slave_set;
-	ca91cx42_bridge->master_get = ca91cx42_master_get;
-	ca91cx42_bridge->master_set = ca91cx42_master_set;
-	ca91cx42_bridge->master_read = ca91cx42_master_read;
-	ca91cx42_bridge->master_write = ca91cx42_master_write;
-	ca91cx42_bridge->master_rmw = ca91cx42_master_rmw;
-	ca91cx42_bridge->dma_list_add = ca91cx42_dma_list_add;
-	ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec;
-	ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty;
-	ca91cx42_bridge->irq_set = ca91cx42_irq_set;
-	ca91cx42_bridge->irq_generate = ca91cx42_irq_generate;
-	ca91cx42_bridge->lm_set = ca91cx42_lm_set;
-	ca91cx42_bridge->lm_get = ca91cx42_lm_get;
-	ca91cx42_bridge->lm_attach = ca91cx42_lm_attach;
-	ca91cx42_bridge->lm_detach = ca91cx42_lm_detach;
-	ca91cx42_bridge->slot_get = ca91cx42_slot_get;
-	ca91cx42_bridge->alloc_consistent = ca91cx42_alloc_consistent;
-	ca91cx42_bridge->free_consistent = ca91cx42_free_consistent;
-
-	data = ioread32(ca91cx42_device->base + MISC_CTL);
-	dev_info(&pdev->dev, "Board is%s the VME system controller\n",
-		(data & CA91CX42_MISC_CTL_SYSCON) ? "" : " not");
-	dev_info(&pdev->dev, "Slot ID is %d\n",
-		ca91cx42_slot_get(ca91cx42_bridge));
-
-	if (ca91cx42_crcsr_init(ca91cx42_bridge, pdev))
-		dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
-
-	/* Need to save ca91cx42_bridge pointer locally in link list for use in
-	 * ca91cx42_remove()
-	 */
-	retval = vme_register_bridge(ca91cx42_bridge);
-	if (retval != 0) {
-		dev_err(&pdev->dev, "Chip Registration failed.\n");
-		goto err_reg;
-	}
-
-	pci_set_drvdata(pdev, ca91cx42_bridge);
-
-	return 0;
-
-err_reg:
-	ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
-err_lm:
-	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->lm_resources) {
-		lm = list_entry(pos, struct vme_lm_resource, list);
-		list_del(pos);
-		kfree(lm);
-	}
-err_dma:
-	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->dma_resources) {
-		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
-		list_del(pos);
-		kfree(dma_ctrlr);
-	}
-err_slave:
-	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->slave_resources) {
-		slave_image = list_entry(pos, struct vme_slave_resource, list);
-		list_del(pos);
-		kfree(slave_image);
-	}
-err_master:
-	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->master_resources) {
-		master_image = list_entry(pos, struct vme_master_resource,
-			list);
-		list_del(pos);
-		kfree(master_image);
-	}
-
-	ca91cx42_irq_exit(ca91cx42_device, pdev);
-err_irq:
-err_test:
-	iounmap(ca91cx42_device->base);
-err_remap:
-	pci_release_regions(pdev);
-err_resource:
-	pci_disable_device(pdev);
-err_enable:
-	kfree(ca91cx42_device);
-err_driver:
-	kfree(ca91cx42_bridge);
-err_struct:
-	return retval;
-
-}
-
-static void ca91cx42_remove(struct pci_dev *pdev)
-{
-	struct list_head *pos = NULL;
-	struct vme_master_resource *master_image;
-	struct vme_slave_resource *slave_image;
-	struct vme_dma_resource *dma_ctrlr;
-	struct vme_lm_resource *lm;
-	struct ca91cx42_driver *bridge;
-	struct vme_bridge *ca91cx42_bridge = pci_get_drvdata(pdev);
-
-	bridge = ca91cx42_bridge->driver_priv;
-
-
-	/* Turn off Ints */
-	iowrite32(0, bridge->base + LINT_EN);
-
-	/* Turn off the windows */
-	iowrite32(0x00800000, bridge->base + LSI0_CTL);
-	iowrite32(0x00800000, bridge->base + LSI1_CTL);
-	iowrite32(0x00800000, bridge->base + LSI2_CTL);
-	iowrite32(0x00800000, bridge->base + LSI3_CTL);
-	iowrite32(0x00800000, bridge->base + LSI4_CTL);
-	iowrite32(0x00800000, bridge->base + LSI5_CTL);
-	iowrite32(0x00800000, bridge->base + LSI6_CTL);
-	iowrite32(0x00800000, bridge->base + LSI7_CTL);
-	iowrite32(0x00F00000, bridge->base + VSI0_CTL);
-	iowrite32(0x00F00000, bridge->base + VSI1_CTL);
-	iowrite32(0x00F00000, bridge->base + VSI2_CTL);
-	iowrite32(0x00F00000, bridge->base + VSI3_CTL);
-	iowrite32(0x00F00000, bridge->base + VSI4_CTL);
-	iowrite32(0x00F00000, bridge->base + VSI5_CTL);
-	iowrite32(0x00F00000, bridge->base + VSI6_CTL);
-	iowrite32(0x00F00000, bridge->base + VSI7_CTL);
-
-	vme_unregister_bridge(ca91cx42_bridge);
-
-	ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
-
-	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->lm_resources) {
-		lm = list_entry(pos, struct vme_lm_resource, list);
-		list_del(pos);
-		kfree(lm);
-	}
-
-	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->dma_resources) {
-		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
-		list_del(pos);
-		kfree(dma_ctrlr);
-	}
-
-	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->slave_resources) {
-		slave_image = list_entry(pos, struct vme_slave_resource, list);
-		list_del(pos);
-		kfree(slave_image);
-	}
-
-	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->master_resources) {
-		master_image = list_entry(pos, struct vme_master_resource,
-			list);
-		list_del(pos);
-		kfree(master_image);
-	}
-
-	ca91cx42_irq_exit(bridge, pdev);
-
-	iounmap(bridge->base);
-
-	pci_release_regions(pdev);
-
-	pci_disable_device(pdev);
-
-	kfree(ca91cx42_bridge);
-}
-
-static void __exit ca91cx42_exit(void)
-{
-	pci_unregister_driver(&ca91cx42_driver);
-}
-
-MODULE_PARM_DESC(geoid, "Override geographical addressing");
-module_param(geoid, int, 0);
-
-MODULE_DESCRIPTION("VME driver for the Tundra Universe II VME bridge");
-MODULE_LICENSE("GPL");
-
-module_init(ca91cx42_init);
-module_exit(ca91cx42_exit);
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c
deleted file mode 100644
index f505821..0000000
--- a/drivers/staging/vme/bridges/vme_tsi148.c
+++ /dev/null
@@ -1,2660 +0,0 @@
-/*
- * Support for the Tundra TSI148 VME-PCI Bridge Chip
- *
- * Author: Martyn Welch <martyn.welch@ge.com>
- * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
- *
- * Based on work by Tom Armistead and Ajit Prem
- * Copyright 2004 Motorola Inc.
- *
- * 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/mm.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/pci.h>
-#include <linux/poll.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-
-#include "../vme.h"
-#include "../vme_bridge.h"
-#include "vme_tsi148.h"
-
-static int __init tsi148_init(void);
-static int tsi148_probe(struct pci_dev *, const struct pci_device_id *);
-static void tsi148_remove(struct pci_dev *);
-static void __exit tsi148_exit(void);
-
-
-/* Module parameter */
-static bool err_chk;
-static int geoid;
-
-static const char driver_name[] = "vme_tsi148";
-
-static DEFINE_PCI_DEVICE_TABLE(tsi148_ids) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) },
-	{ },
-};
-
-static struct pci_driver tsi148_driver = {
-	.name = driver_name,
-	.id_table = tsi148_ids,
-	.probe = tsi148_probe,
-	.remove = tsi148_remove,
-};
-
-static void reg_join(unsigned int high, unsigned int low,
-	unsigned long long *variable)
-{
-	*variable = (unsigned long long)high << 32;
-	*variable |= (unsigned long long)low;
-}
-
-static void reg_split(unsigned long long variable, unsigned int *high,
-	unsigned int *low)
-{
-	*low = (unsigned int)variable & 0xFFFFFFFF;
-	*high = (unsigned int)(variable >> 32);
-}
-
-/*
- * Wakes up DMA queue.
- */
-static u32 tsi148_DMA_irqhandler(struct tsi148_driver *bridge,
-	int channel_mask)
-{
-	u32 serviced = 0;
-
-	if (channel_mask & TSI148_LCSR_INTS_DMA0S) {
-		wake_up(&bridge->dma_queue[0]);
-		serviced |= TSI148_LCSR_INTC_DMA0C;
-	}
-	if (channel_mask & TSI148_LCSR_INTS_DMA1S) {
-		wake_up(&bridge->dma_queue[1]);
-		serviced |= TSI148_LCSR_INTC_DMA1C;
-	}
-
-	return serviced;
-}
-
-/*
- * Wake up location monitor queue
- */
-static u32 tsi148_LM_irqhandler(struct tsi148_driver *bridge, u32 stat)
-{
-	int i;
-	u32 serviced = 0;
-
-	for (i = 0; i < 4; i++) {
-		if (stat & TSI148_LCSR_INTS_LMS[i]) {
-			/* We only enable interrupts if the callback is set */
-			bridge->lm_callback[i](i);
-			serviced |= TSI148_LCSR_INTC_LMC[i];
-		}
-	}
-
-	return serviced;
-}
-
-/*
- * Wake up mail box queue.
- *
- * XXX This functionality is not exposed up though API.
- */
-static u32 tsi148_MB_irqhandler(struct vme_bridge *tsi148_bridge, u32 stat)
-{
-	int i;
-	u32 val;
-	u32 serviced = 0;
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	for (i = 0; i < 4; i++) {
-		if (stat & TSI148_LCSR_INTS_MBS[i]) {
-			val = ioread32be(bridge->base +	TSI148_GCSR_MBOX[i]);
-			dev_err(tsi148_bridge->parent, "VME Mailbox %d received"
-				": 0x%x\n", i, val);
-			serviced |= TSI148_LCSR_INTC_MBC[i];
-		}
-	}
-
-	return serviced;
-}
-
-/*
- * Display error & status message when PERR (PCI) exception interrupt occurs.
- */
-static u32 tsi148_PERR_irqhandler(struct vme_bridge *tsi148_bridge)
-{
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	dev_err(tsi148_bridge->parent, "PCI Exception at address: 0x%08x:%08x, "
-		"attributes: %08x\n",
-		ioread32be(bridge->base + TSI148_LCSR_EDPAU),
-		ioread32be(bridge->base + TSI148_LCSR_EDPAL),
-		ioread32be(bridge->base + TSI148_LCSR_EDPAT));
-
-	dev_err(tsi148_bridge->parent, "PCI-X attribute reg: %08x, PCI-X split "
-		"completion reg: %08x\n",
-		ioread32be(bridge->base + TSI148_LCSR_EDPXA),
-		ioread32be(bridge->base + TSI148_LCSR_EDPXS));
-
-	iowrite32be(TSI148_LCSR_EDPAT_EDPCL, bridge->base + TSI148_LCSR_EDPAT);
-
-	return TSI148_LCSR_INTC_PERRC;
-}
-
-/*
- * Save address and status when VME error interrupt occurs.
- */
-static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge)
-{
-	unsigned int error_addr_high, error_addr_low;
-	unsigned long long error_addr;
-	u32 error_attrib;
-	struct vme_bus_error *error;
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	error_addr_high = ioread32be(bridge->base + TSI148_LCSR_VEAU);
-	error_addr_low = ioread32be(bridge->base + TSI148_LCSR_VEAL);
-	error_attrib = ioread32be(bridge->base + TSI148_LCSR_VEAT);
-
-	reg_join(error_addr_high, error_addr_low, &error_addr);
-
-	/* Check for exception register overflow (we have lost error data) */
-	if (error_attrib & TSI148_LCSR_VEAT_VEOF) {
-		dev_err(tsi148_bridge->parent, "VME Bus Exception Overflow "
-			"Occurred\n");
-	}
-
-	error = kmalloc(sizeof(struct vme_bus_error), GFP_ATOMIC);
-	if (error) {
-		error->address = error_addr;
-		error->attributes = error_attrib;
-		list_add_tail(&error->list, &tsi148_bridge->vme_errors);
-	} else {
-		dev_err(tsi148_bridge->parent, "Unable to alloc memory for "
-			"VMEbus Error reporting\n");
-		dev_err(tsi148_bridge->parent, "VME Bus Error at address: "
-			"0x%llx, attributes: %08x\n", error_addr, error_attrib);
-	}
-
-	/* Clear Status */
-	iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT);
-
-	return TSI148_LCSR_INTC_VERRC;
-}
-
-/*
- * Wake up IACK queue.
- */
-static u32 tsi148_IACK_irqhandler(struct tsi148_driver *bridge)
-{
-	wake_up(&bridge->iack_queue);
-
-	return TSI148_LCSR_INTC_IACKC;
-}
-
-/*
- * Calling VME bus interrupt callback if provided.
- */
-static u32 tsi148_VIRQ_irqhandler(struct vme_bridge *tsi148_bridge,
-	u32 stat)
-{
-	int vec, i, serviced = 0;
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	for (i = 7; i > 0; i--) {
-		if (stat & (1 << i)) {
-			/*
-			 * Note: Even though the registers are defined as
-			 * 32-bits in the spec, we only want to issue 8-bit
-			 * IACK cycles on the bus, read from offset 3.
-			 */
-			vec = ioread8(bridge->base + TSI148_LCSR_VIACK[i] + 3);
-
-			vme_irq_handler(tsi148_bridge, i, vec);
-
-			serviced |= (1 << i);
-		}
-	}
-
-	return serviced;
-}
-
-/*
- * Top level interrupt handler.  Clears appropriate interrupt status bits and
- * then calls appropriate sub handler(s).
- */
-static irqreturn_t tsi148_irqhandler(int irq, void *ptr)
-{
-	u32 stat, enable, serviced = 0;
-	struct vme_bridge *tsi148_bridge;
-	struct tsi148_driver *bridge;
-
-	tsi148_bridge = ptr;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	/* Determine which interrupts are unmasked and set */
-	enable = ioread32be(bridge->base + TSI148_LCSR_INTEO);
-	stat = ioread32be(bridge->base + TSI148_LCSR_INTS);
-
-	/* Only look at unmasked interrupts */
-	stat &= enable;
-
-	if (unlikely(!stat))
-		return IRQ_NONE;
-
-	/* Call subhandlers as appropriate */
-	/* DMA irqs */
-	if (stat & (TSI148_LCSR_INTS_DMA1S | TSI148_LCSR_INTS_DMA0S))
-		serviced |= tsi148_DMA_irqhandler(bridge, stat);
-
-	/* Location monitor irqs */
-	if (stat & (TSI148_LCSR_INTS_LM3S | TSI148_LCSR_INTS_LM2S |
-			TSI148_LCSR_INTS_LM1S | TSI148_LCSR_INTS_LM0S))
-		serviced |= tsi148_LM_irqhandler(bridge, stat);
-
-	/* Mail box irqs */
-	if (stat & (TSI148_LCSR_INTS_MB3S | TSI148_LCSR_INTS_MB2S |
-			TSI148_LCSR_INTS_MB1S | TSI148_LCSR_INTS_MB0S))
-		serviced |= tsi148_MB_irqhandler(tsi148_bridge, stat);
-
-	/* PCI bus error */
-	if (stat & TSI148_LCSR_INTS_PERRS)
-		serviced |= tsi148_PERR_irqhandler(tsi148_bridge);
-
-	/* VME bus error */
-	if (stat & TSI148_LCSR_INTS_VERRS)
-		serviced |= tsi148_VERR_irqhandler(tsi148_bridge);
-
-	/* IACK irq */
-	if (stat & TSI148_LCSR_INTS_IACKS)
-		serviced |= tsi148_IACK_irqhandler(bridge);
-
-	/* VME bus irqs */
-	if (stat & (TSI148_LCSR_INTS_IRQ7S | TSI148_LCSR_INTS_IRQ6S |
-			TSI148_LCSR_INTS_IRQ5S | TSI148_LCSR_INTS_IRQ4S |
-			TSI148_LCSR_INTS_IRQ3S | TSI148_LCSR_INTS_IRQ2S |
-			TSI148_LCSR_INTS_IRQ1S))
-		serviced |= tsi148_VIRQ_irqhandler(tsi148_bridge, stat);
-
-	/* Clear serviced interrupts */
-	iowrite32be(serviced, bridge->base + TSI148_LCSR_INTC);
-
-	return IRQ_HANDLED;
-}
-
-static int tsi148_irq_init(struct vme_bridge *tsi148_bridge)
-{
-	int result;
-	unsigned int tmp;
-	struct pci_dev *pdev;
-	struct tsi148_driver *bridge;
-
-	pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
-
-	bridge = tsi148_bridge->driver_priv;
-
-	/* Initialise list for VME bus errors */
-	INIT_LIST_HEAD(&tsi148_bridge->vme_errors);
-
-	mutex_init(&tsi148_bridge->irq_mtx);
-
-	result = request_irq(pdev->irq,
-			     tsi148_irqhandler,
-			     IRQF_SHARED,
-			     driver_name, tsi148_bridge);
-	if (result) {
-		dev_err(tsi148_bridge->parent, "Can't get assigned pci irq "
-			"vector %02X\n", pdev->irq);
-		return result;
-	}
-
-	/* Enable and unmask interrupts */
-	tmp = TSI148_LCSR_INTEO_DMA1EO | TSI148_LCSR_INTEO_DMA0EO |
-		TSI148_LCSR_INTEO_MB3EO | TSI148_LCSR_INTEO_MB2EO |
-		TSI148_LCSR_INTEO_MB1EO | TSI148_LCSR_INTEO_MB0EO |
-		TSI148_LCSR_INTEO_PERREO | TSI148_LCSR_INTEO_VERREO |
-		TSI148_LCSR_INTEO_IACKEO;
-
-	/* This leaves the following interrupts masked.
-	 * TSI148_LCSR_INTEO_VIEEO
-	 * TSI148_LCSR_INTEO_SYSFLEO
-	 * TSI148_LCSR_INTEO_ACFLEO
-	 */
-
-	/* Don't enable Location Monitor interrupts here - they will be
-	 * enabled when the location monitors are properly configured and
-	 * a callback has been attached.
-	 * TSI148_LCSR_INTEO_LM0EO
-	 * TSI148_LCSR_INTEO_LM1EO
-	 * TSI148_LCSR_INTEO_LM2EO
-	 * TSI148_LCSR_INTEO_LM3EO
-	 */
-
-	/* Don't enable VME interrupts until we add a handler, else the board
-	 * will respond to it and we don't want that unless it knows how to
-	 * properly deal with it.
-	 * TSI148_LCSR_INTEO_IRQ7EO
-	 * TSI148_LCSR_INTEO_IRQ6EO
-	 * TSI148_LCSR_INTEO_IRQ5EO
-	 * TSI148_LCSR_INTEO_IRQ4EO
-	 * TSI148_LCSR_INTEO_IRQ3EO
-	 * TSI148_LCSR_INTEO_IRQ2EO
-	 * TSI148_LCSR_INTEO_IRQ1EO
-	 */
-
-	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
-	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
-
-	return 0;
-}
-
-static void tsi148_irq_exit(struct vme_bridge *tsi148_bridge,
-	struct pci_dev *pdev)
-{
-	struct tsi148_driver *bridge = tsi148_bridge->driver_priv;
-
-	/* Turn off interrupts */
-	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEO);
-	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEN);
-
-	/* Clear all interrupts */
-	iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_INTC);
-
-	/* Detach interrupt handler */
-	free_irq(pdev->irq, tsi148_bridge);
-}
-
-/*
- * Check to see if an IACk has been received, return true (1) or false (0).
- */
-static int tsi148_iack_received(struct tsi148_driver *bridge)
-{
-	u32 tmp;
-
-	tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
-
-	if (tmp & TSI148_LCSR_VICR_IRQS)
-		return 0;
-	else
-		return 1;
-}
-
-/*
- * Configure VME interrupt
- */
-static void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level,
-	int state, int sync)
-{
-	struct pci_dev *pdev;
-	u32 tmp;
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	/* We need to do the ordering differently for enabling and disabling */
-	if (state == 0) {
-		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
-		tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1];
-		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
-
-		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
-		tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1];
-		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
-
-		if (sync != 0) {
-			pdev = container_of(tsi148_bridge->parent,
-				struct pci_dev, dev);
-
-			synchronize_irq(pdev->irq);
-		}
-	} else {
-		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
-		tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
-		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
-
-		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
-		tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
-		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
-	}
-}
-
-/*
- * Generate a VME bus interrupt at the requested level & vector. Wait for
- * interrupt to be acked.
- */
-static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level,
-	int statid)
-{
-	u32 tmp;
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	mutex_lock(&bridge->vme_int);
-
-	/* Read VICR register */
-	tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
-
-	/* Set Status/ID */
-	tmp = (tmp & ~TSI148_LCSR_VICR_STID_M) |
-		(statid & TSI148_LCSR_VICR_STID_M);
-	iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
-
-	/* Assert VMEbus IRQ */
-	tmp = tmp | TSI148_LCSR_VICR_IRQL[level];
-	iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
-
-	/* XXX Consider implementing a timeout? */
-	wait_event_interruptible(bridge->iack_queue,
-		tsi148_iack_received(bridge));
-
-	mutex_unlock(&bridge->vme_int);
-
-	return 0;
-}
-
-/*
- * Find the first error in this address range
- */
-static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge,
-	u32 aspace, unsigned long long address, size_t count)
-{
-	struct list_head *err_pos;
-	struct vme_bus_error *vme_err, *valid = NULL;
-	unsigned long long bound;
-
-	bound = address + count;
-
-	/*
-	 * XXX We are currently not looking at the address space when parsing
-	 *     for errors. This is because parsing the Address Modifier Codes
-	 *     is going to be quite resource intensive to do properly. We
-	 *     should be OK just looking at the addresses and this is certainly
-	 *     much better than what we had before.
-	 */
-	err_pos = NULL;
-	/* Iterate through errors */
-	list_for_each(err_pos, &tsi148_bridge->vme_errors) {
-		vme_err = list_entry(err_pos, struct vme_bus_error, list);
-		if ((vme_err->address >= address) &&
-			(vme_err->address < bound)) {
-
-			valid = vme_err;
-			break;
-		}
-	}
-
-	return valid;
-}
-
-/*
- * Clear errors in the provided address range.
- */
-static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge,
-	u32 aspace, unsigned long long address, size_t count)
-{
-	struct list_head *err_pos, *temp;
-	struct vme_bus_error *vme_err;
-	unsigned long long bound;
-
-	bound = address + count;
-
-	/*
-	 * XXX We are currently not looking at the address space when parsing
-	 *     for errors. This is because parsing the Address Modifier Codes
-	 *     is going to be quite resource intensive to do properly. We
-	 *     should be OK just looking at the addresses and this is certainly
-	 *     much better than what we had before.
-	 */
-	err_pos = NULL;
-	/* Iterate through errors */
-	list_for_each_safe(err_pos, temp, &tsi148_bridge->vme_errors) {
-		vme_err = list_entry(err_pos, struct vme_bus_error, list);
-
-		if ((vme_err->address >= address) &&
-			(vme_err->address < bound)) {
-
-			list_del(err_pos);
-			kfree(vme_err);
-		}
-	}
-}
-
-/*
- * Initialize a slave window with the requested attributes.
- */
-static int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
-	unsigned long long vme_base, unsigned long long size,
-	dma_addr_t pci_base, u32 aspace, u32 cycle)
-{
-	unsigned int i, addr = 0, granularity = 0;
-	unsigned int temp_ctl = 0;
-	unsigned int vme_base_low, vme_base_high;
-	unsigned int vme_bound_low, vme_bound_high;
-	unsigned int pci_offset_low, pci_offset_high;
-	unsigned long long vme_bound, pci_offset;
-	struct vme_bridge *tsi148_bridge;
-	struct tsi148_driver *bridge;
-
-	tsi148_bridge = image->parent;
-	bridge = tsi148_bridge->driver_priv;
-
-	i = image->number;
-
-	switch (aspace) {
-	case VME_A16:
-		granularity = 0x10;
-		addr |= TSI148_LCSR_ITAT_AS_A16;
-		break;
-	case VME_A24:
-		granularity = 0x1000;
-		addr |= TSI148_LCSR_ITAT_AS_A24;
-		break;
-	case VME_A32:
-		granularity = 0x10000;
-		addr |= TSI148_LCSR_ITAT_AS_A32;
-		break;
-	case VME_A64:
-		granularity = 0x10000;
-		addr |= TSI148_LCSR_ITAT_AS_A64;
-		break;
-	case VME_CRCSR:
-	case VME_USER1:
-	case VME_USER2:
-	case VME_USER3:
-	case VME_USER4:
-	default:
-		dev_err(tsi148_bridge->parent, "Invalid address space\n");
-		return -EINVAL;
-		break;
-	}
-
-	/* Convert 64-bit variables to 2x 32-bit variables */
-	reg_split(vme_base, &vme_base_high, &vme_base_low);
-
-	/*
-	 * Bound address is a valid address for the window, adjust
-	 * accordingly
-	 */
-	vme_bound = vme_base + size - granularity;
-	reg_split(vme_bound, &vme_bound_high, &vme_bound_low);
-	pci_offset = (unsigned long long)pci_base - vme_base;
-	reg_split(pci_offset, &pci_offset_high, &pci_offset_low);
-
-	if (vme_base_low & (granularity - 1)) {
-		dev_err(tsi148_bridge->parent, "Invalid VME base alignment\n");
-		return -EINVAL;
-	}
-	if (vme_bound_low & (granularity - 1)) {
-		dev_err(tsi148_bridge->parent, "Invalid VME bound alignment\n");
-		return -EINVAL;
-	}
-	if (pci_offset_low & (granularity - 1)) {
-		dev_err(tsi148_bridge->parent, "Invalid PCI Offset "
-			"alignment\n");
-		return -EINVAL;
-	}
-
-	/*  Disable while we are mucking around */
-	temp_ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITAT);
-	temp_ctl &= ~TSI148_LCSR_ITAT_EN;
-	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITAT);
-
-	/* Setup mapping */
-	iowrite32be(vme_base_high, bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITSAU);
-	iowrite32be(vme_base_low, bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITSAL);
-	iowrite32be(vme_bound_high, bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITEAU);
-	iowrite32be(vme_bound_low, bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITEAL);
-	iowrite32be(pci_offset_high, bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITOFU);
-	iowrite32be(pci_offset_low, bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITOFL);
-
-	/* Setup 2eSST speeds */
-	temp_ctl &= ~TSI148_LCSR_ITAT_2eSSTM_M;
-	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
-	case VME_2eSST160:
-		temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_160;
-		break;
-	case VME_2eSST267:
-		temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_267;
-		break;
-	case VME_2eSST320:
-		temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_320;
-		break;
-	}
-
-	/* Setup cycle types */
-	temp_ctl &= ~(0x1F << 7);
-	if (cycle & VME_BLT)
-		temp_ctl |= TSI148_LCSR_ITAT_BLT;
-	if (cycle & VME_MBLT)
-		temp_ctl |= TSI148_LCSR_ITAT_MBLT;
-	if (cycle & VME_2eVME)
-		temp_ctl |= TSI148_LCSR_ITAT_2eVME;
-	if (cycle & VME_2eSST)
-		temp_ctl |= TSI148_LCSR_ITAT_2eSST;
-	if (cycle & VME_2eSSTB)
-		temp_ctl |= TSI148_LCSR_ITAT_2eSSTB;
-
-	/* Setup address space */
-	temp_ctl &= ~TSI148_LCSR_ITAT_AS_M;
-	temp_ctl |= addr;
-
-	temp_ctl &= ~0xF;
-	if (cycle & VME_SUPER)
-		temp_ctl |= TSI148_LCSR_ITAT_SUPR ;
-	if (cycle & VME_USER)
-		temp_ctl |= TSI148_LCSR_ITAT_NPRIV;
-	if (cycle & VME_PROG)
-		temp_ctl |= TSI148_LCSR_ITAT_PGM;
-	if (cycle & VME_DATA)
-		temp_ctl |= TSI148_LCSR_ITAT_DATA;
-
-	/* Write ctl reg without enable */
-	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITAT);
-
-	if (enabled)
-		temp_ctl |= TSI148_LCSR_ITAT_EN;
-
-	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITAT);
-
-	return 0;
-}
-
-/*
- * Get slave window configuration.
- */
-static int tsi148_slave_get(struct vme_slave_resource *image, int *enabled,
-	unsigned long long *vme_base, unsigned long long *size,
-	dma_addr_t *pci_base, u32 *aspace, u32 *cycle)
-{
-	unsigned int i, granularity = 0, ctl = 0;
-	unsigned int vme_base_low, vme_base_high;
-	unsigned int vme_bound_low, vme_bound_high;
-	unsigned int pci_offset_low, pci_offset_high;
-	unsigned long long vme_bound, pci_offset;
-	struct tsi148_driver *bridge;
-
-	bridge = image->parent->driver_priv;
-
-	i = image->number;
-
-	/* Read registers */
-	ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITAT);
-
-	vme_base_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITSAU);
-	vme_base_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITSAL);
-	vme_bound_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITEAU);
-	vme_bound_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITEAL);
-	pci_offset_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITOFU);
-	pci_offset_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
-		TSI148_LCSR_OFFSET_ITOFL);
-
-	/* Convert 64-bit variables to 2x 32-bit variables */
-	reg_join(vme_base_high, vme_base_low, vme_base);
-	reg_join(vme_bound_high, vme_bound_low, &vme_bound);
-	reg_join(pci_offset_high, pci_offset_low, &pci_offset);
-
-	*pci_base = (dma_addr_t)vme_base + pci_offset;
-
-	*enabled = 0;
-	*aspace = 0;
-	*cycle = 0;
-
-	if (ctl & TSI148_LCSR_ITAT_EN)
-		*enabled = 1;
-
-	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A16) {
-		granularity = 0x10;
-		*aspace |= VME_A16;
-	}
-	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A24) {
-		granularity = 0x1000;
-		*aspace |= VME_A24;
-	}
-	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A32) {
-		granularity = 0x10000;
-		*aspace |= VME_A32;
-	}
-	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A64) {
-		granularity = 0x10000;
-		*aspace |= VME_A64;
-	}
-
-	/* Need granularity before we set the size */
-	*size = (unsigned long long)((vme_bound - *vme_base) + granularity);
-
-
-	if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_160)
-		*cycle |= VME_2eSST160;
-	if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_267)
-		*cycle |= VME_2eSST267;
-	if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_320)
-		*cycle |= VME_2eSST320;
-
-	if (ctl & TSI148_LCSR_ITAT_BLT)
-		*cycle |= VME_BLT;
-	if (ctl & TSI148_LCSR_ITAT_MBLT)
-		*cycle |= VME_MBLT;
-	if (ctl & TSI148_LCSR_ITAT_2eVME)
-		*cycle |= VME_2eVME;
-	if (ctl & TSI148_LCSR_ITAT_2eSST)
-		*cycle |= VME_2eSST;
-	if (ctl & TSI148_LCSR_ITAT_2eSSTB)
-		*cycle |= VME_2eSSTB;
-
-	if (ctl & TSI148_LCSR_ITAT_SUPR)
-		*cycle |= VME_SUPER;
-	if (ctl & TSI148_LCSR_ITAT_NPRIV)
-		*cycle |= VME_USER;
-	if (ctl & TSI148_LCSR_ITAT_PGM)
-		*cycle |= VME_PROG;
-	if (ctl & TSI148_LCSR_ITAT_DATA)
-		*cycle |= VME_DATA;
-
-	return 0;
-}
-
-/*
- * Allocate and map PCI Resource
- */
-static int tsi148_alloc_resource(struct vme_master_resource *image,
-	unsigned long long size)
-{
-	unsigned long long existing_size;
-	int retval = 0;
-	struct pci_dev *pdev;
-	struct vme_bridge *tsi148_bridge;
-
-	tsi148_bridge = image->parent;
-
-	pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
-
-	existing_size = (unsigned long long)(image->bus_resource.end -
-		image->bus_resource.start);
-
-	/* If the existing size is OK, return */
-	if ((size != 0) && (existing_size == (size - 1)))
-		return 0;
-
-	if (existing_size != 0) {
-		iounmap(image->kern_base);
-		image->kern_base = NULL;
-		kfree(image->bus_resource.name);
-		release_resource(&image->bus_resource);
-		memset(&image->bus_resource, 0, sizeof(struct resource));
-	}
-
-	/* Exit here if size is zero */
-	if (size == 0)
-		return 0;
-
-	if (image->bus_resource.name == NULL) {
-		image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC);
-		if (image->bus_resource.name == NULL) {
-			dev_err(tsi148_bridge->parent, "Unable to allocate "
-				"memory for resource name\n");
-			retval = -ENOMEM;
-			goto err_name;
-		}
-	}
-
-	sprintf((char *)image->bus_resource.name, "%s.%d", tsi148_bridge->name,
-		image->number);
-
-	image->bus_resource.start = 0;
-	image->bus_resource.end = (unsigned long)size;
-	image->bus_resource.flags = IORESOURCE_MEM;
-
-	retval = pci_bus_alloc_resource(pdev->bus,
-		&image->bus_resource, size, size, PCIBIOS_MIN_MEM,
-		0, NULL, NULL);
-	if (retval) {
-		dev_err(tsi148_bridge->parent, "Failed to allocate mem "
-			"resource for window %d size 0x%lx start 0x%lx\n",
-			image->number, (unsigned long)size,
-			(unsigned long)image->bus_resource.start);
-		goto err_resource;
-	}
-
-	image->kern_base = ioremap_nocache(
-		image->bus_resource.start, size);
-	if (image->kern_base == NULL) {
-		dev_err(tsi148_bridge->parent, "Failed to remap resource\n");
-		retval = -ENOMEM;
-		goto err_remap;
-	}
-
-	return 0;
-
-err_remap:
-	release_resource(&image->bus_resource);
-err_resource:
-	kfree(image->bus_resource.name);
-	memset(&image->bus_resource, 0, sizeof(struct resource));
-err_name:
-	return retval;
-}
-
-/*
- * Free and unmap PCI Resource
- */
-static void tsi148_free_resource(struct vme_master_resource *image)
-{
-	iounmap(image->kern_base);
-	image->kern_base = NULL;
-	release_resource(&image->bus_resource);
-	kfree(image->bus_resource.name);
-	memset(&image->bus_resource, 0, sizeof(struct resource));
-}
-
-/*
- * Set the attributes of an outbound window.
- */
-static int tsi148_master_set(struct vme_master_resource *image, int enabled,
-	unsigned long long vme_base, unsigned long long size, u32 aspace,
-	u32 cycle, u32 dwidth)
-{
-	int retval = 0;
-	unsigned int i;
-	unsigned int temp_ctl = 0;
-	unsigned int pci_base_low, pci_base_high;
-	unsigned int pci_bound_low, pci_bound_high;
-	unsigned int vme_offset_low, vme_offset_high;
-	unsigned long long pci_bound, vme_offset, pci_base;
-	struct vme_bridge *tsi148_bridge;
-	struct tsi148_driver *bridge;
-
-	tsi148_bridge = image->parent;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	/* Verify input data */
-	if (vme_base & 0xFFFF) {
-		dev_err(tsi148_bridge->parent, "Invalid VME Window "
-			"alignment\n");
-		retval = -EINVAL;
-		goto err_window;
-	}
-
-	if ((size == 0) && (enabled != 0)) {
-		dev_err(tsi148_bridge->parent, "Size must be non-zero for "
-			"enabled windows\n");
-		retval = -EINVAL;
-		goto err_window;
-	}
-
-	spin_lock(&image->lock);
-
-	/* Let's allocate the resource here rather than further up the stack as
-	 * it avoids pushing loads of bus dependent stuff up the stack. If size
-	 * is zero, any existing resource will be freed.
-	 */
-	retval = tsi148_alloc_resource(image, size);
-	if (retval) {
-		spin_unlock(&image->lock);
-		dev_err(tsi148_bridge->parent, "Unable to allocate memory for "
-			"resource\n");
-		goto err_res;
-	}
-
-	if (size == 0) {
-		pci_base = 0;
-		pci_bound = 0;
-		vme_offset = 0;
-	} else {
-		pci_base = (unsigned long long)image->bus_resource.start;
-
-		/*
-		 * Bound address is a valid address for the window, adjust
-		 * according to window granularity.
-		 */
-		pci_bound = pci_base + (size - 0x10000);
-		vme_offset = vme_base - pci_base;
-	}
-
-	/* Convert 64-bit variables to 2x 32-bit variables */
-	reg_split(pci_base, &pci_base_high, &pci_base_low);
-	reg_split(pci_bound, &pci_bound_high, &pci_bound_low);
-	reg_split(vme_offset, &vme_offset_high, &vme_offset_low);
-
-	if (pci_base_low & 0xFFFF) {
-		spin_unlock(&image->lock);
-		dev_err(tsi148_bridge->parent, "Invalid PCI base alignment\n");
-		retval = -EINVAL;
-		goto err_gran;
-	}
-	if (pci_bound_low & 0xFFFF) {
-		spin_unlock(&image->lock);
-		dev_err(tsi148_bridge->parent, "Invalid PCI bound alignment\n");
-		retval = -EINVAL;
-		goto err_gran;
-	}
-	if (vme_offset_low & 0xFFFF) {
-		spin_unlock(&image->lock);
-		dev_err(tsi148_bridge->parent, "Invalid VME Offset "
-			"alignment\n");
-		retval = -EINVAL;
-		goto err_gran;
-	}
-
-	i = image->number;
-
-	/* Disable while we are mucking around */
-	temp_ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTAT);
-	temp_ctl &= ~TSI148_LCSR_OTAT_EN;
-	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTAT);
-
-	/* Setup 2eSST speeds */
-	temp_ctl &= ~TSI148_LCSR_OTAT_2eSSTM_M;
-	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
-	case VME_2eSST160:
-		temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_160;
-		break;
-	case VME_2eSST267:
-		temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_267;
-		break;
-	case VME_2eSST320:
-		temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_320;
-		break;
-	}
-
-	/* Setup cycle types */
-	if (cycle & VME_BLT) {
-		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
-		temp_ctl |= TSI148_LCSR_OTAT_TM_BLT;
-	}
-	if (cycle & VME_MBLT) {
-		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
-		temp_ctl |= TSI148_LCSR_OTAT_TM_MBLT;
-	}
-	if (cycle & VME_2eVME) {
-		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
-		temp_ctl |= TSI148_LCSR_OTAT_TM_2eVME;
-	}
-	if (cycle & VME_2eSST) {
-		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
-		temp_ctl |= TSI148_LCSR_OTAT_TM_2eSST;
-	}
-	if (cycle & VME_2eSSTB) {
-		dev_warn(tsi148_bridge->parent, "Currently not setting "
-			"Broadcast Select Registers\n");
-		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
-		temp_ctl |= TSI148_LCSR_OTAT_TM_2eSSTB;
-	}
-
-	/* Setup data width */
-	temp_ctl &= ~TSI148_LCSR_OTAT_DBW_M;
-	switch (dwidth) {
-	case VME_D16:
-		temp_ctl |= TSI148_LCSR_OTAT_DBW_16;
-		break;
-	case VME_D32:
-		temp_ctl |= TSI148_LCSR_OTAT_DBW_32;
-		break;
-	default:
-		spin_unlock(&image->lock);
-		dev_err(tsi148_bridge->parent, "Invalid data width\n");
-		retval = -EINVAL;
-		goto err_dwidth;
-	}
-
-	/* Setup address space */
-	temp_ctl &= ~TSI148_LCSR_OTAT_AMODE_M;
-	switch (aspace) {
-	case VME_A16:
-		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A16;
-		break;
-	case VME_A24:
-		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A24;
-		break;
-	case VME_A32:
-		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A32;
-		break;
-	case VME_A64:
-		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A64;
-		break;
-	case VME_CRCSR:
-		temp_ctl |= TSI148_LCSR_OTAT_AMODE_CRCSR;
-		break;
-	case VME_USER1:
-		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER1;
-		break;
-	case VME_USER2:
-		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER2;
-		break;
-	case VME_USER3:
-		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER3;
-		break;
-	case VME_USER4:
-		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER4;
-		break;
-	default:
-		spin_unlock(&image->lock);
-		dev_err(tsi148_bridge->parent, "Invalid address space\n");
-		retval = -EINVAL;
-		goto err_aspace;
-		break;
-	}
-
-	temp_ctl &= ~(3<<4);
-	if (cycle & VME_SUPER)
-		temp_ctl |= TSI148_LCSR_OTAT_SUP;
-	if (cycle & VME_PROG)
-		temp_ctl |= TSI148_LCSR_OTAT_PGM;
-
-	/* Setup mapping */
-	iowrite32be(pci_base_high, bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTSAU);
-	iowrite32be(pci_base_low, bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTSAL);
-	iowrite32be(pci_bound_high, bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTEAU);
-	iowrite32be(pci_bound_low, bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTEAL);
-	iowrite32be(vme_offset_high, bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTOFU);
-	iowrite32be(vme_offset_low, bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTOFL);
-
-	/* Write ctl reg without enable */
-	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTAT);
-
-	if (enabled)
-		temp_ctl |= TSI148_LCSR_OTAT_EN;
-
-	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTAT);
-
-	spin_unlock(&image->lock);
-	return 0;
-
-err_aspace:
-err_dwidth:
-err_gran:
-	tsi148_free_resource(image);
-err_res:
-err_window:
-	return retval;
-
-}
-
-/*
- * Set the attributes of an outbound window.
- *
- * XXX Not parsing prefetch information.
- */
-static int __tsi148_master_get(struct vme_master_resource *image, int *enabled,
-	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
-	u32 *cycle, u32 *dwidth)
-{
-	unsigned int i, ctl;
-	unsigned int pci_base_low, pci_base_high;
-	unsigned int pci_bound_low, pci_bound_high;
-	unsigned int vme_offset_low, vme_offset_high;
-
-	unsigned long long pci_base, pci_bound, vme_offset;
-	struct tsi148_driver *bridge;
-
-	bridge = image->parent->driver_priv;
-
-	i = image->number;
-
-	ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTAT);
-
-	pci_base_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTSAU);
-	pci_base_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTSAL);
-	pci_bound_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTEAU);
-	pci_bound_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTEAL);
-	vme_offset_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTOFU);
-	vme_offset_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTOFL);
-
-	/* Convert 64-bit variables to 2x 32-bit variables */
-	reg_join(pci_base_high, pci_base_low, &pci_base);
-	reg_join(pci_bound_high, pci_bound_low, &pci_bound);
-	reg_join(vme_offset_high, vme_offset_low, &vme_offset);
-
-	*vme_base = pci_base + vme_offset;
-	*size = (unsigned long long)(pci_bound - pci_base) + 0x10000;
-
-	*enabled = 0;
-	*aspace = 0;
-	*cycle = 0;
-	*dwidth = 0;
-
-	if (ctl & TSI148_LCSR_OTAT_EN)
-		*enabled = 1;
-
-	/* Setup address space */
-	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A16)
-		*aspace |= VME_A16;
-	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A24)
-		*aspace |= VME_A24;
-	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A32)
-		*aspace |= VME_A32;
-	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A64)
-		*aspace |= VME_A64;
-	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_CRCSR)
-		*aspace |= VME_CRCSR;
-	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER1)
-		*aspace |= VME_USER1;
-	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER2)
-		*aspace |= VME_USER2;
-	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER3)
-		*aspace |= VME_USER3;
-	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER4)
-		*aspace |= VME_USER4;
-
-	/* Setup 2eSST speeds */
-	if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_160)
-		*cycle |= VME_2eSST160;
-	if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_267)
-		*cycle |= VME_2eSST267;
-	if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_320)
-		*cycle |= VME_2eSST320;
-
-	/* Setup cycle types */
-	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_SCT)
-		*cycle |= VME_SCT;
-	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_BLT)
-		*cycle |= VME_BLT;
-	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_MBLT)
-		*cycle |= VME_MBLT;
-	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eVME)
-		*cycle |= VME_2eVME;
-	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSST)
-		*cycle |= VME_2eSST;
-	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSSTB)
-		*cycle |= VME_2eSSTB;
-
-	if (ctl & TSI148_LCSR_OTAT_SUP)
-		*cycle |= VME_SUPER;
-	else
-		*cycle |= VME_USER;
-
-	if (ctl & TSI148_LCSR_OTAT_PGM)
-		*cycle |= VME_PROG;
-	else
-		*cycle |= VME_DATA;
-
-	/* Setup data width */
-	if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_16)
-		*dwidth = VME_D16;
-	if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_32)
-		*dwidth = VME_D32;
-
-	return 0;
-}
-
-
-static int tsi148_master_get(struct vme_master_resource *image, int *enabled,
-	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
-	u32 *cycle, u32 *dwidth)
-{
-	int retval;
-
-	spin_lock(&image->lock);
-
-	retval = __tsi148_master_get(image, enabled, vme_base, size, aspace,
-		cycle, dwidth);
-
-	spin_unlock(&image->lock);
-
-	return retval;
-}
-
-static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
-	size_t count, loff_t offset)
-{
-	int retval, enabled;
-	unsigned long long vme_base, size;
-	u32 aspace, cycle, dwidth;
-	struct vme_bus_error *vme_err = NULL;
-	struct vme_bridge *tsi148_bridge;
-
-	tsi148_bridge = image->parent;
-
-	spin_lock(&image->lock);
-
-	memcpy_fromio(buf, image->kern_base + offset, (unsigned int)count);
-	retval = count;
-
-	if (!err_chk)
-		goto skip_chk;
-
-	__tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
-		&dwidth);
-
-	vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
-		count);
-	if (vme_err != NULL) {
-		dev_err(image->parent->parent, "First VME read error detected "
-			"an at address 0x%llx\n", vme_err->address);
-		retval = vme_err->address - (vme_base + offset);
-		/* Clear down save errors in this address range */
-		tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
-			count);
-	}
-
-skip_chk:
-	spin_unlock(&image->lock);
-
-	return retval;
-}
-
-
-static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
-	size_t count, loff_t offset)
-{
-	int retval = 0, enabled;
-	unsigned long long vme_base, size;
-	u32 aspace, cycle, dwidth;
-
-	struct vme_bus_error *vme_err = NULL;
-	struct vme_bridge *tsi148_bridge;
-	struct tsi148_driver *bridge;
-
-	tsi148_bridge = image->parent;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	spin_lock(&image->lock);
-
-	memcpy_toio(image->kern_base + offset, buf, (unsigned int)count);
-	retval = count;
-
-	/*
-	 * Writes are posted. We need to do a read on the VME bus to flush out
-	 * all of the writes before we check for errors. We can't guarantee
-	 * that reading the data we have just written is safe. It is believed
-	 * that there isn't any read, write re-ordering, so we can read any
-	 * location in VME space, so lets read the Device ID from the tsi148's
-	 * own registers as mapped into CR/CSR space.
-	 *
-	 * We check for saved errors in the written address range/space.
-	 */
-
-	if (!err_chk)
-		goto skip_chk;
-
-	/*
-	 * Get window info first, to maximise the time that the buffers may
-	 * fluch on their own
-	 */
-	__tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
-		&dwidth);
-
-	ioread16(bridge->flush_image->kern_base + 0x7F000);
-
-	vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
-		count);
-	if (vme_err != NULL) {
-		dev_warn(tsi148_bridge->parent, "First VME write error detected"
-			" an at address 0x%llx\n", vme_err->address);
-		retval = vme_err->address - (vme_base + offset);
-		/* Clear down save errors in this address range */
-		tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
-			count);
-	}
-
-skip_chk:
-	spin_unlock(&image->lock);
-
-	return retval;
-}
-
-/*
- * Perform an RMW cycle on the VME bus.
- *
- * Requires a previously configured master window, returns final value.
- */
-static unsigned int tsi148_master_rmw(struct vme_master_resource *image,
-	unsigned int mask, unsigned int compare, unsigned int swap,
-	loff_t offset)
-{
-	unsigned long long pci_addr;
-	unsigned int pci_addr_high, pci_addr_low;
-	u32 tmp, result;
-	int i;
-	struct tsi148_driver *bridge;
-
-	bridge = image->parent->driver_priv;
-
-	/* Find the PCI address that maps to the desired VME address */
-	i = image->number;
-
-	/* Locking as we can only do one of these at a time */
-	mutex_lock(&bridge->vme_rmw);
-
-	/* Lock image */
-	spin_lock(&image->lock);
-
-	pci_addr_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTSAU);
-	pci_addr_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
-		TSI148_LCSR_OFFSET_OTSAL);
-
-	reg_join(pci_addr_high, pci_addr_low, &pci_addr);
-	reg_split(pci_addr + offset, &pci_addr_high, &pci_addr_low);
-
-	/* Configure registers */
-	iowrite32be(mask, bridge->base + TSI148_LCSR_RMWEN);
-	iowrite32be(compare, bridge->base + TSI148_LCSR_RMWC);
-	iowrite32be(swap, bridge->base + TSI148_LCSR_RMWS);
-	iowrite32be(pci_addr_high, bridge->base + TSI148_LCSR_RMWAU);
-	iowrite32be(pci_addr_low, bridge->base + TSI148_LCSR_RMWAL);
-
-	/* Enable RMW */
-	tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
-	tmp |= TSI148_LCSR_VMCTRL_RMWEN;
-	iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
-
-	/* Kick process off with a read to the required address. */
-	result = ioread32be(image->kern_base + offset);
-
-	/* Disable RMW */
-	tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
-	tmp &= ~TSI148_LCSR_VMCTRL_RMWEN;
-	iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
-
-	spin_unlock(&image->lock);
-
-	mutex_unlock(&bridge->vme_rmw);
-
-	return result;
-}
-
-static int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr,
-	u32 aspace, u32 cycle, u32 dwidth)
-{
-	/* Setup 2eSST speeds */
-	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
-	case VME_2eSST160:
-		*attr |= TSI148_LCSR_DSAT_2eSSTM_160;
-		break;
-	case VME_2eSST267:
-		*attr |= TSI148_LCSR_DSAT_2eSSTM_267;
-		break;
-	case VME_2eSST320:
-		*attr |= TSI148_LCSR_DSAT_2eSSTM_320;
-		break;
-	}
-
-	/* Setup cycle types */
-	if (cycle & VME_SCT)
-		*attr |= TSI148_LCSR_DSAT_TM_SCT;
-
-	if (cycle & VME_BLT)
-		*attr |= TSI148_LCSR_DSAT_TM_BLT;
-
-	if (cycle & VME_MBLT)
-		*attr |= TSI148_LCSR_DSAT_TM_MBLT;
-
-	if (cycle & VME_2eVME)
-		*attr |= TSI148_LCSR_DSAT_TM_2eVME;
-
-	if (cycle & VME_2eSST)
-		*attr |= TSI148_LCSR_DSAT_TM_2eSST;
-
-	if (cycle & VME_2eSSTB) {
-		dev_err(dev, "Currently not setting Broadcast Select "
-			"Registers\n");
-		*attr |= TSI148_LCSR_DSAT_TM_2eSSTB;
-	}
-
-	/* Setup data width */
-	switch (dwidth) {
-	case VME_D16:
-		*attr |= TSI148_LCSR_DSAT_DBW_16;
-		break;
-	case VME_D32:
-		*attr |= TSI148_LCSR_DSAT_DBW_32;
-		break;
-	default:
-		dev_err(dev, "Invalid data width\n");
-		return -EINVAL;
-	}
-
-	/* Setup address space */
-	switch (aspace) {
-	case VME_A16:
-		*attr |= TSI148_LCSR_DSAT_AMODE_A16;
-		break;
-	case VME_A24:
-		*attr |= TSI148_LCSR_DSAT_AMODE_A24;
-		break;
-	case VME_A32:
-		*attr |= TSI148_LCSR_DSAT_AMODE_A32;
-		break;
-	case VME_A64:
-		*attr |= TSI148_LCSR_DSAT_AMODE_A64;
-		break;
-	case VME_CRCSR:
-		*attr |= TSI148_LCSR_DSAT_AMODE_CRCSR;
-		break;
-	case VME_USER1:
-		*attr |= TSI148_LCSR_DSAT_AMODE_USER1;
-		break;
-	case VME_USER2:
-		*attr |= TSI148_LCSR_DSAT_AMODE_USER2;
-		break;
-	case VME_USER3:
-		*attr |= TSI148_LCSR_DSAT_AMODE_USER3;
-		break;
-	case VME_USER4:
-		*attr |= TSI148_LCSR_DSAT_AMODE_USER4;
-		break;
-	default:
-		dev_err(dev, "Invalid address space\n");
-		return -EINVAL;
-		break;
-	}
-
-	if (cycle & VME_SUPER)
-		*attr |= TSI148_LCSR_DSAT_SUP;
-	if (cycle & VME_PROG)
-		*attr |= TSI148_LCSR_DSAT_PGM;
-
-	return 0;
-}
-
-static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr,
-	u32 aspace, u32 cycle, u32 dwidth)
-{
-	/* Setup 2eSST speeds */
-	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
-	case VME_2eSST160:
-		*attr |= TSI148_LCSR_DDAT_2eSSTM_160;
-		break;
-	case VME_2eSST267:
-		*attr |= TSI148_LCSR_DDAT_2eSSTM_267;
-		break;
-	case VME_2eSST320:
-		*attr |= TSI148_LCSR_DDAT_2eSSTM_320;
-		break;
-	}
-
-	/* Setup cycle types */
-	if (cycle & VME_SCT)
-		*attr |= TSI148_LCSR_DDAT_TM_SCT;
-
-	if (cycle & VME_BLT)
-		*attr |= TSI148_LCSR_DDAT_TM_BLT;
-
-	if (cycle & VME_MBLT)
-		*attr |= TSI148_LCSR_DDAT_TM_MBLT;
-
-	if (cycle & VME_2eVME)
-		*attr |= TSI148_LCSR_DDAT_TM_2eVME;
-
-	if (cycle & VME_2eSST)
-		*attr |= TSI148_LCSR_DDAT_TM_2eSST;
-
-	if (cycle & VME_2eSSTB) {
-		dev_err(dev, "Currently not setting Broadcast Select "
-			"Registers\n");
-		*attr |= TSI148_LCSR_DDAT_TM_2eSSTB;
-	}
-
-	/* Setup data width */
-	switch (dwidth) {
-	case VME_D16:
-		*attr |= TSI148_LCSR_DDAT_DBW_16;
-		break;
-	case VME_D32:
-		*attr |= TSI148_LCSR_DDAT_DBW_32;
-		break;
-	default:
-		dev_err(dev, "Invalid data width\n");
-		return -EINVAL;
-	}
-
-	/* Setup address space */
-	switch (aspace) {
-	case VME_A16:
-		*attr |= TSI148_LCSR_DDAT_AMODE_A16;
-		break;
-	case VME_A24:
-		*attr |= TSI148_LCSR_DDAT_AMODE_A24;
-		break;
-	case VME_A32:
-		*attr |= TSI148_LCSR_DDAT_AMODE_A32;
-		break;
-	case VME_A64:
-		*attr |= TSI148_LCSR_DDAT_AMODE_A64;
-		break;
-	case VME_CRCSR:
-		*attr |= TSI148_LCSR_DDAT_AMODE_CRCSR;
-		break;
-	case VME_USER1:
-		*attr |= TSI148_LCSR_DDAT_AMODE_USER1;
-		break;
-	case VME_USER2:
-		*attr |= TSI148_LCSR_DDAT_AMODE_USER2;
-		break;
-	case VME_USER3:
-		*attr |= TSI148_LCSR_DDAT_AMODE_USER3;
-		break;
-	case VME_USER4:
-		*attr |= TSI148_LCSR_DDAT_AMODE_USER4;
-		break;
-	default:
-		dev_err(dev, "Invalid address space\n");
-		return -EINVAL;
-		break;
-	}
-
-	if (cycle & VME_SUPER)
-		*attr |= TSI148_LCSR_DDAT_SUP;
-	if (cycle & VME_PROG)
-		*attr |= TSI148_LCSR_DDAT_PGM;
-
-	return 0;
-}
-
-/*
- * Add a link list descriptor to the list
- */
-static int tsi148_dma_list_add(struct vme_dma_list *list,
-	struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
-{
-	struct tsi148_dma_entry *entry, *prev;
-	u32 address_high, address_low;
-	struct vme_dma_pattern *pattern_attr;
-	struct vme_dma_pci *pci_attr;
-	struct vme_dma_vme *vme_attr;
-	dma_addr_t desc_ptr;
-	int retval = 0;
-	struct vme_bridge *tsi148_bridge;
-
-	tsi148_bridge = list->parent->parent;
-
-	/* Descriptor must be aligned on 64-bit boundaries */
-	entry = kmalloc(sizeof(struct tsi148_dma_entry), GFP_KERNEL);
-	if (entry == NULL) {
-		dev_err(tsi148_bridge->parent, "Failed to allocate memory for "
-			"dma resource structure\n");
-		retval = -ENOMEM;
-		goto err_mem;
-	}
-
-	/* Test descriptor alignment */
-	if ((unsigned long)&entry->descriptor & 0x7) {
-		dev_err(tsi148_bridge->parent, "Descriptor not aligned to 8 "
-			"byte boundary as required: %p\n",
-			&entry->descriptor);
-		retval = -EINVAL;
-		goto err_align;
-	}
-
-	/* Given we are going to fill out the structure, we probably don't
-	 * need to zero it, but better safe than sorry for now.
-	 */
-	memset(&entry->descriptor, 0, sizeof(struct tsi148_dma_descriptor));
-
-	/* Fill out source part */
-	switch (src->type) {
-	case VME_DMA_PATTERN:
-		pattern_attr = src->private;
-
-		entry->descriptor.dsal = pattern_attr->pattern;
-		entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PAT;
-		/* Default behaviour is 32 bit pattern */
-		if (pattern_attr->type & VME_DMA_PATTERN_BYTE)
-			entry->descriptor.dsat |= TSI148_LCSR_DSAT_PSZ;
-
-		/* It seems that the default behaviour is to increment */
-		if ((pattern_attr->type & VME_DMA_PATTERN_INCREMENT) == 0)
-			entry->descriptor.dsat |= TSI148_LCSR_DSAT_NIN;
-
-		break;
-	case VME_DMA_PCI:
-		pci_attr = src->private;
-
-		reg_split((unsigned long long)pci_attr->address, &address_high,
-			&address_low);
-		entry->descriptor.dsau = address_high;
-		entry->descriptor.dsal = address_low;
-		entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PCI;
-		break;
-	case VME_DMA_VME:
-		vme_attr = src->private;
-
-		reg_split((unsigned long long)vme_attr->address, &address_high,
-			&address_low);
-		entry->descriptor.dsau = address_high;
-		entry->descriptor.dsal = address_low;
-		entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_VME;
-
-		retval = tsi148_dma_set_vme_src_attributes(
-			tsi148_bridge->parent, &entry->descriptor.dsat,
-			vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
-		if (retval < 0)
-			goto err_source;
-		break;
-	default:
-		dev_err(tsi148_bridge->parent, "Invalid source type\n");
-		retval = -EINVAL;
-		goto err_source;
-		break;
-	}
-
-	/* Assume last link - this will be over-written by adding another */
-	entry->descriptor.dnlau = 0;
-	entry->descriptor.dnlal = TSI148_LCSR_DNLAL_LLA;
-
-
-	/* Fill out destination part */
-	switch (dest->type) {
-	case VME_DMA_PCI:
-		pci_attr = dest->private;
-
-		reg_split((unsigned long long)pci_attr->address, &address_high,
-			&address_low);
-		entry->descriptor.ddau = address_high;
-		entry->descriptor.ddal = address_low;
-		entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_PCI;
-		break;
-	case VME_DMA_VME:
-		vme_attr = dest->private;
-
-		reg_split((unsigned long long)vme_attr->address, &address_high,
-			&address_low);
-		entry->descriptor.ddau = address_high;
-		entry->descriptor.ddal = address_low;
-		entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_VME;
-
-		retval = tsi148_dma_set_vme_dest_attributes(
-			tsi148_bridge->parent, &entry->descriptor.ddat,
-			vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
-		if (retval < 0)
-			goto err_dest;
-		break;
-	default:
-		dev_err(tsi148_bridge->parent, "Invalid destination type\n");
-		retval = -EINVAL;
-		goto err_dest;
-		break;
-	}
-
-	/* Fill out count */
-	entry->descriptor.dcnt = (u32)count;
-
-	/* Add to list */
-	list_add_tail(&entry->list, &list->entries);
-
-	/* Fill out previous descriptors "Next Address" */
-	if (entry->list.prev != &list->entries) {
-		prev = list_entry(entry->list.prev, struct tsi148_dma_entry,
-			list);
-		/* We need the bus address for the pointer */
-		desc_ptr = virt_to_bus(&entry->descriptor);
-		reg_split(desc_ptr, &prev->descriptor.dnlau,
-			&prev->descriptor.dnlal);
-	}
-
-	return 0;
-
-err_dest:
-err_source:
-err_align:
-		kfree(entry);
-err_mem:
-	return retval;
-}
-
-/*
- * Check to see if the provided DMA channel is busy.
- */
-static int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel)
-{
-	u32 tmp;
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	tmp = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
-		TSI148_LCSR_OFFSET_DSTA);
-
-	if (tmp & TSI148_LCSR_DSTA_BSY)
-		return 0;
-	else
-		return 1;
-
-}
-
-/*
- * Execute a previously generated link list
- *
- * XXX Need to provide control register configuration.
- */
-static int tsi148_dma_list_exec(struct vme_dma_list *list)
-{
-	struct vme_dma_resource *ctrlr;
-	int channel, retval = 0;
-	struct tsi148_dma_entry *entry;
-	dma_addr_t bus_addr;
-	u32 bus_addr_high, bus_addr_low;
-	u32 val, dctlreg = 0;
-	struct vme_bridge *tsi148_bridge;
-	struct tsi148_driver *bridge;
-
-	ctrlr = list->parent;
-
-	tsi148_bridge = ctrlr->parent;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	mutex_lock(&ctrlr->mtx);
-
-	channel = ctrlr->number;
-
-	if (!list_empty(&ctrlr->running)) {
-		/*
-		 * XXX We have an active DMA transfer and currently haven't
-		 *     sorted out the mechanism for "pending" DMA transfers.
-		 *     Return busy.
-		 */
-		/* Need to add to pending here */
-		mutex_unlock(&ctrlr->mtx);
-		return -EBUSY;
-	} else {
-		list_add(&list->list, &ctrlr->running);
-	}
-
-	/* Get first bus address and write into registers */
-	entry = list_first_entry(&list->entries, struct tsi148_dma_entry,
-		list);
-
-	bus_addr = virt_to_bus(&entry->descriptor);
-
-	mutex_unlock(&ctrlr->mtx);
-
-	reg_split(bus_addr, &bus_addr_high, &bus_addr_low);
-
-	iowrite32be(bus_addr_high, bridge->base +
-		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU);
-	iowrite32be(bus_addr_low, bridge->base +
-		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL);
-
-	/* Start the operation */
-	iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base +
-		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
-
-	wait_event_interruptible(bridge->dma_queue[channel],
-		tsi148_dma_busy(ctrlr->parent, channel));
-	/*
-	 * Read status register, this register is valid until we kick off a
-	 * new transfer.
-	 */
-	val = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
-		TSI148_LCSR_OFFSET_DSTA);
-
-	if (val & TSI148_LCSR_DSTA_VBE) {
-		dev_err(tsi148_bridge->parent, "DMA Error. DSTA=%08X\n", val);
-		retval = -EIO;
-	}
-
-	/* Remove list from running list */
-	mutex_lock(&ctrlr->mtx);
-	list_del(&list->list);
-	mutex_unlock(&ctrlr->mtx);
-
-	return retval;
-}
-
-/*
- * Clean up a previously generated link list
- *
- * We have a separate function, don't assume that the chain can't be reused.
- */
-static int tsi148_dma_list_empty(struct vme_dma_list *list)
-{
-	struct list_head *pos, *temp;
-	struct tsi148_dma_entry *entry;
-
-	/* detach and free each entry */
-	list_for_each_safe(pos, temp, &list->entries) {
-		list_del(pos);
-		entry = list_entry(pos, struct tsi148_dma_entry, list);
-		kfree(entry);
-	}
-
-	return 0;
-}
-
-/*
- * All 4 location monitors reside at the same base - this is therefore a
- * system wide configuration.
- *
- * This does not enable the LM monitor - that should be done when the first
- * callback is attached and disabled when the last callback is removed.
- */
-static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
-	u32 aspace, u32 cycle)
-{
-	u32 lm_base_high, lm_base_low, lm_ctl = 0;
-	int i;
-	struct vme_bridge *tsi148_bridge;
-	struct tsi148_driver *bridge;
-
-	tsi148_bridge = lm->parent;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	mutex_lock(&lm->mtx);
-
-	/* If we already have a callback attached, we can't move it! */
-	for (i = 0; i < lm->monitors; i++) {
-		if (bridge->lm_callback[i] != NULL) {
-			mutex_unlock(&lm->mtx);
-			dev_err(tsi148_bridge->parent, "Location monitor "
-				"callback attached, can't reset\n");
-			return -EBUSY;
-		}
-	}
-
-	switch (aspace) {
-	case VME_A16:
-		lm_ctl |= TSI148_LCSR_LMAT_AS_A16;
-		break;
-	case VME_A24:
-		lm_ctl |= TSI148_LCSR_LMAT_AS_A24;
-		break;
-	case VME_A32:
-		lm_ctl |= TSI148_LCSR_LMAT_AS_A32;
-		break;
-	case VME_A64:
-		lm_ctl |= TSI148_LCSR_LMAT_AS_A64;
-		break;
-	default:
-		mutex_unlock(&lm->mtx);
-		dev_err(tsi148_bridge->parent, "Invalid address space\n");
-		return -EINVAL;
-		break;
-	}
-
-	if (cycle & VME_SUPER)
-		lm_ctl |= TSI148_LCSR_LMAT_SUPR ;
-	if (cycle & VME_USER)
-		lm_ctl |= TSI148_LCSR_LMAT_NPRIV;
-	if (cycle & VME_PROG)
-		lm_ctl |= TSI148_LCSR_LMAT_PGM;
-	if (cycle & VME_DATA)
-		lm_ctl |= TSI148_LCSR_LMAT_DATA;
-
-	reg_split(lm_base, &lm_base_high, &lm_base_low);
-
-	iowrite32be(lm_base_high, bridge->base + TSI148_LCSR_LMBAU);
-	iowrite32be(lm_base_low, bridge->base + TSI148_LCSR_LMBAL);
-	iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
-
-	mutex_unlock(&lm->mtx);
-
-	return 0;
-}
-
-/* Get configuration of the callback monitor and return whether it is enabled
- * or disabled.
- */
-static int tsi148_lm_get(struct vme_lm_resource *lm,
-	unsigned long long *lm_base, u32 *aspace, u32 *cycle)
-{
-	u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0;
-	struct tsi148_driver *bridge;
-
-	bridge = lm->parent->driver_priv;
-
-	mutex_lock(&lm->mtx);
-
-	lm_base_high = ioread32be(bridge->base + TSI148_LCSR_LMBAU);
-	lm_base_low = ioread32be(bridge->base + TSI148_LCSR_LMBAL);
-	lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
-
-	reg_join(lm_base_high, lm_base_low, lm_base);
-
-	if (lm_ctl & TSI148_LCSR_LMAT_EN)
-		enabled = 1;
-
-	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A16)
-		*aspace |= VME_A16;
-
-	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A24)
-		*aspace |= VME_A24;
-
-	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A32)
-		*aspace |= VME_A32;
-
-	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A64)
-		*aspace |= VME_A64;
-
-
-	if (lm_ctl & TSI148_LCSR_LMAT_SUPR)
-		*cycle |= VME_SUPER;
-	if (lm_ctl & TSI148_LCSR_LMAT_NPRIV)
-		*cycle |= VME_USER;
-	if (lm_ctl & TSI148_LCSR_LMAT_PGM)
-		*cycle |= VME_PROG;
-	if (lm_ctl & TSI148_LCSR_LMAT_DATA)
-		*cycle |= VME_DATA;
-
-	mutex_unlock(&lm->mtx);
-
-	return enabled;
-}
-
-/*
- * Attach a callback to a specific location monitor.
- *
- * Callback will be passed the monitor triggered.
- */
-static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
-	void (*callback)(int))
-{
-	u32 lm_ctl, tmp;
-	struct vme_bridge *tsi148_bridge;
-	struct tsi148_driver *bridge;
-
-	tsi148_bridge = lm->parent;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	mutex_lock(&lm->mtx);
-
-	/* Ensure that the location monitor is configured - need PGM or DATA */
-	lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
-	if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) {
-		mutex_unlock(&lm->mtx);
-		dev_err(tsi148_bridge->parent, "Location monitor not properly "
-			"configured\n");
-		return -EINVAL;
-	}
-
-	/* Check that a callback isn't already attached */
-	if (bridge->lm_callback[monitor] != NULL) {
-		mutex_unlock(&lm->mtx);
-		dev_err(tsi148_bridge->parent, "Existing callback attached\n");
-		return -EBUSY;
-	}
-
-	/* Attach callback */
-	bridge->lm_callback[monitor] = callback;
-
-	/* Enable Location Monitor interrupt */
-	tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
-	tmp |= TSI148_LCSR_INTEN_LMEN[monitor];
-	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
-
-	tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
-	tmp |= TSI148_LCSR_INTEO_LMEO[monitor];
-	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
-
-	/* Ensure that global Location Monitor Enable set */
-	if ((lm_ctl & TSI148_LCSR_LMAT_EN) == 0) {
-		lm_ctl |= TSI148_LCSR_LMAT_EN;
-		iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
-	}
-
-	mutex_unlock(&lm->mtx);
-
-	return 0;
-}
-
-/*
- * Detach a callback function forn a specific location monitor.
- */
-static int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
-{
-	u32 lm_en, tmp;
-	struct tsi148_driver *bridge;
-
-	bridge = lm->parent->driver_priv;
-
-	mutex_lock(&lm->mtx);
-
-	/* Disable Location Monitor and ensure previous interrupts are clear */
-	lm_en = ioread32be(bridge->base + TSI148_LCSR_INTEN);
-	lm_en &= ~TSI148_LCSR_INTEN_LMEN[monitor];
-	iowrite32be(lm_en, bridge->base + TSI148_LCSR_INTEN);
-
-	tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
-	tmp &= ~TSI148_LCSR_INTEO_LMEO[monitor];
-	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
-
-	iowrite32be(TSI148_LCSR_INTC_LMC[monitor],
-		 bridge->base + TSI148_LCSR_INTC);
-
-	/* Detach callback */
-	bridge->lm_callback[monitor] = NULL;
-
-	/* If all location monitors disabled, disable global Location Monitor */
-	if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S |
-			TSI148_LCSR_INTS_LM2S | TSI148_LCSR_INTS_LM3S)) == 0) {
-		tmp = ioread32be(bridge->base + TSI148_LCSR_LMAT);
-		tmp &= ~TSI148_LCSR_LMAT_EN;
-		iowrite32be(tmp, bridge->base + TSI148_LCSR_LMAT);
-	}
-
-	mutex_unlock(&lm->mtx);
-
-	return 0;
-}
-
-/*
- * Determine Geographical Addressing
- */
-static int tsi148_slot_get(struct vme_bridge *tsi148_bridge)
-{
-	u32 slot = 0;
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	if (!geoid) {
-		slot = ioread32be(bridge->base + TSI148_LCSR_VSTAT);
-		slot = slot & TSI148_LCSR_VSTAT_GA_M;
-	} else
-		slot = geoid;
-
-	return (int)slot;
-}
-
-void *tsi148_alloc_consistent(struct device *parent, size_t size,
-	dma_addr_t *dma)
-{
-	struct pci_dev *pdev;
-
-	/* Find pci_dev container of dev */
-	pdev = container_of(parent, struct pci_dev, dev);
-
-	return pci_alloc_consistent(pdev, size, dma);
-}
-
-void tsi148_free_consistent(struct device *parent, size_t size, void *vaddr,
-	dma_addr_t dma)
-{
-	struct pci_dev *pdev;
-
-	/* Find pci_dev container of dev */
-	pdev = container_of(parent, struct pci_dev, dev);
-
-	pci_free_consistent(pdev, size, vaddr, dma);
-}
-
-static int __init tsi148_init(void)
-{
-	return pci_register_driver(&tsi148_driver);
-}
-
-/*
- * Configure CR/CSR space
- *
- * Access to the CR/CSR can be configured at power-up. The location of the
- * CR/CSR registers in the CR/CSR address space is determined by the boards
- * Auto-ID or Geographic address. This function ensures that the window is
- * enabled at an offset consistent with the boards geopgraphic address.
- *
- * Each board has a 512kB window, with the highest 4kB being used for the
- * boards registers, this means there is a fix length 508kB window which must
- * be mapped onto PCI memory.
- */
-static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge,
-	struct pci_dev *pdev)
-{
-	u32 cbar, crat, vstat;
-	u32 crcsr_bus_high, crcsr_bus_low;
-	int retval;
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	/* Allocate mem for CR/CSR image */
-	bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
-		&bridge->crcsr_bus);
-	if (bridge->crcsr_kernel == NULL) {
-		dev_err(tsi148_bridge->parent, "Failed to allocate memory for "
-			"CR/CSR image\n");
-		return -ENOMEM;
-	}
-
-	memset(bridge->crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
-
-	reg_split(bridge->crcsr_bus, &crcsr_bus_high, &crcsr_bus_low);
-
-	iowrite32be(crcsr_bus_high, bridge->base + TSI148_LCSR_CROU);
-	iowrite32be(crcsr_bus_low, bridge->base + TSI148_LCSR_CROL);
-
-	/* Ensure that the CR/CSR is configured at the correct offset */
-	cbar = ioread32be(bridge->base + TSI148_CBAR);
-	cbar = (cbar & TSI148_CRCSR_CBAR_M)>>3;
-
-	vstat = tsi148_slot_get(tsi148_bridge);
-
-	if (cbar != vstat) {
-		cbar = vstat;
-		dev_info(tsi148_bridge->parent, "Setting CR/CSR offset\n");
-		iowrite32be(cbar<<3, bridge->base + TSI148_CBAR);
-	}
-	dev_info(tsi148_bridge->parent, "CR/CSR Offset: %d\n", cbar);
-
-	crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
-	if (crat & TSI148_LCSR_CRAT_EN) {
-		dev_info(tsi148_bridge->parent, "Enabling CR/CSR space\n");
-		iowrite32be(crat | TSI148_LCSR_CRAT_EN,
-			bridge->base + TSI148_LCSR_CRAT);
-	} else
-		dev_info(tsi148_bridge->parent, "CR/CSR already enabled\n");
-
-	/* If we want flushed, error-checked writes, set up a window
-	 * over the CR/CSR registers. We read from here to safely flush
-	 * through VME writes.
-	 */
-	if (err_chk) {
-		retval = tsi148_master_set(bridge->flush_image, 1,
-			(vstat * 0x80000), 0x80000, VME_CRCSR, VME_SCT,
-			VME_D16);
-		if (retval)
-			dev_err(tsi148_bridge->parent, "Configuring flush image"
-				" failed\n");
-	}
-
-	return 0;
-
-}
-
-static void tsi148_crcsr_exit(struct vme_bridge *tsi148_bridge,
-	struct pci_dev *pdev)
-{
-	u32 crat;
-	struct tsi148_driver *bridge;
-
-	bridge = tsi148_bridge->driver_priv;
-
-	/* Turn off CR/CSR space */
-	crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
-	iowrite32be(crat & ~TSI148_LCSR_CRAT_EN,
-		bridge->base + TSI148_LCSR_CRAT);
-
-	/* Free image */
-	iowrite32be(0, bridge->base + TSI148_LCSR_CROU);
-	iowrite32be(0, bridge->base + TSI148_LCSR_CROL);
-
-	pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, bridge->crcsr_kernel,
-		bridge->crcsr_bus);
-}
-
-static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	int retval, i, master_num;
-	u32 data;
-	struct list_head *pos = NULL;
-	struct vme_bridge *tsi148_bridge;
-	struct tsi148_driver *tsi148_device;
-	struct vme_master_resource *master_image;
-	struct vme_slave_resource *slave_image;
-	struct vme_dma_resource *dma_ctrlr;
-	struct vme_lm_resource *lm;
-
-	/* If we want to support more than one of each bridge, we need to
-	 * dynamically generate this so we get one per device
-	 */
-	tsi148_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL);
-	if (tsi148_bridge == NULL) {
-		dev_err(&pdev->dev, "Failed to allocate memory for device "
-			"structure\n");
-		retval = -ENOMEM;
-		goto err_struct;
-	}
-
-	tsi148_device = kzalloc(sizeof(struct tsi148_driver), GFP_KERNEL);
-	if (tsi148_device == NULL) {
-		dev_err(&pdev->dev, "Failed to allocate memory for device "
-			"structure\n");
-		retval = -ENOMEM;
-		goto err_driver;
-	}
-
-	tsi148_bridge->driver_priv = tsi148_device;
-
-	/* Enable the device */
-	retval = pci_enable_device(pdev);
-	if (retval) {
-		dev_err(&pdev->dev, "Unable to enable device\n");
-		goto err_enable;
-	}
-
-	/* Map Registers */
-	retval = pci_request_regions(pdev, driver_name);
-	if (retval) {
-		dev_err(&pdev->dev, "Unable to reserve resources\n");
-		goto err_resource;
-	}
-
-	/* map registers in BAR 0 */
-	tsi148_device->base = ioremap_nocache(pci_resource_start(pdev, 0),
-		4096);
-	if (!tsi148_device->base) {
-		dev_err(&pdev->dev, "Unable to remap CRG region\n");
-		retval = -EIO;
-		goto err_remap;
-	}
-
-	/* Check to see if the mapping worked out */
-	data = ioread32(tsi148_device->base + TSI148_PCFS_ID) & 0x0000FFFF;
-	if (data != PCI_VENDOR_ID_TUNDRA) {
-		dev_err(&pdev->dev, "CRG region check failed\n");
-		retval = -EIO;
-		goto err_test;
-	}
-
-	/* Initialize wait queues & mutual exclusion flags */
-	init_waitqueue_head(&tsi148_device->dma_queue[0]);
-	init_waitqueue_head(&tsi148_device->dma_queue[1]);
-	init_waitqueue_head(&tsi148_device->iack_queue);
-	mutex_init(&tsi148_device->vme_int);
-	mutex_init(&tsi148_device->vme_rmw);
-
-	tsi148_bridge->parent = &pdev->dev;
-	strcpy(tsi148_bridge->name, driver_name);
-
-	/* Setup IRQ */
-	retval = tsi148_irq_init(tsi148_bridge);
-	if (retval != 0) {
-		dev_err(&pdev->dev, "Chip Initialization failed.\n");
-		goto err_irq;
-	}
-
-	/* If we are going to flush writes, we need to read from the VME bus.
-	 * We need to do this safely, thus we read the devices own CR/CSR
-	 * register. To do this we must set up a window in CR/CSR space and
-	 * hence have one less master window resource available.
-	 */
-	master_num = TSI148_MAX_MASTER;
-	if (err_chk) {
-		master_num--;
-
-		tsi148_device->flush_image =
-			kmalloc(sizeof(struct vme_master_resource), GFP_KERNEL);
-		if (tsi148_device->flush_image == NULL) {
-			dev_err(&pdev->dev, "Failed to allocate memory for "
-			"flush resource structure\n");
-			retval = -ENOMEM;
-			goto err_master;
-		}
-		tsi148_device->flush_image->parent = tsi148_bridge;
-		spin_lock_init(&tsi148_device->flush_image->lock);
-		tsi148_device->flush_image->locked = 1;
-		tsi148_device->flush_image->number = master_num;
-		tsi148_device->flush_image->address_attr = VME_A16 | VME_A24 |
-			VME_A32 | VME_A64;
-		tsi148_device->flush_image->cycle_attr = VME_SCT | VME_BLT |
-			VME_MBLT | VME_2eVME | VME_2eSST | VME_2eSSTB |
-			VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER |
-			VME_USER | VME_PROG | VME_DATA;
-		tsi148_device->flush_image->width_attr = VME_D16 | VME_D32;
-		memset(&tsi148_device->flush_image->bus_resource, 0,
-			sizeof(struct resource));
-		tsi148_device->flush_image->kern_base  = NULL;
-	}
-
-	/* Add master windows to list */
-	INIT_LIST_HEAD(&tsi148_bridge->master_resources);
-	for (i = 0; i < master_num; i++) {
-		master_image = kmalloc(sizeof(struct vme_master_resource),
-			GFP_KERNEL);
-		if (master_image == NULL) {
-			dev_err(&pdev->dev, "Failed to allocate memory for "
-			"master resource structure\n");
-			retval = -ENOMEM;
-			goto err_master;
-		}
-		master_image->parent = tsi148_bridge;
-		spin_lock_init(&master_image->lock);
-		master_image->locked = 0;
-		master_image->number = i;
-		master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
-			VME_A64;
-		master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
-			VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
-			VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
-			VME_PROG | VME_DATA;
-		master_image->width_attr = VME_D16 | VME_D32;
-		memset(&master_image->bus_resource, 0,
-			sizeof(struct resource));
-		master_image->kern_base  = NULL;
-		list_add_tail(&master_image->list,
-			&tsi148_bridge->master_resources);
-	}
-
-	/* Add slave windows to list */
-	INIT_LIST_HEAD(&tsi148_bridge->slave_resources);
-	for (i = 0; i < TSI148_MAX_SLAVE; i++) {
-		slave_image = kmalloc(sizeof(struct vme_slave_resource),
-			GFP_KERNEL);
-		if (slave_image == NULL) {
-			dev_err(&pdev->dev, "Failed to allocate memory for "
-			"slave resource structure\n");
-			retval = -ENOMEM;
-			goto err_slave;
-		}
-		slave_image->parent = tsi148_bridge;
-		mutex_init(&slave_image->mtx);
-		slave_image->locked = 0;
-		slave_image->number = i;
-		slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
-			VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
-			VME_USER3 | VME_USER4;
-		slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
-			VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
-			VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
-			VME_PROG | VME_DATA;
-		list_add_tail(&slave_image->list,
-			&tsi148_bridge->slave_resources);
-	}
-
-	/* Add dma engines to list */
-	INIT_LIST_HEAD(&tsi148_bridge->dma_resources);
-	for (i = 0; i < TSI148_MAX_DMA; i++) {
-		dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource),
-			GFP_KERNEL);
-		if (dma_ctrlr == NULL) {
-			dev_err(&pdev->dev, "Failed to allocate memory for "
-			"dma resource structure\n");
-			retval = -ENOMEM;
-			goto err_dma;
-		}
-		dma_ctrlr->parent = tsi148_bridge;
-		mutex_init(&dma_ctrlr->mtx);
-		dma_ctrlr->locked = 0;
-		dma_ctrlr->number = i;
-		dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
-			VME_DMA_MEM_TO_VME | VME_DMA_VME_TO_VME |
-			VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME |
-			VME_DMA_PATTERN_TO_MEM;
-		INIT_LIST_HEAD(&dma_ctrlr->pending);
-		INIT_LIST_HEAD(&dma_ctrlr->running);
-		list_add_tail(&dma_ctrlr->list,
-			&tsi148_bridge->dma_resources);
-	}
-
-	/* Add location monitor to list */
-	INIT_LIST_HEAD(&tsi148_bridge->lm_resources);
-	lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
-	if (lm == NULL) {
-		dev_err(&pdev->dev, "Failed to allocate memory for "
-		"location monitor resource structure\n");
-		retval = -ENOMEM;
-		goto err_lm;
-	}
-	lm->parent = tsi148_bridge;
-	mutex_init(&lm->mtx);
-	lm->locked = 0;
-	lm->number = 1;
-	lm->monitors = 4;
-	list_add_tail(&lm->list, &tsi148_bridge->lm_resources);
-
-	tsi148_bridge->slave_get = tsi148_slave_get;
-	tsi148_bridge->slave_set = tsi148_slave_set;
-	tsi148_bridge->master_get = tsi148_master_get;
-	tsi148_bridge->master_set = tsi148_master_set;
-	tsi148_bridge->master_read = tsi148_master_read;
-	tsi148_bridge->master_write = tsi148_master_write;
-	tsi148_bridge->master_rmw = tsi148_master_rmw;
-	tsi148_bridge->dma_list_add = tsi148_dma_list_add;
-	tsi148_bridge->dma_list_exec = tsi148_dma_list_exec;
-	tsi148_bridge->dma_list_empty = tsi148_dma_list_empty;
-	tsi148_bridge->irq_set = tsi148_irq_set;
-	tsi148_bridge->irq_generate = tsi148_irq_generate;
-	tsi148_bridge->lm_set = tsi148_lm_set;
-	tsi148_bridge->lm_get = tsi148_lm_get;
-	tsi148_bridge->lm_attach = tsi148_lm_attach;
-	tsi148_bridge->lm_detach = tsi148_lm_detach;
-	tsi148_bridge->slot_get = tsi148_slot_get;
-	tsi148_bridge->alloc_consistent = tsi148_alloc_consistent;
-	tsi148_bridge->free_consistent = tsi148_free_consistent;
-
-	data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
-	dev_info(&pdev->dev, "Board is%s the VME system controller\n",
-		(data & TSI148_LCSR_VSTAT_SCONS) ? "" : " not");
-	if (!geoid)
-		dev_info(&pdev->dev, "VME geographical address is %d\n",
-			data & TSI148_LCSR_VSTAT_GA_M);
-	else
-		dev_info(&pdev->dev, "VME geographical address is set to %d\n",
-			geoid);
-
-	dev_info(&pdev->dev, "VME Write and flush and error check is %s\n",
-		err_chk ? "enabled" : "disabled");
-
-	if (tsi148_crcsr_init(tsi148_bridge, pdev)) {
-		dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
-		goto err_crcsr;
-	}
-
-	retval = vme_register_bridge(tsi148_bridge);
-	if (retval != 0) {
-		dev_err(&pdev->dev, "Chip Registration failed.\n");
-		goto err_reg;
-	}
-
-	pci_set_drvdata(pdev, tsi148_bridge);
-
-	/* Clear VME bus "board fail", and "power-up reset" lines */
-	data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
-	data &= ~TSI148_LCSR_VSTAT_BRDFL;
-	data |= TSI148_LCSR_VSTAT_CPURST;
-	iowrite32be(data, tsi148_device->base + TSI148_LCSR_VSTAT);
-
-	return 0;
-
-err_reg:
-	tsi148_crcsr_exit(tsi148_bridge, pdev);
-err_crcsr:
-err_lm:
-	/* resources are stored in link list */
-	list_for_each(pos, &tsi148_bridge->lm_resources) {
-		lm = list_entry(pos, struct vme_lm_resource, list);
-		list_del(pos);
-		kfree(lm);
-	}
-err_dma:
-	/* resources are stored in link list */
-	list_for_each(pos, &tsi148_bridge->dma_resources) {
-		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
-		list_del(pos);
-		kfree(dma_ctrlr);
-	}
-err_slave:
-	/* resources are stored in link list */
-	list_for_each(pos, &tsi148_bridge->slave_resources) {
-		slave_image = list_entry(pos, struct vme_slave_resource, list);
-		list_del(pos);
-		kfree(slave_image);
-	}
-err_master:
-	/* resources are stored in link list */
-	list_for_each(pos, &tsi148_bridge->master_resources) {
-		master_image = list_entry(pos, struct vme_master_resource,
-			list);
-		list_del(pos);
-		kfree(master_image);
-	}
-
-	tsi148_irq_exit(tsi148_bridge, pdev);
-err_irq:
-err_test:
-	iounmap(tsi148_device->base);
-err_remap:
-	pci_release_regions(pdev);
-err_resource:
-	pci_disable_device(pdev);
-err_enable:
-	kfree(tsi148_device);
-err_driver:
-	kfree(tsi148_bridge);
-err_struct:
-	return retval;
-
-}
-
-static void tsi148_remove(struct pci_dev *pdev)
-{
-	struct list_head *pos = NULL;
-	struct list_head *tmplist;
-	struct vme_master_resource *master_image;
-	struct vme_slave_resource *slave_image;
-	struct vme_dma_resource *dma_ctrlr;
-	int i;
-	struct tsi148_driver *bridge;
-	struct vme_bridge *tsi148_bridge = pci_get_drvdata(pdev);
-
-	bridge = tsi148_bridge->driver_priv;
-
-
-	dev_dbg(&pdev->dev, "Driver is being unloaded.\n");
-
-	/*
-	 *  Shutdown all inbound and outbound windows.
-	 */
-	for (i = 0; i < 8; i++) {
-		iowrite32be(0, bridge->base + TSI148_LCSR_IT[i] +
-			TSI148_LCSR_OFFSET_ITAT);
-		iowrite32be(0, bridge->base + TSI148_LCSR_OT[i] +
-			TSI148_LCSR_OFFSET_OTAT);
-	}
-
-	/*
-	 *  Shutdown Location monitor.
-	 */
-	iowrite32be(0, bridge->base + TSI148_LCSR_LMAT);
-
-	/*
-	 *  Shutdown CRG map.
-	 */
-	iowrite32be(0, bridge->base + TSI148_LCSR_CSRAT);
-
-	/*
-	 *  Clear error status.
-	 */
-	iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_EDPAT);
-	iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_VEAT);
-	iowrite32be(0x07000700, bridge->base + TSI148_LCSR_PSTAT);
-
-	/*
-	 *  Remove VIRQ interrupt (if any)
-	 */
-	if (ioread32be(bridge->base + TSI148_LCSR_VICR) & 0x800)
-		iowrite32be(0x8000, bridge->base + TSI148_LCSR_VICR);
-
-	/*
-	 *  Map all Interrupts to PCI INTA
-	 */
-	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM1);
-	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM2);
-
-	tsi148_irq_exit(tsi148_bridge, pdev);
-
-	vme_unregister_bridge(tsi148_bridge);
-
-	tsi148_crcsr_exit(tsi148_bridge, pdev);
-
-	/* resources are stored in link list */
-	list_for_each_safe(pos, tmplist, &tsi148_bridge->dma_resources) {
-		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
-		list_del(pos);
-		kfree(dma_ctrlr);
-	}
-
-	/* resources are stored in link list */
-	list_for_each_safe(pos, tmplist, &tsi148_bridge->slave_resources) {
-		slave_image = list_entry(pos, struct vme_slave_resource, list);
-		list_del(pos);
-		kfree(slave_image);
-	}
-
-	/* resources are stored in link list */
-	list_for_each_safe(pos, tmplist, &tsi148_bridge->master_resources) {
-		master_image = list_entry(pos, struct vme_master_resource,
-			list);
-		list_del(pos);
-		kfree(master_image);
-	}
-
-	iounmap(bridge->base);
-
-	pci_release_regions(pdev);
-
-	pci_disable_device(pdev);
-
-	kfree(tsi148_bridge->driver_priv);
-
-	kfree(tsi148_bridge);
-}
-
-static void __exit tsi148_exit(void)
-{
-	pci_unregister_driver(&tsi148_driver);
-}
-
-MODULE_PARM_DESC(err_chk, "Check for VME errors on reads and writes");
-module_param(err_chk, bool, 0);
-
-MODULE_PARM_DESC(geoid, "Override geographical addressing");
-module_param(geoid, int, 0);
-
-MODULE_DESCRIPTION("VME driver for the Tundra Tempe VME bridge");
-MODULE_LICENSE("GPL");
-
-module_init(tsi148_init);
-module_exit(tsi148_exit);
diff --git a/drivers/staging/vme/bridges/vme_tsi148.h b/drivers/staging/vme/bridges/vme_tsi148.h
deleted file mode 100644
index a3ac2fe..0000000
--- a/drivers/staging/vme/bridges/vme_tsi148.h
+++ /dev/null
@@ -1,1409 +0,0 @@
-/*
- * tsi148.h
- *
- * Support for the Tundra TSI148 VME Bridge chip
- *
- * Author: Tom Armistead
- * Updated and maintained by Ajit Prem
- * Copyright 2004 Motorola Inc.
- *
- * 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 TSI148_H
-#define TSI148_H
-
-#ifndef	PCI_VENDOR_ID_TUNDRA
-#define	PCI_VENDOR_ID_TUNDRA 0x10e3
-#endif
-
-#ifndef	PCI_DEVICE_ID_TUNDRA_TSI148
-#define	PCI_DEVICE_ID_TUNDRA_TSI148 0x148
-#endif
-
-/*
- *  Define the number of each that the Tsi148 supports.
- */
-#define TSI148_MAX_MASTER		8	/* Max Master Windows */
-#define TSI148_MAX_SLAVE		8	/* Max Slave Windows */
-#define TSI148_MAX_DMA			2	/* Max DMA Controllers */
-#define TSI148_MAX_MAILBOX		4	/* Max Mail Box registers */
-#define TSI148_MAX_SEMAPHORE		8	/* Max Semaphores */
-
-/* Structure used to hold driver specific information */
-struct tsi148_driver {
-	void __iomem *base;	/* Base Address of device registers */
-	wait_queue_head_t dma_queue[2];
-	wait_queue_head_t iack_queue;
-	void (*lm_callback[4])(int);	/* Called in interrupt handler */
-	void *crcsr_kernel;
-	dma_addr_t crcsr_bus;
-	struct vme_master_resource *flush_image;
-	struct mutex vme_rmw;		/* Only one RMW cycle at a time */
-	struct mutex vme_int;		/*
-					 * Only one VME interrupt can be
-					 * generated at a time, provide locking
-					 */
-};
-
-/*
- * Layout of a DMAC Linked-List Descriptor
- *
- * Note: This structure is accessed via the chip and therefore must be
- *       correctly laid out - It must also be aligned on 64-bit boundaries.
- */
-struct tsi148_dma_descriptor {
-	u32 dsau;      /* Source Address */
-	u32 dsal;
-	u32 ddau;      /* Destination Address */
-	u32 ddal;
-	u32 dsat;      /* Source attributes */
-	u32 ddat;      /* Destination attributes */
-	u32 dnlau;     /* Next link address */
-	u32 dnlal;
-	u32 dcnt;      /* Byte count */
-	u32 ddbs;      /* 2eSST Broadcast select */
-};
-
-struct tsi148_dma_entry {
-	/*
-	 * The descriptor needs to be aligned on a 64-bit boundary, we increase
-	 * the chance of this by putting it first in the structure.
-	 */
-	struct tsi148_dma_descriptor descriptor;
-	struct list_head list;
-};
-
-/*
- *  TSI148 ASIC register structure overlays and bit field definitions.
- *
- *      Note:   Tsi148 Register Group (CRG) consists of the following
- *              combination of registers:
- *                      PCFS    - PCI Configuration Space Registers
- *                      LCSR    - Local Control and Status Registers
- *                      GCSR    - Global Control and Status Registers
- *                      CR/CSR  - Subset of Configuration ROM /
- *                                Control and Status Registers
- */
-
-
-/*
- *  Command/Status Registers (CRG + $004)
- */
-#define TSI148_PCFS_ID			0x0
-#define TSI148_PCFS_CSR			0x4
-#define TSI148_PCFS_CLASS		0x8
-#define TSI148_PCFS_MISC0		0xC
-#define TSI148_PCFS_MBARL		0x10
-#define TSI148_PCFS_MBARU		0x14
-
-#define TSI148_PCFS_SUBID		0x28
-
-#define TSI148_PCFS_CAPP		0x34
-
-#define TSI148_PCFS_MISC1		0x3C
-
-#define TSI148_PCFS_XCAPP		0x40
-#define TSI148_PCFS_XSTAT		0x44
-
-/*
- * LCSR definitions
- */
-
-/*
- *    Outbound Translations
- */
-#define TSI148_LCSR_OT0_OTSAU		0x100
-#define TSI148_LCSR_OT0_OTSAL		0x104
-#define TSI148_LCSR_OT0_OTEAU		0x108
-#define TSI148_LCSR_OT0_OTEAL		0x10C
-#define TSI148_LCSR_OT0_OTOFU		0x110
-#define TSI148_LCSR_OT0_OTOFL		0x114
-#define TSI148_LCSR_OT0_OTBS		0x118
-#define TSI148_LCSR_OT0_OTAT		0x11C
-
-#define TSI148_LCSR_OT1_OTSAU		0x120
-#define TSI148_LCSR_OT1_OTSAL		0x124
-#define TSI148_LCSR_OT1_OTEAU		0x128
-#define TSI148_LCSR_OT1_OTEAL		0x12C
-#define TSI148_LCSR_OT1_OTOFU		0x130
-#define TSI148_LCSR_OT1_OTOFL		0x134
-#define TSI148_LCSR_OT1_OTBS		0x138
-#define TSI148_LCSR_OT1_OTAT		0x13C
-
-#define TSI148_LCSR_OT2_OTSAU		0x140
-#define TSI148_LCSR_OT2_OTSAL		0x144
-#define TSI148_LCSR_OT2_OTEAU		0x148
-#define TSI148_LCSR_OT2_OTEAL		0x14C
-#define TSI148_LCSR_OT2_OTOFU		0x150
-#define TSI148_LCSR_OT2_OTOFL		0x154
-#define TSI148_LCSR_OT2_OTBS		0x158
-#define TSI148_LCSR_OT2_OTAT		0x15C
-
-#define TSI148_LCSR_OT3_OTSAU		0x160
-#define TSI148_LCSR_OT3_OTSAL		0x164
-#define TSI148_LCSR_OT3_OTEAU		0x168
-#define TSI148_LCSR_OT3_OTEAL		0x16C
-#define TSI148_LCSR_OT3_OTOFU		0x170
-#define TSI148_LCSR_OT3_OTOFL		0x174
-#define TSI148_LCSR_OT3_OTBS		0x178
-#define TSI148_LCSR_OT3_OTAT		0x17C
-
-#define TSI148_LCSR_OT4_OTSAU		0x180
-#define TSI148_LCSR_OT4_OTSAL		0x184
-#define TSI148_LCSR_OT4_OTEAU		0x188
-#define TSI148_LCSR_OT4_OTEAL		0x18C
-#define TSI148_LCSR_OT4_OTOFU		0x190
-#define TSI148_LCSR_OT4_OTOFL		0x194
-#define TSI148_LCSR_OT4_OTBS		0x198
-#define TSI148_LCSR_OT4_OTAT		0x19C
-
-#define TSI148_LCSR_OT5_OTSAU		0x1A0
-#define TSI148_LCSR_OT5_OTSAL		0x1A4
-#define TSI148_LCSR_OT5_OTEAU		0x1A8
-#define TSI148_LCSR_OT5_OTEAL		0x1AC
-#define TSI148_LCSR_OT5_OTOFU		0x1B0
-#define TSI148_LCSR_OT5_OTOFL		0x1B4
-#define TSI148_LCSR_OT5_OTBS		0x1B8
-#define TSI148_LCSR_OT5_OTAT		0x1BC
-
-#define TSI148_LCSR_OT6_OTSAU		0x1C0
-#define TSI148_LCSR_OT6_OTSAL		0x1C4
-#define TSI148_LCSR_OT6_OTEAU		0x1C8
-#define TSI148_LCSR_OT6_OTEAL		0x1CC
-#define TSI148_LCSR_OT6_OTOFU		0x1D0
-#define TSI148_LCSR_OT6_OTOFL		0x1D4
-#define TSI148_LCSR_OT6_OTBS		0x1D8
-#define TSI148_LCSR_OT6_OTAT		0x1DC
-
-#define TSI148_LCSR_OT7_OTSAU		0x1E0
-#define TSI148_LCSR_OT7_OTSAL		0x1E4
-#define TSI148_LCSR_OT7_OTEAU		0x1E8
-#define TSI148_LCSR_OT7_OTEAL		0x1EC
-#define TSI148_LCSR_OT7_OTOFU		0x1F0
-#define TSI148_LCSR_OT7_OTOFL		0x1F4
-#define TSI148_LCSR_OT7_OTBS		0x1F8
-#define TSI148_LCSR_OT7_OTAT		0x1FC
-
-#define TSI148_LCSR_OT0		0x100
-#define TSI148_LCSR_OT1		0x120
-#define TSI148_LCSR_OT2		0x140
-#define TSI148_LCSR_OT3		0x160
-#define TSI148_LCSR_OT4		0x180
-#define TSI148_LCSR_OT5		0x1A0
-#define TSI148_LCSR_OT6		0x1C0
-#define TSI148_LCSR_OT7		0x1E0
-
-static const int TSI148_LCSR_OT[8] = { TSI148_LCSR_OT0, TSI148_LCSR_OT1,
-					 TSI148_LCSR_OT2, TSI148_LCSR_OT3,
-					 TSI148_LCSR_OT4, TSI148_LCSR_OT5,
-					 TSI148_LCSR_OT6, TSI148_LCSR_OT7 };
-
-#define TSI148_LCSR_OFFSET_OTSAU	0x0
-#define TSI148_LCSR_OFFSET_OTSAL	0x4
-#define TSI148_LCSR_OFFSET_OTEAU	0x8
-#define TSI148_LCSR_OFFSET_OTEAL	0xC
-#define TSI148_LCSR_OFFSET_OTOFU	0x10
-#define TSI148_LCSR_OFFSET_OTOFL	0x14
-#define TSI148_LCSR_OFFSET_OTBS		0x18
-#define TSI148_LCSR_OFFSET_OTAT		0x1C
-
-/*
- * VMEbus interrupt ack
- * offset  200
- */
-#define TSI148_LCSR_VIACK1	0x204
-#define TSI148_LCSR_VIACK2	0x208
-#define TSI148_LCSR_VIACK3	0x20C
-#define TSI148_LCSR_VIACK4	0x210
-#define TSI148_LCSR_VIACK5	0x214
-#define TSI148_LCSR_VIACK6	0x218
-#define TSI148_LCSR_VIACK7	0x21C
-
-static const int TSI148_LCSR_VIACK[8] = { 0, TSI148_LCSR_VIACK1,
-				TSI148_LCSR_VIACK2, TSI148_LCSR_VIACK3,
-				TSI148_LCSR_VIACK4, TSI148_LCSR_VIACK5,
-				TSI148_LCSR_VIACK6, TSI148_LCSR_VIACK7 };
-
-/*
- * RMW
- * offset    220
- */
-#define TSI148_LCSR_RMWAU	0x220
-#define TSI148_LCSR_RMWAL	0x224
-#define TSI148_LCSR_RMWEN	0x228
-#define TSI148_LCSR_RMWC	0x22C
-#define TSI148_LCSR_RMWS	0x230
-
-/*
- * VMEbus control
- * offset    234
- */
-#define TSI148_LCSR_VMCTRL	0x234
-#define TSI148_LCSR_VCTRL	0x238
-#define TSI148_LCSR_VSTAT	0x23C
-
-/*
- * PCI status
- * offset  240
- */
-#define TSI148_LCSR_PSTAT	0x240
-
-/*
- * VME filter.
- * offset  250
- */
-#define TSI148_LCSR_VMEFL	0x250
-
-	/*
-	 * VME exception.
-	 * offset  260
- */
-#define TSI148_LCSR_VEAU	0x260
-#define TSI148_LCSR_VEAL	0x264
-#define TSI148_LCSR_VEAT	0x268
-
-	/*
-	 * PCI error
-	 * offset  270
-	 */
-#define TSI148_LCSR_EDPAU	0x270
-#define TSI148_LCSR_EDPAL	0x274
-#define TSI148_LCSR_EDPXA	0x278
-#define TSI148_LCSR_EDPXS	0x27C
-#define TSI148_LCSR_EDPAT	0x280
-
-	/*
-	 * Inbound Translations
-	 * offset  300
-	 */
-#define TSI148_LCSR_IT0_ITSAU		0x300
-#define TSI148_LCSR_IT0_ITSAL		0x304
-#define TSI148_LCSR_IT0_ITEAU		0x308
-#define TSI148_LCSR_IT0_ITEAL		0x30C
-#define TSI148_LCSR_IT0_ITOFU		0x310
-#define TSI148_LCSR_IT0_ITOFL		0x314
-#define TSI148_LCSR_IT0_ITAT		0x318
-
-#define TSI148_LCSR_IT1_ITSAU		0x320
-#define TSI148_LCSR_IT1_ITSAL		0x324
-#define TSI148_LCSR_IT1_ITEAU		0x328
-#define TSI148_LCSR_IT1_ITEAL		0x32C
-#define TSI148_LCSR_IT1_ITOFU		0x330
-#define TSI148_LCSR_IT1_ITOFL		0x334
-#define TSI148_LCSR_IT1_ITAT		0x338
-
-#define TSI148_LCSR_IT2_ITSAU		0x340
-#define TSI148_LCSR_IT2_ITSAL		0x344
-#define TSI148_LCSR_IT2_ITEAU		0x348
-#define TSI148_LCSR_IT2_ITEAL		0x34C
-#define TSI148_LCSR_IT2_ITOFU		0x350
-#define TSI148_LCSR_IT2_ITOFL		0x354
-#define TSI148_LCSR_IT2_ITAT		0x358
-
-#define TSI148_LCSR_IT3_ITSAU		0x360
-#define TSI148_LCSR_IT3_ITSAL		0x364
-#define TSI148_LCSR_IT3_ITEAU		0x368
-#define TSI148_LCSR_IT3_ITEAL		0x36C
-#define TSI148_LCSR_IT3_ITOFU		0x370
-#define TSI148_LCSR_IT3_ITOFL		0x374
-#define TSI148_LCSR_IT3_ITAT		0x378
-
-#define TSI148_LCSR_IT4_ITSAU		0x380
-#define TSI148_LCSR_IT4_ITSAL		0x384
-#define TSI148_LCSR_IT4_ITEAU		0x388
-#define TSI148_LCSR_IT4_ITEAL		0x38C
-#define TSI148_LCSR_IT4_ITOFU		0x390
-#define TSI148_LCSR_IT4_ITOFL		0x394
-#define TSI148_LCSR_IT4_ITAT		0x398
-
-#define TSI148_LCSR_IT5_ITSAU		0x3A0
-#define TSI148_LCSR_IT5_ITSAL		0x3A4
-#define TSI148_LCSR_IT5_ITEAU		0x3A8
-#define TSI148_LCSR_IT5_ITEAL		0x3AC
-#define TSI148_LCSR_IT5_ITOFU		0x3B0
-#define TSI148_LCSR_IT5_ITOFL		0x3B4
-#define TSI148_LCSR_IT5_ITAT		0x3B8
-
-#define TSI148_LCSR_IT6_ITSAU		0x3C0
-#define TSI148_LCSR_IT6_ITSAL		0x3C4
-#define TSI148_LCSR_IT6_ITEAU		0x3C8
-#define TSI148_LCSR_IT6_ITEAL		0x3CC
-#define TSI148_LCSR_IT6_ITOFU		0x3D0
-#define TSI148_LCSR_IT6_ITOFL		0x3D4
-#define TSI148_LCSR_IT6_ITAT		0x3D8
-
-#define TSI148_LCSR_IT7_ITSAU		0x3E0
-#define TSI148_LCSR_IT7_ITSAL		0x3E4
-#define TSI148_LCSR_IT7_ITEAU		0x3E8
-#define TSI148_LCSR_IT7_ITEAL		0x3EC
-#define TSI148_LCSR_IT7_ITOFU		0x3F0
-#define TSI148_LCSR_IT7_ITOFL		0x3F4
-#define TSI148_LCSR_IT7_ITAT		0x3F8
-
-
-#define TSI148_LCSR_IT0		0x300
-#define TSI148_LCSR_IT1		0x320
-#define TSI148_LCSR_IT2		0x340
-#define TSI148_LCSR_IT3		0x360
-#define TSI148_LCSR_IT4		0x380
-#define TSI148_LCSR_IT5		0x3A0
-#define TSI148_LCSR_IT6		0x3C0
-#define TSI148_LCSR_IT7		0x3E0
-
-static const int TSI148_LCSR_IT[8] = { TSI148_LCSR_IT0, TSI148_LCSR_IT1,
-					 TSI148_LCSR_IT2, TSI148_LCSR_IT3,
-					 TSI148_LCSR_IT4, TSI148_LCSR_IT5,
-					 TSI148_LCSR_IT6, TSI148_LCSR_IT7 };
-
-#define TSI148_LCSR_OFFSET_ITSAU	0x0
-#define TSI148_LCSR_OFFSET_ITSAL	0x4
-#define TSI148_LCSR_OFFSET_ITEAU	0x8
-#define TSI148_LCSR_OFFSET_ITEAL	0xC
-#define TSI148_LCSR_OFFSET_ITOFU	0x10
-#define TSI148_LCSR_OFFSET_ITOFL	0x14
-#define TSI148_LCSR_OFFSET_ITAT		0x18
-
-	/*
-	 * Inbound Translation GCSR
-	 * offset  400
-	 */
-#define TSI148_LCSR_GBAU	0x400
-#define TSI148_LCSR_GBAL	0x404
-#define TSI148_LCSR_GCSRAT	0x408
-
-	/*
-	 * Inbound Translation CRG
-	 * offset  40C
-	 */
-#define TSI148_LCSR_CBAU	0x40C
-#define TSI148_LCSR_CBAL	0x410
-#define TSI148_LCSR_CSRAT	0x414
-
-	/*
-	 * Inbound Translation CR/CSR
-	 *         CRG
-	 * offset  418
-	 */
-#define TSI148_LCSR_CROU	0x418
-#define TSI148_LCSR_CROL	0x41C
-#define TSI148_LCSR_CRAT	0x420
-
-	/*
-	 * Inbound Translation Location Monitor
-	 * offset  424
-	 */
-#define TSI148_LCSR_LMBAU	0x424
-#define TSI148_LCSR_LMBAL	0x428
-#define TSI148_LCSR_LMAT	0x42C
-
-	/*
-	 * VMEbus Interrupt Control.
-	 * offset  430
-	 */
-#define TSI148_LCSR_BCU		0x430
-#define TSI148_LCSR_BCL		0x434
-#define TSI148_LCSR_BPGTR	0x438
-#define TSI148_LCSR_BPCTR	0x43C
-#define TSI148_LCSR_VICR	0x440
-
-	/*
-	 * Local Bus Interrupt Control.
-	 * offset  448
-	 */
-#define TSI148_LCSR_INTEN	0x448
-#define TSI148_LCSR_INTEO	0x44C
-#define TSI148_LCSR_INTS	0x450
-#define TSI148_LCSR_INTC	0x454
-#define TSI148_LCSR_INTM1	0x458
-#define TSI148_LCSR_INTM2	0x45C
-
-	/*
-	 * DMA Controllers
-	 * offset 500
-	 */
-#define TSI148_LCSR_DCTL0	0x500
-#define TSI148_LCSR_DSTA0	0x504
-#define TSI148_LCSR_DCSAU0	0x508
-#define TSI148_LCSR_DCSAL0	0x50C
-#define TSI148_LCSR_DCDAU0	0x510
-#define TSI148_LCSR_DCDAL0	0x514
-#define TSI148_LCSR_DCLAU0	0x518
-#define TSI148_LCSR_DCLAL0	0x51C
-#define TSI148_LCSR_DSAU0	0x520
-#define TSI148_LCSR_DSAL0	0x524
-#define TSI148_LCSR_DDAU0	0x528
-#define TSI148_LCSR_DDAL0	0x52C
-#define TSI148_LCSR_DSAT0	0x530
-#define TSI148_LCSR_DDAT0	0x534
-#define TSI148_LCSR_DNLAU0	0x538
-#define TSI148_LCSR_DNLAL0	0x53C
-#define TSI148_LCSR_DCNT0	0x540
-#define TSI148_LCSR_DDBS0	0x544
-
-#define TSI148_LCSR_DCTL1	0x580
-#define TSI148_LCSR_DSTA1	0x584
-#define TSI148_LCSR_DCSAU1	0x588
-#define TSI148_LCSR_DCSAL1	0x58C
-#define TSI148_LCSR_DCDAU1	0x590
-#define TSI148_LCSR_DCDAL1	0x594
-#define TSI148_LCSR_DCLAU1	0x598
-#define TSI148_LCSR_DCLAL1	0x59C
-#define TSI148_LCSR_DSAU1	0x5A0
-#define TSI148_LCSR_DSAL1	0x5A4
-#define TSI148_LCSR_DDAU1	0x5A8
-#define TSI148_LCSR_DDAL1	0x5AC
-#define TSI148_LCSR_DSAT1	0x5B0
-#define TSI148_LCSR_DDAT1	0x5B4
-#define TSI148_LCSR_DNLAU1	0x5B8
-#define TSI148_LCSR_DNLAL1	0x5BC
-#define TSI148_LCSR_DCNT1	0x5C0
-#define TSI148_LCSR_DDBS1	0x5C4
-
-#define TSI148_LCSR_DMA0	0x500
-#define TSI148_LCSR_DMA1	0x580
-
-
-static const int TSI148_LCSR_DMA[TSI148_MAX_DMA] = { TSI148_LCSR_DMA0,
-						TSI148_LCSR_DMA1 };
-
-#define TSI148_LCSR_OFFSET_DCTL		0x0
-#define TSI148_LCSR_OFFSET_DSTA		0x4
-#define TSI148_LCSR_OFFSET_DCSAU	0x8
-#define TSI148_LCSR_OFFSET_DCSAL	0xC
-#define TSI148_LCSR_OFFSET_DCDAU	0x10
-#define TSI148_LCSR_OFFSET_DCDAL	0x14
-#define TSI148_LCSR_OFFSET_DCLAU	0x18
-#define TSI148_LCSR_OFFSET_DCLAL	0x1C
-#define TSI148_LCSR_OFFSET_DSAU		0x20
-#define TSI148_LCSR_OFFSET_DSAL		0x24
-#define TSI148_LCSR_OFFSET_DDAU		0x28
-#define TSI148_LCSR_OFFSET_DDAL		0x2C
-#define TSI148_LCSR_OFFSET_DSAT		0x30
-#define TSI148_LCSR_OFFSET_DDAT		0x34
-#define TSI148_LCSR_OFFSET_DNLAU	0x38
-#define TSI148_LCSR_OFFSET_DNLAL	0x3C
-#define TSI148_LCSR_OFFSET_DCNT		0x40
-#define TSI148_LCSR_OFFSET_DDBS		0x44
-
-	/*
-	 * GCSR Register Group
-	 */
-
-	/*
-	 *         GCSR    CRG
-	 * offset   00     600 - DEVI/VENI
-	 * offset   04     604 - CTRL/GA/REVID
-	 * offset   08     608 - Semaphore3/2/1/0
-	 * offset   0C     60C - Seamphore7/6/5/4
-	 */
-#define TSI148_GCSR_ID		0x600
-#define TSI148_GCSR_CSR		0x604
-#define TSI148_GCSR_SEMA0	0x608
-#define TSI148_GCSR_SEMA1	0x60C
-
-	/*
-	 * Mail Box
-	 *         GCSR    CRG
-	 * offset   10     610 - Mailbox0
-	 */
-#define TSI148_GCSR_MBOX0	0x610
-#define TSI148_GCSR_MBOX1	0x614
-#define TSI148_GCSR_MBOX2	0x618
-#define TSI148_GCSR_MBOX3	0x61C
-
-static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0,
-					TSI148_GCSR_MBOX1,
-					TSI148_GCSR_MBOX2,
-					TSI148_GCSR_MBOX3 };
-
-	/*
-	 * CR/CSR
-	 */
-
-	/*
-	 *        CR/CSR   CRG
-	 * offset  7FFF4   FF4 - CSRBCR
-	 * offset  7FFF8   FF8 - CSRBSR
-	 * offset  7FFFC   FFC - CBAR
-	 */
-#define TSI148_CSRBCR	0xFF4
-#define TSI148_CSRBSR	0xFF8
-#define TSI148_CBAR	0xFFC
-
-
-
-
-	/*
-	 *  TSI148 Register Bit Definitions
-	 */
-
-	/*
-	 *  PFCS Register Set
-	 */
-#define TSI148_PCFS_CMMD_SERR          (1<<8)	/* SERR_L out pin ssys err */
-#define TSI148_PCFS_CMMD_PERR          (1<<6)	/* PERR_L out pin  parity */
-#define TSI148_PCFS_CMMD_MSTR          (1<<2)	/* PCI bus master */
-#define TSI148_PCFS_CMMD_MEMSP         (1<<1)	/* PCI mem space access  */
-#define TSI148_PCFS_CMMD_IOSP          (1<<0)	/* PCI I/O space enable */
-
-#define TSI148_PCFS_STAT_RCPVE         (1<<15)	/* Detected Parity Error */
-#define TSI148_PCFS_STAT_SIGSE         (1<<14)	/* Signalled System Error */
-#define TSI148_PCFS_STAT_RCVMA         (1<<13)	/* Received Master Abort */
-#define TSI148_PCFS_STAT_RCVTA         (1<<12)	/* Received Target Abort */
-#define TSI148_PCFS_STAT_SIGTA         (1<<11)	/* Signalled Target Abort */
-#define TSI148_PCFS_STAT_SELTIM        (3<<9)	/* DELSEL Timing */
-#define TSI148_PCFS_STAT_DPAR          (1<<8)	/* Data Parity Err Reported */
-#define TSI148_PCFS_STAT_FAST          (1<<7)	/* Fast back-to-back Cap */
-#define TSI148_PCFS_STAT_P66M          (1<<5)	/* 66 MHz Capable */
-#define TSI148_PCFS_STAT_CAPL          (1<<4)	/* Capab List - address $34 */
-
-/*
- *  Revision ID/Class Code Registers   (CRG +$008)
- */
-#define TSI148_PCFS_CLAS_M             (0xFF<<24)	/* Class ID */
-#define TSI148_PCFS_SUBCLAS_M          (0xFF<<16)	/* Sub-Class ID */
-#define TSI148_PCFS_PROGIF_M           (0xFF<<8)	/* Sub-Class ID */
-#define TSI148_PCFS_REVID_M            (0xFF<<0)	/* Rev ID */
-
-/*
- * Cache Line Size/ Master Latency Timer/ Header Type Registers (CRG + $00C)
- */
-#define TSI148_PCFS_HEAD_M             (0xFF<<16)	/* Master Lat Timer */
-#define TSI148_PCFS_MLAT_M             (0xFF<<8)	/* Master Lat Timer */
-#define TSI148_PCFS_CLSZ_M             (0xFF<<0)	/* Cache Line Size */
-
-/*
- *  Memory Base Address Lower Reg (CRG + $010)
- */
-#define TSI148_PCFS_MBARL_BASEL_M      (0xFFFFF<<12) /* Base Addr Lower Mask */
-#define TSI148_PCFS_MBARL_PRE          (1<<3)	/* Prefetch */
-#define TSI148_PCFS_MBARL_MTYPE_M      (3<<1)	/* Memory Type Mask */
-#define TSI148_PCFS_MBARL_IOMEM        (1<<0)	/* I/O Space Indicator */
-
-/*
- *  Message Signaled Interrupt Capabilities Register (CRG + $040)
- */
-#define TSI148_PCFS_MSICAP_64BAC       (1<<7)	/* 64-bit Address Capable */
-#define TSI148_PCFS_MSICAP_MME_M       (7<<4)	/* Multiple Msg Enable Mask */
-#define TSI148_PCFS_MSICAP_MMC_M       (7<<1)	/* Multiple Msg Capable Mask */
-#define TSI148_PCFS_MSICAP_MSIEN       (1<<0)	/* Msg signaled INT Enable */
-
-/*
- *  Message Address Lower Register (CRG +$044)
- */
-#define TSI148_PCFS_MSIAL_M            (0x3FFFFFFF<<2)	/* Mask */
-
-/*
- *  Message Data Register (CRG + 4C)
- */
-#define TSI148_PCFS_MSIMD_M            (0xFFFF<<0)	/* Mask */
-
-/*
- *  PCI-X Capabilities Register (CRG + $050)
- */
-#define TSI148_PCFS_PCIXCAP_MOST_M     (7<<4)	/* Max outstanding Split Tran */
-#define TSI148_PCFS_PCIXCAP_MMRBC_M    (3<<2)	/* Max Mem Read byte cnt */
-#define TSI148_PCFS_PCIXCAP_ERO        (1<<1)	/* Enable Relaxed Ordering */
-#define TSI148_PCFS_PCIXCAP_DPERE      (1<<0)	/* Data Parity Recover Enable */
-
-/*
- *  PCI-X Status Register (CRG +$054)
- */
-#define TSI148_PCFS_PCIXSTAT_RSCEM     (1<<29)	/* Received Split Comp Error */
-#define TSI148_PCFS_PCIXSTAT_DMCRS_M   (7<<26)	/* max Cumulative Read Size */
-#define TSI148_PCFS_PCIXSTAT_DMOST_M   (7<<23)	/* max outstanding Split Trans
-						 */
-#define TSI148_PCFS_PCIXSTAT_DMMRC_M   (3<<21)	/* max mem read byte count */
-#define TSI148_PCFS_PCIXSTAT_DC        (1<<20)	/* Device Complexity */
-#define TSI148_PCFS_PCIXSTAT_USC       (1<<19)	/* Unexpected Split comp */
-#define TSI148_PCFS_PCIXSTAT_SCD       (1<<18)	/* Split completion discard */
-#define TSI148_PCFS_PCIXSTAT_133C      (1<<17)	/* 133MHz capable */
-#define TSI148_PCFS_PCIXSTAT_64D       (1<<16)	/* 64 bit device */
-#define TSI148_PCFS_PCIXSTAT_BN_M      (0xFF<<8)	/* Bus number */
-#define TSI148_PCFS_PCIXSTAT_DN_M      (0x1F<<3)	/* Device number */
-#define TSI148_PCFS_PCIXSTAT_FN_M      (7<<0)	/* Function Number */
-
-/*
- *  LCSR Registers
- */
-
-/*
- *  Outbound Translation Starting Address Lower
- */
-#define TSI148_LCSR_OTSAL_M            (0xFFFF<<16)	/* Mask */
-
-/*
- *  Outbound Translation Ending Address Lower
- */
-#define TSI148_LCSR_OTEAL_M            (0xFFFF<<16)	/* Mask */
-
-/*
- *  Outbound Translation Offset Lower
- */
-#define TSI148_LCSR_OTOFFL_M           (0xFFFF<<16)	/* Mask */
-
-/*
- *  Outbound Translation 2eSST Broadcast Select
- */
-#define TSI148_LCSR_OTBS_M             (0xFFFFF<<0)	/* Mask */
-
-/*
- *  Outbound Translation Attribute
- */
-#define TSI148_LCSR_OTAT_EN            (1<<31)	/* Window Enable */
-#define TSI148_LCSR_OTAT_MRPFD         (1<<18)	/* Prefetch Disable */
-
-#define TSI148_LCSR_OTAT_PFS_M         (3<<16)	/* Prefetch Size Mask */
-#define TSI148_LCSR_OTAT_PFS_2         (0<<16)	/* 2 Cache Lines P Size */
-#define TSI148_LCSR_OTAT_PFS_4         (1<<16)	/* 4 Cache Lines P Size */
-#define TSI148_LCSR_OTAT_PFS_8         (2<<16)	/* 8 Cache Lines P Size */
-#define TSI148_LCSR_OTAT_PFS_16        (3<<16)	/* 16 Cache Lines P Size */
-
-#define TSI148_LCSR_OTAT_2eSSTM_M      (7<<11)	/* 2eSST Xfer Rate Mask */
-#define TSI148_LCSR_OTAT_2eSSTM_160    (0<<11)	/* 160MB/s 2eSST Xfer Rate */
-#define TSI148_LCSR_OTAT_2eSSTM_267    (1<<11)	/* 267MB/s 2eSST Xfer Rate */
-#define TSI148_LCSR_OTAT_2eSSTM_320    (2<<11)	/* 320MB/s 2eSST Xfer Rate */
-
-#define TSI148_LCSR_OTAT_TM_M          (7<<8)	/* Xfer Protocol Mask */
-#define TSI148_LCSR_OTAT_TM_SCT        (0<<8)	/* SCT Xfer Protocol */
-#define TSI148_LCSR_OTAT_TM_BLT        (1<<8)	/* BLT Xfer Protocol */
-#define TSI148_LCSR_OTAT_TM_MBLT       (2<<8)	/* MBLT Xfer Protocol */
-#define TSI148_LCSR_OTAT_TM_2eVME      (3<<8)	/* 2eVME Xfer Protocol */
-#define TSI148_LCSR_OTAT_TM_2eSST      (4<<8)	/* 2eSST Xfer Protocol */
-#define TSI148_LCSR_OTAT_TM_2eSSTB     (5<<8)	/* 2eSST Bcast Xfer Protocol */
-
-#define TSI148_LCSR_OTAT_DBW_M         (3<<6)	/* Max Data Width */
-#define TSI148_LCSR_OTAT_DBW_16        (0<<6)	/* 16-bit Data Width */
-#define TSI148_LCSR_OTAT_DBW_32        (1<<6)	/* 32-bit Data Width */
-
-#define TSI148_LCSR_OTAT_SUP           (1<<5)	/* Supervisory Access */
-#define TSI148_LCSR_OTAT_PGM           (1<<4)	/* Program Access */
-
-#define TSI148_LCSR_OTAT_AMODE_M       (0xf<<0)	/* Address Mode Mask */
-#define TSI148_LCSR_OTAT_AMODE_A16     (0<<0)	/* A16 Address Space */
-#define TSI148_LCSR_OTAT_AMODE_A24     (1<<0)	/* A24 Address Space */
-#define TSI148_LCSR_OTAT_AMODE_A32     (2<<0)	/* A32 Address Space */
-#define TSI148_LCSR_OTAT_AMODE_A64     (4<<0)	/* A32 Address Space */
-#define TSI148_LCSR_OTAT_AMODE_CRCSR   (5<<0)	/* CR/CSR Address Space */
-#define TSI148_LCSR_OTAT_AMODE_USER1   (8<<0)	/* User1 Address Space */
-#define TSI148_LCSR_OTAT_AMODE_USER2   (9<<0)	/* User2 Address Space */
-#define TSI148_LCSR_OTAT_AMODE_USER3   (10<<0)	/* User3 Address Space */
-#define TSI148_LCSR_OTAT_AMODE_USER4   (11<<0)	/* User4 Address Space */
-
-/*
- *  VME Master Control Register  CRG+$234
- */
-#define TSI148_LCSR_VMCTRL_VSA         (1<<27)	/* VMEbus Stop Ack */
-#define TSI148_LCSR_VMCTRL_VS          (1<<26)	/* VMEbus Stop */
-#define TSI148_LCSR_VMCTRL_DHB         (1<<25)	/* Device Has Bus */
-#define TSI148_LCSR_VMCTRL_DWB         (1<<24)	/* Device Wants Bus */
-
-#define TSI148_LCSR_VMCTRL_RMWEN       (1<<20)	/* RMW Enable */
-
-#define TSI148_LCSR_VMCTRL_ATO_M       (7<<16)	/* Master Access Time-out Mask
-						 */
-#define TSI148_LCSR_VMCTRL_ATO_32      (0<<16)	/* 32 us */
-#define TSI148_LCSR_VMCTRL_ATO_128     (1<<16)	/* 128 us */
-#define TSI148_LCSR_VMCTRL_ATO_512     (2<<16)	/* 512 us */
-#define TSI148_LCSR_VMCTRL_ATO_2M      (3<<16)	/* 2 ms */
-#define TSI148_LCSR_VMCTRL_ATO_8M      (4<<16)	/* 8 ms */
-#define TSI148_LCSR_VMCTRL_ATO_32M     (5<<16)	/* 32 ms */
-#define TSI148_LCSR_VMCTRL_ATO_128M    (6<<16)	/* 128 ms */
-#define TSI148_LCSR_VMCTRL_ATO_DIS     (7<<16)	/* Disabled */
-
-#define TSI148_LCSR_VMCTRL_VTOFF_M     (7<<12)	/* VMEbus Master Time off */
-#define TSI148_LCSR_VMCTRL_VTOFF_0     (0<<12)	/* 0us */
-#define TSI148_LCSR_VMCTRL_VTOFF_1     (1<<12)	/* 1us */
-#define TSI148_LCSR_VMCTRL_VTOFF_2     (2<<12)	/* 2us */
-#define TSI148_LCSR_VMCTRL_VTOFF_4     (3<<12)	/* 4us */
-#define TSI148_LCSR_VMCTRL_VTOFF_8     (4<<12)	/* 8us */
-#define TSI148_LCSR_VMCTRL_VTOFF_16    (5<<12)	/* 16us */
-#define TSI148_LCSR_VMCTRL_VTOFF_32    (6<<12)	/* 32us */
-#define TSI148_LCSR_VMCTRL_VTOFF_64    (7<<12)	/* 64us */
-
-#define TSI148_LCSR_VMCTRL_VTON_M      (7<<8)	/* VMEbus Master Time On */
-#define TSI148_LCSR_VMCTRL_VTON_4      (0<<8)	/* 8us */
-#define TSI148_LCSR_VMCTRL_VTON_8      (1<<8)	/* 8us */
-#define TSI148_LCSR_VMCTRL_VTON_16     (2<<8)	/* 16us */
-#define TSI148_LCSR_VMCTRL_VTON_32     (3<<8)	/* 32us */
-#define TSI148_LCSR_VMCTRL_VTON_64     (4<<8)	/* 64us */
-#define TSI148_LCSR_VMCTRL_VTON_128    (5<<8)	/* 128us */
-#define TSI148_LCSR_VMCTRL_VTON_256    (6<<8)	/* 256us */
-#define TSI148_LCSR_VMCTRL_VTON_512    (7<<8)	/* 512us */
-
-#define TSI148_LCSR_VMCTRL_VREL_M      (3<<3)	/* VMEbus Master Rel Mode Mask
-						 */
-#define TSI148_LCSR_VMCTRL_VREL_T_D    (0<<3)	/* Time on or Done */
-#define TSI148_LCSR_VMCTRL_VREL_T_R_D  (1<<3)	/* Time on and REQ or Done */
-#define TSI148_LCSR_VMCTRL_VREL_T_B_D  (2<<3)	/* Time on and BCLR or Done */
-#define TSI148_LCSR_VMCTRL_VREL_T_D_R  (3<<3)	/* Time on or Done and REQ */
-
-#define TSI148_LCSR_VMCTRL_VFAIR       (1<<2)	/* VMEbus Master Fair Mode */
-#define TSI148_LCSR_VMCTRL_VREQL_M     (3<<0)	/* VMEbus Master Req Level Mask
-						 */
-
-/*
- *  VMEbus Control Register CRG+$238
- */
-#define TSI148_LCSR_VCTRL_LRE          (1<<31)	/* Late Retry Enable */
-
-#define TSI148_LCSR_VCTRL_DLT_M        (0xF<<24)	/* Deadlock Timer */
-#define TSI148_LCSR_VCTRL_DLT_OFF      (0<<24)	/* Deadlock Timer Off */
-#define TSI148_LCSR_VCTRL_DLT_16       (1<<24)	/* 16 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_32       (2<<24)	/* 32 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_64       (3<<24)	/* 64 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_128      (4<<24)	/* 128 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_256      (5<<24)	/* 256 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_512      (6<<24)	/* 512 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_1024     (7<<24)	/* 1024 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_2048     (8<<24)	/* 2048 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_4096     (9<<24)	/* 4096 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_8192     (0xA<<24)	/* 8192 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_16384    (0xB<<24)	/* 16384 VCLKS */
-#define TSI148_LCSR_VCTRL_DLT_32768    (0xC<<24)	/* 32768 VCLKS */
-
-#define TSI148_LCSR_VCTRL_NERBB        (1<<20)	/* No Early Release of Bus Busy
-						 */
-
-#define TSI148_LCSR_VCTRL_SRESET       (1<<17)	/* System Reset */
-#define TSI148_LCSR_VCTRL_LRESET       (1<<16)	/* Local Reset */
-
-#define TSI148_LCSR_VCTRL_SFAILAI      (1<<15)	/* SYSFAIL Auto Slot ID */
-#define TSI148_LCSR_VCTRL_BID_M        (0x1F<<8)	/* Broadcast ID Mask */
-
-#define TSI148_LCSR_VCTRL_ATOEN        (1<<7)	/* Arbiter Time-out Enable */
-#define TSI148_LCSR_VCTRL_ROBIN        (1<<6)	/* VMEbus Round Robin */
-
-#define TSI148_LCSR_VCTRL_GTO_M        (7<<0)	/* VMEbus Global Time-out Mask
-						 */
-#define TSI148_LCSR_VCTRL_GTO_8	      (0<<0)	/* 8 us */
-#define TSI148_LCSR_VCTRL_GTO_16	      (1<<0)	/* 16 us */
-#define TSI148_LCSR_VCTRL_GTO_32	      (2<<0)	/* 32 us */
-#define TSI148_LCSR_VCTRL_GTO_64	      (3<<0)	/* 64 us */
-#define TSI148_LCSR_VCTRL_GTO_128      (4<<0)	/* 128 us */
-#define TSI148_LCSR_VCTRL_GTO_256      (5<<0)	/* 256 us */
-#define TSI148_LCSR_VCTRL_GTO_512      (6<<0)	/* 512 us */
-#define TSI148_LCSR_VCTRL_GTO_DIS      (7<<0)	/* Disabled */
-
-/*
- *  VMEbus Status Register  CRG + $23C
- */
-#define TSI148_LCSR_VSTAT_CPURST       (1<<15)	/* Clear power up reset */
-#define TSI148_LCSR_VSTAT_BRDFL        (1<<14)	/* Board fail */
-#define TSI148_LCSR_VSTAT_PURSTS       (1<<12)	/* Power up reset status */
-#define TSI148_LCSR_VSTAT_BDFAILS      (1<<11)	/* Board Fail Status */
-#define TSI148_LCSR_VSTAT_SYSFAILS     (1<<10)	/* System Fail Status */
-#define TSI148_LCSR_VSTAT_ACFAILS      (1<<9)	/* AC fail status */
-#define TSI148_LCSR_VSTAT_SCONS        (1<<8)	/* System Cont Status */
-#define TSI148_LCSR_VSTAT_GAP          (1<<5)	/* Geographic Addr Parity */
-#define TSI148_LCSR_VSTAT_GA_M         (0x1F<<0)  /* Geographic Addr Mask */
-
-/*
- *  PCI Configuration Status Register CRG+$240
- */
-#define TSI148_LCSR_PSTAT_REQ64S       (1<<6)	/* Request 64 status set */
-#define TSI148_LCSR_PSTAT_M66ENS       (1<<5)	/* M66ENS 66Mhz enable */
-#define TSI148_LCSR_PSTAT_FRAMES       (1<<4)	/* Frame Status */
-#define TSI148_LCSR_PSTAT_IRDYS        (1<<3)	/* IRDY status */
-#define TSI148_LCSR_PSTAT_DEVSELS      (1<<2)	/* DEVL status */
-#define TSI148_LCSR_PSTAT_STOPS        (1<<1)	/* STOP status */
-#define TSI148_LCSR_PSTAT_TRDYS        (1<<0)	/* TRDY status */
-
-/*
- *  VMEbus Exception Attributes Register  CRG + $268
- */
-#define TSI148_LCSR_VEAT_VES           (1<<31)	/* Status */
-#define TSI148_LCSR_VEAT_VEOF          (1<<30)	/* Overflow */
-#define TSI148_LCSR_VEAT_VESCL         (1<<29)	/* Status Clear */
-#define TSI148_LCSR_VEAT_2EOT          (1<<21)	/* 2e Odd Termination */
-#define TSI148_LCSR_VEAT_2EST          (1<<20)	/* 2e Slave terminated */
-#define TSI148_LCSR_VEAT_BERR          (1<<19)	/* Bus Error */
-#define TSI148_LCSR_VEAT_LWORD         (1<<18)	/* LWORD_ signal state */
-#define TSI148_LCSR_VEAT_WRITE         (1<<17)	/* WRITE_ signal state */
-#define TSI148_LCSR_VEAT_IACK          (1<<16)	/* IACK_ signal state */
-#define TSI148_LCSR_VEAT_DS1           (1<<15)	/* DS1_ signal state */
-#define TSI148_LCSR_VEAT_DS0           (1<<14)	/* DS0_ signal state */
-#define TSI148_LCSR_VEAT_AM_M          (0x3F<<8)	/* Address Mode Mask */
-#define TSI148_LCSR_VEAT_XAM_M         (0xFF<<0)	/* Master AMode Mask */
-
-
-/*
- * VMEbus PCI Error Diagnostics PCI/X Attributes Register  CRG + $280
- */
-#define TSI148_LCSR_EDPAT_EDPCL        (1<<29)
-
-/*
- *  Inbound Translation Starting Address Lower
- */
-#define TSI148_LCSR_ITSAL6432_M        (0xFFFF<<16)	/* Mask */
-#define TSI148_LCSR_ITSAL24_M          (0x00FFF<<12)	/* Mask */
-#define TSI148_LCSR_ITSAL16_M          (0x0000FFF<<4)	/* Mask */
-
-/*
- *  Inbound Translation Ending Address Lower
- */
-#define TSI148_LCSR_ITEAL6432_M        (0xFFFF<<16)	/* Mask */
-#define TSI148_LCSR_ITEAL24_M          (0x00FFF<<12)	/* Mask */
-#define TSI148_LCSR_ITEAL16_M          (0x0000FFF<<4)	/* Mask */
-
-/*
- *  Inbound Translation Offset Lower
- */
-#define TSI148_LCSR_ITOFFL6432_M       (0xFFFF<<16)	/* Mask */
-#define TSI148_LCSR_ITOFFL24_M         (0xFFFFF<<12)	/* Mask */
-#define TSI148_LCSR_ITOFFL16_M         (0xFFFFFFF<<4)	/* Mask */
-
-/*
- *  Inbound Translation Attribute
- */
-#define TSI148_LCSR_ITAT_EN            (1<<31)	/* Window Enable */
-#define TSI148_LCSR_ITAT_TH            (1<<18)	/* Prefetch Threshold */
-
-#define TSI148_LCSR_ITAT_VFS_M         (3<<16)	/* Virtual FIFO Size Mask */
-#define TSI148_LCSR_ITAT_VFS_64        (0<<16)	/* 64 bytes Virtual FIFO Size */
-#define TSI148_LCSR_ITAT_VFS_128       (1<<16)	/* 128 bytes Virtual FIFO Sz */
-#define TSI148_LCSR_ITAT_VFS_256       (2<<16)	/* 256 bytes Virtual FIFO Sz */
-#define TSI148_LCSR_ITAT_VFS_512       (3<<16)	/* 512 bytes Virtual FIFO Sz */
-
-#define TSI148_LCSR_ITAT_2eSSTM_M      (7<<12)	/* 2eSST Xfer Rate Mask */
-#define TSI148_LCSR_ITAT_2eSSTM_160    (0<<12)	/* 160MB/s 2eSST Xfer Rate */
-#define TSI148_LCSR_ITAT_2eSSTM_267    (1<<12)	/* 267MB/s 2eSST Xfer Rate */
-#define TSI148_LCSR_ITAT_2eSSTM_320    (2<<12)	/* 320MB/s 2eSST Xfer Rate */
-
-#define TSI148_LCSR_ITAT_2eSSTB        (1<<11)	/* 2eSST Bcast Xfer Protocol */
-#define TSI148_LCSR_ITAT_2eSST         (1<<10)	/* 2eSST Xfer Protocol */
-#define TSI148_LCSR_ITAT_2eVME         (1<<9)	/* 2eVME Xfer Protocol */
-#define TSI148_LCSR_ITAT_MBLT          (1<<8)	/* MBLT Xfer Protocol */
-#define TSI148_LCSR_ITAT_BLT           (1<<7)	/* BLT Xfer Protocol */
-
-#define TSI148_LCSR_ITAT_AS_M          (7<<4)	/* Address Space Mask */
-#define TSI148_LCSR_ITAT_AS_A16        (0<<4)	/* A16 Address Space */
-#define TSI148_LCSR_ITAT_AS_A24        (1<<4)	/* A24 Address Space */
-#define TSI148_LCSR_ITAT_AS_A32        (2<<4)	/* A32 Address Space */
-#define TSI148_LCSR_ITAT_AS_A64        (4<<4)	/* A64 Address Space */
-
-#define TSI148_LCSR_ITAT_SUPR          (1<<3)	/* Supervisor Access */
-#define TSI148_LCSR_ITAT_NPRIV         (1<<2)	/* Non-Priv (User) Access */
-#define TSI148_LCSR_ITAT_PGM           (1<<1)	/* Program Access */
-#define TSI148_LCSR_ITAT_DATA          (1<<0)	/* Data Access */
-
-/*
- *  GCSR Base Address Lower Address  CRG +$404
- */
-#define TSI148_LCSR_GBAL_M             (0x7FFFFFF<<5)	/* Mask */
-
-/*
- *  GCSR Attribute Register CRG + $408
- */
-#define TSI148_LCSR_GCSRAT_EN          (1<<7)	/* Enable access to GCSR */
-
-#define TSI148_LCSR_GCSRAT_AS_M        (7<<4)	/* Address Space Mask */
-#define TSI148_LCSR_GCSRAT_AS_A16       (0<<4)	/* Address Space 16 */
-#define TSI148_LCSR_GCSRAT_AS_A24       (1<<4)	/* Address Space 24 */
-#define TSI148_LCSR_GCSRAT_AS_A32       (2<<4)	/* Address Space 32 */
-#define TSI148_LCSR_GCSRAT_AS_A64       (4<<4)	/* Address Space 64 */
-
-#define TSI148_LCSR_GCSRAT_SUPR        (1<<3)	/* Sup set -GCSR decoder */
-#define TSI148_LCSR_GCSRAT_NPRIV       (1<<2)	/* Non-Privliged set - CGSR */
-#define TSI148_LCSR_GCSRAT_PGM         (1<<1)	/* Program set - GCSR decoder */
-#define TSI148_LCSR_GCSRAT_DATA        (1<<0)	/* DATA set GCSR decoder */
-
-/*
- *  CRG Base Address Lower Address  CRG + $410
- */
-#define TSI148_LCSR_CBAL_M             (0xFFFFF<<12)
-
-/*
- *  CRG Attribute Register  CRG + $414
- */
-#define TSI148_LCSR_CRGAT_EN           (1<<7)	/* Enable PRG Access */
-
-#define TSI148_LCSR_CRGAT_AS_M         (7<<4)	/* Address Space */
-#define TSI148_LCSR_CRGAT_AS_A16       (0<<4)	/* Address Space 16 */
-#define TSI148_LCSR_CRGAT_AS_A24       (1<<4)	/* Address Space 24 */
-#define TSI148_LCSR_CRGAT_AS_A32       (2<<4)	/* Address Space 32 */
-#define TSI148_LCSR_CRGAT_AS_A64       (4<<4)	/* Address Space 64 */
-
-#define TSI148_LCSR_CRGAT_SUPR         (1<<3)	/* Supervisor Access */
-#define TSI148_LCSR_CRGAT_NPRIV        (1<<2)	/* Non-Privliged(User) Access */
-#define TSI148_LCSR_CRGAT_PGM          (1<<1)	/* Program Access */
-#define TSI148_LCSR_CRGAT_DATA         (1<<0)	/* Data Access */
-
-/*
- *  CR/CSR Offset Lower Register  CRG + $41C
- */
-#define TSI148_LCSR_CROL_M             (0x1FFF<<19)	/* Mask */
-
-/*
- *  CR/CSR Attribute register  CRG + $420
- */
-#define TSI148_LCSR_CRAT_EN            (1<<7)	/* Enable access to CR/CSR */
-
-/*
- *  Location Monitor base address lower register  CRG + $428
- */
-#define TSI148_LCSR_LMBAL_M            (0x7FFFFFF<<5)	/* Mask */
-
-/*
- *  Location Monitor Attribute Register  CRG + $42C
- */
-#define TSI148_LCSR_LMAT_EN            (1<<7)	/* Enable Location Monitor */
-
-#define TSI148_LCSR_LMAT_AS_M          (7<<4)	/* Address Space MASK  */
-#define TSI148_LCSR_LMAT_AS_A16        (0<<4)	/* A16 */
-#define TSI148_LCSR_LMAT_AS_A24        (1<<4)	/* A24 */
-#define TSI148_LCSR_LMAT_AS_A32        (2<<4)	/* A32 */
-#define TSI148_LCSR_LMAT_AS_A64        (4<<4)	/* A64 */
-
-#define TSI148_LCSR_LMAT_SUPR          (1<<3)	/* Supervisor Access */
-#define TSI148_LCSR_LMAT_NPRIV         (1<<2)	/* Non-Priv (User) Access */
-#define TSI148_LCSR_LMAT_PGM           (1<<1)	/* Program Access */
-#define TSI148_LCSR_LMAT_DATA          (1<<0)	/* Data Access  */
-
-/*
- *  Broadcast Pulse Generator Timer Register  CRG + $438
- */
-#define TSI148_LCSR_BPGTR_BPGT_M       (0xFFFF<<0)	/* Mask */
-
-/*
- *  Broadcast Programmable Clock Timer Register  CRG + $43C
- */
-#define TSI148_LCSR_BPCTR_BPCT_M       (0xFFFFFF<<0)	/* Mask */
-
-/*
- *  VMEbus Interrupt Control Register           CRG + $43C
- */
-#define TSI148_LCSR_VICR_CNTS_M        (3<<22)	/* Cntr Source MASK */
-#define TSI148_LCSR_VICR_CNTS_DIS      (1<<22)	/* Cntr Disable */
-#define TSI148_LCSR_VICR_CNTS_IRQ1     (2<<22)	/* IRQ1 to Cntr */
-#define TSI148_LCSR_VICR_CNTS_IRQ2     (3<<22)	/* IRQ2 to Cntr */
-
-#define TSI148_LCSR_VICR_EDGIS_M       (3<<20)	/* Edge interrupt MASK */
-#define TSI148_LCSR_VICR_EDGIS_DIS     (1<<20)	/* Edge interrupt Disable */
-#define TSI148_LCSR_VICR_EDGIS_IRQ1    (2<<20)	/* IRQ1 to Edge */
-#define TSI148_LCSR_VICR_EDGIS_IRQ2    (3<<20)	/* IRQ2 to Edge */
-
-#define TSI148_LCSR_VICR_IRQIF_M       (3<<18)	/* IRQ1* Function MASK */
-#define TSI148_LCSR_VICR_IRQIF_NORM    (1<<18)	/* Normal */
-#define TSI148_LCSR_VICR_IRQIF_PULSE   (2<<18)	/* Pulse Generator */
-#define TSI148_LCSR_VICR_IRQIF_PROG    (3<<18)	/* Programmable Clock */
-#define TSI148_LCSR_VICR_IRQIF_1U      (4<<18)	/* 1us Clock */
-
-#define TSI148_LCSR_VICR_IRQ2F_M       (3<<16)	/* IRQ2* Function MASK */
-#define TSI148_LCSR_VICR_IRQ2F_NORM    (1<<16)	/* Normal */
-#define TSI148_LCSR_VICR_IRQ2F_PULSE   (2<<16)	/* Pulse Generator */
-#define TSI148_LCSR_VICR_IRQ2F_PROG    (3<<16)	/* Programmable Clock */
-#define TSI148_LCSR_VICR_IRQ2F_1U      (4<<16)	/* 1us Clock */
-
-#define TSI148_LCSR_VICR_BIP           (1<<15)	/* Broadcast Interrupt Pulse */
-
-#define TSI148_LCSR_VICR_IRQC          (1<<12)	/* VMEbus IRQ Clear */
-#define TSI148_LCSR_VICR_IRQS          (1<<11)	/* VMEbus IRQ Status */
-
-#define TSI148_LCSR_VICR_IRQL_M        (7<<8)	/* VMEbus SW IRQ Level Mask */
-#define TSI148_LCSR_VICR_IRQL_1        (1<<8)	/* VMEbus SW IRQ Level 1 */
-#define TSI148_LCSR_VICR_IRQL_2        (2<<8)	/* VMEbus SW IRQ Level 2 */
-#define TSI148_LCSR_VICR_IRQL_3        (3<<8)	/* VMEbus SW IRQ Level 3 */
-#define TSI148_LCSR_VICR_IRQL_4        (4<<8)	/* VMEbus SW IRQ Level 4 */
-#define TSI148_LCSR_VICR_IRQL_5        (5<<8)	/* VMEbus SW IRQ Level 5 */
-#define TSI148_LCSR_VICR_IRQL_6        (6<<8)	/* VMEbus SW IRQ Level 6 */
-#define TSI148_LCSR_VICR_IRQL_7        (7<<8)	/* VMEbus SW IRQ Level 7 */
-
-static const int TSI148_LCSR_VICR_IRQL[8] = { 0, TSI148_LCSR_VICR_IRQL_1,
-			TSI148_LCSR_VICR_IRQL_2, TSI148_LCSR_VICR_IRQL_3,
-			TSI148_LCSR_VICR_IRQL_4, TSI148_LCSR_VICR_IRQL_5,
-			TSI148_LCSR_VICR_IRQL_6, TSI148_LCSR_VICR_IRQL_7 };
-
-#define TSI148_LCSR_VICR_STID_M        (0xFF<<0)	/* Status/ID Mask */
-
-/*
- *  Interrupt Enable Register   CRG + $440
- */
-#define TSI148_LCSR_INTEN_DMA1EN       (1<<25)	/* DMAC 1 */
-#define TSI148_LCSR_INTEN_DMA0EN       (1<<24)	/* DMAC 0 */
-#define TSI148_LCSR_INTEN_LM3EN        (1<<23)	/* Location Monitor 3 */
-#define TSI148_LCSR_INTEN_LM2EN        (1<<22)	/* Location Monitor 2 */
-#define TSI148_LCSR_INTEN_LM1EN        (1<<21)	/* Location Monitor 1 */
-#define TSI148_LCSR_INTEN_LM0EN        (1<<20)	/* Location Monitor 0 */
-#define TSI148_LCSR_INTEN_MB3EN        (1<<19)	/* Mail Box 3 */
-#define TSI148_LCSR_INTEN_MB2EN        (1<<18)	/* Mail Box 2 */
-#define TSI148_LCSR_INTEN_MB1EN        (1<<17)	/* Mail Box 1 */
-#define TSI148_LCSR_INTEN_MB0EN        (1<<16)	/* Mail Box 0 */
-#define TSI148_LCSR_INTEN_PERREN       (1<<13)	/* PCI/X Error */
-#define TSI148_LCSR_INTEN_VERREN       (1<<12)	/* VMEbus Error */
-#define TSI148_LCSR_INTEN_VIEEN        (1<<11)	/* VMEbus IRQ Edge */
-#define TSI148_LCSR_INTEN_IACKEN       (1<<10)	/* IACK */
-#define TSI148_LCSR_INTEN_SYSFLEN      (1<<9)	/* System Fail */
-#define TSI148_LCSR_INTEN_ACFLEN       (1<<8)	/* AC Fail */
-#define TSI148_LCSR_INTEN_IRQ7EN       (1<<7)	/* IRQ7 */
-#define TSI148_LCSR_INTEN_IRQ6EN       (1<<6)	/* IRQ6 */
-#define TSI148_LCSR_INTEN_IRQ5EN       (1<<5)	/* IRQ5 */
-#define TSI148_LCSR_INTEN_IRQ4EN       (1<<4)	/* IRQ4 */
-#define TSI148_LCSR_INTEN_IRQ3EN       (1<<3)	/* IRQ3 */
-#define TSI148_LCSR_INTEN_IRQ2EN       (1<<2)	/* IRQ2 */
-#define TSI148_LCSR_INTEN_IRQ1EN       (1<<1)	/* IRQ1 */
-
-static const int TSI148_LCSR_INTEN_LMEN[4] = { TSI148_LCSR_INTEN_LM0EN,
-					TSI148_LCSR_INTEN_LM1EN,
-					TSI148_LCSR_INTEN_LM2EN,
-					TSI148_LCSR_INTEN_LM3EN };
-
-static const int TSI148_LCSR_INTEN_IRQEN[7] = { TSI148_LCSR_INTEN_IRQ1EN,
-					TSI148_LCSR_INTEN_IRQ2EN,
-					TSI148_LCSR_INTEN_IRQ3EN,
-					TSI148_LCSR_INTEN_IRQ4EN,
-					TSI148_LCSR_INTEN_IRQ5EN,
-					TSI148_LCSR_INTEN_IRQ6EN,
-					TSI148_LCSR_INTEN_IRQ7EN };
-
-/*
- *  Interrupt Enable Out Register CRG + $444
- */
-#define TSI148_LCSR_INTEO_DMA1EO       (1<<25)	/* DMAC 1 */
-#define TSI148_LCSR_INTEO_DMA0EO       (1<<24)	/* DMAC 0 */
-#define TSI148_LCSR_INTEO_LM3EO        (1<<23)	/* Loc Monitor 3 */
-#define TSI148_LCSR_INTEO_LM2EO        (1<<22)	/* Loc Monitor 2 */
-#define TSI148_LCSR_INTEO_LM1EO        (1<<21)	/* Loc Monitor 1 */
-#define TSI148_LCSR_INTEO_LM0EO        (1<<20)	/* Location Monitor 0 */
-#define TSI148_LCSR_INTEO_MB3EO        (1<<19)	/* Mail Box 3 */
-#define TSI148_LCSR_INTEO_MB2EO        (1<<18)	/* Mail Box 2 */
-#define TSI148_LCSR_INTEO_MB1EO        (1<<17)	/* Mail Box 1 */
-#define TSI148_LCSR_INTEO_MB0EO        (1<<16)	/* Mail Box 0 */
-#define TSI148_LCSR_INTEO_PERREO       (1<<13)	/* PCI/X Error */
-#define TSI148_LCSR_INTEO_VERREO       (1<<12)	/* VMEbus Error */
-#define TSI148_LCSR_INTEO_VIEEO        (1<<11)	/* VMEbus IRQ Edge */
-#define TSI148_LCSR_INTEO_IACKEO       (1<<10)	/* IACK */
-#define TSI148_LCSR_INTEO_SYSFLEO      (1<<9)	/* System Fail */
-#define TSI148_LCSR_INTEO_ACFLEO       (1<<8)	/* AC Fail */
-#define TSI148_LCSR_INTEO_IRQ7EO       (1<<7)	/* IRQ7 */
-#define TSI148_LCSR_INTEO_IRQ6EO       (1<<6)	/* IRQ6 */
-#define TSI148_LCSR_INTEO_IRQ5EO       (1<<5)	/* IRQ5 */
-#define TSI148_LCSR_INTEO_IRQ4EO       (1<<4)	/* IRQ4 */
-#define TSI148_LCSR_INTEO_IRQ3EO       (1<<3)	/* IRQ3 */
-#define TSI148_LCSR_INTEO_IRQ2EO       (1<<2)	/* IRQ2 */
-#define TSI148_LCSR_INTEO_IRQ1EO       (1<<1)	/* IRQ1 */
-
-static const int TSI148_LCSR_INTEO_LMEO[4] = { TSI148_LCSR_INTEO_LM0EO,
-					TSI148_LCSR_INTEO_LM1EO,
-					TSI148_LCSR_INTEO_LM2EO,
-					TSI148_LCSR_INTEO_LM3EO };
-
-static const int TSI148_LCSR_INTEO_IRQEO[7] = { TSI148_LCSR_INTEO_IRQ1EO,
-					TSI148_LCSR_INTEO_IRQ2EO,
-					TSI148_LCSR_INTEO_IRQ3EO,
-					TSI148_LCSR_INTEO_IRQ4EO,
-					TSI148_LCSR_INTEO_IRQ5EO,
-					TSI148_LCSR_INTEO_IRQ6EO,
-					TSI148_LCSR_INTEO_IRQ7EO };
-
-/*
- *  Interrupt Status Register CRG + $448
- */
-#define TSI148_LCSR_INTS_DMA1S         (1<<25)	/* DMA 1 */
-#define TSI148_LCSR_INTS_DMA0S         (1<<24)	/* DMA 0 */
-#define TSI148_LCSR_INTS_LM3S          (1<<23)	/* Location Monitor 3 */
-#define TSI148_LCSR_INTS_LM2S          (1<<22)	/* Location Monitor 2 */
-#define TSI148_LCSR_INTS_LM1S          (1<<21)	/* Location Monitor 1 */
-#define TSI148_LCSR_INTS_LM0S          (1<<20)	/* Location Monitor 0 */
-#define TSI148_LCSR_INTS_MB3S          (1<<19)	/* Mail Box 3 */
-#define TSI148_LCSR_INTS_MB2S          (1<<18)	/* Mail Box 2 */
-#define TSI148_LCSR_INTS_MB1S          (1<<17)	/* Mail Box 1 */
-#define TSI148_LCSR_INTS_MB0S          (1<<16)	/* Mail Box 0 */
-#define TSI148_LCSR_INTS_PERRS         (1<<13)	/* PCI/X Error */
-#define TSI148_LCSR_INTS_VERRS         (1<<12)	/* VMEbus Error */
-#define TSI148_LCSR_INTS_VIES          (1<<11)	/* VMEbus IRQ Edge */
-#define TSI148_LCSR_INTS_IACKS         (1<<10)	/* IACK */
-#define TSI148_LCSR_INTS_SYSFLS        (1<<9)	/* System Fail */
-#define TSI148_LCSR_INTS_ACFLS         (1<<8)	/* AC Fail */
-#define TSI148_LCSR_INTS_IRQ7S         (1<<7)	/* IRQ7 */
-#define TSI148_LCSR_INTS_IRQ6S         (1<<6)	/* IRQ6 */
-#define TSI148_LCSR_INTS_IRQ5S         (1<<5)	/* IRQ5 */
-#define TSI148_LCSR_INTS_IRQ4S         (1<<4)	/* IRQ4 */
-#define TSI148_LCSR_INTS_IRQ3S         (1<<3)	/* IRQ3 */
-#define TSI148_LCSR_INTS_IRQ2S         (1<<2)	/* IRQ2 */
-#define TSI148_LCSR_INTS_IRQ1S         (1<<1)	/* IRQ1 */
-
-static const int TSI148_LCSR_INTS_LMS[4] = { TSI148_LCSR_INTS_LM0S,
-					TSI148_LCSR_INTS_LM1S,
-					TSI148_LCSR_INTS_LM2S,
-					TSI148_LCSR_INTS_LM3S };
-
-static const int TSI148_LCSR_INTS_MBS[4] = { TSI148_LCSR_INTS_MB0S,
-					TSI148_LCSR_INTS_MB1S,
-					TSI148_LCSR_INTS_MB2S,
-					TSI148_LCSR_INTS_MB3S };
-
-/*
- *  Interrupt Clear Register CRG + $44C
- */
-#define TSI148_LCSR_INTC_DMA1C         (1<<25)	/* DMA 1 */
-#define TSI148_LCSR_INTC_DMA0C         (1<<24)	/* DMA 0 */
-#define TSI148_LCSR_INTC_LM3C          (1<<23)	/* Location Monitor 3 */
-#define TSI148_LCSR_INTC_LM2C          (1<<22)	/* Location Monitor 2 */
-#define TSI148_LCSR_INTC_LM1C          (1<<21)	/* Location Monitor 1 */
-#define TSI148_LCSR_INTC_LM0C          (1<<20)	/* Location Monitor 0 */
-#define TSI148_LCSR_INTC_MB3C          (1<<19)	/* Mail Box 3 */
-#define TSI148_LCSR_INTC_MB2C          (1<<18)	/* Mail Box 2 */
-#define TSI148_LCSR_INTC_MB1C          (1<<17)	/* Mail Box 1 */
-#define TSI148_LCSR_INTC_MB0C          (1<<16)	/* Mail Box 0 */
-#define TSI148_LCSR_INTC_PERRC         (1<<13)	/* VMEbus Error */
-#define TSI148_LCSR_INTC_VERRC         (1<<12)	/* VMEbus Access Time-out */
-#define TSI148_LCSR_INTC_VIEC          (1<<11)	/* VMEbus IRQ Edge */
-#define TSI148_LCSR_INTC_IACKC         (1<<10)	/* IACK */
-#define TSI148_LCSR_INTC_SYSFLC        (1<<9)	/* System Fail */
-#define TSI148_LCSR_INTC_ACFLC         (1<<8)	/* AC Fail */
-
-static const int TSI148_LCSR_INTC_LMC[4] = { TSI148_LCSR_INTC_LM0C,
-					TSI148_LCSR_INTC_LM1C,
-					TSI148_LCSR_INTC_LM2C,
-					TSI148_LCSR_INTC_LM3C };
-
-static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C,
-					TSI148_LCSR_INTC_MB1C,
-					TSI148_LCSR_INTC_MB2C,
-					TSI148_LCSR_INTC_MB3C };
-
-/*
- *  Interrupt Map Register 1 CRG + $458
- */
-#define TSI148_LCSR_INTM1_DMA1M_M      (3<<18)	/* DMA 1 */
-#define TSI148_LCSR_INTM1_DMA0M_M      (3<<16)	/* DMA 0 */
-#define TSI148_LCSR_INTM1_LM3M_M       (3<<14)	/* Location Monitor 3 */
-#define TSI148_LCSR_INTM1_LM2M_M       (3<<12)	/* Location Monitor 2 */
-#define TSI148_LCSR_INTM1_LM1M_M       (3<<10)	/* Location Monitor 1 */
-#define TSI148_LCSR_INTM1_LM0M_M       (3<<8)	/* Location Monitor 0 */
-#define TSI148_LCSR_INTM1_MB3M_M       (3<<6)	/* Mail Box 3 */
-#define TSI148_LCSR_INTM1_MB2M_M       (3<<4)	/* Mail Box 2 */
-#define TSI148_LCSR_INTM1_MB1M_M       (3<<2)	/* Mail Box 1 */
-#define TSI148_LCSR_INTM1_MB0M_M       (3<<0)	/* Mail Box 0 */
-
-/*
- *  Interrupt Map Register 2 CRG + $45C
- */
-#define TSI148_LCSR_INTM2_PERRM_M      (3<<26)	/* PCI Bus Error */
-#define TSI148_LCSR_INTM2_VERRM_M      (3<<24)	/* VMEbus Error */
-#define TSI148_LCSR_INTM2_VIEM_M       (3<<22)	/* VMEbus IRQ Edge */
-#define TSI148_LCSR_INTM2_IACKM_M      (3<<20)	/* IACK */
-#define TSI148_LCSR_INTM2_SYSFLM_M     (3<<18)	/* System Fail */
-#define TSI148_LCSR_INTM2_ACFLM_M      (3<<16)	/* AC Fail */
-#define TSI148_LCSR_INTM2_IRQ7M_M      (3<<14)	/* IRQ7 */
-#define TSI148_LCSR_INTM2_IRQ6M_M      (3<<12)	/* IRQ6 */
-#define TSI148_LCSR_INTM2_IRQ5M_M      (3<<10)	/* IRQ5 */
-#define TSI148_LCSR_INTM2_IRQ4M_M      (3<<8)	/* IRQ4 */
-#define TSI148_LCSR_INTM2_IRQ3M_M      (3<<6)	/* IRQ3 */
-#define TSI148_LCSR_INTM2_IRQ2M_M      (3<<4)	/* IRQ2 */
-#define TSI148_LCSR_INTM2_IRQ1M_M      (3<<2)	/* IRQ1 */
-
-/*
- *  DMA Control (0-1) Registers CRG + $500
- */
-#define TSI148_LCSR_DCTL_ABT           (1<<27)	/* Abort */
-#define TSI148_LCSR_DCTL_PAU           (1<<26)	/* Pause */
-#define TSI148_LCSR_DCTL_DGO           (1<<25)	/* DMA Go */
-
-#define TSI148_LCSR_DCTL_MOD           (1<<23)	/* Mode */
-
-#define TSI148_LCSR_DCTL_VBKS_M        (7<<12)	/* VMEbus block Size MASK */
-#define TSI148_LCSR_DCTL_VBKS_32       (0<<12)	/* VMEbus block Size 32 */
-#define TSI148_LCSR_DCTL_VBKS_64       (1<<12)	/* VMEbus block Size 64 */
-#define TSI148_LCSR_DCTL_VBKS_128      (2<<12)	/* VMEbus block Size 128 */
-#define TSI148_LCSR_DCTL_VBKS_256      (3<<12)	/* VMEbus block Size 256 */
-#define TSI148_LCSR_DCTL_VBKS_512      (4<<12)	/* VMEbus block Size 512 */
-#define TSI148_LCSR_DCTL_VBKS_1024     (5<<12)	/* VMEbus block Size 1024 */
-#define TSI148_LCSR_DCTL_VBKS_2048     (6<<12)	/* VMEbus block Size 2048 */
-#define TSI148_LCSR_DCTL_VBKS_4096     (7<<12)	/* VMEbus block Size 4096 */
-
-#define TSI148_LCSR_DCTL_VBOT_M        (7<<8)	/* VMEbus back-off MASK */
-#define TSI148_LCSR_DCTL_VBOT_0        (0<<8)	/* VMEbus back-off  0us */
-#define TSI148_LCSR_DCTL_VBOT_1        (1<<8)	/* VMEbus back-off 1us */
-#define TSI148_LCSR_DCTL_VBOT_2        (2<<8)	/* VMEbus back-off 2us */
-#define TSI148_LCSR_DCTL_VBOT_4        (3<<8)	/* VMEbus back-off 4us */
-#define TSI148_LCSR_DCTL_VBOT_8        (4<<8)	/* VMEbus back-off 8us */
-#define TSI148_LCSR_DCTL_VBOT_16       (5<<8)	/* VMEbus back-off 16us */
-#define TSI148_LCSR_DCTL_VBOT_32       (6<<8)	/* VMEbus back-off 32us */
-#define TSI148_LCSR_DCTL_VBOT_64       (7<<8)	/* VMEbus back-off 64us */
-
-#define TSI148_LCSR_DCTL_PBKS_M        (7<<4)	/* PCI block size MASK */
-#define TSI148_LCSR_DCTL_PBKS_32       (0<<4)	/* PCI block size 32 bytes */
-#define TSI148_LCSR_DCTL_PBKS_64       (1<<4)	/* PCI block size 64 bytes */
-#define TSI148_LCSR_DCTL_PBKS_128      (2<<4)	/* PCI block size 128 bytes */
-#define TSI148_LCSR_DCTL_PBKS_256      (3<<4)	/* PCI block size 256 bytes */
-#define TSI148_LCSR_DCTL_PBKS_512      (4<<4)	/* PCI block size 512 bytes */
-#define TSI148_LCSR_DCTL_PBKS_1024     (5<<4)	/* PCI block size 1024 bytes */
-#define TSI148_LCSR_DCTL_PBKS_2048     (6<<4)	/* PCI block size 2048 bytes */
-#define TSI148_LCSR_DCTL_PBKS_4096     (7<<4)	/* PCI block size 4096 bytes */
-
-#define TSI148_LCSR_DCTL_PBOT_M        (7<<0)	/* PCI back off MASK */
-#define TSI148_LCSR_DCTL_PBOT_0        (0<<0)	/* PCI back off 0us */
-#define TSI148_LCSR_DCTL_PBOT_1        (1<<0)	/* PCI back off 1us */
-#define TSI148_LCSR_DCTL_PBOT_2        (2<<0)	/* PCI back off 2us */
-#define TSI148_LCSR_DCTL_PBOT_4        (3<<0)	/* PCI back off 3us */
-#define TSI148_LCSR_DCTL_PBOT_8        (4<<0)	/* PCI back off 4us */
-#define TSI148_LCSR_DCTL_PBOT_16       (5<<0)	/* PCI back off 8us */
-#define TSI148_LCSR_DCTL_PBOT_32       (6<<0)	/* PCI back off 16us */
-#define TSI148_LCSR_DCTL_PBOT_64       (7<<0)	/* PCI back off 32us */
-
-/*
- *  DMA Status Registers (0-1)  CRG + $504
- */
-#define TSI148_LCSR_DSTA_SMA           (1<<31)	/* PCI Signalled Master Abt */
-#define TSI148_LCSR_DSTA_RTA           (1<<30)	/* PCI Received Target Abt */
-#define TSI148_LCSR_DSTA_MRC           (1<<29)	/* PCI Max Retry Count */
-#define TSI148_LCSR_DSTA_VBE           (1<<28)	/* VMEbus error */
-#define TSI148_LCSR_DSTA_ABT           (1<<27)	/* Abort */
-#define TSI148_LCSR_DSTA_PAU           (1<<26)	/* Pause */
-#define TSI148_LCSR_DSTA_DON           (1<<25)	/* Done */
-#define TSI148_LCSR_DSTA_BSY           (1<<24)	/* Busy */
-
-/*
- *  DMA Current Link Address Lower (0-1)
- */
-#define TSI148_LCSR_DCLAL_M            (0x3FFFFFF<<6)	/* Mask */
-
-/*
- *  DMA Source Attribute (0-1) Reg
- */
-#define TSI148_LCSR_DSAT_TYP_M         (3<<28)	/* Source Bus Type */
-#define TSI148_LCSR_DSAT_TYP_PCI       (0<<28)	/* PCI Bus */
-#define TSI148_LCSR_DSAT_TYP_VME       (1<<28)	/* VMEbus */
-#define TSI148_LCSR_DSAT_TYP_PAT       (2<<28)	/* Data Pattern */
-
-#define TSI148_LCSR_DSAT_PSZ           (1<<25)	/* Pattern Size */
-#define TSI148_LCSR_DSAT_NIN           (1<<24)	/* No Increment */
-
-#define TSI148_LCSR_DSAT_2eSSTM_M      (3<<11)	/* 2eSST Trans Rate Mask */
-#define TSI148_LCSR_DSAT_2eSSTM_160    (0<<11)	/* 160 MB/s */
-#define TSI148_LCSR_DSAT_2eSSTM_267    (1<<11)	/* 267 MB/s */
-#define TSI148_LCSR_DSAT_2eSSTM_320    (2<<11)	/* 320 MB/s */
-
-#define TSI148_LCSR_DSAT_TM_M          (7<<8)	/* Bus Transfer Protocol Mask */
-#define TSI148_LCSR_DSAT_TM_SCT        (0<<8)	/* SCT */
-#define TSI148_LCSR_DSAT_TM_BLT        (1<<8)	/* BLT */
-#define TSI148_LCSR_DSAT_TM_MBLT       (2<<8)	/* MBLT */
-#define TSI148_LCSR_DSAT_TM_2eVME      (3<<8)	/* 2eVME */
-#define TSI148_LCSR_DSAT_TM_2eSST      (4<<8)	/* 2eSST */
-#define TSI148_LCSR_DSAT_TM_2eSSTB     (5<<8)	/* 2eSST Broadcast */
-
-#define TSI148_LCSR_DSAT_DBW_M         (3<<6)	/* Max Data Width MASK */
-#define TSI148_LCSR_DSAT_DBW_16        (0<<6)	/* 16 Bits */
-#define TSI148_LCSR_DSAT_DBW_32        (1<<6)	/* 32 Bits */
-
-#define TSI148_LCSR_DSAT_SUP           (1<<5)	/* Supervisory Mode */
-#define TSI148_LCSR_DSAT_PGM           (1<<4)	/* Program Mode */
-
-#define TSI148_LCSR_DSAT_AMODE_M       (0xf<<0)	/* Address Space Mask */
-#define TSI148_LCSR_DSAT_AMODE_A16     (0<<0)	/* A16 */
-#define TSI148_LCSR_DSAT_AMODE_A24     (1<<0)	/* A24 */
-#define TSI148_LCSR_DSAT_AMODE_A32     (2<<0)	/* A32 */
-#define TSI148_LCSR_DSAT_AMODE_A64     (4<<0)	/* A64 */
-#define TSI148_LCSR_DSAT_AMODE_CRCSR   (5<<0)	/* CR/CSR */
-#define TSI148_LCSR_DSAT_AMODE_USER1   (8<<0)	/* User1 */
-#define TSI148_LCSR_DSAT_AMODE_USER2   (9<<0)	/* User2 */
-#define TSI148_LCSR_DSAT_AMODE_USER3   (0xa<<0)	/* User3 */
-#define TSI148_LCSR_DSAT_AMODE_USER4   (0xb<<0)	/* User4 */
-
-/*
- *  DMA Destination Attribute Registers (0-1)
- */
-#define TSI148_LCSR_DDAT_TYP_PCI       (0<<28)	/* Destination PCI Bus  */
-#define TSI148_LCSR_DDAT_TYP_VME       (1<<28)	/* Destination VMEbus */
-
-#define TSI148_LCSR_DDAT_2eSSTM_M      (3<<11)	/* 2eSST Transfer Rate Mask */
-#define TSI148_LCSR_DDAT_2eSSTM_160    (0<<11)	/* 160 MB/s */
-#define TSI148_LCSR_DDAT_2eSSTM_267    (1<<11)	/* 267 MB/s */
-#define TSI148_LCSR_DDAT_2eSSTM_320    (2<<11)	/* 320 MB/s */
-
-#define TSI148_LCSR_DDAT_TM_M          (7<<8)	/* Bus Transfer Protocol Mask */
-#define TSI148_LCSR_DDAT_TM_SCT        (0<<8)	/* SCT */
-#define TSI148_LCSR_DDAT_TM_BLT        (1<<8)	/* BLT */
-#define TSI148_LCSR_DDAT_TM_MBLT       (2<<8)	/* MBLT */
-#define TSI148_LCSR_DDAT_TM_2eVME      (3<<8)	/* 2eVME */
-#define TSI148_LCSR_DDAT_TM_2eSST      (4<<8)	/* 2eSST */
-#define TSI148_LCSR_DDAT_TM_2eSSTB     (5<<8)	/* 2eSST Broadcast */
-
-#define TSI148_LCSR_DDAT_DBW_M         (3<<6)	/* Max Data Width MASK */
-#define TSI148_LCSR_DDAT_DBW_16        (0<<6)	/* 16 Bits */
-#define TSI148_LCSR_DDAT_DBW_32        (1<<6)	/* 32 Bits */
-
-#define TSI148_LCSR_DDAT_SUP           (1<<5)	/* Supervisory/User Access */
-#define TSI148_LCSR_DDAT_PGM           (1<<4)	/* Program/Data Access */
-
-#define TSI148_LCSR_DDAT_AMODE_M       (0xf<<0)	/* Address Space Mask */
-#define TSI148_LCSR_DDAT_AMODE_A16      (0<<0)	/* A16 */
-#define TSI148_LCSR_DDAT_AMODE_A24      (1<<0)	/* A24 */
-#define TSI148_LCSR_DDAT_AMODE_A32      (2<<0)	/* A32 */
-#define TSI148_LCSR_DDAT_AMODE_A64      (4<<0)	/* A64 */
-#define TSI148_LCSR_DDAT_AMODE_CRCSR   (5<<0)	/* CRC/SR */
-#define TSI148_LCSR_DDAT_AMODE_USER1   (8<<0)	/* User1 */
-#define TSI148_LCSR_DDAT_AMODE_USER2   (9<<0)	/* User2 */
-#define TSI148_LCSR_DDAT_AMODE_USER3   (0xa<<0)	/* User3 */
-#define TSI148_LCSR_DDAT_AMODE_USER4   (0xb<<0)	/* User4 */
-
-/*
- *  DMA Next Link Address Lower
- */
-#define TSI148_LCSR_DNLAL_DNLAL_M      (0x3FFFFFF<<6)	/* Address Mask */
-#define TSI148_LCSR_DNLAL_LLA          (1<<0)  /* Last Link Address Indicator */
-
-/*
- *  DMA 2eSST Broadcast Select
- */
-#define TSI148_LCSR_DBS_M              (0x1FFFFF<<0)	/* Mask */
-
-/*
- *  GCSR Register Group
- */
-
-/*
- *  GCSR Control and Status Register  CRG + $604
- */
-#define TSI148_GCSR_GCTRL_LRST         (1<<15)	/* Local Reset */
-#define TSI148_GCSR_GCTRL_SFAILEN      (1<<14)	/* System Fail enable */
-#define TSI148_GCSR_GCTRL_BDFAILS      (1<<13)	/* Board Fail Status */
-#define TSI148_GCSR_GCTRL_SCON         (1<<12)	/* System Copntroller */
-#define TSI148_GCSR_GCTRL_MEN          (1<<11)	/* Module Enable (READY) */
-
-#define TSI148_GCSR_GCTRL_LMI3S        (1<<7)	/* Loc Monitor 3 Int Status */
-#define TSI148_GCSR_GCTRL_LMI2S        (1<<6)	/* Loc Monitor 2 Int Status */
-#define TSI148_GCSR_GCTRL_LMI1S        (1<<5)	/* Loc Monitor 1 Int Status */
-#define TSI148_GCSR_GCTRL_LMI0S        (1<<4)	/* Loc Monitor 0 Int Status */
-#define TSI148_GCSR_GCTRL_MBI3S        (1<<3)	/* Mail box 3 Int Status */
-#define TSI148_GCSR_GCTRL_MBI2S        (1<<2)	/* Mail box 2 Int Status */
-#define TSI148_GCSR_GCTRL_MBI1S        (1<<1)	/* Mail box 1 Int Status */
-#define TSI148_GCSR_GCTRL_MBI0S        (1<<0)	/* Mail box 0 Int Status */
-
-#define TSI148_GCSR_GAP                (1<<5)	/* Geographic Addr Parity */
-#define TSI148_GCSR_GA_M               (0x1F<<0)  /* Geographic Address Mask */
-
-/*
- *  CR/CSR Register Group
- */
-
-/*
- *  CR/CSR Bit Clear Register CRG + $FF4
- */
-#define TSI148_CRCSR_CSRBCR_LRSTC      (1<<7)	/* Local Reset Clear */
-#define TSI148_CRCSR_CSRBCR_SFAILC     (1<<6)	/* System Fail Enable Clear */
-#define TSI148_CRCSR_CSRBCR_BDFAILS    (1<<5)	/* Board Fail Status */
-#define TSI148_CRCSR_CSRBCR_MENC       (1<<4)	/* Module Enable Clear */
-#define TSI148_CRCSR_CSRBCR_BERRSC     (1<<3)	/* Bus Error Status Clear */
-
-/*
- *  CR/CSR Bit Set Register CRG+$FF8
- */
-#define TSI148_CRCSR_CSRBSR_LISTS      (1<<7)	/* Local Reset Clear */
-#define TSI148_CRCSR_CSRBSR_SFAILS     (1<<6)	/* System Fail Enable Clear */
-#define TSI148_CRCSR_CSRBSR_BDFAILS    (1<<5)	/* Board Fail Status */
-#define TSI148_CRCSR_CSRBSR_MENS       (1<<4)	/* Module Enable Clear */
-#define TSI148_CRCSR_CSRBSR_BERRS      (1<<3)	/* Bus Error Status Clear */
-
-/*
- *  CR/CSR Base Address Register CRG + FFC
- */
-#define TSI148_CRCSR_CBAR_M            (0x1F<<3)	/* Mask */
-
-#endif				/* TSI148_H */
diff --git a/drivers/staging/vme/devices/Kconfig b/drivers/staging/vme/devices/Kconfig
index 55ec30c..d0cab17 100644
--- a/drivers/staging/vme/devices/Kconfig
+++ b/drivers/staging/vme/devices/Kconfig
@@ -2,6 +2,7 @@
 
 config VME_USER
 	tristate "VME user space access driver"
+	depends on STAGING
 	help
 	  If you say Y here you want to be able to access a limited number of
 	  VME windows in a manner at least semi-compatible with the interface
@@ -9,7 +10,7 @@
 
 config VME_PIO2
 	tristate "GE PIO2 VME"
-	depends on GPIOLIB
+	depends on STAGING && GPIOLIB
 	help
 	  Say Y here to include support for the GE PIO2. The PIO2 is a 6U VME
 	  slave card, implementing 32 solid-state relay switched IO lines, in
diff --git a/drivers/staging/vme/devices/vme_pio2_cntr.c b/drivers/staging/vme/devices/vme_pio2_cntr.c
index 08e0d59..6335471 100644
--- a/drivers/staging/vme/devices/vme_pio2_cntr.c
+++ b/drivers/staging/vme/devices/vme_pio2_cntr.c
@@ -17,8 +17,8 @@
 #include <linux/device.h>
 #include <linux/types.h>
 #include <linux/gpio.h>
+#include <linux/vme.h>
 
-#include "../vme.h"
 #include "vme_pio2.h"
 
 static int pio2_cntr_irq_set(struct pio2_card *card, int id)
diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c
index 573c800..4bf8e05 100644
--- a/drivers/staging/vme/devices/vme_pio2_core.c
+++ b/drivers/staging/vme/devices/vme_pio2_core.c
@@ -10,7 +10,6 @@
  * option) any later version.
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -20,8 +19,8 @@
 #include <linux/ctype.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
+#include <linux/vme.h>
 
-#include "../vme.h"
 #include "vme_pio2.h"
 
 
diff --git a/drivers/staging/vme/devices/vme_pio2_gpio.c b/drivers/staging/vme/devices/vme_pio2_gpio.c
index 8584849..ad76a47 100644
--- a/drivers/staging/vme/devices/vme_pio2_gpio.c
+++ b/drivers/staging/vme/devices/vme_pio2_gpio.c
@@ -10,7 +10,6 @@
  * option) any later version.
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -21,8 +20,8 @@
 #include <linux/ctype.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
+#include <linux/vme.h>
 
-#include "../vme.h"
 #include "vme_pio2.h"
 
 static const char driver_name[] = "pio2_gpio";
@@ -79,7 +78,7 @@
 	if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) |
 		(card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
 
-		dev_err(&card->vdev->dev, "Channel not availabe as output\n");
+		dev_err(&card->vdev->dev, "Channel not available as output\n");
 		return;
 	}
 
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index 7dcd162..e24a6f9 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -27,7 +27,7 @@
 #include <linux/module.h>
 #include <linux/pagemap.h>
 #include <linux/pci.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/syscalls.h>
@@ -36,8 +36,8 @@
 
 #include <linux/io.h>
 #include <linux/uaccess.h>
+#include <linux/vme.h>
 
-#include "../vme.h"
 #include "vme_user.h"
 
 static DEFINE_MUTEX(vme_user_mutex);
@@ -95,7 +95,7 @@
 	void *kern_buf;	/* Buffer address in kernel space */
 	dma_addr_t pci_buf;	/* Buffer address in PCI address space */
 	unsigned long long size_buf;	/* Buffer size */
-	struct semaphore sem;	/* Semaphore for locking image */
+	struct mutex mutex;	/* Mutex for locking image */
 	struct device *device;	/* Sysfs device */
 	struct vme_resource *resource;	/* VME resource */
 	int users;		/* Number of current users */
@@ -168,7 +168,7 @@
 	int err;
 	unsigned int minor = MINOR(inode->i_rdev);
 
-	down(&image[minor].sem);
+	mutex_lock(&image[minor].mutex);
 	/* Allow device to be opened if a resource is needed and allocated. */
 	if (minor < CONTROL_MINOR && image[minor].resource == NULL) {
 		printk(KERN_ERR "No resources allocated for device\n");
@@ -179,12 +179,12 @@
 	/* Increment user count */
 	image[minor].users++;
 
-	up(&image[minor].sem);
+	mutex_unlock(&image[minor].mutex);
 
 	return 0;
 
 err_res:
-	up(&image[minor].sem);
+	mutex_unlock(&image[minor].mutex);
 
 	return err;
 }
@@ -193,12 +193,12 @@
 {
 	unsigned int minor = MINOR(inode->i_rdev);
 
-	down(&image[minor].sem);
+	mutex_lock(&image[minor].mutex);
 
 	/* Decrement user count */
 	image[minor].users--;
 
-	up(&image[minor].sem);
+	mutex_unlock(&image[minor].mutex);
 
 	return 0;
 }
@@ -325,14 +325,14 @@
 	if (minor == CONTROL_MINOR)
 		return 0;
 
-	down(&image[minor].sem);
+	mutex_lock(&image[minor].mutex);
 
 	/* XXX Do we *really* want this helper - we can use vme_*_get ? */
 	image_size = vme_get_size(image[minor].resource);
 
 	/* Ensure we are starting at a valid location */
 	if ((*ppos < 0) || (*ppos > (image_size - 1))) {
-		up(&image[minor].sem);
+		mutex_unlock(&image[minor].mutex);
 		return 0;
 	}
 
@@ -353,8 +353,7 @@
 		retval = -EINVAL;
 	}
 
-	up(&image[minor].sem);
-
+	mutex_unlock(&image[minor].mutex);
 	if (retval > 0)
 		*ppos += retval;
 
@@ -372,13 +371,13 @@
 	if (minor == CONTROL_MINOR)
 		return 0;
 
-	down(&image[minor].sem);
+	mutex_lock(&image[minor].mutex);
 
 	image_size = vme_get_size(image[minor].resource);
 
 	/* Ensure we are starting at a valid location */
 	if ((*ppos < 0) || (*ppos > (image_size - 1))) {
-		up(&image[minor].sem);
+		mutex_unlock(&image[minor].mutex);
 		return 0;
 	}
 
@@ -398,8 +397,8 @@
 	default:
 		retval = -EINVAL;
 	}
-
-	up(&image[minor].sem);
+	
+	mutex_unlock(&image[minor].mutex);
 
 	if (retval > 0)
 		*ppos += retval;
@@ -416,7 +415,7 @@
 	if (minor == CONTROL_MINOR)
 		return -EINVAL;
 
-	down(&image[minor].sem);
+	mutex_lock(&image[minor].mutex);
 	image_size = vme_get_size(image[minor].resource);
 
 	switch (whence) {
@@ -430,19 +429,19 @@
 		absolute = image_size + off;
 		break;
 	default:
-		up(&image[minor].sem);
+		mutex_unlock(&image[minor].mutex);
 		return -EINVAL;
 		break;
 	}
 
 	if ((absolute < 0) || (absolute >= image_size)) {
-		up(&image[minor].sem);
+		mutex_unlock(&image[minor].mutex);
 		return -EINVAL;
 	}
 
 	file->f_pos = absolute;
 
-	up(&image[minor].sem);
+	mutex_unlock(&image[minor].mutex);
 
 	return absolute;
 }
@@ -696,7 +695,7 @@
 	for (i = 0; i < VME_DEVS; i++) {
 		image[i].kern_buf = NULL;
 		image[i].pci_buf = 0;
-		sema_init(&image[i].sem, 1);
+		mutex_init(&image[i].mutex);
 		image[i].device = NULL;
 		image[i].resource = NULL;
 		image[i].users = 0;
@@ -858,8 +857,10 @@
 	int i;
 
 	/* Remove sysfs Entries */
-	for (i = 0; i < VME_DEVS; i++)
+	for (i = 0; i < VME_DEVS; i++) {
+		mutex_destroy(&image[i].mutex);
 		device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
+	}
 	class_destroy(vme_user_sysfs_class);
 
 	for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) {
diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c
deleted file mode 100644
index 70722ae..0000000
--- a/drivers/staging/vme/vme.c
+++ /dev/null
@@ -1,1526 +0,0 @@
-/*
- * VME Bridge Framework
- *
- * Author: Martyn Welch <martyn.welch@ge.com>
- * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
- *
- * Based on work by Tom Armistead and Ajit Prem
- * Copyright 2004 Motorola Inc.
- *
- * 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/mm.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/poll.h>
-#include <linux/highmem.h>
-#include <linux/interrupt.h>
-#include <linux/pagemap.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/syscalls.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-
-#include "vme.h"
-#include "vme_bridge.h"
-
-/* Bitmask and list of registered buses both protected by common mutex */
-static unsigned int vme_bus_numbers;
-static LIST_HEAD(vme_bus_list);
-static DEFINE_MUTEX(vme_buses_lock);
-
-static void __exit vme_exit(void);
-static int __init vme_init(void);
-
-static struct vme_dev *dev_to_vme_dev(struct device *dev)
-{
-	return container_of(dev, struct vme_dev, dev);
-}
-
-/*
- * Find the bridge that the resource is associated with.
- */
-static struct vme_bridge *find_bridge(struct vme_resource *resource)
-{
-	/* Get list to search */
-	switch (resource->type) {
-	case VME_MASTER:
-		return list_entry(resource->entry, struct vme_master_resource,
-			list)->parent;
-		break;
-	case VME_SLAVE:
-		return list_entry(resource->entry, struct vme_slave_resource,
-			list)->parent;
-		break;
-	case VME_DMA:
-		return list_entry(resource->entry, struct vme_dma_resource,
-			list)->parent;
-		break;
-	case VME_LM:
-		return list_entry(resource->entry, struct vme_lm_resource,
-			list)->parent;
-		break;
-	default:
-		printk(KERN_ERR "Unknown resource type\n");
-		return NULL;
-		break;
-	}
-}
-
-/*
- * Allocate a contiguous block of memory for use by the driver. This is used to
- * create the buffers for the slave windows.
- */
-void *vme_alloc_consistent(struct vme_resource *resource, size_t size,
-	dma_addr_t *dma)
-{
-	struct vme_bridge *bridge;
-
-	if (resource == NULL) {
-		printk(KERN_ERR "No resource\n");
-		return NULL;
-	}
-
-	bridge = find_bridge(resource);
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find bridge\n");
-		return NULL;
-	}
-
-	if (bridge->parent == NULL) {
-		printk(KERN_ERR "Dev entry NULL for"
-			" bridge %s\n", bridge->name);
-		return NULL;
-	}
-
-	if (bridge->alloc_consistent == NULL) {
-		printk(KERN_ERR "alloc_consistent not supported by"
-			" bridge %s\n", bridge->name);
-		return NULL;
-	}
-
-	return bridge->alloc_consistent(bridge->parent, size, dma);
-}
-EXPORT_SYMBOL(vme_alloc_consistent);
-
-/*
- * Free previously allocated contiguous block of memory.
- */
-void vme_free_consistent(struct vme_resource *resource, size_t size,
-	void *vaddr, dma_addr_t dma)
-{
-	struct vme_bridge *bridge;
-
-	if (resource == NULL) {
-		printk(KERN_ERR "No resource\n");
-		return;
-	}
-
-	bridge = find_bridge(resource);
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find bridge\n");
-		return;
-	}
-
-	if (bridge->parent == NULL) {
-		printk(KERN_ERR "Dev entry NULL for"
-			" bridge %s\n", bridge->name);
-		return;
-	}
-
-	if (bridge->free_consistent == NULL) {
-		printk(KERN_ERR "free_consistent not supported by"
-			" bridge %s\n", bridge->name);
-		return;
-	}
-
-	bridge->free_consistent(bridge->parent, size, vaddr, dma);
-}
-EXPORT_SYMBOL(vme_free_consistent);
-
-size_t vme_get_size(struct vme_resource *resource)
-{
-	int enabled, retval;
-	unsigned long long base, size;
-	dma_addr_t buf_base;
-	u32 aspace, cycle, dwidth;
-
-	switch (resource->type) {
-	case VME_MASTER:
-		retval = vme_master_get(resource, &enabled, &base, &size,
-			&aspace, &cycle, &dwidth);
-
-		return size;
-		break;
-	case VME_SLAVE:
-		retval = vme_slave_get(resource, &enabled, &base, &size,
-			&buf_base, &aspace, &cycle);
-
-		return size;
-		break;
-	case VME_DMA:
-		return 0;
-		break;
-	default:
-		printk(KERN_ERR "Unknown resource type\n");
-		return 0;
-		break;
-	}
-}
-EXPORT_SYMBOL(vme_get_size);
-
-static int vme_check_window(u32 aspace, unsigned long long vme_base,
-	unsigned long long size)
-{
-	int retval = 0;
-
-	switch (aspace) {
-	case VME_A16:
-		if (((vme_base + size) > VME_A16_MAX) ||
-				(vme_base > VME_A16_MAX))
-			retval = -EFAULT;
-		break;
-	case VME_A24:
-		if (((vme_base + size) > VME_A24_MAX) ||
-				(vme_base > VME_A24_MAX))
-			retval = -EFAULT;
-		break;
-	case VME_A32:
-		if (((vme_base + size) > VME_A32_MAX) ||
-				(vme_base > VME_A32_MAX))
-			retval = -EFAULT;
-		break;
-	case VME_A64:
-		/*
-		 * Any value held in an unsigned long long can be used as the
-		 * base
-		 */
-		break;
-	case VME_CRCSR:
-		if (((vme_base + size) > VME_CRCSR_MAX) ||
-				(vme_base > VME_CRCSR_MAX))
-			retval = -EFAULT;
-		break;
-	case VME_USER1:
-	case VME_USER2:
-	case VME_USER3:
-	case VME_USER4:
-		/* User Defined */
-		break;
-	default:
-		printk(KERN_ERR "Invalid address space\n");
-		retval = -EINVAL;
-		break;
-	}
-
-	return retval;
-}
-
-/*
- * Request a slave image with specific attributes, return some unique
- * identifier.
- */
-struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address,
-	u32 cycle)
-{
-	struct vme_bridge *bridge;
-	struct list_head *slave_pos = NULL;
-	struct vme_slave_resource *allocated_image = NULL;
-	struct vme_slave_resource *slave_image = NULL;
-	struct vme_resource *resource = NULL;
-
-	bridge = vdev->bridge;
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find VME bus\n");
-		goto err_bus;
-	}
-
-	/* Loop through slave resources */
-	list_for_each(slave_pos, &bridge->slave_resources) {
-		slave_image = list_entry(slave_pos,
-			struct vme_slave_resource, list);
-
-		if (slave_image == NULL) {
-			printk(KERN_ERR "Registered NULL Slave resource\n");
-			continue;
-		}
-
-		/* Find an unlocked and compatible image */
-		mutex_lock(&slave_image->mtx);
-		if (((slave_image->address_attr & address) == address) &&
-			((slave_image->cycle_attr & cycle) == cycle) &&
-			(slave_image->locked == 0)) {
-
-			slave_image->locked = 1;
-			mutex_unlock(&slave_image->mtx);
-			allocated_image = slave_image;
-			break;
-		}
-		mutex_unlock(&slave_image->mtx);
-	}
-
-	/* No free image */
-	if (allocated_image == NULL)
-		goto err_image;
-
-	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
-	if (resource == NULL) {
-		printk(KERN_WARNING "Unable to allocate resource structure\n");
-		goto err_alloc;
-	}
-	resource->type = VME_SLAVE;
-	resource->entry = &allocated_image->list;
-
-	return resource;
-
-err_alloc:
-	/* Unlock image */
-	mutex_lock(&slave_image->mtx);
-	slave_image->locked = 0;
-	mutex_unlock(&slave_image->mtx);
-err_image:
-err_bus:
-	return NULL;
-}
-EXPORT_SYMBOL(vme_slave_request);
-
-int vme_slave_set(struct vme_resource *resource, int enabled,
-	unsigned long long vme_base, unsigned long long size,
-	dma_addr_t buf_base, u32 aspace, u32 cycle)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_slave_resource *image;
-	int retval;
-
-	if (resource->type != VME_SLAVE) {
-		printk(KERN_ERR "Not a slave resource\n");
-		return -EINVAL;
-	}
-
-	image = list_entry(resource->entry, struct vme_slave_resource, list);
-
-	if (bridge->slave_set == NULL) {
-		printk(KERN_ERR "Function not supported\n");
-		return -ENOSYS;
-	}
-
-	if (!(((image->address_attr & aspace) == aspace) &&
-		((image->cycle_attr & cycle) == cycle))) {
-		printk(KERN_ERR "Invalid attributes\n");
-		return -EINVAL;
-	}
-
-	retval = vme_check_window(aspace, vme_base, size);
-	if (retval)
-		return retval;
-
-	return bridge->slave_set(image, enabled, vme_base, size, buf_base,
-		aspace, cycle);
-}
-EXPORT_SYMBOL(vme_slave_set);
-
-int vme_slave_get(struct vme_resource *resource, int *enabled,
-	unsigned long long *vme_base, unsigned long long *size,
-	dma_addr_t *buf_base, u32 *aspace, u32 *cycle)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_slave_resource *image;
-
-	if (resource->type != VME_SLAVE) {
-		printk(KERN_ERR "Not a slave resource\n");
-		return -EINVAL;
-	}
-
-	image = list_entry(resource->entry, struct vme_slave_resource, list);
-
-	if (bridge->slave_get == NULL) {
-		printk(KERN_ERR "vme_slave_get not supported\n");
-		return -EINVAL;
-	}
-
-	return bridge->slave_get(image, enabled, vme_base, size, buf_base,
-		aspace, cycle);
-}
-EXPORT_SYMBOL(vme_slave_get);
-
-void vme_slave_free(struct vme_resource *resource)
-{
-	struct vme_slave_resource *slave_image;
-
-	if (resource->type != VME_SLAVE) {
-		printk(KERN_ERR "Not a slave resource\n");
-		return;
-	}
-
-	slave_image = list_entry(resource->entry, struct vme_slave_resource,
-		list);
-	if (slave_image == NULL) {
-		printk(KERN_ERR "Can't find slave resource\n");
-		return;
-	}
-
-	/* Unlock image */
-	mutex_lock(&slave_image->mtx);
-	if (slave_image->locked == 0)
-		printk(KERN_ERR "Image is already free\n");
-
-	slave_image->locked = 0;
-	mutex_unlock(&slave_image->mtx);
-
-	/* Free up resource memory */
-	kfree(resource);
-}
-EXPORT_SYMBOL(vme_slave_free);
-
-/*
- * Request a master image with specific attributes, return some unique
- * identifier.
- */
-struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address,
-	u32 cycle, u32 dwidth)
-{
-	struct vme_bridge *bridge;
-	struct list_head *master_pos = NULL;
-	struct vme_master_resource *allocated_image = NULL;
-	struct vme_master_resource *master_image = NULL;
-	struct vme_resource *resource = NULL;
-
-	bridge = vdev->bridge;
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find VME bus\n");
-		goto err_bus;
-	}
-
-	/* Loop through master resources */
-	list_for_each(master_pos, &bridge->master_resources) {
-		master_image = list_entry(master_pos,
-			struct vme_master_resource, list);
-
-		if (master_image == NULL) {
-			printk(KERN_WARNING "Registered NULL master resource\n");
-			continue;
-		}
-
-		/* Find an unlocked and compatible image */
-		spin_lock(&master_image->lock);
-		if (((master_image->address_attr & address) == address) &&
-			((master_image->cycle_attr & cycle) == cycle) &&
-			((master_image->width_attr & dwidth) == dwidth) &&
-			(master_image->locked == 0)) {
-
-			master_image->locked = 1;
-			spin_unlock(&master_image->lock);
-			allocated_image = master_image;
-			break;
-		}
-		spin_unlock(&master_image->lock);
-	}
-
-	/* Check to see if we found a resource */
-	if (allocated_image == NULL) {
-		printk(KERN_ERR "Can't find a suitable resource\n");
-		goto err_image;
-	}
-
-	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
-	if (resource == NULL) {
-		printk(KERN_ERR "Unable to allocate resource structure\n");
-		goto err_alloc;
-	}
-	resource->type = VME_MASTER;
-	resource->entry = &allocated_image->list;
-
-	return resource;
-
-err_alloc:
-	/* Unlock image */
-	spin_lock(&master_image->lock);
-	master_image->locked = 0;
-	spin_unlock(&master_image->lock);
-err_image:
-err_bus:
-	return NULL;
-}
-EXPORT_SYMBOL(vme_master_request);
-
-int vme_master_set(struct vme_resource *resource, int enabled,
-	unsigned long long vme_base, unsigned long long size, u32 aspace,
-	u32 cycle, u32 dwidth)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_master_resource *image;
-	int retval;
-
-	if (resource->type != VME_MASTER) {
-		printk(KERN_ERR "Not a master resource\n");
-		return -EINVAL;
-	}
-
-	image = list_entry(resource->entry, struct vme_master_resource, list);
-
-	if (bridge->master_set == NULL) {
-		printk(KERN_WARNING "vme_master_set not supported\n");
-		return -EINVAL;
-	}
-
-	if (!(((image->address_attr & aspace) == aspace) &&
-		((image->cycle_attr & cycle) == cycle) &&
-		((image->width_attr & dwidth) == dwidth))) {
-		printk(KERN_WARNING "Invalid attributes\n");
-		return -EINVAL;
-	}
-
-	retval = vme_check_window(aspace, vme_base, size);
-	if (retval)
-		return retval;
-
-	return bridge->master_set(image, enabled, vme_base, size, aspace,
-		cycle, dwidth);
-}
-EXPORT_SYMBOL(vme_master_set);
-
-int vme_master_get(struct vme_resource *resource, int *enabled,
-	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
-	u32 *cycle, u32 *dwidth)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_master_resource *image;
-
-	if (resource->type != VME_MASTER) {
-		printk(KERN_ERR "Not a master resource\n");
-		return -EINVAL;
-	}
-
-	image = list_entry(resource->entry, struct vme_master_resource, list);
-
-	if (bridge->master_get == NULL) {
-		printk(KERN_WARNING "vme_master_set not supported\n");
-		return -EINVAL;
-	}
-
-	return bridge->master_get(image, enabled, vme_base, size, aspace,
-		cycle, dwidth);
-}
-EXPORT_SYMBOL(vme_master_get);
-
-/*
- * Read data out of VME space into a buffer.
- */
-ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count,
-	loff_t offset)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_master_resource *image;
-	size_t length;
-
-	if (bridge->master_read == NULL) {
-		printk(KERN_WARNING "Reading from resource not supported\n");
-		return -EINVAL;
-	}
-
-	if (resource->type != VME_MASTER) {
-		printk(KERN_ERR "Not a master resource\n");
-		return -EINVAL;
-	}
-
-	image = list_entry(resource->entry, struct vme_master_resource, list);
-
-	length = vme_get_size(resource);
-
-	if (offset > length) {
-		printk(KERN_WARNING "Invalid Offset\n");
-		return -EFAULT;
-	}
-
-	if ((offset + count) > length)
-		count = length - offset;
-
-	return bridge->master_read(image, buf, count, offset);
-
-}
-EXPORT_SYMBOL(vme_master_read);
-
-/*
- * Write data out to VME space from a buffer.
- */
-ssize_t vme_master_write(struct vme_resource *resource, void *buf,
-	size_t count, loff_t offset)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_master_resource *image;
-	size_t length;
-
-	if (bridge->master_write == NULL) {
-		printk(KERN_WARNING "Writing to resource not supported\n");
-		return -EINVAL;
-	}
-
-	if (resource->type != VME_MASTER) {
-		printk(KERN_ERR "Not a master resource\n");
-		return -EINVAL;
-	}
-
-	image = list_entry(resource->entry, struct vme_master_resource, list);
-
-	length = vme_get_size(resource);
-
-	if (offset > length) {
-		printk(KERN_WARNING "Invalid Offset\n");
-		return -EFAULT;
-	}
-
-	if ((offset + count) > length)
-		count = length - offset;
-
-	return bridge->master_write(image, buf, count, offset);
-}
-EXPORT_SYMBOL(vme_master_write);
-
-/*
- * Perform RMW cycle to provided location.
- */
-unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask,
-	unsigned int compare, unsigned int swap, loff_t offset)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_master_resource *image;
-
-	if (bridge->master_rmw == NULL) {
-		printk(KERN_WARNING "Writing to resource not supported\n");
-		return -EINVAL;
-	}
-
-	if (resource->type != VME_MASTER) {
-		printk(KERN_ERR "Not a master resource\n");
-		return -EINVAL;
-	}
-
-	image = list_entry(resource->entry, struct vme_master_resource, list);
-
-	return bridge->master_rmw(image, mask, compare, swap, offset);
-}
-EXPORT_SYMBOL(vme_master_rmw);
-
-void vme_master_free(struct vme_resource *resource)
-{
-	struct vme_master_resource *master_image;
-
-	if (resource->type != VME_MASTER) {
-		printk(KERN_ERR "Not a master resource\n");
-		return;
-	}
-
-	master_image = list_entry(resource->entry, struct vme_master_resource,
-		list);
-	if (master_image == NULL) {
-		printk(KERN_ERR "Can't find master resource\n");
-		return;
-	}
-
-	/* Unlock image */
-	spin_lock(&master_image->lock);
-	if (master_image->locked == 0)
-		printk(KERN_ERR "Image is already free\n");
-
-	master_image->locked = 0;
-	spin_unlock(&master_image->lock);
-
-	/* Free up resource memory */
-	kfree(resource);
-}
-EXPORT_SYMBOL(vme_master_free);
-
-/*
- * Request a DMA controller with specific attributes, return some unique
- * identifier.
- */
-struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route)
-{
-	struct vme_bridge *bridge;
-	struct list_head *dma_pos = NULL;
-	struct vme_dma_resource *allocated_ctrlr = NULL;
-	struct vme_dma_resource *dma_ctrlr = NULL;
-	struct vme_resource *resource = NULL;
-
-	/* XXX Not checking resource attributes */
-	printk(KERN_ERR "No VME resource Attribute tests done\n");
-
-	bridge = vdev->bridge;
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find VME bus\n");
-		goto err_bus;
-	}
-
-	/* Loop through DMA resources */
-	list_for_each(dma_pos, &bridge->dma_resources) {
-		dma_ctrlr = list_entry(dma_pos,
-			struct vme_dma_resource, list);
-
-		if (dma_ctrlr == NULL) {
-			printk(KERN_ERR "Registered NULL DMA resource\n");
-			continue;
-		}
-
-		/* Find an unlocked and compatible controller */
-		mutex_lock(&dma_ctrlr->mtx);
-		if (((dma_ctrlr->route_attr & route) == route) &&
-			(dma_ctrlr->locked == 0)) {
-
-			dma_ctrlr->locked = 1;
-			mutex_unlock(&dma_ctrlr->mtx);
-			allocated_ctrlr = dma_ctrlr;
-			break;
-		}
-		mutex_unlock(&dma_ctrlr->mtx);
-	}
-
-	/* Check to see if we found a resource */
-	if (allocated_ctrlr == NULL)
-		goto err_ctrlr;
-
-	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
-	if (resource == NULL) {
-		printk(KERN_WARNING "Unable to allocate resource structure\n");
-		goto err_alloc;
-	}
-	resource->type = VME_DMA;
-	resource->entry = &allocated_ctrlr->list;
-
-	return resource;
-
-err_alloc:
-	/* Unlock image */
-	mutex_lock(&dma_ctrlr->mtx);
-	dma_ctrlr->locked = 0;
-	mutex_unlock(&dma_ctrlr->mtx);
-err_ctrlr:
-err_bus:
-	return NULL;
-}
-EXPORT_SYMBOL(vme_dma_request);
-
-/*
- * Start new list
- */
-struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
-{
-	struct vme_dma_resource *ctrlr;
-	struct vme_dma_list *dma_list;
-
-	if (resource->type != VME_DMA) {
-		printk(KERN_ERR "Not a DMA resource\n");
-		return NULL;
-	}
-
-	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
-
-	dma_list = kmalloc(sizeof(struct vme_dma_list), GFP_KERNEL);
-	if (dma_list == NULL) {
-		printk(KERN_ERR "Unable to allocate memory for new dma list\n");
-		return NULL;
-	}
-	INIT_LIST_HEAD(&dma_list->entries);
-	dma_list->parent = ctrlr;
-	mutex_init(&dma_list->mtx);
-
-	return dma_list;
-}
-EXPORT_SYMBOL(vme_new_dma_list);
-
-/*
- * Create "Pattern" type attributes
- */
-struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type)
-{
-	struct vme_dma_attr *attributes;
-	struct vme_dma_pattern *pattern_attr;
-
-	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
-	if (attributes == NULL) {
-		printk(KERN_ERR "Unable to allocate memory for attributes "
-			"structure\n");
-		goto err_attr;
-	}
-
-	pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
-	if (pattern_attr == NULL) {
-		printk(KERN_ERR "Unable to allocate memory for pattern "
-			"attributes\n");
-		goto err_pat;
-	}
-
-	attributes->type = VME_DMA_PATTERN;
-	attributes->private = (void *)pattern_attr;
-
-	pattern_attr->pattern = pattern;
-	pattern_attr->type = type;
-
-	return attributes;
-
-err_pat:
-	kfree(attributes);
-err_attr:
-	return NULL;
-}
-EXPORT_SYMBOL(vme_dma_pattern_attribute);
-
-/*
- * Create "PCI" type attributes
- */
-struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
-{
-	struct vme_dma_attr *attributes;
-	struct vme_dma_pci *pci_attr;
-
-	/* XXX Run some sanity checks here */
-
-	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
-	if (attributes == NULL) {
-		printk(KERN_ERR "Unable to allocate memory for attributes "
-			"structure\n");
-		goto err_attr;
-	}
-
-	pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
-	if (pci_attr == NULL) {
-		printk(KERN_ERR "Unable to allocate memory for pci "
-			"attributes\n");
-		goto err_pci;
-	}
-
-
-
-	attributes->type = VME_DMA_PCI;
-	attributes->private = (void *)pci_attr;
-
-	pci_attr->address = address;
-
-	return attributes;
-
-err_pci:
-	kfree(attributes);
-err_attr:
-	return NULL;
-}
-EXPORT_SYMBOL(vme_dma_pci_attribute);
-
-/*
- * Create "VME" type attributes
- */
-struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
-	u32 aspace, u32 cycle, u32 dwidth)
-{
-	struct vme_dma_attr *attributes;
-	struct vme_dma_vme *vme_attr;
-
-	attributes = kmalloc(
-		sizeof(struct vme_dma_attr), GFP_KERNEL);
-	if (attributes == NULL) {
-		printk(KERN_ERR "Unable to allocate memory for attributes "
-			"structure\n");
-		goto err_attr;
-	}
-
-	vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
-	if (vme_attr == NULL) {
-		printk(KERN_ERR "Unable to allocate memory for vme "
-			"attributes\n");
-		goto err_vme;
-	}
-
-	attributes->type = VME_DMA_VME;
-	attributes->private = (void *)vme_attr;
-
-	vme_attr->address = address;
-	vme_attr->aspace = aspace;
-	vme_attr->cycle = cycle;
-	vme_attr->dwidth = dwidth;
-
-	return attributes;
-
-err_vme:
-	kfree(attributes);
-err_attr:
-	return NULL;
-}
-EXPORT_SYMBOL(vme_dma_vme_attribute);
-
-/*
- * Free attribute
- */
-void vme_dma_free_attribute(struct vme_dma_attr *attributes)
-{
-	kfree(attributes->private);
-	kfree(attributes);
-}
-EXPORT_SYMBOL(vme_dma_free_attribute);
-
-int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
-	struct vme_dma_attr *dest, size_t count)
-{
-	struct vme_bridge *bridge = list->parent->parent;
-	int retval;
-
-	if (bridge->dma_list_add == NULL) {
-		printk(KERN_WARNING "Link List DMA generation not supported\n");
-		return -EINVAL;
-	}
-
-	if (!mutex_trylock(&list->mtx)) {
-		printk(KERN_ERR "Link List already submitted\n");
-		return -EINVAL;
-	}
-
-	retval = bridge->dma_list_add(list, src, dest, count);
-
-	mutex_unlock(&list->mtx);
-
-	return retval;
-}
-EXPORT_SYMBOL(vme_dma_list_add);
-
-int vme_dma_list_exec(struct vme_dma_list *list)
-{
-	struct vme_bridge *bridge = list->parent->parent;
-	int retval;
-
-	if (bridge->dma_list_exec == NULL) {
-		printk(KERN_ERR "Link List DMA execution not supported\n");
-		return -EINVAL;
-	}
-
-	mutex_lock(&list->mtx);
-
-	retval = bridge->dma_list_exec(list);
-
-	mutex_unlock(&list->mtx);
-
-	return retval;
-}
-EXPORT_SYMBOL(vme_dma_list_exec);
-
-int vme_dma_list_free(struct vme_dma_list *list)
-{
-	struct vme_bridge *bridge = list->parent->parent;
-	int retval;
-
-	if (bridge->dma_list_empty == NULL) {
-		printk(KERN_WARNING "Emptying of Link Lists not supported\n");
-		return -EINVAL;
-	}
-
-	if (!mutex_trylock(&list->mtx)) {
-		printk(KERN_ERR "Link List in use\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * Empty out all of the entries from the dma list. We need to go to the
-	 * low level driver as dma entries are driver specific.
-	 */
-	retval = bridge->dma_list_empty(list);
-	if (retval) {
-		printk(KERN_ERR "Unable to empty link-list entries\n");
-		mutex_unlock(&list->mtx);
-		return retval;
-	}
-	mutex_unlock(&list->mtx);
-	kfree(list);
-
-	return retval;
-}
-EXPORT_SYMBOL(vme_dma_list_free);
-
-int vme_dma_free(struct vme_resource *resource)
-{
-	struct vme_dma_resource *ctrlr;
-
-	if (resource->type != VME_DMA) {
-		printk(KERN_ERR "Not a DMA resource\n");
-		return -EINVAL;
-	}
-
-	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
-
-	if (!mutex_trylock(&ctrlr->mtx)) {
-		printk(KERN_ERR "Resource busy, can't free\n");
-		return -EBUSY;
-	}
-
-	if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) {
-		printk(KERN_WARNING "Resource still processing transfers\n");
-		mutex_unlock(&ctrlr->mtx);
-		return -EBUSY;
-	}
-
-	ctrlr->locked = 0;
-
-	mutex_unlock(&ctrlr->mtx);
-
-	return 0;
-}
-EXPORT_SYMBOL(vme_dma_free);
-
-void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
-{
-	void (*call)(int, int, void *);
-	void *priv_data;
-
-	call = bridge->irq[level - 1].callback[statid].func;
-	priv_data = bridge->irq[level - 1].callback[statid].priv_data;
-
-	if (call != NULL)
-		call(level, statid, priv_data);
-	else
-		printk(KERN_WARNING "Spurilous VME interrupt, level:%x, "
-			"vector:%x\n", level, statid);
-}
-EXPORT_SYMBOL(vme_irq_handler);
-
-int vme_irq_request(struct vme_dev *vdev, int level, int statid,
-	void (*callback)(int, int, void *),
-	void *priv_data)
-{
-	struct vme_bridge *bridge;
-
-	bridge = vdev->bridge;
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find VME bus\n");
-		return -EINVAL;
-	}
-
-	if ((level < 1) || (level > 7)) {
-		printk(KERN_ERR "Invalid interrupt level\n");
-		return -EINVAL;
-	}
-
-	if (bridge->irq_set == NULL) {
-		printk(KERN_ERR "Configuring interrupts not supported\n");
-		return -EINVAL;
-	}
-
-	mutex_lock(&bridge->irq_mtx);
-
-	if (bridge->irq[level - 1].callback[statid].func) {
-		mutex_unlock(&bridge->irq_mtx);
-		printk(KERN_WARNING "VME Interrupt already taken\n");
-		return -EBUSY;
-	}
-
-	bridge->irq[level - 1].count++;
-	bridge->irq[level - 1].callback[statid].priv_data = priv_data;
-	bridge->irq[level - 1].callback[statid].func = callback;
-
-	/* Enable IRQ level */
-	bridge->irq_set(bridge, level, 1, 1);
-
-	mutex_unlock(&bridge->irq_mtx);
-
-	return 0;
-}
-EXPORT_SYMBOL(vme_irq_request);
-
-void vme_irq_free(struct vme_dev *vdev, int level, int statid)
-{
-	struct vme_bridge *bridge;
-
-	bridge = vdev->bridge;
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find VME bus\n");
-		return;
-	}
-
-	if ((level < 1) || (level > 7)) {
-		printk(KERN_ERR "Invalid interrupt level\n");
-		return;
-	}
-
-	if (bridge->irq_set == NULL) {
-		printk(KERN_ERR "Configuring interrupts not supported\n");
-		return;
-	}
-
-	mutex_lock(&bridge->irq_mtx);
-
-	bridge->irq[level - 1].count--;
-
-	/* Disable IRQ level if no more interrupts attached at this level*/
-	if (bridge->irq[level - 1].count == 0)
-		bridge->irq_set(bridge, level, 0, 1);
-
-	bridge->irq[level - 1].callback[statid].func = NULL;
-	bridge->irq[level - 1].callback[statid].priv_data = NULL;
-
-	mutex_unlock(&bridge->irq_mtx);
-}
-EXPORT_SYMBOL(vme_irq_free);
-
-int vme_irq_generate(struct vme_dev *vdev, int level, int statid)
-{
-	struct vme_bridge *bridge;
-
-	bridge = vdev->bridge;
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find VME bus\n");
-		return -EINVAL;
-	}
-
-	if ((level < 1) || (level > 7)) {
-		printk(KERN_WARNING "Invalid interrupt level\n");
-		return -EINVAL;
-	}
-
-	if (bridge->irq_generate == NULL) {
-		printk(KERN_WARNING "Interrupt generation not supported\n");
-		return -EINVAL;
-	}
-
-	return bridge->irq_generate(bridge, level, statid);
-}
-EXPORT_SYMBOL(vme_irq_generate);
-
-/*
- * Request the location monitor, return resource or NULL
- */
-struct vme_resource *vme_lm_request(struct vme_dev *vdev)
-{
-	struct vme_bridge *bridge;
-	struct list_head *lm_pos = NULL;
-	struct vme_lm_resource *allocated_lm = NULL;
-	struct vme_lm_resource *lm = NULL;
-	struct vme_resource *resource = NULL;
-
-	bridge = vdev->bridge;
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find VME bus\n");
-		goto err_bus;
-	}
-
-	/* Loop through DMA resources */
-	list_for_each(lm_pos, &bridge->lm_resources) {
-		lm = list_entry(lm_pos,
-			struct vme_lm_resource, list);
-
-		if (lm == NULL) {
-			printk(KERN_ERR "Registered NULL Location Monitor "
-				"resource\n");
-			continue;
-		}
-
-		/* Find an unlocked controller */
-		mutex_lock(&lm->mtx);
-		if (lm->locked == 0) {
-			lm->locked = 1;
-			mutex_unlock(&lm->mtx);
-			allocated_lm = lm;
-			break;
-		}
-		mutex_unlock(&lm->mtx);
-	}
-
-	/* Check to see if we found a resource */
-	if (allocated_lm == NULL)
-		goto err_lm;
-
-	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
-	if (resource == NULL) {
-		printk(KERN_ERR "Unable to allocate resource structure\n");
-		goto err_alloc;
-	}
-	resource->type = VME_LM;
-	resource->entry = &allocated_lm->list;
-
-	return resource;
-
-err_alloc:
-	/* Unlock image */
-	mutex_lock(&lm->mtx);
-	lm->locked = 0;
-	mutex_unlock(&lm->mtx);
-err_lm:
-err_bus:
-	return NULL;
-}
-EXPORT_SYMBOL(vme_lm_request);
-
-int vme_lm_count(struct vme_resource *resource)
-{
-	struct vme_lm_resource *lm;
-
-	if (resource->type != VME_LM) {
-		printk(KERN_ERR "Not a Location Monitor resource\n");
-		return -EINVAL;
-	}
-
-	lm = list_entry(resource->entry, struct vme_lm_resource, list);
-
-	return lm->monitors;
-}
-EXPORT_SYMBOL(vme_lm_count);
-
-int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
-	u32 aspace, u32 cycle)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_lm_resource *lm;
-
-	if (resource->type != VME_LM) {
-		printk(KERN_ERR "Not a Location Monitor resource\n");
-		return -EINVAL;
-	}
-
-	lm = list_entry(resource->entry, struct vme_lm_resource, list);
-
-	if (bridge->lm_set == NULL) {
-		printk(KERN_ERR "vme_lm_set not supported\n");
-		return -EINVAL;
-	}
-
-	return bridge->lm_set(lm, lm_base, aspace, cycle);
-}
-EXPORT_SYMBOL(vme_lm_set);
-
-int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
-	u32 *aspace, u32 *cycle)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_lm_resource *lm;
-
-	if (resource->type != VME_LM) {
-		printk(KERN_ERR "Not a Location Monitor resource\n");
-		return -EINVAL;
-	}
-
-	lm = list_entry(resource->entry, struct vme_lm_resource, list);
-
-	if (bridge->lm_get == NULL) {
-		printk(KERN_ERR "vme_lm_get not supported\n");
-		return -EINVAL;
-	}
-
-	return bridge->lm_get(lm, lm_base, aspace, cycle);
-}
-EXPORT_SYMBOL(vme_lm_get);
-
-int vme_lm_attach(struct vme_resource *resource, int monitor,
-	void (*callback)(int))
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_lm_resource *lm;
-
-	if (resource->type != VME_LM) {
-		printk(KERN_ERR "Not a Location Monitor resource\n");
-		return -EINVAL;
-	}
-
-	lm = list_entry(resource->entry, struct vme_lm_resource, list);
-
-	if (bridge->lm_attach == NULL) {
-		printk(KERN_ERR "vme_lm_attach not supported\n");
-		return -EINVAL;
-	}
-
-	return bridge->lm_attach(lm, monitor, callback);
-}
-EXPORT_SYMBOL(vme_lm_attach);
-
-int vme_lm_detach(struct vme_resource *resource, int monitor)
-{
-	struct vme_bridge *bridge = find_bridge(resource);
-	struct vme_lm_resource *lm;
-
-	if (resource->type != VME_LM) {
-		printk(KERN_ERR "Not a Location Monitor resource\n");
-		return -EINVAL;
-	}
-
-	lm = list_entry(resource->entry, struct vme_lm_resource, list);
-
-	if (bridge->lm_detach == NULL) {
-		printk(KERN_ERR "vme_lm_detach not supported\n");
-		return -EINVAL;
-	}
-
-	return bridge->lm_detach(lm, monitor);
-}
-EXPORT_SYMBOL(vme_lm_detach);
-
-void vme_lm_free(struct vme_resource *resource)
-{
-	struct vme_lm_resource *lm;
-
-	if (resource->type != VME_LM) {
-		printk(KERN_ERR "Not a Location Monitor resource\n");
-		return;
-	}
-
-	lm = list_entry(resource->entry, struct vme_lm_resource, list);
-
-	mutex_lock(&lm->mtx);
-
-	/* XXX
-	 * Check to see that there aren't any callbacks still attached, if
-	 * there are we should probably be detaching them!
-	 */
-
-	lm->locked = 0;
-
-	mutex_unlock(&lm->mtx);
-
-	kfree(resource);
-}
-EXPORT_SYMBOL(vme_lm_free);
-
-int vme_slot_get(struct vme_dev *vdev)
-{
-	struct vme_bridge *bridge;
-
-	bridge = vdev->bridge;
-	if (bridge == NULL) {
-		printk(KERN_ERR "Can't find VME bus\n");
-		return -EINVAL;
-	}
-
-	if (bridge->slot_get == NULL) {
-		printk(KERN_WARNING "vme_slot_get not supported\n");
-		return -EINVAL;
-	}
-
-	return bridge->slot_get(bridge);
-}
-EXPORT_SYMBOL(vme_slot_get);
-
-
-/* - Bridge Registration --------------------------------------------------- */
-
-static void vme_dev_release(struct device *dev)
-{
-	kfree(dev_to_vme_dev(dev));
-}
-
-int vme_register_bridge(struct vme_bridge *bridge)
-{
-	int i;
-	int ret = -1;
-
-	mutex_lock(&vme_buses_lock);
-	for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
-		if ((vme_bus_numbers & (1 << i)) == 0) {
-			vme_bus_numbers |= (1 << i);
-			bridge->num = i;
-			INIT_LIST_HEAD(&bridge->devices);
-			list_add_tail(&bridge->bus_list, &vme_bus_list);
-			ret = 0;
-			break;
-		}
-	}
-	mutex_unlock(&vme_buses_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(vme_register_bridge);
-
-void vme_unregister_bridge(struct vme_bridge *bridge)
-{
-	struct vme_dev *vdev;
-	struct vme_dev *tmp;
-
-	mutex_lock(&vme_buses_lock);
-	vme_bus_numbers &= ~(1 << bridge->num);
-	list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) {
-		list_del(&vdev->drv_list);
-		list_del(&vdev->bridge_list);
-		device_unregister(&vdev->dev);
-	}
-	list_del(&bridge->bus_list);
-	mutex_unlock(&vme_buses_lock);
-}
-EXPORT_SYMBOL(vme_unregister_bridge);
-
-/* - Driver Registration --------------------------------------------------- */
-
-static int __vme_register_driver_bus(struct vme_driver *drv,
-	struct vme_bridge *bridge, unsigned int ndevs)
-{
-	int err;
-	unsigned int i;
-	struct vme_dev *vdev;
-	struct vme_dev *tmp;
-
-	for (i = 0; i < ndevs; i++) {
-		vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL);
-		if (!vdev) {
-			err = -ENOMEM;
-			goto err_devalloc;
-		}
-		vdev->num = i;
-		vdev->bridge = bridge;
-		vdev->dev.platform_data = drv;
-		vdev->dev.release = vme_dev_release;
-		vdev->dev.parent = bridge->parent;
-		vdev->dev.bus = &vme_bus_type;
-		dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num,
-			vdev->num);
-
-		err = device_register(&vdev->dev);
-		if (err)
-			goto err_reg;
-
-		if (vdev->dev.platform_data) {
-			list_add_tail(&vdev->drv_list, &drv->devices);
-			list_add_tail(&vdev->bridge_list, &bridge->devices);
-		} else
-			device_unregister(&vdev->dev);
-	}
-	return 0;
-
-err_reg:
-	kfree(vdev);
-err_devalloc:
-	list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) {
-		list_del(&vdev->drv_list);
-		list_del(&vdev->bridge_list);
-		device_unregister(&vdev->dev);
-	}
-	return err;
-}
-
-static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
-{
-	struct vme_bridge *bridge;
-	int err = 0;
-
-	mutex_lock(&vme_buses_lock);
-	list_for_each_entry(bridge, &vme_bus_list, bus_list) {
-		/*
-		 * This cannot cause trouble as we already have vme_buses_lock
-		 * and if the bridge is removed, it will have to go through
-		 * vme_unregister_bridge() to do it (which calls remove() on
-		 * the bridge which in turn tries to acquire vme_buses_lock and
-		 * will have to wait).
-		 */
-		err = __vme_register_driver_bus(drv, bridge, ndevs);
-		if (err)
-			break;
-	}
-	mutex_unlock(&vme_buses_lock);
-	return err;
-}
-
-int vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
-{
-	int err;
-
-	drv->driver.name = drv->name;
-	drv->driver.bus = &vme_bus_type;
-	INIT_LIST_HEAD(&drv->devices);
-
-	err = driver_register(&drv->driver);
-	if (err)
-		return err;
-
-	err = __vme_register_driver(drv, ndevs);
-	if (err)
-		driver_unregister(&drv->driver);
-
-	return err;
-}
-EXPORT_SYMBOL(vme_register_driver);
-
-void vme_unregister_driver(struct vme_driver *drv)
-{
-	struct vme_dev *dev, *dev_tmp;
-
-	mutex_lock(&vme_buses_lock);
-	list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) {
-		list_del(&dev->drv_list);
-		list_del(&dev->bridge_list);
-		device_unregister(&dev->dev);
-	}
-	mutex_unlock(&vme_buses_lock);
-
-	driver_unregister(&drv->driver);
-}
-EXPORT_SYMBOL(vme_unregister_driver);
-
-/* - Bus Registration ------------------------------------------------------ */
-
-static int vme_bus_match(struct device *dev, struct device_driver *drv)
-{
-	struct vme_driver *vme_drv;
-
-	vme_drv = container_of(drv, struct vme_driver, driver);
-
-	if (dev->platform_data == vme_drv) {
-		struct vme_dev *vdev = dev_to_vme_dev(dev);
-
-		if (vme_drv->match && vme_drv->match(vdev))
-			return 1;
-
-		dev->platform_data = NULL;
-	}
-	return 0;
-}
-
-static int vme_bus_probe(struct device *dev)
-{
-	int retval = -ENODEV;
-	struct vme_driver *driver;
-	struct vme_dev *vdev = dev_to_vme_dev(dev);
-
-	driver = dev->platform_data;
-
-	if (driver->probe != NULL)
-		retval = driver->probe(vdev);
-
-	return retval;
-}
-
-static int vme_bus_remove(struct device *dev)
-{
-	int retval = -ENODEV;
-	struct vme_driver *driver;
-	struct vme_dev *vdev = dev_to_vme_dev(dev);
-
-	driver = dev->platform_data;
-
-	if (driver->remove != NULL)
-		retval = driver->remove(vdev);
-
-	return retval;
-}
-
-struct bus_type vme_bus_type = {
-	.name = "vme",
-	.match = vme_bus_match,
-	.probe = vme_bus_probe,
-	.remove = vme_bus_remove,
-};
-EXPORT_SYMBOL(vme_bus_type);
-
-static int __init vme_init(void)
-{
-	return bus_register(&vme_bus_type);
-}
-
-static void __exit vme_exit(void)
-{
-	bus_unregister(&vme_bus_type);
-}
-
-MODULE_DESCRIPTION("VME bridge driver framework");
-MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
-MODULE_LICENSE("GPL");
-
-module_init(vme_init);
-module_exit(vme_exit);
diff --git a/drivers/staging/vt6655/wpa.c b/drivers/staging/vt6655/wpa.c
index 61ac46f..0afb9fe 100644
--- a/drivers/staging/vt6655/wpa.c
+++ b/drivers/staging/vt6655/wpa.c
@@ -148,7 +148,7 @@
         {
             j = 0;
             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
-            for(i = 0; (i < pRSN->wPKCount) && (j < sizeof(pBSSList->abyPKType)/sizeof(unsigned char)); i++) {
+            for(i = 0; (i < pRSN->wPKCount) && (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) {
                 if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
                     if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
                         pBSSList->abyPKType[j++] = WPA_NONE;
@@ -180,7 +180,7 @@
             j = 0;
             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
                           pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
-            for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < sizeof(pBSSList->abyAuthType)/sizeof(unsigned char)); i++) {
+            for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) {
                 if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
                     if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
                         pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index c0edf97..e4bdf2a 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -452,7 +452,7 @@
        }
     }
 
-    if (!is_multicast_ether_addr(pMACHeader->abyAddr1) && !is_broadcast_ether_addr(pMACHeader->abyAddr1)) {
+    if (!is_multicast_ether_addr(pMACHeader->abyAddr1)) {
         if ( WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header) pbyFrame) ) {
             pDevice->s802_11Counter.FrameDuplicateCount++;
             return FALSE;
diff --git a/drivers/staging/vt6656/ioctl.c b/drivers/staging/vt6656/ioctl.c
index d59456c..5b9a84f 100644
--- a/drivers/staging/vt6656/ioctl.c
+++ b/drivers/staging/vt6656/ioctl.c
@@ -90,18 +90,17 @@
 		spin_lock_irq(&pDevice->lock);
 
 		if (memcmp(pMgmt->abyCurrBSSID, &abyNullAddr[0], 6) == 0)
-			BSSvClearBSSList((void *)pDevice, FALSE);
+			BSSvClearBSSList(pDevice, FALSE);
 		else
-			BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
+			BSSvClearBSSList(pDevice, pDevice->bLinkPass);
 
 		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_BSS_SCAN..begin\n");
 
 		if (pItemSSID->len != 0)
-			bScheduleCommand((void *)pDevice,
-					 WLAN_CMD_BSSID_SCAN,
+			bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN,
 					 abyScanSSID);
 		else
-			bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+			bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN, NULL);
 
 		spin_unlock_irq(&pDevice->lock);
 		break;
@@ -150,6 +149,7 @@
 			}
 		}
 		break;
+
 	case WLAN_CMD_BSS_JOIN:
 		if (copy_from_user(&sJoinCmd, pReq->data, sizeof(SCmdBSSJoin))) {
 			result = -EFAULT;
@@ -190,10 +190,9 @@
 		netif_stop_queue(pDevice->dev);
 		spin_lock_irq(&pDevice->lock);
 		pMgmt->eCurrState = WMAC_STATE_IDLE;
-		bScheduleCommand((void *) pDevice,
-				 WLAN_CMD_BSSID_SCAN,
+		bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN,
 				 pMgmt->abyDesireSSID);
-		bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
+		bScheduleCommand(pDevice, WLAN_CMD_SSID, NULL);
 		spin_unlock_irq(&pDevice->lock);
 		break;
 
@@ -299,7 +298,7 @@
 			result = -EINVAL;
 			break;
 		}
-		pList = (PSBSSIDList)kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), (int)GFP_ATOMIC);
+		pList = kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), GFP_ATOMIC);
 		if (pList == NULL) {
 			result = -ENOMEM;
 			break;
@@ -313,7 +312,7 @@
 				pList->sBSSIDList[ii].wBeaconInterval = pBSS->wBeaconInterval;
 				pList->sBSSIDList[ii].wCapInfo = pBSS->wCapInfo;
 				RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
-				pList->sBSSIDList[ii].uRSSI = (unsigned int) ldBm;
+				pList->sBSSIDList[ii].uRSSI = (unsigned int)ldBm;
 				/* pList->sBSSIDList[ii].uRSSI = pBSS->uRSSI; */
 				memcpy(pList->sBSSIDList[ii].abyBSSID, pBSS->abyBSSID, WLAN_BSSID_LEN);
 				pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
@@ -356,6 +355,7 @@
 			break;
 		}
 		break;
+
 	case WLAN_CMD_STOP_MAC:
 		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_STOP_MAC\n");
 		/* Todo xxxxxx */
@@ -534,7 +534,7 @@
 
 		netif_stop_queue(pDevice->dev);
 		spin_lock_irq(&pDevice->lock);
-		bScheduleCommand((void *)pDevice, WLAN_CMD_RUN_AP, NULL);
+		bScheduleCommand(pDevice, WLAN_CMD_RUN_AP, NULL);
 		spin_unlock_irq(&pDevice->lock);
 		break;
 
@@ -565,7 +565,7 @@
 			result = -ENOMEM;
 			break;
 		}
-		pNodeList = kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC);
+		pNodeList = kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), GFP_ATOMIC);
 		if (pNodeList == NULL) {
 			result = -ENOMEM;
 			break;
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 763e028..ee5261a 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -1257,9 +1257,7 @@
 	}
 
 	device_release_WPADEV(device);
-
-	if (device->firmware)
-		release_firmware(device->firmware);
+	release_firmware(device->firmware);
 
 	usb_set_intfdata(intf, NULL);
 	usb_put_dev(interface_to_usbdev(intf));
diff --git a/drivers/staging/vt6656/wpa.c b/drivers/staging/vt6656/wpa.c
index 7dde3d6..b16d4dd 100644
--- a/drivers/staging/vt6656/wpa.c
+++ b/drivers/staging/vt6656/wpa.c
@@ -149,7 +149,7 @@
             j = 0;
             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
 	    for (i = 0; (i < pRSN->wPKCount) &&
-		   (j < sizeof(pBSSList->abyPKType)/sizeof(BYTE)); i++) {
+		   (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) {
                 if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
                     if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
                         pBSSList->abyPKType[j++] = WPA_NONE;
@@ -182,7 +182,7 @@
             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
                           pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
 	    for (i = 0; (i < pIE_RSN_Auth->wAuthCount) &&
-		   (j < sizeof(pBSSList->abyAuthType)/sizeof(BYTE)); i++) {
+		   (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) {
                 if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
                     if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
                         pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
diff --git a/drivers/staging/wlags49_h2/README.ubuntu b/drivers/staging/wlags49_h2/README.ubuntu
index edee8b9..5f1cfb8f 100644
--- a/drivers/staging/wlags49_h2/README.ubuntu
+++ b/drivers/staging/wlags49_h2/README.ubuntu
@@ -87,7 +87,7 @@
 -- Recovery actions added
 
 The major problem was the order in which calls can be made. The original
-looks like a traditonal UNIX driver. To call an "ioctl" function you
+looks like a traditional UNIX driver. To call an "ioctl" function you
 have to "open" the device first to get a handle and after "close" no
 "ioctl" function can be called anymore. With the 2.6 driver this all
 changed; the former ioctl functions are now called before "open" and
diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c
index 5957c3a..366e4a4 100644
--- a/drivers/staging/wlags49_h2/hcf.c
+++ b/drivers/staging/wlags49_h2/hcf.c
@@ -2871,8 +2871,8 @@
 *   The Assert validates the HCF assumption about Hermes implementation upon which the range of
 *   Pseudo-RIDs is based.
 *   Then the control fields up to the start of the 802.3 frame are read from the NIC into the lookahead buffer.
-*   The status field is converted to native Endianess.
-*   The length is, after implicit Endianess conversion if needed, and adjustment for the 14 bytes of the
+*   The status field is converted to native Endianness.
+*   The length is, after implicit Endianness conversion if needed, and adjustment for the 14 bytes of the
 *   802.3 MAC header, stored in IFB_RxLen.
 *   In MAC Monitor mode, 802.11 control frames with a TOTAL length of 14 are received, so without this
 *   length adjustment, IFB_RxLen could not be used to distinguish these frames from "no frame".
@@ -2894,7 +2894,7 @@
 *     - the Hermes reported Tunnel encapsulation or
 *     - the Hermes reported 1042 Encapsulation and hcf_encap reports that the HCF would not have used
 *       1042 as the encapsulation mechanism
-*   Note that the first field of the RxFS in bufp has Native Endianess due to the conversion done by the
+*   Note that the first field of the RxFS in bufp has Native Endianness due to the conversion done by the
 *   BE_PAR in get_frag.
 *36: The Type field is the only word kept (after moving) of the just read 8 bytes, it is moved to the
 *   L-field.  The original L-field and 6 byte SNAP header are discarded, so IFB_RxLen and buf_addr must
@@ -3831,7 +3831,7 @@
  *.DESCRIPTION
  * process the single byte (if applicable) read by the previous get_frag and copy len (or len-1) bytes from
  * NIC to bufp.
- * On a Big Endian platform, the parameter word_len controls the number of leading bytes whose endianess is
+ * On a Big Endian platform, the parameter word_len controls the number of leading bytes whose endianness is
  * converted (i.e. byte swapped)
  *
  *
@@ -3980,7 +3980,7 @@
  *    appropriate means on H-I: always
  *    and on H-II if F/W supplier reflects a primary (i.e. only after an Hermes Reset or Init
  *    command).
- *    QUESTION ;? !!!!!! should, For each of the above RIDs the Endianess is converted to native Endianess.
+ *    QUESTION ;? !!!!!! should, For each of the above RIDs the Endianness is converted to native Endianness.
  *    Only the return code of the first hcf_get_info is used. All hcf_get_info calls are made, regardless of
  *    the success or failure of the 1st hcf_get_info. The assumptions are:
  *     - if any call fails, they all fail, so remembering the result of the 1st call is adequate
diff --git a/drivers/staging/wlags49_h2/hcf.h b/drivers/staging/wlags49_h2/hcf.h
index 95527b5..68e2330 100644
--- a/drivers/staging/wlags49_h2/hcf.h
+++ b/drivers/staging/wlags49_h2/hcf.h
@@ -90,7 +90,7 @@
 
 #define LOF(x) 			(sizeof(x)/sizeof(hcf_16)-1)
 
-/*	Endianess
+/*	Endianness
  *	Little Endian (a.k.a. Intel), least significant byte first
  *	Big Endian (a.k.a. Motorola), most significant byte first
  *
@@ -101,7 +101,7 @@
  */
 
 /* To increase portability, use unsigned char and unsigned char * when accessing parts of larger
- * types to convert their Endianess
+ * types to convert their Endianness
  */
 
 #define CNV_END_SHORT(w)  (hcf_16)( ((hcf_16)(w) & 0x00FF) << 8 | ((hcf_16)(w) & 0xFF00) >> 8 )
@@ -109,14 +109,14 @@
 
 #if HCF_BIG_ENDIAN
 //******************************************** B I G   E N D I A N *******************************************
-#define CNV_LITTLE_TO_SHORT(w)	CNV_END_SHORT(w)	//    endianess conversion needed
-#define CNV_BIG_TO_SHORT(w)		(w)				// no endianess conversion needed
+#define CNV_LITTLE_TO_SHORT(w)	CNV_END_SHORT(w)	//    endianness conversion needed
+#define CNV_BIG_TO_SHORT(w)		(w)				// no endianness conversion needed
 #define CNV_LITTLE_TO_LONG(dw)	CNV_END_LONG(dw)
 #define CNV_LONG_TO_LITTLE(dw)	CNV_END_LONG(dw)
 #else
 //****************************************** L I T T L E   E N D I A N ****************************************
-#define CNV_LITTLE_TO_SHORT(w) 	(w)				// no endianess conversion needed
-#define CNV_BIG_TO_SHORT(w)		CNV_END_SHORT(w)	//    endianess conversion needed
+#define CNV_LITTLE_TO_SHORT(w) 	(w)				// no endianness conversion needed
+#define CNV_BIG_TO_SHORT(w)		CNV_END_SHORT(w)	//    endianness conversion needed
 #define CNV_LITTLE_TO_LONG(dw)	(dw)
 #define CNV_LONG_TO_LITTLE(dw)	(dw)
 
diff --git a/drivers/staging/wlags49_h2/mmd.c b/drivers/staging/wlags49_h2/mmd.c
index c8f5210..7204a37 100644
--- a/drivers/staging/wlags49_h2/mmd.c
+++ b/drivers/staging/wlags49_h2/mmd.c
@@ -101,10 +101,10 @@
 *	supp	address of the supplier specification
 *
 *	Description: mmd_check_comp is a support routine to check the compatibility between an actor and a
-*	supplier.  mmd_check_comp is independent of the endianess of the actp and supp structures. This is
+*	supplier.  mmd_check_comp is independent of the endianness of the actp and supp structures. This is
 *	achieved by checking the "bottom" or "role" fields of these structures. Since these fields are restricted
 *	to a limited range, comparing the contents to a value with a known endian-ess gives a clue to their actual
-*	endianess.
+*	endianness.
 *
 *.DIAGRAM
 *1a: The role-field of the actor structure has a known non-zero, not "byte symmetric" value (namely
@@ -114,16 +114,16 @@
 *	for a supplier. A supplier has always exactly 1 variant,top,bottom record with (officially, but see the
 *	note below) each of these 3 values in the range 1 through 99, so one byte of the word value of variant,
 *	top and bottom words is 0x00 and the other byte is non-zero. Whether the lowest address byte or the
-*	highest address byte is non-zero depends on the Endianess of the LTV. If and only if the word value of
+*	highest address byte is non-zero depends on the Endianness of the LTV. If and only if the word value of
 *	bottom is less than 0x0100, the supplier is Native Endian.
 *	NOTE: the variant field of the supplier structure can not be used for the Endian Detection Algorithm,
 *	because a a zero-valued variant has been used as Controlled Deployment indication in the past.
 *	Note: An actor may have multiple sets of variant,top,bottom records, including dummy sets with variant,
-*	top and bottom fields with a zero-value. As a consequence the endianess of the actor can not be determined
+*	top and bottom fields with a zero-value. As a consequence the endianness of the actor can not be determined
 *	based on its variant,top,bottom values.
 *
 *	Note: the L and T field of the structures are always in Native Endian format, so you can not draw
-*	conclusions concerning the Endianess of the structure based on these two fields.
+*	conclusions concerning the Endianness of the structure based on these two fields.
 *
 *1b/2b
 *	The only purpose of the CFG_RANGE_SPEC_BYTE_STRCT is to give easy access to the non-zero byte of the word
@@ -149,7 +149,7 @@
 *
 *	This is implemented as:
 *	#if HCF_BIG_ENDIAN == 0	//platform is LE
-*		sup/act_endian becomes reverse of structure-endianess as determined in 1a/1b
+*		sup/act_endian becomes reverse of structure-endianness as determined in 1a/1b
 *	#endif
 *6:	Each of the actor variant-bottom-top records is checked against the (single) supplier variant-bottom-top
 *	range till either an acceptable match is found or all actor records are tried. As explained above, due to
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index 7084f41..7c7c77f 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -177,10 +177,9 @@
 	if (dev) {
 		unregister_wlags_sysfs(dev);
 		unregister_netdev(dev);
+		wl_device_dealloc(dev);
 	}
 
-	wl_device_dealloc(dev);
-
 	DBG_LEAVE(DbgInfo);
 } /* wl_adapter_detach */
 /*============================================================================*/
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index 90820ff..824b852 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -1063,7 +1063,7 @@
 #if DBG
     if( DBG_FLAGS( DbgInfo ) & DBG_PARAM_ON ) {
         DBG_PRINT("  flags: %s%s%s\n",
-            ( dev->flags & IFF_PROMISC ) ? "Promiscous " : "",
+            ( dev->flags & IFF_PROMISC ) ? "Promiscuous " : "",
             ( dev->flags & IFF_MULTICAST ) ? "Multicast " : "",
             ( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" );
 
@@ -1510,8 +1510,11 @@
     for( count = 0; count < NUM_WDS_PORTS; count++ ) {
         struct net_device *dev_wds = NULL;
 
-        dev_wds = kmalloc( sizeof( struct net_device ), GFP_KERNEL );
-        memset( dev_wds, 0, sizeof( struct net_device ));
+	dev_wds = kzalloc(sizeof(struct net_device), GFP_KERNEL);
+	if (!dev_wds) {
+		DBG_LEAVE(DbgInfo);
+		return;
+	}
 
         ether_setup( dev_wds );
 
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c
index 3df990c..0b31b01 100644
--- a/drivers/staging/wlags49_h2/wl_pci.c
+++ b/drivers/staging/wlags49_h2/wl_pci.c
@@ -524,6 +524,7 @@
     /* Make sure that space was allocated for our private adapter struct */
     if( dev->priv == NULL ) {
         DBG_ERROR( DbgInfo, "Private adapter struct was not allocated!!!\n" );
+	wl_device_dealloc(dev);
         DBG_LEAVE( DbgInfo );
         return -ENOMEM;
     }
@@ -532,6 +533,7 @@
     /* Allocate DMA Descriptors */
     if( wl_pci_dma_alloc( pdev, dev->priv ) < 0 ) {
         DBG_ERROR( DbgInfo, "Could not allocate DMA descriptor memory!!!\n" );
+	wl_device_dealloc(dev);
         DBG_LEAVE( DbgInfo );
         return -ENOMEM;
     }
@@ -561,6 +563,8 @@
     result = request_irq(dev->irq, wl_isr, SA_SHIRQ, dev->name, dev);
     if( result ) {
         DBG_WARNING( DbgInfo, "Could not register ISR!!!\n" );
+	wl_remove(dev);
+	wl_device_dealloc(dev);
         DBG_LEAVE( DbgInfo );
         return result;
 	}
diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c
index b8c96cf..0e49272 100644
--- a/drivers/staging/wlags49_h2/wl_profile.c
+++ b/drivers/staging/wlags49_h2/wl_profile.c
@@ -401,7 +401,7 @@
 		if ((value_convert >= PARM_MIN_BRSC) || (value_convert <= PARM_MAX_BRSC))
 			lp->brsc[0] = value_convert;
 		else
-			DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_BRSC_2GHZ);
+			DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_BRSC_2GHZ);
 	} else if (strcmp(key, PARM_NAME_BRSC_5GHZ) == 0) {
 		DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_BRSC_5GHZ, value);
 
@@ -409,7 +409,7 @@
 		if ((value_convert >= PARM_MIN_BRSC) || (value_convert <= PARM_MAX_BRSC))
 			lp->brsc[1] = value_convert;
 		else
-			DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_BRSC_5GHZ);
+			DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_BRSC_5GHZ);
 	} else if ((strcmp(key, PARM_NAME_DESIRED_SSID) == 0) || (strcmp(key, PARM_NAME_OWN_SSID) == 0)) {
 		DBG_TRACE(DbgInfo, "SSID, value: %s\n", value);
 
@@ -556,7 +556,7 @@
 		if ((value_convert >= PARM_MIN_SRSC) || (value_convert <= PARM_MAX_SRSC))
 			lp->srsc[0] = value_convert;
 		else
-			DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_SRSC_2GHZ);
+			DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_SRSC_2GHZ);
 	} else if (strcmp(key, PARM_NAME_SRSC_5GHZ) == 0) {
 		DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_SRSC_5GHZ, value);
 
@@ -564,7 +564,7 @@
 		if ((value_convert >= PARM_MIN_SRSC) || (value_convert <= PARM_MAX_SRSC))
 			lp->srsc[1] = value_convert;
 		else
-			DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_SRSC_5GHZ);
+			DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_SRSC_5GHZ);
 	} else if (strcmp(key, PARM_NAME_SYSTEM_SCALE) == 0) {
 		DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_SYSTEM_SCALE, value);
 
diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c
index f104e6f..404ec7d 100644
--- a/drivers/staging/wlags49_h2/wl_util.c
+++ b/drivers/staging/wlags49_h2/wl_util.c
@@ -98,8 +98,7 @@
  ******************************************************************************/
 
 /* A matrix which maps channels to frequencies */
-#define MAX_CHAN_FREQ_MAP_ENTRIES   50
-static const long chan_freq_list[][MAX_CHAN_FREQ_MAP_ENTRIES] =
+static const long chan_freq_list[][2] =
 {
     {1,2412},
     {2,2417},
@@ -846,7 +845,7 @@
     }
 
     /* Iterate through the matrix and retrieve the frequency */
-    for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+    for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
         if( chan_freq_list[i][0] == channel ) {
             return 1;
         }
@@ -884,7 +883,7 @@
 
 
     /* Iterate through the matrix and retrieve the channel */
-    for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+    for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
         if( chan_freq_list[i][1] == frequency ) {
             return 1;
         }
@@ -927,7 +926,7 @@
     }
 
     /* Iterate through the matrix and retrieve the frequency */
-    for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+    for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
         if( chan_freq_list[i][0] == channel ) {
             return chan_freq_list[i][1];
         }
@@ -965,7 +964,7 @@
 
 
     /* Iterate through the matrix and retrieve the channel */
-    for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+    for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
         if( chan_freq_list[i][1] == frequency ) {
             return chan_freq_list[i][0];
         }
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 4cd3ba5..8bc562b 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -332,6 +332,7 @@
 	wlandevice_t *wlandev = dev->ml_priv;
 	struct p80211msg_dot11req_scan msg1;
 	struct p80211msg_dot11req_scan_results msg2;
+	struct cfg80211_bss *bss;
 	int result;
 	int err = 0;
 	int numbss = 0;
@@ -401,7 +402,7 @@
 		ie_buf[1] = msg2.ssid.data.len;
 		ie_len = ie_buf[1] + 2;
 		memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len);
-		cfg80211_inform_bss(wiphy,
+		bss = cfg80211_inform_bss(wiphy,
 			ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)),
 			(const u8 *) &(msg2.bssid.data.data),
 			msg2.timestamp.data, msg2.capinfo.data,
@@ -411,6 +412,13 @@
 			(msg2.signal.data - 65536) * 100, /* Conversion to signed type */
 			GFP_KERNEL
 		);
+
+		if (!bss) {
+			err = -ENOMEM;
+			goto exit;
+		}
+
+		cfg80211_put_bss(bss);
 	}
 
 	if (result)
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index c3bb05d..4efa9bc 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -380,8 +380,8 @@
 	}
 
 	count = (hw->scanresults->framelen - 3) / 32;
-	if (count > 32)
-		count = 32;
+	if (count > HFA384x_SCANRESULT_MAX)
+		count = HFA384x_SCANRESULT_MAX;
 
 	if (req->bssindex.data >= count) {
 		pr_debug("requested index (%d) out of range (%d)\n",
diff --git a/drivers/staging/xgifb/XGI_main.h b/drivers/staging/xgifb/XGI_main.h
index e828fd4..9c62aeb 100644
--- a/drivers/staging/xgifb/XGI_main.h
+++ b/drivers/staging/xgifb/XGI_main.h
@@ -12,9 +12,6 @@
 
 #define XGIFAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
 
-#ifndef PCI_DEVICE_ID_XGI_41
-#define PCI_DEVICE_ID_XGI_41      0x041
-#endif
 #ifndef PCI_DEVICE_ID_XGI_42
 #define PCI_DEVICE_ID_XGI_42      0x042
 #endif
@@ -82,177 +79,79 @@
 /* TW: For ioctl XGIFB_GET_INFO */
 /* XGIfb_info XGIfbinfo; */
 
-#define MD_XGI300 1
-#define MD_XGI315 2
+#define MD_XGI315 1
 
 /* mode table */
 static const struct _XGIbios_mode {
-	char name[15];
 	u8 mode_no;
 	u16 vesa_mode_no_1;  /* "XGI defined" VESA mode number */
 	u16 vesa_mode_no_2;  /* Real VESA mode numbers */
 	u16 xres;
 	u16 yres;
 	u16 bpp;
-	u16 rate_idx;
-	u16 cols;
-	u16 rows;
 	u8  chipset;
 } XGIbios_mode[] = {
-	{"320x240x16",   0x56, 0x0000, 0x0000,  320,  240, 16, 1,  40, 15,
-	 MD_XGI315},
-	{"320x480x8",    0x5A, 0x0000, 0x0000,  320,  480,  8, 1,  40, 30,
-	 MD_XGI315},  /* TW: FSTN */
-	{"320x480x16",   0x5B, 0x0000, 0x0000,  320,  480, 16, 1,  40, 30,
-	 MD_XGI315},  /* TW: FSTN */
-	{"640x480x8",    0x2E, 0x0101, 0x0101,  640,  480,  8, 1,  80, 30,
-	 MD_XGI300|MD_XGI315},
-	{"640x480x16",   0x44, 0x0111, 0x0111,  640,  480, 16, 1,  80, 30,
-	 MD_XGI300|MD_XGI315},
-	{"640x480x24",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30,
-	 MD_XGI300|MD_XGI315},  /* TW: That's for people who mix up color-
-					and fb depth */
-	{"640x480x32",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30,
-	 MD_XGI300|MD_XGI315},
-	{"720x480x8",    0x31, 0x0000, 0x0000,  720,  480,  8, 1,  90, 30,
-	 MD_XGI300|MD_XGI315},
-	{"720x480x16",   0x33, 0x0000, 0x0000,  720,  480, 16, 1,  90, 30,
-	 MD_XGI300|MD_XGI315},
-	{"720x480x24",   0x35, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30,
-	 MD_XGI300|MD_XGI315},
-	{"720x480x32",   0x35, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30,
-	 MD_XGI300|MD_XGI315},
-	{"720x576x8",    0x32, 0x0000, 0x0000,  720,  576,  8, 1,  90, 36,
-	 MD_XGI300|MD_XGI315},
-	{"720x576x16",   0x34, 0x0000, 0x0000,  720,  576, 16, 1,  90, 36,
-	 MD_XGI300|MD_XGI315},
-	{"720x576x24",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36,
-	 MD_XGI300|MD_XGI315},
-	{"720x576x32",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36,
-	 MD_XGI300|MD_XGI315},
-	{"800x480x8",    0x70, 0x0000, 0x0000,  800,  480,  8, 1, 100, 30,
-	 MD_XGI300|MD_XGI315},
-	{"800x480x16",   0x7a, 0x0000, 0x0000,  800,  480, 16, 1, 100, 30,
-	 MD_XGI300|MD_XGI315},
-	{"800x480x24",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30,
-	 MD_XGI300|MD_XGI315},
-	{"800x480x32",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30,
-	 MD_XGI300|MD_XGI315},
-	{"800x600x8",    0x30, 0x0103, 0x0103,  800,  600,  8, 1, 100, 37,
-	 MD_XGI300|MD_XGI315},
-#define DEFAULT_MODE              20 /* index for 800x600x16 */
-	{"800x600x16",   0x47, 0x0114, 0x0114,  800,  600, 16, 1, 100, 37,
-	 MD_XGI300|MD_XGI315},
-	{"800x600x24",   0x63, 0x013b, 0x0115,  800,  600, 32, 1, 100, 37,
-	 MD_XGI300|MD_XGI315},
-	{"800x600x32",   0x63, 0x013b, 0x0115,  800,  600, 32, 1, 100, 37,
-	 MD_XGI300|MD_XGI315},
-	{"1024x576x8",   0x71, 0x0000, 0x0000, 1024,  576,  8, 1, 128, 36,
-	 MD_XGI300|MD_XGI315},
-	{"1024x576x16",  0x74, 0x0000, 0x0000, 1024,  576, 16, 1, 128, 36,
-	 MD_XGI300|MD_XGI315},
-	{"1024x576x24",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36,
-	 MD_XGI300|MD_XGI315},
-	{"1024x576x32",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36,
-	 MD_XGI300|MD_XGI315},
-	{"1024x600x8",   0x20, 0x0000, 0x0000, 1024,  600,  8, 1, 128, 37,
-	 MD_XGI300          },  /* TW: 300 series only */
-	{"1024x600x16",  0x21, 0x0000, 0x0000, 1024,  600, 16, 1, 128, 37,
-	 MD_XGI300          },
-	{"1024x600x24",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37,
-	 MD_XGI300          },
-	{"1024x600x32",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37,
-	 MD_XGI300          },
-	{"1024x768x8",   0x38, 0x0105, 0x0105, 1024,  768,  8, 1, 128, 48,
-	 MD_XGI300|MD_XGI315},
-	{"1024x768x16",  0x4A, 0x0117, 0x0117, 1024,  768, 16, 1, 128, 48,
-	 MD_XGI300|MD_XGI315},
-	{"1024x768x24",  0x64, 0x013c, 0x0118, 1024,  768, 32, 1, 128, 48,
-	 MD_XGI300|MD_XGI315},
-	{"1024x768x32",  0x64, 0x013c, 0x0118, 1024,  768, 32, 1, 128, 48,
-	 MD_XGI300|MD_XGI315},
-	{"1152x768x8",   0x23, 0x0000, 0x0000, 1152,  768,  8, 1, 144, 48,
-	 MD_XGI300          },  /* TW: 300 series only */
-	{"1152x768x16",  0x24, 0x0000, 0x0000, 1152,  768, 16, 1, 144, 48,
-	 MD_XGI300          },
-	{"1152x768x24",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48,
-	 MD_XGI300          },
-	{"1152x768x32",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48,
-	 MD_XGI300          },
-	{"1280x720x8",   0x79, 0x0000, 0x0000, 1280,  720,  8, 1, 160, 45,
-	 MD_XGI300|MD_XGI315},
-	{"1280x720x16",  0x75, 0x0000, 0x0000, 1280,  720, 16, 1, 160, 45,
-	 MD_XGI300|MD_XGI315},
-	{"1280x720x24",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45,
-	 MD_XGI300|MD_XGI315},
-	{"1280x720x32",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45,
-	 MD_XGI300|MD_XGI315},
-	{"1280x768x8",   0x23, 0x0000, 0x0000, 1280,  768,  8, 1, 160, 48,
-	 MD_XGI315},  /* TW: 310/325 series only */
-	{"1280x768x16",  0x24, 0x0000, 0x0000, 1280,  768, 16, 1, 160, 48,
-	 MD_XGI315},
-	{"1280x768x24",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48,
-	 MD_XGI315},
-	{"1280x768x32",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48,
-	 MD_XGI315},
-	{"1280x960x8",   0x7C, 0x0000, 0x0000, 1280,  960,  8, 1, 160, 60,
-	 MD_XGI300|MD_XGI315},
-	{"1280x960x16",  0x7D, 0x0000, 0x0000, 1280,  960, 16, 1, 160, 60,
-	 MD_XGI300|MD_XGI315},
-	{"1280x960x24",  0x7E, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60,
-	 MD_XGI300|MD_XGI315},
-	{"1280x960x32",  0x7E, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60,
-	 MD_XGI300|MD_XGI315},
-	{"1280x1024x8",  0x3A, 0x0107, 0x0107, 1280, 1024,  8, 1, 160, 64,
-	 MD_XGI300|MD_XGI315},
-	{"1280x1024x16", 0x4D, 0x011a, 0x011a, 1280, 1024, 16, 1, 160, 64,
-	 MD_XGI300|MD_XGI315},
-	{"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64,
-	 MD_XGI300|MD_XGI315},
-	{"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64,
-	 MD_XGI300|MD_XGI315},
-	{"1400x1050x8",  0x26, 0x0000, 0x0000, 1400, 1050,  8, 1, 175, 65,
-	 MD_XGI315},  /* TW: 310/325 series only */
-	{"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65,
-	 MD_XGI315},
-	{"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,
-	 MD_XGI315},
-	{"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,
-	 MD_XGI315},
-	{"1600x1200x8",  0x3C, 0x0130, 0x011c, 1600, 1200,  8, 1, 200, 75,
-	 MD_XGI300|MD_XGI315},
-	{"1600x1200x16", 0x3D, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75,
-	 MD_XGI300|MD_XGI315},
-	{"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75,
-	 MD_XGI300|MD_XGI315},
-	{"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75,
-	 MD_XGI300|MD_XGI315},
-	{"1920x1440x8",  0x68, 0x013f, 0x0000, 1920, 1440,  8, 1, 240, 75,
-	 MD_XGI300|MD_XGI315},
-	{"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75,
-	 MD_XGI300|MD_XGI315},
-	{"1920x1440x24", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75,
-	 MD_XGI300|MD_XGI315},
-	{"1920x1440x32", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75,
-	 MD_XGI300|MD_XGI315},
-	{"2048x1536x8",  0x6c, 0x0000, 0x0000, 2048, 1536,  8, 1, 256, 96,
-	 MD_XGI315},  /* TW: 310/325 series only */
-	{"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96,
-	 MD_XGI315},
-	{"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,
-	 MD_XGI315},
-	{"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,
-	 MD_XGI315},
-	{"\0", 0x00, 0, 0, 0, 0, 0, 0, 0}
+	{ 0x56, 0x0000, 0x0000,  320,  240, 16, MD_XGI315 },
+	{ 0x5A, 0x0000, 0x0000,  320,  480,  8, MD_XGI315 },
+	{ 0x5B, 0x0000, 0x0000,  320,  480, 16, MD_XGI315 },
+	{ 0x2E, 0x0101, 0x0101,  640,  480,  8, MD_XGI315 },
+	{ 0x44, 0x0111, 0x0111,  640,  480, 16, MD_XGI315 },
+	{ 0x62, 0x013a, 0x0112,  640,  480, 32, MD_XGI315 },
+	{ 0x31, 0x0000, 0x0000,  720,  480,  8, MD_XGI315 },
+	{ 0x33, 0x0000, 0x0000,  720,  480, 16, MD_XGI315 },
+	{ 0x35, 0x0000, 0x0000,  720,  480, 32, MD_XGI315 },
+	{ 0x32, 0x0000, 0x0000,  720,  576,  8, MD_XGI315 },
+	{ 0x34, 0x0000, 0x0000,  720,  576, 16, MD_XGI315 },
+	{ 0x36, 0x0000, 0x0000,  720,  576, 32, MD_XGI315 },
+	{ 0x36, 0x0000, 0x0000,  720,  576, 32, MD_XGI315 },
+	{ 0x70, 0x0000, 0x0000,  800,  480,  8, MD_XGI315 },
+	{ 0x7a, 0x0000, 0x0000,  800,  480, 16, MD_XGI315 },
+	{ 0x76, 0x0000, 0x0000,  800,  480, 32, MD_XGI315 },
+	{ 0x30, 0x0103, 0x0103,  800,  600,  8, MD_XGI315 },
+#define DEFAULT_MODE              17 /* index for 800x600x16 */
+	{ 0x47, 0x0114, 0x0114,  800,  600, 16, MD_XGI315 },
+	{ 0x63, 0x013b, 0x0115,  800,  600, 32, MD_XGI315 },
+	{ 0x71, 0x0000, 0x0000, 1024,  576,  8, MD_XGI315 },
+	{ 0x74, 0x0000, 0x0000, 1024,  576, 16, MD_XGI315 },
+	{ 0x77, 0x0000, 0x0000, 1024,  576, 32, MD_XGI315 },
+	{ 0x77, 0x0000, 0x0000, 1024,  576, 32, MD_XGI315 },
+	{ 0x20, 0x0000, 0x0000, 1024,  600,  8, },
+	{ 0x21, 0x0000, 0x0000, 1024,  600, 16, },
+	{ 0x22, 0x0000, 0x0000, 1024,  600, 32, },
+	{ 0x38, 0x0105, 0x0105, 1024,  768,  8, MD_XGI315 },
+	{ 0x4A, 0x0117, 0x0117, 1024,  768, 16, MD_XGI315 },
+	{ 0x64, 0x013c, 0x0118, 1024,  768, 32, MD_XGI315 },
+	{ 0x64, 0x013c, 0x0118, 1024,  768, 32, MD_XGI315 },
+	{ 0x23, 0x0000, 0x0000, 1152,  768,  8, },
+	{ 0x24, 0x0000, 0x0000, 1152,  768, 16, },
+	{ 0x25, 0x0000, 0x0000, 1152,  768, 32, },
+	{ 0x79, 0x0000, 0x0000, 1280,  720,  8, MD_XGI315 },
+	{ 0x75, 0x0000, 0x0000, 1280,  720, 16, MD_XGI315 },
+	{ 0x78, 0x0000, 0x0000, 1280,  720, 32, MD_XGI315 },
+	{ 0x23, 0x0000, 0x0000, 1280,  768,  8, MD_XGI315 },
+	{ 0x24, 0x0000, 0x0000, 1280,  768, 16, MD_XGI315 },
+	{ 0x25, 0x0000, 0x0000, 1280,  768, 32, MD_XGI315 },
+	{ 0x7C, 0x0000, 0x0000, 1280,  960,  8, MD_XGI315 },
+	{ 0x7D, 0x0000, 0x0000, 1280,  960, 16, MD_XGI315 },
+	{ 0x7E, 0x0000, 0x0000, 1280,  960, 32, MD_XGI315 },
+	{ 0x3A, 0x0107, 0x0107, 1280, 1024,  8, MD_XGI315 },
+	{ 0x4D, 0x011a, 0x011a, 1280, 1024, 16, MD_XGI315 },
+	{ 0x65, 0x013d, 0x011b, 1280, 1024, 32, MD_XGI315 },
+	{ 0x26, 0x0000, 0x0000, 1400, 1050,  8, MD_XGI315 },
+	{ 0x27, 0x0000, 0x0000, 1400, 1050, 16, MD_XGI315 },
+	{ 0x28, 0x0000, 0x0000, 1400, 1050, 32, MD_XGI315 },
+	{ 0x3C, 0x0130, 0x011c, 1600, 1200,  8, MD_XGI315 },
+	{ 0x3D, 0x0131, 0x011e, 1600, 1200, 16, MD_XGI315 },
+	{ 0x66, 0x013e, 0x011f, 1600, 1200, 32, MD_XGI315 },
+	{ 0x68, 0x013f, 0x0000, 1920, 1440,  8, MD_XGI315 },
+	{ 0x69, 0x0140, 0x0000, 1920, 1440, 16, MD_XGI315 },
+	{ 0x6B, 0x0141, 0x0000, 1920, 1440, 32, MD_XGI315 },
+	{ 0x6c, 0x0000, 0x0000, 2048, 1536,  8, MD_XGI315 },
+	{ 0x6d, 0x0000, 0x0000, 2048, 1536, 16, MD_XGI315 },
+	{ 0x6e, 0x0000, 0x0000, 2048, 1536, 32, MD_XGI315 },
+	{ 0 },
 };
 
-/* TW: CR36 evaluation */
-static const unsigned short XGI300paneltype[] = {
-	 LCD_UNKNOWN,  LCD_800x600, LCD_1024x768, LCD_1280x1024,
-	LCD_1280x960,  LCD_640x480, LCD_1024x600, LCD_1152x768,
-	LCD_1024x768, LCD_1024x768, LCD_1024x768,
-	LCD_1024x768, LCD_1024x768, LCD_1024x768, LCD_1024x768};
-
 static const unsigned short XGI310paneltype[] = {
 	 LCD_UNKNOWN,   LCD_800x600, LCD_1024x768, LCD_1280x1024,
 	 LCD_640x480,  LCD_1024x600, LCD_1152x864, LCD_1280x960,
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 21c0378..85dbf32 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -156,25 +156,14 @@
 	unsigned short ModeNo = modeno;
 	unsigned short ModeIdIndex = 0, ClockIndex = 0;
 	unsigned short RefreshRateTableIndex = 0;
-
-	/* unsigned long  temp = 0; */
 	int Clock;
 	InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
 
+	XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr);
+
 	RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
 			ModeIdIndex, XGI_Pr);
 
-	/*
-	temp = XGI_SearchModeID(ModeNo , &ModeIdIndex,  XGI_Pr) ;
-	if (!temp) {
-		printk(KERN_ERR "Could not find mode %x\n", ModeNo);
-		return 65000;
-	}
-
-	RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
-	RefreshRateTableIndex += (rateindex - 1);
-
-	*/
 	ClockIndex = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
 
 	Clock = XGI_Pr->VCLKData[ClockIndex].CLOCK * 1000;
@@ -190,7 +179,7 @@
 		u32 *vmode)
 {
 	unsigned short ModeNo = modeno;
-	unsigned short ModeIdIndex = 0, index = 0;
+	unsigned short ModeIdIndex, index = 0;
 	unsigned short RefreshRateTableIndex = 0;
 
 	unsigned short VRE, VBE, VRS, VBS, VDE, VT;
@@ -199,16 +188,10 @@
 	unsigned long cr_data3;
 	int A, B, C, D, E, F, temp, j;
 	InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
+	if (!XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr))
+		return 0;
 	RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
 			ModeIdIndex, XGI_Pr);
-	/*
-	temp = XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr);
-	if (!temp)
-		return 0;
-
-	RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
-	RefreshRateTableIndex += (rateindex - 1);
-	*/
 	index = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
 
 	sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[5];
@@ -219,12 +202,6 @@
 	HT = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8);
 	A = HT + 5;
 
-	/*
-	cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1];
-
-	Horizontal display enable end
-	HDE = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x0C) << 6);
-	*/
 	HDE = (XGI_Pr->RefIndex[RefreshRateTableIndex].XRes >> 3) - 1;
 	E = HDE + 1;
 
@@ -358,7 +335,6 @@
 
 static void XGIRegInit(struct vb_device_info *XGI_Pr, unsigned long BaseAddr)
 {
-	XGI_Pr->RelIO = BaseAddr;
 	XGI_Pr->P3c4 = BaseAddr + 0x14;
 	XGI_Pr->P3d4 = BaseAddr + 0x24;
 	XGI_Pr->P3c0 = BaseAddr + 0x10;
@@ -414,19 +390,26 @@
 static void XGIfb_search_mode(struct xgifb_video_info *xgifb_info,
 			      const char *name)
 {
-	int i = 0, j = 0, l;
+	unsigned int xres;
+	unsigned int yres;
+	unsigned int bpp;
+	int i;
 
-	while (XGIbios_mode[i].mode_no != 0) {
-		l = min(strlen(name), strlen(XGIbios_mode[i].name));
-		if (!strncmp(name, XGIbios_mode[i].name, l)) {
+	if (sscanf(name, "%ux%ux%u", &xres, &yres, &bpp) != 3)
+		goto invalid_mode;
+
+	if (bpp == 24)
+		bpp = 32; /* That's for people who mix up color and fb depth. */
+
+	for (i = 0; XGIbios_mode[i].mode_no != 0; i++)
+		if (XGIbios_mode[i].xres == xres &&
+		    XGIbios_mode[i].yres == yres &&
+		    XGIbios_mode[i].bpp == bpp) {
 			xgifb_info->mode_idx = i;
-			j = 1;
-			break;
+			return;
 		}
-		i++;
-	}
-	if (!j)
-		pr_info("Invalid mode '%s'\n", name);
+invalid_mode:
+	pr_info("Invalid mode '%s'\n", name);
 }
 
 static void XGIfb_search_vesamode(struct xgifb_video_info *xgifb_info,
@@ -1088,7 +1071,7 @@
 	unsigned int vtotal = var->upper_margin + var->yres + var->lower_margin
 			+ var->vsync_len;
 #if defined(__powerpc__)
-	u8 sr_data, cr_data;
+	u8 cr_data;
 #endif
 	unsigned int drate = 0, hrate = 0;
 	int found_mode = 0;
@@ -1162,8 +1145,7 @@
 
 	if (XGIfb_search_refresh_rate(xgifb_info,
 				      xgifb_info->refresh_rate) == 0) {
-		xgifb_info->rate_idx =
-			XGIbios_mode[xgifb_info->mode_idx].rate_idx;
+		xgifb_info->rate_idx = 1;
 		xgifb_info->refresh_rate = 60;
 	}
 
@@ -1680,17 +1662,6 @@
 			ChannelNum = 1;
 		break;
 
-	case XG45:
-		if (tmp == 1)
-			ChannelNum = 2;
-		else if (tmp == 2)
-			ChannelNum = 3;
-		else if (tmp == 3)
-			ChannelNum = 4;
-		else
-			ChannelNum = 1;
-		break;
-
 	case XG40:
 	default:
 		if (tmp == 2)
@@ -1911,11 +1882,9 @@
 	xgifb_info->mmio_base = pci_resource_start(pdev, 1);
 	xgifb_info->mmio_size = pci_resource_len(pdev, 1);
 	xgifb_info->vga_base = pci_resource_start(pdev, 2) + 0x30;
-	hw_info->pjIOAddress = (unsigned char *)xgifb_info->vga_base;
-	/* XGI_Pr.RelIO  = ioremap(pci_resource_start(pdev, 2), 128) + 0x30; */
-	pr_info("Relocate IO address: %lx [%08lx]\n",
-	       (unsigned long)pci_resource_start(pdev, 2),
-	       xgifb_info->dev_info.RelIO);
+	pr_info("Relocate IO address: %Lx [%08lx]\n",
+	       (u64) pci_resource_start(pdev, 2),
+	       xgifb_info->vga_base);
 
 	if (pci_enable_device(pdev)) {
 		ret = -EIO;
@@ -1927,7 +1896,7 @@
 		xgifb_info->display2_force = true;
 	}
 
-	XGIRegInit(&xgifb_info->dev_info, (unsigned long)hw_info->pjIOAddress);
+	XGIRegInit(&xgifb_info->dev_info, xgifb_info->vga_base);
 
 	xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD);
 	reg1 = xgifb_reg_get(XGISR, IND_SIS_PASSWORD);
@@ -1950,9 +1919,6 @@
 	case PCI_DEVICE_ID_XGI_40:
 		xgifb_info->chip = XG40;
 		break;
-	case PCI_DEVICE_ID_XGI_41:
-		xgifb_info->chip = XG41;
-		break;
 	case PCI_DEVICE_ID_XGI_42:
 		xgifb_info->chip = XG42;
 		break;
@@ -2006,13 +1972,13 @@
 	xgifb_info->mmio_vbase = ioremap(xgifb_info->mmio_base,
 					    xgifb_info->mmio_size);
 
-	pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
-	       xgifb_info->video_base,
+	pr_info("Framebuffer at 0x%Lx, mapped to 0x%p, size %dk\n",
+	       (u64) xgifb_info->video_base,
 	       xgifb_info->video_vbase,
 	       xgifb_info->video_size / 1024);
 
-	pr_info("MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
-	       xgifb_info->mmio_base, xgifb_info->mmio_vbase,
+	pr_info("MMIO at 0x%Lx, mapped to 0x%p, size %ldk\n",
+	       (u64) xgifb_info->mmio_base, xgifb_info->mmio_vbase,
 	       xgifb_info->mmio_size / 1024);
 
 	pci_set_drvdata(pdev, xgifb_info);
@@ -2174,8 +2140,7 @@
 		xgifb_info->refresh_rate = 60;
 	if (XGIfb_search_refresh_rate(xgifb_info,
 			xgifb_info->refresh_rate) == 0) {
-		xgifb_info->rate_idx =
-			XGIbios_mode[xgifb_info->mode_idx].rate_idx;
+		xgifb_info->rate_idx = 1;
 		xgifb_info->refresh_rate = 60;
 	}
 
diff --git a/drivers/staging/xgifb/XGIfb.h b/drivers/staging/xgifb/XGIfb.h
index 37bb730..9068c5a 100644
--- a/drivers/staging/xgifb/XGIfb.h
+++ b/drivers/staging/xgifb/XGIfb.h
@@ -23,9 +23,7 @@
 
 enum XGI_CHIP_TYPE {
 	XG40 = 32,
-	XG41,
 	XG42,
-	XG45,
 	XG20 = 48,
 	XG21,
 	XG27,
@@ -66,9 +64,9 @@
 
 	int           chip_id;
 	unsigned int  video_size;
-	unsigned long video_base;
+	phys_addr_t   video_base;
 	void __iomem *video_vbase;
-	unsigned long mmio_base;
+	phys_addr_t   mmio_base;
 	unsigned long mmio_size;
 	void __iomem *mmio_vbase;
 	unsigned long vga_base;
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index 3650bbf..c222d61 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -353,7 +353,6 @@
 		XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
 
 		switch (HwDeviceExtension->jChipType) {
-		case XG41:
 		case XG42:
 			/* CR82 */
 			xgifb_reg_set(P3d4,
@@ -556,8 +555,7 @@
 		xgifb_reg_set(P3d4, (0x8A + j),
 				pVBInfo->CR40[1 + j][pVBInfo->ram_type]);
 
-	if ((HwDeviceExtension->jChipType == XG41) ||
-	    (HwDeviceExtension->jChipType == XG42))
+	if (HwDeviceExtension->jChipType == XG42)
 		xgifb_reg_set(P3d4, 0x8C, 0x87);
 
 	xgifb_reg_set(P3d4,
@@ -854,78 +852,6 @@
 		pVBInfo->ram_channel = 1; /* Single channel */
 		xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x51); /* 32Mx16 bit*/
 		break;
-	case XG41:
-		if (XGINew_CheckFrequence(pVBInfo) == 1) {
-			pVBInfo->ram_bus = 32; /* 32 bits */
-			pVBInfo->ram_channel = 3; /* Quad Channel */
-			xgifb_reg_set(pVBInfo->P3c4, 0x13, 0xA1);
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x4C);
-
-			if (XGINew_ReadWriteRest(25, 23, pVBInfo) == 1)
-				return;
-
-			pVBInfo->ram_channel = 2; /* Dual channels */
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x48);
-
-			if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
-				return;
-
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x49);
-
-			if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
-				return;
-
-			pVBInfo->ram_channel = 3;
-			xgifb_reg_set(pVBInfo->P3c4, 0x13, 0x21);
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x3C);
-
-			if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
-				return;
-
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x38);
-
-			if (XGINew_ReadWriteRest(8, 4, pVBInfo) == 1)
-				return;
-			else
-				xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x39);
-		} else { /* DDR */
-			pVBInfo->ram_bus = 64; /* 64 bits */
-			pVBInfo->ram_channel = 2; /* Dual channels */
-			xgifb_reg_set(pVBInfo->P3c4, 0x13, 0xA1);
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x5A);
-
-			if (XGINew_ReadWriteRest(25, 24, pVBInfo) == 1)
-				return;
-
-			pVBInfo->ram_channel = 1; /* Single channels */
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x52);
-
-			if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
-				return;
-
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x53);
-
-			if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
-				return;
-
-			pVBInfo->ram_channel = 2; /* Dual channels */
-			xgifb_reg_set(pVBInfo->P3c4, 0x13, 0x21);
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x4A);
-
-			if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
-				return;
-
-			pVBInfo->ram_channel = 1; /* Single channels */
-			xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x42);
-
-			if (XGINew_ReadWriteRest(8, 4, pVBInfo) == 1)
-				return;
-			else
-				xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x43);
-		}
-
-		break;
-
 	case XG42:
 		/*
 		 XG42 SR14 D[3] Reserve
@@ -1478,7 +1404,7 @@
 
 	pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress;
 
-	pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress;
+	pVBInfo->BaseAddr = xgifb_info->vga_base;
 
 	/* Newdebugcode(0x99); */
 
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index 60d4adf..b2f4338 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -16,36 +16,6 @@
 
 #define  IndexMask 0xff
 
-static const unsigned short XGINew_MDA_DAC[] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
-	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
-	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
-	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
-	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F};
-
-static const unsigned short XGINew_CGA_DAC[] = {
-	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
-	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
-	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
-	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
-	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
-	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
-	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
-	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F};
-
-static const unsigned short XGINew_EGA_DAC[] = {
-	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
-	0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
-	0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
-	0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
-	0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
-	0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
-	0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
-	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F};
-
 static const unsigned short XGINew_VGA_DAC[] = {
 	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
 	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
@@ -60,8 +30,7 @@
 
 void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
 {
-	pVBInfo->SModeIDTable = (struct XGI_StStruct *) XGI330_SModeIDTable;
-	pVBInfo->StandTable = (struct SiS_StandTable_S *) XGI330_StandTable;
+	pVBInfo->StandTable = (struct SiS_StandTable_S *) &XGI330_StandTable;
 	pVBInfo->EModeIDTable = (struct XGI_ExtStruct *) XGI330_EModeIDTable;
 	pVBInfo->RefIndex = (struct XGI_Ext2Struct *) XGI330_RefIndex;
 	pVBInfo->XGINEWUB_CRT1Table
@@ -182,38 +151,17 @@
 
 }
 
-static unsigned char XGI_GetModePtr(unsigned short ModeNo,
-				    unsigned short ModeIdIndex,
-				    struct vb_device_info *pVBInfo)
-{
-	unsigned char index;
-
-	if (ModeNo <= 0x13)
-		index = pVBInfo->SModeIDTable[ModeIdIndex].St_StTableIndex;
-	else {
-		if (pVBInfo->ModeType <= 0x02)
-			index = 0x1B; /* 02 -> ModeEGA */
-		else
-			index = 0x0F;
-	}
-	return index; /* Get pVBInfo->StandTable index */
-}
-
 static void XGI_SetSeqRegs(unsigned short ModeNo,
-			   unsigned short StandTableIndex,
 			   unsigned short ModeIdIndex,
 			   struct vb_device_info *pVBInfo)
 {
 	unsigned char tempah, SRdata;
 	unsigned short i, modeflag;
 
-	if (ModeNo <= 0x13)
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	xgifb_reg_set(pVBInfo->P3c4, 0x00, 0x03); /* Set SR0 */
-	tempah = pVBInfo->StandTable[StandTableIndex].SR[0];
+	tempah = pVBInfo->StandTable->SR[0];
 
 	i = XGI_SetCRT2ToLCDA;
 	if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
@@ -230,13 +178,12 @@
 
 	for (i = 02; i <= 04; i++) {
 		/* Get SR2,3,4 from file */
-		SRdata = pVBInfo->StandTable[StandTableIndex].SR[i - 1];
+		SRdata = pVBInfo->StandTable->SR[i - 1];
 		xgifb_reg_set(pVBInfo->P3c4, i, SRdata); /* Set SR2 3 4 */
 	}
 }
 
 static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension,
-			    unsigned short StandTableIndex,
 			    struct vb_device_info *pVBInfo)
 {
 	unsigned char CRTCdata;
@@ -248,26 +195,22 @@
 
 	for (i = 0; i <= 0x18; i++) {
 		/* Get CRTC from file */
-		CRTCdata = pVBInfo->StandTable[StandTableIndex].CRTC[i];
+		CRTCdata = pVBInfo->StandTable->CRTC[i];
 		xgifb_reg_set(pVBInfo->P3d4, i, CRTCdata); /* Set CRTC(3d4) */
 	}
 }
 
 static void XGI_SetATTRegs(unsigned short ModeNo,
-			   unsigned short StandTableIndex,
 			   unsigned short ModeIdIndex,
 			   struct vb_device_info *pVBInfo)
 {
 	unsigned char ARdata;
 	unsigned short i, modeflag;
 
-	if (ModeNo <= 0x13)
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	for (i = 0; i <= 0x13; i++) {
-		ARdata = pVBInfo->StandTable[StandTableIndex].ATTR[i];
+		ARdata = pVBInfo->StandTable->ATTR[i];
 		if (modeflag & Charx8Dot) { /* ifndef Dot9 */
 			if (i == 0x13) {
 				if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
@@ -295,15 +238,14 @@
 	outb(0x20, pVBInfo->P3c0);
 }
 
-static void XGI_SetGRCRegs(unsigned short StandTableIndex,
-			   struct vb_device_info *pVBInfo)
+static void XGI_SetGRCRegs(struct vb_device_info *pVBInfo)
 {
 	unsigned char GRdata;
 	unsigned short i;
 
 	for (i = 0; i <= 0x08; i++) {
 		/* Get GR from file */
-		GRdata = pVBInfo->StandTable[StandTableIndex].GRC[i];
+		GRdata = pVBInfo->StandTable->GRC[i];
 		xgifb_reg_set(pVBInfo->P3ce, i, GRdata); /* Set GR(3ce) */
 	}
 
@@ -344,12 +286,7 @@
 {
 	unsigned short tempax, tempbx, resinfo, modeflag, infoflag;
 
-	if (ModeNo <= 0x13)
-		/* si+St_ModeFlag */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 	resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
 	tempbx = pVBInfo->RefIndex[RefreshRateTableIndex + (*i)].ModeID;
 	tempax = 0;
@@ -584,11 +521,7 @@
 	data &= 0x80;
 	data = data >> 2;
 
-	if (ModeNo <= 0x13)
-		i = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		i = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+	i = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 	i &= DoubleScanMode;
 	if (i)
 		data |= 0x80;
@@ -641,158 +574,97 @@
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
-	unsigned char StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx;
+	unsigned char index, Tempax, Tempbx, Tempcx, Tempdx;
 	unsigned short Temp1, Temp2, Temp3;
 
-	if (ModeNo <= 0x13) {
-		StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
-		/* CR04 HRS */
-		Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[4];
-		/* SR2E [7:0]->HRS */
-		xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
-		/* Tempbx: CR05 HRE */
-		Tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[5];
-		Tempbx &= 0x1F; /* Tempbx: HRE[4:0] */
-		Tempcx = Tempax;
-		Tempcx &= 0xE0; /* Tempcx: HRS[7:5] */
-		Tempdx = Tempcx | Tempbx; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */
-		if (Tempbx < (Tempax & 0x1F)) /* IF HRE < HRS */
-			Tempdx |= 0x20; /* Tempdx: HRE = HRE + 0x20 */
-		Tempdx <<= 2; /* Tempdx << 2 */
-		/* SR2F [7:2]->HRE */
-		xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempdx);
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
+	index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+	/* Tempax: CR4 HRS */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
+	Tempcx = Tempax; /* Tempcx: HRS */
+	/* SR2E[7:0]->HRS */
+	xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
 
-		/* Tempax: CR16 VRS */
-		Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[16];
-		Tempbx = Tempax; /* Tempbx=Tempax */
-		Tempax &= 0x01; /* Tempax: VRS[0] */
-		xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS */
+	Tempdx = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SRB */
+	Tempdx &= 0xC0; /* Tempdx[7:6]: SRB[7:6] */
+	Temp1 = Tempdx; /* Temp1[7:6]: HRS[9:8] */
+	Temp1 <<= 2; /* Temp1[9:8]: HRS[9:8] */
+	Temp1 |= Tempax; /* Temp1[9:0]: HRS[9:0] */
 
-		/* Tempax: CR7 VRS */
-		Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[7];
-		Tempdx = Tempbx >> 1; /* Tempdx: VRS[7:1] */
-		Tempcx = Tempax & 0x04; /* Tempcx: CR7[2] */
-		Tempcx <<= 5; /* Tempcx[7]: VRS[8] */
-		Tempdx |= Tempcx; /* Tempdx: VRS[8:1] */
-		/* SR34[7:0]: VRS[8:1] */
-		xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempdx);
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
+	Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
 
-		/* Temp1[8]: VRS[8] unsigned char -> unsigned short */
-		Temp1 = Tempcx << 1;
-		Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */
-		Tempax &= 0x80; /* Tempax[7]: CR7[7] */
-		Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */
-		Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */
+	Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
+	Tempbx &= 0x04; /* Tempbx[2]: HRE[5] */
+	Tempbx <<= 3; /* Tempbx[5]: HRE[5] */
+	Tempax |= Tempbx; /* Tempax[5:0]: HRE[5:0] */
 
-		/* CR16 VRE */
-		Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[17];
-		Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
-		Temp2 = Temp1 & 0x3F0; /* Temp2[9:4]: VRS[9:4] */
-		Temp2 |= Tempax; /* Temp2[9:0]: VRE[9:0] */
-		Temp3 = Temp1 & 0x0F; /* Temp3[3:0]: VRS[3:0] */
-		if (Tempax < Temp3) /* VRE[3:0]<VRS[3:0] */
-			Temp2 |= 0x10; /* Temp2: VRE + 0x10 */
-		Temp2 &= 0xFF; /* Temp2[7:0]: VRE[7:0] */
-		Tempax = (unsigned char) Temp2; /* Tempax[7:0]: VRE[7:0] */
-		Tempax <<= 2; /* Tempax << 2: VRE[5:0] */
-		Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */
-		Temp1 >>= 9; /* [10:9]->[1:0] */
-		Tempbx = (unsigned char) Temp1; /* Tempbx[1:0]: VRS[10:9] */
-		Tempax |= Tempbx; /* VRE[5:0]VRS[10:9] */
-		Tempax &= 0x7F;
-		/* SR3F D[7:2]->VRE D[1:0]->VRS */
-		xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
-	} else {
-		index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-		/* Tempax: CR4 HRS */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
-		Tempcx = Tempax; /* Tempcx: HRS */
-		/* SR2E[7:0]->HRS */
-		xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
+	Temp2 = Temp1 & 0x3C0; /* Temp2[9:6]: HRS[9:6] */
+	Temp2 |= Tempax; /* Temp2[9:0]: HRE[9:0] */
 
-		Tempdx = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SRB */
-		Tempdx &= 0xC0; /* Tempdx[7:6]: SRB[7:6] */
-		Temp1 = Tempdx; /* Temp1[7:6]: HRS[9:8] */
-		Temp1 <<= 2; /* Temp1[9:8]: HRS[9:8] */
-		Temp1 |= Tempax; /* Temp1[9:0]: HRS[9:0] */
+	Tempcx &= 0x3F; /* Tempcx[5:0]: HRS[5:0] */
+	if (Tempax < Tempcx) /* HRE < HRS */
+		Temp2 |= 0x40; /* Temp2 + 0x40 */
 
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
-		Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
+	Temp2 &= 0xFF;
+	Tempax = (unsigned char) Temp2; /* Tempax: HRE[7:0] */
+	Tempax <<= 2; /* Tempax[7:2]: HRE[5:0] */
+	Tempdx >>= 6; /* Tempdx[7:6]->[1:0] HRS[9:8] */
+	Tempax |= Tempdx; /* HRE[5:0]HRS[9:8] */
+	/* SR2F D[7:2]->HRE, D[1:0]->HRS */
+	xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
+	xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
 
-		Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
-		Tempbx &= 0x04; /* Tempbx[2]: HRE[5] */
-		Tempbx <<= 3; /* Tempbx[5]: HRE[5] */
-		Tempax |= Tempbx; /* Tempax[5:0]: HRE[5:0] */
+	/* CR10 VRS */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
+	Tempbx = Tempax; /* Tempbx: VRS */
+	Tempax &= 0x01; /* Tempax[0]: VRS[0] */
+	xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS[0] */
+	/* CR7[2][7] VRE */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
+	Tempcx = Tempbx >> 1; /* Tempcx[6:0]: VRS[7:1] */
+	Tempdx = Tempax & 0x04; /* Tempdx[2]: CR7[2] */
+	Tempdx <<= 5; /* Tempdx[7]: VRS[8] */
+	Tempcx |= Tempdx; /* Tempcx[7:0]: VRS[8:1] */
+	xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempcx); /* SR34[8:1]->VRS */
 
-		Temp2 = Temp1 & 0x3C0; /* Temp2[9:6]: HRS[9:6] */
-		Temp2 |= Tempax; /* Temp2[9:0]: HRE[9:0] */
+	Temp1 = Tempdx; /* Temp1[7]: Tempdx[7] */
+	Temp1 <<= 1; /* Temp1[8]: VRS[8] */
+	Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */
+	Tempax &= 0x80;
+	Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */
+	Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */
+	/* Tempax: SRA */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+	Tempax &= 0x08; /* Tempax[3]: VRS[3] */
+	Temp2 = Tempax;
+	Temp2 <<= 7; /* Temp2[10]: VRS[10] */
+	Temp1 |= Temp2; /* Temp1[10:0]: VRS[10:0] */
 
-		Tempcx &= 0x3F; /* Tempcx[5:0]: HRS[5:0] */
-		if (Tempax < Tempcx) /* HRE < HRS */
-			Temp2 |= 0x40; /* Temp2 + 0x40 */
+	/* Tempax: CR11 VRE */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
+	Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
+	/* Tempbx: SRA */
+	Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+	Tempbx &= 0x20; /* Tempbx[5]: VRE[5] */
+	Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
+	Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
+	Temp2 = Temp1 & 0x7E0; /* Temp2[10:5]: VRS[10:5] */
+	Temp2 |= Tempax; /* Temp2[10:5]: VRE[10:5] */
 
-		Temp2 &= 0xFF;
-		Tempax = (unsigned char) Temp2; /* Tempax: HRE[7:0] */
-		Tempax <<= 2; /* Tempax[7:2]: HRE[5:0] */
-		Tempdx >>= 6; /* Tempdx[7:6]->[1:0] HRS[9:8] */
-		Tempax |= Tempdx; /* HRE[5:0]HRS[9:8] */
-		/* SR2F D[7:2]->HRE, D[1:0]->HRS */
-		xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
+	Temp3 = Temp1 & 0x1F; /* Temp3[4:0]: VRS[4:0] */
+	if (Tempax < Temp3) /* VRE < VRS */
+		Temp2 |= 0x20; /* VRE + 0x20 */
 
-		/* CR10 VRS */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
-		Tempbx = Tempax; /* Tempbx: VRS */
-		Tempax &= 0x01; /* Tempax[0]: VRS[0] */
-		xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS[0] */
-		/* CR7[2][7] VRE */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
-		Tempcx = Tempbx >> 1; /* Tempcx[6:0]: VRS[7:1] */
-		Tempdx = Tempax & 0x04; /* Tempdx[2]: CR7[2] */
-		Tempdx <<= 5; /* Tempdx[7]: VRS[8] */
-		Tempcx |= Tempdx; /* Tempcx[7:0]: VRS[8:1] */
-		xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempcx); /* SR34[8:1]->VRS */
-
-		Temp1 = Tempdx; /* Temp1[7]: Tempdx[7] */
-		Temp1 <<= 1; /* Temp1[8]: VRS[8] */
-		Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */
-		Tempax &= 0x80;
-		Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */
-		Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */
-		/* Tempax: SRA */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
-		Tempax &= 0x08; /* Tempax[3]: VRS[3] */
-		Temp2 = Tempax;
-		Temp2 <<= 7; /* Temp2[10]: VRS[10] */
-		Temp1 |= Temp2; /* Temp1[10:0]: VRS[10:0] */
-
-		/* Tempax: CR11 VRE */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
-		Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
-		/* Tempbx: SRA */
-		Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
-		Tempbx &= 0x20; /* Tempbx[5]: VRE[5] */
-		Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
-		Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
-		Temp2 = Temp1 & 0x7E0; /* Temp2[10:5]: VRS[10:5] */
-		Temp2 |= Tempax; /* Temp2[10:5]: VRE[10:5] */
-
-		Temp3 = Temp1 & 0x1F; /* Temp3[4:0]: VRS[4:0] */
-		if (Tempax < Temp3) /* VRE < VRS */
-			Temp2 |= 0x20; /* VRE + 0x20 */
-
-		Temp2 &= 0xFF;
-		Tempax = (unsigned char) Temp2; /* Tempax: VRE[7:0] */
-		Tempax <<= 2; /* Tempax[7:0]; VRE[5:0]00 */
-		Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */
-		Temp1 >>= 9; /* Temp1[1:0]: VRS[10:9] */
-		Tempbx = (unsigned char) Temp1;
-		Tempax |= Tempbx; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */
-		Tempax &= 0x7F;
-		/* SR3F D[7:2]->VRE D[1:0]->VRS */
-		xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
-	}
+	Temp2 &= 0xFF;
+	Tempax = (unsigned char) Temp2; /* Tempax: VRE[7:0] */
+	Tempax <<= 2; /* Tempax[7:0]; VRE[5:0]00 */
+	Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */
+	Temp1 >>= 9; /* Temp1[1:0]: VRS[10:9] */
+	Tempbx = (unsigned char) Temp1;
+	Tempax |= Tempbx; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */
+	Tempax &= 0x7F;
+	/* SR3F D[7:2]->VRE D[1:0]->VRS */
+	xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
 }
 
 static void XGI_SetXG27CRTC(unsigned short ModeNo,
@@ -800,139 +672,88 @@
 			    unsigned short RefreshRateTableIndex,
 			    struct vb_device_info *pVBInfo)
 {
-	unsigned short StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx;
+	unsigned short index, Tempax, Tempbx, Tempcx;
 
-	if (ModeNo <= 0x13) {
-		StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
-		/* CR04 HRS */
-		Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[4];
-		/* SR2E [7:0]->HRS */
-		xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
-		/* Tempbx: CR05 HRE */
-		Tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[5];
-		Tempbx &= 0x1F; /* Tempbx: HRE[4:0] */
-		Tempcx = Tempax;
-		Tempcx &= 0xE0; /* Tempcx: HRS[7:5] */
-		Tempdx = Tempcx | Tempbx; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */
-		if (Tempbx < (Tempax & 0x1F)) /* IF HRE < HRS */
-			Tempdx |= 0x20; /* Tempdx: HRE = HRE + 0x20 */
-		Tempdx <<= 2; /* Tempdx << 2 */
-		/* SR2F [7:2]->HRE */
-		xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempdx);
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
+	index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+	/* Tempax: CR4 HRS */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
+	Tempbx = Tempax; /* Tempbx: HRS[7:0] */
+	/* SR2E[7:0]->HRS */
+	xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
 
-		/* Tempax: CR10 VRS */
-		Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[16];
-		xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax); /* SR34[7:0]->VRS */
-		Tempcx = Tempax; /* Tempcx=Tempax=VRS[7:0] */
-		/* Tempax[7][2]: CR7[7][2] VRS[9][8] */
-		Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[7];
-		Tempbx = Tempax; /* Tempbx=CR07 */
-		Tempax &= 0x04; /* Tempax[2]: CR07[2] VRS[8] */
-		Tempax >>= 2;
-		/* SR35 D[0]->VRS D[8] */
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax);
-		Tempcx |= (Tempax << 8); /* Tempcx[8] |= VRS[8] */
-		Tempcx |= (Tempbx & 0x80) << 2; /* Tempcx[9] |= VRS[9] */
+	/* SR0B */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5];
+	Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
+	Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */
 
-		/* CR11 VRE */
-		Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[17];
-		Tempax &= 0x0F; /* Tempax: VRE[3:0] */
-		Tempbx = Tempcx; /* Tempbx=Tempcx=VRS[9:0] */
-		Tempbx &= 0x3F0; /* Tempbx[9:4]: VRS[9:4] */
-		Tempbx |= Tempax; /* Tempbx[9:0]: VRE[9:0] */
-		if (Tempax <= (Tempcx & 0x0F)) /* VRE[3:0]<=VRS[3:0] */
-			Tempbx |= 0x10; /* Tempbx: VRE + 0x10 */
-		/* Tempax[7:0]: VRE[7:0] */
-		Tempax = (unsigned char) Tempbx & 0xFF;
-		Tempax <<= 2; /* Tempax << 2: VRE[5:0] */
-		Tempcx = (Tempcx & 0x600) >> 8; /* Tempcx VRS[10:9] */
-		/* SR3F D[7:2]->VRE D[5:0] */
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax);
-		/* SR35 D[2:1]->VRS[10:9] */
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x06, Tempcx);
-	} else {
-		index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-		/* Tempax: CR4 HRS */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
-		Tempbx = Tempax; /* Tempbx: HRS[7:0] */
-		/* SR2E[7:0]->HRS */
-		xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
+	Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
+	Tempcx = Tempax; /* Tempcx: HRE[4:0] */
 
-		/* SR0B */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5];
-		Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
-		Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
+	Tempax &= 0x04; /* Tempax[2]: HRE[5] */
+	Tempax <<= 3; /* Tempax[5]: HRE[5] */
+	Tempcx |= Tempax; /* Tempcx[5:0]: HRE[5:0] */
 
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
-		Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
-		Tempcx = Tempax; /* Tempcx: HRE[4:0] */
+	Tempbx = Tempbx & 0x3C0; /* Tempbx[9:6]: HRS[9:6] */
+	Tempbx |= Tempcx; /* Tempbx: HRS[9:6]HRE[5:0] */
 
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
-		Tempax &= 0x04; /* Tempax[2]: HRE[5] */
-		Tempax <<= 3; /* Tempax[5]: HRE[5] */
-		Tempcx |= Tempax; /* Tempcx[5:0]: HRE[5:0] */
+	/* Tempax: CR4 HRS */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
+	Tempax &= 0x3F; /* Tempax: HRS[5:0] */
+	if (Tempcx <= Tempax) /* HRE[5:0] < HRS[5:0] */
+		Tempbx += 0x40; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/
 
-		Tempbx = Tempbx & 0x3C0; /* Tempbx[9:6]: HRS[9:6] */
-		Tempbx |= Tempcx; /* Tempbx: HRS[9:6]HRE[5:0] */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SR0B */
+	Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
+	Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/
+	Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */
+	/* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */
+	xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
+	xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
 
-		/* Tempax: CR4 HRS */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
-		Tempax &= 0x3F; /* Tempax: HRS[5:0] */
-		if (Tempcx <= Tempax) /* HRE[5:0] < HRS[5:0] */
-			Tempbx += 0x40; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/
+	/* CR10 VRS */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
+	/* SR34[7:0]->VRS[7:0] */
+	xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax);
 
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SR0B */
-		Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
-		Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/
-		Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */
-		/* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */
-		xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
+	Tempcx = Tempax; /* Tempcx <= VRS[7:0] */
+	/* CR7[7][2] VRS[9][8] */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
+	Tempbx = Tempax; /* Tempbx <= CR07[7:0] */
+	Tempax = Tempax & 0x04; /* Tempax[2]: CR7[2]: VRS[8] */
+	Tempax >>= 2; /* Tempax[0]: VRS[8] */
+	/* SR35[0]: VRS[8] */
+	xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax);
+	Tempcx |= (Tempax << 8); /* Tempcx <= VRS[8:0] */
+	Tempcx |= ((Tempbx & 0x80) << 2); /* Tempcx <= VRS[9:0] */
+	/* Tempax: SR0A */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+	Tempax &= 0x08; /* SR0A[3] VRS[10] */
+	Tempcx |= (Tempax << 7); /* Tempcx <= VRS[10:0] */
 
-		/* CR10 VRS */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
-		/* SR34[7:0]->VRS[7:0] */
-		xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax);
+	/* Tempax: CR11 VRE */
+	Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
+	Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
+	/* Tempbx: SR0A */
+	Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+	Tempbx &= 0x20; /* Tempbx[5]: SR0A[5]: VRE[4] */
+	Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
+	Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
+	Tempbx = Tempcx; /* Tempbx: VRS[10:0] */
+	Tempbx &= 0x7E0; /* Tempbx[10:5]: VRS[10:5] */
+	Tempbx |= Tempax; /* Tempbx: VRS[10:5]VRE[4:0] */
 
-		Tempcx = Tempax; /* Tempcx <= VRS[7:0] */
-		/* CR7[7][2] VRS[9][8] */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
-		Tempbx = Tempax; /* Tempbx <= CR07[7:0] */
-		Tempax = Tempax & 0x04; /* Tempax[2]: CR7[2]: VRS[8] */
-		Tempax >>= 2; /* Tempax[0]: VRS[8] */
-		/* SR35[0]: VRS[8] */
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax);
-		Tempcx |= (Tempax << 8); /* Tempcx <= VRS[8:0] */
-		Tempcx |= ((Tempbx & 0x80) << 2); /* Tempcx <= VRS[9:0] */
-		/* Tempax: SR0A */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
-		Tempax &= 0x08; /* SR0A[3] VRS[10] */
-		Tempcx |= (Tempax << 7); /* Tempcx <= VRS[10:0] */
+	if (Tempbx <= Tempcx) /* VRE <= VRS */
+		Tempbx |= 0x20; /* VRE + 0x20 */
 
-		/* Tempax: CR11 VRE */
-		Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
-		Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
-		/* Tempbx: SR0A */
-		Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
-		Tempbx &= 0x20; /* Tempbx[5]: SR0A[5]: VRE[4] */
-		Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
-		Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
-		Tempbx = Tempcx; /* Tempbx: VRS[10:0] */
-		Tempbx &= 0x7E0; /* Tempbx[10:5]: VRS[10:5] */
-		Tempbx |= Tempax; /* Tempbx: VRS[10:5]VRE[4:0] */
-
-		if (Tempbx <= Tempcx) /* VRE <= VRS */
-			Tempbx |= 0x20; /* VRE + 0x20 */
-
-		/* Tempax: Tempax[7:0]; VRE[5:0]00 */
-		Tempax = (Tempbx << 2) & 0xFF;
-		/* SR3F[7:2]:VRE[5:0] */
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax);
-		Tempax = Tempcx >> 8;
-		/* SR35[2:0]:VRS[10:8] */
-		xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x07, Tempax);
-	}
+	/* Tempax: Tempax[7:0]; VRE[5:0]00 */
+	Tempax = (Tempbx << 2) & 0xFF;
+	/* SR3F[7:2]:VRE[5:0] */
+	xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax);
+	Tempax = Tempcx >> 8;
+	/* SR35[2:0]:VRS[10:8] */
+	xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x07, Tempax);
 }
 
 static void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo)
@@ -954,7 +775,7 @@
 			  unsigned short RefreshRateTableIndex,
 			  unsigned short ModeNo)
 {
-	unsigned short Data, Temp, b3CC;
+	unsigned short Data, Temp;
 	unsigned short XGI_P3cc;
 
 	XGI_P3cc = pVBInfo->P3cc;
@@ -995,23 +816,13 @@
 	xgifb_reg_and(pVBInfo->P3c4, 0x30, ~0x20); /* Hsync polarity */
 	xgifb_reg_and(pVBInfo->P3c4, 0x35, ~0x80); /* Vsync polarity */
 
-	if (ModeNo <= 0x13) {
-		b3CC = (unsigned char) inb(XGI_P3cc);
-		if (b3CC & 0x40)
-			/* Hsync polarity */
-			xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20);
-		if (b3CC & 0x80)
-			/* Vsync polarity */
-			xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80);
-	} else {
-		Data = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-		if (Data & 0x4000)
-			/* Hsync polarity */
-			xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20);
-		if (Data & 0x8000)
-			/* Vsync polarity */
-			xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80);
-	}
+	Data = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+	if (Data & 0x4000)
+		/* Hsync polarity */
+		xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20);
+	if (Data & 0x8000)
+		/* Vsync polarity */
+		xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80);
 }
 
 /* --------------------------------------------------------------------- */
@@ -1024,30 +835,22 @@
 			       struct vb_device_info *pVBInfo,
 			       unsigned short RefreshRateTableIndex)
 {
-	int i, index = -1;
+	int index = -1;
 
 	xgifb_reg_and(pVBInfo->P3d4, 0x11, 0x7F); /* Unlock CR0~7 */
-	if (ModeNo <= 0x13) {
-		for (i = 0; i < 12; i++) {
-			if (ModeNo == pVBInfo->UpdateCRT1[i].ModeID)
-				index = i;
-		}
-	} else {
-		if (ModeNo == 0x2E &&
-		    (pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC ==
-							      RES640x480x60))
-			index = 12;
-		else if (ModeNo == 0x2E &&
-			 (pVBInfo->RefIndex[RefreshRateTableIndex].
+	if (ModeNo == 0x2E &&
+	    (pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC ==
+						      RES640x480x60))
+		index = 12;
+	else if (ModeNo == 0x2E && (pVBInfo->RefIndex[RefreshRateTableIndex].
 				Ext_CRT1CRTC == RES640x480x72))
-			index = 13;
-		else if (ModeNo == 0x2F)
-			index = 14;
-		else if (ModeNo == 0x50)
-			index = 15;
-		else if (ModeNo == 0x59)
-			index = 16;
-	}
+		index = 13;
+	else if (ModeNo == 0x2F)
+		index = 14;
+	else if (ModeNo == 0x50)
+		index = 15;
+	else if (ModeNo == 0x59)
+		index = 16;
 
 	if (index != -1) {
 		xgifb_reg_set(pVBInfo->P3d4, 0x02,
@@ -1061,20 +864,6 @@
 	}
 }
 
-static unsigned short XGI_GetResInfo(unsigned short ModeNo,
-		unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
-{
-	unsigned short resindex;
-
-	if (ModeNo <= 0x13)
-		/* si+St_ResInfo */
-		resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
-	else
-		/* si+Ext_ResInfo */
-		resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
-	return resindex;
-}
-
 static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension,
 		unsigned short ModeNo, unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
@@ -1084,33 +873,25 @@
 
 	unsigned char data;
 
-	resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
+	resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
 
-	if (ModeNo <= 0x13) {
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-		tempax = pVBInfo->StResInfo[resindex].HTotal;
-		tempbx = pVBInfo->StResInfo[resindex].VTotal;
-	} else {
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		tempax = pVBInfo->ModeResInfo[resindex].HTotal;
-		tempbx = pVBInfo->ModeResInfo[resindex].VTotal;
-	}
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	tempax = pVBInfo->ModeResInfo[resindex].HTotal;
+	tempbx = pVBInfo->ModeResInfo[resindex].VTotal;
 
 	if (modeflag & HalfDCLK)
 		tempax = tempax >> 1;
 
-	if (ModeNo > 0x13) {
-		if (modeflag & HalfDCLK)
-			tempax = tempax << 1;
+	if (modeflag & HalfDCLK)
+		tempax = tempax << 1;
 
-		temp = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+	temp = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
 
-		if (temp & InterlaceMode)
-			tempbx = tempbx >> 1;
+	if (temp & InterlaceMode)
+		tempbx = tempbx >> 1;
 
-		if (modeflag & DoubleScanMode)
-			tempbx = tempbx << 1;
-	}
+	if (modeflag & DoubleScanMode)
+		tempbx = tempbx << 1;
 
 	tempcx = 8;
 
@@ -1258,18 +1039,10 @@
 	unsigned short CRT2Index, VCLKIndex;
 	unsigned short modeflag, resinfo;
 
-	if (ModeNo <= 0x13) {
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-		resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
-		CRT2Index = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-	} else {
-		/* si+Ext_ResInfo */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
-		CRT2Index = pVBInfo->RefIndex[RefreshRateTableIndex].
-				Ext_CRT2CRTC;
-	}
+	/* si+Ext_ResInfo */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	CRT2Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
 
 	if (pVBInfo->IF_DEF_LVDS == 0) {
 		CRT2Index = CRT2Index >> 6; /*  for LCD */
@@ -1318,23 +1091,13 @@
 				VCLKIndex += 25;
 			}
 		} else { /* for CRT2 */
-			/* Port 3cch */
-			VCLKIndex = (unsigned char) inb((pVBInfo->P3ca + 0x02));
-			VCLKIndex = ((VCLKIndex >> 2) & 0x03);
-			if (ModeNo > 0x13) {
-				/* di+Ext_CRTVCLK */
-				VCLKIndex = pVBInfo->RefIndex[
-							RefreshRateTableIndex].
+			/* di+Ext_CRTVCLK */
+			VCLKIndex = pVBInfo->RefIndex[RefreshRateTableIndex].
 								Ext_CRTVCLK;
-				VCLKIndex &= IndexMask;
-			}
+			VCLKIndex &= IndexMask;
 		}
 	} else { /* LVDS */
-		if (ModeNo <= 0x13)
-			VCLKIndex = CRT2Index;
-		else
-			VCLKIndex = CRT2Index;
-
+		VCLKIndex = CRT2Index;
 		VCLKIndex = VCLKIndex >> 6;
 		if ((pVBInfo->LCDResInfo == Panel_800x600) ||
 		    (pVBInfo->LCDResInfo == Panel_320x480))
@@ -1431,27 +1194,13 @@
 	data &= 0xfe;
 	xgifb_reg_set(pVBInfo->P3c4, 0x3D, data); /* diable auto-threshold */
 
-	if (ModeNo > 0x13) {
-		xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x34);
-		data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
-		data &= 0xC0;
-		xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x30);
-		data = xgifb_reg_get(pVBInfo->P3c4, 0x3D);
-		data |= 0x01;
-		xgifb_reg_set(pVBInfo->P3c4, 0x3D, data);
-	} else {
-		if (HwDeviceExtension->jChipType == XG27) {
-			xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x0E);
-			data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
-			data &= 0xC0;
-			xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x20);
-		} else {
-			xgifb_reg_set(pVBInfo->P3c4, 0x08, 0xAE);
-			data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
-			data &= 0xF0;
-			xgifb_reg_set(pVBInfo->P3c4, 0x09, data);
-		}
-	}
+	xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x34);
+	data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
+	data &= 0xC0;
+	xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x30);
+	data = xgifb_reg_get(pVBInfo->P3c4, 0x3D);
+	data |= 0x01;
+	xgifb_reg_set(pVBInfo->P3c4, 0x3D, data);
 
 	if (HwDeviceExtension->jChipType == XG21)
 		XGI_SetXG21FPBits(pVBInfo); /* Fix SR9[7:6] can't read back */
@@ -1466,13 +1215,9 @@
 
 	unsigned char index;
 
-	if (ModeNo <= 0x13)
-		VCLK = 0;
-	else {
-		index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-		index &= IndexMask;
-		VCLK = pVBInfo->VCLKData[index].CLOCK;
-	}
+	index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+	index &= IndexMask;
+	VCLK = pVBInfo->VCLKData[index].CLOCK;
 
 	data = xgifb_reg_get(pVBInfo->P3c4, 0x32);
 	data &= 0xf3;
@@ -1508,44 +1253,26 @@
 	unsigned short data, data2, data3, infoflag = 0, modeflag, resindex,
 			xres;
 
-	if (ModeNo > 0x13) {
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].
-				Ext_InfoFlag;
-	} else
-		/* si+St_ModeFlag */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
 
 	if (xgifb_reg_get(pVBInfo->P3d4, 0x31) & 0x01)
 		xgifb_reg_and_or(pVBInfo->P3c4, 0x1F, 0x3F, 0x00);
 
-	if (ModeNo > 0x13)
-		data = infoflag;
-	else
-		data = 0;
-
+	data = infoflag;
 	data2 = 0;
-
-	if (ModeNo > 0x13) {
-		if (pVBInfo->ModeType > 0x02) {
-			data2 |= 0x02;
-			data3 = pVBInfo->ModeType - ModeVGA;
-			data3 = data3 << 2;
-			data2 |= data3;
-		}
-	}
-
+	data2 |= 0x02;
+	data3 = pVBInfo->ModeType - ModeVGA;
+	data3 = data3 << 2;
+	data2 |= data3;
 	data &= InterlaceMode;
 
 	if (data)
 		data2 |= 0x20;
 
 	xgifb_reg_and_or(pVBInfo->P3c4, 0x06, ~0x3F, data2);
-	resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
-	if (ModeNo <= 0x13)
-		xres = pVBInfo->StResInfo[resindex].HTotal;
-	else
-		xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+	resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
 
 	data = 0x0000;
 	if (infoflag & InterlaceMode) {
@@ -1568,18 +1295,10 @@
 	if (modeflag & LineCompareOff)
 		data2 |= 0x08;
 
-	if (ModeNo > 0x13) {
-		if (pVBInfo->ModeType == ModeEGA)
-			data2 |= 0x40;
-	}
-
 	xgifb_reg_and_or(pVBInfo->P3c4, 0x0F, ~0x48, data2);
 	data = 0x60;
-	if (pVBInfo->ModeType != ModeText) {
-		data = data ^ 0x60;
-		if (pVBInfo->ModeType != ModeEGA)
-			data = data ^ 0xA0;
-	}
+	data = data ^ 0x60;
+	data = data ^ 0xA0;
 	xgifb_reg_and_or(pVBInfo->P3c4, 0x21, 0x1F, data);
 
 	XGI_SetVCLKState(HwDeviceExtension, ModeNo, RefreshRateTableIndex,
@@ -1644,38 +1363,13 @@
 static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex,
 		struct vb_device_info *pVBInfo)
 {
-	unsigned short data, data2, time, i, j, k, m, n, o, si, di, bx, dl, al,
-			ah, dh;
-	const unsigned short *table = NULL;
-
-	if (ModeNo <= 0x13)
-		data = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		data = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
-	data &= DACInfoFlag;
-	time = 64;
-
-	if (data == 0x00)
-		table = XGINew_MDA_DAC;
-	else if (data == 0x08)
-		table = XGINew_CGA_DAC;
-	else if (data == 0x10)
-		table = XGINew_EGA_DAC;
-	else if (data == 0x18) {
-		time = 256;
-		table = XGINew_VGA_DAC;
-	}
-
-	if (time == 256)
-		j = 16;
-	else
-		j = time;
+	unsigned short data, data2, i, k, m, n, o, si, di, bx, dl, al, ah, dh;
+	const unsigned short *table = XGINew_VGA_DAC;
 
 	outb(0xFF, pVBInfo->P3c6);
 	outb(0x00, pVBInfo->P3c8);
 
-	for (i = 0; i < j; i++) {
+	for (i = 0; i < 16; i++) {
 		data = table[i];
 
 		for (k = 0; k < 3; k++) {
@@ -1692,45 +1386,43 @@
 		}
 	}
 
-	if (time == 256) {
-		for (i = 16; i < 32; i++) {
-			data = table[i];
+	for (i = 16; i < 32; i++) {
+		data = table[i];
 
-			for (k = 0; k < 3; k++)
-				outb(data, pVBInfo->P3c9);
-		}
+		for (k = 0; k < 3; k++)
+			outb(data, pVBInfo->P3c9);
+	}
 
-		si = 32;
+	si = 32;
 
-		for (m = 0; m < 9; m++) {
-			di = si;
-			bx = si + 0x04;
-			dl = 0;
+	for (m = 0; m < 9; m++) {
+		di = si;
+		bx = si + 0x04;
+		dl = 0;
 
-			for (n = 0; n < 3; n++) {
-				for (o = 0; o < 5; o++) {
-					dh = table[si];
-					ah = table[di];
-					al = table[bx];
-					si++;
-					XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
-				}
-
-				si -= 2;
-
-				for (o = 0; o < 3; o++) {
-					dh = table[bx];
-					ah = table[di];
-					al = table[si];
-					si--;
-					XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
-				}
-
-				dl++;
+		for (n = 0; n < 3; n++) {
+			for (o = 0; o < 5; o++) {
+				dh = table[si];
+				ah = table[di];
+				al = table[bx];
+				si++;
+				XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
 			}
 
-			si += 5;
+			si -= 2;
+
+			for (o = 0; o < 3; o++) {
+				dh = table[bx];
+				ah = table[di];
+				al = table[si];
+				si--;
+				XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
+			}
+
+			dl++;
 		}
+
+		si += 5;
 	}
 }
 
@@ -1740,34 +1432,20 @@
 {
 	unsigned short resindex, xres, yres, modeflag;
 
-	if (ModeNo <= 0x13)
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
-	else
-		/* si+Ext_ResInfo */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	/* si+Ext_ResInfo */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
 
-	if (ModeNo <= 0x13)
-		/* si+St_ResInfo */
-		resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
-	else
-		/* si+Ext_ResInfo */
-		resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	/* si+Ext_ResInfo */
+	resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
 
-	if (ModeNo <= 0x13) {
-		xres = pVBInfo->StResInfo[resindex].HTotal;
-		yres = pVBInfo->StResInfo[resindex].VTotal;
-	} else {
-		xres = pVBInfo->ModeResInfo[resindex].HTotal;
-		yres = pVBInfo->ModeResInfo[resindex].VTotal;
-	}
-	if (ModeNo > 0x13) {
-		if (modeflag & HalfDCLK)
-			xres = xres << 1;
+	xres = pVBInfo->ModeResInfo[resindex].HTotal;
+	yres = pVBInfo->ModeResInfo[resindex].VTotal;
 
-		if (modeflag & DoubleScanMode)
-			yres = yres << 1;
-	}
+	if (modeflag & HalfDCLK)
+		xres = xres << 1;
+
+	if (modeflag & DoubleScanMode)
+		yres = yres << 1;
 
 	if (xres == 720)
 		xres = 640;
@@ -1789,32 +1467,16 @@
 
 	tempbx = BX;
 
-	if (ModeNo <= 0x13) {
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-		tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-	} else {
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-	}
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
 
 	tempal = tempal & 0x0f;
 
 	if (tempbx <= 1) { /* ExpLink */
-		if (ModeNo <= 0x13) {
-			/* find no Ext_CRT2CRTC2 */
-			tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-		} else {
-			tempal = pVBInfo->RefIndex[RefreshRateTableIndex].
-					Ext_CRT2CRTC;
-		}
+		tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
 
 		if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
-			if (ModeNo <= 0x13)
-				tempal = pVBInfo->SModeIDTable[ModeIdIndex].
-						St_CRT2CRTC2;
-			else
-				tempal = pVBInfo->RefIndex[
-						RefreshRateTableIndex].
+			tempal = pVBInfo->RefIndex[RefreshRateTableIndex].
 							Ext_CRT2CRTC2;
 		}
 
@@ -1882,9 +1544,6 @@
 			tempbx = tempdi[i].MASK;
 			tempdx = pVBInfo->LCDInfo;
 
-			if (ModeNo <= 0x13) /* alan 09/10/2003 */
-				tempdx |= SetLCDStdMode;
-
 			if (modeflag & HalfDCLK)
 				tempdx |= SetLCDLowResolution;
 
@@ -2238,15 +1897,8 @@
 	struct XGI330_TVDataTablStruct *tempdi = NULL;
 
 	tempbx = BX;
-
-	if (ModeNo <= 0x13) {
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-		tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-	} else {
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-	}
-
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
 	tempal = tempal & 0x3f;
 	table = tempbx;
 
@@ -2413,11 +2065,7 @@
 	struct XGI_LVDSCRT1HDataStruct *LCDPtr = NULL;
 	struct XGI_LVDSCRT1VDataStruct *LCDPtr1 = NULL;
 
-	if (ModeNo <= 0x13)
-		index = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-	else
-		index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-
+	index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
 	index = index & IndexMask;
 
 	tempbx = 0;
@@ -2530,14 +2178,10 @@
 {
 	unsigned short tempbx, tempax, tempcx, tempdx, push1, push2, modeflag;
 	unsigned long temp, temp1, temp2, temp3, push3;
-	struct XGI330_LCDDataDesStruct *LCDPtr = NULL;
+	struct XGI_LCDDesStruct *LCDPtr = NULL;
 	struct XGI330_LCDDataDesStruct2 *LCDPtr1 = NULL;
 
-	if (ModeNo > 0x13)
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-	else
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 	tempbx = 3;
 	if (pVBInfo->LCDInfo & EnableScalingLCD)
 		LCDPtr1 =
@@ -2550,7 +2194,7 @@
 					  pVBInfo);
 	else
 		LCDPtr =
-		    (struct XGI330_LCDDataDesStruct *)
+		    (struct XGI_LCDDesStruct *)
 				XGI_GetLcdPtr(
 					  tempbx,
 					  ModeNo,
@@ -2829,12 +2473,8 @@
 	unsigned short index, modeflag;
 	unsigned char tempal;
 
-	if (ModeNo <= 0x13)
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		/* si+Ext_ResInfo */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	/* si+Ext_ResInfo */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	if ((pVBInfo->SetFlag & ProgrammingCRT2) &&
 	    (!(pVBInfo->LCDInfo & EnableScalingLCD))) { /* {LCDA/LCDB} */
@@ -2895,9 +2535,6 @@
 	if ((pVBInfo->LCDInfo & EnableScalingLCD) && (modeflag & Charx8Dot))
 		tempal = tempal ^ tempal; /* ; set to VCLK25MHz always */
 
-	if (ModeNo <= 0x13)
-		return tempal;
-
 	tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
 	return tempal;
 }
@@ -3079,11 +2716,7 @@
 {
 	unsigned short tempax, push, tempbx, temp, modeflag;
 
-	if (ModeNo <= 0x13)
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 	pVBInfo->SetFlag = 0;
 	pVBInfo->ModeType = modeflag & ModeTypeMask;
 	tempbx = 0;
@@ -3283,17 +2916,8 @@
 	resinfo = 0;
 
 	if (pVBInfo->VBInfo & SetCRT2ToTV) {
-		if (ModeNo <= 0x13) {
-			modeflag = pVBInfo->SModeIDTable[ModeIdIndex].
-					St_ModeFlag; /* si+St_ModeFlag */
-			resinfo = pVBInfo->SModeIDTable[ModeIdIndex].
-					St_ResInfo; /* si+St_ResInfo */
-		} else {
-			modeflag = pVBInfo->EModeIDTable[ModeIdIndex].
-					Ext_ModeFlag;
-			resinfo = pVBInfo->EModeIDTable[ModeIdIndex].
-					Ext_RESINFO; /* si+Ext_ResInfo */
-		}
+		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+		resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
 
 		if (pVBInfo->VBInfo & SetCRT2ToTV) {
 			temp = xgifb_reg_get(pVBInfo->P3d4, 0x35);
@@ -3380,15 +3004,9 @@
 	pVBInfo->LCDTypeInfo = 0;
 	pVBInfo->LCDInfo = 0;
 
-	if (ModeNo <= 0x13) {
-		/* si+St_ModeFlag // */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	} else {
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		/* si+Ext_ResInfo // */
-		resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
-	}
-
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	/* si+Ext_ResInfo // */
+	resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
 	temp = xgifb_reg_get(pVBInfo->P3d4, 0x36); /* Get LCD Res.Info */
 	tempbx = temp & 0x0F;
 
@@ -3442,8 +3060,8 @@
 
 	if (pVBInfo->IF_DEF_LVDS == 0) {
 		if ((pVBInfo->LCDResInfo == Panel_1400x1050) && (pVBInfo->VBInfo
-				& SetCRT2ToLCD) && (ModeNo > 0x13) && (resinfo
-				== 9) && (!(tempbx & EnableScalingLCD)))
+				& SetCRT2ToLCD) && (resinfo == 9) &&
+				(!(tempbx & EnableScalingLCD)))
 			/* set to center in 1280x1024 LCDB for Panel_1400x1050 */
 			tempbx |= SetLCDtoNonExpanding;
 	}
@@ -3453,12 +3071,9 @@
 			if (!(tempbx & SetLCDtoNonExpanding)) {
 				tempbx |= XGI_EnableLVDSDDA;
 			} else {
-				if (ModeNo > 0x13) {
-					if (pVBInfo->LCDResInfo
-							== Panel_1024x768) {
-						if (resinfo == 4) {/* 512x384 */
-							tempbx |= XGI_EnableLVDSDDA;
-						}
+				if (pVBInfo->LCDResInfo == Panel_1024x768) {
+					if (resinfo == 4) {/* 512x384 */
+						tempbx |= XGI_EnableLVDSDDA;
 					}
 				}
 			}
@@ -3474,56 +3089,17 @@
 
 	pVBInfo->LCDInfo = tempbx;
 
-	if (pVBInfo->IF_DEF_LVDS == 0) {
-		if (tempax & (LockLCDBToA | StLCDBToA)) {
-			if (pVBInfo->VBInfo & SetInSlaveMode) {
-				if (!(tempax & LockLCDBToA)) {
-					if (ModeNo <= 0x13) {
-						pVBInfo->VBInfo &=
-							~(SetSimuScanMode |
-							  SetInSlaveMode |
-							  SetCRT2ToLCD);
-						pVBInfo->VBInfo |=
-							XGI_SetCRT2ToLCDA |
-							SetCRT2ToDualEdge;
-					}
-				}
-			}
-		}
-	}
-
 	return 1;
 }
 
 unsigned char XGI_SearchModeID(unsigned short ModeNo,
 		unsigned short *ModeIdIndex, struct vb_device_info *pVBInfo)
 {
-	if (ModeNo <= 5)
-		ModeNo |= 1;
-	if (ModeNo <= 0x13) {
-		for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
-			if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID ==
-			    ModeNo)
-				break;
-			if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID ==
-			    0xFF)
-				return 0;
-		}
-
-		if (ModeNo == 0x07)
-			(*ModeIdIndex)++; /* 400 lines */
-		if (ModeNo <= 3)
-			(*ModeIdIndex) += 2; /* 400 lines */
-		/* else 350 lines */
-	} else {
-		for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
-			if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID ==
-			    ModeNo)
-				break;
-			if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID ==
-			    0xFF)
-				return 0;
-		}
+	for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
+		if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == ModeNo)
+			break;
+		if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+			return 0;
 	}
 
 	return 1;
@@ -3789,22 +3365,17 @@
 {
 	unsigned short xres, yres, modeflag, resindex;
 
-	resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
-	if (ModeNo <= 0x13) {
-		xres = pVBInfo->StResInfo[resindex].HTotal;
-		yres = pVBInfo->StResInfo[resindex].VTotal;
-	} else {
-		xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
-		yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
-		/* si+St_ModeFlag */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+	yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
+	/* si+St_ModeFlag */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-		if (modeflag & HalfDCLK)
-			xres *= 2;
+	if (modeflag & HalfDCLK)
+		xres *= 2;
 
-		if (modeflag & DoubleScanMode)
-			yres *= 2;
-	}
+	if (modeflag & DoubleScanMode)
+		yres *= 2;
 
 	if (pVBInfo->VBInfo & SetCRT2ToLCD) {
 		if (pVBInfo->IF_DEF_LVDS == 0) {
@@ -3868,37 +3439,23 @@
 			       struct vb_device_info *pVBInfo)
 {
 	unsigned short tempax, tempbx, temp1, temp2, modeflag = 0, tempcx,
-			StandTableIndex, CRT1Index;
+			CRT1Index;
 
 	pVBInfo->RVBHCMAX = 1;
 	pVBInfo->RVBHCFACT = 1;
-
-	if (ModeNo <= 0x13) {
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-		StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
-		tempax = pVBInfo->StandTable[StandTableIndex].CRTC[0];
-		tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[6];
-		temp1 = pVBInfo->StandTable[StandTableIndex].CRTC[7];
-	} else {
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].
-				Ext_CRT1CRTC;
-		CRT1Index &= IndexMask;
-		temp1 = (unsigned short) pVBInfo->
-			XGINEWUB_CRT1Table[CRT1Index].CR[0];
-		temp2 = (unsigned short) pVBInfo->
-			XGINEWUB_CRT1Table[CRT1Index].CR[5];
-		tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
-		tempbx = (unsigned short) pVBInfo->
-			XGINEWUB_CRT1Table[CRT1Index].CR[8];
-		tempcx = (unsigned short) pVBInfo->
-			XGINEWUB_CRT1Table[CRT1Index].CR[14] << 8;
-		tempcx &= 0x0100;
-		tempcx = tempcx << 2;
-		tempbx |= tempcx;
-		temp1 = (unsigned short) pVBInfo->
-			XGINEWUB_CRT1Table[CRT1Index].CR[9];
-	}
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+	CRT1Index &= IndexMask;
+	temp1 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[0];
+	temp2 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[5];
+	tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
+	tempbx = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[8];
+	tempcx = (unsigned short)
+			pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[14] << 8;
+	tempcx &= 0x0100;
+	tempcx = tempcx << 2;
+	tempbx |= tempcx;
+	temp1 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[9];
 
 	if (temp1 & 0x01)
 		tempbx |= 0x0100;
@@ -3928,16 +3485,9 @@
 	struct SiS_LCDData *LCDPtr = NULL;
 	struct SiS_TVData *TVPtr = NULL;
 
-	if (ModeNo <= 0x13) {
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-		resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
-	} else {
-		/* si+Ext_ResInfo */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
-	}
-
+	/* si+Ext_ResInfo */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
 	pVBInfo->NewFlickerMode = 0;
 	pVBInfo->RVBHRS = 50;
 
@@ -4141,11 +3691,7 @@
 	short index;
 	unsigned short modeflag;
 
-	if (ModeNo <= 0x13)
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 	index = (modeflag & ModeTypeMask) - ModeEGA;
 
 	if (index < 0)
@@ -4164,11 +3710,7 @@
 			ColorDepth[] = { 0x01, 0x02, 0x04 };
 
 	modeinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeInfo;
-	if (ModeNo <= 0x14)
-		infoflag = 0;
-	else
-		infoflag = pVBInfo->
-				RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+	infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
 
 	index = (modeinfo >> 8) & 0xFF;
 
@@ -4228,12 +3770,9 @@
 {
 	unsigned short tempcx = 0, CRT1Index = 0, resinfo = 0;
 
-	if (ModeNo > 0x13) {
-		CRT1Index = pVBInfo->
-				RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-		CRT1Index &= IndexMask;
-		resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
-	}
+	CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+	CRT1Index &= IndexMask;
+	resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
 
 	XGI_SetCRT2Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex,
 			HwDeviceExtension, pVBInfo);
@@ -4254,17 +3793,10 @@
 	unsigned short temp = 0, tempax = 0, tempbx = 0, tempcx = 0,
 			pushbx = 0, CRT1Index = 0, modeflag, resinfo = 0;
 
-	if (ModeNo > 0x13) {
-		CRT1Index = pVBInfo->
-				RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-		CRT1Index &= IndexMask;
-		resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
-	}
-
-	if (ModeNo <= 0x13)
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+	CRT1Index &= IndexMask;
+	resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	/* bainy change table name */
 	if (modeflag & HalfDCLK) {
@@ -4422,18 +3954,11 @@
 	unsigned short push1, push2, tempax, tempbx = 0, tempcx, temp, resinfo,
 			modeflag, CRT1Index;
 
-	if (ModeNo <= 0x13) {
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-		resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
-	} else {
-		/* si+Ext_ResInfo */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
-		CRT1Index = pVBInfo->
-				RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-		CRT1Index &= IndexMask;
-	}
+	/* si+Ext_ResInfo */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+	CRT1Index &= IndexMask;
 
 	if (!(pVBInfo->VBInfo & SetInSlaveMode))
 		return;
@@ -4500,8 +4025,7 @@
 			temp -= 6;
 			if (pVBInfo->TVInfo & TVSimuMode) {
 				temp -= 4;
-				if (ModeNo > 0x13)
-					temp -= 10;
+				temp -= 10;
 			}
 		}
 	} else {
@@ -4523,14 +4047,6 @@
 			if (pVBInfo->LCDResInfo != Panel_1280x960 &&
 			    pVBInfo->VGAHDE >= 800) {
 				temp -= 7;
-				if (pVBInfo->ModeType == ModeEGA &&
-				    pVBInfo->VGAVDE == 1024) {
-					temp += 15;
-					if (pVBInfo->LCDResInfo !=
-						Panel_1280x1024)
-						temp += 7;
-				}
-
 				if (pVBInfo->VGAHDE >= 1280 &&
 				    pVBInfo->LCDResInfo != Panel_1280x960 &&
 				    (pVBInfo->LCDInfo & LCDNonExpanding))
@@ -4546,48 +4062,7 @@
 
 	if (pVBInfo->VBInfo & SetCRT2ToTV) {
 		if (pVBInfo->TVInfo & TVSimuMode) {
-			if ((ModeNo == 0x06) || (ModeNo == 0x10) || (ModeNo
-					== 0x11) || (ModeNo == 0x13) || (ModeNo
-					== 0x0F)) {
-				xgifb_reg_set(pVBInfo->Part1Port, 0x07, 0x5b);
-				xgifb_reg_set(pVBInfo->Part1Port, 0x08, 0x03);
-			}
-
-			if ((ModeNo == 0x00) || (ModeNo == 0x01)) {
-				if (pVBInfo->TVInfo & SetNTSCTV) {
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x07, 0x2A);
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x08, 0x61);
-				} else {
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x07, 0x2A);
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x08, 0x41);
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x0C, 0xF0);
-				}
-			}
-
-			if ((ModeNo == 0x02) || (ModeNo == 0x03) || (ModeNo
-					== 0x07)) {
-				if (pVBInfo->TVInfo & SetNTSCTV) {
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x07, 0x54);
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x08, 0x00);
-				} else {
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x07, 0x55);
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x08, 0x00);
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x0C, 0xF0);
-				}
-			}
-
-			if ((ModeNo == 0x04) || (ModeNo == 0x05) || (ModeNo
-					== 0x0D) || (ModeNo == 0x50)) {
+			if (ModeNo == 0x50) {
 				if (pVBInfo->TVInfo & SetNTSCTV) {
 					xgifb_reg_set(pVBInfo->Part1Port,
 							0x07, 0x30);
@@ -4796,18 +4271,10 @@
 
 	unsigned long longtemp, tempeax, tempebx, temp2, tempecx;
 
-	if (ModeNo <= 0x13) {
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-		resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
-		crt2crtc = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-	} else {
-		/* si+Ext_ResInfo */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
-		crt2crtc = pVBInfo->RefIndex[RefreshRateTableIndex].
-				Ext_CRT2CRTC;
-	}
+	/* si+Ext_ResInfo */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	crt2crtc = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
 
 	tempax = 0;
 
@@ -5245,18 +4712,11 @@
 
 	struct XGI_LCDDesStruct *LCDBDesPtr = NULL;
 
-	if (ModeNo <= 0x13) {
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-		resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
-	} else {
-		/* si+Ext_ResInfo */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-		resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
-		CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].
-			Ext_CRT1CRTC;
-		CRT1Index &= IndexMask;
-	}
+	/* si+Ext_ResInfo */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+	CRT1Index &= IndexMask;
 
 	if (!(pVBInfo->VBInfo & SetCRT2ToLCD))
 		return;
@@ -5274,16 +4734,6 @@
 	xgifb_reg_and_or(pVBInfo->Part2Port, 0x2B, 0x0F, temp);
 	temp = 0x01;
 
-	if (pVBInfo->LCDResInfo == Panel_1280x1024) {
-		if (pVBInfo->ModeType == ModeEGA) {
-			if (pVBInfo->VGAHDE >= 1024) {
-				temp = 0x02;
-				if (pVBInfo->LCDInfo & XGI_LCDVESATiming)
-					temp = 0x01;
-			}
-		}
-	}
-
 	xgifb_reg_set(pVBInfo->Part2Port, 0x0B, temp);
 	tempbx = pVBInfo->VDE; /* RTVACTEO=(VDE-1)&0xFF */
 	push1 = tempbx;
@@ -5542,12 +4992,8 @@
 	unsigned char *tempdi;
 	unsigned short modeflag;
 
-	if (ModeNo <= 0x13)
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		/* si+Ext_ResInfo */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	/* si+Ext_ResInfo */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	xgifb_reg_set(pVBInfo->Part3Port, 0x00, 0x00);
 	if (pVBInfo->TVInfo & TVSetPAL) {
@@ -5605,13 +5051,8 @@
 
 	unsigned long tempebx, tempeax, templong;
 
-	if (ModeNo <= 0x13)
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		/* si+Ext_ResInfo */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+	/* si+Ext_ResInfo */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 	temp = pVBInfo->RVBHCFACT;
 	xgifb_reg_set(pVBInfo->Part4Port, 0x13, temp);
 
@@ -5818,32 +5259,22 @@
 {
 	unsigned short xres, yres, colordepth, modeflag, resindex;
 
-	resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
-	if (ModeNo <= 0x13) {
-		xres = pVBInfo->StResInfo[resindex].HTotal;
-		yres = pVBInfo->StResInfo[resindex].VTotal;
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	} else {
-		xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
-		yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
-		/* si+St_ModeFlag */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-	}
+	resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+	yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
+	/* si+St_ModeFlag */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	if (!(modeflag & Charx8Dot)) {
 		xres /= 9;
 		xres *= 8;
 	}
 
-	if (ModeNo > 0x13) {
-		if ((ModeNo > 0x13) && (modeflag & HalfDCLK))
-			xres *= 2;
+	if ((ModeNo > 0x13) && (modeflag & HalfDCLK))
+		xres *= 2;
 
-		if ((ModeNo > 0x13) && (modeflag & DoubleScanMode))
-			yres *= 2;
-
-	}
+	if ((ModeNo > 0x13) && (modeflag & DoubleScanMode))
+		yres *= 2;
 
 	if (xres > xgifb_info->lvds_data.LVDSHDE)
 		return 0;
@@ -5851,16 +5282,11 @@
 	if (yres > xgifb_info->lvds_data.LVDSVDE)
 		return 0;
 
-	if (ModeNo > 0x13) {
-		if (xres != xgifb_info->lvds_data.LVDSHDE ||
-		    yres != xgifb_info->lvds_data.LVDSVDE) {
-			colordepth = XGI_GetColorDepth(ModeNo,
-						       ModeIdIndex,
-						       pVBInfo);
-			if (colordepth > 2)
-				return 0;
-
-		}
+	if (xres != xgifb_info->lvds_data.LVDSHDE ||
+	    yres != xgifb_info->lvds_data.LVDSVDE) {
+		colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, pVBInfo);
+		if (colordepth > 2)
+			return 0;
 	}
 	return 1;
 }
@@ -5895,18 +5321,11 @@
 	else
 		XGI_SetXG21FPBits(pVBInfo);
 
-	resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
-	if (ModeNo <= 0x13) {
-		xres = pVBInfo->StResInfo[resindex].HTotal;
-		yres = pVBInfo->StResInfo[resindex].VTotal;
-		/* si+St_ResInfo */
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	} else {
-		xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
-		yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
-		/* si+St_ModeFlag */
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-	}
+	resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+	yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
+	/* si+St_ModeFlag */
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	if (!(modeflag & Charx8Dot))
 		xres = xres * 8 / 9;
@@ -5914,8 +5333,6 @@
 	LVDSHT = xgifb_info->lvds_data.LVDSHT;
 
 	LVDSHBS = xres + (xgifb_info->lvds_data.LVDSHDE - xres) / 2;
-	if ((ModeNo <= 0x13) && (modeflag & HalfDCLK))
-		LVDSHBS -= xres / 4;
 
 	if (LVDSHBS > LVDSHT)
 		LVDSHBS -= LVDSHT;
@@ -5933,7 +5350,7 @@
 	LVDSVT = xgifb_info->lvds_data.LVDSVT;
 
 	LVDSVBS = yres + (xgifb_info->lvds_data.LVDSVDE - yres) / 2;
-	if ((ModeNo > 0x13) && (modeflag & DoubleScanMode))
+	if (modeflag & DoubleScanMode)
 		LVDSVBS += yres / 2;
 
 	if (LVDSVBS > LVDSVT)
@@ -6527,7 +5944,7 @@
 			       unsigned short ModeIdIndex,
 			       struct vb_device_info *pVBInfo)
 {
-	unsigned short tempbx, index;
+	unsigned short tempbx;
 
 	unsigned char tempah;
 
@@ -6536,13 +5953,6 @@
 
 	tempbx = XGI_GetTVPtrIndex(pVBInfo);
 	tempbx &= 0xFE;
-
-	if (ModeNo <= 0x13)
-		index = pVBInfo->SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex;
-	else
-		index = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex;
-
-	tempbx += index;
 	tempah = TVAntiFlickList[tempbx];
 	tempah = tempah << 4;
 
@@ -6553,19 +5963,12 @@
 			       unsigned short ModeIdIndex,
 			       struct vb_device_info *pVBInfo)
 {
-	unsigned short tempbx, index;
+	unsigned short tempbx;
 
 	unsigned char tempah;
 
 	tempbx = XGI_GetTVPtrIndex(pVBInfo);
 	tempbx &= 0xFE;
-
-	if (ModeNo <= 0x13)
-		index = pVBInfo->SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex;
-	else
-		index = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex;
-
-	tempbx += index;
 	tempah = TVEdgeList[tempbx];
 	tempah = tempah << 5;
 
@@ -6631,13 +6034,7 @@
 		return;
 	}
 
-	if (ModeNo <= 0x13)
-		tempal = pVBInfo->SModeIDTable[ModeIdIndex].
-				VB_StTVYFilterIndex;
-	else
-		tempal = pVBInfo->EModeIDTable[ModeIdIndex].
-				VB_ExtTVYFilterIndex;
-
+	tempal = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
 	if (tempcl == 0)
 		index = tempal * 4;
 	else
@@ -6712,16 +6109,14 @@
 		if (pVBInfo->VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToTV
 				| SetCRT2ToLCD)) {
 			tempah = 0x40; /* BTDRAM */
-			if (ModeNo > 0x13) {
-				tempcl = pVBInfo->ModeType;
-				tempcl -= ModeVGA;
-				if (tempcl >= 0) {
-					/* BT Color */
-					tempah = (0x008 >> tempcl);
-					if (tempah == 0)
-						tempah = 1;
-					tempah |= 0x040;
-				}
+			tempcl = pVBInfo->ModeType;
+			tempcl -= ModeVGA;
+			if (tempcl >= 0) {
+				/* BT Color */
+				tempah = (0x008 >> tempcl);
+				if (tempah == 0)
+					tempah = 1;
+				tempah |= 0x040;
 			}
 			if (pVBInfo->VBInfo & SetInSlaveMode)
 				tempah ^= 0x50; /* BTDAC */
@@ -6797,10 +6192,8 @@
 
 		if (pVBInfo->VBInfo & SetCRT2ToTV) {
 			tempah |= 0x020;
-			if (ModeNo > 0x13) {
-				if (pVBInfo->VBInfo & DriverMode)
-					tempah = tempah ^ 0x20;
-			}
+			if (pVBInfo->VBInfo & DriverMode)
+				tempah = tempah ^ 0x20;
 		}
 
 		xgifb_reg_and_or(pVBInfo->Part4Port, 0x0D, ~0x0BF, tempah);
@@ -6925,13 +6318,7 @@
 
 	unsigned short RefreshRateTableIndex, i, modeflag, index, temp;
 
-	if (ModeNo <= 0x13)
-		modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-	else
-		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
-	if (ModeNo < 0x14)
-		return 0xFFFF;
+	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	index = xgifb_reg_get(pVBInfo->P3d4, 0x33);
 	index = index >> pVBInfo->SelectCRT2Rate;
@@ -7297,16 +6684,13 @@
 		unsigned short ModeNo, unsigned short ModeIdIndex,
 		struct vb_device_info *pVBInfo)
 {
-	unsigned short StandTableIndex, RefreshRateTableIndex, b3CC, temp;
+	unsigned short RefreshRateTableIndex, temp;
 
-	unsigned short XGINew_P3cc = pVBInfo->P3cc;
-
-	StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
-	XGI_SetSeqRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo);
-	outb(pVBInfo->StandTable[StandTableIndex].MISC, pVBInfo->P3c2);
-	XGI_SetCRTCRegs(HwDeviceExtension, StandTableIndex, pVBInfo);
-	XGI_SetATTRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo);
-	XGI_SetGRCRegs(StandTableIndex, pVBInfo);
+	XGI_SetSeqRegs(ModeNo, ModeIdIndex, pVBInfo);
+	outb(pVBInfo->StandTable->MISC, pVBInfo->P3c2);
+	XGI_SetCRTCRegs(HwDeviceExtension, pVBInfo);
+	XGI_SetATTRegs(ModeNo, ModeIdIndex, pVBInfo);
+	XGI_SetGRCRegs(pVBInfo);
 	XGI_ClearExt1Regs(pVBInfo);
 
 	if (HwDeviceExtension->jChipType == XG27) {
@@ -7340,22 +6724,6 @@
 				RefreshRateTableIndex, pVBInfo);
 	}
 
-	if ((HwDeviceExtension->jChipType >= XG20) &&
-	    (HwDeviceExtension->jChipType < XG27)) { /* fix H/W DCLK/2 bug */
-		if ((ModeNo == 0x00) | (ModeNo == 0x01)) {
-			xgifb_reg_set(pVBInfo->P3c4, 0x2B, 0x4E);
-			xgifb_reg_set(pVBInfo->P3c4, 0x2C, 0xE9);
-			b3CC = (unsigned char) inb(XGINew_P3cc);
-			outb((b3CC |= 0x0C), XGINew_P3cc);
-		} else if ((ModeNo == 0x04) | (ModeNo == 0x05) | (ModeNo
-				== 0x0D)) {
-			xgifb_reg_set(pVBInfo->P3c4, 0x2B, 0x1B);
-			xgifb_reg_set(pVBInfo->P3c4, 0x2C, 0xE3);
-			b3CC = (unsigned char) inb(XGINew_P3cc);
-			outb((b3CC |= 0x0C), XGINew_P3cc);
-		}
-	}
-
 	if (HwDeviceExtension->jChipType >= XG21) {
 		temp = xgifb_reg_get(pVBInfo->P3d4, 0x38);
 		if (temp & 0xA0) {
@@ -7394,7 +6762,7 @@
 	unsigned short ModeIdIndex;
 	struct vb_device_info VBINF;
 	struct vb_device_info *pVBInfo = &VBINF;
-	pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress;
+	pVBInfo->BaseAddr = xgifb_info->vga_base;
 	pVBInfo->IF_DEF_LVDS = 0;
 	pVBInfo->IF_DEF_LCDA = 1;
 
@@ -7509,13 +6877,8 @@
 						   pVBInfo))
 				return 0;
 
-		if (ModeNo <= 0x13) {
-			pVBInfo->ModeType = pVBInfo->SModeIDTable[ModeIdIndex].
-						St_ModeFlag & ModeTypeMask;
-		} else {
-			pVBInfo->ModeType = pVBInfo->EModeIDTable[ModeIdIndex].
+		pVBInfo->ModeType = pVBInfo->EModeIDTable[ModeIdIndex].
 						Ext_ModeFlag & ModeTypeMask;
-		}
 
 		pVBInfo->SetFlag = 0;
 		pVBInfo->VBInfo = DisableCRT2Display;
diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h
index a5bd56a..38f47ff 100644
--- a/drivers/staging/xgifb/vb_struct.h
+++ b/drivers/staging/xgifb/vb_struct.h
@@ -10,28 +10,11 @@
 	unsigned char Reg[7];
 };
 
-struct XGI_StStruct {
-	unsigned char St_ModeID;
-	unsigned short St_ModeFlag;
-	unsigned char St_StTableIndex;
-	unsigned char St_CRT2CRTC;
-	unsigned char St_CRT2CRTC2;
-	unsigned char St_ResInfo;
-	unsigned char VB_StTVFlickerIndex;
-	unsigned char VB_StTVEdgeIndex;
-	unsigned char VB_StTVYFilterIndex;
-};
-
 struct XGI_ExtStruct {
 	unsigned char Ext_ModeID;
 	unsigned short Ext_ModeFlag;
 	unsigned short Ext_ModeInfo;
-	unsigned short Ext_Point;
-	unsigned short Ext_VESAID;
-	unsigned char Ext_VESAMEMSize;
 	unsigned char Ext_RESINFO;
-	unsigned char VB_ExtTVFlickerIndex;
-	unsigned char VB_ExtTVEdgeIndex;
 	unsigned char VB_ExtTVYFilterIndex;
 	unsigned char REFindex;
 };
@@ -68,14 +51,6 @@
 	unsigned short DATAPTR;
 };
 
-struct XGI330_LCDDataDesStruct {
-	unsigned short LCDHDES;
-	unsigned short LCDHRS;
-	unsigned short LCDVDES;
-	unsigned short LCDVRS;
-};
-
-
 struct XGI330_LVDSDataStruct {
 	unsigned short VGAHT;
 	unsigned short VGAVT;
@@ -236,7 +211,6 @@
 
 	void __iomem *FBAddr;
 	unsigned long BaseAddr;
-	unsigned long RelIO;
 
 	unsigned char (*CR6B)[4];
 	unsigned char (*CR6E)[4];
@@ -314,7 +288,6 @@
 	struct XGI_TimingHStruct  *TimingH;
 	struct XGI_TimingVStruct  *TimingV;
 
-	struct XGI_StStruct          *SModeIDTable;
 	struct SiS_StandTable_S  *StandTable;
 	struct XGI_ExtStruct         *EModeIDTable;
 	struct XGI_Ext2Struct        *RefIndex;
diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h
index e8d6f67..d22e599 100644
--- a/drivers/staging/xgifb/vb_table.h
+++ b/drivers/staging/xgifb/vb_table.h
@@ -135,609 +135,92 @@
 static unsigned char XG40_CRCF = 0x13;
 static unsigned char XG40_DRAMTypeDefinition = 0xFF ;
 
-static struct XGI_StStruct XGI330_SModeIDTable[] = {
-	{0x01, 0x9208, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00},
-	{0x01, 0x1210, 0x14, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00},
-	{0x01, 0x1010, 0x17, 0x02, 0x11, 0x00, 0x00, 0x01, 0x01},
-	{0x03, 0x8208, 0x03, 0x00, 0x14, 0x00, 0x00, 0x01, 0x02},
-	{0x03, 0x0210, 0x16, 0x01, 0x04, 0x01, 0x00, 0x01, 0x02},
-	{0x03, 0x0010, 0x18, 0x02, 0x15, 0x00, 0x00, 0x01, 0x03},
-	{0x05, 0x9209, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04},
-	{0x06, 0x8209, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05},
-	{0x07, 0x0000, 0x07, 0x03, 0x05, 0x03, 0x00, 0x01, 0x03},
-	{0x07, 0x0000, 0x19, 0x02, 0x15, 0x02, 0x00, 0x01, 0x03},
-	{0x0d, 0x920a, 0x0d, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04},
-	{0x0e, 0x820a, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05},
-	{0x0f, 0x0202, 0x11, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05},
-	{0x10, 0x0212, 0x12, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05},
-	{0x11, 0x0212, 0x1a, 0x04, 0x24, 0x04, 0x00, 0x00, 0x05},
-	{0x12, 0x0212, 0x1b, 0x04, 0x24, 0x04, 0x00, 0x00, 0x05},
-	{0x13, 0x021b, 0x1c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04},
-	{0x12, 0x0010, 0x18, 0x02, 0x24, 0x02, 0x00, 0x00, 0x05},/* St_CRT2CRTC2
-								    not sure */
-	{0x12, 0x0210, 0x18, 0x01, 0x24, 0x01, 0x00, 0x00, 0x05},/* St_CRT2CRTC2
-								    not sure */
-	{0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-};
-
-
 static struct XGI_ExtStruct XGI330_EModeIDTable[] = {
-	{0x6a, 0x2212, 0x0407, 0x3a81, 0x0102, 0x08,
-		0x07, 0x00, 0x00, 0x07, 0x0e},
-	{0x2e, 0x0a1b, 0x0306, 0x3a57, 0x0101, 0x08,
-		0x06, 0x00, 0x00, 0x05, 0x06},
-	{0x2f, 0x0a1b, 0x0305, 0x3a50, 0x0100, 0x08,
-		0x05, 0x00, 0x00, 0x05, 0x05},
-	{0x30, 0x2a1b, 0x0407, 0x3a81, 0x0103, 0x08,
-		0x07, 0x00, 0x00, 0x07, 0x0e},
-	{0x31, 0x0a1b, 0x030d, 0x3b85, 0x0000, 0x08,
-		0x0d, 0x00, 0x00, 0x06, 0x3d},
-	{0x32, 0x0a1b, 0x0a0e, 0x3b8c, 0x0000, 0x08,
-		0x0e, 0x00, 0x00, 0x06, 0x3e},
-	{0x33, 0x0a1d, 0x0a0d, 0x3b85, 0x0000, 0x08,
-		0x0d, 0x00, 0x00, 0x06, 0x3d},
-	{0x34, 0x2a1d, 0x0a0e, 0x3b8c, 0x0000, 0x08,
-		0x0e, 0x00, 0x00, 0x06, 0x3e},
-	{0x35, 0x0a1f, 0x0a0d, 0x3b85, 0x0000, 0x08,
-		0x0d, 0x00, 0x00, 0x06, 0x3d},
-	{0x36, 0x2a1f, 0x0a0e, 0x3b8c, 0x0000, 0x08,
-		0x0e, 0x00, 0x00, 0x06, 0x3e},
-	{0x37, 0x0212, 0x0508, 0x3aab, 0x0104, 0x08,
-		0x08, 0x00, 0x00, 0x00, 0x16},
-	{0x38, 0x0a1b, 0x0508, 0x3aab, 0x0105, 0x08,
-		0x08, 0x00, 0x00, 0x00, 0x16},
-	{0x3a, 0x0e3b, 0x0609, 0x3adc, 0x0107, 0x08,
-		0x09, 0x00, 0x00, 0x00, 0x1e},
-	{0x3c, 0x0e3b, 0x070a, 0x3af2, 0x0130, 0x08,
-		0x0a, 0x00, 0x00, 0x00, 0x22},	/* mode 1600x1200
+	{0x2e, 0x0a1b, 0x0306, 0x06, 0x05, 0x06},
+	{0x2f, 0x0a1b, 0x0305, 0x05, 0x05, 0x05},
+	{0x30, 0x2a1b, 0x0407, 0x07, 0x07, 0x0e},
+	{0x31, 0x0a1b, 0x030d, 0x0d, 0x06, 0x3d},
+	{0x32, 0x0a1b, 0x0a0e, 0x0e, 0x06, 0x3e},
+	{0x33, 0x0a1d, 0x0a0d, 0x0d, 0x06, 0x3d},
+	{0x34, 0x2a1d, 0x0a0e, 0x0e, 0x06, 0x3e},
+	{0x35, 0x0a1f, 0x0a0d, 0x0d, 0x06, 0x3d},
+	{0x36, 0x2a1f, 0x0a0e, 0x0e, 0x06, 0x3e},
+	{0x38, 0x0a1b, 0x0508, 0x08, 0x00, 0x16},
+	{0x3a, 0x0e3b, 0x0609, 0x09, 0x00, 0x1e},
+	{0x3c, 0x0e3b, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200
 						   add CRT2MODE [2003/10/07] */
-	{0x3d, 0x0e7d, 0x070a, 0x3af2, 0x0131, 0x08,
-		0x0a, 0x00, 0x00, 0x00, 0x22},	/* mode 1600x1200
+	{0x3d, 0x0e7d, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200
 						   add CRT2MODE */
-	{0x40, 0x9a1c, 0x0000, 0x3a34, 0x010d, 0x08,
-		0x00, 0x00, 0x00, 0x04, 0x00},
-	{0x41, 0x9a1d, 0x0000, 0x3a34, 0x010e, 0x08,
-		0x00, 0x00, 0x00, 0x04, 0x00},	/* ModeIdIndex = 0x10 */
-	{0x43, 0x0a1c, 0x0306, 0x3a57, 0x0110, 0x08,
-		0x06, 0x00, 0x00, 0x05, 0x06},
-	{0x44, 0x0a1d, 0x0306, 0x3a57, 0x0111, 0x08,
-		0x06, 0x00, 0x00, 0x05, 0x06},
-	{0x46, 0x2a1c, 0x0407, 0x3a81, 0x0113, 0x08,
-		0x07, 0x00, 0x00, 0x07, 0x0e},
-	{0x47, 0x2a1d, 0x0407, 0x3a81, 0x0114, 0x08,
-		0x07, 0x00, 0x00, 0x07, 0x0e},
-	{0x49, 0x0a3c, 0x0508, 0x3aab, 0x0116, 0x08,
-		0x08, 0x00, 0x00, 0x00, 0x16},
-	{0x4a, 0x0a3d, 0x0508, 0x3aab, 0x0117, 0x08,
-		0x08, 0x00, 0x00, 0x00, 0x16},
-	{0x4c, 0x0e7c, 0x0609, 0x3adc, 0x0119, 0x08,
-		0x09, 0x00, 0x00, 0x00, 0x1e},
-	{0x4d, 0x0e7d, 0x0609, 0x3adc, 0x011a, 0x08,
-		0x09, 0x00, 0x00, 0x00, 0x1e},
-	{0x50, 0x9a1b, 0x0001, 0x3a3b, 0x0132, 0x08,
-		0x01, 0x00, 0x00, 0x04, 0x02},
-	{0x51, 0xba1b, 0x0103, 0x3a42, 0x0133, 0x08,
-		0x03, 0x00, 0x00, 0x07, 0x03},
-	{0x52, 0x9a1b, 0x0204, 0x3a49, 0x0134, 0x08,
-		0x04, 0x00, 0x00, 0x00, 0x04},
-	{0x56, 0x9a1d, 0x0001, 0x3a3b, 0x0135, 0x08,
-		0x01, 0x00, 0x00, 0x04, 0x02},
-	{0x57, 0xba1d, 0x0103, 0x3a42, 0x0136, 0x08,
-		0x03, 0x00, 0x00, 0x07, 0x03},
-	{0x58, 0x9a1d, 0x0204, 0x3a49, 0x0137, 0x08,
-		0x04, 0x00, 0x00, 0x00, 0x04},
-	{0x59, 0x9a1b, 0x0000, 0x3a34, 0x0138, 0x08,
-		0x00, 0x00, 0x00, 0x04, 0x00},
-	{0x5A, 0x021b, 0x0014, 0x3b83, 0x0138, 0x08,
-		0x01, 0x00, 0x00, 0x04, 0x3f},	/* ModeIdIndex = 0x20 */
-	{0x5B, 0x0a1d, 0x0014, 0x3b83, 0x0135, 0x08,
-		0x01, 0x00, 0x00, 0x04, 0x3f},
-	{0x5d, 0x0a1d, 0x0305, 0x3a50, 0x0139, 0x08,
-		0x05, 0x00, 0x00, 0x07, 0x05},
-	{0x62, 0x0a3f, 0x0306, 0x3a57, 0x013a, 0x08,
-		0x06, 0x00, 0x00, 0x05, 0x06},
-	{0x63, 0x2a3f, 0x0407, 0x3a81, 0x013b, 0x08,
-		0x07, 0x00, 0x00, 0x07, 0x0e},
-	{0x64, 0x0a7f, 0x0508, 0x3aab, 0x013c, 0x08,
-		0x08, 0x00, 0x00, 0x00, 0x16},
-	{0x65, 0x0eff, 0x0609, 0x3adc, 0x013d, 0x08,
-		0x09, 0x00, 0x00, 0x00, 0x1e},
-	{0x66, 0x0eff, 0x070a, 0x3af2, 0x013e, 0x08,
-		0x0a, 0x00, 0x00, 0x00, 0x22},	/* mode 1600x1200
+	{0x40, 0x9a1c, 0x0000, 0x00, 0x04, 0x00},
+	{0x41, 0x9a1d, 0x0000, 0x00, 0x04, 0x00},
+	{0x43, 0x0a1c, 0x0306, 0x06, 0x05, 0x06},
+	{0x44, 0x0a1d, 0x0306, 0x06, 0x05, 0x06},
+	{0x46, 0x2a1c, 0x0407, 0x07, 0x07, 0x0e},
+	{0x47, 0x2a1d, 0x0407, 0x07, 0x07, 0x0e},
+	{0x49, 0x0a3c, 0x0508, 0x08, 0x00, 0x16},
+	{0x4a, 0x0a3d, 0x0508, 0x08, 0x00, 0x16},
+	{0x4c, 0x0e7c, 0x0609, 0x09, 0x00, 0x1e},
+	{0x4d, 0x0e7d, 0x0609, 0x09, 0x00, 0x1e},
+	{0x50, 0x9a1b, 0x0001, 0x01, 0x04, 0x02},
+	{0x51, 0xba1b, 0x0103, 0x03, 0x07, 0x03},
+	{0x52, 0x9a1b, 0x0204, 0x04, 0x00, 0x04},
+	{0x56, 0x9a1d, 0x0001, 0x01, 0x04, 0x02},
+	{0x57, 0xba1d, 0x0103, 0x03, 0x07, 0x03},
+	{0x58, 0x9a1d, 0x0204, 0x04, 0x00, 0x04},
+	{0x59, 0x9a1b, 0x0000, 0x00, 0x04, 0x00},
+	{0x5A, 0x021b, 0x0014, 0x01, 0x04, 0x3f},
+	{0x5B, 0x0a1d, 0x0014, 0x01, 0x04, 0x3f},
+	{0x5d, 0x0a1d, 0x0305, 0x05, 0x07, 0x05},
+	{0x62, 0x0a3f, 0x0306, 0x06, 0x05, 0x06},
+	{0x63, 0x2a3f, 0x0407, 0x07, 0x07, 0x0e},
+	{0x64, 0x0a7f, 0x0508, 0x08, 0x00, 0x16},
+	{0x65, 0x0eff, 0x0609, 0x09, 0x00, 0x1e},
+	{0x66, 0x0eff, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200
 						   add CRT2MODE */
-	{0x68, 0x067b, 0x080b, 0x3b17, 0x013f, 0x08,
-		0x0b, 0x00, 0x00, 0x00, 0x29},
-	{0x69, 0x06fd, 0x080b, 0x3b17, 0x0140, 0x08,
-		0x0b, 0x00, 0x00, 0x00, 0x29},
-	{0x6b, 0x07ff, 0x080b, 0x3b17, 0x0141, 0x10,
-		0x0b, 0x00, 0x00, 0x00, 0x29},
-	{0x6c, 0x067b, 0x090c, 0x3b37, 0x0000, 0x08,
-		0x0c, 0x00, 0x00, 0x00, 0x2f},
-	{0x6d, 0x06fd, 0x090c, 0x3b37, 0x0000, 0x10,
-		0x0c, 0x00, 0x00, 0x00, 0x2f},
-	{0x6e, 0x07ff, 0x090c, 0x3b37, 0x0000, 0x10,
-		0x0c, 0x00, 0x00, 0x00, 0x2f},
-	{0x70, 0x2a1b, 0x0410, 0x3b52, 0x0000, 0x08,
-		0x10, 0x00, 0x00, 0x07, 0x34},
-	{0x71, 0x0a1b, 0x0511, 0x3b63, 0x0000, 0x08,
-		0x11, 0x00, 0x00, 0x00, 0x37},
-	{0x74, 0x0a1d, 0x0511, 0x3b63, 0x0000, 0x08,
-		0x11, 0x00, 0x00, 0x00, 0x37},	/* ModeIdIndex = 0x30 */
-	{0x75, 0x0a3d, 0x0612, 0x3b74, 0x0000, 0x08,
-		0x12, 0x00, 0x00, 0x00, 0x3a},
-	{0x76, 0x2a1f, 0x0410, 0x3b52, 0x0000, 0x08,
-		0x10, 0x00, 0x00, 0x07, 0x34},
-	{0x77, 0x0a1f, 0x0511, 0x3b63, 0x0000, 0x08,
-		0x11, 0x00, 0x00, 0x00, 0x37},
-	{0x78, 0x0a3f, 0x0612, 0x3b74, 0x0000, 0x08,
-		0x12, 0x00, 0x00, 0x00, 0x3a},
-	{0x79, 0x0a3b, 0x0612, 0x3b74, 0x0000, 0x08,
-		0x12, 0x00, 0x00, 0x00, 0x3a},
-	{0x7a, 0x2a1d, 0x0410, 0x3b52, 0x0000, 0x08,
-		0x10, 0x00, 0x00, 0x07, 0x34},
-	{0x7b, 0x0e3b, 0x060f, 0x3ad0, 0x0000, 0x08,
-		0x0f, 0x00, 0x00, 0x00, 0x1d},
-	{0x7c, 0x0e7d, 0x060f, 0x3ad0, 0x0000, 0x08,
-		0x0f, 0x00, 0x00, 0x00, 0x1d},
-	{0x7d, 0x0eff, 0x060f, 0x3ad0, 0x0000, 0x08,
-		0x0f, 0x00, 0x00, 0x00, 0x1d},
-	{0x20, 0x0e3b, 0x0D16, 0x49e0, 0x0000, 0x08,
-		0x16, 0x00, 0x00, 0x00, 0x43},
-	{0x21, 0x0e7d, 0x0D16, 0x49e0, 0x0000, 0x08,
-		0x16, 0x00, 0x00, 0x00, 0x43},
-	{0x22, 0x0eff, 0x0D16, 0x49e0, 0x0000, 0x08,
-		0x16, 0x00, 0x00, 0x00, 0x43},
-	{0x23, 0x0e3b, 0x0614, 0x49d5, 0x0000, 0x08,
-		0x14, 0x00, 0x00, 0x00, 0x41},
-	{0x24, 0x0e7d, 0x0614, 0x49d5, 0x0000, 0x08,
-		0x14, 0x00, 0x00, 0x00, 0x41},
-	{0x25, 0x0eff, 0x0614, 0x49d5, 0x0000, 0x08,
-		0x14, 0x00, 0x00, 0x00, 0x41},
-	{0x26, 0x063b, 0x0c15, 0x49dc, 0x0000, 0x08,
-		0x15, 0x00, 0x00, 0x00, 0x42},	/* ModeIdIndex = 0x40 */
-	{0x27, 0x067d, 0x0c15, 0x49dc, 0x0000, 0x08,
-		0x15, 0x00, 0x00, 0x00, 0x42},
-	{0x28, 0x06ff, 0x0c15, 0x49dc, 0x0000, 0x08,
-		0x15, 0x00, 0x00, 0x00, 0x42},
-	{0xff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00}
+	{0x68, 0x067b, 0x080b, 0x0b, 0x00, 0x29},
+	{0x69, 0x06fd, 0x080b, 0x0b, 0x00, 0x29},
+	{0x6b, 0x07ff, 0x080b, 0x0b, 0x00, 0x29},
+	{0x6c, 0x067b, 0x090c, 0x0c, 0x00, 0x2f},
+	{0x6d, 0x06fd, 0x090c, 0x0c, 0x00, 0x2f},
+	{0x6e, 0x07ff, 0x090c, 0x0c, 0x00, 0x2f},
+	{0x70, 0x2a1b, 0x0410, 0x10, 0x07, 0x34},
+	{0x71, 0x0a1b, 0x0511, 0x11, 0x00, 0x37},
+	{0x74, 0x0a1d, 0x0511, 0x11, 0x00, 0x37},
+	{0x75, 0x0a3d, 0x0612, 0x12, 0x00, 0x3a},
+	{0x76, 0x2a1f, 0x0410, 0x10, 0x07, 0x34},
+	{0x77, 0x0a1f, 0x0511, 0x11, 0x00, 0x37},
+	{0x78, 0x0a3f, 0x0612, 0x12, 0x00, 0x3a},
+	{0x79, 0x0a3b, 0x0612, 0x12, 0x00, 0x3a},
+	{0x7a, 0x2a1d, 0x0410, 0x10, 0x07, 0x34},
+	{0x7b, 0x0e3b, 0x060f, 0x0f, 0x00, 0x1d},
+	{0x7c, 0x0e7d, 0x060f, 0x0f, 0x00, 0x1d},
+	{0x7d, 0x0eff, 0x060f, 0x0f, 0x00, 0x1d},
+	{0x20, 0x0e3b, 0x0D16, 0x16, 0x00, 0x43},
+	{0x21, 0x0e7d, 0x0D16, 0x16, 0x00, 0x43},
+	{0x22, 0x0eff, 0x0D16, 0x16, 0x00, 0x43},
+	{0x23, 0x0e3b, 0x0614, 0x14, 0x00, 0x41},
+	{0x24, 0x0e7d, 0x0614, 0x14, 0x00, 0x41},
+	{0x25, 0x0eff, 0x0614, 0x14, 0x00, 0x41},
+	{0x26, 0x063b, 0x0c15, 0x15, 0x00, 0x42},
+	{0x27, 0x067d, 0x0c15, 0x15, 0x00, 0x42},
+	{0x28, 0x06ff, 0x0c15, 0x15, 0x00, 0x42},
+	{0xff, 0x0000, 0x0000, 0x00, 0x00, 0x00}
 };
 
-static struct SiS_StandTable_S XGI330_StandTable[] = {
-/* MD_0_200 */
-	{
-		0x28, 0x18, 0x08, 0x0800,
-		{0x09, 0x03, 0x00, 0x02},
-		0x63,
-		{0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
-		 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		 0x08, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_1_200 */
-	{
-		0x28, 0x18, 0x08, 0x0800,
-		{0x09, 0x03, 0x00, 0x02},
-		0x63,
-		{0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
-		 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		 0x08, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_2_200 */
-	{
-		0x50, 0x18, 0x08, 0x1000,
-		{0x01, 0x03, 0x00, 0x02},
-		 0x63,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		 0x08, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_3_200 */
-	{
-		0x50, 0x18, 0x08, 0x1000,
-		{0x01, 0x03, 0x00, 0x02},
-		 0x63,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		 0x08, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_4 */
-	{
-		0x28, 0x18, 0x08, 0x4000,
-		{0x09, 0x03, 0x00, 0x02},
-		 0x63,
-		{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
-		 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
-		 0xff},
-		{0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
-		 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		 0x01, 0x00, 0x03, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00,
-		 0xff}
-	},
-/* MD_5 */
-	{
-		0x28, 0x18, 0x08, 0x4000,
-		{0x09, 0x03, 0x00, 0x02},
-		 0x63,
-		{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
-		 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
-		 0xff},
-		{0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
-		 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		 0x01, 0x00, 0x03, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00,
-		 0xff}
-	},
-/* MD_6 */
-	{
-		0x50, 0x18, 0x08, 0x4000,
-		{0x01, 0x01, 0x00, 0x06},
-		 0x63,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
-		 0xff},
-		{0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
-		 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
-		 0x01, 0x00, 0x01, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
-		 0xff}
-	},
-/* MD_7 */
-	{
-		0x50, 0x18, 0x0e, 0x1000,
-		{0x00, 0x03, 0x00, 0x03},
-		 0xa6,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
-		 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3,
-		 0xff},
-		{0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
-		 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-		 0x0e, 0x00, 0x0f, 0x08},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00,
-		 0xff}
-	},
-/* MDA_DAC */
-	{
-		0x00, 0x00, 0x00, 0x0000,
-		{0x00, 0x00, 0x00, 0x15},
-		 0x15,
-		{0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
-		 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x3f,
-		 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00,
-		 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15,
-		 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
-		 0x15, 0x15, 0x15, 0x15},
-		{0x15, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
-		 0x3f}
-	},
-/* CGA_DAC */
-	{
-		0x00, 0x10, 0x04, 0x0114,
-		{0x11, 0x09, 0x15, 0x00},
-		 0x10,
-		{0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a,
-		 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x2a, 0x3a,
-		 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x10,
-		 0x04},
-		{0x14, 0x01, 0x11, 0x09, 0x15, 0x00, 0x10, 0x04,
-		 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, 0x2e,
-		 0x3e, 0x2b, 0x3b, 0x2f},
-		{0x3f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f,
-		 0x3f}
-	},
-/* EGA_DAC */
-	{
-		0x00, 0x10, 0x04, 0x0114,
-		{0x11, 0x05, 0x15, 0x20},
-		 0x30,
-		{0x24, 0x34, 0x21, 0x31, 0x25, 0x35, 0x08, 0x18,
-		 0x0c, 0x1c, 0x09, 0x19, 0x0d, 0x1d, 0x28, 0x38,
-		 0x2c, 0x3c, 0x29, 0x39, 0x2d, 0x3d, 0x02, 0x12,
-		 0x06},
-		{0x16, 0x03, 0x13, 0x07, 0x17, 0x22, 0x32, 0x26,
-		 0x36, 0x23, 0x33, 0x27, 0x37, 0x0a, 0x1a, 0x0e,
-		 0x1e, 0x0b, 0x1b, 0x0f},
-		{0x1f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f,
-		 0x3f}
-	},
-/* VGA_DAC */
-	{
-		0x00, 0x10, 0x04, 0x0114,
-		{0x11, 0x09, 0x15, 0x2a},
-		 0x3a,
-		{0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x05,
-		 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x18, 0x1c, 0x20,
-		 0x24, 0x28, 0x2d, 0x32, 0x38, 0x3f, 0x00, 0x10,
-		 0x1f},
-		{0x2f, 0x3f, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 0x2d,
-		 0x31, 0x36, 0x3a, 0x3f, 0x00, 0x07, 0x0e, 0x15,
-		 0x1c, 0x0e, 0x11, 0x15},
-		{0x18, 0x1c, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x00,
-		 0x04}
-	},
-	{
-		0x08, 0x0c, 0x10, 0x0a08,
-		{0x0c, 0x0e, 0x10, 0x0b},
-		 0x0c,
-		{0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00,
-		 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00,
-		 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00,
-		 0x06},
-		{0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08,
-		 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00,
-		 0x00, 0x00, 0x00, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x00}
-	},
-/* MD_D */
-	{
-		0x28, 0x18, 0x08, 0x2000,
-		{0x09, 0x0f, 0x00, 0x06},
-		 0x63,
-		{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
-		 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		 0x01, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
-		 0xff}
-	},
-/* MD_E */
-	{
-		0x50, 0x18, 0x08, 0x4000,
-		{0x01, 0x0f, 0x00, 0x06},
-		 0x63,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		 0x01, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
-		 0xff}
-	},
+static struct SiS_StandTable_S XGI330_StandTable = {
 /* ExtVGATable */
-	{
-		0x00, 0x00, 0x00, 0x0000,
-		{0x01, 0x0f, 0x00, 0x0e},
-		 0x23,
-		{0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
-		 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-		 0x01, 0x00, 0x00, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
-		 0xff}
-	},
-/* ROM_SAVEPTR */
-	{
-		0x9f, 0x3b, 0x00, 0x00c0,
-		{0x00, 0x00, 0x00, 0x00},
-		 0x00,
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x3f,
-		 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x00, 0x00, 0x1a, 0x00, 0xac, 0x3e, 0x00, 0xc0,
-		 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x00, 0x00, 0x00, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x00}
-	},
-/* MD_F */
-	{
-		0x50, 0x18, 0x0e, 0x8000,
-		{0x01, 0x0f, 0x00, 0x06},
-		 0xa2,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
-		 0xff},
-		{0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
-		 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
-		 0x0b, 0x00, 0x05, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05,
-		 0xff}
-	},
-/* MD_10 */
-	{
-		0x50, 0x18, 0x0e, 0x8000,
-		{0x01, 0x0f, 0x00, 0x06},
-		 0xa3,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-		 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-		 0x01, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
-		 0xff}
-	},
-/* MD_0_350 */
-	{
-		0x28, 0x18, 0x0e, 0x0800,
-		{0x09, 0x03, 0x00, 0x02},
-		 0xa3,
-		{0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f,
-		 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
-		 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-		 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-		 0x08, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_1_350 */
-	{
-		0x28, 0x18, 0x0e, 0x0800,
-		{0x09, 0x03, 0x00, 0x02},
-		 0xa3,
-		{0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
-		 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
-		 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-		 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-		 0x08, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_2_350 */
-	{
-		0x50, 0x18, 0x0e, 0x1000,
-		{0x01, 0x03, 0x00, 0x02},
-		 0xa3,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
-		 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-		 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-		 0x08, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_3_350 */
-	{
-		0x50, 0x18, 0x0e, 0x1000,
-		{0x01, 0x03, 0x00, 0x02},
-		 0xa3,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
-		 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-		 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-		 0x08, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_0_1_400 */
-	{
-		0x28, 0x18, 0x10, 0x0800,
-		{0x08, 0x03, 0x00, 0x02},
-		 0x67,
-		{0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f,
-		 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-		 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-		 0x0c, 0x00, 0x0f, 0x08},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_2_3_400 */
-	{
-		0x50, 0x18, 0x10, 0x1000,
-		{0x00, 0x03, 0x00, 0x02},
-		 0x67,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-		 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-		 0x0c, 0x00, 0x0f, 0x08},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
-		 0xff}
-	},
-/* MD_7_400 */
-	{
-		0x50, 0x18, 0x10, 0x1000,
-		{0x00, 0x03, 0x00, 0x02},
-		 0x66,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
-		 0xff},
-		{0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
-		 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-		 0x0e, 0x00, 0x0f, 0x08},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00,
-		 0xff}
-	},
-/* MD_11 */
-	{
-		0x50, 0x1d, 0x10, 0xa000,
-		{0x01, 0x0f, 0x00, 0x06},
-		 0xe3,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
-		 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3,
-		 0xff},
-		{0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
-		 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
-		 0x01, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01,
-		 0xff}
-	},
-/* ExtEGATable */
-	{
-		0x50, 0x1d, 0x10, 0xa000,
-		{0x01, 0x0f, 0x00, 0x06},
-		 0xe3,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
-		 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-		 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-		 0x01, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
-		 0xff}
-	},
-/* MD_13 */
-	{
-		0x28, 0x18, 0x08, 0x2000,
-		{0x01, 0x0f, 0x00, 0x0e},
-		 0x63,
-		{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-		 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
-		 0xff},
-		{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-		 0x41, 0x00, 0x0f, 0x00},
-		{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
-		 0xff}
-	}
+	0x00, 0x00, 0x00, 0x0000,
+	{0x01, 0x0f, 0x00, 0x0e},
+	 0x23,
+	{0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+	 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+	 0xff},
+	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	 0x01, 0x00, 0x00, 0x00},
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
+	 0xff}
 };
 
 static struct XGI_TimingHStruct XGI_TimingH[1];
@@ -1143,7 +626,7 @@
 	{1, 1, 1688, 806,  1688, 806}   /* ; 0A (1280x768x75Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_ExtLCDDes1024x768Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDes1024x768Data[] = {
 	{9, 1057, 0,   771}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{9, 1057, 0,   771}, /* ; 01 (320x350,640x350) */
 	{9, 1057, 0,   771}, /* ; 02 (360x400,720x400) */
@@ -1153,7 +636,7 @@
 	{9, 1057, 805, 770}  /* ; 06 (1024x768x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_StLCDDes1024x768Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDes1024x768Data[] = {
 	{9, 1057, 737, 703}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{9, 1057, 686, 651}, /* ; 01 (320x350,640x350) */
 	{9, 1057, 737, 703}, /* ; 02 (360x400,720x400) */
@@ -1163,7 +646,7 @@
 	{9, 1057, 805, 770}  /* ; 06 (1024x768x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_CetLCDDes1024x768Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1024x768Data[] = {
 	{1152, 856,  622, 587}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{1152, 856,  597, 562}, /* ; 01 (320x350,640x350) */
 	{1152, 856,  622, 587}, /* ; 02 (360x400,720x400) */
@@ -1173,7 +656,7 @@
 	{0,    1048, 805, 770}  /* ; 06 (1024x768x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDLDes1280x1024Data[] = {
 	{18, 1346, 981,  940},  /* 00 (320x200,320x400,640x200,640x400) */
 	{18, 1346, 926,  865},  /* 01 (320x350,640x350) */
 	{18, 1346, 981,  940},  /* 02 (360x400,720x400) */
@@ -1184,7 +667,7 @@
 	{18, 1346, 1065, 1024}  /* 07 (1280x1024x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDLDes1280x1024Data[] = {
 	{18, 1346, 970,  907},  /* 00 (320x200,320x400,640x200,640x400) */
 	{18, 1346, 917,  854},  /* 01 (320x350,640x350) */
 	{18, 1346, 970,  907},  /* 02 (360x400,720x400) */
@@ -1195,7 +678,7 @@
 	{18, 1346, 1065, 1024}  /* 07 (1280x1024x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_CetLCDDLDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDLDes1280x1024Data[] = {
 	{1368, 1008, 752,  711}, /* 00 (320x200,320x400,640x200,640x400) */
 	{1368, 1008, 729,  688}, /* 01 (320x350,640x350) */
 	{1368, 1008, 752,  711}, /* 02 (360x400,720x400) */
@@ -1206,7 +689,7 @@
 	{18,   1346, 1065, 1024} /* 07 (1280x1024x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_ExtLCDDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDes1280x1024Data[] = {
 	{9, 1337, 981,  940},  /* ; 00 (320x200,320x400,640x200,640x400) */
 	{9, 1337, 926,  884},  /* ; 01 (320x350,640x350) alan, 2003/09/30 */
 	{9, 1337, 981,  940},  /* ; 02 (360x400,720x400) */
@@ -1217,7 +700,7 @@
 	{9, 1337, 1065, 1024}  /* ; 07 (1280x1024x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_StLCDDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDes1280x1024Data[] = {
 	{9, 1337, 970,  907},  /* ; 00 (320x200,320x400,640x200,640x400) */
 	{9, 1337, 917,  854},  /* ; 01 (320x350,640x350) */
 	{9, 1337, 970,  907},  /* ; 02 (360x400,720x400) */
@@ -1228,7 +711,7 @@
 	{9, 1337, 1065, 1024}  /* ; 07 (1280x1024x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_CetLCDDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1280x1024Data[] = {
 	{1368, 1008, 752,  711}, /* 00 (320x200,320x400,640x200,640x400) */
 	{1368, 1008, 729,  688}, /* 01 (320x350,640x350) */
 	{1368, 1008, 752,  711}, /* 02 (360x400,720x400) */
@@ -1239,7 +722,7 @@
 	{9,    1337, 1065, 1024} /* 07 (1280x1024x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1400x1050[] = {
+static struct XGI_LCDDesStruct xgifb_lcddldes_1400x1050[] = {
 	{18,   1464, 0,    1051}, /* 00 (320x200,320x400,640x200,640x400) */
 	{18,   1464, 0,    1051}, /* 01 (320x350,640x350) */
 	{18,   1464, 0,    1051}, /* 02 (360x400,720x400) */
@@ -1251,7 +734,7 @@
 	{18,   1464, 0,    1051}  /* 08 (1400x1050x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct xgifb_lcddes_1400x1050[] = {
+static struct XGI_LCDDesStruct xgifb_lcddes_1400x1050[] = {
 	{9,    1455, 0,    1051}, /* 00 (320x200,320x400,640x200,640x400) */
 	{9,    1455, 0,    1051}, /* 01 (320x350,640x350) */
 	{9,    1455, 0,    1051}, /* 02 (360x400,720x400) */
@@ -1263,7 +746,7 @@
 	{9,    1455, 0,    1051}  /* 08 (1400x1050x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_CetLCDDes1400x1050Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1400x1050Data[] = {
 	{1308, 1068, 781,  766},  /* 00 (320x200,320x400,640x200,640x400) */
 	{1308, 1068, 781,  766},  /* 01 (320x350,640x350) */
 	{1308, 1068, 781,  766},  /* 02 (360x400,720x400) */
@@ -1275,7 +758,7 @@
 	{18,   1464, 0,    1051}  /* 08 (1400x1050x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_CetLCDDes1400x1050Data2[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1400x1050Data2[] = {
 	{0, 1448, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */
 	{0, 1448, 0, 1051}, /* 01 (320x350,640x350) */
 	{0, 1448, 0, 1051}, /* 02 (360x400,720x400) */
@@ -1283,7 +766,7 @@
 	{0, 1448, 0, 1051}  /* 04 (640x480x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_ExtLCDDLDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDLDes1600x1200Data[] = {
 	{18, 1682, 0, 1201}, /* 00 (320x200,320x400,640x200,640x400) */
 	{18, 1682, 0, 1201}, /* 01 (320x350,640x350) */
 	{18, 1682, 0, 1201}, /* 02 (360x400,720x400) */
@@ -1296,7 +779,7 @@
 	{18, 1682, 0, 1201}  /* 09 (1600x1200x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_StLCDDLDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDLDes1600x1200Data[] = {
 	{18, 1682, 1150, 1101}, /* 00 (320x200,320x400,640x200,640x400) */
 	{18, 1682, 1083, 1034}, /* 01 (320x350,640x350) */
 	{18, 1682, 1150, 1101}, /* 02 (360x400,720x400) */
@@ -1309,7 +792,7 @@
 	{18, 1682, 0,    1201} /* 09 (1600x1200x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_ExtLCDDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDes1600x1200Data[] = {
 	{9, 1673, 0, 1201}, /* 00 (320x200,320x400,640x200,640x400) */
 	{9, 1673, 0, 1201}, /* 01 (320x350,640x350) */
 	{9, 1673, 0, 1201}, /* 02 (360x400,720x400) */
@@ -1322,7 +805,7 @@
 	{9, 1673, 0, 1201}  /* 09 (1600x1200x60Hz) */
 };
 
-static struct XGI330_LCDDataDesStruct  XGI_StLCDDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDes1600x1200Data[] = {
 	{9, 1673, 1150, 1101}, /* 00 (320x200,320x400,640x200,640x400) */
 	{9, 1673, 1083, 1034}, /* 01 (320x350,640x350) */
 	{9, 1673, 1150, 1101}, /* 02 (360x400,720x400) */
@@ -1352,7 +835,7 @@
 };
 
 /* ;;1024x768x75Hz */
-static struct XGI330_LCDDataDesStruct xgifb_lcddes_1024x768x75[] = {
+static struct XGI_LCDDesStruct xgifb_lcddes_1024x768x75[] = {
 	{9, 1049, 0, 769}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{9, 1049, 0, 769}, /* ; 01 (320x350,640x350) */
 	{9, 1049, 0, 769}, /* ; 02 (360x400,720x400) */
@@ -1363,7 +846,7 @@
 };
 
 /* ;;1024x768x75Hz */
-static struct XGI330_LCDDataDesStruct  XGI_CetLCDDes1024x768x75Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1024x768x75Data[] = {
 	{1152, 856,  622, 587}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{1152, 856,  597, 562}, /* ; 01 (320x350,640x350) */
 	{1192, 896,  622, 587}, /* ; 02 (360x400,720x400) */
@@ -1374,7 +857,7 @@
 };
 
 /* ;;1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1280x1024x75[] = {
+static struct XGI_LCDDesStruct xgifb_lcddldes_1280x1024x75[] = {
 	{18, 1314, 0, 1025}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{18, 1314, 0, 1025}, /* ; 01 (320x350,640x350) */
 	{18, 1314, 0, 1025}, /* ; 02 (360x400,720x400) */
@@ -1386,7 +869,7 @@
 };
 
 /* 1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct  XGI_CetLCDDLDes1280x1024x75Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = {
 	{1368, 1008, 752, 711}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{1368, 1008, 729, 688}, /* ; 01 (320x350,640x350) */
 	{1408, 1048, 752, 711}, /* ; 02 (360x400,720x400) */
@@ -1398,7 +881,7 @@
 };
 
 /* ;;1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct xgifb_lcddes_1280x1024x75[] = {
+static struct XGI_LCDDesStruct xgifb_lcddes_1280x1024x75[] = {
 	{9, 1305, 0, 1025}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{9, 1305, 0, 1025}, /* ; 01 (320x350,640x350) */
 	{9, 1305, 0, 1025}, /* ; 02 (360x400,720x400) */
@@ -1410,7 +893,7 @@
 };
 
 /* 1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct  XGI_CetLCDDes1280x1024x75Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1280x1024x75Data[] = {
 	{1368, 1008, 752, 711}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{1368, 1008, 729, 688}, /* ; 01 (320x350,640x350) */
 	{1408, 1048, 752, 711}, /* ; 02 (360x400,720x400) */
diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h
index a7208e3..30cdd1a 100644
--- a/drivers/staging/xgifb/vgatypes.h
+++ b/drivers/staging/xgifb/vgatypes.h
@@ -66,8 +66,6 @@
 	unsigned long ulVideoMemorySize; /* size, in bytes, of the
 					    memory on the board */
 
-	unsigned char *pjIOAddress; /* base I/O address of VGA ports (0x3B0) */
-
 	unsigned char jChipType; /* Used to Identify Graphics Chip */
 				 /* defined in the data structure type  */
 				 /* "XGI_CHIP_TYPE" */
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 917461c..4496737 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -45,12 +45,12 @@
 
 static int is_first_page(struct page *page)
 {
-	return test_bit(PG_private, &page->flags);
+	return PagePrivate(page);
 }
 
 static int is_last_page(struct page *page)
 {
-	return test_bit(PG_private_2, &page->flags);
+	return PagePrivate2(page);
 }
 
 static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
@@ -180,7 +180,7 @@
  * link together 3 PAGE_SIZE sized pages to form a zspage
  * since then we can perfectly fit in 8 such objects.
  */
-static int get_zspage_order(int class_size)
+static int get_pages_per_zspage(int class_size)
 {
 	int i, max_usedpc = 0;
 	/* zspage order which gives maximum used size per KB */
@@ -368,7 +368,7 @@
 	 * identify the last page.
 	 */
 	error = -ENOMEM;
-	for (i = 0; i < class->zspage_order; i++) {
+	for (i = 0; i < class->pages_per_zspage; i++) {
 		struct page *page, *prev_page;
 
 		page = alloc_page(flags);
@@ -377,7 +377,7 @@
 
 		INIT_LIST_HEAD(&page->lru);
 		if (i == 0) {	/* first page */
-			set_bit(PG_private, &page->flags);
+			SetPagePrivate(page);
 			set_page_private(page, 0);
 			first_page = page;
 			first_page->inuse = 0;
@@ -388,9 +388,8 @@
 			page->first_page = first_page;
 		if (i >= 2)
 			list_add(&page->lru, &prev_page->lru);
-		if (i == class->zspage_order - 1)	/* last page */
-			set_bit(PG_private_2, &page->flags);
-
+		if (i == class->pages_per_zspage - 1)	/* last page */
+			SetPagePrivate2(page);
 		prev_page = page;
 	}
 
@@ -398,7 +397,7 @@
 
 	first_page->freelist = obj_location_to_handle(first_page, 0);
 	/* Maximum number of objects we can store in this zspage */
-	first_page->objects = class->zspage_order * PAGE_SIZE / class->size;
+	first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size;
 
 	error = 0; /* Success */
 
@@ -513,7 +512,7 @@
 		class->size = size;
 		class->index = i;
 		spin_lock_init(&class->lock);
-		class->zspage_order = get_zspage_order(size);
+		class->pages_per_zspage = get_pages_per_zspage(size);
 
 	}
 
@@ -567,13 +566,9 @@
  * zs_malloc - Allocate block of given size from pool.
  * @pool: pool to allocate from
  * @size: size of block to allocate
- * @page: page no. that holds the object
- * @offset: location of object within page
  *
- * On success, <page, offset> identifies block allocated
- * and 0 is returned. On failure, <page, offset> is set to
- * 0 and -ENOMEM is returned.
- *
+ * On success, handle to the allocated object is returned,
+ * otherwise NULL.
  * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
  */
 void *zs_malloc(struct zs_pool *pool, size_t size)
@@ -604,7 +599,7 @@
 
 		set_zspage_mapping(first_page, class->index, ZS_EMPTY);
 		spin_lock(&class->lock);
-		class->pages_allocated += class->zspage_order;
+		class->pages_allocated += class->pages_per_zspage;
 	}
 
 	obj = first_page->freelist;
@@ -659,7 +654,7 @@
 	fullness = fix_fullness_group(pool, first_page);
 
 	if (fullness == ZS_EMPTY)
-		class->pages_allocated -= class->zspage_order;
+		class->pages_allocated -= class->pages_per_zspage;
 
 	spin_unlock(&class->lock);
 
@@ -668,6 +663,15 @@
 }
 EXPORT_SYMBOL_GPL(zs_free);
 
+/**
+ * zs_map_object - get address of allocated object from handle.
+ * @pool: pool from which the object was allocated
+ * @handle: handle returned from zs_malloc
+ *
+ * Before using an object allocated from zs_malloc, it must be mapped using
+ * this function. When done with the object, it must be unmapped using
+ * zs_unmap_object
+*/
 void *zs_map_object(struct zs_pool *pool, void *handle)
 {
 	struct page *page;
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
index 92eefc6..6fd32a9 100644
--- a/drivers/staging/zsmalloc/zsmalloc_int.h
+++ b/drivers/staging/zsmalloc/zsmalloc_int.h
@@ -124,7 +124,7 @@
 	unsigned int index;
 
 	/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
-	int zspage_order;
+	int pages_per_zspage;
 
 	spinlock_t lock;
 
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
index b28794b..1830368 100644
--- a/drivers/target/Kconfig
+++ b/drivers/target/Kconfig
@@ -32,5 +32,6 @@
 source "drivers/target/loopback/Kconfig"
 source "drivers/target/tcm_fc/Kconfig"
 source "drivers/target/iscsi/Kconfig"
+source "drivers/target/sbp/Kconfig"
 
 endif
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 62e5405..61648d8 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -25,3 +25,4 @@
 obj-$(CONFIG_LOOPBACK_TARGET)	+= loopback/
 obj-$(CONFIG_TCM_FC)		+= tcm_fc/
 obj-$(CONFIG_ISCSI_TARGET)	+= iscsi/
+obj-$(CONFIG_SBP_TARGET)	+= sbp/
diff --git a/drivers/target/sbp/Kconfig b/drivers/target/sbp/Kconfig
new file mode 100644
index 0000000..132da54
--- /dev/null
+++ b/drivers/target/sbp/Kconfig
@@ -0,0 +1,11 @@
+config SBP_TARGET
+	tristate "FireWire SBP-2 fabric module"
+	depends on FIREWIRE && EXPERIMENTAL
+	help
+	  Say Y or M here to enable SCSI target functionality over FireWire.
+	  This enables you to expose SCSI devices to other nodes on the FireWire
+	  bus, for example hard disks. Similar to FireWire Target Disk mode on
+	  many Apple computers.
+
+	  To compile this driver as a module, say M here: The module will be
+	  called sbp-target.
diff --git a/drivers/target/sbp/Makefile b/drivers/target/sbp/Makefile
new file mode 100644
index 0000000..27747ad
--- /dev/null
+++ b/drivers/target/sbp/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SBP_TARGET) += sbp_target.o
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
new file mode 100644
index 0000000..37c6098
--- /dev/null
+++ b/drivers/target/sbp/sbp_target.c
@@ -0,0 +1,2621 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * 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.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <asm/unaligned.h>
+
+#include "sbp_target.h"
+
+/* Local pointer to allocated TCM configfs fabric module */
+static struct target_fabric_configfs *sbp_fabric_configfs;
+
+/* FireWire address region for management and command block address handlers */
+static const struct fw_address_region sbp_register_region = {
+	.start	= CSR_REGISTER_BASE + 0x10000,
+	.end	= 0x1000000000000ULL,
+};
+
+static const u32 sbp_unit_directory_template[] = {
+	0x1200609e, /* unit_specifier_id: NCITS/T10 */
+	0x13010483, /* unit_sw_version: 1155D Rev 4 */
+	0x3800609e, /* command_set_specifier_id: NCITS/T10 */
+	0x390104d8, /* command_set: SPC-2 */
+	0x3b000000, /* command_set_revision: 0 */
+	0x3c000001, /* firmware_revision: 1 */
+};
+
+#define SESSION_MAINTENANCE_INTERVAL HZ
+
+static atomic_t login_id = ATOMIC_INIT(0);
+
+static void session_maintenance_work(struct work_struct *);
+static int sbp_run_transaction(struct fw_card *, int, int, int, int,
+		unsigned long long, void *, size_t);
+
+static int read_peer_guid(u64 *guid, const struct sbp_management_request *req)
+{
+	int ret;
+	__be32 high, low;
+
+	ret = sbp_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+			req->node_addr, req->generation, req->speed,
+			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 3 * 4,
+			&high, sizeof(high));
+	if (ret != RCODE_COMPLETE)
+		return ret;
+
+	ret = sbp_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+			req->node_addr, req->generation, req->speed,
+			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 4 * 4,
+			&low, sizeof(low));
+	if (ret != RCODE_COMPLETE)
+		return ret;
+
+	*guid = (u64)be32_to_cpu(high) << 32 | be32_to_cpu(low);
+
+	return RCODE_COMPLETE;
+}
+
+static struct sbp_session *sbp_session_find_by_guid(
+	struct sbp_tpg *tpg, u64 guid)
+{
+	struct se_session *se_sess;
+	struct sbp_session *sess, *found = NULL;
+
+	spin_lock_bh(&tpg->se_tpg.session_lock);
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		sess = se_sess->fabric_sess_ptr;
+		if (sess->guid == guid)
+			found = sess;
+	}
+	spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+	return found;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_lun(
+		struct sbp_session *session, struct se_lun *lun)
+{
+	struct sbp_login_descriptor *login, *found = NULL;
+
+	spin_lock_bh(&session->lock);
+	list_for_each_entry(login, &session->login_list, link) {
+		if (login->lun == lun)
+			found = login;
+	}
+	spin_unlock_bh(&session->lock);
+
+	return found;
+}
+
+static int sbp_login_count_all_by_lun(
+		struct sbp_tpg *tpg,
+		struct se_lun *lun,
+		int exclusive)
+{
+	struct se_session *se_sess;
+	struct sbp_session *sess;
+	struct sbp_login_descriptor *login;
+	int count = 0;
+
+	spin_lock_bh(&tpg->se_tpg.session_lock);
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		sess = se_sess->fabric_sess_ptr;
+
+		spin_lock_bh(&sess->lock);
+		list_for_each_entry(login, &sess->login_list, link) {
+			if (login->lun != lun)
+				continue;
+
+			if (!exclusive || login->exclusive)
+				count++;
+		}
+		spin_unlock_bh(&sess->lock);
+	}
+	spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+	return count;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_id(
+	struct sbp_tpg *tpg, int login_id)
+{
+	struct se_session *se_sess;
+	struct sbp_session *sess;
+	struct sbp_login_descriptor *login, *found = NULL;
+
+	spin_lock_bh(&tpg->se_tpg.session_lock);
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		sess = se_sess->fabric_sess_ptr;
+
+		spin_lock_bh(&sess->lock);
+		list_for_each_entry(login, &sess->login_list, link) {
+			if (login->login_id == login_id)
+				found = login;
+		}
+		spin_unlock_bh(&sess->lock);
+	}
+	spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+	return found;
+}
+
+static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun)
+{
+	struct se_portal_group *se_tpg = &tpg->se_tpg;
+	struct se_lun *se_lun;
+
+	if (lun >= TRANSPORT_MAX_LUNS_PER_TPG)
+		return ERR_PTR(-EINVAL);
+
+	spin_lock(&se_tpg->tpg_lun_lock);
+	se_lun = se_tpg->tpg_lun_list[lun];
+
+	if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
+		se_lun = ERR_PTR(-ENODEV);
+
+	spin_unlock(&se_tpg->tpg_lun_lock);
+
+	return se_lun;
+}
+
+static struct sbp_session *sbp_session_create(
+		struct sbp_tpg *tpg,
+		u64 guid)
+{
+	struct sbp_session *sess;
+	int ret;
+	char guid_str[17];
+	struct se_node_acl *se_nacl;
+
+	sess = kmalloc(sizeof(*sess), GFP_KERNEL);
+	if (!sess) {
+		pr_err("failed to allocate session descriptor\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sess->se_sess = transport_init_session();
+	if (IS_ERR(sess->se_sess)) {
+		pr_err("failed to init se_session\n");
+
+		ret = PTR_ERR(sess->se_sess);
+		kfree(sess);
+		return ERR_PTR(ret);
+	}
+
+	snprintf(guid_str, sizeof(guid_str), "%016llx", guid);
+
+	se_nacl = core_tpg_check_initiator_node_acl(&tpg->se_tpg, guid_str);
+	if (!se_nacl) {
+		pr_warn("Node ACL not found for %s\n", guid_str);
+
+		transport_free_session(sess->se_sess);
+		kfree(sess);
+
+		return ERR_PTR(-EPERM);
+	}
+
+	sess->se_sess->se_node_acl = se_nacl;
+
+	spin_lock_init(&sess->lock);
+	INIT_LIST_HEAD(&sess->login_list);
+	INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work);
+
+	sess->guid = guid;
+
+	transport_register_session(&tpg->se_tpg, se_nacl, sess->se_sess, sess);
+
+	return sess;
+}
+
+static void sbp_session_release(struct sbp_session *sess, bool cancel_work)
+{
+	spin_lock_bh(&sess->lock);
+	if (!list_empty(&sess->login_list)) {
+		spin_unlock_bh(&sess->lock);
+		return;
+	}
+	spin_unlock_bh(&sess->lock);
+
+	if (cancel_work)
+		cancel_delayed_work_sync(&sess->maint_work);
+
+	transport_deregister_session_configfs(sess->se_sess);
+	transport_deregister_session(sess->se_sess);
+
+	if (sess->card)
+		fw_card_put(sess->card);
+
+	kfree(sess);
+}
+
+static void sbp_target_agent_unregister(struct sbp_target_agent *);
+
+static void sbp_login_release(struct sbp_login_descriptor *login,
+	bool cancel_work)
+{
+	struct sbp_session *sess = login->sess;
+
+	/* FIXME: abort/wait on tasks */
+
+	sbp_target_agent_unregister(login->tgt_agt);
+
+	if (sess) {
+		spin_lock_bh(&sess->lock);
+		list_del(&login->link);
+		spin_unlock_bh(&sess->lock);
+
+		sbp_session_release(sess, cancel_work);
+	}
+
+	kfree(login);
+}
+
+static struct sbp_target_agent *sbp_target_agent_register(
+	struct sbp_login_descriptor *);
+
+static void sbp_management_request_login(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	struct se_lun *se_lun;
+	int ret;
+	u64 guid;
+	struct sbp_session *sess;
+	struct sbp_login_descriptor *login;
+	struct sbp_login_response_block *response;
+	int login_response_len;
+
+	se_lun = sbp_get_lun_from_tpg(tpg,
+			LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+	if (IS_ERR(se_lun)) {
+		pr_notice("login to unknown LUN: %d\n",
+			LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LUN_NOTSUPP));
+		return;
+	}
+
+	ret = read_peer_guid(&guid, req);
+	if (ret != RCODE_COMPLETE) {
+		pr_warn("failed to read peer GUID: %d\n", ret);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n",
+		se_lun->unpacked_lun, guid);
+
+	sess = sbp_session_find_by_guid(tpg, guid);
+	if (sess) {
+		login = sbp_login_find_by_lun(sess, se_lun);
+		if (login) {
+			pr_notice("initiator already logged-in\n");
+
+			/*
+			 * SBP-2 R4 says we should return access denied, but
+			 * that can confuse initiators. Instead we need to
+			 * treat this like a reconnect, but send the login
+			 * response block like a fresh login.
+			 *
+			 * This is required particularly in the case of Apple
+			 * devices booting off the FireWire target, where
+			 * the firmware has an active login to the target. When
+			 * the OS takes control of the session it issues its own
+			 * LOGIN rather than a RECONNECT. To avoid the machine
+			 * waiting until the reconnect_hold expires, we can skip
+			 * the ACCESS_DENIED errors to speed things up.
+			 */
+
+			goto already_logged_in;
+		}
+	}
+
+	/*
+	 * check exclusive bit in login request
+	 * reject with access_denied if any logins present
+	 */
+	if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) &&
+			sbp_login_count_all_by_lun(tpg, se_lun, 0)) {
+		pr_warn("refusing exclusive login with other active logins\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	/*
+	 * check exclusive bit in any existing login descriptor
+	 * reject with access_denied if any exclusive logins present
+	 */
+	if (sbp_login_count_all_by_lun(tpg, se_lun, 1)) {
+		pr_warn("refusing login while another exclusive login present\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	/*
+	 * check we haven't exceeded the number of allowed logins
+	 * reject with resources_unavailable if we have
+	 */
+	if (sbp_login_count_all_by_lun(tpg, se_lun, 0) >=
+			tport->max_logins_per_lun) {
+		pr_warn("max number of logins reached\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	if (!sess) {
+		sess = sbp_session_create(tpg, guid);
+		if (IS_ERR(sess)) {
+			switch (PTR_ERR(sess)) {
+			case -EPERM:
+				ret = SBP_STATUS_ACCESS_DENIED;
+				break;
+			default:
+				ret = SBP_STATUS_RESOURCES_UNAVAIL;
+				break;
+			}
+
+			req->status.status = cpu_to_be32(
+				STATUS_BLOCK_RESP(
+					STATUS_RESP_REQUEST_COMPLETE) |
+				STATUS_BLOCK_SBP_STATUS(ret));
+			return;
+		}
+
+		sess->node_id = req->node_addr;
+		sess->card = fw_card_get(req->card);
+		sess->generation = req->generation;
+		sess->speed = req->speed;
+
+		schedule_delayed_work(&sess->maint_work,
+				SESSION_MAINTENANCE_INTERVAL);
+	}
+
+	/* only take the latest reconnect_hold into account */
+	sess->reconnect_hold = min(
+		1 << LOGIN_ORB_RECONNECT(be32_to_cpu(req->orb.misc)),
+		tport->max_reconnect_timeout) - 1;
+
+	login = kmalloc(sizeof(*login), GFP_KERNEL);
+	if (!login) {
+		pr_err("failed to allocate login descriptor\n");
+
+		sbp_session_release(sess, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	login->sess = sess;
+	login->lun = se_lun;
+	login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo);
+	login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc));
+	login->login_id = atomic_inc_return(&login_id);
+
+	login->tgt_agt = sbp_target_agent_register(login);
+	if (IS_ERR(login->tgt_agt)) {
+		ret = PTR_ERR(login->tgt_agt);
+		pr_err("failed to map command block handler: %d\n", ret);
+
+		sbp_session_release(sess, true);
+		kfree(login);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	spin_lock_bh(&sess->lock);
+	list_add_tail(&login->link, &sess->login_list);
+	spin_unlock_bh(&sess->lock);
+
+already_logged_in:
+	response = kzalloc(sizeof(*response), GFP_KERNEL);
+	if (!response) {
+		pr_err("failed to allocate login response block\n");
+
+		sbp_login_release(login, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	login_response_len = clamp_val(
+			LOGIN_ORB_RESPONSE_LENGTH(be32_to_cpu(req->orb.length)),
+			12, sizeof(*response));
+	response->misc = cpu_to_be32(
+		((login_response_len & 0xffff) << 16) |
+		(login->login_id & 0xffff));
+	response->reconnect_hold = cpu_to_be32(sess->reconnect_hold & 0xffff);
+	addr_to_sbp2_pointer(login->tgt_agt->handler.offset,
+		&response->command_block_agent);
+
+	ret = sbp_run_transaction(sess->card, TCODE_WRITE_BLOCK_REQUEST,
+		sess->node_id, sess->generation, sess->speed,
+		sbp2_pointer_to_addr(&req->orb.ptr2), response,
+		login_response_len);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("failed to write login response block: %x\n", ret);
+
+		kfree(response);
+		sbp_login_release(login, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	kfree(response);
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void sbp_management_request_query_logins(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	pr_notice("QUERY LOGINS not implemented\n");
+	/* FIXME: implement */
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+}
+
+static void sbp_management_request_reconnect(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	int ret;
+	u64 guid;
+	struct sbp_login_descriptor *login;
+
+	ret = read_peer_guid(&guid, req);
+	if (ret != RCODE_COMPLETE) {
+		pr_warn("failed to read peer GUID: %d\n", ret);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	pr_notice("mgt_agent RECONNECT from %016llx\n", guid);
+
+	login = sbp_login_find_by_id(tpg,
+		RECONNECT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc)));
+
+	if (!login) {
+		pr_err("mgt_agent RECONNECT unknown login ID\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	if (login->sess->guid != guid) {
+		pr_err("mgt_agent RECONNECT login GUID doesn't match\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	spin_lock_bh(&login->sess->lock);
+	if (login->sess->card)
+		fw_card_put(login->sess->card);
+
+	/* update the node details */
+	login->sess->generation = req->generation;
+	login->sess->node_id = req->node_addr;
+	login->sess->card = fw_card_get(req->card);
+	login->sess->speed = req->speed;
+	spin_unlock_bh(&login->sess->lock);
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void sbp_management_request_logout(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	int login_id;
+	struct sbp_login_descriptor *login;
+
+	login_id = LOGOUT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc));
+
+	login = sbp_login_find_by_id(tpg, login_id);
+	if (!login) {
+		pr_warn("cannot find login: %d\n", login_id);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LOGIN_ID_UNKNOWN));
+		return;
+	}
+
+	pr_info("mgt_agent LOGOUT from LUN %d session %d\n",
+		login->lun->unpacked_lun, login->login_id);
+
+	if (req->node_addr != login->sess->node_id) {
+		pr_warn("logout from different node ID\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	sbp_login_release(login, true);
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void session_check_for_reset(struct sbp_session *sess)
+{
+	bool card_valid = false;
+
+	spin_lock_bh(&sess->lock);
+
+	if (sess->card) {
+		spin_lock_irq(&sess->card->lock);
+		card_valid = (sess->card->local_node != NULL);
+		spin_unlock_irq(&sess->card->lock);
+
+		if (!card_valid) {
+			fw_card_put(sess->card);
+			sess->card = NULL;
+		}
+	}
+
+	if (!card_valid || (sess->generation != sess->card->generation)) {
+		pr_info("Waiting for reconnect from node: %016llx\n",
+				sess->guid);
+
+		sess->node_id = -1;
+		sess->reconnect_expires = get_jiffies_64() +
+			((sess->reconnect_hold + 1) * HZ);
+	}
+
+	spin_unlock_bh(&sess->lock);
+}
+
+static void session_reconnect_expired(struct sbp_session *sess)
+{
+	struct sbp_login_descriptor *login, *temp;
+	LIST_HEAD(login_list);
+
+	pr_info("Reconnect timer expired for node: %016llx\n", sess->guid);
+
+	spin_lock_bh(&sess->lock);
+	list_for_each_entry_safe(login, temp, &sess->login_list, link) {
+		login->sess = NULL;
+		list_del(&login->link);
+		list_add_tail(&login->link, &login_list);
+	}
+	spin_unlock_bh(&sess->lock);
+
+	list_for_each_entry_safe(login, temp, &login_list, link) {
+		list_del(&login->link);
+		sbp_login_release(login, false);
+	}
+
+	sbp_session_release(sess, false);
+}
+
+static void session_maintenance_work(struct work_struct *work)
+{
+	struct sbp_session *sess = container_of(work, struct sbp_session,
+			maint_work.work);
+
+	/* could be called while tearing down the session */
+	spin_lock_bh(&sess->lock);
+	if (list_empty(&sess->login_list)) {
+		spin_unlock_bh(&sess->lock);
+		return;
+	}
+	spin_unlock_bh(&sess->lock);
+
+	if (sess->node_id != -1) {
+		/* check for bus reset and make node_id invalid */
+		session_check_for_reset(sess);
+
+		schedule_delayed_work(&sess->maint_work,
+				SESSION_MAINTENANCE_INTERVAL);
+	} else if (!time_after64(get_jiffies_64(), sess->reconnect_expires)) {
+		/* still waiting for reconnect */
+		schedule_delayed_work(&sess->maint_work,
+				SESSION_MAINTENANCE_INTERVAL);
+	} else {
+		/* reconnect timeout has expired */
+		session_reconnect_expired(sess);
+	}
+}
+
+static int tgt_agent_rw_agent_state(struct fw_card *card, int tcode, void *data,
+		struct sbp_target_agent *agent)
+{
+	__be32 state;
+
+	switch (tcode) {
+	case TCODE_READ_QUADLET_REQUEST:
+		pr_debug("tgt_agent AGENT_STATE READ\n");
+
+		spin_lock_bh(&agent->lock);
+		state = cpu_to_be32(agent->state);
+		spin_unlock_bh(&agent->lock);
+		memcpy(data, &state, sizeof(state));
+
+		return RCODE_COMPLETE;
+
+	case TCODE_WRITE_QUADLET_REQUEST:
+		/* ignored */
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_agent_reset(struct fw_card *card, int tcode, void *data,
+		struct sbp_target_agent *agent)
+{
+	switch (tcode) {
+	case TCODE_WRITE_QUADLET_REQUEST:
+		pr_debug("tgt_agent AGENT_RESET\n");
+		spin_lock_bh(&agent->lock);
+		agent->state = AGENT_STATE_RESET;
+		spin_unlock_bh(&agent->lock);
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_orb_pointer(struct fw_card *card, int tcode, void *data,
+		struct sbp_target_agent *agent)
+{
+	struct sbp2_pointer *ptr = data;
+
+	switch (tcode) {
+	case TCODE_WRITE_BLOCK_REQUEST:
+		spin_lock_bh(&agent->lock);
+		if (agent->state != AGENT_STATE_SUSPENDED &&
+				agent->state != AGENT_STATE_RESET) {
+			spin_unlock_bh(&agent->lock);
+			pr_notice("Ignoring ORB_POINTER write while active.\n");
+			return RCODE_CONFLICT_ERROR;
+		}
+		agent->state = AGENT_STATE_ACTIVE;
+		spin_unlock_bh(&agent->lock);
+
+		agent->orb_pointer = sbp2_pointer_to_addr(ptr);
+		agent->doorbell = false;
+
+		pr_debug("tgt_agent ORB_POINTER write: 0x%llx\n",
+				agent->orb_pointer);
+
+		queue_work(system_unbound_wq, &agent->work);
+
+		return RCODE_COMPLETE;
+
+	case TCODE_READ_BLOCK_REQUEST:
+		pr_debug("tgt_agent ORB_POINTER READ\n");
+		spin_lock_bh(&agent->lock);
+		addr_to_sbp2_pointer(agent->orb_pointer, ptr);
+		spin_unlock_bh(&agent->lock);
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_doorbell(struct fw_card *card, int tcode, void *data,
+		struct sbp_target_agent *agent)
+{
+	switch (tcode) {
+	case TCODE_WRITE_QUADLET_REQUEST:
+		spin_lock_bh(&agent->lock);
+		if (agent->state != AGENT_STATE_SUSPENDED) {
+			spin_unlock_bh(&agent->lock);
+			pr_debug("Ignoring DOORBELL while active.\n");
+			return RCODE_CONFLICT_ERROR;
+		}
+		agent->state = AGENT_STATE_ACTIVE;
+		spin_unlock_bh(&agent->lock);
+
+		agent->doorbell = true;
+
+		pr_debug("tgt_agent DOORBELL\n");
+
+		queue_work(system_unbound_wq, &agent->work);
+
+		return RCODE_COMPLETE;
+
+	case TCODE_READ_QUADLET_REQUEST:
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_unsolicited_status_enable(struct fw_card *card,
+		int tcode, void *data, struct sbp_target_agent *agent)
+{
+	switch (tcode) {
+	case TCODE_WRITE_QUADLET_REQUEST:
+		pr_debug("tgt_agent UNSOLICITED_STATUS_ENABLE\n");
+		/* ignored as we don't send unsolicited status */
+		return RCODE_COMPLETE;
+
+	case TCODE_READ_QUADLET_REQUEST:
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static void tgt_agent_rw(struct fw_card *card, struct fw_request *request,
+		int tcode, int destination, int source, int generation,
+		unsigned long long offset, void *data, size_t length,
+		void *callback_data)
+{
+	struct sbp_target_agent *agent = callback_data;
+	struct sbp_session *sess = agent->login->sess;
+	int sess_gen, sess_node, rcode;
+
+	spin_lock_bh(&sess->lock);
+	sess_gen = sess->generation;
+	sess_node = sess->node_id;
+	spin_unlock_bh(&sess->lock);
+
+	if (generation != sess_gen) {
+		pr_notice("ignoring request with wrong generation\n");
+		rcode = RCODE_TYPE_ERROR;
+		goto out;
+	}
+
+	if (source != sess_node) {
+		pr_notice("ignoring request from foreign node (%x != %x)\n",
+				source, sess_node);
+		rcode = RCODE_TYPE_ERROR;
+		goto out;
+	}
+
+	/* turn offset into the offset from the start of the block */
+	offset -= agent->handler.offset;
+
+	if (offset == 0x00 && length == 4) {
+		/* AGENT_STATE */
+		rcode = tgt_agent_rw_agent_state(card, tcode, data, agent);
+	} else if (offset == 0x04 && length == 4) {
+		/* AGENT_RESET */
+		rcode = tgt_agent_rw_agent_reset(card, tcode, data, agent);
+	} else if (offset == 0x08 && length == 8) {
+		/* ORB_POINTER */
+		rcode = tgt_agent_rw_orb_pointer(card, tcode, data, agent);
+	} else if (offset == 0x10 && length == 4) {
+		/* DOORBELL */
+		rcode = tgt_agent_rw_doorbell(card, tcode, data, agent);
+	} else if (offset == 0x14 && length == 4) {
+		/* UNSOLICITED_STATUS_ENABLE */
+		rcode = tgt_agent_rw_unsolicited_status_enable(card, tcode,
+				data, agent);
+	} else {
+		rcode = RCODE_ADDRESS_ERROR;
+	}
+
+out:
+	fw_send_response(card, request, rcode);
+}
+
+static void sbp_handle_command(struct sbp_target_request *);
+static int sbp_send_status(struct sbp_target_request *);
+static void sbp_free_request(struct sbp_target_request *);
+
+static void tgt_agent_process_work(struct work_struct *work)
+{
+	struct sbp_target_request *req =
+		container_of(work, struct sbp_target_request, work);
+
+	pr_debug("tgt_orb ptr:0x%llx next_ORB:0x%llx data_descriptor:0x%llx misc:0x%x\n",
+			req->orb_pointer,
+			sbp2_pointer_to_addr(&req->orb.next_orb),
+			sbp2_pointer_to_addr(&req->orb.data_descriptor),
+			be32_to_cpu(req->orb.misc));
+
+	if (req->orb_pointer >> 32)
+		pr_debug("ORB with high bits set\n");
+
+	switch (ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc))) {
+		case 0:/* Format specified by this standard */
+			sbp_handle_command(req);
+			return;
+		case 1: /* Reserved for future standardization */
+		case 2: /* Vendor-dependent */
+			req->status.status |= cpu_to_be32(
+					STATUS_BLOCK_RESP(
+						STATUS_RESP_REQUEST_COMPLETE) |
+					STATUS_BLOCK_DEAD(0) |
+					STATUS_BLOCK_LEN(1) |
+					STATUS_BLOCK_SBP_STATUS(
+						SBP_STATUS_REQ_TYPE_NOTSUPP));
+			sbp_send_status(req);
+			sbp_free_request(req);
+			return;
+		case 3: /* Dummy ORB */
+			req->status.status |= cpu_to_be32(
+					STATUS_BLOCK_RESP(
+						STATUS_RESP_REQUEST_COMPLETE) |
+					STATUS_BLOCK_DEAD(0) |
+					STATUS_BLOCK_LEN(1) |
+					STATUS_BLOCK_SBP_STATUS(
+						SBP_STATUS_DUMMY_ORB_COMPLETE));
+			sbp_send_status(req);
+			sbp_free_request(req);
+			return;
+		default:
+			BUG();
+	}
+}
+
+/* used to double-check we haven't been issued an AGENT_RESET */
+static inline bool tgt_agent_check_active(struct sbp_target_agent *agent)
+{
+	bool active;
+
+	spin_lock_bh(&agent->lock);
+	active = (agent->state == AGENT_STATE_ACTIVE);
+	spin_unlock_bh(&agent->lock);
+
+	return active;
+}
+
+static void tgt_agent_fetch_work(struct work_struct *work)
+{
+	struct sbp_target_agent *agent =
+		container_of(work, struct sbp_target_agent, work);
+	struct sbp_session *sess = agent->login->sess;
+	struct sbp_target_request *req;
+	int ret;
+	bool doorbell = agent->doorbell;
+	u64 next_orb = agent->orb_pointer;
+
+	while (next_orb && tgt_agent_check_active(agent)) {
+		req = kzalloc(sizeof(*req), GFP_KERNEL);
+		if (!req) {
+			spin_lock_bh(&agent->lock);
+			agent->state = AGENT_STATE_DEAD;
+			spin_unlock_bh(&agent->lock);
+			return;
+		}
+
+		req->login = agent->login;
+		req->orb_pointer = next_orb;
+
+		req->status.status = cpu_to_be32(STATUS_BLOCK_ORB_OFFSET_HIGH(
+					req->orb_pointer >> 32));
+		req->status.orb_low = cpu_to_be32(
+				req->orb_pointer & 0xfffffffc);
+
+		/* read in the ORB */
+		ret = sbp_run_transaction(sess->card, TCODE_READ_BLOCK_REQUEST,
+				sess->node_id, sess->generation, sess->speed,
+				req->orb_pointer, &req->orb, sizeof(req->orb));
+		if (ret != RCODE_COMPLETE) {
+			pr_debug("tgt_orb fetch failed: %x\n", ret);
+			req->status.status |= cpu_to_be32(
+					STATUS_BLOCK_SRC(
+						STATUS_SRC_ORB_FINISHED) |
+					STATUS_BLOCK_RESP(
+						STATUS_RESP_TRANSPORT_FAILURE) |
+					STATUS_BLOCK_DEAD(1) |
+					STATUS_BLOCK_LEN(1) |
+					STATUS_BLOCK_SBP_STATUS(
+						SBP_STATUS_UNSPECIFIED_ERROR));
+			spin_lock_bh(&agent->lock);
+			agent->state = AGENT_STATE_DEAD;
+			spin_unlock_bh(&agent->lock);
+
+			sbp_send_status(req);
+			sbp_free_request(req);
+			return;
+		}
+
+		/* check the next_ORB field */
+		if (be32_to_cpu(req->orb.next_orb.high) & 0x80000000) {
+			next_orb = 0;
+			req->status.status |= cpu_to_be32(STATUS_BLOCK_SRC(
+						STATUS_SRC_ORB_FINISHED));
+		} else {
+			next_orb = sbp2_pointer_to_addr(&req->orb.next_orb);
+			req->status.status |= cpu_to_be32(STATUS_BLOCK_SRC(
+						STATUS_SRC_ORB_CONTINUING));
+		}
+
+		if (tgt_agent_check_active(agent) && !doorbell) {
+			INIT_WORK(&req->work, tgt_agent_process_work);
+			queue_work(system_unbound_wq, &req->work);
+		} else {
+			/* don't process this request, just check next_ORB */
+			sbp_free_request(req);
+		}
+
+		spin_lock_bh(&agent->lock);
+		doorbell = agent->doorbell = false;
+
+		/* check if we should carry on processing */
+		if (next_orb)
+			agent->orb_pointer = next_orb;
+		else
+			agent->state = AGENT_STATE_SUSPENDED;
+
+		spin_unlock_bh(&agent->lock);
+	};
+}
+
+static struct sbp_target_agent *sbp_target_agent_register(
+		struct sbp_login_descriptor *login)
+{
+	struct sbp_target_agent *agent;
+	int ret;
+
+	agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+	if (!agent)
+		return ERR_PTR(-ENOMEM);
+
+	spin_lock_init(&agent->lock);
+
+	agent->handler.length = 0x20;
+	agent->handler.address_callback = tgt_agent_rw;
+	agent->handler.callback_data = agent;
+
+	agent->login = login;
+	agent->state = AGENT_STATE_RESET;
+	INIT_WORK(&agent->work, tgt_agent_fetch_work);
+	agent->orb_pointer = 0;
+	agent->doorbell = false;
+
+	ret = fw_core_add_address_handler(&agent->handler,
+			&sbp_register_region);
+	if (ret < 0) {
+		kfree(agent);
+		return ERR_PTR(ret);
+	}
+
+	return agent;
+}
+
+static void sbp_target_agent_unregister(struct sbp_target_agent *agent)
+{
+	fw_core_remove_address_handler(&agent->handler);
+	cancel_work_sync(&agent->work);
+	kfree(agent);
+}
+
+/*
+ * Simple wrapper around fw_run_transaction that retries the transaction several
+ * times in case of failure, with an exponential backoff.
+ */
+static int sbp_run_transaction(struct fw_card *card, int tcode, int destination_id,
+		int generation, int speed, unsigned long long offset,
+		void *payload, size_t length)
+{
+	int attempt, ret, delay;
+
+	for (attempt = 1; attempt <= 5; attempt++) {
+		ret = fw_run_transaction(card, tcode, destination_id,
+				generation, speed, offset, payload, length);
+
+		switch (ret) {
+		case RCODE_COMPLETE:
+		case RCODE_TYPE_ERROR:
+		case RCODE_ADDRESS_ERROR:
+		case RCODE_GENERATION:
+			return ret;
+
+		default:
+			delay = 5 * attempt * attempt;
+			usleep_range(delay, delay * 2);
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Wrapper around sbp_run_transaction that gets the card, destination,
+ * generation and speed out of the request's session.
+ */
+static int sbp_run_request_transaction(struct sbp_target_request *req,
+		int tcode, unsigned long long offset, void *payload,
+		size_t length)
+{
+	struct sbp_login_descriptor *login = req->login;
+	struct sbp_session *sess = login->sess;
+	struct fw_card *card;
+	int node_id, generation, speed, ret;
+
+	spin_lock_bh(&sess->lock);
+	card = fw_card_get(sess->card);
+	node_id = sess->node_id;
+	generation = sess->generation;
+	speed = sess->speed;
+	spin_unlock_bh(&sess->lock);
+
+	ret = sbp_run_transaction(card, tcode, node_id, generation, speed,
+			offset, payload, length);
+
+	fw_card_put(card);
+
+	return ret;
+}
+
+static int sbp_fetch_command(struct sbp_target_request *req)
+{
+	int ret, cmd_len, copy_len;
+
+	cmd_len = scsi_command_size(req->orb.command_block);
+
+	req->cmd_buf = kmalloc(cmd_len, GFP_KERNEL);
+	if (!req->cmd_buf)
+		return -ENOMEM;
+
+	memcpy(req->cmd_buf, req->orb.command_block,
+		min_t(int, cmd_len, sizeof(req->orb.command_block)));
+
+	if (cmd_len > sizeof(req->orb.command_block)) {
+		pr_debug("sbp_fetch_command: filling in long command\n");
+		copy_len = cmd_len - sizeof(req->orb.command_block);
+
+		ret = sbp_run_request_transaction(req,
+				TCODE_READ_BLOCK_REQUEST,
+				req->orb_pointer + sizeof(req->orb),
+				req->cmd_buf + sizeof(req->orb.command_block),
+				copy_len);
+		if (ret != RCODE_COMPLETE)
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int sbp_fetch_page_table(struct sbp_target_request *req)
+{
+	int pg_tbl_sz, ret;
+	struct sbp_page_table_entry *pg_tbl;
+
+	if (!CMDBLK_ORB_PG_TBL_PRESENT(be32_to_cpu(req->orb.misc)))
+		return 0;
+
+	pg_tbl_sz = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc)) *
+		sizeof(struct sbp_page_table_entry);
+
+	pg_tbl = kmalloc(pg_tbl_sz, GFP_KERNEL);
+	if (!pg_tbl)
+		return -ENOMEM;
+
+	ret = sbp_run_request_transaction(req, TCODE_READ_BLOCK_REQUEST,
+			sbp2_pointer_to_addr(&req->orb.data_descriptor),
+			pg_tbl, pg_tbl_sz);
+	if (ret != RCODE_COMPLETE) {
+		kfree(pg_tbl);
+		return -EIO;
+	}
+
+	req->pg_tbl = pg_tbl;
+	return 0;
+}
+
+static void sbp_calc_data_length_direction(struct sbp_target_request *req,
+	u32 *data_len, enum dma_data_direction *data_dir)
+{
+	int data_size, direction, idx;
+
+	data_size = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+	direction = CMDBLK_ORB_DIRECTION(be32_to_cpu(req->orb.misc));
+
+	if (!data_size) {
+		*data_len = 0;
+		*data_dir = DMA_NONE;
+		return;
+	}
+
+	*data_dir = direction ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+	if (req->pg_tbl) {
+		*data_len = 0;
+		for (idx = 0; idx < data_size; idx++) {
+			*data_len += be16_to_cpu(
+					req->pg_tbl[idx].segment_length);
+		}
+	} else {
+		*data_len = data_size;
+	}
+}
+
+static void sbp_handle_command(struct sbp_target_request *req)
+{
+	struct sbp_login_descriptor *login = req->login;
+	struct sbp_session *sess = login->sess;
+	int ret, unpacked_lun;
+	u32 data_length;
+	enum dma_data_direction data_dir;
+
+	ret = sbp_fetch_command(req);
+	if (ret) {
+		pr_debug("sbp_handle_command: fetch command failed: %d\n", ret);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	}
+
+	ret = sbp_fetch_page_table(req);
+	if (ret) {
+		pr_debug("sbp_handle_command: fetch page table failed: %d\n",
+			ret);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	}
+
+	unpacked_lun = req->login->lun->unpacked_lun;
+	sbp_calc_data_length_direction(req, &data_length, &data_dir);
+
+	pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n",
+			req->orb_pointer, unpacked_lun, data_length, data_dir);
+
+	target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf,
+			req->sense_buf, unpacked_lun, data_length,
+			MSG_SIMPLE_TAG, data_dir, 0);
+}
+
+/*
+ * DMA_TO_DEVICE = read from initiator (SCSI WRITE)
+ * DMA_FROM_DEVICE = write to initiator (SCSI READ)
+ */
+static int sbp_rw_data(struct sbp_target_request *req)
+{
+	struct sbp_session *sess = req->login->sess;
+	int tcode, sg_miter_flags, max_payload, pg_size, speed, node_id,
+		generation, num_pte, length, tfr_length,
+		rcode = RCODE_COMPLETE;
+	struct sbp_page_table_entry *pte;
+	unsigned long long offset;
+	struct fw_card *card;
+	struct sg_mapping_iter iter;
+
+	if (req->se_cmd.data_direction == DMA_FROM_DEVICE) {
+		tcode = TCODE_WRITE_BLOCK_REQUEST;
+		sg_miter_flags = SG_MITER_FROM_SG;
+	} else {
+		tcode = TCODE_READ_BLOCK_REQUEST;
+		sg_miter_flags = SG_MITER_TO_SG;
+	}
+
+	max_payload = 4 << CMDBLK_ORB_MAX_PAYLOAD(be32_to_cpu(req->orb.misc));
+	speed = CMDBLK_ORB_SPEED(be32_to_cpu(req->orb.misc));
+
+	pg_size = CMDBLK_ORB_PG_SIZE(be32_to_cpu(req->orb.misc));
+	if (pg_size) {
+		pr_err("sbp_run_transaction: page size ignored\n");
+		pg_size = 0x100 << pg_size;
+	}
+
+	spin_lock_bh(&sess->lock);
+	card = fw_card_get(sess->card);
+	node_id = sess->node_id;
+	generation = sess->generation;
+	spin_unlock_bh(&sess->lock);
+
+	if (req->pg_tbl) {
+		pte = req->pg_tbl;
+		num_pte = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+
+		offset = 0;
+		length = 0;
+	} else {
+		pte = NULL;
+		num_pte = 0;
+
+		offset = sbp2_pointer_to_addr(&req->orb.data_descriptor);
+		length = req->se_cmd.data_length;
+	}
+
+	sg_miter_start(&iter, req->se_cmd.t_data_sg, req->se_cmd.t_data_nents,
+		sg_miter_flags);
+
+	while (length || num_pte) {
+		if (!length) {
+			offset = (u64)be16_to_cpu(pte->segment_base_hi) << 32 |
+				be32_to_cpu(pte->segment_base_lo);
+			length = be16_to_cpu(pte->segment_length);
+
+			pte++;
+			num_pte--;
+		}
+
+		sg_miter_next(&iter);
+
+		tfr_length = min3(length, max_payload, (int)iter.length);
+
+		/* FIXME: take page_size into account */
+
+		rcode = sbp_run_transaction(card, tcode, node_id,
+				generation, speed,
+				offset, iter.addr, tfr_length);
+
+		if (rcode != RCODE_COMPLETE)
+			break;
+
+		length -= tfr_length;
+		offset += tfr_length;
+		iter.consumed = tfr_length;
+	}
+
+	sg_miter_stop(&iter);
+	fw_card_put(card);
+
+	if (rcode == RCODE_COMPLETE) {
+		WARN_ON(length != 0);
+		return 0;
+	} else {
+		return -EIO;
+	}
+}
+
+static int sbp_send_status(struct sbp_target_request *req)
+{
+	int ret, length;
+	struct sbp_login_descriptor *login = req->login;
+
+	length = (((be32_to_cpu(req->status.status) >> 24) & 0x07) + 1) * 4;
+
+	ret = sbp_run_request_transaction(req, TCODE_WRITE_BLOCK_REQUEST,
+			login->status_fifo_addr, &req->status, length);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("sbp_send_status: write failed: 0x%x\n", ret);
+		return -EIO;
+	}
+
+	pr_debug("sbp_send_status: status write complete for ORB: 0x%llx\n",
+			req->orb_pointer);
+
+	return 0;
+}
+
+static void sbp_sense_mangle(struct sbp_target_request *req)
+{
+	struct se_cmd *se_cmd = &req->se_cmd;
+	u8 *sense = req->sense_buf;
+	u8 *status = req->status.data;
+
+	WARN_ON(se_cmd->scsi_sense_length < 18);
+
+	switch (sense[0] & 0x7f) { 		/* sfmt */
+	case 0x70: /* current, fixed */
+		status[0] = 0 << 6;
+		break;
+	case 0x71: /* deferred, fixed */
+		status[0] = 1 << 6;
+		break;
+	case 0x72: /* current, descriptor */
+	case 0x73: /* deferred, descriptor */
+	default:
+		/*
+		 * TODO: SBP-3 specifies what we should do with descriptor
+		 * format sense data
+		 */
+		pr_err("sbp_send_sense: unknown sense format: 0x%x\n",
+			sense[0]);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQUEST_ABORTED));
+		return;
+	}
+
+	status[0] |= se_cmd->scsi_status & 0x3f;/* status */
+	status[1] =
+		(sense[0] & 0x80) |		/* valid */
+		((sense[2] & 0xe0) >> 1) |	/* mark, eom, ili */
+		(sense[2] & 0x0f);		/* sense_key */
+	status[2] = se_cmd->scsi_asc;		/* sense_code */
+	status[3] = se_cmd->scsi_ascq;		/* sense_qualifier */
+
+	/* information */
+	status[4] = sense[3];
+	status[5] = sense[4];
+	status[6] = sense[5];
+	status[7] = sense[6];
+
+	/* CDB-dependent */
+	status[8] = sense[8];
+	status[9] = sense[9];
+	status[10] = sense[10];
+	status[11] = sense[11];
+
+	/* fru */
+	status[12] = sense[14];
+
+	/* sense_key-dependent */
+	status[13] = sense[15];
+	status[14] = sense[16];
+	status[15] = sense[17];
+
+	req->status.status |= cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_DEAD(0) |
+		STATUS_BLOCK_LEN(5) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static int sbp_send_sense(struct sbp_target_request *req)
+{
+	struct se_cmd *se_cmd = &req->se_cmd;
+
+	if (se_cmd->scsi_sense_length) {
+		sbp_sense_mangle(req);
+	} else {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+	}
+
+	return sbp_send_status(req);
+}
+
+static void sbp_free_request(struct sbp_target_request *req)
+{
+	kfree(req->pg_tbl);
+	kfree(req->cmd_buf);
+	kfree(req);
+}
+
+static void sbp_mgt_agent_process(struct work_struct *work)
+{
+	struct sbp_management_agent *agent =
+		container_of(work, struct sbp_management_agent, work);
+	struct sbp_management_request *req = agent->request;
+	int ret;
+	int status_data_len = 0;
+
+	/* fetch the ORB from the initiator */
+	ret = sbp_run_transaction(req->card, TCODE_READ_BLOCK_REQUEST,
+		req->node_addr, req->generation, req->speed,
+		agent->orb_offset, &req->orb, sizeof(req->orb));
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("mgt_orb fetch failed: %x\n", ret);
+		goto out;
+	}
+
+	pr_debug("mgt_orb ptr1:0x%llx ptr2:0x%llx misc:0x%x len:0x%x status_fifo:0x%llx\n",
+		sbp2_pointer_to_addr(&req->orb.ptr1),
+		sbp2_pointer_to_addr(&req->orb.ptr2),
+		be32_to_cpu(req->orb.misc), be32_to_cpu(req->orb.length),
+		sbp2_pointer_to_addr(&req->orb.status_fifo));
+
+	if (!ORB_NOTIFY(be32_to_cpu(req->orb.misc)) ||
+		ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc)) != 0) {
+		pr_err("mgt_orb bad request\n");
+		goto out;
+	}
+
+	switch (MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc))) {
+	case MANAGEMENT_ORB_FUNCTION_LOGIN:
+		sbp_management_request_login(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS:
+		sbp_management_request_query_logins(agent, req,
+				&status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_RECONNECT:
+		sbp_management_request_reconnect(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_SET_PASSWORD:
+		pr_notice("SET PASSWORD not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_LOGOUT:
+		sbp_management_request_logout(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_ABORT_TASK:
+		pr_notice("ABORT TASK not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET:
+		pr_notice("ABORT TASK SET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET:
+		pr_notice("LOGICAL UNIT RESET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_TARGET_RESET:
+		pr_notice("TARGET RESET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	default:
+		pr_notice("unknown management function 0x%x\n",
+			MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc)));
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+	}
+
+	req->status.status |= cpu_to_be32(
+		STATUS_BLOCK_SRC(1) | /* Response to ORB, next_ORB absent */
+		STATUS_BLOCK_LEN(DIV_ROUND_UP(status_data_len, 4) + 1) |
+		STATUS_BLOCK_ORB_OFFSET_HIGH(agent->orb_offset >> 32));
+	req->status.orb_low = cpu_to_be32(agent->orb_offset);
+
+	/* write the status block back to the initiator */
+	ret = sbp_run_transaction(req->card, TCODE_WRITE_BLOCK_REQUEST,
+		req->node_addr, req->generation, req->speed,
+		sbp2_pointer_to_addr(&req->orb.status_fifo),
+		&req->status, 8 + status_data_len);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("mgt_orb status write failed: %x\n", ret);
+		goto out;
+	}
+
+out:
+	fw_card_put(req->card);
+	kfree(req);
+
+	spin_lock_bh(&agent->lock);
+	agent->state = MANAGEMENT_AGENT_STATE_IDLE;
+	spin_unlock_bh(&agent->lock);
+}
+
+static void sbp_mgt_agent_rw(struct fw_card *card,
+	struct fw_request *request, int tcode, int destination, int source,
+	int generation, unsigned long long offset, void *data, size_t length,
+	void *callback_data)
+{
+	struct sbp_management_agent *agent = callback_data;
+	struct sbp2_pointer *ptr = data;
+	int rcode = RCODE_ADDRESS_ERROR;
+
+	if (!agent->tport->enable)
+		goto out;
+
+	if ((offset != agent->handler.offset) || (length != 8))
+		goto out;
+
+	if (tcode == TCODE_WRITE_BLOCK_REQUEST) {
+		struct sbp_management_request *req;
+		int prev_state;
+
+		spin_lock_bh(&agent->lock);
+		prev_state = agent->state;
+		agent->state = MANAGEMENT_AGENT_STATE_BUSY;
+		spin_unlock_bh(&agent->lock);
+
+		if (prev_state == MANAGEMENT_AGENT_STATE_BUSY) {
+			pr_notice("ignoring management request while busy\n");
+			rcode = RCODE_CONFLICT_ERROR;
+			goto out;
+		}
+
+		req = kzalloc(sizeof(*req), GFP_ATOMIC);
+		if (!req) {
+			rcode = RCODE_CONFLICT_ERROR;
+			goto out;
+		}
+
+		req->card = fw_card_get(card);
+		req->generation = generation;
+		req->node_addr = source;
+		req->speed = fw_get_request_speed(request);
+
+		agent->orb_offset = sbp2_pointer_to_addr(ptr);
+		agent->request = req;
+
+		queue_work(system_unbound_wq, &agent->work);
+		rcode = RCODE_COMPLETE;
+	} else if (tcode == TCODE_READ_BLOCK_REQUEST) {
+		addr_to_sbp2_pointer(agent->orb_offset, ptr);
+		rcode = RCODE_COMPLETE;
+	} else {
+		rcode = RCODE_TYPE_ERROR;
+	}
+
+out:
+	fw_send_response(card, request, rcode);
+}
+
+static struct sbp_management_agent *sbp_management_agent_register(
+		struct sbp_tport *tport)
+{
+	int ret;
+	struct sbp_management_agent *agent;
+
+	agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+	if (!agent)
+		return ERR_PTR(-ENOMEM);
+
+	spin_lock_init(&agent->lock);
+	agent->tport = tport;
+	agent->handler.length = 0x08;
+	agent->handler.address_callback = sbp_mgt_agent_rw;
+	agent->handler.callback_data = agent;
+	agent->state = MANAGEMENT_AGENT_STATE_IDLE;
+	INIT_WORK(&agent->work, sbp_mgt_agent_process);
+	agent->orb_offset = 0;
+	agent->request = NULL;
+
+	ret = fw_core_add_address_handler(&agent->handler,
+			&sbp_register_region);
+	if (ret < 0) {
+		kfree(agent);
+		return ERR_PTR(ret);
+	}
+
+	return agent;
+}
+
+static void sbp_management_agent_unregister(struct sbp_management_agent *agent)
+{
+	fw_core_remove_address_handler(&agent->handler);
+	cancel_work_sync(&agent->work);
+	kfree(agent);
+}
+
+static int sbp_check_true(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int sbp_check_false(struct se_portal_group *se_tpg)
+{
+	return 0;
+}
+
+static char *sbp_get_fabric_name(void)
+{
+	return "sbp";
+}
+
+static char *sbp_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	return &tport->tport_name[0];
+}
+
+static u16 sbp_get_tag(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	return tpg->tport_tpgt;
+}
+
+static u32 sbp_get_default_depth(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+	struct sbp_nacl *nacl;
+
+	nacl = kzalloc(sizeof(struct sbp_nacl), GFP_KERNEL);
+	if (!nacl) {
+		pr_err("Unable to alocate struct sbp_nacl\n");
+		return NULL;
+	}
+
+	return &nacl->se_node_acl;
+}
+
+static void sbp_release_fabric_acl(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl)
+{
+	struct sbp_nacl *nacl =
+		container_of(se_nacl, struct sbp_nacl, se_node_acl);
+	kfree(nacl);
+}
+
+static u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static void sbp_release_cmd(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	sbp_free_request(req);
+}
+
+static int sbp_shutdown_session(struct se_session *se_sess)
+{
+	return 0;
+}
+
+static void sbp_close_session(struct se_session *se_sess)
+{
+	return;
+}
+
+static u32 sbp_sess_get_index(struct se_session *se_sess)
+{
+	return 0;
+}
+
+static int sbp_write_pending(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+	int ret;
+
+	ret = sbp_rw_data(req);
+	if (ret) {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(
+				STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(
+				SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		return ret;
+	}
+
+	transport_generic_process_write(se_cmd);
+
+	return 0;
+}
+
+static int sbp_write_pending_status(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static void sbp_set_default_node_attrs(struct se_node_acl *nacl)
+{
+	return;
+}
+
+static u32 sbp_get_task_tag(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	/* only used for printk until we do TMRs */
+	return (u32)req->orb_pointer;
+}
+
+static int sbp_get_cmd_state(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static int sbp_queue_data_in(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+	int ret;
+
+	ret = sbp_rw_data(req);
+	if (ret) {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		return ret;
+	}
+
+	return sbp_send_sense(req);
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int sbp_queue_status(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	return sbp_send_sense(req);
+}
+
+static int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static u16 sbp_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+	return 0;
+}
+
+static u16 sbp_get_fabric_sense_len(void)
+{
+	return 0;
+}
+
+static int sbp_check_stop_free(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	transport_generic_free_cmd(&req->se_cmd, 0);
+	return 1;
+}
+
+/*
+ * Handlers for Serial Bus Protocol 2/3 (SBP-2 / SBP-3)
+ */
+static u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+	/*
+	 * Return a IEEE 1394 SCSI Protocol identifier for loopback operations
+	 * This is defined in section 7.5.1 Table 362 in spc4r17
+	 */
+	return SCSI_PROTOCOL_SBP;
+}
+
+static u32 sbp_get_pr_transport_id(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code,
+	unsigned char *buf)
+{
+	int ret;
+
+	/*
+	 * Set PROTOCOL IDENTIFIER to 3h for SBP
+	 */
+	buf[0] = SCSI_PROTOCOL_SBP;
+	/*
+	 * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+	 * over IEEE 1394
+	 */
+	ret = hex2bin(&buf[8], se_nacl->initiatorname, 8);
+	if (ret < 0)
+		pr_debug("sbp transport_id: invalid hex string\n");
+
+	/*
+	 * The IEEE 1394 Transport ID is a hardcoded 24-byte length
+	 */
+	return 24;
+}
+
+static u32 sbp_get_pr_transport_id_len(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code)
+{
+	*format_code = 0;
+	/*
+	 * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+	 * over IEEE 1394
+	 *
+	 * The SBP Transport ID is a hardcoded 24-byte length
+	 */
+	return 24;
+}
+
+/*
+ * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
+ * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
+ */
+static char *sbp_parse_pr_out_transport_id(
+	struct se_portal_group *se_tpg,
+	const char *buf,
+	u32 *out_tid_len,
+	char **port_nexus_ptr)
+{
+	/*
+	 * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.4 TransportID
+	 * for initiator ports using SCSI over SBP Serial SCSI Protocol
+	 *
+	 * The TransportID for a IEEE 1394 Initiator Port is of fixed size of
+	 * 24 bytes, and IEEE 1394 does not contain a I_T nexus identifier,
+	 * so we return the **port_nexus_ptr set to NULL.
+	 */
+	*port_nexus_ptr = NULL;
+	*out_tid_len = 24;
+
+	return (char *)&buf[8];
+}
+
+static int sbp_count_se_tpg_luns(struct se_portal_group *tpg)
+{
+	int i, count = 0;
+
+	spin_lock(&tpg->tpg_lun_lock);
+	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+		struct se_lun *se_lun = tpg->tpg_lun_list[i];
+
+		if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+			continue;
+
+		count++;
+	}
+	spin_unlock(&tpg->tpg_lun_lock);
+
+	return count;
+}
+
+static int sbp_update_unit_directory(struct sbp_tport *tport)
+{
+	int num_luns, num_entries, idx = 0, mgt_agt_addr, ret, i;
+	u32 *data;
+
+	if (tport->unit_directory.data) {
+		fw_core_remove_descriptor(&tport->unit_directory);
+		kfree(tport->unit_directory.data);
+		tport->unit_directory.data = NULL;
+	}
+
+	if (!tport->enable || !tport->tpg)
+		return 0;
+
+	num_luns = sbp_count_se_tpg_luns(&tport->tpg->se_tpg);
+
+	/*
+	 * Number of entries in the final unit directory:
+	 *  - all of those in the template
+	 *  - management_agent
+	 *  - unit_characteristics
+	 *  - reconnect_timeout
+	 *  - unit unique ID
+	 *  - one for each LUN
+	 *
+	 *  MUST NOT include leaf or sub-directory entries
+	 */
+	num_entries = ARRAY_SIZE(sbp_unit_directory_template) + 4 + num_luns;
+
+	if (tport->directory_id != -1)
+		num_entries++;
+
+	/* allocate num_entries + 4 for the header and unique ID leaf */
+	data = kcalloc((num_entries + 4), sizeof(u32), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* directory_length */
+	data[idx++] = num_entries << 16;
+
+	/* directory_id */
+	if (tport->directory_id != -1)
+		data[idx++] = (CSR_DIRECTORY_ID << 24) | tport->directory_id;
+
+	/* unit directory template */
+	memcpy(&data[idx], sbp_unit_directory_template,
+			sizeof(sbp_unit_directory_template));
+	idx += ARRAY_SIZE(sbp_unit_directory_template);
+
+	/* management_agent */
+	mgt_agt_addr = (tport->mgt_agt->handler.offset - CSR_REGISTER_BASE) / 4;
+	data[idx++] = 0x54000000 | (mgt_agt_addr & 0x00ffffff);
+
+	/* unit_characteristics */
+	data[idx++] = 0x3a000000 |
+		(((tport->mgt_orb_timeout * 2) << 8) & 0xff00) |
+		SBP_ORB_FETCH_SIZE;
+
+	/* reconnect_timeout */
+	data[idx++] = 0x3d000000 | (tport->max_reconnect_timeout & 0xffff);
+
+	/* unit unique ID (leaf is just after LUNs) */
+	data[idx++] = 0x8d000000 | (num_luns + 1);
+
+	spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+		struct se_lun *se_lun = tport->tpg->se_tpg.tpg_lun_list[i];
+		struct se_device *dev;
+		int type;
+
+		if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+			continue;
+
+		spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+		dev = se_lun->lun_se_dev;
+		type = dev->transport->get_device_type(dev);
+
+		/* logical_unit_number */
+		data[idx++] = 0x14000000 |
+			((type << 16) & 0x1f0000) |
+			(se_lun->unpacked_lun & 0xffff);
+
+		spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+	}
+	spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+	/* unit unique ID leaf */
+	data[idx++] = 2 << 16;
+	data[idx++] = tport->guid >> 32;
+	data[idx++] = tport->guid;
+
+	tport->unit_directory.length = idx;
+	tport->unit_directory.key = (CSR_DIRECTORY | CSR_UNIT) << 24;
+	tport->unit_directory.data = data;
+
+	ret = fw_core_add_descriptor(&tport->unit_directory);
+	if (ret < 0) {
+		kfree(tport->unit_directory.data);
+		tport->unit_directory.data = NULL;
+	}
+
+	return ret;
+}
+
+static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
+{
+	const char *cp;
+	char c, nibble;
+	int pos = 0, err;
+
+	*wwn = 0;
+	for (cp = name; cp < &name[SBP_NAMELEN - 1]; cp++) {
+		c = *cp;
+		if (c == '\n' && cp[1] == '\0')
+			continue;
+		if (c == '\0') {
+			err = 2;
+			if (pos != 16)
+				goto fail;
+			return cp - name;
+		}
+		err = 3;
+		if (isdigit(c))
+			nibble = c - '0';
+		else if (isxdigit(c) && (islower(c) || !strict))
+			nibble = tolower(c) - 'a' + 10;
+		else
+			goto fail;
+		*wwn = (*wwn << 4) | nibble;
+		pos++;
+	}
+	err = 4;
+fail:
+	printk(KERN_INFO "err %u len %zu pos %u\n",
+			err, cp - name, pos);
+	return -1;
+}
+
+static ssize_t sbp_format_wwn(char *buf, size_t len, u64 wwn)
+{
+	return snprintf(buf, len, "%016llx", wwn);
+}
+
+static struct se_node_acl *sbp_make_nodeacl(
+		struct se_portal_group *se_tpg,
+		struct config_group *group,
+		const char *name)
+{
+	struct se_node_acl *se_nacl, *se_nacl_new;
+	struct sbp_nacl *nacl;
+	u64 guid = 0;
+	u32 nexus_depth = 1;
+
+	if (sbp_parse_wwn(name, &guid, 1) < 0)
+		return ERR_PTR(-EINVAL);
+
+	se_nacl_new = sbp_alloc_fabric_acl(se_tpg);
+	if (!se_nacl_new)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+	 * when converting a NodeACL from demo mode -> explict
+	 */
+	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+			name, nexus_depth);
+	if (IS_ERR(se_nacl)) {
+		sbp_release_fabric_acl(se_tpg, se_nacl_new);
+		return se_nacl;
+	}
+
+	nacl = container_of(se_nacl, struct sbp_nacl, se_node_acl);
+	nacl->guid = guid;
+	sbp_format_wwn(nacl->iport_name, SBP_NAMELEN, guid);
+
+	return se_nacl;
+}
+
+static void sbp_drop_nodeacl(struct se_node_acl *se_acl)
+{
+	struct sbp_nacl *nacl =
+		container_of(se_acl, struct sbp_nacl, se_node_acl);
+
+	core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+	kfree(nacl);
+}
+
+static int sbp_post_link_lun(
+		struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+
+	return sbp_update_unit_directory(tpg->tport);
+}
+
+static void sbp_pre_unlink_lun(
+		struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	int ret;
+
+	if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0)
+		tport->enable = 0;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		pr_err("unlink LUN: failed to update unit directory\n");
+}
+
+static struct se_portal_group *sbp_make_tpg(
+		struct se_wwn *wwn,
+		struct config_group *group,
+		const char *name)
+{
+	struct sbp_tport *tport =
+		container_of(wwn, struct sbp_tport, tport_wwn);
+
+	struct sbp_tpg *tpg;
+	unsigned long tpgt;
+	int ret;
+
+	if (strstr(name, "tpgt_") != name)
+		return ERR_PTR(-EINVAL);
+	if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+		return ERR_PTR(-EINVAL);
+
+	if (tport->tpg) {
+		pr_err("Only one TPG per Unit is possible.\n");
+		return ERR_PTR(-EBUSY);
+	}
+
+	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+	if (!tpg) {
+		pr_err("Unable to allocate struct sbp_tpg\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	tpg->tport = tport;
+	tpg->tport_tpgt = tpgt;
+	tport->tpg = tpg;
+
+	/* default attribute values */
+	tport->enable = 0;
+	tport->directory_id = -1;
+	tport->mgt_orb_timeout = 15;
+	tport->max_reconnect_timeout = 5;
+	tport->max_logins_per_lun = 1;
+
+	tport->mgt_agt = sbp_management_agent_register(tport);
+	if (IS_ERR(tport->mgt_agt)) {
+		ret = PTR_ERR(tport->mgt_agt);
+		kfree(tpg);
+		return ERR_PTR(ret);
+	}
+
+	ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
+			&tpg->se_tpg, (void *)tpg,
+			TRANSPORT_TPG_TYPE_NORMAL);
+	if (ret < 0) {
+		sbp_management_agent_unregister(tport->mgt_agt);
+		kfree(tpg);
+		return ERR_PTR(ret);
+	}
+
+	return &tpg->se_tpg;
+}
+
+static void sbp_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	core_tpg_deregister(se_tpg);
+	sbp_management_agent_unregister(tport->mgt_agt);
+	tport->tpg = NULL;
+	kfree(tpg);
+}
+
+static struct se_wwn *sbp_make_tport(
+		struct target_fabric_configfs *tf,
+		struct config_group *group,
+		const char *name)
+{
+	struct sbp_tport *tport;
+	u64 guid = 0;
+
+	if (sbp_parse_wwn(name, &guid, 1) < 0)
+		return ERR_PTR(-EINVAL);
+
+	tport = kzalloc(sizeof(*tport), GFP_KERNEL);
+	if (!tport) {
+		pr_err("Unable to allocate struct sbp_tport\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	tport->guid = guid;
+	sbp_format_wwn(tport->tport_name, SBP_NAMELEN, guid);
+
+	return &tport->tport_wwn;
+}
+
+static void sbp_drop_tport(struct se_wwn *wwn)
+{
+	struct sbp_tport *tport =
+		container_of(wwn, struct sbp_tport, tport_wwn);
+
+	kfree(tport);
+}
+
+static ssize_t sbp_wwn_show_attr_version(
+		struct target_fabric_configfs *tf,
+		char *page)
+{
+	return sprintf(page, "FireWire SBP fabric module %s\n", SBP_VERSION);
+}
+
+TF_WWN_ATTR_RO(sbp, version);
+
+static struct configfs_attribute *sbp_wwn_attrs[] = {
+	&sbp_wwn_version.attr,
+	NULL,
+};
+
+static ssize_t sbp_tpg_show_directory_id(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	if (tport->directory_id == -1)
+		return sprintf(page, "implicit\n");
+	else
+		return sprintf(page, "%06x\n", tport->directory_id);
+}
+
+static ssize_t sbp_tpg_store_directory_id(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+
+	if (tport->enable) {
+		pr_err("Cannot change the directory_id on an active target.\n");
+		return -EBUSY;
+	}
+
+	if (strstr(page, "implicit") == page) {
+		tport->directory_id = -1;
+	} else {
+		if (kstrtoul(page, 16, &val) < 0)
+			return -EINVAL;
+		if (val > 0xffffff)
+			return -EINVAL;
+
+		tport->directory_id = val;
+	}
+
+	return count;
+}
+
+static ssize_t sbp_tpg_show_enable(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->enable);
+}
+
+static ssize_t sbp_tpg_store_enable(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val != 0) && (val != 1))
+		return -EINVAL;
+
+	if (tport->enable == val)
+		return count;
+
+	if (val) {
+		if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0) {
+			pr_err("Cannot enable a target with no LUNs!\n");
+			return -EINVAL;
+		}
+	} else {
+		/* XXX: force-shutdown sessions instead? */
+		spin_lock_bh(&se_tpg->session_lock);
+		if (!list_empty(&se_tpg->tpg_sess_list)) {
+			spin_unlock_bh(&se_tpg->session_lock);
+			return -EBUSY;
+		}
+		spin_unlock_bh(&se_tpg->session_lock);
+	}
+
+	tport->enable = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0) {
+		pr_err("Could not update Config ROM\n");
+		return ret;
+	}
+
+	return count;
+}
+
+TF_TPG_BASE_ATTR(sbp, directory_id, S_IRUGO | S_IWUSR);
+TF_TPG_BASE_ATTR(sbp, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_base_attrs[] = {
+	&sbp_tpg_directory_id.attr,
+	&sbp_tpg_enable.attr,
+	NULL,
+};
+
+static ssize_t sbp_tpg_attrib_show_mgt_orb_timeout(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->mgt_orb_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 127))
+		return -EINVAL;
+
+	if (tport->mgt_orb_timeout == val)
+		return count;
+
+	tport->mgt_orb_timeout = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_reconnect_timeout(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->max_reconnect_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 32767))
+		return -EINVAL;
+
+	if (tport->max_reconnect_timeout == val)
+		return count;
+
+	tport->max_reconnect_timeout = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_logins_per_lun(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->max_logins_per_lun);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_logins_per_lun(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 127))
+		return -EINVAL;
+
+	/* XXX: also check against current count? */
+
+	tport->max_logins_per_lun = val;
+
+	return count;
+}
+
+TF_TPG_ATTRIB_ATTR(sbp, mgt_orb_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_reconnect_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_logins_per_lun, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
+	&sbp_tpg_attrib_mgt_orb_timeout.attr,
+	&sbp_tpg_attrib_max_reconnect_timeout.attr,
+	&sbp_tpg_attrib_max_logins_per_lun.attr,
+	NULL,
+};
+
+static struct target_core_fabric_ops sbp_ops = {
+	.get_fabric_name		= sbp_get_fabric_name,
+	.get_fabric_proto_ident		= sbp_get_fabric_proto_ident,
+	.tpg_get_wwn			= sbp_get_fabric_wwn,
+	.tpg_get_tag			= sbp_get_tag,
+	.tpg_get_default_depth		= sbp_get_default_depth,
+	.tpg_get_pr_transport_id	= sbp_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= sbp_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= sbp_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= sbp_check_true,
+	.tpg_check_demo_mode_cache	= sbp_check_true,
+	.tpg_check_demo_mode_write_protect = sbp_check_false,
+	.tpg_check_prod_mode_write_protect = sbp_check_false,
+	.tpg_alloc_fabric_acl		= sbp_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= sbp_release_fabric_acl,
+	.tpg_get_inst_index		= sbp_tpg_get_inst_index,
+	.release_cmd			= sbp_release_cmd,
+	.shutdown_session		= sbp_shutdown_session,
+	.close_session			= sbp_close_session,
+	.sess_get_index			= sbp_sess_get_index,
+	.write_pending			= sbp_write_pending,
+	.write_pending_status		= sbp_write_pending_status,
+	.set_default_node_attributes	= sbp_set_default_node_attrs,
+	.get_task_tag			= sbp_get_task_tag,
+	.get_cmd_state			= sbp_get_cmd_state,
+	.queue_data_in			= sbp_queue_data_in,
+	.queue_status			= sbp_queue_status,
+	.queue_tm_rsp			= sbp_queue_tm_rsp,
+	.get_fabric_sense_len		= sbp_get_fabric_sense_len,
+	.set_fabric_sense_len		= sbp_set_fabric_sense_len,
+	.check_stop_free		= sbp_check_stop_free,
+
+	.fabric_make_wwn		= sbp_make_tport,
+	.fabric_drop_wwn		= sbp_drop_tport,
+	.fabric_make_tpg		= sbp_make_tpg,
+	.fabric_drop_tpg		= sbp_drop_tpg,
+	.fabric_post_link		= sbp_post_link_lun,
+	.fabric_pre_unlink		= sbp_pre_unlink_lun,
+	.fabric_make_np			= NULL,
+	.fabric_drop_np			= NULL,
+	.fabric_make_nodeacl		= sbp_make_nodeacl,
+	.fabric_drop_nodeacl		= sbp_drop_nodeacl,
+};
+
+static int sbp_register_configfs(void)
+{
+	struct target_fabric_configfs *fabric;
+	int ret;
+
+	fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
+	if (!fabric) {
+		pr_err("target_fabric_configfs_init() failed\n");
+		return -ENOMEM;
+	}
+
+	fabric->tf_ops = sbp_ops;
+
+	/*
+	 * Setup default attribute lists for various fabric->tf_cit_tmpl
+	 */
+	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = sbp_wwn_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+
+	ret = target_fabric_configfs_register(fabric);
+	if (ret < 0) {
+		pr_err("target_fabric_configfs_register() failed for SBP\n");
+		return ret;
+	}
+
+	sbp_fabric_configfs = fabric;
+
+	return 0;
+};
+
+static void sbp_deregister_configfs(void)
+{
+	if (!sbp_fabric_configfs)
+		return;
+
+	target_fabric_configfs_deregister(sbp_fabric_configfs);
+	sbp_fabric_configfs = NULL;
+};
+
+static int __init sbp_init(void)
+{
+	int ret;
+
+	ret = sbp_register_configfs();
+	if (ret < 0)
+		return ret;
+
+	return 0;
+};
+
+static void sbp_exit(void)
+{
+	sbp_deregister_configfs();
+};
+
+MODULE_DESCRIPTION("FireWire SBP fabric driver");
+MODULE_LICENSE("GPL");
+module_init(sbp_init);
+module_exit(sbp_exit);
diff --git a/drivers/target/sbp/sbp_target.h b/drivers/target/sbp/sbp_target.h
new file mode 100644
index 0000000..6d0d74a
--- /dev/null
+++ b/drivers/target/sbp/sbp_target.h
@@ -0,0 +1,251 @@
+#ifndef _SBP_BASE_H
+#define _SBP_BASE_H
+
+#include <linux/firewire.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <target/target_core_base.h>
+
+#define SBP_VERSION  "v0.1"
+#define SBP_NAMELEN 32
+
+#define SBP_ORB_FETCH_SIZE	8
+
+#define MANAGEMENT_AGENT_STATE_IDLE	0
+#define MANAGEMENT_AGENT_STATE_BUSY	1
+
+#define ORB_NOTIFY(v)			(((v) >> 31) & 0x01)
+#define ORB_REQUEST_FORMAT(v)		(((v) >> 29) & 0x03)
+
+#define MANAGEMENT_ORB_FUNCTION(v)	(((v) >> 16) & 0x0f)
+
+#define MANAGEMENT_ORB_FUNCTION_LOGIN			0x0
+#define MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS		0x1
+#define MANAGEMENT_ORB_FUNCTION_RECONNECT		0x3
+#define MANAGEMENT_ORB_FUNCTION_SET_PASSWORD		0x4
+#define MANAGEMENT_ORB_FUNCTION_LOGOUT			0x7
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK		0xb
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET		0xc
+#define MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET	0xe
+#define MANAGEMENT_ORB_FUNCTION_TARGET_RESET		0xf
+
+#define LOGIN_ORB_EXCLUSIVE(v)		(((v) >> 28) &   0x01)
+#define LOGIN_ORB_RESERVED(v)		(((v) >> 24) &   0x0f)
+#define LOGIN_ORB_RECONNECT(v)		(((v) >> 20) &   0x0f)
+#define LOGIN_ORB_LUN(v)		(((v) >>  0) & 0xffff)
+#define LOGIN_ORB_PASSWORD_LENGTH(v)	(((v) >> 16) & 0xffff)
+#define LOGIN_ORB_RESPONSE_LENGTH(v)	(((v) >>  0) & 0xffff)
+
+#define RECONNECT_ORB_LOGIN_ID(v)	(((v) >>  0) & 0xffff)
+#define LOGOUT_ORB_LOGIN_ID(v)		(((v) >>  0) & 0xffff)
+
+#define CMDBLK_ORB_DIRECTION(v)		(((v) >> 27) &   0x01)
+#define CMDBLK_ORB_SPEED(v)		(((v) >> 24) &   0x07)
+#define CMDBLK_ORB_MAX_PAYLOAD(v)	(((v) >> 20) &   0x0f)
+#define CMDBLK_ORB_PG_TBL_PRESENT(v)	(((v) >> 19) &   0x01)
+#define CMDBLK_ORB_PG_SIZE(v)		(((v) >> 16) &   0x07)
+#define CMDBLK_ORB_DATA_SIZE(v)		(((v) >>  0) & 0xffff)
+
+#define STATUS_BLOCK_SRC(v)		(((v) &   0x03) << 30)
+#define STATUS_BLOCK_RESP(v)		(((v) &   0x03) << 28)
+#define STATUS_BLOCK_DEAD(v)		(((v) ? 1 : 0)  << 27)
+#define STATUS_BLOCK_LEN(v)		(((v) &   0x07) << 24)
+#define STATUS_BLOCK_SBP_STATUS(v)	(((v) &   0xff) << 16)
+#define STATUS_BLOCK_ORB_OFFSET_HIGH(v)	(((v) & 0xffff) <<  0)
+
+#define STATUS_SRC_ORB_CONTINUING	0
+#define STATUS_SRC_ORB_FINISHED		1
+#define STATUS_SRC_UNSOLICITED		2
+
+#define STATUS_RESP_REQUEST_COMPLETE	0
+#define STATUS_RESP_TRANSPORT_FAILURE	1
+#define STATUS_RESP_ILLEGAL_REQUEST	2
+#define STATUS_RESP_VENDOR_DEPENDENT	3
+
+#define SBP_STATUS_OK			0
+#define SBP_STATUS_REQ_TYPE_NOTSUPP	1
+#define SBP_STATUS_SPEED_NOTSUPP	2
+#define SBP_STATUS_PAGE_SIZE_NOTSUPP	3
+#define SBP_STATUS_ACCESS_DENIED	4
+#define SBP_STATUS_LUN_NOTSUPP		5
+#define SBP_STATUS_PAYLOAD_TOO_SMALL	6
+/* 7 is reserved */
+#define SBP_STATUS_RESOURCES_UNAVAIL	8
+#define SBP_STATUS_FUNCTION_REJECTED	9
+#define SBP_STATUS_LOGIN_ID_UNKNOWN	10
+#define SBP_STATUS_DUMMY_ORB_COMPLETE	11
+#define SBP_STATUS_REQUEST_ABORTED	12
+#define SBP_STATUS_UNSPECIFIED_ERROR	0xff
+
+#define AGENT_STATE_RESET	0
+#define AGENT_STATE_ACTIVE	1
+#define AGENT_STATE_SUSPENDED	2
+#define AGENT_STATE_DEAD	3
+
+struct sbp2_pointer {
+	__be32 high;
+	__be32 low;
+};
+
+struct sbp_command_block_orb {
+	struct sbp2_pointer next_orb;
+	struct sbp2_pointer data_descriptor;
+	__be32 misc;
+	u8 command_block[12];
+};
+
+struct sbp_page_table_entry {
+	__be16 segment_length;
+	__be16 segment_base_hi;
+	__be32 segment_base_lo;
+};
+
+struct sbp_management_orb {
+	struct sbp2_pointer ptr1;
+	struct sbp2_pointer ptr2;
+	__be32 misc;
+	__be32 length;
+	struct sbp2_pointer status_fifo;
+};
+
+struct sbp_status_block {
+	__be32 status;
+	__be32 orb_low;
+	u8 data[24];
+};
+
+struct sbp_login_response_block {
+	__be32 misc;
+	struct sbp2_pointer command_block_agent;
+	__be32 reconnect_hold;
+};
+
+struct sbp_login_descriptor {
+	struct sbp_session *sess;
+	struct list_head link;
+
+	struct se_lun *lun;
+
+	u64 status_fifo_addr;
+	int exclusive;
+	u16 login_id;
+
+	struct sbp_target_agent *tgt_agt;
+};
+
+struct sbp_session {
+	spinlock_t lock;
+	struct se_session *se_sess;
+	struct list_head login_list;
+	struct delayed_work maint_work;
+
+	u64 guid; /* login_owner_EUI_64 */
+	int node_id; /* login_owner_ID */
+
+	struct fw_card *card;
+	int generation;
+	int speed;
+
+	int reconnect_hold;
+	u64 reconnect_expires;
+};
+
+struct sbp_nacl {
+	/* Initiator EUI-64 */
+	u64 guid;
+	/* ASCII formatted GUID for SBP Initiator port */
+	char iport_name[SBP_NAMELEN];
+	/* Returned by sbp_make_nodeacl() */
+	struct se_node_acl se_node_acl;
+};
+
+struct sbp_tpg {
+	/* Target portal group tag for TCM */
+	u16 tport_tpgt;
+	/* Pointer back to sbp_tport */
+	struct sbp_tport *tport;
+	/* Returned by sbp_make_tpg() */
+	struct se_portal_group se_tpg;
+};
+
+struct sbp_tport {
+	/* Target Unit Identifier (EUI-64) */
+	u64 guid;
+	/* Target port name */
+	char tport_name[SBP_NAMELEN];
+	/* Returned by sbp_make_tport() */
+	struct se_wwn tport_wwn;
+
+	struct sbp_tpg *tpg;
+
+	/* FireWire unit directory */
+	struct fw_descriptor unit_directory;
+
+	/* SBP Management Agent */
+	struct sbp_management_agent *mgt_agt;
+
+	/* Parameters */
+	int enable;
+	s32 directory_id;
+	int mgt_orb_timeout;
+	int max_reconnect_timeout;
+	int max_logins_per_lun;
+};
+
+static inline u64 sbp2_pointer_to_addr(const struct sbp2_pointer *ptr)
+{
+	return (u64)(be32_to_cpu(ptr->high) & 0x0000ffff) << 32 |
+		(be32_to_cpu(ptr->low) & 0xfffffffc);
+}
+
+static inline void addr_to_sbp2_pointer(u64 addr, struct sbp2_pointer *ptr)
+{
+	ptr->high = cpu_to_be32(addr >> 32);
+	ptr->low = cpu_to_be32(addr);
+}
+
+struct sbp_target_agent {
+	spinlock_t lock;
+	struct fw_address_handler handler;
+	struct sbp_login_descriptor *login;
+	int state;
+	struct work_struct work;
+	u64 orb_pointer;
+	bool doorbell;
+};
+
+struct sbp_target_request {
+	struct sbp_login_descriptor *login;
+	u64 orb_pointer;
+	struct sbp_command_block_orb orb;
+	struct sbp_status_block status;
+	struct work_struct work;
+
+	struct se_cmd se_cmd;
+	struct sbp_page_table_entry *pg_tbl;
+	void *cmd_buf;
+
+	unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+struct sbp_management_agent {
+	spinlock_t lock;
+	struct sbp_tport *tport;
+	struct fw_address_handler handler;
+	int state;
+	struct work_struct work;
+	u64 orb_offset;
+	struct sbp_management_request *request;
+};
+
+struct sbp_management_request {
+	struct sbp_management_orb orb;
+	struct sbp_status_block status;
+	struct fw_card *card;
+	int generation;
+	int node_addr;
+	int speed;
+};
+
+#endif
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 6cc4358..35819e3 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1033,7 +1033,7 @@
 	if (!retinfo)
 		return -EFAULT;
 	memset(&tmp, 0, sizeof(tmp));
-	tty_lock();
+	tty_lock(tty);
 	tmp.line = tty->index;
 	tmp.port = state->port;
 	tmp.flags = state->tport.flags;
@@ -1042,7 +1042,7 @@
 	tmp.close_delay = state->tport.close_delay;
 	tmp.closing_wait = state->tport.closing_wait;
 	tmp.custom_divisor = state->custom_divisor;
-	tty_unlock();
+	tty_unlock(tty);
 	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
 		return -EFAULT;
 	return 0;
@@ -1059,12 +1059,12 @@
 	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 		return -EFAULT;
 
-	tty_lock();
+	tty_lock(tty);
 	change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
 		new_serial.custom_divisor != state->custom_divisor;
 	if (new_serial.irq || new_serial.port != state->port ||
 			new_serial.xmit_fifo_size != state->xmit_fifo_size) {
-		tty_unlock();
+		tty_unlock(tty);
 		return -EINVAL;
 	}
   
@@ -1074,7 +1074,7 @@
 		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
 		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
 		     (port->flags & ~ASYNC_USR_MASK))) {
-			tty_unlock();
+			tty_unlock(tty);
 			return -EPERM;
 		}
 		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -1084,7 +1084,7 @@
 	}
 
 	if (new_serial.baud_base < 9600) {
-		tty_unlock();
+		tty_unlock(tty);
 		return -EINVAL;
 	}
 
@@ -1116,7 +1116,7 @@
 		}
 	} else
 		retval = startup(tty, state);
-	tty_unlock();
+	tty_unlock(tty);
 	return retval;
 }
 
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c
index 946f799..61fc74f 100644
--- a/drivers/tty/bfin_jtag_comm.c
+++ b/drivers/tty/bfin_jtag_comm.c
@@ -62,9 +62,7 @@
 
 static struct tty_driver *bfin_jc_driver;
 static struct task_struct *bfin_jc_kthread;
-static struct tty_struct * volatile bfin_jc_tty;
-static unsigned long bfin_jc_count;
-static DEFINE_MUTEX(bfin_jc_tty_mutex);
+static struct tty_port port;
 static volatile struct circ_buf bfin_jc_write_buf;
 
 static int
@@ -73,18 +71,21 @@
 	uint32_t inbound_len = 0, outbound_len = 0;
 
 	while (!kthread_should_stop()) {
+		struct tty_struct *tty = tty_port_tty_get(&port);
 		/* no one left to give data to, so sleep */
-		if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
+		if (tty == NULL && circ_empty(&bfin_jc_write_buf)) {
 			pr_debug("waiting for readers\n");
 			__set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule();
 			__set_current_state(TASK_RUNNING);
+			continue;
 		}
 
 		/* no data available, so just chill */
 		if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
 			pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
 				inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
+			tty_kref_put(tty);
 			if (inbound_len)
 				schedule();
 			else
@@ -94,9 +95,6 @@
 
 		/* if incoming data is ready, eat it */
 		if (bfin_read_DBGSTAT() & EMUDIF) {
-			struct tty_struct *tty;
-			mutex_lock(&bfin_jc_tty_mutex);
-			tty = (struct tty_struct *)bfin_jc_tty;
 			if (tty != NULL) {
 				uint32_t emudat = bfin_read_emudat();
 				if (inbound_len == 0) {
@@ -110,7 +108,6 @@
 					tty_flip_buffer_push(tty);
 				}
 			}
-			mutex_unlock(&bfin_jc_tty_mutex);
 		}
 
 		/* if outgoing data is ready, post it */
@@ -120,7 +117,6 @@
 				bfin_write_emudat(outbound_len);
 				pr_debug("outgoing length: 0x%08x\n", outbound_len);
 			} else {
-				struct tty_struct *tty;
 				int tail = bfin_jc_write_buf.tail;
 				size_t ate = (4 <= outbound_len ? 4 : outbound_len);
 				uint32_t emudat =
@@ -132,14 +128,12 @@
 				);
 				bfin_jc_write_buf.tail += ate;
 				outbound_len -= ate;
-				mutex_lock(&bfin_jc_tty_mutex);
-				tty = (struct tty_struct *)bfin_jc_tty;
 				if (tty)
 					tty_wakeup(tty);
-				mutex_unlock(&bfin_jc_tty_mutex);
 				pr_debug("  outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
 			}
 		}
+		tty_kref_put(tty);
 	}
 
 	__set_current_state(TASK_RUNNING);
@@ -149,24 +143,28 @@
 static int
 bfin_jc_open(struct tty_struct *tty, struct file *filp)
 {
-	mutex_lock(&bfin_jc_tty_mutex);
-	pr_debug("open %lu\n", bfin_jc_count);
-	++bfin_jc_count;
-	bfin_jc_tty = tty;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port.lock, flags);
+	port.count++;
+	spin_unlock_irqrestore(&port.lock, flags);
+	tty_port_tty_set(&port, tty);
 	wake_up_process(bfin_jc_kthread);
-	mutex_unlock(&bfin_jc_tty_mutex);
 	return 0;
 }
 
 static void
 bfin_jc_close(struct tty_struct *tty, struct file *filp)
 {
-	mutex_lock(&bfin_jc_tty_mutex);
-	pr_debug("close %lu\n", bfin_jc_count);
-	if (--bfin_jc_count == 0)
-		bfin_jc_tty = NULL;
+	unsigned long flags;
+	bool last;
+
+	spin_lock_irqsave(&port.lock, flags);
+	last = --port.count == 0;
+	spin_unlock_irqrestore(&port.lock, flags);
+	if (last)
+		tty_port_tty_set(&port, NULL);
 	wake_up_process(bfin_jc_kthread);
-	mutex_unlock(&bfin_jc_tty_mutex);
 }
 
 /* XXX: we dont handle the put_char() case where we must handle count = 1 */
@@ -242,6 +240,8 @@
 {
 	int ret;
 
+	tty_port_init(&port);
+
 	bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
 	if (IS_ERR(bfin_jc_kthread))
 		return PTR_ERR(bfin_jc_kthread);
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index e61cabd..6984e1a 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -1599,7 +1599,7 @@
 	 * If the port is the middle of closing, bail out now
 	 */
 	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
-		wait_event_interruptible_tty(info->port.close_wait,
+		wait_event_interruptible_tty(tty, info->port.close_wait,
 				!(info->port.flags & ASYNC_CLOSING));
 		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
 	}
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 8880adf..2d691eb 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -107,7 +107,7 @@
 	list_for_each_entry(hp, &hvc_structs, next) {
 		spin_lock_irqsave(&hp->lock, flags);
 		if (hp->index == index) {
-			kref_get(&hp->kref);
+			tty_port_get(&hp->port);
 			spin_unlock_irqrestore(&hp->lock, flags);
 			spin_unlock(&hvc_structs_lock);
 			return hp;
@@ -229,9 +229,9 @@
 console_initcall(hvc_console_init);
 
 /* callback when the kboject ref count reaches zero. */
-static void destroy_hvc_struct(struct kref *kref)
+static void hvc_port_destruct(struct tty_port *port)
 {
-	struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
+	struct hvc_struct *hp = container_of(port, struct hvc_struct, port);
 	unsigned long flags;
 
 	spin_lock(&hvc_structs_lock);
@@ -264,7 +264,7 @@
 	/* make sure no no tty has been registered in this index */
 	hp = hvc_get_by_index(index);
 	if (hp) {
-		kref_put(&hp->kref, destroy_hvc_struct);
+		tty_port_put(&hp->port);
 		return -1;
 	}
 
@@ -313,20 +313,17 @@
 	if (!(hp = hvc_get_by_index(tty->index)))
 		return -ENODEV;
 
-	spin_lock_irqsave(&hp->lock, flags);
+	spin_lock_irqsave(&hp->port.lock, flags);
 	/* Check and then increment for fast path open. */
-	if (hp->count++ > 0) {
-		tty_kref_get(tty);
-		spin_unlock_irqrestore(&hp->lock, flags);
+	if (hp->port.count++ > 0) {
+		spin_unlock_irqrestore(&hp->port.lock, flags);
 		hvc_kick();
 		return 0;
 	} /* else count == 0 */
+	spin_unlock_irqrestore(&hp->port.lock, flags);
 
 	tty->driver_data = hp;
-
-	hp->tty = tty_kref_get(tty);
-
-	spin_unlock_irqrestore(&hp->lock, flags);
+	tty_port_tty_set(&hp->port, tty);
 
 	if (hp->ops->notifier_add)
 		rc = hp->ops->notifier_add(hp, hp->data);
@@ -338,12 +335,9 @@
 	 * tty fields and return the kref reference.
 	 */
 	if (rc) {
-		spin_lock_irqsave(&hp->lock, flags);
-		hp->tty = NULL;
-		spin_unlock_irqrestore(&hp->lock, flags);
-		tty_kref_put(tty);
+		tty_port_tty_set(&hp->port, NULL);
 		tty->driver_data = NULL;
-		kref_put(&hp->kref, destroy_hvc_struct);
+		tty_port_put(&hp->port);
 		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
 	}
 	/* Force wakeup of the polling thread */
@@ -370,12 +364,12 @@
 
 	hp = tty->driver_data;
 
-	spin_lock_irqsave(&hp->lock, flags);
+	spin_lock_irqsave(&hp->port.lock, flags);
 
-	if (--hp->count == 0) {
+	if (--hp->port.count == 0) {
+		spin_unlock_irqrestore(&hp->port.lock, flags);
 		/* We are done with the tty pointer now. */
-		hp->tty = NULL;
-		spin_unlock_irqrestore(&hp->lock, flags);
+		tty_port_tty_set(&hp->port, NULL);
 
 		if (hp->ops->notifier_del)
 			hp->ops->notifier_del(hp, hp->data);
@@ -390,14 +384,13 @@
 		 */
 		tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
 	} else {
-		if (hp->count < 0)
+		if (hp->port.count < 0)
 			printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
-				hp->vtermno, hp->count);
-		spin_unlock_irqrestore(&hp->lock, flags);
+				hp->vtermno, hp->port.count);
+		spin_unlock_irqrestore(&hp->port.lock, flags);
 	}
 
-	tty_kref_put(tty);
-	kref_put(&hp->kref, destroy_hvc_struct);
+	tty_port_put(&hp->port);
 }
 
 static void hvc_hangup(struct tty_struct *tty)
@@ -412,32 +405,31 @@
 	/* cancel pending tty resize work */
 	cancel_work_sync(&hp->tty_resize);
 
-	spin_lock_irqsave(&hp->lock, flags);
+	spin_lock_irqsave(&hp->port.lock, flags);
 
 	/*
 	 * The N_TTY line discipline has problems such that in a close vs
 	 * open->hangup case this can be called after the final close so prevent
 	 * that from happening for now.
 	 */
-	if (hp->count <= 0) {
-		spin_unlock_irqrestore(&hp->lock, flags);
+	if (hp->port.count <= 0) {
+		spin_unlock_irqrestore(&hp->port.lock, flags);
 		return;
 	}
 
-	temp_open_count = hp->count;
-	hp->count = 0;
-	hp->n_outbuf = 0;
-	hp->tty = NULL;
+	temp_open_count = hp->port.count;
+	hp->port.count = 0;
+	spin_unlock_irqrestore(&hp->port.lock, flags);
+	tty_port_tty_set(&hp->port, NULL);
 
-	spin_unlock_irqrestore(&hp->lock, flags);
+	hp->n_outbuf = 0;
 
 	if (hp->ops->notifier_hangup)
 		hp->ops->notifier_hangup(hp, hp->data);
 
 	while(temp_open_count) {
 		--temp_open_count;
-		tty_kref_put(tty);
-		kref_put(&hp->kref, destroy_hvc_struct);
+		tty_port_put(&hp->port);
 	}
 }
 
@@ -478,7 +470,8 @@
 	if (!hp)
 		return -EPIPE;
 
-	if (hp->count <= 0)
+	/* FIXME what's this (unprotected) check for? */
+	if (hp->port.count <= 0)
 		return -EIO;
 
 	spin_lock_irqsave(&hp->lock, flags);
@@ -526,13 +519,12 @@
 
 	hp = container_of(work, struct hvc_struct, tty_resize);
 
-	spin_lock_irqsave(&hp->lock, hvc_flags);
-	if (!hp->tty) {
-		spin_unlock_irqrestore(&hp->lock, hvc_flags);
+	tty = tty_port_tty_get(&hp->port);
+	if (!tty)
 		return;
-	}
-	ws  = hp->ws;
-	tty = tty_kref_get(hp->tty);
+
+	spin_lock_irqsave(&hp->lock, hvc_flags);
+	ws = hp->ws;
 	spin_unlock_irqrestore(&hp->lock, hvc_flags);
 
 	tty_do_resize(tty, &ws);
@@ -601,7 +593,7 @@
 	}
 
 	/* No tty attached, just skip */
-	tty = tty_kref_get(hp->tty);
+	tty = tty_port_tty_get(&hp->port);
 	if (tty == NULL)
 		goto bail;
 
@@ -681,8 +673,7 @@
 
 		tty_flip_buffer_push(tty);
 	}
-	if (tty)
-		tty_kref_put(tty);
+	tty_kref_put(tty);
 
 	return poll_mask;
 }
@@ -817,6 +808,10 @@
 #endif
 };
 
+static const struct tty_port_operations hvc_port_ops = {
+	.destruct = hvc_port_destruct,
+};
+
 struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
 			     const struct hv_ops *ops,
 			     int outbuf_size)
@@ -842,7 +837,8 @@
 	hp->outbuf_size = outbuf_size;
 	hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
 
-	kref_init(&hp->kref);
+	tty_port_init(&hp->port);
+	hp->port.ops = &hvc_port_ops;
 
 	INIT_WORK(&hp->tty_resize, hvc_set_winsz);
 	spin_lock_init(&hp->lock);
@@ -875,9 +871,9 @@
 	unsigned long flags;
 	struct tty_struct *tty;
 
-	spin_lock_irqsave(&hp->lock, flags);
-	tty = tty_kref_get(hp->tty);
+	tty = tty_port_tty_get(&hp->port);
 
+	spin_lock_irqsave(&hp->lock, flags);
 	if (hp->index < MAX_NR_HVC_CONSOLES)
 		vtermnos[hp->index] = -1;
 
@@ -891,7 +887,7 @@
 	 * kref cause it to be removed, which will probably be the tty_vhangup
 	 * below.
 	 */
-	kref_put(&hp->kref, destroy_hvc_struct);
+	tty_port_put(&hp->port);
 
 	/*
 	 * This function call will auto chain call hvc_hangup.
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h
index c335a14..674d23c 100644
--- a/drivers/tty/hvc/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
@@ -46,10 +46,9 @@
 #define HVC_ALLOC_TTY_ADAPTERS	8
 
 struct hvc_struct {
+	struct tty_port port;
 	spinlock_t lock;
 	int index;
-	struct tty_struct *tty;
-	int count;
 	int do_wakeup;
 	char *outbuf;
 	int outbuf_size;
@@ -61,7 +60,6 @@
 	struct winsize ws;
 	struct work_struct tty_resize;
 	struct list_head next;
-	struct kref kref; /* ref count & hvc_struct lifetime */
 };
 
 /* implemented by a low level driver */
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 83d5c88..d3d91da 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -430,9 +430,9 @@
 	if (devid == 0)
 		return -ENODEV;
 
-	info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+	info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
 	if (!info)
-		goto error_nomem;
+		return -ENOMEM;
 	dev_set_drvdata(&dev->dev, info);
 	info->xbdev = dev;
 	info->vtermno = xenbus_devid_to_vtermno(devid);
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index 3436436..d56788c 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -261,6 +261,7 @@
 
 /* One vty-server per hvcs_struct */
 struct hvcs_struct {
+	struct tty_port port;
 	spinlock_t lock;
 
 	/*
@@ -269,9 +270,6 @@
 	 */
 	unsigned int index;
 
-	struct tty_struct *tty;
-	int open_count;
-
 	/*
 	 * Used to tell the driver kernel_thread what operations need to take
 	 * place upon this hvcs_struct instance.
@@ -290,12 +288,11 @@
 	int chars_in_buffer;
 
 	/*
-	 * Any variable below the kref is valid before a tty is connected and
+	 * Any variable below is valid before a tty is connected and
 	 * stays valid after the tty is disconnected.  These shouldn't be
 	 * whacked until the kobject refcount reaches zero though some entries
 	 * may be changed via sysfs initiatives.
 	 */
-	struct kref kref; /* ref count & hvcs_struct lifetime */
 	int connected; /* is the vty-server currently connected to a vty? */
 	uint32_t p_unit_address; /* partner unit address */
 	uint32_t p_partition_ID; /* partner partition ID */
@@ -304,9 +301,6 @@
 	struct vio_dev *vdev;
 };
 
-/* Required to back map a kref to its containing object */
-#define from_kref(k) container_of(k, struct hvcs_struct, kref)
-
 static LIST_HEAD(hvcs_structs);
 static DEFINE_SPINLOCK(hvcs_structs_lock);
 static DEFINE_MUTEX(hvcs_init_mutex);
@@ -422,7 +416,7 @@
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 
-	if (hvcsd->open_count > 0) {
+	if (hvcsd->port.count > 0) {
 		spin_unlock_irqrestore(&hvcsd->lock, flags);
 		printk(KERN_INFO "HVCS: vterm state unchanged.  "
 				"The hvcs device node is still in use.\n");
@@ -564,7 +558,7 @@
 static void hvcs_try_write(struct hvcs_struct *hvcsd)
 {
 	uint32_t unit_address = hvcsd->vdev->unit_address;
-	struct tty_struct *tty = hvcsd->tty;
+	struct tty_struct *tty = hvcsd->port.tty;
 	int sent;
 
 	if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
@@ -602,7 +596,7 @@
 	spin_lock_irqsave(&hvcsd->lock, flags);
 
 	unit_address = hvcsd->vdev->unit_address;
-	tty = hvcsd->tty;
+	tty = hvcsd->port.tty;
 
 	hvcs_try_write(hvcsd);
 
@@ -701,10 +695,9 @@
 		hvcs_index_list[index] = -1;
 }
 
-/* callback when the kref ref count reaches zero */
-static void destroy_hvcs_struct(struct kref *kref)
+static void hvcs_destruct_port(struct tty_port *p)
 {
-	struct hvcs_struct *hvcsd = from_kref(kref);
+	struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
 	struct vio_dev *vdev;
 	unsigned long flags;
 
@@ -741,6 +734,10 @@
 	kfree(hvcsd);
 }
 
+static const struct tty_port_operations hvcs_port_ops = {
+	.destruct = hvcs_destruct_port,
+};
+
 static int hvcs_get_index(void)
 {
 	int i;
@@ -789,10 +786,9 @@
 	if (!hvcsd)
 		return -ENODEV;
 
-
+	tty_port_init(&hvcsd->port);
+	hvcsd->port.ops = &hvcs_port_ops;
 	spin_lock_init(&hvcsd->lock);
-	/* Automatically incs the refcount the first time */
-	kref_init(&hvcsd->kref);
 
 	hvcsd->vdev = dev;
 	dev_set_drvdata(&dev->dev, hvcsd);
@@ -852,7 +848,7 @@
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 
-	tty = hvcsd->tty;
+	tty = hvcsd->port.tty;
 
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
 
@@ -860,7 +856,7 @@
 	 * Let the last holder of this object cause it to be removed, which
 	 * would probably be tty_hangup below.
 	 */
-	kref_put(&hvcsd->kref, destroy_hvcs_struct);
+	tty_port_put(&hvcsd->port);
 
 	/*
 	 * The hangup is a scheduled function which will auto chain call
@@ -1094,7 +1090,7 @@
 	list_for_each_entry(hvcsd, &hvcs_structs, next) {
 		spin_lock_irqsave(&hvcsd->lock, flags);
 		if (hvcsd->index == index) {
-			kref_get(&hvcsd->kref);
+			tty_port_get(&hvcsd->port);
 			spin_unlock_irqrestore(&hvcsd->lock, flags);
 			spin_unlock(&hvcs_structs_lock);
 			return hvcsd;
@@ -1138,8 +1134,8 @@
 		if ((retval = hvcs_partner_connect(hvcsd)))
 			goto error_release;
 
-	hvcsd->open_count = 1;
-	hvcsd->tty = tty;
+	hvcsd->port.count = 1;
+	hvcsd->port.tty = tty;
 	tty->driver_data = hvcsd;
 
 	memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
@@ -1160,7 +1156,7 @@
 	 * and will grab the spinlock and free the connection if it fails.
 	 */
 	if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
-		kref_put(&hvcsd->kref, destroy_hvcs_struct);
+		tty_port_put(&hvcsd->port);
 		printk(KERN_WARNING "HVCS: enable device failed.\n");
 		return rc;
 	}
@@ -1171,8 +1167,8 @@
 	hvcsd = tty->driver_data;
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
-	kref_get(&hvcsd->kref);
-	hvcsd->open_count++;
+	tty_port_get(&hvcsd->port);
+	hvcsd->port.count++;
 	hvcsd->todo_mask |= HVCS_SCHED_READ;
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
 
@@ -1186,7 +1182,7 @@
 
 error_release:
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
-	kref_put(&hvcsd->kref, destroy_hvcs_struct);
+	tty_port_put(&hvcsd->port);
 
 	printk(KERN_WARNING "HVCS: partner connect failed.\n");
 	return retval;
@@ -1216,7 +1212,7 @@
 	hvcsd = tty->driver_data;
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
-	if (--hvcsd->open_count == 0) {
+	if (--hvcsd->port.count == 0) {
 
 		vio_disable_interrupts(hvcsd->vdev);
 
@@ -1225,7 +1221,7 @@
 		 * execute any operations on the TTY even though it is obligated
 		 * to deliver any pending I/O to the hypervisor.
 		 */
-		hvcsd->tty = NULL;
+		hvcsd->port.tty = NULL;
 
 		irq = hvcsd->vdev->irq;
 		spin_unlock_irqrestore(&hvcsd->lock, flags);
@@ -1240,16 +1236,16 @@
 		tty->driver_data = NULL;
 
 		free_irq(irq, hvcsd);
-		kref_put(&hvcsd->kref, destroy_hvcs_struct);
+		tty_port_put(&hvcsd->port);
 		return;
-	} else if (hvcsd->open_count < 0) {
+	} else if (hvcsd->port.count < 0) {
 		printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
 				" is missmanaged.\n",
-		hvcsd->vdev->unit_address, hvcsd->open_count);
+		hvcsd->vdev->unit_address, hvcsd->port.count);
 	}
 
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
-	kref_put(&hvcsd->kref, destroy_hvcs_struct);
+	tty_port_put(&hvcsd->port);
 }
 
 static void hvcs_hangup(struct tty_struct * tty)
@@ -1261,7 +1257,7 @@
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	/* Preserve this so that we know how many kref refs to put */
-	temp_open_count = hvcsd->open_count;
+	temp_open_count = hvcsd->port.count;
 
 	/*
 	 * Don't kref put inside the spinlock because the destruction
@@ -1273,10 +1269,10 @@
 	hvcsd->todo_mask = 0;
 
 	/* I don't think the tty needs the hvcs_struct pointer after a hangup */
-	hvcsd->tty->driver_data = NULL;
-	hvcsd->tty = NULL;
+	tty->driver_data = NULL;
+	hvcsd->port.tty = NULL;
 
-	hvcsd->open_count = 0;
+	hvcsd->port.count = 0;
 
 	/* This will drop any buffered data on the floor which is OK in a hangup
 	 * scenario. */
@@ -1301,7 +1297,7 @@
 		 * NOTE:  If this hangup was signaled from user space then the
 		 * final put will never happen.
 		 */
-		kref_put(&hvcsd->kref, destroy_hvcs_struct);
+		tty_port_put(&hvcsd->port);
 	}
 }
 
@@ -1347,7 +1343,7 @@
 	 * the middle of a write operation?  This is a crummy place to do this
 	 * but we want to keep it all in the spinlock.
 	 */
-	if (hvcsd->open_count <= 0) {
+	if (hvcsd->port.count <= 0) {
 		spin_unlock_irqrestore(&hvcsd->lock, flags);
 		return -ENODEV;
 	}
@@ -1421,7 +1417,7 @@
 {
 	struct hvcs_struct *hvcsd = tty->driver_data;
 
-	if (!hvcsd || hvcsd->open_count <= 0)
+	if (!hvcsd || hvcsd->port.count <= 0)
 		return 0;
 
 	return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index a7488b7..6f5bc49 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -69,14 +69,13 @@
 #define __ALIGNED__	__attribute__((__aligned__(sizeof(long))))
 
 struct hvsi_struct {
+	struct tty_port port;
 	struct delayed_work writer;
 	struct work_struct handshaker;
 	wait_queue_head_t emptyq; /* woken when outbuf is emptied */
 	wait_queue_head_t stateq; /* woken when HVSI state changes */
 	spinlock_t lock;
 	int index;
-	struct tty_struct *tty;
-	int count;
 	uint8_t throttle_buf[128];
 	uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
 	/* inbuf is for packet reassembly. leave a little room for leftovers. */
@@ -237,7 +236,7 @@
 }
 
 static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
-	struct tty_struct **to_hangup, struct hvsi_struct **to_handshake)
+	struct tty_struct *tty, struct hvsi_struct **to_handshake)
 {
 	struct hvsi_control *header = (struct hvsi_control *)packet;
 
@@ -247,9 +246,8 @@
 				/* CD went away; no more connection */
 				pr_debug("hvsi%i: CD dropped\n", hp->index);
 				hp->mctrl &= TIOCM_CD;
-				/* If userland hasn't done an open(2) yet, hp->tty is NULL. */
-				if (hp->tty && !(hp->tty->flags & CLOCAL))
-					*to_hangup = hp->tty;
+				if (tty && !C_CLOCAL(tty))
+					tty_hangup(tty);
 			}
 			break;
 		case VSV_CLOSE_PROTOCOL:
@@ -331,7 +329,8 @@
 	}
 }
 
-static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
+static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
+		const char *buf, int len)
 {
 	int i;
 
@@ -347,7 +346,7 @@
 			continue;
 		}
 #endif /* CONFIG_MAGIC_SYSRQ */
-		tty_insert_flip_char(hp->tty, c, 0);
+		tty_insert_flip_char(tty, c, 0);
 	}
 }
 
@@ -360,7 +359,7 @@
  * revisited.
  */
 #define TTY_THRESHOLD_THROTTLE 128
-static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
+static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
 		const uint8_t *packet)
 {
 	const struct hvsi_header *header = (const struct hvsi_header *)packet;
@@ -371,14 +370,14 @@
 	pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
 
 	if (datalen == 0)
-		return NULL;
+		return false;
 
 	if (overflow > 0) {
 		pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
 		datalen = TTY_THRESHOLD_THROTTLE;
 	}
 
-	hvsi_insert_chars(hp, data, datalen);
+	hvsi_insert_chars(hp, tty, data, datalen);
 
 	if (overflow > 0) {
 		/*
@@ -390,7 +389,7 @@
 		hp->n_throttle = overflow;
 	}
 
-	return hp->tty;
+	return true;
 }
 
 /*
@@ -399,14 +398,13 @@
  * machine during console handshaking (in which case tty = NULL and we ignore
  * incoming data).
  */
-static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
-		struct tty_struct **hangup, struct hvsi_struct **handshake)
+static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
+		struct hvsi_struct **handshake)
 {
 	uint8_t *packet = hp->inbuf;
 	int chunklen;
+	bool flip = false;
 
-	*flip = NULL;
-	*hangup = NULL;
 	*handshake = NULL;
 
 	chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
@@ -440,12 +438,12 @@
 			case VS_DATA_PACKET_HEADER:
 				if (!is_open(hp))
 					break;
-				if (hp->tty == NULL)
+				if (tty == NULL)
 					break; /* no tty buffer to put data in */
-				*flip = hvsi_recv_data(hp, packet);
+				flip = hvsi_recv_data(hp, tty, packet);
 				break;
 			case VS_CONTROL_PACKET_HEADER:
-				hvsi_recv_control(hp, packet, hangup, handshake);
+				hvsi_recv_control(hp, packet, tty, handshake);
 				break;
 			case VS_QUERY_RESPONSE_PACKET_HEADER:
 				hvsi_recv_response(hp, packet);
@@ -462,28 +460,26 @@
 
 		packet += len_packet(packet);
 
-		if (*hangup || *handshake) {
-			pr_debug("%s: hangup or handshake\n", __func__);
-			/*
-			 * we need to send the hangup now before receiving any more data.
-			 * If we get "data, hangup, data", we can't deliver the second
-			 * data before the hangup.
-			 */
+		if (*handshake) {
+			pr_debug("%s: handshake\n", __func__);
 			break;
 		}
 	}
 
 	compact_inbuf(hp, packet);
 
+	if (flip)
+		tty_flip_buffer_push(tty);
+
 	return 1;
 }
 
-static void hvsi_send_overflow(struct hvsi_struct *hp)
+static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)
 {
 	pr_debug("%s: delivering %i bytes overflow\n", __func__,
 			hp->n_throttle);
 
-	hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
+	hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);
 	hp->n_throttle = 0;
 }
 
@@ -494,35 +490,20 @@
 static irqreturn_t hvsi_interrupt(int irq, void *arg)
 {
 	struct hvsi_struct *hp = (struct hvsi_struct *)arg;
-	struct tty_struct *flip;
-	struct tty_struct *hangup;
 	struct hvsi_struct *handshake;
+	struct tty_struct *tty;
 	unsigned long flags;
 	int again = 1;
 
 	pr_debug("%s\n", __func__);
 
+	tty = tty_port_tty_get(&hp->port);
+
 	while (again) {
 		spin_lock_irqsave(&hp->lock, flags);
-		again = hvsi_load_chunk(hp, &flip, &hangup, &handshake);
+		again = hvsi_load_chunk(hp, tty, &handshake);
 		spin_unlock_irqrestore(&hp->lock, flags);
 
-		/*
-		 * we have to call tty_flip_buffer_push() and tty_hangup() outside our
-		 * spinlock. But we also have to keep going until we've read all the
-		 * available data.
-		 */
-
-		if (flip) {
-			/* there was data put in the tty flip buffer */
-			tty_flip_buffer_push(flip);
-			flip = NULL;
-		}
-
-		if (hangup) {
-			tty_hangup(hangup);
-		}
-
 		if (handshake) {
 			pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
 			schedule_work(&handshake->handshaker);
@@ -530,18 +511,15 @@
 	}
 
 	spin_lock_irqsave(&hp->lock, flags);
-	if (hp->tty && hp->n_throttle
-			&& (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
-		/* we weren't hung up and we weren't throttled, so we can deliver the
-		 * rest now */
-		flip = hp->tty;
-		hvsi_send_overflow(hp);
+	if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
+		/* we weren't hung up and we weren't throttled, so we can
+		 * deliver the rest now */
+		hvsi_send_overflow(hp, tty);
+		tty_flip_buffer_push(tty);
 	}
 	spin_unlock_irqrestore(&hp->lock, flags);
 
-	if (flip) {
-		tty_flip_buffer_push(flip);
-	}
+	tty_kref_put(tty);
 
 	return IRQ_HANDLED;
 }
@@ -749,9 +727,9 @@
 	if (hp->state == HVSI_FSP_DIED)
 		return -EIO;
 
+	tty_port_tty_set(&hp->port, tty);
 	spin_lock_irqsave(&hp->lock, flags);
-	hp->tty = tty;
-	hp->count++;
+	hp->port.count++;
 	atomic_set(&hp->seqno, 0);
 	h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
 	spin_unlock_irqrestore(&hp->lock, flags);
@@ -808,8 +786,8 @@
 
 	spin_lock_irqsave(&hp->lock, flags);
 
-	if (--hp->count == 0) {
-		hp->tty = NULL;
+	if (--hp->port.count == 0) {
+		tty_port_tty_set(&hp->port, NULL);
 		hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
 
 		/* only close down connection if it is not the console */
@@ -841,9 +819,9 @@
 
 			spin_lock_irqsave(&hp->lock, flags);
 		}
-	} else if (hp->count < 0)
+	} else if (hp->port.count < 0)
 		printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
-		       hp - hvsi_ports, hp->count);
+		       hp - hvsi_ports, hp->port.count);
 
 	spin_unlock_irqrestore(&hp->lock, flags);
 }
@@ -855,12 +833,11 @@
 
 	pr_debug("%s\n", __func__);
 
+	tty_port_tty_set(&hp->port, NULL);
+
 	spin_lock_irqsave(&hp->lock, flags);
-
-	hp->count = 0;
+	hp->port.count = 0;
 	hp->n_outbuf = 0;
-	hp->tty = NULL;
-
 	spin_unlock_irqrestore(&hp->lock, flags);
 }
 
@@ -888,6 +865,7 @@
 {
 	struct hvsi_struct *hp =
 		container_of(work, struct hvsi_struct, writer.work);
+	struct tty_struct *tty;
 	unsigned long flags;
 #ifdef DEBUG
 	static long start_j = 0;
@@ -921,7 +899,11 @@
 		start_j = 0;
 #endif /* DEBUG */
 		wake_up_all(&hp->emptyq);
-		tty_wakeup(hp->tty);
+		tty = tty_port_tty_get(&hp->port);
+		if (tty) {
+			tty_wakeup(tty);
+			tty_kref_put(tty);
+		}
 	}
 
 out:
@@ -966,8 +948,8 @@
 	 * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
 	 * will see there is no room in outbuf and return.
 	 */
-	while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) {
-		int chunksize = min(count, hvsi_write_room(hp->tty));
+	while ((count > 0) && (hvsi_write_room(tty) > 0)) {
+		int chunksize = min(count, hvsi_write_room(tty));
 
 		BUG_ON(hp->n_outbuf < 0);
 		memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
@@ -1014,19 +996,16 @@
 {
 	struct hvsi_struct *hp = tty->driver_data;
 	unsigned long flags;
-	int shouldflip = 0;
 
 	pr_debug("%s\n", __func__);
 
 	spin_lock_irqsave(&hp->lock, flags);
 	if (hp->n_throttle) {
-		hvsi_send_overflow(hp);
-		shouldflip = 1;
+		hvsi_send_overflow(hp, tty);
+		tty_flip_buffer_push(tty);
 	}
 	spin_unlock_irqrestore(&hp->lock, flags);
 
-	if (shouldflip)
-		tty_flip_buffer_push(hp->tty);
 
 	h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
 }
@@ -1228,6 +1207,7 @@
 		init_waitqueue_head(&hp->emptyq);
 		init_waitqueue_head(&hp->stateq);
 		spin_lock_init(&hp->lock);
+		tty_port_init(&hp->port);
 		hp->index = hvsi_count;
 		hp->inbuf_end = hp->inbuf;
 		hp->state = HVSI_CLOSED;
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c
index 6f4dd83..59c135d 100644
--- a/drivers/tty/hvc/hvsi_lib.c
+++ b/drivers/tty/hvc/hvsi_lib.c
@@ -377,7 +377,7 @@
 	pr_devel("HVSI@%x: open !\n", pv->termno);
 
 	/* Keep track of the tty data structure */
-	pv->tty = tty_kref_get(hp->tty);
+	pv->tty = tty_port_tty_get(&hp->port);
 
 	hvsilib_establish(pv);
 
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index 4daf962..f8b5fa0 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -44,14 +44,13 @@
 #define TTYTYPE_RAS_RAW  (2)
 
 struct ipw_tty {
+	struct tty_port port;
 	int index;
 	struct ipw_hardware *hardware;
 	unsigned int channel_idx;
 	unsigned int secondary_channel_idx;
 	int tty_type;
 	struct ipw_network *network;
-	struct tty_struct *linux_tty;
-	int open_count;
 	unsigned int control_lines;
 	struct mutex ipw_tty_mutex;
 	int tx_bytes_queued;
@@ -73,23 +72,6 @@
 	return channel_names[tty_type];
 }
 
-static void report_registering(struct ipw_tty *tty)
-{
-	char *iftype = tty_type_name(tty->tty_type);
-
-	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
-	       ": registering %s device ttyIPWp%d\n", iftype, tty->index);
-}
-
-static void report_deregistering(struct ipw_tty *tty)
-{
-	char *iftype = tty_type_name(tty->tty_type);
-
-	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
-	       ": deregistering %s device ttyIPWp%d\n", iftype,
-	       tty->index);
-}
-
 static struct ipw_tty *get_tty(int index)
 {
 	/*
@@ -117,12 +99,12 @@
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return -ENODEV;
 	}
-	if (tty->open_count == 0)
+	if (tty->port.count == 0)
 		tty->tx_bytes_queued = 0;
 
-	tty->open_count++;
+	tty->port.count++;
 
-	tty->linux_tty = linux_tty;
+	tty->port.tty = linux_tty;
 	linux_tty->driver_data = tty;
 	linux_tty->low_latency = 1;
 
@@ -136,13 +118,13 @@
 
 static void do_ipw_close(struct ipw_tty *tty)
 {
-	tty->open_count--;
+	tty->port.count--;
 
-	if (tty->open_count == 0) {
-		struct tty_struct *linux_tty = tty->linux_tty;
+	if (tty->port.count == 0) {
+		struct tty_struct *linux_tty = tty->port.tty;
 
 		if (linux_tty != NULL) {
-			tty->linux_tty = NULL;
+			tty->port.tty = NULL;
 			linux_tty->driver_data = NULL;
 
 			if (tty->tty_type == TTYTYPE_MODEM)
@@ -159,7 +141,7 @@
 		return;
 
 	mutex_lock(&tty->ipw_tty_mutex);
-	if (tty->open_count == 0) {
+	if (tty->port.count == 0) {
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return;
 	}
@@ -182,13 +164,13 @@
 	int work = 0;
 
 	mutex_lock(&tty->ipw_tty_mutex);
-	linux_tty = tty->linux_tty;
+	linux_tty = tty->port.tty;
 	if (linux_tty == NULL) {
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return;
 	}
 
-	if (!tty->open_count) {
+	if (!tty->port.count) {
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return;
 	}
@@ -230,7 +212,7 @@
 		return -ENODEV;
 
 	mutex_lock(&tty->ipw_tty_mutex);
-	if (!tty->open_count) {
+	if (!tty->port.count) {
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return -EINVAL;
 	}
@@ -270,7 +252,7 @@
 	if (!tty)
 		return -ENODEV;
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return -EINVAL;
 
 	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
@@ -312,7 +294,7 @@
 	if (!tty)
 		return 0;
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return 0;
 
 	return tty->tx_bytes_queued;
@@ -393,7 +375,7 @@
 	if (!tty)
 		return -ENODEV;
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return -EINVAL;
 
 	return get_control_lines(tty);
@@ -409,7 +391,7 @@
 	if (!tty)
 		return -ENODEV;
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return -EINVAL;
 
 	return set_control_lines(tty, set, clear);
@@ -423,7 +405,7 @@
 	if (!tty)
 		return -ENODEV;
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return -EINVAL;
 
 	/* FIXME: Exactly how is the tty object locked here .. */
@@ -492,6 +474,7 @@
 	ttys[j]->network = network;
 	ttys[j]->tty_type = tty_type;
 	mutex_init(&ttys[j]->ipw_tty_mutex);
+	tty_port_init(&ttys[j]->port);
 
 	tty_register_device(ipw_tty_driver, j, NULL);
 	ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
@@ -500,8 +483,12 @@
 		ipwireless_associate_network_tty(network,
 						 secondary_channel_idx,
 						 ttys[j]);
-	if (get_tty(j) == ttys[j])
-		report_registering(ttys[j]);
+	/* check if we provide raw device (if loopback is enabled) */
+	if (get_tty(j))
+		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
+		       ": registering %s device ttyIPWp%d\n",
+		       tty_type_name(tty_type), j);
+
 	return 0;
 }
 
@@ -560,19 +547,21 @@
 
 		if (ttyj) {
 			mutex_lock(&ttyj->ipw_tty_mutex);
-			if (get_tty(j) == ttyj)
-				report_deregistering(ttyj);
+			if (get_tty(j))
+				printk(KERN_INFO IPWIRELESS_PCCARD_NAME
+				       ": deregistering %s device ttyIPWp%d\n",
+				       tty_type_name(ttyj->tty_type), j);
 			ttyj->closing = 1;
-			if (ttyj->linux_tty != NULL) {
+			if (ttyj->port.tty != NULL) {
 				mutex_unlock(&ttyj->ipw_tty_mutex);
-				tty_hangup(ttyj->linux_tty);
-				/* Wait till the tty_hangup has completed */
-				flush_work_sync(&ttyj->linux_tty->hangup_work);
+				tty_vhangup(ttyj->port.tty);
 				/* FIXME: Exactly how is the tty object locked here
 				   against a parallel ioctl etc */
+				/* FIXME2: hangup does not mean all processes
+				 * are gone */
 				mutex_lock(&ttyj->ipw_tty_mutex);
 			}
-			while (ttyj->open_count)
+			while (ttyj->port.count)
 				do_ipw_close(ttyj);
 			ipwireless_disassociate_network_ttys(network,
 							     ttyj->channel_idx);
@@ -661,8 +650,8 @@
 	 */
 	if ((old_control_lines & IPW_CONTROL_LINE_DCD)
 			&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
-			&& tty->linux_tty) {
-		tty_hangup(tty->linux_tty);
+			&& tty->port.tty) {
+		tty_hangup(tty->port.tty);
 	}
 }
 
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index c6f372d..90cc680 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -2326,7 +2326,7 @@
 	.get_icount = mxser_get_icount,
 };
 
-struct tty_port_operations mxser_port_ops = {
+static struct tty_port_operations mxser_port_ops = {
 	.carrier_raised = mxser_carrier_raised,
 	.dtr_rts = mxser_dtr_rts,
 	.activate = mxser_activate,
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
index 5c6c314..656ad93 100644
--- a/drivers/tty/n_r3964.c
+++ b/drivers/tty/n_r3964.c
@@ -1065,7 +1065,8 @@
 
 	TRACE_L("read()");
 
-	tty_lock();
+	/* FIXME: should use a private lock */
+	tty_lock(tty);
 
 	pClient = findClient(pInfo, task_pid(current));
 	if (pClient) {
@@ -1077,7 +1078,7 @@
 				goto unlock;
 			}
 			/* block until there is a message: */
-			wait_event_interruptible_tty(pInfo->read_wait,
+			wait_event_interruptible_tty(tty, pInfo->read_wait,
 					(pMsg = remove_msg(pInfo, pClient)));
 		}
 
@@ -1107,7 +1108,7 @@
 	}
 	ret = -EPERM;
 unlock:
-	tty_unlock();
+	tty_unlock(tty);
 	return ret;
 }
 
@@ -1156,7 +1157,7 @@
 	pHeader->locks = 0;
 	pHeader->owner = NULL;
 
-	tty_lock();
+	tty_lock(tty);
 
 	pClient = findClient(pInfo, task_pid(current));
 	if (pClient) {
@@ -1175,7 +1176,7 @@
 	add_tx_queue(pInfo, pHeader);
 	trigger_transmit(pInfo);
 
-	tty_unlock();
+	tty_unlock(tty);
 
 	return 0;
 }
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 94b6eda..ee1c268 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1630,6 +1630,7 @@
 	int retval;
 	size_t n;
 	unsigned long flags;
+	bool is_eof;
 
 	retval = 0;
 	spin_lock_irqsave(&tty->read_lock, flags);
@@ -1639,15 +1640,15 @@
 	if (n) {
 		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
 		n -= retval;
+		is_eof = n == 1 &&
+			tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
 		tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
 		spin_lock_irqsave(&tty->read_lock, flags);
 		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
 		tty->read_cnt -= n;
 		/* Turn single EOF into zero-length read */
-		if (L_EXTPROC(tty) && tty->icanon && n == 1) {
-			if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
-				n--;
-		}
+		if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
+			n = 0;
 		spin_unlock_irqrestore(&tty->read_lock, flags);
 		*b += n;
 		*nr -= n;
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index eeae7fa..59af394 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -26,11 +26,13 @@
 #include <linux/bitops.h>
 #include <linux/devpts_fs.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 
 
 #ifdef CONFIG_UNIX98_PTYS
 static struct tty_driver *ptm_driver;
 static struct tty_driver *pts_driver;
+static DEFINE_MUTEX(devpts_mutex);
 #endif
 
 static void pty_close(struct tty_struct *tty, struct file *filp)
@@ -45,6 +47,7 @@
 	wake_up_interruptible(&tty->read_wait);
 	wake_up_interruptible(&tty->write_wait);
 	tty->packet = 0;
+	/* Review - krefs on tty_link ?? */
 	if (!tty->link)
 		return;
 	tty->link->packet = 0;
@@ -54,12 +57,15 @@
 	if (tty->driver->subtype == PTY_TYPE_MASTER) {
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
-		if (tty->driver == ptm_driver)
+		if (tty->driver == ptm_driver) {
+		        mutex_lock(&devpts_mutex);
 			devpts_pty_kill(tty->link);
+		        mutex_unlock(&devpts_mutex);
+		}
 #endif
-		tty_unlock();
+		tty_unlock(tty);
 		tty_vhangup(tty->link);
-		tty_lock();
+		tty_lock(tty);
 	}
 }
 
@@ -475,13 +481,17 @@
  *	@idx: tty index
  *
  *	Look up a pty master device. Called under the tty_mutex for now.
- *	This provides our locking.
+ *	This provides our locking for the tty pointer.
  */
 
 static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
 		struct inode *pts_inode, int idx)
 {
-	struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+	struct tty_struct *tty;
+
+	mutex_lock(&devpts_mutex);
+	tty = devpts_get_tty(pts_inode, idx);
+	mutex_unlock(&devpts_mutex);
 	/* Master must be open before slave */
 	if (!tty)
 		return ERR_PTR(-EIO);
@@ -613,24 +623,29 @@
 		return retval;
 
 	/* find a device that is not in use. */
-	tty_lock();
+	mutex_lock(&devpts_mutex);
 	index = devpts_new_index(inode);
-	tty_unlock();
 	if (index < 0) {
 		retval = index;
 		goto err_file;
 	}
 
+	mutex_unlock(&devpts_mutex);
+
 	mutex_lock(&tty_mutex);
-	tty_lock();
+	mutex_lock(&devpts_mutex);
 	tty = tty_init_dev(ptm_driver, index);
-	mutex_unlock(&tty_mutex);
 
 	if (IS_ERR(tty)) {
 		retval = PTR_ERR(tty);
 		goto out;
 	}
 
+	/* The tty returned here is locked so we can safely
+	   drop the mutex */
+	mutex_unlock(&devpts_mutex);
+	mutex_unlock(&tty_mutex);
+
 	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 
 	tty_add_file(tty, filp);
@@ -643,16 +658,17 @@
 	if (retval)
 		goto err_release;
 
-	tty_unlock();
+	tty_unlock(tty);
 	return 0;
 err_release:
-	tty_unlock();
+	tty_unlock(tty);
 	tty_release(inode, filp);
 	return retval;
 out:
+	mutex_unlock(&tty_mutex);
 	devpts_kill_index(inode, index);
-	tty_unlock();
 err_file:
+        mutex_unlock(&devpts_mutex);
 	tty_free_file(filp);
 	return retval;
 }
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 5ce78252..3ed20e4 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -17,6 +17,7 @@
 #include <asm/dbg.h>
 #include <linux/module.h>
 #include <linux/errno.h>
+#include <linux/serial.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
@@ -56,8 +57,6 @@
 #endif /* CONFIG_M68VZ328 */
 #endif /* CONFIG_M68EZ328 */
 
-#include "68328serial.h"
-
 /* Turn off usage of real serial interrupt code, to "support" Copilot */
 #ifdef CONFIG_XCOPILOT_BUGS
 #undef USE_INTS
@@ -65,33 +64,82 @@
 #define USE_INTS
 #endif
 
+/*
+ * I believe this is the optimal setting that reduces the number of interrupts.
+ * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
+ * if that bothers you), but in most cases it will not, since we try to
+ * transmit characters every time rs_interrupt is called. Thus, quite often
+ * you'll see that a receive interrupt occures before the transmit one.
+ *                                  -- Vladimir Gurevich
+ */
+#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
+
+/*
+ * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
+ * "Old data interrupt" which occures whenever the data stay in the FIFO
+ * longer than 30 bits time. This allows us to use FIFO without compromising
+ * latency. '328 does not have this feature and without the real  328-based
+ * board I would assume that RXRE is the safest setting.
+ *
+ * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
+ * interrupts. RXFE (receive queue full) causes the system to lose data
+ * at least at 115200 baud
+ *
+ * If your board is busy doing other stuff, you might consider to use
+ * RXRE (data ready intrrupt) instead.
+ *
+ * The other option is to make these INTR masks run-time configurable, so
+ * that people can dynamically adapt them according to the current usage.
+ *                                  -- Vladimir Gurevich
+ */
+
+/* (es) */
+#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
+#elif defined(CONFIG_M68328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
+#else
+#error Please, define the Rx interrupt events for your CPU
+#endif
+/* (/es) */
+
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct m68k_serial {
+	struct tty_port		tport;
+	char			is_cons;	/* Is this our console. */
+	int			magic;
+	int			baud_base;
+	int			port;
+	int			irq;
+	int			type;		/* UART type */
+	int			custom_divisor;
+	int			x_char;		/* xon/xoff character */
+	int			line;
+	unsigned char		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+};
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * Define the number of ports supported and their irqs.
+ */
+#define NR_PORTS 1
+
 static struct m68k_serial m68k_soft[NR_PORTS];
 
-static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
+static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM };
 
 /* multiple ports are contiguous in memory */
 m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
 
-struct tty_struct m68k_ttys;
-struct m68k_serial *m68k_consinfo = 0;
-
-#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
-
 struct tty_driver *serial_driver;
 
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#define RS_ISR_PASS_LIMIT 256
-
-static void change_speed(struct m68k_serial *info);
+static void change_speed(struct m68k_serial *info, struct tty_struct *tty);
 
 /*
  *	Setup for console. Argument comes from the boot command line.
@@ -143,17 +191,6 @@
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
 	9600, 19200, 38400, 57600, 115200, 0 };
 
-/* Sets or clears DTR/RTS on the requested line */
-static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
-{
-	if (set) {
-		/* set the RTS/CTS line */
-	} else {
-		/* clear it */
-	}
-	return;
-}
-
 /* Utility routines */
 static inline int get_baud(struct m68k_serial *ss)
 {
@@ -189,7 +226,8 @@
 
 static int rs_put_char(char ch)
 {
-        int flags, loops = 0;
+	unsigned long flags;
+	int loops = 0;
 
         local_irq_save(flags);
 
@@ -224,28 +262,9 @@
 	local_irq_restore(flags);
 }
 
-/* Drop into either the boot monitor or kadb upon receiving a break
- * from keyboard/console input.
- */
-static void batten_down_hatches(void)
+static void receive_chars(struct m68k_serial *info, struct tty_struct *tty,
+		unsigned short rx)
 {
-	/* Drop into the debugger */
-}
-
-static void status_handle(struct m68k_serial *info, unsigned short status)
-{
-	/* If this is console input and this is a
-	 * 'break asserted' status change interrupt
-	 * see if we can drop into the debugger
-	 */
-	if((status & URX_BREAK) && info->break_abort)
-		batten_down_hatches();
-	return;
-}
-
-static void receive_chars(struct m68k_serial *info, unsigned short rx)
-{
-	struct tty_struct *tty = info->tty;
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned char ch, flag;
 
@@ -259,7 +278,6 @@
 	
 		if(info->is_cons) {
 			if(URX_BREAK & rx) { /* whee, break received */
-				status_handle(info, rx);
 				return;
 #ifdef CONFIG_MAGIC_SYSRQ
 			} else if (ch == 0x10) { /* ^P */
@@ -280,16 +298,13 @@
 		
 		flag = TTY_NORMAL;
 
-		if(rx & URX_PARITY_ERROR) {
+		if (rx & URX_PARITY_ERROR)
 			flag = TTY_PARITY;
-			status_handle(info, rx);
-		} else if(rx & URX_OVRUN) {
+		else if (rx & URX_OVRUN)
 			flag = TTY_OVERRUN;
-			status_handle(info, rx);
-		} else if(rx & URX_FRAME_ERROR) {
+		else if (rx & URX_FRAME_ERROR)
 			flag = TTY_FRAME;
-			status_handle(info, rx);
-		}
+
 		tty_insert_flip_char(tty, ch, flag);
 #ifndef CONFIG_XCOPILOT_BUGS
 	} while((rx = uart->urx.w) & URX_DATA_READY);
@@ -301,7 +316,7 @@
 	return;
 }
 
-static void transmit_chars(struct m68k_serial *info)
+static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
 {
 	m68328_uart *uart = &uart_addr[info->line];
 
@@ -312,7 +327,7 @@
 		goto clear_and_return;
 	}
 
-	if((info->xmit_cnt <= 0) || info->tty->stopped) {
+	if ((info->xmit_cnt <= 0) || !tty || tty->stopped) {
 		/* That's peculiar... TX ints off */
 		uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
 		goto clear_and_return;
@@ -340,6 +355,7 @@
 irqreturn_t rs_interrupt(int irq, void *dev_id)
 {
 	struct m68k_serial *info = dev_id;
+	struct tty_struct *tty = tty_port_tty_get(&info->tport);
 	m68328_uart *uart;
 	unsigned short rx;
 	unsigned short tx;
@@ -350,20 +366,24 @@
 #ifdef USE_INTS
 	tx = uart->utx.w;
 
-	if (rx & URX_DATA_READY) receive_chars(info, rx);
-	if (tx & UTX_TX_AVAIL)   transmit_chars(info);
+	if (rx & URX_DATA_READY)
+		receive_chars(info, tty, rx);
+	if (tx & UTX_TX_AVAIL)
+		transmit_chars(info, tty);
 #else
-	receive_chars(info, rx);		
+	receive_chars(info, tty, rx);
 #endif
+	tty_kref_put(tty);
+
 	return IRQ_HANDLED;
 }
 
-static int startup(struct m68k_serial * info)
+static int startup(struct m68k_serial *info, struct tty_struct *tty)
 {
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned long flags;
 	
-	if (info->flags & S_INITIALIZED)
+	if (info->tport.flags & ASYNC_INITIALIZED)
 		return 0;
 
 	if (!info->xmit_buf) {
@@ -380,7 +400,6 @@
 	 */
 
 	uart->ustcnt = USTCNT_UEN;
-	info->xmit_fifo_size = 1;
 	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
 	(void)uart->urx.w;
 
@@ -394,17 +413,17 @@
 	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
 #endif
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (tty)
+		clear_bit(TTY_IO_ERROR, &tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
 	/*
 	 * and set the speed of the serial port
 	 */
 
-	change_speed(info);
+	change_speed(info, tty);
 
-	info->flags |= S_INITIALIZED;
+	info->tport.flags |= ASYNC_INITIALIZED;
 	local_irq_restore(flags);
 	return 0;
 }
@@ -413,13 +432,13 @@
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void shutdown(struct m68k_serial * info)
+static void shutdown(struct m68k_serial *info, struct tty_struct *tty)
 {
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned long	flags;
 
 	uart->ustcnt = 0; /* All off! */
-	if (!(info->flags & S_INITIALIZED))
+	if (!(info->tport.flags & ASYNC_INITIALIZED))
 		return;
 
 	local_irq_save(flags);
@@ -429,10 +448,10 @@
 		info->xmit_buf = 0;
 	}
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (tty)
+		set_bit(TTY_IO_ERROR, &tty->flags);
 	
-	info->flags &= ~S_INITIALIZED;
+	info->tport.flags &= ~ASYNC_INITIALIZED;
 	local_irq_restore(flags);
 }
 
@@ -488,7 +507,7 @@
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static void change_speed(struct m68k_serial *info)
+static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
 {
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned short port;
@@ -496,9 +515,7 @@
 	unsigned cflag;
 	int	i;
 
-	if (!info->tty || !info->tty->termios)
-		return;
-	cflag = info->tty->termios->c_cflag;
+	cflag = tty->termios->c_cflag;
 	if (!(port = info->port))
 		return;
 
@@ -510,7 +527,6 @@
                 i = (i & ~CBAUDEX) + B38400;
         }
 
-	info->baud = baud_table[i];
 	uart->ubaud = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
 		PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
 
@@ -807,10 +823,10 @@
 	tmp.line = info->line;
 	tmp.port = info->port;
 	tmp.irq = info->irq;
-	tmp.flags = info->flags;
+	tmp.flags = info->tport.flags;
 	tmp.baud_base = info->baud_base;
-	tmp.close_delay = info->close_delay;
-	tmp.closing_wait = info->closing_wait;
+	tmp.close_delay = info->tport.close_delay;
+	tmp.closing_wait = info->tport.closing_wait;
 	tmp.custom_divisor = info->custom_divisor;
 	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
 		return -EFAULT;
@@ -818,9 +834,10 @@
 	return 0;
 }
 
-static int set_serial_info(struct m68k_serial * info,
+static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,
 			   struct serial_struct * new_info)
 {
+	struct tty_port *port = &info->tport;
 	struct serial_struct new_serial;
 	struct m68k_serial old_info;
 	int 			retval = 0;
@@ -834,17 +851,17 @@
 	if (!capable(CAP_SYS_ADMIN)) {
 		if ((new_serial.baud_base != info->baud_base) ||
 		    (new_serial.type != info->type) ||
-		    (new_serial.close_delay != info->close_delay) ||
-		    ((new_serial.flags & ~S_USR_MASK) !=
-		     (info->flags & ~S_USR_MASK)))
+		    (new_serial.close_delay != port->close_delay) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (port->flags & ~ASYNC_USR_MASK)))
 			return -EPERM;
-		info->flags = ((info->flags & ~S_USR_MASK) |
-			       (new_serial.flags & S_USR_MASK));
+		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
 		info->custom_divisor = new_serial.custom_divisor;
 		goto check_and_exit;
 	}
 
-	if (info->count > 1)
+	if (port->count > 1)
 		return -EBUSY;
 
 	/*
@@ -853,14 +870,14 @@
 	 */
 
 	info->baud_base = new_serial.baud_base;
-	info->flags = ((info->flags & ~S_FLAGS) |
-			(new_serial.flags & S_FLAGS));
+	port->flags = ((port->flags & ~ASYNC_FLAGS) |
+			(new_serial.flags & ASYNC_FLAGS));
 	info->type = new_serial.type;
-	info->close_delay = new_serial.close_delay;
-	info->closing_wait = new_serial.closing_wait;
+	port->close_delay = new_serial.close_delay;
+	port->closing_wait = new_serial.closing_wait;
 
 check_and_exit:
-	retval = startup(info);
+	retval = startup(info, tty);
 	return retval;
 }
 
@@ -946,7 +963,7 @@
 			return get_serial_info(info,
 				       (struct serial_struct *) arg);
 		case TIOCSSERIAL:
-			return set_serial_info(info,
+			return set_serial_info(info, tty,
 					       (struct serial_struct *) arg);
 		case TIOCSERGETLSR: /* Get line status register */
 			return get_lsr_info(info, (unsigned int *) arg);
@@ -965,7 +982,7 @@
 {
 	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
 
-	change_speed(info);
+	change_speed(info, tty);
 
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	    !(tty->termios->c_cflag & CRTSCTS)) {
@@ -988,6 +1005,7 @@
 static void rs_close(struct tty_struct *tty, struct file * filp)
 {
 	struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+	struct tty_port *port = &info->tport;
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned long flags;
 
@@ -1001,7 +1019,7 @@
 		return;
 	}
 	
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (port->count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * structure will be freed.  Info->count should always
@@ -1010,26 +1028,26 @@
 		 * serial port won't be shutdown.
 		 */
 		printk("rs_close: bad serial port count; tty->count is 1, "
-		       "info->count is %d\n", info->count);
-		info->count = 1;
+		       "port->count is %d\n", port->count);
+		port->count = 1;
 	}
-	if (--info->count < 0) {
+	if (--port->count < 0) {
 		printk("rs_close: bad serial port count for ttyS%d: %d\n",
-		       info->line, info->count);
-		info->count = 0;
+		       info->line, port->count);
+		port->count = 0;
 	}
-	if (info->count) {
+	if (port->count) {
 		local_irq_restore(flags);
 		return;
 	}
-	info->flags |= S_CLOSING;
+	port->flags |= ASYNC_CLOSING;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (info->closing_wait != S_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, port->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1040,13 +1058,12 @@
 	uart->ustcnt &= ~USTCNT_RXEN;
 	uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
 
-	shutdown(info);
+	shutdown(info, tty);
 	rs_flush_buffer(tty);
 		
 	tty_ldisc_flush(tty);
 	tty->closing = 0;
-	info->event = 0;
-	info->tty = NULL;
+	tty_port_tty_set(&info->tport, NULL);
 #warning "This is not and has never been valid so fix it"	
 #if 0
 	if (tty->ldisc.num != ldiscs[N_TTY].num) {
@@ -1058,14 +1075,13 @@
 			(tty->ldisc.open)(tty);
 	}
 #endif	
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
-		}
-		wake_up_interruptible(&info->open_wait);
+	if (port->blocked_open) {
+		if (port->close_delay)
+			msleep_interruptible(jiffies_to_msecs(port->close_delay));
+		wake_up_interruptible(&port->open_wait);
 	}
-	info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
-	wake_up_interruptible(&info->close_wait);
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	wake_up_interruptible(&port->close_wait);
 	local_irq_restore(flags);
 }
 
@@ -1080,107 +1096,14 @@
 		return;
 	
 	rs_flush_buffer(tty);
-	shutdown(info);
-	info->event = 0;
-	info->count = 0;
-	info->flags &= ~S_NORMAL_ACTIVE;
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
+	shutdown(info, tty);
+	info->tport.count = 0;
+	info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
+	tty_port_tty_set(&info->tport, NULL);
+	wake_up_interruptible(&info->tport.open_wait);
 }
 
 /*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-			   struct m68k_serial *info)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	int		retval;
-	int		do_clocal = 0;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (info->flags & S_CLOSING) {
-		interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		if (info->flags & S_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-	
-	/*
-	 * If non-blocking mode is set, or the port is not enabled,
-	 * then make the check up front and then exit.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		info->flags |= S_NORMAL_ACTIVE;
-		return 0;
-	}
-
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
-
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
-	 * rs_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-
-	info->count--;
-	info->blocked_open++;
-	while (1) {
-		local_irq_disable();
-		m68k_rtsdtr(info, 1);
-		local_irq_enable();
-		current->state = TASK_INTERRUPTIBLE;
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & S_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-			if (info->flags & S_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;	
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & S_CLOSING) && do_clocal)
-			break;
-                if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-		tty_unlock();
-		schedule();
-		tty_lock();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-
-	if (retval)
-		return retval;
-	info->flags |= S_NORMAL_ACTIVE;
-	return 0;
-}	
-
-/*
  * This routine is called whenever a serial port is opened.  It
  * enables interrupts for a serial port, linking in its S structure into
  * the IRQ chain.   It also performs the serial-specific
@@ -1196,18 +1119,18 @@
 	if (serial_paranoia_check(info, tty->name, "rs_open"))
 		return -ENODEV;
 
-	info->count++;
+	info->tport.count++;
 	tty->driver_data = info;
-	info->tty = tty;
+	tty_port_tty_set(&info->tport, tty);
 
 	/*
 	 * Start up serial port
 	 */
-	retval = startup(info);
+	retval = startup(info, tty);
 	if (retval)
 		return retval;
 
-	return block_til_ready(tty, filp, info);
+	return tty_port_block_til_ready(&info->tport, tty, filp);
 }
 
 /* Finally, routines used to initialize the serial driver. */
@@ -1235,11 +1158,15 @@
 	.set_ldisc = rs_set_ldisc,
 };
 
+static const struct tty_port_operations rs_port_ops = {
+};
+
 /* rs_init inits the driver */
 static int __init
 rs68328_init(void)
 {
-	int flags, i;
+	unsigned long flags;
+	int i;
 	struct m68k_serial *info;
 
 	serial_driver = alloc_tty_driver(NR_PORTS);
@@ -1273,19 +1200,13 @@
 	for(i=0;i<NR_PORTS;i++) {
 
 	    info = &m68k_soft[i];
+	    tty_port_init(&info->tport);
+	    info->tport.ops = &rs_port_ops;
 	    info->magic = SERIAL_MAGIC;
 	    info->port = (int) &uart_addr[i];
-	    info->tty = NULL;
 	    info->irq = uart_irqs[i];
 	    info->custom_divisor = 16;
-	    info->close_delay = 50;
-	    info->closing_wait = 3000;
 	    info->x_char = 0;
-	    info->event = 0;
-	    info->count = 0;
-	    info->blocked_open = 0;
-	    init_waitqueue_head(&info->open_wait);
-	    init_waitqueue_head(&info->close_wait);
 	    info->line = i;
 	    info->is_cons = 1; /* Means shortcuts work */
 	    
diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h
deleted file mode 100644
index 3d2faab..0000000
--- a/drivers/tty/serial/68328serial.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* 68328serial.h: Definitions for the mc68328 serial driver.
- *
- * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
- * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
- * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
- *
- * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
- */
-
-#ifndef _MC683XX_SERIAL_H
-#define _MC683XX_SERIAL_H
-
-
-struct serial_struct {
-	int	type;
-	int	line;
-	int	port;
-	int	irq;
-	int	flags;
-	int	xmit_fifo_size;
-	int	custom_divisor;
-	int	baud_base;
-	unsigned short	close_delay;
-	char	reserved_char[2];
-	int	hub6;  /* FIXME: We don't have AT&T Hub6 boards! */
-	unsigned short	closing_wait; /* time to wait before closing */
-	unsigned short	closing_wait2; /* no longer used... */
-	int	reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define S_CLOSING_WAIT_INF	0
-#define S_CLOSING_WAIT_NONE	65535
-
-/*
- * Definitions for S_struct (and serial_struct) flags field
- */
-#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
-				   on the callout port */
-#define S_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
-#define S_SAK	0x0004	/* Secure Attention Key (Orange book) */
-#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define S_SPD_MASK	0x0030
-#define S_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
-
-#define S_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
-#define S_SPD_CUST	0x0030  /* Use user-specified divisor */
-
-#define S_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
-#define S_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define S_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define S_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define S_FLAGS	0x0FFF	/* Possible legal S flags */
-#define S_USR_MASK 0x0430	/* Legal flags that non-privileged
-				 * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define S_INITIALIZED	0x80000000 /* Serial port was initialized */
-#define S_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
-#define S_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
-#define S_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
-#define S_CLOSING		0x08000000 /* Serial port is closing */
-#define S_CTS_FLOW		0x04000000 /* Do CTS flow control */
-#define S_CHECK_CD		0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-
-/*
- * I believe this is the optimal setting that reduces the number of interrupts.
- * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
- * if that bothers you), but in most cases it will not, since we try to 
- * transmit characters every time rs_interrupt is called. Thus, quite often
- * you'll see that a receive interrupt occures before the transmit one.
- *                                  -- Vladimir Gurevich
- */
-#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-
-/*
- * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
- * "Old data interrupt" which occures whenever the data stay in the FIFO
- * longer than 30 bits time. This allows us to use FIFO without compromising
- * latency. '328 does not have this feature and without the real  328-based
- * board I would assume that RXRE is the safest setting.
- *
- * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
- * interrupts. RXFE (receive queue full) causes the system to lose data
- * at least at 115200 baud
- *
- * If your board is busy doing other stuff, you might consider to use
- * RXRE (data ready intrrupt) instead.
- *
- * The other option is to make these INTR masks run-time configurable, so
- * that people can dynamically adapt them according to the current usage.
- *                                  -- Vladimir Gurevich
- */
-
-/* (es) */
-#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
-#elif defined(CONFIG_M68328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
-#else
-#error Please, define the Rx interrupt events for your CPU
-#endif
-/* (/es) */
-
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct m68k_serial {
-	char soft_carrier;  /* Use soft carrier on this channel */
-	char break_abort;   /* Is serial console in, so process brk/abrt */
-	char is_cons;       /* Is this our console. */
-
-	/* We need to know the current clock divisor
-	 * to read the bps rate the chip has currently
-	 * loaded.
-	 */
-	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
-	int baud;
-	int			magic;
-	int			baud_base;
-	int			port;
-	int			irq;
-	int			flags; 		/* defined in tty.h */
-	int			type; 		/* UART type */
-	struct tty_struct 	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			timeout;
-	int			xmit_fifo_size;
-	int			custom_divisor;
-	int			x_char;	/* xon/xoff character */
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
-	unsigned long		event;
-	unsigned long		last_active;
-	int			line;
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP	0
-
-/* 
- * Define the number of ports supported and their irqs.
- */
-#define NR_PORTS 1
-#define UART_IRQ_DEFNS {UART_IRQ_NUM}
-
-#endif /* __KERNEL__ */
-#endif /* !(_MC683XX_SERIAL_H) */
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 5c27f7e..47d061b 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -284,7 +284,20 @@
 	},
 };
 
-#if defined(CONFIG_MIPS_ALCHEMY)
+/* Uart divisor latch read */
+static int default_serial_dl_read(struct uart_8250_port *up)
+{
+	return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static void default_serial_dl_write(struct uart_8250_port *up, int value)
+{
+	serial_out(up, UART_DLL, value & 0xff);
+	serial_out(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_MIPS_ALCHEMY
 
 /* Au1x00 UART hardware has a weird register layout */
 static const u8 au_io_in_map[] = {
@@ -305,22 +318,32 @@
 	[UART_MCR] = 6,
 };
 
-/* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
+static unsigned int au_serial_in(struct uart_port *p, int offset)
 {
-	if (p->iotype != UPIO_AU)
-		return offset;
-	return au_io_in_map[offset];
+	offset = au_io_in_map[offset] << p->regshift;
+	return __raw_readl(p->membase + offset);
 }
 
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
+static void au_serial_out(struct uart_port *p, int offset, int value)
 {
-	if (p->iotype != UPIO_AU)
-		return offset;
-	return au_io_out_map[offset];
+	offset = au_io_out_map[offset] << p->regshift;
+	__raw_writel(value, p->membase + offset);
 }
 
-#elif defined(CONFIG_SERIAL_8250_RM9K)
+/* Au1x00 haven't got a standard divisor latch */
+static int au_serial_dl_read(struct uart_8250_port *up)
+{
+	return __raw_readl(up->port.membase + 0x28);
+}
+
+static void au_serial_dl_write(struct uart_8250_port *up, int value)
+{
+	__raw_writel(value, up->port.membase + 0x28);
+}
+
+#endif
+
+#ifdef CONFIG_SERIAL_8250_RM9K
 
 static const u8
 	regmap_in[8] = {
@@ -344,87 +367,79 @@
 		[UART_SCR]	= 0x2c
 	};
 
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
+static unsigned int rm9k_serial_in(struct uart_port *p, int offset)
 {
-	if (p->iotype != UPIO_RM9000)
-		return offset;
-	return regmap_in[offset];
+	offset = regmap_in[offset] << p->regshift;
+	return readl(p->membase + offset);
 }
 
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
+static void rm9k_serial_out(struct uart_port *p, int offset, int value)
 {
-	if (p->iotype != UPIO_RM9000)
-		return offset;
-	return regmap_out[offset];
+	offset = regmap_out[offset] << p->regshift;
+	writel(value, p->membase + offset);
 }
 
-#else
+static int rm9k_serial_dl_read(struct uart_8250_port *up)
+{
+	return ((__raw_readl(up->port.membase + 0x10) << 8) |
+		(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff;
+}
 
-/* sane hardware needs no mapping */
-#define map_8250_in_reg(up, offset) (offset)
-#define map_8250_out_reg(up, offset) (offset)
+static void rm9k_serial_dl_write(struct uart_8250_port *up, int value)
+{
+	__raw_writel(value, up->port.membase + 0x08);
+	__raw_writel(value >> 8, up->port.membase + 0x10);
+}
 
 #endif
 
 static unsigned int hub6_serial_in(struct uart_port *p, int offset)
 {
-	offset = map_8250_in_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	outb(p->hub6 - 1 + offset, p->iobase);
 	return inb(p->iobase + 1);
 }
 
 static void hub6_serial_out(struct uart_port *p, int offset, int value)
 {
-	offset = map_8250_out_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	outb(p->hub6 - 1 + offset, p->iobase);
 	outb(value, p->iobase + 1);
 }
 
 static unsigned int mem_serial_in(struct uart_port *p, int offset)
 {
-	offset = map_8250_in_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	return readb(p->membase + offset);
 }
 
 static void mem_serial_out(struct uart_port *p, int offset, int value)
 {
-	offset = map_8250_out_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	writeb(value, p->membase + offset);
 }
 
 static void mem32_serial_out(struct uart_port *p, int offset, int value)
 {
-	offset = map_8250_out_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	writel(value, p->membase + offset);
 }
 
 static unsigned int mem32_serial_in(struct uart_port *p, int offset)
 {
-	offset = map_8250_in_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	return readl(p->membase + offset);
 }
 
-static unsigned int au_serial_in(struct uart_port *p, int offset)
-{
-	offset = map_8250_in_reg(p, offset) << p->regshift;
-	return __raw_readl(p->membase + offset);
-}
-
-static void au_serial_out(struct uart_port *p, int offset, int value)
-{
-	offset = map_8250_out_reg(p, offset) << p->regshift;
-	__raw_writel(value, p->membase + offset);
-}
-
 static unsigned int io_serial_in(struct uart_port *p, int offset)
 {
-	offset = map_8250_in_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	return inb(p->iobase + offset);
 }
 
 static void io_serial_out(struct uart_port *p, int offset, int value)
 {
-	offset = map_8250_out_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	outb(value, p->iobase + offset);
 }
 
@@ -434,6 +449,10 @@
 {
 	struct uart_8250_port *up =
 		container_of(p, struct uart_8250_port, port);
+
+	up->dl_read = default_serial_dl_read;
+	up->dl_write = default_serial_dl_write;
+
 	switch (p->iotype) {
 	case UPIO_HUB6:
 		p->serial_in = hub6_serial_in;
@@ -445,16 +464,28 @@
 		p->serial_out = mem_serial_out;
 		break;
 
-	case UPIO_RM9000:
 	case UPIO_MEM32:
 		p->serial_in = mem32_serial_in;
 		p->serial_out = mem32_serial_out;
 		break;
 
+#ifdef CONFIG_SERIAL_8250_RM9K
+	case UPIO_RM9000:
+		p->serial_in = rm9k_serial_in;
+		p->serial_out = rm9k_serial_out;
+		up->dl_read = rm9k_serial_dl_read;
+		up->dl_write = rm9k_serial_dl_write;
+		break;
+#endif
+
+#ifdef CONFIG_MIPS_ALCHEMY
 	case UPIO_AU:
 		p->serial_in = au_serial_in;
 		p->serial_out = au_serial_out;
+		up->dl_read = au_serial_dl_read;
+		up->dl_write = au_serial_dl_write;
 		break;
+#endif
 
 	default:
 		p->serial_in = io_serial_in;
@@ -481,59 +512,6 @@
 	}
 }
 
-/* Uart divisor latch read */
-static inline int _serial_dl_read(struct uart_8250_port *up)
-{
-	return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
-}
-
-/* Uart divisor latch write */
-static inline void _serial_dl_write(struct uart_8250_port *up, int value)
-{
-	serial_out(up, UART_DLL, value & 0xff);
-	serial_out(up, UART_DLM, value >> 8 & 0xff);
-}
-
-#if defined(CONFIG_MIPS_ALCHEMY)
-/* Au1x00 haven't got a standard divisor latch */
-static int serial_dl_read(struct uart_8250_port *up)
-{
-	if (up->port.iotype == UPIO_AU)
-		return __raw_readl(up->port.membase + 0x28);
-	else
-		return _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
-	if (up->port.iotype == UPIO_AU)
-		__raw_writel(value, up->port.membase + 0x28);
-	else
-		_serial_dl_write(up, value);
-}
-#elif defined(CONFIG_SERIAL_8250_RM9K)
-static int serial_dl_read(struct uart_8250_port *up)
-{
-	return	(up->port.iotype == UPIO_RM9000) ?
-		(((__raw_readl(up->port.membase + 0x10) << 8) |
-		(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
-		_serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
-	if (up->port.iotype == UPIO_RM9000) {
-		__raw_writel(value, up->port.membase + 0x08);
-		__raw_writel(value >> 8, up->port.membase + 0x10);
-	} else {
-		_serial_dl_write(up, value);
-	}
-}
-#else
-#define serial_dl_read(up) _serial_dl_read(up)
-#define serial_dl_write(up, value) _serial_dl_write(up, value)
-#endif
-
 /*
  * For the 16C950
  */
@@ -568,6 +546,16 @@
 	}
 }
 
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
+{
+	unsigned char fcr;
+
+	serial8250_clear_fifos(p);
+	fcr = uart_config[p->port.type].fcr;
+	serial_out(p, UART_FCR, fcr);
+}
+EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
+
 /*
  * IER sleep support.  UARTs which have EFRs need the "extended
  * capability" bit enabled.  Note that on XR16C850s, we need to
@@ -1332,27 +1320,6 @@
 }
 
 /*
- * Clear the Tegra rx fifo after a break
- *
- * FIXME: This needs to become a port specific callback once we have a
- * framework for this
- */
-static void clear_rx_fifo(struct uart_8250_port *up)
-{
-	unsigned int status, tmout = 10000;
-	do {
-		status = serial_in(up, UART_LSR);
-		if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
-			status = serial_in(up, UART_RX);
-		else
-			break;
-		if (--tmout == 0)
-			break;
-		udelay(1);
-	} while (1);
-}
-
-/*
  * serial8250_rx_chars: processes according to the passed in LSR
  * value, and returns the remaining LSR bits not handled
  * by this Rx routine.
@@ -1386,20 +1353,10 @@
 		up->lsr_saved_flags = 0;
 
 		if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
-			/*
-			 * For statistics only
-			 */
 			if (lsr & UART_LSR_BI) {
 				lsr &= ~(UART_LSR_FE | UART_LSR_PE);
 				port->icount.brk++;
 				/*
-				 * If tegra port then clear the rx fifo to
-				 * accept another break/character.
-				 */
-				if (port->type == PORT_TEGRA)
-					clear_rx_fifo(up);
-
-				/*
 				 * We do the SysRQ and SAK checking
 				 * here because otherwise the break
 				 * may get masked by ignore_status_mask
@@ -2280,10 +2237,11 @@
 		quot++;
 
 	if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
-		if (baud < 2400)
-			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
-		else
-			fcr = uart_config[port->type].fcr;
+		fcr = uart_config[port->type].fcr;
+		if (baud < 2400) {
+			fcr &= ~UART_FCR_TRIGGER_MASK;
+			fcr |= UART_FCR_TRIGGER_1;
+		}
 	}
 
 	/*
@@ -3037,6 +2995,7 @@
 		port.serial_in		= p->serial_in;
 		port.serial_out		= p->serial_out;
 		port.handle_irq		= p->handle_irq;
+		port.handle_break	= p->handle_break;
 		port.set_termios	= p->set_termios;
 		port.pm			= p->pm;
 		port.dev		= &dev->dev;
@@ -3153,6 +3112,84 @@
 }
 
 /**
+ *	serial8250_register_8250_port - register a serial port
+ *	@port: serial port template
+ *
+ *	Configure the serial port specified by the request. If the
+ *	port exists and is in use, it is hung up and unregistered
+ *	first.
+ *
+ *	The port is then probed and if necessary the IRQ is autodetected
+ *	If this fails an error is returned.
+ *
+ *	On success the port is ready to use and the line number is returned.
+ */
+int serial8250_register_8250_port(struct uart_8250_port *up)
+{
+	struct uart_8250_port *uart;
+	int ret = -ENOSPC;
+
+	if (up->port.uartclk == 0)
+		return -EINVAL;
+
+	mutex_lock(&serial_mutex);
+
+	uart = serial8250_find_match_or_unused(&up->port);
+	if (uart) {
+		uart_remove_one_port(&serial8250_reg, &uart->port);
+
+		uart->port.iobase       = up->port.iobase;
+		uart->port.membase      = up->port.membase;
+		uart->port.irq          = up->port.irq;
+		uart->port.irqflags     = up->port.irqflags;
+		uart->port.uartclk      = up->port.uartclk;
+		uart->port.fifosize     = up->port.fifosize;
+		uart->port.regshift     = up->port.regshift;
+		uart->port.iotype       = up->port.iotype;
+		uart->port.flags        = up->port.flags | UPF_BOOT_AUTOCONF;
+		uart->port.mapbase      = up->port.mapbase;
+		uart->port.private_data = up->port.private_data;
+		if (up->port.dev)
+			uart->port.dev = up->port.dev;
+
+		if (up->port.flags & UPF_FIXED_TYPE)
+			serial8250_init_fixed_type_port(uart, up->port.type);
+
+		set_io_from_upio(&uart->port);
+		/* Possibly override default I/O functions.  */
+		if (up->port.serial_in)
+			uart->port.serial_in = up->port.serial_in;
+		if (up->port.serial_out)
+			uart->port.serial_out = up->port.serial_out;
+		if (up->port.handle_irq)
+			uart->port.handle_irq = up->port.handle_irq;
+		/*  Possibly override set_termios call */
+		if (up->port.set_termios)
+			uart->port.set_termios = up->port.set_termios;
+		if (up->port.pm)
+			uart->port.pm = up->port.pm;
+		if (up->port.handle_break)
+			uart->port.handle_break = up->port.handle_break;
+		if (up->dl_read)
+			uart->dl_read = up->dl_read;
+		if (up->dl_write)
+			uart->dl_write = up->dl_write;
+
+		if (serial8250_isa_config != NULL)
+			serial8250_isa_config(0, &uart->port,
+					&uart->capabilities);
+
+		ret = uart_add_one_port(&serial8250_reg, &uart->port);
+		if (ret == 0)
+			ret = uart->port.line;
+	}
+	mutex_unlock(&serial_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(serial8250_register_8250_port);
+
+/**
  *	serial8250_register_port - register a serial port
  *	@port: serial port template
  *
@@ -3167,60 +3204,11 @@
  */
 int serial8250_register_port(struct uart_port *port)
 {
-	struct uart_8250_port *uart;
-	int ret = -ENOSPC;
+	struct uart_8250_port up;
 
-	if (port->uartclk == 0)
-		return -EINVAL;
-
-	mutex_lock(&serial_mutex);
-
-	uart = serial8250_find_match_or_unused(port);
-	if (uart) {
-		uart_remove_one_port(&serial8250_reg, &uart->port);
-
-		uart->port.iobase       = port->iobase;
-		uart->port.membase      = port->membase;
-		uart->port.irq          = port->irq;
-		uart->port.irqflags     = port->irqflags;
-		uart->port.uartclk      = port->uartclk;
-		uart->port.fifosize     = port->fifosize;
-		uart->port.regshift     = port->regshift;
-		uart->port.iotype       = port->iotype;
-		uart->port.flags        = port->flags | UPF_BOOT_AUTOCONF;
-		uart->port.mapbase      = port->mapbase;
-		uart->port.private_data = port->private_data;
-		if (port->dev)
-			uart->port.dev = port->dev;
-
-		if (port->flags & UPF_FIXED_TYPE)
-			serial8250_init_fixed_type_port(uart, port->type);
-
-		set_io_from_upio(&uart->port);
-		/* Possibly override default I/O functions.  */
-		if (port->serial_in)
-			uart->port.serial_in = port->serial_in;
-		if (port->serial_out)
-			uart->port.serial_out = port->serial_out;
-		if (port->handle_irq)
-			uart->port.handle_irq = port->handle_irq;
-		/*  Possibly override set_termios call */
-		if (port->set_termios)
-			uart->port.set_termios = port->set_termios;
-		if (port->pm)
-			uart->port.pm = port->pm;
-
-		if (serial8250_isa_config != NULL)
-			serial8250_isa_config(0, &uart->port,
-					&uart->capabilities);
-
-		ret = uart_add_one_port(&serial8250_reg, &uart->port);
-		if (ret == 0)
-			ret = uart->port.line;
-	}
-	mutex_unlock(&serial_mutex);
-
-	return ret;
+	memset(&up, 0, sizeof(up));
+	memcpy(&up.port, port, sizeof(*port));
+	return serial8250_register_8250_port(&up);
 }
 EXPORT_SYMBOL(serial8250_register_port);
 
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 2868a1d..f9719d1 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -37,6 +37,10 @@
 	unsigned char		lsr_saved_flags;
 #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
 	unsigned char		msr_saved_flags;
+
+	/* 8250 specific callbacks */
+	int			(*dl_read)(struct uart_8250_port *);
+	void			(*dl_write)(struct uart_8250_port *, int);
 };
 
 struct old_serial_port {
@@ -96,6 +100,18 @@
 	up->port.serial_out(&up->port, offset, value);
 }
 
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
+
+static inline int serial_dl_read(struct uart_8250_port *up)
+{
+	return up->dl_read(up);
+}
+
+static inline void serial_dl_write(struct uart_8250_port *up, int value)
+{
+	up->dl_write(up, value);
+}
+
 #if defined(__alpha__) && !defined(CONFIG_PCI)
 /*
  * Digital did something really horribly wrong with the OUT1 and OUT2
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
new file mode 100644
index 0000000..3a0363e
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -0,0 +1,186 @@
+/*
+ * Renesas Emma Mobile 8250 driver
+ *
+ *  Copyright (C) 2012 Magnus Damm
+ *
+ * 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
+ *
+ * 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/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include "8250.h"
+
+#define UART_DLL_EM 9
+#define UART_DLM_EM 10
+
+struct serial8250_em_priv {
+	struct clk *sclk;
+	int line;
+};
+
+static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
+{
+	switch (offset) {
+	case UART_TX: /* TX @ 0x00 */
+		writeb(value, p->membase);
+		break;
+	case UART_FCR: /* FCR @ 0x0c (+1) */
+	case UART_LCR: /* LCR @ 0x10 (+1) */
+	case UART_MCR: /* MCR @ 0x14 (+1) */
+	case UART_SCR: /* SCR @ 0x20 (+1) */
+		writel(value, p->membase + ((offset + 1) << 2));
+		break;
+	case UART_IER: /* IER @ 0x04 */
+		value &= 0x0f; /* only 4 valid bits - not Xscale */
+		/* fall-through */
+	case UART_DLL_EM: /* DLL @ 0x24 (+9) */
+	case UART_DLM_EM: /* DLM @ 0x28 (+9) */
+		writel(value, p->membase + (offset << 2));
+	}
+}
+
+static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset)
+{
+	switch (offset) {
+	case UART_RX: /* RX @ 0x00 */
+		return readb(p->membase);
+	case UART_MCR: /* MCR @ 0x14 (+1) */
+	case UART_LSR: /* LSR @ 0x18 (+1) */
+	case UART_MSR: /* MSR @ 0x1c (+1) */
+	case UART_SCR: /* SCR @ 0x20 (+1) */
+		return readl(p->membase + ((offset + 1) << 2));
+	case UART_IER: /* IER @ 0x04 */
+	case UART_IIR: /* IIR @ 0x08 */
+	case UART_DLL_EM: /* DLL @ 0x24 (+9) */
+	case UART_DLM_EM: /* DLM @ 0x28 (+9) */
+		return readl(p->membase + (offset << 2));
+	}
+	return 0;
+}
+
+static int serial8250_em_serial_dl_read(struct uart_8250_port *up)
+{
+	return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8;
+}
+
+static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
+{
+	serial_out(up, UART_DLL_EM, value & 0xff);
+	serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
+}
+
+static int __devinit serial8250_em_probe(struct platform_device *pdev)
+{
+	struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	struct serial8250_em_priv *priv;
+	struct uart_8250_port up;
+	int ret = -EINVAL;
+
+	if (!regs || !irq) {
+		dev_err(&pdev->dev, "missing registers or irq\n");
+		goto err0;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "unable to allocate private data\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	priv->sclk = clk_get(&pdev->dev, "sclk");
+	if (IS_ERR(priv->sclk)) {
+		dev_err(&pdev->dev, "unable to get clock\n");
+		ret = PTR_ERR(priv->sclk);
+		goto err1;
+	}
+
+	memset(&up, 0, sizeof(up));
+	up.port.mapbase = regs->start;
+	up.port.irq = irq->start;
+	up.port.type = PORT_UNKNOWN;
+	up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+	up.port.dev = &pdev->dev;
+	up.port.private_data = priv;
+
+	clk_enable(priv->sclk);
+	up.port.uartclk = clk_get_rate(priv->sclk);
+
+	up.port.iotype = UPIO_MEM32;
+	up.port.serial_in = serial8250_em_serial_in;
+	up.port.serial_out = serial8250_em_serial_out;
+	up.dl_read = serial8250_em_serial_dl_read;
+	up.dl_write = serial8250_em_serial_dl_write;
+
+	ret = serial8250_register_8250_port(&up);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "unable to register 8250 port\n");
+		goto err2;
+	}
+
+	priv->line = ret;
+	platform_set_drvdata(pdev, priv);
+	return 0;
+
+ err2:
+	clk_disable(priv->sclk);
+	clk_put(priv->sclk);
+ err1:
+	kfree(priv);
+ err0:
+	return ret;
+}
+
+static int __devexit serial8250_em_remove(struct platform_device *pdev)
+{
+	struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
+
+	serial8250_unregister_port(priv->line);
+	clk_disable(priv->sclk);
+	clk_put(priv->sclk);
+	kfree(priv);
+	return 0;
+}
+
+static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = {
+	{ .compatible = "renesas,em-uart", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, serial8250_em_dt_ids);
+
+static struct platform_driver serial8250_em_platform_driver = {
+	.driver = {
+		.name		= "serial8250-em",
+		.of_match_table = serial8250_em_dt_ids,
+		.owner		= THIS_MODULE,
+	},
+	.probe			= serial8250_em_probe,
+	.remove			= __devexit_p(serial8250_em_remove),
+};
+
+module_platform_driver(serial8250_em_platform_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_mca.c b/drivers/tty/serial/8250/8250_mca.c
deleted file mode 100644
index d20abf0..0000000
--- a/drivers/tty/serial/8250/8250_mca.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.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.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/mca.h>
-#include <linux/serial_8250.h>
-
-/*
- * FIXME: Should we be doing AUTO_IRQ here?
- */
-#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
-#define MCA_FLAGS	UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ
-#else
-#define MCA_FLAGS	UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
-#endif
-
-#define PORT(_base,_irq)			\
-	{					\
-		.iobase		= _base,	\
-		.irq		= _irq,		\
-		.uartclk	= 1843200,	\
-		.iotype		= UPIO_PORT,	\
-		.flags		= MCA_FLAGS,	\
-	}
-
-static struct plat_serial8250_port mca_data[] = {
-	PORT(0x3220, 3),
-	PORT(0x3228, 3),
-	PORT(0x4220, 3),
-	PORT(0x4228, 3),
-	PORT(0x5220, 3),
-	PORT(0x5228, 3),
-	{ },
-};
-
-static struct platform_device mca_device = {
-	.name			= "serial8250",
-	.id			= PLAT8250_DEV_MCA,
-	.dev			= {
-		.platform_data	= mca_data,
-	},
-};
-
-static int __init mca_init(void)
-{
-	if (!MCA_bus)
-		return -ENODEV;
-	return platform_device_register(&mca_device);
-}
-
-module_init(mca_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for MCA ports");
-MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 858dca8..28e7c7c 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/tty.h>
+#include <linux/serial_reg.h>
 #include <linux/serial_core.h>
 #include <linux/8250_pci.h>
 #include <linux/bitops.h>
@@ -1092,11 +1093,49 @@
 	return pci_default_setup(priv, board, port, idx);
 }
 
+static void kt_handle_break(struct uart_port *p)
+{
+	struct uart_8250_port *up =
+		container_of(p, struct uart_8250_port, port);
+	/*
+	 * On receipt of a BI, serial device in Intel ME (Intel
+	 * management engine) needs to have its fifos cleared for sane
+	 * SOL (Serial Over Lan) output.
+	 */
+	serial8250_clear_and_reinit_fifos(up);
+}
+
+static unsigned int kt_serial_in(struct uart_port *p, int offset)
+{
+	struct uart_8250_port *up =
+		container_of(p, struct uart_8250_port, port);
+	unsigned int val;
+
+	/*
+	 * When the Intel ME (management engine) gets reset its serial
+	 * port registers could return 0 momentarily.  Functions like
+	 * serial8250_console_write, read and save the IER, perform
+	 * some operation and then restore it.  In order to avoid
+	 * setting IER register inadvertently to 0, if the value read
+	 * is 0, double check with ier value in uart_8250_port and use
+	 * that instead.  up->ier should be the same value as what is
+	 * currently configured.
+	 */
+	val = inb(p->iobase + offset);
+	if (offset == UART_IER) {
+		if (val == 0)
+			val = up->ier;
+	}
+	return val;
+}
+
 static int kt_serial_setup(struct serial_private *priv,
 			   const struct pciserial_board *board,
 			   struct uart_port *port, int idx)
 {
 	port->flags |= UPF_BUG_THRE;
+	port->serial_in = kt_serial_in;
+	port->handle_break = kt_handle_break;
 	return skip_tx_en_setup(priv, board, port, idx);
 }
 
@@ -1609,54 +1648,72 @@
 	{
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.device         = 0x8811,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 	},
 	{
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.device         = 0x8812,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 	},
 	{
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.device         = 0x8813,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 	},
 	{
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.device         = 0x8814,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 	},
 	{
 		.vendor         = 0x10DB,
 		.device         = 0x8027,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 	},
 	{
 		.vendor         = 0x10DB,
 		.device         = 0x8028,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 	},
 	{
 		.vendor         = 0x10DB,
 		.device         = 0x8029,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 	},
 	{
 		.vendor         = 0x10DB,
 		.device         = 0x800C,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 	},
 	{
 		.vendor         = 0x10DB,
 		.device         = 0x800D,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 	},
@@ -2775,6 +2832,12 @@
 	for (i = 0; i < priv->nr; i++)
 		if (priv->line[i] >= 0)
 			serial8250_suspend_port(priv->line[i]);
+
+	/*
+	 * Ensure that every init quirk is properly torn down
+	 */
+	if (priv->quirk->exit)
+		priv->quirk->exit(priv->dev);
 }
 EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
 
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 591f801..a27dd05 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -241,15 +241,6 @@
 	help
 	  ::: To be written :::
 
-config SERIAL_8250_MCA
-	tristate "Support 8250-type ports on MCA buses"
-	depends on SERIAL_8250 != n && MCA
-	help
-	  Say Y here if you have a MCA serial ports.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called 8250_mca.
-
 config SERIAL_8250_ACORN
 	tristate "Acorn expansion card serial port support"
 	depends on ARCH_ACORN && SERIAL_8250
@@ -278,3 +269,11 @@
 	help
 	  Selecting this option will enable handling of the extra features
 	  present in the Synopsys DesignWare APB UART.
+
+config SERIAL_8250_EM
+	tristate "Support for Emma Mobile intergrated serial port"
+	depends on SERIAL_8250 && ARM && HAVE_CLK
+	help
+	  Selecting this option will add support for the integrated serial
+	  port hardware found on the Emma Mobile line of processors.
+	  If unsure, say N.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 867bba7..d7533c7 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -15,6 +15,6 @@
 obj-$(CONFIG_SERIAL_8250_BOCA)		+= 8250_boca.o
 obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554)	+= 8250_exar_st16c554.o
 obj-$(CONFIG_SERIAL_8250_HUB6)		+= 8250_hub6.o
-obj-$(CONFIG_SERIAL_8250_MCA)		+= 8250_mca.o
 obj-$(CONFIG_SERIAL_8250_FSL)		+= 8250_fsl.o
 obj-$(CONFIG_SERIAL_8250_DW)		+= 8250_dw.o
+obj-$(CONFIG_SERIAL_8250_EM)		+= 8250_em.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 3d569cd..4ad721f 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -52,6 +52,7 @@
 #include <linux/scatterlist.h>
 #include <linux/delay.h>
 #include <linux/types.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <asm/io.h>
 #include <asm/sizes.h>
@@ -67,30 +68,6 @@
 #define UART_DR_ERROR		(UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
 #define UART_DUMMY_DR_RX	(1 << 16)
 
-
-#define UART_WA_SAVE_NR 14
-
-static void pl011_lockup_wa(unsigned long data);
-static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
-	ST_UART011_DMAWM,
-	ST_UART011_TIMEOUT,
-	ST_UART011_LCRH_RX,
-	UART011_IBRD,
-	UART011_FBRD,
-	ST_UART011_LCRH_TX,
-	UART011_IFLS,
-	ST_UART011_XFCR,
-	ST_UART011_XON1,
-	ST_UART011_XON2,
-	ST_UART011_XOFF1,
-	ST_UART011_XOFF2,
-	UART011_CR,
-	UART011_IMSC
-};
-
-static u32 uart_wa_regdata[UART_WA_SAVE_NR];
-static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
-
 /* There is by now at least one vendor with differing details, so handle it */
 struct vendor_data {
 	unsigned int		ifls;
@@ -100,6 +77,7 @@
 	bool			oversampling;
 	bool			interrupt_may_hang;   /* vendor-specific */
 	bool			dma_threshold;
+	bool			cts_event_workaround;
 };
 
 static struct vendor_data vendor_arm = {
@@ -109,6 +87,7 @@
 	.lcrh_rx		= UART011_LCRH,
 	.oversampling		= false,
 	.dma_threshold		= false,
+	.cts_event_workaround	= false,
 };
 
 static struct vendor_data vendor_st = {
@@ -119,6 +98,7 @@
 	.oversampling		= true,
 	.interrupt_may_hang	= true,
 	.dma_threshold		= true,
+	.cts_event_workaround	= true,
 };
 
 static struct uart_amba_port *amba_ports[UART_NR];
@@ -1054,69 +1034,6 @@
 #define pl011_dma_flush_buffer	NULL
 #endif
 
-
-/*
- * pl011_lockup_wa
- * This workaround aims to break the deadlock situation
- * when after long transfer over uart in hardware flow
- * control, uart interrupt registers cannot be cleared.
- * Hence uart transfer gets blocked.
- *
- * It is seen that during such deadlock condition ICR
- * don't get cleared even on multiple write. This leads
- * pass_counter to decrease and finally reach zero. This
- * can be taken as trigger point to run this UART_BT_WA.
- *
- */
-static void pl011_lockup_wa(unsigned long data)
-{
-	struct uart_amba_port *uap = amba_ports[0];
-	void __iomem *base = uap->port.membase;
-	struct circ_buf *xmit = &uap->port.state->xmit;
-	struct tty_struct *tty = uap->port.state->port.tty;
-	int buf_empty_retries = 200;
-	int loop;
-
-	/* Stop HCI layer from submitting data for tx */
-	tty->hw_stopped = 1;
-	while (!uart_circ_empty(xmit)) {
-		if (buf_empty_retries-- == 0)
-			break;
-		udelay(100);
-	}
-
-	/* Backup registers */
-	for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
-		uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
-
-	/* Disable UART so that FIFO data is flushed out */
-	writew(0x00, uap->port.membase + UART011_CR);
-
-	/* Soft reset UART module */
-	if (uap->port.dev->platform_data) {
-		struct amba_pl011_data *plat;
-
-		plat = uap->port.dev->platform_data;
-		if (plat->reset)
-			plat->reset();
-	}
-
-	/* Restore registers */
-	for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
-		writew(uart_wa_regdata[loop] ,
-				uap->port.membase + uart_wa_reg[loop]);
-
-	/* Initialise the old status of the modem signals */
-	uap->old_status = readw(uap->port.membase + UART01x_FR) &
-		UART01x_FR_MODEM_ANY;
-
-	if (readl(base + UART011_MIS) & 0x2)
-		printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
-
-	/* Start Tx/Rx */
-	tty->hw_stopped = 0;
-}
-
 static void pl011_stop_tx(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1245,12 +1162,26 @@
 	unsigned long flags;
 	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
 	int handled = 0;
+	unsigned int dummy_read;
 
 	spin_lock_irqsave(&uap->port.lock, flags);
 
 	status = readw(uap->port.membase + UART011_MIS);
 	if (status) {
 		do {
+			if (uap->vendor->cts_event_workaround) {
+				/* workaround to make sure that all bits are unlocked.. */
+				writew(0x00, uap->port.membase + UART011_ICR);
+
+				/*
+				 * WA: introduce 26ns(1 uart clk) delay before W1C;
+				 * single apb access will incur 2 pclk(133.12Mhz) delay,
+				 * so add 2 dummy reads
+				 */
+				dummy_read = readw(uap->port.membase + UART011_ICR);
+				dummy_read = readw(uap->port.membase + UART011_ICR);
+			}
+
 			writew(status & ~(UART011_TXIS|UART011_RTIS|
 					  UART011_RXIS),
 			       uap->port.membase + UART011_ICR);
@@ -1267,11 +1198,8 @@
 			if (status & UART011_TXIS)
 				pl011_tx_chars(uap);
 
-			if (pass_counter-- == 0) {
-				if (uap->interrupt_may_hang)
-					tasklet_schedule(&pl011_lockup_tlet);
+			if (pass_counter-- == 0)
 				break;
-			}
 
 			status = readw(uap->port.membase + UART011_MIS);
 		} while (status != 0);
@@ -1916,6 +1844,7 @@
 {
 	struct uart_amba_port *uap;
 	struct vendor_data *vendor = id->data;
+	struct pinctrl *pinctrl;
 	void __iomem *base;
 	int i, ret;
 
@@ -1940,6 +1869,12 @@
 		goto free;
 	}
 
+	pinctrl = devm_pinctrl_get_select_default(&dev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		goto unmap;
+	}
+
 	uap->clk = clk_get(&dev->dev, NULL);
 	if (IS_ERR(uap->clk)) {
 		ret = PTR_ERR(uap->clk);
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 5832fde..bd97db2 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -1,7 +1,7 @@
 /*
  * Blackfin On-Chip Serial Driver
  *
- * Copyright 2006-2010 Analog Devices Inc.
+ * Copyright 2006-2011 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
@@ -35,10 +35,6 @@
 #include <asm/portmux.h>
 #include <asm/cacheflush.h>
 #include <asm/dma.h>
-
-#define port_membase(uart)     (((struct bfin_serial_port *)(uart))->port.membase)
-#define get_lsr_cache(uart)    (((struct bfin_serial_port *)(uart))->lsr)
-#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
 #include <asm/bfin_serial.h>
 
 #ifdef CONFIG_SERIAL_BFIN_MODULE
@@ -166,7 +162,7 @@
 	uart->tx_count = 0;
 	uart->tx_done = 1;
 #else
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
 	/* Clear TFI bit */
 	UART_PUT_LSR(uart, TFI);
 #endif
@@ -337,7 +333,7 @@
 	struct circ_buf *xmit = &uart->port.state->xmit;
 
 	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
 		/* Clear TFI bit */
 		UART_PUT_LSR(uart, TFI);
 #endif
@@ -536,7 +532,7 @@
 		 */
 		UART_CLEAR_IER(uart, ETBEI);
 		uart->port.icount.tx += uart->tx_count;
-		if (!uart_circ_empty(xmit)) {
+		if (!(xmit->tail == 0 && xmit->head == 0)) {
 			xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
 
 			if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -553,7 +549,7 @@
 static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
 {
 	struct bfin_serial_port *uart = dev_id;
-	unsigned short irqstat;
+	unsigned int irqstat;
 	int x_pos, pos;
 
 	spin_lock(&uart->rx_lock);
@@ -586,7 +582,7 @@
 static unsigned int bfin_serial_tx_empty(struct uart_port *port)
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-	unsigned short lsr;
+	unsigned int lsr;
 
 	lsr = UART_GET_LSR(uart);
 	if (lsr & TEMT)
@@ -598,7 +594,7 @@
 static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-	u16 lcr = UART_GET_LCR(uart);
+	u32 lcr = UART_GET_LCR(uart);
 	if (break_state)
 		lcr |= SB;
 	else
@@ -745,7 +741,7 @@
 		}
 
 		/* CTS RTS PINs are negative assertive. */
-		UART_PUT_MCR(uart, ACTS);
+		UART_PUT_MCR(uart, UART_GET_MCR(uart) | ACTS);
 		UART_SET_IER(uart, EDSSI);
 	}
 #endif
@@ -803,7 +799,7 @@
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 	unsigned long flags;
 	unsigned int baud, quot;
-	unsigned short val, ier, lcr = 0;
+	unsigned int ier, lcr = 0;
 
 	switch (termios->c_cflag & CSIZE) {
 	case CS8:
@@ -875,26 +871,23 @@
 
 	/* Disable UART */
 	ier = UART_GET_IER(uart);
+	UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN);
 	UART_DISABLE_INTS(uart);
 
-	/* Set DLAB in LCR to Access DLL and DLH */
+	/* Set DLAB in LCR to Access CLK */
 	UART_SET_DLAB(uart);
 
-	UART_PUT_DLL(uart, quot & 0xFF);
-	UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
+	UART_PUT_CLK(uart, quot);
 	SSYNC();
 
 	/* Clear DLAB in LCR to Access THR RBR IER */
 	UART_CLEAR_DLAB(uart);
 
-	UART_PUT_LCR(uart, lcr);
+	UART_PUT_LCR(uart, (UART_GET_LCR(uart) & ~LCR_MASK) | lcr);
 
 	/* Enable UART */
 	UART_ENABLE_INTS(uart, ier);
-
-	val = UART_GET_GCTL(uart);
-	val |= UCEN;
-	UART_PUT_GCTL(uart, val);
+	UART_PUT_GCTL(uart, UART_GET_GCTL(uart) | UCEN);
 
 	/* Port speed changed, update the per-port timeout. */
 	uart_update_timeout(port, termios->c_cflag, baud);
@@ -954,17 +947,17 @@
 static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-	unsigned short val;
+	unsigned int val;
 
 	switch (ld) {
 	case N_IRDA:
 		val = UART_GET_GCTL(uart);
-		val |= (IREN | RPOLC);
+		val |= (UMOD_IRDA | RPOLC);
 		UART_PUT_GCTL(uart, val);
 		break;
 	default:
 		val = UART_GET_GCTL(uart);
-		val &= ~(IREN | RPOLC);
+		val &= ~(UMOD_MASK | RPOLC);
 		UART_PUT_GCTL(uart, val);
 	}
 }
@@ -972,13 +965,13 @@
 static void bfin_serial_reset_irda(struct uart_port *port)
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-	unsigned short val;
+	unsigned int val;
 
 	val = UART_GET_GCTL(uart);
-	val &= ~(IREN | RPOLC);
+	val &= ~(UMOD_MASK | RPOLC);
 	UART_PUT_GCTL(uart, val);
 	SSYNC();
-	val |= (IREN | RPOLC);
+	val |= (UMOD_IRDA | RPOLC);
 	UART_PUT_GCTL(uart, val);
 	SSYNC();
 }
@@ -1070,12 +1063,12 @@
 bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
 			   int *parity, int *bits)
 {
-	unsigned short status;
+	unsigned int status;
 
 	status = UART_GET_IER(uart) & (ERBFI | ETBEI);
 	if (status == (ERBFI | ETBEI)) {
 		/* ok, the port was enabled */
-		u16 lcr, dlh, dll;
+		u32 lcr, clk;
 
 		lcr = UART_GET_LCR(uart);
 
@@ -1086,30 +1079,17 @@
 			else
 				*parity = 'o';
 		}
-		switch (lcr & 0x03) {
-		case 0:
-			*bits = 5;
-			break;
-		case 1:
-			*bits = 6;
-			break;
-		case 2:
-			*bits = 7;
-			break;
-		case 3:
-			*bits = 8;
-			break;
-		}
-		/* Set DLAB in LCR to Access DLL and DLH */
+		*bits = ((lcr & WLS_MASK) >> WLS_OFFSET) + 5;
+
+		/* Set DLAB in LCR to Access CLK */
 		UART_SET_DLAB(uart);
 
-		dll = UART_GET_DLL(uart);
-		dlh = UART_GET_DLH(uart);
+		clk = UART_GET_CLK(uart);
 
 		/* Clear DLAB in LCR to Access THR RBR IER */
 		UART_CLEAR_DLAB(uart);
 
-		*baud = get_sclk() / (16*(dll | dlh << 8));
+		*baud = get_sclk() / (16*clk);
 	}
 	pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
 }
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 836fe273..d0f719f 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -40,7 +40,6 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/hardware/clps7111.h>
 
 #define UART_NR		2
 
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 5b07c0c..7264d4d 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -952,19 +952,6 @@
 /* Input */
 #define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
 
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static DEFINE_MUTEX(tmp_buf_mutex);
-
 /* Calculate the chartime depending on baudrate, numbor of bits etc. */
 static void update_char_time(struct e100_serial * info)
 {
@@ -3150,7 +3137,7 @@
 
 	/* first some sanity checks */
 
-	if (!tty || !info->xmit.buf || !tmp_buf)
+	if (!tty || !info->xmit.buf)
 		return 0;
 
 #ifdef SERIAL_DEBUG_DATA
@@ -3989,7 +3976,7 @@
 	 */
 	if (tty_hung_up_p(filp) ||
 	    (info->flags & ASYNC_CLOSING)) {
-		wait_event_interruptible_tty(info->close_wait,
+		wait_event_interruptible_tty(tty, info->close_wait,
 			!(info->flags & ASYNC_CLOSING));
 #ifdef SERIAL_DO_RESTART
 		if (info->flags & ASYNC_HUP_NOTIFY)
@@ -4065,9 +4052,9 @@
 		printk("block_til_ready blocking: ttyS%d, count = %d\n",
 		       info->line, info->count);
 #endif
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&info->open_wait, &wait);
@@ -4106,7 +4093,6 @@
 {
 	struct e100_serial	*info;
 	int 			retval;
-	unsigned long           page;
 	int                     allocated_resources = 0;
 
 	info = rs_table + tty->index;
@@ -4124,23 +4110,12 @@
 
 	tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
 
-	if (!tmp_buf) {
-		page = get_zeroed_page(GFP_KERNEL);
-		if (!page) {
-			return -ENOMEM;
-		}
-		if (tmp_buf)
-			free_page(page);
-		else
-			tmp_buf = (unsigned char *) page;
-	}
-
 	/*
 	 * If the port is in the middle of closing, bail out now
 	 */
 	if (tty_hung_up_p(filp) ||
 	    (info->flags & ASYNC_CLOSING)) {
-		wait_event_interruptible_tty(info->close_wait,
+		wait_event_interruptible_tty(tty, info->close_wait,
 			!(info->flags & ASYNC_CLOSING));
 #ifdef SERIAL_DO_RESTART
 		return ((info->flags & ASYNC_HUP_NOTIFY) ?
@@ -4487,6 +4462,7 @@
 				info->enabled = 0;
 			}
 		}
+		tty_port_init(&info->port);
 		info->uses_dma_in = 0;
 		info->uses_dma_out = 0;
 		info->line = i;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index e7fecee..ec20673 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -47,6 +47,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -1464,6 +1465,7 @@
 	void __iomem *base;
 	int ret = 0;
 	struct resource *res;
+	struct pinctrl *pinctrl;
 
 	sport = kzalloc(sizeof(*sport), GFP_KERNEL);
 	if (!sport)
@@ -1503,6 +1505,12 @@
 	sport->timer.function = imx_timeout;
 	sport->timer.data     = (unsigned long)sport;
 
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		goto unmap;
+	}
+
 	sport->clk = clk_get(&pdev->dev, "uart");
 	if (IS_ERR(sport->clk)) {
 		ret = PTR_ERR(sport->clk);
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 55fd362..ec56d83 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -32,6 +32,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <asm/cacheflush.h>
 
@@ -369,6 +370,8 @@
 
 	writel(ctrl, u->membase + AUART_LINECTRL);
 	writel(ctrl2, u->membase + AUART_CTRL2);
+
+	uart_update_timeout(u, termios->c_cflag, baud);
 }
 
 static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
@@ -678,6 +681,7 @@
 	u32 version;
 	int ret = 0;
 	struct resource *r;
+	struct pinctrl *pinctrl;
 
 	s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
 	if (!s) {
@@ -685,6 +689,12 @@
 		goto out;
 	}
 
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		goto out_free;
+	}
+
 	s->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(s->clk)) {
 		ret = PTR_ERR(s->clk);
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index e8c9cee..5410c06 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -12,10 +12,13 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/of_serial.h>
 #include <linux/of_platform.h>
 #include <linux/nwpserial.h>
 
@@ -24,6 +27,26 @@
 	int line;
 };
 
+#ifdef CONFIG_ARCH_TEGRA
+void tegra_serial_handle_break(struct uart_port *p)
+{
+	unsigned int status, tmout = 10000;
+
+	do {
+		status = p->serial_in(p, UART_LSR);
+		if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
+			status = p->serial_in(p, UART_RX);
+		else
+			break;
+		if (--tmout == 0)
+			break;
+		udelay(1);
+	} while (1);
+}
+/* FIXME remove this export when tegra finishes conversion to open firmware */
+EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
+#endif
+
 /*
  * Fill a struct uart_port for a given device node
  */
@@ -84,6 +107,9 @@
 		| UPF_FIXED_PORT | UPF_FIXED_TYPE;
 	port->dev = &ofdev->dev;
 
+	if (type == PORT_TEGRA)
+		port->handle_break = tegra_serial_handle_break;
+
 	return 0;
 }
 
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index d00b38e..d3cda0c 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -44,6 +44,13 @@
 #include <plat/dmtimer.h>
 #include <plat/omap-serial.h>
 
+#define UART_BUILD_REVISION(x, y)	(((x) << 8) | (y))
+
+#define OMAP_UART_REV_42 0x0402
+#define OMAP_UART_REV_46 0x0406
+#define OMAP_UART_REV_52 0x0502
+#define OMAP_UART_REV_63 0x0603
+
 #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
 
 /* SCR register bitmasks */
@@ -53,6 +60,17 @@
 #define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT		6
 #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK			(0x3 << 6)
 
+/* MVR register bitmasks */
+#define OMAP_UART_MVR_SCHEME_SHIFT	30
+
+#define OMAP_UART_LEGACY_MVR_MAJ_MASK	0xf0
+#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT	4
+#define OMAP_UART_LEGACY_MVR_MIN_MASK	0x0f
+
+#define OMAP_UART_MVR_MAJ_MASK		0x700
+#define OMAP_UART_MVR_MAJ_SHIFT		8
+#define OMAP_UART_MVR_MIN_MASK		0x3f
+
 static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 
 /* Forward declaration of functions */
@@ -1346,6 +1364,59 @@
 	return;
 }
 
+static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
+{
+	u32 mvr, scheme;
+	u16 revision, major, minor;
+
+	mvr = serial_in(up, UART_OMAP_MVER);
+
+	/* Check revision register scheme */
+	scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;
+
+	switch (scheme) {
+	case 0: /* Legacy Scheme: OMAP2/3 */
+		/* MINOR_REV[0:4], MAJOR_REV[4:7] */
+		major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >>
+					OMAP_UART_LEGACY_MVR_MAJ_SHIFT;
+		minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK);
+		break;
+	case 1:
+		/* New Scheme: OMAP4+ */
+		/* MINOR_REV[0:5], MAJOR_REV[8:10] */
+		major = (mvr & OMAP_UART_MVR_MAJ_MASK) >>
+					OMAP_UART_MVR_MAJ_SHIFT;
+		minor = (mvr & OMAP_UART_MVR_MIN_MASK);
+		break;
+	default:
+		dev_warn(&up->pdev->dev,
+			"Unknown %s revision, defaulting to highest\n",
+			up->name);
+		/* highest possible revision */
+		major = 0xff;
+		minor = 0xff;
+	}
+
+	/* normalize revision for the driver */
+	revision = UART_BUILD_REVISION(major, minor);
+
+	switch (revision) {
+	case OMAP_UART_REV_46:
+		up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
+				UART_ERRATA_i291_DMA_FORCEIDLE);
+		break;
+	case OMAP_UART_REV_52:
+		up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
+				UART_ERRATA_i291_DMA_FORCEIDLE);
+		break;
+	case OMAP_UART_REV_63:
+		up->errata |= UART_ERRATA_i202_MDR1_ACCESS;
+		break;
+	default:
+		break;
+	}
+}
+
 static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
 {
 	struct omap_uart_port_info *omap_up_info;
@@ -1439,7 +1510,6 @@
 						"%d\n", DEFAULT_CLK_SPEED);
 	}
 	up->uart_dma.uart_base = mem->start;
-	up->errata = omap_up_info->errata;
 
 	if (omap_up_info->dma_enabled) {
 		up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1469,6 +1539,8 @@
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 
+	omap_serial_fill_features_erratas(up);
+
 	ui[up->port.line] = up;
 	serial_omap_add_console_port(up);
 
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index c2816f4..4fdec6a6 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -39,6 +39,7 @@
 	PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
 	PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
 	PCH_UART_HANDLED_MS_INT_SHIFT,
+	PCH_UART_HANDLED_LS_INT_SHIFT,
 };
 
 enum {
@@ -63,6 +64,8 @@
 					PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
 #define PCH_UART_HANDLED_MS_INT	(1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
 
+#define PCH_UART_HANDLED_LS_INT	(1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1))
+
 #define PCH_UART_RBR		0x00
 #define PCH_UART_THR		0x00
 
@@ -229,7 +232,6 @@
 	int start_tx;
 	int start_rx;
 	int tx_empty;
-	int int_dis_flag;
 	int trigger;
 	int trigger_level;
 	struct pch_uart_buffer rxbuf;
@@ -237,7 +239,6 @@
 	unsigned int fcr;
 	unsigned int mcr;
 	unsigned int use_dma;
-	unsigned int use_dma_flag;
 	struct dma_async_tx_descriptor	*desc_tx;
 	struct dma_async_tx_descriptor	*desc_rx;
 	struct pch_dma_slave		param_tx;
@@ -560,14 +561,10 @@
 	return i;
 }
 
-static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
+static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv)
 {
-	unsigned int iir;
-	int ret;
-
-	iir = ioread8(priv->membase + UART_IIR);
-	ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
-	return ret;
+	return ioread8(priv->membase + UART_IIR) &\
+		      (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP);
 }
 
 static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
@@ -666,10 +663,13 @@
 		dma_release_channel(priv->chan_rx);
 		priv->chan_rx = NULL;
 	}
-	if (sg_dma_address(&priv->sg_rx))
-		dma_free_coherent(port->dev, port->fifosize,
-				  sg_virt(&priv->sg_rx),
-				  sg_dma_address(&priv->sg_rx));
+
+	if (priv->rx_buf_dma) {
+		dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt,
+				  priv->rx_buf_dma);
+		priv->rx_buf_virt = NULL;
+		priv->rx_buf_dma = 0;
+	}
 
 	return;
 }
@@ -1053,12 +1053,17 @@
 	unsigned int handled;
 	u8 lsr;
 	int ret = 0;
-	unsigned int iid;
+	unsigned char iid;
 	unsigned long flags;
+	int next = 1;
+	u8 msr;
 
 	spin_lock_irqsave(&priv->port.lock, flags);
 	handled = 0;
-	while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
+	while (next) {
+		iid = pch_uart_hal_get_iid(priv);
+		if (iid & PCH_UART_IIR_IP) /* No Interrupt */
+			break;
 		switch (iid) {
 		case PCH_UART_IID_RLS:	/* Receiver Line Status */
 			lsr = pch_uart_hal_get_line_status(priv);
@@ -1066,6 +1071,8 @@
 						UART_LSR_PE | UART_LSR_OE)) {
 				pch_uart_err_ir(priv, lsr);
 				ret = PCH_UART_HANDLED_RX_ERR_INT;
+			} else {
+				ret = PCH_UART_HANDLED_LS_INT;
 			}
 			break;
 		case PCH_UART_IID_RDR:	/* Received Data Ready */
@@ -1092,20 +1099,22 @@
 				ret = handle_tx(priv);
 			break;
 		case PCH_UART_IID_MS:	/* Modem Status */
-			ret = PCH_UART_HANDLED_MS_INT;
+			msr = pch_uart_hal_get_modem(priv);
+			next = 0; /* MS ir prioirty is the lowest. So, MS ir
+				     means final interrupt */
+			if ((msr & UART_MSR_ANY_DELTA) == 0)
+				break;
+			ret |= PCH_UART_HANDLED_MS_INT;
 			break;
 		default:	/* Never junp to this label */
-			dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__,
+			dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__,
 				iid, jiffies);
 			ret = -1;
+			next = 0;
 			break;
 		}
 		handled |= (unsigned int)ret;
 	}
-	if (handled == 0 && iid <= 1) {
-		if (priv->int_dis_flag)
-			priv->int_dis_flag = 0;
-	}
 
 	spin_unlock_irqrestore(&priv->port.lock, flags);
 	return IRQ_RETVAL(handled);
@@ -1200,7 +1209,6 @@
 	priv = container_of(port, struct eg20t_port, port);
 	priv->start_rx = 0;
 	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
-	priv->int_dis_flag = 1;
 }
 
 /* Enable the modem status interrupts. */
@@ -1447,7 +1455,6 @@
 			__func__);
 		return -EOPNOTSUPP;
 #endif
-		priv->use_dma_flag = 1;
 		dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
 		if (!priv->use_dma)
 			pch_request_dma(port);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 9c4c05b..246b823 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2282,6 +2282,7 @@
 	tty_unregister_driver(p);
 	put_tty_driver(p);
 	kfree(drv->state);
+	drv->state = NULL;
 	drv->tty_driver = NULL;
 }
 
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 3158e17..4604153 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1052,9 +1052,17 @@
 		if (SCIx_IRQ_IS_MUXED(port)) {
 			i = SCIx_MUX_IRQ;
 			irq = up->irq;
-		} else
+		} else {
 			irq = port->cfg->irqs[i];
 
+			/*
+			 * Certain port types won't support all of the
+			 * available interrupt sources.
+			 */
+			if (unlikely(!irq))
+				continue;
+		}
+
 		desc = sci_irq_desc + i;
 		port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
 					    dev_name(up->dev), desc->desc);
@@ -1094,6 +1102,15 @@
 	 * IRQ first.
 	 */
 	for (i = 0; i < SCIx_NR_IRQS; i++) {
+		unsigned int irq = port->cfg->irqs[i];
+
+		/*
+		 * Certain port types won't support all of the available
+		 * interrupt sources.
+		 */
+		if (unlikely(!irq))
+			continue;
+
 		free_irq(port->cfg->irqs[i], port);
 		kfree(port->irqstr[i]);
 
@@ -1564,10 +1581,32 @@
 
 static void sci_break_ctl(struct uart_port *port, int break_state)
 {
-	/*
-	 * Not supported by hardware. Most parts couple break and rx
-	 * interrupts together, with break detection always enabled.
-	 */
+	struct sci_port *s = to_sci_port(port);
+	struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
+	unsigned short scscr, scsptr;
+
+	/* check wheter the port has SCSPTR */
+	if (!reg->size) {
+		/*
+		 * Not supported by hardware. Most parts couple break and rx
+		 * interrupts together, with break detection always enabled.
+		 */
+		return;
+	}
+
+	scsptr = serial_port_in(port, SCSPTR);
+	scscr = serial_port_in(port, SCSCR);
+
+	if (break_state == -1) {
+		scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT;
+		scscr &= ~SCSCR_TE;
+	} else {
+		scsptr = (scsptr | SCSPTR_SPB2DT) & ~SCSPTR_SPB2IO;
+		scscr |= SCSCR_TE;
+	}
+
+	serial_port_out(port, SCSPTR, scsptr);
+	serial_port_out(port, SCSCR, scscr);
 }
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 593d40a..5ed0daa 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -3338,9 +3338,9 @@
 			printk("%s(%d):block_til_ready blocking on %s count=%d\n",
 				 __FILE__,__LINE__, tty->driver->name, port->count );
 				 
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	
 	set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index aa1debf..45b43f1 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -3336,9 +3336,9 @@
 		}
 
 		DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 
 	set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index a3dddc1..4a1e4f0 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -3357,9 +3357,9 @@
 			printk("%s(%d):%s block_til_ready() count=%d\n",
 				 __FILE__,__LINE__, tty->driver->name, port->count );
 
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 
 	set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 6c9b7cd..91e326f 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -185,25 +185,19 @@
 	/* Should possibly check if this fails for the largest buffer we
 	   have queued and recycle that ? */
 }
-
 /**
- *	tty_buffer_request_room		-	grow tty buffer if needed
+ *	__tty_buffer_request_room		-	grow tty buffer if needed
  *	@tty: tty structure
  *	@size: size desired
  *
  *	Make at least size bytes of linear space available for the tty
  *	buffer. If we fail return the size we managed to find.
- *
- *	Locking: Takes tty->buf.lock
+ *      Locking: Caller must hold tty->buf.lock
  */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
 {
 	struct tty_buffer *b, *n;
 	int left;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tty->buf.lock, flags);
-
 	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
 	   remove this conditional if its worth it. This would be invisible
 	   to the callers */
@@ -225,9 +219,30 @@
 			size = left;
 	}
 
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
 	return size;
 }
+
+
+/**
+ *	tty_buffer_request_room		-	grow tty buffer if needed
+ *	@tty: tty structure
+ *	@size: size desired
+ *
+ *	Make at least size bytes of linear space available for the tty
+ *	buffer. If we fail return the size we managed to find.
+ *
+ *	Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+	unsigned long flags;
+	int length;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	length = __tty_buffer_request_room(tty, size);
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
+	return length;
+}
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 
 /**
@@ -249,14 +264,22 @@
 	int copied = 0;
 	do {
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
+		int space;
+		unsigned long flags;
+		struct tty_buffer *tb;
+
+		spin_lock_irqsave(&tty->buf.lock, flags);
+		space = __tty_buffer_request_room(tty, goal);
+		tb = tty->buf.tail;
 		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
+		if (unlikely(space == 0)) {
+			spin_unlock_irqrestore(&tty->buf.lock, flags);
 			break;
+		}
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memset(tb->flag_buf_ptr + tb->used, flag, space);
 		tb->used += space;
+		spin_unlock_irqrestore(&tty->buf.lock, flags);
 		copied += space;
 		chars += space;
 		/* There is a small chance that we need to split the data over
@@ -286,14 +309,22 @@
 	int copied = 0;
 	do {
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
+		int space;
+		unsigned long __flags;
+		struct tty_buffer *tb;
+
+		spin_lock_irqsave(&tty->buf.lock, __flags);
+		space = __tty_buffer_request_room(tty, goal);
+		tb = tty->buf.tail;
 		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
+		if (unlikely(space == 0)) {
+			spin_unlock_irqrestore(&tty->buf.lock, __flags);
 			break;
+		}
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
 		tb->used += space;
+		spin_unlock_irqrestore(&tty->buf.lock, __flags);
 		copied += space;
 		chars += space;
 		flags += space;
@@ -344,13 +375,20 @@
 int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
 								size_t size)
 {
-	int space = tty_buffer_request_room(tty, size);
+	int space;
+	unsigned long flags;
+	struct tty_buffer *tb;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	space = __tty_buffer_request_room(tty, size);
+
+	tb = tty->buf.tail;
 	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
 		*chars = tb->char_buf_ptr + tb->used;
 		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
 		tb->used += space;
 	}
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
 	return space;
 }
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
@@ -374,13 +412,20 @@
 int tty_prepare_flip_string_flags(struct tty_struct *tty,
 			unsigned char **chars, char **flags, size_t size)
 {
-	int space = tty_buffer_request_room(tty, size);
+	int space;
+	unsigned long __flags;
+	struct tty_buffer *tb;
+
+	spin_lock_irqsave(&tty->buf.lock, __flags);
+	space = __tty_buffer_request_room(tty, size);
+
+	tb = tty->buf.tail;
 	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
 		*chars = tb->char_buf_ptr + tb->used;
 		*flags = tb->flag_buf_ptr + tb->used;
 		tb->used += space;
 	}
+	spin_unlock_irqrestore(&tty->buf.lock, __flags);
 	return space;
 }
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index d939bd7..9e930c0 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -185,6 +185,7 @@
 		put_device(tty->dev);
 	kfree(tty->write_buf);
 	tty_buffer_free_all(tty);
+	tty->magic = 0xDEADDEAD;
 	kfree(tty);
 }
 
@@ -573,7 +574,7 @@
 	}
 	spin_unlock(&redirect_lock);
 
-	tty_lock();
+	tty_lock(tty);
 
 	/* some functions below drop BTM, so we need this bit */
 	set_bit(TTY_HUPPING, &tty->flags);
@@ -666,7 +667,7 @@
 	clear_bit(TTY_HUPPING, &tty->flags);
 	tty_ldisc_enable(tty);
 
-	tty_unlock();
+	tty_unlock(tty);
 
 	if (f)
 		fput(f);
@@ -855,10 +856,11 @@
  */
 void no_tty(void)
 {
+	/* FIXME: Review locking here. The tty_lock never covered any race
+	   between a new association and proc_clear_tty but possible we need
+	   to protect against this anyway */
 	struct task_struct *tsk = current;
-	tty_lock();
 	disassociate_ctty(0);
-	tty_unlock();
 	proc_clear_tty(tsk);
 }
 
@@ -1102,12 +1104,12 @@
 {
 	if (tty) {
 		mutex_lock(&tty->atomic_write_lock);
-		tty_lock();
+		tty_lock(tty);
 		if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
-			tty_unlock();
+			tty_unlock(tty);
 			tty->ops->write(tty, msg, strlen(msg));
 		} else
-			tty_unlock();
+			tty_unlock(tty);
 		tty_write_unlock(tty);
 	}
 	return;
@@ -1402,6 +1404,7 @@
 	}
 	initialize_tty_struct(tty, driver, idx);
 
+	tty_lock(tty);
 	retval = tty_driver_install_tty(driver, tty);
 	if (retval < 0)
 		goto err_deinit_tty;
@@ -1414,9 +1417,11 @@
 	retval = tty_ldisc_setup(tty, tty->link);
 	if (retval)
 		goto err_release_tty;
+	/* Return the tty locked so that it cannot vanish under the caller */
 	return tty;
 
 err_deinit_tty:
+	tty_unlock(tty);
 	deinitialize_tty_struct(tty);
 	free_tty_struct(tty);
 err_module_put:
@@ -1425,6 +1430,7 @@
 
 	/* call the tty release_tty routine to clean out this slot */
 err_release_tty:
+	tty_unlock(tty);
 	printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
 				 "clearing slot %d\n", idx);
 	release_tty(tty, idx);
@@ -1627,7 +1633,7 @@
 	if (tty_paranoia_check(tty, inode, __func__))
 		return 0;
 
-	tty_lock();
+	tty_lock(tty);
 	check_tty_count(tty, __func__);
 
 	__tty_fasync(-1, filp, 0);
@@ -1636,10 +1642,11 @@
 	pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
 		      tty->driver->subtype == PTY_TYPE_MASTER);
 	devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+	/* Review: parallel close */
 	o_tty = tty->link;
 
 	if (tty_release_checks(tty, o_tty, idx)) {
-		tty_unlock();
+		tty_unlock(tty);
 		return 0;
 	}
 
@@ -1651,7 +1658,7 @@
 	if (tty->ops->close)
 		tty->ops->close(tty, filp);
 
-	tty_unlock();
+	tty_unlock(tty);
 	/*
 	 * Sanity check: if tty->count is going to zero, there shouldn't be
 	 * any waiters on tty->read_wait or tty->write_wait.  We test the
@@ -1674,7 +1681,7 @@
 		   opens on /dev/tty */
 
 		mutex_lock(&tty_mutex);
-		tty_lock();
+		tty_lock_pair(tty, o_tty);
 		tty_closing = tty->count <= 1;
 		o_tty_closing = o_tty &&
 			(o_tty->count <= (pty_master ? 1 : 0));
@@ -1705,7 +1712,7 @@
 
 		printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
 				__func__, tty_name(tty, buf));
-		tty_unlock();
+		tty_unlock_pair(tty, o_tty);
 		mutex_unlock(&tty_mutex);
 		schedule();
 	}
@@ -1768,7 +1775,7 @@
 
 	/* check whether both sides are closing ... */
 	if (!tty_closing || (o_tty && !o_tty_closing)) {
-		tty_unlock();
+		tty_unlock_pair(tty, o_tty);
 		return 0;
 	}
 
@@ -1781,14 +1788,16 @@
 	tty_ldisc_release(tty, o_tty);
 	/*
 	 * The release_tty function takes care of the details of clearing
-	 * the slots and preserving the termios structure.
+	 * the slots and preserving the termios structure. The tty_unlock_pair
+	 * should be safe as we keep a kref while the tty is locked (so the
+	 * unlock never unlocks a freed tty).
 	 */
 	release_tty(tty, idx);
+	tty_unlock_pair(tty, o_tty);
 
 	/* Make this pty number available for reallocation */
 	if (devpts)
 		devpts_kill_index(inode, idx);
-	tty_unlock();
 	return 0;
 }
 
@@ -1800,6 +1809,9 @@
  *
  *	We cannot return driver and index like for the other nodes because
  *	devpts will not work then. It expects inodes to be from devpts FS.
+ *
+ *	We need to move to returning a refcounted object from all the lookup
+ *	paths including this one.
  */
 static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
 {
@@ -1816,6 +1828,7 @@
 	/* noctty = 1; */
 	tty_kref_put(tty);
 	/* FIXME: we put a reference and return a TTY! */
+	/* This is only safe because the caller holds tty_mutex */
 	return tty;
 }
 
@@ -1888,6 +1901,9 @@
  *	Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
  *		 tty->count should protect the rest.
  *		 ->siglock protects ->signal/->sighand
+ *
+ *	Note: the tty_unlock/lock cases without a ref are only safe due to
+ *	tty_mutex
  */
 
 static int tty_open(struct inode *inode, struct file *filp)
@@ -1911,8 +1927,7 @@
 	retval = 0;
 
 	mutex_lock(&tty_mutex);
-	tty_lock();
-
+	/* This is protected by the tty_mutex */
 	tty = tty_open_current_tty(device, filp);
 	if (IS_ERR(tty)) {
 		retval = PTR_ERR(tty);
@@ -1933,17 +1948,19 @@
 	}
 
 	if (tty) {
+		tty_lock(tty);
 		retval = tty_reopen(tty);
-		if (retval)
+		if (retval < 0) {
+			tty_unlock(tty);
 			tty = ERR_PTR(retval);
-	} else
+		}
+	} else	/* Returns with the tty_lock held for now */
 		tty = tty_init_dev(driver, index);
 
 	mutex_unlock(&tty_mutex);
 	if (driver)
 		tty_driver_kref_put(driver);
 	if (IS_ERR(tty)) {
-		tty_unlock();
 		retval = PTR_ERR(tty);
 		goto err_file;
 	}
@@ -1972,7 +1989,7 @@
 		printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
 				retval, tty->name);
 #endif
-		tty_unlock(); /* need to call tty_release without BTM */
+		tty_unlock(tty); /* need to call tty_release without BTM */
 		tty_release(inode, filp);
 		if (retval != -ERESTARTSYS)
 			return retval;
@@ -1984,17 +2001,15 @@
 		/*
 		 * Need to reset f_op in case a hangup happened.
 		 */
-		tty_lock();
 		if (filp->f_op == &hung_up_tty_fops)
 			filp->f_op = &tty_fops;
-		tty_unlock();
 		goto retry_open;
 	}
-	tty_unlock();
+	tty_unlock(tty);
 
 
 	mutex_lock(&tty_mutex);
-	tty_lock();
+	tty_lock(tty);
 	spin_lock_irq(&current->sighand->siglock);
 	if (!noctty &&
 	    current->signal->leader &&
@@ -2002,11 +2017,10 @@
 	    tty->session == NULL)
 		__proc_set_tty(current, tty);
 	spin_unlock_irq(&current->sighand->siglock);
-	tty_unlock();
+	tty_unlock(tty);
 	mutex_unlock(&tty_mutex);
 	return 0;
 err_unlock:
-	tty_unlock();
 	mutex_unlock(&tty_mutex);
 	/* after locks to avoid deadlock */
 	if (!IS_ERR_OR_NULL(driver))
@@ -2089,10 +2103,13 @@
 
 static int tty_fasync(int fd, struct file *filp, int on)
 {
+	struct tty_struct *tty = file_tty(filp);
 	int retval;
-	tty_lock();
+
+	tty_lock(tty);
 	retval = __tty_fasync(fd, filp, on);
-	tty_unlock();
+	tty_unlock(tty);
+
 	return retval;
 }
 
@@ -2929,6 +2946,7 @@
 	tty->pgrp = NULL;
 	tty->overrun_time = jiffies;
 	tty_buffer_init(tty);
+	mutex_init(&tty->legacy_mutex);
 	mutex_init(&tty->termios_mutex);
 	mutex_init(&tty->ldisc_mutex);
 	init_waitqueue_head(&tty->write_wait);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 24b95db..173a900 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -28,7 +28,6 @@
 
 static DEFINE_SPINLOCK(tty_ldisc_lock);
 static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle);
 /* Line disc dispatch table */
 static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
 
@@ -65,7 +64,7 @@
 		return;
 	}
 	local_irq_restore(flags);
-	wake_up(&tty_ldisc_idle);
+	wake_up(&ld->wq_idle);
 }
 
 /**
@@ -200,6 +199,8 @@
 
 	ld->ops = ldops;
 	atomic_set(&ld->users, 1);
+	init_waitqueue_head(&ld->wq_idle);
+
 	return ld;
 }
 
@@ -538,7 +539,7 @@
 static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
 {
 	long ret;
-	ret = wait_event_timeout(tty_ldisc_idle,
+	ret = wait_event_timeout(tty->ldisc->wq_idle,
 			atomic_read(&tty->ldisc->users) == 1, timeout);
 	return ret > 0 ? 0 : -EBUSY;
 }
@@ -567,7 +568,7 @@
 	if (IS_ERR(new_ldisc))
 		return PTR_ERR(new_ldisc);
 
-	tty_lock();
+	tty_lock(tty);
 	/*
 	 *	We need to look at the tty locking here for pty/tty pairs
 	 *	when both sides try to change in parallel.
@@ -581,12 +582,12 @@
 	 */
 
 	if (tty->ldisc->ops->num == ldisc) {
-		tty_unlock();
+		tty_unlock(tty);
 		tty_ldisc_put(new_ldisc);
 		return 0;
 	}
 
-	tty_unlock();
+	tty_unlock(tty);
 	/*
 	 *	Problem: What do we do if this blocks ?
 	 *	We could deadlock here
@@ -594,7 +595,7 @@
 
 	tty_wait_until_sent(tty, 0);
 
-	tty_lock();
+	tty_lock(tty);
 	mutex_lock(&tty->ldisc_mutex);
 
 	/*
@@ -604,10 +605,10 @@
 
 	while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
 		mutex_unlock(&tty->ldisc_mutex);
-		tty_unlock();
+		tty_unlock(tty);
 		wait_event(tty_ldisc_wait,
 			test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
-		tty_lock();
+		tty_lock(tty);
 		mutex_lock(&tty->ldisc_mutex);
 	}
 
@@ -622,7 +623,7 @@
 
 	o_ldisc = tty->ldisc;
 
-	tty_unlock();
+	tty_unlock(tty);
 	/*
 	 *	Make sure we don't change while someone holds a
 	 *	reference to the line discipline. The TTY_LDISC bit
@@ -649,7 +650,7 @@
 
 	retval = tty_ldisc_wait_idle(tty, 5 * HZ);
 
-	tty_lock();
+	tty_lock(tty);
 	mutex_lock(&tty->ldisc_mutex);
 
 	/* handle wait idle failure locked */
@@ -664,7 +665,7 @@
 		clear_bit(TTY_LDISC_CHANGING, &tty->flags);
 		mutex_unlock(&tty->ldisc_mutex);
 		tty_ldisc_put(new_ldisc);
-		tty_unlock();
+		tty_unlock(tty);
 		return -EIO;
 	}
 
@@ -707,7 +708,7 @@
 	if (o_work)
 		schedule_work(&o_tty->buf.work);
 	mutex_unlock(&tty->ldisc_mutex);
-	tty_unlock();
+	tty_unlock(tty);
 	return retval;
 }
 
@@ -815,11 +816,11 @@
 	 * need to wait for another function taking the BTM
 	 */
 	clear_bit(TTY_LDISC, &tty->flags);
-	tty_unlock();
+	tty_unlock(tty);
 	cancel_work_sync(&tty->buf.work);
 	mutex_unlock(&tty->ldisc_mutex);
 retry:
-	tty_lock();
+	tty_lock(tty);
 	mutex_lock(&tty->ldisc_mutex);
 
 	/* At this point we have a closed ldisc and we want to
@@ -830,7 +831,7 @@
 		if (atomic_read(&tty->ldisc->users) != 1) {
 			char cur_n[TASK_COMM_LEN], tty_n[64];
 			long timeout = 3 * HZ;
-			tty_unlock();
+			tty_unlock(tty);
 
 			while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
 				timeout = MAX_SCHEDULE_TIMEOUT;
@@ -911,10 +912,10 @@
 	 * race with the set_ldisc code path.
 	 */
 
-	tty_unlock();
+	tty_unlock(tty);
 	tty_ldisc_halt(tty);
 	tty_ldisc_flush_works(tty);
-	tty_lock();
+	tty_lock(tty);
 
 	mutex_lock(&tty->ldisc_mutex);
 	/*
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 9ff986c..69adc80 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -4,29 +4,59 @@
 #include <linux/semaphore.h>
 #include <linux/sched.h>
 
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
+/* Legacy tty mutex glue */
 
 /*
  * Getting the big tty mutex.
  */
-void __lockfunc tty_lock(void)
+
+void __lockfunc tty_lock(struct tty_struct *tty)
 {
-	mutex_lock(&big_tty_mutex);
+	if (tty->magic != TTY_MAGIC) {
+		printk(KERN_ERR "L Bad %p\n", tty);
+		WARN_ON(1);
+		return;
+	}
+	tty_kref_get(tty);
+	mutex_lock(&tty->legacy_mutex);
 }
 EXPORT_SYMBOL(tty_lock);
 
-void __lockfunc tty_unlock(void)
+void __lockfunc tty_unlock(struct tty_struct *tty)
 {
-	mutex_unlock(&big_tty_mutex);
+	if (tty->magic != TTY_MAGIC) {
+		printk(KERN_ERR "U Bad %p\n", tty);
+		WARN_ON(1);
+		return;
+	}
+	mutex_unlock(&tty->legacy_mutex);
+	tty_kref_put(tty);
 }
 EXPORT_SYMBOL(tty_unlock);
+
+/*
+ * Getting the big tty mutex for a pair of ttys with lock ordering
+ * On a non pty/tty pair tty2 can be NULL which is just fine.
+ */
+void __lockfunc tty_lock_pair(struct tty_struct *tty,
+					struct tty_struct *tty2)
+{
+	if (tty < tty2) {
+		tty_lock(tty);
+		tty_lock(tty2);
+	} else {
+		if (tty2 && tty2 != tty)
+			tty_lock(tty2);
+		tty_lock(tty);
+	}
+}
+EXPORT_SYMBOL(tty_lock_pair);
+
+void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+						struct tty_struct *tty2)
+{
+	tty_unlock(tty);
+	if (tty2 && tty2 != tty)
+		tty_unlock(tty2);
+}
+EXPORT_SYMBOL(tty_unlock_pair);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index bf6e238..d9cca95 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -230,7 +230,7 @@
 
 	/* block if port is in the process of being closed */
 	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-		wait_event_interruptible_tty(port->close_wait,
+		wait_event_interruptible_tty(tty, port->close_wait,
 				!(port->flags & ASYNC_CLOSING));
 		if (port->flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
@@ -296,9 +296,9 @@
 			retval = -ERESTARTSYS;
 			break;
 		}
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	finish_wait(&port->open_wait, &wait);
 
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 8308fc7..2aaa0c2 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/tty.h>
 #include <asm/uaccess.h>
+#include <linux/console.h>
 #include <linux/consolemap.h>
 #include <linux/vt_kern.h>
 
@@ -312,6 +313,7 @@
 	if (!access_ok(VERIFY_READ, arg, E_TABSZ))
 		return -EFAULT;
 
+	console_lock();
 	for (i=0; i<E_TABSZ ; i++) {
 		unsigned char uc;
 		__get_user(uc, arg+i);
@@ -319,6 +321,7 @@
 	}
 
 	update_user_maps();
+	console_unlock();
 	return 0;
 }
 
@@ -330,11 +333,13 @@
 	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
 		return -EFAULT;
 
+	console_lock();
 	for (i=0; i<E_TABSZ ; i++)
-	  {
-	    ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
-	    __put_user((ch & ~0xff) ? 0 : ch, arg+i);
-	  }
+	{
+		ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
+		__put_user((ch & ~0xff) ? 0 : ch, arg+i);
+	}
+	console_unlock();
 	return 0;
 }
 
@@ -346,6 +351,7 @@
 	if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
 		return -EFAULT;
 
+	console_lock();
 	for (i=0; i<E_TABSZ ; i++) {
 		unsigned short us;
 		__get_user(us, arg+i);
@@ -353,6 +359,7 @@
 	}
 
 	update_user_maps();
+	console_unlock();
 	return 0;
 }
 
@@ -364,8 +371,10 @@
 	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
 		return -EFAULT;
 
+	console_lock();
 	for (i=0; i<E_TABSZ ; i++)
 	  __put_user(p[i], arg+i);
+	console_unlock();
 	
 	return 0;
 }
@@ -407,6 +416,7 @@
 	}
 }
 
+/* Caller must hold the console lock */
 void con_free_unimap(struct vc_data *vc)
 {
 	struct uni_pagedir *p;
@@ -487,17 +497,21 @@
 	return 0;
 }
 
-/* ui is a leftover from using a hashtable, but might be used again */
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+/* ui is a leftover from using a hashtable, but might be used again
+   Caller must hold the lock */
+static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
 {
 	struct uni_pagedir *p, *q;
-  
+
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	if (p && p->readonly) return -EIO;
+	if (p && p->readonly)
+		return -EIO;
+
 	if (!p || --p->refcount) {
 		q = kzalloc(sizeof(*p), GFP_KERNEL);
 		if (!q) {
-			if (p) p->refcount++;
+			if (p)
+				p->refcount++;
 			return -ENOMEM;
 		}
 		q->refcount=1;
@@ -511,23 +525,43 @@
 	return 0;
 }
 
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+{
+	int ret;
+	console_lock();
+	ret = con_do_clear_unimap(vc, ui);
+	console_unlock();
+	return ret;
+}
+	
 int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 {
 	int err = 0, err1, i;
 	struct uni_pagedir *p, *q;
 
+	console_lock();
+
 	/* Save original vc_unipagdir_loc in case we allocate a new one */
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	if (p->readonly) return -EIO;
+	if (p->readonly) {
+		console_unlock();
+		return -EIO;
+	}
 	
-	if (!ct) return 0;
+	if (!ct) {
+		console_unlock();
+		return 0;
+	}
 	
 	if (p->refcount > 1) {
 		int j, k;
 		u16 **p1, *p2, l;
 		
-		err1 = con_clear_unimap(vc, NULL);
-		if (err1) return err1;
+		err1 = con_do_clear_unimap(vc, NULL);
+		if (err1) {
+			console_unlock();
+			return err1;
+		}
 		
 		/*
 		 * Since refcount was > 1, con_clear_unimap() allocated a
@@ -558,7 +592,8 @@
 						*vc->vc_uni_pagedir_loc = (unsigned long)p;
 						con_release_unimap(q);
 						kfree(q);
-						return err1;
+						console_unlock();
+						return err1; 
 					}
 				}
 			} else {
@@ -592,21 +627,30 @@
 	/*
 	 * Merge with fontmaps of any other virtual consoles.
 	 */
-	if (con_unify_unimap(vc, p))
+	if (con_unify_unimap(vc, p)) {
+		console_unlock();
 		return err;
+	}
 
 	for (i = 0; i <= 3; i++)
 		set_inverse_transl(vc, p, i); /* Update inverse translations */
 	set_inverse_trans_unicode(vc, p);
-  
+
+	console_unlock();
 	return err;
 }
 
-/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
-   The representation used was the most compact I could come up
-   with.  This routine is executed at sys_setup time, and when the
-   PIO_FONTRESET ioctl is called. */
-
+/**
+ *	con_set_default_unimap	-	set default unicode map
+ *	@vc: the console we are updating
+ *
+ *	Loads the unimap for the hardware font, as defined in uni_hash.tbl.
+ *	The representation used was the most compact I could come up
+ *	with.  This routine is executed at video setup, and when the
+ *	PIO_FONTRESET ioctl is called. 
+ *
+ *	The caller must hold the console lock
+ */
 int con_set_default_unimap(struct vc_data *vc)
 {
 	int i, j, err = 0, err1;
@@ -617,6 +661,7 @@
 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 		if (p == dflt)
 			return 0;
+
 		dflt->refcount++;
 		*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
 		if (p && !--p->refcount) {
@@ -628,8 +673,9 @@
 	
 	/* The default font is always 256 characters */
 
-	err = con_clear_unimap(vc, NULL);
-	if (err) return err;
+	err = con_do_clear_unimap(vc, NULL);
+	if (err)
+		return err;
     
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	q = dfont_unitable;
@@ -654,6 +700,13 @@
 }
 EXPORT_SYMBOL(con_set_default_unimap);
 
+/**
+ *	con_copy_unimap		-	copy unimap between two vts
+ *	@dst_vc: target
+ *	@src_vt: source
+ *
+ *	The caller must hold the console lock when invoking this method
+ */
 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
 {
 	struct uni_pagedir *q;
@@ -668,13 +721,23 @@
 	*dst_vc->vc_uni_pagedir_loc = (long)q;
 	return 0;
 }
+EXPORT_SYMBOL(con_copy_unimap);
 
+/**
+ *	con_get_unimap		-	get the unicode map
+ *	@vc: the console to read from
+ *
+ *	Read the console unicode data for this console. Called from the ioctl
+ *	handlers.
+ */
 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
 {
 	int i, j, k, ect;
 	u16 **p1, *p2;
 	struct uni_pagedir *p;
 
+	console_lock();
+
 	ect = 0;
 	if (*vc->vc_uni_pagedir_loc) {
 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
@@ -694,22 +757,19 @@
 				}
 	}
 	__put_user(ect, uct);
+	console_unlock();
 	return ((ect <= ct) ? 0 : -ENOMEM);
 }
 
-void con_protect_unimap(struct vc_data *vc, int rdonly)
-{
-	struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	
-	if (p)
-		p->readonly = rdonly;
-}
-
 /*
  * Always use USER_MAP. These functions are used by the keyboard,
  * which shouldn't be affected by G0/G1 switching, etc.
  * If the user map still contains default values, i.e. the
  * direct-to-font mapping, then assume user is using Latin1.
+ *
+ * FIXME: at some point we need to decide if we want to lock the table
+ * update element itself via the keyboard_event_lock for consistency with the
+ * keyboard driver as well as the consoles
  */
 /* may be called during an interrupt */
 u32 conv_8bit_to_uni(unsigned char c)
@@ -777,4 +837,3 @@
 			con_set_default_unimap(vc_cons[i].d);
 }
 
-EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 3b0c4e3..48cc6f2 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -53,17 +53,13 @@
 
 #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
 
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the
- * keypad to be used for numbers.
- */
-
-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
-#define KBD_DEFLEDS (1 << VC_NUMLOCK)
+#if defined(CONFIG_X86) || defined(CONFIG_PARISC)
+#include <asm/kbdleds.h>
 #else
-#define KBD_DEFLEDS 0
+static inline int kbd_defleds(void)
+{
+	return 0;
+}
 #endif
 
 #define KBD_DEFLOCK 0
@@ -1524,8 +1520,8 @@
 	int error;
 
 	for (i = 0; i < MAX_NR_CONSOLES; i++) {
-		kbd_table[i].ledflagstate = KBD_DEFLEDS;
-		kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
+		kbd_table[i].ledflagstate = kbd_defleds();
+		kbd_table[i].default_ledflagstate = kbd_defleds();
 		kbd_table[i].ledmode = LED_SHOW_FLAGS;
 		kbd_table[i].lockstate = KBD_DEFLOCK;
 		kbd_table[i].slockstate = 0;
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 2156188..84cbf29 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3892,36 +3892,6 @@
 		vc->vc_sw->con_set_palette(vc, color_table);
 }
 
-static int set_get_cmap(unsigned char __user *arg, int set)
-{
-    int i, j, k;
-
-    WARN_CONSOLE_UNLOCKED();
-
-    for (i = 0; i < 16; i++)
-	if (set) {
-	    get_user(default_red[i], arg++);
-	    get_user(default_grn[i], arg++);
-	    get_user(default_blu[i], arg++);
-	} else {
-	    put_user(default_red[i], arg++);
-	    put_user(default_grn[i], arg++);
-	    put_user(default_blu[i], arg++);
-	}
-    if (set) {
-	for (i = 0; i < MAX_NR_CONSOLES; i++)
-	    if (vc_cons_allocated(i)) {
-		for (j = k = 0; j < 16; j++) {
-		    vc_cons[i].d->vc_palette[k++] = default_red[j];
-		    vc_cons[i].d->vc_palette[k++] = default_grn[j];
-		    vc_cons[i].d->vc_palette[k++] = default_blu[j];
-		}
-		set_palette(vc_cons[i].d);
-	    }
-    }
-    return 0;
-}
-
 /*
  * Load palette into the DAC registers. arg points to a colour
  * map, 3 bytes per colour, 16 colours, range from 0 to 255.
@@ -3929,24 +3899,50 @@
 
 int con_set_cmap(unsigned char __user *arg)
 {
-	int rc;
+	int i, j, k;
+	unsigned char colormap[3*16];
+
+	if (copy_from_user(colormap, arg, sizeof(colormap)))
+		return -EFAULT;
 
 	console_lock();
-	rc = set_get_cmap (arg,1);
+	for (i = k = 0; i < 16; i++) {
+		default_red[i] = colormap[k++];
+		default_grn[i] = colormap[k++];
+		default_blu[i] = colormap[k++];
+	}
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (!vc_cons_allocated(i))
+			continue;
+		for (j = k = 0; j < 16; j++) {
+			vc_cons[i].d->vc_palette[k++] = default_red[j];
+			vc_cons[i].d->vc_palette[k++] = default_grn[j];
+			vc_cons[i].d->vc_palette[k++] = default_blu[j];
+		}
+		set_palette(vc_cons[i].d);
+	}
 	console_unlock();
 
-	return rc;
+	return 0;
 }
 
 int con_get_cmap(unsigned char __user *arg)
 {
-	int rc;
+	int i, k;
+	unsigned char colormap[3*16];
 
 	console_lock();
-	rc = set_get_cmap (arg,0);
+	for (i = k = 0; i < 16; i++) {
+		colormap[k++] = default_red[i];
+		colormap[k++] = default_grn[i];
+		colormap[k++] = default_blu[i];
+	}
 	console_unlock();
 
-	return rc;
+	if (copy_to_user(arg, colormap, sizeof(colormap)))
+		return -EFAULT;
+
+	return 0;
 }
 
 void reset_palette(struct vc_data *vc)
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef1..6461854 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -910,7 +910,9 @@
 		ret = con_font_op(vc_cons[fg_console].d, &op);
 		if (ret)
 			break;
+		console_lock();
 		con_set_default_unimap(vc_cons[fg_console].d);
+		console_unlock();
 		break;
 		}
 #endif
@@ -934,33 +936,23 @@
 	case PIO_SCRNMAP:
 		if (!perm)
 			ret = -EPERM;
-		else {
-			tty_lock();
+		else
 			ret = con_set_trans_old(up);
-			tty_unlock();
-		}
 		break;
 
 	case GIO_SCRNMAP:
-		tty_lock();
 		ret = con_get_trans_old(up);
-		tty_unlock();
 		break;
 
 	case PIO_UNISCRNMAP:
 		if (!perm)
 			ret = -EPERM;
-		else {
-			tty_lock();
+		else
 			ret = con_set_trans_new(up);
-			tty_unlock();
-		}
 		break;
 
 	case GIO_UNISCRNMAP:
-		tty_lock();
 		ret = con_get_trans_new(up);
-		tty_unlock();
 		break;
 
 	case PIO_UNIMAPCLR:
@@ -970,19 +962,14 @@
 		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
 		if (ret)
 			ret = -EFAULT;
-		else {
-			tty_lock();
+		else
 			con_clear_unimap(vc, &ui);
-			tty_unlock();
-		}
 		break;
 	      }
 
 	case PIO_UNIMAP:
 	case GIO_UNIMAP:
-		tty_lock();
 		ret = do_unimap_ioctl(cmd, up, perm, vc);
-		tty_unlock();
 		break;
 
 	case VT_LOCKSWITCH:
@@ -1196,9 +1183,7 @@
 
 	case PIO_UNIMAP:
 	case GIO_UNIMAP:
-		tty_lock();
 		ret = compat_unimap_ioctl(cmd, up, perm, vc);
-		tty_unlock();
 		break;
 
 	/*
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index b98371d..42202cd 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -146,6 +146,14 @@
 	priv->flags = 0; /* interrupt is enabled to begin with */
 	priv->pdev = pdev;
 
+	if (!uioinfo->irq) {
+		ret = platform_get_irq(pdev, 0);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to get IRQ\n");
+			goto bad0;
+		}
+		uioinfo->irq = ret;
+	}
 	uiomem = &uioinfo->mem[0];
 
 	for (i = 0; i < pdev->num_resources; ++i) {
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 76316a3..a7773a3 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -133,6 +133,8 @@
 
 source "drivers/usb/musb/Kconfig"
 
+source "drivers/usb/chipidea/Kconfig"
+
 source "drivers/usb/renesas_usbhs/Kconfig"
 
 source "drivers/usb/class/Kconfig"
@@ -177,6 +179,8 @@
 
 source "drivers/usb/misc/Kconfig"
 
+source "drivers/usb/phy/Kconfig"
+
 source "drivers/usb/atm/Kconfig"
 
 source "drivers/usb/gadget/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 53a7bc0..c691eea 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -46,12 +46,14 @@
 obj-$(CONFIG_USB_SERIAL)	+= serial/
 
 obj-$(CONFIG_USB)		+= misc/
+obj-$(CONFIG_USB)		+= phy/
 obj-$(CONFIG_EARLY_PRINTK_DBGP)	+= early/
 
 obj-$(CONFIG_USB_ATM)		+= atm/
 obj-$(CONFIG_USB_SPEEDTOUCH)	+= atm/
 
 obj-$(CONFIG_USB_MUSB_HDRC)	+= musb/
+obj-$(CONFIG_USB_CHIPIDEA)	+= chipidea/
 obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
 
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 98b89fe..b7eb86a 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -674,7 +674,7 @@
 	}
 
 	ret = offd;
-	dbg("cm %#x", cm);
+	usb_dbg(instance->usbatm, "cm %#x\n", cm);
 fail:
 	mutex_unlock(&instance->cm_serialize);
 err:
@@ -733,7 +733,7 @@
 {
 	int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
 	if (ret < 0) {		/* firmware not loaded */
-		dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret);
+		usb_dbg(instance->usbatm, "cxacru_adsl_start: CARD_GET_STATUS returned %d\n", ret);
 		return ret;
 	}
 	return 0;
@@ -758,7 +758,7 @@
 	int ret;
 	int start_polling = 1;
 
-	dbg("cxacru_atm_start");
+	dev_dbg(&intf->dev, "%s\n", __func__);
 
 	/* Read MAC address */
 	ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0,
@@ -962,13 +962,13 @@
 			ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD),
 					   buf, offb, NULL, CMD_TIMEOUT);
 			if (ret < 0) {
-				dbg("sending fw %#x failed", fw);
+				dev_dbg(&usb_dev->dev, "sending fw %#x failed\n", fw);
 				goto cleanup;
 			}
 			offb = 0;
 		}
 	} while (offd < size);
-	dbg("sent fw %#x", fw);
+	dev_dbg(&usb_dev->dev, "sent fw %#x\n", fw);
 
 	ret = 0;
 
@@ -988,7 +988,7 @@
 			       usb_dev->descriptor.idProduct };
 	__le32 val;
 
-	dbg("cxacru_upload_firmware");
+	usb_dbg(usbatm, "%s\n", __func__);
 
 	/* FirmwarePllFClkValue */
 	val = cpu_to_le32(instance->modem_type->pll_f_clk);
@@ -1074,7 +1074,7 @@
 	char buf[16];
 
 	sprintf(buf, "cxacru-%s.bin", phase);
-	dbg("cxacru_find_firmware: looking for %s", buf);
+	usb_dbg(usbatm, "cxacru_find_firmware: looking for %s\n", buf);
 
 	if (request_firmware(fw_p, buf, dev)) {
 		usb_dbg(usbatm, "no stage %s firmware found\n", phase);
@@ -1115,9 +1115,9 @@
 
 	ret = cxacru_card_status(instance);
 	if (ret)
-		dbg("modem initialisation failed");
+		usb_dbg(usbatm_instance, "modem initialisation failed\n");
 	else
-		dbg("done setting up the modem");
+		usb_dbg(usbatm_instance, "done setting up the modem\n");
 
 	return ret;
 }
@@ -1133,7 +1133,7 @@
 	/* instance init */
 	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
 	if (!instance) {
-		dbg("cxacru_bind: no memory for instance data");
+		usb_dbg(usbatm_instance, "cxacru_bind: no memory for instance data\n");
 		return -ENOMEM;
 	}
 
@@ -1149,31 +1149,31 @@
 
 	instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
 	if (!instance->rcv_buf) {
-		dbg("cxacru_bind: no memory for rcv_buf");
+		usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_buf\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
 	instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL);
 	if (!instance->snd_buf) {
-		dbg("cxacru_bind: no memory for snd_buf");
+		usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_buf\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
 	instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!instance->rcv_urb) {
-		dbg("cxacru_bind: no memory for rcv_urb");
+		usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_urb\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
 	instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!instance->snd_urb) {
-		dbg("cxacru_bind: no memory for snd_urb");
+		usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_urb\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
 
 	if (!cmd_ep) {
-		dbg("cxacru_bind: no command endpoint");
+		usb_dbg(usbatm_instance, "cxacru_bind: no command endpoint\n");
 		ret = -ENODEV;
 		goto fail;
 	}
@@ -1227,10 +1227,10 @@
 	struct cxacru_data *instance = usbatm_instance->driver_data;
 	int is_polling = 1;
 
-	dbg("cxacru_unbind entered");
+	usb_dbg(usbatm_instance, "cxacru_unbind entered\n");
 
 	if (!instance) {
-		dbg("cxacru_unbind: NULL instance!");
+		usb_dbg(usbatm_instance, "cxacru_unbind: NULL instance!\n");
 		return;
 	}
 
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 98dd9e4..975e9c6 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -170,7 +170,7 @@
 			 "%sabling SW buffering: usb_control_msg returned %d\n",
 			 state ? "En" : "Dis", ret);
 	else
-		dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
+		usb_dbg(usbatm, "speedtch_set_swbuff: %sbled SW buffering\n", state ? "En" : "Dis");
 }
 
 static void speedtch_test_sequence(struct speedtch_instance_data *instance)
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 01ea5d7..d7e422d 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1357,10 +1357,8 @@
 		/* release the dsp firmware as it is not needed until
 		 * the next failure
 		 */
-		if (sc->dsp_firm) {
-			release_firmware(sc->dsp_firm);
-			sc->dsp_firm = NULL;
-		}
+		release_firmware(sc->dsp_firm);
+		sc->dsp_firm = NULL;
 	}
 
 	/* always update it as atm layer could not be init when we switch to
@@ -1496,10 +1494,8 @@
 		/* release the dsp firmware as it is not needed until
 		 * the next failure
 		 */
-		if (sc->dsp_firm) {
-			release_firmware(sc->dsp_firm);
-			sc->dsp_firm = NULL;
-		}
+		release_firmware(sc->dsp_firm);
+		sc->dsp_firm = NULL;
 	}
 
 	/* always update it as atm layer could not be init when we switch to
@@ -2240,8 +2236,7 @@
 	/* flush the work item, when no one can schedule it */
 	flush_work_sync(&sc->task);
 
-	if (sc->dsp_firm)
-		release_firmware(sc->dsp_firm);
+	release_firmware(sc->dsp_firm);
 	uea_leaves(INS_TO_USBDEV(sc));
 }
 
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index d3448ca..ee62b35 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -86,7 +86,7 @@
 #ifdef VERBOSE_DEBUG
 static int usbatm_print_packet(const unsigned char *data, int len);
 #define PACKETDEBUG(arg...)	usbatm_print_packet(arg)
-#define vdbg(arg...)		dbg(arg)
+#define vdbg(arg...)		dev_dbg(arg)
 #else
 #define PACKETDEBUG(arg...)
 #define vdbg(arg...)
@@ -714,7 +714,7 @@
 {
 	struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);
 
-	dbg("%s", __func__);
+	usb_dbg(instance, "%s\n", __func__);
 
 	tasklet_kill(&instance->rx_channel.tasklet);
 	tasklet_kill(&instance->tx_channel.tasklet);
@@ -724,14 +724,14 @@
 
 static void usbatm_get_instance(struct usbatm_data *instance)
 {
-	dbg("%s", __func__);
+	usb_dbg(instance, "%s\n", __func__);
 
 	kref_get(&instance->refcount);
 }
 
 static void usbatm_put_instance(struct usbatm_data *instance)
 {
-	dbg("%s", __func__);
+	usb_dbg(instance, "%s\n", __func__);
 
 	kref_put(&instance->refcount, usbatm_destroy_instance);
 }
@@ -745,11 +745,10 @@
 {
 	struct usbatm_data *instance = atm_dev->dev_data;
 
-	dbg("%s", __func__);
-
 	if (!instance)
 		return;
 
+	usb_dbg(instance, "%s\n", __func__);
 	atm_dev->dev_data = NULL; /* catch bugs */
 	usbatm_put_instance(instance);	/* taken in usbatm_atm_init */
 }
@@ -759,10 +758,8 @@
 	struct usbatm_data *instance = atm_dev->dev_data;
 	int left = *pos;
 
-	if (!instance) {
-		dbg("%s: NULL instance!", __func__);
+	if (!instance)
 		return -ENODEV;
-	}
 
 	if (!left--)
 		return sprintf(page, "%s\n", instance->description);
@@ -804,10 +801,8 @@
 	int vci = vcc->vci;
 	short vpi = vcc->vpi;
 
-	if (!instance) {
-		dbg("%s: NULL data!", __func__);
+	if (!instance)
 		return -ENODEV;
-	}
 
 	atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
 
@@ -884,10 +879,8 @@
 	struct usbatm_data *instance = vcc->dev->dev_data;
 	struct usbatm_vcc_data *vcc_data = vcc->dev_data;
 
-	if (!instance || !vcc_data) {
-		dbg("%s: NULL data!", __func__);
+	if (!instance || !vcc_data)
 		return;
-	}
 
 	atm_dbg(instance, "%s entered\n", __func__);
 
@@ -929,10 +922,8 @@
 {
 	struct usbatm_data *instance = atm_dev->dev_data;
 
-	if (!instance || instance->disconnected) {
-		dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance");
+	if (!instance || instance->disconnected)
 		return -ENODEV;
-	}
 
 	switch (cmd) {
 	case ATM_QUERYLOOP:
@@ -1336,8 +1327,6 @@
 
 static int __init usbatm_usb_init(void)
 {
-	dbg("%s: driver version %s", __func__, DRIVER_VERSION);
-
 	if (sizeof(struct usbatm_control) > FIELD_SIZEOF(struct sk_buff, cb)) {
 		printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
 		return -EIO;
@@ -1357,7 +1346,6 @@
 
 static void __exit usbatm_usb_exit(void)
 {
-	dbg("%s", __func__);
 }
 module_exit(usbatm_usb_exit);
 
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
index 48ee0c5..14ec9f0 100644
--- a/drivers/usb/atm/xusbatm.c
+++ b/drivers/usb/atm/xusbatm.c
@@ -187,8 +187,6 @@
 {
 	int i;
 
-	dbg("xusbatm_init");
-
 	if (!num_vendor ||
 	    num_vendor != num_product ||
 	    num_vendor != num_rx_endpoint ||
@@ -221,8 +219,6 @@
 
 static void __exit xusbatm_exit(void)
 {
-	dbg("xusbatm_exit entered");
-
 	usb_deregister(&xusbatm_usb_driver);
 }
 module_exit(xusbatm_exit);
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
new file mode 100644
index 0000000..fd36dc8
--- /dev/null
+++ b/drivers/usb/chipidea/Kconfig
@@ -0,0 +1,32 @@
+config USB_CHIPIDEA
+	tristate "ChipIdea Highspeed Dual Role Controller"
+	depends on USB
+	help
+          Say Y here if your system has a dual role high speed USB
+          controller based on ChipIdea silicon IP. Currently, only the
+	  peripheral mode is supported.
+
+	  When compiled dynamically, the module will be called ci-hdrc.ko.
+
+if USB_CHIPIDEA
+
+config USB_CHIPIDEA_UDC
+	bool "ChipIdea device controller"
+	depends on USB_GADGET
+	select USB_GADGET_DUALSPEED
+	help
+	  Say Y here to enable device controller functionality of the
+	  ChipIdea driver.
+
+config USB_CHIPIDEA_HOST
+	bool "ChipIdea host controller"
+	help
+	  Say Y here to enable host controller functionality of the
+	  ChipIdea driver.
+
+config USB_CHIPIDEA_DEBUG
+	bool "ChipIdea driver debug"
+	help
+	  Say Y here to enable debugging output of the ChipIdea driver.
+
+endif
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
new file mode 100644
index 0000000..cc34937
--- /dev/null
+++ b/drivers/usb/chipidea/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_USB_CHIPIDEA)		+= ci_hdrc.o
+
+ci_hdrc-y				:= core.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)	+= debug.o
+
+ifneq ($(CONFIG_PCI),)
+	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_pci.o
+endif
+
+ifneq ($(CONFIG_ARCH_MSM),)
+	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_msm.o
+endif
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
new file mode 100644
index 0000000..050de85
--- /dev/null
+++ b/drivers/usb/chipidea/bits.h
@@ -0,0 +1,90 @@
+/*
+ * bits.h - register bits of the ChipIdea USB IP core
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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 __DRIVERS_USB_CHIPIDEA_BITS_H
+#define __DRIVERS_USB_CHIPIDEA_BITS_H
+
+#include <linux/usb/ehci_def.h>
+
+/* HCCPARAMS */
+#define HCCPARAMS_LEN         BIT(17)
+
+/* DCCPARAMS */
+#define DCCPARAMS_DEN         (0x1F << 0)
+#define DCCPARAMS_DC          BIT(7)
+#define DCCPARAMS_HC          BIT(8)
+
+/* TESTMODE */
+#define TESTMODE_FORCE        BIT(0)
+
+/* USBCMD */
+#define USBCMD_RS             BIT(0)
+#define USBCMD_RST            BIT(1)
+#define USBCMD_SUTW           BIT(13)
+#define USBCMD_ATDTW          BIT(14)
+
+/* USBSTS & USBINTR */
+#define USBi_UI               BIT(0)
+#define USBi_UEI              BIT(1)
+#define USBi_PCI              BIT(2)
+#define USBi_URI              BIT(6)
+#define USBi_SLI              BIT(8)
+
+/* DEVICEADDR */
+#define DEVICEADDR_USBADRA    BIT(24)
+#define DEVICEADDR_USBADR     (0x7FUL << 25)
+
+/* PORTSC */
+#define PORTSC_FPR            BIT(6)
+#define PORTSC_SUSP           BIT(7)
+#define PORTSC_HSP            BIT(9)
+#define PORTSC_PTC            (0x0FUL << 16)
+
+/* DEVLC */
+#define DEVLC_PSPD            (0x03UL << 25)
+#define    DEVLC_PSPD_HS      (0x02UL << 25)
+
+/* OTGSC */
+#define OTGSC_IDPU	      BIT(5)
+#define OTGSC_ID	      BIT(8)
+#define OTGSC_AVV	      BIT(9)
+#define OTGSC_ASV	      BIT(10)
+#define OTGSC_BSV	      BIT(11)
+#define OTGSC_BSE	      BIT(12)
+#define OTGSC_IDIS	      BIT(16)
+#define OTGSC_AVVIS	      BIT(17)
+#define OTGSC_ASVIS	      BIT(18)
+#define OTGSC_BSVIS	      BIT(19)
+#define OTGSC_BSEIS	      BIT(20)
+#define OTGSC_IDIE	      BIT(24)
+#define OTGSC_AVVIE	      BIT(25)
+#define OTGSC_ASVIE	      BIT(26)
+#define OTGSC_BSVIE	      BIT(27)
+#define OTGSC_BSEIE	      BIT(28)
+
+/* USBMODE */
+#define USBMODE_CM            (0x03UL <<  0)
+#define USBMODE_CM_DC         (0x02UL <<  0)
+#define USBMODE_SLOM          BIT(3)
+#define USBMODE_CI_SDIS       BIT(4)
+
+/* ENDPTCTRL */
+#define ENDPTCTRL_RXS         BIT(0)
+#define ENDPTCTRL_RXT         (0x03UL <<  2)
+#define ENDPTCTRL_RXR         BIT(6)         /* reserved for port 0 */
+#define ENDPTCTRL_RXE         BIT(7)
+#define ENDPTCTRL_TXS         BIT(16)
+#define ENDPTCTRL_TXT         (0x03UL << 18)
+#define ENDPTCTRL_TXR         BIT(22)        /* reserved for port 0 */
+#define ENDPTCTRL_TXE         BIT(23)
+
+#endif /* __DRIVERS_USB_CHIPIDEA_BITS_H */
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
new file mode 100644
index 0000000..50911f8
--- /dev/null
+++ b/drivers/usb/chipidea/ci.h
@@ -0,0 +1,313 @@
+/*
+ * ci.h - common structures, functions, and macros of the ChipIdea driver
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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 __DRIVERS_USB_CHIPIDEA_CI_H
+#define __DRIVERS_USB_CHIPIDEA_CI_H
+
+#include <linux/list.h>
+#include <linux/irqreturn.h>
+#include <linux/usb.h>
+#include <linux/usb/gadget.h>
+
+/******************************************************************************
+ * DEFINE
+ *****************************************************************************/
+#define CI13XXX_PAGE_SIZE  4096ul /* page size for TD's */
+#define ENDPT_MAX          32
+
+/******************************************************************************
+ * STRUCTURES
+ *****************************************************************************/
+/**
+ * struct ci13xxx_ep - endpoint representation
+ * @ep: endpoint structure for gadget drivers
+ * @dir: endpoint direction (TX/RX)
+ * @num: endpoint number
+ * @type: endpoint type
+ * @name: string description of the endpoint
+ * @qh: queue head for this endpoint
+ * @wedge: is the endpoint wedged
+ * @udc: pointer to the controller
+ * @lock: pointer to controller's spinlock
+ * @td_pool: pointer to controller's TD pool
+ */
+struct ci13xxx_ep {
+	struct usb_ep				ep;
+	u8					dir;
+	u8					num;
+	u8					type;
+	char					name[16];
+	struct {
+		struct list_head	queue;
+		struct ci13xxx_qh	*ptr;
+		dma_addr_t		dma;
+	}					qh;
+	int					wedge;
+
+	/* global resources */
+	struct ci13xxx				*udc;
+	spinlock_t				*lock;
+	struct dma_pool				*td_pool;
+};
+
+enum ci_role {
+	CI_ROLE_HOST = 0,
+	CI_ROLE_GADGET,
+	CI_ROLE_END,
+};
+
+/**
+ * struct ci_role_driver - host/gadget role driver
+ * start: start this role
+ * stop: stop this role
+ * irq: irq handler for this role
+ * name: role name string (host/gadget)
+ */
+struct ci_role_driver {
+	int		(*start)(struct ci13xxx *);
+	void		(*stop)(struct ci13xxx *);
+	irqreturn_t	(*irq)(struct ci13xxx *);
+	const char	*name;
+};
+
+/**
+ * struct hw_bank - hardware register mapping representation
+ * @lpm: set if the device is LPM capable
+ * @phys: physical address of the controller's registers
+ * @abs: absolute address of the beginning of register window
+ * @cap: capability registers
+ * @op: operational registers
+ * @size: size of the register window
+ * @regmap: register lookup table
+ */
+struct hw_bank {
+	unsigned	lpm;
+	resource_size_t	phys;
+	void __iomem	*abs;
+	void __iomem	*cap;
+	void __iomem	*op;
+	size_t		size;
+	void __iomem	**regmap;
+};
+
+/**
+ * struct ci13xxx - chipidea device representation
+ * @dev: pointer to parent device
+ * @lock: access synchronization
+ * @hw_bank: hardware register mapping
+ * @irq: IRQ number
+ * @roles: array of supported roles for this controller
+ * @role: current role
+ * @is_otg: if the device is otg-capable
+ * @work: work for role changing
+ * @wq: workqueue thread
+ * @qh_pool: allocation pool for queue heads
+ * @td_pool: allocation pool for transfer descriptors
+ * @gadget: device side representation for peripheral controller
+ * @driver: gadget driver
+ * @hw_ep_max: total number of endpoints supported by hardware
+ * @ci13xxx_ep: array of endpoints
+ * @ep0_dir: ep0 direction
+ * @ep0out: pointer to ep0 OUT endpoint
+ * @ep0in: pointer to ep0 IN endpoint
+ * @status: ep0 status request
+ * @setaddr: if we should set the address on status completion
+ * @address: usb address received from the host
+ * @remote_wakeup: host-enabled remote wakeup
+ * @suspended: suspended by host
+ * @test_mode: the selected test mode
+ * @udc_driver: platform specific information supplied by parent device
+ * @vbus_active: is VBUS active
+ * @transceiver: pointer to USB PHY, if any
+ * @hcd: pointer to usb_hcd for ehci host driver
+ */
+struct ci13xxx {
+	struct device			*dev;
+	spinlock_t			lock;
+	struct hw_bank			hw_bank;
+	int				irq;
+	struct ci_role_driver		*roles[CI_ROLE_END];
+	enum ci_role			role;
+	bool				is_otg;
+	struct work_struct		work;
+	struct workqueue_struct		*wq;
+
+	struct dma_pool			*qh_pool;
+	struct dma_pool			*td_pool;
+
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+	unsigned			hw_ep_max;
+	struct ci13xxx_ep		ci13xxx_ep[ENDPT_MAX];
+	u32				ep0_dir;
+	struct ci13xxx_ep		*ep0out, *ep0in;
+
+	struct usb_request		*status;
+	bool				setaddr;
+	u8				address;
+	u8				remote_wakeup;
+	u8				suspended;
+	u8				test_mode;
+
+	struct ci13xxx_udc_driver	*udc_driver;
+	int				vbus_active;
+	struct usb_phy			*transceiver;
+	struct usb_hcd			*hcd;
+};
+
+static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
+{
+	BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]);
+	return ci->roles[ci->role];
+}
+
+static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
+{
+	int ret;
+
+	if (role >= CI_ROLE_END)
+		return -EINVAL;
+
+	if (!ci->roles[role])
+		return -ENXIO;
+
+	ret = ci->roles[role]->start(ci);
+	if (!ret)
+		ci->role = role;
+	return ret;
+}
+
+static inline void ci_role_stop(struct ci13xxx *ci)
+{
+	enum ci_role role = ci->role;
+
+	if (role == CI_ROLE_END)
+		return;
+
+	ci->role = CI_ROLE_END;
+
+	ci->roles[role]->stop(ci);
+}
+
+/******************************************************************************
+ * REGISTERS
+ *****************************************************************************/
+/* register size */
+#define REG_BITS   (32)
+
+/* register indices */
+enum ci13xxx_regs {
+	CAP_CAPLENGTH,
+	CAP_HCCPARAMS,
+	CAP_DCCPARAMS,
+	CAP_TESTMODE,
+	CAP_LAST = CAP_TESTMODE,
+	OP_USBCMD,
+	OP_USBSTS,
+	OP_USBINTR,
+	OP_DEVICEADDR,
+	OP_ENDPTLISTADDR,
+	OP_PORTSC,
+	OP_DEVLC,
+	OP_OTGSC,
+	OP_USBMODE,
+	OP_ENDPTSETUPSTAT,
+	OP_ENDPTPRIME,
+	OP_ENDPTFLUSH,
+	OP_ENDPTSTAT,
+	OP_ENDPTCOMPLETE,
+	OP_ENDPTCTRL,
+	/* endptctrl1..15 follow */
+	OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2,
+};
+
+/**
+ * ffs_nr: find first (least significant) bit set
+ * @x: the word to search
+ *
+ * This function returns bit number (instead of position)
+ */
+static inline int ffs_nr(u32 x)
+{
+	int n = ffs(x);
+
+	return n ? n-1 : 32;
+}
+
+/**
+ * hw_read: reads from a hw register
+ * @reg:  register index
+ * @mask: bitfield mask
+ *
+ * This function returns register contents
+ */
+static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask)
+{
+	return ioread32(udc->hw_bank.regmap[reg]) & mask;
+}
+
+/**
+ * hw_write: writes to a hw register
+ * @reg:  register index
+ * @mask: bitfield mask
+ * @data: new value
+ */
+static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
+			    u32 mask, u32 data)
+{
+	if (~mask)
+		data = (ioread32(udc->hw_bank.regmap[reg]) & ~mask)
+			| (data & mask);
+
+	iowrite32(data, udc->hw_bank.regmap[reg]);
+}
+
+/**
+ * hw_test_and_clear: tests & clears a hw register
+ * @reg:  register index
+ * @mask: bitfield mask
+ *
+ * This function returns register contents
+ */
+static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg,
+				    u32 mask)
+{
+	u32 val = ioread32(udc->hw_bank.regmap[reg]) & mask;
+
+	iowrite32(val, udc->hw_bank.regmap[reg]);
+	return val;
+}
+
+/**
+ * hw_test_and_write: tests & writes a hw register
+ * @reg:  register index
+ * @mask: bitfield mask
+ * @data: new value
+ *
+ * This function returns register contents
+ */
+static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
+				    u32 mask, u32 data)
+{
+	u32 val = hw_read(udc, reg, ~0);
+
+	hw_write(udc, reg, mask, data);
+	return (val & mask) >> ffs_nr(mask);
+}
+
+int hw_device_reset(struct ci13xxx *ci, u32 mode);
+
+int hw_port_test_set(struct ci13xxx *ci, u8 mode);
+
+u8 hw_port_test_get(struct ci13xxx *ci);
+
+#endif	/* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/chipidea/ci13xxx_msm.c b/drivers/usb/chipidea/ci13xxx_msm.c
new file mode 100644
index 0000000..958069e
--- /dev/null
+++ b/drivers/usb/chipidea/ci13xxx_msm.c
@@ -0,0 +1,110 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/ulpi.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+
+#define MSM_USB_BASE	(udc->hw_bank.abs)
+
+static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
+{
+	struct device *dev = udc->gadget.dev.parent;
+	int val;
+
+	switch (event) {
+	case CI13XXX_CONTROLLER_RESET_EVENT:
+		dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+		writel(0, USB_AHBBURST);
+		writel(0, USB_AHBMODE);
+		break;
+	case CI13XXX_CONTROLLER_STOPPED_EVENT:
+		dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n");
+		/*
+		 * Put the transceiver in non-driving mode. Otherwise host
+		 * may not detect soft-disconnection.
+		 */
+		val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL);
+		val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+		val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+		usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
+		break;
+	default:
+		dev_dbg(dev, "unknown ci13xxx_udc event\n");
+		break;
+	}
+}
+
+static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
+	.name			= "ci13xxx_msm",
+	.flags			= CI13XXX_REGS_SHARED |
+				  CI13XXX_REQUIRE_TRANSCEIVER |
+				  CI13XXX_PULLUP_ON_VBUS |
+				  CI13XXX_DISABLE_STREAMING,
+
+	.notify_event		= ci13xxx_msm_notify_event,
+};
+
+static int ci13xxx_msm_probe(struct platform_device *pdev)
+{
+	struct platform_device *plat_ci;
+	int ret;
+
+	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
+
+	plat_ci = platform_device_alloc("ci_hdrc", -1);
+	if (!plat_ci) {
+		dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
+		return -ENOMEM;
+	}
+
+	ret = platform_device_add_resources(plat_ci, pdev->resource,
+					    pdev->num_resources);
+	if (ret) {
+		dev_err(&pdev->dev, "can't add resources to platform device\n");
+		goto put_platform;
+	}
+
+	ret = platform_device_add_data(plat_ci, &ci13xxx_msm_udc_driver,
+				       sizeof(ci13xxx_msm_udc_driver));
+	if (ret)
+		goto put_platform;
+
+	ret = platform_device_add(plat_ci);
+	if (ret)
+		goto put_platform;
+
+	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+
+put_platform:
+	platform_device_put(plat_ci);
+
+	return ret;
+}
+
+static struct platform_driver ci13xxx_msm_driver = {
+	.probe = ci13xxx_msm_probe,
+	.driver = { .name = "msm_hsusb", },
+};
+MODULE_ALIAS("platform:msm_hsusb");
+
+static int __init ci13xxx_msm_init(void)
+{
+	return platform_driver_register(&ci13xxx_msm_driver);
+}
+module_init(ci13xxx_msm_init);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/chipidea/ci13xxx_pci.c b/drivers/usb/chipidea/ci13xxx_pci.c
new file mode 100644
index 0000000..e3dab27
--- /dev/null
+++ b/drivers/usb/chipidea/ci13xxx_pci.c
@@ -0,0 +1,180 @@
+/*
+ * ci13xxx_pci.c - MIPS USB IP core family device controller
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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/platform_device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
+
+/* driver name */
+#define UDC_DRIVER_NAME   "ci13xxx_pci"
+
+/******************************************************************************
+ * PCI block
+ *****************************************************************************/
+struct ci13xxx_udc_driver pci_driver = {
+	.name		= UDC_DRIVER_NAME,
+	.capoffset	= DEF_CAPOFFSET,
+};
+
+struct ci13xxx_udc_driver langwell_pci_driver = {
+	.name		= UDC_DRIVER_NAME,
+	.capoffset	= 0,
+};
+
+struct ci13xxx_udc_driver penwell_pci_driver = {
+	.name		= UDC_DRIVER_NAME,
+	.capoffset	= 0,
+	.power_budget	= 200,
+};
+
+/**
+ * ci13xxx_pci_probe: PCI probe
+ * @pdev: USB device controller being probed
+ * @id:   PCI hotplug ID connecting controller to UDC framework
+ *
+ * This function returns an error code
+ * Allocates basic PCI resources for this USB device controller, and then
+ * invokes the udc_probe() method to start the UDC associated with it
+ */
+static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
+				       const struct pci_device_id *id)
+{
+	struct ci13xxx_udc_driver *driver = (void *)id->driver_data;
+	struct platform_device *plat_ci;
+	struct resource res[3];
+	int retval = 0, nres = 2;
+
+	if (!driver) {
+		dev_err(&pdev->dev, "device doesn't provide driver data\n");
+		return -ENODEV;
+	}
+
+	retval = pci_enable_device(pdev);
+	if (retval)
+		goto done;
+
+	if (!pdev->irq) {
+		dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
+		retval = -ENODEV;
+		goto disable_device;
+	}
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_set_master(pdev);
+	pci_try_set_mwi(pdev);
+
+	plat_ci = platform_device_alloc("ci_hdrc", -1);
+	if (!plat_ci) {
+		dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
+		retval = -ENOMEM;
+		goto disable_device;
+	}
+
+	memset(res, 0, sizeof(res));
+	res[0].start	= pci_resource_start(pdev, 0);
+	res[0].end	= pci_resource_end(pdev, 0);
+	res[0].flags	= IORESOURCE_MEM;
+	res[1].start	= pdev->irq;
+	res[1].flags	= IORESOURCE_IRQ;
+
+	retval = platform_device_add_resources(plat_ci, res, nres);
+	if (retval) {
+		dev_err(&pdev->dev, "can't add resources to platform device\n");
+		goto put_platform;
+	}
+
+	retval = platform_device_add_data(plat_ci, driver, sizeof(*driver));
+	if (retval)
+		goto put_platform;
+
+	dma_set_coherent_mask(&plat_ci->dev, pdev->dev.coherent_dma_mask);
+	plat_ci->dev.dma_mask = pdev->dev.dma_mask;
+	plat_ci->dev.dma_parms = pdev->dev.dma_parms;
+	plat_ci->dev.parent = &pdev->dev;
+
+	pci_set_drvdata(pdev, plat_ci);
+
+	retval = platform_device_add(plat_ci);
+	if (retval)
+		goto put_platform;
+
+	return 0;
+
+ put_platform:
+	pci_set_drvdata(pdev, NULL);
+	platform_device_put(plat_ci);
+ disable_device:
+	pci_disable_device(pdev);
+ done:
+	return retval;
+}
+
+/**
+ * ci13xxx_pci_remove: PCI remove
+ * @pdev: USB Device Controller being removed
+ *
+ * Reverses the effect of ci13xxx_pci_probe(),
+ * first invoking the udc_remove() and then releases
+ * all PCI resources allocated for this USB device controller
+ */
+static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
+{
+	struct platform_device *plat_ci = pci_get_drvdata(pdev);
+
+	platform_device_unregister(plat_ci);
+	pci_set_drvdata(pdev, NULL);
+	pci_disable_device(pdev);
+}
+
+/**
+ * PCI device table
+ * PCI device structure
+ *
+ * Check "pci.h" for details
+ */
+static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
+	{
+		PCI_DEVICE(0x153F, 0x1004),
+		.driver_data = (kernel_ulong_t)&pci_driver,
+	},
+	{
+		PCI_DEVICE(0x153F, 0x1006),
+		.driver_data = (kernel_ulong_t)&pci_driver,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
+		.driver_data = (kernel_ulong_t)&langwell_pci_driver,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
+		.driver_data = (kernel_ulong_t)&penwell_pci_driver,
+	},
+	{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
+
+static struct pci_driver ci13xxx_pci_driver = {
+	.name         =	UDC_DRIVER_NAME,
+	.id_table     =	ci13xxx_pci_id_table,
+	.probe        =	ci13xxx_pci_probe,
+	.remove       =	__devexit_p(ci13xxx_pci_remove),
+};
+
+module_pci_driver(ci13xxx_pci_driver);
+
+MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
+MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("June 2008");
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
new file mode 100644
index 0000000..15e03b3
--- /dev/null
+++ b/drivers/usb/chipidea/core.c
@@ -0,0 +1,474 @@
+/*
+ * core.c - ChipIdea USB IP core family device controller
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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.
+ */
+
+/*
+ * Description: ChipIdea USB IP core family device controller
+ *
+ * This driver is composed of several blocks:
+ * - HW:     hardware interface
+ * - DBG:    debug facilities (optional)
+ * - UTIL:   utilities
+ * - ISR:    interrupts handling
+ * - ENDPT:  endpoint operations (Gadget API)
+ * - GADGET: gadget operations (Gadget API)
+ * - BUS:    bus glue code, bus abstraction layer
+ *
+ * Compile Options
+ * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
+ * - STALL_IN:  non-empty bulk-in pipes cannot be halted
+ *              if defined mass storage compliance succeeds but with warnings
+ *              => case 4: Hi >  Dn
+ *              => case 5: Hi >  Di
+ *              => case 8: Hi <> Do
+ *              if undefined usbtest 13 fails
+ * - TRACE:     enable function tracing (depends on DEBUG)
+ *
+ * Main Features
+ * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
+ * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
+ * - Normal & LPM support
+ *
+ * USBTEST Report
+ * - OK: 0-12, 13 (STALL_IN defined) & 14
+ * - Not Supported: 15 & 16 (ISO)
+ *
+ * TODO List
+ * - OTG
+ * - Isochronous & Interrupt Traffic
+ * - Handle requests which spawns into several TDs
+ * - GET_STATUS(device) - always reports 0
+ * - Gadget API (majority of optional features)
+ * - Suspend & Remote Wakeup
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "host.h"
+#include "debug.h"
+
+/* Controller register map */
+static uintptr_t ci_regs_nolpm[] = {
+	[CAP_CAPLENGTH]		= 0x000UL,
+	[CAP_HCCPARAMS]		= 0x008UL,
+	[CAP_DCCPARAMS]		= 0x024UL,
+	[CAP_TESTMODE]		= 0x038UL,
+	[OP_USBCMD]		= 0x000UL,
+	[OP_USBSTS]		= 0x004UL,
+	[OP_USBINTR]		= 0x008UL,
+	[OP_DEVICEADDR]		= 0x014UL,
+	[OP_ENDPTLISTADDR]	= 0x018UL,
+	[OP_PORTSC]		= 0x044UL,
+	[OP_DEVLC]		= 0x084UL,
+	[OP_OTGSC]		= 0x064UL,
+	[OP_USBMODE]		= 0x068UL,
+	[OP_ENDPTSETUPSTAT]	= 0x06CUL,
+	[OP_ENDPTPRIME]		= 0x070UL,
+	[OP_ENDPTFLUSH]		= 0x074UL,
+	[OP_ENDPTSTAT]		= 0x078UL,
+	[OP_ENDPTCOMPLETE]	= 0x07CUL,
+	[OP_ENDPTCTRL]		= 0x080UL,
+};
+
+static uintptr_t ci_regs_lpm[] = {
+	[CAP_CAPLENGTH]		= 0x000UL,
+	[CAP_HCCPARAMS]		= 0x008UL,
+	[CAP_DCCPARAMS]		= 0x024UL,
+	[CAP_TESTMODE]		= 0x0FCUL,
+	[OP_USBCMD]		= 0x000UL,
+	[OP_USBSTS]		= 0x004UL,
+	[OP_USBINTR]		= 0x008UL,
+	[OP_DEVICEADDR]		= 0x014UL,
+	[OP_ENDPTLISTADDR]	= 0x018UL,
+	[OP_PORTSC]		= 0x044UL,
+	[OP_DEVLC]		= 0x084UL,
+	[OP_OTGSC]		= 0x0C4UL,
+	[OP_USBMODE]		= 0x0C8UL,
+	[OP_ENDPTSETUPSTAT]	= 0x0D8UL,
+	[OP_ENDPTPRIME]		= 0x0DCUL,
+	[OP_ENDPTFLUSH]		= 0x0E0UL,
+	[OP_ENDPTSTAT]		= 0x0E4UL,
+	[OP_ENDPTCOMPLETE]	= 0x0E8UL,
+	[OP_ENDPTCTRL]		= 0x0ECUL,
+};
+
+static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm)
+{
+	int i;
+
+	kfree(ci->hw_bank.regmap);
+
+	ci->hw_bank.regmap = kzalloc((OP_LAST + 1) * sizeof(void *),
+				     GFP_KERNEL);
+	if (!ci->hw_bank.regmap)
+		return -ENOMEM;
+
+	for (i = 0; i < OP_ENDPTCTRL; i++)
+		ci->hw_bank.regmap[i] =
+			(i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) +
+			(is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]);
+
+	for (; i <= OP_LAST; i++)
+		ci->hw_bank.regmap[i] = ci->hw_bank.op +
+			4 * (i - OP_ENDPTCTRL) +
+			(is_lpm
+			 ? ci_regs_lpm[OP_ENDPTCTRL]
+			 : ci_regs_nolpm[OP_ENDPTCTRL]);
+
+	return 0;
+}
+
+/**
+ * hw_port_test_set: writes port test mode (execute without interruption)
+ * @mode: new value
+ *
+ * This function returns an error code
+ */
+int hw_port_test_set(struct ci13xxx *ci, u8 mode)
+{
+	const u8 TEST_MODE_MAX = 7;
+
+	if (mode > TEST_MODE_MAX)
+		return -EINVAL;
+
+	hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
+	return 0;
+}
+
+/**
+ * hw_port_test_get: reads port test mode value
+ *
+ * This function returns port test mode value
+ */
+u8 hw_port_test_get(struct ci13xxx *ci)
+{
+	return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
+}
+
+static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
+{
+	u32 reg;
+
+	/* bank is a module variable */
+	ci->hw_bank.abs = base;
+
+	ci->hw_bank.cap = ci->hw_bank.abs;
+	ci->hw_bank.cap += ci->udc_driver->capoffset;
+	ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
+
+	hw_alloc_regmap(ci, false);
+	reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
+		ffs_nr(HCCPARAMS_LEN);
+	ci->hw_bank.lpm  = reg;
+	hw_alloc_regmap(ci, !!reg);
+	ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;
+	ci->hw_bank.size += OP_LAST;
+	ci->hw_bank.size /= sizeof(u32);
+
+	reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
+		ffs_nr(DCCPARAMS_DEN);
+	ci->hw_ep_max = reg * 2;   /* cache hw ENDPT_MAX */
+
+	if (ci->hw_ep_max > ENDPT_MAX)
+		return -ENODEV;
+
+	dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n",
+		ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op);
+
+	/* setup lock mode ? */
+
+	/* ENDPTSETUPSTAT is '0' by default */
+
+	/* HCSPARAMS.bf.ppc SHOULD BE zero for device */
+
+	return 0;
+}
+
+/**
+ * hw_device_reset: resets chip (execute without interruption)
+ * @ci: the controller
+  *
+ * This function returns an error code
+ */
+int hw_device_reset(struct ci13xxx *ci, u32 mode)
+{
+	/* should flush & stop before reset */
+	hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
+	hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+
+	hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);
+	while (hw_read(ci, OP_USBCMD, USBCMD_RST))
+		udelay(10);		/* not RTOS friendly */
+
+
+	if (ci->udc_driver->notify_event)
+		ci->udc_driver->notify_event(ci,
+			CI13XXX_CONTROLLER_RESET_EVENT);
+
+	if (ci->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
+		hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+
+	/* USBMODE should be configured step by step */
+	hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
+	hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
+	/* HW >= 2.3 */
+	hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
+
+	if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) {
+		pr_err("cannot enter in %s mode", ci_role(ci)->name);
+		pr_err("lpm = %i", ci->hw_bank.lpm);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * ci_otg_role - pick role based on ID pin state
+ * @ci: the controller
+ */
+static enum ci_role ci_otg_role(struct ci13xxx *ci)
+{
+	u32 sts = hw_read(ci, OP_OTGSC, ~0);
+	enum ci_role role = sts & OTGSC_ID
+		? CI_ROLE_GADGET
+		: CI_ROLE_HOST;
+
+	return role;
+}
+
+/**
+ * ci_role_work - perform role changing based on ID pin
+ * @work: work struct
+ */
+static void ci_role_work(struct work_struct *work)
+{
+	struct ci13xxx *ci = container_of(work, struct ci13xxx, work);
+	enum ci_role role = ci_otg_role(ci);
+
+	hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
+
+	if (role != ci->role) {
+		dev_dbg(ci->dev, "switching from %s to %s\n",
+			ci_role(ci)->name, ci->roles[role]->name);
+
+		ci_role_stop(ci);
+		ci_role_start(ci, role);
+	}
+}
+
+static ssize_t show_role(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct ci13xxx *ci = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", ci_role(ci)->name);
+}
+
+static ssize_t store_role(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct ci13xxx *ci = dev_get_drvdata(dev);
+	enum ci_role role;
+	int ret;
+
+	for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+		if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name))
+			break;
+
+	if (role == CI_ROLE_END || role == ci->role)
+		return -EINVAL;
+
+	ci_role_stop(ci);
+	ret = ci_role_start(ci, role);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role);
+
+static irqreturn_t ci_irq(int irq, void *data)
+{
+	struct ci13xxx *ci = data;
+	irqreturn_t ret = IRQ_NONE;
+
+	if (ci->is_otg) {
+		u32 sts = hw_read(ci, OP_OTGSC, ~0);
+
+		if (sts & OTGSC_IDIS) {
+			queue_work(ci->wq, &ci->work);
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci);
+}
+
+static int __devinit ci_hdrc_probe(struct platform_device *pdev)
+{
+	struct device	*dev = &pdev->dev;
+	struct ci13xxx	*ci;
+	struct resource	*res;
+	void __iomem	*base;
+	int		ret;
+
+	if (!dev->platform_data) {
+		dev_err(dev, "platform data missing\n");
+		return -ENODEV;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "missing resource\n");
+		return -ENODEV;
+	}
+
+	base = devm_request_and_ioremap(dev, res);
+	if (!res) {
+		dev_err(dev, "can't request and ioremap resource\n");
+		return -ENOMEM;
+	}
+
+	ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
+	if (!ci) {
+		dev_err(dev, "can't allocate device\n");
+		return -ENOMEM;
+	}
+
+	ci->dev = dev;
+	ci->udc_driver = dev->platform_data;
+
+	ret = hw_device_init(ci, base);
+	if (ret < 0) {
+		dev_err(dev, "can't initialize hardware\n");
+		return -ENODEV;
+	}
+
+	ci->hw_bank.phys = res->start;
+
+	ci->irq = platform_get_irq(pdev, 0);
+	if (ci->irq < 0) {
+		dev_err(dev, "missing IRQ\n");
+		return -ENODEV;
+	}
+
+	INIT_WORK(&ci->work, ci_role_work);
+	ci->wq = create_singlethread_workqueue("ci_otg");
+	if (!ci->wq) {
+		dev_err(dev, "can't create workqueue\n");
+		return -ENODEV;
+	}
+
+	/* initialize role(s) before the interrupt is requested */
+	ret = ci_hdrc_host_init(ci);
+	if (ret)
+		dev_info(dev, "doesn't support host\n");
+
+	ret = ci_hdrc_gadget_init(ci);
+	if (ret)
+		dev_info(dev, "doesn't support gadget\n");
+
+	if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
+		dev_err(dev, "no supported roles\n");
+		ret = -ENODEV;
+		goto rm_wq;
+	}
+
+	if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
+		ci->is_otg = true;
+		ci->role = ci_otg_role(ci);
+	} else {
+		ci->role = ci->roles[CI_ROLE_HOST]
+			? CI_ROLE_HOST
+			: CI_ROLE_GADGET;
+	}
+
+	ret = ci_role_start(ci, ci->role);
+	if (ret) {
+		dev_err(dev, "can't start %s role\n", ci_role(ci)->name);
+		ret = -ENODEV;
+		goto rm_wq;
+	}
+
+	platform_set_drvdata(pdev, ci);
+	ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->udc_driver->name,
+			  ci);
+	if (ret)
+		goto stop;
+
+	ret = device_create_file(dev, &dev_attr_role);
+	if (ret)
+		goto rm_attr;
+
+	if (ci->is_otg)
+		hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
+
+	return ret;
+
+rm_attr:
+	device_remove_file(dev, &dev_attr_role);
+stop:
+	ci_role_stop(ci);
+rm_wq:
+	flush_workqueue(ci->wq);
+	destroy_workqueue(ci->wq);
+
+	return ret;
+}
+
+static int __devexit ci_hdrc_remove(struct platform_device *pdev)
+{
+	struct ci13xxx *ci = platform_get_drvdata(pdev);
+
+	flush_workqueue(ci->wq);
+	destroy_workqueue(ci->wq);
+	device_remove_file(ci->dev, &dev_attr_role);
+	free_irq(ci->irq, ci);
+	ci_role_stop(ci);
+
+	return 0;
+}
+
+static struct platform_driver ci_hdrc_driver = {
+	.probe	= ci_hdrc_probe,
+	.remove	= __devexit_p(ci_hdrc_remove),
+	.driver	= {
+		.name	= "ci_hdrc",
+	},
+};
+
+module_platform_driver(ci_hdrc_driver);
+
+MODULE_ALIAS("platform:ci_hdrc");
+MODULE_ALIAS("platform:ci13xxx");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>");
+MODULE_DESCRIPTION("ChipIdea HDRC Driver");
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
new file mode 100644
index 0000000..c4b3e15
--- /dev/null
+++ b/drivers/usb/chipidea/debug.c
@@ -0,0 +1,804 @@
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "debug.h"
+
+/* Interrupt statistics */
+#define ISR_MASK   0x1F
+static struct isr_statistics {
+	u32 test;
+	u32 ui;
+	u32 uei;
+	u32 pci;
+	u32 uri;
+	u32 sli;
+	u32 none;
+	struct {
+		u32 cnt;
+		u32 buf[ISR_MASK+1];
+		u32 idx;
+	} hndl;
+} isr_statistics;
+
+void dbg_interrupt(u32 intmask)
+{
+	if (!intmask) {
+		isr_statistics.none++;
+		return;
+	}
+
+	isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask;
+	isr_statistics.hndl.idx &= ISR_MASK;
+	isr_statistics.hndl.cnt++;
+
+	if (USBi_URI & intmask)
+		isr_statistics.uri++;
+	if (USBi_PCI & intmask)
+		isr_statistics.pci++;
+	if (USBi_UEI & intmask)
+		isr_statistics.uei++;
+	if (USBi_UI  & intmask)
+		isr_statistics.ui++;
+	if (USBi_SLI & intmask)
+		isr_statistics.sli++;
+}
+
+/**
+ * hw_register_read: reads all device registers (execute without interruption)
+ * @buf:  destination buffer
+ * @size: buffer size
+ *
+ * This function returns number of registers read
+ */
+static size_t hw_register_read(struct ci13xxx *udc, u32 *buf, size_t size)
+{
+	unsigned i;
+
+	if (size > udc->hw_bank.size)
+		size = udc->hw_bank.size;
+
+	for (i = 0; i < size; i++)
+		buf[i] = hw_read(udc, i * sizeof(u32), ~0);
+
+	return size;
+}
+
+/**
+ * hw_register_write: writes to register
+ * @addr: register address
+ * @data: register value
+ *
+ * This function returns an error code
+ */
+static int hw_register_write(struct ci13xxx *udc, u16 addr, u32 data)
+{
+	/* align */
+	addr /= sizeof(u32);
+
+	if (addr >= udc->hw_bank.size)
+		return -EINVAL;
+
+	/* align */
+	addr *= sizeof(u32);
+
+	hw_write(udc, addr, ~0, data);
+	return 0;
+}
+
+/**
+ * hw_intr_clear: disables interrupt & clears interrupt status (execute without
+ *                interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_clear(struct ci13xxx *udc, int n)
+{
+	if (n >= REG_BITS)
+		return -EINVAL;
+
+	hw_write(udc, OP_USBINTR, BIT(n), 0);
+	hw_write(udc, OP_USBSTS,  BIT(n), BIT(n));
+	return 0;
+}
+
+/**
+ * hw_intr_force: enables interrupt & forces interrupt status (execute without
+ *                interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_force(struct ci13xxx *udc, int n)
+{
+	if (n >= REG_BITS)
+		return -EINVAL;
+
+	hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
+	hw_write(udc, OP_USBINTR,  BIT(n), BIT(n));
+	hw_write(udc, OP_USBSTS,   BIT(n), BIT(n));
+	hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, 0);
+	return 0;
+}
+
+/**
+ * show_device: prints information about device capabilities and status
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_device(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct usb_gadget *gadget = &udc->gadget;
+	int n = 0;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	n += scnprintf(buf + n, PAGE_SIZE - n, "speed             = %d\n",
+		       gadget->speed);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed         = %d\n",
+		       gadget->max_speed);
+	/* TODO: Scheduled for removal in 3.8. */
+	n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed      = %d\n",
+		       gadget_is_dualspeed(gadget));
+	n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg            = %d\n",
+		       gadget->is_otg);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral   = %d\n",
+		       gadget->is_a_peripheral);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable      = %d\n",
+		       gadget->b_hnp_enable);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support     = %d\n",
+		       gadget->a_hnp_support);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
+		       gadget->a_alt_hnp_support);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "name              = %s\n",
+		       (gadget->name ? gadget->name : ""));
+
+	return n;
+}
+static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
+
+/**
+ * show_driver: prints information about attached gadget (if any)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct usb_gadget_driver *driver = udc->driver;
+	int n = 0;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	if (driver == NULL)
+		return scnprintf(buf, PAGE_SIZE,
+				 "There is no gadget attached!\n");
+
+	n += scnprintf(buf + n, PAGE_SIZE - n, "function  = %s\n",
+		       (driver->function ? driver->function : ""));
+	n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
+		       driver->max_speed);
+
+	return n;
+}
+static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
+
+/* Maximum event message length */
+#define DBG_DATA_MSG   64UL
+
+/* Maximum event messages */
+#define DBG_DATA_MAX   128UL
+
+/* Event buffer descriptor */
+static struct {
+	char     (buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */
+	unsigned idx;   /* index */
+	unsigned tty;   /* print to console? */
+	rwlock_t lck;   /* lock */
+} dbg_data = {
+	.idx = 0,
+	.tty = 0,
+	.lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+/**
+ * dbg_dec: decrements debug event index
+ * @idx: buffer index
+ */
+static void dbg_dec(unsigned *idx)
+{
+	*idx = (*idx - 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_inc: increments debug event index
+ * @idx: buffer index
+ */
+static void dbg_inc(unsigned *idx)
+{
+	*idx = (*idx + 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_print:  prints the common part of the event
+ * @addr:   endpoint address
+ * @name:   event name
+ * @status: status
+ * @extra:  extra information
+ */
+static void dbg_print(u8 addr, const char *name, int status, const char *extra)
+{
+	struct timeval tval;
+	unsigned int stamp;
+	unsigned long flags;
+
+	write_lock_irqsave(&dbg_data.lck, flags);
+
+	do_gettimeofday(&tval);
+	stamp = tval.tv_sec & 0xFFFF;	/* 2^32 = 4294967296. Limit to 4096s */
+	stamp = stamp * 1000000 + tval.tv_usec;
+
+	scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
+		  "%04X\t? %02X %-7.7s %4i ?\t%s\n",
+		  stamp, addr, name, status, extra);
+
+	dbg_inc(&dbg_data.idx);
+
+	write_unlock_irqrestore(&dbg_data.lck, flags);
+
+	if (dbg_data.tty != 0)
+		pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
+			  stamp, addr, name, status, extra);
+}
+
+/**
+ * dbg_done: prints a DONE event
+ * @addr:   endpoint address
+ * @td:     transfer descriptor
+ * @status: status
+ */
+void dbg_done(u8 addr, const u32 token, int status)
+{
+	char msg[DBG_DATA_MSG];
+
+	scnprintf(msg, sizeof(msg), "%d %02X",
+		  (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
+		  (int)(token & TD_STATUS)      >> ffs_nr(TD_STATUS));
+	dbg_print(addr, "DONE", status, msg);
+}
+
+/**
+ * dbg_event: prints a generic event
+ * @addr:   endpoint address
+ * @name:   event name
+ * @status: status
+ */
+void dbg_event(u8 addr, const char *name, int status)
+{
+	if (name != NULL)
+		dbg_print(addr, name, status, "");
+}
+
+/*
+ * dbg_queue: prints a QUEUE event
+ * @addr:   endpoint address
+ * @req:    USB request
+ * @status: status
+ */
+void dbg_queue(u8 addr, const struct usb_request *req, int status)
+{
+	char msg[DBG_DATA_MSG];
+
+	if (req != NULL) {
+		scnprintf(msg, sizeof(msg),
+			  "%d %d", !req->no_interrupt, req->length);
+		dbg_print(addr, "QUEUE", status, msg);
+	}
+}
+
+/**
+ * dbg_setup: prints a SETUP event
+ * @addr: endpoint address
+ * @req:  setup request
+ */
+void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
+{
+	char msg[DBG_DATA_MSG];
+
+	if (req != NULL) {
+		scnprintf(msg, sizeof(msg),
+			  "%02X %02X %04X %04X %d", req->bRequestType,
+			  req->bRequest, le16_to_cpu(req->wValue),
+			  le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
+		dbg_print(addr, "SETUP", 0, msg);
+	}
+}
+
+/**
+ * show_events: displays the event buffer
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_events(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	unsigned long flags;
+	unsigned i, j, n = 0;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev->parent, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	read_lock_irqsave(&dbg_data.lck, flags);
+
+	i = dbg_data.idx;
+	for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
+		n += strlen(dbg_data.buf[i]);
+		if (n >= PAGE_SIZE) {
+			n -= strlen(dbg_data.buf[i]);
+			break;
+		}
+	}
+	for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
+		j += scnprintf(buf + j, PAGE_SIZE - j,
+			       "%s", dbg_data.buf[i]);
+
+	read_unlock_irqrestore(&dbg_data.lck, flags);
+
+	return n;
+}
+
+/**
+ * store_events: configure if events are going to be also printed to console
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_events(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned tty;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
+		dev_err(dev, "<1|0>: enable|disable console log\n");
+		goto done;
+	}
+
+	dbg_data.tty = tty;
+	dev_info(dev, "tty = %u", dbg_data.tty);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
+
+/**
+ * show_inters: interrupt status, enable status and historic
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	u32 intr;
+	unsigned i, j, n = 0;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/*n += scnprintf(buf + n, PAGE_SIZE - n,
+		       "status = %08x\n", hw_read_intr_status(udc));
+	n += scnprintf(buf + n, PAGE_SIZE - n,
+	"enable = %08x\n", hw_read_intr_enable(udc));*/
+
+	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
+		       isr_statistics.test);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? ui  = %d\n",
+		       isr_statistics.ui);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
+		       isr_statistics.uei);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
+		       isr_statistics.pci);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
+		       isr_statistics.uri);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
+		       isr_statistics.sli);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
+		       isr_statistics.none);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
+		       isr_statistics.hndl.cnt);
+
+	for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
+		i   &= ISR_MASK;
+		intr = isr_statistics.hndl.buf[i];
+
+		if (USBi_UI  & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "ui  ");
+		intr &= ~USBi_UI;
+		if (USBi_UEI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
+		intr &= ~USBi_UEI;
+		if (USBi_PCI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
+		intr &= ~USBi_PCI;
+		if (USBi_URI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
+		intr &= ~USBi_URI;
+		if (USBi_SLI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
+		intr &= ~USBi_SLI;
+		if (intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
+		if (isr_statistics.hndl.buf[i])
+			n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return n;
+}
+
+/**
+ * store_inters: enable & force or disable an individual interrutps
+ *                   (to be used for test purposes only)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned en, bit;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(udc->dev, "EINVAL\n");
+		goto done;
+	}
+
+	if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
+		dev_err(udc->dev, "<1|0> <bit>: enable|disable interrupt\n");
+		goto done;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (en) {
+		if (hw_intr_force(udc, bit))
+			dev_err(dev, "invalid bit number\n");
+		else
+			isr_statistics.test++;
+	} else {
+		if (hw_intr_clear(udc, bit))
+			dev_err(dev, "invalid bit number\n");
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
+
+/**
+ * show_port_test: reads port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_port_test(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned mode;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(udc->dev, "EINVAL\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	mode = hw_port_test_get(udc);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
+}
+
+/**
+ * store_port_test: writes port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_port_test(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned mode;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (sscanf(buf, "%u", &mode) != 1) {
+		dev_err(udc->dev, "<mode>: set port test mode");
+		goto done;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (hw_port_test_set(udc, mode))
+		dev_err(udc->dev, "invalid mode\n");
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
+		   show_port_test, store_port_test);
+
+/**
+ * show_qheads: DMA contents of all queue heads
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned i, j, n = 0;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	for (i = 0; i < udc->hw_ep_max/2; i++) {
+		struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
+		struct ci13xxx_ep *mEpTx =
+			&udc->ci13xxx_ep[i + udc->hw_ep_max/2];
+		n += scnprintf(buf + n, PAGE_SIZE - n,
+			       "EP=%02i: RX=%08X TX=%08X\n",
+			       i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
+		for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
+			n += scnprintf(buf + n, PAGE_SIZE - n,
+				       " %04X:    %08X    %08X\n", j,
+				       *((u32 *)mEpRx->qh.ptr + j),
+				       *((u32 *)mEpTx->qh.ptr + j));
+		}
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return n;
+}
+static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
+
+/**
+ * show_registers: dumps all registers
+ *
+ * Check "device.h" for details
+ */
+#define DUMP_ENTRIES	512
+static ssize_t show_registers(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	u32 *dump;
+	unsigned i, k, n = 0;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
+	if (!dump) {
+		dev_err(udc->dev, "%s: out of memory\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	k = hw_register_read(udc, dump, DUMP_ENTRIES);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	for (i = 0; i < k; i++) {
+		n += scnprintf(buf + n, PAGE_SIZE - n,
+			       "reg[0x%04X] = 0x%08X\n",
+			       i * (unsigned)sizeof(u32), dump[i]);
+	}
+	kfree(dump);
+
+	return n;
+}
+
+/**
+ * store_registers: writes value to register address
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_registers(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long addr, data, flags;
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (sscanf(buf, "%li %li", &addr, &data) != 2) {
+		dev_err(udc->dev,
+			"<addr> <data>: write data to register address\n");
+		goto done;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (hw_register_write(udc, addr, data))
+		dev_err(udc->dev, "invalid address range\n");
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
+		   show_registers, store_registers);
+
+/**
+ * show_requests: DMA contents of all requests currently queued (all endpts)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	struct list_head   *ptr = NULL;
+	struct ci13xxx_req *req = NULL;
+	unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+
+	if (attr == NULL || buf == NULL) {
+		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	for (i = 0; i < udc->hw_ep_max; i++)
+		list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
+		{
+			req = list_entry(ptr, struct ci13xxx_req, queue);
+
+			n += scnprintf(buf + n, PAGE_SIZE - n,
+					"EP=%02i: TD=%08X %s\n",
+					i % udc->hw_ep_max/2, (u32)req->dma,
+					((i < udc->hw_ep_max/2) ? "RX" : "TX"));
+
+			for (j = 0; j < qSize; j++)
+				n += scnprintf(buf + n, PAGE_SIZE - n,
+						" %04X:    %08X\n", j,
+						*((u32 *)req->ptr + j));
+		}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return n;
+}
+static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
+
+/**
+ * dbg_create_files: initializes the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+int dbg_create_files(struct device *dev)
+{
+	int retval = 0;
+
+	if (dev == NULL)
+		return -EINVAL;
+	retval = device_create_file(dev, &dev_attr_device);
+	if (retval)
+		goto done;
+	retval = device_create_file(dev, &dev_attr_driver);
+	if (retval)
+		goto rm_device;
+	retval = device_create_file(dev, &dev_attr_events);
+	if (retval)
+		goto rm_driver;
+	retval = device_create_file(dev, &dev_attr_inters);
+	if (retval)
+		goto rm_events;
+	retval = device_create_file(dev, &dev_attr_port_test);
+	if (retval)
+		goto rm_inters;
+	retval = device_create_file(dev, &dev_attr_qheads);
+	if (retval)
+		goto rm_port_test;
+	retval = device_create_file(dev, &dev_attr_registers);
+	if (retval)
+		goto rm_qheads;
+	retval = device_create_file(dev, &dev_attr_requests);
+	if (retval)
+		goto rm_registers;
+	return 0;
+
+ rm_registers:
+	device_remove_file(dev, &dev_attr_registers);
+ rm_qheads:
+	device_remove_file(dev, &dev_attr_qheads);
+ rm_port_test:
+	device_remove_file(dev, &dev_attr_port_test);
+ rm_inters:
+	device_remove_file(dev, &dev_attr_inters);
+ rm_events:
+	device_remove_file(dev, &dev_attr_events);
+ rm_driver:
+	device_remove_file(dev, &dev_attr_driver);
+ rm_device:
+	device_remove_file(dev, &dev_attr_device);
+ done:
+	return retval;
+}
+
+/**
+ * dbg_remove_files: destroys the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+int dbg_remove_files(struct device *dev)
+{
+	if (dev == NULL)
+		return -EINVAL;
+	device_remove_file(dev, &dev_attr_requests);
+	device_remove_file(dev, &dev_attr_registers);
+	device_remove_file(dev, &dev_attr_qheads);
+	device_remove_file(dev, &dev_attr_port_test);
+	device_remove_file(dev, &dev_attr_inters);
+	device_remove_file(dev, &dev_attr_events);
+	device_remove_file(dev, &dev_attr_driver);
+	device_remove_file(dev, &dev_attr_device);
+	return 0;
+}
diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h
new file mode 100644
index 0000000..80d9686
--- /dev/null
+++ b/drivers/usb/chipidea/debug.h
@@ -0,0 +1,56 @@
+/*
+ * debug.h - ChipIdea USB driver debug interfaces
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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 __DRIVERS_USB_CHIPIDEA_DEBUG_H
+#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
+
+#ifdef CONFIG_USB_CHIPIDEA_DEBUG
+void dbg_interrupt(u32 intmask);
+void dbg_done(u8 addr, const u32 token, int status);
+void dbg_event(u8 addr, const char *name, int status);
+void dbg_queue(u8 addr, const struct usb_request *req, int status);
+void dbg_setup(u8 addr, const struct usb_ctrlrequest *req);
+int dbg_create_files(struct device *dev);
+int dbg_remove_files(struct device *dev);
+#else
+static inline void dbg_interrupt(u32 intmask)
+{
+}
+
+static inline void dbg_done(u8 addr, const u32 token, int status)
+{
+}
+
+static inline void dbg_event(u8 addr, const char *name, int status)
+{
+}
+
+static inline void dbg_queue(u8 addr, const struct usb_request *req, int status)
+{
+}
+
+static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
+{
+}
+
+static inline int dbg_create_files(struct device *dev)
+{
+	return 0;
+}
+
+static inline int dbg_remove_files(struct device *dev)
+{
+	return 0;
+}
+#endif
+
+#endif /* __DRIVERS_USB_CHIPIDEA_DEBUG_H */
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
new file mode 100644
index 0000000..9eacd21
--- /dev/null
+++ b/drivers/usb/chipidea/host.c
@@ -0,0 +1,160 @@
+/*
+ * host.c - ChipIdea USB host controller driver
+ *
+ * Copyright (c) 2012 Intel Corporation
+ *
+ * Author: Alexander Shishkin
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/chipidea.h>
+
+#define CHIPIDEA_EHCI
+#include "../host/ehci-hcd.c"
+
+#include "ci.h"
+#include "bits.h"
+#include "host.h"
+
+static int ci_ehci_setup(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int ret;
+
+	hcd->has_tt = 1;
+
+	ret = ehci_setup(hcd);
+	if (ret)
+		return ret;
+
+	ehci_port_power(ehci, 0);
+
+	return ret;
+}
+
+static const struct hc_driver ci_ehci_hc_driver = {
+	.description	= "ehci_hcd",
+	.product_desc	= "ChipIdea HDRC EHCI",
+	.hcd_priv_size	= sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq	= ehci_irq,
+	.flags	= HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset		= ci_ehci_setup,
+	.start		= ehci_run,
+	.stop		= ehci_stop,
+	.shutdown	= ehci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.endpoint_reset		= ehci_endpoint_reset,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number = ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+	.bus_suspend		= ehci_bus_suspend,
+	.bus_resume		= ehci_bus_resume,
+	.relinquish_port	= ehci_relinquish_port,
+	.port_handed_over	= ehci_port_handed_over,
+
+	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static irqreturn_t host_irq(struct ci13xxx *ci)
+{
+	return usb_hcd_irq(ci->irq, ci->hcd);
+}
+
+static int host_start(struct ci13xxx *ci)
+{
+	struct usb_hcd *hcd;
+	struct ehci_hcd *ehci;
+	int ret;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	dev_set_drvdata(ci->dev, ci);
+	hcd->rsrc_start = ci->hw_bank.phys;
+	hcd->rsrc_len = ci->hw_bank.size;
+	hcd->regs = ci->hw_bank.abs;
+	hcd->has_tt = 1;
+
+	hcd->power_budget = ci->udc_driver->power_budget;
+
+	ehci = hcd_to_ehci(hcd);
+	ehci->caps = ci->hw_bank.cap;
+	ehci->has_hostpc = ci->hw_bank.lpm;
+
+	ret = usb_add_hcd(hcd, 0, 0);
+	if (ret)
+		usb_put_hcd(hcd);
+	else
+		ci->hcd = hcd;
+
+	return ret;
+}
+
+static void host_stop(struct ci13xxx *ci)
+{
+	struct usb_hcd *hcd = ci->hcd;
+
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+}
+
+int ci_hdrc_host_init(struct ci13xxx *ci)
+{
+	struct ci_role_driver *rdrv;
+
+	if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_HC))
+		return -ENXIO;
+
+	rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
+	if (!rdrv)
+		return -ENOMEM;
+
+	rdrv->start	= host_start;
+	rdrv->stop	= host_stop;
+	rdrv->irq	= host_irq;
+	rdrv->name	= "host";
+	ci->roles[CI_ROLE_HOST] = rdrv;
+
+	return 0;
+}
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
new file mode 100644
index 0000000..761fb1f
--- /dev/null
+++ b/drivers/usb/chipidea/host.h
@@ -0,0 +1,17 @@
+#ifndef __DRIVERS_USB_CHIPIDEA_HOST_H
+#define __DRIVERS_USB_CHIPIDEA_HOST_H
+
+#ifdef CONFIG_USB_CHIPIDEA_HOST
+
+int ci_hdrc_host_init(struct ci13xxx *ci);
+
+#else
+
+static inline int ci_hdrc_host_init(struct ci13xxx *ci)
+{
+	return -ENXIO;
+}
+
+#endif
+
+#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
new file mode 100644
index 0000000..51f9694
--- /dev/null
+++ b/drivers/usb/chipidea/udc.c
@@ -0,0 +1,1809 @@
+/*
+ * udc.c - ChipIdea UDC driver
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "debug.h"
+
+/* control endpoint description */
+static const struct usb_endpoint_descriptor
+ctrl_endpt_out_desc = {
+	.bLength         = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bEndpointAddress = USB_DIR_OUT,
+	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+static const struct usb_endpoint_descriptor
+ctrl_endpt_in_desc = {
+	.bLength         = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+/**
+ * hw_ep_bit: calculates the bit number
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns bit number
+ */
+static inline int hw_ep_bit(int num, int dir)
+{
+	return num + (dir ? 16 : 0);
+}
+
+static inline int ep_to_bit(struct ci13xxx *udc, int n)
+{
+	int fill = 16 - udc->hw_ep_max / 2;
+
+	if (n >= udc->hw_ep_max / 2)
+		n += fill;
+
+	return n;
+}
+
+/**
+ * hw_device_state: enables/disables interrupts & starts/stops device (execute
+ *                  without interruption)
+ * @dma: 0 => disable, !0 => enable and set dma engine
+ *
+ * This function returns an error code
+ */
+static int hw_device_state(struct ci13xxx *udc, u32 dma)
+{
+	if (dma) {
+		hw_write(udc, OP_ENDPTLISTADDR, ~0, dma);
+		/* interrupt, error, port change, reset, sleep/suspend */
+		hw_write(udc, OP_USBINTR, ~0,
+			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+		hw_write(udc, OP_USBCMD, USBCMD_RS, USBCMD_RS);
+	} else {
+		hw_write(udc, OP_USBCMD, USBCMD_RS, 0);
+		hw_write(udc, OP_USBINTR, ~0, 0);
+	}
+	return 0;
+}
+
+/**
+ * hw_ep_flush: flush endpoint fifo (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_flush(struct ci13xxx *udc, int num, int dir)
+{
+	int n = hw_ep_bit(num, dir);
+
+	do {
+		/* flush any pending transfer */
+		hw_write(udc, OP_ENDPTFLUSH, BIT(n), BIT(n));
+		while (hw_read(udc, OP_ENDPTFLUSH, BIT(n)))
+			cpu_relax();
+	} while (hw_read(udc, OP_ENDPTSTAT, BIT(n)));
+
+	return 0;
+}
+
+/**
+ * hw_ep_disable: disables endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_disable(struct ci13xxx *udc, int num, int dir)
+{
+	hw_ep_flush(udc, num, dir);
+	hw_write(udc, OP_ENDPTCTRL + num,
+		 dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
+	return 0;
+}
+
+/**
+ * hw_ep_enable: enables endpoint (execute without interruption)
+ * @num:  endpoint number
+ * @dir:  endpoint direction
+ * @type: endpoint type
+ *
+ * This function returns an error code
+ */
+static int hw_ep_enable(struct ci13xxx *udc, int num, int dir, int type)
+{
+	u32 mask, data;
+
+	if (dir) {
+		mask  = ENDPTCTRL_TXT;  /* type    */
+		data  = type << ffs_nr(mask);
+
+		mask |= ENDPTCTRL_TXS;  /* unstall */
+		mask |= ENDPTCTRL_TXR;  /* reset data toggle */
+		data |= ENDPTCTRL_TXR;
+		mask |= ENDPTCTRL_TXE;  /* enable  */
+		data |= ENDPTCTRL_TXE;
+	} else {
+		mask  = ENDPTCTRL_RXT;  /* type    */
+		data  = type << ffs_nr(mask);
+
+		mask |= ENDPTCTRL_RXS;  /* unstall */
+		mask |= ENDPTCTRL_RXR;  /* reset data toggle */
+		data |= ENDPTCTRL_RXR;
+		mask |= ENDPTCTRL_RXE;  /* enable  */
+		data |= ENDPTCTRL_RXE;
+	}
+	hw_write(udc, OP_ENDPTCTRL + num, mask, data);
+	return 0;
+}
+
+/**
+ * hw_ep_get_halt: return endpoint halt status
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns 1 if endpoint halted
+ */
+static int hw_ep_get_halt(struct ci13xxx *udc, int num, int dir)
+{
+	u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+
+	return hw_read(udc, OP_ENDPTCTRL + num, mask) ? 1 : 0;
+}
+
+/**
+ * hw_test_and_clear_setup_status: test & clear setup status (execute without
+ *                                 interruption)
+ * @n: endpoint number
+ *
+ * This function returns setup status
+ */
+static int hw_test_and_clear_setup_status(struct ci13xxx *udc, int n)
+{
+	n = ep_to_bit(udc, n);
+	return hw_test_and_clear(udc, OP_ENDPTSETUPSTAT, BIT(n));
+}
+
+/**
+ * hw_ep_prime: primes endpoint (execute without interruption)
+ * @num:     endpoint number
+ * @dir:     endpoint direction
+ * @is_ctrl: true if control endpoint
+ *
+ * This function returns an error code
+ */
+static int hw_ep_prime(struct ci13xxx *udc, int num, int dir, int is_ctrl)
+{
+	int n = hw_ep_bit(num, dir);
+
+	if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num)))
+		return -EAGAIN;
+
+	hw_write(udc, OP_ENDPTPRIME, BIT(n), BIT(n));
+
+	while (hw_read(udc, OP_ENDPTPRIME, BIT(n)))
+		cpu_relax();
+	if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num)))
+		return -EAGAIN;
+
+	/* status shoult be tested according with manual but it doesn't work */
+	return 0;
+}
+
+/**
+ * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
+ *                 without interruption)
+ * @num:   endpoint number
+ * @dir:   endpoint direction
+ * @value: true => stall, false => unstall
+ *
+ * This function returns an error code
+ */
+static int hw_ep_set_halt(struct ci13xxx *udc, int num, int dir, int value)
+{
+	if (value != 0 && value != 1)
+		return -EINVAL;
+
+	do {
+		enum ci13xxx_regs reg = OP_ENDPTCTRL + num;
+		u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+		u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
+
+		/* data toggle - reserved for EP0 but it's in ESS */
+		hw_write(udc, reg, mask_xs|mask_xr,
+			  value ? mask_xs : mask_xr);
+	} while (value != hw_ep_get_halt(udc, num, dir));
+
+	return 0;
+}
+
+/**
+ * hw_is_port_high_speed: test if port is high speed
+ *
+ * This function returns true if high speed port
+ */
+static int hw_port_is_high_speed(struct ci13xxx *udc)
+{
+	return udc->hw_bank.lpm ? hw_read(udc, OP_DEVLC, DEVLC_PSPD) :
+		hw_read(udc, OP_PORTSC, PORTSC_HSP);
+}
+
+/**
+ * hw_read_intr_enable: returns interrupt enable register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_enable(struct ci13xxx *udc)
+{
+	return hw_read(udc, OP_USBINTR, ~0);
+}
+
+/**
+ * hw_read_intr_status: returns interrupt status register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_status(struct ci13xxx *udc)
+{
+	return hw_read(udc, OP_USBSTS, ~0);
+}
+
+/**
+ * hw_test_and_clear_complete: test & clear complete status (execute without
+ *                             interruption)
+ * @n: endpoint number
+ *
+ * This function returns complete status
+ */
+static int hw_test_and_clear_complete(struct ci13xxx *udc, int n)
+{
+	n = ep_to_bit(udc, n);
+	return hw_test_and_clear(udc, OP_ENDPTCOMPLETE, BIT(n));
+}
+
+/**
+ * hw_test_and_clear_intr_active: test & clear active interrupts (execute
+ *                                without interruption)
+ *
+ * This function returns active interrutps
+ */
+static u32 hw_test_and_clear_intr_active(struct ci13xxx *udc)
+{
+	u32 reg = hw_read_intr_status(udc) & hw_read_intr_enable(udc);
+
+	hw_write(udc, OP_USBSTS, ~0, reg);
+	return reg;
+}
+
+/**
+ * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
+ *                                interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_clear_setup_guard(struct ci13xxx *udc)
+{
+	return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, 0);
+}
+
+/**
+ * hw_test_and_set_setup_guard: test & set setup guard (execute without
+ *                              interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_set_setup_guard(struct ci13xxx *udc)
+{
+	return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
+}
+
+/**
+ * hw_usb_set_address: configures USB address (execute without interruption)
+ * @value: new USB address
+ *
+ * This function explicitly sets the address, without the "USBADRA" (advance)
+ * feature, which is not supported by older versions of the controller.
+ */
+static void hw_usb_set_address(struct ci13xxx *udc, u8 value)
+{
+	hw_write(udc, OP_DEVICEADDR, DEVICEADDR_USBADR,
+		 value << ffs_nr(DEVICEADDR_USBADR));
+}
+
+/**
+ * hw_usb_reset: restart device after a bus reset (execute without
+ *               interruption)
+ *
+ * This function returns an error code
+ */
+static int hw_usb_reset(struct ci13xxx *udc)
+{
+	hw_usb_set_address(udc, 0);
+
+	/* ESS flushes only at end?!? */
+	hw_write(udc, OP_ENDPTFLUSH,    ~0, ~0);
+
+	/* clear setup token semaphores */
+	hw_write(udc, OP_ENDPTSETUPSTAT, 0,  0);
+
+	/* clear complete status */
+	hw_write(udc, OP_ENDPTCOMPLETE,  0,  0);
+
+	/* wait until all bits cleared */
+	while (hw_read(udc, OP_ENDPTPRIME, ~0))
+		udelay(10);             /* not RTOS friendly */
+
+	/* reset all endpoints ? */
+
+	/* reset internal status and wait for further instructions
+	   no need to verify the port reset status (ESS does it) */
+
+	return 0;
+}
+
+/******************************************************************************
+ * UTIL block
+ *****************************************************************************/
+/**
+ * _usb_addr: calculates endpoint address from direction & number
+ * @ep:  endpoint
+ */
+static inline u8 _usb_addr(struct ci13xxx_ep *ep)
+{
+	return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
+}
+
+/**
+ * _hardware_queue: configures a request at hardware level
+ * @gadget: gadget
+ * @mEp:    endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+	struct ci13xxx *udc = mEp->udc;
+	unsigned i;
+	int ret = 0;
+	unsigned length = mReq->req.length;
+
+	/* don't queue twice */
+	if (mReq->req.status == -EALREADY)
+		return -EALREADY;
+
+	mReq->req.status = -EALREADY;
+
+	if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
+		mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
+					   &mReq->zdma);
+		if (mReq->zptr == NULL)
+			return -ENOMEM;
+
+		memset(mReq->zptr, 0, sizeof(*mReq->zptr));
+		mReq->zptr->next    = TD_TERMINATE;
+		mReq->zptr->token   = TD_STATUS_ACTIVE;
+		if (!mReq->req.no_interrupt)
+			mReq->zptr->token   |= TD_IOC;
+	}
+	ret = usb_gadget_map_request(&udc->gadget, &mReq->req, mEp->dir);
+	if (ret)
+		return ret;
+
+	/*
+	 * TD configuration
+	 * TODO - handle requests which spawns into several TDs
+	 */
+	memset(mReq->ptr, 0, sizeof(*mReq->ptr));
+	mReq->ptr->token    = length << ffs_nr(TD_TOTAL_BYTES);
+	mReq->ptr->token   &= TD_TOTAL_BYTES;
+	mReq->ptr->token   |= TD_STATUS_ACTIVE;
+	if (mReq->zptr) {
+		mReq->ptr->next    = mReq->zdma;
+	} else {
+		mReq->ptr->next    = TD_TERMINATE;
+		if (!mReq->req.no_interrupt)
+			mReq->ptr->token  |= TD_IOC;
+	}
+	mReq->ptr->page[0]  = mReq->req.dma;
+	for (i = 1; i < 5; i++)
+		mReq->ptr->page[i] =
+			(mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
+
+	if (!list_empty(&mEp->qh.queue)) {
+		struct ci13xxx_req *mReqPrev;
+		int n = hw_ep_bit(mEp->num, mEp->dir);
+		int tmp_stat;
+
+		mReqPrev = list_entry(mEp->qh.queue.prev,
+				struct ci13xxx_req, queue);
+		if (mReqPrev->zptr)
+			mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
+		else
+			mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+		wmb();
+		if (hw_read(udc, OP_ENDPTPRIME, BIT(n)))
+			goto done;
+		do {
+			hw_write(udc, OP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
+			tmp_stat = hw_read(udc, OP_ENDPTSTAT, BIT(n));
+		} while (!hw_read(udc, OP_USBCMD, USBCMD_ATDTW));
+		hw_write(udc, OP_USBCMD, USBCMD_ATDTW, 0);
+		if (tmp_stat)
+			goto done;
+	}
+
+	/*  QH configuration */
+	mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
+	mEp->qh.ptr->td.token &= ~TD_STATUS;   /* clear status */
+	mEp->qh.ptr->cap |=  QH_ZLT;
+
+	wmb();   /* synchronize before ep prime */
+
+	ret = hw_ep_prime(udc, mEp->num, mEp->dir,
+			   mEp->type == USB_ENDPOINT_XFER_CONTROL);
+done:
+	return ret;
+}
+
+/**
+ * _hardware_dequeue: handles a request at hardware level
+ * @gadget: gadget
+ * @mEp:    endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+	if (mReq->req.status != -EALREADY)
+		return -EINVAL;
+
+	if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+		return -EBUSY;
+
+	if (mReq->zptr) {
+		if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
+			return -EBUSY;
+		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+		mReq->zptr = NULL;
+	}
+
+	mReq->req.status = 0;
+
+	usb_gadget_unmap_request(&mEp->udc->gadget, &mReq->req, mEp->dir);
+
+	mReq->req.status = mReq->ptr->token & TD_STATUS;
+	if ((TD_STATUS_HALTED & mReq->req.status) != 0)
+		mReq->req.status = -1;
+	else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
+		mReq->req.status = -1;
+	else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
+		mReq->req.status = -1;
+
+	mReq->req.actual   = mReq->ptr->token & TD_TOTAL_BYTES;
+	mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+	mReq->req.actual   = mReq->req.length - mReq->req.actual;
+	mReq->req.actual   = mReq->req.status ? 0 : mReq->req.actual;
+
+	return mReq->req.actual;
+}
+
+/**
+ * _ep_nuke: dequeues all endpoint requests
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int _ep_nuke(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	if (mEp == NULL)
+		return -EINVAL;
+
+	hw_ep_flush(mEp->udc, mEp->num, mEp->dir);
+
+	while (!list_empty(&mEp->qh.queue)) {
+
+		/* pop oldest request */
+		struct ci13xxx_req *mReq = \
+			list_entry(mEp->qh.queue.next,
+				   struct ci13xxx_req, queue);
+		list_del_init(&mReq->queue);
+		mReq->req.status = -ESHUTDOWN;
+
+		if (mReq->req.complete != NULL) {
+			spin_unlock(mEp->lock);
+			mReq->req.complete(&mEp->ep, &mReq->req);
+			spin_lock(mEp->lock);
+		}
+	}
+	return 0;
+}
+
+/**
+ * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
+ * @gadget: gadget
+ *
+ * This function returns an error code
+ */
+static int _gadget_stop_activity(struct usb_gadget *gadget)
+{
+	struct usb_ep *ep;
+	struct ci13xxx    *udc = container_of(gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->remote_wakeup = 0;
+	udc->suspended = 0;
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	/* flush all endpoints */
+	gadget_for_each_ep(ep, gadget) {
+		usb_ep_fifo_flush(ep);
+	}
+	usb_ep_fifo_flush(&udc->ep0out->ep);
+	usb_ep_fifo_flush(&udc->ep0in->ep);
+
+	if (udc->driver)
+		udc->driver->disconnect(gadget);
+
+	/* make sure to disable all endpoints */
+	gadget_for_each_ep(ep, gadget) {
+		usb_ep_disable(ep);
+	}
+
+	if (udc->status != NULL) {
+		usb_ep_free_request(&udc->ep0in->ep, udc->status);
+		udc->status = NULL;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ * ISR block
+ *****************************************************************************/
+/**
+ * isr_reset_handler: USB reset interrupt handler
+ * @udc: UDC device
+ *
+ * This function resets USB engine after a bus reset occurred
+ */
+static void isr_reset_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+	int retval;
+
+	dbg_event(0xFF, "BUS RST", 0);
+
+	spin_unlock(&udc->lock);
+	retval = _gadget_stop_activity(&udc->gadget);
+	if (retval)
+		goto done;
+
+	retval = hw_usb_reset(udc);
+	if (retval)
+		goto done;
+
+	udc->status = usb_ep_alloc_request(&udc->ep0in->ep, GFP_ATOMIC);
+	if (udc->status == NULL)
+		retval = -ENOMEM;
+
+done:
+	spin_lock(&udc->lock);
+
+	if (retval)
+		dev_err(udc->dev, "error: %i\n", retval);
+}
+
+/**
+ * isr_get_status_complete: get_status request complete function
+ * @ep:  endpoint
+ * @req: request handled
+ *
+ * Caller must release lock
+ */
+static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	if (ep == NULL || req == NULL)
+		return;
+
+	kfree(req->buf);
+	usb_ep_free_request(ep, req);
+}
+
+/**
+ * isr_get_status_response: get_status request response
+ * @udc: udc struct
+ * @setup: setup request packet
+ *
+ * This function returns an error code
+ */
+static int isr_get_status_response(struct ci13xxx *udc,
+				   struct usb_ctrlrequest *setup)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	struct ci13xxx_ep *mEp = udc->ep0in;
+	struct usb_request *req = NULL;
+	gfp_t gfp_flags = GFP_ATOMIC;
+	int dir, num, retval;
+
+	if (mEp == NULL || setup == NULL)
+		return -EINVAL;
+
+	spin_unlock(mEp->lock);
+	req = usb_ep_alloc_request(&mEp->ep, gfp_flags);
+	spin_lock(mEp->lock);
+	if (req == NULL)
+		return -ENOMEM;
+
+	req->complete = isr_get_status_complete;
+	req->length   = 2;
+	req->buf      = kzalloc(req->length, gfp_flags);
+	if (req->buf == NULL) {
+		retval = -ENOMEM;
+		goto err_free_req;
+	}
+
+	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+		/* Assume that device is bus powered for now. */
+		*(u16 *)req->buf = udc->remote_wakeup << 1;
+		retval = 0;
+	} else if ((setup->bRequestType & USB_RECIP_MASK) \
+		   == USB_RECIP_ENDPOINT) {
+		dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
+			TX : RX;
+		num =  le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
+		*(u16 *)req->buf = hw_ep_get_halt(udc, num, dir);
+	}
+	/* else do nothing; reserved for future use */
+
+	spin_unlock(mEp->lock);
+	retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
+	spin_lock(mEp->lock);
+	if (retval)
+		goto err_free_buf;
+
+	return 0;
+
+ err_free_buf:
+	kfree(req->buf);
+ err_free_req:
+	spin_unlock(mEp->lock);
+	usb_ep_free_request(&mEp->ep, req);
+	spin_lock(mEp->lock);
+	return retval;
+}
+
+/**
+ * isr_setup_status_complete: setup_status request complete function
+ * @ep:  endpoint
+ * @req: request handled
+ *
+ * Caller must release lock. Put the port in test mode if test mode
+ * feature is selected.
+ */
+static void
+isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci13xxx *udc = req->context;
+	unsigned long flags;
+
+	if (udc->setaddr) {
+		hw_usb_set_address(udc, udc->address);
+		udc->setaddr = false;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (udc->test_mode)
+		hw_port_test_set(udc, udc->test_mode);
+	spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+/**
+ * isr_setup_status_phase: queues the status phase of a setup transation
+ * @udc: udc struct
+ *
+ * This function returns an error code
+ */
+static int isr_setup_status_phase(struct ci13xxx *udc)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	int retval;
+	struct ci13xxx_ep *mEp;
+
+	mEp = (udc->ep0_dir == TX) ? udc->ep0out : udc->ep0in;
+	udc->status->context = udc;
+	udc->status->complete = isr_setup_status_complete;
+
+	spin_unlock(mEp->lock);
+	retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
+	spin_lock(mEp->lock);
+
+	return retval;
+}
+
+/**
+ * isr_tr_complete_low: transaction complete low level handler
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	struct ci13xxx_req *mReq, *mReqTemp;
+	struct ci13xxx_ep *mEpTemp = mEp;
+	int uninitialized_var(retval);
+
+	if (list_empty(&mEp->qh.queue))
+		return -EINVAL;
+
+	list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
+			queue) {
+		retval = _hardware_dequeue(mEp, mReq);
+		if (retval < 0)
+			break;
+		list_del_init(&mReq->queue);
+		dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
+		if (mReq->req.complete != NULL) {
+			spin_unlock(mEp->lock);
+			if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+					mReq->req.length)
+				mEpTemp = mEp->udc->ep0in;
+			mReq->req.complete(&mEpTemp->ep, &mReq->req);
+			spin_lock(mEp->lock);
+		}
+	}
+
+	if (retval == -EBUSY)
+		retval = 0;
+	if (retval < 0)
+		dbg_event(_usb_addr(mEp), "DONE", retval);
+
+	return retval;
+}
+
+/**
+ * isr_tr_complete_handler: transaction complete interrupt handler
+ * @udc: UDC descriptor
+ *
+ * This function handles traffic events
+ */
+static void isr_tr_complete_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+	unsigned i;
+	u8 tmode = 0;
+
+	for (i = 0; i < udc->hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp  = &udc->ci13xxx_ep[i];
+		int type, num, dir, err = -EINVAL;
+		struct usb_ctrlrequest req;
+
+		if (mEp->ep.desc == NULL)
+			continue;   /* not configured */
+
+		if (hw_test_and_clear_complete(udc, i)) {
+			err = isr_tr_complete_low(mEp);
+			if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+				if (err > 0)   /* needs status phase */
+					err = isr_setup_status_phase(udc);
+				if (err < 0) {
+					dbg_event(_usb_addr(mEp),
+						  "ERROR", err);
+					spin_unlock(&udc->lock);
+					if (usb_ep_set_halt(&mEp->ep))
+						dev_err(udc->dev,
+							"error: ep_set_halt\n");
+					spin_lock(&udc->lock);
+				}
+			}
+		}
+
+		if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
+		    !hw_test_and_clear_setup_status(udc, i))
+			continue;
+
+		if (i != 0) {
+			dev_warn(udc->dev, "ctrl traffic at endpoint %d\n", i);
+			continue;
+		}
+
+		/*
+		 * Flush data and handshake transactions of previous
+		 * setup packet.
+		 */
+		_ep_nuke(udc->ep0out);
+		_ep_nuke(udc->ep0in);
+
+		/* read_setup_packet */
+		do {
+			hw_test_and_set_setup_guard(udc);
+			memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
+		} while (!hw_test_and_clear_setup_guard(udc));
+
+		type = req.bRequestType;
+
+		udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
+
+		dbg_setup(_usb_addr(mEp), &req);
+
+		switch (req.bRequest) {
+		case USB_REQ_CLEAR_FEATURE:
+			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+					le16_to_cpu(req.wValue) ==
+					USB_ENDPOINT_HALT) {
+				if (req.wLength != 0)
+					break;
+				num  = le16_to_cpu(req.wIndex);
+				dir = num & USB_ENDPOINT_DIR_MASK;
+				num &= USB_ENDPOINT_NUMBER_MASK;
+				if (dir) /* TX */
+					num += udc->hw_ep_max/2;
+				if (!udc->ci13xxx_ep[num].wedge) {
+					spin_unlock(&udc->lock);
+					err = usb_ep_clear_halt(
+						&udc->ci13xxx_ep[num].ep);
+					spin_lock(&udc->lock);
+					if (err)
+						break;
+				}
+				err = isr_setup_status_phase(udc);
+			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
+					le16_to_cpu(req.wValue) ==
+					USB_DEVICE_REMOTE_WAKEUP) {
+				if (req.wLength != 0)
+					break;
+				udc->remote_wakeup = 0;
+				err = isr_setup_status_phase(udc);
+			} else {
+				goto delegate;
+			}
+			break;
+		case USB_REQ_GET_STATUS:
+			if (type != (USB_DIR_IN|USB_RECIP_DEVICE)   &&
+			    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
+			    type != (USB_DIR_IN|USB_RECIP_INTERFACE))
+				goto delegate;
+			if (le16_to_cpu(req.wLength) != 2 ||
+			    le16_to_cpu(req.wValue)  != 0)
+				break;
+			err = isr_get_status_response(udc, &req);
+			break;
+		case USB_REQ_SET_ADDRESS:
+			if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
+				goto delegate;
+			if (le16_to_cpu(req.wLength) != 0 ||
+			    le16_to_cpu(req.wIndex)  != 0)
+				break;
+			udc->address = (u8)le16_to_cpu(req.wValue);
+			udc->setaddr = true;
+			err = isr_setup_status_phase(udc);
+			break;
+		case USB_REQ_SET_FEATURE:
+			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+					le16_to_cpu(req.wValue) ==
+					USB_ENDPOINT_HALT) {
+				if (req.wLength != 0)
+					break;
+				num  = le16_to_cpu(req.wIndex);
+				dir = num & USB_ENDPOINT_DIR_MASK;
+				num &= USB_ENDPOINT_NUMBER_MASK;
+				if (dir) /* TX */
+					num += udc->hw_ep_max/2;
+
+				spin_unlock(&udc->lock);
+				err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
+				spin_lock(&udc->lock);
+				if (!err)
+					isr_setup_status_phase(udc);
+			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
+				if (req.wLength != 0)
+					break;
+				switch (le16_to_cpu(req.wValue)) {
+				case USB_DEVICE_REMOTE_WAKEUP:
+					udc->remote_wakeup = 1;
+					err = isr_setup_status_phase(udc);
+					break;
+				case USB_DEVICE_TEST_MODE:
+					tmode = le16_to_cpu(req.wIndex) >> 8;
+					switch (tmode) {
+					case TEST_J:
+					case TEST_K:
+					case TEST_SE0_NAK:
+					case TEST_PACKET:
+					case TEST_FORCE_EN:
+						udc->test_mode = tmode;
+						err = isr_setup_status_phase(
+								udc);
+						break;
+					default:
+						break;
+					}
+				default:
+					goto delegate;
+				}
+			} else {
+				goto delegate;
+			}
+			break;
+		default:
+delegate:
+			if (req.wLength == 0)   /* no data phase */
+				udc->ep0_dir = TX;
+
+			spin_unlock(&udc->lock);
+			err = udc->driver->setup(&udc->gadget, &req);
+			spin_lock(&udc->lock);
+			break;
+		}
+
+		if (err < 0) {
+			dbg_event(_usb_addr(mEp), "ERROR", err);
+
+			spin_unlock(&udc->lock);
+			if (usb_ep_set_halt(&mEp->ep))
+				dev_err(udc->dev, "error: ep_set_halt\n");
+			spin_lock(&udc->lock);
+		}
+	}
+}
+
+/******************************************************************************
+ * ENDPT block
+ *****************************************************************************/
+/**
+ * ep_enable: configure endpoint, making it usable
+ *
+ * Check usb_ep_enable() at "usb_gadget.h" for details
+ */
+static int ep_enable(struct usb_ep *ep,
+		     const struct usb_endpoint_descriptor *desc)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	int retval = 0;
+	unsigned long flags;
+
+	if (ep == NULL || desc == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	/* only internal SW should enable ctrl endpts */
+
+	mEp->ep.desc = desc;
+
+	if (!list_empty(&mEp->qh.queue))
+		dev_warn(mEp->udc->dev, "enabling a non-empty endpoint!\n");
+
+	mEp->dir  = usb_endpoint_dir_in(desc) ? TX : RX;
+	mEp->num  = usb_endpoint_num(desc);
+	mEp->type = usb_endpoint_type(desc);
+
+	mEp->ep.maxpacket = usb_endpoint_maxp(desc);
+
+	dbg_event(_usb_addr(mEp), "ENABLE", 0);
+
+	mEp->qh.ptr->cap = 0;
+
+	if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+		mEp->qh.ptr->cap |=  QH_IOS;
+	else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
+		mEp->qh.ptr->cap &= ~QH_MULT;
+	else
+		mEp->qh.ptr->cap &= ~QH_ZLT;
+
+	mEp->qh.ptr->cap |=
+		(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
+	mEp->qh.ptr->td.next |= TD_TERMINATE;   /* needed? */
+
+	/*
+	 * Enable endpoints in the HW other than ep0 as ep0
+	 * is always enabled
+	 */
+	if (mEp->num)
+		retval |= hw_ep_enable(mEp->udc, mEp->num, mEp->dir, mEp->type);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_disable: endpoint is no longer usable
+ *
+ * Check usb_ep_disable() at "usb_gadget.h" for details
+ */
+static int ep_disable(struct usb_ep *ep)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	int direction, retval = 0;
+	unsigned long flags;
+
+	if (ep == NULL)
+		return -EINVAL;
+	else if (mEp->ep.desc == NULL)
+		return -EBUSY;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	/* only internal SW should disable ctrl endpts */
+
+	direction = mEp->dir;
+	do {
+		dbg_event(_usb_addr(mEp), "DISABLE", 0);
+
+		retval |= _ep_nuke(mEp);
+		retval |= hw_ep_disable(mEp->udc, mEp->num, mEp->dir);
+
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+	} while (mEp->dir != direction);
+
+	mEp->ep.desc = NULL;
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_alloc_request: allocate a request object to use with this endpoint
+ *
+ * Check usb_ep_alloc_request() at "usb_gadget.h" for details
+ */
+static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep, struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = NULL;
+
+	if (ep == NULL)
+		return NULL;
+
+	mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
+	if (mReq != NULL) {
+		INIT_LIST_HEAD(&mReq->queue);
+
+		mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
+					   &mReq->dma);
+		if (mReq->ptr == NULL) {
+			kfree(mReq);
+			mReq = NULL;
+		}
+	}
+
+	dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
+
+	return (mReq == NULL) ? NULL : &mReq->req;
+}
+
+/**
+ * ep_free_request: frees a request object
+ *
+ * Check usb_ep_free_request() at "usb_gadget.h" for details
+ */
+static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	unsigned long flags;
+
+	if (ep == NULL || req == NULL) {
+		return;
+	} else if (!list_empty(&mReq->queue)) {
+		dev_err(mEp->udc->dev, "freeing queued request\n");
+		return;
+	}
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	if (mReq->ptr)
+		dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
+	kfree(mReq);
+
+	dbg_event(_usb_addr(mEp), "FREE", 0);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Check usb_ep_queue()* at usb_gadget.h" for details
+ */
+static int ep_queue(struct usb_ep *ep, struct usb_request *req,
+		    gfp_t __maybe_unused gfp_flags)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	struct ci13xxx *udc = mEp->udc;
+	int retval = 0;
+	unsigned long flags;
+
+	if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+		if (req->length)
+			mEp = (udc->ep0_dir == RX) ?
+			       udc->ep0out : udc->ep0in;
+		if (!list_empty(&mEp->qh.queue)) {
+			_ep_nuke(mEp);
+			retval = -EOVERFLOW;
+			dev_warn(mEp->udc->dev, "endpoint ctrl %X nuked\n",
+				 _usb_addr(mEp));
+		}
+	}
+
+	/* first nuke then test link, e.g. previous status has not sent */
+	if (!list_empty(&mReq->queue)) {
+		retval = -EBUSY;
+		dev_err(mEp->udc->dev, "request already in queue\n");
+		goto done;
+	}
+
+	if (req->length > 4 * CI13XXX_PAGE_SIZE) {
+		req->length = 4 * CI13XXX_PAGE_SIZE;
+		retval = -EMSGSIZE;
+		dev_warn(mEp->udc->dev, "request length truncated\n");
+	}
+
+	dbg_queue(_usb_addr(mEp), req, retval);
+
+	/* push request */
+	mReq->req.status = -EINPROGRESS;
+	mReq->req.actual = 0;
+
+	retval = _hardware_enqueue(mEp, mReq);
+
+	if (retval == -EALREADY) {
+		dbg_event(_usb_addr(mEp), "QUEUE", retval);
+		retval = 0;
+	}
+	if (!retval)
+		list_add_tail(&mReq->queue, &mEp->qh.queue);
+
+ done:
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
+ *
+ * Check usb_ep_dequeue() at "usb_gadget.h" for details
+ */
+static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	unsigned long flags;
+
+	if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
+		mEp->ep.desc == NULL || list_empty(&mReq->queue) ||
+		list_empty(&mEp->qh.queue))
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
+
+	hw_ep_flush(mEp->udc, mEp->num, mEp->dir);
+
+	/* pop request */
+	list_del_init(&mReq->queue);
+
+	usb_gadget_unmap_request(&mEp->udc->gadget, req, mEp->dir);
+
+	req->status = -ECONNRESET;
+
+	if (mReq->req.complete != NULL) {
+		spin_unlock(mEp->lock);
+		mReq->req.complete(&mEp->ep, &mReq->req);
+		spin_lock(mEp->lock);
+	}
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return 0;
+}
+
+/**
+ * ep_set_halt: sets the endpoint halt feature
+ *
+ * Check usb_ep_set_halt() at "usb_gadget.h" for details
+ */
+static int ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	int direction, retval = 0;
+	unsigned long flags;
+
+	if (ep == NULL || mEp->ep.desc == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+#ifndef STALL_IN
+	/* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
+	if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
+	    !list_empty(&mEp->qh.queue)) {
+		spin_unlock_irqrestore(mEp->lock, flags);
+		return -EAGAIN;
+	}
+#endif
+
+	direction = mEp->dir;
+	do {
+		dbg_event(_usb_addr(mEp), "HALT", value);
+		retval |= hw_ep_set_halt(mEp->udc, mEp->num, mEp->dir, value);
+
+		if (!value)
+			mEp->wedge = 0;
+
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+	} while (mEp->dir != direction);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_set_wedge: sets the halt feature and ignores clear requests
+ *
+ * Check usb_ep_set_wedge() at "usb_gadget.h" for details
+ */
+static int ep_set_wedge(struct usb_ep *ep)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	unsigned long flags;
+
+	if (ep == NULL || mEp->ep.desc == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	dbg_event(_usb_addr(mEp), "WEDGE", 0);
+	mEp->wedge = 1;
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+
+	return usb_ep_set_halt(ep);
+}
+
+/**
+ * ep_fifo_flush: flushes contents of a fifo
+ *
+ * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
+ */
+static void ep_fifo_flush(struct usb_ep *ep)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	unsigned long flags;
+
+	if (ep == NULL) {
+		dev_err(mEp->udc->dev, "%02X: -EINVAL\n", _usb_addr(mEp));
+		return;
+	}
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	dbg_event(_usb_addr(mEp), "FFLUSH", 0);
+	hw_ep_flush(mEp->udc, mEp->num, mEp->dir);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * Endpoint-specific part of the API to the USB controller hardware
+ * Check "usb_gadget.h" for details
+ */
+static const struct usb_ep_ops usb_ep_ops = {
+	.enable	       = ep_enable,
+	.disable       = ep_disable,
+	.alloc_request = ep_alloc_request,
+	.free_request  = ep_free_request,
+	.queue	       = ep_queue,
+	.dequeue       = ep_dequeue,
+	.set_halt      = ep_set_halt,
+	.set_wedge     = ep_set_wedge,
+	.fifo_flush    = ep_fifo_flush,
+};
+
+/******************************************************************************
+ * GADGET block
+ *****************************************************************************/
+static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+	int gadget_ready = 0;
+
+	if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
+		return -EOPNOTSUPP;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->vbus_active = is_active;
+	if (udc->driver)
+		gadget_ready = 1;
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	if (gadget_ready) {
+		if (is_active) {
+			pm_runtime_get_sync(&_gadget->dev);
+			hw_device_reset(udc, USBMODE_CM_DC);
+			hw_device_state(udc, udc->ep0out->qh.dma);
+		} else {
+			hw_device_state(udc, 0);
+			if (udc->udc_driver->notify_event)
+				udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_STOPPED_EVENT);
+			_gadget_stop_activity(&udc->gadget);
+			pm_runtime_put_sync(&_gadget->dev);
+		}
+	}
+
+	return 0;
+}
+
+static int ci13xxx_wakeup(struct usb_gadget *_gadget)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (!udc->remote_wakeup) {
+		ret = -EOPNOTSUPP;
+		goto out;
+	}
+	if (!hw_read(udc, OP_PORTSC, PORTSC_SUSP)) {
+		ret = -EINVAL;
+		goto out;
+	}
+	hw_write(udc, OP_PORTSC, PORTSC_FPR, PORTSC_FPR);
+out:
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return ret;
+}
+
+static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+
+	if (udc->transceiver)
+		return usb_phy_set_power(udc->transceiver, mA);
+	return -ENOTSUPP;
+}
+
+static int ci13xxx_start(struct usb_gadget *gadget,
+			 struct usb_gadget_driver *driver);
+static int ci13xxx_stop(struct usb_gadget *gadget,
+			struct usb_gadget_driver *driver);
+/**
+ * Device operations part of the API to the USB controller hardware,
+ * which don't involve endpoints (or i/o)
+ * Check  "usb_gadget.h" for details
+ */
+static const struct usb_gadget_ops usb_gadget_ops = {
+	.vbus_session	= ci13xxx_vbus_session,
+	.wakeup		= ci13xxx_wakeup,
+	.vbus_draw	= ci13xxx_vbus_draw,
+	.udc_start	= ci13xxx_start,
+	.udc_stop	= ci13xxx_stop,
+};
+
+static int init_eps(struct ci13xxx *udc)
+{
+	int retval = 0, i, j;
+
+	for (i = 0; i < udc->hw_ep_max/2; i++)
+		for (j = RX; j <= TX; j++) {
+			int k = i + j * udc->hw_ep_max/2;
+			struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
+
+			scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+					(j == TX)  ? "in" : "out");
+
+			mEp->udc          = udc;
+			mEp->lock         = &udc->lock;
+			mEp->td_pool      = udc->td_pool;
+
+			mEp->ep.name      = mEp->name;
+			mEp->ep.ops       = &usb_ep_ops;
+			mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+
+			INIT_LIST_HEAD(&mEp->qh.queue);
+			mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
+						     &mEp->qh.dma);
+			if (mEp->qh.ptr == NULL)
+				retval = -ENOMEM;
+			else
+				memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+
+			/*
+			 * set up shorthands for ep0 out and in endpoints,
+			 * don't add to gadget's ep_list
+			 */
+			if (i == 0) {
+				if (j == RX)
+					udc->ep0out = mEp;
+				else
+					udc->ep0in = mEp;
+
+				continue;
+			}
+
+			list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+		}
+
+	return retval;
+}
+
+/**
+ * ci13xxx_start: register a gadget driver
+ * @gadget: our gadget
+ * @driver: the driver being registered
+ *
+ * Interrupts are enabled here.
+ */
+static int ci13xxx_start(struct usb_gadget *gadget,
+			 struct usb_gadget_driver *driver)
+{
+	struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+	int retval = -ENOMEM;
+
+	if (driver->disconnect == NULL)
+		return -EINVAL;
+
+
+	udc->ep0out->ep.desc = &ctrl_endpt_out_desc;
+	retval = usb_ep_enable(&udc->ep0out->ep);
+	if (retval)
+		return retval;
+
+	udc->ep0in->ep.desc = &ctrl_endpt_in_desc;
+	retval = usb_ep_enable(&udc->ep0in->ep);
+	if (retval)
+		return retval;
+	spin_lock_irqsave(&udc->lock, flags);
+
+	udc->driver = driver;
+	pm_runtime_get_sync(&udc->gadget.dev);
+	if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
+		if (udc->vbus_active) {
+			if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
+				hw_device_reset(udc, USBMODE_CM_DC);
+		} else {
+			pm_runtime_put_sync(&udc->gadget.dev);
+			goto done;
+		}
+	}
+
+	retval = hw_device_state(udc, udc->ep0out->qh.dma);
+	if (retval)
+		pm_runtime_put_sync(&udc->gadget.dev);
+
+ done:
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return retval;
+}
+
+/**
+ * ci13xxx_stop: unregister a gadget driver
+ */
+static int ci13xxx_stop(struct usb_gadget *gadget,
+			struct usb_gadget_driver *driver)
+{
+	struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
+			udc->vbus_active) {
+		hw_device_state(udc, 0);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+			CI13XXX_CONTROLLER_STOPPED_EVENT);
+		udc->driver = NULL;
+		spin_unlock_irqrestore(&udc->lock, flags);
+		_gadget_stop_activity(&udc->gadget);
+		spin_lock_irqsave(&udc->lock, flags);
+		pm_runtime_put(&udc->gadget.dev);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+/******************************************************************************
+ * BUS block
+ *****************************************************************************/
+/**
+ * udc_irq: udc interrupt handler
+ *
+ * This function returns IRQ_HANDLED if the IRQ has been handled
+ * It locks access to registers
+ */
+static irqreturn_t udc_irq(struct ci13xxx *udc)
+{
+	irqreturn_t retval;
+	u32 intr;
+
+	if (udc == NULL)
+		return IRQ_HANDLED;
+
+	spin_lock(&udc->lock);
+
+	if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
+		if (hw_read(udc, OP_USBMODE, USBMODE_CM) !=
+				USBMODE_CM_DC) {
+			spin_unlock(&udc->lock);
+			return IRQ_NONE;
+		}
+	}
+	intr = hw_test_and_clear_intr_active(udc);
+	dbg_interrupt(intr);
+
+	if (intr) {
+		/* order defines priority - do NOT change it */
+		if (USBi_URI & intr)
+			isr_reset_handler(udc);
+
+		if (USBi_PCI & intr) {
+			udc->gadget.speed = hw_port_is_high_speed(udc) ?
+				USB_SPEED_HIGH : USB_SPEED_FULL;
+			if (udc->suspended && udc->driver->resume) {
+				spin_unlock(&udc->lock);
+				udc->driver->resume(&udc->gadget);
+				spin_lock(&udc->lock);
+				udc->suspended = 0;
+			}
+		}
+
+		if (USBi_UI  & intr)
+			isr_tr_complete_handler(udc);
+
+		if (USBi_SLI & intr) {
+			if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+			    udc->driver->suspend) {
+				udc->suspended = 1;
+				spin_unlock(&udc->lock);
+				udc->driver->suspend(&udc->gadget);
+				spin_lock(&udc->lock);
+			}
+		}
+		retval = IRQ_HANDLED;
+	} else {
+		retval = IRQ_NONE;
+	}
+	spin_unlock(&udc->lock);
+
+	return retval;
+}
+
+/**
+ * udc_release: driver release function
+ * @dev: device
+ *
+ * Currently does nothing
+ */
+static void udc_release(struct device *dev)
+{
+}
+
+/**
+ * udc_start: initialize gadget role
+ * @udc: chipidea controller
+ */
+static int udc_start(struct ci13xxx *udc)
+{
+	struct device *dev = udc->dev;
+	int retval = 0;
+
+	if (!udc)
+		return -EINVAL;
+
+	spin_lock_init(&udc->lock);
+
+	udc->gadget.ops          = &usb_gadget_ops;
+	udc->gadget.speed        = USB_SPEED_UNKNOWN;
+	udc->gadget.max_speed    = USB_SPEED_HIGH;
+	udc->gadget.is_otg       = 0;
+	udc->gadget.name         = udc->udc_driver->name;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+	dev_set_name(&udc->gadget.dev, "gadget");
+	udc->gadget.dev.dma_mask = dev->dma_mask;
+	udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
+	udc->gadget.dev.parent   = dev;
+	udc->gadget.dev.release  = udc_release;
+
+	/* alloc resources */
+	udc->qh_pool = dma_pool_create("ci13xxx_qh", dev,
+				       sizeof(struct ci13xxx_qh),
+				       64, CI13XXX_PAGE_SIZE);
+	if (udc->qh_pool == NULL)
+		return -ENOMEM;
+
+	udc->td_pool = dma_pool_create("ci13xxx_td", dev,
+				       sizeof(struct ci13xxx_td),
+				       64, CI13XXX_PAGE_SIZE);
+	if (udc->td_pool == NULL) {
+		retval = -ENOMEM;
+		goto free_qh_pool;
+	}
+
+	retval = init_eps(udc);
+	if (retval)
+		goto free_pools;
+
+	udc->gadget.ep0 = &udc->ep0in->ep;
+
+	udc->transceiver = usb_get_transceiver();
+
+	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+		if (udc->transceiver == NULL) {
+			retval = -ENODEV;
+			goto free_pools;
+		}
+	}
+
+	if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
+		retval = hw_device_reset(udc, USBMODE_CM_DC);
+		if (retval)
+			goto put_transceiver;
+	}
+
+	retval = device_register(&udc->gadget.dev);
+	if (retval) {
+		put_device(&udc->gadget.dev);
+		goto put_transceiver;
+	}
+
+	retval = dbg_create_files(&udc->gadget.dev);
+	if (retval)
+		goto unreg_device;
+
+	if (udc->transceiver) {
+		retval = otg_set_peripheral(udc->transceiver->otg,
+						&udc->gadget);
+		if (retval)
+			goto remove_dbg;
+	}
+
+	retval = usb_add_gadget_udc(dev, &udc->gadget);
+	if (retval)
+		goto remove_trans;
+
+	pm_runtime_no_callbacks(&udc->gadget.dev);
+	pm_runtime_enable(&udc->gadget.dev);
+
+	return retval;
+
+remove_trans:
+	if (udc->transceiver) {
+		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+		usb_put_transceiver(udc->transceiver);
+	}
+
+	dev_err(dev, "error = %i\n", retval);
+remove_dbg:
+	dbg_remove_files(&udc->gadget.dev);
+unreg_device:
+	device_unregister(&udc->gadget.dev);
+put_transceiver:
+	if (udc->transceiver)
+		usb_put_transceiver(udc->transceiver);
+free_pools:
+	dma_pool_destroy(udc->td_pool);
+free_qh_pool:
+	dma_pool_destroy(udc->qh_pool);
+	return retval;
+}
+
+/**
+ * udc_remove: parent remove must call this to remove UDC
+ *
+ * No interrupts active, the IRQ has been released
+ */
+static void udc_stop(struct ci13xxx *udc)
+{
+	int i;
+
+	if (udc == NULL)
+		return;
+
+	usb_del_gadget_udc(&udc->gadget);
+
+	for (i = 0; i < udc->hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+
+		dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
+	}
+
+	dma_pool_destroy(udc->td_pool);
+	dma_pool_destroy(udc->qh_pool);
+
+	if (udc->transceiver) {
+		otg_set_peripheral(udc->transceiver->otg, NULL);
+		usb_put_transceiver(udc->transceiver);
+	}
+	dbg_remove_files(&udc->gadget.dev);
+	device_unregister(&udc->gadget.dev);
+	/* my kobject is dynamic, I swear! */
+	memset(&udc->gadget, 0, sizeof(udc->gadget));
+}
+
+/**
+ * ci_hdrc_gadget_init - initialize device related bits
+ * ci: the controller
+ *
+ * This function enables the gadget role, if the device is "device capable".
+ */
+int ci_hdrc_gadget_init(struct ci13xxx *ci)
+{
+	struct ci_role_driver *rdrv;
+
+	if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
+		return -ENXIO;
+
+	rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
+	if (!rdrv)
+		return -ENOMEM;
+
+	rdrv->start	= udc_start;
+	rdrv->stop	= udc_stop;
+	rdrv->irq	= udc_irq;
+	rdrv->name	= "gadget";
+	ci->roles[CI_ROLE_GADGET] = rdrv;
+
+	return 0;
+}
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
new file mode 100644
index 0000000..4ff2384d
--- /dev/null
+++ b/drivers/usb/chipidea/udc.h
@@ -0,0 +1,93 @@
+/*
+ * udc.h - ChipIdea UDC structures
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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 __DRIVERS_USB_CHIPIDEA_UDC_H
+#define __DRIVERS_USB_CHIPIDEA_UDC_H
+
+#include <linux/list.h>
+
+#define CTRL_PAYLOAD_MAX   64
+#define RX        0  /* similar to USB_DIR_OUT but can be used as an index */
+#define TX        1  /* similar to USB_DIR_IN  but can be used as an index */
+
+/* DMA layout of transfer descriptors */
+struct ci13xxx_td {
+	/* 0 */
+	u32 next;
+#define TD_TERMINATE          BIT(0)
+#define TD_ADDR_MASK          (0xFFFFFFEUL << 5)
+	/* 1 */
+	u32 token;
+#define TD_STATUS             (0x00FFUL <<  0)
+#define TD_STATUS_TR_ERR      BIT(3)
+#define TD_STATUS_DT_ERR      BIT(5)
+#define TD_STATUS_HALTED      BIT(6)
+#define TD_STATUS_ACTIVE      BIT(7)
+#define TD_MULTO              (0x0003UL << 10)
+#define TD_IOC                BIT(15)
+#define TD_TOTAL_BYTES        (0x7FFFUL << 16)
+	/* 2 */
+	u32 page[5];
+#define TD_CURR_OFFSET        (0x0FFFUL <<  0)
+#define TD_FRAME_NUM          (0x07FFUL <<  0)
+#define TD_RESERVED_MASK      (0x0FFFUL <<  0)
+} __attribute__ ((packed));
+
+/* DMA layout of queue heads */
+struct ci13xxx_qh {
+	/* 0 */
+	u32 cap;
+#define QH_IOS                BIT(15)
+#define QH_MAX_PKT            (0x07FFUL << 16)
+#define QH_ZLT                BIT(29)
+#define QH_MULT               (0x0003UL << 30)
+	/* 1 */
+	u32 curr;
+	/* 2 - 8 */
+	struct ci13xxx_td        td;
+	/* 9 */
+	u32 RESERVED;
+	struct usb_ctrlrequest   setup;
+} __attribute__ ((packed));
+
+/**
+ * struct ci13xxx_req - usb request representation
+ * @req: request structure for gadget drivers
+ * @queue: link to QH list
+ * @ptr: transfer descriptor for this request
+ * @dma: dma address for the transfer descriptor
+ * @zptr: transfer descriptor for the zero packet
+ * @zdma: dma address of the zero packet's transfer descriptor
+ */
+struct ci13xxx_req {
+	struct usb_request	req;
+	struct list_head	queue;
+	struct ci13xxx_td	*ptr;
+	dma_addr_t		dma;
+	struct ci13xxx_td	*zptr;
+	dma_addr_t		zdma;
+};
+
+#ifdef CONFIG_USB_CHIPIDEA_UDC
+
+int ci_hdrc_gadget_init(struct ci13xxx *ci);
+
+#else
+
+static inline int ci_hdrc_gadget_init(struct ci13xxx *ci)
+{
+	return -ENXIO;
+}
+
+#endif
+
+#endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index b32ccb4..f2a120e 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1664,6 +1664,7 @@
 #ifdef CONFIG_PM
 	.supports_autosuspend = 1,
 #endif
+	.disable_hub_initiated_lpm = 1,
 };
 
 /*
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 0bb2b32..ea8b304 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -309,9 +309,6 @@
 
 static void cleanup(struct wdm_device *desc)
 {
-	spin_lock(&wdm_device_list_lock);
-	list_del(&desc->device_list);
-	spin_unlock(&wdm_device_list_lock);
 	kfree(desc->sbuf);
 	kfree(desc->inbuf);
 	kfree(desc->orq);
@@ -369,6 +366,7 @@
 	r = usb_autopm_get_interface(desc->intf);
 	if (r < 0) {
 		kfree(buf);
+		rv = usb_translate_errors(r);
 		goto outnp;
 	}
 
@@ -384,6 +382,7 @@
 
 	if (r < 0) {
 		kfree(buf);
+		rv = r;
 		goto out;
 	}
 
@@ -415,6 +414,7 @@
 		desc->outbuf = NULL;
 		clear_bit(WDM_IN_USE, &desc->flags);
 		dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv);
+		rv = usb_translate_errors(rv);
 	} else {
 		dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d",
 			req->wIndex);
@@ -530,11 +530,13 @@
 	struct wdm_device *desc = file->private_data;
 
 	wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags));
-	if (desc->werr < 0)
+
+	/* cannot dereference desc->intf if WDM_DISCONNECTING */
+	if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags))
 		dev_err(&desc->intf->dev, "Error in flush path: %d\n",
 			desc->werr);
 
-	return desc->werr;
+	return usb_translate_errors(desc->werr);
 }
 
 static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait)
@@ -545,7 +547,7 @@
 
 	spin_lock_irqsave(&desc->iuspin, flags);
 	if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
-		mask = POLLERR;
+		mask = POLLHUP | POLLERR;
 		spin_unlock_irqrestore(&desc->iuspin, flags);
 		goto desc_out;
 	}
@@ -596,6 +598,7 @@
 			desc->count--;
 			dev_err(&desc->intf->dev,
 				"Error submitting int urb - %d\n", rv);
+			rv = usb_translate_errors(rv);
 		}
 	} else {
 		rv = 0;
@@ -621,10 +624,15 @@
 	mutex_unlock(&desc->wlock);
 
 	if (!desc->count) {
-		dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
-		kill_urbs(desc);
-		if (!test_bit(WDM_DISCONNECTING, &desc->flags))
+		if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
+			dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
+			kill_urbs(desc);
 			desc->manage_power(desc->intf, 0);
+		} else {
+			/* must avoid dev_printk here as desc->intf is invalid */
+			pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__);
+			cleanup(desc);
+		}
 	}
 	mutex_unlock(&wdm_mutex);
 	return 0;
@@ -771,6 +779,9 @@
 out:
 	return rv;
 err:
+	spin_lock(&wdm_device_list_lock);
+	list_del(&desc->device_list);
+	spin_unlock(&wdm_device_list_lock);
 	cleanup(desc);
 	return rv;
 }
@@ -896,8 +907,16 @@
 	cancel_work_sync(&desc->rxwork);
 	mutex_unlock(&desc->wlock);
 	mutex_unlock(&desc->rlock);
+
+	/* the desc->intf pointer used as list key is now invalid */
+	spin_lock(&wdm_device_list_lock);
+	list_del(&desc->device_list);
+	spin_unlock(&wdm_device_list_lock);
+
 	if (!desc->count)
 		cleanup(desc);
+	else
+		dev_dbg(&intf->dev, "%s: %d open files - postponing cleanup\n", __func__, desc->count);
 	mutex_unlock(&wdm_mutex);
 }
 
@@ -1015,6 +1034,7 @@
 	.post_reset =	wdm_post_reset,
 	.id_table =	wdm_ids,
 	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(wdm_driver);
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index a68c1a6..d4c47d5 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -172,27 +172,31 @@
 #ifdef DEBUG
 static void usblp_dump(struct usblp *usblp)
 {
+	struct device *dev = &usblp->intf->dev;
 	int p;
 
-	dbg("usblp=0x%p", usblp);
-	dbg("dev=0x%p", usblp->dev);
-	dbg("present=%d", usblp->present);
-	dbg("readbuf=0x%p", usblp->readbuf);
-	dbg("readcount=%d", usblp->readcount);
-	dbg("ifnum=%d", usblp->ifnum);
-    for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
-	dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting);
-	dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite);
-	dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread);
-    }
-	dbg("current_protocol=%d", usblp->current_protocol);
-	dbg("minor=%d", usblp->minor);
-	dbg("wstatus=%d", usblp->wstatus);
-	dbg("rstatus=%d", usblp->rstatus);
-	dbg("quirks=%d", usblp->quirks);
-	dbg("used=%d", usblp->used);
-	dbg("bidir=%d", usblp->bidir);
-	dbg("device_id_string=\"%s\"",
+	dev_dbg(dev, "usblp=0x%p\n", usblp);
+	dev_dbg(dev, "dev=0x%p\n", usblp->dev);
+	dev_dbg(dev, "present=%d\n", usblp->present);
+	dev_dbg(dev, "readbuf=0x%p\n", usblp->readbuf);
+	dev_dbg(dev, "readcount=%d\n", usblp->readcount);
+	dev_dbg(dev, "ifnum=%d\n", usblp->ifnum);
+	for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
+		dev_dbg(dev, "protocol[%d].alt_setting=%d\n", p,
+			usblp->protocol[p].alt_setting);
+		dev_dbg(dev, "protocol[%d].epwrite=%p\n", p,
+			usblp->protocol[p].epwrite);
+		dev_dbg(dev, "protocol[%d].epread=%p\n", p,
+			usblp->protocol[p].epread);
+	}
+	dev_dbg(dev, "current_protocol=%d\n", usblp->current_protocol);
+	dev_dbg(dev, "minor=%d\n", usblp->minor);
+	dev_dbg(dev, "wstatus=%d\n", usblp->wstatus);
+	dev_dbg(dev, "rstatus=%d\n", usblp->rstatus);
+	dev_dbg(dev, "quirks=%d\n", usblp->quirks);
+	dev_dbg(dev, "used=%d\n", usblp->used);
+	dev_dbg(dev, "bidir=%d\n", usblp->bidir);
+	dev_dbg(dev, "device_id_string=\"%s\"\n",
 		usblp->device_id_string ?
 			usblp->device_id_string + 2 :
 			(unsigned char *)"(null)");
@@ -262,7 +266,8 @@
 	retval = usb_control_msg(usblp->dev,
 		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
 		request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
-	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
+	dev_dbg(&usblp->intf->dev,
+		"usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d\n",
 		request, !!dir, recip, value, index, len, retval);
 	return retval < 0 ? retval : 0;
 }
@@ -500,8 +505,9 @@
 		goto done;
 	}
 
-	dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
-		_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));
+	dev_dbg(&usblp->intf->dev,
+		"usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)\n", cmd,
+		_IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));
 
 	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */
 
@@ -594,7 +600,8 @@
 				goto done;
 			}
 
-			dbg("usblp%d requested/got HP channel %ld/%d",
+			dev_dbg(&usblp->intf->dev,
+				"usblp%d requested/got HP channel %ld/%d\n",
 				usblp->minor, arg, newChannel);
 			break;
 
@@ -614,7 +621,8 @@
 				goto done;
 			}
 
-			dbg("usblp%d is bus=%d, device=%d",
+			dev_dbg(&usblp->intf->dev,
+				"usblp%d is bus=%d, device=%d\n",
 				usblp->minor, twoints[0], twoints[1]);
 			break;
 
@@ -634,7 +642,8 @@
 				goto done;
 			}
 
-			dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
+			dev_dbg(&usblp->intf->dev,
+				"usblp%d is VID=0x%4.4X, PID=0x%4.4X\n",
 				usblp->minor, twoints[0], twoints[1]);
 			break;
 
@@ -987,7 +996,7 @@
 	usblp->rcomplete = 0;
 	spin_unlock_irqrestore(&usblp->lock, flags);
 	if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
-		dbg("error submitting urb (%d)", rc);
+		dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc);
 		spin_lock_irqsave(&usblp->lock, flags);
 		usblp->rstatus = rc;
 		usblp->rcomplete = 1;
@@ -1129,7 +1138,8 @@
 	/* Analyze and pick initial alternate settings and endpoints. */
 	protocol = usblp_select_alts(usblp);
 	if (protocol < 0) {
-		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
+		dev_dbg(&intf->dev,
+			"incompatible printer-class device 0x%4.4X/0x%4.4X\n",
 			le16_to_cpu(dev->descriptor.idVendor),
 			le16_to_cpu(dev->descriptor.idProduct));
 		retval = -ENODEV;
@@ -1158,14 +1168,14 @@
 
 	retval = usb_register_dev(intf, &usblp_class);
 	if (retval) {
-		printk(KERN_ERR "usblp: Not able to get a minor"
-		    " (base %u, slice default): %d\n",
-		    USBLP_MINOR_BASE, retval);
+		dev_err(&intf->dev,
+			"usblp: Not able to get a minor (base %u, slice default): %d\n",
+			USBLP_MINOR_BASE, retval);
 		goto abort_intfdata;
 	}
 	usblp->minor = intf->minor;
-	printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d "
-		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
+	dev_info(&intf->dev,
+		"usblp%d: USB %sdirectional printer dev %d if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
 		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
 		usblp->ifnum,
 		usblp->protocol[usblp->current_protocol].alt_setting,
@@ -1302,7 +1312,8 @@
 
 	usblp->bidir = (usblp->protocol[protocol].epread != NULL);
 	usblp->current_protocol = protocol;
-	dbg("usblp%d set protocol %d", usblp->minor, protocol);
+	dev_dbg(&usblp->intf->dev, "usblp%d set protocol %d\n",
+		usblp->minor, protocol);
 	return 0;
 }
 
@@ -1315,7 +1326,8 @@
 
 	err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1);
 	if (err < 0) {
-		dbg("usblp%d: error = %d reading IEEE-1284 Device ID string",
+		dev_dbg(&usblp->intf->dev,
+			"usblp%d: error = %d reading IEEE-1284 Device ID string\n",
 			usblp->minor, err);
 		usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
 		return -EIO;
@@ -1331,7 +1343,7 @@
 		length = USBLP_DEVICE_ID_SIZE - 1;
 	usblp->device_id_string[length] = '\0';
 
-	dbg("usblp%d Device ID string [len=%d]=\"%s\"",
+	dev_dbg(&usblp->intf->dev, "usblp%d Device ID string [len=%d]=\"%s\"\n",
 		usblp->minor, length, &usblp->device_id_string[2]);
 
 	return length;
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 18d02e3..9981984 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -27,58 +27,6 @@
 comment "Miscellaneous USB options"
 	depends on USB
 
-config USB_DEVICEFS
-	bool "USB device filesystem (DEPRECATED)"
-	depends on USB
-	---help---
-	  If you say Y here (and to "/proc file system support" in the "File
-	  systems" section, above), you will get a file /proc/bus/usb/devices
-	  which lists the devices currently connected to your USB bus or
-	  busses, and for every connected device a file named
-	  "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the
-	  device number; the latter files can be used by user space programs
-	  to talk directly to the device. These files are "virtual", meaning
-	  they are generated on the fly and not stored on the hard drive.
-
-	  You may need to mount the usbfs file system to see the files, use
-	  mount -t usbfs none /proc/bus/usb
-
-	  For the format of the various /proc/bus/usb/ files, please read
-	  <file:Documentation/usb/proc_usb_info.txt>.
-
-	  Modern Linux systems do not use this.
-
-	  Usbfs entries are files and not character devices; usbfs can't
-	  handle Access Control Lists (ACL) which are the default way to
-	  grant access to USB devices for untrusted users of a desktop
-	  system.
-
-	  The usbfs functionality is replaced by real device-nodes managed by
-	  udev.  These nodes lived in /dev/bus/usb and are used by libusb.
-
-config USB_DEVICE_CLASS
-	bool "USB device class-devices (DEPRECATED)"
-	depends on USB
-	default y
-	---help---
-	  Userspace access to USB devices is granted by device-nodes exported
-	  directly from the usbdev in sysfs. Old versions of the driver
-	  core and udev needed additional class devices to export device nodes.
-
-	  These additional devices are difficult to handle in userspace, if
-	  information about USB interfaces must be available. One device
-	  contains the device node, the other device contains the interface
-	  data. Both devices are at the same level in sysfs (siblings) and one
-	  can't access the other. The device node created directly by the
-	  usb device is the parent device of the interface and therefore
-	  easily accessible from the interface event.
-
-	  This option provides backward compatibility for libusb device
-	  nodes (lsusb) when usbfs is not used, and the following udev rule
-	  doesn't exist:
-	    SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \
-	    NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644"
-
 config USB_DYNAMIC_MINORS
 	bool "Dynamic USB minor allocation"
 	depends on USB
@@ -125,7 +73,6 @@
 	bool "Rely on OTG Targeted Peripherals List"
 	depends on USB_OTG || EXPERT
 	default y if USB_OTG
-	default n if EXPERT
 	help
 	  If you say Y here, the "otg_whitelist.h" file will be used as a
 	  product whitelist, so USB peripherals not listed there will be
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 507a4e1..26059b9 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -9,6 +9,6 @@
 usbcore-y += devio.o notify.o generic.o quirks.o devices.o
 
 usbcore-$(CONFIG_PCI)		+= hcd-pci.o
-usbcore-$(CONFIG_USB_DEVICEFS)	+= inode.o
+usbcore-$(CONFIG_ACPI)		+= usb-acpi.o
 
 obj-$(CONFIG_USB)		+= usbcore.o
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 8df4b76..e0f1079 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -333,17 +333,14 @@
 static struct async *async_getpending(struct dev_state *ps,
 					     void __user *userurb)
 {
-	unsigned long flags;
 	struct async *as;
 
-	spin_lock_irqsave(&ps->lock, flags);
 	list_for_each_entry(as, &ps->async_pending, asynclist)
 		if (as->userurb == userurb) {
 			list_del_init(&as->asynclist);
-			spin_unlock_irqrestore(&ps->lock, flags);
 			return as;
 		}
-	spin_unlock_irqrestore(&ps->lock, flags);
+
 	return NULL;
 }
 
@@ -398,6 +395,7 @@
 __releases(ps->lock)
 __acquires(ps->lock)
 {
+	struct urb *urb;
 	struct async *as;
 
 	/* Mark all the pending URBs that match bulk_addr, up to but not
@@ -420,8 +418,11 @@
 	list_for_each_entry(as, &ps->async_pending, asynclist) {
 		if (as->bulk_status == AS_UNLINK) {
 			as->bulk_status = 0;		/* Only once */
+			urb = as->urb;
+			usb_get_urb(urb);
 			spin_unlock(&ps->lock);		/* Allow completions */
-			usb_unlink_urb(as->urb);
+			usb_unlink_urb(urb);
+			usb_put_urb(urb);
 			spin_lock(&ps->lock);
 			goto rescan;
 		}
@@ -472,6 +473,7 @@
 
 static void destroy_async(struct dev_state *ps, struct list_head *list)
 {
+	struct urb *urb;
 	struct async *as;
 	unsigned long flags;
 
@@ -479,10 +481,13 @@
 	while (!list_empty(list)) {
 		as = list_entry(list->next, struct async, asynclist);
 		list_del_init(&as->asynclist);
+		urb = as->urb;
+		usb_get_urb(urb);
 
 		/* drop the spinlock so the completion handler can run */
 		spin_unlock_irqrestore(&ps->lock, flags);
-		usb_kill_urb(as->urb);
+		usb_kill_urb(urb);
+		usb_put_urb(urb);
 		spin_lock_irqsave(&ps->lock, flags);
 	}
 	spin_unlock_irqrestore(&ps->lock, flags);
@@ -727,17 +732,6 @@
 	if (imajor(inode) == USB_DEVICE_MAJOR)
 		dev = usbdev_lookup_by_devt(inode->i_rdev);
 
-#ifdef CONFIG_USB_DEVICEFS
-	/* procfs file */
-	if (!dev) {
-		dev = inode->i_private;
-		if (dev && dev->usbfs_dentry &&
-					dev->usbfs_dentry->d_inode == inode)
-			usb_get_dev(dev);
-		else
-			dev = NULL;
-	}
-#endif
 	mutex_unlock(&usbfs_mutex);
 
 	if (!dev)
@@ -1410,12 +1404,24 @@
 
 static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
 {
+	struct urb *urb;
 	struct async *as;
+	unsigned long flags;
 
+	spin_lock_irqsave(&ps->lock, flags);
 	as = async_getpending(ps, arg);
-	if (!as)
+	if (!as) {
+		spin_unlock_irqrestore(&ps->lock, flags);
 		return -EINVAL;
-	usb_kill_urb(as->urb);
+	}
+
+	urb = as->urb;
+	usb_get_urb(urb);
+	spin_unlock_irqrestore(&ps->lock, flags);
+
+	usb_kill_urb(urb);
+	usb_put_urb(urb);
+
 	return 0;
 }
 
@@ -2062,44 +2068,13 @@
 	}
 }
 
-#ifdef CONFIG_USB_DEVICE_CLASS
-static struct class *usb_classdev_class;
-
-static int usb_classdev_add(struct usb_device *dev)
-{
-	struct device *cldev;
-
-	cldev = device_create(usb_classdev_class, &dev->dev, dev->dev.devt,
-			      NULL, "usbdev%d.%d", dev->bus->busnum,
-			      dev->devnum);
-	if (IS_ERR(cldev))
-		return PTR_ERR(cldev);
-	dev->usb_classdev = cldev;
-	return 0;
-}
-
-static void usb_classdev_remove(struct usb_device *dev)
-{
-	if (dev->usb_classdev)
-		device_unregister(dev->usb_classdev);
-}
-
-#else
-#define usb_classdev_add(dev)		0
-#define usb_classdev_remove(dev)	do {} while (0)
-
-#endif
-
 static int usbdev_notify(struct notifier_block *self,
 			       unsigned long action, void *dev)
 {
 	switch (action) {
 	case USB_DEVICE_ADD:
-		if (usb_classdev_add(dev))
-			return NOTIFY_BAD;
 		break;
 	case USB_DEVICE_REMOVE:
-		usb_classdev_remove(dev);
 		usbdev_remove(dev);
 		break;
 	}
@@ -2129,21 +2104,6 @@
 		       USB_DEVICE_MAJOR);
 		goto error_cdev;
 	}
-#ifdef CONFIG_USB_DEVICE_CLASS
-	usb_classdev_class = class_create(THIS_MODULE, "usb_device");
-	if (IS_ERR(usb_classdev_class)) {
-		printk(KERN_ERR "Unable to register usb_device class\n");
-		retval = PTR_ERR(usb_classdev_class);
-		cdev_del(&usb_device_cdev);
-		usb_classdev_class = NULL;
-		goto out;
-	}
-	/* devices of this class shadow the major:minor of their parent
-	 * device, so clear ->dev_kobj to prevent adding duplicate entries
-	 * to /sys/dev
-	 */
-	usb_classdev_class->dev_kobj = NULL;
-#endif
 	usb_register_notify(&usbdev_nb);
 out:
 	return retval;
@@ -2156,9 +2116,6 @@
 void usb_devio_cleanup(void)
 {
 	usb_unregister_notify(&usbdev_nb);
-#ifdef CONFIG_USB_DEVICE_CLASS
-	class_destroy(usb_classdev_class);
-#endif
 	cdev_del(&usb_device_cdev);
 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
 }
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 9a56635..f536aeb 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -79,6 +79,30 @@
 }
 EXPORT_SYMBOL_GPL(usb_store_new_id);
 
+ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf)
+{
+	struct usb_dynid *dynid;
+	size_t count = 0;
+
+	list_for_each_entry(dynid, &dynids->list, node)
+		if (dynid->id.bInterfaceClass != 0)
+			count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x %02x\n",
+					   dynid->id.idVendor, dynid->id.idProduct,
+					   dynid->id.bInterfaceClass);
+		else
+			count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x\n",
+					   dynid->id.idVendor, dynid->id.idProduct);
+	return count;
+}
+EXPORT_SYMBOL_GPL(usb_show_dynids);
+
+static ssize_t show_dynids(struct device_driver *driver, char *buf)
+{
+	struct usb_driver *usb_drv = to_usb_driver(driver);
+
+	return usb_show_dynids(&usb_drv->dynids, buf);
+}
+
 static ssize_t store_new_id(struct device_driver *driver,
 			    const char *buf, size_t count)
 {
@@ -86,7 +110,7 @@
 
 	return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
 }
-static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id);
 
 /**
  * store_remove_id - remove a USB device ID from this driver
@@ -127,7 +151,7 @@
 		return retval;
 	return count;
 }
-static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
+static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id);
 
 static int usb_create_newid_files(struct usb_driver *usb_drv)
 {
@@ -264,6 +288,7 @@
 	struct usb_device *udev = interface_to_usbdev(intf);
 	const struct usb_device_id *id;
 	int error = -ENODEV;
+	int lpm_disable_error;
 
 	dev_dbg(dev, "%s\n", __func__);
 
@@ -300,6 +325,25 @@
 	if (driver->supports_autosuspend)
 		pm_runtime_enable(dev);
 
+	/* If the new driver doesn't allow hub-initiated LPM, and we can't
+	 * disable hub-initiated LPM, then fail the probe.
+	 *
+	 * Otherwise, leaving LPM enabled should be harmless, because the
+	 * endpoint intervals should remain the same, and the U1/U2 timeouts
+	 * should remain the same.
+	 *
+	 * If we need to install alt setting 0 before probe, or another alt
+	 * setting during probe, that should also be fine.  usb_set_interface()
+	 * will attempt to disable LPM, and fail if it can't disable it.
+	 */
+	lpm_disable_error = usb_unlocked_disable_lpm(udev);
+	if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
+		dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
+				__func__, driver->name);
+		error = lpm_disable_error;
+		goto err;
+	}
+
 	/* Carry out a deferred switch to altsetting 0 */
 	if (intf->needs_altsetting0) {
 		error = usb_set_interface(udev, intf->altsetting[0].
@@ -314,6 +358,11 @@
 		goto err;
 
 	intf->condition = USB_INTERFACE_BOUND;
+
+	/* If the LPM disable succeeded, balance the ref counts. */
+	if (!lpm_disable_error)
+		usb_unlocked_enable_lpm(udev);
+
 	usb_autosuspend_device(udev);
 	return error;
 
@@ -337,7 +386,7 @@
 	struct usb_driver *driver = to_usb_driver(dev->driver);
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_device *udev;
-	int error, r;
+	int error, r, lpm_disable_error;
 
 	intf->condition = USB_INTERFACE_UNBINDING;
 
@@ -345,6 +394,13 @@
 	udev = interface_to_usbdev(intf);
 	error = usb_autoresume_device(udev);
 
+	/* Hub-initiated LPM policy may change, so attempt to disable LPM until
+	 * the driver is unbound.  If LPM isn't disabled, that's fine because it
+	 * wouldn't be enabled unless all the bound interfaces supported
+	 * hub-initiated LPM.
+	 */
+	lpm_disable_error = usb_unlocked_disable_lpm(udev);
+
 	/* Terminate all URBs for this interface unless the driver
 	 * supports "soft" unbinding.
 	 */
@@ -378,6 +434,10 @@
 	intf->condition = USB_INTERFACE_UNBOUND;
 	intf->needs_remote_wakeup = 0;
 
+	/* Attempt to re-enable USB3 LPM, if the disable succeeded. */
+	if (!lpm_disable_error)
+		usb_unlocked_enable_lpm(udev);
+
 	/* Unbound interfaces are always runtime-PM-disabled and -suspended */
 	if (driver->supports_autosuspend)
 		pm_runtime_disable(dev);
@@ -418,17 +478,29 @@
 				struct usb_interface *iface, void *priv)
 {
 	struct device *dev = &iface->dev;
+	struct usb_device *udev;
 	int retval = 0;
+	int lpm_disable_error;
 
 	if (dev->driver)
 		return -EBUSY;
 
+	udev = interface_to_usbdev(iface);
+
 	dev->driver = &driver->drvwrap.driver;
 	usb_set_intfdata(iface, priv);
 	iface->needs_binding = 0;
 
 	iface->condition = USB_INTERFACE_BOUND;
 
+	/* Disable LPM until this driver is bound. */
+	lpm_disable_error = usb_unlocked_disable_lpm(udev);
+	if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
+		dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
+				__func__, driver->name);
+		return -ENOMEM;
+	}
+
 	/* Claimed interfaces are initially inactive (suspended) and
 	 * runtime-PM-enabled, but only if the driver has autosuspend
 	 * support.  Otherwise they are marked active, to prevent the
@@ -447,6 +519,10 @@
 	if (device_is_registered(dev))
 		retval = device_bind_driver(dev);
 
+	/* Attempt to re-enable USB3 LPM, if the disable was successful. */
+	if (!lpm_disable_error)
+		usb_unlocked_enable_lpm(udev);
+
 	return retval;
 }
 EXPORT_SYMBOL_GPL(usb_driver_claim_interface);
@@ -726,16 +802,6 @@
 		return -ENODEV;
 	}
 
-#ifdef	CONFIG_USB_DEVICEFS
-	/* If this is available, userspace programs can directly read
-	 * all the device descriptors we don't tell them about.  Or
-	 * act as usermode drivers.
-	 */
-	if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
-			   usb_dev->bus->busnum, usb_dev->devnum))
-		return -ENOMEM;
-#endif
-
 	/* per-device configurations are common */
 	if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
 			   le16_to_cpu(usb_dev->descriptor.idVendor),
@@ -788,15 +854,13 @@
 
 	retval = driver_register(&new_udriver->drvwrap.driver);
 
-	if (!retval) {
+	if (!retval)
 		pr_info("%s: registered new device driver %s\n",
 			usbcore_name, new_udriver->name);
-		usbfs_update_special();
-	} else {
+	else
 		printk(KERN_ERR "%s: error %d registering device "
 			"	driver %s\n",
 			usbcore_name, retval, new_udriver->name);
-	}
 
 	return retval;
 }
@@ -815,7 +879,6 @@
 			usbcore_name, udriver->name);
 
 	driver_unregister(&udriver->drvwrap.driver);
-	usbfs_update_special();
 }
 EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
 
@@ -856,8 +919,6 @@
 	if (retval)
 		goto out;
 
-	usbfs_update_special();
-
 	retval = usb_create_newid_files(new_driver);
 	if (retval)
 		goto out_newid;
@@ -897,8 +958,6 @@
 	usb_remove_newid_files(driver);
 	driver_unregister(&driver->drvwrap.driver);
 	usb_free_dynids(driver);
-
-	usbfs_update_special();
 }
 EXPORT_SYMBOL_GPL(usb_deregister);
 
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index d95760d..e673b26 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -183,7 +183,7 @@
 	if (retval)
 		return retval;
 
-	dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base);
+	dev_dbg(&intf->dev, "looking for a minor, starting at %d\n", minor_base);
 
 	down_write(&minor_rwsem);
 	for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
@@ -239,7 +239,7 @@
 	if (intf->minor == -1)
 		return;
 
-	dbg ("removing %d minor", intf->minor);
+	dev_dbg(&intf->dev, "removing %d minor\n", intf->minor);
 
 	down_write(&minor_rwsem);
 	usb_minors[intf->minor] = NULL;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 140d3e1..190b1ec7 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -138,7 +138,7 @@
 	0x03,       /*  __u8  bDeviceProtocol; USB 3.0 hub */
 	0x09,       /*  __u8  bMaxPacketSize0; 2^9 = 512 Bytes */
 
-	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
+	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation 0x1d6b */
 	0x03, 0x00, /*  __le16 idProduct; device 0x0003 */
 	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
 
@@ -159,7 +159,7 @@
 	0x00,       /*  __u8  bDeviceProtocol; [ usb 2.0 no TT ] */
 	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */
 
-	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
+	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation 0x1d6b */
 	0x02, 0x00, /*  __le16 idProduct; device 0x0002 */
 	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
 
@@ -182,7 +182,7 @@
 	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
 	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */
 
-	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
+	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation 0x1d6b */
 	0x01, 0x00, /*  __le16 idProduct; device 0x0001 */
 	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
 
@@ -997,6 +997,15 @@
 				dev_name(&usb_dev->dev), retval);
 		return (retval < 0) ? retval : -EMSGSIZE;
 	}
+	if (usb_dev->speed == USB_SPEED_SUPER) {
+		retval = usb_get_bos_descriptor(usb_dev);
+		if (retval < 0) {
+			mutex_unlock(&usb_bus_list_lock);
+			dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
+					dev_name(&usb_dev->dev), retval);
+			return retval;
+		}
+	}
 
 	retval = usb_new_device (usb_dev);
 	if (retval) {
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ec6c97d..04fb834 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -177,6 +177,228 @@
 	return usb_get_intfdata(hdev->actconfig->interface[0]);
 }
 
+static int usb_device_supports_lpm(struct usb_device *udev)
+{
+	/* USB 2.1 (and greater) devices indicate LPM support through
+	 * their USB 2.0 Extended Capabilities BOS descriptor.
+	 */
+	if (udev->speed == USB_SPEED_HIGH) {
+		if (udev->bos->ext_cap &&
+			(USB_LPM_SUPPORT &
+			 le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
+			return 1;
+		return 0;
+	}
+
+	/* All USB 3.0 must support LPM, but we need their max exit latency
+	 * information from the SuperSpeed Extended Capabilities BOS descriptor.
+	 */
+	if (!udev->bos->ss_cap) {
+		dev_warn(&udev->dev, "No LPM exit latency info found.  "
+				"Power management will be impacted.\n");
+		return 0;
+	}
+	if (udev->parent->lpm_capable)
+		return 1;
+
+	dev_warn(&udev->dev, "Parent hub missing LPM exit latency info.  "
+			"Power management will be impacted.\n");
+	return 0;
+}
+
+/*
+ * Set the Maximum Exit Latency (MEL) for the host to initiate a transition from
+ * either U1 or U2.
+ */
+static void usb_set_lpm_mel(struct usb_device *udev,
+		struct usb3_lpm_parameters *udev_lpm_params,
+		unsigned int udev_exit_latency,
+		struct usb_hub *hub,
+		struct usb3_lpm_parameters *hub_lpm_params,
+		unsigned int hub_exit_latency)
+{
+	unsigned int total_mel;
+	unsigned int device_mel;
+	unsigned int hub_mel;
+
+	/*
+	 * Calculate the time it takes to transition all links from the roothub
+	 * to the parent hub into U0.  The parent hub must then decode the
+	 * packet (hub header decode latency) to figure out which port it was
+	 * bound for.
+	 *
+	 * The Hub Header decode latency is expressed in 0.1us intervals (0x1
+	 * means 0.1us).  Multiply that by 100 to get nanoseconds.
+	 */
+	total_mel = hub_lpm_params->mel +
+		(hub->descriptor->u.ss.bHubHdrDecLat * 100);
+
+	/*
+	 * How long will it take to transition the downstream hub's port into
+	 * U0?  The greater of either the hub exit latency or the device exit
+	 * latency.
+	 *
+	 * The BOS U1/U2 exit latencies are expressed in 1us intervals.
+	 * Multiply that by 1000 to get nanoseconds.
+	 */
+	device_mel = udev_exit_latency * 1000;
+	hub_mel = hub_exit_latency * 1000;
+	if (device_mel > hub_mel)
+		total_mel += device_mel;
+	else
+		total_mel += hub_mel;
+
+	udev_lpm_params->mel = total_mel;
+}
+
+/*
+ * Set the maximum Device to Host Exit Latency (PEL) for the device to initiate
+ * a transition from either U1 or U2.
+ */
+static void usb_set_lpm_pel(struct usb_device *udev,
+		struct usb3_lpm_parameters *udev_lpm_params,
+		unsigned int udev_exit_latency,
+		struct usb_hub *hub,
+		struct usb3_lpm_parameters *hub_lpm_params,
+		unsigned int hub_exit_latency,
+		unsigned int port_to_port_exit_latency)
+{
+	unsigned int first_link_pel;
+	unsigned int hub_pel;
+
+	/*
+	 * First, the device sends an LFPS to transition the link between the
+	 * device and the parent hub into U0.  The exit latency is the bigger of
+	 * the device exit latency or the hub exit latency.
+	 */
+	if (udev_exit_latency > hub_exit_latency)
+		first_link_pel = udev_exit_latency * 1000;
+	else
+		first_link_pel = hub_exit_latency * 1000;
+
+	/*
+	 * When the hub starts to receive the LFPS, there is a slight delay for
+	 * it to figure out that one of the ports is sending an LFPS.  Then it
+	 * will forward the LFPS to its upstream link.  The exit latency is the
+	 * delay, plus the PEL that we calculated for this hub.
+	 */
+	hub_pel = port_to_port_exit_latency * 1000 + hub_lpm_params->pel;
+
+	/*
+	 * According to figure C-7 in the USB 3.0 spec, the PEL for this device
+	 * is the greater of the two exit latencies.
+	 */
+	if (first_link_pel > hub_pel)
+		udev_lpm_params->pel = first_link_pel;
+	else
+		udev_lpm_params->pel = hub_pel;
+}
+
+/*
+ * Set the System Exit Latency (SEL) to indicate the total worst-case time from
+ * when a device initiates a transition to U0, until when it will receive the
+ * first packet from the host controller.
+ *
+ * Section C.1.5.1 describes the four components to this:
+ *  - t1: device PEL
+ *  - t2: time for the ERDY to make it from the device to the host.
+ *  - t3: a host-specific delay to process the ERDY.
+ *  - t4: time for the packet to make it from the host to the device.
+ *
+ * t3 is specific to both the xHCI host and the platform the host is integrated
+ * into.  The Intel HW folks have said it's negligible, FIXME if a different
+ * vendor says otherwise.
+ */
+static void usb_set_lpm_sel(struct usb_device *udev,
+		struct usb3_lpm_parameters *udev_lpm_params)
+{
+	struct usb_device *parent;
+	unsigned int num_hubs;
+	unsigned int total_sel;
+
+	/* t1 = device PEL */
+	total_sel = udev_lpm_params->pel;
+	/* How many external hubs are in between the device & the root port. */
+	for (parent = udev->parent, num_hubs = 0; parent->parent;
+			parent = parent->parent)
+		num_hubs++;
+	/* t2 = 2.1us + 250ns * (num_hubs - 1) */
+	if (num_hubs > 0)
+		total_sel += 2100 + 250 * (num_hubs - 1);
+
+	/* t4 = 250ns * num_hubs */
+	total_sel += 250 * num_hubs;
+
+	udev_lpm_params->sel = total_sel;
+}
+
+static void usb_set_lpm_parameters(struct usb_device *udev)
+{
+	struct usb_hub *hub;
+	unsigned int port_to_port_delay;
+	unsigned int udev_u1_del;
+	unsigned int udev_u2_del;
+	unsigned int hub_u1_del;
+	unsigned int hub_u2_del;
+
+	if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
+		return;
+
+	hub = hdev_to_hub(udev->parent);
+	/* It doesn't take time to transition the roothub into U0, since it
+	 * doesn't have an upstream link.
+	 */
+	if (!hub)
+		return;
+
+	udev_u1_del = udev->bos->ss_cap->bU1devExitLat;
+	udev_u2_del = udev->bos->ss_cap->bU2DevExitLat;
+	hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat;
+	hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat;
+
+	usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del,
+			hub, &udev->parent->u1_params, hub_u1_del);
+
+	usb_set_lpm_mel(udev, &udev->u2_params, udev_u2_del,
+			hub, &udev->parent->u2_params, hub_u2_del);
+
+	/*
+	 * Appendix C, section C.2.2.2, says that there is a slight delay from
+	 * when the parent hub notices the downstream port is trying to
+	 * transition to U0 to when the hub initiates a U0 transition on its
+	 * upstream port.  The section says the delays are tPort2PortU1EL and
+	 * tPort2PortU2EL, but it doesn't define what they are.
+	 *
+	 * The hub chapter, sections 10.4.2.4 and 10.4.2.5 seem to be talking
+	 * about the same delays.  Use the maximum delay calculations from those
+	 * sections.  For U1, it's tHubPort2PortExitLat, which is 1us max.  For
+	 * U2, it's tHubPort2PortExitLat + U2DevExitLat - U1DevExitLat.  I
+	 * assume the device exit latencies they are talking about are the hub
+	 * exit latencies.
+	 *
+	 * What do we do if the U2 exit latency is less than the U1 exit
+	 * latency?  It's possible, although not likely...
+	 */
+	port_to_port_delay = 1;
+
+	usb_set_lpm_pel(udev, &udev->u1_params, udev_u1_del,
+			hub, &udev->parent->u1_params, hub_u1_del,
+			port_to_port_delay);
+
+	if (hub_u2_del > hub_u1_del)
+		port_to_port_delay = 1 + hub_u2_del - hub_u1_del;
+	else
+		port_to_port_delay = 1 + hub_u1_del;
+
+	usb_set_lpm_pel(udev, &udev->u2_params, udev_u2_del,
+			hub, &udev->parent->u2_params, hub_u2_del,
+			port_to_port_delay);
+
+	/* Now that we've got PEL, calculate SEL. */
+	usb_set_lpm_sel(udev, &udev->u1_params);
+	usb_set_lpm_sel(udev, &udev->u2_params);
+}
+
 /* USB 2.0 spec Section 11.24.4.5 */
 static int get_hub_descriptor(struct usb_device *hdev, void *data)
 {
@@ -2480,6 +2702,12 @@
 	if (udev->usb2_hw_lpm_enabled == 1)
 		usb_set_usb2_hardware_lpm(udev, 0);
 
+	if (usb_unlocked_disable_lpm(udev)) {
+		dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
+				__func__);
+		return -ENOMEM;
+	}
+
 	/* see 7.1.7.6 */
 	if (hub_is_superspeed(hub->hdev))
 		status = set_port_feature(hub->hdev,
@@ -2499,6 +2727,13 @@
 				NULL, 0,
 				USB_CTRL_SET_TIMEOUT);
 
+		/* Try to enable USB2 hardware LPM again */
+		if (udev->usb2_hw_lpm_capable == 1)
+			usb_set_usb2_hardware_lpm(udev, 1);
+
+		/* Try to enable USB3 LPM again */
+		usb_unlocked_enable_lpm(udev);
+
 		/* System sleep transitions should never fail */
 		if (!PMSG_IS_AUTO(msg))
 			status = 0;
@@ -2696,6 +2931,9 @@
 		/* Try to enable USB2 hardware LPM */
 		if (udev->usb2_hw_lpm_capable == 1)
 			usb_set_usb2_hardware_lpm(udev, 1);
+
+		/* Try to enable USB3 LPM */
+		usb_unlocked_enable_lpm(udev);
 	}
 
 	return status;
@@ -2824,11 +3062,429 @@
 }
 EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
 
+static const char * const usb3_lpm_names[]  = {
+	"U0",
+	"U1",
+	"U2",
+	"U3",
+};
+
+/*
+ * Send a Set SEL control transfer to the device, prior to enabling
+ * device-initiated U1 or U2.  This lets the device know the exit latencies from
+ * the time the device initiates a U1 or U2 exit, to the time it will receive a
+ * packet from the host.
+ *
+ * This function will fail if the SEL or PEL values for udev are greater than
+ * the maximum allowed values for the link state to be enabled.
+ */
+static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
+{
+	struct usb_set_sel_req *sel_values;
+	unsigned long long u1_sel;
+	unsigned long long u1_pel;
+	unsigned long long u2_sel;
+	unsigned long long u2_pel;
+	int ret;
+
+	/* Convert SEL and PEL stored in ns to us */
+	u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
+	u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
+	u2_sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
+	u2_pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
+
+	/*
+	 * Make sure that the calculated SEL and PEL values for the link
+	 * state we're enabling aren't bigger than the max SEL/PEL
+	 * value that will fit in the SET SEL control transfer.
+	 * Otherwise the device would get an incorrect idea of the exit
+	 * latency for the link state, and could start a device-initiated
+	 * U1/U2 when the exit latencies are too high.
+	 */
+	if ((state == USB3_LPM_U1 &&
+				(u1_sel > USB3_LPM_MAX_U1_SEL_PEL ||
+				 u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) ||
+			(state == USB3_LPM_U2 &&
+			 (u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
+			  u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) {
+		dev_dbg(&udev->dev, "Device-initiated %s disabled due "
+				"to long SEL %llu ms or PEL %llu ms\n",
+				usb3_lpm_names[state], u1_sel, u1_pel);
+		return -EINVAL;
+	}
+
+	/*
+	 * If we're enabling device-initiated LPM for one link state,
+	 * but the other link state has a too high SEL or PEL value,
+	 * just set those values to the max in the Set SEL request.
+	 */
+	if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL)
+		u1_sel = USB3_LPM_MAX_U1_SEL_PEL;
+
+	if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL)
+		u1_pel = USB3_LPM_MAX_U1_SEL_PEL;
+
+	if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL)
+		u2_sel = USB3_LPM_MAX_U2_SEL_PEL;
+
+	if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL)
+		u2_pel = USB3_LPM_MAX_U2_SEL_PEL;
+
+	/*
+	 * usb_enable_lpm() can be called as part of a failed device reset,
+	 * which may be initiated by an error path of a mass storage driver.
+	 * Therefore, use GFP_NOIO.
+	 */
+	sel_values = kmalloc(sizeof *(sel_values), GFP_NOIO);
+	if (!sel_values)
+		return -ENOMEM;
+
+	sel_values->u1_sel = u1_sel;
+	sel_values->u1_pel = u1_pel;
+	sel_values->u2_sel = cpu_to_le16(u2_sel);
+	sel_values->u2_pel = cpu_to_le16(u2_pel);
+
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			USB_REQ_SET_SEL,
+			USB_RECIP_DEVICE,
+			0, 0,
+			sel_values, sizeof *(sel_values),
+			USB_CTRL_SET_TIMEOUT);
+	kfree(sel_values);
+	return ret;
+}
+
+/*
+ * Enable or disable device-initiated U1 or U2 transitions.
+ */
+static int usb_set_device_initiated_lpm(struct usb_device *udev,
+		enum usb3_link_state state, bool enable)
+{
+	int ret;
+	int feature;
+
+	switch (state) {
+	case USB3_LPM_U1:
+		feature = USB_DEVICE_U1_ENABLE;
+		break;
+	case USB3_LPM_U2:
+		feature = USB_DEVICE_U2_ENABLE;
+		break;
+	default:
+		dev_warn(&udev->dev, "%s: Can't %s non-U1 or U2 state.\n",
+				__func__, enable ? "enable" : "disable");
+		return -EINVAL;
+	}
+
+	if (udev->state != USB_STATE_CONFIGURED) {
+		dev_dbg(&udev->dev, "%s: Can't %s %s state "
+				"for unconfigured device.\n",
+				__func__, enable ? "enable" : "disable",
+				usb3_lpm_names[state]);
+		return 0;
+	}
+
+	if (enable) {
+		/*
+		 * First, let the device know about the exit latencies
+		 * associated with the link state we're about to enable.
+		 */
+		ret = usb_req_set_sel(udev, state);
+		if (ret < 0) {
+			dev_warn(&udev->dev, "Set SEL for device-initiated "
+					"%s failed.\n", usb3_lpm_names[state]);
+			return -EBUSY;
+		}
+		/*
+		 * Now send the control transfer to enable device-initiated LPM
+		 * for either U1 or U2.
+		 */
+		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				USB_REQ_SET_FEATURE,
+				USB_RECIP_DEVICE,
+				feature,
+				0, NULL, 0,
+				USB_CTRL_SET_TIMEOUT);
+	} else {
+		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				USB_REQ_CLEAR_FEATURE,
+				USB_RECIP_DEVICE,
+				feature,
+				0, NULL, 0,
+				USB_CTRL_SET_TIMEOUT);
+	}
+	if (ret < 0) {
+		dev_warn(&udev->dev, "%s of device-initiated %s failed.\n",
+				enable ? "Enable" : "Disable",
+				usb3_lpm_names[state]);
+		return -EBUSY;
+	}
+	return 0;
+}
+
+static int usb_set_lpm_timeout(struct usb_device *udev,
+		enum usb3_link_state state, int timeout)
+{
+	int ret;
+	int feature;
+
+	switch (state) {
+	case USB3_LPM_U1:
+		feature = USB_PORT_FEAT_U1_TIMEOUT;
+		break;
+	case USB3_LPM_U2:
+		feature = USB_PORT_FEAT_U2_TIMEOUT;
+		break;
+	default:
+		dev_warn(&udev->dev, "%s: Can't set timeout for non-U1 or U2 state.\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	if (state == USB3_LPM_U1 && timeout > USB3_LPM_U1_MAX_TIMEOUT &&
+			timeout != USB3_LPM_DEVICE_INITIATED) {
+		dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x, "
+				"which is a reserved value.\n",
+				usb3_lpm_names[state], timeout);
+		return -EINVAL;
+	}
+
+	ret = set_port_feature(udev->parent,
+			USB_PORT_LPM_TIMEOUT(timeout) | udev->portnum,
+			feature);
+	if (ret < 0) {
+		dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x,"
+				"error code %i\n", usb3_lpm_names[state],
+				timeout, ret);
+		return -EBUSY;
+	}
+	if (state == USB3_LPM_U1)
+		udev->u1_params.timeout = timeout;
+	else
+		udev->u2_params.timeout = timeout;
+	return 0;
+}
+
+/*
+ * Enable the hub-initiated U1/U2 idle timeouts, and enable device-initiated
+ * U1/U2 entry.
+ *
+ * We will attempt to enable U1 or U2, but there are no guarantees that the
+ * control transfers to set the hub timeout or enable device-initiated U1/U2
+ * will be successful.
+ *
+ * If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
+ * driver know about it.  If that call fails, it should be harmless, and just
+ * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
+ */
+static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
+		enum usb3_link_state state)
+{
+	int timeout;
+
+	/* We allow the host controller to set the U1/U2 timeout internally
+	 * first, so that it can change its schedule to account for the
+	 * additional latency to send data to a device in a lower power
+	 * link state.
+	 */
+	timeout = hcd->driver->enable_usb3_lpm_timeout(hcd, udev, state);
+
+	/* xHCI host controller doesn't want to enable this LPM state. */
+	if (timeout == 0)
+		return;
+
+	if (timeout < 0) {
+		dev_warn(&udev->dev, "Could not enable %s link state, "
+				"xHCI error %i.\n", usb3_lpm_names[state],
+				timeout);
+		return;
+	}
+
+	if (usb_set_lpm_timeout(udev, state, timeout))
+		/* If we can't set the parent hub U1/U2 timeout,
+		 * device-initiated LPM won't be allowed either, so let the xHCI
+		 * host know that this link state won't be enabled.
+		 */
+		hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
+
+	/* Only a configured device will accept the Set Feature U1/U2_ENABLE */
+	else if (udev->actconfig)
+		usb_set_device_initiated_lpm(udev, state, true);
+
+}
+
+/*
+ * Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated
+ * U1/U2 entry.
+ *
+ * If this function returns -EBUSY, the parent hub will still allow U1/U2 entry.
+ * If zero is returned, the parent will not allow the link to go into U1/U2.
+ *
+ * If zero is returned, device-initiated U1/U2 entry may still be enabled, but
+ * it won't have an effect on the bus link state because the parent hub will
+ * still disallow device-initiated U1/U2 entry.
+ *
+ * If zero is returned, the xHCI host controller may still think U1/U2 entry is
+ * possible.  The result will be slightly more bus bandwidth will be taken up
+ * (to account for U1/U2 exit latency), but it should be harmless.
+ */
+static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
+		enum usb3_link_state state)
+{
+	int feature;
+
+	switch (state) {
+	case USB3_LPM_U1:
+		feature = USB_PORT_FEAT_U1_TIMEOUT;
+		break;
+	case USB3_LPM_U2:
+		feature = USB_PORT_FEAT_U2_TIMEOUT;
+		break;
+	default:
+		dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	if (usb_set_lpm_timeout(udev, state, 0))
+		return -EBUSY;
+
+	usb_set_device_initiated_lpm(udev, state, false);
+
+	if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state))
+		dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
+				"bus schedule bandwidth may be impacted.\n",
+				usb3_lpm_names[state]);
+	return 0;
+}
+
+/*
+ * Disable hub-initiated and device-initiated U1 and U2 entry.
+ * Caller must own the bandwidth_mutex.
+ *
+ * This will call usb_enable_lpm() on failure, which will decrement
+ * lpm_disable_count, and will re-enable LPM if lpm_disable_count reaches zero.
+ */
+int usb_disable_lpm(struct usb_device *udev)
+{
+	struct usb_hcd *hcd;
+
+	if (!udev || !udev->parent ||
+			udev->speed != USB_SPEED_SUPER ||
+			!udev->lpm_capable)
+		return 0;
+
+	hcd = bus_to_hcd(udev->bus);
+	if (!hcd || !hcd->driver->disable_usb3_lpm_timeout)
+		return 0;
+
+	udev->lpm_disable_count++;
+	if ((udev->u1_params.timeout == 0 && udev->u1_params.timeout == 0))
+		return 0;
+
+	/* If LPM is enabled, attempt to disable it. */
+	if (usb_disable_link_state(hcd, udev, USB3_LPM_U1))
+		goto enable_lpm;
+	if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
+		goto enable_lpm;
+
+	return 0;
+
+enable_lpm:
+	usb_enable_lpm(udev);
+	return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(usb_disable_lpm);
+
+/* Grab the bandwidth_mutex before calling usb_disable_lpm() */
+int usb_unlocked_disable_lpm(struct usb_device *udev)
+{
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+	int ret;
+
+	if (!hcd)
+		return -EINVAL;
+
+	mutex_lock(hcd->bandwidth_mutex);
+	ret = usb_disable_lpm(udev);
+	mutex_unlock(hcd->bandwidth_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
+
+/*
+ * Attempt to enable device-initiated and hub-initiated U1 and U2 entry.  The
+ * xHCI host policy may prevent U1 or U2 from being enabled.
+ *
+ * Other callers may have disabled link PM, so U1 and U2 entry will be disabled
+ * until the lpm_disable_count drops to zero.  Caller must own the
+ * bandwidth_mutex.
+ */
+void usb_enable_lpm(struct usb_device *udev)
+{
+	struct usb_hcd *hcd;
+
+	if (!udev || !udev->parent ||
+			udev->speed != USB_SPEED_SUPER ||
+			!udev->lpm_capable)
+		return;
+
+	udev->lpm_disable_count--;
+	hcd = bus_to_hcd(udev->bus);
+	/* Double check that we can both enable and disable LPM.
+	 * Device must be configured to accept set feature U1/U2 timeout.
+	 */
+	if (!hcd || !hcd->driver->enable_usb3_lpm_timeout ||
+			!hcd->driver->disable_usb3_lpm_timeout)
+		return;
+
+	if (udev->lpm_disable_count > 0)
+		return;
+
+	usb_enable_link_state(hcd, udev, USB3_LPM_U1);
+	usb_enable_link_state(hcd, udev, USB3_LPM_U2);
+}
+EXPORT_SYMBOL_GPL(usb_enable_lpm);
+
+/* Grab the bandwidth_mutex before calling usb_enable_lpm() */
+void usb_unlocked_enable_lpm(struct usb_device *udev)
+{
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+	if (!hcd)
+		return;
+
+	mutex_lock(hcd->bandwidth_mutex);
+	usb_enable_lpm(udev);
+	mutex_unlock(hcd->bandwidth_mutex);
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
+
+
 #else	/* CONFIG_PM */
 
 #define hub_suspend		NULL
 #define hub_resume		NULL
 #define hub_reset_resume	NULL
+
+int usb_disable_lpm(struct usb_device *udev)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_disable_lpm);
+
+void usb_enable_lpm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_enable_lpm);
+
+int usb_unlocked_disable_lpm(struct usb_device *udev)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
+
+void usb_unlocked_enable_lpm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
 #endif
 
 
@@ -3208,9 +3864,8 @@
 	if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
 		retval = usb_get_bos_descriptor(udev);
 		if (!retval) {
-			if (udev->bos->ext_cap && (USB_LPM_SUPPORT &
-				le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
-					udev->lpm_capable = 1;
+			udev->lpm_capable = usb_device_supports_lpm(udev);
+			usb_set_lpm_parameters(udev);
 		}
 	}
 
@@ -4042,11 +4697,22 @@
 		goto done;
 
 	mutex_lock(hcd->bandwidth_mutex);
+	/* Disable LPM while we reset the device and reinstall the alt settings.
+	 * Device-initiated LPM settings, and system exit latency settings are
+	 * cleared when the device is reset, so we have to set them up again.
+	 */
+	ret = usb_disable_lpm(udev);
+	if (ret) {
+		dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__);
+		mutex_unlock(hcd->bandwidth_mutex);
+		goto done;
+	}
 	ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
 	if (ret < 0) {
 		dev_warn(&udev->dev,
 				"Busted HC?  Not enough HCD resources for "
 				"old configuration.\n");
+		usb_enable_lpm(udev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		goto re_enumerate;
 	}
@@ -4058,6 +4724,7 @@
 		dev_err(&udev->dev,
 			"can't restore configuration #%d (error=%d)\n",
 			udev->actconfig->desc.bConfigurationValue, ret);
+		usb_enable_lpm(udev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		goto re_enumerate;
   	}
@@ -4096,10 +4763,13 @@
 				desc->bInterfaceNumber,
 				desc->bAlternateSetting,
 				ret);
+			usb_unlocked_enable_lpm(udev);
 			goto re_enumerate;
 		}
 	}
 
+	/* Now that the alt settings are re-installed, enable LPM. */
+	usb_unlocked_enable_lpm(udev);
 done:
 	return 0;
  
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
deleted file mode 100644
index d2b9af5..0000000
--- a/drivers/usb/core/inode.c
+++ /dev/null
@@ -1,748 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	inode.c  --  Inode/Dentry functions for the USB device file system.
- *
- *	Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
- *	Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  History:
- *   0.1  04.01.2000  Created
- *   0.2  10.12.2001  converted to use the vfs layer better
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/pagemap.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/usb.h>
-#include <linux/namei.h>
-#include <linux/usbdevice_fs.h>
-#include <linux/parser.h>
-#include <linux/notifier.h>
-#include <linux/seq_file.h>
-#include <linux/usb/hcd.h>
-#include <asm/byteorder.h>
-#include "usb.h"
-
-#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO)
-#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO)
-#define USBFS_DEFAULT_LISTMODE S_IRUGO
-
-static const struct file_operations default_file_operations;
-static struct vfsmount *usbfs_mount;
-static int usbfs_mount_count;	/* = 0 */
-
-static struct dentry *devices_usbfs_dentry;
-static int num_buses;	/* = 0 */
-
-static uid_t devuid;	/* = 0 */
-static uid_t busuid;	/* = 0 */
-static uid_t listuid;	/* = 0 */
-static gid_t devgid;	/* = 0 */
-static gid_t busgid;	/* = 0 */
-static gid_t listgid;	/* = 0 */
-static umode_t devmode = USBFS_DEFAULT_DEVMODE;
-static umode_t busmode = USBFS_DEFAULT_BUSMODE;
-static umode_t listmode = USBFS_DEFAULT_LISTMODE;
-
-static int usbfs_show_options(struct seq_file *seq, struct dentry *root)
-{
-	if (devuid != 0)
-		seq_printf(seq, ",devuid=%u", devuid);
-	if (devgid != 0)
-		seq_printf(seq, ",devgid=%u", devgid);
-	if (devmode != USBFS_DEFAULT_DEVMODE)
-		seq_printf(seq, ",devmode=%o", devmode);
-	if (busuid != 0)
-		seq_printf(seq, ",busuid=%u", busuid);
-	if (busgid != 0)
-		seq_printf(seq, ",busgid=%u", busgid);
-	if (busmode != USBFS_DEFAULT_BUSMODE)
-		seq_printf(seq, ",busmode=%o", busmode);
-	if (listuid != 0)
-		seq_printf(seq, ",listuid=%u", listuid);
-	if (listgid != 0)
-		seq_printf(seq, ",listgid=%u", listgid);
-	if (listmode != USBFS_DEFAULT_LISTMODE)
-		seq_printf(seq, ",listmode=%o", listmode);
-
-	return 0;
-}
-
-enum {
-	Opt_devuid, Opt_devgid, Opt_devmode,
-	Opt_busuid, Opt_busgid, Opt_busmode,
-	Opt_listuid, Opt_listgid, Opt_listmode,
-	Opt_err,
-};
-
-static const match_table_t tokens = {
-	{Opt_devuid, "devuid=%u"},
-	{Opt_devgid, "devgid=%u"},
-	{Opt_devmode, "devmode=%o"},
-	{Opt_busuid, "busuid=%u"},
-	{Opt_busgid, "busgid=%u"},
-	{Opt_busmode, "busmode=%o"},
-	{Opt_listuid, "listuid=%u"},
-	{Opt_listgid, "listgid=%u"},
-	{Opt_listmode, "listmode=%o"},
-	{Opt_err, NULL}
-};
-
-static int parse_options(struct super_block *s, char *data)
-{
-	char *p;
-	int option;
-
-	/* (re)set to defaults. */
-	devuid = 0;
-	busuid = 0;
-	listuid = 0;
-	devgid = 0;
-	busgid = 0;
-	listgid = 0;
-	devmode = USBFS_DEFAULT_DEVMODE;
-	busmode = USBFS_DEFAULT_BUSMODE;
-	listmode = USBFS_DEFAULT_LISTMODE;
-
-	while ((p = strsep(&data, ",")) != NULL) {
-		substring_t args[MAX_OPT_ARGS];
-		int token;
-		if (!*p)
-			continue;
-
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_devuid:
-			if (match_int(&args[0], &option))
-			       return -EINVAL;
-			devuid = option;
-			break;
-		case Opt_devgid:
-			if (match_int(&args[0], &option))
-			       return -EINVAL;
-			devgid = option;
-			break;
-		case Opt_devmode:
-			if (match_octal(&args[0], &option))
-				return -EINVAL;
-			devmode = option & S_IRWXUGO;
-			break;
-		case Opt_busuid:
-			if (match_int(&args[0], &option))
-			       return -EINVAL;
-			busuid = option;
-			break;
-		case Opt_busgid:
-			if (match_int(&args[0], &option))
-			       return -EINVAL;
-			busgid = option;
-			break;
-		case Opt_busmode:
-			if (match_octal(&args[0], &option))
-				return -EINVAL;
-			busmode = option & S_IRWXUGO;
-			break;
-		case Opt_listuid:
-			if (match_int(&args[0], &option))
-			       return -EINVAL;
-			listuid = option;
-			break;
-		case Opt_listgid:
-			if (match_int(&args[0], &option))
-			       return -EINVAL;
-			listgid = option;
-			break;
-		case Opt_listmode:
-			if (match_octal(&args[0], &option))
-				return -EINVAL;
-			listmode = option & S_IRWXUGO;
-			break;
-		default:
-			printk(KERN_ERR "usbfs: unrecognised mount option "
-			       "\"%s\" or missing value\n", p);
-			return -EINVAL;
-		}
-	}
-
-	return 0;
-}
-
-static void update_special(struct dentry *special)
-{
-	special->d_inode->i_uid = listuid;
-	special->d_inode->i_gid = listgid;
-	special->d_inode->i_mode = S_IFREG | listmode;
-}
-
-static void update_dev(struct dentry *dev)
-{
-	dev->d_inode->i_uid = devuid;
-	dev->d_inode->i_gid = devgid;
-	dev->d_inode->i_mode = S_IFREG | devmode;
-}
-
-static void update_bus(struct dentry *bus)
-{
-	struct dentry *dev = NULL;
-
-	bus->d_inode->i_uid = busuid;
-	bus->d_inode->i_gid = busgid;
-	bus->d_inode->i_mode = S_IFDIR | busmode;
-
-	mutex_lock(&bus->d_inode->i_mutex);
-
-	list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child)
-		if (dev->d_inode)
-			update_dev(dev);
-
-	mutex_unlock(&bus->d_inode->i_mutex);
-}
-
-static void update_sb(struct super_block *sb)
-{
-	struct dentry *root = sb->s_root;
-	struct dentry *bus = NULL;
-
-	if (!root)
-		return;
-
-	mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT);
-
-	list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) {
-		if (bus->d_inode) {
-			switch (S_IFMT & bus->d_inode->i_mode) {
-			case S_IFDIR:
-				update_bus(bus);
-				break;
-			case S_IFREG:
-				update_special(bus);
-				break;
-			default:
-				printk(KERN_WARNING "usbfs: Unknown node %s "
-				       "mode %x found on remount!\n",
-				       bus->d_name.name, bus->d_inode->i_mode);
-				break;
-			}
-		}
-	}
-
-	mutex_unlock(&root->d_inode->i_mutex);
-}
-
-static int remount(struct super_block *sb, int *flags, char *data)
-{
-	/* If this is not a real mount,
-	 * i.e. it's a simple_pin_fs from create_special_files,
-	 * then ignore it.
-	 */
-	if (*flags & MS_KERNMOUNT)
-		return 0;
-
-	if (parse_options(sb, data)) {
-		printk(KERN_WARNING "usbfs: mount parameter error.\n");
-		return -EINVAL;
-	}
-
-	if (usbfs_mount)
-		update_sb(usbfs_mount->mnt_sb);
-
-	return 0;
-}
-
-static struct inode *usbfs_get_inode (struct super_block *sb, umode_t mode, dev_t dev)
-{
-	struct inode *inode = new_inode(sb);
-
-	if (inode) {
-		inode->i_ino = get_next_ino();
-		inode_init_owner(inode, NULL, mode);
-		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-		switch (mode & S_IFMT) {
-		default:
-			init_special_inode(inode, mode, dev);
-			break;
-		case S_IFREG:
-			inode->i_fop = &default_file_operations;
-			break;
-		case S_IFDIR:
-			inode->i_op = &simple_dir_inode_operations;
-			inode->i_fop = &simple_dir_operations;
-
-			/* directory inodes start off with i_nlink == 2 (for "." entry) */
-			inc_nlink(inode);
-			break;
-		}
-	}
-	return inode; 
-}
-
-/* SMP-safe */
-static int usbfs_mknod (struct inode *dir, struct dentry *dentry, umode_t mode,
-			dev_t dev)
-{
-	struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev);
-	int error = -EPERM;
-
-	if (dentry->d_inode)
-		return -EEXIST;
-
-	if (inode) {
-		d_instantiate(dentry, inode);
-		dget(dentry);
-		error = 0;
-	}
-	return error;
-}
-
-static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, umode_t mode)
-{
-	int res;
-
-	mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
-	res = usbfs_mknod (dir, dentry, mode, 0);
-	if (!res)
-		inc_nlink(dir);
-	return res;
-}
-
-static int usbfs_create (struct inode *dir, struct dentry *dentry, umode_t mode)
-{
-	mode = (mode & S_IALLUGO) | S_IFREG;
-	return usbfs_mknod (dir, dentry, mode, 0);
-}
-
-static inline int usbfs_positive (struct dentry *dentry)
-{
-	return dentry->d_inode && !d_unhashed(dentry);
-}
-
-static int usbfs_empty (struct dentry *dentry)
-{
-	struct list_head *list;
-
-	spin_lock(&dentry->d_lock);
-	list_for_each(list, &dentry->d_subdirs) {
-		struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
-
-		spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED);
-		if (usbfs_positive(de)) {
-			spin_unlock(&de->d_lock);
-			spin_unlock(&dentry->d_lock);
-			return 0;
-		}
-		spin_unlock(&de->d_lock);
-	}
-	spin_unlock(&dentry->d_lock);
-	return 1;
-}
-
-static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
-{
-	struct inode *inode = dentry->d_inode;
-	mutex_lock(&inode->i_mutex);
-	drop_nlink(dentry->d_inode);
-	dput(dentry);
-	mutex_unlock(&inode->i_mutex);
-	d_delete(dentry);
-	return 0;
-}
-
-static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
-{
-	int error = -ENOTEMPTY;
-	struct inode * inode = dentry->d_inode;
-
-	mutex_lock(&inode->i_mutex);
-	dentry_unhash(dentry);
-	if (usbfs_empty(dentry)) {
-		dont_mount(dentry);
-		drop_nlink(dentry->d_inode);
-		drop_nlink(dentry->d_inode);
-		dput(dentry);
-		inode->i_flags |= S_DEAD;
-		drop_nlink(dir);
-		error = 0;
-	}
-	mutex_unlock(&inode->i_mutex);
-	if (!error)
-		d_delete(dentry);
-	return error;
-}
-
-
-/* default file operations */
-static ssize_t default_read_file (struct file *file, char __user *buf,
-				  size_t count, loff_t *ppos)
-{
-	return 0;
-}
-
-static ssize_t default_write_file (struct file *file, const char __user *buf,
-				   size_t count, loff_t *ppos)
-{
-	return count;
-}
-
-static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
-{
-	loff_t retval = -EINVAL;
-
-	mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
-	switch(orig) {
-	case 0:
-		if (offset > 0) {
-			file->f_pos = offset;
-			retval = file->f_pos;
-		} 
-		break;
-	case 1:
-		if ((offset + file->f_pos) > 0) {
-			file->f_pos += offset;
-			retval = file->f_pos;
-		} 
-		break;
-	default:
-		break;
-	}
-	mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
-	return retval;
-}
-
-static const struct file_operations default_file_operations = {
-	.read =		default_read_file,
-	.write =	default_write_file,
-	.open =		simple_open,
-	.llseek =	default_file_lseek,
-};
-
-static const struct super_operations usbfs_ops = {
-	.statfs =	simple_statfs,
-	.drop_inode =	generic_delete_inode,
-	.remount_fs =	remount,
-	.show_options = usbfs_show_options,
-};
-
-static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
-{
-	struct inode *inode;
-
-	sb->s_blocksize = PAGE_CACHE_SIZE;
-	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-	sb->s_magic = USBDEVICE_SUPER_MAGIC;
-	sb->s_op = &usbfs_ops;
-	sb->s_time_gran = 1;
-	inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
-	sb->s_root = d_make_root(inode);
-	if (!sb->s_root) {
-		dbg("%s: could not get root dentry!",__func__);
-		return -ENOMEM;
-	}
-	return 0;
-}
-
-/*
- * fs_create_by_name - create a file, given a name
- * @name:	name of file
- * @mode:	type of file
- * @parent:	dentry of directory to create it in
- * @dentry:	resulting dentry of file
- *
- * This function handles both regular files and directories.
- */
-static int fs_create_by_name (const char *name, umode_t mode,
-			      struct dentry *parent, struct dentry **dentry)
-{
-	int error = 0;
-
-	/* If the parent is not specified, we create it in the root.
-	 * We need the root dentry to do this, which is in the super 
-	 * block. A pointer to that is in the struct vfsmount that we
-	 * have around.
-	 */
-	if (!parent ) {
-		if (usbfs_mount)
-			parent = usbfs_mount->mnt_root;
-	}
-
-	if (!parent) {
-		dbg("Ah! can not find a parent!");
-		return -EFAULT;
-	}
-
-	*dentry = NULL;
-	mutex_lock(&parent->d_inode->i_mutex);
-	*dentry = lookup_one_len(name, parent, strlen(name));
-	if (!IS_ERR(*dentry)) {
-		if (S_ISDIR(mode))
-			error = usbfs_mkdir (parent->d_inode, *dentry, mode);
-		else 
-			error = usbfs_create (parent->d_inode, *dentry, mode);
-	} else
-		error = PTR_ERR(*dentry);
-	mutex_unlock(&parent->d_inode->i_mutex);
-
-	return error;
-}
-
-static struct dentry *fs_create_file (const char *name, umode_t mode,
-				      struct dentry *parent, void *data,
-				      const struct file_operations *fops,
-				      uid_t uid, gid_t gid)
-{
-	struct dentry *dentry;
-	int error;
-
-	dbg("creating file '%s'",name);
-
-	error = fs_create_by_name (name, mode, parent, &dentry);
-	if (error) {
-		dentry = NULL;
-	} else {
-		if (dentry->d_inode) {
-			if (data)
-				dentry->d_inode->i_private = data;
-			if (fops)
-				dentry->d_inode->i_fop = fops;
-			dentry->d_inode->i_uid = uid;
-			dentry->d_inode->i_gid = gid;
-		}
-	}
-
-	return dentry;
-}
-
-static void fs_remove_file (struct dentry *dentry)
-{
-	struct dentry *parent = dentry->d_parent;
-	
-	if (!parent || !parent->d_inode)
-		return;
-
-	mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT);
-	if (usbfs_positive(dentry)) {
-		if (dentry->d_inode) {
-			if (S_ISDIR(dentry->d_inode->i_mode))
-				usbfs_rmdir(parent->d_inode, dentry);
-			else
-				usbfs_unlink(parent->d_inode, dentry);
-		dput(dentry);
-		}
-	}
-	mutex_unlock(&parent->d_inode->i_mutex);
-}
-
-/* --------------------------------------------------------------------- */
-
-static struct dentry *usb_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
-{
-	return mount_single(fs_type, flags, data, usbfs_fill_super);
-}
-
-static struct file_system_type usb_fs_type = {
-	.owner =	THIS_MODULE,
-	.name =		"usbfs",
-	.mount =	usb_mount,
-	.kill_sb =	kill_litter_super,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int create_special_files (void)
-{
-	struct dentry *parent;
-	int retval;
-
-	/* create the devices special file */
-	retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
-	if (retval) {
-		printk(KERN_ERR "Unable to get usbfs mount\n");
-		goto exit;
-	}
-
-	parent = usbfs_mount->mnt_root;
-	devices_usbfs_dentry = fs_create_file ("devices",
-					       listmode | S_IFREG, parent,
-					       NULL, &usbfs_devices_fops,
-					       listuid, listgid);
-	if (devices_usbfs_dentry == NULL) {
-		printk(KERN_ERR "Unable to create devices usbfs file\n");
-		retval = -ENODEV;
-		goto error_clean_mounts;
-	}
-
-	goto exit;
-	
-error_clean_mounts:
-	simple_release_fs(&usbfs_mount, &usbfs_mount_count);
-exit:
-	return retval;
-}
-
-static void remove_special_files (void)
-{
-	if (devices_usbfs_dentry)
-		fs_remove_file (devices_usbfs_dentry);
-	devices_usbfs_dentry = NULL;
-	simple_release_fs(&usbfs_mount, &usbfs_mount_count);
-}
-
-void usbfs_update_special (void)
-{
-	struct inode *inode;
-
-	if (devices_usbfs_dentry) {
-		inode = devices_usbfs_dentry->d_inode;
-		if (inode)
-			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	}
-}
-
-static void usbfs_add_bus(struct usb_bus *bus)
-{
-	struct dentry *parent;
-	char name[8];
-	int retval;
-
-	/* create the special files if this is the first bus added */
-	if (num_buses == 0) {
-		retval = create_special_files();
-		if (retval)
-			return;
-	}
-	++num_buses;
-
-	sprintf (name, "%03d", bus->busnum);
-
-	parent = usbfs_mount->mnt_root;
-	bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent,
-					    bus, NULL, busuid, busgid);
-	if (bus->usbfs_dentry == NULL) {
-		printk(KERN_ERR "Error creating usbfs bus entry\n");
-		return;
-	}
-}
-
-static void usbfs_remove_bus(struct usb_bus *bus)
-{
-	if (bus->usbfs_dentry) {
-		fs_remove_file (bus->usbfs_dentry);
-		bus->usbfs_dentry = NULL;
-	}
-
-	--num_buses;
-	if (num_buses <= 0) {
-		remove_special_files();
-		num_buses = 0;
-	}
-}
-
-static void usbfs_add_device(struct usb_device *dev)
-{
-	char name[8];
-	int i;
-	int i_size;
-
-	sprintf (name, "%03d", dev->devnum);
-	dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
-					    dev->bus->usbfs_dentry, dev,
-					    &usbdev_file_operations,
-					    devuid, devgid);
-	if (dev->usbfs_dentry == NULL) {
-		printk(KERN_ERR "Error creating usbfs device entry\n");
-		return;
-	}
-
-	/* Set the size of the device's file to be
-	 * equal to the size of the device descriptors. */
-	i_size = sizeof (struct usb_device_descriptor);
-	for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) {
-		struct usb_config_descriptor *config =
-			(struct usb_config_descriptor *)dev->rawdescriptors[i];
-		i_size += le16_to_cpu(config->wTotalLength);
-	}
-	if (dev->usbfs_dentry->d_inode)
-		dev->usbfs_dentry->d_inode->i_size = i_size;
-}
-
-static void usbfs_remove_device(struct usb_device *dev)
-{
-	if (dev->usbfs_dentry) {
-		fs_remove_file (dev->usbfs_dentry);
-		dev->usbfs_dentry = NULL;
-	}
-}
-
-static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev)
-{
-	switch (action) {
-	case USB_DEVICE_ADD:
-		usbfs_add_device(dev);
-		break;
-	case USB_DEVICE_REMOVE:
-		usbfs_remove_device(dev);
-		break;
-	case USB_BUS_ADD:
-		usbfs_add_bus(dev);
-		break;
-	case USB_BUS_REMOVE:
-		usbfs_remove_bus(dev);
-	}
-
-	usbfs_update_special();
-	usbfs_conn_disc_event();
-	return NOTIFY_OK;
-}
-
-static struct notifier_block usbfs_nb = {
-	.notifier_call = 	usbfs_notify,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct proc_dir_entry *usbdir = NULL;
-
-int __init usbfs_init(void)
-{
-	int retval;
-
-	retval = register_filesystem(&usb_fs_type);
-	if (retval)
-		return retval;
-
-	usb_register_notify(&usbfs_nb);
-
-	/* create mount point for usbfs */
-	usbdir = proc_mkdir("bus/usb", NULL);
-
-	return 0;
-}
-
-void usbfs_cleanup(void)
-{
-	usb_unregister_notify(&usbfs_nb);
-	unregister_filesystem(&usb_fs_type);
-	if (usbdir)
-		remove_proc_entry("bus/usb", NULL);
-}
-
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index ca717da..b548cf1 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1308,10 +1308,19 @@
 	 * Remove the current alt setting and add the new alt setting.
 	 */
 	mutex_lock(hcd->bandwidth_mutex);
+	/* Disable LPM, and re-enable it once the new alt setting is installed,
+	 * so that the xHCI driver can recalculate the U1/U2 timeouts.
+	 */
+	if (usb_disable_lpm(dev)) {
+		dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__);
+		mutex_unlock(hcd->bandwidth_mutex);
+		return -ENOMEM;
+	}
 	ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
 	if (ret < 0) {
 		dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
 				alternate);
+		usb_enable_lpm(dev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		return ret;
 	}
@@ -1334,6 +1343,7 @@
 	} else if (ret < 0) {
 		/* Re-instate the old alt setting */
 		usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting);
+		usb_enable_lpm(dev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		return ret;
 	}
@@ -1354,6 +1364,9 @@
 
 	iface->cur_altsetting = alt;
 
+	/* Now that the interface is installed, re-enable LPM. */
+	usb_unlocked_enable_lpm(dev);
+
 	/* If the interface only has one altsetting and the device didn't
 	 * accept the request, we attempt to carry out the equivalent action
 	 * by manually clearing the HALT feature for each endpoint in the
@@ -1437,6 +1450,14 @@
 	config = dev->actconfig;
 	retval = 0;
 	mutex_lock(hcd->bandwidth_mutex);
+	/* Disable LPM, and re-enable it once the configuration is reset, so
+	 * that the xHCI driver can recalculate the U1/U2 timeouts.
+	 */
+	if (usb_disable_lpm(dev)) {
+		dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
+		mutex_unlock(hcd->bandwidth_mutex);
+		return -ENOMEM;
+	}
 	/* Make sure we have enough bandwidth for each alternate setting 0 */
 	for (i = 0; i < config->desc.bNumInterfaces; i++) {
 		struct usb_interface *intf = config->interface[i];
@@ -1465,6 +1486,7 @@
 				usb_hcd_alloc_bandwidth(dev, NULL,
 						alt, intf->cur_altsetting);
 		}
+		usb_enable_lpm(dev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		return retval;
 	}
@@ -1502,6 +1524,8 @@
 			create_intf_ep_devs(intf);
 		}
 	}
+	/* Now that the interfaces are installed, re-enable LPM. */
+	usb_unlocked_enable_lpm(dev);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(usb_reset_configuration);
@@ -1763,8 +1787,18 @@
 	 * this call fails, the device state is unchanged.
 	 */
 	mutex_lock(hcd->bandwidth_mutex);
+	/* Disable LPM, and re-enable it once the new configuration is
+	 * installed, so that the xHCI driver can recalculate the U1/U2
+	 * timeouts.
+	 */
+	if (usb_disable_lpm(dev)) {
+		dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
+		mutex_unlock(hcd->bandwidth_mutex);
+		return -ENOMEM;
+	}
 	ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
 	if (ret < 0) {
+		usb_enable_lpm(dev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		usb_autosuspend_device(dev);
 		goto free_interfaces;
@@ -1784,6 +1818,7 @@
 	if (!cp) {
 		usb_set_device_state(dev, USB_STATE_ADDRESS);
 		usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+		usb_enable_lpm(dev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		usb_autosuspend_device(dev);
 		goto free_interfaces;
@@ -1838,6 +1873,9 @@
 			!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
 		cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
 
+	/* Now that the interfaces are installed, re-enable LPM. */
+	usb_unlocked_enable_lpm(dev);
+
 	/* Now that all the interfaces are set up, register them
 	 * to trigger binding of drivers to interfaces.  probe()
 	 * routines may install different altsettings and may
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 4c65eb6..32d3adc 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -123,6 +123,9 @@
 	/* Guillemot Webcam Hercules Dualpix Exchange*/
 	{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Midiman M-Audio Keystation 88es */
+	{ USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
+
 	/* M-Systems Flash Disk Pioneers */
 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 566d9f9..9a56e3a 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -73,7 +73,7 @@
 	return (value < 0) ? value : count;
 }
 
-static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR,
 		show_bConfigurationValue, set_bConfigurationValue);
 
 /* String fields */
@@ -595,7 +595,7 @@
 	return result < 0? result : size;
 }
 
-static DEVICE_ATTR(authorized, 0644,
+static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644,
 	    usb_dev_authorized_show, usb_dev_authorized_store);
 
 /* "Safely remove a device" */
@@ -618,7 +618,7 @@
 	usb_unlock_device(udev);
 	return rc;
 }
-static DEVICE_ATTR(remove, 0200, NULL, usb_remove_store);
+static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store);
 
 
 static struct attribute *dev_attrs[] = {
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index cd9b3a2..9d912bf 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -681,6 +681,27 @@
 EXPORT_SYMBOL_GPL(usb_unpoison_urb);
 
 /**
+ * usb_block_urb - reliably prevent further use of an URB
+ * @urb: pointer to URB to be blocked, may be NULL
+ *
+ * After the routine has run, attempts to resubmit the URB will fail
+ * with error -EPERM.  Thus even if the URB's completion handler always
+ * tries to resubmit, it will not succeed and the URB will become idle.
+ *
+ * The URB must not be deallocated while this routine is running.  In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ */
+void usb_block_urb(struct urb *urb)
+{
+	if (!urb)
+		return;
+
+	atomic_inc(&urb->reject);
+}
+EXPORT_SYMBOL_GPL(usb_block_urb);
+
+/**
  * usb_kill_anchored_urbs - cancel transfer requests en masse
  * @anchor: anchor the requests are bound to
  *
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
new file mode 100644
index 0000000..8947b20
--- /dev/null
+++ b/drivers/usb/core/usb-acpi.c
@@ -0,0 +1,117 @@
+/*
+ * USB-ACPI glue code
+ *
+ * Copyright 2012 Red Hat <mjg@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include <acpi/acpi_bus.h>
+
+#include "usb.h"
+
+static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *upc;
+	int ret = 0;
+
+	status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
+
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	upc = buffer.pointer;
+
+	if (!upc || (upc->type != ACPI_TYPE_PACKAGE)
+		|| upc->package.count != 4) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (upc->package.elements[0].integer.value)
+		udev->removable = USB_DEVICE_REMOVABLE;
+	else
+		udev->removable = USB_DEVICE_FIXED;
+
+out:
+	kfree(upc);
+	return ret;
+}
+
+static int usb_acpi_check_pld(struct usb_device *udev, acpi_handle handle)
+{
+	acpi_status status;
+	struct acpi_pld pld;
+
+	status = acpi_get_physical_device_location(handle, &pld);
+
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	if (pld.user_visible)
+		udev->removable = USB_DEVICE_REMOVABLE;
+	else
+		udev->removable = USB_DEVICE_FIXED;
+
+	return 0;
+}
+
+static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
+{
+	struct usb_device *udev;
+	struct device *parent;
+	acpi_handle *parent_handle;
+
+	if (!is_usb_device(dev))
+		return -ENODEV;
+
+	udev = to_usb_device(dev);
+	parent = dev->parent;
+	parent_handle = DEVICE_ACPI_HANDLE(parent);
+
+	if (!parent_handle)
+		return -ENODEV;
+
+	*handle = acpi_get_child(parent_handle, udev->portnum);
+
+	if (!*handle)
+		return -ENODEV;
+
+	/*
+	 * PLD will tell us whether a port is removable to the user or
+	 * not. If we don't get an answer from PLD (it's not present
+	 * or it's malformed) then try to infer it from UPC. If a
+	 * device isn't connectable then it's probably not removable.
+	 */
+	if (usb_acpi_check_pld(udev, *handle) != 0)
+		usb_acpi_check_upc(udev, *handle);
+
+	return 0;
+}
+
+static struct acpi_bus_type usb_acpi_bus = {
+	.bus = &usb_bus_type,
+	.find_bridge = NULL,
+	.find_device = usb_acpi_find_device,
+};
+
+int usb_acpi_register(void)
+{
+	return register_acpi_bus_type(&usb_acpi_bus);
+}
+
+void usb_acpi_unregister(void)
+{
+	unregister_acpi_bus_type(&usb_acpi_bus);
+}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index c74ba7b..25d0c61 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1015,6 +1015,7 @@
 	if (retval)
 		goto out;
 
+	usb_acpi_register();
 	retval = bus_register(&usb_bus_type);
 	if (retval)
 		goto bus_register_failed;
@@ -1030,9 +1031,6 @@
 	retval = usb_devio_init();
 	if (retval)
 		goto usb_devio_init_failed;
-	retval = usbfs_init();
-	if (retval)
-		goto fs_init_failed;
 	retval = usb_hub_init();
 	if (retval)
 		goto hub_init_failed;
@@ -1042,8 +1040,6 @@
 
 	usb_hub_cleanup();
 hub_init_failed:
-	usbfs_cleanup();
-fs_init_failed:
 	usb_devio_cleanup();
 usb_devio_init_failed:
 	usb_deregister(&usbfs_driver);
@@ -1054,6 +1050,7 @@
 bus_notifier_failed:
 	bus_unregister(&usb_bus_type);
 bus_register_failed:
+	usb_acpi_unregister();
 	usb_debugfs_cleanup();
 out:
 	return retval;
@@ -1070,12 +1067,12 @@
 
 	usb_deregister_device_driver(&usb_generic_driver);
 	usb_major_cleanup();
-	usbfs_cleanup();
 	usb_deregister(&usbfs_driver);
 	usb_devio_cleanup();
 	usb_hub_cleanup();
 	bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
 	bus_unregister(&usb_bus_type);
+	usb_acpi_unregister();
 	usb_debugfs_cleanup();
 }
 
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 71648dc..5c5c538 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -156,3 +156,10 @@
 extern void usb_notify_add_bus(struct usb_bus *ubus);
 extern void usb_notify_remove_bus(struct usb_bus *ubus);
 
+#ifdef CONFIG_ACPI
+extern int usb_acpi_register(void);
+extern void usb_acpi_unregister(void);
+#else
+static inline int usb_acpi_register(void) { return 0; };
+static inline void usb_acpi_unregister(void) { };
+#endif
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index d8f741f..d13c60f4 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -4,7 +4,7 @@
 	select USB_OTG_UTILS
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_SUPERSPEED
-	select USB_XHCI_PLATFORM
+	select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
 	help
 	  Say Y or M here if your system has a Dual Role SuperSpeed
 	  USB controller based on the DesignWare USB3 IP Core.
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 99b58d84..1040bdb 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -410,7 +410,6 @@
 	struct device		*dev = &pdev->dev;
 
 	int			ret = -ENOMEM;
-	int			irq;
 
 	void __iomem		*regs;
 	void			*mem;
@@ -425,15 +424,28 @@
 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
 	dwc->mem = mem;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
-		dev_err(dev, "missing resource\n");
+		dev_err(dev, "missing IRQ\n");
 		return -ENODEV;
 	}
+	dwc->xhci_resources[1] = *res;
 
-	dwc->res = res;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "missing memory resource\n");
+		return -ENODEV;
+	}
+	dwc->xhci_resources[0] = *res;
+	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+					DWC3_XHCI_REGS_END;
 
-	res = devm_request_mem_region(dev, res->start, resource_size(res),
+	 /*
+	  * Request memory region but exclude xHCI regs,
+	  * since it will be requested by the xhci-plat driver.
+	  */
+	res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
+			resource_size(res) - DWC3_GLOBALS_REGS_START,
 			dev_name(dev));
 	if (!res) {
 		dev_err(dev, "can't request mem region\n");
@@ -446,19 +458,12 @@
 		return -ENOMEM;
 	}
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(dev, "missing IRQ\n");
-		return -ENODEV;
-	}
-
 	spin_lock_init(&dwc->lock);
 	platform_set_drvdata(pdev, dwc);
 
 	dwc->regs	= regs;
 	dwc->regs_size	= resource_size(res);
 	dwc->dev	= dev;
-	dwc->irq	= irq;
 
 	if (!strncmp("super", maximum_speed, 5))
 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 6c7945b..f69c877 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -51,7 +51,9 @@
 #include <linux/usb/gadget.h>
 
 /* Global constants */
+#define DWC3_EP0_BOUNCE_SIZE	512
 #define DWC3_ENDPOINTS_NUM	32
+#define DWC3_XHCI_RESOURCES_NUM	2
 
 #define DWC3_EVENT_BUFFERS_SIZE	PAGE_SIZE
 #define DWC3_EVENT_TYPE_MASK	0xfe
@@ -75,6 +77,16 @@
 #define DWC3_GSNPSID_MASK	0xffff0000
 #define DWC3_GSNPSREV_MASK	0xffff
 
+/* DWC3 registers memory space boundries */
+#define DWC3_XHCI_REGS_START		0x0
+#define DWC3_XHCI_REGS_END		0x7fff
+#define DWC3_GLOBALS_REGS_START		0xc100
+#define DWC3_GLOBALS_REGS_END		0xc6ff
+#define DWC3_DEVICE_REGS_START		0xc700
+#define DWC3_DEVICE_REGS_END		0xcbff
+#define DWC3_OTG_REGS_START		0xcc00
+#define DWC3_OTG_REGS_END		0xccff
+
 /* Global Registers */
 #define DWC3_GSBUSCFG0		0xc100
 #define DWC3_GSBUSCFG1		0xc104
@@ -183,6 +195,7 @@
 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
 
 /* Device Configuration Register */
+#define DWC3_DCFG_LPM_CAP	(1 << 22)
 #define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
 #define DWC3_DCFG_DEVADDR_MASK	DWC3_DCFG_DEVADDR(0x7f)
 
@@ -272,12 +285,14 @@
 #define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
 #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK	0x10
 
+#define DWC3_DGCMD_STATUS(n)		(((n) >> 15) & 1)
+#define DWC3_DGCMD_CMDACT		(1 << 10)
+
 /* Device Endpoint Command Register */
 #define DWC3_DEPCMD_PARAM_SHIFT		16
 #define DWC3_DEPCMD_PARAM(x)		((x) << DWC3_DEPCMD_PARAM_SHIFT)
 #define DWC3_DEPCMD_GET_RSC_IDX(x)     (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
-#define DWC3_DEPCMD_STATUS_MASK		(0x0f << 12)
-#define DWC3_DEPCMD_STATUS(x)		(((x) & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_STATUS(x)		(((x) >> 15) & 1)
 #define DWC3_DEPCMD_HIPRI_FORCERM	(1 << 11)
 #define DWC3_DEPCMD_CMDACT		(1 << 10)
 #define DWC3_DEPCMD_CMDIOC		(1 << 8)
@@ -361,7 +376,6 @@
 	dma_addr_t		trb_pool_dma;
 	u32			free_slot;
 	u32			busy_slot;
-	const struct usb_endpoint_descriptor *desc;
 	const struct usb_ss_ep_comp_descriptor *comp_desc;
 	struct dwc3		*dwc;
 
@@ -561,6 +575,11 @@
  * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
  * @needs_fifo_resize: not all users might want fifo resizing, flag it
  * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
+ * @isoch_delay: wValue from Set Isochronous Delay request;
+ * @u2sel: parameter from Set SEL request.
+ * @u2pel: parameter from Set SEL request.
+ * @u1sel: parameter from Set SEL request.
+ * @u1pel: parameter from Set SEL request.
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -583,7 +602,7 @@
 	struct device		*dev;
 
 	struct platform_device	*xhci;
-	struct resource		*res;
+	struct resource		xhci_resources[DWC3_XHCI_RESOURCES_NUM];
 
 	struct dwc3_event_buffer **ev_buffs;
 	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];
@@ -594,8 +613,6 @@
 	void __iomem		*regs;
 	size_t			regs_size;
 
-	int			irq;
-
 	u32			num_event_buffers;
 	u32			u1u2;
 	u32			maximum_speed;
@@ -609,6 +626,10 @@
 #define DWC3_REVISION_185A	0x5533185a
 #define DWC3_REVISION_188A	0x5533188a
 #define DWC3_REVISION_190A	0x5533190a
+#define DWC3_REVISION_200A	0x5533200a
+#define DWC3_REVISION_202A	0x5533202a
+#define DWC3_REVISION_210A	0x5533210a
+#define DWC3_REVISION_220A	0x5533220a
 
 	unsigned		is_selfpowered:1;
 	unsigned		three_stage_setup:1;
@@ -625,7 +646,14 @@
 	enum dwc3_link_state	link_state;
 	enum dwc3_device_state	dev_state;
 
+	u16			isoch_delay;
+	u16			u2sel;
+	u16			u2pel;
+	u8			u1sel;
+	u8			u1pel;
+
 	u8			speed;
+
 	void			*mem;
 
 	struct dwc3_hwparams	hwparams;
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index d7d9c0e..479dc04 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -49,7 +49,6 @@
 #include <linux/of.h>
 
 #include "core.h"
-#include "io.h"
 
 /*
  * All these registers belong to OMAP's Wrapper around the
@@ -143,6 +142,17 @@
 	u32			dma_status:1;
 };
 
+static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel(value, base + offset);
+}
+
+
 static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 {
 	struct dwc3_omap	*omap = _omap;
@@ -150,7 +160,7 @@
 
 	spin_lock(&omap->lock);
 
-	reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1);
 
 	if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
 		dev_dbg(omap->dev, "DMA Disable was Cleared\n");
@@ -184,10 +194,10 @@
 	if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
 		dev_dbg(omap->dev, "IDPULLUP Fall\n");
 
-	dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
 
-	reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
-	dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
 
 	spin_unlock(&omap->lock);
 
@@ -270,7 +280,7 @@
 	omap->base	= base;
 	omap->dwc3	= dwc3;
 
-	reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
 
 	utmi_mode = of_get_property(node, "utmi-mode", &size);
 	if (utmi_mode && size == sizeof(*utmi_mode)) {
@@ -293,10 +303,10 @@
 		}
 	}
 
-	dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
 
 	/* check the DMA Status */
-	reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
 	omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
 
 	/* Set No-Idle and No-Standby */
@@ -306,7 +316,7 @@
 	reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
 		| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
 
-	dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
 
 	ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
 			"dwc3-omap", omap);
@@ -318,7 +328,7 @@
 
 	/* enable all IRQs */
 	reg = USBOTGSS_IRQO_COREIRQ_ST;
-	dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
 
 	reg = (USBOTGSS_IRQ1_OEVT |
 			USBOTGSS_IRQ1_DRVVBUS_RISE |
@@ -330,7 +340,7 @@
 			USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
 			USBOTGSS_IRQ1_IDPULLUP_FALL);
 
-	dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
 
 	ret = platform_device_add_resources(dwc3, pdev->resource,
 			pdev->num_resources);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 3584a16..9e8a3dc 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -179,7 +179,7 @@
 	int				ret;
 
 	spin_lock_irqsave(&dwc->lock, flags);
-	if (!dep->desc) {
+	if (!dep->endpoint.desc) {
 		dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
 				request, dep->name);
 		ret = -ESHUTDOWN;
@@ -261,6 +261,7 @@
 {
 	struct dwc3_ep		*dep;
 	u32			recip;
+	u32			reg;
 	u16			usb_status = 0;
 	__le16			*response_pkt;
 
@@ -268,10 +269,18 @@
 	switch (recip) {
 	case USB_RECIP_DEVICE:
 		/*
-		 * We are self-powered. U1/U2/LTM will be set later
-		 * once we handle this states. RemoteWakeup is 0 on SS
+		 * LTM will be set once we know how to set this in HW.
 		 */
 		usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+
+		if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			if (reg & DWC3_DCTL_INITU1ENA)
+				usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
+			if (reg & DWC3_DCTL_INITU2ENA)
+				usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
+		}
+
 		break;
 
 	case USB_RECIP_INTERFACE:
@@ -312,6 +321,7 @@
 	u32			recip;
 	u32			wValue;
 	u32			wIndex;
+	u32			reg;
 	int			ret;
 
 	wValue = le16_to_cpu(ctrl->wValue);
@@ -320,29 +330,43 @@
 	switch (recip) {
 	case USB_RECIP_DEVICE:
 
+		switch (wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			break;
 		/*
 		 * 9.4.1 says only only for SS, in AddressState only for
 		 * default control pipe
 		 */
-		switch (wValue) {
 		case USB_DEVICE_U1_ENABLE:
-		case USB_DEVICE_U2_ENABLE:
-		case USB_DEVICE_LTM_ENABLE:
 			if (dwc->dev_state != DWC3_CONFIGURED_STATE)
 				return -EINVAL;
 			if (dwc->speed != DWC3_DSTS_SUPERSPEED)
 				return -EINVAL;
-		}
 
-		/* XXX add U[12] & LTM */
-		switch (wValue) {
-		case USB_DEVICE_REMOTE_WAKEUP:
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			if (set)
+				reg |= DWC3_DCTL_INITU1ENA;
+			else
+				reg &= ~DWC3_DCTL_INITU1ENA;
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 			break;
-		case USB_DEVICE_U1_ENABLE:
-			break;
+
 		case USB_DEVICE_U2_ENABLE:
+			if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+				return -EINVAL;
+			if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+				return -EINVAL;
+
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			if (set)
+				reg |= DWC3_DCTL_INITU2ENA;
+			else
+				reg &= ~DWC3_DCTL_INITU2ENA;
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 			break;
+
 		case USB_DEVICE_LTM_ENABLE:
+			return -EINVAL;
 			break;
 
 		case USB_DEVICE_TEST_MODE:
@@ -469,6 +493,107 @@
 	return ret;
 }
 
+static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct dwc3_ep	*dep = to_dwc3_ep(ep);
+	struct dwc3	*dwc = dep->dwc;
+
+	u32		param = 0;
+	u32		reg;
+
+	struct timing {
+		u8	u1sel;
+		u8	u1pel;
+		u16	u2sel;
+		u16	u2pel;
+	} __packed timing;
+
+	int		ret;
+
+	memcpy(&timing, req->buf, sizeof(timing));
+
+	dwc->u1sel = timing.u1sel;
+	dwc->u1pel = timing.u1pel;
+	dwc->u2sel = timing.u2sel;
+	dwc->u2pel = timing.u2pel;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	if (reg & DWC3_DCTL_INITU2ENA)
+		param = dwc->u2pel;
+	if (reg & DWC3_DCTL_INITU1ENA)
+		param = dwc->u1pel;
+
+	/*
+	 * According to Synopsys Databook, if parameter is
+	 * greater than 125, a value of zero should be
+	 * programmed in the register.
+	 */
+	if (param > 125)
+		param = 0;
+
+	/* now that we have the time, issue DGCMD Set Sel */
+	ret = dwc3_send_gadget_generic_command(dwc,
+			DWC3_DGCMD_SET_PERIODIC_PAR, param);
+	WARN_ON(ret < 0);
+}
+
+static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	struct dwc3_ep	*dep;
+	u16		wLength;
+	u16		wValue;
+
+	if (dwc->dev_state == DWC3_DEFAULT_STATE)
+		return -EINVAL;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+	wLength = le16_to_cpu(ctrl->wLength);
+
+	if (wLength != 6) {
+		dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n",
+				wLength);
+		return -EINVAL;
+	}
+
+	/*
+	 * To handle Set SEL we need to receive 6 bytes from Host. So let's
+	 * queue a usb_request for 6 bytes.
+	 *
+	 * Remember, though, this controller can't handle non-wMaxPacketSize
+	 * aligned transfers on the OUT direction, so we queue a request for
+	 * wMaxPacketSize instead.
+	 */
+	dep = dwc->eps[0];
+	dwc->ep0_usb_req.dep = dep;
+	dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket;
+	dwc->ep0_usb_req.request.buf = dwc->setup_buf;
+	dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl;
+
+	return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
+}
+
+static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	u16		wLength;
+	u16		wValue;
+	u16		wIndex;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+	wLength = le16_to_cpu(ctrl->wLength);
+	wIndex = le16_to_cpu(ctrl->wIndex);
+
+	if (wIndex || wLength)
+		return -EINVAL;
+
+	/*
+	 * REVISIT It's unclear from Databook what to do with this
+	 * value. For now, just cache it.
+	 */
+	dwc->isoch_delay = wValue;
+
+	return 0;
+}
+
 static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
 	int ret;
@@ -494,6 +619,14 @@
 		dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
 		ret = dwc3_ep0_set_config(dwc, ctrl);
 		break;
+	case USB_REQ_SET_SEL:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_SEL\n");
+		ret = dwc3_ep0_set_sel(dwc, ctrl);
+		break;
+	case USB_REQ_SET_ISOCH_DELAY:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n");
+		ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
+		break;
 	default:
 		dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5255fe97..3df1a19 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -178,8 +178,8 @@
 		if (!(dep->flags & DWC3_EP_ENABLED))
 			continue;
 
-		if (usb_endpoint_xfer_bulk(dep->desc)
-				|| usb_endpoint_xfer_isoc(dep->desc))
+		if (usb_endpoint_xfer_bulk(dep->endpoint.desc)
+				|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
 			mult = 3;
 
 		/*
@@ -229,7 +229,7 @@
 		 * completed (not the LINK TRB).
 		 */
 		if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
-				usb_endpoint_xfer_isoc(dep->desc))
+				usb_endpoint_xfer_isoc(dep->endpoint.desc))
 			dep->busy_slot++;
 	}
 	list_del(&req->list);
@@ -276,6 +276,33 @@
 	}
 }
 
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)
+{
+	u32		timeout = 500;
+	u32		reg;
+
+	dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
+	dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
+
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
+		if (!(reg & DWC3_DGCMD_CMDACT)) {
+			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+					DWC3_DGCMD_STATUS(reg));
+			return 0;
+		}
+
+		/*
+		 * We can't sleep here, because it's also called from
+		 * interrupt context.
+		 */
+		timeout--;
+		if (!timeout)
+			return -ETIMEDOUT;
+		udelay(1);
+	} while (1);
+}
+
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
 {
@@ -470,7 +497,7 @@
 		if (ret)
 			return ret;
 
-		dep->desc = desc;
+		dep->endpoint.desc = desc;
 		dep->comp_desc = comp_desc;
 		dep->type = usb_endpoint_type(desc);
 		dep->flags |= DWC3_EP_ENABLED;
@@ -533,7 +560,6 @@
 	dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
 
 	dep->stream_capable = false;
-	dep->desc = NULL;
 	dep->endpoint.desc = NULL;
 	dep->comp_desc = NULL;
 	dep->type = 0;
@@ -694,7 +720,7 @@
 
 	/* Skip the LINK-TRB on ISOC */
 	if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
-			usb_endpoint_xfer_isoc(dep->desc))
+			usb_endpoint_xfer_isoc(dep->endpoint.desc))
 		return;
 
 	if (!req->trb) {
@@ -707,7 +733,7 @@
 	trb->bpl = lower_32_bits(dma);
 	trb->bph = upper_32_bits(dma);
 
-	switch (usb_endpoint_type(dep->desc)) {
+	switch (usb_endpoint_type(dep->endpoint.desc)) {
 	case USB_ENDPOINT_XFER_CONTROL:
 		trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
 		break;
@@ -732,7 +758,7 @@
 		BUG();
 	}
 
-	if (usb_endpoint_xfer_isoc(dep->desc)) {
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 		trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
 		trb->ctrl |= DWC3_TRB_CTRL_CSP;
 	} else {
@@ -743,7 +769,7 @@
 			trb->ctrl |= DWC3_TRB_CTRL_LST;
 	}
 
-	if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+	if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
 		trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
 
 	trb->ctrl |= DWC3_TRB_CTRL_HWO;
@@ -771,7 +797,7 @@
 	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
 
 	/* Can't wrap around on a non-isoc EP since there's no link TRB */
-	if (!usb_endpoint_xfer_isoc(dep->desc)) {
+	if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 		max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
 		if (trbs_left > max)
 			trbs_left = max;
@@ -797,7 +823,7 @@
 		 * processed from the first TRB until the last one. Since we
 		 * don't wrap around we have to start at the beginning.
 		 */
-		if (usb_endpoint_xfer_isoc(dep->desc)) {
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 			dep->busy_slot = 1;
 			dep->free_slot = 1;
 		} else {
@@ -807,7 +833,7 @@
 	}
 
 	/* The last TRB is a link TRB, not used for xfer */
-	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
+	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
 		return;
 
 	list_for_each_entry_safe(req, n, &dep->request_list, list) {
@@ -930,10 +956,12 @@
 	}
 
 	dep->flags |= DWC3_EP_BUSY;
-	dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
-			dep->number);
 
-	WARN_ON_ONCE(!dep->res_trans_idx);
+	if (start_new) {
+		dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+				dep->number);
+		WARN_ON_ONCE(!dep->res_trans_idx);
+	}
 
 	return 0;
 }
@@ -967,28 +995,37 @@
 
 	list_add_tail(&req->list, &dep->request_list);
 
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY))
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+
 	/*
-	 * There is one special case: XferNotReady with
-	 * empty list of requests. We need to kick the
-	 * transfer here in that situation, otherwise
-	 * we will be NAKing forever.
+	 * There are two special cases:
 	 *
-	 * If we get XferNotReady before gadget driver
-	 * has a chance to queue a request, we will ACK
-	 * the IRQ but won't be able to receive the data
-	 * until the next request is queued. The following
-	 * code is handling exactly that.
+	 * 1. XferNotReady with empty list of requests. We need to kick the
+	 *    transfer here in that situation, otherwise we will be NAKing
+	 *    forever. If we get XferNotReady before gadget driver has a
+	 *    chance to queue a request, we will ACK the IRQ but won't be
+	 *    able to receive the data until the next request is queued.
+	 *    The following code is handling exactly that.
+	 *
+	 * 2. XferInProgress on Isoc EP with an active transfer. We need to
+	 *    kick the transfer here after queuing a request, otherwise the
+	 *    core may not see the modified TRB(s).
 	 */
 	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
-		int ret;
-		int start_trans;
+		int	ret;
+		int	start_trans = 1;
+		u8	trans_idx = dep->res_trans_idx;
 
-		start_trans = 1;
-		if (usb_endpoint_xfer_isoc(dep->desc) &&
-				(dep->flags & DWC3_EP_BUSY))
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+				(dep->flags & DWC3_EP_BUSY)) {
 			start_trans = 0;
+			WARN_ON_ONCE(!trans_idx);
+		} else {
+			trans_idx = 0;
+		}
 
-		ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+		ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans);
 		if (ret && ret != -EBUSY) {
 			struct dwc3	*dwc = dep->dwc;
 
@@ -1011,7 +1048,7 @@
 
 	int				ret;
 
-	if (!dep->desc) {
+	if (!dep->endpoint.desc) {
 		dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
 				request, ep->name);
 		return -ESHUTDOWN;
@@ -1125,7 +1162,7 @@
 
 	spin_lock_irqsave(&dwc->lock, flags);
 
-	if (usb_endpoint_xfer_isoc(dep->desc)) {
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 		dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
 		ret = -EINVAL;
 		goto out;
@@ -1356,7 +1393,24 @@
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
 	reg &= ~(DWC3_DCFG_SPEED_MASK);
-	reg |= dwc->maximum_speed;
+
+	/**
+	 * WORKAROUND: DWC3 revision < 2.20a have an issue
+	 * which would cause metastability state on Run/Stop
+	 * bit if we try to force the IP to USB2-only mode.
+	 *
+	 * Because of that, we cannot configure the IP to any
+	 * speed other than the SuperSpeed
+	 *
+	 * Refers to:
+	 *
+	 * STAR#9000525659: Clock Domain Crossing on DCTL in
+	 * USB 2.0 Mode
+	 */
+	if (dwc->revision < DWC3_REVISION_220A)
+		reg |= DWC3_DCFG_SUPERSPEED;
+	else
+		reg |= dwc->maximum_speed;
 	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
 	dwc->start_config_issued = false;
@@ -1681,7 +1735,7 @@
 	case DWC3_DEPEVT_XFERCOMPLETE:
 		dep->res_trans_idx = 0;
 
-		if (usb_endpoint_xfer_isoc(dep->desc)) {
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 			dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
 					dep->name);
 			return;
@@ -1690,7 +1744,7 @@
 		dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
 		break;
 	case DWC3_DEPEVT_XFERINPROGRESS:
-		if (!usb_endpoint_xfer_isoc(dep->desc)) {
+		if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 			dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
 					dep->name);
 			return;
@@ -1699,7 +1753,7 @@
 		dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
 		break;
 	case DWC3_DEPEVT_XFERNOTREADY:
-		if (usb_endpoint_xfer_isoc(dep->desc)) {
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 			dwc3_gadget_start_isoc(dwc, dep, event);
 		} else {
 			int ret;
@@ -1720,7 +1774,7 @@
 
 		break;
 	case DWC3_DEPEVT_STREAMEVT:
-		if (!usb_endpoint_xfer_bulk(dep->desc)) {
+		if (!usb_endpoint_xfer_bulk(dep->endpoint.desc)) {
 			dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
 					dep->name);
 			return;
@@ -1916,6 +1970,7 @@
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+	reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA);
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 	dwc->test_mode = false;
 
@@ -2263,8 +2318,7 @@
 		goto err1;
 	}
 
-	dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
-			GFP_KERNEL);
+	dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
 	if (!dwc->setup_buf) {
 		dev_err(dwc->dev, "failed to allocate setup buffer\n");
 		ret = -ENOMEM;
@@ -2272,7 +2326,8 @@
 	}
 
 	dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
-			512, &dwc->ep0_bounce_addr, GFP_KERNEL);
+			DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
+			GFP_KERNEL);
 	if (!dwc->ep0_bounce) {
 		dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
 		ret = -ENOMEM;
@@ -2313,6 +2368,14 @@
 		goto err5;
 	}
 
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg |= DWC3_DCFG_LPM_CAP;
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
 	/* Enable all but Start and End of Frame IRQs */
 	reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
 			DWC3_DEVTEN_EVNTOVERFLOWEN |
@@ -2351,8 +2414,8 @@
 	dwc3_gadget_free_endpoints(dwc);
 
 err4:
-	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
-			dwc->ep0_bounce_addr);
+	dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+			dwc->ep0_bounce, dwc->ep0_bounce_addr);
 
 err3:
 	kfree(dwc->setup_buf);
@@ -2381,8 +2444,8 @@
 
 	dwc3_gadget_free_endpoints(dwc);
 
-	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
-			dwc->ep0_bounce_addr);
+	dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+			dwc->ep0_bounce, dwc->ep0_bounce_addr);
 
 	kfree(dwc->setup_buf);
 
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index a860008..95ef6a2 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -111,6 +111,7 @@
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);
 
 /**
  * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index b108d18..56a6234 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -39,15 +39,6 @@
 
 #include "core.h"
 
-static struct resource generic_resources[] = {
-	{
-		.flags = IORESOURCE_IRQ,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-};
-
 int dwc3_host_init(struct dwc3 *dwc)
 {
 	struct platform_device	*xhci;
@@ -68,14 +59,8 @@
 
 	dwc->xhci = xhci;
 
-	/* setup resources */
-	generic_resources[0].start = dwc->irq;
-
-	generic_resources[1].start = dwc->res->start;
-	generic_resources[1].end = dwc->res->start + 0x7fff;
-
-	ret = platform_device_add_resources(xhci, generic_resources,
-			ARRAY_SIZE(generic_resources));
+	ret = platform_device_add_resources(xhci, dwc->xhci_resources,
+						DWC3_XHCI_RESOURCES_NUM);
 	if (ret) {
 		dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
 		goto err1;
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 071d561..a50f76b 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -41,14 +41,26 @@
 
 #include <linux/io.h>
 
+#include "core.h"
+
 static inline u32 dwc3_readl(void __iomem *base, u32 offset)
 {
-	return readl(base + offset);
+	/*
+	 * We requested the mem region starting from the Globals address
+	 * space, see dwc3_probe in core.c.
+	 * However, the offsets are given starting from xHCI address space.
+	 */
+	return readl(base + (offset - DWC3_GLOBALS_REGS_START));
 }
 
 static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
 {
-	writel(value, base + offset);
+	/*
+	 * We requested the mem region starting from the Globals address
+	 * space, see dwc3_probe in core.c.
+	 * However, the offsets are given starting from xHCI address space.
+	 */
+	writel(value, base + (offset - DWC3_GLOBALS_REGS_START));
 }
 
 #endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 569b33e..bddc8fd 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -123,13 +123,7 @@
 #   - discrete ones (including all PCI-only controllers)
 #   - debug/dummy gadget+hcd is last.
 #
-choice
-	prompt "USB Peripheral Controller"
-	help
-	   A USB device uses a controller to talk to its host.
-	   Systems should have only one such upstream link.
-	   Many controller drivers are platform-specific; these
-	   often need board-specific hooks.
+menu "USB Peripheral Controller"
 
 #
 # Integrated controllers
@@ -147,6 +141,17 @@
 	   dynamically linked module called "at91_udc" and force all
 	   gadget drivers to also be dynamically linked.
 
+config USB_LPC32XX
+	tristate "LPC32XX USB Peripheral Controller"
+	depends on ARCH_LPC32XX
+	select USB_ISP1301
+	help
+	   This option selects the USB device controller in the LPC32xx SoC.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "lpc32xx_udc" and force all
+	   gadget drivers to also be dynamically linked.
+
 config USB_ATMEL_USBA
 	tristate "Atmel USBA"
 	select USB_GADGET_DUALSPEED
@@ -161,7 +166,7 @@
 	select USB_GADGET_DUALSPEED
 	select USB_FSL_MPH_DR_OF if OF
 	help
-	   Some of Freescale PowerPC processors have a High Speed
+	   Some of Freescale PowerPC and i.MX processors have a High Speed
 	   Dual-Role(DR) USB controller, which supports device mode.
 
 	   The number of programmable endpoints is different through
@@ -373,18 +378,6 @@
 	   Set CONFIG_USB_GADGET to "m" to build this driver as a
 	   dynamically linked module called "fsl_qe_udc".
 
-config USB_CI13XXX_PCI
-	tristate "MIPS USB CI13xxx PCI UDC"
-	depends on PCI
-	select USB_GADGET_DUALSPEED
-	help
-	  MIPS USB IP core family device controller
-	  Currently it only supports IP part number CI13412
-
-	  Say "y" to link the driver statically, or "m" to build a
-	  dynamically linked module called "ci13xxx_udc" and force all
-	  gadget drivers to also be dynamically linked.
-
 config USB_NET2272
 	tristate "PLX NET2272"
 	select USB_GADGET_DUALSPEED
@@ -438,22 +431,6 @@
 	   dynamically linked module called "goku_udc" and to force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_LANGWELL
-	tristate "Intel Langwell USB Device Controller"
-	depends on PCI
-	depends on !PHYS_ADDR_T_64BIT
-	select USB_GADGET_DUALSPEED
-	help
-	   Intel Langwell USB Device Controller is a High-Speed USB
-	   On-The-Go device controller.
-
-	   The number of programmable endpoints is different through
-	   controller revision.
-
-	   Say "y" to link the driver statically, or "m" to build a
-	   dynamically linked module called "langwell_udc" and force all
-	   gadget drivers to also be dynamically linked.
-
 config USB_EG20T
 	tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
 	depends on PCI
@@ -477,23 +454,6 @@
 	  ML7213/ML7831 is companion chip for Intel Atom E6xx series.
 	  ML7213/ML7831 is completely compatible for Intel EG20T PCH.
 
-config USB_CI13XXX_MSM
-	tristate "MIPS USB CI13xxx for MSM"
-	depends on ARCH_MSM
-	select USB_GADGET_DUALSPEED
-	select USB_MSM_OTG
-	help
-	  MSM SoC has chipidea USB controller.  This driver uses
-	  ci13xxx_udc core.
-	  This driver depends on OTG driver for PHY initialization,
-	  clock management, powering up VBUS, and power management.
-	  This driver is not supported on boards like trout which
-	  has an external PHY.
-
-	  Say "y" to link the driver statically, or "m" to build a
-	  dynamically linked module called "ci13xxx_msm" and force all
-	  gadget drivers to also be dynamically linked.
-
 #
 # LAST -- dummy/emulated controller
 #
@@ -525,7 +485,7 @@
 # NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears
 # first and will be selected by default.
 
-endchoice
+endmenu
 
 # Selected by UDC drivers that support high-speed operation.
 config USB_GADGET_DUALSPEED
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index fc5b8368..1811513 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -22,14 +22,12 @@
 obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
 obj-$(CONFIG_USB_R8A66597)	+= r8a66597-udc.o
 obj-$(CONFIG_USB_FSL_QE)	+= fsl_qe_udc.o
-obj-$(CONFIG_USB_CI13XXX_PCI)	+= ci13xxx_pci.o
 obj-$(CONFIG_USB_S3C_HSOTG)	+= s3c-hsotg.o
 obj-$(CONFIG_USB_S3C_HSUDC)	+= s3c-hsudc.o
-obj-$(CONFIG_USB_LANGWELL)	+= langwell_udc.o
+obj-$(CONFIG_USB_LPC32XX)	+= lpc32xx_udc.o
 obj-$(CONFIG_USB_EG20T)		+= pch_udc.o
 obj-$(CONFIG_USB_MV_UDC)	+= mv_udc.o
 mv_udc-y			:= mv_udc_core.o
-obj-$(CONFIG_USB_CI13XXX_MSM)	+= ci13xxx_msm.o
 obj-$(CONFIG_USB_FUSB300)	+= fusb300_udc.o
 
 #
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 7777927..187d211 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -333,7 +333,7 @@
 		return -ESHUTDOWN;
 
 	spin_lock_irqsave(&dev->lock, iflags);
-	ep->desc = desc;
+	ep->ep.desc = desc;
 
 	ep->halted = 0;
 
@@ -442,7 +442,6 @@
 	u32		tmp;
 
 	VDBG(ep->dev, "ep-%d reset\n", ep->num);
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	ep->ep.ops = &udc_ep_ops;
 	INIT_LIST_HEAD(&ep->queue);
@@ -489,7 +488,7 @@
 		return -EINVAL;
 
 	ep = container_of(usbep, struct udc_ep, ep);
-	if (usbep->name == ep0_string || !ep->desc)
+	if (usbep->name == ep0_string || !ep->ep.desc)
 		return -EINVAL;
 
 	DBG(ep->dev, "Disable ep-%d\n", ep->num);
@@ -1066,7 +1065,7 @@
 		return -EINVAL;
 
 	ep = container_of(usbep, struct udc_ep, ep);
-	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+	if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
 		return -EINVAL;
 
 	VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
@@ -1257,7 +1256,7 @@
 	unsigned long		iflags;
 
 	ep = container_of(usbep, struct udc_ep, ep);
-	if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+	if (!usbep || !usbreq || (!ep->ep.desc && (ep->num != 0
 				&& ep->num != UDC_EP0OUT_IX)))
 		return -EINVAL;
 
@@ -1317,7 +1316,7 @@
 	pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
 
 	ep = container_of(usbep, struct udc_ep, ep);
-	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+	if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
 		return -EINVAL;
 	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
 		return -ESHUTDOWN;
@@ -1539,7 +1538,7 @@
 		 * disabling ep interrupts when ENUM interrupt occurs but ep is
 		 * not enabled by gadget driver
 		 */
-		if (!ep->desc)
+		if (!ep->ep.desc)
 			ep_init(dev->regs, ep);
 
 		if (use_dma) {
@@ -3402,19 +3401,7 @@
 	.remove =	udc_pci_remove,
 };
 
-/* Inits driver */
-static int __init init(void)
-{
-	return pci_register_driver(&udc_pci_driver);
-}
-module_init(init);
-
-/* Cleans driver */
-static void __exit cleanup(void)
-{
-	pci_unregister_driver(&udc_pci_driver);
-}
-module_exit(cleanup);
+module_pci_driver(udc_pci_driver);
 
 MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
 MODULE_AUTHOR("Thomas Dahlmann");
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
index f87e29c..14af87d 100644
--- a/drivers/usb/gadget/amd5536udc.h
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -512,7 +512,6 @@
 
 	/* queue for requests */
 	struct list_head		queue;
-	const struct usb_endpoint_descriptor	*desc;
 	unsigned			halted;
 	unsigned			cancel_transfer;
 	unsigned			num : 5,
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 9d7bcd9..1a4430f 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -212,7 +212,7 @@
 	if (udc->enabled && udc->vbus) {
 		proc_ep_show(s, &udc->ep[0]);
 		list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
-			if (ep->desc)
+			if (ep->ep.desc)
 				proc_ep_show(s, ep);
 		}
 	}
@@ -475,7 +475,7 @@
 	unsigned long	flags;
 
 	if (!_ep || !ep
-			|| !desc || ep->desc
+			|| !desc || ep->ep.desc
 			|| _ep->name == ep0name
 			|| desc->bDescriptorType != USB_DT_ENDPOINT
 			|| (maxpacket = usb_endpoint_maxp(desc)) == 0
@@ -530,7 +530,7 @@
 	tmp |= AT91_UDP_EPEDS;
 	__raw_writel(tmp, ep->creg);
 
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	ep->ep.maxpacket = maxpacket;
 
 	/*
@@ -558,7 +558,6 @@
 	nuke(ep, -ESHUTDOWN);
 
 	/* restore the endpoint's pristine config */
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	ep->ep.maxpacket = ep->maxpacket;
 
@@ -618,7 +617,7 @@
 		return -EINVAL;
 	}
 
-	if (!_ep || (!ep->desc && ep->ep.name != ep0name)) {
+	if (!_ep || (!ep->ep.desc && ep->ep.name != ep0name)) {
 		DBG("invalid ep\n");
 		return -EINVAL;
 	}
@@ -833,7 +832,7 @@
 
 		if (i != 0)
 			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
-		ep->desc = NULL;
+		ep->ep.desc = NULL;
 		ep->stopped = 0;
 		ep->fifo_bank = 0;
 		ep->ep.maxpacket = ep->maxpacket;
@@ -978,18 +977,18 @@
 	return 0;
 }
 
-static int at91_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int at91_stop(struct usb_gadget_driver *driver);
-
+static int at91_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
+static int at91_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops at91_udc_ops = {
 	.get_frame		= at91_get_frame,
 	.wakeup			= at91_wakeup,
 	.set_selfpowered	= at91_set_selfpowered,
 	.vbus_session		= at91_vbus_session,
 	.pullup			= at91_pullup,
-	.start			= at91_start,
-	.stop			= at91_stop,
+	.udc_start		= at91_start,
+	.udc_stop		= at91_stop,
 
 	/*
 	 * VBUS-powered devices may also also want to support bigger
@@ -1172,7 +1171,7 @@
 			| USB_REQ_GET_STATUS:
 		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
 		ep = &udc->ep[tmp];
-		if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc))
+		if (tmp >= NUM_ENDPOINTS || (tmp && !ep->ep.desc))
 			goto stall;
 
 		if (tmp) {
@@ -1197,7 +1196,7 @@
 		ep = &udc->ep[tmp];
 		if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
 			goto stall;
-		if (!ep->desc || ep->is_iso)
+		if (!ep->ep.desc || ep->is_iso)
 			goto stall;
 		if ((w_index & USB_DIR_IN)) {
 			if (!ep->is_in)
@@ -1218,7 +1217,7 @@
 			goto stall;
 		if (tmp == 0)
 			goto succeed;
-		if (!ep->desc || ep->is_iso)
+		if (!ep->ep.desc || ep->is_iso)
 			goto stall;
 		if ((w_index & USB_DIR_IN)) {
 			if (!ep->is_in)
@@ -1627,66 +1626,34 @@
 		schedule_work(&udc->vbus_timer_work);
 }
 
-static int at91_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int at91_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct at91_udc	*udc = &controller;
-	int		retval;
-	unsigned long	flags;
+	struct at91_udc	*udc;
 
-	if (!driver
-			|| driver->max_speed < USB_SPEED_FULL
-			|| !bind
-			|| !driver->setup) {
-		DBG("bad parameter.\n");
-		return -EINVAL;
-	}
-
-	if (udc->driver) {
-		DBG("UDC already has a gadget driver\n");
-		return -EBUSY;
-	}
-
+	udc = container_of(gadget, struct at91_udc, gadget);
 	udc->driver = driver;
 	udc->gadget.dev.driver = &driver->driver;
 	dev_set_drvdata(&udc->gadget.dev, &driver->driver);
 	udc->enabled = 1;
 	udc->selfpowered = 1;
 
-	retval = bind(&udc->gadget);
-	if (retval) {
-		DBG("bind() returned %d\n", retval);
-		udc->driver = NULL;
-		udc->gadget.dev.driver = NULL;
-		dev_set_drvdata(&udc->gadget.dev, NULL);
-		udc->enabled = 0;
-		udc->selfpowered = 0;
-		return retval;
-	}
-
-	spin_lock_irqsave(&udc->lock, flags);
-	pullup(udc, 1);
-	spin_unlock_irqrestore(&udc->lock, flags);
-
 	DBG("bound to %s\n", driver->driver.name);
 	return 0;
 }
 
-static int at91_stop(struct usb_gadget_driver *driver)
+static int at91_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct at91_udc *udc = &controller;
+	struct at91_udc *udc;
 	unsigned long	flags;
 
-	if (!driver || driver != udc->driver || !driver->unbind)
-		return -EINVAL;
-
+	udc = container_of(gadget, struct at91_udc, gadget);
 	spin_lock_irqsave(&udc->lock, flags);
 	udc->enabled = 0;
 	at91_udp_write(udc, AT91_UDP_IDR, ~0);
-	pullup(udc, 0);
 	spin_unlock_irqrestore(&udc->lock, flags);
 
-	driver->unbind(&udc->gadget);
 	udc->gadget.dev.driver = NULL;
 	dev_set_drvdata(&udc->gadget.dev, NULL);
 	udc->driver = NULL;
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 3c0315b..e647d1c 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -105,9 +105,6 @@
 	unsigned			is_in:1;
 	unsigned			is_iso:1;
 	unsigned			fifo_bank:1;
-
-	const struct usb_endpoint_descriptor
-					*desc;
 };
 
 /*
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 9f98508..e23bf79 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -599,13 +599,13 @@
 
 	spin_lock_irqsave(&ep->udc->lock, flags);
 
-	if (ep->desc) {
+	if (ep->ep.desc) {
 		spin_unlock_irqrestore(&ep->udc->lock, flags);
 		DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
 		return -EBUSY;
 	}
 
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	ep->ep.maxpacket = maxpacket;
 
 	usba_ep_writel(ep, CFG, ept_cfg);
@@ -647,7 +647,7 @@
 
 	spin_lock_irqsave(&udc->lock, flags);
 
-	if (!ep->desc) {
+	if (!ep->ep.desc) {
 		spin_unlock_irqrestore(&udc->lock, flags);
 		/* REVISIT because this driver disables endpoints in
 		 * reset_all_endpoints() before calling disconnect(),
@@ -658,7 +658,6 @@
 					ep->ep.name);
 		return -EINVAL;
 	}
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 
 	list_splice_init(&ep->queue, &req_list);
@@ -752,7 +751,7 @@
 	 */
 	ret = -ESHUTDOWN;
 	spin_lock_irqsave(&udc->lock, flags);
-	if (ep->desc) {
+	if (ep->ep.desc) {
 		if (list_empty(&ep->queue))
 			submit_request(ep, req);
 
@@ -776,7 +775,8 @@
 	DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
 			ep->ep.name, req, _req->length);
 
-	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN ||
+	    !ep->ep.desc)
 		return -ESHUTDOWN;
 
 	req->submitted = 0;
@@ -792,7 +792,7 @@
 	/* May have received a reset since last time we checked */
 	ret = -ESHUTDOWN;
 	spin_lock_irqsave(&udc->lock, flags);
-	if (ep->desc) {
+	if (ep->ep.desc) {
 		list_add_tail(&req->queue, &ep->queue);
 
 		if ((!ep_is_control(ep) && ep->is_in) ||
@@ -905,7 +905,7 @@
 	DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
 			value ? "set" : "clear");
 
-	if (!ep->desc) {
+	if (!ep->ep.desc) {
 		DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
 				ep->ep.name);
 		return -ENODEV;
@@ -1008,16 +1008,16 @@
 	return 0;
 }
 
-static int atmel_usba_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int atmel_usba_stop(struct usb_gadget_driver *driver);
-
+static int atmel_usba_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
+static int atmel_usba_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops usba_udc_ops = {
 	.get_frame		= usba_udc_get_frame,
 	.wakeup			= usba_udc_wakeup,
 	.set_selfpowered	= usba_udc_set_selfpowered,
-	.start			= atmel_usba_start,
-	.stop			= atmel_usba_stop,
+	.udc_start		= atmel_usba_start,
+	.udc_stop		= atmel_usba_stop,
 };
 
 static struct usb_endpoint_descriptor usba_ep0_desc = {
@@ -1071,7 +1071,7 @@
 	 * FIXME remove this code ... and retest thoroughly.
 	 */
 	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
-		if (ep->desc) {
+		if (ep->ep.desc) {
 			spin_unlock(&udc->lock);
 			usba_ep_disable(&ep->ep);
 			spin_lock(&udc->lock);
@@ -1089,9 +1089,9 @@
 	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
 		u8 bEndpointAddress;
 
-		if (!ep->desc)
+		if (!ep->ep.desc)
 			continue;
-		bEndpointAddress = ep->desc->bEndpointAddress;
+		bEndpointAddress = ep->ep.desc->bEndpointAddress;
 		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
 			continue;
 		if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
@@ -1727,7 +1727,7 @@
 		    usb_speed_string(udc->gadget.speed));
 
 		ep0 = &usba_ep[0];
-		ep0->desc = &usba_ep0_desc;
+		ep0->ep.desc = &usba_ep0_desc;
 		ep0->state = WAIT_FOR_SETUP;
 		usba_ep_writel(ep0, CFG,
 				(USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
@@ -1795,21 +1795,13 @@
 	return IRQ_HANDLED;
 }
 
-static int atmel_usba_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int atmel_usba_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct usba_udc *udc = &the_udc;
+	struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
 	unsigned long flags;
-	int ret;
-
-	if (!udc->pdev)
-		return -ENODEV;
 
 	spin_lock_irqsave(&udc->lock, flags);
-	if (udc->driver) {
-		spin_unlock_irqrestore(&udc->lock, flags);
-		return -EBUSY;
-	}
 
 	udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
 	udc->driver = driver;
@@ -1819,13 +1811,6 @@
 	clk_enable(udc->pclk);
 	clk_enable(udc->hclk);
 
-	ret = bind(&udc->gadget);
-	if (ret) {
-		DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
-			driver->driver.name, ret);
-		goto err_driver_bind;
-	}
-
 	DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
 
 	udc->vbus_prev = 0;
@@ -1842,23 +1827,14 @@
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 	return 0;
-
-err_driver_bind:
-	udc->driver = NULL;
-	udc->gadget.dev.driver = NULL;
-	return ret;
 }
 
-static int atmel_usba_stop(struct usb_gadget_driver *driver)
+static int atmel_usba_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct usba_udc *udc = &the_udc;
+	struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
 	unsigned long flags;
 
-	if (!udc->pdev)
-		return -ENODEV;
-	if (driver != udc->driver || !driver->unbind)
-		return -EINVAL;
-
 	if (gpio_is_valid(udc->vbus_pin))
 		disable_irq(gpio_to_irq(udc->vbus_pin));
 
@@ -1871,10 +1847,6 @@
 	toggle_bias(0);
 	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 
-	if (udc->driver->disconnect)
-		udc->driver->disconnect(&udc->gadget);
-
-	driver->unbind(&udc->gadget);
 	udc->gadget.dev.driver = NULL;
 	udc->driver = NULL;
 
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
index 88a2e07..9791259 100644
--- a/drivers/usb/gadget/atmel_usba_udc.h
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -280,7 +280,6 @@
 	struct usba_udc				*udc;
 
 	struct list_head			queue;
-	const struct usb_endpoint_descriptor	*desc;
 
 	u16					fifo_size;
 	u8					nr_banks;
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
deleted file mode 100644
index d07e44c..0000000
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/usb/msm_hsusb_hw.h>
-#include <linux/usb/ulpi.h>
-
-#include "ci13xxx_udc.c"
-
-#define MSM_USB_BASE	(udc->regs)
-
-static irqreturn_t msm_udc_irq(int irq, void *data)
-{
-	return udc_irq();
-}
-
-static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
-{
-	struct device *dev = udc->gadget.dev.parent;
-	int val;
-
-	switch (event) {
-	case CI13XXX_CONTROLLER_RESET_EVENT:
-		dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
-		writel(0, USB_AHBBURST);
-		writel(0, USB_AHBMODE);
-		break;
-	case CI13XXX_CONTROLLER_STOPPED_EVENT:
-		dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n");
-		/*
-		 * Put the transceiver in non-driving mode. Otherwise host
-		 * may not detect soft-disconnection.
-		 */
-		val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL);
-		val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
-		val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
-		usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
-		break;
-	default:
-		dev_dbg(dev, "unknown ci13xxx_udc event\n");
-		break;
-	}
-}
-
-static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
-	.name			= "ci13xxx_msm",
-	.flags			= CI13XXX_REGS_SHARED |
-				  CI13XXX_REQUIRE_TRANSCEIVER |
-				  CI13XXX_PULLUP_ON_VBUS |
-				  CI13XXX_DISABLE_STREAMING,
-
-	.notify_event		= ci13xxx_msm_notify_event,
-};
-
-static int ci13xxx_msm_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	void __iomem *regs;
-	int irq;
-	int ret;
-
-	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "failed to get platform resource mem\n");
-		return -ENXIO;
-	}
-
-	regs = ioremap(res->start, resource_size(res));
-	if (!regs) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		return -ENOMEM;
-	}
-
-	ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "udc_probe failed\n");
-		goto iounmap;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(&pdev->dev, "IRQ not found\n");
-		ret = -ENXIO;
-		goto udc_remove;
-	}
-
-	ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "request_irq failed\n");
-		goto udc_remove;
-	}
-
-	pm_runtime_no_callbacks(&pdev->dev);
-	pm_runtime_enable(&pdev->dev);
-
-	return 0;
-
-udc_remove:
-	udc_remove();
-iounmap:
-	iounmap(regs);
-
-	return ret;
-}
-
-static struct platform_driver ci13xxx_msm_driver = {
-	.probe = ci13xxx_msm_probe,
-	.driver = { .name = "msm_hsusb", },
-};
-MODULE_ALIAS("platform:msm_hsusb");
-
-static int __init ci13xxx_msm_init(void)
-{
-	return platform_driver_register(&ci13xxx_msm_driver);
-}
-module_init(ci13xxx_msm_init);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/ci13xxx_pci.c b/drivers/usb/gadget/ci13xxx_pci.c
deleted file mode 100644
index 883ab5e..0000000
--- a/drivers/usb/gadget/ci13xxx_pci.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * ci13xxx_pci.c - MIPS USB IP core family device controller
- *
- * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
- *
- * Author: David Lopo
- *
- * 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/pci.h>
-
-#include "ci13xxx_udc.c"
-
-/* driver name */
-#define UDC_DRIVER_NAME   "ci13xxx_pci"
-
-/******************************************************************************
- * PCI block
- *****************************************************************************/
-/**
- * ci13xxx_pci_irq: interrut handler
- * @irq:  irq number
- * @pdev: USB Device Controller interrupt source
- *
- * This function returns IRQ_HANDLED if the IRQ has been handled
- * This is an ISR don't trace, use attribute interface instead
- */
-static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev)
-{
-	if (irq == 0) {
-		dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!");
-		return IRQ_HANDLED;
-	}
-	return udc_irq();
-}
-
-static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
-	.name		= UDC_DRIVER_NAME,
-};
-
-/**
- * ci13xxx_pci_probe: PCI probe
- * @pdev: USB device controller being probed
- * @id:   PCI hotplug ID connecting controller to UDC framework
- *
- * This function returns an error code
- * Allocates basic PCI resources for this USB device controller, and then
- * invokes the udc_probe() method to start the UDC associated with it
- */
-static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
-				       const struct pci_device_id *id)
-{
-	void __iomem *regs = NULL;
-	int retval = 0;
-
-	if (id == NULL)
-		return -EINVAL;
-
-	retval = pci_enable_device(pdev);
-	if (retval)
-		goto done;
-
-	if (!pdev->irq) {
-		dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
-		retval = -ENODEV;
-		goto disable_device;
-	}
-
-	retval = pci_request_regions(pdev, UDC_DRIVER_NAME);
-	if (retval)
-		goto disable_device;
-
-	/* BAR 0 holds all the registers */
-	regs = pci_iomap(pdev, 0, 0);
-	if (!regs) {
-		dev_err(&pdev->dev, "Error mapping memory!");
-		retval = -EFAULT;
-		goto release_regions;
-	}
-	pci_set_drvdata(pdev, (__force void *)regs);
-
-	pci_set_master(pdev);
-	pci_try_set_mwi(pdev);
-
-	retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs);
-	if (retval)
-		goto iounmap;
-
-	/* our device does not have MSI capability */
-
-	retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED,
-			     UDC_DRIVER_NAME, pdev);
-	if (retval)
-		goto gadget_remove;
-
-	return 0;
-
- gadget_remove:
-	udc_remove();
- iounmap:
-	pci_iounmap(pdev, regs);
- release_regions:
-	pci_release_regions(pdev);
- disable_device:
-	pci_disable_device(pdev);
- done:
-	return retval;
-}
-
-/**
- * ci13xxx_pci_remove: PCI remove
- * @pdev: USB Device Controller being removed
- *
- * Reverses the effect of ci13xxx_pci_probe(),
- * first invoking the udc_remove() and then releases
- * all PCI resources allocated for this USB device controller
- */
-static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
-{
-	free_irq(pdev->irq, pdev);
-	udc_remove();
-	pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev));
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-}
-
-/**
- * PCI device table
- * PCI device structure
- *
- * Check "pci.h" for details
- */
-static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
-	{ PCI_DEVICE(0x153F, 0x1004) },
-	{ PCI_DEVICE(0x153F, 0x1006) },
-	{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
-};
-MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
-
-static struct pci_driver ci13xxx_pci_driver = {
-	.name         =	UDC_DRIVER_NAME,
-	.id_table     =	ci13xxx_pci_id_table,
-	.probe        =	ci13xxx_pci_probe,
-	.remove       =	__devexit_p(ci13xxx_pci_remove),
-};
-
-/**
- * ci13xxx_pci_init: module init
- *
- * Driver load
- */
-static int __init ci13xxx_pci_init(void)
-{
-	return pci_register_driver(&ci13xxx_pci_driver);
-}
-module_init(ci13xxx_pci_init);
-
-/**
- * ci13xxx_pci_exit: module exit
- *
- * Driver unload
- */
-static void __exit ci13xxx_pci_exit(void)
-{
-	pci_unregister_driver(&ci13xxx_pci_driver);
-}
-module_exit(ci13xxx_pci_exit);
-
-MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
-MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("June 2008");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
deleted file mode 100644
index 243ef1a..0000000
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ /dev/null
@@ -1,2996 +0,0 @@
-/*
- * ci13xxx_udc.c - MIPS USB IP core family device controller
- *
- * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
- *
- * Author: David Lopo
- *
- * 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.
- */
-
-/*
- * Description: MIPS USB IP core family device controller
- *              Currently it only supports IP part number CI13412
- *
- * This driver is composed of several blocks:
- * - HW:     hardware interface
- * - DBG:    debug facilities (optional)
- * - UTIL:   utilities
- * - ISR:    interrupts handling
- * - ENDPT:  endpoint operations (Gadget API)
- * - GADGET: gadget operations (Gadget API)
- * - BUS:    bus glue code, bus abstraction layer
- *
- * Compile Options
- * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
- * - STALL_IN:  non-empty bulk-in pipes cannot be halted
- *              if defined mass storage compliance succeeds but with warnings
- *              => case 4: Hi >  Dn
- *              => case 5: Hi >  Di
- *              => case 8: Hi <> Do
- *              if undefined usbtest 13 fails
- * - TRACE:     enable function tracing (depends on DEBUG)
- *
- * Main Features
- * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
- * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
- * - Normal & LPM support
- *
- * USBTEST Report
- * - OK: 0-12, 13 (STALL_IN defined) & 14
- * - Not Supported: 15 & 16 (ISO)
- *
- * TODO List
- * - OTG
- * - Isochronous & Interrupt Traffic
- * - Handle requests which spawns into several TDs
- * - GET_STATUS(device) - always reports 0
- * - Gadget API (majority of optional features)
- * - Suspend & Remote Wakeup
- */
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-
-#include "ci13xxx_udc.h"
-
-
-/******************************************************************************
- * DEFINE
- *****************************************************************************/
-
-#define DMA_ADDR_INVALID	(~(dma_addr_t)0)
-
-/* ctrl register bank access */
-static DEFINE_SPINLOCK(udc_lock);
-
-/* control endpoint description */
-static const struct usb_endpoint_descriptor
-ctrl_endpt_out_desc = {
-	.bLength         = USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType = USB_DT_ENDPOINT,
-
-	.bEndpointAddress = USB_DIR_OUT,
-	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
-	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
-};
-
-static const struct usb_endpoint_descriptor
-ctrl_endpt_in_desc = {
-	.bLength         = USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType = USB_DT_ENDPOINT,
-
-	.bEndpointAddress = USB_DIR_IN,
-	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
-	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
-};
-
-/* UDC descriptor */
-static struct ci13xxx *_udc;
-
-/* Interrupt statistics */
-#define ISR_MASK   0x1F
-static struct {
-	u32 test;
-	u32 ui;
-	u32 uei;
-	u32 pci;
-	u32 uri;
-	u32 sli;
-	u32 none;
-	struct {
-		u32 cnt;
-		u32 buf[ISR_MASK+1];
-		u32 idx;
-	} hndl;
-} isr_statistics;
-
-/**
- * ffs_nr: find first (least significant) bit set
- * @x: the word to search
- *
- * This function returns bit number (instead of position)
- */
-static int ffs_nr(u32 x)
-{
-	int n = ffs(x);
-
-	return n ? n-1 : 32;
-}
-
-/******************************************************************************
- * HW block
- *****************************************************************************/
-/* register bank descriptor */
-static struct {
-	unsigned      lpm;    /* is LPM? */
-	void __iomem *abs;    /* bus map offset */
-	void __iomem *cap;    /* bus map offset + CAP offset + CAP data */
-	size_t        size;   /* bank size */
-} hw_bank;
-
-/* MSM specific */
-#define ABS_AHBBURST        (0x0090UL)
-#define ABS_AHBMODE         (0x0098UL)
-/* UDC register map */
-#define ABS_CAPLENGTH       (0x100UL)
-#define ABS_HCCPARAMS       (0x108UL)
-#define ABS_DCCPARAMS       (0x124UL)
-#define ABS_TESTMODE        (hw_bank.lpm ? 0x0FCUL : 0x138UL)
-/* offset to CAPLENTGH (addr + data) */
-#define CAP_USBCMD          (0x000UL)
-#define CAP_USBSTS          (0x004UL)
-#define CAP_USBINTR         (0x008UL)
-#define CAP_DEVICEADDR      (0x014UL)
-#define CAP_ENDPTLISTADDR   (0x018UL)
-#define CAP_PORTSC          (0x044UL)
-#define CAP_DEVLC           (0x084UL)
-#define CAP_USBMODE         (hw_bank.lpm ? 0x0C8UL : 0x068UL)
-#define CAP_ENDPTSETUPSTAT  (hw_bank.lpm ? 0x0D8UL : 0x06CUL)
-#define CAP_ENDPTPRIME      (hw_bank.lpm ? 0x0DCUL : 0x070UL)
-#define CAP_ENDPTFLUSH      (hw_bank.lpm ? 0x0E0UL : 0x074UL)
-#define CAP_ENDPTSTAT       (hw_bank.lpm ? 0x0E4UL : 0x078UL)
-#define CAP_ENDPTCOMPLETE   (hw_bank.lpm ? 0x0E8UL : 0x07CUL)
-#define CAP_ENDPTCTRL       (hw_bank.lpm ? 0x0ECUL : 0x080UL)
-#define CAP_LAST            (hw_bank.lpm ? 0x12CUL : 0x0C0UL)
-
-/* maximum number of enpoints: valid only after hw_device_reset() */
-static unsigned hw_ep_max;
-
-/**
- * hw_ep_bit: calculates the bit number
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns bit number
- */
-static inline int hw_ep_bit(int num, int dir)
-{
-	return num + (dir ? 16 : 0);
-}
-
-static int ep_to_bit(int n)
-{
-	int fill = 16 - hw_ep_max / 2;
-
-	if (n >= hw_ep_max / 2)
-		n += fill;
-
-	return n;
-}
-
-/**
- * hw_aread: reads from register bitfield
- * @addr: address relative to bus map
- * @mask: bitfield mask
- *
- * This function returns register bitfield data
- */
-static u32 hw_aread(u32 addr, u32 mask)
-{
-	return ioread32(addr + hw_bank.abs) & mask;
-}
-
-/**
- * hw_awrite: writes to register bitfield
- * @addr: address relative to bus map
- * @mask: bitfield mask
- * @data: new data
- */
-static void hw_awrite(u32 addr, u32 mask, u32 data)
-{
-	iowrite32(hw_aread(addr, ~mask) | (data & mask),
-		  addr + hw_bank.abs);
-}
-
-/**
- * hw_cread: reads from register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- *
- * This function returns register bitfield data
- */
-static u32 hw_cread(u32 addr, u32 mask)
-{
-	return ioread32(addr + hw_bank.cap) & mask;
-}
-
-/**
- * hw_cwrite: writes to register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- * @data: new data
- */
-static void hw_cwrite(u32 addr, u32 mask, u32 data)
-{
-	iowrite32(hw_cread(addr, ~mask) | (data & mask),
-		  addr + hw_bank.cap);
-}
-
-/**
- * hw_ctest_and_clear: tests & clears register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- *
- * This function returns register bitfield data
- */
-static u32 hw_ctest_and_clear(u32 addr, u32 mask)
-{
-	u32 reg = hw_cread(addr, mask);
-
-	iowrite32(reg, addr + hw_bank.cap);
-	return reg;
-}
-
-/**
- * hw_ctest_and_write: tests & writes register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- * @data: new data
- *
- * This function returns register bitfield data
- */
-static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data)
-{
-	u32 reg = hw_cread(addr, ~0);
-
-	iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap);
-	return (reg & mask) >> ffs_nr(mask);
-}
-
-static int hw_device_init(void __iomem *base)
-{
-	u32 reg;
-
-	/* bank is a module variable */
-	hw_bank.abs = base;
-
-	hw_bank.cap = hw_bank.abs;
-	hw_bank.cap += ABS_CAPLENGTH;
-	hw_bank.cap += ioread8(hw_bank.cap);
-
-	reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN);
-	hw_bank.lpm  = reg;
-	hw_bank.size = hw_bank.cap - hw_bank.abs;
-	hw_bank.size += CAP_LAST;
-	hw_bank.size /= sizeof(u32);
-
-	reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
-	hw_ep_max = reg * 2;   /* cache hw ENDPT_MAX */
-
-	if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX)
-		return -ENODEV;
-
-	/* setup lock mode ? */
-
-	/* ENDPTSETUPSTAT is '0' by default */
-
-	/* HCSPARAMS.bf.ppc SHOULD BE zero for device */
-
-	return 0;
-}
-/**
- * hw_device_reset: resets chip (execute without interruption)
- * @base: register base address
- *
- * This function returns an error code
- */
-static int hw_device_reset(struct ci13xxx *udc)
-{
-	/* should flush & stop before reset */
-	hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
-	hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
-
-	hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
-	while (hw_cread(CAP_USBCMD, USBCMD_RST))
-		udelay(10);             /* not RTOS friendly */
-
-
-	if (udc->udc_driver->notify_event)
-		udc->udc_driver->notify_event(udc,
-			CI13XXX_CONTROLLER_RESET_EVENT);
-
-	if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
-		hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
-
-	/* USBMODE should be configured step by step */
-	hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
-	hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
-	hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);  /* HW >= 2.3 */
-
-	if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
-		pr_err("cannot enter in device mode");
-		pr_err("lpm = %i", hw_bank.lpm);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-/**
- * hw_device_state: enables/disables interrupts & starts/stops device (execute
- *                  without interruption)
- * @dma: 0 => disable, !0 => enable and set dma engine
- *
- * This function returns an error code
- */
-static int hw_device_state(u32 dma)
-{
-	if (dma) {
-		hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
-		/* interrupt, error, port change, reset, sleep/suspend */
-		hw_cwrite(CAP_USBINTR, ~0,
-			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
-		hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS);
-	} else {
-		hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
-		hw_cwrite(CAP_USBINTR, ~0, 0);
-	}
-	return 0;
-}
-
-/**
- * hw_ep_flush: flush endpoint fifo (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns an error code
- */
-static int hw_ep_flush(int num, int dir)
-{
-	int n = hw_ep_bit(num, dir);
-
-	do {
-		/* flush any pending transfer */
-		hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n));
-		while (hw_cread(CAP_ENDPTFLUSH, BIT(n)))
-			cpu_relax();
-	} while (hw_cread(CAP_ENDPTSTAT, BIT(n)));
-
-	return 0;
-}
-
-/**
- * hw_ep_disable: disables endpoint (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns an error code
- */
-static int hw_ep_disable(int num, int dir)
-{
-	hw_ep_flush(num, dir);
-	hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32),
-		  dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
-	return 0;
-}
-
-/**
- * hw_ep_enable: enables endpoint (execute without interruption)
- * @num:  endpoint number
- * @dir:  endpoint direction
- * @type: endpoint type
- *
- * This function returns an error code
- */
-static int hw_ep_enable(int num, int dir, int type)
-{
-	u32 mask, data;
-
-	if (dir) {
-		mask  = ENDPTCTRL_TXT;  /* type    */
-		data  = type << ffs_nr(mask);
-
-		mask |= ENDPTCTRL_TXS;  /* unstall */
-		mask |= ENDPTCTRL_TXR;  /* reset data toggle */
-		data |= ENDPTCTRL_TXR;
-		mask |= ENDPTCTRL_TXE;  /* enable  */
-		data |= ENDPTCTRL_TXE;
-	} else {
-		mask  = ENDPTCTRL_RXT;  /* type    */
-		data  = type << ffs_nr(mask);
-
-		mask |= ENDPTCTRL_RXS;  /* unstall */
-		mask |= ENDPTCTRL_RXR;  /* reset data toggle */
-		data |= ENDPTCTRL_RXR;
-		mask |= ENDPTCTRL_RXE;  /* enable  */
-		data |= ENDPTCTRL_RXE;
-	}
-	hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data);
-	return 0;
-}
-
-/**
- * hw_ep_get_halt: return endpoint halt status
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns 1 if endpoint halted
- */
-static int hw_ep_get_halt(int num, int dir)
-{
-	u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
-
-	return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0;
-}
-
-/**
- * hw_test_and_clear_setup_status: test & clear setup status (execute without
- *                                 interruption)
- * @n: endpoint number
- *
- * This function returns setup status
- */
-static int hw_test_and_clear_setup_status(int n)
-{
-	n = ep_to_bit(n);
-	return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n));
-}
-
-/**
- * hw_ep_prime: primes endpoint (execute without interruption)
- * @num:     endpoint number
- * @dir:     endpoint direction
- * @is_ctrl: true if control endpoint
- *
- * This function returns an error code
- */
-static int hw_ep_prime(int num, int dir, int is_ctrl)
-{
-	int n = hw_ep_bit(num, dir);
-
-	if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
-		return -EAGAIN;
-
-	hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
-
-	while (hw_cread(CAP_ENDPTPRIME, BIT(n)))
-		cpu_relax();
-	if (is_ctrl && dir == RX  && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
-		return -EAGAIN;
-
-	/* status shoult be tested according with manual but it doesn't work */
-	return 0;
-}
-
-/**
- * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
- *                 without interruption)
- * @num:   endpoint number
- * @dir:   endpoint direction
- * @value: true => stall, false => unstall
- *
- * This function returns an error code
- */
-static int hw_ep_set_halt(int num, int dir, int value)
-{
-	if (value != 0 && value != 1)
-		return -EINVAL;
-
-	do {
-		u32 addr = CAP_ENDPTCTRL + num * sizeof(u32);
-		u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
-		u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
-
-		/* data toggle - reserved for EP0 but it's in ESS */
-		hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr);
-
-	} while (value != hw_ep_get_halt(num, dir));
-
-	return 0;
-}
-
-/**
- * hw_intr_clear: disables interrupt & clears interrupt status (execute without
- *                interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_clear(int n)
-{
-	if (n >= REG_BITS)
-		return -EINVAL;
-
-	hw_cwrite(CAP_USBINTR, BIT(n), 0);
-	hw_cwrite(CAP_USBSTS,  BIT(n), BIT(n));
-	return 0;
-}
-
-/**
- * hw_intr_force: enables interrupt & forces interrupt status (execute without
- *                interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_force(int n)
-{
-	if (n >= REG_BITS)
-		return -EINVAL;
-
-	hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
-	hw_cwrite(CAP_USBINTR,  BIT(n), BIT(n));
-	hw_cwrite(CAP_USBSTS,   BIT(n), BIT(n));
-	hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0);
-	return 0;
-}
-
-/**
- * hw_is_port_high_speed: test if port is high speed
- *
- * This function returns true if high speed port
- */
-static int hw_port_is_high_speed(void)
-{
-	return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) :
-		hw_cread(CAP_PORTSC, PORTSC_HSP);
-}
-
-/**
- * hw_port_test_get: reads port test mode value
- *
- * This function returns port test mode value
- */
-static u8 hw_port_test_get(void)
-{
-	return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
-}
-
-/**
- * hw_port_test_set: writes port test mode (execute without interruption)
- * @mode: new value
- *
- * This function returns an error code
- */
-static int hw_port_test_set(u8 mode)
-{
-	const u8 TEST_MODE_MAX = 7;
-
-	if (mode > TEST_MODE_MAX)
-		return -EINVAL;
-
-	hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
-	return 0;
-}
-
-/**
- * hw_read_intr_enable: returns interrupt enable register
- *
- * This function returns register data
- */
-static u32 hw_read_intr_enable(void)
-{
-	return hw_cread(CAP_USBINTR, ~0);
-}
-
-/**
- * hw_read_intr_status: returns interrupt status register
- *
- * This function returns register data
- */
-static u32 hw_read_intr_status(void)
-{
-	return hw_cread(CAP_USBSTS, ~0);
-}
-
-/**
- * hw_register_read: reads all device registers (execute without interruption)
- * @buf:  destination buffer
- * @size: buffer size
- *
- * This function returns number of registers read
- */
-static size_t hw_register_read(u32 *buf, size_t size)
-{
-	unsigned i;
-
-	if (size > hw_bank.size)
-		size = hw_bank.size;
-
-	for (i = 0; i < size; i++)
-		buf[i] = hw_aread(i * sizeof(u32), ~0);
-
-	return size;
-}
-
-/**
- * hw_register_write: writes to register
- * @addr: register address
- * @data: register value
- *
- * This function returns an error code
- */
-static int hw_register_write(u16 addr, u32 data)
-{
-	/* align */
-	addr /= sizeof(u32);
-
-	if (addr >= hw_bank.size)
-		return -EINVAL;
-
-	/* align */
-	addr *= sizeof(u32);
-
-	hw_awrite(addr, ~0, data);
-	return 0;
-}
-
-/**
- * hw_test_and_clear_complete: test & clear complete status (execute without
- *                             interruption)
- * @n: endpoint number
- *
- * This function returns complete status
- */
-static int hw_test_and_clear_complete(int n)
-{
-	n = ep_to_bit(n);
-	return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n));
-}
-
-/**
- * hw_test_and_clear_intr_active: test & clear active interrupts (execute
- *                                without interruption)
- *
- * This function returns active interrutps
- */
-static u32 hw_test_and_clear_intr_active(void)
-{
-	u32 reg = hw_read_intr_status() & hw_read_intr_enable();
-
-	hw_cwrite(CAP_USBSTS, ~0, reg);
-	return reg;
-}
-
-/**
- * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
- *                                interruption)
- *
- * This function returns guard value
- */
-static int hw_test_and_clear_setup_guard(void)
-{
-	return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0);
-}
-
-/**
- * hw_test_and_set_setup_guard: test & set setup guard (execute without
- *                              interruption)
- *
- * This function returns guard value
- */
-static int hw_test_and_set_setup_guard(void)
-{
-	return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
-}
-
-/**
- * hw_usb_set_address: configures USB address (execute without interruption)
- * @value: new USB address
- *
- * This function returns an error code
- */
-static int hw_usb_set_address(u8 value)
-{
-	/* advance */
-	hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA,
-		  value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA);
-	return 0;
-}
-
-/**
- * hw_usb_reset: restart device after a bus reset (execute without
- *               interruption)
- *
- * This function returns an error code
- */
-static int hw_usb_reset(void)
-{
-	hw_usb_set_address(0);
-
-	/* ESS flushes only at end?!? */
-	hw_cwrite(CAP_ENDPTFLUSH,    ~0, ~0);   /* flush all EPs */
-
-	/* clear setup token semaphores */
-	hw_cwrite(CAP_ENDPTSETUPSTAT, 0,  0);   /* writes its content */
-
-	/* clear complete status */
-	hw_cwrite(CAP_ENDPTCOMPLETE,  0,  0);   /* writes its content */
-
-	/* wait until all bits cleared */
-	while (hw_cread(CAP_ENDPTPRIME, ~0))
-		udelay(10);             /* not RTOS friendly */
-
-	/* reset all endpoints ? */
-
-	/* reset internal status and wait for further instructions
-	   no need to verify the port reset status (ESS does it) */
-
-	return 0;
-}
-
-/******************************************************************************
- * DBG block
- *****************************************************************************/
-/**
- * show_device: prints information about device capabilities and status
- *
- * Check "device.h" for details
- */
-static ssize_t show_device(struct device *dev, struct device_attribute *attr,
-			   char *buf)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	struct usb_gadget *gadget = &udc->gadget;
-	int n = 0;
-
-	dbg_trace("[%s] %p\n", __func__, buf);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		return 0;
-	}
-
-	n += scnprintf(buf + n, PAGE_SIZE - n, "speed             = %d\n",
-		       gadget->speed);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed         = %d\n",
-		       gadget->max_speed);
-	/* TODO: Scheduled for removal in 3.8. */
-	n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed      = %d\n",
-		       gadget_is_dualspeed(gadget));
-	n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg            = %d\n",
-		       gadget->is_otg);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral   = %d\n",
-		       gadget->is_a_peripheral);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable      = %d\n",
-		       gadget->b_hnp_enable);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support     = %d\n",
-		       gadget->a_hnp_support);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
-		       gadget->a_alt_hnp_support);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "name              = %s\n",
-		       (gadget->name ? gadget->name : ""));
-
-	return n;
-}
-static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
-
-/**
- * show_driver: prints information about attached gadget (if any)
- *
- * Check "device.h" for details
- */
-static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
-			   char *buf)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	struct usb_gadget_driver *driver = udc->driver;
-	int n = 0;
-
-	dbg_trace("[%s] %p\n", __func__, buf);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		return 0;
-	}
-
-	if (driver == NULL)
-		return scnprintf(buf, PAGE_SIZE,
-				 "There is no gadget attached!\n");
-
-	n += scnprintf(buf + n, PAGE_SIZE - n, "function  = %s\n",
-		       (driver->function ? driver->function : ""));
-	n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
-		       driver->max_speed);
-
-	return n;
-}
-static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
-
-/* Maximum event message length */
-#define DBG_DATA_MSG   64UL
-
-/* Maximum event messages */
-#define DBG_DATA_MAX   128UL
-
-/* Event buffer descriptor */
-static struct {
-	char     (buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */
-	unsigned idx;   /* index */
-	unsigned tty;   /* print to console? */
-	rwlock_t lck;   /* lock */
-} dbg_data = {
-	.idx = 0,
-	.tty = 0,
-	.lck = __RW_LOCK_UNLOCKED(lck)
-};
-
-/**
- * dbg_dec: decrements debug event index
- * @idx: buffer index
- */
-static void dbg_dec(unsigned *idx)
-{
-	*idx = (*idx - 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_inc: increments debug event index
- * @idx: buffer index
- */
-static void dbg_inc(unsigned *idx)
-{
-	*idx = (*idx + 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_print:  prints the common part of the event
- * @addr:   endpoint address
- * @name:   event name
- * @status: status
- * @extra:  extra information
- */
-static void dbg_print(u8 addr, const char *name, int status, const char *extra)
-{
-	struct timeval tval;
-	unsigned int stamp;
-	unsigned long flags;
-
-	write_lock_irqsave(&dbg_data.lck, flags);
-
-	do_gettimeofday(&tval);
-	stamp = tval.tv_sec & 0xFFFF;	/* 2^32 = 4294967296. Limit to 4096s */
-	stamp = stamp * 1000000 + tval.tv_usec;
-
-	scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
-		  "%04X\t? %02X %-7.7s %4i ?\t%s\n",
-		  stamp, addr, name, status, extra);
-
-	dbg_inc(&dbg_data.idx);
-
-	write_unlock_irqrestore(&dbg_data.lck, flags);
-
-	if (dbg_data.tty != 0)
-		pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
-			  stamp, addr, name, status, extra);
-}
-
-/**
- * dbg_done: prints a DONE event
- * @addr:   endpoint address
- * @td:     transfer descriptor
- * @status: status
- */
-static void dbg_done(u8 addr, const u32 token, int status)
-{
-	char msg[DBG_DATA_MSG];
-
-	scnprintf(msg, sizeof(msg), "%d %02X",
-		  (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
-		  (int)(token & TD_STATUS)      >> ffs_nr(TD_STATUS));
-	dbg_print(addr, "DONE", status, msg);
-}
-
-/**
- * dbg_event: prints a generic event
- * @addr:   endpoint address
- * @name:   event name
- * @status: status
- */
-static void dbg_event(u8 addr, const char *name, int status)
-{
-	if (name != NULL)
-		dbg_print(addr, name, status, "");
-}
-
-/*
- * dbg_queue: prints a QUEUE event
- * @addr:   endpoint address
- * @req:    USB request
- * @status: status
- */
-static void dbg_queue(u8 addr, const struct usb_request *req, int status)
-{
-	char msg[DBG_DATA_MSG];
-
-	if (req != NULL) {
-		scnprintf(msg, sizeof(msg),
-			  "%d %d", !req->no_interrupt, req->length);
-		dbg_print(addr, "QUEUE", status, msg);
-	}
-}
-
-/**
- * dbg_setup: prints a SETUP event
- * @addr: endpoint address
- * @req:  setup request
- */
-static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
-{
-	char msg[DBG_DATA_MSG];
-
-	if (req != NULL) {
-		scnprintf(msg, sizeof(msg),
-			  "%02X %02X %04X %04X %d", req->bRequestType,
-			  req->bRequest, le16_to_cpu(req->wValue),
-			  le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
-		dbg_print(addr, "SETUP", 0, msg);
-	}
-}
-
-/**
- * show_events: displays the event buffer
- *
- * Check "device.h" for details
- */
-static ssize_t show_events(struct device *dev, struct device_attribute *attr,
-			   char *buf)
-{
-	unsigned long flags;
-	unsigned i, j, n = 0;
-
-	dbg_trace("[%s] %p\n", __func__, buf);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		return 0;
-	}
-
-	read_lock_irqsave(&dbg_data.lck, flags);
-
-	i = dbg_data.idx;
-	for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
-		n += strlen(dbg_data.buf[i]);
-		if (n >= PAGE_SIZE) {
-			n -= strlen(dbg_data.buf[i]);
-			break;
-		}
-	}
-	for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
-		j += scnprintf(buf + j, PAGE_SIZE - j,
-			       "%s", dbg_data.buf[i]);
-
-	read_unlock_irqrestore(&dbg_data.lck, flags);
-
-	return n;
-}
-
-/**
- * store_events: configure if events are going to be also printed to console
- *
- * Check "device.h" for details
- */
-static ssize_t store_events(struct device *dev, struct device_attribute *attr,
-			    const char *buf, size_t count)
-{
-	unsigned tty;
-
-	dbg_trace("[%s] %p, %d\n", __func__, buf, count);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		goto done;
-	}
-
-	if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
-		dev_err(dev, "<1|0>: enable|disable console log\n");
-		goto done;
-	}
-
-	dbg_data.tty = tty;
-	dev_info(dev, "tty = %u", dbg_data.tty);
-
- done:
-	return count;
-}
-static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
-
-/**
- * show_inters: interrupt status, enable status and historic
- *
- * Check "device.h" for details
- */
-static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
-			   char *buf)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	unsigned long flags;
-	u32 intr;
-	unsigned i, j, n = 0;
-
-	dbg_trace("[%s] %p\n", __func__, buf);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		return 0;
-	}
-
-	spin_lock_irqsave(udc->lock, flags);
-
-	n += scnprintf(buf + n, PAGE_SIZE - n,
-		       "status = %08x\n", hw_read_intr_status());
-	n += scnprintf(buf + n, PAGE_SIZE - n,
-		       "enable = %08x\n", hw_read_intr_enable());
-
-	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
-		       isr_statistics.test);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "? ui  = %d\n",
-		       isr_statistics.ui);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
-		       isr_statistics.uei);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
-		       isr_statistics.pci);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
-		       isr_statistics.uri);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
-		       isr_statistics.sli);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
-		       isr_statistics.none);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
-		       isr_statistics.hndl.cnt);
-
-	for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
-		i   &= ISR_MASK;
-		intr = isr_statistics.hndl.buf[i];
-
-		if (USBi_UI  & intr)
-			n += scnprintf(buf + n, PAGE_SIZE - n, "ui  ");
-		intr &= ~USBi_UI;
-		if (USBi_UEI & intr)
-			n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
-		intr &= ~USBi_UEI;
-		if (USBi_PCI & intr)
-			n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
-		intr &= ~USBi_PCI;
-		if (USBi_URI & intr)
-			n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
-		intr &= ~USBi_URI;
-		if (USBi_SLI & intr)
-			n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
-		intr &= ~USBi_SLI;
-		if (intr)
-			n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
-		if (isr_statistics.hndl.buf[i])
-			n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
-	}
-
-	spin_unlock_irqrestore(udc->lock, flags);
-
-	return n;
-}
-
-/**
- * store_inters: enable & force or disable an individual interrutps
- *                   (to be used for test purposes only)
- *
- * Check "device.h" for details
- */
-static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
-			    const char *buf, size_t count)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	unsigned long flags;
-	unsigned en, bit;
-
-	dbg_trace("[%s] %p, %d\n", __func__, buf, count);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		goto done;
-	}
-
-	if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
-		dev_err(dev, "<1|0> <bit>: enable|disable interrupt");
-		goto done;
-	}
-
-	spin_lock_irqsave(udc->lock, flags);
-	if (en) {
-		if (hw_intr_force(bit))
-			dev_err(dev, "invalid bit number\n");
-		else
-			isr_statistics.test++;
-	} else {
-		if (hw_intr_clear(bit))
-			dev_err(dev, "invalid bit number\n");
-	}
-	spin_unlock_irqrestore(udc->lock, flags);
-
- done:
-	return count;
-}
-static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
-
-/**
- * show_port_test: reads port test mode
- *
- * Check "device.h" for details
- */
-static ssize_t show_port_test(struct device *dev,
-			      struct device_attribute *attr, char *buf)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	unsigned long flags;
-	unsigned mode;
-
-	dbg_trace("[%s] %p\n", __func__, buf);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		return 0;
-	}
-
-	spin_lock_irqsave(udc->lock, flags);
-	mode = hw_port_test_get();
-	spin_unlock_irqrestore(udc->lock, flags);
-
-	return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
-}
-
-/**
- * store_port_test: writes port test mode
- *
- * Check "device.h" for details
- */
-static ssize_t store_port_test(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf, size_t count)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	unsigned long flags;
-	unsigned mode;
-
-	dbg_trace("[%s] %p, %d\n", __func__, buf, count);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		goto done;
-	}
-
-	if (sscanf(buf, "%u", &mode) != 1) {
-		dev_err(dev, "<mode>: set port test mode");
-		goto done;
-	}
-
-	spin_lock_irqsave(udc->lock, flags);
-	if (hw_port_test_set(mode))
-		dev_err(dev, "invalid mode\n");
-	spin_unlock_irqrestore(udc->lock, flags);
-
- done:
-	return count;
-}
-static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
-		   show_port_test, store_port_test);
-
-/**
- * show_qheads: DMA contents of all queue heads
- *
- * Check "device.h" for details
- */
-static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
-			   char *buf)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	unsigned long flags;
-	unsigned i, j, n = 0;
-
-	dbg_trace("[%s] %p\n", __func__, buf);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		return 0;
-	}
-
-	spin_lock_irqsave(udc->lock, flags);
-	for (i = 0; i < hw_ep_max/2; i++) {
-		struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
-		struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2];
-		n += scnprintf(buf + n, PAGE_SIZE - n,
-			       "EP=%02i: RX=%08X TX=%08X\n",
-			       i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
-		for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
-			n += scnprintf(buf + n, PAGE_SIZE - n,
-				       " %04X:    %08X    %08X\n", j,
-				       *((u32 *)mEpRx->qh.ptr + j),
-				       *((u32 *)mEpTx->qh.ptr + j));
-		}
-	}
-	spin_unlock_irqrestore(udc->lock, flags);
-
-	return n;
-}
-static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
-
-/**
- * show_registers: dumps all registers
- *
- * Check "device.h" for details
- */
-#define DUMP_ENTRIES	512
-static ssize_t show_registers(struct device *dev,
-			      struct device_attribute *attr, char *buf)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	unsigned long flags;
-	u32 *dump;
-	unsigned i, k, n = 0;
-
-	dbg_trace("[%s] %p\n", __func__, buf);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		return 0;
-	}
-
-	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
-	if (!dump) {
-		dev_err(dev, "%s: out of memory\n", __func__);
-		return 0;
-	}
-
-	spin_lock_irqsave(udc->lock, flags);
-	k = hw_register_read(dump, DUMP_ENTRIES);
-	spin_unlock_irqrestore(udc->lock, flags);
-
-	for (i = 0; i < k; i++) {
-		n += scnprintf(buf + n, PAGE_SIZE - n,
-			       "reg[0x%04X] = 0x%08X\n",
-			       i * (unsigned)sizeof(u32), dump[i]);
-	}
-	kfree(dump);
-
-	return n;
-}
-
-/**
- * store_registers: writes value to register address
- *
- * Check "device.h" for details
- */
-static ssize_t store_registers(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf, size_t count)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	unsigned long addr, data, flags;
-
-	dbg_trace("[%s] %p, %d\n", __func__, buf, count);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		goto done;
-	}
-
-	if (sscanf(buf, "%li %li", &addr, &data) != 2) {
-		dev_err(dev, "<addr> <data>: write data to register address");
-		goto done;
-	}
-
-	spin_lock_irqsave(udc->lock, flags);
-	if (hw_register_write(addr, data))
-		dev_err(dev, "invalid address range\n");
-	spin_unlock_irqrestore(udc->lock, flags);
-
- done:
-	return count;
-}
-static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
-		   show_registers, store_registers);
-
-/**
- * show_requests: DMA contents of all requests currently queued (all endpts)
- *
- * Check "device.h" for details
- */
-static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
-			     char *buf)
-{
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	unsigned long flags;
-	struct list_head   *ptr = NULL;
-	struct ci13xxx_req *req = NULL;
-	unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
-
-	dbg_trace("[%s] %p\n", __func__, buf);
-	if (attr == NULL || buf == NULL) {
-		dev_err(dev, "[%s] EINVAL\n", __func__);
-		return 0;
-	}
-
-	spin_lock_irqsave(udc->lock, flags);
-	for (i = 0; i < hw_ep_max; i++)
-		list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
-		{
-			req = list_entry(ptr, struct ci13xxx_req, queue);
-
-			n += scnprintf(buf + n, PAGE_SIZE - n,
-					"EP=%02i: TD=%08X %s\n",
-					i % hw_ep_max/2, (u32)req->dma,
-					((i < hw_ep_max/2) ? "RX" : "TX"));
-
-			for (j = 0; j < qSize; j++)
-				n += scnprintf(buf + n, PAGE_SIZE - n,
-						" %04X:    %08X\n", j,
-						*((u32 *)req->ptr + j));
-		}
-	spin_unlock_irqrestore(udc->lock, flags);
-
-	return n;
-}
-static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
-
-/**
- * dbg_create_files: initializes the attribute interface
- * @dev: device
- *
- * This function returns an error code
- */
-__maybe_unused static int dbg_create_files(struct device *dev)
-{
-	int retval = 0;
-
-	if (dev == NULL)
-		return -EINVAL;
-	retval = device_create_file(dev, &dev_attr_device);
-	if (retval)
-		goto done;
-	retval = device_create_file(dev, &dev_attr_driver);
-	if (retval)
-		goto rm_device;
-	retval = device_create_file(dev, &dev_attr_events);
-	if (retval)
-		goto rm_driver;
-	retval = device_create_file(dev, &dev_attr_inters);
-	if (retval)
-		goto rm_events;
-	retval = device_create_file(dev, &dev_attr_port_test);
-	if (retval)
-		goto rm_inters;
-	retval = device_create_file(dev, &dev_attr_qheads);
-	if (retval)
-		goto rm_port_test;
-	retval = device_create_file(dev, &dev_attr_registers);
-	if (retval)
-		goto rm_qheads;
-	retval = device_create_file(dev, &dev_attr_requests);
-	if (retval)
-		goto rm_registers;
-	return 0;
-
- rm_registers:
-	device_remove_file(dev, &dev_attr_registers);
- rm_qheads:
-	device_remove_file(dev, &dev_attr_qheads);
- rm_port_test:
-	device_remove_file(dev, &dev_attr_port_test);
- rm_inters:
-	device_remove_file(dev, &dev_attr_inters);
- rm_events:
-	device_remove_file(dev, &dev_attr_events);
- rm_driver:
-	device_remove_file(dev, &dev_attr_driver);
- rm_device:
-	device_remove_file(dev, &dev_attr_device);
- done:
-	return retval;
-}
-
-/**
- * dbg_remove_files: destroys the attribute interface
- * @dev: device
- *
- * This function returns an error code
- */
-__maybe_unused static int dbg_remove_files(struct device *dev)
-{
-	if (dev == NULL)
-		return -EINVAL;
-	device_remove_file(dev, &dev_attr_requests);
-	device_remove_file(dev, &dev_attr_registers);
-	device_remove_file(dev, &dev_attr_qheads);
-	device_remove_file(dev, &dev_attr_port_test);
-	device_remove_file(dev, &dev_attr_inters);
-	device_remove_file(dev, &dev_attr_events);
-	device_remove_file(dev, &dev_attr_driver);
-	device_remove_file(dev, &dev_attr_device);
-	return 0;
-}
-
-/******************************************************************************
- * UTIL block
- *****************************************************************************/
-/**
- * _usb_addr: calculates endpoint address from direction & number
- * @ep:  endpoint
- */
-static inline u8 _usb_addr(struct ci13xxx_ep *ep)
-{
-	return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
-}
-
-/**
- * _hardware_queue: configures a request at hardware level
- * @gadget: gadget
- * @mEp:    endpoint
- *
- * This function returns an error code
- */
-static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
-{
-	unsigned i;
-	int ret = 0;
-	unsigned length = mReq->req.length;
-
-	trace("%p, %p", mEp, mReq);
-
-	/* don't queue twice */
-	if (mReq->req.status == -EALREADY)
-		return -EALREADY;
-
-	mReq->req.status = -EALREADY;
-	if (length && mReq->req.dma == DMA_ADDR_INVALID) {
-		mReq->req.dma = \
-			dma_map_single(mEp->device, mReq->req.buf,
-				       length, mEp->dir ? DMA_TO_DEVICE :
-				       DMA_FROM_DEVICE);
-		if (mReq->req.dma == 0)
-			return -ENOMEM;
-
-		mReq->map = 1;
-	}
-
-	if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
-		mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
-					   &mReq->zdma);
-		if (mReq->zptr == NULL) {
-			if (mReq->map) {
-				dma_unmap_single(mEp->device, mReq->req.dma,
-					length, mEp->dir ? DMA_TO_DEVICE :
-					DMA_FROM_DEVICE);
-				mReq->req.dma = DMA_ADDR_INVALID;
-				mReq->map     = 0;
-			}
-			return -ENOMEM;
-		}
-		memset(mReq->zptr, 0, sizeof(*mReq->zptr));
-		mReq->zptr->next    = TD_TERMINATE;
-		mReq->zptr->token   = TD_STATUS_ACTIVE;
-		if (!mReq->req.no_interrupt)
-			mReq->zptr->token   |= TD_IOC;
-	}
-	/*
-	 * TD configuration
-	 * TODO - handle requests which spawns into several TDs
-	 */
-	memset(mReq->ptr, 0, sizeof(*mReq->ptr));
-	mReq->ptr->token    = length << ffs_nr(TD_TOTAL_BYTES);
-	mReq->ptr->token   &= TD_TOTAL_BYTES;
-	mReq->ptr->token   |= TD_STATUS_ACTIVE;
-	if (mReq->zptr) {
-		mReq->ptr->next    = mReq->zdma;
-	} else {
-		mReq->ptr->next    = TD_TERMINATE;
-		if (!mReq->req.no_interrupt)
-			mReq->ptr->token  |= TD_IOC;
-	}
-	mReq->ptr->page[0]  = mReq->req.dma;
-	for (i = 1; i < 5; i++)
-		mReq->ptr->page[i] =
-			(mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
-
-	if (!list_empty(&mEp->qh.queue)) {
-		struct ci13xxx_req *mReqPrev;
-		int n = hw_ep_bit(mEp->num, mEp->dir);
-		int tmp_stat;
-
-		mReqPrev = list_entry(mEp->qh.queue.prev,
-				struct ci13xxx_req, queue);
-		if (mReqPrev->zptr)
-			mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
-		else
-			mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
-		wmb();
-		if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
-			goto done;
-		do {
-			hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
-			tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
-		} while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW));
-		hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0);
-		if (tmp_stat)
-			goto done;
-	}
-
-	/*  QH configuration */
-	mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
-	mEp->qh.ptr->td.token &= ~TD_STATUS;   /* clear status */
-	mEp->qh.ptr->cap |=  QH_ZLT;
-
-	wmb();   /* synchronize before ep prime */
-
-	ret = hw_ep_prime(mEp->num, mEp->dir,
-			   mEp->type == USB_ENDPOINT_XFER_CONTROL);
-done:
-	return ret;
-}
-
-/**
- * _hardware_dequeue: handles a request at hardware level
- * @gadget: gadget
- * @mEp:    endpoint
- *
- * This function returns an error code
- */
-static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
-{
-	trace("%p, %p", mEp, mReq);
-
-	if (mReq->req.status != -EALREADY)
-		return -EINVAL;
-
-	if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
-		return -EBUSY;
-
-	if (mReq->zptr) {
-		if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
-			return -EBUSY;
-		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
-		mReq->zptr = NULL;
-	}
-
-	mReq->req.status = 0;
-
-	if (mReq->map) {
-		dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
-				 mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		mReq->req.dma = DMA_ADDR_INVALID;
-		mReq->map     = 0;
-	}
-
-	mReq->req.status = mReq->ptr->token & TD_STATUS;
-	if ((TD_STATUS_HALTED & mReq->req.status) != 0)
-		mReq->req.status = -1;
-	else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
-		mReq->req.status = -1;
-	else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
-		mReq->req.status = -1;
-
-	mReq->req.actual   = mReq->ptr->token & TD_TOTAL_BYTES;
-	mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
-	mReq->req.actual   = mReq->req.length - mReq->req.actual;
-	mReq->req.actual   = mReq->req.status ? 0 : mReq->req.actual;
-
-	return mReq->req.actual;
-}
-
-/**
- * _ep_nuke: dequeues all endpoint requests
- * @mEp: endpoint
- *
- * This function returns an error code
- * Caller must hold lock
- */
-static int _ep_nuke(struct ci13xxx_ep *mEp)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
-	trace("%p", mEp);
-
-	if (mEp == NULL)
-		return -EINVAL;
-
-	hw_ep_flush(mEp->num, mEp->dir);
-
-	while (!list_empty(&mEp->qh.queue)) {
-
-		/* pop oldest request */
-		struct ci13xxx_req *mReq = \
-			list_entry(mEp->qh.queue.next,
-				   struct ci13xxx_req, queue);
-		list_del_init(&mReq->queue);
-		mReq->req.status = -ESHUTDOWN;
-
-		if (mReq->req.complete != NULL) {
-			spin_unlock(mEp->lock);
-			mReq->req.complete(&mEp->ep, &mReq->req);
-			spin_lock(mEp->lock);
-		}
-	}
-	return 0;
-}
-
-/**
- * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
- * @gadget: gadget
- *
- * This function returns an error code
- */
-static int _gadget_stop_activity(struct usb_gadget *gadget)
-{
-	struct usb_ep *ep;
-	struct ci13xxx    *udc = container_of(gadget, struct ci13xxx, gadget);
-	unsigned long flags;
-
-	trace("%p", gadget);
-
-	if (gadget == NULL)
-		return -EINVAL;
-
-	spin_lock_irqsave(udc->lock, flags);
-	udc->gadget.speed = USB_SPEED_UNKNOWN;
-	udc->remote_wakeup = 0;
-	udc->suspended = 0;
-	spin_unlock_irqrestore(udc->lock, flags);
-
-	/* flush all endpoints */
-	gadget_for_each_ep(ep, gadget) {
-		usb_ep_fifo_flush(ep);
-	}
-	usb_ep_fifo_flush(&udc->ep0out.ep);
-	usb_ep_fifo_flush(&udc->ep0in.ep);
-
-	udc->driver->disconnect(gadget);
-
-	/* make sure to disable all endpoints */
-	gadget_for_each_ep(ep, gadget) {
-		usb_ep_disable(ep);
-	}
-
-	if (udc->status != NULL) {
-		usb_ep_free_request(&udc->ep0in.ep, udc->status);
-		udc->status = NULL;
-	}
-
-	return 0;
-}
-
-/******************************************************************************
- * ISR block
- *****************************************************************************/
-/**
- * isr_reset_handler: USB reset interrupt handler
- * @udc: UDC device
- *
- * This function resets USB engine after a bus reset occurred
- */
-static void isr_reset_handler(struct ci13xxx *udc)
-__releases(udc->lock)
-__acquires(udc->lock)
-{
-	int retval;
-
-	trace("%p", udc);
-
-	if (udc == NULL) {
-		err("EINVAL");
-		return;
-	}
-
-	dbg_event(0xFF, "BUS RST", 0);
-
-	spin_unlock(udc->lock);
-	retval = _gadget_stop_activity(&udc->gadget);
-	if (retval)
-		goto done;
-
-	retval = hw_usb_reset();
-	if (retval)
-		goto done;
-
-	udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
-	if (udc->status == NULL)
-		retval = -ENOMEM;
-
-	spin_lock(udc->lock);
-
- done:
-	if (retval)
-		err("error: %i", retval);
-}
-
-/**
- * isr_get_status_complete: get_status request complete function
- * @ep:  endpoint
- * @req: request handled
- *
- * Caller must release lock
- */
-static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
-	trace("%p, %p", ep, req);
-
-	if (ep == NULL || req == NULL) {
-		err("EINVAL");
-		return;
-	}
-
-	kfree(req->buf);
-	usb_ep_free_request(ep, req);
-}
-
-/**
- * isr_get_status_response: get_status request response
- * @udc: udc struct
- * @setup: setup request packet
- *
- * This function returns an error code
- */
-static int isr_get_status_response(struct ci13xxx *udc,
-				   struct usb_ctrlrequest *setup)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
-	struct ci13xxx_ep *mEp = &udc->ep0in;
-	struct usb_request *req = NULL;
-	gfp_t gfp_flags = GFP_ATOMIC;
-	int dir, num, retval;
-
-	trace("%p, %p", mEp, setup);
-
-	if (mEp == NULL || setup == NULL)
-		return -EINVAL;
-
-	spin_unlock(mEp->lock);
-	req = usb_ep_alloc_request(&mEp->ep, gfp_flags);
-	spin_lock(mEp->lock);
-	if (req == NULL)
-		return -ENOMEM;
-
-	req->complete = isr_get_status_complete;
-	req->length   = 2;
-	req->buf      = kzalloc(req->length, gfp_flags);
-	if (req->buf == NULL) {
-		retval = -ENOMEM;
-		goto err_free_req;
-	}
-
-	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
-		/* Assume that device is bus powered for now. */
-		*((u16 *)req->buf) = _udc->remote_wakeup << 1;
-		retval = 0;
-	} else if ((setup->bRequestType & USB_RECIP_MASK) \
-		   == USB_RECIP_ENDPOINT) {
-		dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
-			TX : RX;
-		num =  le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
-		*((u16 *)req->buf) = hw_ep_get_halt(num, dir);
-	}
-	/* else do nothing; reserved for future use */
-
-	spin_unlock(mEp->lock);
-	retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
-	spin_lock(mEp->lock);
-	if (retval)
-		goto err_free_buf;
-
-	return 0;
-
- err_free_buf:
-	kfree(req->buf);
- err_free_req:
-	spin_unlock(mEp->lock);
-	usb_ep_free_request(&mEp->ep, req);
-	spin_lock(mEp->lock);
-	return retval;
-}
-
-/**
- * isr_setup_status_complete: setup_status request complete function
- * @ep:  endpoint
- * @req: request handled
- *
- * Caller must release lock. Put the port in test mode if test mode
- * feature is selected.
- */
-static void
-isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
-	struct ci13xxx *udc = req->context;
-	unsigned long flags;
-
-	trace("%p, %p", ep, req);
-
-	spin_lock_irqsave(udc->lock, flags);
-	if (udc->test_mode)
-		hw_port_test_set(udc->test_mode);
-	spin_unlock_irqrestore(udc->lock, flags);
-}
-
-/**
- * isr_setup_status_phase: queues the status phase of a setup transation
- * @udc: udc struct
- *
- * This function returns an error code
- */
-static int isr_setup_status_phase(struct ci13xxx *udc)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
-	int retval;
-	struct ci13xxx_ep *mEp;
-
-	trace("%p", udc);
-
-	mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
-	udc->status->context = udc;
-	udc->status->complete = isr_setup_status_complete;
-
-	spin_unlock(mEp->lock);
-	retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
-	spin_lock(mEp->lock);
-
-	return retval;
-}
-
-/**
- * isr_tr_complete_low: transaction complete low level handler
- * @mEp: endpoint
- *
- * This function returns an error code
- * Caller must hold lock
- */
-static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
-	struct ci13xxx_req *mReq, *mReqTemp;
-	struct ci13xxx_ep *mEpTemp = mEp;
-	int uninitialized_var(retval);
-
-	trace("%p", mEp);
-
-	if (list_empty(&mEp->qh.queue))
-		return -EINVAL;
-
-	list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
-			queue) {
-		retval = _hardware_dequeue(mEp, mReq);
-		if (retval < 0)
-			break;
-		list_del_init(&mReq->queue);
-		dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
-		if (mReq->req.complete != NULL) {
-			spin_unlock(mEp->lock);
-			if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
-					mReq->req.length)
-				mEpTemp = &_udc->ep0in;
-			mReq->req.complete(&mEpTemp->ep, &mReq->req);
-			spin_lock(mEp->lock);
-		}
-	}
-
-	if (retval == -EBUSY)
-		retval = 0;
-	if (retval < 0)
-		dbg_event(_usb_addr(mEp), "DONE", retval);
-
-	return retval;
-}
-
-/**
- * isr_tr_complete_handler: transaction complete interrupt handler
- * @udc: UDC descriptor
- *
- * This function handles traffic events
- */
-static void isr_tr_complete_handler(struct ci13xxx *udc)
-__releases(udc->lock)
-__acquires(udc->lock)
-{
-	unsigned i;
-	u8 tmode = 0;
-
-	trace("%p", udc);
-
-	if (udc == NULL) {
-		err("EINVAL");
-		return;
-	}
-
-	for (i = 0; i < hw_ep_max; i++) {
-		struct ci13xxx_ep *mEp  = &udc->ci13xxx_ep[i];
-		int type, num, dir, err = -EINVAL;
-		struct usb_ctrlrequest req;
-
-		if (mEp->desc == NULL)
-			continue;   /* not configured */
-
-		if (hw_test_and_clear_complete(i)) {
-			err = isr_tr_complete_low(mEp);
-			if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
-				if (err > 0)   /* needs status phase */
-					err = isr_setup_status_phase(udc);
-				if (err < 0) {
-					dbg_event(_usb_addr(mEp),
-						  "ERROR", err);
-					spin_unlock(udc->lock);
-					if (usb_ep_set_halt(&mEp->ep))
-						err("error: ep_set_halt");
-					spin_lock(udc->lock);
-				}
-			}
-		}
-
-		if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
-		    !hw_test_and_clear_setup_status(i))
-			continue;
-
-		if (i != 0) {
-			warn("ctrl traffic received at endpoint");
-			continue;
-		}
-
-		/*
-		 * Flush data and handshake transactions of previous
-		 * setup packet.
-		 */
-		_ep_nuke(&udc->ep0out);
-		_ep_nuke(&udc->ep0in);
-
-		/* read_setup_packet */
-		do {
-			hw_test_and_set_setup_guard();
-			memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
-		} while (!hw_test_and_clear_setup_guard());
-
-		type = req.bRequestType;
-
-		udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
-
-		dbg_setup(_usb_addr(mEp), &req);
-
-		switch (req.bRequest) {
-		case USB_REQ_CLEAR_FEATURE:
-			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
-					le16_to_cpu(req.wValue) ==
-					USB_ENDPOINT_HALT) {
-				if (req.wLength != 0)
-					break;
-				num  = le16_to_cpu(req.wIndex);
-				dir = num & USB_ENDPOINT_DIR_MASK;
-				num &= USB_ENDPOINT_NUMBER_MASK;
-				if (dir) /* TX */
-					num += hw_ep_max/2;
-				if (!udc->ci13xxx_ep[num].wedge) {
-					spin_unlock(udc->lock);
-					err = usb_ep_clear_halt(
-						&udc->ci13xxx_ep[num].ep);
-					spin_lock(udc->lock);
-					if (err)
-						break;
-				}
-				err = isr_setup_status_phase(udc);
-			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
-					le16_to_cpu(req.wValue) ==
-					USB_DEVICE_REMOTE_WAKEUP) {
-				if (req.wLength != 0)
-					break;
-				udc->remote_wakeup = 0;
-				err = isr_setup_status_phase(udc);
-			} else {
-				goto delegate;
-			}
-			break;
-		case USB_REQ_GET_STATUS:
-			if (type != (USB_DIR_IN|USB_RECIP_DEVICE)   &&
-			    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
-			    type != (USB_DIR_IN|USB_RECIP_INTERFACE))
-				goto delegate;
-			if (le16_to_cpu(req.wLength) != 2 ||
-			    le16_to_cpu(req.wValue)  != 0)
-				break;
-			err = isr_get_status_response(udc, &req);
-			break;
-		case USB_REQ_SET_ADDRESS:
-			if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
-				goto delegate;
-			if (le16_to_cpu(req.wLength) != 0 ||
-			    le16_to_cpu(req.wIndex)  != 0)
-				break;
-			err = hw_usb_set_address((u8)le16_to_cpu(req.wValue));
-			if (err)
-				break;
-			err = isr_setup_status_phase(udc);
-			break;
-		case USB_REQ_SET_FEATURE:
-			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
-					le16_to_cpu(req.wValue) ==
-					USB_ENDPOINT_HALT) {
-				if (req.wLength != 0)
-					break;
-				num  = le16_to_cpu(req.wIndex);
-				dir = num & USB_ENDPOINT_DIR_MASK;
-				num &= USB_ENDPOINT_NUMBER_MASK;
-				if (dir) /* TX */
-					num += hw_ep_max/2;
-
-				spin_unlock(udc->lock);
-				err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
-				spin_lock(udc->lock);
-				if (!err)
-					isr_setup_status_phase(udc);
-			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
-				if (req.wLength != 0)
-					break;
-				switch (le16_to_cpu(req.wValue)) {
-				case USB_DEVICE_REMOTE_WAKEUP:
-					udc->remote_wakeup = 1;
-					err = isr_setup_status_phase(udc);
-					break;
-				case USB_DEVICE_TEST_MODE:
-					tmode = le16_to_cpu(req.wIndex) >> 8;
-					switch (tmode) {
-					case TEST_J:
-					case TEST_K:
-					case TEST_SE0_NAK:
-					case TEST_PACKET:
-					case TEST_FORCE_EN:
-						udc->test_mode = tmode;
-						err = isr_setup_status_phase(
-								udc);
-						break;
-					default:
-						break;
-					}
-				default:
-					goto delegate;
-				}
-			} else {
-				goto delegate;
-			}
-			break;
-		default:
-delegate:
-			if (req.wLength == 0)   /* no data phase */
-				udc->ep0_dir = TX;
-
-			spin_unlock(udc->lock);
-			err = udc->driver->setup(&udc->gadget, &req);
-			spin_lock(udc->lock);
-			break;
-		}
-
-		if (err < 0) {
-			dbg_event(_usb_addr(mEp), "ERROR", err);
-
-			spin_unlock(udc->lock);
-			if (usb_ep_set_halt(&mEp->ep))
-				err("error: ep_set_halt");
-			spin_lock(udc->lock);
-		}
-	}
-}
-
-/******************************************************************************
- * ENDPT block
- *****************************************************************************/
-/**
- * ep_enable: configure endpoint, making it usable
- *
- * Check usb_ep_enable() at "usb_gadget.h" for details
- */
-static int ep_enable(struct usb_ep *ep,
-		     const struct usb_endpoint_descriptor *desc)
-{
-	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
-	int retval = 0;
-	unsigned long flags;
-
-	trace("%p, %p", ep, desc);
-
-	if (ep == NULL || desc == NULL)
-		return -EINVAL;
-
-	spin_lock_irqsave(mEp->lock, flags);
-
-	/* only internal SW should enable ctrl endpts */
-
-	mEp->desc = desc;
-
-	if (!list_empty(&mEp->qh.queue))
-		warn("enabling a non-empty endpoint!");
-
-	mEp->dir  = usb_endpoint_dir_in(desc) ? TX : RX;
-	mEp->num  = usb_endpoint_num(desc);
-	mEp->type = usb_endpoint_type(desc);
-
-	mEp->ep.maxpacket = usb_endpoint_maxp(desc);
-
-	dbg_event(_usb_addr(mEp), "ENABLE", 0);
-
-	mEp->qh.ptr->cap = 0;
-
-	if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-		mEp->qh.ptr->cap |=  QH_IOS;
-	else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
-		mEp->qh.ptr->cap &= ~QH_MULT;
-	else
-		mEp->qh.ptr->cap &= ~QH_ZLT;
-
-	mEp->qh.ptr->cap |=
-		(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
-	mEp->qh.ptr->td.next |= TD_TERMINATE;   /* needed? */
-
-	/*
-	 * Enable endpoints in the HW other than ep0 as ep0
-	 * is always enabled
-	 */
-	if (mEp->num)
-		retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
-
-	spin_unlock_irqrestore(mEp->lock, flags);
-	return retval;
-}
-
-/**
- * ep_disable: endpoint is no longer usable
- *
- * Check usb_ep_disable() at "usb_gadget.h" for details
- */
-static int ep_disable(struct usb_ep *ep)
-{
-	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
-	int direction, retval = 0;
-	unsigned long flags;
-
-	trace("%p", ep);
-
-	if (ep == NULL)
-		return -EINVAL;
-	else if (mEp->desc == NULL)
-		return -EBUSY;
-
-	spin_lock_irqsave(mEp->lock, flags);
-
-	/* only internal SW should disable ctrl endpts */
-
-	direction = mEp->dir;
-	do {
-		dbg_event(_usb_addr(mEp), "DISABLE", 0);
-
-		retval |= _ep_nuke(mEp);
-		retval |= hw_ep_disable(mEp->num, mEp->dir);
-
-		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-			mEp->dir = (mEp->dir == TX) ? RX : TX;
-
-	} while (mEp->dir != direction);
-
-	mEp->desc = NULL;
-	mEp->ep.desc = NULL;
-
-	spin_unlock_irqrestore(mEp->lock, flags);
-	return retval;
-}
-
-/**
- * ep_alloc_request: allocate a request object to use with this endpoint
- *
- * Check usb_ep_alloc_request() at "usb_gadget.h" for details
- */
-static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
-{
-	struct ci13xxx_ep  *mEp  = container_of(ep, struct ci13xxx_ep, ep);
-	struct ci13xxx_req *mReq = NULL;
-
-	trace("%p, %i", ep, gfp_flags);
-
-	if (ep == NULL) {
-		err("EINVAL");
-		return NULL;
-	}
-
-	mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
-	if (mReq != NULL) {
-		INIT_LIST_HEAD(&mReq->queue);
-		mReq->req.dma = DMA_ADDR_INVALID;
-
-		mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
-					   &mReq->dma);
-		if (mReq->ptr == NULL) {
-			kfree(mReq);
-			mReq = NULL;
-		}
-	}
-
-	dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
-
-	return (mReq == NULL) ? NULL : &mReq->req;
-}
-
-/**
- * ep_free_request: frees a request object
- *
- * Check usb_ep_free_request() at "usb_gadget.h" for details
- */
-static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
-{
-	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
-	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
-	unsigned long flags;
-
-	trace("%p, %p", ep, req);
-
-	if (ep == NULL || req == NULL) {
-		err("EINVAL");
-		return;
-	} else if (!list_empty(&mReq->queue)) {
-		err("EBUSY");
-		return;
-	}
-
-	spin_lock_irqsave(mEp->lock, flags);
-
-	if (mReq->ptr)
-		dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
-	kfree(mReq);
-
-	dbg_event(_usb_addr(mEp), "FREE", 0);
-
-	spin_unlock_irqrestore(mEp->lock, flags);
-}
-
-/**
- * ep_queue: queues (submits) an I/O request to an endpoint
- *
- * Check usb_ep_queue()* at usb_gadget.h" for details
- */
-static int ep_queue(struct usb_ep *ep, struct usb_request *req,
-		    gfp_t __maybe_unused gfp_flags)
-{
-	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
-	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
-	int retval = 0;
-	unsigned long flags;
-
-	trace("%p, %p, %X", ep, req, gfp_flags);
-
-	if (ep == NULL || req == NULL || mEp->desc == NULL)
-		return -EINVAL;
-
-	spin_lock_irqsave(mEp->lock, flags);
-
-	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
-		if (req->length)
-			mEp = (_udc->ep0_dir == RX) ?
-				&_udc->ep0out : &_udc->ep0in;
-		if (!list_empty(&mEp->qh.queue)) {
-			_ep_nuke(mEp);
-			retval = -EOVERFLOW;
-			warn("endpoint ctrl %X nuked", _usb_addr(mEp));
-		}
-	}
-
-	/* first nuke then test link, e.g. previous status has not sent */
-	if (!list_empty(&mReq->queue)) {
-		retval = -EBUSY;
-		err("request already in queue");
-		goto done;
-	}
-
-	if (req->length > (4 * CI13XXX_PAGE_SIZE)) {
-		req->length = (4 * CI13XXX_PAGE_SIZE);
-		retval = -EMSGSIZE;
-		warn("request length truncated");
-	}
-
-	dbg_queue(_usb_addr(mEp), req, retval);
-
-	/* push request */
-	mReq->req.status = -EINPROGRESS;
-	mReq->req.actual = 0;
-
-	retval = _hardware_enqueue(mEp, mReq);
-
-	if (retval == -EALREADY) {
-		dbg_event(_usb_addr(mEp), "QUEUE", retval);
-		retval = 0;
-	}
-	if (!retval)
-		list_add_tail(&mReq->queue, &mEp->qh.queue);
-
- done:
-	spin_unlock_irqrestore(mEp->lock, flags);
-	return retval;
-}
-
-/**
- * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
- *
- * Check usb_ep_dequeue() at "usb_gadget.h" for details
- */
-static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
-{
-	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
-	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
-	unsigned long flags;
-
-	trace("%p, %p", ep, req);
-
-	if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
-		mEp->desc == NULL || list_empty(&mReq->queue) ||
-		list_empty(&mEp->qh.queue))
-		return -EINVAL;
-
-	spin_lock_irqsave(mEp->lock, flags);
-
-	dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
-
-	hw_ep_flush(mEp->num, mEp->dir);
-
-	/* pop request */
-	list_del_init(&mReq->queue);
-	if (mReq->map) {
-		dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
-				 mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		mReq->req.dma = DMA_ADDR_INVALID;
-		mReq->map     = 0;
-	}
-	req->status = -ECONNRESET;
-
-	if (mReq->req.complete != NULL) {
-		spin_unlock(mEp->lock);
-		mReq->req.complete(&mEp->ep, &mReq->req);
-		spin_lock(mEp->lock);
-	}
-
-	spin_unlock_irqrestore(mEp->lock, flags);
-	return 0;
-}
-
-/**
- * ep_set_halt: sets the endpoint halt feature
- *
- * Check usb_ep_set_halt() at "usb_gadget.h" for details
- */
-static int ep_set_halt(struct usb_ep *ep, int value)
-{
-	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
-	int direction, retval = 0;
-	unsigned long flags;
-
-	trace("%p, %i", ep, value);
-
-	if (ep == NULL || mEp->desc == NULL)
-		return -EINVAL;
-
-	spin_lock_irqsave(mEp->lock, flags);
-
-#ifndef STALL_IN
-	/* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
-	if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
-	    !list_empty(&mEp->qh.queue)) {
-		spin_unlock_irqrestore(mEp->lock, flags);
-		return -EAGAIN;
-	}
-#endif
-
-	direction = mEp->dir;
-	do {
-		dbg_event(_usb_addr(mEp), "HALT", value);
-		retval |= hw_ep_set_halt(mEp->num, mEp->dir, value);
-
-		if (!value)
-			mEp->wedge = 0;
-
-		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-			mEp->dir = (mEp->dir == TX) ? RX : TX;
-
-	} while (mEp->dir != direction);
-
-	spin_unlock_irqrestore(mEp->lock, flags);
-	return retval;
-}
-
-/**
- * ep_set_wedge: sets the halt feature and ignores clear requests
- *
- * Check usb_ep_set_wedge() at "usb_gadget.h" for details
- */
-static int ep_set_wedge(struct usb_ep *ep)
-{
-	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
-	unsigned long flags;
-
-	trace("%p", ep);
-
-	if (ep == NULL || mEp->desc == NULL)
-		return -EINVAL;
-
-	spin_lock_irqsave(mEp->lock, flags);
-
-	dbg_event(_usb_addr(mEp), "WEDGE", 0);
-	mEp->wedge = 1;
-
-	spin_unlock_irqrestore(mEp->lock, flags);
-
-	return usb_ep_set_halt(ep);
-}
-
-/**
- * ep_fifo_flush: flushes contents of a fifo
- *
- * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
- */
-static void ep_fifo_flush(struct usb_ep *ep)
-{
-	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
-	unsigned long flags;
-
-	trace("%p", ep);
-
-	if (ep == NULL) {
-		err("%02X: -EINVAL", _usb_addr(mEp));
-		return;
-	}
-
-	spin_lock_irqsave(mEp->lock, flags);
-
-	dbg_event(_usb_addr(mEp), "FFLUSH", 0);
-	hw_ep_flush(mEp->num, mEp->dir);
-
-	spin_unlock_irqrestore(mEp->lock, flags);
-}
-
-/**
- * Endpoint-specific part of the API to the USB controller hardware
- * Check "usb_gadget.h" for details
- */
-static const struct usb_ep_ops usb_ep_ops = {
-	.enable	       = ep_enable,
-	.disable       = ep_disable,
-	.alloc_request = ep_alloc_request,
-	.free_request  = ep_free_request,
-	.queue	       = ep_queue,
-	.dequeue       = ep_dequeue,
-	.set_halt      = ep_set_halt,
-	.set_wedge     = ep_set_wedge,
-	.fifo_flush    = ep_fifo_flush,
-};
-
-/******************************************************************************
- * GADGET block
- *****************************************************************************/
-static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
-{
-	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
-	unsigned long flags;
-	int gadget_ready = 0;
-
-	if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
-		return -EOPNOTSUPP;
-
-	spin_lock_irqsave(udc->lock, flags);
-	udc->vbus_active = is_active;
-	if (udc->driver)
-		gadget_ready = 1;
-	spin_unlock_irqrestore(udc->lock, flags);
-
-	if (gadget_ready) {
-		if (is_active) {
-			pm_runtime_get_sync(&_gadget->dev);
-			hw_device_reset(udc);
-			hw_device_state(udc->ep0out.qh.dma);
-		} else {
-			hw_device_state(0);
-			if (udc->udc_driver->notify_event)
-				udc->udc_driver->notify_event(udc,
-				CI13XXX_CONTROLLER_STOPPED_EVENT);
-			_gadget_stop_activity(&udc->gadget);
-			pm_runtime_put_sync(&_gadget->dev);
-		}
-	}
-
-	return 0;
-}
-
-static int ci13xxx_wakeup(struct usb_gadget *_gadget)
-{
-	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
-	unsigned long flags;
-	int ret = 0;
-
-	trace();
-
-	spin_lock_irqsave(udc->lock, flags);
-	if (!udc->remote_wakeup) {
-		ret = -EOPNOTSUPP;
-		trace("remote wakeup feature is not enabled\n");
-		goto out;
-	}
-	if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
-		ret = -EINVAL;
-		trace("port is not suspended\n");
-		goto out;
-	}
-	hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
-out:
-	spin_unlock_irqrestore(udc->lock, flags);
-	return ret;
-}
-
-static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
-{
-	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
-
-	if (udc->transceiver)
-		return usb_phy_set_power(udc->transceiver, mA);
-	return -ENOTSUPP;
-}
-
-static int ci13xxx_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int ci13xxx_stop(struct usb_gadget_driver *driver);
-/**
- * Device operations part of the API to the USB controller hardware,
- * which don't involve endpoints (or i/o)
- * Check  "usb_gadget.h" for details
- */
-static const struct usb_gadget_ops usb_gadget_ops = {
-	.vbus_session	= ci13xxx_vbus_session,
-	.wakeup		= ci13xxx_wakeup,
-	.vbus_draw	= ci13xxx_vbus_draw,
-	.start		= ci13xxx_start,
-	.stop		= ci13xxx_stop,
-};
-
-/**
- * ci13xxx_start: register a gadget driver
- * @driver: the driver being registered
- * @bind: the driver's bind callback
- *
- * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
- * Interrupts are enabled here.
- */
-static int ci13xxx_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
-{
-	struct ci13xxx *udc = _udc;
-	unsigned long flags;
-	int i, j;
-	int retval = -ENOMEM;
-
-	trace("%p", driver);
-
-	if (driver             == NULL ||
-	    bind               == NULL ||
-	    driver->setup      == NULL ||
-	    driver->disconnect == NULL)
-		return -EINVAL;
-	else if (udc         == NULL)
-		return -ENODEV;
-	else if (udc->driver != NULL)
-		return -EBUSY;
-
-	/* alloc resources */
-	udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev,
-				       sizeof(struct ci13xxx_qh),
-				       64, CI13XXX_PAGE_SIZE);
-	if (udc->qh_pool == NULL)
-		return -ENOMEM;
-
-	udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev,
-				       sizeof(struct ci13xxx_td),
-				       64, CI13XXX_PAGE_SIZE);
-	if (udc->td_pool == NULL) {
-		dma_pool_destroy(udc->qh_pool);
-		udc->qh_pool = NULL;
-		return -ENOMEM;
-	}
-
-	spin_lock_irqsave(udc->lock, flags);
-
-	info("hw_ep_max = %d", hw_ep_max);
-
-	udc->gadget.dev.driver = NULL;
-
-	retval = 0;
-	for (i = 0; i < hw_ep_max/2; i++) {
-		for (j = RX; j <= TX; j++) {
-			int k = i + j * hw_ep_max/2;
-			struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
-
-			scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
-					(j == TX)  ? "in" : "out");
-
-			mEp->lock         = udc->lock;
-			mEp->device       = &udc->gadget.dev;
-			mEp->td_pool      = udc->td_pool;
-
-			mEp->ep.name      = mEp->name;
-			mEp->ep.ops       = &usb_ep_ops;
-			mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
-
-			INIT_LIST_HEAD(&mEp->qh.queue);
-			spin_unlock_irqrestore(udc->lock, flags);
-			mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
-					&mEp->qh.dma);
-			spin_lock_irqsave(udc->lock, flags);
-			if (mEp->qh.ptr == NULL)
-				retval = -ENOMEM;
-			else
-				memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
-
-			/* skip ep0 out and in endpoints */
-			if (i == 0)
-				continue;
-
-			list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
-		}
-	}
-	if (retval)
-		goto done;
-	spin_unlock_irqrestore(udc->lock, flags);
-	udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
-	retval = usb_ep_enable(&udc->ep0out.ep);
-	if (retval)
-		return retval;
-
-	udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
-	retval = usb_ep_enable(&udc->ep0in.ep);
-	if (retval)
-		return retval;
-	spin_lock_irqsave(udc->lock, flags);
-
-	udc->gadget.ep0 = &udc->ep0in.ep;
-	/* bind gadget */
-	driver->driver.bus     = NULL;
-	udc->gadget.dev.driver = &driver->driver;
-
-	spin_unlock_irqrestore(udc->lock, flags);
-	retval = bind(&udc->gadget);                /* MAY SLEEP */
-	spin_lock_irqsave(udc->lock, flags);
-
-	if (retval) {
-		udc->gadget.dev.driver = NULL;
-		goto done;
-	}
-
-	udc->driver = driver;
-	pm_runtime_get_sync(&udc->gadget.dev);
-	if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
-		if (udc->vbus_active) {
-			if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
-				hw_device_reset(udc);
-		} else {
-			pm_runtime_put_sync(&udc->gadget.dev);
-			goto done;
-		}
-	}
-
-	retval = hw_device_state(udc->ep0out.qh.dma);
-	if (retval)
-		pm_runtime_put_sync(&udc->gadget.dev);
-
- done:
-	spin_unlock_irqrestore(udc->lock, flags);
-	return retval;
-}
-
-/**
- * ci13xxx_stop: unregister a gadget driver
- *
- * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
- */
-static int ci13xxx_stop(struct usb_gadget_driver *driver)
-{
-	struct ci13xxx *udc = _udc;
-	unsigned long i, flags;
-
-	trace("%p", driver);
-
-	if (driver             == NULL ||
-	    driver->unbind     == NULL ||
-	    driver->setup      == NULL ||
-	    driver->disconnect == NULL ||
-	    driver             != udc->driver)
-		return -EINVAL;
-
-	spin_lock_irqsave(udc->lock, flags);
-
-	if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
-			udc->vbus_active) {
-		hw_device_state(0);
-		if (udc->udc_driver->notify_event)
-			udc->udc_driver->notify_event(udc,
-			CI13XXX_CONTROLLER_STOPPED_EVENT);
-		spin_unlock_irqrestore(udc->lock, flags);
-		_gadget_stop_activity(&udc->gadget);
-		spin_lock_irqsave(udc->lock, flags);
-		pm_runtime_put(&udc->gadget.dev);
-	}
-
-	/* unbind gadget */
-	spin_unlock_irqrestore(udc->lock, flags);
-	driver->unbind(&udc->gadget);               /* MAY SLEEP */
-	spin_lock_irqsave(udc->lock, flags);
-
-	udc->gadget.dev.driver = NULL;
-
-	/* free resources */
-	for (i = 0; i < hw_ep_max; i++) {
-		struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
-
-		if (!list_empty(&mEp->ep.ep_list))
-			list_del_init(&mEp->ep.ep_list);
-
-		if (mEp->qh.ptr != NULL)
-			dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
-	}
-
-	udc->gadget.ep0 = NULL;
-	udc->driver = NULL;
-
-	spin_unlock_irqrestore(udc->lock, flags);
-
-	if (udc->td_pool != NULL) {
-		dma_pool_destroy(udc->td_pool);
-		udc->td_pool = NULL;
-	}
-	if (udc->qh_pool != NULL) {
-		dma_pool_destroy(udc->qh_pool);
-		udc->qh_pool = NULL;
-	}
-
-	return 0;
-}
-
-/******************************************************************************
- * BUS block
- *****************************************************************************/
-/**
- * udc_irq: global interrupt handler
- *
- * This function returns IRQ_HANDLED if the IRQ has been handled
- * It locks access to registers
- */
-static irqreturn_t udc_irq(void)
-{
-	struct ci13xxx *udc = _udc;
-	irqreturn_t retval;
-	u32 intr;
-
-	trace();
-
-	if (udc == NULL) {
-		err("ENODEV");
-		return IRQ_HANDLED;
-	}
-
-	spin_lock(udc->lock);
-
-	if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
-		if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
-				USBMODE_CM_DEVICE) {
-			spin_unlock(udc->lock);
-			return IRQ_NONE;
-		}
-	}
-	intr = hw_test_and_clear_intr_active();
-	if (intr) {
-		isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
-		isr_statistics.hndl.idx &= ISR_MASK;
-		isr_statistics.hndl.cnt++;
-
-		/* order defines priority - do NOT change it */
-		if (USBi_URI & intr) {
-			isr_statistics.uri++;
-			isr_reset_handler(udc);
-		}
-		if (USBi_PCI & intr) {
-			isr_statistics.pci++;
-			udc->gadget.speed = hw_port_is_high_speed() ?
-				USB_SPEED_HIGH : USB_SPEED_FULL;
-			if (udc->suspended && udc->driver->resume) {
-				spin_unlock(udc->lock);
-				udc->driver->resume(&udc->gadget);
-				spin_lock(udc->lock);
-				udc->suspended = 0;
-			}
-		}
-		if (USBi_UEI & intr)
-			isr_statistics.uei++;
-		if (USBi_UI  & intr) {
-			isr_statistics.ui++;
-			isr_tr_complete_handler(udc);
-		}
-		if (USBi_SLI & intr) {
-			if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
-			    udc->driver->suspend) {
-				udc->suspended = 1;
-				spin_unlock(udc->lock);
-				udc->driver->suspend(&udc->gadget);
-				spin_lock(udc->lock);
-			}
-			isr_statistics.sli++;
-		}
-		retval = IRQ_HANDLED;
-	} else {
-		isr_statistics.none++;
-		retval = IRQ_NONE;
-	}
-	spin_unlock(udc->lock);
-
-	return retval;
-}
-
-/**
- * udc_release: driver release function
- * @dev: device
- *
- * Currently does nothing
- */
-static void udc_release(struct device *dev)
-{
-	trace("%p", dev);
-
-	if (dev == NULL)
-		err("EINVAL");
-}
-
-/**
- * udc_probe: parent probe must call this to initialize UDC
- * @dev:  parent device
- * @regs: registers base address
- * @name: driver name
- *
- * This function returns an error code
- * No interrupts active, the IRQ has not been requested yet
- * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask
- */
-static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
-		void __iomem *regs)
-{
-	struct ci13xxx *udc;
-	int retval = 0;
-
-	trace("%p, %p, %p", dev, regs, driver->name);
-
-	if (dev == NULL || regs == NULL || driver == NULL ||
-			driver->name == NULL)
-		return -EINVAL;
-
-	udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL);
-	if (udc == NULL)
-		return -ENOMEM;
-
-	udc->lock = &udc_lock;
-	udc->regs = regs;
-	udc->udc_driver = driver;
-
-	udc->gadget.ops          = &usb_gadget_ops;
-	udc->gadget.speed        = USB_SPEED_UNKNOWN;
-	udc->gadget.max_speed    = USB_SPEED_HIGH;
-	udc->gadget.is_otg       = 0;
-	udc->gadget.name         = driver->name;
-
-	INIT_LIST_HEAD(&udc->gadget.ep_list);
-	udc->gadget.ep0 = NULL;
-
-	dev_set_name(&udc->gadget.dev, "gadget");
-	udc->gadget.dev.dma_mask = dev->dma_mask;
-	udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
-	udc->gadget.dev.parent   = dev;
-	udc->gadget.dev.release  = udc_release;
-
-	retval = hw_device_init(regs);
-	if (retval < 0)
-		goto free_udc;
-
-	udc->transceiver = usb_get_transceiver();
-
-	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
-		if (udc->transceiver == NULL) {
-			retval = -ENODEV;
-			goto free_udc;
-		}
-	}
-
-	if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
-		retval = hw_device_reset(udc);
-		if (retval)
-			goto put_transceiver;
-	}
-
-	retval = device_register(&udc->gadget.dev);
-	if (retval) {
-		put_device(&udc->gadget.dev);
-		goto put_transceiver;
-	}
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-	retval = dbg_create_files(&udc->gadget.dev);
-#endif
-	if (retval)
-		goto unreg_device;
-
-	if (udc->transceiver) {
-		retval = otg_set_peripheral(udc->transceiver->otg,
-						&udc->gadget);
-		if (retval)
-			goto remove_dbg;
-	}
-
-	retval = usb_add_gadget_udc(dev, &udc->gadget);
-	if (retval)
-		goto remove_trans;
-
-	pm_runtime_no_callbacks(&udc->gadget.dev);
-	pm_runtime_enable(&udc->gadget.dev);
-
-	_udc = udc;
-	return retval;
-
-remove_trans:
-	if (udc->transceiver) {
-		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
-		usb_put_transceiver(udc->transceiver);
-	}
-
-	err("error = %i", retval);
-remove_dbg:
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-	dbg_remove_files(&udc->gadget.dev);
-#endif
-unreg_device:
-	device_unregister(&udc->gadget.dev);
-put_transceiver:
-	if (udc->transceiver)
-		usb_put_transceiver(udc->transceiver);
-free_udc:
-	kfree(udc);
-	_udc = NULL;
-	return retval;
-}
-
-/**
- * udc_remove: parent remove must call this to remove UDC
- *
- * No interrupts active, the IRQ has been released
- */
-static void udc_remove(void)
-{
-	struct ci13xxx *udc = _udc;
-
-	if (udc == NULL) {
-		err("EINVAL");
-		return;
-	}
-	usb_del_gadget_udc(&udc->gadget);
-
-	if (udc->transceiver) {
-		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
-		usb_put_transceiver(udc->transceiver);
-	}
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-	dbg_remove_files(&udc->gadget.dev);
-#endif
-	device_unregister(&udc->gadget.dev);
-
-	kfree(udc);
-	_udc = NULL;
-}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
deleted file mode 100644
index 0d31af5..0000000
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core
- *
- * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
- *
- * Author: David Lopo
- *
- * 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.
- *
- * Description: MIPS USB IP core family device controller
- *              Structures, registers and logging macros
- */
-
-#ifndef _CI13XXX_h_
-#define _CI13XXX_h_
-
-/******************************************************************************
- * DEFINE
- *****************************************************************************/
-#define CI13XXX_PAGE_SIZE  4096ul /* page size for TD's */
-#define ENDPT_MAX          (32)
-#define CTRL_PAYLOAD_MAX   (64)
-#define RX        (0)  /* similar to USB_DIR_OUT but can be used as an index */
-#define TX        (1)  /* similar to USB_DIR_IN  but can be used as an index */
-
-/******************************************************************************
- * STRUCTURES
- *****************************************************************************/
-/* DMA layout of transfer descriptors */
-struct ci13xxx_td {
-	/* 0 */
-	u32 next;
-#define TD_TERMINATE          BIT(0)
-#define TD_ADDR_MASK          (0xFFFFFFEUL << 5)
-	/* 1 */
-	u32 token;
-#define TD_STATUS             (0x00FFUL <<  0)
-#define TD_STATUS_TR_ERR      BIT(3)
-#define TD_STATUS_DT_ERR      BIT(5)
-#define TD_STATUS_HALTED      BIT(6)
-#define TD_STATUS_ACTIVE      BIT(7)
-#define TD_MULTO              (0x0003UL << 10)
-#define TD_IOC                BIT(15)
-#define TD_TOTAL_BYTES        (0x7FFFUL << 16)
-	/* 2 */
-	u32 page[5];
-#define TD_CURR_OFFSET        (0x0FFFUL <<  0)
-#define TD_FRAME_NUM          (0x07FFUL <<  0)
-#define TD_RESERVED_MASK      (0x0FFFUL <<  0)
-} __attribute__ ((packed));
-
-/* DMA layout of queue heads */
-struct ci13xxx_qh {
-	/* 0 */
-	u32 cap;
-#define QH_IOS                BIT(15)
-#define QH_MAX_PKT            (0x07FFUL << 16)
-#define QH_ZLT                BIT(29)
-#define QH_MULT               (0x0003UL << 30)
-	/* 1 */
-	u32 curr;
-	/* 2 - 8 */
-	struct ci13xxx_td        td;
-	/* 9 */
-	u32 RESERVED;
-	struct usb_ctrlrequest   setup;
-} __attribute__ ((packed));
-
-/* Extension of usb_request */
-struct ci13xxx_req {
-	struct usb_request   req;
-	unsigned             map;
-	struct list_head     queue;
-	struct ci13xxx_td   *ptr;
-	dma_addr_t           dma;
-	struct ci13xxx_td   *zptr;
-	dma_addr_t           zdma;
-};
-
-/* Extension of usb_ep */
-struct ci13xxx_ep {
-	struct usb_ep                          ep;
-	const struct usb_endpoint_descriptor  *desc;
-	u8                                     dir;
-	u8                                     num;
-	u8                                     type;
-	char                                   name[16];
-	struct {
-		struct list_head   queue;
-		struct ci13xxx_qh *ptr;
-		dma_addr_t         dma;
-	}                                      qh;
-	int                                    wedge;
-
-	/* global resources */
-	spinlock_t                            *lock;
-	struct device                         *device;
-	struct dma_pool                       *td_pool;
-};
-
-struct ci13xxx;
-struct ci13xxx_udc_driver {
-	const char	*name;
-	unsigned long	 flags;
-#define CI13XXX_REGS_SHARED		BIT(0)
-#define CI13XXX_REQUIRE_TRANSCEIVER	BIT(1)
-#define CI13XXX_PULLUP_ON_VBUS		BIT(2)
-#define CI13XXX_DISABLE_STREAMING	BIT(3)
-
-#define CI13XXX_CONTROLLER_RESET_EVENT		0
-#define CI13XXX_CONTROLLER_STOPPED_EVENT	1
-	void	(*notify_event) (struct ci13xxx *udc, unsigned event);
-};
-
-/* CI13XXX UDC descriptor & global resources */
-struct ci13xxx {
-	spinlock_t		  *lock;      /* ctrl register bank access */
-	void __iomem              *regs;      /* registers address space */
-
-	struct dma_pool           *qh_pool;   /* DMA pool for queue heads */
-	struct dma_pool           *td_pool;   /* DMA pool for transfer descs */
-	struct usb_request        *status;    /* ep0 status request */
-
-	struct usb_gadget          gadget;     /* USB slave device */
-	struct ci13xxx_ep          ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
-	u32                        ep0_dir;    /* ep0 direction */
-#define ep0out ci13xxx_ep[0]
-#define ep0in  ci13xxx_ep[hw_ep_max / 2]
-	u8                         remote_wakeup; /* Is remote wakeup feature
-							enabled by the host? */
-	u8                         suspended;  /* suspended by the host */
-	u8                         test_mode;  /* the selected test mode */
-
-	struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
-	struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
-	int                        vbus_active; /* is VBUS active */
-	struct usb_phy            *transceiver; /* Transceiver struct */
-};
-
-/******************************************************************************
- * REGISTERS
- *****************************************************************************/
-/* register size */
-#define REG_BITS   (32)
-
-/* HCCPARAMS */
-#define HCCPARAMS_LEN         BIT(17)
-
-/* DCCPARAMS */
-#define DCCPARAMS_DEN         (0x1F << 0)
-#define DCCPARAMS_DC          BIT(7)
-
-/* TESTMODE */
-#define TESTMODE_FORCE        BIT(0)
-
-/* USBCMD */
-#define USBCMD_RS             BIT(0)
-#define USBCMD_RST            BIT(1)
-#define USBCMD_SUTW           BIT(13)
-#define USBCMD_ATDTW          BIT(14)
-
-/* USBSTS & USBINTR */
-#define USBi_UI               BIT(0)
-#define USBi_UEI              BIT(1)
-#define USBi_PCI              BIT(2)
-#define USBi_URI              BIT(6)
-#define USBi_SLI              BIT(8)
-
-/* DEVICEADDR */
-#define DEVICEADDR_USBADRA    BIT(24)
-#define DEVICEADDR_USBADR     (0x7FUL << 25)
-
-/* PORTSC */
-#define PORTSC_FPR            BIT(6)
-#define PORTSC_SUSP           BIT(7)
-#define PORTSC_HSP            BIT(9)
-#define PORTSC_PTC            (0x0FUL << 16)
-
-/* DEVLC */
-#define DEVLC_PSPD            (0x03UL << 25)
-#define    DEVLC_PSPD_HS      (0x02UL << 25)
-
-/* USBMODE */
-#define USBMODE_CM            (0x03UL <<  0)
-#define    USBMODE_CM_IDLE    (0x00UL <<  0)
-#define    USBMODE_CM_DEVICE  (0x02UL <<  0)
-#define    USBMODE_CM_HOST    (0x03UL <<  0)
-#define USBMODE_SLOM          BIT(3)
-#define USBMODE_SDIS          BIT(4)
-
-/* ENDPTCTRL */
-#define ENDPTCTRL_RXS         BIT(0)
-#define ENDPTCTRL_RXT         (0x03UL <<  2)
-#define ENDPTCTRL_RXR         BIT(6)         /* reserved for port 0 */
-#define ENDPTCTRL_RXE         BIT(7)
-#define ENDPTCTRL_TXS         BIT(16)
-#define ENDPTCTRL_TXT         (0x03UL << 18)
-#define ENDPTCTRL_TXR         BIT(22)        /* reserved for port 0 */
-#define ENDPTCTRL_TXE         BIT(23)
-
-/******************************************************************************
- * LOGGING
- *****************************************************************************/
-#define ci13xxx_printk(level, format, args...) \
-do { \
-	if (_udc == NULL) \
-		printk(level "[%s] " format "\n", __func__, ## args); \
-	else \
-		dev_printk(level, _udc->gadget.dev.parent, \
-			   "[%s] " format "\n", __func__, ## args); \
-} while (0)
-
-#define err(format, args...)    ci13xxx_printk(KERN_ERR, format, ## args)
-#define warn(format, args...)   ci13xxx_printk(KERN_WARNING, format, ## args)
-#define info(format, args...)   ci13xxx_printk(KERN_INFO, format, ## args)
-
-#ifdef TRACE
-#define trace(format, args...)      ci13xxx_printk(KERN_DEBUG, format, ## args)
-#define dbg_trace(format, args...)  dev_dbg(dev, format, ##args)
-#else
-#define trace(format, args...)      do {} while (0)
-#define dbg_trace(format, args...)  do {} while (0)
-#endif
-
-#endif	/* _CI13XXX_h_ */
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index baaebf2..390749b 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -40,27 +40,27 @@
  */
 
 static ushort idVendor;
-module_param(idVendor, ushort, 0);
+module_param(idVendor, ushort, 0644);
 MODULE_PARM_DESC(idVendor, "USB Vendor ID");
 
 static ushort idProduct;
-module_param(idProduct, ushort, 0);
+module_param(idProduct, ushort, 0644);
 MODULE_PARM_DESC(idProduct, "USB Product ID");
 
 static ushort bcdDevice;
-module_param(bcdDevice, ushort, 0);
+module_param(bcdDevice, ushort, 0644);
 MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
 
 static char *iManufacturer;
-module_param(iManufacturer, charp, 0);
+module_param(iManufacturer, charp, 0644);
 MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
 
 static char *iProduct;
-module_param(iProduct, charp, 0);
+module_param(iProduct, charp, 0644);
 MODULE_PARM_DESC(iProduct, "USB Product string");
 
 static char *iSerialNumber;
-module_param(iSerialNumber, charp, 0);
+module_param(iSerialNumber, charp, 0644);
 MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
 
 static char composite_manufacturer[50];
@@ -734,9 +734,23 @@
 
 	INIT_LIST_HEAD(&config->functions);
 	config->next_interface_id = 0;
+	memset(config->interface, 0, sizeof(config->interface));
 
 	status = bind(config);
 	if (status < 0) {
+		while (!list_empty(&config->functions)) {
+			struct usb_function		*f;
+
+			f = list_first_entry(&config->functions,
+					struct usb_function, list);
+			list_del(&f->list);
+			if (f->unbind) {
+				DBG(cdev, "unbind function '%s'/%p\n",
+					f->name, f);
+				f->unbind(config, f);
+				/* may free memory for "f" */
+			}
+		}
 		list_del(&config->list);
 		config->cdev = NULL;
 	} else {
@@ -774,6 +788,53 @@
 	return status;
 }
 
+static void remove_config(struct usb_composite_dev *cdev,
+			      struct usb_configuration *config)
+{
+	while (!list_empty(&config->functions)) {
+		struct usb_function		*f;
+
+		f = list_first_entry(&config->functions,
+				struct usb_function, list);
+		list_del(&f->list);
+		if (f->unbind) {
+			DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
+			f->unbind(config, f);
+			/* may free memory for "f" */
+		}
+	}
+	list_del(&config->list);
+	if (config->unbind) {
+		DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
+		config->unbind(config);
+			/* may free memory for "c" */
+	}
+}
+
+/**
+ * usb_remove_config() - remove a configuration from a device.
+ * @cdev: wraps the USB gadget
+ * @config: the configuration
+ *
+ * Drivers must call usb_gadget_disconnect before calling this function
+ * to disconnect the device from the host and make sure the host will not
+ * try to enumerate the device while we are changing the config list.
+ */
+void usb_remove_config(struct usb_composite_dev *cdev,
+		      struct usb_configuration *config)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cdev->lock, flags);
+
+	if (cdev->config == config)
+		reset_config(cdev);
+
+	spin_unlock_irqrestore(&cdev->lock, flags);
+
+	remove_config(cdev, config);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* We support strings in multiple languages ... string descriptor zero
@@ -785,7 +846,7 @@
 static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
 {
 	const struct usb_gadget_strings	*s;
-	u16				language;
+	__le16				language;
 	__le16				*tmp;
 
 	while (*sp) {
@@ -877,7 +938,7 @@
 	else if (cdev->product_override == id)
 		str = iProduct ?: composite->iProduct;
 	else if (cdev->serial_override == id)
-		str = iSerialNumber;
+		str = iSerialNumber ?: composite->iSerialNumber;
 	else
 		str = NULL;
 	if (str) {
@@ -1328,28 +1389,9 @@
 
 	while (!list_empty(&cdev->configs)) {
 		struct usb_configuration	*c;
-
 		c = list_first_entry(&cdev->configs,
 				struct usb_configuration, list);
-		while (!list_empty(&c->functions)) {
-			struct usb_function		*f;
-
-			f = list_first_entry(&c->functions,
-					struct usb_function, list);
-			list_del(&f->list);
-			if (f->unbind) {
-				DBG(cdev, "unbind function '%s'/%p\n",
-						f->name, f);
-				f->unbind(c, f);
-				/* may free memory for "f" */
-			}
-		}
-		list_del(&c->list);
-		if (c->unbind) {
-			DBG(cdev, "unbind config '%s'/%p\n", c->label, c);
-			c->unbind(c);
-			/* may free memory for "c" */
-		}
+		remove_config(cdev, c);
 	}
 	if (composite->unbind)
 		composite->unbind(cdev);
@@ -1431,10 +1473,16 @@
 	/* standardized runtime overrides for device ID data */
 	if (idVendor)
 		cdev->desc.idVendor = cpu_to_le16(idVendor);
+	else
+		idVendor = le16_to_cpu(cdev->desc.idVendor);
 	if (idProduct)
 		cdev->desc.idProduct = cpu_to_le16(idProduct);
+	else
+		idProduct = le16_to_cpu(cdev->desc.idProduct);
 	if (bcdDevice)
 		cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
+	else
+		bcdDevice = le16_to_cpu(cdev->desc.bcdDevice);
 
 	/* string overrides */
 	if (iManufacturer || !cdev->desc.iManufacturer) {
@@ -1455,7 +1503,8 @@
 		cdev->product_override =
 			override_id(cdev, &cdev->desc.iProduct);
 
-	if (iSerialNumber)
+	if (iSerialNumber ||
+	    (!cdev->desc.iSerialNumber && composite->iSerialNumber))
 		cdev->serial_override =
 			override_id(cdev, &cdev->desc.iSerialNumber);
 
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 170cbe8..b799106 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -595,14 +595,12 @@
 
 static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req)
 {
-	struct dummy_ep		*ep;
 	struct dummy_request	*req;
 
-	if (!_ep || !_req)
+	if (!_ep || !_req) {
+		WARN_ON(1);
 		return;
-	ep = usb_ep_to_dummy_ep(_ep);
-	if (!ep->desc && _ep->name != ep0name)
-		return;
+	}
 
 	req = usb_request_to_dummy_request(_req);
 	WARN_ON(!list_empty(&req->queue));
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index f52cb1a..dcd1c7f 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1031,6 +1031,12 @@
 	struct ffs_file_perms perms;
 	umode_t root_mode;
 	const char *dev_name;
+	union {
+		/* set by ffs_fs_mount(), read by ffs_sb_fill() */
+		void *private_data;
+		/* set by ffs_sb_fill(), read by ffs_fs_mount */
+		struct ffs_data *ffs_data;
+	};
 };
 
 static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
@@ -1047,8 +1053,14 @@
 		goto Enomem;
 
 	ffs->sb              = sb;
-	ffs->dev_name        = data->dev_name;
+	ffs->dev_name        = kstrdup(data->dev_name, GFP_KERNEL);
+	if (unlikely(!ffs->dev_name))
+		goto Enomem;
 	ffs->file_perms      = data->perms;
+	ffs->private_data    = data->private_data;
+
+	/* used by the caller of this function */
+	data->ffs_data       = ffs;
 
 	sb->s_fs_info        = ffs;
 	sb->s_blocksize      = PAGE_CACHE_SIZE;
@@ -1167,20 +1179,29 @@
 		},
 		.root_mode = S_IFDIR | 0500,
 	};
+	struct dentry *rv;
 	int ret;
+	void *ffs_dev;
 
 	ENTER();
 
-	ret = functionfs_check_dev_callback(dev_name);
-	if (unlikely(ret < 0))
-		return ERR_PTR(ret);
-
 	ret = ffs_fs_parse_opts(&data, opts);
 	if (unlikely(ret < 0))
 		return ERR_PTR(ret);
 
+	ffs_dev = functionfs_acquire_dev_callback(dev_name);
+	if (IS_ERR(ffs_dev))
+		return ffs_dev;
+
 	data.dev_name = dev_name;
-	return mount_single(t, flags, &data, ffs_sb_fill);
+	data.private_data = ffs_dev;
+	rv = mount_nodev(t, flags, &data, ffs_sb_fill);
+
+	/* data.ffs_data is set by ffs_sb_fill */
+	if (IS_ERR(rv))
+		functionfs_release_dev_callback(data.ffs_data);
+
+	return rv;
 }
 
 static void
@@ -1189,8 +1210,10 @@
 	ENTER();
 
 	kill_litter_super(sb);
-	if (sb->s_fs_info)
+	if (sb->s_fs_info) {
+		functionfs_release_dev_callback(sb->s_fs_info);
 		ffs_data_put(sb->s_fs_info);
+	}
 }
 
 static struct file_system_type ffs_fs_type = {
@@ -1256,6 +1279,7 @@
 		ffs_data_clear(ffs);
 		BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
 		       waitqueue_active(&ffs->ep0req_completion.wait));
+		kfree(ffs->dev_name);
 		kfree(ffs);
 	}
 }
@@ -1473,8 +1497,22 @@
 
 static void ffs_func_free(struct ffs_function *func)
 {
+	struct ffs_ep *ep         = func->eps;
+	unsigned count            = func->ffs->eps_count;
+	unsigned long flags;
+
 	ENTER();
 
+	/* cleanup after autoconfig */
+	spin_lock_irqsave(&func->ffs->eps_lock, flags);
+	do {
+		if (ep->ep && ep->req)
+			usb_ep_free_request(ep->ep, ep->req);
+		ep->req = NULL;
+		++ep;
+	} while (--count);
+	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+
 	ffs_data_put(func->ffs);
 
 	kfree(func->eps);
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index b211342..3b3932c 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -374,7 +374,7 @@
 			break;
 
 		default:
-			VDBG(cdev, "Unknown decriptor request 0x%x\n",
+			VDBG(cdev, "Unknown descriptor request 0x%x\n",
 				 value >> 8);
 			goto stall;
 			break;
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index 2c0cd82..7275706 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -286,7 +286,7 @@
 	struct usb_composite_dev	*cdev;
 
 	cdev = loop->function.config->cdev;
-	disable_endpoints(cdev, loop->in_ep, loop->out_ep);
+	disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
 	VDBG(cdev, "%s disabled\n", loop->function.name);
 }
 
@@ -329,7 +329,7 @@
 	 * than 'buflen' bytes each.
 	 */
 	for (i = 0; i < qlen && result == 0; i++) {
-		req = alloc_ep_req(ep);
+		req = alloc_ep_req(ep, 0);
 		if (req) {
 			req->complete = loopback_complete;
 			result = usb_ep_queue(ep, req, GFP_ATOMIC);
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index cb8c162..f67b453 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -3110,13 +3110,6 @@
 	return rc;
 }
 
-static inline int __deprecated __maybe_unused
-fsg_add(struct usb_composite_dev *cdev, struct usb_configuration *c,
-	struct fsg_common *common)
-{
-	return fsg_bind_config(cdev, c, common);
-}
-
 
 /************************* Module parameters *************************/
 
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index d4f823f..b1681e4 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -71,6 +71,8 @@
 	struct gether			port;
 	u8				ctrl_id, data_id;
 	u8				ethaddr[ETH_ALEN];
+	u32				vendorID;
+	const char			*manufacturer;
 	int				config;
 
 	struct usb_ep			*notify;
@@ -768,12 +770,10 @@
 	rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
 	rndis_set_host_mac(rndis->config, rndis->ethaddr);
 
-#if 0
-// FIXME
-	if (rndis_set_param_vendor(rndis->config, vendorID,
-				manufacturer))
-		goto fail0;
-#endif
+	if (rndis->manufacturer && rndis->vendorID &&
+			rndis_set_param_vendor(rndis->config, rndis->vendorID,
+					       rndis->manufacturer))
+		goto fail;
 
 	/* NOTE:  all that is done without knowing or caring about
 	 * the network link ... which is unavailable to this code
@@ -820,6 +820,7 @@
 
 	rndis_deregister(rndis->config);
 	rndis_exit();
+	rndis_string_defs[0].id = 0;
 
 	if (gadget_is_superspeed(c->cdev->gadget))
 		usb_free_descriptors(f->ss_descriptors);
@@ -840,20 +841,9 @@
 	return true;
 }
 
-/**
- * rndis_bind_config - add RNDIS network link to a configuration
- * @c: the configuration to support the network link
- * @ethaddr: a buffer in which the ethernet address of the host side
- *	side of the link was recorded
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- *
- * Caller must have called @gether_setup().  Caller is also responsible
- * for calling @gether_cleanup() before module unload.
- */
 int
-rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+				u32 vendorID, const char *manufacturer)
 {
 	struct f_rndis	*rndis;
 	int		status;
@@ -898,6 +888,8 @@
 		goto fail;
 
 	memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
+	rndis->vendorID = vendorID;
+	rndis->manufacturer = manufacturer;
 
 	/* RNDIS activates when the host changes this filter */
 	rndis->port.cdc_filter = 0;
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index 7aa7ac8..5c1b68b 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -51,6 +51,9 @@
 
 	struct usb_ep		*in_ep;
 	struct usb_ep		*out_ep;
+	struct usb_ep		*iso_in_ep;
+	struct usb_ep		*iso_out_ep;
+	int			cur_alt;
 };
 
 static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
@@ -59,18 +62,45 @@
 }
 
 static unsigned pattern;
-module_param(pattern, uint, 0);
-MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 ");
+module_param(pattern, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none");
+
+static unsigned isoc_interval = 4;
+module_param(isoc_interval, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_interval, "1 - 16");
+
+static unsigned isoc_maxpacket = 1024;
+module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
+
+static unsigned isoc_mult;
+module_param(isoc_mult, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)");
+
+static unsigned isoc_maxburst;
+module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_interface_descriptor source_sink_intf = {
-	.bLength =		sizeof source_sink_intf,
+static struct usb_interface_descriptor source_sink_intf_alt0 = {
+	.bLength =		USB_DT_INTERFACE_SIZE,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
+	.bAlternateSetting =	0,
 	.bNumEndpoints =	2,
 	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
-	/* .iInterface = DYNAMIC */
+	/* .iInterface		= DYNAMIC */
+};
+
+static struct usb_interface_descriptor source_sink_intf_alt1 = {
+	.bLength =		USB_DT_INTERFACE_SIZE,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bAlternateSetting =	1,
+	.bNumEndpoints =	4,
+	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
+	/* .iInterface		= DYNAMIC */
 };
 
 /* full speed support: */
@@ -91,10 +121,36 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
+static struct usb_endpoint_descriptor fs_iso_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize =	cpu_to_le16(1023),
+	.bInterval =		4,
+};
+
+static struct usb_endpoint_descriptor fs_iso_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize =	cpu_to_le16(1023),
+	.bInterval =		4,
+};
+
 static struct usb_descriptor_header *fs_source_sink_descs[] = {
-	(struct usb_descriptor_header *) &source_sink_intf,
+	(struct usb_descriptor_header *) &source_sink_intf_alt0,
 	(struct usb_descriptor_header *) &fs_sink_desc,
 	(struct usb_descriptor_header *) &fs_source_desc,
+	(struct usb_descriptor_header *) &source_sink_intf_alt1,
+#define FS_ALT_IFC_1_OFFSET	3
+	(struct usb_descriptor_header *) &fs_sink_desc,
+	(struct usb_descriptor_header *) &fs_source_desc,
+	(struct usb_descriptor_header *) &fs_iso_sink_desc,
+	(struct usb_descriptor_header *) &fs_iso_source_desc,
 	NULL,
 };
 
@@ -116,10 +172,34 @@
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
+static struct usb_endpoint_descriptor hs_iso_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+	.bInterval =		4,
+};
+
+static struct usb_endpoint_descriptor hs_iso_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+	.bInterval =		4,
+};
+
 static struct usb_descriptor_header *hs_source_sink_descs[] = {
-	(struct usb_descriptor_header *) &source_sink_intf,
+	(struct usb_descriptor_header *) &source_sink_intf_alt0,
 	(struct usb_descriptor_header *) &hs_source_desc,
 	(struct usb_descriptor_header *) &hs_sink_desc,
+	(struct usb_descriptor_header *) &source_sink_intf_alt1,
+#define HS_ALT_IFC_1_OFFSET	3
+	(struct usb_descriptor_header *) &hs_source_desc,
+	(struct usb_descriptor_header *) &hs_sink_desc,
+	(struct usb_descriptor_header *) &hs_iso_source_desc,
+	(struct usb_descriptor_header *) &hs_iso_sink_desc,
 	NULL,
 };
 
@@ -136,6 +216,7 @@
 struct usb_ss_ep_comp_descriptor ss_source_comp_desc = {
 	.bLength =		USB_DT_SS_EP_COMP_SIZE,
 	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
 	.bMaxBurst =		0,
 	.bmAttributes =		0,
 	.wBytesPerInterval =	0,
@@ -152,17 +233,64 @@
 struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = {
 	.bLength =		USB_DT_SS_EP_COMP_SIZE,
 	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
 	.bMaxBurst =		0,
 	.bmAttributes =		0,
 	.wBytesPerInterval =	0,
 };
 
+static struct usb_endpoint_descriptor ss_iso_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+	.bInterval =		4,
+};
+
+struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = {
+	.bLength =		USB_DT_SS_EP_COMP_SIZE,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	.bMaxBurst =		0,
+	.bmAttributes =		0,
+	.wBytesPerInterval =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_iso_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+	.bInterval =		4,
+};
+
+struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
+	.bLength =		USB_DT_SS_EP_COMP_SIZE,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	.bMaxBurst =		0,
+	.bmAttributes =		0,
+	.wBytesPerInterval =	cpu_to_le16(1024),
+};
+
 static struct usb_descriptor_header *ss_source_sink_descs[] = {
-	(struct usb_descriptor_header *) &source_sink_intf,
+	(struct usb_descriptor_header *) &source_sink_intf_alt0,
 	(struct usb_descriptor_header *) &ss_source_desc,
 	(struct usb_descriptor_header *) &ss_source_comp_desc,
 	(struct usb_descriptor_header *) &ss_sink_desc,
 	(struct usb_descriptor_header *) &ss_sink_comp_desc,
+	(struct usb_descriptor_header *) &source_sink_intf_alt1,
+#define SS_ALT_IFC_1_OFFSET	5
+	(struct usb_descriptor_header *) &ss_source_desc,
+	(struct usb_descriptor_header *) &ss_source_comp_desc,
+	(struct usb_descriptor_header *) &ss_sink_desc,
+	(struct usb_descriptor_header *) &ss_sink_comp_desc,
+	(struct usb_descriptor_header *) &ss_iso_source_desc,
+	(struct usb_descriptor_header *) &ss_iso_source_comp_desc,
+	(struct usb_descriptor_header *) &ss_iso_sink_desc,
+	(struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
 	NULL,
 };
 
@@ -196,9 +324,10 @@
 	id = usb_interface_id(c, f);
 	if (id < 0)
 		return id;
-	source_sink_intf.bInterfaceNumber = id;
+	source_sink_intf_alt0.bInterfaceNumber = id;
+	source_sink_intf_alt1.bInterfaceNumber = id;
 
-	/* allocate endpoints */
+	/* allocate bulk endpoints */
 	ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
 	if (!ss->in_ep) {
 autoconf_fail:
@@ -213,12 +342,74 @@
 		goto autoconf_fail;
 	ss->out_ep->driver_data = cdev;	/* claim */
 
+	/* sanity check the isoc module parameters */
+	if (isoc_interval < 1)
+		isoc_interval = 1;
+	if (isoc_interval > 16)
+		isoc_interval = 16;
+	if (isoc_mult > 2)
+		isoc_mult = 2;
+	if (isoc_maxburst > 15)
+		isoc_maxburst = 15;
+
+	/* fill in the FS isoc descriptors from the module parameters */
+	fs_iso_source_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
+						1023 : isoc_maxpacket;
+	fs_iso_source_desc.bInterval = isoc_interval;
+	fs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
+						1023 : isoc_maxpacket;
+	fs_iso_sink_desc.bInterval = isoc_interval;
+
+	/* allocate iso endpoints */
+	ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
+	if (!ss->iso_in_ep)
+		goto no_iso;
+	ss->iso_in_ep->driver_data = cdev;	/* claim */
+
+	ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
+	if (ss->iso_out_ep) {
+		ss->iso_out_ep->driver_data = cdev;	/* claim */
+	} else {
+		ss->iso_in_ep->driver_data = NULL;
+		ss->iso_in_ep = NULL;
+no_iso:
+		/*
+		 * We still want to work even if the UDC doesn't have isoc
+		 * endpoints, so null out the alt interface that contains
+		 * them and continue.
+		 */
+		fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL;
+		hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL;
+		ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
+	}
+
+	if (isoc_maxpacket > 1024)
+		isoc_maxpacket = 1024;
+
 	/* support high speed hardware */
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 		hs_source_desc.bEndpointAddress =
 				fs_source_desc.bEndpointAddress;
 		hs_sink_desc.bEndpointAddress =
 				fs_sink_desc.bEndpointAddress;
+
+		/*
+		 * Fill in the HS isoc descriptors from the module parameters.
+		 * We assume that the user knows what they are doing and won't
+		 * give parameters that their UDC doesn't support.
+		 */
+		hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
+		hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
+		hs_iso_source_desc.bInterval = isoc_interval;
+		hs_iso_source_desc.bEndpointAddress =
+				fs_iso_source_desc.bEndpointAddress;
+
+		hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
+		hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11;
+		hs_iso_sink_desc.bInterval = isoc_interval;
+		hs_iso_sink_desc.bEndpointAddress =
+				fs_iso_sink_desc.bEndpointAddress;
+
 		f->hs_descriptors = hs_source_sink_descs;
 	}
 
@@ -228,13 +419,39 @@
 				fs_source_desc.bEndpointAddress;
 		ss_sink_desc.bEndpointAddress =
 				fs_sink_desc.bEndpointAddress;
+
+		/*
+		 * Fill in the SS isoc descriptors from the module parameters.
+		 * We assume that the user knows what they are doing and won't
+		 * give parameters that their UDC doesn't support.
+		 */
+		ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
+		ss_iso_source_desc.bInterval = isoc_interval;
+		ss_iso_source_comp_desc.bmAttributes = isoc_mult;
+		ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst;
+		ss_iso_source_comp_desc.wBytesPerInterval =
+			isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
+		ss_iso_source_desc.bEndpointAddress =
+				fs_iso_source_desc.bEndpointAddress;
+
+		ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
+		ss_iso_sink_desc.bInterval = isoc_interval;
+		ss_iso_sink_comp_desc.bmAttributes = isoc_mult;
+		ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst;
+		ss_iso_sink_comp_desc.wBytesPerInterval =
+			isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
+		ss_iso_sink_desc.bEndpointAddress =
+				fs_iso_sink_desc.bEndpointAddress;
+
 		f->ss_descriptors = ss_source_sink_descs;
 	}
 
-	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
+	DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
 	    (gadget_is_superspeed(c->cdev->gadget) ? "super" :
 	     (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
-			f->name, ss->in_ep->name, ss->out_ep->name);
+			f->name, ss->in_ep->name, ss->out_ep->name,
+			ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
+			ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
 	return 0;
 }
 
@@ -251,6 +468,9 @@
 	u8			*buf = req->buf;
 	struct usb_composite_dev *cdev = ss->function.config->cdev;
 
+	if (pattern == 2)
+		return 0;
+
 	for (i = 0; i < req->actual; i++, buf++) {
 		switch (pattern) {
 
@@ -265,7 +485,7 @@
 		 * each usb transfer request should be.  Resync is done
 		 * with set_interface or set_config.  (We *WANT* it to
 		 * get quickly out of sync if controllers or their drivers
-		 * stutter for any reason, including buffer duplcation...)
+		 * stutter for any reason, including buffer duplication...)
 		 */
 		case 1:
 			if (*buf == (u8)(i % 63))
@@ -292,21 +512,30 @@
 		for  (i = 0; i < req->length; i++)
 			*buf++ = (u8) (i % 63);
 		break;
+	case 2:
+		break;
 	}
 }
 
 static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct f_sourcesink	*ss = ep->driver_data;
-	struct usb_composite_dev *cdev = ss->function.config->cdev;
-	int			status = req->status;
+	struct usb_composite_dev	*cdev;
+	struct f_sourcesink		*ss = ep->driver_data;
+	int				status = req->status;
+
+	/* driver_data will be null if ep has been disabled */
+	if (!ss)
+		return;
+
+	cdev = ss->function.config->cdev;
 
 	switch (status) {
 
 	case 0:				/* normal completion? */
 		if (ep == ss->out_ep) {
 			check_read_data(ss, req);
-			memset(req->buf, 0x55, req->length);
+			if (pattern != 2)
+				memset(req->buf, 0x55, req->length);
 		} else
 			reinit_write_data(ep, req);
 		break;
@@ -344,32 +573,57 @@
 	}
 }
 
-static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in)
+static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
+		bool is_iso, int speed)
 {
 	struct usb_ep		*ep;
 	struct usb_request	*req;
-	int			status;
+	int			i, size, status;
 
-	ep = is_in ? ss->in_ep : ss->out_ep;
-	req = alloc_ep_req(ep);
-	if (!req)
-		return -ENOMEM;
+	for (i = 0; i < 8; i++) {
+		if (is_iso) {
+			switch (speed) {
+			case USB_SPEED_SUPER:
+				size = isoc_maxpacket * (isoc_mult + 1) *
+						(isoc_maxburst + 1);
+				break;
+			case USB_SPEED_HIGH:
+				size = isoc_maxpacket * (isoc_mult + 1);
+				break;
+			default:
+				size = isoc_maxpacket > 1023 ?
+						1023 : isoc_maxpacket;
+				break;
+			}
+			ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
+			req = alloc_ep_req(ep, size);
+		} else {
+			ep = is_in ? ss->in_ep : ss->out_ep;
+			req = alloc_ep_req(ep, 0);
+		}
 
-	req->complete = source_sink_complete;
-	if (is_in)
-		reinit_write_data(ep, req);
-	else
-		memset(req->buf, 0x55, req->length);
+		if (!req)
+			return -ENOMEM;
 
-	status = usb_ep_queue(ep, req, GFP_ATOMIC);
-	if (status) {
-		struct usb_composite_dev	*cdev;
+		req->complete = source_sink_complete;
+		if (is_in)
+			reinit_write_data(ep, req);
+		else if (pattern != 2)
+			memset(req->buf, 0x55, req->length);
 
-		cdev = ss->function.config->cdev;
-		ERROR(cdev, "start %s %s --> %d\n",
-				is_in ? "IN" : "OUT",
-				ep->name, status);
-		free_ep_req(ep, req);
+		status = usb_ep_queue(ep, req, GFP_ATOMIC);
+		if (status) {
+			struct usb_composite_dev	*cdev;
+
+			cdev = ss->function.config->cdev;
+			ERROR(cdev, "start %s%s %s --> %d\n",
+			      is_iso ? "ISO-" : "", is_in ? "IN" : "OUT",
+			      ep->name, status);
+			free_ep_req(ep, req);
+		}
+
+		if (!is_iso)
+			break;
 	}
 
 	return status;
@@ -380,17 +634,20 @@
 	struct usb_composite_dev	*cdev;
 
 	cdev = ss->function.config->cdev;
-	disable_endpoints(cdev, ss->in_ep, ss->out_ep);
+	disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
+			ss->iso_out_ep);
 	VDBG(cdev, "%s disabled\n", ss->function.name);
 }
 
 static int
-enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
+enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
+		int alt)
 {
 	int					result = 0;
+	int					speed = cdev->gadget->speed;
 	struct usb_ep				*ep;
 
-	/* one endpoint writes (sources) zeroes IN (to the host) */
+	/* one bulk endpoint writes (sources) zeroes IN (to the host) */
 	ep = ss->in_ep;
 	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
 	if (result)
@@ -400,7 +657,7 @@
 		return result;
 	ep->driver_data = ss;
 
-	result = source_sink_start_ep(ss, true);
+	result = source_sink_start_ep(ss, true, false, speed);
 	if (result < 0) {
 fail:
 		ep = ss->in_ep;
@@ -409,7 +666,7 @@
 		return result;
 	}
 
-	/* one endpoint reads (sinks) anything OUT (from the host) */
+	/* one bulk endpoint reads (sinks) anything OUT (from the host) */
 	ep = ss->out_ep;
 	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
 	if (result)
@@ -419,27 +676,82 @@
 		goto fail;
 	ep->driver_data = ss;
 
-	result = source_sink_start_ep(ss, false);
+	result = source_sink_start_ep(ss, false, false, speed);
 	if (result < 0) {
+fail2:
+		ep = ss->out_ep;
 		usb_ep_disable(ep);
 		ep->driver_data = NULL;
 		goto fail;
 	}
 
-	DBG(cdev, "%s enabled\n", ss->function.name);
+	if (alt == 0)
+		goto out;
+
+	/* one iso endpoint writes (sources) zeroes IN (to the host) */
+	ep = ss->iso_in_ep;
+	if (ep) {
+		result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+		if (result)
+			goto fail2;
+		result = usb_ep_enable(ep);
+		if (result < 0)
+			goto fail2;
+		ep->driver_data = ss;
+
+		result = source_sink_start_ep(ss, true, true, speed);
+		if (result < 0) {
+fail3:
+			ep = ss->iso_in_ep;
+			if (ep) {
+				usb_ep_disable(ep);
+				ep->driver_data = NULL;
+			}
+			goto fail2;
+		}
+	}
+
+	/* one iso endpoint reads (sinks) anything OUT (from the host) */
+	ep = ss->iso_out_ep;
+	if (ep) {
+		result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+		if (result)
+			goto fail3;
+		result = usb_ep_enable(ep);
+		if (result < 0)
+			goto fail3;
+		ep->driver_data = ss;
+
+		result = source_sink_start_ep(ss, false, true, speed);
+		if (result < 0) {
+			usb_ep_disable(ep);
+			ep->driver_data = NULL;
+			goto fail3;
+		}
+	}
+out:
+	ss->cur_alt = alt;
+
+	DBG(cdev, "%s enabled, alt intf %d\n", ss->function.name, alt);
 	return result;
 }
 
 static int sourcesink_set_alt(struct usb_function *f,
 		unsigned intf, unsigned alt)
 {
-	struct f_sourcesink	*ss = func_to_ss(f);
-	struct usb_composite_dev *cdev = f->config->cdev;
+	struct f_sourcesink		*ss = func_to_ss(f);
+	struct usb_composite_dev	*cdev = f->config->cdev;
 
-	/* we know alt is zero */
 	if (ss->in_ep->driver_data)
 		disable_source_sink(ss);
-	return enable_source_sink(cdev, ss);
+	return enable_source_sink(cdev, ss, alt);
+}
+
+static int sourcesink_get_alt(struct usb_function *f, unsigned intf)
+{
+	struct f_sourcesink		*ss = func_to_ss(f);
+
+	return ss->cur_alt;
 }
 
 static void sourcesink_disable(struct usb_function *f)
@@ -465,6 +777,7 @@
 	ss->function.bind = sourcesink_bind;
 	ss->function.unbind = sourcesink_unbind;
 	ss->function.set_alt = sourcesink_set_alt;
+	ss->function.get_alt = sourcesink_get_alt;
 	ss->function.disable = sourcesink_disable;
 
 	status = usb_add_function(c, &ss->function);
@@ -536,7 +849,7 @@
 		req->length = value;
 		value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0)
-			ERROR(c->cdev, "source/sinkc response, err %d\n",
+			ERROR(c->cdev, "source/sink response, err %d\n",
 					value);
 	}
 
@@ -545,12 +858,12 @@
 }
 
 static struct usb_configuration sourcesink_driver = {
-	.label		= "source/sink",
-	.strings	= sourcesink_strings,
-	.setup		= sourcesink_setup,
-	.bConfigurationValue = 3,
-	.bmAttributes	= USB_CONFIG_ATT_SELFPOWER,
-	/* .iConfiguration = DYNAMIC */
+	.label			= "source/sink",
+	.strings		= sourcesink_strings,
+	.setup			= sourcesink_setup,
+	.bConfigurationValue	= 3,
+	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+	/* .iConfiguration	= DYNAMIC */
 };
 
 /**
@@ -567,7 +880,8 @@
 		return id;
 	strings_sourcesink[0].id = id;
 
-	source_sink_intf.iInterface = id;
+	source_sink_intf_alt0.iInterface = id;
+	source_sink_intf_alt1.iInterface = id;
 	sourcesink_driver.iConfiguration = id;
 
 	/* support autoresume for remote wakeup testing */
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 877a2c4..51881f3 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -71,9 +71,6 @@
 	.wMaxPacketSize =	USB_MAX_CTRL_PAYLOAD,
 };
 
-/* it is initialized in probe()  */
-static struct qe_udc *udc_controller;
-
 /********************************************************************
  *      Internal Used Function Start
 ********************************************************************/
@@ -188,8 +185,8 @@
 {
 	qe_eptx_stall_change(&udc->eps[0], 1);
 	qe_eprx_stall_change(&udc->eps[0], 1);
-	udc_controller->ep0_state = WAIT_FOR_SETUP;
-	udc_controller->ep0_dir = 0;
+	udc->ep0_state = WAIT_FOR_SETUP;
+	udc->ep0_dir = 0;
 	return 0;
 }
 
@@ -450,13 +447,13 @@
 
 	ep->rxbuf_d = virt_to_phys((void *)ep->rxbuffer);
 	if (ep->rxbuf_d == DMA_ADDR_INVALID) {
-		ep->rxbuf_d = dma_map_single(udc_controller->gadget.dev.parent,
+		ep->rxbuf_d = dma_map_single(ep->udc->gadget.dev.parent,
 					ep->rxbuffer,
 					size,
 					DMA_FROM_DEVICE);
 		ep->rxbufmap = 1;
 	} else {
-		dma_sync_single_for_device(udc_controller->gadget.dev.parent,
+		dma_sync_single_for_device(ep->udc->gadget.dev.parent,
 					ep->rxbuf_d, size,
 					DMA_FROM_DEVICE);
 		ep->rxbufmap = 0;
@@ -489,10 +486,10 @@
 	epparam = udc->ep_param[pipe_num];
 
 	usep = 0;
-	logepnum = (ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	logepnum = (ep->ep.desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
 	usep |= (logepnum << USB_EPNUM_SHIFT);
 
-	switch (ep->desc->bmAttributes & 0x03) {
+	switch (ep->ep.desc->bmAttributes & 0x03) {
 	case USB_ENDPOINT_XFER_BULK:
 		usep |= USB_TRANS_BULK;
 		break;
@@ -644,7 +641,7 @@
 	/* initialize ep structure */
 	ep->ep.maxpacket = max;
 	ep->tm = (u8)(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	ep->stopped = 0;
 	ep->init = 1;
 
@@ -698,14 +695,14 @@
 	return -ENODEV;
 }
 
-static inline void qe_usb_enable(void)
+static inline void qe_usb_enable(struct qe_udc *udc)
 {
-	setbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN);
+	setbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN);
 }
 
-static inline void qe_usb_disable(void)
+static inline void qe_usb_disable(struct qe_udc *udc)
 {
-	clrbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN);
+	clrbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN);
 }
 
 /*----------------------------------------------------------------------------*
@@ -1599,7 +1596,7 @@
 	ep = container_of(_ep, struct qe_ep, ep);
 
 	/* catch various bogus parameters */
-	if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] ||
+	if (!_ep || !desc || ep->ep.desc || _ep->name == ep_name[0] ||
 			(desc->bDescriptorType != USB_DT_ENDPOINT))
 		return -EINVAL;
 
@@ -1629,7 +1626,7 @@
 	ep = container_of(_ep, struct qe_ep, ep);
 	udc = ep->udc;
 
-	if (!_ep || !ep->desc) {
+	if (!_ep || !ep->ep.desc) {
 		dev_dbg(udc->dev, "%s not enabled\n", _ep ? ep->ep.name : NULL);
 		return -EINVAL;
 	}
@@ -1637,7 +1634,6 @@
 	spin_lock_irqsave(&udc->lock, flags);
 	/* Nuke all pending requests (does flush) */
 	nuke(ep, -ESHUTDOWN);
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	ep->stopped = 1;
 	ep->tx_req = NULL;
@@ -1656,13 +1652,13 @@
 	if (ep->dir != USB_DIR_IN) {
 		kfree(ep->rxframe);
 		if (ep->rxbufmap) {
-			dma_unmap_single(udc_controller->gadget.dev.parent,
+			dma_unmap_single(udc->gadget.dev.parent,
 					ep->rxbuf_d, size,
 					DMA_FROM_DEVICE);
 			ep->rxbuf_d = DMA_ADDR_INVALID;
 		} else {
 			dma_sync_single_for_cpu(
-					udc_controller->gadget.dev.parent,
+					udc->gadget.dev.parent,
 					ep->rxbuf_d, size,
 					DMA_FROM_DEVICE);
 		}
@@ -1715,7 +1711,7 @@
 		dev_dbg(udc->dev, "bad params\n");
 		return -EINVAL;
 	}
-	if (!_ep || (!ep->desc && ep_index(ep))) {
+	if (!_ep || (!ep->ep.desc && ep_index(ep))) {
 		dev_dbg(udc->dev, "bad ep\n");
 		return -EINVAL;
 	}
@@ -1826,7 +1822,7 @@
 	struct qe_udc *udc;
 
 	ep = container_of(_ep, struct qe_ep, ep);
-	if (!_ep || !ep->desc) {
+	if (!_ep || !ep->ep.desc) {
 		status = -EINVAL;
 		goto out;
 	}
@@ -1880,9 +1876,10 @@
 /* Get the current frame number */
 static int qe_get_frame(struct usb_gadget *gadget)
 {
+	struct qe_udc *udc = container_of(gadget, struct qe_udc, gadget);
 	u16 tmp;
 
-	tmp = in_be16(&udc_controller->usb_param->frame_n);
+	tmp = in_be16(&udc->usb_param->frame_n);
 	if (tmp & 0x8000)
 		tmp = tmp & 0x07ff;
 	else
@@ -1891,57 +1888,16 @@
 	return (int)tmp;
 }
 
-/* Tries to wake up the host connected to this gadget
- *
- * Return : 0-success
- * Negative-this feature not enabled by host or not supported by device hw
- */
-static int qe_wakeup(struct usb_gadget *gadget)
-{
-	return -ENOTSUPP;
-}
-
-/* Notify controller that VBUS is powered, Called by whatever
-   detects VBUS sessions */
-static int qe_vbus_session(struct usb_gadget *gadget, int is_active)
-{
-	return -ENOTSUPP;
-}
-
-/* constrain controller's VBUS power usage
- * This call is used by gadget drivers during SET_CONFIGURATION calls,
- * reporting how much power the device may consume.  For example, this
- * could affect how quickly batteries are recharged.
- *
- * Returns zero on success, else negative errno.
- */
-static int qe_vbus_draw(struct usb_gadget *gadget, unsigned mA)
-{
-	return -ENOTSUPP;
-}
-
-/* Change Data+ pullup status
- * this func is used by usb_gadget_connect/disconnect
- */
-static int qe_pullup(struct usb_gadget *gadget, int is_on)
-{
-	return -ENOTSUPP;
-}
-
-static int fsl_qe_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int fsl_qe_stop(struct usb_gadget_driver *driver);
+static int fsl_qe_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
+static int fsl_qe_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
 
 /* defined in usb_gadget.h */
 static struct usb_gadget_ops qe_gadget_ops = {
 	.get_frame = qe_get_frame,
-	.wakeup = qe_wakeup,
-/*	.set_selfpowered = qe_set_selfpowered,*/ /* always selfpowered */
-	.vbus_session = qe_vbus_session,
-	.vbus_draw = qe_vbus_draw,
-	.pullup = qe_pullup,
-	.start = fsl_qe_start,
-	.stop = fsl_qe_stop,
+	.udc_start = fsl_qe_start,
+	.udc_stop = fsl_qe_stop,
 };
 
 /*-------------------------------------------------------------------------
@@ -2015,7 +1971,7 @@
 		u16 usep;
 
 		/* stall if endpoint doesn't exist */
-		if (!target_ep->desc)
+		if (!target_ep->ep.desc)
 			goto stall;
 
 		usep = in_be16(&udc->usb_regs->usb_usep[pipe]);
@@ -2190,7 +2146,7 @@
 	if (udc->usb_state == USB_STATE_DEFAULT)
 		return 0;
 
-	qe_usb_disable();
+	qe_usb_disable(udc);
 	out_8(&udc->usb_regs->usb_usadr, 0);
 
 	for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
@@ -2202,7 +2158,7 @@
 	udc->usb_state = USB_STATE_DEFAULT;
 	udc->ep0_state = WAIT_FOR_SETUP;
 	udc->ep0_dir = USB_DIR_OUT;
-	qe_usb_enable();
+	qe_usb_enable(udc);
 	return 0;
 }
 
@@ -2327,92 +2283,65 @@
 /*-------------------------------------------------------------------------
 	Gadget driver probe and unregister.
  --------------------------------------------------------------------------*/
-static int fsl_qe_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int fsl_qe_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	int retval;
-	unsigned long flags = 0;
+	struct qe_udc *udc;
+	unsigned long flags;
 
-	/* standard operations */
-	if (!udc_controller)
-		return -ENODEV;
-
-	if (!driver || driver->max_speed < USB_SPEED_FULL
-			|| !bind || !driver->disconnect || !driver->setup)
-		return -EINVAL;
-
-	if (udc_controller->driver)
-		return -EBUSY;
-
+	udc = container_of(gadget, struct qe_udc, gadget);
 	/* lock is needed but whether should use this lock or another */
-	spin_lock_irqsave(&udc_controller->lock, flags);
+	spin_lock_irqsave(&udc->lock, flags);
 
 	driver->driver.bus = NULL;
 	/* hook up the driver */
-	udc_controller->driver = driver;
-	udc_controller->gadget.dev.driver = &driver->driver;
-	udc_controller->gadget.speed = driver->max_speed;
-	spin_unlock_irqrestore(&udc_controller->lock, flags);
-
-	retval = bind(&udc_controller->gadget);
-	if (retval) {
-		dev_err(udc_controller->dev, "bind to %s --> %d",
-				driver->driver.name, retval);
-		udc_controller->gadget.dev.driver = NULL;
-		udc_controller->driver = NULL;
-		return retval;
-	}
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+	udc->gadget.speed = driver->max_speed;
 
 	/* Enable IRQ reg and Set usbcmd reg EN bit */
-	qe_usb_enable();
+	qe_usb_enable(udc);
 
-	out_be16(&udc_controller->usb_regs->usb_usber, 0xffff);
-	out_be16(&udc_controller->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE);
-	udc_controller->usb_state = USB_STATE_ATTACHED;
-	udc_controller->ep0_state = WAIT_FOR_SETUP;
-	udc_controller->ep0_dir = USB_DIR_OUT;
-	dev_info(udc_controller->dev, "%s bind to driver %s \n",
-		udc_controller->gadget.name, driver->driver.name);
+	out_be16(&udc->usb_regs->usb_usber, 0xffff);
+	out_be16(&udc->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE);
+	udc->usb_state = USB_STATE_ATTACHED;
+	udc->ep0_state = WAIT_FOR_SETUP;
+	udc->ep0_dir = USB_DIR_OUT;
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	dev_info(udc->dev, "%s bind to driver %s\n", udc->gadget.name,
+			driver->driver.name);
 	return 0;
 }
 
-static int fsl_qe_stop(struct usb_gadget_driver *driver)
+static int fsl_qe_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
+	struct qe_udc *udc;
 	struct qe_ep *loop_ep;
 	unsigned long flags;
 
-	if (!udc_controller)
-		return -ENODEV;
-
-	if (!driver || driver != udc_controller->driver)
-		return -EINVAL;
-
+	udc = container_of(gadget, struct qe_udc, gadget);
 	/* stop usb controller, disable intr */
-	qe_usb_disable();
+	qe_usb_disable(udc);
 
 	/* in fact, no needed */
-	udc_controller->usb_state = USB_STATE_ATTACHED;
-	udc_controller->ep0_state = WAIT_FOR_SETUP;
-	udc_controller->ep0_dir = 0;
+	udc->usb_state = USB_STATE_ATTACHED;
+	udc->ep0_state = WAIT_FOR_SETUP;
+	udc->ep0_dir = 0;
 
 	/* stand operation */
-	spin_lock_irqsave(&udc_controller->lock, flags);
-	udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
-	nuke(&udc_controller->eps[0], -ESHUTDOWN);
-	list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list,
-				ep.ep_list)
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	nuke(&udc->eps[0], -ESHUTDOWN);
+	list_for_each_entry(loop_ep, &udc->gadget.ep_list, ep.ep_list)
 		nuke(loop_ep, -ESHUTDOWN);
-	spin_unlock_irqrestore(&udc_controller->lock, flags);
+	spin_unlock_irqrestore(&udc->lock, flags);
 
-	/* report disconnect; the controller is already quiesced */
-	driver->disconnect(&udc_controller->gadget);
+	udc->gadget.dev.driver = NULL;
+	udc->driver = NULL;
 
-	/* unbind gadget and unhook driver. */
-	driver->unbind(&udc_controller->gadget);
-	udc_controller->gadget.dev.driver = NULL;
-	udc_controller->driver = NULL;
-
-	dev_info(udc_controller->dev, "unregistered gadget driver '%s'\r\n",
+	dev_info(udc->dev, "unregistered gadget driver '%s'\r\n",
 			driver->driver.name);
 	return 0;
 }
@@ -2502,7 +2431,7 @@
 	ep->ep.ops = &qe_ep_ops;
 	ep->stopped = 1;
 	ep->ep.maxpacket = (unsigned short) ~0;
-	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->dir = 0xff;
 	ep->epnum = (u8)pipe_num;
 	ep->sent = 0;
@@ -2531,21 +2460,22 @@
  *----------------------------------------------------------------------*/
 static void qe_udc_release(struct device *dev)
 {
-	int i = 0;
+	struct qe_udc *udc = container_of(dev, struct qe_udc, gadget.dev);
+	int i;
 
-	complete(udc_controller->done);
-	cpm_muram_free(cpm_muram_offset(udc_controller->ep_param[0]));
+	complete(udc->done);
+	cpm_muram_free(cpm_muram_offset(udc->ep_param[0]));
 	for (i = 0; i < USB_MAX_ENDPOINTS; i++)
-		udc_controller->ep_param[i] = NULL;
+		udc->ep_param[i] = NULL;
 
-	kfree(udc_controller);
-	udc_controller = NULL;
+	kfree(udc);
 }
 
 /* Driver probe functions */
 static const struct of_device_id qe_udc_match[];
 static int __devinit qe_udc_probe(struct platform_device *ofdev)
 {
+	struct qe_udc *udc;
 	const struct of_device_id *match;
 	struct device_node *np = ofdev->dev.of_node;
 	struct qe_ep *ep;
@@ -2562,44 +2492,44 @@
 		return -ENODEV;
 
 	/* Initialize the udc structure including QH member and other member */
-	udc_controller = qe_udc_config(ofdev);
-	if (!udc_controller) {
+	udc = qe_udc_config(ofdev);
+	if (!udc) {
 		dev_err(&ofdev->dev, "failed to initialize\n");
 		return -ENOMEM;
 	}
 
-	udc_controller->soc_type = (unsigned long)match->data;
-	udc_controller->usb_regs = of_iomap(np, 0);
-	if (!udc_controller->usb_regs) {
+	udc->soc_type = (unsigned long)match->data;
+	udc->usb_regs = of_iomap(np, 0);
+	if (!udc->usb_regs) {
 		ret = -ENOMEM;
 		goto err1;
 	}
 
 	/* initialize usb hw reg except for regs for EP,
 	 * leave usbintr reg untouched*/
-	qe_udc_reg_init(udc_controller);
+	qe_udc_reg_init(udc);
 
 	/* here comes the stand operations for probe
 	 * set the qe_udc->gadget.xxx */
-	udc_controller->gadget.ops = &qe_gadget_ops;
+	udc->gadget.ops = &qe_gadget_ops;
 
 	/* gadget.ep0 is a pointer */
-	udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
+	udc->gadget.ep0 = &udc->eps[0].ep;
 
-	INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
 
 	/* modify in register gadget process */
-	udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
 
 	/* name: Identifies the controller hardware type. */
-	udc_controller->gadget.name = driver_name;
+	udc->gadget.name = driver_name;
 
-	device_initialize(&udc_controller->gadget.dev);
+	device_initialize(&udc->gadget.dev);
 
-	dev_set_name(&udc_controller->gadget.dev, "gadget");
+	dev_set_name(&udc->gadget.dev, "gadget");
 
-	udc_controller->gadget.dev.release = qe_udc_release;
-	udc_controller->gadget.dev.parent = &ofdev->dev;
+	udc->gadget.dev.release = qe_udc_release;
+	udc->gadget.dev.parent = &ofdev->dev;
 
 	/* initialize qe_ep struct */
 	for (i = 0; i < USB_MAX_ENDPOINTS ; i++) {
@@ -2608,104 +2538,104 @@
 
 		/* setup the qe_ep struct and link ep.ep.list
 		 * into gadget.ep_list */
-		qe_ep_config(udc_controller, (unsigned char)i);
+		qe_ep_config(udc, (unsigned char)i);
 	}
 
 	/* ep0 initialization in here */
-	ret = qe_ep_init(udc_controller, 0, &qe_ep0_desc);
+	ret = qe_ep_init(udc, 0, &qe_ep0_desc);
 	if (ret)
 		goto err2;
 
 	/* create a buf for ZLP send, need to remain zeroed */
-	udc_controller->nullbuf = kzalloc(256, GFP_KERNEL);
-	if (udc_controller->nullbuf == NULL) {
-		dev_err(udc_controller->dev, "cannot alloc nullbuf\n");
+	udc->nullbuf = kzalloc(256, GFP_KERNEL);
+	if (udc->nullbuf == NULL) {
+		dev_err(udc->dev, "cannot alloc nullbuf\n");
 		ret = -ENOMEM;
 		goto err3;
 	}
 
 	/* buffer for data of get_status request */
-	udc_controller->statusbuf = kzalloc(2, GFP_KERNEL);
-	if (udc_controller->statusbuf == NULL) {
+	udc->statusbuf = kzalloc(2, GFP_KERNEL);
+	if (udc->statusbuf == NULL) {
 		ret = -ENOMEM;
 		goto err4;
 	}
 
-	udc_controller->nullp = virt_to_phys((void *)udc_controller->nullbuf);
-	if (udc_controller->nullp == DMA_ADDR_INVALID) {
-		udc_controller->nullp = dma_map_single(
-					udc_controller->gadget.dev.parent,
-					udc_controller->nullbuf,
+	udc->nullp = virt_to_phys((void *)udc->nullbuf);
+	if (udc->nullp == DMA_ADDR_INVALID) {
+		udc->nullp = dma_map_single(
+					udc->gadget.dev.parent,
+					udc->nullbuf,
 					256,
 					DMA_TO_DEVICE);
-		udc_controller->nullmap = 1;
+		udc->nullmap = 1;
 	} else {
-		dma_sync_single_for_device(udc_controller->gadget.dev.parent,
-					udc_controller->nullp, 256,
+		dma_sync_single_for_device(udc->gadget.dev.parent,
+					udc->nullp, 256,
 					DMA_TO_DEVICE);
 	}
 
-	tasklet_init(&udc_controller->rx_tasklet, ep_rx_tasklet,
-			(unsigned long)udc_controller);
+	tasklet_init(&udc->rx_tasklet, ep_rx_tasklet,
+			(unsigned long)udc);
 	/* request irq and disable DR  */
-	udc_controller->usb_irq = irq_of_parse_and_map(np, 0);
-	if (!udc_controller->usb_irq) {
+	udc->usb_irq = irq_of_parse_and_map(np, 0);
+	if (!udc->usb_irq) {
 		ret = -EINVAL;
 		goto err_noirq;
 	}
 
-	ret = request_irq(udc_controller->usb_irq, qe_udc_irq, 0,
-				driver_name, udc_controller);
+	ret = request_irq(udc->usb_irq, qe_udc_irq, 0,
+				driver_name, udc);
 	if (ret) {
-		dev_err(udc_controller->dev, "cannot request irq %d err %d \n",
-			udc_controller->usb_irq, ret);
+		dev_err(udc->dev, "cannot request irq %d err %d\n",
+				udc->usb_irq, ret);
 		goto err5;
 	}
 
-	ret = device_add(&udc_controller->gadget.dev);
+	ret = device_add(&udc->gadget.dev);
 	if (ret)
 		goto err6;
 
-	ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget);
+	ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget);
 	if (ret)
 		goto err7;
 
-	dev_info(udc_controller->dev,
+	dev_set_drvdata(&ofdev->dev, udc);
+	dev_info(udc->dev,
 			"%s USB controller initialized as device\n",
-			(udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
+			(udc->soc_type == PORT_QE) ? "QE" : "CPM");
 	return 0;
 
 err7:
-	device_unregister(&udc_controller->gadget.dev);
+	device_unregister(&udc->gadget.dev);
 err6:
-	free_irq(udc_controller->usb_irq, udc_controller);
+	free_irq(udc->usb_irq, udc);
 err5:
-	irq_dispose_mapping(udc_controller->usb_irq);
+	irq_dispose_mapping(udc->usb_irq);
 err_noirq:
-	if (udc_controller->nullmap) {
-		dma_unmap_single(udc_controller->gadget.dev.parent,
-			udc_controller->nullp, 256,
+	if (udc->nullmap) {
+		dma_unmap_single(udc->gadget.dev.parent,
+			udc->nullp, 256,
 				DMA_TO_DEVICE);
-			udc_controller->nullp = DMA_ADDR_INVALID;
+			udc->nullp = DMA_ADDR_INVALID;
 	} else {
-		dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
-			udc_controller->nullp, 256,
+		dma_sync_single_for_cpu(udc->gadget.dev.parent,
+			udc->nullp, 256,
 				DMA_TO_DEVICE);
 	}
-	kfree(udc_controller->statusbuf);
+	kfree(udc->statusbuf);
 err4:
-	kfree(udc_controller->nullbuf);
+	kfree(udc->nullbuf);
 err3:
-	ep = &udc_controller->eps[0];
+	ep = &udc->eps[0];
 	cpm_muram_free(cpm_muram_offset(ep->rxbase));
 	kfree(ep->rxframe);
 	kfree(ep->rxbuffer);
 	kfree(ep->txframe);
 err2:
-	iounmap(udc_controller->usb_regs);
+	iounmap(udc->usb_regs);
 err1:
-	kfree(udc_controller);
-	udc_controller = NULL;
+	kfree(udc);
 	return ret;
 }
 
@@ -2723,44 +2653,41 @@
 
 static int __devexit qe_udc_remove(struct platform_device *ofdev)
 {
+	struct qe_udc *udc = dev_get_drvdata(&ofdev->dev);
 	struct qe_ep *ep;
 	unsigned int size;
-
 	DECLARE_COMPLETION(done);
 
-	if (!udc_controller)
-		return -ENODEV;
+	usb_del_gadget_udc(&udc->gadget);
 
-	usb_del_gadget_udc(&udc_controller->gadget);
+	udc->done = &done;
+	tasklet_disable(&udc->rx_tasklet);
 
-	udc_controller->done = &done;
-	tasklet_disable(&udc_controller->rx_tasklet);
-
-	if (udc_controller->nullmap) {
-		dma_unmap_single(udc_controller->gadget.dev.parent,
-			udc_controller->nullp, 256,
+	if (udc->nullmap) {
+		dma_unmap_single(udc->gadget.dev.parent,
+			udc->nullp, 256,
 				DMA_TO_DEVICE);
-			udc_controller->nullp = DMA_ADDR_INVALID;
+			udc->nullp = DMA_ADDR_INVALID;
 	} else {
-		dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
-			udc_controller->nullp, 256,
+		dma_sync_single_for_cpu(udc->gadget.dev.parent,
+			udc->nullp, 256,
 				DMA_TO_DEVICE);
 	}
-	kfree(udc_controller->statusbuf);
-	kfree(udc_controller->nullbuf);
+	kfree(udc->statusbuf);
+	kfree(udc->nullbuf);
 
-	ep = &udc_controller->eps[0];
+	ep = &udc->eps[0];
 	cpm_muram_free(cpm_muram_offset(ep->rxbase));
 	size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (USB_BDRING_LEN + 1);
 
 	kfree(ep->rxframe);
 	if (ep->rxbufmap) {
-		dma_unmap_single(udc_controller->gadget.dev.parent,
+		dma_unmap_single(udc->gadget.dev.parent,
 				ep->rxbuf_d, size,
 				DMA_FROM_DEVICE);
 		ep->rxbuf_d = DMA_ADDR_INVALID;
 	} else {
-		dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
+		dma_sync_single_for_cpu(udc->gadget.dev.parent,
 				ep->rxbuf_d, size,
 				DMA_FROM_DEVICE);
 	}
@@ -2768,14 +2695,14 @@
 	kfree(ep->rxbuffer);
 	kfree(ep->txframe);
 
-	free_irq(udc_controller->usb_irq, udc_controller);
-	irq_dispose_mapping(udc_controller->usb_irq);
+	free_irq(udc->usb_irq, udc);
+	irq_dispose_mapping(udc->usb_irq);
 
-	tasklet_kill(&udc_controller->rx_tasklet);
+	tasklet_kill(&udc->rx_tasklet);
 
-	iounmap(udc_controller->usb_regs);
+	iounmap(udc->usb_regs);
 
-	device_unregister(&udc_controller->gadget.dev);
+	device_unregister(&udc->gadget.dev);
 	/* wait for release() of gadget.dev to free udc */
 	wait_for_completion(&done);
 
diff --git a/drivers/usb/gadget/fsl_qe_udc.h b/drivers/usb/gadget/fsl_qe_udc.h
index 1da5fb0..4c07ca9 100644
--- a/drivers/usb/gadget/fsl_qe_udc.h
+++ b/drivers/usb/gadget/fsl_qe_udc.h
@@ -266,7 +266,6 @@
 	struct usb_ep ep;
 	struct list_head queue;
 	struct qe_udc *udc;
-	const struct usb_endpoint_descriptor *desc;
 	struct usb_gadget *gadget;
 
 	u8 state;
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 55abfb6..2831685 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2004-2007,2011-2012 Freescale Semiconductor, Inc.
  * All rights reserved.
  *
  * Author: Li Yang <leoli@freescale.com>
@@ -58,9 +58,8 @@
 static const char driver_desc[] = DRIVER_DESC;
 
 static struct usb_dr_device *dr_regs;
-#ifndef CONFIG_ARCH_MXC
+
 static struct usb_sys_interface *usb_sys_regs;
-#endif
 
 /* it is initialized in probe()  */
 static struct fsl_udc *udc_controller = NULL;
@@ -244,10 +243,9 @@
 {
 	unsigned int tmp, portctrl, ep_num;
 	unsigned int max_no_of_ep;
-#ifndef CONFIG_ARCH_MXC
 	unsigned int ctrl;
-#endif
 	unsigned long timeout;
+
 #define FSL_UDC_RESET_TIMEOUT 1000
 
 	/* Config PHY interface */
@@ -255,12 +253,32 @@
 	portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
 	switch (udc->phy_mode) {
 	case FSL_USB2_PHY_ULPI:
+		if (udc->pdata->have_sysif_regs) {
+			if (udc->pdata->controller_ver) {
+				/* controller version 1.6 or above */
+				ctrl = __raw_readl(&usb_sys_regs->control);
+				ctrl &= ~USB_CTRL_UTMI_PHY_EN;
+				ctrl |= USB_CTRL_USB_EN;
+				__raw_writel(ctrl, &usb_sys_regs->control);
+			}
+		}
 		portctrl |= PORTSCX_PTS_ULPI;
 		break;
 	case FSL_USB2_PHY_UTMI_WIDE:
 		portctrl |= PORTSCX_PTW_16BIT;
 		/* fall through */
 	case FSL_USB2_PHY_UTMI:
+		if (udc->pdata->have_sysif_regs) {
+			if (udc->pdata->controller_ver) {
+				/* controller version 1.6 or above */
+				ctrl = __raw_readl(&usb_sys_regs->control);
+				ctrl |= (USB_CTRL_UTMI_PHY_EN |
+					USB_CTRL_USB_EN);
+				__raw_writel(ctrl, &usb_sys_regs->control);
+				mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI
+					PHY CLK to become stable - 10ms*/
+			}
+		}
 		portctrl |= PORTSCX_PTS_UTMI;
 		break;
 	case FSL_USB2_PHY_SERIAL:
@@ -549,7 +567,7 @@
 	ep = container_of(_ep, struct fsl_ep, ep);
 
 	/* catch various bogus parameters */
-	if (!_ep || !desc || ep->desc
+	if (!_ep || !desc || ep->ep.desc
 			|| (desc->bDescriptorType != USB_DT_ENDPOINT))
 		return -EINVAL;
 
@@ -590,7 +608,7 @@
 
 	spin_lock_irqsave(&udc->lock, flags);
 	ep->ep.maxpacket = max;
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	ep->stopped = 0;
 
 	/* Controller related setup */
@@ -614,7 +632,7 @@
 	retval = 0;
 
 	VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name,
-			ep->desc->bEndpointAddress & 0x0f,
+			ep->ep.desc->bEndpointAddress & 0x0f,
 			(desc->bEndpointAddress & USB_DIR_IN)
 				? "in" : "out", max);
 en_done:
@@ -634,7 +652,7 @@
 	int ep_num;
 
 	ep = container_of(_ep, struct fsl_ep, ep);
-	if (!_ep || !ep->desc) {
+	if (!_ep || !ep->ep.desc) {
 		VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
 		return -EINVAL;
 	}
@@ -657,7 +675,6 @@
 	/* nuke all pending requests (does flush) */
 	nuke(ep, -ESHUTDOWN);
 
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	ep->stopped = 1;
 	spin_unlock_irqrestore(&udc->lock, flags);
@@ -736,6 +753,8 @@
 		lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
 		lastreq->tail->next_td_ptr =
 			cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
+		/* Ensure dTD's next dtd pointer to be updated */
+		wmb();
 		/* Read prime bit, if 1 goto done */
 		if (fsl_readl(&dr_regs->endpointprime) & bitmask)
 			return;
@@ -874,11 +893,11 @@
 		VDBG("%s, bad params", __func__);
 		return -EINVAL;
 	}
-	if (unlikely(!_ep || !ep->desc)) {
+	if (unlikely(!_ep || !ep->ep.desc)) {
 		VDBG("%s, bad ep", __func__);
 		return -EINVAL;
 	}
-	if (usb_endpoint_xfer_isoc(ep->desc)) {
+	if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
 		if (req->req.length > ep->ep.maxpacket)
 			return -EMSGSIZE;
 	}
@@ -1017,12 +1036,12 @@
 
 	ep = container_of(_ep, struct fsl_ep, ep);
 	udc = ep->udc;
-	if (!_ep || !ep->desc) {
+	if (!_ep || !ep->ep.desc) {
 		status = -EINVAL;
 		goto out;
 	}
 
-	if (usb_endpoint_xfer_isoc(ep->desc)) {
+	if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
 		status = -EOPNOTSUPP;
 		goto out;
 	}
@@ -1061,7 +1080,7 @@
 	struct ep_queue_head *qh;
 
 	ep = container_of(_ep, struct fsl_ep, ep);
-	if (!_ep || (!ep->desc && ep_index(ep) != 0))
+	if (!_ep || (!ep->ep.desc && ep_index(ep) != 0))
 		return -ENODEV;
 
 	udc = (struct fsl_udc *)ep->udc;
@@ -1094,7 +1113,7 @@
 		return;
 	} else {
 		ep = container_of(_ep, struct fsl_ep, ep);
-		if (!ep->desc)
+		if (!ep->ep.desc)
 			return;
 	}
 	ep_num = ep_index(ep);
@@ -1349,7 +1368,7 @@
 		target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index));
 
 		/* stall if endpoint doesn't exist */
-		if (!target_ep->desc)
+		if (!target_ep->ep.desc)
 			goto stall;
 		tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep))
 				<< USB_ENDPOINT_HALT;
@@ -2259,7 +2278,7 @@
 	}
 	/* other gadget->eplist ep */
 	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
-		if (ep->desc) {
+		if (ep->ep.desc) {
 			t = scnprintf(next, size,
 					"\nFor %s Maxpkt is 0x%x "
 					"index is 0x%x\n",
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index e651469..5cd7b7e 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -1,4 +1,12 @@
 /*
+ * Copyright (C) 2004,2012 Freescale Semiconductor, Inc
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
  * Freescale USB device/endpoint management registers
  */
 #ifndef __FSL_USB2_UDC_H
@@ -348,6 +356,9 @@
 /* control Register Bit Masks */
 #define  USB_CTRL_IOENB                       0x00000004
 #define  USB_CTRL_ULPI_INT0EN                 0x00000001
+#define USB_CTRL_UTMI_PHY_EN		      0x00000200
+#define USB_CTRL_USB_EN			      0x00000004
+#define USB_CTRL_ULPI_PHY_CLK_SEL	      0x00000400
 
 /* Endpoint Queue Head data struct
  * Rem: all the variables of qh are LittleEndian Mode
@@ -450,7 +461,6 @@
 	struct list_head queue;
 	struct fsl_udc *udc;
 	struct ep_queue_head *qh;
-	const struct usb_endpoint_descriptor *desc;
 	struct usb_gadget *gadget;
 
 	char name[14];
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index 5831cb4..cdd9454 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -203,7 +203,7 @@
 	struct fusb300 *fusb300 = ep->fusb300;
 	struct fusb300_ep_info info;
 
-	ep->desc = desc;
+	ep->ep.desc = desc;
 
 	info.interval = 0;
 	info.addrofs = 0;
@@ -443,7 +443,7 @@
 	req->req.actual = 0;
 	req->req.status = -EINPROGRESS;
 
-	if (ep->desc == NULL) /* ep0 */
+	if (ep->ep.desc == NULL) /* ep0 */
 		ep0_queue(ep, req);
 	else if (request && !ep->stall)
 		enable_fifo_int(ep);
diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h
index 92745bd..542cd83 100644
--- a/drivers/usb/gadget/fusb300_udc.h
+++ b/drivers/usb/gadget/fusb300_udc.h
@@ -650,7 +650,6 @@
 
 	unsigned char		epnum;
 	unsigned char		type;
-	const struct usb_endpoint_descriptor	*desc;
 };
 
 struct fusb300 {
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index a85eaf4..d3ace90 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -67,6 +67,15 @@
 #define GFS_VENDOR_ID	0x1d6b	/* Linux Foundation */
 #define GFS_PRODUCT_ID	0x0105	/* FunctionFS Gadget */
 
+#define GFS_MAX_DEVS	10
+
+struct gfs_ffs_obj {
+	const char *name;
+	bool mounted;
+	bool desc_ready;
+	struct ffs_data *ffs_data;
+};
+
 static struct usb_device_descriptor gfs_dev_desc = {
 	.bLength		= sizeof gfs_dev_desc,
 	.bDescriptorType	= USB_DT_DEVICE,
@@ -78,12 +87,17 @@
 	.idProduct		= cpu_to_le16(GFS_PRODUCT_ID),
 };
 
+static char *func_names[GFS_MAX_DEVS];
+static unsigned int func_num;
+
 module_param_named(bDeviceClass,    gfs_dev_desc.bDeviceClass,    byte,   0644);
 MODULE_PARM_DESC(bDeviceClass, "USB Device class");
 module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte,   0644);
 MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
 module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte,   0644);
 MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
+module_param_array_named(functions, func_names, charp, &func_num, 0);
+MODULE_PARM_DESC(functions, "USB Functions list");
 
 static const struct usb_descriptor_header *gfs_otg_desc[] = {
 	(const struct usb_descriptor_header *)
@@ -158,13 +172,34 @@
 	.iProduct	= DRIVER_DESC,
 };
 
-static struct ffs_data *gfs_ffs_data;
-static unsigned long gfs_registered;
+static DEFINE_MUTEX(gfs_lock);
+static unsigned int missing_funcs;
+static bool gfs_ether_setup;
+static bool gfs_registered;
+static bool gfs_single_func;
+static struct gfs_ffs_obj *ffs_tab;
 
 static int __init gfs_init(void)
 {
+	int i;
+
 	ENTER();
 
+	if (!func_num) {
+		gfs_single_func = true;
+		func_num = 1;
+	}
+
+	ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL);
+	if (!ffs_tab)
+		return -ENOMEM;
+
+	if (!gfs_single_func)
+		for (i = 0; i < func_num; i++)
+			ffs_tab[i].name = func_names[i];
+
+	missing_funcs = func_num;
+
 	return functionfs_init();
 }
 module_init(gfs_init);
@@ -172,63 +207,165 @@
 static void __exit gfs_exit(void)
 {
 	ENTER();
+	mutex_lock(&gfs_lock);
 
-	if (test_and_clear_bit(0, &gfs_registered))
+	if (gfs_registered)
 		usb_composite_unregister(&gfs_driver);
+	gfs_registered = false;
 
 	functionfs_cleanup();
+
+	mutex_unlock(&gfs_lock);
+	kfree(ffs_tab);
 }
 module_exit(gfs_exit);
 
-static int functionfs_ready_callback(struct ffs_data *ffs)
+static struct gfs_ffs_obj *gfs_find_dev(const char *dev_name)
 {
-	int ret;
+	int i;
 
 	ENTER();
 
-	if (WARN_ON(test_and_set_bit(0, &gfs_registered)))
-		return -EBUSY;
+	if (gfs_single_func)
+		return &ffs_tab[0];
 
-	gfs_ffs_data = ffs;
+	for (i = 0; i < func_num; i++)
+		if (strcmp(ffs_tab[i].name, dev_name) == 0)
+			return &ffs_tab[i];
+
+	return NULL;
+}
+
+static int functionfs_ready_callback(struct ffs_data *ffs)
+{
+	struct gfs_ffs_obj *ffs_obj;
+	int ret;
+
+	ENTER();
+	mutex_lock(&gfs_lock);
+
+	ffs_obj = ffs->private_data;
+	if (!ffs_obj) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (WARN_ON(ffs_obj->desc_ready)) {
+		ret = -EBUSY;
+		goto done;
+	}
+	ffs_obj->desc_ready = true;
+	ffs_obj->ffs_data = ffs;
+
+	if (--missing_funcs) {
+		ret = 0;
+		goto done;
+	}
+
+	if (gfs_registered) {
+		ret = -EBUSY;
+		goto done;
+	}
+	gfs_registered = true;
+
 	ret = usb_composite_probe(&gfs_driver, gfs_bind);
 	if (unlikely(ret < 0))
-		clear_bit(0, &gfs_registered);
+		gfs_registered = false;
+
+done:
+	mutex_unlock(&gfs_lock);
 	return ret;
 }
 
 static void functionfs_closed_callback(struct ffs_data *ffs)
 {
+	struct gfs_ffs_obj *ffs_obj;
+
 	ENTER();
+	mutex_lock(&gfs_lock);
 
-	if (test_and_clear_bit(0, &gfs_registered))
+	ffs_obj = ffs->private_data;
+	if (!ffs_obj)
+		goto done;
+
+	ffs_obj->desc_ready = false;
+	missing_funcs++;
+
+	if (gfs_registered)
 		usb_composite_unregister(&gfs_driver);
+	gfs_registered = false;
+
+done:
+	mutex_unlock(&gfs_lock);
 }
 
-static int functionfs_check_dev_callback(const char *dev_name)
+static void *functionfs_acquire_dev_callback(const char *dev_name)
 {
-	return 0;
+	struct gfs_ffs_obj *ffs_dev;
+
+	ENTER();
+	mutex_lock(&gfs_lock);
+
+	ffs_dev = gfs_find_dev(dev_name);
+	if (!ffs_dev) {
+		ffs_dev = ERR_PTR(-ENODEV);
+		goto done;
+	}
+
+	if (ffs_dev->mounted) {
+		ffs_dev = ERR_PTR(-EBUSY);
+		goto done;
+	}
+	ffs_dev->mounted = true;
+
+done:
+	mutex_unlock(&gfs_lock);
+	return ffs_dev;
 }
 
+static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
+{
+	struct gfs_ffs_obj *ffs_dev;
+
+	ENTER();
+	mutex_lock(&gfs_lock);
+
+	ffs_dev = ffs_data->private_data;
+	if (ffs_dev)
+		ffs_dev->mounted = false;
+
+	mutex_unlock(&gfs_lock);
+}
+
+/*
+ * It is assumed that gfs_bind is called from a context where gfs_lock is held
+ */
 static int gfs_bind(struct usb_composite_dev *cdev)
 {
 	int ret, i;
 
 	ENTER();
 
-	if (WARN_ON(!gfs_ffs_data))
+	if (missing_funcs)
 		return -ENODEV;
 
 	ret = gether_setup(cdev->gadget, gfs_hostaddr);
 	if (unlikely(ret < 0))
 		goto error_quick;
+	gfs_ether_setup = true;
 
 	ret = usb_string_ids_tab(cdev, gfs_strings);
 	if (unlikely(ret < 0))
 		goto error;
 
-	ret = functionfs_bind(gfs_ffs_data, cdev);
-	if (unlikely(ret < 0))
-		goto error;
+	for (i = func_num; --i; ) {
+		ret = functionfs_bind(ffs_tab[i].ffs_data, cdev);
+		if (unlikely(ret < 0)) {
+			while (++i < func_num)
+				functionfs_unbind(ffs_tab[i].ffs_data);
+			goto error;
+		}
+	}
 
 	for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
 		struct gfs_configuration *c = gfs_configurations + i;
@@ -246,16 +383,22 @@
 	return 0;
 
 error_unbind:
-	functionfs_unbind(gfs_ffs_data);
+	for (i = 0; i < func_num; i++)
+		functionfs_unbind(ffs_tab[i].ffs_data);
 error:
 	gether_cleanup();
 error_quick:
-	gfs_ffs_data = NULL;
+	gfs_ether_setup = false;
 	return ret;
 }
 
+/*
+ * It is assumed that gfs_unbind is called from a context where gfs_lock is held
+ */
 static int gfs_unbind(struct usb_composite_dev *cdev)
 {
+	int i;
+
 	ENTER();
 
 	/*
@@ -266,22 +409,29 @@
 	 * from composite on orror recovery, but what you're gonna
 	 * do...?
 	 */
-	if (gfs_ffs_data) {
+	if (gfs_ether_setup)
 		gether_cleanup();
-		functionfs_unbind(gfs_ffs_data);
-		gfs_ffs_data = NULL;
-	}
+	gfs_ether_setup = false;
+
+	for (i = func_num; --i; )
+		if (ffs_tab[i].ffs_data)
+			functionfs_unbind(ffs_tab[i].ffs_data);
 
 	return 0;
 }
 
+/*
+ * It is assumed that gfs_do_config is called from a context where
+ * gfs_lock is held
+ */
 static int gfs_do_config(struct usb_configuration *c)
 {
 	struct gfs_configuration *gc =
 		container_of(c, struct gfs_configuration, c);
+	int i;
 	int ret;
 
-	if (WARN_ON(!gfs_ffs_data))
+	if (missing_funcs)
 		return -ENODEV;
 
 	if (gadget_is_otg(c->cdev->gadget)) {
@@ -295,9 +445,11 @@
 			return ret;
 	}
 
-	ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data);
-	if (unlikely(ret < 0))
-		return ret;
+	for (i = 0; i < func_num; i++) {
+		ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data);
+		if (unlikely(ret < 0))
+			return ret;
+	}
 
 	/*
 	 * After previous do_configs there may be some invalid
diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h
index e84b3c4..71ca193 100644
--- a/drivers/usb/gadget/g_zero.h
+++ b/drivers/usb/gadget/g_zero.h
@@ -13,10 +13,11 @@
 extern const struct usb_descriptor_header *otg_desc[];
 
 /* common utilities */
-struct usb_request *alloc_ep_req(struct usb_ep *ep);
+struct usb_request *alloc_ep_req(struct usb_ep *ep, int len);
 void free_ep_req(struct usb_ep *ep, struct usb_request *req);
 void disable_endpoints(struct usb_composite_dev *cdev,
-		struct usb_ep *in, struct usb_ep *out);
+		struct usb_ep *in, struct usb_ep *out,
+		struct usb_ep *iso_in, struct usb_ep *iso_out);
 
 /* configuration-specific linkup */
 int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume);
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index a8855d0..b8b3a34 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -37,6 +37,7 @@
 #define gadget_is_goku(g)		(!strcmp("goku_udc", (g)->name))
 #define gadget_is_imx(g)		(!strcmp("imx_udc", (g)->name))
 #define gadget_is_langwell(g)		(!strcmp("langwell_udc", (g)->name))
+#define gadget_is_lpc32xx(g)		(!strcmp("lpc32xx_udc", (g)->name))
 #define gadget_is_m66592(g)		(!strcmp("m66592_udc", (g)->name))
 #define gadget_is_musbhdrc(g)		(!strcmp("musb-hdrc", (g)->name))
 #define gadget_is_net2272(g)		(!strcmp("net2272", (g)->name))
@@ -118,6 +119,8 @@
 		return 0x31;
 	else if (gadget_is_dwc3(gadget))
 		return 0x32;
+	else if (gadget_is_lpc32xx(gadget))
+		return 0x33;
 
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index e151d6b..b241e6c 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -102,7 +102,7 @@
 	unsigned long	flags;
 
 	ep = container_of(_ep, struct goku_ep, ep);
-	if (!_ep || !desc || ep->desc
+	if (!_ep || !desc || ep->ep.desc
 			|| desc->bDescriptorType != USB_DT_ENDPOINT)
 		return -EINVAL;
 	dev = ep->dev;
@@ -176,7 +176,7 @@
 	command(ep->dev->regs, COMMAND_RESET, ep->num);
 	ep->ep.maxpacket = max;
 	ep->stopped = 0;
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	spin_unlock_irqrestore(&ep->dev->lock, flags);
 
 	DBG(dev, "enable %s %s %s maxpacket %u\n", ep->ep.name,
@@ -233,7 +233,6 @@
 	}
 
 	ep->ep.maxpacket = MAX_FIFO_SIZE;
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	ep->stopped = 1;
 	ep->irqs = 0;
@@ -247,7 +246,7 @@
 	unsigned long	flags;
 
 	ep = container_of(_ep, struct goku_ep, ep);
-	if (!_ep || !ep->desc)
+	if (!_ep || !ep->ep.desc)
 		return -ENODEV;
 	dev = ep->dev;
 	if (dev->ep0state == EP0_SUSPEND)
@@ -722,7 +721,7 @@
 			|| !_req->buf || !list_empty(&req->queue)))
 		return -EINVAL;
 	ep = container_of(_ep, struct goku_ep, ep);
-	if (unlikely(!_ep || (!ep->desc && ep->num != 0)))
+	if (unlikely(!_ep || (!ep->ep.desc && ep->num != 0)))
 		return -EINVAL;
 	dev = ep->dev;
 	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
@@ -815,7 +814,7 @@
 	unsigned long		flags;
 
 	ep = container_of(_ep, struct goku_ep, ep);
-	if (!_ep || !_req || (!ep->desc && ep->num != 0))
+	if (!_ep || !_req || (!ep->ep.desc && ep->num != 0))
 		return -EINVAL;
 	dev = ep->dev;
 	if (!dev->driver)
@@ -896,7 +895,7 @@
 			return -EINVAL;
 
 	/* don't change EPxSTATUS_EP_INVALID to READY */
-	} else if (!ep->desc) {
+	} else if (!ep->ep.desc) {
 		DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name);
 		return -EINVAL;
 	}
@@ -955,7 +954,7 @@
 	VDBG(ep->dev, "%s %s\n", __func__, ep->ep.name);
 
 	/* don't change EPxSTATUS_EP_INVALID to READY */
-	if (!ep->desc && ep->num != 0) {
+	if (!ep->ep.desc && ep->num != 0) {
 		DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name);
 		return;
 	}
@@ -1152,7 +1151,7 @@
 		struct goku_ep		*ep = &dev->ep [i];
 		struct goku_request	*req;
 
-		if (i && !ep->desc)
+		if (i && !ep->ep.desc)
 			continue;
 
 		tmp = readl(ep->reg_status);
@@ -1473,7 +1472,8 @@
 			case USB_RECIP_ENDPOINT:
 				tmp = le16_to_cpu(ctrl.wIndex) & 0x0f;
 				/* active endpoint */
-				if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))
+				if (tmp > 3 ||
+				    (!dev->ep[tmp].ep.desc && tmp != 0))
 					goto stall;
 				if (ctrl.wIndex & cpu_to_le16(
 						USB_DIR_IN)) {
@@ -1895,14 +1895,4 @@
 	/* FIXME add power management support */
 };
 
-static int __init init (void)
-{
-	return pci_register_driver (&goku_pci_driver);
-}
-module_init (init);
-
-static void __exit cleanup (void)
-{
-	pci_unregister_driver (&goku_pci_driver);
-}
-module_exit (cleanup);
+module_pci_driver(goku_pci_driver);
diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
index e7e0c69..85cdce0 100644
--- a/drivers/usb/gadget/goku_udc.h
+++ b/drivers/usb/gadget/goku_udc.h
@@ -216,7 +216,6 @@
 
 	/* analogous to a host-side qh */
 	struct list_head			queue;
-	const struct usb_endpoint_descriptor	*desc;
 
 	u32 __iomem				*reg_fifo;
 	u32 __iomem				*reg_mode;
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index 8d1c75a..54034f8 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1237,14 +1237,15 @@
  *******************************************************************************
  */
 
-static int imx_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int imx_udc_stop(struct usb_gadget_driver *driver);
+static int imx_udc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
+static int imx_udc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops imx_udc_ops = {
-	.get_frame	 = imx_udc_get_frame,
-	.wakeup		 = imx_udc_wakeup,
-	.start		= imx_udc_start,
-	.stop		= imx_udc_stop,
+	.get_frame	= imx_udc_get_frame,
+	.wakeup		= imx_udc_wakeup,
+	.udc_start	= imx_udc_start,
+	.udc_stop	= imx_udc_stop,
 };
 
 static struct imx_udc_struct controller = {
@@ -1329,23 +1330,13 @@
  * USB gadget driver functions
  *******************************************************************************
  */
-static int imx_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int imx_udc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct imx_udc_struct *imx_usb = &controller;
+	struct imx_udc_struct *imx_usb;
 	int retval;
 
-	if (!driver
-		|| driver->max_speed < USB_SPEED_FULL
-		|| !bind
-		|| !driver->disconnect
-		|| !driver->setup)
-			return -EINVAL;
-	if (!imx_usb)
-		return -ENODEV;
-	if (imx_usb->driver)
-		return -EBUSY;
-
+	imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
 	/* first hook up the driver ... */
 	imx_usb->driver = driver;
 	imx_usb->gadget.dev.driver = &driver->driver;
@@ -1353,14 +1344,6 @@
 	retval = device_add(&imx_usb->gadget.dev);
 	if (retval)
 		goto fail;
-	retval = bind(&imx_usb->gadget);
-	if (retval) {
-		D_ERR(imx_usb->dev, "<%s> bind to driver %s --> error %d\n",
-			__func__, driver->driver.name, retval);
-		device_del(&imx_usb->gadget.dev);
-
-		goto fail;
-	}
 
 	D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
 		__func__, driver->driver.name);
@@ -1374,20 +1357,16 @@
 	return retval;
 }
 
-static int imx_udc_stop(struct usb_gadget_driver *driver)
+static int imx_udc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct imx_udc_struct *imx_usb = &controller;
-
-	if (!imx_usb)
-		return -ENODEV;
-	if (!driver || driver != imx_usb->driver || !driver->unbind)
-		return -EINVAL;
+	struct imx_udc_struct *imx_usb = container_of(gadget,
+			struct imx_udc_struct, gadget);
 
 	udc_stop_activity(imx_usb, driver);
 	imx_udc_disable(imx_usb);
 	del_timer(&imx_usb->timer);
 
-	driver->unbind(&imx_usb->gadget);
 	imx_usb->gadget.dev.driver = NULL;
 	imx_usb->driver = NULL;
 
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
deleted file mode 100644
index f9cedd5..0000000
--- a/drivers/usb/gadget/langwell_udc.c
+++ /dev/null
@@ -1,3434 +0,0 @@
-/*
- * Intel Langwell USB Device Controller driver
- * Copyright (C) 2008-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.
- */
-
-
-/* #undef	DEBUG */
-/* #undef	VERBOSE_DEBUG */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-#include <linux/pm.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <asm/unaligned.h>
-
-#include "langwell_udc.h"
-
-
-#define	DRIVER_DESC		"Intel Langwell USB Device Controller driver"
-#define	DRIVER_VERSION		"16 May 2009"
-
-static const char driver_name[] = "langwell_udc";
-static const char driver_desc[] = DRIVER_DESC;
-
-
-/* for endpoint 0 operations */
-static const struct usb_endpoint_descriptor
-langwell_ep0_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	0,
-	.bmAttributes =		USB_ENDPOINT_XFER_CONTROL,
-	.wMaxPacketSize =	EP0_MAX_PKT_SIZE,
-};
-
-
-/*-------------------------------------------------------------------------*/
-/* debugging */
-
-#ifdef	VERBOSE_DEBUG
-static inline void print_all_registers(struct langwell_udc *dev)
-{
-	int	i;
-
-	/* Capability Registers */
-	dev_dbg(&dev->pdev->dev,
-		"Capability Registers (offset: 0x%04x, length: 0x%08x)\n",
-		CAP_REG_OFFSET, (u32)sizeof(struct langwell_cap_regs));
-	dev_dbg(&dev->pdev->dev, "caplength=0x%02x\n",
-			readb(&dev->cap_regs->caplength));
-	dev_dbg(&dev->pdev->dev, "hciversion=0x%04x\n",
-			readw(&dev->cap_regs->hciversion));
-	dev_dbg(&dev->pdev->dev, "hcsparams=0x%08x\n",
-			readl(&dev->cap_regs->hcsparams));
-	dev_dbg(&dev->pdev->dev, "hccparams=0x%08x\n",
-			readl(&dev->cap_regs->hccparams));
-	dev_dbg(&dev->pdev->dev, "dciversion=0x%04x\n",
-			readw(&dev->cap_regs->dciversion));
-	dev_dbg(&dev->pdev->dev, "dccparams=0x%08x\n",
-			readl(&dev->cap_regs->dccparams));
-
-	/* Operational Registers */
-	dev_dbg(&dev->pdev->dev,
-		"Operational Registers (offset: 0x%04x, length: 0x%08x)\n",
-		OP_REG_OFFSET, (u32)sizeof(struct langwell_op_regs));
-	dev_dbg(&dev->pdev->dev, "extsts=0x%08x\n",
-			readl(&dev->op_regs->extsts));
-	dev_dbg(&dev->pdev->dev, "extintr=0x%08x\n",
-			readl(&dev->op_regs->extintr));
-	dev_dbg(&dev->pdev->dev, "usbcmd=0x%08x\n",
-			readl(&dev->op_regs->usbcmd));
-	dev_dbg(&dev->pdev->dev, "usbsts=0x%08x\n",
-			readl(&dev->op_regs->usbsts));
-	dev_dbg(&dev->pdev->dev, "usbintr=0x%08x\n",
-			readl(&dev->op_regs->usbintr));
-	dev_dbg(&dev->pdev->dev, "frindex=0x%08x\n",
-			readl(&dev->op_regs->frindex));
-	dev_dbg(&dev->pdev->dev, "ctrldssegment=0x%08x\n",
-			readl(&dev->op_regs->ctrldssegment));
-	dev_dbg(&dev->pdev->dev, "deviceaddr=0x%08x\n",
-			readl(&dev->op_regs->deviceaddr));
-	dev_dbg(&dev->pdev->dev, "endpointlistaddr=0x%08x\n",
-			readl(&dev->op_regs->endpointlistaddr));
-	dev_dbg(&dev->pdev->dev, "ttctrl=0x%08x\n",
-			readl(&dev->op_regs->ttctrl));
-	dev_dbg(&dev->pdev->dev, "burstsize=0x%08x\n",
-			readl(&dev->op_regs->burstsize));
-	dev_dbg(&dev->pdev->dev, "txfilltuning=0x%08x\n",
-			readl(&dev->op_regs->txfilltuning));
-	dev_dbg(&dev->pdev->dev, "txttfilltuning=0x%08x\n",
-			readl(&dev->op_regs->txttfilltuning));
-	dev_dbg(&dev->pdev->dev, "ic_usb=0x%08x\n",
-			readl(&dev->op_regs->ic_usb));
-	dev_dbg(&dev->pdev->dev, "ulpi_viewport=0x%08x\n",
-			readl(&dev->op_regs->ulpi_viewport));
-	dev_dbg(&dev->pdev->dev, "configflag=0x%08x\n",
-			readl(&dev->op_regs->configflag));
-	dev_dbg(&dev->pdev->dev, "portsc1=0x%08x\n",
-			readl(&dev->op_regs->portsc1));
-	dev_dbg(&dev->pdev->dev, "devlc=0x%08x\n",
-			readl(&dev->op_regs->devlc));
-	dev_dbg(&dev->pdev->dev, "otgsc=0x%08x\n",
-			readl(&dev->op_regs->otgsc));
-	dev_dbg(&dev->pdev->dev, "usbmode=0x%08x\n",
-			readl(&dev->op_regs->usbmode));
-	dev_dbg(&dev->pdev->dev, "endptnak=0x%08x\n",
-			readl(&dev->op_regs->endptnak));
-	dev_dbg(&dev->pdev->dev, "endptnaken=0x%08x\n",
-			readl(&dev->op_regs->endptnaken));
-	dev_dbg(&dev->pdev->dev, "endptsetupstat=0x%08x\n",
-			readl(&dev->op_regs->endptsetupstat));
-	dev_dbg(&dev->pdev->dev, "endptprime=0x%08x\n",
-			readl(&dev->op_regs->endptprime));
-	dev_dbg(&dev->pdev->dev, "endptflush=0x%08x\n",
-			readl(&dev->op_regs->endptflush));
-	dev_dbg(&dev->pdev->dev, "endptstat=0x%08x\n",
-			readl(&dev->op_regs->endptstat));
-	dev_dbg(&dev->pdev->dev, "endptcomplete=0x%08x\n",
-			readl(&dev->op_regs->endptcomplete));
-
-	for (i = 0; i < dev->ep_max / 2; i++) {
-		dev_dbg(&dev->pdev->dev, "endptctrl[%d]=0x%08x\n",
-				i, readl(&dev->op_regs->endptctrl[i]));
-	}
-}
-#else
-
-#define	print_all_registers(dev)	do { } while (0)
-
-#endif /* VERBOSE_DEBUG */
-
-
-/*-------------------------------------------------------------------------*/
-
-#define	is_in(ep)	(((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir ==	\
-			USB_DIR_IN) : (usb_endpoint_dir_in((ep)->desc)))
-
-#define	DIR_STRING(ep)	(is_in(ep) ? "in" : "out")
-
-
-static char *type_string(const struct usb_endpoint_descriptor *desc)
-{
-	switch (usb_endpoint_type(desc)) {
-	case USB_ENDPOINT_XFER_BULK:
-		return "bulk";
-	case USB_ENDPOINT_XFER_ISOC:
-		return "iso";
-	case USB_ENDPOINT_XFER_INT:
-		return "int";
-	};
-
-	return "control";
-}
-
-
-/* configure endpoint control registers */
-static void ep_reset(struct langwell_ep *ep, unsigned char ep_num,
-		unsigned char is_in, unsigned char ep_type)
-{
-	struct langwell_udc	*dev;
-	u32			endptctrl;
-
-	dev = ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
-	if (is_in) {	/* TX */
-		if (ep_num)
-			endptctrl |= EPCTRL_TXR;
-		endptctrl |= EPCTRL_TXE;
-		endptctrl |= ep_type << EPCTRL_TXT_SHIFT;
-	} else {	/* RX */
-		if (ep_num)
-			endptctrl |= EPCTRL_RXR;
-		endptctrl |= EPCTRL_RXE;
-		endptctrl |= ep_type << EPCTRL_RXT_SHIFT;
-	}
-
-	writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* reset ep0 dQH and endptctrl */
-static void ep0_reset(struct langwell_udc *dev)
-{
-	struct langwell_ep	*ep;
-	int			i;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* ep0 in and out */
-	for (i = 0; i < 2; i++) {
-		ep = &dev->ep[i];
-		ep->dev = dev;
-
-		/* ep0 dQH */
-		ep->dqh = &dev->ep_dqh[i];
-
-		/* configure ep0 endpoint capabilities in dQH */
-		ep->dqh->dqh_ios = 1;
-		ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE;
-
-		/* enable ep0-in HW zero length termination select */
-		if (is_in(ep))
-			ep->dqh->dqh_zlt = 0;
-		ep->dqh->dqh_mult = 0;
-
-		ep->dqh->dtd_next = DTD_TERM;
-
-		/* configure ep0 control registers */
-		ep_reset(&dev->ep[0], 0, i, USB_ENDPOINT_XFER_CONTROL);
-	}
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoints operations */
-
-/* configure endpoint, making it usable */
-static int langwell_ep_enable(struct usb_ep *_ep,
-		const struct usb_endpoint_descriptor *desc)
-{
-	struct langwell_udc	*dev;
-	struct langwell_ep	*ep;
-	u16			max = 0;
-	unsigned long		flags;
-	int			i, retval = 0;
-	unsigned char		zlt, ios = 0, mult = 0;
-
-	ep = container_of(_ep, struct langwell_ep, ep);
-	dev = ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (!_ep || !desc || ep->desc
-			|| desc->bDescriptorType != USB_DT_ENDPOINT)
-		return -EINVAL;
-
-	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
-		return -ESHUTDOWN;
-
-	max = usb_endpoint_maxp(desc);
-
-	/*
-	 * disable HW zero length termination select
-	 * driver handles zero length packet through req->req.zero
-	 */
-	zlt = 1;
-
-	/*
-	 * sanity check type, direction, address, and then
-	 * initialize the endpoint capabilities fields in dQH
-	 */
-	switch (usb_endpoint_type(desc)) {
-	case USB_ENDPOINT_XFER_CONTROL:
-		ios = 1;
-		break;
-	case USB_ENDPOINT_XFER_BULK:
-		if ((dev->gadget.speed == USB_SPEED_HIGH
-					&& max != 512)
-				|| (dev->gadget.speed == USB_SPEED_FULL
-					&& max > 64)) {
-			goto done;
-		}
-		break;
-	case USB_ENDPOINT_XFER_INT:
-		if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
-			goto done;
-
-		switch (dev->gadget.speed) {
-		case USB_SPEED_HIGH:
-			if (max <= 1024)
-				break;
-		case USB_SPEED_FULL:
-			if (max <= 64)
-				break;
-		default:
-			if (max <= 8)
-				break;
-			goto done;
-		}
-		break;
-	case USB_ENDPOINT_XFER_ISOC:
-		if (strstr(ep->ep.name, "-bulk")
-				|| strstr(ep->ep.name, "-int"))
-			goto done;
-
-		switch (dev->gadget.speed) {
-		case USB_SPEED_HIGH:
-			if (max <= 1024)
-				break;
-		case USB_SPEED_FULL:
-			if (max <= 1023)
-				break;
-		default:
-			goto done;
-		}
-		/*
-		 * FIXME:
-		 * calculate transactions needed for high bandwidth iso
-		 */
-		mult = (unsigned char)(1 + ((max >> 11) & 0x03));
-		max = max & 0x8ff;	/* bit 0~10 */
-		/* 3 transactions at most */
-		if (mult > 3)
-			goto done;
-		break;
-	default:
-		goto done;
-	}
-
-	spin_lock_irqsave(&dev->lock, flags);
-
-	ep->ep.maxpacket = max;
-	ep->desc = desc;
-	ep->stopped = 0;
-	ep->ep_num = usb_endpoint_num(desc);
-
-	/* ep_type */
-	ep->ep_type = usb_endpoint_type(desc);
-
-	/* configure endpoint control registers */
-	ep_reset(ep, ep->ep_num, is_in(ep), ep->ep_type);
-
-	/* configure endpoint capabilities in dQH */
-	i = ep->ep_num * 2 + is_in(ep);
-	ep->dqh = &dev->ep_dqh[i];
-	ep->dqh->dqh_ios = ios;
-	ep->dqh->dqh_mpl = cpu_to_le16(max);
-	ep->dqh->dqh_zlt = zlt;
-	ep->dqh->dqh_mult = mult;
-	ep->dqh->dtd_next = DTD_TERM;
-
-	dev_dbg(&dev->pdev->dev, "enabled %s (ep%d%s-%s), max %04x\n",
-			_ep->name,
-			ep->ep_num,
-			DIR_STRING(ep),
-			type_string(desc),
-			max);
-
-	spin_unlock_irqrestore(&dev->lock, flags);
-done:
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return retval;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* retire a request */
-static void done(struct langwell_ep *ep, struct langwell_request *req,
-		int status)
-{
-	struct langwell_udc	*dev = ep->dev;
-	unsigned		stopped = ep->stopped;
-	struct langwell_dtd	*curr_dtd, *next_dtd;
-	int			i;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* remove the req from ep->queue */
-	list_del_init(&req->queue);
-
-	if (req->req.status == -EINPROGRESS)
-		req->req.status = status;
-	else
-		status = req->req.status;
-
-	/* free dTD for the request */
-	next_dtd = req->head;
-	for (i = 0; i < req->dtd_count; i++) {
-		curr_dtd = next_dtd;
-		if (i != req->dtd_count - 1)
-			next_dtd = curr_dtd->next_dtd_virt;
-		dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma);
-	}
-
-	usb_gadget_unmap_request(&dev->gadget, &req->req, is_in(ep));
-
-	if (status != -ESHUTDOWN)
-		dev_dbg(&dev->pdev->dev,
-				"complete %s, req %p, stat %d, len %u/%u\n",
-				ep->ep.name, &req->req, status,
-				req->req.actual, req->req.length);
-
-	/* don't modify queue heads during completion callback */
-	ep->stopped = 1;
-
-	spin_unlock(&dev->lock);
-	/* complete routine from gadget driver */
-	if (req->req.complete)
-		req->req.complete(&ep->ep, &req->req);
-
-	spin_lock(&dev->lock);
-	ep->stopped = stopped;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-static void langwell_ep_fifo_flush(struct usb_ep *_ep);
-
-/* delete all endpoint requests, called with spinlock held */
-static void nuke(struct langwell_ep *ep, int status)
-{
-	/* called with spinlock held */
-	ep->stopped = 1;
-
-	/* endpoint fifo flush */
-	if (&ep->ep && ep->desc)
-		langwell_ep_fifo_flush(&ep->ep);
-
-	while (!list_empty(&ep->queue)) {
-		struct langwell_request	*req = NULL;
-		req = list_entry(ep->queue.next, struct langwell_request,
-				queue);
-		done(ep, req, status);
-	}
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoint is no longer usable */
-static int langwell_ep_disable(struct usb_ep *_ep)
-{
-	struct langwell_ep	*ep;
-	unsigned long		flags;
-	struct langwell_udc	*dev;
-	int			ep_num;
-	u32			endptctrl;
-
-	ep = container_of(_ep, struct langwell_ep, ep);
-	dev = ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (!_ep || !ep->desc)
-		return -EINVAL;
-
-	spin_lock_irqsave(&dev->lock, flags);
-
-	/* disable endpoint control register */
-	ep_num = ep->ep_num;
-	endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
-	if (is_in(ep))
-		endptctrl &= ~EPCTRL_TXE;
-	else
-		endptctrl &= ~EPCTRL_RXE;
-	writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
-	/* nuke all pending requests (does flush) */
-	nuke(ep, -ESHUTDOWN);
-
-	ep->desc = NULL;
-	ep->ep.desc = NULL;
-	ep->stopped = 1;
-
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	dev_dbg(&dev->pdev->dev, "disabled %s\n", _ep->name);
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
-	return 0;
-}
-
-
-/* allocate a request object to use with this endpoint */
-static struct usb_request *langwell_alloc_request(struct usb_ep *_ep,
-		gfp_t gfp_flags)
-{
-	struct langwell_ep	*ep;
-	struct langwell_udc	*dev;
-	struct langwell_request	*req = NULL;
-
-	if (!_ep)
-		return NULL;
-
-	ep = container_of(_ep, struct langwell_ep, ep);
-	dev = ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	req = kzalloc(sizeof(*req), gfp_flags);
-	if (!req)
-		return NULL;
-
-	req->req.dma = DMA_ADDR_INVALID;
-	INIT_LIST_HEAD(&req->queue);
-
-	dev_vdbg(&dev->pdev->dev, "alloc request for %s\n", _ep->name);
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return &req->req;
-}
-
-
-/* free a request object */
-static void langwell_free_request(struct usb_ep *_ep,
-		struct usb_request *_req)
-{
-	struct langwell_ep	*ep;
-	struct langwell_udc	*dev;
-	struct langwell_request	*req = NULL;
-
-	ep = container_of(_ep, struct langwell_ep, ep);
-	dev = ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (!_ep || !_req)
-		return;
-
-	req = container_of(_req, struct langwell_request, req);
-	WARN_ON(!list_empty(&req->queue));
-
-	if (_req)
-		kfree(req);
-
-	dev_vdbg(&dev->pdev->dev, "free request for %s\n", _ep->name);
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* queue dTD and PRIME endpoint */
-static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req)
-{
-	u32			bit_mask, usbcmd, endptstat, dtd_dma;
-	u8			dtd_status;
-	int			i;
-	struct langwell_dqh	*dqh;
-	struct langwell_udc	*dev;
-
-	dev = ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	i = ep->ep_num * 2 + is_in(ep);
-	dqh = &dev->ep_dqh[i];
-
-	if (ep->ep_num)
-		dev_vdbg(&dev->pdev->dev, "%s\n", ep->name);
-	else
-		/* ep0 */
-		dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep));
-
-	dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n",
-			i, &(dev->ep_dqh[i]));
-
-	bit_mask = is_in(ep) ?
-		(1 << (ep->ep_num + 16)) : (1 << (ep->ep_num));
-
-	dev_vdbg(&dev->pdev->dev, "bit_mask = 0x%08x\n", bit_mask);
-
-	/* check if the pipe is empty */
-	if (!(list_empty(&ep->queue))) {
-		/* add dTD to the end of linked list */
-		struct langwell_request	*lastreq;
-		lastreq = list_entry(ep->queue.prev,
-				struct langwell_request, queue);
-
-		lastreq->tail->dtd_next =
-			cpu_to_le32(req->head->dtd_dma & DTD_NEXT_MASK);
-
-		/* read prime bit, if 1 goto out */
-		if (readl(&dev->op_regs->endptprime) & bit_mask)
-			goto out;
-
-		do {
-			/* set ATDTW bit in USBCMD */
-			usbcmd = readl(&dev->op_regs->usbcmd);
-			writel(usbcmd | CMD_ATDTW, &dev->op_regs->usbcmd);
-
-			/* read correct status bit */
-			endptstat = readl(&dev->op_regs->endptstat) & bit_mask;
-
-		} while (!(readl(&dev->op_regs->usbcmd) & CMD_ATDTW));
-
-		/* write ATDTW bit to 0 */
-		usbcmd = readl(&dev->op_regs->usbcmd);
-		writel(usbcmd & ~CMD_ATDTW, &dev->op_regs->usbcmd);
-
-		if (endptstat)
-			goto out;
-	}
-
-	/* write dQH next pointer and terminate bit to 0 */
-	dtd_dma = req->head->dtd_dma & DTD_NEXT_MASK;
-	dqh->dtd_next = cpu_to_le32(dtd_dma);
-
-	/* clear active and halt bit */
-	dtd_status = (u8) ~(DTD_STS_ACTIVE | DTD_STS_HALTED);
-	dqh->dtd_status &= dtd_status;
-	dev_vdbg(&dev->pdev->dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status);
-
-	/* ensure that updates to the dQH will occur before priming */
-	wmb();
-
-	/* write 1 to endptprime register to PRIME endpoint */
-	bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << ep->ep_num);
-	dev_vdbg(&dev->pdev->dev, "endprime bit_mask = 0x%08x\n", bit_mask);
-	writel(bit_mask, &dev->op_regs->endptprime);
-out:
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-
-/* fill in the dTD structure to build a transfer descriptor */
-static struct langwell_dtd *build_dtd(struct langwell_request *req,
-		unsigned *length, dma_addr_t *dma, int *is_last)
-{
-	u32			 buf_ptr;
-	struct langwell_dtd	*dtd;
-	struct langwell_udc	*dev;
-	int			i;
-
-	dev = req->ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* the maximum transfer length, up to 16k bytes */
-	*length = min(req->req.length - req->req.actual,
-			(unsigned)DTD_MAX_TRANSFER_LENGTH);
-
-	/* create dTD dma_pool resource */
-	dtd = dma_pool_alloc(dev->dtd_pool, GFP_KERNEL, dma);
-	if (dtd == NULL)
-		return dtd;
-	dtd->dtd_dma = *dma;
-
-	/* initialize buffer page pointers */
-	buf_ptr = (u32)(req->req.dma + req->req.actual);
-	for (i = 0; i < 5; i++)
-		dtd->dtd_buf[i] = cpu_to_le32(buf_ptr + i * PAGE_SIZE);
-
-	req->req.actual += *length;
-
-	/* fill in total bytes with transfer size */
-	dtd->dtd_total = cpu_to_le16(*length);
-	dev_vdbg(&dev->pdev->dev, "dtd->dtd_total = %d\n", dtd->dtd_total);
-
-	/* set is_last flag if req->req.zero is set or not */
-	if (req->req.zero) {
-		if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
-			*is_last = 1;
-		else
-			*is_last = 0;
-	} else if (req->req.length == req->req.actual) {
-		*is_last = 1;
-	} else
-		*is_last = 0;
-
-	if (*is_last == 0)
-		dev_vdbg(&dev->pdev->dev, "multi-dtd request!\n");
-
-	/* set interrupt on complete bit for the last dTD */
-	if (*is_last && !req->req.no_interrupt)
-		dtd->dtd_ioc = 1;
-
-	/* set multiplier override 0 for non-ISO and non-TX endpoint */
-	dtd->dtd_multo = 0;
-
-	/* set the active bit of status field to 1 */
-	dtd->dtd_status = DTD_STS_ACTIVE;
-	dev_vdbg(&dev->pdev->dev, "dtd->dtd_status = 0x%02x\n",
-			dtd->dtd_status);
-
-	dev_vdbg(&dev->pdev->dev, "length = %d, dma addr= 0x%08x\n",
-			*length, (int)*dma);
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return dtd;
-}
-
-
-/* generate dTD linked list for a request */
-static int req_to_dtd(struct langwell_request *req)
-{
-	unsigned		count;
-	int			is_last, is_first = 1;
-	struct langwell_dtd	*dtd, *last_dtd = NULL;
-	struct langwell_udc	*dev;
-	dma_addr_t		dma;
-
-	dev = req->ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-	do {
-		dtd = build_dtd(req, &count, &dma, &is_last);
-		if (dtd == NULL)
-			return -ENOMEM;
-
-		if (is_first) {
-			is_first = 0;
-			req->head = dtd;
-		} else {
-			last_dtd->dtd_next = cpu_to_le32(dma);
-			last_dtd->next_dtd_virt = dtd;
-		}
-		last_dtd = dtd;
-		req->dtd_count++;
-	} while (!is_last);
-
-	/* set terminate bit to 1 for the last dTD */
-	dtd->dtd_next = DTD_TERM;
-
-	req->tail = dtd;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* queue (submits) an I/O requests to an endpoint */
-static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
-		gfp_t gfp_flags)
-{
-	struct langwell_request	*req;
-	struct langwell_ep	*ep;
-	struct langwell_udc	*dev;
-	unsigned long		flags;
-	int			is_iso = 0;
-	int			ret;
-
-	/* always require a cpu-view buffer */
-	req = container_of(_req, struct langwell_request, req);
-	ep = container_of(_ep, struct langwell_ep, ep);
-
-	if (!_req || !_req->complete || !_req->buf
-			|| !list_empty(&req->queue)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!_ep || !ep->desc))
-		return -EINVAL;
-
-	dev = ep->dev;
-	req->ep = ep;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (usb_endpoint_xfer_isoc(ep->desc)) {
-		if (req->req.length > ep->ep.maxpacket)
-			return -EMSGSIZE;
-		is_iso = 1;
-	}
-
-	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
-		return -ESHUTDOWN;
-
-	/* set up dma mapping */
-	ret = usb_gadget_map_request(&dev->gadget, &req->req, is_in(ep));
-	if (ret)
-		return ret;
-
-	dev_dbg(&dev->pdev->dev,
-			"%s queue req %p, len %u, buf %p, dma 0x%08x\n",
-			_ep->name,
-			_req, _req->length, _req->buf, (int)_req->dma);
-
-	_req->status = -EINPROGRESS;
-	_req->actual = 0;
-	req->dtd_count = 0;
-
-	spin_lock_irqsave(&dev->lock, flags);
-
-	/* build and put dTDs to endpoint queue */
-	if (!req_to_dtd(req)) {
-		queue_dtd(ep, req);
-	} else {
-		spin_unlock_irqrestore(&dev->lock, flags);
-		return -ENOMEM;
-	}
-
-	/* update ep0 state */
-	if (ep->ep_num == 0)
-		dev->ep0_state = DATA_STATE_XMIT;
-
-	if (likely(req != NULL)) {
-		list_add_tail(&req->queue, &ep->queue);
-		dev_vdbg(&dev->pdev->dev, "list_add_tail()\n");
-	}
-
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-
-/* dequeue (cancels, unlinks) an I/O request from an endpoint */
-static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
-	struct langwell_ep	*ep;
-	struct langwell_udc	*dev;
-	struct langwell_request	*req;
-	unsigned long		flags;
-	int			stopped, ep_num, retval = 0;
-	u32			endptctrl;
-
-	ep = container_of(_ep, struct langwell_ep, ep);
-	dev = ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (!_ep || !ep->desc || !_req)
-		return -EINVAL;
-
-	if (!dev->driver)
-		return -ESHUTDOWN;
-
-	spin_lock_irqsave(&dev->lock, flags);
-	stopped = ep->stopped;
-
-	/* quiesce dma while we patch the queue */
-	ep->stopped = 1;
-	ep_num = ep->ep_num;
-
-	/* disable endpoint control register */
-	endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
-	if (is_in(ep))
-		endptctrl &= ~EPCTRL_TXE;
-	else
-		endptctrl &= ~EPCTRL_RXE;
-	writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
-	/* make sure it's still queued on this endpoint */
-	list_for_each_entry(req, &ep->queue, queue) {
-		if (&req->req == _req)
-			break;
-	}
-
-	if (&req->req != _req) {
-		retval = -EINVAL;
-		goto done;
-	}
-
-	/* queue head may be partially complete. */
-	if (ep->queue.next == &req->queue) {
-		dev_dbg(&dev->pdev->dev, "unlink (%s) dma\n", _ep->name);
-		_req->status = -ECONNRESET;
-		langwell_ep_fifo_flush(&ep->ep);
-
-		/* not the last request in endpoint queue */
-		if (likely(ep->queue.next == &req->queue)) {
-			struct langwell_dqh	*dqh;
-			struct langwell_request	*next_req;
-
-			dqh = ep->dqh;
-			next_req = list_entry(req->queue.next,
-					struct langwell_request, queue);
-
-			/* point the dQH to the first dTD of next request */
-			writel((u32) next_req->head, &dqh->dqh_current);
-		}
-	} else {
-		struct langwell_request	*prev_req;
-
-		prev_req = list_entry(req->queue.prev,
-				struct langwell_request, queue);
-		writel(readl(&req->tail->dtd_next),
-				&prev_req->tail->dtd_next);
-	}
-
-	done(ep, req, -ECONNRESET);
-
-done:
-	/* enable endpoint again */
-	endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
-	if (is_in(ep))
-		endptctrl |= EPCTRL_TXE;
-	else
-		endptctrl |= EPCTRL_RXE;
-	writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
-	ep->stopped = stopped;
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return retval;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoint set/clear halt */
-static void ep_set_halt(struct langwell_ep *ep, int value)
-{
-	u32			endptctrl = 0;
-	int			ep_num;
-	struct langwell_udc	*dev = ep->dev;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	ep_num = ep->ep_num;
-	endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
-
-	/* value: 1 - set halt, 0 - clear halt */
-	if (value) {
-		/* set the stall bit */
-		if (is_in(ep))
-			endptctrl |= EPCTRL_TXS;
-		else
-			endptctrl |= EPCTRL_RXS;
-	} else {
-		/* clear the stall bit and reset data toggle */
-		if (is_in(ep)) {
-			endptctrl &= ~EPCTRL_TXS;
-			endptctrl |= EPCTRL_TXR;
-		} else {
-			endptctrl &= ~EPCTRL_RXS;
-			endptctrl |= EPCTRL_RXR;
-		}
-	}
-
-	writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* set the endpoint halt feature */
-static int langwell_ep_set_halt(struct usb_ep *_ep, int value)
-{
-	struct langwell_ep	*ep;
-	struct langwell_udc	*dev;
-	unsigned long		flags;
-	int			retval = 0;
-
-	ep = container_of(_ep, struct langwell_ep, ep);
-	dev = ep->dev;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (!_ep || !ep->desc)
-		return -EINVAL;
-
-	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
-		return -ESHUTDOWN;
-
-	if (usb_endpoint_xfer_isoc(ep->desc))
-		return  -EOPNOTSUPP;
-
-	spin_lock_irqsave(&dev->lock, flags);
-
-	/*
-	 * attempt to halt IN ep will fail if any transfer requests
-	 * are still queue
-	 */
-	if (!list_empty(&ep->queue) && is_in(ep) && value) {
-		/* IN endpoint FIFO holds bytes */
-		dev_dbg(&dev->pdev->dev, "%s FIFO holds bytes\n", _ep->name);
-		retval = -EAGAIN;
-		goto done;
-	}
-
-	/* endpoint set/clear halt */
-	if (ep->ep_num) {
-		ep_set_halt(ep, value);
-	} else { /* endpoint 0 */
-		dev->ep0_state = WAIT_FOR_SETUP;
-		dev->ep0_dir = USB_DIR_OUT;
-	}
-done:
-	spin_unlock_irqrestore(&dev->lock, flags);
-	dev_dbg(&dev->pdev->dev, "%s %s halt\n",
-			_ep->name, value ? "set" : "clear");
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return retval;
-}
-
-
-/* set the halt feature and ignores clear requests */
-static int langwell_ep_set_wedge(struct usb_ep *_ep)
-{
-	struct langwell_ep	*ep;
-	struct langwell_udc	*dev;
-
-	ep = container_of(_ep, struct langwell_ep, ep);
-	dev = ep->dev;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (!_ep || !ep->desc)
-		return -EINVAL;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return usb_ep_set_halt(_ep);
-}
-
-
-/* flush contents of a fifo */
-static void langwell_ep_fifo_flush(struct usb_ep *_ep)
-{
-	struct langwell_ep	*ep;
-	struct langwell_udc	*dev;
-	u32			flush_bit;
-	unsigned long		timeout;
-
-	ep = container_of(_ep, struct langwell_ep, ep);
-	dev = ep->dev;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (!_ep || !ep->desc) {
-		dev_vdbg(&dev->pdev->dev, "ep or ep->desc is NULL\n");
-		dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-		return;
-	}
-
-	dev_vdbg(&dev->pdev->dev, "%s-%s fifo flush\n",
-			_ep->name, DIR_STRING(ep));
-
-	/* flush endpoint buffer */
-	if (ep->ep_num == 0)
-		flush_bit = (1 << 16) | 1;
-	else if (is_in(ep))
-		flush_bit = 1 << (ep->ep_num + 16);	/* TX */
-	else
-		flush_bit = 1 << ep->ep_num;		/* RX */
-
-	/* wait until flush complete */
-	timeout = jiffies + FLUSH_TIMEOUT;
-	do {
-		writel(flush_bit, &dev->op_regs->endptflush);
-		while (readl(&dev->op_regs->endptflush)) {
-			if (time_after(jiffies, timeout)) {
-				dev_err(&dev->pdev->dev, "ep flush timeout\n");
-				goto done;
-			}
-			cpu_relax();
-		}
-	} while (readl(&dev->op_regs->endptstat) & flush_bit);
-done:
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* endpoints operations structure */
-static const struct usb_ep_ops langwell_ep_ops = {
-
-	/* configure endpoint, making it usable */
-	.enable		= langwell_ep_enable,
-
-	/* endpoint is no longer usable */
-	.disable	= langwell_ep_disable,
-
-	/* allocate a request object to use with this endpoint */
-	.alloc_request	= langwell_alloc_request,
-
-	/* free a request object */
-	.free_request	= langwell_free_request,
-
-	/* queue (submits) an I/O requests to an endpoint */
-	.queue		= langwell_ep_queue,
-
-	/* dequeue (cancels, unlinks) an I/O request from an endpoint */
-	.dequeue	= langwell_ep_dequeue,
-
-	/* set the endpoint halt feature */
-	.set_halt	= langwell_ep_set_halt,
-
-	/* set the halt feature and ignores clear requests */
-	.set_wedge	= langwell_ep_set_wedge,
-
-	/* flush contents of a fifo */
-	.fifo_flush	= langwell_ep_fifo_flush,
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-/* device controller usb_gadget_ops structure */
-
-/* returns the current frame number */
-static int langwell_get_frame(struct usb_gadget *_gadget)
-{
-	struct langwell_udc	*dev;
-	u16			retval;
-
-	if (!_gadget)
-		return -ENODEV;
-
-	dev = container_of(_gadget, struct langwell_udc, gadget);
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	retval = readl(&dev->op_regs->frindex) & FRINDEX_MASK;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return retval;
-}
-
-
-/* enter or exit PHY low power state */
-static void langwell_phy_low_power(struct langwell_udc *dev, bool flag)
-{
-	u32		devlc;
-	u8		devlc_byte2;
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	devlc = readl(&dev->op_regs->devlc);
-	dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc);
-
-	if (flag)
-		devlc |= LPM_PHCD;
-	else
-		devlc &= ~LPM_PHCD;
-
-	/* FIXME: workaround for Langwell A1/A2/A3 sighting */
-	devlc_byte2 = (devlc >> 16) & 0xff;
-	writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2);
-
-	devlc = readl(&dev->op_regs->devlc);
-	dev_vdbg(&dev->pdev->dev,
-			"%s PHY low power suspend, devlc = 0x%08x\n",
-			flag ? "enter" : "exit", devlc);
-}
-
-
-/* tries to wake up the host connected to this gadget */
-static int langwell_wakeup(struct usb_gadget *_gadget)
-{
-	struct langwell_udc	*dev;
-	u32			portsc1;
-	unsigned long		flags;
-
-	if (!_gadget)
-		return 0;
-
-	dev = container_of(_gadget, struct langwell_udc, gadget);
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* remote wakeup feature not enabled by host */
-	if (!dev->remote_wakeup) {
-		dev_info(&dev->pdev->dev, "remote wakeup is disabled\n");
-		return -ENOTSUPP;
-	}
-
-	spin_lock_irqsave(&dev->lock, flags);
-
-	portsc1 = readl(&dev->op_regs->portsc1);
-	if (!(portsc1 & PORTS_SUSP)) {
-		spin_unlock_irqrestore(&dev->lock, flags);
-		return 0;
-	}
-
-	/* LPM L1 to L0 or legacy remote wakeup */
-	if (dev->lpm && dev->lpm_state == LPM_L1)
-		dev_info(&dev->pdev->dev, "LPM L1 to L0 remote wakeup\n");
-	else
-		dev_info(&dev->pdev->dev, "device remote wakeup\n");
-
-	/* exit PHY low power suspend */
-	if (dev->pdev->device != 0x0829)
-		langwell_phy_low_power(dev, 0);
-
-	/* force port resume */
-	portsc1 |= PORTS_FPR;
-	writel(portsc1, &dev->op_regs->portsc1);
-
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-
-/* notify controller that VBUS is powered or not */
-static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active)
-{
-	struct langwell_udc	*dev;
-	unsigned long		flags;
-	u32			usbcmd;
-
-	if (!_gadget)
-		return -ENODEV;
-
-	dev = container_of(_gadget, struct langwell_udc, gadget);
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	spin_lock_irqsave(&dev->lock, flags);
-	dev_vdbg(&dev->pdev->dev, "VBUS status: %s\n",
-			is_active ? "on" : "off");
-
-	dev->vbus_active = (is_active != 0);
-	if (dev->driver && dev->softconnected && dev->vbus_active) {
-		usbcmd = readl(&dev->op_regs->usbcmd);
-		usbcmd |= CMD_RUNSTOP;
-		writel(usbcmd, &dev->op_regs->usbcmd);
-	} else {
-		usbcmd = readl(&dev->op_regs->usbcmd);
-		usbcmd &= ~CMD_RUNSTOP;
-		writel(usbcmd, &dev->op_regs->usbcmd);
-	}
-
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-
-/* constrain controller's VBUS power usage */
-static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
-{
-	struct langwell_udc	*dev;
-
-	if (!_gadget)
-		return -ENODEV;
-
-	dev = container_of(_gadget, struct langwell_udc, gadget);
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (dev->transceiver) {
-		dev_vdbg(&dev->pdev->dev, "usb_phy_set_power\n");
-		dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-		return usb_phy_set_power(dev->transceiver, mA);
-	}
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return -ENOTSUPP;
-}
-
-
-/* D+ pullup, software-controlled connect/disconnect to USB host */
-static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
-{
-	struct langwell_udc	*dev;
-	u32			usbcmd;
-	unsigned long		flags;
-
-	if (!_gadget)
-		return -ENODEV;
-
-	dev = container_of(_gadget, struct langwell_udc, gadget);
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	spin_lock_irqsave(&dev->lock, flags);
-	dev->softconnected = (is_on != 0);
-
-	if (dev->driver && dev->softconnected && dev->vbus_active) {
-		usbcmd = readl(&dev->op_regs->usbcmd);
-		usbcmd |= CMD_RUNSTOP;
-		writel(usbcmd, &dev->op_regs->usbcmd);
-	} else {
-		usbcmd = readl(&dev->op_regs->usbcmd);
-		usbcmd &= ~CMD_RUNSTOP;
-		writel(usbcmd, &dev->op_regs->usbcmd);
-	}
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-static int langwell_start(struct usb_gadget *g,
-		struct usb_gadget_driver *driver);
-
-static int langwell_stop(struct usb_gadget *g,
-		struct usb_gadget_driver *driver);
-
-/* device controller usb_gadget_ops structure */
-static const struct usb_gadget_ops langwell_ops = {
-
-	/* returns the current frame number */
-	.get_frame	= langwell_get_frame,
-
-	/* tries to wake up the host connected to this gadget */
-	.wakeup		= langwell_wakeup,
-
-	/* set the device selfpowered feature, always selfpowered */
-	/* .set_selfpowered = langwell_set_selfpowered, */
-
-	/* notify controller that VBUS is powered or not */
-	.vbus_session	= langwell_vbus_session,
-
-	/* constrain controller's VBUS power usage */
-	.vbus_draw	= langwell_vbus_draw,
-
-	/* D+ pullup, software-controlled connect/disconnect to USB host */
-	.pullup		= langwell_pullup,
-
-	.udc_start	= langwell_start,
-	.udc_stop	= langwell_stop,
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-/* device controller operations */
-
-/* reset device controller */
-static int langwell_udc_reset(struct langwell_udc *dev)
-{
-	u32		usbcmd, usbmode, devlc, endpointlistaddr;
-	u8		devlc_byte0, devlc_byte2;
-	unsigned long	timeout;
-
-	if (!dev)
-		return -EINVAL;
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* set controller to stop state */
-	usbcmd = readl(&dev->op_regs->usbcmd);
-	usbcmd &= ~CMD_RUNSTOP;
-	writel(usbcmd, &dev->op_regs->usbcmd);
-
-	/* reset device controller */
-	usbcmd = readl(&dev->op_regs->usbcmd);
-	usbcmd |= CMD_RST;
-	writel(usbcmd, &dev->op_regs->usbcmd);
-
-	/* wait for reset to complete */
-	timeout = jiffies + RESET_TIMEOUT;
-	while (readl(&dev->op_regs->usbcmd) & CMD_RST) {
-		if (time_after(jiffies, timeout)) {
-			dev_err(&dev->pdev->dev, "device reset timeout\n");
-			return -ETIMEDOUT;
-		}
-		cpu_relax();
-	}
-
-	/* set controller to device mode */
-	usbmode = readl(&dev->op_regs->usbmode);
-	usbmode |= MODE_DEVICE;
-
-	/* turn setup lockout off, require setup tripwire in usbcmd */
-	usbmode |= MODE_SLOM;
-
-	writel(usbmode, &dev->op_regs->usbmode);
-	usbmode = readl(&dev->op_regs->usbmode);
-	dev_vdbg(&dev->pdev->dev, "usbmode=0x%08x\n", usbmode);
-
-	/* Write-Clear setup status */
-	writel(0, &dev->op_regs->usbsts);
-
-	/* if support USB LPM, ACK all LPM token */
-	if (dev->lpm) {
-		devlc = readl(&dev->op_regs->devlc);
-		dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc);
-		/* FIXME: workaround for Langwell A1/A2/A3 sighting */
-		devlc &= ~LPM_STL;	/* don't STALL LPM token */
-		devlc &= ~LPM_NYT_ACK;	/* ACK LPM token */
-		devlc_byte0 = devlc & 0xff;
-		devlc_byte2 = (devlc >> 16) & 0xff;
-		writeb(devlc_byte0, (u8 *)&dev->op_regs->devlc);
-		writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2);
-		devlc = readl(&dev->op_regs->devlc);
-		dev_vdbg(&dev->pdev->dev,
-				"ACK LPM token, devlc = 0x%08x\n", devlc);
-	}
-
-	/* fill endpointlistaddr register */
-	endpointlistaddr = dev->ep_dqh_dma;
-	endpointlistaddr &= ENDPOINTLISTADDR_MASK;
-	writel(endpointlistaddr, &dev->op_regs->endpointlistaddr);
-
-	dev_vdbg(&dev->pdev->dev,
-		"dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n",
-		dev->ep_dqh, endpointlistaddr,
-		readl(&dev->op_regs->endpointlistaddr));
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-
-/* reinitialize device controller endpoints */
-static int eps_reinit(struct langwell_udc *dev)
-{
-	struct langwell_ep	*ep;
-	char			name[14];
-	int			i;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* initialize ep0 */
-	ep = &dev->ep[0];
-	ep->dev = dev;
-	strncpy(ep->name, "ep0", sizeof(ep->name));
-	ep->ep.name = ep->name;
-	ep->ep.ops = &langwell_ep_ops;
-	ep->stopped = 0;
-	ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
-	ep->ep_num = 0;
-	ep->desc = &langwell_ep0_desc;
-	INIT_LIST_HEAD(&ep->queue);
-
-	ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
-
-	/* initialize other endpoints */
-	for (i = 2; i < dev->ep_max; i++) {
-		ep = &dev->ep[i];
-		if (i % 2)
-			snprintf(name, sizeof(name), "ep%din", i / 2);
-		else
-			snprintf(name, sizeof(name), "ep%dout", i / 2);
-		ep->dev = dev;
-		strncpy(ep->name, name, sizeof(ep->name));
-		ep->ep.name = ep->name;
-
-		ep->ep.ops = &langwell_ep_ops;
-		ep->stopped = 0;
-		ep->ep.maxpacket = (unsigned short) ~0;
-		ep->ep_num = i / 2;
-
-		INIT_LIST_HEAD(&ep->queue);
-		list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
-	}
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-
-/* enable interrupt and set controller to run state */
-static void langwell_udc_start(struct langwell_udc *dev)
-{
-	u32	usbintr, usbcmd;
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* enable interrupts */
-	usbintr = INTR_ULPIE	/* ULPI */
-		| INTR_SLE	/* suspend */
-		/* | INTR_SRE	SOF received */
-		| INTR_URE	/* USB reset */
-		| INTR_AAE	/* async advance */
-		| INTR_SEE	/* system error */
-		| INTR_FRE	/* frame list rollover */
-		| INTR_PCE	/* port change detect */
-		| INTR_UEE	/* USB error interrupt */
-		| INTR_UE;	/* USB interrupt */
-	writel(usbintr, &dev->op_regs->usbintr);
-
-	/* clear stopped bit */
-	dev->stopped = 0;
-
-	/* set controller to run */
-	usbcmd = readl(&dev->op_regs->usbcmd);
-	usbcmd |= CMD_RUNSTOP;
-	writel(usbcmd, &dev->op_regs->usbcmd);
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* disable interrupt and set controller to stop state */
-static void langwell_udc_stop(struct langwell_udc *dev)
-{
-	u32	usbcmd;
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* disable all interrupts */
-	writel(0, &dev->op_regs->usbintr);
-
-	/* set stopped bit */
-	dev->stopped = 1;
-
-	/* set controller to stop state */
-	usbcmd = readl(&dev->op_regs->usbcmd);
-	usbcmd &= ~CMD_RUNSTOP;
-	writel(usbcmd, &dev->op_regs->usbcmd);
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* stop all USB activities */
-static void stop_activity(struct langwell_udc *dev)
-{
-	struct langwell_ep	*ep;
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	nuke(&dev->ep[0], -ESHUTDOWN);
-
-	list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
-		nuke(ep, -ESHUTDOWN);
-	}
-
-	/* report disconnect; the driver is already quiesced */
-	if (dev->driver) {
-		spin_unlock(&dev->lock);
-		dev->driver->disconnect(&dev->gadget);
-		spin_lock(&dev->lock);
-	}
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* device "function" sysfs attribute file */
-static ssize_t show_function(struct device *_dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct langwell_udc	*dev = dev_get_drvdata(_dev);
-
-	if (!dev->driver || !dev->driver->function
-			|| strlen(dev->driver->function) > PAGE_SIZE)
-		return 0;
-
-	return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function);
-}
-static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
-
-
-static inline enum usb_device_speed lpm_device_speed(u32 reg)
-{
-	switch (LPM_PSPD(reg)) {
-	case LPM_SPEED_HIGH:
-		return USB_SPEED_HIGH;
-	case LPM_SPEED_FULL:
-		return USB_SPEED_FULL;
-	case LPM_SPEED_LOW:
-		return USB_SPEED_LOW;
-	default:
-		return USB_SPEED_UNKNOWN;
-	}
-}
-
-/* device "langwell_udc" sysfs attribute file */
-static ssize_t show_langwell_udc(struct device *_dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct langwell_udc	*dev = dev_get_drvdata(_dev);
-	struct langwell_request *req;
-	struct langwell_ep	*ep = NULL;
-	char			*next;
-	unsigned		size;
-	unsigned		t;
-	unsigned		i;
-	unsigned long		flags;
-	u32			tmp_reg;
-
-	next = buf;
-	size = PAGE_SIZE;
-	spin_lock_irqsave(&dev->lock, flags);
-
-	/* driver basic information */
-	t = scnprintf(next, size,
-			DRIVER_DESC "\n"
-			"%s version: %s\n"
-			"Gadget driver: %s\n\n",
-			driver_name, DRIVER_VERSION,
-			dev->driver ? dev->driver->driver.name : "(none)");
-	size -= t;
-	next += t;
-
-	/* device registers */
-	tmp_reg = readl(&dev->op_regs->usbcmd);
-	t = scnprintf(next, size,
-			"USBCMD reg:\n"
-			"SetupTW: %d\n"
-			"Run/Stop: %s\n\n",
-			(tmp_reg & CMD_SUTW) ? 1 : 0,
-			(tmp_reg & CMD_RUNSTOP) ? "Run" : "Stop");
-	size -= t;
-	next += t;
-
-	tmp_reg = readl(&dev->op_regs->usbsts);
-	t = scnprintf(next, size,
-			"USB Status Reg:\n"
-			"Device Suspend: %d\n"
-			"Reset Received: %d\n"
-			"System Error: %s\n"
-			"USB Error Interrupt: %s\n\n",
-			(tmp_reg & STS_SLI) ? 1 : 0,
-			(tmp_reg & STS_URI) ? 1 : 0,
-			(tmp_reg & STS_SEI) ? "Error" : "No error",
-			(tmp_reg & STS_UEI) ? "Error detected" : "No error");
-	size -= t;
-	next += t;
-
-	tmp_reg = readl(&dev->op_regs->usbintr);
-	t = scnprintf(next, size,
-			"USB Intrrupt Enable Reg:\n"
-			"Sleep Enable: %d\n"
-			"SOF Received Enable: %d\n"
-			"Reset Enable: %d\n"
-			"System Error Enable: %d\n"
-			"Port Change Dectected Enable: %d\n"
-			"USB Error Intr Enable: %d\n"
-			"USB Intr Enable: %d\n\n",
-			(tmp_reg & INTR_SLE) ? 1 : 0,
-			(tmp_reg & INTR_SRE) ? 1 : 0,
-			(tmp_reg & INTR_URE) ? 1 : 0,
-			(tmp_reg & INTR_SEE) ? 1 : 0,
-			(tmp_reg & INTR_PCE) ? 1 : 0,
-			(tmp_reg & INTR_UEE) ? 1 : 0,
-			(tmp_reg & INTR_UE) ? 1 : 0);
-	size -= t;
-	next += t;
-
-	tmp_reg = readl(&dev->op_regs->frindex);
-	t = scnprintf(next, size,
-			"USB Frame Index Reg:\n"
-			"Frame Number is 0x%08x\n\n",
-			(tmp_reg & FRINDEX_MASK));
-	size -= t;
-	next += t;
-
-	tmp_reg = readl(&dev->op_regs->deviceaddr);
-	t = scnprintf(next, size,
-			"USB Device Address Reg:\n"
-			"Device Addr is 0x%x\n\n",
-			USBADR(tmp_reg));
-	size -= t;
-	next += t;
-
-	tmp_reg = readl(&dev->op_regs->endpointlistaddr);
-	t = scnprintf(next, size,
-			"USB Endpoint List Address Reg:\n"
-			"Endpoint List Pointer is 0x%x\n\n",
-			EPBASE(tmp_reg));
-	size -= t;
-	next += t;
-
-	tmp_reg = readl(&dev->op_regs->portsc1);
-	t = scnprintf(next, size,
-		"USB Port Status & Control Reg:\n"
-		"Port Reset: %s\n"
-		"Port Suspend Mode: %s\n"
-		"Over-current Change: %s\n"
-		"Port Enable/Disable Change: %s\n"
-		"Port Enabled/Disabled: %s\n"
-		"Current Connect Status: %s\n"
-		"LPM Suspend Status: %s\n\n",
-		(tmp_reg & PORTS_PR) ? "Reset" : "Not Reset",
-		(tmp_reg & PORTS_SUSP) ? "Suspend " : "Not Suspend",
-		(tmp_reg & PORTS_OCC) ? "Detected" : "No",
-		(tmp_reg & PORTS_PEC) ? "Changed" : "Not Changed",
-		(tmp_reg & PORTS_PE) ? "Enable" : "Not Correct",
-		(tmp_reg & PORTS_CCS) ?  "Attached" : "Not Attached",
-		(tmp_reg & PORTS_SLP) ? "LPM L1" : "LPM L0");
-	size -= t;
-	next += t;
-
-	tmp_reg = readl(&dev->op_regs->devlc);
-	t = scnprintf(next, size,
-		"Device LPM Control Reg:\n"
-		"Parallel Transceiver : %d\n"
-		"Serial Transceiver : %d\n"
-		"Port Speed: %s\n"
-		"Port Force Full Speed Connenct: %s\n"
-		"PHY Low Power Suspend Clock: %s\n"
-		"BmAttributes: %d\n\n",
-		LPM_PTS(tmp_reg),
-		(tmp_reg & LPM_STS) ? 1 : 0,
-		usb_speed_string(lpm_device_speed(tmp_reg)),
-		(tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force",
-		(tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled",
-		LPM_BA(tmp_reg));
-	size -= t;
-	next += t;
-
-	tmp_reg = readl(&dev->op_regs->usbmode);
-	t = scnprintf(next, size,
-			"USB Mode Reg:\n"
-			"Controller Mode is : %s\n\n", ({
-				char *s;
-				switch (MODE_CM(tmp_reg)) {
-				case MODE_IDLE:
-					s = "Idle"; break;
-				case MODE_DEVICE:
-					s = "Device Controller"; break;
-				case MODE_HOST:
-					s = "Host Controller"; break;
-				default:
-					s = "None"; break;
-				}
-				s;
-			}));
-	size -= t;
-	next += t;
-
-	tmp_reg = readl(&dev->op_regs->endptsetupstat);
-	t = scnprintf(next, size,
-			"Endpoint Setup Status Reg:\n"
-			"SETUP on ep 0x%04x\n\n",
-			tmp_reg & SETUPSTAT_MASK);
-	size -= t;
-	next += t;
-
-	for (i = 0; i < dev->ep_max / 2; i++) {
-		tmp_reg = readl(&dev->op_regs->endptctrl[i]);
-		t = scnprintf(next, size, "EP Ctrl Reg [%d]: 0x%08x\n",
-				i, tmp_reg);
-		size -= t;
-		next += t;
-	}
-	tmp_reg = readl(&dev->op_regs->endptprime);
-	t = scnprintf(next, size, "EP Prime Reg: 0x%08x\n\n", tmp_reg);
-	size -= t;
-	next += t;
-
-	/* langwell_udc, langwell_ep, langwell_request structure information */
-	ep = &dev->ep[0];
-	t = scnprintf(next, size, "%s MaxPacketSize: 0x%x, ep_num: %d\n",
-			ep->ep.name, ep->ep.maxpacket, ep->ep_num);
-	size -= t;
-	next += t;
-
-	if (list_empty(&ep->queue)) {
-		t = scnprintf(next, size, "its req queue is empty\n\n");
-		size -= t;
-		next += t;
-	} else {
-		list_for_each_entry(req, &ep->queue, queue) {
-			t = scnprintf(next, size,
-				"req %p actual 0x%x length 0x%x  buf %p\n",
-				&req->req, req->req.actual,
-				req->req.length, req->req.buf);
-			size -= t;
-			next += t;
-		}
-	}
-	/* other gadget->eplist ep */
-	list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
-		if (ep->desc) {
-			t = scnprintf(next, size,
-					"\n%s MaxPacketSize: 0x%x, "
-					"ep_num: %d\n",
-					ep->ep.name, ep->ep.maxpacket,
-					ep->ep_num);
-			size -= t;
-			next += t;
-
-			if (list_empty(&ep->queue)) {
-				t = scnprintf(next, size,
-						"its req queue is empty\n\n");
-				size -= t;
-				next += t;
-			} else {
-				list_for_each_entry(req, &ep->queue, queue) {
-					t = scnprintf(next, size,
-						"req %p actual 0x%x length "
-						"0x%x  buf %p\n",
-						&req->req, req->req.actual,
-						req->req.length, req->req.buf);
-					size -= t;
-					next += t;
-				}
-			}
-		}
-	}
-
-	spin_unlock_irqrestore(&dev->lock, flags);
-	return PAGE_SIZE - size;
-}
-static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL);
-
-
-/* device "remote_wakeup" sysfs attribute file */
-static ssize_t store_remote_wakeup(struct device *_dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct langwell_udc	*dev = dev_get_drvdata(_dev);
-	unsigned long		flags;
-	ssize_t			rc = count;
-
-	if (count > 2)
-		return -EINVAL;
-
-	if (count > 0 && buf[count-1] == '\n')
-		((char *) buf)[count-1] = 0;
-
-	if (buf[0] != '1')
-		return -EINVAL;
-
-	/* force remote wakeup enabled in case gadget driver doesn't support */
-	spin_lock_irqsave(&dev->lock, flags);
-	dev->remote_wakeup = 1;
-	dev->dev_status |= (1 << USB_DEVICE_REMOTE_WAKEUP);
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	langwell_wakeup(&dev->gadget);
-
-	return rc;
-}
-static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup);
-
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * when a driver is successfully registered, it will receive
- * control requests including set_configuration(), which enables
- * non-control requests.  then usb traffic follows until a
- * disconnect is reported.  then a host may connect again, or
- * the driver might get unbound.
- */
-
-static int langwell_start(struct usb_gadget *g,
-		struct usb_gadget_driver *driver)
-{
-	struct langwell_udc	*dev = gadget_to_langwell(g);
-	unsigned long		flags;
-	int			retval;
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	spin_lock_irqsave(&dev->lock, flags);
-
-	/* hook up the driver ... */
-	driver->driver.bus = NULL;
-	dev->driver = driver;
-	dev->gadget.dev.driver = &driver->driver;
-
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	retval = device_create_file(&dev->pdev->dev, &dev_attr_function);
-	if (retval)
-		goto err;
-
-	dev->usb_state = USB_STATE_ATTACHED;
-	dev->ep0_state = WAIT_FOR_SETUP;
-	dev->ep0_dir = USB_DIR_OUT;
-
-	/* enable interrupt and set controller to run state */
-	if (dev->got_irq)
-		langwell_udc_start(dev);
-
-	dev_vdbg(&dev->pdev->dev,
-			"After langwell_udc_start(), print all registers:\n");
-	print_all_registers(dev);
-
-	dev_info(&dev->pdev->dev, "register driver: %s\n",
-			driver->driver.name);
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
-	return 0;
-
-err:
-	dev->gadget.dev.driver = NULL;
-	dev->driver = NULL;
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
-	return retval;
-}
-
-/* unregister gadget driver */
-static int langwell_stop(struct usb_gadget *g,
-		struct usb_gadget_driver *driver)
-{
-	struct langwell_udc	*dev = gadget_to_langwell(g);
-	unsigned long		flags;
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* exit PHY low power suspend */
-	if (dev->pdev->device != 0x0829)
-		langwell_phy_low_power(dev, 0);
-
-	/* unbind OTG transceiver */
-	if (dev->transceiver)
-		(void)otg_set_peripheral(dev->transceiver->otg, 0);
-
-	/* disable interrupt and set controller to stop state */
-	langwell_udc_stop(dev);
-
-	dev->usb_state = USB_STATE_ATTACHED;
-	dev->ep0_state = WAIT_FOR_SETUP;
-	dev->ep0_dir = USB_DIR_OUT;
-
-	spin_lock_irqsave(&dev->lock, flags);
-
-	/* stop all usb activities */
-	dev->gadget.speed = USB_SPEED_UNKNOWN;
-	dev->gadget.dev.driver = NULL;
-	dev->driver = NULL;
-	stop_activity(dev);
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	device_remove_file(&dev->pdev->dev, &dev_attr_function);
-
-	dev_info(&dev->pdev->dev, "unregistered driver '%s'\n",
-			driver->driver.name);
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * setup tripwire is used as a semaphore to ensure that the setup data
- * payload is extracted from a dQH without being corrupted
- */
-static void setup_tripwire(struct langwell_udc *dev)
-{
-	u32			usbcmd,
-				endptsetupstat;
-	unsigned long		timeout;
-	struct langwell_dqh	*dqh;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* ep0 OUT dQH */
-	dqh = &dev->ep_dqh[EP_DIR_OUT];
-
-	/* Write-Clear endptsetupstat */
-	endptsetupstat = readl(&dev->op_regs->endptsetupstat);
-	writel(endptsetupstat, &dev->op_regs->endptsetupstat);
-
-	/* wait until endptsetupstat is cleared */
-	timeout = jiffies + SETUPSTAT_TIMEOUT;
-	while (readl(&dev->op_regs->endptsetupstat)) {
-		if (time_after(jiffies, timeout)) {
-			dev_err(&dev->pdev->dev, "setup_tripwire timeout\n");
-			break;
-		}
-		cpu_relax();
-	}
-
-	/* while a hazard exists when setup packet arrives */
-	do {
-		/* set setup tripwire bit */
-		usbcmd = readl(&dev->op_regs->usbcmd);
-		writel(usbcmd | CMD_SUTW, &dev->op_regs->usbcmd);
-
-		/* copy the setup packet to local buffer */
-		memcpy(&dev->local_setup_buff, &dqh->dqh_setup, 8);
-	} while (!(readl(&dev->op_regs->usbcmd) & CMD_SUTW));
-
-	/* Write-Clear setup tripwire bit */
-	usbcmd = readl(&dev->op_regs->usbcmd);
-	writel(usbcmd & ~CMD_SUTW, &dev->op_regs->usbcmd);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* protocol ep0 stall, will automatically be cleared on new transaction */
-static void ep0_stall(struct langwell_udc *dev)
-{
-	u32	endptctrl;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* set TX and RX to stall */
-	endptctrl = readl(&dev->op_regs->endptctrl[0]);
-	endptctrl |= EPCTRL_TXS | EPCTRL_RXS;
-	writel(endptctrl, &dev->op_regs->endptctrl[0]);
-
-	/* update ep0 state */
-	dev->ep0_state = WAIT_FOR_SETUP;
-	dev->ep0_dir = USB_DIR_OUT;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* PRIME a status phase for ep0 */
-static int prime_status_phase(struct langwell_udc *dev, int dir)
-{
-	struct langwell_request	*req;
-	struct langwell_ep	*ep;
-	int			status = 0;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (dir == EP_DIR_IN)
-		dev->ep0_dir = USB_DIR_IN;
-	else
-		dev->ep0_dir = USB_DIR_OUT;
-
-	ep = &dev->ep[0];
-	dev->ep0_state = WAIT_FOR_OUT_STATUS;
-
-	req = dev->status_req;
-
-	req->ep = ep;
-	req->req.length = 0;
-	req->req.status = -EINPROGRESS;
-	req->req.actual = 0;
-	req->req.complete = NULL;
-	req->dtd_count = 0;
-
-	if (!req_to_dtd(req))
-		status = queue_dtd(ep, req);
-	else
-		return -ENOMEM;
-
-	if (status)
-		dev_err(&dev->pdev->dev, "can't queue ep0 status request\n");
-
-	list_add_tail(&req->queue, &ep->queue);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return status;
-}
-
-
-/* SET_ADDRESS request routine */
-static void set_address(struct langwell_udc *dev, u16 value,
-		u16 index, u16 length)
-{
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* save the new address to device struct */
-	dev->dev_addr = (u8) value;
-	dev_vdbg(&dev->pdev->dev, "dev->dev_addr = %d\n", dev->dev_addr);
-
-	/* update usb state */
-	dev->usb_state = USB_STATE_ADDRESS;
-
-	/* STATUS phase */
-	if (prime_status_phase(dev, EP_DIR_IN))
-		ep0_stall(dev);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* return endpoint by windex */
-static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev,
-		u16 wIndex)
-{
-	struct langwell_ep		*ep;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
-		return &dev->ep[0];
-
-	list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
-		u8	bEndpointAddress;
-		if (!ep->desc)
-			continue;
-
-		bEndpointAddress = ep->desc->bEndpointAddress;
-		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
-			continue;
-
-		if ((wIndex & USB_ENDPOINT_NUMBER_MASK)
-			== (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK))
-			return ep;
-	}
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return NULL;
-}
-
-
-/* return whether endpoint is stalled, 0: not stalled; 1: stalled */
-static int ep_is_stall(struct langwell_ep *ep)
-{
-	struct langwell_udc	*dev = ep->dev;
-	u32			endptctrl;
-	int			retval;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	endptctrl = readl(&dev->op_regs->endptctrl[ep->ep_num]);
-	if (is_in(ep))
-		retval = endptctrl & EPCTRL_TXS ? 1 : 0;
-	else
-		retval = endptctrl & EPCTRL_RXS ? 1 : 0;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return retval;
-}
-
-
-/* GET_STATUS request routine */
-static void get_status(struct langwell_udc *dev, u8 request_type, u16 value,
-		u16 index, u16 length)
-{
-	struct langwell_request	*req;
-	struct langwell_ep	*ep;
-	u16	status_data = 0;	/* 16 bits cpu view status data */
-	int	status = 0;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	ep = &dev->ep[0];
-
-	if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
-		/* get device status */
-		status_data = dev->dev_status;
-	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
-		/* get interface status */
-		status_data = 0;
-	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
-		/* get endpoint status */
-		struct langwell_ep	*epn;
-		epn = get_ep_by_windex(dev, index);
-		/* stall if endpoint doesn't exist */
-		if (!epn)
-			goto stall;
-
-		status_data = ep_is_stall(epn) << USB_ENDPOINT_HALT;
-	}
-
-	dev_dbg(&dev->pdev->dev, "get status data: 0x%04x\n", status_data);
-
-	dev->ep0_dir = USB_DIR_IN;
-
-	/* borrow the per device status_req */
-	req = dev->status_req;
-
-	/* fill in the reqest structure */
-	*((u16 *) req->req.buf) = cpu_to_le16(status_data);
-	req->ep = ep;
-	req->req.length = 2;
-	req->req.status = -EINPROGRESS;
-	req->req.actual = 0;
-	req->req.complete = NULL;
-	req->dtd_count = 0;
-
-	/* prime the data phase */
-	if (!req_to_dtd(req))
-		status = queue_dtd(ep, req);
-	else			/* no mem */
-		goto stall;
-
-	if (status) {
-		dev_err(&dev->pdev->dev,
-				"response error on GET_STATUS request\n");
-		goto stall;
-	}
-
-	list_add_tail(&req->queue, &ep->queue);
-	dev->ep0_state = DATA_STATE_XMIT;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return;
-stall:
-	ep0_stall(dev);
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* setup packet interrupt handler */
-static void handle_setup_packet(struct langwell_udc *dev,
-		struct usb_ctrlrequest *setup)
-{
-	u16	wValue = le16_to_cpu(setup->wValue);
-	u16	wIndex = le16_to_cpu(setup->wIndex);
-	u16	wLength = le16_to_cpu(setup->wLength);
-	u32	portsc1;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* ep0 fifo flush */
-	nuke(&dev->ep[0], -ESHUTDOWN);
-
-	dev_dbg(&dev->pdev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
-			setup->bRequestType, setup->bRequest,
-			wValue, wIndex, wLength);
-
-	/* RNDIS gadget delegate */
-	if ((setup->bRequestType == 0x21) && (setup->bRequest == 0x00)) {
-		/* USB_CDC_SEND_ENCAPSULATED_COMMAND */
-		goto delegate;
-	}
-
-	/* USB_CDC_GET_ENCAPSULATED_RESPONSE */
-	if ((setup->bRequestType == 0xa1) && (setup->bRequest == 0x01)) {
-		/* USB_CDC_GET_ENCAPSULATED_RESPONSE */
-		goto delegate;
-	}
-
-	/* We process some stardard setup requests here */
-	switch (setup->bRequest) {
-	case USB_REQ_GET_STATUS:
-		dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_GET_STATUS\n");
-		/* get status, DATA and STATUS phase */
-		if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
-					!= (USB_DIR_IN | USB_TYPE_STANDARD))
-			break;
-		get_status(dev, setup->bRequestType, wValue, wIndex, wLength);
-		goto end;
-
-	case USB_REQ_SET_ADDRESS:
-		dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_SET_ADDRESS\n");
-		/* STATUS phase */
-		if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
-						| USB_RECIP_DEVICE))
-			break;
-		set_address(dev, wValue, wIndex, wLength);
-		goto end;
-
-	case USB_REQ_CLEAR_FEATURE:
-	case USB_REQ_SET_FEATURE:
-		/* STATUS phase */
-	{
-		int rc = -EOPNOTSUPP;
-		if (setup->bRequest == USB_REQ_SET_FEATURE)
-			dev_dbg(&dev->pdev->dev,
-					"SETUP: USB_REQ_SET_FEATURE\n");
-		else if (setup->bRequest == USB_REQ_CLEAR_FEATURE)
-			dev_dbg(&dev->pdev->dev,
-					"SETUP: USB_REQ_CLEAR_FEATURE\n");
-
-		if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
-				== (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
-			struct langwell_ep	*epn;
-			epn = get_ep_by_windex(dev, wIndex);
-			/* stall if endpoint doesn't exist */
-			if (!epn) {
-				ep0_stall(dev);
-				goto end;
-			}
-
-			if (wValue != 0 || wLength != 0
-					|| epn->ep_num > dev->ep_max)
-				break;
-
-			spin_unlock(&dev->lock);
-			rc = langwell_ep_set_halt(&epn->ep,
-				(setup->bRequest == USB_REQ_SET_FEATURE)
-				? 1 : 0);
-			spin_lock(&dev->lock);
-
-		} else if ((setup->bRequestType & (USB_RECIP_MASK
-				| USB_TYPE_MASK)) == (USB_RECIP_DEVICE
-				| USB_TYPE_STANDARD)) {
-			rc = 0;
-			switch (wValue) {
-			case USB_DEVICE_REMOTE_WAKEUP:
-				if (setup->bRequest == USB_REQ_SET_FEATURE) {
-					dev->remote_wakeup = 1;
-					dev->dev_status |= (1 << wValue);
-				} else {
-					dev->remote_wakeup = 0;
-					dev->dev_status &= ~(1 << wValue);
-				}
-				break;
-			case USB_DEVICE_TEST_MODE:
-				dev_dbg(&dev->pdev->dev, "SETUP: TEST MODE\n");
-				if ((wIndex & 0xff) ||
-					(dev->gadget.speed != USB_SPEED_HIGH))
-					ep0_stall(dev);
-
-				switch (wIndex >> 8) {
-				case TEST_J:
-				case TEST_K:
-				case TEST_SE0_NAK:
-				case TEST_PACKET:
-				case TEST_FORCE_EN:
-					if (prime_status_phase(dev, EP_DIR_IN))
-						ep0_stall(dev);
-					portsc1 = readl(&dev->op_regs->portsc1);
-					portsc1 |= (wIndex & 0xf00) << 8;
-					writel(portsc1, &dev->op_regs->portsc1);
-					goto end;
-				default:
-					rc = -EOPNOTSUPP;
-				}
-				break;
-			default:
-				rc = -EOPNOTSUPP;
-				break;
-			}
-
-			if (!gadget_is_otg(&dev->gadget))
-				break;
-			else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
-				dev->gadget.b_hnp_enable = 1;
-			else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
-				dev->gadget.a_hnp_support = 1;
-			else if (setup->bRequest ==
-					USB_DEVICE_A_ALT_HNP_SUPPORT)
-				dev->gadget.a_alt_hnp_support = 1;
-			else
-				break;
-		} else
-			break;
-
-		if (rc == 0) {
-			if (prime_status_phase(dev, EP_DIR_IN))
-				ep0_stall(dev);
-		}
-		goto end;
-	}
-
-	case USB_REQ_GET_DESCRIPTOR:
-		dev_dbg(&dev->pdev->dev,
-				"SETUP: USB_REQ_GET_DESCRIPTOR\n");
-		goto delegate;
-
-	case USB_REQ_SET_DESCRIPTOR:
-		dev_dbg(&dev->pdev->dev,
-				"SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n");
-		goto delegate;
-
-	case USB_REQ_GET_CONFIGURATION:
-		dev_dbg(&dev->pdev->dev,
-				"SETUP: USB_REQ_GET_CONFIGURATION\n");
-		goto delegate;
-
-	case USB_REQ_SET_CONFIGURATION:
-		dev_dbg(&dev->pdev->dev,
-				"SETUP: USB_REQ_SET_CONFIGURATION\n");
-		goto delegate;
-
-	case USB_REQ_GET_INTERFACE:
-		dev_dbg(&dev->pdev->dev,
-				"SETUP: USB_REQ_GET_INTERFACE\n");
-		goto delegate;
-
-	case USB_REQ_SET_INTERFACE:
-		dev_dbg(&dev->pdev->dev,
-				"SETUP: USB_REQ_SET_INTERFACE\n");
-		goto delegate;
-
-	case USB_REQ_SYNCH_FRAME:
-		dev_dbg(&dev->pdev->dev,
-				"SETUP: USB_REQ_SYNCH_FRAME unsupported\n");
-		goto delegate;
-
-	default:
-		/* delegate USB standard requests to the gadget driver */
-		goto delegate;
-delegate:
-		/* USB requests handled by gadget */
-		if (wLength) {
-			/* DATA phase from gadget, STATUS phase from udc */
-			dev->ep0_dir = (setup->bRequestType & USB_DIR_IN)
-					?  USB_DIR_IN : USB_DIR_OUT;
-			dev_vdbg(&dev->pdev->dev,
-					"dev->ep0_dir = 0x%x, wLength = %d\n",
-					dev->ep0_dir, wLength);
-			spin_unlock(&dev->lock);
-			if (dev->driver->setup(&dev->gadget,
-					&dev->local_setup_buff) < 0)
-				ep0_stall(dev);
-			spin_lock(&dev->lock);
-			dev->ep0_state = (setup->bRequestType & USB_DIR_IN)
-					?  DATA_STATE_XMIT : DATA_STATE_RECV;
-		} else {
-			/* no DATA phase, IN STATUS phase from gadget */
-			dev->ep0_dir = USB_DIR_IN;
-			dev_vdbg(&dev->pdev->dev,
-					"dev->ep0_dir = 0x%x, wLength = %d\n",
-					dev->ep0_dir, wLength);
-			spin_unlock(&dev->lock);
-			if (dev->driver->setup(&dev->gadget,
-					&dev->local_setup_buff) < 0)
-				ep0_stall(dev);
-			spin_lock(&dev->lock);
-			dev->ep0_state = WAIT_FOR_OUT_STATUS;
-		}
-		break;
-	}
-end:
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* transfer completion, process endpoint request and free the completed dTDs
- * for this request
- */
-static int process_ep_req(struct langwell_udc *dev, int index,
-		struct langwell_request *curr_req)
-{
-	struct langwell_dtd	*curr_dtd;
-	struct langwell_dqh	*curr_dqh;
-	int			td_complete, actual, remaining_length;
-	int			i, dir;
-	u8			dtd_status = 0;
-	int			retval = 0;
-
-	curr_dqh = &dev->ep_dqh[index];
-	dir = index % 2;
-
-	curr_dtd = curr_req->head;
-	td_complete = 0;
-	actual = curr_req->req.length;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	for (i = 0; i < curr_req->dtd_count; i++) {
-
-		/* command execution states by dTD */
-		dtd_status = curr_dtd->dtd_status;
-
-		barrier();
-		remaining_length = le16_to_cpu(curr_dtd->dtd_total);
-		actual -= remaining_length;
-
-		if (!dtd_status) {
-			/* transfers completed successfully */
-			if (!remaining_length) {
-				td_complete++;
-				dev_vdbg(&dev->pdev->dev,
-					"dTD transmitted successfully\n");
-			} else {
-				if (dir) {
-					dev_vdbg(&dev->pdev->dev,
-						"TX dTD remains data\n");
-					retval = -EPROTO;
-					break;
-
-				} else {
-					td_complete++;
-					break;
-				}
-			}
-		} else {
-			/* transfers completed with errors */
-			if (dtd_status & DTD_STS_ACTIVE) {
-				dev_dbg(&dev->pdev->dev,
-					"dTD status ACTIVE dQH[%d]\n", index);
-				retval = 1;
-				return retval;
-			} else if (dtd_status & DTD_STS_HALTED) {
-				dev_err(&dev->pdev->dev,
-					"dTD error %08x dQH[%d]\n",
-					dtd_status, index);
-				/* clear the errors and halt condition */
-				curr_dqh->dtd_status = 0;
-				retval = -EPIPE;
-				break;
-			} else if (dtd_status & DTD_STS_DBE) {
-				dev_dbg(&dev->pdev->dev,
-					"data buffer (overflow) error\n");
-				retval = -EPROTO;
-				break;
-			} else if (dtd_status & DTD_STS_TRE) {
-				dev_dbg(&dev->pdev->dev,
-					"transaction(ISO) error\n");
-				retval = -EILSEQ;
-				break;
-			} else
-				dev_err(&dev->pdev->dev,
-					"unknown error (0x%x)!\n",
-					dtd_status);
-		}
-
-		if (i != curr_req->dtd_count - 1)
-			curr_dtd = (struct langwell_dtd *)
-				curr_dtd->next_dtd_virt;
-	}
-
-	if (retval)
-		return retval;
-
-	curr_req->req.actual = actual;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-
-/* complete DATA or STATUS phase of ep0 prime status phase if needed */
-static void ep0_req_complete(struct langwell_udc *dev,
-		struct langwell_ep *ep0, struct langwell_request *req)
-{
-	u32	new_addr;
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (dev->usb_state == USB_STATE_ADDRESS) {
-		/* set the new address */
-		new_addr = (u32)dev->dev_addr;
-		writel(new_addr << USBADR_SHIFT, &dev->op_regs->deviceaddr);
-
-		new_addr = USBADR(readl(&dev->op_regs->deviceaddr));
-		dev_vdbg(&dev->pdev->dev, "new_addr = %d\n", new_addr);
-	}
-
-	done(ep0, req, 0);
-
-	switch (dev->ep0_state) {
-	case DATA_STATE_XMIT:
-		/* receive status phase */
-		if (prime_status_phase(dev, EP_DIR_OUT))
-			ep0_stall(dev);
-		break;
-	case DATA_STATE_RECV:
-		/* send status phase */
-		if (prime_status_phase(dev, EP_DIR_IN))
-			ep0_stall(dev);
-		break;
-	case WAIT_FOR_OUT_STATUS:
-		dev->ep0_state = WAIT_FOR_SETUP;
-		break;
-	case WAIT_FOR_SETUP:
-		dev_err(&dev->pdev->dev, "unexpect ep0 packets\n");
-		break;
-	default:
-		ep0_stall(dev);
-		break;
-	}
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB transfer completion interrupt */
-static void handle_trans_complete(struct langwell_udc *dev)
-{
-	u32			complete_bits;
-	int			i, ep_num, dir, bit_mask, status;
-	struct langwell_ep	*epn;
-	struct langwell_request	*curr_req, *temp_req;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	complete_bits = readl(&dev->op_regs->endptcomplete);
-	dev_vdbg(&dev->pdev->dev, "endptcomplete register: 0x%08x\n",
-			complete_bits);
-
-	/* Write-Clear the bits in endptcomplete register */
-	writel(complete_bits, &dev->op_regs->endptcomplete);
-
-	if (!complete_bits) {
-		dev_dbg(&dev->pdev->dev, "complete_bits = 0\n");
-		goto done;
-	}
-
-	for (i = 0; i < dev->ep_max; i++) {
-		ep_num = i / 2;
-		dir = i % 2;
-
-		bit_mask = 1 << (ep_num + 16 * dir);
-
-		if (!(complete_bits & bit_mask))
-			continue;
-
-		/* ep0 */
-		if (i == 1)
-			epn = &dev->ep[0];
-		else
-			epn = &dev->ep[i];
-
-		if (epn->name == NULL) {
-			dev_warn(&dev->pdev->dev, "invalid endpoint\n");
-			continue;
-		}
-
-		if (i < 2)
-			/* ep0 in and out */
-			dev_dbg(&dev->pdev->dev, "%s-%s transfer completed\n",
-					epn->name,
-					is_in(epn) ? "in" : "out");
-		else
-			dev_dbg(&dev->pdev->dev, "%s transfer completed\n",
-					epn->name);
-
-		/* process the req queue until an uncomplete request */
-		list_for_each_entry_safe(curr_req, temp_req,
-				&epn->queue, queue) {
-			status = process_ep_req(dev, i, curr_req);
-			dev_vdbg(&dev->pdev->dev, "%s req status: %d\n",
-					epn->name, status);
-
-			if (status)
-				break;
-
-			/* write back status to req */
-			curr_req->req.status = status;
-
-			/* ep0 request completion */
-			if (ep_num == 0) {
-				ep0_req_complete(dev, epn, curr_req);
-				break;
-			} else {
-				done(epn, curr_req, status);
-			}
-		}
-	}
-done:
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-/* port change detect interrupt handler */
-static void handle_port_change(struct langwell_udc *dev)
-{
-	u32	portsc1, devlc;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (dev->bus_reset)
-		dev->bus_reset = 0;
-
-	portsc1 = readl(&dev->op_regs->portsc1);
-	devlc = readl(&dev->op_regs->devlc);
-	dev_vdbg(&dev->pdev->dev, "portsc1 = 0x%08x, devlc = 0x%08x\n",
-			portsc1, devlc);
-
-	/* bus reset is finished */
-	if (!(portsc1 & PORTS_PR)) {
-		/* get the speed */
-		dev->gadget.speed = lpm_device_speed(devlc);
-		dev_vdbg(&dev->pdev->dev, "dev->gadget.speed = %d\n",
-			dev->gadget.speed);
-	}
-
-	/* LPM L0 to L1 */
-	if (dev->lpm && dev->lpm_state == LPM_L0)
-		if (portsc1 & PORTS_SUSP && portsc1 & PORTS_SLP) {
-			dev_info(&dev->pdev->dev, "LPM L0 to L1\n");
-			dev->lpm_state = LPM_L1;
-		}
-
-	/* LPM L1 to L0, force resume or remote wakeup finished */
-	if (dev->lpm && dev->lpm_state == LPM_L1)
-		if (!(portsc1 & PORTS_SUSP)) {
-			dev_info(&dev->pdev->dev, "LPM L1 to L0\n");
-			dev->lpm_state = LPM_L0;
-		}
-
-	/* update USB state */
-	if (!dev->resume_state)
-		dev->usb_state = USB_STATE_DEFAULT;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB reset interrupt handler */
-static void handle_usb_reset(struct langwell_udc *dev)
-{
-	u32		deviceaddr,
-			endptsetupstat,
-			endptcomplete;
-	unsigned long	timeout;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* Write-Clear the device address */
-	deviceaddr = readl(&dev->op_regs->deviceaddr);
-	writel(deviceaddr & ~USBADR_MASK, &dev->op_regs->deviceaddr);
-
-	dev->dev_addr = 0;
-
-	/* clear usb state */
-	dev->resume_state = 0;
-
-	/* LPM L1 to L0, reset */
-	if (dev->lpm)
-		dev->lpm_state = LPM_L0;
-
-	dev->ep0_dir = USB_DIR_OUT;
-	dev->ep0_state = WAIT_FOR_SETUP;
-
-	/* remote wakeup reset to 0 when the device is reset */
-	dev->remote_wakeup = 0;
-	dev->dev_status = 1 << USB_DEVICE_SELF_POWERED;
-	dev->gadget.b_hnp_enable = 0;
-	dev->gadget.a_hnp_support = 0;
-	dev->gadget.a_alt_hnp_support = 0;
-
-	/* Write-Clear all the setup token semaphores */
-	endptsetupstat = readl(&dev->op_regs->endptsetupstat);
-	writel(endptsetupstat, &dev->op_regs->endptsetupstat);
-
-	/* Write-Clear all the endpoint complete status bits */
-	endptcomplete = readl(&dev->op_regs->endptcomplete);
-	writel(endptcomplete, &dev->op_regs->endptcomplete);
-
-	/* wait until all endptprime bits cleared */
-	timeout = jiffies + PRIME_TIMEOUT;
-	while (readl(&dev->op_regs->endptprime)) {
-		if (time_after(jiffies, timeout)) {
-			dev_err(&dev->pdev->dev, "USB reset timeout\n");
-			break;
-		}
-		cpu_relax();
-	}
-
-	/* write 1s to endptflush register to clear any primed buffers */
-	writel((u32) ~0, &dev->op_regs->endptflush);
-
-	if (readl(&dev->op_regs->portsc1) & PORTS_PR) {
-		dev_vdbg(&dev->pdev->dev, "USB bus reset\n");
-		/* bus is reseting */
-		dev->bus_reset = 1;
-
-		/* reset all the queues, stop all USB activities */
-		stop_activity(dev);
-		dev->usb_state = USB_STATE_DEFAULT;
-	} else {
-		dev_vdbg(&dev->pdev->dev, "device controller reset\n");
-		/* controller reset */
-		langwell_udc_reset(dev);
-
-		/* reset all the queues, stop all USB activities */
-		stop_activity(dev);
-
-		/* reset ep0 dQH and endptctrl */
-		ep0_reset(dev);
-
-		/* enable interrupt and set controller to run state */
-		langwell_udc_start(dev);
-
-		dev->usb_state = USB_STATE_ATTACHED;
-	}
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB bus suspend/resume interrupt */
-static void handle_bus_suspend(struct langwell_udc *dev)
-{
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	dev->resume_state = dev->usb_state;
-	dev->usb_state = USB_STATE_SUSPENDED;
-
-	/* report suspend to the driver */
-	if (dev->driver) {
-		if (dev->driver->suspend) {
-			spin_unlock(&dev->lock);
-			dev->driver->suspend(&dev->gadget);
-			spin_lock(&dev->lock);
-			dev_dbg(&dev->pdev->dev, "suspend %s\n",
-					dev->driver->driver.name);
-		}
-	}
-
-	/* enter PHY low power suspend */
-	if (dev->pdev->device != 0x0829)
-		langwell_phy_low_power(dev, 0);
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-static void handle_bus_resume(struct langwell_udc *dev)
-{
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	dev->usb_state = dev->resume_state;
-	dev->resume_state = 0;
-
-	/* exit PHY low power suspend */
-	if (dev->pdev->device != 0x0829)
-		langwell_phy_low_power(dev, 0);
-
-	/* report resume to the driver */
-	if (dev->driver) {
-		if (dev->driver->resume) {
-			spin_unlock(&dev->lock);
-			dev->driver->resume(&dev->gadget);
-			spin_lock(&dev->lock);
-			dev_dbg(&dev->pdev->dev, "resume %s\n",
-					dev->driver->driver.name);
-		}
-	}
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB device controller interrupt handler */
-static irqreturn_t langwell_irq(int irq, void *_dev)
-{
-	struct langwell_udc	*dev = _dev;
-	u32			usbsts,
-				usbintr,
-				irq_sts,
-				portsc1;
-
-	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	if (dev->stopped) {
-		dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n");
-		dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-		return IRQ_NONE;
-	}
-
-	spin_lock(&dev->lock);
-
-	/* USB status */
-	usbsts = readl(&dev->op_regs->usbsts);
-
-	/* USB interrupt enable */
-	usbintr = readl(&dev->op_regs->usbintr);
-
-	irq_sts = usbsts & usbintr;
-	dev_vdbg(&dev->pdev->dev,
-			"usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n",
-			usbsts, usbintr, irq_sts);
-
-	if (!irq_sts) {
-		dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n");
-		dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-		spin_unlock(&dev->lock);
-		return IRQ_NONE;
-	}
-
-	/* Write-Clear interrupt status bits */
-	writel(irq_sts, &dev->op_regs->usbsts);
-
-	/* resume from suspend */
-	portsc1 = readl(&dev->op_regs->portsc1);
-	if (dev->usb_state == USB_STATE_SUSPENDED)
-		if (!(portsc1 & PORTS_SUSP))
-			handle_bus_resume(dev);
-
-	/* USB interrupt */
-	if (irq_sts & STS_UI) {
-		dev_vdbg(&dev->pdev->dev, "USB interrupt\n");
-
-		/* setup packet received from ep0 */
-		if (readl(&dev->op_regs->endptsetupstat)
-				& EP0SETUPSTAT_MASK) {
-			dev_vdbg(&dev->pdev->dev,
-				"USB SETUP packet received interrupt\n");
-			/* setup tripwire semaphone */
-			setup_tripwire(dev);
-			handle_setup_packet(dev, &dev->local_setup_buff);
-		}
-
-		/* USB transfer completion */
-		if (readl(&dev->op_regs->endptcomplete)) {
-			dev_vdbg(&dev->pdev->dev,
-				"USB transfer completion interrupt\n");
-			handle_trans_complete(dev);
-		}
-	}
-
-	/* SOF received interrupt (for ISO transfer) */
-	if (irq_sts & STS_SRI) {
-		/* FIXME */
-		/* dev_vdbg(&dev->pdev->dev, "SOF received interrupt\n"); */
-	}
-
-	/* port change detect interrupt */
-	if (irq_sts & STS_PCI) {
-		dev_vdbg(&dev->pdev->dev, "port change detect interrupt\n");
-		handle_port_change(dev);
-	}
-
-	/* suspend interrupt */
-	if (irq_sts & STS_SLI) {
-		dev_vdbg(&dev->pdev->dev, "suspend interrupt\n");
-		handle_bus_suspend(dev);
-	}
-
-	/* USB reset interrupt */
-	if (irq_sts & STS_URI) {
-		dev_vdbg(&dev->pdev->dev, "USB reset interrupt\n");
-		handle_usb_reset(dev);
-	}
-
-	/* USB error or system error interrupt */
-	if (irq_sts & (STS_UEI | STS_SEI)) {
-		/* FIXME */
-		dev_warn(&dev->pdev->dev, "error IRQ, irq_sts: %x\n", irq_sts);
-	}
-
-	spin_unlock(&dev->lock);
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return IRQ_HANDLED;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* release device structure */
-static void gadget_release(struct device *_dev)
-{
-	struct langwell_udc	*dev = dev_get_drvdata(_dev);
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	complete(dev->done);
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	kfree(dev);
-}
-
-
-/* enable SRAM caching if SRAM detected */
-static void sram_init(struct langwell_udc *dev)
-{
-	struct pci_dev		*pdev = dev->pdev;
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	dev->sram_addr = pci_resource_start(pdev, 1);
-	dev->sram_size = pci_resource_len(pdev, 1);
-	dev_info(&dev->pdev->dev, "Found private SRAM at %x size:%x\n",
-			dev->sram_addr, dev->sram_size);
-	dev->got_sram = 1;
-
-	if (pci_request_region(pdev, 1, kobject_name(&pdev->dev.kobj))) {
-		dev_warn(&dev->pdev->dev, "SRAM request failed\n");
-		dev->got_sram = 0;
-	} else if (!dma_declare_coherent_memory(&pdev->dev, dev->sram_addr,
-			dev->sram_addr, dev->sram_size, DMA_MEMORY_MAP)) {
-		dev_warn(&dev->pdev->dev, "SRAM DMA declare failed\n");
-		pci_release_region(pdev, 1);
-		dev->got_sram = 0;
-	}
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* release SRAM caching */
-static void sram_deinit(struct langwell_udc *dev)
-{
-	struct pci_dev *pdev = dev->pdev;
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	dma_release_declared_memory(&pdev->dev);
-	pci_release_region(pdev, 1);
-
-	dev->got_sram = 0;
-
-	dev_info(&dev->pdev->dev, "release SRAM caching\n");
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* tear down the binding between this driver and the pci device */
-static void langwell_udc_remove(struct pci_dev *pdev)
-{
-	struct langwell_udc	*dev = pci_get_drvdata(pdev);
-
-	DECLARE_COMPLETION(done);
-
-	BUG_ON(dev->driver);
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	dev->done = &done;
-
-	/* free dTD dma_pool and dQH */
-	if (dev->dtd_pool)
-		dma_pool_destroy(dev->dtd_pool);
-
-	if (dev->ep_dqh)
-		dma_free_coherent(&pdev->dev, dev->ep_dqh_size,
-			dev->ep_dqh, dev->ep_dqh_dma);
-
-	/* release SRAM caching */
-	if (dev->has_sram && dev->got_sram)
-		sram_deinit(dev);
-
-	if (dev->status_req) {
-		kfree(dev->status_req->req.buf);
-		kfree(dev->status_req);
-	}
-
-	kfree(dev->ep);
-
-	/* disable IRQ handler */
-	if (dev->got_irq)
-		free_irq(pdev->irq, dev);
-
-	if (dev->cap_regs)
-		iounmap(dev->cap_regs);
-
-	if (dev->region)
-		release_mem_region(pci_resource_start(pdev, 0),
-				pci_resource_len(pdev, 0));
-
-	if (dev->enabled)
-		pci_disable_device(pdev);
-
-	dev->cap_regs = NULL;
-
-	dev_info(&dev->pdev->dev, "unbind\n");
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
-	device_unregister(&dev->gadget.dev);
-	device_remove_file(&pdev->dev, &dev_attr_langwell_udc);
-	device_remove_file(&pdev->dev, &dev_attr_remote_wakeup);
-
-	pci_set_drvdata(pdev, NULL);
-
-	/* free dev, wait for the release() finished */
-	wait_for_completion(&done);
-}
-
-
-/*
- * wrap this driver around the specified device, but
- * don't respond over USB until a gadget driver binds to us.
- */
-static int langwell_udc_probe(struct pci_dev *pdev,
-		const struct pci_device_id *id)
-{
-	struct langwell_udc	*dev;
-	unsigned long		resource, len;
-	void			__iomem *base = NULL;
-	size_t			size;
-	int			retval;
-
-	/* alloc, and start init */
-	dev = kzalloc(sizeof *dev, GFP_KERNEL);
-	if (dev == NULL) {
-		retval = -ENOMEM;
-		goto error;
-	}
-
-	/* initialize device spinlock */
-	spin_lock_init(&dev->lock);
-
-	dev->pdev = pdev;
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	pci_set_drvdata(pdev, dev);
-
-	/* now all the pci goodies ... */
-	if (pci_enable_device(pdev) < 0) {
-		retval = -ENODEV;
-		goto error;
-	}
-	dev->enabled = 1;
-
-	/* control register: BAR 0 */
-	resource = pci_resource_start(pdev, 0);
-	len = pci_resource_len(pdev, 0);
-	if (!request_mem_region(resource, len, driver_name)) {
-		dev_err(&dev->pdev->dev, "controller already in use\n");
-		retval = -EBUSY;
-		goto error;
-	}
-	dev->region = 1;
-
-	base = ioremap_nocache(resource, len);
-	if (base == NULL) {
-		dev_err(&dev->pdev->dev, "can't map memory\n");
-		retval = -EFAULT;
-		goto error;
-	}
-
-	dev->cap_regs = (struct langwell_cap_regs __iomem *) base;
-	dev_vdbg(&dev->pdev->dev, "dev->cap_regs: %p\n", dev->cap_regs);
-	dev->op_regs = (struct langwell_op_regs __iomem *)
-		(base + OP_REG_OFFSET);
-	dev_vdbg(&dev->pdev->dev, "dev->op_regs: %p\n", dev->op_regs);
-
-	/* irq setup after old hardware is cleaned up */
-	if (!pdev->irq) {
-		dev_err(&dev->pdev->dev, "No IRQ. Check PCI setup!\n");
-		retval = -ENODEV;
-		goto error;
-	}
-
-	dev->has_sram = 1;
-	dev->got_sram = 0;
-	dev_vdbg(&dev->pdev->dev, "dev->has_sram: %d\n", dev->has_sram);
-
-	/* enable SRAM caching if detected */
-	if (dev->has_sram && !dev->got_sram)
-		sram_init(dev);
-
-	dev_info(&dev->pdev->dev,
-			"irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n",
-			pdev->irq, resource, len, base);
-	/* enables bus-mastering for device dev */
-	pci_set_master(pdev);
-
-	if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED,
-				driver_name, dev) != 0) {
-		dev_err(&dev->pdev->dev,
-				"request interrupt %d failed\n", pdev->irq);
-		retval = -EBUSY;
-		goto error;
-	}
-	dev->got_irq = 1;
-
-	/* set stopped bit */
-	dev->stopped = 1;
-
-	/* capabilities and endpoint number */
-	dev->lpm = (readl(&dev->cap_regs->hccparams) & HCC_LEN) ? 1 : 0;
-	dev->dciversion = readw(&dev->cap_regs->dciversion);
-	dev->devcap = (readl(&dev->cap_regs->dccparams) & DEVCAP) ? 1 : 0;
-	dev_vdbg(&dev->pdev->dev, "dev->lpm: %d\n", dev->lpm);
-	dev_vdbg(&dev->pdev->dev, "dev->dciversion: 0x%04x\n",
-			dev->dciversion);
-	dev_vdbg(&dev->pdev->dev, "dccparams: 0x%08x\n",
-			readl(&dev->cap_regs->dccparams));
-	dev_vdbg(&dev->pdev->dev, "dev->devcap: %d\n", dev->devcap);
-	if (!dev->devcap) {
-		dev_err(&dev->pdev->dev, "can't support device mode\n");
-		retval = -ENODEV;
-		goto error;
-	}
-
-	/* a pair of endpoints (out/in) for each address */
-	dev->ep_max = DEN(readl(&dev->cap_regs->dccparams)) * 2;
-	dev_vdbg(&dev->pdev->dev, "dev->ep_max: %d\n", dev->ep_max);
-
-	/* allocate endpoints memory */
-	dev->ep = kzalloc(sizeof(struct langwell_ep) * dev->ep_max,
-			GFP_KERNEL);
-	if (!dev->ep) {
-		dev_err(&dev->pdev->dev, "allocate endpoints memory failed\n");
-		retval = -ENOMEM;
-		goto error;
-	}
-
-	/* allocate device dQH memory */
-	size = dev->ep_max * sizeof(struct langwell_dqh);
-	dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
-	if (size < DQH_ALIGNMENT)
-		size = DQH_ALIGNMENT;
-	else if ((size % DQH_ALIGNMENT) != 0) {
-		size += DQH_ALIGNMENT + 1;
-		size &= ~(DQH_ALIGNMENT - 1);
-	}
-	dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
-					&dev->ep_dqh_dma, GFP_KERNEL);
-	if (!dev->ep_dqh) {
-		dev_err(&dev->pdev->dev, "allocate dQH memory failed\n");
-		retval = -ENOMEM;
-		goto error;
-	}
-	dev->ep_dqh_size = size;
-	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
-
-	/* initialize ep0 status request structure */
-	dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL);
-	if (!dev->status_req) {
-		dev_err(&dev->pdev->dev,
-				"allocate status_req memory failed\n");
-		retval = -ENOMEM;
-		goto error;
-	}
-	INIT_LIST_HEAD(&dev->status_req->queue);
-
-	/* allocate a small amount of memory to get valid address */
-	dev->status_req->req.buf = kmalloc(8, GFP_KERNEL);
-	dev->status_req->req.dma = virt_to_phys(dev->status_req->req.buf);
-
-	dev->resume_state = USB_STATE_NOTATTACHED;
-	dev->usb_state = USB_STATE_POWERED;
-	dev->ep0_dir = USB_DIR_OUT;
-
-	/* remote wakeup reset to 0 when the device is reset */
-	dev->remote_wakeup = 0;
-	dev->dev_status = 1 << USB_DEVICE_SELF_POWERED;
-
-	/* reset device controller */
-	langwell_udc_reset(dev);
-
-	/* initialize gadget structure */
-	dev->gadget.ops = &langwell_ops;	/* usb_gadget_ops */
-	dev->gadget.ep0 = &dev->ep[0].ep;	/* gadget ep0 */
-	INIT_LIST_HEAD(&dev->gadget.ep_list);	/* ep_list */
-	dev->gadget.speed = USB_SPEED_UNKNOWN;	/* speed */
-	dev->gadget.max_speed = USB_SPEED_HIGH;	/* support dual speed */
-
-	/* the "gadget" abstracts/virtualizes the controller */
-	dev_set_name(&dev->gadget.dev, "gadget");
-	dev->gadget.dev.parent = &pdev->dev;
-	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
-	dev->gadget.dev.release = gadget_release;
-	dev->gadget.name = driver_name;		/* gadget name */
-
-	/* controller endpoints reinit */
-	eps_reinit(dev);
-
-	/* reset ep0 dQH and endptctrl */
-	ep0_reset(dev);
-
-	/* create dTD dma_pool resource */
-	dev->dtd_pool = dma_pool_create("langwell_dtd",
-			&dev->pdev->dev,
-			sizeof(struct langwell_dtd),
-			DTD_ALIGNMENT,
-			DMA_BOUNDARY);
-
-	if (!dev->dtd_pool) {
-		retval = -ENOMEM;
-		goto error;
-	}
-
-	/* done */
-	dev_info(&dev->pdev->dev, "%s\n", driver_desc);
-	dev_info(&dev->pdev->dev, "irq %d, pci mem %p\n", pdev->irq, base);
-	dev_info(&dev->pdev->dev, "Driver version: " DRIVER_VERSION "\n");
-	dev_info(&dev->pdev->dev, "Support (max) %d endpoints\n", dev->ep_max);
-	dev_info(&dev->pdev->dev, "Device interface version: 0x%04x\n",
-			dev->dciversion);
-	dev_info(&dev->pdev->dev, "Controller mode: %s\n",
-			dev->devcap ? "Device" : "Host");
-	dev_info(&dev->pdev->dev, "Support USB LPM: %s\n",
-			dev->lpm ? "Yes" : "No");
-
-	dev_vdbg(&dev->pdev->dev,
-			"After langwell_udc_probe(), print all registers:\n");
-	print_all_registers(dev);
-
-	retval = device_register(&dev->gadget.dev);
-	if (retval)
-		goto error;
-
-	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
-	if (retval)
-		goto error;
-
-	retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);
-	if (retval)
-		goto error;
-
-	retval = device_create_file(&pdev->dev, &dev_attr_remote_wakeup);
-	if (retval)
-		goto error_attr1;
-
-	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-
-error_attr1:
-	device_remove_file(&pdev->dev, &dev_attr_langwell_udc);
-error:
-	if (dev) {
-		dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-		langwell_udc_remove(pdev);
-	}
-
-	return retval;
-}
-
-
-/* device controller suspend */
-static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-	struct langwell_udc	*dev = pci_get_drvdata(pdev);
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	usb_del_gadget_udc(&dev->gadget);
-	/* disable interrupt and set controller to stop state */
-	langwell_udc_stop(dev);
-
-	/* disable IRQ handler */
-	if (dev->got_irq)
-		free_irq(pdev->irq, dev);
-	dev->got_irq = 0;
-
-	/* save PCI state */
-	pci_save_state(pdev);
-
-	spin_lock_irq(&dev->lock);
-	/* stop all usb activities */
-	stop_activity(dev);
-	spin_unlock_irq(&dev->lock);
-
-	/* free dTD dma_pool and dQH */
-	if (dev->dtd_pool)
-		dma_pool_destroy(dev->dtd_pool);
-
-	if (dev->ep_dqh)
-		dma_free_coherent(&pdev->dev, dev->ep_dqh_size,
-			dev->ep_dqh, dev->ep_dqh_dma);
-
-	/* release SRAM caching */
-	if (dev->has_sram && dev->got_sram)
-		sram_deinit(dev);
-
-	/* set device power state */
-	pci_set_power_state(pdev, PCI_D3hot);
-
-	/* enter PHY low power suspend */
-	if (dev->pdev->device != 0x0829)
-		langwell_phy_low_power(dev, 1);
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-
-/* device controller resume */
-static int langwell_udc_resume(struct pci_dev *pdev)
-{
-	struct langwell_udc	*dev = pci_get_drvdata(pdev);
-	size_t			size;
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* exit PHY low power suspend */
-	if (dev->pdev->device != 0x0829)
-		langwell_phy_low_power(dev, 0);
-
-	/* set device D0 power state */
-	pci_set_power_state(pdev, PCI_D0);
-
-	/* enable SRAM caching if detected */
-	if (dev->has_sram && !dev->got_sram)
-		sram_init(dev);
-
-	/* allocate device dQH memory */
-	size = dev->ep_max * sizeof(struct langwell_dqh);
-	dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
-	if (size < DQH_ALIGNMENT)
-		size = DQH_ALIGNMENT;
-	else if ((size % DQH_ALIGNMENT) != 0) {
-		size += DQH_ALIGNMENT + 1;
-		size &= ~(DQH_ALIGNMENT - 1);
-	}
-	dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
-					&dev->ep_dqh_dma, GFP_KERNEL);
-	if (!dev->ep_dqh) {
-		dev_err(&dev->pdev->dev, "allocate dQH memory failed\n");
-		return -ENOMEM;
-	}
-	dev->ep_dqh_size = size;
-	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
-
-	/* create dTD dma_pool resource */
-	dev->dtd_pool = dma_pool_create("langwell_dtd",
-			&dev->pdev->dev,
-			sizeof(struct langwell_dtd),
-			DTD_ALIGNMENT,
-			DMA_BOUNDARY);
-
-	if (!dev->dtd_pool)
-		return -ENOMEM;
-
-	/* restore PCI state */
-	pci_restore_state(pdev);
-
-	/* enable IRQ handler */
-	if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED,
-				driver_name, dev) != 0) {
-		dev_err(&dev->pdev->dev, "request interrupt %d failed\n",
-				pdev->irq);
-		return -EBUSY;
-	}
-	dev->got_irq = 1;
-
-	/* reset and start controller to run state */
-	if (dev->stopped) {
-		/* reset device controller */
-		langwell_udc_reset(dev);
-
-		/* reset ep0 dQH and endptctrl */
-		ep0_reset(dev);
-
-		/* start device if gadget is loaded */
-		if (dev->driver)
-			langwell_udc_start(dev);
-	}
-
-	/* reset USB status */
-	dev->usb_state = USB_STATE_ATTACHED;
-	dev->ep0_state = WAIT_FOR_SETUP;
-	dev->ep0_dir = USB_DIR_OUT;
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-	return 0;
-}
-
-
-/* pci driver shutdown */
-static void langwell_udc_shutdown(struct pci_dev *pdev)
-{
-	struct langwell_udc	*dev = pci_get_drvdata(pdev);
-	u32			usbmode;
-
-	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-	/* reset controller mode to IDLE */
-	usbmode = readl(&dev->op_regs->usbmode);
-	dev_dbg(&dev->pdev->dev, "usbmode = 0x%08x\n", usbmode);
-	usbmode &= (~3 | MODE_IDLE);
-	writel(usbmode, &dev->op_regs->usbmode);
-
-	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static const struct pci_device_id pci_ids[] = { {
-	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
-	.class_mask =	~0,
-	.vendor =	0x8086,
-	.device =	0x0811,
-	.subvendor =	PCI_ANY_ID,
-	.subdevice =	PCI_ANY_ID,
-}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
-
-static struct pci_driver langwell_pci_driver = {
-	.name =		(char *) driver_name,
-	.id_table =	pci_ids,
-
-	.probe =	langwell_udc_probe,
-	.remove =	langwell_udc_remove,
-
-	/* device controller suspend/resume */
-	.suspend =	langwell_udc_suspend,
-	.resume =	langwell_udc_resume,
-
-	.shutdown =	langwell_udc_shutdown,
-};
-
-
-static int __init init(void)
-{
-	return pci_register_driver(&langwell_pci_driver);
-}
-module_init(init);
-
-
-static void __exit cleanup(void)
-{
-	pci_unregister_driver(&langwell_pci_driver);
-}
-module_exit(cleanup);
-
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Xiaochen Shen <xiaochen.shen@intel.com>");
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h
deleted file mode 100644
index 8c8087a..0000000
--- a/drivers/usb/gadget/langwell_udc.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Intel Langwell USB Device Controller driver
- * Copyright (C) 2008-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.
- */
-
-#include <linux/usb/langwell_udc.h>
-
-/*-------------------------------------------------------------------------*/
-
-/* driver data structures and utilities */
-
-/*
- * dTD: Device Endpoint Transfer Descriptor
- * describe to the device controller the location and quantity of
- * data to be send/received for given transfer
- */
-struct langwell_dtd {
-	u32	dtd_next;
-/* bits 31:5, next transfer element pointer */
-#define	DTD_NEXT(d)	(((d)>>5)&0x7ffffff)
-#define	DTD_NEXT_MASK	(0x7ffffff << 5)
-/* terminate */
-#define	DTD_TERM	BIT(0)
-	/* bits 7:0, execution back states */
-	u32	dtd_status:8;
-#define	DTD_STATUS(d)	(((d)>>0)&0xff)
-#define	DTD_STS_ACTIVE	BIT(7)	/* active */
-#define	DTD_STS_HALTED	BIT(6)	/* halted */
-#define	DTD_STS_DBE	BIT(5)	/* data buffer error */
-#define	DTD_STS_TRE	BIT(3)	/* transaction error  */
-	/* bits 9:8 */
-	u32	dtd_res0:2;
-	/* bits 11:10, multipier override */
-	u32	dtd_multo:2;
-#define	DTD_MULTO	(BIT(11) | BIT(10))
-	/* bits 14:12 */
-	u32	dtd_res1:3;
-	/* bit 15, interrupt on complete */
-	u32	dtd_ioc:1;
-#define	DTD_IOC		BIT(15)
-	/* bits 30:16, total bytes */
-	u32	dtd_total:15;
-#define	DTD_TOTAL(d)	(((d)>>16)&0x7fff)
-#define	DTD_MAX_TRANSFER_LENGTH	0x4000
-	/* bit 31 */
-	u32	dtd_res2:1;
-	/* dTD buffer pointer page 0 to 4 */
-	u32	dtd_buf[5];
-#define	DTD_OFFSET_MASK	0xfff
-/* bits 31:12, buffer pointer */
-#define	DTD_BUFFER(d)	(((d)>>12)&0x3ff)
-/* bits 11:0, current offset */
-#define	DTD_C_OFFSET(d)	(((d)>>0)&0xfff)
-/* bits 10:0, frame number */
-#define	DTD_FRAME(d)	(((d)>>0)&0x7ff)
-
-	/* driver-private parts */
-
-	/* dtd dma address */
-	dma_addr_t		dtd_dma;
-	/* next dtd virtual address */
-	struct langwell_dtd	*next_dtd_virt;
-};
-
-
-/*
- * dQH: Device Endpoint Queue Head
- * describe where all transfers are managed
- * 48-byte data structure, aligned on 64-byte boundary
- *
- * These are associated with dTD structure
- */
-struct langwell_dqh {
-	/* endpoint capabilities and characteristics */
-	u32	dqh_res0:15;	/* bits 14:0 */
-	u32	dqh_ios:1;	/* bit 15, interrupt on setup */
-#define	DQH_IOS		BIT(15)
-	u32	dqh_mpl:11;	/* bits 26:16, maximum packet length */
-#define	DQH_MPL		(0x7ff << 16)
-	u32	dqh_res1:2;	/* bits 28:27 */
-	u32	dqh_zlt:1;	/* bit 29, zero length termination */
-#define	DQH_ZLT		BIT(29)
-	u32	dqh_mult:2;	/* bits 31:30 */
-#define	DQH_MULT	(BIT(30) | BIT(31))
-
-	/* current dTD pointer */
-	u32	dqh_current;	/* locate the transfer in progress */
-#define DQH_C_DTD(e)	\
-	(((e)>>5)&0x7ffffff)	/* bits 31:5, current dTD pointer */
-
-	/* transfer overlay, hardware parts of a struct langwell_dtd */
-	u32	dtd_next;
-	u32	dtd_status:8;	/* bits 7:0, execution back states */
-	u32	dtd_res0:2;	/* bits 9:8 */
-	u32	dtd_multo:2;	/* bits 11:10, multipier override */
-	u32	dtd_res1:3;	/* bits 14:12 */
-	u32	dtd_ioc:1;	/* bit 15, interrupt on complete */
-	u32	dtd_total:15;	/* bits 30:16, total bytes */
-	u32	dtd_res2:1;	/* bit 31 */
-	u32	dtd_buf[5];	/* dTD buffer pointer page 0 to 4 */
-
-	u32	dqh_res2;
-	struct usb_ctrlrequest	dqh_setup;	/* setup packet buffer */
-} __attribute__ ((aligned(64)));
-
-
-/* endpoint data structure */
-struct langwell_ep {
-	struct usb_ep		ep;
-	dma_addr_t		dma;
-	struct langwell_udc	*dev;
-	unsigned long		irqs;
-	struct list_head	queue;
-	struct langwell_dqh	*dqh;
-	const struct usb_endpoint_descriptor	*desc;
-	char			name[14];
-	unsigned		stopped:1,
-				ep_type:2,
-				ep_num:8;
-};
-
-
-/* request data structure */
-struct langwell_request {
-	struct usb_request	req;
-	struct langwell_dtd	*dtd, *head, *tail;
-	struct langwell_ep	*ep;
-	dma_addr_t		dtd_dma;
-	struct list_head	queue;
-	unsigned		dtd_count;
-	unsigned		mapped:1;
-};
-
-
-/* ep0 transfer state */
-enum ep0_state {
-	WAIT_FOR_SETUP,
-	DATA_STATE_XMIT,
-	DATA_STATE_NEED_ZLP,
-	WAIT_FOR_OUT_STATUS,
-	DATA_STATE_RECV,
-};
-
-
-/* device suspend state */
-enum lpm_state {
-	LPM_L0,	/* on */
-	LPM_L1,	/* LPM L1 sleep */
-	LPM_L2,	/* suspend */
-	LPM_L3,	/* off */
-};
-
-
-/* device data structure */
-struct langwell_udc {
-	/* each pci device provides one gadget, several endpoints */
-	struct usb_gadget	gadget;
-	spinlock_t		lock;	/* device lock */
-	struct langwell_ep	*ep;
-	struct usb_gadget_driver	*driver;
-	struct usb_phy		*transceiver;
-	u8			dev_addr;
-	u32			usb_state;
-	u32			resume_state;
-	u32			bus_reset;
-	enum lpm_state		lpm_state;
-	enum ep0_state		ep0_state;
-	u32			ep0_dir;
-	u16			dciversion;
-	unsigned		ep_max;
-	unsigned		devcap:1,
-				enabled:1,
-				region:1,
-				got_irq:1,
-				powered:1,
-				remote_wakeup:1,
-				rate:1,
-				is_reset:1,
-				softconnected:1,
-				vbus_active:1,
-				suspended:1,
-				stopped:1,
-				lpm:1,		/* LPM capability */
-				has_sram:1,	/* SRAM caching */
-				got_sram:1;
-
-	/* pci state used to access those endpoints */
-	struct pci_dev		*pdev;
-
-	/* Langwell otg transceiver */
-	struct langwell_otg	*lotg;
-
-	/* control registers */
-	struct langwell_cap_regs	__iomem	*cap_regs;
-	struct langwell_op_regs		__iomem	*op_regs;
-
-	struct usb_ctrlrequest	local_setup_buff;
-	struct langwell_dqh	*ep_dqh;
-	size_t			ep_dqh_size;
-	dma_addr_t		ep_dqh_dma;
-
-	/* ep0 status request */
-	struct langwell_request	*status_req;
-
-	/* dma pool */
-	struct dma_pool		*dtd_pool;
-
-	/* make sure release() is done */
-	struct completion	*done;
-
-	/* for private SRAM caching */
-	unsigned int		sram_addr;
-	unsigned int		sram_size;
-
-	/* device status data for get_status request */
-	u16			dev_status;
-};
-
-#define gadget_to_langwell(g)	container_of((g), struct langwell_udc, gadget)
-
diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c
new file mode 100644
index 0000000..262acfd
--- /dev/null
+++ b/drivers/usb/gadget/lpc32xx_udc.c
@@ -0,0 +1,3538 @@
+/*
+ * USB Gadget driver for LPC32xx
+ *
+ * Authors:
+ *    Kevin Wells <kevin.wells@nxp.com>
+ *    Mike James
+ *    Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2006 Philips Semiconductors
+ * Copyright (C) 2009 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Note: This driver is based on original work done by Mike James for
+ *       the LPC3180.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/i2c.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/usb/isp1301.h>
+
+#include <asm/byteorder.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <mach/platform.h>
+#include <mach/irqs.h>
+#include <mach/board.h>
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+#include <linux/seq_file.h>
+#endif
+
+/*
+ * USB device configuration structure
+ */
+typedef void (*usc_chg_event)(int);
+struct lpc32xx_usbd_cfg {
+	int vbus_drv_pol;   /* 0=active low drive for VBUS via ISP1301 */
+	usc_chg_event conn_chgb; /* Connection change event (optional) */
+	usc_chg_event susp_chgb; /* Suspend/resume event (optional) */
+	usc_chg_event rmwk_chgb; /* Enable/disable remote wakeup */
+};
+
+/*
+ * controller driver data structures
+ */
+
+/* 16 endpoints (not to be confused with 32 hardware endpoints) */
+#define	NUM_ENDPOINTS	16
+
+/*
+ * IRQ indices make reading the code a little easier
+ */
+#define IRQ_USB_LP	0
+#define IRQ_USB_HP	1
+#define IRQ_USB_DEVDMA	2
+#define IRQ_USB_ATX	3
+
+#define EP_OUT 0 /* RX (from host) */
+#define EP_IN 1 /* TX (to host) */
+
+/* Returns the interrupt mask for the selected hardware endpoint */
+#define EP_MASK_SEL(ep, dir) (1 << (((ep) * 2) + dir))
+
+#define EP_INT_TYPE 0
+#define EP_ISO_TYPE 1
+#define EP_BLK_TYPE 2
+#define EP_CTL_TYPE 3
+
+/* EP0 states */
+#define WAIT_FOR_SETUP 0 /* Wait for setup packet */
+#define DATA_IN        1 /* Expect dev->host transfer */
+#define DATA_OUT       2 /* Expect host->dev transfer */
+
+/* DD (DMA Descriptor) structure, requires word alignment, this is already
+ * defined in the LPC32XX USB device header file, but this version is slightly
+ * modified to tag some work data with each DMA descriptor. */
+struct lpc32xx_usbd_dd_gad {
+	u32 dd_next_phy;
+	u32 dd_setup;
+	u32 dd_buffer_addr;
+	u32 dd_status;
+	u32 dd_iso_ps_mem_addr;
+	u32 this_dma;
+	u32 iso_status[6]; /* 5 spare */
+	u32 dd_next_v;
+};
+
+/*
+ * Logical endpoint structure
+ */
+struct lpc32xx_ep {
+	struct usb_ep		ep;
+	struct list_head	queue;
+	struct lpc32xx_udc	*udc;
+
+	u32			hwep_num_base; /* Physical hardware EP */
+	u32			hwep_num; /* Maps to hardware endpoint */
+	u32			maxpacket;
+	u32			lep;
+
+	bool			is_in;
+	bool			req_pending;
+	u32			eptype;
+
+	u32                     totalints;
+
+	bool			wedge;
+
+	const struct usb_endpoint_descriptor *desc;
+};
+
+/*
+ * Common UDC structure
+ */
+struct lpc32xx_udc {
+	struct usb_gadget	gadget;
+	struct usb_gadget_driver *driver;
+	struct platform_device	*pdev;
+	struct device		*dev;
+	struct dentry		*pde;
+	spinlock_t		lock;
+	struct i2c_client	*isp1301_i2c_client;
+
+	/* Board and device specific */
+	struct lpc32xx_usbd_cfg	*board;
+	u32			io_p_start;
+	u32			io_p_size;
+	void __iomem		*udp_baseaddr;
+	int			udp_irq[4];
+	struct clk		*usb_pll_clk;
+	struct clk		*usb_slv_clk;
+
+	/* DMA support */
+	u32			*udca_v_base;
+	u32			udca_p_base;
+	struct dma_pool		*dd_cache;
+
+	/* Common EP and control data */
+	u32			enabled_devints;
+	u32			enabled_hwepints;
+	u32			dev_status;
+	u32			realized_eps;
+
+	/* VBUS detection, pullup, and power flags */
+	u8			vbus;
+	u8			last_vbus;
+	int			pullup;
+	int			poweron;
+
+	/* Work queues related to I2C support */
+	struct work_struct	pullup_job;
+	struct work_struct	vbus_job;
+	struct work_struct	power_job;
+
+	/* USB device peripheral - various */
+	struct lpc32xx_ep	ep[NUM_ENDPOINTS];
+	bool			enabled;
+	bool			clocked;
+	bool			suspended;
+	bool			selfpowered;
+	int                     ep0state;
+	atomic_t                enabled_ep_cnt;
+	wait_queue_head_t       ep_disable_wait_queue;
+};
+
+/*
+ * Endpoint request
+ */
+struct lpc32xx_request {
+	struct usb_request	req;
+	struct list_head	queue;
+	struct lpc32xx_usbd_dd_gad *dd_desc_ptr;
+	bool			mapped;
+	bool			send_zlp;
+};
+
+static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g)
+{
+	return container_of(g, struct lpc32xx_udc, gadget);
+}
+
+#define ep_dbg(epp, fmt, arg...) \
+	dev_dbg(epp->udc->dev, "%s: " fmt, __func__, ## arg)
+#define ep_err(epp, fmt, arg...) \
+	dev_err(epp->udc->dev, "%s: " fmt, __func__, ## arg)
+#define ep_info(epp, fmt, arg...) \
+	dev_info(epp->udc->dev, "%s: " fmt, __func__, ## arg)
+#define ep_warn(epp, fmt, arg...) \
+	dev_warn(epp->udc->dev, "%s:" fmt, __func__, ## arg)
+
+#define UDCA_BUFF_SIZE (128)
+
+/* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will
+ * be replaced with an inremap()ed pointer, see USB_OTG_CLK_CTRL()
+ * */
+#define USB_CTRL		IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64)
+#define USB_CLOCK_MASK		(AHB_M_CLOCK_ON | OTG_CLOCK_ON | \
+				 DEV_CLOCK_ON | I2C_CLOCK_ON)
+
+/* USB_CTRL bit defines */
+#define USB_SLAVE_HCLK_EN	(1 << 24)
+#define USB_HOST_NEED_CLK_EN	(1 << 21)
+#define USB_DEV_NEED_CLK_EN	(1 << 22)
+
+#define USB_OTG_CLK_CTRL(udc)	((udc)->udp_baseaddr + 0xFF4)
+#define USB_OTG_CLK_STAT(udc)	((udc)->udp_baseaddr + 0xFF8)
+
+/* USB_OTG_CLK_CTRL bit defines */
+#define AHB_M_CLOCK_ON		(1 << 4)
+#define OTG_CLOCK_ON		(1 << 3)
+#define I2C_CLOCK_ON		(1 << 2)
+#define DEV_CLOCK_ON		(1 << 1)
+#define HOST_CLOCK_ON		(1 << 0)
+
+#define USB_OTG_STAT_CONTROL(udc) (udc->udp_baseaddr + 0x110)
+
+/* USB_OTG_STAT_CONTROL bit defines */
+#define TRANSPARENT_I2C_EN	(1 << 7)
+#define HOST_EN			(1 << 0)
+
+/**********************************************************************
+ * USB device controller register offsets
+ **********************************************************************/
+
+#define USBD_DEVINTST(x)	((x) + 0x200)
+#define USBD_DEVINTEN(x)	((x) + 0x204)
+#define USBD_DEVINTCLR(x)	((x) + 0x208)
+#define USBD_DEVINTSET(x)	((x) + 0x20C)
+#define USBD_CMDCODE(x)		((x) + 0x210)
+#define USBD_CMDDATA(x)		((x) + 0x214)
+#define USBD_RXDATA(x)		((x) + 0x218)
+#define USBD_TXDATA(x)		((x) + 0x21C)
+#define USBD_RXPLEN(x)		((x) + 0x220)
+#define USBD_TXPLEN(x)		((x) + 0x224)
+#define USBD_CTRL(x)		((x) + 0x228)
+#define USBD_DEVINTPRI(x)	((x) + 0x22C)
+#define USBD_EPINTST(x)		((x) + 0x230)
+#define USBD_EPINTEN(x)		((x) + 0x234)
+#define USBD_EPINTCLR(x)	((x) + 0x238)
+#define USBD_EPINTSET(x)	((x) + 0x23C)
+#define USBD_EPINTPRI(x)	((x) + 0x240)
+#define USBD_REEP(x)		((x) + 0x244)
+#define USBD_EPIND(x)		((x) + 0x248)
+#define USBD_EPMAXPSIZE(x)	((x) + 0x24C)
+/* DMA support registers only below */
+/* Set, clear, or get enabled state of the DMA request status. If
+ * enabled, an IN or OUT token will start a DMA transfer for the EP */
+#define USBD_DMARST(x)		((x) + 0x250)
+#define USBD_DMARCLR(x)		((x) + 0x254)
+#define USBD_DMARSET(x)		((x) + 0x258)
+/* DMA UDCA head pointer */
+#define USBD_UDCAH(x)		((x) + 0x280)
+/* EP DMA status, enable, and disable. This is used to specifically
+ * enabled or disable DMA for a specific EP */
+#define USBD_EPDMAST(x)		((x) + 0x284)
+#define USBD_EPDMAEN(x)		((x) + 0x288)
+#define USBD_EPDMADIS(x)	((x) + 0x28C)
+/* DMA master interrupts enable and pending interrupts */
+#define USBD_DMAINTST(x)	((x) + 0x290)
+#define USBD_DMAINTEN(x)	((x) + 0x294)
+/* DMA end of transfer interrupt enable, disable, status */
+#define USBD_EOTINTST(x)	((x) + 0x2A0)
+#define USBD_EOTINTCLR(x)	((x) + 0x2A4)
+#define USBD_EOTINTSET(x)	((x) + 0x2A8)
+/* New DD request interrupt enable, disable, status */
+#define USBD_NDDRTINTST(x)	((x) + 0x2AC)
+#define USBD_NDDRTINTCLR(x)	((x) + 0x2B0)
+#define USBD_NDDRTINTSET(x)	((x) + 0x2B4)
+/* DMA error interrupt enable, disable, status */
+#define USBD_SYSERRTINTST(x)	((x) + 0x2B8)
+#define USBD_SYSERRTINTCLR(x)	((x) + 0x2BC)
+#define USBD_SYSERRTINTSET(x)	((x) + 0x2C0)
+
+/**********************************************************************
+ * USBD_DEVINTST/USBD_DEVINTEN/USBD_DEVINTCLR/USBD_DEVINTSET/
+ * USBD_DEVINTPRI register definitions
+ **********************************************************************/
+#define USBD_ERR_INT		(1 << 9)
+#define USBD_EP_RLZED		(1 << 8)
+#define USBD_TXENDPKT		(1 << 7)
+#define USBD_RXENDPKT		(1 << 6)
+#define USBD_CDFULL		(1 << 5)
+#define USBD_CCEMPTY		(1 << 4)
+#define USBD_DEV_STAT		(1 << 3)
+#define USBD_EP_SLOW		(1 << 2)
+#define USBD_EP_FAST		(1 << 1)
+#define USBD_FRAME		(1 << 0)
+
+/**********************************************************************
+ * USBD_EPINTST/USBD_EPINTEN/USBD_EPINTCLR/USBD_EPINTSET/
+ * USBD_EPINTPRI register definitions
+ **********************************************************************/
+/* End point selection macro (RX) */
+#define USBD_RX_EP_SEL(e)	(1 << ((e) << 1))
+
+/* End point selection macro (TX) */
+#define USBD_TX_EP_SEL(e)	(1 << (((e) << 1) + 1))
+
+/**********************************************************************
+ * USBD_REEP/USBD_DMARST/USBD_DMARCLR/USBD_DMARSET/USBD_EPDMAST/
+ * USBD_EPDMAEN/USBD_EPDMADIS/
+ * USBD_NDDRTINTST/USBD_NDDRTINTCLR/USBD_NDDRTINTSET/
+ * USBD_EOTINTST/USBD_EOTINTCLR/USBD_EOTINTSET/
+ * USBD_SYSERRTINTST/USBD_SYSERRTINTCLR/USBD_SYSERRTINTSET
+ * register definitions
+ **********************************************************************/
+/* Endpoint selection macro */
+#define USBD_EP_SEL(e)		(1 << (e))
+
+/**********************************************************************
+ * SBD_DMAINTST/USBD_DMAINTEN
+ **********************************************************************/
+#define USBD_SYS_ERR_INT	(1 << 2)
+#define USBD_NEW_DD_INT		(1 << 1)
+#define USBD_EOT_INT		(1 << 0)
+
+/**********************************************************************
+ * USBD_RXPLEN register definitions
+ **********************************************************************/
+#define USBD_PKT_RDY		(1 << 11)
+#define USBD_DV			(1 << 10)
+#define USBD_PK_LEN_MASK	0x3FF
+
+/**********************************************************************
+ * USBD_CTRL register definitions
+ **********************************************************************/
+#define USBD_LOG_ENDPOINT(e)	((e) << 2)
+#define USBD_WR_EN		(1 << 1)
+#define USBD_RD_EN		(1 << 0)
+
+/**********************************************************************
+ * USBD_CMDCODE register definitions
+ **********************************************************************/
+#define USBD_CMD_CODE(c)	((c) << 16)
+#define USBD_CMD_PHASE(p)	((p) << 8)
+
+/**********************************************************************
+ * USBD_DMARST/USBD_DMARCLR/USBD_DMARSET register definitions
+ **********************************************************************/
+#define USBD_DMAEP(e)		(1 << (e))
+
+/* DD (DMA Descriptor) structure, requires word alignment */
+struct lpc32xx_usbd_dd {
+	u32 *dd_next;
+	u32 dd_setup;
+	u32 dd_buffer_addr;
+	u32 dd_status;
+	u32 dd_iso_ps_mem_addr;
+};
+
+/* dd_setup bit defines */
+#define DD_SETUP_ATLE_DMA_MODE	0x01
+#define DD_SETUP_NEXT_DD_VALID	0x04
+#define DD_SETUP_ISO_EP		0x10
+#define DD_SETUP_PACKETLEN(n)	(((n) & 0x7FF) << 5)
+#define DD_SETUP_DMALENBYTES(n)	(((n) & 0xFFFF) << 16)
+
+/* dd_status bit defines */
+#define DD_STATUS_DD_RETIRED	0x01
+#define DD_STATUS_STS_MASK	0x1E
+#define DD_STATUS_STS_NS	0x00 /* Not serviced */
+#define DD_STATUS_STS_BS	0x02 /* Being serviced */
+#define DD_STATUS_STS_NC	0x04 /* Normal completion */
+#define DD_STATUS_STS_DUR	0x06 /* Data underrun (short packet) */
+#define DD_STATUS_STS_DOR	0x08 /* Data overrun */
+#define DD_STATUS_STS_SE	0x12 /* System error */
+#define DD_STATUS_PKT_VAL	0x20 /* Packet valid */
+#define DD_STATUS_LSB_EX	0x40 /* LS byte extracted (ATLE) */
+#define DD_STATUS_MSB_EX	0x80 /* MS byte extracted (ATLE) */
+#define DD_STATUS_MLEN(n)	(((n) >> 8) & 0x3F)
+#define DD_STATUS_CURDMACNT(n)	(((n) >> 16) & 0xFFFF)
+
+/*
+ *
+ * Protocol engine bits below
+ *
+ */
+/* Device Interrupt Bit Definitions */
+#define FRAME_INT		0x00000001
+#define EP_FAST_INT		0x00000002
+#define EP_SLOW_INT		0x00000004
+#define DEV_STAT_INT		0x00000008
+#define CCEMTY_INT		0x00000010
+#define CDFULL_INT		0x00000020
+#define RxENDPKT_INT		0x00000040
+#define TxENDPKT_INT		0x00000080
+#define EP_RLZED_INT		0x00000100
+#define ERR_INT			0x00000200
+
+/* Rx & Tx Packet Length Definitions */
+#define PKT_LNGTH_MASK		0x000003FF
+#define PKT_DV			0x00000400
+#define PKT_RDY			0x00000800
+
+/* USB Control Definitions */
+#define CTRL_RD_EN		0x00000001
+#define CTRL_WR_EN		0x00000002
+
+/* Command Codes */
+#define CMD_SET_ADDR		0x00D00500
+#define CMD_CFG_DEV		0x00D80500
+#define CMD_SET_MODE		0x00F30500
+#define CMD_RD_FRAME		0x00F50500
+#define DAT_RD_FRAME		0x00F50200
+#define CMD_RD_TEST		0x00FD0500
+#define DAT_RD_TEST		0x00FD0200
+#define CMD_SET_DEV_STAT	0x00FE0500
+#define CMD_GET_DEV_STAT	0x00FE0500
+#define DAT_GET_DEV_STAT	0x00FE0200
+#define CMD_GET_ERR_CODE	0x00FF0500
+#define DAT_GET_ERR_CODE	0x00FF0200
+#define CMD_RD_ERR_STAT		0x00FB0500
+#define DAT_RD_ERR_STAT		0x00FB0200
+#define DAT_WR_BYTE(x)		(0x00000100 | ((x) << 16))
+#define CMD_SEL_EP(x)		(0x00000500 | ((x) << 16))
+#define DAT_SEL_EP(x)		(0x00000200 | ((x) << 16))
+#define CMD_SEL_EP_CLRI(x)	(0x00400500 | ((x) << 16))
+#define DAT_SEL_EP_CLRI(x)	(0x00400200 | ((x) << 16))
+#define CMD_SET_EP_STAT(x)	(0x00400500 | ((x) << 16))
+#define CMD_CLR_BUF		0x00F20500
+#define DAT_CLR_BUF		0x00F20200
+#define CMD_VALID_BUF		0x00FA0500
+
+/* Device Address Register Definitions */
+#define DEV_ADDR_MASK		0x7F
+#define DEV_EN			0x80
+
+/* Device Configure Register Definitions */
+#define CONF_DVICE		0x01
+
+/* Device Mode Register Definitions */
+#define AP_CLK			0x01
+#define INAK_CI			0x02
+#define INAK_CO			0x04
+#define INAK_II			0x08
+#define INAK_IO			0x10
+#define INAK_BI			0x20
+#define INAK_BO			0x40
+
+/* Device Status Register Definitions */
+#define DEV_CON			0x01
+#define DEV_CON_CH		0x02
+#define DEV_SUS			0x04
+#define DEV_SUS_CH		0x08
+#define DEV_RST			0x10
+
+/* Error Code Register Definitions */
+#define ERR_EC_MASK		0x0F
+#define ERR_EA			0x10
+
+/* Error Status Register Definitions */
+#define ERR_PID			0x01
+#define ERR_UEPKT		0x02
+#define ERR_DCRC		0x04
+#define ERR_TIMOUT		0x08
+#define ERR_EOP			0x10
+#define ERR_B_OVRN		0x20
+#define ERR_BTSTF		0x40
+#define ERR_TGL			0x80
+
+/* Endpoint Select Register Definitions */
+#define EP_SEL_F		0x01
+#define EP_SEL_ST		0x02
+#define EP_SEL_STP		0x04
+#define EP_SEL_PO		0x08
+#define EP_SEL_EPN		0x10
+#define EP_SEL_B_1_FULL		0x20
+#define EP_SEL_B_2_FULL		0x40
+
+/* Endpoint Status Register Definitions */
+#define EP_STAT_ST		0x01
+#define EP_STAT_DA		0x20
+#define EP_STAT_RF_MO		0x40
+#define EP_STAT_CND_ST		0x80
+
+/* Clear Buffer Register Definitions */
+#define CLR_BUF_PO		0x01
+
+/* DMA Interrupt Bit Definitions */
+#define EOT_INT			0x01
+#define NDD_REQ_INT		0x02
+#define SYS_ERR_INT		0x04
+
+#define	DRIVER_VERSION	"1.03"
+static const char driver_name[] = "lpc32xx_udc";
+
+/*
+ *
+ * proc interface support
+ *
+ */
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+static char *epnames[] = {"INT", "ISO", "BULK", "CTRL"};
+static const char debug_filename[] = "driver/udc";
+
+static void proc_ep_show(struct seq_file *s, struct lpc32xx_ep *ep)
+{
+	struct lpc32xx_request *req;
+
+	seq_printf(s, "\n");
+	seq_printf(s, "%12s, maxpacket %4d %3s",
+			ep->ep.name, ep->ep.maxpacket,
+			ep->is_in ? "in" : "out");
+	seq_printf(s, " type %4s", epnames[ep->eptype]);
+	seq_printf(s, " ints: %12d", ep->totalints);
+
+	if (list_empty(&ep->queue))
+		seq_printf(s, "\t(queue empty)\n");
+	else {
+		list_for_each_entry(req, &ep->queue, queue) {
+			u32 length = req->req.actual;
+
+			seq_printf(s, "\treq %p len %d/%d buf %p\n",
+				   &req->req, length,
+				   req->req.length, req->req.buf);
+		}
+	}
+}
+
+static int proc_udc_show(struct seq_file *s, void *unused)
+{
+	struct lpc32xx_udc *udc = s->private;
+	struct lpc32xx_ep *ep;
+	unsigned long flags;
+
+	seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n",
+		   udc->vbus ? "present" : "off",
+		   udc->enabled ? (udc->vbus ? "active" : "enabled") :
+		   "disabled",
+		   udc->selfpowered ? "self" : "VBUS",
+		   udc->suspended ? ", suspended" : "",
+		   udc->driver ? udc->driver->driver.name : "(none)");
+
+	if (udc->enabled && udc->vbus) {
+		proc_ep_show(s, &udc->ep[0]);
+		list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+			if (ep->desc)
+				proc_ep_show(s, ep);
+		}
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static int proc_udc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_udc_show, PDE(inode)->data);
+}
+
+static const struct file_operations proc_ops = {
+	.owner		= THIS_MODULE,
+	.open		= proc_udc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void create_debug_file(struct lpc32xx_udc *udc)
+{
+	udc->pde = debugfs_create_file(debug_filename, 0, NULL, udc, &proc_ops);
+}
+
+static void remove_debug_file(struct lpc32xx_udc *udc)
+{
+	if (udc->pde)
+		debugfs_remove(udc->pde);
+}
+
+#else
+static inline void create_debug_file(struct lpc32xx_udc *udc) {}
+static inline void remove_debug_file(struct lpc32xx_udc *udc) {}
+#endif
+
+/* Primary initialization sequence for the ISP1301 transceiver */
+static void isp1301_udc_configure(struct lpc32xx_udc *udc)
+{
+	/* LPC32XX only supports DAT_SE0 USB mode */
+	/* This sequence is important */
+
+	/* Disable transparent UART mode first */
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		(ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+		MC1_UART_EN);
+
+	/* Set full speed and SE0 mode */
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		(ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		ISP1301_I2C_MODE_CONTROL_1, (MC1_SPEED_REG | MC1_DAT_SE0));
+
+	/*
+	 * The PSW_OE enable bit state is reversed in the ISP1301 User's Guide
+	 */
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		(ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_SPD_SUSP_CTRL));
+
+	/* Driver VBUS_DRV high or low depending on board setup */
+	if (udc->board->vbus_drv_pol != 0)
+		i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+			ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
+	else
+		i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+			ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+			OTG1_VBUS_DRV);
+
+	/* Bi-directional mode with suspend control
+	 * Enable both pulldowns for now - the pullup will be enable when VBUS
+	 * is detected */
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		(ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		ISP1301_I2C_OTG_CONTROL_1,
+		(0 | OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+
+	/* Discharge VBUS (just in case) */
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG);
+	msleep(1);
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		(ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+		OTG1_VBUS_DISCHRG);
+
+	/* Clear and enable VBUS high edge interrupt */
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_FALLING, INT_VBUS_VLD);
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+	i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD);
+
+	/* Enable usb_need_clk clock after transceiver is initialized */
+	writel((readl(USB_CTRL) | (1 << 22)), USB_CTRL);
+
+	dev_info(udc->dev, "ISP1301 Vendor ID  : 0x%04x\n",
+		 i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00));
+	dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n",
+		 i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02));
+	dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n",
+		 i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14));
+}
+
+/* Enables or disables the USB device pullup via the ISP1301 transceiver */
+static void isp1301_pullup_set(struct lpc32xx_udc *udc)
+{
+	if (udc->pullup)
+		/* Enable pullup for bus signalling */
+		i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+			ISP1301_I2C_OTG_CONTROL_1, OTG1_DP_PULLUP);
+	else
+		/* Enable pullup for bus signalling */
+		i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+			ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+			OTG1_DP_PULLUP);
+}
+
+static void pullup_work(struct work_struct *work)
+{
+	struct lpc32xx_udc *udc =
+		container_of(work, struct lpc32xx_udc, pullup_job);
+
+	isp1301_pullup_set(udc);
+}
+
+static void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup,
+				  int block)
+{
+	if (en_pullup == udc->pullup)
+		return;
+
+	udc->pullup = en_pullup;
+	if (block)
+		isp1301_pullup_set(udc);
+	else
+		/* defer slow i2c pull up setting */
+		schedule_work(&udc->pullup_job);
+}
+
+#ifdef CONFIG_PM
+/* Powers up or down the ISP1301 transceiver */
+static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable)
+{
+	if (enable != 0)
+		/* Power up ISP1301 - this ISP1301 will automatically wakeup
+		   when VBUS is detected */
+		i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+			ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR,
+			MC2_GLOBAL_PWR_DN);
+	else
+		/* Power down ISP1301 */
+		i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+			ISP1301_I2C_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
+}
+
+static void power_work(struct work_struct *work)
+{
+	struct lpc32xx_udc *udc =
+		container_of(work, struct lpc32xx_udc, power_job);
+
+	isp1301_set_powerstate(udc, udc->poweron);
+}
+#endif
+
+/*
+ *
+ * USB protocol engine command/data read/write helper functions
+ *
+ */
+/* Issues a single command to the USB device state machine */
+static void udc_protocol_cmd_w(struct lpc32xx_udc *udc, u32 cmd)
+{
+	u32 pass = 0;
+	int to;
+
+	/* EP may lock on CLRI if this read isn't done */
+	u32 tmp = readl(USBD_DEVINTST(udc->udp_baseaddr));
+	(void) tmp;
+
+	while (pass == 0) {
+		writel(USBD_CCEMPTY, USBD_DEVINTCLR(udc->udp_baseaddr));
+
+		/* Write command code */
+		writel(cmd, USBD_CMDCODE(udc->udp_baseaddr));
+		to = 10000;
+		while (((readl(USBD_DEVINTST(udc->udp_baseaddr)) &
+			 USBD_CCEMPTY) == 0) && (to > 0)) {
+			to--;
+		}
+
+		if (to > 0)
+			pass = 1;
+
+		cpu_relax();
+	}
+}
+
+/* Issues 2 commands (or command and data) to the USB device state machine */
+static inline void udc_protocol_cmd_data_w(struct lpc32xx_udc *udc, u32 cmd,
+					   u32 data)
+{
+	udc_protocol_cmd_w(udc, cmd);
+	udc_protocol_cmd_w(udc, data);
+}
+
+/* Issues a single command to the USB device state machine and reads
+ * response data */
+static u32 udc_protocol_cmd_r(struct lpc32xx_udc *udc, u32 cmd)
+{
+	u32 tmp;
+	int to = 1000;
+
+	/* Write a command and read data from the protocol engine */
+	writel((USBD_CDFULL | USBD_CCEMPTY),
+		     USBD_DEVINTCLR(udc->udp_baseaddr));
+
+	/* Write command code */
+	udc_protocol_cmd_w(udc, cmd);
+
+	tmp = readl(USBD_DEVINTST(udc->udp_baseaddr));
+	while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & USBD_CDFULL))
+	       && (to > 0))
+		to--;
+	if (!to)
+		dev_dbg(udc->dev,
+			"Protocol engine didn't receive response (CDFULL)\n");
+
+	return readl(USBD_CMDDATA(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * USB device interrupt mask support functions
+ *
+ */
+/* Enable one or more USB device interrupts */
+static inline void uda_enable_devint(struct lpc32xx_udc *udc, u32 devmask)
+{
+	udc->enabled_devints |= devmask;
+	writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr));
+}
+
+/* Disable one or more USB device interrupts */
+static inline void uda_disable_devint(struct lpc32xx_udc *udc, u32 mask)
+{
+	udc->enabled_devints &= ~mask;
+	writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr));
+}
+
+/* Clear one or more USB device interrupts */
+static inline void uda_clear_devint(struct lpc32xx_udc *udc, u32 mask)
+{
+	writel(mask, USBD_DEVINTCLR(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * Endpoint interrupt disable/enable functions
+ *
+ */
+/* Enable one or more USB endpoint interrupts */
+static void uda_enable_hwepint(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc->enabled_hwepints |= (1 << hwep);
+	writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr));
+}
+
+/* Disable one or more USB endpoint interrupts */
+static void uda_disable_hwepint(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc->enabled_hwepints &= ~(1 << hwep);
+	writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr));
+}
+
+/* Clear one or more USB endpoint interrupts */
+static inline void uda_clear_hwepint(struct lpc32xx_udc *udc, u32 hwep)
+{
+	writel((1 << hwep), USBD_EPINTCLR(udc->udp_baseaddr));
+}
+
+/* Enable DMA for the HW channel */
+static inline void udc_ep_dma_enable(struct lpc32xx_udc *udc, u32 hwep)
+{
+	writel((1 << hwep), USBD_EPDMAEN(udc->udp_baseaddr));
+}
+
+/* Disable DMA for the HW channel */
+static inline void udc_ep_dma_disable(struct lpc32xx_udc *udc, u32 hwep)
+{
+	writel((1 << hwep), USBD_EPDMADIS(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * Endpoint realize/unrealize functions
+ *
+ */
+/* Before an endpoint can be used, it needs to be realized
+ * in the USB protocol engine - this realizes the endpoint.
+ * The interrupt (FIFO or DMA) is not enabled with this function */
+static void udc_realize_hwep(struct lpc32xx_udc *udc, u32 hwep,
+			     u32 maxpacket)
+{
+	int to = 1000;
+
+	writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr));
+	writel(hwep, USBD_EPIND(udc->udp_baseaddr));
+	udc->realized_eps |= (1 << hwep);
+	writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr));
+	writel(maxpacket, USBD_EPMAXPSIZE(udc->udp_baseaddr));
+
+	/* Wait until endpoint is realized in hardware */
+	while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) &
+		  USBD_EP_RLZED)) && (to > 0))
+		to--;
+	if (!to)
+		dev_dbg(udc->dev, "EP not correctly realized in hardware\n");
+
+	writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr));
+}
+
+/* Unrealize an EP */
+static void udc_unrealize_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc->realized_eps &= ~(1 << hwep);
+	writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * Endpoint support functions
+ *
+ */
+/* Select and clear endpoint interrupt */
+static u32 udc_selep_clrint(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc_protocol_cmd_w(udc, CMD_SEL_EP_CLRI(hwep));
+	return udc_protocol_cmd_r(udc, DAT_SEL_EP_CLRI(hwep));
+}
+
+/* Disables the endpoint in the USB protocol engine */
+static void udc_disable_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep),
+				DAT_WR_BYTE(EP_STAT_DA));
+}
+
+/* Stalls the endpoint - endpoint will return STALL */
+static void udc_stall_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep),
+				DAT_WR_BYTE(EP_STAT_ST));
+}
+
+/* Clear stall or reset endpoint */
+static void udc_clrstall_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep),
+				DAT_WR_BYTE(0));
+}
+
+/* Select an endpoint for endpoint status, clear, validate */
+static void udc_select_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc_protocol_cmd_w(udc, CMD_SEL_EP(hwep));
+}
+
+/*
+ *
+ * Endpoint buffer management functions
+ *
+ */
+/* Clear the current endpoint's buffer */
+static void udc_clr_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc_select_hwep(udc, hwep);
+	udc_protocol_cmd_w(udc, CMD_CLR_BUF);
+}
+
+/* Validate the current endpoint's buffer */
+static void udc_val_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+	udc_select_hwep(udc, hwep);
+	udc_protocol_cmd_w(udc, CMD_VALID_BUF);
+}
+
+static inline u32 udc_clearep_getsts(struct lpc32xx_udc *udc, u32 hwep)
+{
+	/* Clear EP interrupt */
+	uda_clear_hwepint(udc, hwep);
+	return udc_selep_clrint(udc, hwep);
+}
+
+/*
+ *
+ * USB EP DMA support
+ *
+ */
+/* Allocate a DMA Descriptor */
+static struct lpc32xx_usbd_dd_gad *udc_dd_alloc(struct lpc32xx_udc *udc)
+{
+	dma_addr_t			dma;
+	struct lpc32xx_usbd_dd_gad	*dd;
+
+	dd = (struct lpc32xx_usbd_dd_gad *) dma_pool_alloc(
+			udc->dd_cache, (GFP_KERNEL | GFP_DMA), &dma);
+	if (dd)
+		dd->this_dma = dma;
+
+	return dd;
+}
+
+/* Free a DMA Descriptor */
+static void udc_dd_free(struct lpc32xx_udc *udc, struct lpc32xx_usbd_dd_gad *dd)
+{
+	dma_pool_free(udc->dd_cache, dd, dd->this_dma);
+}
+
+/*
+ *
+ * USB setup and shutdown functions
+ *
+ */
+/* Enables or disables most of the USB system clocks when low power mode is
+ * needed. Clocks are typically started on a connection event, and disabled
+ * when a cable is disconnected */
+#define OTGOFF_CLK_MASK (AHB_M_CLOCK_ON | I2C_CLOCK_ON)
+static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
+{
+	int to = 1000;
+
+	if (enable != 0) {
+		if (udc->clocked)
+			return;
+
+		udc->clocked = 1;
+
+		/* 48MHz PLL up */
+		clk_enable(udc->usb_pll_clk);
+
+		/* Enable the USB device clock */
+		writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN,
+			     USB_CTRL);
+
+		/* Set to enable all needed USB OTG clocks */
+		writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
+
+		while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
+			USB_CLOCK_MASK) && (to > 0))
+			to--;
+		if (!to)
+			dev_dbg(udc->dev, "Cannot enable USB OTG clocking\n");
+	} else {
+		if (!udc->clocked)
+			return;
+
+		udc->clocked = 0;
+
+		/* Never disable the USB_HCLK during normal operation */
+
+		/* 48MHz PLL dpwn */
+		clk_disable(udc->usb_pll_clk);
+
+		/* Enable the USB device clock */
+		writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN,
+			     USB_CTRL);
+
+		/* Set to enable all needed USB OTG clocks */
+		writel(OTGOFF_CLK_MASK, USB_OTG_CLK_CTRL(udc));
+
+		while (((readl(USB_OTG_CLK_STAT(udc)) &
+			 OTGOFF_CLK_MASK) !=
+			OTGOFF_CLK_MASK) && (to > 0))
+			to--;
+		if (!to)
+			dev_dbg(udc->dev, "Cannot disable USB OTG clocking\n");
+	}
+}
+
+/* Set/reset USB device address */
+static void udc_set_address(struct lpc32xx_udc *udc, u32 addr)
+{
+	/* Address will be latched at the end of the status phase, or
+	   latched immediately if function is called twice */
+	udc_protocol_cmd_data_w(udc, CMD_SET_ADDR,
+				DAT_WR_BYTE(DEV_EN | addr));
+}
+
+/* Setup up a IN request for DMA transfer - this consists of determining the
+ * list of DMA addresses for the transfer, allocating DMA Descriptors,
+ * installing the DD into the UDCA, and then enabling the DMA for that EP */
+static int udc_ep_in_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+	struct lpc32xx_request *req;
+	u32 hwep = ep->hwep_num;
+
+	ep->req_pending = 1;
+
+	/* There will always be a request waiting here */
+	req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+
+	/* Place the DD Descriptor into the UDCA */
+	udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma;
+
+	/* Enable DMA and interrupt for the HW EP */
+	udc_ep_dma_enable(udc, hwep);
+
+	/* Clear ZLP if last packet is not of MAXP size */
+	if (req->req.length % ep->ep.maxpacket)
+		req->send_zlp = 0;
+
+	return 0;
+}
+
+/* Setup up a OUT request for DMA transfer - this consists of determining the
+ * list of DMA addresses for the transfer, allocating DMA Descriptors,
+ * installing the DD into the UDCA, and then enabling the DMA for that EP */
+static int udc_ep_out_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+	struct lpc32xx_request *req;
+	u32 hwep = ep->hwep_num;
+
+	ep->req_pending = 1;
+
+	/* There will always be a request waiting here */
+	req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+
+	/* Place the DD Descriptor into the UDCA */
+	udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma;
+
+	/* Enable DMA and interrupt for the HW EP */
+	udc_ep_dma_enable(udc, hwep);
+	return 0;
+}
+
+static void udc_disable(struct lpc32xx_udc *udc)
+{
+	u32 i;
+
+	/* Disable device */
+	udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0));
+	udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(0));
+
+	/* Disable all device interrupts (including EP0) */
+	uda_disable_devint(udc, 0x3FF);
+
+	/* Disable and reset all endpoint interrupts */
+	for (i = 0; i < 32; i++) {
+		uda_disable_hwepint(udc, i);
+		uda_clear_hwepint(udc, i);
+		udc_disable_hwep(udc, i);
+		udc_unrealize_hwep(udc, i);
+		udc->udca_v_base[i] = 0;
+
+		/* Disable and clear all interrupts and DMA */
+		udc_ep_dma_disable(udc, i);
+		writel((1 << i), USBD_EOTINTCLR(udc->udp_baseaddr));
+		writel((1 << i), USBD_NDDRTINTCLR(udc->udp_baseaddr));
+		writel((1 << i), USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+		writel((1 << i), USBD_DMARCLR(udc->udp_baseaddr));
+	}
+
+	/* Disable DMA interrupts */
+	writel(0, USBD_DMAINTEN(udc->udp_baseaddr));
+
+	writel(0, USBD_UDCAH(udc->udp_baseaddr));
+}
+
+static void udc_enable(struct lpc32xx_udc *udc)
+{
+	u32 i;
+	struct lpc32xx_ep *ep = &udc->ep[0];
+
+	/* Start with known state */
+	udc_disable(udc);
+
+	/* Enable device */
+	udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON));
+
+	/* EP interrupts on high priority, FRAME interrupt on low priority */
+	writel(USBD_EP_FAST, USBD_DEVINTPRI(udc->udp_baseaddr));
+	writel(0xFFFF, USBD_EPINTPRI(udc->udp_baseaddr));
+
+	/* Clear any pending device interrupts */
+	writel(0x3FF, USBD_DEVINTCLR(udc->udp_baseaddr));
+
+	/* Setup UDCA - not yet used (DMA) */
+	writel(udc->udca_p_base, USBD_UDCAH(udc->udp_baseaddr));
+
+	/* Only enable EP0 in and out for now, EP0 only works in FIFO mode */
+	for (i = 0; i <= 1; i++) {
+		udc_realize_hwep(udc, i, ep->ep.maxpacket);
+		uda_enable_hwepint(udc, i);
+		udc_select_hwep(udc, i);
+		udc_clrstall_hwep(udc, i);
+		udc_clr_buffer_hwep(udc, i);
+	}
+
+	/* Device interrupt setup */
+	uda_clear_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW |
+			       USBD_EP_FAST));
+	uda_enable_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW |
+				USBD_EP_FAST));
+
+	/* Set device address to 0 - called twice to force a latch in the USB
+	   engine without the need of a setup packet status closure */
+	udc_set_address(udc, 0);
+	udc_set_address(udc, 0);
+
+	/* Enable master DMA interrupts */
+	writel((USBD_SYS_ERR_INT | USBD_EOT_INT),
+		     USBD_DMAINTEN(udc->udp_baseaddr));
+
+	udc->dev_status = 0;
+}
+
+/*
+ *
+ * USB device board specific events handled via callbacks
+ *
+ */
+/* Connection change event - notify board function of change */
+static void uda_power_event(struct lpc32xx_udc *udc, u32 conn)
+{
+	/* Just notify of a connection change event (optional) */
+	if (udc->board->conn_chgb != NULL)
+		udc->board->conn_chgb(conn);
+}
+
+/* Suspend/resume event - notify board function of change */
+static void uda_resm_susp_event(struct lpc32xx_udc *udc, u32 conn)
+{
+	/* Just notify of a Suspend/resume change event (optional) */
+	if (udc->board->susp_chgb != NULL)
+		udc->board->susp_chgb(conn);
+
+	if (conn)
+		udc->suspended = 0;
+	else
+		udc->suspended = 1;
+}
+
+/* Remote wakeup enable/disable - notify board function of change */
+static void uda_remwkp_cgh(struct lpc32xx_udc *udc)
+{
+	if (udc->board->rmwk_chgb != NULL)
+		udc->board->rmwk_chgb(udc->dev_status &
+				      (1 << USB_DEVICE_REMOTE_WAKEUP));
+}
+
+/* Reads data from FIFO, adjusts for alignment and data size */
+static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
+{
+	int n, i, bl;
+	u16 *p16;
+	u32 *p32, tmp, cbytes;
+
+	/* Use optimal data transfer method based on source address and size */
+	switch (((u32) data) & 0x3) {
+	case 0: /* 32-bit aligned */
+		p32 = (u32 *) data;
+		cbytes = (bytes & ~0x3);
+
+		/* Copy 32-bit aligned data first */
+		for (n = 0; n < cbytes; n += 4)
+			*p32++ = readl(USBD_RXDATA(udc->udp_baseaddr));
+
+		/* Handle any remaining bytes */
+		bl = bytes - cbytes;
+		if (bl) {
+			tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+			for (n = 0; n < bl; n++)
+				data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF);
+
+		}
+		break;
+
+	case 1: /* 8-bit aligned */
+	case 3:
+		/* Each byte has to be handled independently */
+		for (n = 0; n < bytes; n += 4) {
+			tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+
+			bl = bytes - n;
+			if (bl > 3)
+				bl = 3;
+
+			for (i = 0; i < bl; i++)
+				data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF);
+		}
+		break;
+
+	case 2: /* 16-bit aligned */
+		p16 = (u16 *) data;
+		cbytes = (bytes & ~0x3);
+
+		/* Copy 32-bit sized objects first with 16-bit alignment */
+		for (n = 0; n < cbytes; n += 4) {
+			tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+			*p16++ = (u16)(tmp & 0xFFFF);
+			*p16++ = (u16)((tmp >> 16) & 0xFFFF);
+		}
+
+		/* Handle any remaining bytes */
+		bl = bytes - cbytes;
+		if (bl) {
+			tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+			for (n = 0; n < bl; n++)
+				data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF);
+		}
+		break;
+	}
+}
+
+/* Read data from the FIFO for an endpoint. This function is for endpoints (such
+ * as EP0) that don't use DMA. This function should only be called if a packet
+ * is known to be ready to read for the endpoint. Note that the endpoint must
+ * be selected in the protocol engine prior to this call. */
+static u32 udc_read_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data,
+			 u32 bytes)
+{
+	u32 tmpv;
+	int to = 1000;
+	u32 tmp, hwrep = ((hwep & 0x1E) << 1) | CTRL_RD_EN;
+
+	/* Setup read of endpoint */
+	writel(hwrep, USBD_CTRL(udc->udp_baseaddr));
+
+	/* Wait until packet is ready */
+	while ((((tmpv = readl(USBD_RXPLEN(udc->udp_baseaddr))) &
+		 PKT_RDY) == 0)	&& (to > 0))
+		to--;
+	if (!to)
+		dev_dbg(udc->dev, "No packet ready on FIFO EP read\n");
+
+	/* Mask out count */
+	tmp = tmpv & PKT_LNGTH_MASK;
+	if (bytes < tmp)
+		tmp = bytes;
+
+	if ((tmp > 0) && (data != NULL))
+		udc_pop_fifo(udc, (u8 *) data, tmp);
+
+	writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr));
+
+	/* Clear the buffer */
+	udc_clr_buffer_hwep(udc, hwep);
+
+	return tmp;
+}
+
+/* Stuffs data into the FIFO, adjusts for alignment and data size */
+static void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
+{
+	int n, i, bl;
+	u16 *p16;
+	u32 *p32, tmp, cbytes;
+
+	/* Use optimal data transfer method based on source address and size */
+	switch (((u32) data) & 0x3) {
+	case 0: /* 32-bit aligned */
+		p32 = (u32 *) data;
+		cbytes = (bytes & ~0x3);
+
+		/* Copy 32-bit aligned data first */
+		for (n = 0; n < cbytes; n += 4)
+			writel(*p32++, USBD_TXDATA(udc->udp_baseaddr));
+
+		/* Handle any remaining bytes */
+		bl = bytes - cbytes;
+		if (bl) {
+			tmp = 0;
+			for (n = 0; n < bl; n++)
+				tmp |= data[cbytes + n] << (n * 8);
+
+			writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+		}
+		break;
+
+	case 1: /* 8-bit aligned */
+	case 3:
+		/* Each byte has to be handled independently */
+		for (n = 0; n < bytes; n += 4) {
+			bl = bytes - n;
+			if (bl > 4)
+				bl = 4;
+
+			tmp = 0;
+			for (i = 0; i < bl; i++)
+				tmp |= data[n + i] << (i * 8);
+
+			writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+		}
+		break;
+
+	case 2: /* 16-bit aligned */
+		p16 = (u16 *) data;
+		cbytes = (bytes & ~0x3);
+
+		/* Copy 32-bit aligned data first */
+		for (n = 0; n < cbytes; n += 4) {
+			tmp = *p16++ & 0xFFFF;
+			tmp |= (*p16++ & 0xFFFF) << 16;
+			writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+		}
+
+		/* Handle any remaining bytes */
+		bl = bytes - cbytes;
+		if (bl) {
+			tmp = 0;
+			for (n = 0; n < bl; n++)
+				tmp |= data[cbytes + n] << (n * 8);
+
+			writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+		}
+		break;
+	}
+}
+
+/* Write data to the FIFO for an endpoint. This function is for endpoints (such
+ * as EP0) that don't use DMA. Note that the endpoint must be selected in the
+ * protocol engine prior to this call. */
+static void udc_write_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data,
+			   u32 bytes)
+{
+	u32 hwwep = ((hwep & 0x1E) << 1) | CTRL_WR_EN;
+
+	if ((bytes > 0) && (data == NULL))
+		return;
+
+	/* Setup write of endpoint */
+	writel(hwwep, USBD_CTRL(udc->udp_baseaddr));
+
+	writel(bytes, USBD_TXPLEN(udc->udp_baseaddr));
+
+	/* Need at least 1 byte to trigger TX */
+	if (bytes == 0)
+		writel(0, USBD_TXDATA(udc->udp_baseaddr));
+	else
+		udc_stuff_fifo(udc, (u8 *) data, bytes);
+
+	writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr));
+
+	udc_val_buffer_hwep(udc, hwep);
+}
+
+/* USB device reset - resets USB to a default state with just EP0
+   enabled */
+static void uda_usb_reset(struct lpc32xx_udc *udc)
+{
+	u32 i = 0;
+	/* Re-init device controller and EP0 */
+	udc_enable(udc);
+	udc->gadget.speed = USB_SPEED_FULL;
+
+	for (i = 1; i < NUM_ENDPOINTS; i++) {
+		struct lpc32xx_ep *ep = &udc->ep[i];
+		ep->req_pending = 0;
+	}
+}
+
+/* Send a ZLP on EP0 */
+static void udc_ep0_send_zlp(struct lpc32xx_udc *udc)
+{
+	udc_write_hwep(udc, EP_IN, NULL, 0);
+}
+
+/* Get current frame number */
+static u16 udc_get_current_frame(struct lpc32xx_udc *udc)
+{
+	u16 flo, fhi;
+
+	udc_protocol_cmd_w(udc, CMD_RD_FRAME);
+	flo = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME);
+	fhi = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME);
+
+	return (fhi << 8) | flo;
+}
+
+/* Set the device as configured - enables all endpoints */
+static inline void udc_set_device_configured(struct lpc32xx_udc *udc)
+{
+	udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(CONF_DVICE));
+}
+
+/* Set the device as unconfigured - disables all endpoints */
+static inline void udc_set_device_unconfigured(struct lpc32xx_udc *udc)
+{
+	udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0));
+}
+
+/* reinit == restore initial software state */
+static void udc_reinit(struct lpc32xx_udc *udc)
+{
+	u32 i;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct lpc32xx_ep *ep = &udc->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+		ep->desc = NULL;
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+		ep->req_pending = 0;
+	}
+
+	udc->ep0state = WAIT_FOR_SETUP;
+}
+
+/* Must be called with lock */
+static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status)
+{
+	struct lpc32xx_udc *udc = ep->udc;
+
+	list_del_init(&req->queue);
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	if (ep->lep) {
+		enum dma_data_direction direction;
+
+		if (ep->is_in)
+			direction = DMA_TO_DEVICE;
+		else
+			direction = DMA_FROM_DEVICE;
+
+		if (req->mapped) {
+			dma_unmap_single(ep->udc->gadget.dev.parent,
+					req->req.dma, req->req.length,
+					direction);
+			req->req.dma = 0;
+			req->mapped = 0;
+		} else
+			dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+						req->req.dma, req->req.length,
+						direction);
+
+		/* Free DDs */
+		udc_dd_free(udc, req->dd_desc_ptr);
+	}
+
+	if (status && status != -ESHUTDOWN)
+		ep_dbg(ep, "%s done %p, status %d\n", ep->ep.name, req, status);
+
+	ep->req_pending = 0;
+	spin_unlock(&udc->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&udc->lock);
+}
+
+/* Must be called with lock */
+static void nuke(struct lpc32xx_ep *ep, int status)
+{
+	struct lpc32xx_request *req;
+
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+		done(ep, req, status);
+	}
+
+	if (ep->desc && status == -ESHUTDOWN) {
+		uda_disable_hwepint(ep->udc, ep->hwep_num);
+		udc_disable_hwep(ep->udc, ep->hwep_num);
+	}
+}
+
+/* IN endpoint 0 transfer */
+static int udc_ep0_in_req(struct lpc32xx_udc *udc)
+{
+	struct lpc32xx_request *req;
+	struct lpc32xx_ep *ep0 = &udc->ep[0];
+	u32 tsend, ts = 0;
+
+	if (list_empty(&ep0->queue))
+		/* Nothing to send */
+		return 0;
+	else
+		req = list_entry(ep0->queue.next, struct lpc32xx_request,
+				 queue);
+
+	tsend = ts = req->req.length - req->req.actual;
+	if (ts == 0) {
+		/* Send a ZLP */
+		udc_ep0_send_zlp(udc);
+		done(ep0, req, 0);
+		return 1;
+	} else if (ts > ep0->ep.maxpacket)
+		ts = ep0->ep.maxpacket; /* Just send what we can */
+
+	/* Write data to the EP0 FIFO and start transfer */
+	udc_write_hwep(udc, EP_IN, (req->req.buf + req->req.actual), ts);
+
+	/* Increment data pointer */
+	req->req.actual += ts;
+
+	if (tsend >= ep0->ep.maxpacket)
+		return 0; /* Stay in data transfer state */
+
+	/* Transfer request is complete */
+	udc->ep0state = WAIT_FOR_SETUP;
+	done(ep0, req, 0);
+	return 1;
+}
+
+/* OUT endpoint 0 transfer */
+static int udc_ep0_out_req(struct lpc32xx_udc *udc)
+{
+	struct lpc32xx_request *req;
+	struct lpc32xx_ep *ep0 = &udc->ep[0];
+	u32 tr, bufferspace;
+
+	if (list_empty(&ep0->queue))
+		return 0;
+	else
+		req = list_entry(ep0->queue.next, struct lpc32xx_request,
+				 queue);
+
+	if (req) {
+		if (req->req.length == 0) {
+			/* Just dequeue request */
+			done(ep0, req, 0);
+			udc->ep0state = WAIT_FOR_SETUP;
+			return 1;
+		}
+
+		/* Get data from FIFO */
+		bufferspace = req->req.length - req->req.actual;
+		if (bufferspace > ep0->ep.maxpacket)
+			bufferspace = ep0->ep.maxpacket;
+
+		/* Copy data to buffer */
+		prefetchw(req->req.buf + req->req.actual);
+		tr = udc_read_hwep(udc, EP_OUT, req->req.buf + req->req.actual,
+				   bufferspace);
+		req->req.actual += bufferspace;
+
+		if (tr < ep0->ep.maxpacket) {
+			/* This is the last packet */
+			done(ep0, req, 0);
+			udc->ep0state = WAIT_FOR_SETUP;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/* Must be called with lock */
+static void stop_activity(struct lpc32xx_udc *udc)
+{
+	struct usb_gadget_driver *driver = udc->driver;
+	int i;
+
+	if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->suspended = 0;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct lpc32xx_ep *ep = &udc->ep[i];
+		nuke(ep, -ESHUTDOWN);
+	}
+	if (driver) {
+		spin_unlock(&udc->lock);
+		driver->disconnect(&udc->gadget);
+		spin_lock(&udc->lock);
+	}
+
+	isp1301_pullup_enable(udc, 0, 0);
+	udc_disable(udc);
+	udc_reinit(udc);
+}
+
+/*
+ * Activate or kill host pullup
+ * Can be called with or without lock
+ */
+static void pullup(struct lpc32xx_udc *udc, int is_on)
+{
+	if (!udc->clocked)
+		return;
+
+	if (!udc->enabled || !udc->vbus)
+		is_on = 0;
+
+	if (is_on != udc->pullup)
+		isp1301_pullup_enable(udc, is_on, 0);
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_disable(struct usb_ep *_ep)
+{
+	struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+	struct lpc32xx_udc *udc = ep->udc;
+	unsigned long	flags;
+
+	if ((ep->hwep_num_base == 0) || (ep->hwep_num == 0))
+		return -EINVAL;
+	spin_lock_irqsave(&udc->lock, flags);
+
+	nuke(ep, -ESHUTDOWN);
+
+	/* restore the endpoint's pristine config */
+	ep->desc = NULL;
+
+	/* Clear all DMA statuses for this EP */
+	udc_ep_dma_disable(udc, ep->hwep_num);
+	writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr));
+	writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr));
+	writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+	writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr));
+
+	/* Remove the DD pointer in the UDCA */
+	udc->udca_v_base[ep->hwep_num] = 0;
+
+	/* Disable and reset endpoint and interrupt */
+	uda_clear_hwepint(udc, ep->hwep_num);
+	udc_unrealize_hwep(udc, ep->hwep_num);
+
+	ep->hwep_num = 0;
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	atomic_dec(&udc->enabled_ep_cnt);
+	wake_up(&udc->ep_disable_wait_queue);
+
+	return 0;
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_enable(struct usb_ep *_ep,
+			     const struct usb_endpoint_descriptor *desc)
+{
+	struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+	struct lpc32xx_udc *udc = ep->udc;
+	u16 maxpacket;
+	u32 tmp;
+	unsigned long flags;
+
+	/* Verify EP data */
+	if ((!_ep) || (!ep) || (!desc) || (ep->desc) ||
+	    (desc->bDescriptorType != USB_DT_ENDPOINT)) {
+		dev_dbg(udc->dev, "bad ep or descriptor\n");
+		return -EINVAL;
+	}
+	maxpacket = usb_endpoint_maxp(desc);
+	if ((maxpacket == 0) || (maxpacket > ep->maxpacket)) {
+		dev_dbg(udc->dev, "bad ep descriptor's packet size\n");
+		return -EINVAL;
+	}
+
+	/* Don't touch EP0 */
+	if (ep->hwep_num_base == 0) {
+		dev_dbg(udc->dev, "Can't re-enable EP0!!!\n");
+		return -EINVAL;
+	}
+
+	/* Is driver ready? */
+	if ((!udc->driver) || (udc->gadget.speed == USB_SPEED_UNKNOWN)) {
+		dev_dbg(udc->dev, "bogus device state\n");
+		return -ESHUTDOWN;
+	}
+
+	tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+	switch (tmp) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_INT:
+		if (maxpacket > ep->maxpacket) {
+			dev_dbg(udc->dev,
+				"Bad INT endpoint maxpacket %d\n", maxpacket);
+			return -EINVAL;
+		}
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		switch (maxpacket) {
+		case 8:
+		case 16:
+		case 32:
+		case 64:
+			break;
+
+		default:
+			dev_dbg(udc->dev,
+				"Bad BULK endpoint maxpacket %d\n", maxpacket);
+			return -EINVAL;
+		}
+		break;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		break;
+	}
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* Initialize endpoint to match the selected descriptor */
+	ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+	ep->desc = desc;
+	ep->ep.maxpacket = maxpacket;
+
+	/* Map hardware endpoint from base and direction */
+	if (ep->is_in)
+		/* IN endpoints are offset 1 from the OUT endpoint */
+		ep->hwep_num = ep->hwep_num_base + EP_IN;
+	else
+		ep->hwep_num = ep->hwep_num_base;
+
+	ep_dbg(ep, "EP enabled: %s, HW:%d, MP:%d IN:%d\n", ep->ep.name,
+	       ep->hwep_num, maxpacket, (ep->is_in == 1));
+
+	/* Realize the endpoint, interrupt is enabled later when
+	 * buffers are queued, IN EPs will NAK until buffers are ready */
+	udc_realize_hwep(udc, ep->hwep_num, ep->ep.maxpacket);
+	udc_clr_buffer_hwep(udc, ep->hwep_num);
+	uda_disable_hwepint(udc, ep->hwep_num);
+	udc_clrstall_hwep(udc, ep->hwep_num);
+
+	/* Clear all DMA statuses for this EP */
+	udc_ep_dma_disable(udc, ep->hwep_num);
+	writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr));
+	writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr));
+	writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+	writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr));
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	atomic_inc(&udc->enabled_ep_cnt);
+	return 0;
+}
+
+/*
+ * Allocate a USB request list
+ * Can be called with or without lock
+ */
+static struct usb_request *lpc32xx_ep_alloc_request(struct usb_ep *_ep,
+						    gfp_t gfp_flags)
+{
+	struct lpc32xx_request *req;
+
+	req = kzalloc(sizeof(struct lpc32xx_request), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+/*
+ * De-allocate a USB request list
+ * Can be called with or without lock
+ */
+static void lpc32xx_ep_free_request(struct usb_ep *_ep,
+				    struct usb_request *_req)
+{
+	struct lpc32xx_request *req;
+
+	req = container_of(_req, struct lpc32xx_request, req);
+	BUG_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_queue(struct usb_ep *_ep,
+			    struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct lpc32xx_request *req;
+	struct lpc32xx_ep *ep;
+	struct lpc32xx_udc *udc;
+	unsigned long flags;
+	int status = 0;
+
+	req = container_of(_req, struct lpc32xx_request, req);
+	ep = container_of(_ep, struct lpc32xx_ep, ep);
+
+	if (!_req || !_req->complete || !_req->buf ||
+	    !list_empty(&req->queue))
+		return -EINVAL;
+
+	udc = ep->udc;
+
+	if (!_ep || (!ep->desc && ep->hwep_num_base != 0)) {
+		dev_dbg(udc->dev, "invalid ep\n");
+		return -EINVAL;
+	}
+
+
+	if ((!udc) || (!udc->driver) ||
+	    (udc->gadget.speed == USB_SPEED_UNKNOWN)) {
+		dev_dbg(udc->dev, "invalid device\n");
+		return -EINVAL;
+	}
+
+	if (ep->lep) {
+		enum dma_data_direction direction;
+		struct lpc32xx_usbd_dd_gad *dd;
+
+		/* Map DMA pointer */
+		if (ep->is_in)
+			direction = DMA_TO_DEVICE;
+		else
+			direction = DMA_FROM_DEVICE;
+
+		if (req->req.dma == 0) {
+			req->req.dma = dma_map_single(
+				ep->udc->gadget.dev.parent,
+				req->req.buf, req->req.length, direction);
+			req->mapped = 1;
+		} else {
+			dma_sync_single_for_device(
+				ep->udc->gadget.dev.parent, req->req.dma,
+				req->req.length, direction);
+			req->mapped = 0;
+		}
+
+		/* For the request, build a list of DDs */
+		dd = udc_dd_alloc(udc);
+		if (!dd) {
+			/* Error allocating DD */
+			return -ENOMEM;
+		}
+		req->dd_desc_ptr = dd;
+
+		/* Setup the DMA descriptor */
+		dd->dd_next_phy = dd->dd_next_v = 0;
+		dd->dd_buffer_addr = req->req.dma;
+		dd->dd_status = 0;
+
+		/* Special handling for ISO EPs */
+		if (ep->eptype == EP_ISO_TYPE) {
+			dd->dd_setup = DD_SETUP_ISO_EP |
+				DD_SETUP_PACKETLEN(0) |
+				DD_SETUP_DMALENBYTES(1);
+			dd->dd_iso_ps_mem_addr = dd->this_dma + 24;
+			if (ep->is_in)
+				dd->iso_status[0] = req->req.length;
+			else
+				dd->iso_status[0] = 0;
+		} else
+			dd->dd_setup = DD_SETUP_PACKETLEN(ep->ep.maxpacket) |
+				DD_SETUP_DMALENBYTES(req->req.length);
+	}
+
+	ep_dbg(ep, "%s queue req %p len %d buf %p (in=%d) z=%d\n", _ep->name,
+	       _req, _req->length, _req->buf, ep->is_in, _req->zero);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+	req->send_zlp = _req->zero;
+
+	/* Kickstart empty queues */
+	if (list_empty(&ep->queue)) {
+		list_add_tail(&req->queue, &ep->queue);
+
+		if (ep->hwep_num_base == 0) {
+			/* Handle expected data direction */
+			if (ep->is_in) {
+				/* IN packet to host */
+				udc->ep0state = DATA_IN;
+				status = udc_ep0_in_req(udc);
+			} else {
+				/* OUT packet from host */
+				udc->ep0state = DATA_OUT;
+				status = udc_ep0_out_req(udc);
+			}
+		} else if (ep->is_in) {
+			/* IN packet to host and kick off transfer */
+			if (!ep->req_pending)
+				udc_ep_in_req_dma(udc, ep);
+		} else
+			/* OUT packet from host and kick off list */
+			if (!ep->req_pending)
+				udc_ep_out_req_dma(udc, ep);
+	} else
+		list_add_tail(&req->queue, &ep->queue);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return (status < 0) ? status : 0;
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct lpc32xx_ep *ep;
+	struct lpc32xx_request *req;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct lpc32xx_ep, ep);
+	if (!_ep || ep->hwep_num_base == 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore(&ep->udc->lock, flags);
+		return -EINVAL;
+	}
+
+	done(ep, req, -ECONNRESET);
+
+	spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+	return 0;
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+	struct lpc32xx_udc *udc = ep->udc;
+	unsigned long flags;
+
+	if ((!ep) || (ep->desc == NULL) || (ep->hwep_num <= 1))
+		return -EINVAL;
+
+	/* Don't halt an IN EP */
+	if (ep->is_in)
+		return -EAGAIN;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (value == 1) {
+		/* stall */
+		udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num),
+					DAT_WR_BYTE(EP_STAT_ST));
+	} else {
+		/* End stall */
+		ep->wedge = 0;
+		udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num),
+					DAT_WR_BYTE(0));
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+/* set the halt feature and ignores clear requests */
+static int lpc32xx_ep_set_wedge(struct usb_ep *_ep)
+{
+	struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+
+	if (!_ep || !ep->udc)
+		return -EINVAL;
+
+	ep->wedge = 1;
+
+	return usb_ep_set_halt(_ep);
+}
+
+static const struct usb_ep_ops lpc32xx_ep_ops = {
+	.enable		= lpc32xx_ep_enable,
+	.disable	= lpc32xx_ep_disable,
+	.alloc_request	= lpc32xx_ep_alloc_request,
+	.free_request	= lpc32xx_ep_free_request,
+	.queue		= lpc32xx_ep_queue,
+	.dequeue	= lpc32xx_ep_dequeue,
+	.set_halt	= lpc32xx_ep_set_halt,
+	.set_wedge	= lpc32xx_ep_set_wedge,
+};
+
+/* Send a ZLP on a non-0 IN EP */
+void udc_send_in_zlp(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+	/* Clear EP status */
+	udc_clearep_getsts(udc, ep->hwep_num);
+
+	/* Send ZLP via FIFO mechanism */
+	udc_write_hwep(udc, ep->hwep_num, NULL, 0);
+}
+
+/*
+ * Handle EP completion for ZLP
+ * This function will only be called when a delayed ZLP needs to be sent out
+ * after a DMA transfer has filled both buffers.
+ */
+void udc_handle_eps(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+	u32 epstatus;
+	struct lpc32xx_request *req;
+
+	if (ep->hwep_num <= 0)
+		return;
+
+	uda_clear_hwepint(udc, ep->hwep_num);
+
+	/* If this interrupt isn't enabled, return now */
+	if (!(udc->enabled_hwepints & (1 << ep->hwep_num)))
+		return;
+
+	/* Get endpoint status */
+	epstatus = udc_clearep_getsts(udc, ep->hwep_num);
+
+	/*
+	 * This should never happen, but protect against writing to the
+	 * buffer when full.
+	 */
+	if (epstatus & EP_SEL_F)
+		return;
+
+	if (ep->is_in) {
+		udc_send_in_zlp(udc, ep);
+		uda_disable_hwepint(udc, ep->hwep_num);
+	} else
+		return;
+
+	/* If there isn't a request waiting, something went wrong */
+	req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+	if (req) {
+		done(ep, req, 0);
+
+		/* Start another request if ready */
+		if (!list_empty(&ep->queue)) {
+			if (ep->is_in)
+				udc_ep_in_req_dma(udc, ep);
+			else
+				udc_ep_out_req_dma(udc, ep);
+		} else
+			ep->req_pending = 0;
+	}
+}
+
+
+/* DMA end of transfer completion */
+static void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+	u32 status, epstatus;
+	struct lpc32xx_request *req;
+	struct lpc32xx_usbd_dd_gad *dd;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+	ep->totalints++;
+#endif
+
+	req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+	if (!req) {
+		ep_err(ep, "DMA interrupt on no req!\n");
+		return;
+	}
+	dd = req->dd_desc_ptr;
+
+	/* DMA descriptor should always be retired for this call */
+	if (!(dd->dd_status & DD_STATUS_DD_RETIRED))
+		ep_warn(ep, "DMA descriptor did not retire\n");
+
+	/* Disable DMA */
+	udc_ep_dma_disable(udc, ep->hwep_num);
+	writel((1 << ep->hwep_num), USBD_EOTINTCLR(udc->udp_baseaddr));
+	writel((1 << ep->hwep_num), USBD_NDDRTINTCLR(udc->udp_baseaddr));
+
+	/* System error? */
+	if (readl(USBD_SYSERRTINTST(udc->udp_baseaddr)) &
+	    (1 << ep->hwep_num)) {
+		writel((1 << ep->hwep_num),
+			     USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+		ep_err(ep, "AHB critical error!\n");
+		ep->req_pending = 0;
+
+		/* The error could have occurred on a packet of a multipacket
+		 * transfer, so recovering the transfer is not possible. Close
+		 * the request with an error */
+		done(ep, req, -ECONNABORTED);
+		return;
+	}
+
+	/* Handle the current DD's status */
+	status = dd->dd_status;
+	switch (status & DD_STATUS_STS_MASK) {
+	case DD_STATUS_STS_NS:
+		/* DD not serviced? This shouldn't happen! */
+		ep->req_pending = 0;
+		ep_err(ep, "DMA critical EP error: DD not serviced (0x%x)!\n",
+		       status);
+
+		done(ep, req, -ECONNABORTED);
+		return;
+
+	case DD_STATUS_STS_BS:
+		/* Interrupt only fires on EOT - This shouldn't happen! */
+		ep->req_pending = 0;
+		ep_err(ep, "DMA critical EP error: EOT prior to service completion (0x%x)!\n",
+		       status);
+		done(ep, req, -ECONNABORTED);
+		return;
+
+	case DD_STATUS_STS_NC:
+	case DD_STATUS_STS_DUR:
+		/* Really just a short packet, not an underrun */
+		/* This is a good status and what we expect */
+		break;
+
+	default:
+		/* Data overrun, system error, or unknown */
+		ep->req_pending = 0;
+		ep_err(ep, "DMA critical EP error: System error (0x%x)!\n",
+		       status);
+		done(ep, req, -ECONNABORTED);
+		return;
+	}
+
+	/* ISO endpoints are handled differently */
+	if (ep->eptype == EP_ISO_TYPE) {
+		if (ep->is_in)
+			req->req.actual = req->req.length;
+		else
+			req->req.actual = dd->iso_status[0] & 0xFFFF;
+	} else
+		req->req.actual += DD_STATUS_CURDMACNT(status);
+
+	/* Send a ZLP if necessary. This will be done for non-int
+	 * packets which have a size that is a divisor of MAXP */
+	if (req->send_zlp) {
+		/*
+		 * If at least 1 buffer is available, send the ZLP now.
+		 * Otherwise, the ZLP send needs to be deferred until a
+		 * buffer is available.
+		 */
+		if (udc_clearep_getsts(udc, ep->hwep_num) & EP_SEL_F) {
+			udc_clearep_getsts(udc, ep->hwep_num);
+			uda_enable_hwepint(udc, ep->hwep_num);
+			epstatus = udc_clearep_getsts(udc, ep->hwep_num);
+
+			/* Let the EP interrupt handle the ZLP */
+			return;
+		} else
+			udc_send_in_zlp(udc, ep);
+	}
+
+	/* Transfer request is complete */
+	done(ep, req, 0);
+
+	/* Start another request if ready */
+	udc_clearep_getsts(udc, ep->hwep_num);
+	if (!list_empty((&ep->queue))) {
+		if (ep->is_in)
+			udc_ep_in_req_dma(udc, ep);
+		else
+			udc_ep_out_req_dma(udc, ep);
+	} else
+		ep->req_pending = 0;
+
+}
+
+/*
+ *
+ * Endpoint 0 functions
+ *
+ */
+static void udc_handle_dev(struct lpc32xx_udc *udc)
+{
+	u32 tmp;
+
+	udc_protocol_cmd_w(udc, CMD_GET_DEV_STAT);
+	tmp = udc_protocol_cmd_r(udc, DAT_GET_DEV_STAT);
+
+	if (tmp & DEV_RST)
+		uda_usb_reset(udc);
+	else if (tmp & DEV_CON_CH)
+		uda_power_event(udc, (tmp & DEV_CON));
+	else if (tmp & DEV_SUS_CH) {
+		if (tmp & DEV_SUS) {
+			if (udc->vbus == 0)
+				stop_activity(udc);
+			else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) &&
+				 udc->driver) {
+				/* Power down transceiver */
+				udc->poweron = 0;
+				schedule_work(&udc->pullup_job);
+				uda_resm_susp_event(udc, 1);
+			}
+		} else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) &&
+			   udc->driver && udc->vbus) {
+			uda_resm_susp_event(udc, 0);
+			/* Power up transceiver */
+			udc->poweron = 1;
+			schedule_work(&udc->pullup_job);
+		}
+	}
+}
+
+static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex)
+{
+	struct lpc32xx_ep *ep;
+	u32 ep0buff = 0, tmp;
+
+	switch (reqtype & USB_RECIP_MASK) {
+	case USB_RECIP_INTERFACE:
+		break; /* Not supported */
+
+	case USB_RECIP_DEVICE:
+		ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+		if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
+			ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		tmp = wIndex & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if ((tmp == 0) || (tmp >= NUM_ENDPOINTS) || (tmp && !ep->desc))
+			return -EOPNOTSUPP;
+
+		if (wIndex & USB_DIR_IN) {
+			if (!ep->is_in)
+				return -EOPNOTSUPP; /* Something's wrong */
+		} else if (ep->is_in)
+			return -EOPNOTSUPP; /* Not an IN endpoint */
+
+		/* Get status of the endpoint */
+		udc_protocol_cmd_w(udc, CMD_SEL_EP(ep->hwep_num));
+		tmp = udc_protocol_cmd_r(udc, DAT_SEL_EP(ep->hwep_num));
+
+		if (tmp & EP_SEL_ST)
+			ep0buff = (1 << USB_ENDPOINT_HALT);
+		else
+			ep0buff = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	/* Return data */
+	udc_write_hwep(udc, EP_IN, &ep0buff, 2);
+
+	return 0;
+}
+
+static void udc_handle_ep0_setup(struct lpc32xx_udc *udc)
+{
+	struct lpc32xx_ep *ep, *ep0 = &udc->ep[0];
+	struct usb_ctrlrequest ctrlpkt;
+	int i, bytes;
+	u16 wIndex, wValue, wLength, reqtype, req, tmp;
+
+	/* Nuke previous transfers */
+	nuke(ep0, -EPROTO);
+
+	/* Get setup packet */
+	bytes = udc_read_hwep(udc, EP_OUT, (u32 *) &ctrlpkt, 8);
+	if (bytes != 8) {
+		ep_warn(ep0, "Incorrectly sized setup packet (s/b 8, is %d)!\n",
+			bytes);
+		return;
+	}
+
+	/* Native endianness */
+	wIndex = le16_to_cpu(ctrlpkt.wIndex);
+	wValue = le16_to_cpu(ctrlpkt.wValue);
+	wLength = le16_to_cpu(ctrlpkt.wLength);
+	reqtype = le16_to_cpu(ctrlpkt.bRequestType);
+
+	/* Set direction of EP0 */
+	if (likely(reqtype & USB_DIR_IN))
+		ep0->is_in = 1;
+	else
+		ep0->is_in = 0;
+
+	/* Handle SETUP packet */
+	req = le16_to_cpu(ctrlpkt.bRequest);
+	switch (req) {
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+		switch (reqtype) {
+		case (USB_TYPE_STANDARD | USB_RECIP_DEVICE):
+			if (wValue != USB_DEVICE_REMOTE_WAKEUP)
+				goto stall; /* Nothing else handled */
+
+			/* Tell board about event */
+			if (req == USB_REQ_CLEAR_FEATURE)
+				udc->dev_status &=
+					~(1 << USB_DEVICE_REMOTE_WAKEUP);
+			else
+				udc->dev_status |=
+					(1 << USB_DEVICE_REMOTE_WAKEUP);
+			uda_remwkp_cgh(udc);
+			goto zlp_send;
+
+		case (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT):
+			tmp = wIndex & USB_ENDPOINT_NUMBER_MASK;
+			if ((wValue != USB_ENDPOINT_HALT) ||
+			    (tmp >= NUM_ENDPOINTS))
+				break;
+
+			/* Find hardware endpoint from logical endpoint */
+			ep = &udc->ep[tmp];
+			tmp = ep->hwep_num;
+			if (tmp == 0)
+				break;
+
+			if (req == USB_REQ_SET_FEATURE)
+				udc_stall_hwep(udc, tmp);
+			else if (!ep->wedge)
+				udc_clrstall_hwep(udc, tmp);
+
+			goto zlp_send;
+
+		default:
+			break;
+		}
+
+
+	case USB_REQ_SET_ADDRESS:
+		if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) {
+			udc_set_address(udc, wValue);
+			goto zlp_send;
+		}
+		break;
+
+	case USB_REQ_GET_STATUS:
+		udc_get_status(udc, reqtype, wIndex);
+		return;
+
+	default:
+		break; /* Let GadgetFS handle the descriptor instead */
+	}
+
+	if (likely(udc->driver)) {
+		/* device-2-host (IN) or no data setup command, process
+		 * immediately */
+		spin_unlock(&udc->lock);
+		i = udc->driver->setup(&udc->gadget, &ctrlpkt);
+
+		spin_lock(&udc->lock);
+		if (req == USB_REQ_SET_CONFIGURATION) {
+			/* Configuration is set after endpoints are realized */
+			if (wValue) {
+				/* Set configuration */
+				udc_set_device_configured(udc);
+
+				udc_protocol_cmd_data_w(udc, CMD_SET_MODE,
+							DAT_WR_BYTE(AP_CLK |
+							INAK_BI | INAK_II));
+			} else {
+				/* Clear configuration */
+				udc_set_device_unconfigured(udc);
+
+				/* Disable NAK interrupts */
+				udc_protocol_cmd_data_w(udc, CMD_SET_MODE,
+							DAT_WR_BYTE(AP_CLK));
+			}
+		}
+
+		if (i < 0) {
+			/* setup processing failed, force stall */
+			dev_err(udc->dev,
+				"req %02x.%02x protocol STALL; stat %d\n",
+				reqtype, req, i);
+			udc->ep0state = WAIT_FOR_SETUP;
+			goto stall;
+		}
+	}
+
+	if (!ep0->is_in)
+		udc_ep0_send_zlp(udc); /* ZLP IN packet on data phase */
+
+	return;
+
+stall:
+	udc_stall_hwep(udc, EP_IN);
+	return;
+
+zlp_send:
+	udc_ep0_send_zlp(udc);
+	return;
+}
+
+/* IN endpoint 0 transfer */
+static void udc_handle_ep0_in(struct lpc32xx_udc *udc)
+{
+	struct lpc32xx_ep *ep0 = &udc->ep[0];
+	u32 epstatus;
+
+	/* Clear EP interrupt */
+	epstatus = udc_clearep_getsts(udc, EP_IN);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+	ep0->totalints++;
+#endif
+
+	/* Stalled? Clear stall and reset buffers */
+	if (epstatus & EP_SEL_ST) {
+		udc_clrstall_hwep(udc, EP_IN);
+		nuke(ep0, -ECONNABORTED);
+		udc->ep0state = WAIT_FOR_SETUP;
+		return;
+	}
+
+	/* Is a buffer available? */
+	if (!(epstatus & EP_SEL_F)) {
+		/* Handle based on current state */
+		if (udc->ep0state == DATA_IN)
+			udc_ep0_in_req(udc);
+		else {
+			/* Unknown state for EP0 oe end of DATA IN phase */
+			nuke(ep0, -ECONNABORTED);
+			udc->ep0state = WAIT_FOR_SETUP;
+		}
+	}
+}
+
+/* OUT endpoint 0 transfer */
+static void udc_handle_ep0_out(struct lpc32xx_udc *udc)
+{
+	struct lpc32xx_ep *ep0 = &udc->ep[0];
+	u32 epstatus;
+
+	/* Clear EP interrupt */
+	epstatus = udc_clearep_getsts(udc, EP_OUT);
+
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+	ep0->totalints++;
+#endif
+
+	/* Stalled? */
+	if (epstatus & EP_SEL_ST) {
+		udc_clrstall_hwep(udc, EP_OUT);
+		nuke(ep0, -ECONNABORTED);
+		udc->ep0state = WAIT_FOR_SETUP;
+		return;
+	}
+
+	/* A NAK may occur if a packet couldn't be received yet */
+	if (epstatus & EP_SEL_EPN)
+		return;
+	/* Setup packet incoming? */
+	if (epstatus & EP_SEL_STP) {
+		nuke(ep0, 0);
+		udc->ep0state = WAIT_FOR_SETUP;
+	}
+
+	/* Data available? */
+	if (epstatus & EP_SEL_F)
+		/* Handle based on current state */
+		switch (udc->ep0state) {
+		case WAIT_FOR_SETUP:
+			udc_handle_ep0_setup(udc);
+			break;
+
+		case DATA_OUT:
+			udc_ep0_out_req(udc);
+			break;
+
+		default:
+			/* Unknown state for EP0 */
+			nuke(ep0, -ECONNABORTED);
+			udc->ep0state = WAIT_FOR_SETUP;
+		}
+}
+
+/* Must be called without lock */
+static int lpc32xx_get_frame(struct usb_gadget *gadget)
+{
+	int frame;
+	unsigned long flags;
+	struct lpc32xx_udc *udc = to_udc(gadget);
+
+	if (!udc->clocked)
+		return -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	frame = (int) udc_get_current_frame(udc);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return frame;
+}
+
+static int lpc32xx_wakeup(struct usb_gadget *gadget)
+{
+	return -ENOTSUPP;
+}
+
+static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+	struct lpc32xx_udc *udc = to_udc(gadget);
+
+	/* Always self-powered */
+	udc->selfpowered = (is_on != 0);
+
+	return 0;
+}
+
+/*
+ * vbus is here!  turn everything on that's ready
+ * Must be called without lock
+ */
+static int lpc32xx_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	unsigned long flags;
+	struct lpc32xx_udc *udc = to_udc(gadget);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* Doesn't need lock */
+	if (udc->driver) {
+		udc_clk_set(udc, 1);
+		udc_enable(udc);
+		pullup(udc, is_active);
+	} else {
+		stop_activity(udc);
+		pullup(udc, 0);
+
+		spin_unlock_irqrestore(&udc->lock, flags);
+		/*
+		 *  Wait for all the endpoints to disable,
+		 *  before disabling clocks. Don't wait if
+		 *  endpoints are not enabled.
+		 */
+		if (atomic_read(&udc->enabled_ep_cnt))
+			wait_event_interruptible(udc->ep_disable_wait_queue,
+				 (atomic_read(&udc->enabled_ep_cnt) == 0));
+
+		spin_lock_irqsave(&udc->lock, flags);
+
+		udc_clk_set(udc, 0);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+/* Can be called with or without lock */
+static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct lpc32xx_udc *udc = to_udc(gadget);
+
+	/* Doesn't need lock */
+	pullup(udc, is_on);
+
+	return 0;
+}
+
+static int lpc32xx_start(struct usb_gadget_driver *driver,
+			 int (*bind)(struct usb_gadget *));
+static int lpc32xx_stop(struct usb_gadget_driver *driver);
+
+static const struct usb_gadget_ops lpc32xx_udc_ops = {
+	.get_frame		= lpc32xx_get_frame,
+	.wakeup			= lpc32xx_wakeup,
+	.set_selfpowered	= lpc32xx_set_selfpowered,
+	.vbus_session		= lpc32xx_vbus_session,
+	.pullup			= lpc32xx_pullup,
+	.start			= lpc32xx_start,
+	.stop			= lpc32xx_stop,
+};
+
+static void nop_release(struct device *dev)
+{
+	/* nothing to free */
+}
+
+static struct lpc32xx_udc controller = {
+	.gadget = {
+		.ops	= &lpc32xx_udc_ops,
+		.ep0	= &controller.ep[0].ep,
+		.name	= driver_name,
+		.dev	= {
+			.init_name = "gadget",
+			.release = nop_release,
+		}
+	},
+	.ep[0] = {
+		.ep = {
+			.name	= "ep0",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 0,
+		.hwep_num	= 0, /* Can be 0 or 1, has special handling */
+		.lep		= 0,
+		.eptype		= EP_CTL_TYPE,
+	},
+	.ep[1] = {
+		.ep = {
+			.name	= "ep1-int",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 2,
+		.hwep_num	= 0, /* 2 or 3, will be set later */
+		.lep		= 1,
+		.eptype		= EP_INT_TYPE,
+	},
+	.ep[2] = {
+		.ep = {
+			.name	= "ep2-bulk",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 4,
+		.hwep_num	= 0, /* 4 or 5, will be set later */
+		.lep		= 2,
+		.eptype		= EP_BLK_TYPE,
+	},
+	.ep[3] = {
+		.ep = {
+			.name	= "ep3-iso",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 1023,
+		.hwep_num_base	= 6,
+		.hwep_num	= 0, /* 6 or 7, will be set later */
+		.lep		= 3,
+		.eptype		= EP_ISO_TYPE,
+	},
+	.ep[4] = {
+		.ep = {
+			.name	= "ep4-int",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 8,
+		.hwep_num	= 0, /* 8 or 9, will be set later */
+		.lep		= 4,
+		.eptype		= EP_INT_TYPE,
+	},
+	.ep[5] = {
+		.ep = {
+			.name	= "ep5-bulk",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 10,
+		.hwep_num	= 0, /* 10 or 11, will be set later */
+		.lep		= 5,
+		.eptype		= EP_BLK_TYPE,
+	},
+	.ep[6] = {
+		.ep = {
+			.name	= "ep6-iso",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 1023,
+		.hwep_num_base	= 12,
+		.hwep_num	= 0, /* 12 or 13, will be set later */
+		.lep		= 6,
+		.eptype		= EP_ISO_TYPE,
+	},
+	.ep[7] = {
+		.ep = {
+			.name	= "ep7-int",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 14,
+		.hwep_num	= 0,
+		.lep		= 7,
+		.eptype		= EP_INT_TYPE,
+	},
+	.ep[8] = {
+		.ep = {
+			.name	= "ep8-bulk",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 16,
+		.hwep_num	= 0,
+		.lep		= 8,
+		.eptype		= EP_BLK_TYPE,
+	},
+	.ep[9] = {
+		.ep = {
+			.name	= "ep9-iso",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 1023,
+		.hwep_num_base	= 18,
+		.hwep_num	= 0,
+		.lep		= 9,
+		.eptype		= EP_ISO_TYPE,
+	},
+	.ep[10] = {
+		.ep = {
+			.name	= "ep10-int",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 20,
+		.hwep_num	= 0,
+		.lep		= 10,
+		.eptype		= EP_INT_TYPE,
+	},
+	.ep[11] = {
+		.ep = {
+			.name	= "ep11-bulk",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 22,
+		.hwep_num	= 0,
+		.lep		= 11,
+		.eptype		= EP_BLK_TYPE,
+	},
+	.ep[12] = {
+		.ep = {
+			.name	= "ep12-iso",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 1023,
+		.hwep_num_base	= 24,
+		.hwep_num	= 0,
+		.lep		= 12,
+		.eptype		= EP_ISO_TYPE,
+	},
+	.ep[13] = {
+		.ep = {
+			.name	= "ep13-int",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 26,
+		.hwep_num	= 0,
+		.lep		= 13,
+		.eptype		= EP_INT_TYPE,
+	},
+	.ep[14] = {
+		.ep = {
+			.name	= "ep14-bulk",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 64,
+		.hwep_num_base	= 28,
+		.hwep_num	= 0,
+		.lep		= 14,
+		.eptype		= EP_BLK_TYPE,
+	},
+	.ep[15] = {
+		.ep = {
+			.name	= "ep15-bulk",
+			.ops	= &lpc32xx_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 1023,
+		.hwep_num_base	= 30,
+		.hwep_num	= 0,
+		.lep		= 15,
+		.eptype		= EP_BLK_TYPE,
+	},
+};
+
+/* ISO and status interrupts */
+static irqreturn_t lpc32xx_usb_lp_irq(int irq, void *_udc)
+{
+	u32 tmp, devstat;
+	struct lpc32xx_udc *udc = _udc;
+
+	spin_lock(&udc->lock);
+
+	/* Read the device status register */
+	devstat = readl(USBD_DEVINTST(udc->udp_baseaddr));
+
+	devstat &= ~USBD_EP_FAST;
+	writel(devstat, USBD_DEVINTCLR(udc->udp_baseaddr));
+	devstat = devstat & udc->enabled_devints;
+
+	/* Device specific handling needed? */
+	if (devstat & USBD_DEV_STAT)
+		udc_handle_dev(udc);
+
+	/* Start of frame? (devstat & FRAME_INT):
+	 * The frame interrupt isn't really needed for ISO support,
+	 * as the driver will queue the necessary packets */
+
+	/* Error? */
+	if (devstat & ERR_INT) {
+		/* All types of errors, from cable removal during transfer to
+		 * misc protocol and bit errors. These are mostly for just info,
+		 * as the USB hardware will work around these. If these errors
+		 * happen alot, something is wrong. */
+		udc_protocol_cmd_w(udc, CMD_RD_ERR_STAT);
+		tmp = udc_protocol_cmd_r(udc, DAT_RD_ERR_STAT);
+		dev_dbg(udc->dev, "Device error (0x%x)!\n", tmp);
+	}
+
+	spin_unlock(&udc->lock);
+
+	return IRQ_HANDLED;
+}
+
+/* EP interrupts */
+static irqreturn_t lpc32xx_usb_hp_irq(int irq, void *_udc)
+{
+	u32 tmp;
+	struct lpc32xx_udc *udc = _udc;
+
+	spin_lock(&udc->lock);
+
+	/* Read the device status register */
+	writel(USBD_EP_FAST, USBD_DEVINTCLR(udc->udp_baseaddr));
+
+	/* Endpoints */
+	tmp = readl(USBD_EPINTST(udc->udp_baseaddr));
+
+	/* Special handling for EP0 */
+	if (tmp & (EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) {
+		/* Handle EP0 IN */
+		if (tmp & (EP_MASK_SEL(0, EP_IN)))
+			udc_handle_ep0_in(udc);
+
+		/* Handle EP0 OUT */
+		if (tmp & (EP_MASK_SEL(0, EP_OUT)))
+			udc_handle_ep0_out(udc);
+	}
+
+	/* All other EPs */
+	if (tmp & ~(EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) {
+		int i;
+
+		/* Handle other EP interrupts */
+		for (i = 1; i < NUM_ENDPOINTS; i++) {
+			if (tmp & (1 << udc->ep[i].hwep_num))
+				udc_handle_eps(udc, &udc->ep[i]);
+		}
+	}
+
+	spin_unlock(&udc->lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t lpc32xx_usb_devdma_irq(int irq, void *_udc)
+{
+	struct lpc32xx_udc *udc = _udc;
+
+	int i;
+	u32 tmp;
+
+	spin_lock(&udc->lock);
+
+	/* Handle EP DMA EOT interrupts */
+	tmp = readl(USBD_EOTINTST(udc->udp_baseaddr)) |
+		(readl(USBD_EPDMAST(udc->udp_baseaddr)) &
+		 readl(USBD_NDDRTINTST(udc->udp_baseaddr))) |
+		readl(USBD_SYSERRTINTST(udc->udp_baseaddr));
+	for (i = 1; i < NUM_ENDPOINTS; i++) {
+		if (tmp & (1 << udc->ep[i].hwep_num))
+			udc_handle_dma_ep(udc, &udc->ep[i]);
+	}
+
+	spin_unlock(&udc->lock);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ *
+ * VBUS detection, pullup handler, and Gadget cable state notification
+ *
+ */
+static void vbus_work(struct work_struct *work)
+{
+	u8 value;
+	struct lpc32xx_udc *udc = container_of(work, struct lpc32xx_udc,
+					       vbus_job);
+
+	if (udc->enabled != 0) {
+		/* Discharge VBUS real quick */
+		i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+			ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG);
+
+		/* Give VBUS some time (100mS) to discharge */
+		msleep(100);
+
+		/* Disable VBUS discharge resistor */
+		i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+			ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+			OTG1_VBUS_DISCHRG);
+
+		/* Clear interrupt */
+		i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+			ISP1301_I2C_INTERRUPT_LATCH |
+			ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+
+		/* Get the VBUS status from the transceiver */
+		value = i2c_smbus_read_byte_data(udc->isp1301_i2c_client,
+						 ISP1301_I2C_OTG_CONTROL_2);
+
+		/* VBUS on or off? */
+		if (value & OTG_B_SESS_VLD)
+			udc->vbus = 1;
+		else
+			udc->vbus = 0;
+
+		/* VBUS changed? */
+		if (udc->last_vbus != udc->vbus) {
+			udc->last_vbus = udc->vbus;
+			lpc32xx_vbus_session(&udc->gadget, udc->vbus);
+		}
+	}
+
+	/* Re-enable after completion */
+	enable_irq(udc->udp_irq[IRQ_USB_ATX]);
+}
+
+static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc)
+{
+	struct lpc32xx_udc *udc = _udc;
+
+	/* Defer handling of VBUS IRQ to work queue */
+	disable_irq_nosync(udc->udp_irq[IRQ_USB_ATX]);
+	schedule_work(&udc->vbus_job);
+
+	return IRQ_HANDLED;
+}
+
+static int lpc32xx_start(struct usb_gadget_driver *driver,
+			 int (*bind)(struct usb_gadget *))
+{
+	struct lpc32xx_udc *udc = &controller;
+	int retval, i;
+
+	if (!driver || driver->max_speed < USB_SPEED_FULL ||
+	    !bind || !driver->setup) {
+		dev_err(udc->dev, "bad parameter.\n");
+		return -EINVAL;
+	}
+
+	if (udc->driver) {
+		dev_err(udc->dev, "UDC already has a gadget driver\n");
+		return -EBUSY;
+	}
+
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+	udc->enabled = 1;
+	udc->selfpowered = 1;
+	udc->vbus = 0;
+
+	retval = bind(&udc->gadget);
+	if (retval) {
+		dev_err(udc->dev, "bind() returned %d\n", retval);
+		udc->enabled = 0;
+		udc->selfpowered = 0;
+		udc->driver = NULL;
+		udc->gadget.dev.driver = NULL;
+		return retval;
+	}
+
+	dev_dbg(udc->dev, "bound to %s\n", driver->driver.name);
+
+	/* Force VBUS process once to check for cable insertion */
+	udc->last_vbus = udc->vbus = 0;
+	schedule_work(&udc->vbus_job);
+
+	/* Do not re-enable ATX IRQ (3) */
+	for (i = IRQ_USB_LP; i < IRQ_USB_ATX; i++)
+		enable_irq(udc->udp_irq[i]);
+
+	return 0;
+}
+
+static int lpc32xx_stop(struct usb_gadget_driver *driver)
+{
+	int i;
+	struct lpc32xx_udc *udc = &controller;
+
+	if (!driver || driver != udc->driver || !driver->unbind)
+		return -EINVAL;
+
+	/* Disable USB pullup */
+	isp1301_pullup_enable(udc, 0, 1);
+
+	for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++)
+		disable_irq(udc->udp_irq[i]);
+
+	if (udc->clocked) {
+
+		spin_lock(&udc->lock);
+		stop_activity(udc);
+		spin_unlock(&udc->lock);
+
+		/*
+		 *  Wait for all the endpoints to disable,
+		 *  before disabling clocks. Don't wait if
+		 *  endpoints are not enabled.
+		 */
+		if (atomic_read(&udc->enabled_ep_cnt))
+			wait_event_interruptible(udc->ep_disable_wait_queue,
+				(atomic_read(&udc->enabled_ep_cnt) == 0));
+
+		spin_lock(&udc->lock);
+		udc_clk_set(udc, 0);
+		spin_unlock(&udc->lock);
+	}
+
+	udc->enabled = 0;
+	pullup(udc, 0);
+
+	driver->unbind(&udc->gadget);
+	udc->gadget.dev.driver = NULL;
+	udc->driver = NULL;
+
+	dev_dbg(udc->dev, "unbound from %s\n", driver->driver.name);
+	return 0;
+}
+
+static void lpc32xx_udc_shutdown(struct platform_device *dev)
+{
+	/* Force disconnect on reboot */
+	struct lpc32xx_udc *udc = &controller;
+
+	pullup(udc, 0);
+}
+
+/*
+ * Callbacks to be overridden by options passed via OF (TODO)
+ */
+
+static void lpc32xx_usbd_conn_chg(int conn)
+{
+	/* Do nothing, it might be nice to enable an LED
+	 * based on conn state being !0 */
+}
+
+static void lpc32xx_usbd_susp_chg(int susp)
+{
+	/* Device suspend if susp != 0 */
+}
+
+static void lpc32xx_rmwkup_chg(int remote_wakup_enable)
+{
+	/* Enable or disable USB remote wakeup */
+}
+
+struct lpc32xx_usbd_cfg lpc32xx_usbddata = {
+	.vbus_drv_pol = 0,
+	.conn_chgb = &lpc32xx_usbd_conn_chg,
+	.susp_chgb = &lpc32xx_usbd_susp_chg,
+	.rmwk_chgb = &lpc32xx_rmwkup_chg,
+};
+
+
+static u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F;
+
+static int __init lpc32xx_udc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct lpc32xx_udc *udc = &controller;
+	int retval, i;
+	struct resource *res;
+	dma_addr_t dma_handle;
+	struct device_node *isp1301_node;
+
+	/* init software state */
+	udc->gadget.dev.parent = dev;
+	udc->pdev = pdev;
+	udc->dev = &pdev->dev;
+	udc->enabled = 0;
+
+	if (pdev->dev.of_node) {
+		isp1301_node = of_parse_phandle(pdev->dev.of_node,
+						"transceiver", 0);
+	} else {
+		isp1301_node = NULL;
+	}
+
+	udc->isp1301_i2c_client = isp1301_get_client(isp1301_node);
+	if (!udc->isp1301_i2c_client)
+		return -EPROBE_DEFER;
+
+	dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n",
+		 udc->isp1301_i2c_client->addr);
+
+	pdev->dev.dma_mask = &lpc32xx_usbd_dmamask;
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	udc->board = &lpc32xx_usbddata;
+
+	/*
+	 * Resources are mapped as follows:
+	 *  IORESOURCE_MEM, base address and size of USB space
+	 *  IORESOURCE_IRQ, USB device low priority interrupt number
+	 *  IORESOURCE_IRQ, USB device high priority interrupt number
+	 *  IORESOURCE_IRQ, USB device interrupt number
+	 *  IORESOURCE_IRQ, USB transceiver interrupt number
+	 */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	spin_lock_init(&udc->lock);
+
+	/* Get IRQs */
+	for (i = 0; i < 4; i++) {
+		udc->udp_irq[i] = platform_get_irq(pdev, i);
+		if (udc->udp_irq[i] < 0) {
+			dev_err(udc->dev,
+				"irq resource %d not available!\n", i);
+			return udc->udp_irq[i];
+		}
+	}
+
+	udc->io_p_start = res->start;
+	udc->io_p_size = resource_size(res);
+	if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) {
+		dev_err(udc->dev, "someone's using UDC memory\n");
+		return -EBUSY;
+	}
+
+	udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size);
+	if (!udc->udp_baseaddr) {
+		retval = -ENOMEM;
+		dev_err(udc->dev, "IO map failure\n");
+		goto io_map_fail;
+	}
+
+	/* Enable AHB slave USB clock, needed for further USB clock control */
+	writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
+
+	/* Get required clocks */
+	udc->usb_pll_clk = clk_get(&pdev->dev, "ck_pll5");
+	if (IS_ERR(udc->usb_pll_clk)) {
+		dev_err(udc->dev, "failed to acquire USB PLL\n");
+		retval = PTR_ERR(udc->usb_pll_clk);
+		goto pll_get_fail;
+	}
+	udc->usb_slv_clk = clk_get(&pdev->dev, "ck_usbd");
+	if (IS_ERR(udc->usb_slv_clk)) {
+		dev_err(udc->dev, "failed to acquire USB device clock\n");
+		retval = PTR_ERR(udc->usb_slv_clk);
+		goto usb_clk_get_fail;
+	}
+
+	/* Setup PLL clock to 48MHz */
+	retval = clk_enable(udc->usb_pll_clk);
+	if (retval < 0) {
+		dev_err(udc->dev, "failed to start USB PLL\n");
+		goto pll_enable_fail;
+	}
+
+	retval = clk_set_rate(udc->usb_pll_clk, 48000);
+	if (retval < 0) {
+		dev_err(udc->dev, "failed to set USB clock rate\n");
+		goto pll_set_fail;
+	}
+
+	writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN, USB_CTRL);
+
+	/* Enable USB device clock */
+	retval = clk_enable(udc->usb_slv_clk);
+	if (retval < 0) {
+		dev_err(udc->dev, "failed to start USB device clock\n");
+		goto usb_clk_enable_fail;
+	}
+
+	/* Set to enable all needed USB OTG clocks */
+	writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
+
+	i = 1000;
+	while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
+		USB_CLOCK_MASK) && (i > 0))
+		i--;
+	if (!i)
+		dev_dbg(udc->dev, "USB OTG clocks not correctly enabled\n");
+
+	/* Setup deferred workqueue data */
+	udc->poweron = udc->pullup = 0;
+	INIT_WORK(&udc->pullup_job, pullup_work);
+	INIT_WORK(&udc->vbus_job, vbus_work);
+#ifdef CONFIG_PM
+	INIT_WORK(&udc->power_job, power_work);
+#endif
+
+	/* All clocks are now on */
+	udc->clocked = 1;
+
+	isp1301_udc_configure(udc);
+	/* Allocate memory for the UDCA */
+	udc->udca_v_base = dma_alloc_coherent(&pdev->dev, UDCA_BUFF_SIZE,
+					      &dma_handle,
+					      (GFP_KERNEL | GFP_DMA));
+	if (!udc->udca_v_base) {
+		dev_err(udc->dev, "error getting UDCA region\n");
+		retval = -ENOMEM;
+		goto i2c_fail;
+	}
+	udc->udca_p_base = dma_handle;
+	dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n",
+		UDCA_BUFF_SIZE, udc->udca_p_base, udc->udca_v_base);
+
+	/* Setup the DD DMA memory pool */
+	udc->dd_cache = dma_pool_create("udc_dd", udc->dev,
+					sizeof(struct lpc32xx_usbd_dd_gad),
+					sizeof(u32), 0);
+	if (!udc->dd_cache) {
+		dev_err(udc->dev, "error getting DD DMA region\n");
+		retval = -ENOMEM;
+		goto dma_alloc_fail;
+	}
+
+	/* Clear USB peripheral and initialize gadget endpoints */
+	udc_disable(udc);
+	udc_reinit(udc);
+
+	retval = device_register(&udc->gadget.dev);
+	if (retval < 0) {
+		dev_err(udc->dev, "Device registration failure\n");
+		goto dev_register_fail;
+	}
+
+	/* Request IRQs - low and high priority USB device IRQs are routed to
+	 * the same handler, while the DMA interrupt is routed elsewhere */
+	retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq,
+			     0, "udc_lp", udc);
+	if (retval < 0) {
+		dev_err(udc->dev, "LP request irq %d failed\n",
+			udc->udp_irq[IRQ_USB_LP]);
+		goto irq_lp_fail;
+	}
+	retval = request_irq(udc->udp_irq[IRQ_USB_HP], lpc32xx_usb_hp_irq,
+			     0, "udc_hp", udc);
+	if (retval < 0) {
+		dev_err(udc->dev, "HP request irq %d failed\n",
+			udc->udp_irq[IRQ_USB_HP]);
+		goto irq_hp_fail;
+	}
+
+	retval = request_irq(udc->udp_irq[IRQ_USB_DEVDMA],
+			     lpc32xx_usb_devdma_irq, 0, "udc_dma", udc);
+	if (retval < 0) {
+		dev_err(udc->dev, "DEV request irq %d failed\n",
+			udc->udp_irq[IRQ_USB_DEVDMA]);
+		goto irq_dev_fail;
+	}
+
+	/* The transceiver interrupt is used for VBUS detection and will
+	   kick off the VBUS handler function */
+	retval = request_irq(udc->udp_irq[IRQ_USB_ATX], lpc32xx_usb_vbus_irq,
+			     0, "udc_otg", udc);
+	if (retval < 0) {
+		dev_err(udc->dev, "VBUS request irq %d failed\n",
+			udc->udp_irq[IRQ_USB_ATX]);
+		goto irq_xcvr_fail;
+	}
+
+	/* Initialize wait queue */
+	init_waitqueue_head(&udc->ep_disable_wait_queue);
+	atomic_set(&udc->enabled_ep_cnt, 0);
+
+	/* Keep all IRQs disabled until GadgetFS starts up */
+	for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++)
+		disable_irq(udc->udp_irq[i]);
+
+	retval = usb_add_gadget_udc(dev, &udc->gadget);
+	if (retval < 0)
+		goto add_gadget_fail;
+
+	dev_set_drvdata(dev, udc);
+	device_init_wakeup(dev, 1);
+	create_debug_file(udc);
+
+	/* Disable clocks for now */
+	udc_clk_set(udc, 0);
+
+	dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION);
+	return 0;
+
+add_gadget_fail:
+	free_irq(udc->udp_irq[IRQ_USB_ATX], udc);
+irq_xcvr_fail:
+	free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc);
+irq_dev_fail:
+	free_irq(udc->udp_irq[IRQ_USB_HP], udc);
+irq_hp_fail:
+	free_irq(udc->udp_irq[IRQ_USB_LP], udc);
+irq_lp_fail:
+	device_unregister(&udc->gadget.dev);
+dev_register_fail:
+	dma_pool_destroy(udc->dd_cache);
+dma_alloc_fail:
+	dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
+			  udc->udca_v_base, udc->udca_p_base);
+i2c_fail:
+	clk_disable(udc->usb_slv_clk);
+usb_clk_enable_fail:
+pll_set_fail:
+	clk_disable(udc->usb_pll_clk);
+pll_enable_fail:
+	clk_put(udc->usb_slv_clk);
+usb_clk_get_fail:
+	clk_put(udc->usb_pll_clk);
+pll_get_fail:
+	iounmap(udc->udp_baseaddr);
+io_map_fail:
+	release_mem_region(udc->io_p_start, udc->io_p_size);
+	dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval);
+
+	return retval;
+}
+
+static int __devexit lpc32xx_udc_remove(struct platform_device *pdev)
+{
+	struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
+
+	usb_del_gadget_udc(&udc->gadget);
+	if (udc->driver)
+		return -EBUSY;
+
+	udc_clk_set(udc, 1);
+	udc_disable(udc);
+	pullup(udc, 0);
+
+	free_irq(udc->udp_irq[IRQ_USB_ATX], udc);
+
+	device_init_wakeup(&pdev->dev, 0);
+	remove_debug_file(udc);
+
+	dma_pool_destroy(udc->dd_cache);
+	dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
+			  udc->udca_v_base, udc->udca_p_base);
+	free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc);
+	free_irq(udc->udp_irq[IRQ_USB_HP], udc);
+	free_irq(udc->udp_irq[IRQ_USB_LP], udc);
+
+	device_unregister(&udc->gadget.dev);
+
+	clk_disable(udc->usb_slv_clk);
+	clk_put(udc->usb_slv_clk);
+	clk_disable(udc->usb_pll_clk);
+	clk_put(udc->usb_pll_clk);
+	iounmap(udc->udp_baseaddr);
+	release_mem_region(udc->io_p_start, udc->io_p_size);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+	int to = 1000;
+	struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
+
+	if (udc->clocked) {
+		/* Power down ISP */
+		udc->poweron = 0;
+		isp1301_set_powerstate(udc, 0);
+
+		/* Disable clocking */
+		udc_clk_set(udc, 0);
+
+		/* Keep clock flag on, so we know to re-enable clocks
+		   on resume */
+		udc->clocked = 1;
+
+		/* Kill OTG and I2C clocks */
+		writel(0, USB_OTG_CLK_CTRL(udc));
+		while (((readl(USB_OTG_CLK_STAT(udc)) & OTGOFF_CLK_MASK) !=
+			OTGOFF_CLK_MASK) && (to > 0))
+			to--;
+		if (!to)
+			dev_dbg(udc->dev,
+				"USB OTG clocks not correctly enabled\n");
+
+		/* Kill global USB clock */
+		clk_disable(udc->usb_slv_clk);
+	}
+
+	return 0;
+}
+
+static int lpc32xx_udc_resume(struct platform_device *pdev)
+{
+	struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
+
+	if (udc->clocked) {
+		/* Enable global USB clock */
+		clk_enable(udc->usb_slv_clk);
+
+		/* Enable clocking */
+		udc_clk_set(udc, 1);
+
+		/* ISP back to normal power mode */
+		udc->poweron = 1;
+		isp1301_set_powerstate(udc, 1);
+	}
+
+	return 0;
+}
+#else
+#define	lpc32xx_udc_suspend	NULL
+#define	lpc32xx_udc_resume	NULL
+#endif
+
+#ifdef CONFIG_OF
+static struct of_device_id lpc32xx_udc_of_match[] = {
+	{ .compatible = "nxp,lpc3220-udc", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match);
+#endif
+
+static struct platform_driver lpc32xx_udc_driver = {
+	.remove		= __devexit_p(lpc32xx_udc_remove),
+	.shutdown	= lpc32xx_udc_shutdown,
+	.suspend	= lpc32xx_udc_suspend,
+	.resume		= lpc32xx_udc_resume,
+	.driver		= {
+		.name	= (char *) driver_name,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(lpc32xx_udc_of_match),
+	},
+};
+
+static int __init udc_init_module(void)
+{
+	return platform_driver_probe(&lpc32xx_udc_driver, lpc32xx_udc_probe);
+}
+module_init(udc_init_module);
+
+static void __exit udc_exit_module(void)
+{
+	platform_driver_unregister(&lpc32xx_udc_driver);
+}
+module_exit(udc_exit_module);
+
+MODULE_DESCRIPTION("LPC32XX udc driver");
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lpc32xx_udc");
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 3608b3b..8981fbb 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -390,7 +390,7 @@
 	int *counter;
 	int ret;
 
-	ep->desc = desc;
+	ep->ep.desc = desc;
 
 	BUG_ON(ep->pipenum);
 
@@ -558,7 +558,7 @@
 
 static void start_packet(struct m66592_ep *ep, struct m66592_request *req)
 {
-	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+	if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
 		start_packet_write(ep, req);
 	else
 		start_packet_read(ep, req);
@@ -734,7 +734,7 @@
 
 	if (restart) {
 		req = list_entry(ep->queue.next, struct m66592_request, queue);
-		if (ep->desc)
+		if (ep->ep.desc)
 			start_packet(ep, req);
 	}
 }
@@ -917,7 +917,7 @@
 				ep = m66592->pipenum2ep[pipenum];
 				req = list_entry(ep->queue.next,
 						 struct m66592_request, queue);
-				if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
 					irq_packet_write(ep, req);
 				else
 					irq_packet_read(ep, req);
@@ -1377,7 +1377,7 @@
 	req->req.actual = 0;
 	req->req.status = -EINPROGRESS;
 
-	if (ep->desc == NULL)	/* control */
+	if (ep->ep.desc == NULL)	/* control */
 		start_ep0(ep, req);
 	else {
 		if (request && !ep->busy)
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 9d9f7e3..88c85b4 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -456,7 +456,7 @@
 	unsigned		use_dma:1;
 	u16			pipenum;
 	u16			type;
-	const struct usb_endpoint_descriptor	*desc;
+
 	/* register address */
 	unsigned long		fifoaddr;
 	unsigned long		fifosel;
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index e2be951..9073436 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -232,7 +232,6 @@
 	struct mv_udc		*udc;
 	struct list_head	queue;
 	struct mv_dqh		*dqh;
-	const struct usb_endpoint_descriptor	*desc;
 	u32			direction;
 	char			name[14];
 	unsigned		stopped:1,
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index a73cf40..dbcd132 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -464,7 +464,7 @@
 	ep = container_of(_ep, struct mv_ep, ep);
 	udc = ep->udc;
 
-	if (!_ep || !desc || ep->desc
+	if (!_ep || !desc || ep->ep.desc
 			|| desc->bDescriptorType != USB_DT_ENDPOINT)
 		return -EINVAL;
 
@@ -528,7 +528,7 @@
 	dqh->size_ioc_int_sts = 0;
 
 	ep->ep.maxpacket = max;
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	ep->stopped = 0;
 
 	/* Enable the endpoint for Rx or Tx and set the endpoint type */
@@ -580,7 +580,7 @@
 	unsigned long flags;
 
 	ep = container_of(_ep, struct mv_ep, ep);
-	if ((_ep == NULL) || !ep->desc)
+	if ((_ep == NULL) || !ep->ep.desc)
 		return -EINVAL;
 
 	udc = ep->udc;
@@ -606,7 +606,6 @@
 	/* nuke all pending requests (does flush) */
 	nuke(ep, -ESHUTDOWN);
 
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	ep->stopped = 1;
 
@@ -651,7 +650,7 @@
 		return;
 
 	ep = container_of(_ep, struct mv_ep, ep);
-	if (!ep->desc)
+	if (!ep->ep.desc)
 		return;
 
 	udc = ep->udc;
@@ -715,11 +714,11 @@
 		dev_err(&udc->dev->dev, "%s, bad params", __func__);
 		return -EINVAL;
 	}
-	if (unlikely(!_ep || !ep->desc)) {
+	if (unlikely(!_ep || !ep->ep.desc)) {
 		dev_err(&udc->dev->dev, "%s, bad ep", __func__);
 		return -EINVAL;
 	}
-	if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+	if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
 		if (req->req.length > ep->ep.maxpacket)
 			return -EMSGSIZE;
 	}
@@ -925,12 +924,12 @@
 
 	ep = container_of(_ep, struct mv_ep, ep);
 	udc = ep->udc;
-	if (!_ep || !ep->desc) {
+	if (!_ep || !ep->ep.desc) {
 		status = -EINVAL;
 		goto out;
 	}
 
-	if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+	if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
 		status = -EOPNOTSUPP;
 		goto out;
 	}
@@ -1279,7 +1278,7 @@
 	ep->stopped = 0;
 	ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
 	ep->ep_num = 0;
-	ep->desc = &mv_ep0_desc;
+	ep->ep.desc = &mv_ep0_desc;
 	INIT_LIST_HEAD(&ep->queue);
 
 	ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 3b4b6dd..7ba3246 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -153,7 +153,7 @@
 	u16		maxp;
 
 	/* catch various bogus parameters */
-	if (!_ep || !desc || ep->desc
+	if (!_ep || !desc || ep->ep.desc
 			|| desc->bDescriptorType != USB_DT_ENDPOINT
 			|| ep->bEndpointAddress != desc->bEndpointAddress
 			|| ep->maxpacket < usb_endpoint_maxp(desc)) {
@@ -200,7 +200,7 @@
 
 	spin_lock_irqsave(&udc->lock, flags);
 
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	ep->irqs = 0;
 	ep->stopped = 0;
 	ep->ep.maxpacket = maxp;
@@ -242,14 +242,13 @@
 	struct omap_ep	*ep = container_of(_ep, struct omap_ep, ep);
 	unsigned long	flags;
 
-	if (!_ep || !ep->desc) {
+	if (!_ep || !ep->ep.desc) {
 		DBG("%s, %s not enabled\n", __func__,
 			_ep ? ep->ep.name : NULL);
 		return -EINVAL;
 	}
 
 	spin_lock_irqsave(&ep->udc->lock, flags);
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	nuke (ep, -ESHUTDOWN);
 	ep->ep.maxpacket = ep->maxpacket;
@@ -917,7 +916,7 @@
 		DBG("%s, bad params\n", __func__);
 		return -EINVAL;
 	}
-	if (!_ep || (!ep->desc && ep->bEndpointAddress)) {
+	if (!_ep || (!ep->ep.desc && ep->bEndpointAddress)) {
 		DBG("%s, bad ep\n", __func__);
 		return -EINVAL;
 	}
@@ -1121,7 +1120,7 @@
 			status = 0;
 
 	/* otherwise, all active non-ISO endpoints can halt */
-	} else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->desc) {
+	} else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->ep.desc) {
 
 		/* IN endpoints must already be idle */
 		if ((ep->bEndpointAddress & USB_DIR_IN)
@@ -1625,7 +1624,7 @@
 				if (w_index & USB_DIR_IN)
 					ep += 16;
 				if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
-						|| !ep->desc)
+						|| !ep->ep.desc)
 					goto do_stall;
 				use_ep(ep, 0);
 				omap_writew(udc->clr_halt, UDC_CTRL);
@@ -1653,7 +1652,7 @@
 			if (w_index & USB_DIR_IN)
 				ep += 16;
 			if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
-					|| ep == ep0 || !ep->desc)
+					|| ep == ep0 || !ep->ep.desc)
 				goto do_stall;
 			if (use_dma && ep->has_dma) {
 				/* this has rude side-effects (aborts) and
@@ -1688,7 +1687,7 @@
 			ep = &udc->ep[w_index & 0xf];
 			if (w_index & USB_DIR_IN)
 				ep += 16;
-			if (!ep->desc)
+			if (!ep->ep.desc)
 				goto do_stall;
 
 			/* iso never stalls */
@@ -2509,7 +2508,7 @@
 		if (tmp & UDC_ADD) {
 			list_for_each_entry (ep, &udc->gadget.ep_list,
 					ep.ep_list) {
-				if (ep->desc)
+				if (ep->ep.desc)
 					proc_ep_show(s, ep);
 			}
 		}
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index 59d3b22..cfadeb5 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -140,7 +140,6 @@
 	struct list_head		queue;
 	unsigned long			irqs;
 	struct list_head		iso;
-	const struct usb_endpoint_descriptor	*desc;
 	char				name[14];
 	u16				maxpacket;
 	u8				bEndpointAddress;
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 6530706..1cfcc9e 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -295,7 +295,6 @@
 	struct pch_udc_data_dma_desc	*td_data;
 	struct pch_udc_dev		*dev;
 	unsigned long			offset_addr;
-	const struct usb_endpoint_descriptor	*desc;
 	struct list_head		queue;
 	unsigned			num:5,
 					in:1,
@@ -1705,7 +1704,7 @@
 	if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN))
 		return -ESHUTDOWN;
 	spin_lock_irqsave(&dev->lock, iflags);
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	ep->halted = 0;
 	pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc);
 	ep->ep.maxpacket = usb_endpoint_maxp(desc);
@@ -1734,7 +1733,7 @@
 
 	ep = container_of(usbep, struct pch_udc_ep, ep);
 	dev = ep->dev;
-	if ((usbep->name == ep0_string) || !ep->desc)
+	if ((usbep->name == ep0_string) || !ep->ep.desc)
 		return -EINVAL;
 
 	spin_lock_irqsave(&ep->dev->lock, iflags);
@@ -1742,7 +1741,6 @@
 	ep->halted = 1;
 	pch_udc_ep_disable(ep);
 	pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	INIT_LIST_HEAD(&ep->queue);
 	spin_unlock_irqrestore(&ep->dev->lock, iflags);
@@ -1849,7 +1847,7 @@
 		return -EINVAL;
 	ep = container_of(usbep, struct pch_udc_ep, ep);
 	dev = ep->dev;
-	if (!ep->desc && ep->num)
+	if (!ep->ep.desc && ep->num)
 		return -EINVAL;
 	req = container_of(usbreq, struct pch_udc_request, req);
 	if (!list_empty(&req->queue))
@@ -1949,7 +1947,7 @@
 
 	ep = container_of(usbep, struct pch_udc_ep, ep);
 	dev = ep->dev;
-	if (!usbep || !usbreq || (!ep->desc && ep->num))
+	if (!usbep || !usbreq || (!ep->ep.desc && ep->num))
 		return ret;
 	req = container_of(usbreq, struct pch_udc_request, req);
 	spin_lock_irqsave(&ep->dev->lock, flags);
@@ -1988,7 +1986,7 @@
 		return -EINVAL;
 	ep = container_of(usbep, struct pch_udc_ep, ep);
 	dev = ep->dev;
-	if (!ep->desc && !ep->num)
+	if (!ep->ep.desc && !ep->num)
 		return -EINVAL;
 	if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
 		return -ESHUTDOWN;
@@ -2033,7 +2031,7 @@
 		return -EINVAL;
 	ep = container_of(usbep, struct pch_udc_ep, ep);
 	dev = ep->dev;
-	if (!ep->desc && !ep->num)
+	if (!ep->ep.desc && !ep->num)
 		return -EINVAL;
 	if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
 		return -ESHUTDOWN;
@@ -2065,7 +2063,7 @@
 		return;
 
 	ep = container_of(usbep, struct pch_udc_ep, ep);
-	if (ep->desc || !ep->num)
+	if (ep->ep.desc || !ep->num)
 		pch_udc_ep_fifo_flush(ep, ep->in);
 }
 
@@ -3282,7 +3280,6 @@
 
 MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id);
 
-
 static struct pci_driver pch_udc_driver = {
 	.name =	KBUILD_MODNAME,
 	.id_table =	pch_udc_pcidev_id,
@@ -3293,17 +3290,7 @@
 	.shutdown =	pch_udc_shutdown,
 };
 
-static int __init pch_udc_pci_init(void)
-{
-	return pci_register_driver(&pch_udc_driver);
-}
-module_init(pch_udc_pci_init);
-
-static void __exit pch_udc_pci_exit(void)
-{
-	pci_unregister_driver(&pch_udc_driver);
-}
-module_exit(pch_udc_pci_exit);
+module_pci_driver(pch_udc_driver);
 
 MODULE_DESCRIPTION("Intel EG20T USB Device Controller");
 MODULE_AUTHOR("LAPIS Semiconductor, <tomoya-linux@dsn.lapis-semi.com>");
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 4e4dc1f..f1f9290 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -51,6 +51,7 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
+#include "composite.c"
 #include "usbstring.c"
 #include "config.c"
 #include "epautoconf.c"
@@ -75,8 +76,6 @@
 	/* lock buffer lists during read/write calls */
 	struct mutex		lock_printer_io;
 	struct usb_gadget	*gadget;
-	struct usb_request	*req;		/* for control responses */
-	u8			config;
 	s8			interface;
 	struct usb_ep		*in_ep, *out_ep;
 
@@ -100,6 +99,7 @@
 	struct device		*pdev;
 	u8			printer_cdev_open;
 	wait_queue_head_t	wait;
+	struct usb_function	function;
 };
 
 static struct printer_dev usb_printer_gadget;
@@ -120,26 +120,6 @@
  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
  */
 
-static ushort idVendor;
-module_param(idVendor, ushort, S_IRUGO);
-MODULE_PARM_DESC(idVendor, "USB Vendor ID");
-
-static ushort idProduct;
-module_param(idProduct, ushort, S_IRUGO);
-MODULE_PARM_DESC(idProduct, "USB Product ID");
-
-static ushort bcdDevice;
-module_param(bcdDevice, ushort, S_IRUGO);
-MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
-
-static char *iManufacturer;
-module_param(iManufacturer, charp, S_IRUGO);
-MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
-
-static char *iProduct;
-module_param(iProduct, charp, S_IRUGO);
-MODULE_PARM_DESC(iProduct, "USB Product string");
-
 static char *iSerialNum;
 module_param(iSerialNum, charp, S_IRUGO);
 MODULE_PARM_DESC(iSerialNum, "1");
@@ -154,47 +134,8 @@
 
 #define QLEN	qlen
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define DEVSPEED	USB_SPEED_HIGH
-#else   /* full speed (low speed doesn't do bulk) */
-#define DEVSPEED        USB_SPEED_FULL
-#endif
-
 /*-------------------------------------------------------------------------*/
 
-#define xprintk(d, level, fmt, args...) \
-	printk(level "%s: " fmt, DRIVER_DESC, ## args)
-
-#ifdef DEBUG
-#define DBG(dev, fmt, args...) \
-	xprintk(dev, KERN_DEBUG, fmt, ## args)
-#else
-#define DBG(dev, fmt, args...) \
-	do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG(dev, fmt, args...) \
-	xprintk(dev, KERN_DEBUG, fmt, ## args)
-#else
-#define VDBG(dev, fmt, args...) \
-	do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev, fmt, args...) \
-	xprintk(dev, KERN_ERR, fmt, ## args)
-#define WARNING(dev, fmt, args...) \
-	xprintk(dev, KERN_WARNING, fmt, ## args)
-#define INFO(dev, fmt, args...) \
-	xprintk(dev, KERN_INFO, fmt, ## args)
-
-/*-------------------------------------------------------------------------*/
-
-/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
- * ep0 implementation:  descriptors, config management, setup().
- * also optional class-specific notification interrupt transfer.
- */
-
 /*
  * DESCRIPTORS ... most are static, but strings and (full) configuration
  * descriptors are built on demand.
@@ -227,24 +168,6 @@
 	.bNumConfigurations =	1
 };
 
-static struct usb_otg_descriptor otg_desc = {
-	.bLength =		sizeof otg_desc,
-	.bDescriptorType =	USB_DT_OTG,
-	.bmAttributes =		USB_OTG_SRP
-};
-
-static struct usb_config_descriptor config_desc = {
-	.bLength =		sizeof config_desc,
-	.bDescriptorType =	USB_DT_CONFIG,
-
-	/* compute wTotalLength on the fly */
-	.bNumInterfaces =	1,
-	.bConfigurationValue =	DEV_CONFIG_VALUE,
-	.iConfiguration =	0,
-	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-	.bMaxPower =		CONFIG_USB_GADGET_VBUS_DRAW / 2,
-};
-
 static struct usb_interface_descriptor intf_desc = {
 	.bLength =		sizeof intf_desc,
 	.bDescriptorType =	USB_DT_INTERFACE,
@@ -270,16 +193,13 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK
 };
 
-static const struct usb_descriptor_header *fs_printer_function [11] = {
-	(struct usb_descriptor_header *) &otg_desc,
+static struct usb_descriptor_header *fs_printer_function[] = {
 	(struct usb_descriptor_header *) &intf_desc,
 	(struct usb_descriptor_header *) &fs_ep_in_desc,
 	(struct usb_descriptor_header *) &fs_ep_out_desc,
 	NULL
 };
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -307,24 +227,27 @@
 	.bNumConfigurations =	1
 };
 
-static const struct usb_descriptor_header *hs_printer_function [11] = {
-	(struct usb_descriptor_header *) &otg_desc,
+static struct usb_descriptor_header *hs_printer_function[] = {
 	(struct usb_descriptor_header *) &intf_desc,
 	(struct usb_descriptor_header *) &hs_ep_in_desc,
 	(struct usb_descriptor_header *) &hs_ep_out_desc,
 	NULL
 };
 
+static struct usb_otg_descriptor otg_descriptor = {
+	.bLength =              sizeof otg_descriptor,
+	.bDescriptorType =      USB_DT_OTG,
+	.bmAttributes =         USB_OTG_SRP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
+	NULL,
+};
+
 /* maxpacket and other transfer characteristics vary by speed. */
 #define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
 
-#else
-
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g, hs, fs) (((void)(g)), (fs))
-
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
-
 /*-------------------------------------------------------------------------*/
 
 /* descriptors that are built on-demand */
@@ -343,11 +266,16 @@
 	{  }		/* end of list */
 };
 
-static struct usb_gadget_strings	stringtab = {
+static struct usb_gadget_strings	stringtab_dev = {
 	.language	= 0x0409,	/* en-us */
 	.strings	= strings,
 };
 
+static struct usb_gadget_strings *dev_strings[] = {
+	&stringtab_dev,
+	NULL,
+};
+
 /*-------------------------------------------------------------------------*/
 
 static struct usb_request *
@@ -937,82 +865,8 @@
 	dev->interface = -1;
 }
 
-/* change our operational config.  must agree with the code
- * that returns config descriptors, and altsetting code.
- */
-static int
-printer_set_config(struct printer_dev *dev, unsigned number)
-{
-	int			result = 0;
-	struct usb_gadget	*gadget = dev->gadget;
-
-	switch (number) {
-	case DEV_CONFIG_VALUE:
-		result = 0;
-		break;
-	default:
-		result = -EINVAL;
-		/* FALL THROUGH */
-	case 0:
-		break;
-	}
-
-	if (result) {
-		usb_gadget_vbus_draw(dev->gadget,
-				dev->gadget->is_otg ? 8 : 100);
-	} else {
-		unsigned power;
-
-		power = 2 * config_desc.bMaxPower;
-		usb_gadget_vbus_draw(dev->gadget, power);
-
-		dev->config = number;
-		INFO(dev, "%s config #%d: %d mA, %s\n",
-		     usb_speed_string(gadget->speed),
-		     number, power, driver_desc);
-	}
-	return result;
-}
-
-static int
-config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index,
-		int is_otg)
-{
-	int					len;
-	const struct usb_descriptor_header	**function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int					hs = (speed == USB_SPEED_HIGH);
-
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
-
-	if (hs) {
-		function = hs_printer_function;
-	} else {
-		function = fs_printer_function;
-	}
-#else
-	function = fs_printer_function;
-#endif
-
-	if (index >= device_desc.bNumConfigurations)
-		return -EINVAL;
-
-	/* for now, don't advertise srp-only devices */
-	if (!is_otg)
-		function++;
-
-	len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE,
-			function);
-	if (len < 0)
-		return len;
-	((struct usb_config_descriptor *) buf)->bDescriptorType = type;
-	return len;
-}
-
 /* Change our operational Interface. */
-static int
-set_interface(struct printer_dev *dev, unsigned number)
+static int set_interface(struct printer_dev *dev, unsigned number)
 {
 	int			result = 0;
 
@@ -1043,14 +897,6 @@
 	return result;
 }
 
-static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req)
-{
-	if (req->status || req->actual != req->length)
-		DBG((struct printer_dev *) ep->driver_data,
-				"setup complete --> %d, %d/%d\n",
-				req->status, req->actual, req->length);
-}
-
 static void printer_soft_reset(struct printer_dev *dev)
 {
 	struct usb_request	*req;
@@ -1107,11 +953,12 @@
  * The setup() callback implements all the ep0 functionality that's not
  * handled lower down.
  */
-static int
-printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+static int printer_func_setup(struct usb_function *f,
+		const struct usb_ctrlrequest *ctrl)
 {
-	struct printer_dev	*dev = get_gadget_data(gadget);
-	struct usb_request	*req = dev->req;
+	struct printer_dev *dev = container_of(f, struct printer_dev, function);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_request	*req = cdev->req;
 	int			value = -EOPNOTSUPP;
 	u16			wIndex = le16_to_cpu(ctrl->wIndex);
 	u16			wValue = le16_to_cpu(ctrl->wValue);
@@ -1120,102 +967,7 @@
 	DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
 		ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
 
-	req->complete = printer_setup_complete;
-
 	switch (ctrl->bRequestType&USB_TYPE_MASK) {
-
-	case USB_TYPE_STANDARD:
-		switch (ctrl->bRequest) {
-
-		case USB_REQ_GET_DESCRIPTOR:
-			if (ctrl->bRequestType != USB_DIR_IN)
-				break;
-			switch (wValue >> 8) {
-
-			case USB_DT_DEVICE:
-				device_desc.bMaxPacketSize0 =
-					gadget->ep0->maxpacket;
-				value = min(wLength, (u16) sizeof device_desc);
-				memcpy(req->buf, &device_desc, value);
-				break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-			case USB_DT_DEVICE_QUALIFIER:
-				if (!gadget_is_dualspeed(gadget))
-					break;
-				/*
-				 * assumes ep0 uses the same value for both
-				 * speeds
-				 */
-				dev_qualifier.bMaxPacketSize0 =
-					gadget->ep0->maxpacket;
-				value = min(wLength,
-						(u16) sizeof dev_qualifier);
-				memcpy(req->buf, &dev_qualifier, value);
-				break;
-
-			case USB_DT_OTHER_SPEED_CONFIG:
-				if (!gadget_is_dualspeed(gadget))
-					break;
-				/* FALLTHROUGH */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-			case USB_DT_CONFIG:
-				value = config_buf(gadget->speed, req->buf,
-						wValue >> 8,
-						wValue & 0xff,
-						gadget->is_otg);
-				if (value >= 0)
-					value = min(wLength, (u16) value);
-				break;
-
-			case USB_DT_STRING:
-				value = usb_gadget_get_string(&stringtab,
-						wValue & 0xff, req->buf);
-				if (value >= 0)
-					value = min(wLength, (u16) value);
-				break;
-			}
-			break;
-
-		case USB_REQ_SET_CONFIGURATION:
-			if (ctrl->bRequestType != 0)
-				break;
-			if (gadget->a_hnp_support)
-				DBG(dev, "HNP available\n");
-			else if (gadget->a_alt_hnp_support)
-				DBG(dev, "HNP needs a different root port\n");
-			value = printer_set_config(dev, wValue);
-			if (!value)
-				value = set_interface(dev, PRINTER_INTERFACE);
-			break;
-		case USB_REQ_GET_CONFIGURATION:
-			if (ctrl->bRequestType != USB_DIR_IN)
-				break;
-			*(u8 *)req->buf = dev->config;
-			value = min(wLength, (u16) 1);
-			break;
-
-		case USB_REQ_SET_INTERFACE:
-			if (ctrl->bRequestType != USB_RECIP_INTERFACE ||
-					!dev->config)
-				break;
-
-			value = set_interface(dev, PRINTER_INTERFACE);
-			break;
-		case USB_REQ_GET_INTERFACE:
-			if (ctrl->bRequestType !=
-					(USB_DIR_IN|USB_RECIP_INTERFACE)
-					|| !dev->config)
-				break;
-
-			*(u8 *)req->buf = dev->interface;
-			value = min(wLength, (u16) 1);
-			break;
-
-		default:
-			goto unknown;
-		}
-		break;
-
 	case USB_TYPE_CLASS:
 		switch (ctrl->bRequest) {
 		case 0: /* Get the IEEE-1284 PNP String */
@@ -1261,44 +1013,50 @@
 			wValue, wIndex, wLength);
 		break;
 	}
-
-	/* respond with data transfer before status phase? */
-	if (value >= 0) {
-		req->length = value;
-		req->zero = value < wLength;
-		value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
-		if (value < 0) {
-			DBG(dev, "ep_queue --> %d\n", value);
-			req->status = 0;
-			printer_setup_complete(gadget->ep0, req);
-		}
-	}
-
 	/* host either stalls (value < 0) or reports success */
 	return value;
 }
 
-static void
-printer_disconnect(struct usb_gadget *gadget)
+static int __init printer_func_bind(struct usb_configuration *c,
+		struct usb_function *f)
 {
-	struct printer_dev	*dev = get_gadget_data(gadget);
+	return 0;
+}
+
+static void printer_func_unbind(struct usb_configuration *c,
+		struct usb_function *f)
+{
+}
+
+static int printer_func_set_alt(struct usb_function *f,
+		unsigned intf, unsigned alt)
+{
+	struct printer_dev *dev = container_of(f, struct printer_dev, function);
+	int ret = -ENOTSUPP;
+
+	if (!alt)
+		ret = set_interface(dev, PRINTER_INTERFACE);
+	return ret;
+}
+
+static void printer_func_disable(struct usb_function *f)
+{
+	struct printer_dev *dev = container_of(f, struct printer_dev, function);
 	unsigned long		flags;
 
 	DBG(dev, "%s\n", __func__);
 
 	spin_lock_irqsave(&dev->lock, flags);
-
 	printer_reset_interface(dev);
-
 	spin_unlock_irqrestore(&dev->lock, flags);
 }
 
-static void
-printer_unbind(struct usb_gadget *gadget)
+static void printer_cfg_unbind(struct usb_configuration *c)
 {
-	struct printer_dev	*dev = get_gadget_data(gadget);
+	struct printer_dev	*dev;
 	struct usb_request	*req;
 
+	dev = &usb_printer_gadget;
 
 	DBG(dev, "%s\n", __func__);
 
@@ -1336,18 +1094,18 @@
 		list_del(&req->list);
 		printer_req_free(dev->out_ep, req);
 	}
-
-	if (dev->req) {
-		printer_req_free(gadget->ep0, dev->req);
-		dev->req = NULL;
-	}
-
-	set_gadget_data(gadget, NULL);
 }
 
-static int __init
-printer_bind(struct usb_gadget *gadget)
+static struct usb_configuration printer_cfg_driver = {
+	.label			= "printer",
+	.unbind			= printer_cfg_unbind,
+	.bConfigurationValue	= 1,
+	.bmAttributes		= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+};
+
+static int __init printer_bind_config(struct usb_configuration *c)
 {
+	struct usb_gadget	*gadget = c->cdev->gadget;
 	struct printer_dev	*dev;
 	struct usb_ep		*in_ep, *out_ep;
 	int			status = -ENOMEM;
@@ -1358,6 +1116,14 @@
 
 	dev = &usb_printer_gadget;
 
+	dev->function.name = shortname;
+	dev->function.descriptors = fs_printer_function;
+	dev->function.hs_descriptors = hs_printer_function;
+	dev->function.bind = printer_func_bind;
+	dev->function.setup = printer_func_setup;
+	dev->function.unbind = printer_func_unbind;
+	dev->function.set_alt = printer_func_set_alt;
+	dev->function.disable = printer_func_disable;
 
 	/* Setup the sysfs files for the printer gadget. */
 	dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
@@ -1393,29 +1159,6 @@
 		init_utsname()->sysname, init_utsname()->release,
 		gadget->name);
 
-	device_desc.idVendor =
-		cpu_to_le16(PRINTER_VENDOR_NUM);
-	device_desc.idProduct =
-		cpu_to_le16(PRINTER_PRODUCT_NUM);
-
-	/* support optional vendor/distro customization */
-	if (idVendor) {
-		if (!idProduct) {
-			dev_err(&gadget->dev, "idVendor needs idProduct!\n");
-			return -ENODEV;
-		}
-		device_desc.idVendor = cpu_to_le16(idVendor);
-		device_desc.idProduct = cpu_to_le16(idProduct);
-		if (bcdDevice)
-			device_desc.bcdDevice = cpu_to_le16(bcdDevice);
-	}
-
-	if (iManufacturer)
-		strlcpy(manufacturer, iManufacturer, sizeof manufacturer);
-
-	if (iProduct)
-		strlcpy(product_desc, iProduct, sizeof product_desc);
-
 	if (iSerialNum)
 		strlcpy(serial_num, iSerialNum, sizeof serial_num);
 
@@ -1442,17 +1185,16 @@
 		goto autoconf_fail;
 	out_ep->driver_data = out_ep;	/* claim */
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
 	/* assumes that all endpoints are dual-speed */
 	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
 	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
-#endif	/* DUALSPEED */
 
 	usb_gadget_set_selfpowered(gadget);
 
 	if (gadget->is_otg) {
-		otg_desc.bmAttributes |= USB_OTG_HNP,
-		config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		otg_descriptor.bmAttributes |= USB_OTG_HNP;
+		printer_cfg_driver.descriptors = otg_desc;
+		printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 	}
 
 	spin_lock_init(&dev->lock);
@@ -1466,7 +1208,6 @@
 	init_waitqueue_head(&dev->tx_wait);
 	init_waitqueue_head(&dev->tx_flush_wait);
 
-	dev->config = 0;
 	dev->interface = -1;
 	dev->printer_cdev_open = 0;
 	dev->printer_status = PRINTER_NOT_ERROR;
@@ -1477,14 +1218,6 @@
 	dev->in_ep = in_ep;
 	dev->out_ep = out_ep;
 
-	/* preallocate control message data and buffer */
-	dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE,
-			GFP_KERNEL);
-	if (!dev->req) {
-		status = -ENOMEM;
-		goto fail;
-	}
-
 	for (i = 0; i < QLEN; i++) {
 		req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
 		if (!req) {
@@ -1513,45 +1246,37 @@
 		list_add(&req->list, &dev->rx_reqs);
 	}
 
-	dev->req->complete = printer_setup_complete;
-
 	/* finish hookup to lower layer ... */
 	dev->gadget = gadget;
-	set_gadget_data(gadget, dev);
-	gadget->ep0->driver_data = dev;
 
 	INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
 	INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
 			in_ep->name);
-
 	return 0;
 
 fail:
-	printer_unbind(gadget);
+	printer_cfg_unbind(c);
 	return status;
 }
 
-/*-------------------------------------------------------------------------*/
+static int printer_unbind(struct usb_composite_dev *cdev)
+{
+	return 0;
+}
 
-static struct usb_gadget_driver printer_driver = {
-	.max_speed	= DEVSPEED,
+static int __init printer_bind(struct usb_composite_dev *cdev)
+{
+	return usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
+}
 
-	.function	= (char *) driver_desc,
+static struct usb_composite_driver printer_driver = {
+	.name           = shortname,
+	.dev            = &device_desc,
+	.strings        = dev_strings,
+	.max_speed      = USB_SPEED_HIGH,
 	.unbind		= printer_unbind,
-
-	.setup		= printer_setup,
-	.disconnect	= printer_disconnect,
-
-	.driver		= {
-		.name		= (char *) shortname,
-		.owner		= THIS_MODULE,
-	},
 };
 
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Craig Nadler");
-MODULE_LICENSE("GPL");
-
 static int __init
 init(void)
 {
@@ -1560,23 +1285,23 @@
 	usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
 	if (IS_ERR(usb_gadget_class)) {
 		status = PTR_ERR(usb_gadget_class);
-		ERROR(dev, "unable to create usb_gadget class %d\n", status);
+		pr_err("unable to create usb_gadget class %d\n", status);
 		return status;
 	}
 
 	status = alloc_chrdev_region(&g_printer_devno, 0, 1,
 			"USB printer gadget");
 	if (status) {
-		ERROR(dev, "alloc_chrdev_region %d\n", status);
+		pr_err("alloc_chrdev_region %d\n", status);
 		class_destroy(usb_gadget_class);
 		return status;
 	}
 
-	status = usb_gadget_probe_driver(&printer_driver, printer_bind);
+	status = usb_composite_probe(&printer_driver, printer_bind);
 	if (status) {
 		class_destroy(usb_gadget_class);
 		unregister_chrdev_region(g_printer_devno, 1);
-		DBG(dev, "usb_gadget_probe_driver %x\n", status);
+		pr_err("usb_gadget_probe_driver %x\n", status);
 	}
 
 	return status;
@@ -1586,15 +1311,14 @@
 static void __exit
 cleanup(void)
 {
-	int status;
-
 	mutex_lock(&usb_printer_gadget.lock_printer_io);
-	status = usb_gadget_unregister_driver(&printer_driver);
-	if (status)
-		ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
-
+	usb_composite_unregister(&printer_driver);
 	unregister_chrdev_region(g_printer_devno, 1);
 	class_destroy(usb_gadget_class);
 	mutex_unlock(&usb_printer_gadget.lock_printer_io);
 }
 module_exit(cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Craig Nadler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 41ed69c..d7c8cb3 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -218,7 +218,7 @@
 	struct pxa25x_udc       *dev;
 
 	ep = container_of (_ep, struct pxa25x_ep, ep);
-	if (!_ep || !desc || ep->desc || _ep->name == ep0name
+	if (!_ep || !desc || ep->ep.desc || _ep->name == ep0name
 			|| desc->bDescriptorType != USB_DT_ENDPOINT
 			|| ep->bEndpointAddress != desc->bEndpointAddress
 			|| ep->fifo_size < usb_endpoint_maxp (desc)) {
@@ -249,7 +249,7 @@
 		return -ESHUTDOWN;
 	}
 
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	ep->stopped = 0;
 	ep->pio_irqs = 0;
 	ep->ep.maxpacket = usb_endpoint_maxp (desc);
@@ -269,7 +269,7 @@
 	unsigned long		flags;
 
 	ep = container_of (_ep, struct pxa25x_ep, ep);
-	if (!_ep || !ep->desc) {
+	if (!_ep || !ep->ep.desc) {
 		DMSG("%s, %s not enabled\n", __func__,
 			_ep ? ep->ep.name : NULL);
 		return -EINVAL;
@@ -281,7 +281,6 @@
 	/* flush fifo (mostly for IN buffers) */
 	pxa25x_ep_fifo_flush (_ep);
 
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	ep->stopped = 1;
 
@@ -390,7 +389,7 @@
 {
 	unsigned		max;
 
-	max = usb_endpoint_maxp(ep->desc);
+	max = usb_endpoint_maxp(ep->ep.desc);
 	do {
 		unsigned	count;
 		int		is_last, is_short;
@@ -644,7 +643,7 @@
 	}
 
 	ep = container_of(_ep, struct pxa25x_ep, ep);
-	if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+	if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
 		DMSG("%s, bad ep\n", __func__);
 		return -EINVAL;
 	}
@@ -660,7 +659,7 @@
 	 * we can report per-packet status.  that also helps with dma.
 	 */
 	if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
-		        && req->req.length > usb_endpoint_maxp (ep->desc)))
+			&& req->req.length > usb_endpoint_maxp(ep->ep.desc)))
 		return -EMSGSIZE;
 
 	DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
@@ -673,7 +672,7 @@
 
 	/* kickstart this i/o queue? */
 	if (list_empty(&ep->queue) && !ep->stopped) {
-		if (ep->desc == NULL/* ep0 */) {
+		if (ep->ep.desc == NULL/* ep0 */) {
 			unsigned	length = _req->length;
 
 			switch (dev->ep0state) {
@@ -722,7 +721,7 @@
 			req = NULL;
 		}
 
-		if (likely (req && ep->desc))
+		if (likely(req && ep->ep.desc))
 			pio_irq_enable(ep->bEndpointAddress);
 	}
 
@@ -749,7 +748,7 @@
 				queue);
 		done(ep, req, status);
 	}
-	if (ep->desc)
+	if (ep->ep.desc)
 		pio_irq_disable (ep->bEndpointAddress);
 }
 
@@ -792,7 +791,7 @@
 
 	ep = container_of(_ep, struct pxa25x_ep, ep);
 	if (unlikely (!_ep
-			|| (!ep->desc && ep->ep.name != ep0name))
+			|| (!ep->ep.desc && ep->ep.name != ep0name))
 			|| ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
 		DMSG("%s, bad ep\n", __func__);
 		return -EINVAL;
@@ -820,7 +819,7 @@
 	*ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF;
 
 	/* ep0 needs special care */
-	if (!ep->desc) {
+	if (!ep->ep.desc) {
 		start_watchdog(ep->dev);
 		ep->dev->req_pending = 0;
 		ep->dev->ep0state = EP0_STALL;
@@ -1087,7 +1086,7 @@
 		if (i != 0) {
 			const struct usb_endpoint_descriptor	*desc;
 
-			desc = ep->desc;
+			desc = ep->ep.desc;
 			if (!desc)
 				continue;
 			tmp = *dev->ep [i].reg_udccs;
@@ -1191,7 +1190,6 @@
 		if (i != 0)
 			list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
 
-		ep->desc = NULL;
 		ep->ep.desc = NULL;
 		ep->stopped = 0;
 		INIT_LIST_HEAD (&ep->queue);
diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h
index 893e917..861f4df 100644
--- a/drivers/usb/gadget/pxa25x_udc.h
+++ b/drivers/usb/gadget/pxa25x_udc.h
@@ -41,7 +41,6 @@
 	struct usb_ep				ep;
 	struct pxa25x_udc			*dev;
 
-	const struct usb_endpoint_descriptor	*desc;
 	struct list_head			queue;
 	unsigned long				pio_irqs;
 
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index c4401e7..f3ac2a2 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -459,7 +459,7 @@
 	unsigned char *counter;
 	int ret;
 
-	ep->desc = desc;
+	ep->ep.desc = desc;
 
 	if (ep->pipenum)	/* already allocated pipe  */
 		return 0;
@@ -648,7 +648,7 @@
 	/* set SUDMAC parameters */
 	dma = &r8a66597->dma;
 	dma->used = 1;
-	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+	if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) {
 		dma->dir = 1;
 	} else {
 		dma->dir = 0;
@@ -770,7 +770,7 @@
 
 static void start_packet(struct r8a66597_ep *ep, struct r8a66597_request *req)
 {
-	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+	if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
 		start_packet_write(ep, req);
 	else
 		start_packet_read(ep, req);
@@ -930,7 +930,7 @@
 
 	if (restart) {
 		req = get_request_from_ep(ep);
-		if (ep->desc)
+		if (ep->ep.desc)
 			start_packet(ep, req);
 	}
 }
@@ -1116,7 +1116,7 @@
 				r8a66597_write(r8a66597, ~check, BRDYSTS);
 				ep = r8a66597->pipenum2ep[pipenum];
 				req = get_request_from_ep(ep);
-				if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
 					irq_packet_write(ep, req);
 				else
 					irq_packet_read(ep, req);
@@ -1170,7 +1170,7 @@
 
 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
 	case USB_RECIP_DEVICE:
-		status = 1 << USB_DEVICE_SELF_POWERED;
+		status = r8a66597->device_status;
 		break;
 	case USB_RECIP_INTERFACE:
 		status = 0;
@@ -1627,7 +1627,7 @@
 	req->req.actual = 0;
 	req->req.status = -EINPROGRESS;
 
-	if (ep->desc == NULL)	/* control */
+	if (ep->ep.desc == NULL)	/* control */
 		start_ep0(ep, req);
 	else {
 		if (request && !ep->busy)
@@ -1692,7 +1692,7 @@
 
 	ep = container_of(_ep, struct r8a66597_ep, ep);
 
-	if (!ep || !ep->desc)
+	if (!ep || !ep->ep.desc)
 		return -EINVAL;
 
 	spin_lock_irqsave(&ep->r8a66597->lock, flags);
@@ -1800,11 +1800,24 @@
 	return 0;
 }
 
+static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self)
+{
+	struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
+
+	if (is_self)
+		r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
+	else
+		r8a66597->device_status &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+	return 0;
+}
+
 static struct usb_gadget_ops r8a66597_gadget_ops = {
 	.get_frame		= r8a66597_get_frame,
 	.udc_start		= r8a66597_start,
 	.udc_stop		= r8a66597_stop,
 	.pullup			= r8a66597_pullup,
+	.set_selfpowered	= r8a66597_set_selfpowered,
 };
 
 static int __exit r8a66597_remove(struct platform_device *pdev)
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h
index 8e3de61..99908c7 100644
--- a/drivers/usb/gadget/r8a66597-udc.h
+++ b/drivers/usb/gadget/r8a66597-udc.h
@@ -72,7 +72,7 @@
 	unsigned		use_dma:1;
 	u16			pipenum;
 	u16			type;
-	const struct usb_endpoint_descriptor	*desc;
+
 	/* register address */
 	unsigned char		fifoaddr;
 	unsigned char		fifosel;
@@ -111,6 +111,7 @@
 	u16			old_vbus;
 	u16			scount;
 	u16			old_dvsq;
+	u16			device_status;	/* for GET_STATUS */
 
 	/* pipe config */
 	unsigned char bulk;
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 105b206..f4abb0e 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -1,4 +1,5 @@
-/* linux/drivers/usb/gadget/s3c-hsotg.c
+/**
+ * linux/drivers/usb/gadget/s3c-hsotg.c
  *
  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
@@ -13,7 +14,7 @@
  * 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>
@@ -27,21 +28,25 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/regulator/consumer.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #include <mach/map.h>
 
-#include <plat/regs-usb-hsotg-phy.h>
-#include <plat/regs-usb-hsotg.h>
-#include <mach/regs-sys.h>
-#include <plat/udc-hs.h>
-#include <plat/cpu.h>
+#include "s3c-hsotg.h"
 
 #define DMA_ADDR_INVALID (~((dma_addr_t)0))
 
-/* EP0_MPS_LIMIT
+static const char * const s3c_hsotg_supply_names[] = {
+	"vusb_d",		/* digital USB supply, 1.2V */
+	"vusb_a",		/* analog USB supply, 1.1V */
+};
+
+/*
+ * EP0_MPS_LIMIT
  *
  * Unfortunately there seems to be a limit of the amount of data that can
  * be transferred by IN transactions on EP0. This is either 127 bytes or 3
@@ -125,8 +130,6 @@
 	char			name[10];
 };
 
-#define S3C_HSOTG_EPS	(8+1)	/* limit to 9 for the moment */
-
 /**
  * struct s3c_hsotg - driver state.
  * @dev: The parent device supplied to the probe function
@@ -135,7 +138,9 @@
  * @regs: The memory area mapped for accessing registers.
  * @regs_res: The resource that was allocated when claiming register space.
  * @irq: The IRQ number we are using
+ * @supplies: Definition of USB power supplies
  * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
+ * @num_of_eps: Number of available EPs (excluding EP0)
  * @debug_root: root directrory for debugfs.
  * @debug_file: main status file for debugfs.
  * @debug_fifo: FIFO status file for debugfs.
@@ -143,6 +148,8 @@
  * @ep0_buff: Buffer for EP0 reply data, if needed.
  * @ctrl_buff: Buffer for EP0 control requests.
  * @ctrl_req: Request for EP0 control packets.
+ * @setup: NAK management for EP0 SETUP
+ * @last_rst: Time of last reset
  * @eps: The endpoints being supplied to the gadget framework
  */
 struct s3c_hsotg {
@@ -155,7 +162,10 @@
 	int			irq;
 	struct clk		*clk;
 
+	struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
+
 	unsigned int		dedicated_fifos:1;
+	unsigned char           num_of_eps;
 
 	struct dentry		*debug_root;
 	struct dentry		*debug_file;
@@ -167,7 +177,9 @@
 	u8			ctrl_buff[8];
 
 	struct usb_gadget	gadget;
-	struct s3c_hsotg_ep	eps[];
+	unsigned int		setup;
+	unsigned long           last_rst;
+	struct s3c_hsotg_ep	*eps;
 };
 
 /**
@@ -244,14 +256,14 @@
  */
 static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints)
 {
-	u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+	u32 gsintmsk = readl(hsotg->regs + GINTMSK);
 	u32 new_gsintmsk;
 
 	new_gsintmsk = gsintmsk | ints;
 
 	if (new_gsintmsk != gsintmsk) {
 		dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk);
-		writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+		writel(new_gsintmsk, hsotg->regs + GINTMSK);
 	}
 }
 
@@ -262,13 +274,13 @@
  */
 static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints)
 {
-	u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+	u32 gsintmsk = readl(hsotg->regs + GINTMSK);
 	u32 new_gsintmsk;
 
 	new_gsintmsk = gsintmsk & ~ints;
 
 	if (new_gsintmsk != gsintmsk)
-		writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+		writel(new_gsintmsk, hsotg->regs + GINTMSK);
 }
 
 /**
@@ -293,12 +305,12 @@
 		bit <<= 16;
 
 	local_irq_save(flags);
-	daint = readl(hsotg->regs + S3C_DAINTMSK);
+	daint = readl(hsotg->regs + DAINTMSK);
 	if (en)
 		daint |= bit;
 	else
 		daint &= ~bit;
-	writel(daint, hsotg->regs + S3C_DAINTMSK);
+	writel(daint, hsotg->regs + DAINTMSK);
 	local_irq_restore(flags);
 }
 
@@ -314,52 +326,51 @@
 	int timeout;
 	u32 val;
 
-	/* the ryu 2.6.24 release ahs
-	   writel(0x1C0, hsotg->regs + S3C_GRXFSIZ);
-	   writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) |
-		S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
-		hsotg->regs + S3C_GNPTXFSIZ);
-	*/
-
 	/* set FIFO sizes to 2048/1024 */
 
-	writel(2048, hsotg->regs + S3C_GRXFSIZ);
-	writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) |
-	       S3C_GNPTXFSIZ_NPTxFDep(1024),
-	       hsotg->regs + S3C_GNPTXFSIZ);
+	writel(2048, hsotg->regs + GRXFSIZ);
+	writel(GNPTXFSIZ_NPTxFStAddr(2048) |
+	       GNPTXFSIZ_NPTxFDep(1024),
+	       hsotg->regs + GNPTXFSIZ);
 
-	/* arange all the rest of the TX FIFOs, as some versions of this
+	/*
+	 * arange all the rest of the TX FIFOs, as some versions of this
 	 * block have overlapping default addresses. This also ensures
 	 * that if the settings have been changed, then they are set to
-	 * known values. */
+	 * known values.
+	 */
 
 	/* start at the end of the GNPTXFSIZ, rounded up */
 	addr = 2048 + 1024;
 	size = 768;
 
-	/* currently we allocate TX FIFOs for all possible endpoints,
-	 * and assume that they are all the same size. */
+	/*
+	 * currently we allocate TX FIFOs for all possible endpoints,
+	 * and assume that they are all the same size.
+	 */
 
 	for (ep = 1; ep <= 15; ep++) {
 		val = addr;
-		val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT;
+		val |= size << DPTXFSIZn_DPTxFSize_SHIFT;
 		addr += size;
 
-		writel(val, hsotg->regs + S3C_DPTXFSIZn(ep));
+		writel(val, hsotg->regs + DPTXFSIZn(ep));
 	}
 
-	/* according to p428 of the design guide, we need to ensure that
-	 * all fifos are flushed before continuing */
+	/*
+	 * according to p428 of the design guide, we need to ensure that
+	 * all fifos are flushed before continuing
+	 */
 
-	writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh |
-	       S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_GRSTCTL);
+	writel(GRSTCTL_TxFNum(0x10) | GRSTCTL_TxFFlsh |
+	       GRSTCTL_RxFFlsh, hsotg->regs + GRSTCTL);
 
 	/* wait until the fifos are both flushed */
 	timeout = 100;
 	while (1) {
-		val = readl(hsotg->regs + S3C_GRSTCTL);
+		val = readl(hsotg->regs + GRSTCTL);
 
-		if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0)
+		if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0)
 			break;
 
 		if (--timeout == 0) {
@@ -415,7 +426,7 @@
  *
  * This is the reverse of s3c_hsotg_map_dma(), called for the completion
  * of a request to ensure the buffer is ready for access by the caller.
-*/
+ */
 static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
 				struct s3c_hsotg_ep *hs_ep,
 				struct s3c_hsotg_req *hs_req)
@@ -456,13 +467,13 @@
  * otherwise -ENOSPC is returned if the FIFO space was used up.
  *
  * This routine is only needed for PIO
-*/
+ */
 static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
 				struct s3c_hsotg_ep *hs_ep,
 				struct s3c_hsotg_req *hs_req)
 {
 	bool periodic = is_ep_periodic(hs_ep);
-	u32 gnptxsts = readl(hsotg->regs + S3C_GNPTXSTS);
+	u32 gnptxsts = readl(hsotg->regs + GNPTXSTS);
 	int buf_pos = hs_req->req.actual;
 	int to_write = hs_ep->size_loaded;
 	void *data;
@@ -476,20 +487,23 @@
 		return 0;
 
 	if (periodic && !hsotg->dedicated_fifos) {
-		u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
+		u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index));
 		int size_left;
 		int size_done;
 
-		/* work out how much data was loaded so we can calculate
-		 * how much data is left in the fifo. */
+		/*
+		 * work out how much data was loaded so we can calculate
+		 * how much data is left in the fifo.
+		 */
 
-		size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+		size_left = DxEPTSIZ_XferSize_GET(epsize);
 
-		/* if shared fifo, we cannot write anything until the
+		/*
+		 * if shared fifo, we cannot write anything until the
 		 * previous data has been completely sent.
 		 */
 		if (hs_ep->fifo_load != 0) {
-			s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+			s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp);
 			return -ENOSPC;
 		}
 
@@ -510,47 +524,50 @@
 			__func__, can_write);
 
 		if (can_write <= 0) {
-			s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+			s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp);
 			return -ENOSPC;
 		}
 	} else if (hsotg->dedicated_fifos && hs_ep->index != 0) {
-		can_write = readl(hsotg->regs + S3C_DTXFSTS(hs_ep->index));
+		can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index));
 
 		can_write &= 0xffff;
 		can_write *= 4;
 	} else {
-		if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
+		if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
 			dev_dbg(hsotg->dev,
 				"%s: no queue slots available (0x%08x)\n",
 				__func__, gnptxsts);
 
-			s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
+			s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp);
 			return -ENOSPC;
 		}
 
-		can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts);
+		can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts);
 		can_write *= 4;	/* fifo size is in 32bit quantities. */
 	}
 
 	dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n",
 		 __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket);
 
-	/* limit to 512 bytes of data, it seems at least on the non-periodic
+	/*
+	 * limit to 512 bytes of data, it seems at least on the non-periodic
 	 * FIFO, requests of >512 cause the endpoint to get stuck with a
 	 * fragment of the end of the transfer in it.
 	 */
 	if (can_write > 512)
 		can_write = 512;
 
-	/* limit the write to one max-packet size worth of data, but allow
+	/*
+	 * limit the write to one max-packet size worth of data, but allow
 	 * the transfer to return that it did not run out of fifo space
-	 * doing it. */
+	 * doing it.
+	 */
 	if (to_write > hs_ep->ep.maxpacket) {
 		to_write = hs_ep->ep.maxpacket;
 
 		s3c_hsotg_en_gsint(hsotg,
-				   periodic ? S3C_GINTSTS_PTxFEmp :
-				   S3C_GINTSTS_NPTxFEmp);
+				   periodic ? GINTSTS_PTxFEmp :
+				   GINTSTS_NPTxFEmp);
 	}
 
 	/* see if we can write data */
@@ -559,8 +576,8 @@
 		to_write = can_write;
 		pkt_round = to_write % hs_ep->ep.maxpacket;
 
-		/* Not sure, but we probably shouldn't be writing partial
-		 * packets into the FIFO, so round the write down to an
+		/*
+		 * Round the write down to an
 		 * exact number of packets.
 		 *
 		 * Note, we do not currently check to see if we can ever
@@ -570,12 +587,14 @@
 		if (pkt_round)
 			to_write -= pkt_round;
 
-		/* enable correct FIFO interrupt to alert us when there
-		 * is more room left. */
+		/*
+		 * enable correct FIFO interrupt to alert us when there
+		 * is more room left.
+		 */
 
 		s3c_hsotg_en_gsint(hsotg,
-				   periodic ? S3C_GINTSTS_PTxFEmp :
-				   S3C_GINTSTS_NPTxFEmp);
+				   periodic ? GINTSTS_PTxFEmp :
+				   GINTSTS_NPTxFEmp);
 	}
 
 	dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n",
@@ -593,7 +612,7 @@
 	to_write = DIV_ROUND_UP(to_write, 4);
 	data = hs_req->req.buf + buf_pos;
 
-	writesl(hsotg->regs + S3C_EPFIFO(hs_ep->index), data, to_write);
+	writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write);
 
 	return (to_write >= can_write) ? -ENOSPC : 0;
 }
@@ -612,12 +631,12 @@
 	unsigned maxpkt;
 
 	if (index != 0) {
-		maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1;
-		maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1;
+		maxsize = DxEPTSIZ_XferSize_LIMIT + 1;
+		maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1;
 	} else {
 		maxsize = 64+64;
 		if (hs_ep->dir_in)
-			maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1;
+			maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1;
 		else
 			maxpkt = 2;
 	}
@@ -626,8 +645,10 @@
 	maxpkt--;
 	maxsize--;
 
-	/* constrain by packet count if maxpkts*pktsize is greater
-	 * than the length register size. */
+	/*
+	 * constrain by packet count if maxpkts*pktsize is greater
+	 * than the length register size.
+	 */
 
 	if ((maxpkt * hs_ep->ep.maxpacket) < maxsize)
 		maxsize = maxpkt * hs_ep->ep.maxpacket;
@@ -674,8 +695,8 @@
 		}
 	}
 
-	epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
-	epsize_reg = dir_in ? S3C_DIEPTSIZ(index) : S3C_DOEPTSIZ(index);
+	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
+	epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
 
 	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n",
 		__func__, readl(hsotg->regs + epctrl_reg), index,
@@ -684,13 +705,14 @@
 	/* If endpoint is stalled, we will restart request later */
 	ctrl = readl(hsotg->regs + epctrl_reg);
 
-	if (ctrl & S3C_DxEPCTL_Stall) {
+	if (ctrl & DxEPCTL_Stall) {
 		dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
 		return;
 	}
 
 	length = ureq->length - ureq->actual;
-
+	dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n",
+		ureq->length, ureq->actual);
 	if (0)
 		dev_dbg(hsotg->dev,
 			"REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n",
@@ -717,20 +739,22 @@
 		packets = 1;	/* send one packet if length is zero. */
 
 	if (dir_in && index != 0)
-		epsize = S3C_DxEPTSIZ_MC(1);
+		epsize = DxEPTSIZ_MC(1);
 	else
 		epsize = 0;
 
 	if (index != 0 && ureq->zero) {
-		/* test for the packets being exactly right for the
-		 * transfer */
+		/*
+		 * test for the packets being exactly right for the
+		 * transfer
+		 */
 
 		if (length == (packets * hs_ep->ep.maxpacket))
 			packets++;
 	}
 
-	epsize |= S3C_DxEPTSIZ_PktCnt(packets);
-	epsize |= S3C_DxEPTSIZ_XferSize(length);
+	epsize |= DxEPTSIZ_PktCnt(packets);
+	epsize |= DxEPTSIZ_XferSize(length);
 
 	dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n",
 		__func__, packets, length, ureq->length, epsize, epsize_reg);
@@ -744,26 +768,38 @@
 	if (using_dma(hsotg) && !continuing) {
 		unsigned int dma_reg;
 
-		/* write DMA address to control register, buffer already
-		 * synced by s3c_hsotg_ep_queue().  */
+		/*
+		 * write DMA address to control register, buffer already
+		 * synced by s3c_hsotg_ep_queue().
+		 */
 
-		dma_reg = dir_in ? S3C_DIEPDMA(index) : S3C_DOEPDMA(index);
+		dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);
 		writel(ureq->dma, hsotg->regs + dma_reg);
 
 		dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n",
 			__func__, ureq->dma, dma_reg);
 	}
 
-	ctrl |= S3C_DxEPCTL_EPEna;	/* ensure ep enabled */
-	ctrl |= S3C_DxEPCTL_USBActEp;
-	ctrl |= S3C_DxEPCTL_CNAK;	/* clear NAK set by core */
+	ctrl |= DxEPCTL_EPEna;	/* ensure ep enabled */
+	ctrl |= DxEPCTL_USBActEp;
+
+	dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup);
+
+	/* For Setup request do not clear NAK */
+	if (hsotg->setup && index == 0)
+		hsotg->setup = 0;
+	else
+		ctrl |= DxEPCTL_CNAK;	/* clear NAK set by core */
+
 
 	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
 	writel(ctrl, hsotg->regs + epctrl_reg);
 
-	/* set these, it seems that DMA support increments past the end
+	/*
+	 * set these, it seems that DMA support increments past the end
 	 * of the packet buffer so we need to calculate the length from
-	 * this information. */
+	 * this information.
+	 */
 	hs_ep->size_loaded = length;
 	hs_ep->last_load = ureq->actual;
 
@@ -774,17 +810,21 @@
 		s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req);
 	}
 
-	/* clear the INTknTXFEmpMsk when we start request, more as a aide
-	 * to debugging to see what is going on. */
+	/*
+	 * clear the INTknTXFEmpMsk when we start request, more as a aide
+	 * to debugging to see what is going on.
+	 */
 	if (dir_in)
-		writel(S3C_DIEPMSK_INTknTXFEmpMsk,
-		       hsotg->regs + S3C_DIEPINT(index));
+		writel(DIEPMSK_INTknTXFEmpMsk,
+		       hsotg->regs + DIEPINT(index));
 
-	/* Note, trying to clear the NAK here causes problems with transmit
-	 * on the S3C6400 ending up with the TXFIFO becoming full. */
+	/*
+	 * Note, trying to clear the NAK here causes problems with transmit
+	 * on the S3C6400 ending up with the TXFIFO becoming full.
+	 */
 
 	/* check ep is enabled */
-	if (!(readl(hsotg->regs + epctrl_reg) & S3C_DxEPCTL_EPEna))
+	if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna))
 		dev_warn(hsotg->dev,
 			 "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n",
 			 index, readl(hsotg->regs + epctrl_reg));
@@ -804,7 +844,7 @@
  * then ensure the buffer has been synced to memory. If our buffer has no
  * DMA memory, then we map the memory and mark our request to allow us to
  * cleanup on completion.
-*/
+ */
 static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
 			     struct s3c_hsotg_ep *hs_ep,
 			     struct usb_request *req)
@@ -922,7 +962,7 @@
  *
  * Convert the given wIndex into a pointer to an driver endpoint
  * structure, or return NULL if it is not a valid endpoint.
-*/
+ */
 static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg,
 					   u32 windex)
 {
@@ -933,7 +973,7 @@
 	if (windex >= 0x100)
 		return NULL;
 
-	if (idx > S3C_HSOTG_EPS)
+	if (idx > hsotg->num_of_eps)
 		return NULL;
 
 	if (idx && ep->dir_in != dir)
@@ -1151,24 +1191,28 @@
 		 ctrl->bRequest, ctrl->bRequestType,
 		 ctrl->wValue, ctrl->wLength);
 
-	/* record the direction of the request, for later use when enquing
-	 * packets onto EP0. */
+	/*
+	 * record the direction of the request, for later use when enquing
+	 * packets onto EP0.
+	 */
 
 	ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0;
 	dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in);
 
-	/* if we've no data with this request, then the last part of the
-	 * transaction is going to implicitly be IN. */
+	/*
+	 * if we've no data with this request, then the last part of the
+	 * transaction is going to implicitly be IN.
+	 */
 	if (ctrl->wLength == 0)
 		ep0->dir_in = 1;
 
 	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
 		switch (ctrl->bRequest) {
 		case USB_REQ_SET_ADDRESS:
-			dcfg = readl(hsotg->regs + S3C_DCFG);
-			dcfg &= ~S3C_DCFG_DevAddr_MASK;
-			dcfg |= ctrl->wValue << S3C_DCFG_DevAddr_SHIFT;
-			writel(dcfg, hsotg->regs + S3C_DCFG);
+			dcfg = readl(hsotg->regs + DCFG);
+			dcfg &= ~DCFG_DevAddr_MASK;
+			dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT;
+			writel(dcfg, hsotg->regs + DCFG);
 
 			dev_info(hsotg->dev, "new address %d\n", ctrl->wValue);
 
@@ -1194,7 +1238,8 @@
 			dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
 	}
 
-	/* the request is either unhandlable, or is not formatted correctly
+	/*
+	 * the request is either unhandlable, or is not formatted correctly
 	 * so respond with a STALL for the status stage to indicate failure.
 	 */
 
@@ -1203,22 +1248,26 @@
 		u32 ctrl;
 
 		dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
-		reg = (ep0->dir_in) ? S3C_DIEPCTL0 : S3C_DOEPCTL0;
+		reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
 
-		/* S3C_DxEPCTL_Stall will be cleared by EP once it has
-		 * taken effect, so no need to clear later. */
+		/*
+		 * DxEPCTL_Stall will be cleared by EP once it has
+		 * taken effect, so no need to clear later.
+		 */
 
 		ctrl = readl(hsotg->regs + reg);
-		ctrl |= S3C_DxEPCTL_Stall;
-		ctrl |= S3C_DxEPCTL_CNAK;
+		ctrl |= DxEPCTL_Stall;
+		ctrl |= DxEPCTL_CNAK;
 		writel(ctrl, hsotg->regs + reg);
 
 		dev_dbg(hsotg->dev,
 			"written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n",
 			ctrl, reg, readl(hsotg->regs + reg));
 
-		/* don't believe we need to anything more to get the EP
-		 * to reply with a STALL packet */
+		/*
+		 * don't believe we need to anything more to get the EP
+		 * to reply with a STALL packet
+		 */
 	}
 }
 
@@ -1279,8 +1328,10 @@
 	ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC);
 	if (ret < 0) {
 		dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret);
-		/* Don't think there's much we can do other than watch the
-		 * driver fail. */
+		/*
+		 * Don't think there's much we can do other than watch the
+		 * driver fail.
+		 */
 	}
 }
 
@@ -1296,7 +1347,7 @@
  * on the endpoint.
  *
  * Note, expects the ep to already be locked as appropriate.
-*/
+ */
 static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
 				       struct s3c_hsotg_ep *hs_ep,
 				       struct s3c_hsotg_req *hs_req,
@@ -1312,8 +1363,10 @@
 	dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n",
 		hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete);
 
-	/* only replace the status if we've not already set an error
-	 * from a previous transaction */
+	/*
+	 * only replace the status if we've not already set an error
+	 * from a previous transaction
+	 */
 
 	if (hs_req->req.status == -EINPROGRESS)
 		hs_req->req.status = result;
@@ -1324,8 +1377,10 @@
 	if (using_dma(hsotg))
 		s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req);
 
-	/* call the complete request with the locks off, just in case the
-	 * request tries to queue more work for this endpoint. */
+	/*
+	 * call the complete request with the locks off, just in case the
+	 * request tries to queue more work for this endpoint.
+	 */
 
 	if (hs_req->req.complete) {
 		spin_unlock(&hs_ep->lock);
@@ -1333,9 +1388,11 @@
 		spin_lock(&hs_ep->lock);
 	}
 
-	/* Look to see if there is anything else to do. Note, the completion
+	/*
+	 * Look to see if there is anything else to do. Note, the completion
 	 * of the previous request may have caused a new request to be started
-	 * so be careful when doing this. */
+	 * so be careful when doing this.
+	 */
 
 	if (!hs_ep->req && result >= 0) {
 		restart = !list_empty(&hs_ep->queue);
@@ -1355,7 +1412,7 @@
  *
  * See s3c_hsotg_complete_request(), but called with the endpoint's
  * lock held.
-*/
+ */
 static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg,
 					    struct s3c_hsotg_ep *hs_ep,
 					    struct s3c_hsotg_req *hs_req,
@@ -1382,13 +1439,13 @@
 {
 	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx];
 	struct s3c_hsotg_req *hs_req = hs_ep->req;
-	void __iomem *fifo = hsotg->regs + S3C_EPFIFO(ep_idx);
+	void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx);
 	int to_read;
 	int max_req;
 	int read_ptr;
 
 	if (!hs_req) {
-		u32 epctl = readl(hsotg->regs + S3C_DOEPCTL(ep_idx));
+		u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx));
 		int ptr;
 
 		dev_warn(hsotg->dev,
@@ -1412,7 +1469,8 @@
 		__func__, to_read, max_req, read_ptr, hs_req->req.length);
 
 	if (to_read > max_req) {
-		/* more data appeared than we where willing
+		/*
+		 * more data appeared than we where willing
 		 * to deal with in this request.
 		 */
 
@@ -1424,8 +1482,10 @@
 	hs_req->req.actual += to_read;
 	to_read = DIV_ROUND_UP(to_read, 4);
 
-	/* note, we might over-write the buffer end by 3 bytes depending on
-	 * alignment of the data. */
+	/*
+	 * note, we might over-write the buffer end by 3 bytes depending on
+	 * alignment of the data.
+	 */
 	readsl(fifo, hs_req->req.buf + read_ptr, to_read);
 
 	spin_unlock(&hs_ep->lock);
@@ -1465,14 +1525,14 @@
 	dev_dbg(hsotg->dev, "sending zero-length packet\n");
 
 	/* issue a zero-sized packet to terminate this */
-	writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) |
-	       S3C_DxEPTSIZ_XferSize(0), hsotg->regs + S3C_DIEPTSIZ(0));
+	writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) |
+	       DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0));
 
-	ctrl = readl(hsotg->regs + S3C_DIEPCTL0);
-	ctrl |= S3C_DxEPCTL_CNAK;  /* clear NAK set by core */
-	ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */
-	ctrl |= S3C_DxEPCTL_USBActEp;
-	writel(ctrl, hsotg->regs + S3C_DIEPCTL0);
+	ctrl = readl(hsotg->regs + DIEPCTL0);
+	ctrl |= DxEPCTL_CNAK;  /* clear NAK set by core */
+	ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */
+	ctrl |= DxEPCTL_USBActEp;
+	writel(ctrl, hsotg->regs + DIEPCTL0);
 }
 
 /**
@@ -1484,15 +1544,15 @@
  * The RXFIFO has delivered an OutDone event, which means that the data
  * transfer for an OUT endpoint has been completed, either by a short
  * packet or by the finish of a transfer.
-*/
+ */
 static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
 				     int epnum, bool was_setup)
 {
-	u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum));
+	u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum));
 	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum];
 	struct s3c_hsotg_req *hs_req = hs_ep->req;
 	struct usb_request *req = &hs_req->req;
-	unsigned size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+	unsigned size_left = DxEPTSIZ_XferSize_GET(epsize);
 	int result = 0;
 
 	if (!hs_req) {
@@ -1503,7 +1563,8 @@
 	if (using_dma(hsotg)) {
 		unsigned size_done;
 
-		/* Calculate the size of the transfer by checking how much
+		/*
+		 * Calculate the size of the transfer by checking how much
 		 * is left in the endpoint size register and then working it
 		 * out from the amount we loaded for the transfer.
 		 *
@@ -1521,17 +1582,29 @@
 	if (req->actual < req->length && size_left == 0) {
 		s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
 		return;
+	} else if (epnum == 0) {
+		/*
+		 * After was_setup = 1 =>
+		 * set CNAK for non Setup requests
+		 */
+		hsotg->setup = was_setup ? 0 : 1;
 	}
 
 	if (req->actual < req->length && req->short_not_ok) {
 		dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n",
 			__func__, req->actual, req->length);
 
-		/* todo - what should we return here? there's no one else
-		 * even bothering to check the status. */
+		/*
+		 * todo - what should we return here? there's no one else
+		 * even bothering to check the status.
+		 */
 	}
 
 	if (epnum == 0) {
+		/*
+		 * Condition req->complete != s3c_hsotg_complete_setup says:
+		 * send ZLP when we have an asynchronous request from gadget
+		 */
 		if (!was_setup && req->complete != s3c_hsotg_complete_setup)
 			s3c_hsotg_send_zlp(hsotg, hs_req);
 	}
@@ -1544,14 +1617,14 @@
  * @hsotg: The device instance
  *
  * Return the current frame number
-*/
+ */
 static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
 {
 	u32 dsts;
 
-	dsts = readl(hsotg->regs + S3C_DSTS);
-	dsts &= S3C_DSTS_SOFFN_MASK;
-	dsts >>= S3C_DSTS_SOFFN_SHIFT;
+	dsts = readl(hsotg->regs + DSTS);
+	dsts &= DSTS_SOFFN_MASK;
+	dsts >>= DSTS_SOFFN_SHIFT;
 
 	return dsts;
 }
@@ -1574,29 +1647,29 @@
  */
 static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
 {
-	u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP);
+	u32 grxstsr = readl(hsotg->regs + GRXSTSP);
 	u32 epnum, status, size;
 
 	WARN_ON(using_dma(hsotg));
 
-	epnum = grxstsr & S3C_GRXSTS_EPNum_MASK;
-	status = grxstsr & S3C_GRXSTS_PktSts_MASK;
+	epnum = grxstsr & GRXSTS_EPNum_MASK;
+	status = grxstsr & GRXSTS_PktSts_MASK;
 
-	size = grxstsr & S3C_GRXSTS_ByteCnt_MASK;
-	size >>= S3C_GRXSTS_ByteCnt_SHIFT;
+	size = grxstsr & GRXSTS_ByteCnt_MASK;
+	size >>= GRXSTS_ByteCnt_SHIFT;
 
 	if (1)
 		dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
 			__func__, grxstsr, size, epnum);
 
-#define __status(x) ((x) >> S3C_GRXSTS_PktSts_SHIFT)
+#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT)
 
-	switch (status >> S3C_GRXSTS_PktSts_SHIFT) {
-	case __status(S3C_GRXSTS_PktSts_GlobalOutNAK):
+	switch (status >> GRXSTS_PktSts_SHIFT) {
+	case __status(GRXSTS_PktSts_GlobalOutNAK):
 		dev_dbg(hsotg->dev, "GlobalOutNAK\n");
 		break;
 
-	case __status(S3C_GRXSTS_PktSts_OutDone):
+	case __status(GRXSTS_PktSts_OutDone):
 		dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n",
 			s3c_hsotg_read_frameno(hsotg));
 
@@ -1604,24 +1677,24 @@
 			s3c_hsotg_handle_outdone(hsotg, epnum, false);
 		break;
 
-	case __status(S3C_GRXSTS_PktSts_SetupDone):
+	case __status(GRXSTS_PktSts_SetupDone):
 		dev_dbg(hsotg->dev,
 			"SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
 			s3c_hsotg_read_frameno(hsotg),
-			readl(hsotg->regs + S3C_DOEPCTL(0)));
+			readl(hsotg->regs + DOEPCTL(0)));
 
 		s3c_hsotg_handle_outdone(hsotg, epnum, true);
 		break;
 
-	case __status(S3C_GRXSTS_PktSts_OutRX):
+	case __status(GRXSTS_PktSts_OutRX):
 		s3c_hsotg_rx_data(hsotg, epnum, size);
 		break;
 
-	case __status(S3C_GRXSTS_PktSts_SetupRX):
+	case __status(GRXSTS_PktSts_SetupRX):
 		dev_dbg(hsotg->dev,
 			"SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
 			s3c_hsotg_read_frameno(hsotg),
-			readl(hsotg->regs + S3C_DOEPCTL(0)));
+			readl(hsotg->regs + DOEPCTL(0)));
 
 		s3c_hsotg_rx_data(hsotg, epnum, size);
 		break;
@@ -1638,18 +1711,18 @@
 /**
  * s3c_hsotg_ep0_mps - turn max packet size into register setting
  * @mps: The maximum packet size in bytes.
-*/
+ */
 static u32 s3c_hsotg_ep0_mps(unsigned int mps)
 {
 	switch (mps) {
 	case 64:
-		return S3C_D0EPCTL_MPS_64;
+		return D0EPCTL_MPS_64;
 	case 32:
-		return S3C_D0EPCTL_MPS_32;
+		return D0EPCTL_MPS_32;
 	case 16:
-		return S3C_D0EPCTL_MPS_16;
+		return D0EPCTL_MPS_16;
 	case 8:
-		return S3C_D0EPCTL_MPS_8;
+		return D0EPCTL_MPS_8;
 	}
 
 	/* bad max packet size, warn and return invalid result */
@@ -1680,7 +1753,7 @@
 		if (mpsval > 3)
 			goto bad_mps;
 	} else {
-		if (mps >= S3C_DxEPCTL_MPS_LIMIT+1)
+		if (mps >= DxEPCTL_MPS_LIMIT+1)
 			goto bad_mps;
 
 		mpsval = mps;
@@ -1688,19 +1761,21 @@
 
 	hs_ep->ep.maxpacket = mps;
 
-	/* update both the in and out endpoint controldir_ registers, even
-	 * if one of the directions may not be in use. */
+	/*
+	 * update both the in and out endpoint controldir_ registers, even
+	 * if one of the directions may not be in use.
+	 */
 
-	reg = readl(regs + S3C_DIEPCTL(ep));
-	reg &= ~S3C_DxEPCTL_MPS_MASK;
+	reg = readl(regs + DIEPCTL(ep));
+	reg &= ~DxEPCTL_MPS_MASK;
 	reg |= mpsval;
-	writel(reg, regs + S3C_DIEPCTL(ep));
+	writel(reg, regs + DIEPCTL(ep));
 
 	if (ep) {
-		reg = readl(regs + S3C_DOEPCTL(ep));
-		reg &= ~S3C_DxEPCTL_MPS_MASK;
+		reg = readl(regs + DOEPCTL(ep));
+		reg &= ~DxEPCTL_MPS_MASK;
 		reg |= mpsval;
-		writel(reg, regs + S3C_DOEPCTL(ep));
+		writel(reg, regs + DOEPCTL(ep));
 	}
 
 	return;
@@ -1719,16 +1794,16 @@
 	int timeout;
 	int val;
 
-	writel(S3C_GRSTCTL_TxFNum(idx) | S3C_GRSTCTL_TxFFlsh,
-		hsotg->regs + S3C_GRSTCTL);
+	writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh,
+		hsotg->regs + GRSTCTL);
 
 	/* wait until the fifo is flushed */
 	timeout = 100;
 
 	while (1) {
-		val = readl(hsotg->regs + S3C_GRSTCTL);
+		val = readl(hsotg->regs + GRSTCTL);
 
-		if ((val & (S3C_GRSTCTL_TxFFlsh)) == 0)
+		if ((val & (GRSTCTL_TxFFlsh)) == 0)
 			break;
 
 		if (--timeout == 0) {
@@ -1778,7 +1853,7 @@
 				  struct s3c_hsotg_ep *hs_ep)
 {
 	struct s3c_hsotg_req *hs_req = hs_ep->req;
-	u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
+	u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index));
 	int size_left, size_done;
 
 	if (!hs_req) {
@@ -1786,7 +1861,15 @@
 		return;
 	}
 
-	/* Calculate the size of the transfer by checking how much is left
+	/* Finish ZLP handling for IN EP0 transactions */
+	if (hsotg->eps[0].sent_zlp) {
+		dev_dbg(hsotg->dev, "zlp packet received\n");
+		s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0);
+		return;
+	}
+
+	/*
+	 * Calculate the size of the transfer by checking how much is left
 	 * in the endpoint size register and then working it out from
 	 * the amount we loaded for the transfer.
 	 *
@@ -1795,7 +1878,7 @@
 	 * aligned).
 	 */
 
-	size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+	size_left = DxEPTSIZ_XferSize_GET(epsize);
 
 	size_done = hs_ep->size_loaded - size_left;
 	size_done += hs_ep->last_load;
@@ -1805,9 +1888,28 @@
 			__func__, hs_req->req.actual, size_done);
 
 	hs_req->req.actual = size_done;
+	dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n",
+		hs_req->req.length, hs_req->req.actual, hs_req->req.zero);
 
-	/* if we did all of the transfer, and there is more data left
-	 * around, then try restarting the rest of the request */
+	/*
+	 * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0
+	 * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B
+	 * ,256B ... ), after last MPS sized packet send IN ZLP packet to
+	 * inform the host that no more data is available.
+	 * The state of req.zero member is checked to be sure that the value to
+	 * send is smaller than wValue expected from host.
+	 * Check req.length to NOT send another ZLP when the current one is
+	 * under completion (the one for which this completion has been called).
+	 */
+	if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero &&
+	    hs_req->req.length == hs_req->req.actual &&
+	    !(hs_req->req.length % hs_ep->ep.maxpacket)) {
+
+		dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n");
+		s3c_hsotg_send_zlp(hsotg, hs_req);
+
+		return;
+	}
 
 	if (!size_left && hs_req->req.actual < hs_req->req.length) {
 		dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
@@ -1823,14 +1925,14 @@
  * @dir_in: Set if this is an IN endpoint
  *
  * Process and clear any interrupt pending for an individual endpoint
-*/
+ */
 static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
 			    int dir_in)
 {
 	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx];
-	u32 epint_reg = dir_in ? S3C_DIEPINT(idx) : S3C_DOEPINT(idx);
-	u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx);
-	u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx);
+	u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);
+	u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
+	u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx);
 	u32 ints;
 
 	ints = readl(hsotg->regs + epint_reg);
@@ -1841,28 +1943,32 @@
 	dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
 		__func__, idx, dir_in ? "in" : "out", ints);
 
-	if (ints & S3C_DxEPINT_XferCompl) {
+	if (ints & DxEPINT_XferCompl) {
 		dev_dbg(hsotg->dev,
 			"%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n",
 			__func__, readl(hsotg->regs + epctl_reg),
 			readl(hsotg->regs + epsiz_reg));
 
-		/* we get OutDone from the FIFO, so we only need to look
-		 * at completing IN requests here */
+		/*
+		 * we get OutDone from the FIFO, so we only need to look
+		 * at completing IN requests here
+		 */
 		if (dir_in) {
 			s3c_hsotg_complete_in(hsotg, hs_ep);
 
 			if (idx == 0 && !hs_ep->req)
 				s3c_hsotg_enqueue_setup(hsotg);
 		} else if (using_dma(hsotg)) {
-			/* We're using DMA, we need to fire an OutDone here
-			 * as we ignore the RXFIFO. */
+			/*
+			 * We're using DMA, we need to fire an OutDone here
+			 * as we ignore the RXFIFO.
+			 */
 
 			s3c_hsotg_handle_outdone(hsotg, idx, false);
 		}
 	}
 
-	if (ints & S3C_DxEPINT_EPDisbld) {
+	if (ints & DxEPINT_EPDisbld) {
 		dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
 
 		if (dir_in) {
@@ -1870,27 +1976,29 @@
 
 			s3c_hsotg_txfifo_flush(hsotg, idx);
 
-			if ((epctl & S3C_DxEPCTL_Stall) &&
-				(epctl & S3C_DxEPCTL_EPType_Bulk)) {
-				int dctl = readl(hsotg->regs + S3C_DCTL);
+			if ((epctl & DxEPCTL_Stall) &&
+				(epctl & DxEPCTL_EPType_Bulk)) {
+				int dctl = readl(hsotg->regs + DCTL);
 
-				dctl |= S3C_DCTL_CGNPInNAK;
-				writel(dctl, hsotg->regs + S3C_DCTL);
+				dctl |= DCTL_CGNPInNAK;
+				writel(dctl, hsotg->regs + DCTL);
 			}
 		}
 	}
 
-	if (ints & S3C_DxEPINT_AHBErr)
+	if (ints & DxEPINT_AHBErr)
 		dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
 
-	if (ints & S3C_DxEPINT_Setup) {  /* Setup or Timeout */
+	if (ints & DxEPINT_Setup) {  /* Setup or Timeout */
 		dev_dbg(hsotg->dev, "%s: Setup/Timeout\n",  __func__);
 
 		if (using_dma(hsotg) && idx == 0) {
-			/* this is the notification we've received a
+			/*
+			 * this is the notification we've received a
 			 * setup packet. In non-DMA mode we'd get this
 			 * from the RXFIFO, instead we need to process
-			 * the setup here. */
+			 * the setup here.
+			 */
 
 			if (dir_in)
 				WARN_ON_ONCE(1);
@@ -1899,26 +2007,25 @@
 		}
 	}
 
-	if (ints & S3C_DxEPINT_Back2BackSetup)
+	if (ints & DxEPINT_Back2BackSetup)
 		dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);
 
 	if (dir_in) {
-		/* not sure if this is important, but we'll clear it anyway
-		 */
-		if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) {
+		/* not sure if this is important, but we'll clear it anyway */
+		if (ints & DIEPMSK_INTknTXFEmpMsk) {
 			dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
 				__func__, idx);
 		}
 
 		/* this probably means something bad is happening */
-		if (ints & S3C_DIEPMSK_INTknEPMisMsk) {
+		if (ints & DIEPMSK_INTknEPMisMsk) {
 			dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
 				 __func__, idx);
 		}
 
 		/* FIFO has space or is empty (see GAHBCFG) */
 		if (hsotg->dedicated_fifos &&
-		    ints & S3C_DIEPMSK_TxFIFOEmpty) {
+		    ints & DIEPMSK_TxFIFOEmpty) {
 			dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
 				__func__, idx);
 			if (!using_dma(hsotg))
@@ -1933,40 +2040,45 @@
  *
  * Handle updating the device settings after the enumeration phase has
  * been completed.
-*/
+ */
 static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
 {
-	u32 dsts = readl(hsotg->regs + S3C_DSTS);
+	u32 dsts = readl(hsotg->regs + DSTS);
 	int ep0_mps = 0, ep_mps;
 
-	/* This should signal the finish of the enumeration phase
+	/*
+	 * This should signal the finish of the enumeration phase
 	 * of the USB handshaking, so we should now know what rate
-	 * we connected at. */
+	 * we connected at.
+	 */
 
 	dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts);
 
-	/* note, since we're limited by the size of transfer on EP0, and
+	/*
+	 * note, since we're limited by the size of transfer on EP0, and
 	 * it seems IN transfers must be a even number of packets we do
-	 * not advertise a 64byte MPS on EP0. */
+	 * not advertise a 64byte MPS on EP0.
+	 */
 
 	/* catch both EnumSpd_FS and EnumSpd_FS48 */
-	switch (dsts & S3C_DSTS_EnumSpd_MASK) {
-	case S3C_DSTS_EnumSpd_FS:
-	case S3C_DSTS_EnumSpd_FS48:
+	switch (dsts & DSTS_EnumSpd_MASK) {
+	case DSTS_EnumSpd_FS:
+	case DSTS_EnumSpd_FS48:
 		hsotg->gadget.speed = USB_SPEED_FULL;
 		ep0_mps = EP0_MPS_LIMIT;
 		ep_mps = 64;
 		break;
 
-	case S3C_DSTS_EnumSpd_HS:
+	case DSTS_EnumSpd_HS:
 		hsotg->gadget.speed = USB_SPEED_HIGH;
 		ep0_mps = EP0_MPS_LIMIT;
 		ep_mps = 512;
 		break;
 
-	case S3C_DSTS_EnumSpd_LS:
+	case DSTS_EnumSpd_LS:
 		hsotg->gadget.speed = USB_SPEED_LOW;
-		/* note, we don't actually support LS in this driver at the
+		/*
+		 * note, we don't actually support LS in this driver at the
 		 * moment, and the documentation seems to imply that it isn't
 		 * supported by the PHYs on some of the devices.
 		 */
@@ -1975,13 +2087,15 @@
 	dev_info(hsotg->dev, "new device is %s\n",
 		 usb_speed_string(hsotg->gadget.speed));
 
-	/* we should now know the maximum packet size for an
-	 * endpoint, so set the endpoints to a default value. */
+	/*
+	 * we should now know the maximum packet size for an
+	 * endpoint, so set the endpoints to a default value.
+	 */
 
 	if (ep0_mps) {
 		int i;
 		s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps);
-		for (i = 1; i < S3C_HSOTG_EPS; i++)
+		for (i = 1; i < hsotg->num_of_eps; i++)
 			s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps);
 	}
 
@@ -1990,8 +2104,8 @@
 	s3c_hsotg_enqueue_setup(hsotg);
 
 	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-		readl(hsotg->regs + S3C_DIEPCTL0),
-		readl(hsotg->regs + S3C_DOEPCTL0));
+		readl(hsotg->regs + DIEPCTL0),
+		readl(hsotg->regs + DOEPCTL0));
 }
 
 /**
@@ -2014,8 +2128,10 @@
 	spin_lock_irqsave(&ep->lock, flags);
 
 	list_for_each_entry_safe(req, treq, &ep->queue, queue) {
-		/* currently, we can't do much about an already
-		 * running request on an in endpoint */
+		/*
+		 * currently, we can't do much about an already
+		 * running request on an in endpoint
+		 */
 
 		if (ep->req == req && ep->dir_in && !force)
 			continue;
@@ -2033,18 +2149,18 @@
 		(_hs)->driver->_entry(&(_hs)->gadget);
 
 /**
- * s3c_hsotg_disconnect_irq - disconnect irq service
+ * s3c_hsotg_disconnect - disconnect service
  * @hsotg: The device state.
  *
- * A disconnect IRQ has been received, meaning that the host has
- * lost contact with the bus. Remove all current transactions
- * and signal the gadget driver that this has happened.
-*/
-static void s3c_hsotg_disconnect_irq(struct s3c_hsotg *hsotg)
+ * The device has been disconnected. Remove all current
+ * transactions and signal the gadget driver that this
+ * has happened.
+ */
+static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg)
 {
 	unsigned ep;
 
-	for (ep = 0; ep < S3C_HSOTG_EPS; ep++)
+	for (ep = 0; ep < hsotg->num_of_eps; ep++)
 		kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
 
 	call_gadget(hsotg, disconnect);
@@ -2062,7 +2178,7 @@
 
 	/* look through for any more data to transmit */
 
-	for (epno = 0; epno < S3C_HSOTG_EPS; epno++) {
+	for (epno = 0; epno < hsotg->num_of_eps; epno++) {
 		ep = &hsotg->eps[epno];
 
 		if (!ep->dir_in)
@@ -2078,12 +2194,187 @@
 	}
 }
 
-static struct s3c_hsotg *our_hsotg;
-
 /* IRQ flags which will trigger a retry around the IRQ loop */
-#define IRQ_RETRY_MASK (S3C_GINTSTS_NPTxFEmp | \
-			S3C_GINTSTS_PTxFEmp |  \
-			S3C_GINTSTS_RxFLvl)
+#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \
+			GINTSTS_PTxFEmp |  \
+			GINTSTS_RxFLvl)
+
+/**
+ * s3c_hsotg_corereset - issue softreset to the core
+ * @hsotg: The device state
+ *
+ * Issue a soft reset to the core, and await the core finishing it.
+ */
+static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
+{
+	int timeout;
+	u32 grstctl;
+
+	dev_dbg(hsotg->dev, "resetting core\n");
+
+	/* issue soft reset */
+	writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL);
+
+	timeout = 1000;
+	do {
+		grstctl = readl(hsotg->regs + GRSTCTL);
+	} while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0);
+
+	if (grstctl & GRSTCTL_CSftRst) {
+		dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
+		return -EINVAL;
+	}
+
+	timeout = 1000;
+
+	while (1) {
+		u32 grstctl = readl(hsotg->regs + GRSTCTL);
+
+		if (timeout-- < 0) {
+			dev_info(hsotg->dev,
+				 "%s: reset failed, GRSTCTL=%08x\n",
+				 __func__, grstctl);
+			return -ETIMEDOUT;
+		}
+
+		if (!(grstctl & GRSTCTL_AHBIdle))
+			continue;
+
+		break;		/* reset done */
+	}
+
+	dev_dbg(hsotg->dev, "reset successful\n");
+	return 0;
+}
+
+/**
+ * s3c_hsotg_core_init - issue softreset to the core
+ * @hsotg: The device state
+ *
+ * Issue a soft reset to the core, and await the core finishing it.
+ */
+static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)
+{
+	s3c_hsotg_corereset(hsotg);
+
+	/*
+	 * we must now enable ep0 ready for host detection and then
+	 * set configuration.
+	 */
+
+	/* set the PLL on, remove the HNP/SRP and set the PHY */
+	writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) |
+	       (0x5 << 10), hsotg->regs + GUSBCFG);
+
+	s3c_hsotg_init_fifo(hsotg);
+
+	__orr32(hsotg->regs + DCTL, DCTL_SftDiscon);
+
+	writel(1 << 18 | DCFG_DevSpd_HS,  hsotg->regs + DCFG);
+
+	/* Clear any pending OTG interrupts */
+	writel(0xffffffff, hsotg->regs + GOTGINT);
+
+	/* Clear any pending interrupts */
+	writel(0xffffffff, hsotg->regs + GINTSTS);
+
+	writel(GINTSTS_ErlySusp | GINTSTS_SessReqInt |
+	       GINTSTS_GOUTNakEff | GINTSTS_GINNakEff |
+	       GINTSTS_ConIDStsChng | GINTSTS_USBRst |
+	       GINTSTS_EnumDone | GINTSTS_OTGInt |
+	       GINTSTS_USBSusp | GINTSTS_WkUpInt,
+	       hsotg->regs + GINTMSK);
+
+	if (using_dma(hsotg))
+		writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn |
+		       GAHBCFG_HBstLen_Incr4,
+		       hsotg->regs + GAHBCFG);
+	else
+		writel(GAHBCFG_GlblIntrEn, hsotg->regs + GAHBCFG);
+
+	/*
+	 * Enabling INTknTXFEmpMsk here seems to be a big mistake, we end
+	 * up being flooded with interrupts if the host is polling the
+	 * endpoint to try and read data.
+	 */
+
+	writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty : 0) |
+	       DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk |
+	       DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk |
+	       DIEPMSK_INTknEPMisMsk,
+	       hsotg->regs + DIEPMSK);
+
+	/*
+	 * don't need XferCompl, we get that from RXFIFO in slave mode. In
+	 * DMA mode we may need this.
+	 */
+	writel((using_dma(hsotg) ? (DIEPMSK_XferComplMsk |
+				    DIEPMSK_TimeOUTMsk) : 0) |
+	       DOEPMSK_EPDisbldMsk | DOEPMSK_AHBErrMsk |
+	       DOEPMSK_SetupMsk,
+	       hsotg->regs + DOEPMSK);
+
+	writel(0, hsotg->regs + DAINTMSK);
+
+	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+		readl(hsotg->regs + DIEPCTL0),
+		readl(hsotg->regs + DOEPCTL0));
+
+	/* enable in and out endpoint interrupts */
+	s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt);
+
+	/*
+	 * Enable the RXFIFO when in slave mode, as this is how we collect
+	 * the data. In DMA mode, we get events from the FIFO but also
+	 * things we cannot process, so do not use it.
+	 */
+	if (!using_dma(hsotg))
+		s3c_hsotg_en_gsint(hsotg, GINTSTS_RxFLvl);
+
+	/* Enable interrupts for EP0 in and out */
+	s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
+	s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
+
+	__orr32(hsotg->regs + DCTL, DCTL_PWROnPrgDone);
+	udelay(10);  /* see openiboot */
+	__bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone);
+
+	dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL));
+
+	/*
+	 * DxEPCTL_USBActEp says RO in manual, but seems to be set by
+	 * writing to the EPCTL register..
+	 */
+
+	/* set to read 1 8byte packet */
+	writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) |
+	       DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0);
+
+	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+	       DxEPCTL_CNAK | DxEPCTL_EPEna |
+	       DxEPCTL_USBActEp,
+	       hsotg->regs + DOEPCTL0);
+
+	/* enable, but don't activate EP0in */
+	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+	       DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0);
+
+	s3c_hsotg_enqueue_setup(hsotg);
+
+	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+		readl(hsotg->regs + DIEPCTL0),
+		readl(hsotg->regs + DOEPCTL0));
+
+	/* clear global NAKs */
+	writel(DCTL_CGOUTNak | DCTL_CGNPInNAK,
+	       hsotg->regs + DCTL);
+
+	/* must be at-least 3ms to allow bus to see disconnect */
+	mdelay(3);
+
+	/* remove the soft-disconnect and let's go */
+	__bic32(hsotg->regs + DCTL, DCTL_SftDiscon);
+}
 
 /**
  * s3c_hsotg_irq - handle device interrupt
@@ -2098,52 +2389,45 @@
 	u32 gintmsk;
 
 irq_retry:
-	gintsts = readl(hsotg->regs + S3C_GINTSTS);
-	gintmsk = readl(hsotg->regs + S3C_GINTMSK);
+	gintsts = readl(hsotg->regs + GINTSTS);
+	gintmsk = readl(hsotg->regs + GINTMSK);
 
 	dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n",
 		__func__, gintsts, gintsts & gintmsk, gintmsk, retry_count);
 
 	gintsts &= gintmsk;
 
-	if (gintsts & S3C_GINTSTS_OTGInt) {
-		u32 otgint = readl(hsotg->regs + S3C_GOTGINT);
+	if (gintsts & GINTSTS_OTGInt) {
+		u32 otgint = readl(hsotg->regs + GOTGINT);
 
 		dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
 
-		writel(otgint, hsotg->regs + S3C_GOTGINT);
+		writel(otgint, hsotg->regs + GOTGINT);
 	}
 
-	if (gintsts & S3C_GINTSTS_DisconnInt) {
-		dev_dbg(hsotg->dev, "%s: DisconnInt\n", __func__);
-		writel(S3C_GINTSTS_DisconnInt, hsotg->regs + S3C_GINTSTS);
-
-		s3c_hsotg_disconnect_irq(hsotg);
-	}
-
-	if (gintsts & S3C_GINTSTS_SessReqInt) {
+	if (gintsts & GINTSTS_SessReqInt) {
 		dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__);
-		writel(S3C_GINTSTS_SessReqInt, hsotg->regs + S3C_GINTSTS);
+		writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS);
 	}
 
-	if (gintsts & S3C_GINTSTS_EnumDone) {
-		writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS);
+	if (gintsts & GINTSTS_EnumDone) {
+		writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS);
 
 		s3c_hsotg_irq_enumdone(hsotg);
 	}
 
-	if (gintsts & S3C_GINTSTS_ConIDStsChng) {
+	if (gintsts & GINTSTS_ConIDStsChng) {
 		dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n",
-			readl(hsotg->regs + S3C_DSTS),
-			readl(hsotg->regs + S3C_GOTGCTL));
+			readl(hsotg->regs + DSTS),
+			readl(hsotg->regs + GOTGCTL));
 
-		writel(S3C_GINTSTS_ConIDStsChng, hsotg->regs + S3C_GINTSTS);
+		writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS);
 	}
 
-	if (gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt)) {
-		u32 daint = readl(hsotg->regs + S3C_DAINT);
-		u32 daint_out = daint >> S3C_DAINT_OutEP_SHIFT;
-		u32 daint_in = daint & ~(daint_out << S3C_DAINT_OutEP_SHIFT);
+	if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) {
+		u32 daint = readl(hsotg->regs + DAINT);
+		u32 daint_out = daint >> DAINT_OutEP_SHIFT;
+		u32 daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT);
 		int ep;
 
 		dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint);
@@ -2159,102 +2443,116 @@
 		}
 	}
 
-	if (gintsts & S3C_GINTSTS_USBRst) {
+	if (gintsts & GINTSTS_USBRst) {
+
+		u32 usb_status = readl(hsotg->regs + GOTGCTL);
+
 		dev_info(hsotg->dev, "%s: USBRst\n", __func__);
 		dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
-			readl(hsotg->regs + S3C_GNPTXSTS));
+			readl(hsotg->regs + GNPTXSTS));
 
-		writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
+		writel(GINTSTS_USBRst, hsotg->regs + GINTSTS);
 
-		kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
+		if (usb_status & GOTGCTL_BSESVLD) {
+			if (time_after(jiffies, hsotg->last_rst +
+				       msecs_to_jiffies(200))) {
 
-		/* it seems after a reset we can end up with a situation
-		 * where the TXFIFO still has data in it... the docs
-		 * suggest resetting all the fifos, so use the init_fifo
-		 * code to relayout and flush the fifos.
-		 */
+				kill_all_requests(hsotg, &hsotg->eps[0],
+							  -ECONNRESET, true);
 
-		s3c_hsotg_init_fifo(hsotg);
-
-		s3c_hsotg_enqueue_setup(hsotg);
+				s3c_hsotg_core_init(hsotg);
+				hsotg->last_rst = jiffies;
+			}
+		}
 	}
 
 	/* check both FIFOs */
 
-	if (gintsts & S3C_GINTSTS_NPTxFEmp) {
+	if (gintsts & GINTSTS_NPTxFEmp) {
 		dev_dbg(hsotg->dev, "NPTxFEmp\n");
 
-		/* Disable the interrupt to stop it happening again
+		/*
+		 * Disable the interrupt to stop it happening again
 		 * unless one of these endpoint routines decides that
-		 * it needs re-enabling */
+		 * it needs re-enabling
+		 */
 
-		s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
+		s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp);
 		s3c_hsotg_irq_fifoempty(hsotg, false);
 	}
 
-	if (gintsts & S3C_GINTSTS_PTxFEmp) {
+	if (gintsts & GINTSTS_PTxFEmp) {
 		dev_dbg(hsotg->dev, "PTxFEmp\n");
 
-		/* See note in S3C_GINTSTS_NPTxFEmp */
+		/* See note in GINTSTS_NPTxFEmp */
 
-		s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+		s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp);
 		s3c_hsotg_irq_fifoempty(hsotg, true);
 	}
 
-	if (gintsts & S3C_GINTSTS_RxFLvl) {
-		/* note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,
+	if (gintsts & GINTSTS_RxFLvl) {
+		/*
+		 * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,
 		 * we need to retry s3c_hsotg_handle_rx if this is still
-		 * set. */
+		 * set.
+		 */
 
 		s3c_hsotg_handle_rx(hsotg);
 	}
 
-	if (gintsts & S3C_GINTSTS_ModeMis) {
+	if (gintsts & GINTSTS_ModeMis) {
 		dev_warn(hsotg->dev, "warning, mode mismatch triggered\n");
-		writel(S3C_GINTSTS_ModeMis, hsotg->regs + S3C_GINTSTS);
+		writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS);
 	}
 
-	if (gintsts & S3C_GINTSTS_USBSusp) {
-		dev_info(hsotg->dev, "S3C_GINTSTS_USBSusp\n");
-		writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS);
+	if (gintsts & GINTSTS_USBSusp) {
+		dev_info(hsotg->dev, "GINTSTS_USBSusp\n");
+		writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS);
 
 		call_gadget(hsotg, suspend);
+		s3c_hsotg_disconnect(hsotg);
 	}
 
-	if (gintsts & S3C_GINTSTS_WkUpInt) {
-		dev_info(hsotg->dev, "S3C_GINTSTS_WkUpIn\n");
-		writel(S3C_GINTSTS_WkUpInt, hsotg->regs + S3C_GINTSTS);
+	if (gintsts & GINTSTS_WkUpInt) {
+		dev_info(hsotg->dev, "GINTSTS_WkUpIn\n");
+		writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS);
 
 		call_gadget(hsotg, resume);
 	}
 
-	if (gintsts & S3C_GINTSTS_ErlySusp) {
-		dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n");
-		writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS);
+	if (gintsts & GINTSTS_ErlySusp) {
+		dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n");
+		writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS);
+
+		s3c_hsotg_disconnect(hsotg);
 	}
 
-	/* these next two seem to crop-up occasionally causing the core
+	/*
+	 * these next two seem to crop-up occasionally causing the core
 	 * to shutdown the USB transfer, so try clearing them and logging
-	 * the occurrence. */
+	 * the occurrence.
+	 */
 
-	if (gintsts & S3C_GINTSTS_GOUTNakEff) {
+	if (gintsts & GINTSTS_GOUTNakEff) {
 		dev_info(hsotg->dev, "GOUTNakEff triggered\n");
 
-		writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL);
+		writel(DCTL_CGOUTNak, hsotg->regs + DCTL);
 
 		s3c_hsotg_dump(hsotg);
 	}
 
-	if (gintsts & S3C_GINTSTS_GINNakEff) {
+	if (gintsts & GINTSTS_GINNakEff) {
 		dev_info(hsotg->dev, "GINNakEff triggered\n");
 
-		writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL);
+		writel(DCTL_CGNPInNAK, hsotg->regs + DCTL);
 
 		s3c_hsotg_dump(hsotg);
 	}
 
-	/* if we've had fifo events, we should try and go around the
-	 * loop again to see if there's any point in returning yet. */
+	/*
+	 * if we've had fifo events, we should try and go around the
+	 * loop again to see if there's any point in returning yet.
+	 */
 
 	if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
 			goto irq_retry;
@@ -2268,7 +2566,7 @@
  * @desc: The USB endpoint descriptor to configure with.
  *
  * This is called from the USB gadget code's usb_ep_enable().
-*/
+ */
 static int s3c_hsotg_ep_enable(struct usb_ep *ep,
 			       const struct usb_endpoint_descriptor *desc)
 {
@@ -2300,7 +2598,7 @@
 
 	/* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */
 
-	epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
+	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
 	epctrl = readl(hsotg->regs + epctrl_reg);
 
 	dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
@@ -2308,20 +2606,23 @@
 
 	spin_lock_irqsave(&hs_ep->lock, flags);
 
-	epctrl &= ~(S3C_DxEPCTL_EPType_MASK | S3C_DxEPCTL_MPS_MASK);
-	epctrl |= S3C_DxEPCTL_MPS(mps);
+	epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK);
+	epctrl |= DxEPCTL_MPS(mps);
 
-	/* mark the endpoint as active, otherwise the core may ignore
-	 * transactions entirely for this endpoint */
-	epctrl |= S3C_DxEPCTL_USBActEp;
+	/*
+	 * mark the endpoint as active, otherwise the core may ignore
+	 * transactions entirely for this endpoint
+	 */
+	epctrl |= DxEPCTL_USBActEp;
 
-	/* set the NAK status on the endpoint, otherwise we might try and
+	/*
+	 * set the NAK status on the endpoint, otherwise we might try and
 	 * do something with data that we've yet got a request to process
 	 * since the RXFIFO will take data for an endpoint even if the
 	 * size register hasn't been set.
 	 */
 
-	epctrl |= S3C_DxEPCTL_SNAK;
+	epctrl |= DxEPCTL_SNAK;
 
 	/* update the endpoint state */
 	hs_ep->ep.maxpacket = mps;
@@ -2336,37 +2637,40 @@
 		goto out;
 
 	case USB_ENDPOINT_XFER_BULK:
-		epctrl |= S3C_DxEPCTL_EPType_Bulk;
+		epctrl |= DxEPCTL_EPType_Bulk;
 		break;
 
 	case USB_ENDPOINT_XFER_INT:
 		if (dir_in) {
-			/* Allocate our TxFNum by simply using the index
+			/*
+			 * Allocate our TxFNum by simply using the index
 			 * of the endpoint for the moment. We could do
 			 * something better if the host indicates how
-			 * many FIFOs we are expecting to use. */
+			 * many FIFOs we are expecting to use.
+			 */
 
 			hs_ep->periodic = 1;
-			epctrl |= S3C_DxEPCTL_TxFNum(index);
+			epctrl |= DxEPCTL_TxFNum(index);
 		}
 
-		epctrl |= S3C_DxEPCTL_EPType_Intterupt;
+		epctrl |= DxEPCTL_EPType_Intterupt;
 		break;
 
 	case USB_ENDPOINT_XFER_CONTROL:
-		epctrl |= S3C_DxEPCTL_EPType_Control;
+		epctrl |= DxEPCTL_EPType_Control;
 		break;
 	}
 
-	/* if the hardware has dedicated fifos, we must give each IN EP
+	/*
+	 * if the hardware has dedicated fifos, we must give each IN EP
 	 * a unique tx-fifo even if it is non-periodic.
 	 */
 	if (dir_in && hsotg->dedicated_fifos)
-		epctrl |= S3C_DxEPCTL_TxFNum(index);
+		epctrl |= DxEPCTL_TxFNum(index);
 
 	/* for non control endpoints, set PID to D0 */
 	if (index)
-		epctrl |= S3C_DxEPCTL_SetD0PID;
+		epctrl |= DxEPCTL_SetD0PID;
 
 	dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
 		__func__, epctrl);
@@ -2383,6 +2687,10 @@
 	return ret;
 }
 
+/**
+ * s3c_hsotg_ep_disable - disable given endpoint
+ * @ep: The endpoint to disable.
+ */
 static int s3c_hsotg_ep_disable(struct usb_ep *ep)
 {
 	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
@@ -2400,7 +2708,7 @@
 		return -EINVAL;
 	}
 
-	epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
+	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
 
 	/* terminate all requests with shutdown */
 	kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
@@ -2408,9 +2716,9 @@
 	spin_lock_irqsave(&hs_ep->lock, flags);
 
 	ctrl = readl(hsotg->regs + epctrl_reg);
-	ctrl &= ~S3C_DxEPCTL_EPEna;
-	ctrl &= ~S3C_DxEPCTL_USBActEp;
-	ctrl |= S3C_DxEPCTL_SNAK;
+	ctrl &= ~DxEPCTL_EPEna;
+	ctrl &= ~DxEPCTL_USBActEp;
+	ctrl |= DxEPCTL_SNAK;
 
 	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
 	writel(ctrl, hsotg->regs + epctrl_reg);
@@ -2426,7 +2734,7 @@
  * on_list - check request is on the given endpoint
  * @ep: The endpoint to check.
  * @test: The request to test if it is on the endpoint.
-*/
+ */
 static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test)
 {
 	struct s3c_hsotg_req *req, *treq;
@@ -2439,6 +2747,11 @@
 	return false;
 }
 
+/**
+ * s3c_hsotg_ep_dequeue - dequeue given endpoint
+ * @ep: The endpoint to dequeue.
+ * @req: The request to be removed from a queue.
+ */
 static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
 {
 	struct s3c_hsotg_req *hs_req = our_req(req);
@@ -2461,6 +2774,11 @@
 	return 0;
 }
 
+/**
+ * s3c_hsotg_ep_sethalt - set halt on a given endpoint
+ * @ep: The endpoint to set halt.
+ * @value: Set or unset the halt.
+ */
 static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
 {
 	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
@@ -2477,34 +2795,34 @@
 
 	/* write both IN and OUT control registers */
 
-	epreg = S3C_DIEPCTL(index);
+	epreg = DIEPCTL(index);
 	epctl = readl(hs->regs + epreg);
 
 	if (value) {
-		epctl |= S3C_DxEPCTL_Stall + S3C_DxEPCTL_SNAK;
-		if (epctl & S3C_DxEPCTL_EPEna)
-			epctl |= S3C_DxEPCTL_EPDis;
+		epctl |= DxEPCTL_Stall + DxEPCTL_SNAK;
+		if (epctl & DxEPCTL_EPEna)
+			epctl |= DxEPCTL_EPDis;
 	} else {
-		epctl &= ~S3C_DxEPCTL_Stall;
-		xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
-		if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
-			xfertype == S3C_DxEPCTL_EPType_Intterupt)
-				epctl |= S3C_DxEPCTL_SetD0PID;
+		epctl &= ~DxEPCTL_Stall;
+		xfertype = epctl & DxEPCTL_EPType_MASK;
+		if (xfertype == DxEPCTL_EPType_Bulk ||
+			xfertype == DxEPCTL_EPType_Intterupt)
+				epctl |= DxEPCTL_SetD0PID;
 	}
 
 	writel(epctl, hs->regs + epreg);
 
-	epreg = S3C_DOEPCTL(index);
+	epreg = DOEPCTL(index);
 	epctl = readl(hs->regs + epreg);
 
 	if (value)
-		epctl |= S3C_DxEPCTL_Stall;
+		epctl |= DxEPCTL_Stall;
 	else {
-		epctl &= ~S3C_DxEPCTL_Stall;
-		xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
-		if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
-			xfertype == S3C_DxEPCTL_EPType_Intterupt)
-				epctl |= S3C_DxEPCTL_SetD0PID;
+		epctl &= ~DxEPCTL_Stall;
+		xfertype = epctl & DxEPCTL_EPType_MASK;
+		if (xfertype == DxEPCTL_EPType_Bulk ||
+			xfertype == DxEPCTL_EPType_Intterupt)
+				epctl |= DxEPCTL_SetD0PID;
 	}
 
 	writel(epctl, hs->regs + epreg);
@@ -2526,57 +2844,91 @@
 };
 
 /**
- * s3c_hsotg_corereset - issue softreset to the core
- * @hsotg: The device state
+ * s3c_hsotg_phy_enable - enable platform phy dev
+ * @hsotg: The driver state
  *
- * Issue a soft reset to the core, and await the core finishing it.
-*/
-static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
+ * A wrapper for platform code responsible for controlling
+ * low-level USB code
+ */
+static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
 {
-	int timeout;
-	u32 grstctl;
+	struct platform_device *pdev = to_platform_device(hsotg->dev);
 
-	dev_dbg(hsotg->dev, "resetting core\n");
-
-	/* issue soft reset */
-	writel(S3C_GRSTCTL_CSftRst, hsotg->regs + S3C_GRSTCTL);
-
-	timeout = 1000;
-	do {
-		grstctl = readl(hsotg->regs + S3C_GRSTCTL);
-	} while ((grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0);
-
-	if (grstctl & S3C_GRSTCTL_CSftRst) {
-		dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
-		return -EINVAL;
-	}
-
-	timeout = 1000;
-
-	while (1) {
-		u32 grstctl = readl(hsotg->regs + S3C_GRSTCTL);
-
-		if (timeout-- < 0) {
-			dev_info(hsotg->dev,
-				 "%s: reset failed, GRSTCTL=%08x\n",
-				 __func__, grstctl);
-			return -ETIMEDOUT;
-		}
-
-		if (!(grstctl & S3C_GRSTCTL_AHBIdle))
-			continue;
-
-		break;		/* reset done */
-	}
-
-	dev_dbg(hsotg->dev, "reset successful\n");
-	return 0;
+	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
+	if (hsotg->plat->phy_init)
+		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
 }
 
-static int s3c_hsotg_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+/**
+ * s3c_hsotg_phy_disable - disable platform phy dev
+ * @hsotg: The driver state
+ *
+ * A wrapper for platform code responsible for controlling
+ * low-level USB code
+ */
+static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
 {
-	struct s3c_hsotg *hsotg = our_hsotg;
+	struct platform_device *pdev = to_platform_device(hsotg->dev);
+
+	if (hsotg->plat->phy_exit)
+		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
+}
+
+/**
+ * s3c_hsotg_init - initalize the usb core
+ * @hsotg: The driver state
+ */
+static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
+{
+	/* unmask subset of endpoint interrupts */
+
+	writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk |
+	       DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk,
+	       hsotg->regs + DIEPMSK);
+
+	writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk |
+	       DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk,
+	       hsotg->regs + DOEPMSK);
+
+	writel(0, hsotg->regs + DAINTMSK);
+
+	/* Be in disconnected state until gadget is registered */
+	__orr32(hsotg->regs + DCTL, DCTL_SftDiscon);
+
+	if (0) {
+		/* post global nak until we're ready */
+		writel(DCTL_SGNPInNAK | DCTL_SGOUTNak,
+		       hsotg->regs + DCTL);
+	}
+
+	/* setup fifos */
+
+	dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
+		readl(hsotg->regs + GRXFSIZ),
+		readl(hsotg->regs + GNPTXFSIZ));
+
+	s3c_hsotg_init_fifo(hsotg);
+
+	/* set the PLL on, remove the HNP/SRP and set the PHY */
+	writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | (0x5 << 10),
+	       hsotg->regs + GUSBCFG);
+
+	writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0,
+	       hsotg->regs + GAHBCFG);
+}
+
+/**
+ * s3c_hsotg_udc_start - prepare the udc for work
+ * @gadget: The usb gadget state
+ * @driver: The usb gadget driver
+ *
+ * Perform initialization to prepare udc device and driver
+ * to work.
+ */
+static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
+			   struct usb_gadget_driver *driver)
+{
+	struct s3c_hsotg *hsotg = to_hsotg(gadget);
 	int ret;
 
 	if (!hsotg) {
@@ -2592,7 +2944,7 @@
 	if (driver->max_speed < USB_SPEED_FULL)
 		dev_err(hsotg->dev, "%s: bad speed\n", __func__);
 
-	if (!bind || !driver->setup) {
+	if (!driver->setup) {
 		dev_err(hsotg->dev, "%s: missing entry points\n", __func__);
 		return -EINVAL;
 	}
@@ -2605,135 +2957,17 @@
 	hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
 	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 
-	ret = device_add(&hsotg->gadget.dev);
+	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
+				    hsotg->supplies);
 	if (ret) {
-		dev_err(hsotg->dev, "failed to register gadget device\n");
+		dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret);
 		goto err;
 	}
 
-	ret = bind(&hsotg->gadget);
-	if (ret) {
-		dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name);
+	s3c_hsotg_phy_enable(hsotg);
 
-		hsotg->gadget.dev.driver = NULL;
-		hsotg->driver = NULL;
-		goto err;
-	}
-
-	/* we must now enable ep0 ready for host detection and then
-	 * set configuration. */
-
-	s3c_hsotg_corereset(hsotg);
-
-	/* set the PLL on, remove the HNP/SRP and set the PHY */
-	writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) |
-	       (0x5 << 10), hsotg->regs + S3C_GUSBCFG);
-
-	/* looks like soft-reset changes state of FIFOs */
-	s3c_hsotg_init_fifo(hsotg);
-
-	__orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
-
-	writel(1 << 18 | S3C_DCFG_DevSpd_HS,  hsotg->regs + S3C_DCFG);
-
-	/* Clear any pending OTG interrupts */
-	writel(0xffffffff, hsotg->regs + S3C_GOTGINT);
-
-	/* Clear any pending interrupts */
-	writel(0xffffffff, hsotg->regs + S3C_GINTSTS);
-
-	writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt |
-	       S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst |
-	       S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt |
-	       S3C_GINTSTS_USBSusp | S3C_GINTSTS_WkUpInt |
-	       S3C_GINTSTS_GOUTNakEff | S3C_GINTSTS_GINNakEff |
-	       S3C_GINTSTS_ErlySusp,
-	       hsotg->regs + S3C_GINTMSK);
-
-	if (using_dma(hsotg))
-		writel(S3C_GAHBCFG_GlblIntrEn | S3C_GAHBCFG_DMAEn |
-		       S3C_GAHBCFG_HBstLen_Incr4,
-		       hsotg->regs + S3C_GAHBCFG);
-	else
-		writel(S3C_GAHBCFG_GlblIntrEn, hsotg->regs + S3C_GAHBCFG);
-
-	/* Enabling INTknTXFEmpMsk here seems to be a big mistake, we end
-	 * up being flooded with interrupts if the host is polling the
-	 * endpoint to try and read data. */
-
-	writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
-	       S3C_DIEPMSK_INTknEPMisMsk |
-	       S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk |
-	       ((hsotg->dedicated_fifos) ? S3C_DIEPMSK_TxFIFOEmpty : 0),
-	       hsotg->regs + S3C_DIEPMSK);
-
-	/* don't need XferCompl, we get that from RXFIFO in slave mode. In
-	 * DMA mode we may need this. */
-	writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
-	       S3C_DOEPMSK_EPDisbldMsk |
-	       (using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk |
-				   S3C_DIEPMSK_TimeOUTMsk) : 0),
-	       hsotg->regs + S3C_DOEPMSK);
-
-	writel(0, hsotg->regs + S3C_DAINTMSK);
-
-	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-		readl(hsotg->regs + S3C_DIEPCTL0),
-		readl(hsotg->regs + S3C_DOEPCTL0));
-
-	/* enable in and out endpoint interrupts */
-	s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt);
-
-	/* Enable the RXFIFO when in slave mode, as this is how we collect
-	 * the data. In DMA mode, we get events from the FIFO but also
-	 * things we cannot process, so do not use it. */
-	if (!using_dma(hsotg))
-		s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_RxFLvl);
-
-	/* Enable interrupts for EP0 in and out */
-	s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
-	s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
-
-	__orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone);
-	udelay(10);  /* see openiboot */
-	__bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone);
-
-	dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL));
-
-	/* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by
-	   writing to the EPCTL register.. */
-
-	/* set to read 1 8byte packet */
-	writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) |
-	       S3C_DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0);
-
-	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
-	       S3C_DxEPCTL_CNAK | S3C_DxEPCTL_EPEna |
-	       S3C_DxEPCTL_USBActEp,
-	       hsotg->regs + S3C_DOEPCTL0);
-
-	/* enable, but don't activate EP0in */
-	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
-	       S3C_DxEPCTL_USBActEp, hsotg->regs + S3C_DIEPCTL0);
-
-	s3c_hsotg_enqueue_setup(hsotg);
-
-	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-		readl(hsotg->regs + S3C_DIEPCTL0),
-		readl(hsotg->regs + S3C_DOEPCTL0));
-
-	/* clear global NAKs */
-	writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK,
-	       hsotg->regs + S3C_DCTL);
-
-	/* must be at-least 3ms to allow bus to see disconnect */
-	msleep(3);
-
-	/* remove the soft-disconnect and let's go */
-	__bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
-
-	/* report to the user, and return */
-
+	s3c_hsotg_core_init(hsotg);
+	hsotg->last_rst = jiffies;
 	dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
 	return 0;
 
@@ -2743,9 +2977,17 @@
 	return ret;
 }
 
-static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
+/**
+ * s3c_hsotg_udc_stop - stop the udc
+ * @gadget: The usb gadget state
+ * @driver: The usb gadget driver
+ *
+ * Stop udc hw block and stay tunned for future transmissions
+ */
+static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
+			  struct usb_gadget_driver *driver)
 {
-	struct s3c_hsotg *hsotg = our_hsotg;
+	struct s3c_hsotg *hsotg = to_hsotg(gadget);
 	int ep;
 
 	if (!hsotg)
@@ -2755,16 +2997,15 @@
 		return -EINVAL;
 
 	/* all endpoints should be shutdown */
-	for (ep = 0; ep < S3C_HSOTG_EPS; ep++)
+	for (ep = 0; ep < hsotg->num_of_eps; ep++)
 		s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
 
-	call_gadget(hsotg, disconnect);
+	s3c_hsotg_phy_disable(hsotg);
+	regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 
-	driver->unbind(&hsotg->gadget);
 	hsotg->driver = NULL;
 	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
-
-	device_del(&hsotg->gadget.dev);
+	hsotg->gadget.dev.driver = NULL;
 
 	dev_info(hsotg->dev, "unregistered gadget driver '%s'\n",
 		 driver->driver.name);
@@ -2772,6 +3013,12 @@
 	return 0;
 }
 
+/**
+ * s3c_hsotg_gadget_getframe - read the frame number
+ * @gadget: The usb gadget state
+ *
+ * Read the {micro} frame number
+ */
 static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
 {
 	return s3c_hsotg_read_frameno(to_hsotg(gadget));
@@ -2779,8 +3026,8 @@
 
 static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
 	.get_frame	= s3c_hsotg_gadget_getframe,
-	.start		= s3c_hsotg_start,
-	.stop		= s3c_hsotg_stop,
+	.udc_start		= s3c_hsotg_udc_start,
+	.udc_stop		= s3c_hsotg_udc_stop,
 };
 
 /**
@@ -2827,112 +3074,43 @@
 	hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT;
 	hs_ep->ep.ops = &s3c_hsotg_ep_ops;
 
-	/* Read the FIFO size for the Periodic TX FIFO, even if we're
+	/*
+	 * Read the FIFO size for the Periodic TX FIFO, even if we're
 	 * an OUT endpoint, we may as well do this if in future the
 	 * code is changed to make each endpoint's direction changeable.
 	 */
 
-	ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum));
-	hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4;
+	ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum));
+	hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4;
 
-	/* if we're using dma, we need to set the next-endpoint pointer
+	/*
+	 * if we're using dma, we need to set the next-endpoint pointer
 	 * to be something valid.
 	 */
 
 	if (using_dma(hsotg)) {
-		u32 next = S3C_DxEPCTL_NextEp((epnum + 1) % 15);
-		writel(next, hsotg->regs + S3C_DIEPCTL(epnum));
-		writel(next, hsotg->regs + S3C_DOEPCTL(epnum));
+		u32 next = DxEPCTL_NextEp((epnum + 1) % 15);
+		writel(next, hsotg->regs + DIEPCTL(epnum));
+		writel(next, hsotg->regs + DOEPCTL(epnum));
 	}
 }
 
 /**
- * s3c_hsotg_otgreset - reset the OtG phy block
- * @hsotg: The host state.
+ * s3c_hsotg_hw_cfg - read HW configuration registers
+ * @param: The device state
  *
- * Power up the phy, set the basic configuration and start the PHY.
+ * Read the USB core HW configuration registers
  */
-static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg)
 {
-	struct clk *xusbxti;
-	u32 pwr, osc;
-
-	pwr = readl(S3C_PHYPWR);
-	pwr &= ~0x19;
-	writel(pwr, S3C_PHYPWR);
-	mdelay(1);
-
-	osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0;
-
-	xusbxti = clk_get(hsotg->dev, "xusbxti");
-	if (xusbxti && !IS_ERR(xusbxti)) {
-		switch (clk_get_rate(xusbxti)) {
-		case 12*MHZ:
-			osc |= S3C_PHYCLK_CLKSEL_12M;
-			break;
-		case 24*MHZ:
-			osc |= S3C_PHYCLK_CLKSEL_24M;
-			break;
-		default:
-		case 48*MHZ:
-			/* default reference clock */
-			break;
-		}
-		clk_put(xusbxti);
-	}
-
-	writel(osc | 0x10, S3C_PHYCLK);
-
-	/* issue a full set of resets to the otg and core */
-
-	writel(S3C_RSTCON_PHY, S3C_RSTCON);
-	udelay(20);	/* at-least 10uS */
-	writel(0, S3C_RSTCON);
-}
-
-
-static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
-{
-	u32 cfg4;
-
-	/* unmask subset of endpoint interrupts */
-
-	writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
-	       S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk,
-	       hsotg->regs + S3C_DIEPMSK);
-
-	writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
-	       S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk,
-	       hsotg->regs + S3C_DOEPMSK);
-
-	writel(0, hsotg->regs + S3C_DAINTMSK);
-
-	/* Be in disconnected state until gadget is registered */
-	__orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
-
-	if (0) {
-		/* post global nak until we're ready */
-		writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak,
-		       hsotg->regs + S3C_DCTL);
-	}
-
-	/* setup fifos */
-
-	dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
-		readl(hsotg->regs + S3C_GRXFSIZ),
-		readl(hsotg->regs + S3C_GNPTXFSIZ));
-
-	s3c_hsotg_init_fifo(hsotg);
-
-	/* set the PLL on, remove the HNP/SRP and set the PHY */
-	writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10),
-	       hsotg->regs + S3C_GUSBCFG);
-
-	writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0,
-	       hsotg->regs + S3C_GAHBCFG);
-
+	u32 cfg2, cfg4;
 	/* check hardware configuration */
 
+	cfg2 = readl(hsotg->regs + 0x48);
+	hsotg->num_of_eps = (cfg2 >> 10) & 0xF;
+
+	dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps);
+
 	cfg4 = readl(hsotg->regs + 0x50);
 	hsotg->dedicated_fifos = (cfg4 >> 25) & 1;
 
@@ -2940,6 +3118,10 @@
 		 hsotg->dedicated_fifos ? "dedicated" : "shared");
 }
 
+/**
+ * s3c_hsotg_dump - dump state of the udc
+ * @param: The device state
+ */
 static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
 {
 #ifdef DEBUG
@@ -2949,46 +3131,45 @@
 	int idx;
 
 	dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n",
-		 readl(regs + S3C_DCFG), readl(regs + S3C_DCTL),
-		 readl(regs + S3C_DIEPMSK));
+		 readl(regs + DCFG), readl(regs + DCTL),
+		 readl(regs + DIEPMSK));
 
 	dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n",
-		 readl(regs + S3C_GAHBCFG), readl(regs + 0x44));
+		 readl(regs + GAHBCFG), readl(regs + 0x44));
 
 	dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
-		 readl(regs + S3C_GRXFSIZ), readl(regs + S3C_GNPTXFSIZ));
+		 readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ));
 
 	/* show periodic fifo settings */
 
 	for (idx = 1; idx <= 15; idx++) {
-		val = readl(regs + S3C_DPTXFSIZn(idx));
+		val = readl(regs + DPTXFSIZn(idx));
 		dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx,
-			 val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT,
-			 val & S3C_DPTXFSIZn_DPTxFStAddr_MASK);
+			 val >> DPTXFSIZn_DPTxFSize_SHIFT,
+			 val & DPTXFSIZn_DPTxFStAddr_MASK);
 	}
 
 	for (idx = 0; idx < 15; idx++) {
 		dev_info(dev,
 			 "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx,
-			 readl(regs + S3C_DIEPCTL(idx)),
-			 readl(regs + S3C_DIEPTSIZ(idx)),
-			 readl(regs + S3C_DIEPDMA(idx)));
+			 readl(regs + DIEPCTL(idx)),
+			 readl(regs + DIEPTSIZ(idx)),
+			 readl(regs + DIEPDMA(idx)));
 
-		val = readl(regs + S3C_DOEPCTL(idx));
+		val = readl(regs + DOEPCTL(idx));
 		dev_info(dev,
 			 "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n",
-			 idx, readl(regs + S3C_DOEPCTL(idx)),
-			 readl(regs + S3C_DOEPTSIZ(idx)),
-			 readl(regs + S3C_DOEPDMA(idx)));
+			 idx, readl(regs + DOEPCTL(idx)),
+			 readl(regs + DOEPTSIZ(idx)),
+			 readl(regs + DOEPDMA(idx)));
 
 	}
 
 	dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n",
-		 readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE));
+		 readl(regs + DVBUSDIS), readl(regs + DVBUSPULSE));
 #endif
 }
 
-
 /**
  * state_show - debugfs: show overall driver and device state.
  * @seq: The seq file to write to.
@@ -3005,38 +3186,38 @@
 	int idx;
 
 	seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
-		 readl(regs + S3C_DCFG),
-		 readl(regs + S3C_DCTL),
-		 readl(regs + S3C_DSTS));
+		 readl(regs + DCFG),
+		 readl(regs + DCTL),
+		 readl(regs + DSTS));
 
 	seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
-		   readl(regs + S3C_DIEPMSK), readl(regs + S3C_DOEPMSK));
+		   readl(regs + DIEPMSK), readl(regs + DOEPMSK));
 
 	seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
-		   readl(regs + S3C_GINTMSK),
-		   readl(regs + S3C_GINTSTS));
+		   readl(regs + GINTMSK),
+		   readl(regs + GINTSTS));
 
 	seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
-		   readl(regs + S3C_DAINTMSK),
-		   readl(regs + S3C_DAINT));
+		   readl(regs + DAINTMSK),
+		   readl(regs + DAINT));
 
 	seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
-		   readl(regs + S3C_GNPTXSTS),
-		   readl(regs + S3C_GRXSTSR));
+		   readl(regs + GNPTXSTS),
+		   readl(regs + GRXSTSR));
 
 	seq_printf(seq, "\nEndpoint status:\n");
 
 	for (idx = 0; idx < 15; idx++) {
 		u32 in, out;
 
-		in = readl(regs + S3C_DIEPCTL(idx));
-		out = readl(regs + S3C_DOEPCTL(idx));
+		in = readl(regs + DIEPCTL(idx));
+		out = readl(regs + DOEPCTL(idx));
 
 		seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
 			   idx, in, out);
 
-		in = readl(regs + S3C_DIEPTSIZ(idx));
-		out = readl(regs + S3C_DOEPTSIZ(idx));
+		in = readl(regs + DIEPTSIZ(idx));
+		out = readl(regs + DOEPTSIZ(idx));
 
 		seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
 			   in, out);
@@ -3067,7 +3248,7 @@
  *
  * Show the FIFO information for the overall fifo and all the
  * periodic transmission FIFOs.
-*/
+ */
 static int fifo_show(struct seq_file *seq, void *v)
 {
 	struct s3c_hsotg *hsotg = seq->private;
@@ -3076,21 +3257,21 @@
 	int idx;
 
 	seq_printf(seq, "Non-periodic FIFOs:\n");
-	seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + S3C_GRXFSIZ));
+	seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ));
 
-	val = readl(regs + S3C_GNPTXFSIZ);
+	val = readl(regs + GNPTXFSIZ);
 	seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
-		   val >> S3C_GNPTXFSIZ_NPTxFDep_SHIFT,
-		   val & S3C_GNPTXFSIZ_NPTxFStAddr_MASK);
+		   val >> GNPTXFSIZ_NPTxFDep_SHIFT,
+		   val & GNPTXFSIZ_NPTxFStAddr_MASK);
 
 	seq_printf(seq, "\nPeriodic TXFIFOs:\n");
 
 	for (idx = 1; idx <= 15; idx++) {
-		val = readl(regs + S3C_DPTXFSIZn(idx));
+		val = readl(regs + DPTXFSIZn(idx));
 
 		seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
-			   val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT,
-			   val & S3C_DPTXFSIZn_DPTxFStAddr_MASK);
+			   val >> DPTXFSIZn_DPTxFSize_SHIFT,
+			   val & DPTXFSIZn_DPTxFStAddr_MASK);
 	}
 
 	return 0;
@@ -3122,7 +3303,7 @@
  *
  * This debugfs entry shows the state of the given endpoint (one is
  * registered for each available).
-*/
+ */
 static int ep_show(struct seq_file *seq, void *v)
 {
 	struct s3c_hsotg_ep *ep = seq->private;
@@ -3139,20 +3320,20 @@
 	/* first show the register state */
 
 	seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
-		   readl(regs + S3C_DIEPCTL(index)),
-		   readl(regs + S3C_DOEPCTL(index)));
+		   readl(regs + DIEPCTL(index)),
+		   readl(regs + DOEPCTL(index)));
 
 	seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
-		   readl(regs + S3C_DIEPDMA(index)),
-		   readl(regs + S3C_DOEPDMA(index)));
+		   readl(regs + DIEPDMA(index)),
+		   readl(regs + DOEPDMA(index)));
 
 	seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
-		   readl(regs + S3C_DIEPINT(index)),
-		   readl(regs + S3C_DOEPINT(index)));
+		   readl(regs + DIEPINT(index)),
+		   readl(regs + DOEPINT(index)));
 
 	seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
-		   readl(regs + S3C_DIEPTSIZ(index)),
-		   readl(regs + S3C_DOEPTSIZ(index)));
+		   readl(regs + DIEPTSIZ(index)),
+		   readl(regs + DOEPTSIZ(index)));
 
 	seq_printf(seq, "\n");
 	seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
@@ -3202,7 +3383,7 @@
  * about the state of the system. The directory name is created
  * with the same name as the device itself, in case we end up
  * with multiple blocks in future systems.
-*/
+ */
 static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
 {
 	struct dentry *root;
@@ -3231,7 +3412,7 @@
 
 	/* create one file for each endpoint */
 
-	for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) {
+	for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
 		struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
 
 		ep->debugfs = debugfs_create_file(ep->name, 0444,
@@ -3248,12 +3429,12 @@
  * @hsotg: The driver state
  *
  * Cleanup (remove) the debugfs files for use on module exit.
-*/
+ */
 static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
 {
 	unsigned epidx;
 
-	for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) {
+	for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
 		struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
 		debugfs_remove(ep->debugfs);
 	}
@@ -3264,48 +3445,39 @@
 }
 
 /**
- * s3c_hsotg_gate - set the hardware gate for the block
- * @pdev: The device we bound to
- * @on: On or off.
- *
- * Set the hardware gate setting into the block. If we end up on
- * something other than an S3C64XX, then we might need to change this
- * to using a platform data callback, or some other mechanism.
+ * s3c_hsotg_release - release callback for hsotg device
+ * @dev: Device to for which release is called
  */
-static void s3c_hsotg_gate(struct platform_device *pdev, bool on)
+static void s3c_hsotg_release(struct device *dev)
 {
-	unsigned long flags;
-	u32 others;
+	struct s3c_hsotg *hsotg = dev_get_drvdata(dev);
 
-	local_irq_save(flags);
-
-	others = __raw_readl(S3C64XX_OTHERS);
-	if (on)
-		others |= S3C64XX_OTHERS_USBMASK;
-	else
-		others &= ~S3C64XX_OTHERS_USBMASK;
-	__raw_writel(others, S3C64XX_OTHERS);
-
-	local_irq_restore(flags);
+	kfree(hsotg);
 }
 
-static struct s3c_hsotg_plat s3c_hsotg_default_pdata;
+/**
+ * s3c_hsotg_probe - probe function for hsotg driver
+ * @pdev: The platform information for the driver
+ */
 
 static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 {
 	struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
 	struct device *dev = &pdev->dev;
+	struct s3c_hsotg_ep *eps;
 	struct s3c_hsotg *hsotg;
 	struct resource *res;
 	int epnum;
 	int ret;
+	int i;
 
-	if (!plat)
-		plat = &s3c_hsotg_default_pdata;
+	plat = pdev->dev.platform_data;
+	if (!plat) {
+		dev_err(&pdev->dev, "no platform data defined\n");
+		return -EINVAL;
+	}
 
-	hsotg = kzalloc(sizeof(struct s3c_hsotg) +
-			sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS,
-			GFP_KERNEL);
+	hsotg = kzalloc(sizeof(struct s3c_hsotg), GFP_KERNEL);
 	if (!hsotg) {
 		dev_err(dev, "cannot get memory\n");
 		return -ENOMEM;
@@ -3371,6 +3543,54 @@
 
 	hsotg->gadget.dev.parent = dev;
 	hsotg->gadget.dev.dma_mask = dev->dma_mask;
+	hsotg->gadget.dev.release = s3c_hsotg_release;
+
+	/* reset the system */
+
+	clk_prepare_enable(hsotg->clk);
+
+	/* regulators */
+
+	for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
+		hsotg->supplies[i].supply = s3c_hsotg_supply_names[i];
+
+	ret = regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies),
+				 hsotg->supplies);
+	if (ret) {
+		dev_err(dev, "failed to request supplies: %d\n", ret);
+		goto err_irq;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
+				    hsotg->supplies);
+
+	if (ret) {
+		dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret);
+		goto err_supplies;
+	}
+
+	/* usb phy enable */
+	s3c_hsotg_phy_enable(hsotg);
+
+	s3c_hsotg_corereset(hsotg);
+	s3c_hsotg_init(hsotg);
+	s3c_hsotg_hw_cfg(hsotg);
+
+	/* hsotg->num_of_eps holds number of EPs other than ep0 */
+
+	if (hsotg->num_of_eps == 0) {
+		dev_err(dev, "wrong number of EPs (zero)\n");
+		goto err_supplies;
+	}
+
+	eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep),
+		      GFP_KERNEL);
+	if (!eps) {
+		dev_err(dev, "cannot get memory\n");
+		goto err_supplies;
+	}
+
+	hsotg->eps = eps;
 
 	/* setup endpoint information */
 
@@ -3383,39 +3603,47 @@
 						     GFP_KERNEL);
 	if (!hsotg->ctrl_req) {
 		dev_err(dev, "failed to allocate ctrl req\n");
-		goto err_regs;
+		goto err_ep_mem;
 	}
 
-	/* reset the system */
-
-	clk_enable(hsotg->clk);
-
-	s3c_hsotg_gate(pdev, true);
-
-	s3c_hsotg_otgreset(hsotg);
-	s3c_hsotg_corereset(hsotg);
-	s3c_hsotg_init(hsotg);
-
 	/* initialise the endpoints now the core has been initialised */
-	for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)
+	for (epnum = 0; epnum < hsotg->num_of_eps; epnum++)
 		s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
 
+	/* disable power and clock */
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
+				    hsotg->supplies);
+	if (ret) {
+		dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret);
+		goto err_ep_mem;
+	}
+
+	s3c_hsotg_phy_disable(hsotg);
+
+	ret = device_add(&hsotg->gadget.dev);
+	if (ret) {
+		put_device(&hsotg->gadget.dev);
+		goto err_ep_mem;
+	}
+
 	ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
 	if (ret)
-		goto err_add_udc;
+		goto err_ep_mem;
 
 	s3c_hsotg_create_debug(hsotg);
 
 	s3c_hsotg_dump(hsotg);
 
-	our_hsotg = hsotg;
 	return 0;
 
-err_add_udc:
-	s3c_hsotg_gate(pdev, false);
-	clk_disable(hsotg->clk);
-	clk_put(hsotg->clk);
-
+err_ep_mem:
+	kfree(eps);
+err_supplies:
+	s3c_hsotg_phy_disable(hsotg);
+	regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
+err_irq:
+	free_irq(hsotg->irq, hsotg);
 err_regs:
 	iounmap(hsotg->regs);
 
@@ -3423,12 +3651,17 @@
 	release_resource(hsotg->regs_res);
 	kfree(hsotg->regs_res);
 err_clk:
+	clk_disable_unprepare(hsotg->clk);
 	clk_put(hsotg->clk);
 err_mem:
 	kfree(hsotg);
 	return ret;
 }
 
+/**
+ * s3c_hsotg_remove - remove function for hsotg driver
+ * @pdev: The platform information for the driver
+ */
 static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
 {
 	struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
@@ -3437,7 +3670,10 @@
 
 	s3c_hsotg_delete_debug(hsotg);
 
-	usb_gadget_unregister_driver(hsotg->driver);
+	if (hsotg->driver) {
+		/* should have been done already by driver model core */
+		usb_gadget_unregister_driver(hsotg->driver);
+	}
 
 	free_irq(hsotg->irq, hsotg);
 	iounmap(hsotg->regs);
@@ -3445,12 +3681,13 @@
 	release_resource(hsotg->regs_res);
 	kfree(hsotg->regs_res);
 
-	s3c_hsotg_gate(pdev, false);
+	s3c_hsotg_phy_disable(hsotg);
+	regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 
-	clk_disable(hsotg->clk);
+	clk_disable_unprepare(hsotg->clk);
 	clk_put(hsotg->clk);
 
-	kfree(hsotg);
+	device_unregister(&hsotg->gadget.dev);
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/s3c-hsotg.h b/drivers/usb/gadget/s3c-hsotg.h
new file mode 100644
index 0000000..d650b12
--- /dev/null
+++ b/drivers/usb/gadget/s3c-hsotg.h
@@ -0,0 +1,377 @@
+/* drivers/usb/gadget/s3c-hsotg.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      http://armlinux.simtec.co.uk/
+ *      Ben Dooks <ben@simtec.co.uk>
+ *
+ * USB2.0 Highspeed/OtG Synopsis DWC2 device block registers
+ *
+ * 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 __REGS_USB_HSOTG_H
+#define __REGS_USB_HSOTG_H __FILE__
+
+#define HSOTG_REG(x) (x)
+
+#define GOTGCTL				HSOTG_REG(0x000)
+#define GOTGCTL_BSESVLD			(1 << 19)
+#define GOTGCTL_ASESVLD			(1 << 18)
+#define GOTGCTL_DBNC_SHORT			(1 << 17)
+#define GOTGCTL_CONID_B			(1 << 16)
+#define GOTGCTL_DEVHNPEN			(1 << 11)
+#define GOTGCTL_HSSETHNPEN			(1 << 10)
+#define GOTGCTL_HNPREQ				(1 << 9)
+#define GOTGCTL_HSTNEGSCS			(1 << 8)
+#define GOTGCTL_SESREQ				(1 << 1)
+#define GOTGCTL_SESREQSCS			(1 << 0)
+
+#define GOTGINT				HSOTG_REG(0x004)
+#define GOTGINT_DbnceDone			(1 << 19)
+#define GOTGINT_ADevTOUTChg			(1 << 18)
+#define GOTGINT_HstNegDet			(1 << 17)
+#define GOTGINT_HstnegSucStsChng		(1 << 9)
+#define GOTGINT_SesReqSucStsChng		(1 << 8)
+#define GOTGINT_SesEndDet			(1 << 2)
+
+#define GAHBCFG				HSOTG_REG(0x008)
+#define GAHBCFG_PTxFEmpLvl			(1 << 8)
+#define GAHBCFG_NPTxFEmpLvl			(1 << 7)
+#define GAHBCFG_DMAEn				(1 << 5)
+#define GAHBCFG_HBstLen_MASK			(0xf << 1)
+#define GAHBCFG_HBstLen_SHIFT			(1)
+#define GAHBCFG_HBstLen_Single			(0x0 << 1)
+#define GAHBCFG_HBstLen_Incr			(0x1 << 1)
+#define GAHBCFG_HBstLen_Incr4			(0x3 << 1)
+#define GAHBCFG_HBstLen_Incr8			(0x5 << 1)
+#define GAHBCFG_HBstLen_Incr16			(0x7 << 1)
+#define GAHBCFG_GlblIntrEn			(1 << 0)
+
+#define GUSBCFG				HSOTG_REG(0x00C)
+#define GUSBCFG_PHYLPClkSel			(1 << 15)
+#define GUSBCFG_HNPCap				(1 << 9)
+#define GUSBCFG_SRPCap				(1 << 8)
+#define GUSBCFG_PHYIf16			(1 << 3)
+#define GUSBCFG_TOutCal_MASK			(0x7 << 0)
+#define GUSBCFG_TOutCal_SHIFT			(0)
+#define GUSBCFG_TOutCal_LIMIT			(0x7)
+#define GUSBCFG_TOutCal(_x)			((_x) << 0)
+
+#define GRSTCTL				HSOTG_REG(0x010)
+
+#define GRSTCTL_AHBIdle			(1 << 31)
+#define GRSTCTL_DMAReq				(1 << 30)
+#define GRSTCTL_TxFNum_MASK			(0x1f << 6)
+#define GRSTCTL_TxFNum_SHIFT			(6)
+#define GRSTCTL_TxFNum_LIMIT			(0x1f)
+#define GRSTCTL_TxFNum(_x)			((_x) << 6)
+#define GRSTCTL_TxFFlsh			(1 << 5)
+#define GRSTCTL_RxFFlsh			(1 << 4)
+#define GRSTCTL_INTknQFlsh			(1 << 3)
+#define GRSTCTL_FrmCntrRst			(1 << 2)
+#define GRSTCTL_HSftRst			(1 << 1)
+#define GRSTCTL_CSftRst			(1 << 0)
+
+#define GINTSTS				HSOTG_REG(0x014)
+#define GINTMSK				HSOTG_REG(0x018)
+
+#define GINTSTS_WkUpInt			(1 << 31)
+#define GINTSTS_SessReqInt			(1 << 30)
+#define GINTSTS_DisconnInt			(1 << 29)
+#define GINTSTS_ConIDStsChng			(1 << 28)
+#define GINTSTS_PTxFEmp			(1 << 26)
+#define GINTSTS_HChInt				(1 << 25)
+#define GINTSTS_PrtInt				(1 << 24)
+#define GINTSTS_FetSusp			(1 << 22)
+#define GINTSTS_incompIP			(1 << 21)
+#define GINTSTS_IncomplSOIN			(1 << 20)
+#define GINTSTS_OEPInt				(1 << 19)
+#define GINTSTS_IEPInt				(1 << 18)
+#define GINTSTS_EPMis				(1 << 17)
+#define GINTSTS_EOPF				(1 << 15)
+#define GINTSTS_ISOutDrop			(1 << 14)
+#define GINTSTS_EnumDone			(1 << 13)
+#define GINTSTS_USBRst				(1 << 12)
+#define GINTSTS_USBSusp			(1 << 11)
+#define GINTSTS_ErlySusp			(1 << 10)
+#define GINTSTS_GOUTNakEff			(1 << 7)
+#define GINTSTS_GINNakEff			(1 << 6)
+#define GINTSTS_NPTxFEmp			(1 << 5)
+#define GINTSTS_RxFLvl				(1 << 4)
+#define GINTSTS_SOF				(1 << 3)
+#define GINTSTS_OTGInt				(1 << 2)
+#define GINTSTS_ModeMis			(1 << 1)
+#define GINTSTS_CurMod_Host			(1 << 0)
+
+#define GRXSTSR				HSOTG_REG(0x01C)
+#define GRXSTSP				HSOTG_REG(0x020)
+
+#define GRXSTS_FN_MASK				(0x7f << 25)
+#define GRXSTS_FN_SHIFT			(25)
+
+#define GRXSTS_PktSts_MASK			(0xf << 17)
+#define GRXSTS_PktSts_SHIFT			(17)
+#define GRXSTS_PktSts_GlobalOutNAK		(0x1 << 17)
+#define GRXSTS_PktSts_OutRX			(0x2 << 17)
+#define GRXSTS_PktSts_OutDone			(0x3 << 17)
+#define GRXSTS_PktSts_SetupDone		(0x4 << 17)
+#define GRXSTS_PktSts_SetupRX			(0x6 << 17)
+
+#define GRXSTS_DPID_MASK			(0x3 << 15)
+#define GRXSTS_DPID_SHIFT			(15)
+#define GRXSTS_ByteCnt_MASK			(0x7ff << 4)
+#define GRXSTS_ByteCnt_SHIFT			(4)
+#define GRXSTS_EPNum_MASK			(0xf << 0)
+#define GRXSTS_EPNum_SHIFT			(0)
+
+#define GRXFSIZ				HSOTG_REG(0x024)
+
+#define GNPTXFSIZ				HSOTG_REG(0x028)
+
+#define GNPTXFSIZ_NPTxFDep_MASK		(0xffff << 16)
+#define GNPTXFSIZ_NPTxFDep_SHIFT		(16)
+#define GNPTXFSIZ_NPTxFDep_LIMIT		(0xffff)
+#define GNPTXFSIZ_NPTxFDep(_x)			((_x) << 16)
+#define GNPTXFSIZ_NPTxFStAddr_MASK		(0xffff << 0)
+#define GNPTXFSIZ_NPTxFStAddr_SHIFT		(0)
+#define GNPTXFSIZ_NPTxFStAddr_LIMIT		(0xffff)
+#define GNPTXFSIZ_NPTxFStAddr(_x)		((_x) << 0)
+
+#define GNPTXSTS				HSOTG_REG(0x02C)
+
+#define GNPTXSTS_NPtxQTop_MASK			(0x7f << 24)
+#define GNPTXSTS_NPtxQTop_SHIFT		(24)
+
+#define GNPTXSTS_NPTxQSpcAvail_MASK		(0xff << 16)
+#define GNPTXSTS_NPTxQSpcAvail_SHIFT		(16)
+#define GNPTXSTS_NPTxQSpcAvail_GET(_v)		(((_v) >> 16) & 0xff)
+
+#define GNPTXSTS_NPTxFSpcAvail_MASK		(0xffff << 0)
+#define GNPTXSTS_NPTxFSpcAvail_SHIFT		(0)
+#define GNPTXSTS_NPTxFSpcAvail_GET(_v)		(((_v) >> 0) & 0xffff)
+
+
+#define HPTXFSIZ				HSOTG_REG(0x100)
+
+#define DPTXFSIZn(_a)		HSOTG_REG(0x104 + (((_a) - 1) * 4))
+
+#define DPTXFSIZn_DPTxFSize_MASK		(0xffff << 16)
+#define DPTXFSIZn_DPTxFSize_SHIFT		(16)
+#define DPTXFSIZn_DPTxFSize_GET(_v)		(((_v) >> 16) & 0xffff)
+#define DPTXFSIZn_DPTxFSize_LIMIT		(0xffff)
+#define DPTXFSIZn_DPTxFSize(_x)		((_x) << 16)
+
+#define DPTXFSIZn_DPTxFStAddr_MASK		(0xffff << 0)
+#define DPTXFSIZn_DPTxFStAddr_SHIFT		(0)
+
+/* Device mode registers */
+#define DCFG					HSOTG_REG(0x800)
+
+#define DCFG_EPMisCnt_MASK			(0x1f << 18)
+#define DCFG_EPMisCnt_SHIFT			(18)
+#define DCFG_EPMisCnt_LIMIT			(0x1f)
+#define DCFG_EPMisCnt(_x)			((_x) << 18)
+
+#define DCFG_PerFrInt_MASK			(0x3 << 11)
+#define DCFG_PerFrInt_SHIFT			(11)
+#define DCFG_PerFrInt_LIMIT			(0x3)
+#define DCFG_PerFrInt(_x)			((_x) << 11)
+
+#define DCFG_DevAddr_MASK			(0x7f << 4)
+#define DCFG_DevAddr_SHIFT			(4)
+#define DCFG_DevAddr_LIMIT			(0x7f)
+#define DCFG_DevAddr(_x)			((_x) << 4)
+
+#define DCFG_NZStsOUTHShk			(1 << 2)
+
+#define DCFG_DevSpd_MASK			(0x3 << 0)
+#define DCFG_DevSpd_SHIFT			(0)
+#define DCFG_DevSpd_HS				(0x0 << 0)
+#define DCFG_DevSpd_FS				(0x1 << 0)
+#define DCFG_DevSpd_LS				(0x2 << 0)
+#define DCFG_DevSpd_FS48			(0x3 << 0)
+
+#define DCTL					HSOTG_REG(0x804)
+
+#define DCTL_PWROnPrgDone			(1 << 11)
+#define DCTL_CGOUTNak				(1 << 10)
+#define DCTL_SGOUTNak				(1 << 9)
+#define DCTL_CGNPInNAK				(1 << 8)
+#define DCTL_SGNPInNAK				(1 << 7)
+#define DCTL_TstCtl_MASK			(0x7 << 4)
+#define DCTL_TstCtl_SHIFT			(4)
+#define DCTL_GOUTNakSts			(1 << 3)
+#define DCTL_GNPINNakSts			(1 << 2)
+#define DCTL_SftDiscon				(1 << 1)
+#define DCTL_RmtWkUpSig			(1 << 0)
+
+#define DSTS					HSOTG_REG(0x808)
+
+#define DSTS_SOFFN_MASK			(0x3fff << 8)
+#define DSTS_SOFFN_SHIFT			(8)
+#define DSTS_SOFFN_LIMIT			(0x3fff)
+#define DSTS_SOFFN(_x)				((_x) << 8)
+#define DSTS_ErraticErr			(1 << 3)
+#define DSTS_EnumSpd_MASK			(0x3 << 1)
+#define DSTS_EnumSpd_SHIFT			(1)
+#define DSTS_EnumSpd_HS			(0x0 << 1)
+#define DSTS_EnumSpd_FS			(0x1 << 1)
+#define DSTS_EnumSpd_LS			(0x2 << 1)
+#define DSTS_EnumSpd_FS48			(0x3 << 1)
+
+#define DSTS_SuspSts				(1 << 0)
+
+#define DIEPMSK				HSOTG_REG(0x810)
+
+#define DIEPMSK_TxFIFOEmpty			(1 << 7)
+#define DIEPMSK_INEPNakEffMsk			(1 << 6)
+#define DIEPMSK_INTknEPMisMsk			(1 << 5)
+#define DIEPMSK_INTknTXFEmpMsk			(1 << 4)
+#define DIEPMSK_TimeOUTMsk			(1 << 3)
+#define DIEPMSK_AHBErrMsk			(1 << 2)
+#define DIEPMSK_EPDisbldMsk			(1 << 1)
+#define DIEPMSK_XferComplMsk			(1 << 0)
+
+#define DOEPMSK				HSOTG_REG(0x814)
+
+#define DOEPMSK_Back2BackSetup			(1 << 6)
+#define DOEPMSK_OUTTknEPdisMsk			(1 << 4)
+#define DOEPMSK_SetupMsk			(1 << 3)
+#define DOEPMSK_AHBErrMsk			(1 << 2)
+#define DOEPMSK_EPDisbldMsk			(1 << 1)
+#define DOEPMSK_XferComplMsk			(1 << 0)
+
+#define DAINT					HSOTG_REG(0x818)
+#define DAINTMSK				HSOTG_REG(0x81C)
+
+#define DAINT_OutEP_SHIFT			(16)
+#define DAINT_OutEP(x)				(1 << ((x) + 16))
+#define DAINT_InEP(x)				(1 << (x))
+
+#define DTKNQR1				HSOTG_REG(0x820)
+#define DTKNQR2				HSOTG_REG(0x824)
+#define DTKNQR3				HSOTG_REG(0x830)
+#define DTKNQR4				HSOTG_REG(0x834)
+
+#define DVBUSDIS				HSOTG_REG(0x828)
+#define DVBUSPULSE				HSOTG_REG(0x82C)
+
+#define DIEPCTL0				HSOTG_REG(0x900)
+#define DOEPCTL0				HSOTG_REG(0xB00)
+#define DIEPCTL(_a)			HSOTG_REG(0x900 + ((_a) * 0x20))
+#define DOEPCTL(_a)			HSOTG_REG(0xB00 + ((_a) * 0x20))
+
+/* EP0 specialness:
+ * bits[29..28] - reserved (no SetD0PID, SetD1PID)
+ * bits[25..22] - should always be zero, this isn't a periodic endpoint
+ * bits[10..0] - MPS setting differenct for EP0
+ */
+#define D0EPCTL_MPS_MASK			(0x3 << 0)
+#define D0EPCTL_MPS_SHIFT			(0)
+#define D0EPCTL_MPS_64				(0x0 << 0)
+#define D0EPCTL_MPS_32				(0x1 << 0)
+#define D0EPCTL_MPS_16				(0x2 << 0)
+#define D0EPCTL_MPS_8				(0x3 << 0)
+
+#define DxEPCTL_EPEna				(1 << 31)
+#define DxEPCTL_EPDis				(1 << 30)
+#define DxEPCTL_SetD1PID			(1 << 29)
+#define DxEPCTL_SetOddFr			(1 << 29)
+#define DxEPCTL_SetD0PID			(1 << 28)
+#define DxEPCTL_SetEvenFr			(1 << 28)
+#define DxEPCTL_SNAK				(1 << 27)
+#define DxEPCTL_CNAK				(1 << 26)
+#define DxEPCTL_TxFNum_MASK			(0xf << 22)
+#define DxEPCTL_TxFNum_SHIFT			(22)
+#define DxEPCTL_TxFNum_LIMIT			(0xf)
+#define DxEPCTL_TxFNum(_x)			((_x) << 22)
+
+#define DxEPCTL_Stall				(1 << 21)
+#define DxEPCTL_Snp				(1 << 20)
+#define DxEPCTL_EPType_MASK			(0x3 << 18)
+#define DxEPCTL_EPType_SHIFT			(18)
+#define DxEPCTL_EPType_Control			(0x0 << 18)
+#define DxEPCTL_EPType_Iso			(0x1 << 18)
+#define DxEPCTL_EPType_Bulk			(0x2 << 18)
+#define DxEPCTL_EPType_Intterupt		(0x3 << 18)
+
+#define DxEPCTL_NAKsts				(1 << 17)
+#define DxEPCTL_DPID				(1 << 16)
+#define DxEPCTL_EOFrNum			(1 << 16)
+#define DxEPCTL_USBActEp			(1 << 15)
+#define DxEPCTL_NextEp_MASK			(0xf << 11)
+#define DxEPCTL_NextEp_SHIFT			(11)
+#define DxEPCTL_NextEp_LIMIT			(0xf)
+#define DxEPCTL_NextEp(_x)			((_x) << 11)
+
+#define DxEPCTL_MPS_MASK			(0x7ff << 0)
+#define DxEPCTL_MPS_SHIFT			(0)
+#define DxEPCTL_MPS_LIMIT			(0x7ff)
+#define DxEPCTL_MPS(_x)			((_x) << 0)
+
+#define DIEPINT(_a)			HSOTG_REG(0x908 + ((_a) * 0x20))
+#define DOEPINT(_a)			HSOTG_REG(0xB08 + ((_a) * 0x20))
+
+#define DxEPINT_INEPNakEff			(1 << 6)
+#define DxEPINT_Back2BackSetup			(1 << 6)
+#define DxEPINT_INTknEPMis			(1 << 5)
+#define DxEPINT_INTknTXFEmp			(1 << 4)
+#define DxEPINT_OUTTknEPdis			(1 << 4)
+#define DxEPINT_Timeout			(1 << 3)
+#define DxEPINT_Setup				(1 << 3)
+#define DxEPINT_AHBErr				(1 << 2)
+#define DxEPINT_EPDisbld			(1 << 1)
+#define DxEPINT_XferCompl			(1 << 0)
+
+#define DIEPTSIZ0				HSOTG_REG(0x910)
+
+#define DIEPTSIZ0_PktCnt_MASK			(0x3 << 19)
+#define DIEPTSIZ0_PktCnt_SHIFT			(19)
+#define DIEPTSIZ0_PktCnt_LIMIT			(0x3)
+#define DIEPTSIZ0_PktCnt(_x)			((_x) << 19)
+
+#define DIEPTSIZ0_XferSize_MASK		(0x7f << 0)
+#define DIEPTSIZ0_XferSize_SHIFT		(0)
+#define DIEPTSIZ0_XferSize_LIMIT		(0x7f)
+#define DIEPTSIZ0_XferSize(_x)			((_x) << 0)
+
+#define DOEPTSIZ0				HSOTG_REG(0xB10)
+#define DOEPTSIZ0_SUPCnt_MASK			(0x3 << 29)
+#define DOEPTSIZ0_SUPCnt_SHIFT			(29)
+#define DOEPTSIZ0_SUPCnt_LIMIT			(0x3)
+#define DOEPTSIZ0_SUPCnt(_x)			((_x) << 29)
+
+#define DOEPTSIZ0_PktCnt			(1 << 19)
+#define DOEPTSIZ0_XferSize_MASK		(0x7f << 0)
+#define DOEPTSIZ0_XferSize_SHIFT		(0)
+
+#define DIEPTSIZ(_a)			HSOTG_REG(0x910 + ((_a) * 0x20))
+#define DOEPTSIZ(_a)			HSOTG_REG(0xB10 + ((_a) * 0x20))
+
+#define DxEPTSIZ_MC_MASK			(0x3 << 29)
+#define DxEPTSIZ_MC_SHIFT			(29)
+#define DxEPTSIZ_MC_LIMIT			(0x3)
+#define DxEPTSIZ_MC(_x)			((_x) << 29)
+
+#define DxEPTSIZ_PktCnt_MASK			(0x3ff << 19)
+#define DxEPTSIZ_PktCnt_SHIFT			(19)
+#define DxEPTSIZ_PktCnt_GET(_v)		(((_v) >> 19) & 0x3ff)
+#define DxEPTSIZ_PktCnt_LIMIT			(0x3ff)
+#define DxEPTSIZ_PktCnt(_x)			((_x) << 19)
+
+#define DxEPTSIZ_XferSize_MASK			(0x7ffff << 0)
+#define DxEPTSIZ_XferSize_SHIFT		(0)
+#define DxEPTSIZ_XferSize_GET(_v)		(((_v) >> 0) & 0x7ffff)
+#define DxEPTSIZ_XferSize_LIMIT		(0x7ffff)
+#define DxEPTSIZ_XferSize(_x)			((_x) << 0)
+
+#define DIEPDMA(_a)			HSOTG_REG(0x914 + ((_a) * 0x20))
+#define DOEPDMA(_a)			HSOTG_REG(0xB14 + ((_a) * 0x20))
+#define DTXFSTS(_a)			HSOTG_REG(0x918 + ((_a) * 0x20))
+
+#define EPFIFO(_a)			HSOTG_REG(0x1000 + ((_a) * 0x1000))
+
+#endif /* __REGS_USB_HSOTG_H */
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index cef9b82..36c6836 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -110,7 +110,6 @@
 	struct usb_ep ep;
 	char name[20];
 	struct s3c_hsudc *dev;
-	const struct usb_endpoint_descriptor *desc;
 	struct list_head queue;
 	u8 stopped;
 	u8 wedge;
@@ -761,7 +760,7 @@
 	u32 ecr = 0;
 
 	hsep = our_ep(_ep);
-	if (!_ep || !desc || hsep->desc || _ep->name == ep0name
+	if (!_ep || !desc || hsep->ep.desc || _ep->name == ep0name
 		|| desc->bDescriptorType != USB_DT_ENDPOINT
 		|| hsep->bEndpointAddress != desc->bEndpointAddress
 		|| ep_maxpacket(hsep) < usb_endpoint_maxp(desc))
@@ -783,7 +782,7 @@
 	writel(ecr, hsudc->regs + S3C_ECR);
 
 	hsep->stopped = hsep->wedge = 0;
-	hsep->desc = desc;
+	hsep->ep.desc = desc;
 	hsep->ep.maxpacket = usb_endpoint_maxp(desc);
 
 	s3c_hsudc_set_halt(_ep, 0);
@@ -806,7 +805,7 @@
 	struct s3c_hsudc *hsudc = hsep->dev;
 	unsigned long flags;
 
-	if (!_ep || !hsep->desc)
+	if (!_ep || !hsep->ep.desc)
 		return -EINVAL;
 
 	spin_lock_irqsave(&hsudc->lock, flags);
@@ -816,7 +815,6 @@
 
 	s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
 
-	hsep->desc = 0;
 	hsep->ep.desc = NULL;
 	hsep->stopped = 1;
 
@@ -1006,7 +1004,6 @@
 	hsep->ep.maxpacket = epnum ? 512 : 64;
 	hsep->ep.ops = &s3c_hsudc_ep_ops;
 	hsep->fifo = hsudc->regs + S3C_BR(epnum);
-	hsep->desc = 0;
 	hsep->ep.desc = NULL;
 	hsep->stopped = 0;
 	hsep->wedge = 0;
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 195524c..3de71d3 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1062,7 +1062,7 @@
 
 	ep = to_s3c2410_ep(_ep);
 
-	if (!_ep || !desc || ep->desc
+	if (!_ep || !desc || ep->ep.desc
 			|| _ep->name == ep0name
 			|| desc->bDescriptorType != USB_DT_ENDPOINT)
 		return -EINVAL;
@@ -1075,7 +1075,7 @@
 
 	local_irq_save (flags);
 	_ep->maxpacket = max & 0x7ff;
-	ep->desc = desc;
+	ep->ep.desc = desc;
 	ep->halted = 0;
 	ep->bEndpointAddress = desc->bEndpointAddress;
 
@@ -1136,7 +1136,7 @@
 	unsigned long flags;
 	u32 int_en_reg;
 
-	if (!_ep || !ep->desc) {
+	if (!_ep || !ep->ep.desc) {
 		dprintk(DEBUG_NORMAL, "%s not enabled\n",
 			_ep ? ep->ep.name : NULL);
 		return -EINVAL;
@@ -1146,7 +1146,6 @@
 
 	dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);
 
-	ep->desc = NULL;
 	ep->ep.desc = NULL;
 	ep->halted = 1;
 
@@ -1195,7 +1194,7 @@
 
 	dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);
 
-	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
+	if (!ep || !_req || (!ep->ep.desc && _ep->name != ep0name))
 		return;
 
 	WARN_ON (!list_empty (&req->queue));
@@ -1215,7 +1214,7 @@
 	int			fifo_count = 0;
 	unsigned long		flags;
 
-	if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+	if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
 		dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__);
 		return -EINVAL;
 	}
@@ -1363,7 +1362,7 @@
 	unsigned long		flags;
 	u32			idx;
 
-	if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+	if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
 		dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__);
 		return -EINVAL;
 	}
@@ -1629,7 +1628,6 @@
 			list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
 
 		ep->dev = dev;
-		ep->desc = NULL;
 		ep->ep.desc = NULL;
 		ep->halted = 0;
 		INIT_LIST_HEAD (&ep->queue);
diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h
index 1653bae..3e80fd5 100644
--- a/drivers/usb/gadget/s3c2410_udc.h
+++ b/drivers/usb/gadget/s3c2410_udc.h
@@ -19,7 +19,6 @@
 	unsigned long			last_io;	/* jiffies timestamp */
 	struct usb_gadget		*gadget;
 	struct s3c2410_udc		*dev;
-	const struct usb_endpoint_descriptor *desc;
 	struct usb_ep			ep;
 	u8				num;
 
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 29c854b..47cf48b 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -744,10 +744,11 @@
 };
 
 /**
- * gether_setup - initialize one ethernet-over-usb link
+ * gether_setup_name - initialize one ethernet-over-usb link
  * @g: gadget to associated with these links
  * @ethaddr: NULL, or a buffer in which the ethernet address of the
  *	host side of the link is recorded
+ * @netname: name for network device (for example, "usb")
  * Context: may sleep
  *
  * This sets up the single network link that may be exported by a
@@ -756,7 +757,8 @@
  *
  * Returns negative errno, or zero on success
  */
-int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+		const char *netname)
 {
 	struct eth_dev		*dev;
 	struct net_device	*net;
@@ -780,7 +782,7 @@
 
 	/* network device setup */
 	dev->net = net;
-	strcpy(net->name, "usb%d");
+	snprintf(net->name, sizeof(net->name), "%s%%d", netname);
 
 	if (get_ether_addr(dev_addr, net->dev_addr))
 		dev_warn(&g->dev,
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 8012357..6f4a1623 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -69,9 +69,28 @@
 			|USB_CDC_PACKET_TYPE_PROMISCUOUS \
 			|USB_CDC_PACKET_TYPE_DIRECTED)
 
+/* variant of gether_setup that allows customizing network device name */
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+		const char *netname);
 
 /* netdev setup/teardown as directed by the gadget driver */
-int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]);
+/* gether_setup - initialize one ethernet-over-usb link
+ * @g: gadget to associated with these links
+ * @ethaddr: NULL, or a buffer in which the ethernet address of the
+ *	host side of the link is recorded
+ * Context: may sleep
+ *
+ * This sets up the single network link that may be exported by a
+ * gadget driver using this framework.  The link layer addresses are
+ * set up using module parameters.
+ *
+ * Returns negative errno, or zero on success
+ */
+static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+{
+	return gether_setup_name(g, ethaddr, "usb");
+}
+
 void gether_cleanup(void);
 
 /* connect/disconnect is handled by individual functions */
@@ -99,16 +118,37 @@
 
 #ifdef USB_ETH_RNDIS
 
-int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+				u32 vendorID, const char *manufacturer);
 
 #else
 
 static inline int
-rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+				u32 vendorID, const char *manufacturer)
 {
 	return 0;
 }
 
 #endif
 
+/**
+ * rndis_bind_config - add RNDIS network link to a configuration
+ * @c: the configuration to support the network link
+ * @ethaddr: a buffer in which the ethernet address of the host side
+ *	side of the link was recorded
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gether_setup().  Caller is also responsible
+ * for calling @gether_cleanup() before module unload.
+ */
+static inline int rndis_bind_config(struct usb_configuration *c,
+				    u8 ethaddr[ETH_ALEN])
+{
+	return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+}
+
+
 #endif /* __U_ETHER_H */
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 6c23938..5b3f5ff 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -94,17 +94,14 @@
  * (and thus for each /dev/ node).
  */
 struct gs_port {
+	struct tty_port		port;
 	spinlock_t		port_lock;	/* guard port_* access */
 
 	struct gserial		*port_usb;
-	struct tty_struct	*port_tty;
 
-	unsigned		open_count;
 	bool			openclose;	/* open/close in progress */
 	u8			port_num;
 
-	wait_queue_head_t	close_wait;	/* wait for last close */
-
 	struct list_head	read_pool;
 	int read_started;
 	int read_allocated;
@@ -412,8 +409,8 @@
 			break;
 	}
 
-	if (do_tty_wake && port->port_tty)
-		tty_wakeup(port->port_tty);
+	if (do_tty_wake && port->port.tty)
+		tty_wakeup(port->port.tty);
 	return status;
 }
 
@@ -435,7 +432,7 @@
 		struct tty_struct	*tty;
 
 		/* no more rx if closed */
-		tty = port->port_tty;
+		tty = port->port.tty;
 		if (!tty)
 			break;
 
@@ -488,7 +485,7 @@
 
 	/* hand any queued data to the tty */
 	spin_lock_irq(&port->port_lock);
-	tty = port->port_tty;
+	tty = port->port.tty;
 	while (!list_empty(queue)) {
 		struct usb_request	*req;
 
@@ -699,7 +696,7 @@
 
 	/* unblock any pending writes into our circular buffer */
 	if (started) {
-		tty_wakeup(port->port_tty);
+		tty_wakeup(port->port.tty);
 	} else {
 		gs_free_requests(ep, head, &port->read_allocated);
 		gs_free_requests(port->port_usb->in, &port->write_pool,
@@ -734,9 +731,9 @@
 			spin_lock_irq(&port->port_lock);
 
 			/* already open?  Great. */
-			if (port->open_count) {
+			if (port->port.count) {
 				status = 0;
-				port->open_count++;
+				port->port.count++;
 
 			/* currently opening/closing? wait ... */
 			} else if (port->openclose) {
@@ -793,9 +790,9 @@
 	/* REVISIT maybe wait for "carrier detect" */
 
 	tty->driver_data = port;
-	port->port_tty = tty;
+	port->port.tty = tty;
 
-	port->open_count = 1;
+	port->port.count = 1;
 	port->openclose = false;
 
 	/* if connected, start the I/O stream */
@@ -837,11 +834,11 @@
 
 	spin_lock_irq(&port->port_lock);
 
-	if (port->open_count != 1) {
-		if (port->open_count == 0)
+	if (port->port.count != 1) {
+		if (port->port.count == 0)
 			WARN_ON(1);
 		else
-			--port->open_count;
+			--port->port.count;
 		goto exit;
 	}
 
@@ -851,7 +848,7 @@
 	 * and sleep if necessary
 	 */
 	port->openclose = true;
-	port->open_count = 0;
+	port->port.count = 0;
 
 	gser = port->port_usb;
 	if (gser && gser->disconnect)
@@ -879,14 +876,14 @@
 		gs_buf_clear(&port->port_write_buf);
 
 	tty->driver_data = NULL;
-	port->port_tty = NULL;
+	port->port.tty = NULL;
 
 	port->openclose = false;
 
 	pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
 			port->port_num, tty, file);
 
-	wake_up_interruptible(&port->close_wait);
+	wake_up_interruptible(&port->port.close_wait);
 exit:
 	spin_unlock_irq(&port->port_lock);
 }
@@ -917,7 +914,7 @@
 	unsigned long	flags;
 	int		status;
 
-	pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+	pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n",
 		port->port_num, tty, ch, __builtin_return_address(0));
 
 	spin_lock_irqsave(&port->port_lock, flags);
@@ -1025,7 +1022,7 @@
 
 static struct tty_driver *gs_tty_driver;
 
-static int __init
+static int
 gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
 {
 	struct gs_port	*port;
@@ -1034,8 +1031,8 @@
 	if (port == NULL)
 		return -ENOMEM;
 
+	tty_port_init(&port->port);
 	spin_lock_init(&port->port_lock);
-	init_waitqueue_head(&port->close_wait);
 	init_waitqueue_head(&port->drain_wait);
 
 	tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
@@ -1071,7 +1068,7 @@
  *
  * Returns negative errno or zero.
  */
-int __init gserial_setup(struct usb_gadget *g, unsigned count)
+int gserial_setup(struct usb_gadget *g, unsigned count)
 {
 	unsigned			i;
 	struct usb_cdc_line_coding	coding;
@@ -1155,7 +1152,7 @@
 	int cond;
 
 	spin_lock_irq(&port->port_lock);
-	cond = (port->open_count == 0) && !port->openclose;
+	cond = (port->port.count == 0) && !port->openclose;
 	spin_unlock_irq(&port->port_lock);
 	return cond;
 }
@@ -1194,7 +1191,7 @@
 		tasklet_kill(&port->push);
 
 		/* wait for old opens to finish */
-		wait_event(port->close_wait, gs_closed(port));
+		wait_event(port->port.close_wait, gs_closed(port));
 
 		WARN_ON(port->port_usb != NULL);
 
@@ -1268,7 +1265,7 @@
 	/* if it's already open, start I/O ... and notify the serial
 	 * protocol about open/close status (connect/disconnect).
 	 */
-	if (port->open_count) {
+	if (port->port.count) {
 		pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
 		gs_start_io(port);
 		if (gser->connect)
@@ -1315,10 +1312,10 @@
 
 	port->port_usb = NULL;
 	gser->ioport = NULL;
-	if (port->open_count > 0 || port->openclose) {
+	if (port->port.count > 0 || port->openclose) {
 		wake_up_interruptible(&port->drain_wait);
-		if (port->port_tty)
-			tty_hangup(port->port_tty);
+		if (port->port.tty)
+			tty_hangup(port->port.tty);
 	}
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
@@ -1331,7 +1328,7 @@
 
 	/* finally, free any unused/unusable I/O buffers */
 	spin_lock_irqsave(&port->port_lock, flags);
-	if (port->open_count == 0 && !port->openclose)
+	if (port->port.count == 0 && !port->openclose)
 		gs_buf_free(&port->port_write_buf);
 	gs_free_requests(gser->out, &port->read_pool, NULL);
 	gs_free_requests(gser->out, &port->read_queue, NULL);
diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
index 0cdf89d..104ae9c 100644
--- a/drivers/usb/gadget/uvc_queue.c
+++ b/drivers/usb/gadget/uvc_queue.c
@@ -543,7 +543,7 @@
 	return ret;
 }
 
-/* called with queue->irqlock held.. */
+/* called with &queue_irqlock held.. */
 static struct uvc_buffer *
 uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
 {
diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c
index 54d7ca5..2ca9386 100644
--- a/drivers/usb/gadget/uvc_v4l2.c
+++ b/drivers/usb/gadget/uvc_v4l2.c
@@ -296,7 +296,7 @@
 		if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
 			return -EINVAL;
 
-		return v4l2_event_subscribe(&handle->vfh, arg, 2);
+		return v4l2_event_subscribe(&handle->vfh, arg, 2, NULL);
 	}
 
 	case VIDIOC_UNSUBSCRIBE_EVENT:
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 31d3483..12ad516 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -72,7 +72,7 @@
 
 static const char longname[] = "Gadget Zero";
 
-unsigned buflen = 4096;
+unsigned buflen = 4096;		/* only used for bulk endpoints */
 module_param(buflen, uint, 0);
 
 /*
@@ -170,14 +170,17 @@
 
 /*-------------------------------------------------------------------------*/
 
-struct usb_request *alloc_ep_req(struct usb_ep *ep)
+struct usb_request *alloc_ep_req(struct usb_ep *ep, int len)
 {
 	struct usb_request	*req;
 
 	req = usb_ep_alloc_request(ep, GFP_ATOMIC);
 	if (req) {
-		req->length = buflen;
-		req->buf = kmalloc(buflen, GFP_ATOMIC);
+		if (len)
+			req->length = len;
+		else
+			req->length = buflen;
+		req->buf = kmalloc(req->length, GFP_ATOMIC);
 		if (!req->buf) {
 			usb_ep_free_request(ep, req);
 			req = NULL;
@@ -206,10 +209,15 @@
 }
 
 void disable_endpoints(struct usb_composite_dev *cdev,
-		struct usb_ep *in, struct usb_ep *out)
+		struct usb_ep *in, struct usb_ep *out,
+		struct usb_ep *iso_in, struct usb_ep *iso_out)
 {
 	disable_ep(cdev, in);
 	disable_ep(cdev, out);
+	if (iso_in)
+		disable_ep(cdev, iso_in);
+	if (iso_out)
+		disable_ep(cdev, iso_out);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -311,7 +319,6 @@
 		device_desc.bcdDevice = cpu_to_le16(0x9999);
 	}
 
-
 	INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
 
 	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index f788eb8..83e58df 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -65,7 +65,7 @@
 
 config USB_EHCI_ROOT_HUB_TT
 	bool "Root Hub Transaction Translators"
-	depends on USB_EHCI_HCD
+	depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST
 	---help---
 	  Some EHCI chips have vendor-specific extensions to integrate
 	  transaction translators, so that no OHCI or UHCI companion
@@ -77,7 +77,7 @@
 
 config USB_EHCI_TT_NEWSCHED
 	bool "Improved Transaction Translator scheduling"
-	depends on USB_EHCI_HCD
+	depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST
 	default y
 	---help---
 	  This changes the periodic scheduling code to fill more of the low
@@ -110,13 +110,14 @@
 	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
 				    ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
 				    PPC_MPC512x || CPU_CAVIUM_OCTEON || \
-				    PMC_MSP || SPARC_LEON)
+				    PMC_MSP || SPARC_LEON || MIPS_SEAD3)
 	default y
 
 config USB_EHCI_BIG_ENDIAN_DESC
 	bool
 	depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
-				    PPC_MPC512x || PMC_MSP || SPARC_LEON)
+				    PPC_MPC512x || PMC_MSP || SPARC_LEON || \
+				    MIPS_SEAD3)
 	default y
 
 config XPS_USB_HCD_XILINX
@@ -152,7 +153,7 @@
 	bool "EHCI support for OMAP3 and later chips"
 	depends on USB_EHCI_HCD && ARCH_OMAP
 	default y
-	--- help ---
+	---help---
 	  Enables support for the on-chip EHCI controller on
 	  OMAP3 and later chips.
 
@@ -291,6 +292,7 @@
 	depends on USB && USB_ARCH_HAS_OHCI
 	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
 	select USB_OTG_UTILS if ARCH_OMAP
+	select USB_ISP1301 if ARCH_LPC32XX || ARCH_PNX4008
 	---help---
 	  The Open Host Controller Interface (OHCI) is a standard for accessing
 	  USB 1.1 host controller hardware.  It does more in hardware than Intel's
@@ -373,10 +375,15 @@
 	  If unsure, say Y.
 
 config USB_OHCI_HCD_SSB
-	bool "OHCI support for Broadcom SSB OHCI core"
+	bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)"
 	depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) && EXPERIMENTAL
+	select USB_HCD_SSB
+	select USB_OHCI_HCD_PLATFORM
 	default n
 	---help---
+	  This option is deprecated now and the driver was removed, use
+	  USB_HCD_SSB and USB_OHCI_HCD_PLATFORM instead.
+
 	  Support for the Sonics Silicon Backplane (SSB) attached
 	  Broadcom USB OHCI core.
 
@@ -638,3 +645,27 @@
 config USB_OCTEON2_COMMON
 	bool
 	default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
+
+config USB_HCD_BCMA
+	tristate "BCMA usb host driver"
+	depends on BCMA && EXPERIMENTAL
+	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
+	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
+	help
+	  Enbale support for the EHCI and OCHI host controller on an bcma bus.
+	  It converts the bcma driver into two platform device drivers
+	  for ehci and ohci.
+
+	  If unsure, say N.
+
+config USB_HCD_SSB
+	tristate "SSB usb host driver"
+	depends on SSB && EXPERIMENTAL
+	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
+	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
+	help
+	  Enbale support for the EHCI and OCHI host controller on an bcma bus.
+	  It converts the bcma driver into two platform device drivers
+	  for ehci and ohci.
+
+	  If unsure, say N.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 0982bcc..9e0a89c 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -41,3 +41,5 @@
 obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= fsl-mph-dr-of.o
 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
 obj-$(CONFIG_MIPS_ALCHEMY)	+= alchemy-common.o
+obj-$(CONFIG_USB_HCD_BCMA)	+= bcma-hcd.o
+obj-$(CONFIG_USB_HCD_SSB)	+= ssb-hcd.o
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
new file mode 100644
index 0000000..443da21
--- /dev/null
+++ b/drivers/usb/host/bcma-hcd.c
@@ -0,0 +1,335 @@
+/*
+ * Broadcom specific Advanced Microcontroller Bus
+ * Broadcom USB-core driver (BCMA bus glue)
+ *
+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Based on ssb-ohci driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005-2011 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/bcma/bcma.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
+
+MODULE_AUTHOR("Hauke Mehrtens");
+MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
+MODULE_LICENSE("GPL");
+
+struct bcma_hcd_device {
+	struct platform_device *ehci_dev;
+	struct platform_device *ohci_dev;
+};
+
+/* Wait for bitmask in a register to get set or cleared.
+ * timeout is in units of ten-microseconds.
+ */
+static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
+			  int timeout)
+{
+	int i;
+	u32 val;
+
+	for (i = 0; i < timeout; i++) {
+		val = bcma_read32(dev, reg);
+		if ((val & bitmask) == bitmask)
+			return 0;
+		udelay(10);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static void __devinit bcma_hcd_4716wa(struct bcma_device *dev)
+{
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+	/* Work around for 4716 failures. */
+	if (dev->bus->chipinfo.id == 0x4716) {
+		u32 tmp;
+
+		tmp = bcma_cpu_clock(&dev->bus->drv_mips);
+		if (tmp >= 480000000)
+			tmp = 0x1846b; /* set CDR to 0x11(fast) */
+		else if (tmp == 453000000)
+			tmp = 0x1046b; /* set CDR to 0x10(slow) */
+		else
+			tmp = 0;
+
+		/* Change Shim mdio control reg to fix host not acking at
+		 * high frequencies
+		 */
+		if (tmp) {
+			bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
+			udelay(500);
+
+			bcma_write32(dev, 0x524, tmp);
+			udelay(500);
+			bcma_write32(dev, 0x524, 0x4ab);
+			udelay(500);
+			bcma_read32(dev, 0x528);
+			bcma_write32(dev, 0x528, 0x80000000);
+		}
+	}
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+}
+
+/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
+static void __devinit bcma_hcd_init_chip(struct bcma_device *dev)
+{
+	u32 tmp;
+
+	/*
+	 * USB 2.0 special considerations:
+	 *
+	 * 1. Since the core supports both OHCI and EHCI functions, it must
+	 *    only be reset once.
+	 *
+	 * 2. In addition to the standard SI reset sequence, the Host Control
+	 *    Register must be programmed to bring the USB core and various
+	 *    phy components out of reset.
+	 */
+	if (!bcma_core_is_enabled(dev)) {
+		bcma_core_enable(dev, 0);
+		mdelay(10);
+		if (dev->id.rev >= 5) {
+			/* Enable Misc PLL */
+			tmp = bcma_read32(dev, 0x1e0);
+			tmp |= 0x100;
+			bcma_write32(dev, 0x1e0, tmp);
+			if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100))
+				printk(KERN_EMERG "Failed to enable misc PPL!\n");
+
+			/* Take out of resets */
+			bcma_write32(dev, 0x200, 0x4ff);
+			udelay(25);
+			bcma_write32(dev, 0x200, 0x6ff);
+			udelay(25);
+
+			/* Make sure digital and AFE are locked in USB PHY */
+			bcma_write32(dev, 0x524, 0x6b);
+			udelay(50);
+			tmp = bcma_read32(dev, 0x524);
+			udelay(50);
+			bcma_write32(dev, 0x524, 0xab);
+			udelay(50);
+			tmp = bcma_read32(dev, 0x524);
+			udelay(50);
+			bcma_write32(dev, 0x524, 0x2b);
+			udelay(50);
+			tmp = bcma_read32(dev, 0x524);
+			udelay(50);
+			bcma_write32(dev, 0x524, 0x10ab);
+			udelay(50);
+			tmp = bcma_read32(dev, 0x524);
+
+			if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
+				tmp = bcma_read32(dev, 0x528);
+				printk(KERN_EMERG
+				       "USB20H mdio_rddata 0x%08x\n", tmp);
+			}
+			bcma_write32(dev, 0x528, 0x80000000);
+			tmp = bcma_read32(dev, 0x314);
+			udelay(265);
+			bcma_write32(dev, 0x200, 0x7ff);
+			udelay(10);
+
+			/* Take USB and HSIC out of non-driving modes */
+			bcma_write32(dev, 0x510, 0);
+		} else {
+			bcma_write32(dev, 0x200, 0x7ff);
+
+			udelay(1);
+		}
+
+		bcma_hcd_4716wa(dev);
+	}
+}
+
+static const struct usb_ehci_pdata ehci_pdata = {
+};
+
+static const struct usb_ohci_pdata ohci_pdata = {
+};
+
+static struct platform_device * __devinit
+bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr)
+{
+	struct platform_device *hci_dev;
+	struct resource hci_res[2];
+	int ret = -ENOMEM;
+
+	memset(hci_res, 0, sizeof(hci_res));
+
+	hci_res[0].start = addr;
+	hci_res[0].end = hci_res[0].start + 0x1000 - 1;
+	hci_res[0].flags = IORESOURCE_MEM;
+
+	hci_res[1].start = dev->irq;
+	hci_res[1].flags = IORESOURCE_IRQ;
+
+	hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
+					"ehci-platform" , 0);
+	if (!hci_dev)
+		return NULL;
+
+	hci_dev->dev.parent = &dev->dev;
+	hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
+
+	ret = platform_device_add_resources(hci_dev, hci_res,
+					    ARRAY_SIZE(hci_res));
+	if (ret)
+		goto err_alloc;
+	if (ohci)
+		ret = platform_device_add_data(hci_dev, &ohci_pdata,
+					       sizeof(ohci_pdata));
+	else
+		ret = platform_device_add_data(hci_dev, &ehci_pdata,
+					       sizeof(ehci_pdata));
+	if (ret)
+		goto err_alloc;
+	ret = platform_device_add(hci_dev);
+	if (ret)
+		goto err_alloc;
+
+	return hci_dev;
+
+err_alloc:
+	platform_device_put(hci_dev);
+	return ERR_PTR(ret);
+}
+
+static int __devinit bcma_hcd_probe(struct bcma_device *dev)
+{
+	int err;
+	u16 chipid_top;
+	u32 ohci_addr;
+	struct bcma_hcd_device *usb_dev;
+	struct bcma_chipinfo *chipinfo;
+
+	chipinfo = &dev->bus->chipinfo;
+	/* USBcores are only connected on embedded devices. */
+	chipid_top = (chipinfo->id & 0xFF00);
+	if (chipid_top != 0x4700 && chipid_top != 0x5300)
+		return -ENODEV;
+
+	/* TODO: Probably need checks here; is the core connected? */
+
+	if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
+	    dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
+		return -EOPNOTSUPP;
+
+	usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL);
+	if (!usb_dev)
+		return -ENOMEM;
+
+	bcma_hcd_init_chip(dev);
+
+	/* In AI chips EHCI is addrspace 0, OHCI is 1 */
+	ohci_addr = dev->addr1;
+	if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749)
+	    && chipinfo->rev == 0)
+		ohci_addr = 0x18009000;
+
+	usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr);
+	if (IS_ERR(usb_dev->ohci_dev)) {
+		err = PTR_ERR(usb_dev->ohci_dev);
+		goto err_free_usb_dev;
+	}
+
+	usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr);
+	if (IS_ERR(usb_dev->ehci_dev)) {
+		err = PTR_ERR(usb_dev->ehci_dev);
+		goto err_unregister_ohci_dev;
+	}
+
+	bcma_set_drvdata(dev, usb_dev);
+	return 0;
+
+err_unregister_ohci_dev:
+	platform_device_unregister(usb_dev->ohci_dev);
+err_free_usb_dev:
+	kfree(usb_dev);
+	return err;
+}
+
+static void __devexit bcma_hcd_remove(struct bcma_device *dev)
+{
+	struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
+	struct platform_device *ohci_dev = usb_dev->ohci_dev;
+	struct platform_device *ehci_dev = usb_dev->ehci_dev;
+
+	if (ohci_dev)
+		platform_device_unregister(ohci_dev);
+	if (ehci_dev)
+		platform_device_unregister(ehci_dev);
+
+	bcma_core_disable(dev, 0);
+}
+
+static void bcma_hcd_shutdown(struct bcma_device *dev)
+{
+	bcma_core_disable(dev, 0);
+}
+
+#ifdef CONFIG_PM
+
+static int bcma_hcd_suspend(struct bcma_device *dev)
+{
+	bcma_core_disable(dev, 0);
+
+	return 0;
+}
+
+static int bcma_hcd_resume(struct bcma_device *dev)
+{
+	bcma_core_enable(dev, 0);
+
+	return 0;
+}
+
+#else /* !CONFIG_PM */
+#define bcma_hcd_suspend	NULL
+#define bcma_hcd_resume	NULL
+#endif /* CONFIG_PM */
+
+static const struct bcma_device_id bcma_hcd_table[] __devinitconst = {
+	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
+	BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
+
+static struct bcma_driver bcma_hcd_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= bcma_hcd_table,
+	.probe		= bcma_hcd_probe,
+	.remove		= __devexit_p(bcma_hcd_remove),
+	.shutdown	= bcma_hcd_shutdown,
+	.suspend	= bcma_hcd_suspend,
+	.resume		= bcma_hcd_resume,
+};
+
+static int __init bcma_hcd_init(void)
+{
+	return bcma_driver_register(&bcma_hcd_driver);
+}
+module_init(bcma_hcd_init);
+
+static void __exit bcma_hcd_exit(void)
+{
+	bcma_driver_unregister(&bcma_hcd_driver);
+}
+module_exit(bcma_hcd_exit);
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 680e1a3..7561966 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -1025,10 +1025,8 @@
 		if (strict_strtoul(buf + 5, 16, &hird))
 			return -EINVAL;
 		printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird);
-		temp = ehci_readl(ehci, &ehci->regs->command);
-		temp &= ~CMD_HIRD;
-		temp |= hird << 24;
-		ehci_writel(ehci, temp, &ehci->regs->command);
+		ehci->command = (ehci->command & ~CMD_HIRD) | (hird << 24);
+		ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	} else if (strncmp(buf, "disable", 7) == 0) {
 		if (strict_strtoul(buf + 8, 10, &port))
 			return -EINVAL;
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index d0a84bd..4336257 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005-2009 MontaVista Software, Inc.
- * Copyright 2008      Freescale Semiconductor, Inc.
+ * Copyright 2008,2012      Freescale Semiconductor, Inc.
  *
  * 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
@@ -150,8 +150,7 @@
 			retval = otg_set_host(ehci->transceiver->otg,
 					      &ehci_to_hcd(ehci)->self);
 			if (retval) {
-				if (ehci->transceiver)
-					put_device(ehci->transceiver->dev);
+				usb_put_transceiver(ehci->transceiver);
 				goto err4;
 			}
 		} else {
@@ -195,7 +194,7 @@
 
 	if (ehci->transceiver) {
 		otg_set_host(ehci->transceiver->otg, NULL);
-		put_device(ehci->transceiver->dev);
+		usb_put_transceiver(ehci->transceiver);
 	}
 
 	usb_remove_hcd(hcd);
@@ -211,22 +210,32 @@
 	usb_put_hcd(hcd);
 }
 
-static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
+static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
 			       enum fsl_usb2_phy_modes phy_mode,
 			       unsigned int port_offset)
 {
-	u32 portsc;
-	struct usb_hcd *hcd = ehci_to_hcd(ehci);
+	u32 portsc, temp;
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	void __iomem *non_ehci = hcd->regs;
-	struct fsl_usb2_platform_data *pdata;
+	struct device *dev = hcd->self.controller;
+	struct fsl_usb2_platform_data *pdata = dev->platform_data;
 
-	pdata = hcd->self.controller->platform_data;
+	if (pdata->controller_ver < 0) {
+		dev_warn(hcd->self.controller, "Could not get controller version\n");
+		return;
+	}
 
 	portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
 	portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
 
 	switch (phy_mode) {
 	case FSL_USB2_PHY_ULPI:
+		if (pdata->controller_ver) {
+			/* controller version 1.6 or above */
+			temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+			out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
+				USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL);
+		}
 		portsc |= PORT_PTS_ULPI;
 		break;
 	case FSL_USB2_PHY_SERIAL:
@@ -236,6 +245,14 @@
 		portsc |= PORT_PTS_PTW;
 		/* fall through */
 	case FSL_USB2_PHY_UTMI:
+		if (pdata->controller_ver) {
+			/* controller version 1.6 or above */
+			temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+			out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
+				UTMI_PHY_EN | USB_CTRL_USB_EN);
+			mdelay(FSL_UTMI_PHY_DLY);  /* Delay for UTMI PHY CLK to
+						become stable - 10ms*/
+		}
 		/* enable UTMI PHY */
 		if (pdata->have_sysif_regs)
 			setbits32(non_ehci + FSL_SOC_USB_CTRL,
@@ -276,7 +293,7 @@
 
 	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
 			(pdata->operating_mode == FSL_USB2_DR_OTG))
-		ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
+		ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
 
 	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
 		unsigned int chip, rev, svr;
@@ -290,9 +307,9 @@
 			ehci->has_fsl_port_bug = 1;
 
 		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
+			ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
 		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
+			ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1);
 	}
 
 	if (pdata->have_sysif_regs) {
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index 863fb0c..8840368 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc.
+/* Copyright (C) 2005-2010,2012 Freescale Semiconductor, Inc.
  * Copyright (c) 2005 MontaVista Software
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -50,4 +50,15 @@
 #define CTRL_UTMI_PHY_EN	(1<<9)
 #define CTRL_PHY_CLK_VALID	(1 << 17)
 #define SNOOP_SIZE_2GB		0x1e
+
+/* control Register Bit Masks */
+#define ULPI_INT_EN             (1<<0)
+#define WU_INT_EN               (1<<1)
+#define USB_CTRL_USB_EN         (1<<2)
+#define LINE_STATE_FILTER__EN   (1<<3)
+#define KEEP_OTG_ON             (1<<4)
+#define OTG_PORT                (1<<5)
+#define PLL_RESET               (1<<8)
+#define UTMI_PHY_EN             (1<<9)
+#define ULPI_PHY_CLK_SEL        (1<<10)
 #endif				/* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 4a3bc5b..b100f5f 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -226,8 +226,13 @@
 	if ((temp & STS_HALT) != 0)
 		return 0;
 
+	/*
+	 * This routine gets called during probe before ehci->command
+	 * has been initialized, so we can't rely on its value.
+	 */
+	ehci->command &= ~CMD_RUN;
 	temp = ehci_readl(ehci, &ehci->regs->command);
-	temp &= ~CMD_RUN;
+	temp &= ~(CMD_RUN | CMD_IAAD);
 	ehci_writel(ehci, temp, &ehci->regs->command);
 	return handshake (ehci, &ehci->regs->status,
 			  STS_HALT, STS_HALT, 16 * 125);
@@ -363,16 +368,14 @@
 #endif
 
 	/* wait for any schedule enables/disables to take effect */
-	temp = ehci_readl(ehci, &ehci->regs->command) << 10;
-	temp &= STS_ASS | STS_PSS;
+	temp = (ehci->command << 10) & (STS_ASS | STS_PSS);
 	if (handshake_on_error_set_halt(ehci, &ehci->regs->status,
 					STS_ASS | STS_PSS, temp, 16 * 125))
 		return;
 
 	/* then disable anything that's still active */
-	temp = ehci_readl(ehci, &ehci->regs->command);
-	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
-	ehci_writel(ehci, temp, &ehci->regs->command);
+	ehci->command &= ~(CMD_ASE | CMD_PSE);
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 
 	/* hardware can take 16 microframes to turn off ... */
 	handshake_on_error_set_halt(ehci, &ehci->regs->status,
@@ -417,9 +420,6 @@
 		 * CMD_IAAD when it sets STS_IAA.)
 		 */
 		cmd = ehci_readl(ehci, &ehci->regs->command);
-		if (cmd & CMD_IAAD)
-			ehci_writel(ehci, cmd & ~CMD_IAAD,
-					&ehci->regs->command);
 
 		/* If IAA is set here it either legitimately triggered
 		 * before we cleared IAAD above (but _way_ late, so we'll
@@ -894,11 +894,8 @@
 	/* complete the unlinking of some qh [4.15.2.3] */
 	if (status & STS_IAA) {
 		/* guard against (alleged) silicon errata */
-		if (cmd & CMD_IAAD) {
-			ehci_writel(ehci, cmd & ~CMD_IAAD,
-					&ehci->regs->command);
+		if (cmd & CMD_IAAD)
 			ehci_dbg(ehci, "IAA with IAAD still set?\n");
-		}
 		if (ehci->reclaim) {
 			COUNT(ehci->stats.reclaim);
 			end_unlink_async(ehci);
@@ -1248,6 +1245,13 @@
 }
 
 /*-------------------------------------------------------------------------*/
+/*
+ * The EHCI in ChipIdea HDRC cannot be a separate module or device,
+ * because its registers (and irq) are shared between host/gadget/otg
+ * functions  and in order to facilitate role switching we cannot
+ * give the ehci driver exclusive access to those.
+ */
+#ifndef CHIPIDEA_EHCI
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -1378,6 +1382,11 @@
 #define PLATFORM_DRIVER		ehci_ls1x_driver
 #endif
 
+#ifdef CONFIG_MIPS_SEAD3
+#include "ehci-sead3.c"
+#define	PLATFORM_DRIVER		ehci_hcd_sead3_driver
+#endif
+
 #ifdef CONFIG_USB_EHCI_HCD_PLATFORM
 #include "ehci-platform.c"
 #define PLATFORM_DRIVER		ehci_platform_driver
@@ -1501,3 +1510,4 @@
 }
 module_exit(ehci_hcd_cleanup);
 
+#endif /* CHIPIDEA_EHCI */
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 38fe076..fc9e7cc 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -233,7 +233,6 @@
 	/* stop schedules, clean any completed work */
 	if (ehci->rh_state == EHCI_RH_RUNNING)
 		ehci_quiesce (ehci);
-	ehci->command = ehci_readl(ehci, &ehci->regs->command);
 	ehci_work(ehci);
 
 	/* Unlike other USB host controller types, EHCI doesn't have
@@ -374,6 +373,7 @@
 	ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
 
 	/* restore CMD_RUN, framelist size, and irq threshold */
+	ehci->command |= CMD_RUN;
 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	ehci->rh_state = EHCI_RH_RUNNING;
 
@@ -531,7 +531,8 @@
 		if (ehci->has_amcc_usb23)
 			set_ohci_hcfs(ehci, 1);
 	} else {
-		ehci_dbg (ehci, "port %d high speed\n", index + 1);
+		ehci_dbg(ehci, "port %d reset complete, port enabled\n",
+			index + 1);
 		/* ensure 440EPx ohci controller state is suspended */
 		if (ehci->has_amcc_usb23)
 			set_ohci_hcfs(ehci, 0);
@@ -699,6 +700,7 @@
 			goto error;
 		wIndex--;
 		temp = ehci_readl(ehci, status_reg);
+		temp &= ~PORT_RWC_BITS;
 
 		/*
 		 * Even if OWNER is set, so the port is owned by the
@@ -712,8 +714,7 @@
 			ehci_writel(ehci, temp & ~PORT_PE, status_reg);
 			break;
 		case USB_PORT_FEAT_C_ENABLE:
-			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
-					status_reg);
+			ehci_writel(ehci, temp | PORT_PEC, status_reg);
 			break;
 		case USB_PORT_FEAT_SUSPEND:
 			if (temp & PORT_RESET)
@@ -742,7 +743,7 @@
 				spin_lock_irqsave(&ehci->lock, flags);
 			}
 			/* resume signaling for 20 msec */
-			temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+			temp &= ~PORT_WAKE_BITS;
 			ehci_writel(ehci, temp | PORT_RESUME, status_reg);
 			ehci->reset_done[wIndex] = jiffies
 					+ msecs_to_jiffies(20);
@@ -752,9 +753,8 @@
 			break;
 		case USB_PORT_FEAT_POWER:
 			if (HCS_PPC (ehci->hcs_params))
-				ehci_writel(ehci,
-					  temp & ~(PORT_RWC_BITS | PORT_POWER),
-					  status_reg);
+				ehci_writel(ehci, temp & ~PORT_POWER,
+						status_reg);
 			break;
 		case USB_PORT_FEAT_C_CONNECTION:
 			if (ehci->has_lpm) {
@@ -762,12 +762,10 @@
 				temp &= ~PORT_LPM;
 				temp &= ~PORT_DEV_ADDR;
 			}
-			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
-					status_reg);
+			ehci_writel(ehci, temp | PORT_CSC, status_reg);
 			break;
 		case USB_PORT_FEAT_C_OVER_CURRENT:
-			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
-					status_reg);
+			ehci_writel(ehci, temp | PORT_OCC, status_reg);
 			break;
 		case USB_PORT_FEAT_C_RESET:
 			/* GetPortStatus clears reset */
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 5c78f9e..a44294d 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -242,6 +242,19 @@
 
 	ehci_reset(omap_ehci);
 
+	if (pdata->phy_reset) {
+		/* Hold the PHY in RESET for enough time till
+		 * PHY is settled and ready
+		 */
+		udelay(10);
+
+		if (gpio_is_valid(pdata->reset_gpio_port[0]))
+			gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
+
+		if (gpio_is_valid(pdata->reset_gpio_port[1]))
+			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
+	}
+
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret) {
 		dev_err(dev, "failed to add hcd with err %d\n", ret);
@@ -251,19 +264,6 @@
 	/* root ports should always stay powered */
 	ehci_port_power(omap_ehci, 1);
 
-	if (pdata->phy_reset) {
-		/* Hold the PHY in RESET for enough time till
-		 * PHY is settled and ready
-		 */
-		udelay(10);
-
-		if (gpio_is_valid(pdata->reset_gpio_port[0]))
-			gpio_set_value(pdata->reset_gpio_port[0], 1);
-
-		if (gpio_is_valid(pdata->reset_gpio_port[1]))
-			gpio_set_value(pdata->reset_gpio_port[1], 1);
-	}
-
 	return 0;
 
 err_add_hcd:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index fe8dc06..bc94d7b 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -368,7 +368,9 @@
 {
 	return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
 		pdev->vendor == PCI_VENDOR_ID_INTEL &&
-		pdev->device == 0x1E26;
+		(pdev->device == 0x1E26 ||
+		 pdev->device == 0x8C2D ||
+		 pdev->device == 0x8C26);
 }
 
 static void ehci_enable_xhci_companion(void)
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index d238b4e2..dfe881a 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -75,8 +75,6 @@
 	.relinquish_port	= ehci_relinquish_port,
 	.port_handed_over	= ehci_port_handed_over,
 
-	.update_device		= ehci_update_device,
-
 	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
 };
 
@@ -94,12 +92,12 @@
 
 	irq = platform_get_irq(dev, 0);
 	if (irq < 0) {
-		pr_err("no irq provieded");
+		pr_err("no irq provided");
 		return irq;
 	}
 	res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	if (!res_mem) {
-		pr_err("no memory recourse provieded");
+		pr_err("no memory recourse provided");
 		return -ENXIO;
 	}
 
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 36ca507..4378bf7 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -943,7 +943,8 @@
 		}
 		break;
 	default:
-		dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+		ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev,
+			urb->dev->speed);
 done:
 		qh_put (qh);
 		return NULL;
@@ -981,14 +982,12 @@
 	head = ehci->async;
 	timer_action_done (ehci, TIMER_ASYNC_OFF);
 	if (!head->qh_next.qh) {
-		u32	cmd = ehci_readl(ehci, &ehci->regs->command);
-
-		if (!(cmd & CMD_ASE)) {
+		if (!(ehci->command & CMD_ASE)) {
 			/* in case a clear of CMD_ASE didn't take yet */
 			(void)handshake(ehci, &ehci->regs->status,
 					STS_ASS, 0, 150);
-			cmd |= CMD_ASE;
-			ehci_writel(ehci, cmd, &ehci->regs->command);
+			ehci->command |= CMD_ASE;
+			ehci_writel(ehci, ehci->command, &ehci->regs->command);
 			/* posted write need not be known to HC yet ... */
 		}
 	}
@@ -1204,7 +1203,6 @@
 
 static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-	int		cmd = ehci_readl(ehci, &ehci->regs->command);
 	struct ehci_qh	*prev;
 
 #ifdef DEBUG
@@ -1222,8 +1220,8 @@
 		if (ehci->rh_state != EHCI_RH_HALTED
 				&& !ehci->reclaim) {
 			/* ... and CMD_IAAD clear */
-			ehci_writel(ehci, cmd & ~CMD_ASE,
-				    &ehci->regs->command);
+			ehci->command &= ~CMD_ASE;
+			ehci_writel(ehci, ehci->command, &ehci->regs->command);
 			wmb ();
 			// handshake later, if we need to
 			timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1253,8 +1251,7 @@
 		return;
 	}
 
-	cmd |= CMD_IAAD;
-	ehci_writel(ehci, cmd, &ehci->regs->command);
+	ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command);
 	(void)ehci_readl(ehci, &ehci->regs->command);
 	iaa_watchdog_start(ehci);
 }
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index f098e2a..c474cec 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -232,6 +232,8 @@
 	if (pdata && pdata->phy_exit)
 		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
 
+	clk_disable(s5p_ehci->clk);
+
 	return rc;
 }
 
@@ -243,6 +245,8 @@
 	struct platform_device *pdev = to_platform_device(dev);
 	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
 
+	clk_enable(s5p_ehci->clk);
+
 	if (pdata && pdata->phy_init)
 		pdata->phy_init(pdev, S5P_USB_PHY_HOST);
 
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index a60679c..33182c6 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -481,7 +481,6 @@
 
 static int enable_periodic (struct ehci_hcd *ehci)
 {
-	u32	cmd;
 	int	status;
 
 	if (ehci->periodic_sched++)
@@ -497,8 +496,8 @@
 		return status;
 	}
 
-	cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
-	ehci_writel(ehci, cmd, &ehci->regs->command);
+	ehci->command |= CMD_PSE;
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	/* posted write ... PSS happens later */
 
 	/* make sure ehci_work scans these */
@@ -511,7 +510,6 @@
 
 static int disable_periodic (struct ehci_hcd *ehci)
 {
-	u32	cmd;
 	int	status;
 
 	if (--ehci->periodic_sched)
@@ -537,8 +535,8 @@
 		return status;
 	}
 
-	cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
-	ehci_writel(ehci, cmd, &ehci->regs->command);
+	ehci->command &= ~CMD_PSE;
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	/* posted write ... */
 
 	free_cached_lists(ehci);
@@ -1333,34 +1331,36 @@
 	if (mask & ~0xffff)
 		return 0;
 
+	/* check bandwidth */
+	uframe %= period_uframes;
+	frame = uframe >> 3;
+
+#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
+	/* The tt's fullspeed bus bandwidth must be available.
+	 * tt_available scheduling guarantees 10+% for control/bulk.
+	 */
+	uf = uframe & 7;
+	if (!tt_available(ehci, period_uframes >> 3,
+			stream->udev, frame, uf, stream->tt_usecs))
+		return 0;
+#else
+	/* tt must be idle for start(s), any gap, and csplit.
+	 * assume scheduling slop leaves 10+% for control/bulk.
+	 */
+	if (!tt_no_collision(ehci, period_uframes >> 3,
+			stream->udev, frame, mask))
+		return 0;
+#endif
+
 	/* this multi-pass logic is simple, but performance may
 	 * suffer when the schedule data isn't cached.
 	 */
-
-	/* check bandwidth */
-	uframe %= period_uframes;
 	do {
 		u32		max_used;
 
 		frame = uframe >> 3;
 		uf = uframe & 7;
 
-#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
-		/* The tt's fullspeed bus bandwidth must be available.
-		 * tt_available scheduling guarantees 10+% for control/bulk.
-		 */
-		if (!tt_available (ehci, period_uframes << 3,
-				stream->udev, frame, uf, stream->tt_usecs))
-			return 0;
-#else
-		/* tt must be idle for start(s), any gap, and csplit.
-		 * assume scheduling slop leaves 10+% for control/bulk.
-		 */
-		if (!tt_no_collision (ehci, period_uframes << 3,
-				stream->udev, frame, mask))
-			return 0;
-#endif
-
 		/* check starts (OUT uses more than one) */
 		max_used = ehci->uframe_periodic_max - stream->usecs;
 		for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
@@ -2358,7 +2358,8 @@
 				 * in the previous frame for completions.
 				 */
 				if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) {
-					dbg ("ignoring completions from FSTNs");
+					ehci_dbg(ehci,
+						"ignoring completions from FSTNs\n");
 				}
 				type = Q_NEXT_TYPE(ehci, q.fstn->hw_next);
 				q = q.fstn->fstn_next;
@@ -2441,7 +2442,7 @@
 				q = *q_p;
 				break;
 			default:
-				dbg ("corrupt type %d frame %d shadow %p",
+				ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n",
 					type, frame, q.ptr);
 				// BUG ();
 				q.ptr = NULL;
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
new file mode 100644
index 0000000..cc199e8
--- /dev/null
+++ b/drivers/usb/host/ehci-sead3.c
@@ -0,0 +1,266 @@
+/*
+ * MIPS CI13320A EHCI Host Controller driver
+ * Based on "ehci-au1xxx.c" by K.Boge <karsten.boge@amd.com>
+ *
+ * Copyright (C) 2012 MIPS Technologies, Inc.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/platform_device.h>
+
+static int ehci_sead3_setup(struct usb_hcd *hcd)
+{
+	int ret;
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+	ehci->caps = hcd->regs + 0x100;
+
+#ifdef __BIG_ENDIAN
+	ehci->big_endian_mmio = 1;
+	ehci->big_endian_desc = 1;
+#endif
+
+	ret = ehci_setup(hcd);
+	if (ret)
+		return ret;
+
+	ehci->need_io_watchdog = 0;
+
+	/* Set burst length to 16 words. */
+	ehci_writel(ehci, 0x1010, &ehci->regs->reserved[1]);
+
+	return ret;
+}
+
+const struct hc_driver ehci_sead3_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "SEAD-3 EHCI",
+	.hcd_priv_size		= sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq			= ehci_irq,
+	.flags			= HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 *
+	 */
+	.reset			= ehci_sead3_setup,
+	.start			= ehci_run,
+	.stop			= ehci_stop,
+	.shutdown		= ehci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.endpoint_reset		= ehci_endpoint_reset,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number	= ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+	.bus_suspend		= ehci_bus_suspend,
+	.bus_resume		= ehci_bus_resume,
+	.relinquish_port	= ehci_relinquish_port,
+	.port_handed_over	= ehci_port_handed_over,
+
+	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd;
+	struct resource *res;
+	int ret;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug("resource[1] is not IORESOURCE_IRQ");
+		return -ENOMEM;
+	}
+	hcd = usb_create_hcd(&ehci_sead3_hc_driver, &pdev->dev, "SEAD-3");
+	if (!hcd)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		ret = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	/* Root hub has integrated TT. */
+	hcd->has_tt = 1;
+
+	ret = usb_add_hcd(hcd, pdev->resource[1].start,
+			  IRQF_SHARED);
+	if (ret == 0) {
+		platform_set_drvdata(pdev, hcd);
+		return ret;
+	}
+
+	iounmap(hcd->regs);
+err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+	usb_put_hcd(hcd);
+	return ret;
+}
+
+static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ehci_hcd_sead3_drv_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	unsigned long flags;
+	int rc = 0;
+
+	if (time_before(jiffies, ehci->next_statechange))
+		msleep(20);
+
+	/* Root hub was already suspended. Disable irq emission and
+	 * mark HW unaccessible.  The PM and USB cores make sure that
+	 * the root hub is either suspended or stopped.
+	 */
+	ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
+	spin_lock_irqsave(&ehci->lock, flags);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
+
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	spin_unlock_irqrestore(&ehci->lock, flags);
+
+	/* could save FLADJ in case of Vaux power loss
+	 * ... we'd only use it to handle clock skew
+	 */
+
+	return rc;
+}
+
+static int ehci_hcd_sead3_drv_resume(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+	/* maybe restore FLADJ. */
+
+	if (time_before(jiffies, ehci->next_statechange))
+		msleep(100);
+
+	/* Mark hardware accessible again as we are out of D3 state by now */
+	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+	/* If CF is still set, we maintained PCI Vaux power.
+	 * Just undo the effect of ehci_pci_suspend().
+	 */
+	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
+		int	mask = INTR_MASK;
+
+		ehci_prepare_ports_for_controller_resume(ehci);
+		if (!hcd->self.root_hub->do_remote_wakeup)
+			mask &= ~STS_PCD;
+		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+		ehci_readl(ehci, &ehci->regs->intr_enable);
+		return 0;
+	}
+
+	ehci_dbg(ehci, "lost power, restarting\n");
+	usb_root_hub_lost_power(hcd->self.root_hub);
+
+	/* Else reset, to cope with power loss or flush-to-storage
+	 * style "resume" having let BIOS kick in during reboot.
+	 */
+	(void) ehci_halt(ehci);
+	(void) ehci_reset(ehci);
+
+	/* emptying the schedule aborts any urbs */
+	spin_lock_irq(&ehci->lock);
+	if (ehci->reclaim)
+		end_unlink_async(ehci);
+	ehci_work(ehci);
+	spin_unlock_irq(&ehci->lock);
+
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
+
+	/* here we "know" root ports should always stay powered */
+	ehci_port_power(ehci, 1);
+
+	ehci->rh_state = EHCI_RH_SUSPENDED;
+
+	return 0;
+}
+
+static const struct dev_pm_ops sead3_ehci_pmops = {
+	.suspend	= ehci_hcd_sead3_drv_suspend,
+	.resume		= ehci_hcd_sead3_drv_resume,
+};
+
+#define SEAD3_EHCI_PMOPS (&sead3_ehci_pmops)
+
+#else
+#define SEAD3_EHCI_PMOPS NULL
+#endif
+
+static struct platform_driver ehci_hcd_sead3_driver = {
+	.probe		= ehci_hcd_sead3_drv_probe,
+	.remove		= ehci_hcd_sead3_drv_remove,
+	.shutdown	= usb_hcd_platform_shutdown,
+	.driver = {
+		.name	= "sead3-ehci",
+		.owner	= THIS_MODULE,
+		.pm	= SEAD3_EHCI_PMOPS,
+	}
+};
+
+MODULE_ALIAS("platform:sead3-ehci");
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 9d9cf47..ca819cd 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -11,6 +11,7 @@
  */
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/platform_data/ehci-sh.h>
 
 struct ehci_sh_priv {
 	struct clk *iclk, *fclk;
@@ -100,6 +101,7 @@
 	const struct hc_driver *driver = &ehci_sh_hc_driver;
 	struct resource *res;
 	struct ehci_sh_priv *priv;
+	struct ehci_sh_platdata *pdata;
 	struct usb_hcd *hcd;
 	int irq, ret;
 
@@ -124,6 +126,9 @@
 		goto fail_create_hcd;
 	}
 
+	if (pdev->dev.platform_data != NULL)
+		pdata = pdev->dev.platform_data;
+
 	/* initialize hcd */
 	hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev,
 			     dev_name(&pdev->dev));
@@ -168,6 +173,9 @@
 	clk_enable(priv->fclk);
 	clk_enable(priv->iclk);
 
+	if (pdata && pdata->phy_init)
+		pdata->phy_init();
+
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Failed to add hcd");
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 6e92855..37ba8c8 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -13,6 +13,7 @@
 
 #include <linux/clk.h>
 #include <linux/jiffies.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 
@@ -25,12 +26,12 @@
 
 static void spear_start_ehci(struct spear_ehci *ehci)
 {
-	clk_enable(ehci->clk);
+	clk_prepare_enable(ehci->clk);
 }
 
 static void spear_stop_ehci(struct spear_ehci *ehci)
 {
-	clk_disable(ehci->clk);
+	clk_disable_unprepare(ehci->clk);
 }
 
 static int ehci_spear_setup(struct usb_hcd *hcd)
@@ -168,6 +169,8 @@
 static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
 		ehci_spear_drv_resume);
 
+static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32);
+
 static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd ;
@@ -175,12 +178,9 @@
 	struct resource *res;
 	struct clk *usbh_clk;
 	const struct hc_driver *driver = &ehci_spear_hc_driver;
-	int *pdata = pdev->dev.platform_data;
 	int irq, retval;
 	char clk_name[20] = "usbh_clk";
-
-	if (pdata == NULL)
-		return -EFAULT;
+	static int instance = -1;
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -191,8 +191,22 @@
 		goto fail_irq_get;
 	}
 
-	if (*pdata >= 0)
-		sprintf(clk_name, "usbh.%01d_clk", *pdata);
+	/*
+	 * Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we have dma capability bindings this can go away.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &spear_ehci_dma_mask;
+
+	/*
+	 * Increment the device instance, when probing via device-tree
+	 */
+	if (pdev->id < 0)
+		instance++;
+	else
+		instance = pdev->id;
+	sprintf(clk_name, "usbh.%01d_clk", instance);
 
 	usbh_clk = clk_get(NULL, clk_name);
 	if (IS_ERR(usbh_clk)) {
@@ -277,6 +291,11 @@
 	return 0;
 }
 
+static struct of_device_id spear_ehci_id_table[] __devinitdata = {
+	{ .compatible = "st,spear600-ehci", },
+	{ },
+};
+
 static struct platform_driver spear_ehci_hcd_driver = {
 	.probe		= spear_ehci_hcd_drv_probe,
 	.remove		= spear_ehci_hcd_drv_remove,
@@ -285,6 +304,7 @@
 		.name = "spear-ehci",
 		.bus = &platform_bus_type,
 		.pm = &ehci_spear_pm_ops,
+		.of_match_table = of_match_ptr(spear_ehci_id_table),
 	}
 };
 
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index f214a80..4a44bf8 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -147,18 +147,7 @@
 
 	spin_lock_irqsave(&ehci->lock, flags);
 
-	/*
-	 * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits
-	 * that are write on clear, by writing back the register read value, so
-	 * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits
-	 */
-	if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) {
-		temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS;
-		ehci_writel(ehci, temp & ~PORT_PE, status_reg);
-		goto done;
-	}
-
-	else if (typeReq == GetPortStatus) {
+	if (typeReq == GetPortStatus) {
 		temp = ehci_readl(ehci, status_reg);
 		if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
 			/* Resume completed, re-enable disconnect detection */
@@ -174,7 +163,7 @@
 			goto done;
 		}
 
-		temp &= ~PORT_WKCONN_E;
+		temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E);
 		temp |= PORT_WKDISC_E | PORT_WKOC_E;
 		ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
 
@@ -319,26 +308,23 @@
 	return retval;
 }
 
-struct temp_buffer {
+struct dma_aligned_buffer {
 	void *kmalloc_ptr;
 	void *old_xfer_buffer;
 	u8 data[0];
 };
 
-static void free_temp_buffer(struct urb *urb)
+static void free_dma_aligned_buffer(struct urb *urb)
 {
-	enum dma_data_direction dir;
-	struct temp_buffer *temp;
+	struct dma_aligned_buffer *temp;
 
 	if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
 		return;
 
-	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	temp = container_of(urb->transfer_buffer,
+		struct dma_aligned_buffer, data);
 
-	temp = container_of(urb->transfer_buffer, struct temp_buffer,
-			    data);
-
-	if (dir == DMA_FROM_DEVICE)
+	if (usb_urb_dir_in(urb))
 		memcpy(temp->old_xfer_buffer, temp->data,
 		       urb->transfer_buffer_length);
 	urb->transfer_buffer = temp->old_xfer_buffer;
@@ -347,10 +333,9 @@
 	urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
 }
 
-static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
+static int alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
 {
-	enum dma_data_direction dir;
-	struct temp_buffer *temp, *kmalloc_ptr;
+	struct dma_aligned_buffer *temp, *kmalloc_ptr;
 	size_t kmalloc_size;
 
 	if (urb->num_sgs || urb->sg ||
@@ -358,22 +343,19 @@
 	    !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1)))
 		return 0;
 
-	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
 	/* Allocate a buffer with enough padding for alignment */
 	kmalloc_size = urb->transfer_buffer_length +
-		sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1;
+		sizeof(struct dma_aligned_buffer) + TEGRA_USB_DMA_ALIGN - 1;
 
 	kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
 	if (!kmalloc_ptr)
 		return -ENOMEM;
 
-	/* Position our struct temp_buffer such that data is aligned */
+	/* Position our struct dma_aligned_buffer such that data is aligned */
 	temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1;
-
 	temp->kmalloc_ptr = kmalloc_ptr;
 	temp->old_xfer_buffer = urb->transfer_buffer;
-	if (dir == DMA_TO_DEVICE)
+	if (usb_urb_dir_out(urb))
 		memcpy(temp->data, urb->transfer_buffer,
 		       urb->transfer_buffer_length);
 	urb->transfer_buffer = temp->data;
@@ -388,13 +370,13 @@
 {
 	int ret;
 
-	ret = alloc_temp_buffer(urb, mem_flags);
+	ret = alloc_dma_aligned_buffer(urb, mem_flags);
 	if (ret)
 		return ret;
 
 	ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
 	if (ret)
-		free_temp_buffer(urb);
+		free_dma_aligned_buffer(urb);
 
 	return ret;
 }
@@ -402,49 +384,51 @@
 static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
 {
 	usb_hcd_unmap_urb_for_dma(hcd, urb);
-	free_temp_buffer(urb);
+	free_dma_aligned_buffer(urb);
 }
 
 static const struct hc_driver tegra_ehci_hc_driver = {
 	.description		= hcd_name,
 	.product_desc		= "Tegra EHCI Host Controller",
 	.hcd_priv_size		= sizeof(struct ehci_hcd),
-
 	.flags			= HCD_USB2 | HCD_MEMORY,
 
-	.reset			= tegra_ehci_setup,
+	/* standard ehci functions */
 	.irq			= ehci_irq,
-
 	.start			= ehci_run,
 	.stop			= ehci_stop,
-	.shutdown		= tegra_ehci_shutdown,
 	.urb_enqueue		= ehci_urb_enqueue,
 	.urb_dequeue		= ehci_urb_dequeue,
-	.map_urb_for_dma	= tegra_ehci_map_urb_for_dma,
-	.unmap_urb_for_dma	= tegra_ehci_unmap_urb_for_dma,
 	.endpoint_disable	= ehci_endpoint_disable,
 	.endpoint_reset		= ehci_endpoint_reset,
 	.get_frame_number	= ehci_get_frame,
 	.hub_status_data	= ehci_hub_status_data,
-	.hub_control		= tegra_ehci_hub_control,
 	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+	.relinquish_port	= ehci_relinquish_port,
+	.port_handed_over	= ehci_port_handed_over,
+
+	/* modified ehci functions for tegra */
+	.reset			= tegra_ehci_setup,
+	.shutdown		= tegra_ehci_shutdown,
+	.map_urb_for_dma	= tegra_ehci_map_urb_for_dma,
+	.unmap_urb_for_dma	= tegra_ehci_unmap_urb_for_dma,
+	.hub_control		= tegra_ehci_hub_control,
 #ifdef CONFIG_PM
 	.bus_suspend		= ehci_bus_suspend,
 	.bus_resume		= ehci_bus_resume,
 #endif
-	.relinquish_port	= ehci_relinquish_port,
-	.port_handed_over	= ehci_port_handed_over,
 };
 
-static int setup_vbus_gpio(struct platform_device *pdev)
+static int setup_vbus_gpio(struct platform_device *pdev,
+			   struct tegra_ehci_platform_data *pdata)
 {
 	int err = 0;
 	int gpio;
 
-	if (!pdev->dev.of_node)
-		return 0;
-
-	gpio = of_get_named_gpio(pdev->dev.of_node, "nvidia,vbus-gpio", 0);
+	gpio = pdata->vbus_gpio;
+	if (!gpio_is_valid(gpio))
+		gpio = of_get_named_gpio(pdev->dev.of_node,
+					 "nvidia,vbus-gpio", 0);
 	if (!gpio_is_valid(gpio))
 		return 0;
 
@@ -664,7 +648,7 @@
 	if (!pdev->dev.dma_mask)
 		pdev->dev.dma_mask = &tegra_ehci_dma_mask;
 
-	setup_vbus_gpio(pdev);
+	setup_vbus_gpio(pdev, pdata);
 
 	tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL);
 	if (!tegra)
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c
index 0ea577b..c5ed881 100644
--- a/drivers/usb/host/fhci-tds.c
+++ b/drivers/usb/host/fhci-tds.c
@@ -155,7 +155,7 @@
 	struct endpoint *ep;
 	struct usb_td __iomem *td;
 	unsigned long ep_offset;
-	char *err_for = "enpoint PRAM";
+	char *err_for = "endpoint PRAM";
 	int ep_mem_size;
 	u32 i;
 
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index ab333ac..22ff6b3a 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -119,6 +119,39 @@
 
 static const struct of_device_id fsl_usb2_mph_dr_of_match[];
 
+static int usb_get_ver_info(struct device_node *np)
+{
+	int ver = -1;
+
+	/*
+	 * returns 1 for usb controller version 1.6
+	 * returns 2 for usb controller version 2.2
+	 * returns 0 otherwise
+	 */
+	if (of_device_is_compatible(np, "fsl-usb2-dr")) {
+		if (of_device_is_compatible(np, "fsl-usb2-dr-v1.6"))
+			ver = FSL_USB_VER_1_6;
+		else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2"))
+			ver = FSL_USB_VER_2_2;
+		else /* for previous controller versions */
+			ver = FSL_USB_VER_OLD;
+
+		if (ver > -1)
+			return ver;
+	}
+
+	if (of_device_is_compatible(np, "fsl-usb2-mph")) {
+		if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6"))
+			ver = FSL_USB_VER_1_6;
+		else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2"))
+			ver = FSL_USB_VER_2_2;
+		else /* for previous controller versions */
+			ver = FSL_USB_VER_OLD;
+	}
+
+	return ver;
+}
+
 static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -166,6 +199,14 @@
 
 	prop = of_get_property(np, "phy_type", NULL);
 	pdata->phy_mode = determine_usb_phy(prop);
+	pdata->controller_ver = usb_get_ver_info(np);
+
+	if (pdata->have_sysif_regs) {
+		if (pdata->controller_ver < 0) {
+			dev_warn(&ofdev->dev, "Could not get controller version\n");
+			return -ENODEV;
+		}
+	}
 
 	for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
 		if (!dev_data->drivers[i])
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index fc72d44..a35bbdd 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -1562,11 +1562,14 @@
 
 	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
 		retval = -ESHUTDOWN;
+		qtd_list_free(&new_qtds);
 		goto out;
 	}
 	retval = usb_hcd_link_urb_to_ep(hcd, urb);
-	if (retval)
+	if (retval) {
+		qtd_list_free(&new_qtds);
 		goto out;
+	}
 
 	qh = urb->ep->hcpriv;
 	if (qh) {
@@ -1584,6 +1587,7 @@
 		if (!qh) {
 			retval = -ENOMEM;
 			usb_hcd_unlink_urb_from_ep(hcd, urb);
+			qtd_list_free(&new_qtds);
 			goto out;
 		}
 		list_add_tail(&qh->qh_list, ep_queue);
@@ -1683,6 +1687,7 @@
 	list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
 		if (qtd->urb == urb) {
 			dequeue_urb_from_qtd(hcd, qh, qtd);
+			list_move(&qtd->qtd_list, &qh->qtd_list);
 			break;
 		}
 
@@ -2176,7 +2181,7 @@
 
 int __init init_kmem_once(void)
 {
-	urb_listitem_cachep = kmem_cache_create("isp1760 urb_listitem",
+	urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
 			sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
 			SLAB_MEM_SPREAD, NULL);
 
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 4592dc1..fff114f 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -398,6 +398,9 @@
 	hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
 			       irqflags, -ENOENT,
 			       &pdev->dev, dev_name(&pdev->dev), devflags);
+
+	dev_set_drvdata(&pdev->dev, hcd);
+
 	if (IS_ERR(hcd)) {
 		pr_warning("isp1760: Failed to register the HCD device\n");
 		ret = -ENODEV;
@@ -417,11 +420,16 @@
 {
 	struct resource *mem_res;
 	resource_size_t mem_size;
+	struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
+
+	usb_remove_hcd(hcd);
 
 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	mem_size = resource_size(mem_res);
 	release_mem_region(mem_res->start, mem_size);
 
+	usb_put_hcd(hcd);
+
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 13ebeca..a665b3e 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -129,7 +129,7 @@
 	if (!hcd)
 		return -ENOMEM;
 	hcd->rsrc_start = pdev->resource[0].start;
-	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+	hcd->rsrc_len = resource_size(&pdev->resource[0]);
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 		pr_debug("request_mem_region failed\n");
@@ -223,7 +223,7 @@
 /*-------------------------------------------------------------------------*/
 
 static int __devinit
-ohci_at91_start (struct usb_hcd *hcd)
+ohci_at91_reset (struct usb_hcd *hcd)
 {
 	struct at91_usbh_data	*board = hcd->self.controller->platform_data;
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
@@ -233,9 +233,18 @@
 		return ret;
 
 	ohci->num_ports = board->ports;
+	return 0;
+}
+
+static int __devinit
+ohci_at91_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	int			ret;
 
 	if ((ret = ohci_run(ohci)) < 0) {
-		err("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
@@ -418,6 +427,7 @@
 	/*
 	 * basic lifecycle operations
 	 */
+	.reset =		ohci_at91_reset,
 	.start =		ohci_at91_start,
 	.stop =			ohci_stop,
 	.shutdown =		ohci_shutdown,
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 4ea63b2..c611699 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -37,7 +37,8 @@
 		return ret;
 
 	if ((ret = ohci_run(ohci)) < 0) {
-		err ("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c
index 5a00a1e..2c9f233 100644
--- a/drivers/usb/host/ohci-cns3xxx.c
+++ b/drivers/usb/host/ohci-cns3xxx.c
@@ -41,7 +41,8 @@
 
 	ret = ohci_run(ohci);
 	if (ret < 0) {
-		err("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 8435097..269b1e0 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -454,3 +454,5 @@
 		.name	= "ohci",
 	},
 };
+
+MODULE_ALIAS("platform:ohci");
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index e4bcb62..31b81f9 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -29,14 +29,14 @@
 	unsigned int pipe= urb->pipe;
 
 	if (!urb->dev || !urb->dev->bus) {
-		dbg("%s URB: no dev", str);
+		printk(KERN_DEBUG "%s URB: no dev\n", str);
 		return;
 	}
 
 #ifndef	OHCI_VERBOSE_DEBUG
 	if (status != 0)
 #endif
-	dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
+	printk(KERN_DEBUG "%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d\n",
 		    str,
 		    urb,
 		    usb_pipedevice (pipe),
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 3d63574..dbfbd1d 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -47,7 +47,7 @@
 	struct usb_hcd *hcd;
 
 	if (pdev->resource[1].flags != IORESOURCE_IRQ) {
-		dbg("resource[1] is not IORESOURCE_IRQ");
+		dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n");
 		return -ENOMEM;
 	}
 
@@ -65,14 +65,14 @@
 
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	if (hcd->regs == NULL) {
-		dbg("ioremap failed");
+		dev_dbg(&pdev->dev, "ioremap failed\n");
 		retval = -ENOMEM;
 		goto err2;
 	}
 
 	usb_host_clock = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(usb_host_clock)) {
-		dbg("clk_get failed");
+		dev_dbg(&pdev->dev, "clk_get failed\n");
 		retval = PTR_ERR(usb_host_clock);
 		goto err3;
 	}
@@ -116,7 +116,8 @@
 		return ret;
 
 	if ((ret = ohci_run(ohci)) < 0) {
-		err("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 37bb20e..2909621 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -35,7 +35,8 @@
 
 	ret = ohci_run(ohci);
 	if (ret < 0) {
-		err("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 235171f..e0adf5c 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1080,11 +1080,6 @@
 #define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_driver
 #endif
 
-#ifdef CONFIG_USB_OHCI_HCD_SSB
-#include "ohci-ssb.c"
-#define SSB_OHCI_DRIVER		ssb_ohci_driver
-#endif
-
 #ifdef CONFIG_MFD_SM501
 #include "ohci-sm501.c"
 #define SM501_OHCI_DRIVER	ohci_hcd_sm501_driver
@@ -1128,8 +1123,7 @@
 	!defined(SA1111_DRIVER) &&	\
 	!defined(PS3_SYSTEM_BUS_DRIVER) && \
 	!defined(SM501_OHCI_DRIVER) && \
-	!defined(TMIO_OHCI_DRIVER) && \
-	!defined(SSB_OHCI_DRIVER)
+	!defined(TMIO_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
 
@@ -1195,12 +1189,6 @@
 		goto error_pci;
 #endif
 
-#ifdef SSB_OHCI_DRIVER
-	retval = ssb_driver_register(&SSB_OHCI_DRIVER);
-	if (retval)
-		goto error_ssb;
-#endif
-
 #ifdef SM501_OHCI_DRIVER
 	retval = platform_driver_register(&SM501_OHCI_DRIVER);
 	if (retval < 0)
@@ -1224,10 +1212,6 @@
 	platform_driver_unregister(&SM501_OHCI_DRIVER);
  error_sm501:
 #endif
-#ifdef SSB_OHCI_DRIVER
-	ssb_driver_unregister(&SSB_OHCI_DRIVER);
- error_ssb:
-#endif
 #ifdef PCI_DRIVER
 	pci_unregister_driver(&PCI_DRIVER);
  error_pci:
@@ -1275,9 +1259,6 @@
 #ifdef SM501_OHCI_DRIVER
 	platform_driver_unregister(&SM501_OHCI_DRIVER);
 #endif
-#ifdef SSB_OHCI_DRIVER
-	ssb_driver_unregister(&SSB_OHCI_DRIVER);
-#endif
 #ifdef PCI_DRIVER
 	pci_unregister_driver(&PCI_DRIVER);
 #endif
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index 6618de1..1e364ec 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -22,6 +22,8 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/usb/isp1301.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -29,7 +31,6 @@
 
 #include <mach/platform.h>
 #include <mach/irqs.h>
-#include <asm/gpio.h>
 
 #define USB_CONFIG_BASE		0x31020000
 #define PWRMAN_BASE		0x40004000
@@ -38,7 +39,9 @@
 
 /* USB_CTRL bit defines */
 #define USB_SLAVE_HCLK_EN	(1 << 24)
+#define USB_DEV_NEED_CLK_EN	(1 << 22)
 #define USB_HOST_NEED_CLK_EN	(1 << 21)
+#define PAD_CONTROL_LAST_DRIVEN	(1 << 19)
 
 #define USB_OTG_CLK_CTRL	IO_ADDRESS(USB_CONFIG_BASE + 0xFF4)
 #define USB_OTG_CLK_STAT	IO_ADDRESS(USB_CONFIG_BASE + 0xFF8)
@@ -56,54 +59,6 @@
 #define TRANSPARENT_I2C_EN	(1 << 7)
 #define HOST_EN			(1 << 0)
 
-/* ISP1301 USB transceiver I2C registers */
-#define	ISP1301_MODE_CONTROL_1		0x04	/* u8 read, set, +1 clear */
-
-#define	MC1_SPEED_REG		(1 << 0)
-#define	MC1_SUSPEND_REG		(1 << 1)
-#define	MC1_DAT_SE0		(1 << 2)
-#define	MC1_TRANSPARENT		(1 << 3)
-#define	MC1_BDIS_ACON_EN	(1 << 4)
-#define	MC1_OE_INT_EN		(1 << 5)
-#define	MC1_UART_EN		(1 << 6)
-#define	MC1_MASK		0x7f
-
-#define	ISP1301_MODE_CONTROL_2		0x12	/* u8 read, set, +1 clear */
-
-#define	MC2_GLOBAL_PWR_DN	(1 << 0)
-#define	MC2_SPD_SUSP_CTRL	(1 << 1)
-#define	MC2_BI_DI		(1 << 2)
-#define	MC2_TRANSP_BDIR0	(1 << 3)
-#define	MC2_TRANSP_BDIR1	(1 << 4)
-#define	MC2_AUDIO_EN		(1 << 5)
-#define	MC2_PSW_EN		(1 << 6)
-#define	MC2_EN2V7		(1 << 7)
-
-#define	ISP1301_OTG_CONTROL_1		0x06	/* u8 read, set, +1 clear */
-#	define	OTG1_DP_PULLUP		(1 << 0)
-#	define	OTG1_DM_PULLUP		(1 << 1)
-#	define	OTG1_DP_PULLDOWN	(1 << 2)
-#	define	OTG1_DM_PULLDOWN	(1 << 3)
-#	define	OTG1_ID_PULLDOWN	(1 << 4)
-#	define	OTG1_VBUS_DRV		(1 << 5)
-#	define	OTG1_VBUS_DISCHRG	(1 << 6)
-#	define	OTG1_VBUS_CHRG		(1 << 7)
-#define	ISP1301_OTG_STATUS		0x10	/* u8 readonly */
-#	define	OTG_B_SESS_END		(1 << 6)
-#	define	OTG_B_SESS_VLD		(1 << 7)
-
-#define ISP1301_I2C_ADDR 0x2C
-
-#define ISP1301_I2C_MODE_CONTROL_1 0x4
-#define ISP1301_I2C_MODE_CONTROL_2 0x12
-#define ISP1301_I2C_OTG_CONTROL_1 0x6
-#define ISP1301_I2C_OTG_CONTROL_2 0x10
-#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
-#define ISP1301_I2C_INTERRUPT_LATCH 0xA
-#define ISP1301_I2C_INTERRUPT_FALLING 0xC
-#define ISP1301_I2C_INTERRUPT_RISING 0xE
-#define ISP1301_I2C_REG_CLEAR_ADDR 1
-
 /* On LPC32xx, those are undefined */
 #ifndef start_int_set_falling_edge
 #define start_int_set_falling_edge(irq)
@@ -113,42 +68,12 @@
 #define start_int_umask(irq)
 #endif
 
-static struct i2c_driver isp1301_driver;
 static struct i2c_client *isp1301_i2c_client;
 
 extern int usb_disabled(void);
-extern int ocpi_enable(void);
 
 static struct clk *usb_clk;
 
-static const unsigned short normal_i2c[] =
-    { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
-
-static int isp1301_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
-{
-	return 0;
-}
-
-static int isp1301_remove(struct i2c_client *client)
-{
-	return 0;
-}
-
-static const struct i2c_device_id isp1301_id[] = {
-	{ "isp1301_nxp", 0 },
-	{ }
-};
-
-static struct i2c_driver isp1301_driver = {
-	.driver = {
-		.name = "isp1301_nxp",
-	},
-	.probe = isp1301_probe,
-	.remove = isp1301_remove,
-	.id_table = isp1301_id,
-};
-
 static void isp1301_configure_pnx4008(void)
 {
 	/* PNX4008 only supports DAT_SE0 USB mode */
@@ -220,7 +145,7 @@
 		ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
 
 	/* Enable usb_need_clk clock after transceiver is initialized */
-	__raw_writel((__raw_readl(USB_CTRL) | (1 << 22)), USB_CTRL);
+	__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
 
 	printk(KERN_INFO "ISP1301 Vendor ID  : 0x%04x\n",
 	      i2c_smbus_read_word_data(isp1301_i2c_client, 0x00));
@@ -372,65 +297,55 @@
 	struct usb_hcd *hcd = 0;
 	struct ohci_hcd *ohci;
 	const struct hc_driver *driver = &ohci_nxp_hc_driver;
-	struct i2c_adapter *i2c_adap;
-	struct i2c_board_info i2c_info;
-
+	struct resource *res;
 	int ret = 0, irq;
+	struct device_node *isp1301_node;
 
-	dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
-	if (usb_disabled()) {
-		err("USB is disabled");
-		ret = -ENODEV;
+	if (pdev->dev.of_node) {
+		isp1301_node = of_parse_phandle(pdev->dev.of_node,
+						"transceiver", 0);
+	} else {
+		isp1301_node = NULL;
+	}
+
+	isp1301_i2c_client = isp1301_get_client(isp1301_node);
+	if (!isp1301_i2c_client) {
+		ret = -EPROBE_DEFER;
 		goto out;
 	}
 
-	if (pdev->num_resources != 2
-	    || pdev->resource[0].flags != IORESOURCE_MEM
-	    || pdev->resource[1].flags != IORESOURCE_IRQ) {
-		err("Invalid resource configuration");
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+	dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
+	if (usb_disabled()) {
+		dev_err(&pdev->dev, "USB is disabled\n");
 		ret = -ENODEV;
 		goto out;
 	}
 
 	/* Enable AHB slave USB clock, needed for further USB clock control */
-	__raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
-
-	ret = i2c_add_driver(&isp1301_driver);
-	if (ret < 0) {
-		err("failed to add ISP1301 driver");
-		goto out;
-	}
-	i2c_adap = i2c_get_adapter(2);
-	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
-	strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE);
-	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
-						   normal_i2c, NULL);
-	i2c_put_adapter(i2c_adap);
-	if (!isp1301_i2c_client) {
-		err("failed to connect I2C to ISP1301 USB Transceiver");
-		ret = -ENODEV;
-		goto out_i2c_driver;
-	}
+	__raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL);
 
 	isp1301_configure();
 
 	/* Enable USB PLL */
 	usb_clk = clk_get(&pdev->dev, "ck_pll5");
 	if (IS_ERR(usb_clk)) {
-		err("failed to acquire USB PLL");
+		dev_err(&pdev->dev, "failed to acquire USB PLL\n");
 		ret = PTR_ERR(usb_clk);
 		goto out1;
 	}
 
 	ret = clk_enable(usb_clk);
 	if (ret < 0) {
-		err("failed to start USB PLL");
+		dev_err(&pdev->dev, "failed to start USB PLL\n");
 		goto out2;
 	}
 
 	ret = clk_set_rate(usb_clk, 48000);
 	if (ret < 0) {
-		err("failed to set USB clock rate");
+		dev_err(&pdev->dev, "failed to set USB clock rate\n");
 		goto out3;
 	}
 
@@ -442,9 +357,9 @@
 	while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
 	       USB_CLOCK_MASK) ;
 
-	hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev));
+	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
 	if (!hcd) {
-		err("Failed to allocate HC buffer");
+		dev_err(&pdev->dev, "Failed to allocate HC buffer\n");
 		ret = -ENOMEM;
 		goto out3;
 	}
@@ -452,14 +367,21 @@
 	/* Set all USB bits in the Start Enable register */
 	nxp_set_usb_bits();
 
-	hcd->rsrc_start = pdev->resource[0].start;
-	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		dev_dbg(&pdev->dev, "request_mem_region failed\n");
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get MEM resource\n");
 		ret =  -ENOMEM;
 		goto out4;
 	}
-	hcd->regs = (void __iomem *)pdev->resource[0].start;
+
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (!hcd->regs) {
+		dev_err(&pdev->dev, "Failed to devm_request_and_ioremap\n");
+		ret =  -ENOMEM;
+		goto out4;
+	}
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
@@ -486,10 +408,7 @@
 out2:
 	clk_put(usb_clk);
 out1:
-	i2c_unregister_device(isp1301_i2c_client);
 	isp1301_i2c_client = NULL;
-out_i2c_driver:
-	i2c_del_driver(&isp1301_driver);
 out:
 	return ret;
 }
@@ -507,7 +426,6 @@
 	clk_put(usb_clk);
 	i2c_unregister_device(isp1301_i2c_client);
 	isp1301_i2c_client = NULL;
-	i2c_del_driver(&isp1301_driver);
 
 	platform_set_drvdata(pdev, NULL);
 
@@ -517,10 +435,19 @@
 /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:usb-ohci");
 
+#ifdef CONFIG_OF
+static const struct of_device_id usb_hcd_nxp_match[] = {
+	{ .compatible = "nxp,ohci-nxp" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, usb_hcd_nxp_match);
+#endif
+
 static struct platform_driver usb_hcd_nxp_driver = {
 	.driver = {
 		.name = "usb-ohci",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(usb_hcd_nxp_match),
 	},
 	.probe = usb_hcd_nxp_probe,
 	.remove = usb_hcd_nxp_remove,
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 96451e4..9ce35d0 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -205,8 +205,9 @@
 	need_transceiver = need_transceiver
 			|| machine_is_omap_h2() || machine_is_omap_h3();
 
-	if (cpu_is_omap16xx())
-		ocpi_enable();
+	/* XXX OMAP16xx only */
+	if (config->ocpi_enable)
+		config->ocpi_enable();
 
 #ifdef	CONFIG_USB_OTG
 	if (need_transceiver) {
@@ -217,8 +218,7 @@
 			dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
 					ohci->transceiver->label, status);
 			if (status) {
-				if (ohci->transceiver)
-					put_device(ohci->transceiver->dev);
+				usb_put_transceiver(ohci->transceiver);
 				return status;
 			}
 		} else {
@@ -405,7 +405,7 @@
 	usb_remove_hcd(hcd);
 	if (ohci->transceiver) {
 		(void) otg_set_host(ohci->transceiver->otg, 0);
-		put_device(ohci->transceiver->dev);
+		usb_put_transceiver(ohci->transceiver);
 	}
 	if (machine_is_omap_osk())
 		gpio_free(9);
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index ec5c679..670c705 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -93,13 +93,13 @@
 
 	irq = platform_get_irq(dev, 0);
 	if (irq < 0) {
-		pr_err("no irq provieded");
+		pr_err("no irq provided");
 		return irq;
 	}
 
 	res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	if (!res_mem) {
-		pr_err("no memory recourse provieded");
+		pr_err("no memory recourse provided");
 		return -ENXIO;
 	}
 
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index f13d08f..148d27d 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -157,7 +157,8 @@
 		return ret;
 
 	if ((ret = ohci_run (ohci)) < 0) {
-		err ("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s",
+			hcd->self.bus_name);
 		ohci_stop (hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index d24cc89d..e27d5ae 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -29,7 +29,8 @@
 		return ret;
 
 	if ((ret = ohci_run(ohci)) < 0) {
-		err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
@@ -236,7 +237,7 @@
 
 #if	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
 	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
-#error "No endianess selected for ppc-of-ohci"
+#error "No endianness selected for ppc-of-ohci"
 #endif
 
 
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1514b70..185c39e 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -130,7 +130,8 @@
 		return ret;
 
 	if ((ret = ohci_run(ohci)) < 0) {
-		err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index 6fd4fa1..2ee1d8d 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -45,7 +45,8 @@
 	result = ohci_run(ohci);
 
 	if (result < 0) {
-		err("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 	}
 
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index c31b281..e1a3cc6 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -419,7 +419,8 @@
 		return ret;
 
 	if ((ret = ohci_run (ohci)) < 0) {
-		err ("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s",
+			hcd->self.bus_name);
 		ohci_stop (hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 56dcf06..664c869 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -420,7 +420,8 @@
 
 	ret = ohci_run(ohci);
 	if (ret < 0) {
-		err("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index e1004fb..b6cc925 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -46,7 +46,7 @@
 {
 	unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
 
-	dbg("%s USB_STATUS = { %s%s%s%s%s}", label,
+	printk(KERN_DEBUG "%s USB_STATUS = { %s%s%s%s%s}\n", label,
 	     ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
 	     ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
 	     ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
@@ -193,7 +193,7 @@
 	hcd->rsrc_len = resource_size(&dev->res);
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		dbg("request_mem_region failed");
+		dev_dbg(&dev->dev, "request_mem_region failed\n");
 		ret = -EBUSY;
 		goto err1;
 	}
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index 84686d9..76a20c2 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -88,20 +88,20 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
-		err("platform_get_resource error.");
+		dev_err(&pdev->dev, "platform_get_resource error.\n");
 		return -ENODEV;
 	}
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		err("platform_get_irq error.");
+		dev_err(&pdev->dev, "platform_get_irq error.\n");
 		return -ENODEV;
 	}
 
 	/* initialize hcd */
 	hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name);
 	if (!hcd) {
-		err("Failed to create hcd");
+		dev_err(&pdev->dev, "Failed to create hcd\n");
 		return -ENOMEM;
 	}
 
@@ -110,7 +110,7 @@
 	hcd->rsrc_len = resource_size(res);
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret != 0) {
-		err("Failed to add hcd");
+		dev_err(&pdev->dev, "Failed to add hcd\n");
 		usb_put_hcd(hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 95c1648..fc7305e 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -14,6 +14,7 @@
 #include <linux/signal.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/of.h>
 
 struct spear_ohci {
 	struct ohci_hcd ohci;
@@ -24,12 +25,12 @@
 
 static void spear_start_ohci(struct spear_ohci *ohci)
 {
-	clk_enable(ohci->clk);
+	clk_prepare_enable(ohci->clk);
 }
 
 static void spear_stop_ohci(struct spear_ohci *ohci)
 {
-	clk_disable(ohci->clk);
+	clk_disable_unprepare(ohci->clk);
 }
 
 static int __devinit ohci_spear_start(struct usb_hcd *hcd)
@@ -90,6 +91,8 @@
 	.start_port_reset	= ohci_start_port_reset,
 };
 
+static u64 spear_ohci_dma_mask = DMA_BIT_MASK(32);
+
 static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
 {
 	const struct hc_driver *driver = &ohci_spear_hc_driver;
@@ -98,11 +101,8 @@
 	struct spear_ohci *ohci_p;
 	struct resource *res;
 	int retval, irq;
-	int *pdata = pdev->dev.platform_data;
 	char clk_name[20] = "usbh_clk";
-
-	if (pdata == NULL)
-		return -EFAULT;
+	static int instance = -1;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
@@ -110,8 +110,22 @@
 		goto fail_irq_get;
 	}
 
-	if (*pdata >= 0)
-		sprintf(clk_name, "usbh.%01d_clk", *pdata);
+	/*
+	 * Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we have dma capability bindings this can go away.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &spear_ohci_dma_mask;
+
+	/*
+	 * Increment the device instance, when probing via device-tree
+	 */
+	if (pdev->id < 0)
+		instance++;
+	else
+		instance = pdev->id;
+	sprintf(clk_name, "usbh.%01d_clk", instance);
 
 	usbh_clk = clk_get(NULL, clk_name);
 	if (IS_ERR(usbh_clk)) {
@@ -222,6 +236,11 @@
 }
 #endif
 
+static struct of_device_id spear_ohci_id_table[] __devinitdata = {
+	{ .compatible = "st,spear600-ohci", },
+	{ },
+};
+
 /* Driver definition to register with the platform bus */
 static struct platform_driver spear_ohci_hcd_driver = {
 	.probe =	spear_ohci_hcd_drv_probe,
@@ -233,6 +252,7 @@
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "spear-ohci",
+		.of_match_table = of_match_ptr(spear_ohci_id_table),
 	},
 };
 
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
deleted file mode 100644
index 5ba1859..0000000
--- a/drivers/usb/host/ohci-ssb.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Sonics Silicon Backplane
- * Broadcom USB-core OHCI driver
- *
- * Copyright 2007 Michael Buesch <m@bues.ch>
- *
- * Derived from the OHCI-PCI driver
- * Copyright 1999 Roman Weissgaerber
- * Copyright 2000-2002 David Brownell
- * Copyright 1999 Linus Torvalds
- * Copyright 1999 Gregory P. Smith
- *
- * Derived from the USBcore related parts of Broadcom-SB
- * Copyright 2005 Broadcom Corporation
- *
- * Licensed under the GNU/GPL. See COPYING for details.
- */
-#include <linux/ssb/ssb.h>
-
-
-#define SSB_OHCI_TMSLOW_HOSTMODE	(1 << 29)
-
-struct ssb_ohci_device {
-	struct ohci_hcd ohci; /* _must_ be at the beginning. */
-
-	u32 enable_flags;
-};
-
-static inline
-struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
-{
-	return (struct ssb_ohci_device *)(hcd->hcd_priv);
-}
-
-
-static int ssb_ohci_reset(struct usb_hcd *hcd)
-{
-	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-	struct ohci_hcd *ohci = &ohcidev->ohci;
-	int err;
-
-	ohci_hcd_init(ohci);
-	err = ohci_init(ohci);
-
-	return err;
-}
-
-static int ssb_ohci_start(struct usb_hcd *hcd)
-{
-	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-	struct ohci_hcd *ohci = &ohcidev->ohci;
-	int err;
-
-	err = ohci_run(ohci);
-	if (err < 0) {
-		ohci_err(ohci, "can't start\n");
-		ohci_stop(hcd);
-	}
-
-	return err;
-}
-
-static const struct hc_driver ssb_ohci_hc_driver = {
-	.description		= "ssb-usb-ohci",
-	.product_desc		= "SSB OHCI Controller",
-	.hcd_priv_size		= sizeof(struct ssb_ohci_device),
-
-	.irq			= ohci_irq,
-	.flags			= HCD_MEMORY | HCD_USB11,
-
-	.reset			= ssb_ohci_reset,
-	.start			= ssb_ohci_start,
-	.stop			= ohci_stop,
-	.shutdown		= ohci_shutdown,
-
-	.urb_enqueue		= ohci_urb_enqueue,
-	.urb_dequeue		= ohci_urb_dequeue,
-	.endpoint_disable	= ohci_endpoint_disable,
-
-	.get_frame_number	= ohci_get_frame,
-
-	.hub_status_data	= ohci_hub_status_data,
-	.hub_control		= ohci_hub_control,
-#ifdef	CONFIG_PM
-	.bus_suspend		= ohci_bus_suspend,
-	.bus_resume		= ohci_bus_resume,
-#endif
-
-	.start_port_reset	= ohci_start_port_reset,
-};
-
-static void ssb_ohci_detach(struct ssb_device *dev)
-{
-	struct usb_hcd *hcd = ssb_get_drvdata(dev);
-
-	if (hcd->driver->shutdown)
-		hcd->driver->shutdown(hcd);
-	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	usb_put_hcd(hcd);
-	ssb_device_disable(dev, 0);
-}
-
-static int ssb_ohci_attach(struct ssb_device *dev)
-{
-	struct ssb_ohci_device *ohcidev;
-	struct usb_hcd *hcd;
-	int err = -ENOMEM;
-	u32 tmp, flags = 0;
-
-	if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
-	    dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
-		return -EOPNOTSUPP;
-
-	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
-		/* Put the device into host-mode. */
-		flags |= SSB_OHCI_TMSLOW_HOSTMODE;
-		ssb_device_enable(dev, flags);
-	} else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
-		/*
-		 * USB 2.0 special considerations:
-		 *
-		 * In addition to the standard SSB reset sequence, the Host
-		 * Control Register must be programmed to bring the USB core
-		 * and various phy components out of reset.
-		 */
-		ssb_device_enable(dev, 0);
-		ssb_write32(dev, 0x200, 0x7ff);
-
-		/* Change Flush control reg */
-		tmp = ssb_read32(dev, 0x400);
-		tmp &= ~8;
-		ssb_write32(dev, 0x400, tmp);
-		tmp = ssb_read32(dev, 0x400);
-
-		/* Change Shim control reg */
-		tmp = ssb_read32(dev, 0x304);
-		tmp &= ~0x100;
-		ssb_write32(dev, 0x304, tmp);
-		tmp = ssb_read32(dev, 0x304);
-
-		udelay(1);
-
-		/* Work around for 5354 failures */
-		if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
-			/* Change syn01 reg */
-			tmp = 0x00fe00fe;
-			ssb_write32(dev, 0x894, tmp);
-
-			/* Change syn03 reg */
-			tmp = ssb_read32(dev, 0x89c);
-			tmp |= 0x1;
-			ssb_write32(dev, 0x89c, tmp);
-		}
-	} else
-		ssb_device_enable(dev, 0);
-
-	hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
-			dev_name(dev->dev));
-	if (!hcd)
-		goto err_dev_disable;
-	ohcidev = hcd_to_ssb_ohci(hcd);
-	ohcidev->enable_flags = flags;
-
-	tmp = ssb_read32(dev, SSB_ADMATCH0);
-	hcd->rsrc_start = ssb_admatch_base(tmp);
-	hcd->rsrc_len = ssb_admatch_size(tmp);
-	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
-	if (!hcd->regs)
-		goto err_put_hcd;
-	err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
-	if (err)
-		goto err_iounmap;
-
-	ssb_set_drvdata(dev, hcd);
-
-	return err;
-
-err_iounmap:
-	iounmap(hcd->regs);
-err_put_hcd:
-	usb_put_hcd(hcd);
-err_dev_disable:
-	ssb_device_disable(dev, flags);
-	return err;
-}
-
-static int ssb_ohci_probe(struct ssb_device *dev,
-		const struct ssb_device_id *id)
-{
-	int err;
-	u16 chipid_top;
-
-	/* USBcores are only connected on embedded devices. */
-	chipid_top = (dev->bus->chip_id & 0xFF00);
-	if (chipid_top != 0x4700 && chipid_top != 0x5300)
-		return -ENODEV;
-
-	/* TODO: Probably need checks here; is the core connected? */
-
-	if (usb_disabled())
-		return -ENODEV;
-
-	/* We currently always attach SSB_DEV_USB11_HOSTDEV
-	 * as HOST OHCI. If we want to attach it as Client device,
-	 * we must branch here and call into the (yet to
-	 * be written) Client mode driver. Same for remove(). */
-
-	err = ssb_ohci_attach(dev);
-
-	return err;
-}
-
-static void ssb_ohci_remove(struct ssb_device *dev)
-{
-	ssb_ohci_detach(dev);
-}
-
-#ifdef CONFIG_PM
-
-static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
-{
-	ssb_device_disable(dev, 0);
-
-	return 0;
-}
-
-static int ssb_ohci_resume(struct ssb_device *dev)
-{
-	struct usb_hcd *hcd = ssb_get_drvdata(dev);
-	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-
-	ssb_device_enable(dev, ohcidev->enable_flags);
-
-	ohci_finish_controller_resume(hcd);
-	return 0;
-}
-
-#else /* !CONFIG_PM */
-#define ssb_ohci_suspend	NULL
-#define ssb_ohci_resume	NULL
-#endif /* CONFIG_PM */
-
-static const struct ssb_device_id ssb_ohci_table[] = {
-	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
-	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
-	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
-	SSB_DEVTABLE_END
-};
-MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
-
-static struct ssb_driver ssb_ohci_driver = {
-	.name		= KBUILD_MODNAME,
-	.id_table	= ssb_ohci_table,
-	.probe		= ssb_ohci_probe,
-	.remove		= ssb_ohci_remove,
-	.suspend	= ssb_ohci_suspend,
-	.resume		= ssb_ohci_resume,
-};
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index 120bfe6..60c2b07 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -140,7 +140,8 @@
 		return ret;
 
 	if ((ret = ohci_run(ohci)) < 0) {
-		err("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c
index a224786..41e378f 100644
--- a/drivers/usb/host/ohci-xls.c
+++ b/drivers/usb/host/ohci-xls.c
@@ -88,7 +88,8 @@
 	ohci = hcd_to_ohci(hcd);
 	ret = ohci_run(ohci);
 	if (ret < 0) {
-		err("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
 		ohci_stop(hcd);
 		return ret;
 	}
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 3b38030..4f0f033 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -1399,8 +1399,8 @@
 				 * But interval 1 scheduling is simpler, and
 				 * includes high bandwidth.
 				 */
-				dbg("intr period %d uframes, NYET!",
-						urb->interval);
+				oxu_dbg(oxu, "intr period %d uframes, NYET!\n",
+					urb->interval);
 				goto done;
 			}
 		} else {
@@ -1471,7 +1471,7 @@
 		}
 		break;
 	default:
-		dbg("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+		oxu_dbg(oxu, "bogus dev %p speed %d\n", urb->dev, urb->dev->speed);
 done:
 		qh_put(qh);
 		return NULL;
@@ -2307,7 +2307,7 @@
 				qh_put(temp.qh);
 				break;
 			default:
-				dbg("corrupt type %d frame %d shadow %p",
+				oxu_dbg(oxu, "corrupt type %d frame %d shadow %p\n",
 					type, frame, q.ptr);
 				q.ptr = NULL;
 			}
@@ -2991,8 +2991,9 @@
 				/* shouldn't happen often, but ...
 				 * FIXME kill those tds' urbs
 				 */
-				err("can't reschedule qh %p, err %d",
-					qh, status);
+				dev_err(hcd->self.controller,
+					"can't reschedule qh %p, err %d\n", qh,
+					status);
 			}
 			return status;
 		}
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 32dada8..df0828c 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/kconfig.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -712,12 +713,28 @@
 	return -ETIMEDOUT;
 }
 
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
+#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI	0x8C31
+
+bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
 {
 	return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
 		pdev->vendor == PCI_VENDOR_ID_INTEL &&
 		pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
 }
+
+/* The Intel Lynx Point chipset also has switchable ports. */
+bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
+{
+	return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
+		pdev->vendor == PCI_VENDOR_ID_INTEL &&
+		pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI;
+}
+
+bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
+{
+	return usb_is_intel_ppt_switchable_xhci(pdev) ||
+		usb_is_intel_lpt_switchable_xhci(pdev);
+}
 EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
 
 /*
@@ -742,6 +759,19 @@
 {
 	u32		ports_available;
 
+	/* Don't switchover the ports if the user hasn't compiled the xHCI
+	 * driver.  Otherwise they will see "dead" USB ports that don't power
+	 * the devices.
+	 */
+	if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) {
+		dev_warn(&xhci_pdev->dev,
+				"CONFIG_USB_XHCI_HCD is turned off, "
+				"defaulting to EHCI.\n");
+		dev_warn(&xhci_pdev->dev,
+				"USB 3.0 devices will work at USB 2.0 speeds.\n");
+		return;
+	}
+
 	ports_available = 0xffffffff;
 	/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
 	 * Register, to turn on SuperSpeed terminations for all
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 2bf1320..c868be6 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -401,7 +401,7 @@
 		if (r8a66597->address_map & (1 << addr))
 			continue;
 
-		dbg("alloc_address: r8a66597_addr=%d", addr);
+		dev_dbg(&urb->dev->dev, "alloc_address: r8a66597_addr=%d\n", addr);
 		r8a66597->address_map |= 1 << addr;
 
 		if (make_r8a66597_device(r8a66597, urb, addr) < 0)
@@ -426,7 +426,7 @@
 	if (!dev)
 		return;
 
-	dbg("free_addr: addr=%d", dev->address);
+	dev_dbg(&dev->udev->dev, "free_addr: addr=%d\n", dev->address);
 
 	dev->state = USB_STATE_DEFAULT;
 	r8a66597->address_map &= ~(1 << dev->address);
@@ -819,7 +819,7 @@
 	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
 	struct r8a66597_pipe *pipe = hep->hcpriv;
 
-	dbg("enable_pipe:");
+	dev_dbg(&dev->udev->dev, "enable_pipe:\n");
 
 	pipe->info = *info;
 	set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA);
@@ -898,7 +898,7 @@
 		force_dequeue(r8a66597, pipenum, dev->address);
 	}
 
-	dbg("disable_pipe");
+	dev_dbg(&dev->udev->dev, "disable_pipe\n");
 
 	r8a66597->dma_map &= ~(dev->dma_map);
 	dev->dma_map = 0;
@@ -2264,7 +2264,7 @@
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	int port;
 
-	dbg("%s", __func__);
+	dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__);
 
 	for (port = 0; port < r8a66597->max_root_hub; port++) {
 		struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
@@ -2273,7 +2273,7 @@
 		if (!(rh->port & USB_PORT_STAT_ENABLE))
 			continue;
 
-		dbg("suspend port = %d", port);
+		dev_dbg(&rh->dev->udev->dev, "suspend port = %d\n", port);
 		r8a66597_bclr(r8a66597, UACT, dvstctr_reg);	/* suspend */
 		rh->port |= USB_PORT_STAT_SUSPEND;
 
@@ -2295,7 +2295,7 @@
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	int port;
 
-	dbg("%s", __func__);
+	dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__);
 
 	for (port = 0; port < r8a66597->max_root_hub; port++) {
 		struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
@@ -2304,7 +2304,7 @@
 		if (!(rh->port & USB_PORT_STAT_SUSPEND))
 			continue;
 
-		dbg("resume port = %d", port);
+		dev_dbg(&rh->dev->udev->dev, "resume port = %d\n", port);
 		rh->port &= ~USB_PORT_STAT_SUSPEND;
 		rh->port |= USB_PORT_STAT_C_SUSPEND << 16;
 		r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
@@ -2360,7 +2360,7 @@
 	struct r8a66597		*r8a66597 = dev_get_drvdata(dev);
 	int port;
 
-	dbg("%s", __func__);
+	dev_dbg(dev, "%s\n", __func__);
 
 	disable_controller(r8a66597);
 
@@ -2378,7 +2378,7 @@
 	struct r8a66597		*r8a66597 = dev_get_drvdata(dev);
 	struct usb_hcd		*hcd = r8a66597_to_hcd(r8a66597);
 
-	dbg("%s", __func__);
+	dev_dbg(dev, "%s\n", __func__);
 
 	enable_controller(r8a66597);
 	usb_root_hub_lost_power(hcd->self.root_hub);
diff --git a/drivers/usb/host/ssb-hcd.c b/drivers/usb/host/ssb-hcd.c
new file mode 100644
index 0000000..c2a29fa
--- /dev/null
+++ b/drivers/usb/host/ssb-hcd.c
@@ -0,0 +1,280 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core driver  (SSB bus glue)
+ *
+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Based on ssb-ohci driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005-2011 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
+
+MODULE_AUTHOR("Hauke Mehrtens");
+MODULE_DESCRIPTION("Common USB driver for SSB Bus");
+MODULE_LICENSE("GPL");
+
+#define SSB_HCD_TMSLOW_HOSTMODE	(1 << 29)
+
+struct ssb_hcd_device {
+	struct platform_device *ehci_dev;
+	struct platform_device *ohci_dev;
+
+	u32 enable_flags;
+};
+
+static void __devinit ssb_hcd_5354wa(struct ssb_device *dev)
+{
+#ifdef CONFIG_SSB_DRIVER_MIPS
+	/* Work around for 5354 failures */
+	if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
+		/* Change syn01 reg */
+		ssb_write32(dev, 0x894, 0x00fe00fe);
+
+		/* Change syn03 reg */
+		ssb_write32(dev, 0x89c, ssb_read32(dev, 0x89c) | 0x1);
+	}
+#endif
+}
+
+static void __devinit ssb_hcd_usb20wa(struct ssb_device *dev)
+{
+	if (dev->id.coreid == SSB_DEV_USB20_HOST) {
+		/*
+		 * USB 2.0 special considerations:
+		 *
+		 * In addition to the standard SSB reset sequence, the Host
+		 * Control Register must be programmed to bring the USB core
+		 * and various phy components out of reset.
+		 */
+		ssb_write32(dev, 0x200, 0x7ff);
+
+		/* Change Flush control reg */
+		ssb_write32(dev, 0x400, ssb_read32(dev, 0x400) & ~8);
+		ssb_read32(dev, 0x400);
+
+		/* Change Shim control reg */
+		ssb_write32(dev, 0x304, ssb_read32(dev, 0x304) & ~0x100);
+		ssb_read32(dev, 0x304);
+
+		udelay(1);
+
+		ssb_hcd_5354wa(dev);
+	}
+}
+
+/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
+static u32 __devinit ssb_hcd_init_chip(struct ssb_device *dev)
+{
+	u32 flags = 0;
+
+	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+		/* Put the device into host-mode. */
+		flags |= SSB_HCD_TMSLOW_HOSTMODE;
+
+	ssb_device_enable(dev, flags);
+
+	ssb_hcd_usb20wa(dev);
+
+	return flags;
+}
+
+static const struct usb_ehci_pdata ehci_pdata = {
+};
+
+static const struct usb_ohci_pdata ohci_pdata = {
+};
+
+static struct platform_device * __devinit
+ssb_hcd_create_pdev(struct ssb_device *dev, bool ohci, u32 addr, u32 len)
+{
+	struct platform_device *hci_dev;
+	struct resource hci_res[2];
+	int ret = -ENOMEM;
+
+	memset(hci_res, 0, sizeof(hci_res));
+
+	hci_res[0].start = addr;
+	hci_res[0].end = hci_res[0].start + len - 1;
+	hci_res[0].flags = IORESOURCE_MEM;
+
+	hci_res[1].start = dev->irq;
+	hci_res[1].flags = IORESOURCE_IRQ;
+
+	hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
+					"ehci-platform" , 0);
+	if (!hci_dev)
+		return NULL;
+
+	hci_dev->dev.parent = dev->dev;
+	hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
+
+	ret = platform_device_add_resources(hci_dev, hci_res,
+					    ARRAY_SIZE(hci_res));
+	if (ret)
+		goto err_alloc;
+	if (ohci)
+		ret = platform_device_add_data(hci_dev, &ohci_pdata,
+					       sizeof(ohci_pdata));
+	else
+		ret = platform_device_add_data(hci_dev, &ehci_pdata,
+					       sizeof(ehci_pdata));
+	if (ret)
+		goto err_alloc;
+	ret = platform_device_add(hci_dev);
+	if (ret)
+		goto err_alloc;
+
+	return hci_dev;
+
+err_alloc:
+	platform_device_put(hci_dev);
+	return ERR_PTR(ret);
+}
+
+static int __devinit ssb_hcd_probe(struct ssb_device *dev,
+				   const struct ssb_device_id *id)
+{
+	int err, tmp;
+	int start, len;
+	u16 chipid_top;
+	u16 coreid = dev->id.coreid;
+	struct ssb_hcd_device *usb_dev;
+
+	/* USBcores are only connected on embedded devices. */
+	chipid_top = (dev->bus->chip_id & 0xFF00);
+	if (chipid_top != 0x4700 && chipid_top != 0x5300)
+		return -ENODEV;
+
+	/* TODO: Probably need checks here; is the core connected? */
+
+	if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
+	    dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
+		return -EOPNOTSUPP;
+
+	usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL);
+	if (!usb_dev)
+		return -ENOMEM;
+
+	/* We currently always attach SSB_DEV_USB11_HOSTDEV
+	 * as HOST OHCI. If we want to attach it as Client device,
+	 * we must branch here and call into the (yet to
+	 * be written) Client mode driver. Same for remove(). */
+	usb_dev->enable_flags = ssb_hcd_init_chip(dev);
+
+	tmp = ssb_read32(dev, SSB_ADMATCH0);
+
+	start = ssb_admatch_base(tmp);
+	len = (coreid == SSB_DEV_USB20_HOST) ? 0x800 : ssb_admatch_size(tmp);
+	usb_dev->ohci_dev = ssb_hcd_create_pdev(dev, true, start, len);
+	if (IS_ERR(usb_dev->ohci_dev)) {
+		err = PTR_ERR(usb_dev->ohci_dev);
+		goto err_free_usb_dev;
+	}
+
+	if (coreid == SSB_DEV_USB20_HOST) {
+		start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */
+		usb_dev->ehci_dev = ssb_hcd_create_pdev(dev, false, start, len);
+		if (IS_ERR(usb_dev->ehci_dev)) {
+			err = PTR_ERR(usb_dev->ehci_dev);
+			goto err_unregister_ohci_dev;
+		}
+	}
+
+	ssb_set_drvdata(dev, usb_dev);
+	return 0;
+
+err_unregister_ohci_dev:
+	platform_device_unregister(usb_dev->ohci_dev);
+err_free_usb_dev:
+	kfree(usb_dev);
+	return err;
+}
+
+static void __devexit ssb_hcd_remove(struct ssb_device *dev)
+{
+	struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
+	struct platform_device *ohci_dev = usb_dev->ohci_dev;
+	struct platform_device *ehci_dev = usb_dev->ehci_dev;
+
+	if (ohci_dev)
+		platform_device_unregister(ohci_dev);
+	if (ehci_dev)
+		platform_device_unregister(ehci_dev);
+
+	ssb_device_disable(dev, 0);
+}
+
+static void __devexit ssb_hcd_shutdown(struct ssb_device *dev)
+{
+	ssb_device_disable(dev, 0);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_hcd_suspend(struct ssb_device *dev, pm_message_t state)
+{
+	ssb_device_disable(dev, 0);
+
+	return 0;
+}
+
+static int ssb_hcd_resume(struct ssb_device *dev)
+{
+	struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
+
+	ssb_device_enable(dev, usb_dev->enable_flags);
+
+	return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_hcd_suspend	NULL
+#define ssb_hcd_resume	NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_hcd_table[] __devinitconst = {
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
+	SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_hcd_table);
+
+static struct ssb_driver ssb_hcd_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= ssb_hcd_table,
+	.probe		= ssb_hcd_probe,
+	.remove		= __devexit_p(ssb_hcd_remove),
+	.shutdown	= ssb_hcd_shutdown,
+	.suspend	= ssb_hcd_suspend,
+	.resume		= ssb_hcd_resume,
+};
+
+static int __init ssb_hcd_init(void)
+{
+	return ssb_driver_register(&ssb_hcd_driver);
+}
+module_init(ssb_hcd_init);
+
+static void __exit ssb_hcd_exit(void)
+{
+	ssb_driver_unregister(&ssb_hcd_driver);
+}
+module_exit(ssb_hcd_exit);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 673ad12..2732ef6 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -475,6 +475,7 @@
 	struct xhci_bus_state *bus_state;
 	u16 link_state = 0;
 	u16 wake_mask = 0;
+	u16 timeout = 0;
 
 	max_ports = xhci_get_ports(hcd, &port_array);
 	bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -558,6 +559,7 @@
 				xhci_dbg(xhci, "Resume USB2 port %d\n",
 					wIndex + 1);
 				bus_state->resume_done[wIndex] = 0;
+				clear_bit(wIndex, &bus_state->resuming_ports);
 				xhci_set_link_state(xhci, port_array, wIndex,
 							XDEV_U0);
 				xhci_dbg(xhci, "set port %d resume\n",
@@ -622,6 +624,8 @@
 			link_state = (wIndex & 0xff00) >> 3;
 		if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
 			wake_mask = wIndex & 0xff00;
+		/* The MSB of wIndex is the U1/U2 timeout */
+		timeout = (wIndex & 0xff00) >> 8;
 		wIndex &= 0xff;
 		if (!wIndex || wIndex > max_ports)
 			goto error;
@@ -746,6 +750,22 @@
 
 			temp = xhci_readl(xhci, port_array[wIndex]);
 			break;
+		case USB_PORT_FEAT_U1_TIMEOUT:
+			if (hcd->speed != HCD_USB3)
+				goto error;
+			temp = xhci_readl(xhci, port_array[wIndex] + 1);
+			temp &= ~PORT_U1_TIMEOUT_MASK;
+			temp |= PORT_U1_TIMEOUT(timeout);
+			xhci_writel(xhci, temp, port_array[wIndex] + 1);
+			break;
+		case USB_PORT_FEAT_U2_TIMEOUT:
+			if (hcd->speed != HCD_USB3)
+				goto error;
+			temp = xhci_readl(xhci, port_array[wIndex] + 1);
+			temp &= ~PORT_U2_TIMEOUT_MASK;
+			temp |= PORT_U2_TIMEOUT(timeout);
+			xhci_writel(xhci, temp, port_array[wIndex] + 1);
+			break;
 		default:
 			goto error;
 		}
@@ -845,7 +865,12 @@
 	/* Initial status is no changes */
 	retval = (max_ports + 8) / 8;
 	memset(buf, 0, retval);
-	status = 0;
+
+	/*
+	 * Inform the usbcore about resume-in-progress by returning
+	 * a non-zero value even if there are no status changes.
+	 */
+	status = bus_state->resuming_ports;
 
 	mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
 
@@ -885,15 +910,11 @@
 	spin_lock_irqsave(&xhci->lock, flags);
 
 	if (hcd->self.root_hub->do_remote_wakeup) {
-		port_index = max_ports;
-		while (port_index--) {
-			if (bus_state->resume_done[port_index] != 0) {
-				spin_unlock_irqrestore(&xhci->lock, flags);
-				xhci_dbg(xhci, "suspend failed because "
-						"port %d is resuming\n",
-						port_index + 1);
-				return -EBUSY;
-			}
+		if (bus_state->resuming_ports) {
+			spin_unlock_irqrestore(&xhci->lock, flags);
+			xhci_dbg(xhci, "suspend failed because "
+						"a port is resuming\n");
+			return -EBUSY;
 		}
 	}
 
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 68eaa90..ec4338e 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1791,6 +1791,14 @@
 {
 	struct pci_dev	*pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
 	struct dev_info	*dev_info, *next;
+	struct list_head *tt_list_head;
+	struct list_head *tt;
+	struct list_head *endpoints;
+	struct list_head *ep, *q;
+	struct xhci_tt_bw_info *tt_info;
+	struct xhci_interval_bw_table *bwt;
+	struct xhci_virt_ep *virt_ep;
+
 	unsigned long	flags;
 	int size;
 	int i;
@@ -1807,6 +1815,9 @@
 	xhci->event_ring = NULL;
 	xhci_dbg(xhci, "Freed event ring\n");
 
+	if (xhci->lpm_command)
+		xhci_free_command(xhci, xhci->lpm_command);
+	xhci->cmd_ring_reserved_trbs = 0;
 	if (xhci->cmd_ring)
 		xhci_ring_free(xhci, xhci->cmd_ring);
 	xhci->cmd_ring = NULL;
@@ -1849,8 +1860,26 @@
 	}
 	spin_unlock_irqrestore(&xhci->lock, flags);
 
+	bwt = &xhci->rh_bw->bw_table;
+	for (i = 0; i < XHCI_MAX_INTERVAL; i++) {
+		endpoints = &bwt->interval_bw[i].endpoints;
+		list_for_each_safe(ep, q, endpoints) {
+			virt_ep = list_entry(ep, struct xhci_virt_ep, bw_endpoint_list);
+			list_del(&virt_ep->bw_endpoint_list);
+			kfree(virt_ep);
+		}
+	}
+
+	tt_list_head = &xhci->rh_bw->tts;
+	list_for_each_safe(tt, q, tt_list_head) {
+		tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list);
+		list_del(tt);
+		kfree(tt_info);
+	}
+
 	xhci->num_usb2_ports = 0;
 	xhci->num_usb3_ports = 0;
+	xhci->num_active_eps = 0;
 	kfree(xhci->usb2_ports);
 	kfree(xhci->usb3_ports);
 	kfree(xhci->port_array);
@@ -2350,6 +2379,16 @@
 	xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
 	xhci_dbg_cmd_ptrs(xhci);
 
+	xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags);
+	if (!xhci->lpm_command)
+		goto fail;
+
+	/* Reserve one command ring TRB for disabling LPM.
+	 * Since the USB core grabs the shared usb_bus bandwidth mutex before
+	 * disabling LPM, we only need to reserve one TRB for all devices.
+	 */
+	xhci->cmd_ring_reserved_trbs++;
+
 	val = xhci_readl(xhci, &xhci->cap_regs->db_off);
 	val &= DBOFF_MASK;
 	xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 7a856a7..18b231b 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -72,6 +72,7 @@
 		xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
 				"has broken MSI implementation\n",
 				pdev->revision);
+		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 	}
 
 	if (pdev->vendor == PCI_VENDOR_ID_NEC)
@@ -83,6 +84,10 @@
 	/* AMD PLL quirk */
 	if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
 		xhci->quirks |= XHCI_AMD_PLL_FIX;
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+		xhci->quirks |= XHCI_LPM_SUPPORT;
+		xhci->quirks |= XHCI_INTEL_HOST;
+	}
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
 			pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
 		xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
@@ -169,6 +174,13 @@
 	if (retval)
 		goto put_usb3_hcd;
 	/* Roothub already marked as USB 3.0 speed */
+
+	/* We know the LPM timeout algorithms for this host, let the USB core
+	 * enable and disable LPM for devices under the USB 3.0 roothub.
+	 */
+	if (xhci->quirks & XHCI_LPM_SUPPORT)
+		hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1;
+
 	return 0;
 
 put_usb3_hcd:
@@ -292,6 +304,8 @@
 	 */
 	.update_device =        xhci_update_device,
 	.set_usb2_hw_lpm =	xhci_set_usb2_hardware_lpm,
+	.enable_usb3_lpm_timeout =	xhci_enable_usb3_lpm_timeout,
+	.disable_usb3_lpm_timeout =	xhci_disable_usb3_lpm_timeout,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 3d9422f..23b4aef 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1377,6 +1377,7 @@
 			xhci_dbg(xhci, "resume HS port %d\n", port_id);
 			bus_state->resume_done[faked_port_index] = jiffies +
 				msecs_to_jiffies(20);
+			set_bit(faked_port_index, &bus_state->resuming_ports);
 			mod_timer(&hcd->rh_timer,
 				  bus_state->resume_done[faked_port_index]);
 			/* Do the rest in GetPortStatus */
@@ -1786,8 +1787,12 @@
 	/* handle completion code */
 	switch (trb_comp_code) {
 	case COMP_SUCCESS:
-		frame->status = 0;
-		break;
+		if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
+			frame->status = 0;
+			break;
+		}
+		if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
+			trb_comp_code = COMP_SHORT_TX;
 	case COMP_SHORT_TX:
 		frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
 				-EREMOTEIO : 0;
@@ -1803,6 +1808,7 @@
 		break;
 	case COMP_DEV_ERR:
 	case COMP_STALL:
+	case COMP_TX_ERR:
 		frame->status = -EPROTO;
 		skip_td = true;
 		break;
@@ -1883,13 +1889,16 @@
 	switch (trb_comp_code) {
 	case COMP_SUCCESS:
 		/* Double check that the HW transferred everything. */
-		if (event_trb != td->last_trb) {
+		if (event_trb != td->last_trb ||
+				TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
 			xhci_warn(xhci, "WARN Successful completion "
 					"on short TX\n");
 			if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
 				*status = -EREMOTEIO;
 			else
 				*status = 0;
+			if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
+				trb_comp_code = COMP_SHORT_TX;
 		} else {
 			*status = 0;
 		}
@@ -2048,6 +2057,13 @@
 	 * transfer type
 	 */
 	case COMP_SUCCESS:
+		if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
+			break;
+		if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
+			trb_comp_code = COMP_SHORT_TX;
+		else
+			xhci_warn(xhci, "WARN Successful completion on short TX: "
+					"needs XHCI_TRUST_TX_LENGTH quirk?\n");
 	case COMP_SHORT_TX:
 		break;
 	case COMP_STOP:
@@ -2270,7 +2286,7 @@
 					(status != 0 &&
 					 !usb_endpoint_xfer_isoc(&urb->ep->desc)))
 				xhci_dbg(xhci, "Giveback URB %p, len = %d, "
-						"expected = %x, status = %d\n",
+						"expected = %d, status = %d\n",
 						urb, urb->actual_length,
 						urb->transfer_buffer_length,
 						status);
@@ -3593,12 +3609,12 @@
 
 /* Queue an evaluate context command TRB */
 int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
-		u32 slot_id)
+		u32 slot_id, bool command_must_succeed)
 {
 	return queue_command(xhci, lower_32_bits(in_ctx_ptr),
 			upper_32_bits(in_ctx_ptr), 0,
 			TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id),
-			false);
+			command_must_succeed);
 }
 
 /*
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 36641a7..afdc73e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -152,7 +152,7 @@
 {
 	u32 command;
 	u32 state;
-	int ret;
+	int ret, i;
 
 	state = xhci_readl(xhci, &xhci->op_regs->status);
 	if ((state & STS_HALT) == 0) {
@@ -175,7 +175,15 @@
 	 * xHCI cannot write to any doorbells or operational registers other
 	 * than status until the "Controller Not Ready" flag is cleared.
 	 */
-	return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
+	ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
+
+	for (i = 0; i < 2; ++i) {
+		xhci->bus_state[i].port_c_suspend = 0;
+		xhci->bus_state[i].suspended_ports = 0;
+		xhci->bus_state[i].resuming_ports = 0;
+	}
+
+	return ret;
 }
 
 #ifdef CONFIG_PCI
@@ -2438,7 +2446,7 @@
 				udev->slot_id, must_succeed);
 	else
 		ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
-				udev->slot_id);
+				udev->slot_id, must_succeed);
 	if (ret < 0) {
 		if (command)
 			list_del(&command->cmd_list);
@@ -3863,6 +3871,474 @@
 
 #endif /* CONFIG_USB_SUSPEND */
 
+/*---------------------- USB 3.0 Link PM functions ------------------------*/
+
+#ifdef CONFIG_PM
+/* Service interval in nanoseconds = 2^(bInterval - 1) * 125us * 1000ns / 1us */
+static unsigned long long xhci_service_interval_to_ns(
+		struct usb_endpoint_descriptor *desc)
+{
+	return (1 << (desc->bInterval - 1)) * 125 * 1000;
+}
+
+static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
+		enum usb3_link_state state)
+{
+	unsigned long long sel;
+	unsigned long long pel;
+	unsigned int max_sel_pel;
+	char *state_name;
+
+	switch (state) {
+	case USB3_LPM_U1:
+		/* Convert SEL and PEL stored in nanoseconds to microseconds */
+		sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
+		pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
+		max_sel_pel = USB3_LPM_MAX_U1_SEL_PEL;
+		state_name = "U1";
+		break;
+	case USB3_LPM_U2:
+		sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
+		pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
+		max_sel_pel = USB3_LPM_MAX_U2_SEL_PEL;
+		state_name = "U2";
+		break;
+	default:
+		dev_warn(&udev->dev, "%s: Can't get timeout for non-U1 or U2 state.\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	if (sel <= max_sel_pel && pel <= max_sel_pel)
+		return USB3_LPM_DEVICE_INITIATED;
+
+	if (sel > max_sel_pel)
+		dev_dbg(&udev->dev, "Device-initiated %s disabled "
+				"due to long SEL %llu ms\n",
+				state_name, sel);
+	else
+		dev_dbg(&udev->dev, "Device-initiated %s disabled "
+				"due to long PEL %llu\n ms",
+				state_name, pel);
+	return USB3_LPM_DISABLED;
+}
+
+/* Returns the hub-encoded U1 timeout value.
+ * The U1 timeout should be the maximum of the following values:
+ *  - For control endpoints, U1 system exit latency (SEL) * 3
+ *  - For bulk endpoints, U1 SEL * 5
+ *  - For interrupt endpoints:
+ *    - Notification EPs, U1 SEL * 3
+ *    - Periodic EPs, max(105% of bInterval, U1 SEL * 2)
+ *  - For isochronous endpoints, max(105% of bInterval, U1 SEL * 2)
+ */
+static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev,
+		struct usb_endpoint_descriptor *desc)
+{
+	unsigned long long timeout_ns;
+	int ep_type;
+	int intr_type;
+
+	ep_type = usb_endpoint_type(desc);
+	switch (ep_type) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		timeout_ns = udev->u1_params.sel * 3;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		timeout_ns = udev->u1_params.sel * 5;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		intr_type = usb_endpoint_interrupt_type(desc);
+		if (intr_type == USB_ENDPOINT_INTR_NOTIFICATION) {
+			timeout_ns = udev->u1_params.sel * 3;
+			break;
+		}
+		/* Otherwise the calculation is the same as isoc eps */
+	case USB_ENDPOINT_XFER_ISOC:
+		timeout_ns = xhci_service_interval_to_ns(desc);
+		timeout_ns = DIV_ROUND_UP_ULL(timeout_ns * 105, 100);
+		if (timeout_ns < udev->u1_params.sel * 2)
+			timeout_ns = udev->u1_params.sel * 2;
+		break;
+	default:
+		return 0;
+	}
+
+	/* The U1 timeout is encoded in 1us intervals. */
+	timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 1000);
+	/* Don't return a timeout of zero, because that's USB3_LPM_DISABLED. */
+	if (timeout_ns == USB3_LPM_DISABLED)
+		timeout_ns++;
+
+	/* If the necessary timeout value is bigger than what we can set in the
+	 * USB 3.0 hub, we have to disable hub-initiated U1.
+	 */
+	if (timeout_ns <= USB3_LPM_U1_MAX_TIMEOUT)
+		return timeout_ns;
+	dev_dbg(&udev->dev, "Hub-initiated U1 disabled "
+			"due to long timeout %llu ms\n", timeout_ns);
+	return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U1);
+}
+
+/* Returns the hub-encoded U2 timeout value.
+ * The U2 timeout should be the maximum of:
+ *  - 10 ms (to avoid the bandwidth impact on the scheduler)
+ *  - largest bInterval of any active periodic endpoint (to avoid going
+ *    into lower power link states between intervals).
+ *  - the U2 Exit Latency of the device
+ */
+static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev,
+		struct usb_endpoint_descriptor *desc)
+{
+	unsigned long long timeout_ns;
+	unsigned long long u2_del_ns;
+
+	timeout_ns = 10 * 1000 * 1000;
+
+	if ((usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) &&
+			(xhci_service_interval_to_ns(desc) > timeout_ns))
+		timeout_ns = xhci_service_interval_to_ns(desc);
+
+	u2_del_ns = udev->bos->ss_cap->bU2DevExitLat * 1000;
+	if (u2_del_ns > timeout_ns)
+		timeout_ns = u2_del_ns;
+
+	/* The U2 timeout is encoded in 256us intervals */
+	timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000);
+	/* If the necessary timeout value is bigger than what we can set in the
+	 * USB 3.0 hub, we have to disable hub-initiated U2.
+	 */
+	if (timeout_ns <= USB3_LPM_U2_MAX_TIMEOUT)
+		return timeout_ns;
+	dev_dbg(&udev->dev, "Hub-initiated U2 disabled "
+			"due to long timeout %llu ms\n", timeout_ns);
+	return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U2);
+}
+
+static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci,
+		struct usb_device *udev,
+		struct usb_endpoint_descriptor *desc,
+		enum usb3_link_state state,
+		u16 *timeout)
+{
+	if (state == USB3_LPM_U1) {
+		if (xhci->quirks & XHCI_INTEL_HOST)
+			return xhci_calculate_intel_u1_timeout(udev, desc);
+	} else {
+		if (xhci->quirks & XHCI_INTEL_HOST)
+			return xhci_calculate_intel_u2_timeout(udev, desc);
+	}
+
+	return USB3_LPM_DISABLED;
+}
+
+static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci,
+		struct usb_device *udev,
+		struct usb_endpoint_descriptor *desc,
+		enum usb3_link_state state,
+		u16 *timeout)
+{
+	u16 alt_timeout;
+
+	alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev,
+		desc, state, timeout);
+
+	/* If we found we can't enable hub-initiated LPM, or
+	 * the U1 or U2 exit latency was too high to allow
+	 * device-initiated LPM as well, just stop searching.
+	 */
+	if (alt_timeout == USB3_LPM_DISABLED ||
+			alt_timeout == USB3_LPM_DEVICE_INITIATED) {
+		*timeout = alt_timeout;
+		return -E2BIG;
+	}
+	if (alt_timeout > *timeout)
+		*timeout = alt_timeout;
+	return 0;
+}
+
+static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci,
+		struct usb_device *udev,
+		struct usb_host_interface *alt,
+		enum usb3_link_state state,
+		u16 *timeout)
+{
+	int j;
+
+	for (j = 0; j < alt->desc.bNumEndpoints; j++) {
+		if (xhci_update_timeout_for_endpoint(xhci, udev,
+					&alt->endpoint[j].desc, state, timeout))
+			return -E2BIG;
+		continue;
+	}
+	return 0;
+}
+
+static int xhci_check_intel_tier_policy(struct usb_device *udev,
+		enum usb3_link_state state)
+{
+	struct usb_device *parent;
+	unsigned int num_hubs;
+
+	if (state == USB3_LPM_U2)
+		return 0;
+
+	/* Don't enable U1 if the device is on a 2nd tier hub or lower. */
+	for (parent = udev->parent, num_hubs = 0; parent->parent;
+			parent = parent->parent)
+		num_hubs++;
+
+	if (num_hubs < 2)
+		return 0;
+
+	dev_dbg(&udev->dev, "Disabling U1 link state for device"
+			" below second-tier hub.\n");
+	dev_dbg(&udev->dev, "Plug device into first-tier hub "
+			"to decrease power consumption.\n");
+	return -E2BIG;
+}
+
+static int xhci_check_tier_policy(struct xhci_hcd *xhci,
+		struct usb_device *udev,
+		enum usb3_link_state state)
+{
+	if (xhci->quirks & XHCI_INTEL_HOST)
+		return xhci_check_intel_tier_policy(udev, state);
+	return -EINVAL;
+}
+
+/* Returns the U1 or U2 timeout that should be enabled.
+ * If the tier check or timeout setting functions return with a non-zero exit
+ * code, that means the timeout value has been finalized and we shouldn't look
+ * at any more endpoints.
+ */
+static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,
+			struct usb_device *udev, enum usb3_link_state state)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct usb_host_config *config;
+	char *state_name;
+	int i;
+	u16 timeout = USB3_LPM_DISABLED;
+
+	if (state == USB3_LPM_U1)
+		state_name = "U1";
+	else if (state == USB3_LPM_U2)
+		state_name = "U2";
+	else {
+		dev_warn(&udev->dev, "Can't enable unknown link state %i\n",
+				state);
+		return timeout;
+	}
+
+	if (xhci_check_tier_policy(xhci, udev, state) < 0)
+		return timeout;
+
+	/* Gather some information about the currently installed configuration
+	 * and alternate interface settings.
+	 */
+	if (xhci_update_timeout_for_endpoint(xhci, udev, &udev->ep0.desc,
+			state, &timeout))
+		return timeout;
+
+	config = udev->actconfig;
+	if (!config)
+		return timeout;
+
+	for (i = 0; i < USB_MAXINTERFACES; i++) {
+		struct usb_driver *driver;
+		struct usb_interface *intf = config->interface[i];
+
+		if (!intf)
+			continue;
+
+		/* Check if any currently bound drivers want hub-initiated LPM
+		 * disabled.
+		 */
+		if (intf->dev.driver) {
+			driver = to_usb_driver(intf->dev.driver);
+			if (driver && driver->disable_hub_initiated_lpm) {
+				dev_dbg(&udev->dev, "Hub-initiated %s disabled "
+						"at request of driver %s\n",
+						state_name, driver->name);
+				return xhci_get_timeout_no_hub_lpm(udev, state);
+			}
+		}
+
+		/* Not sure how this could happen... */
+		if (!intf->cur_altsetting)
+			continue;
+
+		if (xhci_update_timeout_for_interface(xhci, udev,
+					intf->cur_altsetting,
+					state, &timeout))
+			return timeout;
+	}
+	return timeout;
+}
+
+/*
+ * Issue an Evaluate Context command to change the Maximum Exit Latency in the
+ * slot context.  If that succeeds, store the new MEL in the xhci_virt_device.
+ */
+static int xhci_change_max_exit_latency(struct xhci_hcd *xhci,
+			struct usb_device *udev, u16 max_exit_latency)
+{
+	struct xhci_virt_device *virt_dev;
+	struct xhci_command *command;
+	struct xhci_input_control_ctx *ctrl_ctx;
+	struct xhci_slot_ctx *slot_ctx;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&xhci->lock, flags);
+	if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) {
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		return 0;
+	}
+
+	/* Attempt to issue an Evaluate Context command to change the MEL. */
+	virt_dev = xhci->devs[udev->slot_id];
+	command = xhci->lpm_command;
+	xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx);
+	spin_unlock_irqrestore(&xhci->lock, flags);
+
+	ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+	ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
+	slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx);
+	slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
+	slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
+
+	xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n");
+	xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id);
+	xhci_dbg_ctx(xhci, command->in_ctx, 0);
+
+	/* Issue and wait for the evaluate context command. */
+	ret = xhci_configure_endpoint(xhci, udev, command,
+			true, true);
+	xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id);
+	xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0);
+
+	if (!ret) {
+		spin_lock_irqsave(&xhci->lock, flags);
+		virt_dev->current_mel = max_exit_latency;
+		spin_unlock_irqrestore(&xhci->lock, flags);
+	}
+	return ret;
+}
+
+static int calculate_max_exit_latency(struct usb_device *udev,
+		enum usb3_link_state state_changed,
+		u16 hub_encoded_timeout)
+{
+	unsigned long long u1_mel_us = 0;
+	unsigned long long u2_mel_us = 0;
+	unsigned long long mel_us = 0;
+	bool disabling_u1;
+	bool disabling_u2;
+	bool enabling_u1;
+	bool enabling_u2;
+
+	disabling_u1 = (state_changed == USB3_LPM_U1 &&
+			hub_encoded_timeout == USB3_LPM_DISABLED);
+	disabling_u2 = (state_changed == USB3_LPM_U2 &&
+			hub_encoded_timeout == USB3_LPM_DISABLED);
+
+	enabling_u1 = (state_changed == USB3_LPM_U1 &&
+			hub_encoded_timeout != USB3_LPM_DISABLED);
+	enabling_u2 = (state_changed == USB3_LPM_U2 &&
+			hub_encoded_timeout != USB3_LPM_DISABLED);
+
+	/* If U1 was already enabled and we're not disabling it,
+	 * or we're going to enable U1, account for the U1 max exit latency.
+	 */
+	if ((udev->u1_params.timeout != USB3_LPM_DISABLED && !disabling_u1) ||
+			enabling_u1)
+		u1_mel_us = DIV_ROUND_UP(udev->u1_params.mel, 1000);
+	if ((udev->u2_params.timeout != USB3_LPM_DISABLED && !disabling_u2) ||
+			enabling_u2)
+		u2_mel_us = DIV_ROUND_UP(udev->u2_params.mel, 1000);
+
+	if (u1_mel_us > u2_mel_us)
+		mel_us = u1_mel_us;
+	else
+		mel_us = u2_mel_us;
+	/* xHCI host controller max exit latency field is only 16 bits wide. */
+	if (mel_us > MAX_EXIT) {
+		dev_warn(&udev->dev, "Link PM max exit latency of %lluus "
+				"is too big.\n", mel_us);
+		return -E2BIG;
+	}
+	return mel_us;
+}
+
+/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
+int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
+			struct usb_device *udev, enum usb3_link_state state)
+{
+	struct xhci_hcd	*xhci;
+	u16 hub_encoded_timeout;
+	int mel;
+	int ret;
+
+	xhci = hcd_to_xhci(hcd);
+	/* The LPM timeout values are pretty host-controller specific, so don't
+	 * enable hub-initiated timeouts unless the vendor has provided
+	 * information about their timeout algorithm.
+	 */
+	if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
+			!xhci->devs[udev->slot_id])
+		return USB3_LPM_DISABLED;
+
+	hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state);
+	mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout);
+	if (mel < 0) {
+		/* Max Exit Latency is too big, disable LPM. */
+		hub_encoded_timeout = USB3_LPM_DISABLED;
+		mel = 0;
+	}
+
+	ret = xhci_change_max_exit_latency(xhci, udev, mel);
+	if (ret)
+		return ret;
+	return hub_encoded_timeout;
+}
+
+int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
+			struct usb_device *udev, enum usb3_link_state state)
+{
+	struct xhci_hcd	*xhci;
+	u16 mel;
+	int ret;
+
+	xhci = hcd_to_xhci(hcd);
+	if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
+			!xhci->devs[udev->slot_id])
+		return 0;
+
+	mel = calculate_max_exit_latency(udev, state, USB3_LPM_DISABLED);
+	ret = xhci_change_max_exit_latency(xhci, udev, mel);
+	if (ret)
+		return ret;
+	return 0;
+}
+#else /* CONFIG_PM */
+
+int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
+			struct usb_device *udev, enum usb3_link_state state)
+{
+	return USB3_LPM_DISABLED;
+}
+
+int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
+			struct usb_device *udev, enum usb3_link_state state)
+{
+	return 0;
+}
+#endif	/* CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+
 /* Once a hub descriptor is fetched for a device, we need to update the xHC's
  * internal data structures for the device.
  */
@@ -4090,7 +4566,6 @@
 	BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
 	/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
 	BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
-	BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
 	return 0;
 unreg_pci:
 	xhci_unregister_pci();
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3d69c4b..de3d6e3 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -362,8 +362,10 @@
  * Timeout can be up to 127us.  0xFF means an infinite timeout.
  */
 #define PORT_U1_TIMEOUT(p)	((p) & 0xff)
+#define PORT_U1_TIMEOUT_MASK	0xff
 /* Inactivity timer value for transitions into U2 */
 #define PORT_U2_TIMEOUT(p)	(((p) & 0xff) << 8)
+#define PORT_U2_TIMEOUT_MASK	(0xff << 8)
 /* Bits 24:31 for port testing */
 
 /* USB2 Protocol PORTSPMSC */
@@ -914,6 +916,8 @@
 	u8				real_port;
 	struct xhci_interval_bw_table	*bw_table;
 	struct xhci_tt_bw_info		*tt_info;
+	/* The current max exit latency for the enabled USB3 link states. */
+	u16				current_mel;
 };
 
 /*
@@ -1362,6 +1366,8 @@
 	u32			suspended_ports;
 	u32			port_remote_wakeup;
 	unsigned long		resume_done[USB_MAXCHILDREN];
+	/* which ports have started to resume */
+	unsigned long		resuming_ports;
 };
 
 static inline unsigned int hcd_index(struct usb_hcd *hcd)
@@ -1422,6 +1428,8 @@
 	/* slot enabling and address device helpers */
 	struct completion	addr_dev;
 	int slot_id;
+	/* For USB 3.0 LPM enable/disable. */
+	struct xhci_command		*lpm_command;
 	/* Internal mirror of the HW's dcbaa */
 	struct xhci_virt_device	*devs[MAX_HC_SLOTS];
 	/* For keeping track of bandwidth domains per roothub. */
@@ -1479,6 +1487,9 @@
 #define XHCI_RESET_ON_RESUME	(1 << 7)
 #define	XHCI_SW_BW_CHECKING	(1 << 8)
 #define XHCI_AMD_0x96_HOST	(1 << 9)
+#define XHCI_TRUST_TX_LENGTH	(1 << 10)
+#define XHCI_LPM_SUPPORT	(1 << 11)
+#define XHCI_INTEL_HOST		(1 << 12)
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
 	/* There are two roothubs to keep track of bus suspend info for */
@@ -1752,7 +1763,7 @@
 int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
 		u32 slot_id, bool command_must_succeed);
 int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
-		u32 slot_id);
+		u32 slot_id, bool command_must_succeed);
 int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
 		unsigned int ep_index);
 int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id);
@@ -1776,6 +1787,10 @@
 /* xHCI roothub code */
 void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
 				int port_id, u32 link_state);
+int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
+			struct usb_device *udev, enum usb3_link_state state);
+int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
+			struct usb_device *udev, enum usb3_link_state state);
 void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
 				int port_id, u32 port_bit);
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 575b56c..7121b50 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -284,18 +284,16 @@
 	int data_received=0, wake_up;
 	unsigned char* b=urb->transfer_buffer;
 	struct mdc800_data* mdc800=urb->context;
+	struct device *dev = &mdc800->dev->dev;
 	int status = urb->status;
 
 	if (status >= 0) {
-
-		//dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
-
 		if (mdc800_isBusy (b))
 		{
 			if (!mdc800->camera_busy)
 			{
 				mdc800->camera_busy=1;
-				dbg ("gets busy");
+				dev_dbg(dev, "gets busy\n");
 			}
 		}
 		else
@@ -303,13 +301,13 @@
 			if (mdc800->camera_busy && mdc800_isReady (b))
 			{
 				mdc800->camera_busy=0;
-				dbg ("gets ready");
+				dev_dbg(dev, "gets ready\n");
 			}
 		}
 		if (!(mdc800_isBusy (b) || mdc800_isReady (b)))
 		{
 			/* Store Data in camera_answer field */
-			dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+			dev_dbg(dev, "%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
 
 			memcpy (mdc800->camera_response,b,8);
 			data_received=1;
@@ -441,7 +439,7 @@
 	int irq_interval=0;
 	int retval;
 
-	dbg ("(mdc800_usb_probe) called.");
+	dev_dbg(&intf->dev, "(%s) called.\n", __func__);
 
 
 	if (mdc800->dev != NULL)
@@ -554,7 +552,7 @@
 {
 	struct mdc800_data* mdc800 = usb_get_intfdata(intf);
 
-	dbg ("(mdc800_usb_disconnect) called");
+	dev_dbg(&intf->dev, "(%s) called\n", __func__);
 
 	if (mdc800) {
 		if (mdc800->state == NOT_CONNECTED)
@@ -656,7 +654,7 @@
 	}
 
 	mdc800->open=1;
-	dbg ("Mustek MDC800 device opened.");
+	dev_dbg(&mdc800->dev->dev, "Mustek MDC800 device opened.\n");
 
 error_out:
 	mutex_unlock(&mdc800->io_lock);
@@ -670,7 +668,6 @@
 static int mdc800_device_release (struct inode* inode, struct file *file)
 {
 	int retval=0;
-	dbg ("Mustek MDC800 device closed.");
 
 	mutex_lock(&mdc800->io_lock);
 	if (mdc800->open && (mdc800->state != NOT_CONNECTED))
@@ -927,7 +924,7 @@
 						{
 							mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2];
 
-							dbg ("cached imagesize = %i",mdc800->pic_len);
+							dev_dbg(&mdc800->dev->dev, "cached imagesize = %i\n", mdc800->pic_len);
 						}
 
 					}
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index ac0d75a..0fc6e5f 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -88,6 +88,7 @@
 static void appledisplay_complete(struct urb *urb)
 {
 	struct appledisplay *pdata = urb->context;
+	struct device *dev = &pdata->udev->dev;
 	unsigned long flags;
 	int status = urb->status;
 	int retval;
@@ -97,18 +98,18 @@
 		/* success */
 		break;
 	case -EOVERFLOW:
-		printk(KERN_ERR "appletouch: OVERFLOW with data "
-			"length %d, actual length is %d\n",
+		dev_err(dev,
+			"OVERFLOW with data length %d, actual length is %d\n",
 			ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
 	case -ECONNRESET:
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* This urb is terminated, clean up */
-		dbg("%s - urb shuttingdown with status: %d",
+		dev_dbg(dev, "%s - urb shuttingdown with status: %d\n",
 			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
+		dev_dbg(dev, "%s - nonzero urb status received: %d/n",
 			__func__, status);
 		goto exit;
 	}
@@ -132,8 +133,7 @@
 exit:
 	retval = usb_submit_urb(pdata->urb, GFP_ATOMIC);
 	if (retval) {
-		dev_err(&pdata->udev->dev,
-			"%s - usb_submit_urb failed with result %d\n",
+		dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
 			__func__, retval);
 	}
 }
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
index da97dce..d65984d 100644
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -78,18 +78,14 @@
 	const struct firmware *bitstream_fw = NULL;
 	const struct firmware *firmware_fw = NULL;
 	const struct ihex_binrec *rec;
-	int err;
+	int err = -ENOMEM;
 	int i;
 	__u32 addr;	/* Address to write */
 	__u8 *buf;
 
 	buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
-	if (!buf) {
-		dev_err(&dev->dev, "%s - error loading firmware: error = %d\n",
-			__func__, -ENOMEM);
-		err = -ENOMEM;
+	if (!buf)
 		goto wraperr;
-	}
 
 	err = request_ihex_firmware(&loader_fw, "emi26/loader.fw", &dev->dev);
 	if (err)
@@ -111,11 +107,8 @@
 
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi26_set_reset(dev,1);
-	if (err < 0) {
-		dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
-			__func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 
 	rec = (const struct ihex_binrec *)loader_fw->data;
 	/* 1. We need to put the loader for the FPGA into the EZ-USB */
@@ -123,19 +116,15 @@
 		err = emi26_writememory(dev, be32_to_cpu(rec->addr),
 					rec->data, be16_to_cpu(rec->len),
 					ANCHOR_LOAD_INTERNAL);
-		if (err < 0) {
-			err("%s - error loading firmware: error = %d", __func__, err);
+		if (err < 0)
 			goto wraperr;
-		}
 		rec = ihex_next_binrec(rec);
 	}
 
 	/* De-assert reset (let the CPU run) */
 	err = emi26_set_reset(dev,0);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 	msleep(250);	/* let device settle */
 
 	/* 2. We upload the FPGA firmware into the EMI
@@ -153,18 +142,14 @@
 			rec = ihex_next_binrec(rec);
 		}
 		err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
-		if (err < 0) {
-			err("%s - error loading firmware: error = %d", __func__, err);
+		if (err < 0)
 			goto wraperr;
-		}
 	} while (rec);
 
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi26_set_reset(dev,1);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 
 	/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
 	for (rec = (const struct ihex_binrec *)loader_fw->data;
@@ -172,19 +157,15 @@
 		err = emi26_writememory(dev, be32_to_cpu(rec->addr),
 					rec->data, be16_to_cpu(rec->len),
 					ANCHOR_LOAD_INTERNAL);
-		if (err < 0) {
-			err("%s - error loading firmware: error = %d", __func__, err);
+		if (err < 0)
 			goto wraperr;
-		}
 	}
 	msleep(250);	/* let device settle */
 
 	/* De-assert reset (let the CPU run) */
 	err = emi26_set_reset(dev,0);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 
 	/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
 
@@ -194,19 +175,15 @@
 			err = emi26_writememory(dev, be32_to_cpu(rec->addr),
 						rec->data, be16_to_cpu(rec->len),
 						ANCHOR_LOAD_EXTERNAL);
-			if (err < 0) {
-				err("%s - error loading firmware: error = %d", __func__, err);
+			if (err < 0)
 				goto wraperr;
-			}
 		}
 	}
-	
+
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi26_set_reset(dev,1);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 
 	for (rec = (const struct ihex_binrec *)firmware_fw->data;
 	     rec; rec = ihex_next_binrec(rec)) {
@@ -214,19 +191,15 @@
 			err = emi26_writememory(dev, be32_to_cpu(rec->addr),
 						rec->data, be16_to_cpu(rec->len),
 						ANCHOR_LOAD_INTERNAL);
-			if (err < 0) {
-				err("%s - error loading firmware: error = %d", __func__, err);
+			if (err < 0)
 				goto wraperr;
-			}
 		}
 	}
 
 	/* De-assert reset (let the CPU run) */
 	err = emi26_set_reset(dev,0);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 	msleep(250);	/* let device settle */
 
 	/* return 1 to fail the driver inialization
@@ -234,6 +207,10 @@
 	err = 1;
 
 wraperr:
+	if (err < 0)
+		dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
+			__func__, err);
+
 	release_firmware(loader_fw);
 	release_firmware(bitstream_fw);
 	release_firmware(firmware_fw);
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index 4e0f167..ff08015 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -56,7 +56,7 @@
 	unsigned char *buffer =  kmemdup(data, length, GFP_KERNEL);
 
 	if (!buffer) {
-		err("emi62: kmalloc(%d) failed.", length);
+		dev_err(&dev->dev, "kmalloc(%d) failed.\n", length);
 		return -ENOMEM;
 	}
 	/* Note: usb_control_msg returns negative value on error or length of the
@@ -73,9 +73,8 @@
 	dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit);
 	
 	response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
-	if (response < 0) {
-		err("emi62: set_reset (%d) failed", reset_bit);
-	}
+	if (response < 0)
+		dev_err(&dev->dev, "set_reset (%d) failed\n", reset_bit);
 	return response;
 }
 
@@ -87,18 +86,15 @@
 	const struct firmware *bitstream_fw = NULL;
 	const struct firmware *firmware_fw = NULL;
 	const struct ihex_binrec *rec;
-	int err;
+	int err = -ENOMEM;
 	int i;
 	__u32 addr;	/* Address to write */
 	__u8 *buf;
 
 	dev_dbg(&dev->dev, "load_firmware\n");
 	buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
-	if (!buf) {
-		err( "%s - error loading firmware: error = %d", __func__, -ENOMEM);
-		err = -ENOMEM;
+	if (!buf)
 		goto wraperr;
-	}
 
 	err = request_ihex_firmware(&loader_fw, "emi62/loader.fw", &dev->dev);
 	if (err)
@@ -112,16 +108,13 @@
 	err = request_ihex_firmware(&firmware_fw, FIRMWARE_FW, &dev->dev);
 	if (err) {
 	nofw:
-		err( "%s - request_firmware() failed", __func__);
 		goto wraperr;
 	}
 
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi62_set_reset(dev,1);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 
 	rec = (const struct ihex_binrec *)loader_fw->data;
 
@@ -130,19 +123,15 @@
 		err = emi62_writememory(dev, be32_to_cpu(rec->addr),
 					rec->data, be16_to_cpu(rec->len),
 					ANCHOR_LOAD_INTERNAL);
-		if (err < 0) {
-			err("%s - error loading firmware: error = %d", __func__, err);
+		if (err < 0)
 			goto wraperr;
-		}
 		rec = ihex_next_binrec(rec);
 	}
 
 	/* De-assert reset (let the CPU run) */
 	err = emi62_set_reset(dev,0);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 	msleep(250);	/* let device settle */
 
 	/* 2. We upload the FPGA firmware into the EMI
@@ -160,18 +149,14 @@
 			rec = ihex_next_binrec(rec);
 		}
 		err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
-		if (err < 0) {
-			err("%s - error loading firmware: error = %d", __func__, err);
+		if (err < 0)
 			goto wraperr;
-		}
 	} while (rec);
 
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi62_set_reset(dev,1);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 
 	/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
 	for (rec = (const struct ihex_binrec *)loader_fw->data;
@@ -179,18 +164,14 @@
 		err = emi62_writememory(dev, be32_to_cpu(rec->addr),
 					rec->data, be16_to_cpu(rec->len),
 					ANCHOR_LOAD_INTERNAL);
-		if (err < 0) {
-			err("%s - error loading firmware: error = %d", __func__, err);
+		if (err < 0)
 			goto wraperr;
-		}
 	}
 
 	/* De-assert reset (let the CPU run) */
 	err = emi62_set_reset(dev,0);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 	msleep(250);	/* let device settle */
 
 	/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
@@ -201,19 +182,15 @@
 			err = emi62_writememory(dev, be32_to_cpu(rec->addr),
 						rec->data, be16_to_cpu(rec->len),
 						ANCHOR_LOAD_EXTERNAL);
-			if (err < 0) {
-				err("%s - error loading firmware: error = %d", __func__, err);
+			if (err < 0)
 				goto wraperr;
-			}
 		}
 	}
 
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi62_set_reset(dev,1);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 
 	for (rec = (const struct ihex_binrec *)firmware_fw->data;
 	     rec; rec = ihex_next_binrec(rec)) {
@@ -221,19 +198,15 @@
 			err = emi62_writememory(dev, be32_to_cpu(rec->addr),
 						rec->data, be16_to_cpu(rec->len),
 						ANCHOR_LOAD_EXTERNAL);
-			if (err < 0) {
-				err("%s - error loading firmware: error = %d", __func__, err);
+			if (err < 0)
 				goto wraperr;
-			}
 		}
 	}
 
 	/* De-assert reset (let the CPU run) */
 	err = emi62_set_reset(dev,0);
-	if (err < 0) {
-		err("%s - error loading firmware: error = %d", __func__, err);
+	if (err < 0)
 		goto wraperr;
-	}
 	msleep(250);	/* let device settle */
 
 	release_firmware(loader_fw);
@@ -247,6 +220,9 @@
 	return 1;
 
 wraperr:
+	if (err < 0)
+		dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
+			__func__, err);
 	release_firmware(loader_fw);
 	release_firmware(bitstream_fw);
 	release_firmware(firmware_fw);
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 0dee246..ce97838 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -200,7 +200,8 @@
 			return -EAGAIN;
 
 	/* should be IMGSIZE == 65040 */
-	dbg("read %d bytes fingerprint data", bytes_read);
+	dev_dbg(&dev->interface->dev, "read %d bytes fingerprint data\n",
+		bytes_read);
 	return result;
 }
 
@@ -366,14 +367,14 @@
 			kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
 
 		if (!dev->bulk_in_buffer) {
-			err("Unable to allocate input buffer.");
+			dev_err(&interface->dev, "Unable to allocate input buffer.\n");
 			idmouse_delete(dev);
 			return -ENOMEM;
 		}
 	}
 
 	if (!(dev->bulk_in_endpointAddr)) {
-		err("Unable to find bulk-in endpoint.");
+		dev_err(&interface->dev, "Unable to find bulk-in endpoint.\n");
 		idmouse_delete(dev);
 		return -ENODEV;
 	}
@@ -385,7 +386,7 @@
 	result = usb_register_dev(interface, &idmouse_class);
 	if (result) {
 		/* something prevented us from registering this device */
-		err("Unble to allocate minor number.");
+		dev_err(&interface->dev, "Unble to allocate minor number.\n");
 		usb_set_intfdata(interface, NULL);
 		idmouse_delete(dev);
 		return result;
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 4fd0dc8..db46143 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -610,8 +610,8 @@
 	interface = usb_find_interface(&iowarrior_driver, subminor);
 	if (!interface) {
 		mutex_unlock(&iowarrior_mutex);
-		err("%s - error, can't find device for minor %d", __func__,
-		    subminor);
+		printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+		       __func__, subminor);
 		return -ENODEV;
 	}
 
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 5db4ab5..ac76229 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -334,8 +334,8 @@
 	interface = usb_find_interface(&ld_usb_driver, subminor);
 
 	if (!interface) {
-		err("%s - error, can't find device for minor %d\n",
-		     __func__, subminor);
+		printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+		       __func__, subminor);
 		return -ENODEV;
 	}
 
@@ -485,7 +485,7 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->intf == NULL) {
 		retval = -ENODEV;
-		err("No device or device unplugged %d\n", retval);
+		printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
 		goto unlock_exit;
 	}
 
@@ -565,7 +565,7 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->intf == NULL) {
 		retval = -ENODEV;
-		err("No device or device unplugged %d\n", retval);
+		printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
 		goto unlock_exit;
 	}
 
@@ -603,7 +603,9 @@
 					 bytes_to_write,
 					 USB_CTRL_SET_TIMEOUT * HZ);
 		if (retval < 0)
-			err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval);
+			dev_err(&dev->intf->dev,
+				"Couldn't submit HID_REQ_SET_REPORT %d\n",
+				retval);
 		goto unlock_exit;
 	}
 
@@ -624,7 +626,8 @@
 	retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
 	if (retval) {
 		dev->interrupt_out_busy = 0;
-		err("Couldn't submit interrupt_out_urb %d\n", retval);
+		dev_err(&dev->intf->dev,
+			"Couldn't submit interrupt_out_urb %d\n", retval);
 		goto unlock_exit;
 	}
 	retval = bytes_to_write;
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 5752220..a2702cb 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -354,8 +354,8 @@
 	interface = usb_find_interface (&tower_driver, subminor);
 
 	if (!interface) {
-		err ("%s - error, can't find device for minor %d",
-		     __func__, subminor);
+		printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+		       __func__, subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
@@ -397,7 +397,8 @@
 				  sizeof(reset_reply),
 				  1000);
 	if (result < 0) {
-		err("LEGO USB Tower reset control request failed");
+		dev_err(&dev->udev->dev,
+			"LEGO USB Tower reset control request failed\n");
 		retval = result;
 		goto unlock_exit;
 	}
@@ -420,7 +421,8 @@
 
 	retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL);
 	if (retval) {
-		err("Couldn't submit interrupt_in_urb %d", retval);
+		dev_err(&dev->udev->dev,
+			"Couldn't submit interrupt_in_urb %d\n", retval);
 		dev->interrupt_in_running = 0;
 		dev->open_count = 0;
 		goto unlock_exit;
@@ -608,7 +610,7 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->udev == NULL) {
 		retval = -ENODEV;
-		err("No device or device unplugged %d", retval);
+		printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
 		goto unlock_exit;
 	}
 
@@ -697,7 +699,7 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->udev == NULL) {
 		retval = -ENODEV;
-		err("No device or device unplugged %d", retval);
+		printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
 		goto unlock_exit;
 	}
 
@@ -744,7 +746,8 @@
 	retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL);
 	if (retval) {
 		dev->interrupt_out_busy = 0;
-		err("Couldn't submit interrupt_out_urb %d", retval);
+		dev_err(&dev->udev->dev,
+			"Couldn't submit interrupt_out_urb %d\n", retval);
 		goto unlock_exit;
 	}
 	retval = bytes_to_write;
@@ -803,9 +806,10 @@
 	/* resubmit if we're still running */
 	if (dev->interrupt_in_running && dev->udev) {
 		retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);
-		if (retval) {
-			err("%s: usb_submit_urb failed (%d)", __func__, retval);
-		}
+		if (retval)
+			dev_err(&dev->udev->dev,
+				"%s: usb_submit_urb failed (%d)\n",
+				__func__, retval);
 	}
 
 exit:
@@ -852,6 +856,7 @@
  */
 static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id)
 {
+	struct device *idev = &interface->dev;
 	struct usb_device *udev = interface_to_usbdev(interface);
 	struct lego_usb_tower *dev = NULL;
 	struct usb_host_interface *iface_desc;
@@ -871,7 +876,7 @@
 	dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
 
 	if (dev == NULL) {
-		err ("Out of memory");
+		dev_err(idev, "Out of memory\n");
 		goto exit;
 	}
 
@@ -915,37 +920,37 @@
 		}
 	}
 	if(dev->interrupt_in_endpoint == NULL) {
-		err("interrupt in endpoint not found");
+		dev_err(idev, "interrupt in endpoint not found\n");
 		goto error;
 	}
 	if (dev->interrupt_out_endpoint == NULL) {
-		err("interrupt out endpoint not found");
+		dev_err(idev, "interrupt out endpoint not found\n");
 		goto error;
 	}
 
 	dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL);
 	if (!dev->read_buffer) {
-		err("Couldn't allocate read_buffer");
+		dev_err(idev, "Couldn't allocate read_buffer\n");
 		goto error;
 	}
 	dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL);
 	if (!dev->interrupt_in_buffer) {
-		err("Couldn't allocate interrupt_in_buffer");
+		dev_err(idev, "Couldn't allocate interrupt_in_buffer\n");
 		goto error;
 	}
 	dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!dev->interrupt_in_urb) {
-		err("Couldn't allocate interrupt_in_urb");
+		dev_err(idev, "Couldn't allocate interrupt_in_urb\n");
 		goto error;
 	}
 	dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL);
 	if (!dev->interrupt_out_buffer) {
-		err("Couldn't allocate interrupt_out_buffer");
+		dev_err(idev, "Couldn't allocate interrupt_out_buffer\n");
 		goto error;
 	}
 	dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!dev->interrupt_out_urb) {
-		err("Couldn't allocate interrupt_out_urb");
+		dev_err(idev, "Couldn't allocate interrupt_out_urb\n");
 		goto error;
 	}
 	dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
@@ -958,7 +963,7 @@
 
 	if (retval) {
 		/* something prevented us from registering this driver */
-		err ("Not able to get a minor for this device.");
+		dev_err(idev, "Not able to get a minor for this device.\n");
 		usb_set_intfdata (interface, NULL);
 		goto error;
 	}
@@ -980,7 +985,7 @@
 				  sizeof(get_version_reply),
 				  1000);
 	if (result < 0) {
-		err("LEGO USB Tower get version control request failed");
+		dev_err(idev, "LEGO USB Tower get version control request failed\n");
 		retval = result;
 		goto error;
 	}
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 487a8ce..1084124 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -153,10 +153,10 @@
 
 		requesttype = rio_cmd.requesttype | USB_DIR_IN |
 		    USB_TYPE_VENDOR | USB_RECIP_DEVICE;
-		dbg
-		    ("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
-		     requesttype, rio_cmd.request, rio_cmd.value,
-		     rio_cmd.index, rio_cmd.length);
+		dev_dbg(&rio->rio_dev->dev,
+			"sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
+			requesttype, rio_cmd.request, rio_cmd.value,
+			rio_cmd.index, rio_cmd.length);
 		/* Send rio control message */
 		retries = 3;
 		while (retries) {
@@ -171,11 +171,14 @@
 			if (result == -ETIMEDOUT)
 				retries--;
 			else if (result < 0) {
-				err("Error executing ioctrl. code = %d", result);
+				dev_err(&rio->rio_dev->dev,
+					"Error executing ioctrl. code = %d\n",
+					result);
 				retries = 0;
 			} else {
-				dbg("Executed ioctl. Result = %d (data=%02x)",
-				     result, buffer[0]);
+				dev_dbg(&rio->rio_dev->dev,
+					"Executed ioctl. Result = %d (data=%02x)\n",
+					result, buffer[0]);
 				if (copy_to_user(rio_cmd.buffer, buffer,
 						 rio_cmd.length)) {
 					free_page((unsigned long) buffer);
@@ -221,9 +224,10 @@
 
 		requesttype = rio_cmd.requesttype | USB_DIR_OUT |
 		    USB_TYPE_VENDOR | USB_RECIP_DEVICE;
-		dbg("sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
-		     requesttype, rio_cmd.request, rio_cmd.value,
-		     rio_cmd.index, rio_cmd.length);
+		dev_dbg(&rio->rio_dev->dev,
+			"sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
+			requesttype, rio_cmd.request, rio_cmd.value,
+			rio_cmd.index, rio_cmd.length);
 		/* Send rio control message */
 		retries = 3;
 		while (retries) {
@@ -238,10 +242,13 @@
 			if (result == -ETIMEDOUT)
 				retries--;
 			else if (result < 0) {
-				err("Error executing ioctrl. code = %d", result);
+				dev_err(&rio->rio_dev->dev,
+					"Error executing ioctrl. code = %d\n",
+					result);
 				retries = 0;
 			} else {
-				dbg("Executed ioctl. Result = %d", result);
+				dev_dbg(&rio->rio_dev->dev,
+					"Executed ioctl. Result = %d\n", result);
 				retries = 0;
 
 			}
@@ -313,8 +320,9 @@
 					 usb_sndbulkpipe(rio->rio_dev, 2),
 					 obuf, thistime, &partial, 5000);
 
-			dbg("write stats: result:%d thistime:%lu partial:%u",
-			     result, thistime, partial);
+			dev_dbg(&rio->rio_dev->dev,
+				"write stats: result:%d thistime:%lu partial:%u\n",
+				result, thistime, partial);
 
 			if (result == -ETIMEDOUT) {	/* NAK - so hold for a while */
 				if (!maxretry--) {
@@ -332,7 +340,8 @@
 				break;
 		};
 		if (result) {
-			err("Write Whoops - %x", result);
+			dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n",
+				result);
 			errn = -EIO;
 			goto error;
 		}
@@ -393,15 +402,17 @@
 				      ibuf, this_read, &partial,
 				      8000);
 
-		dbg("read stats: result:%d this_read:%u partial:%u",
-		       result, this_read, partial);
+		dev_dbg(&rio->rio_dev->dev,
+			"read stats: result:%d this_read:%u partial:%u\n",
+			result, this_read, partial);
 
 		if (partial) {
 			count = this_read = partial;
 		} else if (result == -ETIMEDOUT || result == 15) {	/* FIXME: 15 ??? */
 			if (!maxretry--) {
 				mutex_unlock(&(rio->lock));
-				err("read_rio: maxretry timeout");
+				dev_err(&rio->rio_dev->dev,
+					"read_rio: maxretry timeout\n");
 				return -ETIME;
 			}
 			prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
@@ -410,8 +421,9 @@
 			continue;
 		} else if (result != -EREMOTEIO) {
 			mutex_unlock(&(rio->lock));
-			err("Read Whoops - result:%u partial:%u this_read:%u",
-			     result, partial, this_read);
+			dev_err(&rio->rio_dev->dev,
+				"Read Whoops - result:%u partial:%u this_read:%u\n",
+				result, partial, this_read);
 			return -EIO;
 		} else {
 			mutex_unlock(&(rio->lock));
@@ -459,26 +471,29 @@
 
 	retval = usb_register_dev(intf, &usb_rio_class);
 	if (retval) {
-		err("Not able to get a minor for this device.");
+		dev_err(&dev->dev,
+			"Not able to get a minor for this device.\n");
 		return -ENOMEM;
 	}
 
 	rio->rio_dev = dev;
 
 	if (!(rio->obuf = kmalloc(OBUF_SIZE, GFP_KERNEL))) {
-		err("probe_rio: Not enough memory for the output buffer");
+		dev_err(&dev->dev,
+			"probe_rio: Not enough memory for the output buffer\n");
 		usb_deregister_dev(intf, &usb_rio_class);
 		return -ENOMEM;
 	}
-	dbg("probe_rio: obuf address:%p", rio->obuf);
+	dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf);
 
 	if (!(rio->ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL))) {
-		err("probe_rio: Not enough memory for the input buffer");
+		dev_err(&dev->dev,
+			"probe_rio: Not enough memory for the input buffer\n");
 		usb_deregister_dev(intf, &usb_rio_class);
 		kfree(rio->obuf);
 		return -ENOMEM;
 	}
-	dbg("probe_rio: ibuf address:%p", rio->ibuf);
+	dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf);
 
 	mutex_init(&(rio->lock));
 
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index e2b4bd3..89927bc 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -87,8 +87,8 @@
 	interface = usb_find_interface(&lcd_driver, subminor);
 	if (!interface) {
 		mutex_unlock(&lcd_mutex);
-		err("USBLCD: %s - error, can't find device for minor %d",
-		     __func__, subminor);
+		printk(KERN_ERR "USBLCD: %s - error, can't find device for minor %d\n",
+		       __func__, subminor);
 		return -ENODEV;
 	}
 
@@ -209,8 +209,8 @@
 	    !(status == -ENOENT ||
 	      status == -ECONNRESET ||
 	      status == -ESHUTDOWN)) {
-		dbg("USBLCD: %s - nonzero write bulk status received: %d",
-		    __func__, status);
+		dev_dbg(&dev->interface->dev,
+			"nonzero write bulk status received: %d\n", status);
 	}
 
 	/* free up our allocated buffer */
@@ -268,8 +268,9 @@
 	/* send the data out the bulk port */
 	retval = usb_submit_urb(urb, GFP_KERNEL);
 	if (retval) {
-		err("USBLCD: %s - failed submitting write urb, error %d",
-		    __func__, retval);
+		dev_err(&dev->udev->dev,
+			"%s - failed submitting write urb, error %d\n",
+			__func__, retval);
 		goto error_unanchor;
 	}
 
@@ -322,7 +323,7 @@
 	/* allocate memory for our device state and initialize it */
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
-		err("Out of memory");
+		dev_err(&interface->dev, "Out of memory\n");
 		goto error;
 	}
 	kref_init(&dev->kref);
@@ -352,7 +353,8 @@
 			dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
 			dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
 			if (!dev->bulk_in_buffer) {
-				err("Could not allocate bulk_in_buffer");
+				dev_err(&interface->dev,
+					"Could not allocate bulk_in_buffer\n");
 				goto error;
 			}
 		}
@@ -364,7 +366,8 @@
 		}
 	}
 	if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
-		err("Could not find both bulk-in and bulk-out endpoints");
+		dev_err(&interface->dev,
+			"Could not find both bulk-in and bulk-out endpoints\n");
 		goto error;
 	}
 
@@ -375,7 +378,8 @@
 	retval = usb_register_dev(interface, &lcd_class);
 	if (retval) {
 		/* something prevented us from registering this driver */
-		err("Not able to get a minor for this device.");
+		dev_err(&interface->dev,
+			"Not able to get a minor for this device.\n");
 		usb_set_intfdata(interface, NULL);
 		goto error;
 	}
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 9dcb68f..055b84a 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1028,7 +1028,10 @@
 		case 13:	/* short read, resembling case 10 */
 			req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0);
 			/* last data packet "should" be DATA1, not DATA0 */
-			len = 1024 - udev->descriptor.bMaxPacketSize0;
+			if (udev->speed == USB_SPEED_SUPER)
+				len = 1024 - 512;
+			else
+				len = 1024 - udev->descriptor.bMaxPacketSize0;
 			expected = -EREMOTEIO;
 			break;
 		case 14:	/* short read; try to fill the last packet */
@@ -1387,11 +1390,15 @@
 
 static int halt_simple(struct usbtest_dev *dev)
 {
-	int		ep;
-	int		retval = 0;
-	struct urb	*urb;
+	int			ep;
+	int			retval = 0;
+	struct urb		*urb;
+	struct usb_device	*udev = testdev_to_usbdev(dev);
 
-	urb = simple_alloc_urb(testdev_to_usbdev(dev), 0, 512);
+	if (udev->speed == USB_SPEED_SUPER)
+		urb = simple_alloc_urb(udev, 0, 1024);
+	else
+		urb = simple_alloc_urb(udev, 0, 512);
 	if (urb == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 8b1d94a..29cad9e 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -85,9 +85,9 @@
 {
 	struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count);
 
+	dev_dbg(&priv->usbdev->dev, "destroying priv datastructure\n");
 	usb_put_dev(priv->usbdev);
 	kfree(priv);
-	dbg("destroying priv datastructure");
 }
 
 static void destroy_async(struct kref *kref)
@@ -118,14 +118,17 @@
 	priv = rq->priv;
 	pp = priv->pp;
 	if (status) {
-		err("async_complete: urb error %d", status);
+		dev_err(&urb->dev->dev, "async_complete: urb error %d\n",
+			status);
 	} else if (rq->dr.bRequest == 3) {
 		memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
-		dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x",
-		    (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2],
-		    (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
-		    (unsigned int)priv->reg[6]);
+		dev_dbg(&priv->usbdev->dev,
+			"async_complete regs %02x %02x %02x %02x %02x %02x %02x\n",
+			(unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
+			(unsigned int)priv->reg[2], (unsigned int)priv->reg[3],
+			(unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
+			(unsigned int)priv->reg[6]);
 #endif
 		/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
 		if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
@@ -151,7 +154,7 @@
 		return NULL;
 	rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);
 	if (!rq) {
-		err("submit_async_request out of memory");
+		dev_err(&usbdev->dev, "submit_async_request out of memory\n");
 		return NULL;
 	}
 	kref_init(&rq->ref_count);
@@ -162,7 +165,7 @@
 	rq->urb = usb_alloc_urb(0, mem_flags);
 	if (!rq->urb) {
 		kref_put(&rq->ref_count, destroy_async);
-		err("submit_async_request out of memory");
+		dev_err(&usbdev->dev, "submit_async_request out of memory\n");
 		return NULL;
 	}
 	rq->dr.bRequestType = requesttype;
@@ -182,7 +185,7 @@
 	if (!ret)
 		return rq;
 	destroy_async(&rq->ref_count);
-	err("submit_async_request submit_urb failed with %d", ret);
+	dev_err(&usbdev->dev, "submit_async_request submit_urb failed with %d\n", ret);
 	return NULL;
 }
 
@@ -217,7 +220,8 @@
 	priv = pp->private_data;
 	rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags);
 	if (!rq) {
-		err("get_1284_register(%u) failed", (unsigned int)reg);
+		dev_err(&priv->usbdev->dev, "get_1284_register(%u) failed",
+			(unsigned int)reg);
 		return -EIO;
 	}
 	if (!val) {
@@ -248,7 +252,8 @@
 	priv = pp->private_data;
 	rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags);
 	if (!rq) {
-		err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val);
+		dev_err(&priv->usbdev->dev, "set_1284_register(%u,%u) failed",
+			(unsigned int)reg, (unsigned int)val);
 		return -EIO;
 	}
 	kref_put(&rq->ref_count, destroy_async);
@@ -690,9 +695,9 @@
 	unsigned char reg;
 	int i;
 
-	dbg("probe: vendor id 0x%x, device id 0x%x\n",
-	    le16_to_cpu(usbdev->descriptor.idVendor),
-	    le16_to_cpu(usbdev->descriptor.idProduct));
+	dev_dbg(&intf->dev, "probe: vendor id 0x%x, device id 0x%x\n",
+		le16_to_cpu(usbdev->descriptor.idVendor),
+		le16_to_cpu(usbdev->descriptor.idProduct));
 
 	/* our known interfaces have 3 alternate settings */
 	if (intf->num_altsetting != 3) {
@@ -700,7 +705,7 @@
 		return -ENODEV;
 	}
 	i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
-	dbg("set inteface result %d", i);
+	dev_dbg(&intf->dev, "set inteface result %d\n", i);
 
 	interface = intf->cur_altsetting;
 
@@ -731,11 +736,13 @@
 	set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
 	/* debugging */
 	get_1284_register(pp, 0, &reg, GFP_KERNEL);
-	dbg("reg: %02x %02x %02x %02x %02x %02x %02x",
-	    priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
+	dev_dbg(&intf->dev, "reg: %02x %02x %02x %02x %02x %02x %02x\n",
+		priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3],
+		priv->reg[4], priv->reg[5], priv->reg[6]);
 
 	endpoint = &interface->endpoint[2];
-	dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
+	dev_dbg(&intf->dev, "epaddr %d interval %d\n",
+		endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
 	parport_announce_port(pp);
 
 	usb_set_intfdata(intf, pp);
@@ -753,20 +760,20 @@
 	struct parport_uss720_private *priv;
 	struct usb_device *usbdev;
 
-	dbg("disconnect");
+	dev_dbg(&intf->dev, "disconnect\n");
 	usb_set_intfdata(intf, NULL);
 	if (pp) {
 		priv = pp->private_data;
 		usbdev = priv->usbdev;
 		priv->usbdev = NULL;
 		priv->pp = NULL;
-		dbg("parport_remove_port");
+		dev_dbg(&intf->dev, "parport_remove_port\n");
 		parport_remove_port(pp);
 		parport_put_port(pp);
 		kill_all_async_requests_priv(priv);
 		kref_put(&priv->ref_count, destroy_priv);
 	}
-	dbg("disconnect done");
+	dev_dbg(&intf->dev, "disconnect done\n");
 }
 
 /* table of cables that work through this driver */
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 7020146..42ad2e6 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -83,7 +83,8 @@
 	int status = urb->status;
 
 	if (status) {
-		err("%s - control failed: %d\n", __func__, status);
+		dev_err(&urb->dev->dev, "%s - control failed: %d\n",
+			__func__, status);
 		wake_up_interruptible(&dev->waitq);
 		return;
 	}
@@ -94,7 +95,7 @@
 {
 	struct usb_yurex *dev = to_yurex_dev(kref);
 
-	dbg("yurex_delete");
+	dev_dbg(&dev->interface->dev, "%s\n", __func__);
 
 	usb_put_dev(dev->udev);
 	if (dev->cntl_urb) {
@@ -137,8 +138,9 @@
 	case 0: /*success*/
 		break;
 	case -EOVERFLOW:
-		err("%s - overflow with length %d, actual length is %d",
-		    __func__, YUREX_BUF_SIZE, dev->urb->actual_length);
+		dev_err(&dev->interface->dev,
+			"%s - overflow with length %d, actual length is %d\n",
+			__func__, YUREX_BUF_SIZE, dev->urb->actual_length);
 	case -ECONNRESET:
 	case -ENOENT:
 	case -ESHUTDOWN:
@@ -146,7 +148,8 @@
 		/* The device is terminated, clean up */
 		return;
 	default:
-		err("%s - unknown status received: %d", __func__, status);
+		dev_err(&dev->interface->dev,
+			"%s - unknown status received: %d\n", __func__, status);
 		goto exit;
 	}
 
@@ -162,16 +165,19 @@
 				if (i != 5)
 					dev->bbu <<= 8;
 			}
-			dbg("%s count: %lld", __func__, dev->bbu);
+			dev_dbg(&dev->interface->dev, "%s count: %lld\n",
+				__func__, dev->bbu);
 			spin_unlock_irqrestore(&dev->lock, flags);
 
 			kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
 		}
 		else
-			dbg("data format error - no EOF");
+			dev_dbg(&dev->interface->dev,
+				"data format error - no EOF\n");
 		break;
 	case CMD_ACK:
-		dbg("%s ack: %c", __func__, buf[1]);
+		dev_dbg(&dev->interface->dev, "%s ack: %c\n",
+			__func__, buf[1]);
 		wake_up_interruptible(&dev->waitq);
 		break;
 	}
@@ -179,7 +185,7 @@
 exit:
 	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
 	if (retval) {
-		err("%s - usb_submit_urb failed: %d",
+		dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n",
 			__func__, retval);
 	}
 }
@@ -196,7 +202,7 @@
 	/* allocate memory for our device state and initialize it */
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev) {
-		err("Out of memory");
+		dev_err(&interface->dev, "Out of memory\n");
 		goto error;
 	}
 	kref_init(&dev->kref);
@@ -219,7 +225,7 @@
 	}
 	if (!dev->int_in_endpointAddr) {
 		retval = -ENODEV;
-		err("Could not find endpoints");
+		dev_err(&interface->dev, "Could not find endpoints\n");
 		goto error;
 	}
 
@@ -227,14 +233,14 @@
 	/* allocate control URB */
 	dev->cntl_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!dev->cntl_urb) {
-		err("Could not allocate control URB");
+		dev_err(&interface->dev, "Could not allocate control URB\n");
 		goto error;
 	}
 
 	/* allocate buffer for control req */
 	dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL);
 	if (!dev->cntl_req) {
-		err("Could not allocate cntl_req");
+		dev_err(&interface->dev, "Could not allocate cntl_req\n");
 		goto error;
 	}
 
@@ -243,7 +249,7 @@
 					      GFP_KERNEL,
 					      &dev->cntl_urb->transfer_dma);
 	if (!dev->cntl_buffer) {
-		err("Could not allocate cntl_buffer");
+		dev_err(&interface->dev, "Could not allocate cntl_buffer\n");
 		goto error;
 	}
 
@@ -265,7 +271,7 @@
 	/* allocate interrupt URB */
 	dev->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!dev->urb) {
-		err("Could not allocate URB");
+		dev_err(&interface->dev, "Could not allocate URB\n");
 		goto error;
 	}
 
@@ -273,7 +279,7 @@
 	dev->int_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE,
 					GFP_KERNEL, &dev->urb->transfer_dma);
 	if (!dev->int_buffer) {
-		err("Could not allocate int_buffer");
+		dev_err(&interface->dev, "Could not allocate int_buffer\n");
 		goto error;
 	}
 
@@ -285,7 +291,7 @@
 	dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	if (usb_submit_urb(dev->urb, GFP_KERNEL)) {
 		retval = -EIO;
-		err("Could not submitting URB");
+		dev_err(&interface->dev, "Could not submitting URB\n");
 		goto error;
 	}
 
@@ -295,7 +301,8 @@
 	/* we can register the device now, as it is ready */
 	retval = usb_register_dev(interface, &yurex_class);
 	if (retval) {
-		err("Not able to get a minor for this device.");
+		dev_err(&interface->dev,
+			"Not able to get a minor for this device.\n");
 		usb_set_intfdata(interface, NULL);
 		goto error;
 	}
@@ -368,8 +375,8 @@
 
 	interface = usb_find_interface(&yurex_driver, subminor);
 	if (!interface) {
-		err("%s - error, can't find device for minor %d",
-		    __func__, subminor);
+		printk(KERN_ERR "%s - error, can't find device for minor %d",
+		       __func__, subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
@@ -505,7 +512,8 @@
 
 	/* send the data as the control msg */
 	prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE);
-	dbg("%s - submit %c", __func__, dev->cntl_buffer[0]);
+	dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__,
+		dev->cntl_buffer[0]);
 	retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL);
 	if (retval >= 0)
 		timeout = schedule_timeout(YUREX_WRITE_TIMEOUT);
@@ -514,7 +522,9 @@
 	mutex_unlock(&dev->io_mutex);
 
 	if (retval < 0) {
-		err("%s - failed to send bulk msg, error %d", __func__, retval);
+		dev_err(&dev->interface->dev,
+			"%s - failed to send bulk msg, error %d\n",
+			__func__, retval);
 		goto error;
 	}
 	if (set && timeout)
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index f70cab3..ef0c3f9 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -8,6 +8,7 @@
 	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
 	depends on USB && USB_GADGET
 	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
+	select NOP_USB_XCEIV if (SOC_OMAPTI81XX || SOC_OMAPAM33XX)
 	select TWL4030_USB if MACH_OMAP_3430SDP
 	select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
 	select USB_OTG_UTILS
@@ -54,6 +55,10 @@
 	tristate "AM35x"
 	depends on ARCH_OMAP
 
+config USB_MUSB_DSPS
+	tristate "TI DSPS platforms"
+	depends on SOC_OMAPTI81XX || SOC_OMAPAM33XX
+
 config USB_MUSB_BLACKFIN
 	tristate "Blackfin"
 	depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
@@ -70,7 +75,8 @@
 	default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
 	default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
 	default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010
-	default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
+	default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \
+				|| USB_MUSB_DSPS
 	help
 	  Unfortunately, only one option can be enabled here. Ideally one
 	  should be able to build all these drivers into one kernel to
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 88bfb9d..3b85871 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -13,6 +13,7 @@
 # Hardware Glue Layer
 obj-$(CONFIG_USB_MUSB_OMAP2PLUS)		+= omap2430.o
 obj-$(CONFIG_USB_MUSB_AM35X)			+= am35x.o
+obj-$(CONFIG_USB_MUSB_DSPS)			+= musb_dsps.o
 obj-$(CONFIG_USB_MUSB_TUSB6010)			+= tusb6010.o
 obj-$(CONFIG_USB_MUSB_DAVINCI)			+= davinci.o
 obj-$(CONFIG_USB_MUSB_DA8XX)			+= da8xx.o
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 66bc376..8637c1f 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -6,6 +6,7 @@
  * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
  */
 
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 66aaccf..db3dff8 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1034,7 +1034,9 @@
 	|| defined(CONFIG_USB_MUSB_OMAP2PLUS)		\
 	|| defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE)	\
 	|| defined(CONFIG_USB_MUSB_AM35X)		\
-	|| defined(CONFIG_USB_MUSB_AM35X_MODULE)
+	|| defined(CONFIG_USB_MUSB_AM35X_MODULE)	\
+	|| defined(CONFIG_USB_MUSB_DSPS)		\
+	|| defined(CONFIG_USB_MUSB_DSPS_MODULE)
 static ushort __devinitdata fifo_mode = 4;
 #elif defined(CONFIG_USB_MUSB_UX500)			\
 	|| defined(CONFIG_USB_MUSB_UX500_MODULE)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
new file mode 100644
index 0000000..23db42d
--- /dev/null
+++ b/drivers/usb/musb/musb_dsps.c
@@ -0,0 +1,711 @@
+/*
+ * Texas Instruments DSPS platforms "glue layer"
+ *
+ * Copyright (C) 2012, by Texas Instruments
+ *
+ * Based on the am35x "glue layer" code.
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * musb_dsps.c will be a common file for all the TI DSPS platforms
+ * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x.
+ * For now only ti81x is using this and in future davinci.c, am35x.c
+ * da8xx.c would be merged to this file after testing.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#include <plat/usb.h>
+
+#include "musb_core.h"
+
+/**
+ * avoid using musb_readx()/musb_writex() as glue layer should not be
+ * dependent on musb core layer symbols.
+ */
+static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
+	{ return __raw_readb(addr + offset); }
+
+static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
+	{ return __raw_readl(addr + offset); }
+
+static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
+	{ __raw_writeb(data, addr + offset); }
+
+static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
+	{ __raw_writel(data, addr + offset); }
+
+/**
+ * DSPS musb wrapper register offset.
+ * FIXME: This should be expanded to have all the wrapper registers from TI DSPS
+ * musb ips.
+ */
+struct dsps_musb_wrapper {
+	u16	revision;
+	u16	control;
+	u16	status;
+	u16	eoi;
+	u16	epintr_set;
+	u16	epintr_clear;
+	u16	epintr_status;
+	u16	coreintr_set;
+	u16	coreintr_clear;
+	u16	coreintr_status;
+	u16	phy_utmi;
+	u16	mode;
+
+	/* bit positions for control */
+	unsigned	reset:5;
+
+	/* bit positions for interrupt */
+	unsigned	usb_shift:5;
+	u32		usb_mask;
+	u32		usb_bitmap;
+	unsigned	drvvbus:5;
+
+	unsigned	txep_shift:5;
+	u32		txep_mask;
+	u32		txep_bitmap;
+
+	unsigned	rxep_shift:5;
+	u32		rxep_mask;
+	u32		rxep_bitmap;
+
+	/* bit positions for phy_utmi */
+	unsigned	otg_disable:5;
+
+	/* bit positions for mode */
+	unsigned	iddig:5;
+	/* miscellaneous stuff */
+	u32		musb_core_offset;
+	u8		poll_seconds;
+};
+
+/**
+ * DSPS glue structure.
+ */
+struct dsps_glue {
+	struct device *dev;
+	struct platform_device *musb;	/* child musb pdev */
+	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
+	struct timer_list timer;	/* otg_workaround timer */
+};
+
+/**
+ * dsps_musb_enable - enable interrupts
+ */
+static void dsps_musb_enable(struct musb *musb)
+{
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+	void __iomem *reg_base = musb->ctrl_base;
+	u32 epmask, coremask;
+
+	/* Workaround: setup IRQs through both register sets. */
+	epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) |
+	       ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift);
+	coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF);
+
+	dsps_writel(reg_base, wrp->epintr_set, epmask);
+	dsps_writel(reg_base, wrp->coreintr_set, coremask);
+	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
+	if (is_otg_enabled(musb))
+		dsps_writel(reg_base, wrp->coreintr_set,
+			    (1 << wrp->drvvbus) << wrp->usb_shift);
+}
+
+/**
+ * dsps_musb_disable - disable HDRC and flush interrupts
+ */
+static void dsps_musb_disable(struct musb *musb)
+{
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+	void __iomem *reg_base = musb->ctrl_base;
+
+	dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
+	dsps_writel(reg_base, wrp->epintr_clear,
+			 wrp->txep_bitmap | wrp->rxep_bitmap);
+	dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
+	dsps_writel(reg_base, wrp->eoi, 0);
+}
+
+static void otg_timer(unsigned long _musb)
+{
+	struct musb *musb = (void *)_musb;
+	void __iomem *mregs = musb->mregs;
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+	u8 devctl;
+	unsigned long flags;
+
+	/*
+	 * We poll because DSPS IP's won't expose several OTG-critical
+	 * status change events (from the transceiver) otherwise.
+	 */
+	devctl = dsps_readb(mregs, MUSB_DEVCTL);
+	dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
+				otg_state_string(musb->xceiv->state));
+
+	spin_lock_irqsave(&musb->lock, flags);
+	switch (musb->xceiv->state) {
+	case OTG_STATE_A_WAIT_BCON:
+		devctl &= ~MUSB_DEVCTL_SESSION;
+		dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+		devctl = dsps_readb(musb->mregs, MUSB_DEVCTL);
+		if (devctl & MUSB_DEVCTL_BDEVICE) {
+			musb->xceiv->state = OTG_STATE_B_IDLE;
+			MUSB_DEV_MODE(musb);
+		} else {
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+			MUSB_HST_MODE(musb);
+		}
+		break;
+	case OTG_STATE_A_WAIT_VFALL:
+		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+		dsps_writel(musb->ctrl_base, wrp->coreintr_set,
+			    MUSB_INTR_VBUSERROR << wrp->usb_shift);
+		break;
+	case OTG_STATE_B_IDLE:
+		if (!is_peripheral_enabled(musb))
+			break;
+
+		devctl = dsps_readb(mregs, MUSB_DEVCTL);
+		if (devctl & MUSB_DEVCTL_BDEVICE)
+			mod_timer(&glue->timer,
+					jiffies + wrp->poll_seconds * HZ);
+		else
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
+{
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	static unsigned long last_timer;
+
+	if (!is_otg_enabled(musb))
+		return;
+
+	if (timeout == 0)
+		timeout = jiffies + msecs_to_jiffies(3);
+
+	/* Never idle if active, or when VBUS timeout is not set as host */
+	if (musb->is_active || (musb->a_wait_bcon == 0 &&
+				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+		dev_dbg(musb->controller, "%s active, deleting timer\n",
+				otg_state_string(musb->xceiv->state));
+		del_timer(&glue->timer);
+		last_timer = jiffies;
+		return;
+	}
+
+	if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) {
+		dev_dbg(musb->controller,
+			"Longer idle timer already pending, ignoring...\n");
+		return;
+	}
+	last_timer = timeout;
+
+	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
+		otg_state_string(musb->xceiv->state),
+			jiffies_to_msecs(timeout - jiffies));
+	mod_timer(&glue->timer, timeout);
+}
+
+static irqreturn_t dsps_interrupt(int irq, void *hci)
+{
+	struct musb  *musb = hci;
+	void __iomem *reg_base = musb->ctrl_base;
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+	unsigned long flags;
+	irqreturn_t ret = IRQ_NONE;
+	u32 epintr, usbintr;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	/* Get endpoint interrupts */
+	epintr = dsps_readl(reg_base, wrp->epintr_status);
+	musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift;
+	musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift;
+
+	if (epintr)
+		dsps_writel(reg_base, wrp->epintr_status, epintr);
+
+	/* Get usb core interrupts */
+	usbintr = dsps_readl(reg_base, wrp->coreintr_status);
+	if (!usbintr && !epintr)
+		goto eoi;
+
+	musb->int_usb =	(usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
+	if (usbintr)
+		dsps_writel(reg_base, wrp->coreintr_status, usbintr);
+
+	dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
+			usbintr, epintr);
+	/*
+	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
+	 * DSPS IP's missing ID change IRQ.  We need an ID change IRQ to
+	 * switch appropriately between halves of the OTG state machine.
+	 * Managing DEVCTL.SESSION per Mentor docs requires that we know its
+	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+	 */
+	if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb))
+		pr_info("CAUTION: musb: Babble Interrupt Occured\n");
+
+	if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
+		int drvvbus = dsps_readl(reg_base, wrp->status);
+		void __iomem *mregs = musb->mregs;
+		u8 devctl = dsps_readb(mregs, MUSB_DEVCTL);
+		int err;
+
+		err = is_host_enabled(musb) && (musb->int_usb &
+						MUSB_INTR_VBUSERROR);
+		if (err) {
+			/*
+			 * The Mentor core doesn't debounce VBUS as needed
+			 * to cope with device connect current spikes. This
+			 * means it's not uncommon for bus-powered devices
+			 * to get VBUS errors during enumeration.
+			 *
+			 * This is a workaround, but newer RTL from Mentor
+			 * seems to allow a better one: "re"-starting sessions
+			 * without waiting for VBUS to stop registering in
+			 * devctl.
+			 */
+			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+			mod_timer(&glue->timer,
+					jiffies + wrp->poll_seconds * HZ);
+			WARNING("VBUS error workaround (delay coming)\n");
+		} else if (is_host_enabled(musb) && drvvbus) {
+			musb->is_active = 1;
+			MUSB_HST_MODE(musb);
+			musb->xceiv->otg->default_a = 1;
+			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+			del_timer(&glue->timer);
+		} else {
+			musb->is_active = 0;
+			MUSB_DEV_MODE(musb);
+			musb->xceiv->otg->default_a = 0;
+			musb->xceiv->state = OTG_STATE_B_IDLE;
+		}
+
+		/* NOTE: this must complete power-on within 100 ms. */
+		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
+				drvvbus ? "on" : "off",
+				otg_state_string(musb->xceiv->state),
+				err ? " ERROR" : "",
+				devctl);
+		ret = IRQ_HANDLED;
+	}
+
+	if (musb->int_tx || musb->int_rx || musb->int_usb)
+		ret |= musb_interrupt(musb);
+
+ eoi:
+	/* EOI needs to be written for the IRQ to be re-asserted. */
+	if (ret == IRQ_HANDLED || epintr || usbintr)
+		dsps_writel(reg_base, wrp->eoi, 1);
+
+	/* Poll for ID change */
+	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return ret;
+}
+
+static int dsps_musb_init(struct musb *musb)
+{
+	struct device *dev = musb->controller;
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+	struct omap_musb_board_data *data = plat->board_data;
+	void __iomem *reg_base = musb->ctrl_base;
+	u32 rev, val;
+	int status;
+
+	/* mentor core register starts at offset of 0x400 from musb base */
+	musb->mregs += wrp->musb_core_offset;
+
+	/* NOP driver needs change if supporting dual instance */
+	usb_nop_xceiv_register();
+	musb->xceiv = usb_get_transceiver();
+	if (!musb->xceiv)
+		return -ENODEV;
+
+	/* Returns zero if e.g. not clocked */
+	rev = dsps_readl(reg_base, wrp->revision);
+	if (!rev) {
+		status = -ENODEV;
+		goto err0;
+	}
+
+	if (is_host_enabled(musb))
+		setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
+
+	/* Reset the musb */
+	dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
+
+	/* Start the on-chip PHY and its PLL. */
+	if (data->set_phy_power)
+		data->set_phy_power(1);
+
+	musb->isr = dsps_interrupt;
+
+	/* reset the otgdisable bit, needed for host mode to work */
+	val = dsps_readl(reg_base, wrp->phy_utmi);
+	val &= ~(1 << wrp->otg_disable);
+	dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
+
+	/* clear level interrupt */
+	dsps_writel(reg_base, wrp->eoi, 0);
+
+	return 0;
+err0:
+	usb_put_transceiver(musb->xceiv);
+	usb_nop_xceiv_unregister();
+	return status;
+}
+
+static int dsps_musb_exit(struct musb *musb)
+{
+	struct device *dev = musb->controller;
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+
+	if (is_host_enabled(musb))
+		del_timer_sync(&glue->timer);
+
+	/* Shutdown the on-chip PHY and its PLL. */
+	if (data->set_phy_power)
+		data->set_phy_power(0);
+
+	/* NOP driver needs change if supporting dual instance */
+	usb_put_transceiver(musb->xceiv);
+	usb_nop_xceiv_unregister();
+
+	return 0;
+}
+
+static struct musb_platform_ops dsps_ops = {
+	.init		= dsps_musb_init,
+	.exit		= dsps_musb_exit,
+
+	.enable		= dsps_musb_enable,
+	.disable	= dsps_musb_disable,
+
+	.try_idle	= dsps_musb_try_idle,
+};
+
+static u64 musb_dmamask = DMA_BIT_MASK(32);
+
+static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
+{
+	struct device *dev = glue->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct musb_hdrc_platform_data  *pdata = dev->platform_data;
+	struct platform_device	*musb;
+	struct resource *res;
+	struct resource	resources[2];
+	char res_name[10];
+	int ret;
+
+	/* get memory resource */
+	sprintf(res_name, "musb%d", id);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
+	if (!res) {
+		dev_err(dev, "%s get mem resource failed\n", res_name);
+		ret = -ENODEV;
+		goto err0;
+	}
+	res->parent = NULL;
+	resources[0] = *res;
+
+	/* get irq resource */
+	sprintf(res_name, "musb%d-irq", id);
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
+	if (!res) {
+		dev_err(dev, "%s get irq resource failed\n", res_name);
+		ret = -ENODEV;
+		goto err0;
+	}
+	strcpy((u8 *)res->name, "mc");
+	res->parent = NULL;
+	resources[1] = *res;
+
+	/* allocate the child platform device */
+	musb = platform_device_alloc("musb-hdrc", -1);
+	if (!musb) {
+		dev_err(dev, "failed to allocate musb device\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	musb->dev.parent		= dev;
+	musb->dev.dma_mask		= &musb_dmamask;
+	musb->dev.coherent_dma_mask	= musb_dmamask;
+
+	glue->musb			= musb;
+
+	pdata->platform_ops		= &dsps_ops;
+
+	ret = platform_device_add_resources(musb, resources, 2);
+	if (ret) {
+		dev_err(dev, "failed to add resources\n");
+		goto err1;
+	}
+
+	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+	if (ret) {
+		dev_err(dev, "failed to add platform_data\n");
+		goto err1;
+	}
+
+	ret = platform_device_add(musb);
+	if (ret) {
+		dev_err(dev, "failed to register musb device\n");
+		goto err1;
+	}
+
+	return 0;
+
+err1:
+	platform_device_put(musb);
+err0:
+	return ret;
+}
+
+static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue)
+{
+	platform_device_del(glue->musb);
+	platform_device_put(glue->musb);
+}
+
+static int __devinit dsps_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	const struct dsps_musb_wrapper *wrp =
+				(struct dsps_musb_wrapper *)id->driver_data;
+	struct dsps_glue *glue;
+	struct resource *iomem;
+	int ret;
+
+	/* allocate glue */
+	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+	if (!glue) {
+		dev_err(&pdev->dev, "unable to allocate glue memory\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	/* get memory resource */
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iomem) {
+		dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	glue->dev = &pdev->dev;
+
+	glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
+	if (!glue->wrp) {
+		dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+	platform_set_drvdata(pdev, glue);
+
+	/* create the child platform device for first instances of musb */
+	ret = dsps_create_musb_pdev(glue, 0);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "failed to create child pdev\n");
+		goto err2;
+	}
+
+	/* enable the usbss clocks */
+	pm_runtime_enable(&pdev->dev);
+
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
+		goto err3;
+	}
+
+	return 0;
+
+err3:
+	pm_runtime_disable(&pdev->dev);
+err2:
+	kfree(glue->wrp);
+err1:
+	kfree(glue);
+err0:
+	return ret;
+}
+static int __devexit dsps_remove(struct platform_device *pdev)
+{
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+
+	/* delete the child platform device */
+	dsps_delete_musb_pdev(glue);
+
+	/* disable usbss clocks */
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	kfree(glue->wrp);
+	kfree(glue);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dsps_suspend(struct device *dev)
+{
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+
+	/* Shutdown the on-chip PHY and its PLL. */
+	if (data->set_phy_power)
+		data->set_phy_power(0);
+
+	return 0;
+}
+
+static int dsps_resume(struct device *dev)
+{
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+
+	/* Start the on-chip PHY and its PLL. */
+	if (data->set_phy_power)
+		data->set_phy_power(1);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
+
+static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = {
+	.revision		= 0x00,
+	.control		= 0x14,
+	.status			= 0x18,
+	.eoi			= 0x24,
+	.epintr_set		= 0x38,
+	.epintr_clear		= 0x40,
+	.epintr_status		= 0x30,
+	.coreintr_set		= 0x3c,
+	.coreintr_clear		= 0x44,
+	.coreintr_status	= 0x34,
+	.phy_utmi		= 0xe0,
+	.mode			= 0xe8,
+	.reset			= 0,
+	.otg_disable		= 21,
+	.iddig			= 8,
+	.usb_shift		= 0,
+	.usb_mask		= 0x1ff,
+	.usb_bitmap		= (0x1ff << 0),
+	.drvvbus		= 8,
+	.txep_shift		= 0,
+	.txep_mask		= 0xffff,
+	.txep_bitmap		= (0xffff << 0),
+	.rxep_shift		= 16,
+	.rxep_mask		= 0xfffe,
+	.rxep_bitmap		= (0xfffe << 16),
+	.musb_core_offset	= 0x400,
+	.poll_seconds		= 2,
+};
+
+static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {
+	{
+		.name	= "musb-ti81xx",
+		.driver_data	= (kernel_ulong_t) &ti81xx_driver_data,
+	},
+	{  },	/* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
+
+static const struct of_device_id musb_dsps_of_match[] __devinitconst = {
+	{ .compatible = "musb-ti81xx", },
+	{ .compatible = "ti,ti81xx-musb", },
+	{ .compatible = "ti,am335x-musb", },
+	{  },
+};
+MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
+
+static struct platform_driver dsps_usbss_driver = {
+	.probe		= dsps_probe,
+	.remove         = __devexit_p(dsps_remove),
+	.driver         = {
+		.name   = "musb-dsps",
+		.pm	= &dsps_pm_ops,
+		.of_match_table	= musb_dsps_of_match,
+	},
+	.id_table	= musb_dsps_id_table,
+};
+
+MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
+MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
+MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init dsps_init(void)
+{
+	return platform_driver_register(&dsps_usbss_driver);
+}
+subsys_initcall(dsps_init);
+
+static void __exit dsps_exit(void)
+{
+	platform_driver_unregister(&dsps_usbss_driver);
+}
+module_exit(dsps_exit);
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
index a0a2178..bde6298 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/otg/gpio_vbus.c
@@ -37,7 +37,9 @@
 	struct regulator       *vbus_draw;
 	int			vbus_draw_enabled;
 	unsigned		mA;
-	struct work_struct	work;
+	struct delayed_work	work;
+	int			vbus;
+	int			irq;
 };
 
 
@@ -51,8 +53,7 @@
  * edges might be workable.
  */
 #define VBUS_IRQ_FLAGS \
-	( IRQF_SAMPLE_RANDOM | IRQF_SHARED \
-	| IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING )
+	(IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
 
 
 /* interface to regulator framework */
@@ -94,20 +95,26 @@
 static void gpio_vbus_work(struct work_struct *work)
 {
 	struct gpio_vbus_data *gpio_vbus =
-		container_of(work, struct gpio_vbus_data, work);
+		container_of(work, struct gpio_vbus_data, work.work);
 	struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
-	int gpio, status;
+	int gpio, status, vbus;
 
 	if (!gpio_vbus->phy.otg->gadget)
 		return;
 
+	vbus = is_vbus_powered(pdata);
+	if ((vbus ^ gpio_vbus->vbus) == 0)
+		return;
+	gpio_vbus->vbus = vbus;
+
 	/* Peripheral controllers which manage the pullup themselves won't have
 	 * gpio_pullup configured here.  If it's configured here, we'll do what
 	 * isp1301_omap::b_peripheral() does and enable the pullup here... although
 	 * that may complicate usb_gadget_{,dis}connect() support.
 	 */
 	gpio = pdata->gpio_pullup;
-	if (is_vbus_powered(pdata)) {
+
+	if (vbus) {
 		status = USB_EVENT_VBUS;
 		gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL;
 		gpio_vbus->phy.last_event = status;
@@ -152,7 +159,7 @@
 		otg->gadget ? otg->gadget->name : "none");
 
 	if (otg->gadget)
-		schedule_work(&gpio_vbus->work);
+		schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100));
 
 	return IRQ_HANDLED;
 }
@@ -166,12 +173,11 @@
 	struct gpio_vbus_data *gpio_vbus;
 	struct gpio_vbus_mach_info *pdata;
 	struct platform_device *pdev;
-	int gpio, irq;
+	int gpio;
 
 	gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
 	pdev = to_platform_device(gpio_vbus->dev);
 	pdata = gpio_vbus->dev->platform_data;
-	irq = gpio_to_irq(pdata->gpio_vbus);
 	gpio = pdata->gpio_pullup;
 
 	if (!gadget) {
@@ -195,7 +201,8 @@
 	dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name);
 
 	/* initialize connection state */
-	gpio_vbus_irq(irq, pdev);
+	gpio_vbus->vbus = 0; /* start with disconnected */
+	gpio_vbus_irq(gpio_vbus->irq, pdev);
 	return 0;
 }
 
@@ -235,6 +242,7 @@
 	struct gpio_vbus_data *gpio_vbus;
 	struct resource *res;
 	int err, gpio, irq;
+	unsigned long irqflags;
 
 	if (!pdata || !gpio_is_valid(pdata->gpio_vbus))
 		return -EINVAL;
@@ -271,10 +279,13 @@
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (res) {
 		irq = res->start;
-		res->flags &= IRQF_TRIGGER_MASK;
-		res->flags |= IRQF_SAMPLE_RANDOM | IRQF_SHARED;
-	} else
+		irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED;
+	} else {
 		irq = gpio_to_irq(gpio);
+		irqflags = VBUS_IRQ_FLAGS;
+	}
+
+	gpio_vbus->irq = irq;
 
 	/* if data line pullup is in use, initialize it to "not pulling up" */
 	gpio = pdata->gpio_pullup;
@@ -290,8 +301,7 @@
 		gpio_direction_output(gpio, pdata->gpio_pullup_inverted);
 	}
 
-	err = request_irq(irq, gpio_vbus_irq, VBUS_IRQ_FLAGS,
-		"vbus_detect", pdev);
+	err = request_irq(irq, gpio_vbus_irq, irqflags, "vbus_detect", pdev);
 	if (err) {
 		dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
 			irq, err);
@@ -300,7 +310,7 @@
 
 	ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier);
 
-	INIT_WORK(&gpio_vbus->work, gpio_vbus_work);
+	INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work);
 
 	gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
 	if (IS_ERR(gpio_vbus->vbus_draw)) {
@@ -317,9 +327,12 @@
 		goto err_otg;
 	}
 
+	device_init_wakeup(&pdev->dev, pdata->wakeup);
+
 	return 0;
 err_otg:
-	free_irq(irq, &pdev->dev);
+	regulator_put(gpio_vbus->vbus_draw);
+	free_irq(irq, pdev);
 err_irq:
 	if (gpio_is_valid(pdata->gpio_pullup))
 		gpio_free(pdata->gpio_pullup);
@@ -337,11 +350,13 @@
 	struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
 	int gpio = pdata->gpio_vbus;
 
+	device_init_wakeup(&pdev->dev, 0);
+	cancel_delayed_work_sync(&gpio_vbus->work);
 	regulator_put(gpio_vbus->vbus_draw);
 
 	usb_set_transceiver(NULL);
 
-	free_irq(gpio_to_irq(gpio), &pdev->dev);
+	free_irq(gpio_vbus->irq, pdev);
 	if (gpio_is_valid(pdata->gpio_pullup))
 		gpio_free(pdata->gpio_pullup);
 	gpio_free(gpio);
@@ -352,6 +367,33 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int gpio_vbus_pm_suspend(struct device *dev)
+{
+	struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(gpio_vbus->irq);
+
+	return 0;
+}
+
+static int gpio_vbus_pm_resume(struct device *dev)
+{
+	struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(gpio_vbus->irq);
+
+	return 0;
+}
+
+static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {
+	.suspend	= gpio_vbus_pm_suspend,
+	.resume		= gpio_vbus_pm_resume,
+};
+#endif
+
 /* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
 
 MODULE_ALIAS("platform:gpio-vbus");
@@ -360,6 +402,9 @@
 	.driver = {
 		.name  = "gpio-vbus",
 		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &gpio_vbus_dev_pm_ops,
+#endif
 	},
 	.remove  = __exit_p(gpio_vbus_remove),
 };
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index e3fa387..d2a9a8e 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -455,7 +455,7 @@
 
 	twl->irq_enabled = true;
 	status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
-			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 			"twl6030_usb", twl);
 	if (status < 0) {
 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
@@ -467,7 +467,7 @@
 	}
 
 	status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
-			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 			"twl6030_usb", twl);
 	if (status < 0) {
 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
new file mode 100644
index 0000000..3cfabcb
--- /dev/null
+++ b/drivers/usb/phy/Kconfig
@@ -0,0 +1,17 @@
+#
+# Physical Layer USB driver configuration
+#
+comment "USB Physical Layer drivers"
+	depends on USB
+
+config USB_ISP1301
+	tristate "NXP ISP1301 USB transceiver support"
+	depends on USB
+	depends on I2C
+	help
+	  Say Y here to add support for the NXP ISP1301 USB transceiver driver.
+	  This chip is typically used as USB transceiver for USB host, gadget
+	  and OTG drivers (to be selected separately).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called isp1301.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
new file mode 100644
index 0000000..eca095b
--- /dev/null
+++ b/drivers/usb/phy/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for physical layer USB drivers
+#
+
+ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
+
+obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c
new file mode 100644
index 0000000..b19f493
--- /dev/null
+++ b/drivers/usb/phy/isp1301.c
@@ -0,0 +1,77 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Author: Roland Stigge <stigge@antcom.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.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#define DRV_NAME		"isp1301"
+
+#define ISP1301_I2C_ADDR	0x2C
+
+static const unsigned short normal_i2c[] = {
+	ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END
+};
+
+static const struct i2c_device_id isp1301_id[] = {
+	{ "isp1301", 0 },
+	{ }
+};
+
+static struct i2c_client *isp1301_i2c_client;
+
+static int isp1301_probe(struct i2c_client *client,
+			 const struct i2c_device_id *i2c_id)
+{
+	isp1301_i2c_client = client;
+	return 0;
+}
+
+static int isp1301_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct i2c_driver isp1301_driver = {
+	.driver = {
+		.name = DRV_NAME,
+	},
+	.probe = isp1301_probe,
+	.remove = isp1301_remove,
+	.id_table = isp1301_id,
+};
+
+module_i2c_driver(isp1301_driver);
+
+static int match(struct device *dev, void *data)
+{
+	struct device_node *node = (struct device_node *)data;
+	return (dev->of_node == node) &&
+		(dev->driver == &isp1301_driver.driver);
+}
+
+struct i2c_client *isp1301_get_client(struct device_node *node)
+{
+	if (node) { /* reference of ISP1301 I2C node via DT */
+		struct device *dev = bus_find_device(&i2c_bus_type, NULL,
+						     node, match);
+		if (!dev)
+			return NULL;
+		return to_i2c_client(dev);
+	} else { /* non-DT: only one ISP1301 chip supported */
+		return isp1301_i2c_client;
+	}
+}
+EXPORT_SYMBOL_GPL(isp1301_get_client);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 00bd2a5..28478ce 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -55,6 +55,7 @@
 #define USBHSG_STATUS_STARTED		(1 << 0)
 #define USBHSG_STATUS_REGISTERD		(1 << 1)
 #define USBHSG_STATUS_WEDGE		(1 << 2)
+#define USBHSG_STATUS_SELF_POWERED	(1 << 3)
 };
 
 struct usbhsg_recip_handle {
@@ -333,7 +334,10 @@
 					       struct usb_ctrlrequest *ctrl)
 {
 	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
-	unsigned short status = 1 << USB_DEVICE_SELF_POWERED;
+	unsigned short status = 0;
+
+	if (usbhsg_status_has(gpriv, USBHSG_STATUS_SELF_POWERED))
+		status = 1 << USB_DEVICE_SELF_POWERED;
 
 	__usbhsg_recip_send_status(gpriv, status);
 
@@ -879,8 +883,21 @@
 	return usbhs_frame_get_num(priv);
 }
 
+static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self)
+{
+	struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
+
+	if (is_self)
+		usbhsg_status_set(gpriv, USBHSG_STATUS_SELF_POWERED);
+	else
+		usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED);
+
+	return 0;
+}
+
 static struct usb_gadget_ops usbhsg_gadget_ops = {
 	.get_frame		= usbhsg_get_frame,
+	.set_selfpowered	= usbhsg_set_selfpowered,
 	.udc_start		= usbhsg_gadget_start,
 	.udc_stop		= usbhsg_gadget_stop,
 };
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 7141d65..325d291 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -669,6 +669,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ssu100.
 
+config USB_SERIAL_QT2
+	tristate "USB Quatech Serial Driver for USB 2 devices"
+	help
+	  Say Y here if you want to use the Quatech USB 2
+	  serial adapters.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called quatech-serial.
+
 config USB_SERIAL_DEBUG
 	tristate "USB Debugging Device"
 	help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 07f198e..1dc483a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -49,6 +49,7 @@
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
 obj-$(CONFIG_USB_SERIAL_QCAUX)			+= qcaux.o
 obj-$(CONFIG_USB_SERIAL_QUALCOMM)		+= qcserial.o
+obj-$(CONFIG_USB_SERIAL_QT2)			+= quatech2.o
 obj-$(CONFIG_USB_SERIAL_SAFE)			+= safe_serial.o
 obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI)		+= siemens_mpi.o
 obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS)		+= sierra.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index eec4fb9..d634e66 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -111,13 +111,14 @@
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
 		endpoint = &iface_desc->endpoint[i].desc;
 		if (usb_endpoint_is_bulk_out(endpoint)) {
-			dbg("found bulk out on endpoint %d", i);
+			dev_dbg(&serial->dev->dev,
+				"found bulk out on endpoint %d\n", i);
 			++num_bulk_out;
 		}
 	}
 
 	if (num_bulk_out == 0) {
-		dbg("Invalid interface, discarding");
+		dev_dbg(&serial->dev->dev, "Invalid interface, discarding\n");
 		return -ENODEV;
 	}
 
@@ -133,7 +134,7 @@
 		packet += HCI_HEADER_LENGTH;
 	}
 	if (len <= 0) {
-		dbg("%s - malformed packet", __func__);
+		dev_dbg(&port->dev, "%s - malformed packet\n", __func__);
 		return 0;
 	}
 
@@ -170,13 +171,6 @@
 	tty_kref_put(tty);
 }
 
-static struct usb_driver aircable_driver = {
-	.name =		"aircable",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver aircable_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -196,7 +190,7 @@
 	&aircable_device, NULL
 };
 
-module_usb_serial_driver(aircable_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index f99f4710..f8ce97d 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -265,7 +265,7 @@
 	hcr = (cflag & CRTSCTS) ? 0x03 : 0x00;
 
 	/* calc baudrate */
-	dbg("%s - setting bps to %d", __func__, bps);
+	dev_dbg(&port->dev, "%s - setting bps to %d\n", __func__, bps);
 	eval = 0;
 	switch (bps) {
 	case 0:
@@ -292,8 +292,8 @@
 	/* keep old LCR_SBC bit */
 	lcr |= (priv->lcr & UART_LCR_SBC);
 
-	dbg("%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d",
-	    __func__, hcr, lcr, quot);
+	dev_dbg(&port->dev, "%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d\n",
+		__func__, hcr, lcr, quot);
 
 	/* handshake control */
 	if (priv->hcr != hcr) {
@@ -375,8 +375,9 @@
 
 	result = usb_serial_generic_open(tty, port);
 	if (result) {
-		dbg("%s - usb_serial_generic_open failed: %d",
-		    __func__, result);
+		dev_dbg(&port->dev,
+			"%s - usb_serial_generic_open failed: %d\n",
+			__func__, result);
 		goto err_out;
 	}
 
@@ -622,24 +623,26 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		break;
 	case 0: /* success */
 		/* discovered this by trail and error... */
 		if ((urb->actual_length == 4) && (data[0] == 0xe8)) {
 			const __u8 id = data[1]&UART_IIR_ID;
-			dbg("%s: iir=%02x", __func__, data[1]);
+			dev_dbg(&port->dev, "%s: iir=%02x\n", __func__, data[1]);
 			if (id == UART_IIR_MSI) {
-				dbg("%s: msr=%02x", __func__, data[3]);
+				dev_dbg(&port->dev, "%s: msr=%02x\n",
+					__func__, data[3]);
 				ark3116_update_msr(port, data[3]);
 				break;
 			} else if (id == UART_IIR_RLSI) {
-				dbg("%s: lsr=%02x", __func__, data[2]);
+				dev_dbg(&port->dev, "%s: lsr=%02x\n",
+					__func__, data[2]);
 				ark3116_update_lsr(port, data[2]);
 				break;
 			}
@@ -714,13 +717,6 @@
 	tty_kref_put(tty);
 }
 
-static struct usb_driver ark3116_driver = {
-	.name =		"ark3116",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver ark3116_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -747,7 +743,7 @@
 	&ark3116_device, NULL
 };
 
-module_usb_serial_driver(ark3116_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index a52e0d2..6b73656 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -2,17 +2,17 @@
  * Belkin USB Serial Adapter Driver
  *
  *  Copyright (C) 2000		William Greathouse (wgreathouse@smva.com)
- *  Copyright (C) 2000-2001 	Greg Kroah-Hartman (greg@kroah.com)
+ *  Copyright (C) 2000-2001	Greg Kroah-Hartman (greg@kroah.com)
  *  Copyright (C) 2010		Johan Hovold (jhovold@gmail.com)
  *
  *  This program is largely derived from work by the linux-usb group
  *  and associated source files.  Please see the usb/serial files for
  *  individual credits and copyrights.
  *
- * 	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 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.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
@@ -62,7 +62,7 @@
 					unsigned int set, unsigned int clear);
 
 
-static const struct usb_device_id id_table_combined[] = {
+static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) },
 	{ USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
 	{ USB_DEVICE(PERACOM_VID, PERACOM_PID) },
@@ -71,14 +71,7 @@
 	{ USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) },
 	{ }	/* Terminating entry */
 };
-MODULE_DEVICE_TABLE(usb, id_table_combined);
-
-static struct usb_driver belkin_driver = {
-	.name =		"belkin",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
+MODULE_DEVICE_TABLE(usb, id_table);
 
 /* All of the device info needed for the serial converters */
 static struct usb_serial_driver belkin_device = {
@@ -87,7 +80,7 @@
 		.name =		"belkin",
 	},
 	.description =		"Belkin / Peracom / GoHubs USB Serial Adapter",
-	.id_table =		id_table_combined,
+	.id_table =		id_table,
 	.num_ports =		1,
 	.open =			belkin_sa_open,
 	.close =		belkin_sa_close,
@@ -159,8 +152,6 @@
 {
 	int i;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i)
 		kfree(usb_get_serial_port_data(serial->port[i]));
 }
@@ -170,8 +161,6 @@
 {
 	int retval;
 
-	dbg("%s port %d", __func__, port->number);
-
 	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (retval) {
 		dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
@@ -187,8 +176,6 @@
 
 static void belkin_sa_close(struct usb_serial_port *port)
 {
-	dbg("%s port %d", __func__, port->number);
-
 	usb_serial_generic_close(port);
 	usb_kill_urb(port->interrupt_in_urb);
 }
@@ -210,12 +197,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
@@ -403,7 +390,9 @@
 		case CS8:
 			urb_value = BELKIN_SA_DATA_BITS(8);
 			break;
-		default: dbg("CSIZE was not CS5-CS8, using default of 8");
+		default:
+			dev_dbg(&port->dev,
+				"CSIZE was not CS5-CS8, using default of 8\n");
 			urb_value = BELKIN_SA_DATA_BITS(8);
 			break;
 		}
@@ -463,8 +452,6 @@
 	unsigned long control_state;
 	unsigned long flags;
 
-	dbg("%s", __func__);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	control_state = priv->control_state;
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -484,8 +471,6 @@
 	int rts = 0;
 	int dtr = 0;
 
-	dbg("%s", __func__);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	control_state = priv->control_state;
 
@@ -524,7 +509,7 @@
 	return retval;
 }
 
-module_usb_serial_driver(belkin_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index ed8adb0..f398d1e 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -124,8 +124,15 @@
 	return retval;
 }
 
+static ssize_t show_dynids(struct device_driver *driver, char *buf)
+{
+	struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+
+	return usb_show_dynids(&usb_drv->dynids, buf);
+}
+
 static struct driver_attribute drv_attrs[] = {
-	__ATTR(new_id, S_IWUSR, NULL, store_new_id),
+	__ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id),
 	__ATTR_NULL,
 };
 
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index aaab32d..cabd1b1 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -125,8 +125,6 @@
 	unsigned long factor;
 	short divisor;
 
-	dbg("ch341_set_baudrate(%d)", priv->baud_rate);
-
 	if (!priv->baud_rate)
 		return -EINVAL;
 	factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate);
@@ -153,7 +151,6 @@
 
 static int ch341_set_handshake(struct usb_device *dev, u8 control)
 {
-	dbg("ch341_set_handshake(0x%02x)", control);
 	return ch341_control_out(dev, 0xa4, ~control, 0);
 }
 
@@ -164,8 +161,6 @@
 	const unsigned size = 8;
 	unsigned long flags;
 
-	dbg("ch341_get_status()");
-
 	buffer = kmalloc(size, GFP_KERNEL);
 	if (!buffer)
 		return -ENOMEM;
@@ -196,8 +191,6 @@
 	int r;
 	const unsigned size = 8;
 
-	dbg("ch341_configure()");
-
 	buffer = kmalloc(size, GFP_KERNEL);
 	if (!buffer)
 		return -ENOMEM;
@@ -254,8 +247,6 @@
 	struct ch341_private *priv;
 	int r;
 
-	dbg("ch341_attach()");
-
 	/* private data */
 	priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
 	if (!priv)
@@ -290,7 +281,6 @@
 	struct ch341_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
 	/* drop DTR and RTS */
 	spin_lock_irqsave(&priv->lock, flags);
 	if (on)
@@ -304,8 +294,6 @@
 
 static void ch341_close(struct usb_serial_port *port)
 {
-	dbg("%s - port %d", __func__, port->number);
-
 	usb_serial_generic_close(port);
 	usb_kill_urb(port->interrupt_in_urb);
 }
@@ -318,8 +306,6 @@
 	struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
 	int r;
 
-	dbg("ch341_open()");
-
 	priv->baud_rate = DEFAULT_BAUD_RATE;
 
 	r = ch341_configure(serial->dev, priv);
@@ -358,8 +344,6 @@
 	unsigned baud_rate;
 	unsigned long flags;
 
-	dbg("ch341_set_termios()");
-
 	baud_rate = tty_get_baud_rate(tty);
 
 	priv->baud_rate = baud_rate;
@@ -393,8 +377,6 @@
 	uint16_t reg_contents;
 	uint8_t *break_reg;
 
-	dbg("%s()", __func__);
-
 	break_reg = kmalloc(2, GFP_KERNEL);
 	if (!break_reg) {
 		dev_err(&port->dev, "%s - kmalloc failed\n", __func__);
@@ -461,8 +443,6 @@
 	unsigned int actual_length = urb->actual_length;
 	int status;
 
-	dbg("%s (%d)", __func__, port->number);
-
 	switch (urb->status) {
 	case 0:
 		/* success */
@@ -580,8 +560,6 @@
 	u8 status;
 	unsigned int result;
 
-	dbg("%s (%d)", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	mcr = priv->line_control;
 	status = priv->line_status;
@@ -599,35 +577,18 @@
 	return result;
 }
 
-
-static int ch341_reset_resume(struct usb_interface *intf)
+static int ch341_reset_resume(struct usb_serial *serial)
 {
-	struct usb_device *dev = interface_to_usbdev(intf);
-	struct usb_serial *serial = NULL;
 	struct ch341_private *priv;
 
-	serial = usb_get_intfdata(intf);
 	priv = usb_get_serial_port_data(serial->port[0]);
 
-	/*reconfigure ch341 serial port after bus-reset*/
-	ch341_configure(dev, priv);
-
-	usb_serial_resume(intf);
+	/* reconfigure ch341 serial port after bus-reset */
+	ch341_configure(serial->dev, priv);
 
 	return 0;
 }
 
-static struct usb_driver ch341_driver = {
-	.name		= "ch341",
-	.probe		= usb_serial_probe,
-	.disconnect	= usb_serial_disconnect,
-	.suspend	= usb_serial_suspend,
-	.resume		= usb_serial_resume,
-	.reset_resume	= ch341_reset_resume,
-	.id_table	= id_table,
-	.supports_autosuspend =	1,
-};
-
 static struct usb_serial_driver ch341_device = {
 	.driver = {
 		.owner	= THIS_MODULE,
@@ -646,13 +607,14 @@
 	.tiocmset          = ch341_tiocmset,
 	.read_int_callback = ch341_read_int_callback,
 	.attach            = ch341_attach,
+	.reset_resume      = ch341_reset_resume,
 };
 
 static struct usb_serial_driver * const serial_drivers[] = {
 	&ch341_device, NULL
 };
 
-module_usb_serial_driver(ch341_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 1ee6b2a..b9cca6d 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -113,7 +113,8 @@
 	serial = usb_serial_get_by_index(co->index);
 	if (serial == NULL) {
 		/* no device is connected yet, sorry :( */
-		err("No USB device connected to ttyUSB%i", co->index);
+		printk(KERN_ERR "No USB device connected to ttyUSB%i\n",
+		       co->index);
 		return -ENODEV;
 	}
 
@@ -137,7 +138,7 @@
 			tty = kzalloc(sizeof(*tty), GFP_KERNEL);
 			if (!tty) {
 				retval = -ENOMEM;
-				err("no more memory");
+				dev_err(&port->dev, "no more memory\n");
 				goto reset_open_count;
 			}
 			kref_init(&tty->kref);
@@ -146,7 +147,7 @@
 			tty->index = co->index;
 			if (tty_init_termios(tty)) {
 				retval = -ENOMEM;
-				err("no more memory");
+				dev_err(&port->dev, "no more memory\n");
 				goto free_tty;
 			}
 		}
@@ -159,7 +160,7 @@
 			retval = usb_serial_generic_open(NULL, port);
 
 		if (retval) {
-			err("could not open USB console port");
+			dev_err(&port->dev, "could not open USB console port\n");
 			goto fail;
 		}
 
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index ec30f95..1b19262 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -156,13 +156,6 @@
 	__u8			bInterfaceNumber;
 };
 
-static struct usb_driver cp210x_driver = {
-	.name		= "cp210x",
-	.probe		= usb_serial_probe,
-	.disconnect	= usb_serial_disconnect,
-	.id_table	= id_table,
-};
-
 static struct usb_serial_driver cp210x_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -188,8 +181,10 @@
 };
 
 /* Config request types */
-#define REQTYPE_HOST_TO_DEVICE	0x41
-#define REQTYPE_DEVICE_TO_HOST	0xc1
+#define REQTYPE_HOST_TO_INTERFACE	0x41
+#define REQTYPE_INTERFACE_TO_HOST	0xc1
+#define REQTYPE_HOST_TO_DEVICE	0x40
+#define REQTYPE_DEVICE_TO_HOST	0xc0
 
 /* Config request codes */
 #define CP210X_IFC_ENABLE	0x00
@@ -286,7 +281,7 @@
 
 	/* Issue the request, attempting to read 'size' bytes */
 	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-				request, REQTYPE_DEVICE_TO_HOST, 0x0000,
+				request, REQTYPE_INTERFACE_TO_HOST, 0x0000,
 				port_priv->bInterfaceNumber, buf, size,
 				USB_CTRL_GET_TIMEOUT);
 
@@ -340,13 +335,13 @@
 	if (size > 2) {
 		result = usb_control_msg(serial->dev,
 				usb_sndctrlpipe(serial->dev, 0),
-				request, REQTYPE_HOST_TO_DEVICE, 0x0000,
+				request, REQTYPE_HOST_TO_INTERFACE, 0x0000,
 				port_priv->bInterfaceNumber, buf, size,
 				USB_CTRL_SET_TIMEOUT);
 	} else {
 		result = usb_control_msg(serial->dev,
 				usb_sndctrlpipe(serial->dev, 0),
-				request, REQTYPE_HOST_TO_DEVICE, data[0],
+				request, REQTYPE_HOST_TO_INTERFACE, data[0],
 				port_priv->bInterfaceNumber, NULL, 0,
 				USB_CTRL_SET_TIMEOUT);
 	}
@@ -422,8 +417,6 @@
 {
 	int result;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
 								UART_ENABLE);
 	if (result) {
@@ -443,8 +436,6 @@
 
 static void cp210x_close(struct usb_serial_port *port)
 {
-	dbg("%s - port %d", __func__, port->number);
-
 	usb_serial_generic_close(port);
 
 	mutex_lock(&port->serial->disc_mutex);
@@ -488,8 +479,6 @@
 	unsigned int baud;
 	unsigned int bits;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
 
 	dbg("%s - baud rate = %d", __func__, baud);
@@ -787,8 +776,6 @@
 {
 	unsigned int control = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (set & TIOCM_RTS) {
 		control |= CONTROL_RTS;
 		control |= CONTROL_WRITE_RTS;
@@ -825,8 +812,6 @@
 	unsigned int control;
 	int result;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);
 
 	result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
@@ -846,7 +831,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	unsigned int state;
 
-	dbg("%s - port %d", __func__, port->number);
 	if (break_state == 0)
 		state = BREAK_OFF;
 	else
@@ -891,7 +875,7 @@
 	}
 }
 
-module_usb_serial_driver(cp210x_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index d39b941..3aa0b53 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -77,13 +77,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver cyberjack_driver = {
-	.name =		"cyberjack",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver cyberjack_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -122,8 +115,6 @@
 	struct cyberjack_private *priv;
 	int i;
 
-	dbg("%s", __func__);
-
 	/* allocate the private data structure */
 	priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
 	if (!priv)
@@ -155,8 +146,6 @@
 {
 	int i;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i)
 		usb_kill_urb(serial->port[i]->interrupt_in_urb);
 }
@@ -165,8 +154,6 @@
 {
 	int i;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i) {
 		/* My special items, the standard routines free my urbs */
 		kfree(usb_get_serial_port_data(serial->port[i]));
@@ -180,8 +167,6 @@
 	unsigned long flags;
 	int result = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	dbg("%s - usb_clear_halt", __func__);
 	usb_clear_halt(port->serial->dev, port->write_urb->pipe);
 
@@ -197,8 +182,6 @@
 
 static void cyberjack_close(struct usb_serial_port *port)
 {
-	dbg("%s - port %d", __func__, port->number);
-
 	if (port->serial->dev) {
 		/* shutdown any bulk reads that might be going on */
 		usb_kill_urb(port->write_urb);
@@ -214,8 +197,6 @@
 	int result;
 	int wrexpected;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (count == 0) {
 		dbg("%s - write request of 0 bytes", __func__);
 		return 0;
@@ -307,8 +288,6 @@
 	int status = urb->status;
 	int result;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/* the urb might have been killed. */
 	if (status)
 		return;
@@ -367,8 +346,6 @@
 	int result;
 	int status = urb->status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
 	if (status) {
@@ -417,8 +394,6 @@
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
 	int status = urb->status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	set_bit(0, &port->write_urbs_free);
 	if (status) {
 		dbg("%s - nonzero write bulk status received: %d",
@@ -475,7 +450,7 @@
 	usb_serial_port_softint(port);
 }
 
-module_usb_serial_driver(cyberjack_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index afc886c..b78c34e 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -89,13 +89,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
-static struct usb_driver cypress_driver = {
-	.name =		"cypress",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
-
 enum packet_format {
 	packet_format_1,  /* b0:status, b1:payload count */
 	packet_format_2   /* b0[7:3]:status, b0[2:0]:payload count */
@@ -305,8 +298,6 @@
 	const unsigned int feature_len = 5;
 	unsigned long flags;
 
-	dbg("%s", __func__);
-
 	priv = usb_get_serial_port_data(port);
 
 	if (!priv->comm_is_ok)
@@ -451,8 +442,6 @@
 	struct cypress_private *priv;
 	struct usb_serial_port *port = serial->port[0];
 
-	dbg("%s - port %d", __func__, port->number);
-
 	priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
@@ -505,8 +494,6 @@
 	struct cypress_private *priv;
 	struct usb_serial_port *port = serial->port[0];
 
-	dbg("%s", __func__);
-
 	if (generic_startup(serial)) {
 		dbg("%s - Failed setting up port %d", __func__,
 				port->number);
@@ -537,8 +524,6 @@
 {
 	struct cypress_private *priv;
 
-	dbg("%s", __func__);
-
 	if (generic_startup(serial)) {
 		dbg("%s - Failed setting up port %d", __func__,
 				serial->port[0]->number);
@@ -556,8 +541,6 @@
 {
 	struct cypress_private *priv;
 
-	dbg("%s", __func__);
-
 	if (generic_startup(serial)) {
 		dbg("%s - Failed setting up port %d", __func__,
 				serial->port[0]->number);
@@ -575,10 +558,7 @@
 {
 	struct cypress_private *priv;
 
-	dbg("%s - port %d", __func__, serial->port[0]->number);
-
 	/* all open ports are closed at this point */
-
 	priv = usb_get_serial_port_data(serial->port[0]);
 
 	if (priv) {
@@ -595,8 +575,6 @@
 	unsigned long flags;
 	int result = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (!priv->comm_is_ok)
 		return -EIO;
 
@@ -661,8 +639,6 @@
 	struct cypress_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/* writing is potentially harmful, lock must be taken */
 	mutex_lock(&port->serial->disc_mutex);
 	if (port->serial->disconnected) {
@@ -720,7 +696,6 @@
 	if (!priv->comm_is_ok)
 		return;
 
-	dbg("%s - port %d", __func__, port->number);
 	dbg("%s - interrupt out size is %d", __func__,
 						port->interrupt_out_size);
 
@@ -828,8 +803,6 @@
 	int room = 0;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	room = kfifo_avail(&priv->write_fifo);
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -847,8 +820,6 @@
 	unsigned int result = 0;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	control = priv->line_control;
 	status = priv->current_status;
@@ -874,8 +845,6 @@
 	struct cypress_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	if (set & TIOCM_RTS)
 		priv->line_control |= CONTROL_RTS;
@@ -948,8 +917,6 @@
 	__u8 oldlines;
 	int linechange = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	/* We can't clean this one up as we don't know the device type
 	   early enough */
@@ -1096,8 +1063,6 @@
 	int chars = 0;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	chars = kfifo_len(&priv->write_fifo);
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -1112,8 +1077,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct cypress_private *priv = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irq(&priv->lock);
 	priv->rx_flags = THROTTLED;
 	spin_unlock_irq(&priv->lock);
@@ -1126,8 +1089,6 @@
 	struct cypress_private *priv = usb_get_serial_port_data(port);
 	int actually_throttled, result;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irq(&priv->lock);
 	actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
 	priv->rx_flags = 0;
@@ -1161,8 +1122,6 @@
 	int i = 0;
 	int status = urb->status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	switch (status) {
 	case 0: /* success */
 		break;
@@ -1303,8 +1262,6 @@
 	int result;
 	int status = urb->status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -1346,7 +1303,7 @@
 	cypress_send(port);
 }
 
-module_usb_serial_driver(cypress_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 999f91b..b5cd838 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -271,14 +271,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
-static struct usb_driver digi_driver = {
-	.name =		"digi_acceleport",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
-
-
 /* device info needed for the Digi serial converter */
 
 static struct usb_serial_driver digi_acceleport_2_device = {
@@ -657,9 +649,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 
-
-	dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num);
-
 	/* stop receiving characters by not resubmitting the read urb */
 	spin_lock_irqsave(&priv->dp_port_lock, flags);
 	priv->dp_throttled = 1;
@@ -675,8 +664,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 
-	dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num);
-
 	spin_lock_irqsave(&priv->dp_port_lock, flags);
 
 	/* restart read chain */
@@ -904,8 +891,6 @@
 	unsigned int val;
 	unsigned long flags;
 
-	dbg("%s: TOP: port=%d", __func__, priv->dp_port_num);
-
 	spin_lock_irqsave(&priv->dp_port_lock, flags);
 	val = priv->dp_modem_signals;
 	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
@@ -921,8 +906,6 @@
 	unsigned int val;
 	unsigned long flags;
 
-	dbg("%s: TOP: port=%d", __func__, priv->dp_port_num);
-
 	spin_lock_irqsave(&priv->dp_port_lock, flags);
 	val = (priv->dp_modem_signals & ~clear) | set;
 	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
@@ -1013,8 +996,6 @@
 	int ret = 0;
 	int status = urb->status;
 
-	dbg("digi_write_bulk_callback: TOP, status=%d", status);
-
 	/* port and serial sanity check */
 	if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
 		pr_err("%s: port or port->private is NULL, status=%d\n",
@@ -1121,8 +1102,6 @@
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	struct ktermios not_termios;
 
-	dbg("digi_open: TOP: port=%d", priv->dp_port_num);
-
 	/* be sure the device is started up */
 	if (digi_startup_device(port->serial) != 0)
 		return -ENXIO;
@@ -1160,8 +1139,6 @@
 	unsigned char buf[32];
 	struct digi_port *priv = usb_get_serial_port_data(port);
 
-	dbg("digi_close: TOP: port=%d", priv->dp_port_num);
-
 	mutex_lock(&port->serial->disc_mutex);
 	/* if disconnected, just clear flags */
 	if (port->serial->disconnected)
@@ -1220,7 +1197,6 @@
 	wake_up_interruptible(&priv->dp_close_wait);
 	spin_unlock_irq(&priv->dp_port_lock);
 	mutex_unlock(&port->serial->disc_mutex);
-	dbg("digi_close: done");
 }
 
 
@@ -1269,8 +1245,6 @@
 	struct digi_port *priv;
 	struct digi_serial *serial_priv;
 
-	dbg("digi_startup: TOP");
-
 	/* allocate the private data structures for all ports */
 	/* number of regular ports + 1 for the out-of-band port */
 	for (i = 0; i < serial->type->num_ports + 1; i++) {
@@ -1325,7 +1299,6 @@
 static void digi_disconnect(struct usb_serial *serial)
 {
 	int i;
-	dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt());
 
 	/* stop reads and writes on all ports */
 	for (i = 0; i < serial->type->num_ports + 1; i++) {
@@ -1338,7 +1311,6 @@
 static void digi_release(struct usb_serial *serial)
 {
 	int i;
-	dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt());
 
 	/* free the private data structures for all ports */
 	/* number of regular ports + 1 for the out-of-band port */
@@ -1356,8 +1328,6 @@
 	int ret;
 	int status = urb->status;
 
-	dbg("digi_read_bulk_callback: TOP");
-
 	/* port sanity check, do not resubmit if port is not valid */
 	if (port == NULL)
 		return;
@@ -1507,9 +1477,6 @@
 	int i;
 	unsigned int rts;
 
-	dbg("digi_read_oob_callback: port=%d, len=%d",
-			priv->dp_port_num, urb->actual_length);
-
 	/* handle each oob command */
 	for (i = 0; i < urb->actual_length - 3;) {
 		opcode = ((unsigned char *)urb->transfer_buffer)[i++];
@@ -1580,7 +1547,7 @@
 
 }
 
-module_usb_serial_driver(digi_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 5b99fc0..cdf61dd 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -51,13 +51,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver empeg_driver = {
-	.name =		"empeg",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver empeg_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -80,14 +73,12 @@
 {
 	int r;
 
-	dbg("%s", __func__);
-
 	if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
 		dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
 			serial->dev->actconfig->desc.bConfigurationValue);
 		return -ENODEV;
 	}
-	dbg("%s - reset config", __func__);
+
 	r = usb_reset_configuration(serial->dev);
 
 	/* continue on with initialization */
@@ -138,7 +129,7 @@
 	tty_encode_baud_rate(tty, 115200, 115200);
 }
 
-module_usb_serial_driver(empeg_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index 3cfc762..800e8eb 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -26,7 +26,6 @@
 	int result;
 	unsigned char *transfer_buffer;
 
-	/* dbg("ezusb_writememory %x, %d", address, length); */
 	if (!serial->dev) {
 		printk(KERN_ERR "ezusb: %s - no physical device present, "
 		       "failing.\n", __func__);
@@ -50,7 +49,6 @@
 {
 	int response;
 
-	/* dbg("%s - %d", __func__, reset_bit); */
 	response = ezusb_writememory(serial, CPUCS_REG, &reset_bit, 1, 0xa0);
 	if (response < 0)
 		dev_err(&serial->dev->dev, "%s- %d failed\n",
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 88c0b19..499b15fd 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -68,8 +68,6 @@
 	int status = urb->status;
 	int retval;
 
-	dbg("%s (%d)", __func__, port->number);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -78,12 +76,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    status);
+		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__,
-		    status);
+		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
@@ -133,7 +131,7 @@
 		tty_flag = TTY_PARITY;
 	else if (line_status & UART_FRAME_ERROR)
 		tty_flag = TTY_FRAME;
-	dbg("%s - tty_flag = %d", __func__, tty_flag);
+	dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
 
 	/* overrun is special, not associated with a char */
 	if (line_status & UART_OVERRUN_ERROR)
@@ -203,7 +201,6 @@
 	if (tty)
 		f81232_set_termios(tty, port, &tmp_termios);
 
-	dbg("%s - submitting interrupt urb", __func__);
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (result) {
 		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -293,7 +290,9 @@
 {
 	struct serial_struct ser;
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+	dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
+		port->number, cmd);
 
 	switch (cmd) {
 	case TIOCGSERIAL:
@@ -309,10 +308,12 @@
 		return 0;
 
 	case TIOCMIWAIT:
-		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
+		dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
+			port->number);
 		return wait_modem_info(port, arg);
 	default:
-		dbg("%s not supported = 0x%04x", __func__, cmd);
+		dev_dbg(&port->dev, "%s not supported = 0x%04x\n",
+			__func__, cmd);
 		break;
 	}
 	return -ENOIOCTLCMD;
@@ -353,24 +354,12 @@
 	}
 }
 
-static struct usb_driver f81232_driver = {
-	.name =		"f81232",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-	.suspend =      usb_serial_suspend,
-	.resume =       usb_serial_resume,
-	.no_dynamic_id = 	1,
-	.supports_autosuspend =	1,
-};
-
 static struct usb_serial_driver f81232_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
 		.name =		"f81232",
 	},
 	.id_table =		id_table,
-	.usb_driver = 		&f81232_driver,
 	.num_ports =		1,
 	.bulk_in_size =		256,
 	.bulk_out_size =	256,
@@ -394,7 +383,7 @@
 	NULL,
 };
 
-module_usb_serial_driver(f81232_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 02e7f2d..8c084ea 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -809,6 +809,7 @@
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
 	{ USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
+	{ USB_DEVICE(PI_VID, PI_E861_PID) },
 	{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
 	{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -861,13 +862,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
-static struct usb_driver ftdi_driver = {
-	.name =		"ftdi_sio",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
-
 static const char *ftdi_chip_name[] = {
 	[SIO] = "SIO",	/* the serial part of FT8U100AX */
 	[FT8U232AM] = "FT8U232AM",
@@ -1285,8 +1279,6 @@
 	unsigned char *buf;
 	int rv;
 
-	dbg("%s", __func__);
-
 	buf = kmalloc(1, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
@@ -1593,8 +1585,6 @@
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	int retval = 0;
 
-	dbg("%s", __func__);
-
 	/* XXX I've no idea if the original SIO supports the event_char
 	 * sysfs parameter, so I'm playing it safe.  */
 	if (priv->chip_type != SIO) {
@@ -1619,8 +1609,6 @@
 {
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 
-	dbg("%s", __func__);
-
 	/* XXX see create_sysfs_attrs */
 	if (priv->chip_type != SIO) {
 		device_remove_file(&port->dev, &dev_attr_event_char);
@@ -1667,8 +1655,6 @@
 	struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
 
 
-	dbg("%s", __func__);
-
 	priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
 	if (!priv) {
 		dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
@@ -1704,8 +1690,6 @@
 /* Called from usbserial:serial_probe */
 static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
 {
-	dbg("%s", __func__);
-
 	priv->flags |= ASYNC_SPD_CUST;
 	priv->custom_divisor = 77;
 	priv->force_baud = 38400;
@@ -1716,8 +1700,6 @@
 
 static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
 {
-	dbg("%s", __func__);
-
 	priv->flags |= ASYNC_SPD_CUST;
 	priv->custom_divisor = 240;
 	priv->force_baud = 38400;
@@ -1767,8 +1749,6 @@
 	struct usb_device *udev = serial->dev;
 	struct usb_interface *interface = serial->interface;
 
-	dbg("%s", __func__);
-
 	if (interface == udev->actconfig->interface[0]) {
 		dev_info(&udev->dev,
 			 "Ignoring serial port reserved for JTAG\n");
@@ -1782,8 +1762,6 @@
 {
 	struct usb_device *udev = serial->dev;
 
-	dbg("%s", __func__);
-
 	if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
 	    (udev->product && !strcmp(udev->product, "BeagleBone/XDS100")))
 		return ftdi_jtag_probe(serial);
@@ -1800,8 +1778,6 @@
 	struct usb_device *udev = serial->dev;
 	struct usb_interface *interface = serial->interface;
 
-	dbg("%s", __func__);
-
 	if (interface == udev->actconfig->interface[2])
 		return 0;
 
@@ -1839,8 +1815,6 @@
 {
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 
-	dbg("%s", __func__);
-
 	priv->dev_gone = true;
 	wake_up_interruptible_all(&priv->delta_msr_wait);
 
@@ -1858,8 +1832,6 @@
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	int result;
 
-	dbg("%s", __func__);
-
 	/* No error checking for this (will get errors later anyway) */
 	/* See ftdi_sio.h for description of what is reset */
 	usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -1918,8 +1890,6 @@
 {
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 
-	dbg("%s", __func__);
-
 	usb_serial_generic_close(port);
 	kref_put(&priv->kref, ftdi_sio_priv_release);
 }
@@ -1976,8 +1946,6 @@
 	char flag;
 	char *ch;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (len < 2) {
 		dbg("malformed packet");
 		return 0;
@@ -2121,8 +2089,6 @@
 	unsigned char vstop;
 	unsigned char vstart;
 
-	dbg("%s", __func__);
-
 	/* Force baud rate if this device requires it, unless it is set to
 	   B0. */
 	if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) {
@@ -2295,8 +2261,6 @@
 	int len;
 	int ret;
 
-	dbg("%s TIOCMGET", __func__);
-
 	buf = kmalloc(2, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
@@ -2346,7 +2310,7 @@
 			unsigned int set, unsigned int clear)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s TIOCMSET", __func__);
+
 	return update_mctrl(port, set, clear);
 }
 
@@ -2435,7 +2399,6 @@
 {
 	int retval;
 
-	dbg("%s", __func__);
 	if (vendor > 0 && product > 0) {
 		/* Add user specified VID/PID to reserved element of table. */
 		int i;
@@ -2445,7 +2408,7 @@
 		id_table_combined[i].idVendor = vendor;
 		id_table_combined[i].idProduct = product;
 	}
-	retval = usb_serial_register_drivers(&ftdi_driver, serial_drivers);
+	retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined);
 	if (retval == 0)
 		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
 			       DRIVER_DESC "\n");
@@ -2454,9 +2417,7 @@
 
 static void __exit ftdi_exit(void)
 {
-	dbg("%s", __func__);
-
-	usb_serial_deregister_drivers(&ftdi_driver, serial_drivers);
+	usb_serial_deregister_drivers(serial_drivers);
 }
 
 
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 0838baf8..f3c7c78 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -785,6 +785,14 @@
 #define RTSYSTEMS_SERIAL_VX7_PID	0x9e52	/* Serial converter for VX-7 Radios using FT232RL */
 #define RTSYSTEMS_CT29B_PID		0x9e54	/* CT29B Radio Cable */
 
+
+/*
+ * Physik Instrumente
+ * http://www.physikinstrumente.com/en/products/
+ */
+#define PI_VID              0x1a72  /* Vendor ID */
+#define PI_E861_PID         0x1008  /* E-861 piezo controller USB connection */
+
 /*
  * Bayer Ascensia Contour blood glucose meter USB-converter cable.
  * http://winglucofacts.com/cables/
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 4577b36..2357079 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -24,13 +24,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver funsoft_driver = {
-	.name =		"funsoft",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver funsoft_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -44,7 +37,7 @@
 	&funsoft_device, NULL
 };
 
-module_usb_serial_driver(funsoft_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index e8eb634..346c15a 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -216,16 +216,8 @@
 	{ USB_DEVICE(GARMIN_VENDOR_ID, 3) },
 	{ }					/* Terminating entry */
 };
-
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver garmin_driver = {
-	.name =		"garmin_gps",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 
 static inline int getLayerId(const __u8 *usbPacket)
 {
@@ -345,8 +337,6 @@
 	unsigned long flags;
 	struct garmin_packet *result = NULL;
 
-	dbg("%s", __func__);
-
 	spin_lock_irqsave(&garmin_data_p->lock, flags);
 	while (!list_empty(&garmin_data_p->pktlist)) {
 		result = (struct garmin_packet *)garmin_data_p->pktlist.next;
@@ -939,8 +929,6 @@
 	int status = 0;
 	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&garmin_data_p->lock, flags);
 	garmin_data_p->mode  = initial_mode;
 	garmin_data_p->count = 0;
@@ -996,8 +984,6 @@
 		struct garmin_data *garmin_data_p =
 					usb_get_serial_port_data(port);
 
-		dbg("%s - port %d", __func__, port->number);
-
 		if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) {
 
 			if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
@@ -1027,9 +1013,6 @@
 	unsigned char *buffer;
 	int status;
 
-	dbg("%s - port %d, state %d", __func__, port->number,
-		garmin_data_p->state);
-
 	spin_lock_irqsave(&garmin_data_p->lock, flags);
 	garmin_data_p->flags &= ~FLAGS_DROP_DATA;
 	spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1224,8 +1207,6 @@
 	int status = urb->status;
 	int retval;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (!serial) {
 		dbg("%s - bad serial pointer, exiting", __func__);
 		return;
@@ -1384,7 +1365,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d", __func__, port->number);
 	/* set flag, data received will be put into a queue
 	   for later processing */
 	spin_lock_irq(&garmin_data_p->lock);
@@ -1399,7 +1379,6 @@
 	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 	int status;
 
-	dbg("%s - port %d", __func__, port->number);
 	spin_lock_irq(&garmin_data_p->lock);
 	garmin_data_p->flags &= ~FLAGS_THROTTLED;
 	spin_unlock_irq(&garmin_data_p->lock);
@@ -1441,8 +1420,6 @@
 	struct usb_serial_port *port = serial->port[0];
 	struct garmin_data *garmin_data_p = NULL;
 
-	dbg("%s", __func__);
-
 	garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
 	if (garmin_data_p == NULL) {
 		dev_err(&port->dev, "%s - Out of memory\n", __func__);
@@ -1471,8 +1448,6 @@
 	struct usb_serial_port *port = serial->port[0];
 	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 
-	dbg("%s", __func__);
-
 	usb_kill_urb(port->interrupt_in_urb);
 	del_timer_sync(&garmin_data_p->timer);
 }
@@ -1483,8 +1458,6 @@
 	struct usb_serial_port *port = serial->port[0];
 	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 
-	dbg("%s", __func__);
-
 	kfree(garmin_data_p);
 }
 
@@ -1516,7 +1489,7 @@
 	&garmin_device, NULL
 };
 
-module_usb_serial_driver(garmin_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 664deb6..105a6d8 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -28,9 +28,6 @@
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
 
-static int generic_probe(struct usb_interface *interface,
-			 const struct usb_device_id *id);
-
 static __u16 vendor  = 0x05f9;
 static __u16 product = 0xffff;
 
@@ -49,13 +46,6 @@
 	{}
 };
 
-static struct usb_driver generic_driver = {
-	.name =		"usbserial_generic",
-	.probe =	generic_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	generic_serial_ids,
-};
-
 /* All of the device info needed for the Generic Serial Converter */
 struct usb_serial_driver usb_serial_generic_device = {
 	.driver = {
@@ -75,16 +65,6 @@
 	&usb_serial_generic_device, NULL
 };
 
-static int generic_probe(struct usb_interface *interface,
-			       const struct usb_device_id *id)
-{
-	const struct usb_device_id *id_pattern;
-
-	id_pattern = usb_match_id(interface, generic_device_ids);
-	if (id_pattern != NULL)
-		return usb_serial_probe(interface, id);
-	return -ENODEV;
-}
 #endif
 
 int usb_serial_generic_register(int _debug)
@@ -99,7 +79,7 @@
 		USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
 
 	/* register our generic driver with ourselves */
-	retval = usb_serial_register_drivers(&generic_driver, serial_drivers);
+	retval = usb_serial_register_drivers(serial_drivers, "usbserial_generic", generic_serial_ids);
 #endif
 	return retval;
 }
@@ -108,7 +88,7 @@
 {
 #ifdef CONFIG_USB_SERIAL_GENERIC
 	/* remove our generic driver */
-	usb_serial_deregister_drivers(&generic_driver, serial_drivers);
+	usb_serial_deregister_drivers(serial_drivers);
 #endif
 }
 
@@ -117,8 +97,6 @@
 	int result = 0;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/* clear the throttle flags */
 	spin_lock_irqsave(&port->lock, flags);
 	port->throttled = 0;
@@ -139,12 +117,9 @@
 	unsigned long flags;
 	int i;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (serial->dev) {
 		/* shutdown any bulk transfers that might be going on */
 		if (port->bulk_out_size) {
-			usb_kill_urb(port->write_urb);
 			for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
 				usb_kill_urb(port->write_urbs[i]);
 
@@ -161,7 +136,6 @@
 
 void usb_serial_generic_close(struct usb_serial_port *port)
 {
-	dbg("%s - port %d", __func__, port->number);
 	generic_cleanup(port);
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_close);
@@ -249,8 +223,6 @@
 {
 	int result;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/* only do something if we have a bulk out endpoint */
 	if (!port->bulk_out_size)
 		return -ENODEV;
@@ -273,8 +245,6 @@
 	unsigned long flags;
 	int room;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (!port->bulk_out_size)
 		return 0;
 
@@ -282,7 +252,7 @@
 	room = kfifo_avail(&port->write_fifo);
 	spin_unlock_irqrestore(&port->lock, flags);
 
-	dbg("%s - returns %d", __func__, room);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
 	return room;
 }
 
@@ -292,8 +262,6 @@
 	unsigned long flags;
 	int chars;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (!port->bulk_out_size)
 		return 0;
 
@@ -301,7 +269,7 @@
 	chars = kfifo_len(&port->write_fifo) + port->tx_bytes;
 	spin_unlock_irqrestore(&port->lock, flags);
 
-	dbg("%s - returns %d", __func__, chars);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
 	return chars;
 }
 
@@ -313,7 +281,8 @@
 	if (!test_and_clear_bit(index, &port->read_urbs_free))
 		return 0;
 
-	dbg("%s - port %d, urb %d\n", __func__, port->number, index);
+	dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__,
+		port->number, index);
 
 	res = usb_submit_urb(port->read_urbs[index], mem_flags);
 	if (res) {
@@ -335,8 +304,6 @@
 	int res;
 	int i;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
 		res = usb_serial_generic_submit_read_urb(port, i, mem_flags);
 		if (res)
@@ -395,10 +362,12 @@
 	}
 	set_bit(i, &port->read_urbs_free);
 
-	dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i,
-							urb->actual_length);
+	dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n",
+		__func__, port->number, i, urb->actual_length);
+
 	if (urb->status) {
-		dbg("%s - non-zero urb status: %d\n", __func__, urb->status);
+		dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
+			__func__, urb->status);
 		return;
 	}
 
@@ -424,8 +393,6 @@
 	int status = urb->status;
 	int i;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
 		if (port->write_urbs[i] == urb)
 			break;
@@ -436,7 +403,8 @@
 	spin_unlock_irqrestore(&port->lock, flags);
 
 	if (status) {
-		dbg("%s - non-zero urb status: %d", __func__, status);
+		dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
+			__func__, status);
 
 		spin_lock_irqsave(&port->lock, flags);
 		kfifo_reset_out(&port->write_fifo);
@@ -454,8 +422,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/* Set the throttle request flag. It will be picked up
 	 * by usb_serial_generic_read_bulk_callback(). */
 	spin_lock_irqsave(&port->lock, flags);
@@ -469,8 +435,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	int was_throttled;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/* Clear the throttle flags */
 	spin_lock_irq(&port->lock);
 	was_throttled = port->throttled;
@@ -525,7 +489,8 @@
 {
 	struct tty_port *port = &usb_port->port;
 
-	dbg("%s - port %d, status %d", __func__, usb_port->number, status);
+	dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__,
+		usb_port->number, status);
 
 	if (status)
 		wake_up_interruptible(&port->open_wait);
@@ -566,8 +531,6 @@
 {
 	int i;
 
-	dbg("%s", __func__);
-
 	/* stop reads and writes on all ports */
 	for (i = 0; i < serial->num_ports; ++i)
 		generic_cleanup(serial->port[i]);
@@ -576,5 +539,4 @@
 
 void usb_serial_generic_release(struct usb_serial *serial)
 {
-	dbg("%s", __func__);
 }
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index 2563e78..0bbaf21 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -36,13 +36,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver hp49gp_driver = {
-	.name =		"hp4X",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver hp49gp_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -56,7 +49,7 @@
 	&hp49gp_device, NULL
 };
 
-module_usb_serial_driver(hp49gp_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 323e872..e1f5ccd 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -3181,7 +3181,7 @@
 	kfree(edge_serial);
 }
 
-module_usb_serial_driver(io_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index d0e7c9a..350afdd 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -95,13 +95,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
-static struct usb_driver io_driver = {
-	.name =		"io_edgeport",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
-
 static struct usb_serial_driver edgeport_2port_device = {
 	.driver = {
 		.owner		= THIS_MODULE,
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 40a95a7..3936904 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -197,14 +197,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
-static struct usb_driver io_driver = {
-	.name =		"io_ti",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
-
-
 static unsigned char OperationalMajorVersion;
 static unsigned char OperationalMinorVersion;
 static unsigned short OperationalBuildNumber;
@@ -547,6 +539,7 @@
 {
 	int baud_rate;
 	struct tty_struct *tty = tty_port_tty_get(&port->port->port);
+	struct usb_serial *serial = port->port->serial;
 	wait_queue_t wait;
 	unsigned long flags;
 
@@ -561,7 +554,7 @@
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (kfifo_len(&port->write_fifo) == 0
 		|| timeout == 0 || signal_pending(current)
-		|| !usb_get_intfdata(port->port->serial->interface))
+		|| serial->disconnected)
 			/* disconnect */
 			break;
 		spin_unlock_irqrestore(&port->ep_lock, flags);
@@ -578,7 +571,7 @@
 	/* wait for data to drain from the device */
 	timeout += jiffies;
 	while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
-	&& usb_get_intfdata(port->port->serial->interface)) {
+						&& !serial->disconnected) {
 		/* not disconnected */
 		if (!tx_active(port))
 			break;
@@ -586,7 +579,7 @@
 	}
 
 	/* disconnected */
-	if (!usb_get_intfdata(port->port->serial->interface))
+	if (serial->disconnected)
 		return;
 
 	/* wait one more character time, based on baud rate */
@@ -2003,8 +1996,8 @@
 {
 	struct edgeport_serial *edge_serial;
 	struct edgeport_port *edge_port;
+	struct usb_serial *serial = port->serial;
 	int port_number;
-	int status;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -2028,12 +2021,18 @@
 	 * send a close port command to it */
 	dbg("%s - send umpc_close_port", __func__);
 	port_number = port->number - port->serial->minor;
-	status = send_cmd(port->serial->dev,
+
+	mutex_lock(&serial->disc_mutex);
+	if (!serial->disconnected) {
+		send_cmd(serial->dev,
 				     UMPC_CLOSE_PORT,
 				     (__u8)(UMPM_UART1_PORT + port_number),
 				     0,
 				     NULL,
 				     0);
+	}
+	mutex_unlock(&serial->disc_mutex);
+
 	mutex_lock(&edge_serial->es_lock);
 	--edge_port->edge_serial->num_ports_open;
 	if (edge_port->edge_serial->num_ports_open <= 0) {
@@ -2783,7 +2782,7 @@
 	&edgeport_1port_device, &edgeport_2port_device, NULL
 };
 
-module_usb_serial_driver(io_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 10c02b8..c85a7eb 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -33,7 +33,6 @@
 #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
 #define DRIVER_DESC "USB PocketPC PDA driver"
 
-static __u16 product, vendor;
 static bool debug;
 static int connect_retries = KP_RETRIES;
 static int initial_wait;
@@ -45,8 +44,6 @@
 static int  ipaq_startup(struct usb_serial *serial);
 
 static struct usb_device_id ipaq_id_table [] = {
-	/* The first entry is a placeholder for the insmod-specified device */
-	{ USB_DEVICE(0x049F, 0x0003) },
 	{ USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */
 	{ USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */
 	{ USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */
@@ -505,13 +502,6 @@
 
 MODULE_DEVICE_TABLE(usb, ipaq_id_table);
 
-static struct usb_driver ipaq_driver = {
-	.name =		"ipaq",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	ipaq_id_table,
-};
-
 
 /* All of the device info needed for the Compaq iPAQ */
 static struct usb_serial_driver ipaq_device = {
@@ -539,8 +529,6 @@
 	int			result = 0;
 	int			retries = connect_retries;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	msleep(1000*initial_wait);
 
 	/*
@@ -577,7 +565,7 @@
 	 */
 	int ipaq_num_ports = 1;
 
-	dbg("%s - numberofendpoints: %d", __FUNCTION__,
+	dev_dbg(&serial->dev->dev, "%s - numberofendpoints: %d\n", __func__,
 		(int)serial->interface->cur_altsetting->desc.bNumEndpoints);
 
 	/*
@@ -596,8 +584,6 @@
 
 static int ipaq_startup(struct usb_serial *serial)
 {
-	dbg("%s", __func__);
-
 	/* Some of the devices in ipaq_id_table[] are composite, and we
 	 * shouldn't bind to all the interfaces.  This test will rule out
 	 * some obviously invalid possibilities.
@@ -617,36 +603,14 @@
 		return -ENODEV;
 	}
 
-	dbg("%s - iPAQ module configured for %d ports",
-		__FUNCTION__, serial->num_ports);
+	dev_dbg(&serial->dev->dev,
+		"%s - iPAQ module configured for %d ports\n", __func__,
+		serial->num_ports);
 
 	return usb_reset_configuration(serial->dev);
 }
 
-static int __init ipaq_init(void)
-{
-	int retval;
-
-	if (vendor) {
-		ipaq_id_table[0].idVendor = vendor;
-		ipaq_id_table[0].idProduct = product;
-	}
-
-	retval = usb_serial_register_drivers(&ipaq_driver, serial_drivers);
-	if (retval == 0)
-		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-			       DRIVER_DESC "\n");
-	return retval;
-}
-
-static void __exit ipaq_exit(void)
-{
-	usb_serial_deregister_drivers(&ipaq_driver, serial_drivers);
-}
-
-
-module_init(ipaq_init);
-module_exit(ipaq_exit);
+module_usb_serial_driver(serial_drivers, ipaq_id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -655,12 +619,6 @@
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified USB idProduct");
-
 module_param(connect_retries, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(connect_retries,
 		"Maximum number of connect retries (one second each)");
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 76a0640..5811d34 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -132,19 +132,11 @@
 
 #define IPW_WANTS_TO_SEND	0x30
 
-static const struct usb_device_id usb_ipw_ids[] = {
+static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(IPW_VID, IPW_PID) },
 	{ },
 };
-
-MODULE_DEVICE_TABLE(usb, usb_ipw_ids);
-
-static struct usb_driver usb_ipw_driver = {
-	.name =		"ipwtty",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	usb_ipw_ids,
-};
+MODULE_DEVICE_TABLE(usb, id_table);
 
 static bool debug;
 
@@ -155,8 +147,6 @@
 	u8 *buf_flow_init;
 	int result;
 
-	dbg("%s", __func__);
-
 	buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL);
 	if (!buf_flow_init)
 		return -ENOMEM;
@@ -317,7 +307,7 @@
 		.name =		"ipw",
 	},
 	.description =		"IPWireless converter",
-	.id_table =		usb_ipw_ids,
+	.id_table =		id_table,
 	.num_ports =		1,
 	.disconnect =		usb_wwan_disconnect,
 	.open =			ipw_open,
@@ -333,7 +323,7 @@
 	&ipw_device, NULL
 };
 
-module_usb_serial_driver(usb_ipw_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 /* Module information */
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 84965cd..fc09414 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -77,13 +77,6 @@
 
 MODULE_DEVICE_TABLE(usb, ir_id_table);
 
-static struct usb_driver ir_driver = {
-	.name		= "ir-usb",
-	.probe		= usb_serial_probe,
-	.disconnect	= usb_serial_disconnect,
-	.id_table	= ir_id_table,
-};
-
 static struct usb_serial_driver ir_device = {
 	.driver	= {
 		.owner	= THIS_MODULE,
@@ -103,18 +96,21 @@
 	&ir_device, NULL
 };
 
-static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc)
+static inline void irda_usb_dump_class_desc(struct usb_serial *serial,
+					    struct usb_irda_cs_descriptor *desc)
 {
-	dbg("bLength=%x", desc->bLength);
-	dbg("bDescriptorType=%x", desc->bDescriptorType);
-	dbg("bcdSpecRevision=%x", __le16_to_cpu(desc->bcdSpecRevision));
-	dbg("bmDataSize=%x", desc->bmDataSize);
-	dbg("bmWindowSize=%x", desc->bmWindowSize);
-	dbg("bmMinTurnaroundTime=%d", desc->bmMinTurnaroundTime);
-	dbg("wBaudRate=%x", __le16_to_cpu(desc->wBaudRate));
-	dbg("bmAdditionalBOFs=%x", desc->bmAdditionalBOFs);
-	dbg("bIrdaRateSniff=%x", desc->bIrdaRateSniff);
-	dbg("bMaxUnicastList=%x", desc->bMaxUnicastList);
+	struct device *dev = &serial->dev->dev;
+
+	dev_dbg(dev, "bLength=%x\n", desc->bLength);
+	dev_dbg(dev, "bDescriptorType=%x\n", desc->bDescriptorType);
+	dev_dbg(dev, "bcdSpecRevision=%x\n", __le16_to_cpu(desc->bcdSpecRevision));
+	dev_dbg(dev, "bmDataSize=%x\n", desc->bmDataSize);
+	dev_dbg(dev, "bmWindowSize=%x\n", desc->bmWindowSize);
+	dev_dbg(dev, "bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);
+	dev_dbg(dev, "wBaudRate=%x\n", __le16_to_cpu(desc->wBaudRate));
+	dev_dbg(dev, "bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs);
+	dev_dbg(dev, "bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
+	dev_dbg(dev, "bMaxUnicastList=%x\n", desc->bMaxUnicastList);
 }
 
 /*------------------------------------------------------------------*/
@@ -130,8 +126,9 @@
  * Based on the same function in drivers/net/irda/irda-usb.c
  */
 static struct usb_irda_cs_descriptor *
-irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
+irda_usb_find_class_desc(struct usb_serial *serial, unsigned int ifnum)
 {
+	struct usb_device *dev = serial->dev;
 	struct usb_irda_cs_descriptor *desc;
 	int ret;
 
@@ -144,20 +141,20 @@
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 			0, ifnum, desc, sizeof(*desc), 1000);
 
-	dbg("%s -  ret=%d", __func__, ret);
+	dev_dbg(&serial->dev->dev, "%s -  ret=%d\n", __func__, ret);
 	if (ret < sizeof(*desc)) {
-		dbg("%s - class descriptor read %s (%d)",
-				__func__,
-				(ret < 0) ? "failed" : "too short",
-				ret);
+		dev_dbg(&serial->dev->dev,
+			"%s - class descriptor read %s (%d)\n", __func__,
+			(ret < 0) ? "failed" : "too short", ret);
 		goto error;
 	}
 	if (desc->bDescriptorType != USB_DT_CS_IRDA) {
-		dbg("%s - bad class descriptor type", __func__);
+		dev_dbg(&serial->dev->dev, "%s - bad class descriptor type\n",
+			__func__);
 		goto error;
 	}
 
-	irda_usb_dump_class_desc(desc);
+	irda_usb_dump_class_desc(serial, desc);
 	return desc;
 
 error:
@@ -207,14 +204,15 @@
 {
 	struct usb_irda_cs_descriptor *irda_desc;
 
-	irda_desc = irda_usb_find_class_desc(serial->dev, 0);
+	irda_desc = irda_usb_find_class_desc(serial, 0);
 	if (!irda_desc) {
 		dev_err(&serial->dev->dev,
 			"IRDA class descriptor not found, device not bound\n");
 		return -ENODEV;
 	}
 
-	dbg("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s",
+	dev_dbg(&serial->dev->dev,
+		"%s - Baud rates supported:%s%s%s%s%s%s%s%s%s\n",
 		__func__,
 		(irda_desc->wBaudRate & USB_IRDA_BR_2400) ? " 2400" : "",
 		(irda_desc->wBaudRate & USB_IRDA_BR_9600) ? " 9600" : "",
@@ -264,8 +262,6 @@
 {
 	int i;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
 		port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET;
 
@@ -322,15 +318,11 @@
 
 static void ir_set_termios_callback(struct urb *urb)
 {
-	struct usb_serial_port *port = urb->context;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
 	kfree(urb->transfer_buffer);
 
-	if (status)
-		dbg("%s - non-zero urb status: %d", __func__, status);
+	if (urb->status)
+		dev_dbg(&urb->dev->dev, "%s - non-zero urb status: %d\n",
+			__func__, urb->status);
 }
 
 static void ir_set_termios(struct tty_struct *tty,
@@ -342,8 +334,6 @@
 	speed_t baud;
 	int ir_baud;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	baud = tty_get_baud_rate(tty);
 
 	/*
@@ -447,7 +437,7 @@
 		ir_device.bulk_out_size = buffer_size;
 	}
 
-	retval = usb_serial_register_drivers(&ir_driver, serial_drivers);
+	retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table);
 	if (retval == 0)
 		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
 			       DRIVER_DESC "\n");
@@ -456,7 +446,7 @@
 
 static void __exit ir_exit(void)
 {
-	usb_serial_deregister_drivers(&ir_driver, serial_drivers);
+	usb_serial_deregister_drivers(serial_drivers);
 }
 
 
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index f2192d5..22b1eb5 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -51,13 +51,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver iuu_driver = {
-	.name = "iuu_phoenix",
-	.probe = usb_serial_probe,
-	.disconnect = usb_serial_disconnect,
-	.id_table = id_table,
-};
-
 /* turbo parameter */
 static int boost = 100;
 static int clockmode = 1;
@@ -135,8 +128,6 @@
 	if (!port)
 		return;
 
-	dbg("%s", __func__);
-
 	if (priv) {
 		iuu_free_buf(priv);
 		dbg("%s - I will free all", __func__);
@@ -198,8 +189,6 @@
 	int result;
 	int status = urb->status;
 
-	dbg("%s - enter", __func__);
-
 	if (status) {
 		dbg("%s - status = %d", __func__, status);
 		/* error stop all */
@@ -221,7 +210,6 @@
 	struct iuu_private *priv = usb_get_serial_port_data(port);
 	int result;
 	char *buf_ptr = port->write_urb->transfer_buffer;
-	dbg("%s - enter", __func__);
 
 	/* Prepare the reset sequence */
 
@@ -255,8 +243,6 @@
 	u8 *st;
 	int status = urb->status;
 
-	dbg("%s - enter", __func__);
-
 	if (status) {
 		dbg("%s - status = %d", __func__, status);
 		/* error stop all */
@@ -299,8 +285,6 @@
 {
 	int result;
 
-	dbg("%s - enter", __func__);
-
 	memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
 	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
 			  usb_sndbulkpipe(port->serial->dev,
@@ -318,8 +302,6 @@
 	struct usb_serial *serial = port->serial;
 	int actual = 0;
 
-	dbg("%s - enter", __func__);
-
 	/* send the data out the bulk port */
 
 	status =
@@ -341,10 +323,7 @@
 	struct usb_serial *serial = port->serial;
 	int actual = 0;
 
-	dbg("%s - enter", __func__);
-
 	/* send the data out the bulk port */
-
 	status =
 	    usb_bulk_msg(serial->dev,
 			 usb_rcvbulkpipe(serial->dev,
@@ -367,8 +346,6 @@
 	if (!buf)
 		return -ENOMEM;
 
-	dbg("%s - enter", __func__);
-
 	buf[0] = IUU_SET_LED;
 	buf[1] = R & 0xFF;
 	buf[2] = (R >> 8) & 0xFF;
@@ -460,8 +437,6 @@
 	unsigned int P2 = 0;
 	int frq = (int)dwFrq;
 
-	dbg("%s - enter", __func__);
-
 	if (frq == 0) {
 		priv->buf[Count++] = IUU_UART_WRITE_I2C;
 		priv->buf[Count++] = FrqGenAdr << 1;
@@ -590,8 +565,6 @@
 	u8 rxcmd = IUU_UART_RX;
 	struct iuu_private *priv = usb_get_serial_port_data(port);
 
-	dbg("%s - enter", __func__);
-
 	if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
 		return -EIO;
 
@@ -630,8 +603,6 @@
 	struct tty_struct *tty;
 	int status = urb->status;
 
-	dbg("%s - status = %d", __func__, status);
-
 	if (status) {
 		if (status == -EPROTO) {
 			/* reschedule needed */
@@ -659,7 +630,6 @@
 	int i;
 	int buf_len;
 	char *buf_ptr = port->write_urb->transfer_buffer;
-	dbg("%s - enter", __func__);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	*buf_ptr++ = IUU_UART_ESC;
@@ -691,7 +661,6 @@
 static int iuu_read_buf(struct usb_serial_port *port, int len)
 {
 	int result;
-	dbg("%s - enter", __func__);
 
 	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
 			  usb_rcvbulkpipe(port->serial->dev,
@@ -713,8 +682,6 @@
 	unsigned char *data = urb->transfer_buffer;
 	priv->poll++;
 
-	dbg("%s - enter", __func__);
-
 	if (status) {
 		dbg("%s - status = %d", __func__, status);
 		/* error stop all */
@@ -771,7 +738,6 @@
 {
 	struct iuu_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
-	dbg("%s - enter", __func__);
 
 	if (count > 256)
 		return -ENOMEM;
@@ -792,8 +758,6 @@
 	int result;
 	int status = urb->status;
 
-	dbg("%s - status = %d", __func__, status);
-
 	if (status) {
 		/* error stop all */
 		return;
@@ -1015,8 +979,6 @@
 	if (!serial)
 		return;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	iuu_uart_off(port);
 	if (serial->dev) {
 		/* free writebuf */
@@ -1031,7 +993,6 @@
 
 static void iuu_init_termios(struct tty_struct *tty)
 {
-	dbg("%s - enter", __func__);
 	*(tty->termios) = tty_std_termios;
 	tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
 				| TIOCM_CTS | CSTOPB | PARENB;
@@ -1188,8 +1149,6 @@
 	if (!buf)
 		return -ENOMEM;
 
-	dbg("%s - enter", __func__);
-
 	buf[0] = IUU_SET_VCC;
 	buf[1] = vcc & 0xFF;
 	buf[2] = (vcc >> 8) & 0xFF;
@@ -1250,15 +1209,11 @@
 
 static int iuu_create_sysfs_attrs(struct usb_serial_port *port)
 {
-	dbg("%s", __func__);
-
 	return device_create_file(&port->dev, &dev_attr_vcc_mode);
 }
 
 static int iuu_remove_sysfs_attrs(struct usb_serial_port *port)
 {
-	dbg("%s", __func__);
-
 	device_remove_file(&port->dev, &dev_attr_vcc_mode);
 	return 0;
 }
@@ -1294,7 +1249,7 @@
 	&iuu_device, NULL
 };
 
-module_usb_serial_driver(iuu_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
 
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index a39ddd1..a1b9924 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -130,15 +130,13 @@
 #include "keyspan_usa67msg.h"
 
 
-module_usb_serial_driver(keyspan_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
 
 static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
 {
 	struct usb_serial_port *port = tty->driver_data;
 	struct keyspan_port_private 	*p_priv;
 
-	dbg("%s", __func__);
-
 	p_priv = usb_get_serial_port_data(port);
 
 	if (break_state == -1)
@@ -158,8 +156,6 @@
 	const struct keyspan_device_details	*d_details;
 	unsigned int 			cflag;
 
-	dbg("%s", __func__);
-
 	p_priv = usb_get_serial_port_data(port);
 	d_details = p_priv->device_details;
 	cflag = tty->termios->c_cflag;
@@ -306,8 +302,6 @@
 	unsigned char 		*data = urb->transfer_buffer;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	endpoint = usb_pipeendpoint(urb->pipe);
 
 	if (status) {
@@ -369,8 +363,6 @@
 
 static void	usa26_inack_callback(struct urb *urb)
 {
-	dbg("%s", __func__);
-
 }
 
 static void	usa26_outcont_callback(struct urb *urb)
@@ -452,7 +444,6 @@
 
 static void	usa26_glocont_callback(struct urb *urb)
 {
-	dbg("%s", __func__);
 }
 
 
@@ -465,8 +456,6 @@
 	struct keyspan_port_private             *p_priv;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	port =  urb->context;
 	p_priv = usb_get_serial_port_data(port);
 	data = urb->transfer_buffer;
@@ -505,7 +494,6 @@
 
 static void	usa28_inack_callback(struct urb *urb)
 {
-	dbg("%s", __func__);
 }
 
 static void	usa28_outcont_callback(struct urb *urb)
@@ -585,7 +573,6 @@
 
 static void	usa28_glocont_callback(struct urb *urb)
 {
-	dbg("%s", __func__);
 }
 
 
@@ -596,8 +583,6 @@
 	struct keyspan_port_private *p_priv;
 	int i;
 
-	dbg("%s", __func__);
-
 	serial =  urb->context;
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
@@ -625,8 +610,6 @@
 	int old_dcd_state;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	serial =  urb->context;
 
 	if (status) {
@@ -679,7 +662,6 @@
 
 static void	usa49_inack_callback(struct urb *urb)
 {
-	dbg("%s", __func__);
 }
 
 static void	usa49_indat_callback(struct urb *urb)
@@ -691,8 +673,6 @@
 	unsigned char 		*data = urb->transfer_buffer;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	endpoint = usb_pipeendpoint(urb->pipe);
 
 	if (status) {
@@ -742,8 +722,6 @@
 	unsigned char 		*data = urb->transfer_buffer;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	serial = urb->context;
 
 	if (status) {
@@ -806,7 +784,6 @@
 /* not used, usa-49 doesn't have per-port control endpoints */
 static void usa49_outcont_callback(struct urb *urb)
 {
-	dbg("%s", __func__);
 }
 
 static void usa90_indat_callback(struct urb *urb)
@@ -819,8 +796,6 @@
 	unsigned char 		*data = urb->transfer_buffer;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	endpoint = usb_pipeendpoint(urb->pipe);
 
 	if (status) {
@@ -957,8 +932,6 @@
 	int old_dcd_state;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	serial = urb->context;
 
 	if (status) {
@@ -1010,8 +983,6 @@
 	struct keyspan_port_private *p_priv;
 	int i;
 
-	dbg("%s", __func__);
-
 	serial = urb->context;
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
@@ -1035,7 +1006,6 @@
 	int				data_len;
 	struct urb			*this_urb;
 
-	dbg("%s", __func__);
 	p_priv = usb_get_serial_port_data(port);
 	d_details = p_priv->device_details;
 
@@ -1078,8 +1048,6 @@
 	p_priv = usb_get_serial_port_data(port);
 	d_details = p_priv->device_details;
 
-	dbg("%s - port%d.", __func__, port->number);
-
 	/* Set some sane defaults */
 	p_priv->rts_state = 1;
 	p_priv->dtr_state = 1;
@@ -1165,7 +1133,6 @@
 	struct keyspan_serial_private 	*s_priv;
 	struct keyspan_port_private 	*p_priv;
 
-	dbg("%s", __func__);
 	s_priv = usb_get_serial_data(serial);
 	p_priv = usb_get_serial_port_data(port);
 
@@ -1438,8 +1405,6 @@
 	struct callbacks		*cback;
 	int				endp;
 
-	dbg("%s", __func__);
-
 	s_priv = usb_get_serial_data(serial);
 	d_details = s_priv->device_details;
 
@@ -1853,8 +1818,6 @@
 	struct urb				*this_urb;
 	int 					device_port, err;
 
-	dbg("%s", __func__);
-
 	s_priv = usb_get_serial_data(serial);
 	p_priv = usb_get_serial_port_data(port);
 	d_details = s_priv->device_details;
@@ -1980,8 +1943,6 @@
 	struct urb				*this_urb;
 	int 					err, device_port;
 
-	dbg("%s", __func__);
-
 	s_priv = usb_get_serial_data(serial);
 	p_priv = usb_get_serial_port_data(port);
 	d_details = s_priv->device_details;
@@ -2168,8 +2129,6 @@
 	int 					err;
 	u8						prescaler;
 
-	dbg("%s", __func__);
-
 	s_priv = usb_get_serial_data(serial);
 	p_priv = usb_get_serial_port_data(port);
 	d_details = s_priv->device_details;
@@ -2300,8 +2259,6 @@
 	struct urb				*this_urb;
 	int 					err, device_port;
 
-	dbg("%s", __func__);
-
 	s_priv = usb_get_serial_data(serial);
 	p_priv = usb_get_serial_port_data(port);
 	d_details = s_priv->device_details;
@@ -2442,8 +2399,6 @@
 	struct keyspan_serial_private *s_priv;
 	const struct keyspan_device_details *d_details;
 
-	dbg("%s", __func__);
-
 	s_priv = usb_get_serial_data(serial);
 	d_details = s_priv->device_details;
 
@@ -2477,8 +2432,6 @@
 	struct keyspan_port_private	*p_priv;
 	const struct keyspan_device_details	*d_details;
 
-	dbg("%s", __func__);
-
 	for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
 		if (d_details->product_id ==
 				le16_to_cpu(serial->dev->descriptor.idProduct))
@@ -2538,8 +2491,6 @@
 	struct keyspan_serial_private 	*s_priv;
 	struct keyspan_port_private	*p_priv;
 
-	dbg("%s", __func__);
-
 	s_priv = usb_get_serial_data(serial);
 
 	/* Stop reading/writing urbs */
@@ -2579,8 +2530,6 @@
 	struct usb_serial_port		*port;
 	struct keyspan_serial_private 	*s_priv;
 
-	dbg("%s", __func__);
-
 	s_priv = usb_get_serial_data(serial);
 
 	/*  dbg("Freeing serial->private."); */
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 622853c..fe1c5d9 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -487,13 +487,6 @@
 
 MODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
 
-static struct usb_driver keyspan_driver = {
-	.name =		"keyspan",                
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	keyspan_ids_combined,
-};
-
 /* usb_device_id table for the pre-firmware download keyspan devices */
 static const struct usb_device_id keyspan_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 693bcdf..a4ac3cf 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -86,13 +86,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
-static struct usb_driver keyspan_pda_driver = {
-	.name =		"keyspan_pda",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
-
 static const struct usb_device_id id_table_std[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
 	{ }						/* Terminating entry */
@@ -131,7 +124,6 @@
 	struct usb_serial *serial = priv->serial;
 	int result;
 
-	dbg(" request_unthrottle");
 	/* ask the device to tell us when the tx buffer becomes
 	   sufficiently empty */
 	result = usb_control_msg(serial->dev,
@@ -226,7 +218,7 @@
 	   send an XOFF, although it might make sense to foist that off
 	   upon the device too. */
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("keyspan_pda_rx_throttle port %d", port->number);
+
 	usb_kill_urb(port->interrupt_in_urb);
 }
 
@@ -235,7 +227,7 @@
 {
 	struct usb_serial_port *port = tty->driver_data;
 	/* just restart the receive interrupt URB */
-	dbg("keyspan_pda_rx_unthrottle port %d", port->number);
+
 	if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
 		dbg(" usb_submit_urb(read urb) failed");
 }
@@ -466,7 +458,6 @@
 	   select() or poll() too) until we receive that unthrottle interrupt.
 	   Block if we can't write anything at all, otherwise write as much as
 	   we can. */
-	dbg("keyspan_pda_write(%d)", count);
 	if (count == 0) {
 		dbg(" write request of 0 bytes");
 		return 0;
@@ -766,8 +757,6 @@
 
 static void keyspan_pda_release(struct usb_serial *serial)
 {
-	dbg("%s", __func__);
-
 	kfree(usb_get_serial_port_data(serial->port[0]));
 }
 
@@ -834,7 +823,7 @@
 	NULL
 };
 
-module_usb_serial_driver(keyspan_pda_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 10f0540..5bed59c 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -86,13 +86,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver kl5kusb105d_driver = {
-	.name =		"kl5kusb105d",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver kl5kusb105d_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -282,8 +275,6 @@
 {
 	int i;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i)
 		kfree(usb_get_serial_port_data(serial->port[i]));
 }
@@ -298,8 +289,6 @@
 	struct klsi_105_port_settings *cfg;
 	unsigned long flags;
 
-	dbg("%s port %d", __func__, port->number);
-
 	/* Do a defined restart:
 	 * Set up sane default baud rate and send the 'READ_ON'
 	 * vendor command.
@@ -376,8 +365,6 @@
 {
 	int rc;
 
-	dbg("%s port %d", __func__, port->number);
-
 	mutex_lock(&port->serial->disc_mutex);
 	if (!port->serial->disconnected) {
 		/* send READ_OFF */
@@ -646,7 +633,6 @@
 	unsigned long flags;
 	int rc;
 	unsigned long line_state;
-	dbg("%s - request, just guessing", __func__);
 
 	rc = klsi_105_get_line_state(port, &line_state);
 	if (rc < 0) {
@@ -668,8 +654,6 @@
 {
 	int retval = -EINVAL;
 
-	dbg("%s", __func__);
-
 /* if this ever gets implemented, it should be done something like this:
 	struct usb_serial *serial = port->serial;
 	struct klsi_105_private *priv = usb_get_serial_port_data(port);
@@ -692,7 +676,7 @@
 	return retval;
 }
 
-module_usb_serial_driver(kl5kusb105d_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 4a9a75e..fafeabb 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -81,18 +81,8 @@
 	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) },
 	{ }			/* Terminating entry */
 };
-
-
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver kobil_driver = {
-	.name =		"kobil",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
-
 static struct usb_serial_driver kobil_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -193,7 +183,6 @@
 static void kobil_release(struct usb_serial *serial)
 {
 	int i;
-	dbg("%s - port %d", __func__, serial->port[0]->number);
 
 	for (i = 0; i < serial->num_ports; ++i)
 		kfree(usb_get_serial_port_data(serial->port[i]));
@@ -217,7 +206,6 @@
 	int transfer_buffer_length = 8;
 	int write_urb_transfer_buffer_length = 8;
 
-	dbg("%s - port %d", __func__, port->number);
 	priv = usb_get_serial_port_data(port);
 
 	/* allocate memory for transfer buffer */
@@ -327,8 +315,6 @@
 
 static void kobil_close(struct usb_serial_port *port)
 {
-	dbg("%s - port %d", __func__, port->number);
-
 	/* FIXME: Add rts/dtr methods */
 	if (port->write_urb) {
 		usb_poison_urb(port->write_urb);
@@ -349,8 +335,6 @@
 	int status = urb->status;
 /*	char *dbg_data; */
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (status) {
 		dbg("%s - port %d Read int status not zero: %d",
 		    __func__, port->number, status);
@@ -474,7 +458,6 @@
 
 static int kobil_write_room(struct tty_struct *tty)
 {
-	/* dbg("%s - port %d", __func__, port->number); */
 	/* FIXME */
 	return 8;
 }
@@ -683,7 +666,7 @@
 	}
 }
 
-module_usb_serial_driver(kobil_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 6edd261..d0ec1aa 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -73,22 +73,14 @@
 /*
  * All of the device info needed for the MCT USB-RS232 converter.
  */
-static const struct usb_device_id id_table_combined[] = {
+static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
 	{ USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
 	{ }		/* Terminating entry */
 };
-
-MODULE_DEVICE_TABLE(usb, id_table_combined);
-
-static struct usb_driver mct_u232_driver = {
-	.name =		"mct_u232",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
+MODULE_DEVICE_TABLE(usb, id_table);
 
 static struct usb_serial_driver mct_u232_device = {
 	.driver = {
@@ -96,7 +88,7 @@
 		.name =		"mct_u232",
 	},
 	.description =	     "MCT U232",
-	.id_table =	     id_table_combined,
+	.id_table =	     id_table,
 	.num_ports =	     1,
 	.open =		     mct_u232_open,
 	.close =	     mct_u232_close,
@@ -427,8 +419,6 @@
 	struct mct_u232_private *priv;
 	int i;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i) {
 		/* My special items, the standard routines free my urbs */
 		priv = usb_get_serial_port_data(serial->port[i]);
@@ -446,8 +436,6 @@
 	unsigned char last_lcr;
 	unsigned char last_msr;
 
-	dbg("%s port %d", __func__, port->number);
-
 	/* Compensate for a hardware bug: although the Sitecom U232-P25
 	 * device reports a maximum output packet size of 32 bytes,
 	 * it seems to be able to accept only 16 bytes (and that's what
@@ -528,8 +516,6 @@
 
 static void mct_u232_close(struct usb_serial_port *port)
 {
-	dbg("%s port %d", __func__, port->number);
-
 	if (port->serial->dev) {
 		/* shutdown our urbs */
 		usb_kill_urb(port->write_urb);
@@ -572,7 +558,6 @@
 		return;
 	}
 
-	dbg("%s - port %d", __func__, port->number);
 	usb_serial_debug_data(debug, &port->dev, __func__,
 					urb->actual_length, data);
 
@@ -733,8 +718,6 @@
 	unsigned char lcr;
 	unsigned long flags;
 
-	dbg("%sstate=%d", __func__, break_state);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	lcr = priv->last_lcr;
 
@@ -753,8 +736,6 @@
 	unsigned int control_state;
 	unsigned long flags;
 
-	dbg("%s", __func__);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	control_state = priv->control_state;
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -771,8 +752,6 @@
 	unsigned int control_state;
 	unsigned long flags;
 
-	dbg("%s", __func__);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	control_state = priv->control_state;
 
@@ -796,8 +775,6 @@
 	struct mct_u232_private *priv = usb_get_serial_port_data(port);
 	unsigned int control_state;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irq(&priv->lock);
 	priv->rx_flags |= THROTTLED;
 	if (C_CRTSCTS(tty)) {
@@ -816,8 +793,6 @@
 	struct mct_u232_private *priv = usb_get_serial_port_data(port);
 	unsigned int control_state;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irq(&priv->lock);
 	if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
 		priv->rx_flags &= ~THROTTLED;
@@ -906,7 +881,7 @@
 	return 0;
 }
 
-module_usb_serial_driver(mct_u232_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index 08d16e8..81423f7 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -17,7 +17,6 @@
 #include <linux/tty_flip.h>
 #include <linux/moduleparam.h>
 #include <linux/spinlock.h>
-#include <linux/errno.h>
 #include <linux/uaccess.h>
 #include <linux/usb/serial.h>
 
@@ -56,6 +55,47 @@
 /* Input parameter constants. */
 static bool debug;
 
+/* UNI-Directional mode commands for device configure */
+#define UNI_CMD_OPEN	0x80
+#define UNI_CMD_CLOSE	0xFF
+
+inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)
+{
+	__u16 product_id = le16_to_cpu(
+		port->serial->dev->descriptor.idProduct);
+
+	return product_id == FOCUS_PRODUCT_ID_UNI;
+}
+
+static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port)
+{
+	int ret;
+	int actual_len;
+	u8 *buffer_cmd = NULL;
+
+	if (!metrousb_is_unidirectional_mode(port))
+		return 0;
+
+	buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL);
+	if (!buffer_cmd)
+		return -ENOMEM;
+
+	*buffer_cmd = cmd;
+
+	ret = usb_interrupt_msg(port->serial->dev,
+		usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
+		buffer_cmd, sizeof(cmd),
+		&actual_len, USB_CTRL_SET_TIMEOUT);
+
+	kfree(buffer_cmd);
+
+	if (ret < 0)
+		return ret;
+	else if (actual_len != sizeof(cmd))
+		return -EIO;
+	return 0;
+}
+
 static void metrousb_read_int_callback(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
@@ -78,12 +118,12 @@
 		/* urb has been terminated. */
 		dev_dbg(&port->dev,
 			"%s - urb shutting down, error code=%d\n",
-			__func__, result);
+			__func__, urb->status);
 		return;
 	default:
 		dev_dbg(&port->dev,
 			"%s - non-zero urb received, error code=%d\n",
-			__func__, result);
+			__func__, urb->status);
 		goto exit;
 	}
 
@@ -91,7 +131,7 @@
 	/* Set the data read from the usb port into the serial port buffer. */
 	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
-		dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n",
+		dev_err(&port->dev, "%s - bad tty pointer - exiting\n",
 			__func__);
 		return;
 	}
@@ -121,7 +161,7 @@
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 
 		if (result)
-			dev_dbg(&port->dev,
+			dev_err(&port->dev,
 				"%s - failed submitting interrupt in urb, error code=%d\n",
 				__func__, result);
 	}
@@ -131,11 +171,19 @@
 	/* Try to resubmit the urb. */
 	result = usb_submit_urb(urb, GFP_ATOMIC);
 	if (result)
-		dev_dbg(&port->dev,
+		dev_err(&port->dev,
 			"%s - failed submitting interrupt in urb, error code=%d\n",
 			__func__, result);
 }
 
+static void metrousb_write_int_callback(struct urb *urb)
+{
+	struct usb_serial_port *port = urb->context;
+
+	dev_warn(&port->dev, "%s not implemented yet.\n",
+		__func__);
+}
+
 static void metrousb_cleanup(struct usb_serial_port *port)
 {
 	dev_dbg(&port->dev, "%s\n", __func__);
@@ -146,6 +194,9 @@
 			usb_unlink_urb(port->interrupt_in_urb);
 			usb_kill_urb(port->interrupt_in_urb);
 		}
+
+		/* Send deactivate cmd to device */
+		metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
 	}
 }
 
@@ -160,7 +211,7 @@
 
 	/* Make sure the urb is initialized. */
 	if (!port->interrupt_in_urb) {
-		dev_dbg(&port->dev, "%s - interrupt urb not initialized\n",
+		dev_err(&port->dev, "%s - interrupt urb not initialized\n",
 			__func__);
 		return -ENODEV;
 	}
@@ -191,12 +242,21 @@
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 
 	if (result) {
-		dev_dbg(&port->dev,
+		dev_err(&port->dev,
 			"%s - failed submitting interrupt in urb, error code=%d\n",
 			__func__, result);
 		goto exit;
 	}
 
+	/* Send activate cmd to device */
+	result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port);
+	if (result) {
+		dev_err(&port->dev,
+			"%s - failed to configure device for port number=%d, error code=%d\n",
+			__func__, port->number, result);
+		goto exit;
+	}
+
 	dev_dbg(&port->dev, "%s - port open\n", __func__);
 exit:
 	return result;
@@ -221,7 +281,7 @@
 				METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST,
 				control_state, 0, NULL, 0, WDR_TIMEOUT);
 	if (retval < 0)
-		dev_dbg(&serial->dev->dev,
+		dev_err(&serial->dev->dev,
 			"%s - set modem ctrl=0x%x failed, error code=%d\n",
 			__func__, mcr, retval);
 
@@ -354,29 +414,23 @@
 	port->interrupt_in_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 	if (result)
-		dev_dbg(tty->dev,
+		dev_err(tty->dev,
 			"failed submitting interrupt in urb error code=%d\n",
 			result);
 }
 
-static struct usb_driver metrousb_driver = {
-	.name =		"metro-usb",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table
-};
-
 static struct usb_serial_driver metrousb_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
 		.name =		"metro-usb",
 	},
-	.description		= "Metrologic USB to serial converter.",
+	.description		= "Metrologic USB to Serial",
 	.id_table		= id_table,
 	.num_ports		= 1,
 	.open			= metrousb_open,
 	.close			= metrousb_cleanup,
 	.read_int_callback	= metrousb_read_int_callback,
+	.write_int_callback	= metrousb_write_int_callback,
 	.attach			= metrousb_startup,
 	.release		= metrousb_shutdown,
 	.throttle		= metrousb_throttle,
@@ -390,7 +444,7 @@
 	NULL,
 };
 
-module_usb_serial_driver(metrousb_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Philip Nicastro");
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index bdce820..a07dd3c 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -79,12 +79,12 @@
 #define MOSCHIP_DEVICE_ID_7720		0x7720
 #define MOSCHIP_DEVICE_ID_7715		0x7715
 
-static const struct usb_device_id moschip_port_id_table[] = {
+static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) },
 	{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) },
 	{ } /* terminating entry */
 };
-MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
 
 #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
 
@@ -257,7 +257,6 @@
 	struct mos7715_parport *mos_parport =
 		container_of(kref, struct mos7715_parport, ref_count);
 
-	dbg("%s called", __func__);
 	kfree(mos_parport);
 }
 
@@ -266,7 +265,7 @@
 	struct urbtracker *urbtrack =
 		container_of(kref, struct urbtracker, ref_count);
 	struct mos7715_parport *mos_parport = urbtrack->mos_parport;
-	dbg("%s called", __func__);
+
 	usb_free_urb(urbtrack->urb);
 	kfree(urbtrack);
 	kref_put(&mos_parport->ref_count, destroy_mos_parport);
@@ -285,8 +284,6 @@
 	struct urbtracker *urbtrack;
 	struct list_head *cursor, *next;
 
-	dbg("%s called", __func__);
-
 	/* if release function ran, game over */
 	if (unlikely(mos_parport->serial == NULL))
 		return;
@@ -335,7 +332,7 @@
 {
 	struct urbtracker *urbtrack = urb->context;
 	int status = urb->status;
-	dbg("%s called", __func__);
+
 	if (unlikely(status))
 		dbg("%s - nonzero urb status received: %d", __func__, status);
 
@@ -355,7 +352,6 @@
 	struct usb_ctrlrequest setup;
 	struct usb_serial *serial = mos_parport->serial;
 	struct usb_device *usbdev = serial->dev;
-	dbg("%s called", __func__);
 
 	/* create and initialize the control urb and containing urbtracker */
 	urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC);
@@ -476,7 +472,7 @@
 static void parport_mos7715_write_data(struct parport *pp, unsigned char d)
 {
 	struct mos7715_parport *mos_parport = pp->private_data;
-	dbg("%s called: %2.2x", __func__, d);
+
 	if (parport_prologue(pp) < 0)
 		return;
 	mos7715_change_mode(mos_parport, SPP);
@@ -488,7 +484,7 @@
 {
 	struct mos7715_parport *mos_parport = pp->private_data;
 	unsigned char d;
-	dbg("%s called", __func__);
+
 	if (parport_prologue(pp) < 0)
 		return 0;
 	read_mos_reg(mos_parport->serial, dummy, DPR, &d);
@@ -500,7 +496,7 @@
 {
 	struct mos7715_parport *mos_parport = pp->private_data;
 	__u8 data;
-	dbg("%s called: %2.2x", __func__, d);
+
 	if (parport_prologue(pp) < 0)
 		return;
 	data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0);
@@ -513,7 +509,7 @@
 {
 	struct mos7715_parport *mos_parport = pp->private_data;
 	__u8 dcr;
-	dbg("%s called", __func__);
+
 	spin_lock(&release_lock);
 	mos_parport = pp->private_data;
 	if (unlikely(mos_parport == NULL)) {
@@ -531,7 +527,7 @@
 {
 	struct mos7715_parport *mos_parport = pp->private_data;
 	__u8 dcr;
-	dbg("%s called", __func__);
+
 	mask &= 0x0f;
 	val &= 0x0f;
 	if (parport_prologue(pp) < 0)
@@ -547,7 +543,7 @@
 {
 	unsigned char status;
 	struct mos7715_parport *mos_parport = pp->private_data;
-	dbg("%s called", __func__);
+
 	spin_lock(&release_lock);
 	mos_parport = pp->private_data;
 	if (unlikely(mos_parport == NULL)) {	/* release called */
@@ -561,17 +557,16 @@
 
 static void parport_mos7715_enable_irq(struct parport *pp)
 {
-	dbg("%s called", __func__);
 }
+
 static void parport_mos7715_disable_irq(struct parport *pp)
 {
-	dbg("%s called", __func__);
 }
 
 static void parport_mos7715_data_forward(struct parport *pp)
 {
 	struct mos7715_parport *mos_parport = pp->private_data;
-	dbg("%s called", __func__);
+
 	if (parport_prologue(pp) < 0)
 		return;
 	mos7715_change_mode(mos_parport, PS2);
@@ -583,7 +578,7 @@
 static void parport_mos7715_data_reverse(struct parport *pp)
 {
 	struct mos7715_parport *mos_parport = pp->private_data;
-	dbg("%s called", __func__);
+
 	if (parport_prologue(pp) < 0)
 		return;
 	mos7715_change_mode(mos_parport, PS2);
@@ -595,7 +590,6 @@
 static void parport_mos7715_init_state(struct pardevice *dev,
 				       struct parport_state *s)
 {
-	dbg("%s called", __func__);
 	s->u.pc.ctr = DCR_INIT_VAL;
 	s->u.pc.ecr = ECR_INIT_VAL;
 }
@@ -605,7 +599,7 @@
 				       struct parport_state *s)
 {
 	struct mos7715_parport *mos_parport;
-	dbg("%s called", __func__);
+
 	spin_lock(&release_lock);
 	mos_parport = pp->private_data;
 	if (unlikely(mos_parport == NULL)) {	/* release called */
@@ -622,7 +616,7 @@
 					  struct parport_state *s)
 {
 	struct mos7715_parport *mos_parport;
-	dbg("%s called", __func__);
+
 	spin_lock(&release_lock);
 	mos_parport = pp->private_data;
 	if (unlikely(mos_parport == NULL)) {	/* release called */
@@ -641,7 +635,7 @@
 	int retval;
 	struct mos7715_parport *mos_parport = pp->private_data;
 	int actual_len;
-	dbg("%s called: %u chars", __func__, (unsigned int)len);
+
 	if (parport_prologue(pp) < 0)
 		return 0;
 	mos7715_change_mode(mos_parport, PPF);
@@ -2164,20 +2158,13 @@
 		kfree(usb_get_serial_port_data(serial->port[i]));
 }
 
-static struct usb_driver usb_driver = {
-	.name =		"moschip7720",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	moschip_port_id_table,
-};
-
 static struct usb_serial_driver moschip7720_2port_driver = {
 	.driver = {
 		.owner =	THIS_MODULE,
 		.name =		"moschip7720",
 	},
 	.description		= "Moschip 2 port adapter",
-	.id_table		= moschip_port_id_table,
+	.id_table		= id_table,
 	.calc_num_ports		= mos77xx_calc_num_ports,
 	.open			= mos7720_open,
 	.close			= mos7720_close,
@@ -2203,7 +2190,7 @@
 	&moschip7720_2port_driver, NULL
 };
 
-module_usb_serial_driver(usb_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index c526550..29160f8 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -114,10 +114,10 @@
 #define USB_VENDOR_ID_MOSCHIP           0x9710
 #define MOSCHIP_DEVICE_ID_7840          0x7840
 #define MOSCHIP_DEVICE_ID_7820          0x7820
+#define MOSCHIP_DEVICE_ID_7810          0x7810
 /* The native component can have its vendor/device id's overridden
  * in vendor-specific implementations.  Such devices can be handled
- * by making a change here, in moschip_port_id_table, and in
- * moschip_id_table_combined
+ * by making a change here, in id_table.
  */
 #define USB_VENDOR_ID_BANDB              0x0856
 #define BANDB_DEVICE_ID_USO9ML2_2        0xAC22
@@ -184,10 +184,16 @@
 #define NUM_URBS                        16	/* URB Count */
 #define URB_TRANSFER_BUFFER_SIZE        32	/* URB Size  */
 
+/* LED on/off milliseconds*/
+#define LED_ON_MS	500
+#define LED_OFF_MS	500
 
-static const struct usb_device_id moschip_port_id_table[] = {
+static int device_type;
+
+static const struct usb_device_id id_table[] __devinitconst = {
 	{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
 	{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
+	{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)},
 	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
 	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
 	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
@@ -205,29 +211,7 @@
 	{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
 	{}			/* terminating entry */
 };
-
-static const struct usb_device_id moschip_id_table_combined[] __devinitconst = {
-	{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
-	{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)},
-	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
-	{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
-	{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
-	{}			/* terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, moschip_id_table_combined);
+MODULE_DEVICE_TABLE(usb, id_table);
 
 /* This structure holds all of the local port information */
 
@@ -261,8 +245,13 @@
 	struct urb *write_urb_pool[NUM_URBS];
 	char busy[NUM_URBS];
 	bool read_urb_busy;
-};
 
+	/* For device(s) with LED indicator */
+	bool has_led;
+	bool led_flag;
+	struct timer_list led_timer1;	/* Timer for LED on */
+	struct timer_list led_timer2;	/* Timer for LED off */
+};
 
 static bool debug;
 
@@ -572,6 +561,69 @@
 	return ret;
 }
 
+static void mos7840_set_led_callback(struct urb *urb)
+{
+	switch (urb->status) {
+	case 0:
+		/* Success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* This urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __func__,
+			urb->status);
+		break;
+	default:
+		dbg("%s - nonzero urb status received: %d", __func__,
+			urb->status);
+	}
+}
+
+static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
+				__u16 reg)
+{
+	struct usb_device *dev = mcs->port->serial->dev;
+	struct usb_ctrlrequest *dr = mcs->dr;
+
+	dr->bRequestType = MCS_WR_RTYPE;
+	dr->bRequest = MCS_WRREQ;
+	dr->wValue = cpu_to_le16(wval);
+	dr->wIndex = cpu_to_le16(reg);
+	dr->wLength = cpu_to_le16(0);
+
+	usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
+		(unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
+
+	usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+}
+
+static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
+				__u16 val)
+{
+	struct usb_device *dev = port->serial->dev;
+
+	usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE,
+			val, reg, NULL, 0, MOS_WDR_TIMEOUT);
+}
+
+static void mos7840_led_off(unsigned long arg)
+{
+	struct moschip_port *mcs = (struct moschip_port *) arg;
+
+	/* Turn off LED */
+	mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER);
+	mod_timer(&mcs->led_timer2,
+				jiffies + msecs_to_jiffies(LED_OFF_MS));
+}
+
+static void mos7840_led_flag_off(unsigned long arg)
+{
+	struct moschip_port *mcs = (struct moschip_port *) arg;
+
+	mcs->led_flag = false;
+}
+
 /*****************************************************************************
  * mos7840_interrupt_callback
  *	this is the callback function for when we have received data on the
@@ -591,8 +643,6 @@
 	__u16 wval, wreg = 0;
 	int status = urb->status;
 
-	dbg("%s", " : Entering");
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -766,12 +816,8 @@
 		return;
 	}
 
-	dbg("%s", "Entering... ");
-
 	data = urb->transfer_buffer;
 
-	dbg("%s", "Entering ...........");
-
 	if (urb->actual_length) {
 		tty = tty_port_tty_get(&mos7840_port->port->port);
 		if (tty) {
@@ -792,6 +838,14 @@
 		return;
 	}
 
+	/* Turn on LED */
+	if (mos7840_port->has_led && !mos7840_port->led_flag) {
+		mos7840_port->led_flag = true;
+		mos7840_set_led_async(mos7840_port, 0x0301,
+					MODEM_CONTROL_REGISTER);
+		mod_timer(&mos7840_port->led_timer1,
+				jiffies + msecs_to_jiffies(LED_ON_MS));
+	}
 
 	mos7840_port->read_urb_busy = true;
 	retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
@@ -835,8 +889,6 @@
 		return;
 	}
 
-	dbg("%s", "Entering .........");
-
 	tty = tty_port_tty_get(&mos7840_port->port->port);
 	if (tty && mos7840_port->open)
 		tty_wakeup(tty);
@@ -878,8 +930,6 @@
 	struct moschip_port *mos7840_port;
 	struct moschip_port *port0;
 
-	dbg ("%s enter", __func__);
-
 	if (mos7840_port_paranoia_check(port, __func__)) {
 		dbg("%s", "Port Paranoia failed");
 		return -ENODEV;
@@ -1151,10 +1201,7 @@
 	dbg("usb_serial serial:%p       mos7840_port:%p\n      usb_serial_port port:%p",
 				serial, mos7840_port, port);
 
-	dbg ("%s leave", __func__);
-
 	return 0;
-
 }
 
 /*****************************************************************************
@@ -1175,18 +1222,14 @@
 	unsigned long flags;
 	struct moschip_port *mos7840_port;
 
-	dbg("%s", " mos7840_chars_in_buffer:entering ...........");
-
 	if (mos7840_port_paranoia_check(port, __func__)) {
 		dbg("%s", "Invalid port");
 		return 0;
 	}
 
 	mos7840_port = mos7840_get_port_private(port);
-	if (mos7840_port == NULL) {
-		dbg("%s", "mos7840_break:leaving ...........");
+	if (mos7840_port == NULL)
 		return 0;
-	}
 
 	spin_lock_irqsave(&mos7840_port->pool_lock, flags);
 	for (i = 0; i < NUM_URBS; ++i)
@@ -1211,8 +1254,6 @@
 	int j;
 	__u16 Data;
 
-	dbg("%s", "mos7840_close:entering...");
-
 	if (mos7840_port_paranoia_check(port, __func__)) {
 		dbg("%s", "Port Paranoia failed");
 		return;
@@ -1287,8 +1328,6 @@
 	mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
 
 	mos7840_port->open = 0;
-
-	dbg("%s", "Leaving ............");
 }
 
 /************************************************************************
@@ -1343,9 +1382,6 @@
 	struct usb_serial *serial;
 	struct moschip_port *mos7840_port;
 
-	dbg("%s", "Entering ...........");
-	dbg("mos7840_break: Start");
-
 	if (mos7840_port_paranoia_check(port, __func__)) {
 		dbg("%s", "Port Paranoia failed");
 		return;
@@ -1395,8 +1431,6 @@
 	unsigned long flags;
 	struct moschip_port *mos7840_port;
 
-	dbg("%s", " mos7840_write_room:entering ...........");
-
 	if (mos7840_port_paranoia_check(port, __func__)) {
 		dbg("%s", "Invalid port");
 		dbg("%s", " mos7840_write_room:leaving ...........");
@@ -1445,9 +1479,6 @@
 	/* __u16 Data; */
 	const unsigned char *current_position = data;
 	unsigned char *data1;
-	dbg("%s", "entering ...........");
-	/* dbg("mos7840_write: mos7840_port->shadowLCR is %x",
-					mos7840_port->shadowLCR); */
 
 #ifdef NOTMOS7840
 	Data = 0x00;
@@ -1554,6 +1585,14 @@
 	data1 = urb->transfer_buffer;
 	dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
 
+	/* Turn on LED */
+	if (mos7840_port->has_led && !mos7840_port->led_flag) {
+		mos7840_port->led_flag = true;
+		mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
+		mod_timer(&mos7840_port->led_timer1,
+				jiffies + msecs_to_jiffies(LED_ON_MS));
+	}
+
 	/* send it down the pipe */
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 
@@ -1602,8 +1641,6 @@
 		return;
 	}
 
-	dbg("%s", "Entering ..........");
-
 	/* if we are implementing XON/XOFF, send the stop character */
 	if (I_IXOFF(tty)) {
 		unsigned char stop_char = STOP_CHAR(tty);
@@ -1646,8 +1683,6 @@
 		return;
 	}
 
-	dbg("%s", "Entering ..........");
-
 	/* if we are implementing XON/XOFF, send the start character */
 	if (I_IXOFF(tty)) {
 		unsigned char start_char = START_CHAR(tty);
@@ -1676,8 +1711,6 @@
 	int status;
 	mos7840_port = mos7840_get_port_private(port);
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (mos7840_port == NULL)
 		return -ENODEV;
 
@@ -1704,8 +1737,6 @@
 	unsigned int mcr;
 	int status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	mos7840_port = mos7840_get_port_private(port);
 
 	if (mos7840_port == NULL)
@@ -1746,7 +1777,6 @@
 static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
 					  __u16 *clk_sel_val)
 {
-
 	dbg("%s - %d", __func__, baudRate);
 
 	if (baudRate <= 115200) {
@@ -1839,8 +1869,6 @@
 		return -1;
 	}
 
-	dbg("%s", "Entering ..........");
-
 	number = mos7840_port->port->number - mos7840_port->port->serial->minor;
 
 	dbg("%s - port = %d, baud = %d", __func__,
@@ -1966,8 +1994,6 @@
 		return;
 	}
 
-	dbg("%s", "Entering ..........");
-
 	lData = LCR_BITS_8;
 	lStop = LCR_STOP_1;
 	lParity = LCR_PAR_NONE;
@@ -2108,7 +2134,7 @@
 	unsigned int cflag;
 	struct usb_serial *serial;
 	struct moschip_port *mos7840_port;
-	dbg("mos7840_set_termios: START");
+
 	if (mos7840_port_paranoia_check(port, __func__)) {
 		dbg("%s", "Invalid port");
 		return;
@@ -2327,28 +2353,74 @@
 	return -ENOIOCTLCMD;
 }
 
+static int mos7810_check(struct usb_serial *serial)
+{
+	int i, pass_count = 0;
+	__u16 data = 0, mcr_data = 0;
+	__u16 test_pattern = 0x55AA;
+
+	/* Store MCR setting */
+	usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+		MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER,
+		&mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+
+	for (i = 0; i < 16; i++) {
+		/* Send the 1-bit test pattern out to MCS7810 test pin */
+		usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			MCS_WRREQ, MCS_WR_RTYPE,
+			(0x0300 | (((test_pattern >> i) & 0x0001) << 1)),
+			MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT);
+
+		/* Read the test pattern back */
+		usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
+			VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+
+		/* If this is a MCS7810 device, both test patterns must match */
+		if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001)
+			break;
+
+		pass_count++;
+	}
+
+	/* Restore MCR setting */
+	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCS_WRREQ,
+		MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL,
+		0, MOS_WDR_TIMEOUT);
+
+	if (pass_count == 16)
+		return 1;
+
+	return 0;
+}
+
 static int mos7840_calc_num_ports(struct usb_serial *serial)
 {
-	__u16 Data = 0x00;
-	int ret = 0;
+	__u16 data = 0x00;
 	int mos7840_num_ports;
 
-	ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-		MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data,
+	usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+		MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
 		VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
 
-	if ((Data & 0x01) == 0) {
-		mos7840_num_ports = 2;
-		serial->num_bulk_in = 2;
-		serial->num_bulk_out = 2;
-		serial->num_ports = 2;
+	if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
+		serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
+		device_type = serial->dev->descriptor.idProduct;
 	} else {
-		mos7840_num_ports = 4;
-		serial->num_bulk_in = 4;
-		serial->num_bulk_out = 4;
-		serial->num_ports = 4;
+		/* For a MCS7840 device GPIO0 must be set to 1 */
+		if ((data & 0x01) == 1)
+			device_type = MOSCHIP_DEVICE_ID_7840;
+		else if (mos7810_check(serial))
+			device_type = MOSCHIP_DEVICE_ID_7810;
+		else
+			device_type = MOSCHIP_DEVICE_ID_7820;
 	}
 
+	mos7840_num_ports = (device_type >> 4) & 0x000F;
+	serial->num_bulk_in = mos7840_num_ports;
+	serial->num_bulk_out = mos7840_num_ports;
+	serial->num_ports = mos7840_num_ports;
+
 	return mos7840_num_ports;
 }
 
@@ -2361,9 +2433,7 @@
 	struct moschip_port *mos7840_port;
 	struct usb_device *dev;
 	int i, status;
-
 	__u16 Data;
-	dbg("%s", "mos7840_startup :Entering..........");
 
 	if (!serial) {
 		dbg("%s", "Invalid Handler");
@@ -2372,9 +2442,6 @@
 
 	dev = serial->dev;
 
-	dbg("%s", "Entering...");
-	dbg ("mos7840_startup: serial = %p", serial);
-
 	/* we set up the pointers to the endpoints in the mos7840_open *
 	 * function, as the structures aren't created yet.             */
 
@@ -2563,6 +2630,34 @@
 			status = -ENOMEM;
 			goto error;
 		}
+
+		mos7840_port->has_led = false;
+
+		/* Initialize LED timers */
+		if (device_type == MOSCHIP_DEVICE_ID_7810) {
+			mos7840_port->has_led = true;
+
+			init_timer(&mos7840_port->led_timer1);
+			mos7840_port->led_timer1.function = mos7840_led_off;
+			mos7840_port->led_timer1.expires =
+					jiffies + msecs_to_jiffies(LED_ON_MS);
+			mos7840_port->led_timer1.data =
+						(unsigned long)mos7840_port;
+
+			init_timer(&mos7840_port->led_timer2);
+			mos7840_port->led_timer2.function =
+						mos7840_led_flag_off;
+			mos7840_port->led_timer2.expires =
+					jiffies + msecs_to_jiffies(LED_OFF_MS);
+			mos7840_port->led_timer2.data =
+						(unsigned long)mos7840_port;
+
+			mos7840_port->led_flag = false;
+
+			/* Turn off LED */
+			mos7840_set_led_sync(serial->port[i],
+						MODEM_CONTROL_REGISTER, 0x0300);
+		}
 	}
 	dbg ("mos7840_startup: all ports configured...........");
 
@@ -2602,7 +2697,6 @@
 	int i;
 	unsigned long flags;
 	struct moschip_port *mos7840_port;
-	dbg("%s", " disconnect :entering..........");
 
 	if (!serial) {
 		dbg("%s", "Invalid Handler");
@@ -2624,9 +2718,6 @@
 			usb_kill_urb(mos7840_port->control_urb);
 		}
 	}
-
-	dbg("%s", "Thank u :: ");
-
 }
 
 /****************************************************************************
@@ -2638,7 +2729,6 @@
 {
 	int i;
 	struct moschip_port *mos7840_port;
-	dbg("%s", " release :entering..........");
 
 	if (!serial) {
 		dbg("%s", "Invalid Handler");
@@ -2654,30 +2744,28 @@
 		mos7840_port = mos7840_get_port_private(serial->port[i]);
 		dbg("mos7840_port %d = %p", i, mos7840_port);
 		if (mos7840_port) {
+			if (mos7840_port->has_led) {
+				/* Turn off LED */
+				mos7840_set_led_sync(mos7840_port->port,
+						MODEM_CONTROL_REGISTER, 0x0300);
+
+				del_timer_sync(&mos7840_port->led_timer1);
+				del_timer_sync(&mos7840_port->led_timer2);
+			}
 			kfree(mos7840_port->ctrl_buf);
 			kfree(mos7840_port->dr);
 			kfree(mos7840_port);
 		}
 	}
-
-	dbg("%s", "Thank u :: ");
-
 }
 
-static struct usb_driver io_driver = {
-	.name = "mos7840",
-	.probe = usb_serial_probe,
-	.disconnect = usb_serial_disconnect,
-	.id_table = moschip_id_table_combined,
-};
-
 static struct usb_serial_driver moschip7840_4port_device = {
 	.driver = {
 		   .owner = THIS_MODULE,
 		   .name = "mos7840",
 		   },
 	.description = DRIVER_DESC,
-	.id_table = moschip_port_id_table,
+	.id_table = id_table,
 	.num_ports = 4,
 	.open = mos7840_open,
 	.close = mos7840_close,
@@ -2707,7 +2795,7 @@
 	&moschip7840_4port_device, NULL
 };
 
-module_usb_serial_driver(io_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
index 3ab6214..c5ff6c7 100644
--- a/drivers/usb/serial/moto_modem.c
+++ b/drivers/usb/serial/moto_modem.c
@@ -31,13 +31,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver moto_driver = {
-	.name =		"moto-modem",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver moto_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -51,5 +44,5 @@
 	&moto_device, NULL
 };
 
-module_usb_serial_driver(moto_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 29ab6eb..d95452c 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -30,13 +30,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver navman_driver = {
-	.name =		"navman",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static void navman_read_int_callback(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
@@ -53,12 +46,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
@@ -84,10 +77,9 @@
 {
 	int result = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (port->interrupt_in_urb) {
-		dbg("%s - adding interrupt input for treo", __func__);
+		dev_dbg(&port->dev, "%s - adding interrupt input for treo\n",
+			__func__);
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (result)
 			dev_err(&port->dev,
@@ -99,16 +91,12 @@
 
 static void navman_close(struct usb_serial_port *port)
 {
-	dbg("%s - port %d", __func__, port->number);
-
 	usb_kill_urb(port->interrupt_in_urb);
 }
 
 static int navman_write(struct tty_struct *tty, struct usb_serial_port *port,
 			const unsigned char *buf, int count)
 {
-	dbg("%s - port %d", __func__, port->number);
-
 	/*
 	 * This device can't write any data, only read from the device
 	 */
@@ -132,7 +120,7 @@
 	&navman_device, NULL
 };
 
-module_usb_serial_driver(navman_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 88dc785..6f3d705 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -54,17 +54,8 @@
 	{ USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) },
 	{ }						/* Terminating entry */
 };
-
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver omninet_driver = {
-	.name =		"omninet",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
-
 static struct usb_serial_driver zyxel_omninet_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -144,8 +135,6 @@
 	struct usb_serial_port	*wport;
 	int			result = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	wport = serial->port[1];
 	tty_port_tty_set(&wport->port, tty);
 
@@ -160,7 +149,6 @@
 
 static void omninet_close(struct usb_serial_port *port)
 {
-	dbg("%s - port %d", __func__, port->number);
 	usb_kill_urb(port->read_urb);
 }
 
@@ -178,8 +166,6 @@
 	int result;
 	int i;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (status) {
 		dbg("%s - nonzero read bulk status received: %d",
 		    __func__, status);
@@ -225,8 +211,6 @@
 
 	int			result;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (count == 0) {
 		dbg("%s - write request of 0 bytes", __func__);
 		return 0;
@@ -289,8 +273,6 @@
 	struct usb_serial_port 	*port   =  urb->context;
 	int status = urb->status;
 
-	dbg("%s - port %0x", __func__, port->number);
-
 	set_bit(0, &port->write_urbs_free);
 	if (status) {
 		dbg("%s - nonzero write bulk status received: %d",
@@ -306,8 +288,6 @@
 {
 	struct usb_serial_port *wport = serial->port[1];
 
-	dbg("%s", __func__);
-
 	usb_kill_urb(wport->write_urb);
 }
 
@@ -316,12 +296,10 @@
 {
 	struct usb_serial_port *port = serial->port[0];
 
-	dbg("%s", __func__);
-
 	kfree(usb_get_serial_port_data(port));
 }
 
-module_usb_serial_driver(omninet_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 82cc9d2..02cb1b7 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -70,8 +70,6 @@
 	int data_length;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -179,8 +177,6 @@
 	unsigned long flags;
 	int result = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->throttled = false;
 	priv->actually_throttled = false;
@@ -216,8 +212,6 @@
 {
 	struct opticon_private *priv = usb_get_serial_data(port->serial);
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/* shutdown our urbs */
 	usb_kill_urb(priv->bulk_read_urb);
 }
@@ -256,8 +250,6 @@
 	int status;
 	struct usb_ctrlrequest *dr;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
 		spin_unlock_irqrestore(&priv->lock, flags);
@@ -338,8 +330,6 @@
 	struct opticon_private *priv = usb_get_serial_data(port->serial);
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/*
 	 * We really can take almost anything the user throws at us
 	 * but let's pick a nice big number to tell the tty
@@ -362,7 +352,6 @@
 	struct opticon_private *priv = usb_get_serial_data(port->serial);
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->throttled = true;
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -376,8 +365,6 @@
 	unsigned long flags;
 	int result, was_throttled;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->throttled = false;
 	was_throttled = priv->actually_throttled;
@@ -400,10 +387,6 @@
 	unsigned long flags;
 	int result = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-	if (!usb_get_intfdata(port->serial->interface))
-		return -ENODEV;
-
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->rts)
 		result |= TIOCM_RTS;
@@ -419,13 +402,13 @@
 			   unsigned int set, unsigned int clear)
 {
 	struct usb_serial_port *port = tty->driver_data;
+	struct usb_serial *serial = port->serial;
 	struct opticon_private *priv = usb_get_serial_data(port->serial);
 	unsigned long flags;
 	bool rts;
 	bool changed = false;
+	int ret;
 
-	if (!usb_get_intfdata(port->serial->interface))
-		return -ENODEV;
 	/* We only support RTS so we only handle that */
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -441,7 +424,14 @@
 		return 0;
 
 	/* Send the new RTS state to the connected device */
-	return send_control_msg(port, CONTROL_RTS, !rts);
+	mutex_lock(&serial->disc_mutex);
+	if (!serial->disconnected)
+		ret = send_control_msg(port, CONTROL_RTS, !rts);
+	else
+		ret = -ENODEV;
+	mutex_unlock(&serial->disc_mutex);
+
+	return ret;
 }
 
 static int get_serial_info(struct opticon_private *priv,
@@ -555,8 +545,6 @@
 {
 	struct opticon_private *priv = usb_get_serial_data(serial);
 
-	dbg("%s", __func__);
-
 	usb_kill_urb(priv->bulk_read_urb);
 	usb_free_urb(priv->bulk_read_urb);
 }
@@ -565,24 +553,20 @@
 {
 	struct opticon_private *priv = usb_get_serial_data(serial);
 
-	dbg("%s", __func__);
-
 	kfree(priv->bulk_in_buffer);
 	kfree(priv);
 }
 
-static int opticon_suspend(struct usb_interface *intf, pm_message_t message)
+static int opticon_suspend(struct usb_serial *serial, pm_message_t message)
 {
-	struct usb_serial *serial = usb_get_intfdata(intf);
 	struct opticon_private *priv = usb_get_serial_data(serial);
 
 	usb_kill_urb(priv->bulk_read_urb);
 	return 0;
 }
 
-static int opticon_resume(struct usb_interface *intf)
+static int opticon_resume(struct usb_serial *serial)
 {
-	struct usb_serial *serial = usb_get_intfdata(intf);
 	struct opticon_private *priv = usb_get_serial_data(serial);
 	struct usb_serial_port *port = serial->port[0];
 	int result;
@@ -597,15 +581,6 @@
 	return result;
 }
 
-static struct usb_driver opticon_driver = {
-	.name =		"opticon",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.suspend =	opticon_suspend,
-	.resume =	opticon_resume,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver opticon_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -625,13 +600,15 @@
 	.ioctl =		opticon_ioctl,
 	.tiocmget =		opticon_tiocmget,
 	.tiocmset =		opticon_tiocmset,
+	.suspend = 		opticon_suspend,
+	.resume =		opticon_resume,
 };
 
 static struct usb_serial_driver * const serial_drivers[] = {
 	&opticon_device, NULL
 };
 
-module_usb_serial_driver(opticon_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index f4465cc..1aae902 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1220,18 +1220,6 @@
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
 
-static struct usb_driver option_driver = {
-	.name       = "option",
-	.probe      = usb_serial_probe,
-	.disconnect = usb_serial_disconnect,
-#ifdef CONFIG_PM
-	.suspend    = usb_serial_suspend,
-	.resume     = usb_serial_resume,
-	.supports_autosuspend =	1,
-#endif
-	.id_table   = option_ids,
-};
-
 /* The card has three separate interfaces, which the serial driver
  * recognizes separately, thus num_port=1.
  */
@@ -1300,7 +1288,7 @@
 	unsigned long tx_start_time[N_OUT_URB];
 };
 
-module_usb_serial_driver(option_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, option_ids);
 
 static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
 			   const struct option_blacklist_info *blacklist)
@@ -1375,7 +1363,6 @@
 	struct usb_serial_port *port =  urb->context;
 	struct option_port_private *portdata = usb_get_serial_port_data(port);
 
-	dbg("%s", __func__);
 	dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
 
 	if (status == 0) {
@@ -1413,7 +1400,7 @@
 				req_pkt->bRequestType, req_pkt->bRequest);
 		}
 	} else
-		err("%s: error %d", __func__, status);
+		dev_err(&port->dev, "%s: error %d\n", __func__, status);
 
 	/* Resubmit urb so we continue receiving IRQ data */
 	if (status != -ESHUTDOWN && status != -ENOENT) {
@@ -1437,7 +1424,6 @@
 	struct option_port_private *portdata;
 	int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
 	int val = 0;
-	dbg("%s", __func__);
 
 	if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
 			(struct option_blacklist_info *) intfdata->private)) {
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 5fdc33c..5976b65 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -66,13 +66,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver oti6858_driver = {
-	.name =		"oti6858",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static bool debug;
 
 /* requests */
@@ -211,8 +204,6 @@
 	unsigned long flags;
 	int result;
 
-	dbg("%s(port = %d)", __func__, port->number);
-
 	new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL);
 	if (new_setup == NULL) {
 		dev_err(&port->dev, "%s(): out of memory!\n", __func__);
@@ -282,8 +273,6 @@
 	unsigned long flags;
 	u8 *allow;
 
-	dbg("%s(port = %d)", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->flags.write_urb_in_use) {
 		spin_unlock_irqrestore(&priv->lock, flags);
@@ -379,8 +368,6 @@
 static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
 			const unsigned char *buf, int count)
 {
-	dbg("%s(port = %d, count = %d)", __func__, port->number, count);
-
 	if (!count)
 		return count;
 
@@ -395,8 +382,6 @@
 	int room = 0;
 	unsigned long flags;
 
-	dbg("%s(port = %d)", __func__, port->number);
-
 	spin_lock_irqsave(&port->lock, flags);
 	room = kfifo_avail(&port->write_fifo);
 	spin_unlock_irqrestore(&port->lock, flags);
@@ -410,8 +395,6 @@
 	int chars = 0;
 	unsigned long flags;
 
-	dbg("%s(port = %d)", __func__, port->number);
-
 	spin_lock_irqsave(&port->lock, flags);
 	chars = kfifo_len(&port->write_fifo);
 	spin_unlock_irqrestore(&port->lock, flags);
@@ -437,8 +420,6 @@
 	__le16 divisor;
 	int br;
 
-	dbg("%s(port = %d)", __func__, port->number);
-
 	if (!tty) {
 		dbg("%s(): no tty structures", __func__);
 		return;
@@ -545,8 +526,6 @@
 	unsigned long flags;
 	int result;
 
-	dbg("%s(port = %d)", __func__, port->number);
-
 	usb_clear_halt(serial->dev, port->write_urb->pipe);
 	usb_clear_halt(serial->dev, port->read_urb->pipe);
 
@@ -602,8 +581,6 @@
 	struct oti6858_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 
-	dbg("%s(port = %d)", __func__, port->number);
-
 	spin_lock_irqsave(&port->lock, flags);
 	/* clear out any remaining data in the buffer */
 	kfifo_reset_out(&port->write_fifo);
@@ -633,9 +610,6 @@
 	dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)",
 				__func__, port->number, set, clear);
 
-	if (!usb_get_intfdata(port->serial->interface))
-		return -ENODEV;
-
 	/* FIXME: check if this is correct (active high/low) */
 	spin_lock_irqsave(&priv->lock, flags);
 	control = priv->pending_setup.control;
@@ -663,11 +637,6 @@
 	unsigned pin_state;
 	unsigned result = 0;
 
-	dbg("%s(port = %d)", __func__, port->number);
-
-	if (!usb_get_intfdata(port->serial->interface))
-		return -ENODEV;
-
 	spin_lock_irqsave(&priv->lock, flags);
 	pin_state = priv->status.pin_state & PIN_MASK;
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -750,8 +719,6 @@
 {
 	int i;
 
-	dbg("%s()", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i)
 		kfree(usb_get_serial_port_data(serial->port[i]));
 }
@@ -763,9 +730,6 @@
 	int transient = 0, can_recv = 0, resubmit = 1;
 	int status = urb->status;
 
-	dbg("%s(port = %d, status = %d)",
-				__func__, port->number, status);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -882,9 +846,6 @@
 	int status = urb->status;
 	int result;
 
-	dbg("%s(port = %d, status = %d)",
-				__func__, port->number, status);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->flags.read_urb_in_use = 0;
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -916,9 +877,6 @@
 	int status = urb->status;
 	int result;
 
-	dbg("%s(port = %d, status = %d)",
-				__func__, port->number, status);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -958,7 +916,7 @@
 	}
 }
 
-module_usb_serial_driver(oti6858_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION(OTI6858_DESCRIPTION);
 MODULE_AUTHOR(OTI6858_AUTHOR);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index a1a9062..13b8dd6 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -38,8 +38,6 @@
 
 static bool debug;
 
-#define PL2303_CLOSING_WAIT	(30*HZ)
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
@@ -97,16 +95,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver pl2303_driver = {
-	.name =		"pl2303",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-	.suspend =      usb_serial_suspend,
-	.resume =       usb_serial_resume,
-	.supports_autosuspend =	1,
-};
-
 #define SET_LINE_REQUEST_TYPE		0x21
 #define SET_LINE_REQUEST		0x20
 
@@ -161,8 +149,9 @@
 	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
 			value, index, buf, 1, 100);
-	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", VENDOR_READ_REQUEST_TYPE,
-			VENDOR_READ_REQUEST, value, index, res, buf[0]);
+	dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x  %d - %x\n",
+		VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
+		res, buf[0]);
 	return res;
 }
 
@@ -172,8 +161,9 @@
 	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
 			value, index, NULL, 0, 100);
-	dbg("0x%x:0x%x:0x%x:0x%x  %d", VENDOR_WRITE_REQUEST_TYPE,
-			VENDOR_WRITE_REQUEST, value, index, res);
+	dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x  %d\n",
+		VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
+		res);
 	return res;
 }
 
@@ -196,7 +186,7 @@
 		type = type_1;
 	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
 		type = type_1;
-	dbg("device type: %d", type);
+	dev_dbg(&serial->interface->dev, "device type: %d\n", type);
 
 	for (i = 0; i < serial->num_ports; ++i) {
 		priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
@@ -243,7 +233,8 @@
 	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
 				 value, 0, NULL, 0, 100);
-	dbg("%s - value = %d, retval = %d", __func__, value, retval);
+	dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__,
+		value, retval);
 	return retval;
 }
 
@@ -265,8 +256,6 @@
 	int baud_floor, baud_ceil;
 	int k;
 
-	dbg("%s -  port %d", __func__, port->number);
-
 	/* The PL2303 is reported to lose bytes if you change
 	   serial settings even to the same values as before. Thus
 	   we actually need to filter in this specific case */
@@ -287,7 +276,7 @@
 	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
 			    0, 0, buf, 7, 100);
-	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
+	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x\n", i,
 	    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
 	if (cflag & CSIZE) {
@@ -306,7 +295,7 @@
 			buf[6] = 8;
 			break;
 		}
-		dbg("%s - data bits = %d", __func__, buf[6]);
+		dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
 	}
 
 	/* For reference buf[0]:buf[3] baud rate value */
@@ -315,7 +304,7 @@
 	 *          9600 baud (at least my PL2303X always does)
 	 */
 	baud = tty_get_baud_rate(tty);
-	dbg("%s - baud requested = %d", __func__, baud);
+	dev_dbg(&port->dev, "baud requested = %d\n", baud);
 	if (baud) {
 		/* Set baudrate to nearest supported value */
 		for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
@@ -341,7 +330,7 @@
 			else if (baud > 6000000)
 				baud = 6000000;
 		}
-		dbg("%s - baud set = %d", __func__, baud);
+		dev_dbg(&port->dev, "baud set = %d\n", baud);
 		if (baud <= 115200) {
 			buf[0] = baud & 0xff;
 			buf[1] = (baud >> 8) & 0xff;
@@ -372,14 +361,14 @@
 		 */
 		if ((cflag & CSIZE) == CS5) {
 			buf[4] = 1;
-			dbg("%s - stop bits = 1.5", __func__);
+			dev_dbg(&port->dev, "stop bits = 1.5\n");
 		} else {
 			buf[4] = 2;
-			dbg("%s - stop bits = 2", __func__);
+			dev_dbg(&port->dev, "stop bits = 2\n");
 		}
 	} else {
 		buf[4] = 0;
-		dbg("%s - stop bits = 1", __func__);
+		dev_dbg(&port->dev, "stop bits = 1\n");
 	}
 
 	if (cflag & PARENB) {
@@ -391,29 +380,29 @@
 		if (cflag & PARODD) {
 			if (cflag & CMSPAR) {
 				buf[5] = 3;
-				dbg("%s - parity = mark", __func__);
+				dev_dbg(&port->dev, "parity = mark\n");
 			} else {
 				buf[5] = 1;
-				dbg("%s - parity = odd", __func__);
+				dev_dbg(&port->dev, "parity = odd\n");
 			}
 		} else {
 			if (cflag & CMSPAR) {
 				buf[5] = 4;
-				dbg("%s - parity = space", __func__);
+				dev_dbg(&port->dev, "parity = space\n");
 			} else {
 				buf[5] = 2;
-				dbg("%s - parity = even", __func__);
+				dev_dbg(&port->dev, "parity = even\n");
 			}
 		}
 	} else {
 		buf[5] = 0;
-		dbg("%s - parity = none", __func__);
+		dev_dbg(&port->dev, "parity = none\n");
 	}
 
 	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
 			    0, 0, buf, 7, 100);
-	dbg("0x21:0x20:0:0  %d", i);
+	dev_dbg(&port->dev, "0x21:0x20:0:0  %d\n", i);
 
 	/* change control lines if we are switching to or from B0 */
 	spin_lock_irqsave(&priv->lock, flags);
@@ -435,7 +424,7 @@
 	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
 			    0, 0, buf, 7, 100);
-	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
+	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x\n", i,
 	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
 	if (cflag & CRTSCTS) {
@@ -473,8 +462,6 @@
 
 static void pl2303_close(struct usb_serial_port *port)
 {
-	dbg("%s - port %d", __func__, port->number);
-
 	usb_serial_generic_close(port);
 	usb_kill_urb(port->interrupt_in_urb);
 }
@@ -486,8 +473,6 @@
 	struct pl2303_private *priv = usb_get_serial_port_data(port);
 	int result;
 
-	dbg("%s -  port %d", __func__, port->number);
-
 	if (priv->type != HX) {
 		usb_clear_halt(serial->dev, port->write_urb->pipe);
 		usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -501,7 +486,6 @@
 	if (tty)
 		pl2303_set_termios(tty, port, &tmp_termios);
 
-	dbg("%s - submitting interrupt urb", __func__);
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (result) {
 		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -523,12 +507,11 @@
 			   unsigned int set, unsigned int clear)
 {
 	struct usb_serial_port *port = tty->driver_data;
+	struct usb_serial *serial = port->serial;
 	struct pl2303_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 	u8 control;
-
-	if (!usb_get_intfdata(port->serial->interface))
-		return -ENODEV;
+	int ret;
 
 	spin_lock_irqsave(&priv->lock, flags);
 	if (set & TIOCM_RTS)
@@ -542,7 +525,14 @@
 	control = priv->line_control;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	return set_control_lines(port->serial->dev, control);
+	mutex_lock(&serial->disc_mutex);
+	if (!serial->disconnected)
+		ret = set_control_lines(serial->dev, control);
+	else
+		ret = -ENODEV;
+	mutex_unlock(&serial->disc_mutex);
+
+	return ret;
 }
 
 static int pl2303_tiocmget(struct tty_struct *tty)
@@ -554,11 +544,6 @@
 	unsigned int status;
 	unsigned int result;
 
-	dbg("%s (%d)", __func__, port->number);
-
-	if (!usb_get_intfdata(port->serial->interface))
-		return -ENODEV;
-
 	spin_lock_irqsave(&priv->lock, flags);
 	mcr = priv->line_control;
 	status = priv->line_status;
@@ -571,7 +556,7 @@
 		  | ((status & UART_RING)	? TIOCM_RI  : 0)
 		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
 
-	dbg("%s - result = %x", __func__, result);
+	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
 
 	return result;
 }
@@ -625,7 +610,8 @@
 {
 	struct serial_struct ser;
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+	dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd);
 
 	switch (cmd) {
 	case TIOCGSERIAL:
@@ -641,10 +627,10 @@
 		return 0;
 
 	case TIOCMIWAIT:
-		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
+		dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
 		return wait_modem_info(port, arg);
 	default:
-		dbg("%s not supported = 0x%04x", __func__, cmd);
+		dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
 		break;
 	}
 	return -ENOIOCTLCMD;
@@ -657,20 +643,18 @@
 	u16 state;
 	int result;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (break_state == 0)
 		state = BREAK_OFF;
 	else
 		state = BREAK_ON;
-	dbg("%s - turning break %s", __func__,
+	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
 			state == BREAK_OFF ? "off" : "on");
 
 	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
 				 0, NULL, 0, 100);
 	if (result)
-		dbg("%s - error sending break = %d", __func__, result);
+		dev_err(&port->dev, "error sending break = %d\n", result);
 }
 
 static void pl2303_release(struct usb_serial *serial)
@@ -678,8 +662,6 @@
 	int i;
 	struct pl2303_private *priv;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i) {
 		priv = usb_get_serial_port_data(serial->port[i]);
 		kfree(priv);
@@ -742,8 +724,6 @@
 	int status = urb->status;
 	int retval;
 
-	dbg("%s (%d)", __func__, port->number);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -752,12 +732,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    status);
+		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__,
-		    status);
+		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
@@ -769,7 +749,7 @@
 exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		dev_err(&urb->dev->dev,
+		dev_err(&port->dev,
 			"%s - usb_submit_urb failed with result %d\n",
 			__func__, retval);
 }
@@ -807,7 +787,7 @@
 		tty_flag = TTY_PARITY;
 	else if (line_status & UART_FRAME_ERROR)
 		tty_flag = TTY_FRAME;
-	dbg("%s - tty_flag = %d", __func__, tty_flag);
+	dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
 
 	/* overrun is special, not associated with a char */
 	if (line_status & UART_OVERRUN_ERROR)
@@ -855,7 +835,7 @@
 	&pl2303_device, NULL
 };
 
-module_usb_serial_driver(pl2303_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
index 9662456..a4edc7e 100644
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -77,13 +77,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver qcaux_driver = {
-	.name =		"qcaux",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver qcaux_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -97,5 +90,5 @@
 	&qcaux_device, NULL
 };
 
-module_usb_serial_driver(qcaux_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 0206b10..0d5fe59 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -112,32 +112,22 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver qcdriver = {
-	.name			= "qcserial",
-	.probe			= usb_serial_probe,
-	.disconnect		= usb_serial_disconnect,
-	.id_table		= id_table,
-	.suspend		= usb_serial_suspend,
-	.resume			= usb_serial_resume,
-	.supports_autosuspend	= true,
-};
-
 static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 {
 	struct usb_wwan_intf_private *data;
 	struct usb_host_interface *intf = serial->interface->cur_altsetting;
+	struct device *dev = &serial->dev->dev;
 	int retval = -ENODEV;
 	__u8 nintf;
 	__u8 ifnum;
 	bool is_gobi1k = id->driver_info ? true : false;
 
-	dbg("%s", __func__);
-	dbg("Is Gobi 1000 = %d", is_gobi1k);
+	dev_dbg(dev, "Is Gobi 1000 = %d\n", is_gobi1k);
 
 	nintf = serial->dev->actconfig->desc.bNumInterfaces;
-	dbg("Num Interfaces = %d", nintf);
+	dev_dbg(dev, "Num Interfaces = %d\n", nintf);
 	ifnum = intf->desc.bInterfaceNumber;
-	dbg("This Interface = %d", ifnum);
+	dev_dbg(dev, "This Interface = %d\n", ifnum);
 
 	data = kzalloc(sizeof(struct usb_wwan_intf_private),
 					 GFP_KERNEL);
@@ -158,7 +148,7 @@
 		if (intf->desc.bNumEndpoints == 2 &&
 		    usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
 		    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
-			dbg("QDL port found");
+			dev_dbg(dev, "QDL port found\n");
 
 			if (serial->interface->num_altsetting == 1) {
 				retval = 0; /* Success */
@@ -167,7 +157,7 @@
 
 			retval = usb_set_interface(serial->dev, ifnum, 1);
 			if (retval < 0) {
-				dev_err(&serial->dev->dev,
+				dev_err(dev,
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
@@ -196,20 +186,20 @@
 		 */
 
 		if (ifnum == 1 && !is_gobi1k) {
-			dbg("Gobi 2K+ DM/DIAG interface found");
+			dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n");
 			retval = usb_set_interface(serial->dev, ifnum, 0);
 			if (retval < 0) {
-				dev_err(&serial->dev->dev,
+				dev_err(dev,
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
 				kfree(data);
 			}
 		} else if (ifnum == 2) {
-			dbg("Modem port found");
+			dev_dbg(dev, "Modem port found\n");
 			retval = usb_set_interface(serial->dev, ifnum, 0);
 			if (retval < 0) {
-				dev_err(&serial->dev->dev,
+				dev_err(dev,
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
@@ -221,10 +211,10 @@
 			 * # echo "\$GPS_START" > /dev/ttyUSBx
 			 * # echo "\$GPS_STOP"  > /dev/ttyUSBx
 			 */
-			dbg("Gobi 2K+ NMEA GPS interface found");
+			dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n");
 			retval = usb_set_interface(serial->dev, ifnum, 0);
 			if (retval < 0) {
-				dev_err(&serial->dev->dev,
+				dev_err(dev,
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
@@ -234,8 +224,7 @@
 		break;
 
 	default:
-		dev_err(&serial->dev->dev,
-			"unknown number of interfaces: %d\n", nintf);
+		dev_err(dev, "unknown number of interfaces: %d\n", nintf);
 		kfree(data);
 		retval = -ENODEV;
 	}
@@ -250,8 +239,6 @@
 {
 	struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
 
-	dbg("%s", __func__);
-
 	/* Call usb_wwan release & free the private data allocated in qcprobe */
 	usb_wwan_release(serial);
 	usb_set_serial_data(serial, NULL);
@@ -285,7 +272,7 @@
 	&qcdevice, NULL
 };
 
-module_usb_serial_driver(qcdriver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
new file mode 100644
index 0000000..8dd88eb
--- /dev/null
+++ b/drivers/usb/serial/quatech2.c
@@ -0,0 +1,1155 @@
+/*
+ * usb-serial driver for Quatech USB 2 devices
+ *
+ * Copyright (C) 2012 Bill Pemberton (wfp5p@virginia.edu)
+ *
+ * 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.
+ *
+ *
+ *  These devices all have only 1 bulk in and 1 bulk out that is shared
+ *  for all serial ports.
+ *
+ */
+
+#include <asm/unaligned.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/uaccess.h>
+
+static bool debug;
+
+/* default urb timeout for usb operations */
+#define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT
+
+#define QT_OPEN_CLOSE_CHANNEL       0xca
+#define QT_SET_GET_DEVICE           0xc2
+#define QT_SET_GET_REGISTER         0xc0
+#define QT_GET_SET_PREBUF_TRIG_LVL  0xcc
+#define QT_SET_ATF                  0xcd
+#define QT_TRANSFER_IN              0xc0
+#define QT_HW_FLOW_CONTROL_MASK     0xc5
+#define QT_SW_FLOW_CONTROL_MASK     0xc6
+#define QT2_BREAK_CONTROL	    0xc8
+#define QT2_GET_SET_UART            0xc1
+#define QT2_FLUSH_DEVICE	    0xc4
+#define QT2_GET_SET_QMCR            0xe1
+#define QT2_QMCR_RS232              0x40
+#define QT2_QMCR_RS422              0x10
+
+#define  SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS)
+
+#define  SERIAL_EVEN_PARITY         (UART_LCR_PARITY | UART_LCR_EPAR)
+
+/* status bytes for the device */
+#define QT2_CONTROL_BYTE    0x1b
+#define QT2_LINE_STATUS     0x00  /* following 1 byte is line status */
+#define QT2_MODEM_STATUS    0x01  /* following 1 byte is modem status */
+#define QT2_XMIT_HOLD       0x02  /* following 2 bytes are ?? */
+#define QT2_CHANGE_PORT     0x03  /* following 1 byte is port to change to */
+#define QT2_REC_FLUSH       0x04  /* no following info */
+#define QT2_XMIT_FLUSH      0x05  /* no following info */
+#define QT2_CONTROL_ESCAPE  0xff  /* pass through previous 2 control bytes */
+
+#define  MAX_BAUD_RATE              921600
+#define  DEFAULT_BAUD_RATE          9600
+
+#define QT2_WRITE_BUFFER_SIZE   512  /* size of write buffer */
+#define QT2_WRITE_CONTROL_SIZE  5    /* control bytes used for a write */
+
+/* Version Information */
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver"
+
+#define	USB_VENDOR_ID_QUATECH	0x061d
+#define QUATECH_SSU2_100	0xC120	/* RS232 single port */
+#define QUATECH_DSU2_100	0xC140	/* RS232 dual port */
+#define QUATECH_DSU2_400	0xC150	/* RS232/422/485 dual port */
+#define QUATECH_QSU2_100	0xC160	/* RS232 four port */
+#define QUATECH_QSU2_400	0xC170	/* RS232/422/485 four port */
+#define QUATECH_ESU2_100	0xC1A0	/* RS232 eight port */
+#define QUATECH_ESU2_400	0xC180	/* RS232/422/485 eight port */
+
+struct qt2_device_detail {
+	int product_id;
+	int num_ports;
+};
+
+#define QT_DETAILS(prod, ports)	\
+	.product_id = (prod),   \
+	.num_ports = (ports)
+
+static const struct qt2_device_detail qt2_device_details[] = {
+	{QT_DETAILS(QUATECH_SSU2_100, 1)},
+	{QT_DETAILS(QUATECH_DSU2_400, 2)},
+	{QT_DETAILS(QUATECH_DSU2_100, 2)},
+	{QT_DETAILS(QUATECH_QSU2_400, 4)},
+	{QT_DETAILS(QUATECH_QSU2_100, 4)},
+	{QT_DETAILS(QUATECH_ESU2_400, 8)},
+	{QT_DETAILS(QUATECH_ESU2_100, 8)},
+	{QT_DETAILS(0, 0)}	/* Terminating entry */
+};
+
+static const struct usb_device_id id_table[] = {
+	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
+	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
+	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
+	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)},
+	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)},
+	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)},
+	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)},
+	{}			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct qt2_serial_private {
+	unsigned char current_port;  /* current port for incoming data */
+
+	struct urb	*read_urb;   /* shared among all ports */
+	char		read_buffer[512];
+};
+
+struct qt2_port_private {
+	bool is_open;
+	u8   device_port;
+
+	spinlock_t urb_lock;
+	bool       urb_in_use;
+	struct urb *write_urb;
+	char       write_buffer[QT2_WRITE_BUFFER_SIZE];
+
+	spinlock_t  lock;
+	u8          shadowLSR;
+	u8          shadowMSR;
+
+	wait_queue_head_t   delta_msr_wait; /* Used for TIOCMIWAIT */
+	struct async_icount icount;
+
+	struct usb_serial_port *port;
+};
+
+static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch);
+static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch);
+static void qt2_write_bulk_callback(struct urb *urb);
+static void qt2_read_bulk_callback(struct urb *urb);
+
+static void qt2_release(struct usb_serial *serial)
+{
+	int i;
+
+	kfree(usb_get_serial_data(serial));
+
+	for (i = 0; i < serial->num_ports; i++)
+		kfree(usb_get_serial_port_data(serial->port[i]));
+}
+
+static inline int calc_baud_divisor(int baudrate)
+{
+	int divisor, rem;
+
+	divisor = MAX_BAUD_RATE / baudrate;
+	rem = MAX_BAUD_RATE % baudrate;
+	/* Round to nearest divisor */
+	if (((rem * 2) >= baudrate) && (baudrate != 110))
+		divisor++;
+
+	return divisor;
+}
+
+static inline int qt2_set_port_config(struct usb_device *dev,
+				      unsigned char port_number,
+				      u16 baudrate, u16 lcr)
+{
+	int divisor = calc_baud_divisor(baudrate);
+	u16 index = ((u16) (lcr << 8) | (u16) (port_number));
+
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			       QT2_GET_SET_UART, 0x40,
+			       divisor, index, NULL, 0, QT2_USB_TIMEOUT);
+}
+
+static inline int qt2_control_msg(struct usb_device *dev,
+				  u8 request, u16 data, u16 index)
+{
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			       request, 0x40, data, index,
+			       NULL, 0, QT2_USB_TIMEOUT);
+}
+
+static inline int qt2_setdevice(struct usb_device *dev, u8 *data)
+{
+	u16 x = ((u16) (data[1] << 8) | (u16) (data[0]));
+
+	return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0);
+}
+
+
+static inline int qt2_getdevice(struct usb_device *dev, u8 *data)
+{
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			       QT_SET_GET_DEVICE, 0xc0, 0, 0,
+			       data, 3, QT2_USB_TIMEOUT);
+}
+
+static inline int qt2_getregister(struct usb_device *dev,
+				  u8 uart,
+				  u8 reg,
+				  u8 *data)
+{
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			       QT_SET_GET_REGISTER, 0xc0, reg,
+			       uart, data, sizeof(*data), QT2_USB_TIMEOUT);
+
+}
+
+static inline int qt2_setregister(struct usb_device *dev,
+				  u8 uart, u8 reg, u16 data)
+{
+	u16 value = (data << 8) | reg;
+
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			       QT_SET_GET_REGISTER, 0x40, value, uart,
+			       NULL, 0, QT2_USB_TIMEOUT);
+}
+
+static inline int update_mctrl(struct qt2_port_private *port_priv,
+			       unsigned int set, unsigned int clear)
+{
+	struct usb_serial_port *port = port_priv->port;
+	struct usb_device *dev = port->serial->dev;
+	unsigned urb_value;
+	int status;
+
+	if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
+		dev_dbg(&port->dev,
+			"update_mctrl - DTR|RTS not being set|cleared\n");
+		return 0;	/* no change */
+	}
+
+	clear &= ~set;	/* 'set' takes precedence over 'clear' */
+	urb_value = 0;
+	if (set & TIOCM_DTR)
+		urb_value |= UART_MCR_DTR;
+	if (set & TIOCM_RTS)
+		urb_value |= UART_MCR_RTS;
+
+	status = qt2_setregister(dev, port_priv->device_port, UART_MCR,
+				 urb_value);
+	if (status < 0)
+		dev_err(&port->dev,
+			"update_mctrl - Error from MODEM_CTRL urb: %i\n",
+			status);
+	return status;
+}
+
+static int qt2_calc_num_ports(struct usb_serial *serial)
+{
+	struct qt2_device_detail d;
+	int i;
+
+	for (i = 0; d = qt2_device_details[i], d.product_id != 0; i++) {
+		if (d.product_id == le16_to_cpu(serial->dev->descriptor.idProduct))
+			return d.num_ports;
+	}
+
+	/* we didn't recognize the device */
+	dev_err(&serial->dev->dev,
+		 "don't know the number of ports, assuming 1\n");
+
+	return 1;
+}
+
+static void qt2_set_termios(struct tty_struct *tty,
+			    struct usb_serial_port *port,
+			    struct ktermios *old_termios)
+{
+	struct usb_device *dev = port->serial->dev;
+	struct qt2_port_private *port_priv;
+	struct ktermios *termios = tty->termios;
+	u16 baud;
+	unsigned int cflag = termios->c_cflag;
+	u16 new_lcr = 0;
+	int status;
+
+	port_priv = usb_get_serial_port_data(port);
+
+	if (cflag & PARENB) {
+		if (cflag & PARODD)
+			new_lcr |= UART_LCR_PARITY;
+		else
+			new_lcr |= SERIAL_EVEN_PARITY;
+	}
+
+	switch (cflag & CSIZE) {
+	case CS5:
+		new_lcr |= UART_LCR_WLEN5;
+		break;
+	case CS6:
+		new_lcr |= UART_LCR_WLEN6;
+		break;
+	case CS7:
+		new_lcr |= UART_LCR_WLEN7;
+		break;
+	default:
+	case CS8:
+		new_lcr |= UART_LCR_WLEN8;
+		break;
+	}
+
+	baud = tty_get_baud_rate(tty);
+	if (!baud)
+		baud = 9600;
+
+	status = qt2_set_port_config(dev, port_priv->device_port, baud,
+				     new_lcr);
+	if (status < 0)
+		dev_err(&port->dev, "%s - qt2_set_port_config failed: %i\n",
+			__func__, status);
+
+	if (cflag & CRTSCTS)
+		status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
+					 SERIAL_CRTSCTS,
+					 port_priv->device_port);
+	else
+		status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
+					 0, port_priv->device_port);
+	if (status < 0)
+		dev_err(&port->dev, "%s - set HW flow control failed: %i\n",
+			__func__, status);
+
+	if (I_IXOFF(tty) || I_IXON(tty)) {
+		u16 x = ((u16) (START_CHAR(tty) << 8) | (u16) (STOP_CHAR(tty)));
+
+		status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
+					 x, port_priv->device_port);
+	} else
+		status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
+					 0, port_priv->device_port);
+
+	if (status < 0)
+		dev_err(&port->dev, "%s - set SW flow control failed: %i\n",
+			__func__, status);
+
+}
+
+static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+	struct usb_serial *serial;
+	struct qt2_serial_private *serial_priv;
+	struct qt2_port_private *port_priv;
+	u8 *data;
+	u16 device_port;
+	int status;
+	unsigned long flags;
+
+	device_port = (u16) (port->number - port->serial->minor);
+
+	serial = port->serial;
+
+	port_priv = usb_get_serial_port_data(port);
+	serial_priv = usb_get_serial_data(serial);
+
+	/* set the port to RS232 mode */
+	status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR,
+				 QT2_QMCR_RS232, device_port);
+	if (status < 0) {
+		dev_err(&port->dev,
+			"%s failed to set RS232 mode for port %i error %i\n",
+			__func__, device_port, status);
+		return status;
+	}
+
+	data = kzalloc(2, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* open the port */
+	status = usb_control_msg(serial->dev,
+				 usb_rcvctrlpipe(serial->dev, 0),
+				 QT_OPEN_CLOSE_CHANNEL,
+				 0xc0, 0,
+				 device_port, data, 2, QT2_USB_TIMEOUT);
+
+	if (status < 0) {
+		dev_err(&port->dev, "%s - open port failed %i", __func__,
+			status);
+		kfree(data);
+		return status;
+	}
+
+	spin_lock_irqsave(&port_priv->lock, flags);
+	port_priv->shadowLSR = data[0];
+	port_priv->shadowMSR = data[1];
+	spin_unlock_irqrestore(&port_priv->lock, flags);
+
+	kfree(data);
+
+	/* set to default speed and 8bit word size */
+	status = qt2_set_port_config(serial->dev, device_port,
+				     DEFAULT_BAUD_RATE, UART_LCR_WLEN8);
+	if (status < 0) {
+		dev_err(&port->dev,
+			"%s - initial setup failed for port %i (%i)\n",
+			__func__, port->number, device_port);
+		return status;
+	}
+
+	port_priv->is_open = true;
+	port_priv->device_port = (u8) device_port;
+
+	if (tty)
+		qt2_set_termios(tty, port, tty->termios);
+
+	return 0;
+
+}
+
+static void qt2_close(struct usb_serial_port *port)
+{
+	struct usb_serial *serial;
+	struct qt2_serial_private *serial_priv;
+	struct qt2_port_private *port_priv;
+	unsigned long flags;
+	int i;
+
+	serial = port->serial;
+	serial_priv = usb_get_serial_data(serial);
+	port_priv = usb_get_serial_port_data(port);
+
+	port_priv->is_open = false;
+
+	spin_lock_irqsave(&port_priv->urb_lock, flags);
+	if (port_priv->write_urb->status == -EINPROGRESS)
+		usb_kill_urb(port_priv->write_urb);
+	port_priv->urb_in_use = false;
+	spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+
+	/* flush the port transmit buffer */
+	i = usb_control_msg(serial->dev,
+			    usb_rcvctrlpipe(serial->dev, 0),
+			    QT2_FLUSH_DEVICE, 0x40, 1,
+			    port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
+
+	if (i < 0)
+		dev_err(&port->dev, "%s - transmit buffer flush failed: %i\n",
+			__func__, i);
+
+	/* flush the port receive buffer */
+	i = usb_control_msg(serial->dev,
+			    usb_rcvctrlpipe(serial->dev, 0),
+			    QT2_FLUSH_DEVICE, 0x40, 0,
+			    port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
+
+	if (i < 0)
+		dev_err(&port->dev, "%s - receive buffer flush failed: %i\n",
+			__func__, i);
+
+	/* close the port */
+	i = usb_control_msg(serial->dev,
+			    usb_sndctrlpipe(serial->dev, 0),
+			    QT_OPEN_CLOSE_CHANNEL,
+			    0x40, 0,
+			    port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
+
+	if (i < 0)
+		dev_err(&port->dev, "%s - close port failed %i\n",
+			__func__, i);
+
+}
+
+static void qt2_disconnect(struct usb_serial *serial)
+{
+	struct qt2_serial_private *serial_priv = usb_get_serial_data(serial);
+	struct qt2_port_private *port_priv;
+	int i;
+
+	if (serial_priv->read_urb->status == -EINPROGRESS)
+		usb_kill_urb(serial_priv->read_urb);
+
+	usb_free_urb(serial_priv->read_urb);
+
+	for (i = 0; i < serial->num_ports; i++) {
+		port_priv = usb_get_serial_port_data(serial->port[i]);
+
+		if (port_priv->write_urb->status == -EINPROGRESS)
+			usb_kill_urb(port_priv->write_urb);
+		usb_free_urb(port_priv->write_urb);
+	}
+}
+
+static int get_serial_info(struct usb_serial_port *port,
+			   struct serial_struct __user *retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.line		= port->serial->minor;
+	tmp.port		= 0;
+	tmp.irq			= 0;
+	tmp.flags		= ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+	tmp.xmit_fifo_size	= port->bulk_out_size;
+	tmp.baud_base		= 9600;
+	tmp.close_delay		= 5*HZ;
+	tmp.closing_wait	= 30*HZ;
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+{
+	struct qt2_port_private *priv = usb_get_serial_port_data(port);
+	struct async_icount prev, cur;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	prev = priv->icount;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	while (1) {
+		wait_event_interruptible(priv->delta_msr_wait,
+					 ((priv->icount.rng != prev.rng) ||
+					  (priv->icount.dsr != prev.dsr) ||
+					  (priv->icount.dcd != prev.dcd) ||
+					  (priv->icount.cts != prev.cts)));
+
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+
+		spin_lock_irqsave(&priv->lock, flags);
+		cur = priv->icount;
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		if ((prev.rng == cur.rng) &&
+		    (prev.dsr == cur.dsr) &&
+		    (prev.dcd == cur.dcd) &&
+		    (prev.cts == cur.cts))
+			return -EIO;
+
+		if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
+		    (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
+		    (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
+		    (arg & TIOCM_CTS && (prev.cts != cur.cts)))
+			return 0;
+	}
+	return 0;
+}
+
+static int qt2_get_icount(struct tty_struct *tty,
+			  struct serial_icounter_struct *icount)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct qt2_port_private *priv = usb_get_serial_port_data(port);
+	struct async_icount cnow = priv->icount;
+
+	icount->cts = cnow.cts;
+	icount->dsr = cnow.dsr;
+	icount->rng = cnow.rng;
+	icount->dcd = cnow.dcd;
+	icount->rx = cnow.rx;
+	icount->tx = cnow.tx;
+	icount->frame = cnow.frame;
+	icount->overrun = cnow.overrun;
+	icount->parity = cnow.parity;
+	icount->brk = cnow.brk;
+	icount->buf_overrun = cnow.buf_overrun;
+
+	return 0;
+}
+
+static int qt2_ioctl(struct tty_struct *tty,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial_port *port = tty->driver_data;
+
+	switch (cmd) {
+	case TIOCGSERIAL:
+		return get_serial_info(port,
+				       (struct serial_struct __user *)arg);
+
+	case TIOCMIWAIT:
+		return wait_modem_info(port, arg);
+
+	default:
+		break;
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch)
+{
+	switch (*ch) {
+	case QT2_LINE_STATUS:
+		qt2_update_lsr(port, ch + 1);
+		break;
+	case QT2_MODEM_STATUS:
+		qt2_update_msr(port, ch + 1);
+		break;
+	}
+}
+
+/* not needed, kept to document functionality */
+static void qt2_process_xmit_empty(struct usb_serial_port *port,
+				   unsigned char *ch)
+{
+	int bytes_written;
+
+	bytes_written = (int)(*ch) + (int)(*(ch + 1) << 4);
+}
+
+/* not needed, kept to document functionality */
+static void qt2_process_flush(struct usb_serial_port *port, unsigned char *ch)
+{
+	return;
+}
+
+void qt2_process_read_urb(struct urb *urb)
+{
+	struct usb_serial *serial;
+	struct qt2_serial_private *serial_priv;
+	struct usb_serial_port *port;
+	struct qt2_port_private *port_priv;
+	struct tty_struct *tty;
+	bool escapeflag;
+	unsigned char *ch;
+	int i;
+	unsigned char newport;
+	int len = urb->actual_length;
+
+	if (!len)
+		return;
+
+	ch = urb->transfer_buffer;
+	tty = NULL;
+	serial = urb->context;
+	serial_priv = usb_get_serial_data(serial);
+	port = serial->port[serial_priv->current_port];
+	port_priv = usb_get_serial_port_data(port);
+
+	if (port_priv->is_open)
+		tty = tty_port_tty_get(&port->port);
+
+	for (i = 0; i < urb->actual_length; i++) {
+		ch = (unsigned char *)urb->transfer_buffer + i;
+		if ((i <= (len - 3)) &&
+		    (*ch == QT2_CONTROL_BYTE) &&
+		    (*(ch + 1) == QT2_CONTROL_BYTE)) {
+			escapeflag = false;
+			switch (*(ch + 2)) {
+			case QT2_LINE_STATUS:
+			case QT2_MODEM_STATUS:
+				if (i > (len - 4)) {
+					dev_warn(&port->dev,
+						 "%s - status message too short\n",
+						__func__);
+					break;
+				}
+				qt2_process_status(port, ch + 2);
+				i += 3;
+				escapeflag = true;
+				break;
+			case QT2_XMIT_HOLD:
+				if (i > (len - 5)) {
+					dev_warn(&port->dev,
+						 "%s - xmit_empty message too short\n",
+						 __func__);
+					break;
+				}
+				qt2_process_xmit_empty(port, ch + 3);
+				i += 4;
+				escapeflag = true;
+				break;
+			case QT2_CHANGE_PORT:
+				if (i > (len - 4)) {
+					dev_warn(&port->dev,
+						 "%s - change_port message too short\n",
+						 __func__);
+					break;
+				}
+				if (tty) {
+					tty_flip_buffer_push(tty);
+					tty_kref_put(tty);
+				}
+
+				newport = *(ch + 3);
+
+				if (newport > serial->num_ports) {
+					dev_err(&port->dev,
+						"%s - port change to invalid port: %i\n",
+						__func__, newport);
+					break;
+				}
+
+				serial_priv->current_port = newport;
+				port = serial->port[serial_priv->current_port];
+				port_priv = usb_get_serial_port_data(port);
+				if (port_priv->is_open)
+					tty = tty_port_tty_get(&port->port);
+				else
+					tty = NULL;
+				i += 3;
+				escapeflag = true;
+				break;
+			case QT2_REC_FLUSH:
+			case QT2_XMIT_FLUSH:
+				qt2_process_flush(port, ch + 2);
+				i += 2;
+				escapeflag = true;
+				break;
+			case QT2_CONTROL_ESCAPE:
+				tty_buffer_request_room(tty, 2);
+				tty_insert_flip_string(tty, ch, 2);
+				i += 2;
+				escapeflag = true;
+				break;
+			default:
+				dev_warn(&port->dev,
+					 "%s - unsupported command %i\n",
+					 __func__, *(ch + 2));
+				break;
+			}
+			if (escapeflag)
+				continue;
+		}
+
+		if (tty) {
+			tty_buffer_request_room(tty, 1);
+			tty_insert_flip_string(tty, ch, 1);
+		}
+	}
+
+	if (tty) {
+		tty_flip_buffer_push(tty);
+		tty_kref_put(tty);
+	}
+}
+
+static void qt2_write_bulk_callback(struct urb *urb)
+{
+	struct usb_serial_port *port;
+	struct qt2_port_private *port_priv;
+
+	port = urb->context;
+	port_priv = usb_get_serial_port_data(port);
+
+	spin_lock(&port_priv->urb_lock);
+
+	port_priv->urb_in_use = false;
+	usb_serial_port_softint(port);
+
+	spin_unlock(&port_priv->urb_lock);
+
+}
+
+static void qt2_read_bulk_callback(struct urb *urb)
+{
+	struct usb_serial *serial = urb->context;
+	int status;
+
+	if (urb->status) {
+		dev_warn(&serial->dev->dev,
+			 "%s - non-zero urb status: %i\n", __func__,
+			 urb->status);
+		return;
+	}
+
+	qt2_process_read_urb(urb);
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status != 0)
+		dev_err(&serial->dev->dev,
+			"%s - resubmit read urb failed: %i\n",
+			__func__, status);
+}
+
+static int qt2_setup_urbs(struct usb_serial *serial)
+{
+	struct usb_serial_port *port;
+	struct usb_serial_port *port0;
+	struct qt2_serial_private *serial_priv;
+	struct qt2_port_private *port_priv;
+	int pcount, status;
+
+	port0 = serial->port[0];
+
+	serial_priv = usb_get_serial_data(serial);
+	serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!serial_priv->read_urb) {
+		dev_err(&serial->dev->dev, "No free urbs available\n");
+		return -ENOMEM;
+	}
+
+	usb_fill_bulk_urb(serial_priv->read_urb, serial->dev,
+			  usb_rcvbulkpipe(serial->dev,
+					  port0->bulk_in_endpointAddress),
+			  serial_priv->read_buffer,
+			  sizeof(serial_priv->read_buffer),
+			  qt2_read_bulk_callback, serial);
+
+	/* setup write_urb for each port */
+	for (pcount = 0; pcount < serial->num_ports; pcount++) {
+
+		port = serial->port[pcount];
+		port_priv = usb_get_serial_port_data(port);
+
+		port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!port_priv->write_urb) {
+			dev_err(&serial->dev->dev,
+				"failed to alloc write_urb for port %i\n",
+				pcount);
+			return -ENOMEM;
+		}
+
+		usb_fill_bulk_urb(port_priv->write_urb,
+				  serial->dev,
+				  usb_sndbulkpipe(serial->dev,
+						  port0->
+						  bulk_out_endpointAddress),
+				  port_priv->write_buffer,
+				  sizeof(port_priv->write_buffer),
+				  qt2_write_bulk_callback, port);
+	}
+
+	status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL);
+	if (status != 0) {
+		dev_err(&serial->dev->dev,
+			"%s - submit read urb failed %i\n", __func__, status);
+		return status;
+	}
+
+	return 0;
+
+}
+
+static int qt2_attach(struct usb_serial *serial)
+{
+	struct qt2_serial_private *serial_priv;
+	struct qt2_port_private *port_priv;
+	int status, pcount;
+
+	/* power on unit */
+	status = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+				 0xc2, 0x40, 0x8000, 0, NULL, 0,
+				 QT2_USB_TIMEOUT);
+	if (status < 0) {
+		dev_err(&serial->dev->dev,
+			"%s - failed to power on unit: %i\n", __func__, status);
+		return status;
+	}
+
+	serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
+	if (!serial_priv) {
+		dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	usb_set_serial_data(serial, serial_priv);
+
+	for (pcount = 0; pcount < serial->num_ports; pcount++) {
+		port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
+		if (!port_priv) {
+			dev_err(&serial->dev->dev,
+				"%s- kmalloc(%Zd) failed.\n", __func__,
+				sizeof(*port_priv));
+			pcount--;
+			status = -ENOMEM;
+			goto attach_failed;
+		}
+
+		spin_lock_init(&port_priv->lock);
+		spin_lock_init(&port_priv->urb_lock);
+		init_waitqueue_head(&port_priv->delta_msr_wait);
+
+		port_priv->port = serial->port[pcount];
+
+		usb_set_serial_port_data(serial->port[pcount], port_priv);
+	}
+
+	status = qt2_setup_urbs(serial);
+	if (status != 0)
+		goto attach_failed;
+
+	return 0;
+
+attach_failed:
+	for (/* empty */; pcount >= 0; pcount--) {
+		port_priv = usb_get_serial_port_data(serial->port[pcount]);
+		kfree(port_priv);
+	}
+	kfree(serial_priv);
+	return status;
+}
+
+static int qt2_tiocmget(struct tty_struct *tty)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct usb_device *dev = port->serial->dev;
+	struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
+	u8 *d;
+	int r;
+
+	d = kzalloc(2, GFP_KERNEL);
+	if (!d)
+		return -ENOMEM;
+
+	r = qt2_getregister(dev, port_priv->device_port, UART_MCR, d);
+	if (r < 0)
+		goto mget_out;
+
+	r = qt2_getregister(dev, port_priv->device_port, UART_MSR, d + 1);
+	if (r < 0)
+		goto mget_out;
+
+	r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) |
+	    (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) |
+	    (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) |
+	    (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) |
+	    (d[1] & UART_MSR_RI ? TIOCM_RI : 0) |
+	    (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0);
+
+mget_out:
+	kfree(d);
+	return r;
+}
+
+static int qt2_tiocmset(struct tty_struct *tty,
+			unsigned int set, unsigned int clear)
+{
+	struct qt2_port_private *port_priv;
+
+	port_priv = usb_get_serial_port_data(tty->driver_data);
+	return update_mctrl(port_priv, set, clear);
+}
+
+static void qt2_break_ctl(struct tty_struct *tty, int break_state)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct qt2_port_private *port_priv;
+	int status;
+	u16 val;
+
+	port_priv = usb_get_serial_port_data(port);
+
+	if (!port_priv->is_open) {
+		dev_err(&port->dev,
+			"%s - port is not open\n", __func__);
+		return;
+	}
+
+	val = (break_state == -1) ? 1 : 0;
+
+	status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL,
+				 val, port_priv->device_port);
+	if (status < 0)
+		dev_warn(&port->dev,
+			 "%s - failed to send control message: %i\n", __func__,
+			 status);
+}
+
+
+
+static void qt2_dtr_rts(struct usb_serial_port *port, int on)
+{
+	struct usb_device *dev = port->serial->dev;
+	struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
+
+	mutex_lock(&port->serial->disc_mutex);
+	if (!port->serial->disconnected) {
+		/* Disable flow control */
+		if (!on && qt2_setregister(dev, port_priv->device_port,
+					   UART_MCR, 0) < 0)
+			dev_warn(&port->dev, "error from flowcontrol urb\n");
+		/* drop RTS and DTR */
+		if (on)
+			update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0);
+		else
+			update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS);
+	}
+	mutex_unlock(&port->serial->disc_mutex);
+}
+
+static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
+{
+	struct qt2_port_private *port_priv;
+	u8 newMSR = (u8) *ch;
+	unsigned long flags;
+
+	port_priv = usb_get_serial_port_data(port);
+
+	spin_lock_irqsave(&port_priv->lock, flags);
+	port_priv->shadowMSR = newMSR;
+	spin_unlock_irqrestore(&port_priv->lock, flags);
+
+	if (newMSR & UART_MSR_ANY_DELTA) {
+		/* update input line counters */
+		if (newMSR & UART_MSR_DCTS)
+			port_priv->icount.cts++;
+
+		if (newMSR & UART_MSR_DDSR)
+			port_priv->icount.dsr++;
+
+		if (newMSR & UART_MSR_DDCD)
+			port_priv->icount.dcd++;
+
+		if (newMSR & UART_MSR_TERI)
+			port_priv->icount.rng++;
+
+		wake_up_interruptible(&port_priv->delta_msr_wait);
+	}
+}
+
+static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)
+{
+	struct qt2_port_private *port_priv;
+	struct async_icount *icount;
+	unsigned long flags;
+	u8 newLSR = (u8) *ch;
+
+	port_priv = usb_get_serial_port_data(port);
+
+	if (newLSR & UART_LSR_BI)
+		newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI);
+
+	spin_lock_irqsave(&port_priv->lock, flags);
+	port_priv->shadowLSR = newLSR;
+	spin_unlock_irqrestore(&port_priv->lock, flags);
+
+	icount = &port_priv->icount;
+
+	if (newLSR & UART_LSR_BRK_ERROR_BITS) {
+
+		if (newLSR & UART_LSR_BI)
+			icount->brk++;
+
+		if (newLSR & UART_LSR_OE)
+			icount->overrun++;
+
+		if (newLSR & UART_LSR_PE)
+			icount->parity++;
+
+		if (newLSR & UART_LSR_FE)
+			icount->frame++;
+	}
+
+}
+
+static int qt2_write_room(struct tty_struct *tty)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct qt2_port_private *port_priv;
+	unsigned long flags = 0;
+	int r;
+
+	port_priv = usb_get_serial_port_data(port);
+
+	spin_lock_irqsave(&port_priv->urb_lock, flags);
+
+	if (port_priv->urb_in_use)
+		r = 0;
+	else
+		r = QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE;
+
+	spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+
+	return r;
+}
+
+static int qt2_write(struct tty_struct *tty,
+		     struct usb_serial_port *port,
+		     const unsigned char *buf, int count)
+{
+	struct qt2_port_private *port_priv;
+	struct urb *write_urb;
+	unsigned char *data;
+	unsigned long flags;
+	int status;
+	int bytes_out = 0;
+
+	port_priv = usb_get_serial_port_data(port);
+
+	if (port_priv->write_urb == NULL) {
+		dev_err(&port->dev, "%s - no output urb\n", __func__);
+		return 0;
+	}
+	write_urb = port_priv->write_urb;
+
+	count = min(count, QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE);
+
+	data = write_urb->transfer_buffer;
+	spin_lock_irqsave(&port_priv->urb_lock, flags);
+	if (port_priv->urb_in_use == true) {
+		printk(KERN_INFO "qt2_write - urb is in use\n");
+		goto write_out;
+	}
+
+	*data++ = QT2_CONTROL_BYTE;
+	*data++ = QT2_CONTROL_BYTE;
+	*data++ = port_priv->device_port;
+	put_unaligned_le16(count, data);
+	data += 2;
+	memcpy(data, buf, count);
+
+	write_urb->transfer_buffer_length = count + QT2_WRITE_CONTROL_SIZE;
+
+	status = usb_submit_urb(write_urb, GFP_ATOMIC);
+	if (status == 0) {
+		port_priv->urb_in_use = true;
+		bytes_out += count;
+	}
+
+write_out:
+	spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+	return bytes_out;
+}
+
+
+static struct usb_serial_driver qt2_device = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "quatech-serial",
+	},
+	.description	     = DRIVER_DESC,
+	.id_table	     = id_table,
+	.open		     = qt2_open,
+	.close		     = qt2_close,
+	.write               = qt2_write,
+	.write_room          = qt2_write_room,
+	.calc_num_ports      = qt2_calc_num_ports,
+	.attach              = qt2_attach,
+	.release             = qt2_release,
+	.disconnect          = qt2_disconnect,
+	.dtr_rts             = qt2_dtr_rts,
+	.break_ctl           = qt2_break_ctl,
+	.tiocmget            = qt2_tiocmget,
+	.tiocmset            = qt2_tiocmset,
+	.get_icount	     = qt2_get_icount,
+	.ioctl               = qt2_ioctl,
+	.set_termios         = qt2_set_termios,
+};
+
+static struct usb_serial_driver *const serial_drivers[] = {
+	&qt2_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index ae4ee30..36e9d9f 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -151,13 +151,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver safe_driver = {
-	.name =		"safe_serial",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static const __u16 crc10_table[256] = {
 	0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff,
 	0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe,
@@ -339,12 +332,12 @@
 		}
 	}
 
-	return usb_serial_register_drivers(&safe_driver, serial_drivers);
+	return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table);
 }
 
 static void __exit safe_exit(void)
 {
-	usb_serial_deregister_drivers(&safe_driver, serial_drivers);
+	usb_serial_deregister_drivers(serial_drivers);
 }
 
 module_init(safe_init);
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
index 46c0430..e4a1787 100644
--- a/drivers/usb/serial/siemens_mpi.c
+++ b/drivers/usb/serial/siemens_mpi.c
@@ -29,13 +29,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver siemens_usb_mpi_driver = {
-	.name =		"siemens_mpi",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver siemens_usb_mpi_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -49,7 +42,7 @@
 	&siemens_usb_mpi_device, NULL
 };
 
-module_usb_serial_driver(siemens_usb_mpi_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 8c8bf80..ba54a0a 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -63,9 +63,7 @@
 
 static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
 {
-	int result;
-	dev_dbg(&udev->dev, "%s\n", __func__);
-	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+	return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			SWIMS_USB_REQUEST_SetPower,	/* __u8 request      */
 			USB_TYPE_VENDOR,		/* __u8 request type */
 			swiState,			/* __u16 value       */
@@ -73,14 +71,11 @@
 			NULL,				/* void *data        */
 			0,				/* __u16 size 	     */
 			USB_CTRL_SET_TIMEOUT);		/* int timeout 	     */
-	return result;
 }
 
 static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
 {
-	int result;
-	dev_dbg(&udev->dev, "%s\n", __func__);
-	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+	return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			SWIMS_USB_REQUEST_SetNmea,	/* __u8 request      */
 			USB_TYPE_VENDOR,		/* __u8 request type */
 			enable,				/* __u16 value       */
@@ -88,7 +83,6 @@
 			NULL,				/* void *data        */
 			0,				/* __u16 size 	     */
 			USB_CTRL_SET_TIMEOUT);		/* int timeout       */
-	return result;
 }
 
 static int sierra_calc_num_ports(struct usb_serial *serial)
@@ -96,8 +90,6 @@
 	int num_ports = 0;
 	u8 ifnum, numendpoints;
 
-	dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
 	ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
 	numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints;
 
@@ -150,7 +142,6 @@
 	int interface;
 	struct usb_interface *p_interface;
 	struct usb_host_interface *p_host_interface;
-	dev_dbg(&serial->dev->dev, "%s\n", __func__);
 
 	/* Get the interface structure pointer from the serial struct */
 	p_interface = serial->interface;
@@ -175,9 +166,8 @@
 	u8 ifnum;
 
 	udev = serial->dev;
-	dev_dbg(&udev->dev, "%s\n", __func__);
-
 	ifnum = sierra_calc_interface(serial);
+
 	/*
 	 * If this interface supports more than 1 alternate
 	 * select the 2nd one
@@ -344,8 +334,6 @@
 	int do_send = 0;
 	int retval;
 
-	dev_dbg(&port->dev, "%s\n", __func__);
-
 	portdata = usb_get_serial_port_data(port);
 
 	if (portdata->dtr_state)
@@ -393,7 +381,6 @@
 static void sierra_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
-	dev_dbg(&port->dev, "%s\n", __func__);
 	tty_termios_copy_hw(tty->termios, old_termios);
 	sierra_send_setup(port);
 }
@@ -404,7 +391,6 @@
 	unsigned int value;
 	struct sierra_port_private *portdata;
 
-	dev_dbg(&port->dev, "%s\n", __func__);
 	portdata = usb_get_serial_port_data(port);
 
 	value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
@@ -441,8 +427,7 @@
 {
 	struct usb_serial_port *port;
 	if (urb) {
-		port =  urb->context;
-		dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
+		port = urb->context;
 		kfree(urb->transfer_buffer);
 		usb_free_urb(urb);
 	}
@@ -455,7 +440,6 @@
 	struct sierra_intf_private *intfdata;
 	int status = urb->status;
 
-	dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
 	intfdata = port->serial->private;
 
 	/* free up the transfer buffer, as usb_free_urb() does not do this */
@@ -598,8 +582,6 @@
 	endpoint = usb_pipeendpoint(urb->pipe);
 	port = urb->context;
 
-	dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
-
 	if (status) {
 		dev_dbg(&port->dev, "%s: nonzero status: %d on"
 			" endpoint %02x\n", __func__, status, endpoint);
@@ -697,8 +679,6 @@
 	struct sierra_port_private *portdata = usb_get_serial_port_data(port);
 	unsigned long flags;
 
-	dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
-
 	/* try to give a good number back based on if we have any free urbs at
 	 * this point in time */
 	spin_lock_irqsave(&portdata->lock, flags);
@@ -805,8 +785,6 @@
 	struct sierra_port_private *portdata;
 	struct sierra_intf_private *intfdata = port->serial->private;
 
-
-	dev_dbg(&port->dev, "%s\n", __func__);
 	portdata = usb_get_serial_port_data(port);
 
 	portdata->rts_state = 0;
@@ -851,8 +829,6 @@
 
 	portdata = usb_get_serial_port_data(port);
 
-	dev_dbg(&port->dev, "%s\n", __func__);
-
 	/* Set some sane defaults */
 	portdata->rts_state = 1;
 	portdata->dtr_state = 1;
@@ -915,8 +891,6 @@
 	int i;
 	u8 ifnum;
 
-	dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
 	/* Set Device mode to D0 */
 	sierra_set_power_state(serial->dev, 0x0000);
 
@@ -977,8 +951,6 @@
 	struct usb_serial_port *port;
 	struct sierra_port_private *portdata;
 
-	dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
 		if (!port)
@@ -1067,29 +1039,11 @@
 	return ec ? -EIO : 0;
 }
 
-static int sierra_reset_resume(struct usb_interface *intf)
-{
-	struct usb_serial *serial = usb_get_intfdata(intf);
-	dev_err(&serial->dev->dev, "%s\n", __func__);
-	return usb_serial_resume(intf);
-}
 #else
 #define sierra_suspend NULL
 #define sierra_resume NULL
-#define sierra_reset_resume NULL
 #endif
 
-static struct usb_driver sierra_driver = {
-	.name       = "sierra",
-	.probe      = usb_serial_probe,
-	.disconnect = usb_serial_disconnect,
-	.suspend    = usb_serial_suspend,
-	.resume     = usb_serial_resume,
-	.reset_resume = sierra_reset_resume,
-	.id_table   = id_table,
-	.supports_autosuspend =	1,
-};
-
 static struct usb_serial_driver sierra_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -1118,7 +1072,7 @@
 	&sierra_device, NULL
 };
 
-module_usb_serial_driver(sierra_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index f06c9a8..cad6089 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -151,14 +151,6 @@
 	SPCP835_TYPE,
 };
 
-static struct usb_driver spcp8x5_driver = {
-	.name =			"spcp8x5",
-	.probe =		usb_serial_probe,
-	.disconnect =		usb_serial_disconnect,
-	.id_table =		id_table,
-};
-
-
 struct spcp8x5_private {
 	spinlock_t 	lock;
 	enum spcp8x5_type	type;
@@ -433,7 +425,7 @@
 	if (i < 0)
 		dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n",
 			uartdata, i);
-	dbg("0x21:0x40:0:0  %d", i);
+	dev_dbg(&port->dev, "0x21:0x40:0:0  %d\n", i);
 
 	if (cflag & CRTSCTS) {
 		/* enable hardware flow control */
@@ -454,8 +446,6 @@
 	u8 status = 0x30;
 	/* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */
 
-	dbg("%s -  port %d", __func__, port->number);
-
 	usb_clear_halt(serial->dev, port->write_urb->pipe);
 	usb_clear_halt(serial->dev, port->read_urb->pipe);
 
@@ -579,15 +569,19 @@
 			 unsigned int cmd, unsigned long arg)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+	dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
+		port->number, cmd);
 
 	switch (cmd) {
 	case TIOCMIWAIT:
-		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
+		dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
+			port->number);
 		return spcp8x5_wait_modem_info(port, arg);
 
 	default:
-		dbg("%s not supported = 0x%04x", __func__, cmd);
+		dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__,
+			cmd);
 		break;
 	}
 
@@ -666,7 +660,7 @@
 	&spcp8x5_device, NULL
 };
 
-module_usb_serial_driver(spcp8x5_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 3cdc8a5..3fee23b 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -59,20 +59,8 @@
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)},
 	{}			/* Terminating entry */
 };
-
 MODULE_DEVICE_TABLE(usb, id_table);
 
-
-static struct usb_driver ssu100_driver = {
-	.name			       = "ssu100",
-	.probe			       = usb_serial_probe,
-	.disconnect		       = usb_serial_disconnect,
-	.id_table		       = id_table,
-	.suspend		       = usb_serial_suspend,
-	.resume			       = usb_serial_resume,
-	.supports_autosuspend	       = 1,
-};
-
 struct ssu100_port_private {
 	spinlock_t status_lock;
 	u8 shadowLSR;
@@ -85,7 +73,6 @@
 {
 	struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port);
 
-	dbg("%s", __func__);
 	kfree(priv);
 }
 
@@ -171,8 +158,6 @@
 	u8 *data;
 	int result = 0;
 
-	dbg("%s", __func__);
-
 	data = kzalloc(3, GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
@@ -237,8 +222,6 @@
 	u16 urb_value = 0; /* will hold the new flags */
 	int result;
 
-	dbg("%s", __func__);
-
 	if (cflag & PARENB) {
 		if (cflag & PARODD)
 			urb_value |= UART_LCR_PARITY;
@@ -312,8 +295,6 @@
 	int result;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	data = kzalloc(2, GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
@@ -348,7 +329,6 @@
 
 static void ssu100_close(struct usb_serial_port *port)
 {
-	dbg("%s", __func__);
 	usb_serial_generic_close(port);
 }
 
@@ -467,8 +447,6 @@
 	struct ssu100_port_private *priv;
 	struct usb_serial_port *port = *serial->port;
 
-	dbg("%s", __func__);
-
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
 		dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
@@ -490,8 +468,6 @@
 	u8 *d;
 	int r;
 
-	dbg("%s\n", __func__);
-
 	d = kzalloc(2, GFP_KERNEL);
 	if (!d)
 		return -ENOMEM;
@@ -522,7 +498,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct usb_device *dev = port->serial->dev;
 
-	dbg("%s\n", __func__);
 	return update_mctrl(dev, set, clear);
 }
 
@@ -530,8 +505,6 @@
 {
 	struct usb_device *dev = port->serial->dev;
 
-	dbg("%s\n", __func__);
-
 	mutex_lock(&port->serial->disc_mutex);
 	if (!port->serial->disconnected) {
 		/* Disable flow control */
@@ -618,8 +591,6 @@
 	int i;
 	char *ch;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if ((len >= 4) &&
 	    (packet[0] == 0x1b) && (packet[1] == 0x1b) &&
 	    ((packet[2] == 0x00) || (packet[2] == 0x01))) {
@@ -656,8 +627,6 @@
 	struct tty_struct *tty;
 	int count;
 
-	dbg("%s", __func__);
-
 	tty = tty_port_tty_get(&port->port);
 	if (!tty)
 		return;
@@ -695,7 +664,7 @@
 	&ssu100_device, NULL
 };
 
-module_usb_serial_driver(ssu100_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 1a5be13..e53d2aa 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -54,8 +54,6 @@
 	int result;
 	int data_length;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -64,12 +62,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
@@ -125,8 +123,6 @@
 	unsigned long flags;
 	int result = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->throttled = false;
 	priv->actually_throttled = false;
@@ -150,8 +146,6 @@
 {
 	struct symbol_private *priv = usb_get_serial_data(port->serial);
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/* shutdown our urbs */
 	usb_kill_urb(priv->int_urb);
 }
@@ -161,7 +155,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct symbol_private *priv = usb_get_serial_data(port->serial);
 
-	dbg("%s - port %d", __func__, port->number);
 	spin_lock_irq(&priv->lock);
 	priv->throttled = true;
 	spin_unlock_irq(&priv->lock);
@@ -174,8 +167,6 @@
 	int result;
 	bool was_throttled;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irq(&priv->lock);
 	priv->throttled = false;
 	was_throttled = priv->actually_throttled;
@@ -266,8 +257,6 @@
 {
 	struct symbol_private *priv = usb_get_serial_data(serial);
 
-	dbg("%s", __func__);
-
 	usb_kill_urb(priv->int_urb);
 	usb_free_urb(priv->int_urb);
 }
@@ -276,19 +265,10 @@
 {
 	struct symbol_private *priv = usb_get_serial_data(serial);
 
-	dbg("%s", __func__);
-
 	kfree(priv->int_buffer);
 	kfree(priv);
 }
 
-static struct usb_driver symbol_driver = {
-	.name =			"symbol",
-	.probe =		usb_serial_probe,
-	.disconnect =		usb_serial_disconnect,
-	.id_table =		id_table,
-};
-
 static struct usb_serial_driver symbol_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -309,7 +289,7 @@
 	&symbol_device, NULL
 };
 
-module_usb_serial_driver(symbol_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index ab74123..a4404f5 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -165,7 +165,7 @@
 /* the array dimension is the number of default entries plus */
 /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
 /* null entry */
-static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
 	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
 	{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -180,6 +180,7 @@
 	{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
 	{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
 	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+	{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
 };
 
 static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
@@ -189,7 +190,7 @@
 	{ USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
 };
 
-static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = {
 	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
 	{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -208,16 +209,10 @@
 	{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
 	{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
 	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+	{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
 	{ }
 };
 
-static struct usb_driver ti_usb_driver = {
-	.name			= "ti_usb_3410_5052",
-	.probe			= usb_serial_probe,
-	.disconnect		= usb_serial_disconnect,
-	.id_table		= ti_id_table_combined,
-};
-
 static struct usb_serial_driver ti_1port_device = {
 	.driver = {
 		.owner		= THIS_MODULE,
@@ -344,20 +339,18 @@
 		ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 	}
 
-	ret = usb_serial_register_drivers(&ti_usb_driver, serial_drivers);
+	ret = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined);
 	if (ret == 0)
 		printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":"
 			       TI_DRIVER_DESC "\n");
 	return ret;
 }
 
-
 static void __exit ti_exit(void)
 {
-	usb_serial_deregister_drivers(&ti_usb_driver, serial_drivers);
+	usb_serial_deregister_drivers(serial_drivers);
 }
 
-
 module_init(ti_init);
 module_exit(ti_exit);
 
@@ -394,7 +387,9 @@
 
 	/* if we have only 1 configuration, download firmware */
 	if (dev->descriptor.bNumConfigurations == 1) {
-		if ((status = ti_download_firmware(tdev)) != 0)
+		status = ti_download_firmware(tdev);
+
+		if (status != 0)
 			goto free_tdev;
 
 		/* 3410 must be reset, 5052 resets itself */
@@ -463,8 +458,6 @@
 	struct ti_device *tdev = usb_get_serial_data(serial);
 	struct ti_port *tport;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i) {
 		tport = usb_get_serial_port_data(serial->port[i]);
 		if (tport) {
@@ -489,8 +482,6 @@
 			     TI_PIPE_TIMEOUT_ENABLE |
 			     (TI_TRANSFER_TIMEOUT << 2));
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (tport == NULL)
 		return -ENODEV;
 
@@ -631,8 +622,6 @@
 	int status;
 	int do_unlock;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	tdev = usb_get_serial_data(port->serial);
 	tport = usb_get_serial_port_data(port);
 	if (tdev == NULL || tport == NULL)
@@ -666,8 +655,6 @@
 	}
 	if (do_unlock)
 		mutex_unlock(&tdev->td_open_close_lock);
-
-	dbg("%s - exit", __func__);
 }
 
 
@@ -676,8 +663,6 @@
 {
 	struct ti_port *tport = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (count == 0) {
 		dbg("%s - write request of 0 bytes", __func__);
 		return 0;
@@ -701,8 +686,6 @@
 	int room = 0;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (tport == NULL)
 		return 0;
 
@@ -722,8 +705,6 @@
 	int chars = 0;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (tport == NULL)
 		return 0;
 
@@ -741,8 +722,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct ti_port *tport = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (tport == NULL)
 		return;
 
@@ -758,8 +737,6 @@
 	struct ti_port *tport = usb_get_serial_port_data(port);
 	int status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (tport == NULL)
 		return;
 
@@ -854,8 +831,6 @@
 	int port_number = port->number - port->serial->minor;
 	unsigned int mcr;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	cflag = tty->termios->c_cflag;
 	iflag = tty->termios->c_iflag;
 
@@ -988,8 +963,6 @@
 	unsigned int mcr;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (tport == NULL)
 		return -ENODEV;
 
@@ -1020,8 +993,6 @@
 	unsigned int mcr;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (tport == NULL)
 		return -ENODEV;
 
@@ -1084,8 +1055,6 @@
 	int retval;
 	__u8 msr;
 
-	dbg("%s", __func__);
-
 	switch (status) {
 	case 0:
 		break;
@@ -1165,8 +1134,6 @@
 	int retval = 0;
 	struct tty_struct *tty;
 
-	dbg("%s", __func__);
-
 	switch (status) {
 	case 0:
 		break;
@@ -1233,8 +1200,6 @@
 	struct usb_serial_port *port = tport->tp_port;
 	int status = urb->status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	tport->tp_write_urb_in_use = 0;
 
 	switch (status) {
@@ -1287,9 +1252,6 @@
 	struct tty_struct *tty = tty_port_tty_get(&port->port);	/* FIXME */
 	unsigned long flags;
 
-
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&tport->tp_lock, flags);
 
 	if (tport->tp_write_urb_in_use)
@@ -1366,8 +1328,6 @@
 	int port_number = port->number - port->serial->minor;
 	struct ti_port_status *data;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	size = sizeof(struct ti_port_status);
 	data = kmalloc(size, GFP_KERNEL);
 	if (!data) {
@@ -1480,8 +1440,6 @@
 	struct usb_serial_port *port = tport->tp_port;
 	wait_queue_t wait;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irq(&tport->tp_lock);
 
 	/* wait for data to drain from the buffer */
@@ -1679,11 +1637,12 @@
 	const struct firmware *fw_p;
 	char buf[32];
 
-	dbg("%s\n", __func__);
 	/* try ID specific firmware first, then try generic firmware */
 	sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor,
 	    dev->descriptor.idProduct);
-	if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) {
+	status = request_firmware(&fw_p, buf, &dev->dev);
+
+	if (status != 0) {
 		buf[0] = '\0';
 		if (dev->descriptor.idVendor == MTS_VENDOR_ID) {
 			switch (dev->descriptor.idProduct) {
diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h
index f140f1b..b353e7e 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.h
+++ b/drivers/usb/serial/ti_usb_3410_5052.h
@@ -37,6 +37,7 @@
 #define TI_5152_BOOT_PRODUCT_ID		0x5152	/* no EEPROM, no firmware */
 #define TI_5052_EEPROM_PRODUCT_ID	0x505A	/* EEPROM, no firmware */
 #define TI_5052_FIRMWARE_PRODUCT_ID	0x505F	/* firmware is running */
+#define FRI2_PRODUCT_ID			0x5053  /* Fish River Island II */
 
 /* Multi-Tech vendor and product ids */
 #define MTS_VENDOR_ID			0x06E0
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 97355a1..6a1b609 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
  * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
  *
@@ -43,17 +43,6 @@
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
 #define DRIVER_DESC "USB Serial Driver core"
 
-/* Driver structure we register with the USB core */
-static struct usb_driver usb_serial_driver = {
-	.name =		"usbserial",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.suspend =	usb_serial_suspend,
-	.resume =	usb_serial_resume,
-	.no_dynamic_id =	1,
-	.supports_autosuspend =	1,
-};
-
 /* There is no MODULE_DEVICE_TABLE for usbserial.c.  Instead
    the MODULE_DEVICE_TABLE declarations in each serial driver
    cause the "hotplug" program to pull in whatever module is necessary
@@ -710,7 +699,7 @@
 	.shutdown = serial_down,
 };
 
-int usb_serial_probe(struct usb_interface *interface,
+static int usb_serial_probe(struct usb_interface *interface,
 			       const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(interface);
@@ -856,6 +845,8 @@
 			module_put(type->driver.owner);
 			return -EIO;
 		}
+		dev_info(&interface->dev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n");
+		dev_info(&interface->dev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n");
 	}
 #endif
 	if (!num_ports) {
@@ -1043,6 +1034,8 @@
 		dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
 	}
 
+	usb_set_intfdata(interface, serial);
+
 	/* if this device type has an attach function, call it */
 	if (type->attach) {
 		retval = type->attach(serial);
@@ -1087,10 +1080,7 @@
 	serial->disconnected = 0;
 
 	usb_serial_console_init(debug, minor);
-
 exit:
-	/* success */
-	usb_set_intfdata(interface, serial);
 	module_put(type->driver.owner);
 	return 0;
 
@@ -1099,9 +1089,8 @@
 	module_put(type->driver.owner);
 	return -EIO;
 }
-EXPORT_SYMBOL_GPL(usb_serial_probe);
 
-void usb_serial_disconnect(struct usb_interface *interface)
+static void usb_serial_disconnect(struct usb_interface *interface)
 {
 	int i;
 	struct usb_serial *serial = usb_get_intfdata(interface);
@@ -1112,7 +1101,6 @@
 	dbg("%s", __func__);
 
 	mutex_lock(&serial->disc_mutex);
-	usb_set_intfdata(interface, NULL);
 	/* must set a flag, to signal subdrivers */
 	serial->disconnected = 1;
 	mutex_unlock(&serial->disc_mutex);
@@ -1137,7 +1125,6 @@
 	usb_serial_put(serial);
 	dev_info(dev, "device disconnected\n");
 }
-EXPORT_SYMBOL_GPL(usb_serial_disconnect);
 
 int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
 {
@@ -1181,6 +1168,22 @@
 }
 EXPORT_SYMBOL(usb_serial_resume);
 
+static int usb_serial_reset_resume(struct usb_interface *intf)
+{
+	struct usb_serial *serial = usb_get_intfdata(intf);
+	int rv;
+
+	serial->suspending = 0;
+	if (serial->type->reset_resume)
+		rv = serial->type->reset_resume(serial);
+	else {
+		rv = -EOPNOTSUPP;
+		intf->needs_binding = 1;
+	}
+
+	return rv;
+}
+
 static const struct tty_operations serial_ops = {
 	.open =			serial_open,
 	.close =		serial_close,
@@ -1204,6 +1207,17 @@
 
 struct tty_driver *usb_serial_tty_driver;
 
+/* Driver structure we register with the USB core */
+static struct usb_driver usb_serial_driver = {
+	.name =		"usbserial",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.suspend =	usb_serial_suspend,
+	.resume =	usb_serial_resume,
+	.no_dynamic_id =	1,
+	.supports_autosuspend =	1,
+};
+
 static int __init usb_serial_init(void)
 {
 	int i;
@@ -1338,7 +1352,6 @@
 				driver->description);
 		return -EINVAL;
 	}
-	driver->usb_driver->supports_autosuspend = 1;
 
 	/* Add this device to our list of devices */
 	mutex_lock(&table_lock);
@@ -1369,18 +1382,19 @@
 
 /**
  * usb_serial_register_drivers - register drivers for a usb-serial module
- * @udriver: usb_driver used for matching devices/interfaces
  * @serial_drivers: NULL-terminated array of pointers to drivers to be registered
+ * @name: name of the usb_driver for this set of @serial_drivers
+ * @id_table: list of all devices this @serial_drivers set binds to
  *
- * Registers @udriver and all the drivers in the @serial_drivers array.
- * Automatically fills in the .no_dynamic_id field in @udriver and
- * the .usb_driver field in each serial driver.
+ * Registers all the drivers in the @serial_drivers array, and dynamically
+ * creates a struct usb_driver with the name @name and id_table of @id_table.
  */
-int usb_serial_register_drivers(struct usb_driver *udriver,
-		struct usb_serial_driver * const serial_drivers[])
+int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[],
+				const char *name,
+				const struct usb_device_id *id_table)
 {
 	int rc;
-	const struct usb_device_id *saved_id_table;
+	struct usb_driver *udriver;
 	struct usb_serial_driver * const *sd;
 
 	/*
@@ -1391,12 +1405,30 @@
 	 * Performance hack: We don't want udriver to be probed until
 	 * the serial drivers are registered, because the probe would
 	 * simply fail for lack of a matching serial driver.
-	 * Therefore save off udriver's id_table until we are all set.
+	 * So we leave udriver's id_table set to NULL until we are all set.
+	 *
+	 * Suspend/resume support is implemented in the usb-serial core,
+	 * so fill in the PM-related fields in udriver.
 	 */
-	saved_id_table = udriver->id_table;
-	udriver->id_table = NULL;
+	udriver = kzalloc(sizeof(*udriver), GFP_KERNEL);
+	if (!udriver)
+		return -ENOMEM;
 
+	udriver->name = name;
 	udriver->no_dynamic_id = 1;
+	udriver->supports_autosuspend = 1;
+	udriver->suspend = usb_serial_suspend;
+	udriver->resume = usb_serial_resume;
+	udriver->probe = usb_serial_probe;
+	udriver->disconnect = usb_serial_disconnect;
+
+	/* we only set the reset_resume field if the serial_driver has one */
+	for (sd = serial_drivers; *sd; ++sd) {
+		if ((*sd)->reset_resume)
+			udriver->reset_resume = usb_serial_reset_resume;
+			break;
+	}
+
 	rc = usb_register(udriver);
 	if (rc)
 		return rc;
@@ -1408,8 +1440,8 @@
 			goto failed;
 	}
 
-	/* Now restore udriver's id_table and look for matches */
-	udriver->id_table = saved_id_table;
+	/* Now set udriver's id_table and look for matches */
+	udriver->id_table = id_table;
 	rc = driver_attach(&udriver->drvwrap.driver);
 	return 0;
 
@@ -1423,17 +1455,20 @@
 
 /**
  * usb_serial_deregister_drivers - deregister drivers for a usb-serial module
- * @udriver: usb_driver to unregister
  * @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered
  *
- * Deregisters @udriver and all the drivers in the @serial_drivers array.
+ * Deregisters all the drivers in the @serial_drivers array and deregisters and
+ * frees the struct usb_driver that was created by the call to
+ * usb_serial_register_drivers().
  */
-void usb_serial_deregister_drivers(struct usb_driver *udriver,
-		struct usb_serial_driver * const serial_drivers[])
+void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[])
 {
+	struct usb_driver *udriver = (*serial_drivers)->usb_driver;
+
 	for (; *serial_drivers; ++serial_drivers)
 		usb_serial_deregister(*serial_drivers);
 	usb_deregister(udriver);
+	kfree(udriver);
 }
 EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers);
 
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index e3e8995..5760f97 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -35,13 +35,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver debug_driver = {
-	.name =		"debug",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 /* This HW really does not support a serial break, so one will be
  * emulated when ever the break state is set to true.
  */
@@ -83,5 +76,5 @@
 	&debug_device, NULL
 };
 
-module_usb_serial_driver(debug_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index c88657d..f35971d 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -43,11 +43,8 @@
 {
 	struct usb_serial *serial = port->serial;
 	struct usb_wwan_port_private *portdata;
-
 	struct usb_wwan_intf_private *intfdata;
 
-	dbg("%s", __func__);
-
 	intfdata = port->serial->private;
 
 	if (!intfdata->send_setup)
@@ -69,8 +66,6 @@
 {
 	struct usb_wwan_intf_private *intfdata = port->serial->private;
 
-	dbg("%s", __func__);
-
 	/* Doesn't support option setting */
 	tty_termios_copy_hw(tty->termios, old_termios);
 
@@ -286,8 +281,6 @@
 	unsigned char *data = urb->transfer_buffer;
 	int status = urb->status;
 
-	dbg("%s: %p", __func__, urb);
-
 	endpoint = usb_pipeendpoint(urb->pipe);
 	port = urb->context;
 
@@ -307,20 +300,17 @@
 		}
 
 		/* Resubmit urb so we continue receiving */
-		if (status != -ESHUTDOWN) {
-			err = usb_submit_urb(urb, GFP_ATOMIC);
-			if (err) {
-				if (err != -EPERM) {
-					printk(KERN_ERR "%s: resubmit read urb failed. "
-						"(%d)", __func__, err);
-					/* busy also in error unless we are killed */
-					usb_mark_last_busy(port->serial->dev);
-				}
-			} else {
+		err = usb_submit_urb(urb, GFP_ATOMIC);
+		if (err) {
+			if (err != -EPERM) {
+				printk(KERN_ERR "%s: resubmit read urb failed. "
+					"(%d)", __func__, err);
+				/* busy also in error unless we are killed */
 				usb_mark_last_busy(port->serial->dev);
 			}
+		} else {
+			usb_mark_last_busy(port->serial->dev);
 		}
-
 	}
 }
 
@@ -331,8 +321,6 @@
 	struct usb_wwan_intf_private *intfdata;
 	int i;
 
-	dbg("%s", __func__);
-
 	port = urb->context;
 	intfdata = port->serial->private;
 
@@ -406,8 +394,6 @@
 	portdata = usb_get_serial_port_data(port);
 	intfdata = serial->private;
 
-	dbg("%s", __func__);
-
 	/* Start reading from the IN endpoint */
 	for (i = 0; i < N_IN_URB; i++) {
 		urb = portdata->in_urbs[i];
@@ -441,7 +427,6 @@
 	struct usb_wwan_port_private *portdata;
 	struct usb_wwan_intf_private *intfdata = port->serial->private;
 
-	dbg("%s", __func__);
 	portdata = usb_get_serial_port_data(port);
 
 	if (serial->dev) {
@@ -492,8 +477,6 @@
 	struct usb_serial_port *port;
 	struct usb_wwan_port_private *portdata;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
 		portdata = usb_get_serial_port_data(port);
@@ -534,8 +517,6 @@
 	struct usb_wwan_port_private *portdata;
 	u8 *buffer;
 
-	dbg("%s", __func__);
-
 	/* Now setup per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
@@ -603,8 +584,6 @@
 
 void usb_wwan_disconnect(struct usb_serial *serial)
 {
-	dbg("%s", __func__);
-
 	stop_read_write_urbs(serial);
 }
 EXPORT_SYMBOL(usb_wwan_disconnect);
@@ -615,8 +594,6 @@
 	struct usb_serial_port *port;
 	struct usb_wwan_port_private *portdata;
 
-	dbg("%s", __func__);
-
 	/* Now free them */
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
@@ -649,8 +626,6 @@
 	struct usb_wwan_intf_private *intfdata = serial->private;
 	int b;
 
-	dbg("%s entered", __func__);
-
 	if (PMSG_IS_AUTO(message)) {
 		spin_lock_irq(&intfdata->susp_lock);
 		b = intfdata->in_flight;
@@ -714,7 +689,6 @@
 	struct urb *urb;
 	int err = 0;
 
-	dbg("%s entered", __func__);
 	/* get the interrupt URBs resubmitted unconditionally */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
@@ -725,8 +699,8 @@
 		err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
 		dbg("Submitted interrupt URB for port %d (result %d)", i, err);
 		if (err < 0) {
-			err("%s: Error %d for interrupt URB of port%d",
-			    __func__, err, i);
+			dev_err(&port->dev, "%s: Error %d for interrupt URB\n",
+				__func__, err);
 			goto err_out;
 		}
 	}
@@ -747,8 +721,8 @@
 			urb = portdata->in_urbs[j];
 			err = usb_submit_urb(urb, GFP_ATOMIC);
 			if (err < 0) {
-				err("%s: Error %d for bulk URB %d",
-				    __func__, err, i);
+				dev_err(&port->dev, "%s: Error %d for bulk URB %d\n",
+					__func__, err, i);
 				spin_unlock_irq(&intfdata->susp_lock);
 				goto err_out;
 			}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 71d6964..f253c91 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -53,8 +53,6 @@
 
 /* Parameters that may be passed into the module. */
 static bool debug;
-static __u16 vendor;
-static __u16 product;
 
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),
@@ -115,14 +113,12 @@
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
-	{ },					/* optional parameter entry */
 	{ }					/* Terminating entry */
 };
 
 static struct usb_device_id clie_id_5_table [] = {
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
-	{ },					/* optional parameter entry */
 	{ }					/* Terminating entry */
 };
 
@@ -162,19 +158,11 @@
 	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) },
 	{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) },
-	{ },					/* optional parameter entry */
 	{ }					/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
-static struct usb_driver visor_driver = {
-	.name =		"visor",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
-
 /* All of the device info needed for the Handspring Visor,
    and Palm 4.0 devices */
 static struct usb_serial_driver handspring_device = {
@@ -244,8 +232,6 @@
 {
 	int result = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (!port->read_urb) {
 		/* this is needed for some brain dead Sony devices */
 		dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n");
@@ -258,7 +244,7 @@
 		goto exit;
 
 	if (port->interrupt_in_urb) {
-		dbg("%s - adding interrupt input for treo", __func__);
+		dev_dbg(&port->dev, "adding interrupt input for treo\n");
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (result)
 			dev_err(&port->dev,
@@ -274,8 +260,6 @@
 {
 	unsigned char *transfer_buffer;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	/* shutdown our urbs */
 	usb_serial_generic_close(port);
 	usb_kill_urb(port->interrupt_in_urb);
@@ -310,12 +294,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
@@ -348,8 +332,6 @@
 	int i;
 	int num_ports = 0;
 
-	dbg("%s", __func__);
-
 	transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
 	if (!transfer_buffer) {
 		dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
@@ -445,8 +427,6 @@
 	unsigned char *transfer_buffer;
 	int retval;
 
-	dbg("%s", __func__);
-
 	transfer_buffer =  kmalloc(sizeof(*connection_info), GFP_KERNEL);
 	if (!transfer_buffer) {
 		dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
@@ -478,8 +458,6 @@
 	int (*startup)(struct usb_serial *serial,
 					const struct usb_device_id *id);
 
-	dbg("%s", __func__);
-
 	/*
 	 * some Samsung Android phones in modem mode have the same ID
 	 * as SPH-I500, but they are ACM devices, so dont bind to them
@@ -521,8 +499,6 @@
 	int result;
 	u8 *data;
 
-	dbg("%s", __func__);
-
 	data = kmalloc(1, GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
@@ -585,8 +561,6 @@
 		(serial->num_interrupt_in == 0))
 		return 0;
 
-	dbg("%s", __func__);
-
 	/*
 	* It appears that Treos and Kyoceras want to use the
 	* 1st bulk in endpoint to communicate with the 2nd bulk out endpoint,
@@ -622,8 +596,6 @@
 	unsigned int pipe;
 	int j;
 
-	dbg("%s", __func__);
-
 	/* TH55 registers 2 ports.
 	   Communication in from the UX50/TH55 uses bulk_in_endpointAddress
 	   from port 0. Communication out to the UX50/TH55 uses
@@ -648,59 +620,7 @@
 	return 0;
 }
 
-static int __init visor_init(void)
-{
-	int i, retval;
-	/* Only if parameters were passed to us */
-	if (vendor > 0 && product > 0) {
-		struct usb_device_id usb_dev_temp[] = {
-			{
-				USB_DEVICE(vendor, product),
-				.driver_info =
-					(kernel_ulong_t) &palm_os_4_probe
-			}
-		};
-
-		/* Find the last entry in id_table */
-		for (i = 0;; i++) {
-			if (id_table[i].idVendor == 0) {
-				id_table[i] = usb_dev_temp[0];
-				break;
-			}
-		}
-		/* Find the last entry in id_table_combined */
-		for (i = 0;; i++) {
-			if (id_table_combined[i].idVendor == 0) {
-				id_table_combined[i] = usb_dev_temp[0];
-				break;
-			}
-		}
-		printk(KERN_INFO KBUILD_MODNAME
-		       ": Untested USB device specified at time of module insertion\n");
-		printk(KERN_INFO KBUILD_MODNAME
-		       ": Warning: This is not guaranteed to work\n");
-		printk(KERN_INFO KBUILD_MODNAME
-		       ": Using a newer kernel is preferred to this method\n");
-		printk(KERN_INFO KBUILD_MODNAME
-		       ": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n",
-			vendor, product);
-	}
-
-	retval = usb_serial_register_drivers(&visor_driver, serial_drivers);
-	if (retval == 0)
-		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
-	return retval;
-}
-
-
-static void __exit visor_exit (void)
-{
-	usb_serial_deregister_drivers(&visor_driver, serial_drivers);
-}
-
-
-module_init(visor_init);
-module_exit(visor_exit);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -708,9 +628,3 @@
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
-
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified vendor ID");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified product ID");
-
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
index 078f338..0c0aa87 100644
--- a/drivers/usb/serial/vivopay-serial.c
+++ b/drivers/usb/serial/vivopay-serial.c
@@ -25,13 +25,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver vivopay_serial_driver = {
-	.name =			"vivopay-serial",
-	.probe =		usb_serial_probe,
-	.disconnect =		usb_serial_disconnect,
-	.id_table =		id_table,
-};
-
 static struct usb_serial_driver vivopay_serial_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -45,7 +38,7 @@
 	&vivopay_serial_device, NULL
 };
 
-module_usb_serial_driver(vivopay_serial_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 407e23c..473635e 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -45,7 +45,6 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>"
 #define DRIVER_DESC "USB ConnectTech WhiteHEAT driver"
 
@@ -78,12 +77,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
-static struct usb_driver whiteheat_driver = {
-	.name =		"whiteheat",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-};
 
 /* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */
 static int  whiteheat_firmware_download(struct usb_serial *serial,
@@ -96,10 +89,6 @@
 static int  whiteheat_open(struct tty_struct *tty,
 			struct usb_serial_port *port);
 static void whiteheat_close(struct usb_serial_port *port);
-static int  whiteheat_write(struct tty_struct *tty,
-			struct usb_serial_port *port,
-			const unsigned char *buf, int count);
-static int  whiteheat_write_room(struct tty_struct *tty);
 static int  whiteheat_ioctl(struct tty_struct *tty,
 			unsigned int cmd, unsigned long arg);
 static void whiteheat_set_termios(struct tty_struct *tty,
@@ -108,11 +97,6 @@
 static int  whiteheat_tiocmset(struct tty_struct *tty,
 			unsigned int set, unsigned int clear);
 static void whiteheat_break_ctl(struct tty_struct *tty, int break_state);
-static int  whiteheat_chars_in_buffer(struct tty_struct *tty);
-static void whiteheat_throttle(struct tty_struct *tty);
-static void whiteheat_unthrottle(struct tty_struct *tty);
-static void whiteheat_read_callback(struct urb *urb);
-static void whiteheat_write_callback(struct urb *urb);
 
 static struct usb_serial_driver whiteheat_fake_device = {
 	.driver = {
@@ -138,18 +122,13 @@
 	.release =		whiteheat_release,
 	.open =			whiteheat_open,
 	.close =		whiteheat_close,
-	.write =		whiteheat_write,
-	.write_room =		whiteheat_write_room,
 	.ioctl =		whiteheat_ioctl,
 	.set_termios =		whiteheat_set_termios,
 	.break_ctl =		whiteheat_break_ctl,
 	.tiocmget =		whiteheat_tiocmget,
 	.tiocmset =		whiteheat_tiocmset,
-	.chars_in_buffer =	whiteheat_chars_in_buffer,
-	.throttle =		whiteheat_throttle,
-	.unthrottle =		whiteheat_unthrottle,
-	.read_bulk_callback =	whiteheat_read_callback,
-	.write_bulk_callback =	whiteheat_write_callback,
+	.throttle =		usb_serial_generic_throttle,
+	.unthrottle =		usb_serial_generic_unthrottle,
 };
 
 static struct usb_serial_driver * const serial_drivers[] = {
@@ -166,29 +145,8 @@
 	__u8			result_buffer[64];
 };
 
-
-#define THROTTLED		0x01
-#define ACTUALLY_THROTTLED	0x02
-
-static int urb_pool_size = 8;
-
-struct whiteheat_urb_wrap {
-	struct list_head	list;
-	struct urb		*urb;
-};
-
 struct whiteheat_private {
-	spinlock_t		lock;
-	__u8			flags;
 	__u8			mcr;		/* FIXME: no locking on mcr */
-	struct list_head	rx_urbs_free;
-	struct list_head	rx_urbs_submitted;
-	struct list_head	rx_urb_q;
-	struct work_struct	rx_work;
-	struct usb_serial_port	*port;
-	struct list_head	tx_urbs_free;
-	struct list_head	tx_urbs_submitted;
-	struct mutex		deathwarrant;
 };
 
 
@@ -198,12 +156,6 @@
 static void command_port_write_callback(struct urb *urb);
 static void command_port_read_callback(struct urb *urb);
 
-static int start_port_read(struct usb_serial_port *port);
-static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb,
-						struct list_head *head);
-static struct list_head *list_first(struct list_head *head);
-static void rx_data_softint(struct work_struct *work);
-
 static int firm_send_command(struct usb_serial_port *port, __u8 command,
 						__u8 *data, __u8 datasize);
 static int firm_open(struct usb_serial_port *port);
@@ -247,8 +199,6 @@
 	const struct firmware *loader_fw = NULL, *firmware_fw = NULL;
 	const struct ihex_binrec *record;
 
-	dbg("%s", __func__);
-
 	if (request_ihex_firmware(&firmware_fw, "whiteheat.fw",
 				  &serial->dev->dev)) {
 		dev_err(&serial->dev->dev,
@@ -349,11 +299,6 @@
 	__u8 *command;
 	__u8 *result;
 	int i;
-	int j;
-	struct urb *urb;
-	int buf_size;
-	struct whiteheat_urb_wrap *wrap;
-	struct list_head *tmp;
 
 	command_port = serial->port[COMMAND_PORT];
 
@@ -408,8 +353,8 @@
 
 	hw_info = (struct whiteheat_hw_info *)&result[1];
 
-	dev_info(&serial->dev->dev, "%s: Driver %s: Firmware v%d.%02d\n",
-		 serial->type->description, DRIVER_VERSION,
+	dev_info(&serial->dev->dev, "%s: Firmware v%d.%02d\n",
+		 serial->type->description,
 		 hw_info->sw_major_rev, hw_info->sw_minor_rev);
 
 	for (i = 0; i < serial->num_ports; i++) {
@@ -423,72 +368,7 @@
 			goto no_private;
 		}
 
-		spin_lock_init(&info->lock);
-		mutex_init(&info->deathwarrant);
-		info->flags = 0;
 		info->mcr = 0;
-		INIT_WORK(&info->rx_work, rx_data_softint);
-		info->port = port;
-
-		INIT_LIST_HEAD(&info->rx_urbs_free);
-		INIT_LIST_HEAD(&info->rx_urbs_submitted);
-		INIT_LIST_HEAD(&info->rx_urb_q);
-		INIT_LIST_HEAD(&info->tx_urbs_free);
-		INIT_LIST_HEAD(&info->tx_urbs_submitted);
-
-		for (j = 0; j < urb_pool_size; j++) {
-			urb = usb_alloc_urb(0, GFP_KERNEL);
-			if (!urb) {
-				dev_err(&port->dev, "No free urbs available\n");
-				goto no_rx_urb;
-			}
-			buf_size = port->read_urb->transfer_buffer_length;
-			urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);
-			if (!urb->transfer_buffer) {
-				dev_err(&port->dev,
-					"Couldn't allocate urb buffer\n");
-				goto no_rx_buf;
-			}
-			wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
-			if (!wrap) {
-				dev_err(&port->dev,
-					"Couldn't allocate urb wrapper\n");
-				goto no_rx_wrap;
-			}
-			usb_fill_bulk_urb(urb, serial->dev,
-					usb_rcvbulkpipe(serial->dev,
-						port->bulk_in_endpointAddress),
-					urb->transfer_buffer, buf_size,
-					whiteheat_read_callback, port);
-			wrap->urb = urb;
-			list_add(&wrap->list, &info->rx_urbs_free);
-
-			urb = usb_alloc_urb(0, GFP_KERNEL);
-			if (!urb) {
-				dev_err(&port->dev, "No free urbs available\n");
-				goto no_tx_urb;
-			}
-			buf_size = port->write_urb->transfer_buffer_length;
-			urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);
-			if (!urb->transfer_buffer) {
-				dev_err(&port->dev,
-					"Couldn't allocate urb buffer\n");
-				goto no_tx_buf;
-			}
-			wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
-			if (!wrap) {
-				dev_err(&port->dev,
-					"Couldn't allocate urb wrapper\n");
-				goto no_tx_wrap;
-			}
-			usb_fill_bulk_urb(urb, serial->dev,
-					usb_sndbulkpipe(serial->dev,
-						port->bulk_out_endpointAddress),
-					urb->transfer_buffer, buf_size,
-					whiteheat_write_callback, port);
-			wrap->urb = urb;
-			list_add(&wrap->list, &info->tx_urbs_free);
-		}
 
 		usb_set_serial_port_data(port, info);
 	}
@@ -531,29 +411,6 @@
 	for (i = serial->num_ports - 1; i >= 0; i--) {
 		port = serial->port[i];
 		info = usb_get_serial_port_data(port);
-		for (j = urb_pool_size - 1; j >= 0; j--) {
-			tmp = list_first(&info->tx_urbs_free);
-			list_del(tmp);
-			wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-			urb = wrap->urb;
-			kfree(wrap);
-no_tx_wrap:
-			kfree(urb->transfer_buffer);
-no_tx_buf:
-			usb_free_urb(urb);
-no_tx_urb:
-			tmp = list_first(&info->rx_urbs_free);
-			list_del(tmp);
-			wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-			urb = wrap->urb;
-			kfree(wrap);
-no_rx_wrap:
-			kfree(urb->transfer_buffer);
-no_rx_buf:
-			usb_free_urb(urb);
-no_rx_urb:
-			;
-		}
 		kfree(info);
 no_private:
 		;
@@ -569,56 +426,27 @@
 static void whiteheat_release(struct usb_serial *serial)
 {
 	struct usb_serial_port *command_port;
-	struct usb_serial_port *port;
 	struct whiteheat_private *info;
-	struct whiteheat_urb_wrap *wrap;
-	struct urb *urb;
-	struct list_head *tmp;
-	struct list_head *tmp2;
 	int i;
 
-	dbg("%s", __func__);
-
 	/* free up our private data for our command port */
 	command_port = serial->port[COMMAND_PORT];
 	kfree(usb_get_serial_port_data(command_port));
 
 	for (i = 0; i < serial->num_ports; i++) {
-		port = serial->port[i];
-		info = usb_get_serial_port_data(port);
-		list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) {
-			list_del(tmp);
-			wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-			urb = wrap->urb;
-			kfree(wrap);
-			kfree(urb->transfer_buffer);
-			usb_free_urb(urb);
-		}
-		list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) {
-			list_del(tmp);
-			wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-			urb = wrap->urb;
-			kfree(wrap);
-			kfree(urb->transfer_buffer);
-			usb_free_urb(urb);
-		}
+		info = usb_get_serial_port_data(serial->port[i]);
 		kfree(info);
 	}
 }
 
 static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-	int		retval = 0;
-
-	dbg("%s - port %d", __func__, port->number);
+	int retval;
 
 	retval = start_command_port(port->serial);
 	if (retval)
 		goto exit;
 
-	if (tty)
-		tty->low_latency = 1;
-
 	/* send an open port command */
 	retval = firm_open(port);
 	if (retval) {
@@ -640,154 +468,33 @@
 	usb_clear_halt(port->serial->dev, port->read_urb->pipe);
 	usb_clear_halt(port->serial->dev, port->write_urb->pipe);
 
-	/* Start reading from the device */
-	retval = start_port_read(port);
+	retval = usb_serial_generic_open(tty, port);
 	if (retval) {
-		dev_err(&port->dev,
-			"%s - failed submitting read urb, error %d\n",
-			__func__, retval);
 		firm_close(port);
 		stop_command_port(port->serial);
 		goto exit;
 	}
-
 exit:
-	dbg("%s - exit, retval = %d", __func__, retval);
 	return retval;
 }
 
 
 static void whiteheat_close(struct usb_serial_port *port)
 {
-	struct whiteheat_private *info = usb_get_serial_port_data(port);
-	struct whiteheat_urb_wrap *wrap;
-	struct urb *urb;
-	struct list_head *tmp;
-	struct list_head *tmp2;
-
-	dbg("%s - port %d", __func__, port->number);
-
 	firm_report_tx_done(port);
 	firm_close(port);
 
-	/* shutdown our bulk reads and writes */
-	mutex_lock(&info->deathwarrant);
-	spin_lock_irq(&info->lock);
-	list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
-		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-		urb = wrap->urb;
-		list_del(tmp);
-		spin_unlock_irq(&info->lock);
-		usb_kill_urb(urb);
-		spin_lock_irq(&info->lock);
-		list_add(tmp, &info->rx_urbs_free);
-	}
-	list_for_each_safe(tmp, tmp2, &info->rx_urb_q)
-		list_move(tmp, &info->rx_urbs_free);
-	list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) {
-		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-		urb = wrap->urb;
-		list_del(tmp);
-		spin_unlock_irq(&info->lock);
-		usb_kill_urb(urb);
-		spin_lock_irq(&info->lock);
-		list_add(tmp, &info->tx_urbs_free);
-	}
-	spin_unlock_irq(&info->lock);
-	mutex_unlock(&info->deathwarrant);
+	usb_serial_generic_close(port);
+
 	stop_command_port(port->serial);
 }
 
-
-static int whiteheat_write(struct tty_struct *tty,
-	struct usb_serial_port *port, const unsigned char *buf, int count)
-{
-	struct whiteheat_private *info = usb_get_serial_port_data(port);
-	struct whiteheat_urb_wrap *wrap;
-	struct urb *urb;
-	int result;
-	int bytes;
-	int sent = 0;
-	unsigned long flags;
-	struct list_head *tmp;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (count == 0) {
-		dbg("%s - write request of 0 bytes", __func__);
-		return (0);
-	}
-
-	while (count) {
-		spin_lock_irqsave(&info->lock, flags);
-		if (list_empty(&info->tx_urbs_free)) {
-			spin_unlock_irqrestore(&info->lock, flags);
-			break;
-		}
-		tmp = list_first(&info->tx_urbs_free);
-		list_del(tmp);
-		spin_unlock_irqrestore(&info->lock, flags);
-
-		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-		urb = wrap->urb;
-		bytes = (count > port->bulk_out_size) ?
-					port->bulk_out_size : count;
-		memcpy(urb->transfer_buffer, buf + sent, bytes);
-
-		usb_serial_debug_data(debug, &port->dev,
-				__func__, bytes, urb->transfer_buffer);
-
-		urb->transfer_buffer_length = bytes;
-		result = usb_submit_urb(urb, GFP_ATOMIC);
-		if (result) {
-			dev_err_console(port,
-				"%s - failed submitting write urb, error %d\n",
-				__func__, result);
-			sent = result;
-			spin_lock_irqsave(&info->lock, flags);
-			list_add(tmp, &info->tx_urbs_free);
-			spin_unlock_irqrestore(&info->lock, flags);
-			break;
-		} else {
-			sent += bytes;
-			count -= bytes;
-			spin_lock_irqsave(&info->lock, flags);
-			list_add(tmp, &info->tx_urbs_submitted);
-			spin_unlock_irqrestore(&info->lock, flags);
-		}
-	}
-
-	return sent;
-}
-
-static int whiteheat_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct whiteheat_private *info = usb_get_serial_port_data(port);
-	struct list_head *tmp;
-	int room = 0;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&info->lock, flags);
-	list_for_each(tmp, &info->tx_urbs_free)
-		room++;
-	spin_unlock_irqrestore(&info->lock, flags);
-	room *= port->bulk_out_size;
-
-	dbg("%s - returns %d", __func__, room);
-	return (room);
-}
-
 static int whiteheat_tiocmget(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
 	struct whiteheat_private *info = usb_get_serial_port_data(port);
 	unsigned int modem_signals = 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	firm_get_dtr_rts(port);
 	if (info->mcr & UART_MCR_DTR)
 		modem_signals |= TIOCM_DTR;
@@ -803,8 +510,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct whiteheat_private *info = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (set & TIOCM_RTS)
 		info->mcr |= UART_MCR_RTS;
 	if (set & TIOCM_DTR)
@@ -837,7 +542,7 @@
 		serstruct.line = port->serial->minor;
 		serstruct.port = port->number;
 		serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
-		serstruct.xmit_fifo_size = port->bulk_out_size;
+		serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo);
 		serstruct.custom_divisor = 0;
 		serstruct.baud_base = 460800;
 		serstruct.close_delay = CLOSING_DELAY;
@@ -867,60 +572,6 @@
 }
 
 
-static int whiteheat_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct whiteheat_private *info = usb_get_serial_port_data(port);
-	struct list_head *tmp;
-	struct whiteheat_urb_wrap *wrap;
-	int chars = 0;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&info->lock, flags);
-	list_for_each(tmp, &info->tx_urbs_submitted) {
-		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-		chars += wrap->urb->transfer_buffer_length;
-	}
-	spin_unlock_irqrestore(&info->lock, flags);
-
-	dbg("%s - returns %d", __func__, chars);
-	return chars;
-}
-
-
-static void whiteheat_throttle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct whiteheat_private *info = usb_get_serial_port_data(port);
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irq(&info->lock);
-	info->flags |= THROTTLED;
-	spin_unlock_irq(&info->lock);
-}
-
-
-static void whiteheat_unthrottle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct whiteheat_private *info = usb_get_serial_port_data(port);
-	int actually_throttled;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irq(&info->lock);
-	actually_throttled = info->flags & ACTUALLY_THROTTLED;
-	info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
-	spin_unlock_irq(&info->lock);
-
-	if (actually_throttled)
-		rx_data_softint(&info->rx_work);
-}
-
-
 /*****************************************************************************
  * Connect Tech's White Heat callback routines
  *****************************************************************************/
@@ -928,8 +579,6 @@
 {
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	if (status) {
 		dbg("nonzero urb status: %d", status);
 		return;
@@ -945,8 +594,6 @@
 	unsigned char *data = urb->transfer_buffer;
 	int result;
 
-	dbg("%s", __func__);
-
 	command_info = usb_get_serial_port_data(command_port);
 	if (!command_info) {
 		dbg("%s - command_info is NULL, exiting.", __func__);
@@ -989,80 +636,6 @@
 }
 
 
-static void whiteheat_read_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	struct whiteheat_urb_wrap *wrap;
-	unsigned char *data = urb->transfer_buffer;
-	struct whiteheat_private *info = usb_get_serial_port_data(port);
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock(&info->lock);
-	wrap = urb_to_wrap(urb, &info->rx_urbs_submitted);
-	if (!wrap) {
-		spin_unlock(&info->lock);
-		dev_err(&port->dev, "%s - Not my urb!\n", __func__);
-		return;
-	}
-	list_del(&wrap->list);
-	spin_unlock(&info->lock);
-
-	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
-		spin_lock(&info->lock);
-		list_add(&wrap->list, &info->rx_urbs_free);
-		spin_unlock(&info->lock);
-		return;
-	}
-
-	usb_serial_debug_data(debug, &port->dev,
-				__func__, urb->actual_length, data);
-
-	spin_lock(&info->lock);
-	list_add_tail(&wrap->list, &info->rx_urb_q);
-	if (info->flags & THROTTLED) {
-		info->flags |= ACTUALLY_THROTTLED;
-		spin_unlock(&info->lock);
-		return;
-	}
-	spin_unlock(&info->lock);
-
-	schedule_work(&info->rx_work);
-}
-
-
-static void whiteheat_write_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	struct whiteheat_private *info = usb_get_serial_port_data(port);
-	struct whiteheat_urb_wrap *wrap;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock(&info->lock);
-	wrap = urb_to_wrap(urb, &info->tx_urbs_submitted);
-	if (!wrap) {
-		spin_unlock(&info->lock);
-		dev_err(&port->dev, "%s - Not my urb!\n", __func__);
-		return;
-	}
-	list_move(&wrap->list, &info->tx_urbs_free);
-	spin_unlock(&info->lock);
-
-	if (status) {
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
-		return;
-	}
-
-	usb_serial_port_softint(port);
-}
-
-
 /*****************************************************************************
  * Connect Tech's White Heat firmware interface
  *****************************************************************************/
@@ -1337,124 +910,7 @@
 	mutex_unlock(&command_info->mutex);
 }
 
-
-static int start_port_read(struct usb_serial_port *port)
-{
-	struct whiteheat_private *info = usb_get_serial_port_data(port);
-	struct whiteheat_urb_wrap *wrap;
-	struct urb *urb;
-	int retval = 0;
-	unsigned long flags;
-	struct list_head *tmp;
-	struct list_head *tmp2;
-
-	spin_lock_irqsave(&info->lock, flags);
-
-	list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) {
-		list_del(tmp);
-		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-		urb = wrap->urb;
-		spin_unlock_irqrestore(&info->lock, flags);
-		retval = usb_submit_urb(urb, GFP_KERNEL);
-		if (retval) {
-			spin_lock_irqsave(&info->lock, flags);
-			list_add(tmp, &info->rx_urbs_free);
-			list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
-				wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-				urb = wrap->urb;
-				list_del(tmp);
-				spin_unlock_irqrestore(&info->lock, flags);
-				usb_kill_urb(urb);
-				spin_lock_irqsave(&info->lock, flags);
-				list_add(tmp, &info->rx_urbs_free);
-			}
-			break;
-		}
-		spin_lock_irqsave(&info->lock, flags);
-		list_add(tmp, &info->rx_urbs_submitted);
-	}
-
-	spin_unlock_irqrestore(&info->lock, flags);
-
-	return retval;
-}
-
-
-static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb,
-						struct list_head *head)
-{
-	struct whiteheat_urb_wrap *wrap;
-	struct list_head *tmp;
-
-	list_for_each(tmp, head) {
-		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-		if (wrap->urb == urb)
-			return wrap;
-	}
-
-	return NULL;
-}
-
-
-static struct list_head *list_first(struct list_head *head)
-{
-	return head->next;
-}
-
-
-static void rx_data_softint(struct work_struct *work)
-{
-	struct whiteheat_private *info =
-		container_of(work, struct whiteheat_private, rx_work);
-	struct usb_serial_port *port = info->port;
-	struct tty_struct *tty = tty_port_tty_get(&port->port);
-	struct whiteheat_urb_wrap *wrap;
-	struct urb *urb;
-	unsigned long flags;
-	struct list_head *tmp;
-	struct list_head *tmp2;
-	int result;
-	int sent = 0;
-
-	spin_lock_irqsave(&info->lock, flags);
-	if (info->flags & THROTTLED) {
-		spin_unlock_irqrestore(&info->lock, flags);
-		goto out;
-	}
-
-	list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
-		list_del(tmp);
-		spin_unlock_irqrestore(&info->lock, flags);
-
-		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
-		urb = wrap->urb;
-
-		if (tty && urb->actual_length)
-			sent += tty_insert_flip_string(tty,
-				urb->transfer_buffer, urb->actual_length);
-
-		result = usb_submit_urb(urb, GFP_ATOMIC);
-		if (result) {
-			dev_err(&port->dev,
-				"%s - failed resubmitting read urb, error %d\n",
-				__func__, result);
-			spin_lock_irqsave(&info->lock, flags);
-			list_add(tmp, &info->rx_urbs_free);
-			continue;
-		}
-
-		spin_lock_irqsave(&info->lock, flags);
-		list_add(tmp, &info->rx_urbs_submitted);
-	}
-	spin_unlock_irqrestore(&info->lock, flags);
-
-	if (sent)
-		tty_flip_buffer_push(tty);
-out:
-	tty_kref_put(tty);
-}
-
-module_usb_serial_driver(whiteheat_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -1463,8 +919,5 @@
 MODULE_FIRMWARE("whiteheat.fw");
 MODULE_FIRMWARE("whiteheat_loader.fw");
 
-module_param(urb_pool_size, int, 0);
-MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering");
-
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
index 9d0bb37..c043aa8 100644
--- a/drivers/usb/serial/zio.c
+++ b/drivers/usb/serial/zio.c
@@ -22,13 +22,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver zio_driver = {
-	.name =		"zio",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static struct usb_serial_driver zio_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -42,5 +35,5 @@
 	&zio_device, NULL
 };
 
-module_usb_serial_driver(zio_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index e7e6781..b28f2ad 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -1933,11 +1933,7 @@
 	kfree(buf);
 
 nofw:
-	if (sd_fw != NULL) {
-		release_firmware(sd_fw);
-		sd_fw = NULL;
-	}
-
+	release_firmware(sd_fw);
 	return result;
 }
 
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 856ad92..1719886 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -110,7 +110,7 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
-/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+/* Deduced by Jonathan Woithe <jwoithe@just42.net>
  * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
  * always fails and confuses drive.
  */
@@ -1885,6 +1885,13 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Jesse Feddema <jdfeddema@gmail.com> */
+UNUSUAL_DEV(  0x177f, 0x0400, 0x0000, 0x0000,
+		"Yarvik",
+		"PMP400",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
+
 /* Reported by Hans de Goede <hdegoede@redhat.com>
  * These Appotech controllers are found in Picture Frames, they provide a
  * (buggy) emulation of a cdrom drive which contains the windows software
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 2653e73..e23c30a 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -121,7 +121,7 @@
 }
 
 static struct us_unusual_dev us_unusual_dev_list[] = {
-#	include "unusual_devs.h" 
+#	include "unusual_devs.h"
 	{ }		/* Terminating entry */
 };
 
@@ -261,17 +261,17 @@
 void fill_inquiry_response(struct us_data *us, unsigned char *data,
 		unsigned int data_len)
 {
-	if (data_len<36) // You lose.
+	if (data_len < 36) /* You lose. */
 		return;
 
 	memset(data+8, ' ', 28);
-	if(data[0]&0x20) { /* USB device currently not connected. Return
+	if (data[0]&0x20) { /* USB device currently not connected. Return
 			      peripheral qualifier 001b ("...however, the
 			      physical device is not currently connected
 			      to this logical unit") and leave vendor and
 			      product identification empty. ("If the target
 			      does store some of the INQUIRY data on the
-			      device, it may return zeros or ASCII spaces 
+			      device, it may return zeros or ASCII spaces
 			      (20h) in those fields until the data is
 			      available from the device."). */
 	} else {
@@ -298,7 +298,7 @@
 	struct us_data *us = (struct us_data *)__us;
 	struct Scsi_Host *host = us_to_host(us);
 
-	for(;;) {
+	for (;;) {
 		US_DEBUGP("*** thread sleeping.\n");
 		if (wait_for_completion_interruptible(&us->cmnd_ready))
 			break;
@@ -327,7 +327,7 @@
 
 		scsi_unlock(host);
 
-		/* reject the command if the direction indicator 
+		/* reject the command if the direction indicator
 		 * is UNKNOWN
 		 */
 		if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
@@ -338,7 +338,7 @@
 		/* reject if target != 0 or if LUN is higher than
 		 * the maximum known LUN
 		 */
-		else if (us->srb->device->id && 
+		else if (us->srb->device->id &&
 				!(us->fflags & US_FL_SCM_MULT_TARG)) {
 			US_DEBUGP("Bad target number (%d:%d)\n",
 				  us->srb->device->id, us->srb->device->lun);
@@ -351,7 +351,7 @@
 			us->srb->result = DID_BAD_TARGET << 16;
 		}
 
-		/* Handle those devices which need us to fake 
+		/* Handle those devices which need us to fake
 		 * their inquiry data */
 		else if ((us->srb->cmnd[0] == INQUIRY) &&
 			    (us->fflags & US_FL_FIX_INQUIRY)) {
@@ -376,7 +376,7 @@
 
 		/* indicate that the command is done */
 		if (us->srb->result != DID_ABORT << 16) {
-			US_DEBUGP("scsi cmd done, result=0x%x\n", 
+			US_DEBUGP("scsi cmd done, result=0x%x\n",
 				   us->srb->result);
 			us->srb->scsi_done(us->srb);
 		} else {
@@ -414,7 +414,7 @@
 	}
 	__set_current_state(TASK_RUNNING);
 	return 0;
-}	
+}
 
 /***********************************************************************
  * Device probing and disconnecting
@@ -732,7 +732,7 @@
 	us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
 	us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
 		usb_endpoint_num(ep_out));
-	us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, 
+	us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
 		usb_endpoint_num(ep_in));
 	if (ep_int) {
 		us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index b4a7167..0616f23 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -93,8 +93,8 @@
 
 	interface = usb_find_interface(&skel_driver, subminor);
 	if (!interface) {
-		err("%s - error, can't find device for minor %d",
-		     __func__, subminor);
+		pr_err("%s - error, can't find device for minor %d\n",
+			__func__, subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
@@ -179,8 +179,9 @@
 		if (!(urb->status == -ENOENT ||
 		    urb->status == -ECONNRESET ||
 		    urb->status == -ESHUTDOWN))
-			err("%s - nonzero write bulk status received: %d",
-			    __func__, urb->status);
+			dev_err(&dev->interface->dev,
+				"%s - nonzero write bulk status received: %d\n",
+				__func__, urb->status);
 
 		dev->errors = urb->status;
 	} else {
@@ -213,7 +214,8 @@
 	/* do it */
 	rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
 	if (rv < 0) {
-		err("%s - failed submitting read urb, error %d",
+		dev_err(&dev->interface->dev,
+			"%s - failed submitting read urb, error %d\n",
 			__func__, rv);
 		dev->bulk_in_filled = 0;
 		rv = (rv == -ENOMEM) ? rv : -EIO;
@@ -364,8 +366,9 @@
 		if (!(urb->status == -ENOENT ||
 		    urb->status == -ECONNRESET ||
 		    urb->status == -ESHUTDOWN))
-			err("%s - nonzero write bulk status received: %d",
-			    __func__, urb->status);
+			dev_err(&dev->interface->dev,
+				"%s - nonzero write bulk status received: %d\n",
+				__func__, urb->status);
 
 		spin_lock(&dev->err_lock);
 		dev->errors = urb->status;
@@ -459,8 +462,9 @@
 	retval = usb_submit_urb(urb, GFP_KERNEL);
 	mutex_unlock(&dev->io_mutex);
 	if (retval) {
-		err("%s - failed submitting write urb, error %d", __func__,
-		    retval);
+		dev_err(&dev->interface->dev,
+			"%s - failed submitting write urb, error %d\n",
+			__func__, retval);
 		goto error_unanchor;
 	}
 
@@ -519,7 +523,7 @@
 	/* allocate memory for our device state and initialize it */
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev) {
-		err("Out of memory");
+		dev_err(&interface->dev, "Out of memory\n");
 		goto error;
 	}
 	kref_init(&dev->kref);
@@ -546,12 +550,14 @@
 			dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
 			dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
 			if (!dev->bulk_in_buffer) {
-				err("Could not allocate bulk_in_buffer");
+				dev_err(&interface->dev,
+					"Could not allocate bulk_in_buffer\n");
 				goto error;
 			}
 			dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
 			if (!dev->bulk_in_urb) {
-				err("Could not allocate bulk_in_urb");
+				dev_err(&interface->dev,
+					"Could not allocate bulk_in_urb\n");
 				goto error;
 			}
 		}
@@ -563,7 +569,8 @@
 		}
 	}
 	if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
-		err("Could not find both bulk-in and bulk-out endpoints");
+		dev_err(&interface->dev,
+			"Could not find both bulk-in and bulk-out endpoints\n");
 		goto error;
 	}
 
@@ -574,7 +581,8 @@
 	retval = usb_register_dev(interface, &skel_class);
 	if (retval) {
 		/* something prevented us from registering this driver */
-		err("Not able to get a minor for this device.");
+		dev_err(&interface->dev,
+			"Not able to get a minor for this device.\n");
 		usb_set_intfdata(interface, NULL);
 		goto error;
 	}
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index ffbce45..fe3b6ec 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -536,7 +536,7 @@
 	for (page = (unsigned long)fbdev->fb_mem;
 	     page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);
 	     page += PAGE_SIZE) {
-#if CONFIG_DMA_NONCOHERENT
+#ifdef CONFIG_DMA_NONCOHERENT
 		SetPageReserved(virt_to_page(CAC_ADDR((void *)page)));
 #else
 		SetPageReserved(virt_to_page(page));
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index 99b354b..f994c8b 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -33,7 +33,6 @@
 #include <asm/mach-types.h>
 #include <linux/uaccess.h>
 
-#include <asm/hardware/clps7111.h>
 #include <mach/syspld.h>
 
 struct fb_info	*cfb;
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 4a89f88..6c6bc57 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -45,6 +45,7 @@
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
 #include <mach/mxsfb.h>
 
 #define REG_SET	4
@@ -756,6 +757,7 @@
 	struct mxsfb_info *host;
 	struct fb_info *fb_info;
 	struct fb_modelist *modelist;
+	struct pinctrl *pinctrl;
 	int i, ret;
 
 	if (!pdata) {
@@ -793,6 +795,12 @@
 
 	host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
 
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		goto error_getpin;
+	}
+
 	host->clk = clk_get(&host->pdev->dev, NULL);
 	if (IS_ERR(host->clk)) {
 		ret = PTR_ERR(host->clk);
@@ -848,6 +856,7 @@
 error_pseudo_pallette:
 	clk_put(host->clk);
 error_getclock:
+error_getpin:
 	iounmap(host->base);
 error_ioremap:
 	framebuffer_release(fb_info);
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index 408a992..c3853c9 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -10,12 +10,12 @@
 	  Supports LCD Panel used in TI SDP3430 and EVM boards,
 	  OMAP3517 EVM boards and CM-T35.
 
-config PANEL_DVI
-	tristate "DVI output"
+config PANEL_TFP410
+	tristate "TFP410 DPI-to-DVI chip"
 	depends on OMAP2_DSS_DPI && I2C
 	help
-	  Driver for external monitors, connected via DVI. The driver uses i2c
-	  to read EDID information from the monitor.
+	  Driver for TFP410 DPI-to-DVI chip. The driver uses i2c to read EDID
+	  information from the monitor.
 
 config PANEL_LGPHILIPS_LB035Q02
 	tristate "LG.Philips LB035Q02 LCD Panel"
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index fbfafc6..58a5176 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o
-obj-$(CONFIG_PANEL_DVI) += panel-dvi.o
+obj-$(CONFIG_PANEL_TFP410) += panel-tfp410.o
 obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
 obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
 obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
diff --git a/drivers/video/omap2/displays/panel-dvi.c b/drivers/video/omap2/displays/panel-dvi.c
deleted file mode 100644
index 03eb14a..0000000
--- a/drivers/video/omap2/displays/panel-dvi.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * DVI output support
- *
- * Copyright (C) 2011 Texas Instruments Inc
- * Author: Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <video/omapdss.h>
-#include <linux/i2c.h>
-#include <drm/drm_edid.h>
-
-#include <video/omap-panel-dvi.h>
-
-static const struct omap_video_timings panel_dvi_default_timings = {
-	.x_res		= 640,
-	.y_res		= 480,
-
-	.pixel_clock	= 23500,
-
-	.hfp		= 48,
-	.hsw		= 32,
-	.hbp		= 80,
-
-	.vfp		= 3,
-	.vsw		= 4,
-	.vbp		= 7,
-};
-
-struct panel_drv_data {
-	struct omap_dss_device *dssdev;
-
-	struct mutex lock;
-};
-
-static inline struct panel_dvi_platform_data
-*get_pdata(const struct omap_dss_device *dssdev)
-{
-	return dssdev->data;
-}
-
-static int panel_dvi_power_on(struct omap_dss_device *dssdev)
-{
-	struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
-	int r;
-
-	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
-		return 0;
-
-	r = omapdss_dpi_display_enable(dssdev);
-	if (r)
-		goto err0;
-
-	if (pdata->platform_enable) {
-		r = pdata->platform_enable(dssdev);
-		if (r)
-			goto err1;
-	}
-
-	return 0;
-err1:
-	omapdss_dpi_display_disable(dssdev);
-err0:
-	return r;
-}
-
-static void panel_dvi_power_off(struct omap_dss_device *dssdev)
-{
-	struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
-
-	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
-		return;
-
-	if (pdata->platform_disable)
-		pdata->platform_disable(dssdev);
-
-	omapdss_dpi_display_disable(dssdev);
-}
-
-static int panel_dvi_probe(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata;
-
-	ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
-	if (!ddata)
-		return -ENOMEM;
-
-	dssdev->panel.timings = panel_dvi_default_timings;
-	dssdev->panel.config = OMAP_DSS_LCD_TFT;
-
-	ddata->dssdev = dssdev;
-	mutex_init(&ddata->lock);
-
-	dev_set_drvdata(&dssdev->dev, ddata);
-
-	return 0;
-}
-
-static void __exit panel_dvi_remove(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-
-	mutex_lock(&ddata->lock);
-
-	dev_set_drvdata(&dssdev->dev, NULL);
-
-	mutex_unlock(&ddata->lock);
-
-	kfree(ddata);
-}
-
-static int panel_dvi_enable(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-	int r;
-
-	mutex_lock(&ddata->lock);
-
-	r = panel_dvi_power_on(dssdev);
-	if (r == 0)
-		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-	mutex_unlock(&ddata->lock);
-
-	return r;
-}
-
-static void panel_dvi_disable(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-
-	mutex_lock(&ddata->lock);
-
-	panel_dvi_power_off(dssdev);
-
-	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
-	mutex_unlock(&ddata->lock);
-}
-
-static int panel_dvi_suspend(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-
-	mutex_lock(&ddata->lock);
-
-	panel_dvi_power_off(dssdev);
-
-	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-
-	mutex_unlock(&ddata->lock);
-
-	return 0;
-}
-
-static int panel_dvi_resume(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-	int r;
-
-	mutex_lock(&ddata->lock);
-
-	r = panel_dvi_power_on(dssdev);
-	if (r == 0)
-		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-	mutex_unlock(&ddata->lock);
-
-	return r;
-}
-
-static void panel_dvi_set_timings(struct omap_dss_device *dssdev,
-		struct omap_video_timings *timings)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-
-	mutex_lock(&ddata->lock);
-	dpi_set_timings(dssdev, timings);
-	mutex_unlock(&ddata->lock);
-}
-
-static void panel_dvi_get_timings(struct omap_dss_device *dssdev,
-		struct omap_video_timings *timings)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-
-	mutex_lock(&ddata->lock);
-	*timings = dssdev->panel.timings;
-	mutex_unlock(&ddata->lock);
-}
-
-static int panel_dvi_check_timings(struct omap_dss_device *dssdev,
-		struct omap_video_timings *timings)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-	int r;
-
-	mutex_lock(&ddata->lock);
-	r = dpi_check_timings(dssdev, timings);
-	mutex_unlock(&ddata->lock);
-
-	return r;
-}
-
-
-static int panel_dvi_ddc_read(struct i2c_adapter *adapter,
-		unsigned char *buf, u16 count, u8 offset)
-{
-	int r, retries;
-
-	for (retries = 3; retries > 0; retries--) {
-		struct i2c_msg msgs[] = {
-			{
-				.addr   = DDC_ADDR,
-				.flags  = 0,
-				.len    = 1,
-				.buf    = &offset,
-			}, {
-				.addr   = DDC_ADDR,
-				.flags  = I2C_M_RD,
-				.len    = count,
-				.buf    = buf,
-			}
-		};
-
-		r = i2c_transfer(adapter, msgs, 2);
-		if (r == 2)
-			return 0;
-
-		if (r != -EAGAIN)
-			break;
-	}
-
-	return r < 0 ? r : -EIO;
-}
-
-static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
-		u8 *edid, int len)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-	struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
-	struct i2c_adapter *adapter;
-	int r, l, bytes_read;
-
-	mutex_lock(&ddata->lock);
-
-	if (pdata->i2c_bus_num == 0) {
-		r = -ENODEV;
-		goto err;
-	}
-
-	adapter = i2c_get_adapter(pdata->i2c_bus_num);
-	if (!adapter) {
-		dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
-				pdata->i2c_bus_num);
-		r = -EINVAL;
-		goto err;
-	}
-
-	l = min(EDID_LENGTH, len);
-	r = panel_dvi_ddc_read(adapter, edid, l, 0);
-	if (r)
-		goto err;
-
-	bytes_read = l;
-
-	/* if there are extensions, read second block */
-	if (len > EDID_LENGTH && edid[0x7e] > 0) {
-		l = min(EDID_LENGTH, len - EDID_LENGTH);
-
-		r = panel_dvi_ddc_read(adapter, edid + EDID_LENGTH,
-				l, EDID_LENGTH);
-		if (r)
-			goto err;
-
-		bytes_read += l;
-	}
-
-	mutex_unlock(&ddata->lock);
-
-	return bytes_read;
-
-err:
-	mutex_unlock(&ddata->lock);
-	return r;
-}
-
-static bool panel_dvi_detect(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-	struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
-	struct i2c_adapter *adapter;
-	unsigned char out;
-	int r;
-
-	mutex_lock(&ddata->lock);
-
-	if (pdata->i2c_bus_num == 0)
-		goto out;
-
-	adapter = i2c_get_adapter(pdata->i2c_bus_num);
-	if (!adapter)
-		goto out;
-
-	r = panel_dvi_ddc_read(adapter, &out, 1, 0);
-
-	mutex_unlock(&ddata->lock);
-
-	return r == 0;
-
-out:
-	mutex_unlock(&ddata->lock);
-	return true;
-}
-
-static struct omap_dss_driver panel_dvi_driver = {
-	.probe		= panel_dvi_probe,
-	.remove		= __exit_p(panel_dvi_remove),
-
-	.enable		= panel_dvi_enable,
-	.disable	= panel_dvi_disable,
-	.suspend	= panel_dvi_suspend,
-	.resume		= panel_dvi_resume,
-
-	.set_timings	= panel_dvi_set_timings,
-	.get_timings	= panel_dvi_get_timings,
-	.check_timings	= panel_dvi_check_timings,
-
-	.read_edid	= panel_dvi_read_edid,
-	.detect		= panel_dvi_detect,
-
-	.driver         = {
-		.name   = "dvi",
-		.owner  = THIS_MODULE,
-	},
-};
-
-static int __init panel_dvi_init(void)
-{
-	return omap_dss_register_driver(&panel_dvi_driver);
-}
-
-static void __exit panel_dvi_exit(void)
-{
-	omap_dss_unregister_driver(&panel_dvi_driver);
-}
-
-module_init(panel_dvi_init);
-module_exit(panel_dvi_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 0f21fa5..b2dd88b 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -993,6 +993,15 @@
 
 	dev_set_drvdata(&dssdev->dev, td);
 
+	if (gpio_is_valid(panel_data->reset_gpio)) {
+		r = gpio_request_one(panel_data->reset_gpio, GPIOF_OUT_INIT_LOW,
+				"taal rst");
+		if (r) {
+			dev_err(&dssdev->dev, "failed to request reset gpio\n");
+			goto err_rst_gpio;
+		}
+	}
+
 	taal_hw_reset(dssdev);
 
 	if (panel_data->use_dsi_backlight) {
@@ -1073,6 +1082,9 @@
 	if (bldev != NULL)
 		backlight_device_unregister(bldev);
 err_bl:
+	if (gpio_is_valid(panel_data->reset_gpio))
+		gpio_free(panel_data->reset_gpio);
+err_rst_gpio:
 	destroy_workqueue(td->workqueue);
 err_wq:
 	free_regulators(panel_config->regulators, panel_config->num_regulators);
@@ -1116,15 +1128,25 @@
 	free_regulators(td->panel_config->regulators,
 			td->panel_config->num_regulators);
 
+	if (gpio_is_valid(panel_data->reset_gpio))
+		gpio_free(panel_data->reset_gpio);
+
 	kfree(td);
 }
 
 static int taal_power_on(struct omap_dss_device *dssdev)
 {
 	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
 	u8 id1, id2, id3;
 	int r;
 
+	r = omapdss_dsi_configure_pins(dssdev, &panel_data->pin_config);
+	if (r) {
+		dev_err(&dssdev->dev, "failed to configure DSI pins\n");
+		goto err0;
+	};
+
 	r = omapdss_dsi_display_enable(dssdev);
 	if (r) {
 		dev_err(&dssdev->dev, "failed to enable DSI\n");
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c
new file mode 100644
index 0000000..52637fa
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-tfp410.c
@@ -0,0 +1,381 @@
+/*
+ * TFP410 DPI-to-DVI chip
+ *
+ * Copyright (C) 2011 Texas Instruments Inc
+ * Author: Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <video/omapdss.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <drm/drm_edid.h>
+
+#include <video/omap-panel-tfp410.h>
+
+static const struct omap_video_timings tfp410_default_timings = {
+	.x_res		= 640,
+	.y_res		= 480,
+
+	.pixel_clock	= 23500,
+
+	.hfp		= 48,
+	.hsw		= 32,
+	.hbp		= 80,
+
+	.vfp		= 3,
+	.vsw		= 4,
+	.vbp		= 7,
+};
+
+struct panel_drv_data {
+	struct omap_dss_device *dssdev;
+
+	struct mutex lock;
+
+	int pd_gpio;
+};
+
+static inline struct tfp410_platform_data
+*get_pdata(const struct omap_dss_device *dssdev)
+{
+	return dssdev->data;
+}
+
+static int tfp410_power_on(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+	int r;
+
+	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+		return 0;
+
+	r = omapdss_dpi_display_enable(dssdev);
+	if (r)
+		goto err0;
+
+	if (gpio_is_valid(ddata->pd_gpio))
+		gpio_set_value(ddata->pd_gpio, 1);
+
+	return 0;
+err0:
+	return r;
+}
+
+static void tfp410_power_off(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+		return;
+
+	if (gpio_is_valid(ddata->pd_gpio))
+		gpio_set_value(ddata->pd_gpio, 0);
+
+	omapdss_dpi_display_disable(dssdev);
+}
+
+static int tfp410_probe(struct omap_dss_device *dssdev)
+{
+	struct tfp410_platform_data *pdata = get_pdata(dssdev);
+	struct panel_drv_data *ddata;
+	int r;
+
+	ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
+	if (!ddata)
+		return -ENOMEM;
+
+	dssdev->panel.timings = tfp410_default_timings;
+	dssdev->panel.config = OMAP_DSS_LCD_TFT;
+
+	ddata->dssdev = dssdev;
+	mutex_init(&ddata->lock);
+
+	if (pdata)
+		ddata->pd_gpio = pdata->power_down_gpio;
+	else
+		ddata->pd_gpio = -1;
+
+	if (gpio_is_valid(ddata->pd_gpio)) {
+		r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW,
+				"tfp410 pd");
+		if (r) {
+			dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n",
+					ddata->pd_gpio);
+			ddata->pd_gpio = -1;
+		}
+	}
+
+	dev_set_drvdata(&dssdev->dev, ddata);
+
+	return 0;
+}
+
+static void __exit tfp410_remove(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&ddata->lock);
+
+	if (gpio_is_valid(ddata->pd_gpio))
+		gpio_free(ddata->pd_gpio);
+
+	dev_set_drvdata(&dssdev->dev, NULL);
+
+	mutex_unlock(&ddata->lock);
+
+	kfree(ddata);
+}
+
+static int tfp410_enable(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+	int r;
+
+	mutex_lock(&ddata->lock);
+
+	r = tfp410_power_on(dssdev);
+	if (r == 0)
+		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+	mutex_unlock(&ddata->lock);
+
+	return r;
+}
+
+static void tfp410_disable(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&ddata->lock);
+
+	tfp410_power_off(dssdev);
+
+	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+	mutex_unlock(&ddata->lock);
+}
+
+static int tfp410_suspend(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&ddata->lock);
+
+	tfp410_power_off(dssdev);
+
+	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+	mutex_unlock(&ddata->lock);
+
+	return 0;
+}
+
+static int tfp410_resume(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+	int r;
+
+	mutex_lock(&ddata->lock);
+
+	r = tfp410_power_on(dssdev);
+	if (r == 0)
+		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+	mutex_unlock(&ddata->lock);
+
+	return r;
+}
+
+static void tfp410_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&ddata->lock);
+	dpi_set_timings(dssdev, timings);
+	mutex_unlock(&ddata->lock);
+}
+
+static void tfp410_get_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&ddata->lock);
+	*timings = dssdev->panel.timings;
+	mutex_unlock(&ddata->lock);
+}
+
+static int tfp410_check_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+	int r;
+
+	mutex_lock(&ddata->lock);
+	r = dpi_check_timings(dssdev, timings);
+	mutex_unlock(&ddata->lock);
+
+	return r;
+}
+
+
+static int tfp410_ddc_read(struct i2c_adapter *adapter,
+		unsigned char *buf, u16 count, u8 offset)
+{
+	int r, retries;
+
+	for (retries = 3; retries > 0; retries--) {
+		struct i2c_msg msgs[] = {
+			{
+				.addr   = DDC_ADDR,
+				.flags  = 0,
+				.len    = 1,
+				.buf    = &offset,
+			}, {
+				.addr   = DDC_ADDR,
+				.flags  = I2C_M_RD,
+				.len    = count,
+				.buf    = buf,
+			}
+		};
+
+		r = i2c_transfer(adapter, msgs, 2);
+		if (r == 2)
+			return 0;
+
+		if (r != -EAGAIN)
+			break;
+	}
+
+	return r < 0 ? r : -EIO;
+}
+
+static int tfp410_read_edid(struct omap_dss_device *dssdev,
+		u8 *edid, int len)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+	struct tfp410_platform_data *pdata = get_pdata(dssdev);
+	struct i2c_adapter *adapter;
+	int r, l, bytes_read;
+
+	mutex_lock(&ddata->lock);
+
+	if (pdata->i2c_bus_num == 0) {
+		r = -ENODEV;
+		goto err;
+	}
+
+	adapter = i2c_get_adapter(pdata->i2c_bus_num);
+	if (!adapter) {
+		dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
+				pdata->i2c_bus_num);
+		r = -EINVAL;
+		goto err;
+	}
+
+	l = min(EDID_LENGTH, len);
+	r = tfp410_ddc_read(adapter, edid, l, 0);
+	if (r)
+		goto err;
+
+	bytes_read = l;
+
+	/* if there are extensions, read second block */
+	if (len > EDID_LENGTH && edid[0x7e] > 0) {
+		l = min(EDID_LENGTH, len - EDID_LENGTH);
+
+		r = tfp410_ddc_read(adapter, edid + EDID_LENGTH,
+				l, EDID_LENGTH);
+		if (r)
+			goto err;
+
+		bytes_read += l;
+	}
+
+	mutex_unlock(&ddata->lock);
+
+	return bytes_read;
+
+err:
+	mutex_unlock(&ddata->lock);
+	return r;
+}
+
+static bool tfp410_detect(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+	struct tfp410_platform_data *pdata = get_pdata(dssdev);
+	struct i2c_adapter *adapter;
+	unsigned char out;
+	int r;
+
+	mutex_lock(&ddata->lock);
+
+	if (pdata->i2c_bus_num == 0)
+		goto out;
+
+	adapter = i2c_get_adapter(pdata->i2c_bus_num);
+	if (!adapter)
+		goto out;
+
+	r = tfp410_ddc_read(adapter, &out, 1, 0);
+
+	mutex_unlock(&ddata->lock);
+
+	return r == 0;
+
+out:
+	mutex_unlock(&ddata->lock);
+	return true;
+}
+
+static struct omap_dss_driver tfp410_driver = {
+	.probe		= tfp410_probe,
+	.remove		= __exit_p(tfp410_remove),
+
+	.enable		= tfp410_enable,
+	.disable	= tfp410_disable,
+	.suspend	= tfp410_suspend,
+	.resume		= tfp410_resume,
+
+	.set_timings	= tfp410_set_timings,
+	.get_timings	= tfp410_get_timings,
+	.check_timings	= tfp410_check_timings,
+
+	.read_edid	= tfp410_read_edid,
+	.detect		= tfp410_detect,
+
+	.driver         = {
+		.name   = "tfp410",
+		.owner  = THIS_MODULE,
+	},
+};
+
+static int __init tfp410_init(void)
+{
+	return omap_dss_register_driver(&tfp410_driver);
+}
+
+static void __exit tfp410_exit(void)
+{
+	omap_dss_unregister_driver(&tfp410_driver);
+}
+
+module_init(tfp410_init);
+module_exit(tfp410_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 662d14f..210a3c4 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -2076,65 +2076,6 @@
 	}
 }
 
-static int dsi_parse_lane_config(struct omap_dss_device *dssdev)
-{
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	u8 lanes[DSI_MAX_NR_LANES];
-	u8 polarities[DSI_MAX_NR_LANES];
-	int num_lanes, i;
-
-	static const enum dsi_lane_function functions[] = {
-		DSI_LANE_CLK,
-		DSI_LANE_DATA1,
-		DSI_LANE_DATA2,
-		DSI_LANE_DATA3,
-		DSI_LANE_DATA4,
-	};
-
-	lanes[0] = dssdev->phy.dsi.clk_lane;
-	lanes[1] = dssdev->phy.dsi.data1_lane;
-	lanes[2] = dssdev->phy.dsi.data2_lane;
-	lanes[3] = dssdev->phy.dsi.data3_lane;
-	lanes[4] = dssdev->phy.dsi.data4_lane;
-	polarities[0] = dssdev->phy.dsi.clk_pol;
-	polarities[1] = dssdev->phy.dsi.data1_pol;
-	polarities[2] = dssdev->phy.dsi.data2_pol;
-	polarities[3] = dssdev->phy.dsi.data3_pol;
-	polarities[4] = dssdev->phy.dsi.data4_pol;
-
-	num_lanes = 0;
-
-	for (i = 0; i < dsi->num_lanes_supported; ++i)
-		dsi->lanes[i].function = DSI_LANE_UNUSED;
-
-	for (i = 0; i < dsi->num_lanes_supported; ++i) {
-		int num;
-
-		if (lanes[i] == DSI_LANE_UNUSED)
-			break;
-
-		num = lanes[i] - 1;
-
-		if (num >= dsi->num_lanes_supported)
-			return -EINVAL;
-
-		if (dsi->lanes[num].function != DSI_LANE_UNUSED)
-			return -EINVAL;
-
-		dsi->lanes[num].function = functions[i];
-		dsi->lanes[num].polarity = polarities[i];
-		num_lanes++;
-	}
-
-	if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported)
-		return -EINVAL;
-
-	dsi->num_lanes_used = num_lanes;
-
-	return 0;
-}
-
 static int dsi_set_lane_config(struct omap_dss_device *dssdev)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -3975,6 +3916,74 @@
 	}
 }
 
+int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
+		const struct omap_dsi_pin_config *pin_cfg)
+{
+	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+	int num_pins;
+	const int *pins;
+	struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
+	int num_lanes;
+	int i;
+
+	static const enum dsi_lane_function functions[] = {
+		DSI_LANE_CLK,
+		DSI_LANE_DATA1,
+		DSI_LANE_DATA2,
+		DSI_LANE_DATA3,
+		DSI_LANE_DATA4,
+	};
+
+	num_pins = pin_cfg->num_pins;
+	pins = pin_cfg->pins;
+
+	if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2
+			|| num_pins % 2 != 0)
+		return -EINVAL;
+
+	for (i = 0; i < DSI_MAX_NR_LANES; ++i)
+		lanes[i].function = DSI_LANE_UNUSED;
+
+	num_lanes = 0;
+
+	for (i = 0; i < num_pins; i += 2) {
+		u8 lane, pol;
+		int dx, dy;
+
+		dx = pins[i];
+		dy = pins[i + 1];
+
+		if (dx < 0 || dx >= dsi->num_lanes_supported * 2)
+			return -EINVAL;
+
+		if (dy < 0 || dy >= dsi->num_lanes_supported * 2)
+			return -EINVAL;
+
+		if (dx & 1) {
+			if (dy != dx - 1)
+				return -EINVAL;
+			pol = 1;
+		} else {
+			if (dy != dx + 1)
+				return -EINVAL;
+			pol = 0;
+		}
+
+		lane = dx / 2;
+
+		lanes[lane].function = functions[i / 2];
+		lanes[lane].polarity = pol;
+		num_lanes++;
+	}
+
+	memcpy(dsi->lanes, lanes, sizeof(dsi->lanes));
+	dsi->num_lanes_used = num_lanes;
+
+	return 0;
+}
+EXPORT_SYMBOL(omapdss_dsi_configure_pins);
+
 int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -4339,12 +4348,6 @@
 	int dsi_module = dsi_get_dsidev_id(dsidev);
 	int r;
 
-	r = dsi_parse_lane_config(dssdev);
-	if (r) {
-		DSSERR("illegal lane config");
-		goto err0;
-	}
-
 	r = dsi_pll_init(dsidev, true, true);
 	if (r)
 		goto err0;
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index a159b63..7af1e81 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -1594,7 +1594,7 @@
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
-		err("dlfb_usb_probe: failed alloc of dev struct\n");
+		dev_err(&interface->dev, "dlfb_usb_probe: failed alloc of dev struct\n");
 		goto error;
 	}
 
diff --git a/drivers/vme/Kconfig b/drivers/vme/Kconfig
new file mode 100644
index 0000000..c5c2246
--- /dev/null
+++ b/drivers/vme/Kconfig
@@ -0,0 +1,19 @@
+#
+# VME configuration.
+#
+
+menuconfig VME_BUS
+	tristate "VME bridge support"
+	depends on PCI
+	---help---
+	  If you say Y here you get support for the VME bridge Framework.
+
+if VME_BUS
+
+source "drivers/vme/bridges/Kconfig"
+
+source "drivers/vme/boards/Kconfig"
+
+source "drivers/staging/vme/devices/Kconfig"
+
+endif # VME
diff --git a/drivers/vme/Makefile b/drivers/vme/Makefile
new file mode 100644
index 0000000..d7bfcb9
--- /dev/null
+++ b/drivers/vme/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the VME bridge device drivers.
+#
+obj-$(CONFIG_VME_BUS)		+= vme.o
+
+obj-y				+= bridges/
+obj-y				+= boards/
diff --git a/drivers/staging/vme/boards/Kconfig b/drivers/vme/boards/Kconfig
similarity index 100%
rename from drivers/staging/vme/boards/Kconfig
rename to drivers/vme/boards/Kconfig
diff --git a/drivers/staging/vme/boards/Makefile b/drivers/vme/boards/Makefile
similarity index 100%
rename from drivers/staging/vme/boards/Makefile
rename to drivers/vme/boards/Makefile
diff --git a/drivers/staging/vme/boards/vme_vmivme7805.c b/drivers/vme/boards/vme_vmivme7805.c
similarity index 100%
rename from drivers/staging/vme/boards/vme_vmivme7805.c
rename to drivers/vme/boards/vme_vmivme7805.c
diff --git a/drivers/staging/vme/boards/vme_vmivme7805.h b/drivers/vme/boards/vme_vmivme7805.h
similarity index 100%
rename from drivers/staging/vme/boards/vme_vmivme7805.h
rename to drivers/vme/boards/vme_vmivme7805.h
diff --git a/drivers/staging/vme/bridges/Kconfig b/drivers/vme/bridges/Kconfig
similarity index 100%
rename from drivers/staging/vme/bridges/Kconfig
rename to drivers/vme/bridges/Kconfig
diff --git a/drivers/staging/vme/bridges/Makefile b/drivers/vme/bridges/Makefile
similarity index 100%
rename from drivers/staging/vme/bridges/Makefile
rename to drivers/vme/bridges/Makefile
diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c
new file mode 100644
index 0000000..e0df92e
--- /dev/null
+++ b/drivers/vme/bridges/vme_ca91cx42.c
@@ -0,0 +1,1959 @@
+/*
+ * Support for the Tundra Universe I/II VME-PCI Bridge Chips
+ *
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * Based on work by Tom Armistead and Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * Derived from ca91c042.c by Michael Wyrick
+ *
+ * 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/mm.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/poll.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/vme.h>
+
+#include "../vme_bridge.h"
+#include "vme_ca91cx42.h"
+
+static int __init ca91cx42_init(void);
+static int ca91cx42_probe(struct pci_dev *, const struct pci_device_id *);
+static void ca91cx42_remove(struct pci_dev *);
+static void __exit ca91cx42_exit(void);
+
+/* Module parameters */
+static int geoid;
+
+static const char driver_name[] = "vme_ca91cx42";
+
+static DEFINE_PCI_DEVICE_TABLE(ca91cx42_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C142) },
+	{ },
+};
+
+static struct pci_driver ca91cx42_driver = {
+	.name = driver_name,
+	.id_table = ca91cx42_ids,
+	.probe = ca91cx42_probe,
+	.remove = ca91cx42_remove,
+};
+
+static u32 ca91cx42_DMA_irqhandler(struct ca91cx42_driver *bridge)
+{
+	wake_up(&bridge->dma_queue);
+
+	return CA91CX42_LINT_DMA;
+}
+
+static u32 ca91cx42_LM_irqhandler(struct ca91cx42_driver *bridge, u32 stat)
+{
+	int i;
+	u32 serviced = 0;
+
+	for (i = 0; i < 4; i++) {
+		if (stat & CA91CX42_LINT_LM[i]) {
+			/* We only enable interrupts if the callback is set */
+			bridge->lm_callback[i](i);
+			serviced |= CA91CX42_LINT_LM[i];
+		}
+	}
+
+	return serviced;
+}
+
+/* XXX This needs to be split into 4 queues */
+static u32 ca91cx42_MB_irqhandler(struct ca91cx42_driver *bridge, int mbox_mask)
+{
+	wake_up(&bridge->mbox_queue);
+
+	return CA91CX42_LINT_MBOX;
+}
+
+static u32 ca91cx42_IACK_irqhandler(struct ca91cx42_driver *bridge)
+{
+	wake_up(&bridge->iack_queue);
+
+	return CA91CX42_LINT_SW_IACK;
+}
+
+static u32 ca91cx42_VERR_irqhandler(struct vme_bridge *ca91cx42_bridge)
+{
+	int val;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	val = ioread32(bridge->base + DGCS);
+
+	if (!(val & 0x00000800)) {
+		dev_err(ca91cx42_bridge->parent, "ca91cx42_VERR_irqhandler DMA "
+			"Read Error DGCS=%08X\n", val);
+	}
+
+	return CA91CX42_LINT_VERR;
+}
+
+static u32 ca91cx42_LERR_irqhandler(struct vme_bridge *ca91cx42_bridge)
+{
+	int val;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	val = ioread32(bridge->base + DGCS);
+
+	if (!(val & 0x00000800))
+		dev_err(ca91cx42_bridge->parent, "ca91cx42_LERR_irqhandler DMA "
+			"Read Error DGCS=%08X\n", val);
+
+	return CA91CX42_LINT_LERR;
+}
+
+
+static u32 ca91cx42_VIRQ_irqhandler(struct vme_bridge *ca91cx42_bridge,
+	int stat)
+{
+	int vec, i, serviced = 0;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+
+	for (i = 7; i > 0; i--) {
+		if (stat & (1 << i)) {
+			vec = ioread32(bridge->base +
+				CA91CX42_V_STATID[i]) & 0xff;
+
+			vme_irq_handler(ca91cx42_bridge, i, vec);
+
+			serviced |= (1 << i);
+		}
+	}
+
+	return serviced;
+}
+
+static irqreturn_t ca91cx42_irqhandler(int irq, void *ptr)
+{
+	u32 stat, enable, serviced = 0;
+	struct vme_bridge *ca91cx42_bridge;
+	struct ca91cx42_driver *bridge;
+
+	ca91cx42_bridge = ptr;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	enable = ioread32(bridge->base + LINT_EN);
+	stat = ioread32(bridge->base + LINT_STAT);
+
+	/* Only look at unmasked interrupts */
+	stat &= enable;
+
+	if (unlikely(!stat))
+		return IRQ_NONE;
+
+	if (stat & CA91CX42_LINT_DMA)
+		serviced |= ca91cx42_DMA_irqhandler(bridge);
+	if (stat & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 |
+			CA91CX42_LINT_LM3))
+		serviced |= ca91cx42_LM_irqhandler(bridge, stat);
+	if (stat & CA91CX42_LINT_MBOX)
+		serviced |= ca91cx42_MB_irqhandler(bridge, stat);
+	if (stat & CA91CX42_LINT_SW_IACK)
+		serviced |= ca91cx42_IACK_irqhandler(bridge);
+	if (stat & CA91CX42_LINT_VERR)
+		serviced |= ca91cx42_VERR_irqhandler(ca91cx42_bridge);
+	if (stat & CA91CX42_LINT_LERR)
+		serviced |= ca91cx42_LERR_irqhandler(ca91cx42_bridge);
+	if (stat & (CA91CX42_LINT_VIRQ1 | CA91CX42_LINT_VIRQ2 |
+			CA91CX42_LINT_VIRQ3 | CA91CX42_LINT_VIRQ4 |
+			CA91CX42_LINT_VIRQ5 | CA91CX42_LINT_VIRQ6 |
+			CA91CX42_LINT_VIRQ7))
+		serviced |= ca91cx42_VIRQ_irqhandler(ca91cx42_bridge, stat);
+
+	/* Clear serviced interrupts */
+	iowrite32(serviced, bridge->base + LINT_STAT);
+
+	return IRQ_HANDLED;
+}
+
+static int ca91cx42_irq_init(struct vme_bridge *ca91cx42_bridge)
+{
+	int result, tmp;
+	struct pci_dev *pdev;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	/* Need pdev */
+	pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
+
+	/* Initialise list for VME bus errors */
+	INIT_LIST_HEAD(&ca91cx42_bridge->vme_errors);
+
+	mutex_init(&ca91cx42_bridge->irq_mtx);
+
+	/* Disable interrupts from PCI to VME */
+	iowrite32(0, bridge->base + VINT_EN);
+
+	/* Disable PCI interrupts */
+	iowrite32(0, bridge->base + LINT_EN);
+	/* Clear Any Pending PCI Interrupts */
+	iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
+
+	result = request_irq(pdev->irq, ca91cx42_irqhandler, IRQF_SHARED,
+			driver_name, ca91cx42_bridge);
+	if (result) {
+		dev_err(&pdev->dev, "Can't get assigned pci irq vector %02X\n",
+		       pdev->irq);
+		return result;
+	}
+
+	/* Ensure all interrupts are mapped to PCI Interrupt 0 */
+	iowrite32(0, bridge->base + LINT_MAP0);
+	iowrite32(0, bridge->base + LINT_MAP1);
+	iowrite32(0, bridge->base + LINT_MAP2);
+
+	/* Enable DMA, mailbox & LM Interrupts */
+	tmp = CA91CX42_LINT_MBOX3 | CA91CX42_LINT_MBOX2 | CA91CX42_LINT_MBOX1 |
+		CA91CX42_LINT_MBOX0 | CA91CX42_LINT_SW_IACK |
+		CA91CX42_LINT_VERR | CA91CX42_LINT_LERR | CA91CX42_LINT_DMA;
+
+	iowrite32(tmp, bridge->base + LINT_EN);
+
+	return 0;
+}
+
+static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge,
+	struct pci_dev *pdev)
+{
+	/* Disable interrupts from PCI to VME */
+	iowrite32(0, bridge->base + VINT_EN);
+
+	/* Disable PCI interrupts */
+	iowrite32(0, bridge->base + LINT_EN);
+	/* Clear Any Pending PCI Interrupts */
+	iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
+
+	free_irq(pdev->irq, pdev);
+}
+
+static int ca91cx42_iack_received(struct ca91cx42_driver *bridge, int level)
+{
+	u32 tmp;
+
+	tmp = ioread32(bridge->base + LINT_STAT);
+
+	if (tmp & (1 << level))
+		return 0;
+	else
+		return 1;
+}
+
+/*
+ * Set up an VME interrupt
+ */
+static void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level,
+	int state, int sync)
+
+{
+	struct pci_dev *pdev;
+	u32 tmp;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	/* Enable IRQ level */
+	tmp = ioread32(bridge->base + LINT_EN);
+
+	if (state == 0)
+		tmp &= ~CA91CX42_LINT_VIRQ[level];
+	else
+		tmp |= CA91CX42_LINT_VIRQ[level];
+
+	iowrite32(tmp, bridge->base + LINT_EN);
+
+	if ((state == 0) && (sync != 0)) {
+		pdev = container_of(ca91cx42_bridge->parent, struct pci_dev,
+			dev);
+
+		synchronize_irq(pdev->irq);
+	}
+}
+
+static int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level,
+	int statid)
+{
+	u32 tmp;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	/* Universe can only generate even vectors */
+	if (statid & 1)
+		return -EINVAL;
+
+	mutex_lock(&bridge->vme_int);
+
+	tmp = ioread32(bridge->base + VINT_EN);
+
+	/* Set Status/ID */
+	iowrite32(statid << 24, bridge->base + STATID);
+
+	/* Assert VMEbus IRQ */
+	tmp = tmp | (1 << (level + 24));
+	iowrite32(tmp, bridge->base + VINT_EN);
+
+	/* Wait for IACK */
+	wait_event_interruptible(bridge->iack_queue,
+				 ca91cx42_iack_received(bridge, level));
+
+	/* Return interrupt to low state */
+	tmp = ioread32(bridge->base + VINT_EN);
+	tmp = tmp & ~(1 << (level + 24));
+	iowrite32(tmp, bridge->base + VINT_EN);
+
+	mutex_unlock(&bridge->vme_int);
+
+	return 0;
+}
+
+static int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
+	unsigned long long vme_base, unsigned long long size,
+	dma_addr_t pci_base, u32 aspace, u32 cycle)
+{
+	unsigned int i, addr = 0, granularity;
+	unsigned int temp_ctl = 0;
+	unsigned int vme_bound, pci_offset;
+	struct vme_bridge *ca91cx42_bridge;
+	struct ca91cx42_driver *bridge;
+
+	ca91cx42_bridge = image->parent;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	i = image->number;
+
+	switch (aspace) {
+	case VME_A16:
+		addr |= CA91CX42_VSI_CTL_VAS_A16;
+		break;
+	case VME_A24:
+		addr |= CA91CX42_VSI_CTL_VAS_A24;
+		break;
+	case VME_A32:
+		addr |= CA91CX42_VSI_CTL_VAS_A32;
+		break;
+	case VME_USER1:
+		addr |= CA91CX42_VSI_CTL_VAS_USER1;
+		break;
+	case VME_USER2:
+		addr |= CA91CX42_VSI_CTL_VAS_USER2;
+		break;
+	case VME_A64:
+	case VME_CRCSR:
+	case VME_USER3:
+	case VME_USER4:
+	default:
+		dev_err(ca91cx42_bridge->parent, "Invalid address space\n");
+		return -EINVAL;
+		break;
+	}
+
+	/*
+	 * Bound address is a valid address for the window, adjust
+	 * accordingly
+	 */
+	vme_bound = vme_base + size;
+	pci_offset = pci_base - vme_base;
+
+	if ((i == 0) || (i == 4))
+		granularity = 0x1000;
+	else
+		granularity = 0x10000;
+
+	if (vme_base & (granularity - 1)) {
+		dev_err(ca91cx42_bridge->parent, "Invalid VME base "
+			"alignment\n");
+		return -EINVAL;
+	}
+	if (vme_bound & (granularity - 1)) {
+		dev_err(ca91cx42_bridge->parent, "Invalid VME bound "
+			"alignment\n");
+		return -EINVAL;
+	}
+	if (pci_offset & (granularity - 1)) {
+		dev_err(ca91cx42_bridge->parent, "Invalid PCI Offset "
+			"alignment\n");
+		return -EINVAL;
+	}
+
+	/* Disable while we are mucking around */
+	temp_ctl = ioread32(bridge->base + CA91CX42_VSI_CTL[i]);
+	temp_ctl &= ~CA91CX42_VSI_CTL_EN;
+	iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]);
+
+	/* Setup mapping */
+	iowrite32(vme_base, bridge->base + CA91CX42_VSI_BS[i]);
+	iowrite32(vme_bound, bridge->base + CA91CX42_VSI_BD[i]);
+	iowrite32(pci_offset, bridge->base + CA91CX42_VSI_TO[i]);
+
+	/* Setup address space */
+	temp_ctl &= ~CA91CX42_VSI_CTL_VAS_M;
+	temp_ctl |= addr;
+
+	/* Setup cycle types */
+	temp_ctl &= ~(CA91CX42_VSI_CTL_PGM_M | CA91CX42_VSI_CTL_SUPER_M);
+	if (cycle & VME_SUPER)
+		temp_ctl |= CA91CX42_VSI_CTL_SUPER_SUPR;
+	if (cycle & VME_USER)
+		temp_ctl |= CA91CX42_VSI_CTL_SUPER_NPRIV;
+	if (cycle & VME_PROG)
+		temp_ctl |= CA91CX42_VSI_CTL_PGM_PGM;
+	if (cycle & VME_DATA)
+		temp_ctl |= CA91CX42_VSI_CTL_PGM_DATA;
+
+	/* Write ctl reg without enable */
+	iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]);
+
+	if (enabled)
+		temp_ctl |= CA91CX42_VSI_CTL_EN;
+
+	iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]);
+
+	return 0;
+}
+
+static int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled,
+	unsigned long long *vme_base, unsigned long long *size,
+	dma_addr_t *pci_base, u32 *aspace, u32 *cycle)
+{
+	unsigned int i, granularity = 0, ctl = 0;
+	unsigned long long vme_bound, pci_offset;
+	struct ca91cx42_driver *bridge;
+
+	bridge = image->parent->driver_priv;
+
+	i = image->number;
+
+	if ((i == 0) || (i == 4))
+		granularity = 0x1000;
+	else
+		granularity = 0x10000;
+
+	/* Read Registers */
+	ctl = ioread32(bridge->base + CA91CX42_VSI_CTL[i]);
+
+	*vme_base = ioread32(bridge->base + CA91CX42_VSI_BS[i]);
+	vme_bound = ioread32(bridge->base + CA91CX42_VSI_BD[i]);
+	pci_offset = ioread32(bridge->base + CA91CX42_VSI_TO[i]);
+
+	*pci_base = (dma_addr_t)vme_base + pci_offset;
+	*size = (unsigned long long)((vme_bound - *vme_base) + granularity);
+
+	*enabled = 0;
+	*aspace = 0;
+	*cycle = 0;
+
+	if (ctl & CA91CX42_VSI_CTL_EN)
+		*enabled = 1;
+
+	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A16)
+		*aspace = VME_A16;
+	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A24)
+		*aspace = VME_A24;
+	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A32)
+		*aspace = VME_A32;
+	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_USER1)
+		*aspace = VME_USER1;
+	if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_USER2)
+		*aspace = VME_USER2;
+
+	if (ctl & CA91CX42_VSI_CTL_SUPER_SUPR)
+		*cycle |= VME_SUPER;
+	if (ctl & CA91CX42_VSI_CTL_SUPER_NPRIV)
+		*cycle |= VME_USER;
+	if (ctl & CA91CX42_VSI_CTL_PGM_PGM)
+		*cycle |= VME_PROG;
+	if (ctl & CA91CX42_VSI_CTL_PGM_DATA)
+		*cycle |= VME_DATA;
+
+	return 0;
+}
+
+/*
+ * Allocate and map PCI Resource
+ */
+static int ca91cx42_alloc_resource(struct vme_master_resource *image,
+	unsigned long long size)
+{
+	unsigned long long existing_size;
+	int retval = 0;
+	struct pci_dev *pdev;
+	struct vme_bridge *ca91cx42_bridge;
+
+	ca91cx42_bridge = image->parent;
+
+	/* Find pci_dev container of dev */
+	if (ca91cx42_bridge->parent == NULL) {
+		dev_err(ca91cx42_bridge->parent, "Dev entry NULL\n");
+		return -EINVAL;
+	}
+	pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
+
+	existing_size = (unsigned long long)(image->bus_resource.end -
+		image->bus_resource.start);
+
+	/* If the existing size is OK, return */
+	if (existing_size == (size - 1))
+		return 0;
+
+	if (existing_size != 0) {
+		iounmap(image->kern_base);
+		image->kern_base = NULL;
+		kfree(image->bus_resource.name);
+		release_resource(&image->bus_resource);
+		memset(&image->bus_resource, 0, sizeof(struct resource));
+	}
+
+	if (image->bus_resource.name == NULL) {
+		image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC);
+		if (image->bus_resource.name == NULL) {
+			dev_err(ca91cx42_bridge->parent, "Unable to allocate "
+				"memory for resource name\n");
+			retval = -ENOMEM;
+			goto err_name;
+		}
+	}
+
+	sprintf((char *)image->bus_resource.name, "%s.%d",
+		ca91cx42_bridge->name, image->number);
+
+	image->bus_resource.start = 0;
+	image->bus_resource.end = (unsigned long)size;
+	image->bus_resource.flags = IORESOURCE_MEM;
+
+	retval = pci_bus_alloc_resource(pdev->bus,
+		&image->bus_resource, size, size, PCIBIOS_MIN_MEM,
+		0, NULL, NULL);
+	if (retval) {
+		dev_err(ca91cx42_bridge->parent, "Failed to allocate mem "
+			"resource for window %d size 0x%lx start 0x%lx\n",
+			image->number, (unsigned long)size,
+			(unsigned long)image->bus_resource.start);
+		goto err_resource;
+	}
+
+	image->kern_base = ioremap_nocache(
+		image->bus_resource.start, size);
+	if (image->kern_base == NULL) {
+		dev_err(ca91cx42_bridge->parent, "Failed to remap resource\n");
+		retval = -ENOMEM;
+		goto err_remap;
+	}
+
+	return 0;
+
+err_remap:
+	release_resource(&image->bus_resource);
+err_resource:
+	kfree(image->bus_resource.name);
+	memset(&image->bus_resource, 0, sizeof(struct resource));
+err_name:
+	return retval;
+}
+
+/*
+ * Free and unmap PCI Resource
+ */
+static void ca91cx42_free_resource(struct vme_master_resource *image)
+{
+	iounmap(image->kern_base);
+	image->kern_base = NULL;
+	release_resource(&image->bus_resource);
+	kfree(image->bus_resource.name);
+	memset(&image->bus_resource, 0, sizeof(struct resource));
+}
+
+
+static int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
+	unsigned long long vme_base, unsigned long long size, u32 aspace,
+	u32 cycle, u32 dwidth)
+{
+	int retval = 0;
+	unsigned int i, granularity = 0;
+	unsigned int temp_ctl = 0;
+	unsigned long long pci_bound, vme_offset, pci_base;
+	struct vme_bridge *ca91cx42_bridge;
+	struct ca91cx42_driver *bridge;
+
+	ca91cx42_bridge = image->parent;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	i = image->number;
+
+	if ((i == 0) || (i == 4))
+		granularity = 0x1000;
+	else
+		granularity = 0x10000;
+
+	/* Verify input data */
+	if (vme_base & (granularity - 1)) {
+		dev_err(ca91cx42_bridge->parent, "Invalid VME Window "
+			"alignment\n");
+		retval = -EINVAL;
+		goto err_window;
+	}
+	if (size & (granularity - 1)) {
+		dev_err(ca91cx42_bridge->parent, "Invalid VME Window "
+			"alignment\n");
+		retval = -EINVAL;
+		goto err_window;
+	}
+
+	spin_lock(&image->lock);
+
+	/*
+	 * Let's allocate the resource here rather than further up the stack as
+	 * it avoids pushing loads of bus dependent stuff up the stack
+	 */
+	retval = ca91cx42_alloc_resource(image, size);
+	if (retval) {
+		spin_unlock(&image->lock);
+		dev_err(ca91cx42_bridge->parent, "Unable to allocate memory "
+			"for resource name\n");
+		retval = -ENOMEM;
+		goto err_res;
+	}
+
+	pci_base = (unsigned long long)image->bus_resource.start;
+
+	/*
+	 * Bound address is a valid address for the window, adjust
+	 * according to window granularity.
+	 */
+	pci_bound = pci_base + size;
+	vme_offset = vme_base - pci_base;
+
+	/* Disable while we are mucking around */
+	temp_ctl = ioread32(bridge->base + CA91CX42_LSI_CTL[i]);
+	temp_ctl &= ~CA91CX42_LSI_CTL_EN;
+	iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
+
+	/* Setup cycle types */
+	temp_ctl &= ~CA91CX42_LSI_CTL_VCT_M;
+	if (cycle & VME_BLT)
+		temp_ctl |= CA91CX42_LSI_CTL_VCT_BLT;
+	if (cycle & VME_MBLT)
+		temp_ctl |= CA91CX42_LSI_CTL_VCT_MBLT;
+
+	/* Setup data width */
+	temp_ctl &= ~CA91CX42_LSI_CTL_VDW_M;
+	switch (dwidth) {
+	case VME_D8:
+		temp_ctl |= CA91CX42_LSI_CTL_VDW_D8;
+		break;
+	case VME_D16:
+		temp_ctl |= CA91CX42_LSI_CTL_VDW_D16;
+		break;
+	case VME_D32:
+		temp_ctl |= CA91CX42_LSI_CTL_VDW_D32;
+		break;
+	case VME_D64:
+		temp_ctl |= CA91CX42_LSI_CTL_VDW_D64;
+		break;
+	default:
+		spin_unlock(&image->lock);
+		dev_err(ca91cx42_bridge->parent, "Invalid data width\n");
+		retval = -EINVAL;
+		goto err_dwidth;
+		break;
+	}
+
+	/* Setup address space */
+	temp_ctl &= ~CA91CX42_LSI_CTL_VAS_M;
+	switch (aspace) {
+	case VME_A16:
+		temp_ctl |= CA91CX42_LSI_CTL_VAS_A16;
+		break;
+	case VME_A24:
+		temp_ctl |= CA91CX42_LSI_CTL_VAS_A24;
+		break;
+	case VME_A32:
+		temp_ctl |= CA91CX42_LSI_CTL_VAS_A32;
+		break;
+	case VME_CRCSR:
+		temp_ctl |= CA91CX42_LSI_CTL_VAS_CRCSR;
+		break;
+	case VME_USER1:
+		temp_ctl |= CA91CX42_LSI_CTL_VAS_USER1;
+		break;
+	case VME_USER2:
+		temp_ctl |= CA91CX42_LSI_CTL_VAS_USER2;
+		break;
+	case VME_A64:
+	case VME_USER3:
+	case VME_USER4:
+	default:
+		spin_unlock(&image->lock);
+		dev_err(ca91cx42_bridge->parent, "Invalid address space\n");
+		retval = -EINVAL;
+		goto err_aspace;
+		break;
+	}
+
+	temp_ctl &= ~(CA91CX42_LSI_CTL_PGM_M | CA91CX42_LSI_CTL_SUPER_M);
+	if (cycle & VME_SUPER)
+		temp_ctl |= CA91CX42_LSI_CTL_SUPER_SUPR;
+	if (cycle & VME_PROG)
+		temp_ctl |= CA91CX42_LSI_CTL_PGM_PGM;
+
+	/* Setup mapping */
+	iowrite32(pci_base, bridge->base + CA91CX42_LSI_BS[i]);
+	iowrite32(pci_bound, bridge->base + CA91CX42_LSI_BD[i]);
+	iowrite32(vme_offset, bridge->base + CA91CX42_LSI_TO[i]);
+
+	/* Write ctl reg without enable */
+	iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
+
+	if (enabled)
+		temp_ctl |= CA91CX42_LSI_CTL_EN;
+
+	iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
+
+	spin_unlock(&image->lock);
+	return 0;
+
+err_aspace:
+err_dwidth:
+	ca91cx42_free_resource(image);
+err_res:
+err_window:
+	return retval;
+}
+
+static int __ca91cx42_master_get(struct vme_master_resource *image,
+	int *enabled, unsigned long long *vme_base, unsigned long long *size,
+	u32 *aspace, u32 *cycle, u32 *dwidth)
+{
+	unsigned int i, ctl;
+	unsigned long long pci_base, pci_bound, vme_offset;
+	struct ca91cx42_driver *bridge;
+
+	bridge = image->parent->driver_priv;
+
+	i = image->number;
+
+	ctl = ioread32(bridge->base + CA91CX42_LSI_CTL[i]);
+
+	pci_base = ioread32(bridge->base + CA91CX42_LSI_BS[i]);
+	vme_offset = ioread32(bridge->base + CA91CX42_LSI_TO[i]);
+	pci_bound = ioread32(bridge->base + CA91CX42_LSI_BD[i]);
+
+	*vme_base = pci_base + vme_offset;
+	*size = (unsigned long long)(pci_bound - pci_base);
+
+	*enabled = 0;
+	*aspace = 0;
+	*cycle = 0;
+	*dwidth = 0;
+
+	if (ctl & CA91CX42_LSI_CTL_EN)
+		*enabled = 1;
+
+	/* Setup address space */
+	switch (ctl & CA91CX42_LSI_CTL_VAS_M) {
+	case CA91CX42_LSI_CTL_VAS_A16:
+		*aspace = VME_A16;
+		break;
+	case CA91CX42_LSI_CTL_VAS_A24:
+		*aspace = VME_A24;
+		break;
+	case CA91CX42_LSI_CTL_VAS_A32:
+		*aspace = VME_A32;
+		break;
+	case CA91CX42_LSI_CTL_VAS_CRCSR:
+		*aspace = VME_CRCSR;
+		break;
+	case CA91CX42_LSI_CTL_VAS_USER1:
+		*aspace = VME_USER1;
+		break;
+	case CA91CX42_LSI_CTL_VAS_USER2:
+		*aspace = VME_USER2;
+		break;
+	}
+
+	/* XXX Not sure howto check for MBLT */
+	/* Setup cycle types */
+	if (ctl & CA91CX42_LSI_CTL_VCT_BLT)
+		*cycle |= VME_BLT;
+	else
+		*cycle |= VME_SCT;
+
+	if (ctl & CA91CX42_LSI_CTL_SUPER_SUPR)
+		*cycle |= VME_SUPER;
+	else
+		*cycle |= VME_USER;
+
+	if (ctl & CA91CX42_LSI_CTL_PGM_PGM)
+		*cycle = VME_PROG;
+	else
+		*cycle = VME_DATA;
+
+	/* Setup data width */
+	switch (ctl & CA91CX42_LSI_CTL_VDW_M) {
+	case CA91CX42_LSI_CTL_VDW_D8:
+		*dwidth = VME_D8;
+		break;
+	case CA91CX42_LSI_CTL_VDW_D16:
+		*dwidth = VME_D16;
+		break;
+	case CA91CX42_LSI_CTL_VDW_D32:
+		*dwidth = VME_D32;
+		break;
+	case CA91CX42_LSI_CTL_VDW_D64:
+		*dwidth = VME_D64;
+		break;
+	}
+
+	return 0;
+}
+
+static int ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
+	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
+	u32 *cycle, u32 *dwidth)
+{
+	int retval;
+
+	spin_lock(&image->lock);
+
+	retval = __ca91cx42_master_get(image, enabled, vme_base, size, aspace,
+		cycle, dwidth);
+
+	spin_unlock(&image->lock);
+
+	return retval;
+}
+
+static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
+	void *buf, size_t count, loff_t offset)
+{
+	ssize_t retval;
+	void *addr = image->kern_base + offset;
+	unsigned int done = 0;
+	unsigned int count32;
+
+	if (count == 0)
+		return 0;
+
+	spin_lock(&image->lock);
+
+	/* The following code handles VME address alignment problem
+	 * in order to assure the maximal data width cycle.
+	 * We cannot use memcpy_xxx directly here because it
+	 * may cut data transfer in 8-bits cycles, thus making
+	 * D16 cycle impossible.
+	 * From the other hand, the bridge itself assures that
+	 * maximal configured data cycle is used and splits it
+	 * automatically for non-aligned addresses.
+	 */
+	if ((uintptr_t)addr & 0x1) {
+		*(u8 *)buf = ioread8(addr);
+		done += 1;
+		if (done == count)
+			goto out;
+	}
+	if ((uintptr_t)addr & 0x2) {
+		if ((count - done) < 2) {
+			*(u8 *)(buf + done) = ioread8(addr + done);
+			done += 1;
+			goto out;
+		} else {
+			*(u16 *)(buf + done) = ioread16(addr + done);
+			done += 2;
+		}
+	}
+
+	count32 = (count - done) & ~0x3;
+	if (count32 > 0) {
+		memcpy_fromio(buf + done, addr + done, (unsigned int)count);
+		done += count32;
+	}
+
+	if ((count - done) & 0x2) {
+		*(u16 *)(buf + done) = ioread16(addr + done);
+		done += 2;
+	}
+	if ((count - done) & 0x1) {
+		*(u8 *)(buf + done) = ioread8(addr + done);
+		done += 1;
+	}
+out:
+	retval = count;
+	spin_unlock(&image->lock);
+
+	return retval;
+}
+
+static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
+	void *buf, size_t count, loff_t offset)
+{
+	ssize_t retval;
+	void *addr = image->kern_base + offset;
+	unsigned int done = 0;
+	unsigned int count32;
+
+	if (count == 0)
+		return 0;
+
+	spin_lock(&image->lock);
+
+	/* Here we apply for the same strategy we do in master_read
+	 * function in order to assure D16 cycle when required.
+	 */
+	if ((uintptr_t)addr & 0x1) {
+		iowrite8(*(u8 *)buf, addr);
+		done += 1;
+		if (done == count)
+			goto out;
+	}
+	if ((uintptr_t)addr & 0x2) {
+		if ((count - done) < 2) {
+			iowrite8(*(u8 *)(buf + done), addr + done);
+			done += 1;
+			goto out;
+		} else {
+			iowrite16(*(u16 *)(buf + done), addr + done);
+			done += 2;
+		}
+	}
+
+	count32 = (count - done) & ~0x3;
+	if (count32 > 0) {
+		memcpy_toio(addr + done, buf + done, count32);
+		done += count32;
+	}
+
+	if ((count - done) & 0x2) {
+		iowrite16(*(u16 *)(buf + done), addr + done);
+		done += 2;
+	}
+	if ((count - done) & 0x1) {
+		iowrite8(*(u8 *)(buf + done), addr + done);
+		done += 1;
+	}
+out:
+	retval = count;
+
+	spin_unlock(&image->lock);
+
+	return retval;
+}
+
+static unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
+	unsigned int mask, unsigned int compare, unsigned int swap,
+	loff_t offset)
+{
+	u32 result;
+	uintptr_t pci_addr;
+	int i;
+	struct ca91cx42_driver *bridge;
+	struct device *dev;
+
+	bridge = image->parent->driver_priv;
+	dev = image->parent->parent;
+
+	/* Find the PCI address that maps to the desired VME address */
+	i = image->number;
+
+	/* Locking as we can only do one of these at a time */
+	mutex_lock(&bridge->vme_rmw);
+
+	/* Lock image */
+	spin_lock(&image->lock);
+
+	pci_addr = (uintptr_t)image->kern_base + offset;
+
+	/* Address must be 4-byte aligned */
+	if (pci_addr & 0x3) {
+		dev_err(dev, "RMW Address not 4-byte aligned\n");
+		result = -EINVAL;
+		goto out;
+	}
+
+	/* Ensure RMW Disabled whilst configuring */
+	iowrite32(0, bridge->base + SCYC_CTL);
+
+	/* Configure registers */
+	iowrite32(mask, bridge->base + SCYC_EN);
+	iowrite32(compare, bridge->base + SCYC_CMP);
+	iowrite32(swap, bridge->base + SCYC_SWP);
+	iowrite32(pci_addr, bridge->base + SCYC_ADDR);
+
+	/* Enable RMW */
+	iowrite32(CA91CX42_SCYC_CTL_CYC_RMW, bridge->base + SCYC_CTL);
+
+	/* Kick process off with a read to the required address. */
+	result = ioread32(image->kern_base + offset);
+
+	/* Disable RMW */
+	iowrite32(0, bridge->base + SCYC_CTL);
+
+out:
+	spin_unlock(&image->lock);
+
+	mutex_unlock(&bridge->vme_rmw);
+
+	return result;
+}
+
+static int ca91cx42_dma_list_add(struct vme_dma_list *list,
+	struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
+{
+	struct ca91cx42_dma_entry *entry, *prev;
+	struct vme_dma_pci *pci_attr;
+	struct vme_dma_vme *vme_attr;
+	dma_addr_t desc_ptr;
+	int retval = 0;
+	struct device *dev;
+
+	dev = list->parent->parent->parent;
+
+	/* XXX descriptor must be aligned on 64-bit boundaries */
+	entry = kmalloc(sizeof(struct ca91cx42_dma_entry), GFP_KERNEL);
+	if (entry == NULL) {
+		dev_err(dev, "Failed to allocate memory for dma resource "
+			"structure\n");
+		retval = -ENOMEM;
+		goto err_mem;
+	}
+
+	/* Test descriptor alignment */
+	if ((unsigned long)&entry->descriptor & CA91CX42_DCPP_M) {
+		dev_err(dev, "Descriptor not aligned to 16 byte boundary as "
+			"required: %p\n", &entry->descriptor);
+		retval = -EINVAL;
+		goto err_align;
+	}
+
+	memset(&entry->descriptor, 0, sizeof(struct ca91cx42_dma_descriptor));
+
+	if (dest->type == VME_DMA_VME) {
+		entry->descriptor.dctl |= CA91CX42_DCTL_L2V;
+		vme_attr = dest->private;
+		pci_attr = src->private;
+	} else {
+		vme_attr = src->private;
+		pci_attr = dest->private;
+	}
+
+	/* Check we can do fulfill required attributes */
+	if ((vme_attr->aspace & ~(VME_A16 | VME_A24 | VME_A32 | VME_USER1 |
+		VME_USER2)) != 0) {
+
+		dev_err(dev, "Unsupported cycle type\n");
+		retval = -EINVAL;
+		goto err_aspace;
+	}
+
+	if ((vme_attr->cycle & ~(VME_SCT | VME_BLT | VME_SUPER | VME_USER |
+		VME_PROG | VME_DATA)) != 0) {
+
+		dev_err(dev, "Unsupported cycle type\n");
+		retval = -EINVAL;
+		goto err_cycle;
+	}
+
+	/* Check to see if we can fulfill source and destination */
+	if (!(((src->type == VME_DMA_PCI) && (dest->type == VME_DMA_VME)) ||
+		((src->type == VME_DMA_VME) && (dest->type == VME_DMA_PCI)))) {
+
+		dev_err(dev, "Cannot perform transfer with this "
+			"source-destination combination\n");
+		retval = -EINVAL;
+		goto err_direct;
+	}
+
+	/* Setup cycle types */
+	if (vme_attr->cycle & VME_BLT)
+		entry->descriptor.dctl |= CA91CX42_DCTL_VCT_BLT;
+
+	/* Setup data width */
+	switch (vme_attr->dwidth) {
+	case VME_D8:
+		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D8;
+		break;
+	case VME_D16:
+		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D16;
+		break;
+	case VME_D32:
+		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D32;
+		break;
+	case VME_D64:
+		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D64;
+		break;
+	default:
+		dev_err(dev, "Invalid data width\n");
+		return -EINVAL;
+	}
+
+	/* Setup address space */
+	switch (vme_attr->aspace) {
+	case VME_A16:
+		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A16;
+		break;
+	case VME_A24:
+		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A24;
+		break;
+	case VME_A32:
+		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A32;
+		break;
+	case VME_USER1:
+		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER1;
+		break;
+	case VME_USER2:
+		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER2;
+		break;
+	default:
+		dev_err(dev, "Invalid address space\n");
+		return -EINVAL;
+		break;
+	}
+
+	if (vme_attr->cycle & VME_SUPER)
+		entry->descriptor.dctl |= CA91CX42_DCTL_SUPER_SUPR;
+	if (vme_attr->cycle & VME_PROG)
+		entry->descriptor.dctl |= CA91CX42_DCTL_PGM_PGM;
+
+	entry->descriptor.dtbc = count;
+	entry->descriptor.dla = pci_attr->address;
+	entry->descriptor.dva = vme_attr->address;
+	entry->descriptor.dcpp = CA91CX42_DCPP_NULL;
+
+	/* Add to list */
+	list_add_tail(&entry->list, &list->entries);
+
+	/* Fill out previous descriptors "Next Address" */
+	if (entry->list.prev != &list->entries) {
+		prev = list_entry(entry->list.prev, struct ca91cx42_dma_entry,
+			list);
+		/* We need the bus address for the pointer */
+		desc_ptr = virt_to_bus(&entry->descriptor);
+		prev->descriptor.dcpp = desc_ptr & ~CA91CX42_DCPP_M;
+	}
+
+	return 0;
+
+err_cycle:
+err_aspace:
+err_direct:
+err_align:
+	kfree(entry);
+err_mem:
+	return retval;
+}
+
+static int ca91cx42_dma_busy(struct vme_bridge *ca91cx42_bridge)
+{
+	u32 tmp;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	tmp = ioread32(bridge->base + DGCS);
+
+	if (tmp & CA91CX42_DGCS_ACT)
+		return 0;
+	else
+		return 1;
+}
+
+static int ca91cx42_dma_list_exec(struct vme_dma_list *list)
+{
+	struct vme_dma_resource *ctrlr;
+	struct ca91cx42_dma_entry *entry;
+	int retval = 0;
+	dma_addr_t bus_addr;
+	u32 val;
+	struct device *dev;
+	struct ca91cx42_driver *bridge;
+
+	ctrlr = list->parent;
+
+	bridge = ctrlr->parent->driver_priv;
+	dev = ctrlr->parent->parent;
+
+	mutex_lock(&ctrlr->mtx);
+
+	if (!(list_empty(&ctrlr->running))) {
+		/*
+		 * XXX We have an active DMA transfer and currently haven't
+		 *     sorted out the mechanism for "pending" DMA transfers.
+		 *     Return busy.
+		 */
+		/* Need to add to pending here */
+		mutex_unlock(&ctrlr->mtx);
+		return -EBUSY;
+	} else {
+		list_add(&list->list, &ctrlr->running);
+	}
+
+	/* Get first bus address and write into registers */
+	entry = list_first_entry(&list->entries, struct ca91cx42_dma_entry,
+		list);
+
+	bus_addr = virt_to_bus(&entry->descriptor);
+
+	mutex_unlock(&ctrlr->mtx);
+
+	iowrite32(0, bridge->base + DTBC);
+	iowrite32(bus_addr & ~CA91CX42_DCPP_M, bridge->base + DCPP);
+
+	/* Start the operation */
+	val = ioread32(bridge->base + DGCS);
+
+	/* XXX Could set VMEbus On and Off Counters here */
+	val &= (CA91CX42_DGCS_VON_M | CA91CX42_DGCS_VOFF_M);
+
+	val |= (CA91CX42_DGCS_CHAIN | CA91CX42_DGCS_STOP | CA91CX42_DGCS_HALT |
+		CA91CX42_DGCS_DONE | CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR |
+		CA91CX42_DGCS_PERR);
+
+	iowrite32(val, bridge->base + DGCS);
+
+	val |= CA91CX42_DGCS_GO;
+
+	iowrite32(val, bridge->base + DGCS);
+
+	wait_event_interruptible(bridge->dma_queue,
+		ca91cx42_dma_busy(ctrlr->parent));
+
+	/*
+	 * Read status register, this register is valid until we kick off a
+	 * new transfer.
+	 */
+	val = ioread32(bridge->base + DGCS);
+
+	if (val & (CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR |
+		CA91CX42_DGCS_PERR)) {
+
+		dev_err(dev, "ca91c042: DMA Error. DGCS=%08X\n", val);
+		val = ioread32(bridge->base + DCTL);
+	}
+
+	/* Remove list from running list */
+	mutex_lock(&ctrlr->mtx);
+	list_del(&list->list);
+	mutex_unlock(&ctrlr->mtx);
+
+	return retval;
+
+}
+
+static int ca91cx42_dma_list_empty(struct vme_dma_list *list)
+{
+	struct list_head *pos, *temp;
+	struct ca91cx42_dma_entry *entry;
+
+	/* detach and free each entry */
+	list_for_each_safe(pos, temp, &list->entries) {
+		list_del(pos);
+		entry = list_entry(pos, struct ca91cx42_dma_entry, list);
+		kfree(entry);
+	}
+
+	return 0;
+}
+
+/*
+ * All 4 location monitors reside at the same base - this is therefore a
+ * system wide configuration.
+ *
+ * This does not enable the LM monitor - that should be done when the first
+ * callback is attached and disabled when the last callback is removed.
+ */
+static int ca91cx42_lm_set(struct vme_lm_resource *lm,
+	unsigned long long lm_base, u32 aspace, u32 cycle)
+{
+	u32 temp_base, lm_ctl = 0;
+	int i;
+	struct ca91cx42_driver *bridge;
+	struct device *dev;
+
+	bridge = lm->parent->driver_priv;
+	dev = lm->parent->parent;
+
+	/* Check the alignment of the location monitor */
+	temp_base = (u32)lm_base;
+	if (temp_base & 0xffff) {
+		dev_err(dev, "Location monitor must be aligned to 64KB "
+			"boundary");
+		return -EINVAL;
+	}
+
+	mutex_lock(&lm->mtx);
+
+	/* If we already have a callback attached, we can't move it! */
+	for (i = 0; i < lm->monitors; i++) {
+		if (bridge->lm_callback[i] != NULL) {
+			mutex_unlock(&lm->mtx);
+			dev_err(dev, "Location monitor callback attached, "
+				"can't reset\n");
+			return -EBUSY;
+		}
+	}
+
+	switch (aspace) {
+	case VME_A16:
+		lm_ctl |= CA91CX42_LM_CTL_AS_A16;
+		break;
+	case VME_A24:
+		lm_ctl |= CA91CX42_LM_CTL_AS_A24;
+		break;
+	case VME_A32:
+		lm_ctl |= CA91CX42_LM_CTL_AS_A32;
+		break;
+	default:
+		mutex_unlock(&lm->mtx);
+		dev_err(dev, "Invalid address space\n");
+		return -EINVAL;
+		break;
+	}
+
+	if (cycle & VME_SUPER)
+		lm_ctl |= CA91CX42_LM_CTL_SUPR;
+	if (cycle & VME_USER)
+		lm_ctl |= CA91CX42_LM_CTL_NPRIV;
+	if (cycle & VME_PROG)
+		lm_ctl |= CA91CX42_LM_CTL_PGM;
+	if (cycle & VME_DATA)
+		lm_ctl |= CA91CX42_LM_CTL_DATA;
+
+	iowrite32(lm_base, bridge->base + LM_BS);
+	iowrite32(lm_ctl, bridge->base + LM_CTL);
+
+	mutex_unlock(&lm->mtx);
+
+	return 0;
+}
+
+/* Get configuration of the callback monitor and return whether it is enabled
+ * or disabled.
+ */
+static int ca91cx42_lm_get(struct vme_lm_resource *lm,
+	unsigned long long *lm_base, u32 *aspace, u32 *cycle)
+{
+	u32 lm_ctl, enabled = 0;
+	struct ca91cx42_driver *bridge;
+
+	bridge = lm->parent->driver_priv;
+
+	mutex_lock(&lm->mtx);
+
+	*lm_base = (unsigned long long)ioread32(bridge->base + LM_BS);
+	lm_ctl = ioread32(bridge->base + LM_CTL);
+
+	if (lm_ctl & CA91CX42_LM_CTL_EN)
+		enabled = 1;
+
+	if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A16)
+		*aspace = VME_A16;
+	if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A24)
+		*aspace = VME_A24;
+	if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A32)
+		*aspace = VME_A32;
+
+	*cycle = 0;
+	if (lm_ctl & CA91CX42_LM_CTL_SUPR)
+		*cycle |= VME_SUPER;
+	if (lm_ctl & CA91CX42_LM_CTL_NPRIV)
+		*cycle |= VME_USER;
+	if (lm_ctl & CA91CX42_LM_CTL_PGM)
+		*cycle |= VME_PROG;
+	if (lm_ctl & CA91CX42_LM_CTL_DATA)
+		*cycle |= VME_DATA;
+
+	mutex_unlock(&lm->mtx);
+
+	return enabled;
+}
+
+/*
+ * Attach a callback to a specific location monitor.
+ *
+ * Callback will be passed the monitor triggered.
+ */
+static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
+	void (*callback)(int))
+{
+	u32 lm_ctl, tmp;
+	struct ca91cx42_driver *bridge;
+	struct device *dev;
+
+	bridge = lm->parent->driver_priv;
+	dev = lm->parent->parent;
+
+	mutex_lock(&lm->mtx);
+
+	/* Ensure that the location monitor is configured - need PGM or DATA */
+	lm_ctl = ioread32(bridge->base + LM_CTL);
+	if ((lm_ctl & (CA91CX42_LM_CTL_PGM | CA91CX42_LM_CTL_DATA)) == 0) {
+		mutex_unlock(&lm->mtx);
+		dev_err(dev, "Location monitor not properly configured\n");
+		return -EINVAL;
+	}
+
+	/* Check that a callback isn't already attached */
+	if (bridge->lm_callback[monitor] != NULL) {
+		mutex_unlock(&lm->mtx);
+		dev_err(dev, "Existing callback attached\n");
+		return -EBUSY;
+	}
+
+	/* Attach callback */
+	bridge->lm_callback[monitor] = callback;
+
+	/* Enable Location Monitor interrupt */
+	tmp = ioread32(bridge->base + LINT_EN);
+	tmp |= CA91CX42_LINT_LM[monitor];
+	iowrite32(tmp, bridge->base + LINT_EN);
+
+	/* Ensure that global Location Monitor Enable set */
+	if ((lm_ctl & CA91CX42_LM_CTL_EN) == 0) {
+		lm_ctl |= CA91CX42_LM_CTL_EN;
+		iowrite32(lm_ctl, bridge->base + LM_CTL);
+	}
+
+	mutex_unlock(&lm->mtx);
+
+	return 0;
+}
+
+/*
+ * Detach a callback function forn a specific location monitor.
+ */
+static int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor)
+{
+	u32 tmp;
+	struct ca91cx42_driver *bridge;
+
+	bridge = lm->parent->driver_priv;
+
+	mutex_lock(&lm->mtx);
+
+	/* Disable Location Monitor and ensure previous interrupts are clear */
+	tmp = ioread32(bridge->base + LINT_EN);
+	tmp &= ~CA91CX42_LINT_LM[monitor];
+	iowrite32(tmp, bridge->base + LINT_EN);
+
+	iowrite32(CA91CX42_LINT_LM[monitor],
+		 bridge->base + LINT_STAT);
+
+	/* Detach callback */
+	bridge->lm_callback[monitor] = NULL;
+
+	/* If all location monitors disabled, disable global Location Monitor */
+	if ((tmp & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 |
+			CA91CX42_LINT_LM3)) == 0) {
+		tmp = ioread32(bridge->base + LM_CTL);
+		tmp &= ~CA91CX42_LM_CTL_EN;
+		iowrite32(tmp, bridge->base + LM_CTL);
+	}
+
+	mutex_unlock(&lm->mtx);
+
+	return 0;
+}
+
+static int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge)
+{
+	u32 slot = 0;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	if (!geoid) {
+		slot = ioread32(bridge->base + VCSR_BS);
+		slot = ((slot & CA91CX42_VCSR_BS_SLOT_M) >> 27);
+	} else
+		slot = geoid;
+
+	return (int)slot;
+
+}
+
+static void *ca91cx42_alloc_consistent(struct device *parent, size_t size,
+	dma_addr_t *dma)
+{
+	struct pci_dev *pdev;
+
+	/* Find pci_dev container of dev */
+	pdev = container_of(parent, struct pci_dev, dev);
+
+	return pci_alloc_consistent(pdev, size, dma);
+}
+
+static void ca91cx42_free_consistent(struct device *parent, size_t size,
+	void *vaddr, dma_addr_t dma)
+{
+	struct pci_dev *pdev;
+
+	/* Find pci_dev container of dev */
+	pdev = container_of(parent, struct pci_dev, dev);
+
+	pci_free_consistent(pdev, size, vaddr, dma);
+}
+
+static int __init ca91cx42_init(void)
+{
+	return pci_register_driver(&ca91cx42_driver);
+}
+
+/*
+ * Configure CR/CSR space
+ *
+ * Access to the CR/CSR can be configured at power-up. The location of the
+ * CR/CSR registers in the CR/CSR address space is determined by the boards
+ * Auto-ID or Geographic address. This function ensures that the window is
+ * enabled at an offset consistent with the boards geopgraphic address.
+ */
+static int ca91cx42_crcsr_init(struct vme_bridge *ca91cx42_bridge,
+	struct pci_dev *pdev)
+{
+	unsigned int crcsr_addr;
+	int tmp, slot;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	slot = ca91cx42_slot_get(ca91cx42_bridge);
+
+	/* Write CSR Base Address if slot ID is supplied as a module param */
+	if (geoid)
+		iowrite32(geoid << 27, bridge->base + VCSR_BS);
+
+	dev_info(&pdev->dev, "CR/CSR Offset: %d\n", slot);
+	if (slot == 0) {
+		dev_err(&pdev->dev, "Slot number is unset, not configuring "
+			"CR/CSR space\n");
+		return -EINVAL;
+	}
+
+	/* Allocate mem for CR/CSR image */
+	bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
+		&bridge->crcsr_bus);
+	if (bridge->crcsr_kernel == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR "
+			"image\n");
+		return -ENOMEM;
+	}
+
+	memset(bridge->crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
+
+	crcsr_addr = slot * (512 * 1024);
+	iowrite32(bridge->crcsr_bus - crcsr_addr, bridge->base + VCSR_TO);
+
+	tmp = ioread32(bridge->base + VCSR_CTL);
+	tmp |= CA91CX42_VCSR_CTL_EN;
+	iowrite32(tmp, bridge->base + VCSR_CTL);
+
+	return 0;
+}
+
+static void ca91cx42_crcsr_exit(struct vme_bridge *ca91cx42_bridge,
+	struct pci_dev *pdev)
+{
+	u32 tmp;
+	struct ca91cx42_driver *bridge;
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+	/* Turn off CR/CSR space */
+	tmp = ioread32(bridge->base + VCSR_CTL);
+	tmp &= ~CA91CX42_VCSR_CTL_EN;
+	iowrite32(tmp, bridge->base + VCSR_CTL);
+
+	/* Free image */
+	iowrite32(0, bridge->base + VCSR_TO);
+
+	pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, bridge->crcsr_kernel,
+		bridge->crcsr_bus);
+}
+
+static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int retval, i;
+	u32 data;
+	struct list_head *pos = NULL;
+	struct vme_bridge *ca91cx42_bridge;
+	struct ca91cx42_driver *ca91cx42_device;
+	struct vme_master_resource *master_image;
+	struct vme_slave_resource *slave_image;
+	struct vme_dma_resource *dma_ctrlr;
+	struct vme_lm_resource *lm;
+
+	/* We want to support more than one of each bridge so we need to
+	 * dynamically allocate the bridge structure
+	 */
+	ca91cx42_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL);
+
+	if (ca91cx42_bridge == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate memory for device "
+			"structure\n");
+		retval = -ENOMEM;
+		goto err_struct;
+	}
+
+	ca91cx42_device = kzalloc(sizeof(struct ca91cx42_driver), GFP_KERNEL);
+
+	if (ca91cx42_device == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate memory for device "
+			"structure\n");
+		retval = -ENOMEM;
+		goto err_driver;
+	}
+
+	ca91cx42_bridge->driver_priv = ca91cx42_device;
+
+	/* Enable the device */
+	retval = pci_enable_device(pdev);
+	if (retval) {
+		dev_err(&pdev->dev, "Unable to enable device\n");
+		goto err_enable;
+	}
+
+	/* Map Registers */
+	retval = pci_request_regions(pdev, driver_name);
+	if (retval) {
+		dev_err(&pdev->dev, "Unable to reserve resources\n");
+		goto err_resource;
+	}
+
+	/* map registers in BAR 0 */
+	ca91cx42_device->base = ioremap_nocache(pci_resource_start(pdev, 0),
+		4096);
+	if (!ca91cx42_device->base) {
+		dev_err(&pdev->dev, "Unable to remap CRG region\n");
+		retval = -EIO;
+		goto err_remap;
+	}
+
+	/* Check to see if the mapping worked out */
+	data = ioread32(ca91cx42_device->base + CA91CX42_PCI_ID) & 0x0000FFFF;
+	if (data != PCI_VENDOR_ID_TUNDRA) {
+		dev_err(&pdev->dev, "PCI_ID check failed\n");
+		retval = -EIO;
+		goto err_test;
+	}
+
+	/* Initialize wait queues & mutual exclusion flags */
+	init_waitqueue_head(&ca91cx42_device->dma_queue);
+	init_waitqueue_head(&ca91cx42_device->iack_queue);
+	mutex_init(&ca91cx42_device->vme_int);
+	mutex_init(&ca91cx42_device->vme_rmw);
+
+	ca91cx42_bridge->parent = &pdev->dev;
+	strcpy(ca91cx42_bridge->name, driver_name);
+
+	/* Setup IRQ */
+	retval = ca91cx42_irq_init(ca91cx42_bridge);
+	if (retval != 0) {
+		dev_err(&pdev->dev, "Chip Initialization failed.\n");
+		goto err_irq;
+	}
+
+	/* Add master windows to list */
+	INIT_LIST_HEAD(&ca91cx42_bridge->master_resources);
+	for (i = 0; i < CA91C142_MAX_MASTER; i++) {
+		master_image = kmalloc(sizeof(struct vme_master_resource),
+			GFP_KERNEL);
+		if (master_image == NULL) {
+			dev_err(&pdev->dev, "Failed to allocate memory for "
+			"master resource structure\n");
+			retval = -ENOMEM;
+			goto err_master;
+		}
+		master_image->parent = ca91cx42_bridge;
+		spin_lock_init(&master_image->lock);
+		master_image->locked = 0;
+		master_image->number = i;
+		master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
+			VME_CRCSR | VME_USER1 | VME_USER2;
+		master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+			VME_SUPER | VME_USER | VME_PROG | VME_DATA;
+		master_image->width_attr = VME_D8 | VME_D16 | VME_D32 | VME_D64;
+		memset(&master_image->bus_resource, 0,
+			sizeof(struct resource));
+		master_image->kern_base  = NULL;
+		list_add_tail(&master_image->list,
+			&ca91cx42_bridge->master_resources);
+	}
+
+	/* Add slave windows to list */
+	INIT_LIST_HEAD(&ca91cx42_bridge->slave_resources);
+	for (i = 0; i < CA91C142_MAX_SLAVE; i++) {
+		slave_image = kmalloc(sizeof(struct vme_slave_resource),
+			GFP_KERNEL);
+		if (slave_image == NULL) {
+			dev_err(&pdev->dev, "Failed to allocate memory for "
+			"slave resource structure\n");
+			retval = -ENOMEM;
+			goto err_slave;
+		}
+		slave_image->parent = ca91cx42_bridge;
+		mutex_init(&slave_image->mtx);
+		slave_image->locked = 0;
+		slave_image->number = i;
+		slave_image->address_attr = VME_A24 | VME_A32 | VME_USER1 |
+			VME_USER2;
+
+		/* Only windows 0 and 4 support A16 */
+		if (i == 0 || i == 4)
+			slave_image->address_attr |= VME_A16;
+
+		slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+			VME_SUPER | VME_USER | VME_PROG | VME_DATA;
+		list_add_tail(&slave_image->list,
+			&ca91cx42_bridge->slave_resources);
+	}
+
+	/* Add dma engines to list */
+	INIT_LIST_HEAD(&ca91cx42_bridge->dma_resources);
+	for (i = 0; i < CA91C142_MAX_DMA; i++) {
+		dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource),
+			GFP_KERNEL);
+		if (dma_ctrlr == NULL) {
+			dev_err(&pdev->dev, "Failed to allocate memory for "
+			"dma resource structure\n");
+			retval = -ENOMEM;
+			goto err_dma;
+		}
+		dma_ctrlr->parent = ca91cx42_bridge;
+		mutex_init(&dma_ctrlr->mtx);
+		dma_ctrlr->locked = 0;
+		dma_ctrlr->number = i;
+		dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
+			VME_DMA_MEM_TO_VME;
+		INIT_LIST_HEAD(&dma_ctrlr->pending);
+		INIT_LIST_HEAD(&dma_ctrlr->running);
+		list_add_tail(&dma_ctrlr->list,
+			&ca91cx42_bridge->dma_resources);
+	}
+
+	/* Add location monitor to list */
+	INIT_LIST_HEAD(&ca91cx42_bridge->lm_resources);
+	lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
+	if (lm == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate memory for "
+		"location monitor resource structure\n");
+		retval = -ENOMEM;
+		goto err_lm;
+	}
+	lm->parent = ca91cx42_bridge;
+	mutex_init(&lm->mtx);
+	lm->locked = 0;
+	lm->number = 1;
+	lm->monitors = 4;
+	list_add_tail(&lm->list, &ca91cx42_bridge->lm_resources);
+
+	ca91cx42_bridge->slave_get = ca91cx42_slave_get;
+	ca91cx42_bridge->slave_set = ca91cx42_slave_set;
+	ca91cx42_bridge->master_get = ca91cx42_master_get;
+	ca91cx42_bridge->master_set = ca91cx42_master_set;
+	ca91cx42_bridge->master_read = ca91cx42_master_read;
+	ca91cx42_bridge->master_write = ca91cx42_master_write;
+	ca91cx42_bridge->master_rmw = ca91cx42_master_rmw;
+	ca91cx42_bridge->dma_list_add = ca91cx42_dma_list_add;
+	ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec;
+	ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty;
+	ca91cx42_bridge->irq_set = ca91cx42_irq_set;
+	ca91cx42_bridge->irq_generate = ca91cx42_irq_generate;
+	ca91cx42_bridge->lm_set = ca91cx42_lm_set;
+	ca91cx42_bridge->lm_get = ca91cx42_lm_get;
+	ca91cx42_bridge->lm_attach = ca91cx42_lm_attach;
+	ca91cx42_bridge->lm_detach = ca91cx42_lm_detach;
+	ca91cx42_bridge->slot_get = ca91cx42_slot_get;
+	ca91cx42_bridge->alloc_consistent = ca91cx42_alloc_consistent;
+	ca91cx42_bridge->free_consistent = ca91cx42_free_consistent;
+
+	data = ioread32(ca91cx42_device->base + MISC_CTL);
+	dev_info(&pdev->dev, "Board is%s the VME system controller\n",
+		(data & CA91CX42_MISC_CTL_SYSCON) ? "" : " not");
+	dev_info(&pdev->dev, "Slot ID is %d\n",
+		ca91cx42_slot_get(ca91cx42_bridge));
+
+	if (ca91cx42_crcsr_init(ca91cx42_bridge, pdev))
+		dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
+
+	/* Need to save ca91cx42_bridge pointer locally in link list for use in
+	 * ca91cx42_remove()
+	 */
+	retval = vme_register_bridge(ca91cx42_bridge);
+	if (retval != 0) {
+		dev_err(&pdev->dev, "Chip Registration failed.\n");
+		goto err_reg;
+	}
+
+	pci_set_drvdata(pdev, ca91cx42_bridge);
+
+	return 0;
+
+err_reg:
+	ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
+err_lm:
+	/* resources are stored in link list */
+	list_for_each(pos, &ca91cx42_bridge->lm_resources) {
+		lm = list_entry(pos, struct vme_lm_resource, list);
+		list_del(pos);
+		kfree(lm);
+	}
+err_dma:
+	/* resources are stored in link list */
+	list_for_each(pos, &ca91cx42_bridge->dma_resources) {
+		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
+		list_del(pos);
+		kfree(dma_ctrlr);
+	}
+err_slave:
+	/* resources are stored in link list */
+	list_for_each(pos, &ca91cx42_bridge->slave_resources) {
+		slave_image = list_entry(pos, struct vme_slave_resource, list);
+		list_del(pos);
+		kfree(slave_image);
+	}
+err_master:
+	/* resources are stored in link list */
+	list_for_each(pos, &ca91cx42_bridge->master_resources) {
+		master_image = list_entry(pos, struct vme_master_resource,
+			list);
+		list_del(pos);
+		kfree(master_image);
+	}
+
+	ca91cx42_irq_exit(ca91cx42_device, pdev);
+err_irq:
+err_test:
+	iounmap(ca91cx42_device->base);
+err_remap:
+	pci_release_regions(pdev);
+err_resource:
+	pci_disable_device(pdev);
+err_enable:
+	kfree(ca91cx42_device);
+err_driver:
+	kfree(ca91cx42_bridge);
+err_struct:
+	return retval;
+
+}
+
+static void ca91cx42_remove(struct pci_dev *pdev)
+{
+	struct list_head *pos = NULL;
+	struct vme_master_resource *master_image;
+	struct vme_slave_resource *slave_image;
+	struct vme_dma_resource *dma_ctrlr;
+	struct vme_lm_resource *lm;
+	struct ca91cx42_driver *bridge;
+	struct vme_bridge *ca91cx42_bridge = pci_get_drvdata(pdev);
+
+	bridge = ca91cx42_bridge->driver_priv;
+
+
+	/* Turn off Ints */
+	iowrite32(0, bridge->base + LINT_EN);
+
+	/* Turn off the windows */
+	iowrite32(0x00800000, bridge->base + LSI0_CTL);
+	iowrite32(0x00800000, bridge->base + LSI1_CTL);
+	iowrite32(0x00800000, bridge->base + LSI2_CTL);
+	iowrite32(0x00800000, bridge->base + LSI3_CTL);
+	iowrite32(0x00800000, bridge->base + LSI4_CTL);
+	iowrite32(0x00800000, bridge->base + LSI5_CTL);
+	iowrite32(0x00800000, bridge->base + LSI6_CTL);
+	iowrite32(0x00800000, bridge->base + LSI7_CTL);
+	iowrite32(0x00F00000, bridge->base + VSI0_CTL);
+	iowrite32(0x00F00000, bridge->base + VSI1_CTL);
+	iowrite32(0x00F00000, bridge->base + VSI2_CTL);
+	iowrite32(0x00F00000, bridge->base + VSI3_CTL);
+	iowrite32(0x00F00000, bridge->base + VSI4_CTL);
+	iowrite32(0x00F00000, bridge->base + VSI5_CTL);
+	iowrite32(0x00F00000, bridge->base + VSI6_CTL);
+	iowrite32(0x00F00000, bridge->base + VSI7_CTL);
+
+	vme_unregister_bridge(ca91cx42_bridge);
+
+	ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
+
+	/* resources are stored in link list */
+	list_for_each(pos, &ca91cx42_bridge->lm_resources) {
+		lm = list_entry(pos, struct vme_lm_resource, list);
+		list_del(pos);
+		kfree(lm);
+	}
+
+	/* resources are stored in link list */
+	list_for_each(pos, &ca91cx42_bridge->dma_resources) {
+		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
+		list_del(pos);
+		kfree(dma_ctrlr);
+	}
+
+	/* resources are stored in link list */
+	list_for_each(pos, &ca91cx42_bridge->slave_resources) {
+		slave_image = list_entry(pos, struct vme_slave_resource, list);
+		list_del(pos);
+		kfree(slave_image);
+	}
+
+	/* resources are stored in link list */
+	list_for_each(pos, &ca91cx42_bridge->master_resources) {
+		master_image = list_entry(pos, struct vme_master_resource,
+			list);
+		list_del(pos);
+		kfree(master_image);
+	}
+
+	ca91cx42_irq_exit(bridge, pdev);
+
+	iounmap(bridge->base);
+
+	pci_release_regions(pdev);
+
+	pci_disable_device(pdev);
+
+	kfree(ca91cx42_bridge);
+}
+
+static void __exit ca91cx42_exit(void)
+{
+	pci_unregister_driver(&ca91cx42_driver);
+}
+
+MODULE_PARM_DESC(geoid, "Override geographical addressing");
+module_param(geoid, int, 0);
+
+MODULE_DESCRIPTION("VME driver for the Tundra Universe II VME bridge");
+MODULE_LICENSE("GPL");
+
+module_init(ca91cx42_init);
+module_exit(ca91cx42_exit);
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.h b/drivers/vme/bridges/vme_ca91cx42.h
similarity index 100%
rename from drivers/staging/vme/bridges/vme_ca91cx42.h
rename to drivers/vme/bridges/vme_ca91cx42.h
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c
new file mode 100644
index 0000000..f6385f7
--- /dev/null
+++ b/drivers/vme/bridges/vme_tsi148.c
@@ -0,0 +1,2691 @@
+/*
+ * Support for the Tundra TSI148 VME-PCI Bridge Chip
+ *
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * Based on work by Tom Armistead and Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * 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/mm.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/byteorder/generic.h>
+#include <linux/vme.h>
+
+#include "../vme_bridge.h"
+#include "vme_tsi148.h"
+
+static int __init tsi148_init(void);
+static int tsi148_probe(struct pci_dev *, const struct pci_device_id *);
+static void tsi148_remove(struct pci_dev *);
+static void __exit tsi148_exit(void);
+
+
+/* Module parameter */
+static bool err_chk;
+static int geoid;
+
+static const char driver_name[] = "vme_tsi148";
+
+static DEFINE_PCI_DEVICE_TABLE(tsi148_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) },
+	{ },
+};
+
+static struct pci_driver tsi148_driver = {
+	.name = driver_name,
+	.id_table = tsi148_ids,
+	.probe = tsi148_probe,
+	.remove = tsi148_remove,
+};
+
+static void reg_join(unsigned int high, unsigned int low,
+	unsigned long long *variable)
+{
+	*variable = (unsigned long long)high << 32;
+	*variable |= (unsigned long long)low;
+}
+
+static void reg_split(unsigned long long variable, unsigned int *high,
+	unsigned int *low)
+{
+	*low = (unsigned int)variable & 0xFFFFFFFF;
+	*high = (unsigned int)(variable >> 32);
+}
+
+/*
+ * Wakes up DMA queue.
+ */
+static u32 tsi148_DMA_irqhandler(struct tsi148_driver *bridge,
+	int channel_mask)
+{
+	u32 serviced = 0;
+
+	if (channel_mask & TSI148_LCSR_INTS_DMA0S) {
+		wake_up(&bridge->dma_queue[0]);
+		serviced |= TSI148_LCSR_INTC_DMA0C;
+	}
+	if (channel_mask & TSI148_LCSR_INTS_DMA1S) {
+		wake_up(&bridge->dma_queue[1]);
+		serviced |= TSI148_LCSR_INTC_DMA1C;
+	}
+
+	return serviced;
+}
+
+/*
+ * Wake up location monitor queue
+ */
+static u32 tsi148_LM_irqhandler(struct tsi148_driver *bridge, u32 stat)
+{
+	int i;
+	u32 serviced = 0;
+
+	for (i = 0; i < 4; i++) {
+		if (stat & TSI148_LCSR_INTS_LMS[i]) {
+			/* We only enable interrupts if the callback is set */
+			bridge->lm_callback[i](i);
+			serviced |= TSI148_LCSR_INTC_LMC[i];
+		}
+	}
+
+	return serviced;
+}
+
+/*
+ * Wake up mail box queue.
+ *
+ * XXX This functionality is not exposed up though API.
+ */
+static u32 tsi148_MB_irqhandler(struct vme_bridge *tsi148_bridge, u32 stat)
+{
+	int i;
+	u32 val;
+	u32 serviced = 0;
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	for (i = 0; i < 4; i++) {
+		if (stat & TSI148_LCSR_INTS_MBS[i]) {
+			val = ioread32be(bridge->base +	TSI148_GCSR_MBOX[i]);
+			dev_err(tsi148_bridge->parent, "VME Mailbox %d received"
+				": 0x%x\n", i, val);
+			serviced |= TSI148_LCSR_INTC_MBC[i];
+		}
+	}
+
+	return serviced;
+}
+
+/*
+ * Display error & status message when PERR (PCI) exception interrupt occurs.
+ */
+static u32 tsi148_PERR_irqhandler(struct vme_bridge *tsi148_bridge)
+{
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	dev_err(tsi148_bridge->parent, "PCI Exception at address: 0x%08x:%08x, "
+		"attributes: %08x\n",
+		ioread32be(bridge->base + TSI148_LCSR_EDPAU),
+		ioread32be(bridge->base + TSI148_LCSR_EDPAL),
+		ioread32be(bridge->base + TSI148_LCSR_EDPAT));
+
+	dev_err(tsi148_bridge->parent, "PCI-X attribute reg: %08x, PCI-X split "
+		"completion reg: %08x\n",
+		ioread32be(bridge->base + TSI148_LCSR_EDPXA),
+		ioread32be(bridge->base + TSI148_LCSR_EDPXS));
+
+	iowrite32be(TSI148_LCSR_EDPAT_EDPCL, bridge->base + TSI148_LCSR_EDPAT);
+
+	return TSI148_LCSR_INTC_PERRC;
+}
+
+/*
+ * Save address and status when VME error interrupt occurs.
+ */
+static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge)
+{
+	unsigned int error_addr_high, error_addr_low;
+	unsigned long long error_addr;
+	u32 error_attrib;
+	struct vme_bus_error *error;
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	error_addr_high = ioread32be(bridge->base + TSI148_LCSR_VEAU);
+	error_addr_low = ioread32be(bridge->base + TSI148_LCSR_VEAL);
+	error_attrib = ioread32be(bridge->base + TSI148_LCSR_VEAT);
+
+	reg_join(error_addr_high, error_addr_low, &error_addr);
+
+	/* Check for exception register overflow (we have lost error data) */
+	if (error_attrib & TSI148_LCSR_VEAT_VEOF) {
+		dev_err(tsi148_bridge->parent, "VME Bus Exception Overflow "
+			"Occurred\n");
+	}
+
+	error = kmalloc(sizeof(struct vme_bus_error), GFP_ATOMIC);
+	if (error) {
+		error->address = error_addr;
+		error->attributes = error_attrib;
+		list_add_tail(&error->list, &tsi148_bridge->vme_errors);
+	} else {
+		dev_err(tsi148_bridge->parent, "Unable to alloc memory for "
+			"VMEbus Error reporting\n");
+		dev_err(tsi148_bridge->parent, "VME Bus Error at address: "
+			"0x%llx, attributes: %08x\n", error_addr, error_attrib);
+	}
+
+	/* Clear Status */
+	iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT);
+
+	return TSI148_LCSR_INTC_VERRC;
+}
+
+/*
+ * Wake up IACK queue.
+ */
+static u32 tsi148_IACK_irqhandler(struct tsi148_driver *bridge)
+{
+	wake_up(&bridge->iack_queue);
+
+	return TSI148_LCSR_INTC_IACKC;
+}
+
+/*
+ * Calling VME bus interrupt callback if provided.
+ */
+static u32 tsi148_VIRQ_irqhandler(struct vme_bridge *tsi148_bridge,
+	u32 stat)
+{
+	int vec, i, serviced = 0;
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	for (i = 7; i > 0; i--) {
+		if (stat & (1 << i)) {
+			/*
+			 * Note: Even though the registers are defined as
+			 * 32-bits in the spec, we only want to issue 8-bit
+			 * IACK cycles on the bus, read from offset 3.
+			 */
+			vec = ioread8(bridge->base + TSI148_LCSR_VIACK[i] + 3);
+
+			vme_irq_handler(tsi148_bridge, i, vec);
+
+			serviced |= (1 << i);
+		}
+	}
+
+	return serviced;
+}
+
+/*
+ * Top level interrupt handler.  Clears appropriate interrupt status bits and
+ * then calls appropriate sub handler(s).
+ */
+static irqreturn_t tsi148_irqhandler(int irq, void *ptr)
+{
+	u32 stat, enable, serviced = 0;
+	struct vme_bridge *tsi148_bridge;
+	struct tsi148_driver *bridge;
+
+	tsi148_bridge = ptr;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	/* Determine which interrupts are unmasked and set */
+	enable = ioread32be(bridge->base + TSI148_LCSR_INTEO);
+	stat = ioread32be(bridge->base + TSI148_LCSR_INTS);
+
+	/* Only look at unmasked interrupts */
+	stat &= enable;
+
+	if (unlikely(!stat))
+		return IRQ_NONE;
+
+	/* Call subhandlers as appropriate */
+	/* DMA irqs */
+	if (stat & (TSI148_LCSR_INTS_DMA1S | TSI148_LCSR_INTS_DMA0S))
+		serviced |= tsi148_DMA_irqhandler(bridge, stat);
+
+	/* Location monitor irqs */
+	if (stat & (TSI148_LCSR_INTS_LM3S | TSI148_LCSR_INTS_LM2S |
+			TSI148_LCSR_INTS_LM1S | TSI148_LCSR_INTS_LM0S))
+		serviced |= tsi148_LM_irqhandler(bridge, stat);
+
+	/* Mail box irqs */
+	if (stat & (TSI148_LCSR_INTS_MB3S | TSI148_LCSR_INTS_MB2S |
+			TSI148_LCSR_INTS_MB1S | TSI148_LCSR_INTS_MB0S))
+		serviced |= tsi148_MB_irqhandler(tsi148_bridge, stat);
+
+	/* PCI bus error */
+	if (stat & TSI148_LCSR_INTS_PERRS)
+		serviced |= tsi148_PERR_irqhandler(tsi148_bridge);
+
+	/* VME bus error */
+	if (stat & TSI148_LCSR_INTS_VERRS)
+		serviced |= tsi148_VERR_irqhandler(tsi148_bridge);
+
+	/* IACK irq */
+	if (stat & TSI148_LCSR_INTS_IACKS)
+		serviced |= tsi148_IACK_irqhandler(bridge);
+
+	/* VME bus irqs */
+	if (stat & (TSI148_LCSR_INTS_IRQ7S | TSI148_LCSR_INTS_IRQ6S |
+			TSI148_LCSR_INTS_IRQ5S | TSI148_LCSR_INTS_IRQ4S |
+			TSI148_LCSR_INTS_IRQ3S | TSI148_LCSR_INTS_IRQ2S |
+			TSI148_LCSR_INTS_IRQ1S))
+		serviced |= tsi148_VIRQ_irqhandler(tsi148_bridge, stat);
+
+	/* Clear serviced interrupts */
+	iowrite32be(serviced, bridge->base + TSI148_LCSR_INTC);
+
+	return IRQ_HANDLED;
+}
+
+static int tsi148_irq_init(struct vme_bridge *tsi148_bridge)
+{
+	int result;
+	unsigned int tmp;
+	struct pci_dev *pdev;
+	struct tsi148_driver *bridge;
+
+	pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
+
+	bridge = tsi148_bridge->driver_priv;
+
+	/* Initialise list for VME bus errors */
+	INIT_LIST_HEAD(&tsi148_bridge->vme_errors);
+
+	mutex_init(&tsi148_bridge->irq_mtx);
+
+	result = request_irq(pdev->irq,
+			     tsi148_irqhandler,
+			     IRQF_SHARED,
+			     driver_name, tsi148_bridge);
+	if (result) {
+		dev_err(tsi148_bridge->parent, "Can't get assigned pci irq "
+			"vector %02X\n", pdev->irq);
+		return result;
+	}
+
+	/* Enable and unmask interrupts */
+	tmp = TSI148_LCSR_INTEO_DMA1EO | TSI148_LCSR_INTEO_DMA0EO |
+		TSI148_LCSR_INTEO_MB3EO | TSI148_LCSR_INTEO_MB2EO |
+		TSI148_LCSR_INTEO_MB1EO | TSI148_LCSR_INTEO_MB0EO |
+		TSI148_LCSR_INTEO_PERREO | TSI148_LCSR_INTEO_VERREO |
+		TSI148_LCSR_INTEO_IACKEO;
+
+	/* This leaves the following interrupts masked.
+	 * TSI148_LCSR_INTEO_VIEEO
+	 * TSI148_LCSR_INTEO_SYSFLEO
+	 * TSI148_LCSR_INTEO_ACFLEO
+	 */
+
+	/* Don't enable Location Monitor interrupts here - they will be
+	 * enabled when the location monitors are properly configured and
+	 * a callback has been attached.
+	 * TSI148_LCSR_INTEO_LM0EO
+	 * TSI148_LCSR_INTEO_LM1EO
+	 * TSI148_LCSR_INTEO_LM2EO
+	 * TSI148_LCSR_INTEO_LM3EO
+	 */
+
+	/* Don't enable VME interrupts until we add a handler, else the board
+	 * will respond to it and we don't want that unless it knows how to
+	 * properly deal with it.
+	 * TSI148_LCSR_INTEO_IRQ7EO
+	 * TSI148_LCSR_INTEO_IRQ6EO
+	 * TSI148_LCSR_INTEO_IRQ5EO
+	 * TSI148_LCSR_INTEO_IRQ4EO
+	 * TSI148_LCSR_INTEO_IRQ3EO
+	 * TSI148_LCSR_INTEO_IRQ2EO
+	 * TSI148_LCSR_INTEO_IRQ1EO
+	 */
+
+	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
+	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
+
+	return 0;
+}
+
+static void tsi148_irq_exit(struct vme_bridge *tsi148_bridge,
+	struct pci_dev *pdev)
+{
+	struct tsi148_driver *bridge = tsi148_bridge->driver_priv;
+
+	/* Turn off interrupts */
+	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEO);
+	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEN);
+
+	/* Clear all interrupts */
+	iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_INTC);
+
+	/* Detach interrupt handler */
+	free_irq(pdev->irq, tsi148_bridge);
+}
+
+/*
+ * Check to see if an IACk has been received, return true (1) or false (0).
+ */
+static int tsi148_iack_received(struct tsi148_driver *bridge)
+{
+	u32 tmp;
+
+	tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
+
+	if (tmp & TSI148_LCSR_VICR_IRQS)
+		return 0;
+	else
+		return 1;
+}
+
+/*
+ * Configure VME interrupt
+ */
+static void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level,
+	int state, int sync)
+{
+	struct pci_dev *pdev;
+	u32 tmp;
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	/* We need to do the ordering differently for enabling and disabling */
+	if (state == 0) {
+		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
+		tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1];
+		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
+
+		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
+		tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1];
+		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
+
+		if (sync != 0) {
+			pdev = container_of(tsi148_bridge->parent,
+				struct pci_dev, dev);
+
+			synchronize_irq(pdev->irq);
+		}
+	} else {
+		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
+		tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
+		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
+
+		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
+		tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
+		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
+	}
+}
+
+/*
+ * Generate a VME bus interrupt at the requested level & vector. Wait for
+ * interrupt to be acked.
+ */
+static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level,
+	int statid)
+{
+	u32 tmp;
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	mutex_lock(&bridge->vme_int);
+
+	/* Read VICR register */
+	tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
+
+	/* Set Status/ID */
+	tmp = (tmp & ~TSI148_LCSR_VICR_STID_M) |
+		(statid & TSI148_LCSR_VICR_STID_M);
+	iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
+
+	/* Assert VMEbus IRQ */
+	tmp = tmp | TSI148_LCSR_VICR_IRQL[level];
+	iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
+
+	/* XXX Consider implementing a timeout? */
+	wait_event_interruptible(bridge->iack_queue,
+		tsi148_iack_received(bridge));
+
+	mutex_unlock(&bridge->vme_int);
+
+	return 0;
+}
+
+/*
+ * Find the first error in this address range
+ */
+static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge,
+	u32 aspace, unsigned long long address, size_t count)
+{
+	struct list_head *err_pos;
+	struct vme_bus_error *vme_err, *valid = NULL;
+	unsigned long long bound;
+
+	bound = address + count;
+
+	/*
+	 * XXX We are currently not looking at the address space when parsing
+	 *     for errors. This is because parsing the Address Modifier Codes
+	 *     is going to be quite resource intensive to do properly. We
+	 *     should be OK just looking at the addresses and this is certainly
+	 *     much better than what we had before.
+	 */
+	err_pos = NULL;
+	/* Iterate through errors */
+	list_for_each(err_pos, &tsi148_bridge->vme_errors) {
+		vme_err = list_entry(err_pos, struct vme_bus_error, list);
+		if ((vme_err->address >= address) &&
+			(vme_err->address < bound)) {
+
+			valid = vme_err;
+			break;
+		}
+	}
+
+	return valid;
+}
+
+/*
+ * Clear errors in the provided address range.
+ */
+static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge,
+	u32 aspace, unsigned long long address, size_t count)
+{
+	struct list_head *err_pos, *temp;
+	struct vme_bus_error *vme_err;
+	unsigned long long bound;
+
+	bound = address + count;
+
+	/*
+	 * XXX We are currently not looking at the address space when parsing
+	 *     for errors. This is because parsing the Address Modifier Codes
+	 *     is going to be quite resource intensive to do properly. We
+	 *     should be OK just looking at the addresses and this is certainly
+	 *     much better than what we had before.
+	 */
+	err_pos = NULL;
+	/* Iterate through errors */
+	list_for_each_safe(err_pos, temp, &tsi148_bridge->vme_errors) {
+		vme_err = list_entry(err_pos, struct vme_bus_error, list);
+
+		if ((vme_err->address >= address) &&
+			(vme_err->address < bound)) {
+
+			list_del(err_pos);
+			kfree(vme_err);
+		}
+	}
+}
+
+/*
+ * Initialize a slave window with the requested attributes.
+ */
+static int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
+	unsigned long long vme_base, unsigned long long size,
+	dma_addr_t pci_base, u32 aspace, u32 cycle)
+{
+	unsigned int i, addr = 0, granularity = 0;
+	unsigned int temp_ctl = 0;
+	unsigned int vme_base_low, vme_base_high;
+	unsigned int vme_bound_low, vme_bound_high;
+	unsigned int pci_offset_low, pci_offset_high;
+	unsigned long long vme_bound, pci_offset;
+	struct vme_bridge *tsi148_bridge;
+	struct tsi148_driver *bridge;
+
+	tsi148_bridge = image->parent;
+	bridge = tsi148_bridge->driver_priv;
+
+	i = image->number;
+
+	switch (aspace) {
+	case VME_A16:
+		granularity = 0x10;
+		addr |= TSI148_LCSR_ITAT_AS_A16;
+		break;
+	case VME_A24:
+		granularity = 0x1000;
+		addr |= TSI148_LCSR_ITAT_AS_A24;
+		break;
+	case VME_A32:
+		granularity = 0x10000;
+		addr |= TSI148_LCSR_ITAT_AS_A32;
+		break;
+	case VME_A64:
+		granularity = 0x10000;
+		addr |= TSI148_LCSR_ITAT_AS_A64;
+		break;
+	case VME_CRCSR:
+	case VME_USER1:
+	case VME_USER2:
+	case VME_USER3:
+	case VME_USER4:
+	default:
+		dev_err(tsi148_bridge->parent, "Invalid address space\n");
+		return -EINVAL;
+		break;
+	}
+
+	/* Convert 64-bit variables to 2x 32-bit variables */
+	reg_split(vme_base, &vme_base_high, &vme_base_low);
+
+	/*
+	 * Bound address is a valid address for the window, adjust
+	 * accordingly
+	 */
+	vme_bound = vme_base + size - granularity;
+	reg_split(vme_bound, &vme_bound_high, &vme_bound_low);
+	pci_offset = (unsigned long long)pci_base - vme_base;
+	reg_split(pci_offset, &pci_offset_high, &pci_offset_low);
+
+	if (vme_base_low & (granularity - 1)) {
+		dev_err(tsi148_bridge->parent, "Invalid VME base alignment\n");
+		return -EINVAL;
+	}
+	if (vme_bound_low & (granularity - 1)) {
+		dev_err(tsi148_bridge->parent, "Invalid VME bound alignment\n");
+		return -EINVAL;
+	}
+	if (pci_offset_low & (granularity - 1)) {
+		dev_err(tsi148_bridge->parent, "Invalid PCI Offset "
+			"alignment\n");
+		return -EINVAL;
+	}
+
+	/*  Disable while we are mucking around */
+	temp_ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITAT);
+	temp_ctl &= ~TSI148_LCSR_ITAT_EN;
+	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITAT);
+
+	/* Setup mapping */
+	iowrite32be(vme_base_high, bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITSAU);
+	iowrite32be(vme_base_low, bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITSAL);
+	iowrite32be(vme_bound_high, bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITEAU);
+	iowrite32be(vme_bound_low, bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITEAL);
+	iowrite32be(pci_offset_high, bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITOFU);
+	iowrite32be(pci_offset_low, bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITOFL);
+
+	/* Setup 2eSST speeds */
+	temp_ctl &= ~TSI148_LCSR_ITAT_2eSSTM_M;
+	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
+	case VME_2eSST160:
+		temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_160;
+		break;
+	case VME_2eSST267:
+		temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_267;
+		break;
+	case VME_2eSST320:
+		temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_320;
+		break;
+	}
+
+	/* Setup cycle types */
+	temp_ctl &= ~(0x1F << 7);
+	if (cycle & VME_BLT)
+		temp_ctl |= TSI148_LCSR_ITAT_BLT;
+	if (cycle & VME_MBLT)
+		temp_ctl |= TSI148_LCSR_ITAT_MBLT;
+	if (cycle & VME_2eVME)
+		temp_ctl |= TSI148_LCSR_ITAT_2eVME;
+	if (cycle & VME_2eSST)
+		temp_ctl |= TSI148_LCSR_ITAT_2eSST;
+	if (cycle & VME_2eSSTB)
+		temp_ctl |= TSI148_LCSR_ITAT_2eSSTB;
+
+	/* Setup address space */
+	temp_ctl &= ~TSI148_LCSR_ITAT_AS_M;
+	temp_ctl |= addr;
+
+	temp_ctl &= ~0xF;
+	if (cycle & VME_SUPER)
+		temp_ctl |= TSI148_LCSR_ITAT_SUPR ;
+	if (cycle & VME_USER)
+		temp_ctl |= TSI148_LCSR_ITAT_NPRIV;
+	if (cycle & VME_PROG)
+		temp_ctl |= TSI148_LCSR_ITAT_PGM;
+	if (cycle & VME_DATA)
+		temp_ctl |= TSI148_LCSR_ITAT_DATA;
+
+	/* Write ctl reg without enable */
+	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITAT);
+
+	if (enabled)
+		temp_ctl |= TSI148_LCSR_ITAT_EN;
+
+	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITAT);
+
+	return 0;
+}
+
+/*
+ * Get slave window configuration.
+ */
+static int tsi148_slave_get(struct vme_slave_resource *image, int *enabled,
+	unsigned long long *vme_base, unsigned long long *size,
+	dma_addr_t *pci_base, u32 *aspace, u32 *cycle)
+{
+	unsigned int i, granularity = 0, ctl = 0;
+	unsigned int vme_base_low, vme_base_high;
+	unsigned int vme_bound_low, vme_bound_high;
+	unsigned int pci_offset_low, pci_offset_high;
+	unsigned long long vme_bound, pci_offset;
+	struct tsi148_driver *bridge;
+
+	bridge = image->parent->driver_priv;
+
+	i = image->number;
+
+	/* Read registers */
+	ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITAT);
+
+	vme_base_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITSAU);
+	vme_base_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITSAL);
+	vme_bound_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITEAU);
+	vme_bound_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITEAL);
+	pci_offset_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITOFU);
+	pci_offset_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
+		TSI148_LCSR_OFFSET_ITOFL);
+
+	/* Convert 64-bit variables to 2x 32-bit variables */
+	reg_join(vme_base_high, vme_base_low, vme_base);
+	reg_join(vme_bound_high, vme_bound_low, &vme_bound);
+	reg_join(pci_offset_high, pci_offset_low, &pci_offset);
+
+	*pci_base = (dma_addr_t)vme_base + pci_offset;
+
+	*enabled = 0;
+	*aspace = 0;
+	*cycle = 0;
+
+	if (ctl & TSI148_LCSR_ITAT_EN)
+		*enabled = 1;
+
+	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A16) {
+		granularity = 0x10;
+		*aspace |= VME_A16;
+	}
+	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A24) {
+		granularity = 0x1000;
+		*aspace |= VME_A24;
+	}
+	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A32) {
+		granularity = 0x10000;
+		*aspace |= VME_A32;
+	}
+	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A64) {
+		granularity = 0x10000;
+		*aspace |= VME_A64;
+	}
+
+	/* Need granularity before we set the size */
+	*size = (unsigned long long)((vme_bound - *vme_base) + granularity);
+
+
+	if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_160)
+		*cycle |= VME_2eSST160;
+	if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_267)
+		*cycle |= VME_2eSST267;
+	if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_320)
+		*cycle |= VME_2eSST320;
+
+	if (ctl & TSI148_LCSR_ITAT_BLT)
+		*cycle |= VME_BLT;
+	if (ctl & TSI148_LCSR_ITAT_MBLT)
+		*cycle |= VME_MBLT;
+	if (ctl & TSI148_LCSR_ITAT_2eVME)
+		*cycle |= VME_2eVME;
+	if (ctl & TSI148_LCSR_ITAT_2eSST)
+		*cycle |= VME_2eSST;
+	if (ctl & TSI148_LCSR_ITAT_2eSSTB)
+		*cycle |= VME_2eSSTB;
+
+	if (ctl & TSI148_LCSR_ITAT_SUPR)
+		*cycle |= VME_SUPER;
+	if (ctl & TSI148_LCSR_ITAT_NPRIV)
+		*cycle |= VME_USER;
+	if (ctl & TSI148_LCSR_ITAT_PGM)
+		*cycle |= VME_PROG;
+	if (ctl & TSI148_LCSR_ITAT_DATA)
+		*cycle |= VME_DATA;
+
+	return 0;
+}
+
+/*
+ * Allocate and map PCI Resource
+ */
+static int tsi148_alloc_resource(struct vme_master_resource *image,
+	unsigned long long size)
+{
+	unsigned long long existing_size;
+	int retval = 0;
+	struct pci_dev *pdev;
+	struct vme_bridge *tsi148_bridge;
+
+	tsi148_bridge = image->parent;
+
+	pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
+
+	existing_size = (unsigned long long)(image->bus_resource.end -
+		image->bus_resource.start);
+
+	/* If the existing size is OK, return */
+	if ((size != 0) && (existing_size == (size - 1)))
+		return 0;
+
+	if (existing_size != 0) {
+		iounmap(image->kern_base);
+		image->kern_base = NULL;
+		kfree(image->bus_resource.name);
+		release_resource(&image->bus_resource);
+		memset(&image->bus_resource, 0, sizeof(struct resource));
+	}
+
+	/* Exit here if size is zero */
+	if (size == 0)
+		return 0;
+
+	if (image->bus_resource.name == NULL) {
+		image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC);
+		if (image->bus_resource.name == NULL) {
+			dev_err(tsi148_bridge->parent, "Unable to allocate "
+				"memory for resource name\n");
+			retval = -ENOMEM;
+			goto err_name;
+		}
+	}
+
+	sprintf((char *)image->bus_resource.name, "%s.%d", tsi148_bridge->name,
+		image->number);
+
+	image->bus_resource.start = 0;
+	image->bus_resource.end = (unsigned long)size;
+	image->bus_resource.flags = IORESOURCE_MEM;
+
+	retval = pci_bus_alloc_resource(pdev->bus,
+		&image->bus_resource, size, size, PCIBIOS_MIN_MEM,
+		0, NULL, NULL);
+	if (retval) {
+		dev_err(tsi148_bridge->parent, "Failed to allocate mem "
+			"resource for window %d size 0x%lx start 0x%lx\n",
+			image->number, (unsigned long)size,
+			(unsigned long)image->bus_resource.start);
+		goto err_resource;
+	}
+
+	image->kern_base = ioremap_nocache(
+		image->bus_resource.start, size);
+	if (image->kern_base == NULL) {
+		dev_err(tsi148_bridge->parent, "Failed to remap resource\n");
+		retval = -ENOMEM;
+		goto err_remap;
+	}
+
+	return 0;
+
+err_remap:
+	release_resource(&image->bus_resource);
+err_resource:
+	kfree(image->bus_resource.name);
+	memset(&image->bus_resource, 0, sizeof(struct resource));
+err_name:
+	return retval;
+}
+
+/*
+ * Free and unmap PCI Resource
+ */
+static void tsi148_free_resource(struct vme_master_resource *image)
+{
+	iounmap(image->kern_base);
+	image->kern_base = NULL;
+	release_resource(&image->bus_resource);
+	kfree(image->bus_resource.name);
+	memset(&image->bus_resource, 0, sizeof(struct resource));
+}
+
+/*
+ * Set the attributes of an outbound window.
+ */
+static int tsi148_master_set(struct vme_master_resource *image, int enabled,
+	unsigned long long vme_base, unsigned long long size, u32 aspace,
+	u32 cycle, u32 dwidth)
+{
+	int retval = 0;
+	unsigned int i;
+	unsigned int temp_ctl = 0;
+	unsigned int pci_base_low, pci_base_high;
+	unsigned int pci_bound_low, pci_bound_high;
+	unsigned int vme_offset_low, vme_offset_high;
+	unsigned long long pci_bound, vme_offset, pci_base;
+	struct vme_bridge *tsi148_bridge;
+	struct tsi148_driver *bridge;
+
+	tsi148_bridge = image->parent;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	/* Verify input data */
+	if (vme_base & 0xFFFF) {
+		dev_err(tsi148_bridge->parent, "Invalid VME Window "
+			"alignment\n");
+		retval = -EINVAL;
+		goto err_window;
+	}
+
+	if ((size == 0) && (enabled != 0)) {
+		dev_err(tsi148_bridge->parent, "Size must be non-zero for "
+			"enabled windows\n");
+		retval = -EINVAL;
+		goto err_window;
+	}
+
+	spin_lock(&image->lock);
+
+	/* Let's allocate the resource here rather than further up the stack as
+	 * it avoids pushing loads of bus dependent stuff up the stack. If size
+	 * is zero, any existing resource will be freed.
+	 */
+	retval = tsi148_alloc_resource(image, size);
+	if (retval) {
+		spin_unlock(&image->lock);
+		dev_err(tsi148_bridge->parent, "Unable to allocate memory for "
+			"resource\n");
+		goto err_res;
+	}
+
+	if (size == 0) {
+		pci_base = 0;
+		pci_bound = 0;
+		vme_offset = 0;
+	} else {
+		pci_base = (unsigned long long)image->bus_resource.start;
+
+		/*
+		 * Bound address is a valid address for the window, adjust
+		 * according to window granularity.
+		 */
+		pci_bound = pci_base + (size - 0x10000);
+		vme_offset = vme_base - pci_base;
+	}
+
+	/* Convert 64-bit variables to 2x 32-bit variables */
+	reg_split(pci_base, &pci_base_high, &pci_base_low);
+	reg_split(pci_bound, &pci_bound_high, &pci_bound_low);
+	reg_split(vme_offset, &vme_offset_high, &vme_offset_low);
+
+	if (pci_base_low & 0xFFFF) {
+		spin_unlock(&image->lock);
+		dev_err(tsi148_bridge->parent, "Invalid PCI base alignment\n");
+		retval = -EINVAL;
+		goto err_gran;
+	}
+	if (pci_bound_low & 0xFFFF) {
+		spin_unlock(&image->lock);
+		dev_err(tsi148_bridge->parent, "Invalid PCI bound alignment\n");
+		retval = -EINVAL;
+		goto err_gran;
+	}
+	if (vme_offset_low & 0xFFFF) {
+		spin_unlock(&image->lock);
+		dev_err(tsi148_bridge->parent, "Invalid VME Offset "
+			"alignment\n");
+		retval = -EINVAL;
+		goto err_gran;
+	}
+
+	i = image->number;
+
+	/* Disable while we are mucking around */
+	temp_ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTAT);
+	temp_ctl &= ~TSI148_LCSR_OTAT_EN;
+	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTAT);
+
+	/* Setup 2eSST speeds */
+	temp_ctl &= ~TSI148_LCSR_OTAT_2eSSTM_M;
+	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
+	case VME_2eSST160:
+		temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_160;
+		break;
+	case VME_2eSST267:
+		temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_267;
+		break;
+	case VME_2eSST320:
+		temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_320;
+		break;
+	}
+
+	/* Setup cycle types */
+	if (cycle & VME_BLT) {
+		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+		temp_ctl |= TSI148_LCSR_OTAT_TM_BLT;
+	}
+	if (cycle & VME_MBLT) {
+		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+		temp_ctl |= TSI148_LCSR_OTAT_TM_MBLT;
+	}
+	if (cycle & VME_2eVME) {
+		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+		temp_ctl |= TSI148_LCSR_OTAT_TM_2eVME;
+	}
+	if (cycle & VME_2eSST) {
+		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+		temp_ctl |= TSI148_LCSR_OTAT_TM_2eSST;
+	}
+	if (cycle & VME_2eSSTB) {
+		dev_warn(tsi148_bridge->parent, "Currently not setting "
+			"Broadcast Select Registers\n");
+		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+		temp_ctl |= TSI148_LCSR_OTAT_TM_2eSSTB;
+	}
+
+	/* Setup data width */
+	temp_ctl &= ~TSI148_LCSR_OTAT_DBW_M;
+	switch (dwidth) {
+	case VME_D16:
+		temp_ctl |= TSI148_LCSR_OTAT_DBW_16;
+		break;
+	case VME_D32:
+		temp_ctl |= TSI148_LCSR_OTAT_DBW_32;
+		break;
+	default:
+		spin_unlock(&image->lock);
+		dev_err(tsi148_bridge->parent, "Invalid data width\n");
+		retval = -EINVAL;
+		goto err_dwidth;
+	}
+
+	/* Setup address space */
+	temp_ctl &= ~TSI148_LCSR_OTAT_AMODE_M;
+	switch (aspace) {
+	case VME_A16:
+		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A16;
+		break;
+	case VME_A24:
+		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A24;
+		break;
+	case VME_A32:
+		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A32;
+		break;
+	case VME_A64:
+		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A64;
+		break;
+	case VME_CRCSR:
+		temp_ctl |= TSI148_LCSR_OTAT_AMODE_CRCSR;
+		break;
+	case VME_USER1:
+		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER1;
+		break;
+	case VME_USER2:
+		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER2;
+		break;
+	case VME_USER3:
+		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER3;
+		break;
+	case VME_USER4:
+		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER4;
+		break;
+	default:
+		spin_unlock(&image->lock);
+		dev_err(tsi148_bridge->parent, "Invalid address space\n");
+		retval = -EINVAL;
+		goto err_aspace;
+		break;
+	}
+
+	temp_ctl &= ~(3<<4);
+	if (cycle & VME_SUPER)
+		temp_ctl |= TSI148_LCSR_OTAT_SUP;
+	if (cycle & VME_PROG)
+		temp_ctl |= TSI148_LCSR_OTAT_PGM;
+
+	/* Setup mapping */
+	iowrite32be(pci_base_high, bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTSAU);
+	iowrite32be(pci_base_low, bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTSAL);
+	iowrite32be(pci_bound_high, bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTEAU);
+	iowrite32be(pci_bound_low, bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTEAL);
+	iowrite32be(vme_offset_high, bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTOFU);
+	iowrite32be(vme_offset_low, bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTOFL);
+
+	/* Write ctl reg without enable */
+	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTAT);
+
+	if (enabled)
+		temp_ctl |= TSI148_LCSR_OTAT_EN;
+
+	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTAT);
+
+	spin_unlock(&image->lock);
+	return 0;
+
+err_aspace:
+err_dwidth:
+err_gran:
+	tsi148_free_resource(image);
+err_res:
+err_window:
+	return retval;
+
+}
+
+/*
+ * Set the attributes of an outbound window.
+ *
+ * XXX Not parsing prefetch information.
+ */
+static int __tsi148_master_get(struct vme_master_resource *image, int *enabled,
+	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
+	u32 *cycle, u32 *dwidth)
+{
+	unsigned int i, ctl;
+	unsigned int pci_base_low, pci_base_high;
+	unsigned int pci_bound_low, pci_bound_high;
+	unsigned int vme_offset_low, vme_offset_high;
+
+	unsigned long long pci_base, pci_bound, vme_offset;
+	struct tsi148_driver *bridge;
+
+	bridge = image->parent->driver_priv;
+
+	i = image->number;
+
+	ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTAT);
+
+	pci_base_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTSAU);
+	pci_base_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTSAL);
+	pci_bound_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTEAU);
+	pci_bound_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTEAL);
+	vme_offset_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTOFU);
+	vme_offset_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTOFL);
+
+	/* Convert 64-bit variables to 2x 32-bit variables */
+	reg_join(pci_base_high, pci_base_low, &pci_base);
+	reg_join(pci_bound_high, pci_bound_low, &pci_bound);
+	reg_join(vme_offset_high, vme_offset_low, &vme_offset);
+
+	*vme_base = pci_base + vme_offset;
+	*size = (unsigned long long)(pci_bound - pci_base) + 0x10000;
+
+	*enabled = 0;
+	*aspace = 0;
+	*cycle = 0;
+	*dwidth = 0;
+
+	if (ctl & TSI148_LCSR_OTAT_EN)
+		*enabled = 1;
+
+	/* Setup address space */
+	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A16)
+		*aspace |= VME_A16;
+	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A24)
+		*aspace |= VME_A24;
+	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A32)
+		*aspace |= VME_A32;
+	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A64)
+		*aspace |= VME_A64;
+	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_CRCSR)
+		*aspace |= VME_CRCSR;
+	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER1)
+		*aspace |= VME_USER1;
+	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER2)
+		*aspace |= VME_USER2;
+	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER3)
+		*aspace |= VME_USER3;
+	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER4)
+		*aspace |= VME_USER4;
+
+	/* Setup 2eSST speeds */
+	if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_160)
+		*cycle |= VME_2eSST160;
+	if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_267)
+		*cycle |= VME_2eSST267;
+	if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_320)
+		*cycle |= VME_2eSST320;
+
+	/* Setup cycle types */
+	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_SCT)
+		*cycle |= VME_SCT;
+	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_BLT)
+		*cycle |= VME_BLT;
+	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_MBLT)
+		*cycle |= VME_MBLT;
+	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eVME)
+		*cycle |= VME_2eVME;
+	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSST)
+		*cycle |= VME_2eSST;
+	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSSTB)
+		*cycle |= VME_2eSSTB;
+
+	if (ctl & TSI148_LCSR_OTAT_SUP)
+		*cycle |= VME_SUPER;
+	else
+		*cycle |= VME_USER;
+
+	if (ctl & TSI148_LCSR_OTAT_PGM)
+		*cycle |= VME_PROG;
+	else
+		*cycle |= VME_DATA;
+
+	/* Setup data width */
+	if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_16)
+		*dwidth = VME_D16;
+	if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_32)
+		*dwidth = VME_D32;
+
+	return 0;
+}
+
+
+static int tsi148_master_get(struct vme_master_resource *image, int *enabled,
+	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
+	u32 *cycle, u32 *dwidth)
+{
+	int retval;
+
+	spin_lock(&image->lock);
+
+	retval = __tsi148_master_get(image, enabled, vme_base, size, aspace,
+		cycle, dwidth);
+
+	spin_unlock(&image->lock);
+
+	return retval;
+}
+
+static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
+	size_t count, loff_t offset)
+{
+	int retval, enabled;
+	unsigned long long vme_base, size;
+	u32 aspace, cycle, dwidth;
+	struct vme_bus_error *vme_err = NULL;
+	struct vme_bridge *tsi148_bridge;
+
+	tsi148_bridge = image->parent;
+
+	spin_lock(&image->lock);
+
+	memcpy_fromio(buf, image->kern_base + offset, (unsigned int)count);
+	retval = count;
+
+	if (!err_chk)
+		goto skip_chk;
+
+	__tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
+		&dwidth);
+
+	vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
+		count);
+	if (vme_err != NULL) {
+		dev_err(image->parent->parent, "First VME read error detected "
+			"an at address 0x%llx\n", vme_err->address);
+		retval = vme_err->address - (vme_base + offset);
+		/* Clear down save errors in this address range */
+		tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
+			count);
+	}
+
+skip_chk:
+	spin_unlock(&image->lock);
+
+	return retval;
+}
+
+
+static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
+	size_t count, loff_t offset)
+{
+	int retval = 0, enabled;
+	unsigned long long vme_base, size;
+	u32 aspace, cycle, dwidth;
+
+	struct vme_bus_error *vme_err = NULL;
+	struct vme_bridge *tsi148_bridge;
+	struct tsi148_driver *bridge;
+
+	tsi148_bridge = image->parent;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	spin_lock(&image->lock);
+
+	memcpy_toio(image->kern_base + offset, buf, (unsigned int)count);
+	retval = count;
+
+	/*
+	 * Writes are posted. We need to do a read on the VME bus to flush out
+	 * all of the writes before we check for errors. We can't guarantee
+	 * that reading the data we have just written is safe. It is believed
+	 * that there isn't any read, write re-ordering, so we can read any
+	 * location in VME space, so lets read the Device ID from the tsi148's
+	 * own registers as mapped into CR/CSR space.
+	 *
+	 * We check for saved errors in the written address range/space.
+	 */
+
+	if (!err_chk)
+		goto skip_chk;
+
+	/*
+	 * Get window info first, to maximise the time that the buffers may
+	 * fluch on their own
+	 */
+	__tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
+		&dwidth);
+
+	ioread16(bridge->flush_image->kern_base + 0x7F000);
+
+	vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
+		count);
+	if (vme_err != NULL) {
+		dev_warn(tsi148_bridge->parent, "First VME write error detected"
+			" an at address 0x%llx\n", vme_err->address);
+		retval = vme_err->address - (vme_base + offset);
+		/* Clear down save errors in this address range */
+		tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
+			count);
+	}
+
+skip_chk:
+	spin_unlock(&image->lock);
+
+	return retval;
+}
+
+/*
+ * Perform an RMW cycle on the VME bus.
+ *
+ * Requires a previously configured master window, returns final value.
+ */
+static unsigned int tsi148_master_rmw(struct vme_master_resource *image,
+	unsigned int mask, unsigned int compare, unsigned int swap,
+	loff_t offset)
+{
+	unsigned long long pci_addr;
+	unsigned int pci_addr_high, pci_addr_low;
+	u32 tmp, result;
+	int i;
+	struct tsi148_driver *bridge;
+
+	bridge = image->parent->driver_priv;
+
+	/* Find the PCI address that maps to the desired VME address */
+	i = image->number;
+
+	/* Locking as we can only do one of these at a time */
+	mutex_lock(&bridge->vme_rmw);
+
+	/* Lock image */
+	spin_lock(&image->lock);
+
+	pci_addr_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTSAU);
+	pci_addr_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
+		TSI148_LCSR_OFFSET_OTSAL);
+
+	reg_join(pci_addr_high, pci_addr_low, &pci_addr);
+	reg_split(pci_addr + offset, &pci_addr_high, &pci_addr_low);
+
+	/* Configure registers */
+	iowrite32be(mask, bridge->base + TSI148_LCSR_RMWEN);
+	iowrite32be(compare, bridge->base + TSI148_LCSR_RMWC);
+	iowrite32be(swap, bridge->base + TSI148_LCSR_RMWS);
+	iowrite32be(pci_addr_high, bridge->base + TSI148_LCSR_RMWAU);
+	iowrite32be(pci_addr_low, bridge->base + TSI148_LCSR_RMWAL);
+
+	/* Enable RMW */
+	tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
+	tmp |= TSI148_LCSR_VMCTRL_RMWEN;
+	iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
+
+	/* Kick process off with a read to the required address. */
+	result = ioread32be(image->kern_base + offset);
+
+	/* Disable RMW */
+	tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
+	tmp &= ~TSI148_LCSR_VMCTRL_RMWEN;
+	iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
+
+	spin_unlock(&image->lock);
+
+	mutex_unlock(&bridge->vme_rmw);
+
+	return result;
+}
+
+static int tsi148_dma_set_vme_src_attributes(struct device *dev, __be32 *attr,
+	u32 aspace, u32 cycle, u32 dwidth)
+{
+	u32 val;
+
+	val = be32_to_cpu(*attr);
+
+	/* Setup 2eSST speeds */
+	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
+	case VME_2eSST160:
+		val |= TSI148_LCSR_DSAT_2eSSTM_160;
+		break;
+	case VME_2eSST267:
+		val |= TSI148_LCSR_DSAT_2eSSTM_267;
+		break;
+	case VME_2eSST320:
+		val |= TSI148_LCSR_DSAT_2eSSTM_320;
+		break;
+	}
+
+	/* Setup cycle types */
+	if (cycle & VME_SCT)
+		val |= TSI148_LCSR_DSAT_TM_SCT;
+
+	if (cycle & VME_BLT)
+		val |= TSI148_LCSR_DSAT_TM_BLT;
+
+	if (cycle & VME_MBLT)
+		val |= TSI148_LCSR_DSAT_TM_MBLT;
+
+	if (cycle & VME_2eVME)
+		val |= TSI148_LCSR_DSAT_TM_2eVME;
+
+	if (cycle & VME_2eSST)
+		val |= TSI148_LCSR_DSAT_TM_2eSST;
+
+	if (cycle & VME_2eSSTB) {
+		dev_err(dev, "Currently not setting Broadcast Select "
+			"Registers\n");
+		val |= TSI148_LCSR_DSAT_TM_2eSSTB;
+	}
+
+	/* Setup data width */
+	switch (dwidth) {
+	case VME_D16:
+		val |= TSI148_LCSR_DSAT_DBW_16;
+		break;
+	case VME_D32:
+		val |= TSI148_LCSR_DSAT_DBW_32;
+		break;
+	default:
+		dev_err(dev, "Invalid data width\n");
+		return -EINVAL;
+	}
+
+	/* Setup address space */
+	switch (aspace) {
+	case VME_A16:
+		val |= TSI148_LCSR_DSAT_AMODE_A16;
+		break;
+	case VME_A24:
+		val |= TSI148_LCSR_DSAT_AMODE_A24;
+		break;
+	case VME_A32:
+		val |= TSI148_LCSR_DSAT_AMODE_A32;
+		break;
+	case VME_A64:
+		val |= TSI148_LCSR_DSAT_AMODE_A64;
+		break;
+	case VME_CRCSR:
+		val |= TSI148_LCSR_DSAT_AMODE_CRCSR;
+		break;
+	case VME_USER1:
+		val |= TSI148_LCSR_DSAT_AMODE_USER1;
+		break;
+	case VME_USER2:
+		val |= TSI148_LCSR_DSAT_AMODE_USER2;
+		break;
+	case VME_USER3:
+		val |= TSI148_LCSR_DSAT_AMODE_USER3;
+		break;
+	case VME_USER4:
+		val |= TSI148_LCSR_DSAT_AMODE_USER4;
+		break;
+	default:
+		dev_err(dev, "Invalid address space\n");
+		return -EINVAL;
+		break;
+	}
+
+	if (cycle & VME_SUPER)
+		val |= TSI148_LCSR_DSAT_SUP;
+	if (cycle & VME_PROG)
+		val |= TSI148_LCSR_DSAT_PGM;
+
+	*attr = cpu_to_be32(val);
+
+	return 0;
+}
+
+static int tsi148_dma_set_vme_dest_attributes(struct device *dev, __be32 *attr,
+	u32 aspace, u32 cycle, u32 dwidth)
+{
+	u32 val;
+
+	val = be32_to_cpu(*attr);
+
+	/* Setup 2eSST speeds */
+	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
+	case VME_2eSST160:
+		val |= TSI148_LCSR_DDAT_2eSSTM_160;
+		break;
+	case VME_2eSST267:
+		val |= TSI148_LCSR_DDAT_2eSSTM_267;
+		break;
+	case VME_2eSST320:
+		val |= TSI148_LCSR_DDAT_2eSSTM_320;
+		break;
+	}
+
+	/* Setup cycle types */
+	if (cycle & VME_SCT)
+		val |= TSI148_LCSR_DDAT_TM_SCT;
+
+	if (cycle & VME_BLT)
+		val |= TSI148_LCSR_DDAT_TM_BLT;
+
+	if (cycle & VME_MBLT)
+		val |= TSI148_LCSR_DDAT_TM_MBLT;
+
+	if (cycle & VME_2eVME)
+		val |= TSI148_LCSR_DDAT_TM_2eVME;
+
+	if (cycle & VME_2eSST)
+		val |= TSI148_LCSR_DDAT_TM_2eSST;
+
+	if (cycle & VME_2eSSTB) {
+		dev_err(dev, "Currently not setting Broadcast Select "
+			"Registers\n");
+		val |= TSI148_LCSR_DDAT_TM_2eSSTB;
+	}
+
+	/* Setup data width */
+	switch (dwidth) {
+	case VME_D16:
+		val |= TSI148_LCSR_DDAT_DBW_16;
+		break;
+	case VME_D32:
+		val |= TSI148_LCSR_DDAT_DBW_32;
+		break;
+	default:
+		dev_err(dev, "Invalid data width\n");
+		return -EINVAL;
+	}
+
+	/* Setup address space */
+	switch (aspace) {
+	case VME_A16:
+		val |= TSI148_LCSR_DDAT_AMODE_A16;
+		break;
+	case VME_A24:
+		val |= TSI148_LCSR_DDAT_AMODE_A24;
+		break;
+	case VME_A32:
+		val |= TSI148_LCSR_DDAT_AMODE_A32;
+		break;
+	case VME_A64:
+		val |= TSI148_LCSR_DDAT_AMODE_A64;
+		break;
+	case VME_CRCSR:
+		val |= TSI148_LCSR_DDAT_AMODE_CRCSR;
+		break;
+	case VME_USER1:
+		val |= TSI148_LCSR_DDAT_AMODE_USER1;
+		break;
+	case VME_USER2:
+		val |= TSI148_LCSR_DDAT_AMODE_USER2;
+		break;
+	case VME_USER3:
+		val |= TSI148_LCSR_DDAT_AMODE_USER3;
+		break;
+	case VME_USER4:
+		val |= TSI148_LCSR_DDAT_AMODE_USER4;
+		break;
+	default:
+		dev_err(dev, "Invalid address space\n");
+		return -EINVAL;
+		break;
+	}
+
+	if (cycle & VME_SUPER)
+		val |= TSI148_LCSR_DDAT_SUP;
+	if (cycle & VME_PROG)
+		val |= TSI148_LCSR_DDAT_PGM;
+
+	*attr = cpu_to_be32(val);
+
+	return 0;
+}
+
+/*
+ * Add a link list descriptor to the list
+ *
+ * Note: DMA engine expects the DMA descriptor to be big endian.
+ */
+static int tsi148_dma_list_add(struct vme_dma_list *list,
+	struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
+{
+	struct tsi148_dma_entry *entry, *prev;
+	u32 address_high, address_low, val;
+	struct vme_dma_pattern *pattern_attr;
+	struct vme_dma_pci *pci_attr;
+	struct vme_dma_vme *vme_attr;
+	int retval = 0;
+	struct vme_bridge *tsi148_bridge;
+
+	tsi148_bridge = list->parent->parent;
+
+	/* Descriptor must be aligned on 64-bit boundaries */
+	entry = kmalloc(sizeof(struct tsi148_dma_entry), GFP_KERNEL);
+	if (entry == NULL) {
+		dev_err(tsi148_bridge->parent, "Failed to allocate memory for "
+			"dma resource structure\n");
+		retval = -ENOMEM;
+		goto err_mem;
+	}
+
+	/* Test descriptor alignment */
+	if ((unsigned long)&entry->descriptor & 0x7) {
+		dev_err(tsi148_bridge->parent, "Descriptor not aligned to 8 "
+			"byte boundary as required: %p\n",
+			&entry->descriptor);
+		retval = -EINVAL;
+		goto err_align;
+	}
+
+	/* Given we are going to fill out the structure, we probably don't
+	 * need to zero it, but better safe than sorry for now.
+	 */
+	memset(&entry->descriptor, 0, sizeof(struct tsi148_dma_descriptor));
+
+	/* Fill out source part */
+	switch (src->type) {
+	case VME_DMA_PATTERN:
+		pattern_attr = src->private;
+
+		entry->descriptor.dsal = cpu_to_be32(pattern_attr->pattern);
+
+		val = TSI148_LCSR_DSAT_TYP_PAT;
+
+		/* Default behaviour is 32 bit pattern */
+		if (pattern_attr->type & VME_DMA_PATTERN_BYTE)
+			val |= TSI148_LCSR_DSAT_PSZ;
+
+		/* It seems that the default behaviour is to increment */
+		if ((pattern_attr->type & VME_DMA_PATTERN_INCREMENT) == 0)
+			val |= TSI148_LCSR_DSAT_NIN;
+		entry->descriptor.dsat = cpu_to_be32(val);
+		break;
+	case VME_DMA_PCI:
+		pci_attr = src->private;
+
+		reg_split((unsigned long long)pci_attr->address, &address_high,
+			&address_low);
+		entry->descriptor.dsau = cpu_to_be32(address_high);
+		entry->descriptor.dsal = cpu_to_be32(address_low);
+		entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_PCI);
+		break;
+	case VME_DMA_VME:
+		vme_attr = src->private;
+
+		reg_split((unsigned long long)vme_attr->address, &address_high,
+			&address_low);
+		entry->descriptor.dsau = cpu_to_be32(address_high);
+		entry->descriptor.dsal = cpu_to_be32(address_low);
+		entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_VME);
+
+		retval = tsi148_dma_set_vme_src_attributes(
+			tsi148_bridge->parent, &entry->descriptor.dsat,
+			vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
+		if (retval < 0)
+			goto err_source;
+		break;
+	default:
+		dev_err(tsi148_bridge->parent, "Invalid source type\n");
+		retval = -EINVAL;
+		goto err_source;
+		break;
+	}
+
+	/* Assume last link - this will be over-written by adding another */
+	entry->descriptor.dnlau = cpu_to_be32(0);
+	entry->descriptor.dnlal = cpu_to_be32(TSI148_LCSR_DNLAL_LLA);
+
+	/* Fill out destination part */
+	switch (dest->type) {
+	case VME_DMA_PCI:
+		pci_attr = dest->private;
+
+		reg_split((unsigned long long)pci_attr->address, &address_high,
+			&address_low);
+		entry->descriptor.ddau = cpu_to_be32(address_high);
+		entry->descriptor.ddal = cpu_to_be32(address_low);
+		entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_PCI);
+		break;
+	case VME_DMA_VME:
+		vme_attr = dest->private;
+
+		reg_split((unsigned long long)vme_attr->address, &address_high,
+			&address_low);
+		entry->descriptor.ddau = cpu_to_be32(address_high);
+		entry->descriptor.ddal = cpu_to_be32(address_low);
+		entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_VME);
+
+		retval = tsi148_dma_set_vme_dest_attributes(
+			tsi148_bridge->parent, &entry->descriptor.ddat,
+			vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
+		if (retval < 0)
+			goto err_dest;
+		break;
+	default:
+		dev_err(tsi148_bridge->parent, "Invalid destination type\n");
+		retval = -EINVAL;
+		goto err_dest;
+		break;
+	}
+
+	/* Fill out count */
+	entry->descriptor.dcnt = cpu_to_be32((u32)count);
+
+	/* Add to list */
+	list_add_tail(&entry->list, &list->entries);
+
+	/* Fill out previous descriptors "Next Address" */
+	if (entry->list.prev != &list->entries) {
+		prev = list_entry(entry->list.prev, struct tsi148_dma_entry,
+			list);
+		/* We need the bus address for the pointer */
+		entry->dma_handle = dma_map_single(tsi148_bridge->parent,
+			&entry->descriptor,
+			sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
+
+		reg_split((unsigned long long)entry->dma_handle, &address_high,
+			&address_low);
+		entry->descriptor.dnlau = cpu_to_be32(address_high);
+		entry->descriptor.dnlal = cpu_to_be32(address_low);
+
+	}
+
+	return 0;
+
+err_dest:
+err_source:
+err_align:
+		kfree(entry);
+err_mem:
+	return retval;
+}
+
+/*
+ * Check to see if the provided DMA channel is busy.
+ */
+static int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel)
+{
+	u32 tmp;
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	tmp = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
+		TSI148_LCSR_OFFSET_DSTA);
+
+	if (tmp & TSI148_LCSR_DSTA_BSY)
+		return 0;
+	else
+		return 1;
+
+}
+
+/*
+ * Execute a previously generated link list
+ *
+ * XXX Need to provide control register configuration.
+ */
+static int tsi148_dma_list_exec(struct vme_dma_list *list)
+{
+	struct vme_dma_resource *ctrlr;
+	int channel, retval = 0;
+	struct tsi148_dma_entry *entry;
+	u32 bus_addr_high, bus_addr_low;
+	u32 val, dctlreg = 0;
+	struct vme_bridge *tsi148_bridge;
+	struct tsi148_driver *bridge;
+
+	ctrlr = list->parent;
+
+	tsi148_bridge = ctrlr->parent;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	mutex_lock(&ctrlr->mtx);
+
+	channel = ctrlr->number;
+
+	if (!list_empty(&ctrlr->running)) {
+		/*
+		 * XXX We have an active DMA transfer and currently haven't
+		 *     sorted out the mechanism for "pending" DMA transfers.
+		 *     Return busy.
+		 */
+		/* Need to add to pending here */
+		mutex_unlock(&ctrlr->mtx);
+		return -EBUSY;
+	} else {
+		list_add(&list->list, &ctrlr->running);
+	}
+
+	/* Get first bus address and write into registers */
+	entry = list_first_entry(&list->entries, struct tsi148_dma_entry,
+		list);
+
+	entry->dma_handle = dma_map_single(tsi148_bridge->parent,
+		&entry->descriptor,
+		sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
+
+	mutex_unlock(&ctrlr->mtx);
+
+	reg_split(entry->dma_handle, &bus_addr_high, &bus_addr_low);
+
+	iowrite32be(bus_addr_high, bridge->base +
+		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU);
+	iowrite32be(bus_addr_low, bridge->base +
+		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL);
+
+	dctlreg = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
+		TSI148_LCSR_OFFSET_DCTL);
+
+	/* Start the operation */
+	iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base +
+		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
+
+	wait_event_interruptible(bridge->dma_queue[channel],
+		tsi148_dma_busy(ctrlr->parent, channel));
+
+	/*
+	 * Read status register, this register is valid until we kick off a
+	 * new transfer.
+	 */
+	val = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
+		TSI148_LCSR_OFFSET_DSTA);
+
+	if (val & TSI148_LCSR_DSTA_VBE) {
+		dev_err(tsi148_bridge->parent, "DMA Error. DSTA=%08X\n", val);
+		retval = -EIO;
+	}
+
+	/* Remove list from running list */
+	mutex_lock(&ctrlr->mtx);
+	list_del(&list->list);
+	mutex_unlock(&ctrlr->mtx);
+
+	return retval;
+}
+
+/*
+ * Clean up a previously generated link list
+ *
+ * We have a separate function, don't assume that the chain can't be reused.
+ */
+static int tsi148_dma_list_empty(struct vme_dma_list *list)
+{
+	struct list_head *pos, *temp;
+	struct tsi148_dma_entry *entry;
+
+	struct vme_bridge *tsi148_bridge = list->parent->parent;
+
+	/* detach and free each entry */
+	list_for_each_safe(pos, temp, &list->entries) {
+		list_del(pos);
+		entry = list_entry(pos, struct tsi148_dma_entry, list);
+
+		dma_unmap_single(tsi148_bridge->parent, entry->dma_handle,
+			sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
+		kfree(entry);
+	}
+
+	return 0;
+}
+
+/*
+ * All 4 location monitors reside at the same base - this is therefore a
+ * system wide configuration.
+ *
+ * This does not enable the LM monitor - that should be done when the first
+ * callback is attached and disabled when the last callback is removed.
+ */
+static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
+	u32 aspace, u32 cycle)
+{
+	u32 lm_base_high, lm_base_low, lm_ctl = 0;
+	int i;
+	struct vme_bridge *tsi148_bridge;
+	struct tsi148_driver *bridge;
+
+	tsi148_bridge = lm->parent;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	mutex_lock(&lm->mtx);
+
+	/* If we already have a callback attached, we can't move it! */
+	for (i = 0; i < lm->monitors; i++) {
+		if (bridge->lm_callback[i] != NULL) {
+			mutex_unlock(&lm->mtx);
+			dev_err(tsi148_bridge->parent, "Location monitor "
+				"callback attached, can't reset\n");
+			return -EBUSY;
+		}
+	}
+
+	switch (aspace) {
+	case VME_A16:
+		lm_ctl |= TSI148_LCSR_LMAT_AS_A16;
+		break;
+	case VME_A24:
+		lm_ctl |= TSI148_LCSR_LMAT_AS_A24;
+		break;
+	case VME_A32:
+		lm_ctl |= TSI148_LCSR_LMAT_AS_A32;
+		break;
+	case VME_A64:
+		lm_ctl |= TSI148_LCSR_LMAT_AS_A64;
+		break;
+	default:
+		mutex_unlock(&lm->mtx);
+		dev_err(tsi148_bridge->parent, "Invalid address space\n");
+		return -EINVAL;
+		break;
+	}
+
+	if (cycle & VME_SUPER)
+		lm_ctl |= TSI148_LCSR_LMAT_SUPR ;
+	if (cycle & VME_USER)
+		lm_ctl |= TSI148_LCSR_LMAT_NPRIV;
+	if (cycle & VME_PROG)
+		lm_ctl |= TSI148_LCSR_LMAT_PGM;
+	if (cycle & VME_DATA)
+		lm_ctl |= TSI148_LCSR_LMAT_DATA;
+
+	reg_split(lm_base, &lm_base_high, &lm_base_low);
+
+	iowrite32be(lm_base_high, bridge->base + TSI148_LCSR_LMBAU);
+	iowrite32be(lm_base_low, bridge->base + TSI148_LCSR_LMBAL);
+	iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
+
+	mutex_unlock(&lm->mtx);
+
+	return 0;
+}
+
+/* Get configuration of the callback monitor and return whether it is enabled
+ * or disabled.
+ */
+static int tsi148_lm_get(struct vme_lm_resource *lm,
+	unsigned long long *lm_base, u32 *aspace, u32 *cycle)
+{
+	u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0;
+	struct tsi148_driver *bridge;
+
+	bridge = lm->parent->driver_priv;
+
+	mutex_lock(&lm->mtx);
+
+	lm_base_high = ioread32be(bridge->base + TSI148_LCSR_LMBAU);
+	lm_base_low = ioread32be(bridge->base + TSI148_LCSR_LMBAL);
+	lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
+
+	reg_join(lm_base_high, lm_base_low, lm_base);
+
+	if (lm_ctl & TSI148_LCSR_LMAT_EN)
+		enabled = 1;
+
+	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A16)
+		*aspace |= VME_A16;
+
+	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A24)
+		*aspace |= VME_A24;
+
+	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A32)
+		*aspace |= VME_A32;
+
+	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A64)
+		*aspace |= VME_A64;
+
+
+	if (lm_ctl & TSI148_LCSR_LMAT_SUPR)
+		*cycle |= VME_SUPER;
+	if (lm_ctl & TSI148_LCSR_LMAT_NPRIV)
+		*cycle |= VME_USER;
+	if (lm_ctl & TSI148_LCSR_LMAT_PGM)
+		*cycle |= VME_PROG;
+	if (lm_ctl & TSI148_LCSR_LMAT_DATA)
+		*cycle |= VME_DATA;
+
+	mutex_unlock(&lm->mtx);
+
+	return enabled;
+}
+
+/*
+ * Attach a callback to a specific location monitor.
+ *
+ * Callback will be passed the monitor triggered.
+ */
+static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
+	void (*callback)(int))
+{
+	u32 lm_ctl, tmp;
+	struct vme_bridge *tsi148_bridge;
+	struct tsi148_driver *bridge;
+
+	tsi148_bridge = lm->parent;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	mutex_lock(&lm->mtx);
+
+	/* Ensure that the location monitor is configured - need PGM or DATA */
+	lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
+	if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) {
+		mutex_unlock(&lm->mtx);
+		dev_err(tsi148_bridge->parent, "Location monitor not properly "
+			"configured\n");
+		return -EINVAL;
+	}
+
+	/* Check that a callback isn't already attached */
+	if (bridge->lm_callback[monitor] != NULL) {
+		mutex_unlock(&lm->mtx);
+		dev_err(tsi148_bridge->parent, "Existing callback attached\n");
+		return -EBUSY;
+	}
+
+	/* Attach callback */
+	bridge->lm_callback[monitor] = callback;
+
+	/* Enable Location Monitor interrupt */
+	tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
+	tmp |= TSI148_LCSR_INTEN_LMEN[monitor];
+	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
+
+	tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
+	tmp |= TSI148_LCSR_INTEO_LMEO[monitor];
+	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
+
+	/* Ensure that global Location Monitor Enable set */
+	if ((lm_ctl & TSI148_LCSR_LMAT_EN) == 0) {
+		lm_ctl |= TSI148_LCSR_LMAT_EN;
+		iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
+	}
+
+	mutex_unlock(&lm->mtx);
+
+	return 0;
+}
+
+/*
+ * Detach a callback function forn a specific location monitor.
+ */
+static int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
+{
+	u32 lm_en, tmp;
+	struct tsi148_driver *bridge;
+
+	bridge = lm->parent->driver_priv;
+
+	mutex_lock(&lm->mtx);
+
+	/* Disable Location Monitor and ensure previous interrupts are clear */
+	lm_en = ioread32be(bridge->base + TSI148_LCSR_INTEN);
+	lm_en &= ~TSI148_LCSR_INTEN_LMEN[monitor];
+	iowrite32be(lm_en, bridge->base + TSI148_LCSR_INTEN);
+
+	tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
+	tmp &= ~TSI148_LCSR_INTEO_LMEO[monitor];
+	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
+
+	iowrite32be(TSI148_LCSR_INTC_LMC[monitor],
+		 bridge->base + TSI148_LCSR_INTC);
+
+	/* Detach callback */
+	bridge->lm_callback[monitor] = NULL;
+
+	/* If all location monitors disabled, disable global Location Monitor */
+	if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S |
+			TSI148_LCSR_INTS_LM2S | TSI148_LCSR_INTS_LM3S)) == 0) {
+		tmp = ioread32be(bridge->base + TSI148_LCSR_LMAT);
+		tmp &= ~TSI148_LCSR_LMAT_EN;
+		iowrite32be(tmp, bridge->base + TSI148_LCSR_LMAT);
+	}
+
+	mutex_unlock(&lm->mtx);
+
+	return 0;
+}
+
+/*
+ * Determine Geographical Addressing
+ */
+static int tsi148_slot_get(struct vme_bridge *tsi148_bridge)
+{
+	u32 slot = 0;
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	if (!geoid) {
+		slot = ioread32be(bridge->base + TSI148_LCSR_VSTAT);
+		slot = slot & TSI148_LCSR_VSTAT_GA_M;
+	} else
+		slot = geoid;
+
+	return (int)slot;
+}
+
+static void *tsi148_alloc_consistent(struct device *parent, size_t size,
+	dma_addr_t *dma)
+{
+	struct pci_dev *pdev;
+
+	/* Find pci_dev container of dev */
+	pdev = container_of(parent, struct pci_dev, dev);
+
+	return pci_alloc_consistent(pdev, size, dma);
+}
+
+static void tsi148_free_consistent(struct device *parent, size_t size,
+	void *vaddr, dma_addr_t dma)
+{
+	struct pci_dev *pdev;
+
+	/* Find pci_dev container of dev */
+	pdev = container_of(parent, struct pci_dev, dev);
+
+	pci_free_consistent(pdev, size, vaddr, dma);
+}
+
+static int __init tsi148_init(void)
+{
+	return pci_register_driver(&tsi148_driver);
+}
+
+/*
+ * Configure CR/CSR space
+ *
+ * Access to the CR/CSR can be configured at power-up. The location of the
+ * CR/CSR registers in the CR/CSR address space is determined by the boards
+ * Auto-ID or Geographic address. This function ensures that the window is
+ * enabled at an offset consistent with the boards geopgraphic address.
+ *
+ * Each board has a 512kB window, with the highest 4kB being used for the
+ * boards registers, this means there is a fix length 508kB window which must
+ * be mapped onto PCI memory.
+ */
+static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge,
+	struct pci_dev *pdev)
+{
+	u32 cbar, crat, vstat;
+	u32 crcsr_bus_high, crcsr_bus_low;
+	int retval;
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	/* Allocate mem for CR/CSR image */
+	bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
+		&bridge->crcsr_bus);
+	if (bridge->crcsr_kernel == NULL) {
+		dev_err(tsi148_bridge->parent, "Failed to allocate memory for "
+			"CR/CSR image\n");
+		return -ENOMEM;
+	}
+
+	memset(bridge->crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
+
+	reg_split(bridge->crcsr_bus, &crcsr_bus_high, &crcsr_bus_low);
+
+	iowrite32be(crcsr_bus_high, bridge->base + TSI148_LCSR_CROU);
+	iowrite32be(crcsr_bus_low, bridge->base + TSI148_LCSR_CROL);
+
+	/* Ensure that the CR/CSR is configured at the correct offset */
+	cbar = ioread32be(bridge->base + TSI148_CBAR);
+	cbar = (cbar & TSI148_CRCSR_CBAR_M)>>3;
+
+	vstat = tsi148_slot_get(tsi148_bridge);
+
+	if (cbar != vstat) {
+		cbar = vstat;
+		dev_info(tsi148_bridge->parent, "Setting CR/CSR offset\n");
+		iowrite32be(cbar<<3, bridge->base + TSI148_CBAR);
+	}
+	dev_info(tsi148_bridge->parent, "CR/CSR Offset: %d\n", cbar);
+
+	crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
+	if (crat & TSI148_LCSR_CRAT_EN) {
+		dev_info(tsi148_bridge->parent, "Enabling CR/CSR space\n");
+		iowrite32be(crat | TSI148_LCSR_CRAT_EN,
+			bridge->base + TSI148_LCSR_CRAT);
+	} else
+		dev_info(tsi148_bridge->parent, "CR/CSR already enabled\n");
+
+	/* If we want flushed, error-checked writes, set up a window
+	 * over the CR/CSR registers. We read from here to safely flush
+	 * through VME writes.
+	 */
+	if (err_chk) {
+		retval = tsi148_master_set(bridge->flush_image, 1,
+			(vstat * 0x80000), 0x80000, VME_CRCSR, VME_SCT,
+			VME_D16);
+		if (retval)
+			dev_err(tsi148_bridge->parent, "Configuring flush image"
+				" failed\n");
+	}
+
+	return 0;
+
+}
+
+static void tsi148_crcsr_exit(struct vme_bridge *tsi148_bridge,
+	struct pci_dev *pdev)
+{
+	u32 crat;
+	struct tsi148_driver *bridge;
+
+	bridge = tsi148_bridge->driver_priv;
+
+	/* Turn off CR/CSR space */
+	crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
+	iowrite32be(crat & ~TSI148_LCSR_CRAT_EN,
+		bridge->base + TSI148_LCSR_CRAT);
+
+	/* Free image */
+	iowrite32be(0, bridge->base + TSI148_LCSR_CROU);
+	iowrite32be(0, bridge->base + TSI148_LCSR_CROL);
+
+	pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, bridge->crcsr_kernel,
+		bridge->crcsr_bus);
+}
+
+static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int retval, i, master_num;
+	u32 data;
+	struct list_head *pos = NULL;
+	struct vme_bridge *tsi148_bridge;
+	struct tsi148_driver *tsi148_device;
+	struct vme_master_resource *master_image;
+	struct vme_slave_resource *slave_image;
+	struct vme_dma_resource *dma_ctrlr;
+	struct vme_lm_resource *lm;
+
+	/* If we want to support more than one of each bridge, we need to
+	 * dynamically generate this so we get one per device
+	 */
+	tsi148_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL);
+	if (tsi148_bridge == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate memory for device "
+			"structure\n");
+		retval = -ENOMEM;
+		goto err_struct;
+	}
+
+	tsi148_device = kzalloc(sizeof(struct tsi148_driver), GFP_KERNEL);
+	if (tsi148_device == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate memory for device "
+			"structure\n");
+		retval = -ENOMEM;
+		goto err_driver;
+	}
+
+	tsi148_bridge->driver_priv = tsi148_device;
+
+	/* Enable the device */
+	retval = pci_enable_device(pdev);
+	if (retval) {
+		dev_err(&pdev->dev, "Unable to enable device\n");
+		goto err_enable;
+	}
+
+	/* Map Registers */
+	retval = pci_request_regions(pdev, driver_name);
+	if (retval) {
+		dev_err(&pdev->dev, "Unable to reserve resources\n");
+		goto err_resource;
+	}
+
+	/* map registers in BAR 0 */
+	tsi148_device->base = ioremap_nocache(pci_resource_start(pdev, 0),
+		4096);
+	if (!tsi148_device->base) {
+		dev_err(&pdev->dev, "Unable to remap CRG region\n");
+		retval = -EIO;
+		goto err_remap;
+	}
+
+	/* Check to see if the mapping worked out */
+	data = ioread32(tsi148_device->base + TSI148_PCFS_ID) & 0x0000FFFF;
+	if (data != PCI_VENDOR_ID_TUNDRA) {
+		dev_err(&pdev->dev, "CRG region check failed\n");
+		retval = -EIO;
+		goto err_test;
+	}
+
+	/* Initialize wait queues & mutual exclusion flags */
+	init_waitqueue_head(&tsi148_device->dma_queue[0]);
+	init_waitqueue_head(&tsi148_device->dma_queue[1]);
+	init_waitqueue_head(&tsi148_device->iack_queue);
+	mutex_init(&tsi148_device->vme_int);
+	mutex_init(&tsi148_device->vme_rmw);
+
+	tsi148_bridge->parent = &pdev->dev;
+	strcpy(tsi148_bridge->name, driver_name);
+
+	/* Setup IRQ */
+	retval = tsi148_irq_init(tsi148_bridge);
+	if (retval != 0) {
+		dev_err(&pdev->dev, "Chip Initialization failed.\n");
+		goto err_irq;
+	}
+
+	/* If we are going to flush writes, we need to read from the VME bus.
+	 * We need to do this safely, thus we read the devices own CR/CSR
+	 * register. To do this we must set up a window in CR/CSR space and
+	 * hence have one less master window resource available.
+	 */
+	master_num = TSI148_MAX_MASTER;
+	if (err_chk) {
+		master_num--;
+
+		tsi148_device->flush_image =
+			kmalloc(sizeof(struct vme_master_resource), GFP_KERNEL);
+		if (tsi148_device->flush_image == NULL) {
+			dev_err(&pdev->dev, "Failed to allocate memory for "
+			"flush resource structure\n");
+			retval = -ENOMEM;
+			goto err_master;
+		}
+		tsi148_device->flush_image->parent = tsi148_bridge;
+		spin_lock_init(&tsi148_device->flush_image->lock);
+		tsi148_device->flush_image->locked = 1;
+		tsi148_device->flush_image->number = master_num;
+		tsi148_device->flush_image->address_attr = VME_A16 | VME_A24 |
+			VME_A32 | VME_A64;
+		tsi148_device->flush_image->cycle_attr = VME_SCT | VME_BLT |
+			VME_MBLT | VME_2eVME | VME_2eSST | VME_2eSSTB |
+			VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER |
+			VME_USER | VME_PROG | VME_DATA;
+		tsi148_device->flush_image->width_attr = VME_D16 | VME_D32;
+		memset(&tsi148_device->flush_image->bus_resource, 0,
+			sizeof(struct resource));
+		tsi148_device->flush_image->kern_base  = NULL;
+	}
+
+	/* Add master windows to list */
+	INIT_LIST_HEAD(&tsi148_bridge->master_resources);
+	for (i = 0; i < master_num; i++) {
+		master_image = kmalloc(sizeof(struct vme_master_resource),
+			GFP_KERNEL);
+		if (master_image == NULL) {
+			dev_err(&pdev->dev, "Failed to allocate memory for "
+			"master resource structure\n");
+			retval = -ENOMEM;
+			goto err_master;
+		}
+		master_image->parent = tsi148_bridge;
+		spin_lock_init(&master_image->lock);
+		master_image->locked = 0;
+		master_image->number = i;
+		master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
+			VME_A64;
+		master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+			VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
+			VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
+			VME_PROG | VME_DATA;
+		master_image->width_attr = VME_D16 | VME_D32;
+		memset(&master_image->bus_resource, 0,
+			sizeof(struct resource));
+		master_image->kern_base  = NULL;
+		list_add_tail(&master_image->list,
+			&tsi148_bridge->master_resources);
+	}
+
+	/* Add slave windows to list */
+	INIT_LIST_HEAD(&tsi148_bridge->slave_resources);
+	for (i = 0; i < TSI148_MAX_SLAVE; i++) {
+		slave_image = kmalloc(sizeof(struct vme_slave_resource),
+			GFP_KERNEL);
+		if (slave_image == NULL) {
+			dev_err(&pdev->dev, "Failed to allocate memory for "
+			"slave resource structure\n");
+			retval = -ENOMEM;
+			goto err_slave;
+		}
+		slave_image->parent = tsi148_bridge;
+		mutex_init(&slave_image->mtx);
+		slave_image->locked = 0;
+		slave_image->number = i;
+		slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
+			VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
+			VME_USER3 | VME_USER4;
+		slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+			VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
+			VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
+			VME_PROG | VME_DATA;
+		list_add_tail(&slave_image->list,
+			&tsi148_bridge->slave_resources);
+	}
+
+	/* Add dma engines to list */
+	INIT_LIST_HEAD(&tsi148_bridge->dma_resources);
+	for (i = 0; i < TSI148_MAX_DMA; i++) {
+		dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource),
+			GFP_KERNEL);
+		if (dma_ctrlr == NULL) {
+			dev_err(&pdev->dev, "Failed to allocate memory for "
+			"dma resource structure\n");
+			retval = -ENOMEM;
+			goto err_dma;
+		}
+		dma_ctrlr->parent = tsi148_bridge;
+		mutex_init(&dma_ctrlr->mtx);
+		dma_ctrlr->locked = 0;
+		dma_ctrlr->number = i;
+		dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
+			VME_DMA_MEM_TO_VME | VME_DMA_VME_TO_VME |
+			VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME |
+			VME_DMA_PATTERN_TO_MEM;
+		INIT_LIST_HEAD(&dma_ctrlr->pending);
+		INIT_LIST_HEAD(&dma_ctrlr->running);
+		list_add_tail(&dma_ctrlr->list,
+			&tsi148_bridge->dma_resources);
+	}
+
+	/* Add location monitor to list */
+	INIT_LIST_HEAD(&tsi148_bridge->lm_resources);
+	lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
+	if (lm == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate memory for "
+		"location monitor resource structure\n");
+		retval = -ENOMEM;
+		goto err_lm;
+	}
+	lm->parent = tsi148_bridge;
+	mutex_init(&lm->mtx);
+	lm->locked = 0;
+	lm->number = 1;
+	lm->monitors = 4;
+	list_add_tail(&lm->list, &tsi148_bridge->lm_resources);
+
+	tsi148_bridge->slave_get = tsi148_slave_get;
+	tsi148_bridge->slave_set = tsi148_slave_set;
+	tsi148_bridge->master_get = tsi148_master_get;
+	tsi148_bridge->master_set = tsi148_master_set;
+	tsi148_bridge->master_read = tsi148_master_read;
+	tsi148_bridge->master_write = tsi148_master_write;
+	tsi148_bridge->master_rmw = tsi148_master_rmw;
+	tsi148_bridge->dma_list_add = tsi148_dma_list_add;
+	tsi148_bridge->dma_list_exec = tsi148_dma_list_exec;
+	tsi148_bridge->dma_list_empty = tsi148_dma_list_empty;
+	tsi148_bridge->irq_set = tsi148_irq_set;
+	tsi148_bridge->irq_generate = tsi148_irq_generate;
+	tsi148_bridge->lm_set = tsi148_lm_set;
+	tsi148_bridge->lm_get = tsi148_lm_get;
+	tsi148_bridge->lm_attach = tsi148_lm_attach;
+	tsi148_bridge->lm_detach = tsi148_lm_detach;
+	tsi148_bridge->slot_get = tsi148_slot_get;
+	tsi148_bridge->alloc_consistent = tsi148_alloc_consistent;
+	tsi148_bridge->free_consistent = tsi148_free_consistent;
+
+	data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
+	dev_info(&pdev->dev, "Board is%s the VME system controller\n",
+		(data & TSI148_LCSR_VSTAT_SCONS) ? "" : " not");
+	if (!geoid)
+		dev_info(&pdev->dev, "VME geographical address is %d\n",
+			data & TSI148_LCSR_VSTAT_GA_M);
+	else
+		dev_info(&pdev->dev, "VME geographical address is set to %d\n",
+			geoid);
+
+	dev_info(&pdev->dev, "VME Write and flush and error check is %s\n",
+		err_chk ? "enabled" : "disabled");
+
+	if (tsi148_crcsr_init(tsi148_bridge, pdev)) {
+		dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
+		goto err_crcsr;
+	}
+
+	retval = vme_register_bridge(tsi148_bridge);
+	if (retval != 0) {
+		dev_err(&pdev->dev, "Chip Registration failed.\n");
+		goto err_reg;
+	}
+
+	pci_set_drvdata(pdev, tsi148_bridge);
+
+	/* Clear VME bus "board fail", and "power-up reset" lines */
+	data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
+	data &= ~TSI148_LCSR_VSTAT_BRDFL;
+	data |= TSI148_LCSR_VSTAT_CPURST;
+	iowrite32be(data, tsi148_device->base + TSI148_LCSR_VSTAT);
+
+	return 0;
+
+err_reg:
+	tsi148_crcsr_exit(tsi148_bridge, pdev);
+err_crcsr:
+err_lm:
+	/* resources are stored in link list */
+	list_for_each(pos, &tsi148_bridge->lm_resources) {
+		lm = list_entry(pos, struct vme_lm_resource, list);
+		list_del(pos);
+		kfree(lm);
+	}
+err_dma:
+	/* resources are stored in link list */
+	list_for_each(pos, &tsi148_bridge->dma_resources) {
+		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
+		list_del(pos);
+		kfree(dma_ctrlr);
+	}
+err_slave:
+	/* resources are stored in link list */
+	list_for_each(pos, &tsi148_bridge->slave_resources) {
+		slave_image = list_entry(pos, struct vme_slave_resource, list);
+		list_del(pos);
+		kfree(slave_image);
+	}
+err_master:
+	/* resources are stored in link list */
+	list_for_each(pos, &tsi148_bridge->master_resources) {
+		master_image = list_entry(pos, struct vme_master_resource,
+			list);
+		list_del(pos);
+		kfree(master_image);
+	}
+
+	tsi148_irq_exit(tsi148_bridge, pdev);
+err_irq:
+err_test:
+	iounmap(tsi148_device->base);
+err_remap:
+	pci_release_regions(pdev);
+err_resource:
+	pci_disable_device(pdev);
+err_enable:
+	kfree(tsi148_device);
+err_driver:
+	kfree(tsi148_bridge);
+err_struct:
+	return retval;
+
+}
+
+static void tsi148_remove(struct pci_dev *pdev)
+{
+	struct list_head *pos = NULL;
+	struct list_head *tmplist;
+	struct vme_master_resource *master_image;
+	struct vme_slave_resource *slave_image;
+	struct vme_dma_resource *dma_ctrlr;
+	int i;
+	struct tsi148_driver *bridge;
+	struct vme_bridge *tsi148_bridge = pci_get_drvdata(pdev);
+
+	bridge = tsi148_bridge->driver_priv;
+
+
+	dev_dbg(&pdev->dev, "Driver is being unloaded.\n");
+
+	/*
+	 *  Shutdown all inbound and outbound windows.
+	 */
+	for (i = 0; i < 8; i++) {
+		iowrite32be(0, bridge->base + TSI148_LCSR_IT[i] +
+			TSI148_LCSR_OFFSET_ITAT);
+		iowrite32be(0, bridge->base + TSI148_LCSR_OT[i] +
+			TSI148_LCSR_OFFSET_OTAT);
+	}
+
+	/*
+	 *  Shutdown Location monitor.
+	 */
+	iowrite32be(0, bridge->base + TSI148_LCSR_LMAT);
+
+	/*
+	 *  Shutdown CRG map.
+	 */
+	iowrite32be(0, bridge->base + TSI148_LCSR_CSRAT);
+
+	/*
+	 *  Clear error status.
+	 */
+	iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_EDPAT);
+	iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_VEAT);
+	iowrite32be(0x07000700, bridge->base + TSI148_LCSR_PSTAT);
+
+	/*
+	 *  Remove VIRQ interrupt (if any)
+	 */
+	if (ioread32be(bridge->base + TSI148_LCSR_VICR) & 0x800)
+		iowrite32be(0x8000, bridge->base + TSI148_LCSR_VICR);
+
+	/*
+	 *  Map all Interrupts to PCI INTA
+	 */
+	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM1);
+	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM2);
+
+	tsi148_irq_exit(tsi148_bridge, pdev);
+
+	vme_unregister_bridge(tsi148_bridge);
+
+	tsi148_crcsr_exit(tsi148_bridge, pdev);
+
+	/* resources are stored in link list */
+	list_for_each_safe(pos, tmplist, &tsi148_bridge->dma_resources) {
+		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
+		list_del(pos);
+		kfree(dma_ctrlr);
+	}
+
+	/* resources are stored in link list */
+	list_for_each_safe(pos, tmplist, &tsi148_bridge->slave_resources) {
+		slave_image = list_entry(pos, struct vme_slave_resource, list);
+		list_del(pos);
+		kfree(slave_image);
+	}
+
+	/* resources are stored in link list */
+	list_for_each_safe(pos, tmplist, &tsi148_bridge->master_resources) {
+		master_image = list_entry(pos, struct vme_master_resource,
+			list);
+		list_del(pos);
+		kfree(master_image);
+	}
+
+	iounmap(bridge->base);
+
+	pci_release_regions(pdev);
+
+	pci_disable_device(pdev);
+
+	kfree(tsi148_bridge->driver_priv);
+
+	kfree(tsi148_bridge);
+}
+
+static void __exit tsi148_exit(void)
+{
+	pci_unregister_driver(&tsi148_driver);
+}
+
+MODULE_PARM_DESC(err_chk, "Check for VME errors on reads and writes");
+module_param(err_chk, bool, 0);
+
+MODULE_PARM_DESC(geoid, "Override geographical addressing");
+module_param(geoid, int, 0);
+
+MODULE_DESCRIPTION("VME driver for the Tundra Tempe VME bridge");
+MODULE_LICENSE("GPL");
+
+module_init(tsi148_init);
+module_exit(tsi148_exit);
diff --git a/drivers/vme/bridges/vme_tsi148.h b/drivers/vme/bridges/vme_tsi148.h
new file mode 100644
index 0000000..f5ed1438
--- /dev/null
+++ b/drivers/vme/bridges/vme_tsi148.h
@@ -0,0 +1,1410 @@
+/*
+ * tsi148.h
+ *
+ * Support for the Tundra TSI148 VME Bridge chip
+ *
+ * Author: Tom Armistead
+ * Updated and maintained by Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * 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 TSI148_H
+#define TSI148_H
+
+#ifndef	PCI_VENDOR_ID_TUNDRA
+#define	PCI_VENDOR_ID_TUNDRA 0x10e3
+#endif
+
+#ifndef	PCI_DEVICE_ID_TUNDRA_TSI148
+#define	PCI_DEVICE_ID_TUNDRA_TSI148 0x148
+#endif
+
+/*
+ *  Define the number of each that the Tsi148 supports.
+ */
+#define TSI148_MAX_MASTER		8	/* Max Master Windows */
+#define TSI148_MAX_SLAVE		8	/* Max Slave Windows */
+#define TSI148_MAX_DMA			2	/* Max DMA Controllers */
+#define TSI148_MAX_MAILBOX		4	/* Max Mail Box registers */
+#define TSI148_MAX_SEMAPHORE		8	/* Max Semaphores */
+
+/* Structure used to hold driver specific information */
+struct tsi148_driver {
+	void __iomem *base;	/* Base Address of device registers */
+	wait_queue_head_t dma_queue[2];
+	wait_queue_head_t iack_queue;
+	void (*lm_callback[4])(int);	/* Called in interrupt handler */
+	void *crcsr_kernel;
+	dma_addr_t crcsr_bus;
+	struct vme_master_resource *flush_image;
+	struct mutex vme_rmw;		/* Only one RMW cycle at a time */
+	struct mutex vme_int;		/*
+					 * Only one VME interrupt can be
+					 * generated at a time, provide locking
+					 */
+};
+
+/*
+ * Layout of a DMAC Linked-List Descriptor
+ *
+ * Note: This structure is accessed via the chip and therefore must be
+ *       correctly laid out - It must also be aligned on 64-bit boundaries.
+ */
+struct tsi148_dma_descriptor {
+	__be32 dsau;      /* Source Address */
+	__be32 dsal;
+	__be32 ddau;      /* Destination Address */
+	__be32 ddal;
+	__be32 dsat;      /* Source attributes */
+	__be32 ddat;      /* Destination attributes */
+	__be32 dnlau;     /* Next link address */
+	__be32 dnlal;
+	__be32 dcnt;      /* Byte count */
+	__be32 ddbs;      /* 2eSST Broadcast select */
+};
+
+struct tsi148_dma_entry {
+	/*
+	 * The descriptor needs to be aligned on a 64-bit boundary, we increase
+	 * the chance of this by putting it first in the structure.
+	 */
+	struct tsi148_dma_descriptor descriptor;
+	struct list_head list;
+	dma_addr_t dma_handle;
+};
+
+/*
+ *  TSI148 ASIC register structure overlays and bit field definitions.
+ *
+ *      Note:   Tsi148 Register Group (CRG) consists of the following
+ *              combination of registers:
+ *                      PCFS    - PCI Configuration Space Registers
+ *                      LCSR    - Local Control and Status Registers
+ *                      GCSR    - Global Control and Status Registers
+ *                      CR/CSR  - Subset of Configuration ROM /
+ *                                Control and Status Registers
+ */
+
+
+/*
+ *  Command/Status Registers (CRG + $004)
+ */
+#define TSI148_PCFS_ID			0x0
+#define TSI148_PCFS_CSR			0x4
+#define TSI148_PCFS_CLASS		0x8
+#define TSI148_PCFS_MISC0		0xC
+#define TSI148_PCFS_MBARL		0x10
+#define TSI148_PCFS_MBARU		0x14
+
+#define TSI148_PCFS_SUBID		0x28
+
+#define TSI148_PCFS_CAPP		0x34
+
+#define TSI148_PCFS_MISC1		0x3C
+
+#define TSI148_PCFS_XCAPP		0x40
+#define TSI148_PCFS_XSTAT		0x44
+
+/*
+ * LCSR definitions
+ */
+
+/*
+ *    Outbound Translations
+ */
+#define TSI148_LCSR_OT0_OTSAU		0x100
+#define TSI148_LCSR_OT0_OTSAL		0x104
+#define TSI148_LCSR_OT0_OTEAU		0x108
+#define TSI148_LCSR_OT0_OTEAL		0x10C
+#define TSI148_LCSR_OT0_OTOFU		0x110
+#define TSI148_LCSR_OT0_OTOFL		0x114
+#define TSI148_LCSR_OT0_OTBS		0x118
+#define TSI148_LCSR_OT0_OTAT		0x11C
+
+#define TSI148_LCSR_OT1_OTSAU		0x120
+#define TSI148_LCSR_OT1_OTSAL		0x124
+#define TSI148_LCSR_OT1_OTEAU		0x128
+#define TSI148_LCSR_OT1_OTEAL		0x12C
+#define TSI148_LCSR_OT1_OTOFU		0x130
+#define TSI148_LCSR_OT1_OTOFL		0x134
+#define TSI148_LCSR_OT1_OTBS		0x138
+#define TSI148_LCSR_OT1_OTAT		0x13C
+
+#define TSI148_LCSR_OT2_OTSAU		0x140
+#define TSI148_LCSR_OT2_OTSAL		0x144
+#define TSI148_LCSR_OT2_OTEAU		0x148
+#define TSI148_LCSR_OT2_OTEAL		0x14C
+#define TSI148_LCSR_OT2_OTOFU		0x150
+#define TSI148_LCSR_OT2_OTOFL		0x154
+#define TSI148_LCSR_OT2_OTBS		0x158
+#define TSI148_LCSR_OT2_OTAT		0x15C
+
+#define TSI148_LCSR_OT3_OTSAU		0x160
+#define TSI148_LCSR_OT3_OTSAL		0x164
+#define TSI148_LCSR_OT3_OTEAU		0x168
+#define TSI148_LCSR_OT3_OTEAL		0x16C
+#define TSI148_LCSR_OT3_OTOFU		0x170
+#define TSI148_LCSR_OT3_OTOFL		0x174
+#define TSI148_LCSR_OT3_OTBS		0x178
+#define TSI148_LCSR_OT3_OTAT		0x17C
+
+#define TSI148_LCSR_OT4_OTSAU		0x180
+#define TSI148_LCSR_OT4_OTSAL		0x184
+#define TSI148_LCSR_OT4_OTEAU		0x188
+#define TSI148_LCSR_OT4_OTEAL		0x18C
+#define TSI148_LCSR_OT4_OTOFU		0x190
+#define TSI148_LCSR_OT4_OTOFL		0x194
+#define TSI148_LCSR_OT4_OTBS		0x198
+#define TSI148_LCSR_OT4_OTAT		0x19C
+
+#define TSI148_LCSR_OT5_OTSAU		0x1A0
+#define TSI148_LCSR_OT5_OTSAL		0x1A4
+#define TSI148_LCSR_OT5_OTEAU		0x1A8
+#define TSI148_LCSR_OT5_OTEAL		0x1AC
+#define TSI148_LCSR_OT5_OTOFU		0x1B0
+#define TSI148_LCSR_OT5_OTOFL		0x1B4
+#define TSI148_LCSR_OT5_OTBS		0x1B8
+#define TSI148_LCSR_OT5_OTAT		0x1BC
+
+#define TSI148_LCSR_OT6_OTSAU		0x1C0
+#define TSI148_LCSR_OT6_OTSAL		0x1C4
+#define TSI148_LCSR_OT6_OTEAU		0x1C8
+#define TSI148_LCSR_OT6_OTEAL		0x1CC
+#define TSI148_LCSR_OT6_OTOFU		0x1D0
+#define TSI148_LCSR_OT6_OTOFL		0x1D4
+#define TSI148_LCSR_OT6_OTBS		0x1D8
+#define TSI148_LCSR_OT6_OTAT		0x1DC
+
+#define TSI148_LCSR_OT7_OTSAU		0x1E0
+#define TSI148_LCSR_OT7_OTSAL		0x1E4
+#define TSI148_LCSR_OT7_OTEAU		0x1E8
+#define TSI148_LCSR_OT7_OTEAL		0x1EC
+#define TSI148_LCSR_OT7_OTOFU		0x1F0
+#define TSI148_LCSR_OT7_OTOFL		0x1F4
+#define TSI148_LCSR_OT7_OTBS		0x1F8
+#define TSI148_LCSR_OT7_OTAT		0x1FC
+
+#define TSI148_LCSR_OT0		0x100
+#define TSI148_LCSR_OT1		0x120
+#define TSI148_LCSR_OT2		0x140
+#define TSI148_LCSR_OT3		0x160
+#define TSI148_LCSR_OT4		0x180
+#define TSI148_LCSR_OT5		0x1A0
+#define TSI148_LCSR_OT6		0x1C0
+#define TSI148_LCSR_OT7		0x1E0
+
+static const int TSI148_LCSR_OT[8] = { TSI148_LCSR_OT0, TSI148_LCSR_OT1,
+					 TSI148_LCSR_OT2, TSI148_LCSR_OT3,
+					 TSI148_LCSR_OT4, TSI148_LCSR_OT5,
+					 TSI148_LCSR_OT6, TSI148_LCSR_OT7 };
+
+#define TSI148_LCSR_OFFSET_OTSAU	0x0
+#define TSI148_LCSR_OFFSET_OTSAL	0x4
+#define TSI148_LCSR_OFFSET_OTEAU	0x8
+#define TSI148_LCSR_OFFSET_OTEAL	0xC
+#define TSI148_LCSR_OFFSET_OTOFU	0x10
+#define TSI148_LCSR_OFFSET_OTOFL	0x14
+#define TSI148_LCSR_OFFSET_OTBS		0x18
+#define TSI148_LCSR_OFFSET_OTAT		0x1C
+
+/*
+ * VMEbus interrupt ack
+ * offset  200
+ */
+#define TSI148_LCSR_VIACK1	0x204
+#define TSI148_LCSR_VIACK2	0x208
+#define TSI148_LCSR_VIACK3	0x20C
+#define TSI148_LCSR_VIACK4	0x210
+#define TSI148_LCSR_VIACK5	0x214
+#define TSI148_LCSR_VIACK6	0x218
+#define TSI148_LCSR_VIACK7	0x21C
+
+static const int TSI148_LCSR_VIACK[8] = { 0, TSI148_LCSR_VIACK1,
+				TSI148_LCSR_VIACK2, TSI148_LCSR_VIACK3,
+				TSI148_LCSR_VIACK4, TSI148_LCSR_VIACK5,
+				TSI148_LCSR_VIACK6, TSI148_LCSR_VIACK7 };
+
+/*
+ * RMW
+ * offset    220
+ */
+#define TSI148_LCSR_RMWAU	0x220
+#define TSI148_LCSR_RMWAL	0x224
+#define TSI148_LCSR_RMWEN	0x228
+#define TSI148_LCSR_RMWC	0x22C
+#define TSI148_LCSR_RMWS	0x230
+
+/*
+ * VMEbus control
+ * offset    234
+ */
+#define TSI148_LCSR_VMCTRL	0x234
+#define TSI148_LCSR_VCTRL	0x238
+#define TSI148_LCSR_VSTAT	0x23C
+
+/*
+ * PCI status
+ * offset  240
+ */
+#define TSI148_LCSR_PSTAT	0x240
+
+/*
+ * VME filter.
+ * offset  250
+ */
+#define TSI148_LCSR_VMEFL	0x250
+
+	/*
+	 * VME exception.
+	 * offset  260
+ */
+#define TSI148_LCSR_VEAU	0x260
+#define TSI148_LCSR_VEAL	0x264
+#define TSI148_LCSR_VEAT	0x268
+
+	/*
+	 * PCI error
+	 * offset  270
+	 */
+#define TSI148_LCSR_EDPAU	0x270
+#define TSI148_LCSR_EDPAL	0x274
+#define TSI148_LCSR_EDPXA	0x278
+#define TSI148_LCSR_EDPXS	0x27C
+#define TSI148_LCSR_EDPAT	0x280
+
+	/*
+	 * Inbound Translations
+	 * offset  300
+	 */
+#define TSI148_LCSR_IT0_ITSAU		0x300
+#define TSI148_LCSR_IT0_ITSAL		0x304
+#define TSI148_LCSR_IT0_ITEAU		0x308
+#define TSI148_LCSR_IT0_ITEAL		0x30C
+#define TSI148_LCSR_IT0_ITOFU		0x310
+#define TSI148_LCSR_IT0_ITOFL		0x314
+#define TSI148_LCSR_IT0_ITAT		0x318
+
+#define TSI148_LCSR_IT1_ITSAU		0x320
+#define TSI148_LCSR_IT1_ITSAL		0x324
+#define TSI148_LCSR_IT1_ITEAU		0x328
+#define TSI148_LCSR_IT1_ITEAL		0x32C
+#define TSI148_LCSR_IT1_ITOFU		0x330
+#define TSI148_LCSR_IT1_ITOFL		0x334
+#define TSI148_LCSR_IT1_ITAT		0x338
+
+#define TSI148_LCSR_IT2_ITSAU		0x340
+#define TSI148_LCSR_IT2_ITSAL		0x344
+#define TSI148_LCSR_IT2_ITEAU		0x348
+#define TSI148_LCSR_IT2_ITEAL		0x34C
+#define TSI148_LCSR_IT2_ITOFU		0x350
+#define TSI148_LCSR_IT2_ITOFL		0x354
+#define TSI148_LCSR_IT2_ITAT		0x358
+
+#define TSI148_LCSR_IT3_ITSAU		0x360
+#define TSI148_LCSR_IT3_ITSAL		0x364
+#define TSI148_LCSR_IT3_ITEAU		0x368
+#define TSI148_LCSR_IT3_ITEAL		0x36C
+#define TSI148_LCSR_IT3_ITOFU		0x370
+#define TSI148_LCSR_IT3_ITOFL		0x374
+#define TSI148_LCSR_IT3_ITAT		0x378
+
+#define TSI148_LCSR_IT4_ITSAU		0x380
+#define TSI148_LCSR_IT4_ITSAL		0x384
+#define TSI148_LCSR_IT4_ITEAU		0x388
+#define TSI148_LCSR_IT4_ITEAL		0x38C
+#define TSI148_LCSR_IT4_ITOFU		0x390
+#define TSI148_LCSR_IT4_ITOFL		0x394
+#define TSI148_LCSR_IT4_ITAT		0x398
+
+#define TSI148_LCSR_IT5_ITSAU		0x3A0
+#define TSI148_LCSR_IT5_ITSAL		0x3A4
+#define TSI148_LCSR_IT5_ITEAU		0x3A8
+#define TSI148_LCSR_IT5_ITEAL		0x3AC
+#define TSI148_LCSR_IT5_ITOFU		0x3B0
+#define TSI148_LCSR_IT5_ITOFL		0x3B4
+#define TSI148_LCSR_IT5_ITAT		0x3B8
+
+#define TSI148_LCSR_IT6_ITSAU		0x3C0
+#define TSI148_LCSR_IT6_ITSAL		0x3C4
+#define TSI148_LCSR_IT6_ITEAU		0x3C8
+#define TSI148_LCSR_IT6_ITEAL		0x3CC
+#define TSI148_LCSR_IT6_ITOFU		0x3D0
+#define TSI148_LCSR_IT6_ITOFL		0x3D4
+#define TSI148_LCSR_IT6_ITAT		0x3D8
+
+#define TSI148_LCSR_IT7_ITSAU		0x3E0
+#define TSI148_LCSR_IT7_ITSAL		0x3E4
+#define TSI148_LCSR_IT7_ITEAU		0x3E8
+#define TSI148_LCSR_IT7_ITEAL		0x3EC
+#define TSI148_LCSR_IT7_ITOFU		0x3F0
+#define TSI148_LCSR_IT7_ITOFL		0x3F4
+#define TSI148_LCSR_IT7_ITAT		0x3F8
+
+
+#define TSI148_LCSR_IT0		0x300
+#define TSI148_LCSR_IT1		0x320
+#define TSI148_LCSR_IT2		0x340
+#define TSI148_LCSR_IT3		0x360
+#define TSI148_LCSR_IT4		0x380
+#define TSI148_LCSR_IT5		0x3A0
+#define TSI148_LCSR_IT6		0x3C0
+#define TSI148_LCSR_IT7		0x3E0
+
+static const int TSI148_LCSR_IT[8] = { TSI148_LCSR_IT0, TSI148_LCSR_IT1,
+					 TSI148_LCSR_IT2, TSI148_LCSR_IT3,
+					 TSI148_LCSR_IT4, TSI148_LCSR_IT5,
+					 TSI148_LCSR_IT6, TSI148_LCSR_IT7 };
+
+#define TSI148_LCSR_OFFSET_ITSAU	0x0
+#define TSI148_LCSR_OFFSET_ITSAL	0x4
+#define TSI148_LCSR_OFFSET_ITEAU	0x8
+#define TSI148_LCSR_OFFSET_ITEAL	0xC
+#define TSI148_LCSR_OFFSET_ITOFU	0x10
+#define TSI148_LCSR_OFFSET_ITOFL	0x14
+#define TSI148_LCSR_OFFSET_ITAT		0x18
+
+	/*
+	 * Inbound Translation GCSR
+	 * offset  400
+	 */
+#define TSI148_LCSR_GBAU	0x400
+#define TSI148_LCSR_GBAL	0x404
+#define TSI148_LCSR_GCSRAT	0x408
+
+	/*
+	 * Inbound Translation CRG
+	 * offset  40C
+	 */
+#define TSI148_LCSR_CBAU	0x40C
+#define TSI148_LCSR_CBAL	0x410
+#define TSI148_LCSR_CSRAT	0x414
+
+	/*
+	 * Inbound Translation CR/CSR
+	 *         CRG
+	 * offset  418
+	 */
+#define TSI148_LCSR_CROU	0x418
+#define TSI148_LCSR_CROL	0x41C
+#define TSI148_LCSR_CRAT	0x420
+
+	/*
+	 * Inbound Translation Location Monitor
+	 * offset  424
+	 */
+#define TSI148_LCSR_LMBAU	0x424
+#define TSI148_LCSR_LMBAL	0x428
+#define TSI148_LCSR_LMAT	0x42C
+
+	/*
+	 * VMEbus Interrupt Control.
+	 * offset  430
+	 */
+#define TSI148_LCSR_BCU		0x430
+#define TSI148_LCSR_BCL		0x434
+#define TSI148_LCSR_BPGTR	0x438
+#define TSI148_LCSR_BPCTR	0x43C
+#define TSI148_LCSR_VICR	0x440
+
+	/*
+	 * Local Bus Interrupt Control.
+	 * offset  448
+	 */
+#define TSI148_LCSR_INTEN	0x448
+#define TSI148_LCSR_INTEO	0x44C
+#define TSI148_LCSR_INTS	0x450
+#define TSI148_LCSR_INTC	0x454
+#define TSI148_LCSR_INTM1	0x458
+#define TSI148_LCSR_INTM2	0x45C
+
+	/*
+	 * DMA Controllers
+	 * offset 500
+	 */
+#define TSI148_LCSR_DCTL0	0x500
+#define TSI148_LCSR_DSTA0	0x504
+#define TSI148_LCSR_DCSAU0	0x508
+#define TSI148_LCSR_DCSAL0	0x50C
+#define TSI148_LCSR_DCDAU0	0x510
+#define TSI148_LCSR_DCDAL0	0x514
+#define TSI148_LCSR_DCLAU0	0x518
+#define TSI148_LCSR_DCLAL0	0x51C
+#define TSI148_LCSR_DSAU0	0x520
+#define TSI148_LCSR_DSAL0	0x524
+#define TSI148_LCSR_DDAU0	0x528
+#define TSI148_LCSR_DDAL0	0x52C
+#define TSI148_LCSR_DSAT0	0x530
+#define TSI148_LCSR_DDAT0	0x534
+#define TSI148_LCSR_DNLAU0	0x538
+#define TSI148_LCSR_DNLAL0	0x53C
+#define TSI148_LCSR_DCNT0	0x540
+#define TSI148_LCSR_DDBS0	0x544
+
+#define TSI148_LCSR_DCTL1	0x580
+#define TSI148_LCSR_DSTA1	0x584
+#define TSI148_LCSR_DCSAU1	0x588
+#define TSI148_LCSR_DCSAL1	0x58C
+#define TSI148_LCSR_DCDAU1	0x590
+#define TSI148_LCSR_DCDAL1	0x594
+#define TSI148_LCSR_DCLAU1	0x598
+#define TSI148_LCSR_DCLAL1	0x59C
+#define TSI148_LCSR_DSAU1	0x5A0
+#define TSI148_LCSR_DSAL1	0x5A4
+#define TSI148_LCSR_DDAU1	0x5A8
+#define TSI148_LCSR_DDAL1	0x5AC
+#define TSI148_LCSR_DSAT1	0x5B0
+#define TSI148_LCSR_DDAT1	0x5B4
+#define TSI148_LCSR_DNLAU1	0x5B8
+#define TSI148_LCSR_DNLAL1	0x5BC
+#define TSI148_LCSR_DCNT1	0x5C0
+#define TSI148_LCSR_DDBS1	0x5C4
+
+#define TSI148_LCSR_DMA0	0x500
+#define TSI148_LCSR_DMA1	0x580
+
+
+static const int TSI148_LCSR_DMA[TSI148_MAX_DMA] = { TSI148_LCSR_DMA0,
+						TSI148_LCSR_DMA1 };
+
+#define TSI148_LCSR_OFFSET_DCTL		0x0
+#define TSI148_LCSR_OFFSET_DSTA		0x4
+#define TSI148_LCSR_OFFSET_DCSAU	0x8
+#define TSI148_LCSR_OFFSET_DCSAL	0xC
+#define TSI148_LCSR_OFFSET_DCDAU	0x10
+#define TSI148_LCSR_OFFSET_DCDAL	0x14
+#define TSI148_LCSR_OFFSET_DCLAU	0x18
+#define TSI148_LCSR_OFFSET_DCLAL	0x1C
+#define TSI148_LCSR_OFFSET_DSAU		0x20
+#define TSI148_LCSR_OFFSET_DSAL		0x24
+#define TSI148_LCSR_OFFSET_DDAU		0x28
+#define TSI148_LCSR_OFFSET_DDAL		0x2C
+#define TSI148_LCSR_OFFSET_DSAT		0x30
+#define TSI148_LCSR_OFFSET_DDAT		0x34
+#define TSI148_LCSR_OFFSET_DNLAU	0x38
+#define TSI148_LCSR_OFFSET_DNLAL	0x3C
+#define TSI148_LCSR_OFFSET_DCNT		0x40
+#define TSI148_LCSR_OFFSET_DDBS		0x44
+
+	/*
+	 * GCSR Register Group
+	 */
+
+	/*
+	 *         GCSR    CRG
+	 * offset   00     600 - DEVI/VENI
+	 * offset   04     604 - CTRL/GA/REVID
+	 * offset   08     608 - Semaphore3/2/1/0
+	 * offset   0C     60C - Seamphore7/6/5/4
+	 */
+#define TSI148_GCSR_ID		0x600
+#define TSI148_GCSR_CSR		0x604
+#define TSI148_GCSR_SEMA0	0x608
+#define TSI148_GCSR_SEMA1	0x60C
+
+	/*
+	 * Mail Box
+	 *         GCSR    CRG
+	 * offset   10     610 - Mailbox0
+	 */
+#define TSI148_GCSR_MBOX0	0x610
+#define TSI148_GCSR_MBOX1	0x614
+#define TSI148_GCSR_MBOX2	0x618
+#define TSI148_GCSR_MBOX3	0x61C
+
+static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0,
+					TSI148_GCSR_MBOX1,
+					TSI148_GCSR_MBOX2,
+					TSI148_GCSR_MBOX3 };
+
+	/*
+	 * CR/CSR
+	 */
+
+	/*
+	 *        CR/CSR   CRG
+	 * offset  7FFF4   FF4 - CSRBCR
+	 * offset  7FFF8   FF8 - CSRBSR
+	 * offset  7FFFC   FFC - CBAR
+	 */
+#define TSI148_CSRBCR	0xFF4
+#define TSI148_CSRBSR	0xFF8
+#define TSI148_CBAR	0xFFC
+
+
+
+
+	/*
+	 *  TSI148 Register Bit Definitions
+	 */
+
+	/*
+	 *  PFCS Register Set
+	 */
+#define TSI148_PCFS_CMMD_SERR          (1<<8)	/* SERR_L out pin ssys err */
+#define TSI148_PCFS_CMMD_PERR          (1<<6)	/* PERR_L out pin  parity */
+#define TSI148_PCFS_CMMD_MSTR          (1<<2)	/* PCI bus master */
+#define TSI148_PCFS_CMMD_MEMSP         (1<<1)	/* PCI mem space access  */
+#define TSI148_PCFS_CMMD_IOSP          (1<<0)	/* PCI I/O space enable */
+
+#define TSI148_PCFS_STAT_RCPVE         (1<<15)	/* Detected Parity Error */
+#define TSI148_PCFS_STAT_SIGSE         (1<<14)	/* Signalled System Error */
+#define TSI148_PCFS_STAT_RCVMA         (1<<13)	/* Received Master Abort */
+#define TSI148_PCFS_STAT_RCVTA         (1<<12)	/* Received Target Abort */
+#define TSI148_PCFS_STAT_SIGTA         (1<<11)	/* Signalled Target Abort */
+#define TSI148_PCFS_STAT_SELTIM        (3<<9)	/* DELSEL Timing */
+#define TSI148_PCFS_STAT_DPAR          (1<<8)	/* Data Parity Err Reported */
+#define TSI148_PCFS_STAT_FAST          (1<<7)	/* Fast back-to-back Cap */
+#define TSI148_PCFS_STAT_P66M          (1<<5)	/* 66 MHz Capable */
+#define TSI148_PCFS_STAT_CAPL          (1<<4)	/* Capab List - address $34 */
+
+/*
+ *  Revision ID/Class Code Registers   (CRG +$008)
+ */
+#define TSI148_PCFS_CLAS_M             (0xFF<<24)	/* Class ID */
+#define TSI148_PCFS_SUBCLAS_M          (0xFF<<16)	/* Sub-Class ID */
+#define TSI148_PCFS_PROGIF_M           (0xFF<<8)	/* Sub-Class ID */
+#define TSI148_PCFS_REVID_M            (0xFF<<0)	/* Rev ID */
+
+/*
+ * Cache Line Size/ Master Latency Timer/ Header Type Registers (CRG + $00C)
+ */
+#define TSI148_PCFS_HEAD_M             (0xFF<<16)	/* Master Lat Timer */
+#define TSI148_PCFS_MLAT_M             (0xFF<<8)	/* Master Lat Timer */
+#define TSI148_PCFS_CLSZ_M             (0xFF<<0)	/* Cache Line Size */
+
+/*
+ *  Memory Base Address Lower Reg (CRG + $010)
+ */
+#define TSI148_PCFS_MBARL_BASEL_M      (0xFFFFF<<12) /* Base Addr Lower Mask */
+#define TSI148_PCFS_MBARL_PRE          (1<<3)	/* Prefetch */
+#define TSI148_PCFS_MBARL_MTYPE_M      (3<<1)	/* Memory Type Mask */
+#define TSI148_PCFS_MBARL_IOMEM        (1<<0)	/* I/O Space Indicator */
+
+/*
+ *  Message Signaled Interrupt Capabilities Register (CRG + $040)
+ */
+#define TSI148_PCFS_MSICAP_64BAC       (1<<7)	/* 64-bit Address Capable */
+#define TSI148_PCFS_MSICAP_MME_M       (7<<4)	/* Multiple Msg Enable Mask */
+#define TSI148_PCFS_MSICAP_MMC_M       (7<<1)	/* Multiple Msg Capable Mask */
+#define TSI148_PCFS_MSICAP_MSIEN       (1<<0)	/* Msg signaled INT Enable */
+
+/*
+ *  Message Address Lower Register (CRG +$044)
+ */
+#define TSI148_PCFS_MSIAL_M            (0x3FFFFFFF<<2)	/* Mask */
+
+/*
+ *  Message Data Register (CRG + 4C)
+ */
+#define TSI148_PCFS_MSIMD_M            (0xFFFF<<0)	/* Mask */
+
+/*
+ *  PCI-X Capabilities Register (CRG + $050)
+ */
+#define TSI148_PCFS_PCIXCAP_MOST_M     (7<<4)	/* Max outstanding Split Tran */
+#define TSI148_PCFS_PCIXCAP_MMRBC_M    (3<<2)	/* Max Mem Read byte cnt */
+#define TSI148_PCFS_PCIXCAP_ERO        (1<<1)	/* Enable Relaxed Ordering */
+#define TSI148_PCFS_PCIXCAP_DPERE      (1<<0)	/* Data Parity Recover Enable */
+
+/*
+ *  PCI-X Status Register (CRG +$054)
+ */
+#define TSI148_PCFS_PCIXSTAT_RSCEM     (1<<29)	/* Received Split Comp Error */
+#define TSI148_PCFS_PCIXSTAT_DMCRS_M   (7<<26)	/* max Cumulative Read Size */
+#define TSI148_PCFS_PCIXSTAT_DMOST_M   (7<<23)	/* max outstanding Split Trans
+						 */
+#define TSI148_PCFS_PCIXSTAT_DMMRC_M   (3<<21)	/* max mem read byte count */
+#define TSI148_PCFS_PCIXSTAT_DC        (1<<20)	/* Device Complexity */
+#define TSI148_PCFS_PCIXSTAT_USC       (1<<19)	/* Unexpected Split comp */
+#define TSI148_PCFS_PCIXSTAT_SCD       (1<<18)	/* Split completion discard */
+#define TSI148_PCFS_PCIXSTAT_133C      (1<<17)	/* 133MHz capable */
+#define TSI148_PCFS_PCIXSTAT_64D       (1<<16)	/* 64 bit device */
+#define TSI148_PCFS_PCIXSTAT_BN_M      (0xFF<<8)	/* Bus number */
+#define TSI148_PCFS_PCIXSTAT_DN_M      (0x1F<<3)	/* Device number */
+#define TSI148_PCFS_PCIXSTAT_FN_M      (7<<0)	/* Function Number */
+
+/*
+ *  LCSR Registers
+ */
+
+/*
+ *  Outbound Translation Starting Address Lower
+ */
+#define TSI148_LCSR_OTSAL_M            (0xFFFF<<16)	/* Mask */
+
+/*
+ *  Outbound Translation Ending Address Lower
+ */
+#define TSI148_LCSR_OTEAL_M            (0xFFFF<<16)	/* Mask */
+
+/*
+ *  Outbound Translation Offset Lower
+ */
+#define TSI148_LCSR_OTOFFL_M           (0xFFFF<<16)	/* Mask */
+
+/*
+ *  Outbound Translation 2eSST Broadcast Select
+ */
+#define TSI148_LCSR_OTBS_M             (0xFFFFF<<0)	/* Mask */
+
+/*
+ *  Outbound Translation Attribute
+ */
+#define TSI148_LCSR_OTAT_EN            (1<<31)	/* Window Enable */
+#define TSI148_LCSR_OTAT_MRPFD         (1<<18)	/* Prefetch Disable */
+
+#define TSI148_LCSR_OTAT_PFS_M         (3<<16)	/* Prefetch Size Mask */
+#define TSI148_LCSR_OTAT_PFS_2         (0<<16)	/* 2 Cache Lines P Size */
+#define TSI148_LCSR_OTAT_PFS_4         (1<<16)	/* 4 Cache Lines P Size */
+#define TSI148_LCSR_OTAT_PFS_8         (2<<16)	/* 8 Cache Lines P Size */
+#define TSI148_LCSR_OTAT_PFS_16        (3<<16)	/* 16 Cache Lines P Size */
+
+#define TSI148_LCSR_OTAT_2eSSTM_M      (7<<11)	/* 2eSST Xfer Rate Mask */
+#define TSI148_LCSR_OTAT_2eSSTM_160    (0<<11)	/* 160MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_OTAT_2eSSTM_267    (1<<11)	/* 267MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_OTAT_2eSSTM_320    (2<<11)	/* 320MB/s 2eSST Xfer Rate */
+
+#define TSI148_LCSR_OTAT_TM_M          (7<<8)	/* Xfer Protocol Mask */
+#define TSI148_LCSR_OTAT_TM_SCT        (0<<8)	/* SCT Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_BLT        (1<<8)	/* BLT Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_MBLT       (2<<8)	/* MBLT Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_2eVME      (3<<8)	/* 2eVME Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_2eSST      (4<<8)	/* 2eSST Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_2eSSTB     (5<<8)	/* 2eSST Bcast Xfer Protocol */
+
+#define TSI148_LCSR_OTAT_DBW_M         (3<<6)	/* Max Data Width */
+#define TSI148_LCSR_OTAT_DBW_16        (0<<6)	/* 16-bit Data Width */
+#define TSI148_LCSR_OTAT_DBW_32        (1<<6)	/* 32-bit Data Width */
+
+#define TSI148_LCSR_OTAT_SUP           (1<<5)	/* Supervisory Access */
+#define TSI148_LCSR_OTAT_PGM           (1<<4)	/* Program Access */
+
+#define TSI148_LCSR_OTAT_AMODE_M       (0xf<<0)	/* Address Mode Mask */
+#define TSI148_LCSR_OTAT_AMODE_A16     (0<<0)	/* A16 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_A24     (1<<0)	/* A24 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_A32     (2<<0)	/* A32 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_A64     (4<<0)	/* A32 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_CRCSR   (5<<0)	/* CR/CSR Address Space */
+#define TSI148_LCSR_OTAT_AMODE_USER1   (8<<0)	/* User1 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_USER2   (9<<0)	/* User2 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_USER3   (10<<0)	/* User3 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_USER4   (11<<0)	/* User4 Address Space */
+
+/*
+ *  VME Master Control Register  CRG+$234
+ */
+#define TSI148_LCSR_VMCTRL_VSA         (1<<27)	/* VMEbus Stop Ack */
+#define TSI148_LCSR_VMCTRL_VS          (1<<26)	/* VMEbus Stop */
+#define TSI148_LCSR_VMCTRL_DHB         (1<<25)	/* Device Has Bus */
+#define TSI148_LCSR_VMCTRL_DWB         (1<<24)	/* Device Wants Bus */
+
+#define TSI148_LCSR_VMCTRL_RMWEN       (1<<20)	/* RMW Enable */
+
+#define TSI148_LCSR_VMCTRL_ATO_M       (7<<16)	/* Master Access Time-out Mask
+						 */
+#define TSI148_LCSR_VMCTRL_ATO_32      (0<<16)	/* 32 us */
+#define TSI148_LCSR_VMCTRL_ATO_128     (1<<16)	/* 128 us */
+#define TSI148_LCSR_VMCTRL_ATO_512     (2<<16)	/* 512 us */
+#define TSI148_LCSR_VMCTRL_ATO_2M      (3<<16)	/* 2 ms */
+#define TSI148_LCSR_VMCTRL_ATO_8M      (4<<16)	/* 8 ms */
+#define TSI148_LCSR_VMCTRL_ATO_32M     (5<<16)	/* 32 ms */
+#define TSI148_LCSR_VMCTRL_ATO_128M    (6<<16)	/* 128 ms */
+#define TSI148_LCSR_VMCTRL_ATO_DIS     (7<<16)	/* Disabled */
+
+#define TSI148_LCSR_VMCTRL_VTOFF_M     (7<<12)	/* VMEbus Master Time off */
+#define TSI148_LCSR_VMCTRL_VTOFF_0     (0<<12)	/* 0us */
+#define TSI148_LCSR_VMCTRL_VTOFF_1     (1<<12)	/* 1us */
+#define TSI148_LCSR_VMCTRL_VTOFF_2     (2<<12)	/* 2us */
+#define TSI148_LCSR_VMCTRL_VTOFF_4     (3<<12)	/* 4us */
+#define TSI148_LCSR_VMCTRL_VTOFF_8     (4<<12)	/* 8us */
+#define TSI148_LCSR_VMCTRL_VTOFF_16    (5<<12)	/* 16us */
+#define TSI148_LCSR_VMCTRL_VTOFF_32    (6<<12)	/* 32us */
+#define TSI148_LCSR_VMCTRL_VTOFF_64    (7<<12)	/* 64us */
+
+#define TSI148_LCSR_VMCTRL_VTON_M      (7<<8)	/* VMEbus Master Time On */
+#define TSI148_LCSR_VMCTRL_VTON_4      (0<<8)	/* 8us */
+#define TSI148_LCSR_VMCTRL_VTON_8      (1<<8)	/* 8us */
+#define TSI148_LCSR_VMCTRL_VTON_16     (2<<8)	/* 16us */
+#define TSI148_LCSR_VMCTRL_VTON_32     (3<<8)	/* 32us */
+#define TSI148_LCSR_VMCTRL_VTON_64     (4<<8)	/* 64us */
+#define TSI148_LCSR_VMCTRL_VTON_128    (5<<8)	/* 128us */
+#define TSI148_LCSR_VMCTRL_VTON_256    (6<<8)	/* 256us */
+#define TSI148_LCSR_VMCTRL_VTON_512    (7<<8)	/* 512us */
+
+#define TSI148_LCSR_VMCTRL_VREL_M      (3<<3)	/* VMEbus Master Rel Mode Mask
+						 */
+#define TSI148_LCSR_VMCTRL_VREL_T_D    (0<<3)	/* Time on or Done */
+#define TSI148_LCSR_VMCTRL_VREL_T_R_D  (1<<3)	/* Time on and REQ or Done */
+#define TSI148_LCSR_VMCTRL_VREL_T_B_D  (2<<3)	/* Time on and BCLR or Done */
+#define TSI148_LCSR_VMCTRL_VREL_T_D_R  (3<<3)	/* Time on or Done and REQ */
+
+#define TSI148_LCSR_VMCTRL_VFAIR       (1<<2)	/* VMEbus Master Fair Mode */
+#define TSI148_LCSR_VMCTRL_VREQL_M     (3<<0)	/* VMEbus Master Req Level Mask
+						 */
+
+/*
+ *  VMEbus Control Register CRG+$238
+ */
+#define TSI148_LCSR_VCTRL_LRE          (1<<31)	/* Late Retry Enable */
+
+#define TSI148_LCSR_VCTRL_DLT_M        (0xF<<24)	/* Deadlock Timer */
+#define TSI148_LCSR_VCTRL_DLT_OFF      (0<<24)	/* Deadlock Timer Off */
+#define TSI148_LCSR_VCTRL_DLT_16       (1<<24)	/* 16 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_32       (2<<24)	/* 32 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_64       (3<<24)	/* 64 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_128      (4<<24)	/* 128 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_256      (5<<24)	/* 256 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_512      (6<<24)	/* 512 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_1024     (7<<24)	/* 1024 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_2048     (8<<24)	/* 2048 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_4096     (9<<24)	/* 4096 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_8192     (0xA<<24)	/* 8192 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_16384    (0xB<<24)	/* 16384 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_32768    (0xC<<24)	/* 32768 VCLKS */
+
+#define TSI148_LCSR_VCTRL_NERBB        (1<<20)	/* No Early Release of Bus Busy
+						 */
+
+#define TSI148_LCSR_VCTRL_SRESET       (1<<17)	/* System Reset */
+#define TSI148_LCSR_VCTRL_LRESET       (1<<16)	/* Local Reset */
+
+#define TSI148_LCSR_VCTRL_SFAILAI      (1<<15)	/* SYSFAIL Auto Slot ID */
+#define TSI148_LCSR_VCTRL_BID_M        (0x1F<<8)	/* Broadcast ID Mask */
+
+#define TSI148_LCSR_VCTRL_ATOEN        (1<<7)	/* Arbiter Time-out Enable */
+#define TSI148_LCSR_VCTRL_ROBIN        (1<<6)	/* VMEbus Round Robin */
+
+#define TSI148_LCSR_VCTRL_GTO_M        (7<<0)	/* VMEbus Global Time-out Mask
+						 */
+#define TSI148_LCSR_VCTRL_GTO_8	      (0<<0)	/* 8 us */
+#define TSI148_LCSR_VCTRL_GTO_16	      (1<<0)	/* 16 us */
+#define TSI148_LCSR_VCTRL_GTO_32	      (2<<0)	/* 32 us */
+#define TSI148_LCSR_VCTRL_GTO_64	      (3<<0)	/* 64 us */
+#define TSI148_LCSR_VCTRL_GTO_128      (4<<0)	/* 128 us */
+#define TSI148_LCSR_VCTRL_GTO_256      (5<<0)	/* 256 us */
+#define TSI148_LCSR_VCTRL_GTO_512      (6<<0)	/* 512 us */
+#define TSI148_LCSR_VCTRL_GTO_DIS      (7<<0)	/* Disabled */
+
+/*
+ *  VMEbus Status Register  CRG + $23C
+ */
+#define TSI148_LCSR_VSTAT_CPURST       (1<<15)	/* Clear power up reset */
+#define TSI148_LCSR_VSTAT_BRDFL        (1<<14)	/* Board fail */
+#define TSI148_LCSR_VSTAT_PURSTS       (1<<12)	/* Power up reset status */
+#define TSI148_LCSR_VSTAT_BDFAILS      (1<<11)	/* Board Fail Status */
+#define TSI148_LCSR_VSTAT_SYSFAILS     (1<<10)	/* System Fail Status */
+#define TSI148_LCSR_VSTAT_ACFAILS      (1<<9)	/* AC fail status */
+#define TSI148_LCSR_VSTAT_SCONS        (1<<8)	/* System Cont Status */
+#define TSI148_LCSR_VSTAT_GAP          (1<<5)	/* Geographic Addr Parity */
+#define TSI148_LCSR_VSTAT_GA_M         (0x1F<<0)  /* Geographic Addr Mask */
+
+/*
+ *  PCI Configuration Status Register CRG+$240
+ */
+#define TSI148_LCSR_PSTAT_REQ64S       (1<<6)	/* Request 64 status set */
+#define TSI148_LCSR_PSTAT_M66ENS       (1<<5)	/* M66ENS 66Mhz enable */
+#define TSI148_LCSR_PSTAT_FRAMES       (1<<4)	/* Frame Status */
+#define TSI148_LCSR_PSTAT_IRDYS        (1<<3)	/* IRDY status */
+#define TSI148_LCSR_PSTAT_DEVSELS      (1<<2)	/* DEVL status */
+#define TSI148_LCSR_PSTAT_STOPS        (1<<1)	/* STOP status */
+#define TSI148_LCSR_PSTAT_TRDYS        (1<<0)	/* TRDY status */
+
+/*
+ *  VMEbus Exception Attributes Register  CRG + $268
+ */
+#define TSI148_LCSR_VEAT_VES           (1<<31)	/* Status */
+#define TSI148_LCSR_VEAT_VEOF          (1<<30)	/* Overflow */
+#define TSI148_LCSR_VEAT_VESCL         (1<<29)	/* Status Clear */
+#define TSI148_LCSR_VEAT_2EOT          (1<<21)	/* 2e Odd Termination */
+#define TSI148_LCSR_VEAT_2EST          (1<<20)	/* 2e Slave terminated */
+#define TSI148_LCSR_VEAT_BERR          (1<<19)	/* Bus Error */
+#define TSI148_LCSR_VEAT_LWORD         (1<<18)	/* LWORD_ signal state */
+#define TSI148_LCSR_VEAT_WRITE         (1<<17)	/* WRITE_ signal state */
+#define TSI148_LCSR_VEAT_IACK          (1<<16)	/* IACK_ signal state */
+#define TSI148_LCSR_VEAT_DS1           (1<<15)	/* DS1_ signal state */
+#define TSI148_LCSR_VEAT_DS0           (1<<14)	/* DS0_ signal state */
+#define TSI148_LCSR_VEAT_AM_M          (0x3F<<8)	/* Address Mode Mask */
+#define TSI148_LCSR_VEAT_XAM_M         (0xFF<<0)	/* Master AMode Mask */
+
+
+/*
+ * VMEbus PCI Error Diagnostics PCI/X Attributes Register  CRG + $280
+ */
+#define TSI148_LCSR_EDPAT_EDPCL        (1<<29)
+
+/*
+ *  Inbound Translation Starting Address Lower
+ */
+#define TSI148_LCSR_ITSAL6432_M        (0xFFFF<<16)	/* Mask */
+#define TSI148_LCSR_ITSAL24_M          (0x00FFF<<12)	/* Mask */
+#define TSI148_LCSR_ITSAL16_M          (0x0000FFF<<4)	/* Mask */
+
+/*
+ *  Inbound Translation Ending Address Lower
+ */
+#define TSI148_LCSR_ITEAL6432_M        (0xFFFF<<16)	/* Mask */
+#define TSI148_LCSR_ITEAL24_M          (0x00FFF<<12)	/* Mask */
+#define TSI148_LCSR_ITEAL16_M          (0x0000FFF<<4)	/* Mask */
+
+/*
+ *  Inbound Translation Offset Lower
+ */
+#define TSI148_LCSR_ITOFFL6432_M       (0xFFFF<<16)	/* Mask */
+#define TSI148_LCSR_ITOFFL24_M         (0xFFFFF<<12)	/* Mask */
+#define TSI148_LCSR_ITOFFL16_M         (0xFFFFFFF<<4)	/* Mask */
+
+/*
+ *  Inbound Translation Attribute
+ */
+#define TSI148_LCSR_ITAT_EN            (1<<31)	/* Window Enable */
+#define TSI148_LCSR_ITAT_TH            (1<<18)	/* Prefetch Threshold */
+
+#define TSI148_LCSR_ITAT_VFS_M         (3<<16)	/* Virtual FIFO Size Mask */
+#define TSI148_LCSR_ITAT_VFS_64        (0<<16)	/* 64 bytes Virtual FIFO Size */
+#define TSI148_LCSR_ITAT_VFS_128       (1<<16)	/* 128 bytes Virtual FIFO Sz */
+#define TSI148_LCSR_ITAT_VFS_256       (2<<16)	/* 256 bytes Virtual FIFO Sz */
+#define TSI148_LCSR_ITAT_VFS_512       (3<<16)	/* 512 bytes Virtual FIFO Sz */
+
+#define TSI148_LCSR_ITAT_2eSSTM_M      (7<<12)	/* 2eSST Xfer Rate Mask */
+#define TSI148_LCSR_ITAT_2eSSTM_160    (0<<12)	/* 160MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_ITAT_2eSSTM_267    (1<<12)	/* 267MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_ITAT_2eSSTM_320    (2<<12)	/* 320MB/s 2eSST Xfer Rate */
+
+#define TSI148_LCSR_ITAT_2eSSTB        (1<<11)	/* 2eSST Bcast Xfer Protocol */
+#define TSI148_LCSR_ITAT_2eSST         (1<<10)	/* 2eSST Xfer Protocol */
+#define TSI148_LCSR_ITAT_2eVME         (1<<9)	/* 2eVME Xfer Protocol */
+#define TSI148_LCSR_ITAT_MBLT          (1<<8)	/* MBLT Xfer Protocol */
+#define TSI148_LCSR_ITAT_BLT           (1<<7)	/* BLT Xfer Protocol */
+
+#define TSI148_LCSR_ITAT_AS_M          (7<<4)	/* Address Space Mask */
+#define TSI148_LCSR_ITAT_AS_A16        (0<<4)	/* A16 Address Space */
+#define TSI148_LCSR_ITAT_AS_A24        (1<<4)	/* A24 Address Space */
+#define TSI148_LCSR_ITAT_AS_A32        (2<<4)	/* A32 Address Space */
+#define TSI148_LCSR_ITAT_AS_A64        (4<<4)	/* A64 Address Space */
+
+#define TSI148_LCSR_ITAT_SUPR          (1<<3)	/* Supervisor Access */
+#define TSI148_LCSR_ITAT_NPRIV         (1<<2)	/* Non-Priv (User) Access */
+#define TSI148_LCSR_ITAT_PGM           (1<<1)	/* Program Access */
+#define TSI148_LCSR_ITAT_DATA          (1<<0)	/* Data Access */
+
+/*
+ *  GCSR Base Address Lower Address  CRG +$404
+ */
+#define TSI148_LCSR_GBAL_M             (0x7FFFFFF<<5)	/* Mask */
+
+/*
+ *  GCSR Attribute Register CRG + $408
+ */
+#define TSI148_LCSR_GCSRAT_EN          (1<<7)	/* Enable access to GCSR */
+
+#define TSI148_LCSR_GCSRAT_AS_M        (7<<4)	/* Address Space Mask */
+#define TSI148_LCSR_GCSRAT_AS_A16       (0<<4)	/* Address Space 16 */
+#define TSI148_LCSR_GCSRAT_AS_A24       (1<<4)	/* Address Space 24 */
+#define TSI148_LCSR_GCSRAT_AS_A32       (2<<4)	/* Address Space 32 */
+#define TSI148_LCSR_GCSRAT_AS_A64       (4<<4)	/* Address Space 64 */
+
+#define TSI148_LCSR_GCSRAT_SUPR        (1<<3)	/* Sup set -GCSR decoder */
+#define TSI148_LCSR_GCSRAT_NPRIV       (1<<2)	/* Non-Privliged set - CGSR */
+#define TSI148_LCSR_GCSRAT_PGM         (1<<1)	/* Program set - GCSR decoder */
+#define TSI148_LCSR_GCSRAT_DATA        (1<<0)	/* DATA set GCSR decoder */
+
+/*
+ *  CRG Base Address Lower Address  CRG + $410
+ */
+#define TSI148_LCSR_CBAL_M             (0xFFFFF<<12)
+
+/*
+ *  CRG Attribute Register  CRG + $414
+ */
+#define TSI148_LCSR_CRGAT_EN           (1<<7)	/* Enable PRG Access */
+
+#define TSI148_LCSR_CRGAT_AS_M         (7<<4)	/* Address Space */
+#define TSI148_LCSR_CRGAT_AS_A16       (0<<4)	/* Address Space 16 */
+#define TSI148_LCSR_CRGAT_AS_A24       (1<<4)	/* Address Space 24 */
+#define TSI148_LCSR_CRGAT_AS_A32       (2<<4)	/* Address Space 32 */
+#define TSI148_LCSR_CRGAT_AS_A64       (4<<4)	/* Address Space 64 */
+
+#define TSI148_LCSR_CRGAT_SUPR         (1<<3)	/* Supervisor Access */
+#define TSI148_LCSR_CRGAT_NPRIV        (1<<2)	/* Non-Privliged(User) Access */
+#define TSI148_LCSR_CRGAT_PGM          (1<<1)	/* Program Access */
+#define TSI148_LCSR_CRGAT_DATA         (1<<0)	/* Data Access */
+
+/*
+ *  CR/CSR Offset Lower Register  CRG + $41C
+ */
+#define TSI148_LCSR_CROL_M             (0x1FFF<<19)	/* Mask */
+
+/*
+ *  CR/CSR Attribute register  CRG + $420
+ */
+#define TSI148_LCSR_CRAT_EN            (1<<7)	/* Enable access to CR/CSR */
+
+/*
+ *  Location Monitor base address lower register  CRG + $428
+ */
+#define TSI148_LCSR_LMBAL_M            (0x7FFFFFF<<5)	/* Mask */
+
+/*
+ *  Location Monitor Attribute Register  CRG + $42C
+ */
+#define TSI148_LCSR_LMAT_EN            (1<<7)	/* Enable Location Monitor */
+
+#define TSI148_LCSR_LMAT_AS_M          (7<<4)	/* Address Space MASK  */
+#define TSI148_LCSR_LMAT_AS_A16        (0<<4)	/* A16 */
+#define TSI148_LCSR_LMAT_AS_A24        (1<<4)	/* A24 */
+#define TSI148_LCSR_LMAT_AS_A32        (2<<4)	/* A32 */
+#define TSI148_LCSR_LMAT_AS_A64        (4<<4)	/* A64 */
+
+#define TSI148_LCSR_LMAT_SUPR          (1<<3)	/* Supervisor Access */
+#define TSI148_LCSR_LMAT_NPRIV         (1<<2)	/* Non-Priv (User) Access */
+#define TSI148_LCSR_LMAT_PGM           (1<<1)	/* Program Access */
+#define TSI148_LCSR_LMAT_DATA          (1<<0)	/* Data Access  */
+
+/*
+ *  Broadcast Pulse Generator Timer Register  CRG + $438
+ */
+#define TSI148_LCSR_BPGTR_BPGT_M       (0xFFFF<<0)	/* Mask */
+
+/*
+ *  Broadcast Programmable Clock Timer Register  CRG + $43C
+ */
+#define TSI148_LCSR_BPCTR_BPCT_M       (0xFFFFFF<<0)	/* Mask */
+
+/*
+ *  VMEbus Interrupt Control Register           CRG + $43C
+ */
+#define TSI148_LCSR_VICR_CNTS_M        (3<<22)	/* Cntr Source MASK */
+#define TSI148_LCSR_VICR_CNTS_DIS      (1<<22)	/* Cntr Disable */
+#define TSI148_LCSR_VICR_CNTS_IRQ1     (2<<22)	/* IRQ1 to Cntr */
+#define TSI148_LCSR_VICR_CNTS_IRQ2     (3<<22)	/* IRQ2 to Cntr */
+
+#define TSI148_LCSR_VICR_EDGIS_M       (3<<20)	/* Edge interrupt MASK */
+#define TSI148_LCSR_VICR_EDGIS_DIS     (1<<20)	/* Edge interrupt Disable */
+#define TSI148_LCSR_VICR_EDGIS_IRQ1    (2<<20)	/* IRQ1 to Edge */
+#define TSI148_LCSR_VICR_EDGIS_IRQ2    (3<<20)	/* IRQ2 to Edge */
+
+#define TSI148_LCSR_VICR_IRQIF_M       (3<<18)	/* IRQ1* Function MASK */
+#define TSI148_LCSR_VICR_IRQIF_NORM    (1<<18)	/* Normal */
+#define TSI148_LCSR_VICR_IRQIF_PULSE   (2<<18)	/* Pulse Generator */
+#define TSI148_LCSR_VICR_IRQIF_PROG    (3<<18)	/* Programmable Clock */
+#define TSI148_LCSR_VICR_IRQIF_1U      (4<<18)	/* 1us Clock */
+
+#define TSI148_LCSR_VICR_IRQ2F_M       (3<<16)	/* IRQ2* Function MASK */
+#define TSI148_LCSR_VICR_IRQ2F_NORM    (1<<16)	/* Normal */
+#define TSI148_LCSR_VICR_IRQ2F_PULSE   (2<<16)	/* Pulse Generator */
+#define TSI148_LCSR_VICR_IRQ2F_PROG    (3<<16)	/* Programmable Clock */
+#define TSI148_LCSR_VICR_IRQ2F_1U      (4<<16)	/* 1us Clock */
+
+#define TSI148_LCSR_VICR_BIP           (1<<15)	/* Broadcast Interrupt Pulse */
+
+#define TSI148_LCSR_VICR_IRQC          (1<<12)	/* VMEbus IRQ Clear */
+#define TSI148_LCSR_VICR_IRQS          (1<<11)	/* VMEbus IRQ Status */
+
+#define TSI148_LCSR_VICR_IRQL_M        (7<<8)	/* VMEbus SW IRQ Level Mask */
+#define TSI148_LCSR_VICR_IRQL_1        (1<<8)	/* VMEbus SW IRQ Level 1 */
+#define TSI148_LCSR_VICR_IRQL_2        (2<<8)	/* VMEbus SW IRQ Level 2 */
+#define TSI148_LCSR_VICR_IRQL_3        (3<<8)	/* VMEbus SW IRQ Level 3 */
+#define TSI148_LCSR_VICR_IRQL_4        (4<<8)	/* VMEbus SW IRQ Level 4 */
+#define TSI148_LCSR_VICR_IRQL_5        (5<<8)	/* VMEbus SW IRQ Level 5 */
+#define TSI148_LCSR_VICR_IRQL_6        (6<<8)	/* VMEbus SW IRQ Level 6 */
+#define TSI148_LCSR_VICR_IRQL_7        (7<<8)	/* VMEbus SW IRQ Level 7 */
+
+static const int TSI148_LCSR_VICR_IRQL[8] = { 0, TSI148_LCSR_VICR_IRQL_1,
+			TSI148_LCSR_VICR_IRQL_2, TSI148_LCSR_VICR_IRQL_3,
+			TSI148_LCSR_VICR_IRQL_4, TSI148_LCSR_VICR_IRQL_5,
+			TSI148_LCSR_VICR_IRQL_6, TSI148_LCSR_VICR_IRQL_7 };
+
+#define TSI148_LCSR_VICR_STID_M        (0xFF<<0)	/* Status/ID Mask */
+
+/*
+ *  Interrupt Enable Register   CRG + $440
+ */
+#define TSI148_LCSR_INTEN_DMA1EN       (1<<25)	/* DMAC 1 */
+#define TSI148_LCSR_INTEN_DMA0EN       (1<<24)	/* DMAC 0 */
+#define TSI148_LCSR_INTEN_LM3EN        (1<<23)	/* Location Monitor 3 */
+#define TSI148_LCSR_INTEN_LM2EN        (1<<22)	/* Location Monitor 2 */
+#define TSI148_LCSR_INTEN_LM1EN        (1<<21)	/* Location Monitor 1 */
+#define TSI148_LCSR_INTEN_LM0EN        (1<<20)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTEN_MB3EN        (1<<19)	/* Mail Box 3 */
+#define TSI148_LCSR_INTEN_MB2EN        (1<<18)	/* Mail Box 2 */
+#define TSI148_LCSR_INTEN_MB1EN        (1<<17)	/* Mail Box 1 */
+#define TSI148_LCSR_INTEN_MB0EN        (1<<16)	/* Mail Box 0 */
+#define TSI148_LCSR_INTEN_PERREN       (1<<13)	/* PCI/X Error */
+#define TSI148_LCSR_INTEN_VERREN       (1<<12)	/* VMEbus Error */
+#define TSI148_LCSR_INTEN_VIEEN        (1<<11)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTEN_IACKEN       (1<<10)	/* IACK */
+#define TSI148_LCSR_INTEN_SYSFLEN      (1<<9)	/* System Fail */
+#define TSI148_LCSR_INTEN_ACFLEN       (1<<8)	/* AC Fail */
+#define TSI148_LCSR_INTEN_IRQ7EN       (1<<7)	/* IRQ7 */
+#define TSI148_LCSR_INTEN_IRQ6EN       (1<<6)	/* IRQ6 */
+#define TSI148_LCSR_INTEN_IRQ5EN       (1<<5)	/* IRQ5 */
+#define TSI148_LCSR_INTEN_IRQ4EN       (1<<4)	/* IRQ4 */
+#define TSI148_LCSR_INTEN_IRQ3EN       (1<<3)	/* IRQ3 */
+#define TSI148_LCSR_INTEN_IRQ2EN       (1<<2)	/* IRQ2 */
+#define TSI148_LCSR_INTEN_IRQ1EN       (1<<1)	/* IRQ1 */
+
+static const int TSI148_LCSR_INTEN_LMEN[4] = { TSI148_LCSR_INTEN_LM0EN,
+					TSI148_LCSR_INTEN_LM1EN,
+					TSI148_LCSR_INTEN_LM2EN,
+					TSI148_LCSR_INTEN_LM3EN };
+
+static const int TSI148_LCSR_INTEN_IRQEN[7] = { TSI148_LCSR_INTEN_IRQ1EN,
+					TSI148_LCSR_INTEN_IRQ2EN,
+					TSI148_LCSR_INTEN_IRQ3EN,
+					TSI148_LCSR_INTEN_IRQ4EN,
+					TSI148_LCSR_INTEN_IRQ5EN,
+					TSI148_LCSR_INTEN_IRQ6EN,
+					TSI148_LCSR_INTEN_IRQ7EN };
+
+/*
+ *  Interrupt Enable Out Register CRG + $444
+ */
+#define TSI148_LCSR_INTEO_DMA1EO       (1<<25)	/* DMAC 1 */
+#define TSI148_LCSR_INTEO_DMA0EO       (1<<24)	/* DMAC 0 */
+#define TSI148_LCSR_INTEO_LM3EO        (1<<23)	/* Loc Monitor 3 */
+#define TSI148_LCSR_INTEO_LM2EO        (1<<22)	/* Loc Monitor 2 */
+#define TSI148_LCSR_INTEO_LM1EO        (1<<21)	/* Loc Monitor 1 */
+#define TSI148_LCSR_INTEO_LM0EO        (1<<20)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTEO_MB3EO        (1<<19)	/* Mail Box 3 */
+#define TSI148_LCSR_INTEO_MB2EO        (1<<18)	/* Mail Box 2 */
+#define TSI148_LCSR_INTEO_MB1EO        (1<<17)	/* Mail Box 1 */
+#define TSI148_LCSR_INTEO_MB0EO        (1<<16)	/* Mail Box 0 */
+#define TSI148_LCSR_INTEO_PERREO       (1<<13)	/* PCI/X Error */
+#define TSI148_LCSR_INTEO_VERREO       (1<<12)	/* VMEbus Error */
+#define TSI148_LCSR_INTEO_VIEEO        (1<<11)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTEO_IACKEO       (1<<10)	/* IACK */
+#define TSI148_LCSR_INTEO_SYSFLEO      (1<<9)	/* System Fail */
+#define TSI148_LCSR_INTEO_ACFLEO       (1<<8)	/* AC Fail */
+#define TSI148_LCSR_INTEO_IRQ7EO       (1<<7)	/* IRQ7 */
+#define TSI148_LCSR_INTEO_IRQ6EO       (1<<6)	/* IRQ6 */
+#define TSI148_LCSR_INTEO_IRQ5EO       (1<<5)	/* IRQ5 */
+#define TSI148_LCSR_INTEO_IRQ4EO       (1<<4)	/* IRQ4 */
+#define TSI148_LCSR_INTEO_IRQ3EO       (1<<3)	/* IRQ3 */
+#define TSI148_LCSR_INTEO_IRQ2EO       (1<<2)	/* IRQ2 */
+#define TSI148_LCSR_INTEO_IRQ1EO       (1<<1)	/* IRQ1 */
+
+static const int TSI148_LCSR_INTEO_LMEO[4] = { TSI148_LCSR_INTEO_LM0EO,
+					TSI148_LCSR_INTEO_LM1EO,
+					TSI148_LCSR_INTEO_LM2EO,
+					TSI148_LCSR_INTEO_LM3EO };
+
+static const int TSI148_LCSR_INTEO_IRQEO[7] = { TSI148_LCSR_INTEO_IRQ1EO,
+					TSI148_LCSR_INTEO_IRQ2EO,
+					TSI148_LCSR_INTEO_IRQ3EO,
+					TSI148_LCSR_INTEO_IRQ4EO,
+					TSI148_LCSR_INTEO_IRQ5EO,
+					TSI148_LCSR_INTEO_IRQ6EO,
+					TSI148_LCSR_INTEO_IRQ7EO };
+
+/*
+ *  Interrupt Status Register CRG + $448
+ */
+#define TSI148_LCSR_INTS_DMA1S         (1<<25)	/* DMA 1 */
+#define TSI148_LCSR_INTS_DMA0S         (1<<24)	/* DMA 0 */
+#define TSI148_LCSR_INTS_LM3S          (1<<23)	/* Location Monitor 3 */
+#define TSI148_LCSR_INTS_LM2S          (1<<22)	/* Location Monitor 2 */
+#define TSI148_LCSR_INTS_LM1S          (1<<21)	/* Location Monitor 1 */
+#define TSI148_LCSR_INTS_LM0S          (1<<20)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTS_MB3S          (1<<19)	/* Mail Box 3 */
+#define TSI148_LCSR_INTS_MB2S          (1<<18)	/* Mail Box 2 */
+#define TSI148_LCSR_INTS_MB1S          (1<<17)	/* Mail Box 1 */
+#define TSI148_LCSR_INTS_MB0S          (1<<16)	/* Mail Box 0 */
+#define TSI148_LCSR_INTS_PERRS         (1<<13)	/* PCI/X Error */
+#define TSI148_LCSR_INTS_VERRS         (1<<12)	/* VMEbus Error */
+#define TSI148_LCSR_INTS_VIES          (1<<11)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTS_IACKS         (1<<10)	/* IACK */
+#define TSI148_LCSR_INTS_SYSFLS        (1<<9)	/* System Fail */
+#define TSI148_LCSR_INTS_ACFLS         (1<<8)	/* AC Fail */
+#define TSI148_LCSR_INTS_IRQ7S         (1<<7)	/* IRQ7 */
+#define TSI148_LCSR_INTS_IRQ6S         (1<<6)	/* IRQ6 */
+#define TSI148_LCSR_INTS_IRQ5S         (1<<5)	/* IRQ5 */
+#define TSI148_LCSR_INTS_IRQ4S         (1<<4)	/* IRQ4 */
+#define TSI148_LCSR_INTS_IRQ3S         (1<<3)	/* IRQ3 */
+#define TSI148_LCSR_INTS_IRQ2S         (1<<2)	/* IRQ2 */
+#define TSI148_LCSR_INTS_IRQ1S         (1<<1)	/* IRQ1 */
+
+static const int TSI148_LCSR_INTS_LMS[4] = { TSI148_LCSR_INTS_LM0S,
+					TSI148_LCSR_INTS_LM1S,
+					TSI148_LCSR_INTS_LM2S,
+					TSI148_LCSR_INTS_LM3S };
+
+static const int TSI148_LCSR_INTS_MBS[4] = { TSI148_LCSR_INTS_MB0S,
+					TSI148_LCSR_INTS_MB1S,
+					TSI148_LCSR_INTS_MB2S,
+					TSI148_LCSR_INTS_MB3S };
+
+/*
+ *  Interrupt Clear Register CRG + $44C
+ */
+#define TSI148_LCSR_INTC_DMA1C         (1<<25)	/* DMA 1 */
+#define TSI148_LCSR_INTC_DMA0C         (1<<24)	/* DMA 0 */
+#define TSI148_LCSR_INTC_LM3C          (1<<23)	/* Location Monitor 3 */
+#define TSI148_LCSR_INTC_LM2C          (1<<22)	/* Location Monitor 2 */
+#define TSI148_LCSR_INTC_LM1C          (1<<21)	/* Location Monitor 1 */
+#define TSI148_LCSR_INTC_LM0C          (1<<20)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTC_MB3C          (1<<19)	/* Mail Box 3 */
+#define TSI148_LCSR_INTC_MB2C          (1<<18)	/* Mail Box 2 */
+#define TSI148_LCSR_INTC_MB1C          (1<<17)	/* Mail Box 1 */
+#define TSI148_LCSR_INTC_MB0C          (1<<16)	/* Mail Box 0 */
+#define TSI148_LCSR_INTC_PERRC         (1<<13)	/* VMEbus Error */
+#define TSI148_LCSR_INTC_VERRC         (1<<12)	/* VMEbus Access Time-out */
+#define TSI148_LCSR_INTC_VIEC          (1<<11)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTC_IACKC         (1<<10)	/* IACK */
+#define TSI148_LCSR_INTC_SYSFLC        (1<<9)	/* System Fail */
+#define TSI148_LCSR_INTC_ACFLC         (1<<8)	/* AC Fail */
+
+static const int TSI148_LCSR_INTC_LMC[4] = { TSI148_LCSR_INTC_LM0C,
+					TSI148_LCSR_INTC_LM1C,
+					TSI148_LCSR_INTC_LM2C,
+					TSI148_LCSR_INTC_LM3C };
+
+static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C,
+					TSI148_LCSR_INTC_MB1C,
+					TSI148_LCSR_INTC_MB2C,
+					TSI148_LCSR_INTC_MB3C };
+
+/*
+ *  Interrupt Map Register 1 CRG + $458
+ */
+#define TSI148_LCSR_INTM1_DMA1M_M      (3<<18)	/* DMA 1 */
+#define TSI148_LCSR_INTM1_DMA0M_M      (3<<16)	/* DMA 0 */
+#define TSI148_LCSR_INTM1_LM3M_M       (3<<14)	/* Location Monitor 3 */
+#define TSI148_LCSR_INTM1_LM2M_M       (3<<12)	/* Location Monitor 2 */
+#define TSI148_LCSR_INTM1_LM1M_M       (3<<10)	/* Location Monitor 1 */
+#define TSI148_LCSR_INTM1_LM0M_M       (3<<8)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTM1_MB3M_M       (3<<6)	/* Mail Box 3 */
+#define TSI148_LCSR_INTM1_MB2M_M       (3<<4)	/* Mail Box 2 */
+#define TSI148_LCSR_INTM1_MB1M_M       (3<<2)	/* Mail Box 1 */
+#define TSI148_LCSR_INTM1_MB0M_M       (3<<0)	/* Mail Box 0 */
+
+/*
+ *  Interrupt Map Register 2 CRG + $45C
+ */
+#define TSI148_LCSR_INTM2_PERRM_M      (3<<26)	/* PCI Bus Error */
+#define TSI148_LCSR_INTM2_VERRM_M      (3<<24)	/* VMEbus Error */
+#define TSI148_LCSR_INTM2_VIEM_M       (3<<22)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTM2_IACKM_M      (3<<20)	/* IACK */
+#define TSI148_LCSR_INTM2_SYSFLM_M     (3<<18)	/* System Fail */
+#define TSI148_LCSR_INTM2_ACFLM_M      (3<<16)	/* AC Fail */
+#define TSI148_LCSR_INTM2_IRQ7M_M      (3<<14)	/* IRQ7 */
+#define TSI148_LCSR_INTM2_IRQ6M_M      (3<<12)	/* IRQ6 */
+#define TSI148_LCSR_INTM2_IRQ5M_M      (3<<10)	/* IRQ5 */
+#define TSI148_LCSR_INTM2_IRQ4M_M      (3<<8)	/* IRQ4 */
+#define TSI148_LCSR_INTM2_IRQ3M_M      (3<<6)	/* IRQ3 */
+#define TSI148_LCSR_INTM2_IRQ2M_M      (3<<4)	/* IRQ2 */
+#define TSI148_LCSR_INTM2_IRQ1M_M      (3<<2)	/* IRQ1 */
+
+/*
+ *  DMA Control (0-1) Registers CRG + $500
+ */
+#define TSI148_LCSR_DCTL_ABT           (1<<27)	/* Abort */
+#define TSI148_LCSR_DCTL_PAU           (1<<26)	/* Pause */
+#define TSI148_LCSR_DCTL_DGO           (1<<25)	/* DMA Go */
+
+#define TSI148_LCSR_DCTL_MOD           (1<<23)	/* Mode */
+
+#define TSI148_LCSR_DCTL_VBKS_M        (7<<12)	/* VMEbus block Size MASK */
+#define TSI148_LCSR_DCTL_VBKS_32       (0<<12)	/* VMEbus block Size 32 */
+#define TSI148_LCSR_DCTL_VBKS_64       (1<<12)	/* VMEbus block Size 64 */
+#define TSI148_LCSR_DCTL_VBKS_128      (2<<12)	/* VMEbus block Size 128 */
+#define TSI148_LCSR_DCTL_VBKS_256      (3<<12)	/* VMEbus block Size 256 */
+#define TSI148_LCSR_DCTL_VBKS_512      (4<<12)	/* VMEbus block Size 512 */
+#define TSI148_LCSR_DCTL_VBKS_1024     (5<<12)	/* VMEbus block Size 1024 */
+#define TSI148_LCSR_DCTL_VBKS_2048     (6<<12)	/* VMEbus block Size 2048 */
+#define TSI148_LCSR_DCTL_VBKS_4096     (7<<12)	/* VMEbus block Size 4096 */
+
+#define TSI148_LCSR_DCTL_VBOT_M        (7<<8)	/* VMEbus back-off MASK */
+#define TSI148_LCSR_DCTL_VBOT_0        (0<<8)	/* VMEbus back-off  0us */
+#define TSI148_LCSR_DCTL_VBOT_1        (1<<8)	/* VMEbus back-off 1us */
+#define TSI148_LCSR_DCTL_VBOT_2        (2<<8)	/* VMEbus back-off 2us */
+#define TSI148_LCSR_DCTL_VBOT_4        (3<<8)	/* VMEbus back-off 4us */
+#define TSI148_LCSR_DCTL_VBOT_8        (4<<8)	/* VMEbus back-off 8us */
+#define TSI148_LCSR_DCTL_VBOT_16       (5<<8)	/* VMEbus back-off 16us */
+#define TSI148_LCSR_DCTL_VBOT_32       (6<<8)	/* VMEbus back-off 32us */
+#define TSI148_LCSR_DCTL_VBOT_64       (7<<8)	/* VMEbus back-off 64us */
+
+#define TSI148_LCSR_DCTL_PBKS_M        (7<<4)	/* PCI block size MASK */
+#define TSI148_LCSR_DCTL_PBKS_32       (0<<4)	/* PCI block size 32 bytes */
+#define TSI148_LCSR_DCTL_PBKS_64       (1<<4)	/* PCI block size 64 bytes */
+#define TSI148_LCSR_DCTL_PBKS_128      (2<<4)	/* PCI block size 128 bytes */
+#define TSI148_LCSR_DCTL_PBKS_256      (3<<4)	/* PCI block size 256 bytes */
+#define TSI148_LCSR_DCTL_PBKS_512      (4<<4)	/* PCI block size 512 bytes */
+#define TSI148_LCSR_DCTL_PBKS_1024     (5<<4)	/* PCI block size 1024 bytes */
+#define TSI148_LCSR_DCTL_PBKS_2048     (6<<4)	/* PCI block size 2048 bytes */
+#define TSI148_LCSR_DCTL_PBKS_4096     (7<<4)	/* PCI block size 4096 bytes */
+
+#define TSI148_LCSR_DCTL_PBOT_M        (7<<0)	/* PCI back off MASK */
+#define TSI148_LCSR_DCTL_PBOT_0        (0<<0)	/* PCI back off 0us */
+#define TSI148_LCSR_DCTL_PBOT_1        (1<<0)	/* PCI back off 1us */
+#define TSI148_LCSR_DCTL_PBOT_2        (2<<0)	/* PCI back off 2us */
+#define TSI148_LCSR_DCTL_PBOT_4        (3<<0)	/* PCI back off 3us */
+#define TSI148_LCSR_DCTL_PBOT_8        (4<<0)	/* PCI back off 4us */
+#define TSI148_LCSR_DCTL_PBOT_16       (5<<0)	/* PCI back off 8us */
+#define TSI148_LCSR_DCTL_PBOT_32       (6<<0)	/* PCI back off 16us */
+#define TSI148_LCSR_DCTL_PBOT_64       (7<<0)	/* PCI back off 32us */
+
+/*
+ *  DMA Status Registers (0-1)  CRG + $504
+ */
+#define TSI148_LCSR_DSTA_SMA           (1<<31)	/* PCI Signalled Master Abt */
+#define TSI148_LCSR_DSTA_RTA           (1<<30)	/* PCI Received Target Abt */
+#define TSI148_LCSR_DSTA_MRC           (1<<29)	/* PCI Max Retry Count */
+#define TSI148_LCSR_DSTA_VBE           (1<<28)	/* VMEbus error */
+#define TSI148_LCSR_DSTA_ABT           (1<<27)	/* Abort */
+#define TSI148_LCSR_DSTA_PAU           (1<<26)	/* Pause */
+#define TSI148_LCSR_DSTA_DON           (1<<25)	/* Done */
+#define TSI148_LCSR_DSTA_BSY           (1<<24)	/* Busy */
+
+/*
+ *  DMA Current Link Address Lower (0-1)
+ */
+#define TSI148_LCSR_DCLAL_M            (0x3FFFFFF<<6)	/* Mask */
+
+/*
+ *  DMA Source Attribute (0-1) Reg
+ */
+#define TSI148_LCSR_DSAT_TYP_M         (3<<28)	/* Source Bus Type */
+#define TSI148_LCSR_DSAT_TYP_PCI       (0<<28)	/* PCI Bus */
+#define TSI148_LCSR_DSAT_TYP_VME       (1<<28)	/* VMEbus */
+#define TSI148_LCSR_DSAT_TYP_PAT       (2<<28)	/* Data Pattern */
+
+#define TSI148_LCSR_DSAT_PSZ           (1<<25)	/* Pattern Size */
+#define TSI148_LCSR_DSAT_NIN           (1<<24)	/* No Increment */
+
+#define TSI148_LCSR_DSAT_2eSSTM_M      (3<<11)	/* 2eSST Trans Rate Mask */
+#define TSI148_LCSR_DSAT_2eSSTM_160    (0<<11)	/* 160 MB/s */
+#define TSI148_LCSR_DSAT_2eSSTM_267    (1<<11)	/* 267 MB/s */
+#define TSI148_LCSR_DSAT_2eSSTM_320    (2<<11)	/* 320 MB/s */
+
+#define TSI148_LCSR_DSAT_TM_M          (7<<8)	/* Bus Transfer Protocol Mask */
+#define TSI148_LCSR_DSAT_TM_SCT        (0<<8)	/* SCT */
+#define TSI148_LCSR_DSAT_TM_BLT        (1<<8)	/* BLT */
+#define TSI148_LCSR_DSAT_TM_MBLT       (2<<8)	/* MBLT */
+#define TSI148_LCSR_DSAT_TM_2eVME      (3<<8)	/* 2eVME */
+#define TSI148_LCSR_DSAT_TM_2eSST      (4<<8)	/* 2eSST */
+#define TSI148_LCSR_DSAT_TM_2eSSTB     (5<<8)	/* 2eSST Broadcast */
+
+#define TSI148_LCSR_DSAT_DBW_M         (3<<6)	/* Max Data Width MASK */
+#define TSI148_LCSR_DSAT_DBW_16        (0<<6)	/* 16 Bits */
+#define TSI148_LCSR_DSAT_DBW_32        (1<<6)	/* 32 Bits */
+
+#define TSI148_LCSR_DSAT_SUP           (1<<5)	/* Supervisory Mode */
+#define TSI148_LCSR_DSAT_PGM           (1<<4)	/* Program Mode */
+
+#define TSI148_LCSR_DSAT_AMODE_M       (0xf<<0)	/* Address Space Mask */
+#define TSI148_LCSR_DSAT_AMODE_A16     (0<<0)	/* A16 */
+#define TSI148_LCSR_DSAT_AMODE_A24     (1<<0)	/* A24 */
+#define TSI148_LCSR_DSAT_AMODE_A32     (2<<0)	/* A32 */
+#define TSI148_LCSR_DSAT_AMODE_A64     (4<<0)	/* A64 */
+#define TSI148_LCSR_DSAT_AMODE_CRCSR   (5<<0)	/* CR/CSR */
+#define TSI148_LCSR_DSAT_AMODE_USER1   (8<<0)	/* User1 */
+#define TSI148_LCSR_DSAT_AMODE_USER2   (9<<0)	/* User2 */
+#define TSI148_LCSR_DSAT_AMODE_USER3   (0xa<<0)	/* User3 */
+#define TSI148_LCSR_DSAT_AMODE_USER4   (0xb<<0)	/* User4 */
+
+/*
+ *  DMA Destination Attribute Registers (0-1)
+ */
+#define TSI148_LCSR_DDAT_TYP_PCI       (0<<28)	/* Destination PCI Bus  */
+#define TSI148_LCSR_DDAT_TYP_VME       (1<<28)	/* Destination VMEbus */
+
+#define TSI148_LCSR_DDAT_2eSSTM_M      (3<<11)	/* 2eSST Transfer Rate Mask */
+#define TSI148_LCSR_DDAT_2eSSTM_160    (0<<11)	/* 160 MB/s */
+#define TSI148_LCSR_DDAT_2eSSTM_267    (1<<11)	/* 267 MB/s */
+#define TSI148_LCSR_DDAT_2eSSTM_320    (2<<11)	/* 320 MB/s */
+
+#define TSI148_LCSR_DDAT_TM_M          (7<<8)	/* Bus Transfer Protocol Mask */
+#define TSI148_LCSR_DDAT_TM_SCT        (0<<8)	/* SCT */
+#define TSI148_LCSR_DDAT_TM_BLT        (1<<8)	/* BLT */
+#define TSI148_LCSR_DDAT_TM_MBLT       (2<<8)	/* MBLT */
+#define TSI148_LCSR_DDAT_TM_2eVME      (3<<8)	/* 2eVME */
+#define TSI148_LCSR_DDAT_TM_2eSST      (4<<8)	/* 2eSST */
+#define TSI148_LCSR_DDAT_TM_2eSSTB     (5<<8)	/* 2eSST Broadcast */
+
+#define TSI148_LCSR_DDAT_DBW_M         (3<<6)	/* Max Data Width MASK */
+#define TSI148_LCSR_DDAT_DBW_16        (0<<6)	/* 16 Bits */
+#define TSI148_LCSR_DDAT_DBW_32        (1<<6)	/* 32 Bits */
+
+#define TSI148_LCSR_DDAT_SUP           (1<<5)	/* Supervisory/User Access */
+#define TSI148_LCSR_DDAT_PGM           (1<<4)	/* Program/Data Access */
+
+#define TSI148_LCSR_DDAT_AMODE_M       (0xf<<0)	/* Address Space Mask */
+#define TSI148_LCSR_DDAT_AMODE_A16      (0<<0)	/* A16 */
+#define TSI148_LCSR_DDAT_AMODE_A24      (1<<0)	/* A24 */
+#define TSI148_LCSR_DDAT_AMODE_A32      (2<<0)	/* A32 */
+#define TSI148_LCSR_DDAT_AMODE_A64      (4<<0)	/* A64 */
+#define TSI148_LCSR_DDAT_AMODE_CRCSR   (5<<0)	/* CRC/SR */
+#define TSI148_LCSR_DDAT_AMODE_USER1   (8<<0)	/* User1 */
+#define TSI148_LCSR_DDAT_AMODE_USER2   (9<<0)	/* User2 */
+#define TSI148_LCSR_DDAT_AMODE_USER3   (0xa<<0)	/* User3 */
+#define TSI148_LCSR_DDAT_AMODE_USER4   (0xb<<0)	/* User4 */
+
+/*
+ *  DMA Next Link Address Lower
+ */
+#define TSI148_LCSR_DNLAL_DNLAL_M      (0x3FFFFFF<<6)	/* Address Mask */
+#define TSI148_LCSR_DNLAL_LLA          (1<<0)  /* Last Link Address Indicator */
+
+/*
+ *  DMA 2eSST Broadcast Select
+ */
+#define TSI148_LCSR_DBS_M              (0x1FFFFF<<0)	/* Mask */
+
+/*
+ *  GCSR Register Group
+ */
+
+/*
+ *  GCSR Control and Status Register  CRG + $604
+ */
+#define TSI148_GCSR_GCTRL_LRST         (1<<15)	/* Local Reset */
+#define TSI148_GCSR_GCTRL_SFAILEN      (1<<14)	/* System Fail enable */
+#define TSI148_GCSR_GCTRL_BDFAILS      (1<<13)	/* Board Fail Status */
+#define TSI148_GCSR_GCTRL_SCON         (1<<12)	/* System Copntroller */
+#define TSI148_GCSR_GCTRL_MEN          (1<<11)	/* Module Enable (READY) */
+
+#define TSI148_GCSR_GCTRL_LMI3S        (1<<7)	/* Loc Monitor 3 Int Status */
+#define TSI148_GCSR_GCTRL_LMI2S        (1<<6)	/* Loc Monitor 2 Int Status */
+#define TSI148_GCSR_GCTRL_LMI1S        (1<<5)	/* Loc Monitor 1 Int Status */
+#define TSI148_GCSR_GCTRL_LMI0S        (1<<4)	/* Loc Monitor 0 Int Status */
+#define TSI148_GCSR_GCTRL_MBI3S        (1<<3)	/* Mail box 3 Int Status */
+#define TSI148_GCSR_GCTRL_MBI2S        (1<<2)	/* Mail box 2 Int Status */
+#define TSI148_GCSR_GCTRL_MBI1S        (1<<1)	/* Mail box 1 Int Status */
+#define TSI148_GCSR_GCTRL_MBI0S        (1<<0)	/* Mail box 0 Int Status */
+
+#define TSI148_GCSR_GAP                (1<<5)	/* Geographic Addr Parity */
+#define TSI148_GCSR_GA_M               (0x1F<<0)  /* Geographic Address Mask */
+
+/*
+ *  CR/CSR Register Group
+ */
+
+/*
+ *  CR/CSR Bit Clear Register CRG + $FF4
+ */
+#define TSI148_CRCSR_CSRBCR_LRSTC      (1<<7)	/* Local Reset Clear */
+#define TSI148_CRCSR_CSRBCR_SFAILC     (1<<6)	/* System Fail Enable Clear */
+#define TSI148_CRCSR_CSRBCR_BDFAILS    (1<<5)	/* Board Fail Status */
+#define TSI148_CRCSR_CSRBCR_MENC       (1<<4)	/* Module Enable Clear */
+#define TSI148_CRCSR_CSRBCR_BERRSC     (1<<3)	/* Bus Error Status Clear */
+
+/*
+ *  CR/CSR Bit Set Register CRG+$FF8
+ */
+#define TSI148_CRCSR_CSRBSR_LISTS      (1<<7)	/* Local Reset Clear */
+#define TSI148_CRCSR_CSRBSR_SFAILS     (1<<6)	/* System Fail Enable Clear */
+#define TSI148_CRCSR_CSRBSR_BDFAILS    (1<<5)	/* Board Fail Status */
+#define TSI148_CRCSR_CSRBSR_MENS       (1<<4)	/* Module Enable Clear */
+#define TSI148_CRCSR_CSRBSR_BERRS      (1<<3)	/* Bus Error Status Clear */
+
+/*
+ *  CR/CSR Base Address Register CRG + FFC
+ */
+#define TSI148_CRCSR_CBAR_M            (0x1F<<3)	/* Mask */
+
+#endif				/* TSI148_H */
diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c
new file mode 100644
index 0000000..95a9f71
--- /dev/null
+++ b/drivers/vme/vme.c
@@ -0,0 +1,1517 @@
+/*
+ * VME Bridge Framework
+ *
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * Based on work by Tom Armistead and Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * 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/mm.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/syscalls.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vme.h>
+
+#include "vme_bridge.h"
+
+/* Bitmask and list of registered buses both protected by common mutex */
+static unsigned int vme_bus_numbers;
+static LIST_HEAD(vme_bus_list);
+static DEFINE_MUTEX(vme_buses_lock);
+
+static void __exit vme_exit(void);
+static int __init vme_init(void);
+
+static struct vme_dev *dev_to_vme_dev(struct device *dev)
+{
+	return container_of(dev, struct vme_dev, dev);
+}
+
+/*
+ * Find the bridge that the resource is associated with.
+ */
+static struct vme_bridge *find_bridge(struct vme_resource *resource)
+{
+	/* Get list to search */
+	switch (resource->type) {
+	case VME_MASTER:
+		return list_entry(resource->entry, struct vme_master_resource,
+			list)->parent;
+		break;
+	case VME_SLAVE:
+		return list_entry(resource->entry, struct vme_slave_resource,
+			list)->parent;
+		break;
+	case VME_DMA:
+		return list_entry(resource->entry, struct vme_dma_resource,
+			list)->parent;
+		break;
+	case VME_LM:
+		return list_entry(resource->entry, struct vme_lm_resource,
+			list)->parent;
+		break;
+	default:
+		printk(KERN_ERR "Unknown resource type\n");
+		return NULL;
+		break;
+	}
+}
+
+/*
+ * Allocate a contiguous block of memory for use by the driver. This is used to
+ * create the buffers for the slave windows.
+ */
+void *vme_alloc_consistent(struct vme_resource *resource, size_t size,
+	dma_addr_t *dma)
+{
+	struct vme_bridge *bridge;
+
+	if (resource == NULL) {
+		printk(KERN_ERR "No resource\n");
+		return NULL;
+	}
+
+	bridge = find_bridge(resource);
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find bridge\n");
+		return NULL;
+	}
+
+	if (bridge->parent == NULL) {
+		printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name);
+		return NULL;
+	}
+
+	if (bridge->alloc_consistent == NULL) {
+		printk(KERN_ERR "alloc_consistent not supported by bridge %s\n",
+		       bridge->name);
+		return NULL;
+	}
+
+	return bridge->alloc_consistent(bridge->parent, size, dma);
+}
+EXPORT_SYMBOL(vme_alloc_consistent);
+
+/*
+ * Free previously allocated contiguous block of memory.
+ */
+void vme_free_consistent(struct vme_resource *resource, size_t size,
+	void *vaddr, dma_addr_t dma)
+{
+	struct vme_bridge *bridge;
+
+	if (resource == NULL) {
+		printk(KERN_ERR "No resource\n");
+		return;
+	}
+
+	bridge = find_bridge(resource);
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find bridge\n");
+		return;
+	}
+
+	if (bridge->parent == NULL) {
+		printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name);
+		return;
+	}
+
+	if (bridge->free_consistent == NULL) {
+		printk(KERN_ERR "free_consistent not supported by bridge %s\n",
+		       bridge->name);
+		return;
+	}
+
+	bridge->free_consistent(bridge->parent, size, vaddr, dma);
+}
+EXPORT_SYMBOL(vme_free_consistent);
+
+size_t vme_get_size(struct vme_resource *resource)
+{
+	int enabled, retval;
+	unsigned long long base, size;
+	dma_addr_t buf_base;
+	u32 aspace, cycle, dwidth;
+
+	switch (resource->type) {
+	case VME_MASTER:
+		retval = vme_master_get(resource, &enabled, &base, &size,
+			&aspace, &cycle, &dwidth);
+
+		return size;
+		break;
+	case VME_SLAVE:
+		retval = vme_slave_get(resource, &enabled, &base, &size,
+			&buf_base, &aspace, &cycle);
+
+		return size;
+		break;
+	case VME_DMA:
+		return 0;
+		break;
+	default:
+		printk(KERN_ERR "Unknown resource type\n");
+		return 0;
+		break;
+	}
+}
+EXPORT_SYMBOL(vme_get_size);
+
+static int vme_check_window(u32 aspace, unsigned long long vme_base,
+	unsigned long long size)
+{
+	int retval = 0;
+
+	switch (aspace) {
+	case VME_A16:
+		if (((vme_base + size) > VME_A16_MAX) ||
+				(vme_base > VME_A16_MAX))
+			retval = -EFAULT;
+		break;
+	case VME_A24:
+		if (((vme_base + size) > VME_A24_MAX) ||
+				(vme_base > VME_A24_MAX))
+			retval = -EFAULT;
+		break;
+	case VME_A32:
+		if (((vme_base + size) > VME_A32_MAX) ||
+				(vme_base > VME_A32_MAX))
+			retval = -EFAULT;
+		break;
+	case VME_A64:
+		/*
+		 * Any value held in an unsigned long long can be used as the
+		 * base
+		 */
+		break;
+	case VME_CRCSR:
+		if (((vme_base + size) > VME_CRCSR_MAX) ||
+				(vme_base > VME_CRCSR_MAX))
+			retval = -EFAULT;
+		break;
+	case VME_USER1:
+	case VME_USER2:
+	case VME_USER3:
+	case VME_USER4:
+		/* User Defined */
+		break;
+	default:
+		printk(KERN_ERR "Invalid address space\n");
+		retval = -EINVAL;
+		break;
+	}
+
+	return retval;
+}
+
+/*
+ * Request a slave image with specific attributes, return some unique
+ * identifier.
+ */
+struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address,
+	u32 cycle)
+{
+	struct vme_bridge *bridge;
+	struct list_head *slave_pos = NULL;
+	struct vme_slave_resource *allocated_image = NULL;
+	struct vme_slave_resource *slave_image = NULL;
+	struct vme_resource *resource = NULL;
+
+	bridge = vdev->bridge;
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find VME bus\n");
+		goto err_bus;
+	}
+
+	/* Loop through slave resources */
+	list_for_each(slave_pos, &bridge->slave_resources) {
+		slave_image = list_entry(slave_pos,
+			struct vme_slave_resource, list);
+
+		if (slave_image == NULL) {
+			printk(KERN_ERR "Registered NULL Slave resource\n");
+			continue;
+		}
+
+		/* Find an unlocked and compatible image */
+		mutex_lock(&slave_image->mtx);
+		if (((slave_image->address_attr & address) == address) &&
+			((slave_image->cycle_attr & cycle) == cycle) &&
+			(slave_image->locked == 0)) {
+
+			slave_image->locked = 1;
+			mutex_unlock(&slave_image->mtx);
+			allocated_image = slave_image;
+			break;
+		}
+		mutex_unlock(&slave_image->mtx);
+	}
+
+	/* No free image */
+	if (allocated_image == NULL)
+		goto err_image;
+
+	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+	if (resource == NULL) {
+		printk(KERN_WARNING "Unable to allocate resource structure\n");
+		goto err_alloc;
+	}
+	resource->type = VME_SLAVE;
+	resource->entry = &allocated_image->list;
+
+	return resource;
+
+err_alloc:
+	/* Unlock image */
+	mutex_lock(&slave_image->mtx);
+	slave_image->locked = 0;
+	mutex_unlock(&slave_image->mtx);
+err_image:
+err_bus:
+	return NULL;
+}
+EXPORT_SYMBOL(vme_slave_request);
+
+int vme_slave_set(struct vme_resource *resource, int enabled,
+	unsigned long long vme_base, unsigned long long size,
+	dma_addr_t buf_base, u32 aspace, u32 cycle)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_slave_resource *image;
+	int retval;
+
+	if (resource->type != VME_SLAVE) {
+		printk(KERN_ERR "Not a slave resource\n");
+		return -EINVAL;
+	}
+
+	image = list_entry(resource->entry, struct vme_slave_resource, list);
+
+	if (bridge->slave_set == NULL) {
+		printk(KERN_ERR "Function not supported\n");
+		return -ENOSYS;
+	}
+
+	if (!(((image->address_attr & aspace) == aspace) &&
+		((image->cycle_attr & cycle) == cycle))) {
+		printk(KERN_ERR "Invalid attributes\n");
+		return -EINVAL;
+	}
+
+	retval = vme_check_window(aspace, vme_base, size);
+	if (retval)
+		return retval;
+
+	return bridge->slave_set(image, enabled, vme_base, size, buf_base,
+		aspace, cycle);
+}
+EXPORT_SYMBOL(vme_slave_set);
+
+int vme_slave_get(struct vme_resource *resource, int *enabled,
+	unsigned long long *vme_base, unsigned long long *size,
+	dma_addr_t *buf_base, u32 *aspace, u32 *cycle)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_slave_resource *image;
+
+	if (resource->type != VME_SLAVE) {
+		printk(KERN_ERR "Not a slave resource\n");
+		return -EINVAL;
+	}
+
+	image = list_entry(resource->entry, struct vme_slave_resource, list);
+
+	if (bridge->slave_get == NULL) {
+		printk(KERN_ERR "vme_slave_get not supported\n");
+		return -EINVAL;
+	}
+
+	return bridge->slave_get(image, enabled, vme_base, size, buf_base,
+		aspace, cycle);
+}
+EXPORT_SYMBOL(vme_slave_get);
+
+void vme_slave_free(struct vme_resource *resource)
+{
+	struct vme_slave_resource *slave_image;
+
+	if (resource->type != VME_SLAVE) {
+		printk(KERN_ERR "Not a slave resource\n");
+		return;
+	}
+
+	slave_image = list_entry(resource->entry, struct vme_slave_resource,
+		list);
+	if (slave_image == NULL) {
+		printk(KERN_ERR "Can't find slave resource\n");
+		return;
+	}
+
+	/* Unlock image */
+	mutex_lock(&slave_image->mtx);
+	if (slave_image->locked == 0)
+		printk(KERN_ERR "Image is already free\n");
+
+	slave_image->locked = 0;
+	mutex_unlock(&slave_image->mtx);
+
+	/* Free up resource memory */
+	kfree(resource);
+}
+EXPORT_SYMBOL(vme_slave_free);
+
+/*
+ * Request a master image with specific attributes, return some unique
+ * identifier.
+ */
+struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address,
+	u32 cycle, u32 dwidth)
+{
+	struct vme_bridge *bridge;
+	struct list_head *master_pos = NULL;
+	struct vme_master_resource *allocated_image = NULL;
+	struct vme_master_resource *master_image = NULL;
+	struct vme_resource *resource = NULL;
+
+	bridge = vdev->bridge;
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find VME bus\n");
+		goto err_bus;
+	}
+
+	/* Loop through master resources */
+	list_for_each(master_pos, &bridge->master_resources) {
+		master_image = list_entry(master_pos,
+			struct vme_master_resource, list);
+
+		if (master_image == NULL) {
+			printk(KERN_WARNING "Registered NULL master resource\n");
+			continue;
+		}
+
+		/* Find an unlocked and compatible image */
+		spin_lock(&master_image->lock);
+		if (((master_image->address_attr & address) == address) &&
+			((master_image->cycle_attr & cycle) == cycle) &&
+			((master_image->width_attr & dwidth) == dwidth) &&
+			(master_image->locked == 0)) {
+
+			master_image->locked = 1;
+			spin_unlock(&master_image->lock);
+			allocated_image = master_image;
+			break;
+		}
+		spin_unlock(&master_image->lock);
+	}
+
+	/* Check to see if we found a resource */
+	if (allocated_image == NULL) {
+		printk(KERN_ERR "Can't find a suitable resource\n");
+		goto err_image;
+	}
+
+	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+	if (resource == NULL) {
+		printk(KERN_ERR "Unable to allocate resource structure\n");
+		goto err_alloc;
+	}
+	resource->type = VME_MASTER;
+	resource->entry = &allocated_image->list;
+
+	return resource;
+
+err_alloc:
+	/* Unlock image */
+	spin_lock(&master_image->lock);
+	master_image->locked = 0;
+	spin_unlock(&master_image->lock);
+err_image:
+err_bus:
+	return NULL;
+}
+EXPORT_SYMBOL(vme_master_request);
+
+int vme_master_set(struct vme_resource *resource, int enabled,
+	unsigned long long vme_base, unsigned long long size, u32 aspace,
+	u32 cycle, u32 dwidth)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_master_resource *image;
+	int retval;
+
+	if (resource->type != VME_MASTER) {
+		printk(KERN_ERR "Not a master resource\n");
+		return -EINVAL;
+	}
+
+	image = list_entry(resource->entry, struct vme_master_resource, list);
+
+	if (bridge->master_set == NULL) {
+		printk(KERN_WARNING "vme_master_set not supported\n");
+		return -EINVAL;
+	}
+
+	if (!(((image->address_attr & aspace) == aspace) &&
+		((image->cycle_attr & cycle) == cycle) &&
+		((image->width_attr & dwidth) == dwidth))) {
+		printk(KERN_WARNING "Invalid attributes\n");
+		return -EINVAL;
+	}
+
+	retval = vme_check_window(aspace, vme_base, size);
+	if (retval)
+		return retval;
+
+	return bridge->master_set(image, enabled, vme_base, size, aspace,
+		cycle, dwidth);
+}
+EXPORT_SYMBOL(vme_master_set);
+
+int vme_master_get(struct vme_resource *resource, int *enabled,
+	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
+	u32 *cycle, u32 *dwidth)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_master_resource *image;
+
+	if (resource->type != VME_MASTER) {
+		printk(KERN_ERR "Not a master resource\n");
+		return -EINVAL;
+	}
+
+	image = list_entry(resource->entry, struct vme_master_resource, list);
+
+	if (bridge->master_get == NULL) {
+		printk(KERN_WARNING "vme_master_set not supported\n");
+		return -EINVAL;
+	}
+
+	return bridge->master_get(image, enabled, vme_base, size, aspace,
+		cycle, dwidth);
+}
+EXPORT_SYMBOL(vme_master_get);
+
+/*
+ * Read data out of VME space into a buffer.
+ */
+ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count,
+	loff_t offset)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_master_resource *image;
+	size_t length;
+
+	if (bridge->master_read == NULL) {
+		printk(KERN_WARNING "Reading from resource not supported\n");
+		return -EINVAL;
+	}
+
+	if (resource->type != VME_MASTER) {
+		printk(KERN_ERR "Not a master resource\n");
+		return -EINVAL;
+	}
+
+	image = list_entry(resource->entry, struct vme_master_resource, list);
+
+	length = vme_get_size(resource);
+
+	if (offset > length) {
+		printk(KERN_WARNING "Invalid Offset\n");
+		return -EFAULT;
+	}
+
+	if ((offset + count) > length)
+		count = length - offset;
+
+	return bridge->master_read(image, buf, count, offset);
+
+}
+EXPORT_SYMBOL(vme_master_read);
+
+/*
+ * Write data out to VME space from a buffer.
+ */
+ssize_t vme_master_write(struct vme_resource *resource, void *buf,
+	size_t count, loff_t offset)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_master_resource *image;
+	size_t length;
+
+	if (bridge->master_write == NULL) {
+		printk(KERN_WARNING "Writing to resource not supported\n");
+		return -EINVAL;
+	}
+
+	if (resource->type != VME_MASTER) {
+		printk(KERN_ERR "Not a master resource\n");
+		return -EINVAL;
+	}
+
+	image = list_entry(resource->entry, struct vme_master_resource, list);
+
+	length = vme_get_size(resource);
+
+	if (offset > length) {
+		printk(KERN_WARNING "Invalid Offset\n");
+		return -EFAULT;
+	}
+
+	if ((offset + count) > length)
+		count = length - offset;
+
+	return bridge->master_write(image, buf, count, offset);
+}
+EXPORT_SYMBOL(vme_master_write);
+
+/*
+ * Perform RMW cycle to provided location.
+ */
+unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask,
+	unsigned int compare, unsigned int swap, loff_t offset)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_master_resource *image;
+
+	if (bridge->master_rmw == NULL) {
+		printk(KERN_WARNING "Writing to resource not supported\n");
+		return -EINVAL;
+	}
+
+	if (resource->type != VME_MASTER) {
+		printk(KERN_ERR "Not a master resource\n");
+		return -EINVAL;
+	}
+
+	image = list_entry(resource->entry, struct vme_master_resource, list);
+
+	return bridge->master_rmw(image, mask, compare, swap, offset);
+}
+EXPORT_SYMBOL(vme_master_rmw);
+
+void vme_master_free(struct vme_resource *resource)
+{
+	struct vme_master_resource *master_image;
+
+	if (resource->type != VME_MASTER) {
+		printk(KERN_ERR "Not a master resource\n");
+		return;
+	}
+
+	master_image = list_entry(resource->entry, struct vme_master_resource,
+		list);
+	if (master_image == NULL) {
+		printk(KERN_ERR "Can't find master resource\n");
+		return;
+	}
+
+	/* Unlock image */
+	spin_lock(&master_image->lock);
+	if (master_image->locked == 0)
+		printk(KERN_ERR "Image is already free\n");
+
+	master_image->locked = 0;
+	spin_unlock(&master_image->lock);
+
+	/* Free up resource memory */
+	kfree(resource);
+}
+EXPORT_SYMBOL(vme_master_free);
+
+/*
+ * Request a DMA controller with specific attributes, return some unique
+ * identifier.
+ */
+struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route)
+{
+	struct vme_bridge *bridge;
+	struct list_head *dma_pos = NULL;
+	struct vme_dma_resource *allocated_ctrlr = NULL;
+	struct vme_dma_resource *dma_ctrlr = NULL;
+	struct vme_resource *resource = NULL;
+
+	/* XXX Not checking resource attributes */
+	printk(KERN_ERR "No VME resource Attribute tests done\n");
+
+	bridge = vdev->bridge;
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find VME bus\n");
+		goto err_bus;
+	}
+
+	/* Loop through DMA resources */
+	list_for_each(dma_pos, &bridge->dma_resources) {
+		dma_ctrlr = list_entry(dma_pos,
+			struct vme_dma_resource, list);
+
+		if (dma_ctrlr == NULL) {
+			printk(KERN_ERR "Registered NULL DMA resource\n");
+			continue;
+		}
+
+		/* Find an unlocked and compatible controller */
+		mutex_lock(&dma_ctrlr->mtx);
+		if (((dma_ctrlr->route_attr & route) == route) &&
+			(dma_ctrlr->locked == 0)) {
+
+			dma_ctrlr->locked = 1;
+			mutex_unlock(&dma_ctrlr->mtx);
+			allocated_ctrlr = dma_ctrlr;
+			break;
+		}
+		mutex_unlock(&dma_ctrlr->mtx);
+	}
+
+	/* Check to see if we found a resource */
+	if (allocated_ctrlr == NULL)
+		goto err_ctrlr;
+
+	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+	if (resource == NULL) {
+		printk(KERN_WARNING "Unable to allocate resource structure\n");
+		goto err_alloc;
+	}
+	resource->type = VME_DMA;
+	resource->entry = &allocated_ctrlr->list;
+
+	return resource;
+
+err_alloc:
+	/* Unlock image */
+	mutex_lock(&dma_ctrlr->mtx);
+	dma_ctrlr->locked = 0;
+	mutex_unlock(&dma_ctrlr->mtx);
+err_ctrlr:
+err_bus:
+	return NULL;
+}
+EXPORT_SYMBOL(vme_dma_request);
+
+/*
+ * Start new list
+ */
+struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
+{
+	struct vme_dma_resource *ctrlr;
+	struct vme_dma_list *dma_list;
+
+	if (resource->type != VME_DMA) {
+		printk(KERN_ERR "Not a DMA resource\n");
+		return NULL;
+	}
+
+	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
+
+	dma_list = kmalloc(sizeof(struct vme_dma_list), GFP_KERNEL);
+	if (dma_list == NULL) {
+		printk(KERN_ERR "Unable to allocate memory for new dma list\n");
+		return NULL;
+	}
+	INIT_LIST_HEAD(&dma_list->entries);
+	dma_list->parent = ctrlr;
+	mutex_init(&dma_list->mtx);
+
+	return dma_list;
+}
+EXPORT_SYMBOL(vme_new_dma_list);
+
+/*
+ * Create "Pattern" type attributes
+ */
+struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type)
+{
+	struct vme_dma_attr *attributes;
+	struct vme_dma_pattern *pattern_attr;
+
+	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
+	if (attributes == NULL) {
+		printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
+		goto err_attr;
+	}
+
+	pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
+	if (pattern_attr == NULL) {
+		printk(KERN_ERR "Unable to allocate memory for pattern attributes\n");
+		goto err_pat;
+	}
+
+	attributes->type = VME_DMA_PATTERN;
+	attributes->private = (void *)pattern_attr;
+
+	pattern_attr->pattern = pattern;
+	pattern_attr->type = type;
+
+	return attributes;
+
+err_pat:
+	kfree(attributes);
+err_attr:
+	return NULL;
+}
+EXPORT_SYMBOL(vme_dma_pattern_attribute);
+
+/*
+ * Create "PCI" type attributes
+ */
+struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
+{
+	struct vme_dma_attr *attributes;
+	struct vme_dma_pci *pci_attr;
+
+	/* XXX Run some sanity checks here */
+
+	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
+	if (attributes == NULL) {
+		printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
+		goto err_attr;
+	}
+
+	pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
+	if (pci_attr == NULL) {
+		printk(KERN_ERR "Unable to allocate memory for pci attributes\n");
+		goto err_pci;
+	}
+
+
+
+	attributes->type = VME_DMA_PCI;
+	attributes->private = (void *)pci_attr;
+
+	pci_attr->address = address;
+
+	return attributes;
+
+err_pci:
+	kfree(attributes);
+err_attr:
+	return NULL;
+}
+EXPORT_SYMBOL(vme_dma_pci_attribute);
+
+/*
+ * Create "VME" type attributes
+ */
+struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
+	u32 aspace, u32 cycle, u32 dwidth)
+{
+	struct vme_dma_attr *attributes;
+	struct vme_dma_vme *vme_attr;
+
+	attributes = kmalloc(
+		sizeof(struct vme_dma_attr), GFP_KERNEL);
+	if (attributes == NULL) {
+		printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
+		goto err_attr;
+	}
+
+	vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
+	if (vme_attr == NULL) {
+		printk(KERN_ERR "Unable to allocate memory for vme attributes\n");
+		goto err_vme;
+	}
+
+	attributes->type = VME_DMA_VME;
+	attributes->private = (void *)vme_attr;
+
+	vme_attr->address = address;
+	vme_attr->aspace = aspace;
+	vme_attr->cycle = cycle;
+	vme_attr->dwidth = dwidth;
+
+	return attributes;
+
+err_vme:
+	kfree(attributes);
+err_attr:
+	return NULL;
+}
+EXPORT_SYMBOL(vme_dma_vme_attribute);
+
+/*
+ * Free attribute
+ */
+void vme_dma_free_attribute(struct vme_dma_attr *attributes)
+{
+	kfree(attributes->private);
+	kfree(attributes);
+}
+EXPORT_SYMBOL(vme_dma_free_attribute);
+
+int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
+	struct vme_dma_attr *dest, size_t count)
+{
+	struct vme_bridge *bridge = list->parent->parent;
+	int retval;
+
+	if (bridge->dma_list_add == NULL) {
+		printk(KERN_WARNING "Link List DMA generation not supported\n");
+		return -EINVAL;
+	}
+
+	if (!mutex_trylock(&list->mtx)) {
+		printk(KERN_ERR "Link List already submitted\n");
+		return -EINVAL;
+	}
+
+	retval = bridge->dma_list_add(list, src, dest, count);
+
+	mutex_unlock(&list->mtx);
+
+	return retval;
+}
+EXPORT_SYMBOL(vme_dma_list_add);
+
+int vme_dma_list_exec(struct vme_dma_list *list)
+{
+	struct vme_bridge *bridge = list->parent->parent;
+	int retval;
+
+	if (bridge->dma_list_exec == NULL) {
+		printk(KERN_ERR "Link List DMA execution not supported\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&list->mtx);
+
+	retval = bridge->dma_list_exec(list);
+
+	mutex_unlock(&list->mtx);
+
+	return retval;
+}
+EXPORT_SYMBOL(vme_dma_list_exec);
+
+int vme_dma_list_free(struct vme_dma_list *list)
+{
+	struct vme_bridge *bridge = list->parent->parent;
+	int retval;
+
+	if (bridge->dma_list_empty == NULL) {
+		printk(KERN_WARNING "Emptying of Link Lists not supported\n");
+		return -EINVAL;
+	}
+
+	if (!mutex_trylock(&list->mtx)) {
+		printk(KERN_ERR "Link List in use\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Empty out all of the entries from the dma list. We need to go to the
+	 * low level driver as dma entries are driver specific.
+	 */
+	retval = bridge->dma_list_empty(list);
+	if (retval) {
+		printk(KERN_ERR "Unable to empty link-list entries\n");
+		mutex_unlock(&list->mtx);
+		return retval;
+	}
+	mutex_unlock(&list->mtx);
+	kfree(list);
+
+	return retval;
+}
+EXPORT_SYMBOL(vme_dma_list_free);
+
+int vme_dma_free(struct vme_resource *resource)
+{
+	struct vme_dma_resource *ctrlr;
+
+	if (resource->type != VME_DMA) {
+		printk(KERN_ERR "Not a DMA resource\n");
+		return -EINVAL;
+	}
+
+	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
+
+	if (!mutex_trylock(&ctrlr->mtx)) {
+		printk(KERN_ERR "Resource busy, can't free\n");
+		return -EBUSY;
+	}
+
+	if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) {
+		printk(KERN_WARNING "Resource still processing transfers\n");
+		mutex_unlock(&ctrlr->mtx);
+		return -EBUSY;
+	}
+
+	ctrlr->locked = 0;
+
+	mutex_unlock(&ctrlr->mtx);
+
+	return 0;
+}
+EXPORT_SYMBOL(vme_dma_free);
+
+void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
+{
+	void (*call)(int, int, void *);
+	void *priv_data;
+
+	call = bridge->irq[level - 1].callback[statid].func;
+	priv_data = bridge->irq[level - 1].callback[statid].priv_data;
+
+	if (call != NULL)
+		call(level, statid, priv_data);
+	else
+		printk(KERN_WARNING "Spurilous VME interrupt, level:%x, vector:%x\n",
+		       level, statid);
+}
+EXPORT_SYMBOL(vme_irq_handler);
+
+int vme_irq_request(struct vme_dev *vdev, int level, int statid,
+	void (*callback)(int, int, void *),
+	void *priv_data)
+{
+	struct vme_bridge *bridge;
+
+	bridge = vdev->bridge;
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find VME bus\n");
+		return -EINVAL;
+	}
+
+	if ((level < 1) || (level > 7)) {
+		printk(KERN_ERR "Invalid interrupt level\n");
+		return -EINVAL;
+	}
+
+	if (bridge->irq_set == NULL) {
+		printk(KERN_ERR "Configuring interrupts not supported\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&bridge->irq_mtx);
+
+	if (bridge->irq[level - 1].callback[statid].func) {
+		mutex_unlock(&bridge->irq_mtx);
+		printk(KERN_WARNING "VME Interrupt already taken\n");
+		return -EBUSY;
+	}
+
+	bridge->irq[level - 1].count++;
+	bridge->irq[level - 1].callback[statid].priv_data = priv_data;
+	bridge->irq[level - 1].callback[statid].func = callback;
+
+	/* Enable IRQ level */
+	bridge->irq_set(bridge, level, 1, 1);
+
+	mutex_unlock(&bridge->irq_mtx);
+
+	return 0;
+}
+EXPORT_SYMBOL(vme_irq_request);
+
+void vme_irq_free(struct vme_dev *vdev, int level, int statid)
+{
+	struct vme_bridge *bridge;
+
+	bridge = vdev->bridge;
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find VME bus\n");
+		return;
+	}
+
+	if ((level < 1) || (level > 7)) {
+		printk(KERN_ERR "Invalid interrupt level\n");
+		return;
+	}
+
+	if (bridge->irq_set == NULL) {
+		printk(KERN_ERR "Configuring interrupts not supported\n");
+		return;
+	}
+
+	mutex_lock(&bridge->irq_mtx);
+
+	bridge->irq[level - 1].count--;
+
+	/* Disable IRQ level if no more interrupts attached at this level*/
+	if (bridge->irq[level - 1].count == 0)
+		bridge->irq_set(bridge, level, 0, 1);
+
+	bridge->irq[level - 1].callback[statid].func = NULL;
+	bridge->irq[level - 1].callback[statid].priv_data = NULL;
+
+	mutex_unlock(&bridge->irq_mtx);
+}
+EXPORT_SYMBOL(vme_irq_free);
+
+int vme_irq_generate(struct vme_dev *vdev, int level, int statid)
+{
+	struct vme_bridge *bridge;
+
+	bridge = vdev->bridge;
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find VME bus\n");
+		return -EINVAL;
+	}
+
+	if ((level < 1) || (level > 7)) {
+		printk(KERN_WARNING "Invalid interrupt level\n");
+		return -EINVAL;
+	}
+
+	if (bridge->irq_generate == NULL) {
+		printk(KERN_WARNING "Interrupt generation not supported\n");
+		return -EINVAL;
+	}
+
+	return bridge->irq_generate(bridge, level, statid);
+}
+EXPORT_SYMBOL(vme_irq_generate);
+
+/*
+ * Request the location monitor, return resource or NULL
+ */
+struct vme_resource *vme_lm_request(struct vme_dev *vdev)
+{
+	struct vme_bridge *bridge;
+	struct list_head *lm_pos = NULL;
+	struct vme_lm_resource *allocated_lm = NULL;
+	struct vme_lm_resource *lm = NULL;
+	struct vme_resource *resource = NULL;
+
+	bridge = vdev->bridge;
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find VME bus\n");
+		goto err_bus;
+	}
+
+	/* Loop through DMA resources */
+	list_for_each(lm_pos, &bridge->lm_resources) {
+		lm = list_entry(lm_pos,
+			struct vme_lm_resource, list);
+
+		if (lm == NULL) {
+			printk(KERN_ERR "Registered NULL Location Monitor resource\n");
+			continue;
+		}
+
+		/* Find an unlocked controller */
+		mutex_lock(&lm->mtx);
+		if (lm->locked == 0) {
+			lm->locked = 1;
+			mutex_unlock(&lm->mtx);
+			allocated_lm = lm;
+			break;
+		}
+		mutex_unlock(&lm->mtx);
+	}
+
+	/* Check to see if we found a resource */
+	if (allocated_lm == NULL)
+		goto err_lm;
+
+	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+	if (resource == NULL) {
+		printk(KERN_ERR "Unable to allocate resource structure\n");
+		goto err_alloc;
+	}
+	resource->type = VME_LM;
+	resource->entry = &allocated_lm->list;
+
+	return resource;
+
+err_alloc:
+	/* Unlock image */
+	mutex_lock(&lm->mtx);
+	lm->locked = 0;
+	mutex_unlock(&lm->mtx);
+err_lm:
+err_bus:
+	return NULL;
+}
+EXPORT_SYMBOL(vme_lm_request);
+
+int vme_lm_count(struct vme_resource *resource)
+{
+	struct vme_lm_resource *lm;
+
+	if (resource->type != VME_LM) {
+		printk(KERN_ERR "Not a Location Monitor resource\n");
+		return -EINVAL;
+	}
+
+	lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+	return lm->monitors;
+}
+EXPORT_SYMBOL(vme_lm_count);
+
+int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
+	u32 aspace, u32 cycle)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_lm_resource *lm;
+
+	if (resource->type != VME_LM) {
+		printk(KERN_ERR "Not a Location Monitor resource\n");
+		return -EINVAL;
+	}
+
+	lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+	if (bridge->lm_set == NULL) {
+		printk(KERN_ERR "vme_lm_set not supported\n");
+		return -EINVAL;
+	}
+
+	return bridge->lm_set(lm, lm_base, aspace, cycle);
+}
+EXPORT_SYMBOL(vme_lm_set);
+
+int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
+	u32 *aspace, u32 *cycle)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_lm_resource *lm;
+
+	if (resource->type != VME_LM) {
+		printk(KERN_ERR "Not a Location Monitor resource\n");
+		return -EINVAL;
+	}
+
+	lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+	if (bridge->lm_get == NULL) {
+		printk(KERN_ERR "vme_lm_get not supported\n");
+		return -EINVAL;
+	}
+
+	return bridge->lm_get(lm, lm_base, aspace, cycle);
+}
+EXPORT_SYMBOL(vme_lm_get);
+
+int vme_lm_attach(struct vme_resource *resource, int monitor,
+	void (*callback)(int))
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_lm_resource *lm;
+
+	if (resource->type != VME_LM) {
+		printk(KERN_ERR "Not a Location Monitor resource\n");
+		return -EINVAL;
+	}
+
+	lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+	if (bridge->lm_attach == NULL) {
+		printk(KERN_ERR "vme_lm_attach not supported\n");
+		return -EINVAL;
+	}
+
+	return bridge->lm_attach(lm, monitor, callback);
+}
+EXPORT_SYMBOL(vme_lm_attach);
+
+int vme_lm_detach(struct vme_resource *resource, int monitor)
+{
+	struct vme_bridge *bridge = find_bridge(resource);
+	struct vme_lm_resource *lm;
+
+	if (resource->type != VME_LM) {
+		printk(KERN_ERR "Not a Location Monitor resource\n");
+		return -EINVAL;
+	}
+
+	lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+	if (bridge->lm_detach == NULL) {
+		printk(KERN_ERR "vme_lm_detach not supported\n");
+		return -EINVAL;
+	}
+
+	return bridge->lm_detach(lm, monitor);
+}
+EXPORT_SYMBOL(vme_lm_detach);
+
+void vme_lm_free(struct vme_resource *resource)
+{
+	struct vme_lm_resource *lm;
+
+	if (resource->type != VME_LM) {
+		printk(KERN_ERR "Not a Location Monitor resource\n");
+		return;
+	}
+
+	lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+	mutex_lock(&lm->mtx);
+
+	/* XXX
+	 * Check to see that there aren't any callbacks still attached, if
+	 * there are we should probably be detaching them!
+	 */
+
+	lm->locked = 0;
+
+	mutex_unlock(&lm->mtx);
+
+	kfree(resource);
+}
+EXPORT_SYMBOL(vme_lm_free);
+
+int vme_slot_get(struct vme_dev *vdev)
+{
+	struct vme_bridge *bridge;
+
+	bridge = vdev->bridge;
+	if (bridge == NULL) {
+		printk(KERN_ERR "Can't find VME bus\n");
+		return -EINVAL;
+	}
+
+	if (bridge->slot_get == NULL) {
+		printk(KERN_WARNING "vme_slot_get not supported\n");
+		return -EINVAL;
+	}
+
+	return bridge->slot_get(bridge);
+}
+EXPORT_SYMBOL(vme_slot_get);
+
+
+/* - Bridge Registration --------------------------------------------------- */
+
+static void vme_dev_release(struct device *dev)
+{
+	kfree(dev_to_vme_dev(dev));
+}
+
+int vme_register_bridge(struct vme_bridge *bridge)
+{
+	int i;
+	int ret = -1;
+
+	mutex_lock(&vme_buses_lock);
+	for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
+		if ((vme_bus_numbers & (1 << i)) == 0) {
+			vme_bus_numbers |= (1 << i);
+			bridge->num = i;
+			INIT_LIST_HEAD(&bridge->devices);
+			list_add_tail(&bridge->bus_list, &vme_bus_list);
+			ret = 0;
+			break;
+		}
+	}
+	mutex_unlock(&vme_buses_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(vme_register_bridge);
+
+void vme_unregister_bridge(struct vme_bridge *bridge)
+{
+	struct vme_dev *vdev;
+	struct vme_dev *tmp;
+
+	mutex_lock(&vme_buses_lock);
+	vme_bus_numbers &= ~(1 << bridge->num);
+	list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) {
+		list_del(&vdev->drv_list);
+		list_del(&vdev->bridge_list);
+		device_unregister(&vdev->dev);
+	}
+	list_del(&bridge->bus_list);
+	mutex_unlock(&vme_buses_lock);
+}
+EXPORT_SYMBOL(vme_unregister_bridge);
+
+/* - Driver Registration --------------------------------------------------- */
+
+static int __vme_register_driver_bus(struct vme_driver *drv,
+	struct vme_bridge *bridge, unsigned int ndevs)
+{
+	int err;
+	unsigned int i;
+	struct vme_dev *vdev;
+	struct vme_dev *tmp;
+
+	for (i = 0; i < ndevs; i++) {
+		vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL);
+		if (!vdev) {
+			err = -ENOMEM;
+			goto err_devalloc;
+		}
+		vdev->num = i;
+		vdev->bridge = bridge;
+		vdev->dev.platform_data = drv;
+		vdev->dev.release = vme_dev_release;
+		vdev->dev.parent = bridge->parent;
+		vdev->dev.bus = &vme_bus_type;
+		dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num,
+			vdev->num);
+
+		err = device_register(&vdev->dev);
+		if (err)
+			goto err_reg;
+
+		if (vdev->dev.platform_data) {
+			list_add_tail(&vdev->drv_list, &drv->devices);
+			list_add_tail(&vdev->bridge_list, &bridge->devices);
+		} else
+			device_unregister(&vdev->dev);
+	}
+	return 0;
+
+err_reg:
+	kfree(vdev);
+err_devalloc:
+	list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) {
+		list_del(&vdev->drv_list);
+		list_del(&vdev->bridge_list);
+		device_unregister(&vdev->dev);
+	}
+	return err;
+}
+
+static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
+{
+	struct vme_bridge *bridge;
+	int err = 0;
+
+	mutex_lock(&vme_buses_lock);
+	list_for_each_entry(bridge, &vme_bus_list, bus_list) {
+		/*
+		 * This cannot cause trouble as we already have vme_buses_lock
+		 * and if the bridge is removed, it will have to go through
+		 * vme_unregister_bridge() to do it (which calls remove() on
+		 * the bridge which in turn tries to acquire vme_buses_lock and
+		 * will have to wait).
+		 */
+		err = __vme_register_driver_bus(drv, bridge, ndevs);
+		if (err)
+			break;
+	}
+	mutex_unlock(&vme_buses_lock);
+	return err;
+}
+
+int vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
+{
+	int err;
+
+	drv->driver.name = drv->name;
+	drv->driver.bus = &vme_bus_type;
+	INIT_LIST_HEAD(&drv->devices);
+
+	err = driver_register(&drv->driver);
+	if (err)
+		return err;
+
+	err = __vme_register_driver(drv, ndevs);
+	if (err)
+		driver_unregister(&drv->driver);
+
+	return err;
+}
+EXPORT_SYMBOL(vme_register_driver);
+
+void vme_unregister_driver(struct vme_driver *drv)
+{
+	struct vme_dev *dev, *dev_tmp;
+
+	mutex_lock(&vme_buses_lock);
+	list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) {
+		list_del(&dev->drv_list);
+		list_del(&dev->bridge_list);
+		device_unregister(&dev->dev);
+	}
+	mutex_unlock(&vme_buses_lock);
+
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(vme_unregister_driver);
+
+/* - Bus Registration ------------------------------------------------------ */
+
+static int vme_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct vme_driver *vme_drv;
+
+	vme_drv = container_of(drv, struct vme_driver, driver);
+
+	if (dev->platform_data == vme_drv) {
+		struct vme_dev *vdev = dev_to_vme_dev(dev);
+
+		if (vme_drv->match && vme_drv->match(vdev))
+			return 1;
+
+		dev->platform_data = NULL;
+	}
+	return 0;
+}
+
+static int vme_bus_probe(struct device *dev)
+{
+	int retval = -ENODEV;
+	struct vme_driver *driver;
+	struct vme_dev *vdev = dev_to_vme_dev(dev);
+
+	driver = dev->platform_data;
+
+	if (driver->probe != NULL)
+		retval = driver->probe(vdev);
+
+	return retval;
+}
+
+static int vme_bus_remove(struct device *dev)
+{
+	int retval = -ENODEV;
+	struct vme_driver *driver;
+	struct vme_dev *vdev = dev_to_vme_dev(dev);
+
+	driver = dev->platform_data;
+
+	if (driver->remove != NULL)
+		retval = driver->remove(vdev);
+
+	return retval;
+}
+
+struct bus_type vme_bus_type = {
+	.name = "vme",
+	.match = vme_bus_match,
+	.probe = vme_bus_probe,
+	.remove = vme_bus_remove,
+};
+EXPORT_SYMBOL(vme_bus_type);
+
+static int __init vme_init(void)
+{
+	return bus_register(&vme_bus_type);
+}
+
+static void __exit vme_exit(void)
+{
+	bus_unregister(&vme_bus_type);
+}
+
+MODULE_DESCRIPTION("VME bridge driver framework");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
+MODULE_LICENSE("GPL");
+
+module_init(vme_init);
+module_exit(vme_exit);
diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/vme/vme_bridge.h
similarity index 100%
rename from drivers/staging/vme/vme_bridge.h
rename to drivers/vme/vme_bridge.h
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index fd2c7bd..6743bde 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -16,7 +16,7 @@
 	depends on CONNECTOR
 	bool "Userspace communication over connector"
 	default y
-	--- help ---
+	---help---
 	  This allows to communicate with userspace using connector. For more
 	  information see <file:Documentation/connector/connector.txt>.
 	  There are three types of messages between w1 core and userspace:
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index 7c8cdb8..8e813ee 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -332,7 +332,6 @@
 		},
 		.size = 1,
 		.read = w1_f29_read_cond_search_mask,
-		.write = 0,
 	},
 	{
 		.attr =	{
@@ -341,7 +340,6 @@
 		},
 		.size = 1,
 		.read = w1_f29_read_cond_search_polarity,
-		.write = 0,
 	},
 	{
 		.attr =	{
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 9761950..2f2e894 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -1027,7 +1027,7 @@
 	retval = driver_register(&w1_slave_driver);
 	if (retval) {
 		printk(KERN_ERR
-			"Failed to register master driver. err=%d.\n",
+			"Failed to register slave driver. err=%d.\n",
 			retval);
 		goto err_out_master_unregister;
 	}
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 3135b2c..e10acc2 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -31,6 +31,9 @@
 static int w1_delay_parm = 1;
 module_param_named(delay_coef, w1_delay_parm, int, 0);
 
+static int w1_disable_irqs = 0;
+module_param_named(disable_irqs, w1_disable_irqs, int, 0);
+
 static u8 w1_crc8_table[] = {
 	0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
 	157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
@@ -79,6 +82,10 @@
  */
 static void w1_write_bit(struct w1_master *dev, int bit)
 {
+	unsigned long flags = 0;
+
+	if(w1_disable_irqs) local_irq_save(flags);
+
 	if (bit) {
 		dev->bus_master->write_bit(dev->bus_master->data, 0);
 		w1_delay(6);
@@ -90,6 +97,8 @@
 		dev->bus_master->write_bit(dev->bus_master->data, 1);
 		w1_delay(10);
 	}
+
+	if(w1_disable_irqs) local_irq_restore(flags);
 }
 
 /**
@@ -158,7 +167,7 @@
 static u8 w1_read_bit(struct w1_master *dev)
 {
 	int result;
-	unsigned long flags;
+	unsigned long flags = 0;
 
 	/* sample timing is critical here */
 	local_irq_save(flags);
@@ -318,6 +327,9 @@
 int w1_reset_bus(struct w1_master *dev)
 {
 	int result;
+	unsigned long flags = 0;
+
+	if(w1_disable_irqs) local_irq_save(flags);
 
 	if (dev->bus_master->reset_bus)
 		result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1;
@@ -330,19 +342,21 @@
 		 * cpu for such a short amount of time AND get it back in
 		 * the maximum amount of time.
 		 */
-		w1_delay(480);
+		w1_delay(500);
 		dev->bus_master->write_bit(dev->bus_master->data, 1);
 		w1_delay(70);
 
 		result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1;
-		/* minmum 70 (above) + 410 = 480 us
+		/* minmum 70 (above) + 430 = 500 us
 		 * There aren't any timing requirements between a reset and
 		 * the following transactions.  Sleeping is safe here.
 		 */
-		/* w1_delay(410); min required time */
+		/* w1_delay(430); min required time */
 		msleep(1);
 	}
 
+	if(w1_disable_irqs) local_irq_restore(flags);
+
 	return result;
 }
 EXPORT_SYMBOL_GPL(w1_reset_bus);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3709624..a18bf63 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -129,17 +129,6 @@
 
 	  Not sure? It's safe to say N.
 
-config IXP2000_WATCHDOG
-	tristate "IXP2000 Watchdog"
-	depends on ARCH_IXP2000
-	help
-	  Say Y here if to include support for the watchdog timer
-	  in the Intel IXP2000(2400, 2800, 2850) network processors.
-	  This driver can be built as a module by choosing M. The module
-	  will be called ixp2000_wdt.
-
-	  Say N if you are unsure.
-
 config IXP4XX_WATCHDOG
 	tristate "IXP4xx Watchdog"
 	depends on ARCH_IXP4XX
@@ -543,7 +532,7 @@
 
 config I6300ESB_WDT
 	tristate "Intel 6300ESB Timer/Watchdog"
-	depends on X86 && PCI
+	depends on PCI
 	---help---
 	  Hardware driver for the watchdog timer built into the Intel
 	  6300ESB controller hub.
@@ -551,6 +540,19 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called i6300esb.
 
+config IE6XX_WDT
+	tristate "Intel Atom E6xx Watchdog"
+	depends on X86 && PCI
+	select WATCHDOG_CORE
+	select MFD_CORE
+	select LPC_SCH
+	---help---
+	  Hardware driver for the watchdog timer built into the Intel
+	  Atom E6XX (TunnelCreek) processor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ie6xx_wdt.
+
 config INTEL_SCU_WATCHDOG
 	bool "Intel SCU Watchdog for Mobile Platforms"
 	depends on X86_MRST
@@ -607,7 +609,12 @@
 	depends on X86 && EXPERIMENTAL
 	---help---
 	  This is the driver for the hardware watchdog on the ITE IT8702,
-	  IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 Super I/O chips.
+	  IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728
+	  Super I/O chips.
+
+	  If the driver does not work, then make sure that the game port in
+	  the BIOS is enabled.
+
 	  This watchdog simply watches your kernel to make sure it doesn't
 	  freeze, and if it does, it reboots your computer after a certain
 	  amount of time.
@@ -780,7 +787,7 @@
 
 config VIA_WDT
 	tristate "VIA Watchdog Timer"
-	depends on X86
+	depends on X86 && PCI
 	select WATCHDOG_CORE
 	---help---
 	This is the driver for the hardware watchdog timer on VIA
@@ -937,7 +944,7 @@
 	tristate "Broadcom BCM47xx Watchdog Timer"
 	depends on BCM47XX
 	help
-	  Hardware driver for the Broadcom BCM47xx Watchog Timer.
+	  Hardware driver for the Broadcom BCM47xx Watchdog Timer.
 
 config RC32434_WDT
 	tristate "IDT RC32434 SoC Watchdog Timer"
@@ -1138,6 +1145,7 @@
 config SH_WDT
 	tristate "SuperH Watchdog"
 	depends on SUPERH && (CPU_SH3 || CPU_SH4)
+	select WATCHDOG_CORE
 	help
 	  This driver adds watchdog support for the integrated watchdog in the
 	  SuperH processors. If you have one of these processors and wish
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index e8f479a..442bfbe 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -36,7 +36,6 @@
 obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
 obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
@@ -81,6 +80,7 @@
 obj-$(CONFIG_IBMASR) += ibmasr.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
+obj-$(CONFIG_IE6XX_WDT) += ie6xx_wdt.o
 obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o
 ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y)
 obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index 639ae9a..dc30dbd 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -282,29 +282,19 @@
 		platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
 	if (!ar7_regs_wdt) {
 		pr_err("could not get registers resource\n");
-		rc = -ENODEV;
-		goto out;
+		return -ENODEV;
 	}
 
-	if (!request_mem_region(ar7_regs_wdt->start,
-				resource_size(ar7_regs_wdt), LONGNAME)) {
-		pr_warn("watchdog I/O region busy\n");
-		rc = -EBUSY;
-		goto out;
-	}
-
-	ar7_wdt = ioremap(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
+	ar7_wdt = devm_request_and_ioremap(&pdev->dev, ar7_regs_wdt);
 	if (!ar7_wdt) {
 		pr_err("could not ioremap registers\n");
-		rc = -ENXIO;
-		goto out_mem_region;
+		return -ENXIO;
 	}
 
 	vbus_clk = clk_get(NULL, "vbus");
 	if (IS_ERR(vbus_clk)) {
 		pr_err("could not get vbus clock\n");
-		rc = PTR_ERR(vbus_clk);
-		goto out_mem_region;
+		return PTR_ERR(vbus_clk);
 	}
 
 	ar7_wdt_disable_wdt();
@@ -314,24 +304,21 @@
 	rc = misc_register(&ar7_wdt_miscdev);
 	if (rc) {
 		pr_err("unable to register misc device\n");
-		goto out_alloc;
+		goto out;
 	}
-	goto out;
+	return 0;
 
-out_alloc:
-	iounmap(ar7_wdt);
-out_mem_region:
-	release_mem_region(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
 out:
+	clk_put(vbus_clk);
+	vbus_clk = NULL;
 	return rc;
 }
 
 static int __devexit ar7_wdt_remove(struct platform_device *pdev)
 {
 	misc_deregister(&ar7_wdt_miscdev);
-	iounmap(ar7_wdt);
-	release_mem_region(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
-
+	clk_put(vbus_clk);
+	vbus_clk = NULL;
 	return 0;
 }
 
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 23885f2d..2b76381 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -861,16 +861,6 @@
 	.remove = __devexit_p(hpwdt_exit),
 };
 
-static void __exit hpwdt_cleanup(void)
-{
-	pci_unregister_driver(&hpwdt_driver);
-}
-
-static int __init hpwdt_init(void)
-{
-	return pci_register_driver(&hpwdt_driver);
-}
-
 MODULE_AUTHOR("Tom Mingarelli");
 MODULE_DESCRIPTION("hp watchdog driver");
 MODULE_LICENSE("GPL");
@@ -889,5 +879,4 @@
 MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs");
 #endif /* !CONFIG_HPWDT_NMI_DECODING */
 
-module_init(hpwdt_init);
-module_exit(hpwdt_cleanup);
+module_pci_driver(hpwdt_driver);
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index 738032a..276877d 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -492,19 +492,7 @@
 	.shutdown       = esb_shutdown,
 };
 
-static int __init watchdog_init(void)
-{
-	return pci_register_driver(&esb_driver);
-}
-
-static void __exit watchdog_cleanup(void)
-{
-	pci_unregister_driver(&esb_driver);
-	pr_info("Watchdog Module Unloaded\n");
-}
-
-module_init(watchdog_init);
-module_exit(watchdog_cleanup);
+module_pci_driver(esb_driver);
 
 MODULE_AUTHOR("Ross Biro and David Härdeman");
 MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
diff --git a/drivers/watchdog/ie6xx_wdt.c b/drivers/watchdog/ie6xx_wdt.c
new file mode 100644
index 0000000..5f0d776
--- /dev/null
+++ b/drivers/watchdog/ie6xx_wdt.c
@@ -0,0 +1,348 @@
+/*
+ *      Intel Atom E6xx Watchdog driver
+ *
+ *      Copyright (C) 2011 Alexander Stein
+ *                <alexander.stein@systec-electronic.com>
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of version 2 of the GNU General
+ *      Public License 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., 59 Temple Place - Suite 330,
+ *      Boston, MA  02111-1307, USA.
+ *      The full GNU General Public License is included in this
+ *      distribution in the file called COPYING.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+
+#define DRIVER_NAME "ie6xx_wdt"
+
+#define PV1	0x00
+#define PV2	0x04
+
+#define RR0	0x0c
+#define RR1	0x0d
+#define WDT_RELOAD	0x01
+#define WDT_TOUT	0x02
+
+#define WDTCR	0x10
+#define WDT_PRE_SEL	0x04
+#define WDT_RESET_SEL	0x08
+#define WDT_RESET_EN	0x10
+#define WDT_TOUT_EN	0x20
+
+#define DCR	0x14
+
+#define WDTLR	0x18
+#define WDT_LOCK	0x01
+#define WDT_ENABLE	0x02
+#define WDT_TOUT_CNF	0x03
+
+#define MIN_TIME	1
+#define MAX_TIME	(10 * 60) /* 10 minutes */
+#define DEFAULT_TIME	60
+
+static unsigned int timeout = DEFAULT_TIME;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+		"Default Watchdog timer setting ("
+		__MODULE_STRING(DEFAULT_TIME) "s)."
+		"The range is from 1 to 600");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+	"Watchdog cannot be stopped once started (default="
+		__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static u8 resetmode = 0x10;
+module_param(resetmode, byte, 0);
+MODULE_PARM_DESC(resetmode,
+	"Resetmode bits: 0x08 warm reset (cold reset otherwise), "
+	"0x10 reset enable, 0x20 disable toggle GPIO[4] (default=0x10)");
+
+static struct {
+	unsigned short sch_wdtba;
+	struct spinlock unlock_sequence;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs;
+#endif
+} ie6xx_wdt_data;
+
+/*
+ * This is needed to write to preload and reload registers
+ * struct ie6xx_wdt_data.unlock_sequence must be used
+ * to prevent sequence interrupts
+ */
+static void ie6xx_wdt_unlock_registers(void)
+{
+	outb(0x80, ie6xx_wdt_data.sch_wdtba + RR0);
+	outb(0x86, ie6xx_wdt_data.sch_wdtba + RR0);
+}
+
+static int ie6xx_wdt_ping(struct watchdog_device *wdd)
+{
+	spin_lock(&ie6xx_wdt_data.unlock_sequence);
+	ie6xx_wdt_unlock_registers();
+	outb(WDT_RELOAD, ie6xx_wdt_data.sch_wdtba + RR1);
+	spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+	return 0;
+}
+
+static int ie6xx_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
+{
+	u32 preload;
+	u64 clock;
+	u8 wdtcr;
+
+	/* Watchdog clock is PCI Clock (33MHz) */
+	clock = 33000000;
+	/* and the preload value is loaded into [34:15] of the down counter */
+	preload = (t * clock) >> 15;
+	/*
+	 * Manual states preload must be one less.
+	 * Does not wrap as t is at least 1
+	 */
+	preload -= 1;
+
+	spin_lock(&ie6xx_wdt_data.unlock_sequence);
+
+	/* Set ResetMode & Enable prescaler for range 10ms to 10 min */
+	wdtcr = resetmode & 0x38;
+	outb(wdtcr, ie6xx_wdt_data.sch_wdtba + WDTCR);
+
+	ie6xx_wdt_unlock_registers();
+	outl(0, ie6xx_wdt_data.sch_wdtba + PV1);
+
+	ie6xx_wdt_unlock_registers();
+	outl(preload, ie6xx_wdt_data.sch_wdtba + PV2);
+
+	ie6xx_wdt_unlock_registers();
+	outb(WDT_RELOAD | WDT_TOUT, ie6xx_wdt_data.sch_wdtba + RR1);
+
+	spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+
+	wdd->timeout = t;
+	return 0;
+}
+
+static int ie6xx_wdt_start(struct watchdog_device *wdd)
+{
+	ie6xx_wdt_set_timeout(wdd, wdd->timeout);
+
+	/* Enable the watchdog timer */
+	spin_lock(&ie6xx_wdt_data.unlock_sequence);
+	outb(WDT_ENABLE, ie6xx_wdt_data.sch_wdtba + WDTLR);
+	spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+
+	return 0;
+}
+
+static int ie6xx_wdt_stop(struct watchdog_device *wdd)
+{
+	if (inb(ie6xx_wdt_data.sch_wdtba + WDTLR) & WDT_LOCK)
+		return -1;
+
+	/* Disable the watchdog timer */
+	spin_lock(&ie6xx_wdt_data.unlock_sequence);
+	outb(0, ie6xx_wdt_data.sch_wdtba + WDTLR);
+	spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+
+	return 0;
+}
+
+static const struct watchdog_info ie6xx_wdt_info = {
+	.identity =	"Intel Atom E6xx Watchdog",
+	.options =	WDIOF_SETTIMEOUT |
+			WDIOF_MAGICCLOSE |
+			WDIOF_KEEPALIVEPING,
+};
+
+static const struct watchdog_ops ie6xx_wdt_ops = {
+	.owner =	THIS_MODULE,
+	.start =	ie6xx_wdt_start,
+	.stop =		ie6xx_wdt_stop,
+	.ping =		ie6xx_wdt_ping,
+	.set_timeout =	ie6xx_wdt_set_timeout,
+};
+
+static struct watchdog_device ie6xx_wdt_dev = {
+	.info =		&ie6xx_wdt_info,
+	.ops =		&ie6xx_wdt_ops,
+	.min_timeout =	MIN_TIME,
+	.max_timeout =	MAX_TIME,
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+static int ie6xx_wdt_dbg_show(struct seq_file *s, void *unused)
+{
+	seq_printf(s, "PV1   = 0x%08x\n",
+		inl(ie6xx_wdt_data.sch_wdtba + PV1));
+	seq_printf(s, "PV2   = 0x%08x\n",
+		inl(ie6xx_wdt_data.sch_wdtba + PV2));
+	seq_printf(s, "RR    = 0x%08x\n",
+		inw(ie6xx_wdt_data.sch_wdtba + RR0));
+	seq_printf(s, "WDTCR = 0x%08x\n",
+		inw(ie6xx_wdt_data.sch_wdtba + WDTCR));
+	seq_printf(s, "DCR   = 0x%08x\n",
+		inl(ie6xx_wdt_data.sch_wdtba + DCR));
+	seq_printf(s, "WDTLR = 0x%08x\n",
+		inw(ie6xx_wdt_data.sch_wdtba + WDTLR));
+
+	seq_printf(s, "\n");
+	return 0;
+}
+
+static int ie6xx_wdt_dbg_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ie6xx_wdt_dbg_show, NULL);
+}
+
+static const struct file_operations ie6xx_wdt_dbg_operations = {
+	.open		= ie6xx_wdt_dbg_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void __devinit ie6xx_wdt_debugfs_init(void)
+{
+	/* /sys/kernel/debug/ie6xx_wdt */
+	ie6xx_wdt_data.debugfs = debugfs_create_file("ie6xx_wdt",
+		S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_dbg_operations);
+}
+
+static void __devexit ie6xx_wdt_debugfs_exit(void)
+{
+	debugfs_remove(ie6xx_wdt_data.debugfs);
+}
+
+#else
+static void __devinit ie6xx_wdt_debugfs_init(void)
+{
+}
+
+static void __devexit ie6xx_wdt_debugfs_exit(void)
+{
+}
+#endif
+
+static int __devinit ie6xx_wdt_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	u8 wdtlr;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!res)
+		return -ENODEV;
+
+	if (!request_region(res->start, resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "Watchdog region 0x%llx already in use!\n",
+			(u64)res->start);
+		return -EBUSY;
+	}
+
+	ie6xx_wdt_data.sch_wdtba = res->start;
+	dev_dbg(&pdev->dev, "WDT = 0x%X\n", ie6xx_wdt_data.sch_wdtba);
+
+	ie6xx_wdt_dev.timeout = timeout;
+	watchdog_set_nowayout(&ie6xx_wdt_dev, nowayout);
+
+	spin_lock_init(&ie6xx_wdt_data.unlock_sequence);
+
+	wdtlr = inb(ie6xx_wdt_data.sch_wdtba + WDTLR);
+	if (wdtlr & WDT_LOCK)
+		dev_warn(&pdev->dev,
+			"Watchdog Timer is Locked (Reg=0x%x)\n", wdtlr);
+
+	ie6xx_wdt_debugfs_init();
+
+	ret = watchdog_register_device(&ie6xx_wdt_dev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Watchdog timer: cannot register device (err =%d)\n",
+									ret);
+		goto misc_register_error;
+	}
+
+	return 0;
+
+misc_register_error:
+	ie6xx_wdt_debugfs_exit();
+	release_region(res->start, resource_size(res));
+	ie6xx_wdt_data.sch_wdtba = 0;
+	return ret;
+}
+
+static int __devexit ie6xx_wdt_remove(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	ie6xx_wdt_stop(NULL);
+	watchdog_unregister_device(&ie6xx_wdt_dev);
+	ie6xx_wdt_debugfs_exit();
+	release_region(res->start, resource_size(res));
+	ie6xx_wdt_data.sch_wdtba = 0;
+
+	return 0;
+}
+
+static struct platform_driver ie6xx_wdt_driver = {
+	.probe		= ie6xx_wdt_probe,
+	.remove		= __devexit_p(ie6xx_wdt_remove),
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ie6xx_wdt_init(void)
+{
+	/* Check boot parameters to verify that their initial values */
+	/* are in range. */
+	if ((timeout < MIN_TIME) ||
+	    (timeout > MAX_TIME)) {
+		pr_err("Watchdog timer: value of timeout %d (dec) "
+		  "is out of range from %d to %d (dec)\n",
+		  timeout, MIN_TIME, MAX_TIME);
+		return -EINVAL;
+	}
+
+	return platform_driver_register(&ie6xx_wdt_driver);
+}
+
+static void __exit ie6xx_wdt_exit(void)
+{
+	platform_driver_unregister(&ie6xx_wdt_driver);
+}
+
+late_initcall(ie6xx_wdt_init);
+module_exit(ie6xx_wdt_exit);
+
+MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
+MODULE_DESCRIPTION("Intel Atom E6xx Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index 8a741bc..d3dcc69 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -12,7 +12,8 @@
  *		    http://www.ite.com.tw/
  *
  *	Support of the watchdog timers, which are available on
- *	IT8702, IT8712, IT8716, IT8718, IT8720, IT8721 and IT8726.
+ *	IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726
+ *	and IT8728.
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -84,6 +85,7 @@
 #define IT8720_ID	0x8720
 #define IT8721_ID	0x8721
 #define IT8726_ID	0x8726	/* the data sheet suggest wrongly 0x8716 */
+#define IT8728_ID	0x8728
 
 /* GPIO Configuration Registers LDN=0x07 */
 #define WDTCTRL		0x71
@@ -95,7 +97,7 @@
 #define WDT_CIRINT	0x80
 #define WDT_MOUSEINT	0x40
 #define WDT_KYBINT	0x20
-#define WDT_GAMEPORT	0x10 /* not in it8718, it8720, it8721 */
+#define WDT_GAMEPORT	0x10 /* not in it8718, it8720, it8721, it8728 */
 #define WDT_FORCE	0x02
 #define WDT_ZERO	0x01
 
@@ -616,6 +618,7 @@
 	case IT8718_ID:
 	case IT8720_ID:
 	case IT8721_ID:
+	case IT8728_ID:
 		max_units = 65535;
 		try_gameport = 0;
 		break;
diff --git a/drivers/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c
deleted file mode 100644
index 3f047a5..0000000
--- a/drivers/watchdog/ixp2000_wdt.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * drivers/char/watchdog/ixp2000_wdt.c
- *
- * Watchdog driver for Intel IXP2000 network processors
- *
- * Adapted from the IXP4xx watchdog driver by Lennert Buytenhek.
- * The original version carries these notices:
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2004 (c) MontaVista, Software, Inc.
- * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
- *
- * 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.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/uaccess.h>
-#include <mach/hardware.h>
-
-static bool nowayout = WATCHDOG_NOWAYOUT;
-static unsigned int heartbeat = 60;	/* (secs) Default is 1 minute */
-static unsigned long wdt_status;
-static DEFINE_SPINLOCK(wdt_lock);
-
-#define	WDT_IN_USE		0
-#define	WDT_OK_TO_CLOSE		1
-
-static unsigned long wdt_tick_rate;
-
-static void wdt_enable(void)
-{
-	spin_lock(&wdt_lock);
-	ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
-	ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
-	ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
-	ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
-	spin_unlock(&wdt_lock);
-}
-
-static void wdt_disable(void)
-{
-	spin_lock(&wdt_lock);
-	ixp2000_reg_write(IXP2000_T4_CTL, 0);
-	spin_unlock(&wdt_lock);
-}
-
-static void wdt_keepalive(void)
-{
-	spin_lock(&wdt_lock);
-	ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
-	spin_unlock(&wdt_lock);
-}
-
-static int ixp2000_wdt_open(struct inode *inode, struct file *file)
-{
-	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-		return -EBUSY;
-
-	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-	wdt_enable();
-
-	return nonseekable_open(inode, file);
-}
-
-static ssize_t ixp2000_wdt_write(struct file *file, const char *data,
-						size_t len, loff_t *ppos)
-{
-	if (len) {
-		if (!nowayout) {
-			size_t i;
-
-			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-			for (i = 0; i != len; i++) {
-				char c;
-
-				if (get_user(c, data + i))
-					return -EFAULT;
-				if (c == 'V')
-					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-			}
-		}
-		wdt_keepalive();
-	}
-
-	return len;
-}
-
-
-static const struct watchdog_info ident = {
-	.options	= WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
-				WDIOF_KEEPALIVEPING,
-	.identity	= "IXP2000 Watchdog",
-};
-
-static long ixp2000_wdt_ioctl(struct file *file, unsigned int cmd,
-							unsigned long arg)
-{
-	int ret = -ENOTTY;
-	int time;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		ret = copy_to_user((struct watchdog_info *)arg, &ident,
-				   sizeof(ident)) ? -EFAULT : 0;
-		break;
-
-	case WDIOC_GETSTATUS:
-		ret = put_user(0, (int *)arg);
-		break;
-
-	case WDIOC_GETBOOTSTATUS:
-		ret = put_user(0, (int *)arg);
-		break;
-
-	case WDIOC_KEEPALIVE:
-		wdt_enable();
-		ret = 0;
-		break;
-
-	case WDIOC_SETTIMEOUT:
-		ret = get_user(time, (int *)arg);
-		if (ret)
-			break;
-
-		if (time <= 0 || time > 60) {
-			ret = -EINVAL;
-			break;
-		}
-
-		heartbeat = time;
-		wdt_keepalive();
-		/* Fall through */
-
-	case WDIOC_GETTIMEOUT:
-		ret = put_user(heartbeat, (int *)arg);
-		break;
-	}
-
-	return ret;
-}
-
-static int ixp2000_wdt_release(struct inode *inode, struct file *file)
-{
-	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-		wdt_disable();
-	else
-		pr_crit("Device closed unexpectedly - timer will not stop\n");
-	clear_bit(WDT_IN_USE, &wdt_status);
-	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-	return 0;
-}
-
-
-static const struct file_operations ixp2000_wdt_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.write		= ixp2000_wdt_write,
-	.unlocked_ioctl	= ixp2000_wdt_ioctl,
-	.open		= ixp2000_wdt_open,
-	.release	= ixp2000_wdt_release,
-};
-
-static struct miscdevice ixp2000_wdt_miscdev = {
-	.minor		= WATCHDOG_MINOR,
-	.name		= "watchdog",
-	.fops		= &ixp2000_wdt_fops,
-};
-
-static int __init ixp2000_wdt_init(void)
-{
-	if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
-		pr_info("Unable to use IXP2000 watchdog due to IXP2800 erratum #25\n");
-		return -EIO;
-	}
-	wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
-	return misc_register(&ixp2000_wdt_miscdev);
-}
-
-static void __exit ixp2000_wdt_exit(void)
-{
-	misc_deregister(&ixp2000_wdt_miscdev);
-}
-
-module_init(ixp2000_wdt_init);
-module_exit(ixp2000_wdt_exit);
-
-MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
-
-module_param(nowayout, bool, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
-
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index c891399..ee6900d 100644
--- a/drivers/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
@@ -707,6 +707,7 @@
 		goto err_out_disable_device;
 	}
 
+	spin_lock_init(&pcipcwd_private.io_lock);
 	pcipcwd_private.pdev = pdev;
 	pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
 
@@ -814,22 +815,7 @@
 	.remove		= __devexit_p(pcipcwd_card_exit),
 };
 
-static int __init pcipcwd_init_module(void)
-{
-	spin_lock_init(&pcipcwd_private.io_lock);
-
-	return pci_register_driver(&pcipcwd_driver);
-}
-
-static void __exit pcipcwd_cleanup_module(void)
-{
-	pci_unregister_driver(&pcipcwd_driver);
-
-	pr_info("Watchdog Module Unloaded\n");
-}
-
-module_init(pcipcwd_init_module);
-module_exit(pcipcwd_cleanup_module);
+module_pci_driver(pcipcwd_driver);
 
 MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
 MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 6b8432f..87722e1 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -32,6 +32,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/of.h>
 #include <mach/hardware.h>
 
 /* WatchDog Timer - Chapter 23 Page 207 */
@@ -201,10 +202,19 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id pnx4008_wdt_match[] = {
+	{ .compatible = "nxp,pnx4008-wdt" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pnx4008_wdt_match);
+#endif
+
 static struct platform_driver platform_wdt_driver = {
 	.driver = {
 		.name = "pnx4008-watchdog",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(pnx4008_wdt_match),
 	},
 	.probe = pnx4008_wdt_probe,
 	.remove = __devexit_p(pnx4008_wdt_remove),
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 04e5a6d..200ece5 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -40,6 +40,7 @@
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/of.h>
 
 #include <mach/map.h>
 
@@ -201,7 +202,7 @@
 	writel(count, wdt_base + S3C2410_WTDAT);
 	writel(wtcon, wdt_base + S3C2410_WTCON);
 
-	wdd->timeout = timeout;
+	wdd->timeout = (count * divisor) / freq;
 
 	return 0;
 }
@@ -503,8 +504,6 @@
 	{},
 };
 MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
-#else
-#define s3c2410_wdt_match NULL
 #endif
 
 static struct platform_driver s3c2410wdt_driver = {
@@ -516,7 +515,7 @@
 	.driver		= {
 		.owner	= THIS_MODULE,
 		.name	= "s3c2410-wdt",
-		.of_match_table	= s3c2410_wdt_match,
+		.of_match_table	= of_match_ptr(s3c2410_wdt_match),
 	},
 };
 
diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c
index bd86f32..f847700 100644
--- a/drivers/watchdog/sch311x_wdt.c
+++ b/drivers/watchdog/sch311x_wdt.c
@@ -41,7 +41,6 @@
 #define DRV_NAME	"sch311x_wdt"
 
 /* Runtime registers */
-#define RESGEN			0x1d
 #define GP60			0x47
 #define WDT_TIME_OUT		0x65
 #define WDT_VAL			0x66
@@ -69,10 +68,6 @@
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
-static unsigned short therm_trip;
-module_param(therm_trip, ushort, 0);
-MODULE_PARM_DESC(therm_trip, "Should a ThermTrip trigger the reset generator");
-
 #define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
 static int timeout = WATCHDOG_TIMEOUT;	/* in seconds */
 module_param(timeout, int, 0);
@@ -358,26 +353,16 @@
 static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	unsigned char val;
 	int err;
 
 	spin_lock_init(&sch311x_wdt_data.io_lock);
 
-	if (!request_region(sch311x_wdt_data.runtime_reg + RESGEN, 1,
-								DRV_NAME)) {
-		dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
-			sch311x_wdt_data.runtime_reg + RESGEN,
-			sch311x_wdt_data.runtime_reg + RESGEN);
-		err = -EBUSY;
-		goto exit;
-	}
-
 	if (!request_region(sch311x_wdt_data.runtime_reg + GP60, 1, DRV_NAME)) {
 		dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
 			sch311x_wdt_data.runtime_reg + GP60,
 			sch311x_wdt_data.runtime_reg + GP60);
 		err = -EBUSY;
-		goto exit_release_region;
+		goto exit;
 	}
 
 	if (!request_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4,
@@ -386,7 +371,7 @@
 			sch311x_wdt_data.runtime_reg + WDT_TIME_OUT,
 			sch311x_wdt_data.runtime_reg + WDT_CTRL);
 		err = -EBUSY;
-		goto exit_release_region2;
+		goto exit_release_region;
 	}
 
 	/* Make sure that the watchdog is not running */
@@ -414,24 +399,13 @@
 	/* Get status at boot */
 	sch311x_wdt_get_status(&sch311x_wdt_data.boot_status);
 
-	/* enable watchdog */
-	/* -- Reset Generator --
-	 * Bit 0   Enable Watchdog Timer Generation: 0* = Enabled, 1 = Disabled
-	 * Bit 1   Thermtrip Source Select: O* = No Source, 1 = Source
-	 * Bit 2   WDT2_CTL: WDT input bit
-	 * Bit 3-7 Reserved
-	 */
-	outb(0, sch311x_wdt_data.runtime_reg + RESGEN);
-	val = therm_trip ? 0x06 : 0x04;
-	outb(val, sch311x_wdt_data.runtime_reg + RESGEN);
-
 	sch311x_wdt_miscdev.parent = dev;
 
 	err = misc_register(&sch311x_wdt_miscdev);
 	if (err != 0) {
 		dev_err(dev, "cannot register miscdev on minor=%d (err=%d)\n",
 							WATCHDOG_MINOR, err);
-		goto exit_release_region3;
+		goto exit_release_region2;
 	}
 
 	dev_info(dev,
@@ -440,12 +414,10 @@
 
 	return 0;
 
-exit_release_region3:
-	release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
 exit_release_region2:
-	release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
+	release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
 exit_release_region:
-	release_region(sch311x_wdt_data.runtime_reg + RESGEN, 1);
+	release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
 	sch311x_wdt_data.runtime_reg = 0;
 exit:
 	return err;
@@ -461,7 +433,6 @@
 	misc_deregister(&sch311x_wdt_miscdev);
 	release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
 	release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
-	release_region(sch311x_wdt_data.runtime_reg + RESGEN, 1);
 	sch311x_wdt_data.runtime_reg = 0;
 	return 0;
 }
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index 93958a7..e5b59be 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -3,7 +3,7 @@
  *
  * Watchdog driver for integrated watchdog in the SuperH processors.
  *
- * Copyright (C) 2001 - 2010  Paul Mundt <lethal@linux-sh.org>
+ * Copyright (C) 2001 - 2012  Paul Mundt <lethal@linux-sh.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
@@ -25,16 +25,15 @@
 #include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/spinlock.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/ioport.h>
+#include <linux/pm_runtime.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/io.h>
-#include <linux/uaccess.h>
+#include <linux/clk.h>
 #include <asm/watchdog.h>
 
 #define DRV_NAME "sh-wdt"
@@ -69,10 +68,6 @@
 static int clock_division_ratio = WTCSR_CKS_4096;
 #define next_ping_period(cks)	(jiffies + msecs_to_jiffies(cks - 4))
 
-static const struct watchdog_info sh_wdt_info;
-static struct platform_device *sh_wdt_dev;
-static DEFINE_SPINLOCK(shwdt_lock);
-
 #define WATCHDOG_HEARTBEAT 30			/* 30 sec default heartbeat */
 static int heartbeat = WATCHDOG_HEARTBEAT;	/* in seconds */
 static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -81,19 +76,22 @@
 struct sh_wdt {
 	void __iomem		*base;
 	struct device		*dev;
+	struct clk		*clk;
+	spinlock_t		lock;
 
 	struct timer_list	timer;
-
-	unsigned long		enabled;
-	char			expect_close;
 };
 
-static void sh_wdt_start(struct sh_wdt *wdt)
+static int sh_wdt_start(struct watchdog_device *wdt_dev)
 {
+	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 	unsigned long flags;
 	u8 csr;
 
-	spin_lock_irqsave(&shwdt_lock, flags);
+	pm_runtime_get_sync(wdt->dev);
+	clk_enable(wdt->clk);
+
+	spin_lock_irqsave(&wdt->lock, flags);
 
 	next_heartbeat = jiffies + (heartbeat * HZ);
 	mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
@@ -122,15 +120,18 @@
 	csr &= ~RSTCSR_RSTS;
 	sh_wdt_write_rstcsr(csr);
 #endif
-	spin_unlock_irqrestore(&shwdt_lock, flags);
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	return 0;
 }
 
-static void sh_wdt_stop(struct sh_wdt *wdt)
+static int sh_wdt_stop(struct watchdog_device *wdt_dev)
 {
+	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 	unsigned long flags;
 	u8 csr;
 
-	spin_lock_irqsave(&shwdt_lock, flags);
+	spin_lock_irqsave(&wdt->lock, flags);
 
 	del_timer(&wdt->timer);
 
@@ -138,28 +139,39 @@
 	csr &= ~WTCSR_TME;
 	sh_wdt_write_csr(csr);
 
-	spin_unlock_irqrestore(&shwdt_lock, flags);
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	clk_disable(wdt->clk);
+	pm_runtime_put_sync(wdt->dev);
+
+	return 0;
 }
 
-static inline void sh_wdt_keepalive(struct sh_wdt *wdt)
+static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
 {
+	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 	unsigned long flags;
 
-	spin_lock_irqsave(&shwdt_lock, flags);
+	spin_lock_irqsave(&wdt->lock, flags);
 	next_heartbeat = jiffies + (heartbeat * HZ);
-	spin_unlock_irqrestore(&shwdt_lock, flags);
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	return 0;
 }
 
-static int sh_wdt_set_heartbeat(int t)
+static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
 {
+	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 	unsigned long flags;
 
 	if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
 		return -EINVAL;
 
-	spin_lock_irqsave(&shwdt_lock, flags);
+	spin_lock_irqsave(&wdt->lock, flags);
 	heartbeat = t;
-	spin_unlock_irqrestore(&shwdt_lock, flags);
+	wdt_dev->timeout = t;
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
 	return 0;
 }
 
@@ -168,7 +180,7 @@
 	struct sh_wdt *wdt = (struct sh_wdt *)data;
 	unsigned long flags;
 
-	spin_lock_irqsave(&shwdt_lock, flags);
+	spin_lock_irqsave(&wdt->lock, flags);
 	if (time_before(jiffies, next_heartbeat)) {
 		u8 csr;
 
@@ -182,137 +194,9 @@
 	} else
 		dev_warn(wdt->dev, "Heartbeat lost! Will not ping "
 		         "the watchdog\n");
-	spin_unlock_irqrestore(&shwdt_lock, flags);
+	spin_unlock_irqrestore(&wdt->lock, flags);
 }
 
-static int sh_wdt_open(struct inode *inode, struct file *file)
-{
-	struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
-
-	if (test_and_set_bit(0, &wdt->enabled))
-		return -EBUSY;
-	if (nowayout)
-		__module_get(THIS_MODULE);
-
-	file->private_data = wdt;
-
-	sh_wdt_start(wdt);
-
-	return nonseekable_open(inode, file);
-}
-
-static int sh_wdt_close(struct inode *inode, struct file *file)
-{
-	struct sh_wdt *wdt = file->private_data;
-
-	if (wdt->expect_close == 42) {
-		sh_wdt_stop(wdt);
-	} else {
-		dev_crit(wdt->dev, "Unexpected close, not "
-		         "stopping watchdog!\n");
-		sh_wdt_keepalive(wdt);
-	}
-
-	clear_bit(0, &wdt->enabled);
-	wdt->expect_close = 0;
-
-	return 0;
-}
-
-static ssize_t sh_wdt_write(struct file *file, const char *buf,
-			    size_t count, loff_t *ppos)
-{
-	struct sh_wdt *wdt = file->private_data;
-
-	if (count) {
-		if (!nowayout) {
-			size_t i;
-
-			wdt->expect_close = 0;
-
-			for (i = 0; i != count; i++) {
-				char c;
-				if (get_user(c, buf + i))
-					return -EFAULT;
-				if (c == 'V')
-					wdt->expect_close = 42;
-			}
-		}
-		sh_wdt_keepalive(wdt);
-	}
-
-	return count;
-}
-
-static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
-							unsigned long arg)
-{
-	struct sh_wdt *wdt = file->private_data;
-	int new_heartbeat;
-	int options, retval = -EINVAL;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		return copy_to_user((struct watchdog_info *)arg,
-			  &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
-	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
-		return put_user(0, (int *)arg);
-	case WDIOC_SETOPTIONS:
-		if (get_user(options, (int *)arg))
-			return -EFAULT;
-
-		if (options & WDIOS_DISABLECARD) {
-			sh_wdt_stop(wdt);
-			retval = 0;
-		}
-
-		if (options & WDIOS_ENABLECARD) {
-			sh_wdt_start(wdt);
-			retval = 0;
-		}
-
-		return retval;
-	case WDIOC_KEEPALIVE:
-		sh_wdt_keepalive(wdt);
-		return 0;
-	case WDIOC_SETTIMEOUT:
-		if (get_user(new_heartbeat, (int *)arg))
-			return -EFAULT;
-
-		if (sh_wdt_set_heartbeat(new_heartbeat))
-			return -EINVAL;
-
-		sh_wdt_keepalive(wdt);
-		/* Fall */
-	case WDIOC_GETTIMEOUT:
-		return put_user(heartbeat, (int *)arg);
-	default:
-		return -ENOTTY;
-	}
-	return 0;
-}
-
-static int sh_wdt_notify_sys(struct notifier_block *this,
-			     unsigned long code, void *unused)
-{
-	struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
-
-	if (code == SYS_DOWN || code == SYS_HALT)
-		sh_wdt_stop(wdt);
-
-	return NOTIFY_DONE;
-}
-
-static const struct file_operations sh_wdt_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.write		= sh_wdt_write,
-	.unlocked_ioctl	= sh_wdt_ioctl,
-	.open		= sh_wdt_open,
-	.release	= sh_wdt_close,
-};
-
 static const struct watchdog_info sh_wdt_info = {
 	.options		= WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
 				  WDIOF_MAGICCLOSE,
@@ -320,14 +204,17 @@
 	.identity		= "SH WDT",
 };
 
-static struct notifier_block sh_wdt_notifier = {
-	.notifier_call		= sh_wdt_notify_sys,
+static const struct watchdog_ops sh_wdt_ops = {
+	.owner		= THIS_MODULE,
+	.start		= sh_wdt_start,
+	.stop		= sh_wdt_stop,
+	.ping		= sh_wdt_keepalive,
+	.set_timeout	= sh_wdt_set_heartbeat,
 };
 
-static struct miscdevice sh_wdt_miscdev = {
-	.minor		= WATCHDOG_MINOR,
-	.name		= "watchdog",
-	.fops		= &sh_wdt_fops,
+static struct watchdog_device sh_wdt_dev = {
+	.info	= &sh_wdt_info,
+	.ops	= &sh_wdt_ops,
 };
 
 static int __devinit sh_wdt_probe(struct platform_device *pdev)
@@ -347,39 +234,49 @@
 	if (unlikely(!res))
 		return -EINVAL;
 
-	if (!devm_request_mem_region(&pdev->dev, res->start,
-				     resource_size(res), DRV_NAME))
-		return -EBUSY;
-
 	wdt = devm_kzalloc(&pdev->dev, sizeof(struct sh_wdt), GFP_KERNEL);
-	if (unlikely(!wdt)) {
-		rc = -ENOMEM;
-		goto out_release;
-	}
+	if (unlikely(!wdt))
+		return -ENOMEM;
 
 	wdt->dev = &pdev->dev;
 
-	wdt->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	wdt->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(wdt->clk)) {
+		/*
+		 * Clock framework support is optional, continue on
+		 * anyways if we don't find a matching clock.
+		 */
+		wdt->clk = NULL;
+	}
+
+	wdt->base = devm_request_and_ioremap(wdt->dev, res);
 	if (unlikely(!wdt->base)) {
-		rc = -ENXIO;
-		goto out_err;
+		rc = -EADDRNOTAVAIL;
+		goto err;
 	}
 
-	rc = register_reboot_notifier(&sh_wdt_notifier);
+	watchdog_set_nowayout(&sh_wdt_dev, nowayout);
+	watchdog_set_drvdata(&sh_wdt_dev, wdt);
+
+	spin_lock_init(&wdt->lock);
+
+	rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
 	if (unlikely(rc)) {
-		dev_err(&pdev->dev,
-			"Can't register reboot notifier (err=%d)\n", rc);
-		goto out_unmap;
+		/* Default timeout if invalid */
+		sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
+
+		dev_warn(&pdev->dev,
+			 "heartbeat value must be 1<=x<=3600, using %d\n",
+			 sh_wdt_dev.timeout);
 	}
 
-	sh_wdt_miscdev.parent = wdt->dev;
+	dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
+		 sh_wdt_dev.timeout, nowayout);
 
-	rc = misc_register(&sh_wdt_miscdev);
+	rc = watchdog_register_device(&sh_wdt_dev);
 	if (unlikely(rc)) {
-		dev_err(&pdev->dev,
-			"Can't register miscdev on minor=%d (err=%d)\n",
-						sh_wdt_miscdev.minor, rc);
-		goto out_unreg;
+		dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
+		goto err;
 	}
 
 	init_timer(&wdt->timer);
@@ -388,20 +285,15 @@
 	wdt->timer.expires	= next_ping_period(clock_division_ratio);
 
 	platform_set_drvdata(pdev, wdt);
-	sh_wdt_dev = pdev;
 
 	dev_info(&pdev->dev, "initialized.\n");
 
+	pm_runtime_enable(&pdev->dev);
+
 	return 0;
 
-out_unreg:
-	unregister_reboot_notifier(&sh_wdt_notifier);
-out_unmap:
-	devm_iounmap(&pdev->dev, wdt->base);
-out_err:
-	devm_kfree(&pdev->dev, wdt);
-out_release:
-	devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
+err:
+	clk_put(wdt->clk);
 
 	return rc;
 }
@@ -409,36 +301,35 @@
 static int __devexit sh_wdt_remove(struct platform_device *pdev)
 {
 	struct sh_wdt *wdt = platform_get_drvdata(pdev);
-	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	platform_set_drvdata(pdev, NULL);
 
-	misc_deregister(&sh_wdt_miscdev);
+	watchdog_unregister_device(&sh_wdt_dev);
 
-	sh_wdt_dev = NULL;
-
-	unregister_reboot_notifier(&sh_wdt_notifier);
-	devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
-	devm_iounmap(&pdev->dev, wdt->base);
-	devm_kfree(&pdev->dev, wdt);
+	pm_runtime_disable(&pdev->dev);
+	clk_put(wdt->clk);
 
 	return 0;
 }
 
+static void sh_wdt_shutdown(struct platform_device *pdev)
+{
+	sh_wdt_stop(&sh_wdt_dev);
+}
+
 static struct platform_driver sh_wdt_driver = {
 	.driver		= {
 		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
 	},
 
-	.probe	= sh_wdt_probe,
-	.remove	= __devexit_p(sh_wdt_remove),
+	.probe		= sh_wdt_probe,
+	.remove		= __devexit_p(sh_wdt_remove),
+	.shutdown	= sh_wdt_shutdown,
 };
 
 static int __init sh_wdt_init(void)
 {
-	int rc;
-
 	if (unlikely(clock_division_ratio < 0x5 ||
 		     clock_division_ratio > 0x7)) {
 		clock_division_ratio = WTCSR_CKS_4096;
@@ -447,17 +338,6 @@
 			clock_division_ratio);
 	}
 
-	rc = sh_wdt_set_heartbeat(heartbeat);
-	if (unlikely(rc)) {
-		heartbeat = WATCHDOG_HEARTBEAT;
-
-		pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
-			heartbeat);
-	}
-
-	pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
-		heartbeat, nowayout);
-
 	return platform_driver_register(&sh_wdt_driver);
 }
 
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 59108e4..ae5e82c 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -313,7 +313,7 @@
 	tcobase_phys = val;
 
 	tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
-	if (tcobase == 0) {
+	if (!tcobase) {
 		pr_err("failed to get tcobase address\n");
 		goto unreg_mem_region;
 	}
diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c
index 465e082..5603e31 100644
--- a/drivers/watchdog/via_wdt.c
+++ b/drivers/watchdog/via_wdt.c
@@ -202,6 +202,9 @@
 		goto err_out_release;
 	}
 
+	if (timeout < 1 || timeout > WDT_TIMEOUT_MAX)
+		timeout = WDT_TIMEOUT;
+
 	wdt_dev.timeout = timeout;
 	watchdog_set_nowayout(&wdt_dev, nowayout);
 	if (readl(wdt_mem) & VIA_WDT_FIRED)
@@ -250,20 +253,7 @@
 	.remove		= __devexit_p(wdt_remove),
 };
 
-static int __init wdt_init(void)
-{
-	if (timeout < 1 || timeout > WDT_TIMEOUT_MAX)
-		timeout = WDT_TIMEOUT;
-	return pci_register_driver(&wdt_driver);
-}
-
-static void __exit wdt_exit(void)
-{
-	pci_unregister_driver(&wdt_driver);
-}
-
-module_init(wdt_init);
-module_exit(wdt_exit);
+module_pci_driver(wdt_driver);
 
 MODULE_AUTHOR("Marc Vertes");
 MODULE_DESCRIPTION("Driver for watchdog timer on VIA chipset");
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index 1c888c7..e32654e 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -739,39 +739,7 @@
 	.remove		= __devexit_p(wdtpci_remove_one),
 };
 
-
-/**
- *	wdtpci_cleanup:
- *
- *	Unload the watchdog. You cannot do this with any file handles open.
- *	If your watchdog is set to continue ticking on close and you unload
- *	it, well it keeps ticking. We won't get the interrupt but the board
- *	will not touch PC memory so all is fine. You just have to load a new
- *	module in xx seconds or reboot.
- */
-
-static void __exit wdtpci_cleanup(void)
-{
-	pci_unregister_driver(&wdtpci_driver);
-}
-
-
-/**
- *	wdtpci_init:
- *
- *	Set up the WDT watchdog board. All we have to do is grab the
- *	resources we require and bitch if anyone beat us to them.
- *	The open() function will actually kick the board off.
- */
-
-static int __init wdtpci_init(void)
-{
-	return pci_register_driver(&wdtpci_driver);
-}
-
-
-module_init(wdtpci_init);
-module_exit(wdtpci_cleanup);
+module_pci_driver(wdtpci_driver);
 
 MODULE_AUTHOR("JP Nollmann, Alan Cox");
 MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index b1815c5..87d66d2 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -247,8 +247,9 @@
 		reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
 
 		if (pdata->update_gpio) {
-			ret = gpio_request(pdata->update_gpio,
-					   "Watchdog update");
+			ret = gpio_request_one(pdata->update_gpio,
+					       GPIOF_DIR_OUT | GPIOF_INIT_LOW,
+					       "Watchdog update");
 			if (ret < 0) {
 				dev_err(wm831x->dev,
 					"Failed to request update GPIO: %d\n",
@@ -256,14 +257,6 @@
 				goto err;
 			}
 
-			ret = gpio_direction_output(pdata->update_gpio, 0);
-			if (ret != 0) {
-				dev_err(wm831x->dev,
-					"gpio_direction_output returned: %d\n",
-					ret);
-				goto err_gpio;
-			}
-
 			driver_data->update_gpio = pdata->update_gpio;
 
 			/* Make sure the watchdog takes hardware updates */
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index ea20c51..8d2501e 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -71,7 +71,7 @@
 	tristate "Xen /dev/xen/evtchn device"
 	default y
 	help
-	  The evtchn driver allows a userspace process to triger event
+	  The evtchn driver allows a userspace process to trigger event
 	  channels and to receive notification of an event channel
 	  firing.
 	  If in doubt, say yes.
diff --git a/fs/attr.c b/fs/attr.c
index 73f69a6..584620e 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -47,14 +47,14 @@
 
 	/* Make sure a caller can chown. */
 	if ((ia_valid & ATTR_UID) &&
-	    (current_fsuid() != inode->i_uid ||
-	     attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
+	    (!uid_eq(current_fsuid(), inode->i_uid) ||
+	     !uid_eq(attr->ia_uid, inode->i_uid)) && !capable(CAP_CHOWN))
 		return -EPERM;
 
 	/* Make sure caller can chgrp. */
 	if ((ia_valid & ATTR_GID) &&
-	    (current_fsuid() != inode->i_uid ||
-	    (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
+	    (!uid_eq(current_fsuid(), inode->i_uid) ||
+	    (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
 	    !capable(CAP_CHOWN))
 		return -EPERM;
 
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 16f7354..e658dd1 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -226,10 +226,10 @@
 	NEW_AUX_ENT(AT_BASE, interp_load_addr);
 	NEW_AUX_ENT(AT_FLAGS, 0);
 	NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
-	NEW_AUX_ENT(AT_UID, cred->uid);
-	NEW_AUX_ENT(AT_EUID, cred->euid);
-	NEW_AUX_ENT(AT_GID, cred->gid);
-	NEW_AUX_ENT(AT_EGID, cred->egid);
+	NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid));
+	NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid));
+	NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid));
+	NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid));
  	NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
 	NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes);
 	NEW_AUX_ENT(AT_EXECFN, bprm->exec);
@@ -1356,8 +1356,8 @@
 	psinfo->pr_flag = p->flags;
 	rcu_read_lock();
 	cred = __task_cred(p);
-	SET_UID(psinfo->pr_uid, cred->uid);
-	SET_GID(psinfo->pr_gid, cred->gid);
+	SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid));
+	SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));
 	rcu_read_unlock();
 	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
 	
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index d390a0f..3d77cf8 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -627,10 +627,10 @@
 	NEW_AUX_ENT(AT_BASE,	interp_params->elfhdr_addr);
 	NEW_AUX_ENT(AT_FLAGS,	0);
 	NEW_AUX_ENT(AT_ENTRY,	exec_params->entry_addr);
-	NEW_AUX_ENT(AT_UID,	(elf_addr_t) cred->uid);
-	NEW_AUX_ENT(AT_EUID,	(elf_addr_t) cred->euid);
-	NEW_AUX_ENT(AT_GID,	(elf_addr_t) cred->gid);
-	NEW_AUX_ENT(AT_EGID,	(elf_addr_t) cred->egid);
+	NEW_AUX_ENT(AT_UID,	(elf_addr_t) from_kuid_munged(cred->user_ns, cred->uid));
+	NEW_AUX_ENT(AT_EUID,	(elf_addr_t) from_kuid_munged(cred->user_ns, cred->euid));
+	NEW_AUX_ENT(AT_GID,	(elf_addr_t) from_kgid_munged(cred->user_ns, cred->gid));
+	NEW_AUX_ENT(AT_EGID,	(elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid));
 	NEW_AUX_ENT(AT_SECURE,	security_bprm_secureexec(bprm));
 	NEW_AUX_ENT(AT_EXECFN,	bprm->exec);
 
@@ -1421,8 +1421,8 @@
 	psinfo->pr_flag = p->flags;
 	rcu_read_lock();
 	cred = __task_cred(p);
-	SET_UID(psinfo->pr_uid, cred->uid);
-	SET_GID(psinfo->pr_gid, cred->gid);
+	SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid));
+	SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));
 	rcu_read_unlock();
 	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
 
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index a7ffc88..e1fe74a 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2753,7 +2753,7 @@
 	 * one reference for us, and we leave it for the
 	 * caller
 	 */
-	device->flush_bio = NULL;;
+	device->flush_bio = NULL;
 	bio = bio_alloc(GFP_NOFS, 0);
 	if (!bio)
 		return -ENOMEM;
diff --git a/fs/compat.c b/fs/compat.c
index f2944ac..0781e61 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -144,8 +144,8 @@
 	tmp.st_nlink = stat->nlink;
 	if (tmp.st_nlink != stat->nlink)
 		return -EOVERFLOW;
-	SET_UID(tmp.st_uid, stat->uid);
-	SET_GID(tmp.st_gid, stat->gid);
+	SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
+	SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
 	tmp.st_rdev = old_encode_dev(stat->rdev);
 	if ((u64) stat->size > MAX_NON_LFS)
 		return -EOVERFLOW;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 10f5e0b..979c1e3 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -98,8 +98,8 @@
 struct pts_mount_opts {
 	int setuid;
 	int setgid;
-	uid_t   uid;
-	gid_t   gid;
+	kuid_t   uid;
+	kgid_t   gid;
 	umode_t mode;
 	umode_t ptmxmode;
 	int newinstance;
@@ -158,11 +158,13 @@
 static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
 {
 	char *p;
+	kuid_t uid;
+	kgid_t gid;
 
 	opts->setuid  = 0;
 	opts->setgid  = 0;
-	opts->uid     = 0;
-	opts->gid     = 0;
+	opts->uid     = GLOBAL_ROOT_UID;
+	opts->gid     = GLOBAL_ROOT_GID;
 	opts->mode    = DEVPTS_DEFAULT_MODE;
 	opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
 	opts->max     = NR_UNIX98_PTY_MAX;
@@ -184,13 +186,19 @@
 		case Opt_uid:
 			if (match_int(&args[0], &option))
 				return -EINVAL;
-			opts->uid = option;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid))
+				return -EINVAL;
+			opts->uid = uid;
 			opts->setuid = 1;
 			break;
 		case Opt_gid:
 			if (match_int(&args[0], &option))
 				return -EINVAL;
-			opts->gid = option;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid))
+				return -EINVAL;
+			opts->gid = gid;
 			opts->setgid = 1;
 			break;
 		case Opt_mode:
@@ -315,9 +323,9 @@
 	struct pts_mount_opts *opts = &fsi->mount_opts;
 
 	if (opts->setuid)
-		seq_printf(seq, ",uid=%u", opts->uid);
+		seq_printf(seq, ",uid=%u", from_kuid_munged(&init_user_ns, opts->uid));
 	if (opts->setgid)
-		seq_printf(seq, ",gid=%u", opts->gid);
+		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, opts->gid));
 	seq_printf(seq, ",mode=%03o", opts->mode);
 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
 	seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
index 90e5997..63dc19c 100644
--- a/fs/dlm/ast.c
+++ b/fs/dlm/ast.c
@@ -310,6 +310,7 @@
 	}
 	mutex_unlock(&ls->ls_cb_mutex);
 
-	log_debug(ls, "dlm_callback_resume %d", count);
+	if (count)
+		log_debug(ls, "dlm_callback_resume %d", count);
 }
 
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 3a564d1..bc342f7 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -38,6 +38,7 @@
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
 #include <linux/idr.h>
+#include <linux/ratelimit.h>
 #include <asm/uaccess.h>
 
 #include <linux/dlm.h>
@@ -74,6 +75,13 @@
 		       (ls)->ls_name , ##args); \
 } while (0)
 
+#define log_limit(ls, fmt, args...) \
+do { \
+	if (dlm_config.ci_log_debug) \
+		printk_ratelimited(KERN_DEBUG "dlm: %s: " fmt "\n", \
+			(ls)->ls_name , ##args); \
+} while (0)
+
 #define DLM_ASSERT(x, do) \
 { \
   if (!(x)) \
@@ -263,6 +271,8 @@
 	ktime_t			lkb_last_cast_time;	/* for debugging */
 	ktime_t			lkb_last_bast_time;	/* for debugging */
 
+	uint64_t		lkb_recover_seq; /* from ls_recover_seq */
+
 	char			*lkb_lvbptr;
 	struct dlm_lksb		*lkb_lksb;      /* caller's status block */
 	void			(*lkb_astfn) (void *astparam);
@@ -317,7 +327,7 @@
 	RSB_NEW_MASTER,
 	RSB_NEW_MASTER2,
 	RSB_RECOVER_CONVERT,
-	RSB_LOCKS_PURGED,
+	RSB_RECOVER_GRANT,
 };
 
 static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag)
@@ -563,6 +573,7 @@
 	struct mutex		ls_requestqueue_mutex;
 	struct dlm_rcom		*ls_recover_buf;
 	int			ls_recover_nodeid; /* for debugging */
+	unsigned int		ls_recover_locks_in; /* for log info */
 	uint64_t		ls_rcom_seq;
 	spinlock_t		ls_rcom_spin;
 	struct list_head	ls_recover_list;
@@ -589,6 +600,7 @@
 #define LSFL_UEVENT_WAIT	5
 #define LSFL_TIMEWARN		6
 #define LSFL_CB_DELAY		7
+#define LSFL_NODIR		8
 
 /* much of this is just saving user space pointers associated with the
    lock that we pass back to the user lib with an ast */
@@ -636,7 +648,7 @@
 
 static inline int dlm_no_directory(struct dlm_ls *ls)
 {
-	return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0;
+	return test_bit(LSFL_NODIR, &ls->ls_flags);
 }
 
 int dlm_netlink_init(void);
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 4c58d4a..bdafb65 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -160,11 +160,12 @@
 
 void dlm_print_lkb(struct dlm_lkb *lkb)
 {
-	printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n"
-	       "     status %d rqmode %d grmode %d wait_type %d\n",
+	printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x "
+	       "sts %d rq %d gr %d wait_type %d wait_nodeid %d seq %llu\n",
 	       lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags,
 	       lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode,
-	       lkb->lkb_grmode, lkb->lkb_wait_type);
+	       lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_wait_nodeid,
+	       (unsigned long long)lkb->lkb_recover_seq);
 }
 
 static void dlm_print_rsb(struct dlm_rsb *r)
@@ -251,8 +252,6 @@
 
 static inline int is_master_copy(struct dlm_lkb *lkb)
 {
-	if (lkb->lkb_flags & DLM_IFL_MSTCPY)
-		DLM_ASSERT(lkb->lkb_nodeid, dlm_print_lkb(lkb););
 	return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? 1 : 0;
 }
 
@@ -479,6 +478,9 @@
 		kref_get(&r->res_ref);
 		goto out;
 	}
+	if (error == -ENOTBLK)
+		goto out;
+
 	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
 	if (error)
 		goto out;
@@ -586,6 +588,23 @@
 	return error;
 }
 
+static void dlm_dump_rsb_hash(struct dlm_ls *ls, uint32_t hash)
+{
+	struct rb_node *n;
+	struct dlm_rsb *r;
+	int i;
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		spin_lock(&ls->ls_rsbtbl[i].lock);
+		for (n = rb_first(&ls->ls_rsbtbl[i].keep); n; n = rb_next(n)) {
+			r = rb_entry(n, struct dlm_rsb, res_hashnode);
+			if (r->res_hash == hash)
+				dlm_dump_rsb(r);
+		}
+		spin_unlock(&ls->ls_rsbtbl[i].lock);
+	}
+}
+
 /* This is only called to add a reference when the code already holds
    a valid reference to the rsb, so there's no need for locking. */
 
@@ -1064,8 +1083,9 @@
 		goto out_del;
 	}
 
-	log_error(ls, "remwait error %x reply %d flags %x no wait_type",
-		  lkb->lkb_id, mstype, lkb->lkb_flags);
+	log_error(ls, "remwait error %x remote %d %x msg %d flags %x no wait",
+		  lkb->lkb_id, ms ? ms->m_header.h_nodeid : 0, lkb->lkb_remid,
+		  mstype, lkb->lkb_flags);
 	return -1;
 
  out_del:
@@ -1498,13 +1518,13 @@
 	}
 
 	lkb->lkb_rqmode = DLM_LOCK_IV;
+	lkb->lkb_highbast = 0;
 }
 
 static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
 	set_lvb_lock(r, lkb);
 	_grant_lock(r, lkb);
-	lkb->lkb_highbast = 0;
 }
 
 static void grant_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
@@ -1866,7 +1886,8 @@
 /* Returns the highest requested mode of all blocked conversions; sets
    cw if there's a blocked conversion to DLM_LOCK_CW. */
 
-static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw)
+static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw,
+				 unsigned int *count)
 {
 	struct dlm_lkb *lkb, *s;
 	int hi, demoted, quit, grant_restart, demote_restart;
@@ -1885,6 +1906,8 @@
 		if (can_be_granted(r, lkb, 0, &deadlk)) {
 			grant_lock_pending(r, lkb);
 			grant_restart = 1;
+			if (count)
+				(*count)++;
 			continue;
 		}
 
@@ -1918,14 +1941,17 @@
 	return max_t(int, high, hi);
 }
 
-static int grant_pending_wait(struct dlm_rsb *r, int high, int *cw)
+static int grant_pending_wait(struct dlm_rsb *r, int high, int *cw,
+			      unsigned int *count)
 {
 	struct dlm_lkb *lkb, *s;
 
 	list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) {
-		if (can_be_granted(r, lkb, 0, NULL))
+		if (can_be_granted(r, lkb, 0, NULL)) {
 			grant_lock_pending(r, lkb);
-                else {
+			if (count)
+				(*count)++;
+		} else {
 			high = max_t(int, lkb->lkb_rqmode, high);
 			if (lkb->lkb_rqmode == DLM_LOCK_CW)
 				*cw = 1;
@@ -1954,16 +1980,20 @@
 	return 0;
 }
 
-static void grant_pending_locks(struct dlm_rsb *r)
+static void grant_pending_locks(struct dlm_rsb *r, unsigned int *count)
 {
 	struct dlm_lkb *lkb, *s;
 	int high = DLM_LOCK_IV;
 	int cw = 0;
 
-	DLM_ASSERT(is_master(r), dlm_dump_rsb(r););
+	if (!is_master(r)) {
+		log_print("grant_pending_locks r nodeid %d", r->res_nodeid);
+		dlm_dump_rsb(r);
+		return;
+	}
 
-	high = grant_pending_convert(r, high, &cw);
-	high = grant_pending_wait(r, high, &cw);
+	high = grant_pending_convert(r, high, &cw, count);
+	high = grant_pending_wait(r, high, &cw, count);
 
 	if (high == DLM_LOCK_IV)
 		return;
@@ -2499,7 +2529,7 @@
 	   before we try again to grant this one. */
 
 	if (is_demoted(lkb)) {
-		grant_pending_convert(r, DLM_LOCK_IV, NULL);
+		grant_pending_convert(r, DLM_LOCK_IV, NULL, NULL);
 		if (_can_be_granted(r, lkb, 1)) {
 			grant_lock(r, lkb);
 			queue_cast(r, lkb, 0);
@@ -2527,7 +2557,7 @@
 {
 	switch (error) {
 	case 0:
-		grant_pending_locks(r);
+		grant_pending_locks(r, NULL);
 		/* grant_pending_locks also sends basts */
 		break;
 	case -EAGAIN:
@@ -2550,7 +2580,7 @@
 static void do_unlock_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
 			      int error)
 {
-	grant_pending_locks(r);
+	grant_pending_locks(r, NULL);
 }
 
 /* returns: 0 did nothing, -DLM_ECANCEL canceled lock */
@@ -2571,7 +2601,7 @@
 			      int error)
 {
 	if (error)
-		grant_pending_locks(r);
+		grant_pending_locks(r, NULL);
 }
 
 /*
@@ -3372,7 +3402,7 @@
 	return error;
 }
 
-static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_request(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
@@ -3412,14 +3442,15 @@
 		error = 0;
 	if (error)
 		dlm_put_lkb(lkb);
-	return;
+	return 0;
 
  fail:
 	setup_stub_lkb(ls, ms);
 	send_request_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+	return error;
 }
 
-static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
@@ -3429,6 +3460,15 @@
 	if (error)
 		goto fail;
 
+	if (lkb->lkb_remid != ms->m_lkid) {
+		log_error(ls, "receive_convert %x remid %x recover_seq %llu "
+			  "remote %d %x", lkb->lkb_id, lkb->lkb_remid,
+			  (unsigned long long)lkb->lkb_recover_seq,
+			  ms->m_header.h_nodeid, ms->m_lkid);
+		error = -ENOENT;
+		goto fail;
+	}
+
 	r = lkb->lkb_resource;
 
 	hold_rsb(r);
@@ -3456,14 +3496,15 @@
 	unlock_rsb(r);
 	put_rsb(r);
 	dlm_put_lkb(lkb);
-	return;
+	return 0;
 
  fail:
 	setup_stub_lkb(ls, ms);
 	send_convert_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+	return error;
 }
 
-static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
@@ -3473,6 +3514,14 @@
 	if (error)
 		goto fail;
 
+	if (lkb->lkb_remid != ms->m_lkid) {
+		log_error(ls, "receive_unlock %x remid %x remote %d %x",
+			  lkb->lkb_id, lkb->lkb_remid,
+			  ms->m_header.h_nodeid, ms->m_lkid);
+		error = -ENOENT;
+		goto fail;
+	}
+
 	r = lkb->lkb_resource;
 
 	hold_rsb(r);
@@ -3497,14 +3546,15 @@
 	unlock_rsb(r);
 	put_rsb(r);
 	dlm_put_lkb(lkb);
-	return;
+	return 0;
 
  fail:
 	setup_stub_lkb(ls, ms);
 	send_unlock_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+	return error;
 }
 
-static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
@@ -3532,25 +3582,23 @@
 	unlock_rsb(r);
 	put_rsb(r);
 	dlm_put_lkb(lkb);
-	return;
+	return 0;
 
  fail:
 	setup_stub_lkb(ls, ms);
 	send_cancel_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+	return error;
 }
 
-static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
 	int error;
 
 	error = find_lkb(ls, ms->m_remid, &lkb);
-	if (error) {
-		log_debug(ls, "receive_grant from %d no lkb %x",
-			  ms->m_header.h_nodeid, ms->m_remid);
-		return;
-	}
+	if (error)
+		return error;
 
 	r = lkb->lkb_resource;
 
@@ -3570,20 +3618,18 @@
 	unlock_rsb(r);
 	put_rsb(r);
 	dlm_put_lkb(lkb);
+	return 0;
 }
 
-static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
 	int error;
 
 	error = find_lkb(ls, ms->m_remid, &lkb);
-	if (error) {
-		log_debug(ls, "receive_bast from %d no lkb %x",
-			  ms->m_header.h_nodeid, ms->m_remid);
-		return;
-	}
+	if (error)
+		return error;
 
 	r = lkb->lkb_resource;
 
@@ -3595,10 +3641,12 @@
 		goto out;
 
 	queue_bast(r, lkb, ms->m_bastmode);
+	lkb->lkb_highbast = ms->m_bastmode;
  out:
 	unlock_rsb(r);
 	put_rsb(r);
 	dlm_put_lkb(lkb);
+	return 0;
 }
 
 static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms)
@@ -3653,18 +3701,15 @@
 	do_purge(ls, ms->m_nodeid, ms->m_pid);
 }
 
-static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
 	int error, mstype, result;
 
 	error = find_lkb(ls, ms->m_remid, &lkb);
-	if (error) {
-		log_debug(ls, "receive_request_reply from %d no lkb %x",
-			  ms->m_header.h_nodeid, ms->m_remid);
-		return;
-	}
+	if (error)
+		return error;
 
 	r = lkb->lkb_resource;
 	hold_rsb(r);
@@ -3676,8 +3721,13 @@
 
 	mstype = lkb->lkb_wait_type;
 	error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY);
-	if (error)
+	if (error) {
+		log_error(ls, "receive_request_reply %x remote %d %x result %d",
+			  lkb->lkb_id, ms->m_header.h_nodeid, ms->m_lkid,
+			  ms->m_result);
+		dlm_dump_rsb(r);
 		goto out;
+	}
 
 	/* Optimization: the dir node was also the master, so it took our
 	   lookup as a request and sent request reply instead of lookup reply */
@@ -3755,6 +3805,7 @@
 	unlock_rsb(r);
 	put_rsb(r);
 	dlm_put_lkb(lkb);
+	return 0;
 }
 
 static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
@@ -3793,8 +3844,11 @@
 		break;
 
 	default:
-		log_error(r->res_ls, "receive_convert_reply %x error %d",
-			  lkb->lkb_id, ms->m_result);
+		log_error(r->res_ls, "receive_convert_reply %x remote %d %x %d",
+			  lkb->lkb_id, ms->m_header.h_nodeid, ms->m_lkid,
+			  ms->m_result);
+		dlm_print_rsb(r);
+		dlm_print_lkb(lkb);
 	}
 }
 
@@ -3821,20 +3875,18 @@
 	put_rsb(r);
 }
 
-static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	int error;
 
 	error = find_lkb(ls, ms->m_remid, &lkb);
-	if (error) {
-		log_debug(ls, "receive_convert_reply from %d no lkb %x",
-			  ms->m_header.h_nodeid, ms->m_remid);
-		return;
-	}
+	if (error)
+		return error;
 
 	_receive_convert_reply(lkb, ms);
 	dlm_put_lkb(lkb);
+	return 0;
 }
 
 static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
@@ -3873,20 +3925,18 @@
 	put_rsb(r);
 }
 
-static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	int error;
 
 	error = find_lkb(ls, ms->m_remid, &lkb);
-	if (error) {
-		log_debug(ls, "receive_unlock_reply from %d no lkb %x",
-			  ms->m_header.h_nodeid, ms->m_remid);
-		return;
-	}
+	if (error)
+		return error;
 
 	_receive_unlock_reply(lkb, ms);
 	dlm_put_lkb(lkb);
+	return 0;
 }
 
 static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
@@ -3925,20 +3975,18 @@
 	put_rsb(r);
 }
 
-static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	int error;
 
 	error = find_lkb(ls, ms->m_remid, &lkb);
-	if (error) {
-		log_debug(ls, "receive_cancel_reply from %d no lkb %x",
-			  ms->m_header.h_nodeid, ms->m_remid);
-		return;
-	}
+	if (error)
+		return error;
 
 	_receive_cancel_reply(lkb, ms);
 	dlm_put_lkb(lkb);
+	return 0;
 }
 
 static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
@@ -3949,7 +3997,7 @@
 
 	error = find_lkb(ls, ms->m_lkid, &lkb);
 	if (error) {
-		log_error(ls, "receive_lookup_reply no lkb");
+		log_error(ls, "receive_lookup_reply no lkid %x", ms->m_lkid);
 		return;
 	}
 
@@ -3993,8 +4041,11 @@
 	dlm_put_lkb(lkb);
 }
 
-static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms)
+static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms,
+			     uint32_t saved_seq)
 {
+	int error = 0, noent = 0;
+
 	if (!dlm_is_member(ls, ms->m_header.h_nodeid)) {
 		log_debug(ls, "ignore non-member message %d from %d %x %x %d",
 			  ms->m_type, ms->m_header.h_nodeid, ms->m_lkid,
@@ -4007,47 +4058,50 @@
 	/* messages sent to a master node */
 
 	case DLM_MSG_REQUEST:
-		receive_request(ls, ms);
+		error = receive_request(ls, ms);
 		break;
 
 	case DLM_MSG_CONVERT:
-		receive_convert(ls, ms);
+		error = receive_convert(ls, ms);
 		break;
 
 	case DLM_MSG_UNLOCK:
-		receive_unlock(ls, ms);
+		error = receive_unlock(ls, ms);
 		break;
 
 	case DLM_MSG_CANCEL:
-		receive_cancel(ls, ms);
+		noent = 1;
+		error = receive_cancel(ls, ms);
 		break;
 
 	/* messages sent from a master node (replies to above) */
 
 	case DLM_MSG_REQUEST_REPLY:
-		receive_request_reply(ls, ms);
+		error = receive_request_reply(ls, ms);
 		break;
 
 	case DLM_MSG_CONVERT_REPLY:
-		receive_convert_reply(ls, ms);
+		error = receive_convert_reply(ls, ms);
 		break;
 
 	case DLM_MSG_UNLOCK_REPLY:
-		receive_unlock_reply(ls, ms);
+		error = receive_unlock_reply(ls, ms);
 		break;
 
 	case DLM_MSG_CANCEL_REPLY:
-		receive_cancel_reply(ls, ms);
+		error = receive_cancel_reply(ls, ms);
 		break;
 
 	/* messages sent from a master node (only two types of async msg) */
 
 	case DLM_MSG_GRANT:
-		receive_grant(ls, ms);
+		noent = 1;
+		error = receive_grant(ls, ms);
 		break;
 
 	case DLM_MSG_BAST:
-		receive_bast(ls, ms);
+		noent = 1;
+		error = receive_bast(ls, ms);
 		break;
 
 	/* messages sent to a dir node */
@@ -4075,6 +4129,37 @@
 	default:
 		log_error(ls, "unknown message type %d", ms->m_type);
 	}
+
+	/*
+	 * When checking for ENOENT, we're checking the result of
+	 * find_lkb(m_remid):
+	 *
+	 * The lock id referenced in the message wasn't found.  This may
+	 * happen in normal usage for the async messages and cancel, so
+	 * only use log_debug for them.
+	 *
+	 * Some errors are expected and normal.
+	 */
+
+	if (error == -ENOENT && noent) {
+		log_debug(ls, "receive %d no %x remote %d %x saved_seq %u",
+			  ms->m_type, ms->m_remid, ms->m_header.h_nodeid,
+			  ms->m_lkid, saved_seq);
+	} else if (error == -ENOENT) {
+		log_error(ls, "receive %d no %x remote %d %x saved_seq %u",
+			  ms->m_type, ms->m_remid, ms->m_header.h_nodeid,
+			  ms->m_lkid, saved_seq);
+
+		if (ms->m_type == DLM_MSG_CONVERT)
+			dlm_dump_rsb_hash(ls, ms->m_hash);
+	}
+
+	if (error == -EINVAL) {
+		log_error(ls, "receive %d inval from %d lkid %x remid %x "
+			  "saved_seq %u",
+			  ms->m_type, ms->m_header.h_nodeid,
+			  ms->m_lkid, ms->m_remid, saved_seq);
+	}
 }
 
 /* If the lockspace is in recovery mode (locking stopped), then normal
@@ -4092,16 +4177,17 @@
 		dlm_add_requestqueue(ls, nodeid, ms);
 	} else {
 		dlm_wait_requestqueue(ls);
-		_receive_message(ls, ms);
+		_receive_message(ls, ms, 0);
 	}
 }
 
 /* This is called by dlm_recoverd to process messages that were saved on
    the requestqueue. */
 
-void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms)
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms,
+			       uint32_t saved_seq)
 {
-	_receive_message(ls, ms);
+	_receive_message(ls, ms, saved_seq);
 }
 
 /* This is called by the midcomms layer when something is received for
@@ -4137,9 +4223,11 @@
 
 	ls = dlm_find_lockspace_global(hd->h_lockspace);
 	if (!ls) {
-		if (dlm_config.ci_log_debug)
-			log_print("invalid lockspace %x from %d cmd %d type %d",
-				  hd->h_lockspace, nodeid, hd->h_cmd, type);
+		if (dlm_config.ci_log_debug) {
+			printk_ratelimited(KERN_DEBUG "dlm: invalid lockspace "
+				"%u from %d cmd %d type %d\n",
+				hd->h_lockspace, nodeid, hd->h_cmd, type);
+		}
 
 		if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS)
 			dlm_send_ls_not_ready(nodeid, &p->rcom);
@@ -4187,15 +4275,13 @@
 /* A waiting lkb needs recovery if the master node has failed, or
    the master node is changing (only when no directory is used) */
 
-static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)
+static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb,
+				 int dir_nodeid)
 {
-	if (dlm_is_removed(ls, lkb->lkb_nodeid))
+	if (dlm_no_directory(ls))
 		return 1;
 
-	if (!dlm_no_directory(ls))
-		return 0;
-
-	if (dlm_dir_nodeid(lkb->lkb_resource) != lkb->lkb_nodeid)
+	if (dlm_is_removed(ls, lkb->lkb_wait_nodeid))
 		return 1;
 
 	return 0;
@@ -4212,6 +4298,7 @@
 	struct dlm_lkb *lkb, *safe;
 	struct dlm_message *ms_stub;
 	int wait_type, stub_unlock_result, stub_cancel_result;
+	int dir_nodeid;
 
 	ms_stub = kmalloc(sizeof(struct dlm_message), GFP_KERNEL);
 	if (!ms_stub) {
@@ -4223,13 +4310,21 @@
 
 	list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) {
 
+		dir_nodeid = dlm_dir_nodeid(lkb->lkb_resource);
+
 		/* exclude debug messages about unlocks because there can be so
 		   many and they aren't very interesting */
 
 		if (lkb->lkb_wait_type != DLM_MSG_UNLOCK) {
-			log_debug(ls, "recover_waiter %x nodeid %d "
-				  "msg %d to %d", lkb->lkb_id, lkb->lkb_nodeid,
-				  lkb->lkb_wait_type, lkb->lkb_wait_nodeid);
+			log_debug(ls, "waiter %x remote %x msg %d r_nodeid %d "
+				  "lkb_nodeid %d wait_nodeid %d dir_nodeid %d",
+				  lkb->lkb_id,
+				  lkb->lkb_remid,
+				  lkb->lkb_wait_type,
+				  lkb->lkb_resource->res_nodeid,
+				  lkb->lkb_nodeid,
+				  lkb->lkb_wait_nodeid,
+				  dir_nodeid);
 		}
 
 		/* all outstanding lookups, regardless of destination  will be
@@ -4240,7 +4335,7 @@
 			continue;
 		}
 
-		if (!waiter_needs_recovery(ls, lkb))
+		if (!waiter_needs_recovery(ls, lkb, dir_nodeid))
 			continue;
 
 		wait_type = lkb->lkb_wait_type;
@@ -4373,8 +4468,11 @@
 		ou = is_overlap_unlock(lkb);
 		err = 0;
 
-		log_debug(ls, "recover_waiter %x nodeid %d msg %d r_nodeid %d",
-			  lkb->lkb_id, lkb->lkb_nodeid, mstype, r->res_nodeid);
+		log_debug(ls, "waiter %x remote %x msg %d r_nodeid %d "
+			  "lkb_nodeid %d wait_nodeid %d dir_nodeid %d "
+			  "overlap %d %d", lkb->lkb_id, lkb->lkb_remid, mstype,
+			  r->res_nodeid, lkb->lkb_nodeid, lkb->lkb_wait_nodeid,
+			  dlm_dir_nodeid(r), oc, ou);
 
 		/* At this point we assume that we won't get a reply to any
 		   previous op or overlap op on this lock.  First, do a big
@@ -4426,9 +4524,12 @@
 			}
 		}
 
-		if (err)
-			log_error(ls, "recover_waiters_post %x %d %x %d %d",
-			  	  lkb->lkb_id, mstype, lkb->lkb_flags, oc, ou);
+		if (err) {
+			log_error(ls, "waiter %x msg %d r_nodeid %d "
+				  "dir_nodeid %d overlap %d %d",
+				  lkb->lkb_id, mstype, r->res_nodeid,
+				  dlm_dir_nodeid(r), oc, ou);
+		}
 		unlock_rsb(r);
 		put_rsb(r);
 		dlm_put_lkb(lkb);
@@ -4437,112 +4538,177 @@
 	return error;
 }
 
-static void purge_queue(struct dlm_rsb *r, struct list_head *queue,
-			int (*test)(struct dlm_ls *ls, struct dlm_lkb *lkb))
+static void purge_mstcpy_list(struct dlm_ls *ls, struct dlm_rsb *r,
+			      struct list_head *list)
 {
-	struct dlm_ls *ls = r->res_ls;
 	struct dlm_lkb *lkb, *safe;
 
-	list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) {
-		if (test(ls, lkb)) {
-			rsb_set_flag(r, RSB_LOCKS_PURGED);
-			del_lkb(r, lkb);
-			/* this put should free the lkb */
-			if (!dlm_put_lkb(lkb))
-				log_error(ls, "purged lkb not released");
-		}
+	list_for_each_entry_safe(lkb, safe, list, lkb_statequeue) {
+		if (!is_master_copy(lkb))
+			continue;
+
+		/* don't purge lkbs we've added in recover_master_copy for
+		   the current recovery seq */
+
+		if (lkb->lkb_recover_seq == ls->ls_recover_seq)
+			continue;
+
+		del_lkb(r, lkb);
+
+		/* this put should free the lkb */
+		if (!dlm_put_lkb(lkb))
+			log_error(ls, "purged mstcpy lkb not released");
 	}
 }
 
-static int purge_dead_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
-{
-	return (is_master_copy(lkb) && dlm_is_removed(ls, lkb->lkb_nodeid));
-}
-
-static int purge_mstcpy_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
-{
-	return is_master_copy(lkb);
-}
-
-static void purge_dead_locks(struct dlm_rsb *r)
-{
-	purge_queue(r, &r->res_grantqueue, &purge_dead_test);
-	purge_queue(r, &r->res_convertqueue, &purge_dead_test);
-	purge_queue(r, &r->res_waitqueue, &purge_dead_test);
-}
-
 void dlm_purge_mstcpy_locks(struct dlm_rsb *r)
 {
-	purge_queue(r, &r->res_grantqueue, &purge_mstcpy_test);
-	purge_queue(r, &r->res_convertqueue, &purge_mstcpy_test);
-	purge_queue(r, &r->res_waitqueue, &purge_mstcpy_test);
+	struct dlm_ls *ls = r->res_ls;
+
+	purge_mstcpy_list(ls, r, &r->res_grantqueue);
+	purge_mstcpy_list(ls, r, &r->res_convertqueue);
+	purge_mstcpy_list(ls, r, &r->res_waitqueue);
+}
+
+static void purge_dead_list(struct dlm_ls *ls, struct dlm_rsb *r,
+			    struct list_head *list,
+			    int nodeid_gone, unsigned int *count)
+{
+	struct dlm_lkb *lkb, *safe;
+
+	list_for_each_entry_safe(lkb, safe, list, lkb_statequeue) {
+		if (!is_master_copy(lkb))
+			continue;
+
+		if ((lkb->lkb_nodeid == nodeid_gone) ||
+		    dlm_is_removed(ls, lkb->lkb_nodeid)) {
+
+			del_lkb(r, lkb);
+
+			/* this put should free the lkb */
+			if (!dlm_put_lkb(lkb))
+				log_error(ls, "purged dead lkb not released");
+
+			rsb_set_flag(r, RSB_RECOVER_GRANT);
+
+			(*count)++;
+		}
+	}
 }
 
 /* Get rid of locks held by nodes that are gone. */
 
-int dlm_purge_locks(struct dlm_ls *ls)
+void dlm_recover_purge(struct dlm_ls *ls)
 {
 	struct dlm_rsb *r;
+	struct dlm_member *memb;
+	int nodes_count = 0;
+	int nodeid_gone = 0;
+	unsigned int lkb_count = 0;
 
-	log_debug(ls, "dlm_purge_locks");
+	/* cache one removed nodeid to optimize the common
+	   case of a single node removed */
+
+	list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
+		nodes_count++;
+		nodeid_gone = memb->nodeid;
+	}
+
+	if (!nodes_count)
+		return;
 
 	down_write(&ls->ls_root_sem);
 	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
 		hold_rsb(r);
 		lock_rsb(r);
-		if (is_master(r))
-			purge_dead_locks(r);
+		if (is_master(r)) {
+			purge_dead_list(ls, r, &r->res_grantqueue,
+					nodeid_gone, &lkb_count);
+			purge_dead_list(ls, r, &r->res_convertqueue,
+					nodeid_gone, &lkb_count);
+			purge_dead_list(ls, r, &r->res_waitqueue,
+					nodeid_gone, &lkb_count);
+		}
 		unlock_rsb(r);
 		unhold_rsb(r);
-
-		schedule();
+		cond_resched();
 	}
 	up_write(&ls->ls_root_sem);
 
-	return 0;
+	if (lkb_count)
+		log_debug(ls, "dlm_recover_purge %u locks for %u nodes",
+			  lkb_count, nodes_count);
 }
 
-static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
+static struct dlm_rsb *find_grant_rsb(struct dlm_ls *ls, int bucket)
 {
 	struct rb_node *n;
-	struct dlm_rsb *r, *r_ret = NULL;
+	struct dlm_rsb *r;
 
 	spin_lock(&ls->ls_rsbtbl[bucket].lock);
 	for (n = rb_first(&ls->ls_rsbtbl[bucket].keep); n; n = rb_next(n)) {
 		r = rb_entry(n, struct dlm_rsb, res_hashnode);
-		if (!rsb_flag(r, RSB_LOCKS_PURGED))
+
+		if (!rsb_flag(r, RSB_RECOVER_GRANT))
+			continue;
+		rsb_clear_flag(r, RSB_RECOVER_GRANT);
+		if (!is_master(r))
 			continue;
 		hold_rsb(r);
-		rsb_clear_flag(r, RSB_LOCKS_PURGED);
-		r_ret = r;
-		break;
+		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+		return r;
 	}
 	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
-	return r_ret;
+	return NULL;
 }
 
-void dlm_grant_after_purge(struct dlm_ls *ls)
+/*
+ * Attempt to grant locks on resources that we are the master of.
+ * Locks may have become grantable during recovery because locks
+ * from departed nodes have been purged (or not rebuilt), allowing
+ * previously blocked locks to now be granted.  The subset of rsb's
+ * we are interested in are those with lkb's on either the convert or
+ * waiting queues.
+ *
+ * Simplest would be to go through each master rsb and check for non-empty
+ * convert or waiting queues, and attempt to grant on those rsbs.
+ * Checking the queues requires lock_rsb, though, for which we'd need
+ * to release the rsbtbl lock.  This would make iterating through all
+ * rsb's very inefficient.  So, we rely on earlier recovery routines
+ * to set RECOVER_GRANT on any rsb's that we should attempt to grant
+ * locks for.
+ */
+
+void dlm_recover_grant(struct dlm_ls *ls)
 {
 	struct dlm_rsb *r;
 	int bucket = 0;
+	unsigned int count = 0;
+	unsigned int rsb_count = 0;
+	unsigned int lkb_count = 0;
 
 	while (1) {
-		r = find_purged_rsb(ls, bucket);
+		r = find_grant_rsb(ls, bucket);
 		if (!r) {
 			if (bucket == ls->ls_rsbtbl_size - 1)
 				break;
 			bucket++;
 			continue;
 		}
+		rsb_count++;
+		count = 0;
 		lock_rsb(r);
-		if (is_master(r)) {
-			grant_pending_locks(r);
-			confirm_master(r, 0);
-		}
+		grant_pending_locks(r, &count);
+		lkb_count += count;
+		confirm_master(r, 0);
 		unlock_rsb(r);
 		put_rsb(r);
-		schedule();
+		cond_resched();
 	}
+
+	if (lkb_count)
+		log_debug(ls, "dlm_recover_grant %u locks on %u resources",
+			  lkb_count, rsb_count);
 }
 
 static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,
@@ -4631,6 +4797,7 @@
 	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
 	struct dlm_rsb *r;
 	struct dlm_lkb *lkb;
+	uint32_t remid = 0;
 	int error;
 
 	if (rl->rl_parent_lkid) {
@@ -4638,14 +4805,31 @@
 		goto out;
 	}
 
-	error = find_rsb(ls, rl->rl_name, le16_to_cpu(rl->rl_namelen),
-			 R_MASTER, &r);
+	remid = le32_to_cpu(rl->rl_lkid);
+
+	/* In general we expect the rsb returned to be R_MASTER, but we don't
+	   have to require it.  Recovery of masters on one node can overlap
+	   recovery of locks on another node, so one node can send us MSTCPY
+	   locks before we've made ourselves master of this rsb.  We can still
+	   add new MSTCPY locks that we receive here without any harm; when
+	   we make ourselves master, dlm_recover_masters() won't touch the
+	   MSTCPY locks we've received early. */
+
+	error = find_rsb(ls, rl->rl_name, le16_to_cpu(rl->rl_namelen), 0, &r);
 	if (error)
 		goto out;
 
+	if (dlm_no_directory(ls) && (dlm_dir_nodeid(r) != dlm_our_nodeid())) {
+		log_error(ls, "dlm_recover_master_copy remote %d %x not dir",
+			  rc->rc_header.h_nodeid, remid);
+		error = -EBADR;
+		put_rsb(r);
+		goto out;
+	}
+
 	lock_rsb(r);
 
-	lkb = search_remid(r, rc->rc_header.h_nodeid, le32_to_cpu(rl->rl_lkid));
+	lkb = search_remid(r, rc->rc_header.h_nodeid, remid);
 	if (lkb) {
 		error = -EEXIST;
 		goto out_remid;
@@ -4664,19 +4848,25 @@
 	attach_lkb(r, lkb);
 	add_lkb(r, lkb, rl->rl_status);
 	error = 0;
+	ls->ls_recover_locks_in++;
+
+	if (!list_empty(&r->res_waitqueue) || !list_empty(&r->res_convertqueue))
+		rsb_set_flag(r, RSB_RECOVER_GRANT);
 
  out_remid:
 	/* this is the new value returned to the lock holder for
 	   saving in its process-copy lkb */
 	rl->rl_remid = cpu_to_le32(lkb->lkb_id);
 
+	lkb->lkb_recover_seq = ls->ls_recover_seq;
+
  out_unlock:
 	unlock_rsb(r);
 	put_rsb(r);
  out:
-	if (error)
-		log_debug(ls, "recover_master_copy %d %x", error,
-			  le32_to_cpu(rl->rl_lkid));
+	if (error && error != -EEXIST)
+		log_debug(ls, "dlm_recover_master_copy remote %d %x error %d",
+			  rc->rc_header.h_nodeid, remid, error);
 	rl->rl_result = cpu_to_le32(error);
 	return error;
 }
@@ -4687,41 +4877,52 @@
 	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
 	struct dlm_rsb *r;
 	struct dlm_lkb *lkb;
-	int error;
+	uint32_t lkid, remid;
+	int error, result;
 
-	error = find_lkb(ls, le32_to_cpu(rl->rl_lkid), &lkb);
+	lkid = le32_to_cpu(rl->rl_lkid);
+	remid = le32_to_cpu(rl->rl_remid);
+	result = le32_to_cpu(rl->rl_result);
+
+	error = find_lkb(ls, lkid, &lkb);
 	if (error) {
-		log_error(ls, "recover_process_copy no lkid %x",
-				le32_to_cpu(rl->rl_lkid));
+		log_error(ls, "dlm_recover_process_copy no %x remote %d %x %d",
+			  lkid, rc->rc_header.h_nodeid, remid, result);
 		return error;
 	}
 
-	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
-
-	error = le32_to_cpu(rl->rl_result);
-
 	r = lkb->lkb_resource;
 	hold_rsb(r);
 	lock_rsb(r);
 
-	switch (error) {
+	if (!is_process_copy(lkb)) {
+		log_error(ls, "dlm_recover_process_copy bad %x remote %d %x %d",
+			  lkid, rc->rc_header.h_nodeid, remid, result);
+		dlm_dump_rsb(r);
+		unlock_rsb(r);
+		put_rsb(r);
+		dlm_put_lkb(lkb);
+		return -EINVAL;
+	}
+
+	switch (result) {
 	case -EBADR:
 		/* There's a chance the new master received our lock before
 		   dlm_recover_master_reply(), this wouldn't happen if we did
 		   a barrier between recover_masters and recover_locks. */
-		log_debug(ls, "master copy not ready %x r %lx %s", lkb->lkb_id,
-			  (unsigned long)r, r->res_name);
+
+		log_debug(ls, "dlm_recover_process_copy %x remote %d %x %d",
+			  lkid, rc->rc_header.h_nodeid, remid, result);
+	
 		dlm_send_rcom_lock(r, lkb);
 		goto out;
 	case -EEXIST:
-		log_debug(ls, "master copy exists %x", lkb->lkb_id);
-		/* fall through */
 	case 0:
-		lkb->lkb_remid = le32_to_cpu(rl->rl_remid);
+		lkb->lkb_remid = remid;
 		break;
 	default:
-		log_error(ls, "dlm_recover_process_copy unknown error %d %x",
-			  error, lkb->lkb_id);
+		log_error(ls, "dlm_recover_process_copy %x remote %d %x %d unk",
+			  lkid, rc->rc_header.h_nodeid, remid, result);
 	}
 
 	/* an ack for dlm_recover_locks() which waits for replies from
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 1a25530..c8b226c 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -15,7 +15,8 @@
 
 void dlm_dump_rsb(struct dlm_rsb *r);
 void dlm_print_lkb(struct dlm_lkb *lkb);
-void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms);
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms,
+			       uint32_t saved_seq);
 void dlm_receive_buffer(union dlm_packet *p, int nodeid);
 int dlm_modes_compat(int mode1, int mode2);
 void dlm_put_rsb(struct dlm_rsb *r);
@@ -31,9 +32,9 @@
 int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len,
 			unsigned int flags, struct dlm_rsb **r_ret);
 
-int dlm_purge_locks(struct dlm_ls *ls);
+void dlm_recover_purge(struct dlm_ls *ls);
 void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
-void dlm_grant_after_purge(struct dlm_ls *ls);
+void dlm_recover_grant(struct dlm_ls *ls);
 int dlm_recover_waiters_post(struct dlm_ls *ls);
 void dlm_recover_waiters_pre(struct dlm_ls *ls);
 int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index a1ea25f..ca506abb 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -74,6 +74,19 @@
 	return len;
 }
 
+static ssize_t dlm_nodir_show(struct dlm_ls *ls, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", dlm_no_directory(ls));
+}
+
+static ssize_t dlm_nodir_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+	int val = simple_strtoul(buf, NULL, 0);
+	if (val == 1)
+		set_bit(LSFL_NODIR, &ls->ls_flags);
+	return len;
+}
+
 static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf)
 {
 	uint32_t status = dlm_recover_status(ls);
@@ -107,6 +120,12 @@
 	.store = dlm_id_store
 };
 
+static struct dlm_attr dlm_attr_nodir = {
+	.attr  = {.name = "nodir", .mode = S_IRUGO | S_IWUSR},
+	.show  = dlm_nodir_show,
+	.store = dlm_nodir_store
+};
+
 static struct dlm_attr dlm_attr_recover_status = {
 	.attr  = {.name = "recover_status", .mode = S_IRUGO},
 	.show  = dlm_recover_status_show
@@ -121,6 +140,7 @@
 	&dlm_attr_control.attr,
 	&dlm_attr_event.attr,
 	&dlm_attr_id.attr,
+	&dlm_attr_nodir.attr,
 	&dlm_attr_recover_status.attr,
 	&dlm_attr_recover_nodeid.attr,
 	NULL,
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 133ef6d..5c1b0e3 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -142,6 +142,7 @@
 
 static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
 static int dlm_local_count;
+static int dlm_allow_conn;
 
 /* Work queues */
 static struct workqueue_struct *recv_workqueue;
@@ -710,6 +711,13 @@
 	struct connection *newcon;
 	struct connection *addcon;
 
+	mutex_lock(&connections_lock);
+	if (!dlm_allow_conn) {
+		mutex_unlock(&connections_lock);
+		return -1;
+	}
+	mutex_unlock(&connections_lock);
+
 	memset(&peeraddr, 0, sizeof(peeraddr));
 	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
 				  IPPROTO_TCP, &newsock);
@@ -1503,6 +1511,7 @@
 	   socket activity.
 	*/
 	mutex_lock(&connections_lock);
+	dlm_allow_conn = 0;
 	foreach_conn(stop_conn);
 	mutex_unlock(&connections_lock);
 
@@ -1530,7 +1539,7 @@
 	if (!dlm_local_count) {
 		error = -ENOTCONN;
 		log_print("no local IP address has been set");
-		goto out;
+		goto fail;
 	}
 
 	error = -ENOMEM;
@@ -1538,7 +1547,13 @@
 				      __alignof__(struct connection), 0,
 				      NULL);
 	if (!con_cache)
-		goto out;
+		goto fail;
+
+	error = work_start();
+	if (error)
+		goto fail_destroy;
+
+	dlm_allow_conn = 1;
 
 	/* Start listening */
 	if (dlm_config.ci_protocol == 0)
@@ -1548,20 +1563,17 @@
 	if (error)
 		goto fail_unlisten;
 
-	error = work_start();
-	if (error)
-		goto fail_unlisten;
-
 	return 0;
 
 fail_unlisten:
+	dlm_allow_conn = 0;
 	con = nodeid2con(0,0);
 	if (con) {
 		close_connection(con, false);
 		kmem_cache_free(con_cache, con);
 	}
+fail_destroy:
 	kmem_cache_destroy(con_cache);
-
-out:
+fail:
 	return error;
 }
diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c
index da64df7..7cd24bc 100644
--- a/fs/dlm/memory.c
+++ b/fs/dlm/memory.c
@@ -21,21 +21,19 @@
 
 int __init dlm_memory_init(void)
 {
-	int ret = 0;
-
 	lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb),
 				__alignof__(struct dlm_lkb), 0, NULL);
 	if (!lkb_cache)
-		ret = -ENOMEM;
+		return -ENOMEM;
 
 	rsb_cache = kmem_cache_create("dlm_rsb", sizeof(struct dlm_rsb),
 				__alignof__(struct dlm_rsb), 0, NULL);
 	if (!rsb_cache) {
 		kmem_cache_destroy(lkb_cache);
-		ret = -ENOMEM;
+		return -ENOMEM;
 	}
 
-	return ret;
+	return 0;
 }
 
 void dlm_memory_exit(void)
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index ac5c616..64d3e2b 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -486,47 +486,50 @@
 	return 0;
 }
 
-static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
-{
-	uint64_t seq;
-	int rv = 0;
-
-	switch (rc->rc_type) {
-	case DLM_RCOM_STATUS_REPLY:
-	case DLM_RCOM_NAMES_REPLY:
-	case DLM_RCOM_LOOKUP_REPLY:
-	case DLM_RCOM_LOCK_REPLY:
-		spin_lock(&ls->ls_recover_lock);
-		seq = ls->ls_recover_seq;
-		spin_unlock(&ls->ls_recover_lock);
-		if (rc->rc_seq_reply != seq) {
-			log_debug(ls, "ignoring old reply %x from %d "
-				      "seq_reply %llx expect %llx",
-				      rc->rc_type, rc->rc_header.h_nodeid,
-				      (unsigned long long)rc->rc_seq_reply,
-				      (unsigned long long)seq);
-			rv = 1;
-		}
-	}
-	return rv;
-}
-
 /* Called by dlm_recv; corresponds to dlm_receive_message() but special
    recovery-only comms are sent through here. */
 
 void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 {
 	int lock_size = sizeof(struct dlm_rcom) + sizeof(struct rcom_lock);
+	int stop, reply = 0, lock = 0;
+	uint32_t status;
+	uint64_t seq;
 
-	if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
-		log_debug(ls, "ignoring recovery message %x from %d",
-			  rc->rc_type, nodeid);
+	switch (rc->rc_type) {
+	case DLM_RCOM_LOCK:
+		lock = 1;
+		break;
+	case DLM_RCOM_LOCK_REPLY:
+		lock = 1;
+		reply = 1;
+		break;
+	case DLM_RCOM_STATUS_REPLY:
+	case DLM_RCOM_NAMES_REPLY:
+	case DLM_RCOM_LOOKUP_REPLY:
+		reply = 1;
+	};
+
+	spin_lock(&ls->ls_recover_lock);
+	status = ls->ls_recover_status;
+	stop = test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+	seq = ls->ls_recover_seq;
+	spin_unlock(&ls->ls_recover_lock);
+
+	if ((stop && (rc->rc_type != DLM_RCOM_STATUS)) ||
+	    (reply && (rc->rc_seq_reply != seq)) ||
+	    (lock && !(status & DLM_RS_DIR))) {
+		log_limit(ls, "dlm_receive_rcom ignore msg %d "
+			  "from %d %llu %llu recover seq %llu sts %x gen %u",
+			   rc->rc_type,
+			   nodeid,
+			   (unsigned long long)rc->rc_seq,
+			   (unsigned long long)rc->rc_seq_reply,
+			   (unsigned long long)seq,
+			   status, ls->ls_generation);
 		goto out;
 	}
 
-	if (is_old_reply(ls, rc))
-		goto out;
-
 	switch (rc->rc_type) {
 	case DLM_RCOM_STATUS:
 		receive_rcom_status(ls, rc);
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c
index 34d5adf1f..7554e4d 100644
--- a/fs/dlm/recover.c
+++ b/fs/dlm/recover.c
@@ -339,9 +339,12 @@
 {
 	struct dlm_lkb *lkb;
 
-	list_for_each_entry(lkb, queue, lkb_statequeue)
-		if (!(lkb->lkb_flags & DLM_IFL_MSTCPY))
+	list_for_each_entry(lkb, queue, lkb_statequeue) {
+		if (!(lkb->lkb_flags & DLM_IFL_MSTCPY)) {
 			lkb->lkb_nodeid = nodeid;
+			lkb->lkb_remid = 0;
+		}
+	}
 }
 
 static void set_master_lkbs(struct dlm_rsb *r)
@@ -354,18 +357,16 @@
 /*
  * Propagate the new master nodeid to locks
  * The NEW_MASTER flag tells dlm_recover_locks() which rsb's to consider.
- * The NEW_MASTER2 flag tells recover_lvb() and set_locks_purged() which
+ * The NEW_MASTER2 flag tells recover_lvb() and recover_grant() which
  * rsb's to consider.
  */
 
 static void set_new_master(struct dlm_rsb *r, int nodeid)
 {
-	lock_rsb(r);
 	r->res_nodeid = nodeid;
 	set_master_lkbs(r);
 	rsb_set_flag(r, RSB_NEW_MASTER);
 	rsb_set_flag(r, RSB_NEW_MASTER2);
-	unlock_rsb(r);
 }
 
 /*
@@ -376,9 +377,9 @@
 static int recover_master(struct dlm_rsb *r)
 {
 	struct dlm_ls *ls = r->res_ls;
-	int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
-
-	dir_nodeid = dlm_dir_nodeid(r);
+	int error, ret_nodeid;
+	int our_nodeid = dlm_our_nodeid();
+	int dir_nodeid = dlm_dir_nodeid(r);
 
 	if (dir_nodeid == our_nodeid) {
 		error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
@@ -388,7 +389,9 @@
 
 		if (ret_nodeid == our_nodeid)
 			ret_nodeid = 0;
+		lock_rsb(r);
 		set_new_master(r, ret_nodeid);
+		unlock_rsb(r);
 	} else {
 		recover_list_add(r);
 		error = dlm_send_rcom_lookup(r, dir_nodeid);
@@ -398,24 +401,33 @@
 }
 
 /*
- * When not using a directory, most resource names will hash to a new static
- * master nodeid and the resource will need to be remastered.
+ * All MSTCPY locks are purged and rebuilt, even if the master stayed the same.
+ * This is necessary because recovery can be started, aborted and restarted,
+ * causing the master nodeid to briefly change during the aborted recovery, and
+ * change back to the original value in the second recovery.  The MSTCPY locks
+ * may or may not have been purged during the aborted recovery.  Another node
+ * with an outstanding request in waiters list and a request reply saved in the
+ * requestqueue, cannot know whether it should ignore the reply and resend the
+ * request, or accept the reply and complete the request.  It must do the
+ * former if the remote node purged MSTCPY locks, and it must do the later if
+ * the remote node did not.  This is solved by always purging MSTCPY locks, in
+ * which case, the request reply would always be ignored and the request
+ * resent.
  */
 
 static int recover_master_static(struct dlm_rsb *r)
 {
-	int master = dlm_dir_nodeid(r);
+	int dir_nodeid = dlm_dir_nodeid(r);
+	int new_master = dir_nodeid;
 
-	if (master == dlm_our_nodeid())
-		master = 0;
+	if (dir_nodeid == dlm_our_nodeid())
+		new_master = 0;
 
-	if (r->res_nodeid != master) {
-		if (is_master(r))
-			dlm_purge_mstcpy_locks(r);
-		set_new_master(r, master);
-		return 1;
-	}
-	return 0;
+	lock_rsb(r);
+	dlm_purge_mstcpy_locks(r);
+	set_new_master(r, new_master);
+	unlock_rsb(r);
+	return 1;
 }
 
 /*
@@ -481,7 +493,9 @@
 	if (nodeid == dlm_our_nodeid())
 		nodeid = 0;
 
+	lock_rsb(r);
 	set_new_master(r, nodeid);
+	unlock_rsb(r);
 	recover_list_del(r);
 
 	if (recover_list_empty(ls))
@@ -556,8 +570,6 @@
 	struct dlm_rsb *r;
 	int error, count = 0;
 
-	log_debug(ls, "dlm_recover_locks");
-
 	down_read(&ls->ls_root_sem);
 	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
 		if (is_master(r)) {
@@ -584,7 +596,7 @@
 	}
 	up_read(&ls->ls_root_sem);
 
-	log_debug(ls, "dlm_recover_locks %d locks", count);
+	log_debug(ls, "dlm_recover_locks %d out", count);
 
 	error = dlm_wait_function(ls, &recover_list_empty);
  out:
@@ -721,21 +733,19 @@
 }
 
 /* We've become the new master for this rsb and waiting/converting locks may
-   need to be granted in dlm_grant_after_purge() due to locks that may have
+   need to be granted in dlm_recover_grant() due to locks that may have
    existed from a removed node. */
 
-static void set_locks_purged(struct dlm_rsb *r)
+static void recover_grant(struct dlm_rsb *r)
 {
 	if (!list_empty(&r->res_waitqueue) || !list_empty(&r->res_convertqueue))
-		rsb_set_flag(r, RSB_LOCKS_PURGED);
+		rsb_set_flag(r, RSB_RECOVER_GRANT);
 }
 
 void dlm_recover_rsbs(struct dlm_ls *ls)
 {
 	struct dlm_rsb *r;
-	int count = 0;
-
-	log_debug(ls, "dlm_recover_rsbs");
+	unsigned int count = 0;
 
 	down_read(&ls->ls_root_sem);
 	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
@@ -744,7 +754,7 @@
 			if (rsb_flag(r, RSB_RECOVER_CONVERT))
 				recover_conversion(r);
 			if (rsb_flag(r, RSB_NEW_MASTER2))
-				set_locks_purged(r);
+				recover_grant(r);
 			recover_lvb(r);
 			count++;
 		}
@@ -754,7 +764,8 @@
 	}
 	up_read(&ls->ls_root_sem);
 
-	log_debug(ls, "dlm_recover_rsbs %d rsbs", count);
+	if (count)
+		log_debug(ls, "dlm_recover_rsbs %d done", count);
 }
 
 /* Create a single list of all root rsb's to be used during recovery */
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index 3780caf..f1a9073 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -54,7 +54,7 @@
 	unsigned long start;
 	int error, neg = 0;
 
-	log_debug(ls, "dlm_recover %llx", (unsigned long long)rv->seq);
+	log_debug(ls, "dlm_recover %llu", (unsigned long long)rv->seq);
 
 	mutex_lock(&ls->ls_recoverd_active);
 
@@ -84,6 +84,8 @@
 		goto fail;
 	}
 
+	ls->ls_recover_locks_in = 0;
+
 	dlm_set_recover_status(ls, DLM_RS_NODES);
 
 	error = dlm_recover_members_wait(ls);
@@ -130,7 +132,7 @@
 		 * Clear lkb's for departed nodes.
 		 */
 
-		dlm_purge_locks(ls);
+		dlm_recover_purge(ls);
 
 		/*
 		 * Get new master nodeid's for rsb's that were mastered on
@@ -161,6 +163,9 @@
 			goto fail;
 		}
 
+		log_debug(ls, "dlm_recover_locks %u in",
+			  ls->ls_recover_locks_in);
+
 		/*
 		 * Finalize state in master rsb's now that all locks can be
 		 * checked.  This includes conversion resolution and lvb
@@ -225,9 +230,9 @@
 		goto fail;
 	}
 
-	dlm_grant_after_purge(ls);
+	dlm_recover_grant(ls);
 
-	log_debug(ls, "dlm_recover %llx generation %u done: %u ms",
+	log_debug(ls, "dlm_recover %llu generation %u done: %u ms",
 		  (unsigned long long)rv->seq, ls->ls_generation,
 		  jiffies_to_msecs(jiffies - start));
 	mutex_unlock(&ls->ls_recoverd_active);
@@ -237,7 +242,7 @@
 
  fail:
 	dlm_release_root_list(ls);
-	log_debug(ls, "dlm_recover %llx error %d",
+	log_debug(ls, "dlm_recover %llu error %d",
 		  (unsigned long long)rv->seq, error);
 	mutex_unlock(&ls->ls_recoverd_active);
 	return error;
diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c
index a44fa22..1695f1b 100644
--- a/fs/dlm/requestqueue.c
+++ b/fs/dlm/requestqueue.c
@@ -19,6 +19,7 @@
 
 struct rq_entry {
 	struct list_head list;
+	uint32_t recover_seq;
 	int nodeid;
 	struct dlm_message request;
 };
@@ -41,6 +42,7 @@
 		return;
 	}
 
+	e->recover_seq = ls->ls_recover_seq & 0xFFFFFFFF;
 	e->nodeid = nodeid;
 	memcpy(&e->request, ms, ms->m_header.h_length);
 
@@ -63,6 +65,7 @@
 int dlm_process_requestqueue(struct dlm_ls *ls)
 {
 	struct rq_entry *e;
+	struct dlm_message *ms;
 	int error = 0;
 
 	mutex_lock(&ls->ls_requestqueue_mutex);
@@ -76,7 +79,15 @@
 		e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
 		mutex_unlock(&ls->ls_requestqueue_mutex);
 
-		dlm_receive_message_saved(ls, &e->request);
+		ms = &e->request;
+
+		log_limit(ls, "dlm_process_requestqueue msg %d from %d "
+			  "lkid %x remid %x result %d seq %u",
+			  ms->m_type, ms->m_header.h_nodeid,
+			  ms->m_lkid, ms->m_remid, ms->m_result,
+			  e->recover_seq);
+
+		dlm_receive_message_saved(ls, &e->request, e->recover_seq);
 
 		mutex_lock(&ls->ls_requestqueue_mutex);
 		list_del(&e->list);
@@ -138,35 +149,7 @@
 	if (!dlm_no_directory(ls))
 		return 0;
 
-	/* with no directory, the master is likely to change as a part of
-	   recovery; requests to/from the defunct master need to be purged */
-
-	switch (type) {
-	case DLM_MSG_REQUEST:
-	case DLM_MSG_CONVERT:
-	case DLM_MSG_UNLOCK:
-	case DLM_MSG_CANCEL:
-		/* we're no longer the master of this resource, the sender
-		   will resend to the new master (see waiter_needs_recovery) */
-
-		if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid())
-			return 1;
-		break;
-
-	case DLM_MSG_REQUEST_REPLY:
-	case DLM_MSG_CONVERT_REPLY:
-	case DLM_MSG_UNLOCK_REPLY:
-	case DLM_MSG_CANCEL_REPLY:
-	case DLM_MSG_GRANT:
-		/* this reply is from the former master of the resource,
-		   we'll resend to the new master if needed */
-
-		if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid)
-			return 1;
-		break;
-	}
-
-	return 0;
+	return 1;
 }
 
 void dlm_purge_requestqueue(struct dlm_ls *ls)
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index ab22480..a750f95 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -303,7 +303,7 @@
 		mutex_unlock(&ecryptfs_daemon_hash_mux);
 		goto wake_up;
 	}
-	tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns;
+	tsk_user_ns = __task_cred(msg_ctx->task)->user_ns;
 	ctx_euid = task_euid(msg_ctx->task);
 	rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);
 	rcu_read_unlock();
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index c0b3c70..079d1be 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -33,6 +33,7 @@
 #include <linux/bitops.h>
 #include <linux/mutex.h>
 #include <linux/anon_inodes.h>
+#include <linux/device.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/mman.h>
@@ -87,7 +88,7 @@
  */
 
 /* Epoll private bits inside the event mask */
-#define EP_PRIVATE_BITS (EPOLLONESHOT | EPOLLET)
+#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET)
 
 /* Maximum number of nesting allowed inside epoll sets */
 #define EP_MAX_NESTS 4
@@ -154,6 +155,9 @@
 	/* List header used to link this item to the "struct file" items list */
 	struct list_head fllink;
 
+	/* wakeup_source used when EPOLLWAKEUP is set */
+	struct wakeup_source *ws;
+
 	/* The structure that describe the interested events and the source fd */
 	struct epoll_event event;
 };
@@ -194,6 +198,9 @@
 	 */
 	struct epitem *ovflist;
 
+	/* wakeup_source used when ep_scan_ready_list is running */
+	struct wakeup_source *ws;
+
 	/* The user that created the eventpoll descriptor */
 	struct user_struct *user;
 
@@ -588,8 +595,10 @@
 		 * queued into ->ovflist but the "txlist" might already
 		 * contain them, and the list_splice() below takes care of them.
 		 */
-		if (!ep_is_linked(&epi->rdllink))
+		if (!ep_is_linked(&epi->rdllink)) {
 			list_add_tail(&epi->rdllink, &ep->rdllist);
+			__pm_stay_awake(epi->ws);
+		}
 	}
 	/*
 	 * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after
@@ -602,6 +611,7 @@
 	 * Quickly re-inject items left on "txlist".
 	 */
 	list_splice(&txlist, &ep->rdllist);
+	__pm_relax(ep->ws);
 
 	if (!list_empty(&ep->rdllist)) {
 		/*
@@ -656,6 +666,8 @@
 		list_del_init(&epi->rdllink);
 	spin_unlock_irqrestore(&ep->lock, flags);
 
+	wakeup_source_unregister(epi->ws);
+
 	/* At this point it is safe to free the eventpoll item */
 	kmem_cache_free(epi_cache, epi);
 
@@ -706,6 +718,7 @@
 	mutex_unlock(&epmutex);
 	mutex_destroy(&ep->mtx);
 	free_uid(ep->user);
+	wakeup_source_unregister(ep->ws);
 	kfree(ep);
 }
 
@@ -737,6 +750,7 @@
 			 * callback, but it's not actually ready, as far as
 			 * caller requested events goes. We can remove it here.
 			 */
+			__pm_relax(epi->ws);
 			list_del_init(&epi->rdllink);
 		}
 	}
@@ -927,13 +941,23 @@
 		if (epi->next == EP_UNACTIVE_PTR) {
 			epi->next = ep->ovflist;
 			ep->ovflist = epi;
+			if (epi->ws) {
+				/*
+				 * Activate ep->ws since epi->ws may get
+				 * deactivated at any time.
+				 */
+				__pm_stay_awake(ep->ws);
+			}
+
 		}
 		goto out_unlock;
 	}
 
 	/* If this file is already in the ready list we exit soon */
-	if (!ep_is_linked(&epi->rdllink))
+	if (!ep_is_linked(&epi->rdllink)) {
 		list_add_tail(&epi->rdllink, &ep->rdllist);
+		__pm_stay_awake(epi->ws);
+	}
 
 	/*
 	 * Wake up ( if active ) both the eventpoll wait list and the ->poll()
@@ -1091,6 +1115,30 @@
 	return error;
 }
 
+static int ep_create_wakeup_source(struct epitem *epi)
+{
+	const char *name;
+
+	if (!epi->ep->ws) {
+		epi->ep->ws = wakeup_source_register("eventpoll");
+		if (!epi->ep->ws)
+			return -ENOMEM;
+	}
+
+	name = epi->ffd.file->f_path.dentry->d_name.name;
+	epi->ws = wakeup_source_register(name);
+	if (!epi->ws)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void ep_destroy_wakeup_source(struct epitem *epi)
+{
+	wakeup_source_unregister(epi->ws);
+	epi->ws = NULL;
+}
+
 /*
  * Must be called with "mtx" held.
  */
@@ -1118,6 +1166,13 @@
 	epi->event = *event;
 	epi->nwait = 0;
 	epi->next = EP_UNACTIVE_PTR;
+	if (epi->event.events & EPOLLWAKEUP) {
+		error = ep_create_wakeup_source(epi);
+		if (error)
+			goto error_create_wakeup_source;
+	} else {
+		epi->ws = NULL;
+	}
 
 	/* Initialize the poll table using the queue callback */
 	epq.epi = epi;
@@ -1164,6 +1219,7 @@
 	/* If the file is already "ready" we drop it inside the ready list */
 	if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) {
 		list_add_tail(&epi->rdllink, &ep->rdllist);
+		__pm_stay_awake(epi->ws);
 
 		/* Notify waiting tasks that events are available */
 		if (waitqueue_active(&ep->wq))
@@ -1204,6 +1260,9 @@
 		list_del_init(&epi->rdllink);
 	spin_unlock_irqrestore(&ep->lock, flags);
 
+	wakeup_source_unregister(epi->ws);
+
+error_create_wakeup_source:
 	kmem_cache_free(epi_cache, epi);
 
 	return error;
@@ -1229,6 +1288,12 @@
 	epi->event.events = event->events;
 	pt._key = event->events;
 	epi->event.data = event->data; /* protected by mtx */
+	if (epi->event.events & EPOLLWAKEUP) {
+		if (!epi->ws)
+			ep_create_wakeup_source(epi);
+	} else if (epi->ws) {
+		ep_destroy_wakeup_source(epi);
+	}
 
 	/*
 	 * Get current event bits. We can safely use the file* here because
@@ -1244,6 +1309,7 @@
 		spin_lock_irq(&ep->lock);
 		if (!ep_is_linked(&epi->rdllink)) {
 			list_add_tail(&epi->rdllink, &ep->rdllist);
+			__pm_stay_awake(epi->ws);
 
 			/* Notify waiting tasks that events are available */
 			if (waitqueue_active(&ep->wq))
@@ -1282,6 +1348,18 @@
 	     !list_empty(head) && eventcnt < esed->maxevents;) {
 		epi = list_first_entry(head, struct epitem, rdllink);
 
+		/*
+		 * Activate ep->ws before deactivating epi->ws to prevent
+		 * triggering auto-suspend here (in case we reactive epi->ws
+		 * below).
+		 *
+		 * This could be rearranged to delay the deactivation of epi->ws
+		 * instead, but then epi->ws would temporarily be out of sync
+		 * with ep_is_linked().
+		 */
+		if (epi->ws && epi->ws->active)
+			__pm_stay_awake(ep->ws);
+		__pm_relax(epi->ws);
 		list_del_init(&epi->rdllink);
 
 		pt._key = epi->event.events;
@@ -1298,6 +1376,7 @@
 			if (__put_user(revents, &uevent->events) ||
 			    __put_user(epi->event.data, &uevent->data)) {
 				list_add(&epi->rdllink, head);
+				__pm_stay_awake(epi->ws);
 				return eventcnt ? eventcnt : -EFAULT;
 			}
 			eventcnt++;
@@ -1317,6 +1396,7 @@
 				 * poll callback will queue them in ep->ovflist.
 				 */
 				list_add_tail(&epi->rdllink, &ep->rdllist);
+				__pm_stay_awake(epi->ws);
 			}
 		}
 	}
@@ -1629,6 +1709,10 @@
 	if (!tfile->f_op || !tfile->f_op->poll)
 		goto error_tgt_fput;
 
+	/* Check if EPOLLWAKEUP is allowed */
+	if ((epds.events & EPOLLWAKEUP) && !capable(CAP_EPOLLWAKEUP))
+		epds.events &= ~EPOLLWAKEUP;
+
 	/*
 	 * We have to check that the file structure underneath the file descriptor
 	 * the user passed to us _is_ an eventpoll file. And also we do not permit
diff --git a/fs/exec.c b/fs/exec.c
index d038968..52c9e2f 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1139,7 +1139,7 @@
 	/* This is the point of no return */
 	current->sas_ss_sp = current->sas_ss_size = 0;
 
-	if (current_euid() == current_uid() && current_egid() == current_gid())
+	if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid()))
 		set_dumpable(current->mm, 1);
 	else
 		set_dumpable(current->mm, suid_dumpable);
@@ -1153,8 +1153,8 @@
 	current->mm->task_size = TASK_SIZE;
 
 	/* install the new credentials */
-	if (bprm->cred->uid != current_euid() ||
-	    bprm->cred->gid != current_egid()) {
+	if (!uid_eq(bprm->cred->uid, current_euid()) ||
+	    !gid_eq(bprm->cred->gid, current_egid())) {
 		current->pdeath_signal = 0;
 	} else {
 		would_dump(bprm, bprm->file);
@@ -1299,8 +1299,11 @@
 	    !current->no_new_privs) {
 		/* Set-uid? */
 		if (mode & S_ISUID) {
+			if (!kuid_has_mapping(bprm->cred->user_ns, inode->i_uid))
+				return -EPERM;
 			bprm->per_clear |= PER_CLEAR_ON_SETID;
 			bprm->cred->euid = inode->i_uid;
+
 		}
 
 		/* Set-gid? */
@@ -1310,6 +1313,8 @@
 		 * executable.
 		 */
 		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+			if (!kgid_has_mapping(bprm->cred->user_ns, inode->i_gid))
+				return -EPERM;
 			bprm->per_clear |= PER_CLEAR_ON_SETID;
 			bprm->cred->egid = inode->i_gid;
 		}
@@ -1938,8 +1943,21 @@
 		core_waiters = zap_threads(tsk, mm, core_state, exit_code);
 	up_write(&mm->mmap_sem);
 
-	if (core_waiters > 0)
+	if (core_waiters > 0) {
+		struct core_thread *ptr;
+
 		wait_for_completion(&core_state->startup);
+		/*
+		 * Wait for all the threads to become inactive, so that
+		 * all the thread context (extended register state, like
+		 * fpu etc) gets copied to the memory.
+		 */
+		ptr = core_state->dumper.next;
+		while (ptr != NULL) {
+			wait_task_inactive(ptr->task, 0);
+			ptr = ptr->next;
+		}
+	}
 
 	return core_waiters;
 }
@@ -2129,7 +2147,7 @@
 	if (__get_dumpable(cprm.mm_flags) == 2) {
 		/* Setuid core dump mode */
 		flag = O_EXCL;		/* Stop rewrite attacks */
-		cred->fsuid = 0;	/* Dump root private */
+		cred->fsuid = GLOBAL_ROOT_UID;	/* Dump root private */
 	}
 
 	retval = coredump_wait(exit_code, &core_state);
@@ -2230,7 +2248,7 @@
 		 * Dont allow local users get cute and trick others to coredump
 		 * into their pre-created files.
 		 */
-		if (inode->i_uid != current_fsuid())
+		if (!uid_eq(inode->i_uid, current_fsuid()))
 			goto close_fail;
 		if (!cprm.file->f_op || !cprm.file->f_op->write)
 			goto close_fail;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index a8cbe1b..030c6d2 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -1193,8 +1193,9 @@
 	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
 	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
 	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
-		sbi->s_resuid != current_fsuid() &&
-		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+		!uid_eq(sbi->s_resuid, current_fsuid()) &&
+		(gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) ||
+		 !in_group_p (sbi->s_resgid))) {
 		return 0;
 	}
 	return 1;
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 0b2b4db..d9a17d0 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -82,8 +82,8 @@
 	struct buffer_head ** s_group_desc;
 	unsigned long  s_mount_opt;
 	unsigned long s_sb_block;
-	uid_t s_resuid;
-	gid_t s_resgid;
+	kuid_t s_resuid;
+	kgid_t s_resgid;
 	unsigned short s_mount_state;
 	unsigned short s_pad;
 	int s_addr_per_block_bits;
@@ -637,8 +637,8 @@
  */
 struct ext2_mount_options {
 	unsigned long s_mount_opt;
-	uid_t s_resuid;
-	gid_t s_resgid;
+	kuid_t s_resuid;
+	kgid_t s_resgid;
 };
 
 /*
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 740cad8..f9fa95f 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1293,6 +1293,8 @@
 	struct inode *inode;
 	long ret = -EIO;
 	int n;
+	uid_t i_uid;
+	gid_t i_gid;
 
 	inode = iget_locked(sb, ino);
 	if (!inode)
@@ -1310,12 +1312,14 @@
 	}
 
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
-	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
-	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+	i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+	i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
 	if (!(test_opt (inode->i_sb, NO_UID32))) {
-		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
-		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+		i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+		i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
+	i_uid_write(inode, i_uid);
+	i_gid_write(inode, i_gid);
 	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
@@ -1413,8 +1417,8 @@
 	struct ext2_inode_info *ei = EXT2_I(inode);
 	struct super_block *sb = inode->i_sb;
 	ino_t ino = inode->i_ino;
-	uid_t uid = inode->i_uid;
-	gid_t gid = inode->i_gid;
+	uid_t uid = i_uid_read(inode);
+	gid_t gid = i_gid_read(inode);
 	struct buffer_head * bh;
 	struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh);
 	int n;
@@ -1529,8 +1533,8 @@
 
 	if (is_quota_modification(inode, iattr))
 		dquot_initialize(inode);
-	if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
-	    (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
+	if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
+	    (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
 		error = dquot_transfer(inode, iattr);
 		if (error)
 			return error;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index e1025c7..38f8160 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -228,13 +228,15 @@
 		seq_puts(seq, ",grpid");
 	if (!test_opt(sb, GRPID) && (def_mount_opts & EXT2_DEFM_BSDGROUPS))
 		seq_puts(seq, ",nogrpid");
-	if (sbi->s_resuid != EXT2_DEF_RESUID ||
+	if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT2_DEF_RESUID)) ||
 	    le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) {
-		seq_printf(seq, ",resuid=%u", sbi->s_resuid);
+		seq_printf(seq, ",resuid=%u",
+				from_kuid_munged(&init_user_ns, sbi->s_resuid));
 	}
-	if (sbi->s_resgid != EXT2_DEF_RESGID ||
+	if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT2_DEF_RESGID)) ||
 	    le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) {
-		seq_printf(seq, ",resgid=%u", sbi->s_resgid);
+		seq_printf(seq, ",resgid=%u",
+				from_kgid_munged(&init_user_ns, sbi->s_resgid));
 	}
 	if (test_opt(sb, ERRORS_RO)) {
 		int def_errors = le16_to_cpu(es->s_errors);
@@ -436,6 +438,8 @@
 	struct ext2_sb_info *sbi = EXT2_SB(sb);
 	substring_t args[MAX_OPT_ARGS];
 	int option;
+	kuid_t uid;
+	kgid_t gid;
 
 	if (!options)
 		return 1;
@@ -462,12 +466,23 @@
 		case Opt_resuid:
 			if (match_int(&args[0], &option))
 				return 0;
-			sbi->s_resuid = option;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid)) {
+				ext2_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+				return -1;
+
+			}
+			sbi->s_resuid = uid;
 			break;
 		case Opt_resgid:
 			if (match_int(&args[0], &option))
 				return 0;
-			sbi->s_resgid = option;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid)) {
+				ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+				return -1;
+			}
+			sbi->s_resgid = gid;
 			break;
 		case Opt_sb:
 			/* handled by get_sb_block() instead of here */
@@ -841,8 +856,8 @@
 	else
 		set_opt(sbi->s_mount_opt, ERRORS_RO);
 
-	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
-	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+	sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
+	sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
 	
 	set_opt(sbi->s_mount_opt, RESERVATION);
 
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index baac1b1..25cd608 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1439,8 +1439,9 @@
 	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
 	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
 	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
-		!use_reservation && sbi->s_resuid != current_fsuid() &&
-		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+		!use_reservation && !uid_eq(sbi->s_resuid, current_fsuid()) &&
+		(gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) ||
+		 !in_group_p (sbi->s_resgid))) {
 		return 0;
 	}
 	return 1;
diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h
index b6515fd..7977973 100644
--- a/fs/ext3/ext3.h
+++ b/fs/ext3/ext3.h
@@ -243,8 +243,8 @@
  */
 struct ext3_mount_options {
 	unsigned long s_mount_opt;
-	uid_t s_resuid;
-	gid_t s_resgid;
+	kuid_t s_resuid;
+	kgid_t s_resgid;
 	unsigned long s_commit_interval;
 #ifdef CONFIG_QUOTA
 	int s_jquota_fmt;
@@ -637,8 +637,8 @@
 	struct buffer_head ** s_group_desc;
 	unsigned long  s_mount_opt;
 	ext3_fsblk_t s_sb_block;
-	uid_t s_resuid;
-	gid_t s_resgid;
+	kuid_t s_resuid;
+	kgid_t s_resgid;
 	unsigned short s_mount_state;
 	unsigned short s_pad;
 	int s_addr_per_block_bits;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 10d7812..a09790a 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2891,6 +2891,8 @@
 	transaction_t *transaction;
 	long ret;
 	int block;
+	uid_t i_uid;
+	gid_t i_gid;
 
 	inode = iget_locked(sb, ino);
 	if (!inode)
@@ -2907,12 +2909,14 @@
 	bh = iloc.bh;
 	raw_inode = ext3_raw_inode(&iloc);
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
-	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
-	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+	i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+	i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
 	if(!(test_opt (inode->i_sb, NO_UID32))) {
-		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
-		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+		i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+		i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
+	i_uid_write(inode, i_uid);
+	i_gid_write(inode, i_gid);
 	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
@@ -3068,6 +3072,8 @@
 	struct ext3_inode_info *ei = EXT3_I(inode);
 	struct buffer_head *bh = iloc->bh;
 	int err = 0, rc, block;
+	uid_t i_uid;
+	gid_t i_gid;
 
 again:
 	/* we can't allow multiple procs in here at once, its a bit racey */
@@ -3080,27 +3086,29 @@
 
 	ext3_get_inode_flags(ei);
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+	i_uid = i_uid_read(inode);
+	i_gid = i_gid_read(inode);
 	if(!(test_opt(inode->i_sb, NO_UID32))) {
-		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
-		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
+		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
+		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
 		if(!ei->i_dtime) {
 			raw_inode->i_uid_high =
-				cpu_to_le16(high_16_bits(inode->i_uid));
+				cpu_to_le16(high_16_bits(i_uid));
 			raw_inode->i_gid_high =
-				cpu_to_le16(high_16_bits(inode->i_gid));
+				cpu_to_le16(high_16_bits(i_gid));
 		} else {
 			raw_inode->i_uid_high = 0;
 			raw_inode->i_gid_high = 0;
 		}
 	} else {
 		raw_inode->i_uid_low =
-			cpu_to_le16(fs_high2lowuid(inode->i_uid));
+			cpu_to_le16(fs_high2lowuid(i_uid));
 		raw_inode->i_gid_low =
-			cpu_to_le16(fs_high2lowgid(inode->i_gid));
+			cpu_to_le16(fs_high2lowgid(i_gid));
 		raw_inode->i_uid_high = 0;
 		raw_inode->i_gid_high = 0;
 	}
@@ -3262,8 +3270,8 @@
 
 	if (is_quota_modification(inode, attr))
 		dquot_initialize(inode);
-	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-		(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||
+	    (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {
 		handle_t *handle;
 
 		/* (user+group)*(old+new) structure, inode write (sb,
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index cf0b592..94ef7e6 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -617,13 +617,15 @@
 		seq_puts(seq, ",grpid");
 	if (!test_opt(sb, GRPID) && (def_mount_opts & EXT3_DEFM_BSDGROUPS))
 		seq_puts(seq, ",nogrpid");
-	if (sbi->s_resuid != EXT3_DEF_RESUID ||
+	if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT3_DEF_RESUID)) ||
 	    le16_to_cpu(es->s_def_resuid) != EXT3_DEF_RESUID) {
-		seq_printf(seq, ",resuid=%u", sbi->s_resuid);
+		seq_printf(seq, ",resuid=%u",
+				from_kuid_munged(&init_user_ns, sbi->s_resuid));
 	}
-	if (sbi->s_resgid != EXT3_DEF_RESGID ||
+	if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT3_DEF_RESGID)) ||
 	    le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) {
-		seq_printf(seq, ",resgid=%u", sbi->s_resgid);
+		seq_printf(seq, ",resgid=%u",
+				from_kgid_munged(&init_user_ns, sbi->s_resgid));
 	}
 	if (test_opt(sb, ERRORS_RO)) {
 		int def_errors = le16_to_cpu(es->s_errors);
@@ -967,6 +969,8 @@
 	substring_t args[MAX_OPT_ARGS];
 	int data_opt = 0;
 	int option;
+	kuid_t uid;
+	kgid_t gid;
 #ifdef CONFIG_QUOTA
 	int qfmt;
 #endif
@@ -1000,12 +1004,23 @@
 		case Opt_resuid:
 			if (match_int(&args[0], &option))
 				return 0;
-			sbi->s_resuid = option;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid)) {
+				ext3_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+				return -1;
+
+			}
+			sbi->s_resuid = uid;
 			break;
 		case Opt_resgid:
 			if (match_int(&args[0], &option))
 				return 0;
-			sbi->s_resgid = option;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid)) {
+				ext3_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+				return -1;
+			}
+			sbi->s_resgid = gid;
 			break;
 		case Opt_sb:
 			/* handled by get_sb_block() instead of here */
@@ -1651,8 +1666,8 @@
 	}
 	sb->s_fs_info = sbi;
 	sbi->s_mount_opt = 0;
-	sbi->s_resuid = EXT3_DEF_RESUID;
-	sbi->s_resgid = EXT3_DEF_RESGID;
+	sbi->s_resuid = make_kuid(&init_user_ns, EXT3_DEF_RESUID);
+	sbi->s_resgid = make_kgid(&init_user_ns, EXT3_DEF_RESGID);
 	sbi->s_sb_block = sb_block;
 
 	blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE);
@@ -1716,8 +1731,8 @@
 	else
 		set_opt(sbi->s_mount_opt, ERRORS_RO);
 
-	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
-	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+	sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
+	sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
 
 	/* enable barriers by default */
 	set_opt(sbi->s_mount_opt, BARRIER);
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 4bbd07a..c45c411 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -461,8 +461,8 @@
 		return 1;
 
 	/* Hm, nope.  Are (enough) root reserved clusters available? */
-	if (sbi->s_resuid == current_fsuid() ||
-	    ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) ||
+	if (uid_eq(sbi->s_resuid, current_fsuid()) ||
+	    (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) ||
 	    capable(CAP_SYS_RESOURCE) ||
 		(flags & EXT4_MB_USE_ROOT_BLOCKS)) {
 
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 0e01e90..c21b1de5 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1153,8 +1153,8 @@
 	unsigned int s_mount_flags;
 	unsigned int s_def_mount_opt;
 	ext4_fsblk_t s_sb_block;
-	uid_t s_resuid;
-	gid_t s_resgid;
+	kuid_t s_resuid;
+	kgid_t s_resgid;
 	unsigned short s_mount_state;
 	unsigned short s_pad;
 	int s_addr_per_block_bits;
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 409c2ee..9f9acac 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -808,8 +808,8 @@
 	}
 	if (owner) {
 		inode->i_mode = mode;
-		inode->i_uid = owner[0];
-		inode->i_gid = owner[1];
+		i_uid_write(inode, owner[0]);
+		i_gid_write(inode, owner[1]);
 	} else if (test_opt(sb, GRPID)) {
 		inode->i_mode = mode;
 		inode->i_uid = current_fsuid();
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c77b0bd..07eaf56 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3630,6 +3630,8 @@
 	journal_t *journal = EXT4_SB(sb)->s_journal;
 	long ret;
 	int block;
+	uid_t i_uid;
+	gid_t i_gid;
 
 	inode = iget_locked(sb, ino);
 	if (!inode)
@@ -3645,12 +3647,14 @@
 		goto bad_inode;
 	raw_inode = ext4_raw_inode(&iloc);
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
-	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
-	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+	i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+	i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
 	if (!(test_opt(inode->i_sb, NO_UID32))) {
-		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
-		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+		i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+		i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
+	i_uid_write(inode, i_uid);
+	i_gid_write(inode, i_gid);
 	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 
 	ext4_clear_state_flags(ei);	/* Only relevant on 32-bit archs */
@@ -3870,6 +3874,8 @@
 	struct ext4_inode_info *ei = EXT4_I(inode);
 	struct buffer_head *bh = iloc->bh;
 	int err = 0, rc, block;
+	uid_t i_uid;
+	gid_t i_gid;
 
 	/* For fields not not tracking in the in-memory inode,
 	 * initialise them to zero for new inodes. */
@@ -3878,27 +3884,27 @@
 
 	ext4_get_inode_flags(ei);
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+	i_uid = i_uid_read(inode);
+	i_gid = i_gid_read(inode);
 	if (!(test_opt(inode->i_sb, NO_UID32))) {
-		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
-		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
+		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
+		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
 		if (!ei->i_dtime) {
 			raw_inode->i_uid_high =
-				cpu_to_le16(high_16_bits(inode->i_uid));
+				cpu_to_le16(high_16_bits(i_uid));
 			raw_inode->i_gid_high =
-				cpu_to_le16(high_16_bits(inode->i_gid));
+				cpu_to_le16(high_16_bits(i_gid));
 		} else {
 			raw_inode->i_uid_high = 0;
 			raw_inode->i_gid_high = 0;
 		}
 	} else {
-		raw_inode->i_uid_low =
-			cpu_to_le16(fs_high2lowuid(inode->i_uid));
-		raw_inode->i_gid_low =
-			cpu_to_le16(fs_high2lowgid(inode->i_gid));
+		raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
+		raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(i_gid));
 		raw_inode->i_uid_high = 0;
 		raw_inode->i_gid_high = 0;
 	}
@@ -4084,8 +4090,8 @@
 
 	if (is_quota_modification(inode, attr))
 		dquot_initialize(inode);
-	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-		(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||
+	    (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {
 		handle_t *handle;
 
 		/* (user+group)*(old+new) structure, inode write (sb,
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index f39f80f..f1bb32e 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -466,8 +466,8 @@
 	}
 	goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) *
 		EXT4_INODES_PER_GROUP(inode->i_sb)) + 1;
-	owner[0] = inode->i_uid;
-	owner[1] = inode->i_gid;
+	owner[0] = i_uid_read(inode);
+	owner[1] = i_gid_read(inode);
 	tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode,
 				   S_IFREG, NULL, goal, owner);
 	if (IS_ERR(tmp_inode)) {
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index e1fb1d5..436b422 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1448,6 +1448,8 @@
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	const struct mount_opts *m;
+	kuid_t uid;
+	kgid_t gid;
 	int arg = 0;
 
 #ifdef CONFIG_QUOTA
@@ -1474,10 +1476,20 @@
 			 "Ignoring removed %s option", opt);
 		return 1;
 	case Opt_resuid:
-		sbi->s_resuid = arg;
+		uid = make_kuid(current_user_ns(), arg);
+		if (!uid_valid(uid)) {
+			ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
+			return -1;
+		}
+		sbi->s_resuid = uid;
 		return 1;
 	case Opt_resgid:
-		sbi->s_resgid = arg;
+		gid = make_kgid(current_user_ns(), arg);
+		if (!gid_valid(gid)) {
+			ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
+			return -1;
+		}
+		sbi->s_resgid = gid;
 		return 1;
 	case Opt_abort:
 		sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
@@ -1732,12 +1744,14 @@
 		SEQ_OPTS_PRINT("%s", token2str(m->token));
 	}
 
-	if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID ||
+	if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT4_DEF_RESUID)) ||
 	    le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID)
-		SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid);
-	if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID ||
+		SEQ_OPTS_PRINT("resuid=%u",
+				from_kuid_munged(&init_user_ns, sbi->s_resuid));
+	if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT4_DEF_RESGID)) ||
 	    le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
-		SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid);
+		SEQ_OPTS_PRINT("resgid=%u",
+				from_kgid_munged(&init_user_ns, sbi->s_resgid));
 	def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
 	if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
 		SEQ_OPTS_PUTS("errors=remount-ro");
@@ -2980,8 +2994,8 @@
 	}
 	sb->s_fs_info = sbi;
 	sbi->s_mount_opt = 0;
-	sbi->s_resuid = EXT4_DEF_RESUID;
-	sbi->s_resgid = EXT4_DEF_RESGID;
+	sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID);
+	sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID);
 	sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
 	sbi->s_sb_block = sb_block;
 	if (sb->s_bdev->bd_part)
@@ -3060,8 +3074,8 @@
 	if (def_mount_opts & EXT4_DEFM_DISCARD)
 		set_opt(sb, DISCARD);
 
-	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
-	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+	sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
+	sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
 	sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ;
 	sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
 	sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
@@ -4213,8 +4227,8 @@
 struct ext4_mount_options {
 	unsigned long s_mount_opt;
 	unsigned long s_mount_opt2;
-	uid_t s_resuid;
-	gid_t s_resgid;
+	kuid_t s_resuid;
+	kgid_t s_resgid;
 	unsigned long s_commit_interval;
 	u32 s_min_batch_time, s_max_batch_time;
 #ifdef CONFIG_QUOTA
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 75e7c1f..d078b75 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -532,9 +532,9 @@
 
 	rcu_read_lock();
 	cred = __task_cred(p);
-	ret = ((fown->euid == 0 ||
-		fown->euid == cred->suid || fown->euid == cred->uid ||
-		fown->uid  == cred->suid || fown->uid  == cred->uid) &&
+	ret = ((uid_eq(fown->euid, GLOBAL_ROOT_UID) ||
+		uid_eq(fown->euid, cred->suid) || uid_eq(fown->euid, cred->uid) ||
+		uid_eq(fown->uid,  cred->suid) || uid_eq(fown->uid,  cred->uid)) &&
 	       !security_file_send_sigiotask(p, fown, sig));
 	rcu_read_unlock();
 	return ret;
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index aa9949e..67fd6be 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -543,7 +543,6 @@
 struct lm_lockstruct {
 	int ls_jid;
 	unsigned int ls_first;
-	unsigned int ls_nodir;
 	const struct lm_lockops *ls_ops;
 	dlm_lockspace_t *ls_dlm;
 
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
index 5f5e70e..4a38db7 100644
--- a/fs/gfs2/lock_dlm.c
+++ b/fs/gfs2/lock_dlm.c
@@ -1209,8 +1209,6 @@
 	fsname++;
 
 	flags = DLM_LSFL_FS | DLM_LSFL_NEWEXCL;
-	if (ls->ls_nodir)
-		flags |= DLM_LSFL_NODIR;
 
 	/*
 	 * create/join lockspace
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index c5871ae..b8c250f 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -993,6 +993,7 @@
 				ls->ls_jid = option;
 			break;
 		case Opt_id:
+		case Opt_nodir:
 			/* Obsolete, but left for backward compat purposes */
 			break;
 		case Opt_first:
@@ -1001,12 +1002,6 @@
 				goto hostdata_error;
 			ls->ls_first = option;
 			break;
-		case Opt_nodir:
-			ret = match_int(&tmp[0], &option);
-			if (ret || (option != 0 && option != 1))
-				goto hostdata_error;
-			ls->ls_nodir = option;
-			break;
 		case Opt_err:
 		default:
 hostdata_error:
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index d33172c..9c2592b 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -368,10 +368,7 @@
 	struct gfs2_jdesc *jd;
 	int rv;
 
-	rv = -ESHUTDOWN;
 	spin_lock(&sdp->sd_jindex_spin);
-	if (test_bit(SDF_NORECOVERY, &sdp->sd_flags))
-		goto out;
 	rv = -EBUSY;
 	if (sdp->sd_jdesc->jd_jid == jid)
 		goto out;
@@ -396,8 +393,13 @@
 	if (rv != 1)
 		return -EINVAL;
 
-	rv = gfs2_recover_set(sdp, jid);
+	if (test_bit(SDF_NORECOVERY, &sdp->sd_flags)) {
+		rv = -ESHUTDOWN;
+		goto out;
+	}
 
+	rv = gfs2_recover_set(sdp, jid);
+out:
 	return rv ? rv : len;
 }
 
diff --git a/fs/inode.c b/fs/inode.c
index e3ef257..da93f7d 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -135,8 +135,8 @@
 	inode->i_fop = &empty_fops;
 	inode->__i_nlink = 1;
 	inode->i_opflags = 0;
-	inode->i_uid = 0;
-	inode->i_gid = 0;
+	i_uid_write(inode, 0);
+	i_gid_write(inode, 0);
 	atomic_set(&inode->i_writecount, 0);
 	inode->i_size = 0;
 	inode->i_blocks = 0;
@@ -1734,11 +1734,9 @@
  */
 bool inode_owner_or_capable(const struct inode *inode)
 {
-	struct user_namespace *ns = inode_userns(inode);
-
-	if (current_user_ns() == ns && current_fsuid() == inode->i_uid)
+	if (uid_eq(current_fsuid(), inode->i_uid))
 		return true;
-	if (ns_capable(ns, CAP_FOWNER))
+	if (inode_capable(inode, CAP_FOWNER))
 		return true;
 	return false;
 }
diff --git a/fs/ioprio.c b/fs/ioprio.c
index 0f1b951..5e6dbe89 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -37,8 +37,8 @@
 
 	rcu_read_lock();
 	tcred = __task_cred(task);
-	if (tcred->uid != cred->euid &&
-	    tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) {
+	if (!uid_eq(tcred->uid, cred->euid) &&
+	    !uid_eq(tcred->uid, cred->uid) && !capable(CAP_SYS_NICE)) {
 		rcu_read_unlock();
 		return -EPERM;
 	}
@@ -65,6 +65,7 @@
 	struct task_struct *p, *g;
 	struct user_struct *user;
 	struct pid *pgrp;
+	kuid_t uid;
 	int ret;
 
 	switch (class) {
@@ -110,16 +111,19 @@
 			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
 			break;
 		case IOPRIO_WHO_USER:
+			uid = make_kuid(current_user_ns(), who);
+			if (!uid_valid(uid))
+				break;
 			if (!who)
 				user = current_user();
 			else
-				user = find_user(who);
+				user = find_user(uid);
 
 			if (!user)
 				break;
 
 			do_each_thread(g, p) {
-				if (__task_cred(p)->uid != who)
+				if (!uid_eq(task_uid(p), uid))
 					continue;
 				ret = set_task_ioprio(p, ioprio);
 				if (ret)
@@ -174,6 +178,7 @@
 	struct task_struct *g, *p;
 	struct user_struct *user;
 	struct pid *pgrp;
+	kuid_t uid;
 	int ret = -ESRCH;
 	int tmpio;
 
@@ -203,16 +208,17 @@
 			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
 			break;
 		case IOPRIO_WHO_USER:
+			uid = make_kuid(current_user_ns(), who);
 			if (!who)
 				user = current_user();
 			else
-				user = find_user(who);
+				user = find_user(uid);
 
 			if (!user)
 				break;
 
 			do_each_thread(g, p) {
-				if (__task_cred(p)->uid != user->uid)
+				if (!uid_eq(task_uid(p), user->uid))
 					continue;
 				tmpio = get_task_ioprio(p);
 				if (tmpio < 0)
diff --git a/fs/locks.c b/fs/locks.c
index 0d68f1f..4f441e4 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1446,7 +1446,7 @@
 	struct inode *inode = dentry->d_inode;
 	int error;
 
-	if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
+	if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE))
 		return -EACCES;
 	if (!S_ISREG(inode->i_mode))
 		return -EINVAL;
diff --git a/fs/namei.c b/fs/namei.c
index f9e883c..e70ebab 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -218,10 +218,7 @@
 {
 	unsigned int mode = inode->i_mode;
 
-	if (current_user_ns() != inode_userns(inode))
-		goto other_perms;
-
-	if (likely(current_fsuid() == inode->i_uid))
+	if (likely(uid_eq(current_fsuid(), inode->i_uid)))
 		mode >>= 6;
 	else {
 		if (IS_POSIXACL(inode) && (mode & S_IRWXG)) {
@@ -234,7 +231,6 @@
 			mode >>= 3;
 	}
 
-other_perms:
 	/*
 	 * If the DACs are ok we don't need any capability check.
 	 */
@@ -270,10 +266,10 @@
 
 	if (S_ISDIR(inode->i_mode)) {
 		/* DACs are overridable for directories */
-		if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
+		if (inode_capable(inode, CAP_DAC_OVERRIDE))
 			return 0;
 		if (!(mask & MAY_WRITE))
-			if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
+			if (inode_capable(inode, CAP_DAC_READ_SEARCH))
 				return 0;
 		return -EACCES;
 	}
@@ -283,7 +279,7 @@
 	 * at least one exec bit set.
 	 */
 	if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO))
-		if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
+		if (inode_capable(inode, CAP_DAC_OVERRIDE))
 			return 0;
 
 	/*
@@ -291,7 +287,7 @@
 	 */
 	mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
 	if (mask == MAY_READ)
-		if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
+		if (inode_capable(inode, CAP_DAC_READ_SEARCH))
 			return 0;
 
 	return -EACCES;
@@ -1934,19 +1930,15 @@
  */
 static inline int check_sticky(struct inode *dir, struct inode *inode)
 {
-	uid_t fsuid = current_fsuid();
+	kuid_t fsuid = current_fsuid();
 
 	if (!(dir->i_mode & S_ISVTX))
 		return 0;
-	if (current_user_ns() != inode_userns(inode))
-		goto other_userns;
-	if (inode->i_uid == fsuid)
+	if (uid_eq(inode->i_uid, fsuid))
 		return 0;
-	if (dir->i_uid == fsuid)
+	if (uid_eq(dir->i_uid, fsuid))
 		return 0;
-
-other_userns:
-	return !ns_capable(inode_userns(inode), CAP_FOWNER);
+	return !inode_capable(inode, CAP_FOWNER);
 }
 
 /*
@@ -2534,8 +2526,7 @@
 	if (error)
 		return error;
 
-	if ((S_ISCHR(mode) || S_ISBLK(mode)) &&
-	    !ns_capable(inode_userns(dir), CAP_MKNOD))
+	if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
 		return -EPERM;
 
 	if (!dir->i_op->mknod)
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 79717a4..204438c 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -1,6 +1,7 @@
 /* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */
 
 #include <linux/sched.h>
+#include <linux/user_namespace.h>
 #include "nfsd.h"
 #include "auth.h"
 
@@ -56,8 +57,8 @@
 			goto oom;
 
 		for (i = 0; i < rqgi->ngroups; i++) {
-			if (!GROUP_AT(rqgi, i))
-				GROUP_AT(gi, i) = exp->ex_anon_gid;
+			if (gid_eq(GLOBAL_ROOT_GID, GROUP_AT(rqgi, i)))
+				GROUP_AT(gi, i) = make_kgid(&init_user_ns, exp->ex_anon_gid);
 			else
 				GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
 		}
diff --git a/fs/open.c b/fs/open.c
index 5eccdce..d543012 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -316,7 +316,8 @@
 
 	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 		/* Clear the capabilities if we switch to a non-root user */
-		if (override_cred->uid)
+		kuid_t root_uid = make_kuid(override_cred->user_ns, 0);
+		if (!uid_eq(override_cred->uid, root_uid))
 			cap_clear(override_cred->cap_effective);
 		else
 			override_cred->cap_effective =
@@ -505,15 +506,24 @@
 	struct inode *inode = path->dentry->d_inode;
 	int error;
 	struct iattr newattrs;
+	kuid_t uid;
+	kgid_t gid;
+
+	uid = make_kuid(current_user_ns(), user);
+	gid = make_kgid(current_user_ns(), group);
 
 	newattrs.ia_valid =  ATTR_CTIME;
 	if (user != (uid_t) -1) {
+		if (!uid_valid(uid))
+			return -EINVAL;
 		newattrs.ia_valid |= ATTR_UID;
-		newattrs.ia_uid = user;
+		newattrs.ia_uid = uid;
 	}
 	if (group != (gid_t) -1) {
+		if (!gid_valid(gid))
+			return -EINVAL;
 		newattrs.ia_valid |= ATTR_GID;
-		newattrs.ia_gid = group;
+		newattrs.ia_gid = gid;
 	}
 	if (!S_ISDIR(inode->i_mode))
 		newattrs.ia_valid |=
diff --git a/fs/proc/array.c b/fs/proc/array.c
index f9bd395..dc4c5a7 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -81,6 +81,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/ptrace.h>
 #include <linux/tracehook.h>
+#include <linux/user_namespace.h>
 
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -161,6 +162,7 @@
 static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
 				struct pid *pid, struct task_struct *p)
 {
+	struct user_namespace *user_ns = current_user_ns();
 	struct group_info *group_info;
 	int g;
 	struct fdtable *fdt = NULL;
@@ -189,8 +191,14 @@
 		task_tgid_nr_ns(p, ns),
 		pid_nr_ns(pid, ns),
 		ppid, tpid,
-		cred->uid, cred->euid, cred->suid, cred->fsuid,
-		cred->gid, cred->egid, cred->sgid, cred->fsgid);
+		from_kuid_munged(user_ns, cred->uid),
+		from_kuid_munged(user_ns, cred->euid),
+		from_kuid_munged(user_ns, cred->suid),
+		from_kuid_munged(user_ns, cred->fsuid),
+		from_kgid_munged(user_ns, cred->gid),
+		from_kgid_munged(user_ns, cred->egid),
+		from_kgid_munged(user_ns, cred->sgid),
+		from_kgid_munged(user_ns, cred->fsgid));
 
 	task_lock(p);
 	if (p->files)
@@ -205,7 +213,8 @@
 	task_unlock(p);
 
 	for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++)
-		seq_printf(m, "%d ", GROUP_AT(group_info, g));
+		seq_printf(m, "%d ",
+			   from_kgid_munged(user_ns, GROUP_AT(group_info, g)));
 	put_cred(cred);
 
 	seq_putc(m, '\n');
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 57b8159..d2d3108 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -81,6 +81,7 @@
 #include <linux/oom.h>
 #include <linux/elf.h>
 #include <linux/pid_namespace.h>
+#include <linux/user_namespace.h>
 #include <linux/fs_struct.h>
 #include <linux/slab.h>
 #include <linux/flex_array.h>
@@ -1561,8 +1562,8 @@
 	generic_fillattr(inode, stat);
 
 	rcu_read_lock();
-	stat->uid = 0;
-	stat->gid = 0;
+	stat->uid = GLOBAL_ROOT_UID;
+	stat->gid = GLOBAL_ROOT_GID;
 	task = pid_task(proc_pid(inode), PIDTYPE_PID);
 	if (task) {
 		if (!has_pid_permissions(pid, task, 2)) {
@@ -1622,8 +1623,8 @@
 			inode->i_gid = cred->egid;
 			rcu_read_unlock();
 		} else {
-			inode->i_uid = 0;
-			inode->i_gid = 0;
+			inode->i_uid = GLOBAL_ROOT_UID;
+			inode->i_gid = GLOBAL_ROOT_GID;
 		}
 		inode->i_mode &= ~(S_ISUID | S_ISGID);
 		security_task_to_inode(task, inode);
@@ -1815,8 +1816,8 @@
 					inode->i_gid = cred->egid;
 					rcu_read_unlock();
 				} else {
-					inode->i_uid = 0;
-					inode->i_gid = 0;
+					inode->i_uid = GLOBAL_ROOT_UID;
+					inode->i_gid = GLOBAL_ROOT_GID;
 				}
 
 				i_mode = S_IFLNK;
@@ -2045,8 +2046,8 @@
 			inode->i_gid = cred->egid;
 			rcu_read_unlock();
 		} else {
-			inode->i_uid = 0;
-			inode->i_gid = 0;
+			inode->i_uid = GLOBAL_ROOT_UID;
+			inode->i_gid = GLOBAL_ROOT_GID;
 		}
 		security_task_to_inode(task, inode);
 		status = 1;
@@ -2924,6 +2925,74 @@
 }
 #endif /* CONFIG_TASK_IO_ACCOUNTING */
 
+#ifdef CONFIG_USER_NS
+static int proc_id_map_open(struct inode *inode, struct file *file,
+	struct seq_operations *seq_ops)
+{
+	struct user_namespace *ns = NULL;
+	struct task_struct *task;
+	struct seq_file *seq;
+	int ret = -EINVAL;
+
+	task = get_proc_task(inode);
+	if (task) {
+		rcu_read_lock();
+		ns = get_user_ns(task_cred_xxx(task, user_ns));
+		rcu_read_unlock();
+		put_task_struct(task);
+	}
+	if (!ns)
+		goto err;
+
+	ret = seq_open(file, seq_ops);
+	if (ret)
+		goto err_put_ns;
+
+	seq = file->private_data;
+	seq->private = ns;
+
+	return 0;
+err_put_ns:
+	put_user_ns(ns);
+err:
+	return ret;
+}
+
+static int proc_id_map_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct user_namespace *ns = seq->private;
+	put_user_ns(ns);
+	return seq_release(inode, file);
+}
+
+static int proc_uid_map_open(struct inode *inode, struct file *file)
+{
+	return proc_id_map_open(inode, file, &proc_uid_seq_operations);
+}
+
+static int proc_gid_map_open(struct inode *inode, struct file *file)
+{
+	return proc_id_map_open(inode, file, &proc_gid_seq_operations);
+}
+
+static const struct file_operations proc_uid_map_operations = {
+	.open		= proc_uid_map_open,
+	.write		= proc_uid_map_write,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= proc_id_map_release,
+};
+
+static const struct file_operations proc_gid_map_operations = {
+	.open		= proc_gid_map_open,
+	.write		= proc_gid_map_write,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= proc_id_map_release,
+};
+#endif /* CONFIG_USER_NS */
+
 static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
 				struct pid *pid, struct task_struct *task)
 {
@@ -3026,6 +3095,10 @@
 #ifdef CONFIG_HARDWALL
 	INF("hardwall",   S_IRUGO, proc_pid_hardwall),
 #endif
+#ifdef CONFIG_USER_NS
+	REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
+	REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
+#endif
 };
 
 static int proc_tgid_base_readdir(struct file * filp,
@@ -3381,6 +3454,10 @@
 #ifdef CONFIG_HARDWALL
 	INF("hardwall",   S_IRUGO, proc_pid_hardwall),
 #endif
+#ifdef CONFIG_USER_NS
+	REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
+	REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
+#endif
 };
 
 static int proc_tid_base_readdir(struct file * filp,
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 205c922..554ecc5 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -108,8 +108,8 @@
 	struct super_block *sb = root->d_sb;
 	struct pid_namespace *pid = sb->s_fs_info;
 
-	if (pid->pid_gid)
-		seq_printf(seq, ",gid=%lu", (unsigned long)pid->pid_gid);
+	if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID))
+		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid));
 	if (pid->hide_pid != 0)
 		seq_printf(seq, ",hidepid=%u", pid->hide_pid);
 
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 21d836f..3476bca 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -371,9 +371,9 @@
 
 static int test_perm(int mode, int op)
 {
-	if (!current_euid())
+	if (uid_eq(current_euid(), GLOBAL_ROOT_UID))
 		mode >>= 6;
-	else if (in_egroup_p(0))
+	else if (in_egroup_p(GLOBAL_ROOT_GID))
 		mode >>= 3;
 	if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
 		return 0;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index eed44bf..7c30fce 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -67,7 +67,7 @@
 		case Opt_gid:
 			if (match_int(&args[0], &option))
 				return 0;
-			pid->pid_gid = option;
+			pid->pid_gid = make_kgid(current_user_ns(), option);
 			break;
 		case Opt_hidepid:
 			if (match_int(&args[0], &option))
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 8007ae7..23ade26 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -11,3 +11,20 @@
 	   (e.g. ACPI_APEI on X86) which will select this for you.
 	   If you don't have a platform persistent store driver,
 	   say N.
+
+config PSTORE_RAM
+	tristate "Log panic/oops to a RAM buffer"
+	depends on PSTORE
+	depends on HAS_IOMEM
+	depends on HAVE_MEMBLOCK
+	select REED_SOLOMON
+	select REED_SOLOMON_ENC8
+	select REED_SOLOMON_DEC8
+	help
+	  This enables panic and oops messages to be logged to a circular
+	  buffer in RAM where it can be read back at some later point.
+
+	  Note that for historical reasons, the module will be named
+	  "ramoops.ko".
+
+	  For more information, see Documentation/ramoops.txt.
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index 760f4bc..278a44e 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -5,3 +5,6 @@
 obj-y += pstore.o
 
 pstore-objs += inode.o platform.o
+
+ramoops-objs += ram.o ram_core.o
+obj-$(CONFIG_PSTORE_RAM)	+= ramoops.o
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
new file mode 100644
index 0000000..9123cce
--- /dev/null
+++ b/fs/pstore/ram.c
@@ -0,0 +1,383 @@
+/*
+ * RAM Oops/Panic logger
+ *
+ * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ * Copyright (C) 2011 Kees Cook <keescook@chromium.org>
+ *
+ * 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
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/pstore.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pstore_ram.h>
+
+#define RAMOOPS_KERNMSG_HDR "===="
+#define MIN_MEM_SIZE 4096UL
+
+static ulong record_size = MIN_MEM_SIZE;
+module_param(record_size, ulong, 0400);
+MODULE_PARM_DESC(record_size,
+		"size of each dump done on oops/panic");
+
+static ulong mem_address;
+module_param(mem_address, ulong, 0400);
+MODULE_PARM_DESC(mem_address,
+		"start of reserved RAM used to store oops/panic logs");
+
+static ulong mem_size;
+module_param(mem_size, ulong, 0400);
+MODULE_PARM_DESC(mem_size,
+		"size of reserved RAM used to store oops/panic logs");
+
+static int dump_oops = 1;
+module_param(dump_oops, int, 0600);
+MODULE_PARM_DESC(dump_oops,
+		"set to 1 to dump oopses, 0 to only dump panics (default 1)");
+
+static int ramoops_ecc;
+module_param_named(ecc, ramoops_ecc, int, 0600);
+MODULE_PARM_DESC(ramoops_ecc,
+		"set to 1 to enable ECC support");
+
+struct ramoops_context {
+	struct persistent_ram_zone **przs;
+	phys_addr_t phys_addr;
+	unsigned long size;
+	size_t record_size;
+	int dump_oops;
+	bool ecc;
+	unsigned int count;
+	unsigned int max_count;
+	unsigned int read_count;
+	struct pstore_info pstore;
+};
+
+static struct platform_device *dummy;
+static struct ramoops_platform_data *dummy_data;
+
+static int ramoops_pstore_open(struct pstore_info *psi)
+{
+	struct ramoops_context *cxt = psi->data;
+
+	cxt->read_count = 0;
+	return 0;
+}
+
+static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
+				   struct timespec *time,
+				   char **buf,
+				   struct pstore_info *psi)
+{
+	ssize_t size;
+	struct ramoops_context *cxt = psi->data;
+	struct persistent_ram_zone *prz;
+
+	if (cxt->read_count >= cxt->max_count)
+		return -EINVAL;
+
+	*id = cxt->read_count++;
+	prz = cxt->przs[*id];
+
+	/* Only supports dmesg output so far. */
+	*type = PSTORE_TYPE_DMESG;
+	/* TODO(kees): Bogus time for the moment. */
+	time->tv_sec = 0;
+	time->tv_nsec = 0;
+
+	size = persistent_ram_old_size(prz);
+	*buf = kmalloc(size, GFP_KERNEL);
+	if (*buf == NULL)
+		return -ENOMEM;
+	memcpy(*buf, persistent_ram_old(prz), size);
+
+	return size;
+}
+
+static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
+{
+	char *hdr;
+	struct timeval timestamp;
+	size_t len;
+
+	do_gettimeofday(&timestamp);
+	hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
+		(long)timestamp.tv_sec, (long)timestamp.tv_usec);
+	WARN_ON_ONCE(!hdr);
+	len = hdr ? strlen(hdr) : 0;
+	persistent_ram_write(prz, hdr, len);
+	kfree(hdr);
+
+	return len;
+}
+
+static int ramoops_pstore_write(enum pstore_type_id type,
+				enum kmsg_dump_reason reason,
+				u64 *id,
+				unsigned int part,
+				size_t size, struct pstore_info *psi)
+{
+	struct ramoops_context *cxt = psi->data;
+	struct persistent_ram_zone *prz = cxt->przs[cxt->count];
+	size_t hlen;
+
+	/* Currently ramoops is designed to only store dmesg dumps. */
+	if (type != PSTORE_TYPE_DMESG)
+		return -EINVAL;
+
+	/* Out of the various dmesg dump types, ramoops is currently designed
+	 * to only store crash logs, rather than storing general kernel logs.
+	 */
+	if (reason != KMSG_DUMP_OOPS &&
+	    reason != KMSG_DUMP_PANIC)
+		return -EINVAL;
+
+	/* Skip Oopes when configured to do so. */
+	if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
+		return -EINVAL;
+
+	/* Explicitly only take the first part of any new crash.
+	 * If our buffer is larger than kmsg_bytes, this can never happen,
+	 * and if our buffer is smaller than kmsg_bytes, we don't want the
+	 * report split across multiple records.
+	 */
+	if (part != 1)
+		return -ENOSPC;
+
+	hlen = ramoops_write_kmsg_hdr(prz);
+	if (size + hlen > prz->buffer_size)
+		size = prz->buffer_size - hlen;
+	persistent_ram_write(prz, cxt->pstore.buf, size);
+
+	cxt->count = (cxt->count + 1) % cxt->max_count;
+
+	return 0;
+}
+
+static int ramoops_pstore_erase(enum pstore_type_id type, u64 id,
+				struct pstore_info *psi)
+{
+	struct ramoops_context *cxt = psi->data;
+
+	if (id >= cxt->max_count)
+		return -EINVAL;
+
+	persistent_ram_free_old(cxt->przs[id]);
+
+	return 0;
+}
+
+static struct ramoops_context oops_cxt = {
+	.pstore = {
+		.owner	= THIS_MODULE,
+		.name	= "ramoops",
+		.open	= ramoops_pstore_open,
+		.read	= ramoops_pstore_read,
+		.write	= ramoops_pstore_write,
+		.erase	= ramoops_pstore_erase,
+	},
+};
+
+static int __init ramoops_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ramoops_platform_data *pdata = pdev->dev.platform_data;
+	struct ramoops_context *cxt = &oops_cxt;
+	int err = -EINVAL;
+	int i;
+
+	/* Only a single ramoops area allowed at a time, so fail extra
+	 * probes.
+	 */
+	if (cxt->max_count)
+		goto fail_out;
+
+	if (!pdata->mem_size || !pdata->record_size) {
+		pr_err("The memory size and the record size must be "
+			"non-zero\n");
+		goto fail_out;
+	}
+
+	pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
+	pdata->record_size = rounddown_pow_of_two(pdata->record_size);
+
+	/* Check for the minimum memory size */
+	if (pdata->mem_size < MIN_MEM_SIZE &&
+			pdata->record_size < MIN_MEM_SIZE) {
+		pr_err("memory size too small, minimum is %lu\n",
+			MIN_MEM_SIZE);
+		goto fail_out;
+	}
+
+	if (pdata->mem_size < pdata->record_size) {
+		pr_err("The memory size must be larger than the "
+			"records size\n");
+		goto fail_out;
+	}
+
+	cxt->max_count = pdata->mem_size / pdata->record_size;
+	cxt->count = 0;
+	cxt->size = pdata->mem_size;
+	cxt->phys_addr = pdata->mem_address;
+	cxt->record_size = pdata->record_size;
+	cxt->dump_oops = pdata->dump_oops;
+	cxt->ecc = pdata->ecc;
+
+	cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_count, GFP_KERNEL);
+	if (!cxt->przs) {
+		err = -ENOMEM;
+		dev_err(dev, "failed to initialize a prz array\n");
+		goto fail_out;
+	}
+
+	for (i = 0; i < cxt->max_count; i++) {
+		size_t sz = cxt->record_size;
+		phys_addr_t start = cxt->phys_addr + sz * i;
+
+		cxt->przs[i] = persistent_ram_new(start, sz, cxt->ecc);
+		if (IS_ERR(cxt->przs[i])) {
+			err = PTR_ERR(cxt->przs[i]);
+			dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
+				sz, (unsigned long long)start, err);
+			goto fail_przs;
+		}
+	}
+
+	cxt->pstore.data = cxt;
+	cxt->pstore.bufsize = cxt->przs[0]->buffer_size;
+	cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
+	spin_lock_init(&cxt->pstore.buf_lock);
+	if (!cxt->pstore.buf) {
+		pr_err("cannot allocate pstore buffer\n");
+		goto fail_clear;
+	}
+
+	err = pstore_register(&cxt->pstore);
+	if (err) {
+		pr_err("registering with pstore failed\n");
+		goto fail_buf;
+	}
+
+	/*
+	 * Update the module parameter variables as well so they are visible
+	 * through /sys/module/ramoops/parameters/
+	 */
+	mem_size = pdata->mem_size;
+	mem_address = pdata->mem_address;
+	record_size = pdata->record_size;
+	dump_oops = pdata->dump_oops;
+
+	pr_info("attached 0x%lx@0x%llx (%ux0x%zx), ecc: %s\n",
+		cxt->size, (unsigned long long)cxt->phys_addr,
+		cxt->max_count, cxt->record_size,
+		ramoops_ecc ? "on" : "off");
+
+	return 0;
+
+fail_buf:
+	kfree(cxt->pstore.buf);
+fail_clear:
+	cxt->pstore.bufsize = 0;
+	cxt->max_count = 0;
+fail_przs:
+	for (i = 0; cxt->przs[i]; i++)
+		persistent_ram_free(cxt->przs[i]);
+	kfree(cxt->przs);
+fail_out:
+	return err;
+}
+
+static int __exit ramoops_remove(struct platform_device *pdev)
+{
+#if 0
+	/* TODO(kees): We cannot unload ramoops since pstore doesn't support
+	 * unregistering yet.
+	 */
+	struct ramoops_context *cxt = &oops_cxt;
+
+	iounmap(cxt->virt_addr);
+	release_mem_region(cxt->phys_addr, cxt->size);
+	cxt->max_count = 0;
+
+	/* TODO(kees): When pstore supports unregistering, call it here. */
+	kfree(cxt->pstore.buf);
+	cxt->pstore.bufsize = 0;
+
+	return 0;
+#endif
+	return -EBUSY;
+}
+
+static struct platform_driver ramoops_driver = {
+	.remove		= __exit_p(ramoops_remove),
+	.driver		= {
+		.name	= "ramoops",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ramoops_init(void)
+{
+	int ret;
+	ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
+	if (ret == -ENODEV) {
+		/*
+		 * If we didn't find a platform device, we use module parameters
+		 * building platform data on the fly.
+		 */
+		pr_info("platform device not found, using module parameters\n");
+		dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
+				     GFP_KERNEL);
+		if (!dummy_data)
+			return -ENOMEM;
+		dummy_data->mem_size = mem_size;
+		dummy_data->mem_address = mem_address;
+		dummy_data->record_size = record_size;
+		dummy_data->dump_oops = dump_oops;
+		dummy_data->ecc = ramoops_ecc;
+		dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
+			NULL, 0, dummy_data,
+			sizeof(struct ramoops_platform_data));
+
+		if (IS_ERR(dummy))
+			ret = PTR_ERR(dummy);
+		else
+			ret = 0;
+	}
+
+	return ret;
+}
+
+static void __exit ramoops_exit(void)
+{
+	platform_driver_unregister(&ramoops_driver);
+	kfree(dummy_data);
+}
+
+module_init(ramoops_init);
+module_exit(ramoops_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
+MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
new file mode 100644
index 0000000..31f8d18
--- /dev/null
+++ b/fs/pstore/ram_core.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/rslib.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/pstore_ram.h>
+#include <asm/page.h>
+
+struct persistent_ram_buffer {
+	uint32_t    sig;
+	atomic_t    start;
+	atomic_t    size;
+	uint8_t     data[0];
+};
+
+#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
+
+static __initdata LIST_HEAD(persistent_ram_list);
+
+static inline size_t buffer_size(struct persistent_ram_zone *prz)
+{
+	return atomic_read(&prz->buffer->size);
+}
+
+static inline size_t buffer_start(struct persistent_ram_zone *prz)
+{
+	return atomic_read(&prz->buffer->start);
+}
+
+/* increase and wrap the start pointer, returning the old value */
+static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
+{
+	int old;
+	int new;
+
+	do {
+		old = atomic_read(&prz->buffer->start);
+		new = old + a;
+		while (unlikely(new > prz->buffer_size))
+			new -= prz->buffer_size;
+	} while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
+
+	return old;
+}
+
+/* increase the size counter until it hits the max size */
+static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
+{
+	size_t old;
+	size_t new;
+
+	if (atomic_read(&prz->buffer->size) == prz->buffer_size)
+		return;
+
+	do {
+		old = atomic_read(&prz->buffer->size);
+		new = old + a;
+		if (new > prz->buffer_size)
+			new = prz->buffer_size;
+	} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
+}
+
+static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
+	uint8_t *data, size_t len, uint8_t *ecc)
+{
+	int i;
+	uint16_t par[prz->ecc_size];
+
+	/* Initialize the parity buffer */
+	memset(par, 0, sizeof(par));
+	encode_rs8(prz->rs_decoder, data, len, par, 0);
+	for (i = 0; i < prz->ecc_size; i++)
+		ecc[i] = par[i];
+}
+
+static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
+	void *data, size_t len, uint8_t *ecc)
+{
+	int i;
+	uint16_t par[prz->ecc_size];
+
+	for (i = 0; i < prz->ecc_size; i++)
+		par[i] = ecc[i];
+	return decode_rs8(prz->rs_decoder, data, par, len,
+				NULL, 0, NULL, 0, NULL);
+}
+
+static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
+	unsigned int start, unsigned int count)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	uint8_t *buffer_end = buffer->data + prz->buffer_size;
+	uint8_t *block;
+	uint8_t *par;
+	int ecc_block_size = prz->ecc_block_size;
+	int ecc_size = prz->ecc_size;
+	int size = prz->ecc_block_size;
+
+	if (!prz->ecc)
+		return;
+
+	block = buffer->data + (start & ~(ecc_block_size - 1));
+	par = prz->par_buffer + (start / ecc_block_size) * prz->ecc_size;
+
+	do {
+		if (block + ecc_block_size > buffer_end)
+			size = buffer_end - block;
+		persistent_ram_encode_rs8(prz, block, size, par);
+		block += ecc_block_size;
+		par += ecc_size;
+	} while (block < buffer->data + start + count);
+}
+
+static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+
+	if (!prz->ecc)
+		return;
+
+	persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
+				  prz->par_header);
+}
+
+static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	uint8_t *block;
+	uint8_t *par;
+
+	if (!prz->ecc)
+		return;
+
+	block = buffer->data;
+	par = prz->par_buffer;
+	while (block < buffer->data + buffer_size(prz)) {
+		int numerr;
+		int size = prz->ecc_block_size;
+		if (block + size > buffer->data + prz->buffer_size)
+			size = buffer->data + prz->buffer_size - block;
+		numerr = persistent_ram_decode_rs8(prz, block, size, par);
+		if (numerr > 0) {
+			pr_devel("persistent_ram: error in block %p, %d\n",
+			       block, numerr);
+			prz->corrected_bytes += numerr;
+		} else if (numerr < 0) {
+			pr_devel("persistent_ram: uncorrectable error in block %p\n",
+				block);
+			prz->bad_blocks++;
+		}
+		block += prz->ecc_block_size;
+		par += prz->ecc_size;
+	}
+}
+
+static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
+	size_t buffer_size)
+{
+	int numerr;
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	int ecc_blocks;
+
+	if (!prz->ecc)
+		return 0;
+
+	prz->ecc_block_size = 128;
+	prz->ecc_size = 16;
+	prz->ecc_symsize = 8;
+	prz->ecc_poly = 0x11d;
+
+	ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
+	prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
+
+	if (prz->buffer_size > buffer_size) {
+		pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
+		       buffer_size, prz->buffer_size);
+		return -EINVAL;
+	}
+
+	prz->par_buffer = buffer->data + prz->buffer_size;
+	prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
+
+	/*
+	 * first consecutive root is 0
+	 * primitive element to generate roots = 1
+	 */
+	prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
+				  prz->ecc_size);
+	if (prz->rs_decoder == NULL) {
+		pr_info("persistent_ram: init_rs failed\n");
+		return -EINVAL;
+	}
+
+	prz->corrected_bytes = 0;
+	prz->bad_blocks = 0;
+
+	numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
+					   prz->par_header);
+	if (numerr > 0) {
+		pr_info("persistent_ram: error in header, %d\n", numerr);
+		prz->corrected_bytes += numerr;
+	} else if (numerr < 0) {
+		pr_info("persistent_ram: uncorrectable error in header\n");
+		prz->bad_blocks++;
+	}
+
+	return 0;
+}
+
+ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+	char *str, size_t len)
+{
+	ssize_t ret;
+
+	if (prz->corrected_bytes || prz->bad_blocks)
+		ret = snprintf(str, len, ""
+			"\n%d Corrected bytes, %d unrecoverable blocks\n",
+			prz->corrected_bytes, prz->bad_blocks);
+	else
+		ret = snprintf(str, len, "\nNo errors detected\n");
+
+	return ret;
+}
+
+static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
+	const void *s, unsigned int start, unsigned int count)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	memcpy(buffer->data + start, s, count);
+	persistent_ram_update_ecc(prz, start, count);
+}
+
+static void __init
+persistent_ram_save_old(struct persistent_ram_zone *prz)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	size_t size = buffer_size(prz);
+	size_t start = buffer_start(prz);
+	char *dest;
+
+	persistent_ram_ecc_old(prz);
+
+	dest = kmalloc(size, GFP_KERNEL);
+	if (dest == NULL) {
+		pr_err("persistent_ram: failed to allocate buffer\n");
+		return;
+	}
+
+	prz->old_log = dest;
+	prz->old_log_size = size;
+	memcpy(prz->old_log, &buffer->data[start], size - start);
+	memcpy(prz->old_log + size - start, &buffer->data[0], start);
+}
+
+int notrace persistent_ram_write(struct persistent_ram_zone *prz,
+	const void *s, unsigned int count)
+{
+	int rem;
+	int c = count;
+	size_t start;
+
+	if (unlikely(c > prz->buffer_size)) {
+		s += c - prz->buffer_size;
+		c = prz->buffer_size;
+	}
+
+	buffer_size_add(prz, c);
+
+	start = buffer_start_add(prz, c);
+
+	rem = prz->buffer_size - start;
+	if (unlikely(rem < c)) {
+		persistent_ram_update(prz, s, start, rem);
+		s += rem;
+		c -= rem;
+		start = 0;
+	}
+	persistent_ram_update(prz, s, start, c);
+
+	persistent_ram_update_header_ecc(prz);
+
+	return count;
+}
+
+size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
+{
+	return prz->old_log_size;
+}
+
+void *persistent_ram_old(struct persistent_ram_zone *prz)
+{
+	return prz->old_log;
+}
+
+void persistent_ram_free_old(struct persistent_ram_zone *prz)
+{
+	kfree(prz->old_log);
+	prz->old_log = NULL;
+	prz->old_log_size = 0;
+}
+
+static void *persistent_ram_vmap(phys_addr_t start, size_t size)
+{
+	struct page **pages;
+	phys_addr_t page_start;
+	unsigned int page_count;
+	pgprot_t prot;
+	unsigned int i;
+	void *vaddr;
+
+	page_start = start - offset_in_page(start);
+	page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
+
+	prot = pgprot_noncached(PAGE_KERNEL);
+
+	pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
+	if (!pages) {
+		pr_err("%s: Failed to allocate array for %u pages\n", __func__,
+			page_count);
+		return NULL;
+	}
+
+	for (i = 0; i < page_count; i++) {
+		phys_addr_t addr = page_start + i * PAGE_SIZE;
+		pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
+	}
+	vaddr = vmap(pages, page_count, VM_MAP, prot);
+	kfree(pages);
+
+	return vaddr;
+}
+
+static void *persistent_ram_iomap(phys_addr_t start, size_t size)
+{
+	if (!request_mem_region(start, size, "persistent_ram")) {
+		pr_err("request mem region (0x%llx@0x%llx) failed\n",
+			(unsigned long long)size, (unsigned long long)start);
+		return NULL;
+	}
+
+	return ioremap(start, size);
+}
+
+static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
+		struct persistent_ram_zone *prz)
+{
+	prz->paddr = start;
+	prz->size = size;
+
+	if (pfn_valid(start >> PAGE_SHIFT))
+		prz->vaddr = persistent_ram_vmap(start, size);
+	else
+		prz->vaddr = persistent_ram_iomap(start, size);
+
+	if (!prz->vaddr) {
+		pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__,
+			(unsigned long long)size, (unsigned long long)start);
+		return -ENOMEM;
+	}
+
+	prz->buffer = prz->vaddr + offset_in_page(start);
+	prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
+
+	return 0;
+}
+
+static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool ecc)
+{
+	int ret;
+
+	prz->ecc = ecc;
+
+	ret = persistent_ram_init_ecc(prz, prz->buffer_size);
+	if (ret)
+		return ret;
+
+	if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
+		if (buffer_size(prz) > prz->buffer_size ||
+		    buffer_start(prz) > buffer_size(prz))
+			pr_info("persistent_ram: found existing invalid buffer,"
+				" size %zu, start %zu\n",
+			       buffer_size(prz), buffer_start(prz));
+		else {
+			pr_info("persistent_ram: found existing buffer,"
+				" size %zu, start %zu\n",
+			       buffer_size(prz), buffer_start(prz));
+			persistent_ram_save_old(prz);
+		}
+	} else {
+		pr_info("persistent_ram: no valid data in buffer"
+			" (sig = 0x%08x)\n", prz->buffer->sig);
+	}
+
+	prz->buffer->sig = PERSISTENT_RAM_SIG;
+	atomic_set(&prz->buffer->start, 0);
+	atomic_set(&prz->buffer->size, 0);
+
+	return 0;
+}
+
+void persistent_ram_free(struct persistent_ram_zone *prz)
+{
+	if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
+		vunmap(prz->vaddr);
+	} else {
+		iounmap(prz->vaddr);
+		release_mem_region(prz->paddr, prz->size);
+	}
+	persistent_ram_free_old(prz);
+	kfree(prz);
+}
+
+struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
+						       size_t size,
+						       bool ecc)
+{
+	struct persistent_ram_zone *prz;
+	int ret = -ENOMEM;
+
+	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
+	if (!prz) {
+		pr_err("persistent_ram: failed to allocate persistent ram zone\n");
+		goto err;
+	}
+
+	ret = persistent_ram_buffer_map(start, size, prz);
+	if (ret)
+		goto err;
+
+	persistent_ram_post_init(prz, ecc);
+	persistent_ram_update_header_ecc(prz);
+
+	return prz;
+err:
+	kfree(prz);
+	return ERR_PTR(ret);
+}
+
+#ifndef MODULE
+static int __init persistent_ram_buffer_init(const char *name,
+		struct persistent_ram_zone *prz)
+{
+	int i;
+	struct persistent_ram *ram;
+	struct persistent_ram_descriptor *desc;
+	phys_addr_t start;
+
+	list_for_each_entry(ram, &persistent_ram_list, node) {
+		start = ram->start;
+		for (i = 0; i < ram->num_descs; i++) {
+			desc = &ram->descs[i];
+			if (!strcmp(desc->name, name))
+				return persistent_ram_buffer_map(start,
+						desc->size, prz);
+			start += desc->size;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static  __init
+struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
+{
+	struct persistent_ram_zone *prz;
+	int ret = -ENOMEM;
+
+	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
+	if (!prz) {
+		pr_err("persistent_ram: failed to allocate persistent ram zone\n");
+		goto err;
+	}
+
+	ret = persistent_ram_buffer_init(dev_name(dev), prz);
+	if (ret) {
+		pr_err("persistent_ram: failed to initialize buffer\n");
+		goto err;
+	}
+
+	persistent_ram_post_init(prz, ecc);
+
+	return prz;
+err:
+	kfree(prz);
+	return ERR_PTR(ret);
+}
+
+struct persistent_ram_zone * __init
+persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
+{
+	return __persistent_ram_init(dev, ecc);
+}
+
+int __init persistent_ram_early_init(struct persistent_ram *ram)
+{
+	int ret;
+
+	ret = memblock_reserve(ram->start, ram->size);
+	if (ret) {
+		pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
+			(long)ram->start, (long)(ram->start + ram->size - 1));
+		return ret;
+	}
+
+	list_add_tail(&ram->node, &persistent_ram_list);
+
+	pr_info("Initialized persistent memory from %08lx-%08lx\n",
+		(long)ram->start, (long)(ram->start + ram->size - 1));
+
+	return 0;
+}
+#endif
diff --git a/fs/stat.c b/fs/stat.c
index 0cef336..b6ff118 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -138,8 +138,8 @@
 	tmp.st_nlink = stat->nlink;
 	if (tmp.st_nlink != stat->nlink)
 		return -EOVERFLOW;
-	SET_UID(tmp.st_uid, stat->uid);
-	SET_GID(tmp.st_gid, stat->gid);
+	SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
+	SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
 	tmp.st_rdev = old_encode_dev(stat->rdev);
 #if BITS_PER_LONG == 32
 	if (stat->size > MAX_NON_LFS)
@@ -224,8 +224,8 @@
 	tmp.st_nlink = stat->nlink;
 	if (tmp.st_nlink != stat->nlink)
 		return -EOVERFLOW;
-	SET_UID(tmp.st_uid, stat->uid);
-	SET_GID(tmp.st_gid, stat->gid);
+	SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
+	SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
 	tmp.st_rdev = encode_dev(stat->rdev);
 	tmp.st_size = stat->size;
 	tmp.st_atime = stat->atime.tv_sec;
@@ -355,8 +355,8 @@
 #endif
 	tmp.st_mode = stat->mode;
 	tmp.st_nlink = stat->nlink;
-	tmp.st_uid = stat->uid;
-	tmp.st_gid = stat->gid;
+	tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
+	tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
 	tmp.st_atime = stat->atime.tv_sec;
 	tmp.st_atime_nsec = stat->atime.tv_nsec;
 	tmp.st_mtime = stat->mtime.tv_sec;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 35a36d3..e6bb9b2 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -132,6 +132,24 @@
 	rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children);
 }
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+
+/* Test for attributes that want to ignore lockdep for read-locking */
+static bool ignore_lockdep(struct sysfs_dirent *sd)
+{
+	return sysfs_type(sd) == SYSFS_KOBJ_ATTR &&
+			sd->s_attr.attr->ignore_lockdep;
+}
+
+#else
+
+static inline bool ignore_lockdep(struct sysfs_dirent *sd)
+{
+	return true;
+}
+
+#endif
+
 /**
  *	sysfs_get_active - get an active reference to sysfs_dirent
  *	@sd: sysfs_dirent to get an active reference to
@@ -155,15 +173,17 @@
 			return NULL;
 
 		t = atomic_cmpxchg(&sd->s_active, v, v + 1);
-		if (likely(t == v)) {
-			rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
-			return sd;
-		}
+		if (likely(t == v))
+			break;
 		if (t < 0)
 			return NULL;
 
 		cpu_relax();
 	}
+
+	if (likely(!ignore_lockdep(sd)))
+		rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
+	return sd;
 }
 
 /**
@@ -180,7 +200,8 @@
 	if (unlikely(!sd))
 		return;
 
-	rwsem_release(&sd->dep_map, 1, _RET_IP_);
+	if (likely(!ignore_lockdep(sd)))
+		rwsem_release(&sd->dep_map, 1, _RET_IP_);
 	v = atomic_dec_return(&sd->s_active);
 	if (likely(v != SD_DEACTIVATED_BIAS))
 		return;
@@ -858,7 +879,6 @@
 	struct sysfs_dirent *new_parent_sd, const void *new_ns,
 	const char *new_name)
 {
-	const char *dup_name = NULL;
 	int error;
 
 	mutex_lock(&sysfs_mutex);
@@ -875,11 +895,11 @@
 	/* rename sysfs_dirent */
 	if (strcmp(sd->s_name, new_name) != 0) {
 		error = -ENOMEM;
-		new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
+		new_name = kstrdup(new_name, GFP_KERNEL);
 		if (!new_name)
 			goto out;
 
-		dup_name = sd->s_name;
+		kfree(sd->s_name);
 		sd->s_name = new_name;
 	}
 
@@ -895,7 +915,6 @@
 	error = 0;
  out:
 	mutex_unlock(&sysfs_mutex);
-	kfree(dup_name);
 	return error;
 }
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index feb2d69..907c2b3 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -62,8 +62,8 @@
 
 	/* assign default attributes */
 	iattrs->ia_mode = sd->s_mode;
-	iattrs->ia_uid = 0;
-	iattrs->ia_gid = 0;
+	iattrs->ia_uid = GLOBAL_ROOT_UID;
+	iattrs->ia_gid = GLOBAL_ROOT_GID;
 	iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME;
 
 	return attrs;
diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
index f8b0160..ba66d508 100644
--- a/fs/ubifs/Kconfig
+++ b/fs/ubifs/Kconfig
@@ -11,12 +11,6 @@
 	help
 	  UBIFS is a file system for flash devices which works on top of UBI.
 
-config UBIFS_FS_XATTR
-	bool "Extended attributes support"
-	depends on UBIFS_FS
-	help
-	  This option enables support of extended attributes.
-
 config UBIFS_FS_ADVANCED_COMPR
 	bool "Advanced compression options"
 	depends on UBIFS_FS
@@ -41,20 +35,3 @@
 	default y
 	help
 	  Zlib compresses better than LZO but it is slower. Say 'Y' if unsure.
-
-# Debugging-related stuff
-config UBIFS_FS_DEBUG
-	bool "Enable debugging support"
-	depends on UBIFS_FS
-	select DEBUG_FS
-	select KALLSYMS
-	help
-	  This option enables UBIFS debugging support. It makes sure various
-	  assertions, self-checks, debugging messages and test modes are compiled
-	  in (this all is compiled out otherwise). Assertions are light-weight
-	  and this option also enables them. Self-checks, debugging messages and
-	  test modes are switched off by default. Thus, it is safe and actually
-	  recommended to have debugging support enabled, and it should not slow
-	  down UBIFS. You can then further enable / disable individual  debugging
-	  features using UBIFS module parameters and the corresponding sysfs
-	  interfaces.
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index 80e93c3..2c6f0cb 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -3,7 +3,4 @@
 ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o
 ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
 ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
-ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o
-
-ubifs-$(CONFIG_UBIFS_FS_DEBUG) += debug.o
-ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o
+ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
index fb3b5c8..8eda717 100644
--- a/fs/ubifs/commit.c
+++ b/fs/ubifs/commit.c
@@ -496,7 +496,9 @@
 	return ret;
 }
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
+/*
+ * Everything below is related to debugging.
+ */
 
 /**
  * struct idx_node - hold index nodes during index tree traversal.
@@ -714,14 +716,14 @@
 	return 0;
 
 out_dump:
-	dbg_err("dumping index node (iip=%d)", i->iip);
-	dbg_dump_node(c, idx);
+	ubifs_err("dumping index node (iip=%d)", i->iip);
+	ubifs_dump_node(c, idx);
 	list_del(&i->list);
 	kfree(i);
 	if (!list_empty(&list)) {
 		i = list_entry(list.prev, struct idx_node, list);
-		dbg_err("dumping parent index node");
-		dbg_dump_node(c, &i->idx);
+		ubifs_err("dumping parent index node");
+		ubifs_dump_node(c, &i->idx);
 	}
 out_free:
 	while (!list_empty(&list)) {
@@ -734,5 +736,3 @@
 		err = -EINVAL;
 	return err;
 }
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 1934084..685a837 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -34,8 +34,6 @@
 #include <linux/random.h>
 #include "ubifs.h"
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
 static DEFINE_SPINLOCK(dbg_lock);
 
 static const char *get_key_fmt(int fmt)
@@ -232,7 +230,7 @@
 	printk(KERN_ERR "\tlen            %u\n", le32_to_cpu(ch->len));
 }
 
-void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
+void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
 {
 	const struct ubifs_inode *ui = ubifs_inode(inode);
 	struct qstr nm = { .name = NULL };
@@ -300,7 +298,7 @@
 	kfree(pdent);
 }
 
-void dbg_dump_node(const struct ubifs_info *c, const void *node)
+void ubifs_dump_node(const struct ubifs_info *c, const void *node)
 {
 	int i, n;
 	union ubifs_key key;
@@ -603,7 +601,7 @@
 	spin_unlock(&dbg_lock);
 }
 
-void dbg_dump_budget_req(const struct ubifs_budget_req *req)
+void ubifs_dump_budget_req(const struct ubifs_budget_req *req)
 {
 	spin_lock(&dbg_lock);
 	printk(KERN_ERR "Budgeting request: new_ino %d, dirtied_ino %d\n",
@@ -620,7 +618,7 @@
 	spin_unlock(&dbg_lock);
 }
 
-void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
+void ubifs_dump_lstats(const struct ubifs_lp_stats *lst)
 {
 	spin_lock(&dbg_lock);
 	printk(KERN_ERR "(pid %d) Lprops statistics: empty_lebs %d, "
@@ -634,7 +632,7 @@
 	spin_unlock(&dbg_lock);
 }
 
-void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
+void ubifs_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
 {
 	int i;
 	struct rb_node *rb;
@@ -707,7 +705,7 @@
 	spin_unlock(&c->space_lock);
 }
 
-void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+void ubifs_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
 {
 	int i, spc, dark = 0, dead = 0;
 	struct rb_node *rb;
@@ -801,7 +799,7 @@
 	printk(KERN_CONT ")\n");
 }
 
-void dbg_dump_lprops(struct ubifs_info *c)
+void ubifs_dump_lprops(struct ubifs_info *c)
 {
 	int lnum, err;
 	struct ubifs_lprops lp;
@@ -810,20 +808,20 @@
 	printk(KERN_ERR "(pid %d) start dumping LEB properties\n",
 	       current->pid);
 	ubifs_get_lp_stats(c, &lst);
-	dbg_dump_lstats(&lst);
+	ubifs_dump_lstats(&lst);
 
 	for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
 		err = ubifs_read_one_lp(c, lnum, &lp);
 		if (err)
 			ubifs_err("cannot read lprops for LEB %d", lnum);
 
-		dbg_dump_lprop(c, &lp);
+		ubifs_dump_lprop(c, &lp);
 	}
 	printk(KERN_ERR "(pid %d) finish dumping LEB properties\n",
 	       current->pid);
 }
 
-void dbg_dump_lpt_info(struct ubifs_info *c)
+void ubifs_dump_lpt_info(struct ubifs_info *c)
 {
 	int i;
 
@@ -862,8 +860,8 @@
 	spin_unlock(&dbg_lock);
 }
 
-void dbg_dump_sleb(const struct ubifs_info *c,
-		   const struct ubifs_scan_leb *sleb, int offs)
+void ubifs_dump_sleb(const struct ubifs_info *c,
+		     const struct ubifs_scan_leb *sleb, int offs)
 {
 	struct ubifs_scan_node *snod;
 
@@ -874,11 +872,11 @@
 		cond_resched();
 		printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", sleb->lnum,
 		       snod->offs, snod->len);
-		dbg_dump_node(c, snod->node);
+		ubifs_dump_node(c, snod->node);
 	}
 }
 
-void dbg_dump_leb(const struct ubifs_info *c, int lnum)
+void ubifs_dump_leb(const struct ubifs_info *c, int lnum)
 {
 	struct ubifs_scan_leb *sleb;
 	struct ubifs_scan_node *snod;
@@ -909,7 +907,7 @@
 		cond_resched();
 		printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", lnum,
 		       snod->offs, snod->len);
-		dbg_dump_node(c, snod->node);
+		ubifs_dump_node(c, snod->node);
 	}
 
 	printk(KERN_ERR "(pid %d) finish dumping LEB %d\n",
@@ -921,8 +919,8 @@
 	return;
 }
 
-void dbg_dump_znode(const struct ubifs_info *c,
-		    const struct ubifs_znode *znode)
+void ubifs_dump_znode(const struct ubifs_info *c,
+		      const struct ubifs_znode *znode)
 {
 	int n;
 	const struct ubifs_zbranch *zbr;
@@ -965,7 +963,7 @@
 	spin_unlock(&dbg_lock);
 }
 
-void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
+void ubifs_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
 {
 	int i;
 
@@ -981,8 +979,8 @@
 	printk(KERN_ERR "(pid %d) finish dumping heap\n", current->pid);
 }
 
-void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
-		    struct ubifs_nnode *parent, int iip)
+void ubifs_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+		      struct ubifs_nnode *parent, int iip)
 {
 	int i;
 
@@ -999,7 +997,7 @@
 	}
 }
 
-void dbg_dump_tnc(struct ubifs_info *c)
+void ubifs_dump_tnc(struct ubifs_info *c)
 {
 	struct ubifs_znode *znode;
 	int level;
@@ -1014,7 +1012,7 @@
 			level = znode->level;
 			printk(KERN_ERR "== Level %d ==\n", level);
 		}
-		dbg_dump_znode(c, znode);
+		ubifs_dump_znode(c, znode);
 		znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
 	}
 	printk(KERN_ERR "(pid %d) finish dumping TNC tree\n", current->pid);
@@ -1023,18 +1021,18 @@
 static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
 		      void *priv)
 {
-	dbg_dump_znode(c, znode);
+	ubifs_dump_znode(c, znode);
 	return 0;
 }
 
 /**
- * dbg_dump_index - dump the on-flash index.
+ * ubifs_dump_index - dump the on-flash index.
  * @c: UBIFS file-system description object
  *
- * This function dumps whole UBIFS indexing B-tree, unlike 'dbg_dump_tnc()'
+ * This function dumps whole UBIFS indexing B-tree, unlike 'ubifs_dump_tnc()'
  * which dumps only in-memory znodes and does not read znodes which from flash.
  */
-void dbg_dump_index(struct ubifs_info *c)
+void ubifs_dump_index(struct ubifs_info *c)
 {
 	dbg_walk_index(c, NULL, dump_znode, NULL);
 }
@@ -1120,15 +1118,15 @@
 
 out:
 	ubifs_msg("saved lprops statistics dump");
-	dbg_dump_lstats(&d->saved_lst);
+	ubifs_dump_lstats(&d->saved_lst);
 	ubifs_msg("saved budgeting info dump");
-	dbg_dump_budg(c, &d->saved_bi);
+	ubifs_dump_budg(c, &d->saved_bi);
 	ubifs_msg("saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
 	ubifs_msg("current lprops statistics dump");
 	ubifs_get_lp_stats(c, &lst);
-	dbg_dump_lstats(&lst);
+	ubifs_dump_lstats(&lst);
 	ubifs_msg("current budgeting info dump");
-	dbg_dump_budg(c, &c->bi);
+	ubifs_dump_budg(c, &c->bi);
 	dump_stack();
 	return -EINVAL;
 }
@@ -1160,7 +1158,7 @@
 			  "is clean", ui->ui_size, ui->synced_i_size);
 		ubifs_err("i_ino %lu, i_mode %#x, i_size %lld", inode->i_ino,
 			  inode->i_mode, i_size_read(inode));
-		dbg_dump_stack();
+		dump_stack();
 		err = -EINVAL;
 	}
 	spin_unlock(&ui->ui_lock);
@@ -1223,14 +1221,14 @@
 			  "but calculated size is %llu", dir->i_ino,
 			  (unsigned long long)i_size_read(dir),
 			  (unsigned long long)size);
-		dbg_dump_inode(c, dir);
+		ubifs_dump_inode(c, dir);
 		dump_stack();
 		return -EINVAL;
 	}
 	if (dir->i_nlink != nlink) {
 		ubifs_err("directory inode %lu has nlink %u, but calculated "
 			  "nlink is %u", dir->i_ino, dir->i_nlink, nlink);
-		dbg_dump_inode(c, dir);
+		ubifs_dump_inode(c, dir);
 		dump_stack();
 		return -EINVAL;
 	}
@@ -1287,25 +1285,25 @@
 	err = 1;
 	key_read(c, &dent1->key, &key);
 	if (keys_cmp(c, &zbr1->key, &key)) {
-		dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
-			zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
-						     DBG_KEY_BUF_LEN));
-		dbg_err("but it should have key %s according to tnc",
-			dbg_snprintf_key(c, &zbr1->key, key_buf,
-					 DBG_KEY_BUF_LEN));
-		dbg_dump_node(c, dent1);
+		ubifs_err("1st entry at %d:%d has key %s", zbr1->lnum,
+			  zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
+						       DBG_KEY_BUF_LEN));
+		ubifs_err("but it should have key %s according to tnc",
+			  dbg_snprintf_key(c, &zbr1->key, key_buf,
+					   DBG_KEY_BUF_LEN));
+		ubifs_dump_node(c, dent1);
 		goto out_free;
 	}
 
 	key_read(c, &dent2->key, &key);
 	if (keys_cmp(c, &zbr2->key, &key)) {
-		dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
-			zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
-						     DBG_KEY_BUF_LEN));
-		dbg_err("but it should have key %s according to tnc",
-			dbg_snprintf_key(c, &zbr2->key, key_buf,
-					 DBG_KEY_BUF_LEN));
-		dbg_dump_node(c, dent2);
+		ubifs_err("2nd entry at %d:%d has key %s", zbr1->lnum,
+			  zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
+						       DBG_KEY_BUF_LEN));
+		ubifs_err("but it should have key %s according to tnc",
+			  dbg_snprintf_key(c, &zbr2->key, key_buf,
+					   DBG_KEY_BUF_LEN));
+		ubifs_dump_node(c, dent2);
 		goto out_free;
 	}
 
@@ -1318,15 +1316,15 @@
 		goto out_free;
 	}
 	if (cmp == 0 && nlen1 == nlen2)
-		dbg_err("2 xent/dent nodes with the same name");
+		ubifs_err("2 xent/dent nodes with the same name");
 	else
-		dbg_err("bad order of colliding key %s",
-			dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
+		ubifs_err("bad order of colliding key %s",
+			  dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
 
 	ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
-	dbg_dump_node(c, dent1);
+	ubifs_dump_node(c, dent1);
 	ubifs_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs);
-	dbg_dump_node(c, dent2);
+	ubifs_dump_node(c, dent2);
 
 out_free:
 	kfree(dent2);
@@ -1529,10 +1527,10 @@
 out:
 	ubifs_err("failed, error %d", err);
 	ubifs_msg("dump of the znode");
-	dbg_dump_znode(c, znode);
+	ubifs_dump_znode(c, znode);
 	if (zp) {
 		ubifs_msg("dump of the parent znode");
-		dbg_dump_znode(c, zp);
+		ubifs_dump_znode(c, zp);
 	}
 	dump_stack();
 	return -EINVAL;
@@ -1599,9 +1597,9 @@
 				return err;
 			if (err) {
 				ubifs_msg("first znode");
-				dbg_dump_znode(c, prev);
+				ubifs_dump_znode(c, prev);
 				ubifs_msg("second znode");
-				dbg_dump_znode(c, znode);
+				ubifs_dump_znode(c, znode);
 				return -EINVAL;
 			}
 		}
@@ -1690,7 +1688,7 @@
 			if (err) {
 				ubifs_err("znode checking function returned "
 					  "error %d", err);
-				dbg_dump_znode(c, znode);
+				ubifs_dump_znode(c, znode);
 				goto out_dump;
 			}
 		}
@@ -1758,7 +1756,7 @@
 	else
 		zbr = &c->zroot;
 	ubifs_msg("dump of znode at LEB %d:%d", zbr->lnum, zbr->offs);
-	dbg_dump_znode(c, znode);
+	ubifs_dump_znode(c, znode);
 out_unlock:
 	mutex_unlock(&c->tnc_mutex);
 	return err;
@@ -2194,7 +2192,7 @@
 
 out_dump:
 	ubifs_msg("dump of node at LEB %d:%d", zbr->lnum, zbr->offs);
-	dbg_dump_node(c, node);
+	ubifs_dump_node(c, node);
 out_free:
 	kfree(node);
 	return err;
@@ -2352,7 +2350,7 @@
 
 	ubifs_msg("dump of the inode %lu sitting in LEB %d:%d",
 		  (unsigned long)fscki->inum, zbr->lnum, zbr->offs);
-	dbg_dump_node(c, ino);
+	ubifs_dump_node(c, ino);
 	kfree(ino);
 	return -EINVAL;
 }
@@ -2423,12 +2421,12 @@
 
 		if (sa->type != UBIFS_DATA_NODE) {
 			ubifs_err("bad node type %d", sa->type);
-			dbg_dump_node(c, sa->node);
+			ubifs_dump_node(c, sa->node);
 			return -EINVAL;
 		}
 		if (sb->type != UBIFS_DATA_NODE) {
 			ubifs_err("bad node type %d", sb->type);
-			dbg_dump_node(c, sb->node);
+			ubifs_dump_node(c, sb->node);
 			return -EINVAL;
 		}
 
@@ -2459,8 +2457,8 @@
 	return 0;
 
 error_dump:
-	dbg_dump_node(c, sa->node);
-	dbg_dump_node(c, sb->node);
+	ubifs_dump_node(c, sa->node);
+	ubifs_dump_node(c, sb->node);
 	return -EINVAL;
 }
 
@@ -2491,13 +2489,13 @@
 		if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
 		    sa->type != UBIFS_XENT_NODE) {
 			ubifs_err("bad node type %d", sa->type);
-			dbg_dump_node(c, sa->node);
+			ubifs_dump_node(c, sa->node);
 			return -EINVAL;
 		}
 		if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
 		    sa->type != UBIFS_XENT_NODE) {
 			ubifs_err("bad node type %d", sb->type);
-			dbg_dump_node(c, sb->node);
+			ubifs_dump_node(c, sb->node);
 			return -EINVAL;
 		}
 
@@ -2547,9 +2545,9 @@
 
 error_dump:
 	ubifs_msg("dumping first node");
-	dbg_dump_node(c, sa->node);
+	ubifs_dump_node(c, sa->node);
 	ubifs_msg("dumping second node");
-	dbg_dump_node(c, sb->node);
+	ubifs_dump_node(c, sb->node);
 	return -EINVAL;
 	return 0;
 }
@@ -2678,7 +2676,7 @@
 }
 
 int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
-		  int offs, int len, int dtype)
+		  int offs, int len)
 {
 	int err, failing;
 
@@ -2688,7 +2686,7 @@
 	failing = power_cut_emulated(c, lnum, 1);
 	if (failing)
 		cut_data(buf, len);
-	err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+	err = ubi_leb_write(c->ubi, lnum, buf, offs, len);
 	if (err)
 		return err;
 	if (failing)
@@ -2697,7 +2695,7 @@
 }
 
 int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
-		   int len, int dtype)
+		   int len)
 {
 	int err;
 
@@ -2705,7 +2703,7 @@
 		return -EROFS;
 	if (power_cut_emulated(c, lnum, 1))
 		return -EROFS;
-	err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+	err = ubi_leb_change(c->ubi, lnum, buf, len);
 	if (err)
 		return err;
 	if (power_cut_emulated(c, lnum, 1))
@@ -2729,7 +2727,7 @@
 	return 0;
 }
 
-int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype)
+int dbg_leb_map(struct ubifs_info *c, int lnum)
 {
 	int err;
 
@@ -2737,7 +2735,7 @@
 		return -EROFS;
 	if (power_cut_emulated(c, lnum, 0))
 		return -EROFS;
-	err = ubi_leb_map(c->ubi, lnum, dtype);
+	err = ubi_leb_map(c->ubi, lnum);
 	if (err)
 		return err;
 	if (power_cut_emulated(c, lnum, 0))
@@ -2857,16 +2855,16 @@
 	 * 'ubifs-debug' file-system instead.
 	 */
 	if (file->f_path.dentry == d->dfs_dump_lprops) {
-		dbg_dump_lprops(c);
+		ubifs_dump_lprops(c);
 		return count;
 	}
 	if (file->f_path.dentry == d->dfs_dump_budg) {
-		dbg_dump_budg(c, &c->bi);
+		ubifs_dump_budg(c, &c->bi);
 		return count;
 	}
 	if (file->f_path.dentry == d->dfs_dump_tnc) {
 		mutex_lock(&c->tnc_mutex);
-		dbg_dump_tnc(c);
+		ubifs_dump_tnc(c);
 		mutex_unlock(&c->tnc_mutex);
 		return count;
 	}
@@ -3189,5 +3187,3 @@
 {
 	kfree(c->dbg);
 }
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index 9f71765..486a8e0 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -29,8 +29,6 @@
 typedef int (*dbg_znode_callback)(struct ubifs_info *c,
 				  struct ubifs_znode *znode, void *priv);
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
 /*
  * The UBIFS debugfs directory name pattern and maximum name length (3 for "ubi"
  * + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte.
@@ -149,7 +147,7 @@
 	if (unlikely(!(expr))) {                                               \
 		printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
 		       __func__, __LINE__, current->pid);                      \
-		dbg_dump_stack();                                              \
+		dump_stack();                                                  \
 	}                                                                      \
 } while (0)
 
@@ -161,12 +159,6 @@
 	}                                                                      \
 } while (0)
 
-#define dbg_dump_stack() dump_stack()
-
-#define dbg_err(fmt, ...) do {                                                 \
-	ubifs_err(fmt, ##__VA_ARGS__);                                         \
-} while (0)
-
 #define ubifs_dbg_msg(type, fmt, ...) \
 	pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__)
 
@@ -257,27 +249,27 @@
 			     const union ubifs_key *key);
 const char *dbg_snprintf_key(const struct ubifs_info *c,
 			     const union ubifs_key *key, char *buffer, int len);
-void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
-void dbg_dump_node(const struct ubifs_info *c, const void *node);
-void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
-		       int offs);
-void dbg_dump_budget_req(const struct ubifs_budget_req *req);
-void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
-void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi);
-void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp);
-void dbg_dump_lprops(struct ubifs_info *c);
-void dbg_dump_lpt_info(struct ubifs_info *c);
-void dbg_dump_leb(const struct ubifs_info *c, int lnum);
-void dbg_dump_sleb(const struct ubifs_info *c,
-		   const struct ubifs_scan_leb *sleb, int offs);
-void dbg_dump_znode(const struct ubifs_info *c,
-		    const struct ubifs_znode *znode);
-void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat);
-void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
-		    struct ubifs_nnode *parent, int iip);
-void dbg_dump_tnc(struct ubifs_info *c);
-void dbg_dump_index(struct ubifs_info *c);
-void dbg_dump_lpt_lebs(const struct ubifs_info *c);
+void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode);
+void ubifs_dump_node(const struct ubifs_info *c, const void *node);
+void ubifs_dump_budget_req(const struct ubifs_budget_req *req);
+void ubifs_dump_lstats(const struct ubifs_lp_stats *lst);
+void ubifs_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi);
+void ubifs_dump_lprop(const struct ubifs_info *c,
+		      const struct ubifs_lprops *lp);
+void ubifs_dump_lprops(struct ubifs_info *c);
+void ubifs_dump_lpt_info(struct ubifs_info *c);
+void ubifs_dump_leb(const struct ubifs_info *c, int lnum);
+void ubifs_dump_sleb(const struct ubifs_info *c,
+		     const struct ubifs_scan_leb *sleb, int offs);
+void ubifs_dump_znode(const struct ubifs_info *c,
+		      const struct ubifs_znode *znode);
+void ubifs_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
+		     int cat);
+void ubifs_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+		      struct ubifs_nnode *parent, int iip);
+void ubifs_dump_tnc(struct ubifs_info *c);
+void ubifs_dump_index(struct ubifs_info *c);
+void ubifs_dump_lpt_lebs(const struct ubifs_info *c);
 
 int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
 		   dbg_znode_callback znode_cb, void *priv);
@@ -307,11 +299,10 @@
 int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
 
 int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
-		  int len, int dtype);
-int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
-		   int dtype);
+		  int len);
+int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len);
 int dbg_leb_unmap(struct ubifs_info *c, int lnum);
-int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype);
+int dbg_leb_map(struct ubifs_info *c, int lnum);
 
 /* Debugfs-related stuff */
 int dbg_debugfs_init(void);
@@ -319,162 +310,4 @@
 int dbg_debugfs_init_fs(struct ubifs_info *c);
 void dbg_debugfs_exit_fs(struct ubifs_info *c);
 
-#else /* !CONFIG_UBIFS_FS_DEBUG */
-
-/* Use "if (0)" to make compiler check arguments even if debugging is off */
-#define ubifs_assert(expr)  do {                                               \
-	if (0)                                                                 \
-		printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
-		       __func__, __LINE__, current->pid);                      \
-} while (0)
-
-#define dbg_err(fmt, ...)   do {                   \
-	if (0)                                     \
-		ubifs_err(fmt, ##__VA_ARGS__);     \
-} while (0)
-
-#define DBGKEY(key)  ((char *)(key))
-#define DBGKEY1(key) ((char *)(key))
-
-#define ubifs_dbg_msg(fmt, ...) do {                        \
-	if (0)                                              \
-		printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \
-} while (0)
-
-#define dbg_dump_stack()
-#define ubifs_assert_cmt_locked(c)
-
-#define dbg_msg(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gen(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_jnl(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_jnlk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_tnc(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_tnck(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_lp(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_find(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_mnt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_mntk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_io(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_cmt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_budg(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_log(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gc(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_scan(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_rcvry(fmt, ...)     ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-
-static inline int ubifs_debugging_init(struct ubifs_info *c)      { return 0; }
-static inline void ubifs_debugging_exit(struct ubifs_info *c)     { return; }
-static inline const char *dbg_ntype(int type)                     { return ""; }
-static inline const char *dbg_cstate(int cmt_state)               { return ""; }
-static inline const char *dbg_jhead(int jhead)                    { return ""; }
-static inline const char *
-dbg_get_key_dump(const struct ubifs_info *c,
-		 const union ubifs_key *key)                      { return ""; }
-static inline const char *
-dbg_snprintf_key(const struct ubifs_info *c,
-		 const union ubifs_key *key, char *buffer,
-		 int len)                                         { return ""; }
-static inline void dbg_dump_inode(struct ubifs_info *c,
-				  const struct inode *inode)      { return; }
-static inline void dbg_dump_node(const struct ubifs_info *c,
-				 const void *node)                { return; }
-static inline void dbg_dump_lpt_node(const struct ubifs_info *c,
-				     void *node, int lnum,
-				     int offs)                    { return; }
-static inline void
-dbg_dump_budget_req(const struct ubifs_budget_req *req)           { return; }
-static inline void
-dbg_dump_lstats(const struct ubifs_lp_stats *lst)                 { return; }
-static inline void
-dbg_dump_budg(struct ubifs_info *c,
-	      const struct ubifs_budg_info *bi)                   { return; }
-static inline void dbg_dump_lprop(const struct ubifs_info *c,
-				  const struct ubifs_lprops *lp)  { return; }
-static inline void dbg_dump_lprops(struct ubifs_info *c)          { return; }
-static inline void dbg_dump_lpt_info(struct ubifs_info *c)        { return; }
-static inline void dbg_dump_leb(const struct ubifs_info *c,
-				int lnum)                         { return; }
-static inline void
-dbg_dump_sleb(const struct ubifs_info *c,
-	      const struct ubifs_scan_leb *sleb, int offs)        { return; }
-static inline void
-dbg_dump_znode(const struct ubifs_info *c,
-	       const struct ubifs_znode *znode)                   { return; }
-static inline void dbg_dump_heap(struct ubifs_info *c,
-				 struct ubifs_lpt_heap *heap,
-				 int cat)                         { return; }
-static inline void dbg_dump_pnode(struct ubifs_info *c,
-				  struct ubifs_pnode *pnode,
-				  struct ubifs_nnode *parent,
-				  int iip)                        { return; }
-static inline void dbg_dump_tnc(struct ubifs_info *c)             { return; }
-static inline void dbg_dump_index(struct ubifs_info *c)           { return; }
-static inline void dbg_dump_lpt_lebs(const struct ubifs_info *c)  { return; }
-
-static inline int dbg_walk_index(struct ubifs_info *c,
-				 dbg_leaf_callback leaf_cb,
-				 dbg_znode_callback znode_cb,
-				 void *priv)                      { return 0; }
-static inline void dbg_save_space_info(struct ubifs_info *c)      { return; }
-static inline int dbg_check_space_info(struct ubifs_info *c)      { return 0; }
-static inline int dbg_check_lprops(struct ubifs_info *c)          { return 0; }
-static inline int
-dbg_old_index_check_init(struct ubifs_info *c,
-			 struct ubifs_zbranch *zroot)             { return 0; }
-static inline int
-dbg_check_old_index(struct ubifs_info *c,
-		    struct ubifs_zbranch *zroot)                  { return 0; }
-static inline int dbg_check_cats(struct ubifs_info *c)            { return 0; }
-static inline int dbg_check_ltab(struct ubifs_info *c)            { return 0; }
-static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c)      { return 0; }
-static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
-				 int action, int len)             { return 0; }
-static inline int
-dbg_check_synced_i_size(const struct ubifs_info *c,
-			struct inode *inode)                      { return 0; }
-static inline int dbg_check_dir(struct ubifs_info *c,
-				const struct inode *dir)          { return 0; }
-static inline int dbg_check_tnc(struct ubifs_info *c, int extra)  { return 0; }
-static inline int dbg_check_idx_size(struct ubifs_info *c,
-				     long long idx_size)          { return 0; }
-static inline int dbg_check_filesystem(struct ubifs_info *c)      { return 0; }
-static inline void dbg_check_heap(struct ubifs_info *c,
-				  struct ubifs_lpt_heap *heap,
-				  int cat, int add_pos)           { return; }
-static inline int dbg_check_lpt_nodes(struct ubifs_info *c,
-	struct ubifs_cnode *cnode, int row, int col)              { return 0; }
-static inline int dbg_check_inode_size(struct ubifs_info *c,
-				       const struct inode *inode,
-				       loff_t size)               { return 0; }
-static inline int
-dbg_check_data_nodes_order(struct ubifs_info *c,
-			   struct list_head *head)                { return 0; }
-static inline int
-dbg_check_nondata_nodes_order(struct ubifs_info *c,
-			      struct list_head *head)             { return 0; }
-
-static inline int dbg_leb_write(struct ubifs_info *c, int lnum,
-				const void *buf, int offset,
-				int len, int dtype)               { return 0; }
-static inline int dbg_leb_change(struct ubifs_info *c, int lnum,
-				 const void *buf, int len,
-				 int dtype)                       { return 0; }
-static inline int dbg_leb_unmap(struct ubifs_info *c, int lnum)   { return 0; }
-static inline int dbg_leb_map(struct ubifs_info *c, int lnum,
-			      int dtype)                          { return 0; }
-
-static inline int dbg_is_chk_gen(const struct ubifs_info *c)      { return 0; }
-static inline int dbg_is_chk_index(const struct ubifs_info *c)    { return 0; }
-static inline int dbg_is_chk_orph(const struct ubifs_info *c)     { return 0; }
-static inline int dbg_is_chk_lprops(const struct ubifs_info *c)   { return 0; }
-static inline int dbg_is_chk_fs(const struct ubifs_info *c)       { return 0; }
-static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)    { return 0; }
-static inline int dbg_is_power_cut(const struct ubifs_info *c)    { return 0; }
-
-static inline int dbg_debugfs_init(void)                          { return 0; }
-static inline void dbg_debugfs_exit(void)                         { return; }
-static inline int dbg_debugfs_init_fs(struct ubifs_info *c)       { return 0; }
-static inline int dbg_debugfs_exit_fs(struct ubifs_info *c)       { return 0; }
-
-#endif /* !CONFIG_UBIFS_FS_DEBUG */
 #endif /* !__UBIFS_DEBUG_H__ */
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index ec9f187..62a2727 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -170,8 +170,6 @@
 	return inode;
 }
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
 static int dbg_check_name(const struct ubifs_info *c,
 			  const struct ubifs_dent_node *dent,
 			  const struct qstr *nm)
@@ -185,12 +183,6 @@
 	return 0;
 }
 
-#else
-
-#define dbg_check_name(c, dent, nm) 0
-
-#endif
-
 static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 				   struct nameidata *nd)
 {
@@ -1187,12 +1179,10 @@
 	.rename      = ubifs_rename,
 	.setattr     = ubifs_setattr,
 	.getattr     = ubifs_getattr,
-#ifdef CONFIG_UBIFS_FS_XATTR
 	.setxattr    = ubifs_setxattr,
 	.getxattr    = ubifs_getxattr,
 	.listxattr   = ubifs_listxattr,
 	.removexattr = ubifs_removexattr,
-#endif
 };
 
 const struct file_operations ubifs_dir_operations = {
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 5c8f6dc..35389ca 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -97,7 +97,7 @@
 dump:
 	ubifs_err("bad data node (block %u, inode %lu)",
 		  block, inode->i_ino);
-	dbg_dump_node(c, dn);
+	ubifs_dump_node(c, dn);
 	return -EINVAL;
 }
 
@@ -1562,12 +1562,10 @@
 const struct inode_operations ubifs_file_inode_operations = {
 	.setattr     = ubifs_setattr,
 	.getattr     = ubifs_getattr,
-#ifdef CONFIG_UBIFS_FS_XATTR
 	.setxattr    = ubifs_setxattr,
 	.getxattr    = ubifs_getxattr,
 	.listxattr   = ubifs_listxattr,
 	.removexattr = ubifs_removexattr,
-#endif
 };
 
 const struct inode_operations ubifs_symlink_inode_operations = {
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index ded29f6..04dd6f4 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -109,7 +109,7 @@
 		return err;
 
 	c->gc_lnum = -1;
-	err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0, UBI_LONGTERM);
+	err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0);
 	return err;
 }
 
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index 9228950a..e18b988 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -109,13 +109,13 @@
 	if (err && (err != -EBADMSG || even_ebadmsg)) {
 		ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
 			  len, lnum, offs, err);
-		dbg_dump_stack();
+		dump_stack();
 	}
 	return err;
 }
 
 int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
-		    int len, int dtype)
+		    int len)
 {
 	int err;
 
@@ -123,20 +123,19 @@
 	if (c->ro_error)
 		return -EROFS;
 	if (!dbg_is_tst_rcvry(c))
-		err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+		err = ubi_leb_write(c->ubi, lnum, buf, offs, len);
 	else
-		err = dbg_leb_write(c, lnum, buf, offs, len, dtype);
+		err = dbg_leb_write(c, lnum, buf, offs, len);
 	if (err) {
 		ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
 			  len, lnum, offs, err);
 		ubifs_ro_mode(c, err);
-		dbg_dump_stack();
+		dump_stack();
 	}
 	return err;
 }
 
-int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
-		     int dtype)
+int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len)
 {
 	int err;
 
@@ -144,14 +143,14 @@
 	if (c->ro_error)
 		return -EROFS;
 	if (!dbg_is_tst_rcvry(c))
-		err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+		err = ubi_leb_change(c->ubi, lnum, buf, len);
 	else
-		err = dbg_leb_change(c, lnum, buf, len, dtype);
+		err = dbg_leb_change(c, lnum, buf, len);
 	if (err) {
 		ubifs_err("changing %d bytes in LEB %d failed, error %d",
 			  len, lnum, err);
 		ubifs_ro_mode(c, err);
-		dbg_dump_stack();
+		dump_stack();
 	}
 	return err;
 }
@@ -170,12 +169,12 @@
 	if (err) {
 		ubifs_err("unmap LEB %d failed, error %d", lnum, err);
 		ubifs_ro_mode(c, err);
-		dbg_dump_stack();
+		dump_stack();
 	}
 	return err;
 }
 
-int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
+int ubifs_leb_map(struct ubifs_info *c, int lnum)
 {
 	int err;
 
@@ -183,13 +182,13 @@
 	if (c->ro_error)
 		return -EROFS;
 	if (!dbg_is_tst_rcvry(c))
-		err = ubi_leb_map(c->ubi, lnum, dtype);
+		err = ubi_leb_map(c->ubi, lnum);
 	else
-		err = dbg_leb_map(c, lnum, dtype);
+		err = dbg_leb_map(c, lnum);
 	if (err) {
 		ubifs_err("mapping LEB %d failed, error %d", lnum, err);
 		ubifs_ro_mode(c, err);
-		dbg_dump_stack();
+		dump_stack();
 	}
 	return err;
 }
@@ -202,7 +201,7 @@
 	if (err < 0) {
 		ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
 			  lnum, err);
-		dbg_dump_stack();
+		dump_stack();
 	}
 	return err;
 }
@@ -294,8 +293,8 @@
 out:
 	if (!quiet) {
 		ubifs_err("bad node at LEB %d:%d", lnum, offs);
-		dbg_dump_node(c, buf);
-		dbg_dump_stack();
+		ubifs_dump_node(c, buf);
+		dump_stack();
 	}
 	return err;
 }
@@ -523,8 +522,7 @@
 	dirt = sync_len - wbuf->used;
 	if (dirt)
 		ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
-	err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
-			      wbuf->dtype);
+	err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len);
 	if (err)
 		return err;
 
@@ -562,14 +560,12 @@
  * @wbuf: write-buffer
  * @lnum: logical eraseblock number to seek to
  * @offs: logical eraseblock offset to seek to
- * @dtype: data type
  *
  * This function targets the write-buffer to logical eraseblock @lnum:@offs.
  * The write-buffer has to be empty. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
-			   int dtype)
+int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs)
 {
 	const struct ubifs_info *c = wbuf->c;
 
@@ -592,7 +588,6 @@
 	wbuf->avail = wbuf->size;
 	wbuf->used = 0;
 	spin_unlock(&wbuf->lock);
-	wbuf->dtype = dtype;
 
 	return 0;
 }
@@ -719,8 +714,7 @@
 			dbg_io("flush jhead %s wbuf to LEB %d:%d",
 			       dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
 			err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
-					      wbuf->offs, wbuf->size,
-					      wbuf->dtype);
+					      wbuf->offs, wbuf->size);
 			if (err)
 				goto out;
 
@@ -756,7 +750,7 @@
 		       dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
 		memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
 		err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
-				      wbuf->size, wbuf->dtype);
+				      wbuf->size);
 		if (err)
 			goto out;
 
@@ -775,7 +769,7 @@
 		dbg_io("write %d bytes to LEB %d:%d",
 		       wbuf->size, wbuf->lnum, wbuf->offs);
 		err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
-				      wbuf->size, wbuf->dtype);
+				      wbuf->size);
 		if (err)
 			goto out;
 
@@ -797,7 +791,7 @@
 		dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
 		       wbuf->offs);
 		err = ubifs_leb_write(c, wbuf->lnum, buf + written,
-				      wbuf->offs, n, wbuf->dtype);
+				      wbuf->offs, n);
 		if (err)
 			goto out;
 		wbuf->offs += n;
@@ -841,9 +835,9 @@
 out:
 	ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
 		  len, wbuf->lnum, wbuf->offs, err);
-	dbg_dump_node(c, buf);
-	dbg_dump_stack();
-	dbg_dump_leb(c, wbuf->lnum);
+	ubifs_dump_node(c, buf);
+	dump_stack();
+	ubifs_dump_leb(c, wbuf->lnum);
 	return err;
 }
 
@@ -854,7 +848,6 @@
  * @len: node length
  * @lnum: logical eraseblock number
  * @offs: offset within the logical eraseblock
- * @dtype: node life-time hint (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
  *
  * This function automatically fills node magic number, assigns sequence
  * number, and calculates node CRC checksum. The length of the @buf buffer has
@@ -863,7 +856,7 @@
  * success and a negative error code in case of failure.
  */
 int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
-		     int offs, int dtype)
+		     int offs)
 {
 	int err, buf_len = ALIGN(len, c->min_io_size);
 
@@ -879,9 +872,9 @@
 		return -EROFS;
 
 	ubifs_prepare_node(c, buf, len, 1);
-	err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
+	err = ubifs_leb_write(c, lnum, buf, offs, buf_len);
 	if (err)
-		dbg_dump_node(c, buf);
+		ubifs_dump_node(c, buf);
 
 	return err;
 }
@@ -960,8 +953,8 @@
 
 out:
 	ubifs_err("bad node at LEB %d:%d", lnum, offs);
-	dbg_dump_node(c, buf);
-	dbg_dump_stack();
+	ubifs_dump_node(c, buf);
+	dump_stack();
 	return -EINVAL;
 }
 
@@ -1017,8 +1010,8 @@
 out:
 	ubifs_err("bad node at LEB %d:%d, LEB mapping status %d", lnum, offs,
 		  ubi_is_mapped(c->ubi, lnum));
-	dbg_dump_node(c, buf);
-	dbg_dump_stack();
+	ubifs_dump_node(c, buf);
+	dump_stack();
 	return -EINVAL;
 }
 
@@ -1056,7 +1049,6 @@
 	 */
 	size = c->max_write_size - (c->leb_start % c->max_write_size);
 	wbuf->avail = wbuf->size = size;
-	wbuf->dtype = UBI_UNKNOWN;
 	wbuf->sync_callback = NULL;
 	mutex_init(&wbuf->io_mutex);
 	spin_lock_init(&wbuf->lock);
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index 2f438ab..12c0f15 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -214,7 +214,7 @@
 	err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
 	if (err)
 		goto out_return;
-	err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
+	err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs);
 	if (err)
 		goto out_unlock;
 
@@ -385,9 +385,9 @@
 	if (err == -ENOSPC) {
 		/* This are some budgeting problems, print useful information */
 		down_write(&c->commit_sem);
-		dbg_dump_stack();
-		dbg_dump_budg(c, &c->bi);
-		dbg_dump_lprops(c);
+		dump_stack();
+		ubifs_dump_budg(c, &c->bi);
+		ubifs_dump_lprops(c);
 		cmt_retries = dbg_check_lprops(c);
 		up_write(&c->commit_sem);
 	}
@@ -1267,7 +1267,6 @@
 	return err;
 }
 
-#ifdef CONFIG_UBIFS_FS_XATTR
 
 /**
  * ubifs_jnl_delete_xattr - delete an extended attribute.
@@ -1462,4 +1461,3 @@
 	return err;
 }
 
-#endif /* CONFIG_UBIFS_FS_XATTR */
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
index f9fd068..c80b15d 100644
--- a/fs/ubifs/log.c
+++ b/fs/ubifs/log.c
@@ -29,11 +29,7 @@
 
 #include "ubifs.h"
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
 static int dbg_check_bud_bytes(struct ubifs_info *c);
-#else
-#define dbg_check_bud_bytes(c) 0
-#endif
 
 /**
  * ubifs_search_bud - search bud LEB.
@@ -262,7 +258,7 @@
 		 * an unclean reboot, because the target LEB might have been
 		 * unmapped, but not yet physically erased.
 		 */
-		err = ubifs_leb_map(c, bud->lnum, UBI_SHORTTERM);
+		err = ubifs_leb_map(c, bud->lnum);
 		if (err)
 			goto out_unlock;
 	}
@@ -270,7 +266,7 @@
 	dbg_log("write ref LEB %d:%d",
 		c->lhead_lnum, c->lhead_offs);
 	err = ubifs_write_node(c, ref, UBIFS_REF_NODE_SZ, c->lhead_lnum,
-			       c->lhead_offs, UBI_SHORTTERM);
+			       c->lhead_offs);
 	if (err)
 		goto out_unlock;
 
@@ -422,7 +418,7 @@
 
 	len = ALIGN(len, c->min_io_size);
 	dbg_log("writing commit start at LEB %d:0, len %d", c->lhead_lnum, len);
-	err = ubifs_leb_write(c, c->lhead_lnum, cs, 0, len, UBI_SHORTTERM);
+	err = ubifs_leb_write(c, c->lhead_lnum, cs, 0, len);
 	if (err)
 		goto out;
 
@@ -623,7 +619,7 @@
 		int sz = ALIGN(*offs, c->min_io_size), err;
 
 		ubifs_pad(c, buf + *offs, sz - *offs);
-		err = ubifs_leb_change(c, *lnum, buf, sz, UBI_SHORTTERM);
+		err = ubifs_leb_change(c, *lnum, buf, sz);
 		if (err)
 			return err;
 		*lnum = ubifs_next_log_lnum(c, *lnum);
@@ -702,7 +698,7 @@
 		int sz = ALIGN(offs, c->min_io_size);
 
 		ubifs_pad(c, buf + offs, sz - offs);
-		err = ubifs_leb_change(c, write_lnum, buf, sz, UBI_SHORTTERM);
+		err = ubifs_leb_change(c, write_lnum, buf, sz);
 		if (err)
 			goto out_free;
 		offs = ALIGN(offs, c->min_io_size);
@@ -734,8 +730,6 @@
 	return err;
 }
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
 /**
  * dbg_check_bud_bytes - make sure bud bytes calculation are all right.
  * @c: UBIFS file-system description object
@@ -767,5 +761,3 @@
 
 	return err;
 }
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index f8a181e..86eb8e5 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -447,7 +447,7 @@
 	int new_cat = ubifs_categorize_lprops(c, lprops);
 
 	if (old_cat == new_cat) {
-		struct ubifs_lpt_heap *heap = &c->lpt_heap[new_cat - 1];
+		struct ubifs_lpt_heap *heap;
 
 		/* lprops on a heap now must be moved up or down */
 		if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
@@ -846,7 +846,9 @@
 	return lprops;
 }
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
+/*
+ * Everything below is related to debugging.
+ */
 
 /**
  * dbg_check_cats - check category heaps and lists.
@@ -1001,8 +1003,8 @@
 out:
 	if (err) {
 		dbg_msg("failed cat %d hpos %d err %d", cat, i, err);
-		dbg_dump_stack();
-		dbg_dump_heap(c, heap, cat);
+		dump_stack();
+		ubifs_dump_heap(c, heap, cat);
 	}
 }
 
@@ -1109,8 +1111,8 @@
 	if (IS_ERR(sleb)) {
 		ret = PTR_ERR(sleb);
 		if (ret == -EUCLEAN) {
-			dbg_dump_lprops(c);
-			dbg_dump_budg(c, &c->bi);
+			ubifs_dump_lprops(c);
+			ubifs_dump_budg(c, &c->bi);
 		}
 		goto out;
 	}
@@ -1237,7 +1239,7 @@
 	ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, "
 		  "should be free %d, dirty %d",
 		  lnum, lp->free, lp->dirty, lp->flags, free, dirty);
-	dbg_dump_leb(c, lnum);
+	ubifs_dump_leb(c, lnum);
 out_destroy:
 	ubifs_scan_destroy(sleb);
 	ret = -EINVAL;
@@ -1315,5 +1317,3 @@
 out:
 	return err;
 }
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
index 66d59d0..ce33b2b 100644
--- a/fs/ubifs/lpt.c
+++ b/fs/ubifs/lpt.c
@@ -701,8 +701,7 @@
 			alen = ALIGN(len, c->min_io_size);
 			set_ltab(c, lnum, c->leb_size - alen, alen - len);
 			memset(p, 0xff, alen - len);
-			err = ubifs_leb_change(c, lnum++, buf, alen,
-					       UBI_SHORTTERM);
+			err = ubifs_leb_change(c, lnum++, buf, alen);
 			if (err)
 				goto out;
 			p = buf;
@@ -732,8 +731,7 @@
 				set_ltab(c, lnum, c->leb_size - alen,
 					    alen - len);
 				memset(p, 0xff, alen - len);
-				err = ubifs_leb_change(c, lnum++, buf, alen,
-						       UBI_SHORTTERM);
+				err = ubifs_leb_change(c, lnum++, buf, alen);
 				if (err)
 					goto out;
 				p = buf;
@@ -780,8 +778,7 @@
 			alen = ALIGN(len, c->min_io_size);
 			set_ltab(c, lnum, c->leb_size - alen, alen - len);
 			memset(p, 0xff, alen - len);
-			err = ubifs_leb_change(c, lnum++, buf, alen,
-					       UBI_SHORTTERM);
+			err = ubifs_leb_change(c, lnum++, buf, alen);
 			if (err)
 				goto out;
 			p = buf;
@@ -806,7 +803,7 @@
 		alen = ALIGN(len, c->min_io_size);
 		set_ltab(c, lnum, c->leb_size - alen, alen - len);
 		memset(p, 0xff, alen - len);
-		err = ubifs_leb_change(c, lnum++, buf, alen, UBI_SHORTTERM);
+		err = ubifs_leb_change(c, lnum++, buf, alen);
 		if (err)
 			goto out;
 		p = buf;
@@ -826,7 +823,7 @@
 
 	/* Write remaining buffer */
 	memset(p, 0xff, alen - len);
-	err = ubifs_leb_change(c, lnum, buf, alen, UBI_SHORTTERM);
+	err = ubifs_leb_change(c, lnum, buf, alen);
 	if (err)
 		goto out;
 
@@ -926,7 +923,7 @@
 	if (crc != calc_crc) {
 		ubifs_err("invalid crc in LPT node: crc %hx calc %hx", crc,
 			  calc_crc);
-		dbg_dump_stack();
+		dump_stack();
 		return -EINVAL;
 	}
 	return 0;
@@ -949,7 +946,7 @@
 	if (node_type != type) {
 		ubifs_err("invalid type (%d) in LPT node type %d", node_type,
 			  type);
-		dbg_dump_stack();
+		dump_stack();
 		return -EINVAL;
 	}
 	return 0;
@@ -1247,7 +1244,7 @@
 
 out:
 	ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
-	dbg_dump_stack();
+	dump_stack();
 	kfree(nnode);
 	return err;
 }
@@ -1312,8 +1309,8 @@
 
 out:
 	ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
-	dbg_dump_pnode(c, pnode, parent, iip);
-	dbg_dump_stack();
+	ubifs_dump_pnode(c, pnode, parent, iip);
+	dump_stack();
 	dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
 	kfree(pnode);
 	return err;
@@ -1740,16 +1737,20 @@
 	if (rd) {
 		err = lpt_init_rd(c);
 		if (err)
-			return err;
+			goto out_err;
 	}
 
 	if (wr) {
 		err = lpt_init_wr(c);
 		if (err)
-			return err;
+			goto out_err;
 	}
 
 	return 0;
+
+out_err:
+	ubifs_lpt_free(c, 0);
+	return err;
 }
 
 /**
@@ -2080,8 +2081,6 @@
 	return err;
 }
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
 /**
  * dbg_chk_pnode - check a pnode.
  * @c: the UBIFS file-system description object
@@ -2096,8 +2095,8 @@
 	int i;
 
 	if (pnode->num != col) {
-		dbg_err("pnode num %d expected %d parent num %d iip %d",
-			pnode->num, col, pnode->parent->num, pnode->iip);
+		ubifs_err("pnode num %d expected %d parent num %d iip %d",
+			  pnode->num, col, pnode->parent->num, pnode->iip);
 		return -EINVAL;
 	}
 	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
@@ -2111,14 +2110,14 @@
 		if (lnum >= c->leb_cnt)
 			continue;
 		if (lprops->lnum != lnum) {
-			dbg_err("bad LEB number %d expected %d",
-				lprops->lnum, lnum);
+			ubifs_err("bad LEB number %d expected %d",
+				  lprops->lnum, lnum);
 			return -EINVAL;
 		}
 		if (lprops->flags & LPROPS_TAKEN) {
 			if (cat != LPROPS_UNCAT) {
-				dbg_err("LEB %d taken but not uncat %d",
-					lprops->lnum, cat);
+				ubifs_err("LEB %d taken but not uncat %d",
+					  lprops->lnum, cat);
 				return -EINVAL;
 			}
 			continue;
@@ -2130,8 +2129,8 @@
 			case LPROPS_FRDI_IDX:
 				break;
 			default:
-				dbg_err("LEB %d index but cat %d",
-					lprops->lnum, cat);
+				ubifs_err("LEB %d index but cat %d",
+					  lprops->lnum, cat);
 				return -EINVAL;
 			}
 		} else {
@@ -2143,8 +2142,8 @@
 			case LPROPS_FREEABLE:
 				break;
 			default:
-				dbg_err("LEB %d not index but cat %d",
-					lprops->lnum, cat);
+				ubifs_err("LEB %d not index but cat %d",
+					  lprops->lnum, cat);
 				return -EINVAL;
 			}
 		}
@@ -2184,24 +2183,24 @@
 			break;
 		}
 		if (!found) {
-			dbg_err("LEB %d cat %d not found in cat heap/list",
-				lprops->lnum, cat);
+			ubifs_err("LEB %d cat %d not found in cat heap/list",
+				  lprops->lnum, cat);
 			return -EINVAL;
 		}
 		switch (cat) {
 		case LPROPS_EMPTY:
 			if (lprops->free != c->leb_size) {
-				dbg_err("LEB %d cat %d free %d dirty %d",
-					lprops->lnum, cat, lprops->free,
-					lprops->dirty);
+				ubifs_err("LEB %d cat %d free %d dirty %d",
+					  lprops->lnum, cat, lprops->free,
+					  lprops->dirty);
 				return -EINVAL;
 			}
 		case LPROPS_FREEABLE:
 		case LPROPS_FRDI_IDX:
 			if (lprops->free + lprops->dirty != c->leb_size) {
-				dbg_err("LEB %d cat %d free %d dirty %d",
-					lprops->lnum, cat, lprops->free,
-					lprops->dirty);
+				ubifs_err("LEB %d cat %d free %d dirty %d",
+					  lprops->lnum, cat, lprops->free,
+					  lprops->dirty);
 				return -EINVAL;
 			}
 		}
@@ -2235,9 +2234,10 @@
 			/* cnode is a nnode */
 			num = calc_nnode_num(row, col);
 			if (cnode->num != num) {
-				dbg_err("nnode num %d expected %d "
-					"parent num %d iip %d", cnode->num, num,
-					(nnode ? nnode->num : 0), cnode->iip);
+				ubifs_err("nnode num %d expected %d "
+					  "parent num %d iip %d",
+					  cnode->num, num,
+					  (nnode ? nnode->num : 0), cnode->iip);
 				return -EINVAL;
 			}
 			nn = (struct ubifs_nnode *)cnode;
@@ -2274,5 +2274,3 @@
 	}
 	return 0;
 }
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index cddd6bd..4fa7073 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -30,11 +30,7 @@
 #include <linux/random.h>
 #include "ubifs.h"
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
 static int dbg_populate_lsave(struct ubifs_info *c);
-#else
-#define dbg_populate_lsave(c) 0
-#endif
 
 /**
  * first_dirty_cnode - find first dirty cnode.
@@ -324,11 +320,10 @@
 	return 0;
 
 no_space:
-	ubifs_err("LPT out of space");
-	dbg_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, "
-		"done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
-	dbg_dump_lpt_info(c);
-	dbg_dump_lpt_lebs(c);
+	ubifs_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, "
+		  "done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
+	ubifs_dump_lpt_info(c);
+	ubifs_dump_lpt_lebs(c);
 	dump_stack();
 	return err;
 }
@@ -421,7 +416,7 @@
 				alen = ALIGN(wlen, c->min_io_size);
 				memset(buf + offs, 0xff, alen - wlen);
 				err = ubifs_leb_write(c, lnum, buf + from, from,
-						       alen, UBI_SHORTTERM);
+						       alen);
 				if (err)
 					return err;
 			}
@@ -479,8 +474,7 @@
 			wlen = offs - from;
 			alen = ALIGN(wlen, c->min_io_size);
 			memset(buf + offs, 0xff, alen - wlen);
-			err = ubifs_leb_write(c, lnum, buf + from, from, alen,
-					      UBI_SHORTTERM);
+			err = ubifs_leb_write(c, lnum, buf + from, from, alen);
 			if (err)
 				return err;
 			dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
@@ -506,8 +500,7 @@
 			wlen = offs - from;
 			alen = ALIGN(wlen, c->min_io_size);
 			memset(buf + offs, 0xff, alen - wlen);
-			err = ubifs_leb_write(c, lnum, buf + from, from, alen,
-					      UBI_SHORTTERM);
+			err = ubifs_leb_write(c, lnum, buf + from, from, alen);
 			if (err)
 				return err;
 			dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
@@ -531,7 +524,7 @@
 	wlen = offs - from;
 	alen = ALIGN(wlen, c->min_io_size);
 	memset(buf + offs, 0xff, alen - wlen);
-	err = ubifs_leb_write(c, lnum, buf + from, from, alen, UBI_SHORTTERM);
+	err = ubifs_leb_write(c, lnum, buf + from, from, alen);
 	if (err)
 		return err;
 
@@ -552,11 +545,10 @@
 	return 0;
 
 no_space:
-	ubifs_err("LPT out of space mismatch");
-	dbg_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab "
-		"%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
-	dbg_dump_lpt_info(c);
-	dbg_dump_lpt_lebs(c);
+	ubifs_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab "
+		  "%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
+	ubifs_dump_lpt_info(c);
+	ubifs_dump_lpt_lebs(c);
 	dump_stack();
 	return err;
 }
@@ -1497,7 +1489,9 @@
 	kfree(c->lpt_nod_buf);
 }
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
+/*
+ * Everything below is related to debugging.
+ */
 
 /**
  * dbg_is_all_ff - determine if a buffer contains only 0xFF bytes.
@@ -1735,7 +1729,7 @@
 	for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
 		err = dbg_check_ltab_lnum(c, lnum);
 		if (err) {
-			dbg_err("failed at LEB %d", lnum);
+			ubifs_err("failed at LEB %d", lnum);
 			return err;
 		}
 	}
@@ -1767,10 +1761,10 @@
 			free += c->leb_size;
 	}
 	if (free < c->lpt_sz) {
-		dbg_err("LPT space error: free %lld lpt_sz %lld",
-			free, c->lpt_sz);
-		dbg_dump_lpt_info(c);
-		dbg_dump_lpt_lebs(c);
+		ubifs_err("LPT space error: free %lld lpt_sz %lld",
+			  free, c->lpt_sz);
+		ubifs_dump_lpt_info(c);
+		ubifs_dump_lpt_lebs(c);
 		dump_stack();
 		return -EINVAL;
 	}
@@ -1807,13 +1801,13 @@
 		d->chk_lpt_lebs = 0;
 		d->chk_lpt_wastage = 0;
 		if (c->dirty_pn_cnt > c->pnode_cnt) {
-			dbg_err("dirty pnodes %d exceed max %d",
-				c->dirty_pn_cnt, c->pnode_cnt);
+			ubifs_err("dirty pnodes %d exceed max %d",
+				  c->dirty_pn_cnt, c->pnode_cnt);
 			err = -EINVAL;
 		}
 		if (c->dirty_nn_cnt > c->nnode_cnt) {
-			dbg_err("dirty nnodes %d exceed max %d",
-				c->dirty_nn_cnt, c->nnode_cnt);
+			ubifs_err("dirty nnodes %d exceed max %d",
+				  c->dirty_nn_cnt, c->nnode_cnt);
 			err = -EINVAL;
 		}
 		return err;
@@ -1830,23 +1824,23 @@
 		chk_lpt_sz *= d->chk_lpt_lebs;
 		chk_lpt_sz += len - c->nhead_offs;
 		if (d->chk_lpt_sz != chk_lpt_sz) {
-			dbg_err("LPT wrote %lld but space used was %lld",
-				d->chk_lpt_sz, chk_lpt_sz);
+			ubifs_err("LPT wrote %lld but space used was %lld",
+				  d->chk_lpt_sz, chk_lpt_sz);
 			err = -EINVAL;
 		}
 		if (d->chk_lpt_sz > c->lpt_sz) {
-			dbg_err("LPT wrote %lld but lpt_sz is %lld",
-				d->chk_lpt_sz, c->lpt_sz);
+			ubifs_err("LPT wrote %lld but lpt_sz is %lld",
+				  d->chk_lpt_sz, c->lpt_sz);
 			err = -EINVAL;
 		}
 		if (d->chk_lpt_sz2 && d->chk_lpt_sz != d->chk_lpt_sz2) {
-			dbg_err("LPT layout size %lld but wrote %lld",
-				d->chk_lpt_sz, d->chk_lpt_sz2);
+			ubifs_err("LPT layout size %lld but wrote %lld",
+				  d->chk_lpt_sz, d->chk_lpt_sz2);
 			err = -EINVAL;
 		}
 		if (d->chk_lpt_sz2 && d->new_nhead_offs != len) {
-			dbg_err("LPT new nhead offs: expected %d was %d",
-				d->new_nhead_offs, len);
+			ubifs_err("LPT new nhead offs: expected %d was %d",
+				  d->new_nhead_offs, len);
 			err = -EINVAL;
 		}
 		lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
@@ -1855,13 +1849,13 @@
 		if (c->big_lpt)
 			lpt_sz += c->lsave_sz;
 		if (d->chk_lpt_sz - d->chk_lpt_wastage > lpt_sz) {
-			dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
-				d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz);
+			ubifs_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
+				  d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz);
 			err = -EINVAL;
 		}
 		if (err) {
-			dbg_dump_lpt_info(c);
-			dbg_dump_lpt_lebs(c);
+			ubifs_dump_lpt_info(c);
+			ubifs_dump_lpt_lebs(c);
 			dump_stack();
 		}
 		d->chk_lpt_sz2 = d->chk_lpt_sz;
@@ -1880,7 +1874,7 @@
 }
 
 /**
- * dbg_dump_lpt_leb - dump an LPT LEB.
+ * ubifs_dump_lpt_leb - dump an LPT LEB.
  * @c: UBIFS file-system description object
  * @lnum: LEB number to dump
  *
@@ -1986,13 +1980,13 @@
 }
 
 /**
- * dbg_dump_lpt_lebs - dump LPT lebs.
+ * ubifs_dump_lpt_lebs - dump LPT lebs.
  * @c: UBIFS file-system description object
  *
  * This function dumps all LPT LEBs. The caller has to make sure the LPT is
  * locked.
  */
-void dbg_dump_lpt_lebs(const struct ubifs_info *c)
+void ubifs_dump_lpt_lebs(const struct ubifs_info *c)
 {
 	int i;
 
@@ -2046,5 +2040,3 @@
 
 	return 1;
 }
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index 278c238..ab83ace 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -241,7 +241,7 @@
 
 out:
 	ubifs_err("bad master node at offset %d error %d", c->mst_offs, err);
-	dbg_dump_node(c, c->mst_node);
+	ubifs_dump_node(c, c->mst_node);
 	return -EINVAL;
 }
 
@@ -317,7 +317,7 @@
 		if (c->leb_cnt < old_leb_cnt ||
 		    c->leb_cnt < UBIFS_MIN_LEB_CNT) {
 			ubifs_err("bad leb_cnt on master node");
-			dbg_dump_node(c, c->mst_node);
+			ubifs_dump_node(c, c->mst_node);
 			return -EINVAL;
 		}
 
@@ -379,7 +379,7 @@
 	c->mst_offs = offs;
 	c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
 
-	err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM);
+	err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
 	if (err)
 		return err;
 
@@ -390,7 +390,7 @@
 		if (err)
 			return err;
 	}
-	err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM);
+	err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
 
 	return err;
 }
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
index c542c73..b02734d 100644
--- a/fs/ubifs/orphan.c
+++ b/fs/ubifs/orphan.c
@@ -52,11 +52,7 @@
  * than the maximum number of orphans allowed.
  */
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
 static int dbg_check_orphans(struct ubifs_info *c);
-#else
-#define dbg_check_orphans(c) 0
-#endif
 
 /**
  * ubifs_add_orphan - add an orphan.
@@ -92,7 +88,7 @@
 		else if (inum > o->inum)
 			p = &(*p)->rb_right;
 		else {
-			dbg_err("orphaned twice");
+			ubifs_err("orphaned twice");
 			spin_unlock(&c->orphan_lock);
 			kfree(orphan);
 			return 0;
@@ -158,8 +154,8 @@
 		}
 	}
 	spin_unlock(&c->orphan_lock);
-	dbg_err("missing orphan ino %lu", (unsigned long)inum);
-	dbg_dump_stack();
+	ubifs_err("missing orphan ino %lu", (unsigned long)inum);
+	dump_stack();
 }
 
 /**
@@ -248,8 +244,7 @@
 		ubifs_assert(c->ohead_offs == 0);
 		ubifs_prepare_node(c, c->orph_buf, len, 1);
 		len = ALIGN(len, c->min_io_size);
-		err = ubifs_leb_change(c, c->ohead_lnum, c->orph_buf, len,
-				       UBI_SHORTTERM);
+		err = ubifs_leb_change(c, c->ohead_lnum, c->orph_buf, len);
 	} else {
 		if (c->ohead_offs == 0) {
 			/* Ensure LEB has been unmapped */
@@ -258,7 +253,7 @@
 				return err;
 		}
 		err = ubifs_write_node(c, c->orph_buf, len, c->ohead_lnum,
-				       c->ohead_offs, UBI_SHORTTERM);
+				       c->ohead_offs);
 	}
 	return err;
 }
@@ -569,7 +564,7 @@
 		if (snod->type != UBIFS_ORPH_NODE) {
 			ubifs_err("invalid node type %d in orphan area at "
 				  "%d:%d", snod->type, sleb->lnum, snod->offs);
-			dbg_dump_node(c, snod->node);
+			ubifs_dump_node(c, snod->node);
 			return -EINVAL;
 		}
 
@@ -597,7 +592,7 @@
 				ubifs_err("out of order commit number %llu in "
 					  "orphan node at %d:%d",
 					  cmt_no, sleb->lnum, snod->offs);
-				dbg_dump_node(c, snod->node);
+				ubifs_dump_node(c, snod->node);
 				return -EINVAL;
 			}
 			dbg_rcvry("out of date LEB %d", sleb->lnum);
@@ -725,7 +720,9 @@
 	return err;
 }
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
+/*
+ * Everything below is related to debugging.
+ */
 
 struct check_orphan {
 	struct rb_node rb;
@@ -968,5 +965,3 @@
 	kfree(ci.node);
 	return err;
 }
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 2a935b3..c30d976b 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -213,10 +213,10 @@
 	mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
 
 	ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
-	err = ubifs_leb_change(c, lnum, mst, sz, UBI_SHORTTERM);
+	err = ubifs_leb_change(c, lnum, mst, sz);
 	if (err)
 		goto out;
-	err = ubifs_leb_change(c, lnum + 1, mst, sz, UBI_SHORTTERM);
+	err = ubifs_leb_change(c, lnum + 1, mst, sz);
 	if (err)
 		goto out;
 out:
@@ -362,12 +362,12 @@
 out_free:
 	ubifs_err("failed to recover master node");
 	if (mst1) {
-		dbg_err("dumping first master node");
-		dbg_dump_node(c, mst1);
+		ubifs_err("dumping first master node");
+		ubifs_dump_node(c, mst1);
 	}
 	if (mst2) {
-		dbg_err("dumping second master node");
-		dbg_dump_node(c, mst2);
+		ubifs_err("dumping second master node");
+		ubifs_dump_node(c, mst2);
 	}
 	vfree(buf2);
 	vfree(buf1);
@@ -555,8 +555,7 @@
 					ubifs_pad(c, buf, pad_len);
 				}
 			}
-			err = ubifs_leb_change(c, lnum, sleb->buf, len,
-					       UBI_UNKNOWN);
+			err = ubifs_leb_change(c, lnum, sleb->buf, len);
 			if (err)
 				return err;
 		}
@@ -683,7 +682,7 @@
 				  ret, lnum, offs);
 			break;
 		} else {
-			dbg_err("unexpected return value %d", ret);
+			ubifs_err("unexpected return value %d", ret);
 			err = -EINVAL;
 			goto error;
 		}
@@ -789,7 +788,7 @@
 
 corrupted_rescan:
 	/* Re-scan the corrupted data with verbose messages */
-	dbg_err("corruptio %d", ret);
+	ubifs_err("corruptio %d", ret);
 	ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
 corrupted:
 	ubifs_scanned_corruption(c, lnum, offs, buf);
@@ -827,17 +826,17 @@
 		goto out_free;
 	ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
 	if (ret != SCANNED_A_NODE) {
-		dbg_err("Not a valid node");
+		ubifs_err("Not a valid node");
 		goto out_err;
 	}
 	if (cs_node->ch.node_type != UBIFS_CS_NODE) {
-		dbg_err("Node a CS node, type is %d", cs_node->ch.node_type);
+		ubifs_err("Node a CS node, type is %d", cs_node->ch.node_type);
 		goto out_err;
 	}
 	if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) {
-		dbg_err("CS node cmt_no %llu != current cmt_no %llu",
-			(unsigned long long)le64_to_cpu(cs_node->cmt_no),
-			c->cmt_no);
+		ubifs_err("CS node cmt_no %llu != current cmt_no %llu",
+			  (unsigned long long)le64_to_cpu(cs_node->cmt_no),
+			  c->cmt_no);
 		goto out_err;
 	}
 	*cs_sqnum = le64_to_cpu(cs_node->ch.sqnum);
@@ -941,7 +940,7 @@
 		err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
 		if (err)
 			return err;
-		return ubifs_leb_change(c, lnum, sbuf, offs, UBI_UNKNOWN);
+		return ubifs_leb_change(c, lnum, sbuf, offs);
 	}
 
 	return 0;
@@ -1071,7 +1070,7 @@
 	}
 
 	/* Write back the LEB atomically */
-	err = ubifs_leb_change(c, lnum, sbuf, len, UBI_UNKNOWN);
+	err = ubifs_leb_change(c, lnum, sbuf, len);
 	if (err)
 		return err;
 
@@ -1138,9 +1137,9 @@
 	 */
 	lnum = ubifs_find_free_leb_for_idx(c);
 	if (lnum < 0) {
-		dbg_err("could not find an empty LEB");
-		dbg_dump_lprops(c);
-		dbg_dump_budg(c, &c->bi);
+		ubifs_err("could not find an empty LEB");
+		ubifs_dump_lprops(c);
+		ubifs_dump_budg(c, &c->bi);
 		return lnum;
 	}
 
@@ -1218,7 +1217,7 @@
 	}
 	mutex_unlock(&wbuf->io_mutex);
 	if (err < 0) {
-		dbg_err("GC failed, error %d", err);
+		ubifs_err("GC failed, error %d", err);
 		if (err == -EAGAIN)
 			err = -EINVAL;
 		return err;
@@ -1472,7 +1471,7 @@
 		len -= 1;
 	len = ALIGN(len + 1, c->min_io_size);
 	/* Atomically write the fixed LEB back again */
-	err = ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
+	err = ubifs_leb_change(c, lnum, c->sbuf, len);
 	if (err)
 		goto out;
 	dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index b007637..3a2da7e 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -154,8 +154,7 @@
 
 	/* Make sure the journal head points to the latest bud */
 	err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
-				     b->bud->lnum, c->leb_size - b->free,
-				     UBI_SHORTTERM);
+				     b->bud->lnum, c->leb_size - b->free);
 
 out:
 	ubifs_release_lprops(c);
@@ -686,7 +685,7 @@
 
 out_dump:
 	ubifs_err("bad node is at LEB %d:%d", lnum, snod->offs);
-	dbg_dump_node(c, snod->node);
+	ubifs_dump_node(c, snod->node);
 	ubifs_scan_destroy(sleb);
 	return -EINVAL;
 }
@@ -861,16 +860,16 @@
 		 * numbers.
 		 */
 		if (snod->type != UBIFS_CS_NODE) {
-			dbg_err("first log node at LEB %d:%d is not CS node",
-				lnum, offs);
+			ubifs_err("first log node at LEB %d:%d is not CS node",
+				  lnum, offs);
 			goto out_dump;
 		}
 		if (le64_to_cpu(node->cmt_no) != c->cmt_no) {
-			dbg_err("first CS node at LEB %d:%d has wrong "
-				"commit number %llu expected %llu",
-				lnum, offs,
-				(unsigned long long)le64_to_cpu(node->cmt_no),
-				c->cmt_no);
+			ubifs_err("first CS node at LEB %d:%d has wrong "
+				  "commit number %llu expected %llu",
+				  lnum, offs,
+				  (unsigned long long)le64_to_cpu(node->cmt_no),
+				  c->cmt_no);
 			goto out_dump;
 		}
 
@@ -892,7 +891,7 @@
 
 	/* Make sure the first node sits at offset zero of the LEB */
 	if (snod->offs != 0) {
-		dbg_err("first node is not at zero offset");
+		ubifs_err("first node is not at zero offset");
 		goto out_dump;
 	}
 
@@ -905,8 +904,8 @@
 		}
 
 		if (snod->sqnum < c->cs_sqnum) {
-			dbg_err("bad sqnum %llu, commit sqnum %llu",
-				snod->sqnum, c->cs_sqnum);
+			ubifs_err("bad sqnum %llu, commit sqnum %llu",
+				  snod->sqnum, c->cs_sqnum);
 			goto out_dump;
 		}
 
@@ -958,7 +957,7 @@
 out_dump:
 	ubifs_err("log error detected while replaying the log at LEB %d:%d",
 		  lnum, offs + snod->offs);
-	dbg_dump_node(c, snod->node);
+	ubifs_dump_node(c, snod->node);
 	ubifs_scan_destroy(sleb);
 	return -EINVAL;
 }
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 771f7fb..ef3d1ba 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -130,7 +130,6 @@
 	 * orphan node.
 	 */
 	orph_lebs = UBIFS_MIN_ORPH_LEBS;
-#ifdef CONFIG_UBIFS_FS_DEBUG
 	if (c->leb_cnt - min_leb_cnt > 1)
 		/*
 		 * For debugging purposes it is better to have at least 2
@@ -138,7 +137,6 @@
 		 * consolidations and would be stressed more.
 		 */
 		orph_lebs += 1;
-#endif
 
 	main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs;
 	main_lebs -= orph_lebs;
@@ -196,7 +194,7 @@
 	sup->rp_size = cpu_to_le64(tmp64);
 	sup->ro_compat_version = cpu_to_le32(UBIFS_RO_COMPAT_VERSION);
 
-	err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0, UBI_LONGTERM);
+	err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0);
 	kfree(sup);
 	if (err)
 		return err;
@@ -252,14 +250,13 @@
 
 	mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ);
 
-	err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0,
-			       UBI_UNKNOWN);
+	err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0);
 	if (err) {
 		kfree(mst);
 		return err;
 	}
-	err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1, 0,
-			       UBI_UNKNOWN);
+	err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1,
+			       0);
 	kfree(mst);
 	if (err)
 		return err;
@@ -282,8 +279,7 @@
 	key_write_idx(c, &key, &br->key);
 	br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB);
 	br->len  = cpu_to_le32(UBIFS_INO_NODE_SZ);
-	err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0,
-			       UBI_UNKNOWN);
+	err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0);
 	kfree(idx);
 	if (err)
 		return err;
@@ -315,8 +311,7 @@
 	ino->flags = cpu_to_le32(UBIFS_COMPR_FL);
 
 	err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ,
-			       main_first + DEFAULT_DATA_LEB, 0,
-			       UBI_UNKNOWN);
+			       main_first + DEFAULT_DATA_LEB, 0);
 	kfree(ino);
 	if (err)
 		return err;
@@ -335,8 +330,7 @@
 		return -ENOMEM;
 
 	cs->ch.node_type = UBIFS_CS_NODE;
-	err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM,
-			       0, UBI_UNKNOWN);
+	err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM, 0);
 	kfree(cs);
 
 	ubifs_msg("default file-system created");
@@ -475,7 +469,7 @@
 
 failed:
 	ubifs_err("bad superblock, error %d", err);
-	dbg_dump_node(c, sup);
+	ubifs_dump_node(c, sup);
 	return -EINVAL;
 }
 
@@ -518,7 +512,7 @@
 	int len = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
 
 	ubifs_prepare_node(c, sup, UBIFS_SB_NODE_SZ, 1);
-	return ubifs_leb_change(c, UBIFS_SB_LNUM, sup, len, UBI_LONGTERM);
+	return ubifs_leb_change(c, UBIFS_SB_LNUM, sup, len);
 }
 
 /**
@@ -691,7 +685,7 @@
 	if (err)
 		return err;
 
-	return ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
+	return ubifs_leb_change(c, lnum, c->sbuf, len);
 }
 
 /**
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
index 37383e8..7c40e602 100644
--- a/fs/ubifs/scan.c
+++ b/fs/ubifs/scan.c
@@ -101,7 +101,7 @@
 			if (!quiet) {
 				ubifs_err("bad pad node at LEB %d:%d",
 					  lnum, offs);
-				dbg_dump_node(c, pad);
+				ubifs_dump_node(c, pad);
 			}
 			return SCANNED_A_BAD_PAD_NODE;
 		}
@@ -109,8 +109,8 @@
 		/* Make the node pads to 8-byte boundary */
 		if ((node_len + pad_len) & 7) {
 			if (!quiet)
-				dbg_err("bad padding length %d - %d",
-					offs, offs + node_len + pad_len);
+				ubifs_err("bad padding length %d - %d",
+					  offs, offs + node_len + pad_len);
 			return SCANNED_A_BAD_PAD_NODE;
 		}
 
@@ -245,7 +245,7 @@
 	len = c->leb_size - offs;
 	if (len > 8192)
 		len = 8192;
-	dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs);
+	ubifs_err("first %d bytes from LEB %d:%d", len, lnum, offs);
 	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1);
 }
 
@@ -300,16 +300,16 @@
 
 		switch (ret) {
 		case SCANNED_GARBAGE:
-			dbg_err("garbage");
+			ubifs_err("garbage");
 			goto corrupted;
 		case SCANNED_A_NODE:
 			break;
 		case SCANNED_A_CORRUPT_NODE:
 		case SCANNED_A_BAD_PAD_NODE:
-			dbg_err("bad node");
+			ubifs_err("bad node");
 			goto corrupted;
 		default:
-			dbg_err("unknown");
+			ubifs_err("unknown");
 			err = -EINVAL;
 			goto error;
 		}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 76e4e05..001accc 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -246,8 +246,8 @@
 
 out_invalid:
 	ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err);
-	dbg_dump_node(c, ino);
-	dbg_dump_inode(c, inode);
+	ubifs_dump_node(c, ino);
+	ubifs_dump_inode(c, inode);
 	err = -EINVAL;
 out_ino:
 	kfree(ino);
@@ -668,8 +668,8 @@
 	tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt;
 	tmp = ALIGN(tmp, c->min_io_size);
 	if (tmp > c->leb_size) {
-		dbg_err("too small LEB size %d, at least %d needed",
-			c->leb_size, tmp);
+		ubifs_err("too small LEB size %d, at least %d needed",
+			  c->leb_size, tmp);
 		return -EINVAL;
 	}
 
@@ -683,8 +683,8 @@
 	tmp /= c->leb_size;
 	tmp += 1;
 	if (c->log_lebs < tmp) {
-		dbg_err("too small log %d LEBs, required min. %d LEBs",
-			c->log_lebs, tmp);
+		ubifs_err("too small log %d LEBs, required min. %d LEBs",
+			  c->log_lebs, tmp);
 		return -EINVAL;
 	}
 
@@ -813,13 +813,10 @@
 		c->jheads[i].grouped = 1;
 	}
 
-	c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM;
 	/*
-	 * Garbage Collector head likely contains long-term data and
-	 * does not need to be synchronized by timer. Also GC head nodes are
-	 * not grouped.
+	 * Garbage Collector head does not need to be synchronized by timer.
+	 * Also GC head nodes are not grouped.
 	 */
-	c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
 	c->jheads[GCHD].wbuf.no_timer = 1;
 	c->jheads[GCHD].grouped = 0;
 
@@ -863,7 +860,7 @@
 		orph = list_entry(c->orph_list.next, struct ubifs_orphan, list);
 		list_del(&orph->list);
 		kfree(orph);
-		dbg_err("orphan list not empty at unmount");
+		ubifs_err("orphan list not empty at unmount");
 	}
 
 	vfree(c->orph_buf);
@@ -1147,8 +1144,8 @@
 	ubifs_assert(c->dark_wm > 0);
 	if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
 		ubifs_err("insufficient free space to mount in R/W mode");
-		dbg_dump_budg(c, &c->bi);
-		dbg_dump_lprops(c);
+		ubifs_dump_budg(c, &c->bi);
+		ubifs_dump_lprops(c);
 		return -ENOSPC;
 	}
 	return 0;
@@ -1301,7 +1298,7 @@
 	if (!c->ro_mount && c->space_fixup) {
 		err = ubifs_fixup_free_space(c);
 		if (err)
-			goto out_master;
+			goto out_lpt;
 	}
 
 	if (!c->ro_mount) {
@@ -2126,8 +2123,8 @@
 	 */
 	ubi = open_ubi(name, UBI_READONLY);
 	if (IS_ERR(ubi)) {
-		dbg_err("cannot open \"%s\", error %d",
-			name, (int)PTR_ERR(ubi));
+		ubifs_err("cannot open \"%s\", error %d",
+			  name, (int)PTR_ERR(ubi));
 		return ERR_CAST(ubi);
 	}
 
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index abd5133..349f31a 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -339,8 +339,8 @@
 
 	err = ubifs_validate_entry(c, dent);
 	if (err) {
-		dbg_dump_stack();
-		dbg_dump_node(c, dent);
+		dump_stack();
+		ubifs_dump_node(c, dent);
 		return err;
 	}
 
@@ -372,8 +372,8 @@
 
 	err = ubifs_validate_entry(c, node);
 	if (err) {
-		dbg_dump_stack();
-		dbg_dump_node(c, node);
+		dump_stack();
+		ubifs_dump_node(c, node);
 		return err;
 	}
 
@@ -1733,8 +1733,8 @@
 	err = -EINVAL;
 out:
 	ubifs_err("bad node at LEB %d:%d", zbr->lnum, zbr->offs);
-	dbg_dump_node(c, buf);
-	dbg_dump_stack();
+	ubifs_dump_node(c, buf);
+	dump_stack();
 	return err;
 }
 
@@ -1775,7 +1775,7 @@
 	if (err && err != -EBADMSG) {
 		ubifs_err("failed to read from LEB %d:%d, error %d",
 			  lnum, offs, err);
-		dbg_dump_stack();
+		dump_stack();
 		dbg_tnck(&bu->key, "key ");
 		return err;
 	}
@@ -2403,7 +2403,7 @@
 
 	err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
 	if (err) {
-		dbg_dump_znode(c, znode);
+		ubifs_dump_znode(c, znode);
 		return err;
 	}
 
@@ -2649,7 +2649,7 @@
 			err = ubifs_add_dirt(c, znode->zbranch[i].lnum,
 					     znode->zbranch[i].len);
 			if (err) {
-				dbg_dump_znode(c, znode);
+				ubifs_dump_znode(c, znode);
 				goto out_unlock;
 			}
 			dbg_tnck(key, "removing key ");
@@ -3275,8 +3275,6 @@
 	return err;
 }
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
 /**
  * dbg_check_inode_size - check if inode size is correct.
  * @c: UBIFS file-system description object
@@ -3335,13 +3333,11 @@
 		  (unsigned long)inode->i_ino, size,
 		  ((loff_t)block) << UBIFS_BLOCK_SHIFT);
 	mutex_unlock(&c->tnc_mutex);
-	dbg_dump_inode(c, inode);
-	dbg_dump_stack();
+	ubifs_dump_inode(c, inode);
+	dump_stack();
 	return -EINVAL;
 
 out_unlock:
 	mutex_unlock(&c->tnc_mutex);
 	return err;
 }
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
index 4c15f07..523bbad 100644
--- a/fs/ubifs/tnc_commit.c
+++ b/fs/ubifs/tnc_commit.c
@@ -54,18 +54,16 @@
 		br->len = cpu_to_le32(zbr->len);
 		if (!zbr->lnum || !zbr->len) {
 			ubifs_err("bad ref in znode");
-			dbg_dump_znode(c, znode);
+			ubifs_dump_znode(c, znode);
 			if (zbr->znode)
-				dbg_dump_znode(c, zbr->znode);
+				ubifs_dump_znode(c, zbr->znode);
 		}
 	}
 	ubifs_prepare_node(c, idx, len, 0);
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
 	znode->lnum = lnum;
 	znode->offs = offs;
 	znode->len = len;
-#endif
 
 	err = insert_old_idx_znode(c, znode);
 
@@ -322,8 +320,7 @@
 				  0, 0, 0);
 	if (err)
 		return err;
-	err = ubifs_leb_change(c, lnum, c->ileb_buf, c->ileb_len,
-			       UBI_SHORTTERM);
+	err = ubifs_leb_change(c, lnum, c->ileb_buf, c->ileb_len);
 	if (err)
 		return err;
 	dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
@@ -388,8 +385,8 @@
 				 * option which forces in-the-gaps is enabled.
 				 */
 				ubifs_warn("out of space");
-				dbg_dump_budg(c, &c->bi);
-				dbg_dump_lprops(c);
+				ubifs_dump_budg(c, &c->bi);
+				ubifs_dump_lprops(c);
 			}
 			/* Try to commit anyway */
 			err = 0;
@@ -456,11 +453,9 @@
 
 		offs = buf_offs + used;
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
 		znode->lnum = lnum;
 		znode->offs = offs;
 		znode->len = len;
-#endif
 
 		/* Update the parent */
 		zp = znode->parent;
@@ -536,10 +531,8 @@
 		break;
 	}
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
 	c->dbg->new_ihead_lnum = lnum;
 	c->dbg->new_ihead_offs = buf_offs;
-#endif
 
 	return 0;
 }
@@ -864,9 +857,9 @@
 			br->len = cpu_to_le32(zbr->len);
 			if (!zbr->lnum || !zbr->len) {
 				ubifs_err("bad ref in znode");
-				dbg_dump_znode(c, znode);
+				ubifs_dump_znode(c, znode);
 				if (zbr->znode)
-					dbg_dump_znode(c, zbr->znode);
+					ubifs_dump_znode(c, zbr->znode);
 			}
 		}
 		len = ubifs_idx_node_sz(c, znode->child_cnt);
@@ -881,13 +874,11 @@
 		}
 		offs = buf_offs + used;
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
 		if (lnum != znode->lnum || offs != znode->offs ||
 		    len != znode->len) {
 			ubifs_err("inconsistent znode posn");
 			return -EINVAL;
 		}
-#endif
 
 		/* Grab some stuff from znode while we still can */
 		cnext = znode->cnext;
@@ -959,8 +950,7 @@
 		}
 
 		/* The buffer is full or there are no more znodes to do */
-		err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
-				      UBI_SHORTTERM);
+		err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen);
 		if (err)
 			return err;
 		buf_offs += blen;
@@ -982,13 +972,11 @@
 		break;
 	}
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
 	if (lnum != c->dbg->new_ihead_lnum ||
 	    buf_offs != c->dbg->new_ihead_offs) {
 		ubifs_err("inconsistent ihead");
 		return -EINVAL;
 	}
-#endif
 
 	c->ihead_lnum = lnum;
 	c->ihead_offs = buf_offs;
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
index dc28fe6..d38ac7f 100644
--- a/fs/ubifs/tnc_misc.c
+++ b/fs/ubifs/tnc_misc.c
@@ -293,10 +293,10 @@
 		lnum, offs, znode->level, znode->child_cnt);
 
 	if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) {
-		dbg_err("current fanout %d, branch count %d",
-			c->fanout, znode->child_cnt);
-		dbg_err("max levels %d, znode level %d",
-			UBIFS_MAX_LEVELS, znode->level);
+		ubifs_err("current fanout %d, branch count %d",
+			  c->fanout, znode->child_cnt);
+		ubifs_err("max levels %d, znode level %d",
+			  UBIFS_MAX_LEVELS, znode->level);
 		err = 1;
 		goto out_dump;
 	}
@@ -316,7 +316,7 @@
 		if (zbr->lnum < c->main_first ||
 		    zbr->lnum >= c->leb_cnt || zbr->offs < 0 ||
 		    zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) {
-			dbg_err("bad branch %d", i);
+			ubifs_err("bad branch %d", i);
 			err = 2;
 			goto out_dump;
 		}
@@ -340,19 +340,19 @@
 		type = key_type(c, &zbr->key);
 		if (c->ranges[type].max_len == 0) {
 			if (zbr->len != c->ranges[type].len) {
-				dbg_err("bad target node (type %d) length (%d)",
-					type, zbr->len);
-				dbg_err("have to be %d", c->ranges[type].len);
+				ubifs_err("bad target node (type %d) length (%d)",
+					  type, zbr->len);
+				ubifs_err("have to be %d", c->ranges[type].len);
 				err = 4;
 				goto out_dump;
 			}
 		} else if (zbr->len < c->ranges[type].min_len ||
 			   zbr->len > c->ranges[type].max_len) {
-			dbg_err("bad target node (type %d) length (%d)",
-				type, zbr->len);
-			dbg_err("have to be in range of %d-%d",
-				c->ranges[type].min_len,
-				c->ranges[type].max_len);
+			ubifs_err("bad target node (type %d) length (%d)",
+				  type, zbr->len);
+			ubifs_err("have to be in range of %d-%d",
+				  c->ranges[type].min_len,
+				  c->ranges[type].max_len);
 			err = 5;
 			goto out_dump;
 		}
@@ -370,13 +370,13 @@
 
 		cmp = keys_cmp(c, key1, key2);
 		if (cmp > 0) {
-			dbg_err("bad key order (keys %d and %d)", i, i + 1);
+			ubifs_err("bad key order (keys %d and %d)", i, i + 1);
 			err = 6;
 			goto out_dump;
 		} else if (cmp == 0 && !is_hash_key(c, key1)) {
 			/* These can only be keys with colliding hash */
-			dbg_err("keys %d and %d are not hashed but equivalent",
-				i, i + 1);
+			ubifs_err("keys %d and %d are not hashed but equivalent",
+				  i, i + 1);
 			err = 7;
 			goto out_dump;
 		}
@@ -387,7 +387,7 @@
 
 out_dump:
 	ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
-	dbg_dump_node(c, idx);
+	ubifs_dump_node(c, idx);
 	kfree(idx);
 	return -EINVAL;
 }
@@ -486,7 +486,7 @@
 			  zbr->lnum, zbr->offs);
 		dbg_tnck(key, "looked for key ");
 		dbg_tnck(&key1, "but found node's key ");
-		dbg_dump_node(c, node);
+		ubifs_dump_node(c, node);
 		return -EINVAL;
 	}
 
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 93d59ac..1e5a086 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -650,8 +650,6 @@
  * @avail: number of bytes available in the write-buffer
  * @used:  number of used bytes in the write-buffer
  * @size: write-buffer size (in [@c->min_io_size, @c->max_write_size] range)
- * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM,
- * %UBI_UNKNOWN)
  * @jhead: journal head the mutex belongs to (note, needed only to shut lockdep
  *         up by 'mutex_lock_nested()).
  * @sync_callback: write-buffer synchronization callback
@@ -685,7 +683,6 @@
 	int avail;
 	int used;
 	int size;
-	int dtype;
 	int jhead;
 	int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
 	struct mutex io_mutex;
@@ -762,6 +759,9 @@
  * @offs: offset of the corresponding indexing node
  * @len: length  of the corresponding indexing node
  * @zbranch: array of znode branches (@c->fanout elements)
+ *
+ * Note! The @lnum, @offs, and @len fields are not really needed - we have them
+ * only for internal consistency check. They could be removed to save some RAM.
  */
 struct ubifs_znode {
 	struct ubifs_znode *parent;
@@ -772,9 +772,9 @@
 	int child_cnt;
 	int iip;
 	int alt;
-#ifdef CONFIG_UBIFS_FS_DEBUG
-	int lnum, offs, len;
-#endif
+	int lnum;
+	int offs;
+	int len;
 	struct ubifs_zbranch zbranch[];
 };
 
@@ -1444,9 +1444,7 @@
 	struct rb_root size_tree;
 	struct ubifs_mount_opts mount_opts;
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
 	struct ubifs_debug_info *dbg;
-#endif
 };
 
 extern struct list_head ubifs_infos;
@@ -1468,22 +1466,20 @@
 int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
 		   int len, int even_ebadmsg);
 int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
-		    int len, int dtype);
-int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
-		     int dtype);
+		    int len);
+int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len);
 int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
-int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype);
+int ubifs_leb_map(struct ubifs_info *c, int lnum);
 int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
 int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
-int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
-			   int dtype);
+int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs);
 int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf);
 int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
 		    int lnum, int offs);
 int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
 			 int lnum, int offs);
 int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
-		     int offs, int dtype);
+		     int offs);
 int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
 		     int offs, int quiet, int must_chk_crc);
 void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 7a8bafa..0f7139b 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -399,8 +399,8 @@
 	if (buf) {
 		/* If @buf is %NULL we are supposed to return the length */
 		if (ui->data_len > size) {
-			dbg_err("buffer size %zd, xattr len %d",
-				size, ui->data_len);
+			ubifs_err("buffer size %zd, xattr len %d",
+				  size, ui->data_len);
 			err = -ERANGE;
 			goto out_iput;
 		}
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index f1c8ca6..b0d6282 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -51,6 +51,37 @@
 			struct acpi_object_list *arguments,
 			struct acpi_handle_list *list);
 
+struct acpi_pld {
+	unsigned int revision:7; /* 0 */
+	unsigned int ignore_colour:1; /* 7 */
+	unsigned int colour:24; /* 8 */
+	unsigned int width:16; /* 32 */
+	unsigned int height:16; /* 48 */
+	unsigned int user_visible:1; /* 64 */
+	unsigned int dock:1; /* 65 */
+	unsigned int lid:1; /* 66 */
+	unsigned int panel:3; /* 67 */
+	unsigned int vertical_pos:2; /* 70 */
+	unsigned int horizontal_pos:2; /* 72 */
+	unsigned int shape:4; /* 74 */
+	unsigned int group_orientation:1; /* 78 */
+	unsigned int group_token:8; /* 79 */
+	unsigned int group_position:8; /* 87 */
+	unsigned int bay:1; /* 95 */
+	unsigned int ejectable:1; /* 96 */
+	unsigned int ospm_eject_required:1; /* 97 */
+	unsigned int cabinet_number:8; /* 98 */
+	unsigned int card_cage_number:8; /* 106 */
+	unsigned int reference:1; /* 114 */
+	unsigned int rotation:4; /* 115 */
+	unsigned int order:5; /* 119 */
+	unsigned int reserved:4; /* 124 */
+	unsigned int vertical_offset:16; /* 128 */
+	unsigned int horizontal_offset:16; /* 144 */
+} __attribute__((__packed__));
+
+acpi_status
+acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld *pld);
 #ifdef CONFIG_ACPI
 
 #include <linux/proc_fs.h>
@@ -407,6 +438,11 @@
 }
 #endif
 
+#else	/* CONFIG_ACPI */
+
+static int register_acpi_bus_type(struct acpi_bus_type *bus) { return 0; }
+static int unregister_acpi_bus_type(struct acpi_bus_type *bus) { return 0; }
+
 #endif				/* CONFIG_ACPI */
 
 #endif /*__ACPI_BUS_H__*/
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8aeadf6..4e2e1cc 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -486,8 +486,8 @@
 	CPU_DISCARD(init.data)						\
 	MEM_DISCARD(init.data)						\
 	KERNEL_CTORS()							\
-	*(.init.rodata)							\
 	MCOUNT_REC()							\
+	*(.init.rodata)							\
 	FTRACE_EVENTS()							\
 	TRACE_SYSCALLS()						\
 	DEV_DISCARD(init.rodata)					\
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 233f423..4cd59b9 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -238,6 +238,7 @@
 header-y += matroxfb.h
 header-y += mdio.h
 header-y += media.h
+header-y += mei.h
 header-y += mempolicy.h
 header-y += meye.h
 header-y += mii.h
@@ -381,7 +382,9 @@
 header-y += usbdevice_fs.h
 header-y += utime.h
 header-y += utsname.h
+header-y += uuid.h
 header-y += uvcvideo.h
+header-y += v4l2-dv-timings.h
 header-y += v4l2-mediabus.h
 header-y += v4l2-subdev.h
 header-y += veth.h
diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h
index 975009e..96c5c24 100644
--- a/include/linux/alarmtimer.h
+++ b/include/linux/alarmtimer.h
@@ -76,4 +76,7 @@
 }
 
 
+/* Provide way to access the rtc device being used by alarmtimers */
+struct rtc_device *alarmtimer_get_rtcdev(void);
+
 #endif
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 747f2ca..8deaf6d 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -144,6 +144,7 @@
 	u8 core_unit;
 
 	u32 addr;
+	u32 addr1;
 	u32 wrap;
 
 	void __iomem *io_addr;
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 12d52de..68d56ef 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -360,8 +360,11 @@
 
 #define CAP_WAKE_ALARM            35
 
+/* Allow preventing system suspends while epoll events are pending */
 
-#define CAP_LAST_CAP         CAP_WAKE_ALARM
+#define CAP_EPOLLWAKEUP      36
+
+#define CAP_LAST_CAP         CAP_EPOLLWAKEUP
 
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 
@@ -374,6 +377,7 @@
 
 #ifdef __KERNEL__
 
+struct inode;
 struct dentry;
 struct user_namespace;
 
@@ -548,6 +552,7 @@
 extern bool capable(int cap);
 extern bool ns_capable(struct user_namespace *ns, int cap);
 extern bool nsown_capable(int cap);
+extern bool inode_capable(const struct inode *inode, int cap);
 
 /* audit system wants to get cap info from files as well */
 extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 5a85b34..d3f5fba 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -16,6 +16,7 @@
 #include <linux/prio_heap.h>
 #include <linux/rwsem.h>
 #include <linux/idr.h>
+#include <linux/workqueue.h>
 
 #ifdef CONFIG_CGROUPS
 
@@ -76,12 +77,16 @@
 	unsigned long flags;
 	/* ID for this css, if possible */
 	struct css_id __rcu *id;
+
+	/* Used to put @cgroup->dentry on the last css_put() */
+	struct work_struct dput_work;
 };
 
 /* bits in struct cgroup_subsys_state flags field */
 enum {
 	CSS_ROOT, /* This CSS is the root of the subsystem */
 	CSS_REMOVED, /* This CSS is dead */
+	CSS_CLEAR_CSS_REFS,		/* @ss->__DEPRECATED_clear_css_refs */
 };
 
 /* Caller must verify that the css is not for root cgroup */
@@ -115,16 +120,12 @@
  * the css has been destroyed.
  */
 
+extern bool __css_tryget(struct cgroup_subsys_state *css);
 static inline bool css_tryget(struct cgroup_subsys_state *css)
 {
 	if (test_bit(CSS_ROOT, &css->flags))
 		return true;
-	while (!atomic_inc_not_zero(&css->refcnt)) {
-		if (test_bit(CSS_REMOVED, &css->flags))
-			return false;
-		cpu_relax();
-	}
-	return true;
+	return __css_tryget(css);
 }
 
 /*
@@ -132,11 +133,11 @@
  * css_get() or css_tryget()
  */
 
-extern void __css_put(struct cgroup_subsys_state *css, int count);
+extern void __css_put(struct cgroup_subsys_state *css);
 static inline void css_put(struct cgroup_subsys_state *css)
 {
 	if (!test_bit(CSS_ROOT, &css->flags))
-		__css_put(css, 1);
+		__css_put(css);
 }
 
 /* bits in struct cgroup flags field */
@@ -175,6 +176,7 @@
 	 */
 	struct list_head sibling;	/* my parent's children */
 	struct list_head children;	/* my children */
+	struct list_head files;		/* my files */
 
 	struct cgroup *parent;		/* my parent */
 	struct dentry __rcu *dentry;	/* cgroup fs entry, RCU protected */
@@ -191,6 +193,9 @@
 	 */
 	struct list_head css_sets;
 
+	struct list_head allcg_node;	/* cgroupfs_root->allcg_list */
+	struct list_head cft_q_node;	/* used during cftype add/rm */
+
 	/*
 	 * Linked list running through all cgroups that can
 	 * potentially be reaped by the release agent. Protected by
@@ -275,11 +280,17 @@
  *	- the 'cftype' of the file is file->f_dentry->d_fsdata
  */
 
-#define MAX_CFTYPE_NAME 64
+/* cftype->flags */
+#define CFTYPE_ONLY_ON_ROOT	(1U << 0)	/* only create on root cg */
+#define CFTYPE_NOT_ON_ROOT	(1U << 1)	/* don't create onp root cg */
+
+#define MAX_CFTYPE_NAME		64
+
 struct cftype {
 	/*
 	 * By convention, the name should begin with the name of the
-	 * subsystem, followed by a period
+	 * subsystem, followed by a period.  Zero length string indicates
+	 * end of cftype array.
 	 */
 	char name[MAX_CFTYPE_NAME];
 	int private;
@@ -295,6 +306,9 @@
 	 */
 	size_t max_write_len;
 
+	/* CFTYPE_* flags */
+	unsigned int flags;
+
 	int (*open)(struct inode *inode, struct file *file);
 	ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft,
 			struct file *file,
@@ -373,6 +387,16 @@
 			struct eventfd_ctx *eventfd);
 };
 
+/*
+ * cftype_sets describe cftypes belonging to a subsystem and are chained at
+ * cgroup_subsys->cftsets.  Each cftset points to an array of cftypes
+ * terminated by zero length name.
+ */
+struct cftype_set {
+	struct list_head		node;	/* chained at subsys->cftsets */
+	const struct cftype		*cfts;
+};
+
 struct cgroup_scanner {
 	struct cgroup *cg;
 	int (*test_task)(struct task_struct *p, struct cgroup_scanner *scan);
@@ -382,21 +406,8 @@
 	void *data;
 };
 
-/*
- * Add a new file to the given cgroup directory. Should only be
- * called by subsystems from within a populate() method
- */
-int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
-		       const struct cftype *cft);
-
-/*
- * Add a set of new files to the given cgroup directory. Should
- * only be called by subsystems from within a populate() method
- */
-int cgroup_add_files(struct cgroup *cgrp,
-			struct cgroup_subsys *subsys,
-			const struct cftype cft[],
-			int count);
+int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
+int cgroup_rm_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
 
 int cgroup_is_removed(const struct cgroup *cgrp);
 
@@ -461,7 +472,6 @@
 	void (*fork)(struct task_struct *task);
 	void (*exit)(struct cgroup *cgrp, struct cgroup *old_cgrp,
 		     struct task_struct *task);
-	int (*populate)(struct cgroup_subsys *ss, struct cgroup *cgrp);
 	void (*post_clone)(struct cgroup *cgrp);
 	void (*bind)(struct cgroup *root);
 
@@ -474,6 +484,18 @@
 	 * (not available in early_init time.)
 	 */
 	bool use_id;
+
+	/*
+	 * If %true, cgroup removal will try to clear css refs by retrying
+	 * ss->pre_destroy() until there's no css ref left.  This behavior
+	 * is strictly for backward compatibility and will be removed as
+	 * soon as the current user (memcg) is updated.
+	 *
+	 * If %false, ss->pre_destroy() can't fail and cgroup removal won't
+	 * wait for css refs to drop to zero before proceeding.
+	 */
+	bool __DEPRECATED_clear_css_refs;
+
 #define MAX_CGROUP_TYPE_NAMELEN 32
 	const char *name;
 
@@ -500,6 +522,13 @@
 	struct idr idr;
 	spinlock_t id_lock;
 
+	/* list of cftype_sets */
+	struct list_head cftsets;
+
+	/* base cftypes, automatically [de]registered with subsys itself */
+	struct cftype *base_cftypes;
+	struct cftype_set base_cftset;
+
 	/* should be defined only by modular subsystems */
 	struct module *module;
 };
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index ee28844..7230bb5 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -36,8 +36,6 @@
 extern int cpu_add_dev_attr_group(struct attribute_group *attrs);
 extern void cpu_remove_dev_attr_group(struct attribute_group *attrs);
 
-extern int sched_create_sysfs_power_savings_entries(struct device *dev);
-
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *cpu);
 extern ssize_t arch_cpu_probe(const char *, size_t);
diff --git a/include/linux/cred.h b/include/linux/cred.h
index adadf71..917dc5a 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -17,6 +17,7 @@
 #include <linux/key.h>
 #include <linux/selinux.h>
 #include <linux/atomic.h>
+#include <linux/uidgid.h>
 
 struct user_struct;
 struct cred;
@@ -26,14 +27,14 @@
  * COW Supplementary groups list
  */
 #define NGROUPS_SMALL		32
-#define NGROUPS_PER_BLOCK	((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
+#define NGROUPS_PER_BLOCK	((unsigned int)(PAGE_SIZE / sizeof(kgid_t)))
 
 struct group_info {
 	atomic_t	usage;
 	int		ngroups;
 	int		nblocks;
-	gid_t		small_block[NGROUPS_SMALL];
-	gid_t		*blocks[0];
+	kgid_t		small_block[NGROUPS_SMALL];
+	kgid_t		*blocks[0];
 };
 
 /**
@@ -66,14 +67,14 @@
 extern void groups_free(struct group_info *);
 extern int set_current_groups(struct group_info *);
 extern int set_groups(struct cred *, struct group_info *);
-extern int groups_search(const struct group_info *, gid_t);
+extern int groups_search(const struct group_info *, kgid_t);
 
 /* access the groups "array" with this macro */
 #define GROUP_AT(gi, i) \
 	((gi)->blocks[(i) / NGROUPS_PER_BLOCK][(i) % NGROUPS_PER_BLOCK])
 
-extern int in_group_p(gid_t);
-extern int in_egroup_p(gid_t);
+extern int in_group_p(kgid_t);
+extern int in_egroup_p(kgid_t);
 
 /*
  * The common credentials for a thread group
@@ -122,14 +123,14 @@
 #define CRED_MAGIC	0x43736564
 #define CRED_MAGIC_DEAD	0x44656144
 #endif
-	uid_t		uid;		/* real UID of the task */
-	gid_t		gid;		/* real GID of the task */
-	uid_t		suid;		/* saved UID of the task */
-	gid_t		sgid;		/* saved GID of the task */
-	uid_t		euid;		/* effective UID of the task */
-	gid_t		egid;		/* effective GID of the task */
-	uid_t		fsuid;		/* UID for VFS ops */
-	gid_t		fsgid;		/* GID for VFS ops */
+	kuid_t		uid;		/* real UID of the task */
+	kgid_t		gid;		/* real GID of the task */
+	kuid_t		suid;		/* saved UID of the task */
+	kgid_t		sgid;		/* saved GID of the task */
+	kuid_t		euid;		/* effective UID of the task */
+	kgid_t		egid;		/* effective GID of the task */
+	kuid_t		fsuid;		/* UID for VFS ops */
+	kgid_t		fsgid;		/* GID for VFS ops */
 	unsigned	securebits;	/* SUID-less security management */
 	kernel_cap_t	cap_inheritable; /* caps our children can inherit */
 	kernel_cap_t	cap_permitted;	/* caps we're permitted */
@@ -146,7 +147,7 @@
 	void		*security;	/* subjective LSM security */
 #endif
 	struct user_struct *user;	/* real user ID subscription */
-	struct user_namespace *user_ns; /* cached user->user_ns */
+	struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
 	struct group_info *group_info;	/* supplementary groups for euid/fsgid */
 	struct rcu_head	rcu;		/* RCU deletion hook */
 };
@@ -357,11 +358,11 @@
 #define current_user()		(current_cred_xxx(user))
 #define current_security()	(current_cred_xxx(security))
 
+extern struct user_namespace init_user_ns;
 #ifdef CONFIG_USER_NS
 #define current_user_ns()	(current_cred_xxx(user_ns))
 #define task_user_ns(task)	(task_cred_xxx((task), user_ns))
 #else
-extern struct user_namespace init_user_ns;
 #define current_user_ns()	(&init_user_ns)
 #define task_user_ns(task)	(&init_user_ns)
 #endif
diff --git a/include/linux/cs5535.h b/include/linux/cs5535.h
index c077aec..cfe8323 100644
--- a/include/linux/cs5535.h
+++ b/include/linux/cs5535.h
@@ -95,6 +95,7 @@
 
 /* CS5536_PM1_STS bits */
 #define CS5536_WAK_FLAG		(1 << 15)
+#define CS5536_RTC_FLAG		(1 << 10)
 #define CS5536_PWRBTN_FLAG	(1 << 8)
 
 /* CS5536_PM1_EN bits */
diff --git a/include/linux/device.h b/include/linux/device.h
index 5ad17ccc..e04f577 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -23,6 +23,7 @@
 #include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/atomic.h>
+#include <linux/ratelimit.h>
 #include <asm/device.h>
 
 struct device;
@@ -502,7 +503,10 @@
 		{ __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) }
 #define DEVICE_INT_ATTR(_name, _mode, _var) \
 	struct dev_ext_attribute dev_attr_##_name = \
-		{ __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) }
+		{ __ATTR(_name, _mode, device_show_int, device_store_int), &(_var) }
+#define DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \
+	struct device_attribute dev_attr_##_name =		\
+		__ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store)
 
 extern int device_create_file(struct device *device,
 			      const struct device_attribute *entry);
@@ -541,6 +545,8 @@
 			   dr_match_t match, void *match_data);
 extern int devres_destroy(struct device *dev, dr_release_t release,
 			  dr_match_t match, void *match_data);
+extern int devres_release(struct device *dev, dr_release_t release,
+			  dr_match_t match, void *match_data);
 
 /* devres group */
 extern void * __must_check devres_open_group(struct device *dev, void *id,
@@ -931,6 +937,32 @@
 
 #endif
 
+#define dev_level_ratelimited(dev_level, dev, fmt, ...)			\
+do {									\
+	static DEFINE_RATELIMIT_STATE(_rs,				\
+				      DEFAULT_RATELIMIT_INTERVAL,	\
+				      DEFAULT_RATELIMIT_BURST);		\
+	if (__ratelimit(&_rs))						\
+		dev_level(dev, fmt, ##__VA_ARGS__);			\
+} while (0)
+
+#define dev_emerg_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_emerg, dev, fmt, ##__VA_ARGS__)
+#define dev_alert_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_alert, dev, fmt, ##__VA_ARGS__)
+#define dev_crit_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_crit, dev, fmt, ##__VA_ARGS__)
+#define dev_err_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_err, dev, fmt, ##__VA_ARGS__)
+#define dev_warn_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_warn, dev, fmt, ##__VA_ARGS__)
+#define dev_notice_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_notice, dev, fmt, ##__VA_ARGS__)
+#define dev_info_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_info, dev, fmt, ##__VA_ARGS__)
+#define dev_dbg_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_dbg, dev, fmt, ##__VA_ARGS__)
+
 /*
  * Stupid hackaround for existing uses of non-printk uses dev_info
  *
diff --git a/include/linux/dlm.h b/include/linux/dlm.h
index 6c7f6e9..5201524 100644
--- a/include/linux/dlm.h
+++ b/include/linux/dlm.h
@@ -67,7 +67,6 @@
 
 /* dlm_new_lockspace() flags */
 
-#define DLM_LSFL_NODIR		0x00000001
 #define DLM_LSFL_TIMEWARN	0x00000002
 #define DLM_LSFL_FS     	0x00000004
 #define DLM_LSFL_NEWEXCL     	0x00000008
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index cb4428a..f50d405 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -320,7 +320,24 @@
 
 #define DTV_ENUM_DELSYS		44
 
-#define DTV_MAX_COMMAND				DTV_ENUM_DELSYS
+/* ATSC-MH */
+#define DTV_ATSCMH_FIC_VER		45
+#define DTV_ATSCMH_PARADE_ID		46
+#define DTV_ATSCMH_NOG			47
+#define DTV_ATSCMH_TNOG			48
+#define DTV_ATSCMH_SGN			49
+#define DTV_ATSCMH_PRC			50
+#define DTV_ATSCMH_RS_FRAME_MODE	51
+#define DTV_ATSCMH_RS_FRAME_ENSEMBLE	52
+#define DTV_ATSCMH_RS_CODE_MODE_PRI	53
+#define DTV_ATSCMH_RS_CODE_MODE_SEC	54
+#define DTV_ATSCMH_SCCC_BLOCK_MODE	55
+#define DTV_ATSCMH_SCCC_CODE_MODE_A	56
+#define DTV_ATSCMH_SCCC_CODE_MODE_B	57
+#define DTV_ATSCMH_SCCC_CODE_MODE_C	58
+#define DTV_ATSCMH_SCCC_CODE_MODE_D	59
+
+#define DTV_MAX_COMMAND				DTV_ATSCMH_SCCC_CODE_MODE_D
 
 typedef enum fe_pilot {
 	PILOT_ON,
@@ -360,6 +377,38 @@
 
 #define SYS_DVBC_ANNEX_AC	SYS_DVBC_ANNEX_A
 
+/* ATSC-MH */
+
+enum atscmh_sccc_block_mode {
+	ATSCMH_SCCC_BLK_SEP      = 0,
+	ATSCMH_SCCC_BLK_COMB     = 1,
+	ATSCMH_SCCC_BLK_RES      = 2,
+};
+
+enum atscmh_sccc_code_mode {
+	ATSCMH_SCCC_CODE_HLF     = 0,
+	ATSCMH_SCCC_CODE_QTR     = 1,
+	ATSCMH_SCCC_CODE_RES     = 2,
+};
+
+enum atscmh_rs_frame_ensemble {
+	ATSCMH_RSFRAME_ENS_PRI   = 0,
+	ATSCMH_RSFRAME_ENS_SEC   = 1,
+};
+
+enum atscmh_rs_frame_mode {
+	ATSCMH_RSFRAME_PRI_ONLY  = 0,
+	ATSCMH_RSFRAME_PRI_SEC   = 1,
+	ATSCMH_RSFRAME_RES       = 2,
+};
+
+enum atscmh_rs_code_mode {
+	ATSCMH_RSCODE_211_187    = 0,
+	ATSCMH_RSCODE_223_187    = 1,
+	ATSCMH_RSCODE_235_187    = 2,
+	ATSCMH_RSCODE_RES        = 3,
+};
+
 
 struct dtv_cmds_h {
 	char	*name;		/* A display name for debugging purposes */
diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
index 0559e2b..43d9e8d 100644
--- a/include/linux/dvb/version.h
+++ b/include/linux/dvb/version.h
@@ -24,6 +24,6 @@
 #define _DVBVERSION_H_
 
 #define DVB_API_VERSION 5
-#define DVB_API_VERSION_MINOR 5
+#define DVB_API_VERSION_MINOR 6
 
 #endif /*_DVBVERSION_H_*/
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 7e3c53a..c18257b 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -17,8 +17,8 @@
 	const char *format;
 	unsigned int lineno:18;
 	/*
- 	 * The flags field controls the behaviour at the callsite.
- 	 * The bits here are changed dynamically when the user
+	 * The flags field controls the behaviour at the callsite.
+	 * The bits here are changed dynamically when the user
 	 * writes commands to <debugfs>/dynamic_debug/control
 	 */
 #define _DPRINTK_FLAGS_NONE	0
@@ -44,6 +44,9 @@
 extern __printf(2, 3)
 int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
 
+extern int ddebug_dyndbg_module_param_cb(char *param, char *val,
+					const char *modname);
+
 struct device;
 
 extern __printf(3, 4)
@@ -94,11 +97,26 @@
 
 #else
 
+#include <linux/string.h>
+#include <linux/errno.h>
+
 static inline int ddebug_remove_module(const char *mod)
 {
 	return 0;
 }
 
+static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
+						const char *modname)
+{
+	if (strstr(param, "dyndbg")) {
+		/* avoid pr_warn(), which wants pr_fmt() fully defined */
+		printk(KERN_WARNING "dyndbg param is supported only in "
+			"CONFIG_DYNAMIC_DEBUG builds\n");
+		return 0; /* allow and ignore */
+	}
+	return -EINVAL;
+}
+
 #define dynamic_pr_debug(fmt, ...)					\
 	do { if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0)
 #define dynamic_dev_dbg(dev, fmt, ...)					\
diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h
index 657ab55..6f8be32 100644
--- a/include/linux/eventpoll.h
+++ b/include/linux/eventpoll.h
@@ -26,6 +26,18 @@
 #define EPOLL_CTL_DEL 2
 #define EPOLL_CTL_MOD 3
 
+/*
+ * Request the handling of system wakeup events so as to prevent system suspends
+ * from happening while those events are being processed.
+ *
+ * Assuming neither EPOLLET nor EPOLLONESHOT is set, system suspends will not be
+ * re-allowed until epoll_wait is called again after consuming the wakeup
+ * event(s).
+ *
+ * Requires CAP_EPOLLWAKEUP
+ */
+#define EPOLLWAKEUP (1 << 29)
+
 /* Set the One Shot behaviour for the target file descriptor */
 #define EPOLLONESHOT (1 << 30)
 
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
new file mode 100644
index 0000000..cdd4014
--- /dev/null
+++ b/include/linux/extcon.h
@@ -0,0 +1,324 @@
+/*
+ *  External connector (extcon) class driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Donggeun Kim <dg77.kim@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on switch class driver
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#ifndef __LINUX_EXTCON_H__
+#define __LINUX_EXTCON_H__
+
+#include <linux/notifier.h>
+
+#define SUPPORTED_CABLE_MAX	32
+#define CABLE_NAME_MAX		30
+
+/*
+ * The standard cable name is to help support general notifier
+ * and notifee device drivers to share the common names.
+ * Please use standard cable names unless your notifier device has
+ * a very unique and abnormal cable or
+ * the cable type is supposed to be used with only one unique
+ * pair of notifier/notifee devices.
+ *
+ * Please add any other "standard" cables used with extcon dev.
+ *
+ * You may add a dot and number to specify version or specification
+ * of the specific cable if it is required. (e.g., "Fast-charger.18"
+ * and "Fast-charger.10" for 1.8A and 1.0A chargers)
+ * However, the notifee and notifier should be able to handle such
+ * string and if the notifee can negotiate the protocol or idenify,
+ * you don't need such convention. This convention is helpful when
+ * notifier can distinguish but notifiee cannot.
+ */
+enum extcon_cable_name {
+	EXTCON_USB = 0,
+	EXTCON_USB_HOST,
+	EXTCON_TA, /* Travel Adaptor */
+	EXTCON_FAST_CHARGER,
+	EXTCON_SLOW_CHARGER,
+	EXTCON_CHARGE_DOWNSTREAM, /* Charging an external device */
+	EXTCON_HDMI,
+	EXTCON_MHL,
+	EXTCON_DVI,
+	EXTCON_VGA,
+	EXTCON_DOCK,
+	EXTCON_LINE_IN,
+	EXTCON_LINE_OUT,
+	EXTCON_MIC_IN,
+	EXTCON_HEADPHONE_OUT,
+	EXTCON_SPDIF_IN,
+	EXTCON_SPDIF_OUT,
+	EXTCON_VIDEO_IN,
+	EXTCON_VIDEO_OUT,
+	EXTCON_MECHANICAL,
+};
+extern const char *extcon_cable_name[];
+
+struct extcon_cable;
+
+/**
+ * struct extcon_dev - An extcon device represents one external connector.
+ * @name	The name of this extcon device. Parent device name is used
+ *		if NULL.
+ * @supported_cable	Array of supported cable name ending with NULL.
+ *			If supported_cable is NULL, cable name related APIs
+ *			are disabled.
+ * @mutually_exclusive	Array of mutually exclusive set of cables that cannot
+ *			be attached simultaneously. The array should be
+ *			ending with NULL or be NULL (no mutually exclusive
+ *			cables). For example, if it is { 0x7, 0x30, 0}, then,
+ *			{0, 1}, {0, 1, 2}, {0, 2}, {1, 2}, or {4, 5} cannot
+ *			be attached simulataneously. {0x7, 0} is equivalent to
+ *			{0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there
+ *			can be no simultaneous connections.
+ * @print_name	An optional callback to override the method to print the
+ *		name of the extcon device.
+ * @print_state	An optional callback to override the method to print the
+ *		status of the extcon device.
+ * @dev		Device of this extcon. Do not provide at register-time.
+ * @state	Attach/detach state of this extcon. Do not provide at
+ *		register-time
+ * @nh	Notifier for the state change events from this extcon
+ * @entry	To support list of extcon devices so that uses can search
+ *		for extcon devices based on the extcon name.
+ * @lock
+ * @max_supported	Internal value to store the number of cables.
+ * @extcon_dev_type	Device_type struct to provide attribute_groups
+ *			customized for each extcon device.
+ * @cables	Sysfs subdirectories. Each represents one cable.
+ *
+ * In most cases, users only need to provide "User initializing data" of
+ * this struct when registering an extcon. In some exceptional cases,
+ * optional callbacks may be needed. However, the values in "internal data"
+ * are overwritten by register function.
+ */
+struct extcon_dev {
+	/* --- Optional user initializing data --- */
+	const char	*name;
+	const char **supported_cable;
+	const u32	*mutually_exclusive;
+
+	/* --- Optional callbacks to override class functions --- */
+	ssize_t	(*print_name)(struct extcon_dev *edev, char *buf);
+	ssize_t	(*print_state)(struct extcon_dev *edev, char *buf);
+
+	/* --- Internal data. Please do not set. --- */
+	struct device	*dev;
+	u32		state;
+	struct raw_notifier_head nh;
+	struct list_head entry;
+	spinlock_t lock; /* could be called by irq handler */
+	int max_supported;
+
+	/* /sys/class/extcon/.../cable.n/... */
+	struct device_type extcon_dev_type;
+	struct extcon_cable *cables;
+	/* /sys/class/extcon/.../mutually_exclusive/... */
+	struct attribute_group attr_g_muex;
+	struct attribute **attrs_muex;
+	struct device_attribute *d_attrs_muex;
+};
+
+/**
+ * struct extcon_cable	- An internal data for each cable of extcon device.
+ * @edev	The extcon device
+ * @cable_index	Index of this cable in the edev
+ * @attr_g	Attribute group for the cable
+ * @attr_name	"name" sysfs entry
+ * @attr_state	"state" sysfs entry
+ * @attrs	Array pointing to attr_name and attr_state for attr_g
+ */
+struct extcon_cable {
+	struct extcon_dev *edev;
+	int cable_index;
+
+	struct attribute_group attr_g;
+	struct device_attribute attr_name;
+	struct device_attribute attr_state;
+
+	struct attribute *attrs[3]; /* to be fed to attr_g.attrs */
+};
+
+/**
+ * struct extcon_specific_cable_nb - An internal data for
+ *				extcon_register_interest().
+ * @internal_nb	a notifier block bridging extcon notifier and cable notifier.
+ * @user_nb	user provided notifier block for events from a specific cable.
+ * @cable_index	the target cable.
+ * @edev	the target extcon device.
+ * @previous_value	the saved previous event value.
+ */
+struct extcon_specific_cable_nb {
+	struct notifier_block internal_nb;
+	struct notifier_block *user_nb;
+	int cable_index;
+	struct extcon_dev *edev;
+	unsigned long previous_value;
+};
+
+#if IS_ENABLED(CONFIG_EXTCON)
+
+/*
+ * Following APIs are for notifiers or configurations.
+ * Notifiers are the external port and connection devices.
+ */
+extern int extcon_dev_register(struct extcon_dev *edev, struct device *dev);
+extern void extcon_dev_unregister(struct extcon_dev *edev);
+extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
+
+/*
+ * get/set/update_state access the 32b encoded state value, which represents
+ * states of all possible cables of the multistate port. For example, if one
+ * calls extcon_set_state(edev, 0x7), it may mean that all the three cables
+ * are attached to the port.
+ */
+static inline u32 extcon_get_state(struct extcon_dev *edev)
+{
+	return edev->state;
+}
+
+extern int extcon_set_state(struct extcon_dev *edev, u32 state);
+extern int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state);
+
+/*
+ * get/set_cable_state access each bit of the 32b encoded state value.
+ * They are used to access the status of each cable based on the cable_name
+ * or cable_index, which is retrived by extcon_find_cable_index
+ */
+extern int extcon_find_cable_index(struct extcon_dev *sdev,
+				   const char *cable_name);
+extern int extcon_get_cable_state_(struct extcon_dev *edev, int cable_index);
+extern int extcon_set_cable_state_(struct extcon_dev *edev, int cable_index,
+				   bool cable_state);
+
+extern int extcon_get_cable_state(struct extcon_dev *edev,
+				  const char *cable_name);
+extern int extcon_set_cable_state(struct extcon_dev *edev,
+				  const char *cable_name, bool cable_state);
+
+/*
+ * Following APIs are for notifiees (those who want to be notified)
+ * to register a callback for events from a specific cable of the extcon.
+ * Notifiees are the connected device drivers wanting to get notified by
+ * a specific external port of a connection device.
+ */
+extern int extcon_register_interest(struct extcon_specific_cable_nb *obj,
+				    const char *extcon_name,
+				    const char *cable_name,
+				    struct notifier_block *nb);
+extern int extcon_unregister_interest(struct extcon_specific_cable_nb *nb);
+
+/*
+ * Following APIs are to monitor every action of a notifier.
+ * Registerer gets notified for every external port of a connection device.
+ * Probably this could be used to debug an action of notifier; however,
+ * we do not recommend to use this at normal 'notifiee' device drivers who
+ * want to be notified by a specific external port of the notifier.
+ */
+extern int extcon_register_notifier(struct extcon_dev *edev,
+				    struct notifier_block *nb);
+extern int extcon_unregister_notifier(struct extcon_dev *edev,
+				      struct notifier_block *nb);
+#else /* CONFIG_EXTCON */
+static inline int extcon_dev_register(struct extcon_dev *edev,
+				      struct device *dev)
+{
+	return 0;
+}
+
+static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
+
+static inline u32 extcon_get_state(struct extcon_dev *edev)
+{
+	return 0;
+}
+
+static inline int extcon_set_state(struct extcon_dev *edev, u32 state)
+{
+	return 0;
+}
+
+static inline int extcon_update_state(struct extcon_dev *edev, u32 mask,
+				       u32 state)
+{
+	return 0;
+}
+
+static inline int extcon_find_cable_index(struct extcon_dev *edev,
+					  const char *cable_name)
+{
+	return 0;
+}
+
+static inline int extcon_get_cable_state_(struct extcon_dev *edev,
+					  int cable_index)
+{
+	return 0;
+}
+
+static inline int extcon_set_cable_state_(struct extcon_dev *edev,
+					  int cable_index, bool cable_state)
+{
+	return 0;
+}
+
+static inline int extcon_get_cable_state(struct extcon_dev *edev,
+			const char *cable_name)
+{
+	return 0;
+}
+
+static inline int extcon_set_cable_state(struct extcon_dev *edev,
+			const char *cable_name, int state)
+{
+	return 0;
+}
+
+static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
+{
+	return NULL;
+}
+
+static inline int extcon_register_notifier(struct extcon_dev *edev,
+					   struct notifier_block *nb)
+{
+	return 0;
+}
+
+static inline int extcon_unregister_notifier(struct extcon_dev *edev,
+					     struct notifier_block *nb)
+{
+	return 0;
+}
+
+static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj,
+					   const char *extcon_name,
+					   const char *cable_name,
+					   struct notifier_block *nb)
+{
+	return 0;
+}
+
+static inline int extcon_unregister_interest(struct extcon_specific_cable_nb
+						    *obj)
+{
+	return 0;
+}
+#endif /* CONFIG_EXTCON */
+#endif /* __LINUX_EXTCON_H__ */
diff --git a/include/linux/extcon/extcon_gpio.h b/include/linux/extcon/extcon_gpio.h
new file mode 100644
index 0000000..a2129b7
--- /dev/null
+++ b/include/linux/extcon/extcon_gpio.h
@@ -0,0 +1,52 @@
+/*
+ *  External connector (extcon) class generic GPIO driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on switch class driver
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+#ifndef __EXTCON_GPIO_H__
+#define __EXTCON_GPIO_H__ __FILE__
+
+#include <linux/extcon.h>
+
+/**
+ * struct gpio_extcon_platform_data - A simple GPIO-controlled extcon device.
+ * @name	The name of this GPIO extcon device.
+ * @gpio	Corresponding GPIO.
+ * @debounce	Debounce time for GPIO IRQ in ms.
+ * @irq_flags	IRQ Flags (e.g., IRQF_TRIGGER_LOW).
+ * @state_on	print_state is overriden with state_on if attached. If Null,
+ *		default method of extcon class is used.
+ * @state_off	print_state is overriden with state_on if dettached. If Null,
+ *		default method of extcon class is used.
+ *
+ * Note that in order for state_on or state_off to be valid, both state_on
+ * and state_off should be not NULL. If at least one of them is NULL,
+ * the print_state is not overriden.
+ */
+struct gpio_extcon_platform_data {
+	const char *name;
+	unsigned gpio;
+	unsigned long debounce;
+	unsigned long irq_flags;
+
+	/* if NULL, "0" or "1" will be printed */
+	const char *state_on;
+	const char *state_off;
+};
+
+#endif /* __EXTCON_GPIO_H__ */
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index cdc9b71..e83c24a 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -135,6 +135,20 @@
 	__be32 maint_utility_register;
 };
 
+static inline struct fw_card *fw_card_get(struct fw_card *card)
+{
+	kref_get(&card->kref);
+
+	return card;
+}
+
+void fw_card_release(struct kref *kref);
+
+static inline void fw_card_put(struct fw_card *card)
+{
+	kref_put(&card->kref, fw_card_release);
+}
+
 struct fw_attribute_group {
 	struct attribute_group *groups[2];
 	struct attribute_group group;
@@ -325,6 +339,7 @@
 void fw_core_remove_address_handler(struct fw_address_handler *handler);
 void fw_send_response(struct fw_card *card,
 		      struct fw_request *request, int rcode);
+int fw_get_request_speed(struct fw_request *request);
 void fw_send_request(struct fw_card *card, struct fw_transaction *t,
 		     int tcode, int destination_id, int generation, int speed,
 		     unsigned long long offset, void *payload, size_t length,
diff --git a/drivers/input/fixp-arith.h b/include/linux/fixp-arith.h
similarity index 100%
rename from drivers/input/fixp-arith.h
rename to include/linux/fixp-arith.h
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 25c40b9..c0e53372 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -402,6 +402,7 @@
 #include <linux/atomic.h>
 #include <linux/shrinker.h>
 #include <linux/migrate_mode.h>
+#include <linux/uidgid.h>
 
 #include <asm/byteorder.h>
 
@@ -469,8 +470,8 @@
 struct iattr {
 	unsigned int	ia_valid;
 	umode_t		ia_mode;
-	uid_t		ia_uid;
-	gid_t		ia_gid;
+	kuid_t		ia_uid;
+	kgid_t		ia_gid;
 	loff_t		ia_size;
 	struct timespec	ia_atime;
 	struct timespec	ia_mtime;
@@ -761,8 +762,8 @@
 struct inode {
 	umode_t			i_mode;
 	unsigned short		i_opflags;
-	uid_t			i_uid;
-	gid_t			i_gid;
+	kuid_t			i_uid;
+	kgid_t			i_gid;
 	unsigned int		i_flags;
 
 #ifdef CONFIG_FS_POSIX_ACL
@@ -927,6 +928,31 @@
 #endif
 }
 
+/* Helper functions so that in most cases filesystems will
+ * not need to deal directly with kuid_t and kgid_t and can
+ * instead deal with the raw numeric values that are stored
+ * in the filesystem.
+ */
+static inline uid_t i_uid_read(const struct inode *inode)
+{
+	return from_kuid(&init_user_ns, inode->i_uid);
+}
+
+static inline gid_t i_gid_read(const struct inode *inode)
+{
+	return from_kgid(&init_user_ns, inode->i_gid);
+}
+
+static inline void i_uid_write(struct inode *inode, uid_t uid)
+{
+	inode->i_uid = make_kuid(&init_user_ns, uid);
+}
+
+static inline void i_gid_write(struct inode *inode, gid_t gid)
+{
+	inode->i_gid = make_kgid(&init_user_ns, gid);
+}
+
 static inline unsigned iminor(const struct inode *inode)
 {
 	return MINOR(inode->i_rdev);
@@ -943,7 +969,7 @@
 	rwlock_t lock;          /* protects pid, uid, euid fields */
 	struct pid *pid;	/* pid or -pgrp where SIGIO should be sent */
 	enum pid_type pid_type;	/* Kind of process group SIGIO should be sent to */
-	uid_t uid, euid;	/* uid/euid of process setting the owner */
+	kuid_t uid, euid;	/* uid/euid of process setting the owner */
 	int signum;		/* posix.1b rt signal to be delivered on IO */
 };
 
@@ -1527,12 +1553,6 @@
 #define vfs_check_frozen(sb, level) \
 	wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level)))
 
-/*
- * until VFS tracks user namespaces for inodes, just make all files
- * belong to init_user_ns
- */
-extern struct user_namespace init_user_ns;
-#define inode_userns(inode) (&init_user_ns)
 extern bool inode_owner_or_capable(const struct inode *inode);
 
 /* not quite ready to be deprecated, but... */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index fffdf00..15be561 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -6,7 +6,7 @@
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
- * Copyright 2004 Freescale Semiconductor, Inc
+ * Copyright 2004,2012 Freescale Semiconductor, Inc
  *
  * 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
@@ -17,6 +17,12 @@
 #ifndef _FSL_DEVICE_H_
 #define _FSL_DEVICE_H_
 
+#define FSL_UTMI_PHY_DLY	10	/*As per P1010RM, delay for UTMI
+				PHY CLK to become stable - 10ms*/
+#define FSL_USB_VER_OLD		0
+#define FSL_USB_VER_1_6		1
+#define FSL_USB_VER_2_2		2
+
 #include <linux/types.h>
 
 /*
@@ -63,6 +69,7 @@
 
 struct fsl_usb2_platform_data {
 	/* board specific information */
+	int				controller_ver;
 	enum fsl_usb2_operating_modes	operating_mode;
 	enum fsl_usb2_phy_modes		phy_mode;
 	unsigned int			port_enables;
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 72a6cab..55e6d63 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -286,10 +286,16 @@
 struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter);
 struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter);
 
+#define for_ftrace_rec_iter(iter)		\
+	for (iter = ftrace_rec_iter_start();	\
+	     iter;				\
+	     iter = ftrace_rec_iter_next(iter))
+
+
 int ftrace_update_record(struct dyn_ftrace *rec, int enable);
 int ftrace_test_record(struct dyn_ftrace *rec, int enable);
 void ftrace_run_stop_machine(int command);
-int ftrace_location(unsigned long ip);
+unsigned long ftrace_location(unsigned long ip);
 
 extern ftrace_func_t ftrace_trace_function;
 
@@ -308,11 +314,14 @@
 /* defined in arch */
 extern int ftrace_ip_converted(unsigned long ip);
 extern int ftrace_dyn_arch_init(void *data);
+extern void ftrace_replace_code(int enable);
 extern int ftrace_update_ftrace_func(ftrace_func_t func);
 extern void ftrace_caller(void);
 extern void ftrace_call(void);
 extern void mcount_call(void);
 
+void ftrace_modify_all_code(int command);
+
 #ifndef FTRACE_ADDR
 #define FTRACE_ADDR ((unsigned long)ftrace_caller)
 #endif
@@ -485,8 +494,12 @@
   extern void trace_preempt_on(unsigned long a0, unsigned long a1);
   extern void trace_preempt_off(unsigned long a0, unsigned long a1);
 #else
-  static inline void trace_preempt_on(unsigned long a0, unsigned long a1) { }
-  static inline void trace_preempt_off(unsigned long a0, unsigned long a1) { }
+/*
+ * Use defines instead of static inlines because some arches will make code out
+ * of the CALLER_ADDR, when we really want these to be a real nop.
+ */
+# define trace_preempt_on(a0, a1) do { } while (0)
+# define trace_preempt_off(a0, a1) do { } while (0)
 #endif
 
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
index b456b08..b986be5 100644
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -153,6 +153,19 @@
 
 void gameport_unregister_driver(struct gameport_driver *drv);
 
+/**
+ * module_gameport_driver() - Helper macro for registering a gameport driver
+ * @__gameport_driver: gameport_driver struct
+ *
+ * Helper macro for gameport drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module may
+ * only use this macro once, and calling it replaces module_init() and
+ * module_exit().
+ */
+#define module_gameport_driver(__gameport_driver) \
+	module_driver(__gameport_driver, gameport_register_driver, \
+		       gameport_unregister_driver)
+
 #endif /* __KERNEL__ */
 
 #define GAMEPORT_MODE_DISABLED		0
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
index fadff28..79b3eb3 100644
--- a/include/linux/generic_serial.h
+++ b/include/linux/generic_serial.h
@@ -4,7 +4,6 @@
  *  Copyright (C) 1998 R.E.Wolff@BitWizard.nl
  *
  *  written for the SX serial driver.
- *     Contains the code that should be shared over all the serial drivers.
  *
  *  Version 0.1 -- December, 1998.
  */
@@ -12,45 +11,8 @@
 #ifndef GENERIC_SERIAL_H
 #define GENERIC_SERIAL_H
 
-#ifdef __KERNEL__
-#include <linux/mutex.h>
-#include <linux/tty.h>
-
-struct real_driver {
-  void                    (*disable_tx_interrupts) (void *);
-  void                    (*enable_tx_interrupts) (void *);
-  void                    (*disable_rx_interrupts) (void *);
-  void                    (*enable_rx_interrupts) (void *);
-  void                    (*shutdown_port) (void*);
-  int                     (*set_real_termios) (void*);
-  int                     (*chars_in_buffer) (void*);
-  void                    (*close) (void*);
-  void                    (*hungup) (void*);
-  void                    (*getserial) (void*, struct serial_struct *sp);
-};
-
-
-
-struct gs_port {
-  int                     magic;
-  struct tty_port	  port;
-  unsigned char           *xmit_buf; 
-  int                     xmit_head;
-  int                     xmit_tail;
-  int                     xmit_cnt;
-  struct mutex            port_write_mutex;
-  unsigned long           event;
-  unsigned short          closing_wait;
-  int                     close_delay;
-  struct real_driver      *rd;
-  int                     wakeup_chars;
-  int                     baud_base;
-  int                     baud;
-  int                     custom_divisor;
-  spinlock_t              driver_lock;
-};
-
-#endif /* __KERNEL__ */
+#warning Use of this header is deprecated.
+#warning Since nobody sets the constants defined here for you, you should not, in any case, use them. Including the header is thus pointless.
 
 /* Flags */
 /* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
@@ -60,8 +22,6 @@
 #define GS_RX_INTEN      0x00400000
 #define GS_ACTIVE        0x00200000
 
-
-
 #define GS_TYPE_NORMAL   1
 
 #define GS_DEBUG_FLUSH   0x00000001
@@ -72,24 +32,4 @@
 #define GS_DEBUG_FLOW    0x00000020
 #define GS_DEBUG_WRITE   0x00000040
 
-#ifdef __KERNEL__
-int gs_put_char(struct tty_struct *tty, unsigned char ch);
-int  gs_write(struct tty_struct *tty, 
-             const unsigned char *buf, int count);
-int  gs_write_room(struct tty_struct *tty);
-int  gs_chars_in_buffer(struct tty_struct *tty);
-void gs_flush_buffer(struct tty_struct *tty);
-void gs_flush_chars(struct tty_struct *tty);
-void gs_stop(struct tty_struct *tty);
-void gs_start(struct tty_struct *tty);
-void gs_hangup(struct tty_struct *tty);
-int  gs_block_til_ready(void *port, struct file *filp);
-void gs_close(struct tty_struct *tty, struct file *filp);
-void gs_set_termios (struct tty_struct * tty, 
-                     struct ktermios * old_termios);
-int  gs_init_port(struct gs_port *port);
-int  gs_setserial(struct gs_port *port, struct serial_struct __user *sp);
-int  gs_getserial(struct gs_port *port, struct serial_struct __user *sp);
-void gs_got_break(struct gs_port *port);
-#endif /* __KERNEL__ */
 #endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 3a95da6..449fa38 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -317,7 +317,6 @@
 #define HID_QUIRK_BADPAD			0x00000020
 #define HID_QUIRK_MULTI_INPUT			0x00000040
 #define HID_QUIRK_HIDINPUT_FORCE		0x00000080
-#define HID_QUIRK_MULTITOUCH			0x00000100
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS		0x00010000
 #define HID_QUIRK_FULLSPEED_INTERVAL		0x10000000
 #define HID_QUIRK_NO_INIT_REPORTS		0x20000000
@@ -325,6 +324,12 @@
 #define HID_QUIRK_NO_INPUT_SYNC			0x80000000
 
 /*
+ * HID device groups
+ */
+#define HID_GROUP_GENERIC			0x0001
+#define HID_GROUP_MULTITOUCH			0x0002
+
+/*
  * This is the global environment of the parser. This information is
  * persistent for main-items. The global environment can be saved and
  * restored with PUSH/POP statements.
@@ -467,6 +472,8 @@
 struct hid_ll_driver;
 
 struct hid_device {							/* device report descriptor */
+	__u8 *dev_rdesc;
+	unsigned dev_rsize;
 	__u8 *rdesc;
 	unsigned rsize;
 	struct hid_collection *collection;				/* List of HID collections */
@@ -474,6 +481,7 @@
 	unsigned maxcollection;						/* Number of parsed collections */
 	unsigned maxapplication;					/* Number of applications */
 	__u16 bus;							/* BUS ID */
+	__u16 group;							/* Report group */
 	__u32 vendor;							/* Vendor ID */
 	__u32 product;							/* Product ID */
 	__u32 version;							/* HID version */
@@ -578,12 +586,12 @@
 	struct hid_class_descriptor desc[1];
 } __attribute__ ((packed));
 
-#define HID_DEVICE(b, ven, prod) \
-	.bus = (b), \
-	.vendor = (ven), .product = (prod)
-
-#define HID_USB_DEVICE(ven, prod)	HID_DEVICE(BUS_USB, ven, prod)
-#define HID_BLUETOOTH_DEVICE(ven, prod)	HID_DEVICE(BUS_BLUETOOTH, ven, prod)
+#define HID_DEVICE(b, g, ven, prod)					\
+	.bus = (b), .group = (g), .vendor = (ven), .product = (prod)
+#define HID_USB_DEVICE(ven, prod)				\
+	.bus = BUS_USB, .vendor = (ven), .product = (prod)
+#define HID_BLUETOOTH_DEVICE(ven, prod)					\
+	.bus = BUS_BLUETOOTH, .vendor = (ven), .product = (prod)
 
 #define HID_REPORT_ID(rep) \
 	.report_type = (rep)
@@ -735,6 +743,7 @@
 struct hid_device *hid_allocate_device(void);
 struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
 int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+int hid_open_report(struct hid_device *device);
 int hid_check_keys_pressed(struct hid_device *hid);
 int hid_connect(struct hid_device *hid, unsigned int connect_mask);
 void hid_disconnect(struct hid_device *hid);
@@ -805,16 +814,7 @@
  */
 static inline int __must_check hid_parse(struct hid_device *hdev)
 {
-	int ret;
-
-	if (hdev->status & HID_STAT_PARSED)
-		return 0;
-
-	ret = hdev->ll_driver->parse(hdev);
-	if (!ret)
-		hdev->status |= HID_STAT_PARSED;
-
-	return ret;
+	return hid_open_report(hdev);
 }
 
 /**
@@ -896,7 +896,7 @@
 	return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0;
 }
 
-void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
 		int interrupt);
 
 extern int hid_generic_init(void);
diff --git a/include/linux/hidraw.h b/include/linux/hidraw.h
index 4b88e69..45e9fcb 100644
--- a/include/linux/hidraw.h
+++ b/include/linux/hidraw.h
@@ -76,13 +76,13 @@
 #ifdef CONFIG_HIDRAW
 int hidraw_init(void);
 void hidraw_exit(void);
-void hidraw_report_event(struct hid_device *, u8 *, int);
+int hidraw_report_event(struct hid_device *, u8 *, int);
 int hidraw_connect(struct hid_device *);
 void hidraw_disconnect(struct hid_device *);
 #else
 static inline int hidraw_init(void) { return 0; }
 static inline void hidraw_exit(void) { }
-static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { }
+static inline int hidraw_report_event(struct hid_device *hid, u8 *data, int len) { return 0; }
 static inline int hidraw_connect(struct hid_device *hid) { return -1; }
 static inline void hidraw_disconnect(struct hid_device *hid) { }
 #endif
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 6af8738..68ed7f7 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1062,8 +1062,10 @@
 	void (*callback) (void *context);
 };
 
+#define MAX_SRV_VER	0x7ffffff
 extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *,
-				      struct icmsg_negotiate *, u8 *);
+					struct icmsg_negotiate *, u8 *, int,
+					int);
 
 int hv_kvp_init(struct hv_util_service *);
 void hv_kvp_deinit(void);
diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h
index a87124d4..1bc74af 100644
--- a/include/linux/i2c-pnx.h
+++ b/include/linux/i2c-pnx.h
@@ -29,14 +29,10 @@
 	struct i2c_pnx_mif	mif;
 	int			last;
 	struct clk		*clk;
-	struct i2c_pnx_data	*i2c_pnx;
 	struct i2c_adapter	adapter;
-};
-
-struct i2c_pnx_data {
-	const char *name;
-	u32 base;
-	int irq;
+	phys_addr_t		base;
+	int			irq;
+	u32			timeout;
 };
 
 #endif /* __I2C_PNX_H__ */
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
index cec17cf..d8341cb 100644
--- a/include/linux/i2c/adp5588.h
+++ b/include/linux/i2c/adp5588.h
@@ -157,6 +157,7 @@
 
 struct adp5588_gpio_platform_data {
 	int gpio_start;		/* GPIO Chip base # */
+	const char *const *names;
 	unsigned irq_base;	/* interrupt base # */
 	unsigned pullup_dis_mask; /* Pull-Up Disable Mask */
 	int	(*setup)(struct i2c_client *client,
diff --git a/include/linux/i2o-dev.h b/include/linux/i2o-dev.h
index a0b23dd..a8093bf 100644
--- a/include/linux/i2o-dev.h
+++ b/include/linux/i2o-dev.h
@@ -124,7 +124,7 @@
 #define I2O_BUS_LOCAL	0
 #define I2O_BUS_ISA	1
 #define I2O_BUS_EISA	2
-#define I2O_BUS_MCA	3
+/* was  I2O_BUS_MCA	3 */
 #define I2O_BUS_PCI	4
 #define I2O_BUS_PCMCIA	5
 #define I2O_BUS_NUBUS	6
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
new file mode 100644
index 0000000..fb0fe46
--- /dev/null
+++ b/include/linux/iio/buffer.h
@@ -0,0 +1,191 @@
+/* The industrial I/O core - generic buffer interfaces.
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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 _IIO_BUFFER_GENERIC_H_
+#define _IIO_BUFFER_GENERIC_H_
+#include <linux/sysfs.h>
+#include <linux/iio/iio.h>
+
+#ifdef CONFIG_IIO_BUFFER
+
+struct iio_buffer;
+
+/**
+ * struct iio_buffer_access_funcs - access functions for buffers.
+ * @store_to:		actually store stuff to the buffer
+ * @read_first_n:	try to get a specified number of bytes (must exist)
+ * @request_update:	if a parameter change has been marked, update underlying
+ *			storage.
+ * @get_bytes_per_datum:get current bytes per datum
+ * @set_bytes_per_datum:set number of bytes per datum
+ * @get_length:		get number of datums in buffer
+ * @set_length:		set number of datums in buffer
+ *
+ * The purpose of this structure is to make the buffer element
+ * modular as event for a given driver, different usecases may require
+ * different buffer designs (space efficiency vs speed for example).
+ *
+ * It is worth noting that a given buffer implementation may only support a
+ * small proportion of these functions.  The core code 'should' cope fine with
+ * any of them not existing.
+ **/
+struct iio_buffer_access_funcs {
+	int (*store_to)(struct iio_buffer *buffer, u8 *data, s64 timestamp);
+	int (*read_first_n)(struct iio_buffer *buffer,
+			    size_t n,
+			    char __user *buf);
+
+	int (*request_update)(struct iio_buffer *buffer);
+
+	int (*get_bytes_per_datum)(struct iio_buffer *buffer);
+	int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
+	int (*get_length)(struct iio_buffer *buffer);
+	int (*set_length)(struct iio_buffer *buffer, int length);
+};
+
+/**
+ * struct iio_buffer - general buffer structure
+ * @length:		[DEVICE] number of datums in buffer
+ * @bytes_per_datum:	[DEVICE] size of individual datum including timestamp
+ * @scan_el_attrs:	[DRIVER] control of scan elements if that scan mode
+ *			control method is used
+ * @scan_mask:		[INTERN] bitmask used in masking scan mode elements
+ * @scan_timestamp:	[INTERN] does the scan mode include a timestamp
+ * @access:		[DRIVER] buffer access functions associated with the
+ *			implementation.
+ * @scan_el_dev_attr_list:[INTERN] list of scan element related attributes.
+ * @scan_el_group:	[DRIVER] attribute group for those attributes not
+ *			created from the iio_chan_info array.
+ * @pollq:		[INTERN] wait queue to allow for polling on the buffer.
+ * @stufftoread:	[INTERN] flag to indicate new data.
+ * @demux_list:		[INTERN] list of operations required to demux the scan.
+ * @demux_bounce:	[INTERN] buffer for doing gather from incoming scan.
+ **/
+struct iio_buffer {
+	int					length;
+	int					bytes_per_datum;
+	struct attribute_group			*scan_el_attrs;
+	long					*scan_mask;
+	bool					scan_timestamp;
+	const struct iio_buffer_access_funcs	*access;
+	struct list_head			scan_el_dev_attr_list;
+	struct attribute_group			scan_el_group;
+	wait_queue_head_t			pollq;
+	bool					stufftoread;
+	const struct attribute_group *attrs;
+	struct list_head			demux_list;
+	unsigned char				*demux_bounce;
+};
+
+/**
+ * iio_buffer_init() - Initialize the buffer structure
+ * @buffer: buffer to be initialized
+ **/
+void iio_buffer_init(struct iio_buffer *buffer);
+
+/**
+ * __iio_update_buffer() - update common elements of buffers
+ * @buffer:		buffer that is the event source
+ * @bytes_per_datum:	size of individual datum including timestamp
+ * @length:		number of datums in buffer
+ **/
+static inline void __iio_update_buffer(struct iio_buffer *buffer,
+				       int bytes_per_datum, int length)
+{
+	buffer->bytes_per_datum = bytes_per_datum;
+	buffer->length = length;
+}
+
+int iio_scan_mask_query(struct iio_dev *indio_dev,
+			struct iio_buffer *buffer, int bit);
+
+/**
+ * iio_scan_mask_set() - set particular bit in the scan mask
+ * @buffer: the buffer whose scan mask we are interested in
+ * @bit: the bit to be set.
+ **/
+int iio_scan_mask_set(struct iio_dev *indio_dev,
+		      struct iio_buffer *buffer, int bit);
+
+/**
+ * iio_push_to_buffer() - push to a registered buffer.
+ * @buffer:		IIO buffer structure for device
+ * @scan:		Full scan.
+ * @timestamp:
+ */
+int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
+		       s64 timestamp);
+
+int iio_update_demux(struct iio_dev *indio_dev);
+
+/**
+ * iio_buffer_register() - register the buffer with IIO core
+ * @indio_dev: device with the buffer to be registered
+ **/
+int iio_buffer_register(struct iio_dev *indio_dev,
+			const struct iio_chan_spec *channels,
+			int num_channels);
+
+/**
+ * iio_buffer_unregister() - unregister the buffer from IIO core
+ * @indio_dev: the device with the buffer to be unregistered
+ **/
+void iio_buffer_unregister(struct iio_dev *indio_dev);
+
+/**
+ * iio_buffer_read_length() - attr func to get number of datums in the buffer
+ **/
+ssize_t iio_buffer_read_length(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf);
+/**
+ * iio_buffer_write_length() - attr func to set number of datums in the buffer
+ **/
+ssize_t iio_buffer_write_length(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf,
+			      size_t len);
+/**
+ * iio_buffer_store_enable() - attr to turn the buffer on
+ **/
+ssize_t iio_buffer_store_enable(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t len);
+/**
+ * iio_buffer_show_enable() - attr to see if the buffer is on
+ **/
+ssize_t iio_buffer_show_enable(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf);
+#define IIO_BUFFER_LENGTH_ATTR DEVICE_ATTR(length, S_IRUGO | S_IWUSR,	\
+					   iio_buffer_read_length,	\
+					   iio_buffer_write_length)
+
+#define IIO_BUFFER_ENABLE_ATTR DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,	\
+					   iio_buffer_show_enable,	\
+					   iio_buffer_store_enable)
+
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev);
+
+#else /* CONFIG_IIO_BUFFER */
+
+static inline int iio_buffer_register(struct iio_dev *indio_dev,
+					   struct iio_chan_spec *channels,
+					   int num_channels)
+{
+	return 0;
+}
+
+static inline void iio_buffer_unregister(struct iio_dev *indio_dev)
+{};
+
+#endif /* CONFIG_IIO_BUFFER */
+
+#endif /* _IIO_BUFFER_GENERIC_H_ */
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
new file mode 100644
index 0000000..1a15e560
--- /dev/null
+++ b/include/linux/iio/consumer.h
@@ -0,0 +1,96 @@
+/*
+ * Industrial I/O in kernel consumer interface
+ *
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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 _IIO_INKERN_CONSUMER_H_
+#define _IIO_INKERN_CONSUMER_H
+#include <linux/iio/types.h>
+
+struct iio_dev;
+struct iio_chan_spec;
+
+/**
+ * struct iio_channel - everything needed for a consumer to use a channel
+ * @indio_dev:		Device on which the channel exists.
+ * @channel:		Full description of the channel.
+ */
+struct iio_channel {
+	struct iio_dev *indio_dev;
+	const struct iio_chan_spec *channel;
+};
+
+/**
+ * iio_channel_get() - get description of all that is needed to access channel.
+ * @name:		Unique name of the device as provided in the iio_map
+ *			with which the desired provider to consumer mapping
+ *			was registered.
+ * @consumer_channel:	Unique name to identify the channel on the consumer
+ *			side. This typically describes the channels use within
+ *			the consumer. E.g. 'battery_voltage'
+ */
+struct iio_channel *iio_st_channel_get(const char *name,
+				       const char *consumer_channel);
+
+/**
+ * iio_st_channel_release() - release channels obtained via iio_st_channel_get
+ * @chan:		The channel to be released.
+ */
+void iio_st_channel_release(struct iio_channel *chan);
+
+/**
+ * iio_st_channel_get_all() - get all channels associated with a client
+ * @name:		name of consumer device.
+ *
+ * Returns an array of iio_channel structures terminated with one with
+ * null iio_dev pointer.
+ * This function is used by fairly generic consumers to get all the
+ * channels registered as having this consumer.
+ */
+struct iio_channel *iio_st_channel_get_all(const char *name);
+
+/**
+ * iio_st_channel_release_all() - reverse iio_st_get_all
+ * @chan:		Array of channels to be released.
+ */
+void iio_st_channel_release_all(struct iio_channel *chan);
+
+/**
+ * iio_st_read_channel_raw() - read from a given channel
+ * @channel:		The channel being queried.
+ * @val:		Value read back.
+ *
+ * Note raw reads from iio channels are in adc counts and hence
+ * scale will need to be applied if standard units required.
+ */
+int iio_st_read_channel_raw(struct iio_channel *chan,
+			    int *val);
+
+/**
+ * iio_st_get_channel_type() - get the type of a channel
+ * @channel:		The channel being queried.
+ * @type:		The type of the channel.
+ *
+ * returns the enum iio_chan_type of the channel
+ */
+int iio_st_get_channel_type(struct iio_channel *channel,
+			    enum iio_chan_type *type);
+
+/**
+ * iio_st_read_channel_scale() - read the scale value for a channel
+ * @channel:		The channel being queried.
+ * @val:		First part of value read back.
+ * @val2:		Second part of value read back.
+ *
+ * Note returns a description of what is in val and val2, such
+ * as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val
+ * + val2/1e6
+ */
+int iio_st_read_channel_scale(struct iio_channel *chan, int *val,
+			      int *val2);
+
+#endif
diff --git a/drivers/staging/iio/driver.h b/include/linux/iio/driver.h
similarity index 100%
rename from drivers/staging/iio/driver.h
rename to include/linux/iio/driver.h
diff --git a/include/linux/iio/events.h b/include/linux/iio/events.h
new file mode 100644
index 0000000..b5acbf9
--- /dev/null
+++ b/include/linux/iio/events.h
@@ -0,0 +1,105 @@
+/* The industrial I/O - event passing to userspace
+ *
+ * Copyright (c) 2008-2011 Jonathan Cameron
+ *
+ * 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 _IIO_EVENTS_H_
+#define _IIO_EVENTS_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/iio/types.h>
+
+/**
+ * struct iio_event_data - The actual event being pushed to userspace
+ * @id:		event identifier
+ * @timestamp:	best estimate of time of event occurrence (often from
+ *		the interrupt handler)
+ */
+struct iio_event_data {
+	__u64	id;
+	__s64	timestamp;
+};
+
+#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int)
+
+enum iio_event_type {
+	IIO_EV_TYPE_THRESH,
+	IIO_EV_TYPE_MAG,
+	IIO_EV_TYPE_ROC,
+	IIO_EV_TYPE_THRESH_ADAPTIVE,
+	IIO_EV_TYPE_MAG_ADAPTIVE,
+};
+
+enum iio_event_direction {
+	IIO_EV_DIR_EITHER,
+	IIO_EV_DIR_RISING,
+	IIO_EV_DIR_FALLING,
+};
+
+/**
+ * IIO_EVENT_CODE() - create event identifier
+ * @chan_type:	Type of the channel. Should be one of enum iio_chan_type.
+ * @diff:	Whether the event is for an differential channel or not.
+ * @modifier:	Modifier for the channel. Should be one of enum iio_modifier.
+ * @direction:	Direction of the event. One of enum iio_event_direction.
+ * @type:	Type of the event. Should be one enum iio_event_type.
+ * @chan:	Channel number for non-differential channels.
+ * @chan1:	First channel number for differential channels.
+ * @chan2:	Second channel number for differential channels.
+ */
+
+#define IIO_EVENT_CODE(chan_type, diff, modifier, direction,		\
+		       type, chan, chan1, chan2)			\
+	(((u64)type << 56) | ((u64)diff << 55) |			\
+	 ((u64)direction << 48) | ((u64)modifier << 40) |		\
+	 ((u64)chan_type << 32) | (((u16)chan2) << 16) | ((u16)chan1) | \
+	 ((u16)chan))
+
+
+#define IIO_EV_DIR_MAX 4
+#define IIO_EV_BIT(type, direction)			\
+	(1 << (type*IIO_EV_DIR_MAX + direction))
+
+/**
+ * IIO_MOD_EVENT_CODE() - create event identifier for modified channels
+ * @chan_type:	Type of the channel. Should be one of enum iio_chan_type.
+ * @number:	Channel number.
+ * @modifier:	Modifier for the channel. Should be one of enum iio_modifier.
+ * @type:	Type of the event. Should be one enum iio_event_type.
+ * @direction:	Direction of the event. One of enum iio_event_direction.
+ */
+
+#define IIO_MOD_EVENT_CODE(chan_type, number, modifier,		\
+			   type, direction)				\
+	IIO_EVENT_CODE(chan_type, 0, modifier, direction, type, number, 0, 0)
+
+/**
+ * IIO_UNMOD_EVENT_CODE() - create event identifier for unmodified channels
+ * @chan_type:	Type of the channel. Should be one of enum iio_chan_type.
+ * @number:	Channel number.
+ * @type:	Type of the event. Should be one enum iio_event_type.
+ * @direction:	Direction of the event. One of enum iio_event_direction.
+ */
+
+#define IIO_UNMOD_EVENT_CODE(chan_type, number, type, direction)	\
+	IIO_EVENT_CODE(chan_type, 0, 0, direction, type, number, 0, 0)
+
+#define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF)
+
+#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0xCF)
+
+#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF)
+
+/* Event code number extraction depends on which type of event we have.
+ * Perhaps review this function in the future*/
+#define IIO_EVENT_CODE_EXTRACT_CHAN(mask) ((__s16)(mask & 0xFFFF))
+#define IIO_EVENT_CODE_EXTRACT_CHAN2(mask) ((__s16)(((mask) >> 16) & 0xFFFF))
+
+#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF)
+#define IIO_EVENT_CODE_EXTRACT_DIFF(mask) (((mask) >> 55) & 0x1)
+
+#endif
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
new file mode 100644
index 0000000..3a4f6a3
--- /dev/null
+++ b/include/linux/iio/iio.h
@@ -0,0 +1,492 @@
+
+/* The industrial I/O core
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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 _INDUSTRIAL_IO_H_
+#define _INDUSTRIAL_IO_H_
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/iio/types.h>
+/* IIO TODO LIST */
+/*
+ * Provide means of adjusting timer accuracy.
+ * Currently assumes nano seconds.
+ */
+
+enum iio_chan_info_enum {
+	IIO_CHAN_INFO_RAW = 0,
+	IIO_CHAN_INFO_PROCESSED,
+	IIO_CHAN_INFO_SCALE,
+	IIO_CHAN_INFO_OFFSET,
+	IIO_CHAN_INFO_CALIBSCALE,
+	IIO_CHAN_INFO_CALIBBIAS,
+	IIO_CHAN_INFO_PEAK,
+	IIO_CHAN_INFO_PEAK_SCALE,
+	IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
+	IIO_CHAN_INFO_AVERAGE_RAW,
+	IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY,
+	IIO_CHAN_INFO_SAMP_FREQ,
+	IIO_CHAN_INFO_FREQUENCY,
+	IIO_CHAN_INFO_PHASE,
+	IIO_CHAN_INFO_HARDWAREGAIN,
+};
+
+#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2)
+#define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1)
+
+#define IIO_CHAN_INFO_RAW_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_RAW)
+#define IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PROCESSED)
+#define IIO_CHAN_INFO_SCALE_SEPARATE_BIT		\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SCALE)
+#define IIO_CHAN_INFO_SCALE_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SCALE)
+#define IIO_CHAN_INFO_OFFSET_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_OFFSET)
+#define IIO_CHAN_INFO_OFFSET_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_OFFSET)
+#define IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBSCALE)
+#define IIO_CHAN_INFO_CALIBSCALE_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBSCALE)
+#define IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBBIAS)
+#define IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBBIAS)
+#define IIO_CHAN_INFO_PEAK_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAK)
+#define IIO_CHAN_INFO_PEAK_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAK)
+#define IIO_CHAN_INFO_PEAKSCALE_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAKSCALE)
+#define IIO_CHAN_INFO_PEAKSCALE_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAKSCALE)
+#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT	\
+	IIO_CHAN_INFO_SEPARATE_BIT(				\
+		IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
+#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED_BIT	\
+	IIO_CHAN_INFO_SHARED_BIT(				\
+		IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
+#define IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
+#define IIO_CHAN_INFO_AVERAGE_RAW_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
+#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT \
+	IIO_CHAN_INFO_SHARED_BIT(			       \
+		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
+#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT \
+	IIO_CHAN_INFO_SEPARATE_BIT(			       \
+		IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
+#define IIO_CHAN_INFO_SAMP_FREQ_SEPARATE_BIT		\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SAMP_FREQ)
+#define IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SAMP_FREQ)
+#define IIO_CHAN_INFO_FREQUENCY_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_FREQUENCY)
+#define IIO_CHAN_INFO_FREQUENCY_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_FREQUENCY)
+#define IIO_CHAN_INFO_PHASE_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PHASE)
+#define IIO_CHAN_INFO_PHASE_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PHASE)
+#define IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_HARDWAREGAIN)
+#define IIO_CHAN_INFO_HARDWAREGAIN_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_HARDWAREGAIN)
+
+enum iio_endian {
+	IIO_CPU,
+	IIO_BE,
+	IIO_LE,
+};
+
+struct iio_chan_spec;
+struct iio_dev;
+
+/**
+ * struct iio_chan_spec_ext_info - Extended channel info attribute
+ * @name:	Info attribute name
+ * @shared:	Whether this attribute is shared between all channels.
+ * @read:	Read callback for this info attribute, may be NULL.
+ * @write:	Write callback for this info attribute, may be NULL.
+ * @private:	Data private to the driver.
+ */
+struct iio_chan_spec_ext_info {
+	const char *name;
+	bool shared;
+	ssize_t (*read)(struct iio_dev *, uintptr_t private,
+			struct iio_chan_spec const *, char *buf);
+	ssize_t (*write)(struct iio_dev *, uintptr_t private,
+			 struct iio_chan_spec const *, const char *buf,
+			 size_t len);
+	uintptr_t private;
+};
+
+/**
+ * struct iio_chan_spec - specification of a single channel
+ * @type:		What type of measurement is the channel making.
+ * @channel:		What number or name do we wish to assign the channel.
+ * @channel2:		If there is a second number for a differential
+ *			channel then this is it. If modified is set then the
+ *			value here specifies the modifier.
+ * @address:		Driver specific identifier.
+ * @scan_index:	Monotonic index to give ordering in scans when read
+ *			from a buffer.
+ * @scan_type:		Sign:		's' or 'u' to specify signed or unsigned
+ *			realbits:	Number of valid bits of data
+ *			storage_bits:	Realbits + padding
+ *			shift:		Shift right by this before masking out
+ *					realbits.
+ *			endianness:	little or big endian
+ * @info_mask:		What information is to be exported about this channel.
+ *			This includes calibbias, scale etc.
+ * @event_mask:	What events can this channel produce.
+ * @ext_info:		Array of extended info attributes for this channel.
+ *			The array is NULL terminated, the last element should
+ *			have it's name field set to NULL.
+ * @extend_name:	Allows labeling of channel attributes with an
+ *			informative name. Note this has no effect codes etc,
+ *			unlike modifiers.
+ * @datasheet_name:	A name used in in kernel mapping of channels. It should
+ *			correspond to the first name that the channel is referred
+ *			to by in the datasheet (e.g. IND), or the nearest
+ *			possible compound name (e.g. IND-INC).
+ * @modified:		Does a modifier apply to this channel. What these are
+ *			depends on the channel type.  Modifier is set in
+ *			channel2. Examples are IIO_MOD_X for axial sensors about
+ *			the 'x' axis.
+ * @indexed:		Specify the channel has a numerical index. If not,
+ *			the value in channel will be suppressed for attribute
+ *			but not for event codes. Typically set it to 0 when
+ *			the index is false.
+ * @differential:	Channel is differential.
+ */
+struct iio_chan_spec {
+	enum iio_chan_type	type;
+	int			channel;
+	int			channel2;
+	unsigned long		address;
+	int			scan_index;
+	struct {
+		char	sign;
+		u8	realbits;
+		u8	storagebits;
+		u8	shift;
+		enum iio_endian endianness;
+	} scan_type;
+	long			info_mask;
+	long			event_mask;
+	const struct iio_chan_spec_ext_info *ext_info;
+	const char		*extend_name;
+	const char		*datasheet_name;
+	unsigned		modified:1;
+	unsigned		indexed:1;
+	unsigned		output:1;
+	unsigned		differential:1;
+};
+
+#define IIO_ST(si, rb, sb, sh)						\
+	{ .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
+
+#define IIO_CHAN_SOFT_TIMESTAMP(_si)					\
+	{ .type = IIO_TIMESTAMP, .channel = -1,				\
+			.scan_index = _si, .scan_type = IIO_ST('s', 64, 64, 0) }
+
+/**
+ * iio_get_time_ns() - utility function to get a time stamp for events etc
+ **/
+static inline s64 iio_get_time_ns(void)
+{
+	struct timespec ts;
+	/*
+	 * calls getnstimeofday.
+	 * If hrtimers then up to ns accurate, if not microsecond.
+	 */
+	ktime_get_real_ts(&ts);
+
+	return timespec_to_ns(&ts);
+}
+
+/* Device operating modes */
+#define INDIO_DIRECT_MODE		0x01
+#define INDIO_BUFFER_TRIGGERED		0x02
+#define INDIO_BUFFER_HARDWARE		0x08
+
+#define INDIO_ALL_BUFFER_MODES					\
+	(INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE)
+
+struct iio_trigger; /* forward declaration */
+struct iio_dev;
+
+/**
+ * struct iio_info - constant information about device
+ * @driver_module:	module structure used to ensure correct
+ *			ownership of chrdevs etc
+ * @event_attrs:	event control attributes
+ * @attrs:		general purpose device attributes
+ * @read_raw:		function to request a value from the device.
+ *			mask specifies which value. Note 0 means a reading of
+ *			the channel in question.  Return value will specify the
+ *			type of value returned by the device. val and val2 will
+ *			contain the elements making up the returned value.
+ * @write_raw:		function to write a value to the device.
+ *			Parameters are the same as for read_raw.
+ * @write_raw_get_fmt:	callback function to query the expected
+ *			format/precision. If not set by the driver, write_raw
+ *			returns IIO_VAL_INT_PLUS_MICRO.
+ * @read_event_config:	find out if the event is enabled.
+ * @write_event_config:	set if the event is enabled.
+ * @read_event_value:	read a value associated with the event. Meaning
+ *			is event dependant. event_code specifies which event.
+ * @write_event_value:	write the value associated with the event.
+ *			Meaning is event dependent.
+ * @validate_trigger:	function to validate the trigger when the
+ *			current trigger gets changed.
+ **/
+struct iio_info {
+	struct module			*driver_module;
+	struct attribute_group		*event_attrs;
+	const struct attribute_group	*attrs;
+
+	int (*read_raw)(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val,
+			int *val2,
+			long mask);
+
+	int (*write_raw)(struct iio_dev *indio_dev,
+			 struct iio_chan_spec const *chan,
+			 int val,
+			 int val2,
+			 long mask);
+
+	int (*write_raw_get_fmt)(struct iio_dev *indio_dev,
+			 struct iio_chan_spec const *chan,
+			 long mask);
+
+	int (*read_event_config)(struct iio_dev *indio_dev,
+				 u64 event_code);
+
+	int (*write_event_config)(struct iio_dev *indio_dev,
+				  u64 event_code,
+				  int state);
+
+	int (*read_event_value)(struct iio_dev *indio_dev,
+				u64 event_code,
+				int *val);
+	int (*write_event_value)(struct iio_dev *indio_dev,
+				 u64 event_code,
+				 int val);
+	int (*validate_trigger)(struct iio_dev *indio_dev,
+				struct iio_trigger *trig);
+	int (*update_scan_mode)(struct iio_dev *indio_dev,
+				const unsigned long *scan_mask);
+	int (*debugfs_reg_access)(struct iio_dev *indio_dev,
+				  unsigned reg, unsigned writeval,
+				  unsigned *readval);
+};
+
+/**
+ * struct iio_buffer_setup_ops - buffer setup related callbacks
+ * @preenable:		[DRIVER] function to run prior to marking buffer enabled
+ * @postenable:		[DRIVER] function to run after marking buffer enabled
+ * @predisable:		[DRIVER] function to run prior to marking buffer
+ *			disabled
+ * @postdisable:	[DRIVER] function to run after marking buffer disabled
+ */
+struct iio_buffer_setup_ops {
+	int				(*preenable)(struct iio_dev *);
+	int				(*postenable)(struct iio_dev *);
+	int				(*predisable)(struct iio_dev *);
+	int				(*postdisable)(struct iio_dev *);
+};
+
+/**
+ * struct iio_dev - industrial I/O device
+ * @id:			[INTERN] used to identify device internally
+ * @modes:		[DRIVER] operating modes supported by device
+ * @currentmode:	[DRIVER] current operating mode
+ * @dev:		[DRIVER] device structure, should be assigned a parent
+ *			and owner
+ * @event_interface:	[INTERN] event chrdevs associated with interrupt lines
+ * @buffer:		[DRIVER] any buffer present
+ * @scan_bytes:		[INTERN] num bytes captured to be fed to buffer demux
+ * @mlock:		[INTERN] lock used to prevent simultaneous device state
+ *			changes
+ * @available_scan_masks: [DRIVER] optional array of allowed bitmasks
+ * @masklength:		[INTERN] the length of the mask established from
+ *			channels
+ * @active_scan_mask:	[INTERN] union of all scan masks requested by buffers
+ * @scan_timestamp:	[INTERN] set if any buffers have requested timestamp
+ * @scan_index_timestamp:[INTERN] cache of the index to the timestamp
+ * @trig:		[INTERN] current device trigger (buffer modes)
+ * @pollfunc:		[DRIVER] function run on trigger being received
+ * @channels:		[DRIVER] channel specification structure table
+ * @num_channels:	[DRIVER] number of chanels specified in @channels.
+ * @channel_attr_list:	[INTERN] keep track of automatically created channel
+ *			attributes
+ * @chan_attr_group:	[INTERN] group for all attrs in base directory
+ * @name:		[DRIVER] name of the device.
+ * @info:		[DRIVER] callbacks and constant info from driver
+ * @info_exist_lock:	[INTERN] lock to prevent use during removal
+ * @setup_ops:		[DRIVER] callbacks to call before and after buffer
+ *			enable/disable
+ * @chrdev:		[INTERN] associated character device
+ * @groups:		[INTERN] attribute groups
+ * @groupcounter:	[INTERN] index of next attribute group
+ * @flags:		[INTERN] file ops related flags including busy flag.
+ * @debugfs_dentry:	[INTERN] device specific debugfs dentry.
+ * @cached_reg_addr:	[INTERN] cached register address for debugfs reads.
+ */
+struct iio_dev {
+	int				id;
+
+	int				modes;
+	int				currentmode;
+	struct device			dev;
+
+	struct iio_event_interface	*event_interface;
+
+	struct iio_buffer		*buffer;
+	int				scan_bytes;
+	struct mutex			mlock;
+
+	const unsigned long		*available_scan_masks;
+	unsigned			masklength;
+	const unsigned long		*active_scan_mask;
+	bool				scan_timestamp;
+	unsigned			scan_index_timestamp;
+	struct iio_trigger		*trig;
+	struct iio_poll_func		*pollfunc;
+
+	struct iio_chan_spec const	*channels;
+	int				num_channels;
+
+	struct list_head		channel_attr_list;
+	struct attribute_group		chan_attr_group;
+	const char			*name;
+	const struct iio_info		*info;
+	struct mutex			info_exist_lock;
+	const struct iio_buffer_setup_ops	*setup_ops;
+	struct cdev			chrdev;
+#define IIO_MAX_GROUPS 6
+	const struct attribute_group	*groups[IIO_MAX_GROUPS + 1];
+	int				groupcounter;
+
+	unsigned long			flags;
+#if defined(CONFIG_DEBUG_FS)
+	struct dentry			*debugfs_dentry;
+	unsigned			cached_reg_addr;
+#endif
+};
+
+/**
+ * iio_find_channel_from_si() - get channel from its scan index
+ * @indio_dev:		device
+ * @si:			scan index to match
+ */
+const struct iio_chan_spec
+*iio_find_channel_from_si(struct iio_dev *indio_dev, int si);
+
+/**
+ * iio_device_register() - register a device with the IIO subsystem
+ * @indio_dev:		Device structure filled by the device driver
+ **/
+int iio_device_register(struct iio_dev *indio_dev);
+
+/**
+ * iio_device_unregister() - unregister a device from the IIO subsystem
+ * @indio_dev:		Device structure representing the device.
+ **/
+void iio_device_unregister(struct iio_dev *indio_dev);
+
+/**
+ * iio_push_event() - try to add event to the list for userspace reading
+ * @indio_dev:		IIO device structure
+ * @ev_code:		What event
+ * @timestamp:		When the event occurred
+ **/
+int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp);
+
+extern struct bus_type iio_bus_type;
+
+/**
+ * iio_device_put() - reference counted deallocation of struct device
+ * @dev: the iio_device containing the device
+ **/
+static inline void iio_device_put(struct iio_dev *indio_dev)
+{
+	if (indio_dev)
+		put_device(&indio_dev->dev);
+};
+
+/**
+ * dev_to_iio_dev() - Get IIO device struct from a device struct
+ * @dev: The device embedded in the IIO device
+ *
+ * Note: The device must be a IIO device, otherwise the result is undefined.
+ */
+static inline struct iio_dev *dev_to_iio_dev(struct device *dev)
+{
+	return container_of(dev, struct iio_dev, dev);
+}
+
+/* Can we make this smaller? */
+#define IIO_ALIGN L1_CACHE_BYTES
+/**
+ * iio_device_alloc() - allocate an iio_dev from a driver
+ * @sizeof_priv: Space to allocate for private structure.
+ **/
+struct iio_dev *iio_device_alloc(int sizeof_priv);
+
+static inline void *iio_priv(const struct iio_dev *indio_dev)
+{
+	return (char *)indio_dev + ALIGN(sizeof(struct iio_dev), IIO_ALIGN);
+}
+
+static inline struct iio_dev *iio_priv_to_dev(void *priv)
+{
+	return (struct iio_dev *)((char *)priv -
+				  ALIGN(sizeof(struct iio_dev), IIO_ALIGN));
+}
+
+/**
+ * iio_device_free() - free an iio_dev from a driver
+ * @dev: the iio_dev associated with the device
+ **/
+void iio_device_free(struct iio_dev *indio_dev);
+
+/**
+ * iio_buffer_enabled() - helper function to test if the buffer is enabled
+ * @indio_dev:		IIO device info structure for device
+ **/
+static inline bool iio_buffer_enabled(struct iio_dev *indio_dev)
+{
+	return indio_dev->currentmode
+		& (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE);
+};
+
+/**
+ * iio_get_debugfs_dentry() - helper function to get the debugfs_dentry
+ * @indio_dev:		IIO device info structure for device
+ **/
+#if defined(CONFIG_DEBUG_FS)
+static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
+{
+	return indio_dev->debugfs_dentry;
+};
+#else
+static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
+{
+	return NULL;
+};
+#endif
+
+#endif /* _INDUSTRIAL_IO_H_ */
diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h
new file mode 100644
index 0000000..014d5a1
--- /dev/null
+++ b/include/linux/iio/kfifo_buf.h
@@ -0,0 +1,8 @@
+
+#include <linux/kfifo.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+
+struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
+void iio_kfifo_free(struct iio_buffer *r);
+
diff --git a/drivers/staging/iio/machine.h b/include/linux/iio/machine.h
similarity index 100%
rename from drivers/staging/iio/machine.h
rename to include/linux/iio/machine.h
diff --git a/drivers/staging/iio/sysfs.h b/include/linux/iio/sysfs.h
similarity index 100%
rename from drivers/staging/iio/sysfs.h
rename to include/linux/iio/sysfs.h
diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h
new file mode 100644
index 0000000..a981994
--- /dev/null
+++ b/include/linux/iio/trigger.h
@@ -0,0 +1,119 @@
+/* The industrial I/O core, trigger handling functions
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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/irq.h>
+#include <linux/module.h>
+
+#ifndef _IIO_TRIGGER_H_
+#define _IIO_TRIGGER_H_
+
+struct iio_subirq {
+	bool enabled;
+};
+
+/**
+ * struct iio_trigger_ops - operations structure for an iio_trigger.
+ * @owner:		used to monitor usage count of the trigger.
+ * @set_trigger_state:	switch on/off the trigger on demand
+ * @try_reenable:	function to reenable the trigger when the
+ *			use count is zero (may be NULL)
+ * @validate_device:	function to validate the device when the
+ *			current trigger gets changed.
+ *
+ * This is typically static const within a driver and shared by
+ * instances of a given device.
+ **/
+struct iio_trigger_ops {
+	struct module			*owner;
+	int (*set_trigger_state)(struct iio_trigger *trig, bool state);
+	int (*try_reenable)(struct iio_trigger *trig);
+	int (*validate_device)(struct iio_trigger *trig,
+			       struct iio_dev *indio_dev);
+};
+
+
+/**
+ * struct iio_trigger - industrial I/O trigger device
+ *
+ * @id:			[INTERN] unique id number
+ * @name:		[DRIVER] unique name
+ * @dev:		[DRIVER] associated device (if relevant)
+ * @private_data:	[DRIVER] device specific data
+ * @list:		[INTERN] used in maintenance of global trigger list
+ * @alloc_list:		[DRIVER] used for driver specific trigger list
+ * @use_count:		use count for the trigger
+ * @subirq_chip:	[INTERN] associate 'virtual' irq chip.
+ * @subirq_base:	[INTERN] base number for irqs provided by trigger.
+ * @subirqs:		[INTERN] information about the 'child' irqs.
+ * @pool:		[INTERN] bitmap of irqs currently in use.
+ * @pool_lock:		[INTERN] protection of the irq pool.
+ **/
+struct iio_trigger {
+	const struct iio_trigger_ops	*ops;
+	int				id;
+	const char			*name;
+	struct device			dev;
+
+	void				*private_data;
+	struct list_head		list;
+	struct list_head		alloc_list;
+	int use_count;
+
+	struct irq_chip			subirq_chip;
+	int				subirq_base;
+
+	struct iio_subirq subirqs[CONFIG_IIO_CONSUMERS_PER_TRIGGER];
+	unsigned long pool[BITS_TO_LONGS(CONFIG_IIO_CONSUMERS_PER_TRIGGER)];
+	struct mutex			pool_lock;
+};
+
+
+static inline struct iio_trigger *to_iio_trigger(struct device *d)
+{
+	return container_of(d, struct iio_trigger, dev);
+};
+
+static inline void iio_trigger_put(struct iio_trigger *trig)
+{
+	module_put(trig->ops->owner);
+	put_device(&trig->dev);
+};
+
+static inline void iio_trigger_get(struct iio_trigger *trig)
+{
+	get_device(&trig->dev);
+	__module_get(trig->ops->owner);
+};
+
+/**
+ * iio_trigger_register() - register a trigger with the IIO core
+ * @trig_info:	trigger to be registered
+ **/
+int iio_trigger_register(struct iio_trigger *trig_info);
+
+/**
+ * iio_trigger_unregister() - unregister a trigger from the core
+ * @trig_info:	trigger to be unregistered
+ **/
+void iio_trigger_unregister(struct iio_trigger *trig_info);
+
+/**
+ * iio_trigger_poll() - called on a trigger occurring
+ * @trig: trigger which occurred
+ *
+ * Typically called in relevant hardware interrupt handler.
+ **/
+void iio_trigger_poll(struct iio_trigger *trig, s64 time);
+void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time);
+
+irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private);
+
+__printf(1, 2) struct iio_trigger *iio_trigger_alloc(const char *fmt, ...);
+void iio_trigger_free(struct iio_trigger *trig);
+
+#endif /* _IIO_TRIGGER_H_ */
diff --git a/drivers/staging/iio/trigger_consumer.h b/include/linux/iio/trigger_consumer.h
similarity index 100%
rename from drivers/staging/iio/trigger_consumer.h
rename to include/linux/iio/trigger_consumer.h
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
new file mode 100644
index 0000000..1b073b1
--- /dev/null
+++ b/include/linux/iio/types.h
@@ -0,0 +1,55 @@
+/* industrial I/O data types needed both in and out of kernel
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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 _IIO_TYPES_H_
+#define _IIO_TYPES_H_
+
+enum iio_chan_type {
+	/* real channel types */
+	IIO_VOLTAGE,
+	IIO_CURRENT,
+	IIO_POWER,
+	IIO_ACCEL,
+	IIO_ANGL_VEL,
+	IIO_MAGN,
+	IIO_LIGHT,
+	IIO_INTENSITY,
+	IIO_PROXIMITY,
+	IIO_TEMP,
+	IIO_INCLI,
+	IIO_ROT,
+	IIO_ANGL,
+	IIO_TIMESTAMP,
+	IIO_CAPACITANCE,
+	IIO_ALTVOLTAGE,
+};
+
+enum iio_modifier {
+	IIO_NO_MOD,
+	IIO_MOD_X,
+	IIO_MOD_Y,
+	IIO_MOD_Z,
+	IIO_MOD_X_AND_Y,
+	IIO_MOD_X_AND_Z,
+	IIO_MOD_Y_AND_Z,
+	IIO_MOD_X_AND_Y_AND_Z,
+	IIO_MOD_X_OR_Y,
+	IIO_MOD_X_OR_Z,
+	IIO_MOD_Y_OR_Z,
+	IIO_MOD_X_OR_Y_OR_Z,
+	IIO_MOD_LIGHT_BOTH,
+	IIO_MOD_LIGHT_IR,
+};
+
+#define IIO_VAL_INT 1
+#define IIO_VAL_INT_PLUS_MICRO 2
+#define IIO_VAL_INT_PLUS_NANO 3
+#define IIO_VAL_INT_PLUS_MICRO_DB 4
+
+#endif /* _IIO_TYPES_H_ */
diff --git a/include/linux/input/lm8333.h b/include/linux/input/lm8333.h
new file mode 100644
index 0000000..79f918c
--- /dev/null
+++ b/include/linux/input/lm8333.h
@@ -0,0 +1,24 @@
+/*
+ * public include for LM8333 keypad driver - same license as driver
+ * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
+ */
+
+#ifndef _LM8333_H
+#define _LM8333_H
+
+struct lm8333;
+
+struct lm8333_platform_data {
+	/* Keymap data */
+	const struct matrix_keymap_data *matrix_data;
+	/* Active timeout before enter HALT mode in microseconds */
+	unsigned active_time;
+	/* Debounce interval in microseconds */
+	unsigned debounce_time;
+};
+
+extern int lm8333_read8(struct lm8333 *lm8333, u8 cmd);
+extern int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val);
+extern int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf);
+
+#endif /* _LM8333_H */
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h
index 6c07ced0..5f3aa6b 100644
--- a/include/linux/input/matrix_keypad.h
+++ b/include/linux/input/matrix_keypad.h
@@ -75,54 +75,10 @@
 	bool		no_autorepeat;
 };
 
-/**
- * matrix_keypad_build_keymap - convert platform keymap into matrix keymap
- * @keymap_data: keymap supplied by the platform code
- * @row_shift: number of bits to shift row value by to advance to the next
- * line in the keymap
- * @keymap: expanded version of keymap that is suitable for use by
- * matrix keyboad driver
- * @keybit: pointer to bitmap of keys supported by input device
- *
- * This function converts platform keymap (encoded with KEY() macro) into
- * an array of keycodes that is suitable for using in a standard matrix
- * keyboard driver that uses row and col as indices.
- */
-static inline void
-matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
-			   unsigned int row_shift,
-			   unsigned short *keymap, unsigned long *keybit)
-{
-	int i;
-
-	for (i = 0; i < keymap_data->keymap_size; i++) {
-		unsigned int key = keymap_data->keymap[i];
-		unsigned int row = KEY_ROW(key);
-		unsigned int col = KEY_COL(key);
-		unsigned short code = KEY_VAL(key);
-
-		keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
-		__set_bit(code, keybit);
-	}
-	__clear_bit(KEY_RESERVED, keybit);
-}
-
-#ifdef CONFIG_INPUT_OF_MATRIX_KEYMAP
-struct matrix_keymap_data *
-matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname);
-
-void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd);
-#else
-static inline struct matrix_keymap_data *
-matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname)
-{
-	return NULL;
-}
-
-static inline void
-matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
-{
-}
-#endif
+int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
+			       const char *keymap_name,
+			       unsigned int rows, unsigned int cols,
+			       unsigned short *keymap,
+			       struct input_dev *input_dev);
 
 #endif /* _MATRIX_KEYPAD_H */
diff --git a/include/linux/input/navpoint.h b/include/linux/input/navpoint.h
new file mode 100644
index 0000000..45050eb
--- /dev/null
+++ b/include/linux/input/navpoint.h
@@ -0,0 +1,12 @@
+/*
+ *  Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.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.
+ */
+
+struct navpoint_platform_data {
+	int		port;		/* PXA SSP port for pxa_ssp_request() */
+	int		gpio;		/* GPIO for power on/off */
+};
diff --git a/include/linux/irq.h b/include/linux/irq.h
index b27cfcf..61f5cec 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -335,11 +335,6 @@
 	void		(*irq_print_chip)(struct irq_data *data, struct seq_file *p);
 
 	unsigned long	flags;
-
-	/* Currently used only by UML, might disappear one day.*/
-#ifdef CONFIG_IRQ_RELEASE_METHOD
-	void		(*release)(unsigned int irq, void *dev_id);
-#endif
 };
 
 /*
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index 292f27a..215c416 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -15,6 +15,7 @@
 #define __ISDN_H__
 
 #include <linux/ioctl.h>
+#include <linux/tty.h>
 
 #define ISDN_MAX_DRIVERS    32
 #define ISDN_MAX_CHANNELS   64
@@ -392,21 +393,8 @@
 /*======================= Start of ISDN-tty stuff ===========================*/
 
 #define ISDN_ASYNC_MAGIC          0x49344C01 /* for paranoia-checking        */
-#define ISDN_ASYNC_INITIALIZED	  0x80000000 /* port was initialized         */
-#define ISDN_ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device active       */
-#define ISDN_ASYNC_NORMAL_ACTIVE  0x20000000 /* Normal device active         */
-#define ISDN_ASYNC_CLOSING	  0x08000000 /* Serial port is closing       */
-#define ISDN_ASYNC_CTS_FLOW	  0x04000000 /* Do CTS flow control          */
-#define ISDN_ASYNC_CHECK_CD	  0x02000000 /* i.e., CLOCAL                 */
-#define ISDN_ASYNC_HUP_NOTIFY         0x0001 /* Notify tty on hangups/closes */
-#define ISDN_ASYNC_SESSION_LOCKOUT    0x0100 /* Lock cua opens on session    */
-#define ISDN_ASYNC_PGRP_LOCKOUT       0x0200 /* Lock cua opens on pgrp       */
-#define ISDN_ASYNC_CALLOUT_NOHUP      0x0400 /* No hangup for cui            */
-#define ISDN_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
 #define ISDN_SERIAL_XMIT_SIZE           1024 /* Default bufsize for write    */
 #define ISDN_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
-#define ISDN_SERIAL_TYPE_NORMAL            1
-#define ISDN_SERIAL_TYPE_CALLOUT           2
 
 #ifdef CONFIG_ISDN_AUDIO
 /* For using sk_buffs with audio we need some private variables
@@ -448,17 +436,12 @@
 /* Private data (similar to async_struct in <linux/serial.h>) */
 typedef struct modem_info {
   int			magic;
-  struct module		*owner;
-  int			flags;		 /* defined in tty.h               */
+  struct tty_port	port;
   int			x_char;		 /* xon/xoff character             */
   int			mcr;		 /* Modem control register         */
   int                   msr;             /* Modem status register          */
   int                   lsr;             /* Line status register           */
   int			line;
-  int			count;		 /* # of fd on device              */
-  int			blocked_open;	 /* # of blocked opens             */
-  long			session;	 /* Session of opening process     */
-  long			pgrp;		 /* pgrp of opening process        */
   int                   online;          /* 1 = B-Channel is up, drop data */
 					 /* 2 = B-Channel is up, deliver d.*/
   int                   dialing;         /* Dial in progress or ATA        */
@@ -478,7 +461,6 @@
   int                   send_outstanding;/* # of outstanding send-requests */
   int                   xmit_size;       /* max. # of chars in xmit_buf    */
   int                   xmit_count;      /* # of chars in xmit_buf         */
-  unsigned char         *xmit_buf;       /* transmit buffer                */
   struct sk_buff_head   xmit_queue;      /* transmit queue                 */
   atomic_t              xmit_lock;       /* Semaphore for isdn_tty_write   */
 #ifdef CONFIG_ISDN_AUDIO
@@ -496,11 +478,7 @@
   struct T30_s		*fax;		 /* T30 Fax Group 3 data/interface */
   int			faxonline;	 /* Fax-channel status             */
 #endif
-  struct tty_struct 	*tty;            /* Pointer to corresponding tty   */
   atemu                 emu;             /* AT-emulator data               */
-  struct ktermios	normal_termios;  /* For saving termios structs     */
-  struct ktermios	callout_termios;
-  wait_queue_head_t	open_wait, close_wait;
   spinlock_t	        readlock;
 } modem_info;
 
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 645231c..c0d3442 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -480,15 +480,16 @@
 
 #define trace_printk(fmt, args...)					\
 do {									\
-	__trace_printk_check_format(fmt, ##args);			\
-	if (__builtin_constant_p(fmt)) {				\
-		static const char *trace_printk_fmt			\
-		  __attribute__((section("__trace_printk_fmt"))) =	\
-			__builtin_constant_p(fmt) ? fmt : NULL;		\
+	static const char *trace_printk_fmt				\
+		__attribute__((section("__trace_printk_fmt"))) =	\
+		__builtin_constant_p(fmt) ? fmt : NULL;			\
 									\
+	__trace_printk_check_format(fmt, ##args);			\
+									\
+	if (__builtin_constant_p(fmt))					\
 		__trace_bprintk(_THIS_IP_, trace_printk_fmt, ##args);	\
-	} else								\
-		__trace_printk(_THIS_IP_, fmt, ##args);		\
+	else								\
+		__trace_printk(_THIS_IP_, fmt, ##args);			\
 } while (0)
 
 extern __printf(2, 3)
diff --git a/include/linux/libata.h b/include/linux/libata.h
index e926df7..6e887c7 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -247,6 +247,7 @@
 	ATA_HOST_SIMPLEX	= (1 << 0),	/* Host is simplex, one DMA channel per host only */
 	ATA_HOST_STARTED	= (1 << 1),	/* Host started */
 	ATA_HOST_PARALLEL_SCAN	= (1 << 2),	/* Ports on this host can be scanned in parallel */
+	ATA_HOST_IGNORE_ATA	= (1 << 3),	/* Ignore ATA devices on this host. */
 
 	/* bits 24:31 of host->flags are reserved for LLD specific flags */
 
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index d36619e..00e4637 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -157,6 +157,24 @@
 #endif
 };
 
+static inline void lockdep_copy_map(struct lockdep_map *to,
+				    struct lockdep_map *from)
+{
+	int i;
+
+	*to = *from;
+	/*
+	 * Since the class cache can be modified concurrently we could observe
+	 * half pointers (64bit arch using 32bit copy insns). Therefore clear
+	 * the caches and take the performance hit.
+	 *
+	 * XXX it doesn't work well with lockdep_set_class_and_subclass(), since
+	 *     that relies on cache abuse.
+	 */
+	for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++)
+		to->class_cache[i] = NULL;
+}
+
 /*
  * Every lock has a list of other locks that were taken after it.
  * We only grow the list, never remove from it:
diff --git a/include/linux/mca-legacy.h b/include/linux/mca-legacy.h
deleted file mode 100644
index 7a3aea8..0000000
--- a/include/linux/mca-legacy.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/* This is the function prototypes for the old legacy MCA interface
- *
- * Please move your driver to the new sysfs based one instead */
-
-#ifndef _LINUX_MCA_LEGACY_H
-#define _LINUX_MCA_LEGACY_H
-
-#include <linux/mca.h>
-
-#warning "MCA legacy - please move your driver to the new sysfs api"
-
-/* MCA_NOTFOUND is an error condition.  The other two indicate
- * motherboard POS registers contain the adapter.  They might be
- * returned by the mca_find_adapter() function, and can be used as
- * arguments to mca_read_stored_pos().  I'm not going to allow direct
- * access to the motherboard registers until we run across an adapter
- * that requires it.  We don't know enough about them to know if it's
- * safe.
- *
- * See Documentation/mca.txt or one of the existing drivers for
- * more information.
- */
-#define MCA_NOTFOUND	(-1)
-
-
-
-/* Returns the slot of the first enabled adapter matching id.  User can
- * specify a starting slot beyond zero, to deal with detecting multiple
- * devices.  Returns MCA_NOTFOUND if id not found.  Also checks the
- * integrated adapters.
- */
-extern int mca_find_adapter(int id, int start);
-extern int mca_find_unused_adapter(int id, int start);
-
-extern int mca_mark_as_used(int slot);
-extern void mca_mark_as_unused(int slot);
-
-/* gets a byte out of POS register (stored in memory) */
-extern unsigned char mca_read_stored_pos(int slot, int reg);
-
-/* This can be expanded later.  Right now, it gives us a way of
- * getting meaningful information into the MCA_info structure,
- * so we can have a more interesting /proc/mca.
- */
-extern void mca_set_adapter_name(int slot, char* name);
-
-/* These routines actually mess with the hardware POS registers.  They
- * temporarily disable the device (and interrupts), so make sure you know
- * what you're doing if you use them.  Furthermore, writing to a POS may
- * result in two devices trying to share a resource, which in turn can
- * result in multiple devices sharing memory spaces, IRQs, or even trashing
- * hardware.  YOU HAVE BEEN WARNED.
- *
- * You can only access slots with this.  Motherboard registers are off
- * limits.
- */
-
-/* read a byte from the specified POS register. */
-extern unsigned char mca_read_pos(int slot, int reg);
-
-/* write a byte to the specified POS register. */
-extern void mca_write_pos(int slot, int reg, unsigned char byte);
-
-#endif
diff --git a/include/linux/mca.h b/include/linux/mca.h
deleted file mode 100644
index 3797270..0000000
--- a/include/linux/mca.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Header for Microchannel Architecture Bus
- * Written by Martin Kolinek, February 1996
- */
-
-#ifndef _LINUX_MCA_H
-#define _LINUX_MCA_H
-
-#include <linux/device.h>
-
-#ifdef CONFIG_MCA
-#include <asm/mca.h>
-
-extern int MCA_bus;
-#else
-#define MCA_bus 0
-#endif
-
-/* This sets up an information callback for /proc/mca/slot?.  The
- * function is called with the buffer, slot, and device pointer (or
- * some equally informative context information, or nothing, if you
- * prefer), and is expected to put useful information into the
- * buffer.  The adapter name, id, and POS registers get printed
- * before this is called though, so don't do it again.
- *
- * This should be called with a NULL procfn when a module
- * unregisters, thus preventing kernel crashes and other such
- * nastiness.
- */
-typedef int (*MCA_ProcFn)(char* buf, int slot, void* dev);
-
-/* Should only be called by the NMI interrupt handler, this will do some
- * fancy stuff to figure out what might have generated a NMI.
- */
-extern void mca_handle_nmi(void);
-
-enum MCA_AdapterStatus {
-	MCA_ADAPTER_NORMAL = 0,
-	MCA_ADAPTER_NONE = 1,
-	MCA_ADAPTER_DISABLED = 2,
-	MCA_ADAPTER_ERROR = 3
-};
-
-struct mca_device {
-	u64			dma_mask;
-	int			pos_id;
-	int			slot;
-
-	/* index into id_table, set by the bus match routine */
-	int			index;
-
-	/* is there a driver installed? 0 - No, 1 - Yes */
-	int			driver_loaded;
-	/* POS registers */
-	unsigned char		pos[8];
-	/* if a pseudo adapter of the motherboard, this is the motherboard
-	 * register value to use for setup cycles */
-	short			pos_register;
-	
-	enum MCA_AdapterStatus	status;
-#ifdef CONFIG_MCA_PROC_FS
-	/* name of the proc/mca file */
-	char			procname[8];
-	/* /proc info callback */
-	MCA_ProcFn		procfn;
-	/* device/context info for proc callback */
-	void			*proc_dev;
-#endif
-	struct device		dev;
-	char			name[32];
-};
-#define to_mca_device(mdev) container_of(mdev, struct mca_device, dev)
-
-struct mca_bus_accessor_functions {
-	unsigned char	(*mca_read_pos)(struct mca_device *, int reg);
-	void		(*mca_write_pos)(struct mca_device *, int reg,
-					 unsigned char byte);
-	int		(*mca_transform_irq)(struct mca_device *, int irq);
-	int		(*mca_transform_ioport)(struct mca_device *,
-						  int region);
-	void *		(*mca_transform_memory)(struct mca_device *,
-						void *memory);
-};
-
-struct mca_bus {
-	u64			default_dma_mask;
-	int			number;
-	struct mca_bus_accessor_functions f;
-	struct device		dev;
-	char			name[32];
-};
-#define to_mca_bus(mdev) container_of(mdev, struct mca_bus, dev)
-
-struct mca_driver {
-	const short		*id_table;
-	void			*driver_data;
-	int			integrated_id;
-	struct device_driver	driver;
-};
-#define to_mca_driver(mdriver) container_of(mdriver, struct mca_driver, driver)
-
-/* Ongoing supported API functions */
-extern struct mca_device *mca_find_device_by_slot(int slot);
-extern int mca_system_init(void);
-extern struct mca_bus *mca_attach_bus(int);
-
-extern unsigned char mca_device_read_stored_pos(struct mca_device *mca_dev,
-						int reg);
-extern unsigned char mca_device_read_pos(struct mca_device *mca_dev, int reg);
-extern void mca_device_write_pos(struct mca_device *mca_dev, int reg,
-				 unsigned char byte);
-extern int mca_device_transform_irq(struct mca_device *mca_dev, int irq);
-extern int mca_device_transform_ioport(struct mca_device *mca_dev, int port);
-extern void *mca_device_transform_memory(struct mca_device *mca_dev,
-					 void *mem);
-extern int mca_device_claimed(struct mca_device *mca_dev);
-extern void mca_device_set_claim(struct mca_device *mca_dev, int val);
-extern void mca_device_set_name(struct mca_device *mca_dev, const char *name);
-static inline char *mca_device_get_name(struct mca_device *mca_dev)
-{
-	return mca_dev ? mca_dev->name : NULL;
-}
-
-extern enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev);
-
-extern struct bus_type mca_bus_type;
-
-extern int mca_register_driver(struct mca_driver *drv);
-extern int mca_register_driver_integrated(struct mca_driver *, int);
-extern void mca_unregister_driver(struct mca_driver *drv);
-
-/* WARNING: only called by the boot time device setup */
-extern int mca_register_device(int bus, struct mca_device *mca_dev);
-
-#ifdef CONFIG_MCA_PROC_FS
-extern void mca_do_proc_init(void);
-extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev);
-#else
-static inline void mca_do_proc_init(void)
-{
-}
-
-static inline void mca_set_adapter_procfn(int slot, MCA_ProcFn fn, void* dev)
-{
-}
-#endif
-
-#endif /* _LINUX_MCA_H */
diff --git a/drivers/staging/mei/mei.h b/include/linux/mei.h
similarity index 100%
rename from drivers/staging/mei/mei.h
rename to include/linux/mei.h
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index ee96cd5..1318ca6 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -6,7 +6,7 @@
  *
  * ABX500 core access functions.
  * The abx500 interface is used for the Analog Baseband chip
- * ab3100, ab5500, and ab8500.
+ * ab3100 and ab8500.
  *
  * Author: Mattias Wallin <mattias.wallin@stericsson.com>
  * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
@@ -30,9 +30,6 @@
 #define AB3100_P1G	0xc6
 #define AB3100_R2A	0xc7
 #define AB3100_R2B	0xc8
-#define AB5500_1_0	0x20
-#define AB5500_1_1	0x21
-#define AB5500_2_0	0x24
 
 /*
  * AB3100, EVENTA1, A2 and A3 event register flags
diff --git a/include/linux/mfd/abx500/ab5500.h b/include/linux/mfd/abx500/ab5500.h
deleted file mode 100644
index 54f820e..0000000
--- a/include/linux/mfd/abx500/ab5500.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson 2011
- *
- * License Terms: GNU General Public License v2
- */
-#ifndef MFD_AB5500_H
-#define MFD_AB5500_H
-
-struct device;
-
-enum ab5500_devid {
-	AB5500_DEVID_ADC,
-	AB5500_DEVID_LEDS,
-	AB5500_DEVID_POWER,
-	AB5500_DEVID_REGULATORS,
-	AB5500_DEVID_SIM,
-	AB5500_DEVID_RTC,
-	AB5500_DEVID_CHARGER,
-	AB5500_DEVID_FUELGAUGE,
-	AB5500_DEVID_VIBRATOR,
-	AB5500_DEVID_CODEC,
-	AB5500_DEVID_USB,
-	AB5500_DEVID_OTP,
-	AB5500_DEVID_VIDEO,
-	AB5500_DEVID_DBIECI,
-	AB5500_DEVID_ONSWA,
-	AB5500_NUM_DEVICES,
-};
-
-enum ab5500_banks {
-	AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP = 0,
-	AB5500_BANK_VDDDIG_IO_I2C_CLK_TST = 1,
-	AB5500_BANK_VDENC = 2,
-	AB5500_BANK_SIM_USBSIM  = 3,
-	AB5500_BANK_LED = 4,
-	AB5500_BANK_ADC  = 5,
-	AB5500_BANK_RTC  = 6,
-	AB5500_BANK_STARTUP  = 7,
-	AB5500_BANK_DBI_ECI  = 8,
-	AB5500_BANK_CHG  = 9,
-	AB5500_BANK_FG_BATTCOM_ACC = 10,
-	AB5500_BANK_USB = 11,
-	AB5500_BANK_IT = 12,
-	AB5500_BANK_VIBRA = 13,
-	AB5500_BANK_AUDIO_HEADSETUSB = 14,
-	AB5500_NUM_BANKS = 15,
-};
-
-enum ab5500_banks_addr {
-	AB5500_ADDR_VIT_IO_I2C_CLK_TST_OTP = 0x4A,
-	AB5500_ADDR_VDDDIG_IO_I2C_CLK_TST = 0x4B,
-	AB5500_ADDR_VDENC = 0x06,
-	AB5500_ADDR_SIM_USBSIM  = 0x04,
-	AB5500_ADDR_LED = 0x10,
-	AB5500_ADDR_ADC  = 0x0A,
-	AB5500_ADDR_RTC  = 0x0F,
-	AB5500_ADDR_STARTUP  = 0x03,
-	AB5500_ADDR_DBI_ECI  = 0x07,
-	AB5500_ADDR_CHG  = 0x0B,
-	AB5500_ADDR_FG_BATTCOM_ACC = 0x0C,
-	AB5500_ADDR_USB = 0x05,
-	AB5500_ADDR_IT = 0x0E,
-	AB5500_ADDR_VIBRA = 0x02,
-	AB5500_ADDR_AUDIO_HEADSETUSB = 0x0D,
-};
-
-/*
- * Interrupt register offsets
- * Bank : 0x0E
- */
-#define AB5500_IT_SOURCE0_REG		0x20
-#define AB5500_IT_SOURCE1_REG		0x21
-#define AB5500_IT_SOURCE2_REG		0x22
-#define AB5500_IT_SOURCE3_REG		0x23
-#define AB5500_IT_SOURCE4_REG		0x24
-#define AB5500_IT_SOURCE5_REG		0x25
-#define AB5500_IT_SOURCE6_REG		0x26
-#define AB5500_IT_SOURCE7_REG		0x27
-#define AB5500_IT_SOURCE8_REG		0x28
-#define AB5500_IT_SOURCE9_REG		0x29
-#define AB5500_IT_SOURCE10_REG		0x2A
-#define AB5500_IT_SOURCE11_REG		0x2B
-#define AB5500_IT_SOURCE12_REG		0x2C
-#define AB5500_IT_SOURCE13_REG		0x2D
-#define AB5500_IT_SOURCE14_REG		0x2E
-#define AB5500_IT_SOURCE15_REG		0x2F
-#define AB5500_IT_SOURCE16_REG		0x30
-#define AB5500_IT_SOURCE17_REG		0x31
-#define AB5500_IT_SOURCE18_REG		0x32
-#define AB5500_IT_SOURCE19_REG		0x33
-#define AB5500_IT_SOURCE20_REG		0x34
-#define AB5500_IT_SOURCE21_REG		0x35
-#define AB5500_IT_SOURCE22_REG		0x36
-#define AB5500_IT_SOURCE23_REG		0x37
-
-#define AB5500_NUM_IRQ_REGS		23
-
-/**
- * struct ab5500
- * @access_mutex: lock out concurrent accesses to the AB registers
- * @dev: a pointer to the device struct for this chip driver
- * @ab5500_irq: the analog baseband irq
- * @irq_base: the platform configuration irq base for subdevices
- * @chip_name: name of this chip variant
- * @chip_id: 8 bit chip ID for this chip variant
- * @irq_lock: a lock to protect the mask
- * @abb_events: a local bit mask of the prcmu wakeup events
- * @event_mask: a local copy of the mask event registers
- * @last_event_mask: a copy of the last event_mask written to hardware
- * @startup_events: a copy of the first reading of the event registers
- * @startup_events_read: whether the first events have been read
- */
-struct ab5500 {
-	struct mutex access_mutex;
-	struct device *dev;
-	unsigned int ab5500_irq;
-	unsigned int irq_base;
-	char chip_name[32];
-	u8 chip_id;
-	struct mutex irq_lock;
-	u32 abb_events;
-	u8 mask[AB5500_NUM_IRQ_REGS];
-	u8 oldmask[AB5500_NUM_IRQ_REGS];
-	u8 startup_events[AB5500_NUM_IRQ_REGS];
-	bool startup_events_read;
-#ifdef CONFIG_DEBUG_FS
-	unsigned int debug_bank;
-	unsigned int debug_address;
-#endif
-};
-
-struct ab5500_platform_data {
-	struct {unsigned int base; unsigned int count; } irq;
-	void *dev_data[AB5500_NUM_DEVICES];
-	struct abx500_init_settings *init_settings;
-	unsigned int init_settings_sz;
-	bool pm_power_off;
-};
-
-#endif /* MFD_AB5500_H */
diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
index ed793b7..ef6faa5 100644
--- a/include/linux/mfd/asic3.h
+++ b/include/linux/mfd/asic3.h
@@ -138,6 +138,7 @@
 #define ASIC3_GPIOC13_nPWAIT		ASIC3_CONFIG_GPIO(45, 1, 1, 0)
 #define ASIC3_GPIOC14_nPIOIS16		ASIC3_CONFIG_GPIO(46, 1, 1, 0)
 #define ASIC3_GPIOC15_nPIOR		ASIC3_CONFIG_GPIO(47, 1, 0, 0)
+#define ASIC3_GPIOD4_CF_nCD		ASIC3_CONFIG_GPIO(52, 1, 0, 0)
 #define ASIC3_GPIOD11_nCIOIS16		ASIC3_CONFIG_GPIO(59, 1, 0, 0)
 #define ASIC3_GPIOD12_nCWAIT		ASIC3_CONFIG_GPIO(60, 1, 0, 0)
 #define ASIC3_GPIOD15_nPIOW		ASIC3_CONFIG_GPIO(63, 1, 0, 0)
diff --git a/include/linux/mfd/db5500-prcmu.h b/include/linux/mfd/db5500-prcmu.h
deleted file mode 100644
index 5a049df..0000000
--- a/include/linux/mfd/db5500-prcmu.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- *
- * U5500 PRCMU API.
- */
-#ifndef __MFD_DB5500_PRCMU_H
-#define __MFD_DB5500_PRCMU_H
-
-static inline int prcmu_resetout(u8 resoutn, u8 state)
-{
-	return 0;
-}
-
-static inline int db5500_prcmu_set_epod(u16 epod_id, u8 epod_state)
-{
-	return 0;
-}
-
-static inline int db5500_prcmu_request_clock(u8 clock, bool enable)
-{
-	return 0;
-}
-
-static inline int db5500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
-	bool keep_ap_pll)
-{
-	return 0;
-}
-
-static inline int db5500_prcmu_config_esram0_deep_sleep(u8 state)
-{
-	return 0;
-}
-
-static inline u16 db5500_prcmu_get_reset_code(void)
-{
-	return 0;
-}
-
-static inline bool db5500_prcmu_is_ac_wake_requested(void)
-{
-	return 0;
-}
-
-static inline int db5500_prcmu_set_arm_opp(u8 opp)
-{
-	return 0;
-}
-
-static inline int db5500_prcmu_get_arm_opp(void)
-{
-	return 0;
-}
-
-static inline void db5500_prcmu_config_abb_event_readout(u32 abb_events) {}
-
-static inline void db5500_prcmu_get_abb_event_buffer(void __iomem **buf) {}
-
-static inline void db5500_prcmu_system_reset(u16 reset_code) {}
-
-static inline void db5500_prcmu_enable_wakeups(u32 wakeups) {}
-
-#ifdef CONFIG_MFD_DB5500_PRCMU
-
-void db5500_prcmu_early_init(void);
-int db5500_prcmu_set_display_clocks(void);
-int db5500_prcmu_disable_dsipll(void);
-int db5500_prcmu_enable_dsipll(void);
-int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
-int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
-
-#else /* !CONFIG_UX500_SOC_DB5500 */
-
-static inline void db5500_prcmu_early_init(void) {}
-
-static inline int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
-{
-	return -ENOSYS;
-}
-
-static inline int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
-{
-	return -ENOSYS;
-}
-
-static inline int db5500_prcmu_set_display_clocks(void)
-{
-	return 0;
-}
-
-static inline int db5500_prcmu_disable_dsipll(void)
-{
-	return 0;
-}
-
-static inline int db5500_prcmu_enable_dsipll(void)
-{
-	return 0;
-}
-
-#endif /* CONFIG_MFD_DB5500_PRCMU */
-
-#endif /* __MFD_DB5500_PRCMU_H */
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index d7674eb..5a13f93 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -55,17 +55,6 @@
 #define NUM_EPOD_ID		8
 
 /*
- * DB5500 EPODs
- */
-#define DB5500_EPOD_ID_BASE 0x0100
-#define DB5500_EPOD_ID_SGA (DB5500_EPOD_ID_BASE + 0)
-#define DB5500_EPOD_ID_HVA (DB5500_EPOD_ID_BASE + 1)
-#define DB5500_EPOD_ID_SIA (DB5500_EPOD_ID_BASE + 2)
-#define DB5500_EPOD_ID_DISP (DB5500_EPOD_ID_BASE + 3)
-#define DB5500_EPOD_ID_ESRAM12 (DB5500_EPOD_ID_BASE + 6)
-#define DB5500_NUM_EPOD_ID 7
-
-/*
  * state definition for EPOD (power domain)
  * - EPOD_STATE_NO_CHANGE: The EPOD should remain unchanged
  * - EPOD_STATE_OFF: The EPOD is switched off
@@ -80,29 +69,6 @@
 #define EPOD_STATE_ON_CLK_OFF	0x03
 #define EPOD_STATE_ON		0x04
 
-/* DB5500 CLKOUT IDs */
-enum {
-	DB5500_CLKOUT0 = 0,
-	DB5500_CLKOUT1,
-};
-
-/* DB5500 CLKOUTx sources */
-enum {
-	DB5500_CLKOUT_REF_CLK_SEL0,
-	DB5500_CLKOUT_RTC_CLK0_SEL0,
-	DB5500_CLKOUT_ULP_CLK_SEL0,
-	DB5500_CLKOUT_STATIC0,
-	DB5500_CLKOUT_REFCLK,
-	DB5500_CLKOUT_ULPCLK,
-	DB5500_CLKOUT_ARMCLK,
-	DB5500_CLKOUT_SYSACC0CLK,
-	DB5500_CLKOUT_SOC0PLLCLK,
-	DB5500_CLKOUT_SOC1PLLCLK,
-	DB5500_CLKOUT_DDRPLLCLK,
-	DB5500_CLKOUT_TVCLK,
-	DB5500_CLKOUT_IRDACLK,
-};
-
 /*
  * CLKOUT sources
  */
@@ -248,101 +214,66 @@
 };
 
 #include <linux/mfd/db8500-prcmu.h>
-#include <linux/mfd/db5500-prcmu.h>
 
-#if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
+#if defined(CONFIG_UX500_SOC_DB8500)
 
 #include <mach/id.h>
 
 static inline void __init prcmu_early_init(void)
 {
-	if (cpu_is_u5500())
-		return db5500_prcmu_early_init();
-	else
-		return db8500_prcmu_early_init();
+	return db8500_prcmu_early_init();
 }
 
 static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
 		bool keep_ap_pll)
 {
-	if (cpu_is_u5500())
-		return db5500_prcmu_set_power_state(state, keep_ulp_clk,
-			keep_ap_pll);
-	else
-		return db8500_prcmu_set_power_state(state, keep_ulp_clk,
-			keep_ap_pll);
+	return db8500_prcmu_set_power_state(state, keep_ulp_clk,
+		keep_ap_pll);
 }
 
 static inline u8 prcmu_get_power_state_result(void)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_get_power_state_result();
+	return db8500_prcmu_get_power_state_result();
 }
 
 static inline int prcmu_gic_decouple(void)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_gic_decouple();
+	return db8500_prcmu_gic_decouple();
 }
 
 static inline int prcmu_gic_recouple(void)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_gic_recouple();
+	return db8500_prcmu_gic_recouple();
 }
 
 static inline bool prcmu_gic_pending_irq(void)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_gic_pending_irq();
+	return db8500_prcmu_gic_pending_irq();
 }
 
 static inline bool prcmu_is_cpu_in_wfi(int cpu)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_is_cpu_in_wfi(cpu);
+	return db8500_prcmu_is_cpu_in_wfi(cpu);
 }
 
 static inline int prcmu_copy_gic_settings(void)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_copy_gic_settings();
+	return db8500_prcmu_copy_gic_settings();
 }
 
 static inline bool prcmu_pending_irq(void)
 {
-        if (cpu_is_u5500())
-                return -EINVAL;
-        else
-                return db8500_prcmu_pending_irq();
+	return db8500_prcmu_pending_irq();
 }
 
 static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_set_epod(epod_id, epod_state);
+	return db8500_prcmu_set_epod(epod_id, epod_state);
 }
 
 static inline void prcmu_enable_wakeups(u32 wakeups)
 {
-	if (cpu_is_u5500())
-		db5500_prcmu_enable_wakeups(wakeups);
-	else
-		db8500_prcmu_enable_wakeups(wakeups);
+	db8500_prcmu_enable_wakeups(wakeups);
 }
 
 static inline void prcmu_disable_wakeups(void)
@@ -352,18 +283,12 @@
 
 static inline void prcmu_config_abb_event_readout(u32 abb_events)
 {
-	if (cpu_is_u5500())
-		db5500_prcmu_config_abb_event_readout(abb_events);
-	else
-		db8500_prcmu_config_abb_event_readout(abb_events);
+	db8500_prcmu_config_abb_event_readout(abb_events);
 }
 
 static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
 {
-	if (cpu_is_u5500())
-		db5500_prcmu_get_abb_event_buffer(buf);
-	else
-		db8500_prcmu_get_abb_event_buffer(buf);
+	db8500_prcmu_get_abb_event_buffer(buf);
 }
 
 int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
@@ -374,10 +299,7 @@
 
 static inline int prcmu_request_clock(u8 clock, bool enable)
 {
-	if (cpu_is_u5500())
-		return db5500_prcmu_request_clock(clock, enable);
-	else
-		return db8500_prcmu_request_clock(clock, enable);
+	return db8500_prcmu_request_clock(clock, enable);
 }
 
 unsigned long prcmu_clock_rate(u8 clock);
@@ -386,211 +308,133 @@
 
 static inline int prcmu_set_ddr_opp(u8 opp)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_set_ddr_opp(opp);
+	return db8500_prcmu_set_ddr_opp(opp);
 }
 static inline int prcmu_get_ddr_opp(void)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_get_ddr_opp();
+	return db8500_prcmu_get_ddr_opp();
 }
 
 static inline int prcmu_set_arm_opp(u8 opp)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_set_arm_opp(opp);
+	return db8500_prcmu_set_arm_opp(opp);
 }
 
 static inline int prcmu_get_arm_opp(void)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_get_arm_opp();
+	return db8500_prcmu_get_arm_opp();
 }
 
 static inline int prcmu_set_ape_opp(u8 opp)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_set_ape_opp(opp);
+	return db8500_prcmu_set_ape_opp(opp);
 }
 
 static inline int prcmu_get_ape_opp(void)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_get_ape_opp();
+	return db8500_prcmu_get_ape_opp();
 }
 
 static inline void prcmu_system_reset(u16 reset_code)
 {
-	if (cpu_is_u5500())
-		return db5500_prcmu_system_reset(reset_code);
-	else
-		return db8500_prcmu_system_reset(reset_code);
+	return db8500_prcmu_system_reset(reset_code);
 }
 
 static inline u16 prcmu_get_reset_code(void)
 {
-	if (cpu_is_u5500())
-		return db5500_prcmu_get_reset_code();
-	else
-		return db8500_prcmu_get_reset_code();
+	return db8500_prcmu_get_reset_code();
 }
 
 void prcmu_ac_wake_req(void);
 void prcmu_ac_sleep_req(void);
 static inline void prcmu_modem_reset(void)
 {
-	if (cpu_is_u5500())
-		return;
-	else
-		return db8500_prcmu_modem_reset();
+	return db8500_prcmu_modem_reset();
 }
 
 static inline bool prcmu_is_ac_wake_requested(void)
 {
-	if (cpu_is_u5500())
-		return db5500_prcmu_is_ac_wake_requested();
-	else
-		return db8500_prcmu_is_ac_wake_requested();
+	return db8500_prcmu_is_ac_wake_requested();
 }
 
 static inline int prcmu_set_display_clocks(void)
 {
-	if (cpu_is_u5500())
-		return db5500_prcmu_set_display_clocks();
-	else
-		return db8500_prcmu_set_display_clocks();
+	return db8500_prcmu_set_display_clocks();
 }
 
 static inline int prcmu_disable_dsipll(void)
 {
-	if (cpu_is_u5500())
-		return db5500_prcmu_disable_dsipll();
-	else
-		return db8500_prcmu_disable_dsipll();
+	return db8500_prcmu_disable_dsipll();
 }
 
 static inline int prcmu_enable_dsipll(void)
 {
-	if (cpu_is_u5500())
-		return db5500_prcmu_enable_dsipll();
-	else
-		return db8500_prcmu_enable_dsipll();
+	return db8500_prcmu_enable_dsipll();
 }
 
 static inline int prcmu_config_esram0_deep_sleep(u8 state)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_config_esram0_deep_sleep(state);
+	return db8500_prcmu_config_esram0_deep_sleep(state);
 }
 
 static inline int prcmu_config_hotdog(u8 threshold)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_config_hotdog(threshold);
+	return db8500_prcmu_config_hotdog(threshold);
 }
 
 static inline int prcmu_config_hotmon(u8 low, u8 high)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_config_hotmon(low, high);
+	return db8500_prcmu_config_hotmon(low, high);
 }
 
 static inline int prcmu_start_temp_sense(u16 cycles32k)
 {
-	if (cpu_is_u5500())
-		return  -EINVAL;
-	else
-		return  db8500_prcmu_start_temp_sense(cycles32k);
+	return  db8500_prcmu_start_temp_sense(cycles32k);
 }
 
 static inline int prcmu_stop_temp_sense(void)
 {
-	if (cpu_is_u5500())
-		return  -EINVAL;
-	else
-		return  db8500_prcmu_stop_temp_sense();
+	return  db8500_prcmu_stop_temp_sense();
 }
 
 static inline u32 prcmu_read(unsigned int reg)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_read(reg);
+	return db8500_prcmu_read(reg);
 }
 
 static inline void prcmu_write(unsigned int reg, u32 value)
 {
-	if (cpu_is_u5500())
-		return;
-	else
-		db8500_prcmu_write(reg, value);
+	db8500_prcmu_write(reg, value);
 }
 
 static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
 {
-	if (cpu_is_u5500())
-		return;
-	else
-		db8500_prcmu_write_masked(reg, mask, value);
+	db8500_prcmu_write_masked(reg, mask, value);
 }
 
 static inline int prcmu_enable_a9wdog(u8 id)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_enable_a9wdog(id);
+	return db8500_prcmu_enable_a9wdog(id);
 }
 
 static inline int prcmu_disable_a9wdog(u8 id)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_disable_a9wdog(id);
+	return db8500_prcmu_disable_a9wdog(id);
 }
 
 static inline int prcmu_kick_a9wdog(u8 id)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_kick_a9wdog(id);
+	return db8500_prcmu_kick_a9wdog(id);
 }
 
 static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_load_a9wdog(id, timeout);
+	return db8500_prcmu_load_a9wdog(id, timeout);
 }
 
 static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
 {
-	if (cpu_is_u5500())
-		return -EINVAL;
-	else
-		return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
+	return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
 }
 #else
 
@@ -768,7 +612,7 @@
 	prcmu_write_masked(reg, bits, 0);
 }
 
-#if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
+#if defined(CONFIG_UX500_SOC_DB8500)
 
 /**
  * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h
index 28726dd..b40c08c 100644
--- a/include/linux/mfd/max8997.h
+++ b/include/linux/mfd/max8997.h
@@ -99,34 +99,11 @@
 
 /**
  * struct max8997_muic_platform_data
- * @usb_callback: callback function for USB
- *		  inform callee of USB type (HOST or DEVICE)
- *		  and attached state(true or false)
- * @charger_callback: callback function for charger
- *		  inform callee of charger_type
- *		  and attached state(true or false)
- * @deskdock_callback: callback function for desk dock
- *		  inform callee of attached state(true or false)
- * @cardock_callback: callback function for car dock
- *		  inform callee of attached state(true or false)
- * @mhl_callback: callback function for MHL (Mobile High-definition Link)
- *		  inform callee of attached state(true or false)
- * @uart_callback: callback function for JIG UART
- *		   inform callee of attached state(true or false)
  * @init_data: array of max8997_muic_reg_data
  *	       used for initializing registers of MAX8997 MUIC device
  * @num_init_data: array size of init_data
  */
 struct max8997_muic_platform_data {
-	void (*usb_callback)(enum max8997_muic_usb_type usb_type,
-		bool attached);
-	void (*charger_callback)(bool attached,
-		enum max8997_muic_charger_type charger_type);
-	void (*deskdock_callback) (bool attached);
-	void (*cardock_callback) (bool attached);
-	void (*mhl_callback) (bool attached);
-	void (*uart_callback) (bool attached);
-
 	struct max8997_muic_reg_data *init_data;
 	int num_init_data;
 };
diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h
index 10e038b..bf07075 100644
--- a/include/linux/mfd/mc13xxx.h
+++ b/include/linux/mfd/mc13xxx.h
@@ -170,6 +170,16 @@
 	bool atox;
 };
 
+enum mc13783_ssi_port {
+	MC13783_SSI1_PORT,
+	MC13783_SSI2_PORT,
+};
+
+struct mc13xxx_codec_platform_data {
+	enum mc13783_ssi_port adc_ssi_port;
+	enum mc13783_ssi_port dac_ssi_port;
+};
+
 struct mc13xxx_platform_data {
 #define MC13XXX_USE_TOUCHSCREEN (1 << 0)
 #define MC13XXX_USE_CODEC	(1 << 1)
@@ -181,6 +191,7 @@
 	struct mc13xxx_leds_platform_data *leds;
 	struct mc13xxx_buttons_platform_data *buttons;
 	struct mc13xxx_ts_platform_data touch;
+	struct mc13xxx_codec_platform_data *codec;
 };
 
 #define MC13XXX_ADC_MODE_TS		1
diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h
index 1d7a3f7..dcc9631 100644
--- a/include/linux/mfd/wm831x/pdata.h
+++ b/include/linux/mfd/wm831x/pdata.h
@@ -26,7 +26,7 @@
 struct wm831x_backup_pdata {
 	int charger_enable;
 	int no_constant_voltage;  /** Disable constant voltage charging */
-	int vlim;   /** Voltage limit in milivolts */
+	int vlim;   /** Voltage limit in millivolts */
 	int ilim;   /** Current limit in microamps */
 };
 
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 3cc3062..26574c7 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -12,6 +12,7 @@
 #include <linux/completion.h>
 #include <linux/cpumask.h>
 #include <linux/page-debug-flags.h>
+#include <linux/uprobes.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
 
@@ -388,6 +389,7 @@
 #ifdef CONFIG_CPUMASK_OFFSTACK
 	struct cpumask cpumask_allocation;
 #endif
+	struct uprobes_state uprobes_state;
 };
 
 static inline void mm_init_cpumask(struct mm_struct *mm)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index dff7115..41aa49b 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -30,7 +30,7 @@
 /*
  * PAGE_ALLOC_COSTLY_ORDER is the order at which allocations are deemed
  * costly to service.  That is between allocation orders which should
- * coelesce naturally under reasonable reclaim pressure and those which
+ * coalesce naturally under reasonable reclaim pressure and those which
  * will not.
  */
 #define PAGE_ALLOC_COSTLY_ORDER 3
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 501da4c..5db9382 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -132,10 +132,12 @@
 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL	0x0200
 
 #define HID_ANY_ID				(~0)
+#define HID_BUS_ANY				0xffff
+#define HID_GROUP_ANY				0x0000
 
 struct hid_device_id {
 	__u16 bus;
-	__u16 pad1;
+	__u16 group;
 	__u32 vendor;
 	__u32 product;
 	kernel_ulong_t driver_data
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index ea36486..1b14d25 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -320,7 +320,8 @@
 		      unsigned num,
 		      s16 level_min,
 		      s16 level_max,
-		      int (*unknown)(char *param, char *val));
+		      int (*unknown)(char *param, char *val,
+			      const char *doing));
 
 /* Called by module remove. */
 #ifdef CONFIG_SYSFS
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index db4836b..c3918a0 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -25,6 +25,9 @@
 #include <linux/types.h>
 #include <mtd/ubi-user.h>
 
+/* All voumes/LEBs */
+#define UBI_ALL -1
+
 /*
  * enum ubi_open_mode - UBI volume open mode constants.
  *
@@ -208,14 +211,15 @@
 int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
 		 int len, int check);
 int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
-		  int offset, int len, int dtype);
+		  int offset, int len);
 int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
-		   int len, int dtype);
+		   int len);
 int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum);
 int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum);
-int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum);
 int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum);
 int ubi_sync(int ubi_num);
+int ubi_flush(int ubi_num, int vol_id, int lnum);
 
 /*
  * This function is the same as the 'ubi_leb_read()' function, but it does not
@@ -226,25 +230,4 @@
 {
 	return ubi_leb_read(desc, lnum, buf, offset, len, 0);
 }
-
-/*
- * This function is the same as the 'ubi_leb_write()' functions, but it does
- * not have the data type argument.
- */
-static inline int ubi_write(struct ubi_volume_desc *desc, int lnum,
-			    const void *buf, int offset, int len)
-{
-	return ubi_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
-}
-
-/*
- * This function is the same as the 'ubi_leb_change()' functions, but it does
- * not have the data type argument.
- */
-static inline int ubi_change(struct ubi_volume_desc *desc, int lnum,
-				    const void *buf, int len)
-{
-	return ubi_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
-}
-
 #endif /* !__LINUX_UBI_H__ */
diff --git a/include/linux/of_serial.h b/include/linux/of_serial.h
new file mode 100644
index 0000000..4a73ed8
--- /dev/null
+++ b/include/linux/of_serial.h
@@ -0,0 +1,17 @@
+#ifndef __LINUX_OF_SERIAL_H
+#define __LINUX_OF_SERIAL_H
+
+/*
+ * FIXME remove this file when tegra finishes conversion to open firmware,
+ * expectation is that all quirks will then be self-contained in
+ * drivers/tty/serial/of_serial.c.
+ */
+#ifdef CONFIG_ARCH_TEGRA
+extern void tegra_serial_handle_break(struct uart_port *port);
+#else
+static inline void tegra_serial_handle_break(struct uart_port *port)
+{
+}
+#endif
+
+#endif /* __LINUX_OF_SERIAL */
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 21638ae..2b9f82c 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -166,60 +166,6 @@
 	(typeof(type) __percpu *)__alloc_percpu(sizeof(type), __alignof__(type))
 
 /*
- * Optional methods for optimized non-lvalue per-cpu variable access.
- *
- * @var can be a percpu variable or a field of it and its size should
- * equal char, int or long.  percpu_read() evaluates to a lvalue and
- * all others to void.
- *
- * These operations are guaranteed to be atomic.
- * The generic versions disable interrupts.  Archs are
- * encouraged to implement single-instruction alternatives which don't
- * require protection.
- */
-#ifndef percpu_read
-# define percpu_read(var)						\
-  ({									\
-	typeof(var) *pr_ptr__ = &(var);					\
-	typeof(var) pr_ret__;						\
-	pr_ret__ = get_cpu_var(*pr_ptr__);				\
-	put_cpu_var(*pr_ptr__);						\
-	pr_ret__;							\
-  })
-#endif
-
-#define __percpu_generic_to_op(var, val, op)				\
-do {									\
-	typeof(var) *pgto_ptr__ = &(var);				\
-	get_cpu_var(*pgto_ptr__) op val;				\
-	put_cpu_var(*pgto_ptr__);					\
-} while (0)
-
-#ifndef percpu_write
-# define percpu_write(var, val)		__percpu_generic_to_op(var, (val), =)
-#endif
-
-#ifndef percpu_add
-# define percpu_add(var, val)		__percpu_generic_to_op(var, (val), +=)
-#endif
-
-#ifndef percpu_sub
-# define percpu_sub(var, val)		__percpu_generic_to_op(var, (val), -=)
-#endif
-
-#ifndef percpu_and
-# define percpu_and(var, val)		__percpu_generic_to_op(var, (val), &=)
-#endif
-
-#ifndef percpu_or
-# define percpu_or(var, val)		__percpu_generic_to_op(var, (val), |=)
-#endif
-
-#ifndef percpu_xor
-# define percpu_xor(var, val)		__percpu_generic_to_op(var, (val), ^=)
-#endif
-
-/*
  * Branching function to split up a function into a set of functions that
  * are called for different scalar sizes of the objects handled.
  */
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index ddbb6a9..f325786 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1132,11 +1132,14 @@
 	struct perf_branch_stack	*br_stack;
 };
 
-static inline void perf_sample_data_init(struct perf_sample_data *data, u64 addr)
+static inline void perf_sample_data_init(struct perf_sample_data *data,
+					 u64 addr, u64 period)
 {
+	/* remaining struct members initialized in perf_prepare_sample() */
 	data->addr = addr;
 	data->raw  = NULL;
 	data->br_stack = NULL;
+	data->period	= period;
 }
 
 extern void perf_output_sample(struct perf_output_handle *handle,
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index b067bd8..00474b0 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -31,7 +31,7 @@
 #ifdef CONFIG_BSD_PROCESS_ACCT
 	struct bsd_acct_struct *bacct;
 #endif
-	gid_t pid_gid;
+	kgid_t pid_gid;
 	int hide_pid;
 	int reboot;	/* group exit code if this pidns was rebooted */
 };
diff --git a/include/linux/pinctrl/pinctrl-state.h b/include/linux/pinctrl/pinctrl-state.h
index 3920e28..634608dc 100644
--- a/include/linux/pinctrl/pinctrl-state.h
+++ b/include/linux/pinctrl/pinctrl-state.h
@@ -2,5 +2,18 @@
  * Standard pin control state definitions
  */
 
+/**
+ * @PINCTRL_STATE_DEFAULT: the state the pinctrl handle shall be put
+ *	into as default, usually this means the pins are up and ready to
+ *	be used by the device driver. This state is commonly used by
+ *	hogs to configure muxing and pins at boot.
+ * @PINCTRL_STATE_IDLE: the state the pinctrl handle shall be put into
+ *	when the pins are idle. Could typically be set from a
+ *	pm_runtime_suspend() operation.
+ * @PINCTRL_STATE_SLEEP: the state the pinctrl handle shall be put into
+ *	when the pins are sleeping. Could typically be set from a
+ *	common suspend() function.
+ */
 #define PINCTRL_STATE_DEFAULT "default"
 #define PINCTRL_STATE_IDLE "idle"
+#define PINCTRL_STATE_SLEEP "sleep"
diff --git a/include/linux/platform_data/at91_adc.h b/include/linux/platform_data/at91_adc.h
new file mode 100644
index 0000000..e15745b
--- /dev/null
+++ b/include/linux/platform_data/at91_adc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#ifndef _AT91_ADC_H_
+#define _AT91_ADC_H_
+
+/**
+ * struct at91_adc_reg_desc - Various informations relative to registers
+ * @channel_base:	Base offset for the channel data registers
+ * @drdy_mask:		Mask of the DRDY field in the relevant registers
+			(Interruptions registers mostly)
+ * @status_register:	Offset of the Interrupt Status Register
+ * @trigger_register:	Offset of the Trigger setup register
+ */
+struct at91_adc_reg_desc {
+	u8	channel_base;
+	u32	drdy_mask;
+	u8	status_register;
+	u8	trigger_register;
+};
+
+/**
+ * struct at91_adc_trigger - description of triggers
+ * @name:		name of the trigger advertised to the user
+ * @value:		value to set in the ADC's trigger setup register
+			to enable the trigger
+ * @is_external:	Does the trigger rely on an external pin?
+ */
+struct at91_adc_trigger {
+	const char	*name;
+	u8		value;
+	bool		is_external;
+};
+
+/**
+ * struct at91_adc_data - platform data for ADC driver
+ * @channels_used:		channels in use on the board as a bitmask
+ * @num_channels:		global number of channels available on the board
+ * @registers:			Registers definition on the board
+ * @startup_time:		startup time of the ADC in microseconds
+ * @trigger_list:		Triggers available in the ADC
+ * @trigger_number:		Number of triggers available in the ADC
+ * @use_external_triggers:	does the board has external triggers availables
+ * @vref:			Reference voltage for the ADC in millivolts
+ */
+struct at91_adc_data {
+	unsigned long			channels_used;
+	u8				num_channels;
+	struct at91_adc_reg_desc	*registers;
+	u8				startup_time;
+	struct at91_adc_trigger		*trigger_list;
+	u8				trigger_number;
+	bool				use_external_triggers;
+	u16				vref;
+};
+
+extern void __init at91_add_device_adc(struct at91_adc_data *data);
+#endif
diff --git a/include/linux/platform_data/ehci-sh.h b/include/linux/platform_data/ehci-sh.h
new file mode 100644
index 0000000..5c15a73
--- /dev/null
+++ b/include/linux/platform_data/ehci-sh.h
@@ -0,0 +1,28 @@
+/*
+ * EHCI SuperH driver platform data
+ *
+ * Copyright (C) 2012  Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ * Copyright (C) 2012  Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __USB_EHCI_SH_H
+#define __USB_EHCI_SH_H
+
+struct ehci_sh_platdata {
+	void (*phy_init)(void); /* Phy init function */
+};
+
+#endif /* __USB_EHCI_SH_H */
diff --git a/include/linux/platform_data/emif_plat.h b/include/linux/platform_data/emif_plat.h
new file mode 100644
index 0000000..03378ca
--- /dev/null
+++ b/include/linux/platform_data/emif_plat.h
@@ -0,0 +1,128 @@
+/*
+ * Definitions for TI EMIF device platform data
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@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.
+ */
+#ifndef __EMIF_PLAT_H
+#define __EMIF_PLAT_H
+
+/* Low power modes - EMIF_PWR_MGMT_CTRL */
+#define EMIF_LP_MODE_DISABLE				0
+#define EMIF_LP_MODE_CLOCK_STOP				1
+#define EMIF_LP_MODE_SELF_REFRESH			2
+#define EMIF_LP_MODE_PWR_DN				4
+
+/* Hardware capabilities */
+#define	EMIF_HW_CAPS_LL_INTERFACE			0x00000001
+
+/*
+ * EMIF IP Revisions
+ *	EMIF4D  - Used in OMAP4
+ *	EMIF4D5 - Used in OMAP5
+ */
+#define	EMIF_4D						1
+#define	EMIF_4D5					2
+
+/*
+ * PHY types
+ *	ATTILAPHY  - Used in OMAP4
+ *	INTELLIPHY - Used in OMAP5
+ */
+#define	EMIF_PHY_TYPE_ATTILAPHY				1
+#define	EMIF_PHY_TYPE_INTELLIPHY			2
+
+/* Custom config requests */
+#define EMIF_CUSTOM_CONFIG_LPMODE			0x00000001
+#define EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL	0x00000002
+
+#ifndef __ASSEMBLY__
+/**
+ * struct ddr_device_info - All information about the DDR device except AC
+ *		timing parameters
+ * @type:	Device type (LPDDR2-S4, LPDDR2-S2 etc)
+ * @density:	Device density
+ * @io_width:	Bus width
+ * @cs1_used:	Whether there is a DDR device attached to the second
+ *		chip-select(CS1) of this EMIF instance
+ * @cal_resistors_per_cs: Whether there is one calibration resistor per
+ *		chip-select or whether it's a single one for both
+ * @manufacturer: Manufacturer name string
+ */
+struct ddr_device_info {
+	u32	type;
+	u32	density;
+	u32	io_width;
+	u32	cs1_used;
+	u32	cal_resistors_per_cs;
+	char	manufacturer[10];
+};
+
+/**
+ * struct emif_custom_configs - Custom configuration parameters/policies
+ *		passed from the platform layer
+ * @mask:	Mask to indicate which configs are requested
+ * @lpmode:	LPMODE to be used in PWR_MGMT_CTRL register
+ * @lpmode_timeout_performance: Timeout before LPMODE entry when higher
+ *		performance is desired at the cost of power (typically
+ *		at higher OPPs)
+ * @lpmode_timeout_power: Timeout before LPMODE entry when better power
+ *		savings is desired and performance is not important
+ *		(typically at lower loads indicated by lower OPPs)
+ * @lpmode_freq_threshold: The DDR frequency threshold to identify between
+ *		the above two cases:
+ *		timeout = (freq >= lpmode_freq_threshold) ?
+ *			lpmode_timeout_performance :
+ *			lpmode_timeout_power;
+ * @temp_alert_poll_interval_ms: LPDDR2 MR4 polling interval at nominal
+ *		temperature(in milliseconds). When temperature is high
+ *		polling is done 4 times as frequently.
+ */
+struct emif_custom_configs {
+	u32 mask;
+	u32 lpmode;
+	u32 lpmode_timeout_performance;
+	u32 lpmode_timeout_power;
+	u32 lpmode_freq_threshold;
+	u32 temp_alert_poll_interval_ms;
+};
+
+/**
+ * struct emif_platform_data - Platform data passed on EMIF platform
+ *				device creation. Used by the driver.
+ * @hw_caps:		Hw capabilities of the EMIF IP in the respective SoC
+ * @device_info:	Device info structure containing information such
+ *			as type, bus width, density etc
+ * @timings:		Timings information from device datasheet passed
+ *			as an array of 'struct lpddr2_timings'. Can be NULL
+ *			if if default timings are ok
+ * @timings_arr_size:	Size of the timings array. Depends on the number
+ *			of different frequencies for which timings data
+ *			is provided
+ * @min_tck:		Minimum value of some timing parameters in terms
+ *			of number of cycles. Can be NULL if default values
+ *			are ok
+ * @custom_configs:	Custom configurations requested by SoC or board
+ *			code and the data for them. Can be NULL if default
+ *			configurations done by the driver are ok. See
+ *			documentation for 'struct emif_custom_configs' for
+ *			more details
+ */
+struct emif_platform_data {
+	u32 hw_caps;
+	struct ddr_device_info *device_info;
+	const struct lpddr2_timings *timings;
+	u32 timings_arr_size;
+	const struct lpddr2_min_tck *min_tck;
+	struct emif_custom_configs *custom_configs;
+	u32 ip_rev;
+	u32 phy_type;
+};
+#endif /* __ASSEMBLY__ */
+
+#endif /* __LINUX_EMIF_H */
diff --git a/include/linux/platform_data/gpio-em.h b/include/linux/platform_data/gpio-em.h
new file mode 100644
index 0000000..573edfb
--- /dev/null
+++ b/include/linux/platform_data/gpio-em.h
@@ -0,0 +1,10 @@
+#ifndef __GPIO_EM_H__
+#define __GPIO_EM_H__
+
+struct gpio_em_config {
+	unsigned int gpio_base;
+	unsigned int irq_base;
+	unsigned int number_of_pins;
+};
+
+#endif /* __GPIO_EM_H__ */
diff --git a/include/linux/platform_data/ina2xx.h b/include/linux/platform_data/ina2xx.h
new file mode 100644
index 0000000..9abc0ca
--- /dev/null
+++ b/include/linux/platform_data/ina2xx.h
@@ -0,0 +1,19 @@
+/*
+ * Driver for Texas Instruments INA219, INA226 power monitor chips
+ *
+ * Copyright (C) 2012 Lothar Felten <l-felten@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.
+ *
+ * For further information, see the Documentation/hwmon/ina2xx file.
+ */
+
+/**
+ * struct ina2xx_platform_data - ina2xx info
+ * @shunt_uohms		shunt resistance in microohms
+ */
+struct ina2xx_platform_data {
+	long shunt_uohms;
+};
diff --git a/include/linux/platform_data/s3c-hsotg.h b/include/linux/platform_data/s3c-hsotg.h
new file mode 100644
index 0000000..97ec12c
--- /dev/null
+++ b/include/linux/platform_data/s3c-hsotg.h
@@ -0,0 +1,35 @@
+/* include/linux/platform_data/s3c-hsotg.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C USB2.0 High-speed / OtG platform information
+ *
+ * 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.
+*/
+
+enum s3c_hsotg_dmamode {
+	S3C_HSOTG_DMA_NONE,	/* do not use DMA at-all */
+	S3C_HSOTG_DMA_ONLY,	/* always use DMA */
+	S3C_HSOTG_DMA_DRV,	/* DMA is chosen by driver */
+};
+
+/**
+ * struct s3c_hsotg_plat - platform data for high-speed otg/udc
+ * @dma: Whether to use DMA or not.
+ * @is_osc: The clock source is an oscillator, not a crystal
+ */
+struct s3c_hsotg_plat {
+	enum s3c_hsotg_dmamode	dma;
+	unsigned int		is_osc:1;
+	int                     phy_type;
+
+	int (*phy_init)(struct platform_device *pdev, int type);
+	int (*phy_exit)(struct platform_device *pdev, int type);
+};
+
+extern void s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd);
diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h
index 6bca5b5..66c673f 100644
--- a/include/linux/platform_data/tegra_usb.h
+++ b/include/linux/platform_data/tegra_usb.h
@@ -26,6 +26,7 @@
 	/* power down the phy on bus suspend */
 	int power_down_on_bus_suspend;
 	void *phy_config;
+	int vbus_gpio;
 };
 
 #endif /* _TEGRA_USB_H_ */
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 715305e..f067e60 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -544,8 +544,6 @@
 	unsigned long		active_jiffies;
 	unsigned long		suspended_jiffies;
 	unsigned long		accounting_timestamp;
-	ktime_t			suspend_time;
-	s64			max_time_suspended_ns;
 	struct dev_pm_qos_request *pq_req;
 #endif
 	struct pm_subsys_data	*subsys_data;  /* Owned by the subsystem. */
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 91f8286..30f794e 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -14,6 +14,7 @@
 #include <linux/pm.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/notifier.h>
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
@@ -70,9 +71,9 @@
 	int (*power_on)(struct generic_pm_domain *domain);
 	s64 power_on_latency_ns;
 	struct gpd_dev_ops dev_ops;
-	s64 break_even_ns;	/* Power break even for the entire domain. */
 	s64 max_off_time_ns;	/* Maximum allowed "suspended" time. */
-	ktime_t power_off_time;
+	bool max_off_time_changed;
+	bool cached_power_down_ok;
 	struct device_node *of_node; /* Node in device tree */
 };
 
@@ -93,13 +94,17 @@
 	s64 start_latency_ns;
 	s64 save_state_latency_ns;
 	s64 restore_state_latency_ns;
-	s64 break_even_ns;
+	s64 effective_constraint_ns;
+	bool constraint_changed;
+	bool cached_stop_ok;
 };
 
 struct generic_pm_domain_data {
 	struct pm_domain_data base;
 	struct gpd_dev_ops ops;
 	struct gpd_timing_data td;
+	struct notifier_block nb;
+	struct mutex lock;
 	bool need_restore;
 	bool always_on;
 };
@@ -141,6 +146,7 @@
 extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 				  struct device *dev);
 extern void pm_genpd_dev_always_on(struct device *dev, bool val);
+extern void pm_genpd_dev_need_restore(struct device *dev, bool val);
 extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 				  struct generic_pm_domain *new_subdomain);
 extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
@@ -184,6 +190,7 @@
 	return -ENOSYS;
 }
 static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {}
+static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {}
 static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 					 struct generic_pm_domain *new_sd)
 {
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 609daae..f271860 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -150,9 +150,6 @@
 static inline unsigned long pm_runtime_autosuspend_expiration(
 				struct device *dev) { return 0; }
 
-static inline void pm_runtime_update_max_time_suspended(struct device *dev,
-							s64 delta_ns) {}
-
 #endif /* !CONFIG_PM_RUNTIME */
 
 static inline int pm_runtime_idle(struct device *dev)
diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
index d9f0511..569781f 100644
--- a/include/linux/pm_wakeup.h
+++ b/include/linux/pm_wakeup.h
@@ -33,12 +33,15 @@
  *
  * @total_time: Total time this wakeup source has been active.
  * @max_time: Maximum time this wakeup source has been continuously active.
- * @last_time: Monotonic clock when the wakeup source's was activated last time.
+ * @last_time: Monotonic clock when the wakeup source's was touched last time.
+ * @prevent_sleep_time: Total time this source has been preventing autosleep.
  * @event_count: Number of signaled wakeup events.
  * @active_count: Number of times the wakeup sorce was activated.
  * @relax_count: Number of times the wakeup sorce was deactivated.
- * @hit_count: Number of times the wakeup sorce might abort system suspend.
+ * @expire_count: Number of times the wakeup source's timeout has expired.
+ * @wakeup_count: Number of times the wakeup source might abort suspend.
  * @active: Status of the wakeup source.
+ * @has_timeout: The wakeup source has been activated with a timeout.
  */
 struct wakeup_source {
 	const char 		*name;
@@ -49,11 +52,15 @@
 	ktime_t total_time;
 	ktime_t max_time;
 	ktime_t last_time;
+	ktime_t start_prevent_time;
+	ktime_t prevent_sleep_time;
 	unsigned long		event_count;
 	unsigned long		active_count;
 	unsigned long		relax_count;
-	unsigned long		hit_count;
-	unsigned int		active:1;
+	unsigned long		expire_count;
+	unsigned long		wakeup_count;
+	bool			active:1;
+	bool			autosleep_enabled:1;
 };
 
 #ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 0525927..1bec2f7 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -95,8 +95,19 @@
 extern void printk_tick(void);
 
 #ifdef CONFIG_PRINTK
+asmlinkage __printf(5, 0)
+int vprintk_emit(int facility, int level,
+		 const char *dict, size_t dictlen,
+		 const char *fmt, va_list args);
+
 asmlinkage __printf(1, 0)
 int vprintk(const char *fmt, va_list args);
+
+asmlinkage __printf(5, 6) __cold
+asmlinkage int printk_emit(int facility, int level,
+			   const char *dict, size_t dictlen,
+			   const char *fmt, ...);
+
 asmlinkage __printf(1, 2) __cold
 int printk(const char *fmt, ...);
 
@@ -289,6 +300,8 @@
 	no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
 #endif
 
+extern const struct file_operations kmsg_fops;
+
 enum {
 	DUMP_PREFIX_NONE,
 	DUMP_PREFIX_ADDRESS,
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 85c5073..3fd2e87 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -52,8 +52,8 @@
 	unsigned int low_ino;
 	umode_t mode;
 	nlink_t nlink;
-	uid_t uid;
-	gid_t gid;
+	kuid_t uid;
+	kgid_t gid;
 	loff_t size;
 	const struct inode_operations *proc_iops;
 	/*
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
new file mode 100644
index 0000000..7ed7fd4
--- /dev/null
+++ b/include/linux/pstore_ram.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ * Copyright (C) 2011 Kees Cook <keescook@chromium.org>
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_PSTORE_RAM_H__
+#define __LINUX_PSTORE_RAM_H__
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+struct persistent_ram_buffer;
+
+struct persistent_ram_descriptor {
+	const char	*name;
+	phys_addr_t	size;
+};
+
+struct persistent_ram {
+	phys_addr_t	start;
+	phys_addr_t	size;
+
+	int					num_descs;
+	struct persistent_ram_descriptor	*descs;
+
+	struct list_head node;
+};
+
+struct persistent_ram_zone {
+	phys_addr_t paddr;
+	size_t size;
+	void *vaddr;
+	struct persistent_ram_buffer *buffer;
+	size_t buffer_size;
+
+	/* ECC correction */
+	bool ecc;
+	char *par_buffer;
+	char *par_header;
+	struct rs_control *rs_decoder;
+	int corrected_bytes;
+	int bad_blocks;
+	int ecc_block_size;
+	int ecc_size;
+	int ecc_symsize;
+	int ecc_poly;
+
+	char *old_log;
+	size_t old_log_size;
+};
+
+int persistent_ram_early_init(struct persistent_ram *ram);
+
+struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
+						       size_t size,
+						       bool ecc);
+void persistent_ram_free(struct persistent_ram_zone *prz);
+struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev,
+		bool ecc);
+
+int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
+	unsigned int count);
+
+size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
+void *persistent_ram_old(struct persistent_ram_zone *prz);
+void persistent_ram_free_old(struct persistent_ram_zone *prz);
+ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+	char *str, size_t len);
+
+/*
+ * Ramoops platform data
+ * @mem_size	memory size for ramoops
+ * @mem_address	physical memory address to contain ramoops
+ */
+
+struct ramoops_platform_data {
+	unsigned long	mem_size;
+	unsigned long	mem_address;
+	unsigned long	record_size;
+	int		dump_oops;
+	bool		ecc;
+};
+
+#endif
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index d93f95e..17b9773 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -22,8 +22,8 @@
 static inline bool is_quota_modification(struct inode *inode, struct iattr *ia)
 {
 	return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) ||
-		(ia->ia_valid & ATTR_UID && ia->ia_uid != inode->i_uid) ||
-		(ia->ia_valid & ATTR_GID && ia->ia_gid != inode->i_gid);
+		(ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) ||
+		(ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid));
 }
 
 #if defined(CONFIG_QUOTA)
diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h
index 8c0a3ad..ee75353 100644
--- a/include/linux/raid/md_p.h
+++ b/include/linux/raid/md_p.h
@@ -233,7 +233,10 @@
 	__le32	delta_disks;	/* change in number of raid_disks		*/
 	__le32	new_layout;	/* new layout					*/
 	__le32	new_chunk;	/* new chunk size (512byte sectors)		*/
-	__u8	pad1[128-124];	/* set to 0 when written */
+	__le32  new_offset;	/* signed number to add to data_offset in new
+				 * layout.  0 == no-change.  This can be
+				 * different on each device in the array.
+				 */
 
 	/* constant this-device information - 64 bytes */
 	__le64	data_offset;	/* sector start of data, often 0 */
@@ -281,10 +284,18 @@
 					    * active device with same 'role'.
 					    * 'recovery_offset' is also set.
 					    */
+#define	MD_FEATURE_RESHAPE_BACKWARDS	32 /* Reshape doesn't change number
+					    * of devices, but is going
+					    * backwards anyway.
+					    */
+#define	MD_FEATURE_NEW_OFFSET		64 /* new_offset must be honoured */
 #define	MD_FEATURE_ALL			(MD_FEATURE_BITMAP_OFFSET	\
 					|MD_FEATURE_RECOVERY_OFFSET	\
 					|MD_FEATURE_RESHAPE_ACTIVE	\
 					|MD_FEATURE_BAD_BLOCKS		\
-					|MD_FEATURE_REPLACEMENT)
+					|MD_FEATURE_REPLACEMENT		\
+					|MD_FEATURE_RESHAPE_BACKWARDS	\
+					|MD_FEATURE_NEW_OFFSET		\
+					)
 
 #endif 
diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h
index 53272e9..640c69c 100644
--- a/include/linux/raid/pq.h
+++ b/include/linux/raid/pq.h
@@ -99,8 +99,20 @@
 extern const struct raid6_calls raid6_altivec4;
 extern const struct raid6_calls raid6_altivec8;
 
+struct raid6_recov_calls {
+	void (*data2)(int, size_t, int, int, void **);
+	void (*datap)(int, size_t, int, void **);
+	int  (*valid)(void);
+	const char *name;
+	int priority;
+};
+
+extern const struct raid6_recov_calls raid6_recov_intx1;
+extern const struct raid6_recov_calls raid6_recov_ssse3;
+
 /* Algorithm list */
 extern const struct raid6_calls * const raid6_algos[];
+extern const struct raid6_recov_calls *const raid6_recov_algos[];
 int raid6_select_algo(void);
 
 /* Return values from chk_syndrome */
@@ -111,14 +123,16 @@
 
 /* Galois field tables */
 extern const u8 raid6_gfmul[256][256] __attribute__((aligned(256)));
+extern const u8 raid6_vgfmul[256][32] __attribute__((aligned(256)));
 extern const u8 raid6_gfexp[256]      __attribute__((aligned(256)));
 extern const u8 raid6_gfinv[256]      __attribute__((aligned(256)));
 extern const u8 raid6_gfexi[256]      __attribute__((aligned(256)));
 
 /* Recovery routines */
-void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
+extern void (*raid6_2data_recov)(int disks, size_t bytes, int faila, int failb,
 		       void **ptrs);
-void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs);
+extern void (*raid6_datap_recov)(int disks, size_t bytes, int faila,
+			void **ptrs);
 void raid6_dual_recov(int disks, size_t bytes, int faila, int failb,
 		      void **ptrs);
 
diff --git a/include/linux/ramoops.h b/include/linux/ramoops.h
deleted file mode 100644
index 484fef8..0000000
--- a/include/linux/ramoops.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __RAMOOPS_H
-#define __RAMOOPS_H
-
-/*
- * Ramoops platform data
- * @mem_size	memory size for ramoops
- * @mem_address	physical memory address to contain ramoops
- */
-
-struct ramoops_platform_data {
-	unsigned long	mem_size;
-	unsigned long	mem_address;
-	unsigned long	record_size;
-	int		dump_oops;
-};
-
-#endif
diff --git a/include/linux/rational.h b/include/linux/rational.h
index 4f532fc..bfa6a2b 100644
--- a/include/linux/rational.h
+++ b/include/linux/rational.h
@@ -1,7 +1,7 @@
 /*
  * rational fractions
  *
- * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <os@emlix.com>
+ * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
  *
  * helper functions when coping with rational numbers,
  * e.g. when calculating optimum numerator/denominator pairs for
diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
index da81af0..fb20189 100644
--- a/include/linux/res_counter.h
+++ b/include/linux/res_counter.h
@@ -116,7 +116,7 @@
  */
 
 int __must_check res_counter_charge_locked(struct res_counter *counter,
-		unsigned long val);
+					   unsigned long val, bool force);
 int __must_check res_counter_charge(struct res_counter *counter,
 		unsigned long val, struct res_counter **limit_fail_at);
 int __must_check res_counter_charge_nofail(struct res_counter *counter,
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 7be2e88..6c8835f 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -96,9 +96,11 @@
 	__ring_buffer_alloc((size), (flags), &__key);	\
 })
 
+#define RING_BUFFER_ALL_CPUS -1
+
 void ring_buffer_free(struct ring_buffer *buffer);
 
-int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size);
+int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size, int cpu);
 
 void ring_buffer_change_overwrite(struct ring_buffer *buffer, int val);
 
@@ -129,7 +131,7 @@
 void ring_buffer_iter_reset(struct ring_buffer_iter *iter);
 int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
 
-unsigned long ring_buffer_size(struct ring_buffer *buffer);
+unsigned long ring_buffer_size(struct ring_buffer *buffer, int cpu);
 
 void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu);
 void ring_buffer_reset(struct ring_buffer *buffer);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f774d88..f45c0b2 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -90,6 +90,7 @@
 #include <linux/latencytop.h>
 #include <linux/cred.h>
 #include <linux/llist.h>
+#include <linux/uidgid.h>
 
 #include <asm/processor.h>
 
@@ -728,8 +729,7 @@
 
 	/* Hash table maintenance information */
 	struct hlist_node uidhash_node;
-	uid_t uid;
-	struct user_namespace *user_ns;
+	kuid_t uid;
 
 #ifdef CONFIG_PERF_EVENTS
 	atomic_long_t locked_vm;
@@ -738,7 +738,7 @@
 
 extern int uids_sysfs_init(void);
 
-extern struct user_struct *find_user(uid_t);
+extern struct user_struct *find_user(kuid_t);
 
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
@@ -855,61 +855,14 @@
 #define SD_WAKE_AFFINE		0x0020	/* Wake task to waking CPU */
 #define SD_PREFER_LOCAL		0x0040  /* Prefer to keep tasks local to this domain */
 #define SD_SHARE_CPUPOWER	0x0080	/* Domain members share cpu power */
-#define SD_POWERSAVINGS_BALANCE	0x0100	/* Balance for power savings */
 #define SD_SHARE_PKG_RESOURCES	0x0200	/* Domain members share cpu pkg resources */
 #define SD_SERIALIZE		0x0400	/* Only a single load balancing instance */
 #define SD_ASYM_PACKING		0x0800  /* Place busy groups earlier in the domain */
 #define SD_PREFER_SIBLING	0x1000	/* Prefer to place tasks in a sibling domain */
 #define SD_OVERLAP		0x2000	/* sched_domains of this level overlap */
 
-enum powersavings_balance_level {
-	POWERSAVINGS_BALANCE_NONE = 0,  /* No power saving load balance */
-	POWERSAVINGS_BALANCE_BASIC,	/* Fill one thread/core/package
-					 * first for long running threads
-					 */
-	POWERSAVINGS_BALANCE_WAKEUP,	/* Also bias task wakeups to semi-idle
-					 * cpu package for power savings
-					 */
-	MAX_POWERSAVINGS_BALANCE_LEVELS
-};
-
-extern int sched_mc_power_savings, sched_smt_power_savings;
-
-static inline int sd_balance_for_mc_power(void)
-{
-	if (sched_smt_power_savings)
-		return SD_POWERSAVINGS_BALANCE;
-
-	if (!sched_mc_power_savings)
-		return SD_PREFER_SIBLING;
-
-	return 0;
-}
-
-static inline int sd_balance_for_package_power(void)
-{
-	if (sched_mc_power_savings | sched_smt_power_savings)
-		return SD_POWERSAVINGS_BALANCE;
-
-	return SD_PREFER_SIBLING;
-}
-
 extern int __weak arch_sd_sibiling_asym_packing(void);
 
-/*
- * Optimise SD flags for power savings:
- * SD_BALANCE_NEWIDLE helps aggressive task consolidation and power savings.
- * Keep default SD flags if sched_{smt,mc}_power_saving=0
- */
-
-static inline int sd_power_saving_flags(void)
-{
-	if (sched_mc_power_savings | sched_smt_power_savings)
-		return SD_BALANCE_NEWIDLE;
-
-	return 0;
-}
-
 struct sched_group_power {
 	atomic_t ref;
 	/*
@@ -1619,6 +1572,10 @@
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 	atomic_t ptrace_bp_refcnt;
 #endif
+#ifdef CONFIG_UPROBES
+	struct uprobe_task *utask;
+	int uprobe_srcu_id;
+#endif
 };
 
 /* Future-safe accessor for struct task_struct's cpus_allowed. */
@@ -1962,7 +1919,7 @@
  */
 extern unsigned long long notrace sched_clock(void);
 /*
- * See the comment in kernel/sched_clock.c
+ * See the comment in kernel/sched/clock.c
  */
 extern u64 cpu_clock(int cpu);
 extern u64 local_clock(void);
@@ -2189,14 +2146,13 @@
 extern void __set_special_pids(struct pid *pid);
 
 /* per-UID process charging. */
-extern struct user_struct * alloc_uid(struct user_namespace *, uid_t);
+extern struct user_struct * alloc_uid(kuid_t);
 static inline struct user_struct *get_uid(struct user_struct *u)
 {
 	atomic_inc(&u->__count);
 	return u;
 }
 extern void free_uid(struct user_struct *);
-extern void release_uids(struct user_namespace *ns);
 
 #include <asm/current.h>
 
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 441980e..90e9f98 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -130,7 +130,6 @@
 #define ASYNCB_CHECK_CD		25 /* i.e., CLOCAL */
 #define ASYNCB_SHARE_IRQ	24 /* for multifunction cards, no longer used */
 #define ASYNCB_CONS_FLOW	23 /* flow control for console  */
-#define ASYNCB_BOOT_ONLYMCA	22 /* Probe only if MCA bus */
 #define ASYNCB_FIRST_KERNEL	22
 
 #define ASYNC_HUP_NOTIFY	(1U << ASYNCB_HUP_NOTIFY)
@@ -166,7 +165,6 @@
 #define ASYNC_CHECK_CD		(1U << ASYNCB_CHECK_CD)
 #define ASYNC_SHARE_IRQ		(1U << ASYNCB_SHARE_IRQ)
 #define ASYNC_CONS_FLOW		(1U << ASYNCB_CONS_FLOW)
-#define ASYNC_BOOT_ONLYMCA	(1U << ASYNCB_BOOT_ONLYMCA)
 #define ASYNC_INTERNAL_FLAGS	(~((1U << ASYNCB_FIRST_KERNEL) - 1))
 
 /*
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 8f012f8..a416e92 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -38,6 +38,7 @@
 	int		(*handle_irq)(struct uart_port *);
 	void		(*pm)(struct uart_port *, unsigned int state,
 			      unsigned old);
+	void		(*handle_break)(struct uart_port *);
 };
 
 /*
@@ -54,7 +55,6 @@
 	PLAT8250_DEV_BOCA,
 	PLAT8250_DEV_EXAR_ST16C554,
 	PLAT8250_DEV_HUB6,
-	PLAT8250_DEV_MCA,
 	PLAT8250_DEV_AU1X00,
 	PLAT8250_DEV_SM501,
 };
@@ -68,6 +68,7 @@
 struct uart_port;
 struct uart_8250_port;
 
+int serial8250_register_8250_port(struct uart_8250_port *);
 int serial8250_register_port(struct uart_port *);
 void serial8250_unregister_port(int line);
 void serial8250_suspend_port(int line);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 2db407a..65db992 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -310,6 +310,7 @@
 	int			(*handle_irq)(struct uart_port *);
 	void			(*pm)(struct uart_port *, unsigned int state,
 				      unsigned int old);
+	void			(*handle_break)(struct uart_port *);
 	unsigned int		irq;			/* irq number */
 	unsigned long		irqflags;		/* irq flags  */
 	unsigned int		uartclk;		/* base uart clock */
@@ -533,6 +534,10 @@
 static inline int uart_handle_break(struct uart_port *port)
 {
 	struct uart_state *state = port->state;
+
+	if (port->handle_break)
+		port->handle_break(port);
+
 #ifdef SUPPORT_SYSRQ
 	if (port->cons && port->cons->index == port->line) {
 		if (!port->sysrq) {
diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h
index 7877907..eb763ad 100644
--- a/include/linux/serial_sci.h
+++ b/include/linux/serial_sci.h
@@ -52,6 +52,8 @@
 /* SCSPTR, optional */
 #define SCSPTR_RTSIO	(1 << 7)
 #define SCSPTR_CTSIO	(1 << 5)
+#define SCSPTR_SPB2IO	(1 << 1)
+#define SCSPTR_SPB2DT	(1 << 0)
 
 /* Offsets into the sci_port->irqs array */
 enum {
diff --git a/include/linux/serio.h b/include/linux/serio.h
index ca82861..6d6cfd3 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -96,6 +96,19 @@
 
 void serio_unregister_driver(struct serio_driver *drv);
 
+/**
+ * module_serio_driver() - Helper macro for registering a serio driver
+ * @__serio_driver: serio_driver struct
+ *
+ * Helper macro for serio drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module
+ * may only use this macro once, and calling it replaces module_init()
+ * and module_exit().
+ */
+#define module_serio_driver(__serio_driver) \
+	module_driver(__serio_driver, serio_register_driver, \
+		       serio_unregister_driver)
+
 static inline int serio_write(struct serio *serio, unsigned char data)
 {
 	if (serio->write)
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index 0a9d8f2..c513b73 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -59,7 +59,15 @@
 	unsigned int		nr_freqs;
 };
 
-#define CLK_ENABLE_ON_INIT	(1 << 0)
+#define CLK_ENABLE_ON_INIT	BIT(0)
+
+#define CLK_ENABLE_REG_32BIT	BIT(1)	/* default access size */
+#define CLK_ENABLE_REG_16BIT	BIT(2)
+#define CLK_ENABLE_REG_8BIT	BIT(3)
+
+#define CLK_ENABLE_REG_MASK	(CLK_ENABLE_REG_32BIT | \
+				 CLK_ENABLE_REG_16BIT | \
+				 CLK_ENABLE_REG_8BIT)
 
 /* drivers/sh/clk.c */
 unsigned long followparent_recalc(struct clk *);
@@ -102,7 +110,7 @@
 		      unsigned long *best_freq, unsigned long *parent_freq,
 		      unsigned int div_min, unsigned int div_max);
 
-#define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags)	\
+#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _flags)		\
 {									\
 	.parent		= _parent,					\
 	.enable_reg	= (void __iomem *)_enable_reg,			\
@@ -110,7 +118,27 @@
 	.flags		= _flags,					\
 }
 
-int sh_clk_mstp32_register(struct clk *clks, int nr);
+#define SH_CLK_MSTP32(_p, _r, _b, _f)					\
+	SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_32BIT)
+
+#define SH_CLK_MSTP16(_p, _r, _b, _f)					\
+	SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_16BIT)
+
+#define SH_CLK_MSTP8(_p, _r, _b, _f)					\
+	SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_8BIT)
+
+int sh_clk_mstp_register(struct clk *clks, int nr);
+
+/*
+ * MSTP registration never really cared about access size, despite the
+ * original enable/disable pairs assuming a 32-bit access. Clocks are
+ * responsible for defining their access sizes either directly or via the
+ * clock definition wrappers.
+ */
+static inline int __deprecated sh_clk_mstp32_register(struct clk *clks, int nr)
+{
+	return sh_clk_mstp_register(clks, nr);
+}
 
 #define SH_CLK_DIV4(_parent, _reg, _shift, _div_bitmap, _flags)	\
 {								\
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index 6aed080..3238328 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -133,7 +133,6 @@
 }
 
 int register_intc_controller(struct intc_desc *desc);
-void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
 int intc_set_priority(unsigned int irq, unsigned int prio);
 int intc_irq_lookup(const char *chipname, intc_enum enum_id);
 void intc_finalize(void);
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 79ab255..bef2cf0 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -28,8 +28,8 @@
 	unsigned long max_inodes;   /* How many inodes are allowed */
 	unsigned long free_inodes;  /* How many are left for allocation */
 	spinlock_t stat_lock;	    /* Serialize shmem_sb_info changes */
-	uid_t uid;		    /* Mount uid for root directory */
-	gid_t gid;		    /* Mount gid for root directory */
+	kuid_t uid;		    /* Mount uid for root directory */
+	kgid_t gid;		    /* Mount gid for root directory */
 	umode_t mode;		    /* Mount mode for root directory */
 	struct mempolicy *mpol;     /* default memory policy for mappings */
 };
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 7987ce74..17046cc 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -252,6 +252,7 @@
 extern int sigprocmask(int, sigset_t *, sigset_t *);
 extern void set_current_blocked(const sigset_t *);
 extern int show_unhandled_signals;
+extern int sigsuspend(sigset_t *);
 
 extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
 extern void block_sigmask(struct k_sigaction *ka, int signr);
diff --git a/include/linux/spi/eeprom.h b/include/linux/spi/eeprom.h
index 306e7b1..403e007 100644
--- a/include/linux/spi/eeprom.h
+++ b/include/linux/spi/eeprom.h
@@ -20,6 +20,16 @@
 #define	EE_ADDR3	0x0004			/* 24 bit addrs */
 #define	EE_READONLY	0x0008			/* disallow writes */
 
+	/*
+	 * Certain EEPROMS have a size that is larger than the number of address
+	 * bytes would allow (e.g. like M95040 from ST that has 512 Byte size
+	 * but uses only one address byte (A0 to A7) for addressing.) For
+	 * the extra address bit (A8, A16 or A24) bit 3 of the instruction byte
+	 * is used. This instruction bit is normally defined as don't care for
+	 * other AT25 like chips.
+	 */
+#define EE_INSTR_BIT3_IS_ADDR	0x0010
+
 	/* for exporting this chip's data to other kernel code */
 	void (*setup)(struct memory_accessor *mem, void *context);
 	void *context;
diff --git a/include/linux/stat.h b/include/linux/stat.h
index 611c398..4613240 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -58,14 +58,15 @@
 
 #include <linux/types.h>
 #include <linux/time.h>
+#include <linux/uidgid.h>
 
 struct kstat {
 	u64		ino;
 	dev_t		dev;
 	umode_t		mode;
 	unsigned int	nlink;
-	uid_t		uid;
-	gid_t		gid;
+	kuid_t		uid;
+	kgid_t		gid;
 	dev_t		rdev;
 	loff_t		size;
 	struct timespec  atime;
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index ac1c114..cd83059 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -356,8 +356,9 @@
 extern bool events_check_enabled;
 
 extern bool pm_wakeup_pending(void);
-extern bool pm_get_wakeup_count(unsigned int *count);
+extern bool pm_get_wakeup_count(unsigned int *count, bool block);
 extern bool pm_save_wakeup_count(unsigned int count);
+extern void pm_wakep_autosleep_enabled(bool set);
 
 static inline void lock_system_sleep(void)
 {
@@ -407,6 +408,17 @@
 
 #endif /* !CONFIG_PM_SLEEP */
 
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+void queue_up_suspend_work(void);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline void queue_up_suspend_work(void) {}
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
 #ifdef CONFIG_ARCH_SAVE_PAGE_KEYS
 /*
  * The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 0010009..381f06d 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -27,6 +27,7 @@
 	const char		*name;
 	umode_t			mode;
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
+	bool			ignore_lockdep:1;
 	struct lock_class_key	*key;
 	struct lock_class_key	skey;
 #endif
@@ -80,6 +81,17 @@
 
 #define __ATTR_NULL { .attr = { .name = NULL } }
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#define __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) {	\
+	.attr = {.name = __stringify(_name), .mode = _mode,	\
+			.ignore_lockdep = true },		\
+	.show		= _show,				\
+	.store		= _store,				\
+}
+#else
+#define __ATTR_IGNORE_LOCKDEP	__ATTR
+#endif
+
 #define attr_name(_attr) (_attr).attr.name
 
 struct file;
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index d9b42c5be..4c5b632 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -426,7 +426,7 @@
 
 	struct sk_buff_head	out_of_order_queue; /* Out of order segments go here */
 
-	/* SACKs data, these 2 need to be together (see tcp_build_and_update_options) */
+	/* SACKs data, these 2 need to be together (see tcp_options_write) */
 	struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
 	struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
 
diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
index 2ef4385..3ca0269 100644
--- a/include/linux/ti_wilink_st.h
+++ b/include/linux/ti_wilink_st.h
@@ -25,6 +25,8 @@
 #ifndef TI_WILINK_ST_H
 #define TI_WILINK_ST_H
 
+#include <linux/skbuff.h>
+
 /**
  * enum proto-type - The protocol on WiLink chips which share a
  *	common physical interface like UART.
diff --git a/include/linux/topology.h b/include/linux/topology.h
index e26db03..e91cd43 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -70,7 +70,6 @@
  * Below are the 3 major initializers used in building sched_domains:
  * SD_SIBLING_INIT, for SMT domains
  * SD_CPU_INIT, for SMP domains
- * SD_NODE_INIT, for NUMA domains
  *
  * Any architecture that cares to do any tuning to these values should do so
  * by defining their own arch-specific initializer in include/asm/topology.h.
@@ -99,7 +98,6 @@
 				| 0*SD_BALANCE_WAKE			\
 				| 1*SD_WAKE_AFFINE			\
 				| 1*SD_SHARE_CPUPOWER			\
-				| 0*SD_POWERSAVINGS_BALANCE		\
 				| 1*SD_SHARE_PKG_RESOURCES		\
 				| 0*SD_SERIALIZE			\
 				| 0*SD_PREFER_SIBLING			\
@@ -135,8 +133,6 @@
 				| 0*SD_SHARE_CPUPOWER			\
 				| 1*SD_SHARE_PKG_RESOURCES		\
 				| 0*SD_SERIALIZE			\
-				| sd_balance_for_mc_power()		\
-				| sd_power_saving_flags()		\
 				,					\
 	.last_balance		= jiffies,				\
 	.balance_interval	= 1,					\
@@ -168,56 +164,18 @@
 				| 0*SD_SHARE_CPUPOWER			\
 				| 0*SD_SHARE_PKG_RESOURCES		\
 				| 0*SD_SERIALIZE			\
-				| sd_balance_for_package_power()	\
-				| sd_power_saving_flags()		\
 				,					\
 	.last_balance		= jiffies,				\
 	.balance_interval	= 1,					\
 }
 #endif
 
-/* sched_domains SD_ALLNODES_INIT for NUMA machines */
-#define SD_ALLNODES_INIT (struct sched_domain) {			\
-	.min_interval		= 64,					\
-	.max_interval		= 64*num_online_cpus(),			\
-	.busy_factor		= 128,					\
-	.imbalance_pct		= 133,					\
-	.cache_nice_tries	= 1,					\
-	.busy_idx		= 3,					\
-	.idle_idx		= 3,					\
-	.flags			= 1*SD_LOAD_BALANCE			\
-				| 1*SD_BALANCE_NEWIDLE			\
-				| 0*SD_BALANCE_EXEC			\
-				| 0*SD_BALANCE_FORK			\
-				| 0*SD_BALANCE_WAKE			\
-				| 0*SD_WAKE_AFFINE			\
-				| 0*SD_SHARE_CPUPOWER			\
-				| 0*SD_POWERSAVINGS_BALANCE		\
-				| 0*SD_SHARE_PKG_RESOURCES		\
-				| 1*SD_SERIALIZE			\
-				| 0*SD_PREFER_SIBLING			\
-				,					\
-	.last_balance		= jiffies,				\
-	.balance_interval	= 64,					\
-}
-
-#ifndef SD_NODES_PER_DOMAIN
-#define SD_NODES_PER_DOMAIN 16
-#endif
-
 #ifdef CONFIG_SCHED_BOOK
 #ifndef SD_BOOK_INIT
 #error Please define an appropriate SD_BOOK_INIT in include/asm/topology.h!!!
 #endif
 #endif /* CONFIG_SCHED_BOOK */
 
-#ifdef CONFIG_NUMA
-#ifndef SD_NODE_INIT
-#error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
-#endif
-
-#endif /* CONFIG_NUMA */
-
 #ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID
 DECLARE_PER_CPU(int, numa_node);
 
@@ -239,7 +197,7 @@
 #ifndef set_numa_node
 static inline void set_numa_node(int node)
 {
-	percpu_write(numa_node, node);
+	this_cpu_write(numa_node, node);
 }
 #endif
 
@@ -274,7 +232,7 @@
 #ifndef set_numa_mem
 static inline void set_numa_mem(int node)
 {
-	percpu_write(_numa_mem_, node);
+	this_cpu_write(_numa_mem_, node);
 }
 #endif
 
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 9f47ab5..4990ef2 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -268,6 +268,7 @@
 	struct mutex ldisc_mutex;
 	struct tty_ldisc *ldisc;
 
+	struct mutex legacy_mutex;
 	struct mutex termios_mutex;
 	spinlock_t ctrl_lock;
 	/* Termios values are protected by the termios mutex */
@@ -605,8 +606,12 @@
 
 /* tty_mutex.c */
 /* functions for preparation of BKL removal */
-extern void __lockfunc tty_lock(void) __acquires(tty_lock);
-extern void __lockfunc tty_unlock(void) __releases(tty_lock);
+extern void __lockfunc tty_lock(struct tty_struct *tty);
+extern void __lockfunc tty_unlock(struct tty_struct *tty);
+extern void __lockfunc tty_lock_pair(struct tty_struct *tty,
+				struct tty_struct *tty2);
+extern void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+				struct tty_struct *tty2);
 
 /*
  * this shall be called only from where BTM is held (like close)
@@ -621,9 +626,9 @@
 static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
 		long timeout)
 {
-	tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */
+	tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
 	tty_wait_until_sent(tty, timeout);
-	tty_lock();
+	tty_lock(tty);
 }
 
 /*
@@ -638,16 +643,16 @@
  *
  * Do not use in new code.
  */
-#define wait_event_interruptible_tty(wq, condition)			\
+#define wait_event_interruptible_tty(tty, wq, condition)		\
 ({									\
 	int __ret = 0;							\
 	if (!(condition)) {						\
-		__wait_event_interruptible_tty(wq, condition, __ret);	\
+		__wait_event_interruptible_tty(tty, wq, condition, __ret);	\
 	}								\
 	__ret;								\
 })
 
-#define __wait_event_interruptible_tty(wq, condition, ret)		\
+#define __wait_event_interruptible_tty(tty, wq, condition, ret)		\
 do {									\
 	DEFINE_WAIT(__wait);						\
 									\
@@ -656,9 +661,9 @@
 		if (condition)						\
 			break;						\
 		if (!signal_pending(current)) {				\
-			tty_unlock();					\
+			tty_unlock(tty);					\
 			schedule();					\
-			tty_lock();					\
+			tty_lock(tty);					\
 			continue;					\
 		}							\
 		ret = -ERESTARTSYS;					\
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index ff7dc08..fb79dd8d 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -110,6 +110,7 @@
 #include <linux/fs.h>
 #include <linux/wait.h>
 #include <linux/pps_kernel.h>
+#include <linux/wait.h>
 
 struct tty_ldisc_ops {
 	int	magic;
@@ -154,6 +155,7 @@
 struct tty_ldisc {
 	struct tty_ldisc_ops *ops;
 	atomic_t users;
+	wait_queue_head_t wq_idle;
 };
 
 #define TTY_LDISC_MAGIC	0x5403
diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h
new file mode 100644
index 0000000..8e522cbc
--- /dev/null
+++ b/include/linux/uidgid.h
@@ -0,0 +1,200 @@
+#ifndef _LINUX_UIDGID_H
+#define _LINUX_UIDGID_H
+
+/*
+ * A set of types for the internal kernel types representing uids and gids.
+ *
+ * The types defined in this header allow distinguishing which uids and gids in
+ * the kernel are values used by userspace and which uid and gid values are
+ * the internal kernel values.  With the addition of user namespaces the values
+ * can be different.  Using the type system makes it possible for the compiler
+ * to detect when we overlook these differences.
+ *
+ */
+#include <linux/types.h>
+#include <linux/highuid.h>
+
+struct user_namespace;
+extern struct user_namespace init_user_ns;
+
+#ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS
+
+typedef struct {
+	uid_t val;
+} kuid_t;
+
+
+typedef struct {
+	gid_t val;
+} kgid_t;
+
+#define KUIDT_INIT(value) (kuid_t){ value }
+#define KGIDT_INIT(value) (kgid_t){ value }
+
+static inline uid_t __kuid_val(kuid_t uid)
+{
+	return uid.val;
+}
+
+static inline gid_t __kgid_val(kgid_t gid)
+{
+	return gid.val;
+}
+
+#else
+
+typedef uid_t kuid_t;
+typedef gid_t kgid_t;
+
+static inline uid_t __kuid_val(kuid_t uid)
+{
+	return uid;
+}
+
+static inline gid_t __kgid_val(kgid_t gid)
+{
+	return gid;
+}
+
+#define KUIDT_INIT(value) ((kuid_t) value )
+#define KGIDT_INIT(value) ((kgid_t) value )
+
+#endif
+
+#define GLOBAL_ROOT_UID KUIDT_INIT(0)
+#define GLOBAL_ROOT_GID KGIDT_INIT(0)
+
+#define INVALID_UID KUIDT_INIT(-1)
+#define INVALID_GID KGIDT_INIT(-1)
+
+static inline bool uid_eq(kuid_t left, kuid_t right)
+{
+	return __kuid_val(left) == __kuid_val(right);
+}
+
+static inline bool gid_eq(kgid_t left, kgid_t right)
+{
+	return __kgid_val(left) == __kgid_val(right);
+}
+
+static inline bool uid_gt(kuid_t left, kuid_t right)
+{
+	return __kuid_val(left) > __kuid_val(right);
+}
+
+static inline bool gid_gt(kgid_t left, kgid_t right)
+{
+	return __kgid_val(left) > __kgid_val(right);
+}
+
+static inline bool uid_gte(kuid_t left, kuid_t right)
+{
+	return __kuid_val(left) >= __kuid_val(right);
+}
+
+static inline bool gid_gte(kgid_t left, kgid_t right)
+{
+	return __kgid_val(left) >= __kgid_val(right);
+}
+
+static inline bool uid_lt(kuid_t left, kuid_t right)
+{
+	return __kuid_val(left) < __kuid_val(right);
+}
+
+static inline bool gid_lt(kgid_t left, kgid_t right)
+{
+	return __kgid_val(left) < __kgid_val(right);
+}
+
+static inline bool uid_lte(kuid_t left, kuid_t right)
+{
+	return __kuid_val(left) <= __kuid_val(right);
+}
+
+static inline bool gid_lte(kgid_t left, kgid_t right)
+{
+	return __kgid_val(left) <= __kgid_val(right);
+}
+
+static inline bool uid_valid(kuid_t uid)
+{
+	return !uid_eq(uid, INVALID_UID);
+}
+
+static inline bool gid_valid(kgid_t gid)
+{
+	return !gid_eq(gid, INVALID_GID);
+}
+
+#ifdef CONFIG_USER_NS
+
+extern kuid_t make_kuid(struct user_namespace *from, uid_t uid);
+extern kgid_t make_kgid(struct user_namespace *from, gid_t gid);
+
+extern uid_t from_kuid(struct user_namespace *to, kuid_t uid);
+extern gid_t from_kgid(struct user_namespace *to, kgid_t gid);
+extern uid_t from_kuid_munged(struct user_namespace *to, kuid_t uid);
+extern gid_t from_kgid_munged(struct user_namespace *to, kgid_t gid);
+
+static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid)
+{
+	return from_kuid(ns, uid) != (uid_t) -1;
+}
+
+static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid)
+{
+	return from_kgid(ns, gid) != (gid_t) -1;
+}
+
+#else
+
+static inline kuid_t make_kuid(struct user_namespace *from, uid_t uid)
+{
+	return KUIDT_INIT(uid);
+}
+
+static inline kgid_t make_kgid(struct user_namespace *from, gid_t gid)
+{
+	return KGIDT_INIT(gid);
+}
+
+static inline uid_t from_kuid(struct user_namespace *to, kuid_t kuid)
+{
+	return __kuid_val(kuid);
+}
+
+static inline gid_t from_kgid(struct user_namespace *to, kgid_t kgid)
+{
+	return __kgid_val(kgid);
+}
+
+static inline uid_t from_kuid_munged(struct user_namespace *to, kuid_t kuid)
+{
+	uid_t uid = from_kuid(to, kuid);
+	if (uid == (uid_t)-1)
+		uid = overflowuid;
+	return uid;
+}
+
+static inline gid_t from_kgid_munged(struct user_namespace *to, kgid_t kgid)
+{
+	gid_t gid = from_kgid(to, kgid);
+	if (gid == (gid_t)-1)
+		gid = overflowgid;
+	return gid;
+}
+
+static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid)
+{
+	return true;
+}
+
+static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid)
+{
+	return true;
+}
+
+#endif /* CONFIG_USER_NS */
+
+#endif /* _LINUX_UIDGID_H */
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
new file mode 100644
index 0000000..efe4b33
--- /dev/null
+++ b/include/linux/uprobes.h
@@ -0,0 +1,165 @@
+#ifndef _LINUX_UPROBES_H
+#define _LINUX_UPROBES_H
+/*
+ * User-space Probes (UProbes)
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2008-2012
+ * Authors:
+ *	Srikar Dronamraju
+ *	Jim Keniston
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/rbtree.h>
+
+struct vm_area_struct;
+struct mm_struct;
+struct inode;
+
+#ifdef CONFIG_ARCH_SUPPORTS_UPROBES
+# include <asm/uprobes.h>
+#endif
+
+/* flags that denote/change uprobes behaviour */
+
+/* Have a copy of original instruction */
+#define UPROBE_COPY_INSN	0x1
+
+/* Dont run handlers when first register/ last unregister in progress*/
+#define UPROBE_RUN_HANDLER	0x2
+/* Can skip singlestep */
+#define UPROBE_SKIP_SSTEP	0x4
+
+struct uprobe_consumer {
+	int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
+	/*
+	 * filter is optional; If a filter exists, handler is run
+	 * if and only if filter returns true.
+	 */
+	bool (*filter)(struct uprobe_consumer *self, struct task_struct *task);
+
+	struct uprobe_consumer *next;
+};
+
+#ifdef CONFIG_UPROBES
+enum uprobe_task_state {
+	UTASK_RUNNING,
+	UTASK_BP_HIT,
+	UTASK_SSTEP,
+	UTASK_SSTEP_ACK,
+	UTASK_SSTEP_TRAPPED,
+};
+
+/*
+ * uprobe_task: Metadata of a task while it singlesteps.
+ */
+struct uprobe_task {
+	enum uprobe_task_state		state;
+	struct arch_uprobe_task		autask;
+
+	struct uprobe			*active_uprobe;
+
+	unsigned long			xol_vaddr;
+	unsigned long			vaddr;
+};
+
+/*
+ * On a breakpoint hit, thread contests for a slot.  It frees the
+ * slot after singlestep. Currently a fixed number of slots are
+ * allocated.
+ */
+struct xol_area {
+	wait_queue_head_t 	wq;		/* if all slots are busy */
+	atomic_t 		slot_count;	/* number of in-use slots */
+	unsigned long 		*bitmap;	/* 0 = free slot */
+	struct page 		*page;
+
+	/*
+	 * We keep the vma's vm_start rather than a pointer to the vma
+	 * itself.  The probed process or a naughty kernel module could make
+	 * the vma go away, and we must handle that reasonably gracefully.
+	 */
+	unsigned long 		vaddr;		/* Page(s) of instruction slots */
+};
+
+struct uprobes_state {
+	struct xol_area		*xol_area;
+	atomic_t		count;
+};
+extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
+extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm,  unsigned long vaddr, bool verify);
+extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
+extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
+extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
+extern int uprobe_mmap(struct vm_area_struct *vma);
+extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void uprobe_free_utask(struct task_struct *t);
+extern void uprobe_copy_process(struct task_struct *t);
+extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
+extern int uprobe_post_sstep_notifier(struct pt_regs *regs);
+extern int uprobe_pre_sstep_notifier(struct pt_regs *regs);
+extern void uprobe_notify_resume(struct pt_regs *regs);
+extern bool uprobe_deny_signal(void);
+extern bool __weak arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs);
+extern void uprobe_clear_state(struct mm_struct *mm);
+extern void uprobe_reset_state(struct mm_struct *mm);
+#else /* !CONFIG_UPROBES */
+struct uprobes_state {
+};
+static inline int
+uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
+{
+	return -ENOSYS;
+}
+static inline void
+uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
+{
+}
+static inline int uprobe_mmap(struct vm_area_struct *vma)
+{
+	return 0;
+}
+static inline void
+uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+}
+static inline void uprobe_notify_resume(struct pt_regs *regs)
+{
+}
+static inline bool uprobe_deny_signal(void)
+{
+	return false;
+}
+static inline unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
+{
+	return 0;
+}
+static inline void uprobe_free_utask(struct task_struct *t)
+{
+}
+static inline void uprobe_copy_process(struct task_struct *t)
+{
+}
+static inline void uprobe_clear_state(struct mm_struct *mm)
+{
+}
+static inline void uprobe_reset_state(struct mm_struct *mm)
+{
+}
+#endif /* !CONFIG_UPROBES */
+#endif	/* _LINUX_UPROBES_H */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 73b68d1..dea39dc 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -351,10 +351,6 @@
 	int bandwidth_int_reqs;		/* number of Interrupt requests */
 	int bandwidth_isoc_reqs;	/* number of Isoc. requests */
 
-#ifdef CONFIG_USB_DEVICEFS
-	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the bus */
-#endif
-
 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
 	struct mon_bus *mon_bus;	/* non-null when associated */
 	int monitored;			/* non-zero when monitored */
@@ -382,6 +378,45 @@
 	USB_DEVICE_FIXED,
 };
 
+/*
+ * USB 3.0 Link Power Management (LPM) parameters.
+ *
+ * PEL and SEL are USB 3.0 Link PM latencies for device-initiated LPM exit.
+ * MEL is the USB 3.0 Link PM latency for host-initiated LPM exit.
+ * All three are stored in nanoseconds.
+ */
+struct usb3_lpm_parameters {
+	/*
+	 * Maximum exit latency (MEL) for the host to send a packet to the
+	 * device (either a Ping for isoc endpoints, or a data packet for
+	 * interrupt endpoints), the hubs to decode the packet, and for all hubs
+	 * in the path to transition the links to U0.
+	 */
+	unsigned int mel;
+	/*
+	 * Maximum exit latency for a device-initiated LPM transition to bring
+	 * all links into U0.  Abbreviated as "PEL" in section 9.4.12 of the USB
+	 * 3.0 spec, with no explanation of what "P" stands for.  "Path"?
+	 */
+	unsigned int pel;
+
+	/*
+	 * The System Exit Latency (SEL) includes PEL, and three other
+	 * latencies.  After a device initiates a U0 transition, it will take
+	 * some time from when the device sends the ERDY to when it will finally
+	 * receive the data packet.  Basically, SEL should be the worse-case
+	 * latency from when a device starts initiating a U0 transition to when
+	 * it will get data.
+	 */
+	unsigned int sel;
+	/*
+	 * The idle timeout value that is currently programmed into the parent
+	 * hub for this device.  When the timer counts to zero, the parent hub
+	 * will initiate an LPM transition to either U1 or U2.
+	 */
+	int timeout;
+};
+
 /**
  * struct usb_device - kernel's representation of a USB device
  * @devnum: device number; address on a USB bus
@@ -439,6 +474,12 @@
  *	specific data for the device.
  * @slot_id: Slot ID assigned by xHCI
  * @removable: Device can be physically removed from this port
+ * @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout.
+ * @u2_params: exit latencies for USB3 U2 LPM state, and hub-initiated timeout.
+ * @lpm_disable_count: Ref count used by usb_disable_lpm() and usb_enable_lpm()
+ *	to keep track of the number of functions that require USB 3.0 Link Power
+ *	Management to be disabled for this usb_device.  This count should only
+ *	be manipulated by those functions, with the bandwidth_mutex is held.
  *
  * Notes:
  * Usbcore drivers should not set usbdev->state directly.  Instead use
@@ -485,6 +526,7 @@
 	unsigned lpm_capable:1;
 	unsigned usb2_hw_lpm_capable:1;
 	unsigned usb2_hw_lpm_enabled:1;
+	unsigned usb3_lpm_enabled:1;
 	int string_langid;
 
 	/* static strings from the device */
@@ -493,12 +535,6 @@
 	char *serial;
 
 	struct list_head filelist;
-#ifdef CONFIG_USB_DEVICE_CLASS
-	struct device *usb_classdev;
-#endif
-#ifdef CONFIG_USB_DEVICEFS
-	struct dentry *usbfs_dentry;
-#endif
 
 	int maxchild;
 	struct usb_device **children;
@@ -517,6 +553,10 @@
 	struct wusb_dev *wusb_dev;
 	int slot_id;
 	enum usb_device_removable removable;
+	struct usb3_lpm_parameters u1_params;
+	struct usb3_lpm_parameters u2_params;
+	unsigned lpm_disable_count;
+	unsigned hub_initiated_lpm_disable_count;
 };
 #define	to_usb_device(d) container_of(d, struct usb_device, dev)
 
@@ -583,6 +623,12 @@
 { }
 #endif
 
+extern int usb_disable_lpm(struct usb_device *udev);
+extern void usb_enable_lpm(struct usb_device *udev);
+/* Same as above, but these functions lock/unlock the bandwidth_mutex. */
+extern int usb_unlocked_disable_lpm(struct usb_device *udev);
+extern void usb_unlocked_enable_lpm(struct usb_device *udev);
+
 /*-------------------------------------------------------------------------*/
 
 /* for drivers using iso endpoints */
@@ -800,6 +846,8 @@
 				struct device_driver *driver,
 				const char *buf, size_t count);
 
+extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf);
+
 /**
  * struct usbdrv_wrap - wrapper for driver-model structure
  * @driver: The driver-model core driver structure.
@@ -850,6 +898,9 @@
  *	for interfaces bound to this driver.
  * @soft_unbind: if set to 1, the USB core will not kill URBs and disable
  *	endpoints before calling the driver's disconnect method.
+ * @disable_hub_initiated_lpm: if set to 0, the USB core will not allow hubs
+ *	to initiate lower power link state transitions when an idle timeout
+ *	occurs.  Device-initiated USB 3.0 link PM will still be allowed.
  *
  * USB interface drivers must provide a name, probe() and disconnect()
  * methods, and an id_table.  Other driver fields are optional.
@@ -890,6 +941,7 @@
 	struct usbdrv_wrap drvwrap;
 	unsigned int no_dynamic_id:1;
 	unsigned int supports_autosuspend:1;
+	unsigned int disable_hub_initiated_lpm:1;
 	unsigned int soft_unbind:1;
 };
 #define	to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)
@@ -1379,6 +1431,7 @@
 extern void usb_kill_urb(struct urb *urb);
 extern void usb_poison_urb(struct urb *urb);
 extern void usb_unpoison_urb(struct urb *urb);
+extern void usb_block_urb(struct urb *urb);
 extern void usb_kill_anchored_urbs(struct usb_anchor *anchor);
 extern void usb_poison_anchored_urbs(struct usb_anchor *anchor);
 extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor);
@@ -1391,6 +1444,8 @@
 extern void usb_scuttle_anchored_urbs(struct usb_anchor *anchor);
 extern int usb_anchor_empty(struct usb_anchor *anchor);
 
+#define usb_unblock_urb	usb_unpoison_urb
+
 /**
  * usb_urb_dir_in - check if an URB describes an IN transfer
  * @urb: URB to be checked
@@ -1627,6 +1682,7 @@
 	case 0:
 	case -ENOMEM:
 	case -ENODEV:
+	case -EOPNOTSUPP:
 		return error_code;
 	default:
 		return -EIO;
@@ -1652,9 +1708,6 @@
 } while (0)
 #endif
 
-#define err(format, arg...)					\
-	printk(KERN_ERR KBUILD_MODNAME ": " format "\n", ##arg)
-
 /* debugfs stuff */
 extern struct dentry *usb_debug_root;
 
diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h
index f1d26b6..b6c2863 100644
--- a/include/linux/usb/ch11.h
+++ b/include/linux/usb/ch11.h
@@ -76,6 +76,8 @@
 #define USB_PORT_FEAT_C_BH_PORT_RESET		29
 #define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT	30
 
+#define USB_PORT_LPM_TIMEOUT(p)			(((p) & 0xff) << 8)
+
 /* USB 3.0 hub remote wake mask bits, see table 10-14 */
 #define USB_PORT_FEAT_REMOTE_WAKE_CONNECT	(1 << 8)
 #define USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT	(1 << 9)
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index af21f31..d1d732c 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -88,6 +88,8 @@
 #define USB_REQ_GET_INTERFACE		0x0A
 #define USB_REQ_SET_INTERFACE		0x0B
 #define USB_REQ_SYNCH_FRAME		0x0C
+#define USB_REQ_SET_SEL			0x30
+#define USB_REQ_SET_ISOCH_DELAY		0x31
 
 #define USB_REQ_SET_ENCRYPTION		0x0D	/* Wireless USB */
 #define USB_REQ_GET_ENCRYPTION		0x0E
@@ -390,6 +392,11 @@
 #define USB_ENDPOINT_XFER_INT		3
 #define USB_ENDPOINT_MAX_ADJUSTABLE	0x80
 
+/* The USB 3.0 spec redefines bits 5:4 of bmAttributes as interrupt ep type. */
+#define USB_ENDPOINT_INTRTYPE		0x30
+#define USB_ENDPOINT_INTR_PERIODIC	(0 << 4)
+#define USB_ENDPOINT_INTR_NOTIFICATION	(1 << 4)
+
 #define USB_ENDPOINT_SYNCTYPE		0x0c
 #define USB_ENDPOINT_SYNC_NONE		(0 << 2)
 #define USB_ENDPOINT_SYNC_ASYNC		(1 << 2)
@@ -592,6 +599,12 @@
 	return __le16_to_cpu(epd->wMaxPacketSize);
 }
 
+static inline int usb_endpoint_interrupt_type(
+		const struct usb_endpoint_descriptor *epd)
+{
+	return epd->bmAttributes & USB_ENDPOINT_INTRTYPE;
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
@@ -933,6 +946,51 @@
 	 */
 };
 
+enum usb3_link_state {
+	USB3_LPM_U0 = 0,
+	USB3_LPM_U1,
+	USB3_LPM_U2,
+	USB3_LPM_U3
+};
+
+/*
+ * A U1 timeout of 0x0 means the parent hub will reject any transitions to U1.
+ * 0xff means the parent hub will accept transitions to U1, but will not
+ * initiate a transition.
+ *
+ * A U1 timeout of 0x1 to 0x7F also causes the hub to initiate a transition to
+ * U1 after that many microseconds.  Timeouts of 0x80 to 0xFE are reserved
+ * values.
+ *
+ * A U2 timeout of 0x0 means the parent hub will reject any transitions to U2.
+ * 0xff means the parent hub will accept transitions to U2, but will not
+ * initiate a transition.
+ *
+ * A U2 timeout of 0x1 to 0xFE also causes the hub to initiate a transition to
+ * U2 after N*256 microseconds.  Therefore a U2 timeout value of 0x1 means a U2
+ * idle timer of 256 microseconds, 0x2 means 512 microseconds, 0xFE means
+ * 65.024ms.
+ */
+#define USB3_LPM_DISABLED		0x0
+#define USB3_LPM_U1_MAX_TIMEOUT		0x7F
+#define USB3_LPM_U2_MAX_TIMEOUT		0xFE
+#define USB3_LPM_DEVICE_INITIATED	0xFF
+
+struct usb_set_sel_req {
+	__u8	u1_sel;
+	__u8	u1_pel;
+	__le16	u2_sel;
+	__le16	u2_pel;
+} __attribute__ ((packed));
+
+/*
+ * The Set System Exit Latency control transfer provides one byte each for
+ * U1 SEL and U1 PEL, so the max exit latency is 0xFF.  U2 SEL and U2 PEL each
+ * are two bytes long.
+ */
+#define USB3_LPM_MAX_U1_SEL_PEL		0xFF
+#define USB3_LPM_MAX_U2_SEL_PEL		0xFFFF
+
 /*-------------------------------------------------------------------------*/
 
 /*
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
new file mode 100644
index 0000000..edb90d6
--- /dev/null
+++ b/include/linux/usb/chipidea.h
@@ -0,0 +1,28 @@
+/*
+ * Platform data for the chipidea USB dual role controller
+ */
+
+#ifndef __LINUX_USB_CHIPIDEA_H
+#define __LINUX_USB_CHIPIDEA_H
+
+struct ci13xxx;
+struct ci13xxx_udc_driver {
+	const char	*name;
+	/* offset of the capability registers */
+	uintptr_t	 capoffset;
+	unsigned	 power_budget;
+	unsigned long	 flags;
+#define CI13XXX_REGS_SHARED		BIT(0)
+#define CI13XXX_REQUIRE_TRANSCEIVER	BIT(1)
+#define CI13XXX_PULLUP_ON_VBUS		BIT(2)
+#define CI13XXX_DISABLE_STREAMING	BIT(3)
+
+#define CI13XXX_CONTROLLER_RESET_EVENT		0
+#define CI13XXX_CONTROLLER_STOPPED_EVENT	1
+	void	(*notify_event) (struct ci13xxx *udc, unsigned event);
+};
+
+/* Default offset of capability registers */
+#define DEF_CAPOFFSET		0x100
+
+#endif
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index a316fba..9d8c3b6 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -242,6 +242,9 @@
 		struct usb_configuration *,
 		int (*)(struct usb_configuration *));
 
+void usb_remove_config(struct usb_composite_dev *,
+		struct usb_configuration *);
+
 /**
  * struct usb_composite_driver - groups configurations into a gadget
  * @name: For diagnostics, identifies the driver.
@@ -250,6 +253,8 @@
  * @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is
  *	not set. If NULL a default "<system> <release> with <udc>" value
  *	will be used.
+ * @iSerialNumber: Used as iSerialNumber override if @dev->iSerialNumber is
+ *	not set.
  * @dev: Template descriptor for the device, including default device
  *	identifiers.
  * @strings: tables of strings, keyed by identifiers assigned during bind()
@@ -280,6 +285,7 @@
 	const char				*name;
 	const char				*iProduct;
 	const char				*iManufacturer;
+	const char				*iSerialNumber;
 	const struct usb_device_descriptor	*dev;
 	struct usb_gadget_strings		**strings;
 	enum usb_device_speed			max_speed;
diff --git a/include/linux/usb/functionfs.h b/include/linux/usb/functionfs.h
index 7587ef9..a843d08 100644
--- a/include/linux/usb/functionfs.h
+++ b/include/linux/usb/functionfs.h
@@ -190,8 +190,10 @@
 	__attribute__((warn_unused_result, nonnull));
 static void functionfs_closed_callback(struct ffs_data *ffs)
 	__attribute__((nonnull));
-static int functionfs_check_dev_callback(const char *dev_name)
+static void *functionfs_acquire_dev_callback(const char *dev_name)
 	__attribute__((warn_unused_result, nonnull));
+static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
+	__attribute__((nonnull));
 
 
 #endif
diff --git a/include/linux/usb/gpio_vbus.h b/include/linux/usb/gpio_vbus.h
index d9f03cc..837bba6 100644
--- a/include/linux/usb/gpio_vbus.h
+++ b/include/linux/usb/gpio_vbus.h
@@ -17,6 +17,7 @@
  * @gpio_pullup: optional D+ or D- pullup GPIO (else negative/invalid)
  * @gpio_vbus_inverted: true if gpio_vbus is active low
  * @gpio_pullup_inverted: true if gpio_pullup is active low
+ * @wakeup: configure gpio_vbus as a wake-up source
  *
  * The VBUS sensing GPIO should have a pulldown, which will normally be
  * part of a resistor ladder turning a 4.0V-5.25V level on VBUS into a
@@ -27,4 +28,5 @@
 	int gpio_pullup;
 	bool gpio_vbus_inverted;
 	bool gpio_pullup_inverted;
+	bool wakeup;
 };
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index d28cc78..7f855d5 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -344,6 +344,15 @@
 		 */
 	int	(*update_device)(struct usb_hcd *, struct usb_device *);
 	int	(*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int);
+	/* USB 3.0 Link Power Management */
+		/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
+	int	(*enable_usb3_lpm_timeout)(struct usb_hcd *,
+			struct usb_device *, enum usb3_link_state state);
+		/* The xHCI host controller can still fail the command to
+		 * disable the LPM timeouts, so this can return an error code.
+		 */
+	int	(*disable_usb3_lpm_timeout)(struct usb_hcd *,
+			struct usb_device *, enum usb3_link_state state);
 };
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -584,29 +593,6 @@
 }
 #endif /* CONFIG_USB_SUSPEND */
 
-
-/*
- * USB device fs stuff
- */
-
-#ifdef CONFIG_USB_DEVICEFS
-
-/*
- * these are expected to be called from the USB core/hub thread
- * with the kernel lock held
- */
-extern void usbfs_update_special(void);
-extern int usbfs_init(void);
-extern void usbfs_cleanup(void);
-
-#else /* CONFIG_USB_DEVICEFS */
-
-static inline void usbfs_update_special(void) {}
-static inline int usbfs_init(void) { return 0; }
-static inline void usbfs_cleanup(void) { }
-
-#endif /* CONFIG_USB_DEVICEFS */
-
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
diff --git a/include/linux/usb/isp1301.h b/include/linux/usb/isp1301.h
new file mode 100644
index 0000000..d3a851c
--- /dev/null
+++ b/include/linux/usb/isp1301.h
@@ -0,0 +1,80 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge <stigge@antcom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_USB_ISP1301_H
+#define __LINUX_USB_ISP1301_H
+
+#include <linux/of.h>
+
+/* I2C Register definitions: */
+
+#define ISP1301_I2C_MODE_CONTROL_1	0x04	/* u8 read, set, +1 clear */
+
+#define MC1_SPEED_REG			(1 << 0)
+#define MC1_SUSPEND_REG			(1 << 1)
+#define MC1_DAT_SE0			(1 << 2)
+#define MC1_TRANSPARENT			(1 << 3)
+#define MC1_BDIS_ACON_EN		(1 << 4)
+#define MC1_OE_INT_EN			(1 << 5)
+#define MC1_UART_EN			(1 << 6)
+#define MC1_MASK			0x7f
+
+#define ISP1301_I2C_MODE_CONTROL_2	0x12	/* u8 read, set, +1 clear */
+
+#define MC2_GLOBAL_PWR_DN		(1 << 0)
+#define MC2_SPD_SUSP_CTRL		(1 << 1)
+#define MC2_BI_DI			(1 << 2)
+#define MC2_TRANSP_BDIR0		(1 << 3)
+#define MC2_TRANSP_BDIR1		(1 << 4)
+#define MC2_AUDIO_EN			(1 << 5)
+#define MC2_PSW_EN			(1 << 6)
+#define MC2_EN2V7			(1 << 7)
+
+#define ISP1301_I2C_OTG_CONTROL_1	0x06	/* u8 read, set, +1 clear */
+
+#define OTG1_DP_PULLUP			(1 << 0)
+#define OTG1_DM_PULLUP			(1 << 1)
+#define OTG1_DP_PULLDOWN		(1 << 2)
+#define OTG1_DM_PULLDOWN		(1 << 3)
+#define OTG1_ID_PULLDOWN		(1 << 4)
+#define OTG1_VBUS_DRV			(1 << 5)
+#define OTG1_VBUS_DISCHRG		(1 << 6)
+#define OTG1_VBUS_CHRG			(1 << 7)
+
+#define ISP1301_I2C_OTG_CONTROL_2	0x10	/* u8 readonly */
+
+#define OTG_B_SESS_END			(1 << 6)
+#define OTG_B_SESS_VLD			(1 << 7)
+
+#define ISP1301_I2C_INTERRUPT_SOURCE	0x8
+#define ISP1301_I2C_INTERRUPT_LATCH	0xA
+#define ISP1301_I2C_INTERRUPT_FALLING	0xC
+#define ISP1301_I2C_INTERRUPT_RISING	0xE
+
+#define INT_VBUS_VLD			(1 << 0)
+#define INT_SESS_VLD			(1 << 1)
+#define INT_DP_HI			(1 << 2)
+#define INT_ID_GND			(1 << 3)
+#define INT_DM_HI			(1 << 4)
+#define INT_ID_FLOAT			(1 << 5)
+#define INT_BDIS_ACON			(1 << 6)
+#define INT_CR_INT			(1 << 7)
+
+#define ISP1301_I2C_REG_CLEAR_ADDR	1	/* Register Address Modifier */
+
+struct i2c_client *isp1301_get_client(struct device_node *node);
+
+#endif /* __LINUX_USB_ISP1301_H */
diff --git a/include/linux/usb/langwell_udc.h b/include/linux/usb/langwell_udc.h
deleted file mode 100644
index 2d2d1bb..0000000
--- a/include/linux/usb/langwell_udc.h
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Intel Langwell USB Device Controller driver
- * Copyright (C) 2008-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.
- *
- */
-
-#ifndef __LANGWELL_UDC_H
-#define __LANGWELL_UDC_H
-
-
-/* MACRO defines */
-#define	CAP_REG_OFFSET		0x0
-#define	OP_REG_OFFSET		0x28
-
-#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
-
-#define	DQH_ALIGNMENT		2048
-#define	DTD_ALIGNMENT		64
-#define	DMA_BOUNDARY		4096
-
-#define	EP0_MAX_PKT_SIZE	64
-#define EP_DIR_IN		1
-#define EP_DIR_OUT		0
-
-#define FLUSH_TIMEOUT		1000
-#define RESET_TIMEOUT		1000
-#define SETUPSTAT_TIMEOUT	100
-#define PRIME_TIMEOUT		100
-
-
-/* device memory space registers */
-
-/* Capability Registers, BAR0 + CAP_REG_OFFSET */
-struct langwell_cap_regs {
-	/* offset: 0x0 */
-	u8	caplength;	/* offset of Operational Register */
-	u8	_reserved3;
-	u16	hciversion;	/* H: BCD encoding of host version */
-	u32	hcsparams;	/* H: host port steering logic capability */
-	u32	hccparams;	/* H: host multiple mode control capability */
-#define	HCC_LEN	BIT(17)		/* Link power management (LPM) capability */
-	u8	_reserved4[0x20-0xc];
-	/* offset: 0x20 */
-	u16	dciversion;	/* BCD encoding of device version */
-	u8	_reserved5[0x24-0x22];
-	u32	dccparams;	/* overall device controller capability */
-#define	HOSTCAP	BIT(8)		/* host capable */
-#define	DEVCAP	BIT(7)		/* device capable */
-#define DEN(d)	\
-	(((d)>>0)&0x1f)		/* bits 4:0, device endpoint number */
-} __attribute__ ((packed));
-
-
-/* Operational Registers, BAR0 + OP_REG_OFFSET */
-struct langwell_op_regs {
-	/* offset: 0x28 */
-	u32	extsts;
-#define	EXTS_TI1	BIT(4)	/* general purpose timer interrupt 1 */
-#define	EXTS_TI1TI0	BIT(3)	/* general purpose timer interrupt 0 */
-#define	EXTS_TI1UPI	BIT(2)	/* USB host periodic interrupt */
-#define	EXTS_TI1UAI	BIT(1)	/* USB host asynchronous interrupt */
-#define	EXTS_TI1NAKI	BIT(0)	/* NAK interrupt */
-	u32	extintr;
-#define	EXTI_TIE1	BIT(4)	/* general purpose timer interrupt enable 1 */
-#define	EXTI_TIE0	BIT(3)	/* general purpose timer interrupt enable 0 */
-#define	EXTI_UPIE	BIT(2)	/* USB host periodic interrupt enable */
-#define	EXTI_UAIE	BIT(1)	/* USB host asynchronous interrupt enable */
-#define	EXTI_NAKE	BIT(0)	/* NAK interrupt enable */
-	/* offset: 0x30 */
-	u32	usbcmd;
-#define	CMD_HIRD(u)	\
-	(((u)>>24)&0xf)		/* bits 27:24, host init resume duration */
-#define	CMD_ITC(u)	\
-	(((u)>>16)&0xff)	/* bits 23:16, interrupt threshold control */
-#define	CMD_PPE		BIT(15)	/* per-port change events enable */
-#define	CMD_ATDTW	BIT(14)	/* add dTD tripwire */
-#define	CMD_SUTW	BIT(13)	/* setup tripwire */
-#define	CMD_ASPE	BIT(11) /* asynchronous schedule park mode enable */
-#define	CMD_FS2		BIT(10)	/* frame list size */
-#define	CMD_ASP1	BIT(9)	/* asynchronous schedule park mode count */
-#define	CMD_ASP0	BIT(8)
-#define	CMD_LR		BIT(7)	/* light host/device controller reset */
-#define	CMD_IAA		BIT(6)	/* interrupt on async advance doorbell */
-#define	CMD_ASE		BIT(5)	/* asynchronous schedule enable */
-#define	CMD_PSE		BIT(4)	/* periodic schedule enable */
-#define	CMD_FS1		BIT(3)
-#define	CMD_FS0		BIT(2)
-#define	CMD_RST		BIT(1)	/* controller reset */
-#define	CMD_RUNSTOP	BIT(0)	/* run/stop */
-	u32	usbsts;
-#define	STS_PPCI(u)	\
-	(((u)>>16)&0xffff)	/* bits 31:16, port-n change detect */
-#define	STS_AS		BIT(15)	/* asynchronous schedule status */
-#define	STS_PS		BIT(14)	/* periodic schedule status */
-#define	STS_RCL		BIT(13)	/* reclamation */
-#define	STS_HCH		BIT(12)	/* HC halted */
-#define	STS_ULPII	BIT(10)	/* ULPI interrupt */
-#define	STS_SLI		BIT(8)	/* DC suspend */
-#define	STS_SRI		BIT(7)	/* SOF received */
-#define	STS_URI		BIT(6)	/* USB reset received */
-#define	STS_AAI		BIT(5)	/* interrupt on async advance */
-#define	STS_SEI		BIT(4)	/* system error */
-#define	STS_FRI		BIT(3)	/* frame list rollover */
-#define	STS_PCI		BIT(2)	/* port change detect */
-#define	STS_UEI		BIT(1)	/* USB error interrupt */
-#define	STS_UI		BIT(0)	/* USB interrupt */
-	u32	usbintr;
-/* bits 31:16, per-port interrupt enable */
-#define	INTR_PPCE(u)	(((u)>>16)&0xffff)
-#define	INTR_ULPIE	BIT(10)	/* ULPI enable */
-#define	INTR_SLE	BIT(8)	/* DC sleep/suspend enable */
-#define	INTR_SRE	BIT(7)	/* SOF received enable */
-#define	INTR_URE	BIT(6)	/* USB reset enable */
-#define	INTR_AAE	BIT(5)	/* interrupt on async advance enable */
-#define	INTR_SEE	BIT(4)	/* system error enable */
-#define	INTR_FRE	BIT(3)	/* frame list rollover enable */
-#define	INTR_PCE	BIT(2)	/* port change detect enable */
-#define	INTR_UEE	BIT(1)	/* USB error interrupt enable */
-#define	INTR_UE		BIT(0)	/* USB interrupt enable */
-	u32	frindex;	/* frame index */
-#define	FRINDEX_MASK	(0x3fff << 0)
-	u32	ctrldssegment;	/* not used */
-	u32	deviceaddr;
-#define USBADR_SHIFT	25
-#define	USBADR(d)	\
-	(((d)>>25)&0x7f)	/* bits 31:25, device address */
-#define USBADR_MASK	(0x7f << 25)
-#define	USBADRA		BIT(24)	/* device address advance */
-	u32	endpointlistaddr;/* endpoint list top memory address */
-/* bits 31:11, endpoint list pointer */
-#define	EPBASE(d)	(((d)>>11)&0x1fffff)
-#define	ENDPOINTLISTADDR_MASK	(0x1fffff << 11)
-	u32	ttctrl;		/* H: TT operatin, not used */
-	/* offset: 0x50 */
-	u32	burstsize;	/* burst size of data movement */
-#define	TXPBURST(b)	\
-	(((b)>>8)&0xff)		/* bits 15:8, TX burst length */
-#define	RXPBURST(b)	\
-	(((b)>>0)&0xff)		/* bits 7:0, RX burst length */
-	u32	txfilltuning;	/* TX tuning */
-	u32	txttfilltuning;	/* H: TX TT tuning */
-	u32	ic_usb;		/* control the IC_USB FS/LS transceiver */
-	/* offset: 0x60 */
-	u32	ulpi_viewport;	/* indirect access to ULPI PHY */
-#define	ULPIWU		BIT(31)	/* ULPI wakeup */
-#define	ULPIRUN		BIT(30)	/* ULPI read/write run */
-#define	ULPIRW		BIT(29)	/* ULPI read/write control */
-#define	ULPISS		BIT(27)	/* ULPI sync state */
-#define	ULPIPORT(u)	\
-	(((u)>>24)&7)		/* bits 26:24, ULPI port number */
-#define	ULPIADDR(u)	\
-	(((u)>>16)&0xff)	/* bits 23:16, ULPI data address */
-#define	ULPIDATRD(u)	\
-	(((u)>>8)&0xff)		/* bits 15:8, ULPI data read */
-#define	ULPIDATWR(u)	\
-	(((u)>>0)&0xff)		/* bits 7:0, ULPI date write */
-	u8	_reserved6[0x70-0x64];
-	/* offset: 0x70 */
-	u32	configflag;	/* H: not used */
-	u32	portsc1;	/* port status */
-#define	DA(p)	\
-	(((p)>>25)&0x7f)	/* bits 31:25, device address */
-#define	PORTS_SSTS	(BIT(24) | BIT(23))	/* suspend status */
-#define	PORTS_WKOC	BIT(22)	/* wake on over-current enable */
-#define	PORTS_WKDS	BIT(21)	/* wake on disconnect enable */
-#define	PORTS_WKCN	BIT(20)	/* wake on connect enable */
-#define	PORTS_PTC(p)	(((p)>>16)&0xf)	/* bits 19:16, port test control */
-#define	PORTS_PIC	(BIT(15) | BIT(14))	/* port indicator control */
-#define	PORTS_PO	BIT(13)	/* port owner */
-#define	PORTS_PP	BIT(12)	/* port power */
-#define	PORTS_LS	(BIT(11) | BIT(10))	/* line status */
-#define	PORTS_SLP	BIT(9)	/* suspend using L1 */
-#define	PORTS_PR	BIT(8)	/* port reset */
-#define	PORTS_SUSP	BIT(7)	/* suspend */
-#define	PORTS_FPR	BIT(6)	/* force port resume */
-#define	PORTS_OCC	BIT(5)	/* over-current change */
-#define	PORTS_OCA	BIT(4)	/* over-current active */
-#define	PORTS_PEC	BIT(3)	/* port enable/disable change */
-#define	PORTS_PE	BIT(2)	/* port enable/disable */
-#define	PORTS_CSC	BIT(1)	/* connect status change */
-#define	PORTS_CCS	BIT(0)	/* current connect status */
-	u8	_reserved7[0xb4-0x78];
-	/* offset: 0xb4 */
-	u32	devlc;		/* control LPM and each USB port behavior */
-/* bits 31:29, parallel transceiver select */
-#define	LPM_PTS(d)	(((d)>>29)&7)
-#define	LPM_STS		BIT(28)	/* serial transceiver select */
-#define	LPM_PTW		BIT(27)	/* parallel transceiver width */
-#define	LPM_PSPD(d)	(((d)>>25)&3)	/* bits 26:25, port speed */
-#define LPM_PSPD_MASK	(BIT(26) | BIT(25))
-#define LPM_SPEED_FULL	0
-#define LPM_SPEED_LOW	1
-#define LPM_SPEED_HIGH	2
-#define	LPM_SRT		BIT(24)	/* shorten reset time */
-#define	LPM_PFSC	BIT(23)	/* port force full speed connect */
-#define	LPM_PHCD	BIT(22) /* PHY low power suspend clock disable */
-#define	LPM_STL		BIT(16)	/* STALL reply to LPM token */
-#define	LPM_BA(d)	\
-	(((d)>>1)&0x7ff)	/* bits 11:1, BmAttributes */
-#define	LPM_NYT_ACK	BIT(0)	/* NYET/ACK reply to LPM token */
-	u8	_reserved8[0xf4-0xb8];
-	/* offset: 0xf4 */
-	u32	otgsc;		/* On-The-Go status and control */
-#define	OTGSC_DPIE	BIT(30)	/* data pulse interrupt enable */
-#define	OTGSC_MSE	BIT(29)	/* 1 ms timer interrupt enable */
-#define	OTGSC_BSEIE	BIT(28)	/* B session end interrupt enable */
-#define	OTGSC_BSVIE	BIT(27)	/* B session valid interrupt enable */
-#define	OTGSC_ASVIE	BIT(26)	/* A session valid interrupt enable */
-#define	OTGSC_AVVIE	BIT(25)	/* A VBUS valid interrupt enable */
-#define	OTGSC_IDIE	BIT(24)	/* USB ID interrupt enable */
-#define	OTGSC_DPIS	BIT(22)	/* data pulse interrupt status */
-#define	OTGSC_MSS	BIT(21)	/* 1 ms timer interrupt status */
-#define	OTGSC_BSEIS	BIT(20)	/* B session end interrupt status */
-#define	OTGSC_BSVIS	BIT(19)	/* B session valid interrupt status */
-#define	OTGSC_ASVIS	BIT(18)	/* A session valid interrupt status */
-#define	OTGSC_AVVIS	BIT(17)	/* A VBUS valid interrupt status */
-#define	OTGSC_IDIS	BIT(16)	/* USB ID interrupt status */
-#define	OTGSC_DPS	BIT(14)	/* data bus pulsing status */
-#define	OTGSC_MST	BIT(13)	/* 1 ms timer toggle */
-#define	OTGSC_BSE	BIT(12)	/* B session end */
-#define	OTGSC_BSV	BIT(11)	/* B session valid */
-#define	OTGSC_ASV	BIT(10)	/* A session valid */
-#define	OTGSC_AVV	BIT(9)	/* A VBUS valid */
-#define	OTGSC_USBID	BIT(8)	/* USB ID */
-#define	OTGSC_HABA	BIT(7)	/* hw assist B-disconnect to A-connect */
-#define	OTGSC_HADP	BIT(6)	/* hw assist data pulse */
-#define	OTGSC_IDPU	BIT(5)	/* ID pullup */
-#define	OTGSC_DP	BIT(4)	/* data pulsing */
-#define	OTGSC_OT	BIT(3)	/* OTG termination */
-#define	OTGSC_HAAR	BIT(2)	/* hw assist auto reset */
-#define	OTGSC_VC	BIT(1)	/* VBUS charge */
-#define	OTGSC_VD	BIT(0)	/* VBUS discharge */
-	u32	usbmode;
-#define	MODE_VBPS	BIT(5)	/* R/W VBUS power select */
-#define	MODE_SDIS	BIT(4)	/* R/W stream disable mode */
-#define	MODE_SLOM	BIT(3)	/* R/W setup lockout mode */
-#define	MODE_ENSE	BIT(2)	/* endian select */
-#define	MODE_CM(u)	(((u)>>0)&3)	/* bits 1:0, controller mode */
-#define	MODE_IDLE	0
-#define	MODE_DEVICE	2
-#define	MODE_HOST	3
-	u8	_reserved9[0x100-0xfc];
-	/* offset: 0x100 */
-	u32	endptnak;
-#define	EPTN(e)		\
-	(((e)>>16)&0xffff)	/* bits 31:16, TX endpoint NAK */
-#define	EPRN(e)		\
-	(((e)>>0)&0xffff)	/* bits 15:0, RX endpoint NAK */
-	u32	endptnaken;
-#define	EPTNE(e)	\
-	(((e)>>16)&0xffff)	/* bits 31:16, TX endpoint NAK enable */
-#define	EPRNE(e)	\
-	(((e)>>0)&0xffff)	/* bits 15:0, RX endpoint NAK enable */
-	u32	endptsetupstat;
-#define	SETUPSTAT_MASK		(0xffff << 0)	/* bits 15:0 */
-#define EP0SETUPSTAT_MASK	1
-	u32	endptprime;
-/* bits 31:16, prime endpoint transmit buffer */
-#define	PETB(e)		(((e)>>16)&0xffff)
-/* bits 15:0, prime endpoint receive buffer */
-#define	PERB(e)		(((e)>>0)&0xffff)
-	/* offset: 0x110 */
-	u32	endptflush;
-/* bits 31:16, flush endpoint transmit buffer */
-#define	FETB(e)		(((e)>>16)&0xffff)
-/* bits 15:0, flush endpoint receive buffer */
-#define	FERB(e)		(((e)>>0)&0xffff)
-	u32	endptstat;
-/* bits 31:16, endpoint transmit buffer ready */
-#define	ETBR(e)		(((e)>>16)&0xffff)
-/* bits 15:0, endpoint receive buffer ready */
-#define	ERBR(e)		(((e)>>0)&0xffff)
-	u32	endptcomplete;
-/* bits 31:16, endpoint transmit complete event */
-#define	ETCE(e)		(((e)>>16)&0xffff)
-/* bits 15:0, endpoint receive complete event */
-#define	ERCE(e)		(((e)>>0)&0xffff)
-	/* offset: 0x11c */
-	u32	endptctrl[16];
-#define	EPCTRL_TXE	BIT(23)	/* TX endpoint enable */
-#define	EPCTRL_TXR	BIT(22)	/* TX data toggle reset */
-#define	EPCTRL_TXI	BIT(21)	/* TX data toggle inhibit */
-#define	EPCTRL_TXT(e)	(((e)>>18)&3)	/* bits 19:18, TX endpoint type */
-#define	EPCTRL_TXT_SHIFT	18
-#define	EPCTRL_TXD	BIT(17)	/* TX endpoint data source */
-#define	EPCTRL_TXS	BIT(16)	/* TX endpoint STALL */
-#define	EPCTRL_RXE	BIT(7)	/* RX endpoint enable */
-#define	EPCTRL_RXR	BIT(6)	/* RX data toggle reset */
-#define	EPCTRL_RXI	BIT(5)	/* RX data toggle inhibit */
-#define	EPCTRL_RXT(e)	(((e)>>2)&3)	/* bits 3:2, RX endpoint type */
-#define	EPCTRL_RXT_SHIFT	2	/* bits 19:18, TX endpoint type */
-#define	EPCTRL_RXD	BIT(1)	/* RX endpoint data sink */
-#define	EPCTRL_RXS	BIT(0)	/* RX endpoint STALL */
-} __attribute__ ((packed));
-
-#endif /* __LANGWELL_UDC_H */
-
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 4742838..86c0b45 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter stuff
  *
- *	Copyright (C) 1999 - 2005
+ *	Copyright (C) 1999 - 2012
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -249,6 +249,7 @@
 
 	int (*suspend)(struct usb_serial *serial, pm_message_t message);
 	int (*resume)(struct usb_serial *serial);
+	int (*reset_resume)(struct usb_serial *serial);
 
 	/* serial function calls */
 	/* Called by console and by the tty layer */
@@ -292,16 +293,11 @@
 #define to_usb_serial_driver(d) \
 	container_of(d, struct usb_serial_driver, driver)
 
-extern int usb_serial_register_drivers(struct usb_driver *udriver,
-		struct usb_serial_driver * const serial_drivers[]);
-extern void usb_serial_deregister_drivers(struct usb_driver *udriver,
-		struct usb_serial_driver * const serial_drivers[]);
+extern int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[],
+		const char *name, const struct usb_device_id *id_table);
+extern void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]);
 extern void usb_serial_port_softint(struct usb_serial_port *port);
 
-extern int usb_serial_probe(struct usb_interface *iface,
-			    const struct usb_device_id *id);
-extern void usb_serial_disconnect(struct usb_interface *iface);
-
 extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
 extern int usb_serial_resume(struct usb_interface *intf);
 
@@ -400,8 +396,8 @@
 
 /*
  * module_usb_serial_driver() - Helper macro for registering a USB Serial driver
- * @__usb_driver: usb_driver struct to register
  * @__serial_drivers: list of usb_serial drivers to register
+ * @__ids: all device ids that @__serial_drivers bind to
  *
  * Helper macro for USB serial drivers which do not do anything special
  * in module init/exit. This eliminates a lot of boilerplate. Each
@@ -409,9 +405,21 @@
  * module_init() and module_exit()
  *
  */
-#define module_usb_serial_driver(__usb_driver, __serial_drivers)	\
-	module_driver(__usb_driver, usb_serial_register_drivers,	\
-		       usb_serial_deregister_drivers, __serial_drivers)
+#define usb_serial_module_driver(__name, __serial_drivers, __ids)	\
+static int __init usb_serial_module_init(void)				\
+{									\
+	return usb_serial_register_drivers(__serial_drivers,		\
+					   __name, __ids);		\
+}									\
+module_init(usb_serial_module_init);					\
+static void __exit usb_serial_module_exit(void)				\
+{									\
+	usb_serial_deregister_drivers(__serial_drivers);		\
+}									\
+module_exit(usb_serial_module_exit);
+
+#define module_usb_serial_driver(__serial_drivers, __ids)		\
+	usb_serial_module_driver(KBUILD_MODNAME, __serial_drivers, __ids)
 
 #endif /* __LINUX_USB_SERIAL_H */
 
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index faf4679..4e72922 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -6,14 +6,24 @@
 #include <linux/sched.h>
 #include <linux/err.h>
 
-#define UIDHASH_BITS	(CONFIG_BASE_SMALL ? 3 : 7)
-#define UIDHASH_SZ	(1 << UIDHASH_BITS)
+#define UID_GID_MAP_MAX_EXTENTS 5
+
+struct uid_gid_map {	/* 64 bytes -- 1 cache line */
+	u32 nr_extents;
+	struct uid_gid_extent {
+		u32 first;
+		u32 lower_first;
+		u32 count;
+	} extent[UID_GID_MAP_MAX_EXTENTS];
+};
 
 struct user_namespace {
+	struct uid_gid_map	uid_map;
+	struct uid_gid_map	gid_map;
 	struct kref		kref;
-	struct hlist_head	uidhash_table[UIDHASH_SZ];
-	struct user_struct	*creator;
-	struct work_struct	destroyer;
+	struct user_namespace	*parent;
+	kuid_t			owner;
+	kgid_t			group;
 };
 
 extern struct user_namespace init_user_ns;
@@ -36,9 +46,11 @@
 		kref_put(&ns->kref, free_user_ns);
 }
 
-uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid);
-gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid);
-
+struct seq_operations;
+extern struct seq_operations proc_uid_seq_operations;
+extern struct seq_operations proc_gid_seq_operations;
+extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *);
+extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *);
 #else
 
 static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
@@ -55,17 +67,6 @@
 {
 }
 
-static inline uid_t user_ns_map_uid(struct user_namespace *to,
-	const struct cred *cred, uid_t uid)
-{
-	return uid;
-}
-static inline gid_t user_ns_map_gid(struct user_namespace *to,
-	const struct cred *cred, gid_t gid)
-{
-	return gid;
-}
-
 #endif
 
 #endif /* _LINUX_USER_H */
diff --git a/include/linux/uuid.h b/include/linux/uuid.h
index 5b7efbf..f86c37b 100644
--- a/include/linux/uuid.h
+++ b/include/linux/uuid.h
@@ -54,6 +54,8 @@
 	UUID_BE(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,	\
 		0x00, 0x00, 0x00, 0x00)
 
+#ifdef __KERNEL__
+
 static inline int uuid_le_cmp(const uuid_le u1, const uuid_le u2)
 {
 	return memcmp(&u1, &u2, sizeof(uuid_le));
@@ -67,4 +69,6 @@
 extern void uuid_le_gen(uuid_le *u);
 extern void uuid_be_gen(uuid_be *u);
 
+#endif /* __KERNEL__ */
+
 #endif
diff --git a/include/linux/v4l2-dv-timings.h b/include/linux/v4l2-dv-timings.h
new file mode 100644
index 0000000..9ef8172
--- /dev/null
+++ b/include/linux/v4l2-dv-timings.h
@@ -0,0 +1,816 @@
+/*
+ * V4L2 DV timings header.
+ *
+ * Copyright (C) 2012  Hans Verkuil <hans.verkuil@cisco.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 _V4L2_DV_TIMINGS_H
+#define _V4L2_DV_TIMINGS_H
+
+#if __GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 6))
+/* Sadly gcc versions older than 4.6 have a bug in how they initialize
+   anonymous unions where they require additional curly brackets.
+   This violates the C1x standard. This workaround adds the curly brackets
+   if needed. */
+#define V4L2_INIT_BT_TIMINGS(_width, args...) \
+	{ .bt = { _width , ## args } }
+#else
+#define V4L2_INIT_BT_TIMINGS(_width, args...) \
+	.bt = { _width , ## args }
+#endif
+
+/* CEA-861-E timings (i.e. standard HDTV timings) */
+
+#define V4L2_DV_BT_CEA_640X480P59_94 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(640, 480, 0, 0, \
+		25175000, 16, 96, 48, 10, 2, 33, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_720X480P59_94 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(720, 480, 0, 0, \
+		27000000, 16, 62, 60, 9, 6, 30, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_720X576P50 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(720, 576, 0, 0, \
+		27000000, 12, 64, 68, 5, 5, 39, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P24 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		59400000, 1760, 40, 220, 5, 5, 20, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, \
+		V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P25 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		74250000, 2420, 40, 220, 5, 5, 20, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P30 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		74250000, 1760, 40, 220, 5, 5, 20, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P50 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		74250000, 440, 40, 220, 5, 5, 20, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		74250000, 110, 40, 220, 5, 5, 20, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P24 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		74250000, 638, 44, 148, 4, 5, 36, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P25 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		74250000, 528, 44, 148, 4, 5, 36, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P30 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		74250000, 88, 44, 148, 4, 5, 36, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080I50 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1080, 1, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		74250000, 528, 44, 148, 2, 5, 15, 2, 5, 16, \
+		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P50 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		148500000, 528, 44, 148, 4, 5, 36, 0, 0, 0, \
+		V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080I60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1080, 1, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		74250000, 88, 44, 148, 2, 5, 15, 2, 5, 16, \
+		V4L2_DV_BT_STD_CEA861, \
+		V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_HALF_LINE) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		148500000, 88, 44, 148, 4, 5, 36, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, \
+		V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+
+/* VESA Discrete Monitor Timings as per version 1.0, revision 12 */
+
+#define V4L2_DV_BT_DMT_640X350P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(640, 350, 0, V4L2_DV_HSYNC_POS_POL, \
+		31500000, 32, 64, 96, 32, 3, 60, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_640X400P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(640, 400, 0, V4L2_DV_VSYNC_POS_POL, \
+		31500000, 32, 64, 96, 1, 3, 41, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_720X400P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(720, 400, 0, V4L2_DV_VSYNC_POS_POL, \
+		35500000, 36, 72, 108, 1, 3, 42, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+/* VGA resolutions */
+#define V4L2_DV_BT_DMT_640X480P60 V4L2_DV_BT_CEA_640X480P59_94
+
+#define V4L2_DV_BT_DMT_640X480P72 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(640, 480, 0, 0, \
+		31500000, 24, 40, 128, 9, 3, 28, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_640X480P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(640, 480, 0, 0, \
+		31500000, 16, 64, 120, 1, 3, 16, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_640X480P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(640, 480, 0, 0, \
+		36000000, 56, 56, 80, 1, 3, 25, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+/* SVGA resolutions */
+#define V4L2_DV_BT_DMT_800X600P56 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		36000000, 24, 72, 128, 1, 2, 22, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		40000000, 40, 128, 88, 1, 4, 23, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P72 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		50000000, 56, 120, 64, 37, 6, 23, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		49500000, 16, 80, 160, 1, 3, 21, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		56250000, 32, 64, 152, 1, 3, 27, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(800, 600, 0, V4L2_DV_HSYNC_POS_POL, \
+		73250000, 48, 32, 80, 3, 4, 29, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_848X480P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(848, 480, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		33750000, 16, 112, 112, 6, 8, 23, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768I43 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1024, 768, 1, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		44900000, 8, 176, 56, 0, 4, 20, 0, 4, 21, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+/* XGA resolutions */
+#define V4L2_DV_BT_DMT_1024X768P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1024, 768, 0, 0, \
+		65000000, 24, 136, 160, 3, 6, 29, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768P70 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1024, 768, 0, 0, \
+		75000000, 24, 136, 144, 3, 6, 29, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1024, 768, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		78750000, 16, 96, 176, 1, 3, 28, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1024, 768, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		94500000, 48, 96, 208, 1, 3, 36, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1024, 768, 0, V4L2_DV_HSYNC_POS_POL, \
+		115500000, 48, 32, 80, 3, 4, 38, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* XGA+ resolution */
+#define V4L2_DV_BT_DMT_1152X864P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1152, 864, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		108000000, 64, 128, 256, 1, 3, 32, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X720P60 V4L2_DV_BT_CEA_1280X720P60
+
+/* WXGA resolutions */
+#define V4L2_DV_BT_DMT_1280X768P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_HSYNC_POS_POL, \
+		68250000, 48, 32, 80, 3, 7, 12, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1280X768P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_VSYNC_POS_POL, \
+		79500000, 64, 128, 192, 3, 7, 20, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X768P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_VSYNC_POS_POL, \
+		102250000, 80, 128, 208, 3, 7, 27, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X768P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_VSYNC_POS_POL, \
+		117500000, 80, 136, 216, 3, 7, 31, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X768P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_HSYNC_POS_POL, \
+		140250000, 48, 32, 80, 3, 7, 35, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_HSYNC_POS_POL, \
+		71000000, 48, 32, 80, 3, 6, 14, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_VSYNC_POS_POL, \
+		83500000, 72, 128, 200, 3, 6, 22, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_VSYNC_POS_POL, \
+		106500000, 80, 128, 208, 3, 6, 29, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_VSYNC_POS_POL, \
+		122500000, 80, 136, 216, 3, 6, 34, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_HSYNC_POS_POL, \
+		146250000, 48, 32, 80, 3, 6, 38, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1280X960P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 960, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		108000000, 96, 112, 312, 1, 3, 36, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X960P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 960, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		148500000, 64, 160, 224, 1, 3, 47, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X960P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 960, 0, V4L2_DV_HSYNC_POS_POL, \
+		175500000, 48, 32, 80, 3, 4, 50, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* SXGA resolutions */
+#define V4L2_DV_BT_DMT_1280X1024P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 1024, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		108000000, 48, 112, 248, 1, 3, 38, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X1024P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 1024, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		135000000, 16, 144, 248, 1, 3, 38, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X1024P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 1024, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		157500000, 64, 160, 224, 1, 3, 44, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X1024P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1280, 1024, 0, V4L2_DV_HSYNC_POS_POL, \
+		187250000, 48, 32, 80, 3, 7, 50, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1360X768P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1360, 768, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		85500000, 64, 112, 256, 3, 6, 18, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1360X768P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1360, 768, 0, V4L2_DV_HSYNC_POS_POL, \
+		148250000, 48, 32, 80, 3, 5, 37, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1366X768P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1366, 768, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		85500000, 70, 143, 213, 3, 3, 24, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1366X768P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1366, 768, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		72000000, 14, 56, 64, 1, 3, 28, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* SXGA+ resolutions */
+#define V4L2_DV_BT_DMT_1400X1050P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_HSYNC_POS_POL, \
+		101000000, 48, 32, 80, 3, 4, 23, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1400X1050P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+		121750000, 88, 144, 232, 3, 4, 32, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1400X1050P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+		156000000, 104, 144, 248, 3, 4, 42, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1400X1050P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+		179500000, 104, 152, 256, 3, 4, 48, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1400X1050P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_HSYNC_POS_POL, \
+		208000000, 48, 32, 80, 3, 4, 55, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* WXGA+ resolutions */
+#define V4L2_DV_BT_DMT_1440X900P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_HSYNC_POS_POL, \
+		88750000, 48, 32, 80, 3, 6, 17, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1440X900P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_VSYNC_POS_POL, \
+		106500000, 80, 152, 232, 3, 6, 25, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1440X900P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_VSYNC_POS_POL, \
+		136750000, 96, 152, 248, 3, 6, 33, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1440X900P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_VSYNC_POS_POL, \
+		157000000, 104, 152, 256, 3, 6, 39, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1440X900P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_HSYNC_POS_POL, \
+		182750000, 48, 32, 80, 3, 6, 44, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1600X900P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1600, 900, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		108000000, 24, 80, 96, 1, 3, 96, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* UXGA resolutions */
+#define V4L2_DV_BT_DMT_1600X1200P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		162000000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P65 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		175500000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P70 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		189000000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		202500000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		229500000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1600, 1200, 0, V4L2_DV_HSYNC_POS_POL, \
+		268250000, 48, 32, 80, 3, 4, 64, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* WSXGA+ resolutions */
+#define V4L2_DV_BT_DMT_1680X1050P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_HSYNC_POS_POL, \
+		119000000, 48, 32, 80, 3, 6, 21, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1680X1050P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+		146250000, 104, 176, 280, 3, 6, 30, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1680X1050P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+		187000000, 120, 176, 296, 3, 6, 40, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1680X1050P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+		214750000, 128, 176, 304, 3, 6, 46, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1680X1050P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_HSYNC_POS_POL, \
+		245500000, 48, 32, 80, 3, 6, 53, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1792X1344P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1792, 1344, 0, V4L2_DV_VSYNC_POS_POL, \
+		204750000, 128, 200, 328, 1, 3, 46, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1792X1344P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1792, 1344, 0, V4L2_DV_VSYNC_POS_POL, \
+		261000000, 96, 216, 352, 1, 3, 69, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1792X1344P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1792, 1344, 0, V4L2_DV_HSYNC_POS_POL, \
+		333250000, 48, 32, 80, 3, 4, 72, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1856X1392P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1856, 1392, 0, V4L2_DV_VSYNC_POS_POL, \
+		218250000, 96, 224, 352, 1, 3, 43, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1856X1392P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1856, 1392, 0, V4L2_DV_VSYNC_POS_POL, \
+		288000000, 128, 224, 352, 1, 3, 104, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1856X1392P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1856, 1392, 0, V4L2_DV_HSYNC_POS_POL, \
+		356500000, 48, 32, 80, 3, 4, 75, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1080P60 V4L2_DV_BT_CEA_1920X1080P60
+
+/* WUXGA resolutions */
+#define V4L2_DV_BT_DMT_1920X1200P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_HSYNC_POS_POL, \
+		154000000, 48, 32, 80, 3, 6, 26, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1200P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_VSYNC_POS_POL, \
+		193250000, 136, 200, 336, 3, 6, 36, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1200P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_VSYNC_POS_POL, \
+		245250000, 136, 208, 344, 3, 6, 46, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1200P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_VSYNC_POS_POL, \
+		281250000, 144, 208, 352, 3, 6, 53, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1200P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_HSYNC_POS_POL, \
+		317000000, 48, 32, 80, 3, 6, 62, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1440P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1440, 0, V4L2_DV_VSYNC_POS_POL, \
+		234000000, 128, 208, 344, 1, 3, 56, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1440P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1440, 0, V4L2_DV_VSYNC_POS_POL, \
+		297000000, 144, 224, 352, 1, 3, 56, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1440P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1920, 1440, 0, V4L2_DV_HSYNC_POS_POL, \
+		380500000, 48, 32, 80, 3, 4, 78, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_2048X1152P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(2048, 1152, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		162000000, 26, 80, 96, 1, 3, 44, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* WQXGA resolutions */
+#define V4L2_DV_BT_DMT_2560X1600P60_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_HSYNC_POS_POL, \
+		268500000, 48, 32, 80, 3, 6, 37, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_2560X1600P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_VSYNC_POS_POL, \
+		348500000, 192, 280, 472, 3, 6, 49, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_2560X1600P75 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_VSYNC_POS_POL, \
+		443250000, 208, 280, 488, 3, 6, 63, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_2560X1600P85 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_VSYNC_POS_POL, \
+		505250000, 208, 280, 488, 3, 6, 73, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_2560X1600P120_RB { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_HSYNC_POS_POL, \
+		552750000, 48, 32, 80, 3, 6, 85, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+		V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1366X768P60 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(1366, 768, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+		85500000, 70, 143, 213, 3, 3, 24, 0, 0, 0, \
+		V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#endif
diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
index ed29cbb..812019e 100644
--- a/include/linux/v4l2-subdev.h
+++ b/include/linux/v4l2-subdev.h
@@ -123,6 +123,43 @@
 	__u32 reserved[9];
 };
 
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE			(1 << 0)
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE			(1 << 1)
+#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG		(1 << 2)
+
+/* active cropping area */
+#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL			0x0000
+/* cropping bounds */
+#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS			0x0002
+/* current composing area */
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL		0x0100
+/* composing bounds */
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS		0x0102
+
+
+/**
+ * struct v4l2_subdev_selection - selection info
+ *
+ * @which: either V4L2_SUBDEV_FORMAT_ACTIVE or V4L2_SUBDEV_FORMAT_TRY
+ * @pad: pad number, as reported by the media API
+ * @target: selection target, used to choose one of possible rectangles
+ * @flags: constraint flags
+ * @r: coordinates of the selection window
+ * @reserved: for future use, set to zero for now
+ *
+ * Hardware may use multiple helper windows to process a video stream.
+ * The structure is used to exchange this selection areas between
+ * an application and a driver.
+ */
+struct v4l2_subdev_selection {
+	__u32 which;
+	__u32 pad;
+	__u32 target;
+	__u32 flags;
+	struct v4l2_rect r;
+	__u32 reserved[8];
+};
+
 #define VIDIOC_SUBDEV_G_FMT	_IOWR('V',  4, struct v4l2_subdev_format)
 #define VIDIOC_SUBDEV_S_FMT	_IOWR('V',  5, struct v4l2_subdev_format)
 #define VIDIOC_SUBDEV_G_FRAME_INTERVAL \
@@ -137,5 +174,9 @@
 			_IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)
 #define VIDIOC_SUBDEV_G_CROP	_IOWR('V', 59, struct v4l2_subdev_crop)
 #define VIDIOC_SUBDEV_S_CROP	_IOWR('V', 60, struct v4l2_subdev_crop)
+#define VIDIOC_SUBDEV_G_SELECTION \
+	_IOWR('V', 61, struct v4l2_subdev_selection)
+#define VIDIOC_SUBDEV_S_SELECTION \
+	_IOWR('V', 62, struct v4l2_subdev_selection)
 
 #endif
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index c9c9a46..370d111 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -292,10 +292,10 @@
 	__u32         		width;
 	__u32			height;
 	__u32			pixelformat;
-	enum v4l2_field  	field;
+	__u32			field;		/* enum v4l2_field */
 	__u32            	bytesperline;	/* for padding, zero if unused */
 	__u32          		sizeimage;
-	enum v4l2_colorspace	colorspace;
+	__u32			colorspace;	/* enum v4l2_colorspace */
 	__u32			priv;		/* private data, depends on pixelformat */
 };
 
@@ -378,7 +378,10 @@
 #define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12  GRGR.. BGBG.. */
 #define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12  RGRG.. GBGB.. */
 	/* 10bit raw bayer DPCM compressed to 8 bits */
+#define V4L2_PIX_FMT_SBGGR10DPCM8 v4l2_fourcc('b', 'B', 'A', '8')
+#define V4L2_PIX_FMT_SGBRG10DPCM8 v4l2_fourcc('b', 'G', 'A', '8')
 #define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
+#define V4L2_PIX_FMT_SRGGB10DPCM8 v4l2_fourcc('b', 'R', 'A', '8')
 	/*
 	 * 10bit raw bayer, expanded to 16 bits
 	 * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
@@ -432,7 +435,7 @@
  */
 struct v4l2_fmtdesc {
 	__u32		    index;             /* Format number      */
-	enum v4l2_buf_type  type;              /* buffer type        */
+	__u32		    type;              /* enum v4l2_buf_type */
 	__u32               flags;
 	__u8		    description[32];   /* Description string */
 	__u32		    pixelformat;       /* Format fourcc      */
@@ -573,8 +576,8 @@
  */
 struct v4l2_requestbuffers {
 	__u32			count;
-	enum v4l2_buf_type      type;
-	enum v4l2_memory        memory;
+	__u32			type;		/* enum v4l2_buf_type */
+	__u32			memory;		/* enum v4l2_memory */
 	__u32			reserved[2];
 };
 
@@ -610,15 +613,17 @@
 /**
  * struct v4l2_buffer - video buffer info
  * @index:	id number of the buffer
- * @type:	buffer type (type == *_MPLANE for multiplanar buffers)
+ * @type:	enum v4l2_buf_type; buffer type (type == *_MPLANE for
+ *		multiplanar buffers);
  * @bytesused:	number of bytes occupied by data in the buffer (payload);
  *		unused (set to 0) for multiplanar buffers
  * @flags:	buffer informational flags
- * @field:	field order of the image in the buffer
+ * @field:	enum v4l2_field; field order of the image in the buffer
  * @timestamp:	frame timestamp
  * @timecode:	frame timecode
  * @sequence:	sequence count of this frame
- * @memory:	the method, in which the actual video data is passed
+ * @memory:	enum v4l2_memory; the method, in which the actual video data is
+ *		passed
  * @offset:	for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
  *		offset from the start of the device memory for this plane,
  *		(or a "cookie" that should be passed to mmap() as offset)
@@ -636,16 +641,16 @@
  */
 struct v4l2_buffer {
 	__u32			index;
-	enum v4l2_buf_type      type;
+	__u32			type;
 	__u32			bytesused;
 	__u32			flags;
-	enum v4l2_field		field;
+	__u32			field;
 	struct timeval		timestamp;
 	struct v4l2_timecode	timecode;
 	__u32			sequence;
 
 	/* memory location */
-	enum v4l2_memory        memory;
+	__u32			memory;
 	union {
 		__u32           offset;
 		unsigned long   userptr;
@@ -708,7 +713,7 @@
 
 struct v4l2_window {
 	struct v4l2_rect        w;
-	enum v4l2_field  	field;
+	__u32			field;	 /* enum v4l2_field */
 	__u32			chromakey;
 	struct v4l2_clip	__user *clips;
 	__u32			clipcount;
@@ -745,14 +750,14 @@
  *	I N P U T   I M A G E   C R O P P I N G
  */
 struct v4l2_cropcap {
-	enum v4l2_buf_type      type;
+	__u32			type;	/* enum v4l2_buf_type */
 	struct v4l2_rect        bounds;
 	struct v4l2_rect        defrect;
 	struct v4l2_fract       pixelaspect;
 };
 
 struct v4l2_crop {
-	enum v4l2_buf_type      type;
+	__u32			type;	/* enum v4l2_buf_type */
 	struct v4l2_rect        c;
 };
 
@@ -939,6 +944,9 @@
 	__u32		     reserved[4];
 };
 
+/* The DV Preset API is deprecated in favor of the DV Timings API.
+   New drivers shouldn't use this anymore! */
+
 /*
  *	V I D E O	T I M I N G S	D V	P R E S E T
  */
@@ -986,29 +994,56 @@
  *	D V 	B T	T I M I N G S
  */
 
-/* BT.656/BT.1120 timing data */
+/** struct v4l2_bt_timings - BT.656/BT.1120 timing data
+ * @width:	total width of the active video in pixels
+ * @height:	total height of the active video in lines
+ * @interlaced:	Interlaced or progressive
+ * @polarities:	Positive or negative polarities
+ * @pixelclock:	Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @hfrontporch:Horizontal front porch in pixels
+ * @hsync:	Horizontal Sync length in pixels
+ * @hbackporch:	Horizontal back porch in pixels
+ * @vfrontporch:Vertical front porch in lines
+ * @vsync:	Vertical Sync length in lines
+ * @vbackporch:	Vertical back porch in lines
+ * @il_vfrontporch:Vertical front porch for the even field
+ *		(aka field 2) of interlaced field formats
+ * @il_vsync:	Vertical Sync length for the even field
+ *		(aka field 2) of interlaced field formats
+ * @il_vbackporch:Vertical back porch for the even field
+ *		(aka field 2) of interlaced field formats
+ * @standards:	Standards the timing belongs to
+ * @flags:	Flags
+ * @reserved:	Reserved fields, must be zeroed.
+ *
+ * A note regarding vertical interlaced timings: height refers to the total
+ * height of the active video frame (= two fields). The blanking timings refer
+ * to the blanking of each field. So the height of the total frame is
+ * calculated as follows:
+ *
+ * tot_height = height + vfrontporch + vsync + vbackporch +
+ *                       il_vfrontporch + il_vsync + il_vbackporch
+ *
+ * The active height of each field is height / 2.
+ */
 struct v4l2_bt_timings {
-	__u32	width;		/* width in pixels */
-	__u32	height;		/* height in lines */
-	__u32	interlaced;	/* Interlaced or progressive */
-	__u32	polarities;	/* Positive or negative polarity */
-	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
-	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
-	__u32	hsync;		/* Horizontal Sync length in pixels */
-	__u32	hbackporch;	/* Horizontal back porch in pixels */
-	__u32	vfrontporch;	/* Vertical front porch in pixels */
-	__u32	vsync;		/* Vertical Sync length in lines */
-	__u32	vbackporch;	/* Vertical back porch in lines */
-	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
-				 * interlaced field formats
-				 */
-	__u32	il_vsync;	/* Vertical sync length for bottom field of
-				 * interlaced field formats
-				 */
-	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
-				 * interlaced field formats
-				 */
-	__u32	reserved[16];
+	__u32	width;
+	__u32	height;
+	__u32	interlaced;
+	__u32	polarities;
+	__u64	pixelclock;
+	__u32	hfrontporch;
+	__u32	hsync;
+	__u32	hbackporch;
+	__u32	vfrontporch;
+	__u32	vsync;
+	__u32	vbackporch;
+	__u32	il_vfrontporch;
+	__u32	il_vsync;
+	__u32	il_vbackporch;
+	__u32	standards;
+	__u32	flags;
+	__u32	reserved[14];
 } __attribute__ ((packed));
 
 /* Interlaced or progressive format */
@@ -1019,8 +1054,42 @@
 #define V4L2_DV_VSYNC_POS_POL	0x00000001
 #define V4L2_DV_HSYNC_POS_POL	0x00000002
 
+/* Timings standards */
+#define V4L2_DV_BT_STD_CEA861	(1 << 0)  /* CEA-861 Digital TV Profile */
+#define V4L2_DV_BT_STD_DMT	(1 << 1)  /* VESA Discrete Monitor Timings */
+#define V4L2_DV_BT_STD_CVT	(1 << 2)  /* VESA Coordinated Video Timings */
+#define V4L2_DV_BT_STD_GTF	(1 << 3)  /* VESA Generalized Timings Formula */
 
-/* DV timings */
+/* Flags */
+
+/* CVT/GTF specific: timing uses reduced blanking (CVT) or the 'Secondary
+   GTF' curve (GTF). In both cases the horizontal and/or vertical blanking
+   intervals are reduced, allowing a higher resolution over the same
+   bandwidth. This is a read-only flag. */
+#define V4L2_DV_FL_REDUCED_BLANKING		(1 << 0)
+/* CEA-861 specific: set for CEA-861 formats with a framerate of a multiple
+   of six. These formats can be optionally played at 1 / 1.001 speed.
+   This is a read-only flag. */
+#define V4L2_DV_FL_CAN_REDUCE_FPS		(1 << 1)
+/* CEA-861 specific: only valid for video transmitters, the flag is cleared
+   by receivers.
+   If the framerate of the format is a multiple of six, then the pixelclock
+   used to set up the transmitter is divided by 1.001 to make it compatible
+   with 60 Hz based standards such as NTSC and PAL-M that use a framerate of
+   29.97 Hz. Otherwise this flag is cleared. If the transmitter can't generate
+   such frequencies, then the flag will also be cleared. */
+#define V4L2_DV_FL_REDUCED_FPS			(1 << 2)
+/* Specific to interlaced formats: if set, then field 1 is really one half-line
+   longer and field 2 is really one half-line shorter, so each field has
+   exactly the same number of half-lines. Whether half-lines can be detected
+   or used depends on the hardware. */
+#define V4L2_DV_FL_HALF_LINE			(1 << 0)
+
+
+/** struct v4l2_dv_timings - DV timings
+ * @type:	the type of the timings
+ * @bt:	BT656/1120 timings
+ */
 struct v4l2_dv_timings {
 	__u32 type;
 	union {
@@ -1032,6 +1101,64 @@
 /* Values for the type field */
 #define V4L2_DV_BT_656_1120	0	/* BT.656/1120 timing type */
 
+
+/** struct v4l2_enum_dv_timings - DV timings enumeration
+ * @index:	enumeration index
+ * @reserved:	must be zeroed
+ * @timings:	the timings for the given index
+ */
+struct v4l2_enum_dv_timings {
+	__u32 index;
+	__u32 reserved[3];
+	struct v4l2_dv_timings timings;
+};
+
+/** struct v4l2_bt_timings_cap - BT.656/BT.1120 timing capabilities
+ * @min_width:		width in pixels
+ * @max_width:		width in pixels
+ * @min_height:		height in lines
+ * @max_height:		height in lines
+ * @min_pixelclock:	Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @max_pixelclock:	Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @standards:		Supported standards
+ * @capabilities:	Supported capabilities
+ * @reserved:		Must be zeroed
+ */
+struct v4l2_bt_timings_cap {
+	__u32	min_width;
+	__u32	max_width;
+	__u32	min_height;
+	__u32	max_height;
+	__u64	min_pixelclock;
+	__u64	max_pixelclock;
+	__u32	standards;
+	__u32	capabilities;
+	__u32	reserved[16];
+} __attribute__ ((packed));
+
+/* Supports interlaced formats */
+#define V4L2_DV_BT_CAP_INTERLACED	(1 << 0)
+/* Supports progressive formats */
+#define V4L2_DV_BT_CAP_PROGRESSIVE	(1 << 1)
+/* Supports CVT/GTF reduced blanking */
+#define V4L2_DV_BT_CAP_REDUCED_BLANKING	(1 << 2)
+/* Supports custom formats */
+#define V4L2_DV_BT_CAP_CUSTOM		(1 << 3)
+
+/** struct v4l2_dv_timings_cap - DV timings capabilities
+ * @type:	the type of the timings (same as in struct v4l2_dv_timings)
+ * @bt:		the BT656/1120 timings capabilities
+ */
+struct v4l2_dv_timings_cap {
+	__u32 type;
+	__u32 reserved[3];
+	union {
+		struct v4l2_bt_timings_cap bt;
+		__u32 raw_data[32];
+	};
+};
+
+
 /*
  *	V I D E O   I N P U T S
  */
@@ -1040,7 +1167,7 @@
 	__u8	     name[32];		/*  Label */
 	__u32	     type;		/*  Type of input */
 	__u32	     audioset;		/*  Associated audios (bitfield) */
-	__u32        tuner;             /*  Associated tuner */
+	__u32        tuner;             /*  enum v4l2_tuner_type */
 	v4l2_std_id  std;
 	__u32	     status;
 	__u32	     capabilities;
@@ -1137,6 +1264,8 @@
 #define V4L2_CTRL_CLASS_FM_TX 0x009b0000	/* FM Modulator control class */
 #define V4L2_CTRL_CLASS_FLASH 0x009c0000	/* Camera flash controls */
 #define V4L2_CTRL_CLASS_JPEG 0x009d0000		/* JPEG-compression controls */
+#define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009e0000	/* Image source controls */
+#define V4L2_CTRL_CLASS_IMAGE_PROC 0x009f0000	/* Image processing controls */
 
 #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
@@ -1151,12 +1280,13 @@
 	V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
 	V4L2_CTRL_TYPE_STRING        = 7,
 	V4L2_CTRL_TYPE_BITMASK       = 8,
+	V4L2_CTRL_TYPE_INTEGER_MENU = 9,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
 struct v4l2_queryctrl {
 	__u32		     id;
-	enum v4l2_ctrl_type  type;
+	__u32		     type;	/* enum v4l2_ctrl_type */
 	__u8		     name[32];	/* Whatever */
 	__s32		     minimum;	/* Note signedness */
 	__s32		     maximum;
@@ -1170,9 +1300,12 @@
 struct v4l2_querymenu {
 	__u32		id;
 	__u32		index;
-	__u8		name[32];	/* Whatever */
+	union {
+		__u8	name[32];	/* Whatever */
+		__s64	value;
+	};
 	__u32		reserved;
-};
+} __attribute__ ((packed));
 
 /*  Control flags  */
 #define V4L2_CTRL_FLAG_DISABLED		0x0001
@@ -1237,16 +1370,22 @@
 #define V4L2_CID_COLOR_KILLER                   (V4L2_CID_BASE+30)
 #define V4L2_CID_COLORFX			(V4L2_CID_BASE+31)
 enum v4l2_colorfx {
-	V4L2_COLORFX_NONE	= 0,
-	V4L2_COLORFX_BW		= 1,
-	V4L2_COLORFX_SEPIA	= 2,
-	V4L2_COLORFX_NEGATIVE = 3,
-	V4L2_COLORFX_EMBOSS = 4,
-	V4L2_COLORFX_SKETCH = 5,
-	V4L2_COLORFX_SKY_BLUE = 6,
-	V4L2_COLORFX_GRASS_GREEN = 7,
-	V4L2_COLORFX_SKIN_WHITEN = 8,
-	V4L2_COLORFX_VIVID = 9,
+	V4L2_COLORFX_NONE			= 0,
+	V4L2_COLORFX_BW				= 1,
+	V4L2_COLORFX_SEPIA			= 2,
+	V4L2_COLORFX_NEGATIVE			= 3,
+	V4L2_COLORFX_EMBOSS			= 4,
+	V4L2_COLORFX_SKETCH			= 5,
+	V4L2_COLORFX_SKY_BLUE			= 6,
+	V4L2_COLORFX_GRASS_GREEN		= 7,
+	V4L2_COLORFX_SKIN_WHITEN		= 8,
+	V4L2_COLORFX_VIVID			= 9,
+	V4L2_COLORFX_AQUA			= 10,
+	V4L2_COLORFX_ART_FREEZE			= 11,
+	V4L2_COLORFX_SILHOUETTE			= 12,
+	V4L2_COLORFX_SOLARIZATION		= 13,
+	V4L2_COLORFX_ANTIQUE			= 14,
+	V4L2_COLORFX_SET_CBCR			= 15,
 };
 #define V4L2_CID_AUTOBRIGHTNESS			(V4L2_CID_BASE+32)
 #define V4L2_CID_BAND_STOP_FILTER		(V4L2_CID_BASE+33)
@@ -1263,9 +1402,10 @@
 #define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT		(V4L2_CID_BASE+40)
 
 #define V4L2_CID_ALPHA_COMPONENT		(V4L2_CID_BASE+41)
+#define V4L2_CID_COLORFX_CBCR			(V4L2_CID_BASE+42)
 
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+42)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+43)
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE 			(V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1689,6 +1829,78 @@
 #define V4L2_CID_IRIS_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+17)
 #define V4L2_CID_IRIS_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+18)
 
+#define V4L2_CID_AUTO_EXPOSURE_BIAS		(V4L2_CID_CAMERA_CLASS_BASE+19)
+
+#define V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE	(V4L2_CID_CAMERA_CLASS_BASE+20)
+enum v4l2_auto_n_preset_white_balance {
+	V4L2_WHITE_BALANCE_MANUAL		= 0,
+	V4L2_WHITE_BALANCE_AUTO			= 1,
+	V4L2_WHITE_BALANCE_INCANDESCENT		= 2,
+	V4L2_WHITE_BALANCE_FLUORESCENT		= 3,
+	V4L2_WHITE_BALANCE_FLUORESCENT_H	= 4,
+	V4L2_WHITE_BALANCE_HORIZON		= 5,
+	V4L2_WHITE_BALANCE_DAYLIGHT		= 6,
+	V4L2_WHITE_BALANCE_FLASH		= 7,
+	V4L2_WHITE_BALANCE_CLOUDY		= 8,
+	V4L2_WHITE_BALANCE_SHADE		= 9,
+};
+
+#define V4L2_CID_WIDE_DYNAMIC_RANGE		(V4L2_CID_CAMERA_CLASS_BASE+21)
+#define V4L2_CID_IMAGE_STABILIZATION		(V4L2_CID_CAMERA_CLASS_BASE+22)
+
+#define V4L2_CID_ISO_SENSITIVITY		(V4L2_CID_CAMERA_CLASS_BASE+23)
+#define V4L2_CID_ISO_SENSITIVITY_AUTO		(V4L2_CID_CAMERA_CLASS_BASE+24)
+enum v4l2_iso_sensitivity_auto_type {
+	V4L2_ISO_SENSITIVITY_MANUAL		= 0,
+	V4L2_ISO_SENSITIVITY_AUTO		= 1,
+};
+
+#define V4L2_CID_EXPOSURE_METERING		(V4L2_CID_CAMERA_CLASS_BASE+25)
+enum v4l2_exposure_metering {
+	V4L2_EXPOSURE_METERING_AVERAGE		= 0,
+	V4L2_EXPOSURE_METERING_CENTER_WEIGHTED	= 1,
+	V4L2_EXPOSURE_METERING_SPOT		= 2,
+};
+
+#define V4L2_CID_SCENE_MODE			(V4L2_CID_CAMERA_CLASS_BASE+26)
+enum v4l2_scene_mode {
+	V4L2_SCENE_MODE_NONE			= 0,
+	V4L2_SCENE_MODE_BACKLIGHT		= 1,
+	V4L2_SCENE_MODE_BEACH_SNOW		= 2,
+	V4L2_SCENE_MODE_CANDLE_LIGHT		= 3,
+	V4L2_SCENE_MODE_DAWN_DUSK		= 4,
+	V4L2_SCENE_MODE_FALL_COLORS		= 5,
+	V4L2_SCENE_MODE_FIREWORKS		= 6,
+	V4L2_SCENE_MODE_LANDSCAPE		= 7,
+	V4L2_SCENE_MODE_NIGHT			= 8,
+	V4L2_SCENE_MODE_PARTY_INDOOR		= 9,
+	V4L2_SCENE_MODE_PORTRAIT		= 10,
+	V4L2_SCENE_MODE_SPORTS			= 11,
+	V4L2_SCENE_MODE_SUNSET			= 12,
+	V4L2_SCENE_MODE_TEXT			= 13,
+};
+
+#define V4L2_CID_3A_LOCK			(V4L2_CID_CAMERA_CLASS_BASE+27)
+#define V4L2_LOCK_EXPOSURE			(1 << 0)
+#define V4L2_LOCK_WHITE_BALANCE			(1 << 1)
+#define V4L2_LOCK_FOCUS				(1 << 2)
+
+#define V4L2_CID_AUTO_FOCUS_START		(V4L2_CID_CAMERA_CLASS_BASE+28)
+#define V4L2_CID_AUTO_FOCUS_STOP		(V4L2_CID_CAMERA_CLASS_BASE+29)
+#define V4L2_CID_AUTO_FOCUS_STATUS		(V4L2_CID_CAMERA_CLASS_BASE+30)
+#define V4L2_AUTO_FOCUS_STATUS_IDLE		(0 << 0)
+#define V4L2_AUTO_FOCUS_STATUS_BUSY		(1 << 0)
+#define V4L2_AUTO_FOCUS_STATUS_REACHED		(1 << 1)
+#define V4L2_AUTO_FOCUS_STATUS_FAILED		(1 << 2)
+
+#define V4L2_CID_AUTO_FOCUS_RANGE		(V4L2_CID_CAMERA_CLASS_BASE+31)
+enum v4l2_auto_focus_range {
+	V4L2_AUTO_FOCUS_RANGE_AUTO		= 0,
+	V4L2_AUTO_FOCUS_RANGE_NORMAL		= 1,
+	V4L2_AUTO_FOCUS_RANGE_MACRO		= 2,
+	V4L2_AUTO_FOCUS_RANGE_INFINITY		= 3,
+};
+
 /* FM Modulator class control IDs */
 #define V4L2_CID_FM_TX_CLASS_BASE		(V4L2_CTRL_CLASS_FM_TX | 0x900)
 #define V4L2_CID_FM_TX_CLASS			(V4L2_CTRL_CLASS_FM_TX | 1)
@@ -1782,13 +1994,28 @@
 #define	V4L2_JPEG_ACTIVE_MARKER_DQT		(1 << 17)
 #define	V4L2_JPEG_ACTIVE_MARKER_DHT		(1 << 18)
 
+/* Image source controls */
+#define V4L2_CID_IMAGE_SOURCE_CLASS_BASE	(V4L2_CTRL_CLASS_IMAGE_SOURCE | 0x900)
+#define V4L2_CID_IMAGE_SOURCE_CLASS		(V4L2_CTRL_CLASS_IMAGE_SOURCE | 1)
+
+#define V4L2_CID_VBLANK				(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1)
+#define V4L2_CID_HBLANK				(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
+#define V4L2_CID_ANALOGUE_GAIN			(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
+
+/* Image processing controls */
+#define V4L2_CID_IMAGE_PROC_CLASS_BASE		(V4L2_CTRL_CLASS_IMAGE_PROC | 0x900)
+#define V4L2_CID_IMAGE_PROC_CLASS		(V4L2_CTRL_CLASS_IMAGE_PROC | 1)
+
+#define V4L2_CID_LINK_FREQ			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 1)
+#define V4L2_CID_PIXEL_RATE			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 2)
+
 /*
  *	T U N I N G
  */
 struct v4l2_tuner {
 	__u32                   index;
 	__u8			name[32];
-	enum v4l2_tuner_type    type;
+	__u32			type;	/* enum v4l2_tuner_type */
 	__u32			capability;
 	__u32			rangelow;
 	__u32			rangehigh;
@@ -1838,14 +2065,14 @@
 
 struct v4l2_frequency {
 	__u32		      tuner;
-	enum v4l2_tuner_type  type;
+	__u32		      type;	/* enum v4l2_tuner_type */
 	__u32		      frequency;
 	__u32		      reserved[8];
 };
 
 struct v4l2_hw_freq_seek {
 	__u32		      tuner;
-	enum v4l2_tuner_type  type;
+	__u32		      type;	/* enum v4l2_tuner_type */
 	__u32		      seek_upward;
 	__u32		      wrap_around;
 	__u32		      spacing;
@@ -2056,7 +2283,7 @@
 				 (equals frame lines 313-336 for 625 line video
 				  standards, 263-286 for 525 line standards) */
 	__u16   service_lines[2][24];
-	enum v4l2_buf_type type;
+	__u32	type;		/* enum v4l2_buf_type */
 	__u32   reserved[3];    /* must be 0 */
 };
 
@@ -2137,8 +2364,8 @@
  * @width:		image width in pixels
  * @height:		image height in pixels
  * @pixelformat:	little endian four character code (fourcc)
- * @field:		field order (for interlaced video)
- * @colorspace:		supplemental to pixelformat
+ * @field:		enum v4l2_field; field order (for interlaced video)
+ * @colorspace:		enum v4l2_colorspace; supplemental to pixelformat
  * @plane_fmt:		per-plane information
  * @num_planes:		number of planes for this format
  */
@@ -2146,8 +2373,8 @@
 	__u32				width;
 	__u32				height;
 	__u32				pixelformat;
-	enum v4l2_field			field;
-	enum v4l2_colorspace		colorspace;
+	__u32				field;
+	__u32				colorspace;
 
 	struct v4l2_plane_pix_format	plane_fmt[VIDEO_MAX_PLANES];
 	__u8				num_planes;
@@ -2156,7 +2383,7 @@
 
 /**
  * struct v4l2_format - stream data format
- * @type:	type of the data stream
+ * @type:	enum v4l2_buf_type; type of the data stream
  * @pix:	definition of an image format
  * @pix_mp:	definition of a multiplanar image format
  * @win:	definition of an overlaid image
@@ -2165,7 +2392,7 @@
  * @raw_data:	placeholder for future extensions and custom formats
  */
 struct v4l2_format {
-	enum v4l2_buf_type type;
+	__u32	 type;
 	union {
 		struct v4l2_pix_format		pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
 		struct v4l2_pix_format_mplane	pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
@@ -2179,7 +2406,7 @@
 /*	Stream type-dependent parameters
  */
 struct v4l2_streamparm {
-	enum v4l2_buf_type type;
+	__u32	 type;			/* enum v4l2_buf_type */
 	union {
 		struct v4l2_captureparm	capture;
 		struct v4l2_outputparm	output;
@@ -2292,14 +2519,14 @@
  * @index:	on return, index of the first created buffer
  * @count:	entry: number of requested buffers,
  *		return: number of created buffers
- * @memory:	buffer memory type
+ * @memory:	enum v4l2_memory; buffer memory type
  * @format:	frame format, for which buffers are requested
  * @reserved:	future extensions
  */
 struct v4l2_create_buffers {
 	__u32			index;
 	__u32			count;
-	enum v4l2_memory        memory;
+	__u32			memory;
 	struct v4l2_format	format;
 	__u32			reserved[8];
 };
@@ -2356,8 +2583,8 @@
 #define VIDIOC_TRY_FMT      	_IOWR('V', 64, struct v4l2_format)
 #define VIDIOC_ENUMAUDIO	_IOWR('V', 65, struct v4l2_audio)
 #define VIDIOC_ENUMAUDOUT	_IOWR('V', 66, struct v4l2_audioout)
-#define VIDIOC_G_PRIORITY        _IOR('V', 67, enum v4l2_priority)
-#define VIDIOC_S_PRIORITY        _IOW('V', 68, enum v4l2_priority)
+#define VIDIOC_G_PRIORITY	 _IOR('V', 67, __u32) /* enum v4l2_priority */
+#define VIDIOC_S_PRIORITY	 _IOW('V', 68, __u32) /* enum v4l2_priority */
 #define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap)
 #define VIDIOC_LOG_STATUS         _IO('V', 70)
 #define VIDIOC_G_EXT_CTRLS	_IOWR('V', 71, struct v4l2_ext_controls)
@@ -2384,6 +2611,9 @@
 #endif
 
 #define VIDIOC_S_HW_FREQ_SEEK	 _IOW('V', 82, struct v4l2_hw_freq_seek)
+
+/* These four DV Preset ioctls are deprecated in favor of the DV Timings
+   ioctls. */
 #define	VIDIOC_ENUM_DV_PRESETS	_IOWR('V', 83, struct v4l2_dv_enum_preset)
 #define	VIDIOC_S_DV_PRESET	_IOWR('V', 84, struct v4l2_dv_preset)
 #define	VIDIOC_G_DV_PRESET	_IOWR('V', 85, struct v4l2_dv_preset)
@@ -2408,6 +2638,12 @@
 #define VIDIOC_DECODER_CMD	_IOWR('V', 96, struct v4l2_decoder_cmd)
 #define VIDIOC_TRY_DECODER_CMD	_IOWR('V', 97, struct v4l2_decoder_cmd)
 
+/* Experimental, these three ioctls may change over the next couple of kernel
+   versions. */
+#define VIDIOC_ENUM_DV_TIMINGS  _IOWR('V', 96, struct v4l2_enum_dv_timings)
+#define VIDIOC_QUERY_DV_TIMINGS  _IOR('V', 97, struct v4l2_dv_timings)
+#define VIDIOC_DV_TIMINGS_CAP   _IOWR('V', 98, struct v4l2_dv_timings_cap)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
diff --git a/drivers/staging/vme/vme.h b/include/linux/vme.h
similarity index 100%
rename from drivers/staging/vme/vme.h
rename to include/linux/vme.h
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index e33d77f..50ae7d0 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -70,7 +70,6 @@
 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list);
 int con_set_default_unimap(struct vc_data *vc);
 void con_free_unimap(struct vc_data *vc);
-void con_protect_unimap(struct vc_data *vc, int rdonly);
 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
 
 #define vc_translate(vc, c) ((vc)->vc_translate[(c) |			\
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 29e7bba..0c16f51 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -46,6 +46,7 @@
 	int (*link_setup)(struct media_entity *entity,
 			  const struct media_pad *local,
 			  const struct media_pad *remote, u32 flags);
+	int (*link_validate)(struct media_link *link);
 };
 
 struct media_entity {
@@ -140,8 +141,8 @@
 		struct media_entity *entity);
 struct media_entity *
 media_entity_graph_walk_next(struct media_entity_graph *graph);
-void media_entity_pipeline_start(struct media_entity *entity,
-		struct media_pipeline *pipe);
+__must_check int media_entity_pipeline_start(struct media_entity *entity,
+					     struct media_pipeline *pipe);
 void media_entity_pipeline_stop(struct media_entity *entity);
 
 #define media_entity_call(entity, operation, args...)			\
diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h
index 96448c7..0c97b19 100644
--- a/include/media/mt9p031.h
+++ b/include/media/mt9p031.h
@@ -3,17 +3,18 @@
 
 struct v4l2_subdev;
 
-enum {
-	MT9P031_COLOR_VERSION,
-	MT9P031_MONOCHROME_VERSION,
-};
-
+/*
+ * struct mt9p031_platform_data - MT9P031 platform data
+ * @set_xclk: Clock frequency set callback
+ * @reset: Chip reset GPIO (set to -1 if not used)
+ * @ext_freq: Input clock frequency
+ * @target_freq: Pixel clock frequency
+ */
 struct mt9p031_platform_data {
 	int (*set_xclk)(struct v4l2_subdev *subdev, int hz);
-	int (*reset)(struct v4l2_subdev *subdev, int active);
-	int ext_freq; /* input frequency to the mt9p031 for PLL dividers */
-	int target_freq; /* frequency target for the PLL */
-	int version; /* MT9P031_COLOR_VERSION or MT9P031_MONOCHROME_VERSION */
+	int reset;
+	int ext_freq;
+	int target_freq;
 };
 
 #endif
diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
index 042849a..4d94be5 100644
--- a/include/media/omap3isp.h
+++ b/include/media/omap3isp.h
@@ -29,6 +29,10 @@
 struct i2c_board_info;
 struct isp_device;
 
+#define ISP_XCLK_NONE			0
+#define ISP_XCLK_A			1
+#define ISP_XCLK_B			2
+
 enum isp_interface_type {
 	ISP_INTERFACE_PARALLEL,
 	ISP_INTERFACE_CSI2A_PHY2,
@@ -87,6 +91,29 @@
 };
 
 /**
+ * struct isp_csiphy_lane: CCP2/CSI2 lane position and polarity
+ * @pos: position of the lane
+ * @pol: polarity of the lane
+ */
+struct isp_csiphy_lane {
+	u8 pos;
+	u8 pol;
+};
+
+#define ISP_CSIPHY1_NUM_DATA_LANES	1
+#define ISP_CSIPHY2_NUM_DATA_LANES	2
+
+/**
+ * struct isp_csiphy_lanes_cfg - CCP2/CSI2 lane configuration
+ * @data: Configuration of one or two data lanes
+ * @clk: Clock lane configuration
+ */
+struct isp_csiphy_lanes_cfg {
+	struct isp_csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
+	struct isp_csiphy_lane clk;
+};
+
+/**
  * struct isp_ccp2_platform_data - CCP2 interface platform data
  * @strobe_clk_pol: Strobe/clock polarity
  *		0 - Non Inverted, 1 - Inverted
@@ -105,6 +132,7 @@
 	unsigned int ccp2_mode:1;
 	unsigned int phy_layer:1;
 	unsigned int vpclk_div:2;
+	struct isp_csiphy_lanes_cfg lanecfg;
 };
 
 /**
@@ -115,6 +143,7 @@
 struct isp_csi2_platform_data {
 	unsigned crc:1;
 	unsigned vpclk_div:2;
+	struct isp_csiphy_lanes_cfg lanecfg;
 };
 
 struct isp_subdev_i2c_board_info {
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 8db6741..cfd5163 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -62,6 +62,7 @@
 #define RC_MAP_ANYSEE                    "rc-anysee"
 #define RC_MAP_APAC_VIEWCOMP             "rc-apac-viewcomp"
 #define RC_MAP_ASUS_PC39                 "rc-asus-pc39"
+#define RC_MAP_ASUS_PS3_100              "rc-asus-ps3-100"
 #define RC_MAP_ATI_TV_WONDER_HD_600      "rc-ati-tv-wonder-hd-600"
 #define RC_MAP_ATI_X10                   "rc-ati-x10"
 #define RC_MAP_AVERMEDIA_A16D            "rc-avermedia-a16d"
@@ -113,6 +114,8 @@
 #define RC_MAP_LME2510                   "rc-lme2510"
 #define RC_MAP_MANLI                     "rc-manli"
 #define RC_MAP_MEDION_X10                "rc-medion-x10"
+#define RC_MAP_MEDION_X10_DIGITAINER     "rc-medion-x10-digitainer"
+#define RC_MAP_MEDION_X10_OR2X           "rc-medion-x10-or2x"
 #define RC_MAP_MSI_DIGIVOX_II            "rc-msi-digivox-ii"
 #define RC_MAP_MSI_DIGIVOX_III           "rc-msi-digivox-iii"
 #define RC_MAP_MSI_TVANYWHERE_PLUS       "rc-msi-tvanywhere-plus"
diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h
index 688fb3f..8587aaf 100644
--- a/include/media/s5p_fimc.h
+++ b/include/media/s5p_fimc.h
@@ -64,4 +64,20 @@
  */
 #define S5P_FIMC_TX_END_NOTIFY _IO('e', 0)
 
+enum fimc_subdev_index {
+	IDX_SENSOR,
+	IDX_CSIS,
+	IDX_FLITE,
+	IDX_FIMC,
+	IDX_MAX,
+};
+
+struct media_pipeline;
+struct v4l2_subdev;
+
+struct fimc_pipeline {
+	struct v4l2_subdev *subdevs[IDX_MAX];
+	struct media_pipeline *m_pipeline;
+};
+
 #endif /* S5P_FIMC_H_ */
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index 0f037e8e..773e527 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -13,12 +13,11 @@
 #include <linux/mutex.h>
 #include <linux/scatterlist.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 
 #include <linux/vmalloc.h>	/* for vmalloc() */
 #include <linux/mm.h>		/* for vmalloc_to_page() */
 
-#define SAA7146_VERSION_CODE 0x000600	/* 0.6.0 */
-
 #define saa7146_write(sxy,adr,dat)    writel((dat),(sxy->mem+(adr)))
 #define saa7146_read(sxy,adr)         readl(sxy->mem+(adr))
 
@@ -121,6 +120,7 @@
 	struct list_head		item;
 
 	struct v4l2_device 		v4l2_dev;
+	struct v4l2_ctrl_handler	ctrl_handler;
 
 	/* different device locks */
 	spinlock_t			slock;
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
index 4aeff96..944ecdf 100644
--- a/include/media/saa7146_vv.h
+++ b/include/media/saa7146_vv.h
@@ -3,6 +3,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
 #include <media/saa7146.h>
 #include <media/videobuf-dma-sg.h>
 
@@ -84,21 +85,15 @@
 
 /* per open data */
 struct saa7146_fh {
+	/* Must be the first field! */
+	struct v4l2_fh		fh;
 	struct saa7146_dev	*dev;
-	/* if this is a vbi or capture open */
-	enum v4l2_buf_type	type;
-
-	/* video overlay */
-	struct saa7146_overlay	ov;
 
 	/* video capture */
 	struct videobuf_queue	video_q;
-	struct v4l2_pix_format	video_fmt;
 
 	/* vbi capture */
 	struct videobuf_queue	vbi_q;
-	struct v4l2_vbi_format	vbi_fmt;
-	struct timer_list	vbi_read_timeout;
 
 	unsigned int resources;	/* resource management for device open */
 };
@@ -109,7 +104,9 @@
 struct saa7146_vv
 {
 	/* vbi capture */
-	struct saa7146_dmaqueue		vbi_q;
+	struct saa7146_dmaqueue		vbi_dmaq;
+	struct v4l2_vbi_format		vbi_fmt;
+	struct timer_list		vbi_read_timeout;
 	/* vbi workaround interrupt queue */
 	wait_queue_head_t		vbi_wq;
 	int				vbi_fieldcount;
@@ -119,13 +116,14 @@
 	struct saa7146_fh		*video_fh;
 
 	/* video overlay */
+	struct saa7146_overlay		ov;
 	struct v4l2_framebuffer		ov_fb;
 	struct saa7146_format		*ov_fmt;
-	struct saa7146_overlay		*ov_data;
 	struct saa7146_fh		*ov_suspend;
 
 	/* video capture */
-	struct saa7146_dmaqueue		video_q;
+	struct saa7146_dmaqueue		video_dmaq;
+	struct v4l2_pix_format		video_fmt;
 	enum v4l2_field			last_field;
 
 	/* common: fixme? shouldn't this be in saa7146_fh?
@@ -163,7 +161,8 @@
 	int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
 
 	/* the extension can override this */
-	struct v4l2_ioctl_ops ops;
+	struct v4l2_ioctl_ops vid_ops;
+	struct v4l2_ioctl_ops vbi_ops;
 	/* pointer to the saa7146 core ops */
 	const struct v4l2_ioctl_ops *core_ops;
 
@@ -202,10 +201,12 @@
 
 /* from saa7146_video.c */
 extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
+extern const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops;
 extern struct saa7146_use_ops saa7146_video_uops;
 int saa7146_start_preview(struct saa7146_fh *fh);
 int saa7146_stop_preview(struct saa7146_fh *fh);
 long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
+int saa7146_s_ctrl(struct v4l2_ctrl *ctrl);
 
 /* from saa7146_vbi.c */
 extern struct saa7146_use_ops saa7146_vbi_uops;
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
index a90a765..6fdb6ad 100644
--- a/include/media/sh_mobile_ceu.h
+++ b/include/media/sh_mobile_ceu.h
@@ -5,6 +5,7 @@
 #define SH_CEU_FLAG_USE_16BIT_BUS	(1 << 1) /* use 16bit bus width */
 #define SH_CEU_FLAG_HSYNC_LOW		(1 << 2) /* default High if possible */
 #define SH_CEU_FLAG_VSYNC_LOW		(1 << 3) /* default High if possible */
+#define SH_CEU_FLAG_LOWER_8BIT		(1 << 4) /* default upper 8bit */
 
 struct device;
 struct resource;
diff --git a/include/media/smiapp.h b/include/media/smiapp.h
new file mode 100644
index 0000000..9ab07fd
--- /dev/null
+++ b/include/media/smiapp.h
@@ -0,0 +1,84 @@
+/*
+ * include/media/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.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 __SMIAPP_H_
+#define __SMIAPP_H_
+
+#include <media/v4l2-subdev.h>
+
+#define SMIAPP_NAME		"smiapp"
+
+#define SMIAPP_DFL_I2C_ADDR	(0x20 >> 1) /* Default I2C Address */
+#define SMIAPP_ALT_I2C_ADDR	(0x6e >> 1) /* Alternate I2C Address */
+
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK	0
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE	1
+#define SMIAPP_CSI_SIGNALLING_MODE_CSI2			2
+
+#define SMIAPP_NO_XSHUTDOWN	-1
+
+/*
+ * Sometimes due to board layout considerations the camera module can be
+ * mounted rotated. The typical rotation used is 180 degrees which can be
+ * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
+ * FIXME: rotation also changes the bayer pattern.
+ */
+enum smiapp_module_board_orient {
+	SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
+	SMIAPP_MODULE_BOARD_ORIENT_180,
+};
+
+struct smiapp_flash_strobe_parms {
+	u8 mode;
+	u32 strobe_width_high_us;
+	u16 strobe_delay;
+	u16 stobe_start_point;
+	u8 trigger;
+};
+
+struct smiapp_platform_data {
+	/*
+	 * Change the cci address if i2c_addr_alt is set.
+	 * Both default and alternate cci addr need to be present
+	 */
+	unsigned short i2c_addr_dfl;	/* Default i2c addr */
+	unsigned short i2c_addr_alt;	/* Alternate i2c addr */
+
+	unsigned int nvm_size;			/* bytes */
+	unsigned int ext_clk;			/* sensor external clk */
+
+	unsigned int lanes;		/* Number of CSI-2 lanes */
+	u8 csi_signalling_mode;		/* SMIAPP_CSI_SIGNALLING_MODE_* */
+	const s64 *op_sys_clock;
+
+	enum smiapp_module_board_orient module_board_orient;
+
+	struct smiapp_flash_strobe_parms *strobe_setup;
+
+	int (*set_xclk)(struct v4l2_subdev *sd, int hz);
+	char *ext_clk_name;
+	int xshutdown;			/* gpio or SMIAPP_NO_XSHUTDOWN */
+};
+
+#endif /* __SMIAPP_H_  */
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index cad374b..d865dcf 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -56,11 +56,15 @@
 	};
 };
 
+/* Host supports programmable stride */
+#define SOCAM_HOST_CAP_STRIDE		(1 << 0)
+
 struct soc_camera_host {
 	struct v4l2_device v4l2_dev;
 	struct list_head list;
 	struct mutex host_lock;		/* Protect during probing */
 	unsigned char nr;		/* Host number */
+	u32 capabilities;
 	void *priv;
 	const char *drv_name;
 	struct soc_camera_host_ops *ops;
@@ -98,7 +102,7 @@
 	int (*set_bus_param)(struct soc_camera_device *);
 	int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *);
 	int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *);
-	int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *);
+	int (*enum_framesizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *);
 	unsigned int (*poll)(struct file *, poll_table *);
 };
 
diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h
index 73f1e7e..0dc6f46 100644
--- a/include/media/soc_mediabus.h
+++ b/include/media/soc_mediabus.h
@@ -47,6 +47,24 @@
 };
 
 /**
+ * enum soc_mbus_layout - planes layout in memory
+ * @SOC_MBUS_LAYOUT_PACKED:		color components packed
+ * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:	YUV components stored in 3 planes (4:2:2)
+ * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:	YUV components stored in a luma and a
+ *					chroma plane (C plane is half the size
+ *					of Y plane)
+ * @SOC_MBUS_LAYOUT_PLANAR_Y_C:		YUV components stored in a luma and a
+ *					chroma plane (C plane is the same size
+ *					as Y plane)
+ */
+enum soc_mbus_layout {
+	SOC_MBUS_LAYOUT_PACKED = 0,
+	SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
+	SOC_MBUS_LAYOUT_PLANAR_2Y_C,
+	SOC_MBUS_LAYOUT_PLANAR_Y_C,
+};
+
+/**
  * struct soc_mbus_pixelfmt - Data format on the media bus
  * @name:		Name of the format
  * @fourcc:		Fourcc code, that will be obtained if the data is
@@ -60,6 +78,7 @@
 	u32			fourcc;
 	enum soc_mbus_packing	packing;
 	enum soc_mbus_order	order;
+	enum soc_mbus_layout	layout;
 	u8			bits_per_sample;
 };
 
@@ -80,6 +99,8 @@
 const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
 	enum v4l2_mbus_pixelcode code);
 s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf);
+s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
+			u32 bytes_per_line, u32 height);
 int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
 			unsigned int *numerator, unsigned int *denominator);
 unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 11e6756..776605f 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -25,6 +25,7 @@
 #include <linux/videodev2.h>
 
 /* forward references */
+struct file;
 struct v4l2_ctrl_handler;
 struct v4l2_ctrl_helper;
 struct v4l2_ctrl;
@@ -129,7 +130,10 @@
 		u32 step;
 		u32 menu_skip_mask;
 	};
-	const char * const *qmenu;
+	union {
+		const char * const *qmenu;
+		const s64 *qmenu_int;
+	};
 	unsigned long flags;
 	union {
 		s32 val;
@@ -164,7 +168,9 @@
 /** struct v4l2_ctrl_handler - The control handler keeps track of all the
   * controls: both the controls owned by the handler and those inherited
   * from other handlers.
+  * @_lock:	Default for "lock".
   * @lock:	Lock to control access to this handler and its controls.
+  *		May be replaced by the user right after init.
   * @ctrls:	The list of controls owned by this handler.
   * @ctrl_refs:	The list of control references.
   * @cached:	The last found control reference. It is common that the same
@@ -175,7 +181,8 @@
   * @error:	The error code of the first failed control addition.
   */
 struct v4l2_ctrl_handler {
-	struct mutex lock;
+	struct mutex _lock;
+	struct mutex *lock;
 	struct list_head ctrls;
 	struct list_head ctrl_refs;
 	struct v4l2_ctrl_ref *cached;
@@ -219,6 +226,7 @@
 	u32 flags;
 	u32 menu_skip_mask;
 	const char * const *qmenu;
+	const s64 *qmenu_int;
 	unsigned int is_private:1;
 };
 
@@ -343,6 +351,23 @@
 			const struct v4l2_ctrl_ops *ops,
 			u32 id, s32 max, s32 mask, s32 def);
 
+/** v4l2_ctrl_new_int_menu() - Create a new standard V4L2 integer menu control.
+  * @hdl:	The control handler.
+  * @ops:	The control ops.
+  * @id:	The control ID.
+  * @max:	The control's maximum value.
+  * @def:	The control's default value.
+  * @qmenu_int:	The control's menu entries.
+  *
+  * Same as v4l2_ctrl_new_std_menu(), but @mask is set to 0 and it additionaly
+  * takes as an argument an array of integers determining the menu items.
+  *
+  * If @id refers to a non-integer-menu control, then this function will return NULL.
+  */
+struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
+			const struct v4l2_ctrl_ops *ops,
+			u32 id, s32 max, s32 def, const s64 *qmenu_int);
+
 /** v4l2_ctrl_add_ctrl() - Add a control from another handler to this handler.
   * @hdl:	The control handler.
   * @ctrl:	The control to add.
@@ -451,7 +476,7 @@
   */
 static inline void v4l2_ctrl_lock(struct v4l2_ctrl *ctrl)
 {
-	mutex_lock(&ctrl->handler->lock);
+	mutex_lock(ctrl->handler->lock);
 }
 
 /** v4l2_ctrl_lock() - Helper function to unlock the handler
@@ -460,7 +485,7 @@
   */
 static inline void v4l2_ctrl_unlock(struct v4l2_ctrl *ctrl)
 {
-	mutex_unlock(&ctrl->handler->lock);
+	mutex_unlock(ctrl->handler->lock);
 }
 
 /** v4l2_ctrl_g_ctrl() - Helper function to get the control's value from within a driver.
@@ -487,10 +512,9 @@
 int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
 
 /* Internal helper functions that deal with control events. */
-void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
-		struct v4l2_subscribed_event *sev);
-void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
-		struct v4l2_subscribed_event *sev);
+extern const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops;
+void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new);
+void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new);
 
 /* Can be used as a vidioc_log_status function that just dumps all controls
    associated with the filehandle. */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 96d2221..a056e6e 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -39,6 +39,9 @@
 #define V4L2_FL_USES_V4L2_FH	(1)
 /* Use the prio field of v4l2_fh for core priority checking */
 #define V4L2_FL_USE_FH_PRIO	(2)
+/* If ioctl core locking is in use, then apply that also to all
+   file operations. Don't use this flag in new drivers! */
+#define V4L2_FL_LOCK_ALL_FOPS	(3)
 
 /* Priority helper functions */
 
@@ -126,8 +129,10 @@
 
 	/* ioctl callbacks */
 	const struct v4l2_ioctl_ops *ioctl_ops;
+	DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
 
 	/* serialization lock */
+	DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);
 	struct mutex *lock;
 };
 
@@ -173,6 +178,26 @@
    a dubious construction at best. */
 void video_device_release_empty(struct video_device *vdev);
 
+/* returns true if cmd is a known V4L2 ioctl */
+bool v4l2_is_known_ioctl(unsigned int cmd);
+
+/* mark that this command shouldn't use core locking */
+static inline void v4l2_disable_ioctl_locking(struct video_device *vdev, unsigned int cmd)
+{
+	if (_IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
+		set_bit(_IOC_NR(cmd), vdev->disable_locking);
+}
+
+/* Mark that this command isn't implemented. This must be called before
+   video_device_register. See also the comments in determine_valid_ioctls().
+   This function allows drivers to provide just one v4l2_ioctl_ops struct, but
+   disable ioctls based on the specific card that is actually found. */
+static inline void v4l2_disable_ioctl(struct video_device *vdev, unsigned int cmd)
+{
+	if (_IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
+		set_bit(_IOC_NR(cmd), vdev->valid_ioctls);
+}
+
 /* helper functions to access driver private data. */
 static inline void *video_get_drvdata(struct video_device *vdev)
 {
diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h
index 5f14e88..2885a81 100644
--- a/include/media/v4l2-event.h
+++ b/include/media/v4l2-event.h
@@ -78,6 +78,19 @@
 	struct v4l2_event	event;
 };
 
+/** struct v4l2_subscribed_event_ops - Subscribed event operations.
+  * @add:	Optional callback, called when a new listener is added
+  * @del:	Optional callback, called when a listener stops listening
+  * @replace:	Optional callback that can replace event 'old' with event 'new'.
+  * @merge:	Optional callback that can merge event 'old' into event 'new'.
+  */
+struct v4l2_subscribed_event_ops {
+	int  (*add)(struct v4l2_subscribed_event *sev, unsigned elems);
+	void (*del)(struct v4l2_subscribed_event *sev);
+	void (*replace)(struct v4l2_event *old, const struct v4l2_event *new);
+	void (*merge)(const struct v4l2_event *old, struct v4l2_event *new);
+};
+
 /** struct v4l2_subscribed_event - Internal struct representing a subscribed event.
   * @list:	List node for the v4l2_fh->subscribed list.
   * @type:	Event type.
@@ -85,8 +98,7 @@
   * @flags:	Copy of v4l2_event_subscription->flags.
   * @fh:	Filehandle that subscribed to this event.
   * @node:	List node that hooks into the object's event list (if there is one).
-  * @replace:	Optional callback that can replace event 'old' with event 'new'.
-  * @merge:	Optional callback that can merge event 'old' into event 'new'.
+  * @ops:	v4l2_subscribed_event_ops
   * @elems:	The number of elements in the events array.
   * @first:	The index of the events containing the oldest available event.
   * @in_use:	The number of queued events.
@@ -99,10 +111,7 @@
 	u32			flags;
 	struct v4l2_fh		*fh;
 	struct list_head	node;
-	void			(*replace)(struct v4l2_event *old,
-					   const struct v4l2_event *new);
-	void			(*merge)(const struct v4l2_event *old,
-					 struct v4l2_event *new);
+	const struct v4l2_subscribed_event_ops *ops;
 	unsigned		elems;
 	unsigned		first;
 	unsigned		in_use;
@@ -115,7 +124,8 @@
 void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev);
 int v4l2_event_pending(struct v4l2_fh *fh);
 int v4l2_event_subscribe(struct v4l2_fh *fh,
-			 struct v4l2_event_subscription *sub, unsigned elems);
+			 struct v4l2_event_subscription *sub, unsigned elems,
+			 const struct v4l2_subscribed_event_ops *ops);
 int v4l2_event_unsubscribe(struct v4l2_fh *fh,
 			   struct v4l2_event_subscription *sub);
 void v4l2_event_unsubscribe_all(struct v4l2_fh *fh);
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 3cb939c..d8b76f7 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -271,6 +271,12 @@
 				    struct v4l2_dv_timings *timings);
 	int (*vidioc_g_dv_timings) (struct file *file, void *fh,
 				    struct v4l2_dv_timings *timings);
+	int (*vidioc_query_dv_timings) (struct file *file, void *fh,
+				    struct v4l2_dv_timings *timings);
+	int (*vidioc_enum_dv_timings) (struct file *file, void *fh,
+				    struct v4l2_enum_dv_timings *timings);
+	int (*vidioc_dv_timings_cap) (struct file *file, void *fh,
+				    struct v4l2_dv_timings_cap *cap);
 
 	int (*vidioc_subscribe_event)  (struct v4l2_fh *fh,
 					struct v4l2_event_subscription *sub);
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index f0f3358..c35a354 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -307,6 +307,12 @@
 			struct v4l2_dv_timings *timings);
 	int (*g_dv_timings)(struct v4l2_subdev *sd,
 			struct v4l2_dv_timings *timings);
+	int (*enum_dv_timings)(struct v4l2_subdev *sd,
+			struct v4l2_enum_dv_timings *timings);
+	int (*query_dv_timings)(struct v4l2_subdev *sd,
+			struct v4l2_dv_timings *timings);
+	int (*dv_timings_cap)(struct v4l2_subdev *sd,
+			struct v4l2_dv_timings_cap *cap);
 	int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index,
 			     enum v4l2_mbus_pixelcode *code);
 	int (*enum_mbus_fsizes)(struct v4l2_subdev *sd,
@@ -466,6 +472,15 @@
 		       struct v4l2_subdev_crop *crop);
 	int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 		       struct v4l2_subdev_crop *crop);
+	int (*get_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_selection *sel);
+	int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_selection *sel);
+#ifdef CONFIG_MEDIA_CONTROLLER
+	int (*link_validate)(struct v4l2_subdev *sd, struct media_link *link,
+			     struct v4l2_subdev_format *source_fmt,
+			     struct v4l2_subdev_format *sink_fmt);
+#endif /* CONFIG_MEDIA_CONTROLLER */
 };
 
 struct v4l2_subdev_ops {
@@ -541,7 +556,7 @@
 #define media_entity_to_v4l2_subdev(ent) \
 	container_of(ent, struct v4l2_subdev, entity)
 #define vdev_to_v4l2_subdev(vdev) \
-	video_get_drvdata(vdev)
+	((struct v4l2_subdev *)video_get_drvdata(vdev))
 
 /*
  * Used for storing subdev information per file handle
@@ -549,8 +564,11 @@
 struct v4l2_subdev_fh {
 	struct v4l2_fh vfh;
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-	struct v4l2_mbus_framefmt *try_fmt;
-	struct v4l2_rect *try_crop;
+	struct {
+		struct v4l2_mbus_framefmt try_fmt;
+		struct v4l2_rect try_crop;
+		struct v4l2_rect try_compose;
+	} *pad;
 #endif
 };
 
@@ -558,17 +576,19 @@
 	container_of(fh, struct v4l2_subdev_fh, vfh)
 
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static inline struct v4l2_mbus_framefmt *
-v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad)
-{
-	return &fh->try_fmt[pad];
-}
+#define __V4L2_SUBDEV_MK_GET_TRY(rtype, fun_name, field_name)		\
+	static inline struct rtype *					\
+	v4l2_subdev_get_try_##fun_name(struct v4l2_subdev_fh *fh,	\
+				       unsigned int pad)		\
+	{								\
+		BUG_ON(unlikely(pad >= vdev_to_v4l2_subdev(		\
+					fh->vfh.vdev)->entity.num_pads)); \
+		return &fh->pad[pad].field_name;			\
+	}
 
-static inline struct v4l2_rect *
-v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
-{
-	return &fh->try_crop[pad];
-}
+__V4L2_SUBDEV_MK_GET_TRY(v4l2_mbus_framefmt, format, try_fmt)
+__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, crop, try_compose)
+__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, compose, try_compose)
 #endif
 
 extern const struct v4l2_file_operations v4l2_subdev_fops;
@@ -593,6 +613,13 @@
 	return sd->host_priv;
 }
 
+#ifdef CONFIG_MEDIA_CONTROLLER
+int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
+				      struct media_link *link,
+				      struct v4l2_subdev_format *source_fmt,
+				      struct v4l2_subdev_format *sink_fmt);
+int v4l2_subdev_link_validate(struct media_link *link);
+#endif /* CONFIG_MEDIA_CONTROLLER */
 void v4l2_subdev_init(struct v4l2_subdev *sd,
 		      const struct v4l2_subdev_ops *ops);
 
diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h
index f0ed825..f473aeb 100644
--- a/include/media/videobuf-dma-contig.h
+++ b/include/media/videobuf-dma-contig.h
@@ -26,6 +26,16 @@
 				    void *priv,
 				    struct mutex *ext_lock);
 
+void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q,
+					   const struct videobuf_queue_ops *ops,
+					   struct device *dev,
+					   spinlock_t *irqlock,
+					   enum v4l2_buf_type type,
+					   enum v4l2_field field,
+					   unsigned int msize,
+					   void *priv,
+					   struct mutex *ext_lock);
+
 dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
 void videobuf_dma_contig_free(struct videobuf_queue *q,
 			      struct videobuf_buffer *buf);
diff --git a/include/memory/jedec_ddr.h b/include/memory/jedec_ddr.h
new file mode 100644
index 0000000..ddad0f8
--- /dev/null
+++ b/include/memory/jedec_ddr.h
@@ -0,0 +1,175 @@
+/*
+ * Definitions for DDR memories based on JEDEC specs
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@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.
+ */
+#ifndef __LINUX_JEDEC_DDR_H
+#define __LINUX_JEDEC_DDR_H
+
+#include <linux/types.h>
+
+/* DDR Densities */
+#define DDR_DENSITY_64Mb	1
+#define DDR_DENSITY_128Mb	2
+#define DDR_DENSITY_256Mb	3
+#define DDR_DENSITY_512Mb	4
+#define DDR_DENSITY_1Gb		5
+#define DDR_DENSITY_2Gb		6
+#define DDR_DENSITY_4Gb		7
+#define DDR_DENSITY_8Gb		8
+#define DDR_DENSITY_16Gb	9
+#define DDR_DENSITY_32Gb	10
+
+/* DDR type */
+#define DDR_TYPE_DDR2		1
+#define DDR_TYPE_DDR3		2
+#define DDR_TYPE_LPDDR2_S4	3
+#define DDR_TYPE_LPDDR2_S2	4
+#define DDR_TYPE_LPDDR2_NVM	5
+
+/* DDR IO width */
+#define DDR_IO_WIDTH_4		1
+#define DDR_IO_WIDTH_8		2
+#define DDR_IO_WIDTH_16		3
+#define DDR_IO_WIDTH_32		4
+
+/* Number of Row bits */
+#define R9			9
+#define R10			10
+#define R11			11
+#define R12			12
+#define R13			13
+#define R14			14
+#define R15			15
+#define R16			16
+
+/* Number of Column bits */
+#define C7			7
+#define C8			8
+#define C9			9
+#define C10			10
+#define C11			11
+#define C12			12
+
+/* Number of Banks */
+#define B1			0
+#define B2			1
+#define B4			2
+#define B8			3
+
+/* Refresh rate in nano-seconds */
+#define T_REFI_15_6		15600
+#define T_REFI_7_8		7800
+#define T_REFI_3_9		3900
+
+/* tRFC values */
+#define T_RFC_90		90000
+#define T_RFC_110		110000
+#define T_RFC_130		130000
+#define T_RFC_160		160000
+#define T_RFC_210		210000
+#define T_RFC_300		300000
+#define T_RFC_350		350000
+
+/* Mode register numbers */
+#define DDR_MR0			0
+#define DDR_MR1			1
+#define DDR_MR2			2
+#define DDR_MR3			3
+#define DDR_MR4			4
+#define DDR_MR5			5
+#define DDR_MR6			6
+#define DDR_MR7			7
+#define DDR_MR8			8
+#define DDR_MR9			9
+#define DDR_MR10		10
+#define DDR_MR11		11
+#define DDR_MR16		16
+#define DDR_MR17		17
+#define DDR_MR18		18
+
+/*
+ * LPDDR2 related defines
+ */
+
+/* MR4 register fields */
+#define MR4_SDRAM_REF_RATE_SHIFT			0
+#define MR4_SDRAM_REF_RATE_MASK				7
+#define MR4_TUF_SHIFT					7
+#define MR4_TUF_MASK					(1 << 7)
+
+/* MR4 SDRAM Refresh Rate field values */
+#define SDRAM_TEMP_NOMINAL				0x3
+#define SDRAM_TEMP_RESERVED_4				0x4
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH			0x5
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS	0x6
+#define SDRAM_TEMP_VERY_HIGH_SHUTDOWN			0x7
+
+#define NUM_DDR_ADDR_TABLE_ENTRIES			11
+#define NUM_DDR_TIMING_TABLE_ENTRIES			4
+
+/* Structure for DDR addressing info from the JEDEC spec */
+struct lpddr2_addressing {
+	u32 num_banks;
+	u32 tREFI_ns;
+	u32 tRFCab_ps;
+};
+
+/*
+ * Structure for timings from the LPDDR2 datasheet
+ * All parameters are in pico seconds(ps) unless explicitly indicated
+ * with a suffix like tRAS_max_ns below
+ */
+struct lpddr2_timings {
+	u32 max_freq;
+	u32 min_freq;
+	u32 tRPab;
+	u32 tRCD;
+	u32 tWR;
+	u32 tRAS_min;
+	u32 tRRD;
+	u32 tWTR;
+	u32 tXP;
+	u32 tRTP;
+	u32 tCKESR;
+	u32 tDQSCK_max;
+	u32 tDQSCK_max_derated;
+	u32 tFAW;
+	u32 tZQCS;
+	u32 tZQCL;
+	u32 tZQinit;
+	u32 tRAS_max_ns;
+};
+
+/*
+ * Min value for some parameters in terms of number of tCK cycles(nCK)
+ * Please set to zero parameters that are not valid for a given memory
+ * type
+ */
+struct lpddr2_min_tck {
+	u32 tRPab;
+	u32 tRCD;
+	u32 tWR;
+	u32 tRASmin;
+	u32 tRRD;
+	u32 tWTR;
+	u32 tXP;
+	u32 tRTP;
+	u32 tCKE;
+	u32 tCKESR;
+	u32 tFAW;
+};
+
+extern const struct lpddr2_addressing
+	lpddr2_jedec_addressing_table[NUM_DDR_ADDR_TABLE_ENTRIES];
+extern const struct lpddr2_timings
+	lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES];
+extern const struct lpddr2_min_tck lpddr2_jedec_min_tck;
+
+#endif /* __LINUX_JEDEC_DDR_H */
diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h
index 3c41097..8787349 100644
--- a/include/mtd/ubi-user.h
+++ b/include/mtd/ubi-user.h
@@ -196,23 +196,6 @@
 #define UBI_MAX_RNVOL 32
 
 /*
- * UBI data type hint constants.
- *
- * UBI_LONGTERM: long-term data
- * UBI_SHORTTERM: short-term data
- * UBI_UNKNOWN: data persistence is unknown
- *
- * These constants are used when data is written to UBI volumes in order to
- * help the UBI wear-leveling unit to find more appropriate physical
- * eraseblocks.
- */
-enum {
-	UBI_LONGTERM  = 1,
-	UBI_SHORTTERM = 2,
-	UBI_UNKNOWN   = 3,
-};
-
-/*
  * UBI volume type constants.
  *
  * @UBI_DYNAMIC_VOLUME: dynamic volume
@@ -375,25 +358,34 @@
  *                             requests.
  * @lnum: logical eraseblock number to change
  * @bytes: how many bytes will be written to the logical eraseblock
- * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
+ * @dtype: pass "3" for better compatibility with old kernels
  * @padding: reserved for future, not used, has to be zeroed
+ *
+ * The @dtype field used to inform UBI about what kind of data will be written
+ * to the LEB: long term (value 1), short term (value 2), unknown (value 3).
+ * UBI tried to pick a PEB with lower erase counter for short term data and a
+ * PEB with higher erase counter for long term data. But this was not really
+ * used because users usually do not know this and could easily mislead UBI. We
+ * removed this feature in May 2012. UBI currently just ignores the @dtype
+ * field. But for better compatibility with older kernels it is recommended to
+ * set @dtype to 3 (unknown).
  */
 struct ubi_leb_change_req {
 	__s32 lnum;
 	__s32 bytes;
-	__s8  dtype;
+	__s8  dtype; /* obsolete, do not use! */
 	__s8  padding[7];
 } __packed;
 
 /**
  * struct ubi_map_req - a data structure used in map LEB requests.
+ * @dtype: pass "3" for better compatibility with old kernels
  * @lnum: logical eraseblock number to unmap
- * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
  * @padding: reserved for future, not used, has to be zeroed
  */
 struct ubi_map_req {
 	__s32 lnum;
-	__s8  dtype;
+	__s8  dtype; /* obsolete, do not use! */
 	__s8  padding[3];
 } __packed;
 
diff --git a/include/net/sock.h b/include/net/sock.h
index da93155..d89f058 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -70,16 +70,16 @@
 struct cgroup;
 struct cgroup_subsys;
 #ifdef CONFIG_NET
-int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss);
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp);
+int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
+void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg);
 #else
 static inline
-int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
+int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
 {
 	return 0;
 }
 static inline
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp)
+void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
 {
 }
 #endif
@@ -914,9 +914,9 @@
 	 * This function has to setup any files the protocol want to
 	 * appear in the kmem cgroup filesystem.
 	 */
-	int			(*init_cgroup)(struct cgroup *cgrp,
+	int			(*init_cgroup)(struct mem_cgroup *memcg,
 					       struct cgroup_subsys *ss);
-	void			(*destroy_cgroup)(struct cgroup *cgrp);
+	void			(*destroy_cgroup)(struct mem_cgroup *memcg);
 	struct cg_proto		*(*proto_cgroup)(struct mem_cgroup *memcg);
 #endif
 };
diff --git a/include/net/tcp_memcontrol.h b/include/net/tcp_memcontrol.h
index 48410ff..7df18bc 100644
--- a/include/net/tcp_memcontrol.h
+++ b/include/net/tcp_memcontrol.h
@@ -12,8 +12,8 @@
 };
 
 struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg);
-int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss);
-void tcp_destroy_cgroup(struct cgroup *cgrp);
+int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
+void tcp_destroy_cgroup(struct mem_cgroup *memcg);
 unsigned long long tcp_max_memory(const struct mem_cgroup *memcg);
 void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx);
 #endif /* _TCP_MEMCG_H */
diff --git a/include/sound/asound.h b/include/sound/asound.h
index a2e4ff5..0876a1e 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -70,6 +70,20 @@
 
 /****************************************************************************
  *                                                                          *
+ *        CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort		    *
+ *                                                                          *
+ ****************************************************************************/
+
+struct snd_cea_861_aud_if {
+	unsigned char db1_ct_cc; /* coding type and channel count */
+	unsigned char db2_sf_ss; /* sample frequency and size */
+	unsigned char db3; /* not used, all zeros */
+	unsigned char db4_ca; /* channel allocation code */
+	unsigned char db5_dminh_lsv; /* downmix inhibit & level-shit values */
+};
+
+/****************************************************************************
+ *                                                                          *
  *      Section for driver hardware dependent interface - /dev/snd/hw?      *
  *                                                                          *
  ****************************************************************************/
diff --git a/include/sound/asoundef.h b/include/sound/asoundef.h
index 20ebf32..bb05c02 100644
--- a/include/sound/asoundef.h
+++ b/include/sound/asoundef.h
@@ -170,6 +170,47 @@
 #define IEC958_AES5_CON_CGMSA_COPYNOMORE (2<<0)	/* condition not be used */
 #define IEC958_AES5_CON_CGMSA_COPYNEVER	(3<<0)	/* no copying is permitted */
 
+/****************************************************************************
+ *                                                                          *
+ *        CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort		    *
+ *                                                                          *
+ ****************************************************************************/
+#define CEA861_AUDIO_INFOFRAME_DB1CC		(7<<0) /* mask - channel count */
+#define CEA861_AUDIO_INFOFRAME_DB1CT		(0xf<<4) /* mask - coding type */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM (0<<4) /* refer to stream */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_IEC60958	(1<<4) /* IEC-60958 L-PCM */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_AC3	(2<<4) /* AC-3 */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG1	(3<<4) /* MPEG1 Layers 1 & 2 */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MP3	(4<<4) /* MPEG1 Layer 3 */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG2_MULTICH (5<<4) /* MPEG2 Multichannel */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_AAC	(6<<4) /* AAC */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS	(7<<4) /* DTS */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_ATRAC	(8<<4) /* ATRAC */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_ONEBIT	(9<<4) /* One Bit Audio */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DOLBY_DIG_PLUS (10<<4) /* Dolby Digital + */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS_HD	(11<<4) /* DTS-HD */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MAT	(12<<4) /* MAT (MLP) */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DST	(13<<4) /* DST */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_WMA_PRO	(14<<4) /* WMA Pro */
+#define CEA861_AUDIO_INFOFRAME_DB2SF		(7<<2) /* mask - sample frequency */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM (0<<2) /* refer to stream */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_32000	(1<<2) /* 32kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_44100	(2<<2) /* 44.1kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_48000	(3<<2) /* 48kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_88200	(4<<2) /* 88.2kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_96000	(5<<2) /* 96kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_176400	(6<<2) /* 176.4kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_192000	(7<<2) /* 192kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SS		(3<<0) /* mask - sample size */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM (0<<0) /* refer to stream */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_16BIT	(1<<0) /* 16 bits */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_20BIT	(2<<0) /* 20 bits */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_24BIT	(3<<0) /* 24 bits */
+#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH	(1<<7) /* mask - inhibit downmixing */
+#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED (0<<7) /* stereo downmix permitted */
+#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED (1<<7) /* stereo downmis prohibited */
+#define CEA861_AUDIO_INFOFRAME_DB5_LSV		(0xf<<3) /* mask - level-shift values */
+
 /*****************************************************************************
  *                                                                           *
  *                            MIDI v1.0 interface                            *
diff --git a/include/sound/cs42l52.h b/include/sound/cs42l52.h
new file mode 100644
index 0000000..4c68955
--- /dev/null
+++ b/include/sound/cs42l52.h
@@ -0,0 +1,36 @@
+/*
+ * linux/sound/cs42l52.h -- Platform data for CS42L52
+ *
+ * Copyright (c) 2012 Cirrus Logic 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 __CS42L52_H
+#define __CS42L52_H
+
+struct cs42l52_platform_data {
+
+	/* MICBIAS Level. Check datasheet Pg48 */
+	unsigned int micbias_lvl;
+
+	/* MICA mode selection 0=Single 1=Differential */
+	unsigned int mica_cfg;
+
+	/* MICB mode selection 0=Single 1=Differential */
+	unsigned int micb_cfg;
+
+	/* MICA Select 0=MIC1A 1=MIC2A */
+	unsigned int mica_sel;
+
+	/* MICB Select 0=MIC2A 1=MIC2B */
+	unsigned int micb_sel;
+
+	/* Charge Pump Freq. Check datasheet Pg73 */
+	unsigned int chgfreq;
+
+};
+
+#endif /* __CS42L52_H */
diff --git a/include/sound/max98095.h b/include/sound/max98095.h
index 7513a42..e87ae67 100644
--- a/include/sound/max98095.h
+++ b/include/sound/max98095.h
@@ -49,6 +49,18 @@
 	 */
 	unsigned int digmic_left_mode:1;
 	unsigned int digmic_right_mode:1;
+
+	/* Pin5 is the mechanical method of sensing jack insertion
+	 * but it is something that might not be supported.
+	 * 0 = PIN5 not supported
+	 * 1 = PIN5 supported
+	 */
+	unsigned int jack_detect_pin5en:1;
+
+	/* Slew amount for jack detection. Calculated as 4 * (delay + 1).
+	 * Default delay is 24 to get a time of 100ms.
+	 */
+	unsigned int jack_detect_delay;
 };
 
 #endif
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h
index b457e87..9060103 100644
--- a/include/sound/sh_fsi.h
+++ b/include/sound/sh_fsi.h
@@ -21,10 +21,11 @@
 /*
  * flags format
  *
- * 0x000000BA
+ * 0x00000CBA
  *
  * A:  inversion
  * B:  format mode
+ * C:  chip specific
  */
 
 /* A: clock inversion */
@@ -39,6 +40,9 @@
 #define SH_FSI_FMT_DAI		(0 << 4)
 #define SH_FSI_FMT_SPDIF	(1 << 4)
 
+/* C: chip specific */
+#define SH_FSI_OPTION_MASK	0x00000F00
+#define SH_FSI_ENABLE_STREAM_MODE	(1 << 8) /* for 16bit data */
 
 /*
  * set_rate return value
@@ -84,16 +88,4 @@
 	struct sh_fsi_port_info port_b;
 };
 
-/*
- * for fsi-ak4642
- */
-struct fsi_ak4642_info {
-	const char *name;
-	const char *card;
-	const char *cpu_dai;
-	const char *codec;
-	const char *platform;
-	int id;
-};
-
 #endif /* __SOUND_FSI_H */
diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h
new file mode 100644
index 0000000..4b62b8d
--- /dev/null
+++ b/include/sound/simple_card.h
@@ -0,0 +1,38 @@
+/*
+ * ASoC simple sound card support
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 __SIMPLE_CARD_H
+#define __SIMPLE_CARD_H
+
+#include <sound/soc.h>
+
+struct asoc_simple_dai_init_info {
+	unsigned int fmt;
+	unsigned int cpu_daifmt;
+	unsigned int codec_daifmt;
+	unsigned int sysclk;
+};
+
+struct asoc_simple_card_info {
+	const char *name;
+	const char *card;
+	const char *cpu_dai;
+	const char *codec;
+	const char *platform;
+	const char *codec_dai;
+	struct asoc_simple_dai_init_info *init; /* for snd_link.init */
+
+	/* used in simple-card.c */
+	struct snd_soc_dai_link snd_link;
+	struct snd_soc_card snd_card;
+};
+
+#endif /* __SIMPLE_CARD_H */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index c429f24..1f69e0a 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -173,6 +173,8 @@
 		struct snd_soc_dai *);
 	int (*trigger)(struct snd_pcm_substream *, int,
 		struct snd_soc_dai *);
+	int (*bespoke_trigger)(struct snd_pcm_substream *, int,
+		struct snd_soc_dai *);
 	/*
 	 * For hardware based FIFO caused delay reporting.
 	 * Optional.
@@ -196,6 +198,7 @@
 	const char *name;
 	unsigned int id;
 	int ac97_control;
+	unsigned int base;
 
 	/* DAI driver callbacks */
 	int (*probe)(struct snd_soc_dai *dai);
@@ -241,6 +244,7 @@
 
 	struct snd_soc_dapm_widget *playback_widget;
 	struct snd_soc_dapm_widget *capture_widget;
+	struct snd_soc_dapm_context dapm;
 
 	/* DAI DMA data */
 	void *playback_dma_data;
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 8da3c24..e3833d9 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -141,10 +141,6 @@
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 	.invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
-#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
-{	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0, \
-	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
@@ -324,6 +320,8 @@
 struct snd_soc_dapm_pin;
 struct snd_soc_dapm_route;
 struct snd_soc_dapm_context;
+struct regulator;
+struct snd_soc_dapm_widget_list;
 
 int dapm_reg_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event);
@@ -359,6 +357,10 @@
 int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
 				 struct snd_soc_dai *dai);
 int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
+int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
+			 const struct snd_soc_pcm_stream *params,
+			 struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink);
 
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
@@ -369,8 +371,8 @@
 			     const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
-			      struct snd_soc_dai *dai, int event);
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+	int event);
 void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* external DAPM widget events */
@@ -402,6 +404,10 @@
 /* Mostly internal - should not normally be used */
 void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
 
+/* dapm path query */
+int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
+	struct snd_soc_dapm_widget_list **list);
+
 /* dapm widget types */
 enum snd_soc_dapm_type {
 	snd_soc_dapm_input = 0,		/* input pin */
@@ -430,6 +436,12 @@
 	snd_soc_dapm_aif_out,		/* audio interface output */
 	snd_soc_dapm_siggen,		/* signal generator */
 	snd_soc_dapm_dai,		/* link to DAI structure */
+	snd_soc_dapm_dai_link,		/* link between two DAI structures */
+};
+
+enum snd_soc_dapm_subclass {
+	SND_SOC_DAPM_CLASS_INIT		= 0,
+	SND_SOC_DAPM_CLASS_RUNTIME	= 1,
 };
 
 /*
@@ -482,9 +494,11 @@
 	struct snd_soc_dapm_context *dapm;
 
 	void *priv;				/* widget specific data */
+	struct regulator *regulator;		/* attached regulator */
+	const struct snd_soc_pcm_stream *params; /* params for dai links */
 
 	/* dapm control */
-	short reg;						/* negative reg = no direct dapm */
+	int reg;				/* negative reg = no direct dapm */
 	unsigned char shift;			/* bits to shift */
 	unsigned int saved_value;		/* widget saved value */
 	unsigned int value;				/* widget current value */
diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
new file mode 100644
index 0000000..04598f1
--- /dev/null
+++ b/include/sound/soc-dpcm.h
@@ -0,0 +1,138 @@
+/*
+ * linux/sound/soc-dpcm.h -- ALSA SoC Dynamic PCM Support
+ *
+ * Author:		Liam Girdwood <lrg@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.
+ */
+
+#ifndef __LINUX_SND_SOC_DPCM_H
+#define __LINUX_SND_SOC_DPCM_H
+
+#include <linux/list.h>
+#include <sound/pcm.h>
+
+struct snd_soc_pcm_runtime;
+
+/*
+ * Types of runtime_update to perform. e.g. originated from FE PCM ops
+ * or audio route changes triggered by muxes/mixers.
+ */
+enum snd_soc_dpcm_update {
+	SND_SOC_DPCM_UPDATE_NO	= 0,
+	SND_SOC_DPCM_UPDATE_BE,
+	SND_SOC_DPCM_UPDATE_FE,
+};
+
+/*
+ * Dynamic PCM Frontend -> Backend link management states.
+ */
+enum snd_soc_dpcm_link_state {
+	SND_SOC_DPCM_LINK_STATE_NEW	= 0,	/* newly created link */
+	SND_SOC_DPCM_LINK_STATE_FREE,		/* link to be dismantled */
+};
+
+/*
+ * Dynamic PCM Frontend -> Backend link PCM states.
+ */
+enum snd_soc_dpcm_state {
+	SND_SOC_DPCM_STATE_NEW	= 0,
+	SND_SOC_DPCM_STATE_OPEN,
+	SND_SOC_DPCM_STATE_HW_PARAMS,
+	SND_SOC_DPCM_STATE_PREPARE,
+	SND_SOC_DPCM_STATE_START,
+	SND_SOC_DPCM_STATE_STOP,
+	SND_SOC_DPCM_STATE_PAUSED,
+	SND_SOC_DPCM_STATE_SUSPEND,
+	SND_SOC_DPCM_STATE_HW_FREE,
+	SND_SOC_DPCM_STATE_CLOSE,
+};
+
+/*
+ * Dynamic PCM trigger ordering. Triggering flexibility is required as some
+ * DSPs require triggering before/after their CPU platform and DAIs.
+ *
+ * i.e. some clients may want to manually order this call in their PCM
+ * trigger() whilst others will just use the regular core ordering.
+ */
+enum snd_soc_dpcm_trigger {
+	SND_SOC_DPCM_TRIGGER_PRE		= 0,
+	SND_SOC_DPCM_TRIGGER_POST,
+	SND_SOC_DPCM_TRIGGER_BESPOKE,
+};
+
+/*
+ * Dynamic PCM link
+ * This links together a FE and BE DAI at runtime and stores the link
+ * state information and the hw_params configuration.
+ */
+struct snd_soc_dpcm {
+	/* FE and BE DAIs*/
+	struct snd_soc_pcm_runtime *be;
+	struct snd_soc_pcm_runtime *fe;
+
+	/* link state */
+	enum snd_soc_dpcm_link_state state;
+
+	/* list of BE and FE for this DPCM link */
+	struct list_head list_be;
+	struct list_head list_fe;
+
+	/* hw params for this link - may be different for each link */
+	struct snd_pcm_hw_params hw_params;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_state;
+#endif
+};
+
+/*
+ * Dynamic PCM runtime data.
+ */
+struct snd_soc_dpcm_runtime {
+	struct list_head be_clients;
+	struct list_head fe_clients;
+
+	int users;
+	struct snd_pcm_runtime *runtime;
+	struct snd_pcm_hw_params hw_params;
+
+	/* state and update */
+	enum snd_soc_dpcm_update runtime_update;
+	enum snd_soc_dpcm_state state;
+};
+
+/* can this BE stop and free */
+int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
+		struct snd_soc_pcm_runtime *be, int stream);
+
+/* can this BE perform a hw_params() */
+int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
+		struct snd_soc_pcm_runtime *be, int stream);
+
+/* is the current PCM operation for this FE ? */
+int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream);
+
+/* is the current PCM operation for this BE ? */
+int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
+		struct snd_soc_pcm_runtime *be, int stream);
+
+/* get the substream for this BE */
+struct snd_pcm_substream *
+	snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream);
+
+/* get the BE runtime state */
+enum snd_soc_dpcm_state
+	snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream);
+
+/* set the BE runtime state */
+void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
+	enum snd_soc_dpcm_state state);
+
+/* internal use only */
+int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
+int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
+int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *);
+
+#endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 2ebf787..c703871 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -55,6 +55,18 @@
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
 	.put = snd_soc_put_volsw, \
 	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \
+{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+	SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p  = (tlv_array),\
+	.info = snd_soc_info_volsw, \
+	.get = snd_soc_get_volsw_sx,\
+	.put = snd_soc_put_volsw_sx, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .rreg = xreg, \
+		.shift = xshift, .rshift = xshift, \
+		.max = xmax, .min = xmin} }
 #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
@@ -85,6 +97,18 @@
 	.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
 	.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
 					    xmax, xinvert) }
+#define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \
+{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+	SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p  = (tlv_array), \
+	.info = snd_soc_info_volsw, \
+	.get = snd_soc_get_volsw_sx, \
+	.put = snd_soc_put_volsw_sx, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .rreg = xrreg, \
+		.shift = xshift, .rshift = xshift, \
+		.max = xmax, .min = xmin} }
 #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
 {	.iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@@ -171,20 +195,6 @@
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = (unsigned long)&xenum }
 
-#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\
-		xmin, xmax, tlv_array) \
-{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
-		  SNDRV_CTL_ELEM_ACCESS_READWRITE, \
-	.tlv.p = (tlv_array), \
-	.info = snd_soc_info_volsw_2r_sx, \
-	.get = snd_soc_get_volsw_2r_sx, \
-	.put = snd_soc_put_volsw_2r_sx, \
-	.private_value = (unsigned long)&(struct soc_mixer_control) \
-		{.reg = xreg_left, \
-		 .rreg = xreg_right, .shift = xshift, \
-		 .min = xmin, .max = xmax} }
-
 #define SND_SOC_BYTES(xname, xbase, xregs)		      \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,   \
 	.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
@@ -200,6 +210,19 @@
 		{.base = xbase, .num_regs = xregs,	      \
 		 .mask = xmask }) }
 
+#define SOC_SINGLE_XR_SX(xname, xregbase, xregcount, xnbits, \
+		xmin, xmax, xinvert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = snd_soc_info_xr_sx, .get = snd_soc_get_xr_sx, \
+	.put = snd_soc_put_xr_sx, \
+	.private_value = (unsigned long)&(struct soc_mreg_control) \
+		{.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \
+		.invert = xinvert, .min = xmin, .max = xmax} }
+
+#define SOC_SINGLE_STROBE(xname, xreg, xshift, xinvert) \
+	SOC_SINGLE_EXT(xname, xreg, xshift, 1, xinvert, \
+		snd_soc_get_strobe, snd_soc_put_strobe)
+
 /*
  * Simplified versions of above macros, declaring a struct and calculating
  * ARRAY_SIZE internally
@@ -264,6 +287,7 @@
 struct snd_soc_jack_pin;
 struct snd_soc_cache_ops;
 #include <sound/soc-dapm.h>
+#include <sound/soc-dpcm.h>
 
 #ifdef CONFIG_GPIOLIB
 struct snd_soc_jack_gpio;
@@ -288,6 +312,11 @@
 	SND_SOC_PCM_CLASS_BE	= 1,
 };
 
+enum snd_soc_card_subclass {
+	SND_SOC_CARD_CLASS_INIT		= 0,
+	SND_SOC_CARD_CLASS_RUNTIME	= 1,
+};
+
 int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 			     int source, unsigned int freq, int dir);
 int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
@@ -333,6 +362,11 @@
 					unsigned int reg, unsigned int val);
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
 
+struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
+		const char *dai_link, int stream);
+struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
+		const char *dai_link);
+
 /* 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);
@@ -343,6 +377,9 @@
 int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
 	const struct snd_pcm_hardware *hw);
 
+int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
+		int cmd, struct snd_soc_platform *platform);
+
 /* Jack reporting */
 int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
 		     struct snd_soc_jack *jack);
@@ -413,6 +450,10 @@
 	struct snd_ctl_elem_value *ucontrol);
 #define snd_soc_get_volsw_2r snd_soc_get_volsw
 #define snd_soc_put_volsw_2r snd_soc_put_volsw
+int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo);
 int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
@@ -421,19 +462,22 @@
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_limit_volume(struct snd_soc_codec *codec,
 	const char *name, int max);
-int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_info *uinfo);
-int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol);
-int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_info *uinfo);
 int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
 		      struct snd_ctl_elem_value *ucontrol);
 int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
 		      struct snd_ctl_elem_value *ucontrol);
-
+int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
 
 /**
  * struct snd_soc_reg_access - Describes whether a given register is
@@ -513,6 +557,7 @@
 #endif
 
 struct snd_soc_jack {
+	struct mutex mutex;
 	struct snd_jack *jack;
 	struct snd_soc_codec *codec;
 	struct list_head pins;
@@ -711,6 +756,7 @@
 	/* platform IO - used for platform DAPM */
 	unsigned int (*read)(struct snd_soc_platform *, unsigned int);
 	int (*write)(struct snd_soc_platform *, unsigned int, unsigned int);
+	int (*bespoke_trigger)(struct snd_pcm_substream *, int);
 };
 
 struct snd_soc_platform {
@@ -746,21 +792,36 @@
 	const char *cpu_dai_name;
 	const struct device_node *cpu_dai_of_node;
 	const char *codec_dai_name;
+	int be_id;	/* optional ID for machine driver BE identification */
+
+	const struct snd_soc_pcm_stream *params;
 
 	unsigned int dai_fmt;           /* format to set on init */
 
+	enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
+
 	/* Keep DAI active over suspend */
 	unsigned int ignore_suspend:1;
 
 	/* Symmetry requirements */
 	unsigned int symmetric_rates:1;
 
+	/* Do not create a PCM for this DAI link (Backend link) */
+	unsigned int no_pcm:1;
+
+	/* This DAI link can route to other DAI links at runtime (Frontend)*/
+	unsigned int dynamic:1;
+
 	/* pmdown_time is ignored at stop */
 	unsigned int ignore_pmdown_time:1;
 
 	/* codec/machine specific init - e.g. add machine controls */
 	int (*init)(struct snd_soc_pcm_runtime *rtd);
 
+	/* optional hw_params re-writing for BE and FE sync */
+	int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params);
+
 	/* machine stream operations */
 	struct snd_soc_ops *ops;
 };
@@ -800,6 +861,7 @@
 
 	struct list_head list;
 	struct mutex mutex;
+	struct mutex dapm_mutex;
 
 	bool instantiated;
 
@@ -889,9 +951,11 @@
 	enum snd_soc_pcm_subclass pcm_subclass;
 	struct snd_pcm_ops ops;
 
-	unsigned int complete:1;
 	unsigned int dev_registered:1;
 
+	/* Dynamic PCM BE runtime data */
+	struct snd_soc_dpcm_runtime dpcm[2];
+
 	long pmdown_time;
 
 	/* runtime devices */
@@ -902,6 +966,10 @@
 	struct snd_soc_dai *cpu_dai;
 
 	struct delayed_work delayed_work;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_dpcm_root;
+	struct dentry *debugfs_dpcm_state;
+#endif
 };
 
 /* mixer control */
@@ -916,6 +984,12 @@
 	u32 mask;
 };
 
+/* multi register control */
+struct soc_mreg_control {
+	long min, max;
+	unsigned int regbase, regcount, nbits, invert;
+};
+
 /* enumerated kcontrol */
 struct soc_enum {
 	unsigned short reg;
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h
index ab26f8a..5fc2dcd 100644
--- a/include/trace/events/asoc.h
+++ b/include/trace/events/asoc.h
@@ -7,6 +7,8 @@
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
 
+#define DAPM_DIRECT "(direct)"
+
 struct snd_soc_jack;
 struct snd_soc_codec;
 struct snd_soc_platform;
@@ -241,6 +243,84 @@
 		  (int)__entry->path_checks, (int)__entry->neighbour_checks)
 );
 
+TRACE_EVENT(snd_soc_dapm_output_path,
+
+	TP_PROTO(struct snd_soc_dapm_widget *widget,
+		struct snd_soc_dapm_path *path),
+
+	TP_ARGS(widget, path),
+
+	TP_STRUCT__entry(
+		__string(	wname,	widget->name		)
+		__string(	pname,	path->name ? path->name : DAPM_DIRECT)
+		__string(	psname,	path->sink->name	)
+		__field(	int,	path_sink		)
+		__field(	int,	path_connect		)
+	),
+
+	TP_fast_assign(
+		__assign_str(wname, widget->name);
+		__assign_str(pname, path->name ? path->name : DAPM_DIRECT);
+		__assign_str(psname, path->sink->name);
+		__entry->path_connect = path->connect;
+		__entry->path_sink = (long)path->sink;
+	),
+
+	TP_printk("%c%s -> %s -> %s\n",
+		(int) __entry->path_sink &&
+		(int) __entry->path_connect ? '*' : ' ',
+		__get_str(wname), __get_str(pname), __get_str(psname))
+);
+
+TRACE_EVENT(snd_soc_dapm_input_path,
+
+	TP_PROTO(struct snd_soc_dapm_widget *widget,
+		struct snd_soc_dapm_path *path),
+
+	TP_ARGS(widget, path),
+
+	TP_STRUCT__entry(
+		__string(	wname,	widget->name		)
+		__string(	pname,	path->name ? path->name : DAPM_DIRECT)
+		__string(	psname,	path->source->name	)
+		__field(	int,	path_source		)
+		__field(	int,	path_connect		)
+	),
+
+	TP_fast_assign(
+		__assign_str(wname, widget->name);
+		__assign_str(pname, path->name ? path->name : DAPM_DIRECT);
+		__assign_str(psname, path->source->name);
+		__entry->path_connect = path->connect;
+		__entry->path_source = (long)path->source;
+	),
+
+	TP_printk("%c%s <- %s <- %s\n",
+		(int) __entry->path_source &&
+		(int) __entry->path_connect ? '*' : ' ',
+		__get_str(wname), __get_str(pname), __get_str(psname))
+);
+
+TRACE_EVENT(snd_soc_dapm_connected,
+
+	TP_PROTO(int paths, int stream),
+
+	TP_ARGS(paths, stream),
+
+	TP_STRUCT__entry(
+		__field(	int,	paths		)
+		__field(	int,	stream		)
+	),
+
+	TP_fast_assign(
+		__entry->paths = paths;
+		__entry->stream = stream;
+	),
+
+	TP_printk("%s: found %d paths\n",
+		__entry->stream ? "capture" : "playback", __entry->paths)
+);
+
 TRACE_EVENT(snd_soc_jack_irq,
 
 	TP_PROTO(const char *name),
diff --git a/include/trace/events/ext3.h b/include/trace/events/ext3.h
index 7b53c05..15d11a3 100644
--- a/include/trace/events/ext3.h
+++ b/include/trace/events/ext3.h
@@ -24,8 +24,8 @@
 		__entry->dev	= inode->i_sb->s_dev;
 		__entry->ino	= inode->i_ino;
 		__entry->mode	= inode->i_mode;
-		__entry->uid	= inode->i_uid;
-		__entry->gid	= inode->i_gid;
+		__entry->uid	= i_uid_read(inode);
+		__entry->gid	= i_gid_read(inode);
 		__entry->blocks	= inode->i_blocks;
 	),
 
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index 319538b..69d8a69 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -36,8 +36,8 @@
 		__entry->dev	= inode->i_sb->s_dev;
 		__entry->ino	= inode->i_ino;
 		__entry->mode	= inode->i_mode;
-		__entry->uid	= inode->i_uid;
-		__entry->gid	= inode->i_gid;
+		__entry->uid	= i_uid_read(inode);
+		__entry->gid	= i_gid_read(inode);
 		__entry->blocks	= inode->i_blocks;
 	),
 
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index cae9a94..0c978384 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -65,6 +65,40 @@
 	TP_printk("state=%lu", (unsigned long)__entry->state)
 );
 
+DECLARE_EVENT_CLASS(wakeup_source,
+
+	TP_PROTO(const char *name, unsigned int state),
+
+	TP_ARGS(name, state),
+
+	TP_STRUCT__entry(
+		__string(       name,           name            )
+		__field(        u64,            state           )
+	),
+
+	TP_fast_assign(
+		__assign_str(name, name);
+		__entry->state = state;
+	),
+
+	TP_printk("%s state=0x%lx", __get_str(name),
+		(unsigned long)__entry->state)
+);
+
+DEFINE_EVENT(wakeup_source, wakeup_source_activate,
+
+	TP_PROTO(const char *name, unsigned int state),
+
+	TP_ARGS(name, state)
+);
+
+DEFINE_EVENT(wakeup_source, wakeup_source_deactivate,
+
+	TP_PROTO(const char *name, unsigned int state),
+
+	TP_ARGS(name, state)
+);
+
 #ifdef CONFIG_EVENT_POWER_TRACING_DEPRECATED
 
 /*
diff --git a/include/trace/events/workqueue.h b/include/trace/events/workqueue.h
index 7d49729..4018f50 100644
--- a/include/trace/events/workqueue.h
+++ b/include/trace/events/workqueue.h
@@ -103,7 +103,7 @@
 );
 
 /**
- * workqueue_execute_end - called immediately before the workqueue callback
+ * workqueue_execute_end - called immediately after the workqueue callback
  * @work:	pointer to struct work_struct
  *
  * Allows to track workqueue execution.
diff --git a/include/video/omap-panel-dvi.h b/include/video/omap-panel-dvi.h
deleted file mode 100644
index 87ad567b..0000000
--- a/include/video/omap-panel-dvi.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Header for DVI output driver
- *
- * Copyright (C) 2011 Texas Instruments Inc
- * Author: Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __OMAP_PANEL_DVI_H
-#define __OMAP_PANEL_DVI_H
-
-struct omap_dss_device;
-
-/**
- * struct panel_dvi_platform_data - panel driver configuration data
- * @platform_enable: platform specific panel enable function
- * @platform_disable: platform specific panel disable function
- * @i2c_bus_num: i2c bus id for the panel
- */
-struct panel_dvi_platform_data {
-	int (*platform_enable)(struct omap_dss_device *dssdev);
-	void (*platform_disable)(struct omap_dss_device *dssdev);
-	u16 i2c_bus_num;
-};
-
-#endif /* __OMAP_PANEL_DVI_H */
diff --git a/include/video/omap-panel-nokia-dsi.h b/include/video/omap-panel-nokia-dsi.h
index 7dc71f9..04219a2 100644
--- a/include/video/omap-panel-nokia-dsi.h
+++ b/include/video/omap-panel-nokia-dsi.h
@@ -11,6 +11,7 @@
  * @esd_interval: interval of ESD checks, 0 = disabled (ms)
  * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
  * @use_dsi_backlight: true if panel uses DSI command to control backlight
+ * @pin_config: DSI pin configuration
  */
 struct nokia_dsi_panel_data {
 	const char *name;
@@ -24,6 +25,8 @@
 	unsigned ulps_timeout;
 
 	bool use_dsi_backlight;
+
+	struct omap_dsi_pin_config pin_config;
 };
 
 #endif /* __OMAP_NOKIA_DSI_PANEL_H */
diff --git a/include/video/omap-panel-tfp410.h b/include/video/omap-panel-tfp410.h
new file mode 100644
index 0000000..68c31d7
--- /dev/null
+++ b/include/video/omap-panel-tfp410.h
@@ -0,0 +1,35 @@
+/*
+ * Header for TFP410 chip driver
+ *
+ * Copyright (C) 2011 Texas Instruments Inc
+ * Author: Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP_PANEL_TFP410_H
+#define __OMAP_PANEL_TFP410_H
+
+struct omap_dss_device;
+
+/**
+ * struct tfp410_platform_data - panel driver configuration data
+ * @i2c_bus_num: i2c bus id for the panel
+ * @power_down_gpio: gpio number for PD pin (or -1 if not available)
+ */
+struct tfp410_platform_data {
+	u16 i2c_bus_num;
+	int power_down_gpio;
+};
+
+#endif /* __OMAP_PANEL_TFP410_H */
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 483f67c..1c46a14 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -468,6 +468,21 @@
 	int (*wait_for_vsync)(struct omap_overlay_manager *mgr);
 };
 
+/* 22 pins means 1 clk lane and 10 data lanes */
+#define OMAP_DSS_MAX_DSI_PINS 22
+
+struct omap_dsi_pin_config {
+	int num_pins;
+	/*
+	 * pin numbers in the following order:
+	 * clk+, clk-
+	 * data1+, data1-
+	 * data2+, data2-
+	 * ...
+	 */
+	int pins[OMAP_DSS_MAX_DSI_PINS];
+};
+
 struct omap_dss_device {
 	struct device dev;
 
@@ -490,17 +505,6 @@
 		} sdi;
 
 		struct {
-			u8 clk_lane;
-			u8 clk_pol;
-			u8 data1_lane;
-			u8 data1_pol;
-			u8 data2_lane;
-			u8 data2_pol;
-			u8 data3_lane;
-			u8 data3_pol;
-			u8 data4_lane;
-			u8 data4_pol;
-
 			int module;
 
 			bool ext_te;
@@ -687,6 +691,8 @@
 int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel);
 int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id);
 void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel);
+int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
+		const struct omap_dsi_pin_config *pin_cfg);
 
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
diff --git a/init/Kconfig b/init/Kconfig
index 6d18ef8..ccb5248 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -27,6 +27,9 @@
 	bool
 	depends on HAVE_IRQ_WORK
 
+config BUILDTIME_EXTABLE_SORT
+	bool
+
 menu "General setup"
 
 config EXPERIMENTAL
@@ -870,7 +873,10 @@
 config USER_NS
 	bool "User namespace (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
-	default y
+	depends on UIDGID_CONVERTED
+	select UIDGID_STRICT_TYPE_CHECKS
+
+	default n
 	help
 	  This allows containers, i.e. vservers, to use user namespaces
 	  to provide different user info for different servers.
@@ -894,6 +900,131 @@
 
 endif # NAMESPACES
 
+config UIDGID_CONVERTED
+	# True if all of the selected software conmponents are known
+	# to have uid_t and gid_t converted to kuid_t and kgid_t
+	# where appropriate and are otherwise safe to use with
+	# the user namespace.
+	bool
+	default y
+
+	# List of kernel pieces that need user namespace work
+	# Features
+	depends on SYSVIPC = n
+	depends on IMA = n
+	depends on EVM = n
+	depends on KEYS = n
+	depends on AUDIT = n
+	depends on AUDITSYSCALL = n
+	depends on TASKSTATS = n
+	depends on TRACING = n
+	depends on FS_POSIX_ACL = n
+	depends on QUOTA = n
+	depends on QUOTACTL = n
+	depends on DEBUG_CREDENTIALS = n
+	depends on BSD_PROCESS_ACCT = n
+	depends on DRM = n
+	depends on PROC_EVENTS = n
+
+	# Networking
+	depends on NET = n
+	depends on NET_9P = n
+	depends on IPX = n
+	depends on PHONET = n
+	depends on NET_CLS_FLOW = n
+	depends on NETFILTER_XT_MATCH_OWNER = n
+	depends on NETFILTER_XT_MATCH_RECENT = n
+	depends on NETFILTER_XT_TARGET_LOG = n
+	depends on NETFILTER_NETLINK_LOG = n
+	depends on INET = n
+	depends on IPV6 = n
+	depends on IP_SCTP = n
+	depends on AF_RXRPC = n
+	depends on LLC2 = n
+	depends on NET_KEY = n
+	depends on INET_DIAG = n
+	depends on DNS_RESOLVER = n
+	depends on AX25 = n
+	depends on ATALK = n
+
+	# Filesystems
+	depends on USB_DEVICEFS = n
+	depends on USB_GADGETFS = n
+	depends on USB_FUNCTIONFS = n
+	depends on DEVTMPFS = n
+	depends on XENFS = n
+
+	depends on 9P_FS = n
+	depends on ADFS_FS = n
+	depends on AFFS_FS = n
+	depends on AFS_FS = n
+	depends on AUTOFS4_FS = n
+	depends on BEFS_FS = n
+	depends on BFS_FS = n
+	depends on BTRFS_FS = n
+	depends on CEPH_FS = n
+	depends on CIFS = n
+	depends on CODA_FS = n
+	depends on CONFIGFS_FS = n
+	depends on CRAMFS = n
+	depends on DEBUG_FS = n
+	depends on ECRYPT_FS = n
+	depends on EFS_FS = n
+	depends on EXOFS_FS = n
+	depends on FAT_FS = n
+	depends on FUSE_FS = n
+	depends on GFS2_FS = n
+	depends on HFS_FS = n
+	depends on HFSPLUS_FS = n
+	depends on HPFS_FS = n
+	depends on HUGETLBFS = n
+	depends on ISO9660_FS = n
+	depends on JFFS2_FS = n
+	depends on JFS_FS = n
+	depends on LOGFS = n
+	depends on MINIX_FS = n
+	depends on NCP_FS = n
+	depends on NFSD = n
+	depends on NFS_FS = n
+	depends on NILFS2_FS = n
+	depends on NTFS_FS = n
+	depends on OCFS2_FS = n
+	depends on OMFS_FS = n
+	depends on QNX4FS_FS = n
+	depends on QNX6FS_FS = n
+	depends on REISERFS_FS = n
+	depends on SQUASHFS = n
+	depends on SYSV_FS = n
+	depends on UBIFS_FS = n
+	depends on UDF_FS = n
+	depends on UFS_FS = n
+	depends on VXFS_FS = n
+	depends on XFS_FS = n
+
+	depends on !UML || HOSTFS = n
+
+	# The rare drivers that won't build
+	depends on AIRO = n
+	depends on AIRO_CS = n
+	depends on TUN = n
+	depends on INFINIBAND_QIB = n
+	depends on BLK_DEV_LOOP = n
+	depends on ANDROID_BINDER_IPC = n
+
+	# Security modules
+	depends on SECURITY_TOMOYO = n
+	depends on SECURITY_APPARMOR = n
+
+config UIDGID_STRICT_TYPE_CHECKS
+	bool "Require conversions between uid/gids and their internal representation"
+	depends on UIDGID_CONVERTED
+	default n
+	help
+	 While the nececessary conversions are being added to all subsystems this option allows
+	 the code to continue to build for unconverted subsystems.
+
+	 Say Y here if you want the strict type checking enabled
+
 config SCHED_AUTOGROUP
 	bool "Automatic process group scheduling"
 	select EVENTFD
@@ -1198,7 +1329,7 @@
 
 config PERF_EVENTS
 	bool "Kernel performance events and counters"
-	default y if (PROFILING || PERF_COUNTERS)
+	default y if PROFILING
 	depends on HAVE_PERF_EVENTS
 	select ANON_INODES
 	select IRQ_WORK
@@ -1225,18 +1356,6 @@
 
 	  Say Y if unsure.
 
-config PERF_COUNTERS
-	bool "Kernel performance counters (old config option)"
-	depends on HAVE_PERF_EVENTS
-	help
-	  This config has been obsoleted by the PERF_EVENTS
-	  config option - please see that one for details.
-
-	  It has no effect on the kernel whether you enable
-	  it or not, it is a compatibility placeholder.
-
-	  Say N if unsure.
-
 config DEBUG_PERF_USE_VMALLOC
 	default n
 	bool "Debug: use vmalloc to back perf mmap() buffers"
diff --git a/init/main.c b/init/main.c
index cb54cd3..1ca6b32 100644
--- a/init/main.c
+++ b/init/main.c
@@ -226,7 +226,7 @@
 early_param("loglevel", loglevel);
 
 /* Change NUL term back to "=", to make "param" the whole string. */
-static int __init repair_env_string(char *param, char *val)
+static int __init repair_env_string(char *param, char *val, const char *unused)
 {
 	if (val) {
 		/* param=val or param="val"? */
@@ -246,9 +246,9 @@
  * Unknown boot options get handed to init, unless they look like
  * unused parameters (modprobe will find them in /proc/cmdline).
  */
-static int __init unknown_bootoption(char *param, char *val)
+static int __init unknown_bootoption(char *param, char *val, const char *unused)
 {
-	repair_env_string(param, val);
+	repair_env_string(param, val, unused);
 
 	/* Handle obsolete-style parameters */
 	if (obsolete_checksetup(param))
@@ -385,7 +385,7 @@
 }
 
 /* Check for early params. */
-static int __init do_early_param(char *param, char *val)
+static int __init do_early_param(char *param, char *val, const char *unused)
 {
 	const struct obs_kernel_param *p;
 
@@ -725,14 +725,14 @@
 };
 
 static char *initcall_level_names[] __initdata = {
-	"early parameters",
-	"core parameters",
-	"postcore parameters",
-	"arch parameters",
-	"subsys parameters",
-	"fs parameters",
-	"device parameters",
-	"late parameters",
+	"early",
+	"core",
+	"postcore",
+	"arch",
+	"subsys",
+	"fs",
+	"device",
+	"late",
 };
 
 static void __init do_initcall_level(int level)
@@ -745,7 +745,7 @@
 		   static_command_line, __start___param,
 		   __stop___param - __start___param,
 		   level, level,
-		   repair_env_string);
+		   &repair_env_string);
 
 	for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
 		do_one_initcall(*fn);
@@ -755,8 +755,13 @@
 {
 	int level;
 
-	for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
+	for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) {
+		pr_info("initlevel:%d=%s, %d registered initcalls\n",
+			level, initcall_level_names[level],
+			(int) (initcall_levels[level+1]
+				- initcall_levels[level]));
 		do_initcall_level(level);
+	}
 }
 
 /*
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 28bd64d..b6a0d46 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -66,6 +66,7 @@
 
 	struct sigevent notify;
 	struct pid* notify_owner;
+	struct user_namespace *notify_user_ns;
 	struct user_struct *user;	/* user who created, for accounting */
 	struct sock *notify_sock;
 	struct sk_buff *notify_cookie;
@@ -139,6 +140,7 @@
 		INIT_LIST_HEAD(&info->e_wait_q[0].list);
 		INIT_LIST_HEAD(&info->e_wait_q[1].list);
 		info->notify_owner = NULL;
+		info->notify_user_ns = NULL;
 		info->qsize = 0;
 		info->user = NULL;	/* set when all is ok */
 		memset(&info->attr, 0, sizeof(info->attr));
@@ -536,8 +538,7 @@
 			rcu_read_lock();
 			sig_i.si_pid = task_tgid_nr_ns(current,
 						ns_of_pid(info->notify_owner));
-			sig_i.si_uid = user_ns_map_uid(info->user->user_ns,
-						current_cred(), current_uid());
+			sig_i.si_uid = from_kuid_munged(info->notify_user_ns, current_uid());
 			rcu_read_unlock();
 
 			kill_pid_info(info->notify.sigev_signo,
@@ -550,7 +551,9 @@
 		}
 		/* after notification unregisters process */
 		put_pid(info->notify_owner);
+		put_user_ns(info->notify_user_ns);
 		info->notify_owner = NULL;
+		info->notify_user_ns = NULL;
 	}
 	wake_up(&info->wait_q);
 }
@@ -575,7 +578,9 @@
 		netlink_sendskb(info->notify_sock, info->notify_cookie);
 	}
 	put_pid(info->notify_owner);
+	put_user_ns(info->notify_user_ns);
 	info->notify_owner = NULL;
+	info->notify_user_ns = NULL;
 }
 
 static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
@@ -1140,6 +1145,7 @@
 		}
 
 		info->notify_owner = get_pid(task_tgid(current));
+		info->notify_user_ns = get_user_ns(current_user_ns());
 		inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	}
 	spin_unlock(&info->lock);
diff --git a/ipc/namespace.c b/ipc/namespace.c
index ce0a647..f362298c 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -46,7 +46,7 @@
 	ipcns_notify(IPCNS_CREATED);
 	register_ipcns_notifier(ns);
 
-	ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
+	ns->user_ns = get_user_ns(task_cred_xxx(tsk, user_ns));
 
 	return ns;
 }
diff --git a/kernel/capability.c b/kernel/capability.c
index 3f1adb6..493d972 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -419,3 +419,24 @@
 {
 	return ns_capable(current_user_ns(), cap);
 }
+
+/**
+ * inode_capable - Check superior capability over inode
+ * @inode: The inode in question
+ * @cap: The capability in question
+ *
+ * Return true if the current task has the given superior capability
+ * targeted at it's own user namespace and that the given inode is owned
+ * by the current user namespace or a child namespace.
+ *
+ * Currently we check to see if an inode is owned by the current
+ * user namespace by seeing if the inode's owner maps into the
+ * current user namespace.
+ *
+ */
+bool inode_capable(const struct inode *inode, int cap)
+{
+	struct user_namespace *ns = current_user_ns();
+
+	return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid);
+}
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index ed64cca..a0c6af3 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -60,9 +60,13 @@
 #include <linux/eventfd.h>
 #include <linux/poll.h>
 #include <linux/flex_array.h> /* used in cgroup_attach_proc */
+#include <linux/kthread.h>
 
 #include <linux/atomic.h>
 
+/* css deactivation bias, makes css->refcnt negative to deny new trygets */
+#define CSS_DEACT_BIAS		INT_MIN
+
 /*
  * cgroup_mutex is the master lock.  Any modification to cgroup or its
  * hierarchy must be performed while holding it.
@@ -127,6 +131,9 @@
 	/* A list running through the active hierarchies */
 	struct list_head root_list;
 
+	/* All cgroups on this root, cgroup_mutex protected */
+	struct list_head allcg_list;
+
 	/* Hierarchy-specific flags */
 	unsigned long flags;
 
@@ -145,6 +152,15 @@
 static struct cgroupfs_root rootnode;
 
 /*
+ * cgroupfs file entry, pointed to from leaf dentry->d_fsdata.
+ */
+struct cfent {
+	struct list_head		node;
+	struct dentry			*dentry;
+	struct cftype			*type;
+};
+
+/*
  * CSS ID -- ID per subsys's Cgroup Subsys State(CSS). used only when
  * cgroup_subsys->use_id != 0.
  */
@@ -239,6 +255,14 @@
 
 EXPORT_SYMBOL_GPL(cgroup_lock_is_held);
 
+/* the current nr of refs, always >= 0 whether @css is deactivated or not */
+static int css_refcnt(struct cgroup_subsys_state *css)
+{
+	int v = atomic_read(&css->refcnt);
+
+	return v >= 0 ? v : v - CSS_DEACT_BIAS;
+}
+
 /* convenient tests for these bits */
 inline int cgroup_is_removed(const struct cgroup *cgrp)
 {
@@ -279,6 +303,21 @@
 #define for_each_active_root(_root) \
 list_for_each_entry(_root, &roots, root_list)
 
+static inline struct cgroup *__d_cgrp(struct dentry *dentry)
+{
+	return dentry->d_fsdata;
+}
+
+static inline struct cfent *__d_cfe(struct dentry *dentry)
+{
+	return dentry->d_fsdata;
+}
+
+static inline struct cftype *__d_cft(struct dentry *dentry)
+{
+	return __d_cfe(dentry)->type;
+}
+
 /* the list of cgroups eligible for automatic release. Protected by
  * release_list_lock */
 static LIST_HEAD(release_list);
@@ -816,12 +855,17 @@
 	struct cgroup_subsys *ss;
 	int ret = 0;
 
-	for_each_subsys(cgrp->root, ss)
-		if (ss->pre_destroy) {
-			ret = ss->pre_destroy(cgrp);
-			if (ret)
-				break;
+	for_each_subsys(cgrp->root, ss) {
+		if (!ss->pre_destroy)
+			continue;
+
+		ret = ss->pre_destroy(cgrp);
+		if (ret) {
+			/* ->pre_destroy() failure is being deprecated */
+			WARN_ON_ONCE(!ss->__DEPRECATED_clear_css_refs);
+			break;
 		}
+	}
 
 	return ret;
 }
@@ -864,6 +908,14 @@
 		BUG_ON(!list_empty(&cgrp->pidlists));
 
 		kfree_rcu(cgrp, rcu_head);
+	} else {
+		struct cfent *cfe = __d_cfe(dentry);
+		struct cgroup *cgrp = dentry->d_parent->d_fsdata;
+
+		WARN_ONCE(!list_empty(&cfe->node) &&
+			  cgrp != &cgrp->root->top_cgroup,
+			  "cfe still linked for %s\n", cfe->type->name);
+		kfree(cfe);
 	}
 	iput(inode);
 }
@@ -882,34 +934,36 @@
 	dput(parent);
 }
 
-static void cgroup_clear_directory(struct dentry *dentry)
+static int cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft)
 {
-	struct list_head *node;
+	struct cfent *cfe;
 
-	BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex));
-	spin_lock(&dentry->d_lock);
-	node = dentry->d_subdirs.next;
-	while (node != &dentry->d_subdirs) {
-		struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
+	lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex);
+	lockdep_assert_held(&cgroup_mutex);
 
-		spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
-		list_del_init(node);
-		if (d->d_inode) {
-			/* This should never be called on a cgroup
-			 * directory with child cgroups */
-			BUG_ON(d->d_inode->i_mode & S_IFDIR);
-			dget_dlock(d);
-			spin_unlock(&d->d_lock);
-			spin_unlock(&dentry->d_lock);
-			d_delete(d);
-			simple_unlink(dentry->d_inode, d);
-			dput(d);
-			spin_lock(&dentry->d_lock);
-		} else
-			spin_unlock(&d->d_lock);
-		node = dentry->d_subdirs.next;
+	list_for_each_entry(cfe, &cgrp->files, node) {
+		struct dentry *d = cfe->dentry;
+
+		if (cft && cfe->type != cft)
+			continue;
+
+		dget(d);
+		d_delete(d);
+		simple_unlink(d->d_inode, d);
+		list_del_init(&cfe->node);
+		dput(d);
+
+		return 0;
 	}
-	spin_unlock(&dentry->d_lock);
+	return -ENOENT;
+}
+
+static void cgroup_clear_directory(struct dentry *dir)
+{
+	struct cgroup *cgrp = __d_cgrp(dir);
+
+	while (!list_empty(&cgrp->files))
+		cgroup_rm_file(cgrp, NULL);
 }
 
 /*
@@ -1294,6 +1348,11 @@
 	if (ret)
 		goto out_unlock;
 
+	/* See feature-removal-schedule.txt */
+	if (opts.subsys_bits != root->actual_subsys_bits || opts.release_agent)
+		pr_warning("cgroup: option changes via remount are deprecated (pid=%d comm=%s)\n",
+			   task_tgid_nr(current), current->comm);
+
 	/* Don't allow flags or name to change at remount */
 	if (opts.flags != root->flags ||
 	    (opts.name && strcmp(opts.name, root->name))) {
@@ -1308,7 +1367,8 @@
 		goto out_unlock;
 	}
 
-	/* (re)populate subsystem files */
+	/* clear out any existing files and repopulate subsystem files */
+	cgroup_clear_directory(cgrp->dentry);
 	cgroup_populate_dir(cgrp);
 
 	if (opts.release_agent)
@@ -1333,6 +1393,7 @@
 {
 	INIT_LIST_HEAD(&cgrp->sibling);
 	INIT_LIST_HEAD(&cgrp->children);
+	INIT_LIST_HEAD(&cgrp->files);
 	INIT_LIST_HEAD(&cgrp->css_sets);
 	INIT_LIST_HEAD(&cgrp->release_list);
 	INIT_LIST_HEAD(&cgrp->pidlists);
@@ -1344,11 +1405,14 @@
 static void init_cgroup_root(struct cgroupfs_root *root)
 {
 	struct cgroup *cgrp = &root->top_cgroup;
+
 	INIT_LIST_HEAD(&root->subsys_list);
 	INIT_LIST_HEAD(&root->root_list);
+	INIT_LIST_HEAD(&root->allcg_list);
 	root->number_of_cgroups = 1;
 	cgrp->root = root;
 	cgrp->top_cgroup = cgrp;
+	list_add_tail(&cgrp->allcg_node, &root->allcg_list);
 	init_cgroup_housekeeping(cgrp);
 }
 
@@ -1692,16 +1756,6 @@
 
 static struct kobject *cgroup_kobj;
 
-static inline struct cgroup *__d_cgrp(struct dentry *dentry)
-{
-	return dentry->d_fsdata;
-}
-
-static inline struct cftype *__d_cft(struct dentry *dentry)
-{
-	return dentry->d_fsdata;
-}
-
 /**
  * cgroup_path - generate the path of a cgroup
  * @cgrp: the cgroup in question
@@ -2160,9 +2214,9 @@
 		 * only need to check permissions on one of them.
 		 */
 		tcred = __task_cred(tsk);
-		if (cred->euid &&
-		    cred->euid != tcred->uid &&
-		    cred->euid != tcred->suid) {
+		if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
+		    !uid_eq(cred->euid, tcred->uid) &&
+		    !uid_eq(cred->euid, tcred->suid)) {
 			rcu_read_unlock();
 			ret = -EACCES;
 			goto out_unlock_cgroup;
@@ -2172,6 +2226,18 @@
 
 	if (threadgroup)
 		tsk = tsk->group_leader;
+
+	/*
+	 * Workqueue threads may acquire PF_THREAD_BOUND and become
+	 * trapped in a cpuset, or RT worker may be born in a cgroup
+	 * with no rt_runtime allocated.  Just say no.
+	 */
+	if (tsk == kthreadd_task || (tsk->flags & PF_THREAD_BOUND)) {
+		ret = -EINVAL;
+		rcu_read_unlock();
+		goto out_unlock_cgroup;
+	}
+
 	get_task_struct(tsk);
 	rcu_read_unlock();
 
@@ -2603,50 +2669,191 @@
 	return mode;
 }
 
-int cgroup_add_file(struct cgroup *cgrp,
-		       struct cgroup_subsys *subsys,
-		       const struct cftype *cft)
+static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
+			   const struct cftype *cft)
 {
 	struct dentry *dir = cgrp->dentry;
+	struct cgroup *parent = __d_cgrp(dir);
 	struct dentry *dentry;
+	struct cfent *cfe;
 	int error;
 	umode_t mode;
-
 	char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 };
+
+	/* does @cft->flags tell us to skip creation on @cgrp? */
+	if ((cft->flags & CFTYPE_NOT_ON_ROOT) && !cgrp->parent)
+		return 0;
+	if ((cft->flags & CFTYPE_ONLY_ON_ROOT) && cgrp->parent)
+		return 0;
+
 	if (subsys && !test_bit(ROOT_NOPREFIX, &cgrp->root->flags)) {
 		strcpy(name, subsys->name);
 		strcat(name, ".");
 	}
 	strcat(name, cft->name);
+
 	BUG_ON(!mutex_is_locked(&dir->d_inode->i_mutex));
+
+	cfe = kzalloc(sizeof(*cfe), GFP_KERNEL);
+	if (!cfe)
+		return -ENOMEM;
+
 	dentry = lookup_one_len(name, dir, strlen(name));
-	if (!IS_ERR(dentry)) {
-		mode = cgroup_file_mode(cft);
-		error = cgroup_create_file(dentry, mode | S_IFREG,
-						cgrp->root->sb);
-		if (!error)
-			dentry->d_fsdata = (void *)cft;
-		dput(dentry);
-	} else
+	if (IS_ERR(dentry)) {
 		error = PTR_ERR(dentry);
+		goto out;
+	}
+
+	mode = cgroup_file_mode(cft);
+	error = cgroup_create_file(dentry, mode | S_IFREG, cgrp->root->sb);
+	if (!error) {
+		cfe->type = (void *)cft;
+		cfe->dentry = dentry;
+		dentry->d_fsdata = cfe;
+		list_add_tail(&cfe->node, &parent->files);
+		cfe = NULL;
+	}
+	dput(dentry);
+out:
+	kfree(cfe);
 	return error;
 }
-EXPORT_SYMBOL_GPL(cgroup_add_file);
 
-int cgroup_add_files(struct cgroup *cgrp,
-			struct cgroup_subsys *subsys,
-			const struct cftype cft[],
-			int count)
+static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
+			      const struct cftype cfts[], bool is_add)
 {
-	int i, err;
-	for (i = 0; i < count; i++) {
-		err = cgroup_add_file(cgrp, subsys, &cft[i]);
-		if (err)
-			return err;
+	const struct cftype *cft;
+	int err, ret = 0;
+
+	for (cft = cfts; cft->name[0] != '\0'; cft++) {
+		if (is_add)
+			err = cgroup_add_file(cgrp, subsys, cft);
+		else
+			err = cgroup_rm_file(cgrp, cft);
+		if (err) {
+			pr_warning("cgroup_addrm_files: failed to %s %s, err=%d\n",
+				   is_add ? "add" : "remove", cft->name, err);
+			ret = err;
+		}
 	}
+	return ret;
+}
+
+static DEFINE_MUTEX(cgroup_cft_mutex);
+
+static void cgroup_cfts_prepare(void)
+	__acquires(&cgroup_cft_mutex) __acquires(&cgroup_mutex)
+{
+	/*
+	 * Thanks to the entanglement with vfs inode locking, we can't walk
+	 * the existing cgroups under cgroup_mutex and create files.
+	 * Instead, we increment reference on all cgroups and build list of
+	 * them using @cgrp->cft_q_node.  Grab cgroup_cft_mutex to ensure
+	 * exclusive access to the field.
+	 */
+	mutex_lock(&cgroup_cft_mutex);
+	mutex_lock(&cgroup_mutex);
+}
+
+static void cgroup_cfts_commit(struct cgroup_subsys *ss,
+			       const struct cftype *cfts, bool is_add)
+	__releases(&cgroup_mutex) __releases(&cgroup_cft_mutex)
+{
+	LIST_HEAD(pending);
+	struct cgroup *cgrp, *n;
+
+	/* %NULL @cfts indicates abort and don't bother if @ss isn't attached */
+	if (cfts && ss->root != &rootnode) {
+		list_for_each_entry(cgrp, &ss->root->allcg_list, allcg_node) {
+			dget(cgrp->dentry);
+			list_add_tail(&cgrp->cft_q_node, &pending);
+		}
+	}
+
+	mutex_unlock(&cgroup_mutex);
+
+	/*
+	 * All new cgroups will see @cfts update on @ss->cftsets.  Add/rm
+	 * files for all cgroups which were created before.
+	 */
+	list_for_each_entry_safe(cgrp, n, &pending, cft_q_node) {
+		struct inode *inode = cgrp->dentry->d_inode;
+
+		mutex_lock(&inode->i_mutex);
+		mutex_lock(&cgroup_mutex);
+		if (!cgroup_is_removed(cgrp))
+			cgroup_addrm_files(cgrp, ss, cfts, is_add);
+		mutex_unlock(&cgroup_mutex);
+		mutex_unlock(&inode->i_mutex);
+
+		list_del_init(&cgrp->cft_q_node);
+		dput(cgrp->dentry);
+	}
+
+	mutex_unlock(&cgroup_cft_mutex);
+}
+
+/**
+ * cgroup_add_cftypes - add an array of cftypes to a subsystem
+ * @ss: target cgroup subsystem
+ * @cfts: zero-length name terminated array of cftypes
+ *
+ * Register @cfts to @ss.  Files described by @cfts are created for all
+ * existing cgroups to which @ss is attached and all future cgroups will
+ * have them too.  This function can be called anytime whether @ss is
+ * attached or not.
+ *
+ * Returns 0 on successful registration, -errno on failure.  Note that this
+ * function currently returns 0 as long as @cfts registration is successful
+ * even if some file creation attempts on existing cgroups fail.
+ */
+int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts)
+{
+	struct cftype_set *set;
+
+	set = kzalloc(sizeof(*set), GFP_KERNEL);
+	if (!set)
+		return -ENOMEM;
+
+	cgroup_cfts_prepare();
+	set->cfts = cfts;
+	list_add_tail(&set->node, &ss->cftsets);
+	cgroup_cfts_commit(ss, cfts, true);
+
 	return 0;
 }
-EXPORT_SYMBOL_GPL(cgroup_add_files);
+EXPORT_SYMBOL_GPL(cgroup_add_cftypes);
+
+/**
+ * cgroup_rm_cftypes - remove an array of cftypes from a subsystem
+ * @ss: target cgroup subsystem
+ * @cfts: zero-length name terminated array of cftypes
+ *
+ * Unregister @cfts from @ss.  Files described by @cfts are removed from
+ * all existing cgroups to which @ss is attached and all future cgroups
+ * won't have them either.  This function can be called anytime whether @ss
+ * is attached or not.
+ *
+ * Returns 0 on successful unregistration, -ENOENT if @cfts is not
+ * registered with @ss.
+ */
+int cgroup_rm_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts)
+{
+	struct cftype_set *set;
+
+	cgroup_cfts_prepare();
+
+	list_for_each_entry(set, &ss->cftsets, node) {
+		if (set->cfts == cfts) {
+			list_del_init(&set->node);
+			cgroup_cfts_commit(ss, cfts, false);
+			return 0;
+		}
+	}
+
+	cgroup_cfts_commit(ss, NULL, false);
+	return -ENOENT;
+}
 
 /**
  * cgroup_task_count - count the number of tasks in a cgroup.
@@ -3625,13 +3832,14 @@
 		.read_u64 = cgroup_clone_children_read,
 		.write_u64 = cgroup_clone_children_write,
 	},
-};
-
-static struct cftype cft_release_agent = {
-	.name = "release_agent",
-	.read_seq_string = cgroup_release_agent_show,
-	.write_string = cgroup_release_agent_write,
-	.max_write_len = PATH_MAX,
+	{
+		.name = "release_agent",
+		.flags = CFTYPE_ONLY_ON_ROOT,
+		.read_seq_string = cgroup_release_agent_show,
+		.write_string = cgroup_release_agent_write,
+		.max_write_len = PATH_MAX,
+	},
+	{ }	/* terminate */
 };
 
 static int cgroup_populate_dir(struct cgroup *cgrp)
@@ -3639,22 +3847,18 @@
 	int err;
 	struct cgroup_subsys *ss;
 
-	/* First clear out any existing files */
-	cgroup_clear_directory(cgrp->dentry);
-
-	err = cgroup_add_files(cgrp, NULL, files, ARRAY_SIZE(files));
+	err = cgroup_addrm_files(cgrp, NULL, files, true);
 	if (err < 0)
 		return err;
 
-	if (cgrp == cgrp->top_cgroup) {
-		if ((err = cgroup_add_file(cgrp, NULL, &cft_release_agent)) < 0)
-			return err;
+	/* process cftsets of each subsystem */
+	for_each_subsys(cgrp->root, ss) {
+		struct cftype_set *set;
+
+		list_for_each_entry(set, &ss->cftsets, node)
+			cgroup_addrm_files(cgrp, ss, set->cfts, true);
 	}
 
-	for_each_subsys(cgrp->root, ss) {
-		if (ss->populate && (err = ss->populate(ss, cgrp)) < 0)
-			return err;
-	}
 	/* This cgroup is ready now */
 	for_each_subsys(cgrp->root, ss) {
 		struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
@@ -3670,6 +3874,14 @@
 	return 0;
 }
 
+static void css_dput_fn(struct work_struct *work)
+{
+	struct cgroup_subsys_state *css =
+		container_of(work, struct cgroup_subsys_state, dput_work);
+
+	dput(css->cgroup->dentry);
+}
+
 static void init_cgroup_css(struct cgroup_subsys_state *css,
 			       struct cgroup_subsys *ss,
 			       struct cgroup *cgrp)
@@ -3682,6 +3894,16 @@
 		set_bit(CSS_ROOT, &css->flags);
 	BUG_ON(cgrp->subsys[ss->subsys_id]);
 	cgrp->subsys[ss->subsys_id] = css;
+
+	/*
+	 * If !clear_css_refs, css holds an extra ref to @cgrp->dentry
+	 * which is put on the last css_put().  dput() requires process
+	 * context, which css_put() may be called without.  @css->dput_work
+	 * will be used to invoke dput() asynchronously from css_put().
+	 */
+	INIT_WORK(&css->dput_work, css_dput_fn);
+	if (ss->__DEPRECATED_clear_css_refs)
+		set_bit(CSS_CLEAR_CSS_REFS, &css->flags);
 }
 
 static void cgroup_lock_hierarchy(struct cgroupfs_root *root)
@@ -3784,9 +4006,16 @@
 	if (err < 0)
 		goto err_remove;
 
+	/* If !clear_css_refs, each css holds a ref to the cgroup's dentry */
+	for_each_subsys(root, ss)
+		if (!ss->__DEPRECATED_clear_css_refs)
+			dget(dentry);
+
 	/* The cgroup directory was pre-locked for us */
 	BUG_ON(!mutex_is_locked(&cgrp->dentry->d_inode->i_mutex));
 
+	list_add_tail(&cgrp->allcg_node, &root->allcg_list);
+
 	err = cgroup_populate_dir(cgrp);
 	/* If err < 0, we have a half-filled directory - oh well ;) */
 
@@ -3826,18 +4055,19 @@
 	return cgroup_create(c_parent, dentry, mode | S_IFDIR);
 }
 
+/*
+ * Check the reference count on each subsystem. Since we already
+ * established that there are no tasks in the cgroup, if the css refcount
+ * is also 1, then there should be no outstanding references, so the
+ * subsystem is safe to destroy. We scan across all subsystems rather than
+ * using the per-hierarchy linked list of mounted subsystems since we can
+ * be called via check_for_release() with no synchronization other than
+ * RCU, and the subsystem linked list isn't RCU-safe.
+ */
 static int cgroup_has_css_refs(struct cgroup *cgrp)
 {
-	/* Check the reference count on each subsystem. Since we
-	 * already established that there are no tasks in the
-	 * cgroup, if the css refcount is also 1, then there should
-	 * be no outstanding references, so the subsystem is safe to
-	 * destroy. We scan across all subsystems rather than using
-	 * the per-hierarchy linked list of mounted subsystems since
-	 * we can be called via check_for_release() with no
-	 * synchronization other than RCU, and the subsystem linked
-	 * list isn't RCU-safe */
 	int i;
+
 	/*
 	 * We won't need to lock the subsys array, because the subsystems
 	 * we're concerned about aren't going anywhere since our cgroup root
@@ -3846,17 +4076,21 @@
 	for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
 		struct cgroup_subsys *ss = subsys[i];
 		struct cgroup_subsys_state *css;
+
 		/* Skip subsystems not present or not in this hierarchy */
 		if (ss == NULL || ss->root != cgrp->root)
 			continue;
+
 		css = cgrp->subsys[ss->subsys_id];
-		/* When called from check_for_release() it's possible
+		/*
+		 * When called from check_for_release() it's possible
 		 * that by this point the cgroup has been removed
 		 * and the css deleted. But a false-positive doesn't
 		 * matter, since it can only happen if the cgroup
 		 * has been deleted and hence no longer needs the
-		 * release agent to be called anyway. */
-		if (css && (atomic_read(&css->refcnt) > 1))
+		 * release agent to be called anyway.
+		 */
+		if (css && css_refcnt(css) > 1)
 			return 1;
 	}
 	return 0;
@@ -3866,51 +4100,63 @@
  * Atomically mark all (or else none) of the cgroup's CSS objects as
  * CSS_REMOVED. Return true on success, or false if the cgroup has
  * busy subsystems. Call with cgroup_mutex held
+ *
+ * Depending on whether a subsys has __DEPRECATED_clear_css_refs set or
+ * not, cgroup removal behaves differently.
+ *
+ * If clear is set, css refcnt for the subsystem should be zero before
+ * cgroup removal can be committed.  This is implemented by
+ * CGRP_WAIT_ON_RMDIR and retry logic around ->pre_destroy(), which may be
+ * called multiple times until all css refcnts reach zero and is allowed to
+ * veto removal on any invocation.  This behavior is deprecated and will be
+ * removed as soon as the existing user (memcg) is updated.
+ *
+ * If clear is not set, each css holds an extra reference to the cgroup's
+ * dentry and cgroup removal proceeds regardless of css refs.
+ * ->pre_destroy() will be called at least once and is not allowed to fail.
+ * On the last put of each css, whenever that may be, the extra dentry ref
+ * is put so that dentry destruction happens only after all css's are
+ * released.
  */
-
 static int cgroup_clear_css_refs(struct cgroup *cgrp)
 {
 	struct cgroup_subsys *ss;
 	unsigned long flags;
 	bool failed = false;
+
 	local_irq_save(flags);
+
+	/*
+	 * Block new css_tryget() by deactivating refcnt.  If all refcnts
+	 * for subsystems w/ clear_css_refs set were 1 at the moment of
+	 * deactivation, we succeeded.
+	 */
 	for_each_subsys(cgrp->root, ss) {
 		struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
-		int refcnt;
-		while (1) {
-			/* We can only remove a CSS with a refcnt==1 */
-			refcnt = atomic_read(&css->refcnt);
-			if (refcnt > 1) {
-				failed = true;
-				goto done;
-			}
-			BUG_ON(!refcnt);
-			/*
-			 * Drop the refcnt to 0 while we check other
-			 * subsystems. This will cause any racing
-			 * css_tryget() to spin until we set the
-			 * CSS_REMOVED bits or abort
-			 */
-			if (atomic_cmpxchg(&css->refcnt, refcnt, 0) == refcnt)
-				break;
-			cpu_relax();
-		}
+
+		WARN_ON(atomic_read(&css->refcnt) < 0);
+		atomic_add(CSS_DEACT_BIAS, &css->refcnt);
+
+		if (ss->__DEPRECATED_clear_css_refs)
+			failed |= css_refcnt(css) != 1;
 	}
- done:
+
+	/*
+	 * If succeeded, set REMOVED and put all the base refs; otherwise,
+	 * restore refcnts to positive values.  Either way, all in-progress
+	 * css_tryget() will be released.
+	 */
 	for_each_subsys(cgrp->root, ss) {
 		struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
-		if (failed) {
-			/*
-			 * Restore old refcnt if we previously managed
-			 * to clear it from 1 to 0
-			 */
-			if (!atomic_read(&css->refcnt))
-				atomic_set(&css->refcnt, 1);
-		} else {
-			/* Commit the fact that the CSS is removed */
+
+		if (!failed) {
 			set_bit(CSS_REMOVED, &css->flags);
+			css_put(css);
+		} else {
+			atomic_sub(CSS_DEACT_BIAS, &css->refcnt);
 		}
 	}
+
 	local_irq_restore(flags);
 	return !failed;
 }
@@ -3995,6 +4241,8 @@
 	list_del_init(&cgrp->sibling);
 	cgroup_unlock_hierarchy(cgrp->root);
 
+	list_del_init(&cgrp->allcg_node);
+
 	d = dget(cgrp->dentry);
 
 	cgroup_d_remove_dir(d);
@@ -4021,12 +4269,29 @@
 	return 0;
 }
 
+static void __init_or_module cgroup_init_cftsets(struct cgroup_subsys *ss)
+{
+	INIT_LIST_HEAD(&ss->cftsets);
+
+	/*
+	 * base_cftset is embedded in subsys itself, no need to worry about
+	 * deregistration.
+	 */
+	if (ss->base_cftypes) {
+		ss->base_cftset.cfts = ss->base_cftypes;
+		list_add_tail(&ss->base_cftset.node, &ss->cftsets);
+	}
+}
+
 static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
 {
 	struct cgroup_subsys_state *css;
 
 	printk(KERN_INFO "Initializing cgroup subsys %s\n", ss->name);
 
+	/* init base cftset */
+	cgroup_init_cftsets(ss);
+
 	/* Create the top cgroup state for this subsystem */
 	list_add(&ss->sibling, &rootnode.subsys_list);
 	ss->root = &rootnode;
@@ -4096,6 +4361,9 @@
 		return 0;
 	}
 
+	/* init base cftset */
+	cgroup_init_cftsets(ss);
+
 	/*
 	 * need to register a subsys id before anything else - for example,
 	 * init_cgroup_css needs it.
@@ -4685,21 +4953,41 @@
 }
 
 /* Caller must verify that the css is not for root cgroup */
-void __css_put(struct cgroup_subsys_state *css, int count)
+bool __css_tryget(struct cgroup_subsys_state *css)
+{
+	do {
+		int v = css_refcnt(css);
+
+		if (atomic_cmpxchg(&css->refcnt, v, v + 1) == v)
+			return true;
+		cpu_relax();
+	} while (!test_bit(CSS_REMOVED, &css->flags));
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(__css_tryget);
+
+/* Caller must verify that the css is not for root cgroup */
+void __css_put(struct cgroup_subsys_state *css)
 {
 	struct cgroup *cgrp = css->cgroup;
-	int val;
+
 	rcu_read_lock();
-	val = atomic_sub_return(count, &css->refcnt);
-	if (val == 1) {
+	atomic_dec(&css->refcnt);
+	switch (css_refcnt(css)) {
+	case 1:
 		if (notify_on_release(cgrp)) {
 			set_bit(CGRP_RELEASABLE, &cgrp->flags);
 			check_for_release(cgrp);
 		}
 		cgroup_wakeup_rmdir_waiter(cgrp);
+		break;
+	case 0:
+		if (!test_bit(CSS_CLEAR_CSS_REFS, &css->flags))
+			schedule_work(&css->dput_work);
+		break;
 	}
 	rcu_read_unlock();
-	WARN_ON_ONCE(val < 1);
 }
 EXPORT_SYMBOL_GPL(__css_put);
 
@@ -4818,7 +5106,7 @@
 	 * on this or this is under rcu_read_lock(). Once css->id is allocated,
 	 * it's unchanged until freed.
 	 */
-	cssid = rcu_dereference_check(css->id, atomic_read(&css->refcnt));
+	cssid = rcu_dereference_check(css->id, css_refcnt(css));
 
 	if (cssid)
 		return cssid->id;
@@ -4830,7 +5118,7 @@
 {
 	struct css_id *cssid;
 
-	cssid = rcu_dereference_check(css->id, atomic_read(&css->refcnt));
+	cssid = rcu_dereference_check(css->id, css_refcnt(css));
 
 	if (cssid)
 		return cssid->depth;
@@ -5211,19 +5499,15 @@
 		.name = "releasable",
 		.read_u64 = releasable_read,
 	},
-};
 
-static int debug_populate(struct cgroup_subsys *ss, struct cgroup *cont)
-{
-	return cgroup_add_files(cont, ss, debug_files,
-				ARRAY_SIZE(debug_files));
-}
+	{ }	/* terminate */
+};
 
 struct cgroup_subsys debug_subsys = {
 	.name = "debug",
 	.create = debug_create,
 	.destroy = debug_destroy,
-	.populate = debug_populate,
 	.subsys_id = debug_subsys_id,
+	.base_cftypes = debug_files,
 };
 #endif /* CONFIG_CGROUP_DEBUG */
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index f86e939..3649fc6 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -358,24 +358,19 @@
 static struct cftype files[] = {
 	{
 		.name = "state",
+		.flags = CFTYPE_NOT_ON_ROOT,
 		.read_seq_string = freezer_read,
 		.write_string = freezer_write,
 	},
+	{ }	/* terminate */
 };
 
-static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup)
-{
-	if (!cgroup->parent)
-		return 0;
-	return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files));
-}
-
 struct cgroup_subsys freezer_subsys = {
 	.name		= "freezer",
 	.create		= freezer_create,
 	.destroy	= freezer_destroy,
-	.populate	= freezer_populate,
 	.subsys_id	= freezer_subsys_id,
 	.can_attach	= freezer_can_attach,
 	.fork		= freezer_fork,
+	.base_cftypes	= files,
 };
diff --git a/kernel/compat.c b/kernel/compat.c
index d2c67aa..c28a306 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -1073,15 +1073,7 @@
 	if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t)))
 		return -EFAULT;
 	sigset_from_compat(&newset, &newset32);
-	sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
-
-	current->saved_sigmask = current->blocked;
-	set_current_blocked(&newset);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_restore_sigmask();
-	return -ERESTARTNOHAND;
+	return sigsuspend(&newset);
 }
 #endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
 
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 14f7070..8c8bd65 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1765,29 +1765,18 @@
 		.write_u64 = cpuset_write_u64,
 		.private = FILE_SPREAD_SLAB,
 	},
+
+	{
+		.name = "memory_pressure_enabled",
+		.flags = CFTYPE_ONLY_ON_ROOT,
+		.read_u64 = cpuset_read_u64,
+		.write_u64 = cpuset_write_u64,
+		.private = FILE_MEMORY_PRESSURE_ENABLED,
+	},
+
+	{ }	/* terminate */
 };
 
-static struct cftype cft_memory_pressure_enabled = {
-	.name = "memory_pressure_enabled",
-	.read_u64 = cpuset_read_u64,
-	.write_u64 = cpuset_write_u64,
-	.private = FILE_MEMORY_PRESSURE_ENABLED,
-};
-
-static int cpuset_populate(struct cgroup_subsys *ss, struct cgroup *cont)
-{
-	int err;
-
-	err = cgroup_add_files(cont, ss, files, ARRAY_SIZE(files));
-	if (err)
-		return err;
-	/* memory_pressure_enabled is in root cpuset only */
-	if (!cont->parent)
-		err = cgroup_add_file(cont, ss,
-				      &cft_memory_pressure_enabled);
-	return err;
-}
-
 /*
  * post_clone() is called during cgroup_create() when the
  * clone_children mount argument was specified.  The cgroup
@@ -1887,9 +1876,9 @@
 	.destroy = cpuset_destroy,
 	.can_attach = cpuset_can_attach,
 	.attach = cpuset_attach,
-	.populate = cpuset_populate,
 	.post_clone = cpuset_post_clone,
 	.subsys_id = cpuset_subsys_id,
+	.base_cftypes = files,
 	.early_init = 1,
 };
 
diff --git a/kernel/cred.c b/kernel/cred.c
index e70683d..430557e 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -49,6 +49,14 @@
 	.subscribers		= ATOMIC_INIT(2),
 	.magic			= CRED_MAGIC,
 #endif
+	.uid			= GLOBAL_ROOT_UID,
+	.gid			= GLOBAL_ROOT_GID,
+	.suid			= GLOBAL_ROOT_UID,
+	.sgid			= GLOBAL_ROOT_GID,
+	.euid			= GLOBAL_ROOT_UID,
+	.egid			= GLOBAL_ROOT_GID,
+	.fsuid			= GLOBAL_ROOT_UID,
+	.fsgid			= GLOBAL_ROOT_GID,
 	.securebits		= SECUREBITS_DEFAULT,
 	.cap_inheritable	= CAP_EMPTY_SET,
 	.cap_permitted		= CAP_FULL_SET,
@@ -148,6 +156,7 @@
 	if (cred->group_info)
 		put_group_info(cred->group_info);
 	free_uid(cred->user);
+	put_user_ns(cred->user_ns);
 	kmem_cache_free(cred_jar, cred);
 }
 
@@ -303,6 +312,7 @@
 	set_cred_subscribers(new, 0);
 	get_group_info(new->group_info);
 	get_uid(new->user);
+	get_user_ns(new->user_ns);
 
 #ifdef CONFIG_KEYS
 	key_get(new->thread_keyring);
@@ -414,11 +424,6 @@
 			goto error_put;
 	}
 
-	/* cache user_ns in cred.  Doesn't need a refcount because it will
-	 * stay pinned by cred->user
-	 */
-	new->user_ns = new->user->user_ns;
-
 #ifdef CONFIG_KEYS
 	/* new threads get their own thread keyrings if their parent already
 	 * had one */
@@ -493,10 +498,10 @@
 	get_cred(new); /* we will require a ref for the subj creds too */
 
 	/* dumpability changes */
-	if (old->euid != new->euid ||
-	    old->egid != new->egid ||
-	    old->fsuid != new->fsuid ||
-	    old->fsgid != new->fsgid ||
+	if (!uid_eq(old->euid, new->euid) ||
+	    !gid_eq(old->egid, new->egid) ||
+	    !uid_eq(old->fsuid, new->fsuid) ||
+	    !gid_eq(old->fsgid, new->fsgid) ||
 	    !cap_issubset(new->cap_permitted, old->cap_permitted)) {
 		if (task->mm)
 			set_dumpable(task->mm, suid_dumpable);
@@ -505,9 +510,9 @@
 	}
 
 	/* alter the thread keyring */
-	if (new->fsuid != old->fsuid)
+	if (!uid_eq(new->fsuid, old->fsuid))
 		key_fsuid_changed(task);
-	if (new->fsgid != old->fsgid)
+	if (!gid_eq(new->fsgid, old->fsgid))
 		key_fsgid_changed(task);
 
 	/* do it
@@ -524,16 +529,16 @@
 	alter_cred_subscribers(old, -2);
 
 	/* send notifications */
-	if (new->uid   != old->uid  ||
-	    new->euid  != old->euid ||
-	    new->suid  != old->suid ||
-	    new->fsuid != old->fsuid)
+	if (!uid_eq(new->uid,   old->uid)  ||
+	    !uid_eq(new->euid,  old->euid) ||
+	    !uid_eq(new->suid,  old->suid) ||
+	    !uid_eq(new->fsuid, old->fsuid))
 		proc_id_connector(task, PROC_EVENT_UID);
 
-	if (new->gid   != old->gid  ||
-	    new->egid  != old->egid ||
-	    new->sgid  != old->sgid ||
-	    new->fsgid != old->fsgid)
+	if (!gid_eq(new->gid,   old->gid)  ||
+	    !gid_eq(new->egid,  old->egid) ||
+	    !gid_eq(new->sgid,  old->sgid) ||
+	    !gid_eq(new->fsgid, old->fsgid))
 		proc_id_connector(task, PROC_EVENT_GID);
 
 	/* release the old obj and subj refs both */
@@ -678,6 +683,7 @@
 	atomic_set(&new->usage, 1);
 	set_cred_subscribers(new, 0);
 	get_uid(new->user);
+	get_user_ns(new->user_ns);
 	get_group_info(new->group_info);
 
 #ifdef CONFIG_KEYS
diff --git a/kernel/events/Makefile b/kernel/events/Makefile
index 22d901f..103f5d1 100644
--- a/kernel/events/Makefile
+++ b/kernel/events/Makefile
@@ -3,4 +3,7 @@
 endif
 
 obj-y := core.o ring_buffer.o callchain.o
+
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
+obj-$(CONFIG_UPROBES) += uprobes.o
+
diff --git a/kernel/events/core.c b/kernel/events/core.c
index fd126f8..5b06cbb 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4957,7 +4957,7 @@
 	if (rctx < 0)
 		return;
 
-	perf_sample_data_init(&data, addr);
+	perf_sample_data_init(&data, addr, 0);
 
 	do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, &data, regs);
 
@@ -5215,7 +5215,7 @@
 		.data = record,
 	};
 
-	perf_sample_data_init(&data, addr);
+	perf_sample_data_init(&data, addr, 0);
 	data.raw = &raw;
 
 	hlist_for_each_entry_rcu(event, node, head, hlist_entry) {
@@ -5318,7 +5318,7 @@
 	struct perf_sample_data sample;
 	struct pt_regs *regs = data;
 
-	perf_sample_data_init(&sample, bp->attr.bp_addr);
+	perf_sample_data_init(&sample, bp->attr.bp_addr, 0);
 
 	if (!bp->hw.state && !perf_exclude_event(bp, regs))
 		perf_swevent_event(bp, 1, &sample, regs);
@@ -5344,13 +5344,12 @@
 
 	event->pmu->read(event);
 
-	perf_sample_data_init(&data, 0);
-	data.period = event->hw.last_period;
+	perf_sample_data_init(&data, 0, event->hw.last_period);
 	regs = get_irq_regs();
 
 	if (regs && !perf_exclude_event(event, regs)) {
 		if (!(event->attr.exclude_idle && is_idle_task(current)))
-			if (perf_event_overflow(event, &data, regs))
+			if (__perf_event_overflow(event, 1, &data, regs))
 				ret = HRTIMER_NORESTART;
 	}
 
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
new file mode 100644
index 0000000..985be4d
--- /dev/null
+++ b/kernel/events/uprobes.c
@@ -0,0 +1,1667 @@
+/*
+ * User-space Probes (UProbes)
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2008-2012
+ * Authors:
+ *	Srikar Dronamraju
+ *	Jim Keniston
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>	/* read_mapping_page */
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/rmap.h>		/* anon_vma_prepare */
+#include <linux/mmu_notifier.h>	/* set_pte_at_notify */
+#include <linux/swap.h>		/* try_to_free_swap */
+#include <linux/ptrace.h>	/* user_enable_single_step */
+#include <linux/kdebug.h>	/* notifier mechanism */
+
+#include <linux/uprobes.h>
+
+#define UINSNS_PER_PAGE			(PAGE_SIZE/UPROBE_XOL_SLOT_BYTES)
+#define MAX_UPROBE_XOL_SLOTS		UINSNS_PER_PAGE
+
+static struct srcu_struct uprobes_srcu;
+static struct rb_root uprobes_tree = RB_ROOT;
+
+static DEFINE_SPINLOCK(uprobes_treelock);	/* serialize rbtree access */
+
+#define UPROBES_HASH_SZ	13
+
+/* serialize (un)register */
+static struct mutex uprobes_mutex[UPROBES_HASH_SZ];
+
+#define uprobes_hash(v)		(&uprobes_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ])
+
+/* serialize uprobe->pending_list */
+static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ];
+#define uprobes_mmap_hash(v)	(&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ])
+
+/*
+ * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe
+ * events active at this time.  Probably a fine grained per inode count is
+ * better?
+ */
+static atomic_t uprobe_events = ATOMIC_INIT(0);
+
+/*
+ * Maintain a temporary per vma info that can be used to search if a vma
+ * has already been handled. This structure is introduced since extending
+ * vm_area_struct wasnt recommended.
+ */
+struct vma_info {
+	struct list_head	probe_list;
+	struct mm_struct	*mm;
+	loff_t			vaddr;
+};
+
+struct uprobe {
+	struct rb_node		rb_node;	/* node in the rb tree */
+	atomic_t		ref;
+	struct rw_semaphore	consumer_rwsem;
+	struct list_head	pending_list;
+	struct uprobe_consumer	*consumers;
+	struct inode		*inode;		/* Also hold a ref to inode */
+	loff_t			offset;
+	int			flags;
+	struct arch_uprobe	arch;
+};
+
+/*
+ * valid_vma: Verify if the specified vma is an executable vma
+ * Relax restrictions while unregistering: vm_flags might have
+ * changed after breakpoint was inserted.
+ *	- is_register: indicates if we are in register context.
+ *	- Return 1 if the specified virtual address is in an
+ *	  executable vma.
+ */
+static bool valid_vma(struct vm_area_struct *vma, bool is_register)
+{
+	if (!vma->vm_file)
+		return false;
+
+	if (!is_register)
+		return true;
+
+	if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == (VM_READ|VM_EXEC))
+		return true;
+
+	return false;
+}
+
+static loff_t vma_address(struct vm_area_struct *vma, loff_t offset)
+{
+	loff_t vaddr;
+
+	vaddr = vma->vm_start + offset;
+	vaddr -= vma->vm_pgoff << PAGE_SHIFT;
+
+	return vaddr;
+}
+
+/**
+ * __replace_page - replace page in vma by new page.
+ * based on replace_page in mm/ksm.c
+ *
+ * @vma:      vma that holds the pte pointing to page
+ * @page:     the cowed page we are replacing by kpage
+ * @kpage:    the modified page we replace page by
+ *
+ * Returns 0 on success, -EFAULT on failure.
+ */
+static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *ptep;
+	spinlock_t *ptl;
+	unsigned long addr;
+	int err = -EFAULT;
+
+	addr = page_address_in_vma(page, vma);
+	if (addr == -EFAULT)
+		goto out;
+
+	pgd = pgd_offset(mm, addr);
+	if (!pgd_present(*pgd))
+		goto out;
+
+	pud = pud_offset(pgd, addr);
+	if (!pud_present(*pud))
+		goto out;
+
+	pmd = pmd_offset(pud, addr);
+	if (!pmd_present(*pmd))
+		goto out;
+
+	ptep = pte_offset_map_lock(mm, pmd, addr, &ptl);
+	if (!ptep)
+		goto out;
+
+	get_page(kpage);
+	page_add_new_anon_rmap(kpage, vma, addr);
+
+	if (!PageAnon(page)) {
+		dec_mm_counter(mm, MM_FILEPAGES);
+		inc_mm_counter(mm, MM_ANONPAGES);
+	}
+
+	flush_cache_page(vma, addr, pte_pfn(*ptep));
+	ptep_clear_flush(vma, addr, ptep);
+	set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
+
+	page_remove_rmap(page);
+	if (!page_mapped(page))
+		try_to_free_swap(page);
+	put_page(page);
+	pte_unmap_unlock(ptep, ptl);
+	err = 0;
+
+out:
+	return err;
+}
+
+/**
+ * is_swbp_insn - check if instruction is breakpoint instruction.
+ * @insn: instruction to be checked.
+ * Default implementation of is_swbp_insn
+ * Returns true if @insn is a breakpoint instruction.
+ */
+bool __weak is_swbp_insn(uprobe_opcode_t *insn)
+{
+	return *insn == UPROBE_SWBP_INSN;
+}
+
+/*
+ * NOTE:
+ * Expect the breakpoint instruction to be the smallest size instruction for
+ * the architecture. If an arch has variable length instruction and the
+ * breakpoint instruction is not of the smallest length instruction
+ * supported by that architecture then we need to modify read_opcode /
+ * write_opcode accordingly. This would never be a problem for archs that
+ * have fixed length instructions.
+ */
+
+/*
+ * write_opcode - write the opcode at a given virtual address.
+ * @auprobe: arch breakpointing information.
+ * @mm: the probed process address space.
+ * @vaddr: the virtual address to store the opcode.
+ * @opcode: opcode to be written at @vaddr.
+ *
+ * Called with mm->mmap_sem held (for read and with a reference to
+ * mm).
+ *
+ * For mm @mm, write the opcode at @vaddr.
+ * Return 0 (success) or a negative errno.
+ */
+static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
+			unsigned long vaddr, uprobe_opcode_t opcode)
+{
+	struct page *old_page, *new_page;
+	struct address_space *mapping;
+	void *vaddr_old, *vaddr_new;
+	struct vm_area_struct *vma;
+	struct uprobe *uprobe;
+	loff_t addr;
+	int ret;
+
+	/* Read the page with vaddr into memory */
+	ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma);
+	if (ret <= 0)
+		return ret;
+
+	ret = -EINVAL;
+
+	/*
+	 * We are interested in text pages only. Our pages of interest
+	 * should be mapped for read and execute only. We desist from
+	 * adding probes in write mapped pages since the breakpoints
+	 * might end up in the file copy.
+	 */
+	if (!valid_vma(vma, is_swbp_insn(&opcode)))
+		goto put_out;
+
+	uprobe = container_of(auprobe, struct uprobe, arch);
+	mapping = uprobe->inode->i_mapping;
+	if (mapping != vma->vm_file->f_mapping)
+		goto put_out;
+
+	addr = vma_address(vma, uprobe->offset);
+	if (vaddr != (unsigned long)addr)
+		goto put_out;
+
+	ret = -ENOMEM;
+	new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
+	if (!new_page)
+		goto put_out;
+
+	__SetPageUptodate(new_page);
+
+	/*
+	 * lock page will serialize against do_wp_page()'s
+	 * PageAnon() handling
+	 */
+	lock_page(old_page);
+	/* copy the page now that we've got it stable */
+	vaddr_old = kmap_atomic(old_page);
+	vaddr_new = kmap_atomic(new_page);
+
+	memcpy(vaddr_new, vaddr_old, PAGE_SIZE);
+
+	/* poke the new insn in, ASSUMES we don't cross page boundary */
+	vaddr &= ~PAGE_MASK;
+	BUG_ON(vaddr + UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
+	memcpy(vaddr_new + vaddr, &opcode, UPROBE_SWBP_INSN_SIZE);
+
+	kunmap_atomic(vaddr_new);
+	kunmap_atomic(vaddr_old);
+
+	ret = anon_vma_prepare(vma);
+	if (ret)
+		goto unlock_out;
+
+	lock_page(new_page);
+	ret = __replace_page(vma, old_page, new_page);
+	unlock_page(new_page);
+
+unlock_out:
+	unlock_page(old_page);
+	page_cache_release(new_page);
+
+put_out:
+	put_page(old_page);
+
+	return ret;
+}
+
+/**
+ * read_opcode - read the opcode at a given virtual address.
+ * @mm: the probed process address space.
+ * @vaddr: the virtual address to read the opcode.
+ * @opcode: location to store the read opcode.
+ *
+ * Called with mm->mmap_sem held (for read and with a reference to
+ * mm.
+ *
+ * For mm @mm, read the opcode at @vaddr and store it in @opcode.
+ * Return 0 (success) or a negative errno.
+ */
+static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t *opcode)
+{
+	struct page *page;
+	void *vaddr_new;
+	int ret;
+
+	ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &page, NULL);
+	if (ret <= 0)
+		return ret;
+
+	lock_page(page);
+	vaddr_new = kmap_atomic(page);
+	vaddr &= ~PAGE_MASK;
+	memcpy(opcode, vaddr_new + vaddr, UPROBE_SWBP_INSN_SIZE);
+	kunmap_atomic(vaddr_new);
+	unlock_page(page);
+
+	put_page(page);
+
+	return 0;
+}
+
+static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
+{
+	uprobe_opcode_t opcode;
+	int result;
+
+	result = read_opcode(mm, vaddr, &opcode);
+	if (result)
+		return result;
+
+	if (is_swbp_insn(&opcode))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * set_swbp - store breakpoint at a given address.
+ * @auprobe: arch specific probepoint information.
+ * @mm: the probed process address space.
+ * @vaddr: the virtual address to insert the opcode.
+ *
+ * For mm @mm, store the breakpoint instruction at @vaddr.
+ * Return 0 (success) or a negative errno.
+ */
+int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
+{
+	int result;
+
+	result = is_swbp_at_addr(mm, vaddr);
+	if (result == 1)
+		return -EEXIST;
+
+	if (result)
+		return result;
+
+	return write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN);
+}
+
+/**
+ * set_orig_insn - Restore the original instruction.
+ * @mm: the probed process address space.
+ * @auprobe: arch specific probepoint information.
+ * @vaddr: the virtual address to insert the opcode.
+ * @verify: if true, verify existance of breakpoint instruction.
+ *
+ * For mm @mm, restore the original opcode (opcode) at @vaddr.
+ * Return 0 (success) or a negative errno.
+ */
+int __weak
+set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr, bool verify)
+{
+	if (verify) {
+		int result;
+
+		result = is_swbp_at_addr(mm, vaddr);
+		if (!result)
+			return -EINVAL;
+
+		if (result != 1)
+			return result;
+	}
+	return write_opcode(auprobe, mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
+}
+
+static int match_uprobe(struct uprobe *l, struct uprobe *r)
+{
+	if (l->inode < r->inode)
+		return -1;
+
+	if (l->inode > r->inode)
+		return 1;
+
+	if (l->offset < r->offset)
+		return -1;
+
+	if (l->offset > r->offset)
+		return 1;
+
+	return 0;
+}
+
+static struct uprobe *__find_uprobe(struct inode *inode, loff_t offset)
+{
+	struct uprobe u = { .inode = inode, .offset = offset };
+	struct rb_node *n = uprobes_tree.rb_node;
+	struct uprobe *uprobe;
+	int match;
+
+	while (n) {
+		uprobe = rb_entry(n, struct uprobe, rb_node);
+		match = match_uprobe(&u, uprobe);
+		if (!match) {
+			atomic_inc(&uprobe->ref);
+			return uprobe;
+		}
+
+		if (match < 0)
+			n = n->rb_left;
+		else
+			n = n->rb_right;
+	}
+	return NULL;
+}
+
+/*
+ * Find a uprobe corresponding to a given inode:offset
+ * Acquires uprobes_treelock
+ */
+static struct uprobe *find_uprobe(struct inode *inode, loff_t offset)
+{
+	struct uprobe *uprobe;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uprobes_treelock, flags);
+	uprobe = __find_uprobe(inode, offset);
+	spin_unlock_irqrestore(&uprobes_treelock, flags);
+
+	return uprobe;
+}
+
+static struct uprobe *__insert_uprobe(struct uprobe *uprobe)
+{
+	struct rb_node **p = &uprobes_tree.rb_node;
+	struct rb_node *parent = NULL;
+	struct uprobe *u;
+	int match;
+
+	while (*p) {
+		parent = *p;
+		u = rb_entry(parent, struct uprobe, rb_node);
+		match = match_uprobe(uprobe, u);
+		if (!match) {
+			atomic_inc(&u->ref);
+			return u;
+		}
+
+		if (match < 0)
+			p = &parent->rb_left;
+		else
+			p = &parent->rb_right;
+
+	}
+
+	u = NULL;
+	rb_link_node(&uprobe->rb_node, parent, p);
+	rb_insert_color(&uprobe->rb_node, &uprobes_tree);
+	/* get access + creation ref */
+	atomic_set(&uprobe->ref, 2);
+
+	return u;
+}
+
+/*
+ * Acquire uprobes_treelock.
+ * Matching uprobe already exists in rbtree;
+ *	increment (access refcount) and return the matching uprobe.
+ *
+ * No matching uprobe; insert the uprobe in rb_tree;
+ *	get a double refcount (access + creation) and return NULL.
+ */
+static struct uprobe *insert_uprobe(struct uprobe *uprobe)
+{
+	unsigned long flags;
+	struct uprobe *u;
+
+	spin_lock_irqsave(&uprobes_treelock, flags);
+	u = __insert_uprobe(uprobe);
+	spin_unlock_irqrestore(&uprobes_treelock, flags);
+
+	/* For now assume that the instruction need not be single-stepped */
+	uprobe->flags |= UPROBE_SKIP_SSTEP;
+
+	return u;
+}
+
+static void put_uprobe(struct uprobe *uprobe)
+{
+	if (atomic_dec_and_test(&uprobe->ref))
+		kfree(uprobe);
+}
+
+static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
+{
+	struct uprobe *uprobe, *cur_uprobe;
+
+	uprobe = kzalloc(sizeof(struct uprobe), GFP_KERNEL);
+	if (!uprobe)
+		return NULL;
+
+	uprobe->inode = igrab(inode);
+	uprobe->offset = offset;
+	init_rwsem(&uprobe->consumer_rwsem);
+	INIT_LIST_HEAD(&uprobe->pending_list);
+
+	/* add to uprobes_tree, sorted on inode:offset */
+	cur_uprobe = insert_uprobe(uprobe);
+
+	/* a uprobe exists for this inode:offset combination */
+	if (cur_uprobe) {
+		kfree(uprobe);
+		uprobe = cur_uprobe;
+		iput(inode);
+	} else {
+		atomic_inc(&uprobe_events);
+	}
+
+	return uprobe;
+}
+
+static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
+{
+	struct uprobe_consumer *uc;
+
+	if (!(uprobe->flags & UPROBE_RUN_HANDLER))
+		return;
+
+	down_read(&uprobe->consumer_rwsem);
+	for (uc = uprobe->consumers; uc; uc = uc->next) {
+		if (!uc->filter || uc->filter(uc, current))
+			uc->handler(uc, regs);
+	}
+	up_read(&uprobe->consumer_rwsem);
+}
+
+/* Returns the previous consumer */
+static struct uprobe_consumer *
+consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc)
+{
+	down_write(&uprobe->consumer_rwsem);
+	uc->next = uprobe->consumers;
+	uprobe->consumers = uc;
+	up_write(&uprobe->consumer_rwsem);
+
+	return uc->next;
+}
+
+/*
+ * For uprobe @uprobe, delete the consumer @uc.
+ * Return true if the @uc is deleted successfully
+ * or return false.
+ */
+static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *uc)
+{
+	struct uprobe_consumer **con;
+	bool ret = false;
+
+	down_write(&uprobe->consumer_rwsem);
+	for (con = &uprobe->consumers; *con; con = &(*con)->next) {
+		if (*con == uc) {
+			*con = uc->next;
+			ret = true;
+			break;
+		}
+	}
+	up_write(&uprobe->consumer_rwsem);
+
+	return ret;
+}
+
+static int
+__copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *insn,
+			unsigned long nbytes, unsigned long offset)
+{
+	struct file *filp = vma->vm_file;
+	struct page *page;
+	void *vaddr;
+	unsigned long off1;
+	unsigned long idx;
+
+	if (!filp)
+		return -EINVAL;
+
+	idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT);
+	off1 = offset &= ~PAGE_MASK;
+
+	/*
+	 * Ensure that the page that has the original instruction is
+	 * populated and in page-cache.
+	 */
+	page = read_mapping_page(mapping, idx, filp);
+	if (IS_ERR(page))
+		return PTR_ERR(page);
+
+	vaddr = kmap_atomic(page);
+	memcpy(insn, vaddr + off1, nbytes);
+	kunmap_atomic(vaddr);
+	page_cache_release(page);
+
+	return 0;
+}
+
+static int
+copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr)
+{
+	struct address_space *mapping;
+	unsigned long nbytes;
+	int bytes;
+
+	addr &= ~PAGE_MASK;
+	nbytes = PAGE_SIZE - addr;
+	mapping = uprobe->inode->i_mapping;
+
+	/* Instruction at end of binary; copy only available bytes */
+	if (uprobe->offset + MAX_UINSN_BYTES > uprobe->inode->i_size)
+		bytes = uprobe->inode->i_size - uprobe->offset;
+	else
+		bytes = MAX_UINSN_BYTES;
+
+	/* Instruction at the page-boundary; copy bytes in second page */
+	if (nbytes < bytes) {
+		if (__copy_insn(mapping, vma, uprobe->arch.insn + nbytes,
+				bytes - nbytes, uprobe->offset + nbytes))
+			return -ENOMEM;
+
+		bytes = nbytes;
+	}
+	return __copy_insn(mapping, vma, uprobe->arch.insn, bytes, uprobe->offset);
+}
+
+/*
+ * How mm->uprobes_state.count gets updated
+ * uprobe_mmap() increments the count if
+ * 	- it successfully adds a breakpoint.
+ * 	- it cannot add a breakpoint, but sees that there is a underlying
+ * 	  breakpoint (via a is_swbp_at_addr()).
+ *
+ * uprobe_munmap() decrements the count if
+ * 	- it sees a underlying breakpoint, (via is_swbp_at_addr)
+ * 	  (Subsequent uprobe_unregister wouldnt find the breakpoint
+ * 	  unless a uprobe_mmap kicks in, since the old vma would be
+ * 	  dropped just after uprobe_munmap.)
+ *
+ * uprobe_register increments the count if:
+ * 	- it successfully adds a breakpoint.
+ *
+ * uprobe_unregister decrements the count if:
+ * 	- it sees a underlying breakpoint and removes successfully.
+ * 	  (via is_swbp_at_addr)
+ * 	  (Subsequent uprobe_munmap wouldnt find the breakpoint
+ * 	  since there is no underlying breakpoint after the
+ * 	  breakpoint removal.)
+ */
+static int
+install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
+			struct vm_area_struct *vma, loff_t vaddr)
+{
+	unsigned long addr;
+	int ret;
+
+	/*
+	 * If probe is being deleted, unregister thread could be done with
+	 * the vma-rmap-walk through. Adding a probe now can be fatal since
+	 * nobody will be able to cleanup. Also we could be from fork or
+	 * mremap path, where the probe might have already been inserted.
+	 * Hence behave as if probe already existed.
+	 */
+	if (!uprobe->consumers)
+		return -EEXIST;
+
+	addr = (unsigned long)vaddr;
+
+	if (!(uprobe->flags & UPROBE_COPY_INSN)) {
+		ret = copy_insn(uprobe, vma, addr);
+		if (ret)
+			return ret;
+
+		if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn))
+			return -EEXIST;
+
+		ret = arch_uprobe_analyze_insn(&uprobe->arch, mm);
+		if (ret)
+			return ret;
+
+		uprobe->flags |= UPROBE_COPY_INSN;
+	}
+
+	/*
+	 * Ideally, should be updating the probe count after the breakpoint
+	 * has been successfully inserted. However a thread could hit the
+	 * breakpoint we just inserted even before the probe count is
+	 * incremented. If this is the first breakpoint placed, breakpoint
+	 * notifier might ignore uprobes and pass the trap to the thread.
+	 * Hence increment before and decrement on failure.
+	 */
+	atomic_inc(&mm->uprobes_state.count);
+	ret = set_swbp(&uprobe->arch, mm, addr);
+	if (ret)
+		atomic_dec(&mm->uprobes_state.count);
+
+	return ret;
+}
+
+static void
+remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, loff_t vaddr)
+{
+	if (!set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true))
+		atomic_dec(&mm->uprobes_state.count);
+}
+
+/*
+ * There could be threads that have hit the breakpoint and are entering the
+ * notifier code and trying to acquire the uprobes_treelock. The thread
+ * calling delete_uprobe() that is removing the uprobe from the rb_tree can
+ * race with these threads and might acquire the uprobes_treelock compared
+ * to some of the breakpoint hit threads. In such a case, the breakpoint
+ * hit threads will not find the uprobe. The current unregistering thread
+ * waits till all other threads have hit a breakpoint, to acquire the
+ * uprobes_treelock before the uprobe is removed from the rbtree.
+ */
+static void delete_uprobe(struct uprobe *uprobe)
+{
+	unsigned long flags;
+
+	synchronize_srcu(&uprobes_srcu);
+	spin_lock_irqsave(&uprobes_treelock, flags);
+	rb_erase(&uprobe->rb_node, &uprobes_tree);
+	spin_unlock_irqrestore(&uprobes_treelock, flags);
+	iput(uprobe->inode);
+	put_uprobe(uprobe);
+	atomic_dec(&uprobe_events);
+}
+
+static struct vma_info *
+__find_next_vma_info(struct address_space *mapping, struct list_head *head,
+			struct vma_info *vi, loff_t offset, bool is_register)
+{
+	struct prio_tree_iter iter;
+	struct vm_area_struct *vma;
+	struct vma_info *tmpvi;
+	unsigned long pgoff;
+	int existing_vma;
+	loff_t vaddr;
+
+	pgoff = offset >> PAGE_SHIFT;
+
+	vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
+		if (!valid_vma(vma, is_register))
+			continue;
+
+		existing_vma = 0;
+		vaddr = vma_address(vma, offset);
+
+		list_for_each_entry(tmpvi, head, probe_list) {
+			if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) {
+				existing_vma = 1;
+				break;
+			}
+		}
+
+		/*
+		 * Another vma needs a probe to be installed. However skip
+		 * installing the probe if the vma is about to be unlinked.
+		 */
+		if (!existing_vma && atomic_inc_not_zero(&vma->vm_mm->mm_users)) {
+			vi->mm = vma->vm_mm;
+			vi->vaddr = vaddr;
+			list_add(&vi->probe_list, head);
+
+			return vi;
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Iterate in the rmap prio tree  and find a vma where a probe has not
+ * yet been inserted.
+ */
+static struct vma_info *
+find_next_vma_info(struct address_space *mapping, struct list_head *head,
+		loff_t offset, bool is_register)
+{
+	struct vma_info *vi, *retvi;
+
+	vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL);
+	if (!vi)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_lock(&mapping->i_mmap_mutex);
+	retvi = __find_next_vma_info(mapping, head, vi, offset, is_register);
+	mutex_unlock(&mapping->i_mmap_mutex);
+
+	if (!retvi)
+		kfree(vi);
+
+	return retvi;
+}
+
+static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
+{
+	struct list_head try_list;
+	struct vm_area_struct *vma;
+	struct address_space *mapping;
+	struct vma_info *vi, *tmpvi;
+	struct mm_struct *mm;
+	loff_t vaddr;
+	int ret;
+
+	mapping = uprobe->inode->i_mapping;
+	INIT_LIST_HEAD(&try_list);
+
+	ret = 0;
+
+	for (;;) {
+		vi = find_next_vma_info(mapping, &try_list, uprobe->offset, is_register);
+		if (!vi)
+			break;
+
+		if (IS_ERR(vi)) {
+			ret = PTR_ERR(vi);
+			break;
+		}
+
+		mm = vi->mm;
+		down_read(&mm->mmap_sem);
+		vma = find_vma(mm, (unsigned long)vi->vaddr);
+		if (!vma || !valid_vma(vma, is_register)) {
+			list_del(&vi->probe_list);
+			kfree(vi);
+			up_read(&mm->mmap_sem);
+			mmput(mm);
+			continue;
+		}
+		vaddr = vma_address(vma, uprobe->offset);
+		if (vma->vm_file->f_mapping->host != uprobe->inode ||
+						vaddr != vi->vaddr) {
+			list_del(&vi->probe_list);
+			kfree(vi);
+			up_read(&mm->mmap_sem);
+			mmput(mm);
+			continue;
+		}
+
+		if (is_register)
+			ret = install_breakpoint(uprobe, mm, vma, vi->vaddr);
+		else
+			remove_breakpoint(uprobe, mm, vi->vaddr);
+
+		up_read(&mm->mmap_sem);
+		mmput(mm);
+		if (is_register) {
+			if (ret && ret == -EEXIST)
+				ret = 0;
+			if (ret)
+				break;
+		}
+	}
+
+	list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) {
+		list_del(&vi->probe_list);
+		kfree(vi);
+	}
+
+	return ret;
+}
+
+static int __uprobe_register(struct uprobe *uprobe)
+{
+	return register_for_each_vma(uprobe, true);
+}
+
+static void __uprobe_unregister(struct uprobe *uprobe)
+{
+	if (!register_for_each_vma(uprobe, false))
+		delete_uprobe(uprobe);
+
+	/* TODO : cant unregister? schedule a worker thread */
+}
+
+/*
+ * uprobe_register - register a probe
+ * @inode: the file in which the probe has to be placed.
+ * @offset: offset from the start of the file.
+ * @uc: information on howto handle the probe..
+ *
+ * Apart from the access refcount, uprobe_register() takes a creation
+ * refcount (thro alloc_uprobe) if and only if this @uprobe is getting
+ * inserted into the rbtree (i.e first consumer for a @inode:@offset
+ * tuple).  Creation refcount stops uprobe_unregister from freeing the
+ * @uprobe even before the register operation is complete. Creation
+ * refcount is released when the last @uc for the @uprobe
+ * unregisters.
+ *
+ * Return errno if it cannot successully install probes
+ * else return 0 (success)
+ */
+int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
+{
+	struct uprobe *uprobe;
+	int ret;
+
+	if (!inode || !uc || uc->next)
+		return -EINVAL;
+
+	if (offset > i_size_read(inode))
+		return -EINVAL;
+
+	ret = 0;
+	mutex_lock(uprobes_hash(inode));
+	uprobe = alloc_uprobe(inode, offset);
+
+	if (uprobe && !consumer_add(uprobe, uc)) {
+		ret = __uprobe_register(uprobe);
+		if (ret) {
+			uprobe->consumers = NULL;
+			__uprobe_unregister(uprobe);
+		} else {
+			uprobe->flags |= UPROBE_RUN_HANDLER;
+		}
+	}
+
+	mutex_unlock(uprobes_hash(inode));
+	put_uprobe(uprobe);
+
+	return ret;
+}
+
+/*
+ * uprobe_unregister - unregister a already registered probe.
+ * @inode: the file in which the probe has to be removed.
+ * @offset: offset from the start of the file.
+ * @uc: identify which probe if multiple probes are colocated.
+ */
+void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
+{
+	struct uprobe *uprobe;
+
+	if (!inode || !uc)
+		return;
+
+	uprobe = find_uprobe(inode, offset);
+	if (!uprobe)
+		return;
+
+	mutex_lock(uprobes_hash(inode));
+
+	if (consumer_del(uprobe, uc)) {
+		if (!uprobe->consumers) {
+			__uprobe_unregister(uprobe);
+			uprobe->flags &= ~UPROBE_RUN_HANDLER;
+		}
+	}
+
+	mutex_unlock(uprobes_hash(inode));
+	if (uprobe)
+		put_uprobe(uprobe);
+}
+
+/*
+ * Of all the nodes that correspond to the given inode, return the node
+ * with the least offset.
+ */
+static struct rb_node *find_least_offset_node(struct inode *inode)
+{
+	struct uprobe u = { .inode = inode, .offset = 0};
+	struct rb_node *n = uprobes_tree.rb_node;
+	struct rb_node *close_node = NULL;
+	struct uprobe *uprobe;
+	int match;
+
+	while (n) {
+		uprobe = rb_entry(n, struct uprobe, rb_node);
+		match = match_uprobe(&u, uprobe);
+
+		if (uprobe->inode == inode)
+			close_node = n;
+
+		if (!match)
+			return close_node;
+
+		if (match < 0)
+			n = n->rb_left;
+		else
+			n = n->rb_right;
+	}
+
+	return close_node;
+}
+
+/*
+ * For a given inode, build a list of probes that need to be inserted.
+ */
+static void build_probe_list(struct inode *inode, struct list_head *head)
+{
+	struct uprobe *uprobe;
+	unsigned long flags;
+	struct rb_node *n;
+
+	spin_lock_irqsave(&uprobes_treelock, flags);
+
+	n = find_least_offset_node(inode);
+
+	for (; n; n = rb_next(n)) {
+		uprobe = rb_entry(n, struct uprobe, rb_node);
+		if (uprobe->inode != inode)
+			break;
+
+		list_add(&uprobe->pending_list, head);
+		atomic_inc(&uprobe->ref);
+	}
+
+	spin_unlock_irqrestore(&uprobes_treelock, flags);
+}
+
+/*
+ * Called from mmap_region.
+ * called with mm->mmap_sem acquired.
+ *
+ * Return -ve no if we fail to insert probes and we cannot
+ * bail-out.
+ * Return 0 otherwise. i.e:
+ *
+ *	- successful insertion of probes
+ *	- (or) no possible probes to be inserted.
+ *	- (or) insertion of probes failed but we can bail-out.
+ */
+int uprobe_mmap(struct vm_area_struct *vma)
+{
+	struct list_head tmp_list;
+	struct uprobe *uprobe, *u;
+	struct inode *inode;
+	int ret, count;
+
+	if (!atomic_read(&uprobe_events) || !valid_vma(vma, true))
+		return 0;
+
+	inode = vma->vm_file->f_mapping->host;
+	if (!inode)
+		return 0;
+
+	INIT_LIST_HEAD(&tmp_list);
+	mutex_lock(uprobes_mmap_hash(inode));
+	build_probe_list(inode, &tmp_list);
+
+	ret = 0;
+	count = 0;
+
+	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
+		loff_t vaddr;
+
+		list_del(&uprobe->pending_list);
+		if (!ret) {
+			vaddr = vma_address(vma, uprobe->offset);
+
+			if (vaddr < vma->vm_start || vaddr >= vma->vm_end) {
+				put_uprobe(uprobe);
+				continue;
+			}
+
+			ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
+
+			/* Ignore double add: */
+			if (ret == -EEXIST) {
+				ret = 0;
+
+				if (!is_swbp_at_addr(vma->vm_mm, vaddr))
+					continue;
+
+				/*
+				 * Unable to insert a breakpoint, but
+				 * breakpoint lies underneath. Increment the
+				 * probe count.
+				 */
+				atomic_inc(&vma->vm_mm->uprobes_state.count);
+			}
+
+			if (!ret)
+				count++;
+		}
+		put_uprobe(uprobe);
+	}
+
+	mutex_unlock(uprobes_mmap_hash(inode));
+
+	if (ret)
+		atomic_sub(count, &vma->vm_mm->uprobes_state.count);
+
+	return ret;
+}
+
+/*
+ * Called in context of a munmap of a vma.
+ */
+void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+	struct list_head tmp_list;
+	struct uprobe *uprobe, *u;
+	struct inode *inode;
+
+	if (!atomic_read(&uprobe_events) || !valid_vma(vma, false))
+		return;
+
+	if (!atomic_read(&vma->vm_mm->uprobes_state.count))
+		return;
+
+	inode = vma->vm_file->f_mapping->host;
+	if (!inode)
+		return;
+
+	INIT_LIST_HEAD(&tmp_list);
+	mutex_lock(uprobes_mmap_hash(inode));
+	build_probe_list(inode, &tmp_list);
+
+	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
+		loff_t vaddr;
+
+		list_del(&uprobe->pending_list);
+		vaddr = vma_address(vma, uprobe->offset);
+
+		if (vaddr >= start && vaddr < end) {
+			/*
+			 * An unregister could have removed the probe before
+			 * unmap. So check before we decrement the count.
+			 */
+			if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1)
+				atomic_dec(&vma->vm_mm->uprobes_state.count);
+		}
+		put_uprobe(uprobe);
+	}
+	mutex_unlock(uprobes_mmap_hash(inode));
+}
+
+/* Slot allocation for XOL */
+static int xol_add_vma(struct xol_area *area)
+{
+	struct mm_struct *mm;
+	int ret;
+
+	area->page = alloc_page(GFP_HIGHUSER);
+	if (!area->page)
+		return -ENOMEM;
+
+	ret = -EALREADY;
+	mm = current->mm;
+
+	down_write(&mm->mmap_sem);
+	if (mm->uprobes_state.xol_area)
+		goto fail;
+
+	ret = -ENOMEM;
+
+	/* Try to map as high as possible, this is only a hint. */
+	area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0);
+	if (area->vaddr & ~PAGE_MASK) {
+		ret = area->vaddr;
+		goto fail;
+	}
+
+	ret = install_special_mapping(mm, area->vaddr, PAGE_SIZE,
+				VM_EXEC|VM_MAYEXEC|VM_DONTCOPY|VM_IO, &area->page);
+	if (ret)
+		goto fail;
+
+	smp_wmb();	/* pairs with get_xol_area() */
+	mm->uprobes_state.xol_area = area;
+	ret = 0;
+
+fail:
+	up_write(&mm->mmap_sem);
+	if (ret)
+		__free_page(area->page);
+
+	return ret;
+}
+
+static struct xol_area *get_xol_area(struct mm_struct *mm)
+{
+	struct xol_area *area;
+
+	area = mm->uprobes_state.xol_area;
+	smp_read_barrier_depends();	/* pairs with wmb in xol_add_vma() */
+
+	return area;
+}
+
+/*
+ * xol_alloc_area - Allocate process's xol_area.
+ * This area will be used for storing instructions for execution out of
+ * line.
+ *
+ * Returns the allocated area or NULL.
+ */
+static struct xol_area *xol_alloc_area(void)
+{
+	struct xol_area *area;
+
+	area = kzalloc(sizeof(*area), GFP_KERNEL);
+	if (unlikely(!area))
+		return NULL;
+
+	area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL);
+
+	if (!area->bitmap)
+		goto fail;
+
+	init_waitqueue_head(&area->wq);
+	if (!xol_add_vma(area))
+		return area;
+
+fail:
+	kfree(area->bitmap);
+	kfree(area);
+
+	return get_xol_area(current->mm);
+}
+
+/*
+ * uprobe_clear_state - Free the area allocated for slots.
+ */
+void uprobe_clear_state(struct mm_struct *mm)
+{
+	struct xol_area *area = mm->uprobes_state.xol_area;
+
+	if (!area)
+		return;
+
+	put_page(area->page);
+	kfree(area->bitmap);
+	kfree(area);
+}
+
+/*
+ * uprobe_reset_state - Free the area allocated for slots.
+ */
+void uprobe_reset_state(struct mm_struct *mm)
+{
+	mm->uprobes_state.xol_area = NULL;
+	atomic_set(&mm->uprobes_state.count, 0);
+}
+
+/*
+ *  - search for a free slot.
+ */
+static unsigned long xol_take_insn_slot(struct xol_area *area)
+{
+	unsigned long slot_addr;
+	int slot_nr;
+
+	do {
+		slot_nr = find_first_zero_bit(area->bitmap, UINSNS_PER_PAGE);
+		if (slot_nr < UINSNS_PER_PAGE) {
+			if (!test_and_set_bit(slot_nr, area->bitmap))
+				break;
+
+			slot_nr = UINSNS_PER_PAGE;
+			continue;
+		}
+		wait_event(area->wq, (atomic_read(&area->slot_count) < UINSNS_PER_PAGE));
+	} while (slot_nr >= UINSNS_PER_PAGE);
+
+	slot_addr = area->vaddr + (slot_nr * UPROBE_XOL_SLOT_BYTES);
+	atomic_inc(&area->slot_count);
+
+	return slot_addr;
+}
+
+/*
+ * xol_get_insn_slot - If was not allocated a slot, then
+ * allocate a slot.
+ * Returns the allocated slot address or 0.
+ */
+static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot_addr)
+{
+	struct xol_area *area;
+	unsigned long offset;
+	void *vaddr;
+
+	area = get_xol_area(current->mm);
+	if (!area) {
+		area = xol_alloc_area();
+		if (!area)
+			return 0;
+	}
+	current->utask->xol_vaddr = xol_take_insn_slot(area);
+
+	/*
+	 * Initialize the slot if xol_vaddr points to valid
+	 * instruction slot.
+	 */
+	if (unlikely(!current->utask->xol_vaddr))
+		return 0;
+
+	current->utask->vaddr = slot_addr;
+	offset = current->utask->xol_vaddr & ~PAGE_MASK;
+	vaddr = kmap_atomic(area->page);
+	memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
+	kunmap_atomic(vaddr);
+
+	return current->utask->xol_vaddr;
+}
+
+/*
+ * xol_free_insn_slot - If slot was earlier allocated by
+ * @xol_get_insn_slot(), make the slot available for
+ * subsequent requests.
+ */
+static void xol_free_insn_slot(struct task_struct *tsk)
+{
+	struct xol_area *area;
+	unsigned long vma_end;
+	unsigned long slot_addr;
+
+	if (!tsk->mm || !tsk->mm->uprobes_state.xol_area || !tsk->utask)
+		return;
+
+	slot_addr = tsk->utask->xol_vaddr;
+
+	if (unlikely(!slot_addr || IS_ERR_VALUE(slot_addr)))
+		return;
+
+	area = tsk->mm->uprobes_state.xol_area;
+	vma_end = area->vaddr + PAGE_SIZE;
+	if (area->vaddr <= slot_addr && slot_addr < vma_end) {
+		unsigned long offset;
+		int slot_nr;
+
+		offset = slot_addr - area->vaddr;
+		slot_nr = offset / UPROBE_XOL_SLOT_BYTES;
+		if (slot_nr >= UINSNS_PER_PAGE)
+			return;
+
+		clear_bit(slot_nr, area->bitmap);
+		atomic_dec(&area->slot_count);
+		if (waitqueue_active(&area->wq))
+			wake_up(&area->wq);
+
+		tsk->utask->xol_vaddr = 0;
+	}
+}
+
+/**
+ * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs
+ * @regs: Reflects the saved state of the task after it has hit a breakpoint
+ * instruction.
+ * Return the address of the breakpoint instruction.
+ */
+unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs)
+{
+	return instruction_pointer(regs) - UPROBE_SWBP_INSN_SIZE;
+}
+
+/*
+ * Called with no locks held.
+ * Called in context of a exiting or a exec-ing thread.
+ */
+void uprobe_free_utask(struct task_struct *t)
+{
+	struct uprobe_task *utask = t->utask;
+
+	if (t->uprobe_srcu_id != -1)
+		srcu_read_unlock_raw(&uprobes_srcu, t->uprobe_srcu_id);
+
+	if (!utask)
+		return;
+
+	if (utask->active_uprobe)
+		put_uprobe(utask->active_uprobe);
+
+	xol_free_insn_slot(t);
+	kfree(utask);
+	t->utask = NULL;
+}
+
+/*
+ * Called in context of a new clone/fork from copy_process.
+ */
+void uprobe_copy_process(struct task_struct *t)
+{
+	t->utask = NULL;
+	t->uprobe_srcu_id = -1;
+}
+
+/*
+ * Allocate a uprobe_task object for the task.
+ * Called when the thread hits a breakpoint for the first time.
+ *
+ * Returns:
+ * - pointer to new uprobe_task on success
+ * - NULL otherwise
+ */
+static struct uprobe_task *add_utask(void)
+{
+	struct uprobe_task *utask;
+
+	utask = kzalloc(sizeof *utask, GFP_KERNEL);
+	if (unlikely(!utask))
+		return NULL;
+
+	utask->active_uprobe = NULL;
+	current->utask = utask;
+	return utask;
+}
+
+/* Prepare to single-step probed instruction out of line. */
+static int
+pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long vaddr)
+{
+	if (xol_get_insn_slot(uprobe, vaddr) && !arch_uprobe_pre_xol(&uprobe->arch, regs))
+		return 0;
+
+	return -EFAULT;
+}
+
+/*
+ * If we are singlestepping, then ensure this thread is not connected to
+ * non-fatal signals until completion of singlestep.  When xol insn itself
+ * triggers the signal,  restart the original insn even if the task is
+ * already SIGKILL'ed (since coredump should report the correct ip).  This
+ * is even more important if the task has a handler for SIGSEGV/etc, The
+ * _same_ instruction should be repeated again after return from the signal
+ * handler, and SSTEP can never finish in this case.
+ */
+bool uprobe_deny_signal(void)
+{
+	struct task_struct *t = current;
+	struct uprobe_task *utask = t->utask;
+
+	if (likely(!utask || !utask->active_uprobe))
+		return false;
+
+	WARN_ON_ONCE(utask->state != UTASK_SSTEP);
+
+	if (signal_pending(t)) {
+		spin_lock_irq(&t->sighand->siglock);
+		clear_tsk_thread_flag(t, TIF_SIGPENDING);
+		spin_unlock_irq(&t->sighand->siglock);
+
+		if (__fatal_signal_pending(t) || arch_uprobe_xol_was_trapped(t)) {
+			utask->state = UTASK_SSTEP_TRAPPED;
+			set_tsk_thread_flag(t, TIF_UPROBE);
+			set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
+		}
+	}
+
+	return true;
+}
+
+/*
+ * Avoid singlestepping the original instruction if the original instruction
+ * is a NOP or can be emulated.
+ */
+static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs)
+{
+	if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
+		return true;
+
+	uprobe->flags &= ~UPROBE_SKIP_SSTEP;
+	return false;
+}
+
+/*
+ * Run handler and ask thread to singlestep.
+ * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
+ */
+static void handle_swbp(struct pt_regs *regs)
+{
+	struct vm_area_struct *vma;
+	struct uprobe_task *utask;
+	struct uprobe *uprobe;
+	struct mm_struct *mm;
+	unsigned long bp_vaddr;
+
+	uprobe = NULL;
+	bp_vaddr = uprobe_get_swbp_addr(regs);
+	mm = current->mm;
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, bp_vaddr);
+
+	if (vma && vma->vm_start <= bp_vaddr && valid_vma(vma, false)) {
+		struct inode *inode;
+		loff_t offset;
+
+		inode = vma->vm_file->f_mapping->host;
+		offset = bp_vaddr - vma->vm_start;
+		offset += (vma->vm_pgoff << PAGE_SHIFT);
+		uprobe = find_uprobe(inode, offset);
+	}
+
+	srcu_read_unlock_raw(&uprobes_srcu, current->uprobe_srcu_id);
+	current->uprobe_srcu_id = -1;
+	up_read(&mm->mmap_sem);
+
+	if (!uprobe) {
+		/* No matching uprobe; signal SIGTRAP. */
+		send_sig(SIGTRAP, current, 0);
+		return;
+	}
+
+	utask = current->utask;
+	if (!utask) {
+		utask = add_utask();
+		/* Cannot allocate; re-execute the instruction. */
+		if (!utask)
+			goto cleanup_ret;
+	}
+	utask->active_uprobe = uprobe;
+	handler_chain(uprobe, regs);
+	if (uprobe->flags & UPROBE_SKIP_SSTEP && can_skip_sstep(uprobe, regs))
+		goto cleanup_ret;
+
+	utask->state = UTASK_SSTEP;
+	if (!pre_ssout(uprobe, regs, bp_vaddr)) {
+		user_enable_single_step(current);
+		return;
+	}
+
+cleanup_ret:
+	if (utask) {
+		utask->active_uprobe = NULL;
+		utask->state = UTASK_RUNNING;
+	}
+	if (uprobe) {
+		if (!(uprobe->flags & UPROBE_SKIP_SSTEP))
+
+			/*
+			 * cannot singlestep; cannot skip instruction;
+			 * re-execute the instruction.
+			 */
+			instruction_pointer_set(regs, bp_vaddr);
+
+		put_uprobe(uprobe);
+	}
+}
+
+/*
+ * Perform required fix-ups and disable singlestep.
+ * Allow pending signals to take effect.
+ */
+static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs)
+{
+	struct uprobe *uprobe;
+
+	uprobe = utask->active_uprobe;
+	if (utask->state == UTASK_SSTEP_ACK)
+		arch_uprobe_post_xol(&uprobe->arch, regs);
+	else if (utask->state == UTASK_SSTEP_TRAPPED)
+		arch_uprobe_abort_xol(&uprobe->arch, regs);
+	else
+		WARN_ON_ONCE(1);
+
+	put_uprobe(uprobe);
+	utask->active_uprobe = NULL;
+	utask->state = UTASK_RUNNING;
+	user_disable_single_step(current);
+	xol_free_insn_slot(current);
+
+	spin_lock_irq(&current->sighand->siglock);
+	recalc_sigpending(); /* see uprobe_deny_signal() */
+	spin_unlock_irq(&current->sighand->siglock);
+}
+
+/*
+ * On breakpoint hit, breakpoint notifier sets the TIF_UPROBE flag.  (and on
+ * subsequent probe hits on the thread sets the state to UTASK_BP_HIT) and
+ * allows the thread to return from interrupt.
+ *
+ * On singlestep exception, singlestep notifier sets the TIF_UPROBE flag and
+ * also sets the state to UTASK_SSTEP_ACK and allows the thread to return from
+ * interrupt.
+ *
+ * While returning to userspace, thread notices the TIF_UPROBE flag and calls
+ * uprobe_notify_resume().
+ */
+void uprobe_notify_resume(struct pt_regs *regs)
+{
+	struct uprobe_task *utask;
+
+	utask = current->utask;
+	if (!utask || utask->state == UTASK_BP_HIT)
+		handle_swbp(regs);
+	else
+		handle_singlestep(utask, regs);
+}
+
+/*
+ * uprobe_pre_sstep_notifier gets called from interrupt context as part of
+ * notifier mechanism. Set TIF_UPROBE flag and indicate breakpoint hit.
+ */
+int uprobe_pre_sstep_notifier(struct pt_regs *regs)
+{
+	struct uprobe_task *utask;
+
+	if (!current->mm || !atomic_read(&current->mm->uprobes_state.count))
+		/* task is currently not uprobed */
+		return 0;
+
+	utask = current->utask;
+	if (utask)
+		utask->state = UTASK_BP_HIT;
+
+	set_thread_flag(TIF_UPROBE);
+	current->uprobe_srcu_id = srcu_read_lock_raw(&uprobes_srcu);
+
+	return 1;
+}
+
+/*
+ * uprobe_post_sstep_notifier gets called in interrupt context as part of notifier
+ * mechanism. Set TIF_UPROBE flag and indicate completion of singlestep.
+ */
+int uprobe_post_sstep_notifier(struct pt_regs *regs)
+{
+	struct uprobe_task *utask = current->utask;
+
+	if (!current->mm || !utask || !utask->active_uprobe)
+		/* task is currently not uprobed */
+		return 0;
+
+	utask->state = UTASK_SSTEP_ACK;
+	set_thread_flag(TIF_UPROBE);
+	return 1;
+}
+
+static struct notifier_block uprobe_exception_nb = {
+	.notifier_call		= arch_uprobe_exception_notify,
+	.priority		= INT_MAX-1,	/* notified after kprobes, kgdb */
+};
+
+static int __init init_uprobes(void)
+{
+	int i;
+
+	for (i = 0; i < UPROBES_HASH_SZ; i++) {
+		mutex_init(&uprobes_mutex[i]);
+		mutex_init(&uprobes_mmap_mutex[i]);
+	}
+	init_srcu_struct(&uprobes_srcu);
+
+	return register_die_notifier(&uprobe_exception_nb);
+}
+module_init(init_uprobes);
+
+static void __exit exit_uprobes(void)
+{
+}
+module_exit(exit_uprobes);
diff --git a/kernel/exit.c b/kernel/exit.c
index d8bd3b42..910a071 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1214,7 +1214,7 @@
 	unsigned long state;
 	int retval, status, traced;
 	pid_t pid = task_pid_vnr(p);
-	uid_t uid = __task_cred(p)->uid;
+	uid_t uid = from_kuid_munged(current_user_ns(), __task_cred(p)->uid);
 	struct siginfo __user *infop;
 
 	if (!likely(wo->wo_flags & WEXITED))
@@ -1427,7 +1427,7 @@
 	if (!unlikely(wo->wo_flags & WNOWAIT))
 		*p_code = 0;
 
-	uid = task_uid(p);
+	uid = from_kuid_munged(current_user_ns(), task_uid(p));
 unlock_sig:
 	spin_unlock_irq(&p->sighand->siglock);
 	if (!exit_code)
@@ -1500,7 +1500,7 @@
 	}
 	if (!unlikely(wo->wo_flags & WNOWAIT))
 		p->signal->flags &= ~SIGNAL_STOP_CONTINUED;
-	uid = task_uid(p);
+	uid = from_kuid_munged(current_user_ns(), task_uid(p));
 	spin_unlock_irq(&p->sighand->siglock);
 
 	pid = task_pid_vnr(p);
diff --git a/kernel/extable.c b/kernel/extable.c
index 5339705..fe35a63 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -35,10 +35,16 @@
 extern struct exception_table_entry __start___ex_table[];
 extern struct exception_table_entry __stop___ex_table[];
 
+/* Cleared by build time tools if the table is already sorted. */
+u32 __initdata main_extable_sort_needed = 1;
+
 /* Sort the kernel's built-in exception table */
 void __init sort_main_extable(void)
 {
-	sort_extable(__start___ex_table, __stop___ex_table);
+	if (main_extable_sort_needed)
+		sort_extable(__start___ex_table, __stop___ex_table);
+	else
+		pr_notice("__ex_table already sorted, skipping sort\n");
 }
 
 /* Given an address, look for it in the exception tables. */
diff --git a/kernel/fork.c b/kernel/fork.c
index ad54c83..47b4e4f 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -69,6 +69,7 @@
 #include <linux/oom.h>
 #include <linux/khugepaged.h>
 #include <linux/signalfd.h>
+#include <linux/uprobes.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -292,8 +293,6 @@
 	int node = tsk_fork_get_node(orig);
 	int err;
 
-	prepare_to_copy(orig);
-
 	tsk = alloc_task_struct_node(node);
 	if (!tsk)
 		return NULL;
@@ -453,6 +452,9 @@
 
 		if (retval)
 			goto out;
+
+		if (file && uprobe_mmap(tmp))
+			goto out;
 	}
 	/* a new mm has just been created */
 	arch_dup_mmap(oldmm, mm);
@@ -601,6 +603,7 @@
 	might_sleep();
 
 	if (atomic_dec_and_test(&mm->mm_users)) {
+		uprobe_clear_state(mm);
 		exit_aio(mm);
 		ksm_exit(mm);
 		khugepaged_exit(mm); /* must run before exit_mmap */
@@ -779,6 +782,8 @@
 		exit_pi_state_list(tsk);
 #endif
 
+	uprobe_free_utask(tsk);
+
 	/* Get rid of any cached register state */
 	deactivate_mm(tsk, mm);
 
@@ -833,6 +838,7 @@
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	mm->pmd_huge_pte = NULL;
 #endif
+	uprobe_reset_state(mm);
 
 	if (!mm_init(mm, tsk))
 		goto fail_nomem;
@@ -1375,6 +1381,7 @@
 	INIT_LIST_HEAD(&p->pi_state_list);
 	p->pi_state_cache = NULL;
 #endif
+	uprobe_copy_process(p);
 	/*
 	 * sigaltstack should be cleared when sharing the same VM
 	 */
diff --git a/kernel/groups.c b/kernel/groups.c
index 99b53d1..6b2588d 100644
--- a/kernel/groups.c
+++ b/kernel/groups.c
@@ -31,7 +31,7 @@
 		group_info->blocks[0] = group_info->small_block;
 	else {
 		for (i = 0; i < nblocks; i++) {
-			gid_t *b;
+			kgid_t *b;
 			b = (void *)__get_free_page(GFP_USER);
 			if (!b)
 				goto out_undo_partial_alloc;
@@ -66,18 +66,15 @@
 static int groups_to_user(gid_t __user *grouplist,
 			  const struct group_info *group_info)
 {
+	struct user_namespace *user_ns = current_user_ns();
 	int i;
 	unsigned int count = group_info->ngroups;
 
-	for (i = 0; i < group_info->nblocks; i++) {
-		unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
-		unsigned int len = cp_count * sizeof(*grouplist);
-
-		if (copy_to_user(grouplist, group_info->blocks[i], len))
+	for (i = 0; i < count; i++) {
+		gid_t gid;
+		gid = from_kgid_munged(user_ns, GROUP_AT(group_info, i));
+		if (put_user(gid, grouplist+i))
 			return -EFAULT;
-
-		grouplist += NGROUPS_PER_BLOCK;
-		count -= cp_count;
 	}
 	return 0;
 }
@@ -86,18 +83,21 @@
 static int groups_from_user(struct group_info *group_info,
     gid_t __user *grouplist)
 {
+	struct user_namespace *user_ns = current_user_ns();
 	int i;
 	unsigned int count = group_info->ngroups;
 
-	for (i = 0; i < group_info->nblocks; i++) {
-		unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
-		unsigned int len = cp_count * sizeof(*grouplist);
-
-		if (copy_from_user(group_info->blocks[i], grouplist, len))
+	for (i = 0; i < count; i++) {
+		gid_t gid;
+		kgid_t kgid;
+		if (get_user(gid, grouplist+i))
 			return -EFAULT;
 
-		grouplist += NGROUPS_PER_BLOCK;
-		count -= cp_count;
+		kgid = make_kgid(user_ns, gid);
+		if (!gid_valid(kgid))
+			return -EINVAL;
+
+		GROUP_AT(group_info, i) = kgid;
 	}
 	return 0;
 }
@@ -117,9 +117,9 @@
 		for (base = 0; base < max; base++) {
 			int left = base;
 			int right = left + stride;
-			gid_t tmp = GROUP_AT(group_info, right);
+			kgid_t tmp = GROUP_AT(group_info, right);
 
-			while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
+			while (left >= 0 && gid_gt(GROUP_AT(group_info, left), tmp)) {
 				GROUP_AT(group_info, right) =
 				    GROUP_AT(group_info, left);
 				right = left;
@@ -132,7 +132,7 @@
 }
 
 /* a simple bsearch */
-int groups_search(const struct group_info *group_info, gid_t grp)
+int groups_search(const struct group_info *group_info, kgid_t grp)
 {
 	unsigned int left, right;
 
@@ -143,9 +143,9 @@
 	right = group_info->ngroups;
 	while (left < right) {
 		unsigned int mid = (left+right)/2;
-		if (grp > GROUP_AT(group_info, mid))
+		if (gid_gt(grp, GROUP_AT(group_info, mid)))
 			left = mid + 1;
-		else if (grp < GROUP_AT(group_info, mid))
+		else if (gid_lt(grp, GROUP_AT(group_info, mid)))
 			right = mid;
 		else
 			return 1;
@@ -256,24 +256,24 @@
 /*
  * Check whether we're fsgid/egid or in the supplemental group..
  */
-int in_group_p(gid_t grp)
+int in_group_p(kgid_t grp)
 {
 	const struct cred *cred = current_cred();
 	int retval = 1;
 
-	if (grp != cred->fsgid)
+	if (!gid_eq(grp, cred->fsgid))
 		retval = groups_search(cred->group_info, grp);
 	return retval;
 }
 
 EXPORT_SYMBOL(in_group_p);
 
-int in_egroup_p(gid_t grp)
+int in_egroup_p(kgid_t grp)
 {
 	const struct cred *cred = current_cred();
 	int retval = 1;
 
-	if (grp != cred->egid)
+	if (!gid_eq(grp, cred->egid))
 		retval = groups_search(cred->group_info, grp);
 	return retval;
 }
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 585f638..bb32326 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1220,12 +1220,6 @@
 	/* Found it - now remove it from the list of entries: */
 	*action_ptr = action->next;
 
-	/* Currently used only by UML, might disappear one day: */
-#ifdef CONFIG_IRQ_RELEASE_METHOD
-	if (desc->irq_data.chip->release)
-		desc->irq_data.chip->release(irq, dev_id);
-#endif
-
 	/* If this was the last handler, shut down the IRQ line: */
 	if (!desc->action)
 		irq_shutdown(desc);
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index c744b88..59dcf5b 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -402,6 +402,7 @@
 		return max;
 	return len;
 }
+EXPORT_SYMBOL(__kfifo_max_r);
 
 #define	__KFIFO_PEEK(data, out, mask) \
 	((data)[(out) & (mask)])
diff --git a/kernel/module.c b/kernel/module.c
index 78ac6ec..4edbd9c 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2429,7 +2429,8 @@
 		goto free_hdr;
 	}
 
-	if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
+	if (hdr->e_shoff >= len ||
+	    hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) {
 		err = -ENOEXEC;
 		goto free_hdr;
 	}
@@ -2953,7 +2954,7 @@
 
 	/* Module is ready to execute: parsing args may do that. */
 	err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
-			 -32768, 32767, NULL);
+			 -32768, 32767, &ddebug_dyndbg_module_param_cb);
 	if (err < 0)
 		goto unlink;
 
diff --git a/kernel/params.c b/kernel/params.c
index f37d826..ed35345 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -85,11 +85,13 @@
 
 static int parse_one(char *param,
 		     char *val,
+		     const char *doing,
 		     const struct kernel_param *params,
 		     unsigned num_params,
 		     s16 min_level,
 		     s16 max_level,
-		     int (*handle_unknown)(char *param, char *val))
+		     int (*handle_unknown)(char *param, char *val,
+				     const char *doing))
 {
 	unsigned int i;
 	int err;
@@ -104,8 +106,8 @@
 			if (!val && params[i].ops->set != param_set_bool
 			    && params[i].ops->set != param_set_bint)
 				return -EINVAL;
-			pr_debug("They are equal!  Calling %p\n",
-			       params[i].ops->set);
+			pr_debug("handling %s with %p\n", param,
+				params[i].ops->set);
 			mutex_lock(&param_lock);
 			err = params[i].ops->set(val, &params[i]);
 			mutex_unlock(&param_lock);
@@ -114,11 +116,11 @@
 	}
 
 	if (handle_unknown) {
-		pr_debug("Unknown argument: calling %p\n", handle_unknown);
-		return handle_unknown(param, val);
+		pr_debug("doing %s: %s='%s'\n", doing, param, val);
+		return handle_unknown(param, val, doing);
 	}
 
-	pr_debug("Unknown argument `%s'\n", param);
+	pr_debug("Unknown argument '%s'\n", param);
 	return -ENOENT;
 }
 
@@ -175,49 +177,47 @@
 }
 
 /* Args looks like "foo=bar,bar2 baz=fuz wiz". */
-int parse_args(const char *name,
+int parse_args(const char *doing,
 	       char *args,
 	       const struct kernel_param *params,
 	       unsigned num,
 	       s16 min_level,
 	       s16 max_level,
-	       int (*unknown)(char *param, char *val))
+	       int (*unknown)(char *param, char *val, const char *doing))
 {
 	char *param, *val;
 
-	pr_debug("Parsing ARGS: %s\n", args);
-
 	/* Chew leading spaces */
 	args = skip_spaces(args);
 
+	if (*args)
+		pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);
+
 	while (*args) {
 		int ret;
 		int irq_was_disabled;
 
 		args = next_arg(args, &param, &val);
 		irq_was_disabled = irqs_disabled();
-		ret = parse_one(param, val, params, num,
+		ret = parse_one(param, val, doing, params, num,
 				min_level, max_level, unknown);
-		if (irq_was_disabled && !irqs_disabled()) {
-			printk(KERN_WARNING "parse_args(): option '%s' enabled "
-					"irq's!\n", param);
-		}
+		if (irq_was_disabled && !irqs_disabled())
+			pr_warn("%s: option '%s' enabled irq's!\n",
+				doing, param);
+
 		switch (ret) {
 		case -ENOENT:
-			printk(KERN_ERR "%s: Unknown parameter `%s'\n",
-			       name, param);
+			pr_err("%s: Unknown parameter `%s'\n", doing, param);
 			return ret;
 		case -ENOSPC:
-			printk(KERN_ERR
-			       "%s: `%s' too large for parameter `%s'\n",
-			       name, val ?: "", param);
+			pr_err("%s: `%s' too large for parameter `%s'\n",
+			       doing, val ?: "", param);
 			return ret;
 		case 0:
 			break;
 		default:
-			printk(KERN_ERR
-			       "%s: `%s' invalid for parameter `%s'\n",
-			       name, val ?: "", param);
+			pr_err("%s: `%s' invalid for parameter `%s'\n",
+			       doing, val ?: "", param);
 			return ret;
 		}
 	}
@@ -263,8 +263,7 @@
 int param_set_charp(const char *val, const struct kernel_param *kp)
 {
 	if (strlen(val) > 1024) {
-		printk(KERN_ERR "%s: string parameter too long\n",
-		       kp->name);
+		pr_err("%s: string parameter too long\n", kp->name);
 		return -ENOSPC;
 	}
 
@@ -400,8 +399,7 @@
 		int len;
 
 		if (*num == max) {
-			printk(KERN_ERR "%s: can only take %i arguments\n",
-			       name, max);
+			pr_err("%s: can only take %i arguments\n", name, max);
 			return -EINVAL;
 		}
 		len = strcspn(val, ",");
@@ -420,8 +418,7 @@
 	} while (save == ',');
 
 	if (*num < min) {
-		printk(KERN_ERR "%s: needs at least %i arguments\n",
-		       name, min);
+		pr_err("%s: needs at least %i arguments\n", name, min);
 		return -EINVAL;
 	}
 	return 0;
@@ -480,7 +477,7 @@
 	const struct kparam_string *kps = kp->str;
 
 	if (strlen(val)+1 > kps->maxlen) {
-		printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
+		pr_err("%s: string doesn't fit in %u chars.\n",
 		       kp->name, kps->maxlen-1);
 		return -ENOSPC;
 	}
@@ -750,11 +747,8 @@
 #endif
 		if (err) {
 			kobject_put(&mk->kobj);
-			printk(KERN_ERR
-				"Module '%s' failed add to sysfs, error number %d\n",
+			pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable.\n",
 				name, err);
-			printk(KERN_ERR
-				"The system will be unstable now.\n");
 			return NULL;
 		}
 
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index deb5461..8f9b4eb 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -103,6 +103,33 @@
 	select HOTPLUG
 	select HOTPLUG_CPU
 
+config PM_AUTOSLEEP
+	bool "Opportunistic sleep"
+	depends on PM_SLEEP
+	default n
+	---help---
+	Allow the kernel to trigger a system transition into a global sleep
+	state automatically whenever there are no active wakeup sources.
+
+config PM_WAKELOCKS
+	bool "User space wakeup sources interface"
+	depends on PM_SLEEP
+	default n
+	---help---
+	Allow user space to create, activate and deactivate wakeup source
+	objects with the help of a sysfs-based interface.
+
+config PM_WAKELOCKS_LIMIT
+	int "Maximum number of user space wakeup sources (0 = no limit)"
+	range 0 100000
+	default 100
+	depends on PM_WAKELOCKS
+
+config PM_WAKELOCKS_GC
+	bool "Garbage collector for user space wakeup sources"
+	depends on PM_WAKELOCKS
+	default y
+
 config PM_RUNTIME
 	bool "Run-time PM core functionality"
 	depends on !IA64_HP_SIM
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 66d808e..29472bf 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -9,5 +9,7 @@
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o \
 				   block_io.o
+obj-$(CONFIG_PM_AUTOSLEEP)	+= autosleep.o
+obj-$(CONFIG_PM_WAKELOCKS)	+= wakelock.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
diff --git a/kernel/power/autosleep.c b/kernel/power/autosleep.c
new file mode 100644
index 0000000..ca304046
--- /dev/null
+++ b/kernel/power/autosleep.c
@@ -0,0 +1,127 @@
+/*
+ * kernel/power/autosleep.c
+ *
+ * Opportunistic sleep support.
+ *
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
+ */
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/pm_wakeup.h>
+
+#include "power.h"
+
+static suspend_state_t autosleep_state;
+static struct workqueue_struct *autosleep_wq;
+/*
+ * Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source
+ * is active, otherwise a deadlock with try_to_suspend() is possible.
+ * Alternatively mutex_lock_interruptible() can be used.  This will then fail
+ * if an auto_sleep cycle tries to freeze processes.
+ */
+static DEFINE_MUTEX(autosleep_lock);
+static struct wakeup_source *autosleep_ws;
+
+static void try_to_suspend(struct work_struct *work)
+{
+	unsigned int initial_count, final_count;
+
+	if (!pm_get_wakeup_count(&initial_count, true))
+		goto out;
+
+	mutex_lock(&autosleep_lock);
+
+	if (!pm_save_wakeup_count(initial_count)) {
+		mutex_unlock(&autosleep_lock);
+		goto out;
+	}
+
+	if (autosleep_state == PM_SUSPEND_ON) {
+		mutex_unlock(&autosleep_lock);
+		return;
+	}
+	if (autosleep_state >= PM_SUSPEND_MAX)
+		hibernate();
+	else
+		pm_suspend(autosleep_state);
+
+	mutex_unlock(&autosleep_lock);
+
+	if (!pm_get_wakeup_count(&final_count, false))
+		goto out;
+
+	/*
+	 * If the wakeup occured for an unknown reason, wait to prevent the
+	 * system from trying to suspend and waking up in a tight loop.
+	 */
+	if (final_count == initial_count)
+		schedule_timeout_uninterruptible(HZ / 2);
+
+ out:
+	queue_up_suspend_work();
+}
+
+static DECLARE_WORK(suspend_work, try_to_suspend);
+
+void queue_up_suspend_work(void)
+{
+	if (!work_pending(&suspend_work) && autosleep_state > PM_SUSPEND_ON)
+		queue_work(autosleep_wq, &suspend_work);
+}
+
+suspend_state_t pm_autosleep_state(void)
+{
+	return autosleep_state;
+}
+
+int pm_autosleep_lock(void)
+{
+	return mutex_lock_interruptible(&autosleep_lock);
+}
+
+void pm_autosleep_unlock(void)
+{
+	mutex_unlock(&autosleep_lock);
+}
+
+int pm_autosleep_set_state(suspend_state_t state)
+{
+
+#ifndef CONFIG_HIBERNATION
+	if (state >= PM_SUSPEND_MAX)
+		return -EINVAL;
+#endif
+
+	__pm_stay_awake(autosleep_ws);
+
+	mutex_lock(&autosleep_lock);
+
+	autosleep_state = state;
+
+	__pm_relax(autosleep_ws);
+
+	if (state > PM_SUSPEND_ON) {
+		pm_wakep_autosleep_enabled(true);
+		queue_up_suspend_work();
+	} else {
+		pm_wakep_autosleep_enabled(false);
+	}
+
+	mutex_unlock(&autosleep_lock);
+	return 0;
+}
+
+int __init pm_autosleep_init(void)
+{
+	autosleep_ws = wakeup_source_register("autosleep");
+	if (!autosleep_ws)
+		return -ENOMEM;
+
+	autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
+	if (autosleep_wq)
+		return 0;
+
+	wakeup_source_unregister(autosleep_ws);
+	return -ENOMEM;
+}
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index e09dfbf..8b53db3 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -25,6 +25,8 @@
 #include <linux/freezer.h>
 #include <linux/gfp.h>
 #include <linux/syscore_ops.h>
+#include <linux/ctype.h>
+#include <linux/genhd.h>
 #include <scsi/scsi_scan.h>
 
 #include "power.h"
@@ -722,6 +724,17 @@
 
 	/* Check if the device is there */
 	swsusp_resume_device = name_to_dev_t(resume_file);
+
+	/*
+	 * name_to_dev_t is ineffective to verify parition if resume_file is in
+	 * integer format. (e.g. major:minor)
+	 */
+	if (isdigit(resume_file[0]) && resume_wait) {
+		int partno;
+		while (!get_gendisk(swsusp_resume_device, &partno))
+			msleep(10);
+	}
+
 	if (!swsusp_resume_device) {
 		/*
 		 * Some device discovery might still be in progress; we need
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 1c12581..428f8a0 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -269,8 +269,7 @@
 	return (s - buf);
 }
 
-static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
-			   const char *buf, size_t n)
+static suspend_state_t decode_state(const char *buf, size_t n)
 {
 #ifdef CONFIG_SUSPEND
 	suspend_state_t state = PM_SUSPEND_STANDBY;
@@ -278,27 +277,48 @@
 #endif
 	char *p;
 	int len;
-	int error = -EINVAL;
 
 	p = memchr(buf, '\n', n);
 	len = p ? p - buf : n;
 
-	/* First, check if we are requested to hibernate */
-	if (len == 4 && !strncmp(buf, "disk", len)) {
-		error = hibernate();
-		goto Exit;
-	}
+	/* Check hibernation first. */
+	if (len == 4 && !strncmp(buf, "disk", len))
+		return PM_SUSPEND_MAX;
 
 #ifdef CONFIG_SUSPEND
-	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
-		if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
-			error = pm_suspend(state);
-			break;
-		}
-	}
+	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++)
+		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
+			return state;
 #endif
 
- Exit:
+	return PM_SUSPEND_ON;
+}
+
+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
+			   const char *buf, size_t n)
+{
+	suspend_state_t state;
+	int error;
+
+	error = pm_autosleep_lock();
+	if (error)
+		return error;
+
+	if (pm_autosleep_state() > PM_SUSPEND_ON) {
+		error = -EBUSY;
+		goto out;
+	}
+
+	state = decode_state(buf, n);
+	if (state < PM_SUSPEND_MAX)
+		error = pm_suspend(state);
+	else if (state == PM_SUSPEND_MAX)
+		error = hibernate();
+	else
+		error = -EINVAL;
+
+ out:
+	pm_autosleep_unlock();
 	return error ? error : n;
 }
 
@@ -339,7 +359,8 @@
 {
 	unsigned int val;
 
-	return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR;
+	return pm_get_wakeup_count(&val, true) ?
+		sprintf(buf, "%u\n", val) : -EINTR;
 }
 
 static ssize_t wakeup_count_store(struct kobject *kobj,
@@ -347,15 +368,106 @@
 				const char *buf, size_t n)
 {
 	unsigned int val;
+	int error;
 
+	error = pm_autosleep_lock();
+	if (error)
+		return error;
+
+	if (pm_autosleep_state() > PM_SUSPEND_ON) {
+		error = -EBUSY;
+		goto out;
+	}
+
+	error = -EINVAL;
 	if (sscanf(buf, "%u", &val) == 1) {
 		if (pm_save_wakeup_count(val))
-			return n;
+			error = n;
 	}
-	return -EINVAL;
+
+ out:
+	pm_autosleep_unlock();
+	return error;
 }
 
 power_attr(wakeup_count);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t autosleep_show(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      char *buf)
+{
+	suspend_state_t state = pm_autosleep_state();
+
+	if (state == PM_SUSPEND_ON)
+		return sprintf(buf, "off\n");
+
+#ifdef CONFIG_SUSPEND
+	if (state < PM_SUSPEND_MAX)
+		return sprintf(buf, "%s\n", valid_state(state) ?
+						pm_states[state] : "error");
+#endif
+#ifdef CONFIG_HIBERNATION
+	return sprintf(buf, "disk\n");
+#else
+	return sprintf(buf, "error");
+#endif
+}
+
+static ssize_t autosleep_store(struct kobject *kobj,
+			       struct kobj_attribute *attr,
+			       const char *buf, size_t n)
+{
+	suspend_state_t state = decode_state(buf, n);
+	int error;
+
+	if (state == PM_SUSPEND_ON
+	    && strcmp(buf, "off") && strcmp(buf, "off\n"))
+		return -EINVAL;
+
+	error = pm_autosleep_set_state(state);
+	return error ? error : n;
+}
+
+power_attr(autosleep);
+#endif /* CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+static ssize_t wake_lock_show(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      char *buf)
+{
+	return pm_show_wakelocks(buf, true);
+}
+
+static ssize_t wake_lock_store(struct kobject *kobj,
+			       struct kobj_attribute *attr,
+			       const char *buf, size_t n)
+{
+	int error = pm_wake_lock(buf);
+	return error ? error : n;
+}
+
+power_attr(wake_lock);
+
+static ssize_t wake_unlock_show(struct kobject *kobj,
+				struct kobj_attribute *attr,
+				char *buf)
+{
+	return pm_show_wakelocks(buf, false);
+}
+
+static ssize_t wake_unlock_store(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf, size_t n)
+{
+	int error = pm_wake_unlock(buf);
+	return error ? error : n;
+}
+
+power_attr(wake_unlock);
+
+#endif /* CONFIG_PM_WAKELOCKS */
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_TRACE
@@ -409,6 +521,13 @@
 #ifdef CONFIG_PM_SLEEP
 	&pm_async_attr.attr,
 	&wakeup_count_attr.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+	&autosleep_attr.attr,
+#endif
+#ifdef CONFIG_PM_WAKELOCKS
+	&wake_lock_attr.attr,
+	&wake_unlock_attr.attr,
+#endif
 #ifdef CONFIG_PM_DEBUG
 	&pm_test_attr.attr,
 #endif
@@ -444,7 +563,10 @@
 	power_kobj = kobject_create_and_add("power", NULL);
 	if (!power_kobj)
 		return -ENOMEM;
-	return sysfs_create_group(power_kobj, &attr_group);
+	error = sysfs_create_group(power_kobj, &attr_group);
+	if (error)
+		return error;
+	return pm_autosleep_init();
 }
 
 core_initcall(pm_init);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 98f3622..b0bd4be 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -264,3 +264,30 @@
 {
 }
 #endif
+
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+extern int pm_autosleep_init(void);
+extern int pm_autosleep_lock(void);
+extern void pm_autosleep_unlock(void);
+extern suspend_state_t pm_autosleep_state(void);
+extern int pm_autosleep_set_state(suspend_state_t state);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline int pm_autosleep_init(void) { return 0; }
+static inline int pm_autosleep_lock(void) { return 0; }
+static inline void pm_autosleep_unlock(void) {}
+static inline suspend_state_t pm_autosleep_state(void) { return PM_SUSPEND_ON; }
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+
+/* kernel/power/wakelock.c */
+extern ssize_t pm_show_wakelocks(char *buf, bool show_active);
+extern int pm_wake_lock(const char *buf);
+extern int pm_wake_unlock(const char *buf);
+
+#endif /* !CONFIG_PM_WAKELOCKS */
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index eef311a..11e22c0 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -6,7 +6,7 @@
  *
  * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
  * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
- * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com>
+ * Copyright (C) 2010-2012 Bojan Smojver <bojan@rexursive.com>
  *
  * This file is released under the GPLv2.
  *
@@ -282,14 +282,17 @@
 		return -ENOSPC;
 
 	if (bio_chain) {
-		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+		src = (void *)__get_free_page(__GFP_WAIT | __GFP_NOWARN |
+		                              __GFP_NORETRY);
 		if (src) {
 			copy_page(src, buf);
 		} else {
 			ret = hib_wait_on_bio_chain(bio_chain); /* Free pages */
 			if (ret)
 				return ret;
-			src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+			src = (void *)__get_free_page(__GFP_WAIT |
+			                              __GFP_NOWARN |
+			                              __GFP_NORETRY);
 			if (src) {
 				copy_page(src, buf);
 			} else {
@@ -367,12 +370,17 @@
 		clear_page(handle->cur);
 		handle->cur_swap = offset;
 		handle->k = 0;
-	}
-	if (bio_chain && low_free_pages() <= handle->reqd_free_pages) {
-		error = hib_wait_on_bio_chain(bio_chain);
-		if (error)
-			goto out;
-		handle->reqd_free_pages = reqd_free_pages();
+
+		if (bio_chain && low_free_pages() <= handle->reqd_free_pages) {
+			error = hib_wait_on_bio_chain(bio_chain);
+			if (error)
+				goto out;
+			/*
+			 * Recalculate the number of required free pages, to
+			 * make sure we never take more than half.
+			 */
+			handle->reqd_free_pages = reqd_free_pages();
+		}
 	}
  out:
 	return error;
@@ -419,8 +427,9 @@
 /* Maximum number of threads for compression/decompression. */
 #define LZO_THREADS	3
 
-/* Maximum number of pages for read buffering. */
-#define LZO_READ_PAGES	(MAP_PAGE_ENTRIES * 8)
+/* Minimum/maximum number of pages for read buffering. */
+#define LZO_MIN_RD_PAGES	1024
+#define LZO_MAX_RD_PAGES	8192
 
 
 /**
@@ -631,12 +640,6 @@
 	}
 
 	/*
-	 * Adjust number of free pages after all allocations have been done.
-	 * We don't want to run out of pages when writing.
-	 */
-	handle->reqd_free_pages = reqd_free_pages();
-
-	/*
 	 * Start the CRC32 thread.
 	 */
 	init_waitqueue_head(&crc->go);
@@ -657,6 +660,12 @@
 		goto out_clean;
 	}
 
+	/*
+	 * Adjust the number of required free pages after all allocations have
+	 * been done. We don't want to run out of pages when writing.
+	 */
+	handle->reqd_free_pages = reqd_free_pages();
+
 	printk(KERN_INFO
 		"PM: Using %u thread(s) for compression.\n"
 		"PM: Compressing and saving image data (%u pages) ...     ",
@@ -1067,7 +1076,7 @@
 	unsigned i, thr, run_threads, nr_threads;
 	unsigned ring = 0, pg = 0, ring_size = 0,
 	         have = 0, want, need, asked = 0;
-	unsigned long read_pages;
+	unsigned long read_pages = 0;
 	unsigned char **page = NULL;
 	struct dec_data *data = NULL;
 	struct crc_data *crc = NULL;
@@ -1079,7 +1088,7 @@
 	nr_threads = num_online_cpus() - 1;
 	nr_threads = clamp_val(nr_threads, 1, LZO_THREADS);
 
-	page = vmalloc(sizeof(*page) * LZO_READ_PAGES);
+	page = vmalloc(sizeof(*page) * LZO_MAX_RD_PAGES);
 	if (!page) {
 		printk(KERN_ERR "PM: Failed to allocate LZO page\n");
 		ret = -ENOMEM;
@@ -1144,15 +1153,22 @@
 	}
 
 	/*
-	 * Adjust number of pages for read buffering, in case we are short.
+	 * Set the number of pages for read buffering.
+	 * This is complete guesswork, because we'll only know the real
+	 * picture once prepare_image() is called, which is much later on
+	 * during the image load phase. We'll assume the worst case and
+	 * say that none of the image pages are from high memory.
 	 */
-	read_pages = (nr_free_pages() - snapshot_get_image_size()) >> 1;
-	read_pages = clamp_val(read_pages, LZO_CMP_PAGES, LZO_READ_PAGES);
+	if (low_free_pages() > snapshot_get_image_size())
+		read_pages = (low_free_pages() - snapshot_get_image_size()) / 2;
+	read_pages = clamp_val(read_pages, LZO_MIN_RD_PAGES, LZO_MAX_RD_PAGES);
 
 	for (i = 0; i < read_pages; i++) {
 		page[i] = (void *)__get_free_page(i < LZO_CMP_PAGES ?
 		                                  __GFP_WAIT | __GFP_HIGH :
-		                                  __GFP_WAIT);
+		                                  __GFP_WAIT | __GFP_NOWARN |
+		                                  __GFP_NORETRY);
+
 		if (!page[i]) {
 			if (i < LZO_CMP_PAGES) {
 				ring_size = i;
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
new file mode 100644
index 0000000..c8fba33
--- /dev/null
+++ b/kernel/power/wakelock.c
@@ -0,0 +1,259 @@
+/*
+ * kernel/power/wakelock.c
+ *
+ * User space wakeup sources support.
+ *
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
+ *
+ * This code is based on the analogous interface allowing user space to
+ * manipulate wakelocks on Android.
+ */
+
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(wakelocks_lock);
+
+struct wakelock {
+	char			*name;
+	struct rb_node		node;
+	struct wakeup_source	ws;
+#ifdef CONFIG_PM_WAKELOCKS_GC
+	struct list_head	lru;
+#endif
+};
+
+static struct rb_root wakelocks_tree = RB_ROOT;
+
+ssize_t pm_show_wakelocks(char *buf, bool show_active)
+{
+	struct rb_node *node;
+	struct wakelock *wl;
+	char *str = buf;
+	char *end = buf + PAGE_SIZE;
+
+	mutex_lock(&wakelocks_lock);
+
+	for (node = rb_first(&wakelocks_tree); node; node = rb_next(node)) {
+		wl = rb_entry(node, struct wakelock, node);
+		if (wl->ws.active == show_active)
+			str += scnprintf(str, end - str, "%s ", wl->name);
+	}
+	if (str > buf)
+		str--;
+
+	str += scnprintf(str, end - str, "\n");
+
+	mutex_unlock(&wakelocks_lock);
+	return (str - buf);
+}
+
+#if CONFIG_PM_WAKELOCKS_LIMIT > 0
+static unsigned int number_of_wakelocks;
+
+static inline bool wakelocks_limit_exceeded(void)
+{
+	return number_of_wakelocks > CONFIG_PM_WAKELOCKS_LIMIT;
+}
+
+static inline void increment_wakelocks_number(void)
+{
+	number_of_wakelocks++;
+}
+
+static inline void decrement_wakelocks_number(void)
+{
+	number_of_wakelocks--;
+}
+#else /* CONFIG_PM_WAKELOCKS_LIMIT = 0 */
+static inline bool wakelocks_limit_exceeded(void) { return false; }
+static inline void increment_wakelocks_number(void) {}
+static inline void decrement_wakelocks_number(void) {}
+#endif /* CONFIG_PM_WAKELOCKS_LIMIT */
+
+#ifdef CONFIG_PM_WAKELOCKS_GC
+#define WL_GC_COUNT_MAX	100
+#define WL_GC_TIME_SEC	300
+
+static LIST_HEAD(wakelocks_lru_list);
+static unsigned int wakelocks_gc_count;
+
+static inline void wakelocks_lru_add(struct wakelock *wl)
+{
+	list_add(&wl->lru, &wakelocks_lru_list);
+}
+
+static inline void wakelocks_lru_most_recent(struct wakelock *wl)
+{
+	list_move(&wl->lru, &wakelocks_lru_list);
+}
+
+static void wakelocks_gc(void)
+{
+	struct wakelock *wl, *aux;
+	ktime_t now;
+
+	if (++wakelocks_gc_count <= WL_GC_COUNT_MAX)
+		return;
+
+	now = ktime_get();
+	list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
+		u64 idle_time_ns;
+		bool active;
+
+		spin_lock_irq(&wl->ws.lock);
+		idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
+		active = wl->ws.active;
+		spin_unlock_irq(&wl->ws.lock);
+
+		if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
+			break;
+
+		if (!active) {
+			wakeup_source_remove(&wl->ws);
+			rb_erase(&wl->node, &wakelocks_tree);
+			list_del(&wl->lru);
+			kfree(wl->name);
+			kfree(wl);
+			decrement_wakelocks_number();
+		}
+	}
+	wakelocks_gc_count = 0;
+}
+#else /* !CONFIG_PM_WAKELOCKS_GC */
+static inline void wakelocks_lru_add(struct wakelock *wl) {}
+static inline void wakelocks_lru_most_recent(struct wakelock *wl) {}
+static inline void wakelocks_gc(void) {}
+#endif /* !CONFIG_PM_WAKELOCKS_GC */
+
+static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
+					    bool add_if_not_found)
+{
+	struct rb_node **node = &wakelocks_tree.rb_node;
+	struct rb_node *parent = *node;
+	struct wakelock *wl;
+
+	while (*node) {
+		int diff;
+
+		parent = *node;
+		wl = rb_entry(*node, struct wakelock, node);
+		diff = strncmp(name, wl->name, len);
+		if (diff == 0) {
+			if (wl->name[len])
+				diff = -1;
+			else
+				return wl;
+		}
+		if (diff < 0)
+			node = &(*node)->rb_left;
+		else
+			node = &(*node)->rb_right;
+	}
+	if (!add_if_not_found)
+		return ERR_PTR(-EINVAL);
+
+	if (wakelocks_limit_exceeded())
+		return ERR_PTR(-ENOSPC);
+
+	/* Not found, we have to add a new one. */
+	wl = kzalloc(sizeof(*wl), GFP_KERNEL);
+	if (!wl)
+		return ERR_PTR(-ENOMEM);
+
+	wl->name = kstrndup(name, len, GFP_KERNEL);
+	if (!wl->name) {
+		kfree(wl);
+		return ERR_PTR(-ENOMEM);
+	}
+	wl->ws.name = wl->name;
+	wakeup_source_add(&wl->ws);
+	rb_link_node(&wl->node, parent, node);
+	rb_insert_color(&wl->node, &wakelocks_tree);
+	wakelocks_lru_add(wl);
+	increment_wakelocks_number();
+	return wl;
+}
+
+int pm_wake_lock(const char *buf)
+{
+	const char *str = buf;
+	struct wakelock *wl;
+	u64 timeout_ns = 0;
+	size_t len;
+	int ret = 0;
+
+	while (*str && !isspace(*str))
+		str++;
+
+	len = str - buf;
+	if (!len)
+		return -EINVAL;
+
+	if (*str && *str != '\n') {
+		/* Find out if there's a valid timeout string appended. */
+		ret = kstrtou64(skip_spaces(str), 10, &timeout_ns);
+		if (ret)
+			return -EINVAL;
+	}
+
+	mutex_lock(&wakelocks_lock);
+
+	wl = wakelock_lookup_add(buf, len, true);
+	if (IS_ERR(wl)) {
+		ret = PTR_ERR(wl);
+		goto out;
+	}
+	if (timeout_ns) {
+		u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;
+
+		do_div(timeout_ms, NSEC_PER_MSEC);
+		__pm_wakeup_event(&wl->ws, timeout_ms);
+	} else {
+		__pm_stay_awake(&wl->ws);
+	}
+
+	wakelocks_lru_most_recent(wl);
+
+ out:
+	mutex_unlock(&wakelocks_lock);
+	return ret;
+}
+
+int pm_wake_unlock(const char *buf)
+{
+	struct wakelock *wl;
+	size_t len;
+	int ret = 0;
+
+	len = strlen(buf);
+	if (!len)
+		return -EINVAL;
+
+	if (buf[len-1] == '\n')
+		len--;
+
+	if (!len)
+		return -EINVAL;
+
+	mutex_lock(&wakelocks_lock);
+
+	wl = wakelock_lookup_add(buf, len, false);
+	if (IS_ERR(wl)) {
+		ret = PTR_ERR(wl);
+		goto out;
+	}
+	__pm_relax(&wl->ws);
+
+	wakelocks_lru_most_recent(wl);
+	wakelocks_gc();
+
+ out:
+	mutex_unlock(&wakelocks_lock);
+	return ret;
+}
diff --git a/kernel/printk.c b/kernel/printk.c
index b663c2c..32462d2 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -41,6 +41,7 @@
 #include <linux/cpu.h>
 #include <linux/notifier.h>
 #include <linux/rculist.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 
@@ -54,8 +55,6 @@
 {
 }
 
-#define __LOG_BUF_LEN	(1 << CONFIG_LOG_BUF_SHIFT)
-
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
 
@@ -99,24 +98,6 @@
 static int console_locked, console_suspended;
 
 /*
- * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
- * It is also used in interesting ways to provide interlocking in
- * console_unlock();.
- */
-static DEFINE_RAW_SPINLOCK(logbuf_lock);
-
-#define LOG_BUF_MASK (log_buf_len-1)
-#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
-
-/*
- * The indices into log_buf are not constrained to log_buf_len - they
- * must be masked before subscripting
- */
-static unsigned log_start;	/* Index into log_buf: next char to be read by syslog() */
-static unsigned con_start;	/* Index into log_buf: next char to be sent to consoles */
-static unsigned log_end;	/* Index into log_buf: most-recently-written-char + 1 */
-
-/*
  * If exclusive_console is non-NULL then only this console is to be printed to.
  */
 static struct console *exclusive_console;
@@ -145,13 +126,491 @@
 /* Flag: console code may call schedule() */
 static int console_may_schedule;
 
-#ifdef CONFIG_PRINTK
+/*
+ * The printk log buffer consists of a chain of concatenated variable
+ * length records. Every record starts with a record header, containing
+ * the overall length of the record.
+ *
+ * The heads to the first and last entry in the buffer, as well as the
+ * sequence numbers of these both entries are maintained when messages
+ * are stored..
+ *
+ * If the heads indicate available messages, the length in the header
+ * tells the start next message. A length == 0 for the next message
+ * indicates a wrap-around to the beginning of the buffer.
+ *
+ * Every record carries the monotonic timestamp in microseconds, as well as
+ * the standard userspace syslog level and syslog facility. The usual
+ * kernel messages use LOG_KERN; userspace-injected messages always carry
+ * a matching syslog facility, by default LOG_USER. The origin of every
+ * message can be reliably determined that way.
+ *
+ * The human readable log message directly follows the message header. The
+ * length of the message text is stored in the header, the stored message
+ * is not terminated.
+ *
+ * Optionally, a message can carry a dictionary of properties (key/value pairs),
+ * to provide userspace with a machine-readable message context.
+ *
+ * Examples for well-defined, commonly used property names are:
+ *   DEVICE=b12:8               device identifier
+ *                                b12:8         block dev_t
+ *                                c127:3        char dev_t
+ *                                n8            netdev ifindex
+ *                                +sound:card0  subsystem:devname
+ *   SUBSYSTEM=pci              driver-core subsystem name
+ *
+ * Valid characters in property names are [a-zA-Z0-9.-_]. The plain text value
+ * follows directly after a '=' character. Every property is terminated by
+ * a '\0' character. The last property is not terminated.
+ *
+ * Example of a message structure:
+ *   0000  ff 8f 00 00 00 00 00 00      monotonic time in nsec
+ *   0008  34 00                        record is 52 bytes long
+ *   000a        0b 00                  text is 11 bytes long
+ *   000c              1f 00            dictionary is 23 bytes long
+ *   000e                    03 00      LOG_KERN (facility) LOG_ERR (level)
+ *   0010  69 74 27 73 20 61 20 6c      "it's a l"
+ *         69 6e 65                     "ine"
+ *   001b           44 45 56 49 43      "DEVIC"
+ *         45 3d 62 38 3a 32 00 44      "E=b8:2\0D"
+ *         52 49 56 45 52 3d 62 75      "RIVER=bu"
+ *         67                           "g"
+ *   0032     00 00 00                  padding to next message header
+ *
+ * The 'struct log' buffer header must never be directly exported to
+ * userspace, it is a kernel-private implementation detail that might
+ * need to be changed in the future, when the requirements change.
+ *
+ * /dev/kmsg exports the structured data in the following line format:
+ *   "level,sequnum,timestamp;<message text>\n"
+ *
+ * The optional key/value pairs are attached as continuation lines starting
+ * with a space character and terminated by a newline. All possible
+ * non-prinatable characters are escaped in the "\xff" notation.
+ *
+ * Users of the export format should ignore possible additional values
+ * separated by ',', and find the message after the ';' character.
+ */
 
-static char __log_buf[__LOG_BUF_LEN];
+struct log {
+	u64 ts_nsec;		/* timestamp in nanoseconds */
+	u16 len;		/* length of entire record */
+	u16 text_len;		/* length of text buffer */
+	u16 dict_len;		/* length of dictionary buffer */
+	u16 level;		/* syslog level + facility */
+};
+
+/*
+ * The logbuf_lock protects kmsg buffer, indices, counters. It is also
+ * used in interesting ways to provide interlocking in console_unlock();
+ */
+static DEFINE_RAW_SPINLOCK(logbuf_lock);
+
+/* the next printk record to read by syslog(READ) or /proc/kmsg */
+static u64 syslog_seq;
+static u32 syslog_idx;
+
+/* index and sequence number of the first record stored in the buffer */
+static u64 log_first_seq;
+static u32 log_first_idx;
+
+/* index and sequence number of the next record to store in the buffer */
+static u64 log_next_seq;
+#ifdef CONFIG_PRINTK
+static u32 log_next_idx;
+
+/* the next printk record to read after the last 'clear' command */
+static u64 clear_seq;
+static u32 clear_idx;
+
+#define LOG_LINE_MAX 1024
+
+/* record buffer */
+#if !defined(CONFIG_64BIT) || defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+#define LOG_ALIGN 4
+#else
+#define LOG_ALIGN 8
+#endif
+#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
+static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
 static char *log_buf = __log_buf;
-static int log_buf_len = __LOG_BUF_LEN;
-static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
-static int saved_console_loglevel = -1;
+static u32 log_buf_len = __LOG_BUF_LEN;
+
+/* cpu currently holding logbuf_lock */
+static volatile unsigned int logbuf_cpu = UINT_MAX;
+
+/* human readable text of the record */
+static char *log_text(const struct log *msg)
+{
+	return (char *)msg + sizeof(struct log);
+}
+
+/* optional key/value pair dictionary attached to the record */
+static char *log_dict(const struct log *msg)
+{
+	return (char *)msg + sizeof(struct log) + msg->text_len;
+}
+
+/* get record by index; idx must point to valid msg */
+static struct log *log_from_idx(u32 idx)
+{
+	struct log *msg = (struct log *)(log_buf + idx);
+
+	/*
+	 * A length == 0 record is the end of buffer marker. Wrap around and
+	 * read the message at the start of the buffer.
+	 */
+	if (!msg->len)
+		return (struct log *)log_buf;
+	return msg;
+}
+
+/* get next record; idx must point to valid msg */
+static u32 log_next(u32 idx)
+{
+	struct log *msg = (struct log *)(log_buf + idx);
+
+	/* length == 0 indicates the end of the buffer; wrap */
+	/*
+	 * A length == 0 record is the end of buffer marker. Wrap around and
+	 * read the message at the start of the buffer as *this* one, and
+	 * return the one after that.
+	 */
+	if (!msg->len) {
+		msg = (struct log *)log_buf;
+		return msg->len;
+	}
+	return idx + msg->len;
+}
+
+/* insert record into the buffer, discard old ones, update heads */
+static void log_store(int facility, int level,
+		      const char *dict, u16 dict_len,
+		      const char *text, u16 text_len)
+{
+	struct log *msg;
+	u32 size, pad_len;
+
+	/* number of '\0' padding bytes to next message */
+	size = sizeof(struct log) + text_len + dict_len;
+	pad_len = (-size) & (LOG_ALIGN - 1);
+	size += pad_len;
+
+	while (log_first_seq < log_next_seq) {
+		u32 free;
+
+		if (log_next_idx > log_first_idx)
+			free = max(log_buf_len - log_next_idx, log_first_idx);
+		else
+			free = log_first_idx - log_next_idx;
+
+		if (free > size + sizeof(struct log))
+			break;
+
+		/* drop old messages until we have enough contiuous space */
+		log_first_idx = log_next(log_first_idx);
+		log_first_seq++;
+	}
+
+	if (log_next_idx + size + sizeof(struct log) >= log_buf_len) {
+		/*
+		 * This message + an additional empty header does not fit
+		 * at the end of the buffer. Add an empty header with len == 0
+		 * to signify a wrap around.
+		 */
+		memset(log_buf + log_next_idx, 0, sizeof(struct log));
+		log_next_idx = 0;
+	}
+
+	/* fill message */
+	msg = (struct log *)(log_buf + log_next_idx);
+	memcpy(log_text(msg), text, text_len);
+	msg->text_len = text_len;
+	memcpy(log_dict(msg), dict, dict_len);
+	msg->dict_len = dict_len;
+	msg->level = (facility << 3) | (level & 7);
+	msg->ts_nsec = local_clock();
+	memset(log_dict(msg) + dict_len, 0, pad_len);
+	msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
+
+	/* insert message */
+	log_next_idx += msg->len;
+	log_next_seq++;
+}
+
+/* /dev/kmsg - userspace message inject/listen interface */
+struct devkmsg_user {
+	u64 seq;
+	u32 idx;
+	struct mutex lock;
+	char buf[8192];
+};
+
+static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv,
+			      unsigned long count, loff_t pos)
+{
+	char *buf, *line;
+	int i;
+	int level = default_message_loglevel;
+	int facility = 1;	/* LOG_USER */
+	size_t len = iov_length(iv, count);
+	ssize_t ret = len;
+
+	if (len > LOG_LINE_MAX)
+		return -EINVAL;
+	buf = kmalloc(len+1, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	line = buf;
+	for (i = 0; i < count; i++) {
+		if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len))
+			goto out;
+		line += iv[i].iov_len;
+	}
+
+	/*
+	 * Extract and skip the syslog prefix <[0-9]*>. Coming from userspace
+	 * the decimal value represents 32bit, the lower 3 bit are the log
+	 * level, the rest are the log facility.
+	 *
+	 * If no prefix or no userspace facility is specified, we
+	 * enforce LOG_USER, to be able to reliably distinguish
+	 * kernel-generated messages from userspace-injected ones.
+	 */
+	line = buf;
+	if (line[0] == '<') {
+		char *endp = NULL;
+
+		i = simple_strtoul(line+1, &endp, 10);
+		if (endp && endp[0] == '>') {
+			level = i & 7;
+			if (i >> 3)
+				facility = i >> 3;
+			endp++;
+			len -= endp - line;
+			line = endp;
+		}
+	}
+	line[len] = '\0';
+
+	printk_emit(facility, level, NULL, 0, "%s", line);
+out:
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t devkmsg_read(struct file *file, char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct devkmsg_user *user = file->private_data;
+	struct log *msg;
+	u64 ts_usec;
+	size_t i;
+	size_t len;
+	ssize_t ret;
+
+	if (!user)
+		return -EBADF;
+
+	mutex_lock(&user->lock);
+	raw_spin_lock(&logbuf_lock);
+	while (user->seq == log_next_seq) {
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			raw_spin_unlock(&logbuf_lock);
+			goto out;
+		}
+
+		raw_spin_unlock(&logbuf_lock);
+		ret = wait_event_interruptible(log_wait,
+					       user->seq != log_next_seq);
+		if (ret)
+			goto out;
+		raw_spin_lock(&logbuf_lock);
+	}
+
+	if (user->seq < log_first_seq) {
+		/* our last seen message is gone, return error and reset */
+		user->idx = log_first_idx;
+		user->seq = log_first_seq;
+		ret = -EPIPE;
+		raw_spin_unlock(&logbuf_lock);
+		goto out;
+	}
+
+	msg = log_from_idx(user->idx);
+	ts_usec = msg->ts_nsec;
+	do_div(ts_usec, 1000);
+	len = sprintf(user->buf, "%u,%llu,%llu;",
+		      msg->level, user->seq, ts_usec);
+
+	/* escape non-printable characters */
+	for (i = 0; i < msg->text_len; i++) {
+		unsigned char c = log_text(msg)[i];
+
+		if (c < ' ' || c >= 128)
+			len += sprintf(user->buf + len, "\\x%02x", c);
+		else
+			user->buf[len++] = c;
+	}
+	user->buf[len++] = '\n';
+
+	if (msg->dict_len) {
+		bool line = true;
+
+		for (i = 0; i < msg->dict_len; i++) {
+			unsigned char c = log_dict(msg)[i];
+
+			if (line) {
+				user->buf[len++] = ' ';
+				line = false;
+			}
+
+			if (c == '\0') {
+				user->buf[len++] = '\n';
+				line = true;
+				continue;
+			}
+
+			if (c < ' ' || c >= 128) {
+				len += sprintf(user->buf + len, "\\x%02x", c);
+				continue;
+			}
+
+			user->buf[len++] = c;
+		}
+		user->buf[len++] = '\n';
+	}
+
+	user->idx = log_next(user->idx);
+	user->seq++;
+	raw_spin_unlock(&logbuf_lock);
+
+	if (len > count) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (copy_to_user(buf, user->buf, len)) {
+		ret = -EFAULT;
+		goto out;
+	}
+	ret = len;
+out:
+	mutex_unlock(&user->lock);
+	return ret;
+}
+
+static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
+{
+	struct devkmsg_user *user = file->private_data;
+	loff_t ret = 0;
+
+	if (!user)
+		return -EBADF;
+	if (offset)
+		return -ESPIPE;
+
+	raw_spin_lock(&logbuf_lock);
+	switch (whence) {
+	case SEEK_SET:
+		/* the first record */
+		user->idx = log_first_idx;
+		user->seq = log_first_seq;
+		break;
+	case SEEK_DATA:
+		/*
+		 * The first record after the last SYSLOG_ACTION_CLEAR,
+		 * like issued by 'dmesg -c'. Reading /dev/kmsg itself
+		 * changes no global state, and does not clear anything.
+		 */
+		user->idx = clear_idx;
+		user->seq = clear_seq;
+		break;
+	case SEEK_END:
+		/* after the last record */
+		user->idx = log_next_idx;
+		user->seq = log_next_seq;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	raw_spin_unlock(&logbuf_lock);
+	return ret;
+}
+
+static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
+{
+	struct devkmsg_user *user = file->private_data;
+	int ret = 0;
+
+	if (!user)
+		return POLLERR|POLLNVAL;
+
+	poll_wait(file, &log_wait, wait);
+
+	raw_spin_lock(&logbuf_lock);
+	if (user->seq < log_next_seq) {
+		/* return error when data has vanished underneath us */
+		if (user->seq < log_first_seq)
+			ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
+		ret = POLLIN|POLLRDNORM;
+	}
+	raw_spin_unlock(&logbuf_lock);
+
+	return ret;
+}
+
+static int devkmsg_open(struct inode *inode, struct file *file)
+{
+	struct devkmsg_user *user;
+	int err;
+
+	/* write-only does not need any file context */
+	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
+		return 0;
+
+	err = security_syslog(SYSLOG_ACTION_READ_ALL);
+	if (err)
+		return err;
+
+	user = kmalloc(sizeof(struct devkmsg_user), GFP_KERNEL);
+	if (!user)
+		return -ENOMEM;
+
+	mutex_init(&user->lock);
+
+	raw_spin_lock(&logbuf_lock);
+	user->idx = log_first_idx;
+	user->seq = log_first_seq;
+	raw_spin_unlock(&logbuf_lock);
+
+	file->private_data = user;
+	return 0;
+}
+
+static int devkmsg_release(struct inode *inode, struct file *file)
+{
+	struct devkmsg_user *user = file->private_data;
+
+	if (!user)
+		return 0;
+
+	mutex_destroy(&user->lock);
+	kfree(user);
+	return 0;
+}
+
+const struct file_operations kmsg_fops = {
+	.open = devkmsg_open,
+	.read = devkmsg_read,
+	.aio_write = devkmsg_writev,
+	.llseek = devkmsg_llseek,
+	.poll = devkmsg_poll,
+	.release = devkmsg_release,
+};
 
 #ifdef CONFIG_KEXEC
 /*
@@ -165,9 +624,9 @@
 void log_buf_kexec_setup(void)
 {
 	VMCOREINFO_SYMBOL(log_buf);
-	VMCOREINFO_SYMBOL(log_end);
 	VMCOREINFO_SYMBOL(log_buf_len);
-	VMCOREINFO_SYMBOL(logged_chars);
+	VMCOREINFO_SYMBOL(log_first_idx);
+	VMCOREINFO_SYMBOL(log_next_idx);
 }
 #endif
 
@@ -191,7 +650,6 @@
 void __init setup_log_buf(int early)
 {
 	unsigned long flags;
-	unsigned start, dest_idx, offset;
 	char *new_log_buf;
 	int free;
 
@@ -219,20 +677,8 @@
 	log_buf_len = new_log_buf_len;
 	log_buf = new_log_buf;
 	new_log_buf_len = 0;
-	free = __LOG_BUF_LEN - log_end;
-
-	offset = start = min(con_start, log_start);
-	dest_idx = 0;
-	while (start != log_end) {
-		unsigned log_idx_mask = start & (__LOG_BUF_LEN - 1);
-
-		log_buf[dest_idx] = __log_buf[log_idx_mask];
-		start++;
-		dest_idx++;
-	}
-	log_start -= offset;
-	con_start -= offset;
-	log_end -= offset;
+	free = __LOG_BUF_LEN - log_next_idx;
+	memcpy(log_buf, __log_buf, __LOG_BUF_LEN);
 	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 
 	pr_info("log_buf_len: %d\n", log_buf_len);
@@ -332,11 +778,202 @@
 	return 0;
 }
 
+#if defined(CONFIG_PRINTK_TIME)
+static bool printk_time = 1;
+#else
+static bool printk_time;
+#endif
+module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
+
+static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
+{
+	size_t len = 0;
+
+	if (syslog) {
+		if (buf) {
+			len += sprintf(buf, "<%u>", msg->level);
+		} else {
+			len += 3;
+			if (msg->level > 9)
+				len++;
+			if (msg->level > 99)
+				len++;
+		}
+	}
+
+	if (printk_time) {
+		if (buf) {
+			unsigned long long ts = msg->ts_nsec;
+			unsigned long rem_nsec = do_div(ts, 1000000000);
+
+			len += sprintf(buf + len, "[%5lu.%06lu] ",
+					 (unsigned long) ts, rem_nsec / 1000);
+		} else {
+			len += 15;
+		}
+	}
+
+	return len;
+}
+
+static size_t msg_print_text(const struct log *msg, bool syslog,
+			     char *buf, size_t size)
+{
+	const char *text = log_text(msg);
+	size_t text_size = msg->text_len;
+	size_t len = 0;
+
+	do {
+		const char *next = memchr(text, '\n', text_size);
+		size_t text_len;
+
+		if (next) {
+			text_len = next - text;
+			next++;
+			text_size -= next - text;
+		} else {
+			text_len = text_size;
+		}
+
+		if (buf) {
+			if (print_prefix(msg, syslog, NULL) +
+			    text_len + 1>= size - len)
+				break;
+
+			len += print_prefix(msg, syslog, buf + len);
+			memcpy(buf + len, text, text_len);
+			len += text_len;
+			buf[len++] = '\n';
+		} else {
+			/* SYSLOG_ACTION_* buffer size only calculation */
+			len += print_prefix(msg, syslog, NULL);
+			len += text_len + 1;
+		}
+
+		text = next;
+	} while (text);
+
+	return len;
+}
+
+static int syslog_print(char __user *buf, int size)
+{
+	char *text;
+	struct log *msg;
+	int len;
+
+	text = kmalloc(LOG_LINE_MAX, GFP_KERNEL);
+	if (!text)
+		return -ENOMEM;
+
+	raw_spin_lock_irq(&logbuf_lock);
+	if (syslog_seq < log_first_seq) {
+		/* messages are gone, move to first one */
+		syslog_seq = log_first_seq;
+		syslog_idx = log_first_idx;
+	}
+	msg = log_from_idx(syslog_idx);
+	len = msg_print_text(msg, true, text, LOG_LINE_MAX);
+	syslog_idx = log_next(syslog_idx);
+	syslog_seq++;
+	raw_spin_unlock_irq(&logbuf_lock);
+
+	if (len > 0 && copy_to_user(buf, text, len))
+		len = -EFAULT;
+
+	kfree(text);
+	return len;
+}
+
+static int syslog_print_all(char __user *buf, int size, bool clear)
+{
+	char *text;
+	int len = 0;
+
+	text = kmalloc(LOG_LINE_MAX, GFP_KERNEL);
+	if (!text)
+		return -ENOMEM;
+
+	raw_spin_lock_irq(&logbuf_lock);
+	if (buf) {
+		u64 next_seq;
+		u64 seq;
+		u32 idx;
+
+		if (clear_seq < log_first_seq) {
+			/* messages are gone, move to first available one */
+			clear_seq = log_first_seq;
+			clear_idx = log_first_idx;
+		}
+
+		/*
+		 * Find first record that fits, including all following records,
+		 * into the user-provided buffer for this dump.
+		*/
+		seq = clear_seq;
+		idx = clear_idx;
+		while (seq < log_next_seq) {
+			struct log *msg = log_from_idx(idx);
+
+			len += msg_print_text(msg, true, NULL, 0);
+			idx = log_next(idx);
+			seq++;
+		}
+		seq = clear_seq;
+		idx = clear_idx;
+		while (len > size && seq < log_next_seq) {
+			struct log *msg = log_from_idx(idx);
+
+			len -= msg_print_text(msg, true, NULL, 0);
+			idx = log_next(idx);
+			seq++;
+		}
+
+		/* last message in this dump */
+		next_seq = log_next_seq;
+
+		len = 0;
+		while (len >= 0 && seq < next_seq) {
+			struct log *msg = log_from_idx(idx);
+			int textlen;
+
+			textlen = msg_print_text(msg, true, text, LOG_LINE_MAX);
+			if (textlen < 0) {
+				len = textlen;
+				break;
+			}
+			idx = log_next(idx);
+			seq++;
+
+			raw_spin_unlock_irq(&logbuf_lock);
+			if (copy_to_user(buf + len, text, textlen))
+				len = -EFAULT;
+			else
+				len += textlen;
+			raw_spin_lock_irq(&logbuf_lock);
+
+			if (seq < log_first_seq) {
+				/* messages are gone, move to next one */
+				seq = log_first_seq;
+				idx = log_first_idx;
+			}
+		}
+	}
+
+	if (clear) {
+		clear_seq = log_next_seq;
+		clear_idx = log_next_idx;
+	}
+	raw_spin_unlock_irq(&logbuf_lock);
+
+	kfree(text);
+	return len;
+}
+
 int do_syslog(int type, char __user *buf, int len, bool from_file)
 {
-	unsigned i, j, limit, count;
-	int do_clear = 0;
-	char c;
+	bool clear = false;
+	static int saved_console_loglevel = -1;
 	int error;
 
 	error = check_syslog_permissions(type, from_file);
@@ -364,28 +1001,14 @@
 			goto out;
 		}
 		error = wait_event_interruptible(log_wait,
-							(log_start - log_end));
+						 syslog_seq != log_next_seq);
 		if (error)
 			goto out;
-		i = 0;
-		raw_spin_lock_irq(&logbuf_lock);
-		while (!error && (log_start != log_end) && i < len) {
-			c = LOG_BUF(log_start);
-			log_start++;
-			raw_spin_unlock_irq(&logbuf_lock);
-			error = __put_user(c,buf);
-			buf++;
-			i++;
-			cond_resched();
-			raw_spin_lock_irq(&logbuf_lock);
-		}
-		raw_spin_unlock_irq(&logbuf_lock);
-		if (!error)
-			error = i;
+		error = syslog_print(buf, len);
 		break;
 	/* Read/clear last kernel messages */
 	case SYSLOG_ACTION_READ_CLEAR:
-		do_clear = 1;
+		clear = true;
 		/* FALL THRU */
 	/* Read last kernel messages */
 	case SYSLOG_ACTION_READ_ALL:
@@ -399,52 +1022,11 @@
 			error = -EFAULT;
 			goto out;
 		}
-		count = len;
-		if (count > log_buf_len)
-			count = log_buf_len;
-		raw_spin_lock_irq(&logbuf_lock);
-		if (count > logged_chars)
-			count = logged_chars;
-		if (do_clear)
-			logged_chars = 0;
-		limit = log_end;
-		/*
-		 * __put_user() could sleep, and while we sleep
-		 * printk() could overwrite the messages
-		 * we try to copy to user space. Therefore
-		 * the messages are copied in reverse. <manfreds>
-		 */
-		for (i = 0; i < count && !error; i++) {
-			j = limit-1-i;
-			if (j + log_buf_len < log_end)
-				break;
-			c = LOG_BUF(j);
-			raw_spin_unlock_irq(&logbuf_lock);
-			error = __put_user(c,&buf[count-1-i]);
-			cond_resched();
-			raw_spin_lock_irq(&logbuf_lock);
-		}
-		raw_spin_unlock_irq(&logbuf_lock);
-		if (error)
-			break;
-		error = i;
-		if (i != count) {
-			int offset = count-error;
-			/* buffer overflow during copy, correct user buffer. */
-			for (i = 0; i < error; i++) {
-				if (__get_user(c,&buf[i+offset]) ||
-				    __put_user(c,&buf[i])) {
-					error = -EFAULT;
-					break;
-				}
-				cond_resched();
-			}
-		}
+		error = syslog_print_all(buf, len, clear);
 		break;
 	/* Clear ring buffer */
 	case SYSLOG_ACTION_CLEAR:
-		logged_chars = 0;
-		break;
+		syslog_print_all(NULL, 0, true);
 	/* Disable logging to console */
 	case SYSLOG_ACTION_CONSOLE_OFF:
 		if (saved_console_loglevel == -1)
@@ -472,7 +1054,35 @@
 		break;
 	/* Number of chars in the log buffer */
 	case SYSLOG_ACTION_SIZE_UNREAD:
-		error = log_end - log_start;
+		raw_spin_lock_irq(&logbuf_lock);
+		if (syslog_seq < log_first_seq) {
+			/* messages are gone, move to first one */
+			syslog_seq = log_first_seq;
+			syslog_idx = log_first_idx;
+		}
+		if (from_file) {
+			/*
+			 * Short-cut for poll(/"proc/kmsg") which simply checks
+			 * for pending data, not the size; return the count of
+			 * records, not the length.
+			 */
+			error = log_next_idx - syslog_idx;
+		} else {
+			u64 seq;
+			u32 idx;
+
+			error = 0;
+			seq = syslog_seq;
+			idx = syslog_idx;
+			while (seq < log_next_seq) {
+				struct log *msg = log_from_idx(idx);
+
+				error += msg_print_text(msg, true, NULL, 0);
+				idx = log_next(idx);
+				seq++;
+			}
+		}
+		raw_spin_unlock_irq(&logbuf_lock);
 		break;
 	/* Size of the log buffer */
 	case SYSLOG_ACTION_SIZE_BUFFER:
@@ -501,29 +1111,11 @@
 {
 	syslog_data[0] = log_buf;
 	syslog_data[1] = log_buf + log_buf_len;
-	syslog_data[2] = log_buf + log_end -
-		(logged_chars < log_buf_len ? logged_chars : log_buf_len);
-	syslog_data[3] = log_buf + log_end;
+	syslog_data[2] = log_buf + log_first_idx;
+	syslog_data[3] = log_buf + log_next_idx;
 }
 #endif	/* CONFIG_KGDB_KDB */
 
-/*
- * Call the console drivers on a range of log_buf
- */
-static void __call_console_drivers(unsigned start, unsigned end)
-{
-	struct console *con;
-
-	for_each_console(con) {
-		if (exclusive_console && con != exclusive_console)
-			continue;
-		if ((con->flags & CON_ENABLED) && con->write &&
-				(cpu_online(smp_processor_id()) ||
-				(con->flags & CON_ANYTIME)))
-			con->write(con, &LOG_BUF(start), end - start);
-	}
-}
-
 static bool __read_mostly ignore_loglevel;
 
 static int __init ignore_loglevel_setup(char *str)
@@ -540,142 +1132,33 @@
 	"print all kernel messages to the console.");
 
 /*
- * Write out chars from start to end - 1 inclusive
- */
-static void _call_console_drivers(unsigned start,
-				unsigned end, int msg_log_level)
-{
-	trace_console(&LOG_BUF(0), start, end, log_buf_len);
-
-	if ((msg_log_level < console_loglevel || ignore_loglevel) &&
-			console_drivers && start != end) {
-		if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
-			/* wrapped write */
-			__call_console_drivers(start & LOG_BUF_MASK,
-						log_buf_len);
-			__call_console_drivers(0, end & LOG_BUF_MASK);
-		} else {
-			__call_console_drivers(start, end);
-		}
-	}
-}
-
-/*
- * Parse the syslog header <[0-9]*>. The decimal value represents 32bit, the
- * lower 3 bit are the log level, the rest are the log facility. In case
- * userspace passes usual userspace syslog messages to /dev/kmsg or
- * /dev/ttyprintk, the log prefix might contain the facility. Printk needs
- * to extract the correct log level for in-kernel processing, and not mangle
- * the original value.
- *
- * If a prefix is found, the length of the prefix is returned. If 'level' is
- * passed, it will be filled in with the log level without a possible facility
- * value. If 'special' is passed, the special printk prefix chars are accepted
- * and returned. If no valid header is found, 0 is returned and the passed
- * variables are not touched.
- */
-static size_t log_prefix(const char *p, unsigned int *level, char *special)
-{
-	unsigned int lev = 0;
-	char sp = '\0';
-	size_t len;
-
-	if (p[0] != '<' || !p[1])
-		return 0;
-	if (p[2] == '>') {
-		/* usual single digit level number or special char */
-		switch (p[1]) {
-		case '0' ... '7':
-			lev = p[1] - '0';
-			break;
-		case 'c': /* KERN_CONT */
-		case 'd': /* KERN_DEFAULT */
-			sp = p[1];
-			break;
-		default:
-			return 0;
-		}
-		len = 3;
-	} else {
-		/* multi digit including the level and facility number */
-		char *endp = NULL;
-
-		lev = (simple_strtoul(&p[1], &endp, 10) & 7);
-		if (endp == NULL || endp[0] != '>')
-			return 0;
-		len = (endp + 1) - p;
-	}
-
-	/* do not accept special char if not asked for */
-	if (sp && !special)
-		return 0;
-
-	if (special) {
-		*special = sp;
-		/* return special char, do not touch level */
-		if (sp)
-			return len;
-	}
-
-	if (level)
-		*level = lev;
-	return len;
-}
-
-/*
  * Call the console drivers, asking them to write out
  * log_buf[start] to log_buf[end - 1].
  * The console_lock must be held.
  */
-static void call_console_drivers(unsigned start, unsigned end)
+static void call_console_drivers(int level, const char *text, size_t len)
 {
-	unsigned cur_index, start_print;
-	static int msg_level = -1;
+	struct console *con;
 
-	BUG_ON(((int)(start - end)) > 0);
+	trace_console(text, 0, len, len);
 
-	cur_index = start;
-	start_print = start;
-	while (cur_index != end) {
-		if (msg_level < 0 && ((end - cur_index) > 2)) {
-			/* strip log prefix */
-			cur_index += log_prefix(&LOG_BUF(cur_index), &msg_level, NULL);
-			start_print = cur_index;
-		}
-		while (cur_index != end) {
-			char c = LOG_BUF(cur_index);
+	if (level >= console_loglevel && !ignore_loglevel)
+		return;
+	if (!console_drivers)
+		return;
 
-			cur_index++;
-			if (c == '\n') {
-				if (msg_level < 0) {
-					/*
-					 * printk() has already given us loglevel tags in
-					 * the buffer.  This code is here in case the
-					 * log buffer has wrapped right round and scribbled
-					 * on those tags
-					 */
-					msg_level = default_message_loglevel;
-				}
-				_call_console_drivers(start_print, cur_index, msg_level);
-				msg_level = -1;
-				start_print = cur_index;
-				break;
-			}
-		}
+	for_each_console(con) {
+		if (exclusive_console && con != exclusive_console)
+			continue;
+		if (!(con->flags & CON_ENABLED))
+			continue;
+		if (!con->write)
+			continue;
+		if (!cpu_online(smp_processor_id()) &&
+		    !(con->flags & CON_ANYTIME))
+			continue;
+		con->write(con, text, len);
 	}
-	_call_console_drivers(start_print, end, msg_level);
-}
-
-static void emit_log_char(char c)
-{
-	LOG_BUF(log_end) = c;
-	log_end++;
-	if (log_end - log_start > log_buf_len)
-		log_start = log_end - log_buf_len;
-	if (log_end - con_start > log_buf_len)
-		con_start = log_end - log_buf_len;
-	if (logged_chars < log_buf_len)
-		logged_chars++;
 }
 
 /*
@@ -700,16 +1183,6 @@
 	sema_init(&console_sem, 1);
 }
 
-#if defined(CONFIG_PRINTK_TIME)
-static bool printk_time = 1;
-#else
-static bool printk_time = 0;
-#endif
-module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
-
-static bool always_kmsg_dump;
-module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR);
-
 /* Check if we have any console registered that can be called early in boot. */
 static int have_callable_console(void)
 {
@@ -722,51 +1195,6 @@
 	return 0;
 }
 
-/**
- * printk - print a kernel message
- * @fmt: format string
- *
- * This is printk().  It can be called from any context.  We want it to work.
- *
- * We try to grab the console_lock.  If we succeed, it's easy - we log the output and
- * call the console drivers.  If we fail to get the semaphore we place the output
- * into the log buffer and return.  The current holder of the console_sem will
- * notice the new output in console_unlock(); and will send it to the
- * consoles before releasing the lock.
- *
- * One effect of this deferred printing is that code which calls printk() and
- * then changes console_loglevel may break. This is because console_loglevel
- * is inspected when the actual printing occurs.
- *
- * See also:
- * printf(3)
- *
- * See the vsnprintf() documentation for format string extensions over C99.
- */
-
-asmlinkage int printk(const char *fmt, ...)
-{
-	va_list args;
-	int r;
-
-#ifdef CONFIG_KGDB_KDB
-	if (unlikely(kdb_trap_printk)) {
-		va_start(args, fmt);
-		r = vkdb_printf(fmt, args);
-		va_end(args);
-		return r;
-	}
-#endif
-	va_start(args, fmt);
-	r = vprintk(fmt, args);
-	va_end(args);
-
-	return r;
-}
-
-/* cpu currently holding logbuf_lock */
-static volatile unsigned int printk_cpu = UINT_MAX;
-
 /*
  * Can we actually use the console at this time on this cpu?
  *
@@ -810,17 +1238,12 @@
 			retval = 0;
 		}
 	}
-	printk_cpu = UINT_MAX;
+	logbuf_cpu = UINT_MAX;
 	if (wake)
 		up(&console_sem);
 	raw_spin_unlock(&logbuf_lock);
 	return retval;
 }
-static const char recursion_bug_msg [] =
-		KERN_CRIT "BUG: recent printk recursion!\n";
-static int recursion_bug;
-static int new_text_line = 1;
-static char printk_buf[1024];
 
 int printk_delay_msec __read_mostly;
 
@@ -836,15 +1259,23 @@
 	}
 }
 
-asmlinkage int vprintk(const char *fmt, va_list args)
+asmlinkage int vprintk_emit(int facility, int level,
+			    const char *dict, size_t dictlen,
+			    const char *fmt, va_list args)
 {
-	int printed_len = 0;
-	int current_log_level = default_message_loglevel;
+	static int recursion_bug;
+	static char cont_buf[LOG_LINE_MAX];
+	static size_t cont_len;
+	static int cont_level;
+	static struct task_struct *cont_task;
+	static char textbuf[LOG_LINE_MAX];
+	char *text = textbuf;
+	size_t text_len;
 	unsigned long flags;
 	int this_cpu;
-	char *p;
-	size_t plen;
-	char special;
+	bool newline = false;
+	bool prefix = false;
+	int printed_len = 0;
 
 	boot_delay_msec();
 	printk_delay();
@@ -856,7 +1287,7 @@
 	/*
 	 * Ouch, printk recursed into itself!
 	 */
-	if (unlikely(printk_cpu == this_cpu)) {
+	if (unlikely(logbuf_cpu == this_cpu)) {
 		/*
 		 * If a crash is occurring during printk() on this CPU,
 		 * then try to get the crash message out but make sure
@@ -873,97 +1304,110 @@
 
 	lockdep_off();
 	raw_spin_lock(&logbuf_lock);
-	printk_cpu = this_cpu;
+	logbuf_cpu = this_cpu;
 
 	if (recursion_bug) {
+		static const char recursion_msg[] =
+			"BUG: recent printk recursion!";
+
 		recursion_bug = 0;
-		strcpy(printk_buf, recursion_bug_msg);
-		printed_len = strlen(recursion_bug_msg);
-	}
-	/* Emit the output into the temporary buffer */
-	printed_len += vscnprintf(printk_buf + printed_len,
-				  sizeof(printk_buf) - printed_len, fmt, args);
-
-	p = printk_buf;
-
-	/* Read log level and handle special printk prefix */
-	plen = log_prefix(p, &current_log_level, &special);
-	if (plen) {
-		p += plen;
-
-		switch (special) {
-		case 'c': /* Strip <c> KERN_CONT, continue line */
-			plen = 0;
-			break;
-		case 'd': /* Strip <d> KERN_DEFAULT, start new line */
-			plen = 0;
-		default:
-			if (!new_text_line) {
-				emit_log_char('\n');
-				new_text_line = 1;
-			}
-		}
+		printed_len += strlen(recursion_msg);
+		/* emit KERN_CRIT message */
+		log_store(0, 2, NULL, 0, recursion_msg, printed_len);
 	}
 
 	/*
-	 * Copy the output into log_buf. If the caller didn't provide
-	 * the appropriate log prefix, we insert them here
+	 * The printf needs to come first; we need the syslog
+	 * prefix which might be passed-in as a parameter.
 	 */
-	for (; *p; p++) {
-		if (new_text_line) {
-			new_text_line = 0;
+	text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
 
-			if (plen) {
-				/* Copy original log prefix */
-				int i;
+	/* mark and strip a trailing newline */
+	if (text_len && text[text_len-1] == '\n') {
+		text_len--;
+		newline = true;
+	}
 
-				for (i = 0; i < plen; i++)
-					emit_log_char(printk_buf[i]);
-				printed_len += plen;
-			} else {
-				/* Add log prefix */
-				emit_log_char('<');
-				emit_log_char(current_log_level + '0');
-				emit_log_char('>');
-				printed_len += 3;
-			}
+	/* strip syslog prefix and extract log level or control flags */
+	if (text[0] == '<' && text[1] && text[2] == '>') {
+		switch (text[1]) {
+		case '0' ... '7':
+			if (level == -1)
+				level = text[1] - '0';
+		case 'd':	/* KERN_DEFAULT */
+			prefix = true;
+		case 'c':	/* KERN_CONT */
+			text += 3;
+			text_len -= 3;
+		}
+	}
 
-			if (printk_time) {
-				/* Add the current time stamp */
-				char tbuf[50], *tp;
-				unsigned tlen;
-				unsigned long long t;
-				unsigned long nanosec_rem;
+	if (level == -1)
+		level = default_message_loglevel;
 
-				t = cpu_clock(printk_cpu);
-				nanosec_rem = do_div(t, 1000000000);
-				tlen = sprintf(tbuf, "[%5lu.%06lu] ",
-						(unsigned long) t,
-						nanosec_rem / 1000);
+	if (dict) {
+		prefix = true;
+		newline = true;
+	}
 
-				for (tp = tbuf; tp < tbuf + tlen; tp++)
-					emit_log_char(*tp);
-				printed_len += tlen;
-			}
-
-			if (!*p)
-				break;
+	if (!newline) {
+		if (cont_len && (prefix || cont_task != current)) {
+			/*
+			 * Flush earlier buffer, which is either from a
+			 * different thread, or when we got a new prefix.
+			 */
+			log_store(facility, cont_level, NULL, 0, cont_buf, cont_len);
+			cont_len = 0;
 		}
 
-		emit_log_char(*p);
-		if (*p == '\n')
-			new_text_line = 1;
+		if (!cont_len) {
+			cont_level = level;
+			cont_task = current;
+		}
+
+		/* buffer or append to earlier buffer from the same thread */
+		if (cont_len + text_len > sizeof(cont_buf))
+			text_len = sizeof(cont_buf) - cont_len;
+		memcpy(cont_buf + cont_len, text, text_len);
+		cont_len += text_len;
+	} else {
+		if (cont_len && cont_task == current) {
+			if (prefix) {
+				/*
+				 * New prefix from the same thread; flush. We
+				 * either got no earlier newline, or we race
+				 * with an interrupt.
+				 */
+				log_store(facility, cont_level,
+					  NULL, 0, cont_buf, cont_len);
+				cont_len = 0;
+			}
+
+			/* append to the earlier buffer and flush */
+			if (cont_len + text_len > sizeof(cont_buf))
+				text_len = sizeof(cont_buf) - cont_len;
+			memcpy(cont_buf + cont_len, text, text_len);
+			cont_len += text_len;
+			log_store(facility, cont_level,
+				  NULL, 0, cont_buf, cont_len);
+			cont_len = 0;
+			cont_task = NULL;
+			printed_len = cont_len;
+		} else {
+			/* ordinary single and terminated line */
+			log_store(facility, level,
+				  dict, dictlen, text, text_len);
+			printed_len = text_len;
+		}
 	}
 
 	/*
-	 * Try to acquire and then immediately release the
-	 * console semaphore. The release will do all the
-	 * actual magic (print out buffers, wake up klogd,
-	 * etc). 
+	 * Try to acquire and then immediately release the console semaphore.
+	 * The release will print out buffers and wake up /dev/kmsg and syslog()
+	 * users.
 	 *
-	 * The console_trylock_for_printk() function
-	 * will release 'logbuf_lock' regardless of whether it
-	 * actually gets the semaphore or not.
+	 * The console_trylock_for_printk() function will release 'logbuf_lock'
+	 * regardless of whether it actually gets the console semaphore or not.
 	 */
 	if (console_trylock_for_printk(this_cpu))
 		console_unlock();
@@ -974,16 +1418,81 @@
 
 	return printed_len;
 }
-EXPORT_SYMBOL(printk);
+EXPORT_SYMBOL(vprintk_emit);
+
+asmlinkage int vprintk(const char *fmt, va_list args)
+{
+	return vprintk_emit(0, -1, NULL, 0, fmt, args);
+}
 EXPORT_SYMBOL(vprintk);
 
+asmlinkage int printk_emit(int facility, int level,
+			   const char *dict, size_t dictlen,
+			   const char *fmt, ...)
+{
+	va_list args;
+	int r;
+
+	va_start(args, fmt);
+	r = vprintk_emit(facility, level, dict, dictlen, fmt, args);
+	va_end(args);
+
+	return r;
+}
+EXPORT_SYMBOL(printk_emit);
+
+/**
+ * printk - print a kernel message
+ * @fmt: format string
+ *
+ * This is printk(). It can be called from any context. We want it to work.
+ *
+ * We try to grab the console_lock. If we succeed, it's easy - we log the
+ * output and call the console drivers.  If we fail to get the semaphore, we
+ * place the output into the log buffer and return. The current holder of
+ * the console_sem will notice the new output in console_unlock(); and will
+ * send it to the consoles before releasing the lock.
+ *
+ * One effect of this deferred printing is that code which calls printk() and
+ * then changes console_loglevel may break. This is because console_loglevel
+ * is inspected when the actual printing occurs.
+ *
+ * See also:
+ * printf(3)
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
+ */
+asmlinkage int printk(const char *fmt, ...)
+{
+	va_list args;
+	int r;
+
+#ifdef CONFIG_KGDB_KDB
+	if (unlikely(kdb_trap_printk)) {
+		va_start(args, fmt);
+		r = vkdb_printf(fmt, args);
+		va_end(args);
+		return r;
+	}
+#endif
+	va_start(args, fmt);
+	r = vprintk_emit(0, -1, NULL, 0, fmt, args);
+	va_end(args);
+
+	return r;
+}
+EXPORT_SYMBOL(printk);
+
 #else
 
-static void call_console_drivers(unsigned start, unsigned end)
-{
-}
+#define LOG_LINE_MAX 0
+static struct log *log_from_idx(u32 idx) { return NULL; }
+static u32 log_next(u32 idx) { return 0; }
+static void call_console_drivers(int level, const char *text, size_t len) {}
+static size_t msg_print_text(const struct log *msg, bool syslog,
+			     char *buf, size_t size) { return 0; }
 
-#endif
+#endif /* CONFIG_PRINTK */
 
 static int __add_preferred_console(char *name, int idx, char *options,
 				   char *brl_options)
@@ -1217,7 +1726,7 @@
 }
 
 /*
- * Delayed printk facility, for scheduler-internal messages:
+ * Delayed printk version, for scheduler-internal messages:
  */
 #define PRINTK_BUF_SIZE		512
 
@@ -1253,6 +1762,10 @@
 		this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
 }
 
+/* the next printk record to write to the console */
+static u64 console_seq;
+static u32 console_idx;
+
 /**
  * console_unlock - unlock the console system
  *
@@ -1263,15 +1776,16 @@
  * by printk().  If this is the case, console_unlock(); emits
  * the output prior to releasing the lock.
  *
- * If there is output waiting for klogd, we wake it up.
+ * If there is output waiting, we wake /dev/kmsg and syslog() users.
  *
  * console_unlock(); may be called from any context.
  */
 void console_unlock(void)
 {
+	static u64 seen_seq;
 	unsigned long flags;
-	unsigned _con_start, _log_end;
-	unsigned wake_klogd = 0, retry = 0;
+	bool wake_klogd = false;
+	bool retry;
 
 	if (console_suspended) {
 		up(&console_sem);
@@ -1281,17 +1795,38 @@
 	console_may_schedule = 0;
 
 again:
-	for ( ; ; ) {
+	for (;;) {
+		struct log *msg;
+		static char text[LOG_LINE_MAX];
+		size_t len;
+		int level;
+
 		raw_spin_lock_irqsave(&logbuf_lock, flags);
-		wake_klogd |= log_start - log_end;
-		if (con_start == log_end)
-			break;			/* Nothing to print */
-		_con_start = con_start;
-		_log_end = log_end;
-		con_start = log_end;		/* Flush */
+		if (seen_seq != log_next_seq) {
+			wake_klogd = true;
+			seen_seq = log_next_seq;
+		}
+
+		if (console_seq < log_first_seq) {
+			/* messages are gone, move to first one */
+			console_seq = log_first_seq;
+			console_idx = log_first_idx;
+		}
+
+		if (console_seq == log_next_seq)
+			break;
+
+		msg = log_from_idx(console_idx);
+		level = msg->level & 7;
+
+		len = msg_print_text(msg, false, text, sizeof(text));
+
+		console_idx = log_next(console_idx);
+		console_seq++;
 		raw_spin_unlock(&logbuf_lock);
+
 		stop_critical_timings();	/* don't trace print latency */
-		call_console_drivers(_con_start, _log_end);
+		call_console_drivers(level, text, len);
 		start_critical_timings();
 		local_irq_restore(flags);
 	}
@@ -1312,8 +1847,7 @@
 	 * flush, no worries.
 	 */
 	raw_spin_lock(&logbuf_lock);
-	if (con_start != log_end)
-		retry = 1;
+	retry = console_seq != log_next_seq;
 	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 
 	if (retry && console_trylock())
@@ -1549,7 +2083,8 @@
 		 * for us.
 		 */
 		raw_spin_lock_irqsave(&logbuf_lock, flags);
-		con_start = log_start;
+		console_seq = syslog_seq;
+		console_idx = syslog_idx;
 		raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 		/*
 		 * We're about to replay the log buffer.  Only do this to the
@@ -1758,6 +2293,9 @@
 }
 EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
 
+static bool always_kmsg_dump;
+module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR);
+
 /**
  * kmsg_dump - dump kernel log to kernel message dumpers.
  * @reason: the reason (oops, panic etc) for dumping
@@ -1767,8 +2305,7 @@
  */
 void kmsg_dump(enum kmsg_dump_reason reason)
 {
-	unsigned long end;
-	unsigned chars;
+	u64 idx;
 	struct kmsg_dumper *dumper;
 	const char *s1, *s2;
 	unsigned long l1, l2;
@@ -1780,24 +2317,27 @@
 	/* Theoretically, the log could move on after we do this, but
 	   there's not a lot we can do about that. The new messages
 	   will overwrite the start of what we dump. */
+
 	raw_spin_lock_irqsave(&logbuf_lock, flags);
-	end = log_end & LOG_BUF_MASK;
-	chars = logged_chars;
-	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+	if (syslog_seq < log_first_seq)
+		idx = syslog_idx;
+	else
+		idx = log_first_idx;
 
-	if (chars > end) {
-		s1 = log_buf + log_buf_len - chars + end;
-		l1 = chars - end;
+	if (idx > log_next_idx) {
+		s1 = log_buf;
+		l1 = log_next_idx;
 
-		s2 = log_buf;
-		l2 = end;
+		s2 = log_buf + idx;
+		l2 = log_buf_len - idx;
 	} else {
 		s1 = "";
 		l1 = 0;
 
-		s2 = log_buf + end - chars;
-		l2 = chars;
+		s2 = log_buf + idx;
+		l2 = log_next_idx - idx;
 	}
+	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(dumper, &dump_list, list)
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index ee8d49b..a232bb5 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -198,15 +198,14 @@
 		return 0;
 	rcu_read_lock();
 	tcred = __task_cred(task);
-	if (cred->user->user_ns == tcred->user->user_ns &&
-	    (cred->uid == tcred->euid &&
-	     cred->uid == tcred->suid &&
-	     cred->uid == tcred->uid  &&
-	     cred->gid == tcred->egid &&
-	     cred->gid == tcred->sgid &&
-	     cred->gid == tcred->gid))
+	if (uid_eq(cred->uid, tcred->euid) &&
+	    uid_eq(cred->uid, tcred->suid) &&
+	    uid_eq(cred->uid, tcred->uid)  &&
+	    gid_eq(cred->gid, tcred->egid) &&
+	    gid_eq(cred->gid, tcred->sgid) &&
+	    gid_eq(cred->gid, tcred->gid))
 		goto ok;
-	if (ptrace_has_cap(tcred->user->user_ns, mode))
+	if (ptrace_has_cap(tcred->user_ns, mode))
 		goto ok;
 	rcu_read_unlock();
 	return -EPERM;
diff --git a/kernel/res_counter.c b/kernel/res_counter.c
index d508363..bebe2b1 100644
--- a/kernel/res_counter.c
+++ b/kernel/res_counter.c
@@ -22,75 +22,70 @@
 	counter->parent = parent;
 }
 
-int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
+int res_counter_charge_locked(struct res_counter *counter, unsigned long val,
+			      bool force)
 {
+	int ret = 0;
+
 	if (counter->usage + val > counter->limit) {
 		counter->failcnt++;
-		return -ENOMEM;
+		ret = -ENOMEM;
+		if (!force)
+			return ret;
 	}
 
 	counter->usage += val;
 	if (counter->usage > counter->max_usage)
 		counter->max_usage = counter->usage;
-	return 0;
-}
-
-int res_counter_charge(struct res_counter *counter, unsigned long val,
-			struct res_counter **limit_fail_at)
-{
-	int ret;
-	unsigned long flags;
-	struct res_counter *c, *u;
-
-	*limit_fail_at = NULL;
-	local_irq_save(flags);
-	for (c = counter; c != NULL; c = c->parent) {
-		spin_lock(&c->lock);
-		ret = res_counter_charge_locked(c, val);
-		spin_unlock(&c->lock);
-		if (ret < 0) {
-			*limit_fail_at = c;
-			goto undo;
-		}
-	}
-	ret = 0;
-	goto done;
-undo:
-	for (u = counter; u != c; u = u->parent) {
-		spin_lock(&u->lock);
-		res_counter_uncharge_locked(u, val);
-		spin_unlock(&u->lock);
-	}
-done:
-	local_irq_restore(flags);
 	return ret;
 }
 
-int res_counter_charge_nofail(struct res_counter *counter, unsigned long val,
-			      struct res_counter **limit_fail_at)
+static int __res_counter_charge(struct res_counter *counter, unsigned long val,
+				struct res_counter **limit_fail_at, bool force)
 {
 	int ret, r;
 	unsigned long flags;
-	struct res_counter *c;
+	struct res_counter *c, *u;
 
 	r = ret = 0;
 	*limit_fail_at = NULL;
 	local_irq_save(flags);
 	for (c = counter; c != NULL; c = c->parent) {
 		spin_lock(&c->lock);
-		r = res_counter_charge_locked(c, val);
-		if (r)
-			c->usage += val;
+		r = res_counter_charge_locked(c, val, force);
 		spin_unlock(&c->lock);
-		if (r < 0 && ret == 0) {
-			*limit_fail_at = c;
+		if (r < 0 && !ret) {
 			ret = r;
+			*limit_fail_at = c;
+			if (!force)
+				break;
+		}
+	}
+
+	if (ret < 0 && !force) {
+		for (u = counter; u != c; u = u->parent) {
+			spin_lock(&u->lock);
+			res_counter_uncharge_locked(u, val);
+			spin_unlock(&u->lock);
 		}
 	}
 	local_irq_restore(flags);
 
 	return ret;
 }
+
+int res_counter_charge(struct res_counter *counter, unsigned long val,
+			struct res_counter **limit_fail_at)
+{
+	return __res_counter_charge(counter, val, limit_fail_at, false);
+}
+
+int res_counter_charge_nofail(struct res_counter *counter, unsigned long val,
+			      struct res_counter **limit_fail_at)
+{
+	return __res_counter_charge(counter, val, limit_fail_at, true);
+}
+
 void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
 {
 	if (WARN_ON(counter->usage < val))
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index ea8a476..39eb601 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -693,8 +693,6 @@
 }
 #endif
 
-void update_cpu_load(struct rq *this_rq);
-
 static void set_load_weight(struct task_struct *p)
 {
 	int prio = p->static_prio - MAX_RT_PRIO;
@@ -2488,22 +2486,13 @@
  * scheduler tick (TICK_NSEC). With tickless idle this will not be called
  * every tick. We fix it up based on jiffies.
  */
-void update_cpu_load(struct rq *this_rq)
+static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
+			      unsigned long pending_updates)
 {
-	unsigned long this_load = this_rq->load.weight;
-	unsigned long curr_jiffies = jiffies;
-	unsigned long pending_updates;
 	int i, scale;
 
 	this_rq->nr_load_updates++;
 
-	/* Avoid repeated calls on same jiffy, when moving in and out of idle */
-	if (curr_jiffies == this_rq->last_load_update_tick)
-		return;
-
-	pending_updates = curr_jiffies - this_rq->last_load_update_tick;
-	this_rq->last_load_update_tick = curr_jiffies;
-
 	/* Update our load: */
 	this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */
 	for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
@@ -2528,9 +2517,45 @@
 	sched_avg_update(this_rq);
 }
 
+/*
+ * Called from nohz_idle_balance() to update the load ratings before doing the
+ * idle balance.
+ */
+void update_idle_cpu_load(struct rq *this_rq)
+{
+	unsigned long curr_jiffies = jiffies;
+	unsigned long load = this_rq->load.weight;
+	unsigned long pending_updates;
+
+	/*
+	 * Bloody broken means of dealing with nohz, but better than nothing..
+	 * jiffies is updated by one cpu, another cpu can drift wrt the jiffy
+	 * update and see 0 difference the one time and 2 the next, even though
+	 * we ticked at roughtly the same rate.
+	 *
+	 * Hence we only use this from nohz_idle_balance() and skip this
+	 * nonsense when called from the scheduler_tick() since that's
+	 * guaranteed a stable rate.
+	 */
+	if (load || curr_jiffies == this_rq->last_load_update_tick)
+		return;
+
+	pending_updates = curr_jiffies - this_rq->last_load_update_tick;
+	this_rq->last_load_update_tick = curr_jiffies;
+
+	__update_cpu_load(this_rq, load, pending_updates);
+}
+
+/*
+ * Called from scheduler_tick()
+ */
 static void update_cpu_load_active(struct rq *this_rq)
 {
-	update_cpu_load(this_rq);
+	/*
+	 * See the mess in update_idle_cpu_load().
+	 */
+	this_rq->last_load_update_tick = jiffies;
+	__update_cpu_load(this_rq, this_rq->load.weight, 1);
 
 	calc_load_account_active(this_rq);
 }
@@ -3115,6 +3140,7 @@
 	if (irqs_disabled())
 		print_irqtrace_events(prev);
 	dump_stack();
+	add_taint(TAINT_WARN);
 }
 
 /*
@@ -4044,11 +4070,8 @@
 
 	rcu_read_lock();
 	pcred = __task_cred(p);
-	if (cred->user->user_ns == pcred->user->user_ns)
-		match = (cred->euid == pcred->euid ||
-			 cred->euid == pcred->uid);
-	else
-		match = false;
+	match = (uid_eq(cred->euid, pcred->euid) ||
+		 uid_eq(cred->euid, pcred->uid));
 	rcu_read_unlock();
 	return match;
 }
@@ -5562,7 +5585,8 @@
 			break;
 		}
 
-		if (cpumask_intersects(groupmask, sched_group_cpus(group))) {
+		if (!(sd->flags & SD_OVERLAP) &&
+		    cpumask_intersects(groupmask, sched_group_cpus(group))) {
 			printk(KERN_CONT "\n");
 			printk(KERN_ERR "ERROR: repeated CPUs\n");
 			break;
@@ -5900,99 +5924,11 @@
 
 __setup("isolcpus=", isolated_cpu_setup);
 
-#ifdef CONFIG_NUMA
-
-/**
- * find_next_best_node - find the next node to include in a sched_domain
- * @node: node whose sched_domain we're building
- * @used_nodes: nodes already in the sched_domain
- *
- * Find the next node to include in a given scheduling domain. Simply
- * finds the closest node not already in the @used_nodes map.
- *
- * Should use nodemask_t.
- */
-static int find_next_best_node(int node, nodemask_t *used_nodes)
-{
-	int i, n, val, min_val, best_node = -1;
-
-	min_val = INT_MAX;
-
-	for (i = 0; i < nr_node_ids; i++) {
-		/* Start at @node */
-		n = (node + i) % nr_node_ids;
-
-		if (!nr_cpus_node(n))
-			continue;
-
-		/* Skip already used nodes */
-		if (node_isset(n, *used_nodes))
-			continue;
-
-		/* Simple min distance search */
-		val = node_distance(node, n);
-
-		if (val < min_val) {
-			min_val = val;
-			best_node = n;
-		}
-	}
-
-	if (best_node != -1)
-		node_set(best_node, *used_nodes);
-	return best_node;
-}
-
-/**
- * sched_domain_node_span - get a cpumask for a node's sched_domain
- * @node: node whose cpumask we're constructing
- * @span: resulting cpumask
- *
- * Given a node, construct a good cpumask for its sched_domain to span. It
- * should be one that prevents unnecessary balancing, but also spreads tasks
- * out optimally.
- */
-static void sched_domain_node_span(int node, struct cpumask *span)
-{
-	nodemask_t used_nodes;
-	int i;
-
-	cpumask_clear(span);
-	nodes_clear(used_nodes);
-
-	cpumask_or(span, span, cpumask_of_node(node));
-	node_set(node, used_nodes);
-
-	for (i = 1; i < SD_NODES_PER_DOMAIN; i++) {
-		int next_node = find_next_best_node(node, &used_nodes);
-		if (next_node < 0)
-			break;
-		cpumask_or(span, span, cpumask_of_node(next_node));
-	}
-}
-
-static const struct cpumask *cpu_node_mask(int cpu)
-{
-	lockdep_assert_held(&sched_domains_mutex);
-
-	sched_domain_node_span(cpu_to_node(cpu), sched_domains_tmpmask);
-
-	return sched_domains_tmpmask;
-}
-
-static const struct cpumask *cpu_allnodes_mask(int cpu)
-{
-	return cpu_possible_mask;
-}
-#endif /* CONFIG_NUMA */
-
 static const struct cpumask *cpu_cpu_mask(int cpu)
 {
 	return cpumask_of_node(cpu_to_node(cpu));
 }
 
-int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
-
 struct sd_data {
 	struct sched_domain **__percpu sd;
 	struct sched_group **__percpu sg;
@@ -6022,6 +5958,7 @@
 	sched_domain_init_f init;
 	sched_domain_mask_f mask;
 	int		    flags;
+	int		    numa_level;
 	struct sd_data      data;
 };
 
@@ -6213,10 +6150,6 @@
 }
 
 SD_INIT_FUNC(CPU)
-#ifdef CONFIG_NUMA
- SD_INIT_FUNC(ALLNODES)
- SD_INIT_FUNC(NODE)
-#endif
 #ifdef CONFIG_SCHED_SMT
  SD_INIT_FUNC(SIBLING)
 #endif
@@ -6338,15 +6271,184 @@
 	{ sd_init_BOOK, cpu_book_mask, },
 #endif
 	{ sd_init_CPU, cpu_cpu_mask, },
-#ifdef CONFIG_NUMA
-	{ sd_init_NODE, cpu_node_mask, SDTL_OVERLAP, },
-	{ sd_init_ALLNODES, cpu_allnodes_mask, },
-#endif
 	{ NULL, },
 };
 
 static struct sched_domain_topology_level *sched_domain_topology = default_topology;
 
+#ifdef CONFIG_NUMA
+
+static int sched_domains_numa_levels;
+static int sched_domains_numa_scale;
+static int *sched_domains_numa_distance;
+static struct cpumask ***sched_domains_numa_masks;
+static int sched_domains_curr_level;
+
+static inline int sd_local_flags(int level)
+{
+	if (sched_domains_numa_distance[level] > REMOTE_DISTANCE)
+		return 0;
+
+	return SD_BALANCE_EXEC | SD_BALANCE_FORK | SD_WAKE_AFFINE;
+}
+
+static struct sched_domain *
+sd_numa_init(struct sched_domain_topology_level *tl, int cpu)
+{
+	struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu);
+	int level = tl->numa_level;
+	int sd_weight = cpumask_weight(
+			sched_domains_numa_masks[level][cpu_to_node(cpu)]);
+
+	*sd = (struct sched_domain){
+		.min_interval		= sd_weight,
+		.max_interval		= 2*sd_weight,
+		.busy_factor		= 32,
+		.imbalance_pct		= 125,
+		.cache_nice_tries	= 2,
+		.busy_idx		= 3,
+		.idle_idx		= 2,
+		.newidle_idx		= 0,
+		.wake_idx		= 0,
+		.forkexec_idx		= 0,
+
+		.flags			= 1*SD_LOAD_BALANCE
+					| 1*SD_BALANCE_NEWIDLE
+					| 0*SD_BALANCE_EXEC
+					| 0*SD_BALANCE_FORK
+					| 0*SD_BALANCE_WAKE
+					| 0*SD_WAKE_AFFINE
+					| 0*SD_PREFER_LOCAL
+					| 0*SD_SHARE_CPUPOWER
+					| 0*SD_SHARE_PKG_RESOURCES
+					| 1*SD_SERIALIZE
+					| 0*SD_PREFER_SIBLING
+					| sd_local_flags(level)
+					,
+		.last_balance		= jiffies,
+		.balance_interval	= sd_weight,
+	};
+	SD_INIT_NAME(sd, NUMA);
+	sd->private = &tl->data;
+
+	/*
+	 * Ugly hack to pass state to sd_numa_mask()...
+	 */
+	sched_domains_curr_level = tl->numa_level;
+
+	return sd;
+}
+
+static const struct cpumask *sd_numa_mask(int cpu)
+{
+	return sched_domains_numa_masks[sched_domains_curr_level][cpu_to_node(cpu)];
+}
+
+static void sched_init_numa(void)
+{
+	int next_distance, curr_distance = node_distance(0, 0);
+	struct sched_domain_topology_level *tl;
+	int level = 0;
+	int i, j, k;
+
+	sched_domains_numa_scale = curr_distance;
+	sched_domains_numa_distance = kzalloc(sizeof(int) * nr_node_ids, GFP_KERNEL);
+	if (!sched_domains_numa_distance)
+		return;
+
+	/*
+	 * O(nr_nodes^2) deduplicating selection sort -- in order to find the
+	 * unique distances in the node_distance() table.
+	 *
+	 * Assumes node_distance(0,j) includes all distances in
+	 * node_distance(i,j) in order to avoid cubic time.
+	 *
+	 * XXX: could be optimized to O(n log n) by using sort()
+	 */
+	next_distance = curr_distance;
+	for (i = 0; i < nr_node_ids; i++) {
+		for (j = 0; j < nr_node_ids; j++) {
+			int distance = node_distance(0, j);
+			if (distance > curr_distance &&
+					(distance < next_distance ||
+					 next_distance == curr_distance))
+				next_distance = distance;
+		}
+		if (next_distance != curr_distance) {
+			sched_domains_numa_distance[level++] = next_distance;
+			sched_domains_numa_levels = level;
+			curr_distance = next_distance;
+		} else break;
+	}
+	/*
+	 * 'level' contains the number of unique distances, excluding the
+	 * identity distance node_distance(i,i).
+	 *
+	 * The sched_domains_nume_distance[] array includes the actual distance
+	 * numbers.
+	 */
+
+	sched_domains_numa_masks = kzalloc(sizeof(void *) * level, GFP_KERNEL);
+	if (!sched_domains_numa_masks)
+		return;
+
+	/*
+	 * Now for each level, construct a mask per node which contains all
+	 * cpus of nodes that are that many hops away from us.
+	 */
+	for (i = 0; i < level; i++) {
+		sched_domains_numa_masks[i] =
+			kzalloc(nr_node_ids * sizeof(void *), GFP_KERNEL);
+		if (!sched_domains_numa_masks[i])
+			return;
+
+		for (j = 0; j < nr_node_ids; j++) {
+			struct cpumask *mask = kzalloc_node(cpumask_size(), GFP_KERNEL, j);
+			if (!mask)
+				return;
+
+			sched_domains_numa_masks[i][j] = mask;
+
+			for (k = 0; k < nr_node_ids; k++) {
+				if (node_distance(j, k) > sched_domains_numa_distance[i])
+					continue;
+
+				cpumask_or(mask, mask, cpumask_of_node(k));
+			}
+		}
+	}
+
+	tl = kzalloc((ARRAY_SIZE(default_topology) + level) *
+			sizeof(struct sched_domain_topology_level), GFP_KERNEL);
+	if (!tl)
+		return;
+
+	/*
+	 * Copy the default topology bits..
+	 */
+	for (i = 0; default_topology[i].init; i++)
+		tl[i] = default_topology[i];
+
+	/*
+	 * .. and append 'j' levels of NUMA goodness.
+	 */
+	for (j = 0; j < level; i++, j++) {
+		tl[i] = (struct sched_domain_topology_level){
+			.init = sd_numa_init,
+			.mask = sd_numa_mask,
+			.flags = SDTL_OVERLAP,
+			.numa_level = j,
+		};
+	}
+
+	sched_domain_topology = tl;
+}
+#else
+static inline void sched_init_numa(void)
+{
+}
+#endif /* CONFIG_NUMA */
+
 static int __sdt_alloc(const struct cpumask *cpu_map)
 {
 	struct sched_domain_topology_level *tl;
@@ -6714,97 +6816,6 @@
 	mutex_unlock(&sched_domains_mutex);
 }
 
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-static void reinit_sched_domains(void)
-{
-	get_online_cpus();
-
-	/* Destroy domains first to force the rebuild */
-	partition_sched_domains(0, NULL, NULL);
-
-	rebuild_sched_domains();
-	put_online_cpus();
-}
-
-static ssize_t sched_power_savings_store(const char *buf, size_t count, int smt)
-{
-	unsigned int level = 0;
-
-	if (sscanf(buf, "%u", &level) != 1)
-		return -EINVAL;
-
-	/*
-	 * level is always be positive so don't check for
-	 * level < POWERSAVINGS_BALANCE_NONE which is 0
-	 * What happens on 0 or 1 byte write,
-	 * need to check for count as well?
-	 */
-
-	if (level >= MAX_POWERSAVINGS_BALANCE_LEVELS)
-		return -EINVAL;
-
-	if (smt)
-		sched_smt_power_savings = level;
-	else
-		sched_mc_power_savings = level;
-
-	reinit_sched_domains();
-
-	return count;
-}
-
-#ifdef CONFIG_SCHED_MC
-static ssize_t sched_mc_power_savings_show(struct device *dev,
-					   struct device_attribute *attr,
-					   char *buf)
-{
-	return sprintf(buf, "%u\n", sched_mc_power_savings);
-}
-static ssize_t sched_mc_power_savings_store(struct device *dev,
-					    struct device_attribute *attr,
-					    const char *buf, size_t count)
-{
-	return sched_power_savings_store(buf, count, 0);
-}
-static DEVICE_ATTR(sched_mc_power_savings, 0644,
-		   sched_mc_power_savings_show,
-		   sched_mc_power_savings_store);
-#endif
-
-#ifdef CONFIG_SCHED_SMT
-static ssize_t sched_smt_power_savings_show(struct device *dev,
-					    struct device_attribute *attr,
-					    char *buf)
-{
-	return sprintf(buf, "%u\n", sched_smt_power_savings);
-}
-static ssize_t sched_smt_power_savings_store(struct device *dev,
-					    struct device_attribute *attr,
-					     const char *buf, size_t count)
-{
-	return sched_power_savings_store(buf, count, 1);
-}
-static DEVICE_ATTR(sched_smt_power_savings, 0644,
-		   sched_smt_power_savings_show,
-		   sched_smt_power_savings_store);
-#endif
-
-int __init sched_create_sysfs_power_savings_entries(struct device *dev)
-{
-	int err = 0;
-
-#ifdef CONFIG_SCHED_SMT
-	if (smt_capable())
-		err = device_create_file(dev, &dev_attr_sched_smt_power_savings);
-#endif
-#ifdef CONFIG_SCHED_MC
-	if (!err && mc_capable())
-		err = device_create_file(dev, &dev_attr_sched_mc_power_savings);
-#endif
-	return err;
-}
-#endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */
-
 /*
  * Update cpusets according to cpu_active mask.  If cpusets are
  * disabled, cpuset_update_active_cpus() becomes a simple wrapper
@@ -6842,6 +6853,8 @@
 	alloc_cpumask_var(&non_isolated_cpus, GFP_KERNEL);
 	alloc_cpumask_var(&fallback_doms, GFP_KERNEL);
 
+	sched_init_numa();
+
 	get_online_cpus();
 	mutex_lock(&sched_domains_mutex);
 	init_sched_domains(cpu_active_mask);
@@ -7985,13 +7998,9 @@
 		.write_u64 = cpu_rt_period_write_uint,
 	},
 #endif
+	{ }	/* terminate */
 };
 
-static int cpu_cgroup_populate(struct cgroup_subsys *ss, struct cgroup *cont)
-{
-	return cgroup_add_files(cont, ss, cpu_files, ARRAY_SIZE(cpu_files));
-}
-
 struct cgroup_subsys cpu_cgroup_subsys = {
 	.name		= "cpu",
 	.create		= cpu_cgroup_create,
@@ -7999,8 +8008,8 @@
 	.can_attach	= cpu_cgroup_can_attach,
 	.attach		= cpu_cgroup_attach,
 	.exit		= cpu_cgroup_exit,
-	.populate	= cpu_cgroup_populate,
 	.subsys_id	= cpu_cgroup_subsys_id,
+	.base_cftypes	= cpu_files,
 	.early_init	= 1,
 };
 
@@ -8185,13 +8194,9 @@
 		.name = "stat",
 		.read_map = cpuacct_stats_show,
 	},
+	{ }	/* terminate */
 };
 
-static int cpuacct_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
-{
-	return cgroup_add_files(cgrp, ss, files, ARRAY_SIZE(files));
-}
-
 /*
  * charge this task's execution time to its accounting group.
  *
@@ -8223,7 +8228,7 @@
 	.name = "cpuacct",
 	.create = cpuacct_create,
 	.destroy = cpuacct_destroy,
-	.populate = cpuacct_populate,
 	.subsys_id = cpuacct_subsys_id,
+	.base_cftypes = files,
 };
 #endif	/* CONFIG_CGROUP_CPUACCT */
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 09acaa1..6f79596 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -202,7 +202,7 @@
 			SPLIT_NS(spread0));
 	SEQ_printf(m, "  .%-30s: %d\n", "nr_spread_over",
 			cfs_rq->nr_spread_over);
-	SEQ_printf(m, "  .%-30s: %ld\n", "nr_running", cfs_rq->nr_running);
+	SEQ_printf(m, "  .%-30s: %d\n", "nr_running", cfs_rq->nr_running);
 	SEQ_printf(m, "  .%-30s: %ld\n", "load", cfs_rq->load.weight);
 #ifdef CONFIG_FAIR_GROUP_SCHED
 #ifdef CONFIG_SMP
@@ -260,8 +260,14 @@
 	SEQ_printf(m, "\ncpu#%d\n", cpu);
 #endif
 
-#define P(x) \
-	SEQ_printf(m, "  .%-30s: %Ld\n", #x, (long long)(rq->x))
+#define P(x)								\
+do {									\
+	if (sizeof(rq->x) == 4)						\
+		SEQ_printf(m, "  .%-30s: %ld\n", #x, (long)(rq->x));	\
+	else								\
+		SEQ_printf(m, "  .%-30s: %Ld\n", #x, (long long)(rq->x));\
+} while (0)
+
 #define PN(x) \
 	SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rq->x))
 
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index e955364..940e6d1 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2721,7 +2721,7 @@
 		 * If power savings logic is enabled for a domain, see if we
 		 * are not overloaded, if so, don't balance wider.
 		 */
-		if (tmp->flags & (SD_POWERSAVINGS_BALANCE|SD_PREFER_LOCAL)) {
+		if (tmp->flags & (SD_PREFER_LOCAL)) {
 			unsigned long power = 0;
 			unsigned long nr_running = 0;
 			unsigned long capacity;
@@ -2734,9 +2734,6 @@
 
 			capacity = DIV_ROUND_CLOSEST(power, SCHED_POWER_SCALE);
 
-			if (tmp->flags & SD_POWERSAVINGS_BALANCE)
-				nr_running /= 2;
-
 			if (nr_running < capacity)
 				want_sd = 0;
 		}
@@ -3082,7 +3079,7 @@
 	struct rq		*dst_rq;
 
 	enum cpu_idle_type	idle;
-	long			load_move;
+	long			imbalance;
 	unsigned int		flags;
 
 	unsigned int		loop;
@@ -3218,7 +3215,7 @@
 static const unsigned int sched_nr_migrate_break = 32;
 
 /*
- * move_tasks tries to move up to load_move weighted load from busiest to
+ * move_tasks tries to move up to imbalance weighted load from busiest to
  * this_rq, as part of a balancing operation within domain "sd".
  * Returns 1 if successful and 0 otherwise.
  *
@@ -3231,7 +3228,7 @@
 	unsigned long load;
 	int pulled = 0;
 
-	if (env->load_move <= 0)
+	if (env->imbalance <= 0)
 		return 0;
 
 	while (!list_empty(tasks)) {
@@ -3257,7 +3254,7 @@
 		if (sched_feat(LB_MIN) && load < 16 && !env->sd->nr_balance_failed)
 			goto next;
 
-		if ((load / 2) > env->load_move)
+		if ((load / 2) > env->imbalance)
 			goto next;
 
 		if (!can_migrate_task(p, env))
@@ -3265,7 +3262,7 @@
 
 		move_task(p, env);
 		pulled++;
-		env->load_move -= load;
+		env->imbalance -= load;
 
 #ifdef CONFIG_PREEMPT
 		/*
@@ -3281,7 +3278,7 @@
 		 * We only want to steal up to the prescribed amount of
 		 * weighted load.
 		 */
-		if (env->load_move <= 0)
+		if (env->imbalance <= 0)
 			break;
 
 		continue;
@@ -3435,14 +3432,6 @@
 	unsigned int  busiest_group_weight;
 
 	int group_imb; /* Is there imbalance in this sd */
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-	int power_savings_balance; /* Is powersave balance needed for this sd */
-	struct sched_group *group_min; /* Least loaded group in sd */
-	struct sched_group *group_leader; /* Group which relieves group_min */
-	unsigned long min_load_per_task; /* load_per_task in group_min */
-	unsigned long leader_nr_running; /* Nr running of group_leader */
-	unsigned long min_nr_running; /* Nr running of group_min */
-#endif
 };
 
 /*
@@ -3486,148 +3475,6 @@
 	return load_idx;
 }
 
-
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-/**
- * init_sd_power_savings_stats - Initialize power savings statistics for
- * the given sched_domain, during load balancing.
- *
- * @sd: Sched domain whose power-savings statistics are to be initialized.
- * @sds: Variable containing the statistics for sd.
- * @idle: Idle status of the CPU at which we're performing load-balancing.
- */
-static inline void init_sd_power_savings_stats(struct sched_domain *sd,
-	struct sd_lb_stats *sds, enum cpu_idle_type idle)
-{
-	/*
-	 * Busy processors will not participate in power savings
-	 * balance.
-	 */
-	if (idle == CPU_NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE))
-		sds->power_savings_balance = 0;
-	else {
-		sds->power_savings_balance = 1;
-		sds->min_nr_running = ULONG_MAX;
-		sds->leader_nr_running = 0;
-	}
-}
-
-/**
- * update_sd_power_savings_stats - Update the power saving stats for a
- * sched_domain while performing load balancing.
- *
- * @group: sched_group belonging to the sched_domain under consideration.
- * @sds: Variable containing the statistics of the sched_domain
- * @local_group: Does group contain the CPU for which we're performing
- * 		load balancing ?
- * @sgs: Variable containing the statistics of the group.
- */
-static inline void update_sd_power_savings_stats(struct sched_group *group,
-	struct sd_lb_stats *sds, int local_group, struct sg_lb_stats *sgs)
-{
-
-	if (!sds->power_savings_balance)
-		return;
-
-	/*
-	 * If the local group is idle or completely loaded
-	 * no need to do power savings balance at this domain
-	 */
-	if (local_group && (sds->this_nr_running >= sgs->group_capacity ||
-				!sds->this_nr_running))
-		sds->power_savings_balance = 0;
-
-	/*
-	 * If a group is already running at full capacity or idle,
-	 * don't include that group in power savings calculations
-	 */
-	if (!sds->power_savings_balance ||
-		sgs->sum_nr_running >= sgs->group_capacity ||
-		!sgs->sum_nr_running)
-		return;
-
-	/*
-	 * Calculate the group which has the least non-idle load.
-	 * This is the group from where we need to pick up the load
-	 * for saving power
-	 */
-	if ((sgs->sum_nr_running < sds->min_nr_running) ||
-	    (sgs->sum_nr_running == sds->min_nr_running &&
-	     group_first_cpu(group) > group_first_cpu(sds->group_min))) {
-		sds->group_min = group;
-		sds->min_nr_running = sgs->sum_nr_running;
-		sds->min_load_per_task = sgs->sum_weighted_load /
-						sgs->sum_nr_running;
-	}
-
-	/*
-	 * Calculate the group which is almost near its
-	 * capacity but still has some space to pick up some load
-	 * from other group and save more power
-	 */
-	if (sgs->sum_nr_running + 1 > sgs->group_capacity)
-		return;
-
-	if (sgs->sum_nr_running > sds->leader_nr_running ||
-	    (sgs->sum_nr_running == sds->leader_nr_running &&
-	     group_first_cpu(group) < group_first_cpu(sds->group_leader))) {
-		sds->group_leader = group;
-		sds->leader_nr_running = sgs->sum_nr_running;
-	}
-}
-
-/**
- * check_power_save_busiest_group - see if there is potential for some power-savings balance
- * @sds: Variable containing the statistics of the sched_domain
- *	under consideration.
- * @this_cpu: Cpu at which we're currently performing load-balancing.
- * @imbalance: Variable to store the imbalance.
- *
- * Description:
- * Check if we have potential to perform some power-savings balance.
- * If yes, set the busiest group to be the least loaded group in the
- * sched_domain, so that it's CPUs can be put to idle.
- *
- * Returns 1 if there is potential to perform power-savings balance.
- * Else returns 0.
- */
-static inline int check_power_save_busiest_group(struct sd_lb_stats *sds,
-					int this_cpu, unsigned long *imbalance)
-{
-	if (!sds->power_savings_balance)
-		return 0;
-
-	if (sds->this != sds->group_leader ||
-			sds->group_leader == sds->group_min)
-		return 0;
-
-	*imbalance = sds->min_load_per_task;
-	sds->busiest = sds->group_min;
-
-	return 1;
-
-}
-#else /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */
-static inline void init_sd_power_savings_stats(struct sched_domain *sd,
-	struct sd_lb_stats *sds, enum cpu_idle_type idle)
-{
-	return;
-}
-
-static inline void update_sd_power_savings_stats(struct sched_group *group,
-	struct sd_lb_stats *sds, int local_group, struct sg_lb_stats *sgs)
-{
-	return;
-}
-
-static inline int check_power_save_busiest_group(struct sd_lb_stats *sds,
-					int this_cpu, unsigned long *imbalance)
-{
-	return 0;
-}
-#endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */
-
-
 unsigned long default_scale_freq_power(struct sched_domain *sd, int cpu)
 {
 	return SCHED_POWER_SCALE;
@@ -3765,24 +3612,22 @@
  * update_sg_lb_stats - Update sched_group's statistics for load balancing.
  * @sd: The sched_domain whose statistics are to be updated.
  * @group: sched_group whose statistics are to be updated.
- * @this_cpu: Cpu for which load balance is currently performed.
- * @idle: Idle status of this_cpu
  * @load_idx: Load index of sched_domain of this_cpu for load calc.
  * @local_group: Does group contain this_cpu.
  * @cpus: Set of cpus considered for load balancing.
  * @balance: Should we balance.
  * @sgs: variable to hold the statistics for this group.
  */
-static inline void update_sg_lb_stats(struct sched_domain *sd,
-			struct sched_group *group, int this_cpu,
-			enum cpu_idle_type idle, int load_idx,
+static inline void update_sg_lb_stats(struct lb_env *env,
+			struct sched_group *group, int load_idx,
 			int local_group, const struct cpumask *cpus,
 			int *balance, struct sg_lb_stats *sgs)
 {
-	unsigned long load, max_cpu_load, min_cpu_load, max_nr_running;
-	int i;
+	unsigned long nr_running, max_nr_running, min_nr_running;
+	unsigned long load, max_cpu_load, min_cpu_load;
 	unsigned int balance_cpu = -1, first_idle_cpu = 0;
 	unsigned long avg_load_per_task = 0;
+	int i;
 
 	if (local_group)
 		balance_cpu = group_first_cpu(group);
@@ -3791,10 +3636,13 @@
 	max_cpu_load = 0;
 	min_cpu_load = ~0UL;
 	max_nr_running = 0;
+	min_nr_running = ~0UL;
 
 	for_each_cpu_and(i, sched_group_cpus(group), cpus) {
 		struct rq *rq = cpu_rq(i);
 
+		nr_running = rq->nr_running;
+
 		/* Bias balancing toward cpus of our domain */
 		if (local_group) {
 			if (idle_cpu(i) && !first_idle_cpu) {
@@ -3805,16 +3653,19 @@
 			load = target_load(i, load_idx);
 		} else {
 			load = source_load(i, load_idx);
-			if (load > max_cpu_load) {
+			if (load > max_cpu_load)
 				max_cpu_load = load;
-				max_nr_running = rq->nr_running;
-			}
 			if (min_cpu_load > load)
 				min_cpu_load = load;
+
+			if (nr_running > max_nr_running)
+				max_nr_running = nr_running;
+			if (min_nr_running > nr_running)
+				min_nr_running = nr_running;
 		}
 
 		sgs->group_load += load;
-		sgs->sum_nr_running += rq->nr_running;
+		sgs->sum_nr_running += nr_running;
 		sgs->sum_weighted_load += weighted_cpuload(i);
 		if (idle_cpu(i))
 			sgs->idle_cpus++;
@@ -3827,14 +3678,14 @@
 	 * to do the newly idle load balance.
 	 */
 	if (local_group) {
-		if (idle != CPU_NEWLY_IDLE) {
-			if (balance_cpu != this_cpu) {
+		if (env->idle != CPU_NEWLY_IDLE) {
+			if (balance_cpu != env->dst_cpu) {
 				*balance = 0;
 				return;
 			}
-			update_group_power(sd, this_cpu);
+			update_group_power(env->sd, env->dst_cpu);
 		} else if (time_after_eq(jiffies, group->sgp->next_update))
-			update_group_power(sd, this_cpu);
+			update_group_power(env->sd, env->dst_cpu);
 	}
 
 	/* Adjust by relative CPU power of the group */
@@ -3852,13 +3703,14 @@
 	if (sgs->sum_nr_running)
 		avg_load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running;
 
-	if ((max_cpu_load - min_cpu_load) >= avg_load_per_task && max_nr_running > 1)
+	if ((max_cpu_load - min_cpu_load) >= avg_load_per_task &&
+	    (max_nr_running - min_nr_running) > 1)
 		sgs->group_imb = 1;
 
 	sgs->group_capacity = DIV_ROUND_CLOSEST(group->sgp->power,
 						SCHED_POWER_SCALE);
 	if (!sgs->group_capacity)
-		sgs->group_capacity = fix_small_capacity(sd, group);
+		sgs->group_capacity = fix_small_capacity(env->sd, group);
 	sgs->group_weight = group->group_weight;
 
 	if (sgs->group_capacity > sgs->sum_nr_running)
@@ -3876,11 +3728,10 @@
  * Determine if @sg is a busier group than the previously selected
  * busiest group.
  */
-static bool update_sd_pick_busiest(struct sched_domain *sd,
+static bool update_sd_pick_busiest(struct lb_env *env,
 				   struct sd_lb_stats *sds,
 				   struct sched_group *sg,
-				   struct sg_lb_stats *sgs,
-				   int this_cpu)
+				   struct sg_lb_stats *sgs)
 {
 	if (sgs->avg_load <= sds->max_load)
 		return false;
@@ -3896,8 +3747,8 @@
 	 * numbered CPUs in the group, therefore mark all groups
 	 * higher than ourself as busy.
 	 */
-	if ((sd->flags & SD_ASYM_PACKING) && sgs->sum_nr_running &&
-	    this_cpu < group_first_cpu(sg)) {
+	if ((env->sd->flags & SD_ASYM_PACKING) && sgs->sum_nr_running &&
+	    env->dst_cpu < group_first_cpu(sg)) {
 		if (!sds->busiest)
 			return true;
 
@@ -3917,28 +3768,27 @@
  * @balance: Should we balance.
  * @sds: variable to hold the statistics for this sched_domain.
  */
-static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
-			enum cpu_idle_type idle, const struct cpumask *cpus,
-			int *balance, struct sd_lb_stats *sds)
+static inline void update_sd_lb_stats(struct lb_env *env,
+				      const struct cpumask *cpus,
+				      int *balance, struct sd_lb_stats *sds)
 {
-	struct sched_domain *child = sd->child;
-	struct sched_group *sg = sd->groups;
+	struct sched_domain *child = env->sd->child;
+	struct sched_group *sg = env->sd->groups;
 	struct sg_lb_stats sgs;
 	int load_idx, prefer_sibling = 0;
 
 	if (child && child->flags & SD_PREFER_SIBLING)
 		prefer_sibling = 1;
 
-	init_sd_power_savings_stats(sd, sds, idle);
-	load_idx = get_sd_load_idx(sd, idle);
+	load_idx = get_sd_load_idx(env->sd, env->idle);
 
 	do {
 		int local_group;
 
-		local_group = cpumask_test_cpu(this_cpu, sched_group_cpus(sg));
+		local_group = cpumask_test_cpu(env->dst_cpu, sched_group_cpus(sg));
 		memset(&sgs, 0, sizeof(sgs));
-		update_sg_lb_stats(sd, sg, this_cpu, idle, load_idx,
-				local_group, cpus, balance, &sgs);
+		update_sg_lb_stats(env, sg, load_idx, local_group,
+				   cpus, balance, &sgs);
 
 		if (local_group && !(*balance))
 			return;
@@ -3966,7 +3816,7 @@
 			sds->this_load_per_task = sgs.sum_weighted_load;
 			sds->this_has_capacity = sgs.group_has_capacity;
 			sds->this_idle_cpus = sgs.idle_cpus;
-		} else if (update_sd_pick_busiest(sd, sds, sg, &sgs, this_cpu)) {
+		} else if (update_sd_pick_busiest(env, sds, sg, &sgs)) {
 			sds->max_load = sgs.avg_load;
 			sds->busiest = sg;
 			sds->busiest_nr_running = sgs.sum_nr_running;
@@ -3978,9 +3828,8 @@
 			sds->group_imb = sgs.group_imb;
 		}
 
-		update_sd_power_savings_stats(sg, sds, local_group, &sgs);
 		sg = sg->next;
-	} while (sg != sd->groups);
+	} while (sg != env->sd->groups);
 }
 
 /**
@@ -4008,24 +3857,23 @@
  * @this_cpu: The cpu at whose sched_domain we're performing load-balance.
  * @imbalance: returns amount of imbalanced due to packing.
  */
-static int check_asym_packing(struct sched_domain *sd,
-			      struct sd_lb_stats *sds,
-			      int this_cpu, unsigned long *imbalance)
+static int check_asym_packing(struct lb_env *env, struct sd_lb_stats *sds)
 {
 	int busiest_cpu;
 
-	if (!(sd->flags & SD_ASYM_PACKING))
+	if (!(env->sd->flags & SD_ASYM_PACKING))
 		return 0;
 
 	if (!sds->busiest)
 		return 0;
 
 	busiest_cpu = group_first_cpu(sds->busiest);
-	if (this_cpu > busiest_cpu)
+	if (env->dst_cpu > busiest_cpu)
 		return 0;
 
-	*imbalance = DIV_ROUND_CLOSEST(sds->max_load * sds->busiest->sgp->power,
-				       SCHED_POWER_SCALE);
+	env->imbalance = DIV_ROUND_CLOSEST(
+		sds->max_load * sds->busiest->sgp->power, SCHED_POWER_SCALE);
+
 	return 1;
 }
 
@@ -4037,8 +3885,8 @@
  * @this_cpu: The cpu at whose sched_domain we're performing load-balance.
  * @imbalance: Variable to store the imbalance.
  */
-static inline void fix_small_imbalance(struct sd_lb_stats *sds,
-				int this_cpu, unsigned long *imbalance)
+static inline
+void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
 {
 	unsigned long tmp, pwr_now = 0, pwr_move = 0;
 	unsigned int imbn = 2;
@@ -4049,9 +3897,10 @@
 		if (sds->busiest_load_per_task >
 				sds->this_load_per_task)
 			imbn = 1;
-	} else
+	} else {
 		sds->this_load_per_task =
-			cpu_avg_load_per_task(this_cpu);
+			cpu_avg_load_per_task(env->dst_cpu);
+	}
 
 	scaled_busy_load_per_task = sds->busiest_load_per_task
 					 * SCHED_POWER_SCALE;
@@ -4059,7 +3908,7 @@
 
 	if (sds->max_load - sds->this_load + scaled_busy_load_per_task >=
 			(scaled_busy_load_per_task * imbn)) {
-		*imbalance = sds->busiest_load_per_task;
+		env->imbalance = sds->busiest_load_per_task;
 		return;
 	}
 
@@ -4096,18 +3945,16 @@
 
 	/* Move if we gain throughput */
 	if (pwr_move > pwr_now)
-		*imbalance = sds->busiest_load_per_task;
+		env->imbalance = sds->busiest_load_per_task;
 }
 
 /**
  * calculate_imbalance - Calculate the amount of imbalance present within the
  *			 groups of a given sched_domain during load balance.
+ * @env: load balance environment
  * @sds: statistics of the sched_domain whose imbalance is to be calculated.
- * @this_cpu: Cpu for which currently load balance is being performed.
- * @imbalance: The variable to store the imbalance.
  */
-static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu,
-		unsigned long *imbalance)
+static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
 {
 	unsigned long max_pull, load_above_capacity = ~0UL;
 
@@ -4123,8 +3970,8 @@
 	 * its cpu_power, while calculating max_load..)
 	 */
 	if (sds->max_load < sds->avg_load) {
-		*imbalance = 0;
-		return fix_small_imbalance(sds, this_cpu, imbalance);
+		env->imbalance = 0;
+		return fix_small_imbalance(env, sds);
 	}
 
 	if (!sds->group_imb) {
@@ -4152,7 +3999,7 @@
 	max_pull = min(sds->max_load - sds->avg_load, load_above_capacity);
 
 	/* How much load to actually move to equalise the imbalance */
-	*imbalance = min(max_pull * sds->busiest->sgp->power,
+	env->imbalance = min(max_pull * sds->busiest->sgp->power,
 		(sds->avg_load - sds->this_load) * sds->this->sgp->power)
 			/ SCHED_POWER_SCALE;
 
@@ -4162,8 +4009,8 @@
 	 * a think about bumping its value to force at least one task to be
 	 * moved
 	 */
-	if (*imbalance < sds->busiest_load_per_task)
-		return fix_small_imbalance(sds, this_cpu, imbalance);
+	if (env->imbalance < sds->busiest_load_per_task)
+		return fix_small_imbalance(env, sds);
 
 }
 
@@ -4194,9 +4041,7 @@
  *		   put to idle by rebalancing its tasks onto our group.
  */
 static struct sched_group *
-find_busiest_group(struct sched_domain *sd, int this_cpu,
-		   unsigned long *imbalance, enum cpu_idle_type idle,
-		   const struct cpumask *cpus, int *balance)
+find_busiest_group(struct lb_env *env, const struct cpumask *cpus, int *balance)
 {
 	struct sd_lb_stats sds;
 
@@ -4206,7 +4051,7 @@
 	 * Compute the various statistics relavent for load balancing at
 	 * this level.
 	 */
-	update_sd_lb_stats(sd, this_cpu, idle, cpus, balance, &sds);
+	update_sd_lb_stats(env, cpus, balance, &sds);
 
 	/*
 	 * this_cpu is not the appropriate cpu to perform load balancing at
@@ -4215,8 +4060,8 @@
 	if (!(*balance))
 		goto ret;
 
-	if ((idle == CPU_IDLE || idle == CPU_NEWLY_IDLE) &&
-	    check_asym_packing(sd, &sds, this_cpu, imbalance))
+	if ((env->idle == CPU_IDLE || env->idle == CPU_NEWLY_IDLE) &&
+	    check_asym_packing(env, &sds))
 		return sds.busiest;
 
 	/* There is no busy sibling group to pull tasks from */
@@ -4234,7 +4079,7 @@
 		goto force_balance;
 
 	/* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
-	if (idle == CPU_NEWLY_IDLE && sds.this_has_capacity &&
+	if (env->idle == CPU_NEWLY_IDLE && sds.this_has_capacity &&
 			!sds.busiest_has_capacity)
 		goto force_balance;
 
@@ -4252,7 +4097,7 @@
 	if (sds.this_load >= sds.avg_load)
 		goto out_balanced;
 
-	if (idle == CPU_IDLE) {
+	if (env->idle == CPU_IDLE) {
 		/*
 		 * This cpu is idle. If the busiest group load doesn't
 		 * have more tasks than the number of available cpu's and
@@ -4267,34 +4112,27 @@
 		 * In the CPU_NEWLY_IDLE, CPU_NOT_IDLE cases, use
 		 * imbalance_pct to be conservative.
 		 */
-		if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load)
+		if (100 * sds.max_load <= env->sd->imbalance_pct * sds.this_load)
 			goto out_balanced;
 	}
 
 force_balance:
 	/* Looks like there is an imbalance. Compute it */
-	calculate_imbalance(&sds, this_cpu, imbalance);
+	calculate_imbalance(env, &sds);
 	return sds.busiest;
 
 out_balanced:
-	/*
-	 * There is no obvious imbalance. But check if we can do some balancing
-	 * to save power.
-	 */
-	if (check_power_save_busiest_group(&sds, this_cpu, imbalance))
-		return sds.busiest;
 ret:
-	*imbalance = 0;
+	env->imbalance = 0;
 	return NULL;
 }
 
 /*
  * find_busiest_queue - find the busiest runqueue among the cpus in group.
  */
-static struct rq *
-find_busiest_queue(struct sched_domain *sd, struct sched_group *group,
-		   enum cpu_idle_type idle, unsigned long imbalance,
-		   const struct cpumask *cpus)
+static struct rq *find_busiest_queue(struct lb_env *env,
+				     struct sched_group *group,
+				     const struct cpumask *cpus)
 {
 	struct rq *busiest = NULL, *rq;
 	unsigned long max_load = 0;
@@ -4307,7 +4145,7 @@
 		unsigned long wl;
 
 		if (!capacity)
-			capacity = fix_small_capacity(sd, group);
+			capacity = fix_small_capacity(env->sd, group);
 
 		if (!cpumask_test_cpu(i, cpus))
 			continue;
@@ -4319,7 +4157,7 @@
 		 * When comparing with imbalance, use weighted_cpuload()
 		 * which is not scaled with the cpu power.
 		 */
-		if (capacity && rq->nr_running == 1 && wl > imbalance)
+		if (capacity && rq->nr_running == 1 && wl > env->imbalance)
 			continue;
 
 		/*
@@ -4348,40 +4186,19 @@
 /* Working cpumask for load_balance and load_balance_newidle. */
 DEFINE_PER_CPU(cpumask_var_t, load_balance_tmpmask);
 
-static int need_active_balance(struct sched_domain *sd, int idle,
-			       int busiest_cpu, int this_cpu)
+static int need_active_balance(struct lb_env *env)
 {
-	if (idle == CPU_NEWLY_IDLE) {
+	struct sched_domain *sd = env->sd;
+
+	if (env->idle == CPU_NEWLY_IDLE) {
 
 		/*
 		 * ASYM_PACKING needs to force migrate tasks from busy but
 		 * higher numbered CPUs in order to pack all tasks in the
 		 * lowest numbered CPUs.
 		 */
-		if ((sd->flags & SD_ASYM_PACKING) && busiest_cpu > this_cpu)
+		if ((sd->flags & SD_ASYM_PACKING) && env->src_cpu > env->dst_cpu)
 			return 1;
-
-		/*
-		 * The only task running in a non-idle cpu can be moved to this
-		 * cpu in an attempt to completely freeup the other CPU
-		 * package.
-		 *
-		 * The package power saving logic comes from
-		 * find_busiest_group(). If there are no imbalance, then
-		 * f_b_g() will return NULL. However when sched_mc={1,2} then
-		 * f_b_g() will select a group from which a running task may be
-		 * pulled to this cpu in order to make the other package idle.
-		 * If there is no opportunity to make a package idle and if
-		 * there are no imbalance, then f_b_g() will return NULL and no
-		 * action will be taken in load_balance_newidle().
-		 *
-		 * Under normal task pull operation due to imbalance, there
-		 * will be more than one task in the source run queue and
-		 * move_tasks() will succeed.  ld_moved will be true and this
-		 * active balance code will not be triggered.
-		 */
-		if (sched_mc_power_savings < POWERSAVINGS_BALANCE_WAKEUP)
-			return 0;
 	}
 
 	return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2);
@@ -4399,7 +4216,6 @@
 {
 	int ld_moved, active_balance = 0;
 	struct sched_group *group;
-	unsigned long imbalance;
 	struct rq *busiest;
 	unsigned long flags;
 	struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
@@ -4417,8 +4233,7 @@
 	schedstat_inc(sd, lb_count[idle]);
 
 redo:
-	group = find_busiest_group(sd, this_cpu, &imbalance, idle,
-				   cpus, balance);
+	group = find_busiest_group(&env, cpus, balance);
 
 	if (*balance == 0)
 		goto out_balanced;
@@ -4428,7 +4243,7 @@
 		goto out_balanced;
 	}
 
-	busiest = find_busiest_queue(sd, group, idle, imbalance, cpus);
+	busiest = find_busiest_queue(&env, group, cpus);
 	if (!busiest) {
 		schedstat_inc(sd, lb_nobusyq[idle]);
 		goto out_balanced;
@@ -4436,7 +4251,7 @@
 
 	BUG_ON(busiest == this_rq);
 
-	schedstat_add(sd, lb_imbalance[idle], imbalance);
+	schedstat_add(sd, lb_imbalance[idle], env.imbalance);
 
 	ld_moved = 0;
 	if (busiest->nr_running > 1) {
@@ -4447,10 +4262,9 @@
 		 * correctly treated as an imbalance.
 		 */
 		env.flags |= LBF_ALL_PINNED;
-		env.load_move	= imbalance;
-		env.src_cpu	= busiest->cpu;
-		env.src_rq	= busiest;
-		env.loop_max	= min_t(unsigned long, sysctl_sched_nr_migrate, busiest->nr_running);
+		env.src_cpu   = busiest->cpu;
+		env.src_rq    = busiest;
+		env.loop_max  = min(sysctl_sched_nr_migrate, busiest->nr_running);
 
 more_balance:
 		local_irq_save(flags);
@@ -4492,7 +4306,7 @@
 		if (idle != CPU_NEWLY_IDLE)
 			sd->nr_balance_failed++;
 
-		if (need_active_balance(sd, idle, cpu_of(busiest), this_cpu)) {
+		if (need_active_balance(&env)) {
 			raw_spin_lock_irqsave(&busiest->lock, flags);
 
 			/* don't kick the active_load_balance_cpu_stop,
@@ -4519,10 +4333,11 @@
 			}
 			raw_spin_unlock_irqrestore(&busiest->lock, flags);
 
-			if (active_balance)
+			if (active_balance) {
 				stop_one_cpu_nowait(cpu_of(busiest),
 					active_load_balance_cpu_stop, busiest,
 					&busiest->active_balance_work);
+			}
 
 			/*
 			 * We've kicked active balancing, reset the failure
@@ -4703,104 +4518,15 @@
 	unsigned long next_balance;     /* in jiffy units */
 } nohz ____cacheline_aligned;
 
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-/**
- * lowest_flag_domain - Return lowest sched_domain containing flag.
- * @cpu:	The cpu whose lowest level of sched domain is to
- *		be returned.
- * @flag:	The flag to check for the lowest sched_domain
- *		for the given cpu.
- *
- * Returns the lowest sched_domain of a cpu which contains the given flag.
- */
-static inline struct sched_domain *lowest_flag_domain(int cpu, int flag)
-{
-	struct sched_domain *sd;
-
-	for_each_domain(cpu, sd)
-		if (sd->flags & flag)
-			break;
-
-	return sd;
-}
-
-/**
- * for_each_flag_domain - Iterates over sched_domains containing the flag.
- * @cpu:	The cpu whose domains we're iterating over.
- * @sd:		variable holding the value of the power_savings_sd
- *		for cpu.
- * @flag:	The flag to filter the sched_domains to be iterated.
- *
- * Iterates over all the scheduler domains for a given cpu that has the 'flag'
- * set, starting from the lowest sched_domain to the highest.
- */
-#define for_each_flag_domain(cpu, sd, flag) \
-	for (sd = lowest_flag_domain(cpu, flag); \
-		(sd && (sd->flags & flag)); sd = sd->parent)
-
-/**
- * find_new_ilb - Finds the optimum idle load balancer for nomination.
- * @cpu:	The cpu which is nominating a new idle_load_balancer.
- *
- * Returns:	Returns the id of the idle load balancer if it exists,
- *		Else, returns >= nr_cpu_ids.
- *
- * This algorithm picks the idle load balancer such that it belongs to a
- * semi-idle powersavings sched_domain. The idea is to try and avoid
- * completely idle packages/cores just for the purpose of idle load balancing
- * when there are other idle cpu's which are better suited for that job.
- */
-static int find_new_ilb(int cpu)
+static inline int find_new_ilb(int call_cpu)
 {
 	int ilb = cpumask_first(nohz.idle_cpus_mask);
-	struct sched_group *ilbg;
-	struct sched_domain *sd;
 
-	/*
-	 * Have idle load balancer selection from semi-idle packages only
-	 * when power-aware load balancing is enabled
-	 */
-	if (!(sched_smt_power_savings || sched_mc_power_savings))
-		goto out_done;
-
-	/*
-	 * Optimize for the case when we have no idle CPUs or only one
-	 * idle CPU. Don't walk the sched_domain hierarchy in such cases
-	 */
-	if (cpumask_weight(nohz.idle_cpus_mask) < 2)
-		goto out_done;
-
-	rcu_read_lock();
-	for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) {
-		ilbg = sd->groups;
-
-		do {
-			if (ilbg->group_weight !=
-				atomic_read(&ilbg->sgp->nr_busy_cpus)) {
-				ilb = cpumask_first_and(nohz.idle_cpus_mask,
-							sched_group_cpus(ilbg));
-				goto unlock;
-			}
-
-			ilbg = ilbg->next;
-
-		} while (ilbg != sd->groups);
-	}
-unlock:
-	rcu_read_unlock();
-
-out_done:
 	if (ilb < nr_cpu_ids && idle_cpu(ilb))
 		return ilb;
 
 	return nr_cpu_ids;
 }
-#else /*  (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */
-static inline int find_new_ilb(int call_cpu)
-{
-	return nr_cpu_ids;
-}
-#endif
 
 /*
  * Kick a CPU to do the nohz balancing, if it is time for it. We pick the
@@ -5023,7 +4749,7 @@
 
 		raw_spin_lock_irq(&this_rq->lock);
 		update_rq_clock(this_rq);
-		update_cpu_load(this_rq);
+		update_idle_cpu_load(this_rq);
 		raw_spin_unlock_irq(&this_rq->lock);
 
 		rebalance_domains(balance_cpu, CPU_IDLE);
diff --git a/kernel/sched/idle_task.c b/kernel/sched/idle_task.c
index 91b4c95..b44d604 100644
--- a/kernel/sched/idle_task.c
+++ b/kernel/sched/idle_task.c
@@ -4,7 +4,7 @@
  * idle-task scheduling class.
  *
  * (NOTE: these are not related to SCHED_IDLE tasks which are
- *  handled in sched_fair.c)
+ *  handled in sched/fair.c)
  */
 
 #ifdef CONFIG_SMP
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 44af55e..c5565c3 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1803,44 +1803,40 @@
 static void set_cpus_allowed_rt(struct task_struct *p,
 				const struct cpumask *new_mask)
 {
-	int weight = cpumask_weight(new_mask);
+	struct rq *rq;
+	int weight;
 
 	BUG_ON(!rt_task(p));
 
+	if (!p->on_rq)
+		return;
+
+	weight = cpumask_weight(new_mask);
+
 	/*
-	 * Update the migration status of the RQ if we have an RT task
-	 * which is running AND changing its weight value.
+	 * Only update if the process changes its state from whether it
+	 * can migrate or not.
 	 */
-	if (p->on_rq && (weight != p->rt.nr_cpus_allowed)) {
-		struct rq *rq = task_rq(p);
+	if ((p->rt.nr_cpus_allowed > 1) == (weight > 1))
+		return;
 
-		if (!task_current(rq, p)) {
-			/*
-			 * Make sure we dequeue this task from the pushable list
-			 * before going further.  It will either remain off of
-			 * the list because we are no longer pushable, or it
-			 * will be requeued.
-			 */
-			if (p->rt.nr_cpus_allowed > 1)
-				dequeue_pushable_task(rq, p);
+	rq = task_rq(p);
 
-			/*
-			 * Requeue if our weight is changing and still > 1
-			 */
-			if (weight > 1)
-				enqueue_pushable_task(rq, p);
-
-		}
-
-		if ((p->rt.nr_cpus_allowed <= 1) && (weight > 1)) {
-			rq->rt.rt_nr_migratory++;
-		} else if ((p->rt.nr_cpus_allowed > 1) && (weight <= 1)) {
-			BUG_ON(!rq->rt.rt_nr_migratory);
-			rq->rt.rt_nr_migratory--;
-		}
-
-		update_rt_migration(&rq->rt);
+	/*
+	 * The process used to be able to migrate OR it can now migrate
+	 */
+	if (weight <= 1) {
+		if (!task_current(rq, p))
+			dequeue_pushable_task(rq, p);
+		BUG_ON(!rq->rt.rt_nr_migratory);
+		rq->rt.rt_nr_migratory--;
+	} else {
+		if (!task_current(rq, p))
+			enqueue_pushable_task(rq, p);
+		rq->rt.rt_nr_migratory++;
 	}
+
+	update_rt_migration(&rq->rt);
 }
 
 /* Assumes rq->lock is held */
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index fb3acba..ba9dccf 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -201,7 +201,7 @@
 /* CFS-related fields in a runqueue */
 struct cfs_rq {
 	struct load_weight load;
-	unsigned long nr_running, h_nr_running;
+	unsigned int nr_running, h_nr_running;
 
 	u64 exec_clock;
 	u64 min_vruntime;
@@ -279,7 +279,7 @@
 /* Real-Time classes' related field in a runqueue: */
 struct rt_rq {
 	struct rt_prio_array active;
-	unsigned long rt_nr_running;
+	unsigned int rt_nr_running;
 #if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED
 	struct {
 		int curr; /* highest queued rt task prio */
@@ -353,7 +353,7 @@
 	 * nr_running and cpu_load should be in the same cacheline because
 	 * remote CPUs use both these fields when doing load calculation.
 	 */
-	unsigned long nr_running;
+	unsigned int nr_running;
 	#define CPU_LOAD_IDX_MAX 5
 	unsigned long cpu_load[CPU_LOAD_IDX_MAX];
 	unsigned long last_load_update_tick;
@@ -876,7 +876,7 @@
 extern struct rt_bandwidth def_rt_bandwidth;
 extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime);
 
-extern void update_cpu_load(struct rq *this_rq);
+extern void update_idle_cpu_load(struct rq *this_rq);
 
 #ifdef CONFIG_CGROUP_CPUACCT
 #include <linux/cgroup.h>
diff --git a/kernel/semaphore.c b/kernel/semaphore.c
index 60636a4..4567fc0 100644
--- a/kernel/semaphore.c
+++ b/kernel/semaphore.c
@@ -118,7 +118,7 @@
  * down_trylock - try to acquire the semaphore, without waiting
  * @sem: the semaphore to be acquired
  *
- * Try to acquire the semaphore atomically.  Returns 0 if the mutex has
+ * Try to acquire the semaphore atomically.  Returns 0 if the semaphore has
  * been acquired successfully or 1 if it it cannot be acquired.
  *
  * NOTE: This return value is inverted from both spin_trylock and
diff --git a/kernel/signal.c b/kernel/signal.c
index 1a006b5..f7b4182 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -29,6 +29,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/nsproxy.h>
 #include <linux/user_namespace.h>
+#include <linux/uprobes.h>
 #define CREATE_TRACE_POINTS
 #include <trace/events/signal.h>
 
@@ -767,14 +768,13 @@
 	const struct cred *cred = current_cred();
 	const struct cred *tcred = __task_cred(t);
 
-	if (cred->user->user_ns == tcred->user->user_ns &&
-	    (cred->euid == tcred->suid ||
-	     cred->euid == tcred->uid ||
-	     cred->uid  == tcred->suid ||
-	     cred->uid  == tcred->uid))
+	if (uid_eq(cred->euid, tcred->suid) ||
+	    uid_eq(cred->euid, tcred->uid)  ||
+	    uid_eq(cred->uid,  tcred->suid) ||
+	    uid_eq(cred->uid,  tcred->uid))
 		return 1;
 
-	if (ns_capable(tcred->user->user_ns, CAP_KILL))
+	if (ns_capable(tcred->user_ns, CAP_KILL))
 		return 1;
 
 	return 0;
@@ -1020,15 +1020,6 @@
 	return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
 }
 
-/*
- * map the uid in struct cred into user namespace *ns
- */
-static inline uid_t map_cred_ns(const struct cred *cred,
-				struct user_namespace *ns)
-{
-	return user_ns_map_uid(ns, cred, cred->uid);
-}
-
 #ifdef CONFIG_USER_NS
 static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
 {
@@ -1038,8 +1029,10 @@
 	if (SI_FROMKERNEL(info))
 		return;
 
-	info->si_uid = user_ns_map_uid(task_cred_xxx(t, user_ns),
-					current_cred(), info->si_uid);
+	rcu_read_lock();
+	info->si_uid = from_kuid_munged(task_cred_xxx(t, user_ns),
+					make_kuid(current_user_ns(), info->si_uid));
+	rcu_read_unlock();
 }
 #else
 static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
@@ -1106,7 +1099,7 @@
 			q->info.si_code = SI_USER;
 			q->info.si_pid = task_tgid_nr_ns(current,
 							task_active_pid_ns(t));
-			q->info.si_uid = current_uid();
+			q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
 			break;
 		case (unsigned long) SEND_SIG_PRIV:
 			q->info.si_signo = sig;
@@ -1387,10 +1380,8 @@
 			     struct task_struct *target)
 {
 	const struct cred *pcred = __task_cred(target);
-	if (cred->user_ns != pcred->user_ns)
-		return 0;
-	if (cred->euid != pcred->suid && cred->euid != pcred->uid &&
-	    cred->uid  != pcred->suid && cred->uid  != pcred->uid)
+	if (!uid_eq(cred->euid, pcred->suid) && !uid_eq(cred->euid, pcred->uid) &&
+	    !uid_eq(cred->uid,  pcred->suid) && !uid_eq(cred->uid,  pcred->uid))
 		return 0;
 	return 1;
 }
@@ -1678,8 +1669,8 @@
 	 */
 	rcu_read_lock();
 	info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
-	info.si_uid = map_cred_ns(__task_cred(tsk),
-			task_cred_xxx(tsk->parent, user_ns));
+	info.si_uid = from_kuid_munged(task_cred_xxx(tsk->parent, user_ns),
+				       task_uid(tsk));
 	rcu_read_unlock();
 
 	info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime);
@@ -1762,8 +1753,7 @@
 	 */
 	rcu_read_lock();
 	info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns);
-	info.si_uid = map_cred_ns(__task_cred(tsk),
-			task_cred_xxx(parent, user_ns));
+	info.si_uid = from_kuid_munged(task_cred_xxx(parent, user_ns), task_uid(tsk));
 	rcu_read_unlock();
 
 	info.si_utime = cputime_to_clock_t(tsk->utime);
@@ -1973,7 +1963,7 @@
 	info.si_signo = signr;
 	info.si_code = exit_code;
 	info.si_pid = task_pid_vnr(current);
-	info.si_uid = current_uid();
+	info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
 
 	/* Let the debugger run.  */
 	ptrace_stop(exit_code, why, 1, &info);
@@ -2181,8 +2171,8 @@
 		info->si_code = SI_USER;
 		rcu_read_lock();
 		info->si_pid = task_pid_vnr(current->parent);
-		info->si_uid = map_cred_ns(__task_cred(current->parent),
-				current_user_ns());
+		info->si_uid = from_kuid_munged(current_user_ns(),
+						task_uid(current->parent));
 		rcu_read_unlock();
 	}
 
@@ -2202,6 +2192,9 @@
 	struct signal_struct *signal = current->signal;
 	int signr;
 
+	if (unlikely(uprobe_deny_signal()))
+		return 0;
+
 relock:
 	/*
 	 * We'll jump back here after any time we were stopped in TASK_STOPPED.
@@ -2835,7 +2828,7 @@
 	info.si_errno = 0;
 	info.si_code = SI_USER;
 	info.si_pid = task_tgid_vnr(current);
-	info.si_uid = current_uid();
+	info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
 
 	return kill_something_info(sig, &info, pid);
 }
@@ -2878,7 +2871,7 @@
 	info.si_errno = 0;
 	info.si_code = SI_TKILL;
 	info.si_pid = task_tgid_vnr(current);
-	info.si_uid = current_uid();
+	info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
 
 	return do_send_specific(tgid, pid, sig, &info);
 }
@@ -3243,6 +3236,21 @@
 
 #endif
 
+#ifdef HAVE_SET_RESTORE_SIGMASK
+int sigsuspend(sigset_t *set)
+{
+	sigdelsetmask(set, sigmask(SIGKILL)|sigmask(SIGSTOP));
+
+	current->saved_sigmask = current->blocked;
+	set_current_blocked(set);
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_restore_sigmask();
+	return -ERESTARTNOHAND;
+}
+#endif
+
 #ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
 /**
  *  sys_rt_sigsuspend - replace the signal mask for a value with the
@@ -3260,15 +3268,7 @@
 
 	if (copy_from_user(&newset, unewset, sizeof(newset)))
 		return -EFAULT;
-	sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
-
-	current->saved_sigmask = current->blocked;
-	set_current_blocked(&newset);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_restore_sigmask();
-	return -ERESTARTNOHAND;
+	return sigsuspend(&newset);
 }
 #endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
 
diff --git a/kernel/sys.c b/kernel/sys.c
index ba0ae8e..6df4262 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -93,10 +93,8 @@
 int overflowuid = DEFAULT_OVERFLOWUID;
 int overflowgid = DEFAULT_OVERFLOWGID;
 
-#ifdef CONFIG_UID16
 EXPORT_SYMBOL(overflowuid);
 EXPORT_SYMBOL(overflowgid);
-#endif
 
 /*
  * the same as above, but for filesystems which can only store a 16-bit
@@ -133,11 +131,10 @@
 {
 	const struct cred *cred = current_cred(), *pcred = __task_cred(p);
 
-	if (pcred->user->user_ns == cred->user->user_ns &&
-	    (pcred->uid  == cred->euid ||
-	     pcred->euid == cred->euid))
+	if (uid_eq(pcred->uid,  cred->euid) ||
+	    uid_eq(pcred->euid, cred->euid))
 		return true;
-	if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE))
+	if (ns_capable(pcred->user_ns, CAP_SYS_NICE))
 		return true;
 	return false;
 }
@@ -177,6 +174,7 @@
 	const struct cred *cred = current_cred();
 	int error = -EINVAL;
 	struct pid *pgrp;
+	kuid_t uid;
 
 	if (which > PRIO_USER || which < PRIO_PROCESS)
 		goto out;
@@ -209,18 +207,19 @@
 			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
 			break;
 		case PRIO_USER:
-			user = (struct user_struct *) cred->user;
+			uid = make_kuid(cred->user_ns, who);
+			user = cred->user;
 			if (!who)
-				who = cred->uid;
-			else if ((who != cred->uid) &&
-				 !(user = find_user(who)))
+				uid = cred->uid;
+			else if (!uid_eq(uid, cred->uid) &&
+				 !(user = find_user(uid)))
 				goto out_unlock;	/* No processes for this user */
 
 			do_each_thread(g, p) {
-				if (__task_cred(p)->uid == who)
+				if (uid_eq(task_uid(p), uid))
 					error = set_one_prio(p, niceval, error);
 			} while_each_thread(g, p);
-			if (who != cred->uid)
+			if (!uid_eq(uid, cred->uid))
 				free_uid(user);		/* For find_user() */
 			break;
 	}
@@ -244,6 +243,7 @@
 	const struct cred *cred = current_cred();
 	long niceval, retval = -ESRCH;
 	struct pid *pgrp;
+	kuid_t uid;
 
 	if (which > PRIO_USER || which < PRIO_PROCESS)
 		return -EINVAL;
@@ -274,21 +274,22 @@
 			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
 			break;
 		case PRIO_USER:
-			user = (struct user_struct *) cred->user;
+			uid = make_kuid(cred->user_ns, who);
+			user = cred->user;
 			if (!who)
-				who = cred->uid;
-			else if ((who != cred->uid) &&
-				 !(user = find_user(who)))
+				uid = cred->uid;
+			else if (!uid_eq(uid, cred->uid) &&
+				 !(user = find_user(uid)))
 				goto out_unlock;	/* No processes for this user */
 
 			do_each_thread(g, p) {
-				if (__task_cred(p)->uid == who) {
+				if (uid_eq(task_uid(p), uid)) {
 					niceval = 20 - task_nice(p);
 					if (niceval > retval)
 						retval = niceval;
 				}
 			} while_each_thread(g, p);
-			if (who != cred->uid)
+			if (!uid_eq(uid, cred->uid))
 				free_uid(user);		/* for find_user() */
 			break;
 	}
@@ -553,9 +554,19 @@
  */
 SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
 {
+	struct user_namespace *ns = current_user_ns();
 	const struct cred *old;
 	struct cred *new;
 	int retval;
+	kgid_t krgid, kegid;
+
+	krgid = make_kgid(ns, rgid);
+	kegid = make_kgid(ns, egid);
+
+	if ((rgid != (gid_t) -1) && !gid_valid(krgid))
+		return -EINVAL;
+	if ((egid != (gid_t) -1) && !gid_valid(kegid))
+		return -EINVAL;
 
 	new = prepare_creds();
 	if (!new)
@@ -564,25 +575,25 @@
 
 	retval = -EPERM;
 	if (rgid != (gid_t) -1) {
-		if (old->gid == rgid ||
-		    old->egid == rgid ||
+		if (gid_eq(old->gid, krgid) ||
+		    gid_eq(old->egid, krgid) ||
 		    nsown_capable(CAP_SETGID))
-			new->gid = rgid;
+			new->gid = krgid;
 		else
 			goto error;
 	}
 	if (egid != (gid_t) -1) {
-		if (old->gid == egid ||
-		    old->egid == egid ||
-		    old->sgid == egid ||
+		if (gid_eq(old->gid, kegid) ||
+		    gid_eq(old->egid, kegid) ||
+		    gid_eq(old->sgid, kegid) ||
 		    nsown_capable(CAP_SETGID))
-			new->egid = egid;
+			new->egid = kegid;
 		else
 			goto error;
 	}
 
 	if (rgid != (gid_t) -1 ||
-	    (egid != (gid_t) -1 && egid != old->gid))
+	    (egid != (gid_t) -1 && !gid_eq(kegid, old->gid)))
 		new->sgid = new->egid;
 	new->fsgid = new->egid;
 
@@ -600,9 +611,15 @@
  */
 SYSCALL_DEFINE1(setgid, gid_t, gid)
 {
+	struct user_namespace *ns = current_user_ns();
 	const struct cred *old;
 	struct cred *new;
 	int retval;
+	kgid_t kgid;
+
+	kgid = make_kgid(ns, gid);
+	if (!gid_valid(kgid))
+		return -EINVAL;
 
 	new = prepare_creds();
 	if (!new)
@@ -611,9 +628,9 @@
 
 	retval = -EPERM;
 	if (nsown_capable(CAP_SETGID))
-		new->gid = new->egid = new->sgid = new->fsgid = gid;
-	else if (gid == old->gid || gid == old->sgid)
-		new->egid = new->fsgid = gid;
+		new->gid = new->egid = new->sgid = new->fsgid = kgid;
+	else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
+		new->egid = new->fsgid = kgid;
 	else
 		goto error;
 
@@ -631,7 +648,7 @@
 {
 	struct user_struct *new_user;
 
-	new_user = alloc_uid(current_user_ns(), new->uid);
+	new_user = alloc_uid(new->uid);
 	if (!new_user)
 		return -EAGAIN;
 
@@ -670,9 +687,19 @@
  */
 SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
 {
+	struct user_namespace *ns = current_user_ns();
 	const struct cred *old;
 	struct cred *new;
 	int retval;
+	kuid_t kruid, keuid;
+
+	kruid = make_kuid(ns, ruid);
+	keuid = make_kuid(ns, euid);
+
+	if ((ruid != (uid_t) -1) && !uid_valid(kruid))
+		return -EINVAL;
+	if ((euid != (uid_t) -1) && !uid_valid(keuid))
+		return -EINVAL;
 
 	new = prepare_creds();
 	if (!new)
@@ -681,29 +708,29 @@
 
 	retval = -EPERM;
 	if (ruid != (uid_t) -1) {
-		new->uid = ruid;
-		if (old->uid != ruid &&
-		    old->euid != ruid &&
+		new->uid = kruid;
+		if (!uid_eq(old->uid, kruid) &&
+		    !uid_eq(old->euid, kruid) &&
 		    !nsown_capable(CAP_SETUID))
 			goto error;
 	}
 
 	if (euid != (uid_t) -1) {
-		new->euid = euid;
-		if (old->uid != euid &&
-		    old->euid != euid &&
-		    old->suid != euid &&
+		new->euid = keuid;
+		if (!uid_eq(old->uid, keuid) &&
+		    !uid_eq(old->euid, keuid) &&
+		    !uid_eq(old->suid, keuid) &&
 		    !nsown_capable(CAP_SETUID))
 			goto error;
 	}
 
-	if (new->uid != old->uid) {
+	if (!uid_eq(new->uid, old->uid)) {
 		retval = set_user(new);
 		if (retval < 0)
 			goto error;
 	}
 	if (ruid != (uid_t) -1 ||
-	    (euid != (uid_t) -1 && euid != old->uid))
+	    (euid != (uid_t) -1 && !uid_eq(keuid, old->uid)))
 		new->suid = new->euid;
 	new->fsuid = new->euid;
 
@@ -731,9 +758,15 @@
  */
 SYSCALL_DEFINE1(setuid, uid_t, uid)
 {
+	struct user_namespace *ns = current_user_ns();
 	const struct cred *old;
 	struct cred *new;
 	int retval;
+	kuid_t kuid;
+
+	kuid = make_kuid(ns, uid);
+	if (!uid_valid(kuid))
+		return -EINVAL;
 
 	new = prepare_creds();
 	if (!new)
@@ -742,17 +775,17 @@
 
 	retval = -EPERM;
 	if (nsown_capable(CAP_SETUID)) {
-		new->suid = new->uid = uid;
-		if (uid != old->uid) {
+		new->suid = new->uid = kuid;
+		if (!uid_eq(kuid, old->uid)) {
 			retval = set_user(new);
 			if (retval < 0)
 				goto error;
 		}
-	} else if (uid != old->uid && uid != new->suid) {
+	} else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) {
 		goto error;
 	}
 
-	new->fsuid = new->euid = uid;
+	new->fsuid = new->euid = kuid;
 
 	retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
 	if (retval < 0)
@@ -772,9 +805,24 @@
  */
 SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
 {
+	struct user_namespace *ns = current_user_ns();
 	const struct cred *old;
 	struct cred *new;
 	int retval;
+	kuid_t kruid, keuid, ksuid;
+
+	kruid = make_kuid(ns, ruid);
+	keuid = make_kuid(ns, euid);
+	ksuid = make_kuid(ns, suid);
+
+	if ((ruid != (uid_t) -1) && !uid_valid(kruid))
+		return -EINVAL;
+
+	if ((euid != (uid_t) -1) && !uid_valid(keuid))
+		return -EINVAL;
+
+	if ((suid != (uid_t) -1) && !uid_valid(ksuid))
+		return -EINVAL;
 
 	new = prepare_creds();
 	if (!new)
@@ -784,29 +832,29 @@
 
 	retval = -EPERM;
 	if (!nsown_capable(CAP_SETUID)) {
-		if (ruid != (uid_t) -1 && ruid != old->uid &&
-		    ruid != old->euid  && ruid != old->suid)
+		if (ruid != (uid_t) -1        && !uid_eq(kruid, old->uid) &&
+		    !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid))
 			goto error;
-		if (euid != (uid_t) -1 && euid != old->uid &&
-		    euid != old->euid  && euid != old->suid)
+		if (euid != (uid_t) -1        && !uid_eq(keuid, old->uid) &&
+		    !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid))
 			goto error;
-		if (suid != (uid_t) -1 && suid != old->uid &&
-		    suid != old->euid  && suid != old->suid)
+		if (suid != (uid_t) -1        && !uid_eq(ksuid, old->uid) &&
+		    !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid))
 			goto error;
 	}
 
 	if (ruid != (uid_t) -1) {
-		new->uid = ruid;
-		if (ruid != old->uid) {
+		new->uid = kruid;
+		if (!uid_eq(kruid, old->uid)) {
 			retval = set_user(new);
 			if (retval < 0)
 				goto error;
 		}
 	}
 	if (euid != (uid_t) -1)
-		new->euid = euid;
+		new->euid = keuid;
 	if (suid != (uid_t) -1)
-		new->suid = suid;
+		new->suid = ksuid;
 	new->fsuid = new->euid;
 
 	retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
@@ -820,14 +868,19 @@
 	return retval;
 }
 
-SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid)
+SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t __user *, suidp)
 {
 	const struct cred *cred = current_cred();
 	int retval;
+	uid_t ruid, euid, suid;
 
-	if (!(retval   = put_user(cred->uid,  ruid)) &&
-	    !(retval   = put_user(cred->euid, euid)))
-		retval = put_user(cred->suid, suid);
+	ruid = from_kuid_munged(cred->user_ns, cred->uid);
+	euid = from_kuid_munged(cred->user_ns, cred->euid);
+	suid = from_kuid_munged(cred->user_ns, cred->suid);
+
+	if (!(retval   = put_user(ruid, ruidp)) &&
+	    !(retval   = put_user(euid, euidp)))
+		retval = put_user(suid, suidp);
 
 	return retval;
 }
@@ -837,9 +890,22 @@
  */
 SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
 {
+	struct user_namespace *ns = current_user_ns();
 	const struct cred *old;
 	struct cred *new;
 	int retval;
+	kgid_t krgid, kegid, ksgid;
+
+	krgid = make_kgid(ns, rgid);
+	kegid = make_kgid(ns, egid);
+	ksgid = make_kgid(ns, sgid);
+
+	if ((rgid != (gid_t) -1) && !gid_valid(krgid))
+		return -EINVAL;
+	if ((egid != (gid_t) -1) && !gid_valid(kegid))
+		return -EINVAL;
+	if ((sgid != (gid_t) -1) && !gid_valid(ksgid))
+		return -EINVAL;
 
 	new = prepare_creds();
 	if (!new)
@@ -848,23 +914,23 @@
 
 	retval = -EPERM;
 	if (!nsown_capable(CAP_SETGID)) {
-		if (rgid != (gid_t) -1 && rgid != old->gid &&
-		    rgid != old->egid  && rgid != old->sgid)
+		if (rgid != (gid_t) -1        && !gid_eq(krgid, old->gid) &&
+		    !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid))
 			goto error;
-		if (egid != (gid_t) -1 && egid != old->gid &&
-		    egid != old->egid  && egid != old->sgid)
+		if (egid != (gid_t) -1        && !gid_eq(kegid, old->gid) &&
+		    !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid))
 			goto error;
-		if (sgid != (gid_t) -1 && sgid != old->gid &&
-		    sgid != old->egid  && sgid != old->sgid)
+		if (sgid != (gid_t) -1        && !gid_eq(ksgid, old->gid) &&
+		    !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid))
 			goto error;
 	}
 
 	if (rgid != (gid_t) -1)
-		new->gid = rgid;
+		new->gid = krgid;
 	if (egid != (gid_t) -1)
-		new->egid = egid;
+		new->egid = kegid;
 	if (sgid != (gid_t) -1)
-		new->sgid = sgid;
+		new->sgid = ksgid;
 	new->fsgid = new->egid;
 
 	return commit_creds(new);
@@ -874,14 +940,19 @@
 	return retval;
 }
 
-SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid)
+SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t __user *, sgidp)
 {
 	const struct cred *cred = current_cred();
 	int retval;
+	gid_t rgid, egid, sgid;
 
-	if (!(retval   = put_user(cred->gid,  rgid)) &&
-	    !(retval   = put_user(cred->egid, egid)))
-		retval = put_user(cred->sgid, sgid);
+	rgid = from_kgid_munged(cred->user_ns, cred->gid);
+	egid = from_kgid_munged(cred->user_ns, cred->egid);
+	sgid = from_kgid_munged(cred->user_ns, cred->sgid);
+
+	if (!(retval   = put_user(rgid, rgidp)) &&
+	    !(retval   = put_user(egid, egidp)))
+		retval = put_user(sgid, sgidp);
 
 	return retval;
 }
@@ -898,18 +969,24 @@
 	const struct cred *old;
 	struct cred *new;
 	uid_t old_fsuid;
+	kuid_t kuid;
+
+	old = current_cred();
+	old_fsuid = from_kuid_munged(old->user_ns, old->fsuid);
+
+	kuid = make_kuid(old->user_ns, uid);
+	if (!uid_valid(kuid))
+		return old_fsuid;
 
 	new = prepare_creds();
 	if (!new)
-		return current_fsuid();
-	old = current_cred();
-	old_fsuid = old->fsuid;
+		return old_fsuid;
 
-	if (uid == old->uid  || uid == old->euid  ||
-	    uid == old->suid || uid == old->fsuid ||
+	if (uid_eq(kuid, old->uid)  || uid_eq(kuid, old->euid)  ||
+	    uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
 	    nsown_capable(CAP_SETUID)) {
-		if (uid != old_fsuid) {
-			new->fsuid = uid;
+		if (!uid_eq(kuid, old->fsuid)) {
+			new->fsuid = kuid;
 			if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
 				goto change_okay;
 		}
@@ -931,18 +1008,24 @@
 	const struct cred *old;
 	struct cred *new;
 	gid_t old_fsgid;
+	kgid_t kgid;
+
+	old = current_cred();
+	old_fsgid = from_kgid_munged(old->user_ns, old->fsgid);
+
+	kgid = make_kgid(old->user_ns, gid);
+	if (!gid_valid(kgid))
+		return old_fsgid;
 
 	new = prepare_creds();
 	if (!new)
-		return current_fsgid();
-	old = current_cred();
-	old_fsgid = old->fsgid;
+		return old_fsgid;
 
-	if (gid == old->gid  || gid == old->egid  ||
-	    gid == old->sgid || gid == old->fsgid ||
+	if (gid_eq(kgid, old->gid)  || gid_eq(kgid, old->egid)  ||
+	    gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
 	    nsown_capable(CAP_SETGID)) {
-		if (gid != old_fsgid) {
-			new->fsgid = gid;
+		if (!gid_eq(kgid, old->fsgid)) {
+			new->fsgid = kgid;
 			goto change_okay;
 		}
 	}
@@ -1498,15 +1581,14 @@
 		return 0;
 
 	tcred = __task_cred(task);
-	if (cred->user->user_ns == tcred->user->user_ns &&
-	    (cred->uid == tcred->euid &&
-	     cred->uid == tcred->suid &&
-	     cred->uid == tcred->uid  &&
-	     cred->gid == tcred->egid &&
-	     cred->gid == tcred->sgid &&
-	     cred->gid == tcred->gid))
+	if (uid_eq(cred->uid, tcred->euid) &&
+	    uid_eq(cred->uid, tcred->suid) &&
+	    uid_eq(cred->uid, tcred->uid)  &&
+	    gid_eq(cred->gid, tcred->egid) &&
+	    gid_eq(cred->gid, tcred->sgid) &&
+	    gid_eq(cred->gid, tcred->gid))
 		return 0;
-	if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE))
+	if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE))
 		return 0;
 
 	return -EPERM;
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 8a538c5..aa27d39 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -59,7 +59,7 @@
  * If one has not already been chosen, it checks to see if a
  * functional rtc device is available.
  */
-static struct rtc_device *alarmtimer_get_rtcdev(void)
+struct rtc_device *alarmtimer_get_rtcdev(void)
 {
 	unsigned long flags;
 	struct rtc_device *ret;
@@ -115,7 +115,7 @@
 	class_interface_unregister(&alarmtimer_rtc_interface);
 }
 #else
-static inline struct rtc_device *alarmtimer_get_rtcdev(void)
+struct rtc_device *alarmtimer_get_rtcdev(void)
 {
 	return NULL;
 }
diff --git a/kernel/timer.c b/kernel/timer.c
index 837c552f..6ec7e7e 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1108,7 +1108,9 @@
 	 * warnings as well as problems when looking into
 	 * timer->lockdep_map, make a copy and use that here.
 	 */
-	struct lockdep_map lockdep_map = timer->lockdep_map;
+	struct lockdep_map lockdep_map;
+
+	lockdep_copy_map(&lockdep_map, &timer->lockdep_map);
 #endif
 	/*
 	 * Couple the lock chain with the lock chain at
@@ -1433,25 +1435,25 @@
 SYSCALL_DEFINE0(getuid)
 {
 	/* Only we change this so SMP safe */
-	return current_uid();
+	return from_kuid_munged(current_user_ns(), current_uid());
 }
 
 SYSCALL_DEFINE0(geteuid)
 {
 	/* Only we change this so SMP safe */
-	return current_euid();
+	return from_kuid_munged(current_user_ns(), current_euid());
 }
 
 SYSCALL_DEFINE0(getgid)
 {
 	/* Only we change this so SMP safe */
-	return current_gid();
+	return from_kgid_munged(current_user_ns(), current_gid());
 }
 
 SYSCALL_DEFINE0(getegid)
 {
 	/* Only we change this so SMP safe */
-	return  current_egid();
+	return from_kgid_munged(current_user_ns(), current_egid());
 }
 
 #endif
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index a1d2849..8c4c070 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -141,7 +141,6 @@
 config FUNCTION_TRACER
 	bool "Kernel Function Tracer"
 	depends on HAVE_FUNCTION_TRACER
-	select FRAME_POINTER if !ARM_UNWIND && !PPC && !S390 && !MICROBLAZE
 	select KALLSYMS
 	select GENERIC_TRACER
 	select CONTEXT_SWITCH_TRACER
@@ -272,7 +271,7 @@
 	bool "Trace likely/unlikely profiler"
 	select TRACE_BRANCH_PROFILING
 	help
-	  This tracer profiles all the the likely and unlikely macros
+	  This tracer profiles all likely and unlikely macros
 	  in the kernel. It will display the results in:
 
 	  /sys/kernel/debug/tracing/trace_stat/branch_annotated
@@ -373,6 +372,7 @@
 	depends on HAVE_REGS_AND_STACK_ACCESS_API
 	bool "Enable kprobes-based dynamic events"
 	select TRACING
+	select PROBE_EVENTS
 	default y
 	help
 	  This allows the user to add tracing events (similar to tracepoints)
@@ -385,6 +385,25 @@
 	  This option is also required by perf-probe subcommand of perf tools.
 	  If you want to use perf tools, this option is strongly recommended.
 
+config UPROBE_EVENT
+	bool "Enable uprobes-based dynamic events"
+	depends on ARCH_SUPPORTS_UPROBES
+	depends on MMU
+	select UPROBES
+	select PROBE_EVENTS
+	select TRACING
+	default n
+	help
+	  This allows the user to add tracing events on top of userspace
+	  dynamic events (similar to tracepoints) on the fly via the trace
+	  events interface. Those events can be inserted wherever uprobes
+	  can probe, and record various registers.
+	  This option is required if you plan to use perf-probe subcommand
+	  of perf tools on user space applications.
+
+config PROBE_EVENTS
+	def_bool n
+
 config DYNAMIC_FTRACE
 	bool "enable/disable ftrace tracepoints dynamically"
 	depends on FUNCTION_TRACER
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 5f39a07..b831087 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -41,7 +41,6 @@
 obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o
 obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
-obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o
 obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
 ifeq ($(CONFIG_BLOCK),y)
 obj-$(CONFIG_EVENT_TRACING) += blktrace.o
@@ -61,5 +60,7 @@
 ifeq ($(CONFIG_TRACING),y)
 obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
 endif
+obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
+obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o
 
 libftrace-y := ftrace.o
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 0fa92f6..a008663 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1383,13 +1383,36 @@
 
 static int ftrace_cmp_recs(const void *a, const void *b)
 {
-	const struct dyn_ftrace *reca = a;
-	const struct dyn_ftrace *recb = b;
+	const struct dyn_ftrace *key = a;
+	const struct dyn_ftrace *rec = b;
 
-	if (reca->ip > recb->ip)
-		return 1;
-	if (reca->ip < recb->ip)
+	if (key->flags < rec->ip)
 		return -1;
+	if (key->ip >= rec->ip + MCOUNT_INSN_SIZE)
+		return 1;
+	return 0;
+}
+
+static unsigned long ftrace_location_range(unsigned long start, unsigned long end)
+{
+	struct ftrace_page *pg;
+	struct dyn_ftrace *rec;
+	struct dyn_ftrace key;
+
+	key.ip = start;
+	key.flags = end;	/* overload flags, as it is unsigned long */
+
+	for (pg = ftrace_pages_start; pg; pg = pg->next) {
+		if (end < pg->records[0].ip ||
+		    start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))
+			continue;
+		rec = bsearch(&key, pg->records, pg->index,
+			      sizeof(struct dyn_ftrace),
+			      ftrace_cmp_recs);
+		if (rec)
+			return rec->ip;
+	}
+
 	return 0;
 }
 
@@ -1397,28 +1420,34 @@
  * ftrace_location - return true if the ip giving is a traced location
  * @ip: the instruction pointer to check
  *
- * Returns 1 if @ip given is a pointer to a ftrace location.
+ * Returns rec->ip if @ip given is a pointer to a ftrace location.
  * That is, the instruction that is either a NOP or call to
  * the function tracer. It checks the ftrace internal tables to
  * determine if the address belongs or not.
  */
-int ftrace_location(unsigned long ip)
+unsigned long ftrace_location(unsigned long ip)
 {
-	struct ftrace_page *pg;
-	struct dyn_ftrace *rec;
-	struct dyn_ftrace key;
+	return ftrace_location_range(ip, ip);
+}
 
-	key.ip = ip;
+/**
+ * ftrace_text_reserved - return true if range contains an ftrace location
+ * @start: start of range to search
+ * @end: end of range to search (inclusive). @end points to the last byte to check.
+ *
+ * Returns 1 if @start and @end contains a ftrace location.
+ * That is, the instruction that is either a NOP or call to
+ * the function tracer. It checks the ftrace internal tables to
+ * determine if the address belongs or not.
+ */
+int ftrace_text_reserved(void *start, void *end)
+{
+	unsigned long ret;
 
-	for (pg = ftrace_pages_start; pg; pg = pg->next) {
-		rec = bsearch(&key, pg->records, pg->index,
-			      sizeof(struct dyn_ftrace),
-			      ftrace_cmp_recs);
-		if (rec)
-			return 1;
-	}
+	ret = ftrace_location_range((unsigned long)start,
+				    (unsigned long)end);
 
-	return 0;
+	return (int)!!ret;
 }
 
 static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
@@ -1520,35 +1549,6 @@
 	__ftrace_hash_rec_update(ops, filter_hash, 1);
 }
 
-static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
-{
-	if (ftrace_pages->index == ftrace_pages->size) {
-		/* We should have allocated enough */
-		if (WARN_ON(!ftrace_pages->next))
-			return NULL;
-		ftrace_pages = ftrace_pages->next;
-	}
-
-	return &ftrace_pages->records[ftrace_pages->index++];
-}
-
-static struct dyn_ftrace *
-ftrace_record_ip(unsigned long ip)
-{
-	struct dyn_ftrace *rec;
-
-	if (ftrace_disabled)
-		return NULL;
-
-	rec = ftrace_alloc_dyn_node(ip);
-	if (!rec)
-		return NULL;
-
-	rec->ip = ip;
-
-	return rec;
-}
-
 static void print_ip_ins(const char *fmt, unsigned char *p)
 {
 	int i;
@@ -1598,21 +1598,6 @@
 	}
 }
 
-
-/* Return 1 if the address range is reserved for ftrace */
-int ftrace_text_reserved(void *start, void *end)
-{
-	struct dyn_ftrace *rec;
-	struct ftrace_page *pg;
-
-	do_for_each_ftrace_rec(pg, rec) {
-		if (rec->ip <= (unsigned long)end &&
-		    rec->ip + MCOUNT_INSN_SIZE > (unsigned long)start)
-			return 1;
-	} while_for_each_ftrace_rec();
-	return 0;
-}
-
 static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
 {
 	unsigned long flag = 0UL;
@@ -1698,7 +1683,7 @@
 	return -1; /* unknow ftrace bug */
 }
 
-static void ftrace_replace_code(int update)
+void __weak ftrace_replace_code(int enable)
 {
 	struct dyn_ftrace *rec;
 	struct ftrace_page *pg;
@@ -1708,7 +1693,7 @@
 		return;
 
 	do_for_each_ftrace_rec(pg, rec) {
-		failed = __ftrace_replace_code(rec, update);
+		failed = __ftrace_replace_code(rec, enable);
 		if (failed) {
 			ftrace_bug(failed, rec->ip);
 			/* Stop processing */
@@ -1826,22 +1811,27 @@
 	return 0;
 }
 
+void ftrace_modify_all_code(int command)
+{
+	if (command & FTRACE_UPDATE_CALLS)
+		ftrace_replace_code(1);
+	else if (command & FTRACE_DISABLE_CALLS)
+		ftrace_replace_code(0);
+
+	if (command & FTRACE_UPDATE_TRACE_FUNC)
+		ftrace_update_ftrace_func(ftrace_trace_function);
+
+	if (command & FTRACE_START_FUNC_RET)
+		ftrace_enable_ftrace_graph_caller();
+	else if (command & FTRACE_STOP_FUNC_RET)
+		ftrace_disable_ftrace_graph_caller();
+}
+
 static int __ftrace_modify_code(void *data)
 {
 	int *command = data;
 
-	if (*command & FTRACE_UPDATE_CALLS)
-		ftrace_replace_code(1);
-	else if (*command & FTRACE_DISABLE_CALLS)
-		ftrace_replace_code(0);
-
-	if (*command & FTRACE_UPDATE_TRACE_FUNC)
-		ftrace_update_ftrace_func(ftrace_trace_function);
-
-	if (*command & FTRACE_START_FUNC_RET)
-		ftrace_enable_ftrace_graph_caller();
-	else if (*command & FTRACE_STOP_FUNC_RET)
-		ftrace_disable_ftrace_graph_caller();
+	ftrace_modify_all_code(*command);
 
 	return 0;
 }
@@ -2469,57 +2459,35 @@
 ftrace_avail_open(struct inode *inode, struct file *file)
 {
 	struct ftrace_iterator *iter;
-	int ret;
 
 	if (unlikely(ftrace_disabled))
 		return -ENODEV;
 
-	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
-	if (!iter)
-		return -ENOMEM;
-
-	iter->pg = ftrace_pages_start;
-	iter->ops = &global_ops;
-
-	ret = seq_open(file, &show_ftrace_seq_ops);
-	if (!ret) {
-		struct seq_file *m = file->private_data;
-
-		m->private = iter;
-	} else {
-		kfree(iter);
+	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
+	if (iter) {
+		iter->pg = ftrace_pages_start;
+		iter->ops = &global_ops;
 	}
 
-	return ret;
+	return iter ? 0 : -ENOMEM;
 }
 
 static int
 ftrace_enabled_open(struct inode *inode, struct file *file)
 {
 	struct ftrace_iterator *iter;
-	int ret;
 
 	if (unlikely(ftrace_disabled))
 		return -ENODEV;
 
-	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
-	if (!iter)
-		return -ENOMEM;
-
-	iter->pg = ftrace_pages_start;
-	iter->flags = FTRACE_ITER_ENABLED;
-	iter->ops = &global_ops;
-
-	ret = seq_open(file, &show_ftrace_seq_ops);
-	if (!ret) {
-		struct seq_file *m = file->private_data;
-
-		m->private = iter;
-	} else {
-		kfree(iter);
+	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
+	if (iter) {
+		iter->pg = ftrace_pages_start;
+		iter->flags = FTRACE_ITER_ENABLED;
+		iter->ops = &global_ops;
 	}
 
-	return ret;
+	return iter ? 0 : -ENOMEM;
 }
 
 static void ftrace_filter_reset(struct ftrace_hash *hash)
@@ -3688,22 +3656,36 @@
 	return 0;
 }
 
-static void ftrace_swap_recs(void *a, void *b, int size)
+static int ftrace_cmp_ips(const void *a, const void *b)
 {
-	struct dyn_ftrace *reca = a;
-	struct dyn_ftrace *recb = b;
-	struct dyn_ftrace t;
+	const unsigned long *ipa = a;
+	const unsigned long *ipb = b;
 
-	t = *reca;
-	*reca = *recb;
-	*recb = t;
+	if (*ipa > *ipb)
+		return 1;
+	if (*ipa < *ipb)
+		return -1;
+	return 0;
+}
+
+static void ftrace_swap_ips(void *a, void *b, int size)
+{
+	unsigned long *ipa = a;
+	unsigned long *ipb = b;
+	unsigned long t;
+
+	t = *ipa;
+	*ipa = *ipb;
+	*ipb = t;
 }
 
 static int ftrace_process_locs(struct module *mod,
 			       unsigned long *start,
 			       unsigned long *end)
 {
+	struct ftrace_page *start_pg;
 	struct ftrace_page *pg;
+	struct dyn_ftrace *rec;
 	unsigned long count;
 	unsigned long *p;
 	unsigned long addr;
@@ -3715,8 +3697,11 @@
 	if (!count)
 		return 0;
 
-	pg = ftrace_allocate_pages(count);
-	if (!pg)
+	sort(start, count, sizeof(*start),
+	     ftrace_cmp_ips, ftrace_swap_ips);
+
+	start_pg = ftrace_allocate_pages(count);
+	if (!start_pg)
 		return -ENOMEM;
 
 	mutex_lock(&ftrace_lock);
@@ -3729,7 +3714,7 @@
 	if (!mod) {
 		WARN_ON(ftrace_pages || ftrace_pages_start);
 		/* First initialization */
-		ftrace_pages = ftrace_pages_start = pg;
+		ftrace_pages = ftrace_pages_start = start_pg;
 	} else {
 		if (!ftrace_pages)
 			goto out;
@@ -3740,11 +3725,11 @@
 				ftrace_pages = ftrace_pages->next;
 		}
 
-		ftrace_pages->next = pg;
-		ftrace_pages = pg;
+		ftrace_pages->next = start_pg;
 	}
 
 	p = start;
+	pg = start_pg;
 	while (p < end) {
 		addr = ftrace_call_adjust(*p++);
 		/*
@@ -3755,17 +3740,26 @@
 		 */
 		if (!addr)
 			continue;
-		if (!ftrace_record_ip(addr))
-			break;
+
+		if (pg->index == pg->size) {
+			/* We should have allocated enough */
+			if (WARN_ON(!pg->next))
+				break;
+			pg = pg->next;
+		}
+
+		rec = &pg->records[pg->index++];
+		rec->ip = addr;
 	}
 
-	/* These new locations need to be initialized */
-	ftrace_new_pgs = pg;
+	/* We should have used all pages */
+	WARN_ON(pg->next);
 
-	/* Make each individual set of pages sorted by ips */
-	for (; pg; pg = pg->next)
-		sort(pg->records, pg->index, sizeof(struct dyn_ftrace),
-		     ftrace_cmp_recs, ftrace_swap_recs);
+	/* Assign the last page to ftrace_pages */
+	ftrace_pages = pg;
+
+	/* These new locations need to be initialized */
+	ftrace_new_pgs = start_pg;
 
 	/*
 	 * We only need to disable interrupts on start up
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index cf8d11e..6420cda 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -23,6 +23,8 @@
 #include <asm/local.h>
 #include "trace.h"
 
+static void update_pages_handler(struct work_struct *work);
+
 /*
  * The ring buffer header is special. We must manually up keep it.
  */
@@ -449,6 +451,7 @@
 	raw_spinlock_t			reader_lock;	/* serialize readers */
 	arch_spinlock_t			lock;
 	struct lock_class_key		lock_key;
+	unsigned int			nr_pages;
 	struct list_head		*pages;
 	struct buffer_page		*head_page;	/* read from head */
 	struct buffer_page		*tail_page;	/* write to tail */
@@ -466,13 +469,18 @@
 	unsigned long			read_bytes;
 	u64				write_stamp;
 	u64				read_stamp;
+	/* ring buffer pages to update, > 0 to add, < 0 to remove */
+	int				nr_pages_to_update;
+	struct list_head		new_pages; /* new pages to add */
+	struct work_struct		update_pages_work;
+	struct completion		update_done;
 };
 
 struct ring_buffer {
-	unsigned			pages;
 	unsigned			flags;
 	int				cpus;
 	atomic_t			record_disabled;
+	atomic_t			resize_disabled;
 	cpumask_var_t			cpumask;
 
 	struct lock_class_key		*reader_lock_key;
@@ -937,6 +945,10 @@
 	struct list_head *head = cpu_buffer->pages;
 	struct buffer_page *bpage, *tmp;
 
+	/* Reset the head page if it exists */
+	if (cpu_buffer->head_page)
+		rb_set_head_page(cpu_buffer);
+
 	rb_head_page_deactivate(cpu_buffer);
 
 	if (RB_WARN_ON(cpu_buffer, head->next->prev != head))
@@ -963,14 +975,10 @@
 	return 0;
 }
 
-static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
-			     unsigned nr_pages)
+static int __rb_allocate_pages(int nr_pages, struct list_head *pages, int cpu)
 {
+	int i;
 	struct buffer_page *bpage, *tmp;
-	LIST_HEAD(pages);
-	unsigned i;
-
-	WARN_ON(!nr_pages);
 
 	for (i = 0; i < nr_pages; i++) {
 		struct page *page;
@@ -981,15 +989,13 @@
 		 */
 		bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
 				    GFP_KERNEL | __GFP_NORETRY,
-				    cpu_to_node(cpu_buffer->cpu));
+				    cpu_to_node(cpu));
 		if (!bpage)
 			goto free_pages;
 
-		rb_check_bpage(cpu_buffer, bpage);
+		list_add(&bpage->list, pages);
 
-		list_add(&bpage->list, &pages);
-
-		page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu),
+		page = alloc_pages_node(cpu_to_node(cpu),
 					GFP_KERNEL | __GFP_NORETRY, 0);
 		if (!page)
 			goto free_pages;
@@ -997,6 +1003,27 @@
 		rb_init_page(bpage->page);
 	}
 
+	return 0;
+
+free_pages:
+	list_for_each_entry_safe(bpage, tmp, pages, list) {
+		list_del_init(&bpage->list);
+		free_buffer_page(bpage);
+	}
+
+	return -ENOMEM;
+}
+
+static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
+			     unsigned nr_pages)
+{
+	LIST_HEAD(pages);
+
+	WARN_ON(!nr_pages);
+
+	if (__rb_allocate_pages(nr_pages, &pages, cpu_buffer->cpu))
+		return -ENOMEM;
+
 	/*
 	 * The ring buffer page list is a circular list that does not
 	 * start and end with a list head. All page list items point to
@@ -1005,20 +1032,15 @@
 	cpu_buffer->pages = pages.next;
 	list_del(&pages);
 
+	cpu_buffer->nr_pages = nr_pages;
+
 	rb_check_pages(cpu_buffer);
 
 	return 0;
-
- free_pages:
-	list_for_each_entry_safe(bpage, tmp, &pages, list) {
-		list_del_init(&bpage->list);
-		free_buffer_page(bpage);
-	}
-	return -ENOMEM;
 }
 
 static struct ring_buffer_per_cpu *
-rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
+rb_allocate_cpu_buffer(struct ring_buffer *buffer, int nr_pages, int cpu)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
 	struct buffer_page *bpage;
@@ -1035,6 +1057,8 @@
 	raw_spin_lock_init(&cpu_buffer->reader_lock);
 	lockdep_set_class(&cpu_buffer->reader_lock, buffer->reader_lock_key);
 	cpu_buffer->lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
+	INIT_WORK(&cpu_buffer->update_pages_work, update_pages_handler);
+	init_completion(&cpu_buffer->update_done);
 
 	bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
 			    GFP_KERNEL, cpu_to_node(cpu));
@@ -1052,7 +1076,7 @@
 
 	INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
 
-	ret = rb_allocate_pages(cpu_buffer, buffer->pages);
+	ret = rb_allocate_pages(cpu_buffer, nr_pages);
 	if (ret < 0)
 		goto fail_free_reader;
 
@@ -1113,7 +1137,7 @@
 {
 	struct ring_buffer *buffer;
 	int bsize;
-	int cpu;
+	int cpu, nr_pages;
 
 	/* keep it in its own cache line */
 	buffer = kzalloc(ALIGN(sizeof(*buffer), cache_line_size()),
@@ -1124,14 +1148,14 @@
 	if (!alloc_cpumask_var(&buffer->cpumask, GFP_KERNEL))
 		goto fail_free_buffer;
 
-	buffer->pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
+	nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
 	buffer->flags = flags;
 	buffer->clock = trace_clock_local;
 	buffer->reader_lock_key = key;
 
 	/* need at least two pages */
-	if (buffer->pages < 2)
-		buffer->pages = 2;
+	if (nr_pages < 2)
+		nr_pages = 2;
 
 	/*
 	 * In case of non-hotplug cpu, if the ring-buffer is allocated
@@ -1154,7 +1178,7 @@
 
 	for_each_buffer_cpu(buffer, cpu) {
 		buffer->buffers[cpu] =
-			rb_allocate_cpu_buffer(buffer, cpu);
+			rb_allocate_cpu_buffer(buffer, nr_pages, cpu);
 		if (!buffer->buffers[cpu])
 			goto fail_free_buffers;
 	}
@@ -1222,58 +1246,222 @@
 
 static void rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer);
 
-static void
-rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages)
+static inline unsigned long rb_page_entries(struct buffer_page *bpage)
 {
-	struct buffer_page *bpage;
-	struct list_head *p;
-	unsigned i;
-
-	raw_spin_lock_irq(&cpu_buffer->reader_lock);
-	rb_head_page_deactivate(cpu_buffer);
-
-	for (i = 0; i < nr_pages; i++) {
-		if (RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages)))
-			goto out;
-		p = cpu_buffer->pages->next;
-		bpage = list_entry(p, struct buffer_page, list);
-		list_del_init(&bpage->list);
-		free_buffer_page(bpage);
-	}
-	if (RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages)))
-		goto out;
-
-	rb_reset_cpu(cpu_buffer);
-	rb_check_pages(cpu_buffer);
-
-out:
-	raw_spin_unlock_irq(&cpu_buffer->reader_lock);
+	return local_read(&bpage->entries) & RB_WRITE_MASK;
 }
 
-static void
-rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer,
-		struct list_head *pages, unsigned nr_pages)
+static inline unsigned long rb_page_write(struct buffer_page *bpage)
 {
-	struct buffer_page *bpage;
-	struct list_head *p;
-	unsigned i;
+	return local_read(&bpage->write) & RB_WRITE_MASK;
+}
+
+static int
+rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned int nr_pages)
+{
+	struct list_head *tail_page, *to_remove, *next_page;
+	struct buffer_page *to_remove_page, *tmp_iter_page;
+	struct buffer_page *last_page, *first_page;
+	unsigned int nr_removed;
+	unsigned long head_bit;
+	int page_entries;
+
+	head_bit = 0;
 
 	raw_spin_lock_irq(&cpu_buffer->reader_lock);
-	rb_head_page_deactivate(cpu_buffer);
+	atomic_inc(&cpu_buffer->record_disabled);
+	/*
+	 * We don't race with the readers since we have acquired the reader
+	 * lock. We also don't race with writers after disabling recording.
+	 * This makes it easy to figure out the first and the last page to be
+	 * removed from the list. We unlink all the pages in between including
+	 * the first and last pages. This is done in a busy loop so that we
+	 * lose the least number of traces.
+	 * The pages are freed after we restart recording and unlock readers.
+	 */
+	tail_page = &cpu_buffer->tail_page->list;
 
-	for (i = 0; i < nr_pages; i++) {
-		if (RB_WARN_ON(cpu_buffer, list_empty(pages)))
-			goto out;
-		p = pages->next;
-		bpage = list_entry(p, struct buffer_page, list);
-		list_del_init(&bpage->list);
-		list_add_tail(&bpage->list, cpu_buffer->pages);
+	/*
+	 * tail page might be on reader page, we remove the next page
+	 * from the ring buffer
+	 */
+	if (cpu_buffer->tail_page == cpu_buffer->reader_page)
+		tail_page = rb_list_head(tail_page->next);
+	to_remove = tail_page;
+
+	/* start of pages to remove */
+	first_page = list_entry(rb_list_head(to_remove->next),
+				struct buffer_page, list);
+
+	for (nr_removed = 0; nr_removed < nr_pages; nr_removed++) {
+		to_remove = rb_list_head(to_remove)->next;
+		head_bit |= (unsigned long)to_remove & RB_PAGE_HEAD;
 	}
-	rb_reset_cpu(cpu_buffer);
-	rb_check_pages(cpu_buffer);
 
-out:
+	next_page = rb_list_head(to_remove)->next;
+
+	/*
+	 * Now we remove all pages between tail_page and next_page.
+	 * Make sure that we have head_bit value preserved for the
+	 * next page
+	 */
+	tail_page->next = (struct list_head *)((unsigned long)next_page |
+						head_bit);
+	next_page = rb_list_head(next_page);
+	next_page->prev = tail_page;
+
+	/* make sure pages points to a valid page in the ring buffer */
+	cpu_buffer->pages = next_page;
+
+	/* update head page */
+	if (head_bit)
+		cpu_buffer->head_page = list_entry(next_page,
+						struct buffer_page, list);
+
+	/*
+	 * change read pointer to make sure any read iterators reset
+	 * themselves
+	 */
+	cpu_buffer->read = 0;
+
+	/* pages are removed, resume tracing and then free the pages */
+	atomic_dec(&cpu_buffer->record_disabled);
 	raw_spin_unlock_irq(&cpu_buffer->reader_lock);
+
+	RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages));
+
+	/* last buffer page to remove */
+	last_page = list_entry(rb_list_head(to_remove), struct buffer_page,
+				list);
+	tmp_iter_page = first_page;
+
+	do {
+		to_remove_page = tmp_iter_page;
+		rb_inc_page(cpu_buffer, &tmp_iter_page);
+
+		/* update the counters */
+		page_entries = rb_page_entries(to_remove_page);
+		if (page_entries) {
+			/*
+			 * If something was added to this page, it was full
+			 * since it is not the tail page. So we deduct the
+			 * bytes consumed in ring buffer from here.
+			 * No need to update overruns, since this page is
+			 * deleted from ring buffer and its entries are
+			 * already accounted for.
+			 */
+			local_sub(BUF_PAGE_SIZE, &cpu_buffer->entries_bytes);
+		}
+
+		/*
+		 * We have already removed references to this list item, just
+		 * free up the buffer_page and its page
+		 */
+		free_buffer_page(to_remove_page);
+		nr_removed--;
+
+	} while (to_remove_page != last_page);
+
+	RB_WARN_ON(cpu_buffer, nr_removed);
+
+	return nr_removed == 0;
+}
+
+static int
+rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer)
+{
+	struct list_head *pages = &cpu_buffer->new_pages;
+	int retries, success;
+
+	raw_spin_lock_irq(&cpu_buffer->reader_lock);
+	/*
+	 * We are holding the reader lock, so the reader page won't be swapped
+	 * in the ring buffer. Now we are racing with the writer trying to
+	 * move head page and the tail page.
+	 * We are going to adapt the reader page update process where:
+	 * 1. We first splice the start and end of list of new pages between
+	 *    the head page and its previous page.
+	 * 2. We cmpxchg the prev_page->next to point from head page to the
+	 *    start of new pages list.
+	 * 3. Finally, we update the head->prev to the end of new list.
+	 *
+	 * We will try this process 10 times, to make sure that we don't keep
+	 * spinning.
+	 */
+	retries = 10;
+	success = 0;
+	while (retries--) {
+		struct list_head *head_page, *prev_page, *r;
+		struct list_head *last_page, *first_page;
+		struct list_head *head_page_with_bit;
+
+		head_page = &rb_set_head_page(cpu_buffer)->list;
+		prev_page = head_page->prev;
+
+		first_page = pages->next;
+		last_page  = pages->prev;
+
+		head_page_with_bit = (struct list_head *)
+				     ((unsigned long)head_page | RB_PAGE_HEAD);
+
+		last_page->next = head_page_with_bit;
+		first_page->prev = prev_page;
+
+		r = cmpxchg(&prev_page->next, head_page_with_bit, first_page);
+
+		if (r == head_page_with_bit) {
+			/*
+			 * yay, we replaced the page pointer to our new list,
+			 * now, we just have to update to head page's prev
+			 * pointer to point to end of list
+			 */
+			head_page->prev = last_page;
+			success = 1;
+			break;
+		}
+	}
+
+	if (success)
+		INIT_LIST_HEAD(pages);
+	/*
+	 * If we weren't successful in adding in new pages, warn and stop
+	 * tracing
+	 */
+	RB_WARN_ON(cpu_buffer, !success);
+	raw_spin_unlock_irq(&cpu_buffer->reader_lock);
+
+	/* free pages if they weren't inserted */
+	if (!success) {
+		struct buffer_page *bpage, *tmp;
+		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
+					 list) {
+			list_del_init(&bpage->list);
+			free_buffer_page(bpage);
+		}
+	}
+	return success;
+}
+
+static void rb_update_pages(struct ring_buffer_per_cpu *cpu_buffer)
+{
+	int success;
+
+	if (cpu_buffer->nr_pages_to_update > 0)
+		success = rb_insert_pages(cpu_buffer);
+	else
+		success = rb_remove_pages(cpu_buffer,
+					-cpu_buffer->nr_pages_to_update);
+
+	if (success)
+		cpu_buffer->nr_pages += cpu_buffer->nr_pages_to_update;
+}
+
+static void update_pages_handler(struct work_struct *work)
+{
+	struct ring_buffer_per_cpu *cpu_buffer = container_of(work,
+			struct ring_buffer_per_cpu, update_pages_work);
+	rb_update_pages(cpu_buffer);
+	complete(&cpu_buffer->update_done);
 }
 
 /**
@@ -1283,16 +1471,14 @@
  *
  * Minimum size is 2 * BUF_PAGE_SIZE.
  *
- * Returns -1 on failure.
+ * Returns 0 on success and < 0 on failure.
  */
-int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
+int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size,
+			int cpu_id)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
-	unsigned nr_pages, rm_pages, new_pages;
-	struct buffer_page *bpage, *tmp;
-	unsigned long buffer_size;
-	LIST_HEAD(pages);
-	int i, cpu;
+	unsigned nr_pages;
+	int cpu, err = 0;
 
 	/*
 	 * Always succeed at resizing a non-existent buffer:
@@ -1302,113 +1488,154 @@
 
 	size = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
 	size *= BUF_PAGE_SIZE;
-	buffer_size = buffer->pages * BUF_PAGE_SIZE;
 
 	/* we need a minimum of two pages */
 	if (size < BUF_PAGE_SIZE * 2)
 		size = BUF_PAGE_SIZE * 2;
 
-	if (size == buffer_size)
-		return size;
-
-	atomic_inc(&buffer->record_disabled);
-
-	/* Make sure all writers are done with this buffer. */
-	synchronize_sched();
-
-	mutex_lock(&buffer->mutex);
-	get_online_cpus();
-
 	nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
 
-	if (size < buffer_size) {
+	/*
+	 * Don't succeed if resizing is disabled, as a reader might be
+	 * manipulating the ring buffer and is expecting a sane state while
+	 * this is true.
+	 */
+	if (atomic_read(&buffer->resize_disabled))
+		return -EBUSY;
 
-		/* easy case, just free pages */
-		if (RB_WARN_ON(buffer, nr_pages >= buffer->pages))
-			goto out_fail;
+	/* prevent another thread from changing buffer sizes */
+	mutex_lock(&buffer->mutex);
 
-		rm_pages = buffer->pages - nr_pages;
-
+	if (cpu_id == RING_BUFFER_ALL_CPUS) {
+		/* calculate the pages to update */
 		for_each_buffer_cpu(buffer, cpu) {
 			cpu_buffer = buffer->buffers[cpu];
-			rb_remove_pages(cpu_buffer, rm_pages);
-		}
-		goto out;
-	}
 
-	/*
-	 * This is a bit more difficult. We only want to add pages
-	 * when we can allocate enough for all CPUs. We do this
-	 * by allocating all the pages and storing them on a local
-	 * link list. If we succeed in our allocation, then we
-	 * add these pages to the cpu_buffers. Otherwise we just free
-	 * them all and return -ENOMEM;
-	 */
-	if (RB_WARN_ON(buffer, nr_pages <= buffer->pages))
-		goto out_fail;
-
-	new_pages = nr_pages - buffer->pages;
-
-	for_each_buffer_cpu(buffer, cpu) {
-		for (i = 0; i < new_pages; i++) {
-			struct page *page;
+			cpu_buffer->nr_pages_to_update = nr_pages -
+							cpu_buffer->nr_pages;
 			/*
-			 * __GFP_NORETRY flag makes sure that the allocation
-			 * fails gracefully without invoking oom-killer and
-			 * the system is not destabilized.
+			 * nothing more to do for removing pages or no update
 			 */
-			bpage = kzalloc_node(ALIGN(sizeof(*bpage),
-						  cache_line_size()),
-					    GFP_KERNEL | __GFP_NORETRY,
-					    cpu_to_node(cpu));
-			if (!bpage)
-				goto free_pages;
-			list_add(&bpage->list, &pages);
-			page = alloc_pages_node(cpu_to_node(cpu),
-						GFP_KERNEL | __GFP_NORETRY, 0);
-			if (!page)
-				goto free_pages;
-			bpage->page = page_address(page);
-			rb_init_page(bpage->page);
+			if (cpu_buffer->nr_pages_to_update <= 0)
+				continue;
+			/*
+			 * to add pages, make sure all new pages can be
+			 * allocated without receiving ENOMEM
+			 */
+			INIT_LIST_HEAD(&cpu_buffer->new_pages);
+			if (__rb_allocate_pages(cpu_buffer->nr_pages_to_update,
+						&cpu_buffer->new_pages, cpu)) {
+				/* not enough memory for new pages */
+				err = -ENOMEM;
+				goto out_err;
+			}
 		}
-	}
 
-	for_each_buffer_cpu(buffer, cpu) {
-		cpu_buffer = buffer->buffers[cpu];
-		rb_insert_pages(cpu_buffer, &pages, new_pages);
-	}
+		get_online_cpus();
+		/*
+		 * Fire off all the required work handlers
+		 * We can't schedule on offline CPUs, but it's not necessary
+		 * since we can change their buffer sizes without any race.
+		 */
+		for_each_buffer_cpu(buffer, cpu) {
+			cpu_buffer = buffer->buffers[cpu];
+			if (!cpu_buffer->nr_pages_to_update)
+				continue;
 
-	if (RB_WARN_ON(buffer, !list_empty(&pages)))
-		goto out_fail;
+			if (cpu_online(cpu))
+				schedule_work_on(cpu,
+						&cpu_buffer->update_pages_work);
+			else
+				rb_update_pages(cpu_buffer);
+		}
+
+		/* wait for all the updates to complete */
+		for_each_buffer_cpu(buffer, cpu) {
+			cpu_buffer = buffer->buffers[cpu];
+			if (!cpu_buffer->nr_pages_to_update)
+				continue;
+
+			if (cpu_online(cpu))
+				wait_for_completion(&cpu_buffer->update_done);
+			cpu_buffer->nr_pages_to_update = 0;
+		}
+
+		put_online_cpus();
+	} else {
+		cpu_buffer = buffer->buffers[cpu_id];
+
+		if (nr_pages == cpu_buffer->nr_pages)
+			goto out;
+
+		cpu_buffer->nr_pages_to_update = nr_pages -
+						cpu_buffer->nr_pages;
+
+		INIT_LIST_HEAD(&cpu_buffer->new_pages);
+		if (cpu_buffer->nr_pages_to_update > 0 &&
+			__rb_allocate_pages(cpu_buffer->nr_pages_to_update,
+					    &cpu_buffer->new_pages, cpu_id)) {
+			err = -ENOMEM;
+			goto out_err;
+		}
+
+		get_online_cpus();
+
+		if (cpu_online(cpu_id)) {
+			schedule_work_on(cpu_id,
+					 &cpu_buffer->update_pages_work);
+			wait_for_completion(&cpu_buffer->update_done);
+		} else
+			rb_update_pages(cpu_buffer);
+
+		cpu_buffer->nr_pages_to_update = 0;
+		put_online_cpus();
+	}
 
  out:
-	buffer->pages = nr_pages;
-	put_online_cpus();
+	/*
+	 * The ring buffer resize can happen with the ring buffer
+	 * enabled, so that the update disturbs the tracing as little
+	 * as possible. But if the buffer is disabled, we do not need
+	 * to worry about that, and we can take the time to verify
+	 * that the buffer is not corrupt.
+	 */
+	if (atomic_read(&buffer->record_disabled)) {
+		atomic_inc(&buffer->record_disabled);
+		/*
+		 * Even though the buffer was disabled, we must make sure
+		 * that it is truly disabled before calling rb_check_pages.
+		 * There could have been a race between checking
+		 * record_disable and incrementing it.
+		 */
+		synchronize_sched();
+		for_each_buffer_cpu(buffer, cpu) {
+			cpu_buffer = buffer->buffers[cpu];
+			rb_check_pages(cpu_buffer);
+		}
+		atomic_dec(&buffer->record_disabled);
+	}
+
 	mutex_unlock(&buffer->mutex);
-
-	atomic_dec(&buffer->record_disabled);
-
 	return size;
 
- free_pages:
-	list_for_each_entry_safe(bpage, tmp, &pages, list) {
-		list_del_init(&bpage->list);
-		free_buffer_page(bpage);
-	}
-	put_online_cpus();
-	mutex_unlock(&buffer->mutex);
-	atomic_dec(&buffer->record_disabled);
-	return -ENOMEM;
+ out_err:
+	for_each_buffer_cpu(buffer, cpu) {
+		struct buffer_page *bpage, *tmp;
 
-	/*
-	 * Something went totally wrong, and we are too paranoid
-	 * to even clean up the mess.
-	 */
- out_fail:
-	put_online_cpus();
+		cpu_buffer = buffer->buffers[cpu];
+		cpu_buffer->nr_pages_to_update = 0;
+
+		if (list_empty(&cpu_buffer->new_pages))
+			continue;
+
+		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
+					list) {
+			list_del_init(&bpage->list);
+			free_buffer_page(bpage);
+		}
+	}
 	mutex_unlock(&buffer->mutex);
-	atomic_dec(&buffer->record_disabled);
-	return -1;
+	return err;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_resize);
 
@@ -1447,21 +1674,11 @@
 	return __rb_page_index(iter->head_page, iter->head);
 }
 
-static inline unsigned long rb_page_write(struct buffer_page *bpage)
-{
-	return local_read(&bpage->write) & RB_WRITE_MASK;
-}
-
 static inline unsigned rb_page_commit(struct buffer_page *bpage)
 {
 	return local_read(&bpage->page->commit);
 }
 
-static inline unsigned long rb_page_entries(struct buffer_page *bpage)
-{
-	return local_read(&bpage->entries) & RB_WRITE_MASK;
-}
-
 /* Size is determined by what has been committed */
 static inline unsigned rb_page_size(struct buffer_page *bpage)
 {
@@ -1510,7 +1727,7 @@
 	 * assign the commit to the tail.
 	 */
  again:
-	max_count = cpu_buffer->buffer->pages * 100;
+	max_count = cpu_buffer->nr_pages * 100;
 
 	while (cpu_buffer->commit_page != cpu_buffer->tail_page) {
 		if (RB_WARN_ON(cpu_buffer, !(--max_count)))
@@ -3486,6 +3703,7 @@
 
 	iter->cpu_buffer = cpu_buffer;
 
+	atomic_inc(&buffer->resize_disabled);
 	atomic_inc(&cpu_buffer->record_disabled);
 
 	return iter;
@@ -3548,7 +3766,14 @@
 {
 	struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
 
+	/*
+	 * Ring buffer is disabled from recording, here's a good place
+	 * to check the integrity of the ring buffer. 
+	 */
+	rb_check_pages(cpu_buffer);
+
 	atomic_dec(&cpu_buffer->record_disabled);
+	atomic_dec(&cpu_buffer->buffer->resize_disabled);
 	kfree(iter);
 }
 EXPORT_SYMBOL_GPL(ring_buffer_read_finish);
@@ -3588,9 +3813,18 @@
  * ring_buffer_size - return the size of the ring buffer (in bytes)
  * @buffer: The ring buffer.
  */
-unsigned long ring_buffer_size(struct ring_buffer *buffer)
+unsigned long ring_buffer_size(struct ring_buffer *buffer, int cpu)
 {
-	return BUF_PAGE_SIZE * buffer->pages;
+	/*
+	 * Earlier, this method returned
+	 *	BUF_PAGE_SIZE * buffer->nr_pages
+	 * Since the nr_pages field is now removed, we have converted this to
+	 * return the per cpu buffer value.
+	 */
+	if (!cpumask_test_cpu(cpu, buffer->cpumask))
+		return 0;
+
+	return BUF_PAGE_SIZE * buffer->buffers[cpu]->nr_pages;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_size);
 
@@ -3611,6 +3845,7 @@
 	cpu_buffer->commit_page = cpu_buffer->head_page;
 
 	INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
+	INIT_LIST_HEAD(&cpu_buffer->new_pages);
 	local_set(&cpu_buffer->reader_page->write, 0);
 	local_set(&cpu_buffer->reader_page->entries, 0);
 	local_set(&cpu_buffer->reader_page->page->commit, 0);
@@ -3647,8 +3882,12 @@
 	if (!cpumask_test_cpu(cpu, buffer->cpumask))
 		return;
 
+	atomic_inc(&buffer->resize_disabled);
 	atomic_inc(&cpu_buffer->record_disabled);
 
+	/* Make sure all commits have finished */
+	synchronize_sched();
+
 	raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
 
 	if (RB_WARN_ON(cpu_buffer, local_read(&cpu_buffer->committing)))
@@ -3664,6 +3903,7 @@
 	raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
 	atomic_dec(&cpu_buffer->record_disabled);
+	atomic_dec(&buffer->resize_disabled);
 }
 EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu);
 
@@ -3765,8 +4005,11 @@
 	    !cpumask_test_cpu(cpu, buffer_b->cpumask))
 		goto out;
 
+	cpu_buffer_a = buffer_a->buffers[cpu];
+	cpu_buffer_b = buffer_b->buffers[cpu];
+
 	/* At least make sure the two buffers are somewhat the same */
-	if (buffer_a->pages != buffer_b->pages)
+	if (cpu_buffer_a->nr_pages != cpu_buffer_b->nr_pages)
 		goto out;
 
 	ret = -EAGAIN;
@@ -3780,9 +4023,6 @@
 	if (atomic_read(&buffer_b->record_disabled))
 		goto out;
 
-	cpu_buffer_a = buffer_a->buffers[cpu];
-	cpu_buffer_b = buffer_b->buffers[cpu];
-
 	if (atomic_read(&cpu_buffer_a->record_disabled))
 		goto out;
 
@@ -4071,6 +4311,8 @@
 	struct ring_buffer *buffer =
 		container_of(self, struct ring_buffer, cpu_notify);
 	long cpu = (long)hcpu;
+	int cpu_i, nr_pages_same;
+	unsigned int nr_pages;
 
 	switch (action) {
 	case CPU_UP_PREPARE:
@@ -4078,8 +4320,23 @@
 		if (cpumask_test_cpu(cpu, buffer->cpumask))
 			return NOTIFY_OK;
 
+		nr_pages = 0;
+		nr_pages_same = 1;
+		/* check if all cpu sizes are same */
+		for_each_buffer_cpu(buffer, cpu_i) {
+			/* fill in the size from first enabled cpu */
+			if (nr_pages == 0)
+				nr_pages = buffer->buffers[cpu_i]->nr_pages;
+			if (nr_pages != buffer->buffers[cpu_i]->nr_pages) {
+				nr_pages_same = 0;
+				break;
+			}
+		}
+		/* allocate minimum pages, user can later expand it */
+		if (!nr_pages_same)
+			nr_pages = 2;
 		buffer->buffers[cpu] =
-			rb_allocate_cpu_buffer(buffer, cpu);
+			rb_allocate_cpu_buffer(buffer, nr_pages, cpu);
 		if (!buffer->buffers[cpu]) {
 			WARN(1, "failed to allocate ring buffer on CPU %ld\n",
 			     cpu);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 2a22255..68032c6 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -87,18 +87,6 @@
 
 DEFINE_PER_CPU(int, ftrace_cpu_disabled);
 
-static inline void ftrace_disable_cpu(void)
-{
-	preempt_disable();
-	__this_cpu_inc(ftrace_cpu_disabled);
-}
-
-static inline void ftrace_enable_cpu(void)
-{
-	__this_cpu_dec(ftrace_cpu_disabled);
-	preempt_enable();
-}
-
 cpumask_var_t __read_mostly	tracing_buffer_mask;
 
 /*
@@ -629,7 +617,6 @@
 static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt)
 {
 	int len;
-	void *ret;
 
 	if (s->len <= s->readpos)
 		return -EBUSY;
@@ -637,9 +624,7 @@
 	len = s->len - s->readpos;
 	if (cnt > len)
 		cnt = len;
-	ret = memcpy(buf, s->buffer + s->readpos, cnt);
-	if (!ret)
-		return -EFAULT;
+	memcpy(buf, s->buffer + s->readpos, cnt);
 
 	s->readpos += cnt;
 	return cnt;
@@ -751,8 +736,6 @@
 
 	arch_spin_lock(&ftrace_max_lock);
 
-	ftrace_disable_cpu();
-
 	ret = ring_buffer_swap_cpu(max_tr.buffer, tr->buffer, cpu);
 
 	if (ret == -EBUSY) {
@@ -766,8 +749,6 @@
 			"Failed to swap buffers due to commit in progress\n");
 	}
 
-	ftrace_enable_cpu();
-
 	WARN_ON_ONCE(ret && ret != -EAGAIN && ret != -EBUSY);
 
 	__update_max_tr(tr, tsk, cpu);
@@ -782,8 +763,6 @@
  * Register a new plugin tracer.
  */
 int register_tracer(struct tracer *type)
-__releases(kernel_lock)
-__acquires(kernel_lock)
 {
 	struct tracer *t;
 	int ret = 0;
@@ -841,7 +820,8 @@
 
 		/* If we expanded the buffers, make sure the max is expanded too */
 		if (ring_buffer_expanded && type->use_max_tr)
-			ring_buffer_resize(max_tr.buffer, trace_buf_size);
+			ring_buffer_resize(max_tr.buffer, trace_buf_size,
+						RING_BUFFER_ALL_CPUS);
 
 		/* the test is responsible for initializing and enabling */
 		pr_info("Testing tracer %s: ", type->name);
@@ -857,7 +837,8 @@
 
 		/* Shrink the max buffer again */
 		if (ring_buffer_expanded && type->use_max_tr)
-			ring_buffer_resize(max_tr.buffer, 1);
+			ring_buffer_resize(max_tr.buffer, 1,
+						RING_BUFFER_ALL_CPUS);
 
 		printk(KERN_CONT "PASSED\n");
 	}
@@ -917,13 +898,6 @@
 	mutex_unlock(&trace_types_lock);
 }
 
-static void __tracing_reset(struct ring_buffer *buffer, int cpu)
-{
-	ftrace_disable_cpu();
-	ring_buffer_reset_cpu(buffer, cpu);
-	ftrace_enable_cpu();
-}
-
 void tracing_reset(struct trace_array *tr, int cpu)
 {
 	struct ring_buffer *buffer = tr->buffer;
@@ -932,7 +906,7 @@
 
 	/* Make sure all commits have finished */
 	synchronize_sched();
-	__tracing_reset(buffer, cpu);
+	ring_buffer_reset_cpu(buffer, cpu);
 
 	ring_buffer_record_enable(buffer);
 }
@@ -950,7 +924,7 @@
 	tr->time_start = ftrace_now(tr->cpu);
 
 	for_each_online_cpu(cpu)
-		__tracing_reset(buffer, cpu);
+		ring_buffer_reset_cpu(buffer, cpu);
 
 	ring_buffer_record_enable(buffer);
 }
@@ -1498,25 +1472,119 @@
 
 #endif /* CONFIG_STACKTRACE */
 
+/* created for use with alloc_percpu */
+struct trace_buffer_struct {
+	char buffer[TRACE_BUF_SIZE];
+};
+
+static struct trace_buffer_struct *trace_percpu_buffer;
+static struct trace_buffer_struct *trace_percpu_sirq_buffer;
+static struct trace_buffer_struct *trace_percpu_irq_buffer;
+static struct trace_buffer_struct *trace_percpu_nmi_buffer;
+
+/*
+ * The buffer used is dependent on the context. There is a per cpu
+ * buffer for normal context, softirq contex, hard irq context and
+ * for NMI context. Thise allows for lockless recording.
+ *
+ * Note, if the buffers failed to be allocated, then this returns NULL
+ */
+static char *get_trace_buf(void)
+{
+	struct trace_buffer_struct *percpu_buffer;
+	struct trace_buffer_struct *buffer;
+
+	/*
+	 * If we have allocated per cpu buffers, then we do not
+	 * need to do any locking.
+	 */
+	if (in_nmi())
+		percpu_buffer = trace_percpu_nmi_buffer;
+	else if (in_irq())
+		percpu_buffer = trace_percpu_irq_buffer;
+	else if (in_softirq())
+		percpu_buffer = trace_percpu_sirq_buffer;
+	else
+		percpu_buffer = trace_percpu_buffer;
+
+	if (!percpu_buffer)
+		return NULL;
+
+	buffer = per_cpu_ptr(percpu_buffer, smp_processor_id());
+
+	return buffer->buffer;
+}
+
+static int alloc_percpu_trace_buffer(void)
+{
+	struct trace_buffer_struct *buffers;
+	struct trace_buffer_struct *sirq_buffers;
+	struct trace_buffer_struct *irq_buffers;
+	struct trace_buffer_struct *nmi_buffers;
+
+	buffers = alloc_percpu(struct trace_buffer_struct);
+	if (!buffers)
+		goto err_warn;
+
+	sirq_buffers = alloc_percpu(struct trace_buffer_struct);
+	if (!sirq_buffers)
+		goto err_sirq;
+
+	irq_buffers = alloc_percpu(struct trace_buffer_struct);
+	if (!irq_buffers)
+		goto err_irq;
+
+	nmi_buffers = alloc_percpu(struct trace_buffer_struct);
+	if (!nmi_buffers)
+		goto err_nmi;
+
+	trace_percpu_buffer = buffers;
+	trace_percpu_sirq_buffer = sirq_buffers;
+	trace_percpu_irq_buffer = irq_buffers;
+	trace_percpu_nmi_buffer = nmi_buffers;
+
+	return 0;
+
+ err_nmi:
+	free_percpu(irq_buffers);
+ err_irq:
+	free_percpu(sirq_buffers);
+ err_sirq:
+	free_percpu(buffers);
+ err_warn:
+	WARN(1, "Could not allocate percpu trace_printk buffer");
+	return -ENOMEM;
+}
+
+void trace_printk_init_buffers(void)
+{
+	static int buffers_allocated;
+
+	if (buffers_allocated)
+		return;
+
+	if (alloc_percpu_trace_buffer())
+		return;
+
+	pr_info("ftrace: Allocated trace_printk buffers\n");
+
+	buffers_allocated = 1;
+}
+
 /**
  * trace_vbprintk - write binary msg to tracing buffer
  *
  */
 int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
 {
-	static arch_spinlock_t trace_buf_lock =
-		(arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
-	static u32 trace_buf[TRACE_BUF_SIZE];
-
 	struct ftrace_event_call *call = &event_bprint;
 	struct ring_buffer_event *event;
 	struct ring_buffer *buffer;
 	struct trace_array *tr = &global_trace;
-	struct trace_array_cpu *data;
 	struct bprint_entry *entry;
 	unsigned long flags;
-	int disable;
-	int cpu, len = 0, size, pc;
+	char *tbuffer;
+	int len = 0, size, pc;
 
 	if (unlikely(tracing_selftest_running || tracing_disabled))
 		return 0;
@@ -1526,43 +1594,36 @@
 
 	pc = preempt_count();
 	preempt_disable_notrace();
-	cpu = raw_smp_processor_id();
-	data = tr->data[cpu];
 
-	disable = atomic_inc_return(&data->disabled);
-	if (unlikely(disable != 1))
+	tbuffer = get_trace_buf();
+	if (!tbuffer) {
+		len = 0;
+		goto out;
+	}
+
+	len = vbin_printf((u32 *)tbuffer, TRACE_BUF_SIZE/sizeof(int), fmt, args);
+
+	if (len > TRACE_BUF_SIZE/sizeof(int) || len < 0)
 		goto out;
 
-	/* Lockdep uses trace_printk for lock tracing */
-	local_irq_save(flags);
-	arch_spin_lock(&trace_buf_lock);
-	len = vbin_printf(trace_buf, TRACE_BUF_SIZE, fmt, args);
-
-	if (len > TRACE_BUF_SIZE || len < 0)
-		goto out_unlock;
-
+	local_save_flags(flags);
 	size = sizeof(*entry) + sizeof(u32) * len;
 	buffer = tr->buffer;
 	event = trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size,
 					  flags, pc);
 	if (!event)
-		goto out_unlock;
+		goto out;
 	entry = ring_buffer_event_data(event);
 	entry->ip			= ip;
 	entry->fmt			= fmt;
 
-	memcpy(entry->buf, trace_buf, sizeof(u32) * len);
+	memcpy(entry->buf, tbuffer, sizeof(u32) * len);
 	if (!filter_check_discard(call, entry, buffer, event)) {
 		ring_buffer_unlock_commit(buffer, event);
 		ftrace_trace_stack(buffer, flags, 6, pc);
 	}
 
-out_unlock:
-	arch_spin_unlock(&trace_buf_lock);
-	local_irq_restore(flags);
-
 out:
-	atomic_dec_return(&data->disabled);
 	preempt_enable_notrace();
 	unpause_graph_tracing();
 
@@ -1588,58 +1649,53 @@
 int trace_array_vprintk(struct trace_array *tr,
 			unsigned long ip, const char *fmt, va_list args)
 {
-	static arch_spinlock_t trace_buf_lock = __ARCH_SPIN_LOCK_UNLOCKED;
-	static char trace_buf[TRACE_BUF_SIZE];
-
 	struct ftrace_event_call *call = &event_print;
 	struct ring_buffer_event *event;
 	struct ring_buffer *buffer;
-	struct trace_array_cpu *data;
-	int cpu, len = 0, size, pc;
+	int len = 0, size, pc;
 	struct print_entry *entry;
-	unsigned long irq_flags;
-	int disable;
+	unsigned long flags;
+	char *tbuffer;
 
 	if (tracing_disabled || tracing_selftest_running)
 		return 0;
 
+	/* Don't pollute graph traces with trace_vprintk internals */
+	pause_graph_tracing();
+
 	pc = preempt_count();
 	preempt_disable_notrace();
-	cpu = raw_smp_processor_id();
-	data = tr->data[cpu];
 
-	disable = atomic_inc_return(&data->disabled);
-	if (unlikely(disable != 1))
+
+	tbuffer = get_trace_buf();
+	if (!tbuffer) {
+		len = 0;
+		goto out;
+	}
+
+	len = vsnprintf(tbuffer, TRACE_BUF_SIZE, fmt, args);
+	if (len > TRACE_BUF_SIZE)
 		goto out;
 
-	pause_graph_tracing();
-	raw_local_irq_save(irq_flags);
-	arch_spin_lock(&trace_buf_lock);
-	len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args);
-
+	local_save_flags(flags);
 	size = sizeof(*entry) + len + 1;
 	buffer = tr->buffer;
 	event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
-					  irq_flags, pc);
+					  flags, pc);
 	if (!event)
-		goto out_unlock;
+		goto out;
 	entry = ring_buffer_event_data(event);
 	entry->ip = ip;
 
-	memcpy(&entry->buf, trace_buf, len);
+	memcpy(&entry->buf, tbuffer, len);
 	entry->buf[len] = '\0';
 	if (!filter_check_discard(call, entry, buffer, event)) {
 		ring_buffer_unlock_commit(buffer, event);
-		ftrace_trace_stack(buffer, irq_flags, 6, pc);
+		ftrace_trace_stack(buffer, flags, 6, pc);
 	}
-
- out_unlock:
-	arch_spin_unlock(&trace_buf_lock);
-	raw_local_irq_restore(irq_flags);
-	unpause_graph_tracing();
  out:
-	atomic_dec_return(&data->disabled);
 	preempt_enable_notrace();
+	unpause_graph_tracing();
 
 	return len;
 }
@@ -1652,14 +1708,9 @@
 
 static void trace_iterator_increment(struct trace_iterator *iter)
 {
-	/* Don't allow ftrace to trace into the ring buffers */
-	ftrace_disable_cpu();
-
 	iter->idx++;
 	if (iter->buffer_iter[iter->cpu])
 		ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
-
-	ftrace_enable_cpu();
 }
 
 static struct trace_entry *
@@ -1669,17 +1720,12 @@
 	struct ring_buffer_event *event;
 	struct ring_buffer_iter *buf_iter = iter->buffer_iter[cpu];
 
-	/* Don't allow ftrace to trace into the ring buffers */
-	ftrace_disable_cpu();
-
 	if (buf_iter)
 		event = ring_buffer_iter_peek(buf_iter, ts);
 	else
 		event = ring_buffer_peek(iter->tr->buffer, cpu, ts,
 					 lost_events);
 
-	ftrace_enable_cpu();
-
 	if (event) {
 		iter->ent_size = ring_buffer_event_length(event);
 		return ring_buffer_event_data(event);
@@ -1769,11 +1815,8 @@
 
 static void trace_consume(struct trace_iterator *iter)
 {
-	/* Don't allow ftrace to trace into the ring buffers */
-	ftrace_disable_cpu();
 	ring_buffer_consume(iter->tr->buffer, iter->cpu, &iter->ts,
 			    &iter->lost_events);
-	ftrace_enable_cpu();
 }
 
 static void *s_next(struct seq_file *m, void *v, loff_t *pos)
@@ -1862,16 +1905,12 @@
 		iter->cpu = 0;
 		iter->idx = -1;
 
-		ftrace_disable_cpu();
-
 		if (cpu_file == TRACE_PIPE_ALL_CPU) {
 			for_each_tracing_cpu(cpu)
 				tracing_iter_reset(iter, cpu);
 		} else
 			tracing_iter_reset(iter, cpu_file);
 
-		ftrace_enable_cpu();
-
 		iter->leftover = 0;
 		for (p = iter; p && l < *pos; p = s_next(m, p, &l))
 			;
@@ -2332,15 +2371,13 @@
 __tracing_open(struct inode *inode, struct file *file)
 {
 	long cpu_file = (long) inode->i_private;
-	void *fail_ret = ERR_PTR(-ENOMEM);
 	struct trace_iterator *iter;
-	struct seq_file *m;
-	int cpu, ret;
+	int cpu;
 
 	if (tracing_disabled)
 		return ERR_PTR(-ENODEV);
 
-	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+	iter = __seq_open_private(file, &tracer_seq_ops, sizeof(*iter));
 	if (!iter)
 		return ERR_PTR(-ENOMEM);
 
@@ -2397,32 +2434,15 @@
 		tracing_iter_reset(iter, cpu);
 	}
 
-	ret = seq_open(file, &tracer_seq_ops);
-	if (ret < 0) {
-		fail_ret = ERR_PTR(ret);
-		goto fail_buffer;
-	}
-
-	m = file->private_data;
-	m->private = iter;
-
 	mutex_unlock(&trace_types_lock);
 
 	return iter;
 
- fail_buffer:
-	for_each_tracing_cpu(cpu) {
-		if (iter->buffer_iter[cpu])
-			ring_buffer_read_finish(iter->buffer_iter[cpu]);
-	}
-	free_cpumask_var(iter->started);
-	tracing_start();
  fail:
 	mutex_unlock(&trace_types_lock);
 	kfree(iter->trace);
-	kfree(iter);
-
-	return fail_ret;
+	seq_release_private(inode, file);
+	return ERR_PTR(-ENOMEM);
 }
 
 int tracing_open_generic(struct inode *inode, struct file *filp)
@@ -2458,11 +2478,10 @@
 	tracing_start();
 	mutex_unlock(&trace_types_lock);
 
-	seq_release(inode, file);
 	mutex_destroy(&iter->mutex);
 	free_cpumask_var(iter->started);
 	kfree(iter->trace);
-	kfree(iter);
+	seq_release_private(inode, file);
 	return 0;
 }
 
@@ -2648,10 +2667,12 @@
 		if (cpumask_test_cpu(cpu, tracing_cpumask) &&
 				!cpumask_test_cpu(cpu, tracing_cpumask_new)) {
 			atomic_inc(&global_trace.data[cpu]->disabled);
+			ring_buffer_record_disable_cpu(global_trace.buffer, cpu);
 		}
 		if (!cpumask_test_cpu(cpu, tracing_cpumask) &&
 				cpumask_test_cpu(cpu, tracing_cpumask_new)) {
 			atomic_dec(&global_trace.data[cpu]->disabled);
+			ring_buffer_record_enable_cpu(global_trace.buffer, cpu);
 		}
 	}
 	arch_spin_unlock(&ftrace_max_lock);
@@ -2974,7 +2995,14 @@
 	return t->init(tr);
 }
 
-static int __tracing_resize_ring_buffer(unsigned long size)
+static void set_buffer_entries(struct trace_array *tr, unsigned long val)
+{
+	int cpu;
+	for_each_tracing_cpu(cpu)
+		tr->data[cpu]->entries = val;
+}
+
+static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
 {
 	int ret;
 
@@ -2985,19 +3013,32 @@
 	 */
 	ring_buffer_expanded = 1;
 
-	ret = ring_buffer_resize(global_trace.buffer, size);
+	ret = ring_buffer_resize(global_trace.buffer, size, cpu);
 	if (ret < 0)
 		return ret;
 
 	if (!current_trace->use_max_tr)
 		goto out;
 
-	ret = ring_buffer_resize(max_tr.buffer, size);
+	ret = ring_buffer_resize(max_tr.buffer, size, cpu);
 	if (ret < 0) {
-		int r;
+		int r = 0;
 
-		r = ring_buffer_resize(global_trace.buffer,
-				       global_trace.entries);
+		if (cpu == RING_BUFFER_ALL_CPUS) {
+			int i;
+			for_each_tracing_cpu(i) {
+				r = ring_buffer_resize(global_trace.buffer,
+						global_trace.data[i]->entries,
+						i);
+				if (r < 0)
+					break;
+			}
+		} else {
+			r = ring_buffer_resize(global_trace.buffer,
+						global_trace.data[cpu]->entries,
+						cpu);
+		}
+
 		if (r < 0) {
 			/*
 			 * AARGH! We are left with different
@@ -3019,43 +3060,39 @@
 		return ret;
 	}
 
-	max_tr.entries = size;
+	if (cpu == RING_BUFFER_ALL_CPUS)
+		set_buffer_entries(&max_tr, size);
+	else
+		max_tr.data[cpu]->entries = size;
+
  out:
-	global_trace.entries = size;
+	if (cpu == RING_BUFFER_ALL_CPUS)
+		set_buffer_entries(&global_trace, size);
+	else
+		global_trace.data[cpu]->entries = size;
 
 	return ret;
 }
 
-static ssize_t tracing_resize_ring_buffer(unsigned long size)
+static ssize_t tracing_resize_ring_buffer(unsigned long size, int cpu_id)
 {
-	int cpu, ret = size;
+	int ret = size;
 
 	mutex_lock(&trace_types_lock);
 
-	tracing_stop();
-
-	/* disable all cpu buffers */
-	for_each_tracing_cpu(cpu) {
-		if (global_trace.data[cpu])
-			atomic_inc(&global_trace.data[cpu]->disabled);
-		if (max_tr.data[cpu])
-			atomic_inc(&max_tr.data[cpu]->disabled);
+	if (cpu_id != RING_BUFFER_ALL_CPUS) {
+		/* make sure, this cpu is enabled in the mask */
+		if (!cpumask_test_cpu(cpu_id, tracing_buffer_mask)) {
+			ret = -EINVAL;
+			goto out;
+		}
 	}
 
-	if (size != global_trace.entries)
-		ret = __tracing_resize_ring_buffer(size);
-
+	ret = __tracing_resize_ring_buffer(size, cpu_id);
 	if (ret < 0)
 		ret = -ENOMEM;
 
-	for_each_tracing_cpu(cpu) {
-		if (global_trace.data[cpu])
-			atomic_dec(&global_trace.data[cpu]->disabled);
-		if (max_tr.data[cpu])
-			atomic_dec(&max_tr.data[cpu]->disabled);
-	}
-
-	tracing_start();
+out:
 	mutex_unlock(&trace_types_lock);
 
 	return ret;
@@ -3078,7 +3115,8 @@
 
 	mutex_lock(&trace_types_lock);
 	if (!ring_buffer_expanded)
-		ret = __tracing_resize_ring_buffer(trace_buf_size);
+		ret = __tracing_resize_ring_buffer(trace_buf_size,
+						RING_BUFFER_ALL_CPUS);
 	mutex_unlock(&trace_types_lock);
 
 	return ret;
@@ -3102,7 +3140,8 @@
 	mutex_lock(&trace_types_lock);
 
 	if (!ring_buffer_expanded) {
-		ret = __tracing_resize_ring_buffer(trace_buf_size);
+		ret = __tracing_resize_ring_buffer(trace_buf_size,
+						RING_BUFFER_ALL_CPUS);
 		if (ret < 0)
 			goto out;
 		ret = 0;
@@ -3128,8 +3167,8 @@
 		 * The max_tr ring buffer has some state (e.g. ring->clock) and
 		 * we want preserve it.
 		 */
-		ring_buffer_resize(max_tr.buffer, 1);
-		max_tr.entries = 1;
+		ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS);
+		set_buffer_entries(&max_tr, 1);
 	}
 	destroy_trace_option_files(topts);
 
@@ -3137,10 +3176,17 @@
 
 	topts = create_trace_option_files(current_trace);
 	if (current_trace->use_max_tr) {
-		ret = ring_buffer_resize(max_tr.buffer, global_trace.entries);
-		if (ret < 0)
-			goto out;
-		max_tr.entries = global_trace.entries;
+		int cpu;
+		/* we need to make per cpu buffer sizes equivalent */
+		for_each_tracing_cpu(cpu) {
+			ret = ring_buffer_resize(max_tr.buffer,
+						global_trace.data[cpu]->entries,
+						cpu);
+			if (ret < 0)
+				goto out;
+			max_tr.data[cpu]->entries =
+					global_trace.data[cpu]->entries;
+		}
 	}
 
 	if (t->init) {
@@ -3642,30 +3688,82 @@
 	goto out;
 }
 
+struct ftrace_entries_info {
+	struct trace_array	*tr;
+	int			cpu;
+};
+
+static int tracing_entries_open(struct inode *inode, struct file *filp)
+{
+	struct ftrace_entries_info *info;
+
+	if (tracing_disabled)
+		return -ENODEV;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->tr = &global_trace;
+	info->cpu = (unsigned long)inode->i_private;
+
+	filp->private_data = info;
+
+	return 0;
+}
+
 static ssize_t
 tracing_entries_read(struct file *filp, char __user *ubuf,
 		     size_t cnt, loff_t *ppos)
 {
-	struct trace_array *tr = filp->private_data;
-	char buf[96];
-	int r;
+	struct ftrace_entries_info *info = filp->private_data;
+	struct trace_array *tr = info->tr;
+	char buf[64];
+	int r = 0;
+	ssize_t ret;
 
 	mutex_lock(&trace_types_lock);
-	if (!ring_buffer_expanded)
-		r = sprintf(buf, "%lu (expanded: %lu)\n",
-			    tr->entries >> 10,
-			    trace_buf_size >> 10);
-	else
-		r = sprintf(buf, "%lu\n", tr->entries >> 10);
+
+	if (info->cpu == RING_BUFFER_ALL_CPUS) {
+		int cpu, buf_size_same;
+		unsigned long size;
+
+		size = 0;
+		buf_size_same = 1;
+		/* check if all cpu sizes are same */
+		for_each_tracing_cpu(cpu) {
+			/* fill in the size from first enabled cpu */
+			if (size == 0)
+				size = tr->data[cpu]->entries;
+			if (size != tr->data[cpu]->entries) {
+				buf_size_same = 0;
+				break;
+			}
+		}
+
+		if (buf_size_same) {
+			if (!ring_buffer_expanded)
+				r = sprintf(buf, "%lu (expanded: %lu)\n",
+					    size >> 10,
+					    trace_buf_size >> 10);
+			else
+				r = sprintf(buf, "%lu\n", size >> 10);
+		} else
+			r = sprintf(buf, "X\n");
+	} else
+		r = sprintf(buf, "%lu\n", tr->data[info->cpu]->entries >> 10);
+
 	mutex_unlock(&trace_types_lock);
 
-	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+	ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+	return ret;
 }
 
 static ssize_t
 tracing_entries_write(struct file *filp, const char __user *ubuf,
 		      size_t cnt, loff_t *ppos)
 {
+	struct ftrace_entries_info *info = filp->private_data;
 	unsigned long val;
 	int ret;
 
@@ -3680,7 +3778,7 @@
 	/* value is in KB */
 	val <<= 10;
 
-	ret = tracing_resize_ring_buffer(val);
+	ret = tracing_resize_ring_buffer(val, info->cpu);
 	if (ret < 0)
 		return ret;
 
@@ -3689,6 +3787,16 @@
 	return cnt;
 }
 
+static int
+tracing_entries_release(struct inode *inode, struct file *filp)
+{
+	struct ftrace_entries_info *info = filp->private_data;
+
+	kfree(info);
+
+	return 0;
+}
+
 static ssize_t
 tracing_total_entries_read(struct file *filp, char __user *ubuf,
 				size_t cnt, loff_t *ppos)
@@ -3700,7 +3808,7 @@
 
 	mutex_lock(&trace_types_lock);
 	for_each_tracing_cpu(cpu) {
-		size += tr->entries >> 10;
+		size += tr->data[cpu]->entries >> 10;
 		if (!ring_buffer_expanded)
 			expanded_size += trace_buf_size >> 10;
 	}
@@ -3734,7 +3842,7 @@
 	if (trace_flags & TRACE_ITER_STOP_ON_FREE)
 		tracing_off();
 	/* resize the ring buffer to 0 */
-	tracing_resize_ring_buffer(0);
+	tracing_resize_ring_buffer(0, RING_BUFFER_ALL_CPUS);
 
 	return 0;
 }
@@ -3749,14 +3857,14 @@
 	struct print_entry *entry;
 	unsigned long irq_flags;
 	struct page *pages[2];
+	void *map_page[2];
 	int nr_pages = 1;
 	ssize_t written;
-	void *page1;
-	void *page2;
 	int offset;
 	int size;
 	int len;
 	int ret;
+	int i;
 
 	if (tracing_disabled)
 		return -EINVAL;
@@ -3795,9 +3903,8 @@
 		goto out;
 	}
 
-	page1 = kmap_atomic(pages[0]);
-	if (nr_pages == 2)
-		page2 = kmap_atomic(pages[1]);
+	for (i = 0; i < nr_pages; i++)
+		map_page[i] = kmap_atomic(pages[i]);
 
 	local_save_flags(irq_flags);
 	size = sizeof(*entry) + cnt + 2; /* possible \n added */
@@ -3815,10 +3922,10 @@
 
 	if (nr_pages == 2) {
 		len = PAGE_SIZE - offset;
-		memcpy(&entry->buf, page1 + offset, len);
-		memcpy(&entry->buf[len], page2, cnt - len);
+		memcpy(&entry->buf, map_page[0] + offset, len);
+		memcpy(&entry->buf[len], map_page[1], cnt - len);
 	} else
-		memcpy(&entry->buf, page1 + offset, cnt);
+		memcpy(&entry->buf, map_page[0] + offset, cnt);
 
 	if (entry->buf[cnt - 1] != '\n') {
 		entry->buf[cnt] = '\n';
@@ -3833,11 +3940,10 @@
 	*fpos += written;
 
  out_unlock:
-	if (nr_pages == 2)
-		kunmap_atomic(page2);
-	kunmap_atomic(page1);
-	while (nr_pages > 0)
-		put_page(pages[--nr_pages]);
+	for (i = 0; i < nr_pages; i++){
+		kunmap_atomic(map_page[i]);
+		put_page(pages[i]);
+	}
  out:
 	return written;
 }
@@ -3933,9 +4039,10 @@
 };
 
 static const struct file_operations tracing_entries_fops = {
-	.open		= tracing_open_generic,
+	.open		= tracing_entries_open,
 	.read		= tracing_entries_read,
 	.write		= tracing_entries_write,
+	.release	= tracing_entries_release,
 	.llseek		= generic_file_llseek,
 };
 
@@ -4367,6 +4474,9 @@
 	struct dentry *d_cpu;
 	char cpu_dir[30]; /* 30 characters should be more than enough */
 
+	if (!d_percpu)
+		return;
+
 	snprintf(cpu_dir, 30, "cpu%ld", cpu);
 	d_cpu = debugfs_create_dir(cpu_dir, d_percpu);
 	if (!d_cpu) {
@@ -4387,6 +4497,9 @@
 
 	trace_create_file("stats", 0444, d_cpu,
 			(void *) cpu, &tracing_stats_fops);
+
+	trace_create_file("buffer_size_kb", 0444, d_cpu,
+			(void *) cpu, &tracing_entries_fops);
 }
 
 #ifdef CONFIG_FTRACE_SELFTEST
@@ -4718,7 +4831,7 @@
 			(void *) TRACE_PIPE_ALL_CPU, &tracing_pipe_fops);
 
 	trace_create_file("buffer_size_kb", 0644, d_tracer,
-			&global_trace, &tracing_entries_fops);
+			(void *) RING_BUFFER_ALL_CPUS, &tracing_entries_fops);
 
 	trace_create_file("buffer_total_size_kb", 0444, d_tracer,
 			&global_trace, &tracing_total_entries_fops);
@@ -4957,6 +5070,10 @@
 	if (!alloc_cpumask_var(&tracing_cpumask, GFP_KERNEL))
 		goto out_free_buffer_mask;
 
+	/* Only allocate trace_printk buffers if a trace_printk exists */
+	if (__stop___trace_bprintk_fmt != __start___trace_bprintk_fmt)
+		trace_printk_init_buffers();
+
 	/* To save memory, keep the ring buffer size to its minimum */
 	if (ring_buffer_expanded)
 		ring_buf_size = trace_buf_size;
@@ -4975,7 +5092,6 @@
 		WARN_ON(1);
 		goto out_free_cpumask;
 	}
-	global_trace.entries = ring_buffer_size(global_trace.buffer);
 	if (global_trace.buffer_disabled)
 		tracing_off();
 
@@ -4988,7 +5104,6 @@
 		ring_buffer_free(global_trace.buffer);
 		goto out_free_cpumask;
 	}
-	max_tr.entries = 1;
 #endif
 
 	/* Allocate the first page for all buffers */
@@ -4997,6 +5112,12 @@
 		max_tr.data[i] = &per_cpu(max_tr_data, i);
 	}
 
+	set_buffer_entries(&global_trace,
+			   ring_buffer_size(global_trace.buffer, 0));
+#ifdef CONFIG_TRACER_MAX_TRACE
+	set_buffer_entries(&max_tr, 1);
+#endif
+
 	trace_init_cmdlines();
 
 	register_tracer(&nop_trace);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index f95d65d..5aec220 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -103,6 +103,11 @@
 	unsigned long		ret_ip;
 };
 
+struct uprobe_trace_entry_head {
+	struct trace_entry	ent;
+	unsigned long		ip;
+};
+
 /*
  * trace_flag_type is an enumeration that holds different
  * states when a trace occurs. These are:
@@ -131,6 +136,7 @@
 	atomic_t		disabled;
 	void			*buffer_page;	/* ring buffer spare */
 
+	unsigned long		entries;
 	unsigned long		saved_latency;
 	unsigned long		critical_start;
 	unsigned long		critical_end;
@@ -152,7 +158,6 @@
  */
 struct trace_array {
 	struct ring_buffer	*buffer;
-	unsigned long		entries;
 	int			cpu;
 	int			buffer_disabled;
 	cycle_t			time_start;
@@ -826,6 +831,8 @@
 extern const char *__start___trace_bprintk_fmt[];
 extern const char *__stop___trace_bprintk_fmt[];
 
+void trace_printk_init_buffers(void);
+
 #undef FTRACE_ENTRY
 #define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter)	\
 	extern struct ftrace_event_call					\
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 580a05e..b31d3d5 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -19,547 +19,15 @@
 
 #include <linux/module.h>
 #include <linux/uaccess.h>
-#include <linux/kprobes.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/smp.h>
-#include <linux/debugfs.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ptrace.h>
-#include <linux/perf_event.h>
-#include <linux/stringify.h>
-#include <linux/limits.h>
-#include <asm/bitsperlong.h>
 
-#include "trace.h"
-#include "trace_output.h"
+#include "trace_probe.h"
 
-#define MAX_TRACE_ARGS 128
-#define MAX_ARGSTR_LEN 63
-#define MAX_EVENT_NAME_LEN 64
-#define MAX_STRING_SIZE PATH_MAX
 #define KPROBE_EVENT_SYSTEM "kprobes"
 
-/* Reserved field names */
-#define FIELD_STRING_IP "__probe_ip"
-#define FIELD_STRING_RETIP "__probe_ret_ip"
-#define FIELD_STRING_FUNC "__probe_func"
-
-const char *reserved_field_names[] = {
-	"common_type",
-	"common_flags",
-	"common_preempt_count",
-	"common_pid",
-	"common_tgid",
-	FIELD_STRING_IP,
-	FIELD_STRING_RETIP,
-	FIELD_STRING_FUNC,
-};
-
-/* Printing function type */
-typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *,
-				 void *);
-#define PRINT_TYPE_FUNC_NAME(type)	print_type_##type
-#define PRINT_TYPE_FMT_NAME(type)	print_type_format_##type
-
-/* Printing  in basic type function template */
-#define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast)			\
-static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s,	\
-						const char *name,	\
-						void *data, void *ent)\
-{									\
-	return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\
-}									\
-static const char PRINT_TYPE_FMT_NAME(type)[] = fmt;
-
-DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int)
-DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int)
-DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long)
-DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long)
-DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int)
-DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int)
-DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long)
-DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long)
-
-/* data_rloc: data relative location, compatible with u32 */
-#define make_data_rloc(len, roffs)	\
-	(((u32)(len) << 16) | ((u32)(roffs) & 0xffff))
-#define get_rloc_len(dl)	((u32)(dl) >> 16)
-#define get_rloc_offs(dl)	((u32)(dl) & 0xffff)
-
-static inline void *get_rloc_data(u32 *dl)
-{
-	return (u8 *)dl + get_rloc_offs(*dl);
-}
-
-/* For data_loc conversion */
-static inline void *get_loc_data(u32 *dl, void *ent)
-{
-	return (u8 *)ent + get_rloc_offs(*dl);
-}
-
-/*
- * Convert data_rloc to data_loc:
- *  data_rloc stores the offset from data_rloc itself, but data_loc
- *  stores the offset from event entry.
- */
-#define convert_rloc_to_loc(dl, offs)	((u32)(dl) + (offs))
-
-/* For defining macros, define string/string_size types */
-typedef u32 string;
-typedef u32 string_size;
-
-/* Print type function for string type */
-static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s,
-						  const char *name,
-						  void *data, void *ent)
-{
-	int len = *(u32 *)data >> 16;
-
-	if (!len)
-		return trace_seq_printf(s, " %s=(fault)", name);
-	else
-		return trace_seq_printf(s, " %s=\"%s\"", name,
-					(const char *)get_loc_data(data, ent));
-}
-static const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
-
-/* Data fetch function type */
-typedef	void (*fetch_func_t)(struct pt_regs *, void *, void *);
-
-struct fetch_param {
-	fetch_func_t	fn;
-	void *data;
-};
-
-static __kprobes void call_fetch(struct fetch_param *fprm,
-				 struct pt_regs *regs, void *dest)
-{
-	return fprm->fn(regs, fprm->data, dest);
-}
-
-#define FETCH_FUNC_NAME(method, type)	fetch_##method##_##type
-/*
- * Define macro for basic types - we don't need to define s* types, because
- * we have to care only about bitwidth at recording time.
- */
-#define DEFINE_BASIC_FETCH_FUNCS(method) \
-DEFINE_FETCH_##method(u8)		\
-DEFINE_FETCH_##method(u16)		\
-DEFINE_FETCH_##method(u32)		\
-DEFINE_FETCH_##method(u64)
-
-#define CHECK_FETCH_FUNCS(method, fn)			\
-	(((FETCH_FUNC_NAME(method, u8) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, u16) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, u32) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, u64) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, string) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, string_size) == fn)) \
-	 && (fn != NULL))
-
-/* Data fetch function templates */
-#define DEFINE_FETCH_reg(type)						\
-static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs,	\
-					void *offset, void *dest)	\
-{									\
-	*(type *)dest = (type)regs_get_register(regs,			\
-				(unsigned int)((unsigned long)offset));	\
-}
-DEFINE_BASIC_FETCH_FUNCS(reg)
-/* No string on the register */
-#define fetch_reg_string NULL
-#define fetch_reg_string_size NULL
-
-#define DEFINE_FETCH_stack(type)					\
-static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\
-					  void *offset, void *dest)	\
-{									\
-	*(type *)dest = (type)regs_get_kernel_stack_nth(regs,		\
-				(unsigned int)((unsigned long)offset));	\
-}
-DEFINE_BASIC_FETCH_FUNCS(stack)
-/* No string on the stack entry */
-#define fetch_stack_string NULL
-#define fetch_stack_string_size NULL
-
-#define DEFINE_FETCH_retval(type)					\
-static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\
-					  void *dummy, void *dest)	\
-{									\
-	*(type *)dest = (type)regs_return_value(regs);			\
-}
-DEFINE_BASIC_FETCH_FUNCS(retval)
-/* No string on the retval */
-#define fetch_retval_string NULL
-#define fetch_retval_string_size NULL
-
-#define DEFINE_FETCH_memory(type)					\
-static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
-					  void *addr, void *dest)	\
-{									\
-	type retval;							\
-	if (probe_kernel_address(addr, retval))				\
-		*(type *)dest = 0;					\
-	else								\
-		*(type *)dest = retval;					\
-}
-DEFINE_BASIC_FETCH_FUNCS(memory)
-/*
- * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
- * length and relative data location.
- */
-static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
-						      void *addr, void *dest)
-{
-	long ret;
-	int maxlen = get_rloc_len(*(u32 *)dest);
-	u8 *dst = get_rloc_data(dest);
-	u8 *src = addr;
-	mm_segment_t old_fs = get_fs();
-	if (!maxlen)
-		return;
-	/*
-	 * Try to get string again, since the string can be changed while
-	 * probing.
-	 */
-	set_fs(KERNEL_DS);
-	pagefault_disable();
-	do
-		ret = __copy_from_user_inatomic(dst++, src++, 1);
-	while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
-	dst[-1] = '\0';
-	pagefault_enable();
-	set_fs(old_fs);
-
-	if (ret < 0) {	/* Failed to fetch string */
-		((u8 *)get_rloc_data(dest))[0] = '\0';
-		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
-	} else
-		*(u32 *)dest = make_data_rloc(src - (u8 *)addr,
-					      get_rloc_offs(*(u32 *)dest));
-}
-/* Return the length of string -- including null terminal byte */
-static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
-							void *addr, void *dest)
-{
-	int ret, len = 0;
-	u8 c;
-	mm_segment_t old_fs = get_fs();
-
-	set_fs(KERNEL_DS);
-	pagefault_disable();
-	do {
-		ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
-		len++;
-	} while (c && ret == 0 && len < MAX_STRING_SIZE);
-	pagefault_enable();
-	set_fs(old_fs);
-
-	if (ret < 0)	/* Failed to check the length */
-		*(u32 *)dest = 0;
-	else
-		*(u32 *)dest = len;
-}
-
-/* Memory fetching by symbol */
-struct symbol_cache {
-	char *symbol;
-	long offset;
-	unsigned long addr;
-};
-
-static unsigned long update_symbol_cache(struct symbol_cache *sc)
-{
-	sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol);
-	if (sc->addr)
-		sc->addr += sc->offset;
-	return sc->addr;
-}
-
-static void free_symbol_cache(struct symbol_cache *sc)
-{
-	kfree(sc->symbol);
-	kfree(sc);
-}
-
-static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset)
-{
-	struct symbol_cache *sc;
-
-	if (!sym || strlen(sym) == 0)
-		return NULL;
-	sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL);
-	if (!sc)
-		return NULL;
-
-	sc->symbol = kstrdup(sym, GFP_KERNEL);
-	if (!sc->symbol) {
-		kfree(sc);
-		return NULL;
-	}
-	sc->offset = offset;
-
-	update_symbol_cache(sc);
-	return sc;
-}
-
-#define DEFINE_FETCH_symbol(type)					\
-static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\
-					  void *data, void *dest)	\
-{									\
-	struct symbol_cache *sc = data;					\
-	if (sc->addr)							\
-		fetch_memory_##type(regs, (void *)sc->addr, dest);	\
-	else								\
-		*(type *)dest = 0;					\
-}
-DEFINE_BASIC_FETCH_FUNCS(symbol)
-DEFINE_FETCH_symbol(string)
-DEFINE_FETCH_symbol(string_size)
-
-/* Dereference memory access function */
-struct deref_fetch_param {
-	struct fetch_param orig;
-	long offset;
-};
-
-#define DEFINE_FETCH_deref(type)					\
-static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\
-					    void *data, void *dest)	\
-{									\
-	struct deref_fetch_param *dprm = data;				\
-	unsigned long addr;						\
-	call_fetch(&dprm->orig, regs, &addr);				\
-	if (addr) {							\
-		addr += dprm->offset;					\
-		fetch_memory_##type(regs, (void *)addr, dest);		\
-	} else								\
-		*(type *)dest = 0;					\
-}
-DEFINE_BASIC_FETCH_FUNCS(deref)
-DEFINE_FETCH_deref(string)
-DEFINE_FETCH_deref(string_size)
-
-static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data)
-{
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		update_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		update_symbol_cache(data->orig.data);
-}
-
-static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data)
-{
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		free_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		free_symbol_cache(data->orig.data);
-	kfree(data);
-}
-
-/* Bitfield fetch function */
-struct bitfield_fetch_param {
-	struct fetch_param orig;
-	unsigned char hi_shift;
-	unsigned char low_shift;
-};
-
-#define DEFINE_FETCH_bitfield(type)					\
-static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\
-					    void *data, void *dest)	\
-{									\
-	struct bitfield_fetch_param *bprm = data;			\
-	type buf = 0;							\
-	call_fetch(&bprm->orig, regs, &buf);				\
-	if (buf) {							\
-		buf <<= bprm->hi_shift;					\
-		buf >>= bprm->low_shift;				\
-	}								\
-	*(type *)dest = buf;						\
-}
-DEFINE_BASIC_FETCH_FUNCS(bitfield)
-#define fetch_bitfield_string NULL
-#define fetch_bitfield_string_size NULL
-
-static __kprobes void
-update_bitfield_fetch_param(struct bitfield_fetch_param *data)
-{
-	/*
-	 * Don't check the bitfield itself, because this must be the
-	 * last fetch function.
-	 */
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		update_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		update_symbol_cache(data->orig.data);
-}
-
-static __kprobes void
-free_bitfield_fetch_param(struct bitfield_fetch_param *data)
-{
-	/*
-	 * Don't check the bitfield itself, because this must be the
-	 * last fetch function.
-	 */
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		free_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		free_symbol_cache(data->orig.data);
-	kfree(data);
-}
-
-/* Default (unsigned long) fetch type */
-#define __DEFAULT_FETCH_TYPE(t) u##t
-#define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)
-#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
-#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
-
-/* Fetch types */
-enum {
-	FETCH_MTD_reg = 0,
-	FETCH_MTD_stack,
-	FETCH_MTD_retval,
-	FETCH_MTD_memory,
-	FETCH_MTD_symbol,
-	FETCH_MTD_deref,
-	FETCH_MTD_bitfield,
-	FETCH_MTD_END,
-};
-
-#define ASSIGN_FETCH_FUNC(method, type)	\
-	[FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type)
-
-#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)	\
-	{.name = _name,				\
-	 .size = _size,					\
-	 .is_signed = sign,				\
-	 .print = PRINT_TYPE_FUNC_NAME(ptype),		\
-	 .fmt = PRINT_TYPE_FMT_NAME(ptype),		\
-	 .fmttype = _fmttype,				\
-	 .fetch = {					\
-ASSIGN_FETCH_FUNC(reg, ftype),				\
-ASSIGN_FETCH_FUNC(stack, ftype),			\
-ASSIGN_FETCH_FUNC(retval, ftype),			\
-ASSIGN_FETCH_FUNC(memory, ftype),			\
-ASSIGN_FETCH_FUNC(symbol, ftype),			\
-ASSIGN_FETCH_FUNC(deref, ftype),			\
-ASSIGN_FETCH_FUNC(bitfield, ftype),			\
-	  }						\
-	}
-
-#define ASSIGN_FETCH_TYPE(ptype, ftype, sign)			\
-	__ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype)
-
-#define FETCH_TYPE_STRING 0
-#define FETCH_TYPE_STRSIZE 1
-
-/* Fetch type information table */
-static const struct fetch_type {
-	const char	*name;		/* Name of type */
-	size_t		size;		/* Byte size of type */
-	int		is_signed;	/* Signed flag */
-	print_type_func_t	print;	/* Print functions */
-	const char	*fmt;		/* Fromat string */
-	const char	*fmttype;	/* Name in format file */
-	/* Fetch functions */
-	fetch_func_t	fetch[FETCH_MTD_END];
-} fetch_type_table[] = {
-	/* Special types */
-	[FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,
-					sizeof(u32), 1, "__data_loc char[]"),
-	[FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,
-					string_size, sizeof(u32), 0, "u32"),
-	/* Basic types */
-	ASSIGN_FETCH_TYPE(u8,  u8,  0),
-	ASSIGN_FETCH_TYPE(u16, u16, 0),
-	ASSIGN_FETCH_TYPE(u32, u32, 0),
-	ASSIGN_FETCH_TYPE(u64, u64, 0),
-	ASSIGN_FETCH_TYPE(s8,  u8,  1),
-	ASSIGN_FETCH_TYPE(s16, u16, 1),
-	ASSIGN_FETCH_TYPE(s32, u32, 1),
-	ASSIGN_FETCH_TYPE(s64, u64, 1),
-};
-
-static const struct fetch_type *find_fetch_type(const char *type)
-{
-	int i;
-
-	if (!type)
-		type = DEFAULT_FETCH_TYPE_STR;
-
-	/* Special case: bitfield */
-	if (*type == 'b') {
-		unsigned long bs;
-		type = strchr(type, '/');
-		if (!type)
-			goto fail;
-		type++;
-		if (strict_strtoul(type, 0, &bs))
-			goto fail;
-		switch (bs) {
-		case 8:
-			return find_fetch_type("u8");
-		case 16:
-			return find_fetch_type("u16");
-		case 32:
-			return find_fetch_type("u32");
-		case 64:
-			return find_fetch_type("u64");
-		default:
-			goto fail;
-		}
-	}
-
-	for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++)
-		if (strcmp(type, fetch_type_table[i].name) == 0)
-			return &fetch_type_table[i];
-fail:
-	return NULL;
-}
-
-/* Special function : only accept unsigned long */
-static __kprobes void fetch_stack_address(struct pt_regs *regs,
-					  void *dummy, void *dest)
-{
-	*(unsigned long *)dest = kernel_stack_pointer(regs);
-}
-
-static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
-					    fetch_func_t orig_fn)
-{
-	int i;
-
-	if (type != &fetch_type_table[FETCH_TYPE_STRING])
-		return NULL;	/* Only string type needs size function */
-	for (i = 0; i < FETCH_MTD_END; i++)
-		if (type->fetch[i] == orig_fn)
-			return fetch_type_table[FETCH_TYPE_STRSIZE].fetch[i];
-
-	WARN_ON(1);	/* This should not happen */
-	return NULL;
-}
-
 /**
  * Kprobe event core functions
  */
 
-struct probe_arg {
-	struct fetch_param	fetch;
-	struct fetch_param	fetch_size;
-	unsigned int		offset;	/* Offset from argument entry */
-	const char		*name;	/* Name of this argument */
-	const char		*comm;	/* Command of this argument */
-	const struct fetch_type	*type;	/* Type of this argument */
-};
-
-/* Flags for trace_probe */
-#define TP_FLAG_TRACE	1
-#define TP_FLAG_PROFILE	2
-#define TP_FLAG_REGISTERED 4
-
 struct trace_probe {
 	struct list_head	list;
 	struct kretprobe	rp;	/* Use rp.kp for kprobe use */
@@ -631,18 +99,6 @@
 static int kretprobe_dispatcher(struct kretprobe_instance *ri,
 				struct pt_regs *regs);
 
-/* Check the name is good for event/group/fields */
-static int is_good_name(const char *name)
-{
-	if (!isalpha(*name) && *name != '_')
-		return 0;
-	while (*++name != '\0') {
-		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
-			return 0;
-	}
-	return 1;
-}
-
 /*
  * Allocate new trace_probe and initialize it (including kprobes).
  */
@@ -651,7 +107,7 @@
 					     void *addr,
 					     const char *symbol,
 					     unsigned long offs,
-					     int nargs, int is_return)
+					     int nargs, bool is_return)
 {
 	struct trace_probe *tp;
 	int ret = -ENOMEM;
@@ -702,34 +158,12 @@
 	return ERR_PTR(ret);
 }
 
-static void update_probe_arg(struct probe_arg *arg)
-{
-	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
-		update_bitfield_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
-		update_deref_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
-		update_symbol_cache(arg->fetch.data);
-}
-
-static void free_probe_arg(struct probe_arg *arg)
-{
-	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
-		free_bitfield_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
-		free_deref_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
-		free_symbol_cache(arg->fetch.data);
-	kfree(arg->name);
-	kfree(arg->comm);
-}
-
 static void free_trace_probe(struct trace_probe *tp)
 {
 	int i;
 
 	for (i = 0; i < tp->nr_args; i++)
-		free_probe_arg(&tp->args[i]);
+		traceprobe_free_probe_arg(&tp->args[i]);
 
 	kfree(tp->call.class->system);
 	kfree(tp->call.name);
@@ -787,7 +221,7 @@
 		return -EINVAL;
 
 	for (i = 0; i < tp->nr_args; i++)
-		update_probe_arg(&tp->args[i]);
+		traceprobe_update_arg(&tp->args[i]);
 
 	/* Set/clear disabled flag according to tp->flag */
 	if (trace_probe_is_enabled(tp))
@@ -919,227 +353,6 @@
 	.priority = 1	/* Invoked after kprobe module callback */
 };
 
-/* Split symbol and offset. */
-static int split_symbol_offset(char *symbol, unsigned long *offset)
-{
-	char *tmp;
-	int ret;
-
-	if (!offset)
-		return -EINVAL;
-
-	tmp = strchr(symbol, '+');
-	if (tmp) {
-		/* skip sign because strict_strtol doesn't accept '+' */
-		ret = strict_strtoul(tmp + 1, 0, offset);
-		if (ret)
-			return ret;
-		*tmp = '\0';
-	} else
-		*offset = 0;
-	return 0;
-}
-
-#define PARAM_MAX_ARGS 16
-#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
-
-static int parse_probe_vars(char *arg, const struct fetch_type *t,
-			    struct fetch_param *f, int is_return)
-{
-	int ret = 0;
-	unsigned long param;
-
-	if (strcmp(arg, "retval") == 0) {
-		if (is_return)
-			f->fn = t->fetch[FETCH_MTD_retval];
-		else
-			ret = -EINVAL;
-	} else if (strncmp(arg, "stack", 5) == 0) {
-		if (arg[5] == '\0') {
-			if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR) == 0)
-				f->fn = fetch_stack_address;
-			else
-				ret = -EINVAL;
-		} else if (isdigit(arg[5])) {
-			ret = strict_strtoul(arg + 5, 10, &param);
-			if (ret || param > PARAM_MAX_STACK)
-				ret = -EINVAL;
-			else {
-				f->fn = t->fetch[FETCH_MTD_stack];
-				f->data = (void *)param;
-			}
-		} else
-			ret = -EINVAL;
-	} else
-		ret = -EINVAL;
-	return ret;
-}
-
-/* Recursive argument parser */
-static int __parse_probe_arg(char *arg, const struct fetch_type *t,
-			     struct fetch_param *f, int is_return)
-{
-	int ret = 0;
-	unsigned long param;
-	long offset;
-	char *tmp;
-
-	switch (arg[0]) {
-	case '$':
-		ret = parse_probe_vars(arg + 1, t, f, is_return);
-		break;
-	case '%':	/* named register */
-		ret = regs_query_register_offset(arg + 1);
-		if (ret >= 0) {
-			f->fn = t->fetch[FETCH_MTD_reg];
-			f->data = (void *)(unsigned long)ret;
-			ret = 0;
-		}
-		break;
-	case '@':	/* memory or symbol */
-		if (isdigit(arg[1])) {
-			ret = strict_strtoul(arg + 1, 0, &param);
-			if (ret)
-				break;
-			f->fn = t->fetch[FETCH_MTD_memory];
-			f->data = (void *)param;
-		} else {
-			ret = split_symbol_offset(arg + 1, &offset);
-			if (ret)
-				break;
-			f->data = alloc_symbol_cache(arg + 1, offset);
-			if (f->data)
-				f->fn = t->fetch[FETCH_MTD_symbol];
-		}
-		break;
-	case '+':	/* deref memory */
-		arg++;	/* Skip '+', because strict_strtol() rejects it. */
-	case '-':
-		tmp = strchr(arg, '(');
-		if (!tmp)
-			break;
-		*tmp = '\0';
-		ret = strict_strtol(arg, 0, &offset);
-		if (ret)
-			break;
-		arg = tmp + 1;
-		tmp = strrchr(arg, ')');
-		if (tmp) {
-			struct deref_fetch_param *dprm;
-			const struct fetch_type *t2 = find_fetch_type(NULL);
-			*tmp = '\0';
-			dprm = kzalloc(sizeof(struct deref_fetch_param),
-				       GFP_KERNEL);
-			if (!dprm)
-				return -ENOMEM;
-			dprm->offset = offset;
-			ret = __parse_probe_arg(arg, t2, &dprm->orig,
-						is_return);
-			if (ret)
-				kfree(dprm);
-			else {
-				f->fn = t->fetch[FETCH_MTD_deref];
-				f->data = (void *)dprm;
-			}
-		}
-		break;
-	}
-	if (!ret && !f->fn) {	/* Parsed, but do not find fetch method */
-		pr_info("%s type has no corresponding fetch method.\n",
-			t->name);
-		ret = -EINVAL;
-	}
-	return ret;
-}
-
-#define BYTES_TO_BITS(nb)	((BITS_PER_LONG * (nb)) / sizeof(long))
-
-/* Bitfield type needs to be parsed into a fetch function */
-static int __parse_bitfield_probe_arg(const char *bf,
-				      const struct fetch_type *t,
-				      struct fetch_param *f)
-{
-	struct bitfield_fetch_param *bprm;
-	unsigned long bw, bo;
-	char *tail;
-
-	if (*bf != 'b')
-		return 0;
-
-	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
-	if (!bprm)
-		return -ENOMEM;
-	bprm->orig = *f;
-	f->fn = t->fetch[FETCH_MTD_bitfield];
-	f->data = (void *)bprm;
-
-	bw = simple_strtoul(bf + 1, &tail, 0);	/* Use simple one */
-	if (bw == 0 || *tail != '@')
-		return -EINVAL;
-
-	bf = tail + 1;
-	bo = simple_strtoul(bf, &tail, 0);
-	if (tail == bf || *tail != '/')
-		return -EINVAL;
-
-	bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);
-	bprm->low_shift = bprm->hi_shift + bo;
-	return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
-}
-
-/* String length checking wrapper */
-static int parse_probe_arg(char *arg, struct trace_probe *tp,
-			   struct probe_arg *parg, int is_return)
-{
-	const char *t;
-	int ret;
-
-	if (strlen(arg) > MAX_ARGSTR_LEN) {
-		pr_info("Argument is too long.: %s\n",  arg);
-		return -ENOSPC;
-	}
-	parg->comm = kstrdup(arg, GFP_KERNEL);
-	if (!parg->comm) {
-		pr_info("Failed to allocate memory for command '%s'.\n", arg);
-		return -ENOMEM;
-	}
-	t = strchr(parg->comm, ':');
-	if (t) {
-		arg[t - parg->comm] = '\0';
-		t++;
-	}
-	parg->type = find_fetch_type(t);
-	if (!parg->type) {
-		pr_info("Unsupported type: %s\n", t);
-		return -EINVAL;
-	}
-	parg->offset = tp->size;
-	tp->size += parg->type->size;
-	ret = __parse_probe_arg(arg, parg->type, &parg->fetch, is_return);
-	if (ret >= 0 && t != NULL)
-		ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
-	if (ret >= 0) {
-		parg->fetch_size.fn = get_fetch_size_function(parg->type,
-							      parg->fetch.fn);
-		parg->fetch_size.data = parg->fetch.data;
-	}
-	return ret;
-}
-
-/* Return 1 if name is reserved or already used by another argument */
-static int conflict_field_name(const char *name,
-			       struct probe_arg *args, int narg)
-{
-	int i;
-	for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++)
-		if (strcmp(reserved_field_names[i], name) == 0)
-			return 1;
-	for (i = 0; i < narg; i++)
-		if (strcmp(args[i].name, name) == 0)
-			return 1;
-	return 0;
-}
-
 static int create_trace_probe(int argc, char **argv)
 {
 	/*
@@ -1162,7 +375,7 @@
 	 */
 	struct trace_probe *tp;
 	int i, ret = 0;
-	int is_return = 0, is_delete = 0;
+	bool is_return = false, is_delete = false;
 	char *symbol = NULL, *event = NULL, *group = NULL;
 	char *arg;
 	unsigned long offset = 0;
@@ -1171,11 +384,11 @@
 
 	/* argc must be >= 1 */
 	if (argv[0][0] == 'p')
-		is_return = 0;
+		is_return = false;
 	else if (argv[0][0] == 'r')
-		is_return = 1;
+		is_return = true;
 	else if (argv[0][0] == '-')
-		is_delete = 1;
+		is_delete = true;
 	else {
 		pr_info("Probe definition must be started with 'p', 'r' or"
 			" '-'.\n");
@@ -1240,7 +453,7 @@
 		/* a symbol specified */
 		symbol = argv[1];
 		/* TODO: support .init module functions */
-		ret = split_symbol_offset(symbol, &offset);
+		ret = traceprobe_split_symbol_offset(symbol, &offset);
 		if (ret) {
 			pr_info("Failed to parse symbol.\n");
 			return ret;
@@ -1302,7 +515,8 @@
 			goto error;
 		}
 
-		if (conflict_field_name(tp->args[i].name, tp->args, i)) {
+		if (traceprobe_conflict_field_name(tp->args[i].name,
+							tp->args, i)) {
 			pr_info("Argument[%d] name '%s' conflicts with "
 				"another field.\n", i, argv[i]);
 			ret = -EINVAL;
@@ -1310,7 +524,8 @@
 		}
 
 		/* Parse fetch argument */
-		ret = parse_probe_arg(arg, tp, &tp->args[i], is_return);
+		ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i],
+						is_return, true);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;
@@ -1412,70 +627,11 @@
 	return seq_open(file, &probes_seq_op);
 }
 
-static int command_trace_probe(const char *buf)
-{
-	char **argv;
-	int argc = 0, ret = 0;
-
-	argv = argv_split(GFP_KERNEL, buf, &argc);
-	if (!argv)
-		return -ENOMEM;
-
-	if (argc)
-		ret = create_trace_probe(argc, argv);
-
-	argv_free(argv);
-	return ret;
-}
-
-#define WRITE_BUFSIZE 4096
-
 static ssize_t probes_write(struct file *file, const char __user *buffer,
 			    size_t count, loff_t *ppos)
 {
-	char *kbuf, *tmp;
-	int ret;
-	size_t done;
-	size_t size;
-
-	kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL);
-	if (!kbuf)
-		return -ENOMEM;
-
-	ret = done = 0;
-	while (done < count) {
-		size = count - done;
-		if (size >= WRITE_BUFSIZE)
-			size = WRITE_BUFSIZE - 1;
-		if (copy_from_user(kbuf, buffer + done, size)) {
-			ret = -EFAULT;
-			goto out;
-		}
-		kbuf[size] = '\0';
-		tmp = strchr(kbuf, '\n');
-		if (tmp) {
-			*tmp = '\0';
-			size = tmp - kbuf + 1;
-		} else if (done + size < count) {
-			pr_warning("Line length is too long: "
-				   "Should be less than %d.", WRITE_BUFSIZE);
-			ret = -EINVAL;
-			goto out;
-		}
-		done += size;
-		/* Remove comments */
-		tmp = strchr(kbuf, '#');
-		if (tmp)
-			*tmp = '\0';
-
-		ret = command_trace_probe(kbuf);
-		if (ret)
-			goto out;
-	}
-	ret = done;
-out:
-	kfree(kbuf);
-	return ret;
+	return traceprobe_probes_write(file, buffer, count, ppos,
+			create_trace_probe);
 }
 
 static const struct file_operations kprobe_events_ops = {
@@ -1711,16 +867,6 @@
 	return TRACE_TYPE_PARTIAL_LINE;
 }
 
-#undef DEFINE_FIELD
-#define DEFINE_FIELD(type, item, name, is_signed)			\
-	do {								\
-		ret = trace_define_field(event_call, #type, name,	\
-					 offsetof(typeof(field), item),	\
-					 sizeof(field.item), is_signed, \
-					 FILTER_OTHER);			\
-		if (ret)						\
-			return ret;					\
-	} while (0)
 
 static int kprobe_event_define_fields(struct ftrace_event_call *event_call)
 {
@@ -2051,8 +1197,9 @@
 
 	pr_info("Testing kprobe tracing: ");
 
-	ret = command_trace_probe("p:testprobe kprobe_trace_selftest_target "
-				  "$stack $stack0 +0($stack)");
+	ret = traceprobe_command("p:testprobe kprobe_trace_selftest_target "
+				  "$stack $stack0 +0($stack)",
+				  create_trace_probe);
 	if (WARN_ON_ONCE(ret)) {
 		pr_warning("error on probing function entry.\n");
 		warn++;
@@ -2066,8 +1213,8 @@
 			enable_trace_probe(tp, TP_FLAG_TRACE);
 	}
 
-	ret = command_trace_probe("r:testprobe2 kprobe_trace_selftest_target "
-				  "$retval");
+	ret = traceprobe_command("r:testprobe2 kprobe_trace_selftest_target "
+				  "$retval", create_trace_probe);
 	if (WARN_ON_ONCE(ret)) {
 		pr_warning("error on probing function return.\n");
 		warn++;
@@ -2101,13 +1248,13 @@
 	} else
 		disable_trace_probe(tp, TP_FLAG_TRACE);
 
-	ret = command_trace_probe("-:testprobe");
+	ret = traceprobe_command("-:testprobe", create_trace_probe);
 	if (WARN_ON_ONCE(ret)) {
 		pr_warning("error on deleting a probe.\n");
 		warn++;
 	}
 
-	ret = command_trace_probe("-:testprobe2");
+	ret = traceprobe_command("-:testprobe2", create_trace_probe);
 	if (WARN_ON_ONCE(ret)) {
 		pr_warning("error on deleting a probe.\n");
 		warn++;
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index 6fd4ffd..a9077c1 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -51,6 +51,10 @@
 	const char **iter;
 	char *fmt;
 
+	/* allocate the trace_printk per cpu buffers */
+	if (start != end)
+		trace_printk_init_buffers();
+
 	mutex_lock(&btrace_mutex);
 	for (iter = start; iter < end; iter++) {
 		struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
new file mode 100644
index 0000000..daa9980
--- /dev/null
+++ b/kernel/trace/trace_probe.c
@@ -0,0 +1,839 @@
+/*
+ * Common code for probe-based Dynamic events.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This code was copied from kernel/trace/trace_kprobe.c written by
+ * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+ *
+ * Updates to make this generic:
+ * Copyright (C) IBM Corporation, 2010-2011
+ * Author:     Srikar Dronamraju
+ */
+
+#include "trace_probe.h"
+
+const char *reserved_field_names[] = {
+	"common_type",
+	"common_flags",
+	"common_preempt_count",
+	"common_pid",
+	"common_tgid",
+	FIELD_STRING_IP,
+	FIELD_STRING_RETIP,
+	FIELD_STRING_FUNC,
+};
+
+/* Printing function type */
+#define PRINT_TYPE_FUNC_NAME(type)	print_type_##type
+#define PRINT_TYPE_FMT_NAME(type)	print_type_format_##type
+
+/* Printing  in basic type function template */
+#define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast)			\
+static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s,	\
+						const char *name,	\
+						void *data, void *ent)\
+{									\
+	return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\
+}									\
+static const char PRINT_TYPE_FMT_NAME(type)[] = fmt;
+
+DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int)
+DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int)
+DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long)
+DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long)
+DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int)
+DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int)
+DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long)
+DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long)
+
+static inline void *get_rloc_data(u32 *dl)
+{
+	return (u8 *)dl + get_rloc_offs(*dl);
+}
+
+/* For data_loc conversion */
+static inline void *get_loc_data(u32 *dl, void *ent)
+{
+	return (u8 *)ent + get_rloc_offs(*dl);
+}
+
+/* For defining macros, define string/string_size types */
+typedef u32 string;
+typedef u32 string_size;
+
+/* Print type function for string type */
+static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s,
+						  const char *name,
+						  void *data, void *ent)
+{
+	int len = *(u32 *)data >> 16;
+
+	if (!len)
+		return trace_seq_printf(s, " %s=(fault)", name);
+	else
+		return trace_seq_printf(s, " %s=\"%s\"", name,
+					(const char *)get_loc_data(data, ent));
+}
+
+static const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
+
+#define FETCH_FUNC_NAME(method, type)	fetch_##method##_##type
+/*
+ * Define macro for basic types - we don't need to define s* types, because
+ * we have to care only about bitwidth at recording time.
+ */
+#define DEFINE_BASIC_FETCH_FUNCS(method) \
+DEFINE_FETCH_##method(u8)		\
+DEFINE_FETCH_##method(u16)		\
+DEFINE_FETCH_##method(u32)		\
+DEFINE_FETCH_##method(u64)
+
+#define CHECK_FETCH_FUNCS(method, fn)			\
+	(((FETCH_FUNC_NAME(method, u8) == fn) ||	\
+	  (FETCH_FUNC_NAME(method, u16) == fn) ||	\
+	  (FETCH_FUNC_NAME(method, u32) == fn) ||	\
+	  (FETCH_FUNC_NAME(method, u64) == fn) ||	\
+	  (FETCH_FUNC_NAME(method, string) == fn) ||	\
+	  (FETCH_FUNC_NAME(method, string_size) == fn)) \
+	 && (fn != NULL))
+
+/* Data fetch function templates */
+#define DEFINE_FETCH_reg(type)						\
+static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs,	\
+					void *offset, void *dest)	\
+{									\
+	*(type *)dest = (type)regs_get_register(regs,			\
+				(unsigned int)((unsigned long)offset));	\
+}
+DEFINE_BASIC_FETCH_FUNCS(reg)
+/* No string on the register */
+#define fetch_reg_string	NULL
+#define fetch_reg_string_size	NULL
+
+#define DEFINE_FETCH_stack(type)					\
+static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\
+					  void *offset, void *dest)	\
+{									\
+	*(type *)dest = (type)regs_get_kernel_stack_nth(regs,		\
+				(unsigned int)((unsigned long)offset));	\
+}
+DEFINE_BASIC_FETCH_FUNCS(stack)
+/* No string on the stack entry */
+#define fetch_stack_string	NULL
+#define fetch_stack_string_size	NULL
+
+#define DEFINE_FETCH_retval(type)					\
+static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\
+					  void *dummy, void *dest)	\
+{									\
+	*(type *)dest = (type)regs_return_value(regs);			\
+}
+DEFINE_BASIC_FETCH_FUNCS(retval)
+/* No string on the retval */
+#define fetch_retval_string		NULL
+#define fetch_retval_string_size	NULL
+
+#define DEFINE_FETCH_memory(type)					\
+static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
+					  void *addr, void *dest)	\
+{									\
+	type retval;							\
+	if (probe_kernel_address(addr, retval))				\
+		*(type *)dest = 0;					\
+	else								\
+		*(type *)dest = retval;					\
+}
+DEFINE_BASIC_FETCH_FUNCS(memory)
+/*
+ * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
+ * length and relative data location.
+ */
+static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
+						      void *addr, void *dest)
+{
+	long ret;
+	int maxlen = get_rloc_len(*(u32 *)dest);
+	u8 *dst = get_rloc_data(dest);
+	u8 *src = addr;
+	mm_segment_t old_fs = get_fs();
+
+	if (!maxlen)
+		return;
+
+	/*
+	 * Try to get string again, since the string can be changed while
+	 * probing.
+	 */
+	set_fs(KERNEL_DS);
+	pagefault_disable();
+
+	do
+		ret = __copy_from_user_inatomic(dst++, src++, 1);
+	while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
+
+	dst[-1] = '\0';
+	pagefault_enable();
+	set_fs(old_fs);
+
+	if (ret < 0) {	/* Failed to fetch string */
+		((u8 *)get_rloc_data(dest))[0] = '\0';
+		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
+	} else {
+		*(u32 *)dest = make_data_rloc(src - (u8 *)addr,
+					      get_rloc_offs(*(u32 *)dest));
+	}
+}
+
+/* Return the length of string -- including null terminal byte */
+static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
+							void *addr, void *dest)
+{
+	mm_segment_t old_fs;
+	int ret, len = 0;
+	u8 c;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	pagefault_disable();
+
+	do {
+		ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
+		len++;
+	} while (c && ret == 0 && len < MAX_STRING_SIZE);
+
+	pagefault_enable();
+	set_fs(old_fs);
+
+	if (ret < 0)	/* Failed to check the length */
+		*(u32 *)dest = 0;
+	else
+		*(u32 *)dest = len;
+}
+
+/* Memory fetching by symbol */
+struct symbol_cache {
+	char		*symbol;
+	long		offset;
+	unsigned long	addr;
+};
+
+static unsigned long update_symbol_cache(struct symbol_cache *sc)
+{
+	sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol);
+
+	if (sc->addr)
+		sc->addr += sc->offset;
+
+	return sc->addr;
+}
+
+static void free_symbol_cache(struct symbol_cache *sc)
+{
+	kfree(sc->symbol);
+	kfree(sc);
+}
+
+static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset)
+{
+	struct symbol_cache *sc;
+
+	if (!sym || strlen(sym) == 0)
+		return NULL;
+
+	sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL);
+	if (!sc)
+		return NULL;
+
+	sc->symbol = kstrdup(sym, GFP_KERNEL);
+	if (!sc->symbol) {
+		kfree(sc);
+		return NULL;
+	}
+	sc->offset = offset;
+	update_symbol_cache(sc);
+
+	return sc;
+}
+
+#define DEFINE_FETCH_symbol(type)					\
+static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\
+					  void *data, void *dest)	\
+{									\
+	struct symbol_cache *sc = data;					\
+	if (sc->addr)							\
+		fetch_memory_##type(regs, (void *)sc->addr, dest);	\
+	else								\
+		*(type *)dest = 0;					\
+}
+DEFINE_BASIC_FETCH_FUNCS(symbol)
+DEFINE_FETCH_symbol(string)
+DEFINE_FETCH_symbol(string_size)
+
+/* Dereference memory access function */
+struct deref_fetch_param {
+	struct fetch_param	orig;
+	long			offset;
+};
+
+#define DEFINE_FETCH_deref(type)					\
+static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\
+					    void *data, void *dest)	\
+{									\
+	struct deref_fetch_param *dprm = data;				\
+	unsigned long addr;						\
+	call_fetch(&dprm->orig, regs, &addr);				\
+	if (addr) {							\
+		addr += dprm->offset;					\
+		fetch_memory_##type(regs, (void *)addr, dest);		\
+	} else								\
+		*(type *)dest = 0;					\
+}
+DEFINE_BASIC_FETCH_FUNCS(deref)
+DEFINE_FETCH_deref(string)
+DEFINE_FETCH_deref(string_size)
+
+static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data)
+{
+	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
+		update_deref_fetch_param(data->orig.data);
+	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
+		update_symbol_cache(data->orig.data);
+}
+
+static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data)
+{
+	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
+		free_deref_fetch_param(data->orig.data);
+	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
+		free_symbol_cache(data->orig.data);
+	kfree(data);
+}
+
+/* Bitfield fetch function */
+struct bitfield_fetch_param {
+	struct fetch_param	orig;
+	unsigned char		hi_shift;
+	unsigned char		low_shift;
+};
+
+#define DEFINE_FETCH_bitfield(type)					\
+static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\
+					    void *data, void *dest)	\
+{									\
+	struct bitfield_fetch_param *bprm = data;			\
+	type buf = 0;							\
+	call_fetch(&bprm->orig, regs, &buf);				\
+	if (buf) {							\
+		buf <<= bprm->hi_shift;					\
+		buf >>= bprm->low_shift;				\
+	}								\
+	*(type *)dest = buf;						\
+}
+
+DEFINE_BASIC_FETCH_FUNCS(bitfield)
+#define fetch_bitfield_string		NULL
+#define fetch_bitfield_string_size	NULL
+
+static __kprobes void
+update_bitfield_fetch_param(struct bitfield_fetch_param *data)
+{
+	/*
+	 * Don't check the bitfield itself, because this must be the
+	 * last fetch function.
+	 */
+	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
+		update_deref_fetch_param(data->orig.data);
+	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
+		update_symbol_cache(data->orig.data);
+}
+
+static __kprobes void
+free_bitfield_fetch_param(struct bitfield_fetch_param *data)
+{
+	/*
+	 * Don't check the bitfield itself, because this must be the
+	 * last fetch function.
+	 */
+	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
+		free_deref_fetch_param(data->orig.data);
+	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
+		free_symbol_cache(data->orig.data);
+
+	kfree(data);
+}
+
+/* Default (unsigned long) fetch type */
+#define __DEFAULT_FETCH_TYPE(t) u##t
+#define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)
+#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
+#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
+
+#define ASSIGN_FETCH_FUNC(method, type)	\
+	[FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type)
+
+#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)	\
+	{.name = _name,				\
+	 .size = _size,					\
+	 .is_signed = sign,				\
+	 .print = PRINT_TYPE_FUNC_NAME(ptype),		\
+	 .fmt = PRINT_TYPE_FMT_NAME(ptype),		\
+	 .fmttype = _fmttype,				\
+	 .fetch = {					\
+ASSIGN_FETCH_FUNC(reg, ftype),				\
+ASSIGN_FETCH_FUNC(stack, ftype),			\
+ASSIGN_FETCH_FUNC(retval, ftype),			\
+ASSIGN_FETCH_FUNC(memory, ftype),			\
+ASSIGN_FETCH_FUNC(symbol, ftype),			\
+ASSIGN_FETCH_FUNC(deref, ftype),			\
+ASSIGN_FETCH_FUNC(bitfield, ftype),			\
+	  }						\
+	}
+
+#define ASSIGN_FETCH_TYPE(ptype, ftype, sign)			\
+	__ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype)
+
+#define FETCH_TYPE_STRING	0
+#define FETCH_TYPE_STRSIZE	1
+
+/* Fetch type information table */
+static const struct fetch_type fetch_type_table[] = {
+	/* Special types */
+	[FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,
+					sizeof(u32), 1, "__data_loc char[]"),
+	[FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,
+					string_size, sizeof(u32), 0, "u32"),
+	/* Basic types */
+	ASSIGN_FETCH_TYPE(u8,  u8,  0),
+	ASSIGN_FETCH_TYPE(u16, u16, 0),
+	ASSIGN_FETCH_TYPE(u32, u32, 0),
+	ASSIGN_FETCH_TYPE(u64, u64, 0),
+	ASSIGN_FETCH_TYPE(s8,  u8,  1),
+	ASSIGN_FETCH_TYPE(s16, u16, 1),
+	ASSIGN_FETCH_TYPE(s32, u32, 1),
+	ASSIGN_FETCH_TYPE(s64, u64, 1),
+};
+
+static const struct fetch_type *find_fetch_type(const char *type)
+{
+	int i;
+
+	if (!type)
+		type = DEFAULT_FETCH_TYPE_STR;
+
+	/* Special case: bitfield */
+	if (*type == 'b') {
+		unsigned long bs;
+
+		type = strchr(type, '/');
+		if (!type)
+			goto fail;
+
+		type++;
+		if (strict_strtoul(type, 0, &bs))
+			goto fail;
+
+		switch (bs) {
+		case 8:
+			return find_fetch_type("u8");
+		case 16:
+			return find_fetch_type("u16");
+		case 32:
+			return find_fetch_type("u32");
+		case 64:
+			return find_fetch_type("u64");
+		default:
+			goto fail;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++)
+		if (strcmp(type, fetch_type_table[i].name) == 0)
+			return &fetch_type_table[i];
+
+fail:
+	return NULL;
+}
+
+/* Special function : only accept unsigned long */
+static __kprobes void fetch_stack_address(struct pt_regs *regs,
+					void *dummy, void *dest)
+{
+	*(unsigned long *)dest = kernel_stack_pointer(regs);
+}
+
+static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
+					fetch_func_t orig_fn)
+{
+	int i;
+
+	if (type != &fetch_type_table[FETCH_TYPE_STRING])
+		return NULL;	/* Only string type needs size function */
+
+	for (i = 0; i < FETCH_MTD_END; i++)
+		if (type->fetch[i] == orig_fn)
+			return fetch_type_table[FETCH_TYPE_STRSIZE].fetch[i];
+
+	WARN_ON(1);	/* This should not happen */
+
+	return NULL;
+}
+
+/* Split symbol and offset. */
+int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset)
+{
+	char *tmp;
+	int ret;
+
+	if (!offset)
+		return -EINVAL;
+
+	tmp = strchr(symbol, '+');
+	if (tmp) {
+		/* skip sign because strict_strtol doesn't accept '+' */
+		ret = strict_strtoul(tmp + 1, 0, offset);
+		if (ret)
+			return ret;
+
+		*tmp = '\0';
+	} else
+		*offset = 0;
+
+	return 0;
+}
+
+#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
+
+static int parse_probe_vars(char *arg, const struct fetch_type *t,
+			    struct fetch_param *f, bool is_return)
+{
+	int ret = 0;
+	unsigned long param;
+
+	if (strcmp(arg, "retval") == 0) {
+		if (is_return)
+			f->fn = t->fetch[FETCH_MTD_retval];
+		else
+			ret = -EINVAL;
+	} else if (strncmp(arg, "stack", 5) == 0) {
+		if (arg[5] == '\0') {
+			if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR) == 0)
+				f->fn = fetch_stack_address;
+			else
+				ret = -EINVAL;
+		} else if (isdigit(arg[5])) {
+			ret = strict_strtoul(arg + 5, 10, &param);
+			if (ret || param > PARAM_MAX_STACK)
+				ret = -EINVAL;
+			else {
+				f->fn = t->fetch[FETCH_MTD_stack];
+				f->data = (void *)param;
+			}
+		} else
+			ret = -EINVAL;
+	} else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/* Recursive argument parser */
+static int parse_probe_arg(char *arg, const struct fetch_type *t,
+		     struct fetch_param *f, bool is_return, bool is_kprobe)
+{
+	unsigned long param;
+	long offset;
+	char *tmp;
+	int ret;
+
+	ret = 0;
+
+	/* Until uprobe_events supports only reg arguments */
+	if (!is_kprobe && arg[0] != '%')
+		return -EINVAL;
+
+	switch (arg[0]) {
+	case '$':
+		ret = parse_probe_vars(arg + 1, t, f, is_return);
+		break;
+
+	case '%':	/* named register */
+		ret = regs_query_register_offset(arg + 1);
+		if (ret >= 0) {
+			f->fn = t->fetch[FETCH_MTD_reg];
+			f->data = (void *)(unsigned long)ret;
+			ret = 0;
+		}
+		break;
+
+	case '@':	/* memory or symbol */
+		if (isdigit(arg[1])) {
+			ret = strict_strtoul(arg + 1, 0, &param);
+			if (ret)
+				break;
+
+			f->fn = t->fetch[FETCH_MTD_memory];
+			f->data = (void *)param;
+		} else {
+			ret = traceprobe_split_symbol_offset(arg + 1, &offset);
+			if (ret)
+				break;
+
+			f->data = alloc_symbol_cache(arg + 1, offset);
+			if (f->data)
+				f->fn = t->fetch[FETCH_MTD_symbol];
+		}
+		break;
+
+	case '+':	/* deref memory */
+		arg++;	/* Skip '+', because strict_strtol() rejects it. */
+	case '-':
+		tmp = strchr(arg, '(');
+		if (!tmp)
+			break;
+
+		*tmp = '\0';
+		ret = strict_strtol(arg, 0, &offset);
+
+		if (ret)
+			break;
+
+		arg = tmp + 1;
+		tmp = strrchr(arg, ')');
+
+		if (tmp) {
+			struct deref_fetch_param	*dprm;
+			const struct fetch_type		*t2;
+
+			t2 = find_fetch_type(NULL);
+			*tmp = '\0';
+			dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL);
+
+			if (!dprm)
+				return -ENOMEM;
+
+			dprm->offset = offset;
+			ret = parse_probe_arg(arg, t2, &dprm->orig, is_return,
+							is_kprobe);
+			if (ret)
+				kfree(dprm);
+			else {
+				f->fn = t->fetch[FETCH_MTD_deref];
+				f->data = (void *)dprm;
+			}
+		}
+		break;
+	}
+	if (!ret && !f->fn) {	/* Parsed, but do not find fetch method */
+		pr_info("%s type has no corresponding fetch method.\n", t->name);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+#define BYTES_TO_BITS(nb)	((BITS_PER_LONG * (nb)) / sizeof(long))
+
+/* Bitfield type needs to be parsed into a fetch function */
+static int __parse_bitfield_probe_arg(const char *bf,
+				      const struct fetch_type *t,
+				      struct fetch_param *f)
+{
+	struct bitfield_fetch_param *bprm;
+	unsigned long bw, bo;
+	char *tail;
+
+	if (*bf != 'b')
+		return 0;
+
+	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
+	if (!bprm)
+		return -ENOMEM;
+
+	bprm->orig = *f;
+	f->fn = t->fetch[FETCH_MTD_bitfield];
+	f->data = (void *)bprm;
+	bw = simple_strtoul(bf + 1, &tail, 0);	/* Use simple one */
+
+	if (bw == 0 || *tail != '@')
+		return -EINVAL;
+
+	bf = tail + 1;
+	bo = simple_strtoul(bf, &tail, 0);
+
+	if (tail == bf || *tail != '/')
+		return -EINVAL;
+
+	bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);
+	bprm->low_shift = bprm->hi_shift + bo;
+
+	return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
+}
+
+/* String length checking wrapper */
+int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
+		struct probe_arg *parg, bool is_return, bool is_kprobe)
+{
+	const char *t;
+	int ret;
+
+	if (strlen(arg) > MAX_ARGSTR_LEN) {
+		pr_info("Argument is too long.: %s\n",  arg);
+		return -ENOSPC;
+	}
+	parg->comm = kstrdup(arg, GFP_KERNEL);
+	if (!parg->comm) {
+		pr_info("Failed to allocate memory for command '%s'.\n", arg);
+		return -ENOMEM;
+	}
+	t = strchr(parg->comm, ':');
+	if (t) {
+		arg[t - parg->comm] = '\0';
+		t++;
+	}
+	parg->type = find_fetch_type(t);
+	if (!parg->type) {
+		pr_info("Unsupported type: %s\n", t);
+		return -EINVAL;
+	}
+	parg->offset = *size;
+	*size += parg->type->size;
+	ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, is_kprobe);
+
+	if (ret >= 0 && t != NULL)
+		ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
+
+	if (ret >= 0) {
+		parg->fetch_size.fn = get_fetch_size_function(parg->type,
+							      parg->fetch.fn);
+		parg->fetch_size.data = parg->fetch.data;
+	}
+
+	return ret;
+}
+
+/* Return 1 if name is reserved or already used by another argument */
+int traceprobe_conflict_field_name(const char *name,
+			       struct probe_arg *args, int narg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++)
+		if (strcmp(reserved_field_names[i], name) == 0)
+			return 1;
+
+	for (i = 0; i < narg; i++)
+		if (strcmp(args[i].name, name) == 0)
+			return 1;
+
+	return 0;
+}
+
+void traceprobe_update_arg(struct probe_arg *arg)
+{
+	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
+		update_bitfield_fetch_param(arg->fetch.data);
+	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
+		update_deref_fetch_param(arg->fetch.data);
+	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
+		update_symbol_cache(arg->fetch.data);
+}
+
+void traceprobe_free_probe_arg(struct probe_arg *arg)
+{
+	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
+		free_bitfield_fetch_param(arg->fetch.data);
+	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
+		free_deref_fetch_param(arg->fetch.data);
+	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
+		free_symbol_cache(arg->fetch.data);
+
+	kfree(arg->name);
+	kfree(arg->comm);
+}
+
+int traceprobe_command(const char *buf, int (*createfn)(int, char **))
+{
+	char **argv;
+	int argc, ret;
+
+	argc = 0;
+	ret = 0;
+	argv = argv_split(GFP_KERNEL, buf, &argc);
+	if (!argv)
+		return -ENOMEM;
+
+	if (argc)
+		ret = createfn(argc, argv);
+
+	argv_free(argv);
+
+	return ret;
+}
+
+#define WRITE_BUFSIZE  4096
+
+ssize_t traceprobe_probes_write(struct file *file, const char __user *buffer,
+				size_t count, loff_t *ppos,
+				int (*createfn)(int, char **))
+{
+	char *kbuf, *tmp;
+	int ret = 0;
+	size_t done = 0;
+	size_t size;
+
+	kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL);
+	if (!kbuf)
+		return -ENOMEM;
+
+	while (done < count) {
+		size = count - done;
+
+		if (size >= WRITE_BUFSIZE)
+			size = WRITE_BUFSIZE - 1;
+
+		if (copy_from_user(kbuf, buffer + done, size)) {
+			ret = -EFAULT;
+			goto out;
+		}
+		kbuf[size] = '\0';
+		tmp = strchr(kbuf, '\n');
+
+		if (tmp) {
+			*tmp = '\0';
+			size = tmp - kbuf + 1;
+		} else if (done + size < count) {
+			pr_warning("Line length is too long: "
+				   "Should be less than %d.", WRITE_BUFSIZE);
+			ret = -EINVAL;
+			goto out;
+		}
+		done += size;
+		/* Remove comments */
+		tmp = strchr(kbuf, '#');
+
+		if (tmp)
+			*tmp = '\0';
+
+		ret = traceprobe_command(kbuf, createfn);
+		if (ret)
+			goto out;
+	}
+	ret = done;
+
+out:
+	kfree(kbuf);
+
+	return ret;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
new file mode 100644
index 0000000..9337086
--- /dev/null
+++ b/kernel/trace/trace_probe.h
@@ -0,0 +1,161 @@
+/*
+ * Common header file for probe-based Dynamic events.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This code was copied from kernel/trace/trace_kprobe.h written by
+ * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+ *
+ * Updates to make this generic:
+ * Copyright (C) IBM Corporation, 2010-2011
+ * Author:     Srikar Dronamraju
+ */
+
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ptrace.h>
+#include <linux/perf_event.h>
+#include <linux/kprobes.h>
+#include <linux/stringify.h>
+#include <linux/limits.h>
+#include <linux/uaccess.h>
+#include <asm/bitsperlong.h>
+
+#include "trace.h"
+#include "trace_output.h"
+
+#define MAX_TRACE_ARGS		128
+#define MAX_ARGSTR_LEN		63
+#define MAX_EVENT_NAME_LEN	64
+#define MAX_STRING_SIZE		PATH_MAX
+
+/* Reserved field names */
+#define FIELD_STRING_IP		"__probe_ip"
+#define FIELD_STRING_RETIP	"__probe_ret_ip"
+#define FIELD_STRING_FUNC	"__probe_func"
+
+#undef DEFINE_FIELD
+#define DEFINE_FIELD(type, item, name, is_signed)			\
+	do {								\
+		ret = trace_define_field(event_call, #type, name,	\
+					 offsetof(typeof(field), item),	\
+					 sizeof(field.item), is_signed, \
+					 FILTER_OTHER);			\
+		if (ret)						\
+			return ret;					\
+	} while (0)
+
+
+/* Flags for trace_probe */
+#define TP_FLAG_TRACE		1
+#define TP_FLAG_PROFILE		2
+#define TP_FLAG_REGISTERED	4
+#define TP_FLAG_UPROBE		8
+
+
+/* data_rloc: data relative location, compatible with u32 */
+#define make_data_rloc(len, roffs)	\
+	(((u32)(len) << 16) | ((u32)(roffs) & 0xffff))
+#define get_rloc_len(dl)		((u32)(dl) >> 16)
+#define get_rloc_offs(dl)		((u32)(dl) & 0xffff)
+
+/*
+ * Convert data_rloc to data_loc:
+ *  data_rloc stores the offset from data_rloc itself, but data_loc
+ *  stores the offset from event entry.
+ */
+#define convert_rloc_to_loc(dl, offs)	((u32)(dl) + (offs))
+
+/* Data fetch function type */
+typedef	void (*fetch_func_t)(struct pt_regs *, void *, void *);
+/* Printing function type */
+typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *, void *);
+
+/* Fetch types */
+enum {
+	FETCH_MTD_reg = 0,
+	FETCH_MTD_stack,
+	FETCH_MTD_retval,
+	FETCH_MTD_memory,
+	FETCH_MTD_symbol,
+	FETCH_MTD_deref,
+	FETCH_MTD_bitfield,
+	FETCH_MTD_END,
+};
+
+/* Fetch type information table */
+struct fetch_type {
+	const char		*name;		/* Name of type */
+	size_t			size;		/* Byte size of type */
+	int			is_signed;	/* Signed flag */
+	print_type_func_t	print;		/* Print functions */
+	const char		*fmt;		/* Fromat string */
+	const char		*fmttype;	/* Name in format file */
+	/* Fetch functions */
+	fetch_func_t		fetch[FETCH_MTD_END];
+};
+
+struct fetch_param {
+	fetch_func_t		fn;
+	void 			*data;
+};
+
+struct probe_arg {
+	struct fetch_param	fetch;
+	struct fetch_param	fetch_size;
+	unsigned int		offset;	/* Offset from argument entry */
+	const char		*name;	/* Name of this argument */
+	const char		*comm;	/* Command of this argument */
+	const struct fetch_type	*type;	/* Type of this argument */
+};
+
+static inline __kprobes void call_fetch(struct fetch_param *fprm,
+				 struct pt_regs *regs, void *dest)
+{
+	return fprm->fn(regs, fprm->data, dest);
+}
+
+/* Check the name is good for event/group/fields */
+static inline int is_good_name(const char *name)
+{
+	if (!isalpha(*name) && *name != '_')
+		return 0;
+	while (*++name != '\0') {
+		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
+			return 0;
+	}
+	return 1;
+}
+
+extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
+		   struct probe_arg *parg, bool is_return, bool is_kprobe);
+
+extern int traceprobe_conflict_field_name(const char *name,
+			       struct probe_arg *args, int narg);
+
+extern void traceprobe_update_arg(struct probe_arg *arg);
+extern void traceprobe_free_probe_arg(struct probe_arg *arg);
+
+extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset);
+
+extern ssize_t traceprobe_probes_write(struct file *file,
+		const char __user *buffer, size_t count, loff_t *ppos,
+		int (*createfn)(int, char**));
+
+extern int traceprobe_command(const char *buf, int (*createfn)(int, char**));
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
new file mode 100644
index 0000000..2b36ac6
--- /dev/null
+++ b/kernel/trace/trace_uprobe.c
@@ -0,0 +1,788 @@
+/*
+ * uprobes-based tracing events
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Copyright (C) IBM Corporation, 2010-2012
+ * Author:	Srikar Dronamraju <srikar@linux.vnet.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/uprobes.h>
+#include <linux/namei.h>
+
+#include "trace_probe.h"
+
+#define UPROBE_EVENT_SYSTEM	"uprobes"
+
+/*
+ * uprobe event core functions
+ */
+struct trace_uprobe;
+struct uprobe_trace_consumer {
+	struct uprobe_consumer		cons;
+	struct trace_uprobe		*tu;
+};
+
+struct trace_uprobe {
+	struct list_head		list;
+	struct ftrace_event_class	class;
+	struct ftrace_event_call	call;
+	struct uprobe_trace_consumer	*consumer;
+	struct inode			*inode;
+	char				*filename;
+	unsigned long			offset;
+	unsigned long			nhit;
+	unsigned int			flags;	/* For TP_FLAG_* */
+	ssize_t				size;	/* trace entry size */
+	unsigned int			nr_args;
+	struct probe_arg		args[];
+};
+
+#define SIZEOF_TRACE_UPROBE(n)			\
+	(offsetof(struct trace_uprobe, args) +	\
+	(sizeof(struct probe_arg) * (n)))
+
+static int register_uprobe_event(struct trace_uprobe *tu);
+static void unregister_uprobe_event(struct trace_uprobe *tu);
+
+static DEFINE_MUTEX(uprobe_lock);
+static LIST_HEAD(uprobe_list);
+
+static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs);
+
+/*
+ * Allocate new trace_uprobe and initialize it (including uprobes).
+ */
+static struct trace_uprobe *
+alloc_trace_uprobe(const char *group, const char *event, int nargs)
+{
+	struct trace_uprobe *tu;
+
+	if (!event || !is_good_name(event))
+		return ERR_PTR(-EINVAL);
+
+	if (!group || !is_good_name(group))
+		return ERR_PTR(-EINVAL);
+
+	tu = kzalloc(SIZEOF_TRACE_UPROBE(nargs), GFP_KERNEL);
+	if (!tu)
+		return ERR_PTR(-ENOMEM);
+
+	tu->call.class = &tu->class;
+	tu->call.name = kstrdup(event, GFP_KERNEL);
+	if (!tu->call.name)
+		goto error;
+
+	tu->class.system = kstrdup(group, GFP_KERNEL);
+	if (!tu->class.system)
+		goto error;
+
+	INIT_LIST_HEAD(&tu->list);
+	return tu;
+
+error:
+	kfree(tu->call.name);
+	kfree(tu);
+
+	return ERR_PTR(-ENOMEM);
+}
+
+static void free_trace_uprobe(struct trace_uprobe *tu)
+{
+	int i;
+
+	for (i = 0; i < tu->nr_args; i++)
+		traceprobe_free_probe_arg(&tu->args[i]);
+
+	iput(tu->inode);
+	kfree(tu->call.class->system);
+	kfree(tu->call.name);
+	kfree(tu->filename);
+	kfree(tu);
+}
+
+static struct trace_uprobe *find_probe_event(const char *event, const char *group)
+{
+	struct trace_uprobe *tu;
+
+	list_for_each_entry(tu, &uprobe_list, list)
+		if (strcmp(tu->call.name, event) == 0 &&
+		    strcmp(tu->call.class->system, group) == 0)
+			return tu;
+
+	return NULL;
+}
+
+/* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */
+static void unregister_trace_uprobe(struct trace_uprobe *tu)
+{
+	list_del(&tu->list);
+	unregister_uprobe_event(tu);
+	free_trace_uprobe(tu);
+}
+
+/* Register a trace_uprobe and probe_event */
+static int register_trace_uprobe(struct trace_uprobe *tu)
+{
+	struct trace_uprobe *old_tp;
+	int ret;
+
+	mutex_lock(&uprobe_lock);
+
+	/* register as an event */
+	old_tp = find_probe_event(tu->call.name, tu->call.class->system);
+	if (old_tp)
+		/* delete old event */
+		unregister_trace_uprobe(old_tp);
+
+	ret = register_uprobe_event(tu);
+	if (ret) {
+		pr_warning("Failed to register probe event(%d)\n", ret);
+		goto end;
+	}
+
+	list_add_tail(&tu->list, &uprobe_list);
+
+end:
+	mutex_unlock(&uprobe_lock);
+
+	return ret;
+}
+
+/*
+ * Argument syntax:
+ *  - Add uprobe: p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS]
+ *
+ *  - Remove uprobe: -:[GRP/]EVENT
+ */
+static int create_trace_uprobe(int argc, char **argv)
+{
+	struct trace_uprobe *tu;
+	struct inode *inode;
+	char *arg, *event, *group, *filename;
+	char buf[MAX_EVENT_NAME_LEN];
+	struct path path;
+	unsigned long offset;
+	bool is_delete;
+	int i, ret;
+
+	inode = NULL;
+	ret = 0;
+	is_delete = false;
+	event = NULL;
+	group = NULL;
+
+	/* argc must be >= 1 */
+	if (argv[0][0] == '-')
+		is_delete = true;
+	else if (argv[0][0] != 'p') {
+		pr_info("Probe definition must be started with 'p', 'r' or" " '-'.\n");
+		return -EINVAL;
+	}
+
+	if (argv[0][1] == ':') {
+		event = &argv[0][2];
+		arg = strchr(event, '/');
+
+		if (arg) {
+			group = event;
+			event = arg + 1;
+			event[-1] = '\0';
+
+			if (strlen(group) == 0) {
+				pr_info("Group name is not specified\n");
+				return -EINVAL;
+			}
+		}
+		if (strlen(event) == 0) {
+			pr_info("Event name is not specified\n");
+			return -EINVAL;
+		}
+	}
+	if (!group)
+		group = UPROBE_EVENT_SYSTEM;
+
+	if (is_delete) {
+		if (!event) {
+			pr_info("Delete command needs an event name.\n");
+			return -EINVAL;
+		}
+		mutex_lock(&uprobe_lock);
+		tu = find_probe_event(event, group);
+
+		if (!tu) {
+			mutex_unlock(&uprobe_lock);
+			pr_info("Event %s/%s doesn't exist.\n", group, event);
+			return -ENOENT;
+		}
+		/* delete an event */
+		unregister_trace_uprobe(tu);
+		mutex_unlock(&uprobe_lock);
+		return 0;
+	}
+
+	if (argc < 2) {
+		pr_info("Probe point is not specified.\n");
+		return -EINVAL;
+	}
+	if (isdigit(argv[1][0])) {
+		pr_info("probe point must be have a filename.\n");
+		return -EINVAL;
+	}
+	arg = strchr(argv[1], ':');
+	if (!arg)
+		goto fail_address_parse;
+
+	*arg++ = '\0';
+	filename = argv[1];
+	ret = kern_path(filename, LOOKUP_FOLLOW, &path);
+	if (ret)
+		goto fail_address_parse;
+
+	ret = strict_strtoul(arg, 0, &offset);
+	if (ret)
+		goto fail_address_parse;
+
+	inode = igrab(path.dentry->d_inode);
+
+	argc -= 2;
+	argv += 2;
+
+	/* setup a probe */
+	if (!event) {
+		char *tail = strrchr(filename, '/');
+		char *ptr;
+
+		ptr = kstrdup((tail ? tail + 1 : filename), GFP_KERNEL);
+		if (!ptr) {
+			ret = -ENOMEM;
+			goto fail_address_parse;
+		}
+
+		tail = ptr;
+		ptr = strpbrk(tail, ".-_");
+		if (ptr)
+			*ptr = '\0';
+
+		snprintf(buf, MAX_EVENT_NAME_LEN, "%c_%s_0x%lx", 'p', tail, offset);
+		event = buf;
+		kfree(tail);
+	}
+
+	tu = alloc_trace_uprobe(group, event, argc);
+	if (IS_ERR(tu)) {
+		pr_info("Failed to allocate trace_uprobe.(%d)\n", (int)PTR_ERR(tu));
+		ret = PTR_ERR(tu);
+		goto fail_address_parse;
+	}
+	tu->offset = offset;
+	tu->inode = inode;
+	tu->filename = kstrdup(filename, GFP_KERNEL);
+
+	if (!tu->filename) {
+		pr_info("Failed to allocate filename.\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	/* parse arguments */
+	ret = 0;
+	for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
+		/* Increment count for freeing args in error case */
+		tu->nr_args++;
+
+		/* Parse argument name */
+		arg = strchr(argv[i], '=');
+		if (arg) {
+			*arg++ = '\0';
+			tu->args[i].name = kstrdup(argv[i], GFP_KERNEL);
+		} else {
+			arg = argv[i];
+			/* If argument name is omitted, set "argN" */
+			snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1);
+			tu->args[i].name = kstrdup(buf, GFP_KERNEL);
+		}
+
+		if (!tu->args[i].name) {
+			pr_info("Failed to allocate argument[%d] name.\n", i);
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		if (!is_good_name(tu->args[i].name)) {
+			pr_info("Invalid argument[%d] name: %s\n", i, tu->args[i].name);
+			ret = -EINVAL;
+			goto error;
+		}
+
+		if (traceprobe_conflict_field_name(tu->args[i].name, tu->args, i)) {
+			pr_info("Argument[%d] name '%s' conflicts with "
+				"another field.\n", i, argv[i]);
+			ret = -EINVAL;
+			goto error;
+		}
+
+		/* Parse fetch argument */
+		ret = traceprobe_parse_probe_arg(arg, &tu->size, &tu->args[i], false, false);
+		if (ret) {
+			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
+			goto error;
+		}
+	}
+
+	ret = register_trace_uprobe(tu);
+	if (ret)
+		goto error;
+	return 0;
+
+error:
+	free_trace_uprobe(tu);
+	return ret;
+
+fail_address_parse:
+	if (inode)
+		iput(inode);
+
+	pr_info("Failed to parse address.\n");
+
+	return ret;
+}
+
+static void cleanup_all_probes(void)
+{
+	struct trace_uprobe *tu;
+
+	mutex_lock(&uprobe_lock);
+	while (!list_empty(&uprobe_list)) {
+		tu = list_entry(uprobe_list.next, struct trace_uprobe, list);
+		unregister_trace_uprobe(tu);
+	}
+	mutex_unlock(&uprobe_lock);
+}
+
+/* Probes listing interfaces */
+static void *probes_seq_start(struct seq_file *m, loff_t *pos)
+{
+	mutex_lock(&uprobe_lock);
+	return seq_list_start(&uprobe_list, *pos);
+}
+
+static void *probes_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	return seq_list_next(v, &uprobe_list, pos);
+}
+
+static void probes_seq_stop(struct seq_file *m, void *v)
+{
+	mutex_unlock(&uprobe_lock);
+}
+
+static int probes_seq_show(struct seq_file *m, void *v)
+{
+	struct trace_uprobe *tu = v;
+	int i;
+
+	seq_printf(m, "p:%s/%s", tu->call.class->system, tu->call.name);
+	seq_printf(m, " %s:0x%p", tu->filename, (void *)tu->offset);
+
+	for (i = 0; i < tu->nr_args; i++)
+		seq_printf(m, " %s=%s", tu->args[i].name, tu->args[i].comm);
+
+	seq_printf(m, "\n");
+	return 0;
+}
+
+static const struct seq_operations probes_seq_op = {
+	.start	= probes_seq_start,
+	.next	= probes_seq_next,
+	.stop	= probes_seq_stop,
+	.show	= probes_seq_show
+};
+
+static int probes_open(struct inode *inode, struct file *file)
+{
+	if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC))
+		cleanup_all_probes();
+
+	return seq_open(file, &probes_seq_op);
+}
+
+static ssize_t probes_write(struct file *file, const char __user *buffer,
+			    size_t count, loff_t *ppos)
+{
+	return traceprobe_probes_write(file, buffer, count, ppos, create_trace_uprobe);
+}
+
+static const struct file_operations uprobe_events_ops = {
+	.owner		= THIS_MODULE,
+	.open		= probes_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+	.write		= probes_write,
+};
+
+/* Probes profiling interfaces */
+static int probes_profile_seq_show(struct seq_file *m, void *v)
+{
+	struct trace_uprobe *tu = v;
+
+	seq_printf(m, "  %s %-44s %15lu\n", tu->filename, tu->call.name, tu->nhit);
+	return 0;
+}
+
+static const struct seq_operations profile_seq_op = {
+	.start	= probes_seq_start,
+	.next	= probes_seq_next,
+	.stop	= probes_seq_stop,
+	.show	= probes_profile_seq_show
+};
+
+static int profile_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &profile_seq_op);
+}
+
+static const struct file_operations uprobe_profile_ops = {
+	.owner		= THIS_MODULE,
+	.open		= profile_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+/* uprobe handler */
+static void uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs)
+{
+	struct uprobe_trace_entry_head *entry;
+	struct ring_buffer_event *event;
+	struct ring_buffer *buffer;
+	u8 *data;
+	int size, i, pc;
+	unsigned long irq_flags;
+	struct ftrace_event_call *call = &tu->call;
+
+	tu->nhit++;
+
+	local_save_flags(irq_flags);
+	pc = preempt_count();
+
+	size = sizeof(*entry) + tu->size;
+
+	event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
+						  size, irq_flags, pc);
+	if (!event)
+		return;
+
+	entry = ring_buffer_event_data(event);
+	entry->ip = uprobe_get_swbp_addr(task_pt_regs(current));
+	data = (u8 *)&entry[1];
+	for (i = 0; i < tu->nr_args; i++)
+		call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
+
+	if (!filter_current_check_discard(buffer, call, entry, event))
+		trace_buffer_unlock_commit(buffer, event, irq_flags, pc);
+}
+
+/* Event entry printers */
+static enum print_line_t
+print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *event)
+{
+	struct uprobe_trace_entry_head *field;
+	struct trace_seq *s = &iter->seq;
+	struct trace_uprobe *tu;
+	u8 *data;
+	int i;
+
+	field = (struct uprobe_trace_entry_head *)iter->ent;
+	tu = container_of(event, struct trace_uprobe, call.event);
+
+	if (!trace_seq_printf(s, "%s: (", tu->call.name))
+		goto partial;
+
+	if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET))
+		goto partial;
+
+	if (!trace_seq_puts(s, ")"))
+		goto partial;
+
+	data = (u8 *)&field[1];
+	for (i = 0; i < tu->nr_args; i++) {
+		if (!tu->args[i].type->print(s, tu->args[i].name,
+					     data + tu->args[i].offset, field))
+			goto partial;
+	}
+
+	if (trace_seq_puts(s, "\n"))
+		return TRACE_TYPE_HANDLED;
+
+partial:
+	return TRACE_TYPE_PARTIAL_LINE;
+}
+
+static int probe_event_enable(struct trace_uprobe *tu, int flag)
+{
+	struct uprobe_trace_consumer *utc;
+	int ret = 0;
+
+	if (!tu->inode || tu->consumer)
+		return -EINTR;
+
+	utc = kzalloc(sizeof(struct uprobe_trace_consumer), GFP_KERNEL);
+	if (!utc)
+		return -EINTR;
+
+	utc->cons.handler = uprobe_dispatcher;
+	utc->cons.filter = NULL;
+	ret = uprobe_register(tu->inode, tu->offset, &utc->cons);
+	if (ret) {
+		kfree(utc);
+		return ret;
+	}
+
+	tu->flags |= flag;
+	utc->tu = tu;
+	tu->consumer = utc;
+
+	return 0;
+}
+
+static void probe_event_disable(struct trace_uprobe *tu, int flag)
+{
+	if (!tu->inode || !tu->consumer)
+		return;
+
+	uprobe_unregister(tu->inode, tu->offset, &tu->consumer->cons);
+	tu->flags &= ~flag;
+	kfree(tu->consumer);
+	tu->consumer = NULL;
+}
+
+static int uprobe_event_define_fields(struct ftrace_event_call *event_call)
+{
+	int ret, i;
+	struct uprobe_trace_entry_head field;
+	struct trace_uprobe *tu = (struct trace_uprobe *)event_call->data;
+
+	DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
+	/* Set argument names as fields */
+	for (i = 0; i < tu->nr_args; i++) {
+		ret = trace_define_field(event_call, tu->args[i].type->fmttype,
+					 tu->args[i].name,
+					 sizeof(field) + tu->args[i].offset,
+					 tu->args[i].type->size,
+					 tu->args[i].type->is_signed,
+					 FILTER_OTHER);
+
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+#define LEN_OR_ZERO		(len ? len - pos : 0)
+static int __set_print_fmt(struct trace_uprobe *tu, char *buf, int len)
+{
+	const char *fmt, *arg;
+	int i;
+	int pos = 0;
+
+	fmt = "(%lx)";
+	arg = "REC->" FIELD_STRING_IP;
+
+	/* When len=0, we just calculate the needed length */
+
+	pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt);
+
+	for (i = 0; i < tu->nr_args; i++) {
+		pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s",
+				tu->args[i].name, tu->args[i].type->fmt);
+	}
+
+	pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg);
+
+	for (i = 0; i < tu->nr_args; i++) {
+		pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s",
+				tu->args[i].name);
+	}
+
+	return pos;	/* return the length of print_fmt */
+}
+#undef LEN_OR_ZERO
+
+static int set_print_fmt(struct trace_uprobe *tu)
+{
+	char *print_fmt;
+	int len;
+
+	/* First: called with 0 length to calculate the needed length */
+	len = __set_print_fmt(tu, NULL, 0);
+	print_fmt = kmalloc(len + 1, GFP_KERNEL);
+	if (!print_fmt)
+		return -ENOMEM;
+
+	/* Second: actually write the @print_fmt */
+	__set_print_fmt(tu, print_fmt, len + 1);
+	tu->call.print_fmt = print_fmt;
+
+	return 0;
+}
+
+#ifdef CONFIG_PERF_EVENTS
+/* uprobe profile handler */
+static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
+{
+	struct ftrace_event_call *call = &tu->call;
+	struct uprobe_trace_entry_head *entry;
+	struct hlist_head *head;
+	u8 *data;
+	int size, __size, i;
+	int rctx;
+
+	__size = sizeof(*entry) + tu->size;
+	size = ALIGN(__size + sizeof(u32), sizeof(u64));
+	size -= sizeof(u32);
+	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
+		return;
+
+	preempt_disable();
+
+	entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
+	if (!entry)
+		goto out;
+
+	entry->ip = uprobe_get_swbp_addr(task_pt_regs(current));
+	data = (u8 *)&entry[1];
+	for (i = 0; i < tu->nr_args; i++)
+		call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
+
+	head = this_cpu_ptr(call->perf_events);
+	perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
+
+ out:
+	preempt_enable();
+}
+#endif	/* CONFIG_PERF_EVENTS */
+
+static
+int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, void *data)
+{
+	struct trace_uprobe *tu = (struct trace_uprobe *)event->data;
+
+	switch (type) {
+	case TRACE_REG_REGISTER:
+		return probe_event_enable(tu, TP_FLAG_TRACE);
+
+	case TRACE_REG_UNREGISTER:
+		probe_event_disable(tu, TP_FLAG_TRACE);
+		return 0;
+
+#ifdef CONFIG_PERF_EVENTS
+	case TRACE_REG_PERF_REGISTER:
+		return probe_event_enable(tu, TP_FLAG_PROFILE);
+
+	case TRACE_REG_PERF_UNREGISTER:
+		probe_event_disable(tu, TP_FLAG_PROFILE);
+		return 0;
+#endif
+	default:
+		return 0;
+	}
+	return 0;
+}
+
+static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
+{
+	struct uprobe_trace_consumer *utc;
+	struct trace_uprobe *tu;
+
+	utc = container_of(con, struct uprobe_trace_consumer, cons);
+	tu = utc->tu;
+	if (!tu || tu->consumer != utc)
+		return 0;
+
+	if (tu->flags & TP_FLAG_TRACE)
+		uprobe_trace_func(tu, regs);
+
+#ifdef CONFIG_PERF_EVENTS
+	if (tu->flags & TP_FLAG_PROFILE)
+		uprobe_perf_func(tu, regs);
+#endif
+	return 0;
+}
+
+static struct trace_event_functions uprobe_funcs = {
+	.trace		= print_uprobe_event
+};
+
+static int register_uprobe_event(struct trace_uprobe *tu)
+{
+	struct ftrace_event_call *call = &tu->call;
+	int ret;
+
+	/* Initialize ftrace_event_call */
+	INIT_LIST_HEAD(&call->class->fields);
+	call->event.funcs = &uprobe_funcs;
+	call->class->define_fields = uprobe_event_define_fields;
+
+	if (set_print_fmt(tu) < 0)
+		return -ENOMEM;
+
+	ret = register_ftrace_event(&call->event);
+	if (!ret) {
+		kfree(call->print_fmt);
+		return -ENODEV;
+	}
+	call->flags = 0;
+	call->class->reg = trace_uprobe_register;
+	call->data = tu;
+	ret = trace_add_event_call(call);
+
+	if (ret) {
+		pr_info("Failed to register uprobe event: %s\n", call->name);
+		kfree(call->print_fmt);
+		unregister_ftrace_event(&call->event);
+	}
+
+	return ret;
+}
+
+static void unregister_uprobe_event(struct trace_uprobe *tu)
+{
+	/* tu->event is unregistered in trace_remove_event_call() */
+	trace_remove_event_call(&tu->call);
+	kfree(tu->call.print_fmt);
+	tu->call.print_fmt = NULL;
+}
+
+/* Make a trace interface for controling probe points */
+static __init int init_uprobe_trace(void)
+{
+	struct dentry *d_tracer;
+
+	d_tracer = tracing_init_dentry();
+	if (!d_tracer)
+		return 0;
+
+	trace_create_file("uprobe_events", 0644, d_tracer,
+				    NULL, &uprobe_events_ops);
+	/* Profile interface */
+	trace_create_file("uprobe_profile", 0444, d_tracer,
+				    NULL, &uprobe_profile_ops);
+	return 0;
+}
+
+fs_initcall(init_uprobe_trace);
diff --git a/kernel/trace/trace_workqueue.c b/kernel/trace/trace_workqueue.c
deleted file mode 100644
index 209b379..0000000
--- a/kernel/trace/trace_workqueue.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Workqueue statistical tracer.
- *
- * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
- *
- */
-
-
-#include <trace/events/workqueue.h>
-#include <linux/list.h>
-#include <linux/percpu.h>
-#include <linux/slab.h>
-#include <linux/kref.h>
-#include "trace_stat.h"
-#include "trace.h"
-
-
-/* A cpu workqueue thread */
-struct cpu_workqueue_stats {
-	struct list_head            list;
-	struct kref                 kref;
-	int		            cpu;
-	pid_t			    pid;
-/* Can be inserted from interrupt or user context, need to be atomic */
-	atomic_t	            inserted;
-/*
- *  Don't need to be atomic, works are serialized in a single workqueue thread
- *  on a single CPU.
- */
-	unsigned int		    executed;
-};
-
-/* List of workqueue threads on one cpu */
-struct workqueue_global_stats {
-	struct list_head	list;
-	spinlock_t		lock;
-};
-
-/* Don't need a global lock because allocated before the workqueues, and
- * never freed.
- */
-static DEFINE_PER_CPU(struct workqueue_global_stats, all_workqueue_stat);
-#define workqueue_cpu_stat(cpu) (&per_cpu(all_workqueue_stat, cpu))
-
-static void cpu_workqueue_stat_free(struct kref *kref)
-{
-	kfree(container_of(kref, struct cpu_workqueue_stats, kref));
-}
-
-/* Insertion of a work */
-static void
-probe_workqueue_insertion(void *ignore,
-			  struct task_struct *wq_thread,
-			  struct work_struct *work)
-{
-	int cpu = cpumask_first(&wq_thread->cpus_allowed);
-	struct cpu_workqueue_stats *node;
-	unsigned long flags;
-
-	spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-	list_for_each_entry(node, &workqueue_cpu_stat(cpu)->list, list) {
-		if (node->pid == wq_thread->pid) {
-			atomic_inc(&node->inserted);
-			goto found;
-		}
-	}
-	pr_debug("trace_workqueue: entry not found\n");
-found:
-	spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-}
-
-/* Execution of a work */
-static void
-probe_workqueue_execution(void *ignore,
-			  struct task_struct *wq_thread,
-			  struct work_struct *work)
-{
-	int cpu = cpumask_first(&wq_thread->cpus_allowed);
-	struct cpu_workqueue_stats *node;
-	unsigned long flags;
-
-	spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-	list_for_each_entry(node, &workqueue_cpu_stat(cpu)->list, list) {
-		if (node->pid == wq_thread->pid) {
-			node->executed++;
-			goto found;
-		}
-	}
-	pr_debug("trace_workqueue: entry not found\n");
-found:
-	spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-}
-
-/* Creation of a cpu workqueue thread */
-static void probe_workqueue_creation(void *ignore,
-				     struct task_struct *wq_thread, int cpu)
-{
-	struct cpu_workqueue_stats *cws;
-	unsigned long flags;
-
-	WARN_ON(cpu < 0);
-
-	/* Workqueues are sometimes created in atomic context */
-	cws = kzalloc(sizeof(struct cpu_workqueue_stats), GFP_ATOMIC);
-	if (!cws) {
-		pr_warning("trace_workqueue: not enough memory\n");
-		return;
-	}
-	INIT_LIST_HEAD(&cws->list);
-	kref_init(&cws->kref);
-	cws->cpu = cpu;
-	cws->pid = wq_thread->pid;
-
-	spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-	list_add_tail(&cws->list, &workqueue_cpu_stat(cpu)->list);
-	spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-}
-
-/* Destruction of a cpu workqueue thread */
-static void
-probe_workqueue_destruction(void *ignore, struct task_struct *wq_thread)
-{
-	/* Workqueue only execute on one cpu */
-	int cpu = cpumask_first(&wq_thread->cpus_allowed);
-	struct cpu_workqueue_stats *node, *next;
-	unsigned long flags;
-
-	spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-	list_for_each_entry_safe(node, next, &workqueue_cpu_stat(cpu)->list,
-							list) {
-		if (node->pid == wq_thread->pid) {
-			list_del(&node->list);
-			kref_put(&node->kref, cpu_workqueue_stat_free);
-			goto found;
-		}
-	}
-
-	pr_debug("trace_workqueue: don't find workqueue to destroy\n");
-found:
-	spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-
-}
-
-static struct cpu_workqueue_stats *workqueue_stat_start_cpu(int cpu)
-{
-	unsigned long flags;
-	struct cpu_workqueue_stats *ret = NULL;
-
-
-	spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-
-	if (!list_empty(&workqueue_cpu_stat(cpu)->list)) {
-		ret = list_entry(workqueue_cpu_stat(cpu)->list.next,
-				 struct cpu_workqueue_stats, list);
-		kref_get(&ret->kref);
-	}
-
-	spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-
-	return ret;
-}
-
-static void *workqueue_stat_start(struct tracer_stat *trace)
-{
-	int cpu;
-	void *ret = NULL;
-
-	for_each_possible_cpu(cpu) {
-		ret = workqueue_stat_start_cpu(cpu);
-		if (ret)
-			return ret;
-	}
-	return NULL;
-}
-
-static void *workqueue_stat_next(void *prev, int idx)
-{
-	struct cpu_workqueue_stats *prev_cws = prev;
-	struct cpu_workqueue_stats *ret;
-	int cpu = prev_cws->cpu;
-	unsigned long flags;
-
-	spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-	if (list_is_last(&prev_cws->list, &workqueue_cpu_stat(cpu)->list)) {
-		spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-		do {
-			cpu = cpumask_next(cpu, cpu_possible_mask);
-			if (cpu >= nr_cpu_ids)
-				return NULL;
-		} while (!(ret = workqueue_stat_start_cpu(cpu)));
-		return ret;
-	} else {
-		ret = list_entry(prev_cws->list.next,
-				 struct cpu_workqueue_stats, list);
-		kref_get(&ret->kref);
-	}
-	spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-
-	return ret;
-}
-
-static int workqueue_stat_show(struct seq_file *s, void *p)
-{
-	struct cpu_workqueue_stats *cws = p;
-	struct pid *pid;
-	struct task_struct *tsk;
-
-	pid = find_get_pid(cws->pid);
-	if (pid) {
-		tsk = get_pid_task(pid, PIDTYPE_PID);
-		if (tsk) {
-			seq_printf(s, "%3d %6d     %6u       %s\n", cws->cpu,
-				   atomic_read(&cws->inserted), cws->executed,
-				   tsk->comm);
-			put_task_struct(tsk);
-		}
-		put_pid(pid);
-	}
-
-	return 0;
-}
-
-static void workqueue_stat_release(void *stat)
-{
-	struct cpu_workqueue_stats *node = stat;
-
-	kref_put(&node->kref, cpu_workqueue_stat_free);
-}
-
-static int workqueue_stat_headers(struct seq_file *s)
-{
-	seq_printf(s, "# CPU  INSERTED  EXECUTED   NAME\n");
-	seq_printf(s, "# |      |         |          |\n");
-	return 0;
-}
-
-struct tracer_stat workqueue_stats __read_mostly = {
-	.name = "workqueues",
-	.stat_start = workqueue_stat_start,
-	.stat_next = workqueue_stat_next,
-	.stat_show = workqueue_stat_show,
-	.stat_release = workqueue_stat_release,
-	.stat_headers = workqueue_stat_headers
-};
-
-
-int __init stat_workqueue_init(void)
-{
-	if (register_stat_tracer(&workqueue_stats)) {
-		pr_warning("Unable to register workqueue stat tracer\n");
-		return 1;
-	}
-
-	return 0;
-}
-fs_initcall(stat_workqueue_init);
-
-/*
- * Workqueues are created very early, just after pre-smp initcalls.
- * So we must register our tracepoints at this stage.
- */
-int __init trace_workqueue_early_init(void)
-{
-	int ret, cpu;
-
-	for_each_possible_cpu(cpu) {
-		spin_lock_init(&workqueue_cpu_stat(cpu)->lock);
-		INIT_LIST_HEAD(&workqueue_cpu_stat(cpu)->list);
-	}
-
-	ret = register_trace_workqueue_insertion(probe_workqueue_insertion, NULL);
-	if (ret)
-		goto out;
-
-	ret = register_trace_workqueue_execution(probe_workqueue_execution, NULL);
-	if (ret)
-		goto no_insertion;
-
-	ret = register_trace_workqueue_creation(probe_workqueue_creation, NULL);
-	if (ret)
-		goto no_execution;
-
-	ret = register_trace_workqueue_destruction(probe_workqueue_destruction, NULL);
-	if (ret)
-		goto no_creation;
-
-	return 0;
-
-no_creation:
-	unregister_trace_workqueue_creation(probe_workqueue_creation, NULL);
-no_execution:
-	unregister_trace_workqueue_execution(probe_workqueue_execution, NULL);
-no_insertion:
-	unregister_trace_workqueue_insertion(probe_workqueue_insertion, NULL);
-out:
-	pr_warning("trace_workqueue: unable to trace workqueues\n");
-
-	return 1;
-}
-early_initcall(trace_workqueue_early_init);
diff --git a/kernel/uid16.c b/kernel/uid16.c
index 51c6e89..d7948eb 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -81,14 +81,19 @@
 	return ret;
 }
 
-SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruid, old_uid_t __user *, euid, old_uid_t __user *, suid)
+SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruidp, old_uid_t __user *, euidp, old_uid_t __user *, suidp)
 {
 	const struct cred *cred = current_cred();
 	int retval;
+	old_uid_t ruid, euid, suid;
 
-	if (!(retval   = put_user(high2lowuid(cred->uid),  ruid)) &&
-	    !(retval   = put_user(high2lowuid(cred->euid), euid)))
-		retval = put_user(high2lowuid(cred->suid), suid);
+	ruid = high2lowuid(from_kuid_munged(cred->user_ns, cred->uid));
+	euid = high2lowuid(from_kuid_munged(cred->user_ns, cred->euid));
+	suid = high2lowuid(from_kuid_munged(cred->user_ns, cred->suid));
+
+	if (!(retval   = put_user(ruid, ruidp)) &&
+	    !(retval   = put_user(euid, euidp)))
+		retval = put_user(suid, suidp);
 
 	return retval;
 }
@@ -103,14 +108,19 @@
 }
 
 
-SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgid, old_gid_t __user *, egid, old_gid_t __user *, sgid)
+SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgidp, old_gid_t __user *, egidp, old_gid_t __user *, sgidp)
 {
 	const struct cred *cred = current_cred();
 	int retval;
+	old_gid_t rgid, egid, sgid;
 
-	if (!(retval   = put_user(high2lowgid(cred->gid),  rgid)) &&
-	    !(retval   = put_user(high2lowgid(cred->egid), egid)))
-		retval = put_user(high2lowgid(cred->sgid), sgid);
+	rgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->gid));
+	egid = high2lowgid(from_kgid_munged(cred->user_ns, cred->egid));
+	sgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->sgid));
+
+	if (!(retval   = put_user(rgid, rgidp)) &&
+	    !(retval   = put_user(egid, egidp)))
+		retval = put_user(sgid, sgidp);
 
 	return retval;
 }
@@ -134,11 +144,14 @@
 static int groups16_to_user(old_gid_t __user *grouplist,
     struct group_info *group_info)
 {
+	struct user_namespace *user_ns = current_user_ns();
 	int i;
 	old_gid_t group;
+	kgid_t kgid;
 
 	for (i = 0; i < group_info->ngroups; i++) {
-		group = high2lowgid(GROUP_AT(group_info, i));
+		kgid = GROUP_AT(group_info, i);
+		group = high2lowgid(from_kgid_munged(user_ns, kgid));
 		if (put_user(group, grouplist+i))
 			return -EFAULT;
 	}
@@ -149,13 +162,20 @@
 static int groups16_from_user(struct group_info *group_info,
     old_gid_t __user *grouplist)
 {
+	struct user_namespace *user_ns = current_user_ns();
 	int i;
 	old_gid_t group;
+	kgid_t kgid;
 
 	for (i = 0; i < group_info->ngroups; i++) {
 		if (get_user(group, grouplist+i))
 			return  -EFAULT;
-		GROUP_AT(group_info, i) = low2highgid(group);
+
+		kgid = make_kgid(user_ns, low2highgid(group));
+		if (!gid_valid(kgid))
+			return -EINVAL;
+
+		GROUP_AT(group_info, i) = kgid;
 	}
 
 	return 0;
@@ -211,20 +231,20 @@
 
 SYSCALL_DEFINE0(getuid16)
 {
-	return high2lowuid(current_uid());
+	return high2lowuid(from_kuid_munged(current_user_ns(), current_uid()));
 }
 
 SYSCALL_DEFINE0(geteuid16)
 {
-	return high2lowuid(current_euid());
+	return high2lowuid(from_kuid_munged(current_user_ns(), current_euid()));
 }
 
 SYSCALL_DEFINE0(getgid16)
 {
-	return high2lowgid(current_gid());
+	return high2lowgid(from_kgid_munged(current_user_ns(), current_gid()));
 }
 
 SYSCALL_DEFINE0(getegid16)
 {
-	return high2lowgid(current_egid());
+	return high2lowgid(from_kgid_munged(current_user_ns(), current_egid()));
 }
diff --git a/kernel/user.c b/kernel/user.c
index 71dd236..b815fef 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -22,10 +22,27 @@
  * and 1 for... ?
  */
 struct user_namespace init_user_ns = {
+	.uid_map = {
+		.nr_extents = 1,
+		.extent[0] = {
+			.first = 0,
+			.lower_first = 0,
+			.count = 4294967295U,
+		},
+	},
+	.gid_map = {
+		.nr_extents = 1,
+		.extent[0] = {
+			.first = 0,
+			.lower_first = 0,
+			.count = 4294967295U,
+		},
+	},
 	.kref = {
 		.refcount	= ATOMIC_INIT(3),
 	},
-	.creator = &root_user,
+	.owner = GLOBAL_ROOT_UID,
+	.group = GLOBAL_ROOT_GID,
 };
 EXPORT_SYMBOL_GPL(init_user_ns);
 
@@ -34,11 +51,14 @@
  * when changing user ID's (ie setuid() and friends).
  */
 
+#define UIDHASH_BITS	(CONFIG_BASE_SMALL ? 3 : 7)
+#define UIDHASH_SZ	(1 << UIDHASH_BITS)
 #define UIDHASH_MASK		(UIDHASH_SZ - 1)
 #define __uidhashfn(uid)	(((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
-#define uidhashentry(ns, uid)	((ns)->uidhash_table + __uidhashfn((uid)))
+#define uidhashentry(uid)	(uidhash_table + __uidhashfn((__kuid_val(uid))))
 
 static struct kmem_cache *uid_cachep;
+struct hlist_head uidhash_table[UIDHASH_SZ];
 
 /*
  * The uidhash_lock is mostly taken from process context, but it is
@@ -51,14 +71,14 @@
  */
 static DEFINE_SPINLOCK(uidhash_lock);
 
-/* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->user_ns */
+/* root_user.__count is 1, for init task cred */
 struct user_struct root_user = {
-	.__count	= ATOMIC_INIT(2),
+	.__count	= ATOMIC_INIT(1),
 	.processes	= ATOMIC_INIT(1),
 	.files		= ATOMIC_INIT(0),
 	.sigpending	= ATOMIC_INIT(0),
 	.locked_shm     = 0,
-	.user_ns	= &init_user_ns,
+	.uid		= GLOBAL_ROOT_UID,
 };
 
 /*
@@ -72,16 +92,15 @@
 static void uid_hash_remove(struct user_struct *up)
 {
 	hlist_del_init(&up->uidhash_node);
-	put_user_ns(up->user_ns);
 }
 
-static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
+static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent)
 {
 	struct user_struct *user;
 	struct hlist_node *h;
 
 	hlist_for_each_entry(user, h, hashent, uidhash_node) {
-		if (user->uid == uid) {
+		if (uid_eq(user->uid, uid)) {
 			atomic_inc(&user->__count);
 			return user;
 		}
@@ -110,14 +129,13 @@
  *
  * If the user_struct could not be found, return NULL.
  */
-struct user_struct *find_user(uid_t uid)
+struct user_struct *find_user(kuid_t uid)
 {
 	struct user_struct *ret;
 	unsigned long flags;
-	struct user_namespace *ns = current_user_ns();
 
 	spin_lock_irqsave(&uidhash_lock, flags);
-	ret = uid_hash_find(uid, uidhashentry(ns, uid));
+	ret = uid_hash_find(uid, uidhashentry(uid));
 	spin_unlock_irqrestore(&uidhash_lock, flags);
 	return ret;
 }
@@ -136,9 +154,9 @@
 		local_irq_restore(flags);
 }
 
-struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
+struct user_struct *alloc_uid(kuid_t uid)
 {
-	struct hlist_head *hashent = uidhashentry(ns, uid);
+	struct hlist_head *hashent = uidhashentry(uid);
 	struct user_struct *up, *new;
 
 	spin_lock_irq(&uidhash_lock);
@@ -153,8 +171,6 @@
 		new->uid = uid;
 		atomic_set(&new->__count, 1);
 
-		new->user_ns = get_user_ns(ns);
-
 		/*
 		 * Before adding this, check whether we raced
 		 * on adding the same user already..
@@ -162,7 +178,6 @@
 		spin_lock_irq(&uidhash_lock);
 		up = uid_hash_find(uid, hashent);
 		if (up) {
-			put_user_ns(ns);
 			key_put(new->uid_keyring);
 			key_put(new->session_keyring);
 			kmem_cache_free(uid_cachep, new);
@@ -187,11 +202,11 @@
 			0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
 	for(n = 0; n < UIDHASH_SZ; ++n)
-		INIT_HLIST_HEAD(init_user_ns.uidhash_table + n);
+		INIT_HLIST_HEAD(uidhash_table + n);
 
 	/* Insert the root user immediately (init already runs as root) */
 	spin_lock_irq(&uidhash_lock);
-	uid_hash_insert(&root_user, uidhashentry(&init_user_ns, 0));
+	uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID));
 	spin_unlock_irq(&uidhash_lock);
 
 	return 0;
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 3b906e9..8660231 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -11,9 +11,20 @@
 #include <linux/user_namespace.h>
 #include <linux/highuid.h>
 #include <linux/cred.h>
+#include <linux/securebits.h>
+#include <linux/keyctl.h>
+#include <linux/key-type.h>
+#include <keys/user-type.h>
+#include <linux/seq_file.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/ctype.h>
 
 static struct kmem_cache *user_ns_cachep __read_mostly;
 
+static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+				struct uid_gid_map *map);
+
 /*
  * Create a new user namespace, deriving the creator from the user in the
  * passed credentials, and replacing that user with the new root user for the
@@ -24,109 +35,565 @@
  */
 int create_user_ns(struct cred *new)
 {
-	struct user_namespace *ns;
-	struct user_struct *root_user;
-	int n;
+	struct user_namespace *ns, *parent_ns = new->user_ns;
+	kuid_t owner = new->euid;
+	kgid_t group = new->egid;
 
-	ns = kmem_cache_alloc(user_ns_cachep, GFP_KERNEL);
+	/* The creator needs a mapping in the parent user namespace
+	 * or else we won't be able to reasonably tell userspace who
+	 * created a user_namespace.
+	 */
+	if (!kuid_has_mapping(parent_ns, owner) ||
+	    !kgid_has_mapping(parent_ns, group))
+		return -EPERM;
+
+	ns = kmem_cache_zalloc(user_ns_cachep, GFP_KERNEL);
 	if (!ns)
 		return -ENOMEM;
 
 	kref_init(&ns->kref);
+	ns->parent = parent_ns;
+	ns->owner = owner;
+	ns->group = group;
 
-	for (n = 0; n < UIDHASH_SZ; ++n)
-		INIT_HLIST_HEAD(ns->uidhash_table + n);
-
-	/* Alloc new root user.  */
-	root_user = alloc_uid(ns, 0);
-	if (!root_user) {
-		kmem_cache_free(user_ns_cachep, ns);
-		return -ENOMEM;
-	}
-
-	/* set the new root user in the credentials under preparation */
-	ns->creator = new->user;
-	new->user = root_user;
-	new->uid = new->euid = new->suid = new->fsuid = 0;
-	new->gid = new->egid = new->sgid = new->fsgid = 0;
-	put_group_info(new->group_info);
-	new->group_info = get_group_info(&init_groups);
+	/* Start with the same capabilities as init but useless for doing
+	 * anything as the capabilities are bound to the new user namespace.
+	 */
+	new->securebits = SECUREBITS_DEFAULT;
+	new->cap_inheritable = CAP_EMPTY_SET;
+	new->cap_permitted = CAP_FULL_SET;
+	new->cap_effective = CAP_FULL_SET;
+	new->cap_bset = CAP_FULL_SET;
 #ifdef CONFIG_KEYS
 	key_put(new->request_key_auth);
 	new->request_key_auth = NULL;
 #endif
 	/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
 
-	/* root_user holds a reference to ns, our reference can be dropped */
-	put_user_ns(ns);
+	/* Leave the new->user_ns reference with the new user namespace. */
+	/* Leave the reference to our user_ns with the new cred. */
+	new->user_ns = ns;
 
 	return 0;
 }
 
-/*
- * Deferred destructor for a user namespace.  This is required because
- * free_user_ns() may be called with uidhash_lock held, but we need to call
- * back to free_uid() which will want to take the lock again.
- */
-static void free_user_ns_work(struct work_struct *work)
-{
-	struct user_namespace *ns =
-		container_of(work, struct user_namespace, destroyer);
-	free_uid(ns->creator);
-	kmem_cache_free(user_ns_cachep, ns);
-}
-
 void free_user_ns(struct kref *kref)
 {
-	struct user_namespace *ns =
+	struct user_namespace *parent, *ns =
 		container_of(kref, struct user_namespace, kref);
 
-	INIT_WORK(&ns->destroyer, free_user_ns_work);
-	schedule_work(&ns->destroyer);
+	parent = ns->parent;
+	kmem_cache_free(user_ns_cachep, ns);
+	put_user_ns(parent);
 }
 EXPORT_SYMBOL(free_user_ns);
 
-uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid)
+static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count)
 {
-	struct user_namespace *tmp;
+	unsigned idx, extents;
+	u32 first, last, id2;
 
-	if (likely(to == cred->user->user_ns))
-		return uid;
+	id2 = id + count - 1;
 
-
-	/* Is cred->user the creator of the target user_ns
-	 * or the creator of one of it's parents?
-	 */
-	for ( tmp = to; tmp != &init_user_ns;
-	      tmp = tmp->creator->user_ns ) {
-		if (cred->user == tmp->creator) {
-			return (uid_t)0;
-		}
+	/* Find the matching extent */
+	extents = map->nr_extents;
+	smp_read_barrier_depends();
+	for (idx = 0; idx < extents; idx++) {
+		first = map->extent[idx].first;
+		last = first + map->extent[idx].count - 1;
+		if (id >= first && id <= last &&
+		    (id2 >= first && id2 <= last))
+			break;
 	}
+	/* Map the id or note failure */
+	if (idx < extents)
+		id = (id - first) + map->extent[idx].lower_first;
+	else
+		id = (u32) -1;
 
-	/* No useful relationship so no mapping */
-	return overflowuid;
+	return id;
 }
 
-gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid)
+static u32 map_id_down(struct uid_gid_map *map, u32 id)
 {
-	struct user_namespace *tmp;
+	unsigned idx, extents;
+	u32 first, last;
 
-	if (likely(to == cred->user->user_ns))
-		return gid;
+	/* Find the matching extent */
+	extents = map->nr_extents;
+	smp_read_barrier_depends();
+	for (idx = 0; idx < extents; idx++) {
+		first = map->extent[idx].first;
+		last = first + map->extent[idx].count - 1;
+		if (id >= first && id <= last)
+			break;
+	}
+	/* Map the id or note failure */
+	if (idx < extents)
+		id = (id - first) + map->extent[idx].lower_first;
+	else
+		id = (u32) -1;
 
-	/* Is cred->user the creator of the target user_ns
-	 * or the creator of one of it's parents?
+	return id;
+}
+
+static u32 map_id_up(struct uid_gid_map *map, u32 id)
+{
+	unsigned idx, extents;
+	u32 first, last;
+
+	/* Find the matching extent */
+	extents = map->nr_extents;
+	smp_read_barrier_depends();
+	for (idx = 0; idx < extents; idx++) {
+		first = map->extent[idx].lower_first;
+		last = first + map->extent[idx].count - 1;
+		if (id >= first && id <= last)
+			break;
+	}
+	/* Map the id or note failure */
+	if (idx < extents)
+		id = (id - first) + map->extent[idx].first;
+	else
+		id = (u32) -1;
+
+	return id;
+}
+
+/**
+ *	make_kuid - Map a user-namespace uid pair into a kuid.
+ *	@ns:  User namespace that the uid is in
+ *	@uid: User identifier
+ *
+ *	Maps a user-namespace uid pair into a kernel internal kuid,
+ *	and returns that kuid.
+ *
+ *	When there is no mapping defined for the user-namespace uid
+ *	pair INVALID_UID is returned.  Callers are expected to test
+ *	for and handle handle INVALID_UID being returned.  INVALID_UID
+ *	may be tested for using uid_valid().
+ */
+kuid_t make_kuid(struct user_namespace *ns, uid_t uid)
+{
+	/* Map the uid to a global kernel uid */
+	return KUIDT_INIT(map_id_down(&ns->uid_map, uid));
+}
+EXPORT_SYMBOL(make_kuid);
+
+/**
+ *	from_kuid - Create a uid from a kuid user-namespace pair.
+ *	@targ: The user namespace we want a uid in.
+ *	@kuid: The kernel internal uid to start with.
+ *
+ *	Map @kuid into the user-namespace specified by @targ and
+ *	return the resulting uid.
+ *
+ *	There is always a mapping into the initial user_namespace.
+ *
+ *	If @kuid has no mapping in @targ (uid_t)-1 is returned.
+ */
+uid_t from_kuid(struct user_namespace *targ, kuid_t kuid)
+{
+	/* Map the uid from a global kernel uid */
+	return map_id_up(&targ->uid_map, __kuid_val(kuid));
+}
+EXPORT_SYMBOL(from_kuid);
+
+/**
+ *	from_kuid_munged - Create a uid from a kuid user-namespace pair.
+ *	@targ: The user namespace we want a uid in.
+ *	@kuid: The kernel internal uid to start with.
+ *
+ *	Map @kuid into the user-namespace specified by @targ and
+ *	return the resulting uid.
+ *
+ *	There is always a mapping into the initial user_namespace.
+ *
+ *	Unlike from_kuid from_kuid_munged never fails and always
+ *	returns a valid uid.  This makes from_kuid_munged appropriate
+ *	for use in syscalls like stat and getuid where failing the
+ *	system call and failing to provide a valid uid are not an
+ *	options.
+ *
+ *	If @kuid has no mapping in @targ overflowuid is returned.
+ */
+uid_t from_kuid_munged(struct user_namespace *targ, kuid_t kuid)
+{
+	uid_t uid;
+	uid = from_kuid(targ, kuid);
+
+	if (uid == (uid_t) -1)
+		uid = overflowuid;
+	return uid;
+}
+EXPORT_SYMBOL(from_kuid_munged);
+
+/**
+ *	make_kgid - Map a user-namespace gid pair into a kgid.
+ *	@ns:  User namespace that the gid is in
+ *	@uid: group identifier
+ *
+ *	Maps a user-namespace gid pair into a kernel internal kgid,
+ *	and returns that kgid.
+ *
+ *	When there is no mapping defined for the user-namespace gid
+ *	pair INVALID_GID is returned.  Callers are expected to test
+ *	for and handle INVALID_GID being returned.  INVALID_GID may be
+ *	tested for using gid_valid().
+ */
+kgid_t make_kgid(struct user_namespace *ns, gid_t gid)
+{
+	/* Map the gid to a global kernel gid */
+	return KGIDT_INIT(map_id_down(&ns->gid_map, gid));
+}
+EXPORT_SYMBOL(make_kgid);
+
+/**
+ *	from_kgid - Create a gid from a kgid user-namespace pair.
+ *	@targ: The user namespace we want a gid in.
+ *	@kgid: The kernel internal gid to start with.
+ *
+ *	Map @kgid into the user-namespace specified by @targ and
+ *	return the resulting gid.
+ *
+ *	There is always a mapping into the initial user_namespace.
+ *
+ *	If @kgid has no mapping in @targ (gid_t)-1 is returned.
+ */
+gid_t from_kgid(struct user_namespace *targ, kgid_t kgid)
+{
+	/* Map the gid from a global kernel gid */
+	return map_id_up(&targ->gid_map, __kgid_val(kgid));
+}
+EXPORT_SYMBOL(from_kgid);
+
+/**
+ *	from_kgid_munged - Create a gid from a kgid user-namespace pair.
+ *	@targ: The user namespace we want a gid in.
+ *	@kgid: The kernel internal gid to start with.
+ *
+ *	Map @kgid into the user-namespace specified by @targ and
+ *	return the resulting gid.
+ *
+ *	There is always a mapping into the initial user_namespace.
+ *
+ *	Unlike from_kgid from_kgid_munged never fails and always
+ *	returns a valid gid.  This makes from_kgid_munged appropriate
+ *	for use in syscalls like stat and getgid where failing the
+ *	system call and failing to provide a valid gid are not options.
+ *
+ *	If @kgid has no mapping in @targ overflowgid is returned.
+ */
+gid_t from_kgid_munged(struct user_namespace *targ, kgid_t kgid)
+{
+	gid_t gid;
+	gid = from_kgid(targ, kgid);
+
+	if (gid == (gid_t) -1)
+		gid = overflowgid;
+	return gid;
+}
+EXPORT_SYMBOL(from_kgid_munged);
+
+static int uid_m_show(struct seq_file *seq, void *v)
+{
+	struct user_namespace *ns = seq->private;
+	struct uid_gid_extent *extent = v;
+	struct user_namespace *lower_ns;
+	uid_t lower;
+
+	lower_ns = current_user_ns();
+	if ((lower_ns == ns) && lower_ns->parent)
+		lower_ns = lower_ns->parent;
+
+	lower = from_kuid(lower_ns, KUIDT_INIT(extent->lower_first));
+
+	seq_printf(seq, "%10u %10u %10u\n",
+		extent->first,
+		lower,
+		extent->count);
+
+	return 0;
+}
+
+static int gid_m_show(struct seq_file *seq, void *v)
+{
+	struct user_namespace *ns = seq->private;
+	struct uid_gid_extent *extent = v;
+	struct user_namespace *lower_ns;
+	gid_t lower;
+
+	lower_ns = current_user_ns();
+	if ((lower_ns == ns) && lower_ns->parent)
+		lower_ns = lower_ns->parent;
+
+	lower = from_kgid(lower_ns, KGIDT_INIT(extent->lower_first));
+
+	seq_printf(seq, "%10u %10u %10u\n",
+		extent->first,
+		lower,
+		extent->count);
+
+	return 0;
+}
+
+static void *m_start(struct seq_file *seq, loff_t *ppos, struct uid_gid_map *map)
+{
+	struct uid_gid_extent *extent = NULL;
+	loff_t pos = *ppos;
+
+	if (pos < map->nr_extents)
+		extent = &map->extent[pos];
+
+	return extent;
+}
+
+static void *uid_m_start(struct seq_file *seq, loff_t *ppos)
+{
+	struct user_namespace *ns = seq->private;
+
+	return m_start(seq, ppos, &ns->uid_map);
+}
+
+static void *gid_m_start(struct seq_file *seq, loff_t *ppos)
+{
+	struct user_namespace *ns = seq->private;
+
+	return m_start(seq, ppos, &ns->gid_map);
+}
+
+static void *m_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	(*pos)++;
+	return seq->op->start(seq, pos);
+}
+
+static void m_stop(struct seq_file *seq, void *v)
+{
+	return;
+}
+
+struct seq_operations proc_uid_seq_operations = {
+	.start = uid_m_start,
+	.stop = m_stop,
+	.next = m_next,
+	.show = uid_m_show,
+};
+
+struct seq_operations proc_gid_seq_operations = {
+	.start = gid_m_start,
+	.stop = m_stop,
+	.next = m_next,
+	.show = gid_m_show,
+};
+
+static DEFINE_MUTEX(id_map_mutex);
+
+static ssize_t map_write(struct file *file, const char __user *buf,
+			 size_t count, loff_t *ppos,
+			 int cap_setid,
+			 struct uid_gid_map *map,
+			 struct uid_gid_map *parent_map)
+{
+	struct seq_file *seq = file->private_data;
+	struct user_namespace *ns = seq->private;
+	struct uid_gid_map new_map;
+	unsigned idx;
+	struct uid_gid_extent *extent, *last = NULL;
+	unsigned long page = 0;
+	char *kbuf, *pos, *next_line;
+	ssize_t ret = -EINVAL;
+
+	/*
+	 * The id_map_mutex serializes all writes to any given map.
+	 *
+	 * Any map is only ever written once.
+	 *
+	 * An id map fits within 1 cache line on most architectures.
+	 *
+	 * On read nothing needs to be done unless you are on an
+	 * architecture with a crazy cache coherency model like alpha.
+	 *
+	 * There is a one time data dependency between reading the
+	 * count of the extents and the values of the extents.  The
+	 * desired behavior is to see the values of the extents that
+	 * were written before the count of the extents.
+	 *
+	 * To achieve this smp_wmb() is used on guarantee the write
+	 * order and smp_read_barrier_depends() is guaranteed that we
+	 * don't have crazy architectures returning stale data.
+	 *
 	 */
-	for ( tmp = to; tmp != &init_user_ns;
-	      tmp = tmp->creator->user_ns ) {
-		if (cred->user == tmp->creator) {
-			return (gid_t)0;
+	mutex_lock(&id_map_mutex);
+
+	ret = -EPERM;
+	/* Only allow one successful write to the map */
+	if (map->nr_extents != 0)
+		goto out;
+
+	/* Require the appropriate privilege CAP_SETUID or CAP_SETGID
+	 * over the user namespace in order to set the id mapping.
+	 */
+	if (!ns_capable(ns, cap_setid))
+		goto out;
+
+	/* Get a buffer */
+	ret = -ENOMEM;
+	page = __get_free_page(GFP_TEMPORARY);
+	kbuf = (char *) page;
+	if (!page)
+		goto out;
+
+	/* Only allow <= page size writes at the beginning of the file */
+	ret = -EINVAL;
+	if ((*ppos != 0) || (count >= PAGE_SIZE))
+		goto out;
+
+	/* Slurp in the user data */
+	ret = -EFAULT;
+	if (copy_from_user(kbuf, buf, count))
+		goto out;
+	kbuf[count] = '\0';
+
+	/* Parse the user data */
+	ret = -EINVAL;
+	pos = kbuf;
+	new_map.nr_extents = 0;
+	for (;pos; pos = next_line) {
+		extent = &new_map.extent[new_map.nr_extents];
+
+		/* Find the end of line and ensure I don't look past it */
+		next_line = strchr(pos, '\n');
+		if (next_line) {
+			*next_line = '\0';
+			next_line++;
+			if (*next_line == '\0')
+				next_line = NULL;
 		}
+
+		pos = skip_spaces(pos);
+		extent->first = simple_strtoul(pos, &pos, 10);
+		if (!isspace(*pos))
+			goto out;
+
+		pos = skip_spaces(pos);
+		extent->lower_first = simple_strtoul(pos, &pos, 10);
+		if (!isspace(*pos))
+			goto out;
+
+		pos = skip_spaces(pos);
+		extent->count = simple_strtoul(pos, &pos, 10);
+		if (*pos && !isspace(*pos))
+			goto out;
+
+		/* Verify there is not trailing junk on the line */
+		pos = skip_spaces(pos);
+		if (*pos != '\0')
+			goto out;
+
+		/* Verify we have been given valid starting values */
+		if ((extent->first == (u32) -1) ||
+		    (extent->lower_first == (u32) -1 ))
+			goto out;
+
+		/* Verify count is not zero and does not cause the extent to wrap */
+		if ((extent->first + extent->count) <= extent->first)
+			goto out;
+		if ((extent->lower_first + extent->count) <= extent->lower_first)
+			goto out;
+
+		/* For now only accept extents that are strictly in order */
+		if (last &&
+		    (((last->first + last->count) > extent->first) ||
+		     ((last->lower_first + last->count) > extent->lower_first)))
+			goto out;
+
+		new_map.nr_extents++;
+		last = extent;
+
+		/* Fail if the file contains too many extents */
+		if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) &&
+		    (next_line != NULL))
+			goto out;
+	}
+	/* Be very certaint the new map actually exists */
+	if (new_map.nr_extents == 0)
+		goto out;
+
+	ret = -EPERM;
+	/* Validate the user is allowed to use user id's mapped to. */
+	if (!new_idmap_permitted(ns, cap_setid, &new_map))
+		goto out;
+
+	/* Map the lower ids from the parent user namespace to the
+	 * kernel global id space.
+	 */
+	for (idx = 0; idx < new_map.nr_extents; idx++) {
+		u32 lower_first;
+		extent = &new_map.extent[idx];
+
+		lower_first = map_id_range_down(parent_map,
+						extent->lower_first,
+						extent->count);
+
+		/* Fail if we can not map the specified extent to
+		 * the kernel global id space.
+		 */
+		if (lower_first == (u32) -1)
+			goto out;
+
+		extent->lower_first = lower_first;
 	}
 
-	/* No useful relationship so no mapping */
-	return overflowgid;
+	/* Install the map */
+	memcpy(map->extent, new_map.extent,
+		new_map.nr_extents*sizeof(new_map.extent[0]));
+	smp_wmb();
+	map->nr_extents = new_map.nr_extents;
+
+	*ppos = count;
+	ret = count;
+out:
+	mutex_unlock(&id_map_mutex);
+	if (page)
+		free_page(page);
+	return ret;
+}
+
+ssize_t proc_uid_map_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
+{
+	struct seq_file *seq = file->private_data;
+	struct user_namespace *ns = seq->private;
+
+	if (!ns->parent)
+		return -EPERM;
+
+	return map_write(file, buf, size, ppos, CAP_SETUID,
+			 &ns->uid_map, &ns->parent->uid_map);
+}
+
+ssize_t proc_gid_map_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
+{
+	struct seq_file *seq = file->private_data;
+	struct user_namespace *ns = seq->private;
+
+	if (!ns->parent)
+		return -EPERM;
+
+	return map_write(file, buf, size, ppos, CAP_SETGID,
+			 &ns->gid_map, &ns->parent->gid_map);
+}
+
+static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+				struct uid_gid_map *new_map)
+{
+	/* Allow the specified ids if we have the appropriate capability
+	 * (CAP_SETUID or CAP_SETGID) over the parent user namespace.
+	 */
+	if (ns_capable(ns->parent, cap_setid))
+		return true;
+
+	return false;
 }
 
 static __init int user_namespaces_init(void)
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 405caf9..679d97a 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -43,7 +43,7 @@
 
 	down_read(&uts_sem);
 	memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
-	ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
+	ns->user_ns = get_user_ns(task_cred_xxx(tsk, user_ns));
 	up_read(&uts_sem);
 	return ns;
 }
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 5abf42f..9a3128d 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1032,7 +1032,10 @@
 	cwq = get_cwq(gcwq->cpu, wq);
 	trace_workqueue_queue_work(cpu, cwq, work);
 
-	BUG_ON(!list_empty(&work->entry));
+	if (WARN_ON(!list_empty(&work->entry))) {
+		spin_unlock_irqrestore(&gcwq->lock, flags);
+		return;
+	}
 
 	cwq->nr_in_flight[cwq->work_color]++;
 	work_flags = work_color_to_flags(cwq->work_color);
@@ -1210,8 +1213,13 @@
 	} else
 		wake_up_all(&gcwq->trustee_wait);
 
-	/* sanity check nr_running */
-	WARN_ON_ONCE(gcwq->nr_workers == gcwq->nr_idle &&
+	/*
+	 * Sanity check nr_running.  Because trustee releases gcwq->lock
+	 * between setting %WORKER_ROGUE and zapping nr_running, the
+	 * warning may trigger spuriously.  Check iff trustee is idle.
+	 */
+	WARN_ON_ONCE(gcwq->trustee_state == TRUSTEE_DONE &&
+		     gcwq->nr_workers == gcwq->nr_idle &&
 		     atomic_read(get_gcwq_nr_running(gcwq->cpu)));
 }
 
@@ -1810,7 +1818,9 @@
 	 * lock freed" warnings as well as problems when looking into
 	 * work->lockdep_map, make a copy and use that here.
 	 */
-	struct lockdep_map lockdep_map = work->lockdep_map;
+	struct lockdep_map lockdep_map;
+
+	lockdep_copy_map(&lockdep_map, &work->lockdep_map);
 #endif
 	/*
 	 * A single work shouldn't be executed concurrently by
@@ -2506,6 +2516,9 @@
 {
 	struct wq_barrier barr;
 
+	lock_map_acquire(&work->lockdep_map);
+	lock_map_release(&work->lockdep_map);
+
 	if (start_flush_work(work, &barr, true)) {
 		wait_for_completion(&barr.done);
 		destroy_work_on_stack(&barr.work);
diff --git a/lib/Kconfig b/lib/Kconfig
index 4a8aba2..0e25c03 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -353,6 +353,14 @@
 	  This option provides an implementation of the CORDIC algorithm;
 	  calculations are in fixed point. Module will be called cordic.
 
+config DDR
+	bool "JEDEC DDR data"
+	help
+	  Data from JEDEC specs for DDR SDRAM memories,
+	  particularly the AC timing parameters and addressing
+	  information. This data is useful for drivers handling
+	  DDR SDRAM controllers.
+
 config MPILIB
 	tristate
 	select CLZ_TAB
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 6777153..a42d3ae 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -3,12 +3,16 @@
 	bool "Show timing information on printks"
 	depends on PRINTK
 	help
-	  Selecting this option causes timing information to be
-	  included in printk output.  This allows you to measure
-	  the interval between kernel operations, including bootup
-	  operations.  This is useful for identifying long delays
-	  in kernel startup.  Or add printk.time=1 at boot-time.
-	  See Documentation/kernel-parameters.txt
+	  Selecting this option causes time stamps of the printk()
+	  messages to be added to the output of the syslog() system
+	  call and at the console.
+
+	  The timestamp is always recorded internally, and exported
+	  to /dev/kmsg. This flag just specifies if the timestamp should
+	  be included, not that the timestamp is recorded.
+
+	  The behavior is also controlled by the kernel command line
+	  parameter printk.time=1. See Documentation/kernel-parameters.txt
 
 config DEFAULT_MESSAGE_LOGLEVEL
 	int "Default message log level (1-7)"
@@ -70,6 +74,15 @@
 	  that look like '.Lxxx') so they don't pollute the output of
 	  get_wchan() and suchlike.
 
+config READABLE_ASM
+        bool "Generate readable assembler code"
+        depends on DEBUG_KERNEL
+        help
+          Disable some compiler optimizations that tend to generate human unreadable
+          assembler output. This may make the kernel slightly slower, but it helps
+          to keep kernel developers who have to stare a lot at assembler listings
+          sane.
+
 config UNUSED_SYMBOLS
 	bool "Enable unused/obsolete exported symbols"
 	default y if X86
@@ -1205,8 +1218,13 @@
 	  otherwise be available at runtime. These messages can then be
 	  enabled/disabled based on various levels of scope - per source file,
 	  function, module, format string, and line number. This mechanism
-	  implicitly enables all pr_debug() and dev_dbg() calls. The impact of
-	  this compile option is a larger kernel text size of about 2%.
+	  implicitly compiles in all pr_debug() and dev_dbg() calls, which
+	  enlarges the kernel text size by about 2%.
+
+	  If a source file is compiled with DEBUG flag set, any
+	  pr_debug() calls in it are enabled by default, but can be
+	  disabled at runtime as below.  Note that DEBUG flag is
+	  turned on by many CONFIG_*DEBUG* options.
 
 	  Usage:
 
@@ -1223,16 +1241,16 @@
 	  lineno : line number of the debug statement
 	  module : module that contains the debug statement
 	  function : function that contains the debug statement
-          flags : 'p' means the line is turned 'on' for printing
+          flags : '=p' means the line is turned 'on' for printing
           format : the format used for the debug statement
 
 	  From a live system:
 
 		nullarbor:~ # cat <debugfs>/dynamic_debug/control
 		# filename:lineno [module]function flags format
-		fs/aio.c:222 [aio]__put_ioctx - "__put_ioctx:\040freeing\040%p\012"
-		fs/aio.c:248 [aio]ioctx_alloc - "ENOMEM:\040nr_events\040too\040high\012"
-		fs/aio.c:1770 [aio]sys_io_cancel - "calling\040cancel\012"
+		fs/aio.c:222 [aio]__put_ioctx =_ "__put_ioctx:\040freeing\040%p\012"
+		fs/aio.c:248 [aio]ioctx_alloc =_ "ENOMEM:\040nr_events\040too\040high\012"
+		fs/aio.c:1770 [aio]sys_io_cancel =_ "calling\040cancel\012"
 
 	  Example usage:
 
diff --git a/lib/Makefile b/lib/Makefile
index 18515f0..74290c9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -123,6 +123,8 @@
 
 obj-$(CONFIG_CLZ_TAB) += clz_tab.o
 
+obj-$(CONFIG_DDR) += jedec_ddr_data.o
+
 hostprogs-y	:= gen_crc32table
 clean-files	:= crc32table.h
 
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 310c753..7ca29a0 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -107,20 +107,22 @@
 	return buf;
 }
 
-#define vpr_info_dq(q, msg)						\
-do {									\
-	if (verbose)							\
-		/* trim last char off format print */			\
-		pr_info("%s: func=\"%s\" file=\"%s\" "			\
-			"module=\"%s\" format=\"%.*s\" "		\
-			"lineno=%u-%u",					\
-			msg,						\
-			q->function ? q->function : "",			\
-			q->filename ? q->filename : "",			\
-			q->module ? q->module : "",			\
-			(int)(q->format ? strlen(q->format) - 1 : 0),	\
-			q->format ? q->format : "",			\
-			q->first_lineno, q->last_lineno);		\
+#define vpr_info(fmt, ...) \
+	if (verbose) do { pr_info(fmt, ##__VA_ARGS__); } while (0)
+
+#define vpr_info_dq(q, msg)					\
+do {								\
+	/* trim last char off format print */			\
+	vpr_info("%s: func=\"%s\" file=\"%s\" "			\
+		"module=\"%s\" format=\"%.*s\" "		\
+		"lineno=%u-%u",					\
+		msg,						\
+		q->function ? q->function : "",			\
+		q->filename ? q->filename : "",			\
+		q->module ? q->module : "",			\
+		(int)(q->format ? strlen(q->format) - 1 : 0),	\
+		q->format ? q->format : "",			\
+		q->first_lineno, q->last_lineno);		\
 } while (0)
 
 /*
@@ -180,12 +182,11 @@
 			if (newflags == dp->flags)
 				continue;
 			dp->flags = newflags;
-			if (verbose)
-				pr_info("changed %s:%d [%s]%s =%s\n",
-					trim_prefix(dp->filename), dp->lineno,
-					dt->mod_name, dp->function,
-					ddebug_describe_flags(dp, flagbuf,
-							sizeof(flagbuf)));
+			vpr_info("changed %s:%d [%s]%s =%s\n",
+				trim_prefix(dp->filename), dp->lineno,
+				dt->mod_name, dp->function,
+				ddebug_describe_flags(dp, flagbuf,
+						sizeof(flagbuf)));
 		}
 	}
 	mutex_unlock(&ddebug_lock);
@@ -337,7 +338,7 @@
  * Returns 0 on success, <0 on error.
  */
 static int ddebug_parse_query(char *words[], int nwords,
-			       struct ddebug_query *query)
+			struct ddebug_query *query, const char *modname)
 {
 	unsigned int i;
 	int rc;
@@ -347,6 +348,10 @@
 		return -EINVAL;
 	memset(query, 0, sizeof(*query));
 
+	if (modname)
+		/* support $modname.dyndbg=<multiple queries> */
+		query->module = modname;
+
 	for (i = 0 ; i < nwords ; i += 2) {
 		if (!strcmp(words[i], "func"))
 			rc = check_set(&query->function, words[i+1], "func");
@@ -410,8 +415,7 @@
 	default:
 		return -EINVAL;
 	}
-	if (verbose)
-		pr_info("op='%c'\n", op);
+	vpr_info("op='%c'\n", op);
 
 	for ( ; *str ; ++str) {
 		for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
@@ -423,8 +427,7 @@
 		if (i < 0)
 			return -EINVAL;
 	}
-	if (verbose)
-		pr_info("flags=0x%x\n", flags);
+	vpr_info("flags=0x%x\n", flags);
 
 	/* calculate final *flagsp, *maskp according to mask and op */
 	switch (op) {
@@ -441,12 +444,11 @@
 		*flagsp = 0;
 		break;
 	}
-	if (verbose)
-		pr_info("*flagsp=0x%x *maskp=0x%x\n", *flagsp, *maskp);
+	vpr_info("*flagsp=0x%x *maskp=0x%x\n", *flagsp, *maskp);
 	return 0;
 }
 
-static int ddebug_exec_query(char *query_string)
+static int ddebug_exec_query(char *query_string, const char *modname)
 {
 	unsigned int flags = 0, mask = 0;
 	struct ddebug_query query;
@@ -457,7 +459,7 @@
 	nwords = ddebug_tokenize(query_string, words, MAXWORDS);
 	if (nwords <= 0)
 		return -EINVAL;
-	if (ddebug_parse_query(words, nwords-1, &query))
+	if (ddebug_parse_query(words, nwords-1, &query, modname))
 		return -EINVAL;
 	if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
 		return -EINVAL;
@@ -473,7 +475,7 @@
    last error or number of matching callsites.  Module name is either
    in param (for boot arg) or perhaps in query string.
 */
-static int ddebug_exec_queries(char *query)
+static int ddebug_exec_queries(char *query, const char *modname)
 {
 	char *split;
 	int i, errs = 0, exitcode = 0, rc, nfound = 0;
@@ -487,10 +489,9 @@
 		if (!query || !*query || *query == '#')
 			continue;
 
-		if (verbose)
-			pr_info("query %d: \"%s\"\n", i, query);
+		vpr_info("query %d: \"%s\"\n", i, query);
 
-		rc = ddebug_exec_query(query);
+		rc = ddebug_exec_query(query, modname);
 		if (rc < 0) {
 			errs++;
 			exitcode = rc;
@@ -498,7 +499,7 @@
 			nfound += rc;
 		i++;
 	}
-	pr_info("processed %d queries, with %d matches, %d errs\n",
+	vpr_info("processed %d queries, with %d matches, %d errs\n",
 		 i, nfound, errs);
 
 	if (exitcode)
@@ -653,10 +654,9 @@
 		return -EFAULT;
 	}
 	tmpbuf[len] = '\0';
-	if (verbose)
-		pr_info("read %d bytes from userspace\n", (int)len);
+	vpr_info("read %d bytes from userspace\n", (int)len);
 
-	ret = ddebug_exec_queries(tmpbuf);
+	ret = ddebug_exec_queries(tmpbuf, NULL);
 	kfree(tmpbuf);
 	if (ret < 0)
 		return ret;
@@ -717,8 +717,7 @@
 	struct _ddebug *dp;
 	int n = *pos;
 
-	if (verbose)
-		pr_info("called m=%p *pos=%lld\n", m, (unsigned long long)*pos);
+	vpr_info("called m=%p *pos=%lld\n", m, (unsigned long long)*pos);
 
 	mutex_lock(&ddebug_lock);
 
@@ -742,9 +741,8 @@
 	struct ddebug_iter *iter = m->private;
 	struct _ddebug *dp;
 
-	if (verbose)
-		pr_info("called m=%p p=%p *pos=%lld\n",
-			m, p, (unsigned long long)*pos);
+	vpr_info("called m=%p p=%p *pos=%lld\n",
+		m, p, (unsigned long long)*pos);
 
 	if (p == SEQ_START_TOKEN)
 		dp = ddebug_iter_first(iter);
@@ -766,8 +764,7 @@
 	struct _ddebug *dp = p;
 	char flagsbuf[10];
 
-	if (verbose)
-		pr_info("called m=%p p=%p\n", m, p);
+	vpr_info("called m=%p p=%p\n", m, p);
 
 	if (p == SEQ_START_TOKEN) {
 		seq_puts(m,
@@ -791,8 +788,7 @@
  */
 static void ddebug_proc_stop(struct seq_file *m, void *p)
 {
-	if (verbose)
-		pr_info("called m=%p p=%p\n", m, p);
+	vpr_info("called m=%p p=%p\n", m, p);
 	mutex_unlock(&ddebug_lock);
 }
 
@@ -815,8 +811,7 @@
 	struct ddebug_iter *iter;
 	int err;
 
-	if (verbose)
-		pr_info("called\n");
+	vpr_info("called\n");
 
 	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
 	if (iter == NULL)
@@ -866,12 +861,51 @@
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
-	if (verbose)
-		pr_info("%u debug prints in module %s\n", n, dt->mod_name);
+	vpr_info("%u debug prints in module %s\n", n, dt->mod_name);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ddebug_add_module);
 
+/* helper for ddebug_dyndbg_(boot|module)_param_cb */
+static int ddebug_dyndbg_param_cb(char *param, char *val,
+				const char *modname, int on_err)
+{
+	char *sep;
+
+	sep = strchr(param, '.');
+	if (sep) {
+		/* needed only for ddebug_dyndbg_boot_param_cb */
+		*sep = '\0';
+		modname = param;
+		param = sep + 1;
+	}
+	if (strcmp(param, "dyndbg"))
+		return on_err; /* determined by caller */
+
+	ddebug_exec_queries((val ? val : "+p"), modname);
+
+	return 0; /* query failure shouldnt stop module load */
+}
+
+/* handle both dyndbg and $module.dyndbg params at boot */
+static int ddebug_dyndbg_boot_param_cb(char *param, char *val,
+				const char *unused)
+{
+	vpr_info("%s=\"%s\"\n", param, val);
+	return ddebug_dyndbg_param_cb(param, val, NULL, 0);
+}
+
+/*
+ * modprobe foo finds foo.params in boot-args, strips "foo.", and
+ * passes them to load_module().  This callback gets unknown params,
+ * processes dyndbg params, rejects others.
+ */
+int ddebug_dyndbg_module_param_cb(char *param, char *val, const char *module)
+{
+	vpr_info("module: %s %s=\"%s\"\n", module, param, val);
+	return ddebug_dyndbg_param_cb(param, val, module, -ENOENT);
+}
+
 static void ddebug_table_free(struct ddebug_table *dt)
 {
 	list_del_init(&dt->link);
@@ -888,8 +922,7 @@
 	struct ddebug_table *dt, *nextdt;
 	int ret = -ENOENT;
 
-	if (verbose)
-		pr_info("removing module \"%s\"\n", mod_name);
+	vpr_info("removing module \"%s\"\n", mod_name);
 
 	mutex_lock(&ddebug_lock);
 	list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
@@ -940,8 +973,10 @@
 {
 	struct _ddebug *iter, *iter_start;
 	const char *modname = NULL;
+	char *cmdline;
 	int ret = 0;
-	int n = 0;
+	int n = 0, entries = 0, modct = 0;
+	int verbose_bytes = 0;
 
 	if (__start___verbose == __stop___verbose) {
 		pr_warn("_ddebug table is empty in a "
@@ -952,10 +987,15 @@
 	modname = iter->modname;
 	iter_start = iter;
 	for (; iter < __stop___verbose; iter++) {
+		entries++;
+		verbose_bytes += strlen(iter->modname) + strlen(iter->function)
+			+ strlen(iter->filename) + strlen(iter->format);
+
 		if (strcmp(modname, iter->modname)) {
+			modct++;
 			ret = ddebug_add_module(iter_start, n, modname);
 			if (ret)
-				goto out_free;
+				goto out_err;
 			n = 0;
 			modname = iter->modname;
 			iter_start = iter;
@@ -964,29 +1004,45 @@
 	}
 	ret = ddebug_add_module(iter_start, n, modname);
 	if (ret)
-		goto out_free;
+		goto out_err;
 
-	/* ddebug_query boot param got passed -> set it up */
+	ddebug_init_success = 1;
+	vpr_info("%d modules, %d entries and %d bytes in ddebug tables,"
+		" %d bytes in (readonly) verbose section\n",
+		modct, entries, (int)( modct * sizeof(struct ddebug_table)),
+		verbose_bytes + (int)(__stop___verbose - __start___verbose));
+
+	/* apply ddebug_query boot param, dont unload tables on err */
 	if (ddebug_setup_string[0] != '\0') {
-		ret = ddebug_exec_queries(ddebug_setup_string);
+		pr_warn("ddebug_query param name is deprecated,"
+			" change it to dyndbg\n");
+		ret = ddebug_exec_queries(ddebug_setup_string, NULL);
 		if (ret < 0)
 			pr_warn("Invalid ddebug boot param %s",
 				ddebug_setup_string);
 		else
 			pr_info("%d changes by ddebug_query\n", ret);
-
-		/* keep tables even on ddebug_query parse error */
-		ret = 0;
 	}
+	/* now that ddebug tables are loaded, process all boot args
+	 * again to find and activate queries given in dyndbg params.
+	 * While this has already been done for known boot params, it
+	 * ignored the unknown ones (dyndbg in particular).  Reusing
+	 * parse_args avoids ad-hoc parsing.  This will also attempt
+	 * to activate queries for not-yet-loaded modules, which is
+	 * slightly noisy if verbose, but harmless.
+	 */
+	cmdline = kstrdup(saved_command_line, GFP_KERNEL);
+	parse_args("dyndbg params", cmdline, NULL,
+		   0, 0, 0, &ddebug_dyndbg_boot_param_cb);
+	kfree(cmdline);
+	return 0;
 
-out_free:
-	if (ret)
-		ddebug_remove_all_tables();
-	else
-		ddebug_init_success = 1;
+out_err:
+	ddebug_remove_all_tables();
 	return 0;
 }
 /* Allow early initialization for boot messages via boot param */
-arch_initcall(dynamic_debug_init);
+early_initcall(dynamic_debug_init);
+
 /* Debugfs setup must be done later */
-module_init(dynamic_debug_init_debugfs);
+fs_initcall(dynamic_debug_init_debugfs);
diff --git a/lib/jedec_ddr_data.c b/lib/jedec_ddr_data.c
new file mode 100644
index 0000000..6d2cbf1
--- /dev/null
+++ b/lib/jedec_ddr_data.c
@@ -0,0 +1,135 @@
+/*
+ * DDR addressing details and AC timing parameters from JEDEC specs
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@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.
+ */
+
+#include <memory/jedec_ddr.h>
+#include <linux/module.h>
+
+/* LPDDR2 addressing details from JESD209-2 section 2.4 */
+const struct lpddr2_addressing
+	lpddr2_jedec_addressing_table[NUM_DDR_ADDR_TABLE_ENTRIES] = {
+	{B4, T_REFI_15_6, T_RFC_90}, /* 64M */
+	{B4, T_REFI_15_6, T_RFC_90}, /* 128M */
+	{B4, T_REFI_7_8,  T_RFC_90}, /* 256M */
+	{B4, T_REFI_7_8,  T_RFC_90}, /* 512M */
+	{B8, T_REFI_7_8, T_RFC_130}, /* 1GS4 */
+	{B8, T_REFI_3_9, T_RFC_130}, /* 2GS4 */
+	{B8, T_REFI_3_9, T_RFC_130}, /* 4G */
+	{B8, T_REFI_3_9, T_RFC_210}, /* 8G */
+	{B4, T_REFI_7_8, T_RFC_130}, /* 1GS2 */
+	{B4, T_REFI_3_9, T_RFC_130}, /* 2GS2 */
+};
+EXPORT_SYMBOL_GPL(lpddr2_jedec_addressing_table);
+
+/* LPDDR2 AC timing parameters from JESD209-2 section 12 */
+const struct lpddr2_timings
+	lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES] = {
+	/* Speed bin 400(200 MHz) */
+	[0] = {
+		.max_freq	= 200000000,
+		.min_freq	= 10000000,
+		.tRPab		= 21000,
+		.tRCD		= 18000,
+		.tWR		= 15000,
+		.tRAS_min	= 42000,
+		.tRRD		= 10000,
+		.tWTR		= 10000,
+		.tXP		= 7500,
+		.tRTP		= 7500,
+		.tCKESR		= 15000,
+		.tDQSCK_max	= 5500,
+		.tFAW		= 50000,
+		.tZQCS		= 90000,
+		.tZQCL		= 360000,
+		.tZQinit	= 1000000,
+		.tRAS_max_ns	= 70000,
+		.tDQSCK_max_derated = 6000,
+	},
+	/* Speed bin 533(266 MHz) */
+	[1] = {
+		.max_freq	= 266666666,
+		.min_freq	= 10000000,
+		.tRPab		= 21000,
+		.tRCD		= 18000,
+		.tWR		= 15000,
+		.tRAS_min	= 42000,
+		.tRRD		= 10000,
+		.tWTR		= 7500,
+		.tXP		= 7500,
+		.tRTP		= 7500,
+		.tCKESR		= 15000,
+		.tDQSCK_max	= 5500,
+		.tFAW		= 50000,
+		.tZQCS		= 90000,
+		.tZQCL		= 360000,
+		.tZQinit	= 1000000,
+		.tRAS_max_ns	= 70000,
+		.tDQSCK_max_derated = 6000,
+	},
+	/* Speed bin 800(400 MHz) */
+	[2] = {
+		.max_freq	= 400000000,
+		.min_freq	= 10000000,
+		.tRPab		= 21000,
+		.tRCD		= 18000,
+		.tWR		= 15000,
+		.tRAS_min	= 42000,
+		.tRRD		= 10000,
+		.tWTR		= 7500,
+		.tXP		= 7500,
+		.tRTP		= 7500,
+		.tCKESR		= 15000,
+		.tDQSCK_max	= 5500,
+		.tFAW		= 50000,
+		.tZQCS		= 90000,
+		.tZQCL		= 360000,
+		.tZQinit	= 1000000,
+		.tRAS_max_ns	= 70000,
+		.tDQSCK_max_derated = 6000,
+	},
+	/* Speed bin 1066(533 MHz) */
+	[3] = {
+		.max_freq	= 533333333,
+		.min_freq	= 10000000,
+		.tRPab		= 21000,
+		.tRCD		= 18000,
+		.tWR		= 15000,
+		.tRAS_min	= 42000,
+		.tRRD		= 10000,
+		.tWTR		= 7500,
+		.tXP		= 7500,
+		.tRTP		= 7500,
+		.tCKESR		= 15000,
+		.tDQSCK_max	= 5500,
+		.tFAW		= 50000,
+		.tZQCS		= 90000,
+		.tZQCL		= 360000,
+		.tZQinit	= 1000000,
+		.tRAS_max_ns	= 70000,
+		.tDQSCK_max_derated = 5620,
+	},
+};
+EXPORT_SYMBOL_GPL(lpddr2_jedec_timings);
+
+const struct lpddr2_min_tck lpddr2_jedec_min_tck = {
+	.tRPab		= 3,
+	.tRCD		= 3,
+	.tWR		= 3,
+	.tRASmin	= 3,
+	.tRRD		= 2,
+	.tWTR		= 2,
+	.tXP		= 2,
+	.tRTP		= 2,
+	.tCKE		= 3,
+	.tCKESR		= 3,
+	.tFAW		= 8
+};
+EXPORT_SYMBOL_GPL(lpddr2_jedec_min_tck);
diff --git a/lib/kobject.c b/lib/kobject.c
index aeefa8b..e07ee1f 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -47,13 +47,11 @@
 static int create_dir(struct kobject *kobj)
 {
 	int error = 0;
-	if (kobject_name(kobj)) {
-		error = sysfs_create_dir(kobj);
-		if (!error) {
-			error = populate_dir(kobj);
-			if (error)
-				sysfs_remove_dir(kobj);
-		}
+	error = sysfs_create_dir(kobj);
+	if (!error) {
+		error = populate_dir(kobj);
+		if (error)
+			sysfs_remove_dir(kobj);
 	}
 	return error;
 }
@@ -634,7 +632,7 @@
 /**
  * kobject_create_and_add - create a struct kobject dynamically and register it with sysfs
  *
- * @name: the name for the kset
+ * @name: the name for the kobject
  * @parent: the parent kobject of this kobject, if any.
  *
  * This function creates a kobject structure dynamically and registers it
diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile
index 8a38102..de06dfe 100644
--- a/lib/raid6/Makefile
+++ b/lib/raid6/Makefile
@@ -1,6 +1,6 @@
 obj-$(CONFIG_RAID6_PQ)	+= raid6_pq.o
 
-raid6_pq-y	+= algos.o recov.o tables.o int1.o int2.o int4.o \
+raid6_pq-y	+= algos.o recov.o recov_ssse3.o tables.o int1.o int2.o int4.o \
 		   int8.o int16.o int32.o altivec1.o altivec2.o altivec4.o \
 		   altivec8.o mmx.o sse1.o sse2.o
 hostprogs-y	+= mktables
diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index 8b02f60..589f5f5 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -17,11 +17,11 @@
  */
 
 #include <linux/raid/pq.h>
-#include <linux/module.h>
 #ifndef __KERNEL__
 #include <sys/mman.h>
 #include <stdio.h>
 #else
+#include <linux/module.h>
 #include <linux/gfp.h>
 #if !RAID6_USE_EMPTY_ZERO_PAGE
 /* In .bss so it's zeroed */
@@ -34,10 +34,6 @@
 EXPORT_SYMBOL_GPL(raid6_call);
 
 const struct raid6_calls * const raid6_algos[] = {
-	&raid6_intx1,
-	&raid6_intx2,
-	&raid6_intx4,
-	&raid6_intx8,
 #if defined(__ia64__)
 	&raid6_intx16,
 	&raid6_intx32,
@@ -61,6 +57,24 @@
 	&raid6_altivec4,
 	&raid6_altivec8,
 #endif
+	&raid6_intx1,
+	&raid6_intx2,
+	&raid6_intx4,
+	&raid6_intx8,
+	NULL
+};
+
+void (*raid6_2data_recov)(int, size_t, int, int, void **);
+EXPORT_SYMBOL_GPL(raid6_2data_recov);
+
+void (*raid6_datap_recov)(int, size_t, int, void **);
+EXPORT_SYMBOL_GPL(raid6_datap_recov);
+
+const struct raid6_recov_calls *const raid6_recov_algos[] = {
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
+	&raid6_recov_ssse3,
+#endif
+	&raid6_recov_intx1,
 	NULL
 };
 
@@ -72,59 +86,55 @@
 #define time_before(x, y) ((x) < (y))
 #endif
 
-/* Try to pick the best algorithm */
-/* This code uses the gfmul table as convenient data set to abuse */
-
-int __init raid6_select_algo(void)
+static inline const struct raid6_recov_calls *raid6_choose_recov(void)
 {
-	const struct raid6_calls * const * algo;
-	const struct raid6_calls * best;
-	char *syndromes;
-	void *dptrs[(65536/PAGE_SIZE)+2];
-	int i, disks;
-	unsigned long perf, bestperf;
-	int bestprefer;
-	unsigned long j0, j1;
+	const struct raid6_recov_calls *const *algo;
+	const struct raid6_recov_calls *best;
 
-	disks = (65536/PAGE_SIZE)+2;
-	for ( i = 0 ; i < disks-2 ; i++ ) {
-		dptrs[i] = ((char *)raid6_gfmul) + PAGE_SIZE*i;
-	}
+	for (best = NULL, algo = raid6_recov_algos; *algo; algo++)
+		if (!best || (*algo)->priority > best->priority)
+			if (!(*algo)->valid || (*algo)->valid())
+				best = *algo;
 
-	/* Normal code - use a 2-page allocation to avoid D$ conflict */
-	syndromes = (void *) __get_free_pages(GFP_KERNEL, 1);
+	if (best) {
+		raid6_2data_recov = best->data2;
+		raid6_datap_recov = best->datap;
 
-	if ( !syndromes ) {
-		printk("raid6: Yikes!  No memory available.\n");
-		return -ENOMEM;
-	}
+		printk("raid6: using %s recovery algorithm\n", best->name);
+	} else
+		printk("raid6: Yikes! No recovery algorithm found!\n");
 
-	dptrs[disks-2] = syndromes;
-	dptrs[disks-1] = syndromes + PAGE_SIZE;
+	return best;
+}
 
-	bestperf = 0;  bestprefer = 0;  best = NULL;
+static inline const struct raid6_calls *raid6_choose_gen(
+	void *(*const dptrs)[(65536/PAGE_SIZE)+2], const int disks)
+{
+	unsigned long perf, bestperf, j0, j1;
+	const struct raid6_calls *const *algo;
+	const struct raid6_calls *best;
 
-	for ( algo = raid6_algos ; *algo ; algo++ ) {
-		if ( !(*algo)->valid || (*algo)->valid() ) {
+	for (bestperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) {
+		if (!best || (*algo)->prefer >= best->prefer) {
+			if ((*algo)->valid && !(*algo)->valid())
+				continue;
+
 			perf = 0;
 
 			preempt_disable();
 			j0 = jiffies;
-			while ( (j1 = jiffies) == j0 )
+			while ((j1 = jiffies) == j0)
 				cpu_relax();
 			while (time_before(jiffies,
 					    j1 + (1<<RAID6_TIME_JIFFIES_LG2))) {
-				(*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs);
+				(*algo)->gen_syndrome(disks, PAGE_SIZE, *dptrs);
 				perf++;
 			}
 			preempt_enable();
 
-			if ( (*algo)->prefer > bestprefer ||
-			     ((*algo)->prefer == bestprefer &&
-			      perf > bestperf) ) {
-				best = *algo;
-				bestprefer = best->prefer;
+			if (perf > bestperf) {
 				bestperf = perf;
+				best = *algo;
 			}
 			printk("raid6: %-8s %5ld MB/s\n", (*algo)->name,
 			       (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2));
@@ -139,9 +149,46 @@
 	} else
 		printk("raid6: Yikes!  No algorithm found!\n");
 
+	return best;
+}
+
+
+/* Try to pick the best algorithm */
+/* This code uses the gfmul table as convenient data set to abuse */
+
+int __init raid6_select_algo(void)
+{
+	const int disks = (65536/PAGE_SIZE)+2;
+
+	const struct raid6_calls *gen_best;
+	const struct raid6_recov_calls *rec_best;
+	char *syndromes;
+	void *dptrs[(65536/PAGE_SIZE)+2];
+	int i;
+
+	for (i = 0; i < disks-2; i++)
+		dptrs[i] = ((char *)raid6_gfmul) + PAGE_SIZE*i;
+
+	/* Normal code - use a 2-page allocation to avoid D$ conflict */
+	syndromes = (void *) __get_free_pages(GFP_KERNEL, 1);
+
+	if (!syndromes) {
+		printk("raid6: Yikes!  No memory available.\n");
+		return -ENOMEM;
+	}
+
+	dptrs[disks-2] = syndromes;
+	dptrs[disks-1] = syndromes + PAGE_SIZE;
+
+	/* select raid gen_syndrome function */
+	gen_best = raid6_choose_gen(&dptrs, disks);
+
+	/* select raid recover functions */
+	rec_best = raid6_choose_recov();
+
 	free_pages((unsigned long)syndromes, 1);
 
-	return best ? 0 : -EINVAL;
+	return gen_best && rec_best ? 0 : -EINVAL;
 }
 
 static void raid6_exit(void)
diff --git a/lib/raid6/mktables.c b/lib/raid6/mktables.c
index 8a37809..39787db 100644
--- a/lib/raid6/mktables.c
+++ b/lib/raid6/mktables.c
@@ -81,6 +81,31 @@
 	printf("EXPORT_SYMBOL(raid6_gfmul);\n");
 	printf("#endif\n");
 
+	/* Compute vector multiplication table */
+	printf("\nconst u8  __attribute__((aligned(256)))\n"
+		"raid6_vgfmul[256][32] =\n"
+		"{\n");
+	for (i = 0; i < 256; i++) {
+		printf("\t{\n");
+		for (j = 0; j < 16; j += 8) {
+			printf("\t\t");
+			for (k = 0; k < 8; k++)
+				printf("0x%02x,%c", gfmul(i, j + k),
+				       (k == 7) ? '\n' : ' ');
+		}
+		for (j = 0; j < 16; j += 8) {
+			printf("\t\t");
+			for (k = 0; k < 8; k++)
+				printf("0x%02x,%c", gfmul(i, (j + k) << 4),
+				       (k == 7) ? '\n' : ' ');
+		}
+		printf("\t},\n");
+	}
+	printf("};\n");
+	printf("#ifdef __KERNEL__\n");
+	printf("EXPORT_SYMBOL(raid6_vgfmul);\n");
+	printf("#endif\n");
+
 	/* Compute power-of-2 table (exponent) */
 	v = 1;
 	printf("\nconst u8 __attribute__((aligned(256)))\n"
diff --git a/lib/raid6/recov.c b/lib/raid6/recov.c
index fe275d7..1805a5c 100644
--- a/lib/raid6/recov.c
+++ b/lib/raid6/recov.c
@@ -22,7 +22,7 @@
 #include <linux/raid/pq.h>
 
 /* Recover two failed data blocks. */
-void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
+void raid6_2data_recov_intx1(int disks, size_t bytes, int faila, int failb,
 		       void **ptrs)
 {
 	u8 *p, *q, *dp, *dq;
@@ -64,10 +64,9 @@
 		p++; q++;
 	}
 }
-EXPORT_SYMBOL_GPL(raid6_2data_recov);
 
 /* Recover failure of one data block plus the P block */
-void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs)
+void raid6_datap_recov_intx1(int disks, size_t bytes, int faila, void **ptrs)
 {
 	u8 *p, *q, *dq;
 	const u8 *qmul;		/* Q multiplier table */
@@ -96,7 +95,15 @@
 		q++; dq++;
 	}
 }
-EXPORT_SYMBOL_GPL(raid6_datap_recov);
+
+
+const struct raid6_recov_calls raid6_recov_intx1 = {
+	.data2 = raid6_2data_recov_intx1,
+	.datap = raid6_datap_recov_intx1,
+	.valid = NULL,
+	.name = "intx1",
+	.priority = 0,
+};
 
 #ifndef __KERNEL__
 /* Testing only */
diff --git a/lib/raid6/recov_ssse3.c b/lib/raid6/recov_ssse3.c
new file mode 100644
index 0000000..37ae619
--- /dev/null
+++ b/lib/raid6/recov_ssse3.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
+
+#include <linux/raid/pq.h>
+#include "x86.h"
+
+static int raid6_has_ssse3(void)
+{
+	return boot_cpu_has(X86_FEATURE_XMM) &&
+		boot_cpu_has(X86_FEATURE_XMM2) &&
+		boot_cpu_has(X86_FEATURE_SSSE3);
+}
+
+void raid6_2data_recov_ssse3(int disks, size_t bytes, int faila, int failb,
+		       void **ptrs)
+{
+	u8 *p, *q, *dp, *dq;
+	const u8 *pbmul;	/* P multiplier table for B data */
+	const u8 *qmul;		/* Q multiplier table (for both) */
+	static const u8 __aligned(16) x0f[16] = {
+		 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+		 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f};
+
+	p = (u8 *)ptrs[disks-2];
+	q = (u8 *)ptrs[disks-1];
+
+	/* Compute syndrome with zero for the missing data pages
+	   Use the dead data pages as temporary storage for
+	   delta p and delta q */
+	dp = (u8 *)ptrs[faila];
+	ptrs[faila] = (void *)raid6_empty_zero_page;
+	ptrs[disks-2] = dp;
+	dq = (u8 *)ptrs[failb];
+	ptrs[failb] = (void *)raid6_empty_zero_page;
+	ptrs[disks-1] = dq;
+
+	raid6_call.gen_syndrome(disks, bytes, ptrs);
+
+	/* Restore pointer table */
+	ptrs[faila]   = dp;
+	ptrs[failb]   = dq;
+	ptrs[disks-2] = p;
+	ptrs[disks-1] = q;
+
+	/* Now, pick the proper data tables */
+	pbmul = raid6_vgfmul[raid6_gfexi[failb-faila]];
+	qmul  = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^
+		raid6_gfexp[failb]]];
+
+	kernel_fpu_begin();
+
+	asm volatile("movdqa %0,%%xmm7" : : "m" (x0f[0]));
+
+#ifdef CONFIG_X86_64
+	asm volatile("movdqa %0,%%xmm6" : : "m" (qmul[0]));
+	asm volatile("movdqa %0,%%xmm14" : : "m" (pbmul[0]));
+	asm volatile("movdqa %0,%%xmm15" : : "m" (pbmul[16]));
+#endif
+
+	/* Now do it... */
+	while (bytes) {
+#ifdef CONFIG_X86_64
+		/* xmm6, xmm14, xmm15 */
+
+		asm volatile("movdqa %0,%%xmm1" : : "m" (q[0]));
+		asm volatile("movdqa %0,%%xmm9" : : "m" (q[16]));
+		asm volatile("movdqa %0,%%xmm0" : : "m" (p[0]));
+		asm volatile("movdqa %0,%%xmm8" : : "m" (p[16]));
+		asm volatile("pxor   %0,%%xmm1" : : "m" (dq[0]));
+		asm volatile("pxor   %0,%%xmm9" : : "m" (dq[16]));
+		asm volatile("pxor   %0,%%xmm0" : : "m" (dp[0]));
+		asm volatile("pxor   %0,%%xmm8" : : "m" (dp[16]));
+
+		/* xmm0/8 = px */
+
+		asm volatile("movdqa %xmm6,%xmm4");
+		asm volatile("movdqa %0,%%xmm5" : : "m" (qmul[16]));
+		asm volatile("movdqa %xmm6,%xmm12");
+		asm volatile("movdqa %xmm5,%xmm13");
+		asm volatile("movdqa %xmm1,%xmm3");
+		asm volatile("movdqa %xmm9,%xmm11");
+		asm volatile("movdqa %xmm0,%xmm2"); /* xmm2/10 = px */
+		asm volatile("movdqa %xmm8,%xmm10");
+		asm volatile("psraw  $4,%xmm1");
+		asm volatile("psraw  $4,%xmm9");
+		asm volatile("pand   %xmm7,%xmm3");
+		asm volatile("pand   %xmm7,%xmm11");
+		asm volatile("pand   %xmm7,%xmm1");
+		asm volatile("pand   %xmm7,%xmm9");
+		asm volatile("pshufb %xmm3,%xmm4");
+		asm volatile("pshufb %xmm11,%xmm12");
+		asm volatile("pshufb %xmm1,%xmm5");
+		asm volatile("pshufb %xmm9,%xmm13");
+		asm volatile("pxor   %xmm4,%xmm5");
+		asm volatile("pxor   %xmm12,%xmm13");
+
+		/* xmm5/13 = qx */
+
+		asm volatile("movdqa %xmm14,%xmm4");
+		asm volatile("movdqa %xmm15,%xmm1");
+		asm volatile("movdqa %xmm14,%xmm12");
+		asm volatile("movdqa %xmm15,%xmm9");
+		asm volatile("movdqa %xmm2,%xmm3");
+		asm volatile("movdqa %xmm10,%xmm11");
+		asm volatile("psraw  $4,%xmm2");
+		asm volatile("psraw  $4,%xmm10");
+		asm volatile("pand   %xmm7,%xmm3");
+		asm volatile("pand   %xmm7,%xmm11");
+		asm volatile("pand   %xmm7,%xmm2");
+		asm volatile("pand   %xmm7,%xmm10");
+		asm volatile("pshufb %xmm3,%xmm4");
+		asm volatile("pshufb %xmm11,%xmm12");
+		asm volatile("pshufb %xmm2,%xmm1");
+		asm volatile("pshufb %xmm10,%xmm9");
+		asm volatile("pxor   %xmm4,%xmm1");
+		asm volatile("pxor   %xmm12,%xmm9");
+
+		/* xmm1/9 = pbmul[px] */
+		asm volatile("pxor   %xmm5,%xmm1");
+		asm volatile("pxor   %xmm13,%xmm9");
+		/* xmm1/9 = db = DQ */
+		asm volatile("movdqa %%xmm1,%0" : "=m" (dq[0]));
+		asm volatile("movdqa %%xmm9,%0" : "=m" (dq[16]));
+
+		asm volatile("pxor   %xmm1,%xmm0");
+		asm volatile("pxor   %xmm9,%xmm8");
+		asm volatile("movdqa %%xmm0,%0" : "=m" (dp[0]));
+		asm volatile("movdqa %%xmm8,%0" : "=m" (dp[16]));
+
+		bytes -= 32;
+		p += 32;
+		q += 32;
+		dp += 32;
+		dq += 32;
+#else
+		asm volatile("movdqa %0,%%xmm1" : : "m" (*q));
+		asm volatile("movdqa %0,%%xmm0" : : "m" (*p));
+		asm volatile("pxor   %0,%%xmm1" : : "m" (*dq));
+		asm volatile("pxor   %0,%%xmm0" : : "m" (*dp));
+
+		/* 1 = dq ^ q
+		 * 0 = dp ^ p
+		 */
+		asm volatile("movdqa %0,%%xmm4" : : "m" (qmul[0]));
+		asm volatile("movdqa %0,%%xmm5" : : "m" (qmul[16]));
+
+		asm volatile("movdqa %xmm1,%xmm3");
+		asm volatile("psraw  $4,%xmm1");
+		asm volatile("pand   %xmm7,%xmm3");
+		asm volatile("pand   %xmm7,%xmm1");
+		asm volatile("pshufb %xmm3,%xmm4");
+		asm volatile("pshufb %xmm1,%xmm5");
+		asm volatile("pxor   %xmm4,%xmm5");
+
+		asm volatile("movdqa %xmm0,%xmm2"); /* xmm2 = px */
+
+		/* xmm5 = qx */
+
+		asm volatile("movdqa %0,%%xmm4" : : "m" (pbmul[0]));
+		asm volatile("movdqa %0,%%xmm1" : : "m" (pbmul[16]));
+		asm volatile("movdqa %xmm2,%xmm3");
+		asm volatile("psraw  $4,%xmm2");
+		asm volatile("pand   %xmm7,%xmm3");
+		asm volatile("pand   %xmm7,%xmm2");
+		asm volatile("pshufb %xmm3,%xmm4");
+		asm volatile("pshufb %xmm2,%xmm1");
+		asm volatile("pxor   %xmm4,%xmm1");
+
+		/* xmm1 = pbmul[px] */
+		asm volatile("pxor   %xmm5,%xmm1");
+		/* xmm1 = db = DQ */
+		asm volatile("movdqa %%xmm1,%0" : "=m" (*dq));
+
+		asm volatile("pxor   %xmm1,%xmm0");
+		asm volatile("movdqa %%xmm0,%0" : "=m" (*dp));
+
+		bytes -= 16;
+		p += 16;
+		q += 16;
+		dp += 16;
+		dq += 16;
+#endif
+	}
+
+	kernel_fpu_end();
+}
+
+
+void raid6_datap_recov_ssse3(int disks, size_t bytes, int faila, void **ptrs)
+{
+	u8 *p, *q, *dq;
+	const u8 *qmul;		/* Q multiplier table */
+	static const u8 __aligned(16) x0f[16] = {
+		 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+		 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f};
+
+	p = (u8 *)ptrs[disks-2];
+	q = (u8 *)ptrs[disks-1];
+
+	/* Compute syndrome with zero for the missing data page
+	   Use the dead data page as temporary storage for delta q */
+	dq = (u8 *)ptrs[faila];
+	ptrs[faila] = (void *)raid6_empty_zero_page;
+	ptrs[disks-1] = dq;
+
+	raid6_call.gen_syndrome(disks, bytes, ptrs);
+
+	/* Restore pointer table */
+	ptrs[faila]   = dq;
+	ptrs[disks-1] = q;
+
+	/* Now, pick the proper data tables */
+	qmul  = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]];
+
+	kernel_fpu_begin();
+
+	asm volatile("movdqa %0, %%xmm7" : : "m" (x0f[0]));
+
+	while (bytes) {
+#ifdef CONFIG_X86_64
+		asm volatile("movdqa %0, %%xmm3" : : "m" (dq[0]));
+		asm volatile("movdqa %0, %%xmm4" : : "m" (dq[16]));
+		asm volatile("pxor %0, %%xmm3" : : "m" (q[0]));
+		asm volatile("movdqa %0, %%xmm0" : : "m" (qmul[0]));
+
+		/* xmm3 = q[0] ^ dq[0] */
+
+		asm volatile("pxor %0, %%xmm4" : : "m" (q[16]));
+		asm volatile("movdqa %0, %%xmm1" : : "m" (qmul[16]));
+
+		/* xmm4 = q[16] ^ dq[16] */
+
+		asm volatile("movdqa %xmm3, %xmm6");
+		asm volatile("movdqa %xmm4, %xmm8");
+
+		/* xmm4 = xmm8 = q[16] ^ dq[16] */
+
+		asm volatile("psraw $4, %xmm3");
+		asm volatile("pand %xmm7, %xmm6");
+		asm volatile("pand %xmm7, %xmm3");
+		asm volatile("pshufb %xmm6, %xmm0");
+		asm volatile("pshufb %xmm3, %xmm1");
+		asm volatile("movdqa %0, %%xmm10" : : "m" (qmul[0]));
+		asm volatile("pxor %xmm0, %xmm1");
+		asm volatile("movdqa %0, %%xmm11" : : "m" (qmul[16]));
+
+		/* xmm1 = qmul[q[0] ^ dq[0]] */
+
+		asm volatile("psraw $4, %xmm4");
+		asm volatile("pand %xmm7, %xmm8");
+		asm volatile("pand %xmm7, %xmm4");
+		asm volatile("pshufb %xmm8, %xmm10");
+		asm volatile("pshufb %xmm4, %xmm11");
+		asm volatile("movdqa %0, %%xmm2" : : "m" (p[0]));
+		asm volatile("pxor %xmm10, %xmm11");
+		asm volatile("movdqa %0, %%xmm12" : : "m" (p[16]));
+
+		/* xmm11 = qmul[q[16] ^ dq[16]] */
+
+		asm volatile("pxor %xmm1, %xmm2");
+
+		/* xmm2 = p[0] ^ qmul[q[0] ^ dq[0]] */
+
+		asm volatile("pxor %xmm11, %xmm12");
+
+		/* xmm12 = p[16] ^ qmul[q[16] ^ dq[16]] */
+
+		asm volatile("movdqa %%xmm1, %0" : "=m" (dq[0]));
+		asm volatile("movdqa %%xmm11, %0" : "=m" (dq[16]));
+
+		asm volatile("movdqa %%xmm2, %0" : "=m" (p[0]));
+		asm volatile("movdqa %%xmm12, %0" : "=m" (p[16]));
+
+		bytes -= 32;
+		p += 32;
+		q += 32;
+		dq += 32;
+
+#else
+		asm volatile("movdqa %0, %%xmm3" : : "m" (dq[0]));
+		asm volatile("movdqa %0, %%xmm0" : : "m" (qmul[0]));
+		asm volatile("pxor %0, %%xmm3" : : "m" (q[0]));
+		asm volatile("movdqa %0, %%xmm1" : : "m" (qmul[16]));
+
+		/* xmm3 = *q ^ *dq */
+
+		asm volatile("movdqa %xmm3, %xmm6");
+		asm volatile("movdqa %0, %%xmm2" : : "m" (p[0]));
+		asm volatile("psraw $4, %xmm3");
+		asm volatile("pand %xmm7, %xmm6");
+		asm volatile("pand %xmm7, %xmm3");
+		asm volatile("pshufb %xmm6, %xmm0");
+		asm volatile("pshufb %xmm3, %xmm1");
+		asm volatile("pxor %xmm0, %xmm1");
+
+		/* xmm1 = qmul[*q ^ *dq */
+
+		asm volatile("pxor %xmm1, %xmm2");
+
+		/* xmm2 = *p ^ qmul[*q ^ *dq] */
+
+		asm volatile("movdqa %%xmm1, %0" : "=m" (dq[0]));
+		asm volatile("movdqa %%xmm2, %0" : "=m" (p[0]));
+
+		bytes -= 16;
+		p += 16;
+		q += 16;
+		dq += 16;
+#endif
+	}
+
+	kernel_fpu_end();
+}
+
+const struct raid6_recov_calls raid6_recov_ssse3 = {
+	.data2 = raid6_2data_recov_ssse3,
+	.datap = raid6_datap_recov_ssse3,
+	.valid = raid6_has_ssse3,
+#ifdef CONFIG_X86_64
+	.name = "ssse3x2",
+#else
+	.name = "ssse3x1",
+#endif
+	.priority = 1,
+};
+
+#endif
diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile
index aa65169..c76151d 100644
--- a/lib/raid6/test/Makefile
+++ b/lib/raid6/test/Makefile
@@ -23,7 +23,7 @@
 all:	raid6.a raid6test
 
 raid6.a: int1.o int2.o int4.o int8.o int16.o int32.o mmx.o sse1.o sse2.o \
-	 altivec1.o altivec2.o altivec4.o altivec8.o recov.o algos.o \
+	 altivec1.o altivec2.o altivec4.o altivec8.o recov.o recov_ssse3.o algos.o \
 	 tables.o
 	 rm -f $@
 	 $(AR) cq $@ $^
diff --git a/lib/raid6/test/test.c b/lib/raid6/test/test.c
index 7a93031..5a485b7 100644
--- a/lib/raid6/test/test.c
+++ b/lib/raid6/test/test.c
@@ -90,25 +90,35 @@
 int main(int argc, char *argv[])
 {
 	const struct raid6_calls *const *algo;
+	const struct raid6_recov_calls *const *ra;
 	int i, j;
 	int err = 0;
 
 	makedata();
 
-	for (algo = raid6_algos; *algo; algo++) {
-		if (!(*algo)->valid || (*algo)->valid()) {
-			raid6_call = **algo;
+	for (ra = raid6_recov_algos; *ra; ra++) {
+		if ((*ra)->valid  && !(*ra)->valid())
+			continue;
+		raid6_2data_recov = (*ra)->data2;
+		raid6_datap_recov = (*ra)->datap;
 
-			/* Nuke syndromes */
-			memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE);
+		printf("using recovery %s\n", (*ra)->name);
 
-			/* Generate assumed good syndrome */
-			raid6_call.gen_syndrome(NDISKS, PAGE_SIZE,
-						(void **)&dataptrs);
+		for (algo = raid6_algos; *algo; algo++) {
+			if (!(*algo)->valid || (*algo)->valid()) {
+				raid6_call = **algo;
 
-			for (i = 0; i < NDISKS-1; i++)
-				for (j = i+1; j < NDISKS; j++)
-					err += test_disks(i, j);
+				/* Nuke syndromes */
+				memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE);
+
+				/* Generate assumed good syndrome */
+				raid6_call.gen_syndrome(NDISKS, PAGE_SIZE,
+							(void **)&dataptrs);
+
+				for (i = 0; i < NDISKS-1; i++)
+					for (j = i+1; j < NDISKS; j++)
+						err += test_disks(i, j);
+			}
 		}
 		printf("\n");
 	}
diff --git a/lib/raid6/x86.h b/lib/raid6/x86.h
index cb2a8c9..d55d632 100644
--- a/lib/raid6/x86.h
+++ b/lib/raid6/x86.h
@@ -35,24 +35,29 @@
 {
 }
 
+#define __aligned(x) __attribute__((aligned(x)))
+
 #define X86_FEATURE_MMX		(0*32+23) /* Multimedia Extensions */
 #define X86_FEATURE_FXSR	(0*32+24) /* FXSAVE and FXRSTOR instructions
 					   * (fast save and restore) */
 #define X86_FEATURE_XMM		(0*32+25) /* Streaming SIMD Extensions */
 #define X86_FEATURE_XMM2	(0*32+26) /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_XMM3	(4*32+ 0) /* "pni" SSE-3 */
+#define X86_FEATURE_SSSE3	(4*32+ 9) /* Supplemental SSE-3 */
+#define X86_FEATURE_AVX	(4*32+28) /* Advanced Vector Extensions */
 #define X86_FEATURE_MMXEXT	(1*32+22) /* AMD MMX extensions */
 
 /* Should work well enough on modern CPUs for testing */
 static inline int boot_cpu_has(int flag)
 {
-	u32 eax = (flag >> 5) ? 0x80000001 : 1;
-	u32 edx;
+	u32 eax = (flag & 0x20) ? 0x80000001 : 1;
+	u32 ecx, edx;
 
 	asm volatile("cpuid"
-		     : "+a" (eax), "=d" (edx)
-		     : : "ecx", "ebx");
+		     : "+a" (eax), "=d" (edx), "=c" (ecx)
+		     : : "ebx");
 
-	return (edx >> (flag & 31)) & 1;
+	return ((flag & 0x80 ? ecx : edx) >> (flag & 31)) & 1;
 }
 
 #endif /* ndef __KERNEL__ */
diff --git a/lib/rational.c b/lib/rational.c
index d326da3..f0aa21c 100644
--- a/lib/rational.c
+++ b/lib/rational.c
@@ -1,7 +1,7 @@
 /*
  * rational fractions
  *
- * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <os@emlix.com>
+ * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
  *
  * helper functions when coping with rational numbers
  */
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7685d4a..f342778 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -3873,14 +3873,21 @@
 	return val << PAGE_SHIFT;
 }
 
-static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
+static ssize_t mem_cgroup_read(struct cgroup *cont, struct cftype *cft,
+			       struct file *file, char __user *buf,
+			       size_t nbytes, loff_t *ppos)
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	char str[64];
 	u64 val;
-	int type, name;
+	int type, name, len;
 
 	type = MEMFILE_TYPE(cft->private);
 	name = MEMFILE_ATTR(cft->private);
+
+	if (!do_swap_account && type == _MEMSWAP)
+		return -EOPNOTSUPP;
+
 	switch (type) {
 	case _MEM:
 		if (name == RES_USAGE)
@@ -3897,7 +3904,9 @@
 	default:
 		BUG();
 	}
-	return val;
+
+	len = scnprintf(str, sizeof(str), "%llu\n", (unsigned long long)val);
+	return simple_read_from_buffer(buf, nbytes, ppos, str, len);
 }
 /*
  * The user of this function is...
@@ -3913,6 +3922,10 @@
 
 	type = MEMFILE_TYPE(cft->private);
 	name = MEMFILE_ATTR(cft->private);
+
+	if (!do_swap_account && type == _MEMSWAP)
+		return -EOPNOTSUPP;
+
 	switch (name) {
 	case RES_LIMIT:
 		if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */
@@ -3978,12 +3991,15 @@
 
 static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
 {
-	struct mem_cgroup *memcg;
+	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
 	int type, name;
 
-	memcg = mem_cgroup_from_cont(cont);
 	type = MEMFILE_TYPE(event);
 	name = MEMFILE_ATTR(event);
+
+	if (!do_swap_account && type == _MEMSWAP)
+		return -EOPNOTSUPP;
+
 	switch (name) {
 	case RES_MAX_USAGE:
 		if (type == _MEM)
@@ -4624,29 +4640,22 @@
 #endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
-static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss)
+static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
 {
-	/*
-	 * Part of this would be better living in a separate allocation
-	 * function, leaving us with just the cgroup tree population work.
-	 * We, however, depend on state such as network's proto_list that
-	 * is only initialized after cgroup creation. I found the less
-	 * cumbersome way to deal with it to defer it all to populate time
-	 */
-	return mem_cgroup_sockets_init(cont, ss);
+	return mem_cgroup_sockets_init(memcg, ss);
 };
 
-static void kmem_cgroup_destroy(struct cgroup *cont)
+static void kmem_cgroup_destroy(struct mem_cgroup *memcg)
 {
-	mem_cgroup_sockets_destroy(cont);
+	mem_cgroup_sockets_destroy(memcg);
 }
 #else
-static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss)
+static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
 {
 	return 0;
 }
 
-static void kmem_cgroup_destroy(struct cgroup *cont)
+static void kmem_cgroup_destroy(struct mem_cgroup *memcg)
 {
 }
 #endif
@@ -4655,7 +4664,7 @@
 	{
 		.name = "usage_in_bytes",
 		.private = MEMFILE_PRIVATE(_MEM, RES_USAGE),
-		.read_u64 = mem_cgroup_read,
+		.read = mem_cgroup_read,
 		.register_event = mem_cgroup_usage_register_event,
 		.unregister_event = mem_cgroup_usage_unregister_event,
 	},
@@ -4663,25 +4672,25 @@
 		.name = "max_usage_in_bytes",
 		.private = MEMFILE_PRIVATE(_MEM, RES_MAX_USAGE),
 		.trigger = mem_cgroup_reset,
-		.read_u64 = mem_cgroup_read,
+		.read = mem_cgroup_read,
 	},
 	{
 		.name = "limit_in_bytes",
 		.private = MEMFILE_PRIVATE(_MEM, RES_LIMIT),
 		.write_string = mem_cgroup_write,
-		.read_u64 = mem_cgroup_read,
+		.read = mem_cgroup_read,
 	},
 	{
 		.name = "soft_limit_in_bytes",
 		.private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT),
 		.write_string = mem_cgroup_write,
-		.read_u64 = mem_cgroup_read,
+		.read = mem_cgroup_read,
 	},
 	{
 		.name = "failcnt",
 		.private = MEMFILE_PRIVATE(_MEM, RES_FAILCNT),
 		.trigger = mem_cgroup_reset,
-		.read_u64 = mem_cgroup_read,
+		.read = mem_cgroup_read,
 	},
 	{
 		.name = "stat",
@@ -4721,14 +4730,11 @@
 		.mode = S_IRUGO,
 	},
 #endif
-};
-
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
-static struct cftype memsw_cgroup_files[] = {
 	{
 		.name = "memsw.usage_in_bytes",
 		.private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE),
-		.read_u64 = mem_cgroup_read,
+		.read = mem_cgroup_read,
 		.register_event = mem_cgroup_usage_register_event,
 		.unregister_event = mem_cgroup_usage_unregister_event,
 	},
@@ -4736,35 +4742,23 @@
 		.name = "memsw.max_usage_in_bytes",
 		.private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE),
 		.trigger = mem_cgroup_reset,
-		.read_u64 = mem_cgroup_read,
+		.read = mem_cgroup_read,
 	},
 	{
 		.name = "memsw.limit_in_bytes",
 		.private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT),
 		.write_string = mem_cgroup_write,
-		.read_u64 = mem_cgroup_read,
+		.read = mem_cgroup_read,
 	},
 	{
 		.name = "memsw.failcnt",
 		.private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT),
 		.trigger = mem_cgroup_reset,
-		.read_u64 = mem_cgroup_read,
+		.read = mem_cgroup_read,
 	},
-};
-
-static int register_memsw_files(struct cgroup *cont, struct cgroup_subsys *ss)
-{
-	if (!do_swap_account)
-		return 0;
-	return cgroup_add_files(cont, ss, memsw_cgroup_files,
-				ARRAY_SIZE(memsw_cgroup_files));
-};
-#else
-static int register_memsw_files(struct cgroup *cont, struct cgroup_subsys *ss)
-{
-	return 0;
-}
 #endif
+	{ },	/* terminate */
+};
 
 static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
 {
@@ -5016,6 +5010,17 @@
 	memcg->move_charge_at_immigrate = 0;
 	mutex_init(&memcg->thresholds_lock);
 	spin_lock_init(&memcg->move_lock);
+
+	error = memcg_init_kmem(memcg, &mem_cgroup_subsys);
+	if (error) {
+		/*
+		 * We call put now because our (and parent's) refcnts
+		 * are already in place. mem_cgroup_put() will internally
+		 * call __mem_cgroup_free, so return directly
+		 */
+		mem_cgroup_put(memcg);
+		return ERR_PTR(error);
+	}
 	return &memcg->css;
 free_out:
 	__mem_cgroup_free(memcg);
@@ -5033,28 +5038,11 @@
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
 
-	kmem_cgroup_destroy(cont);
+	kmem_cgroup_destroy(memcg);
 
 	mem_cgroup_put(memcg);
 }
 
-static int mem_cgroup_populate(struct cgroup_subsys *ss,
-				struct cgroup *cont)
-{
-	int ret;
-
-	ret = cgroup_add_files(cont, ss, mem_cgroup_files,
-				ARRAY_SIZE(mem_cgroup_files));
-
-	if (!ret)
-		ret = register_memsw_files(cont, ss);
-
-	if (!ret)
-		ret = register_kmem_files(cont, ss);
-
-	return ret;
-}
-
 #ifdef CONFIG_MMU
 /* Handlers for move charge at task migration. */
 #define PRECHARGE_COUNT_AT_ONCE	256
@@ -5638,12 +5626,13 @@
 	.create = mem_cgroup_create,
 	.pre_destroy = mem_cgroup_pre_destroy,
 	.destroy = mem_cgroup_destroy,
-	.populate = mem_cgroup_populate,
 	.can_attach = mem_cgroup_can_attach,
 	.cancel_attach = mem_cgroup_cancel_attach,
 	.attach = mem_cgroup_move_task,
+	.base_cftypes = mem_cgroup_files,
 	.early_init = 0,
 	.use_id = 1,
+	.__DEPRECATED_clear_css_refs = true,
 };
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
diff --git a/mm/memory.c b/mm/memory.c
index 1e77da6..e40f675 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1307,6 +1307,9 @@
 	if (end <= vma->vm_start)
 		return;
 
+	if (vma->vm_file)
+		uprobe_munmap(vma, start, end);
+
 	if (unlikely(is_pfn_mapping(vma)))
 		untrack_pfn_vma(vma, 0, 0);
 
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index b195691..88f9422 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -607,27 +607,6 @@
 	return first;
 }
 
-/* Apply policy to a single VMA */
-static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new)
-{
-	int err = 0;
-	struct mempolicy *old = vma->vm_policy;
-
-	pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n",
-		 vma->vm_start, vma->vm_end, vma->vm_pgoff,
-		 vma->vm_ops, vma->vm_file,
-		 vma->vm_ops ? vma->vm_ops->set_policy : NULL);
-
-	if (vma->vm_ops && vma->vm_ops->set_policy)
-		err = vma->vm_ops->set_policy(vma, new);
-	if (!err) {
-		mpol_get(new);
-		vma->vm_policy = new;
-		mpol_put(old);
-	}
-	return err;
-}
-
 /* Step 2: apply policy to a range and do splits. */
 static int mbind_range(struct mm_struct *mm, unsigned long start,
 		       unsigned long end, struct mempolicy *new_pol)
@@ -676,9 +655,23 @@
 			if (err)
 				goto out;
 		}
-		err = policy_vma(vma, new_pol);
-		if (err)
-			goto out;
+
+		/*
+		 * Apply policy to a single VMA. The reference counting of
+		 * policy for vma_policy linkages has already been handled by
+		 * vma_merge and split_vma as necessary. If this is a shared
+		 * policy then ->set_policy will increment the reference count
+		 * for an sp node.
+		 */
+		pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n",
+			vma->vm_start, vma->vm_end, vma->vm_pgoff,
+			vma->vm_ops, vma->vm_file,
+			vma->vm_ops ? vma->vm_ops->set_policy : NULL);
+		if (vma->vm_ops && vma->vm_ops->set_policy) {
+			err = vma->vm_ops->set_policy(vma, new_pol);
+			if (err)
+				goto out;
+		}
 	}
 
  out:
@@ -1334,8 +1327,8 @@
 	 * userid as the target process.
 	 */
 	tcred = __task_cred(task);
-	if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
-	    cred->uid  != tcred->suid && cred->uid  != tcred->uid &&
+	if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
+	    !uid_eq(cred->uid,  tcred->suid) && !uid_eq(cred->uid,  tcred->uid) &&
 	    !capable(CAP_SYS_NICE)) {
 		rcu_read_unlock();
 		err = -EPERM;
diff --git a/mm/migrate.c b/mm/migrate.c
index 1107238..ab81d48 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1371,8 +1371,8 @@
 	 * userid as the target process.
 	 */
 	tcred = __task_cred(task);
-	if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
-	    cred->uid  != tcred->suid && cred->uid  != tcred->uid &&
+	if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
+	    !uid_eq(cred->uid,  tcred->suid) && !uid_eq(cred->uid,  tcred->uid) &&
 	    !capable(CAP_SYS_NICE)) {
 		rcu_read_unlock();
 		err = -EPERM;
diff --git a/mm/mmap.c b/mm/mmap.c
index 69a1889..e8dcfc7 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -30,6 +30,7 @@
 #include <linux/perf_event.h>
 #include <linux/audit.h>
 #include <linux/khugepaged.h>
+#include <linux/uprobes.h>
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
@@ -546,8 +547,15 @@
 
 	if (file) {
 		mapping = file->f_mapping;
-		if (!(vma->vm_flags & VM_NONLINEAR))
+		if (!(vma->vm_flags & VM_NONLINEAR)) {
 			root = &mapping->i_mmap;
+			uprobe_munmap(vma, vma->vm_start, vma->vm_end);
+
+			if (adjust_next)
+				uprobe_munmap(next, next->vm_start,
+							next->vm_end);
+		}
+
 		mutex_lock(&mapping->i_mmap_mutex);
 		if (insert) {
 			/*
@@ -617,8 +625,16 @@
 	if (mapping)
 		mutex_unlock(&mapping->i_mmap_mutex);
 
+	if (root) {
+		uprobe_mmap(vma);
+
+		if (adjust_next)
+			uprobe_mmap(next);
+	}
+
 	if (remove_next) {
 		if (file) {
+			uprobe_munmap(next, next->vm_start, next->vm_end);
 			fput(file);
 			if (next->vm_flags & VM_EXECUTABLE)
 				removed_exe_file_vma(mm);
@@ -638,6 +654,8 @@
 			goto again;
 		}
 	}
+	if (insert && file)
+		uprobe_mmap(insert);
 
 	validate_mm(mm);
 
@@ -1371,6 +1389,11 @@
 			mm->locked_vm += (len >> PAGE_SHIFT);
 	} else if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK))
 		make_pages_present(addr, addr + len);
+
+	if (file && uprobe_mmap(vma))
+		/* matching probes but cannot insert */
+		goto unmap_and_free_vma;
+
 	return addr;
 
 unmap_and_free_vma:
@@ -2358,6 +2381,10 @@
 	if ((vma->vm_flags & VM_ACCOUNT) &&
 	     security_vm_enough_memory_mm(mm, vma_pages(vma)))
 		return -ENOMEM;
+
+	if (vma->vm_file && uprobe_mmap(vma))
+		return -EINVAL;
+
 	vma_link(mm, vma, prev, rb_link, rb_parent);
 	return 0;
 }
@@ -2427,6 +2454,10 @@
 			new_vma->vm_pgoff = pgoff;
 			if (new_vma->vm_file) {
 				get_file(new_vma->vm_file);
+
+				if (uprobe_mmap(new_vma))
+					goto out_free_mempol;
+
 				if (vma->vm_flags & VM_EXECUTABLE)
 					added_exe_file_vma(mm);
 			}
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 46bf2ed5..9f09a1f 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -410,8 +410,8 @@
 		}
 
 		pr_info("[%5d] %5d %5d %8lu %8lu %3u     %3d         %5d %s\n",
-			task->pid, task_uid(task), task->tgid,
-			task->mm->total_vm, get_mm_rss(task->mm),
+			task->pid, from_kuid(&init_user_ns, task_uid(task)),
+			task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
 			task_cpu(task), task->signal->oom_adj,
 			task->signal->oom_score_adj, task->comm);
 		task_unlock(task);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index b7af568..1851df6 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -4763,12 +4763,12 @@
 	for (i = 0; i < MAX_NR_ZONES; i++) {
 		if (i == ZONE_MOVABLE)
 			continue;
-		printk("  %-8s ", zone_names[i]);
+		printk(KERN_CONT "  %-8s ", zone_names[i]);
 		if (arch_zone_lowest_possible_pfn[i] ==
 				arch_zone_highest_possible_pfn[i])
-			printk("empty\n");
+			printk(KERN_CONT "empty\n");
 		else
-			printk("%0#10lx -> %0#10lx\n",
+			printk(KERN_CONT "%0#10lx -> %0#10lx\n",
 				arch_zone_lowest_possible_pfn[i],
 				arch_zone_highest_possible_pfn[i]);
 	}
diff --git a/mm/shmem.c b/mm/shmem.c
index f99ff3e..d7b433a 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2075,6 +2075,8 @@
 			       bool remount)
 {
 	char *this_char, *value, *rest;
+	uid_t uid;
+	gid_t gid;
 
 	while (options != NULL) {
 		this_char = options;
@@ -2134,15 +2136,21 @@
 		} else if (!strcmp(this_char,"uid")) {
 			if (remount)
 				continue;
-			sbinfo->uid = simple_strtoul(value, &rest, 0);
+			uid = simple_strtoul(value, &rest, 0);
 			if (*rest)
 				goto bad_val;
+			sbinfo->uid = make_kuid(current_user_ns(), uid);
+			if (!uid_valid(sbinfo->uid))
+				goto bad_val;
 		} else if (!strcmp(this_char,"gid")) {
 			if (remount)
 				continue;
-			sbinfo->gid = simple_strtoul(value, &rest, 0);
+			gid = simple_strtoul(value, &rest, 0);
 			if (*rest)
 				goto bad_val;
+			sbinfo->gid = make_kgid(current_user_ns(), gid);
+			if (!gid_valid(sbinfo->gid))
+				goto bad_val;
 		} else if (!strcmp(this_char,"mpol")) {
 			if (mpol_parse_str(value, &sbinfo->mpol, 1))
 				goto bad_val;
@@ -2210,10 +2218,12 @@
 		seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
 	if (sbinfo->mode != (S_IRWXUGO | S_ISVTX))
 		seq_printf(seq, ",mode=%03ho", sbinfo->mode);
-	if (sbinfo->uid != 0)
-		seq_printf(seq, ",uid=%u", sbinfo->uid);
-	if (sbinfo->gid != 0)
-		seq_printf(seq, ",gid=%u", sbinfo->gid);
+	if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
+		seq_printf(seq, ",uid=%u",
+				from_kuid_munged(&init_user_ns, sbinfo->uid));
+	if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID))
+		seq_printf(seq, ",gid=%u",
+				from_kgid_munged(&init_user_ns, sbinfo->gid));
 	shmem_show_mpol(seq, sbinfo->mpol);
 	return 0;
 }
diff --git a/net/atm/lec.h b/net/atm/lec.h
index c730e57..a86aff9 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -55,11 +55,11 @@
  * frames.
  *
  * 1. Dix Ethernet EtherType frames encoded by placing EtherType
- *    field in h_type field. Data follows immediatelly after header.
+ *    field in h_type field. Data follows immediately after header.
  * 2. LLC Data frames whose total length, including LLC field and data,
  *    but not padding required to meet the minimum data frame length,
  *    is less than 1536(0x0600) MUST be encoded by placing that length
- *    in the h_type field. The LLC field follows header immediatelly.
+ *    in the h_type field. The LLC field follows header immediately.
  * 3. LLC data frames longer than this maximum MUST be encoded by placing
  *    the value 0 in the h_type field.
  *
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index d478be1..2c20d76 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -1195,41 +1195,16 @@
 	return err;
 }
 
-static const struct hid_device_id hidp_table[] = {
-	{ HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
-	{ }
-};
-
-static struct hid_driver hidp_driver = {
-	.name = "generic-bluetooth",
-	.id_table = hidp_table,
-};
-
 static int __init hidp_init(void)
 {
-	int ret;
-
 	BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
 
-	ret = hid_register_driver(&hidp_driver);
-	if (ret)
-		goto err;
-
-	ret = hidp_init_sockets();
-	if (ret)
-		goto err_drv;
-
-	return 0;
-err_drv:
-	hid_unregister_driver(&hidp_driver);
-err:
-	return ret;
+	return hidp_init_sockets();
 }
 
 static void __exit hidp_exit(void)
 {
 	hidp_cleanup_sockets();
-	hid_unregister_driver(&hidp_driver);
 }
 
 module_init(hidp_init);
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 4bf54b3..aa5d73b 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -48,13 +48,12 @@
 static struct tty_driver *rfcomm_tty_driver;
 
 struct rfcomm_dev {
+	struct tty_port		port;
 	struct list_head	list;
-	atomic_t		refcnt;
 
 	char			name[12];
 	int			id;
 	unsigned long		flags;
-	atomic_t		opened;
 	int			err;
 
 	bdaddr_t		src;
@@ -64,9 +63,7 @@
 	uint			modem_status;
 
 	struct rfcomm_dlc	*dlc;
-	struct tty_struct	*tty;
 	wait_queue_head_t       wait;
-	struct work_struct	wakeup_task;
 
 	struct device		*tty_dev;
 
@@ -82,11 +79,18 @@
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
 static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
 
-static void rfcomm_tty_wakeup(struct work_struct *work);
-
 /* ---- Device functions ---- */
-static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
+
+/*
+ * The reason this isn't actually a race, as you no doubt have a little voice
+ * screaming at you in your head, is that the refcount should never actually
+ * reach zero unless the device has already been taken off the list, in
+ * rfcomm_dev_del(). And if that's not true, we'll hit the BUG() in
+ * rfcomm_dev_destruct() anyway.
+ */
+static void rfcomm_dev_destruct(struct tty_port *port)
 {
+	struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
 	struct rfcomm_dlc *dlc = dev->dlc;
 
 	BT_DBG("dev %p dlc %p", dev, dlc);
@@ -113,23 +117,9 @@
 	module_put(THIS_MODULE);
 }
 
-static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
-{
-	atomic_inc(&dev->refcnt);
-}
-
-static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
-{
-	/* The reason this isn't actually a race, as you no
-	   doubt have a little voice screaming at you in your
-	   head, is that the refcount should never actually
-	   reach zero unless the device has already been taken
-	   off the list, in rfcomm_dev_del(). And if that's not
-	   true, we'll hit the BUG() in rfcomm_dev_destruct()
-	   anyway. */
-	if (atomic_dec_and_test(&dev->refcnt))
-		rfcomm_dev_destruct(dev);
-}
+static const struct tty_port_operations rfcomm_port_ops = {
+	.destruct = rfcomm_dev_destruct,
+};
 
 static struct rfcomm_dev *__rfcomm_dev_get(int id)
 {
@@ -154,7 +144,7 @@
 		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
 			dev = NULL;
 		else
-			rfcomm_dev_hold(dev);
+			tty_port_get(&dev->port);
 	}
 
 	spin_unlock(&rfcomm_dev_lock);
@@ -241,7 +231,6 @@
 	sprintf(dev->name, "rfcomm%d", dev->id);
 
 	list_add(&dev->list, head);
-	atomic_set(&dev->refcnt, 1);
 
 	bacpy(&dev->src, &req->src);
 	bacpy(&dev->dst, &req->dst);
@@ -250,10 +239,9 @@
 	dev->flags = req->flags &
 		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
 
-	atomic_set(&dev->opened, 0);
-
+	tty_port_init(&dev->port);
+	dev->port.ops = &rfcomm_port_ops;
 	init_waitqueue_head(&dev->wait);
-	INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
 
 	skb_queue_head_init(&dev->pending);
 
@@ -320,18 +308,23 @@
 
 static void rfcomm_dev_del(struct rfcomm_dev *dev)
 {
+	unsigned long flags;
 	BT_DBG("dev %p", dev);
 
 	BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
 
-	if (atomic_read(&dev->opened) > 0)
+	spin_lock_irqsave(&dev->port.lock, flags);
+	if (dev->port.count > 0) {
+		spin_unlock_irqrestore(&dev->port.lock, flags);
 		return;
+	}
+	spin_unlock_irqrestore(&dev->port.lock, flags);
 
 	spin_lock(&rfcomm_dev_lock);
 	list_del_init(&dev->list);
 	spin_unlock(&rfcomm_dev_lock);
 
-	rfcomm_dev_put(dev);
+	tty_port_put(&dev->port);
 }
 
 /* ---- Send buffer ---- */
@@ -345,15 +338,16 @@
 static void rfcomm_wfree(struct sk_buff *skb)
 {
 	struct rfcomm_dev *dev = (void *) skb->sk;
+	struct tty_struct *tty = dev->port.tty;
 	atomic_sub(skb->truesize, &dev->wmem_alloc);
-	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
-		queue_work(system_nrt_wq, &dev->wakeup_task);
-	rfcomm_dev_put(dev);
+	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags) && tty)
+		tty_wakeup(tty);
+	tty_port_put(&dev->port);
 }
 
 static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
 {
-	rfcomm_dev_hold(dev);
+	tty_port_get(&dev->port);
 	atomic_add(skb->truesize, &dev->wmem_alloc);
 	skb->sk = (void *) dev;
 	skb->destructor = rfcomm_wfree;
@@ -432,7 +426,7 @@
 		return -ENODEV;
 
 	if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
-		rfcomm_dev_put(dev);
+		tty_port_put(&dev->port);
 		return -EPERM;
 	}
 
@@ -440,12 +434,12 @@
 		rfcomm_dlc_close(dev->dlc, 0);
 
 	/* Shut down TTY synchronously before freeing rfcomm_dev */
-	if (dev->tty)
-		tty_vhangup(dev->tty);
+	if (dev->port.tty)
+		tty_vhangup(dev->port.tty);
 
 	if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
 		rfcomm_dev_del(dev);
-	rfcomm_dev_put(dev);
+	tty_port_put(&dev->port);
 	return 0;
 }
 
@@ -523,7 +517,7 @@
 	if (copy_to_user(arg, &di, sizeof(di)))
 		err = -EFAULT;
 
-	rfcomm_dev_put(dev);
+	tty_port_put(&dev->port);
 	return err;
 }
 
@@ -559,7 +553,7 @@
 		return;
 	}
 
-	tty = dev->tty;
+	tty = dev->port.tty;
 	if (!tty || !skb_queue_empty(&dev->pending)) {
 		skb_queue_tail(&dev->pending, skb);
 		return;
@@ -585,13 +579,13 @@
 	wake_up_interruptible(&dev->wait);
 
 	if (dlc->state == BT_CLOSED) {
-		if (!dev->tty) {
+		if (!dev->port.tty) {
 			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
 				/* Drop DLC lock here to avoid deadlock
 				 * 1. rfcomm_dev_get will take rfcomm_dev_lock
 				 *    but in rfcomm_dev_add there's lock order:
 				 *    rfcomm_dev_lock -> dlc lock
-				 * 2. rfcomm_dev_put will deadlock if it's
+				 * 2. tty_port_put will deadlock if it's
 				 *    the last reference
 				 */
 				rfcomm_dlc_unlock(dlc);
@@ -601,11 +595,11 @@
 				}
 
 				rfcomm_dev_del(dev);
-				rfcomm_dev_put(dev);
+				tty_port_put(&dev->port);
 				rfcomm_dlc_lock(dlc);
 			}
 		} else
-			tty_hangup(dev->tty);
+			tty_hangup(dev->port.tty);
 	}
 }
 
@@ -618,8 +612,8 @@
 	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
 
 	if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {
-		if (dev->tty && !C_CLOCAL(dev->tty))
-			tty_hangup(dev->tty);
+		if (dev->port.tty && !C_CLOCAL(dev->port.tty))
+			tty_hangup(dev->port.tty);
 	}
 
 	dev->modem_status =
@@ -630,21 +624,9 @@
 }
 
 /* ---- TTY functions ---- */
-static void rfcomm_tty_wakeup(struct work_struct *work)
-{
-	struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
-								wakeup_task);
-	struct tty_struct *tty = dev->tty;
-	if (!tty)
-		return;
-
-	BT_DBG("dev %p tty %p", dev, tty);
-	tty_wakeup(tty);
-}
-
 static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
 {
-	struct tty_struct *tty = dev->tty;
+	struct tty_struct *tty = dev->port.tty;
 	struct sk_buff *skb;
 	int inserted = 0;
 
@@ -671,6 +653,7 @@
 	DECLARE_WAITQUEUE(wait, current);
 	struct rfcomm_dev *dev;
 	struct rfcomm_dlc *dlc;
+	unsigned long flags;
 	int err, id;
 
 	id = tty->index;
@@ -686,10 +669,14 @@
 		return -ENODEV;
 
 	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
-				dev->channel, atomic_read(&dev->opened));
+				dev->channel, dev->port.count);
 
-	if (atomic_inc_return(&dev->opened) > 1)
+	spin_lock_irqsave(&dev->port.lock, flags);
+	if (++dev->port.count > 1) {
+		spin_unlock_irqrestore(&dev->port.lock, flags);
 		return 0;
+	}
+	spin_unlock_irqrestore(&dev->port.lock, flags);
 
 	dlc = dev->dlc;
 
@@ -697,7 +684,7 @@
 
 	rfcomm_dlc_lock(dlc);
 	tty->driver_data = dev;
-	dev->tty = tty;
+	dev->port.tty = tty;
 	rfcomm_dlc_unlock(dlc);
 	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
 
@@ -723,9 +710,9 @@
 			break;
 		}
 
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dev->wait, &wait);
@@ -744,13 +731,17 @@
 static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
 {
 	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	unsigned long flags;
+
 	if (!dev)
 		return;
 
 	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
-						atomic_read(&dev->opened));
+						dev->port.count);
 
-	if (atomic_dec_and_test(&dev->opened)) {
+	spin_lock_irqsave(&dev->port.lock, flags);
+	if (!--dev->port.count) {
+		spin_unlock_irqrestore(&dev->port.lock, flags);
 		if (dev->tty_dev->parent)
 			device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
 
@@ -758,11 +749,10 @@
 		rfcomm_dlc_close(dev->dlc, 0);
 
 		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-		cancel_work_sync(&dev->wakeup_task);
 
 		rfcomm_dlc_lock(dev->dlc);
 		tty->driver_data = NULL;
-		dev->tty = NULL;
+		dev->port.tty = NULL;
 		rfcomm_dlc_unlock(dev->dlc);
 
 		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
@@ -770,11 +760,12 @@
 			list_del_init(&dev->list);
 			spin_unlock(&rfcomm_dev_lock);
 
-			rfcomm_dev_put(dev);
+			tty_port_put(&dev->port);
 		}
-	}
+	} else
+		spin_unlock_irqrestore(&dev->port.lock, flags);
 
-	rfcomm_dev_put(dev);
+	tty_port_put(&dev->port);
 }
 
 static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1083,7 +1074,7 @@
 		if (rfcomm_dev_get(dev->id) == NULL)
 			return;
 		rfcomm_dev_del(dev);
-		rfcomm_dev_put(dev);
+		tty_port_put(&dev->port);
 	}
 }
 
diff --git a/net/caif/Kconfig b/net/caif/Kconfig
index 936361e..d369495 100644
--- a/net/caif/Kconfig
+++ b/net/caif/Kconfig
@@ -25,7 +25,7 @@
 	bool "Enable Debug"
 	depends on CAIF
 	default n
-	--- help ---
+	---help---
 	Enable the inclusion of debug code in the CAIF stack.
 	Be aware that doing this will impact performance.
 	If unsure say N.
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index 09eda68..5b8aa2f 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -25,21 +25,6 @@
 #include <net/sock.h>
 #include <net/netprio_cgroup.h>
 
-static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp);
-static void cgrp_destroy(struct cgroup *cgrp);
-static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp);
-
-struct cgroup_subsys net_prio_subsys = {
-	.name		= "net_prio",
-	.create		= cgrp_create,
-	.destroy	= cgrp_destroy,
-	.populate	= cgrp_populate,
-#ifdef CONFIG_NETPRIO_CGROUP
-	.subsys_id	= net_prio_subsys_id,
-#endif
-	.module		= THIS_MODULE
-};
-
 #define PRIOIDX_SZ 128
 
 static unsigned long prioidx_map[PRIOIDX_SZ];
@@ -259,12 +244,19 @@
 		.read_map = read_priomap,
 		.write_string = write_priomap,
 	},
+	{ }	/* terminate */
 };
 
-static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
-{
-	return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files));
-}
+struct cgroup_subsys net_prio_subsys = {
+	.name		= "net_prio",
+	.create		= cgrp_create,
+	.destroy	= cgrp_destroy,
+#ifdef CONFIG_NETPRIO_CGROUP
+	.subsys_id	= net_prio_subsys_id,
+#endif
+	.base_cftypes	= ss_files,
+	.module		= THIS_MODULE
+};
 
 static int netprio_device_event(struct notifier_block *unused,
 				unsigned long event, void *ptr)
diff --git a/net/core/sock.c b/net/core/sock.c
index 5efcd63..653f8c0 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -143,7 +143,7 @@
 static LIST_HEAD(proto_list);
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
-int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
+int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
 {
 	struct proto *proto;
 	int ret = 0;
@@ -151,7 +151,7 @@
 	mutex_lock(&proto_list_mutex);
 	list_for_each_entry(proto, &proto_list, node) {
 		if (proto->init_cgroup) {
-			ret = proto->init_cgroup(cgrp, ss);
+			ret = proto->init_cgroup(memcg, ss);
 			if (ret)
 				goto out;
 		}
@@ -162,19 +162,19 @@
 out:
 	list_for_each_entry_continue_reverse(proto, &proto_list, node)
 		if (proto->destroy_cgroup)
-			proto->destroy_cgroup(cgrp);
+			proto->destroy_cgroup(memcg);
 	mutex_unlock(&proto_list_mutex);
 	return ret;
 }
 
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp)
+void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
 {
 	struct proto *proto;
 
 	mutex_lock(&proto_list_mutex);
 	list_for_each_entry_reverse(proto, &proto_list, node)
 		if (proto->destroy_cgroup)
-			proto->destroy_cgroup(cgrp);
+			proto->destroy_cgroup(memcg);
 	mutex_unlock(&proto_list_mutex);
 }
 #endif
@@ -813,8 +813,8 @@
 	if (cred) {
 		struct user_namespace *current_ns = current_user_ns();
 
-		ucred->uid = user_ns_map_uid(current_ns, cred, cred->euid);
-		ucred->gid = user_ns_map_gid(current_ns, cred, cred->egid);
+		ucred->uid = from_kuid(current_ns, cred->euid);
+		ucred->gid = from_kgid(current_ns, cred->egid);
 	}
 }
 EXPORT_SYMBOL_GPL(cred_to_ucred);
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 6e930c7..2c00e8b 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -207,17 +207,22 @@
 	gid_t range[2];
 	struct group_info *group_info = get_current_groups();
 	int i, j, count = group_info->ngroups;
+	kgid_t low, high;
 
 	inet_get_ping_group_range_net(net, range, range+1);
+	low = make_kgid(&init_user_ns, range[0]);
+	high = make_kgid(&init_user_ns, range[1]);
+	if (!gid_valid(low) || !gid_valid(high) || gid_lt(high, low))
+		return -EACCES;
+
 	if (range[0] <= group && group <= range[1])
 		return 0;
 
 	for (i = 0; i < group_info->nblocks; i++) {
 		int cp_count = min_t(int, NGROUPS_PER_BLOCK, count);
-
 		for (j = 0; j < cp_count; j++) {
-			group = group_info->blocks[i][j];
-			if (range[0] <= group && group <= range[1])
+			kgid_t gid = group_info->blocks[i][j];
+			if (gid_lte(low, gid) && gid_lte(gid, high))
 				return 0;
 		}
 
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index e795272..1517037 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -6,37 +6,6 @@
 #include <linux/memcontrol.h>
 #include <linux/module.h>
 
-static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft);
-static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
-			    const char *buffer);
-static int tcp_cgroup_reset(struct cgroup *cont, unsigned int event);
-
-static struct cftype tcp_files[] = {
-	{
-		.name = "kmem.tcp.limit_in_bytes",
-		.write_string = tcp_cgroup_write,
-		.read_u64 = tcp_cgroup_read,
-		.private = RES_LIMIT,
-	},
-	{
-		.name = "kmem.tcp.usage_in_bytes",
-		.read_u64 = tcp_cgroup_read,
-		.private = RES_USAGE,
-	},
-	{
-		.name = "kmem.tcp.failcnt",
-		.private = RES_FAILCNT,
-		.trigger = tcp_cgroup_reset,
-		.read_u64 = tcp_cgroup_read,
-	},
-	{
-		.name = "kmem.tcp.max_usage_in_bytes",
-		.private = RES_MAX_USAGE,
-		.trigger = tcp_cgroup_reset,
-		.read_u64 = tcp_cgroup_read,
-	},
-};
-
 static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto)
 {
 	return container_of(cg_proto, struct tcp_memcontrol, cg_proto);
@@ -49,7 +18,7 @@
 }
 EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure);
 
-int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
+int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
 {
 	/*
 	 * The root cgroup does not use res_counters, but rather,
@@ -59,13 +28,12 @@
 	struct res_counter *res_parent = NULL;
 	struct cg_proto *cg_proto, *parent_cg;
 	struct tcp_memcontrol *tcp;
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
 	struct mem_cgroup *parent = parent_mem_cgroup(memcg);
 	struct net *net = current->nsproxy->net_ns;
 
 	cg_proto = tcp_prot.proto_cgroup(memcg);
 	if (!cg_proto)
-		goto create_files;
+		return 0;
 
 	tcp = tcp_from_cgproto(cg_proto);
 
@@ -88,15 +56,12 @@
 	cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated;
 	cg_proto->memcg = memcg;
 
-create_files:
-	return cgroup_add_files(cgrp, ss, tcp_files,
-				ARRAY_SIZE(tcp_files));
+	return 0;
 }
 EXPORT_SYMBOL(tcp_init_cgroup);
 
-void tcp_destroy_cgroup(struct cgroup *cgrp)
+void tcp_destroy_cgroup(struct mem_cgroup *memcg)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
 	struct cg_proto *cg_proto;
 	struct tcp_memcontrol *tcp;
 	u64 val;
@@ -270,3 +235,37 @@
 
 	tcp->tcp_prot_mem[idx] = val;
 }
+
+static struct cftype tcp_files[] = {
+	{
+		.name = "kmem.tcp.limit_in_bytes",
+		.write_string = tcp_cgroup_write,
+		.read_u64 = tcp_cgroup_read,
+		.private = RES_LIMIT,
+	},
+	{
+		.name = "kmem.tcp.usage_in_bytes",
+		.read_u64 = tcp_cgroup_read,
+		.private = RES_USAGE,
+	},
+	{
+		.name = "kmem.tcp.failcnt",
+		.private = RES_FAILCNT,
+		.trigger = tcp_cgroup_reset,
+		.read_u64 = tcp_cgroup_read,
+	},
+	{
+		.name = "kmem.tcp.max_usage_in_bytes",
+		.private = RES_MAX_USAGE,
+		.trigger = tcp_cgroup_reset,
+		.read_u64 = tcp_cgroup_read,
+	},
+	{ }	/* terminate */
+};
+
+static int __init tcp_memcontrol_init(void)
+{
+	WARN_ON(cgroup_add_cftypes(&mem_cgroup_subsys, tcp_files));
+	return 0;
+}
+__initcall(tcp_memcontrol_init);
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index 4d50579..ee2e5bc 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -87,7 +87,7 @@
 	const struct xt_tee_tginfo *info = par->targinfo;
 	struct iphdr *iph;
 
-	if (percpu_read(tee_active))
+	if (__this_cpu_read(tee_active))
 		return XT_CONTINUE;
 	/*
 	 * Copy the skb, and route the copy. Will later return %XT_CONTINUE for
@@ -124,9 +124,9 @@
 	ip_send_check(iph);
 
 	if (tee_tg_route4(skb, info)) {
-		percpu_write(tee_active, true);
+		__this_cpu_write(tee_active, true);
 		ip_local_out(skb);
-		percpu_write(tee_active, false);
+		__this_cpu_write(tee_active, false);
 	} else {
 		kfree_skb(skb);
 	}
@@ -168,7 +168,7 @@
 {
 	const struct xt_tee_tginfo *info = par->targinfo;
 
-	if (percpu_read(tee_active))
+	if (__this_cpu_read(tee_active))
 		return XT_CONTINUE;
 	skb = pskb_copy(skb, GFP_ATOMIC);
 	if (skb == NULL)
@@ -186,9 +186,9 @@
 		--iph->hop_limit;
 	}
 	if (tee_tg_route6(skb, info)) {
-		percpu_write(tee_active, true);
+		__this_cpu_write(tee_active, true);
 		ip6_local_out(skb);
-		percpu_write(tee_active, false);
+		__this_cpu_write(tee_active, false);
 	} else {
 		kfree_skb(skb);
 	}
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index 1afaa28..7743ea8 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -22,22 +22,6 @@
 #include <net/sock.h>
 #include <net/cls_cgroup.h>
 
-static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp);
-static void cgrp_destroy(struct cgroup *cgrp);
-static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp);
-
-struct cgroup_subsys net_cls_subsys = {
-	.name		= "net_cls",
-	.create		= cgrp_create,
-	.destroy	= cgrp_destroy,
-	.populate	= cgrp_populate,
-#ifdef CONFIG_NET_CLS_CGROUP
-	.subsys_id	= net_cls_subsys_id,
-#endif
-	.module		= THIS_MODULE,
-};
-
-
 static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp)
 {
 	return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id),
@@ -86,12 +70,19 @@
 		.read_u64 = read_classid,
 		.write_u64 = write_classid,
 	},
+	{ }	/* terminate */
 };
 
-static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
-{
-	return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files));
-}
+struct cgroup_subsys net_cls_subsys = {
+	.name		= "net_cls",
+	.create		= cgrp_create,
+	.destroy	= cgrp_destroy,
+#ifdef CONFIG_NET_CLS_CGROUP
+	.subsys_id	= net_cls_subsys_id,
+#endif
+	.base_cftypes	= ss_files,
+	.module		= THIS_MODULE,
+};
 
 struct cls_cgroup_head {
 	u32			handle;
diff --git a/net/socket.c b/net/socket.c
index 2a2898ce..6e0ccc0 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -479,7 +479,7 @@
 	inode->i_uid = current_fsuid();
 	inode->i_gid = current_fsgid();
 
-	percpu_add(sockets_in_use, 1);
+	this_cpu_add(sockets_in_use, 1);
 	return sock;
 }
 
@@ -522,7 +522,7 @@
 	if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
 		printk(KERN_ERR "sock_release: fasync list not empty!\n");
 
-	percpu_sub(sockets_in_use, 1);
+	this_cpu_sub(sockets_in_use, 1);
 	if (!sock->file) {
 		iput(SOCK_INODE(sock));
 		return;
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index 75762f3..6ed6f20 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -160,8 +160,8 @@
 	if (gcred->acred.group_info->ngroups != acred->group_info->ngroups)
 		goto out_nomatch;
 	for (i = 0; i < gcred->acred.group_info->ngroups; i++) {
-		if (GROUP_AT(gcred->acred.group_info, i) !=
-				GROUP_AT(acred->group_info, i))
+		if (!gid_eq(GROUP_AT(gcred->acred.group_info, i),
+				GROUP_AT(acred->group_info, i)))
 			goto out_nomatch;
 	}
 out_match:
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 1600cfb..28b62db 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -41,6 +41,7 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
+#include <linux/user_namespace.h>
 
 #include <linux/sunrpc/auth_gss.h>
 #include <linux/sunrpc/gss_err.h>
@@ -470,9 +471,13 @@
 		status = -EINVAL;
 		for (i=0; i<N; i++) {
 			gid_t gid;
+			kgid_t kgid;
 			if (get_int(&mesg, &gid))
 				goto out;
-			GROUP_AT(rsci.cred.cr_group_info, i) = gid;
+			kgid = make_kgid(&init_user_ns, gid);
+			if (!gid_valid(kgid))
+				goto out;
+			GROUP_AT(rsci.cred.cr_group_info, i) = kgid;
 		}
 
 		/* mech name */
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index e50502d..52c5abd 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/auth.h>
+#include <linux/user_namespace.h>
 
 #define NFS_NGROUPS	16
 
@@ -78,8 +79,11 @@
 		groups = NFS_NGROUPS;
 
 	cred->uc_gid = acred->gid;
-	for (i = 0; i < groups; i++)
-		cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
+	for (i = 0; i < groups; i++) {
+		gid_t gid;
+		gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i));
+		cred->uc_gids[i] = gid;
+	}
 	if (i < NFS_NGROUPS)
 		cred->uc_gids[i] = NOGROUP;
 
@@ -126,9 +130,12 @@
 		groups = acred->group_info->ngroups;
 	if (groups > NFS_NGROUPS)
 		groups = NFS_NGROUPS;
-	for (i = 0; i < groups ; i++)
-		if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i))
+	for (i = 0; i < groups ; i++) {
+		gid_t gid;
+		gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i));
+		if (cred->uc_gids[i] != gid)
 			return 0;
+	}
 	if (groups < NFS_NGROUPS &&
 	    cred->uc_gids[groups] != NOGROUP)
 		return 0;
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 521d8f7..71ec853 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -14,6 +14,7 @@
 #include <net/sock.h>
 #include <net/ipv6.h>
 #include <linux/kernel.h>
+#include <linux/user_namespace.h>
 #define RPCDBG_FACILITY	RPCDBG_AUTH
 
 #include <linux/sunrpc/clnt.h>
@@ -530,11 +531,15 @@
 
 	for (i = 0 ; i < gids ; i++) {
 		int gid;
+		kgid_t kgid;
 		rv = get_int(&mesg, &gid);
 		err = -EINVAL;
 		if (rv)
 			goto out;
-		GROUP_AT(ug.gi, i) = gid;
+		kgid = make_kgid(&init_user_ns, gid);
+		if (!gid_valid(kgid))
+			goto out;
+		GROUP_AT(ug.gi, i) = kgid;
 	}
 
 	ugp = unix_gid_lookup(cd, uid);
@@ -563,6 +568,7 @@
 			 struct cache_detail *cd,
 			 struct cache_head *h)
 {
+	struct user_namespace *user_ns = current_user_ns();
 	struct unix_gid *ug;
 	int i;
 	int glen;
@@ -580,7 +586,7 @@
 
 	seq_printf(m, "%u %d:", ug->uid, glen);
 	for (i = 0; i < glen; i++)
-		seq_printf(m, " %d", GROUP_AT(ug->gi, i));
+		seq_printf(m, " %d", from_kgid_munged(user_ns, GROUP_AT(ug->gi, i)));
 	seq_printf(m, "\n");
 	return 0;
 }
@@ -831,8 +837,12 @@
 	cred->cr_group_info = groups_alloc(slen);
 	if (cred->cr_group_info == NULL)
 		return SVC_CLOSE;
-	for (i = 0; i < slen; i++)
-		GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
+	for (i = 0; i < slen; i++) {
+		kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv));
+		if (!gid_valid(kgid))
+			goto badcred;
+		GROUP_AT(cred->cr_group_info, i) = kgid;
+	}
 	if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
 		*authp = rpc_autherr_badverf;
 		return SVC_DENIED;
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 105b21f..65f362d 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -9,3 +9,4 @@
 ihex2fw
 recordmcount
 docproc
+sortextable
diff --git a/scripts/Makefile b/scripts/Makefile
index 3626666..a55b006 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -15,6 +15,9 @@
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(CONFIG_IKCONFIG)     += bin2c
 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
+hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
+
+HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
 
 always		:= $(hostprogs-y) $(hostprogs-m)
 
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 2c6286c..f606738 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -240,7 +240,7 @@
 	"Defined at drivers/pci/Kconfig:47\n"
 	"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
 	"Location:\n"
-	"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+	"  -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
 	"    -> PCI support (PCI [=y])\n"
 	"      -> PCI access mode (<choice> [=y])\n"
 	"Selects: LIBCRC32\n"
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
index 73070cb..8c0eb659 100644
--- a/scripts/kconfig/nconf.c
+++ b/scripts/kconfig/nconf.c
@@ -223,7 +223,7 @@
 "Defined at drivers/pci/Kconfig:47\n"
 "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
 "Location:\n"
-"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+"  -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
 "    -> PCI support (PCI [ = y])\n"
 "      -> PCI access mode (<choice> [ = y])\n"
 "Selects: LIBCRC32\n"
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 44ddaa5..5759751 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -336,10 +336,13 @@
 			     struct hid_device_id *id, char *alias)
 {
 	id->bus = TO_NATIVE(id->bus);
+	id->group = TO_NATIVE(id->group);
 	id->vendor = TO_NATIVE(id->vendor);
 	id->product = TO_NATIVE(id->product);
 
-	sprintf(alias, "hid:b%04X", id->bus);
+	sprintf(alias, "hid:");
+	ADD(alias, "b", id->bus != HID_BUS_ANY, id->bus);
+	ADD(alias, "g", id->group != HID_GROUP_ANY, id->group);
 	ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor);
 	ADD(alias, "p", id->product != HID_ANY_ID, id->product);
 
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index c4e7d15..0f84bb3 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -337,17 +337,20 @@
 void *grab_file(const char *filename, unsigned long *size)
 {
 	struct stat st;
-	void *map;
+	void *map = MAP_FAILED;
 	int fd;
 
 	fd = open(filename, O_RDONLY);
-	if (fd < 0 || fstat(fd, &st) != 0)
+	if (fd < 0)
 		return NULL;
+	if (fstat(fd, &st))
+		goto failed;
 
 	*size = st.st_size;
 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-	close(fd);
 
+failed:
+	close(fd);
 	if (map == MAP_FAILED)
 		return NULL;
 	return map;
@@ -1850,14 +1853,14 @@
 	buf_printf(b, "\n");
 	buf_printf(b, "struct module __this_module\n");
 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
-	buf_printf(b, " .name = KBUILD_MODNAME,\n");
+	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
 	if (mod->has_init)
-		buf_printf(b, " .init = init_module,\n");
+		buf_printf(b, "\t.init = init_module,\n");
 	if (mod->has_cleanup)
 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
-			      " .exit = cleanup_module,\n"
+			      "\t.exit = cleanup_module,\n"
 			      "#endif\n");
-	buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
+	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
 	buf_printf(b, "};\n");
 }
 
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
new file mode 100644
index 0000000..1ca9ceb
--- /dev/null
+++ b/scripts/sortextable.c
@@ -0,0 +1,322 @@
+/*
+ * sortextable.c: Sort the kernel's exception table
+ *
+ * Copyright 2011 - 2012 Cavium, Inc.
+ *
+ * Based on code taken from recortmcount.c which is:
+ *
+ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
+ * Licensed under the GNU General Public License, version 2 (GPLv2).
+ *
+ * Restructured to fit Linux format, as well as other updates:
+ *  Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+ */
+
+/*
+ * Strategy: alter the vmlinux file in-place.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tools/be_byteshift.h>
+#include <tools/le_byteshift.h>
+
+static int fd_map;	/* File descriptor for file being modified. */
+static int mmap_failed; /* Boolean flag. */
+static void *ehdr_curr; /* current ElfXX_Ehdr *  for resource cleanup */
+static struct stat sb;	/* Remember .st_size, etc. */
+static jmp_buf jmpenv;	/* setjmp/longjmp per-file error escape */
+
+/* setjmp() return values */
+enum {
+	SJ_SETJMP = 0,  /* hardwired first return */
+	SJ_FAIL,
+	SJ_SUCCEED
+};
+
+/* Per-file resource cleanup when multiple files. */
+static void
+cleanup(void)
+{
+	if (!mmap_failed)
+		munmap(ehdr_curr, sb.st_size);
+	close(fd_map);
+}
+
+static void __attribute__((noreturn))
+fail_file(void)
+{
+	cleanup();
+	longjmp(jmpenv, SJ_FAIL);
+}
+
+static void __attribute__((noreturn))
+succeed_file(void)
+{
+	cleanup();
+	longjmp(jmpenv, SJ_SUCCEED);
+}
+
+
+/*
+ * Get the whole file as a programming convenience in order to avoid
+ * malloc+lseek+read+free of many pieces.  If successful, then mmap
+ * avoids copying unused pieces; else just read the whole file.
+ * Open for both read and write.
+ */
+static void *mmap_file(char const *fname)
+{
+	void *addr;
+
+	fd_map = open(fname, O_RDWR);
+	if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
+		perror(fname);
+		fail_file();
+	}
+	if (!S_ISREG(sb.st_mode)) {
+		fprintf(stderr, "not a regular file: %s\n", fname);
+		fail_file();
+	}
+	addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+		    fd_map, 0);
+	if (addr == MAP_FAILED) {
+		mmap_failed = 1;
+		fprintf(stderr, "Could not mmap file: %s\n", fname);
+		fail_file();
+	}
+	return addr;
+}
+
+static uint64_t r8be(const uint64_t *x)
+{
+	return get_unaligned_be64(x);
+}
+static uint32_t rbe(const uint32_t *x)
+{
+	return get_unaligned_be32(x);
+}
+static uint16_t r2be(const uint16_t *x)
+{
+	return get_unaligned_be16(x);
+}
+static uint64_t r8le(const uint64_t *x)
+{
+	return get_unaligned_le64(x);
+}
+static uint32_t rle(const uint32_t *x)
+{
+	return get_unaligned_le32(x);
+}
+static uint16_t r2le(const uint16_t *x)
+{
+	return get_unaligned_le16(x);
+}
+
+static void w8be(uint64_t val, uint64_t *x)
+{
+	put_unaligned_be64(val, x);
+}
+static void wbe(uint32_t val, uint32_t *x)
+{
+	put_unaligned_be32(val, x);
+}
+static void w2be(uint16_t val, uint16_t *x)
+{
+	put_unaligned_be16(val, x);
+}
+static void w8le(uint64_t val, uint64_t *x)
+{
+	put_unaligned_le64(val, x);
+}
+static void wle(uint32_t val, uint32_t *x)
+{
+	put_unaligned_le32(val, x);
+}
+static void w2le(uint16_t val, uint16_t *x)
+{
+	put_unaligned_le16(val, x);
+}
+
+static uint64_t (*r8)(const uint64_t *);
+static uint32_t (*r)(const uint32_t *);
+static uint16_t (*r2)(const uint16_t *);
+static void (*w8)(uint64_t, uint64_t *);
+static void (*w)(uint32_t, uint32_t *);
+static void (*w2)(uint16_t, uint16_t *);
+
+typedef void (*table_sort_t)(char *, int);
+
+/* 32 bit and 64 bit are very similar */
+#include "sortextable.h"
+#define SORTEXTABLE_64
+#include "sortextable.h"
+
+static int compare_x86_table(const void *a, const void *b)
+{
+	int32_t av = (int32_t)r(a);
+	int32_t bv = (int32_t)r(b);
+
+	if (av < bv)
+		return -1;
+	if (av > bv)
+		return 1;
+	return 0;
+}
+
+static void sort_x86_table(char *extab_image, int image_size)
+{
+	int i;
+
+	/*
+	 * Do the same thing the runtime sort does, first normalize to
+	 * being relative to the start of the section.
+	 */
+	i = 0;
+	while (i < image_size) {
+		uint32_t *loc = (uint32_t *)(extab_image + i);
+		w(r(loc) + i, loc);
+		i += 4;
+	}
+
+	qsort(extab_image, image_size / 8, 8, compare_x86_table);
+
+	/* Now denormalize. */
+	i = 0;
+	while (i < image_size) {
+		uint32_t *loc = (uint32_t *)(extab_image + i);
+		w(r(loc) - i, loc);
+		i += 4;
+	}
+}
+
+static void
+do_file(char const *const fname)
+{
+	table_sort_t custom_sort;
+	Elf32_Ehdr *ehdr = mmap_file(fname);
+
+	ehdr_curr = ehdr;
+	switch (ehdr->e_ident[EI_DATA]) {
+	default:
+		fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
+			ehdr->e_ident[EI_DATA], fname);
+		fail_file();
+		break;
+	case ELFDATA2LSB:
+		r = rle;
+		r2 = r2le;
+		r8 = r8le;
+		w = wle;
+		w2 = w2le;
+		w8 = w8le;
+		break;
+	case ELFDATA2MSB:
+		r = rbe;
+		r2 = r2be;
+		r8 = r8be;
+		w = wbe;
+		w2 = w2be;
+		w8 = w8be;
+		break;
+	}  /* end switch */
+	if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
+	||  r2(&ehdr->e_type) != ET_EXEC
+	||  ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
+		fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
+		fail_file();
+	}
+
+	custom_sort = NULL;
+	switch (r2(&ehdr->e_machine)) {
+	default:
+		fprintf(stderr, "unrecognized e_machine %d %s\n",
+			r2(&ehdr->e_machine), fname);
+		fail_file();
+		break;
+	case EM_386:
+	case EM_X86_64:
+		custom_sort = sort_x86_table;
+		break;
+	case EM_MIPS:
+		break;
+	}  /* end switch */
+
+	switch (ehdr->e_ident[EI_CLASS]) {
+	default:
+		fprintf(stderr, "unrecognized ELF class %d %s\n",
+			ehdr->e_ident[EI_CLASS], fname);
+		fail_file();
+		break;
+	case ELFCLASS32:
+		if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
+		||  r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
+			fprintf(stderr,
+				"unrecognized ET_EXEC file: %s\n", fname);
+			fail_file();
+		}
+		do32(ehdr, fname, custom_sort);
+		break;
+	case ELFCLASS64: {
+		Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
+		if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
+		||  r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
+			fprintf(stderr,
+				"unrecognized ET_EXEC file: %s\n", fname);
+			fail_file();
+		}
+		do64(ghdr, fname, custom_sort);
+		break;
+	}
+	}  /* end switch */
+
+	cleanup();
+}
+
+int
+main(int argc, char *argv[])
+{
+	int n_error = 0;  /* gcc-4.3.0 false positive complaint */
+	int i;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: sortextable vmlinux...\n");
+		return 0;
+	}
+
+	/* Process each file in turn, allowing deep failure. */
+	for (i = 1; i < argc; i++) {
+		char *file = argv[i];
+		int const sjval = setjmp(jmpenv);
+
+		switch (sjval) {
+		default:
+			fprintf(stderr, "internal error: %s\n", file);
+			exit(1);
+			break;
+		case SJ_SETJMP:    /* normal sequence */
+			/* Avoid problems if early cleanup() */
+			fd_map = -1;
+			ehdr_curr = NULL;
+			mmap_failed = 1;
+			do_file(file);
+			break;
+		case SJ_FAIL:    /* error in do_file or below */
+			++n_error;
+			break;
+		case SJ_SUCCEED:    /* premature success */
+			/* do nothing */
+			break;
+		}  /* end switch */
+	}
+	return !!n_error;
+}
diff --git a/scripts/sortextable.h b/scripts/sortextable.h
new file mode 100644
index 0000000..e4fd45b
--- /dev/null
+++ b/scripts/sortextable.h
@@ -0,0 +1,191 @@
+/*
+ * sortextable.h
+ *
+ * Copyright 2011 - 2012 Cavium, Inc.
+ *
+ * Some of this code was taken out of recordmcount.h written by:
+ *
+ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
+ * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+ *
+ *
+ * Licensed under the GNU General Public License, version 2 (GPLv2).
+ */
+
+#undef extable_ent_size
+#undef compare_extable
+#undef do_func
+#undef Elf_Addr
+#undef Elf_Ehdr
+#undef Elf_Shdr
+#undef Elf_Rel
+#undef Elf_Rela
+#undef Elf_Sym
+#undef ELF_R_SYM
+#undef Elf_r_sym
+#undef ELF_R_INFO
+#undef Elf_r_info
+#undef ELF_ST_BIND
+#undef ELF_ST_TYPE
+#undef fn_ELF_R_SYM
+#undef fn_ELF_R_INFO
+#undef uint_t
+#undef _r
+#undef _w
+
+#ifdef SORTEXTABLE_64
+# define extable_ent_size	16
+# define compare_extable	compare_extable_64
+# define do_func		do64
+# define Elf_Addr		Elf64_Addr
+# define Elf_Ehdr		Elf64_Ehdr
+# define Elf_Shdr		Elf64_Shdr
+# define Elf_Rel		Elf64_Rel
+# define Elf_Rela		Elf64_Rela
+# define Elf_Sym		Elf64_Sym
+# define ELF_R_SYM		ELF64_R_SYM
+# define Elf_r_sym		Elf64_r_sym
+# define ELF_R_INFO		ELF64_R_INFO
+# define Elf_r_info		Elf64_r_info
+# define ELF_ST_BIND		ELF64_ST_BIND
+# define ELF_ST_TYPE		ELF64_ST_TYPE
+# define fn_ELF_R_SYM		fn_ELF64_R_SYM
+# define fn_ELF_R_INFO		fn_ELF64_R_INFO
+# define uint_t			uint64_t
+# define _r			r8
+# define _w			w8
+#else
+# define extable_ent_size	8
+# define compare_extable	compare_extable_32
+# define do_func		do32
+# define Elf_Addr		Elf32_Addr
+# define Elf_Ehdr		Elf32_Ehdr
+# define Elf_Shdr		Elf32_Shdr
+# define Elf_Rel		Elf32_Rel
+# define Elf_Rela		Elf32_Rela
+# define Elf_Sym		Elf32_Sym
+# define ELF_R_SYM		ELF32_R_SYM
+# define Elf_r_sym		Elf32_r_sym
+# define ELF_R_INFO		ELF32_R_INFO
+# define Elf_r_info		Elf32_r_info
+# define ELF_ST_BIND		ELF32_ST_BIND
+# define ELF_ST_TYPE		ELF32_ST_TYPE
+# define fn_ELF_R_SYM		fn_ELF32_R_SYM
+# define fn_ELF_R_INFO		fn_ELF32_R_INFO
+# define uint_t			uint32_t
+# define _r			r
+# define _w			w
+#endif
+
+static int compare_extable(const void *a, const void *b)
+{
+	Elf_Addr av = _r(a);
+	Elf_Addr bv = _r(b);
+
+	if (av < bv)
+		return -1;
+	if (av > bv)
+		return 1;
+	return 0;
+}
+
+static void
+do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
+{
+	Elf_Shdr *shdr;
+	Elf_Shdr *shstrtab_sec;
+	Elf_Shdr *strtab_sec = NULL;
+	Elf_Shdr *symtab_sec = NULL;
+	Elf_Shdr *extab_sec = NULL;
+	Elf_Sym *sym;
+	Elf_Sym *sort_needed_sym;
+	Elf_Shdr *sort_needed_sec;
+	Elf_Rel *relocs = NULL;
+	int relocs_size;
+	uint32_t *sort_done_location;
+	const char *secstrtab;
+	const char *strtab;
+	char *extab_image;
+	int extab_index = 0;
+	int i;
+	int idx;
+
+	shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
+	shstrtab_sec = shdr + r2(&ehdr->e_shstrndx);
+	secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset);
+	for (i = 0; i < r2(&ehdr->e_shnum); i++) {
+		idx = r(&shdr[i].sh_name);
+		if (strcmp(secstrtab + idx, "__ex_table") == 0) {
+			extab_sec = shdr + i;
+			extab_index = i;
+		}
+		if ((r(&shdr[i].sh_type) == SHT_REL ||
+		     r(&shdr[i].sh_type) == SHT_RELA) &&
+		    r(&shdr[i].sh_info) == extab_index) {
+			relocs = (void *)ehdr + _r(&shdr[i].sh_offset);
+			relocs_size = _r(&shdr[i].sh_size);
+		}
+		if (strcmp(secstrtab + idx, ".symtab") == 0)
+			symtab_sec = shdr + i;
+		if (strcmp(secstrtab + idx, ".strtab") == 0)
+			strtab_sec = shdr + i;
+	}
+	if (strtab_sec == NULL) {
+		fprintf(stderr,	"no .strtab in  file: %s\n", fname);
+		fail_file();
+	}
+	if (symtab_sec == NULL) {
+		fprintf(stderr,	"no .symtab in  file: %s\n", fname);
+		fail_file();
+	}
+	if (extab_sec == NULL) {
+		fprintf(stderr,	"no __ex_table in  file: %s\n", fname);
+		fail_file();
+	}
+	strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
+
+	extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
+
+	if (custom_sort) {
+		custom_sort(extab_image, _r(&extab_sec->sh_size));
+	} else {
+		int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
+		qsort(extab_image, num_entries,
+		      extable_ent_size, compare_extable);
+	}
+	/* If there were relocations, we no longer need them. */
+	if (relocs)
+		memset(relocs, 0, relocs_size);
+
+	/* find main_extable_sort_needed */
+	sort_needed_sym = NULL;
+	for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) {
+		sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
+		sym += i;
+		if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
+			continue;
+		idx = r(&sym->st_name);
+		if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) {
+			sort_needed_sym = sym;
+			break;
+		}
+	}
+	if (sort_needed_sym == NULL) {
+		fprintf(stderr,
+			"no main_extable_sort_needed symbol in  file: %s\n",
+			fname);
+		fail_file();
+	}
+	sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)];
+	sort_done_location = (void *)ehdr +
+		_r(&sort_needed_sec->sh_offset) +
+		_r(&sort_needed_sym->st_value) -
+		_r(&sort_needed_sec->sh_addr);
+
+#if 1
+	printf("sort done marker at %lx\n",
+	       (unsigned long)((char *)sort_done_location - (char *)ehdr));
+#endif
+	/* We sorted it, clear the flag. */
+	w(0, sort_done_location);
+}
diff --git a/security/commoncap.c b/security/commoncap.c
index f80d116..e771cb1 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -77,12 +77,12 @@
 		int cap, int audit)
 {
 	for (;;) {
-		/* The creator of the user namespace has all caps. */
-		if (targ_ns != &init_user_ns && targ_ns->creator == cred->user)
+		/* The owner of the user namespace has all caps. */
+		if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid))
 			return 0;
 
 		/* Do we have the necessary capabilities? */
-		if (targ_ns == cred->user->user_ns)
+		if (targ_ns == cred->user_ns)
 			return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
 
 		/* Have we tried all of the parent namespaces? */
@@ -93,7 +93,7 @@
 		 *If you have a capability in a parent user ns, then you have
 		 * it over all children user namespaces as well.
 		 */
-		targ_ns = targ_ns->creator->user_ns;
+		targ_ns = targ_ns->parent;
 	}
 
 	/* We never get here */
@@ -137,10 +137,10 @@
 	rcu_read_lock();
 	cred = current_cred();
 	child_cred = __task_cred(child);
-	if (cred->user->user_ns == child_cred->user->user_ns &&
+	if (cred->user_ns == child_cred->user_ns &&
 	    cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
 		goto out;
-	if (ns_capable(child_cred->user->user_ns, CAP_SYS_PTRACE))
+	if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE))
 		goto out;
 	ret = -EPERM;
 out:
@@ -169,10 +169,10 @@
 	rcu_read_lock();
 	cred = __task_cred(parent);
 	child_cred = current_cred();
-	if (cred->user->user_ns == child_cred->user->user_ns &&
+	if (cred->user_ns == child_cred->user_ns &&
 	    cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
 		goto out;
-	if (has_ns_capability(parent, child_cred->user->user_ns, CAP_SYS_PTRACE))
+	if (has_ns_capability(parent, child_cred->user_ns, CAP_SYS_PTRACE))
 		goto out;
 	ret = -EPERM;
 out:
@@ -215,7 +215,7 @@
 	/* they are so limited unless the current task has the CAP_SETPCAP
 	 * capability
 	 */
-	if (cap_capable(current_cred(), current_cred()->user->user_ns,
+	if (cap_capable(current_cred(), current_cred()->user_ns,
 			CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
 		return 0;
 	return 1;
@@ -473,19 +473,22 @@
 	struct cred *new = bprm->cred;
 	bool effective, has_cap = false;
 	int ret;
+	kuid_t root_uid;
 
 	effective = false;
 	ret = get_file_caps(bprm, &effective, &has_cap);
 	if (ret < 0)
 		return ret;
 
+	root_uid = make_kuid(new->user_ns, 0);
+
 	if (!issecure(SECURE_NOROOT)) {
 		/*
 		 * If the legacy file capability is set, then don't set privs
 		 * for a setuid root binary run by a non-root user.  Do set it
 		 * for a root user just to cause least surprise to an admin.
 		 */
-		if (has_cap && new->uid != 0 && new->euid == 0) {
+		if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) {
 			warn_setuid_and_fcaps_mixed(bprm->filename);
 			goto skip;
 		}
@@ -496,12 +499,12 @@
 		 *
 		 * If only the real uid is 0, we do not set the effective bit.
 		 */
-		if (new->euid == 0 || new->uid == 0) {
+		if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) {
 			/* pP' = (cap_bset & ~0) | (pI & ~0) */
 			new->cap_permitted = cap_combine(old->cap_bset,
 							 old->cap_inheritable);
 		}
-		if (new->euid == 0)
+		if (uid_eq(new->euid, root_uid))
 			effective = true;
 	}
 skip:
@@ -516,8 +519,8 @@
 	 *
 	 * In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
 	 */
-	if ((new->euid != old->uid ||
-	     new->egid != old->gid ||
+	if ((!uid_eq(new->euid, old->uid) ||
+	     !gid_eq(new->egid, old->gid) ||
 	     !cap_issubset(new->cap_permitted, old->cap_permitted)) &&
 	    bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
 		/* downgrade; they get no more than they had, and maybe less */
@@ -553,7 +556,7 @@
 	 */
 	if (!cap_isclear(new->cap_effective)) {
 		if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
-		    new->euid != 0 || new->uid != 0 ||
+		    !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) ||
 		    issecure(SECURE_NOROOT)) {
 			ret = audit_log_bprm_fcaps(bprm, new, old);
 			if (ret < 0)
@@ -578,16 +581,17 @@
 int cap_bprm_secureexec(struct linux_binprm *bprm)
 {
 	const struct cred *cred = current_cred();
+	kuid_t root_uid = make_kuid(cred->user_ns, 0);
 
-	if (cred->uid != 0) {
+	if (!uid_eq(cred->uid, root_uid)) {
 		if (bprm->cap_effective)
 			return 1;
 		if (!cap_isclear(cred->cap_permitted))
 			return 1;
 	}
 
-	return (cred->euid != cred->uid ||
-		cred->egid != cred->gid);
+	return (!uid_eq(cred->euid, cred->uid) ||
+		!gid_eq(cred->egid, cred->gid));
 }
 
 /**
@@ -677,15 +681,21 @@
  */
 static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
 {
-	if ((old->uid == 0 || old->euid == 0 || old->suid == 0) &&
-	    (new->uid != 0 && new->euid != 0 && new->suid != 0) &&
+	kuid_t root_uid = make_kuid(old->user_ns, 0);
+
+	if ((uid_eq(old->uid, root_uid) ||
+	     uid_eq(old->euid, root_uid) ||
+	     uid_eq(old->suid, root_uid)) &&
+	    (!uid_eq(new->uid, root_uid) &&
+	     !uid_eq(new->euid, root_uid) &&
+	     !uid_eq(new->suid, root_uid)) &&
 	    !issecure(SECURE_KEEP_CAPS)) {
 		cap_clear(new->cap_permitted);
 		cap_clear(new->cap_effective);
 	}
-	if (old->euid == 0 && new->euid != 0)
+	if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid))
 		cap_clear(new->cap_effective);
-	if (old->euid != 0 && new->euid == 0)
+	if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid))
 		new->cap_effective = new->cap_permitted;
 }
 
@@ -718,11 +728,12 @@
 		 *          if not, we might be a bit too harsh here.
 		 */
 		if (!issecure(SECURE_NO_SETUID_FIXUP)) {
-			if (old->fsuid == 0 && new->fsuid != 0)
+			kuid_t root_uid = make_kuid(old->user_ns, 0);
+			if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid))
 				new->cap_effective =
 					cap_drop_fs_set(new->cap_effective);
 
-			if (old->fsuid != 0 && new->fsuid == 0)
+			if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid))
 				new->cap_effective =
 					cap_raise_fs_set(new->cap_effective,
 							 new->cap_permitted);
@@ -875,7 +886,7 @@
 		    || ((new->securebits & SECURE_ALL_LOCKS & ~arg2))	/*[2]*/
 		    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS))	/*[3]*/
 		    || (cap_capable(current_cred(),
-				    current_cred()->user->user_ns, CAP_SETPCAP,
+				    current_cred()->user_ns, CAP_SETPCAP,
 				    SECURITY_CAP_AUDIT) != 0)		/*[4]*/
 			/*
 			 * [1] no changing of bits that are locked
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index c43a332..442204c 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -447,22 +447,16 @@
 		.read_seq_string = devcgroup_seq_read,
 		.private = DEVCG_LIST,
 	},
+	{ }	/* terminate */
 };
 
-static int devcgroup_populate(struct cgroup_subsys *ss,
-				struct cgroup *cgroup)
-{
-	return cgroup_add_files(cgroup, ss, dev_cgroup_files,
-					ARRAY_SIZE(dev_cgroup_files));
-}
-
 struct cgroup_subsys devices_subsys = {
 	.name = "devices",
 	.can_attach = devcgroup_can_attach,
 	.create = devcgroup_create,
 	.destroy = devcgroup_destroy,
-	.populate = devcgroup_populate,
 	.subsys_id = devices_subsys_id,
+	.base_cftypes = dev_cgroup_files,
 };
 
 int __devcgroup_inode_permission(struct inode *inode, int mask)
diff --git a/security/keys/key.c b/security/keys/key.c
index c9bf66a..50d96d4 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -253,7 +253,7 @@
 	quotalen = desclen + type->def_datalen;
 
 	/* get hold of the key tracking for this user */
-	user = key_user_lookup(uid, cred->user->user_ns);
+	user = key_user_lookup(uid, cred->user_ns);
 	if (!user)
 		goto no_memory_1;
 
diff --git a/security/keys/permission.c b/security/keys/permission.c
index 57d9636..0b4d019 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -36,7 +36,7 @@
 
 	key = key_ref_to_ptr(key_ref);
 
-	if (key->user->user_ns != cred->user->user_ns)
+	if (key->user->user_ns != cred->user_ns)
 		goto use_other_perms;
 
 	/* use the second 8-bits of permissions for keys the caller owns */
@@ -53,7 +53,8 @@
 			goto use_these_perms;
 		}
 
-		ret = groups_search(cred->group_info, key->gid);
+		ret = groups_search(cred->group_info,
+				    make_kgid(current_user_ns(), key->gid));
 		if (ret) {
 			kperm = key->perm >> 8;
 			goto use_these_perms;
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index e137fcd..d71056d 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -860,7 +860,7 @@
 	new-> sgid	= old-> sgid;
 	new->fsgid	= old->fsgid;
 	new->user	= get_uid(old->user);
-	new->user_ns	= new->user->user_ns;
+	new->user_ns	= get_user_ns(new->user_ns);
 	new->group_info	= get_group_info(old->group_info);
 
 	new->securebits	= old->securebits;
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index 115313e..f5ded64 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -991,6 +991,8 @@
 			gpio_direction_output(pdata->reset_pin, 1);
 			chip->reset_pin = pdata->reset_pin;
 		}
+	} else {
+		chip->reset_pin = -EINVAL;
 	}
 
 	snd_card_set_dev(card, &pdev->dev);
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 471e1e3..a06b165 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -155,7 +155,7 @@
  * @jack:   The jack to configure
  * @parent: The device to set as parent for the jack.
  *
- * Set the parent for the jack input device in the device tree.  This
+ * Set the parent for the jack devices in the device tree.  This
  * function is only valid prior to registration of the jack.  If no
  * parent is configured then the parent device will be the sound card.
  */
@@ -179,6 +179,9 @@
  * mapping is provided but keys are enabled in the jack type then
  * BTN_n numeric buttons will be reported.
  *
+ * If jacks are not reporting via the input API this call will have no
+ * effect.
+ *
  * Note that this is intended to be use by simple devices with small
  * numbers of keys that can be reported.  It is also possible to
  * access the input device directly - devices with complex input
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 4d18941..faedb14 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1894,6 +1894,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_uframes_t xfer = 0;
 	snd_pcm_uframes_t offset = 0;
+	snd_pcm_uframes_t avail;
 	int err = 0;
 
 	if (size == 0)
@@ -1917,13 +1918,12 @@
 	}
 
 	runtime->twake = runtime->control->avail_min ? : 1;
+	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+		snd_pcm_update_hw_ptr(substream);
+	avail = snd_pcm_playback_avail(runtime);
 	while (size > 0) {
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
-		snd_pcm_uframes_t avail;
 		snd_pcm_uframes_t cont;
-		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-			snd_pcm_update_hw_ptr(substream);
-		avail = snd_pcm_playback_avail(runtime);
 		if (!avail) {
 			if (nonblock) {
 				err = -EAGAIN;
@@ -1971,6 +1971,7 @@
 		offset += frames;
 		size -= frames;
 		xfer += frames;
+		avail -= frames;
 		if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
 		    snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
 			err = snd_pcm_start(substream);
@@ -2111,6 +2112,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_uframes_t xfer = 0;
 	snd_pcm_uframes_t offset = 0;
+	snd_pcm_uframes_t avail;
 	int err = 0;
 
 	if (size == 0)
@@ -2141,13 +2143,12 @@
 	}
 
 	runtime->twake = runtime->control->avail_min ? : 1;
+	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+		snd_pcm_update_hw_ptr(substream);
+	avail = snd_pcm_capture_avail(runtime);
 	while (size > 0) {
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
-		snd_pcm_uframes_t avail;
 		snd_pcm_uframes_t cont;
-		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-			snd_pcm_update_hw_ptr(substream);
-		avail = snd_pcm_capture_avail(runtime);
 		if (!avail) {
 			if (runtime->status->state ==
 			    SNDRV_PCM_STATE_DRAINING) {
@@ -2202,6 +2203,7 @@
 		offset += frames;
 		size -= frames;
 		xfer += frames;
+		avail -= frames;
 	}
  _end_unlock:
 	runtime->twake = 0;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 3fe99e6..53b5ada 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1360,7 +1360,14 @@
 
 static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)
 {
-	substream->runtime->trigger_master = substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	switch (runtime->status->state) {
+	case SNDRV_PCM_STATE_OPEN:
+	case SNDRV_PCM_STATE_DISCONNECTED:
+	case SNDRV_PCM_STATE_SUSPENDED:
+		return -EBADFD;
+	}
+	runtime->trigger_master = substream;
 	return 0;
 }
 
@@ -1379,6 +1386,9 @@
 		case SNDRV_PCM_STATE_RUNNING:
 			runtime->status->state = SNDRV_PCM_STATE_DRAINING;
 			break;
+		case SNDRV_PCM_STATE_XRUN:
+			runtime->status->state = SNDRV_PCM_STATE_SETUP;
+			break;
 		default:
 			break;
 		}
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index c700920..e952833 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -35,7 +35,7 @@
 #include <linux/sound.h>
 #include <linux/mutex.h>
 
-#define SNDRV_OSS_MINORS 128
+#define SNDRV_OSS_MINORS 256
 
 static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
 static DEFINE_MUTEX(sound_oss_mutex);
@@ -111,7 +111,7 @@
 	int register1 = -1, register2 = -1;
 	struct device *carddev = snd_card_get_device_link(card);
 
-	if (card && card->number >= 8)
+	if (card && card->number >= SNDRV_MINOR_OSS_DEVICES)
 		return 0; /* ignore silently */
 	if (minor < 0)
 		return minor;
@@ -170,7 +170,7 @@
 	int track2 = -1;
 	struct snd_minor *mptr;
 
-	if (card && card->number >= 8)
+	if (card && card->number >= SNDRV_MINOR_OSS_DEVICES)
 		return 0;
 	if (minor < 0)
 		return minor;
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index ad079b6..8b5c36f 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -117,6 +117,7 @@
 	/* timer stuff */
 	unsigned int irq_pos;		/* fractional IRQ position */
 	unsigned int period_size_frac;
+	unsigned int last_drift;
 	unsigned long last_jiffies;
 	struct timer_list timer;
 };
@@ -264,6 +265,7 @@
 			return err;
 		dpcm->last_jiffies = jiffies;
 		dpcm->pcm_rate_shift = 0;
+		dpcm->last_drift = 0;
 		spin_lock(&cable->lock);	
 		cable->running |= stream;
 		cable->pause &= ~stream;
@@ -444,34 +446,30 @@
 	}
 }
 
-#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)
+static inline unsigned int bytepos_delta(struct loopback_pcm *dpcm,
+					 unsigned int jiffies_delta)
 {
-	unsigned int count;
 	unsigned long last_pos;
+	unsigned int delta;
 
 	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;
+	dpcm->irq_pos += jiffies_delta * dpcm->pcm_bps;
+	delta = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
+	if (delta >= dpcm->last_drift)
+		delta -= dpcm->last_drift;
+	dpcm->last_drift = 0;
 	if (dpcm->irq_pos >= dpcm->period_size_frac) {
 		dpcm->irq_pos %= dpcm->period_size_frac;
 		dpcm->period_update_pending = 1;
 	}
+	return delta;
+}
+
+static inline void bytepos_finish(struct loopback_pcm *dpcm,
+				  unsigned int delta)
+{
+	dpcm->buf_pos += delta;
+	dpcm->buf_pos %= dpcm->pcm_buffer_size;
 }
 
 static unsigned int loopback_pos_update(struct loopback_cable *cable)
@@ -481,7 +479,7 @@
 	struct loopback_pcm *dpcm_capt =
 			cable->streams[SNDRV_PCM_STREAM_CAPTURE];
 	unsigned long delta_play = 0, delta_capt = 0;
-	unsigned int running;
+	unsigned int running, count1, count2;
 	unsigned long flags;
 
 	spin_lock_irqsave(&cable->lock, flags);
@@ -500,12 +498,13 @@
 		goto unlock;
 		
 	if (delta_play > delta_capt) {
-		loopback_bytepos_update(dpcm_play, delta_play - delta_capt,
-					BYTEPOS_UPDATE_POSONLY);
+		count1 = bytepos_delta(dpcm_play, delta_play - delta_capt);
+		bytepos_finish(dpcm_play, count1);
 		delta_play = delta_capt;
 	} else if (delta_play < delta_capt) {
-		loopback_bytepos_update(dpcm_capt, delta_capt - delta_play,
-					BYTEPOS_UPDATE_CLEAR);
+		count1 = bytepos_delta(dpcm_capt, delta_capt - delta_play);
+		clear_capture_buf(dpcm_capt, count1);
+		bytepos_finish(dpcm_capt, count1);
 		delta_capt = delta_play;
 	}
 
@@ -513,8 +512,17 @@
 		goto unlock;
 
 	/* 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);
+	count1 = bytepos_delta(dpcm_play, delta_play);
+	count2 = bytepos_delta(dpcm_capt, delta_capt);
+	if (count1 < count2) {
+		dpcm_capt->last_drift = count2 - count1;
+		count1 = count2;
+	} else if (count1 > count2) {
+		dpcm_play->last_drift = count1 - count2;
+	}
+	copy_play_buf(dpcm_play, dpcm_capt, count1);
+	bytepos_finish(dpcm_play, count1);
+	bytepos_finish(dpcm_capt, count1);
  unlock:
 	spin_unlock_irqrestore(&cable->lock, flags);
 	return running;
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 87657dd..ea995af 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -31,6 +31,8 @@
 #define INTERRUPT_INTERVAL	16
 #define QUEUE_LENGTH		48
 
+static void pcm_period_tasklet(unsigned long data);
+
 /**
  * amdtp_out_stream_init - initialize an AMDTP output stream structure
  * @s: the AMDTP output stream to initialize
@@ -47,6 +49,7 @@
 	s->flags = flags;
 	s->context = ERR_PTR(-1);
 	mutex_init(&s->mutex);
+	tasklet_init(&s->period_tasklet, pcm_period_tasklet, (unsigned long)s);
 	s->packet_index = 0;
 
 	return 0;
@@ -164,6 +167,21 @@
 }
 EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format);
 
+/**
+ * amdtp_out_stream_pcm_prepare - prepare PCM device for running
+ * @s: the AMDTP output stream
+ *
+ * This function should be called from the PCM device's .prepare callback.
+ */
+void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
+{
+	tasklet_kill(&s->period_tasklet);
+	s->pcm_buffer_pointer = 0;
+	s->pcm_period_pointer = 0;
+	s->pointer_flush = true;
+}
+EXPORT_SYMBOL(amdtp_out_stream_pcm_prepare);
+
 static unsigned int calculate_data_blocks(struct amdtp_out_stream *s)
 {
 	unsigned int phase, data_blocks;
@@ -376,11 +394,21 @@
 		s->pcm_period_pointer += data_blocks;
 		if (s->pcm_period_pointer >= pcm->runtime->period_size) {
 			s->pcm_period_pointer -= pcm->runtime->period_size;
-			snd_pcm_period_elapsed(pcm);
+			s->pointer_flush = false;
+			tasklet_hi_schedule(&s->period_tasklet);
 		}
 	}
 }
 
+static void pcm_period_tasklet(unsigned long data)
+{
+	struct amdtp_out_stream *s = (void *)data;
+	struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+
+	if (pcm)
+		snd_pcm_period_elapsed(pcm);
+}
+
 static void out_packet_callback(struct fw_iso_context *context, u32 cycle,
 				size_t header_length, void *header, void *data)
 {
@@ -506,6 +534,24 @@
 EXPORT_SYMBOL(amdtp_out_stream_start);
 
 /**
+ * amdtp_out_stream_pcm_pointer - get the PCM buffer position
+ * @s: the AMDTP output stream that transports the PCM data
+ *
+ * Returns the current buffer position, in frames.
+ */
+unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s)
+{
+	/* this optimization is allowed to be racy */
+	if (s->pointer_flush)
+		fw_iso_context_flush_completions(s->context);
+	else
+		s->pointer_flush = true;
+
+	return ACCESS_ONCE(s->pcm_buffer_pointer);
+}
+EXPORT_SYMBOL(amdtp_out_stream_pcm_pointer);
+
+/**
  * amdtp_out_stream_update - update the stream after a bus reset
  * @s: the AMDTP output stream
  */
@@ -532,6 +578,7 @@
 		return;
 	}
 
+	tasklet_kill(&s->period_tasklet);
 	fw_iso_context_stop(s->context);
 	fw_iso_context_destroy(s->context);
 	s->context = ERR_PTR(-1);
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
index 537a9cb..b680c5e 100644
--- a/sound/firewire/amdtp.h
+++ b/sound/firewire/amdtp.h
@@ -1,6 +1,7 @@
 #ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED
 #define SOUND_FIREWIRE_AMDTP_H_INCLUDED
 
+#include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include "packets-buffer.h"
@@ -55,6 +56,7 @@
 	struct iso_packets_buffer buffer;
 
 	struct snd_pcm_substream *pcm;
+	struct tasklet_struct period_tasklet;
 
 	int packet_index;
 	unsigned int data_block_counter;
@@ -66,6 +68,7 @@
 
 	unsigned int pcm_buffer_pointer;
 	unsigned int pcm_period_pointer;
+	bool pointer_flush;
 };
 
 int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
@@ -81,6 +84,8 @@
 
 void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
 				     snd_pcm_format_t format);
+void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s);
+unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s);
 void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s);
 
 /**
@@ -123,18 +128,6 @@
 }
 
 /**
- * amdtp_out_stream_pcm_prepare - prepare PCM device for running
- * @s: the AMDTP output stream
- *
- * This function should be called from the PCM device's .prepare callback.
- */
-static inline void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
-{
-	s->pcm_buffer_pointer = 0;
-	s->pcm_period_pointer = 0;
-}
-
-/**
  * amdtp_out_stream_pcm_trigger - start/stop playback from a PCM device
  * @s: the AMDTP output stream
  * @pcm: the PCM device to be started, or %NULL to stop the current device
@@ -149,18 +142,6 @@
 	ACCESS_ONCE(s->pcm) = pcm;
 }
 
-/**
- * amdtp_out_stream_pcm_pointer - get the PCM buffer position
- * @s: the AMDTP output stream that transports the PCM data
- *
- * Returns the current buffer position, in frames.
- */
-static inline unsigned long
-amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s)
-{
-	return ACCESS_ONCE(s->pcm_buffer_pointer);
-}
-
 static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
 {
 	return sfc & 1;
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
index a63faec..582aace 100644
--- a/sound/i2c/other/tea575x-tuner.c
+++ b/sound/i2c/other/tea575x-tuner.c
@@ -375,6 +375,9 @@
 	tea->vd.v4l2_dev = tea->v4l2_dev;
 	tea->vd.ctrl_handler = &tea->ctrl_handler;
 	set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags);
+	/* disable hw_freq_seek if we can't use it */
+	if (tea->cannot_read_data)
+		v4l2_disable_ioctl(&tea->vd, VIDIOC_S_HW_FREQ_SEEK);
 
 	v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
 	v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
index d1f4351..2d67c78 100644
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -7,7 +7,7 @@
     Thanks to Pierfrancesco 'qM2' Passerini.
 
     Generalised for soundcards based on DT-0196 and ALS-007 chips
-    by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
+    by Jonathan Woithe <jwoithe@just42.net>: June 2002.
 
     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
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 5ca0939..ff3af6e 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -228,7 +228,7 @@
 	  Say Y here to include support for sound cards based on the
 	  C-Media CMI8788 (Oxygen HD Audio) chip:
 	   * Asound A-8788
-	   * Asus Xonar DG
+	   * Asus Xonar DG/DGX
 	   * AuzenTech X-Meridian
 	   * AuzenTech X-Meridian 2G
 	   * Bgears b-Enspirer
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 9d91d61..e672ff4 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -1062,17 +1062,4 @@
 	.remove = __devexit_p(snd_ad1889_remove),
 };
 
-static int __init
-alsa_ad1889_init(void)
-{
-	return pci_register_driver(&ad1889_pci_driver);
-}
-
-static void __exit
-alsa_ad1889_fini(void)
-{
-	pci_unregister_driver(&ad1889_pci_driver);
-}
-
-module_init(alsa_ad1889_init);
-module_exit(alsa_ad1889_fini);
+module_pci_driver(ad1889_pci_driver);
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index bdd6164..9dfc27b 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -2294,7 +2294,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver ali5451_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_ali_ids,
 	.probe = snd_ali_probe,
@@ -2305,15 +2305,4 @@
 #endif
 };                                
 
-static int __init alsa_card_ali_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ali_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ali_init)
-module_exit(alsa_card_ali_exit)
+module_pci_driver(ali5451_driver);
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 8196e22..59d6538 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -852,7 +852,7 @@
 	return 0;
 }
 
-static struct pci_driver driver = {
+static struct pci_driver als300_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_als300_ids,
 	.probe = snd_als300_probe,
@@ -863,15 +863,4 @@
 #endif
 };
 
-static int __init alsa_card_als300_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_als300_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_als300_init)
-module_exit(alsa_card_als300_exit)
+module_pci_driver(als300_driver);
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 3269b80..7d7f259 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -1036,7 +1036,7 @@
 #endif /* CONFIG_PM */
 
 
-static struct pci_driver driver = {
+static struct pci_driver als4000_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_als4000_ids,
 	.probe = snd_card_als4000_probe,
@@ -1047,15 +1047,4 @@
 #endif
 };
 
-static int __init alsa_card_als4000_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_als4000_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_als4000_init)
-module_exit(alsa_card_als4000_exit)
+module_pci_driver(als4000_driver);
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 590682f..156a94f 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1700,7 +1700,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver atiixp_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_atiixp_ids,
 	.probe = snd_atiixp_probe,
@@ -1711,16 +1711,4 @@
 #endif
 };
 
-
-static int __init alsa_card_atiixp_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_atiixp_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_atiixp_init)
-module_exit(alsa_card_atiixp_exit)
+module_pci_driver(atiixp_driver);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 524d35f..30a4fd9 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1331,7 +1331,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver atiixp_modem_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_atiixp_ids,
 	.probe = snd_atiixp_probe,
@@ -1342,16 +1342,4 @@
 #endif
 };
 
-
-static int __init alsa_card_atiixp_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_atiixp_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_atiixp_init)
-module_exit(alsa_card_atiixp_exit)
+module_pci_driver(atiixp_modem_driver);
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index f13ad53..ffc376f 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -375,24 +375,11 @@
 }
 
 // pci_driver definition
-static struct pci_driver driver = {
+static struct pci_driver vortex_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_vortex_ids,
 	.probe = snd_vortex_probe,
 	.remove = __devexit_p(snd_vortex_remove),
 };
 
-// initialization of the module
-static int __init alsa_card_vortex_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-// clean up the module
-static void __exit alsa_card_vortex_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_vortex_init)
-module_exit(alsa_card_vortex_exit)
+module_pci_driver(vortex_driver);
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 1c523193..0f80474 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -112,8 +112,6 @@
 /*********************************
  * FUNCTION DECLARATIONS
  ********************************/
-static int __init alsa_card_aw2_init(void);
-static void __exit alsa_card_aw2_exit(void);
 static int snd_aw2_dev_free(struct snd_device *device);
 static int __devinit snd_aw2_create(struct snd_card *card,
 				    struct pci_dev *pci, struct aw2 **rchip);
@@ -171,13 +169,15 @@
 MODULE_DEVICE_TABLE(pci, snd_aw2_ids);
 
 /* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver aw2_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_aw2_ids,
 	.probe = snd_aw2_probe,
 	.remove = __devexit_p(snd_aw2_remove),
 };
 
+module_pci_driver(aw2_driver);
+
 /* operators for playback PCM alsa interface */
 static struct snd_pcm_ops snd_aw2_playback_ops = {
 	.open = snd_aw2_pcm_playback_open,
@@ -217,23 +217,6 @@
  * FUNCTION IMPLEMENTATIONS
  ********************************/
 
-/* initialization of the module */
-static int __init alsa_card_aw2_init(void)
-{
-	snd_printdd(KERN_DEBUG "aw2: Load aw2 module\n");
-	return pci_register_driver(&driver);
-}
-
-/* clean up the module */
-static void __exit alsa_card_aw2_exit(void)
-{
-	snd_printdd(KERN_DEBUG "aw2: Unload aw2 module\n");
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_aw2_init);
-module_exit(alsa_card_aw2_exit);
-
 /* component-destructor */
 static int snd_aw2_dev_free(struct snd_device *device)
 {
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 496f14c..f0b4d74 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -2862,7 +2862,7 @@
 #endif /* CONFIG_PM */
 
 
-static struct pci_driver driver = {
+static struct pci_driver azf3328_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_azf3328_ids,
 	.probe = snd_azf3328_probe,
@@ -2873,23 +2873,4 @@
 #endif
 };
 
-static int __init
-alsa_card_azf3328_init(void)
-{
-	int err;
-	snd_azf3328_dbgcallenter();
-	err = pci_register_driver(&driver);
-	snd_azf3328_dbgcallleave();
-	return err;
-}
-
-static void __exit
-alsa_card_azf3328_exit(void)
-{
-	snd_azf3328_dbgcallenter();
-	pci_unregister_driver(&driver);
-	snd_azf3328_dbgcallleave();
-}
-
-module_init(alsa_card_azf3328_init)
-module_exit(alsa_card_azf3328_exit)
+module_pci_driver(azf3328_driver);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 62d6163..b6a95ee 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -836,8 +836,6 @@
 	{0x7063, 0x2000}, /* pcHDTV HD-2000 TV */
 };
 
-static struct pci_driver driver;
-
 /* return the id of the card, or a negative value if it's blacklisted */
 static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
 {
@@ -964,24 +962,11 @@
 	{ }
 };
 
-static struct pci_driver driver = {
+static struct pci_driver bt87x_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_bt87x_ids,
 	.probe = snd_bt87x_probe,
 	.remove = __devexit_p(snd_bt87x_remove),
 };
 
-static int __init alsa_card_bt87x_init(void)
-{
-	if (load_all)
-		driver.id_table = snd_bt87x_default_ids;
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_bt87x_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_bt87x_init)
-module_exit(alsa_card_bt87x_exit)
+module_pci_driver(bt87x_driver);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 08d6ebf..e76d68a 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1932,7 +1932,7 @@
 MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);
 
 // pci_driver definition
-static struct pci_driver driver = {
+static struct pci_driver ca0106_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_ca0106_ids,
 	.probe = snd_ca0106_probe,
@@ -1943,17 +1943,4 @@
 #endif
 };
 
-// initialization of the module
-static int __init alsa_card_ca0106_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-// clean up the module
-static void __exit alsa_card_ca0106_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ca0106_init)
-module_exit(alsa_card_ca0106_exit)
+module_pci_driver(ca0106_driver);
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 19b0626..3815bd4 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -3398,7 +3398,7 @@
 }
 #endif /* CONFIG_PM */
 
-static struct pci_driver driver = {
+static struct pci_driver cmipci_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_cmipci_ids,
 	.probe = snd_cmipci_probe,
@@ -3409,15 +3409,4 @@
 #endif
 };
 	
-static int __init alsa_card_cmipci_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cmipci_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cmipci_init)
-module_exit(alsa_card_cmipci_exit)
+module_pci_driver(cmipci_driver);
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index a9f368f..33506ee 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -2084,7 +2084,7 @@
 }
 #endif /* CONFIG_PM */
 
-static struct pci_driver driver = {
+static struct pci_driver cs4281_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_cs4281_ids,
 	.probe = snd_cs4281_probe,
@@ -2095,15 +2095,4 @@
 #endif
 };
 	
-static int __init alsa_card_cs4281_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs4281_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs4281_init)
-module_exit(alsa_card_cs4281_exit)
+module_pci_driver(cs4281_driver);
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 819d79d..6cc7404 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -161,7 +161,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver cs46xx_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_cs46xx_ids,
 	.probe = snd_card_cs46xx_probe,
@@ -172,15 +172,4 @@
 #endif
 };
 
-static int __init alsa_card_cs46xx_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs46xx_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs46xx_init)
-module_exit(alsa_card_cs46xx_exit)
+module_pci_driver(cs46xx_driver);
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index c47cabf..f1e4229 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -291,23 +291,11 @@
 	return 0;
 }
 
-static struct pci_driver driver = {
+static struct pci_driver cs5530_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_cs5530_ids,
 	.probe = snd_cs5530_probe,
 	.remove = __devexit_p(snd_cs5530_remove),
 };
 
-static int __init alsa_card_cs5530_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs5530_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs5530_init)
-module_exit(alsa_card_cs5530_exit)
-
+module_pci_driver(cs5530_driver);
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index a2fb217..2c9697c 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -394,7 +394,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver cs5535audio_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_cs5535audio_ids,
 	.probe = snd_cs5535audio_probe,
@@ -405,18 +405,7 @@
 #endif
 };
 
-static int __init alsa_card_cs5535audio_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs5535audio_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs5535audio_init)
-module_exit(alsa_card_cs5535audio_exit)
+module_pci_driver(cs5535audio_driver);
 
 MODULE_AUTHOR("Jaya Kumar");
 MODULE_LICENSE("GPL");
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
index 15d95d2..75aa2c3 100644
--- a/sound/pci/ctxfi/xfi.c
+++ b/sound/pci/ctxfi/xfi.c
@@ -154,15 +154,4 @@
 #endif
 };
 
-static int __init ct_card_init(void)
-{
-	return pci_register_driver(&ct_driver);
-}
-
-static void __exit ct_card_exit(void)
-{
-	pci_unregister_driver(&ct_driver);
-}
-
-module_init(ct_card_init)
-module_exit(ct_card_exit)
+module_pci_driver(ct_driver);
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 595c11f..0f8eda1 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -2328,7 +2328,7 @@
 ******************************************************************************/
 
 /* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver echo_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_echo_ids,
 	.probe = snd_echo_probe,
@@ -2339,22 +2339,4 @@
 #endif /* CONFIG_PM */
 };
 
-
-
-/* initialization of the module */
-static int __init alsa_card_echo_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-
-
-/* clean up the module */
-static void __exit alsa_card_echo_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-
-module_init(alsa_card_echo_init)
-module_exit(alsa_card_echo_exit)
+module_pci_driver(echo_driver);
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 790c65d..7fdbbe4 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -263,7 +263,7 @@
 }
 #endif
 
-static struct pci_driver driver = {
+static struct pci_driver emu10k1_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_emu10k1_ids,
 	.probe = snd_card_emu10k1_probe,
@@ -274,15 +274,4 @@
 #endif
 };
 
-static int __init alsa_card_emu10k1_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_emu10k1_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_emu10k1_init)
-module_exit(alsa_card_emu10k1_exit)
+module_pci_driver(emu10k1_driver);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 47a651c..5c8978b 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1612,24 +1612,11 @@
 MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
 
 // pci_driver definition
-static struct pci_driver driver = {
+static struct pci_driver emu10k1x_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_emu10k1x_ids,
 	.probe = snd_emu10k1x_probe,
 	.remove = __devexit_p(snd_emu10k1x_remove),
 };
 
-// initialization of the module
-static int __init alsa_card_emu10k1x_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-// clean up the module
-static void __exit alsa_card_emu10k1x_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_emu10k1x_init)
-module_exit(alsa_card_emu10k1x_exit)
+module_pci_driver(emu10k1x_driver);
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 47a245e..3821c81 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -2488,7 +2488,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver ens137x_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_audiopci_ids,
 	.probe = snd_audiopci_probe,
@@ -2499,15 +2499,4 @@
 #endif
 };
 	
-static int __init alsa_card_ens137x_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ens137x_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ens137x_init)
-module_exit(alsa_card_ens137x_exit)
+module_pci_driver(ens137x_driver);
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 53eb76b..82c8d8c 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1882,7 +1882,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver es1938_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_es1938_ids,
 	.probe = snd_es1938_probe,
@@ -1893,15 +1893,4 @@
 #endif
 };
 
-static int __init alsa_card_es1938_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_es1938_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_es1938_init)
-module_exit(alsa_card_es1938_exit)
+module_pci_driver(es1938_driver);
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index a8faae1..67f47d8 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -2898,7 +2898,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver es1968_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_es1968_ids,
 	.probe = snd_es1968_probe,
@@ -2909,15 +2909,4 @@
 #endif
 };
 
-static int __init alsa_card_es1968_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_es1968_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_es1968_init)
-module_exit(alsa_card_es1968_exit)
+module_pci_driver(es1968_driver);
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index a416ea8..f696623 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1416,7 +1416,7 @@
 }
 #endif
 
-static struct pci_driver driver = {
+static struct pci_driver fm801_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_fm801_ids,
 	.probe = snd_card_fm801_probe,
@@ -1427,15 +1427,4 @@
 #endif
 };
 
-static int __init alsa_card_fm801_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_fm801_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_fm801_init)
-module_exit(alsa_card_fm801_exit)
+module_pci_driver(fm801_driver);
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index ace157c..bd4149f 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,6 +1,6 @@
 snd-hda-intel-objs := hda_intel.o
 
-snd-hda-codec-y := hda_codec.o hda_jack.o
+snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o
 snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
new file mode 100644
index 0000000..6e9ef3e
--- /dev/null
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -0,0 +1,760 @@
+/*
+ * BIOS auto-parser helper functions for HD-audio
+ *
+ * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver 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/slab.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+
+#define SFX	"hda_codec: "
+
+/*
+ * Helper for automatic pin configuration
+ */
+
+static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
+{
+	for (; *list; list++)
+		if (*list == nid)
+			return 1;
+	return 0;
+}
+
+
+/*
+ * Sort an associated group of pins according to their sequence numbers.
+ */
+static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
+				  int num_pins)
+{
+	int i, j;
+	short seq;
+	hda_nid_t nid;
+
+	for (i = 0; i < num_pins; i++) {
+		for (j = i + 1; j < num_pins; j++) {
+			if (sequences[i] > sequences[j]) {
+				seq = sequences[i];
+				sequences[i] = sequences[j];
+				sequences[j] = seq;
+				nid = pins[i];
+				pins[i] = pins[j];
+				pins[j] = nid;
+			}
+		}
+	}
+}
+
+
+/* add the found input-pin to the cfg->inputs[] table */
+static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
+				   int type)
+{
+	if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
+		cfg->inputs[cfg->num_inputs].pin = nid;
+		cfg->inputs[cfg->num_inputs].type = type;
+		cfg->num_inputs++;
+	}
+}
+
+/* sort inputs in the order of AUTO_PIN_* type */
+static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
+{
+	int i, j;
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		for (j = i + 1; j < cfg->num_inputs; j++) {
+			if (cfg->inputs[i].type > cfg->inputs[j].type) {
+				struct auto_pin_cfg_item tmp;
+				tmp = cfg->inputs[i];
+				cfg->inputs[i] = cfg->inputs[j];
+				cfg->inputs[j] = tmp;
+			}
+		}
+	}
+}
+
+/* Reorder the surround channels
+ * ALSA sequence is front/surr/clfe/side
+ * HDA sequence is:
+ *    4-ch: front/surr  =>  OK as it is
+ *    6-ch: front/clfe/surr
+ *    8-ch: front/clfe/rear/side|fc
+ */
+static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
+{
+	hda_nid_t nid;
+
+	switch (nums) {
+	case 3:
+	case 4:
+		nid = pins[1];
+		pins[1] = pins[2];
+		pins[2] = nid;
+		break;
+	}
+}
+
+/*
+ * Parse all pin widgets and store the useful pin nids to cfg
+ *
+ * The number of line-outs or any primary output is stored in line_outs,
+ * and the corresponding output pins are assigned to line_out_pins[],
+ * in the order of front, rear, CLFE, side, ...
+ *
+ * If more extra outputs (speaker and headphone) are found, the pins are
+ * assisnged to hp_pins[] and speaker_pins[], respectively.  If no line-out jack
+ * is detected, one of speaker of HP pins is assigned as the primary
+ * output, i.e. to line_out_pins[0].  So, line_outs is always positive
+ * if any analog output exists.
+ *
+ * The analog input pins are assigned to inputs array.
+ * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
+ * respectively.
+ */
+int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
+			     struct auto_pin_cfg *cfg,
+			     const hda_nid_t *ignore_nids,
+			     unsigned int cond_flags)
+{
+	hda_nid_t nid, end_nid;
+	short seq, assoc_line_out;
+	short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
+	short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
+	short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
+	int i;
+
+	memset(cfg, 0, sizeof(*cfg));
+
+	memset(sequences_line_out, 0, sizeof(sequences_line_out));
+	memset(sequences_speaker, 0, sizeof(sequences_speaker));
+	memset(sequences_hp, 0, sizeof(sequences_hp));
+	assoc_line_out = 0;
+
+	codec->ignore_misc_bit = true;
+	end_nid = codec->start_nid + codec->num_nodes;
+	for (nid = codec->start_nid; nid < end_nid; nid++) {
+		unsigned int wid_caps = get_wcaps(codec, nid);
+		unsigned int wid_type = get_wcaps_type(wid_caps);
+		unsigned int def_conf;
+		short assoc, loc, conn, dev;
+
+		/* read all default configuration for pin complex */
+		if (wid_type != AC_WID_PIN)
+			continue;
+		/* ignore the given nids (e.g. pc-beep returns error) */
+		if (ignore_nids && is_in_nid_list(nid, ignore_nids))
+			continue;
+
+		def_conf = snd_hda_codec_get_pincfg(codec, nid);
+		if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+		      AC_DEFCFG_MISC_NO_PRESENCE))
+			codec->ignore_misc_bit = false;
+		conn = get_defcfg_connect(def_conf);
+		if (conn == AC_JACK_PORT_NONE)
+			continue;
+		loc = get_defcfg_location(def_conf);
+		dev = get_defcfg_device(def_conf);
+
+		/* workaround for buggy BIOS setups */
+		if (dev == AC_JACK_LINE_OUT) {
+			if (conn == AC_JACK_PORT_FIXED)
+				dev = AC_JACK_SPEAKER;
+		}
+
+		switch (dev) {
+		case AC_JACK_LINE_OUT:
+			seq = get_defcfg_sequence(def_conf);
+			assoc = get_defcfg_association(def_conf);
+
+			if (!(wid_caps & AC_WCAP_STEREO))
+				if (!cfg->mono_out_pin)
+					cfg->mono_out_pin = nid;
+			if (!assoc)
+				continue;
+			if (!assoc_line_out)
+				assoc_line_out = assoc;
+			else if (assoc_line_out != assoc)
+				continue;
+			if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
+				continue;
+			cfg->line_out_pins[cfg->line_outs] = nid;
+			sequences_line_out[cfg->line_outs] = seq;
+			cfg->line_outs++;
+			break;
+		case AC_JACK_SPEAKER:
+			seq = get_defcfg_sequence(def_conf);
+			assoc = get_defcfg_association(def_conf);
+			if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
+				continue;
+			cfg->speaker_pins[cfg->speaker_outs] = nid;
+			sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq;
+			cfg->speaker_outs++;
+			break;
+		case AC_JACK_HP_OUT:
+			seq = get_defcfg_sequence(def_conf);
+			assoc = get_defcfg_association(def_conf);
+			if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
+				continue;
+			cfg->hp_pins[cfg->hp_outs] = nid;
+			sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
+			cfg->hp_outs++;
+			break;
+		case AC_JACK_MIC_IN:
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
+			break;
+		case AC_JACK_LINE_IN:
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
+			break;
+		case AC_JACK_CD:
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
+			break;
+		case AC_JACK_AUX:
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
+			break;
+		case AC_JACK_SPDIF_OUT:
+		case AC_JACK_DIG_OTHER_OUT:
+			if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
+				continue;
+			cfg->dig_out_pins[cfg->dig_outs] = nid;
+			cfg->dig_out_type[cfg->dig_outs] =
+				(loc == AC_JACK_LOC_HDMI) ?
+				HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF;
+			cfg->dig_outs++;
+			break;
+		case AC_JACK_SPDIF_IN:
+		case AC_JACK_DIG_OTHER_IN:
+			cfg->dig_in_pin = nid;
+			if (loc == AC_JACK_LOC_HDMI)
+				cfg->dig_in_type = HDA_PCM_TYPE_HDMI;
+			else
+				cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
+			break;
+		}
+	}
+
+	/* FIX-UP:
+	 * If no line-out is defined but multiple HPs are found,
+	 * some of them might be the real line-outs.
+	 */
+	if (!cfg->line_outs && cfg->hp_outs > 1 &&
+	    !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
+		int i = 0;
+		while (i < cfg->hp_outs) {
+			/* The real HPs should have the sequence 0x0f */
+			if ((sequences_hp[i] & 0x0f) == 0x0f) {
+				i++;
+				continue;
+			}
+			/* Move it to the line-out table */
+			cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i];
+			sequences_line_out[cfg->line_outs] = sequences_hp[i];
+			cfg->line_outs++;
+			cfg->hp_outs--;
+			memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1,
+				sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i));
+			memmove(sequences_hp + i, sequences_hp + i + 1,
+				sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
+		}
+		memset(cfg->hp_pins + cfg->hp_outs, 0,
+		       sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
+		if (!cfg->hp_outs)
+			cfg->line_out_type = AUTO_PIN_HP_OUT;
+
+	}
+
+	/* sort by sequence */
+	sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out,
+			      cfg->line_outs);
+	sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
+			      cfg->speaker_outs);
+	sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
+			      cfg->hp_outs);
+
+	/*
+	 * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
+	 * as a primary output
+	 */
+	if (!cfg->line_outs &&
+	    !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) {
+		if (cfg->speaker_outs) {
+			cfg->line_outs = cfg->speaker_outs;
+			memcpy(cfg->line_out_pins, cfg->speaker_pins,
+			       sizeof(cfg->speaker_pins));
+			cfg->speaker_outs = 0;
+			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
+			cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
+		} else if (cfg->hp_outs) {
+			cfg->line_outs = cfg->hp_outs;
+			memcpy(cfg->line_out_pins, cfg->hp_pins,
+			       sizeof(cfg->hp_pins));
+			cfg->hp_outs = 0;
+			memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+			cfg->line_out_type = AUTO_PIN_HP_OUT;
+		}
+	}
+
+	reorder_outputs(cfg->line_outs, cfg->line_out_pins);
+	reorder_outputs(cfg->hp_outs, cfg->hp_pins);
+	reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
+
+	sort_autocfg_input_pins(cfg);
+
+	/*
+	 * debug prints of the parsed results
+	 */
+	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
+		   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
+		   cfg->line_out_pins[2], cfg->line_out_pins[3],
+		   cfg->line_out_pins[4],
+		   cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
+		   (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
+		    "speaker" : "line"));
+	snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+		   cfg->speaker_outs, cfg->speaker_pins[0],
+		   cfg->speaker_pins[1], cfg->speaker_pins[2],
+		   cfg->speaker_pins[3], cfg->speaker_pins[4]);
+	snd_printd("   hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+		   cfg->hp_outs, cfg->hp_pins[0],
+		   cfg->hp_pins[1], cfg->hp_pins[2],
+		   cfg->hp_pins[3], cfg->hp_pins[4]);
+	snd_printd("   mono: mono_out=0x%x\n", cfg->mono_out_pin);
+	if (cfg->dig_outs)
+		snd_printd("   dig-out=0x%x/0x%x\n",
+			   cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
+	snd_printd("   inputs:");
+	for (i = 0; i < cfg->num_inputs; i++) {
+		snd_printd(" %s=0x%x",
+			    hda_get_autocfg_input_label(codec, cfg, i),
+			    cfg->inputs[i].pin);
+	}
+	snd_printd("\n");
+	if (cfg->dig_in_pin)
+		snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
+
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf)
+{
+	unsigned int loc = get_defcfg_location(def_conf);
+	unsigned int conn = get_defcfg_connect(def_conf);
+	if (conn == AC_JACK_PORT_NONE)
+		return INPUT_PIN_ATTR_UNUSED;
+	/* Windows may claim the internal mic to be BOTH, too */
+	if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
+		return INPUT_PIN_ATTR_INT;
+	if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
+		return INPUT_PIN_ATTR_INT;
+	if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
+		return INPUT_PIN_ATTR_DOCK;
+	if (loc == AC_JACK_LOC_REAR)
+		return INPUT_PIN_ATTR_REAR;
+	if (loc == AC_JACK_LOC_FRONT)
+		return INPUT_PIN_ATTR_FRONT;
+	return INPUT_PIN_ATTR_NORMAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
+
+/**
+ * hda_get_input_pin_label - Give a label for the given input pin
+ *
+ * When check_location is true, the function checks the pin location
+ * for mic and line-in pins, and set an appropriate prefix like "Front",
+ * "Rear", "Internal".
+ */
+
+static const char *hda_get_input_pin_label(struct hda_codec *codec,
+					   hda_nid_t pin, bool check_location)
+{
+	unsigned int def_conf;
+	static const char * const mic_names[] = {
+		"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
+	};
+	int attr;
+
+	def_conf = snd_hda_codec_get_pincfg(codec, pin);
+
+	switch (get_defcfg_device(def_conf)) {
+	case AC_JACK_MIC_IN:
+		if (!check_location)
+			return "Mic";
+		attr = snd_hda_get_input_pin_attr(def_conf);
+		if (!attr)
+			return "None";
+		return mic_names[attr - 1];
+	case AC_JACK_LINE_IN:
+		if (!check_location)
+			return "Line";
+		attr = snd_hda_get_input_pin_attr(def_conf);
+		if (!attr)
+			return "None";
+		if (attr == INPUT_PIN_ATTR_DOCK)
+			return "Dock Line";
+		return "Line";
+	case AC_JACK_AUX:
+		return "Aux";
+	case AC_JACK_CD:
+		return "CD";
+	case AC_JACK_SPDIF_IN:
+		return "SPDIF In";
+	case AC_JACK_DIG_OTHER_IN:
+		return "Digital In";
+	default:
+		return "Misc";
+	}
+}
+
+/* Check whether the location prefix needs to be added to the label.
+ * If all mic-jacks are in the same location (e.g. rear panel), we don't
+ * have to put "Front" prefix to each label.  In such a case, returns false.
+ */
+static int check_mic_location_need(struct hda_codec *codec,
+				   const struct auto_pin_cfg *cfg,
+				   int input)
+{
+	unsigned int defc;
+	int i, attr, attr2;
+
+	defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
+	attr = snd_hda_get_input_pin_attr(defc);
+	/* for internal or docking mics, we need locations */
+	if (attr <= INPUT_PIN_ATTR_NORMAL)
+		return 1;
+
+	attr = 0;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
+		attr2 = snd_hda_get_input_pin_attr(defc);
+		if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
+			if (attr && attr != attr2)
+				return 1; /* different locations found */
+			attr = attr2;
+		}
+	}
+	return 0;
+}
+
+/**
+ * hda_get_autocfg_input_label - Get a label for the given input
+ *
+ * Get a label for the given input pin defined by the autocfg item.
+ * Unlike hda_get_input_pin_label(), this function checks all inputs
+ * defined in autocfg and avoids the redundant mic/line prefix as much as
+ * possible.
+ */
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+					const struct auto_pin_cfg *cfg,
+					int input)
+{
+	int type = cfg->inputs[input].type;
+	int has_multiple_pins = 0;
+
+	if ((input > 0 && cfg->inputs[input - 1].type == type) ||
+	    (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
+		has_multiple_pins = 1;
+	if (has_multiple_pins && type == AUTO_PIN_MIC)
+		has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+	return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+				       has_multiple_pins);
+}
+EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+	int i;
+	for (i = 0; i < nums; i++)
+		if (list[i] == nid)
+			return i;
+	return -1;
+}
+
+/* get a unique suffix or an index number */
+static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
+				    int num_pins, int *indexp)
+{
+	static const char * const channel_sfx[] = {
+		" Front", " Surround", " CLFE", " Side"
+	};
+	int i;
+
+	i = find_idx_in_nid_list(nid, pins, num_pins);
+	if (i < 0)
+		return NULL;
+	if (num_pins == 1)
+		return "";
+	if (num_pins > ARRAY_SIZE(channel_sfx)) {
+		if (indexp)
+			*indexp = i;
+		return "";
+	}
+	return channel_sfx[i];
+}
+
+static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
+			       const struct auto_pin_cfg *cfg,
+			       const char *name, char *label, int maxlen,
+			       int *indexp)
+{
+	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+	int attr = snd_hda_get_input_pin_attr(def_conf);
+	const char *pfx = "", *sfx = "";
+
+	/* handle as a speaker if it's a fixed line-out */
+	if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)
+		name = "Speaker";
+	/* check the location */
+	switch (attr) {
+	case INPUT_PIN_ATTR_DOCK:
+		pfx = "Dock ";
+		break;
+	case INPUT_PIN_ATTR_FRONT:
+		pfx = "Front ";
+		break;
+	}
+	if (cfg) {
+		/* try to give a unique suffix if needed */
+		sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
+				       indexp);
+		if (!sfx)
+			sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
+					       indexp);
+		if (!sfx) {
+			/* don't add channel suffix for Headphone controls */
+			int idx = find_idx_in_nid_list(nid, cfg->hp_pins,
+						       cfg->hp_outs);
+			if (idx >= 0)
+				*indexp = idx;
+			sfx = "";
+		}
+	}
+	snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
+	return 1;
+}
+
+/**
+ * snd_hda_get_pin_label - Get a label for the given I/O pin
+ *
+ * Get a label for the given pin.  This function works for both input and
+ * output pins.  When @cfg is given as non-NULL, the function tries to get
+ * an optimized label using hda_get_autocfg_input_label().
+ *
+ * This function tries to give a unique label string for the pin as much as
+ * possible.  For example, when the multiple line-outs are present, it adds
+ * the channel suffix like "Front", "Surround", etc (only when @cfg is given).
+ * If no unique name with a suffix is available and @indexp is non-NULL, the
+ * index number is stored in the pointer.
+ */
+int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
+			  const struct auto_pin_cfg *cfg,
+			  char *label, int maxlen, int *indexp)
+{
+	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+	const char *name = NULL;
+	int i;
+
+	if (indexp)
+		*indexp = 0;
+	if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+		return 0;
+
+	switch (get_defcfg_device(def_conf)) {
+	case AC_JACK_LINE_OUT:
+		return fill_audio_out_name(codec, nid, cfg, "Line Out",
+					   label, maxlen, indexp);
+	case AC_JACK_SPEAKER:
+		return fill_audio_out_name(codec, nid, cfg, "Speaker",
+					   label, maxlen, indexp);
+	case AC_JACK_HP_OUT:
+		return fill_audio_out_name(codec, nid, cfg, "Headphone",
+					   label, maxlen, indexp);
+	case AC_JACK_SPDIF_OUT:
+	case AC_JACK_DIG_OTHER_OUT:
+		if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
+			name = "HDMI";
+		else
+			name = "SPDIF";
+		if (cfg && indexp) {
+			i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
+						 cfg->dig_outs);
+			if (i >= 0)
+				*indexp = i;
+		}
+		break;
+	default:
+		if (cfg) {
+			for (i = 0; i < cfg->num_inputs; i++) {
+				if (cfg->inputs[i].pin != nid)
+					continue;
+				name = hda_get_autocfg_input_label(codec, cfg, i);
+				if (name)
+					break;
+			}
+		}
+		if (!name)
+			name = hda_get_input_pin_label(codec, nid, true);
+		break;
+	}
+	if (!name)
+		return 0;
+	strlcpy(label, name, maxlen);
+	return 1;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
+
+int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
+			  const struct hda_verb *list)
+{
+	const struct hda_verb **v;
+	snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
+	v = snd_array_new(&spec->verbs);
+	if (!v)
+		return -ENOMEM;
+	*v = list;
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs);
+
+void snd_hda_gen_apply_verbs(struct hda_codec *codec)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	int i;
+	for (i = 0; i < spec->verbs.used; i++) {
+		struct hda_verb **v = snd_array_elem(&spec->verbs, i);
+		snd_hda_sequence_write(codec, *v);
+	}
+}
+EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs);
+
+void snd_hda_apply_pincfgs(struct hda_codec *codec,
+			   const struct hda_pintbl *cfg)
+{
+	for (; cfg->nid; cfg++)
+		snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+}
+EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs);
+
+void snd_hda_apply_fixup(struct hda_codec *codec, int action)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	int id = spec->fixup_id;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+	const char *modelname = spec->fixup_name;
+#endif
+	int depth = 0;
+
+	if (!spec->fixup_list)
+		return;
+
+	while (id >= 0) {
+		const struct hda_fixup *fix = spec->fixup_list + id;
+
+		switch (fix->type) {
+		case HDA_FIXUP_PINS:
+			if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins)
+				break;
+			snd_printdd(KERN_INFO SFX
+				    "%s: Apply pincfg for %s\n",
+				    codec->chip_name, modelname);
+			snd_hda_apply_pincfgs(codec, fix->v.pins);
+			break;
+		case HDA_FIXUP_VERBS:
+			if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs)
+				break;
+			snd_printdd(KERN_INFO SFX
+				    "%s: Apply fix-verbs for %s\n",
+				    codec->chip_name, modelname);
+			snd_hda_gen_add_verbs(codec->spec, fix->v.verbs);
+			break;
+		case HDA_FIXUP_FUNC:
+			if (!fix->v.func)
+				break;
+			snd_printdd(KERN_INFO SFX
+				    "%s: Apply fix-func for %s\n",
+				    codec->chip_name, modelname);
+			fix->v.func(codec, fix, action);
+			break;
+		default:
+			snd_printk(KERN_ERR SFX
+				   "%s: Invalid fixup type %d\n",
+				   codec->chip_name, fix->type);
+			break;
+		}
+		if (!fix->chained)
+			break;
+		if (++depth > 10)
+			break;
+		id = fix->chain_id;
+	}
+}
+EXPORT_SYMBOL_HDA(snd_hda_apply_fixup);
+
+void snd_hda_pick_fixup(struct hda_codec *codec,
+			const struct hda_model_fixup *models,
+			const struct snd_pci_quirk *quirk,
+			const struct hda_fixup *fixlist)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	const struct snd_pci_quirk *q;
+	int id = -1;
+	const char *name = NULL;
+
+	/* when model=nofixup is given, don't pick up any fixups */
+	if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
+		spec->fixup_list = NULL;
+		spec->fixup_id = -1;
+		return;
+	}
+
+	if (codec->modelname && models) {
+		while (models->name) {
+			if (!strcmp(codec->modelname, models->name)) {
+				id = models->id;
+				name = models->name;
+				break;
+			}
+			models++;
+		}
+	}
+	if (id < 0) {
+		q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+		if (q) {
+			id = q->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+			name = q->name;
+#endif
+		}
+	}
+	if (id < 0) {
+		for (q = quirk; q->subvendor; q++) {
+			unsigned int vendorid =
+				q->subdevice | (q->subvendor << 16);
+			if (vendorid == codec->subsystem_id) {
+				id = q->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+				name = q->name;
+#endif
+				break;
+			}
+		}
+	}
+
+	spec->fixup_id = id;
+	if (id >= 0) {
+		spec->fixup_list = fixlist;
+		spec->fixup_name = name;
+	}
+}
+EXPORT_SYMBOL_HDA(snd_hda_pick_fixup);
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h
new file mode 100644
index 0000000..2a7889d
--- /dev/null
+++ b/sound/pci/hda/hda_auto_parser.h
@@ -0,0 +1,160 @@
+/*
+ * BIOS auto-parser helper functions for HD-audio
+ *
+ * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver 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_HDA_AUTO_PARSER_H
+#define __SOUND_HDA_AUTO_PARSER_H
+
+/*
+ * Helper for automatic pin configuration
+ */
+
+enum {
+	AUTO_PIN_MIC,
+	AUTO_PIN_LINE_IN,
+	AUTO_PIN_CD,
+	AUTO_PIN_AUX,
+	AUTO_PIN_LAST
+};
+
+enum {
+	AUTO_PIN_LINE_OUT,
+	AUTO_PIN_SPEAKER_OUT,
+	AUTO_PIN_HP_OUT
+};
+
+#define AUTO_CFG_MAX_OUTS	HDA_MAX_OUTS
+#define AUTO_CFG_MAX_INS	8
+
+struct auto_pin_cfg_item {
+	hda_nid_t pin;
+	int type;
+};
+
+struct auto_pin_cfg;
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+					const struct auto_pin_cfg *cfg,
+					int input);
+int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
+			  const struct auto_pin_cfg *cfg,
+			  char *label, int maxlen, int *indexp);
+
+enum {
+	INPUT_PIN_ATTR_UNUSED,	/* pin not connected */
+	INPUT_PIN_ATTR_INT,	/* internal mic/line-in */
+	INPUT_PIN_ATTR_DOCK,	/* docking mic/line-in */
+	INPUT_PIN_ATTR_NORMAL,	/* mic/line-in jack */
+	INPUT_PIN_ATTR_FRONT,	/* mic/line-in jack in front */
+	INPUT_PIN_ATTR_REAR,	/* mic/line-in jack in rear */
+};
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf);
+
+struct auto_pin_cfg {
+	int line_outs;
+	/* sorted in the order of Front/Surr/CLFE/Side */
+	hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
+	int speaker_outs;
+	hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
+	int hp_outs;
+	int line_out_type;	/* AUTO_PIN_XXX_OUT */
+	hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
+	int num_inputs;
+	struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
+	int dig_outs;
+	hda_nid_t dig_out_pins[2];
+	hda_nid_t dig_in_pin;
+	hda_nid_t mono_out_pin;
+	int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */
+	int dig_in_type; /* HDA_PCM_TYPE_XXX */
+};
+
+/* bit-flags for snd_hda_parse_pin_def_config() behavior */
+#define HDA_PINCFG_NO_HP_FIXUP	(1 << 0) /* no HP-split */
+#define HDA_PINCFG_NO_LO_FIXUP	(1 << 1) /* don't take other outs as LO */
+
+int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
+			     struct auto_pin_cfg *cfg,
+			     const hda_nid_t *ignore_nids,
+			     unsigned int cond_flags);
+
+/* older function */
+#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
+	snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
+
+/*
+ */
+
+struct hda_gen_spec {
+	/* fix-up list */
+	int fixup_id;
+	const struct hda_fixup *fixup_list;
+	const char *fixup_name;
+
+	/* additional init verbs */
+	struct snd_array verbs;
+};
+
+
+/*
+ * Fix-up pin default configurations and add default verbs
+ */
+
+struct hda_pintbl {
+	hda_nid_t nid;
+	u32 val;
+};
+
+struct hda_model_fixup {
+	const int id;
+	const char *name;
+};
+
+struct hda_fixup {
+	int type;
+	bool chained;
+	int chain_id;
+	union {
+		const struct hda_pintbl *pins;
+		const struct hda_verb *verbs;
+		void (*func)(struct hda_codec *codec,
+			     const struct hda_fixup *fix,
+			     int action);
+	} v;
+};
+
+/* fixup types */
+enum {
+	HDA_FIXUP_INVALID,
+	HDA_FIXUP_PINS,
+	HDA_FIXUP_VERBS,
+	HDA_FIXUP_FUNC,
+};
+
+/* fixup action definitions */
+enum {
+	HDA_FIXUP_ACT_PRE_PROBE,
+	HDA_FIXUP_ACT_PROBE,
+	HDA_FIXUP_ACT_INIT,
+	HDA_FIXUP_ACT_BUILD,
+};
+
+int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
+			  const struct hda_verb *list);
+void snd_hda_gen_apply_verbs(struct hda_codec *codec);
+void snd_hda_apply_pincfgs(struct hda_codec *codec,
+			   const struct hda_pintbl *cfg);
+void snd_hda_apply_fixup(struct hda_codec *codec, int action);
+void snd_hda_pick_fixup(struct hda_codec *codec,
+			const struct hda_model_fixup *models,
+			const struct snd_pci_quirk *quirk,
+			const struct hda_fixup *fixlist);
+
+#endif /* __SOUND_HDA_AUTO_PARSER_H */
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 841475c..eb09a33 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -334,54 +334,23 @@
 	return NULL;
 }
 
-/**
- * snd_hda_get_conn_list - get connection list
- * @codec: the HDA codec
- * @nid: NID to parse
- * @listp: the pointer to store NID list
- *
- * Parses the connection list of the given widget and stores the list
- * of NIDs.
- *
- * Returns the number of connections, or a negative error code.
- */
-int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
-			  const hda_nid_t **listp)
+/* read the connection and add to the cache */
+static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
 {
-	struct snd_array *array = &codec->conn_lists;
-	int len, err;
 	hda_nid_t list[HDA_MAX_CONNECTIONS];
-	hda_nid_t *p;
-	bool added = false;
+	int len;
 
- again:
-	/* if the connection-list is already cached, read it */
-	p = lookup_conn_list(array, nid);
-	if (p) {
-		if (listp)
-			*listp = p + 2;
-		return p[1];
-	}
-	if (snd_BUG_ON(added))
-		return -EINVAL;
-
-	/* read the connection and add to the cache */
-	len = snd_hda_get_raw_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
+	len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list));
 	if (len < 0)
 		return len;
-	err = snd_hda_override_conn_list(codec, nid, len, list);
-	if (err < 0)
-		return err;
-	added = true;
-	goto again;
+	return snd_hda_override_conn_list(codec, nid, len, list);
 }
-EXPORT_SYMBOL_HDA(snd_hda_get_conn_list);
 
 /**
  * snd_hda_get_connections - copy connection list
  * @codec: the HDA codec
  * @nid: NID to parse
- * @conn_list: connection list array
+ * @conn_list: connection list array; when NULL, checks only the size
  * @max_conns: max. number of connections to store
  *
  * Parses the connection list of the given widget and stores the list
@@ -390,21 +359,41 @@
  * Returns the number of connections, or a negative error code.
  */
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
-			     hda_nid_t *conn_list, int max_conns)
+			    hda_nid_t *conn_list, int max_conns)
 {
-	const hda_nid_t *list;
-	int len = snd_hda_get_conn_list(codec, nid, &list);
+	struct snd_array *array = &codec->conn_lists;
+	int len;
+	hda_nid_t *p;
+	bool added = false;
 
-	if (len <= 0)
-		return len;
-	if (len > max_conns) {
-		snd_printk(KERN_ERR "hda_codec: "
-			   "Too many connections %d for NID 0x%x\n",
-			   len, nid);
-		return -EINVAL;
+ again:
+	mutex_lock(&codec->hash_mutex);
+	len = -1;
+	/* if the connection-list is already cached, read it */
+	p = lookup_conn_list(array, nid);
+	if (p) {
+		len = p[1];
+		if (conn_list && len > max_conns) {
+			snd_printk(KERN_ERR "hda_codec: "
+				   "Too many connections %d for NID 0x%x\n",
+				   len, nid);
+			mutex_unlock(&codec->hash_mutex);
+			return -EINVAL;
+		}
+		if (conn_list && len)
+			memcpy(conn_list, p + 2, len * sizeof(hda_nid_t));
 	}
-	memcpy(conn_list, list, len * sizeof(hda_nid_t));
-	return len;
+	mutex_unlock(&codec->hash_mutex);
+	if (len >= 0)
+		return len;
+	if (snd_BUG_ON(added))
+		return -EINVAL;
+
+	len = read_and_add_raw_conns(codec, nid);
+	if (len < 0)
+		return len;
+	added = true;
+	goto again;
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_connections);
 
@@ -543,6 +532,7 @@
 	hda_nid_t *p;
 	int i, old_used;
 
+	mutex_lock(&codec->hash_mutex);
 	p = lookup_conn_list(array, nid);
 	if (p)
 		*p = -1; /* invalidate the old entry */
@@ -553,10 +543,12 @@
 	for (i = 0; i < len; i++)
 		if (!add_conn_list(array, list[i]))
 			goto error_add;
+	mutex_unlock(&codec->hash_mutex);
 	return 0;
 
  error_add:
 	array->used = old_used;
+	mutex_unlock(&codec->hash_mutex);
 	return -ENOMEM;
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
@@ -1255,6 +1247,7 @@
 	codec->addr = codec_addr;
 	mutex_init(&codec->spdif_mutex);
 	mutex_init(&codec->control_mutex);
+	mutex_init(&codec->hash_mutex);
 	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
 	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
 	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
@@ -1264,15 +1257,9 @@
 	snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
 	snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
 	snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
-	if (codec->bus->modelname) {
-		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
-		if (!codec->modelname) {
-			snd_hda_codec_free(codec);
-			return -ENODEV;
-		}
-	}
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
+	spin_lock_init(&codec->power_lock);
 	INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
 	/* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
 	 * the caller has to power down appropriatley after initialization
@@ -1281,6 +1268,14 @@
 	hda_keep_power_on(codec);
 #endif
 
+	if (codec->bus->modelname) {
+		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
+		if (!codec->modelname) {
+			snd_hda_codec_free(codec);
+			return -ENODEV;
+		}
+	}
+
 	list_add_tail(&codec->list, &bus->codec_list);
 	bus->caddr_tbl[codec_addr] = codec;
 
@@ -1603,6 +1598,60 @@
 	return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key);
 }
 
+/* overwrite the value with the key in the caps hash */
+static int write_caps_hash(struct hda_codec *codec, u32 key, unsigned int val)
+{
+	struct hda_amp_info *info;
+
+	mutex_lock(&codec->hash_mutex);
+	info = get_alloc_amp_hash(codec, key);
+	if (!info) {
+		mutex_unlock(&codec->hash_mutex);
+		return -EINVAL;
+	}
+	info->amp_caps = val;
+	info->head.val |= INFO_AMP_CAPS;
+	mutex_unlock(&codec->hash_mutex);
+	return 0;
+}
+
+/* query the value from the caps hash; if not found, fetch the current
+ * value from the given function and store in the hash
+ */
+static unsigned int
+query_caps_hash(struct hda_codec *codec, hda_nid_t nid, int dir, u32 key,
+		unsigned int (*func)(struct hda_codec *, hda_nid_t, int))
+{
+	struct hda_amp_info *info;
+	unsigned int val;
+
+	mutex_lock(&codec->hash_mutex);
+	info = get_alloc_amp_hash(codec, key);
+	if (!info) {
+		mutex_unlock(&codec->hash_mutex);
+		return 0;
+	}
+	if (!(info->head.val & INFO_AMP_CAPS)) {
+		mutex_unlock(&codec->hash_mutex); /* for reentrance */
+		val = func(codec, nid, dir);
+		write_caps_hash(codec, key, val);
+	} else {
+		val = info->amp_caps;
+		mutex_unlock(&codec->hash_mutex);
+	}
+	return val;
+}
+
+static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid,
+				 int direction)
+{
+	if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
+		nid = codec->afg;
+	return snd_hda_param_read(codec, nid,
+				  direction == HDA_OUTPUT ?
+				  AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
+}
+
 /**
  * query_amp_caps - query AMP capabilities
  * @codec: the HD-auio codec
@@ -1617,22 +1666,9 @@
  */
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
 {
-	struct hda_amp_info *info;
-
-	info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0));
-	if (!info)
-		return 0;
-	if (!(info->head.val & INFO_AMP_CAPS)) {
-		if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
-			nid = codec->afg;
-		info->amp_caps = snd_hda_param_read(codec, nid,
-						    direction == HDA_OUTPUT ?
-						    AC_PAR_AMP_OUT_CAP :
-						    AC_PAR_AMP_IN_CAP);
-		if (info->amp_caps)
-			info->head.val |= INFO_AMP_CAPS;
-	}
-	return info->amp_caps;
+	return query_caps_hash(codec, nid, direction,
+			       HDA_HASH_KEY(nid, direction, 0),
+			       read_amp_cap);
 }
 EXPORT_SYMBOL_HDA(query_amp_caps);
 
@@ -1652,34 +1688,12 @@
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 			      unsigned int caps)
 {
-	struct hda_amp_info *info;
-
-	info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, dir, 0));
-	if (!info)
-		return -EINVAL;
-	info->amp_caps = caps;
-	info->head.val |= INFO_AMP_CAPS;
-	return 0;
+	return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps);
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
 
-static unsigned int
-query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key,
-		unsigned int (*func)(struct hda_codec *, hda_nid_t))
-{
-	struct hda_amp_info *info;
-
-	info = get_alloc_amp_hash(codec, key);
-	if (!info)
-		return 0;
-	if (!info->head.val) {
-		info->head.val |= INFO_AMP_CAPS;
-		info->amp_caps = func(codec, nid);
-	}
-	return info->amp_caps;
-}
-
-static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid,
+				 int dir)
 {
 	return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 }
@@ -1697,7 +1711,7 @@
  */
 u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
 {
-	return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid),
+	return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid),
 			       read_pin_cap);
 }
 EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
@@ -1715,41 +1729,47 @@
 int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
 			      unsigned int caps)
 {
-	struct hda_amp_info *info;
-	info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
-	if (!info)
-		return -ENOMEM;
-	info->amp_caps = caps;
-	info->head.val |= INFO_AMP_CAPS;
-	return 0;
+	return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps);
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps);
 
-/*
- * read the current volume to info
- * if the cache exists, read the cache value.
+/* read or sync the hash value with the current value;
+ * call within hash_mutex
  */
-static unsigned int get_vol_mute(struct hda_codec *codec,
-				 struct hda_amp_info *info, hda_nid_t nid,
-				 int ch, int direction, int index)
+static struct hda_amp_info *
+update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch,
+		int direction, int index)
 {
-	u32 val, parm;
+	struct hda_amp_info *info;
+	unsigned int parm, val = 0;
+	bool val_read = false;
 
-	if (info->head.val & INFO_AMP_VOL(ch))
-		return info->vol[ch];
-
-	parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
-	parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
-	parm |= index;
-	val = snd_hda_codec_read(codec, nid, 0,
+ retry:
+	info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
+	if (!info)
+		return NULL;
+	if (!(info->head.val & INFO_AMP_VOL(ch))) {
+		if (!val_read) {
+			mutex_unlock(&codec->hash_mutex);
+			parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
+			parm |= direction == HDA_OUTPUT ?
+				AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
+			parm |= index;
+			val = snd_hda_codec_read(codec, nid, 0,
 				 AC_VERB_GET_AMP_GAIN_MUTE, parm);
-	info->vol[ch] = val & 0xff;
-	info->head.val |= INFO_AMP_VOL(ch);
-	return info->vol[ch];
+			val &= 0xff;
+			val_read = true;
+			mutex_lock(&codec->hash_mutex);
+			goto retry;
+		}
+		info->vol[ch] = val;
+		info->head.val |= INFO_AMP_VOL(ch);
+	}
+	return info;
 }
 
 /*
- * write the current volume in info to the h/w and update the cache
+ * write the current volume in info to the h/w
  */
 static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
 			 hda_nid_t nid, int ch, int direction, int index,
@@ -1766,7 +1786,6 @@
 	else
 		parm |= val;
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
-	info->vol[ch] = val;
 }
 
 /**
@@ -1783,10 +1802,14 @@
 			   int direction, int index)
 {
 	struct hda_amp_info *info;
-	info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
-	if (!info)
-		return 0;
-	return get_vol_mute(codec, info, nid, ch, direction, index);
+	unsigned int val = 0;
+
+	mutex_lock(&codec->hash_mutex);
+	info = update_amp_hash(codec, nid, ch, direction, index);
+	if (info)
+		val = info->vol[ch];
+	mutex_unlock(&codec->hash_mutex);
+	return val;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read);
 
@@ -1808,15 +1831,23 @@
 {
 	struct hda_amp_info *info;
 
-	info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
-	if (!info)
-		return 0;
 	if (snd_BUG_ON(mask & ~0xff))
 		mask &= 0xff;
 	val &= mask;
-	val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask;
-	if (info->vol[ch] == val)
+
+	mutex_lock(&codec->hash_mutex);
+	info = update_amp_hash(codec, nid, ch, direction, idx);
+	if (!info) {
+		mutex_unlock(&codec->hash_mutex);
 		return 0;
+	}
+	val |= info->vol[ch] & ~mask;
+	if (info->vol[ch] == val) {
+		mutex_unlock(&codec->hash_mutex);
+		return 0;
+	}
+	info->vol[ch] = val;
+	mutex_unlock(&codec->hash_mutex);
 	put_vol_mute(codec, info, nid, ch, direction, idx, val);
 	return 1;
 }
@@ -2263,7 +2294,10 @@
 	/* OK, let it free */
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-	cancel_delayed_work(&codec->power_work);
+	cancel_delayed_work_sync(&codec->power_work);
+	codec->power_on = 0;
+	codec->power_transition = 0;
+	codec->power_jiffies = jiffies;
 	flush_workqueue(codec->bus->workq);
 #endif
 	snd_hda_ctls_clear(codec);
@@ -2859,12 +2893,15 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	int idx = kcontrol->private_value;
-	struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+	struct hda_spdif_out *spdif;
 
+	mutex_lock(&codec->spdif_mutex);
+	spdif = snd_array_elem(&codec->spdif_out, idx);
 	ucontrol->value.iec958.status[0] = spdif->status & 0xff;
 	ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff;
 	ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff;
 	ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff;
+	mutex_unlock(&codec->spdif_mutex);
 
 	return 0;
 }
@@ -2950,12 +2987,14 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	int idx = kcontrol->private_value;
-	struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
-	hda_nid_t nid = spdif->nid;
+	struct hda_spdif_out *spdif;
+	hda_nid_t nid;
 	unsigned short val;
 	int change;
 
 	mutex_lock(&codec->spdif_mutex);
+	spdif = snd_array_elem(&codec->spdif_out, idx);
+	nid = spdif->nid;
 	spdif->status = ucontrol->value.iec958.status[0] |
 		((unsigned int)ucontrol->value.iec958.status[1] << 8) |
 		((unsigned int)ucontrol->value.iec958.status[2] << 16) |
@@ -2977,9 +3016,12 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	int idx = kcontrol->private_value;
-	struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+	struct hda_spdif_out *spdif;
 
+	mutex_lock(&codec->spdif_mutex);
+	spdif = snd_array_elem(&codec->spdif_out, idx);
 	ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE;
+	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
 
@@ -2999,12 +3041,14 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	int idx = kcontrol->private_value;
-	struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
-	hda_nid_t nid = spdif->nid;
+	struct hda_spdif_out *spdif;
+	hda_nid_t nid;
 	unsigned short val;
 	int change;
 
 	mutex_lock(&codec->spdif_mutex);
+	spdif = snd_array_elem(&codec->spdif_out, idx);
+	nid = spdif->nid;
 	val = spdif->ctls & ~AC_DIG1_ENABLE;
 	if (ucontrol->value.integer.value[0])
 		val |= AC_DIG1_ENABLE;
@@ -3092,6 +3136,9 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls);
 
+/* get the hda_spdif_out entry from the given NID
+ * call within spdif_mutex lock
+ */
 struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
 					       hda_nid_t nid)
 {
@@ -3108,9 +3155,10 @@
 
 void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
 {
-	struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+	struct hda_spdif_out *spdif;
 
 	mutex_lock(&codec->spdif_mutex);
+	spdif = snd_array_elem(&codec->spdif_out, idx);
 	spdif->nid = (u16)-1;
 	mutex_unlock(&codec->spdif_mutex);
 }
@@ -3118,10 +3166,11 @@
 
 void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
 {
-	struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+	struct hda_spdif_out *spdif;
 	unsigned short val;
 
 	mutex_lock(&codec->spdif_mutex);
+	spdif = snd_array_elem(&codec->spdif_out, idx);
 	if (spdif->nid != nid) {
 		spdif->nid = nid;
 		val = spdif->ctls;
@@ -3486,11 +3535,14 @@
 			    codec->afg ? codec->afg : codec->mfg,
 			    AC_PWRST_D3);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-	snd_hda_update_power_acct(codec);
 	cancel_delayed_work(&codec->power_work);
+	spin_lock(&codec->power_lock);
+	snd_hda_update_power_acct(codec);
+	trace_hda_power_down(codec);
 	codec->power_on = 0;
 	codec->power_transition = 0;
 	codec->power_jiffies = jiffies;
+	spin_unlock(&codec->power_lock);
 #endif
 }
 
@@ -3499,6 +3551,10 @@
  */
 static void hda_call_codec_resume(struct hda_codec *codec)
 {
+	/* set as if powered on for avoiding re-entering the resume
+	 * in the resume / power-save sequence
+	 */
+	hda_keep_power_on(codec);
 	hda_set_power_state(codec,
 			    codec->afg ? codec->afg : codec->mfg,
 			    AC_PWRST_D0);
@@ -3514,6 +3570,7 @@
 		snd_hda_codec_resume_amp(codec);
 		snd_hda_codec_resume_cache(codec);
 	}
+	snd_hda_power_down(codec); /* flag down before returning */
 }
 #endif /* CONFIG_PM */
 
@@ -3665,7 +3722,8 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
 
-static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid,
+				  int dir)
 {
 	unsigned int val = 0;
 	if (nid != codec->afg &&
@@ -3680,11 +3738,12 @@
 
 static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
 {
-	return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid),
+	return query_caps_hash(codec, nid, 0, HDA_HASH_PARPCM_KEY(nid),
 			       get_pcm_param);
 }
 
-static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid,
+				     int dir)
 {
 	unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
 	if (!streams || streams == -1)
@@ -3696,7 +3755,7 @@
 
 static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
 {
-	return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid),
+	return query_caps_hash(codec, nid, 0, HDA_HASH_PARSTR_KEY(nid),
 			       get_stream_param);
 }
 
@@ -3775,11 +3834,13 @@
 					bps = 20;
 			}
 		}
+#if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */
 		if (streams & AC_SUPFMT_FLOAT32) {
 			formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
 			if (!bps)
 				bps = 32;
 		}
+#endif
 		if (streams == AC_SUPFMT_AC3) {
 			/* should be exclusive */
 			/* temporary hack: we have still no proper support
@@ -4283,12 +4344,18 @@
 		container_of(work, struct hda_codec, power_work.work);
 	struct hda_bus *bus = codec->bus;
 
-	if (!codec->power_on || codec->power_count) {
-		codec->power_transition = 0;
+	spin_lock(&codec->power_lock);
+	if (codec->power_transition > 0) { /* during power-up sequence? */
+		spin_unlock(&codec->power_lock);
 		return;
 	}
+	if (!codec->power_on || codec->power_count) {
+		codec->power_transition = 0;
+		spin_unlock(&codec->power_lock);
+		return;
+	}
+	spin_unlock(&codec->power_lock);
 
-	trace_hda_power_down(codec);
 	hda_call_codec_suspend(codec);
 	if (bus->ops.pm_notify)
 		bus->ops.pm_notify(bus);
@@ -4296,9 +4363,11 @@
 
 static void hda_keep_power_on(struct hda_codec *codec)
 {
+	spin_lock(&codec->power_lock);
 	codec->power_count++;
 	codec->power_on = 1;
 	codec->power_jiffies = jiffies;
+	spin_unlock(&codec->power_lock);
 }
 
 /* update the power on/off account with the current jiffies */
@@ -4323,19 +4392,31 @@
 {
 	struct hda_bus *bus = codec->bus;
 
+	spin_lock(&codec->power_lock);
 	codec->power_count++;
-	if (codec->power_on || codec->power_transition)
+	if (codec->power_on || codec->power_transition > 0) {
+		spin_unlock(&codec->power_lock);
 		return;
+	}
+	spin_unlock(&codec->power_lock);
 
+	cancel_delayed_work_sync(&codec->power_work);
+
+	spin_lock(&codec->power_lock);
 	trace_hda_power_up(codec);
 	snd_hda_update_power_acct(codec);
 	codec->power_on = 1;
 	codec->power_jiffies = jiffies;
+	codec->power_transition = 1; /* avoid reentrance */
+	spin_unlock(&codec->power_lock);
+
 	if (bus->ops.pm_notify)
 		bus->ops.pm_notify(bus);
 	hda_call_codec_resume(codec);
-	cancel_delayed_work(&codec->power_work);
+
+	spin_lock(&codec->power_lock);
 	codec->power_transition = 0;
+	spin_unlock(&codec->power_lock);
 }
 EXPORT_SYMBOL_HDA(snd_hda_power_up);
 
@@ -4351,14 +4432,18 @@
  */
 void snd_hda_power_down(struct hda_codec *codec)
 {
+	spin_lock(&codec->power_lock);
 	--codec->power_count;
-	if (!codec->power_on || codec->power_count || codec->power_transition)
+	if (!codec->power_on || codec->power_count || codec->power_transition) {
+		spin_unlock(&codec->power_lock);
 		return;
+	}
 	if (power_save(codec)) {
-		codec->power_transition = 1; /* avoid reentrance */
+		codec->power_transition = -1; /* avoid reentrance */
 		queue_delayed_work(codec->bus->workq, &codec->power_work,
 				msecs_to_jiffies(power_save(codec) * 1000));
 	}
+	spin_unlock(&codec->power_lock);
 }
 EXPORT_SYMBOL_HDA(snd_hda_power_down);
 
@@ -4710,11 +4795,11 @@
 {
 	const hda_nid_t *nids = mout->dac_nids;
 	int chs = substream->runtime->channels;
-	struct hda_spdif_out *spdif =
-			snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
+	struct hda_spdif_out *spdif;
 	int i;
 
 	mutex_lock(&codec->spdif_mutex);
+	spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
 	if (mout->dig_out_nid && mout->share_spdif &&
 	    mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
 		if (chs == 2 &&
@@ -4795,601 +4880,58 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup);
 
-/*
- * Helper for automatic pin configuration
- */
-
-static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
-{
-	for (; *list; list++)
-		if (*list == nid)
-			return 1;
-	return 0;
-}
-
-
-/*
- * Sort an associated group of pins according to their sequence numbers.
- */
-static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
-				  int num_pins)
-{
-	int i, j;
-	short seq;
-	hda_nid_t nid;
-
-	for (i = 0; i < num_pins; i++) {
-		for (j = i + 1; j < num_pins; j++) {
-			if (sequences[i] > sequences[j]) {
-				seq = sequences[i];
-				sequences[i] = sequences[j];
-				sequences[j] = seq;
-				nid = pins[i];
-				pins[i] = pins[j];
-				pins[j] = nid;
-			}
-		}
-	}
-}
-
-
-/* add the found input-pin to the cfg->inputs[] table */
-static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
-				   int type)
-{
-	if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
-		cfg->inputs[cfg->num_inputs].pin = nid;
-		cfg->inputs[cfg->num_inputs].type = type;
-		cfg->num_inputs++;
-	}
-}
-
-/* sort inputs in the order of AUTO_PIN_* type */
-static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
-{
-	int i, j;
-
-	for (i = 0; i < cfg->num_inputs; i++) {
-		for (j = i + 1; j < cfg->num_inputs; j++) {
-			if (cfg->inputs[i].type > cfg->inputs[j].type) {
-				struct auto_pin_cfg_item tmp;
-				tmp = cfg->inputs[i];
-				cfg->inputs[i] = cfg->inputs[j];
-				cfg->inputs[j] = tmp;
-			}
-		}
-	}
-}
-
-/* Reorder the surround channels
- * ALSA sequence is front/surr/clfe/side
- * HDA sequence is:
- *    4-ch: front/surr  =>  OK as it is
- *    6-ch: front/clfe/surr
- *    8-ch: front/clfe/rear/side|fc
- */
-static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
-{
-	hda_nid_t nid;
-
-	switch (nums) {
-	case 3:
-	case 4:
-		nid = pins[1];
-		pins[1] = pins[2];
-		pins[2] = nid;
-		break;
-	}
-}
-
-/*
- * Parse all pin widgets and store the useful pin nids to cfg
- *
- * The number of line-outs or any primary output is stored in line_outs,
- * and the corresponding output pins are assigned to line_out_pins[],
- * in the order of front, rear, CLFE, side, ...
- *
- * If more extra outputs (speaker and headphone) are found, the pins are
- * assisnged to hp_pins[] and speaker_pins[], respectively.  If no line-out jack
- * is detected, one of speaker of HP pins is assigned as the primary
- * output, i.e. to line_out_pins[0].  So, line_outs is always positive
- * if any analog output exists.
- *
- * The analog input pins are assigned to inputs array.
- * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
- * respectively.
- */
-int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
-			     struct auto_pin_cfg *cfg,
-			     const hda_nid_t *ignore_nids,
-			     unsigned int cond_flags)
-{
-	hda_nid_t nid, end_nid;
-	short seq, assoc_line_out;
-	short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
-	short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
-	short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
-	int i;
-
-	memset(cfg, 0, sizeof(*cfg));
-
-	memset(sequences_line_out, 0, sizeof(sequences_line_out));
-	memset(sequences_speaker, 0, sizeof(sequences_speaker));
-	memset(sequences_hp, 0, sizeof(sequences_hp));
-	assoc_line_out = 0;
-
-	codec->ignore_misc_bit = true;
-	end_nid = codec->start_nid + codec->num_nodes;
-	for (nid = codec->start_nid; nid < end_nid; nid++) {
-		unsigned int wid_caps = get_wcaps(codec, nid);
-		unsigned int wid_type = get_wcaps_type(wid_caps);
-		unsigned int def_conf;
-		short assoc, loc, conn, dev;
-
-		/* read all default configuration for pin complex */
-		if (wid_type != AC_WID_PIN)
-			continue;
-		/* ignore the given nids (e.g. pc-beep returns error) */
-		if (ignore_nids && is_in_nid_list(nid, ignore_nids))
-			continue;
-
-		def_conf = snd_hda_codec_get_pincfg(codec, nid);
-		if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
-		      AC_DEFCFG_MISC_NO_PRESENCE))
-			codec->ignore_misc_bit = false;
-		conn = get_defcfg_connect(def_conf);
-		if (conn == AC_JACK_PORT_NONE)
-			continue;
-		loc = get_defcfg_location(def_conf);
-		dev = get_defcfg_device(def_conf);
-
-		/* workaround for buggy BIOS setups */
-		if (dev == AC_JACK_LINE_OUT) {
-			if (conn == AC_JACK_PORT_FIXED)
-				dev = AC_JACK_SPEAKER;
-		}
-
-		switch (dev) {
-		case AC_JACK_LINE_OUT:
-			seq = get_defcfg_sequence(def_conf);
-			assoc = get_defcfg_association(def_conf);
-
-			if (!(wid_caps & AC_WCAP_STEREO))
-				if (!cfg->mono_out_pin)
-					cfg->mono_out_pin = nid;
-			if (!assoc)
-				continue;
-			if (!assoc_line_out)
-				assoc_line_out = assoc;
-			else if (assoc_line_out != assoc)
-				continue;
-			if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
-				continue;
-			cfg->line_out_pins[cfg->line_outs] = nid;
-			sequences_line_out[cfg->line_outs] = seq;
-			cfg->line_outs++;
-			break;
-		case AC_JACK_SPEAKER:
-			seq = get_defcfg_sequence(def_conf);
-			assoc = get_defcfg_association(def_conf);
-			if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
-				continue;
-			cfg->speaker_pins[cfg->speaker_outs] = nid;
-			sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq;
-			cfg->speaker_outs++;
-			break;
-		case AC_JACK_HP_OUT:
-			seq = get_defcfg_sequence(def_conf);
-			assoc = get_defcfg_association(def_conf);
-			if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
-				continue;
-			cfg->hp_pins[cfg->hp_outs] = nid;
-			sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
-			cfg->hp_outs++;
-			break;
-		case AC_JACK_MIC_IN:
-			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
-			break;
-		case AC_JACK_LINE_IN:
-			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
-			break;
-		case AC_JACK_CD:
-			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
-			break;
-		case AC_JACK_AUX:
-			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
-			break;
-		case AC_JACK_SPDIF_OUT:
-		case AC_JACK_DIG_OTHER_OUT:
-			if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
-				continue;
-			cfg->dig_out_pins[cfg->dig_outs] = nid;
-			cfg->dig_out_type[cfg->dig_outs] =
-				(loc == AC_JACK_LOC_HDMI) ?
-				HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF;
-			cfg->dig_outs++;
-			break;
-		case AC_JACK_SPDIF_IN:
-		case AC_JACK_DIG_OTHER_IN:
-			cfg->dig_in_pin = nid;
-			if (loc == AC_JACK_LOC_HDMI)
-				cfg->dig_in_type = HDA_PCM_TYPE_HDMI;
-			else
-				cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
-			break;
-		}
-	}
-
-	/* FIX-UP:
-	 * If no line-out is defined but multiple HPs are found,
-	 * some of them might be the real line-outs.
-	 */
-	if (!cfg->line_outs && cfg->hp_outs > 1 &&
-	    !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
-		int i = 0;
-		while (i < cfg->hp_outs) {
-			/* The real HPs should have the sequence 0x0f */
-			if ((sequences_hp[i] & 0x0f) == 0x0f) {
-				i++;
-				continue;
-			}
-			/* Move it to the line-out table */
-			cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i];
-			sequences_line_out[cfg->line_outs] = sequences_hp[i];
-			cfg->line_outs++;
-			cfg->hp_outs--;
-			memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1,
-				sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i));
-			memmove(sequences_hp + i, sequences_hp + i + 1,
-				sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
-		}
-		memset(cfg->hp_pins + cfg->hp_outs, 0,
-		       sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
-		if (!cfg->hp_outs)
-			cfg->line_out_type = AUTO_PIN_HP_OUT;
-
-	}
-
-	/* sort by sequence */
-	sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out,
-			      cfg->line_outs);
-	sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
-			      cfg->speaker_outs);
-	sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
-			      cfg->hp_outs);
-
-	/*
-	 * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
-	 * as a primary output
-	 */
-	if (!cfg->line_outs &&
-	    !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) {
-		if (cfg->speaker_outs) {
-			cfg->line_outs = cfg->speaker_outs;
-			memcpy(cfg->line_out_pins, cfg->speaker_pins,
-			       sizeof(cfg->speaker_pins));
-			cfg->speaker_outs = 0;
-			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
-			cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
-		} else if (cfg->hp_outs) {
-			cfg->line_outs = cfg->hp_outs;
-			memcpy(cfg->line_out_pins, cfg->hp_pins,
-			       sizeof(cfg->hp_pins));
-			cfg->hp_outs = 0;
-			memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
-			cfg->line_out_type = AUTO_PIN_HP_OUT;
-		}
-	}
-
-	reorder_outputs(cfg->line_outs, cfg->line_out_pins);
-	reorder_outputs(cfg->hp_outs, cfg->hp_pins);
-	reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
-
-	sort_autocfg_input_pins(cfg);
-
-	/*
-	 * debug prints of the parsed results
-	 */
-	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
-		   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
-		   cfg->line_out_pins[2], cfg->line_out_pins[3],
-		   cfg->line_out_pins[4],
-		   cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
-		   (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
-		    "speaker" : "line"));
-	snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
-		   cfg->speaker_outs, cfg->speaker_pins[0],
-		   cfg->speaker_pins[1], cfg->speaker_pins[2],
-		   cfg->speaker_pins[3], cfg->speaker_pins[4]);
-	snd_printd("   hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
-		   cfg->hp_outs, cfg->hp_pins[0],
-		   cfg->hp_pins[1], cfg->hp_pins[2],
-		   cfg->hp_pins[3], cfg->hp_pins[4]);
-	snd_printd("   mono: mono_out=0x%x\n", cfg->mono_out_pin);
-	if (cfg->dig_outs)
-		snd_printd("   dig-out=0x%x/0x%x\n",
-			   cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
-	snd_printd("   inputs:");
-	for (i = 0; i < cfg->num_inputs; i++) {
-		snd_printd(" %s=0x%x",
-			    hda_get_autocfg_input_label(codec, cfg, i),
-			    cfg->inputs[i].pin);
-	}
-	snd_printd("\n");
-	if (cfg->dig_in_pin)
-		snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
-
-	return 0;
-}
-EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
-
-int snd_hda_get_input_pin_attr(unsigned int def_conf)
-{
-	unsigned int loc = get_defcfg_location(def_conf);
-	unsigned int conn = get_defcfg_connect(def_conf);
-	if (conn == AC_JACK_PORT_NONE)
-		return INPUT_PIN_ATTR_UNUSED;
-	/* Windows may claim the internal mic to be BOTH, too */
-	if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
-		return INPUT_PIN_ATTR_INT;
-	if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
-		return INPUT_PIN_ATTR_INT;
-	if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
-		return INPUT_PIN_ATTR_DOCK;
-	if (loc == AC_JACK_LOC_REAR)
-		return INPUT_PIN_ATTR_REAR;
-	if (loc == AC_JACK_LOC_FRONT)
-		return INPUT_PIN_ATTR_FRONT;
-	return INPUT_PIN_ATTR_NORMAL;
-}
-EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
-
 /**
- * hda_get_input_pin_label - Give a label for the given input pin
+ * snd_hda_get_default_vref - Get the default (mic) VREF pin bits
  *
- * When check_location is true, the function checks the pin location
- * for mic and line-in pins, and set an appropriate prefix like "Front",
- * "Rear", "Internal".
+ * Guess the suitable VREF pin bits to be set as the pin-control value.
+ * Note: the function doesn't set the AC_PINCTL_IN_EN bit.
  */
-
-static const char *hda_get_input_pin_label(struct hda_codec *codec,
-					   hda_nid_t pin, bool check_location)
+unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin)
 {
-	unsigned int def_conf;
-	static const char * const mic_names[] = {
-		"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
-	};
-	int attr;
-
-	def_conf = snd_hda_codec_get_pincfg(codec, pin);
-
-	switch (get_defcfg_device(def_conf)) {
-	case AC_JACK_MIC_IN:
-		if (!check_location)
-			return "Mic";
-		attr = snd_hda_get_input_pin_attr(def_conf);
-		if (!attr)
-			return "None";
-		return mic_names[attr - 1];
-	case AC_JACK_LINE_IN:
-		if (!check_location)
-			return "Line";
-		attr = snd_hda_get_input_pin_attr(def_conf);
-		if (!attr)
-			return "None";
-		if (attr == INPUT_PIN_ATTR_DOCK)
-			return "Dock Line";
-		return "Line";
-	case AC_JACK_AUX:
-		return "Aux";
-	case AC_JACK_CD:
-		return "CD";
-	case AC_JACK_SPDIF_IN:
-		return "SPDIF In";
-	case AC_JACK_DIG_OTHER_IN:
-		return "Digital In";
-	default:
-		return "Misc";
-	}
+	unsigned int pincap;
+	unsigned int oldval;
+	oldval = snd_hda_codec_read(codec, pin, 0,
+				    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+	pincap = snd_hda_query_pin_caps(codec, pin);
+	pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+	/* Exception: if the default pin setup is vref50, we give it priority */
+	if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
+		return AC_PINCTL_VREF_80;
+	else if (pincap & AC_PINCAP_VREF_50)
+		return AC_PINCTL_VREF_50;
+	else if (pincap & AC_PINCAP_VREF_100)
+		return AC_PINCTL_VREF_100;
+	else if (pincap & AC_PINCAP_VREF_GRD)
+		return AC_PINCTL_VREF_GRD;
+	return AC_PINCTL_VREF_HIZ;
 }
+EXPORT_SYMBOL_HDA(snd_hda_get_default_vref);
 
-/* Check whether the location prefix needs to be added to the label.
- * If all mic-jacks are in the same location (e.g. rear panel), we don't
- * have to put "Front" prefix to each label.  In such a case, returns false.
- */
-static int check_mic_location_need(struct hda_codec *codec,
-				   const struct auto_pin_cfg *cfg,
-				   int input)
+int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
+			 unsigned int val, bool cached)
 {
-	unsigned int defc;
-	int i, attr, attr2;
-
-	defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
-	attr = snd_hda_get_input_pin_attr(defc);
-	/* for internal or docking mics, we need locations */
-	if (attr <= INPUT_PIN_ATTR_NORMAL)
-		return 1;
-
-	attr = 0;
-	for (i = 0; i < cfg->num_inputs; i++) {
-		defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
-		attr2 = snd_hda_get_input_pin_attr(defc);
-		if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
-			if (attr && attr != attr2)
-				return 1; /* different locations found */
-			attr = attr2;
+	if (val) {
+		unsigned int cap = snd_hda_query_pin_caps(codec, pin);
+		if (cap && (val & AC_PINCTL_OUT_EN)) {
+			if (!(cap & AC_PINCAP_OUT))
+				val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+			else if ((val & AC_PINCTL_HP_EN) &&
+				 !(cap & AC_PINCAP_HP_DRV))
+				val &= ~AC_PINCTL_HP_EN;
+		}
+		if (cap && (val & AC_PINCTL_IN_EN)) {
+			if (!(cap & AC_PINCAP_IN))
+				val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN);
 		}
 	}
-	return 0;
+	if (cached)
+		return snd_hda_codec_update_cache(codec, pin, 0,
+				AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+	else
+		return snd_hda_codec_write(codec, pin, 0,
+					   AC_VERB_SET_PIN_WIDGET_CONTROL, val);
 }
-
-/**
- * hda_get_autocfg_input_label - Get a label for the given input
- *
- * Get a label for the given input pin defined by the autocfg item.
- * Unlike hda_get_input_pin_label(), this function checks all inputs
- * defined in autocfg and avoids the redundant mic/line prefix as much as
- * possible.
- */
-const char *hda_get_autocfg_input_label(struct hda_codec *codec,
-					const struct auto_pin_cfg *cfg,
-					int input)
-{
-	int type = cfg->inputs[input].type;
-	int has_multiple_pins = 0;
-
-	if ((input > 0 && cfg->inputs[input - 1].type == type) ||
-	    (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
-		has_multiple_pins = 1;
-	if (has_multiple_pins && type == AUTO_PIN_MIC)
-		has_multiple_pins &= check_mic_location_need(codec, cfg, input);
-	return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
-				       has_multiple_pins);
-}
-EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
-
-/* return the position of NID in the list, or -1 if not found */
-static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-	int i;
-	for (i = 0; i < nums; i++)
-		if (list[i] == nid)
-			return i;
-	return -1;
-}
-
-/* get a unique suffix or an index number */
-static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
-				    int num_pins, int *indexp)
-{
-	static const char * const channel_sfx[] = {
-		" Front", " Surround", " CLFE", " Side"
-	};
-	int i;
-
-	i = find_idx_in_nid_list(nid, pins, num_pins);
-	if (i < 0)
-		return NULL;
-	if (num_pins == 1)
-		return "";
-	if (num_pins > ARRAY_SIZE(channel_sfx)) {
-		if (indexp)
-			*indexp = i;
-		return "";
-	}
-	return channel_sfx[i];
-}
-
-static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
-			       const struct auto_pin_cfg *cfg,
-			       const char *name, char *label, int maxlen,
-			       int *indexp)
-{
-	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
-	int attr = snd_hda_get_input_pin_attr(def_conf);
-	const char *pfx = "", *sfx = "";
-
-	/* handle as a speaker if it's a fixed line-out */
-	if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)
-		name = "Speaker";
-	/* check the location */
-	switch (attr) {
-	case INPUT_PIN_ATTR_DOCK:
-		pfx = "Dock ";
-		break;
-	case INPUT_PIN_ATTR_FRONT:
-		pfx = "Front ";
-		break;
-	}
-	if (cfg) {
-		/* try to give a unique suffix if needed */
-		sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
-				       indexp);
-		if (!sfx)
-			sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
-					       indexp);
-		if (!sfx) {
-			/* don't add channel suffix for Headphone controls */
-			int idx = find_idx_in_nid_list(nid, cfg->hp_pins,
-						       cfg->hp_outs);
-			if (idx >= 0)
-				*indexp = idx;
-			sfx = "";
-		}
-	}
-	snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
-	return 1;
-}
-
-/**
- * snd_hda_get_pin_label - Get a label for the given I/O pin
- *
- * Get a label for the given pin.  This function works for both input and
- * output pins.  When @cfg is given as non-NULL, the function tries to get
- * an optimized label using hda_get_autocfg_input_label().
- *
- * This function tries to give a unique label string for the pin as much as
- * possible.  For example, when the multiple line-outs are present, it adds
- * the channel suffix like "Front", "Surround", etc (only when @cfg is given).
- * If no unique name with a suffix is available and @indexp is non-NULL, the
- * index number is stored in the pointer.
- */
-int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
-			  const struct auto_pin_cfg *cfg,
-			  char *label, int maxlen, int *indexp)
-{
-	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
-	const char *name = NULL;
-	int i;
-
-	if (indexp)
-		*indexp = 0;
-	if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
-		return 0;
-
-	switch (get_defcfg_device(def_conf)) {
-	case AC_JACK_LINE_OUT:
-		return fill_audio_out_name(codec, nid, cfg, "Line Out",
-					   label, maxlen, indexp);
-	case AC_JACK_SPEAKER:
-		return fill_audio_out_name(codec, nid, cfg, "Speaker",
-					   label, maxlen, indexp);
-	case AC_JACK_HP_OUT:
-		return fill_audio_out_name(codec, nid, cfg, "Headphone",
-					   label, maxlen, indexp);
-	case AC_JACK_SPDIF_OUT:
-	case AC_JACK_DIG_OTHER_OUT:
-		if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
-			name = "HDMI";
-		else
-			name = "SPDIF";
-		if (cfg && indexp) {
-			i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
-						 cfg->dig_outs);
-			if (i >= 0)
-				*indexp = i;
-		}
-		break;
-	default:
-		if (cfg) {
-			for (i = 0; i < cfg->num_inputs; i++) {
-				if (cfg->inputs[i].pin != nid)
-					continue;
-				name = hda_get_autocfg_input_label(codec, cfg, i);
-				if (name)
-					break;
-			}
-		}
-		if (!name)
-			name = hda_get_input_pin_label(codec, nid, true);
-		break;
-	}
-	if (!name)
-		return 0;
-	strlcpy(label, name, maxlen);
-	return 1;
-}
-EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
+EXPORT_SYMBOL_HDA(_snd_hda_set_pin_ctl);
 
 /**
  * snd_hda_add_imux_item - Add an item to input_mux
@@ -5444,8 +4986,6 @@
 	list_for_each_entry(codec, &bus->codec_list, list) {
 		if (hda_codec_is_power_on(codec))
 			hda_call_codec_suspend(codec);
-		if (codec->patch_ops.post_suspend)
-			codec->patch_ops.post_suspend(codec);
 	}
 	return 0;
 }
@@ -5465,10 +5005,7 @@
 	struct hda_codec *codec;
 
 	list_for_each_entry(codec, &bus->codec_list, list) {
-		if (codec->patch_ops.pre_resume)
-			codec->patch_ops.pre_resume(codec);
-		if (snd_hda_codec_needs_resume(codec))
-			hda_call_codec_resume(codec);
+		hda_call_codec_resume(codec);
 	}
 	return 0;
 }
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 56b4f74..54b5281 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -704,8 +704,6 @@
 				unsigned int power_state);
 #ifdef CONFIG_PM
 	int (*suspend)(struct hda_codec *codec, pm_message_t state);
-	int (*post_suspend)(struct hda_codec *codec);
-	int (*pre_resume)(struct hda_codec *codec);
 	int (*resume)(struct hda_codec *codec);
 #endif
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -829,6 +827,7 @@
 
 	struct mutex spdif_mutex;
 	struct mutex control_mutex;
+	struct mutex hash_mutex;
 	struct snd_array spdif_out;
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
 	const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
@@ -861,12 +860,13 @@
 	unsigned int no_jack_detect:1;	/* Machine has no jack-detection */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	unsigned int power_on :1;	/* current (global) power-state */
-	unsigned int power_transition :1; /* power-state in transition */
+	int power_transition;	/* power-state in transition */
 	int power_count;	/* current (global) power refcount */
 	struct delayed_work power_work; /* delayed task for powerdown */
 	unsigned long power_on_acct;
 	unsigned long power_off_acct;
 	unsigned long power_jiffies;
+	spinlock_t power_lock;
 #endif
 
 	/* codec-specific additional proc output */
@@ -911,10 +911,13 @@
 			  hda_nid_t *start_id);
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 			    hda_nid_t *conn_list, int max_conns);
+static inline int
+snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
+{
+	return snd_hda_get_connections(codec, nid, NULL, 0);
+}
 int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
 			    hda_nid_t *conn_list, int max_conns);
-int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
-			  const hda_nid_t **listp);
 int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
 			  const hda_nid_t *list);
 int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
@@ -1051,12 +1054,10 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 void snd_hda_power_up(struct hda_codec *codec);
 void snd_hda_power_down(struct hda_codec *codec);
-#define snd_hda_codec_needs_resume(codec) codec->power_count
 void snd_hda_update_power_acct(struct hda_codec *codec);
 #else
 static inline void snd_hda_power_up(struct hda_codec *codec) {}
 static inline void snd_hda_power_down(struct hda_codec *codec) {}
-#define snd_hda_codec_needs_resume(codec) 1
 #endif
 
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1f35052..4ab8102 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -497,6 +497,7 @@
 	AZX_DRIVER_NVIDIA,
 	AZX_DRIVER_TERA,
 	AZX_DRIVER_CTX,
+	AZX_DRIVER_CTHDA,
 	AZX_DRIVER_GENERIC,
 	AZX_NUM_DRIVERS, /* keep this as last entry */
 };
@@ -518,6 +519,7 @@
 #define AZX_DCAPS_OLD_SSYNC	(1 << 20)	/* Old SSYNC reg for ICH */
 #define AZX_DCAPS_BUFSIZE	(1 << 21)	/* no buffer size alignment */
 #define AZX_DCAPS_ALIGN_BUFSIZE	(1 << 22)	/* buffer size alignment */
+#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)	/* BDLE in 4k boundary */
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -533,6 +535,9 @@
 	(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
 	 AZX_DCAPS_ALIGN_BUFSIZE)
 
+#define AZX_DCAPS_PRESET_CTHDA \
+	(AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY)
+
 static char *driver_short_names[] __devinitdata = {
 	[AZX_DRIVER_ICH] = "HDA Intel",
 	[AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -546,6 +551,7 @@
 	[AZX_DRIVER_NVIDIA] = "HDA NVidia",
 	[AZX_DRIVER_TERA] = "HDA Teradici", 
 	[AZX_DRIVER_CTX] = "HDA Creative", 
+	[AZX_DRIVER_CTHDA] = "HDA Creative",
 	[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
@@ -1285,7 +1291,8 @@
 /*
  * set up a BDL entry
  */
-static int setup_bdle(struct snd_pcm_substream *substream,
+static int setup_bdle(struct azx *chip,
+		      struct snd_pcm_substream *substream,
 		      struct azx_dev *azx_dev, u32 **bdlp,
 		      int ofs, int size, int with_ioc)
 {
@@ -1304,6 +1311,12 @@
 		bdl[1] = cpu_to_le32(upper_32_bits(addr));
 		/* program the size field of the BDL entry */
 		chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
+		/* one BDLE cannot cross 4K boundary on CTHDA chips */
+		if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
+			u32 remain = 0x1000 - (ofs & 0xfff);
+			if (chunk > remain)
+				chunk = remain;
+		}
 		bdl[2] = cpu_to_le32(chunk);
 		/* program the IOC to enable interrupt
 		 * only when the whole fragment is processed
@@ -1356,7 +1369,7 @@
 				   bdl_pos_adj[chip->dev_index]);
 			pos_adj = 0;
 		} else {
-			ofs = setup_bdle(substream, azx_dev,
+			ofs = setup_bdle(chip, substream, azx_dev,
 					 &bdl, ofs, pos_adj,
 					 !substream->runtime->no_period_wakeup);
 			if (ofs < 0)
@@ -1366,10 +1379,10 @@
 		pos_adj = 0;
 	for (i = 0; i < periods; i++) {
 		if (i == periods - 1 && pos_adj)
-			ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+			ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
 					 period_bytes - pos_adj, 0);
 		else
-			ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+			ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
 					 period_bytes,
 					 !substream->runtime->no_period_wakeup);
 		if (ofs < 0)
@@ -2353,17 +2366,6 @@
  * power management
  */
 
-static int snd_hda_codecs_inuse(struct hda_bus *bus)
-{
-	struct hda_codec *codec;
-
-	list_for_each_entry(codec, &bus->codec_list, list) {
-		if (snd_hda_codec_needs_resume(codec))
-			return 1;
-	}
-	return 0;
-}
-
 static int azx_suspend(struct pci_dev *pci, pm_message_t state)
 {
 	struct snd_card *card = pci_get_drvdata(pci);
@@ -2410,8 +2412,7 @@
 		return -EIO;
 	azx_init_pci(chip);
 
-	if (snd_hda_codecs_inuse(chip->bus))
-		azx_init_chip(chip, 1);
+	azx_init_chip(chip, 1);
 
 	snd_hda_resume(chip->bus);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -2565,6 +2566,8 @@
 	/* forced codec slots */
 	SND_PCI_QUIRK(0x1043, 0x1262, "ASUS W5Fm", 0x103),
 	SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103),
+	/* WinFast VP200 H (Teradici) user reported broken communication */
+	SND_PCI_QUIRK(0x3a21, 0x040d, "WinFast VP200 H", 0x101),
 	{}
 };
 
@@ -3130,6 +3133,11 @@
 	  .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
 	  AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
 #endif
+	/* CTHDA chips */
+	{ PCI_DEVICE(0x1102, 0x0010),
+	  .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
+	{ PCI_DEVICE(0x1102, 0x0012),
+	  .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
 	/* Vortex86MX */
 	{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
 	/* VMware HDAudio */
@@ -3148,7 +3156,7 @@
 MODULE_DEVICE_TABLE(pci, azx_ids);
 
 /* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver azx_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = azx_ids,
 	.probe = azx_probe,
@@ -3159,15 +3167,4 @@
 #endif
 };
 
-static int __init alsa_card_azx_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_azx_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_azx_init)
-module_exit(alsa_card_azx_exit)
+module_pci_driver(azx_driver);
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index d689484..2dd1c11 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -17,6 +17,7 @@
 #include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_jack.h"
 
 bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index c66655c..8ae5246 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -12,6 +12,8 @@
 #ifndef __SOUND_HDA_JACK_H
 #define __SOUND_HDA_JACK_H
 
+struct auto_pin_cfg;
+
 struct hda_jack_tbl {
 	hda_nid_t nid;
 	unsigned char action;		/* event action (0 = none) */
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 0ec9248..9a096a8 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -262,6 +262,8 @@
 			  const struct hda_input_mux *imux,
 			  struct snd_ctl_elem_value *ucontrol, hda_nid_t nid,
 			  unsigned int *cur_val);
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+			  int index, int *type_index_ret);
 
 /*
  * Channel mode helper
@@ -393,72 +395,7 @@
 	struct hda_bus *bus;
 };
 
-/*
- * Helper for automatic pin configuration
- */
-
-enum {
-	AUTO_PIN_MIC,
-	AUTO_PIN_LINE_IN,
-	AUTO_PIN_CD,
-	AUTO_PIN_AUX,
-	AUTO_PIN_LAST
-};
-
-enum {
-	AUTO_PIN_LINE_OUT,
-	AUTO_PIN_SPEAKER_OUT,
-	AUTO_PIN_HP_OUT
-};
-
-#define AUTO_CFG_MAX_OUTS	HDA_MAX_OUTS
-#define AUTO_CFG_MAX_INS	8
-
-struct auto_pin_cfg_item {
-	hda_nid_t pin;
-	int type;
-};
-
-struct auto_pin_cfg;
-const char *hda_get_autocfg_input_label(struct hda_codec *codec,
-					const struct auto_pin_cfg *cfg,
-					int input);
-int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
-			  const struct auto_pin_cfg *cfg,
-			  char *label, int maxlen, int *indexp);
-int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
-			  int index, int *type_index_ret);
-
-enum {
-	INPUT_PIN_ATTR_UNUSED,	/* pin not connected */
-	INPUT_PIN_ATTR_INT,	/* internal mic/line-in */
-	INPUT_PIN_ATTR_DOCK,	/* docking mic/line-in */
-	INPUT_PIN_ATTR_NORMAL,	/* mic/line-in jack */
-	INPUT_PIN_ATTR_FRONT,	/* mic/line-in jack in front */
-	INPUT_PIN_ATTR_REAR,	/* mic/line-in jack in rear */
-};
-
-int snd_hda_get_input_pin_attr(unsigned int def_conf);
-
-struct auto_pin_cfg {
-	int line_outs;
-	/* sorted in the order of Front/Surr/CLFE/Side */
-	hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
-	int speaker_outs;
-	hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
-	int hp_outs;
-	int line_out_type;	/* AUTO_PIN_XXX_OUT */
-	hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
-	int num_inputs;
-	struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
-	int dig_outs;
-	hda_nid_t dig_out_pins[2];
-	hda_nid_t dig_in_pin;
-	hda_nid_t mono_out_pin;
-	int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */
-	int dig_in_type; /* HDA_PCM_TYPE_XXX */
-};
-
+/* helper macros to retrieve pin default-config values */
 #define get_defcfg_connect(cfg) \
 	((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
 #define get_defcfg_association(cfg) \
@@ -472,19 +409,6 @@
 #define get_defcfg_misc(cfg) \
 	((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT)
 
-/* bit-flags for snd_hda_parse_pin_def_config() behavior */
-#define HDA_PINCFG_NO_HP_FIXUP	(1 << 0) /* no HP-split */
-#define HDA_PINCFG_NO_LO_FIXUP	(1 << 1) /* don't take other outs as LO */
-
-int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
-			     struct auto_pin_cfg *cfg,
-			     const hda_nid_t *ignore_nids,
-			     unsigned int cond_flags);
-
-/* older function */
-#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
-	snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
-
 /* amp values */
 #define AMP_IN_MUTE(idx)	(0x7080 | ((idx)<<8))
 #define AMP_IN_UNMUTE(idx)	(0x7000 | ((idx)<<8))
@@ -502,6 +426,46 @@
 #define PIN_HP			(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
 #define PIN_HP_AMP		(AC_PINCTL_HP_EN)
 
+unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin);
+int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
+			 unsigned int val, bool cached);
+
+/**
+ * _snd_hda_set_pin_ctl - Set a pin-control value safely
+ * @codec: the codec instance
+ * @pin: the pin NID to set the control
+ * @val: the pin-control value (AC_PINCTL_* bits)
+ *
+ * This function sets the pin-control value to the given pin, but
+ * filters out the invalid pin-control bits when the pin has no such
+ * capabilities.  For example, when PIN_HP is passed but the pin has no
+ * HP-drive capability, the HP bit is omitted.
+ *
+ * The function doesn't check the input VREF capability bits, though.
+ * Use snd_hda_get_default_vref() to guess the right value.
+ * Also, this function is only for analog pins, not for HDMI pins.
+ */
+static inline int
+snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val)
+{
+	return _snd_hda_set_pin_ctl(codec, pin, val, false);
+}
+
+/**
+ * snd_hda_set_pin_ctl_cache - Set a pin-control value safely
+ * @codec: the codec instance
+ * @pin: the pin NID to set the control
+ * @val: the pin-control value (AC_PINCTL_* bits)
+ *
+ * Just like snd_hda_set_pin_ctl() but write to cache as well.
+ */
+static inline int
+snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin,
+			  unsigned int val)
+{
+	return _snd_hda_set_pin_ctl(codec, pin, val, true);
+}
+
 /*
  * get widget capabilities
  */
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 7143393..d8b2d6d 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -28,6 +28,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
 
@@ -1742,9 +1743,7 @@
 	if (! ad198x_eapd_put(kcontrol, ucontrol))
 		return 0;
 	/* change speaker pin appropriately */
-	snd_hda_codec_write(codec, 0x05, 0,
-			    AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    spec->cur_eapd ? PIN_OUT : 0);
+	snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0);
 	/* toggle HP mute appropriately */
 	snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
 				 HDA_AMP_MUTE,
@@ -3103,7 +3102,7 @@
 					      int dac_idx)
 {
 	/* set as output */
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+	snd_hda_set_pin_ctl(codec, nid, pin_type);
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
 	switch (nid) {
 	case 0x11: /* port-A - DAC 03 */
@@ -3157,6 +3156,7 @@
 	for (i = 0; i < cfg->num_inputs; i++) {
 		hda_nid_t nid = cfg->inputs[i].pin;
 		int type = cfg->inputs[i].type;
+		int val;
 		switch (nid) {
 		case 0x15: /* port-C */
 			snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
@@ -3165,8 +3165,10 @@
 			snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
 			break;
 		}
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
+		val = PIN_IN;
+		if (type == AUTO_PIN_MIC)
+			val |= snd_hda_get_default_vref(codec, nid);
+		snd_hda_set_pin_ctl(codec, nid, val);
 		if (nid != AD1988_PIN_CD_NID)
 			snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 					    AMP_OUT_MUTE);
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index 09ccfab..19ae14f 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -26,6 +26,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 
 /*
  */
@@ -341,8 +342,7 @@
 static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 {
 	if (pin) {
-		snd_hda_codec_write(codec, pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+		snd_hda_set_pin_ctl(codec, pin, PIN_HP);
 		if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
 			snd_hda_codec_write(codec, pin, 0,
 					    AC_VERB_SET_AMP_GAIN_MUTE,
@@ -356,8 +356,8 @@
 static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
 {
 	if (pin) {
-		snd_hda_codec_write(codec, pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80);
+		snd_hda_set_pin_ctl(codec, pin, PIN_IN |
+				    snd_hda_get_default_vref(codec, pin));
 		if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
 			snd_hda_codec_write(codec, pin, 0,
 					    AC_VERB_SET_AMP_GAIN_MUTE,
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 21d91d5..d0d3540 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -30,6 +30,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 
 #define WIDGET_CHIP_CTRL      0x15
 #define WIDGET_DSP_CTRL       0x16
@@ -239,8 +240,7 @@
 static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 {
 	if (pin) {
-		snd_hda_codec_write(codec, pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+		snd_hda_set_pin_ctl(codec, pin, PIN_HP);
 		if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
 			snd_hda_codec_write(codec, pin, 0,
 					    AC_VERB_SET_AMP_GAIN_MUTE,
@@ -254,9 +254,8 @@
 static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
 {
 	if (pin) {
-		snd_hda_codec_write(codec, pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    PIN_VREF80);
+		snd_hda_set_pin_ctl(codec, pin, PIN_IN |
+				    snd_hda_get_default_vref(codec, pin));
 		if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
 			snd_hda_codec_write(codec, pin, 0,
 					    AC_VERB_SET_AMP_GAIN_MUTE,
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index c83ccdb..9647ed4 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -26,6 +26,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include <sound/tlv.h>
 
@@ -933,8 +934,7 @@
 			pin_ctl = 0;
 
 		nid = cfg->speaker_pins[i];
-		snd_hda_codec_write(codec, nid, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl);
+		snd_hda_set_pin_ctl(codec, nid, pin_ctl);
 	}
 	if (spec->gpio_eapd_hp) {
 		unsigned int gpio = hp_present ?
@@ -948,16 +948,14 @@
 		/* mute HPs if spdif jack (SENSE_B) is present */
 		for (i = 0; i < cfg->hp_outs; i++) {
 			nid = cfg->hp_pins[i];
-			snd_hda_codec_write(codec, nid, 0,
-				AC_VERB_SET_PIN_WIDGET_CONTROL,
+			snd_hda_set_pin_ctl(codec, nid,
 				(spdif_present && spec->sense_b) ? 0 : PIN_HP);
 		}
 
 		/* SPDIF TX on/off */
 		if (cfg->dig_outs) {
 			nid = cfg->dig_out_pins[0];
-			snd_hda_codec_write(codec, nid, 0,
-				AC_VERB_SET_PIN_WIDGET_CONTROL,
+			snd_hda_set_pin_ctl(codec, nid,
 				spdif_present ? PIN_OUT : 0);
 
 		}
@@ -1024,13 +1022,11 @@
 
 	/* set appropriate pin controls */
 	for (i = 0; i < cfg->line_outs; i++)
-		snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+		snd_hda_set_pin_ctl(codec, cfg->line_out_pins[i], PIN_OUT);
 	/* HP */
 	for (i = 0; i < cfg->hp_outs; i++) {
 		hda_nid_t nid = cfg->hp_pins[i];
-		snd_hda_codec_write(codec, nid, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+		snd_hda_set_pin_ctl(codec, nid, PIN_HP);
 		if (!cfg->speaker_outs)
 			continue;
 		if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
@@ -1041,8 +1037,7 @@
 
 	/* Speaker */
 	for (i = 0; i < cfg->speaker_outs; i++)
-		snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+		snd_hda_set_pin_ctl(codec, cfg->speaker_pins[i], PIN_OUT);
 
 	/* SPDIF is enabled on presence detect for CS421x */
 	if (spec->hp_detect || spec->spdif_detect)
@@ -1063,14 +1058,9 @@
 			continue;
 		/* set appropriate pin control and mute first */
 		ctl = PIN_IN;
-		if (cfg->inputs[i].type == AUTO_PIN_MIC) {
-			unsigned int caps = snd_hda_query_pin_caps(codec, pin);
-			caps >>= AC_PINCAP_VREF_SHIFT;
-			if (caps & AC_PINCAP_VREF_80)
-				ctl = PIN_VREF80;
-		}
-		snd_hda_codec_write(codec, pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
+		if (cfg->inputs[i].type == AUTO_PIN_MIC)
+			ctl |= snd_hda_get_default_vref(codec, pin);
+		snd_hda_set_pin_ctl(codec, pin, ctl);
 		snd_hda_codec_write(codec, spec->adc_nid[i], 0,
 				    AC_VERB_SET_AMP_GAIN_MUTE,
 				    AMP_IN_MUTE(spec->adc_idx[i]));
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index b6767b4..c8fdaae 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -29,6 +29,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #define NUM_PINS	11
 
 
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index d906c5b..3acb582 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -30,6 +30,7 @@
 
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
 
@@ -66,6 +67,7 @@
 };
 
 struct conexant_spec {
+	struct hda_gen_spec gen;
 
 	const struct snd_kcontrol_new *mixers[5];
 	int num_mixers;
@@ -141,6 +143,7 @@
 	unsigned int hp_laptop:1;
 	unsigned int asus:1;
 	unsigned int pin_eapd_ctrls:1;
+	unsigned int fixup_stereo_dmic:1;
 
 	unsigned int adc_switching:1;
 
@@ -1601,17 +1604,13 @@
 	unsigned int pinctl;
 	/* headphone pin */
 	pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0;
-	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pinctl);
+	snd_hda_set_pin_ctl(codec, 0x16, pinctl);
 	/* speaker pin */
 	pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
-	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pinctl);
+	snd_hda_set_pin_ctl(codec, 0x1a, pinctl);
 	/* on ideapad there is an additional speaker (subwoofer) to mute */
 	if (spec->ideapad)
-		snd_hda_codec_write(codec, 0x1b, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    pinctl);
+		snd_hda_set_pin_ctl(codec, 0x1b, pinctl);
 }
 
 /* turn on/off EAPD (+ mute HP) as a master switch */
@@ -1996,8 +1995,7 @@
 
 	/* Port A (HP) */
 	pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0;
-	snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			pinctl);
+	snd_hda_set_pin_ctl(codec, 0x19, pinctl);
 
 	/* Port D (HP/LO) */
 	pinctl = spec->cur_eapd ? spec->port_d_mode : 0;
@@ -2010,13 +2008,11 @@
 		if (!hp_port_d_present(spec))
 			pinctl = 0;
 	}
-	snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			pinctl);
+	snd_hda_set_pin_ctl(codec, 0x1c, pinctl);
 
 	/* CLASS_D AMP */
 	pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
-	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			pinctl);
+	snd_hda_set_pin_ctl(codec, 0x1f, pinctl);
 }
 
 /* turn on/off EAPD (+ mute HP) as a master switch */
@@ -2047,8 +2043,7 @@
 	/* Even though port F is the DC input, the bias is controlled on port B.
 	 * we also leave that port as an active input (but unselected) in DC mode
 	 * just in case that is necessary to make the bias setting take effect. */
-	return snd_hda_codec_write_cache(codec, 0x1a, 0,
-		AC_VERB_SET_PIN_WIDGET_CONTROL,
+	return snd_hda_set_pin_ctl_cache(codec, 0x1a,
 		cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
 }
 
@@ -2081,14 +2076,14 @@
 	}
 
 	/* disable DC (port F) */
-	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+	snd_hda_set_pin_ctl(codec, 0x1e, 0);
 
 	/* external mic, port B */
-	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+	snd_hda_set_pin_ctl(codec, 0x1a,
 		spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
 
 	/* internal mic, port C */
-	snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+	snd_hda_set_pin_ctl(codec, 0x1b,
 		spec->ext_mic_present ? 0 : PIN_VREF80);
 }
 
@@ -3357,9 +3352,7 @@
 	struct conexant_spec *spec = codec->spec;
 	int i;
 	for (i = 0; i < num_pins; i++)
-		snd_hda_codec_write(codec, pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    on ? PIN_OUT : 0);
+		snd_hda_set_pin_ctl(codec, pins[i], on ? PIN_OUT : 0);
 	if (spec->pin_eapd_ctrls)
 		cx_auto_turn_eapd(codec, num_pins, pins, on);
 }
@@ -3976,8 +3969,7 @@
 		if (snd_hda_query_pin_caps(codec, cfg->hp_pins[i]) &
 		    AC_PINCAP_HP_DRV)
 			val |= AC_PINCTL_HP_EN;
-		snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+		snd_hda_set_pin_ctl(codec, cfg->hp_pins[i], val);
 	}
 	mute_outputs(codec, cfg->hp_outs, cfg->hp_pins);
 	mute_outputs(codec, cfg->line_outs, cfg->line_out_pins);
@@ -4030,13 +4022,11 @@
 	}
 
 	for (i = 0; i < cfg->num_inputs; i++) {
-		unsigned int type;
+		hda_nid_t pin = cfg->inputs[i].pin;
+		unsigned int type = PIN_IN;
 		if (cfg->inputs[i].type == AUTO_PIN_MIC)
-			type = PIN_VREF80;
-		else
-			type = PIN_IN;
-		snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, type);
+			type |= snd_hda_get_default_vref(codec, pin);
+		snd_hda_set_pin_ctl(codec, pin, type);
 	}
 
 	if (spec->auto_mic) {
@@ -4063,11 +4053,9 @@
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 
 	if (spec->multiout.dig_out_nid)
-		snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+		snd_hda_set_pin_ctl(codec, cfg->dig_out_pins[0], PIN_OUT);
 	if (spec->dig_in_nid)
-		snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+		snd_hda_set_pin_ctl(codec, cfg->dig_in_pin, PIN_IN);
 }
 
 static int cx_auto_init(struct hda_codec *codec)
@@ -4084,9 +4072,9 @@
 
 static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
 			      const char *dir, int cidx,
-			      hda_nid_t nid, int hda_dir, int amp_idx)
+			      hda_nid_t nid, int hda_dir, int amp_idx, int chs)
 {
-	static char name[32];
+	static char name[44];
 	static struct snd_kcontrol_new knew[] = {
 		HDA_CODEC_VOLUME(name, 0, 0, 0),
 		HDA_CODEC_MUTE(name, 0, 0, 0),
@@ -4096,7 +4084,7 @@
 
 	for (i = 0; i < 2; i++) {
 		struct snd_kcontrol *kctl;
-		knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
+		knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx,
 							    hda_dir);
 		knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
 		knew[i].index = cidx;
@@ -4115,7 +4103,7 @@
 }
 
 #define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir)		\
-	cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
+	cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3)
 
 #define cx_auto_add_pb_volume(codec, nid, str, idx)			\
 	cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
@@ -4185,6 +4173,36 @@
 	return 0;
 }
 
+/* Returns zero if this is a normal stereo channel, and non-zero if it should
+   be split in two independent channels.
+   dest_label must be at least 44 characters. */
+static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label,
+				     char *dest_label, int nid)
+{
+	struct conexant_spec *spec = codec->spec;
+	int i;
+
+	if (!spec->fixup_stereo_dmic)
+		return 0;
+
+	for (i = 0; i < AUTO_CFG_MAX_INS; i++) {
+		int def_conf;
+		if (spec->autocfg.inputs[i].pin != nid)
+			continue;
+
+		if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC)
+			return 0;
+		def_conf = snd_hda_codec_get_pincfg(codec, nid);
+		if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT)
+			return 0;
+
+		/* Finally found the inverted internal mic! */
+		snprintf(dest_label, 44, "Inverted %s", label);
+		return 1;
+	}
+	return 0;
+}
+
 static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
 				      const char *label, const char *pfx,
 				      int cidx)
@@ -4193,14 +4211,25 @@
 	int i;
 
 	for (i = 0; i < spec->num_adc_nids; i++) {
+		char rightch_label[44];
 		hda_nid_t adc_nid = spec->adc_nids[i];
 		int idx = get_input_connection(codec, adc_nid, nid);
 		if (idx < 0)
 			continue;
 		if (codec->single_adc_amp)
 			idx = 0;
+
+		if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
+			/* Make two independent kcontrols for left and right */
+			int err = cx_auto_add_volume_idx(codec, label, pfx,
+					      cidx, adc_nid, HDA_INPUT, idx, 1);
+			if (err < 0)
+				return err;
+			return cx_auto_add_volume_idx(codec, rightch_label, pfx,
+						      cidx, adc_nid, HDA_INPUT, idx, 2);
+		}
 		return cx_auto_add_volume_idx(codec, label, pfx,
-					      cidx, adc_nid, HDA_INPUT, idx);
+					      cidx, adc_nid, HDA_INPUT, idx, 3);
 	}
 	return 0;
 }
@@ -4213,9 +4242,19 @@
 	int i, con;
 
 	nid = spec->imux_info[idx].pin;
-	if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+	if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
+		char rightch_label[44];
+		if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
+			int err = cx_auto_add_volume_idx(codec, label, " Boost",
+							 cidx, nid, HDA_INPUT, 0, 1);
+			if (err < 0)
+				return err;
+			return cx_auto_add_volume_idx(codec, rightch_label, " Boost",
+						      cidx, nid, HDA_INPUT, 0, 2);
+		}
 		return cx_auto_add_volume(codec, label, " Boost", cidx,
 					  nid, HDA_INPUT);
+	}
 	con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
 					&mux, false, 0);
 	if (con < 0)
@@ -4370,37 +4409,21 @@
 /*
  * pin fix-up
  */
-struct cxt_pincfg {
-	hda_nid_t nid;
-	u32 val;
-};
-
-static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg)
-{
-	for (; cfg->nid; cfg++)
-		snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
-
-}
-
-static void apply_pin_fixup(struct hda_codec *codec,
-			    const struct snd_pci_quirk *quirk,
-			    const struct cxt_pincfg **table)
-{
-	quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
-	if (quirk) {
-		snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n",
-			    quirk->name);
-		apply_pincfg(codec, table[quirk->value]);
-	}
-}
-
 enum {
 	CXT_PINCFG_LENOVO_X200,
 	CXT_PINCFG_LENOVO_TP410,
+	CXT_FIXUP_STEREO_DMIC,
 };
 
+static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
+				  const struct hda_fixup *fix, int action)
+{
+	struct conexant_spec *spec = codec->spec;
+	spec->fixup_stereo_dmic = 1;
+}
+
 /* ThinkPad X200 & co with cxt5051 */
-static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
+static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
 	{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
 	{ 0x17, 0x21a11000 }, /* dock-mic */
 	{ 0x19, 0x2121103f }, /* dock-HP */
@@ -4409,16 +4432,26 @@
 };
 
 /* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
-static const struct cxt_pincfg cxt_pincfg_lenovo_tp410[] = {
+static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = {
 	{ 0x19, 0x042110ff }, /* HP (seq# overridden) */
 	{ 0x1a, 0x21a190f0 }, /* dock-mic */
 	{ 0x1c, 0x212140ff }, /* dock-HP */
 	{}
 };
 
-static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
-	[CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
-	[CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410,
+static const struct hda_fixup cxt_fixups[] = {
+	[CXT_PINCFG_LENOVO_X200] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = cxt_pincfg_lenovo_x200,
+	},
+	[CXT_PINCFG_LENOVO_TP410] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = cxt_pincfg_lenovo_tp410,
+	},
+	[CXT_FIXUP_STEREO_DMIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = cxt_fixup_stereo_dmic,
+	},
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -4432,6 +4465,7 @@
 	SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
+	SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
 	{}
 };
 
@@ -4471,13 +4505,16 @@
 	case 0x14f15051:
 		add_cx5051_fake_mutes(codec);
 		codec->pin_amp_workaround = 1;
-		apply_pin_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
+		snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups);
 		break;
 	default:
 		codec->pin_amp_workaround = 1;
-		apply_pin_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
+		snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups);
+		break;
 	}
 
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
 	/* Show mute-led control only on HP laptops
 	 * This is a sort of white-list: on HP laptops, EAPD corresponds
 	 * only to the mute-LED without actualy amp function.  Meanwhile,
@@ -4556,6 +4593,12 @@
 	  .patch = patch_conexant_auto },
 	{ .id = 0x14f150b9, .name = "CX20665",
 	  .patch = patch_conexant_auto },
+	{ .id = 0x14f1510f, .name = "CX20751/2",
+	  .patch = patch_conexant_auto },
+	{ .id = 0x14f15110, .name = "CX20751/2",
+	  .patch = patch_conexant_auto },
+	{ .id = 0x14f15111, .name = "CX20753/4",
+	  .patch = patch_conexant_auto },
 	{} /* terminator */
 };
 
@@ -4576,6 +4619,9 @@
 MODULE_ALIAS("snd-hda-codec-id:14f150ac");
 MODULE_ALIAS("snd-hda-codec-id:14f150b8");
 MODULE_ALIAS("snd-hda-codec-id:14f150b9");
+MODULE_ALIAS("snd-hda-codec-id:14f1510f");
+MODULE_ALIAS("snd-hda-codec-id:14f15110");
+MODULE_ALIAS("snd-hda-codec-id:14f15111");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 83f345f..ad319d4d 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1592,10 +1592,10 @@
 	unsigned int dataDCC2, channel_id;
 	int i;
 	struct hdmi_spec *spec = codec->spec;
-	struct hda_spdif_out *spdif =
-		snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
+	struct hda_spdif_out *spdif;
 
 	mutex_lock(&codec->spdif_mutex);
+	spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
 
 	chs = substream->runtime->channels;
 
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7810913..ff71dce 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6,7 +6,7 @@
  * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
  *                    PeiSen Hou <pshou@realtek.com.tw>
  *                    Takashi Iwai <tiwai@suse.de>
- *                    Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ *                    Jonathan Woithe <jwoithe@just42.net>
  *
  *  This driver is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -32,6 +32,7 @@
 #include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
 
@@ -66,8 +67,6 @@
 	unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
 };
 
-struct alc_fixup;
-
 struct alc_multi_io {
 	hda_nid_t pin;		/* multi-io widget pin NID */
 	hda_nid_t dac;		/* DAC to be connected */
@@ -82,19 +81,33 @@
 
 #define MAX_VOL_NIDS	0x40
 
+/* make compatible with old code */
+#define alc_apply_pincfgs	snd_hda_apply_pincfgs
+#define alc_apply_fixup		snd_hda_apply_fixup
+#define alc_pick_fixup		snd_hda_pick_fixup
+#define alc_fixup		hda_fixup
+#define alc_pincfg		hda_pintbl
+#define alc_model_fixup		hda_model_fixup
+
+#define ALC_FIXUP_PINS	HDA_FIXUP_PINS
+#define ALC_FIXUP_VERBS	HDA_FIXUP_VERBS
+#define ALC_FIXUP_FUNC	HDA_FIXUP_FUNC
+
+#define ALC_FIXUP_ACT_PRE_PROBE	HDA_FIXUP_ACT_PRE_PROBE
+#define ALC_FIXUP_ACT_PROBE	HDA_FIXUP_ACT_PROBE
+#define ALC_FIXUP_ACT_INIT	HDA_FIXUP_ACT_INIT
+#define ALC_FIXUP_ACT_BUILD	HDA_FIXUP_ACT_BUILD
+
+
 struct alc_spec {
+	struct hda_gen_spec gen;
+
 	/* codec parameterization */
 	const struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
 	unsigned int num_mixers;
 	const struct snd_kcontrol_new *cap_mixer;	/* capture mixer */
 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
 
-	const struct hda_verb *init_verbs[10];	/* initialization verbs
-						 * don't forget NULL
-						 * termination!
-						 */
-	unsigned int num_init_verbs;
-
 	char stream_name_analog[32];	/* analog PCM stream */
 	const struct hda_pcm_stream *stream_analog_playback;
 	const struct hda_pcm_stream *stream_analog_capture;
@@ -210,11 +223,6 @@
 	unsigned int pll_coef_idx, pll_coef_bit;
 	unsigned int coef0;
 
-	/* fix-up list */
-	int fixup_id;
-	const struct alc_fixup *fixup_list;
-	const char *fixup_name;
-
 	/* multi-io */
 	int multi_ios;
 	struct alc_multi_io multi_io[4];
@@ -319,13 +327,16 @@
 
 	/* for shared I/O, change the pin-control accordingly */
 	if (spec->shared_mic_hp) {
+		unsigned int val;
+		hda_nid_t pin = spec->autocfg.inputs[1].pin;
 		/* NOTE: this assumes that there are only two inputs, the
 		 * first is the real internal mic and the second is HP jack.
 		 */
-		snd_hda_codec_write(codec, spec->autocfg.inputs[1].pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    spec->cur_mux[adc_idx] ?
-				    PIN_VREF80 : PIN_HP);
+		if (spec->cur_mux[adc_idx])
+			val = snd_hda_get_default_vref(codec, pin) | PIN_IN;
+		else
+			val = PIN_HP;
+		snd_hda_set_pin_ctl(codec, pin, val);
 		spec->automute_speaker = !spec->cur_mux[adc_idx];
 		call_update_outputs(codec);
 	}
@@ -338,7 +349,7 @@
 	nid = get_capsrc(spec, adc_idx);
 
 	/* no selection? */
-	num_conns = snd_hda_get_conn_list(codec, nid, NULL);
+	num_conns = snd_hda_get_num_conns(codec, nid);
 	if (num_conns <= 1)
 		return 1;
 
@@ -376,25 +387,9 @@
 			      int auto_pin_type)
 {
 	unsigned int val = PIN_IN;
-
-	if (auto_pin_type == AUTO_PIN_MIC) {
-		unsigned int pincap;
-		unsigned int oldval;
-		oldval = snd_hda_codec_read(codec, nid, 0,
-					    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-		pincap = snd_hda_query_pin_caps(codec, nid);
-		pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
-		/* if the default pin setup is vref50, we give it priority */
-		if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
-			val = PIN_VREF80;
-		else if (pincap & AC_PINCAP_VREF_50)
-			val = PIN_VREF50;
-		else if (pincap & AC_PINCAP_VREF_100)
-			val = PIN_VREF100;
-		else if (pincap & AC_PINCAP_VREF_GRD)
-			val = PIN_VREFGRD;
-	}
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+	if (auto_pin_type == AUTO_PIN_MIC)
+		val |= snd_hda_get_default_vref(codec, nid);
+	snd_hda_set_pin_ctl(codec, nid, val);
 }
 
 /*
@@ -409,13 +404,6 @@
 	spec->mixers[spec->num_mixers++] = mix;
 }
 
-static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
-{
-	if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
-		return;
-	spec->init_verbs[spec->num_init_verbs++] = verb;
-}
-
 /*
  * GPIO setup tables, used in initialization
  */
@@ -517,9 +505,7 @@
 			} else
 				val = 0;
 			val |= pin_bits;
-			snd_hda_codec_write(codec, nid, 0,
-					    AC_VERB_SET_PIN_WIDGET_CONTROL,
-					    val);
+			snd_hda_set_pin_ctl(codec, nid, val);
 			break;
 		case ALC_AUTOMUTE_AMP:
 			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
@@ -1200,6 +1186,16 @@
  */
 #define ALC_FIXUP_SKU_IGNORE (2)
 
+static void alc_fixup_sku_ignore(struct hda_codec *codec,
+				 const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->cdefine.fixup = 1;
+		spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
+	}
+}
+
 static int alc_auto_parse_customize_define(struct hda_codec *codec)
 {
 	unsigned int ass, tmp, i;
@@ -1403,178 +1399,6 @@
 }
 
 /*
- * Fix-up pin default configurations and add default verbs
- */
-
-struct alc_pincfg {
-	hda_nid_t nid;
-	u32 val;
-};
-
-struct alc_model_fixup {
-	const int id;
-	const char *name;
-};
-
-struct alc_fixup {
-	int type;
-	bool chained;
-	int chain_id;
-	union {
-		unsigned int sku;
-		const struct alc_pincfg *pins;
-		const struct hda_verb *verbs;
-		void (*func)(struct hda_codec *codec,
-			     const struct alc_fixup *fix,
-			     int action);
-	} v;
-};
-
-enum {
-	ALC_FIXUP_INVALID,
-	ALC_FIXUP_SKU,
-	ALC_FIXUP_PINS,
-	ALC_FIXUP_VERBS,
-	ALC_FIXUP_FUNC,
-};
-
-enum {
-	ALC_FIXUP_ACT_PRE_PROBE,
-	ALC_FIXUP_ACT_PROBE,
-	ALC_FIXUP_ACT_INIT,
-	ALC_FIXUP_ACT_BUILD,
-};
-
-static void alc_apply_pincfgs(struct hda_codec *codec,
-			      const struct alc_pincfg *cfg)
-{
-	for (; cfg->nid; cfg++)
-		snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
-}
-
-static void alc_apply_fixup(struct hda_codec *codec, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	int id = spec->fixup_id;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-	const char *modelname = spec->fixup_name;
-#endif
-	int depth = 0;
-
-	if (!spec->fixup_list)
-		return;
-
-	while (id >= 0) {
-		const struct alc_fixup *fix = spec->fixup_list + id;
-		const struct alc_pincfg *cfg;
-
-		switch (fix->type) {
-		case ALC_FIXUP_SKU:
-			if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
-				break;
-			snd_printdd(KERN_INFO "hda_codec: %s: "
-				    "Apply sku override for %s\n",
-				    codec->chip_name, modelname);
-			spec->cdefine.sku_cfg = fix->v.sku;
-			spec->cdefine.fixup = 1;
-			break;
-		case ALC_FIXUP_PINS:
-			cfg = fix->v.pins;
-			if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
-				break;
-			snd_printdd(KERN_INFO "hda_codec: %s: "
-				    "Apply pincfg for %s\n",
-				    codec->chip_name, modelname);
-			alc_apply_pincfgs(codec, cfg);
-			break;
-		case ALC_FIXUP_VERBS:
-			if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
-				break;
-			snd_printdd(KERN_INFO "hda_codec: %s: "
-				    "Apply fix-verbs for %s\n",
-				    codec->chip_name, modelname);
-			add_verb(codec->spec, fix->v.verbs);
-			break;
-		case ALC_FIXUP_FUNC:
-			if (!fix->v.func)
-				break;
-			snd_printdd(KERN_INFO "hda_codec: %s: "
-				    "Apply fix-func for %s\n",
-				    codec->chip_name, modelname);
-			fix->v.func(codec, fix, action);
-			break;
-		default:
-			snd_printk(KERN_ERR "hda_codec: %s: "
-				   "Invalid fixup type %d\n",
-				   codec->chip_name, fix->type);
-			break;
-		}
-		if (!fix->chained)
-			break;
-		if (++depth > 10)
-			break;
-		id = fix->chain_id;
-	}
-}
-
-static void alc_pick_fixup(struct hda_codec *codec,
-			   const struct alc_model_fixup *models,
-			   const struct snd_pci_quirk *quirk,
-			   const struct alc_fixup *fixlist)
-{
-	struct alc_spec *spec = codec->spec;
-	const struct snd_pci_quirk *q;
-	int id = -1;
-	const char *name = NULL;
-
-	/* when model=nofixup is given, don't pick up any fixups */
-	if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
-		spec->fixup_list = NULL;
-		spec->fixup_id = -1;
-		return;
-	}
-
-	if (codec->modelname && models) {
-		while (models->name) {
-			if (!strcmp(codec->modelname, models->name)) {
-				id = models->id;
-				name = models->name;
-				break;
-			}
-			models++;
-		}
-	}
-	if (id < 0) {
-		q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
-		if (q) {
-			id = q->value;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-			name = q->name;
-#endif
-		}
-	}
-	if (id < 0) {
-		for (q = quirk; q->subvendor; q++) {
-			unsigned int vendorid =
-				q->subdevice | (q->subvendor << 16);
-			if (vendorid == codec->subsystem_id) {
-				id = q->value;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-				name = q->name;
-#endif
-				break;
-			}
-		}
-	}
-
-	spec->fixup_id = id;
-	if (id >= 0) {
-		spec->fixup_list = fixlist;
-		spec->fixup_name = name;
-	}
-}
-
-/*
  * COEF access helper functions
  */
 static int alc_read_coef_idx(struct hda_codec *codec,
@@ -1621,8 +1445,7 @@
 		pin = spec->autocfg.dig_out_pins[i];
 		if (!pin)
 			continue;
-		snd_hda_codec_write(codec, pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+		snd_hda_set_pin_ctl(codec, pin, PIN_OUT);
 		if (!i)
 			dac = spec->multiout.dig_out_nid;
 		else
@@ -1635,9 +1458,7 @@
 	}
 	pin = spec->autocfg.dig_in_pin;
 	if (pin)
-		snd_hda_codec_write(codec, pin, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    PIN_IN);
+		snd_hda_set_pin_ctl(codec, pin, PIN_IN);
 }
 
 /* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
@@ -2068,7 +1889,6 @@
 static int alc_init(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int i;
 
 	if (spec->init_hook)
 		spec->init_hook(codec);
@@ -2076,8 +1896,6 @@
 	alc_fix_pll(codec);
 	alc_auto_init_amp(codec, spec->init_amp);
 
-	for (i = 0; i < spec->num_init_verbs; i++)
-		snd_hda_sequence_write(codec, spec->init_verbs[i]);
 	alc_init_special_input_src(codec);
 	alc_auto_init_std(codec);
 
@@ -2725,7 +2543,6 @@
 	nid = codec->start_nid;
 	for (i = 0; i < codec->num_nodes; i++, nid++) {
 		hda_nid_t src;
-		const hda_nid_t *list;
 		unsigned int caps = get_wcaps(codec, nid);
 		int type = get_wcaps_type(caps);
 
@@ -2743,13 +2560,14 @@
 				cap_nids[nums] = src;
 				break;
 			}
-			n = snd_hda_get_conn_list(codec, src, &list);
+			n = snd_hda_get_num_conns(codec, src);
 			if (n > 1) {
 				cap_nids[nums] = src;
 				break;
 			} else if (n != 1)
 				break;
-			src = *list;
+			if (snd_hda_get_connections(codec, src, &src, 1) != 1)
+				break;
 		}
 		if (++nums >= max_nums)
 			break;
@@ -2856,8 +2674,7 @@
 static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
 			       unsigned int pin_type)
 {
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
+	snd_hda_set_pin_ctl(codec, nid, pin_type);
 	/* unmute pin */
 	if (nid_has_mute(codec, nid, HDA_OUTPUT))
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
@@ -2891,7 +2708,7 @@
 
 	/* mute all loopback inputs */
 	if (spec->mixer_nid) {
-		int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
+		int nums = snd_hda_get_num_conns(codec, spec->mixer_nid);
 		for (i = 0; i < nums; i++)
 			snd_hda_codec_write(codec, spec->mixer_nid, 0,
 					    AC_VERB_SET_AMP_GAIN_MUTE,
@@ -3521,7 +3338,7 @@
 	if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
 		type = ALC_CTL_WIDGET_MUTE;
 		val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
-	} else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
+	} else if (snd_hda_get_num_conns(codec, nid) == 1) {
 		type = ALC_CTL_WIDGET_MUTE;
 		val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
 	} else {
@@ -3998,9 +3815,7 @@
 			snd_hda_codec_read(codec, nid, 0,
 					   AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 	if (output) {
-		snd_hda_codec_update_cache(codec, nid, 0,
-					   AC_VERB_SET_PIN_WIDGET_CONTROL,
-					   PIN_OUT);
+		snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT);
 		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
 			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
 						 HDA_AMP_MUTE, 0);
@@ -4009,9 +3824,8 @@
 		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
 			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
 						 HDA_AMP_MUTE, HDA_AMP_MUTE);
-		snd_hda_codec_update_cache(codec, nid, 0,
-					   AC_VERB_SET_PIN_WIDGET_CONTROL,
-					   spec->multi_io[idx].ctl_in);
+		snd_hda_set_pin_ctl_cache(codec, nid,
+					  spec->multi_io[idx].ctl_in);
 	}
 	return 0;
 }
@@ -4084,7 +3898,7 @@
 	nums = 0;
 	for (n = 0; n < spec->num_adc_nids; n++) {
 		hda_nid_t cap = spec->private_capsrc_nids[n];
-		int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
+		int num_conns = snd_hda_get_num_conns(codec, cap);
 		for (i = 0; i < imux->num_items; i++) {
 			hda_nid_t pin = spec->imux_pins[i];
 			if (pin) {
@@ -4213,7 +4027,7 @@
 	if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
 		snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
 					 HDA_AMP_MUTE, 0);
-	} else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
+	} else if (snd_hda_get_num_conns(codec, cap) > 1) {
 		snd_hda_codec_write_cache(codec, cap, 0,
 					  AC_VERB_SET_CONNECT_SEL, idx);
 	}
@@ -4427,6 +4241,25 @@
 	return 1;
 }
 
+/* common preparation job for alc_spec */
+static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
+{
+	struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	int err;
+
+	if (!spec)
+		return -ENOMEM;
+	codec->spec = spec;
+	spec->mixer_nid = mixer_nid;
+
+	err = alc_codec_rename_from_preset(codec);
+	if (err < 0) {
+		kfree(spec);
+		return err;
+	}
+	return 0;
+}
+
 static int alc880_parse_auto_config(struct hda_codec *codec)
 {
 	static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
@@ -4808,13 +4641,11 @@
 	struct alc_spec *spec;
 	int err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
 
-	codec->spec = spec;
-
-	spec->mixer_nid = 0x0b;
+	spec = codec->spec;
 	spec->need_dac_fix = 1;
 
 	alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
@@ -4890,7 +4721,7 @@
 		spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
 		snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT);
 		spec->unsol_event = alc_sku_unsol_event;
-		add_verb(codec->spec, alc_gpio1_init_verbs);
+		snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs);
 	}
 }
 
@@ -5001,13 +4832,11 @@
 	struct alc_spec *spec;
 	int err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
+	err = alc_alloc_spec(codec, 0x07);
+	if (err < 0)
+		return err;
 
-	codec->spec = spec;
-
-	spec->mixer_nid = 0x07;
+	spec = codec->spec;
 
 	alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
 	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -5171,8 +5000,7 @@
 		val = snd_hda_codec_read(codec, nids[i], 0,
 					 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 		val |= AC_PINCTL_VREF_80;
-		snd_hda_codec_write(codec, nids[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+		snd_hda_set_pin_ctl(codec, nids[i], val);
 		spec->keep_vref_in_automute = 1;
 		break;
 	}
@@ -5193,8 +5021,7 @@
 		val = snd_hda_codec_read(codec, nids[i], 0,
 					 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 		val |= AC_PINCTL_VREF_50;
-		snd_hda_codec_write(codec, nids[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+		snd_hda_set_pin_ctl(codec, nids[i], val);
 	}
 	spec->keep_vref_in_automute = 1;
 }
@@ -5225,8 +5052,8 @@
 		}
 	},
 	[ALC882_FIXUP_ACER_ASPIRE_7736] = {
-		.type = ALC_FIXUP_SKU,
-		.v.sku = ALC_FIXUP_SKU_IGNORE,
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_sku_ignore,
 	},
 	[ALC882_FIXUP_ASUS_W90V] = {
 		.type = ALC_FIXUP_PINS,
@@ -5476,13 +5303,11 @@
 	struct alc_spec *spec;
 	int err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
 
-	codec->spec = spec;
-
-	spec->mixer_nid = 0x0b;
+	spec = codec->spec;
 
 	switch (codec->vendor_id) {
 	case 0x10ec0882:
@@ -5494,10 +5319,6 @@
 		break;
 	}
 
-	err = alc_codec_rename_from_preset(codec);
-	if (err < 0)
-		goto error;
-
 	alc_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
 		       alc882_fixups);
 	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -5621,13 +5442,11 @@
 	struct alc_spec *spec;
 	int err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
 
-	codec->spec = spec;
-
-	spec->mixer_nid = 0x0b;
+	spec = codec->spec;
 
 #if 0
 	/* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
@@ -5710,7 +5529,7 @@
 	if (err > 0) {
 		if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
 			add_mixer(spec, alc268_beep_mixer);
-			add_verb(spec, alc268_beep_init_verbs);
+			snd_hda_gen_add_verbs(&spec->gen, alc268_beep_init_verbs);
 		}
 	}
 	return err;
@@ -5723,13 +5542,12 @@
 	struct alc_spec *spec;
 	int i, has_beep, err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
-
-	codec->spec = spec;
-
 	/* ALC268 has no aa-loopback mixer */
+	err = alc_alloc_spec(codec, 0);
+	if (err < 0)
+		return err;
+
+	spec = codec->spec;
 
 	/* automatic parse from the BIOS config */
 	err = alc268_parse_auto_config(codec);
@@ -5946,9 +5764,7 @@
 {
 	struct hda_codec *codec = private_data;
 	unsigned int pinval = enabled ? 0x20 : 0x24;
-	snd_hda_codec_update_cache(codec, 0x19, 0,
-				   AC_VERB_SET_PIN_WIDGET_CONTROL,
-				   pinval);
+	snd_hda_set_pin_ctl_cache(codec, 0x19, pinval);
 }
 
 static void alc269_fixup_mic2_mute(struct hda_codec *codec,
@@ -6015,8 +5831,8 @@
 		}
 	},
 	[ALC269_FIXUP_SKU_IGNORE] = {
-		.type = ALC_FIXUP_SKU,
-		.v.sku = ALC_FIXUP_SKU_IGNORE,
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_sku_ignore,
 	},
 	[ALC269_FIXUP_ASUS_G73JW] = {
 		.type = ALC_FIXUP_PINS,
@@ -6242,19 +6058,13 @@
 static int patch_alc269(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
-	int err = 0;
+	int err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
-
-	codec->spec = spec;
-
-	spec->mixer_nid = 0x0b;
-
-	err = alc_codec_rename_from_preset(codec);
+	err = alc_alloc_spec(codec, 0x0b);
 	if (err < 0)
-		goto error;
+		return err;
+
+	spec = codec->spec;
 
 	if (codec->vendor_id == 0x10ec0269) {
 		spec->codec_variant = ALC269_TYPE_ALC269VA;
@@ -6346,8 +6156,7 @@
 	if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
 		val |= AC_PINCTL_IN_EN;
 	val |= AC_PINCTL_VREF_50;
-	snd_hda_codec_write(codec, 0x0f, 0,
-			    AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+	snd_hda_set_pin_ctl(codec, 0x0f, val);
 	spec->keep_vref_in_automute = 1;
 }
 
@@ -6401,13 +6210,11 @@
 	struct alc_spec *spec;
 	int err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
+	err = alc_alloc_spec(codec, 0x15);
+	if (err < 0)
+		return err;
 
-	codec->spec = spec;
-
-	spec->mixer_nid = 0x15;
+	spec = codec->spec;
 
 	alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
 	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -6504,13 +6311,11 @@
 	struct alc_spec *spec;
 	int err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
 
-	codec->spec = spec;
-
-	spec->mixer_nid = 0x0b;
+	spec = codec->spec;
 
 	alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
 	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -6522,7 +6327,7 @@
 
 	if (codec->vendor_id == 0x10ec0660) {
 		/* always turn on EAPD */
-		add_verb(spec, alc660vd_eapd_verbs);
+		snd_hda_gen_add_verbs(&spec->gen, alc660vd_eapd_verbs);
 	}
 
 	if (!spec->no_analog) {
@@ -6635,8 +6440,8 @@
 		}
 	},
 	[ALC662_FIXUP_SKU_IGNORE] = {
-		.type = ALC_FIXUP_SKU,
-		.v.sku = ALC_FIXUP_SKU_IGNORE,
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_sku_ignore,
 	},
 	[ALC662_FIXUP_HP_RP5800] = {
 		.type = ALC_FIXUP_PINS,
@@ -6849,25 +6654,19 @@
 static int patch_alc662(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
-	int err = 0;
+	int err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (!spec)
-		return -ENOMEM;
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
 
-	codec->spec = spec;
-
-	spec->mixer_nid = 0x0b;
+	spec = codec->spec;
 
 	/* handle multiple HPs as is */
 	spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
 
 	alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
-	err = alc_codec_rename_from_preset(codec);
-	if (err < 0)
-		goto error;
-
 	if ((alc_get_coef0(codec) & (1 << 14)) &&
 	    codec->bus->pci->subsystem_vendor == 0x1025 &&
 	    spec->cdefine.platform_type == 1) {
@@ -6930,16 +6729,12 @@
  */
 static int patch_alc680(struct hda_codec *codec)
 {
-	struct alc_spec *spec;
 	int err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
-
-	codec->spec = spec;
-
 	/* ALC680 has no aa-loopback mixer */
+	err = alc_alloc_spec(codec, 0);
+	if (err < 0)
+		return err;
 
 	/* automatic parse from the BIOS config */
 	err = alc680_parse_auto_config(codec);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 2cb1e08..7db8228 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -36,6 +36,7 @@
 #include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
 
@@ -221,6 +222,7 @@
 	unsigned char aloopback_shift;
 
 	/* power management */
+	unsigned int power_map_bits;
 	unsigned int num_pwrs;
 	const hda_nid_t *pwr_nids;
 	const hda_nid_t *dac_list;
@@ -314,6 +316,9 @@
 	struct hda_vmaster_mute_hook vmaster_mute;
 };
 
+#define AC_VERB_IDT_SET_POWER_MAP	0x7ec
+#define AC_VERB_IDT_GET_POWER_MAP	0xfec
+
 static const hda_nid_t stac9200_adc_nids[1] = {
         0x03,
 };
@@ -681,8 +686,7 @@
 	pinctl &= ~AC_PINCTL_VREFEN;
 	pinctl |= (new_vref & AC_PINCTL_VREFEN);
 
-	error = snd_hda_codec_write_cache(codec, nid, 0,
-					AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+	error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl);
 	if (error < 0)
 		return error;
 
@@ -706,8 +710,7 @@
 	else
 		pincfg |= AC_PINCTL_IN_EN;
 
-	error = snd_hda_codec_write_cache(codec, nid, 0,
-					AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg);
+	error = snd_hda_set_pin_ctl_cache(codec, nid, pincfg);
 	if (error < 0)
 		return error;
 	else
@@ -2505,27 +2508,10 @@
 	return 0;
 }
 
-static unsigned int stac92xx_get_default_vref(struct hda_codec *codec,
-					hda_nid_t nid)
-{
-	unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
-	pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
-	if (pincap & AC_PINCAP_VREF_100)
-		return AC_PINCTL_VREF_100;
-	if (pincap & AC_PINCAP_VREF_80)
-		return AC_PINCTL_VREF_80;
-	if (pincap & AC_PINCAP_VREF_50)
-		return AC_PINCTL_VREF_50;
-	if (pincap & AC_PINCAP_VREF_GRD)
-		return AC_PINCTL_VREF_GRD;
-	return 0;
-}
-
 static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
 
 {
-	snd_hda_codec_write_cache(codec, nid, 0,
-				  AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+	snd_hda_set_pin_ctl_cache(codec, nid, pin_type);
 }
 
 #define stac92xx_hp_switch_info		snd_ctl_boolean_mono_info
@@ -2594,7 +2580,7 @@
 	hda_nid_t nid = kcontrol->private_value;
 	unsigned int vref = stac92xx_vref_get(codec, nid);
 
-	if (vref == stac92xx_get_default_vref(codec, nid))
+	if (vref == snd_hda_get_default_vref(codec, nid))
 		ucontrol->value.enumerated.item[0] = 0;
 	else if (vref == AC_PINCTL_VREF_GRD)
 		ucontrol->value.enumerated.item[0] = 1;
@@ -2613,7 +2599,7 @@
 	hda_nid_t nid = kcontrol->private_value;
 
 	if (ucontrol->value.enumerated.item[0] == 0)
-		new_vref = stac92xx_get_default_vref(codec, nid);
+		new_vref = snd_hda_get_default_vref(codec, nid);
 	else if (ucontrol->value.enumerated.item[0] == 1)
 		new_vref = AC_PINCTL_VREF_GRD;
 	else if (ucontrol->value.enumerated.item[0] == 2)
@@ -2679,7 +2665,7 @@
 	else {
 		unsigned int pinctl = AC_PINCTL_IN_EN;
 		if (io_idx) /* set VREF for mic */
-			pinctl |= stac92xx_get_default_vref(codec, nid);
+			pinctl |= snd_hda_get_default_vref(codec, nid);
 		stac92xx_auto_set_pinctl(codec, nid, pinctl);
 	}
 
@@ -2847,7 +2833,7 @@
 	char name[22];
 
 	if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
-		if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
+		if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
 			&& nid == spec->line_switch)
 			control = STAC_CTL_WIDGET_IO_SWITCH;
 		else if (snd_hda_query_pin_caps(codec, nid)
@@ -4250,13 +4236,6 @@
 	val = snd_hda_get_bool_hint(codec, "eapd_switch");
 	if (val >= 0)
 		spec->eapd_switch = val;
-	get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity);
-	if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
-		spec->gpio_mask |= spec->gpio_led;
-		spec->gpio_dir |= spec->gpio_led;
-		if (spec->gpio_led_polarity)
-			spec->gpio_data |= spec->gpio_led;
-	}
 }
 
 static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins,
@@ -4354,7 +4333,7 @@
 		unsigned int pinctl, conf;
 		if (type == AUTO_PIN_MIC) {
 			/* for mic pins, force to initialize */
-			pinctl = stac92xx_get_default_vref(codec, nid);
+			pinctl = snd_hda_get_default_vref(codec, nid);
 			pinctl |= AC_PINCTL_IN_EN;
 			stac92xx_auto_set_pinctl(codec, nid, pinctl);
 		} else {
@@ -4390,10 +4369,18 @@
 		hda_nid_t nid = spec->pwr_nids[i];
 		int pinctl, def_conf;
 
+		def_conf = snd_hda_codec_get_pincfg(codec, nid);
+		def_conf = get_defcfg_connect(def_conf);
+		if (def_conf == AC_JACK_PORT_NONE) {
+			/* power off unused ports */
+			stac_toggle_power_map(codec, nid, 0);
+			continue;
+		}
 		/* power on when no jack detection is available */
 		/* or when the VREF is used for controlling LED */
 		if (!spec->hp_detect ||
-		    spec->vref_mute_led_nid == nid) {
+		    spec->vref_mute_led_nid == nid ||
+		    !is_jack_detectable(codec, nid)) {
 			stac_toggle_power_map(codec, nid, 1);
 			continue;
 		}
@@ -4411,15 +4398,6 @@
 			stac_toggle_power_map(codec, nid, 1);
 			continue;
 		}
-		def_conf = snd_hda_codec_get_pincfg(codec, nid);
-		def_conf = get_defcfg_connect(def_conf);
-		/* skip any ports that don't have jacks since presence
- 		 * detection is useless */
-		if (def_conf != AC_JACK_PORT_NONE &&
-		    !is_jack_detectable(codec, nid)) {
-			stac_toggle_power_map(codec, nid, 1);
-			continue;
-		}
 		if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
 			stac_issue_unsol_event(codec, nid);
 			continue;
@@ -4432,6 +4410,12 @@
 
 	/* sync mute LED */
 	snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
+
+	/* sync the power-map */
+	if (spec->num_pwrs)
+		snd_hda_codec_write(codec, codec->afg, 0,
+				    AC_VERB_IDT_SET_POWER_MAP,
+				    spec->power_map_bits);
 	if (spec->dac_list)
 		stac92xx_power_down(codec);
 	return 0;
@@ -4460,8 +4444,7 @@
 		struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
 		def_conf = snd_hda_codec_get_pincfg(codec, pin->nid);
 		if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
-			snd_hda_codec_write(codec, pin->nid, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+			snd_hda_set_pin_ctl(codec, pin->nid, 0);
 	}
 }
 
@@ -4517,9 +4500,7 @@
 	
 	pin_ctl |= flag;
 	if (old_ctl != pin_ctl)
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_PIN_WIDGET_CONTROL,
-					  pin_ctl);
+		snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl);
 }
 
 static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
@@ -4528,9 +4509,7 @@
 	unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
 			0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
 	if (pin_ctl & flag)
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_PIN_WIDGET_CONTROL,
-					  pin_ctl & ~flag);
+		snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl & ~flag);
 }
 
 static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
@@ -4682,14 +4661,18 @@
 
 	idx = 1 << idx;
 
-	val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
+	val = spec->power_map_bits;
 	if (enable)
 		val &= ~idx;
 	else
 		val |= idx;
 
 	/* power down unused output ports */
-	snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
+	if (val != spec->power_map_bits) {
+		spec->power_map_bits = val;
+		snd_hda_codec_write(codec, codec->afg, 0,
+				    AC_VERB_IDT_SET_POWER_MAP, val);
+	}
 }
 
 static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
@@ -4866,6 +4849,11 @@
 	struct sigmatel_spec *spec = codec->spec;
 	const struct dmi_device *dev = NULL;
 
+	if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
+		get_int_hint(codec, "gpio_led_polarity",
+			     &spec->gpio_led_polarity);
+		return 1;
+	}
 	if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
 		while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
 								NULL, dev))) {
@@ -4952,7 +4940,8 @@
 {
 	if (nid == codec->afg)
 		snd_iprintf(buffer, "Power-Map: 0x%02x\n", 
-			    snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0));
+			    snd_hda_codec_read(codec, nid, 0,
+					       AC_VERB_IDT_GET_POWER_MAP, 0));
 }
 
 static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
@@ -5009,20 +4998,6 @@
 	return 0;
 }
 
-static int stac92xx_pre_resume(struct hda_codec *codec)
-{
-	struct sigmatel_spec *spec = codec->spec;
-
-	/* sync mute LED */
-	if (spec->vref_mute_led_nid)
-		stac_vrefout_set(codec, spec->vref_mute_led_nid,
-				 spec->vref_led);
-	else if (spec->gpio_led)
-		stac_gpio_set(codec, spec->gpio_mask,
-			      spec->gpio_dir, spec->gpio_data);
-	return 0;
-}
-
 static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 				unsigned int power_state)
 {
@@ -5046,7 +5021,6 @@
 #else
 #define stac92xx_suspend	NULL
 #define stac92xx_resume		NULL
-#define stac92xx_pre_resume	NULL
 #define stac92xx_set_power_state NULL
 #endif /* CONFIG_PM */
 
@@ -5592,9 +5566,6 @@
 			codec->patch_ops.set_power_state =
 					stac92xx_set_power_state;
 		}
-#ifdef CONFIG_PM
-		codec->patch_ops.pre_resume = stac92xx_pre_resume;
-#endif
 	}
 
 	err = stac92xx_parse_auto_config(codec);
@@ -5901,9 +5872,6 @@
 			codec->patch_ops.set_power_state =
 					stac92xx_set_power_state;
 		}
-#ifdef CONFIG_PM
-		codec->patch_ops.pre_resume = stac92xx_pre_resume;
-#endif
 	}
 
 	spec->multiout.dac_nids = spec->dac_nids;
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 06214fd..82b3680 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -54,6 +54,7 @@
 #include <sound/asoundef.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_jack.h"
 
 /* Pin Widget NID */
@@ -484,7 +485,7 @@
 
 	if (!path)
 		return;
-	num = snd_hda_get_conn_list(codec, mix_nid, NULL);
+	num = snd_hda_get_num_conns(codec, mix_nid);
 	for (i = 0; i < num; i++) {
 		if (i == idx)
 			val = AMP_IN_UNMUTE(i);
@@ -532,8 +533,7 @@
 {
 	if (!pin)
 		return;
-	snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
+	snd_hda_set_pin_ctl(codec, pin, pin_type);
 	if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)
 		snd_hda_codec_write(codec, pin, 0,
 				    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
@@ -662,12 +662,12 @@
 		hda_nid_t nid = cfg->inputs[i].pin;
 		if (spec->smart51_enabled && is_smart51_pins(codec, nid))
 			ctl = PIN_OUT;
-		else if (cfg->inputs[i].type == AUTO_PIN_MIC)
-			ctl = PIN_VREF50;
-		else
+		else {
 			ctl = PIN_IN;
-		snd_hda_codec_write(codec, nid, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
+			if (cfg->inputs[i].type == AUTO_PIN_MIC)
+				ctl |= snd_hda_get_default_vref(codec, nid);
+		}
+		snd_hda_set_pin_ctl(codec, nid, ctl);
 	}
 
 	/* init input-src */
@@ -1006,9 +1006,7 @@
 					  AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 		parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
 		parm |= out_in;
-		snd_hda_codec_write(codec, nid, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    parm);
+		snd_hda_set_pin_ctl(codec, nid, parm);
 		if (out_in == AC_PINCTL_OUT_EN) {
 			mute_aa_path(codec, 1);
 			notify_aa_path_ctls(codec);
@@ -1647,8 +1645,7 @@
 			parm &= ~AC_PINCTL_OUT_EN;
 		else
 			parm |= AC_PINCTL_OUT_EN;
-		snd_hda_codec_write(codec, pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, parm);
+		snd_hda_set_pin_ctl(codec, pins[i], parm);
 	}
 }
 
@@ -1709,8 +1706,7 @@
 
 	if (gpio_data == 0x02) {
 		/* unmute line out */
-		snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
+		snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0],
 				    PIN_OUT);
 		if (vol_counter & 0x20) {
 			/* decrease volume */
@@ -1728,9 +1724,7 @@
 		}
 	} else if (!(gpio_data & 0x02)) {
 		/* mute line out */
-		snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    0);
+		snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], 0);
 	}
 }
 
@@ -2757,8 +2751,7 @@
 	struct via_spec *spec = codec->spec;
 	if (!spec->dig_in_nid)
 		return;
-	snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
-			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+	snd_hda_set_pin_ctl(codec, spec->autocfg.dig_in_pin, PIN_IN);
 }
 
 /* initialize the unsolicited events */
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 132a86e..5be2e12 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -2803,22 +2803,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver ice1712_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_ice1712_ids,
 	.probe = snd_ice1712_probe,
 	.remove = __devexit_p(snd_ice1712_remove),
 };
 
-static int __init alsa_card_ice1712_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ice1712_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ice1712_init)
-module_exit(alsa_card_ice1712_exit)
+module_pci_driver(ice1712_driver);
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 812d10e..a01a00d 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2873,7 +2873,7 @@
 }
 #endif
 
-static struct pci_driver driver = {
+static struct pci_driver vt1724_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_vt1724_ids,
 	.probe = snd_vt1724_probe,
@@ -2884,15 +2884,4 @@
 #endif
 };
 
-static int __init alsa_card_ice1724_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ice1724_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ice1724_init)
-module_exit(alsa_card_ice1724_exit)
+module_pci_driver(vt1724_driver);
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index e0a4263..f4e2dd4 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -3338,7 +3338,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver intel8x0_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_intel8x0_ids,
 	.probe = snd_intel8x0_probe,
@@ -3349,16 +3349,4 @@
 #endif
 };
 
-
-static int __init alsa_card_intel8x0_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_intel8x0_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_intel8x0_init)
-module_exit(alsa_card_intel8x0_exit)
+module_pci_driver(intel8x0_driver);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index d689913..fc27a6a 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -1324,7 +1324,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver intel8x0m_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_intel8x0m_ids,
 	.probe = snd_intel8x0m_probe,
@@ -1335,16 +1335,4 @@
 #endif
 };
 
-
-static int __init alsa_card_intel8x0m_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_intel8x0m_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_intel8x0m_init)
-module_exit(alsa_card_intel8x0m_exit)
+module_pci_driver(intel8x0m_driver);
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 8fea45a..e69ce5f 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2476,22 +2476,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver korg1212_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_korg1212_ids,
 	.probe = snd_korg1212_probe,
 	.remove = __devexit_p(snd_korg1212_remove),
 };
 
-static int __init alsa_card_korg1212_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_korg1212_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_korg1212_init)
-module_exit(alsa_card_korg1212_exit)
+module_pci_driver(korg1212_driver);
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 3759827..ac15166 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -770,22 +770,11 @@
 MODULE_DEVICE_TABLE(pci, lola_ids);
 
 /* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver lola_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = lola_ids,
 	.probe = lola_probe,
 	.remove = __devexit_p(lola_remove),
 };
 
-static int __init alsa_card_lola_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_lola_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_lola_init)
-module_exit(alsa_card_lola_exit)
+module_pci_driver(lola_driver);
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index d94c0c2..d1ab437 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -1141,24 +1141,11 @@
 }
 
 
-static struct pci_driver driver = {
+static struct pci_driver lx6464es_driver = {
 	.name =     KBUILD_MODNAME,
 	.id_table = snd_lx6464es_ids,
 	.probe =    snd_lx6464es_probe,
 	.remove = __devexit_p(snd_lx6464es_remove),
 };
 
-
-/* module initialization */
-static int __init mod_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit mod_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(mod_init);
-module_exit(mod_exit);
+module_pci_driver(lx6464es_driver);
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 78229b0..deef213 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -2837,7 +2837,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver m3_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_m3_ids,
 	.probe = snd_m3_probe,
@@ -2848,15 +2848,4 @@
 #endif
 };
 	
-static int __init alsa_card_m3_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_m3_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_m3_init)
-module_exit(alsa_card_m3_exit)
+module_pci_driver(m3_driver);
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 487837c..0762610 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1380,22 +1380,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver mixart_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_mixart_ids,
 	.probe = snd_mixart_probe,
 	.remove = __devexit_p(snd_mixart_remove),
 };
 
-static int __init alsa_card_mixart_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_mixart_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_mixart_init)
-module_exit(alsa_card_mixart_exit)
+module_pci_driver(mixart_driver);
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index ade2c64..8159b05 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1742,7 +1742,7 @@
 }
 
 
-static struct pci_driver driver = {
+static struct pci_driver nm256_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_nm256_ids,
 	.probe = snd_nm256_probe,
@@ -1753,16 +1753,4 @@
 #endif
 };
 
-
-static int __init alsa_card_nm256_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_nm256_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_nm256_init)
-module_exit(alsa_card_nm256_exit)
+module_pci_driver(nm256_driver);
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index eab663e..610275b 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -94,6 +94,7 @@
 	MODEL_2CH_OUTPUT,
 	MODEL_HG2PCI,
 	MODEL_XONAR_DG,
+	MODEL_XONAR_DGX,
 };
 
 static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
@@ -109,6 +110,8 @@
 	{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
 	/* Asus Xonar DG */
 	{ OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG },
+	/* Asus Xonar DGX */
+	{ OXYGEN_PCI_SUBID(0x1043, 0x8521), .driver_data = MODEL_XONAR_DGX },
 	/* PCI 2.0 HD Audio */
 	{ OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT },
 	/* Kuroutoshikou CMI8787-HG2PCI */
@@ -827,6 +830,11 @@
 		break;
 	case MODEL_XONAR_DG:
 		chip->model = model_xonar_dg;
+		chip->model.shortname = "Xonar DG";
+		break;
+	case MODEL_XONAR_DGX:
+		chip->model = model_xonar_dg;
+		chip->model.shortname = "Xonar DGX";
 		break;
 	}
 	if (id->driver_data == MODEL_MERIDIAN ||
@@ -870,15 +878,4 @@
 #endif
 };
 
-static int __init alsa_card_oxygen_init(void)
-{
-	return pci_register_driver(&oxygen_driver);
-}
-
-static void __exit alsa_card_oxygen_exit(void)
-{
-	pci_unregister_driver(&oxygen_driver);
-}
-
-module_init(alsa_card_oxygen_init)
-module_exit(alsa_card_oxygen_exit)
+module_pci_driver(oxygen_driver);
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 3fdee49..19962c6 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -100,15 +100,4 @@
 	.shutdown = oxygen_pci_shutdown,
 };
 
-static int __init alsa_card_xonar_init(void)
-{
-	return pci_register_driver(&xonar_driver);
-}
-
-static void __exit alsa_card_xonar_exit(void)
-{
-	pci_unregister_driver(&xonar_driver);
-}
-
-module_init(alsa_card_xonar_init)
-module_exit(alsa_card_xonar_exit)
+module_pci_driver(xonar_driver);
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 793bdf0..77acd79 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -1,5 +1,5 @@
 /*
- * card driver for the Xonar DG
+ * card driver for the Xonar DG/DGX
  *
  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
  *
@@ -17,8 +17,8 @@
  */
 
 /*
- * Xonar DG
- * --------
+ * Xonar DG/DGX
+ * ------------
  *
  * CMI8788:
  *
@@ -581,7 +581,6 @@
 }
 
 struct oxygen_model model_xonar_dg = {
-	.shortname = "Xonar DG",
 	.longname = "C-Media Oxygen HD Audio",
 	.chip = "CMI8786",
 	.init = dg_init,
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index fd1809a..0435f45 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -1607,22 +1607,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver pcxhr_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = pcxhr_ids,
 	.probe = pcxhr_probe,
 	.remove = __devexit_p(pcxhr_remove),
 };
 
-static int __init pcxhr_module_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit pcxhr_module_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(pcxhr_module_init)
-module_exit(pcxhr_module_exit)
+module_pci_driver(pcxhr_driver);
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 0481d94..cbeb3f7 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -1837,8 +1837,7 @@
 	}
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
-	if (chip->fw_entry)
-		release_firmware(chip->fw_entry);
+	release_firmware(chip->fw_entry);
 	release_and_free_resource(chip->res_port);
 	kfree(chip);
 	return 0;
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index b4819d5..46b3629 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1984,22 +1984,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver rme32_driver = {
 	.name =		KBUILD_MODNAME,
 	.id_table =	snd_rme32_ids,
 	.probe =	snd_rme32_probe,
 	.remove =	__devexit_p(snd_rme32_remove),
 };
 
-static int __init alsa_card_rme32_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_rme32_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_rme32_init)
-module_exit(alsa_card_rme32_exit)
+module_pci_driver(rme32_driver);
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index ba89415..9b98dc4 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -2395,22 +2395,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver rme96_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_rme96_ids,
 	.probe = snd_rme96_probe,
 	.remove = __devexit_p(snd_rme96_remove),
 };
 
-static int __init alsa_card_rme96_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_rme96_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_rme96_init)
-module_exit(alsa_card_rme96_exit)
+module_pci_driver(rme96_driver);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 0b2aea2..0d6930c 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -5636,22 +5636,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver hdsp_driver = {
 	.name =     KBUILD_MODNAME,
 	.id_table = snd_hdsp_ids,
 	.probe =    snd_hdsp_probe,
 	.remove = __devexit_p(snd_hdsp_remove),
 };
 
-static int __init alsa_card_hdsp_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_hdsp_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_hdsp_init)
-module_exit(alsa_card_hdsp_exit)
+module_pci_driver(hdsp_driver);
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index bc030a2..0a5027b 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -6918,23 +6918,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver hdspm_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_hdspm_ids,
 	.probe = snd_hdspm_probe,
 	.remove = __devexit_p(snd_hdspm_remove),
 };
 
-
-static int __init alsa_card_hdspm_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_hdspm_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_hdspm_init)
-module_exit(alsa_card_hdspm_exit)
+module_pci_driver(hdspm_driver);
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index b737d16..a15fc10 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -2631,22 +2631,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver rme9652_driver = {
 	.name	  = KBUILD_MODNAME,
 	.id_table = snd_rme9652_ids,
 	.probe	  = snd_rme9652_probe,
 	.remove	  = __devexit_p(snd_rme9652_remove),
 };
 
-static int __init alsa_card_hammerfall_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_hammerfall_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_hammerfall_init)
-module_exit(alsa_card_hammerfall_exit)
+module_pci_driver(rme9652_driver);
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index ff500a8..1552642 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -1488,15 +1488,4 @@
 #endif
 };
 
-static int __init sis7019_init(void)
-{
-	return pci_register_driver(&sis7019_driver);
-}
-
-static void __exit sis7019_exit(void)
-{
-	pci_unregister_driver(&sis7019_driver);
-}
-
-module_init(sis7019_init);
-module_exit(sis7019_exit);
+module_pci_driver(sis7019_driver);
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 54cc802..baa9946b 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -1530,22 +1530,11 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver sonicvibes_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_sonic_ids,
 	.probe = snd_sonic_probe,
 	.remove = __devexit_p(snd_sonic_remove),
 };
 
-static int __init alsa_card_sonicvibes_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_sonicvibes_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_sonicvibes_init)
-module_exit(alsa_card_sonicvibes_exit)
+module_pci_driver(sonicvibes_driver);
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index 5f1def7..611983e 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -172,7 +172,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver trident_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_trident_ids,
 	.probe = snd_trident_probe,
@@ -183,15 +183,4 @@
 #endif
 };
 
-static int __init alsa_card_trident_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_trident_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_trident_init)
-module_exit(alsa_card_trident_exit)
+module_pci_driver(trident_driver);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 7563040..b5afab4 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -2619,7 +2619,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver via82xx_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_via82xx_ids,
 	.probe = snd_via82xx_probe,
@@ -2630,15 +2630,4 @@
 #endif
 };
 
-static int __init alsa_card_via82xx_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_via82xx_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_via82xx_init)
-module_exit(alsa_card_via82xx_exit)
+module_pci_driver(via82xx_driver);
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 5efcbca..59fd47e 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -1223,7 +1223,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver via82xx_modem_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_via82xx_modem_ids,
 	.probe = snd_via82xx_probe,
@@ -1234,15 +1234,4 @@
 #endif
 };
 
-static int __init alsa_card_via82xx_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_via82xx_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_via82xx_init)
-module_exit(alsa_card_via82xx_exit)
+module_pci_driver(via82xx_modem_driver);
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 6a534bf..1ea1f65 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -289,7 +289,7 @@
 }
 #endif
 
-static struct pci_driver driver = {
+static struct pci_driver vx222_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_vx222_ids,
 	.probe = snd_vx222_probe,
@@ -300,15 +300,4 @@
 #endif
 };
 
-static int __init alsa_card_vx222_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_vx222_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_vx222_init)
-module_exit(alsa_card_vx222_exit)
+module_pci_driver(vx222_driver);
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 94ab728..9a1d01d 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -350,7 +350,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver ymfpci_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = snd_ymfpci_ids,
 	.probe = snd_card_ymfpci_probe,
@@ -361,15 +361,4 @@
 #endif
 };
 
-static int __init alsa_card_ymfpci_init(void)
-{
-	return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ymfpci_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ymfpci_init)
-module_exit(alsa_card_ymfpci_exit)
+module_pci_driver(ymfpci_driver);
diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c
index b11f82b..f8b01c7 100644
--- a/sound/sh/sh_dac_audio.c
+++ b/sound/sh/sh_dac_audio.c
@@ -433,7 +433,7 @@
 /*
  * "driver" definition
  */
-static struct platform_driver driver = {
+static struct platform_driver sh_dac_driver = {
 	.probe	= snd_sh_dac_probe,
 	.remove = snd_sh_dac_remove,
 	.driver = {
@@ -441,4 +441,4 @@
 	},
 };
 
-module_platform_driver(driver);
+module_platform_driver(sh_dac_driver);
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 91c9855..40b2ad1 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -35,7 +35,6 @@
 source "sound/soc/davinci/Kconfig"
 source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
-source "sound/soc/imx/Kconfig"
 source "sound/soc/jz4740/Kconfig"
 source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
@@ -48,9 +47,13 @@
 source "sound/soc/sh/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
+source "sound/soc/ux500/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
 
+# generic frame-work
+source "sound/soc/generic/Kconfig"
+
 endif	# SND_SOC
 
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 2feaf37..70990f4 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -6,13 +6,13 @@
 
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= codecs/
+obj-$(CONFIG_SND_SOC)	+= generic/
 obj-$(CONFIG_SND_SOC)	+= atmel/
 obj-$(CONFIG_SND_SOC)	+= au1x/
 obj-$(CONFIG_SND_SOC)	+= blackfin/
 obj-$(CONFIG_SND_SOC)	+= davinci/
 obj-$(CONFIG_SND_SOC)	+= ep93xx/
 obj-$(CONFIG_SND_SOC)	+= fsl/
-obj-$(CONFIG_SND_SOC)   += imx/
 obj-$(CONFIG_SND_SOC)	+= jz4740/
 obj-$(CONFIG_SND_SOC)	+= mid-x86/
 obj-$(CONFIG_SND_SOC)	+= mxs/
@@ -25,3 +25,4 @@
 obj-$(CONFIG_SND_SOC)	+= sh/
 obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= txx9/
+obj-$(CONFIG_SND_SOC)	+= ux500/
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
index b39ad35..7dbeef1 100644
--- a/sound/soc/blackfin/bf5xx-ssm2602.c
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -44,16 +44,8 @@
 
 static struct snd_soc_card bf5xx_ssm2602;
 
-static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+static int bf5xx_ssm2602_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	unsigned int clk = 0;
-	int ret = 0;
-
-	pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
-		params_format(params));
 	/*
 	 * If you are using a crystal source which frequency is not 12MHz
 	 * then modify the below case statement with frequency of the crystal.
@@ -61,31 +53,10 @@
 	 * If you are using the SPORT to generate clocking then this is
 	 * where to do it.
 	 */
-
-	switch (params_rate(params)) {
-	case 8000:
-	case 16000:
-	case 48000:
-	case 96000:
-	case 11025:
-	case 22050:
-	case 44100:
-		clk = 12000000;
-		break;
-	}
-
-	ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk,
+	return snd_soc_dai_set_sysclk(rtd->codec_dai, SSM2602_SYSCLK, 12000000,
 		SND_SOC_CLOCK_IN);
-	if (ret < 0)
-		return ret;
-
-	return 0;
 }
 
-static struct snd_soc_ops bf5xx_ssm2602_ops = {
-	.hw_params = bf5xx_ssm2602_hw_params,
-};
-
 /* CODEC is master for BCLK and LRC in this configuration. */
 #define BF5XX_SSM2602_DAIFMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
 				SND_SOC_DAIFMT_CBM_CFM)
@@ -98,7 +69,7 @@
 		.codec_dai_name = "ssm2602-hifi",
 		.platform_name = "bfin-i2s-pcm-audio",
 		.codec_name = "ssm2602.0-001b",
-		.ops = &bf5xx_ssm2602_ops,
+		.init = bf5xx_ssm2602_dai_init,
 		.dai_fmt = BF5XX_SSM2602_DAIFMT,
 	},
 	{
@@ -108,7 +79,7 @@
 		.codec_dai_name = "ssm2602-hifi",
 		.platform_name = "bfin-i2s-pcm-audio",
 		.codec_name = "ssm2602.0-001b",
-		.ops = &bf5xx_ssm2602_ops,
+		.init = bf5xx_ssm2602_dai_init,
 		.dai_fmt = BF5XX_SSM2602_DAIFMT,
 	},
 };
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 59d8efa..1e1613a 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -29,6 +29,7 @@
 	select SND_SOC_ALC5632 if I2C
 	select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
 	select SND_SOC_CS42L51 if I2C
+	select SND_SOC_CS42L52 if I2C
 	select SND_SOC_CS42L73 if I2C
 	select SND_SOC_CS4270 if I2C
 	select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
@@ -37,11 +38,15 @@
 	select SND_SOC_DFBMCS320
 	select SND_SOC_JZ4740_CODEC
 	select SND_SOC_LM4857 if I2C
+	select SND_SOC_LM49453 if I2C
 	select SND_SOC_MAX98088 if I2C
 	select SND_SOC_MAX98095 if I2C
 	select SND_SOC_MAX9850 if I2C
 	select SND_SOC_MAX9768 if I2C
 	select SND_SOC_MAX9877 if I2C
+	select SND_SOC_MC13783 if MFD_MC13XXX
+	select SND_SOC_ML26124 if I2C
+	select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI
 	select SND_SOC_PCM3008
 	select SND_SOC_RT5631 if I2C
 	select SND_SOC_SGTL5000 if I2C
@@ -181,6 +186,9 @@
 config SND_SOC_CS42L51
 	tristate
 
+config SND_SOC_CS42L52
+	tristate
+
 config SND_SOC_CS42L73
 	tristate
 
@@ -217,6 +225,9 @@
 config SND_SOC_DMIC
 	tristate
 
+config SND_SOC_LM49453
+	tristate
+
 config SND_SOC_MAX98088
        tristate
 
@@ -226,6 +237,9 @@
 config SND_SOC_MAX9850
 	tristate
 
+config SND_SOC_OMAP_HDMI_CODEC
+       tristate
+
 config SND_SOC_PCM3008
        tristate
 
@@ -435,5 +449,11 @@
 config SND_SOC_MAX9877
 	tristate
 
+config SND_SOC_MC13783
+	tristate
+
+config SND_SOC_ML26124
+	tristate
+
 config SND_SOC_TPA6130A2
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 6662eb0..fc27fec 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -15,6 +15,7 @@
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs42l51-objs := cs42l51.o
+snd-soc-cs42l52-objs := cs42l52.o
 snd-soc-cs42l73-objs := cs42l73.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
@@ -25,10 +26,14 @@
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
+snd-soc-lm49453-objs := lm49453.o
 snd-soc-max9768-objs := max9768.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
+snd-soc-mc13783-objs := mc13783.o
+snd-soc-ml26124-objs := ml26124.o
+snd-soc-omap-hdmi-codec-objs := omap-hdmi.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-sgtl5000-objs := sgtl5000.o
@@ -121,6 +126,7 @@
 obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
 obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o
+obj-$(CONFIG_SND_SOC_CS42L52)	+= snd-soc-cs42l52.o
 obj-$(CONFIG_SND_SOC_CS42L73)	+= snd-soc-cs42l73.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o
@@ -128,13 +134,17 @@
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DFBMCS320)	+= snd-soc-dfbmcs320.o
 obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_LM4857)	+= snd-soc-lm4857.o
-obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_LM49453)   += snd-soc-lm49453.o
 obj-$(CONFIG_SND_SOC_MAX9768)	+= snd-soc-max9768.o
 obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
+obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
+obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
+obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)	+= snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 1bbad4c..2023c74 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -26,13 +26,11 @@
 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_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 
 	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
-	return snd_ac97_set_rate(codec->ac97, reg, runtime->rate);
+	return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate);
 }
 
 #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 12e3b41..c67b50d 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -162,9 +162,7 @@
 		struct snd_soc_dai *dai)
 {
 	int word_len = 0;
-
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 
 	/* bit size */
 	switch (params_format(params)) {
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index a4a6bef..13e62be 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -245,9 +245,7 @@
 		struct snd_soc_dai *dai)
 {
 	int word_len = 0, master_rate = 0;
-
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
 
 	/* bit size */
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 78e9ce4..3d50fc8 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -258,8 +258,7 @@
 static int adau1701_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 snd_soc_codec *codec = dai->codec;
 	snd_pcm_format_t format;
 	unsigned int val;
 
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index ceb96ecf..31d4483 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -88,8 +88,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	int val = 0;
 
 	/* set the IEC958 bits: consumer mode, no copyright bit */
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 838ae8b..618fdc3 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -262,8 +262,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
 	u8 mode2 = snd_soc_read(codec, AK4535_MODE2) & ~(0x3 << 5);
 	int rate = params_rate(params), fs = 256;
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index c4d165a..543a12f 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -296,8 +296,7 @@
 				 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 snd_soc_codec *codec = dai->codec;
 	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
 	int rate = params_rate(params), fs = 256;
 	u8 mode2;
@@ -517,67 +516,24 @@
 
 static int ak4641_probe(struct snd_soc_codec *codec)
 {
-	struct ak4641_platform_data *pdata = codec->dev->platform_data;
 	int ret;
 
-
-	if (pdata) {
-		if (gpio_is_valid(pdata->gpio_power)) {
-			ret = gpio_request_one(pdata->gpio_power,
-					GPIOF_OUT_INIT_LOW, "ak4641 power");
-			if (ret)
-				goto err_out;
-		}
-		if (gpio_is_valid(pdata->gpio_npdn)) {
-			ret = gpio_request_one(pdata->gpio_npdn,
-					GPIOF_OUT_INIT_LOW, "ak4641 npdn");
-			if (ret)
-				goto err_gpio;
-
-			udelay(1); /* > 150 ns */
-			gpio_set_value(pdata->gpio_npdn, 1);
-		}
-	}
-
 	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);
-		goto err_register;
+		return ret;
 	}
 
 	/* power on device */
 	ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	return 0;
-
-err_register:
-	if (pdata) {
-		if (gpio_is_valid(pdata->gpio_power))
-			gpio_set_value(pdata->gpio_power, 0);
-		if (gpio_is_valid(pdata->gpio_npdn))
-			gpio_free(pdata->gpio_npdn);
-	}
-err_gpio:
-	if (pdata && gpio_is_valid(pdata->gpio_power))
-		gpio_free(pdata->gpio_power);
-err_out:
-	return ret;
 }
 
 static int ak4641_remove(struct snd_soc_codec *codec)
 {
-	struct ak4641_platform_data *pdata = codec->dev->platform_data;
-
 	ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-	if (pdata) {
-		if (gpio_is_valid(pdata->gpio_power)) {
-			gpio_set_value(pdata->gpio_power, 0);
-			gpio_free(pdata->gpio_power);
-		}
-		if (gpio_is_valid(pdata->gpio_npdn))
-			gpio_free(pdata->gpio_npdn);
-	}
 	return 0;
 }
 
@@ -604,6 +560,7 @@
 static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
+	struct ak4641_platform_data *pdata = i2c->dev.platform_data;
 	struct ak4641_priv *ak4641;
 	int ret;
 
@@ -612,16 +569,62 @@
 	if (!ak4641)
 		return -ENOMEM;
 
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			ret = gpio_request_one(pdata->gpio_power,
+					GPIOF_OUT_INIT_LOW, "ak4641 power");
+			if (ret)
+				goto err_out;
+		}
+		if (gpio_is_valid(pdata->gpio_npdn)) {
+			ret = gpio_request_one(pdata->gpio_npdn,
+					GPIOF_OUT_INIT_LOW, "ak4641 npdn");
+			if (ret)
+				goto err_gpio;
+
+			udelay(1); /* > 150 ns */
+			gpio_set_value(pdata->gpio_npdn, 1);
+		}
+	}
+
 	i2c_set_clientdata(i2c, ak4641);
 
 	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
 				ak4641_dai, ARRAY_SIZE(ak4641_dai));
+	if (ret != 0)
+		goto err_gpio2;
+
+	return 0;
+
+err_gpio2:
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power))
+			gpio_set_value(pdata->gpio_power, 0);
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+err_gpio:
+	if (pdata && gpio_is_valid(pdata->gpio_power))
+		gpio_free(pdata->gpio_power);
+err_out:
 	return ret;
 }
 
 static int __devexit ak4641_i2c_remove(struct i2c_client *i2c)
 {
+	struct ak4641_platform_data *pdata = i2c->dev.platform_data;
+
 	snd_soc_unregister_codec(&i2c->dev);
+
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			gpio_set_value(pdata->gpio_power, 0);
+			gpio_free(pdata->gpio_power);
+		}
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+
 	return 0;
 }
 
@@ -641,23 +644,7 @@
 	.id_table = ak4641_i2c_id,
 };
 
-static int __init ak4641_modinit(void)
-{
-	int ret;
-
-	ret = i2c_add_driver(&ak4641_i2c_driver);
-	if (ret != 0)
-		pr_err("Failed to register AK4641 I2C driver: %d\n", ret);
-
-	return ret;
-}
-module_init(ak4641_modinit);
-
-static void __exit ak4641_exit(void)
-{
-	i2c_del_driver(&ak4641_i2c_driver);
-}
-module_exit(ak4641_exit);
+module_i2c_driver(ak4641_i2c_driver);
 
 MODULE_DESCRIPTION("SoC AK4641 driver");
 MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>");
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index d47b62d..1960478 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -705,8 +705,7 @@
 static int alc5623_pcm_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 snd_soc_codec *codec = dai->codec;
 	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
 	int coeff, rate;
 	u16 iface;
@@ -1084,25 +1083,7 @@
 	.id_table = alc5623_i2c_table,
 };
 
-static int __init alc5623_modinit(void)
-{
-	int ret;
-
-	ret = i2c_add_driver(&alc5623_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "%s: can't add i2c driver", __func__);
-		return ret;
-	}
-
-	return ret;
-}
-module_init(alc5623_modinit);
-
-static void __exit alc5623_modexit(void)
-{
-	i2c_del_driver(&alc5623_i2c_driver);
-}
-module_exit(alc5623_modexit);
+module_i2c_driver(alc5623_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC alc5621/2/3 driver");
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index e2111e0..7dd0242 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -861,8 +861,7 @@
 static int alc5632_pcm_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 snd_soc_codec *codec = dai->codec;
 	int coeff, rate;
 	u16 iface;
 
@@ -1131,7 +1130,7 @@
 
 	i2c_set_clientdata(client, alc5632);
 
-	alc5632->regmap = regmap_init_i2c(client, &alc5632_regmap);
+	alc5632->regmap = devm_regmap_init_i2c(client, &alc5632_regmap);
 	if (IS_ERR(alc5632->regmap)) {
 		ret = PTR_ERR(alc5632->regmap);
 		dev_err(&client->dev, "regmap_init() failed: %d\n", ret);
@@ -1143,7 +1142,6 @@
 	if (ret1 != 0 || ret2 != 0) {
 		dev_err(&client->dev,
 		"Failed to read chip ID: ret1=%d, ret2=%d\n", ret1, ret2);
-		regmap_exit(alc5632->regmap);
 		return -EIO;
 	}
 
@@ -1152,14 +1150,12 @@
 	if ((vid1 != 0x10EC) || (vid2 != id->driver_data)) {
 		dev_err(&client->dev,
 		"Device is not a ALC5632: VID1=0x%x, VID2=0x%x\n", vid1, vid2);
-		regmap_exit(alc5632->regmap);
 		return -EINVAL;
 	}
 
 	ret = alc5632_reset(alc5632->regmap);
 	if (ret < 0) {
 		dev_err(&client->dev, "Failed to issue reset\n");
-		regmap_exit(alc5632->regmap);
 		return ret;
 	}
 
@@ -1177,7 +1173,6 @@
 
 	if (ret < 0) {
 		dev_err(&client->dev, "Failed to register codec: %d\n", ret);
-		regmap_exit(alc5632->regmap);
 		return ret;
 	}
 
@@ -1186,9 +1181,7 @@
 
 static __devexit int alc5632_i2c_remove(struct i2c_client *client)
 {
-	struct alc5632_priv *alc5632 = i2c_get_clientdata(client);
 	snd_soc_unregister_codec(&client->dev);
-	regmap_exit(alc5632->regmap);
 	return 0;
 }
 
@@ -1209,25 +1202,7 @@
 	.id_table = alc5632_i2c_table,
 };
 
-static int __init alc5632_modinit(void)
-{
-	int ret;
-
-	ret = i2c_add_driver(&alc5632_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "%s: can't add i2c driver", __func__);
-		return ret;
-	}
-
-	return ret;
-}
-module_init(alc5632_modinit);
-
-static void __exit alc5632_modexit(void)
-{
-	i2c_del_driver(&alc5632_i2c_driver);
-}
-module_exit(alc5632_modexit);
+module_i2c_driver(alc5632_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC ALC5632 driver");
 MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>");
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 1d672f5..047917f 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -307,8 +307,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	unsigned int i;
@@ -600,10 +599,12 @@
 static int cs4270_soc_resume(struct snd_soc_codec *codec)
 {
 	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-	int reg;
+	int reg, ret;
 
-	regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
-			      cs4270->supplies);
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+				    cs4270->supplies);
+	if (ret != 0)
+		return ret;
 
 	/* In case the device was put to hard reset during sleep, we need to
 	 * wait 500ns here before any I2C communication. */
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index bf71412..9eb01d7 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -318,8 +318,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 	int i, ret;
 	unsigned int ratio, val;
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index a8bf588..091d019 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -141,15 +141,15 @@
 static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
 	SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
 			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
-			7, 0xffffff99, 0x18, adc_pcm_tlv),
+			6, 0x19, 0x7F, adc_pcm_tlv),
 	SOC_DOUBLE_R("PCM Playback Switch",
 			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
 	SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
 			CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
-			8, 0xffffff19, 0x18, aout_tlv),
+			0, 0x34, 0xE4, aout_tlv),
 	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
 			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
-			7, 0xffffff99, 0x18, adc_pcm_tlv),
+			6, 0x19, 0x7F, adc_pcm_tlv),
 	SOC_DOUBLE_R("ADC Mixer Switch",
 			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
 	SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
@@ -356,8 +356,7 @@
 		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 snd_soc_codec *codec = dai->codec;
 	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	unsigned int i;
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
new file mode 100644
index 0000000..a710941
--- /dev/null
+++ b/sound/soc/codecs/cs42l52.c
@@ -0,0 +1,1295 @@
+/*
+ * cs42l52.c -- CS42L52 ALSA SoC audio driver
+ *
+ * Copyright 2012 CirrusLogic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ * Author: Brian Austin <brian.austin@cirrus.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/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.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 <sound/cs42l52.h>
+#include "cs42l52.h"
+
+struct sp_config {
+	u8 spc, format, spfs;
+	u32 srate;
+};
+
+struct  cs42l52_private {
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+	struct device *dev;
+	struct sp_config config;
+	struct cs42l52_platform_data pdata;
+	u32 sysclk;
+	u8 mclksel;
+	u32 mclk;
+	u8 flags;
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	struct input_dev *beep;
+	struct work_struct beep_work;
+	int beep_rate;
+#endif
+};
+
+static const struct reg_default cs42l52_reg_defaults[] = {
+	{ CS42L52_PWRCTL1, 0x9F },	/* r02 PWRCTL 1 */
+	{ CS42L52_PWRCTL2, 0x07 },	/* r03 PWRCTL 2 */
+	{ CS42L52_PWRCTL3, 0xFF },	/* r04 PWRCTL 3 */
+	{ CS42L52_CLK_CTL, 0xA0 },	/* r05 Clocking Ctl */
+	{ CS42L52_IFACE_CTL1, 0x00 },	/* r06 Interface Ctl 1 */
+	{ CS42L52_ADC_PGA_A, 0x80 },	/* r08 Input A Select */
+	{ CS42L52_ADC_PGA_B, 0x80 },	/* r09 Input B Select */
+	{ CS42L52_ANALOG_HPF_CTL, 0xA5 },	/* r0A Analog HPF Ctl */
+	{ CS42L52_ADC_HPF_FREQ, 0x00 },	/* r0B ADC HPF Corner Freq */
+	{ CS42L52_ADC_MISC_CTL, 0x00 },	/* r0C Misc. ADC Ctl */
+	{ CS42L52_PB_CTL1, 0x60 },	/* r0D Playback Ctl 1 */
+	{ CS42L52_MISC_CTL, 0x02 },	/* r0E Misc. Ctl */
+	{ CS42L52_PB_CTL2, 0x00 },	/* r0F Playback Ctl 2 */
+	{ CS42L52_MICA_CTL, 0x00 },	/* r10 MICA Amp Ctl */
+	{ CS42L52_MICB_CTL, 0x00 },	/* r11 MICB Amp Ctl */
+	{ CS42L52_PGAA_CTL, 0x00 },	/* r12 PGAA Vol, Misc. */
+	{ CS42L52_PGAB_CTL, 0x00 },	/* r13 PGAB Vol, Misc. */
+	{ CS42L52_PASSTHRUA_VOL, 0x00 },	/* r14 Bypass A Vol */
+	{ CS42L52_PASSTHRUB_VOL, 0x00 },	/* r15 Bypass B Vol */
+	{ CS42L52_ADCA_VOL, 0x00 },	/* r16 ADCA Volume */
+	{ CS42L52_ADCB_VOL, 0x00 },	/* r17 ADCB Volume */
+	{ CS42L52_ADCA_MIXER_VOL, 0x80 },	/* r18 ADCA Mixer Volume */
+	{ CS42L52_ADCB_MIXER_VOL, 0x80 },	/* r19 ADCB Mixer Volume */
+	{ CS42L52_PCMA_MIXER_VOL, 0x00 },	/* r1A PCMA Mixer Volume */
+	{ CS42L52_PCMB_MIXER_VOL, 0x00 },	/* r1B PCMB Mixer Volume */
+	{ CS42L52_BEEP_FREQ, 0x00 },	/* r1C Beep Freq on Time */
+	{ CS42L52_BEEP_VOL, 0x00 },	/* r1D Beep Volume off Time */
+	{ CS42L52_BEEP_TONE_CTL, 0x00 },	/* r1E Beep Tone Cfg. */
+	{ CS42L52_TONE_CTL, 0x00 },	/* r1F Tone Ctl */
+	{ CS42L52_MASTERA_VOL, 0x88 },	/* r20 Master A Volume */
+	{ CS42L52_MASTERB_VOL, 0x00 },	/* r21 Master B Volume */
+	{ CS42L52_HPA_VOL, 0x00 },	/* r22 Headphone A Volume */
+	{ CS42L52_HPB_VOL, 0x00 },	/* r23 Headphone B Volume */
+	{ CS42L52_SPKA_VOL, 0x00 },	/* r24 Speaker A Volume */
+	{ CS42L52_SPKB_VOL, 0x00 },	/* r25 Speaker B Volume */
+	{ CS42L52_ADC_PCM_MIXER, 0x00 },	/* r26 Channel Mixer and Swap */
+	{ CS42L52_LIMITER_CTL1, 0x00 },	/* r27 Limit Ctl 1 Thresholds */
+	{ CS42L52_LIMITER_CTL2, 0x7F },	/* r28 Limit Ctl 2 Release Rate */
+	{ CS42L52_LIMITER_AT_RATE, 0xC0 },	/* r29 Limiter Attack Rate */
+	{ CS42L52_ALC_CTL, 0x00 },	/* r2A ALC Ctl 1 Attack Rate */
+	{ CS42L52_ALC_RATE, 0x3F },	/* r2B ALC Release Rate */
+	{ CS42L52_ALC_THRESHOLD, 0x3f },	/* r2C ALC Thresholds */
+	{ CS42L52_NOISE_GATE_CTL, 0x00 },	/* r2D Noise Gate Ctl */
+	{ CS42L52_CLK_STATUS, 0x00 },	/* r2E Overflow and Clock Status */
+	{ CS42L52_BATT_COMPEN, 0x00 },	/* r2F battery Compensation */
+	{ CS42L52_BATT_LEVEL, 0x00 },	/* r30 VP Battery Level */
+	{ CS42L52_SPK_STATUS, 0x00 },	/* r31 Speaker Status */
+	{ CS42L52_TEM_CTL, 0x3B },	/* r32 Temp Ctl */
+	{ CS42L52_THE_FOLDBACK, 0x00 },	/* r33 Foldback */
+};
+
+static bool cs42l52_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L52_CHIP:
+	case CS42L52_PWRCTL1:
+	case CS42L52_PWRCTL2:
+	case CS42L52_PWRCTL3:
+	case CS42L52_CLK_CTL:
+	case CS42L52_IFACE_CTL1:
+	case CS42L52_IFACE_CTL2:
+	case CS42L52_ADC_PGA_A:
+	case CS42L52_ADC_PGA_B:
+	case CS42L52_ANALOG_HPF_CTL:
+	case CS42L52_ADC_HPF_FREQ:
+	case CS42L52_ADC_MISC_CTL:
+	case CS42L52_PB_CTL1:
+	case CS42L52_MISC_CTL:
+	case CS42L52_PB_CTL2:
+	case CS42L52_MICA_CTL:
+	case CS42L52_MICB_CTL:
+	case CS42L52_PGAA_CTL:
+	case CS42L52_PGAB_CTL:
+	case CS42L52_PASSTHRUA_VOL:
+	case CS42L52_PASSTHRUB_VOL:
+	case CS42L52_ADCA_VOL:
+	case CS42L52_ADCB_VOL:
+	case CS42L52_ADCA_MIXER_VOL:
+	case CS42L52_ADCB_MIXER_VOL:
+	case CS42L52_PCMA_MIXER_VOL:
+	case CS42L52_PCMB_MIXER_VOL:
+	case CS42L52_BEEP_FREQ:
+	case CS42L52_BEEP_VOL:
+	case CS42L52_BEEP_TONE_CTL:
+	case CS42L52_TONE_CTL:
+	case CS42L52_MASTERA_VOL:
+	case CS42L52_MASTERB_VOL:
+	case CS42L52_HPA_VOL:
+	case CS42L52_HPB_VOL:
+	case CS42L52_SPKA_VOL:
+	case CS42L52_SPKB_VOL:
+	case CS42L52_ADC_PCM_MIXER:
+	case CS42L52_LIMITER_CTL1:
+	case CS42L52_LIMITER_CTL2:
+	case CS42L52_LIMITER_AT_RATE:
+	case CS42L52_ALC_CTL:
+	case CS42L52_ALC_RATE:
+	case CS42L52_ALC_THRESHOLD:
+	case CS42L52_NOISE_GATE_CTL:
+	case CS42L52_CLK_STATUS:
+	case CS42L52_BATT_COMPEN:
+	case CS42L52_BATT_LEVEL:
+	case CS42L52_SPK_STATUS:
+	case CS42L52_TEM_CTL:
+	case CS42L52_THE_FOLDBACK:
+	case CS42L52_CHARGE_PUMP:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs42l52_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L52_IFACE_CTL2:
+	case CS42L52_CLK_STATUS:
+	case CS42L52_BATT_LEVEL:
+	case CS42L52_SPK_STATUS:
+	case CS42L52_CHARGE_PUMP:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(hl_tlv, -10200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(hpd_tlv, -9600, 50, 1);
+
+static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(mic_tlv, 1600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
+
+static const unsigned int limiter_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
+	3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),
+};
+
+static const char * const cs42l52_adca_text[] = {
+	"Input1A", "Input2A", "Input3A", "Input4A", "PGA Input Left"};
+
+static const char * const cs42l52_adcb_text[] = {
+	"Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"};
+
+static const struct soc_enum adca_enum =
+	SOC_ENUM_SINGLE(CS42L52_ADC_PGA_A, 5,
+		ARRAY_SIZE(cs42l52_adca_text), cs42l52_adca_text);
+
+static const struct soc_enum adcb_enum =
+	SOC_ENUM_SINGLE(CS42L52_ADC_PGA_B, 5,
+		ARRAY_SIZE(cs42l52_adcb_text), cs42l52_adcb_text);
+
+static const struct snd_kcontrol_new adca_mux =
+	SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum);
+
+static const struct snd_kcontrol_new adcb_mux =
+	SOC_DAPM_ENUM("Right ADC Input Capture Mux", adcb_enum);
+
+static const char * const mic_bias_level_text[] = {
+	"0.5 +VA", "0.6 +VA", "0.7 +VA",
+	"0.8 +VA", "0.83 +VA", "0.91 +VA"
+};
+
+static const struct soc_enum mic_bias_level_enum =
+	SOC_ENUM_SINGLE(CS42L52_IFACE_CTL1, 0,
+			ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text);
+
+static const char * const cs42l52_mic_text[] = { "Single", "Differential" };
+
+static const struct soc_enum mica_enum =
+	SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5,
+			ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+
+static const struct soc_enum micb_enum =
+	SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5,
+			ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+
+static const struct snd_kcontrol_new mica_mux =
+	SOC_DAPM_ENUM("Left Mic Input Capture Mux", mica_enum);
+
+static const struct snd_kcontrol_new micb_mux =
+	SOC_DAPM_ENUM("Right Mic Input Capture Mux", micb_enum);
+
+static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
+
+static const struct soc_enum digital_output_mux_enum =
+	SOC_ENUM_SINGLE(CS42L52_ADC_MISC_CTL, 6,
+			ARRAY_SIZE(digital_output_mux_text),
+			digital_output_mux_text);
+
+static const struct snd_kcontrol_new digital_output_mux =
+	SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum);
+
+static const char * const hp_gain_num_text[] = {
+	"0.3959", "0.4571", "0.5111", "0.6047",
+	"0.7099", "0.8399", "1.000", "1.1430"
+};
+
+static const struct soc_enum hp_gain_enum =
+	SOC_ENUM_SINGLE(CS42L52_PB_CTL1, 4,
+		ARRAY_SIZE(hp_gain_num_text), hp_gain_num_text);
+
+static const char * const beep_pitch_text[] = {
+	"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
+	"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
+};
+
+static const struct soc_enum beep_pitch_enum =
+	SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 4,
+			ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
+
+static const char * const beep_ontime_text[] = {
+	"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
+	"1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
+	"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
+};
+
+static const struct soc_enum beep_ontime_enum =
+	SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 0,
+			ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
+
+static const char * const beep_offtime_text[] = {
+	"1.23 s", "2.58 s", "3.90 s", "5.20 s",
+	"6.60 s", "8.05 s", "9.35 s", "10.80 s"
+};
+
+static const struct soc_enum beep_offtime_enum =
+	SOC_ENUM_SINGLE(CS42L52_BEEP_VOL, 5,
+			ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
+
+static const char * const beep_config_text[] = {
+	"Off", "Single", "Multiple", "Continuous"
+};
+
+static const struct soc_enum beep_config_enum =
+	SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 6,
+			ARRAY_SIZE(beep_config_text), beep_config_text);
+
+static const char * const beep_bass_text[] = {
+	"50 Hz", "100 Hz", "200 Hz", "250 Hz"
+};
+
+static const struct soc_enum beep_bass_enum =
+	SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 1,
+			ARRAY_SIZE(beep_bass_text), beep_bass_text);
+
+static const char * const beep_treble_text[] = {
+	"5 kHz", "7 kHz", "10 kHz", " 15 kHz"
+};
+
+static const struct soc_enum beep_treble_enum =
+	SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 3,
+			ARRAY_SIZE(beep_treble_text), beep_treble_text);
+
+static const char * const ng_threshold_text[] = {
+	"-34dB", "-37dB", "-40dB", "-43dB",
+	"-46dB", "-52dB", "-58dB", "-64dB"
+};
+
+static const struct soc_enum ng_threshold_enum =
+	SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 2,
+		ARRAY_SIZE(ng_threshold_text), ng_threshold_text);
+
+static const char * const cs42l52_ng_delay_text[] = {
+	"50ms", "100ms", "150ms", "200ms"};
+
+static const struct soc_enum ng_delay_enum =
+	SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 0,
+		ARRAY_SIZE(cs42l52_ng_delay_text), cs42l52_ng_delay_text);
+
+static const char * const cs42l52_ng_type_text[] = {
+	"Apply Specific", "Apply All"
+};
+
+static const struct soc_enum ng_type_enum =
+	SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 6,
+		ARRAY_SIZE(cs42l52_ng_type_text), cs42l52_ng_type_text);
+
+static const char * const left_swap_text[] = {
+	"Left", "LR 2", "Right"};
+
+static const char * const right_swap_text[] = {
+	"Right", "LR 2", "Left"};
+
+static const unsigned int swap_values[] = { 0, 1, 3 };
+
+static const struct soc_enum adca_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 1,
+			      ARRAY_SIZE(left_swap_text),
+			      left_swap_text,
+			      swap_values);
+
+static const struct snd_kcontrol_new adca_mixer =
+	SOC_DAPM_ENUM("Route", adca_swap_enum);
+
+static const struct soc_enum pcma_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 1,
+			      ARRAY_SIZE(left_swap_text),
+			      left_swap_text,
+			      swap_values);
+
+static const struct snd_kcontrol_new pcma_mixer =
+	SOC_DAPM_ENUM("Route", pcma_swap_enum);
+
+static const struct soc_enum adcb_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 1,
+			      ARRAY_SIZE(right_swap_text),
+			      right_swap_text,
+			      swap_values);
+
+static const struct snd_kcontrol_new adcb_mixer =
+	SOC_DAPM_ENUM("Route", adcb_swap_enum);
+
+static const struct soc_enum pcmb_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 1,
+			      ARRAY_SIZE(right_swap_text),
+			      right_swap_text,
+			      swap_values);
+
+static const struct snd_kcontrol_new pcmb_mixer =
+	SOC_DAPM_ENUM("Route", pcmb_swap_enum);
+
+
+static const struct snd_kcontrol_new passthrul_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new passthrur_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 7, 1, 0);
+
+static const struct snd_kcontrol_new spkl_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 0, 1, 1);
+
+static const struct snd_kcontrol_new spkr_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 2, 1, 1);
+
+static const struct snd_kcontrol_new hpl_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 4, 1, 1);
+
+static const struct snd_kcontrol_new hpr_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 6, 1, 1);
+
+static const struct snd_kcontrol_new cs42l52_snd_controls[] = {
+
+	SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L52_MASTERA_VOL,
+			      CS42L52_MASTERB_VOL, 0, 0x34, 0xE4, hl_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L52_HPA_VOL,
+			      CS42L52_HPB_VOL, 0, 0x34, 0xCC, hpd_tlv),
+
+	SOC_ENUM("Headphone Analog Gain", hp_gain_enum),
+
+	SOC_DOUBLE_R_SX_TLV("Speaker Volume", CS42L52_SPKA_VOL,
+			      CS42L52_SPKB_VOL, 7, 0x1, 0xff, hl_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL,
+			      CS42L52_PASSTHRUB_VOL, 6, 0x18, 0x90, pga_tlv),
+
+	SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0),
+
+	SOC_DOUBLE_R_TLV("MIC Gain Volume", CS42L52_MICA_CTL,
+			      CS42L52_MICB_CTL, 0, 0x10, 0, mic_tlv),
+
+	SOC_ENUM("MIC Bias Level", mic_bias_level_enum),
+
+	SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L52_ADCA_VOL,
+			      CS42L52_ADCB_VOL, 7, 0x80, 0xA0, ipd_tlv),
+	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
+			     CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL,
+				6, 0x7f, 0x19, ipd_tlv),
+
+	SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0),
+
+	SOC_DOUBLE_R("ADC Mixer Switch", CS42L52_ADCA_MIXER_VOL,
+		     CS42L52_ADCB_MIXER_VOL, 7, 1, 1),
+
+	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L52_PGAA_CTL,
+			    CS42L52_PGAB_CTL, 0, 0x28, 0x30, pga_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume",
+			    CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL,
+				6, 0x7f, 0x19, hl_tlv),
+	SOC_DOUBLE_R("PCM Mixer Switch",
+		     CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, 7, 1, 1),
+
+	SOC_ENUM("Beep Config", beep_config_enum),
+	SOC_ENUM("Beep Pitch", beep_pitch_enum),
+	SOC_ENUM("Beep on Time", beep_ontime_enum),
+	SOC_ENUM("Beep off Time", beep_offtime_enum),
+	SOC_SINGLE_TLV("Beep Volume", CS42L52_BEEP_VOL, 0, 0x1f, 0x07, hl_tlv),
+	SOC_SINGLE("Beep Mixer Switch", CS42L52_BEEP_TONE_CTL, 5, 1, 1),
+	SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
+	SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
+
+	SOC_SINGLE("Tone Control Switch", CS42L52_BEEP_TONE_CTL, 0, 1, 1),
+	SOC_SINGLE_TLV("Treble Gain Volume",
+			    CS42L52_TONE_CTL, 4, 15, 1, hl_tlv),
+	SOC_SINGLE_TLV("Bass Gain Volume",
+			    CS42L52_TONE_CTL, 0, 15, 1, hl_tlv),
+
+	/* Limiter */
+	SOC_SINGLE_TLV("Limiter Max Threshold Volume",
+		       CS42L52_LIMITER_CTL1, 5, 7, 0, limiter_tlv),
+	SOC_SINGLE_TLV("Limiter Cushion Threshold Volume",
+		       CS42L52_LIMITER_CTL1, 2, 7, 0, limiter_tlv),
+	SOC_SINGLE_TLV("Limiter Release Rate Volume",
+		       CS42L52_LIMITER_CTL2, 0, 63, 0, limiter_tlv),
+	SOC_SINGLE_TLV("Limiter Attack Rate Volume",
+		       CS42L52_LIMITER_AT_RATE, 0, 63, 0, limiter_tlv),
+
+	SOC_SINGLE("Limiter SR Switch", CS42L52_LIMITER_CTL1, 1, 1, 0),
+	SOC_SINGLE("Limiter ZC Switch", CS42L52_LIMITER_CTL1, 0, 1, 0),
+	SOC_SINGLE("Limiter Switch", CS42L52_LIMITER_CTL2, 7, 1, 0),
+
+	/* ALC */
+	SOC_SINGLE_TLV("ALC Attack Rate Volume", CS42L52_ALC_CTL,
+		       0, 63, 0, limiter_tlv),
+	SOC_SINGLE_TLV("ALC Release Rate Volume", CS42L52_ALC_RATE,
+		       0, 63, 0, limiter_tlv),
+	SOC_SINGLE_TLV("ALC Max Threshold Volume", CS42L52_ALC_THRESHOLD,
+		       5, 7, 0, limiter_tlv),
+	SOC_SINGLE_TLV("ALC Min Threshold Volume", CS42L52_ALC_THRESHOLD,
+		       2, 7, 0, limiter_tlv),
+
+	SOC_DOUBLE_R("ALC SR Capture Switch", CS42L52_PGAA_CTL,
+		     CS42L52_PGAB_CTL, 7, 1, 1),
+	SOC_DOUBLE_R("ALC ZC Capture Switch", CS42L52_PGAA_CTL,
+		     CS42L52_PGAB_CTL, 6, 1, 1),
+	SOC_DOUBLE("ALC Capture Switch", CS42L52_ALC_CTL, 6, 7, 1, 0),
+
+	/* Noise gate */
+	SOC_ENUM("NG Type Switch", ng_type_enum),
+	SOC_SINGLE("NG Enable Switch", CS42L52_NOISE_GATE_CTL, 6, 1, 0),
+	SOC_SINGLE("NG Boost Switch", CS42L52_NOISE_GATE_CTL, 5, 1, 1),
+	SOC_ENUM("NG Threshold", ng_threshold_enum),
+	SOC_ENUM("NG Delay", ng_delay_enum),
+
+	SOC_DOUBLE("HPF Switch", CS42L52_ANALOG_HPF_CTL, 5, 7, 1, 0),
+
+	SOC_DOUBLE("Analog SR Switch", CS42L52_ANALOG_HPF_CTL, 1, 3, 1, 1),
+	SOC_DOUBLE("Analog ZC Switch", CS42L52_ANALOG_HPF_CTL, 0, 2, 1, 1),
+	SOC_SINGLE("Digital SR Switch", CS42L52_MISC_CTL, 1, 1, 0),
+	SOC_SINGLE("Digital ZC Switch", CS42L52_MISC_CTL, 0, 1, 0),
+	SOC_SINGLE("Deemphasis Switch", CS42L52_MISC_CTL, 2, 1, 0),
+
+	SOC_SINGLE("Batt Compensation Switch", CS42L52_BATT_COMPEN, 7, 1, 0),
+	SOC_SINGLE("Batt VP Monitor Switch", CS42L52_BATT_COMPEN, 6, 1, 0),
+	SOC_SINGLE("Batt VP ref", CS42L52_BATT_COMPEN, 0, 0x0f, 0),
+
+	SOC_SINGLE("PGA AIN1L Switch", CS42L52_ADC_PGA_A, 0, 1, 0),
+	SOC_SINGLE("PGA AIN1R Switch", CS42L52_ADC_PGA_B, 0, 1, 0),
+	SOC_SINGLE("PGA AIN2L Switch", CS42L52_ADC_PGA_A, 1, 1, 0),
+	SOC_SINGLE("PGA AIN2R Switch", CS42L52_ADC_PGA_B, 1, 1, 0),
+
+	SOC_SINGLE("PGA AIN3L Switch", CS42L52_ADC_PGA_A, 2, 1, 0),
+	SOC_SINGLE("PGA AIN3R Switch", CS42L52_ADC_PGA_B, 2, 1, 0),
+
+	SOC_SINGLE("PGA AIN4L Switch", CS42L52_ADC_PGA_A, 3, 1, 0),
+	SOC_SINGLE("PGA AIN4R Switch", CS42L52_ADC_PGA_B, 3, 1, 0),
+
+	SOC_SINGLE("PGA MICA Switch", CS42L52_ADC_PGA_A, 4, 1, 0),
+	SOC_SINGLE("PGA MICB Switch", CS42L52_ADC_PGA_B, 4, 1, 0),
+
+};
+
+static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
+
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+	SND_SOC_DAPM_INPUT("AIN3L"),
+	SND_SOC_DAPM_INPUT("AIN3R"),
+	SND_SOC_DAPM_INPUT("AIN4L"),
+	SND_SOC_DAPM_INPUT("AIN4R"),
+	SND_SOC_DAPM_INPUT("MICA"),
+	SND_SOC_DAPM_INPUT("MICB"),
+	SND_SOC_DAPM_SIGGEN("Beep"),
+
+	SND_SOC_DAPM_AIF_OUT("AIFOUTL", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("MICA Mux", SND_SOC_NOPM, 0, 0, &mica_mux),
+	SND_SOC_DAPM_MUX("MICB Mux", SND_SOC_NOPM, 0, 0, &micb_mux),
+
+	SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1),
+	SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1),
+	SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA Right", CS42L52_PWRCTL1, 4, 1, NULL, 0),
+
+	SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adca_mux),
+	SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcb_mux),
+
+	SND_SOC_DAPM_MUX("ADC Left Swap", SND_SOC_NOPM,
+			 0, 0, &adca_mixer),
+	SND_SOC_DAPM_MUX("ADC Right Swap", SND_SOC_NOPM,
+			 0, 0, &adcb_mixer),
+
+	SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM,
+			 0, 0, &digital_output_mux),
+
+	SND_SOC_DAPM_PGA("PGA MICA", CS42L52_PWRCTL2, 1, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA MICB", CS42L52_PWRCTL2, 2, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", CS42L52_PWRCTL2, 0, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L52_PWRCTL1, 7, 1, NULL, 0),
+
+	SND_SOC_DAPM_AIF_IN("AIFINL", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIFINR", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_DAC("DAC Left", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC Right", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SWITCH("Bypass Left", CS42L52_MISC_CTL,
+			    6, 0, &passthrul_ctl),
+	SND_SOC_DAPM_SWITCH("Bypass Right", CS42L52_MISC_CTL,
+			    7, 0, &passthrur_ctl),
+
+	SND_SOC_DAPM_MUX("PCM Left Swap", SND_SOC_NOPM,
+			 0, 0, &pcma_mixer),
+	SND_SOC_DAPM_MUX("PCM Right Swap", SND_SOC_NOPM,
+			 0, 0, &pcmb_mixer),
+
+	SND_SOC_DAPM_SWITCH("HP Left Amp", SND_SOC_NOPM, 0, 0, &hpl_ctl),
+	SND_SOC_DAPM_SWITCH("HP Right Amp", SND_SOC_NOPM, 0, 0, &hpr_ctl),
+
+	SND_SOC_DAPM_SWITCH("SPK Left Amp", SND_SOC_NOPM, 0, 0, &spkl_ctl),
+	SND_SOC_DAPM_SWITCH("SPK Right Amp", SND_SOC_NOPM, 0, 0, &spkr_ctl),
+
+	SND_SOC_DAPM_OUTPUT("HPOUTA"),
+	SND_SOC_DAPM_OUTPUT("HPOUTB"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTA"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTB"),
+
+};
+
+static const struct snd_soc_dapm_route cs42l52_audio_map[] = {
+
+	{"Capture", NULL, "AIFOUTL"},
+	{"Capture", NULL, "AIFOUTL"},
+
+	{"AIFOUTL", NULL, "Output Mux"},
+	{"AIFOUTR", NULL, "Output Mux"},
+
+	{"Output Mux", "ADC", "ADC Left"},
+	{"Output Mux", "ADC", "ADC Right"},
+
+	{"ADC Left", NULL, "Charge Pump"},
+	{"ADC Right", NULL, "Charge Pump"},
+
+	{"Charge Pump", NULL, "ADC Left Mux"},
+	{"Charge Pump", NULL, "ADC Right Mux"},
+
+	{"ADC Left Mux", "Input1A", "AIN1L"},
+	{"ADC Right Mux", "Input1B", "AIN1R"},
+	{"ADC Left Mux", "Input2A", "AIN2L"},
+	{"ADC Right Mux", "Input2B", "AIN2R"},
+	{"ADC Left Mux", "Input3A", "AIN3L"},
+	{"ADC Right Mux", "Input3B", "AIN3R"},
+	{"ADC Left Mux", "Input4A", "AIN4L"},
+	{"ADC Right Mux", "Input4B", "AIN4R"},
+	{"ADC Left Mux", "PGA Input Left", "PGA Left"},
+	{"ADC Right Mux", "PGA Input Right" , "PGA Right"},
+
+	{"PGA Left", "Switch", "AIN1L"},
+	{"PGA Right", "Switch", "AIN1R"},
+	{"PGA Left", "Switch", "AIN2L"},
+	{"PGA Right", "Switch", "AIN2R"},
+	{"PGA Left", "Switch", "AIN3L"},
+	{"PGA Right", "Switch", "AIN3R"},
+	{"PGA Left", "Switch", "AIN4L"},
+	{"PGA Right", "Switch", "AIN4R"},
+
+	{"PGA Left", "Switch", "PGA MICA"},
+	{"PGA MICA", NULL, "MICA"},
+
+	{"PGA Right", "Switch", "PGA MICB"},
+	{"PGA MICB", NULL, "MICB"},
+
+	{"HPOUTA", NULL, "HP Left Amp"},
+	{"HPOUTB", NULL, "HP Right Amp"},
+	{"HP Left Amp", NULL, "Bypass Left"},
+	{"HP Right Amp", NULL, "Bypass Right"},
+	{"Bypass Left", "Switch", "PGA Left"},
+	{"Bypass Right", "Switch", "PGA Right"},
+	{"HP Left Amp", "Switch", "DAC Left"},
+	{"HP Right Amp", "Switch", "DAC Right"},
+
+	{"SPKOUTA", NULL, "SPK Left Amp"},
+	{"SPKOUTB", NULL, "SPK Right Amp"},
+
+	{"SPK Left Amp", NULL, "Beep"},
+	{"SPK Right Amp", NULL, "Beep"},
+	{"SPK Left Amp", "Switch", "Playback"},
+	{"SPK Right Amp", "Switch", "Playback"},
+
+	{"DAC Left", NULL, "Beep"},
+	{"DAC Right", NULL, "Beep"},
+	{"DAC Left", NULL, "Playback"},
+	{"DAC Right", NULL, "Playback"},
+
+	{"Output Mux", "DSP", "Playback"},
+	{"Output Mux", "DSP", "Playback"},
+
+	{"AIFINL", NULL, "Playback"},
+	{"AIFINR", NULL, "Playback"},
+
+};
+
+struct cs42l52_clk_para {
+	u32 mclk;
+	u32 rate;
+	u8 speed;
+	u8 group;
+	u8 videoclk;
+	u8 ratio;
+	u8 mclkdiv2;
+};
+
+static const struct cs42l52_clk_para clk_map_table[] = {
+	/*8k*/
+	{12288000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+	{27000000, 8000, CLK_QS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
+
+	/*11.025k*/
+	{11289600, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{16934400, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+	/*16k*/
+	{12288000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+	{27000000, 16000, CLK_HS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 1},
+
+	/*22.05k*/
+	{11289600, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{16934400, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+	/* 32k */
+	{12288000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+	{27000000, 32000, CLK_SS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
+
+	/* 44.1k */
+	{11289600, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{16934400, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+	/* 48k */
+	{12288000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
+	{27000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_27M_MCLK, CLK_R_125, 1},
+
+	/* 88.2k */
+	{11289600, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{16934400, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+	/* 96k */
+	{12288000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
+};
+
+static int cs42l52_get_clk(int mclk, int rate)
+{
+	int i, ret = 0;
+	u_int mclk1, mclk2 = 0;
+
+	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
+		if (clk_map_table[i].rate == rate) {
+			mclk1 = clk_map_table[i].mclk;
+			if (abs(mclk - mclk1) < abs(mclk - mclk2)) {
+				mclk2 = mclk1;
+				ret = i;
+			}
+		}
+	}
+	if (ret > ARRAY_SIZE(clk_map_table))
+		return -EINVAL;
+	return ret;
+}
+
+static int cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
+			int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+	if ((freq >= CS42L52_MIN_CLK) && (freq <= CS42L52_MAX_CLK)) {
+		cs42l52->sysclk = freq;
+	} else {
+		dev_err(codec->dev, "Invalid freq paramter\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+	u8 iface = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = CS42L52_IFACE_CTL1_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		iface = CS42L52_IFACE_CTL1_SLAVE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	 /* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= CS42L52_IFACE_CTL1_ADC_FMT_I2S |
+				CS42L52_IFACE_CTL1_DAC_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface |= CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J |
+				CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= CS42L52_IFACE_CTL1_DSP_MODE_EN;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= CS42L52_IFACE_CTL1_INV_SCLK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= CS42L52_IFACE_CTL1_INV_SCLK;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	cs42l52->config.format = iface;
+	snd_soc_write(codec, CS42L52_IFACE_CTL1, cs42l52->config.format);
+
+	return 0;
+}
+
+static int cs42l52_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	if (mute)
+		snd_soc_update_bits(codec, CS42L52_PB_CTL1,
+				    CS42L52_PB_CTL1_MUTE_MASK,
+				CS42L52_PB_CTL1_MUTE);
+	else
+		snd_soc_update_bits(codec, CS42L52_PB_CTL1,
+				    CS42L52_PB_CTL1_MUTE_MASK,
+				CS42L52_PB_CTL1_UNMUTE);
+
+	return 0;
+}
+
+static int cs42l52_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;
+	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	u32 clk = 0;
+	int index;
+
+	index = cs42l52_get_clk(cs42l52->sysclk, params_rate(params));
+	if (index >= 0) {
+		cs42l52->sysclk = clk_map_table[index].mclk;
+
+		clk |= (clk_map_table[index].speed << CLK_SPEED_SHIFT) |
+		(clk_map_table[index].group << CLK_32K_SR_SHIFT) |
+		(clk_map_table[index].videoclk << CLK_27M_MCLK_SHIFT) |
+		(clk_map_table[index].ratio << CLK_RATIO_SHIFT) |
+		clk_map_table[index].mclkdiv2;
+
+		snd_soc_write(codec, CS42L52_CLK_CTL, clk);
+	} else {
+		dev_err(codec->dev, "can't get correct mclk\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
+					enum snd_soc_bias_level level)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_update_bits(codec, CS42L52_PWRCTL1,
+				    CS42L52_PWRCTL1_PDN_CODEC, 0);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			regcache_cache_only(cs42l52->regmap, false);
+			regcache_sync(cs42l52->regmap);
+		}
+		snd_soc_write(codec, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_write(codec, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+		regcache_cache_only(cs42l52->regmap, true);
+		break;
+	}
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+#define CS42L52_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define CS42L52_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+			SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
+
+static struct snd_soc_dai_ops cs42l52_ops = {
+	.hw_params	= cs42l52_pcm_hw_params,
+	.digital_mute	= cs42l52_digital_mute,
+	.set_fmt	= cs42l52_set_fmt,
+	.set_sysclk	= cs42l52_set_sysclk,
+};
+
+static struct snd_soc_dai_driver cs42l52_dai = {
+		.name = "cs42l52",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS42L52_RATES,
+			.formats = CS42L52_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS42L52_RATES,
+			.formats = CS42L52_FORMATS,
+		},
+		.ops = &cs42l52_ops,
+};
+
+static int cs42l52_suspend(struct snd_soc_codec *codec)
+{
+	cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int cs42l52_resume(struct snd_soc_codec *codec)
+{
+	cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static int beep_rates[] = {
+	261, 522, 585, 667, 706, 774, 889, 1000,
+	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
+};
+
+static void cs42l52_beep_work(struct work_struct *work)
+{
+	struct cs42l52_private *cs42l52 =
+		container_of(work, struct cs42l52_private, beep_work);
+	struct snd_soc_codec *codec = cs42l52->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int i;
+	int val = 0;
+	int best = 0;
+
+	if (cs42l52->beep_rate) {
+		for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
+			if (abs(cs42l52->beep_rate - beep_rates[i]) <
+			    abs(cs42l52->beep_rate - beep_rates[best]))
+				best = i;
+		}
+
+		dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+			beep_rates[best], cs42l52->beep_rate);
+
+		val = (best << CS42L52_BEEP_RATE_SHIFT);
+
+		snd_soc_dapm_enable_pin(dapm, "Beep");
+	} else {
+		dev_dbg(codec->dev, "Disabling beep\n");
+		snd_soc_dapm_disable_pin(dapm, "Beep");
+	}
+
+	snd_soc_update_bits(codec, CS42L52_BEEP_FREQ,
+			    CS42L52_BEEP_RATE_MASK, val);
+
+	snd_soc_dapm_sync(dapm);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int cs42l52_beep_event(struct input_dev *dev, unsigned int type,
+			     unsigned int code, int hz)
+{
+	struct snd_soc_codec *codec = input_get_drvdata(dev);
+	struct cs42l52_private *cs42l52 = 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 = 261;
+	case SND_TONE:
+		break;
+	default:
+		return -1;
+	}
+
+	/* Kick the beep from a workqueue */
+	cs42l52->beep_rate = hz;
+	schedule_work(&cs42l52->beep_work);
+	return 0;
+}
+
+static ssize_t cs42l52_beep_set(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct cs42l52_private *cs42l52 = dev_get_drvdata(dev);
+	long int time;
+	int ret;
+
+	ret = kstrtol(buf, 10, &time);
+	if (ret != 0)
+		return ret;
+
+	input_event(cs42l52->beep, EV_SND, SND_TONE, time);
+
+	return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, cs42l52_beep_set);
+
+static void cs42l52_init_beep(struct snd_soc_codec *codec)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	cs42l52->beep = input_allocate_device();
+	if (!cs42l52->beep) {
+		dev_err(codec->dev, "Failed to allocate beep device\n");
+		return;
+	}
+
+	INIT_WORK(&cs42l52->beep_work, cs42l52_beep_work);
+	cs42l52->beep_rate = 0;
+
+	cs42l52->beep->name = "CS42L52 Beep Generator";
+	cs42l52->beep->phys = dev_name(codec->dev);
+	cs42l52->beep->id.bustype = BUS_I2C;
+
+	cs42l52->beep->evbit[0] = BIT_MASK(EV_SND);
+	cs42l52->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+	cs42l52->beep->event = cs42l52_beep_event;
+	cs42l52->beep->dev.parent = codec->dev;
+	input_set_drvdata(cs42l52->beep, codec);
+
+	ret = input_register_device(cs42l52->beep);
+	if (ret != 0) {
+		input_free_device(cs42l52->beep);
+		cs42l52->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 cs42l52_free_beep(struct snd_soc_codec *codec)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+	device_remove_file(codec->dev, &dev_attr_beep);
+	input_unregister_device(cs42l52->beep);
+	cancel_work_sync(&cs42l52->beep_work);
+	cs42l52->beep = NULL;
+
+	snd_soc_update_bits(codec, CS42L52_BEEP_TONE_CTL,
+			    CS42L52_BEEP_EN_MASK, 0);
+}
+#else
+static void cs42l52_init_beep(struct snd_soc_codec *codec)
+{
+}
+
+static void cs42l52_free_beep(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static int cs42l52_probe(struct snd_soc_codec *codec)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	codec->control_data = cs42l52->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+	regcache_cache_only(cs42l52->regmap, true);
+
+	cs42l52_init_beep(codec);
+
+	cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	cs42l52->sysclk = CS42L52_DEFAULT_CLK;
+	cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
+
+	/* Set Platform MICx CFG */
+	snd_soc_update_bits(codec, CS42L52_MICA_CTL,
+			    CS42L52_MIC_CTL_TYPE_MASK,
+				cs42l52->pdata.mica_cfg <<
+				CS42L52_MIC_CTL_TYPE_SHIFT);
+
+	snd_soc_update_bits(codec, CS42L52_MICB_CTL,
+			    CS42L52_MIC_CTL_TYPE_MASK,
+				cs42l52->pdata.micb_cfg <<
+				CS42L52_MIC_CTL_TYPE_SHIFT);
+
+	/* if Single Ended, Get Mic_Select */
+	if (cs42l52->pdata.mica_cfg)
+		snd_soc_update_bits(codec, CS42L52_MICA_CTL,
+				    CS42L52_MIC_CTL_MIC_SEL_MASK,
+				cs42l52->pdata.mica_sel <<
+				CS42L52_MIC_CTL_MIC_SEL_SHIFT);
+	if (cs42l52->pdata.micb_cfg)
+		snd_soc_update_bits(codec, CS42L52_MICB_CTL,
+				    CS42L52_MIC_CTL_MIC_SEL_MASK,
+				cs42l52->pdata.micb_sel <<
+				CS42L52_MIC_CTL_MIC_SEL_SHIFT);
+
+	/* Set Platform Charge Pump Freq */
+	snd_soc_update_bits(codec, CS42L52_CHARGE_PUMP,
+			    CS42L52_CHARGE_PUMP_MASK,
+				cs42l52->pdata.chgfreq <<
+				CS42L52_CHARGE_PUMP_SHIFT);
+
+	/* Set Platform Bias Level */
+	snd_soc_update_bits(codec, CS42L52_IFACE_CTL2,
+			    CS42L52_IFACE_CTL2_BIAS_LVL,
+				cs42l52->pdata.micbias_lvl);
+
+	return ret;
+}
+
+static int cs42l52_remove(struct snd_soc_codec *codec)
+{
+	cs42l52_free_beep(codec);
+	cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
+	.probe = cs42l52_probe,
+	.remove = cs42l52_remove,
+	.suspend = cs42l52_suspend,
+	.resume = cs42l52_resume,
+	.set_bias_level = cs42l52_set_bias_level,
+
+	.dapm_widgets = cs42l52_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets),
+	.dapm_routes = cs42l52_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(cs42l52_audio_map),
+
+	.controls = cs42l52_snd_controls,
+	.num_controls = ARRAY_SIZE(cs42l52_snd_controls),
+};
+
+/* Current and threshold powerup sequence Pg37 */
+static const struct reg_default cs42l52_threshold_patch[] = {
+
+	{ 0x00, 0x99 },
+	{ 0x3E, 0xBA },
+	{ 0x47, 0x80 },
+	{ 0x32, 0xBB },
+	{ 0x32, 0x3B },
+	{ 0x00, 0x00 },
+
+};
+
+static struct regmap_config cs42l52_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS42L52_MAX_REGISTER,
+	.reg_defaults = cs42l52_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs42l52_reg_defaults),
+	.readable_reg = cs42l52_readable_register,
+	.volatile_reg = cs42l52_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
+			     const struct i2c_device_id *id)
+{
+	struct cs42l52_private *cs42l52;
+	int ret;
+	unsigned int devid = 0;
+	unsigned int reg;
+
+	cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private),
+			       GFP_KERNEL);
+	if (cs42l52 == NULL)
+		return -ENOMEM;
+	cs42l52->dev = &i2c_client->dev;
+
+	cs42l52->regmap = regmap_init_i2c(i2c_client, &cs42l52_regmap);
+	if (IS_ERR(cs42l52->regmap)) {
+		ret = PTR_ERR(cs42l52->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		goto err;
+	}
+
+	i2c_set_clientdata(i2c_client, cs42l52);
+
+	if (dev_get_platdata(&i2c_client->dev))
+		memcpy(&cs42l52->pdata, dev_get_platdata(&i2c_client->dev),
+		       sizeof(cs42l52->pdata));
+
+	ret = regmap_register_patch(cs42l52->regmap, cs42l52_threshold_patch,
+				    ARRAY_SIZE(cs42l52_threshold_patch));
+	if (ret != 0)
+		dev_warn(cs42l52->dev, "Failed to apply regmap patch: %d\n",
+			 ret);
+
+	ret = regmap_read(cs42l52->regmap, CS42L52_CHIP, &reg);
+	devid = reg & CS42L52_CHIP_ID_MASK;
+	if (devid != CS42L52_CHIP_ID) {
+		ret = -ENODEV;
+		dev_err(&i2c_client->dev,
+			"CS42L52 Device ID (%X). Expected %X\n",
+			devid, CS42L52_CHIP_ID);
+		goto err_regmap;
+	}
+
+	regcache_cache_only(cs42l52->regmap, true);
+
+	ret =  snd_soc_register_codec(&i2c_client->dev,
+			&soc_codec_dev_cs42l52, &cs42l52_dai, 1);
+	if (ret < 0)
+		goto err_regmap;
+	return 0;
+
+err_regmap:
+	regmap_exit(cs42l52->regmap);
+
+err:
+	return ret;
+}
+
+static int cs42l52_i2c_remove(struct i2c_client *client)
+{
+	struct cs42l52_private *cs42l52 = i2c_get_clientdata(client);
+
+	snd_soc_unregister_codec(&client->dev);
+	regmap_exit(cs42l52->regmap);
+
+	return 0;
+}
+
+static const struct i2c_device_id cs42l52_id[] = {
+	{ "cs42l52", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs42l52_id);
+
+static struct i2c_driver cs42l52_i2c_driver = {
+	.driver = {
+		.name = "cs42l52",
+		.owner = THIS_MODULE,
+	},
+	.id_table = cs42l52_id,
+	.probe =    cs42l52_i2c_probe,
+	.remove =   __devexit_p(cs42l52_i2c_remove),
+};
+
+module_i2c_driver(cs42l52_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L52 driver");
+MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l52.h b/sound/soc/codecs/cs42l52.h
new file mode 100644
index 0000000..60985c0
--- /dev/null
+++ b/sound/soc/codecs/cs42l52.h
@@ -0,0 +1,274 @@
+/*
+ * cs42l52.h -- CS42L52 ALSA SoC audio driver
+ *
+ * Copyright 2012 CirrusLogic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ * Author: Brian Austin <brian.austin@cirrus.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 __CS42L52_H__
+#define __CS42L52_H__
+
+#define CS42L52_NAME				"CS42L52"
+#define CS42L52_DEFAULT_CLK			12000000
+#define CS42L52_MIN_CLK				11000000
+#define CS42L52_MAX_CLK				27000000
+#define CS42L52_DEFAULT_FORMAT			SNDRV_PCM_FMTBIT_S16_LE
+#define CS42L52_DEFAULT_MAX_CHANS		2
+#define CS42L52_SYSCLK				1
+
+#define CS42L52_CHIP_SWICTH			(1 << 17)
+#define CS42L52_ALL_IN_ONE			(1 << 16)
+#define CS42L52_CHIP_ONE			0x00
+#define CS42L52_CHIP_TWO			0x01
+#define CS42L52_CHIP_THR			0x02
+#define CS42L52_CHIP_MASK			0x0f
+
+#define CS42L52_FIX_BITS_CTL			0x00
+#define CS42L52_CHIP				0x01
+#define CS42L52_CHIP_ID				0xE0
+#define CS42L52_CHIP_ID_MASK			0xF8
+#define CS42L52_CHIP_REV_A0			0x00
+#define CS42L52_CHIP_REV_A1			0x01
+#define CS42L52_CHIP_REV_B0			0x02
+#define CS42L52_CHIP_REV_MASK			0x03
+
+#define CS42L52_PWRCTL1				0x02
+#define CS42L52_PWRCTL1_PDN_ALL			0x9F
+#define CS42L52_PWRCTL1_PDN_CHRG		0x80
+#define CS42L52_PWRCTL1_PDN_PGAB		0x10
+#define CS42L52_PWRCTL1_PDN_PGAA		0x08
+#define CS42L52_PWRCTL1_PDN_ADCB		0x04
+#define CS42L52_PWRCTL1_PDN_ADCA		0x02
+#define CS42L52_PWRCTL1_PDN_CODEC		0x01
+
+#define CS42L52_PWRCTL2				0x03
+#define CS42L52_PWRCTL2_OVRDB			(1 << 4)
+#define CS42L52_PWRCTL2_OVRDA			(1 << 3)
+#define	CS42L52_PWRCTL2_PDN_MICB		(1 << 2)
+#define CS42L52_PWRCTL2_PDN_MICB_SHIFT		2
+#define CS42L52_PWRCTL2_PDN_MICA		(1 << 1)
+#define CS42L52_PWRCTL2_PDN_MICA_SHIFT		1
+#define CS42L52_PWRCTL2_PDN_MICBIAS		(1 << 0)
+#define CS42L52_PWRCTL2_PDN_MICBIAS_SHIFT	0
+
+#define CS42L52_PWRCTL3				0x04
+#define CS42L52_PWRCTL3_HPB_PDN_SHIFT		6
+#define CS42L52_PWRCTL3_HPB_ON_LOW		0x00
+#define CS42L52_PWRCTL3_HPB_ON_HIGH		0x01
+#define CS42L52_PWRCTL3_HPB_ALWAYS_ON		0x02
+#define CS42L52_PWRCTL3_HPB_ALWAYS_OFF		0x03
+#define CS42L52_PWRCTL3_HPA_PDN_SHIFT		4
+#define CS42L52_PWRCTL3_HPA_ON_LOW		0x00
+#define CS42L52_PWRCTL3_HPA_ON_HIGH		0x01
+#define CS42L52_PWRCTL3_HPA_ALWAYS_ON		0x02
+#define CS42L52_PWRCTL3_HPA_ALWAYS_OFF		0x03
+#define CS42L52_PWRCTL3_SPKB_PDN_SHIFT		2
+#define CS42L52_PWRCTL3_SPKB_ON_LOW		0x00
+#define CS42L52_PWRCTL3_SPKB_ON_HIGH		0x01
+#define CS42L52_PWRCTL3_SPKB_ALWAYS_ON		0x02
+#define CS42L52_PWRCTL3_PDN_SPKB		(1 << 2)
+#define CS42L52_PWRCTL3_PDN_SPKA		(1 << 0)
+#define CS42L52_PWRCTL3_SPKA_PDN_SHIFT		0
+#define CS42L52_PWRCTL3_SPKA_ON_LOW		0x00
+#define CS42L52_PWRCTL3_SPKA_ON_HIGH		0x01
+#define CS42L52_PWRCTL3_SPKA_ALWAYS_ON		0x02
+
+#define CS42L52_DEFAULT_OUTPUT_STATE		0x05
+#define CS42L52_PWRCTL3_CONF_MASK		0x03
+
+#define CS42L52_CLK_CTL				0x05
+#define CLK_AUTODECT_ENABLE			(1 << 7)
+#define CLK_SPEED_SHIFT				5
+#define CLK_DS_MODE				0x00
+#define CLK_SS_MODE				0x01
+#define CLK_HS_MODE				0x02
+#define CLK_QS_MODE				0x03
+#define CLK_32K_SR_SHIFT			4
+#define CLK_32K					0x01
+#define CLK_NO_32K				0x00
+#define CLK_27M_MCLK_SHIFT			3
+#define CLK_27M_MCLK				0x01
+#define CLK_NO_27M				0x00
+#define CLK_RATIO_SHIFT				1
+#define CLK_R_128				0x00
+#define CLK_R_125				0x01
+#define CLK_R_132				0x02
+#define CLK_R_136				0x03
+
+#define CS42L52_IFACE_CTL1			0x06
+#define CS42L52_IFACE_CTL1_MASTER		(1 << 7)
+#define CS42L52_IFACE_CTL1_SLAVE		(0 << 7)
+#define CS42L52_IFACE_CTL1_INV_SCLK		(1 << 6)
+#define CS42L52_IFACE_CTL1_ADC_FMT_I2S		(1 << 5)
+#define CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J	(0 << 5)
+#define CS42L52_IFACE_CTL1_DSP_MODE_EN		(1 << 4)
+#define CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J	(0 << 2)
+#define CS42L52_IFACE_CTL1_DAC_FMT_I2S		(1 << 2)
+#define CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J	(2 << 2)
+#define CS42L52_IFACE_CTL1_WL_32BIT		(0x00)
+#define CS42L52_IFACE_CTL1_WL_24BIT		(0x01)
+#define CS42L52_IFACE_CTL1_WL_20BIT		(0x02)
+#define CS42L52_IFACE_CTL1_WL_16BIT		(0x03)
+#define CS42L52_IFACE_CTL1_WL_MASK		0xFFFF
+
+#define CS42L52_IFACE_CTL2			0x07
+#define CS42L52_IFACE_CTL2_SC_MC_EQ		(1 << 6)
+#define CS42L52_IFACE_CTL2_LOOPBACK		(1 << 5)
+#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_EN	(0 << 4)
+#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_HIZ	(1 << 4)
+#define CS42L52_IFACE_CTL2_HP_SW_INV		(1 << 3)
+#define CS42L52_IFACE_CTL2_BIAS_LVL		0x07
+
+#define CS42L52_ADC_PGA_A			0x08
+#define CS42L52_ADC_PGA_B			0x09
+#define CS42L52_ADC_SEL_SHIFT			5
+#define CS42L52_ADC_SEL_AIN1			0x00
+#define CS42L52_ADC_SEL_AIN2			0x01
+#define CS42L52_ADC_SEL_AIN3			0x02
+#define CS42L52_ADC_SEL_AIN4			0x03
+#define CS42L52_ADC_SEL_PGA			0x04
+
+#define CS42L52_ANALOG_HPF_CTL			0x0A
+#define CS42L52_HPF_CTL_ANLGSFTB		(1 << 3)
+#define CS42L52_HPF_CTL_ANLGSFTA                (1 << 0)
+
+#define CS42L52_ADC_HPF_FREQ			0x0B
+#define CS42L52_ADC_MISC_CTL			0x0C
+#define CS42L52_ADC_MISC_CTL_SOURCE_DSP		(1 << 6)
+
+#define CS42L52_PB_CTL1				0x0D
+#define CS42L52_PB_CTL1_HP_GAIN_SHIFT		5
+#define CS42L52_PB_CTL1_HP_GAIN_03959		0x00
+#define CS42L52_PB_CTL1_HP_GAIN_04571		0x01
+#define CS42L52_PB_CTL1_HP_GAIN_05111		0x02
+#define CS42L52_PB_CTL1_HP_GAIN_06047		0x03
+#define CS42L52_PB_CTL1_HP_GAIN_07099		0x04
+#define CS42L52_PB_CTL1_HP_GAIN_08399		0x05
+#define CS42L52_PB_CTL1_HP_GAIN_10000		0x06
+#define CS42L52_PB_CTL1_HP_GAIN_11430		0x07
+#define CS42L52_PB_CTL1_INV_PCMB		(1 << 3)
+#define CS42L52_PB_CTL1_INV_PCMA		(1 << 2)
+#define CS42L52_PB_CTL1_MSTB_MUTE		(1 << 1)
+#define CS42L52_PB_CTL1_MSTA_MUTE		(1 << 0)
+#define CS42L52_PB_CTL1_MUTE_MASK		0xFFFD
+#define CS42L52_PB_CTL1_MUTE			3
+#define CS42L52_PB_CTL1_UNMUTE			0
+
+#define CS42L52_MISC_CTL			0x0E
+#define CS42L52_MISC_CTL_DEEMPH			(1 << 2)
+#define CS42L52_MISC_CTL_DIGSFT			(1 << 1)
+#define CS42L52_MISC_CTL_DIGZC			(1 << 0)
+
+#define CS42L52_PB_CTL2				0x0F
+#define CS42L52_PB_CTL2_HPB_MUTE		(1 << 7)
+#define CS42L52_PB_CTL2_HPA_MUTE		(1 << 6)
+#define CS42L52_PB_CTL2_SPKB_MUTE		(1 << 5)
+#define CS42L52_PB_CTL2_SPKA_MUTE		(1 << 4)
+#define CS42L52_PB_CTL2_SPK_SWAP		(1 << 2)
+#define CS42L52_PB_CTL2_SPK_MONO		(1 << 1)
+#define CS42L52_PB_CTL2_SPK_MUTE50		(1 << 0)
+
+#define	CS42L52_MICA_CTL			0x10
+#define CS42L52_MICB_CTL			0x11
+#define	CS42L52_MIC_CTL_MIC_SEL_MASK		0xBF
+#define	CS42L52_MIC_CTL_MIC_SEL_SHIFT		6
+#define CS42L52_MIC_CTL_TYPE_MASK		0xDF
+#define CS42L52_MIC_CTL_TYPE_SHIFT		5
+
+
+#define CS42L52_PGAA_CTL			0x12
+#define CS42L52_PGAB_CTL			0x13
+#define CS42L52_PGAX_CTL_VOL_12DB		24
+#define CS42L52_PGAX_CTL_VOL_6DB		12 /*step size 0.5db*/
+
+#define CS42L52_PASSTHRUA_VOL			0x14
+#define CS42L52_PASSTHRUB_VOL			0x15
+
+#define CS42L52_ADCA_VOL			0x16
+#define CS42L52_ADCB_VOL			0x17
+#define CS42L52_ADCX_VOL_24DB			24 /*step size 1db*/
+#define CS42L52_ADCX_VOL_12DB			12
+#define CS42L52_ADCX_VOL_6DB			6
+
+#define CS42L52_ADCA_MIXER_VOL			0x18
+#define CS42L52_ADCB_MIXER_VOL			0x19
+#define CS42L52_ADC_MIXER_VOL_12DB		0x18
+
+#define CS42L52_PCMA_MIXER_VOL			0x1A
+#define CS42L52_PCMB_MIXER_VOL			0x1B
+
+#define CS42L52_BEEP_FREQ			0x1C
+#define CS42L52_BEEP_VOL			0x1D
+#define CS42L52_BEEP_TONE_CTL			0x1E
+#define CS42L52_BEEP_RATE_SHIFT			4
+#define CS42L52_BEEP_RATE_MASK			0x0F
+
+#define CS42L52_TONE_CTL			0x1F
+#define CS42L52_BEEP_EN_MASK			0x3F
+
+#define CS42L52_MASTERA_VOL			0x20
+#define CS42L52_MASTERB_VOL			0x21
+
+#define CS42L52_HPA_VOL				0x22
+#define CS42L52_HPB_VOL				0x23
+#define CS42L52_DEFAULT_HP_VOL			0xF0
+
+#define CS42L52_SPKA_VOL			0x24
+#define CS42L52_SPKB_VOL			0x25
+#define CS42L52_DEFAULT_SPK_VOL			0xF0
+
+#define CS42L52_ADC_PCM_MIXER			0x26
+
+#define CS42L52_LIMITER_CTL1			0x27
+#define CS42L52_LIMITER_CTL2			0x28
+#define CS42L52_LIMITER_AT_RATE			0x29
+
+#define CS42L52_ALC_CTL				0x2A
+#define CS42L52_ALC_CTL_ALCB_ENABLE_SHIFT	7
+#define CS42L52_ALC_CTL_ALCA_ENABLE_SHIFT	6
+#define CS42L52_ALC_CTL_FASTEST_ATTACK		0
+
+#define CS42L52_ALC_RATE			0x2B
+#define CS42L52_ALC_SLOWEST_RELEASE		0x3F
+
+#define CS42L52_ALC_THRESHOLD			0x2C
+#define CS42L52_ALC_MAX_RATE_SHIFT		5
+#define CS42L52_ALC_MIN_RATE_SHIFT		2
+#define CS42L52_ALC_RATE_0DB			0
+#define CS42L52_ALC_RATE_3DB			1
+#define CS42L52_ALC_RATE_6DB			2
+
+#define CS42L52_NOISE_GATE_CTL			0x2D
+#define CS42L52_NG_ENABLE_SHIFT			6
+#define CS42L52_NG_THRESHOLD_SHIFT		2
+#define CS42L52_NG_MIN_70DB			2
+#define CS42L52_NG_DELAY_SHIFT			0
+#define CS42L52_NG_DELAY_100MS			1
+
+#define CS42L52_CLK_STATUS			0x2E
+#define CS42L52_BATT_COMPEN			0x2F
+
+#define CS42L52_BATT_LEVEL			0x30
+#define CS42L52_SPK_STATUS			0x31
+#define CS42L52_SPK_STATUS_PIN_SHIFT		3
+#define CS42L52_SPK_STATUS_PIN_HIGH		1
+
+#define CS42L52_TEM_CTL				0x32
+#define CS42L52_TEM_CTL_SET			0x80
+#define CS42L52_THE_FOLDBACK			0x33
+#define CS42L52_CHARGE_PUMP			0x34
+#define CS42L52_CHARGE_PUMP_MASK		0xF0
+#define CS42L52_CHARGE_PUMP_SHIFT		4
+#define CS42L52_FIX_BITS1			0x3E
+#define CS42L52_FIX_BITS2			0x47
+
+#define CS42L52_MAX_REGISTER			0x34
+
+#endif
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 3686417..e0d45fd 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -43,9 +43,6 @@
 };
 
 static const struct reg_default cs42l73_reg_defaults[] = {
-	{ 1, 0x42 },	/* r01	- Device ID A&B */
-	{ 2, 0xA7 },	/* r02	- Device ID C&D */
-	{ 3, 0x30 },	/* r03	- Device ID E */
 	{ 6, 0xF1 },	/* r06	- Power Ctl 1 */
 	{ 7, 0xDF },	/* r07	- Power Ctl 2 */
 	{ 8, 0x3F },	/* r08	- Power Ctl 3 */
@@ -402,37 +399,37 @@
 
 static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
 	SOC_DOUBLE_R_SX_TLV("Headphone Analog Playback Volume",
-			CS42L73_HPAAVOL, CS42L73_HPBAVOL, 7,
-			0xffffffC1, 0x0C, hpaloa_tlv),
+			CS42L73_HPAAVOL, CS42L73_HPBAVOL, 0,
+			0x41, 0x4B, hpaloa_tlv),
 
 	SOC_DOUBLE_R_SX_TLV("LineOut Analog Playback Volume", CS42L73_LOAAVOL,
-			CS42L73_LOBAVOL, 7, 0xffffffC1, 0x0C, hpaloa_tlv),
+			CS42L73_LOBAVOL, 0, 0x41, 0x4B, hpaloa_tlv),
 
 	SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL,
-			CS42L73_MICBPREPGABVOL, 5, 0xffffff35,
-			0x34, micpga_tlv),
+			CS42L73_MICBPREPGABVOL, 5, 0x34,
+			0x24, micpga_tlv),
 
 	SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL,
 			CS42L73_MICBPREPGABVOL, 6, 1, 1),
 
 	SOC_DOUBLE_R_SX_TLV("Input Path Digital Volume", CS42L73_IPADVOL,
-			CS42L73_IPBDVOL, 7, 0xffffffA0, 0xA0, ipd_tlv),
+			CS42L73_IPBDVOL, 0, 0xA0, 0x6C, ipd_tlv),
 
 	SOC_DOUBLE_R_SX_TLV("HL Digital Playback Volume",
-			CS42L73_HLADVOL, CS42L73_HLBDVOL, 7, 0xffffffE5,
-			0xE4, hl_tlv),
+			CS42L73_HLADVOL, CS42L73_HLBDVOL,
+			0, 0x34, 0xE4, hl_tlv),
 
 	SOC_SINGLE_TLV("ADC A Boost Volume",
 			CS42L73_ADCIPC, 2, 0x01, 1, adc_boost_tlv),
 
 	SOC_SINGLE_TLV("ADC B Boost Volume",
-			CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
+		       CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
 
-	SOC_SINGLE_TLV("Speakerphone Digital Playback Volume",
-			CS42L73_SPKDVOL, 0, 0xE4, 1, hl_tlv),
+	SOC_SINGLE_SX_TLV("Speakerphone Digital Volume",
+			    CS42L73_SPKDVOL, 0, 0x34, 0xE4, hl_tlv),
 
-	SOC_SINGLE_TLV("Ear Speaker Digital Playback Volume",
-			CS42L73_ESLDVOL, 0, 0xE4, 1, hl_tlv),
+	SOC_SINGLE_SX_TLV("Ear Speaker Digital Volume",
+			    CS42L73_ESLDVOL, 0, 0x34, 0xE4, hl_tlv),
 
 	SOC_DOUBLE_R("Headphone Analog Playback Switch", CS42L73_HPAAVOL,
 			CS42L73_HPBAVOL, 7, 1, 1),
@@ -599,17 +596,17 @@
 	SND_SOC_DAPM_INPUT("MIC2"),
 	SND_SOC_DAPM_SUPPLY("MIC2 Bias", CS42L73_PWRCTL2, 7, 1, NULL, 0),
 
-	SND_SOC_DAPM_AIF_OUT("XSPOUTL", "XSP Capture",  0,
+	SND_SOC_DAPM_AIF_OUT("XSPOUTL", NULL,  0,
 			CS42L73_PWRCTL2, 1, 1),
-	SND_SOC_DAPM_AIF_OUT("XSPOUTR", "XSP Capture",  0,
+	SND_SOC_DAPM_AIF_OUT("XSPOUTR", NULL,  0,
 			CS42L73_PWRCTL2, 1, 1),
-	SND_SOC_DAPM_AIF_OUT("ASPOUTL", "ASP Capture",  0,
+	SND_SOC_DAPM_AIF_OUT("ASPOUTL", NULL,  0,
 			CS42L73_PWRCTL2, 3, 1),
-	SND_SOC_DAPM_AIF_OUT("ASPOUTR", "ASP Capture",  0,
+	SND_SOC_DAPM_AIF_OUT("ASPOUTR", NULL,  0,
 			CS42L73_PWRCTL2, 3, 1),
-	SND_SOC_DAPM_AIF_OUT("VSPOUTL", "VSP Capture",  0,
+	SND_SOC_DAPM_AIF_OUT("VSPOUTL", NULL,  0,
 			CS42L73_PWRCTL2, 4, 1),
-	SND_SOC_DAPM_AIF_OUT("VSPOUTR", "VSP Capture",  0,
+	SND_SOC_DAPM_AIF_OUT("VSPOUTR", NULL,  0,
 			CS42L73_PWRCTL2, 4, 1),
 
 	SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -638,21 +635,21 @@
 	SND_SOC_DAPM_MIXER("VSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("VSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 
-	SND_SOC_DAPM_AIF_IN("XSPINL", "XSP Playback", 0,
+	SND_SOC_DAPM_AIF_IN("XSPINL", NULL, 0,
 				CS42L73_PWRCTL2, 0, 1),
-	SND_SOC_DAPM_AIF_IN("XSPINR", "XSP Playback", 0,
+	SND_SOC_DAPM_AIF_IN("XSPINR", NULL, 0,
 				CS42L73_PWRCTL2, 0, 1),
-	SND_SOC_DAPM_AIF_IN("XSPINM", "XSP Playback", 0,
+	SND_SOC_DAPM_AIF_IN("XSPINM", NULL, 0,
 				CS42L73_PWRCTL2, 0, 1),
 
-	SND_SOC_DAPM_AIF_IN("ASPINL", "ASP Playback", 0,
+	SND_SOC_DAPM_AIF_IN("ASPINL", NULL, 0,
 				CS42L73_PWRCTL2, 2, 1),
-	SND_SOC_DAPM_AIF_IN("ASPINR", "ASP Playback", 0,
+	SND_SOC_DAPM_AIF_IN("ASPINR", NULL, 0,
 				CS42L73_PWRCTL2, 2, 1),
-	SND_SOC_DAPM_AIF_IN("ASPINM", "ASP Playback", 0,
+	SND_SOC_DAPM_AIF_IN("ASPINM", NULL, 0,
 				CS42L73_PWRCTL2, 2, 1),
 
-	SND_SOC_DAPM_AIF_IN("VSPIN", "VSP Playback", 0,
+	SND_SOC_DAPM_AIF_IN("VSPIN", NULL, 0,
 				CS42L73_PWRCTL2, 4, 1),
 
 	SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -776,6 +773,14 @@
 	{"HL Left Mixer", NULL, "VSPIN"},
 	{"HL Right Mixer", NULL, "VSPIN"},
 
+	{"ASPINL", NULL, "ASP Playback"},
+	{"ASPINM", NULL, "ASP Playback"},
+	{"ASPINR", NULL, "ASP Playback"},
+	{"XSPINL", NULL, "XSP Playback"},
+	{"XSPINM", NULL, "XSP Playback"},
+	{"XSPINR", NULL, "XSP Playback"},
+	{"VSPIN", NULL, "VSP Playback"},
+
 	/* Capture Paths */
 	{"MIC1", NULL, "MIC1 Bias"},
 	{"PGA Left Mux", "Mic 1", "MIC1"},
@@ -822,6 +827,13 @@
 
 	{"VSPOUTL", NULL, "VSPL Output Mixer"},
 	{"VSPOUTR", NULL, "VSPR Output Mixer"},
+
+	{"ASP Capture", NULL, "ASPOUTL"},
+	{"ASP Capture", NULL, "ASPOUTR"},
+	{"XSP Capture", NULL, "XSPOUTL"},
+	{"XSP Capture", NULL, "XSPOUTR"},
+	{"VSP Capture", NULL, "VSPOUTL"},
+	{"VSP Capture", NULL, "VSPOUTR"},
 };
 
 struct cs42l73_mclk_div {
@@ -1091,8 +1103,7 @@
 				 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 snd_soc_codec *codec = dai->codec;
 	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
 	int id = dai->id;
 	int mclk_coeff;
@@ -1429,25 +1440,7 @@
 
 };
 
-static int __init cs42l73_modinit(void)
-{
-	int ret;
-	ret = i2c_add_driver(&cs42l73_i2c_driver);
-	if (ret != 0) {
-		pr_err("Failed to register CS42L73 I2C driver: %d\n", ret);
-		return ret;
-	}
-	return 0;
-}
-
-module_init(cs42l73_modinit);
-
-static void __exit cs42l73_exit(void)
-{
-	i2c_del_driver(&cs42l73_i2c_driver);
-}
-
-module_exit(cs42l73_exit);
+module_i2c_driver(cs42l73_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC CS42L73 driver");
 MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 7843711..af5db70 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -17,6 +17,7 @@
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -27,6 +28,7 @@
 #include <sound/tlv.h>
 
 /* DA7210 register space */
+#define DA7210_PAGE_CONTROL		0x00
 #define DA7210_CONTROL			0x01
 #define DA7210_STATUS			0x02
 #define DA7210_STARTUP1			0x03
@@ -146,6 +148,7 @@
 #define DA7210_DAI_EN			(1 << 7)
 
 /*PLL_DIV3 bit fields */
+#define DA7210_PLL_DIV_L_MASK		(0xF << 0)
 #define DA7210_MCLK_RANGE_10_20_MHZ	(1 << 4)
 #define DA7210_PLL_BYP			(1 << 6)
 
@@ -162,12 +165,16 @@
 #define DA7210_PLL_FS_48000		(0xB << 0)
 #define DA7210_PLL_FS_88200		(0xE << 0)
 #define DA7210_PLL_FS_96000		(0xF << 0)
+#define DA7210_MCLK_DET_EN		(0x1 << 5)
+#define DA7210_MCLK_SRM_EN		(0x1 << 6)
 #define DA7210_PLL_EN			(0x1 << 7)
 
 /* SOFTMUTE bit fields */
 #define DA7210_RAMP_EN			(1 << 6)
 
 /* CONTROL bit fields */
+#define DA7210_REG_EN			(1 << 0)
+#define DA7210_BIAS_EN			(1 << 2)
 #define DA7210_NOISE_SUP_EN		(1 << 3)
 
 /* IN_GAIN bit fields */
@@ -206,6 +213,47 @@
 #define DA7210_OUT2_OUTMIX_L		(1 << 6)
 #define DA7210_OUT2_EN			(1 << 7)
 
+struct pll_div {
+	int fref;
+	int fout;
+	u8 div1;
+	u8 div2;
+	u8 div3;
+	u8 mode;	/* 0 = slave, 1 = master */
+};
+
+/* PLL dividers table */
+static const struct pll_div da7210_pll_div[] = {
+	/* for MASTER mode, fs = 44.1Khz */
+	{ 12000000, 2822400, 0xE8, 0x6C, 0x2, 1},	/* MCLK=12Mhz */
+	{ 13000000, 2822400, 0xDF, 0x28, 0xC, 1},	/* MCLK=13Mhz */
+	{ 13500000, 2822400, 0xDB, 0x0A, 0xD, 1},	/* MCLK=13.5Mhz */
+	{ 14400000, 2822400, 0xD4, 0x5A, 0x2, 1},	/* MCLK=14.4Mhz */
+	{ 19200000, 2822400, 0xBB, 0x43, 0x9, 1},	/* MCLK=19.2Mhz */
+	{ 19680000, 2822400, 0xB9, 0x6D, 0xA, 1},	/* MCLK=19.68Mhz */
+	{ 19800000, 2822400, 0xB8, 0xFB, 0xB, 1},	/* MCLK=19.8Mhz */
+	/* for MASTER mode, fs = 48Khz */
+	{ 12000000, 3072000, 0xF3, 0x12, 0x7, 1},	/* MCLK=12Mhz */
+	{ 13000000, 3072000, 0xE8, 0xFD, 0x5, 1},	/* MCLK=13Mhz */
+	{ 13500000, 3072000, 0xE4, 0x82, 0x3, 1},	/* MCLK=13.5Mhz */
+	{ 14400000, 3072000, 0xDD, 0x3A, 0x0, 1},	/* MCLK=14.4Mhz */
+	{ 19200000, 3072000, 0xC1, 0xEB, 0x8, 1},	/* MCLK=19.2Mhz */
+	{ 19680000, 3072000, 0xBF, 0xEC, 0x0, 1},	/* MCLK=19.68Mhz */
+	{ 19800000, 3072000, 0xBF, 0x70, 0x0, 1},	/* MCLK=19.8Mhz */
+	/* for SLAVE mode with SRM */
+	{ 12000000, 2822400, 0xED, 0xBF, 0x5, 0},	/* MCLK=12Mhz */
+	{ 13000000, 2822400, 0xE4, 0x13, 0x0, 0},	/* MCLK=13Mhz */
+	{ 13500000, 2822400, 0xDF, 0xC6, 0x8, 0},	/* MCLK=13.5Mhz */
+	{ 14400000, 2822400, 0xD8, 0xCA, 0x1, 0},	/* MCLK=14.4Mhz */
+	{ 19200000, 2822400, 0xBE, 0x97, 0x9, 0},	/* MCLK=19.2Mhz */
+	{ 19680000, 2822400, 0xBC, 0xAC, 0xD, 0},	/* MCLK=19.68Mhz */
+	{ 19800000, 2822400, 0xBC, 0x35, 0xE, 0},	/* MCLK=19.8Mhz  */
+};
+
+enum clk_src {
+	DA7210_CLKSRC_MCLK
+};
+
 #define DA7210_VERSION "0.0.1"
 
 /*
@@ -628,9 +676,12 @@
 /* Codec private data */
 struct da7210_priv {
 	struct regmap *regmap;
+	unsigned int mclk_rate;
+	int master;
 };
 
 static struct reg_default da7210_reg_defaults[] = {
+	{ 0x00, 0x00 },
 	{ 0x01, 0x11 },
 	{ 0x03, 0x00 },
 	{ 0x04, 0x00 },
@@ -713,10 +764,10 @@
 			    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 snd_soc_codec *codec = dai->codec;
+	struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
 	u32 dai_cfg1;
-	u32 fs, bypass;
+	u32 fs, sysclk;
 
 	/* set DAI source to Left and Right ADC */
 	snd_soc_write(codec, DA7210_DAI_SRC_SEL,
@@ -749,43 +800,43 @@
 	switch (params_rate(params)) {
 	case 8000:
 		fs		= DA7210_PLL_FS_8000;
-		bypass		= DA7210_PLL_BYP;
+		sysclk		= 3072000;
 		break;
 	case 11025:
 		fs		= DA7210_PLL_FS_11025;
-		bypass		= 0;
+		sysclk		= 2822400;
 		break;
 	case 12000:
 		fs		= DA7210_PLL_FS_12000;
-		bypass		= DA7210_PLL_BYP;
+		sysclk		= 3072000;
 		break;
 	case 16000:
 		fs		= DA7210_PLL_FS_16000;
-		bypass		= DA7210_PLL_BYP;
+		sysclk		= 3072000;
 		break;
 	case 22050:
 		fs		= DA7210_PLL_FS_22050;
-		bypass		= 0;
+		sysclk		= 2822400;
 		break;
 	case 32000:
 		fs		= DA7210_PLL_FS_32000;
-		bypass		= DA7210_PLL_BYP;
+		sysclk		= 3072000;
 		break;
 	case 44100:
 		fs		= DA7210_PLL_FS_44100;
-		bypass		= 0;
+		sysclk		= 2822400;
 		break;
 	case 48000:
 		fs		= DA7210_PLL_FS_48000;
-		bypass		= DA7210_PLL_BYP;
+		sysclk		= 3072000;
 		break;
 	case 88200:
 		fs		= DA7210_PLL_FS_88200;
-		bypass		= 0;
+		sysclk		= 2822400;
 		break;
 	case 96000:
 		fs		= DA7210_PLL_FS_96000;
-		bypass		= DA7210_PLL_BYP;
+		sysclk		= 3072000;
 		break;
 	default:
 		return -EINVAL;
@@ -795,8 +846,26 @@
 	snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
 
 	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
-	snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, bypass);
 
+	if (da7210->mclk_rate && (da7210->mclk_rate != sysclk)) {
+		/* PLL mode, disable PLL bypass */
+		snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, 0);
+
+		if (!da7210->master) {
+			/* PLL slave mode, also enable SRM */
+			snd_soc_update_bits(codec, DA7210_PLL,
+						   (DA7210_MCLK_SRM_EN |
+						    DA7210_MCLK_DET_EN),
+						   (DA7210_MCLK_SRM_EN |
+						    DA7210_MCLK_DET_EN));
+		}
+	} else {
+		/* PLL bypass mode, enable PLL bypass and Auto Detection */
+		snd_soc_update_bits(codec, DA7210_PLL, DA7210_MCLK_DET_EN,
+						       DA7210_MCLK_DET_EN);
+		snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP,
+							    DA7210_PLL_BYP);
+	}
 	/* Enable active mode */
 	snd_soc_update_bits(codec, DA7210_STARTUP1,
 			    DA7210_SC_MST_EN, DA7210_SC_MST_EN);
@@ -810,17 +879,24 @@
 static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
+	struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
 	u32 dai_cfg1;
 	u32 dai_cfg3;
 
 	dai_cfg1 = 0x7f & snd_soc_read(codec, DA7210_DAI_CFG1);
 	dai_cfg3 = 0xfc & snd_soc_read(codec, DA7210_DAI_CFG3);
 
+	if ((snd_soc_read(codec, DA7210_PLL) & DA7210_PLL_EN) &&
+		(!(snd_soc_read(codec, DA7210_PLL_DIV3) & DA7210_PLL_BYP)))
+		return -EINVAL;
+
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
+		da7210->master = 1;
 		dai_cfg1 |= DA7210_DAI_MODE_MASTER;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
+		da7210->master = 0;
 		dai_cfg1 |= DA7210_DAI_MODE_SLAVE;
 		break;
 	default:
@@ -872,10 +948,101 @@
 #define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static int da7210_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 da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+
+	switch (clk_id) {
+	case DA7210_CLKSRC_MCLK:
+		switch (freq) {
+		case 12000000:
+		case 13000000:
+		case 13500000:
+		case 14400000:
+		case 19200000:
+		case 19680000:
+		case 19800000:
+			da7210->mclk_rate = freq;
+			return 0;
+		default:
+			dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+				freq);
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+}
+
+/**
+ * da7210_set_dai_pll	:Configure the codec PLL
+ * @param codec_dai	: pointer to codec DAI
+ * @param pll_id	: da7210 has only one pll, so pll_id is always zero
+ * @param fref		: MCLK frequency, should be < 20MHz
+ * @param fout		: FsDM value, Refer page 44 & 45 of datasheet
+ * @return int		: Zero for success, negative error code for error
+ *
+ * Note: Supported PLL input frequencies are 12MHz, 13MHz, 13.5MHz, 14.4MHz,
+ *       19.2MHz, 19.6MHz and 19.8MHz
+ */
+static int da7210_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+			      int source, unsigned int fref, unsigned int fout)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+
+	u8 pll_div1, pll_div2, pll_div3, cnt;
+
+	/* In slave mode, there is only one set of divisors */
+	if (!da7210->master)
+		fout = 2822400;
+
+	/* Search pll div array for correct divisors */
+	for (cnt = 0; cnt < ARRAY_SIZE(da7210_pll_div); cnt++) {
+		/* check fref, mode  and fout */
+		if ((fref == da7210_pll_div[cnt].fref) &&
+		    (da7210->master ==  da7210_pll_div[cnt].mode) &&
+		    (fout == da7210_pll_div[cnt].fout)) {
+			/* all match, pick up divisors */
+			pll_div1 = da7210_pll_div[cnt].div1;
+			pll_div2 = da7210_pll_div[cnt].div2;
+			pll_div3 = da7210_pll_div[cnt].div3;
+			break;
+		}
+	}
+	if (cnt >= ARRAY_SIZE(da7210_pll_div))
+		goto err;
+
+	/* Disable active mode */
+	snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
+	/* Write PLL dividers */
+	snd_soc_write(codec, DA7210_PLL_DIV1, pll_div1);
+	snd_soc_write(codec, DA7210_PLL_DIV2, pll_div2);
+	snd_soc_update_bits(codec, DA7210_PLL_DIV3,
+				   DA7210_PLL_DIV_L_MASK, pll_div3);
+
+	/* Enable PLL */
+	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
+
+	/* Enable active mode */
+	snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN,
+						    DA7210_SC_MST_EN);
+	return 0;
+err:
+	dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n", fref);
+	return -EINVAL;
+}
+
 /* DAI operations */
 static const struct snd_soc_dai_ops da7210_dai_ops = {
 	.hw_params	= da7210_hw_params,
 	.set_fmt	= da7210_set_dai_fmt,
+	.set_sysclk	= da7210_set_dai_sysclk,
+	.set_pll	= da7210_set_dai_pll,
 	.digital_mute	= da7210_mute,
 };
 
@@ -915,24 +1082,11 @@
 		return ret;
 	}
 
-	/* FIXME
-	 *
-	 * This driver use fixed value here
-	 * And below settings expects MCLK = 12.288MHz
-	 *
-	 * When you select different MCLK, please check...
-	 *      DA7210_PLL_DIV1 val
-	 *      DA7210_PLL_DIV2 val
-	 *      DA7210_PLL_DIV3 val
-	 *      DA7210_PLL_DIV3 :: DA7210_MCLK_RANGExxx
-	 */
+	da7210->mclk_rate       = 0;    /* This will be set from set_sysclk() */
+	da7210->master          = 0;    /* This will be set from set_fmt() */
 
-	/*
-	 * make sure that DA7210 use bypass mode before start up
-	 */
-	snd_soc_write(codec, DA7210_STARTUP1, 0);
-	snd_soc_write(codec, DA7210_PLL_DIV3,
-		     DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
+	/* Enable internal regulator & bias current */
+	snd_soc_write(codec, DA7210_CONTROL, DA7210_REG_EN | DA7210_BIAS_EN);
 
 	/*
 	 * ADC settings
@@ -1007,34 +1161,13 @@
 	/* Enable Aux2 */
 	snd_soc_write(codec, DA7210_AUX2, DA7210_AUX2_EN);
 
+	/* Set PLL Master clock range 10-20 MHz, enable PLL bypass */
+	snd_soc_write(codec, DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ |
+					      DA7210_PLL_BYP);
+
 	/* Diable PLL and bypass it */
 	snd_soc_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
 
-	/*
-	 * If 48kHz sound came, it use bypass mode,
-	 * and when it is 44.1kHz, it use PLL.
-	 *
-	 * This time, this driver sets PLL always ON
-	 * and controls bypass/PLL mode by switching
-	 * DA7210_PLL_DIV3 :: DA7210_PLL_BYP bit.
-	 *   see da7210_hw_params
-	 */
-	snd_soc_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */
-	snd_soc_write(codec, DA7210_PLL_DIV2, 0x99);
-	snd_soc_write(codec, DA7210_PLL_DIV3, 0x0A |
-		     DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
-	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
-
-	/* As suggested by Dialog */
-	/* unlock */
-	regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK,	0x8B);
-	regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK,	0xB4);
-	regmap_write(da7210->regmap, DA7210_A_PLL1,		0x01);
-	regmap_write(da7210->regmap, DA7210_A_CP_MODE,		0x7C);
-	/* re-lock */
-	regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK,	0x00);
-	regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK,	0x00);
-
 	/* Activate all enabled subsystem */
 	snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
 
@@ -1055,7 +1188,26 @@
 	.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
 };
 
-static struct regmap_config da7210_regmap = {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static struct reg_default da7210_regmap_i2c_patch[] = {
+
+	/* System controller master disable */
+	{ DA7210_STARTUP1, 0x00 },
+	/* Set PLL Master clock range 10-20 MHz */
+	{ DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ },
+
+	/* to unlock */
+	{ DA7210_A_HID_UNLOCK, 0x8B},
+	{ DA7210_A_TEST_UNLOCK, 0xB4},
+	{ DA7210_A_PLL1, 0x01},
+	{ DA7210_A_CP_MODE, 0x7C},
+	/* to re-lock */
+	{ DA7210_A_HID_UNLOCK, 0x00},
+	{ DA7210_A_TEST_UNLOCK, 0x00},
+};
+
+static const struct regmap_config da7210_regmap_config_i2c = {
 	.reg_bits = 8,
 	.val_bits = 8,
 
@@ -1066,7 +1218,6 @@
 	.cache_type = REGCACHE_RBTREE,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
 			   	      const struct i2c_device_id *id)
 {
@@ -1080,13 +1231,18 @@
 
 	i2c_set_clientdata(i2c, da7210);
 
-	da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap);
+	da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap_config_i2c);
 	if (IS_ERR(da7210->regmap)) {
 		ret = PTR_ERR(da7210->regmap);
 		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
 		return ret;
 	}
 
+	ret = regmap_register_patch(da7210->regmap, da7210_regmap_i2c_patch,
+				    ARRAY_SIZE(da7210_regmap_i2c_patch));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
 	ret =  snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_da7210, &da7210_dai, 1);
 	if (ret < 0) {
@@ -1119,7 +1275,7 @@
 /* I2C codec control layer */
 static struct i2c_driver da7210_i2c_driver = {
 	.driver = {
-		.name = "da7210-codec",
+		.name = "da7210",
 		.owner = THIS_MODULE,
 	},
 	.probe		= da7210_i2c_probe,
@@ -1128,12 +1284,112 @@
 };
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+
+static struct reg_default da7210_regmap_spi_patch[] = {
+	/* Dummy read to give two pulses over nCS for SPI */
+	{ DA7210_AUX2, 0x00 },
+	{ DA7210_AUX2, 0x00 },
+
+	/* System controller master disable */
+	{ DA7210_STARTUP1, 0x00 },
+	/* Set PLL Master clock range 10-20 MHz */
+	{ DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ },
+
+	/* to set PAGE1 of SPI register space */
+	{ DA7210_PAGE_CONTROL, 0x80 },
+	/* to unlock */
+	{ DA7210_A_HID_UNLOCK, 0x8B},
+	{ DA7210_A_TEST_UNLOCK, 0xB4},
+	{ DA7210_A_PLL1, 0x01},
+	{ DA7210_A_CP_MODE, 0x7C},
+	/* to re-lock */
+	{ DA7210_A_HID_UNLOCK, 0x00},
+	{ DA7210_A_TEST_UNLOCK, 0x00},
+	/* to set back PAGE0 of SPI register space */
+	{ DA7210_PAGE_CONTROL, 0x00 },
+};
+
+static const struct regmap_config da7210_regmap_config_spi = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.read_flag_mask = 0x01,
+	.write_flag_mask = 0x00,
+
+	.reg_defaults = da7210_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults),
+	.volatile_reg = da7210_volatile_register,
+	.readable_reg = da7210_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit da7210_spi_probe(struct spi_device *spi)
+{
+	struct da7210_priv *da7210;
+	int ret;
+
+	da7210 = devm_kzalloc(&spi->dev, sizeof(struct da7210_priv),
+			      GFP_KERNEL);
+	if (!da7210)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, da7210);
+	da7210->regmap = devm_regmap_init_spi(spi, &da7210_regmap_config_spi);
+	if (IS_ERR(da7210->regmap)) {
+		ret = PTR_ERR(da7210->regmap);
+		dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_register_patch(da7210->regmap, da7210_regmap_spi_patch,
+				    ARRAY_SIZE(da7210_regmap_spi_patch));
+	if (ret != 0)
+		dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	ret =  snd_soc_register_codec(&spi->dev,
+			&soc_codec_dev_da7210, &da7210_dai, 1);
+	if (ret < 0)
+		goto err_regmap;
+
+	return ret;
+
+err_regmap:
+	regmap_exit(da7210->regmap);
+
+	return ret;
+}
+
+static int __devexit da7210_spi_remove(struct spi_device *spi)
+{
+	struct da7210_priv *da7210 = spi_get_drvdata(spi);
+	snd_soc_unregister_codec(&spi->dev);
+	regmap_exit(da7210->regmap);
+	return 0;
+}
+
+static struct spi_driver da7210_spi_driver = {
+	.driver = {
+		.name = "da7210",
+		.owner = THIS_MODULE,
+	},
+	.probe = da7210_spi_probe,
+	.remove = __devexit_p(da7210_spi_remove)
+};
+#endif
+
 static int __init da7210_modinit(void)
 {
 	int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&da7210_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&da7210_spi_driver);
+	if (ret) {
+		printk(KERN_ERR "Failed to register da7210 SPI driver: %d\n",
+		       ret);
+	}
+#endif
 	return ret;
 }
 module_init(da7210_modinit);
@@ -1143,6 +1399,9 @@
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&da7210_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&da7210_spi_driver);
+#endif
 }
 module_exit(da7210_exit);
 
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 4624e75..85d9cab 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -164,8 +164,7 @@
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
 	uint32_t val;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec =rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 
 	switch (params_rate(params)) {
 	case 8000:
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
new file mode 100644
index 0000000..802b9f1
--- /dev/null
+++ b/sound/soc/codecs/lm49453.c
@@ -0,0 +1,1550 @@
+/*
+ * lm49453.c  -  LM49453 ALSA Soc Audio driver
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * Initially based on sound/soc/codecs/wm8350.c
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.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/jack.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+#include "lm49453.h"
+
+static struct reg_default lm49453_reg_defs[] = {
+	{ 0, 0x00 },
+	{ 1, 0x00 },
+	{ 2, 0x00 },
+	{ 3, 0x00 },
+	{ 4, 0x00 },
+	{ 5, 0x00 },
+	{ 6, 0x00 },
+	{ 7, 0x00 },
+	{ 8, 0x00 },
+	{ 9, 0x00 },
+	{ 10, 0x00 },
+	{ 11, 0x00 },
+	{ 12, 0x00 },
+	{ 13, 0x00 },
+	{ 14, 0x00 },
+	{ 15, 0x00 },
+	{ 16, 0x00 },
+	{ 17, 0x00 },
+	{ 18, 0x00 },
+	{ 19, 0x00 },
+	{ 20, 0x00 },
+	{ 21, 0x00 },
+	{ 22, 0x00 },
+	{ 23, 0x00 },
+	{ 32, 0x00 },
+	{ 33, 0x00 },
+	{ 35, 0x00 },
+	{ 36, 0x00 },
+	{ 37, 0x00 },
+	{ 46, 0x00 },
+	{ 48, 0x00 },
+	{ 49, 0x00 },
+	{ 51, 0x00 },
+	{ 56, 0x00 },
+	{ 58, 0x00 },
+	{ 59, 0x00 },
+	{ 60, 0x00 },
+	{ 61, 0x00 },
+	{ 62, 0x00 },
+	{ 63, 0x00 },
+	{ 64, 0x00 },
+	{ 65, 0x00 },
+	{ 66, 0x00 },
+	{ 67, 0x00 },
+	{ 68, 0x00 },
+	{ 69, 0x00 },
+	{ 70, 0x00 },
+	{ 71, 0x00 },
+	{ 72, 0x00 },
+	{ 73, 0x00 },
+	{ 74, 0x00 },
+	{ 75, 0x00 },
+	{ 76, 0x00 },
+	{ 77, 0x00 },
+	{ 78, 0x00 },
+	{ 79, 0x00 },
+	{ 80, 0x00 },
+	{ 81, 0x00 },
+	{ 82, 0x00 },
+	{ 83, 0x00 },
+	{ 85, 0x00 },
+	{ 85, 0x00 },
+	{ 86, 0x00 },
+	{ 87, 0x00 },
+	{ 88, 0x00 },
+	{ 89, 0x00 },
+	{ 90, 0x00 },
+	{ 91, 0x00 },
+	{ 92, 0x00 },
+	{ 93, 0x00 },
+	{ 94, 0x00 },
+	{ 95, 0x00 },
+	{ 96, 0x01 },
+	{ 97, 0x00 },
+	{ 98, 0x00 },
+	{ 99, 0x00 },
+	{ 100, 0x00 },
+	{ 101, 0x00 },
+	{ 102, 0x00 },
+	{ 103, 0x01 },
+	{ 105, 0x01 },
+	{ 106, 0x00 },
+	{ 107, 0x01 },
+	{ 107, 0x00 },
+	{ 108, 0x00 },
+	{ 109, 0x00 },
+	{ 110, 0x00 },
+	{ 111, 0x02 },
+	{ 112, 0x02 },
+	{ 113, 0x00 },
+	{ 121, 0x80 },
+	{ 122, 0xBB },
+	{ 123, 0x80 },
+	{ 124, 0xBB },
+	{ 128, 0x00 },
+	{ 130, 0x00 },
+	{ 131, 0x00 },
+	{ 132, 0x00 },
+	{ 133, 0x0A },
+	{ 134, 0x0A },
+	{ 135, 0x0A },
+	{ 136, 0x0F },
+	{ 137, 0x00 },
+	{ 138, 0x73 },
+	{ 139, 0x33 },
+	{ 140, 0x73 },
+	{ 141, 0x33 },
+	{ 142, 0x73 },
+	{ 143, 0x33 },
+	{ 144, 0x73 },
+	{ 145, 0x33 },
+	{ 146, 0x73 },
+	{ 147, 0x33 },
+	{ 148, 0x73 },
+	{ 149, 0x33 },
+	{ 150, 0x73 },
+	{ 151, 0x33 },
+	{ 152, 0x00 },
+	{ 153, 0x00 },
+	{ 154, 0x00 },
+	{ 155, 0x00 },
+	{ 176, 0x00 },
+	{ 177, 0x00 },
+	{ 178, 0x00 },
+	{ 179, 0x00 },
+	{ 180, 0x00 },
+	{ 181, 0x00 },
+	{ 182, 0x00 },
+	{ 183, 0x00 },
+	{ 184, 0x00 },
+	{ 185, 0x00 },
+	{ 186, 0x00 },
+	{ 189, 0x00 },
+	{ 188, 0x00 },
+	{ 194, 0x00 },
+	{ 195, 0x00 },
+	{ 196, 0x00 },
+	{ 197, 0x00 },
+	{ 200, 0x00 },
+	{ 201, 0x00 },
+	{ 202, 0x00 },
+	{ 203, 0x00 },
+	{ 204, 0x00 },
+	{ 205, 0x00 },
+	{ 208, 0x00 },
+	{ 209, 0x00 },
+	{ 210, 0x00 },
+	{ 211, 0x00 },
+	{ 213, 0x00 },
+	{ 214, 0x00 },
+	{ 215, 0x00 },
+	{ 216, 0x00 },
+	{ 217, 0x00 },
+	{ 218, 0x00 },
+	{ 219, 0x00 },
+	{ 221, 0x00 },
+	{ 222, 0x00 },
+	{ 224, 0x00 },
+	{ 225, 0x00 },
+	{ 226, 0x00 },
+	{ 227, 0x00 },
+	{ 228, 0x00 },
+	{ 229, 0x00 },
+	{ 230, 0x13 },
+	{ 231, 0x00 },
+	{ 232, 0x80 },
+	{ 233, 0x0C },
+	{ 234, 0xDD },
+	{ 235, 0x00 },
+	{ 236, 0x04 },
+	{ 237, 0x00 },
+	{ 238, 0x00 },
+	{ 239, 0x00 },
+	{ 240, 0x00 },
+	{ 241, 0x00 },
+	{ 242, 0x00 },
+	{ 243, 0x00 },
+	{ 244, 0x00 },
+	{ 245, 0x00 },
+	{ 248, 0x00 },
+	{ 249, 0x00 },
+	{ 254, 0x00 },
+	{ 255, 0x00 },
+};
+
+/* codec private data */
+struct lm49453_priv {
+	struct regmap *regmap;
+	int fs_rate;
+};
+
+/* capture path controls */
+
+static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"};
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5,
+				  lm49453_mic2mode_text);
+
+static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"};
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum,
+				  LM49453_P0_DIGITAL_MIC1_CONFIG_REG,
+				  7, lm49453_dmic_cfg_text);
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum,
+				  LM49453_P0_DIGITAL_MIC2_CONFIG_REG,
+				  7, lm49453_dmic_cfg_text);
+
+/* MUX Controls */
+static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" };
+
+static const char *lm49453_adcr_mux_text[] = { "MIC2", "Aux_R" };
+
+static const struct soc_enum lm49453_adcl_enum =
+	SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 0,
+			ARRAY_SIZE(lm49453_adcl_mux_text),
+			lm49453_adcl_mux_text);
+
+static const struct soc_enum lm49453_adcr_enum =
+	SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 1,
+			ARRAY_SIZE(lm49453_adcr_mux_text),
+			lm49453_adcr_mux_text);
+
+static const struct snd_kcontrol_new lm49453_adcl_mux_control =
+	SOC_DAPM_ENUM("ADC Left Mux", lm49453_adcl_enum);
+
+static const struct snd_kcontrol_new lm49453_adcr_mux_control =
+	SOC_DAPM_ENUM("ADC Right Mux", lm49453_adcr_enum);
+
+static const struct snd_kcontrol_new lm49453_headset_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 0, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_headset_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 1, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 2, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 3, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 4, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 5, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 6, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 7, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT1_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT1_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT1_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT1_TX2_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx3_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX3_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX3_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX3_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX3_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX3_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX3_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_PORT1_TX3_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx4_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX4_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX4_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX4_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX4_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX4_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX4_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_PORT1_TX4_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx5_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX5_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX5_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX5_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX5_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX5_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX5_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_PORT1_TX5_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx6_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX6_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX6_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX6_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX6_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX6_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX6_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_PORT1_TX6_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx7_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX7_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX7_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX7_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX7_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX7_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX7_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_PORT1_TX7_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx8_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX8_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX8_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX8_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX8_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX8_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX8_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_PORT1_TX8_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT2_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT2_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT2_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT2_TX2_REG, 7, 1, 0),
+};
+
+/* TLV Declarations */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7650, 150, 1);
+static const DECLARE_TLV_DB_SCALE(port_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = {
+/* Sidetone supports mono only */
+SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG,
+		     0, 0x3F, 0, digital_tlv),
+};
+
+static const struct snd_kcontrol_new lm49453_snd_controls[] = {
+	/* mic1 and mic2 supports mono only */
+	SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_ADC_LEVELL_REG, 0, 6,
+			0, digital_tlv),
+	SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_ADC_LEVELR_REG, 0, 6,
+			0, digital_tlv),
+
+	SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG,
+			  LM49453_P0_DMIC1_LEVELR_REG, 0, 6, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG,
+			  LM49453_P0_DMIC2_LEVELR_REG, 0, 6, 0, digital_tlv),
+
+	SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum),
+	SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum),
+	SOC_DAPM_ENUM("DMIC34 SRC", lm49453_dmic34_cfg_enum),
+
+	/* Capture path filter enable */
+	SOC_SINGLE("DMIC1 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+					    0, 1, 0),
+	SOC_SINGLE("DMIC2 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+					    1, 1, 0),
+	SOC_SINGLE("ADC HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+					  2, 1, 0),
+
+	SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG,
+			  LM49453_P0_DAC_HP_LEVELR_REG, 0, 6, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG,
+			  LM49453_P0_DAC_LO_LEVELR_REG, 0, 6, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+			  LM49453_P0_DAC_LS_LEVELR_REG, 0, 6, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG,
+			  LM49453_P0_DAC_HA_LEVELR_REG, 0, 6, 0, digital_tlv),
+
+	SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+			0, 6, 0, digital_tlv),
+
+	SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			0, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_2_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			2, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_3_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			4, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_4_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			6, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_5_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			0, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_6_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			2, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_7_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			4, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_8_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			6, 3, 0, port_tlv),
+
+	SOC_SINGLE_TLV("PORT2_1_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+			0, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT2_2_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+			2, 3, 0, port_tlv),
+
+	SOC_SINGLE("Port1 Playback Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+		    1, 1, 0),
+	SOC_SINGLE("Port2 Playback Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+		    1, 1, 0),
+	SOC_SINGLE("Port1 Capture Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+		    2, 1, 0),
+	SOC_SINGLE("Port2 Capture Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+		    2, 1, 0)
+
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget lm49453_dapm_widgets[] = {
+
+	/* All end points HP,EP, LS, Lineout and Haptic */
+	SND_SOC_DAPM_OUTPUT("HPOUTL"),
+	SND_SOC_DAPM_OUTPUT("HPOUTR"),
+	SND_SOC_DAPM_OUTPUT("EPOUT"),
+	SND_SOC_DAPM_OUTPUT("LSOUTL"),
+	SND_SOC_DAPM_OUTPUT("LSOUTR"),
+	SND_SOC_DAPM_OUTPUT("LOOUTR"),
+	SND_SOC_DAPM_OUTPUT("LOOUTL"),
+	SND_SOC_DAPM_OUTPUT("HAOUTL"),
+	SND_SOC_DAPM_OUTPUT("HAOUTR"),
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_INPUT("DMIC1DAT"),
+	SND_SOC_DAPM_INPUT("DMIC2DAT"),
+	SND_SOC_DAPM_INPUT("AUXL"),
+	SND_SOC_DAPM_INPUT("AUXR"),
+
+	SND_SOC_DAPM_PGA("PORT1_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_3_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_4_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_5_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_6_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_7_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_8_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT2_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT2_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("AMIC1Bias", LM49453_P0_MICL_REG, 6, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AMIC2Bias", LM49453_P0_MICR_REG, 6, 0, NULL, 0),
+
+	/* playback path driver enables */
+	SND_SOC_DAPM_OUT_DRV("Headset Switch",
+			LM49453_P0_PMC_SETUP_REG, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Earpiece Switch",
+			LM49453_P0_EP_REG, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker Left Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 0, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker Right Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 1, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Haptic Left Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 2, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Haptic Right Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 3, 1, NULL, 0),
+
+	/* DAC */
+	SND_SOC_DAPM_DAC("HPL DAC", "Headset", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HPR DAC", "Headset", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LSL DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LSR DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HAL DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HAR DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LOL DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LOR DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+
+
+	SND_SOC_DAPM_PGA("AUXL Input",
+			LM49453_P0_ANALOG_MIXER_ADC_REG, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUXR Input",
+			LM49453_P0_ANALOG_MIXER_ADC_REG, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Sidetone", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("DMIC1 Left", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("DMIC1 Right", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("DMIC2 Left", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("DMIC2 Right", "Capture", SND_SOC_NOPM, 1, 0),
+
+	SND_SOC_DAPM_ADC("ADC Left", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("ADC Right", "Capture", SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 0, 0,
+			  &lm49453_adcl_mux_control),
+	SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
+			  &lm49453_adcr_mux_control),
+
+	SND_SOC_DAPM_MUX("Mic1 Input",
+			SND_SOC_NOPM, 0, 0, &lm49453_adcl_mux_control),
+
+	SND_SOC_DAPM_MUX("Mic2 Input",
+			SND_SOC_NOPM, 0, 0, &lm49453_adcr_mux_control),
+
+	/* AIF */
+	SND_SOC_DAPM_AIF_IN("PORT1_SDI", NULL, 0,
+			    LM49453_P0_PULL_CONFIG1_REG, 2, 0),
+	SND_SOC_DAPM_AIF_IN("PORT2_SDI", NULL, 0,
+			    LM49453_P0_PULL_CONFIG1_REG, 6, 0),
+
+	SND_SOC_DAPM_AIF_OUT("PORT1_SDO", NULL, 0,
+			     LM49453_P0_PULL_CONFIG1_REG, 3, 0),
+	SND_SOC_DAPM_AIF_OUT("PORT2_SDO", NULL, 0,
+			      LM49453_P0_PULL_CONFIG1_REG, 7, 0),
+
+	/* Port1 TX controls */
+	SND_SOC_DAPM_OUT_DRV("P1_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_3_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_4_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_5_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_6_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_7_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_8_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Port2 TX controls */
+	SND_SOC_DAPM_OUT_DRV("P2_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P2_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Sidetone Mixer */
+	SND_SOC_DAPM_MIXER("Sidetone Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_sidetone_mixer_controls,
+			    ARRAY_SIZE(lm49453_sidetone_mixer_controls)),
+
+	/* DAC MIXERS */
+	SND_SOC_DAPM_MIXER("HPL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_headset_left_mixer,
+			    ARRAY_SIZE(lm49453_headset_left_mixer)),
+	SND_SOC_DAPM_MIXER("HPR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_headset_right_mixer,
+			    ARRAY_SIZE(lm49453_headset_right_mixer)),
+	SND_SOC_DAPM_MIXER("LOL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_lineout_left_mixer,
+			    ARRAY_SIZE(lm49453_lineout_left_mixer)),
+	SND_SOC_DAPM_MIXER("LOR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_lineout_right_mixer,
+			    ARRAY_SIZE(lm49453_lineout_right_mixer)),
+	SND_SOC_DAPM_MIXER("LSL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_speaker_left_mixer,
+			    ARRAY_SIZE(lm49453_speaker_left_mixer)),
+	SND_SOC_DAPM_MIXER("LSR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_speaker_right_mixer,
+			    ARRAY_SIZE(lm49453_speaker_right_mixer)),
+	SND_SOC_DAPM_MIXER("HAL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_haptic_left_mixer,
+			    ARRAY_SIZE(lm49453_haptic_left_mixer)),
+	SND_SOC_DAPM_MIXER("HAR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_haptic_right_mixer,
+			    ARRAY_SIZE(lm49453_haptic_right_mixer)),
+
+	/* Capture Mixer */
+	SND_SOC_DAPM_MIXER("Port1_1 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx1_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx1_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_2 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx2_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx2_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_3 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx3_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx3_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_4 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx4_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx4_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_5 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx5_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx5_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_6 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx6_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx6_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_7 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx7_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx7_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_8 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx8_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx8_mixer)),
+
+	SND_SOC_DAPM_MIXER("Port2_1 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port2_tx1_mixer,
+			    ARRAY_SIZE(lm49453_port2_tx1_mixer)),
+	SND_SOC_DAPM_MIXER("Port2_2 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port2_tx2_mixer,
+			    ARRAY_SIZE(lm49453_port2_tx2_mixer)),
+};
+
+static const struct snd_soc_dapm_route lm49453_audio_map[] = {
+	/* Port SDI mapping */
+	{ "PORT1_1_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_2_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_3_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_4_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_5_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_6_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_7_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_8_RX", "Port1 Playback Switch", "PORT1_SDI" },
+
+	{ "PORT2_1_RX", "Port2 Playback Switch", "PORT2_SDI" },
+	{ "PORT2_2_RX", "Port2 Playback Switch", "PORT2_SDI" },
+
+	/* HP mapping */
+	{ "HPL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HPL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HPL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HPL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HPL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HPL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HPL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HPL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	{ "HPL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HPL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HPL Mixer", "ADCL Switch", "ADC Left" },
+	{ "HPL Mixer", "ADCR Switch", "ADC Right" },
+	{ "HPL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HPL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HPL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HPL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "HPL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "HPL DAC", NULL, "HPL Mixer" },
+
+	{ "HPR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HPR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HPR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HPR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HPR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HPR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HPR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HPR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "HPR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HPR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HPR Mixer", "ADCL Switch", "ADC Left" },
+	{ "HPR Mixer", "ADCR Switch", "ADC Right" },
+	{ "HPR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HPR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HPR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HPR Mixer", "DMIC2L Switch", "DMIC2 Right" },
+	{ "HPR Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "HPR DAC", NULL, "HPR Mixer" },
+
+	{ "HPOUTL", "Headset Switch", "HPL DAC"},
+	{ "HPOUTR", "Headset Switch", "HPR DAC"},
+
+	/* EP map */
+	{ "EPOUT", "Earpiece Switch", "HPL DAC" },
+
+	/* Speaker map */
+	{ "LSL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LSL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LSL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LSL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LSL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LSL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LSL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LSL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LSL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LSL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LSL Mixer", "ADCL Switch", "ADC Left" },
+	{ "LSL Mixer", "ADCR Switch", "ADC Right" },
+	{ "LSL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LSL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LSL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LSL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LSL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LSL DAC", NULL, "LSL Mixer" },
+
+	{ "LSR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LSR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LSR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LSR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LSR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LSR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LSR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LSR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LSR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LSR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LSR Mixer", "ADCL Switch", "ADC Left" },
+	{ "LSR Mixer", "ADCR Switch", "ADC Right" },
+	{ "LSR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LSR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LSR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LSR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LSR Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LSR DAC", NULL, "LSR Mixer" },
+
+	{ "LSOUTL", "Speaker Left Switch", "LSL DAC"},
+	{ "LSOUTR", "Speaker Left Switch", "LSR DAC"},
+
+	/* Haptic map */
+	{ "HAL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HAL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HAL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HAL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HAL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HAL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HAL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HAL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "HAL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HAL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HAL Mixer", "ADCL Switch", "ADC Left" },
+	{ "HAL Mixer", "ADCR Switch", "ADC Right" },
+	{ "HAL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HAL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HAL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HAL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "HAL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "HAL DAC", NULL, "HAL Mixer" },
+
+	{ "HAR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HAR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HAR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HAR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HAR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HAR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HAR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HAR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "HAR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HAR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HAR Mixer", "ADCL Switch", "ADC Left" },
+	{ "HAR Mixer", "ADCR Switch", "ADC Right" },
+	{ "HAR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HAR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HAR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HAR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "HAR Mixer", "Sideton Switch", "Sidetone" },
+
+	{ "HAR DAC", NULL, "HAR Mixer" },
+
+	{ "HAOUTL", "Haptic Left Switch", "HAL DAC" },
+	{ "HAOUTR", "Haptic Right Switch", "HAR DAC" },
+
+	/* Lineout map */
+	{ "LOL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LOL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LOL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LOL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LOL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LOL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LOL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LOL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LOL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LOL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LOL Mixer", "ADCL Switch", "ADC Left" },
+	{ "LOL Mixer", "ADCR Switch", "ADC Right" },
+	{ "LOL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LOL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LOL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LOL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LOL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LOL DAC", NULL, "LOL Mixer" },
+
+	{ "LOR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LOR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LOR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LOR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LOR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LOR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LOR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LOR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LOR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LOR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LOR Mixer", "ADCL Switch", "ADC Left" },
+	{ "LOR Mixer", "ADCR Switch", "ADC Right" },
+	{ "LOR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LOR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LOR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LOR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LOR Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LOR DAC", NULL, "LOR Mixer" },
+
+	{ "LOOUTL", NULL, "LOL DAC" },
+	{ "LOOUTR", NULL, "LOR DAC" },
+
+	/* TX map */
+	/* Port1 mappings */
+	{ "Port1_1 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_1 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_2 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_2 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_3 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_3 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_3 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_3 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_3 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_3 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_4 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_4 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_4 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_4 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_4 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_4 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_5 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_5 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_5 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_5 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_5 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_5 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_6 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_6 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_6 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_6 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_6 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_6 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_7 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_7 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_7 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_7 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_7 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_7 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_8 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_8 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_8 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_8 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_8 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_8 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port2_1 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port2_1 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port2_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port2_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port2_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port2_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port2_2 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port2_2 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port2_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port2_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port2_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port2_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "P1_1_TX", NULL, "Port1_1 Mixer" },
+	{ "P1_2_TX", NULL, "Port1_2 Mixer" },
+	{ "P1_3_TX", NULL, "Port1_3 Mixer" },
+	{ "P1_4_TX", NULL, "Port1_4 Mixer" },
+	{ "P1_5_TX", NULL, "Port1_5 Mixer" },
+	{ "P1_6_TX", NULL, "Port1_6 Mixer" },
+	{ "P1_7_TX", NULL, "Port1_7 Mixer" },
+	{ "P1_8_TX", NULL, "Port1_8 Mixer" },
+
+	{ "P2_1_TX", NULL, "Port2_1 Mixer" },
+	{ "P2_2_TX", NULL, "Port2_2 Mixer" },
+
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_1_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_2_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_3_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_4_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_5_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_6_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_7_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_8_TX"},
+
+	{ "PORT2_SDO", "Port2 Capture Switch", "P2_1_TX"},
+	{ "PORT2_SDO", "Port2 Capture Switch", "P2_2_TX"},
+
+	{ "Mic1 Input", NULL, "AMIC1" },
+	{ "Mic2 Input", NULL, "AMIC2" },
+
+	{ "AUXL Input", NULL, "AUXL" },
+	{ "AUXR Input", NULL, "AUXR" },
+
+	/* AUX connections */
+	{ "ADCL Mux", "Aux_L", "AUXL Input" },
+	{ "ADCL Mux", "MIC1", "Mic1 Input" },
+
+	{ "ADCR Mux", "Aux_R", "AUXR Input" },
+	{ "ADCR Mux", "MIC2", "Mic2 Input" },
+
+	/* ADC connection */
+	{ "ADC Left", NULL, "ADCL Mux"},
+	{ "ADC Right", NULL, "ADCR Mux"},
+
+	{ "DMIC1 Left", NULL, "DMIC1DAT"},
+	{ "DMIC1 Right", NULL, "DMIC1DAT"},
+	{ "DMIC2 Left", NULL, "DMIC2DAT"},
+	{ "DMIC2 Right", NULL, "DMIC2DAT"},
+
+	/* Sidetone map */
+	{ "Sidetone Mixer", NULL, "ADC Left" },
+	{ "Sidetone Mixer", NULL, "ADC Right" },
+	{ "Sidetone Mixer", NULL, "DMIC1 Left" },
+	{ "Sidetone Mixer", NULL, "DMIC1 Right" },
+	{ "Sidetone Mixer", NULL, "DMIC2 Left" },
+	{ "Sidetone Mixer", NULL, "DMIC2 Right" },
+
+	{ "Sidetone", "Sidetone Switch", "Sidetone Mixer" },
+};
+
+static int lm49453_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 lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+	u16 clk_div = 0;
+
+	lm49453->fs_rate = params_rate(params);
+
+	/* Setting DAC clock dividers based on substream sample rate. */
+	switch (lm49453->fs_rate) {
+	case 8000:
+	case 16000:
+	case 32000:
+	case 24000:
+	case 48000:
+		clk_div = 256;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk_div = 216;
+		break;
+	case 96000:
+		clk_div = 127;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, LM49453_P0_ADC_CLK_DIV_REG, clk_div);
+	snd_soc_write(codec, LM49453_P0_DAC_HP_CLK_DIV_REG, clk_div);
+
+	return 0;
+}
+
+static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	u16 aif_val;
+	int mode = 0;
+	int clk_phase = 0;
+	int clk_shift = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aif_val = 0;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aif_val = LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS |
+			  LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		mode = 1;
+		clk_phase = (1 << 5);
+		clk_shift = 1;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		mode = 1;
+		clk_phase = (1 << 5);
+		clk_shift = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG,
+			    LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(1)|BIT(5),
+			    (aif_val | mode | clk_phase));
+
+	snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift);
+
+	return 0;
+}
+
+static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				  unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 pll_clk = 0;
+
+	switch (freq) {
+	case 12288000:
+	case 26000000:
+	case 19200000:
+		/* pll clk slection */
+		pll_clk = 0;
+		break;
+	case 48000:
+	case 32576:
+		/* fll clk slection */
+		pll_clk = BIT(4);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG, BIT(4), pll_clk);
+
+	return 0;
+}
+
+static int lm49453_hp_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(1)|BIT(0),
+			    (mute ? (BIT(1)|BIT(0)) : 0));
+	return 0;
+}
+
+static int lm49453_lo_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(3)|BIT(2),
+			    (mute ? (BIT(3)|BIT(2)) : 0));
+	return 0;
+}
+
+static int lm49453_ls_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(5)|BIT(4),
+			    (mute ? (BIT(5)|BIT(4)) : 0));
+	return 0;
+}
+
+static int lm49453_ep_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(4),
+			    (mute ? BIT(4) : 0));
+	return 0;
+}
+
+static int lm49453_ha_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(7)|BIT(6),
+			    (mute ? (BIT(7)|BIT(6)) : 0));
+	return 0;
+}
+
+static int lm49453_set_bias_level(struct snd_soc_codec *codec,
+				  enum snd_soc_bias_level level)
+{
+	struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+			regcache_sync(lm49453->regmap);
+
+		snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+				    LM49453_PMC_SETUP_CHIP_EN, LM49453_CHIP_EN);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+				    LM49453_PMC_SETUP_CHIP_EN, 0);
+		break;
+	}
+
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+/* Formates supported by LM49453 driver. */
+#define LM49453_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 lm49453_headset_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_hp_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_speaker_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_ls_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_haptic_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_ha_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_ep_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_ep_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_lo_mute,
+};
+
+/* LM49453 dai structure. */
+static const struct snd_soc_dai_driver lm49453_dai[] = {
+	{
+		.name = "LM49453 Headset",
+		.playback = {
+			.stream_name = "Headset",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 5,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_headset_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "LM49453 Speaker",
+		.playback = {
+			.stream_name = "Speaker",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_speaker_dai_ops,
+	},
+	{
+		.name = "LM49453 Haptic",
+		.playback = {
+			.stream_name = "Haptic",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_haptic_dai_ops,
+	},
+	{
+		.name = "LM49453 Earpiece",
+		.playback = {
+			.stream_name = "Earpiece",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_ep_dai_ops,
+	},
+	{
+		.name = "LM49453 line out",
+		.playback = {
+			.stream_name = "Lineout",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_lineout_dai_ops,
+	},
+};
+
+static int lm49453_suspend(struct snd_soc_codec *codec)
+{
+	lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int lm49453_resume(struct snd_soc_codec *codec)
+{
+	lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
+}
+
+static int lm49453_probe(struct snd_soc_codec *codec)
+{
+	struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	codec->control_data = lm49453->regmap;
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* power down chip */
+static int lm49453_remove(struct snd_soc_codec *codec)
+{
+	lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
+	.probe = lm49453_probe,
+	.remove = lm49453_remove,
+	.suspend = lm49453_suspend,
+	.resume = lm49453_resume,
+	.set_bias_level = lm49453_set_bias_level,
+	.controls = lm49453_snd_controls,
+	.num_controls = ARRAY_SIZE(lm49453_snd_controls),
+	.dapm_widgets = lm49453_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(lm49453_dapm_widgets),
+	.dapm_routes = lm49453_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(lm49453_audio_map),
+	.idle_bias_off = true,
+};
+
+static const struct regmap_config lm49453_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = LM49453_MAX_REGISTER,
+	.reg_defaults = lm49453_reg_defs,
+	.num_reg_defaults = ARRAY_SIZE(lm49453_reg_defs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int lm49453_i2c_probe(struct i2c_client *i2c,
+				       const struct i2c_device_id *id)
+{
+	struct lm49453_priv *lm49453;
+	int ret = 0;
+
+	lm49453 = devm_kzalloc(&i2c->dev, sizeof(struct lm49453_priv),
+				GFP_KERNEL);
+
+	if (lm49453 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, lm49453);
+
+	lm49453->regmap = regmap_init_i2c(i2c, &lm49453_regmap_config);
+	if (IS_ERR(lm49453->regmap)) {
+		ret = PTR_ERR(lm49453->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret =  snd_soc_register_codec(&i2c->dev,
+				      &soc_codec_dev_lm49453,
+				      lm49453_dai, ARRAY_SIZE(lm49453_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		regmap_exit(lm49453->regmap);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int __devexit lm49453_i2c_remove(struct i2c_client *client)
+{
+	struct lm49453_priv *lm49453 = i2c_get_clientdata(client);
+
+	snd_soc_unregister_codec(&client->dev);
+	regmap_exit(lm49453->regmap);
+	return 0;
+}
+
+static const struct i2c_device_id lm49453_i2c_id[] = {
+	{ "lm49453", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm49453_i2c_id);
+
+static struct i2c_driver lm49453_i2c_driver = {
+	.driver = {
+		.name = "lm49453",
+		.owner = THIS_MODULE,
+	},
+	.probe = lm49453_i2c_probe,
+	.remove = __devexit_p(lm49453_i2c_remove),
+	.id_table = lm49453_i2c_id,
+};
+
+module_i2c_driver(lm49453_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC LM49453 driver");
+MODULE_AUTHOR("M R Swami Reddy <MR.Swami.Reddy@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/lm49453.h b/sound/soc/codecs/lm49453.h
new file mode 100644
index 0000000..a63cfa5
--- /dev/null
+++ b/sound/soc/codecs/lm49453.h
@@ -0,0 +1,380 @@
+/*
+ * lm49453.h  -  LM49453 ALSA Soc Audio drive
+ *
+ * Copyright (c) 2012  Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#ifndef _LM49453_H
+#define _LM49453_H
+
+#include <linux/bitops.h>
+
+/* LM49453_P0 register space for page0 */
+#define LM49453_P0_PMC_SETUP_REG			0x00
+#define LM49453_P0_PLL_CLK_SEL1_REG			0x01
+#define LM49453_P0_PLL_CLK_SEL2_REG			0x02
+#define LM49453_P0_PMC_CLK_DIV_REG			0x03
+#define LM49453_P0_HSDET_CLK_DIV_REG			0x04
+#define LM49453_P0_DMIC_CLK_DIV_REG			0x05
+#define LM49453_P0_ADC_CLK_DIV_REG			0x06
+#define LM49453_P0_DAC_OT_CLK_DIV_REG			0x07
+#define LM49453_P0_PLL_HF_M_REG				0x08
+#define LM49453_P0_PLL_LF_M_REG				0x09
+#define LM49453_P0_PLL_NL_REG				0x0A
+#define LM49453_P0_PLL_N_MODL_REG			0x0B
+#define LM49453_P0_PLL_N_MODH_REG			0x0C
+#define LM49453_P0_PLL_P1_REG				0x0D
+#define LM49453_P0_PLL_P2_REG				0x0E
+#define LM49453_P0_FLL_REF_FREQL_REG			0x0F
+#define LM49453_P0_FLL_REF_FREQH_REG			0x10
+#define LM49453_P0_VCO_TARGETLL_REG			0x11
+#define LM49453_P0_VCO_TARGETLH_REG			0x12
+#define LM49453_P0_VCO_TARGETHL_REG			0x13
+#define LM49453_P0_VCO_TARGETHH_REG			0x14
+#define LM49453_P0_PLL_CONFIG_REG			0x15
+#define LM49453_P0_DAC_CLK_SEL_REG			0x16
+#define LM49453_P0_DAC_HP_CLK_DIV_REG			0x17
+
+/* Analog Mixer Input Stages */
+#define LM49453_P0_MICL_REG				0x20
+#define LM49453_P0_MICR_REG				0x21
+#define LM49453_P0_EP_REG				0x24
+#define LM49453_P0_DIS_PKVL_FB_REG			0x25
+
+/* Analog Mixer Output Stages */
+#define LM49453_P0_ANALOG_MIXER_ADC_REG			0x2E
+
+/*ADC or DAC */
+#define LM49453_P0_ADC_DSP_REG				0x30
+#define LM49453_P0_DAC_DSP_REG				0x31
+
+/* EFFECTS ENABLES */
+#define LM49453_P0_ADC_FX_ENABLES_REG			0x33
+
+/* GPIO */
+#define LM49453_P0_GPIO1_REG				0x38
+#define LM49453_P0_GPIO2_REG				0x39
+#define LM49453_P0_GPIO3_REG				0x3A
+#define LM49453_P0_HAP_CTL_REG				0x3B
+#define LM49453_P0_HAP_FREQ_PROG_LEFTL_REG		0x3C
+#define LM49453_P0_HAP_FREQ_PROG_LEFTH_REG		0x3D
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTL_REG		0x3E
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTH_REG		0x3F
+
+/* DIGITAL MIXER */
+#define LM49453_P0_DMIX_CLK_SEL_REG			0x40
+#define LM49453_P0_PORT1_RX_LVL1_REG			0x41
+#define LM49453_P0_PORT1_RX_LVL2_REG			0x42
+#define LM49453_P0_PORT2_RX_LVL_REG			0x43
+#define LM49453_P0_PORT1_TX1_REG			0x44
+#define LM49453_P0_PORT1_TX2_REG			0x45
+#define LM49453_P0_PORT1_TX3_REG			0x46
+#define LM49453_P0_PORT1_TX4_REG			0x47
+#define LM49453_P0_PORT1_TX5_REG			0x48
+#define LM49453_P0_PORT1_TX6_REG			0x49
+#define LM49453_P0_PORT1_TX7_REG			0x4A
+#define LM49453_P0_PORT1_TX8_REG			0x4B
+#define LM49453_P0_PORT2_TX1_REG			0x4C
+#define LM49453_P0_PORT2_TX2_REG			0x4D
+#define LM49453_P0_STN_SEL_REG				0x4F
+#define LM49453_P0_DACHPL1_REG				0x50
+#define LM49453_P0_DACHPL2_REG				0x51
+#define LM49453_P0_DACHPR1_REG				0x52
+#define LM49453_P0_DACHPR2_REG				0x53
+#define LM49453_P0_DACLOL1_REG				0x54
+#define LM49453_P0_DACLOL2_REG				0x55
+#define LM49453_P0_DACLOR1_REG				0x56
+#define LM49453_P0_DACLOR2_REG				0x57
+#define LM49453_P0_DACLSL1_REG				0x58
+#define LM49453_P0_DACLSL2_REG				0x59
+#define LM49453_P0_DACLSR1_REG				0x5A
+#define LM49453_P0_DACLSR2_REG				0x5B
+#define LM49453_P0_DACHAL1_REG				0x5C
+#define LM49453_P0_DACHAL2_REG				0x5D
+#define LM49453_P0_DACHAR1_REG				0x5E
+#define LM49453_P0_DACHAR2_REG				0x5F
+
+/* AUDIO PORT 1 (TDM) */
+#define LM49453_P0_AUDIO_PORT1_BASIC_REG		0x60
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN1_REG		0x61
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN2_REG		0x62
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN3_REG		0x63
+#define LM49453_P0_AUDIO_PORT1_SYNC_RATE_REG		0x64
+#define LM49453_P0_AUDIO_PORT1_SYNC_SDO_SETUP_REG	0x65
+#define LM49453_P0_AUDIO_PORT1_DATA_WIDTH_REG		0x66
+#define LM49453_P0_AUDIO_PORT1_RX_MSB_REG		0x67
+#define LM49453_P0_AUDIO_PORT1_TX_MSB_REG		0x68
+#define LM49453_P0_AUDIO_PORT1_TDM_CHANNELS_REG		0x69
+
+/* AUDIO PORT 2 */
+#define LM49453_P0_AUDIO_PORT2_BASIC_REG		0x6A
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN1_REG		0x6B
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN2_REG		0x6C
+#define LM49453_P0_AUDIO_PORT2_SYNC_GEN_REG		0x6D
+#define LM49453_P0_AUDIO_PORT2_DATA_WIDTH_REG		0x6E
+#define LM49453_P0_AUDIO_PORT2_RX_MODE_REG		0x6F
+#define LM49453_P0_AUDIO_PORT2_TX_MODE_REG		0x70
+
+/* SAMPLE RATE */
+#define LM49453_P0_PORT1_SR_LSB_REG			0x79
+#define LM49453_P0_PORT1_SR_MSB_REG			0x7A
+#define LM49453_P0_PORT2_SR_LSB_REG			0x7B
+#define LM49453_P0_PORT2_SR_MSB_REG			0x7C
+
+/* EFFECTS - HPFs */
+#define LM49453_P0_HPF_REG				0x80
+
+/* EFFECTS ADC ALC */
+#define LM49453_P0_ADC_ALC1_REG				0x82
+#define LM49453_P0_ADC_ALC2_REG				0x83
+#define LM49453_P0_ADC_ALC3_REG				0x84
+#define LM49453_P0_ADC_ALC4_REG				0x85
+#define LM49453_P0_ADC_ALC5_REG				0x86
+#define LM49453_P0_ADC_ALC6_REG				0x87
+#define LM49453_P0_ADC_ALC7_REG				0x88
+#define LM49453_P0_ADC_ALC8_REG				0x89
+#define LM49453_P0_DMIC1_LEVELL_REG			0x8A
+#define LM49453_P0_DMIC1_LEVELR_REG			0x8B
+#define LM49453_P0_DMIC2_LEVELL_REG			0x8C
+#define LM49453_P0_DMIC2_LEVELR_REG			0x8D
+#define LM49453_P0_ADC_LEVELL_REG			0x8E
+#define LM49453_P0_ADC_LEVELR_REG			0x8F
+#define LM49453_P0_DAC_HP_LEVELL_REG			0x90
+#define LM49453_P0_DAC_HP_LEVELR_REG			0x91
+#define LM49453_P0_DAC_LO_LEVELL_REG			0x92
+#define LM49453_P0_DAC_LO_LEVELR_REG			0x93
+#define LM49453_P0_DAC_LS_LEVELL_REG			0x94
+#define LM49453_P0_DAC_LS_LEVELR_REG			0x95
+#define LM49453_P0_DAC_HA_LEVELL_REG			0x96
+#define LM49453_P0_DAC_HA_LEVELR_REG			0x97
+#define LM49453_P0_SOFT_MUTE_REG			0x98
+#define LM49453_P0_DMIC_MUTE_CFG_REG			0x99
+#define LM49453_P0_ADC_MUTE_CFG_REG			0x9A
+#define LM49453_P0_DAC_MUTE_CFG_REG			0x9B
+
+/*DIGITAL MIC1 */
+#define LM49453_P0_DIGITAL_MIC1_CONFIG_REG		0xB0
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYL_REG		0xB1
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYR_REG		0xB2
+
+/*DIGITAL MIC2 */
+#define LM49453_P0_DIGITAL_MIC2_CONFIG_REG		0xB3
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYL_REG		0xB4
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYR_REG		0xB5
+
+/* ADC DECIMATOR */
+#define LM49453_P0_ADC_DECIMATOR_REG			0xB6
+
+/* DAC CONFIGURE */
+#define LM49453_P0_DAC_CONFIG_REG			0xB7
+
+/* SIDETONE */
+#define LM49453_P0_STN_VOL_ADCL_REG			0xB8
+#define LM49453_P0_STN_VOL_ADCR_REG			0xB9
+#define LM49453_P0_STN_VOL_DMIC1L_REG			0xBA
+#define LM49453_P0_STN_VOL_DMIC1R_REG			0xBB
+#define LM49453_P0_STN_VOL_DMIC2L_REG			0xBC
+#define LM49453_P0_STN_VOL_DMIC2R_REG			0xBD
+
+/* ADC/DAC CLIPPING MONITORS (Read Only/Write to Clear) */
+#define LM49453_P0_ADC_DEC_CLIP_REG			0xC2
+#define LM49453_P0_ADC_HPF_CLIP_REG			0xC3
+#define LM49453_P0_ADC_LVL_CLIP_REG			0xC4
+#define LM49453_P0_DAC_LVL_CLIP_REG			0xC5
+
+/* ADC ALC EFFECT MONITORS (Read Only) */
+#define LM49453_P0_ADC_LVLMONL_REG			0xC8
+#define LM49453_P0_ADC_LVLMONR_REG			0xC9
+#define LM49453_P0_ADC_ALCMONL_REG			0xCA
+#define LM49453_P0_ADC_ALCMONR_REG			0xCB
+#define LM49453_P0_ADC_MUTED_REG			0xCC
+#define LM49453_P0_DAC_MUTED_REG			0xCD
+
+/* HEADSET DETECT */
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITL_REG		0xD0
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITR_REG		0xD1
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITL_REG	0xD2
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITH_REG	0xD3
+#define LM49453_P0_HSD_TIMEOUT1_REG			0xD4
+#define LM49453_P0_HSD_TIMEOUT2_REG			0xD5
+#define LM49453_P0_HSD_TIMEOUT3_REG			0xD6
+#define LM49453_P0_HSD_PIN3_4_CFG_REG			0xD7
+#define LM49453_P0_HSD_IRQ1_REG				0xD8
+#define LM49453_P0_HSD_IRQ2_REG				0xD9
+#define LM49453_P0_HSD_IRQ3_REG				0xDA
+#define LM49453_P0_HSD_IRQ4_REG				0xDB
+#define LM49453_P0_HSD_IRQ_MASK1_REG			0xDC
+#define LM49453_P0_HSD_IRQ_MASK2_REG			0xDD
+#define LM49453_P0_HSD_IRQ_MASK3_REG			0xDE
+#define LM49453_P0_HSD_R_HPLL_REG			0xE0
+#define LM49453_P0_HSD_R_HPLH_REG			0xE1
+#define LM49453_P0_HSD_R_HPLU_REG			0xE2
+#define LM49453_P0_HSD_R_HPRL_REG			0xE3
+#define LM49453_P0_HSD_R_HPRH_REG			0xE4
+#define LM49453_P0_HSD_R_HPRU_REG			0xE5
+#define LM49453_P0_HSD_VEL_L_FINALL_REG			0xE6
+#define LM49453_P0_HSD_VEL_L_FINALH_REG			0xE7
+#define LM49453_P0_HSD_VEL_L_FINALU_REG			0xE8
+#define LM49453_P0_HSD_RO_FINALL_REG			0xE9
+#define LM49453_P0_HSD_RO_FINALH_REG			0xEA
+#define LM49453_P0_HSD_RO_FINALU_REG			0xEB
+#define LM49453_P0_HSD_VMIC_BIAS_FINALL_REG		0xEC
+#define LM49453_P0_HSD_VMIC_BIAS_FINALH_REG		0xED
+#define LM49453_P0_HSD_VMIC_BIAS_FINALU_REG		0xEE
+#define LM49453_P0_HSD_PIN_CONFIG_REG			0xEF
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS1_REG	0xF1
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS2_REG	0xF2
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS3_REG	0xF3
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEL_REG	0xF4
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEH_REG	0xF5
+
+/* I/O PULLDOWN CONFIG */
+#define LM49453_P0_PULL_CONFIG1_REG			0xF8
+#define LM49453_P0_PULL_CONFIG2_REG			0xF9
+#define LM49453_P0_PULL_CONFIG3_REG			0xFA
+
+/* RESET */
+#define LM49453_P0_RESET_REG				0xFE
+
+/* PAGE */
+#define LM49453_PAGE_REG				0xFF
+
+#define LM49453_MAX_REGISTER				(0xFF+1)
+
+/* LM49453_P0_PMC_SETUP_REG (0x00h) */
+#define LM49453_PMC_SETUP_CHIP_EN			(BIT(1)|BIT(0))
+#define LM49453_PMC_SETUP_PLL_EN			BIT(2)
+#define LM49453_PMC_SETUP_PLL_P2_EN			BIT(3)
+#define LM49453_PMC_SETUP_PLL_FLL			BIT(4)
+#define LM49453_PMC_SETUP_MCLK_OVER			BIT(5)
+#define LM49453_PMC_SETUP_RTC_CLK_OVER			BIT(6)
+#define LM49453_PMC_SETUP_CHIP_ACTIVE			BIT(7)
+
+/* Chip Enable bits */
+#define LM49453_CHIP_EN_SHUTDOWN			0x00
+#define LM49453_CHIP_EN					0x01
+#define LM49453_CHIP_EN_HSD_DETECT			0x02
+#define LM49453_CHIP_EN_INVALID_HSD			0x03
+
+/* LM49453_P0_PLL_CLK_SEL1_REG (0x01h) */
+#define LM49453_CLK_SEL1_MCLK_SEL			0x11
+#define LM49453_CLK_SEL1_RTC_SEL			0x11
+#define LM49453_CLK_SEL1_PORT1_SEL			0x10
+#define LM49453_CLK_SEL1_PORT2_SEL			0x11
+
+/* LM49453_P0_PLL_CLK_SEL2_REG (0x02h) */
+#define LM49453_CLK_SEL2_ADC_CLK_SEL			0x38
+
+/* LM49453_P0_FLL_REF_FREQL_REG (0x0F) */
+#define LM49453_FLL_REF_FREQ_VAL			0x8ca0001
+
+/* LM49453_P0_VCO_TARGETLL_REG (0x11) */
+#define LM49453_VCO_TARGET_VAL				0x8ca0001
+
+/* LM49453_P0_ADC_DSP_REG (0x30h) */
+#define LM49453_ADC_DSP_ADC_MUTEL			BIT(0)
+#define LM49453_ADC_DSP_ADC_MUTER			BIT(1)
+#define LM49453_ADC_DSP_DMIC1_MUTEL			BIT(2)
+#define LM49453_ADC_DSP_DMIC1_MUTER			BIT(3)
+#define LM49453_ADC_DSP_DMIC2_MUTEL			BIT(4)
+#define LM49453_ADC_DSP_DMIC2_MUTER			BIT(5)
+#define LM49453_ADC_DSP_MUTE_ALL			0x3F
+
+/* LM49453_P0_DAC_DSP_REG (0x31h) */
+#define LM49453_DAC_DSP_MUTE_ALL			0xFF
+
+/* LM49453_P0_AUDIO_PORT1_BASIC_REG (0x60h) */
+#define LM49453_AUDIO_PORT1_BASIC_FMT_MASK		(BIT(4)|BIT(3))
+#define LM49453_AUDIO_PORT1_BASIC_CLK_MS		BIT(3)
+#define LM49453_AUDIO_PORT1_BASIC_SYNC_MS		BIT(4)
+
+/* LM49453_P0_RESET_REG (0xFEh) */
+#define LM49453_RESET_REG_RST				BIT(0)
+
+/* Page select register bits (0xFF) */
+#define LM49453_PAGE0_SELECT				0x0
+#define LM49453_PAGE1_SELECT				0x1
+
+/* LM49453_P0_HSD_PIN3_4_CFG_REG (Jack Pin config - 0xD7) */
+#define LM49453_JACK_DISABLE				0x00
+#define LM49453_JACK_CONFIG1				0x01
+#define LM49453_JACK_CONFIG2				0x02
+#define LM49453_JACK_CONFIG3				0x03
+#define LM49453_JACK_CONFIG4				0x04
+#define LM49453_JACK_CONFIG5				0x05
+
+/* Page 1 REGISTERS */
+
+/* SIDETONE */
+#define LM49453_P1_SIDETONE_SA0L_REG			0x80
+#define LM49453_P1_SIDETONE_SA0H_REG			0x81
+#define LM49453_P1_SIDETONE_SAB0U_REG			0x82
+#define LM49453_P1_SIDETONE_SB0L_REG			0x83
+#define LM49453_P1_SIDETONE_SB0H_REG			0x84
+#define LM49453_P1_SIDETONE_SH0L_REG			0x85
+#define LM49453_P1_SIDETONE_SH0H_REG			0x86
+#define LM49453_P1_SIDETONE_SH0U_REG			0x87
+#define LM49453_P1_SIDETONE_SA1L_REG			0x88
+#define LM49453_P1_SIDETONE_SA1H_REG			0x89
+#define LM49453_P1_SIDETONE_SAB1U_REG			0x8A
+#define LM49453_P1_SIDETONE_SB1L_REG			0x8B
+#define LM49453_P1_SIDETONE_SB1H_REG			0x8C
+#define LM49453_P1_SIDETONE_SH1L_REG			0x8D
+#define LM49453_P1_SIDETONE_SH1H_REG			0x8E
+#define LM49453_P1_SIDETONE_SH1U_REG			0x8F
+#define LM49453_P1_SIDETONE_SA2L_REG			0x90
+#define LM49453_P1_SIDETONE_SA2H_REG			0x91
+#define LM49453_P1_SIDETONE_SAB2U_REG			0x92
+#define LM49453_P1_SIDETONE_SB2L_REG			0x93
+#define LM49453_P1_SIDETONE_SB2H_REG			0x94
+#define LM49453_P1_SIDETONE_SH2L_REG			0x95
+#define LM49453_P1_SIDETONE_SH2H_REG			0x96
+#define LM49453_P1_SIDETONE_SH2U_REG			0x97
+#define LM49453_P1_SIDETONE_SA3L_REG			0x98
+#define LM49453_P1_SIDETONE_SA3H_REG			0x99
+#define LM49453_P1_SIDETONE_SAB3U_REG			0x9A
+#define LM49453_P1_SIDETONE_SB3L_REG			0x9B
+#define LM49453_P1_SIDETONE_SB3H_REG			0x9C
+#define LM49453_P1_SIDETONE_SH3L_REG			0x9D
+#define LM49453_P1_SIDETONE_SH3H_REG			0x9E
+#define LM49453_P1_SIDETONE_SH3U_REG			0x9F
+#define LM49453_P1_SIDETONE_SA4L_REG			0xA0
+#define LM49453_P1_SIDETONE_SA4H_REG			0xA1
+#define LM49453_P1_SIDETONE_SAB4U_REG			0xA2
+#define LM49453_P1_SIDETONE_SB4L_REG			0xA3
+#define LM49453_P1_SIDETONE_SB4H_REG			0xA4
+#define LM49453_P1_SIDETONE_SH4L_REG			0xA5
+#define LM49453_P1_SIDETONE_SH4H_REG			0xA6
+#define LM49453_P1_SIDETONE_SH4U_REG			0xA7
+#define LM49453_P1_SIDETONE_SA5L_REG			0xA8
+#define LM49453_P1_SIDETONE_SA5H_REG			0xA9
+#define LM49453_P1_SIDETONE_SAB5U_REG			0xAA
+#define LM49453_P1_SIDETONE_SB5L_REG			0xAB
+#define LM49453_P1_SIDETONE_SB5H_REG			0xAC
+#define LM49453_P1_SIDETONE_SH5L_REG			0xAD
+#define LM49453_P1_SIDETONE_SH5H_REG			0xAE
+#define LM49453_P1_SIDETONE_SH5U_REG			0xAF
+
+/* CHARGE PUMP CONFIG */
+#define LM49453_P1_CP_CONFIG1_REG			0xB0
+#define LM49453_P1_CP_CONFIG2_REG			0xB1
+#define LM49453_P1_CP_CONFIG3_REG			0xB2
+#define LM49453_P1_CP_CONFIG4_REG			0xB3
+#define LM49453_P1_CP_LA_VTH1L_REG			0xB4
+#define LM49453_P1_CP_LA_VTH1M_REG			0xB5
+#define LM49453_P1_CP_LA_VTH2L_REG			0xB6
+#define LM49453_P1_CP_LA_VTH2M_REG			0xB7
+#define LM49453_P1_CP_LA_VTH3L_REG			0xB8
+#define LM49453_P1_CP_LA_VTH3H_REG			0xB9
+#define LM49453_P1_CP_CLK_DIV_REG			0xBA
+
+/* DAC */
+#define LM49453_P1_DAC_CHOP_REG				0xC0
+
+#define	LM49453_CLK_SRC_MCLK				1
+#endif
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 0bb511a..35179e2 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <asm/div64.h>
 #include <sound/max98095.h>
+#include <sound/jack.h>
 #include "max98095.h"
 
 enum max98095_type {
@@ -51,6 +52,8 @@
 	u8 lin_state;
 	unsigned int mic1pre;
 	unsigned int mic2pre;
+	struct snd_soc_jack *headphone_jack;
+	struct snd_soc_jack *mic_jack;
 };
 
 static const u8 max98095_reg_def[M98095_REG_CNT] = {
@@ -2173,9 +2176,125 @@
 		max98095_handle_bq_pdata(codec);
 }
 
+static irqreturn_t max98095_report_jack(int irq, void *data)
+{
+	struct snd_soc_codec *codec = data;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	unsigned int value;
+	int hp_report = 0;
+	int mic_report = 0;
+
+	/* Read the Jack Status Register */
+	value = snd_soc_read(codec, M98095_007_JACK_AUTO_STS);
+
+	/* If ddone is not set, then detection isn't finished yet */
+	if ((value & M98095_DDONE) == 0)
+		return IRQ_NONE;
+
+	/* if hp, check its bit, and if set, clear it */
+	if ((value & M98095_HP_IN || value & M98095_LO_IN) &&
+		max98095->headphone_jack)
+		hp_report |= SND_JACK_HEADPHONE;
+
+	/* if mic, check its bit, and if set, clear it */
+	if ((value & M98095_MIC_IN) && max98095->mic_jack)
+		mic_report |= SND_JACK_MICROPHONE;
+
+	if (max98095->headphone_jack == max98095->mic_jack) {
+		snd_soc_jack_report(max98095->headphone_jack,
+					hp_report | mic_report,
+					SND_JACK_HEADSET);
+	} else {
+		if (max98095->headphone_jack)
+			snd_soc_jack_report(max98095->headphone_jack,
+					hp_report, SND_JACK_HEADPHONE);
+		if (max98095->mic_jack)
+			snd_soc_jack_report(max98095->mic_jack,
+					mic_report, SND_JACK_MICROPHONE);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int max98095_jack_detect_enable(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+	int detect_enable = M98095_JDEN;
+	unsigned int slew = M98095_DEFAULT_SLEW_DELAY;
+
+	if (max98095->pdata->jack_detect_pin5en)
+		detect_enable |= M98095_PIN5EN;
+
+	if (max98095->pdata->jack_detect_delay)
+		slew = max98095->pdata->jack_detect_delay;
+
+	ret = snd_soc_write(codec, M98095_08E_JACK_DC_SLEW, slew);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+		return ret;
+	}
+
+	/* configure auto detection to be enabled */
+	ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, detect_enable);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+int max98095_jack_detect_disable(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+
+	/* configure auto detection to be disabled */
+	ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, 0x0);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+int max98095_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *client = to_i2c_client(codec->dev);
+	int ret = 0;
+
+	max98095->headphone_jack = hp_jack;
+	max98095->mic_jack = mic_jack;
+
+	/* only progress if we have at least 1 jack pointer */
+	if (!hp_jack && !mic_jack)
+		return -EINVAL;
+
+	max98095_jack_detect_enable(codec);
+
+	/* enable interrupts for headphone jack detection */
+	ret = snd_soc_update_bits(codec, M98095_013_JACK_INT_EN,
+		M98095_IDDONE, M98095_IDDONE);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to cfg jack irqs %d\n", ret);
+		return ret;
+	}
+
+	max98095_report_jack(client->irq, codec);
+	return 0;
+}
+
 #ifdef CONFIG_PM
 static int max98095_suspend(struct snd_soc_codec *codec)
 {
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	if (max98095->headphone_jack || max98095->mic_jack)
+		max98095_jack_detect_disable(codec);
+
 	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	return 0;
@@ -2183,8 +2302,16 @@
 
 static int max98095_resume(struct snd_soc_codec *codec)
 {
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *client = to_i2c_client(codec->dev);
+
 	max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+	if (max98095->headphone_jack || max98095->mic_jack) {
+		max98095_jack_detect_enable(codec);
+		max98095_report_jack(client->irq, codec);
+	}
+
 	return 0;
 }
 #else
@@ -2227,6 +2354,7 @@
 {
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	struct max98095_cdata *cdata;
+	struct i2c_client *client;
 	int ret = 0;
 
 	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
@@ -2238,6 +2366,8 @@
 	/* reset the codec, the DSP core, and disable all interrupts */
 	max98095_reset(codec);
 
+	client = to_i2c_client(codec->dev);
+
 	/* initialize private data */
 
 	max98095->sysclk = (unsigned)-1;
@@ -2266,11 +2396,23 @@
 	max98095->mic1pre = 0;
 	max98095->mic2pre = 0;
 
+	if (client->irq) {
+		/* register an audio interrupt */
+		ret = request_threaded_irq(client->irq, NULL,
+			max98095_report_jack,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			"max98095", codec);
+		if (ret) {
+			dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+			goto err_access;
+		}
+	}
+
 	ret = snd_soc_read(codec, M98095_0FF_REV_ID);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failure reading hardware revision: %d\n",
 			ret);
-		goto err_access;
+		goto err_irq;
 	}
 	dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A');
 
@@ -2306,14 +2448,28 @@
 
 	max98095_add_widgets(codec);
 
+	return 0;
+
+err_irq:
+	if (client->irq)
+		free_irq(client->irq, codec);
 err_access:
 	return ret;
 }
 
 static int max98095_remove(struct snd_soc_codec *codec)
 {
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *client = to_i2c_client(codec->dev);
+
 	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
+	if (max98095->headphone_jack || max98095->mic_jack)
+		max98095_jack_detect_disable(codec);
+
+	if (client->irq)
+		free_irq(client->irq, codec);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/max98095.h b/sound/soc/codecs/max98095.h
index 891584a..2ebbe4e 100644
--- a/sound/soc/codecs/max98095.h
+++ b/sound/soc/codecs/max98095.h
@@ -175,11 +175,23 @@
 
 /* MAX98095 Registers Bit Fields */
 
+/* M98095_007_JACK_AUTO_STS */
+	#define M98095_MIC_IN			(1<<3)
+	#define M98095_LO_IN			(1<<5)
+	#define M98095_HP_IN			(1<<6)
+	#define M98095_DDONE			(1<<7)
+
 /* M98095_00F_HOST_CFG */
 	#define M98095_SEG                      (1<<0)
 	#define M98095_XTEN                     (1<<1)
 	#define M98095_MDLLEN                   (1<<2)
 
+/* M98095_013_JACK_INT_EN */
+	#define M98095_IMIC_IN			(1<<3)
+	#define M98095_ILO_IN			(1<<5)
+	#define M98095_IHP_IN			(1<<6)
+	#define M98095_IDDONE			(1<<7)
+
 /* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
 	#define M98095_CLKMODE_MASK             0xFF
 
@@ -255,6 +267,10 @@
 	#define M98095_EQ2EN                    (1<<1)
 	#define M98095_EQ1EN                    (1<<0)
 
+/* M98095_089_JACK_DET_AUTO */
+	#define M98095_PIN5EN			(1<<2)
+	#define M98095_JDEN			(1<<7)
+
 /* M98095_090_PWR_EN_IN */
 	#define M98095_INEN                     (1<<7)
 	#define M98095_MB2EN                    (1<<3)
@@ -296,4 +312,10 @@
 #define M98095_174_DAI1_BQ_BASE             0x74
 #define M98095_17E_DAI2_BQ_BASE             0x7E
 
+/* Default Delay used in Slew Rate Calculation for Jack detection */
+#define M98095_DEFAULT_SLEW_DELAY		0x18
+
+extern int max98095_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
+
 #endif
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
new file mode 100644
index 0000000..6276e35
--- /dev/null
+++ b/sound/soc/codecs/mc13783.c
@@ -0,0 +1,786 @@
+/*
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ * Copyright 2009 Sascha Hauer, s.hauer@pengutronix.de
+ * Copyright 2012 Philippe Retornaz, philippe.retornaz@epfl.ch
+ *
+ * Initial development of this code was funded by
+ * Phytec Messtechnik GmbH, http://www.phytec.de
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mfd/mc13xxx.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/soc-dapm.h>
+
+#include "mc13783.h"
+
+#define MC13783_AUDIO_RX0	36
+#define MC13783_AUDIO_RX1	37
+#define MC13783_AUDIO_TX	38
+#define MC13783_SSI_NETWORK	39
+#define MC13783_AUDIO_CODEC	40
+#define MC13783_AUDIO_DAC	41
+
+#define AUDIO_RX0_ALSPEN		(1 << 5)
+#define AUDIO_RX0_ALSPSEL		(1 << 7)
+#define AUDIO_RX0_ADDCDC		(1 << 21)
+#define AUDIO_RX0_ADDSTDC		(1 << 22)
+#define AUDIO_RX0_ADDRXIN		(1 << 23)
+
+#define AUDIO_RX1_PGARXEN		(1 << 0);
+#define AUDIO_RX1_PGASTEN		(1 << 5)
+#define AUDIO_RX1_ARXINEN		(1 << 10)
+
+#define AUDIO_TX_AMC1REN		(1 << 5)
+#define AUDIO_TX_AMC1LEN		(1 << 7)
+#define AUDIO_TX_AMC2EN			(1 << 9)
+#define AUDIO_TX_ATXINEN		(1 << 11)
+#define AUDIO_TX_RXINREC		(1 << 13)
+
+#define SSI_NETWORK_CDCTXRXSLOT(x)	(((x) & 0x3) << 2)
+#define SSI_NETWORK_CDCTXSECSLOT(x)	(((x) & 0x3) << 4)
+#define SSI_NETWORK_CDCRXSECSLOT(x)	(((x) & 0x3) << 6)
+#define SSI_NETWORK_CDCRXSECGAIN(x)	(((x) & 0x3) << 8)
+#define SSI_NETWORK_CDCSUMGAIN(x)	(1 << 10)
+#define SSI_NETWORK_CDCFSDLY(x)		(1 << 11)
+#define SSI_NETWORK_DAC_SLOTS_8		(1 << 12)
+#define SSI_NETWORK_DAC_SLOTS_4		(2 << 12)
+#define SSI_NETWORK_DAC_SLOTS_2		(3 << 12)
+#define SSI_NETWORK_DAC_SLOT_MASK	(3 << 12)
+#define SSI_NETWORK_DAC_RXSLOT_0_1	(0 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_2_3	(1 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_4_5	(2 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_6_7	(3 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_MASK	(3 << 14)
+#define SSI_NETWORK_STDCRXSECSLOT(x)	(((x) & 0x3) << 16)
+#define SSI_NETWORK_STDCRXSECGAIN(x)	(((x) & 0x3) << 18)
+#define SSI_NETWORK_STDCSUMGAIN		(1 << 20)
+
+/*
+ * MC13783_AUDIO_CODEC and MC13783_AUDIO_DAC mostly share the same
+ * register layout
+ */
+#define AUDIO_SSI_SEL			(1 << 0)
+#define AUDIO_CLK_SEL			(1 << 1)
+#define AUDIO_CSM			(1 << 2)
+#define AUDIO_BCL_INV			(1 << 3)
+#define AUDIO_CFS_INV			(1 << 4)
+#define AUDIO_CFS(x)			(((x) & 0x3) << 5)
+#define AUDIO_CLK(x)			(((x) & 0x7) << 7)
+#define AUDIO_C_EN			(1 << 11)
+#define AUDIO_C_CLK_EN			(1 << 12)
+#define AUDIO_C_RESET			(1 << 15)
+
+#define AUDIO_CODEC_CDCFS8K16K		(1 << 10)
+#define AUDIO_DAC_CFS_DLY_B		(1 << 10)
+
+struct mc13783_priv {
+	struct snd_soc_codec codec;
+	struct mc13xxx *mc13xxx;
+
+	enum mc13783_ssi_port adc_ssi_port;
+	enum mc13783_ssi_port dac_ssi_port;
+};
+
+static unsigned int mc13783_read(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+	unsigned int value = 0;
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	mc13xxx_reg_read(priv->mc13xxx, reg, &value);
+
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return value;
+}
+
+static int mc13783_write(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int value)
+{
+	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
+
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+/* Mapping between sample rates and register value */
+static unsigned int mc13783_rates[] = {
+	8000, 11025, 12000, 16000,
+	22050, 24000, 32000, 44100,
+	48000, 64000, 96000
+};
+
+static int mc13783_pcm_hw_params_dac(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;
+	unsigned int rate = params_rate(params);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mc13783_rates); i++) {
+		if (rate == mc13783_rates[i]) {
+			snd_soc_update_bits(codec, MC13783_AUDIO_DAC,
+					0xf << 17, i << 17);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int mc13783_pcm_hw_params_codec(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;
+	unsigned int rate = params_rate(params);
+	unsigned int val;
+
+	switch (rate) {
+	case 8000:
+		val = 0;
+		break;
+	case 16000:
+		val = AUDIO_CODEC_CDCFS8K16K;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, MC13783_AUDIO_CODEC, AUDIO_CODEC_CDCFS8K16K,
+			val);
+
+	return 0;
+}
+
+static int mc13783_pcm_hw_params_sync(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return mc13783_pcm_hw_params_dac(substream, params, dai);
+	else
+		return mc13783_pcm_hw_params_codec(substream, params, dai);
+}
+
+static int mc13783_set_fmt(struct snd_soc_dai *dai, unsigned int fmt,
+			unsigned int reg)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int val = 0;
+	unsigned int mask = AUDIO_CFS(3) | AUDIO_BCL_INV | AUDIO_CFS_INV |
+				AUDIO_CSM | AUDIO_C_CLK_EN | AUDIO_C_RESET;
+
+
+	/* DAI mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		val |= AUDIO_CFS(2);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		val |= AUDIO_CFS(1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* DAI clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		val |= AUDIO_BCL_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		val |= AUDIO_BCL_INV | AUDIO_CFS_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		val |= AUDIO_CFS_INV;
+		break;
+	}
+
+	/* DAI clock master masks */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		val |= AUDIO_C_CLK_EN;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		val |= AUDIO_CSM;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+	case SND_SOC_DAIFMT_CBS_CFM:
+		return -EINVAL;
+	}
+
+	val |= AUDIO_C_RESET;
+
+	snd_soc_update_bits(codec, reg, mask, val);
+
+	return 0;
+}
+
+static int mc13783_set_fmt_async(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	if (dai->id == MC13783_ID_STEREO_DAC)
+		return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
+	else
+		return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_fmt_sync(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	int ret;
+
+	ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
+	if (ret)
+		return ret;
+
+	/*
+	 * In synchronous mode force the voice codec into slave mode
+	 * so that the clock / framesync from the stereo DAC is used
+	 */
+	fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+	fmt |= SND_SOC_DAIFMT_CBS_CFS;
+	ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
+
+	return ret;
+}
+
+static int mc13783_sysclk[] = {
+	13000000,
+	15360000,
+	16800000,
+	-1,
+	26000000,
+	-1, /* 12000000, invalid for voice codec */
+	-1, /* 3686400, invalid for voice codec */
+	33600000,
+};
+
+static int mc13783_set_sysclk(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir,
+				  unsigned int reg)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int clk;
+	unsigned int val = 0;
+	unsigned int mask = AUDIO_CLK(0x7) | AUDIO_CLK_SEL;
+
+	for (clk = 0; clk < ARRAY_SIZE(mc13783_sysclk); clk++) {
+		if (mc13783_sysclk[clk] < 0)
+			continue;
+		if (mc13783_sysclk[clk] == freq)
+			break;
+	}
+
+	if (clk == ARRAY_SIZE(mc13783_sysclk))
+		return -EINVAL;
+
+	if (clk_id == MC13783_CLK_CLIB)
+		val |= AUDIO_CLK_SEL;
+
+	val |= AUDIO_CLK(clk);
+
+	snd_soc_update_bits(codec, reg, mask, val);
+
+	return 0;
+}
+
+static int mc13783_set_sysclk_dac(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
+}
+
+static int mc13783_set_sysclk_codec(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_sysclk_sync(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	int ret;
+
+	ret = mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
+	if (ret)
+		return ret;
+
+	return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots,
+	int slot_width)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int val = 0;
+	unsigned int mask = SSI_NETWORK_DAC_SLOT_MASK |
+				SSI_NETWORK_DAC_RXSLOT_MASK;
+
+	switch (slots) {
+	case 2:
+		val |= SSI_NETWORK_DAC_SLOTS_2;
+		break;
+	case 4:
+		val |= SSI_NETWORK_DAC_SLOTS_4;
+		break;
+	case 8:
+		val |= SSI_NETWORK_DAC_SLOTS_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (rx_mask) {
+	case 0xfffffffc:
+		val |= SSI_NETWORK_DAC_RXSLOT_0_1;
+		break;
+	case 0xfffffff3:
+		val |= SSI_NETWORK_DAC_RXSLOT_2_3;
+		break;
+	case 0xffffffcf:
+		val |= SSI_NETWORK_DAC_RXSLOT_4_5;
+		break;
+	case 0xffffff3f:
+		val |= SSI_NETWORK_DAC_RXSLOT_6_7;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
+
+	return 0;
+}
+
+static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots,
+	int slot_width)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int val = 0;
+	unsigned int mask = 0x3f;
+
+	if (slots != 4)
+		return -EINVAL;
+
+	if (tx_mask != 0xfffffffc)
+		return -EINVAL;
+
+	val |= (0x00 << 2);	/* primary timeslot RX/TX(?) is 0 */
+	val |= (0x01 << 4);	/* secondary timeslot TX is 1 */
+
+	snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
+
+	return 0;
+}
+
+static int mc13783_set_tdm_slot_sync(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots,
+	int slot_width)
+{
+	int ret;
+
+	ret = mc13783_set_tdm_slot_dac(dai, tx_mask, rx_mask, slots,
+			slot_width);
+	if (ret)
+		return ret;
+
+	ret = mc13783_set_tdm_slot_codec(dai, tx_mask, rx_mask, slots,
+			slot_width);
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new mc1l_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", 38, 7, 1, 0);
+
+static const struct snd_kcontrol_new mc1r_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", 38, 5, 1, 0);
+
+static const struct snd_kcontrol_new mc2_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", 38, 9, 1, 0);
+
+static const struct snd_kcontrol_new atx_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", 38, 11, 1, 0);
+
+
+/* Virtual mux. The chip does the input selection automatically
+ * as soon as we enable one input. */
+static const char * const adcl_enum_text[] = {
+	"MC1L", "RXINL",
+};
+
+static const struct soc_enum adcl_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text);
+
+static const struct snd_kcontrol_new left_input_mux =
+	SOC_DAPM_ENUM_VIRT("Route", adcl_enum);
+
+static const char * const adcr_enum_text[] = {
+	"MC1R", "MC2", "RXINR", "TXIN",
+};
+
+static const struct soc_enum adcr_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text);
+
+static const struct snd_kcontrol_new right_input_mux =
+	SOC_DAPM_ENUM_VIRT("Route", adcr_enum);
+
+static const struct snd_kcontrol_new samp_ctl =
+	SOC_DAPM_SINGLE("Switch", 36, 3, 1, 0);
+
+static const struct snd_kcontrol_new lamp_ctl =
+	SOC_DAPM_SINGLE("Switch", 36, 5, 1, 0);
+
+static const struct snd_kcontrol_new hlamp_ctl =
+	SOC_DAPM_SINGLE("Switch", 36, 10, 1, 0);
+
+static const struct snd_kcontrol_new hramp_ctl =
+	SOC_DAPM_SINGLE("Switch", 36, 9, 1, 0);
+
+static const struct snd_kcontrol_new llamp_ctl =
+	SOC_DAPM_SINGLE("Switch", 36, 16, 1, 0);
+
+static const struct snd_kcontrol_new lramp_ctl =
+	SOC_DAPM_SINGLE("Switch", 36, 15, 1, 0);
+
+static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
+/* Input */
+	SND_SOC_DAPM_INPUT("MC1LIN"),
+	SND_SOC_DAPM_INPUT("MC1RIN"),
+	SND_SOC_DAPM_INPUT("MC2IN"),
+	SND_SOC_DAPM_INPUT("RXINR"),
+	SND_SOC_DAPM_INPUT("RXINL"),
+	SND_SOC_DAPM_INPUT("TXIN"),
+
+	SND_SOC_DAPM_SUPPLY("MC1 Bias", 38, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MC2 Bias", 38, 1, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("MC1L Amp", 38, 7, 0, &mc1l_amp_ctl),
+	SND_SOC_DAPM_SWITCH("MC1R Amp", 38, 5, 0, &mc1r_amp_ctl),
+	SND_SOC_DAPM_SWITCH("MC2 Amp", 38, 9, 0, &mc2_amp_ctl),
+	SND_SOC_DAPM_SWITCH("TXIN Amp", 38, 11, 0, &atx_amp_ctl),
+
+	SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
+			      &left_input_mux),
+	SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
+			      &right_input_mux),
+
+	SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_ADC("ADC", "Capture", 40, 11, 0),
+	SND_SOC_DAPM_SUPPLY("ADC_Reset", 40, 15, 0, NULL, 0),
+
+/* Output */
+	SND_SOC_DAPM_SUPPLY("DAC_E", 41, 11, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC_Reset", 41, 15, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("RXOUTL"),
+	SND_SOC_DAPM_OUTPUT("RXOUTR"),
+	SND_SOC_DAPM_OUTPUT("HSL"),
+	SND_SOC_DAPM_OUTPUT("HSR"),
+	SND_SOC_DAPM_OUTPUT("LSP"),
+	SND_SOC_DAPM_OUTPUT("SP"),
+
+	SND_SOC_DAPM_SWITCH("Speaker Amp", 36, 3, 0, &samp_ctl),
+	SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),
+	SND_SOC_DAPM_SWITCH("Headset Amp Left", 36, 10, 0, &hlamp_ctl),
+	SND_SOC_DAPM_SWITCH("Headset Amp Right", 36, 9, 0, &hramp_ctl),
+	SND_SOC_DAPM_SWITCH("Line out Amp Left", 36, 16, 0, &llamp_ctl),
+	SND_SOC_DAPM_SWITCH("Line out Amp Right", 36, 15, 0, &lramp_ctl),
+	SND_SOC_DAPM_DAC("DAC", "Playback", 36, 22, 0),
+	SND_SOC_DAPM_PGA("DAC PGA", 37, 5, 0, NULL, 0),
+};
+
+static struct snd_soc_dapm_route mc13783_routes[] = {
+/* Input */
+	{ "MC1L Amp", NULL, "MC1LIN"},
+	{ "MC1R Amp", NULL, "MC1RIN" },
+	{ "MC2 Amp", NULL, "MC2IN" },
+	{ "TXIN Amp", NULL, "TXIN"},
+
+	{ "PGA Left Input Mux", "MC1L", "MC1L Amp" },
+	{ "PGA Left Input Mux", "RXINL", "RXINL"},
+	{ "PGA Right Input Mux", "MC1R", "MC1R Amp" },
+	{ "PGA Right Input Mux", "MC2",  "MC2 Amp"},
+	{ "PGA Right Input Mux", "TXIN", "TXIN Amp"},
+	{ "PGA Right Input Mux", "RXINR", "RXINR"},
+
+	{ "PGA Left Input", NULL, "PGA Left Input Mux"},
+	{ "PGA Right Input", NULL, "PGA Right Input Mux"},
+
+	{ "ADC", NULL, "PGA Left Input"},
+	{ "ADC", NULL, "PGA Right Input"},
+	{ "ADC", NULL, "ADC_Reset"},
+
+/* Output */
+	{ "HSL", NULL, "Headset Amp Left" },
+	{ "HSR", NULL, "Headset Amp Right"},
+	{ "RXOUTL", NULL, "Line out Amp Left"},
+	{ "RXOUTR", NULL, "Line out Amp Right"},
+	{ "SP", NULL, "Speaker Amp"},
+	{ "Speaker Amp", NULL, "DAC PGA"},
+	{ "LSP", NULL, "DAC PGA"},
+	{ "Headset Amp Left", NULL, "DAC PGA"},
+	{ "Headset Amp Right", NULL, "DAC PGA"},
+	{ "Line out Amp Left", NULL, "DAC PGA"},
+	{ "Line out Amp Right", NULL, "DAC PGA"},
+	{ "DAC PGA", NULL, "DAC"},
+	{ "DAC", NULL, "DAC_E"},
+};
+
+static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
+						"Mono", "Mono Mix"};
+
+static const struct soc_enum mc13783_enum_3d_mixer =
+	SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer),
+			mc13783_3d_mixer);
+
+static struct snd_kcontrol_new mc13783_control_list[] = {
+	SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
+	SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0),
+	SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),
+	SOC_ENUM("3D Control", mc13783_enum_3d_mixer),
+};
+
+static int mc13783_probe(struct snd_soc_codec *codec)
+{
+	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	/* these are the reset values */
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX1, 0x00d35A);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_TX, 0x420000);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_SSI_NETWORK, 0x013060);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_CODEC, 0x180027);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_DAC, 0x0e0004);
+
+	if (priv->adc_ssi_port == MC13783_SSI1_PORT)
+		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
+				AUDIO_SSI_SEL, 0);
+	else
+		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
+				0, AUDIO_SSI_SEL);
+
+	if (priv->dac_ssi_port == MC13783_SSI1_PORT)
+		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
+				AUDIO_SSI_SEL, 0);
+	else
+		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
+				0, AUDIO_SSI_SEL);
+
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return 0;
+}
+
+static int mc13783_remove(struct snd_soc_codec *codec)
+{
+	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	/* Make sure VAUDIOON is off */
+	mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0);
+
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return 0;
+}
+
+#define MC13783_RATES_RECORD (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
+
+#define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops mc13783_ops_dac = {
+	.hw_params	= mc13783_pcm_hw_params_dac,
+	.set_fmt	= mc13783_set_fmt_async,
+	.set_sysclk	= mc13783_set_sysclk_dac,
+	.set_tdm_slot	= mc13783_set_tdm_slot_dac,
+};
+
+static struct snd_soc_dai_ops mc13783_ops_codec = {
+	.hw_params	= mc13783_pcm_hw_params_codec,
+	.set_fmt	= mc13783_set_fmt_async,
+	.set_sysclk	= mc13783_set_sysclk_codec,
+	.set_tdm_slot	= mc13783_set_tdm_slot_codec,
+};
+
+/*
+ * The mc13783 has two SSI ports, both of them can be routed either
+ * to the voice codec or the stereo DAC. When two different SSI ports
+ * are used for the voice codec and the stereo DAC we can do different
+ * formats and sysclock settings for playback and capture
+ * (mc13783-hifi-playback and mc13783-hifi-capture). Using the same port
+ * forces us to use symmetric rates (mc13783-hifi).
+ */
+static struct snd_soc_dai_driver mc13783_dai_async[] = {
+	{
+		.name = "mc13783-hifi-playback",
+		.id = MC13783_ID_STEREO_DAC,
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = MC13783_FORMATS,
+		},
+		.ops = &mc13783_ops_dac,
+	}, {
+		.name = "mc13783-hifi-capture",
+		.id = MC13783_ID_STEREO_CODEC,
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MC13783_RATES_RECORD,
+			.formats = MC13783_FORMATS,
+		},
+		.ops = &mc13783_ops_codec,
+	},
+};
+
+static struct snd_soc_dai_ops mc13783_ops_sync = {
+	.hw_params	= mc13783_pcm_hw_params_sync,
+	.set_fmt	= mc13783_set_fmt_sync,
+	.set_sysclk	= mc13783_set_sysclk_sync,
+	.set_tdm_slot	= mc13783_set_tdm_slot_sync,
+};
+
+static struct snd_soc_dai_driver mc13783_dai_sync[] = {
+	{
+		.name = "mc13783-hifi",
+		.id = MC13783_ID_SYNC,
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = MC13783_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MC13783_RATES_RECORD,
+			.formats = MC13783_FORMATS,
+		},
+		.ops = &mc13783_ops_sync,
+		.symmetric_rates = 1,
+	}
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
+	.probe		= mc13783_probe,
+	.remove		= mc13783_remove,
+	.read		= mc13783_read,
+	.write		= mc13783_write,
+	.controls	= mc13783_control_list,
+	.num_controls	= ARRAY_SIZE(mc13783_control_list),
+	.dapm_widgets	= mc13783_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mc13783_dapm_widgets),
+	.dapm_routes	= mc13783_routes,
+	.num_dapm_routes = ARRAY_SIZE(mc13783_routes),
+};
+
+static int mc13783_codec_probe(struct platform_device *pdev)
+{
+	struct mc13xxx *mc13xxx;
+	struct mc13783_priv *priv;
+	struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
+	int ret;
+
+	mc13xxx = dev_get_drvdata(pdev->dev.parent);
+
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(&pdev->dev, priv);
+	priv->mc13xxx = mc13xxx;
+	if (pdata) {
+		priv->adc_ssi_port = pdata->adc_ssi_port;
+		priv->dac_ssi_port = pdata->dac_ssi_port;
+	} else {
+		priv->adc_ssi_port = MC13783_SSI1_PORT;
+		priv->dac_ssi_port = MC13783_SSI2_PORT;
+	}
+
+	if (priv->adc_ssi_port == priv->dac_ssi_port)
+		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
+			mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync));
+	else
+		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
+			mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
+
+	if (ret)
+		goto err_register_codec;
+
+	return 0;
+
+err_register_codec:
+	dev_err(&pdev->dev, "register codec failed with %d\n", ret);
+
+	return ret;
+}
+
+static int mc13783_codec_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver mc13783_codec_driver = {
+	.driver = {
+		   .name = "mc13783-codec",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = mc13783_codec_probe,
+	.remove = __devexit_p(mc13783_codec_remove),
+};
+
+module_platform_driver(mc13783_codec_driver);
+
+MODULE_DESCRIPTION("ASoC MC13783 driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/mc13783.h b/sound/soc/codecs/mc13783.h
new file mode 100644
index 0000000..3a6d199
--- /dev/null
+++ b/sound/soc/codecs/mc13783.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * 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.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef MC13783_MIXER_H
+#define MC13783_MIXER_H
+
+#define MC13783_CLK_CLIA	1
+#define MC13783_CLK_CLIB	2
+
+#define MC13783_ID_STEREO_DAC	1
+#define MC13783_ID_STEREO_CODEC	2
+#define MC13783_ID_SYNC		3
+
+#endif /* MC13783_MIXER_H */
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
new file mode 100644
index 0000000..22cb5bf
--- /dev/null
+++ b/sound/soc/codecs/ml26124.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "ml26124.h"
+
+#define DVOL_CTL_DVMUTE_ON		BIT(4)	/* Digital volume MUTE On */
+#define DVOL_CTL_DVMUTE_OFF		0	/* Digital volume MUTE Off */
+#define ML26124_SAI_NO_DELAY	BIT(1)
+#define ML26124_SAI_FRAME_SYNC	(BIT(5) | BIT(0)) /* For mono (Telecodec) */
+#define ML26134_CACHESIZE 212
+#define ML26124_VMID	BIT(1)
+#define ML26124_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |\
+		       SNDRV_PCM_RATE_48000)
+#define ML26124_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+#define ML26124_NUM_REGISTER ML26134_CACHESIZE
+
+struct ml26124_priv {
+	u32 mclk;
+	u32 rate;
+	struct regmap *regmap;
+	int clk_in;
+	struct snd_pcm_substream *substream;
+};
+
+struct clk_coeff {
+	u32 mclk;
+	u32 rate;
+	u8 pllnl;
+	u8 pllnh;
+	u8 pllml;
+	u8 pllmh;
+	u8 plldiv;
+};
+
+/* ML26124 configuration */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7150, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(alclvl, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mingain, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(maxgain, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_vol, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
+
+static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
+						  "A-law"};
+
+static const struct soc_enum ml26124_adc_companding_enum
+	= SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding);
+
+static const struct soc_enum ml26124_dac_companding_enum
+	= SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding);
+
+static const struct snd_kcontrol_new ml26124_snd_controls[] = {
+	SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("Playback Digital Volume", ML26124_PLBAK_DIG_VOL, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("Digital Boost Volume", ML26124_DIGI_BOOST_VOL, 0,
+			0x3f, 0, boost_vol),
+	SOC_SINGLE_TLV("EQ Band0 Volume", ML26124_EQ_GAIN_BRAND0, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band1 Volume", ML26124_EQ_GAIN_BRAND1, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band2 Volume", ML26124_EQ_GAIN_BRAND2, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band3 Volume", ML26124_EQ_GAIN_BRAND3, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band4 Volume", ML26124_EQ_GAIN_BRAND4, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("ALC Target Level", ML26124_ALC_TARGET_LEV, 0,
+			0xf, 1, alclvl),
+	SOC_SINGLE_TLV("ALC Min Input Volume", ML26124_ALC_MAXMIN_GAIN, 0,
+			7, 0, mingain),
+	SOC_SINGLE_TLV("ALC Max Input Volume", ML26124_ALC_MAXMIN_GAIN, 4,
+			7, 1, maxgain),
+	SOC_SINGLE_TLV("Playback Limiter Min Input Volume",
+			ML26124_PL_MAXMIN_GAIN, 0, 7, 0, mingain),
+	SOC_SINGLE_TLV("Playback Limiter Max Input Volume",
+			ML26124_PL_MAXMIN_GAIN, 4, 7, 1, maxgain),
+	SOC_SINGLE_TLV("Playback Boost Volume", ML26124_PLYBAK_BOST_VOL, 0,
+			0x3f, 0, boost_vol),
+	SOC_SINGLE("DC High Pass Filter Switch", ML26124_FILTER_EN, 0, 1, 0),
+	SOC_SINGLE("Noise High Pass Filter Switch", ML26124_FILTER_EN, 1, 1, 0),
+	SOC_SINGLE("ZC Switch", ML26124_PW_ZCCMP_PW_MNG, 1,
+		    1, 0),
+	SOC_SINGLE("EQ Band0 Switch", ML26124_FILTER_EN, 2, 1, 0),
+	SOC_SINGLE("EQ Band1 Switch", ML26124_FILTER_EN, 3, 1, 0),
+	SOC_SINGLE("EQ Band2 Switch", ML26124_FILTER_EN, 4, 1, 0),
+	SOC_SINGLE("EQ Band3 Switch", ML26124_FILTER_EN, 5, 1, 0),
+	SOC_SINGLE("EQ Band4 Switch", ML26124_FILTER_EN, 6, 1, 0),
+	SOC_SINGLE("Play Limiter", ML26124_DVOL_CTL, 0, 1, 0),
+	SOC_SINGLE("Capture Limiter", ML26124_DVOL_CTL, 1, 1, 0),
+	SOC_SINGLE("Digital Volume Fade Switch", ML26124_DVOL_CTL, 3, 1, 0),
+	SOC_SINGLE("Digital Switch", ML26124_DVOL_CTL, 4, 1, 0),
+	SOC_ENUM("DAC Companding", ml26124_dac_companding_enum),
+	SOC_ENUM("ADC Companding", ml26124_adc_companding_enum),
+};
+
+static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", ML26124_SPK_AMP_OUT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Line in loopback Switch", ML26124_SPK_AMP_OUT, 3, 1,
+			 0),
+	SOC_DAPM_SINGLE("PGA Switch", ML26124_SPK_AMP_OUT, 5, 1, 0),
+};
+
+/* Input mux */
+static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",
+				"Digital MIC in", "Analog MIC Differential in"};
+
+static const struct soc_enum ml26124_insel_enum =
+	SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select);
+
+static const struct snd_kcontrol_new ml26124_input_mux_controls =
+	SOC_DAPM_ENUM("Input Select", ml26124_insel_enum);
+
+static const struct snd_kcontrol_new ml26124_line_control =
+	SOC_DAPM_SINGLE("Switch", ML26124_PW_LOUT_PW_MNG, 1, 1, 0);
+
+static const struct snd_soc_dapm_widget ml26124_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("MCLKEN", ML26124_CLK_EN, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLLEN", ML26124_CLK_EN, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLLOE", ML26124_CLK_EN, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS", ML26124_PW_REF_PW_MNG, 2, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+			   &ml26124_output_mixer_controls[0],
+			   ARRAY_SIZE(ml26124_output_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "Playback", ML26124_PW_DAC_PW_MNG, 1, 0),
+	SND_SOC_DAPM_ADC("ADC", "Capture", ML26124_PW_IN_PW_MNG, 1, 0),
+	SND_SOC_DAPM_PGA("PGA", ML26124_PW_IN_PW_MNG, 3, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+			  &ml26124_input_mux_controls),
+	SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
+			     &ml26124_line_control),
+	SND_SOC_DAPM_INPUT("MDIN"),
+	SND_SOC_DAPM_INPUT("MIN"),
+	SND_SOC_DAPM_INPUT("LIN"),
+	SND_SOC_DAPM_OUTPUT("SPOUT"),
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+};
+
+static const struct snd_soc_dapm_route ml26124_intercon[] = {
+	/* Supply */
+	{"DAC", NULL, "MCLKEN"},
+	{"ADC", NULL, "MCLKEN"},
+	{"DAC", NULL, "PLLEN"},
+	{"ADC", NULL, "PLLEN"},
+	{"DAC", NULL, "PLLOE"},
+	{"ADC", NULL, "PLLOE"},
+
+	/* output mixer */
+	{"Output Mixer", "DAC Switch", "DAC"},
+	{"Output Mixer", "Line in loopback Switch", "LIN"},
+
+	/* outputs */
+	{"LOUT", NULL, "Output Mixer"},
+	{"SPOUT", NULL, "Output Mixer"},
+	{"Line Out Enable", NULL, "LOUT"},
+
+	/* input */
+	{"ADC", NULL, "Input Mux"},
+	{"Input Mux", "Analog MIC SingleEnded in", "PGA"},
+	{"Input Mux", "Analog MIC Differential in", "PGA"},
+	{"PGA", NULL, "MIN"},
+};
+
+/* PLLOutputFreq(Hz) = InputMclkFreq(Hz) * PLLM / (PLLN * PLLDIV) */
+static const struct clk_coeff coeff_div[] = {
+	{12288000, 16000, 0xc, 0x0, 0x20, 0x0, 0x4},
+	{12288000, 32000, 0xc, 0x0, 0x20, 0x0, 0x4},
+	{12288000, 48000, 0xc, 0x0, 0x30, 0x0, 0x4},
+};
+
+static struct reg_default ml26124_reg[] = {
+	/* CLOCK control Register */
+	{0x00, 0x00 },	/* Sampling Rate */
+	{0x02, 0x00},	/* PLL NL */
+	{0x04, 0x00},	/* PLLNH */
+	{0x06, 0x00},	/* PLLML */
+	{0x08, 0x00},	/* MLLMH */
+	{0x0a, 0x00},	/* PLLDIV */
+	{0x0c, 0x00},	/* Clock Enable */
+	{0x0e, 0x00},	/* CLK Input/Output Control */
+
+	/* System Control Register */
+	{0x10, 0x00},	/* Software RESET */
+	{0x12, 0x00},	/* Record/Playback Run */
+	{0x14, 0x00},	/* Mic Input/Output control */
+
+	/* Power Management Register */
+	{0x20, 0x00},	/* Reference Power Management */
+	{0x22, 0x00},	/* Input Power Management */
+	{0x24, 0x00},	/* DAC Power Management */
+	{0x26, 0x00},	/* SP-AMP Power Management */
+	{0x28, 0x00},	/* LINEOUT Power Management */
+	{0x2a, 0x00},	/* VIDEO Power Management */
+	{0x2e, 0x00},	/* AC-CMP Power Management */
+
+	/* Analog reference Control Register */
+	{0x30, 0x04},	/* MICBIAS Voltage Control */
+
+	/* Input/Output Amplifier Control Register */
+	{0x32, 0x10},	/* MIC Input Volume */
+	{0x38, 0x00},	/* Mic Boost Volume */
+	{0x3a, 0x33},	/* Speaker AMP Volume */
+	{0x48, 0x00},	/* AMP Volume Control Function Enable */
+	{0x4a, 0x00},	/* Amplifier Volume Fader Control */
+
+	/* Analog Path Control Register */
+	{0x54, 0x00},	/* Speaker AMP Output Control */
+	{0x5a, 0x00},	/* Mic IF Control */
+	{0xe8, 0x01},	/* Mic Select Control */
+
+	/* Audio Interface Control Register */
+	{0x60, 0x00},	/* SAI-Trans Control */
+	{0x62, 0x00},	/* SAI-Receive Control */
+	{0x64, 0x00},	/* SAI Mode select */
+
+	/* DSP Control Register */
+	{0x66, 0x01},	/* Filter Func Enable */
+	{0x68, 0x00},	/* Volume Control Func Enable */
+	{0x6A, 0x00},	/* Mixer & Volume Control*/
+	{0x6C, 0xff},	/* Record Digital Volume */
+	{0x70, 0xff},	/* Playback Digital Volume */
+	{0x72, 0x10},	/* Digital Boost Volume */
+	{0x74, 0xe7},	/* EQ gain Band0 */
+	{0x76, 0xe7},	/* EQ gain Band1 */
+	{0x78, 0xe7},	/* EQ gain Band2 */
+	{0x7A, 0xe7},	/* EQ gain Band3 */
+	{0x7C, 0xe7},	/* EQ gain Band4 */
+	{0x7E, 0x00},	/* HPF2 CutOff*/
+	{0x80, 0x00},	/* EQ Band0 Coef0L */
+	{0x82, 0x00},	/* EQ Band0 Coef0H */
+	{0x84, 0x00},	/* EQ Band0 Coef0L */
+	{0x86, 0x00},	/* EQ Band0 Coef0H */
+	{0x88, 0x00},	/* EQ Band1 Coef0L */
+	{0x8A, 0x00},	/* EQ Band1 Coef0H */
+	{0x8C, 0x00},	/* EQ Band1 Coef0L */
+	{0x8E, 0x00},	/* EQ Band1 Coef0H */
+	{0x90, 0x00},	/* EQ Band2 Coef0L */
+	{0x92, 0x00},	/* EQ Band2 Coef0H */
+	{0x94, 0x00},	/* EQ Band2 Coef0L */
+	{0x96, 0x00},	/* EQ Band2 Coef0H */
+	{0x98, 0x00},	/* EQ Band3 Coef0L */
+	{0x9A, 0x00},	/* EQ Band3 Coef0H */
+	{0x9C, 0x00},	/* EQ Band3 Coef0L */
+	{0x9E, 0x00},	/* EQ Band3 Coef0H */
+	{0xA0, 0x00},	/* EQ Band4 Coef0L */
+	{0xA2, 0x00},	/* EQ Band4 Coef0H */
+	{0xA4, 0x00},	/* EQ Band4 Coef0L */
+	{0xA6, 0x00},	/* EQ Band4 Coef0H */
+
+	/* ALC Control Register */
+	{0xb0, 0x00},	/* ALC Mode */
+	{0xb2, 0x02},	/* ALC Attack Time */
+	{0xb4, 0x03},	/* ALC Decay Time */
+	{0xb6, 0x00},	/* ALC Hold Time */
+	{0xb8, 0x0b},	/* ALC Target Level */
+	{0xba, 0x70},	/* ALC Max/Min Gain */
+	{0xbc, 0x00},	/* Noise Gate Threshold */
+	{0xbe, 0x00},	/* ALC ZeroCross TimeOut */
+
+	/* Playback Limiter Control Register */
+	{0xc0, 0x04},	/* PL Attack Time */
+	{0xc2, 0x05},	/* PL Decay Time */
+	{0xc4, 0x0d},	/* PL Target Level */
+	{0xc6, 0x70},	/* PL Max/Min Gain */
+	{0xc8, 0x10},	/* Playback Boost Volume */
+	{0xca, 0x00},	/* PL ZeroCross TimeOut */
+
+	/* Video Amplifier Control Register */
+	{0xd0, 0x01},	/* VIDEO AMP Gain Control */
+	{0xd2, 0x01},	/* VIDEO AMP Setup 1 */
+	{0xd4, 0x01},	/* VIDEO AMP Control2 */
+};
+
+/* Get sampling rate value of sampling rate setting register (0x0) */
+static inline int get_srate(int rate)
+{
+	int srate;
+
+	switch (rate) {
+	case 16000:
+		srate = 3;
+		break;
+	case 32000:
+		srate = 6;
+		break;
+	case 48000:
+		srate = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return srate;
+}
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int ml26124_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *hw_params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int i = get_coeff(priv->mclk, params_rate(hw_params));
+
+	priv->substream = substream;
+	priv->rate = params_rate(hw_params);
+
+	if (priv->clk_in) {
+		switch (priv->mclk / params_rate(hw_params)) {
+		case 256:
+			snd_soc_update_bits(codec, ML26124_CLK_CTL,
+					    BIT(0) | BIT(1), 1);
+			break;
+		case 512:
+			snd_soc_update_bits(codec, ML26124_CLK_CTL,
+					    BIT(0) | BIT(1), 2);
+			break;
+		case 1024:
+			snd_soc_update_bits(codec, ML26124_CLK_CTL,
+					    BIT(0) | BIT(1), 3);
+			break;
+		default:
+			dev_err(codec->dev, "Unsupported MCLKI\n");
+			break;
+		}
+	} else {
+		snd_soc_update_bits(codec, ML26124_CLK_CTL,
+				    BIT(0) | BIT(1), 0);
+	}
+
+	switch (params_rate(hw_params)) {
+	case 16000:
+		snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+				    get_srate(params_rate(hw_params)));
+		snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+				    coeff_div[i].pllnl);
+		snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+				    coeff_div[i].pllnh);
+		snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+				    coeff_div[i].pllml);
+		snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+				    coeff_div[i].pllmh);
+		snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+				    coeff_div[i].plldiv);
+		break;
+	case 32000:
+		snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+				    get_srate(params_rate(hw_params)));
+		snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+				    coeff_div[i].pllnl);
+		snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+				    coeff_div[i].pllnh);
+		snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+				    coeff_div[i].pllml);
+		snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+				    coeff_div[i].pllmh);
+		snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+				    coeff_div[i].plldiv);
+		break;
+	case 48000:
+		snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+				    get_srate(params_rate(hw_params)));
+		snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+				    coeff_div[i].pllnl);
+		snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+				    coeff_div[i].pllnh);
+		snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+				    coeff_div[i].pllml);
+		snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+				    coeff_div[i].pllmh);
+		snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+				    coeff_div[i].plldiv);
+		break;
+	default:
+		pr_err("%s:this rate is no support for ml26124\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ml26124_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (priv->substream->stream) {
+	case SNDRV_PCM_STREAM_CAPTURE:
+		snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(0), 1);
+		break;
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(1), 2);
+		break;
+	}
+
+	if (mute)
+		snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+				    DVOL_CTL_DVMUTE_ON);
+	else
+		snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+				    DVOL_CTL_DVMUTE_OFF);
+
+	return 0;
+}
+
+static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	unsigned char mode;
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		mode = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		mode = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, ML26124_SAI_MODE_SEL, BIT(0), mode);
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ml26124_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 ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (clk_id) {
+	case ML26124_USE_PLLOUT:
+		priv->clk_in = ML26124_USE_PLLOUT;
+		break;
+	case ML26124_USE_MCLKI:
+		priv->clk_in = ML26124_USE_MCLKI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	priv->mclk = freq;
+
+	return 0;
+}
+
+static int ml26124_set_bias_level(struct snd_soc_codec *codec,
+		enum snd_soc_bias_level level)
+{
+	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+				    ML26124_R26_MASK, ML26124_BLT_PREAMP_ON);
+		msleep(100);
+		snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+				    ML26124_R26_MASK,
+				    ML26124_MICBEN_ON | ML26124_BLT_ALL_ON);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* VMID ON */
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+					    ML26124_VMID, ML26124_VMID);
+			msleep(500);
+			regcache_sync(priv->regmap);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* VMID OFF */
+		snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+				    ML26124_VMID, 0);
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ml26124_dai_ops = {
+	.hw_params	= ml26124_hw_params,
+	.digital_mute	= ml26124_mute,
+	.set_fmt	= ml26124_set_dai_fmt,
+	.set_sysclk	= ml26124_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver ml26124_dai = {
+	.name = "ml26124-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ML26124_RATES,
+		.formats = ML26124_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ML26124_RATES,
+		.formats = ML26124_FORMATS,},
+	.ops = &ml26124_dai_ops,
+	.symmetric_rates = 1,
+};
+
+#ifdef CONFIG_PM
+static int ml26124_suspend(struct snd_soc_codec *codec)
+{
+	ml26124_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int ml26124_resume(struct snd_soc_codec *codec)
+{
+	ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+#else
+#define ml26124_suspend NULL
+#define ml26124_resume NULL
+#endif
+
+static int ml26124_probe(struct snd_soc_codec *codec)
+{
+	int ret;
+	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+	codec->control_data = priv->regmap;
+
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	/* Software Reset */
+	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
+	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
+
+	ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
+	.probe =	ml26124_probe,
+	.suspend =	ml26124_suspend,
+	.resume =	ml26124_resume,
+	.set_bias_level = ml26124_set_bias_level,
+	.dapm_widgets = ml26124_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets),
+	.dapm_routes = ml26124_intercon,
+	.num_dapm_routes = ARRAY_SIZE(ml26124_intercon),
+	.controls = ml26124_snd_controls,
+	.num_controls = ARRAY_SIZE(ml26124_snd_controls),
+};
+
+static const struct regmap_config ml26124_i2c_regmap = {
+	.val_bits = 8,
+	.reg_bits = 8,
+	.max_register = ML26124_NUM_REGISTER,
+	.reg_defaults = ml26124_reg,
+	.num_reg_defaults = ARRAY_SIZE(ml26124_reg),
+	.cache_type = REGCACHE_RBTREE,
+	.write_flag_mask = 0x01,
+};
+
+static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct ml26124_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, priv);
+
+	priv->regmap = regmap_init_i2c(i2c, &ml26124_i2c_regmap);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret);
+		return ret;
+	}
+
+	return snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_ml26124, &ml26124_dai, 1);
+}
+
+static __devexit int ml26124_i2c_remove(struct i2c_client *client)
+{
+	struct ml26124_priv *priv = i2c_get_clientdata(client);
+
+	snd_soc_unregister_codec(&client->dev);
+	regmap_exit(priv->regmap);
+	return 0;
+}
+
+static const struct i2c_device_id ml26124_i2c_id[] = {
+	{ "ml26124", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id);
+
+static struct i2c_driver ml26124_i2c_driver = {
+	.driver = {
+		.name = "ml26124",
+		.owner = THIS_MODULE,
+	},
+	.probe = ml26124_i2c_probe,
+	.remove = __devexit_p(ml26124_i2c_remove),
+	.id_table = ml26124_i2c_id,
+};
+
+module_i2c_driver(ml26124_i2c_driver);
+
+MODULE_AUTHOR("Tomoya MORINAGA <tomoya.rohm@gmail.com>");
+MODULE_DESCRIPTION("LAPIS Semiconductor ML26124 ALSA SoC codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ml26124.h b/sound/soc/codecs/ml26124.h
new file mode 100644
index 0000000..5ea0cbb
--- /dev/null
+++ b/sound/soc/codecs/ml26124.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef ML26124_H
+#define ML26124_H
+
+/* Clock Control Register */
+#define ML26124_SMPLING_RATE		0x00
+#define ML26124_PLLNL			0x02
+#define ML26124_PLLNH			0x04
+#define ML26124_PLLML			0x06
+#define ML26124_PLLMH			0x08
+#define ML26124_PLLDIV			0x0a
+#define ML26124_CLK_EN			0x0c
+#define ML26124_CLK_CTL			0x0e
+
+/* System Control Register */
+#define ML26124_SW_RST			0x10
+#define ML26124_REC_PLYBAK_RUN		0x12
+#define ML26124_MIC_TIM			0x14
+
+/* Power Mnagement Register */
+#define ML26124_PW_REF_PW_MNG		0x20
+#define ML26124_PW_IN_PW_MNG		0x22
+#define ML26124_PW_DAC_PW_MNG		0x24
+#define ML26124_PW_SPAMP_PW_MNG		0x26
+#define ML26124_PW_LOUT_PW_MNG		0x28
+#define ML26124_PW_VOUT_PW_MNG		0x2a
+#define ML26124_PW_ZCCMP_PW_MNG		0x2e
+
+/* Analog Reference Control Register */
+#define ML26124_PW_MICBIAS_VOL		0x30
+
+/* Input/Output Amplifier Control Register */
+#define ML26124_PW_MIC_IN_VOL		0x32
+#define ML26124_PW_MIC_BOST_VOL		0x38
+#define ML26124_PW_SPK_AMP_VOL		0x3a
+#define ML26124_PW_AMP_VOL_FUNC		0x48
+#define ML26124_PW_AMP_VOL_FADE		0x4a
+
+/* Analog Path Control Register */
+#define ML26124_SPK_AMP_OUT		0x54
+#define ML26124_MIC_IF_CTL		0x5a
+#define ML26124_MIC_SELECT		0xe8
+
+/* Audio Interface Control Register */
+#define ML26124_SAI_TRANS_CTL		0x60
+#define ML26124_SAI_RCV_CTL		0x62
+#define ML26124_SAI_MODE_SEL		0x64
+
+/* DSP Control Register */
+#define ML26124_FILTER_EN		0x66
+#define ML26124_DVOL_CTL		0x68
+#define ML26124_MIXER_VOL_CTL		0x6a
+#define ML26124_RECORD_DIG_VOL		0x6c
+#define ML26124_PLBAK_DIG_VOL		0x70
+#define ML26124_DIGI_BOOST_VOL		0x72
+#define ML26124_EQ_GAIN_BRAND0		0x74
+#define ML26124_EQ_GAIN_BRAND1		0x76
+#define ML26124_EQ_GAIN_BRAND2		0x78
+#define ML26124_EQ_GAIN_BRAND3		0x7a
+#define ML26124_EQ_GAIN_BRAND4		0x7c
+#define ML26124_HPF2_CUTOFF		0x7e
+#define ML26124_EQBRAND0_F0L		0x80
+#define ML26124_EQBRAND0_F0H		0x82
+#define ML26124_EQBRAND0_F1L		0x84
+#define ML26124_EQBRAND0_F1H		0x86
+#define ML26124_EQBRAND1_F0L		0x88
+#define ML26124_EQBRAND1_F0H		0x8a
+#define ML26124_EQBRAND1_F1L		0x8c
+#define ML26124_EQBRAND1_F1H		0x8e
+#define ML26124_EQBRAND2_F0L		0x90
+#define ML26124_EQBRAND2_F0H		0x92
+#define ML26124_EQBRAND2_F1L		0x94
+#define ML26124_EQBRAND2_F1H		0x96
+#define ML26124_EQBRAND3_F0L		0x98
+#define ML26124_EQBRAND3_F0H		0x9a
+#define ML26124_EQBRAND3_F1L		0x9c
+#define ML26124_EQBRAND3_F1H		0x9e
+#define ML26124_EQBRAND4_F0L		0xa0
+#define ML26124_EQBRAND4_F0H		0xa2
+#define ML26124_EQBRAND4_F1L		0xa4
+#define ML26124_EQBRAND4_F1H		0xa6
+
+/* ALC Control Register */
+#define ML26124_ALC_MODE		0xb0
+#define ML26124_ALC_ATTACK_TIM		0xb2
+#define ML26124_ALC_DECAY_TIM		0xb4
+#define ML26124_ALC_HOLD_TIM		0xb6
+#define ML26124_ALC_TARGET_LEV		0xb8
+#define ML26124_ALC_MAXMIN_GAIN		0xba
+#define ML26124_NOIS_GATE_THRSH		0xbc
+#define ML26124_ALC_ZERO_TIMOUT		0xbe
+
+/* Playback Limiter Control Register */
+#define ML26124_PL_ATTACKTIME		0xc0
+#define ML26124_PL_DECAYTIME		0xc2
+#define ML26124_PL_TARGETTIME		0xc4
+#define ML26124_PL_MAXMIN_GAIN		0xc6
+#define ML26124_PLYBAK_BOST_VOL		0xc8
+#define ML26124_PL_0CROSS_TIMOUT	0xca
+
+/* Video Amplifer Control Register */
+#define ML26124_VIDEO_AMP_GAIN_CTL	0xd0
+#define ML26124_VIDEO_AMP_SETUP1	0xd2
+#define ML26124_VIDEO_AMP_CTL2		0xd4
+
+/* Clock select for machine driver */
+#define ML26124_USE_PLL			0
+#define ML26124_USE_MCLKI_256FS		1
+#define ML26124_USE_MCLKI_512FS		2
+#define ML26124_USE_MCLKI_1024FS	3
+
+/* Register Mask */
+#define ML26124_R0_MASK	0xf
+#define ML26124_R2_MASK	0xff
+#define ML26124_R4_MASK	0x1
+#define ML26124_R6_MASK	0xf
+#define ML26124_R8_MASK	0x3f
+#define ML26124_Ra_MASK	0x1f
+#define ML26124_Rc_MASK	0x1f
+#define ML26124_Re_MASK	0x7
+#define ML26124_R10_MASK	0x1
+#define ML26124_R12_MASK	0x17
+#define ML26124_R14_MASK	0x3f
+#define ML26124_R20_MASK	0x47
+#define ML26124_R22_MASK	0xa
+#define ML26124_R24_MASK	0x2
+#define ML26124_R26_MASK	0x1f
+#define ML26124_R28_MASK	0x2
+#define ML26124_R2a_MASK	0x2
+#define ML26124_R2e_MASK	0x2
+#define ML26124_R30_MASK	0x7
+#define ML26124_R32_MASK	0x3f
+#define ML26124_R38_MASK	0x38
+#define ML26124_R3a_MASK	0x3f
+#define ML26124_R48_MASK	0x3
+#define ML26124_R4a_MASK	0x7
+#define ML26124_R54_MASK	0x2a
+#define ML26124_R5a_MASK	0x3
+#define ML26124_Re8_MASK	0x3
+#define ML26124_R60_MASK	0xff
+#define ML26124_R62_MASK	0xff
+#define ML26124_R64_MASK	0x1
+#define ML26124_R66_MASK	0xff
+#define ML26124_R68_MASK	0x3b
+#define ML26124_R6a_MASK	0xf3
+#define ML26124_R6c_MASK	0xff
+#define ML26124_R70_MASK	0xff
+
+#define ML26124_MCLKEN		BIT(0)
+#define ML26124_PLLEN		BIT(1)
+#define ML26124_PLLOE		BIT(2)
+#define ML26124_MCLKOE		BIT(3)
+
+#define ML26124_BLT_ALL_ON	0x1f
+#define ML26124_BLT_PREAMP_ON	0x13
+
+#define ML26124_MICBEN_ON	BIT(2)
+
+enum ml26124_regs {
+	ML26124_MCLK = 0,
+};
+
+enum ml26124_clk_in {
+	ML26124_USE_PLLOUT = 0,
+	ML26124_USE_MCLKI,
+};
+
+#endif
diff --git a/sound/soc/codecs/omap-hdmi.c b/sound/soc/codecs/omap-hdmi.c
new file mode 100644
index 0000000..1bf5c74
--- /dev/null
+++ b/sound/soc/codecs/omap-hdmi.c
@@ -0,0 +1,69 @@
+/*
+ * ALSA SoC codec driver for HDMI audio on OMAP processors.
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Ricardo Neri <ricardo.neri@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
+ *
+ */
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "hdmi-audio-codec"
+
+static struct snd_soc_codec_driver omap_hdmi_codec;
+
+static struct snd_soc_dai_driver omap_hdmi_codec_dai = {
+	.name = "omap-hdmi-hifi",
+	.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 __devinit int omap_hdmi_codec_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec,
+			&omap_hdmi_codec_dai, 1);
+}
+
+static __devexit int omap_hdmi_codec_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver omap_hdmi_codec_driver = {
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+
+	.probe		= omap_hdmi_codec_probe,
+	.remove		= __devexit_p(omap_hdmi_codec_remove),
+};
+
+module_platform_driver(omap_hdmi_codec_driver);
+
+MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
+MODULE_DESCRIPTION("ASoC OMAP HDMI codec driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 20c324c..960d0e9 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -18,7 +18,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -30,6 +30,7 @@
 #include "rt5631.h"
 
 struct rt5631_priv {
+	struct regmap *regmap;
 	int codec_version;
 	int master;
 	int sysclk;
@@ -38,33 +39,33 @@
 	int dmic_used_flag;
 };
 
-static const u16 rt5631_reg[RT5631_VENDOR_ID2 + 1] = {
-	[RT5631_SPK_OUT_VOL] = 0x8888,
-	[RT5631_HP_OUT_VOL] = 0x8080,
-	[RT5631_MONO_AXO_1_2_VOL] = 0xa080,
-	[RT5631_AUX_IN_VOL] = 0x0808,
-	[RT5631_ADC_REC_MIXER] = 0xf0f0,
-	[RT5631_VDAC_DIG_VOL] = 0x0010,
-	[RT5631_OUTMIXER_L_CTRL] = 0xffc0,
-	[RT5631_OUTMIXER_R_CTRL] = 0xffc0,
-	[RT5631_AXO1MIXER_CTRL] = 0x88c0,
-	[RT5631_AXO2MIXER_CTRL] = 0x88c0,
-	[RT5631_DIG_MIC_CTRL] = 0x3000,
-	[RT5631_MONO_INPUT_VOL] = 0x8808,
-	[RT5631_SPK_MIXER_CTRL] = 0xf8f8,
-	[RT5631_SPK_MONO_OUT_CTRL] = 0xfc00,
-	[RT5631_SPK_MONO_HP_OUT_CTRL] = 0x4440,
-	[RT5631_SDP_CTRL] = 0x8000,
-	[RT5631_MONO_SDP_CTRL] = 0x8000,
-	[RT5631_STEREO_AD_DA_CLK_CTRL] = 0x2010,
-	[RT5631_GEN_PUR_CTRL_REG] = 0x0e00,
-	[RT5631_INT_ST_IRQ_CTRL_2] = 0x071a,
-	[RT5631_MISC_CTRL] = 0x2040,
-	[RT5631_DEPOP_FUN_CTRL_2] = 0x8000,
-	[RT5631_SOFT_VOL_CTRL] = 0x07e0,
-	[RT5631_ALC_CTRL_1] = 0x0206,
-	[RT5631_ALC_CTRL_3] = 0x2000,
-	[RT5631_PSEUDO_SPATL_CTRL] = 0x0553,
+static const struct reg_default rt5631_reg[] = {
+	{ RT5631_SPK_OUT_VOL, 0x8888 },
+	{ RT5631_HP_OUT_VOL, 0x8080 },
+	{ RT5631_MONO_AXO_1_2_VOL, 0xa080 },
+	{ RT5631_AUX_IN_VOL, 0x0808 },
+	{ RT5631_ADC_REC_MIXER, 0xf0f0 },
+	{ RT5631_VDAC_DIG_VOL, 0x0010 },
+	{ RT5631_OUTMIXER_L_CTRL, 0xffc0 },
+	{ RT5631_OUTMIXER_R_CTRL, 0xffc0 },
+	{ RT5631_AXO1MIXER_CTRL, 0x88c0 },
+	{ RT5631_AXO2MIXER_CTRL, 0x88c0 },
+	{ RT5631_DIG_MIC_CTRL, 0x3000 },
+	{ RT5631_MONO_INPUT_VOL, 0x8808 },
+	{ RT5631_SPK_MIXER_CTRL, 0xf8f8 },
+	{ RT5631_SPK_MONO_OUT_CTRL, 0xfc00 },
+	{ RT5631_SPK_MONO_HP_OUT_CTRL, 0x4440 },
+	{ RT5631_SDP_CTRL, 0x8000 },
+	{ RT5631_MONO_SDP_CTRL, 0x8000 },
+	{ RT5631_STEREO_AD_DA_CLK_CTRL, 0x2010 },
+	{ RT5631_GEN_PUR_CTRL_REG, 0x0e00 },
+	{ RT5631_INT_ST_IRQ_CTRL_2, 0x071a },
+	{ RT5631_MISC_CTRL, 0x2040 },
+	{ RT5631_DEPOP_FUN_CTRL_2, 0x8000 },
+	{ RT5631_SOFT_VOL_CTRL, 0x07e0 },
+	{ RT5631_ALC_CTRL_1, 0x0206 },
+	{ RT5631_ALC_CTRL_3, 0x2000 },
+	{ RT5631_PSEUDO_SPATL_CTRL, 0x0553 },
 };
 
 /**
@@ -96,8 +97,7 @@
 	return snd_soc_write(codec, RT5631_RESET, 0);
 }
 
-static int rt5631_volatile_register(struct snd_soc_codec *codec,
-				    unsigned int reg)
+static bool rt5631_volatile_register(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
 	case RT5631_RESET:
@@ -111,8 +111,7 @@
 	}
 }
 
-static int rt5631_readable_register(struct snd_soc_codec *codec,
-				    unsigned int reg)
+static bool rt5631_readable_register(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
 	case RT5631_RESET:
@@ -1361,8 +1360,7 @@
 static int rt5631_hifi_pcm_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 snd_soc_codec *codec = dai->codec;
 	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 	int timesofbclk = 32, coeff;
 	unsigned int iface = 0;
@@ -1544,6 +1542,8 @@
 static int rt5631_set_bias_level(struct snd_soc_codec *codec,
 			enum snd_soc_bias_level level)
 {
+	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
@@ -1561,8 +1561,8 @@
 			snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
 				RT5631_PWR_FAST_VREF_CTRL,
 				RT5631_PWR_FAST_VREF_CTRL);
-			codec->cache_only = false;
-			snd_soc_cache_sync(codec);
+			regcache_cache_only(rt5631->regmap, false);
+			regcache_sync(rt5631->regmap);
 		}
 		break;
 
@@ -1587,7 +1587,9 @@
 	unsigned int val;
 	int ret;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+	codec->control_data = rt5631->regmap;
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -1698,12 +1700,6 @@
 	.suspend = rt5631_suspend,
 	.resume = rt5631_resume,
 	.set_bias_level = rt5631_set_bias_level,
-	.reg_cache_size = RT5631_VENDOR_ID2 + 1,
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = rt5631_reg,
-	.volatile_register = rt5631_volatile_register,
-	.readable_register = rt5631_readable_register,
-	.reg_cache_step = 1,
 	.controls = rt5631_snd_controls,
 	.num_controls = ARRAY_SIZE(rt5631_snd_controls),
 	.dapm_widgets = rt5631_dapm_widgets,
@@ -1718,6 +1714,18 @@
 };
 MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
 
+static const struct regmap_config rt5631_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.readable_reg = rt5631_readable_register,
+	.volatile_reg = rt5631_volatile_register,
+	.max_register = RT5631_VENDOR_ID2,
+	.reg_defaults = rt5631_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5631_reg),
+	.cache_type = REGCACHE_RBTREE,
+};
+
 static int rt5631_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 {
@@ -1731,6 +1739,10 @@
 
 	i2c_set_clientdata(i2c, rt5631);
 
+	rt5631->regmap = devm_regmap_init_i2c(i2c, &rt5631_regmap_config);
+	if (IS_ERR(rt5631->regmap))
+		return PTR_ERR(rt5631->regmap);
+
 	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5631,
 			rt5631_dai, ARRAY_SIZE(rt5631_dai));
 	return ret;
@@ -1752,17 +1764,7 @@
 	.id_table = rt5631_i2c_id,
 };
 
-static int __init rt5631_modinit(void)
-{
-	return i2c_add_driver(&rt5631_i2c_driver);
-}
-module_init(rt5631_modinit);
-
-static void __exit rt5631_modexit(void)
-{
-	i2c_del_driver(&rt5631_i2c_driver);
-}
-module_exit(rt5631_modexit);
+module_i2c_driver(rt5631_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC RT5631 driver");
 MODULE_AUTHOR("flove <flove@realtek.com>");
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index c395ec3..8af6a52 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -84,8 +84,8 @@
 
 static struct regulator_init_data ldo_init_data = {
 	.constraints = {
-		.min_uV                 = 850000,
-		.max_uV                 = 1600000,
+		.min_uV                 = 1200000,
+		.max_uV                 = 1200000,
 		.valid_modes_mask       = REGULATOR_MODE_NORMAL,
 		.valid_ops_mask         = REGULATOR_CHANGE_STATUS,
 	},
@@ -197,9 +197,9 @@
 	SND_SOC_DAPM_OUTPUT("HP_OUT"),
 	SND_SOC_DAPM_OUTPUT("LINE_OUT"),
 
-	SND_SOC_DAPM_MICBIAS_E("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
-				mic_bias_event,
-				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
+			    mic_bias_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 	SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0),
@@ -665,8 +665,7 @@
 				  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 snd_soc_codec *codec = dai->codec;
 	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 	int channels = params_channels(params);
 	int i2s_ctl = 0;
@@ -1455,17 +1454,7 @@
 	.id_table = sgtl5000_id,
 };
 
-static int __init sgtl5000_modinit(void)
-{
-	return i2c_add_driver(&sgtl5000_i2c_driver);
-}
-module_init(sgtl5000_modinit);
-
-static void __exit sgtl5000_exit(void)
-{
-	i2c_del_driver(&sgtl5000_i2c_driver);
-}
-module_exit(sgtl5000_exit);
+module_i2c_driver(sgtl5000_i2c_driver);
 
 MODULE_DESCRIPTION("Freescale SGTL5000 ALSA SoC Codec Driver");
 MODULE_AUTHOR("Zeng Zhaoming <zengzm.kernel@gmail.com>");
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index de2b205..079066f 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -33,6 +33,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -43,8 +44,6 @@
 
 #include "ssm2602.h"
 
-#define SSM2602_VERSION "0.1"
-
 enum ssm2602_type {
 	SSM2602,
 	SSM2604,
@@ -53,10 +52,12 @@
 /* codec private data */
 struct ssm2602_priv {
 	unsigned int sysclk;
-	enum snd_soc_control_type control_type;
+	struct snd_pcm_hw_constraint_list *sysclk_constraints;
 	struct snd_pcm_substream *master_substream;
 	struct snd_pcm_substream *slave_substream;
 
+	struct regmap *regmap;
+
 	enum ssm2602_type type;
 	unsigned int clk_out_pwr;
 };
@@ -73,7 +74,6 @@
 	0x0000, 0x0000
 };
 
-#define ssm2602_reset(c)	snd_soc_write(c, SSM2602_RESET, 0)
 
 /*Appending several "None"s just for OSS mixer use*/
 static const char *ssm2602_input_select[] = {
@@ -195,6 +195,24 @@
 	{"ADC", NULL, "Line Input"},
 };
 
+static const unsigned int ssm2602_rates_12288000[] = {
+	8000, 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
+	.list = ssm2602_rates_12288000,
+	.count = ARRAY_SIZE(ssm2602_rates_12288000),
+};
+
+static const unsigned int ssm2602_rates_11289600[] = {
+	8000, 44100, 88200,
+};
+
+static struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
+	.list = ssm2602_rates_11289600,
+	.count = ARRAY_SIZE(ssm2602_rates_11289600),
+};
+
 struct ssm2602_coeff {
 	u32 mclk;
 	u32 rate;
@@ -254,11 +272,10 @@
 	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 snd_soc_codec *codec = dai->codec;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-	u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
 	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
+	unsigned int iface;
 
 	if (substream == ssm2602->slave_substream) {
 		dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
@@ -268,31 +285,34 @@
 	if (srate < 0)
 		return srate;
 
-	snd_soc_write(codec, SSM2602_SRATE, srate);
+	regmap_write(ssm2602->regmap, SSM2602_SRATE, srate);
 
 	/* bit size */
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
+		iface = 0x0;
 		break;
 	case SNDRV_PCM_FORMAT_S20_3LE:
-		iface |= 0x0004;
+		iface = 0x4;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
-		iface |= 0x0008;
+		iface = 0x8;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
-		iface |= 0x000c;
+		iface = 0xc;
 		break;
+	default:
+		return -EINVAL;
 	}
-	snd_soc_write(codec, SSM2602_IFACE, iface);
+	regmap_update_bits(ssm2602->regmap, SSM2602_IFACE,
+		IFACE_AUDIO_DATA_LEN, iface);
 	return 0;
 }
 
 static int ssm2602_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 snd_soc_codec *codec = dai->codec;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 	struct snd_pcm_runtime *master_runtime;
 
@@ -322,14 +342,19 @@
 	} else
 		ssm2602->master_substream = substream;
 
+	if (ssm2602->sysclk_constraints) {
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE,
+				   ssm2602->sysclk_constraints);
+	}
+
 	return 0;
 }
 
 static void ssm2602_shutdown(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 snd_soc_codec *codec = dai->codec;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
 	if (ssm2602->master_substream == substream)
@@ -341,14 +366,14 @@
 
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec);
 
 	if (mute)
-		snd_soc_update_bits(codec, SSM2602_APDIGI,
+		regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
 				    APDIGI_ENABLE_DAC_MUTE,
 				    APDIGI_ENABLE_DAC_MUTE);
 	else
-		snd_soc_update_bits(codec, SSM2602_APDIGI,
+		regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
 				    APDIGI_ENABLE_DAC_MUTE, 0);
 	return 0;
 }
@@ -364,16 +389,21 @@
 			return -EINVAL;
 
 		switch (freq) {
-		case 11289600:
-		case 12000000:
 		case 12288000:
-		case 16934400:
 		case 18432000:
-			ssm2602->sysclk = freq;
+			ssm2602->sysclk_constraints = &ssm2602_constraints_12288000;
+			break;
+		case 11289600:
+		case 16934400:
+			ssm2602->sysclk_constraints = &ssm2602_constraints_11289600;
+			break;
+		case 12000000:
+			ssm2602->sysclk_constraints = NULL;
 			break;
 		default:
 			return -EINVAL;
 		}
+		ssm2602->sysclk = freq;
 	} else {
 		unsigned int mask;
 
@@ -393,7 +423,7 @@
 		else
 			ssm2602->clk_out_pwr &= ~mask;
 
-		snd_soc_update_bits(codec, SSM2602_PWR,
+		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
 			PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
 	}
 
@@ -403,8 +433,8 @@
 static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 iface = 0;
+	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec_dai->codec);
+	unsigned int iface = 0;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -455,7 +485,7 @@
 	}
 
 	/* set iface */
-	snd_soc_write(codec, SSM2602_IFACE, iface);
+	regmap_write(ssm2602->regmap, SSM2602_IFACE, iface);
 	return 0;
 }
 
@@ -467,7 +497,7 @@
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* vref/mid on, osc and clkout on if enabled */
-		snd_soc_update_bits(codec, SSM2602_PWR,
+		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
 			PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
 			ssm2602->clk_out_pwr);
 		break;
@@ -475,13 +505,13 @@
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* everything off except vref/vmid, */
-		snd_soc_update_bits(codec, SSM2602_PWR,
+		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
 			PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
 			PWR_CLK_OUT_PDN | PWR_OSC_PDN);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* everything off */
-		snd_soc_update_bits(codec, SSM2602_PWR,
+		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
 			PWR_POWER_OFF, PWR_POWER_OFF);
 		break;
 
@@ -540,12 +570,13 @@
 
 static int ssm2602_probe(struct snd_soc_codec *codec)
 {
+	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret;
 
-	snd_soc_update_bits(codec, SSM2602_LOUT1V,
+	regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
 			    LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
-	snd_soc_update_bits(codec, SSM2602_ROUT1V,
+	regmap_update_bits(ssm2602->regmap, SSM2602_ROUT1V,
 			    ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
 
 	ret = snd_soc_add_codec_controls(codec, ssm2602_snd_controls,
@@ -581,27 +612,26 @@
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
-	pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
-
-	ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type);
+	codec->control_data = ssm2602->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
 	}
 
-	ret = ssm2602_reset(codec);
+	ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
 		return ret;
 	}
 
 	/* set the update bits */
-	snd_soc_update_bits(codec, SSM2602_LINVOL,
+	regmap_update_bits(ssm2602->regmap, SSM2602_LINVOL,
 			    LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
-	snd_soc_update_bits(codec, SSM2602_RINVOL,
+	regmap_update_bits(ssm2602->regmap, SSM2602_RINVOL,
 			    RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
 	/*select Line in as default input*/
-	snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
+	regmap_write(ssm2602->regmap, SSM2602_APANA, APANA_SELECT_DAC |
 			APANA_ENABLE_MIC_BOOST);
 
 	switch (ssm2602->type) {
@@ -634,9 +664,6 @@
 	.suspend =	ssm2602_suspend,
 	.resume =	ssm2602_resume,
 	.set_bias_level = ssm2602_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(ssm2602_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = ssm2602_reg,
 
 	.controls = ssm260x_snd_controls,
 	.num_controls = ARRAY_SIZE(ssm260x_snd_controls),
@@ -646,6 +673,23 @@
 	.num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
 };
 
+static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == SSM2602_RESET;
+}
+
+static const struct regmap_config ssm2602_regmap_config = {
+	.val_bits = 9,
+	.reg_bits = 7,
+
+	.max_register = SSM2602_RESET,
+	.volatile_reg = ssm2602_register_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults_raw = ssm2602_reg,
+	.num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg),
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit ssm2602_spi_probe(struct spi_device *spi)
 {
@@ -658,9 +702,12 @@
 		return -ENOMEM;
 
 	spi_set_drvdata(spi, ssm2602);
-	ssm2602->control_type = SND_SOC_SPI;
 	ssm2602->type = SSM2602;
 
+	ssm2602->regmap = devm_regmap_init_spi(spi, &ssm2602_regmap_config);
+	if (IS_ERR(ssm2602->regmap))
+		return PTR_ERR(ssm2602->regmap);
+
 	ret = snd_soc_register_codec(&spi->dev,
 			&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
 	return ret;
@@ -701,9 +748,12 @@
 		return -ENOMEM;
 
 	i2c_set_clientdata(i2c, ssm2602);
-	ssm2602->control_type = SND_SOC_I2C;
 	ssm2602->type = id->driver_data;
 
+	ssm2602->regmap = devm_regmap_init_i2c(i2c, &ssm2602_regmap_config);
+	if (IS_ERR(ssm2602->regmap))
+		return PTR_ERR(ssm2602->regmap);
+
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
 	return ret;
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 7db6fa5..8d717f4 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -609,8 +609,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
 	unsigned int rate;
 	int i, mcs = -1, ir = -1;
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index df1e07f..31762eb 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -34,8 +34,6 @@
 
 #include "tlv320aic23.h"
 
-#define AIC23_VERSION "0.1"
-
 /*
  * AIC23 register cache
  */
@@ -325,8 +323,7 @@
 				 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 snd_soc_codec *codec = dai->codec;
 	u16 iface_reg;
 	int ret;
 	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
@@ -371,8 +368,7 @@
 static int tlv320aic23_pcm_prepare(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 snd_soc_codec *codec = dai->codec;
 
 	/* set active */
 	snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -383,8 +379,7 @@
 static void tlv320aic23_shutdown(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 snd_soc_codec *codec = dai->codec;
 	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
 
 	/* deactivate */
@@ -548,8 +543,6 @@
 	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
-	printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
-
 	ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 802064b..85944e9 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -126,8 +126,7 @@
 			   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 snd_soc_codec *codec = dai->codec;
 	struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
 	int fsref, divisor, wlen, pval, jval, dval, qval;
 	u16 reg;
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 8d20f6e..64d2a4f 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -802,8 +802,7 @@
 			   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 snd_soc_codec *codec = dai->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;
@@ -1161,24 +1160,6 @@
 	return 0;
 }
 
-void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
-				 int headset_debounce, int button_debounce)
-{
-	u8 val;
-
-	val = ((detect & AIC3X_HEADSET_DETECT_MASK)
-		<< AIC3X_HEADSET_DETECT_SHIFT) |
-	      ((headset_debounce & AIC3X_HEADSET_DEBOUNCE_MASK)
-		<< AIC3X_HEADSET_DEBOUNCE_SHIFT) |
-	      ((button_debounce & AIC3X_BUTTON_DEBOUNCE_MASK)
-		<< AIC3X_BUTTON_DEBOUNCE_SHIFT);
-
-	if (detect & AIC3X_HEADSET_DETECT_MASK)
-		val |= AIC3X_HEADSET_DETECT_ENABLED;
-
-	snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
-}
-
 #define AIC3X_RATES	SNDRV_PCM_RATE_8000_96000
 #define AIC3X_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 4587ddd..0dd4107 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -62,8 +62,10 @@
 #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
 	(((samples)*5000) / (((burstrate)*5000) / ((burstrate) - (playrate))))
 
-static void dac33_calculate_times(struct snd_pcm_substream *substream);
-static int dac33_prepare_chip(struct snd_pcm_substream *substream);
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+				  struct snd_soc_codec *codec);
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+			      struct snd_soc_codec *codec);
 
 enum dac33_state {
 	DAC33_IDLE = 0,
@@ -427,8 +429,8 @@
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (likely(dac33->substream)) {
-			dac33_calculate_times(dac33->substream);
-			dac33_prepare_chip(dac33->substream);
+			dac33_calculate_times(dac33->substream, w->codec);
+			dac33_prepare_chip(dac33->substream, w->codec);
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
@@ -799,8 +801,7 @@
 static int dac33_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 snd_soc_codec *codec = dai->codec;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
 	/* Stream started, save the substream pointer */
@@ -812,8 +813,7 @@
 static void dac33_shutdown(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 snd_soc_codec *codec = dai->codec;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
 	dac33->substream = NULL;
@@ -825,8 +825,7 @@
 			   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 snd_soc_codec *codec = dai->codec;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
 	/* Check parameters for validity */
@@ -868,10 +867,9 @@
  * writes happens in different order, than dac33 might end up in unknown state.
  * Use the known, working sequence of register writes to initialize the dac33.
  */
-static int dac33_prepare_chip(struct snd_pcm_substream *substream)
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+			      struct snd_soc_codec *codec)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	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;
@@ -1067,10 +1065,9 @@
 	return 0;
 }
 
-static void dac33_calculate_times(struct snd_pcm_substream *substream)
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+				  struct snd_soc_codec *codec)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	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;
@@ -1128,8 +1125,7 @@
 static int dac33_pcm_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_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
 
@@ -1161,8 +1157,7 @@
 			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 snd_soc_codec *codec = dai->codec;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	unsigned long long t0, t1, t_now;
 	unsigned int time_delta, uthr;
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 170cf9a..391fcfc 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -1685,8 +1685,7 @@
 static int twl4030_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 snd_soc_codec *codec = dai->codec;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
 	if (twl4030->master_substream) {
@@ -1715,8 +1714,7 @@
 static void twl4030_shutdown(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 snd_soc_codec *codec = dai->codec;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
 	if (twl4030->master_substream == substream)
@@ -1740,8 +1738,7 @@
 			   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 snd_soc_codec *codec = dai->codec;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 	u8 mode, old_mode, format, old_format;
 
@@ -1974,8 +1971,7 @@
 static int twl4030_voice_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 snd_soc_codec *codec = dai->codec;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 	u8 mode;
 
@@ -2007,8 +2003,7 @@
 static void twl4030_voice_shutdown(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 snd_soc_codec *codec = dai->codec;
 
 	/* Enable voice digital filters */
 	twl4030_voice_enable(codec, substream->stream, 0);
@@ -2017,8 +2012,7 @@
 static int twl4030_voice_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 snd_soc_codec *codec = dai->codec;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 	u8 old_mode, mode;
 
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index dc7509b..a36e9fc 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -46,17 +46,6 @@
 #define TWL6040_OUTHF_0dB 0x03
 #define TWL6040_OUTHF_M52dB 0x1D
 
-#define TWL6040_RAMP_NONE	0
-#define TWL6040_RAMP_UP		1
-#define TWL6040_RAMP_DOWN	2
-
-#define TWL6040_HSL_VOL_MASK	0x0F
-#define TWL6040_HSL_VOL_SHIFT	0
-#define TWL6040_HSR_VOL_MASK	0xF0
-#define TWL6040_HSR_VOL_SHIFT	4
-#define TWL6040_HF_VOL_MASK	0x1F
-#define TWL6040_HF_VOL_SHIFT	0
-
 /* Shadow register used by the driver */
 #define TWL6040_REG_SW_SHADOW	0x2F
 #define TWL6040_CACHEREGNUM	(TWL6040_REG_SW_SHADOW + 1)
@@ -64,18 +53,6 @@
 /* TWL6040_REG_SW_SHADOW (0x2F) fields */
 #define TWL6040_EAR_PATH_ENABLE	0x01
 
-struct twl6040_output {
-	u16 active;
-	u16 left_vol;
-	u16 right_vol;
-	u16 left_step;
-	u16 right_step;
-	unsigned int step_delay;
-	u16 ramp;
-	struct delayed_work work;
-	struct completion ramp_done;
-};
-
 struct twl6040_jack_data {
 	struct snd_soc_jack *jack;
 	struct delayed_work work;
@@ -100,8 +77,6 @@
 	struct snd_soc_codec *codec;
 	struct workqueue_struct *workqueue;
 	struct mutex mutex;
-	struct twl6040_output headset;
-	struct twl6040_output handsfree;
 };
 
 /*
@@ -311,318 +286,6 @@
 	}
 }
 
-/*
- * Ramp HS PGA volume to minimise pops at stream startup and shutdown.
- */
-static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
-			unsigned int left_step, unsigned int right_step)
-{
-
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-	struct twl6040_output *headset = &priv->headset;
-	int left_complete = 0, right_complete = 0;
-	u8 reg, val;
-
-	/* left channel */
-	left_step = (left_step > 0xF) ? 0xF : left_step;
-	reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
-	val = (~reg & TWL6040_HSL_VOL_MASK);
-
-	if (headset->ramp == TWL6040_RAMP_UP) {
-		/* ramp step up */
-		if (val < headset->left_vol) {
-			if (val + left_step > headset->left_vol)
-				val = headset->left_vol;
-			else
-				val += left_step;
-
-			reg &= ~TWL6040_HSL_VOL_MASK;
-			twl6040_write(codec, TWL6040_REG_HSGAIN,
-					(reg | (~val & TWL6040_HSL_VOL_MASK)));
-		} else {
-			left_complete = 1;
-		}
-	} else if (headset->ramp == TWL6040_RAMP_DOWN) {
-		/* ramp step down */
-		if (val > 0x0) {
-			if ((int)val - (int)left_step < 0)
-				val = 0;
-			else
-				val -= left_step;
-
-			reg &= ~TWL6040_HSL_VOL_MASK;
-			twl6040_write(codec, TWL6040_REG_HSGAIN, reg |
-						(~val & TWL6040_HSL_VOL_MASK));
-		} else {
-			left_complete = 1;
-		}
-	}
-
-	/* right channel */
-	right_step = (right_step > 0xF) ? 0xF : right_step;
-	reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
-	val = (~reg & TWL6040_HSR_VOL_MASK) >> TWL6040_HSR_VOL_SHIFT;
-
-	if (headset->ramp == TWL6040_RAMP_UP) {
-		/* ramp step up */
-		if (val < headset->right_vol) {
-			if (val + right_step > headset->right_vol)
-				val = headset->right_vol;
-			else
-				val += right_step;
-
-			reg &= ~TWL6040_HSR_VOL_MASK;
-			twl6040_write(codec, TWL6040_REG_HSGAIN,
-				(reg | (~val << TWL6040_HSR_VOL_SHIFT)));
-		} else {
-			right_complete = 1;
-		}
-	} else if (headset->ramp == TWL6040_RAMP_DOWN) {
-		/* ramp step down */
-		if (val > 0x0) {
-			if ((int)val - (int)right_step < 0)
-				val = 0;
-			else
-				val -= right_step;
-
-			reg &= ~TWL6040_HSR_VOL_MASK;
-			twl6040_write(codec, TWL6040_REG_HSGAIN,
-					 reg | (~val << TWL6040_HSR_VOL_SHIFT));
-		} else {
-			right_complete = 1;
-		}
-	}
-
-	return left_complete & right_complete;
-}
-
-/*
- * Ramp HF PGA volume to minimise pops at stream startup and shutdown.
- */
-static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
-			unsigned int left_step, unsigned int right_step)
-{
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-	struct twl6040_output *handsfree = &priv->handsfree;
-	int left_complete = 0, right_complete = 0;
-	u16 reg, val;
-
-	/* left channel */
-	left_step = (left_step > 0x1D) ? 0x1D : left_step;
-	reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFLGAIN);
-	reg = 0x1D - reg;
-	val = (reg & TWL6040_HF_VOL_MASK);
-	if (handsfree->ramp == TWL6040_RAMP_UP) {
-		/* ramp step up */
-		if (val < handsfree->left_vol) {
-			if (val + left_step > handsfree->left_vol)
-				val = handsfree->left_vol;
-			else
-				val += left_step;
-
-			reg &= ~TWL6040_HF_VOL_MASK;
-			twl6040_write(codec, TWL6040_REG_HFLGAIN,
-						reg | (0x1D - val));
-		} else {
-			left_complete = 1;
-		}
-	} else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
-		/* ramp step down */
-		if (val > 0) {
-			if ((int)val - (int)left_step < 0)
-				val = 0;
-			else
-				val -= left_step;
-
-			reg &= ~TWL6040_HF_VOL_MASK;
-			twl6040_write(codec, TWL6040_REG_HFLGAIN,
-						reg | (0x1D - val));
-		} else {
-			left_complete = 1;
-		}
-	}
-
-	/* right channel */
-	right_step = (right_step > 0x1D) ? 0x1D : right_step;
-	reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFRGAIN);
-	reg = 0x1D - reg;
-	val = (reg & TWL6040_HF_VOL_MASK);
-	if (handsfree->ramp == TWL6040_RAMP_UP) {
-		/* ramp step up */
-		if (val < handsfree->right_vol) {
-			if (val + right_step > handsfree->right_vol)
-				val = handsfree->right_vol;
-			else
-				val += right_step;
-
-			reg &= ~TWL6040_HF_VOL_MASK;
-			twl6040_write(codec, TWL6040_REG_HFRGAIN,
-						reg | (0x1D - val));
-		} else {
-			right_complete = 1;
-		}
-	} else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
-		/* ramp step down */
-		if (val > 0) {
-			if ((int)val - (int)right_step < 0)
-				val = 0;
-			else
-				val -= right_step;
-
-			reg &= ~TWL6040_HF_VOL_MASK;
-			twl6040_write(codec, TWL6040_REG_HFRGAIN,
-						reg | (0x1D - val));
-		}
-	}
-
-	return left_complete & right_complete;
-}
-
-/*
- * This work ramps both output PGAs at stream start/stop time to
- * minimise pop associated with DAPM power switching.
- */
-static void twl6040_pga_hs_work(struct work_struct *work)
-{
-	struct twl6040_data *priv =
-		container_of(work, struct twl6040_data, headset.work.work);
-	struct snd_soc_codec *codec = priv->codec;
-	struct twl6040_output *headset = &priv->headset;
-	int i, headset_complete;
-
-	/* do we need to ramp at all ? */
-	if (headset->ramp == TWL6040_RAMP_NONE)
-		return;
-
-	/* HS PGA gain range: 0x0 - 0xf (0 - 15) */
-	for (i = 0; i < 16; i++) {
-		headset_complete = twl6040_hs_ramp_step(codec,
-						headset->left_step,
-						headset->right_step);
-
-		/* ramp finished ? */
-		if (headset_complete)
-			break;
-
-		schedule_timeout_interruptible(
-				msecs_to_jiffies(headset->step_delay));
-	}
-
-	if (headset->ramp == TWL6040_RAMP_DOWN) {
-		headset->active = 0;
-		complete(&headset->ramp_done);
-	} else {
-		headset->active = 1;
-	}
-	headset->ramp = TWL6040_RAMP_NONE;
-}
-
-static void twl6040_pga_hf_work(struct work_struct *work)
-{
-	struct twl6040_data *priv =
-		container_of(work, struct twl6040_data, handsfree.work.work);
-	struct snd_soc_codec *codec = priv->codec;
-	struct twl6040_output *handsfree = &priv->handsfree;
-	int i, handsfree_complete;
-
-	/* do we need to ramp at all ? */
-	if (handsfree->ramp == TWL6040_RAMP_NONE)
-		return;
-
-	/*
-	 * HF PGA gain range: 0x00 - 0x1d (0 - 29) */
-	for (i = 0; i < 30; i++) {
-		handsfree_complete = twl6040_hf_ramp_step(codec,
-						handsfree->left_step,
-						handsfree->right_step);
-
-		/* ramp finished ? */
-		if (handsfree_complete)
-			break;
-
-		schedule_timeout_interruptible(
-				msecs_to_jiffies(handsfree->step_delay));
-	}
-
-
-	if (handsfree->ramp == TWL6040_RAMP_DOWN) {
-		handsfree->active = 0;
-		complete(&handsfree->ramp_done);
-	} else
-		handsfree->active = 1;
-	handsfree->ramp = TWL6040_RAMP_NONE;
-}
-
-static int out_drv_event(struct snd_soc_dapm_widget *w,
-			struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-	struct twl6040_output *out;
-	struct delayed_work *work;
-
-	switch (w->shift) {
-	case 2: /* Headset output driver */
-		out = &priv->headset;
-		work = &out->work;
-		/*
-		 * Make sure, that we do not mess up variables for already
-		 * executing work.
-		 */
-		cancel_delayed_work_sync(work);
-
-		out->left_step = priv->hs_left_step;
-		out->right_step = priv->hs_right_step;
-		out->step_delay = 5;	/* 5 ms between volume ramp steps */
-		break;
-	case 4: /* Handsfree output driver */
-		out = &priv->handsfree;
-		work = &out->work;
-		/*
-		 * Make sure, that we do not mess up variables for already
-		 * executing work.
-		 */
-		cancel_delayed_work_sync(work);
-
-		out->left_step = priv->hf_left_step;
-		out->right_step = priv->hf_right_step;
-		out->step_delay = 5;	/* 5 ms between volume ramp steps */
-		break;
-	default:
-		return -1;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		if (out->active)
-			break;
-
-		/* don't use volume ramp for power-up */
-		out->ramp = TWL6040_RAMP_UP;
-		out->left_step = out->left_vol;
-		out->right_step = out->right_vol;
-
-		queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
-		break;
-
-	case SND_SOC_DAPM_PRE_PMD:
-		if (!out->active)
-			break;
-
-		/* use volume ramp for power-down */
-		out->ramp = TWL6040_RAMP_DOWN;
-		INIT_COMPLETION(out->ramp_done);
-
-		queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
-
-		wait_for_completion_timeout(&out->ramp_done,
-					    msecs_to_jiffies(2000));
-		break;
-	}
-
-	return 0;
-}
-
 /* set headset dac and driver power mode */
 static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 {
@@ -747,71 +410,6 @@
 	return IRQ_HANDLED;
 }
 
-static int twl6040_put_volsw(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
-	struct twl6040_output *out = NULL;
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	int ret;
-
-	/* For HS and HF we shadow the values and only actually write
-	 * them out when active in order to ensure the amplifier comes on
-	 * as quietly as possible. */
-	switch (mc->reg) {
-	case TWL6040_REG_HSGAIN:
-		out = &twl6040_priv->headset;
-		break;
-	case TWL6040_REG_HFLGAIN:
-		out = &twl6040_priv->handsfree;
-		break;
-	default:
-		dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
-					__func__, mc->reg);
-		return -EINVAL;
-	}
-
-	out->left_vol = ucontrol->value.integer.value[0];
-	out->right_vol = ucontrol->value.integer.value[1];
-	if (!out->active)
-		return 1;
-
-	ret = snd_soc_put_volsw(kcontrol, ucontrol);
-	if (ret < 0)
-		return ret;
-
-	return 1;
-}
-
-static int twl6040_get_volsw(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
-	struct twl6040_output *out = &twl6040_priv->headset;
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-
-	switch (mc->reg) {
-	case TWL6040_REG_HSGAIN:
-		out = &twl6040_priv->headset;
-		break;
-	case TWL6040_REG_HFLGAIN:
-		out = &twl6040_priv->handsfree;
-		break;
-	default:
-		dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
-					__func__, mc->reg);
-		return -EINVAL;
-	}
-
-	ucontrol->value.integer.value[0] = out->left_vol;
-	ucontrol->value.integer.value[1] = out->right_vol;
-	return 0;
-}
-
 static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -1076,12 +674,10 @@
 		TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
 
 	/* Playback gains */
-	SOC_DOUBLE_EXT_TLV("Headset Playback Volume",
-		TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, twl6040_get_volsw,
-		twl6040_put_volsw, hs_tlv),
-	SOC_DOUBLE_R_EXT_TLV("Handsfree Playback Volume",
-		TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1,
-		twl6040_get_volsw, twl6040_put_volsw, hf_tlv),
+	SOC_DOUBLE_TLV("Headset Playback Volume",
+		TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv),
+	SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
+		TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
 	SOC_SINGLE_TLV("Earphone Playback Volume",
 		TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
 
@@ -1180,22 +776,14 @@
 			&auxr_switch_control),
 
 	/* Analog playback drivers */
-	SND_SOC_DAPM_OUT_DRV_E("HF Left Driver",
-			TWL6040_REG_HFLCTL, 4, 0, NULL, 0,
-			out_drv_event,
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-	SND_SOC_DAPM_OUT_DRV_E("HF Right Driver",
-			TWL6040_REG_HFRCTL, 4, 0, NULL, 0,
-			out_drv_event,
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-	SND_SOC_DAPM_OUT_DRV_E("HS Left Driver",
-			TWL6040_REG_HSLCTL, 2, 0, NULL, 0,
-			out_drv_event,
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-	SND_SOC_DAPM_OUT_DRV_E("HS Right Driver",
-			TWL6040_REG_HSRCTL, 2, 0, NULL, 0,
-			out_drv_event,
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_OUT_DRV("HF Left Driver",
+			TWL6040_REG_HFLCTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HF Right Driver",
+			TWL6040_REG_HFRCTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HS Left Driver",
+			TWL6040_REG_HSLCTL, 2, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HS Right Driver",
+			TWL6040_REG_HSRCTL, 2, 0, NULL, 0),
 	SND_SOC_DAPM_OUT_DRV_E("Earphone Driver",
 			TWL6040_REG_EARCTL, 0, 0, NULL, 0,
 			twl6040_ep_drv_event,
@@ -1339,8 +927,7 @@
 static int twl6040_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 snd_soc_codec *codec = dai->codec;
 	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
 	snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -1354,8 +941,7 @@
 			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 snd_soc_codec *codec = dai->codec;
 	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 	int rate;
 
@@ -1391,8 +977,7 @@
 static int twl6040_prepare(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 snd_soc_codec *codec = dai->codec;
 	struct twl6040 *twl6040 = codec->control_data;
 	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 	int ret;
@@ -1570,14 +1155,9 @@
 	}
 
 	INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
-	INIT_DELAYED_WORK(&priv->headset.work, twl6040_pga_hs_work);
-	INIT_DELAYED_WORK(&priv->handsfree.work, twl6040_pga_hf_work);
 
 	mutex_init(&priv->mutex);
 
-	init_completion(&priv->headset.ramp_done);
-	init_completion(&priv->handsfree.ramp_done);
-
 	ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler,
 				   0, "twl6040_irq_plug", codec);
 	if (ret) {
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 797b0dd..6c3d43b 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -159,8 +159,7 @@
 static int uda134x_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 snd_soc_codec *codec = dai->codec;
 	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 	struct snd_pcm_runtime *master_runtime;
 
@@ -191,8 +190,7 @@
 static void uda134x_shutdown(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 snd_soc_codec *codec = dai->codec;
 	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 
 	if (uda134x->master_substream == substream)
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 4f1b23d..2502214 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -502,8 +502,7 @@
 static int uda1380_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_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
 	int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
 
@@ -528,8 +527,7 @@
 				 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 snd_soc_codec *codec = dai->codec;
 	u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
 	/* set WSPLL power and divider if running from this clock */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 3d868dc..7b24d6d 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -293,8 +293,7 @@
 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 snd_soc_codec *codec = dai->codec;
 	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
 
 	switch (wl1273->mode) {
@@ -329,8 +328,7 @@
 			    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_priv *wl1273 = snd_soc_codec_get_drvdata(dai->codec);
 	struct wl1273_core *core = wl1273->core;
 	unsigned int rate, width, r;
 
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index aefb4f8..e0b51e9 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -79,22 +79,65 @@
 	{ "WM1250 Output", NULL, "DAC" },
 };
 
+static int wm1250_ev1_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct wm1250_priv *wm1250 = snd_soc_codec_get_drvdata(dai->codec);
+
+	switch (params_rate(params)) {
+	case 8000:
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+			       1);
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+			       1);
+		break;
+	case 16000:
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+			       0);
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+			       1);
+		break;
+	case 32000:
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+			       1);
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+			       0);
+		break;
+	case 64000:
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+			       0);
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+			       0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wm1250_ev1_ops = {
+	.hw_params = wm1250_ev1_hw_params,
+};
+
 static struct snd_soc_dai_driver wm1250_ev1_dai = {
 	.name = "wm1250-ev1",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
-		.channels_max = 1,
+		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_8000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 	.capture = {
 		.stream_name = "Capture",
 		.channels_min = 1,
-		.channels_max = 1,
+		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_8000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
+	.ops = &wm1250_ev1_ops,
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
@@ -215,23 +258,7 @@
 	.id_table = wm1250_ev1_i2c_id,
 };
 
-static int __init wm1250_ev1_modinit(void)
-{
-	int ret = 0;
-
-	ret = i2c_add_driver(&wm1250_ev1_i2c_driver);
-	if (ret != 0)
-		pr_err("Failed to register WM1250-EV1 I2C driver: %d\n", ret);
-
-	return ret;
-}
-module_init(wm1250_ev1_modinit);
-
-static void __exit wm1250_ev1_exit(void)
-{
-	i2c_del_driver(&wm1250_ev1_i2c_driver);
-}
-module_exit(wm1250_ev1_exit);
+module_i2c_driver(wm1250_ev1_i2c_driver);
 
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_DESCRIPTION("WM1250-EV1 audio I/O module driver");
diff --git a/sound/soc/codecs/wm5100-tables.c b/sound/soc/codecs/wm5100-tables.c
index 9a18fae..e167207 100644
--- a/sound/soc/codecs/wm5100-tables.c
+++ b/sound/soc/codecs/wm5100-tables.c
@@ -32,7 +32,18 @@
 	case WM5100_MIC_DETECT_3:
 		return 1;
 	default:
-		return 0;
+		if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
+		    (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
+		    (reg >= WM5100_DSP1_DM_0 && reg <= WM5100_DSP1_DM_511) ||
+		    (reg >= WM5100_DSP2_PM_0 && reg <= WM5100_DSP2_PM_1535) ||
+		    (reg >= WM5100_DSP2_ZM_0 && reg <= WM5100_DSP2_ZM_2047) ||
+		    (reg >= WM5100_DSP2_DM_0 && reg <= WM5100_DSP2_DM_511) ||
+		    (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
+		    (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
+		    (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
+			return 1;
+		else
+			return 0;
 	}
 }
 
@@ -697,9 +708,110 @@
 	case WM5100_HPLPF3_2:
 	case WM5100_HPLPF4_1:
 	case WM5100_HPLPF4_2:
+	case WM5100_DSP1_CONTROL_1:
+	case WM5100_DSP1_CONTROL_2:
+	case WM5100_DSP1_CONTROL_3:
+	case WM5100_DSP1_CONTROL_4:
+	case WM5100_DSP1_CONTROL_5:
+	case WM5100_DSP1_CONTROL_6:
+	case WM5100_DSP1_CONTROL_7:
+	case WM5100_DSP1_CONTROL_8:
+	case WM5100_DSP1_CONTROL_9:
+	case WM5100_DSP1_CONTROL_10:
+	case WM5100_DSP1_CONTROL_11:
+	case WM5100_DSP1_CONTROL_12:
+	case WM5100_DSP1_CONTROL_13:
+	case WM5100_DSP1_CONTROL_14:
+	case WM5100_DSP1_CONTROL_15:
+	case WM5100_DSP1_CONTROL_16:
+	case WM5100_DSP1_CONTROL_17:
+	case WM5100_DSP1_CONTROL_18:
+	case WM5100_DSP1_CONTROL_19:
+	case WM5100_DSP1_CONTROL_20:
+	case WM5100_DSP1_CONTROL_21:
+	case WM5100_DSP1_CONTROL_22:
+	case WM5100_DSP1_CONTROL_23:
+	case WM5100_DSP1_CONTROL_24:
+	case WM5100_DSP1_CONTROL_25:
+	case WM5100_DSP1_CONTROL_26:
+	case WM5100_DSP1_CONTROL_27:
+	case WM5100_DSP1_CONTROL_28:
+	case WM5100_DSP1_CONTROL_29:
+	case WM5100_DSP1_CONTROL_30:
+	case WM5100_DSP2_CONTROL_1:
+	case WM5100_DSP2_CONTROL_2:
+	case WM5100_DSP2_CONTROL_3:
+	case WM5100_DSP2_CONTROL_4:
+	case WM5100_DSP2_CONTROL_5:
+	case WM5100_DSP2_CONTROL_6:
+	case WM5100_DSP2_CONTROL_7:
+	case WM5100_DSP2_CONTROL_8:
+	case WM5100_DSP2_CONTROL_9:
+	case WM5100_DSP2_CONTROL_10:
+	case WM5100_DSP2_CONTROL_11:
+	case WM5100_DSP2_CONTROL_12:
+	case WM5100_DSP2_CONTROL_13:
+	case WM5100_DSP2_CONTROL_14:
+	case WM5100_DSP2_CONTROL_15:
+	case WM5100_DSP2_CONTROL_16:
+	case WM5100_DSP2_CONTROL_17:
+	case WM5100_DSP2_CONTROL_18:
+	case WM5100_DSP2_CONTROL_19:
+	case WM5100_DSP2_CONTROL_20:
+	case WM5100_DSP2_CONTROL_21:
+	case WM5100_DSP2_CONTROL_22:
+	case WM5100_DSP2_CONTROL_23:
+	case WM5100_DSP2_CONTROL_24:
+	case WM5100_DSP2_CONTROL_25:
+	case WM5100_DSP2_CONTROL_26:
+	case WM5100_DSP2_CONTROL_27:
+	case WM5100_DSP2_CONTROL_28:
+	case WM5100_DSP2_CONTROL_29:
+	case WM5100_DSP2_CONTROL_30:
+	case WM5100_DSP3_CONTROL_1:
+	case WM5100_DSP3_CONTROL_2:
+	case WM5100_DSP3_CONTROL_3:
+	case WM5100_DSP3_CONTROL_4:
+	case WM5100_DSP3_CONTROL_5:
+	case WM5100_DSP3_CONTROL_6:
+	case WM5100_DSP3_CONTROL_7:
+	case WM5100_DSP3_CONTROL_8:
+	case WM5100_DSP3_CONTROL_9:
+	case WM5100_DSP3_CONTROL_10:
+	case WM5100_DSP3_CONTROL_11:
+	case WM5100_DSP3_CONTROL_12:
+	case WM5100_DSP3_CONTROL_13:
+	case WM5100_DSP3_CONTROL_14:
+	case WM5100_DSP3_CONTROL_15:
+	case WM5100_DSP3_CONTROL_16:
+	case WM5100_DSP3_CONTROL_17:
+	case WM5100_DSP3_CONTROL_18:
+	case WM5100_DSP3_CONTROL_19:
+	case WM5100_DSP3_CONTROL_20:
+	case WM5100_DSP3_CONTROL_21:
+	case WM5100_DSP3_CONTROL_22:
+	case WM5100_DSP3_CONTROL_23:
+	case WM5100_DSP3_CONTROL_24:
+	case WM5100_DSP3_CONTROL_25:
+	case WM5100_DSP3_CONTROL_26:
+	case WM5100_DSP3_CONTROL_27:
+	case WM5100_DSP3_CONTROL_28:
+	case WM5100_DSP3_CONTROL_29:
+	case WM5100_DSP3_CONTROL_30:
 		return 1;
 	default:
-		return 0;
+		if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
+		    (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
+		    (reg >= WM5100_DSP1_DM_0 && reg <= WM5100_DSP1_DM_511) ||
+		    (reg >= WM5100_DSP2_PM_0 && reg <= WM5100_DSP2_PM_1535) ||
+		    (reg >= WM5100_DSP2_ZM_0 && reg <= WM5100_DSP2_ZM_2047) ||
+		    (reg >= WM5100_DSP2_DM_0 && reg <= WM5100_DSP2_DM_511) ||
+		    (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
+		    (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
+		    (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
+			return 1;
+		else
+			return 0;
 	}
 }
 
@@ -1361,4 +1473,13 @@
 	{ 0x0EC9, 0x0000 },  /* R3785  - HPLPF3_2 */
 	{ 0x0ECC, 0x0000 },  /* R3788  - HPLPF4_1 */
 	{ 0x0ECD, 0x0000 },  /* R3789  - HPLPF4_2 */
+	{ 0x0F02, 0x0000 },  /* R3842  - DSP1 Control 2 */
+	{ 0x0F03, 0x0000 },  /* R3843  - DSP1 Control 3 */
+	{ 0x0F04, 0x0000 },  /* R3844  - DSP1 Control 4 */
+	{ 0x1002, 0x0000 },  /* R4098  - DSP2 Control 2 */
+	{ 0x1003, 0x0000 },  /* R4099  - DSP2 Control 3 */
+	{ 0x1004, 0x0000 },  /* R4100  - DSP2 Control 4 */
+	{ 0x1102, 0x0000 },  /* R4354  - DSP3 Control 2 */
+	{ 0x1103, 0x0000 },  /* R4355  - DSP3 Control 3 */
+	{ 0x1104, 0x0000 },  /* R4356  - DSP3 Control 4 */
 };
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index b9c185c..cb6d537 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -1265,29 +1265,12 @@
 	{ WM5100_AUDIO_IF_3_19, 1 },
 };
 
-static int wm5100_dai_to_base(struct snd_soc_dai *dai)
-{
-	switch (dai->id) {
-	case 0:
-		return WM5100_AUDIO_IF_1_1 - 1;
-	case 1:
-		return WM5100_AUDIO_IF_2_1 - 1;
-	case 2:
-		return WM5100_AUDIO_IF_3_1 - 1;
-	default:
-		BUG();
-		return -EINVAL;
-	}
-}
-
 static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct snd_soc_codec *codec = dai->codec;
 	int lrclk, bclk, mask, base;
 
-	base = wm5100_dai_to_base(dai);
-	if (base < 0)
-		return base;
+	base = dai->driver->base;
 
 	lrclk = 0;
 	bclk = 0;
@@ -1414,9 +1397,7 @@
 	int i, base, bclk, aif_rate, lrclk, wl, fl, sr;
 	int *bclk_rates;
 
-	base = wm5100_dai_to_base(dai);
-	if (base < 0)
-		return base;
+	base = dai->driver->base;
 
 	/* Data sizes if not using TDM */
 	wl = snd_pcm_format_width(params_format(params));
@@ -1897,6 +1878,7 @@
 static struct snd_soc_dai_driver wm5100_dai[] = {
 	{
 		.name = "wm5100-aif1",
+		.base = WM5100_AUDIO_IF_1_1 - 1,
 		.playback = {
 			.stream_name = "AIF1 Playback",
 			.channels_min = 2,
@@ -1916,6 +1898,7 @@
 	{
 		.name = "wm5100-aif2",
 		.id = 1,
+		.base = WM5100_AUDIO_IF_2_1 - 1,
 		.playback = {
 			.stream_name = "AIF2 Playback",
 			.channels_min = 2,
@@ -1935,6 +1918,7 @@
 	{
 		.name = "wm5100-aif3",
 		.id = 2,
+		.base = WM5100_AUDIO_IF_3_1 - 1,
 		.playback = {
 			.stream_name = "AIF3 Playback",
 			.channels_min = 2,
@@ -2454,7 +2438,7 @@
 
 	wm5100->dev = &i2c->dev;
 
-	wm5100->regmap = regmap_init_i2c(i2c, &wm5100_regmap);
+	wm5100->regmap = devm_regmap_init_i2c(i2c, &wm5100_regmap);
 	if (IS_ERR(wm5100->regmap)) {
 		ret = PTR_ERR(wm5100->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -2479,7 +2463,7 @@
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
 			ret);
-		goto err_regmap;
+		goto err;
 	}
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
@@ -2487,7 +2471,7 @@
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
 			ret);
-		goto err_regmap;
+		goto err;
 	}
 
 	if (wm5100->pdata.ldo_ena) {
@@ -2660,8 +2644,6 @@
 err_enable:
 	regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
 			       wm5100->core_supplies);
-err_regmap:
-	regmap_exit(wm5100->regmap);
 err:
 	return ret;
 }
@@ -2682,7 +2664,6 @@
 		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
 		gpio_free(wm5100->pdata.ldo_ena);
 	}
-	regmap_exit(wm5100->regmap);
 
 	return 0;
 }
@@ -2749,17 +2730,7 @@
 	.id_table = wm5100_i2c_id,
 };
 
-static int __init wm5100_modinit(void)
-{
-	return i2c_add_driver(&wm5100_i2c_driver);
-}
-module_init(wm5100_modinit);
-
-static void __exit wm5100_exit(void)
-{
-	i2c_del_driver(&wm5100_i2c_driver);
-}
-module_exit(wm5100_exit);
+module_i2c_driver(wm5100_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM5100 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm5100.h b/sound/soc/codecs/wm5100.h
index 25cb601..935a9b7 100644
--- a/sound/soc/codecs/wm5100.h
+++ b/sound/soc/codecs/wm5100.h
@@ -709,6 +709,96 @@
 #define WM5100_HPLPF3_2                         0xEC9
 #define WM5100_HPLPF4_1                         0xECC
 #define WM5100_HPLPF4_2                         0xECD
+#define WM5100_DSP1_CONTROL_1                   0xF00
+#define WM5100_DSP1_CONTROL_2                   0xF02
+#define WM5100_DSP1_CONTROL_3                   0xF03
+#define WM5100_DSP1_CONTROL_4                   0xF04
+#define WM5100_DSP1_CONTROL_5                   0xF06
+#define WM5100_DSP1_CONTROL_6                   0xF07
+#define WM5100_DSP1_CONTROL_7                   0xF08
+#define WM5100_DSP1_CONTROL_8                   0xF09
+#define WM5100_DSP1_CONTROL_9                   0xF0A
+#define WM5100_DSP1_CONTROL_10                  0xF0B
+#define WM5100_DSP1_CONTROL_11                  0xF0C
+#define WM5100_DSP1_CONTROL_12                  0xF0D
+#define WM5100_DSP1_CONTROL_13                  0xF0F
+#define WM5100_DSP1_CONTROL_14                  0xF10
+#define WM5100_DSP1_CONTROL_15                  0xF11
+#define WM5100_DSP1_CONTROL_16                  0xF12
+#define WM5100_DSP1_CONTROL_17                  0xF13
+#define WM5100_DSP1_CONTROL_18                  0xF14
+#define WM5100_DSP1_CONTROL_19                  0xF16
+#define WM5100_DSP1_CONTROL_20                  0xF17
+#define WM5100_DSP1_CONTROL_21                  0xF18
+#define WM5100_DSP1_CONTROL_22                  0xF1A
+#define WM5100_DSP1_CONTROL_23                  0xF1B
+#define WM5100_DSP1_CONTROL_24                  0xF1C
+#define WM5100_DSP1_CONTROL_25                  0xF1E
+#define WM5100_DSP1_CONTROL_26                  0xF20
+#define WM5100_DSP1_CONTROL_27                  0xF21
+#define WM5100_DSP1_CONTROL_28                  0xF22
+#define WM5100_DSP1_CONTROL_29                  0xF23
+#define WM5100_DSP1_CONTROL_30                  0xF24
+#define WM5100_DSP2_CONTROL_1                   0x1000
+#define WM5100_DSP2_CONTROL_2                   0x1002
+#define WM5100_DSP2_CONTROL_3                   0x1003
+#define WM5100_DSP2_CONTROL_4                   0x1004
+#define WM5100_DSP2_CONTROL_5                   0x1006
+#define WM5100_DSP2_CONTROL_6                   0x1007
+#define WM5100_DSP2_CONTROL_7                   0x1008
+#define WM5100_DSP2_CONTROL_8                   0x1009
+#define WM5100_DSP2_CONTROL_9                   0x100A
+#define WM5100_DSP2_CONTROL_10                  0x100B
+#define WM5100_DSP2_CONTROL_11                  0x100C
+#define WM5100_DSP2_CONTROL_12                  0x100D
+#define WM5100_DSP2_CONTROL_13                  0x100F
+#define WM5100_DSP2_CONTROL_14                  0x1010
+#define WM5100_DSP2_CONTROL_15                  0x1011
+#define WM5100_DSP2_CONTROL_16                  0x1012
+#define WM5100_DSP2_CONTROL_17                  0x1013
+#define WM5100_DSP2_CONTROL_18                  0x1014
+#define WM5100_DSP2_CONTROL_19                  0x1016
+#define WM5100_DSP2_CONTROL_20                  0x1017
+#define WM5100_DSP2_CONTROL_21                  0x1018
+#define WM5100_DSP2_CONTROL_22                  0x101A
+#define WM5100_DSP2_CONTROL_23                  0x101B
+#define WM5100_DSP2_CONTROL_24                  0x101C
+#define WM5100_DSP2_CONTROL_25                  0x101E
+#define WM5100_DSP2_CONTROL_26                  0x1020
+#define WM5100_DSP2_CONTROL_27                  0x1021
+#define WM5100_DSP2_CONTROL_28                  0x1022
+#define WM5100_DSP2_CONTROL_29                  0x1023
+#define WM5100_DSP2_CONTROL_30                  0x1024
+#define WM5100_DSP3_CONTROL_1                   0x1100
+#define WM5100_DSP3_CONTROL_2                   0x1102
+#define WM5100_DSP3_CONTROL_3                   0x1103
+#define WM5100_DSP3_CONTROL_4                   0x1104
+#define WM5100_DSP3_CONTROL_5                   0x1106
+#define WM5100_DSP3_CONTROL_6                   0x1107
+#define WM5100_DSP3_CONTROL_7                   0x1108
+#define WM5100_DSP3_CONTROL_8                   0x1109
+#define WM5100_DSP3_CONTROL_9                   0x110A
+#define WM5100_DSP3_CONTROL_10                  0x110B
+#define WM5100_DSP3_CONTROL_11                  0x110C
+#define WM5100_DSP3_CONTROL_12                  0x110D
+#define WM5100_DSP3_CONTROL_13                  0x110F
+#define WM5100_DSP3_CONTROL_14                  0x1110
+#define WM5100_DSP3_CONTROL_15                  0x1111
+#define WM5100_DSP3_CONTROL_16                  0x1112
+#define WM5100_DSP3_CONTROL_17                  0x1113
+#define WM5100_DSP3_CONTROL_18                  0x1114
+#define WM5100_DSP3_CONTROL_19                  0x1116
+#define WM5100_DSP3_CONTROL_20                  0x1117
+#define WM5100_DSP3_CONTROL_21                  0x1118
+#define WM5100_DSP3_CONTROL_22                  0x111A
+#define WM5100_DSP3_CONTROL_23                  0x111B
+#define WM5100_DSP3_CONTROL_24                  0x111C
+#define WM5100_DSP3_CONTROL_25                  0x111E
+#define WM5100_DSP3_CONTROL_26                  0x1120
+#define WM5100_DSP3_CONTROL_27                  0x1121
+#define WM5100_DSP3_CONTROL_28                  0x1122
+#define WM5100_DSP3_CONTROL_29                  0x1123
+#define WM5100_DSP3_CONTROL_30                  0x1124
 #define WM5100_DSP1_DM_0                        0x4000
 #define WM5100_DSP1_DM_1                        0x4001
 #define WM5100_DSP1_DM_2                        0x4002
@@ -4561,6 +4651,75 @@
 #define WM5100_LHPF4_COEFF_WIDTH                    16  /* LHPF4_COEFF - [15:0] */
 
 /*
+ * R4132 (0x1024) - DSP2 Control 30
+ */
+#define WM5100_DSP2_RATE_MASK                   0xC000  /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_RATE_SHIFT                      14  /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_RATE_WIDTH                       2  /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_DBG_CLK_ENA                 0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_MASK            0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_SHIFT                3  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_WIDTH                1  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_SYS_ENA                     0x0004  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_MASK                0x0004  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_SHIFT                    2  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_WIDTH                    1  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_CORE_ENA                    0x0002  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_MASK               0x0002  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_SHIFT                   1  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_WIDTH                   1  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_START                       0x0001  /* DSP2_START */
+#define WM5100_DSP2_START_MASK                  0x0001  /* DSP2_START */
+#define WM5100_DSP2_START_SHIFT                      0  /* DSP2_START */
+#define WM5100_DSP2_START_WIDTH                      1  /* DSP2_START */
+
+/*
+ * R3876 (0xF24) - DSP1 Control 30
+ */
+#define WM5100_DSP1_RATE_MASK                   0xC000  /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_RATE_SHIFT                      14  /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_RATE_WIDTH                       2  /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_START                       0x0001  /* DSP1_START */
+#define WM5100_DSP1_START_MASK                  0x0001  /* DSP1_START */
+#define WM5100_DSP1_START_SHIFT                      0  /* DSP1_START */
+#define WM5100_DSP1_START_WIDTH                      1  /* DSP1_START */
+
+/*
+ * R4388 (0x1124) - DSP3 Control 30
+ */
+#define WM5100_DSP3_RATE_MASK                   0xC000  /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_RATE_SHIFT                      14  /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_RATE_WIDTH                       2  /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_DBG_CLK_ENA                 0x0008  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_MASK            0x0008  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_SHIFT                3  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_WIDTH                1  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_SYS_ENA                     0x0004  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_MASK                0x0004  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_SHIFT                    2  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_WIDTH                    1  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_CORE_ENA                    0x0002  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_MASK               0x0002  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_SHIFT                   1  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_WIDTH                   1  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_START                       0x0001  /* DSP3_START */
+#define WM5100_DSP3_START_MASK                  0x0001  /* DSP3_START */
+#define WM5100_DSP3_START_SHIFT                      0  /* DSP3_START */
+#define WM5100_DSP3_START_WIDTH                      1  /* DSP3_START */
+
+/*
  * R16384 (0x4000) - DSP1 DM 0
  */
 #define WM5100_DSP1_DM_START_1_MASK             0x00FF  /* DSP1_DM_START - [7:0] */
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index aa12c6b..555ee14 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -71,13 +71,6 @@
 	int fll_freq_in;
 };
 
-static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec,
-					    unsigned int reg)
-{
-	struct wm8350 *wm8350 = codec->control_data;
-	return wm8350->reg_cache[reg];
-}
-
 static unsigned int wm8350_codec_read(struct snd_soc_codec *codec,
 				      unsigned int reg)
 {
@@ -99,7 +92,7 @@
 {
 	struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
 	struct wm8350_output *out1 = &wm8350_data->out1;
-	struct wm8350 *wm8350 = codec->control_data;
+	struct wm8350 *wm8350 = wm8350_data->wm8350;
 	int left_complete = 0, right_complete = 0;
 	u16 reg, val;
 
@@ -165,7 +158,7 @@
 {
 	struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
 	struct wm8350_output *out2 = &wm8350_data->out2;
-	struct wm8350 *wm8350 = codec->control_data;
+	struct wm8350 *wm8350 = wm8350_data->wm8350;
 	int left_complete = 0, right_complete = 0;
 	u16 reg, val;
 
@@ -360,8 +353,8 @@
 		return ret;
 
 	/* now hit the volume update bits (always bit 8) */
-	val = wm8350_codec_read(codec, reg);
-	wm8350_codec_write(codec, reg, val | WM8350_OUT1_VU);
+	val = snd_soc_read(codec, reg);
+	snd_soc_write(codec, reg, val | WM8350_OUT1_VU);
 	return 1;
 }
 
@@ -781,7 +774,8 @@
 				 int clk_id, unsigned int freq, int dir)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8350 *wm8350 = codec->control_data;
+	struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+	struct wm8350 *wm8350 = wm8350_data->wm8350;
 	u16 fll_4;
 
 	switch (clk_id) {
@@ -795,9 +789,9 @@
 	case WM8350_MCLK_SEL_PLL_32K:
 		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1,
 				WM8350_MCLK_SEL);
-		fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) &
+		fll_4 = snd_soc_read(codec, WM8350_FLL_CONTROL_4) &
 		    ~WM8350_FLL_CLK_SRC_MASK;
-		wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
+		snd_soc_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
 		break;
 	}
 
@@ -819,39 +813,39 @@
 
 	switch (div_id) {
 	case WM8350_ADC_CLKDIV:
-		val = wm8350_codec_read(codec, WM8350_ADC_DIVIDER) &
+		val = snd_soc_read(codec, WM8350_ADC_DIVIDER) &
 		    ~WM8350_ADC_CLKDIV_MASK;
-		wm8350_codec_write(codec, WM8350_ADC_DIVIDER, val | div);
+		snd_soc_write(codec, WM8350_ADC_DIVIDER, val | div);
 		break;
 	case WM8350_DAC_CLKDIV:
-		val = wm8350_codec_read(codec, WM8350_DAC_CLOCK_CONTROL) &
+		val = snd_soc_read(codec, WM8350_DAC_CLOCK_CONTROL) &
 		    ~WM8350_DAC_CLKDIV_MASK;
-		wm8350_codec_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div);
+		snd_soc_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div);
 		break;
 	case WM8350_BCLK_CLKDIV:
-		val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+		val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
 		    ~WM8350_BCLK_DIV_MASK;
-		wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+		snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
 		break;
 	case WM8350_OPCLK_CLKDIV:
-		val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+		val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
 		    ~WM8350_OPCLK_DIV_MASK;
-		wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+		snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
 		break;
 	case WM8350_SYS_CLKDIV:
-		val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+		val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
 		    ~WM8350_MCLK_DIV_MASK;
-		wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+		snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
 		break;
 	case WM8350_DACLR_CLKDIV:
-		val = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) &
+		val = snd_soc_read(codec, WM8350_DAC_LR_RATE) &
 		    ~WM8350_DACLRC_RATE_MASK;
-		wm8350_codec_write(codec, WM8350_DAC_LR_RATE, val | div);
+		snd_soc_write(codec, WM8350_DAC_LR_RATE, val | div);
 		break;
 	case WM8350_ADCLR_CLKDIV:
-		val = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) &
+		val = snd_soc_read(codec, WM8350_ADC_LR_RATE) &
 		    ~WM8350_ADCLRC_RATE_MASK;
-		wm8350_codec_write(codec, WM8350_ADC_LR_RATE, val | div);
+		snd_soc_write(codec, WM8350_ADC_LR_RATE, val | div);
 		break;
 	default:
 		return -EINVAL;
@@ -863,13 +857,13 @@
 static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
+	u16 iface = snd_soc_read(codec, WM8350_AI_FORMATING) &
 	    ~(WM8350_AIF_BCLK_INV | WM8350_AIF_LRCLK_INV | WM8350_AIF_FMT_MASK);
-	u16 master = wm8350_codec_read(codec, WM8350_AI_DAC_CONTROL) &
+	u16 master = snd_soc_read(codec, WM8350_AI_DAC_CONTROL) &
 	    ~WM8350_BCLK_MSTR;
-	u16 dac_lrc = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) &
+	u16 dac_lrc = snd_soc_read(codec, WM8350_DAC_LR_RATE) &
 	    ~WM8350_DACLRC_ENA;
-	u16 adc_lrc = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) &
+	u16 adc_lrc = snd_soc_read(codec, WM8350_ADC_LR_RATE) &
 	    ~WM8350_ADCLRC_ENA;
 
 	/* set master/slave audio interface */
@@ -922,42 +916,10 @@
 		return -EINVAL;
 	}
 
-	wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
-	wm8350_codec_write(codec, WM8350_AI_DAC_CONTROL, master);
-	wm8350_codec_write(codec, WM8350_DAC_LR_RATE, dac_lrc);
-	wm8350_codec_write(codec, WM8350_ADC_LR_RATE, adc_lrc);
-	return 0;
-}
-
-static int wm8350_pcm_trigger(struct snd_pcm_substream *substream,
-			      int cmd, struct snd_soc_dai *codec_dai)
-{
-	struct snd_soc_codec *codec = codec_dai->codec;
-	int master = wm8350_codec_cache_read(codec, WM8350_AI_DAC_CONTROL) &
-	    WM8350_BCLK_MSTR;
-	int enabled = 0;
-
-	/* Check that the DACs or ADCs are enabled since they are
-	 * required for LRC in master mode. The DACs or ADCs need a
-	 * valid audio path i.e. pin -> ADC or DAC -> pin before
-	 * the LRC will be enabled in master mode. */
-	if (!master || cmd != SNDRV_PCM_TRIGGER_START)
-		return 0;
-
-	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) &
-		    (WM8350_ADCR_ENA | WM8350_ADCL_ENA);
-	} else {
-		enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) &
-		    (WM8350_DACR_ENA | WM8350_DACL_ENA);
-	}
-
-	if (!enabled) {
-		dev_err(codec->dev,
-		       "%s: invalid audio path - no clocks available\n",
-		       __func__);
-		return -EINVAL;
-	}
+	snd_soc_write(codec, WM8350_AI_FORMATING, iface);
+	snd_soc_write(codec, WM8350_AI_DAC_CONTROL, master);
+	snd_soc_write(codec, WM8350_DAC_LR_RATE, dac_lrc);
+	snd_soc_write(codec, WM8350_ADC_LR_RATE, adc_lrc);
 	return 0;
 }
 
@@ -966,8 +928,9 @@
 				struct snd_soc_dai *codec_dai)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8350 *wm8350 = codec->control_data;
-	u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
+	struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+	struct wm8350 *wm8350 = wm8350_data->wm8350;
+	u16 iface = snd_soc_read(codec, WM8350_AI_FORMATING) &
 	    ~WM8350_AIF_WL_MASK;
 
 	/* bit size */
@@ -985,7 +948,7 @@
 		break;
 	}
 
-	wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
+	snd_soc_write(codec, WM8350_AI_FORMATING, iface);
 
 	/* The sloping stopband filter is recommended for use with
 	 * lower sample rates to improve performance.
@@ -1005,12 +968,15 @@
 static int wm8350_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	struct wm8350 *wm8350 = codec->control_data;
+	unsigned int val;
 
 	if (mute)
-		wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+		val = WM8350_DAC_MUTE_ENA;
 	else
-		wm8350_clear_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+		val = 0;
+
+	snd_soc_update_bits(codec, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA, val);
+
 	return 0;
 }
 
@@ -1079,8 +1045,8 @@
 			  unsigned int freq_out)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8350 *wm8350 = codec->control_data;
 	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm8350 *wm8350 = priv->wm8350;
 	struct _fll_div fll_div;
 	int ret = 0;
 	u16 fll_1, fll_4;
@@ -1104,17 +1070,17 @@
 		fll_div.ratio);
 
 	/* set up N.K & dividers */
-	fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) &
+	fll_1 = snd_soc_read(codec, WM8350_FLL_CONTROL_1) &
 	    ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000);
-	wm8350_codec_write(codec, WM8350_FLL_CONTROL_1,
+	snd_soc_write(codec, WM8350_FLL_CONTROL_1,
 			   fll_1 | (fll_div.div << 8) | 0x50);
-	wm8350_codec_write(codec, WM8350_FLL_CONTROL_2,
+	snd_soc_write(codec, WM8350_FLL_CONTROL_2,
 			   (fll_div.ratio << 11) | (fll_div.
 						    n & WM8350_FLL_N_MASK));
-	wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
-	fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) &
+	snd_soc_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
+	fll_4 = snd_soc_read(codec, WM8350_FLL_CONTROL_4) &
 	    ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF);
-	wm8350_codec_write(codec, WM8350_FLL_CONTROL_4,
+	snd_soc_write(codec, WM8350_FLL_CONTROL_4,
 			   fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) |
 			   (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0));
 
@@ -1131,8 +1097,8 @@
 static int wm8350_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8350 *wm8350 = codec->control_data;
 	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm8350 *wm8350 = priv->wm8350;
 	struct wm8350_audio_platform_data *platform =
 		wm8350->codec.platform_data;
 	u16 pm1;
@@ -1339,35 +1305,36 @@
 	wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL);
 }
 
-static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
+static irqreturn_t wm8350_hpl_jack_handler(int irq, void *data)
 {
 	struct wm8350_data *priv = data;
 	struct wm8350 *wm8350 = priv->wm8350;
-	struct wm8350_jack_data *jack = NULL;
 
-	switch (irq - wm8350->irq_base) {
-	case WM8350_IRQ_CODEC_JCK_DET_L:
 #ifndef CONFIG_SND_SOC_WM8350_MODULE
-		trace_snd_soc_jack_irq("WM8350 HPL");
+	trace_snd_soc_jack_irq("WM8350 HPL");
 #endif
-		jack = &priv->hpl;
-		break;
-
-	case WM8350_IRQ_CODEC_JCK_DET_R:
-#ifndef CONFIG_SND_SOC_WM8350_MODULE
-		trace_snd_soc_jack_irq("WM8350 HPR");
-#endif
-		jack = &priv->hpr;
-		break;
-
-	default:
-		BUG();
-	}
 
 	if (device_may_wakeup(wm8350->dev))
 		pm_wakeup_event(wm8350->dev, 250);
 
-	schedule_delayed_work(&jack->work, 200);
+	schedule_delayed_work(&priv->hpl.work, 200);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wm8350_hpr_jack_handler(int irq, void *data)
+{
+	struct wm8350_data *priv = data;
+	struct wm8350 *wm8350 = priv->wm8350;
+
+#ifndef CONFIG_SND_SOC_WM8350_MODULE
+	trace_snd_soc_jack_irq("WM8350 HPR");
+#endif
+
+	if (device_may_wakeup(wm8350->dev))
+		pm_wakeup_event(wm8350->dev, 250);
+
+	schedule_delayed_work(&priv->hpr.work, 200);
 
 	return IRQ_HANDLED;
 }
@@ -1387,7 +1354,7 @@
 			  struct snd_soc_jack *jack, int report)
 {
 	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
-	struct wm8350 *wm8350 = codec->control_data;
+	struct wm8350 *wm8350 = priv->wm8350;
 	int irq;
 	int ena;
 
@@ -1418,7 +1385,14 @@
 	}
 
 	/* Sync status */
-	wm8350_hp_jack_handler(irq + wm8350->irq_base, priv);
+	switch (which) {
+	case WM8350_JDL:
+		wm8350_hpl_jack_handler(0, priv);
+		break;
+	case WM8350_JDR:
+		wm8350_hpr_jack_handler(0, priv);
+		break;
+	}
 
 	return 0;
 }
@@ -1463,7 +1437,7 @@
 			   int detect_report, int short_report)
 {
 	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
-	struct wm8350 *wm8350 = codec->control_data;
+	struct wm8350 *wm8350 = priv->wm8350;
 
 	priv->mic.jack = jack;
 	priv->mic.report = detect_report;
@@ -1491,7 +1465,6 @@
 static const 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,
@@ -1559,9 +1532,9 @@
 	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
 	/* Enable robust clocking mode in ADC */
-	wm8350_codec_write(codec, WM8350_SECURITY, 0xa7);
-	wm8350_codec_write(codec, 0xde, 0x13);
-	wm8350_codec_write(codec, WM8350_SECURITY, 0);
+	snd_soc_write(codec, WM8350_SECURITY, 0xa7);
+	snd_soc_write(codec, 0xde, 0x13);
+	snd_soc_write(codec, WM8350_SECURITY, 0);
 
 	/* read OUT1 & OUT2 volumes */
 	out1 = &priv->out1;
@@ -1601,10 +1574,10 @@
 			  WM8350_JDL_ENA | WM8350_JDR_ENA);
 
 	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
-			    wm8350_hp_jack_handler, 0, "Left jack detect",
+			    wm8350_hpl_jack_handler, 0, "Left jack detect",
 			    priv);
 	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
-			    wm8350_hp_jack_handler, 0, "Right jack detect",
+			    wm8350_hpr_jack_handler, 0, "Right jack detect",
 			    priv);
 	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD,
 			    wm8350_mic_handler, 0, "Microphone short", priv);
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 898979d..5dc31eb 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -138,8 +138,8 @@
                 return ret;
 
         /* now hit the volume update bits (always bit 8) */
-        val = wm8400_read(codec, reg);
-        return wm8400_write(codec, reg, val | 0x0100);
+        val = snd_soc_read(codec, reg);
+        return snd_soc_write(codec, reg, val | 0x0100);
 }
 
 #define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
@@ -362,8 +362,8 @@
 {
 	u16 reg, fakepower;
 
-	reg = wm8400_read(w->codec, WM8400_POWER_MANAGEMENT_2);
-	fakepower = wm8400_read(w->codec, WM8400_INTDRIVBITS);
+	reg = snd_soc_read(w->codec, WM8400_POWER_MANAGEMENT_2);
+	fakepower = snd_soc_read(w->codec, WM8400_INTDRIVBITS);
 
 	if (fakepower & ((1 << WM8400_INMIXL_PWR) |
 		(1 << WM8400_AINLMUX_PWR))) {
@@ -378,7 +378,7 @@
 	} else {
 		reg &= ~WM8400_AINR_ENA;
 	}
-	wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
+	snd_soc_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
 
 	return 0;
 }
@@ -394,7 +394,7 @@
 
 	switch (reg_shift) {
 	case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
-		reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER1);
+		reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER1);
 		if (reg & WM8400_LDLO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 1 LDLO Set\n");
@@ -402,7 +402,7 @@
 		}
 		break;
 	case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
-		reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER2);
+		reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER2);
 		if (reg & WM8400_RDRO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 2 RDRO Set\n");
@@ -410,7 +410,7 @@
 		}
 		break;
 	case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
-		reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+		reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
 		if (reg & WM8400_LDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer LDSPK Set\n");
@@ -418,7 +418,7 @@
 		}
 		break;
 	case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
-		reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+		reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
 		if (reg & WM8400_RDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer RDSPK Set\n");
@@ -1021,13 +1021,13 @@
 	wm8400->fll_in = freq_in;
 
 	/* We *must* disable the FLL before any changes */
-	reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_2);
+	reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_2);
 	reg &= ~WM8400_FLL_ENA;
-	wm8400_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
+	snd_soc_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
 
-	reg = wm8400_read(codec, WM8400_FLL_CONTROL_1);
+	reg = snd_soc_read(codec, WM8400_FLL_CONTROL_1);
 	reg &= ~WM8400_FLL_OSC_ENA;
-	wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
 
 	if (!freq_out)
 		return 0;
@@ -1035,15 +1035,15 @@
 	reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
 	reg |= WM8400_FLL_FRAC | factors.fratio;
 	reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT;
-	wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
 
-	wm8400_write(codec, WM8400_FLL_CONTROL_2, factors.k);
-	wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_2, factors.k);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_3, factors.n);
 
-	reg = wm8400_read(codec, WM8400_FLL_CONTROL_4);
+	reg = snd_soc_read(codec, WM8400_FLL_CONTROL_4);
 	reg &= ~WM8400_FLL_OUTDIV_MASK;
 	reg |= factors.outdiv;
-	wm8400_write(codec, WM8400_FLL_CONTROL_4, reg);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_4, reg);
 
 	return 0;
 }
@@ -1057,8 +1057,8 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	u16 audio1, audio3;
 
-	audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
-	audio3 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_3);
+	audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
+	audio3 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_3);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1099,8 +1099,8 @@
 		return -EINVAL;
 	}
 
-	wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
-	wm8400_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
+	snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+	snd_soc_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
 	return 0;
 }
 
@@ -1112,24 +1112,24 @@
 
 	switch (div_id) {
 	case WM8400_MCLK_DIV:
-		reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+		reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
 			~WM8400_MCLK_DIV_MASK;
-		wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+		snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
 		break;
 	case WM8400_DACCLK_DIV:
-		reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+		reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
 			~WM8400_DAC_CLKDIV_MASK;
-		wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+		snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
 		break;
 	case WM8400_ADCCLK_DIV:
-		reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+		reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
 			~WM8400_ADC_CLKDIV_MASK;
-		wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+		snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
 		break;
 	case WM8400_BCLK_DIV:
-		reg = wm8400_read(codec, WM8400_CLOCKING_1) &
+		reg = snd_soc_read(codec, WM8400_CLOCKING_1) &
 			~WM8400_BCLK_DIV_MASK;
-		wm8400_write(codec, WM8400_CLOCKING_1, reg | div);
+		snd_soc_write(codec, WM8400_CLOCKING_1, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -1145,9 +1145,8 @@
 	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;
-	u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
+	struct snd_soc_codec *codec = dai->codec;
+	u16 audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
 
 	audio1 &= ~WM8400_AIF_WL_MASK;
 	/* bit size */
@@ -1165,19 +1164,19 @@
 		break;
 	}
 
-	wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+	snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
 	return 0;
 }
 
 static int wm8400_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 val = wm8400_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
+	u16 val = snd_soc_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
 
 	if (mute)
-		wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+		snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
 	else
-		wm8400_write(codec, WM8400_DAC_CTRL, val);
+		snd_soc_write(codec, WM8400_DAC_CTRL, val);
 
 	return 0;
 }
@@ -1196,9 +1195,9 @@
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID=2*50k */
-		val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+		val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
 			~WM8400_VMID_MODE_MASK;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
@@ -1212,74 +1211,74 @@
 				return ret;
 			}
 
-			wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+			snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
 				     WM8400_CODEC_ENA | WM8400_SYSCLK_ENA);
 
 			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
-			wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+			snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
 				     WM8400_BUFDCOPEN | WM8400_POBCTRL);
 
 			msleep(50);
 
 			/* Enable VREF & VMID at 2x50k */
-			val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+			val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
 			val |= 0x2 | WM8400_VREF_ENA;
-			wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+			snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
 			/* Enable BUFIOEN */
-			wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+			snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
 				     WM8400_BUFDCOPEN | WM8400_POBCTRL |
 				     WM8400_BUFIOEN);
 
 			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-			wm8400_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
+			snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
 		}
 
 		/* VMID=2*300k */
-		val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+		val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
 			~WM8400_VMID_MODE_MASK;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Enable POBCTRL and SOFT_ST */
-		wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+		snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
 			WM8400_POBCTRL | WM8400_BUFIOEN);
 
 		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
-		wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+		snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
 			WM8400_BUFDCOPEN | WM8400_POBCTRL |
 			WM8400_BUFIOEN);
 
 		/* mute DAC */
-		val = wm8400_read(codec, WM8400_DAC_CTRL);
-		wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+		val = snd_soc_read(codec, WM8400_DAC_CTRL);
+		snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
 
 		/* Enable any disabled outputs */
-		val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+		val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
 		val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
 			WM8400_OUT4_ENA | WM8400_LOUT_ENA |
 			WM8400_ROUT_ENA;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
 		/* Disable VMID */
 		val &= ~WM8400_VMID_MODE_MASK;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
 		msleep(300);
 
 		/* Enable all output discharge bits */
-		wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
+		snd_soc_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
 			WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
 			WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
 			WM8400_DIS_ROUT);
 
 		/* Disable VREF */
 		val &= ~WM8400_VREF_ENA;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
 		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-		wm8400_write(codec, WM8400_ANTIPOP2, 0x0);
+		snd_soc_write(codec, WM8400_ANTIPOP2, 0x0);
 
 		ret = regulator_bulk_disable(ARRAY_SIZE(power),
 					     &power[0]);
@@ -1385,19 +1384,19 @@
 
 	wm8400_codec_reset(codec);
 
-	reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
-	wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
+	reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+	snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
 
 	/* Latch volume update bits */
-	reg = wm8400_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
-	wm8400_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+	reg = snd_soc_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
+	snd_soc_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
 		     reg & WM8400_IPVU);
-	reg = wm8400_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
-	wm8400_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+	reg = snd_soc_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
+	snd_soc_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
 		     reg & WM8400_IPVU);
 
-	wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
-	wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
 	if (!schedule_work(&priv->work)) {
 		ret = -EINVAL;
@@ -1414,8 +1413,8 @@
 {
 	u16 reg;
 
-	reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
-	wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+	reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+	snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
 		     reg & (~WM8400_CODEC_ENA));
 
 	regulator_bulk_free(ARRAY_SIZE(power), power);
@@ -1428,7 +1427,7 @@
 	.remove =	wm8400_codec_remove,
 	.suspend =	wm8400_suspend,
 	.resume =	wm8400_resume,
-	.read = wm8400_read,
+	.read = snd_soc_read,
 	.write = wm8400_write,
 	.set_bias_level = wm8400_set_bias_level,
 
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 9166126..56a0495 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -392,8 +392,7 @@
 				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 snd_soc_codec *codec = dai->codec;
 	u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
 	u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
 
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 7fea2c3..1c3ffb2 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -145,8 +145,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
 	int i;
 	u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index fc3d59e..1467f97 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -88,8 +88,7 @@
 	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 snd_soc_codec *codec = dai->codec;
 	u16 dac = snd_soc_read(codec, WM8728_DACCTL);
 
 	dac &= ~0x18;
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index a32caa7..9d1b9b02 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -635,16 +635,17 @@
 	struct wm8731_priv *wm8731;
 	int ret;
 
-	wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+	wm8731 = devm_kzalloc(&spi->dev, sizeof(struct wm8731_priv),
+			      GFP_KERNEL);
 	if (wm8731 == NULL)
 		return -ENOMEM;
 
-	wm8731->regmap = regmap_init_spi(spi, &wm8731_regmap);
+	wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap);
 	if (IS_ERR(wm8731->regmap)) {
 		ret = PTR_ERR(wm8731->regmap);
 		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
 			ret);
-		goto err;
+		return ret;
 	}
 
 	spi_set_drvdata(spi, wm8731);
@@ -653,25 +654,15 @@
 			&soc_codec_dev_wm8731, &wm8731_dai, 1);
 	if (ret != 0) {
 		dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
-		goto err_regmap;
+		return ret;
 	}
 
 	return 0;
-
-err_regmap:
-	regmap_exit(wm8731->regmap);
-err:
-	kfree(wm8731);
-	return ret;
 }
 
 static int __devexit wm8731_spi_remove(struct spi_device *spi)
 {
-	struct wm8731_priv *wm8731 = spi_get_drvdata(spi);
-
 	snd_soc_unregister_codec(&spi->dev);
-	regmap_exit(wm8731->regmap);
-	kfree(wm8731);
 	return 0;
 }
 
@@ -693,16 +684,17 @@
 	struct wm8731_priv *wm8731;
 	int ret;
 
-	wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+	wm8731 = devm_kzalloc(&i2c->dev, sizeof(struct wm8731_priv),
+			      GFP_KERNEL);
 	if (wm8731 == NULL)
 		return -ENOMEM;
 
-	wm8731->regmap = regmap_init_i2c(i2c, &wm8731_regmap);
+	wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
 	if (IS_ERR(wm8731->regmap)) {
 		ret = PTR_ERR(wm8731->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
 			ret);
-		goto err;
+		return ret;
 	}
 
 	i2c_set_clientdata(i2c, wm8731);
@@ -711,24 +703,15 @@
 			&soc_codec_dev_wm8731, &wm8731_dai, 1);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
-		goto err_regmap;
+		return ret;
 	}
 
 	return 0;
-
-err_regmap:
-	regmap_exit(wm8731->regmap);
-err:
-	kfree(wm8731);
-	return ret;
 }
 
 static __devexit int wm8731_i2c_remove(struct i2c_client *client)
 {
-	struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
 	snd_soc_unregister_codec(&client->dev);
-	regmap_exit(wm8731->regmap);
-	kfree(wm8731);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 4fe9d19..d052012 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -329,8 +329,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
 	int i;
 	u16 clocking = 0;
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 3941f50..6e849cb 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -203,8 +203,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
 	u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
 	int i;
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index e4c50ce..89151ca 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -547,8 +547,7 @@
 				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 snd_soc_codec *codec = dai->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;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index e27e7b6..a26482c 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -931,8 +931,7 @@
 				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 snd_soc_codec *codec = dai->codec;
 	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 	u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01f3;
 	u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x017f;
@@ -1161,8 +1160,7 @@
 				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 snd_soc_codec *codec = dai->codec;
 	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 	u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x01c0;
 	u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01f3;
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index f18c554..077c962 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -610,8 +610,7 @@
 	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 snd_soc_codec *codec = dai->codec;
 	u16 reg;
 
 	reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index c91fb2f..86b8a29 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1432,8 +1432,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 	int fs = params_rate(params);
 	int bclk;
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index d2883af..481a3d9 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -371,8 +371,7 @@
 				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 snd_soc_codec *codec = dai->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,
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 840d720..8bc659d 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -505,8 +505,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 	u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
 	int i;
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 15d467f..0cfce99 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -1478,7 +1478,8 @@
 
 static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
 {
-	return 0;
+	return regcache_sync_region(codec->control_data,
+				    WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);
 }
 
 static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val)
@@ -1755,10 +1756,22 @@
 SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,
 		 WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv),
 
+SOC_SINGLE("3D Switch", WM8962_THREED1, 0, 1, 0),
+SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA),
+
+SOC_SINGLE("DF1 Switch", WM8962_DF1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DF1 Coefficients", WM8962_DF1, 7, WM8962_DF1_ENA),
+
+SOC_SINGLE("DRC Switch", WM8962_DRC_1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DRC Coefficients", WM8962_DRC_1, 5, WM8962_DRC_ENA),
+
 WM8962_DSP2_ENABLE("VSS Switch", WM8962_VSS_ENA_SHIFT),
+SND_SOC_BYTES("VSS Coefficients", WM8962_VSS_XHD2_1, 148),
 WM8962_DSP2_ENABLE("HPF1 Switch", WM8962_HPF1_ENA_SHIFT),
 WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT),
+SND_SOC_BYTES("HPF Coefficients", WM8962_LHPF2, 1),
 WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT),
+SND_SOC_BYTES("HD Bass Coefficients", WM8962_HDBASS_AI_1, 30),
 };
 
 static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
@@ -2519,8 +2532,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 	int i;
 	int aif0 = 0;
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 28fe59e..eef783f 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -478,8 +478,7 @@
 	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 snd_soc_codec *codec = dai->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;
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 72d5fdc..a5be3ad 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -723,8 +723,7 @@
 			    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 snd_soc_codec *codec = dai->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;
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 6cdf6a2..1d4c5cf 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -668,8 +668,7 @@
 				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 snd_soc_codec *codec = dai->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;
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 9d24235..db63c97 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1112,8 +1112,7 @@
 			    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 snd_soc_codec *codec = dai->codec;
 	u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
 
 	audio1 &= ~WM8990_AIF_WL_MASK;
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index d256a93..36acfcc 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -218,7 +218,6 @@
 	unsigned int sysclk_rate;
 	unsigned int fs;
 	unsigned int bclk;
-	int class_w_users;
 	unsigned int fll_fref;
 	unsigned int fll_fout;
 	int fll_src;
@@ -824,84 +823,6 @@
 	return 0;
 }
 
-/*
- * When used with DAC outputs only the WM8993 charge pump supports
- * operation in class W mode, providing very low power consumption
- * when used with digital sources.  Enable and disable this mode
- * automatically depending on the mixer configuration.
- *
- * Currently the only supported paths are the direct DAC->headphone
- * paths (which provide minimum power consumption anyway).
- */
-static int class_w_put(struct snd_kcontrol *kcontrol,
-		       struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = widget->codec;
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
-	int ret;
-
-	/* Turn it off if we're using the main output mixer */
-	if (ucontrol->value.integer.value[0] == 0) {
-		if (wm8993->class_w_users == 0) {
-			dev_dbg(codec->dev, "Disabling Class W\n");
-			snd_soc_update_bits(codec, WM8993_CLASS_W_0,
-					    WM8993_CP_DYN_FREQ |
-					    WM8993_CP_DYN_V,
-					    0);
-		}
-		wm8993->class_w_users++;
-		wm8993->hubs_data.class_w = true;
-	}
-
-	/* Implement the change */
-	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
-	/* Enable it if we're using the direct DAC path */
-	if (ucontrol->value.integer.value[0] == 1) {
-		if (wm8993->class_w_users == 1) {
-			dev_dbg(codec->dev, "Enabling Class W\n");
-			snd_soc_update_bits(codec, WM8993_CLASS_W_0,
-					    WM8993_CP_DYN_FREQ |
-					    WM8993_CP_DYN_V,
-					    WM8993_CP_DYN_FREQ |
-					    WM8993_CP_DYN_V);
-		}
-		wm8993->class_w_users--;
-		wm8993->hubs_data.class_w = false;
-	}
-
-	dev_dbg(codec->dev, "Indirect DAC use count now %d\n",
-		wm8993->class_w_users);
-
-	return ret;
-}
-
-#define SOC_DAPM_ENUM_W(xname, xenum) \
-{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-	.info = snd_soc_info_enum_double, \
-	.get = snd_soc_dapm_get_enum_double, \
-	.put = class_w_put, \
-	.private_value = (unsigned long)&xenum }
-
-static const char *hp_mux_text[] = {
-	"Mixer",
-	"DAC",
-};
-
-static const struct soc_enum hpl_enum =
-	SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpl_mux =
-	SOC_DAPM_ENUM_W("Left Headphone Mux", hpl_enum);
-
-static const struct soc_enum hpr_enum =
-	SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpr_mux =
-	SOC_DAPM_ENUM_W("Right Headphone Mux", hpr_enum);
-
 static const struct snd_kcontrol_new left_speaker_mixer[] = {
 SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0),
 SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0),
@@ -988,8 +909,8 @@
 SND_SOC_DAPM_DAC("DACL", NULL, WM8993_POWER_MANAGEMENT_3, 1, 0),
 SND_SOC_DAPM_DAC("DACR", NULL, WM8993_POWER_MANAGEMENT_3, 0, 0),
 
-SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
-SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
 
 SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0,
 		   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
@@ -1579,9 +1500,6 @@
 		return ret;
 	}
 
-	/* By default we're using the output mixers */
-	wm8993->class_w_users = 2;
-
 	/* Latch volume update bits and default ZC on */
 	snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
 			    WM8993_DAC_VU, WM8993_DAC_VU);
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 2de12eb..993639d 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -70,8 +70,8 @@
 static const struct wm8958_micd_rate jackdet_rates[] = {
 	{ 32768,       true,  0, 1 },
 	{ 32768,       false, 0, 1 },
-	{ 44100 * 256, true,  7, 10 },
-	{ 44100 * 256, false, 7, 10 },
+	{ 44100 * 256, true,  10, 10 },
+	{ 44100 * 256, false, 7, 8 },
 };
 
 static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
@@ -82,7 +82,8 @@
 	const struct wm8958_micd_rate *rates;
 	int num_rates;
 
-	if (wm8994->jack_cb != wm8958_default_micdet)
+	if (!(wm8994->pdata && wm8994->pdata->micd_rates) &&
+	    wm8994->jack_cb != wm8958_default_micdet)
 		return;
 
 	idle = !wm8994->jack_mic;
@@ -118,6 +119,10 @@
 	val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT
 		| rates[best].rate << WM8958_MICD_RATE_SHIFT;
 
+	dev_dbg(codec->dev, "MICD rate %d,%d for %dHz %s\n",
+		rates[best].start, rates[best].rate, sysclk,
+		idle ? "idle" : "active");
+
 	snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
 			    WM8958_MICD_BIAS_STARTTIME_MASK |
 			    WM8958_MICD_RATE_MASK, val);
@@ -398,7 +403,7 @@
 		wm8994->dac_rates[iface]);
 
 	/* The EQ will be disabled while reconfiguring it, remember the
-	 * current configuration. 
+	 * current configuration.
 	 */
 	save = snd_soc_read(codec, base);
 	save &= WM8994_AIF1DAC1_EQ_ENA;
@@ -689,6 +694,9 @@
 	if (!wm8994->jackdet || !wm8994->jack_cb)
 		return;
 
+	if (!wm8994->jackdet || !wm8994->jack_cb)
+		return;
+
 	if (wm8994->active_refcount)
 		mode = WM1811_JACKDET_MODE_AUDIO;
 
@@ -784,7 +792,7 @@
 
 		switch (wm8994->vmid_mode) {
 		default:
-			WARN_ON(0 == "Invalid VMID mode");
+			WARN_ON(NULL == "Invalid VMID mode");
 		case WM8994_VMID_NORMAL:
 			/* Startup bias, VMID ramp & buffer */
 			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
@@ -937,27 +945,12 @@
 	return 0;
 }
 
-static void wm8994_update_class_w(struct snd_soc_codec *codec)
+static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-	int enable = 1;
 	int source = 0;  /* GCC flow analysis can't track enable */
 	int reg, reg_r;
 
-	/* Only support direct DAC->headphone paths */
-	reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1);
-	if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) {
-		dev_vdbg(codec->dev, "HPL connected to output mixer\n");
-		enable = 0;
-	}
-
-	reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2);
-	if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) {
-		dev_vdbg(codec->dev, "HPR connected to output mixer\n");
-		enable = 0;
-	}
-
-	/* We also need the same setting for L/R and only one path */
+	/* We also need the same AIF source for L/R and only one path */
 	reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING);
 	switch (reg) {
 	case WM8994_AIF2DACL_TO_DAC1L:
@@ -974,30 +967,20 @@
 		break;
 	default:
 		dev_vdbg(codec->dev, "DAC mixer setting: %x\n", reg);
-		enable = 0;
-		break;
+		return false;
 	}
 
 	reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING);
 	if (reg_r != reg) {
 		dev_vdbg(codec->dev, "Left and right DAC mixers different\n");
-		enable = 0;
+		return false;
 	}
 
-	if (enable) {
-		dev_dbg(codec->dev, "Class W enabled\n");
-		snd_soc_update_bits(codec, WM8994_CLASS_W_1,
-				    WM8994_CP_DYN_PWR |
-				    WM8994_CP_DYN_SRC_SEL_MASK,
-				    source | WM8994_CP_DYN_PWR);
-		wm8994->hubs.class_w = true;
-		
-	} else {
-		dev_dbg(codec->dev, "Class W disabled\n");
-		snd_soc_update_bits(codec, WM8994_CLASS_W_1,
-				    WM8994_CP_DYN_PWR, 0);
-		wm8994->hubs.class_w = false;
-	}
+	/* Set the source up */
+	snd_soc_update_bits(codec, WM8994_CLASS_W_1,
+			    WM8994_CP_DYN_SRC_SEL_MASK, source);
+
+	return true;
 }
 
 static int aif1clk_ev(struct snd_soc_dapm_widget *w,
@@ -1280,45 +1263,6 @@
 	return 0;
 }
 
-static const char *hp_mux_text[] = {
-	"Mixer",
-	"DAC",
-};
-
-#define WM8994_HP_ENUM(xname, xenum) \
-{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-	.info = snd_soc_info_enum_double, \
- 	.get = snd_soc_dapm_get_enum_double, \
- 	.put = wm8994_put_hp_enum, \
-  	.private_value = (unsigned long)&xenum }
-
-static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *w = wlist->widgets[0];
-	struct snd_soc_codec *codec = w->codec;
-	int ret;
-
-	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
-	wm8994_update_class_w(codec);
-
-	return ret;
-}
-
-static const struct soc_enum hpl_enum =
-	SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_1, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpl_mux =
-	WM8994_HP_ENUM("Left Headphone Mux", hpl_enum);
-
-static const struct soc_enum hpr_enum =
-	SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_2, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpr_mux =
-	WM8994_HP_ENUM("Right Headphone Mux", hpr_enum);
-
 static const char *adc_mux_text[] = {
 	"ADC",
 	"DMIC",
@@ -1430,7 +1374,7 @@
 
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
 
-	wm8994_update_class_w(codec);
+	wm_hubs_update_class_w(codec);
 
 	return ret;
 }
@@ -1524,7 +1468,7 @@
 	SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);
 
 static const char *mono_pcm_out_text[] = {
-	"None", "AIF2ADCL", "AIF2ADCR", 
+	"None", "AIF2ADCL", "AIF2ADCR",
 };
 
 static const struct soc_enum mono_pcm_out_enum =
@@ -1573,9 +1517,9 @@
 SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
 		     right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer),
 		     late_enable_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux,
+SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux,
 		   late_enable_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux,
+SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux,
 		   late_enable_ev, SND_SOC_DAPM_PRE_PMU),
 
 SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
@@ -1591,8 +1535,8 @@
 		   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
 SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
 		   right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
-SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
-SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
 };
 
 static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
@@ -1732,6 +1676,7 @@
 };
 
 static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("AIF3", WM8994_POWER_MANAGEMENT_6, 5, 1, NULL, 0),
 SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux),
 SND_SOC_DAPM_MUX("AIF2DACL Mux", SND_SOC_NOPM, 0, 0, &aif2dacl_src_mux),
 SND_SOC_DAPM_MUX("AIF2DACR Mux", SND_SOC_NOPM, 0, 0, &aif2dacr_src_mux),
@@ -1972,6 +1917,9 @@
 	{ "AIF2DACR Mux", "AIF2", "AIF2DAC Mux" },
 	{ "AIF2DACR Mux", "AIF3", "AIF3DACDAT" },
 
+	{ "AIF3DACDAT", NULL, "AIF3" },
+	{ "AIF3ADCDAT", NULL, "AIF3" },
+
 	{ "Mono PCM Out Mux", "AIF2ADCL", "AIF2ADCL" },
 	{ "Mono PCM Out Mux", "AIF2ADCR", "AIF2ADCR" },
 
@@ -2068,24 +2016,20 @@
 	struct wm8994 *control = wm8994->wm8994;
 	int reg_offset, ret;
 	struct fll_div fll;
-	u16 reg, aif1, aif2;
+	u16 reg, clk1, aif_reg, aif_src;
 	unsigned long timeout;
 	bool was_enabled;
 
-	aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
-		& WM8994_AIF1CLK_ENA;
-
-	aif2 = snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
-		& WM8994_AIF2CLK_ENA;
-
 	switch (id) {
 	case WM8994_FLL1:
 		reg_offset = 0;
 		id = 0;
+		aif_src = 0x10;
 		break;
 	case WM8994_FLL2:
 		reg_offset = 0x20;
 		id = 1;
+		aif_src = 0x18;
 		break;
 	default:
 		return -EINVAL;
@@ -2127,16 +2071,33 @@
 	if (ret < 0)
 		return ret;
 
-	/* Gate the AIF clocks while we reclock */
-	snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
-			    WM8994_AIF1CLK_ENA, 0);
-	snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
-			    WM8994_AIF2CLK_ENA, 0);
+	/* Make sure that we're not providing SYSCLK right now */
+	clk1 = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (clk1 & WM8994_SYSCLK_SRC)
+		aif_reg = WM8994_AIF2_CLOCKING_1;
+	else
+		aif_reg = WM8994_AIF1_CLOCKING_1;
+	reg = snd_soc_read(codec, aif_reg);
+
+	if ((reg & WM8994_AIF1CLK_ENA) &&
+	    (reg & WM8994_AIF1CLK_SRC_MASK) == aif_src) {
+		dev_err(codec->dev, "FLL%d is currently providing SYSCLK\n",
+			id + 1);
+		return -EBUSY;
+	}
 
 	/* We always need to disable the FLL while reconfiguring */
 	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
 			    WM8994_FLL1_ENA, 0);
 
+	if (wm8994->fll_byp && src == WM8994_FLL_SRC_BCLK &&
+	    freq_in == freq_out && freq_out) {
+		dev_dbg(codec->dev, "Bypassing FLL%d\n", id + 1);
+		snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+				    WM8958_FLL1_BYP, WM8958_FLL1_BYP);
+		goto out;
+	}
+
 	reg = (fll.outdiv << WM8994_FLL1_OUTDIV_SHIFT) |
 		(fll.fll_fratio << WM8994_FLL1_FRATIO_SHIFT);
 	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_2 + reg_offset,
@@ -2151,6 +2112,7 @@
 				    fll.n << WM8994_FLL1_N_SHIFT);
 
 	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+			    WM8958_FLL1_BYP |
 			    WM8994_FLL1_REFCLK_DIV_MASK |
 			    WM8994_FLL1_REFCLK_SRC_MASK,
 			    (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
@@ -2213,16 +2175,11 @@
 		}
 	}
 
+out:
 	wm8994->fll[id].in = freq_in;
 	wm8994->fll[id].out = freq_out;
 	wm8994->fll[id].src = src;
 
-	/* Enable any gated AIF clocks */
-	snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
-			    WM8994_AIF1CLK_ENA, aif1);
-	snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
-			    WM8994_AIF2CLK_ENA, aif2);
-
 	configure_clock(codec);
 
 	return 0;
@@ -2290,7 +2247,7 @@
 
 	case WM8994_SYSCLK_OPCLK:
 		/* Special case - a division (times 10) is given and
-		 * no effect on main clocking. 
+		 * no effect on main clocking.
 		 */
 		if (freq) {
 			for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
@@ -2792,33 +2749,6 @@
 	return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
 }
 
-static void wm8994_aif_shutdown(struct snd_pcm_substream *substream,
-				struct snd_soc_dai *dai)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	int rate_reg = 0;
-
-	switch (dai->id) {
-	case 1:
-		rate_reg = WM8994_AIF1_RATE;
-		break;
-	case 2:
-		rate_reg = WM8994_AIF2_RATE;
-		break;
-	default:
-		break;
-	}
-
-	/* If the DAI is idle then configure the divider tree for the
-	 * lowest output rate to save a little power if the clock is
-	 * still active (eg, because it is system clock).
-	 */
-	if (rate_reg && !dai->playback_active && !dai->capture_active)
-		snd_soc_update_bits(codec, rate_reg,
-				    WM8994_AIF1_SR_MASK |
-				    WM8994_AIF1CLK_RATE_MASK, 0x9);
-}
-
 static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
@@ -2860,10 +2790,6 @@
 		reg = WM8994_AIF2_MASTER_SLAVE;
 		mask = WM8994_AIF2_TRI;
 		break;
-	case 3:
-		reg = WM8994_POWER_MANAGEMENT_6;
-		mask = WM8994_AIF3_TRI;
-		break;
 	default:
 		return -EINVAL;
 	}
@@ -2900,7 +2826,6 @@
 	.set_sysclk	= wm8994_set_dai_sysclk,
 	.set_fmt	= wm8994_set_dai_fmt,
 	.hw_params	= wm8994_hw_params,
-	.shutdown	= wm8994_aif_shutdown,
 	.digital_mute	= wm8994_aif_mute,
 	.set_pll	= wm8994_set_fll,
 	.set_tristate	= wm8994_set_tristate,
@@ -2910,7 +2835,6 @@
 	.set_sysclk	= wm8994_set_dai_sysclk,
 	.set_fmt	= wm8994_set_dai_fmt,
 	.hw_params	= wm8994_hw_params,
-	.shutdown	= wm8994_aif_shutdown,
 	.digital_mute   = wm8994_aif_mute,
 	.set_pll	= wm8994_set_fll,
 	.set_tristate	= wm8994_set_tristate,
@@ -2918,7 +2842,6 @@
 
 static const struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
 	.hw_params	= wm8994_aif3_hw_params,
-	.set_tristate	= wm8994_set_tristate,
 };
 
 static struct snd_soc_dai_driver wm8994_dai[] = {
@@ -3126,14 +3049,14 @@
 
 		/* Expand the array... */
 		t = krealloc(wm8994->retune_mobile_texts,
-			     sizeof(char *) * 
+			     sizeof(char *) *
 			     (wm8994->num_retune_mobile_texts + 1),
 			     GFP_KERNEL);
 		if (t == NULL)
 			continue;
 
 		/* ...store the new entry... */
-		t[wm8994->num_retune_mobile_texts] = 
+		t[wm8994->num_retune_mobile_texts] =
 			pdata->retune_mobile_cfgs[i].name;
 
 		/* ...and remember the new version. */
@@ -3304,25 +3227,25 @@
 }
 EXPORT_SYMBOL_GPL(wm8994_mic_detect);
 
-static irqreturn_t wm8994_mic_irq(int irq, void *data)
+static void wm8994_mic_work(struct work_struct *work)
 {
-	struct wm8994_priv *priv = data;
-	struct snd_soc_codec *codec = priv->codec;
-	int reg;
+	struct wm8994_priv *priv = container_of(work,
+						struct wm8994_priv,
+						mic_work.work);
+	struct regmap *regmap = priv->wm8994->regmap;
+	struct device *dev = priv->wm8994->dev;
+	unsigned int reg;
+	int ret;
 	int report;
 
-#ifndef CONFIG_SND_SOC_WM8994_MODULE
-	trace_snd_soc_jack_irq(dev_name(codec->dev));
-#endif
-
-	reg = snd_soc_read(codec, WM8994_INTERRUPT_RAW_STATUS_2);
-	if (reg < 0) {
-		dev_err(codec->dev, "Failed to read microphone status: %d\n",
-			reg);
-		return IRQ_HANDLED;
+	ret = regmap_read(regmap, WM8994_INTERRUPT_RAW_STATUS_2, &reg);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read microphone status: %d\n",
+			ret);
+		return;
 	}
 
-	dev_dbg(codec->dev, "Microphone status: %x\n", reg);
+	dev_dbg(dev, "Microphone status: %x\n", reg);
 
 	report = 0;
 	if (reg & WM8994_MIC1_DET_STS) {
@@ -3361,6 +3284,20 @@
 
 	snd_soc_jack_report(priv->micdet[1].jack, report,
 			    SND_JACK_HEADSET | SND_JACK_BTN_0);
+}
+
+static irqreturn_t wm8994_mic_irq(int irq, void *data)
+{
+	struct wm8994_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+
+#ifndef CONFIG_SND_SOC_WM8994_MODULE
+	trace_snd_soc_jack_irq(dev_name(codec->dev));
+#endif
+
+	pm_wakeup_event(codec->dev, 300);
+
+	schedule_delayed_work(&priv->mic_work, msecs_to_jiffies(250));
 
 	return IRQ_HANDLED;
 }
@@ -3415,9 +3352,6 @@
 
 		wm8958_micd_set_rate(codec);
 
-		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
-				    SND_JACK_HEADSET);
-
 		/* If we have jackdet that will detect removal */
 		if (wm8994->jackdet) {
 			mutex_lock(&wm8994->accdet_lock);
@@ -3430,14 +3364,13 @@
 
 			mutex_unlock(&wm8994->accdet_lock);
 
-			if (wm8994->pdata->jd_ext_cap) {
-				mutex_lock(&codec->mutex);
+			if (wm8994->pdata->jd_ext_cap)
 				snd_soc_dapm_disable_pin(&codec->dapm,
 							 "MICBIAS2");
-				snd_soc_dapm_sync(&codec->dapm);
-				mutex_unlock(&codec->mutex);
-			}
 		}
+
+		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
+				    SND_JACK_HEADSET);
 	}
 
 	/* Report short circuit as a button */
@@ -3489,6 +3422,8 @@
 	if (present) {
 		dev_dbg(codec->dev, "Jack detected\n");
 
+		wm8958_micd_set_rate(codec);
+
 		snd_soc_update_bits(codec, WM8958_MICBIAS2,
 				    WM8958_MICB2_DISCH, 0);
 
@@ -3526,16 +3461,11 @@
 
 	/* If required for an external cap force MICBIAS on */
 	if (wm8994->pdata->jd_ext_cap) {
-		mutex_lock(&codec->mutex);
-
 		if (present)
 			snd_soc_dapm_force_enable_pin(&codec->dapm,
 						      "MICBIAS2");
 		else
 			snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
-
-		snd_soc_dapm_sync(&codec->dapm);
-		mutex_unlock(&codec->mutex);
 	}
 
 	if (present)
@@ -3740,6 +3670,7 @@
 	wm8994->codec = codec;
 
 	mutex_init(&wm8994->accdet_lock);
+	INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
 
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
 		init_completion(&wm8994->fll_locked[i]);
@@ -3783,13 +3714,22 @@
 	case WM8958:
 		wm8994->hubs.dcs_readback_mode = 1;
 		wm8994->hubs.hp_startup_mode = 1;
+
+		switch (wm8994->revision) {
+		case 0:
+			break;
+		default:
+			wm8994->fll_byp = true;
+			break;
+		}
 		break;
 
 	case WM1811:
 		wm8994->hubs.dcs_readback_mode = 2;
 		wm8994->hubs.no_series_update = 1;
 		wm8994->hubs.hp_startup_mode = 1;
-		wm8994->hubs.no_cache_class_w = true;
+		wm8994->hubs.no_cache_dac_hp_direct = true;
+		wm8994->fll_byp = true;
 
 		switch (wm8994->revision) {
 		case 0:
@@ -4010,7 +3950,8 @@
 		break;
 	}
 
-	wm8994_update_class_w(codec);
+	wm8994->hubs.check_class_w_digital = wm8994_check_class_w_digital;
+	wm_hubs_update_class_w(codec);
 
 	wm8994_handle_pdata(wm8994);
 
@@ -4075,7 +4016,6 @@
 					  ARRAY_SIZE(wm8994_dac_widgets));
 		break;
 	}
-		
 
 	wm_hubs_add_analogue_routes(codec, 0, 0);
 	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
@@ -4140,7 +4080,7 @@
 	return ret;
 }
 
-static int  wm8994_codec_remove(struct snd_soc_codec *codec)
+static int wm8994_codec_remove(struct snd_soc_codec *codec)
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct wm8994 *control = wm8994->wm8994;
@@ -4181,14 +4121,10 @@
 			free_irq(wm8994->micdet_irq, wm8994);
 		break;
 	}
-	if (wm8994->mbc)
-		release_firmware(wm8994->mbc);
-	if (wm8994->mbc_vss)
-		release_firmware(wm8994->mbc_vss);
-	if (wm8994->enh_eq)
-		release_firmware(wm8994->enh_eq);
+	release_firmware(wm8994->mbc);
+	release_firmware(wm8994->mbc_vss);
+	release_firmware(wm8994->enh_eq);
 	kfree(wm8994->retune_mobile_texts);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index c724112..d77e06f 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -12,6 +12,7 @@
 #include <sound/soc.h>
 #include <linux/firmware.h>
 #include <linux/completion.h>
+#include <linux/workqueue.h>
 
 #include "wm_hubs.h"
 
@@ -79,6 +80,7 @@
 	struct wm8994_fll_config fll[2], fll_suspend[2];
 	struct completion fll_locked[2];
 	bool fll_locked_irq;
+	bool fll_byp;
 
 	int vmid_refcount;
 	int active_refcount;
@@ -126,6 +128,7 @@
 
 	struct mutex accdet_lock;
 	struct wm8994_micdet micdet[2];
+	struct delayed_work mic_work;
 	bool mic_detecting;
 	bool jack_mic;
 	int btn_mask;
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 1fd6354..8af422e 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -1770,7 +1770,13 @@
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
+		break;
 	case SND_SOC_BIAS_PREPARE:
+		/* Put the MICBIASes into regulating mode */
+		snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+				    WM8996_MICB1_MODE, 0);
+		snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+				    WM8996_MICB2_MODE, 0);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
@@ -1793,6 +1799,12 @@
 			regcache_cache_only(codec->control_data, false);
 			regcache_sync(codec->control_data);
 		}
+
+		/* Bypass the MICBIASes for lowest power */
+		snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+				    WM8996_MICB1_MODE, WM8996_MICB1_MODE);
+		snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+				    WM8996_MICB2_MODE, WM8996_MICB2_MODE);
 		break;
 
 	case SND_SOC_BIAS_OFF:
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 076c126..9328270 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -774,7 +774,7 @@
 SND_SOC_DAPM_INPUT("IN1"),
 SND_SOC_DAPM_INPUT("IN2"),
 
-SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM9081_POWER_MANAGEMENT, 0, 0),
+SND_SOC_DAPM_DAC("DAC", NULL, WM9081_POWER_MANAGEMENT, 0, 0),
 
 SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0,
 			     mixer, ARRAY_SIZE(mixer)),
@@ -799,6 +799,7 @@
 static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
 	{ "DAC", NULL, "CLK_SYS" },
 	{ "DAC", NULL, "CLK_DSP" },
+	{ "DAC", NULL, "AIF" },
 
 	{ "Mixer", "IN1 Switch", "IN1" },
 	{ "Mixer", "IN2 Switch", "IN2" },
@@ -1252,7 +1253,7 @@
 static struct snd_soc_dai_driver wm9081_dai = {
 	.name = "wm9081-hifi",
 	.playback = {
-		.stream_name = "HiFi Playback",
+		.stream_name = "AIF",
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = WM9081_RATES,
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index cacc6a8..e8e782a 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -236,9 +236,7 @@
 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_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	int reg;
 	u16 vra;
 
@@ -250,7 +248,7 @@
 	else
 		reg = AC97_PCM_LR_ADC_RATE;
 
-	return ac97_write(codec, reg, runtime->rate);
+	return ac97_write(codec, reg, substream->runtime->rate);
 }
 
 #define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index b342ae5..a154141 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -467,11 +467,10 @@
 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_codec *codec =rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	int reg;
 	u16 vra;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
 	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
@@ -487,10 +486,9 @@
 static int ac97_aux_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_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	u16 vra, xsle;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
 	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 6c028c4..dfe957a 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -109,12 +109,103 @@
 }
 EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
 
+static bool wm_hubs_dac_hp_direct(struct snd_soc_codec *codec)
+{
+	int reg;
+
+	/* If we're going via the mixer we'll need to do additional checks */
+	reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER1);
+	if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
+		if (reg & ~WM8993_DACL_TO_MIXOUTL) {
+			dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
+				 reg & ~WM8993_DACL_TO_HPOUT1L);
+			return false;
+		} else {
+			dev_vdbg(codec->dev, "HPL connected to mixer\n");
+		}
+	} else {
+		dev_vdbg(codec->dev, "HPL connected to DAC\n");
+	}
+
+	reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER2);
+	if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
+		if (reg & ~WM8993_DACR_TO_MIXOUTR) {
+			dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
+				 reg & ~WM8993_DACR_TO_HPOUT1R);
+			return false;
+		} else {
+			dev_vdbg(codec->dev, "HPR connected to mixer\n");
+		}
+	} else {
+		dev_vdbg(codec->dev, "HPR connected to DAC\n");
+	}
+
+	return true;
+}
+
+struct wm_hubs_dcs_cache {
+	struct list_head list;
+	unsigned int left;
+	unsigned int right;
+	u16 dcs_cfg;
+};
+
+static bool wm_hubs_dcs_cache_get(struct snd_soc_codec *codec,
+				  struct wm_hubs_dcs_cache **entry)
+{
+	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_dcs_cache *cache;
+	unsigned int left, right;
+
+	left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
+	left &= WM8993_HPOUT1L_VOL_MASK;
+
+	right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
+	right &= WM8993_HPOUT1R_VOL_MASK;
+
+	list_for_each_entry(cache, &hubs->dcs_cache, list) {
+		if (cache->left != left || cache->right != right)
+			continue;
+
+		*entry = cache;
+		return true;
+	}
+
+	return false;
+}
+
+static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
+{
+	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_dcs_cache *cache;
+
+	if (hubs->no_cache_dac_hp_direct)
+		return;
+
+	cache = devm_kzalloc(codec->dev, sizeof(*cache), GFP_KERNEL);
+	if (!cache) {
+		dev_err(codec->dev, "Failed to allocate DCS cache entry\n");
+		return;
+	}
+
+	cache->left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
+	cache->left &= WM8993_HPOUT1L_VOL_MASK;
+
+	cache->right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
+	cache->right &= WM8993_HPOUT1R_VOL_MASK;
+
+	cache->dcs_cfg = dcs_cfg;
+
+	list_add_tail(&cache->list, &hubs->dcs_cache);
+}
+
 /*
  * Startup calibration of the DC servo
  */
 static void calibrate_dc_servo(struct snd_soc_codec *codec)
 {
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_dcs_cache *cache;
 	s8 offset;
 	u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;
 
@@ -129,10 +220,11 @@
 
 	/* If we're using a digital only path and have a previously
 	 * callibrated DC servo offset stored then use that. */
-	if (hubs->class_w && hubs->class_w_dcs) {
-		dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
-			hubs->class_w_dcs);
-		snd_soc_write(codec, dcs_reg, hubs->class_w_dcs);
+	if (wm_hubs_dac_hp_direct(codec) &&
+	    wm_hubs_dcs_cache_get(codec, &cache)) {
+		dev_dbg(codec->dev, "Using cached DCS offset %x for %d,%d\n",
+			cache->dcs_cfg, cache->left, cache->right);
+		snd_soc_write(codec, dcs_reg, cache->dcs_cfg);
 		wait_for_dc_servo(codec,
 				  WM8993_DCS_TRIG_DAC_WR_0 |
 				  WM8993_DCS_TRIG_DAC_WR_1);
@@ -207,8 +299,8 @@
 
 	/* Save the callibrated offset if we're in class W mode and
 	 * therefore don't have any analogue signal mixed in. */
-	if (hubs->class_w && !hubs->no_cache_class_w)
-		hubs->class_w_dcs = dcs_cfg;
+	if (wm_hubs_dac_hp_direct(codec))
+		wm_hubs_dcs_cache_set(codec, dcs_cfg);
 }
 
 /*
@@ -223,9 +315,6 @@
 
 	ret = snd_soc_put_volsw(kcontrol, ucontrol);
 
-	/* Updating the analogue gains invalidates the DC servo cache */
-	hubs->class_w_dcs = 0;
-
 	/* If we're applying an offset correction then updating the
 	 * callibration would be likely to introduce further offsets. */
 	if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
@@ -530,6 +619,86 @@
 	return 0;
 }
 
+void wm_hubs_update_class_w(struct snd_soc_codec *codec)
+{
+	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	int enable = WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ;
+
+	if (!wm_hubs_dac_hp_direct(codec))
+		enable = false;
+
+	if (hubs->check_class_w_digital && !hubs->check_class_w_digital(codec))
+		enable = false;
+
+	dev_vdbg(codec->dev, "Class W %s\n", enable ? "enabled" : "disabled");
+
+	snd_soc_update_bits(codec, WM8993_CLASS_W_0,
+			    WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
+}
+EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
+
+#define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, \
+	.get = snd_soc_dapm_get_volsw, .put = class_w_put_volsw, \
+	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = widget->codec;
+	int ret;
+
+	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+	wm_hubs_update_class_w(codec);
+
+	return ret;
+}
+
+#define WM_HUBS_ENUM_W(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_double, \
+	.get = snd_soc_dapm_get_enum_double, \
+	.put = class_w_put_double, \
+	.private_value = (unsigned long)&xenum }
+
+static int class_w_put_double(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = widget->codec;
+	int ret;
+
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+	wm_hubs_update_class_w(codec);
+
+	return ret;
+}
+
+static const char *hp_mux_text[] = {
+	"Mixer",
+	"DAC",
+};
+
+static const struct soc_enum hpl_enum =
+	SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
+
+const struct snd_kcontrol_new wm_hubs_hpl_mux =
+	WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
+EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);
+
+static const struct soc_enum hpr_enum =
+	SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
+
+const struct snd_kcontrol_new wm_hubs_hpr_mux =
+	WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
+EXPORT_SYMBOL_GPL(wm_hubs_hpr_mux);
+
 static const struct snd_kcontrol_new in1l_pga[] = {
 SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
 SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
@@ -561,25 +730,25 @@
 };
 
 static const struct snd_kcontrol_new left_output_mixer[] = {
-SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
-SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
-SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
-SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
-SOC_DAPM_SINGLE("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
-SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
-SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
+WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
+WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
+WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
+WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
+WM_HUBS_SINGLE_W("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
+WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
+WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
+WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new right_output_mixer[] = {
-SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
-SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
-SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
-SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
-SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
-SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
-SOC_DAPM_SINGLE("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
+WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
+WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
+WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
+WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
+WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
+WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
+WM_HUBS_SINGLE_W("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
+WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new earpiece_mixer[] = {
@@ -943,6 +1112,7 @@
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+	INIT_LIST_HEAD(&hubs->dcs_cache);
 	init_completion(&hubs->dcs_done);
 
 	snd_soc_dapm_add_routes(dapm, analogue_routes,
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index 5705276..da2dc89 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -16,6 +16,8 @@
 
 #include <linux/completion.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
+#include <sound/control.h>
 
 struct snd_soc_codec;
 
@@ -30,9 +32,9 @@
 	int series_startup;
 	int no_series_update;
 
-	bool no_cache_class_w;
-	bool class_w;
-	u16 class_w_dcs;
+	bool no_cache_dac_hp_direct;
+	struct list_head dcs_cache;
+	bool (*check_class_w_digital)(struct snd_soc_codec *);
 
 	bool lineout1_se;
 	bool lineout1n_ena;
@@ -58,5 +60,9 @@
 extern void wm_hubs_vmid_ena(struct snd_soc_codec *codec);
 extern void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
 				   enum snd_soc_bias_level level);
+extern void wm_hubs_update_class_w(struct snd_soc_codec *codec);
+
+extern const struct snd_kcontrol_new wm_hubs_hpl_mux;
+extern const struct snd_kcontrol_new wm_hubs_hpr_mux;
 
 #endif
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
index 0678637..bdffab3 100644
--- a/sound/soc/ep93xx/ep93xx-ac97.c
+++ b/sound/soc/ep93xx/ep93xx-ac97.c
@@ -87,17 +87,13 @@
  * 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;
 };
 
@@ -359,66 +355,50 @@
 static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
 {
 	struct ep93xx_ac97_info *info;
+	struct resource *res;
+	unsigned int irq;
 	int ret;
 
-	info = kzalloc(sizeof(struct ep93xx_ac97_info), GFP_KERNEL);
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	info->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (!info->regs)
+		return -ENXIO;
+
+	irq = platform_get_irq(pdev, 0);
+	if (!irq)
+		return -ENODEV;
+
+	ret = devm_request_irq(&pdev->dev, irq, ep93xx_ac97_interrupt,
+			       IRQF_TRIGGER_HIGH, pdev->name, info);
+	if (ret)
+		goto fail;
+
 	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;
+		goto fail;
 
 	return 0;
 
-fail_free_irq:
+fail:
 	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);
-
+	ep93xx_ac97_info = NULL;
+	dev_set_drvdata(&pdev->dev, NULL);
 	return ret;
 }
 
@@ -431,11 +411,9 @@
 	/* 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);
+	ep93xx_ac97_info = NULL;
+	dev_set_drvdata(&pdev->dev, NULL);
 
 	return 0;
 }
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index f7a6234..8df8f6d 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -63,7 +63,6 @@
 	struct clk			*sclk;
 	struct clk			*lrclk;
 	struct ep93xx_pcm_dma_params	*dma_params;
-	struct resource			*mem;
 	void __iomem			*regs;
 };
 
@@ -373,38 +372,22 @@
 	struct resource *res;
 	int err;
 
-	info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
-	if (!info) {
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	dev_set_drvdata(&pdev->dev, info);
-	info->dma_params = ep93xx_i2s_dma_params;
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		err = -ENODEV;
-		goto fail_free_info;
-	}
+	if (!res)
+		return -ENODEV;
 
-	info->mem = request_mem_region(res->start, resource_size(res),
-				       pdev->name);
-	if (!info->mem) {
-		err = -EBUSY;
-		goto fail_free_info;
-	}
-
-	info->regs = ioremap(info->mem->start, resource_size(info->mem));
-	if (!info->regs) {
-		err = -ENXIO;
-		goto fail_release_mem;
-	}
+	info->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (!info->regs)
+		return -ENXIO;
 
 	info->mclk = clk_get(&pdev->dev, "mclk");
 	if (IS_ERR(info->mclk)) {
 		err = PTR_ERR(info->mclk);
-		goto fail_unmap_mem;
+		goto fail;
 	}
 
 	info->sclk = clk_get(&pdev->dev, "sclk");
@@ -419,6 +402,9 @@
 		goto fail_put_sclk;
 	}
 
+	dev_set_drvdata(&pdev->dev, info);
+	info->dma_params = ep93xx_i2s_dma_params;
+
 	err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
 	if (err)
 		goto fail_put_lrclk;
@@ -426,17 +412,12 @@
 	return 0;
 
 fail_put_lrclk:
+	dev_set_drvdata(&pdev->dev, NULL);
 	clk_put(info->lrclk);
 fail_put_sclk:
 	clk_put(info->sclk);
 fail_put_mclk:
 	clk_put(info->mclk);
-fail_unmap_mem:
-	iounmap(info->regs);
-fail_release_mem:
-	release_mem_region(info->mem->start, resource_size(info->mem));
-fail_free_info:
-	kfree(info);
 fail:
 	return err;
 }
@@ -446,12 +427,10 @@
 	struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
 
 	snd_soc_unregister_dai(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, NULL);
 	clk_put(info->lrclk);
 	clk_put(info->sclk);
 	clk_put(info->mclk);
-	iounmap(info->regs);
-	release_mem_region(info->mem->start, resource_size(info->mem));
-	kfree(info);
 	return 0;
 }
 
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index d754d34..d701330 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,18 +1,31 @@
+config SND_SOC_FSL_SSI
+	tristate
+
+config SND_SOC_FSL_UTILS
+	tristate
+
+menuconfig SND_POWERPC_SOC
+	tristate "SoC Audio for Freescale PowerPC CPUs"
+	depends on FSL_SOC
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the PowerPC CPUs.
+
+if SND_POWERPC_SOC
+
 config SND_MPC52xx_DMA
 	tristate
 
-# 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
+config SND_SOC_POWERPC_DMA
 	tristate
-	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_POWERPC_SSI
+	select SND_SOC_FSL_SSI
+	select SND_SOC_FSL_UTILS
+	select SND_SOC_POWERPC_DMA
 	select SND_SOC_CS4270
 	select SND_SOC_CS4270_VD33_ERRATA
 	default y if MPC8610_HPCD
@@ -23,7 +36,9 @@
 	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_FSL_SSI
+	select SND_SOC_FSL_UTILS
+	select SND_SOC_POWERPC_DMA
 	select SND_SOC_WM8776
 	default y if P1022_DS
 	help
@@ -65,3 +80,103 @@
 	help
 	  Say Y if you want to add support for sound on the Efika.
 
+endif # SND_POWERPC_SOC
+
+menuconfig SND_IMX_SOC
+	tristate "SoC Audio for Freescale i.MX CPUs"
+	depends on ARCH_MXC
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the i.MX CPUs.
+
+if SND_IMX_SOC
+
+config SND_SOC_IMX_SSI
+	tristate
+
+config SND_SOC_IMX_PCM
+	tristate
+
+config SND_SOC_IMX_PCM_FIQ
+	tristate
+	select FIQ
+	select SND_SOC_IMX_PCM
+
+config SND_SOC_IMX_PCM_DMA
+	tristate
+	select SND_SOC_DMAENGINE_PCM
+	select SND_SOC_IMX_PCM
+
+config SND_SOC_IMX_AUDMUX
+	tristate
+
+config SND_MXC_SOC_WM1133_EV1
+	tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted"
+	depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
+	select SND_SOC_WM8350
+	select SND_SOC_IMX_PCM_FIQ
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
+	help
+	  Enable support for audio on the i.MX31ADS with the WM1133-EV1
+	  PMIC board with WM8835x fitted.
+
+config SND_SOC_MX27VIS_AIC32X4
+	tristate "SoC audio support for Visstrim M10 boards"
+	depends on MACH_IMX27_VISSTRIM_M10 && I2C
+	select SND_SOC_TLV320AIC32X4
+	select SND_SOC_IMX_PCM_DMA
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
+	help
+	  Say Y if you want to add support for SoC audio on Visstrim SM10
+	  board with TLV320AIC32X4 codec.
+
+config SND_SOC_PHYCORE_AC97
+	tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
+	depends on MACH_PCM043 || MACH_PCA100
+	select SND_SOC_AC97_BUS
+	select SND_SOC_WM9712
+	select SND_SOC_IMX_PCM_FIQ
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
+	help
+	  Say Y if you want to add support for SoC audio on Phytec phyCORE
+	  and phyCARD boards in AC97 mode
+
+config SND_SOC_EUKREA_TLV320
+	tristate "Eukrea TLV320"
+	depends on MACH_EUKREA_MBIMX27_BASEBOARD \
+		|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
+		|| MACH_EUKREA_MBIMXSD35_BASEBOARD \
+		|| MACH_EUKREA_MBIMXSD51_BASEBOARD
+	depends on I2C
+	select SND_SOC_TLV320AIC23
+	select SND_SOC_IMX_PCM_FIQ
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
+	help
+	  Enable I2S based access to the TLV320AIC23B codec attached
+	  to the SSI interface
+
+config SND_SOC_IMX_SGTL5000
+	tristate "SoC Audio support for i.MX boards with sgtl5000"
+	depends on OF && I2C
+	select SND_SOC_SGTL5000
+	select SND_SOC_IMX_PCM_DMA
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_FSL_SSI
+	select SND_SOC_FSL_UTILS
+	help
+	  Say Y if you want to add support for SoC audio on an i.MX board with
+	  a sgtl5000 codec.
+
+config SND_SOC_IMX_MC13783
+	tristate "SoC Audio support for I.MX boards with mc13783"
+	depends on MFD_MC13783
+	select SND_SOC_IMX_SSI
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_MC13783
+	select SND_SOC_IMX_PCM_DMA
+
+endif # SND_IMX_SOC
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b4a38c0..5f3cf3f 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -8,8 +8,11 @@
 
 # Freescale PowerPC SSI/DMA Platform Support
 snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
-obj-$(CONFIG_SND_SOC_POWERPC_SSI) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
+obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
+obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
@@ -20,3 +23,29 @@
 obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
 obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 
+# i.MX Platform Support
+snd-soc-imx-ssi-objs := imx-ssi.o
+snd-soc-imx-audmux-objs := imx-audmux.o
+
+obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
+obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
+
+obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
+snd-soc-imx-pcm-y := imx-pcm.o
+snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
+snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
+
+# i.MX Machine Support
+snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
+snd-soc-phycore-ac97-objs := phycore-ac97.o
+snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
+snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
+snd-soc-imx-mc13783-objs := imx-mc13783.o
+
+obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
+obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
+obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
+obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
+obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
+obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
new file mode 100644
index 0000000..efb9ede
--- /dev/null
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -0,0 +1,164 @@
+/*
+ * eukrea-tlv320.c  --  SoC audio for eukrea_cpuimxXX in I2S mode
+ *
+ * Copyright 2010 Eric Bénard, Eukréa Electromatique <eric@eukrea.com>
+ *
+ * based on sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+ * which is Copyright 2009 Simtec Electronics
+ * and on sound/soc/imx/phycore-ac97.c which is
+ * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ *  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/device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/mach-types.h>
+
+#include "../codecs/tlv320aic23.h"
+#include "imx-ssi.h"
+#include "imx-audmux.h"
+
+#define CODEC_CLOCK 12000000
+
+static int eukrea_tlv320_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 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) {
+		pr_err("%s: failed set cpu dai format\n", __func__);
+		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) {
+		pr_err("%s: failed set codec dai format\n", __func__);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+				     CODEC_CLOCK, SND_SOC_CLOCK_OUT);
+	if (ret) {
+		pr_err("%s: failed setting codec sysclk\n", __func__);
+		return ret;
+	}
+	snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
+				SND_SOC_CLOCK_IN);
+	if (ret) {
+		pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops eukrea_tlv320_snd_ops = {
+	.hw_params	= eukrea_tlv320_hw_params,
+};
+
+static struct snd_soc_dai_link eukrea_tlv320_dai = {
+	.name		= "tlv320aic23",
+	.stream_name	= "TLV320AIC23",
+	.codec_dai_name	= "tlv320aic23-hifi",
+	.platform_name	= "imx-fiq-pcm-audio.0",
+	.codec_name	= "tlv320aic23-codec.0-001a",
+	.cpu_dai_name	= "imx-ssi.0",
+	.ops		= &eukrea_tlv320_snd_ops,
+};
+
+static struct snd_soc_card eukrea_tlv320 = {
+	.name		= "cpuimx-audio",
+	.owner		= THIS_MODULE,
+	.dai_link	= &eukrea_tlv320_dai,
+	.num_links	= 1,
+};
+
+static struct platform_device *eukrea_tlv320_snd_device;
+
+static int __init eukrea_tlv320_init(void)
+{
+	int ret;
+	int int_port = 0, ext_port;
+
+	if (machine_is_eukrea_cpuimx27()) {
+		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
+			IMX_AUDMUX_V1_PCR_SYN |
+			IMX_AUDMUX_V1_PCR_TFSDIR |
+			IMX_AUDMUX_V1_PCR_TCLKDIR |
+			IMX_AUDMUX_V1_PCR_RFSDIR |
+			IMX_AUDMUX_V1_PCR_RCLKDIR |
+			IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
+			IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
+			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
+		);
+		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
+			IMX_AUDMUX_V1_PCR_SYN |
+			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
+		);
+	} else if (machine_is_eukrea_cpuimx25sd() ||
+		   machine_is_eukrea_cpuimx35sd() ||
+		   machine_is_eukrea_cpuimx51sd()) {
+		ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3;
+		imx_audmux_v2_configure_port(int_port,
+			IMX_AUDMUX_V2_PTCR_SYN |
+			IMX_AUDMUX_V2_PTCR_TFSDIR |
+			IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+			IMX_AUDMUX_V2_PTCR_TCLKDIR |
+			IMX_AUDMUX_V2_PTCR_TCSEL(ext_port),
+			IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)
+		);
+		imx_audmux_v2_configure_port(ext_port,
+			IMX_AUDMUX_V2_PTCR_SYN,
+			IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)
+		);
+	} else {
+		/* return happy. We might run on a totally different machine */
+		return 0;
+	}
+
+	eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!eukrea_tlv320_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320);
+	ret = platform_device_add(eukrea_tlv320_snd_device);
+
+	if (ret) {
+		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+		platform_device_put(eukrea_tlv320_snd_device);
+	}
+
+	return ret;
+}
+
+static void __exit eukrea_tlv320_exit(void)
+{
+	platform_device_unregister(eukrea_tlv320_snd_device);
+}
+
+module_init(eukrea_tlv320_init);
+module_exit(eukrea_tlv320_exit);
+
+MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");
+MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 2eb407f..4ed2afd 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -11,11 +11,15 @@
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 
 #include <sound/core.h>
@@ -25,6 +29,26 @@
 #include <sound/soc.h>
 
 #include "fsl_ssi.h"
+#include "imx-pcm.h"
+
+#ifdef PPC
+#define read_ssi(addr)			 in_be32(addr)
+#define write_ssi(val, addr)		 out_be32(addr, val)
+#define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set)
+#elif defined ARM
+#define read_ssi(addr)			 readl(addr)
+#define write_ssi(val, addr)		 writel(val, addr)
+/*
+ * FIXME: Proper locking should be added at write_ssi_mask caller level
+ * to ensure this register read/modify/write sequence is race free.
+ */
+static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
+{
+	u32 val = readl(addr);
+	val = (val & ~clear) | set;
+	writel(val, addr);
+}
+#endif
 
 /**
  * FSLSSI_I2S_RATES: sample rates supported by the I2S
@@ -94,6 +118,13 @@
 	struct device_attribute dev_attr;
 	struct platform_device *pdev;
 
+	bool new_binding;
+	bool ssi_on_imx;
+	struct clk *clk;
+	struct platform_device *imx_pcm_pdev;
+	struct imx_pcm_dma_params dma_params_tx;
+	struct imx_pcm_dma_params dma_params_rx;
+
 	struct {
 		unsigned int rfrc;
 		unsigned int tfrc;
@@ -145,7 +176,7 @@
 	   were interrupted for.  We mask it with the Interrupt Enable register
 	   so that we only check for events that we're interested in.
 	 */
-	sisr = in_be32(&ssi->sisr) & SIER_FLAGS;
+	sisr = read_ssi(&ssi->sisr) & SIER_FLAGS;
 
 	if (sisr & CCSR_SSI_SISR_RFRC) {
 		ssi_private->stats.rfrc++;
@@ -260,7 +291,7 @@
 
 	/* Clear the bits that we set */
 	if (sisr2)
-		out_be32(&ssi->sisr, sisr2);
+		write_ssi(sisr2, &ssi->sisr);
 
 	return ret;
 }
@@ -295,7 +326,7 @@
 		 * SSI needs to be disabled before updating the registers we set
 		 * here.
 		 */
-		clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+		write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
 
 		/*
 		 * Program the SSI into I2S Slave Non-Network Synchronous mode.
@@ -303,20 +334,18 @@
 		 *
 		 * FIXME: Little-endian samples require a different shift dir
 		 */
-		clrsetbits_be32(&ssi->scr,
+		write_ssi_mask(&ssi->scr,
 			CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
 			CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
 			| (synchronous ? CCSR_SSI_SCR_SYN : 0));
 
-		out_be32(&ssi->stcr,
-			 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
+		write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
 			 CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
-			 CCSR_SSI_STCR_TSCKP);
+			 CCSR_SSI_STCR_TSCKP, &ssi->stcr);
 
-		out_be32(&ssi->srcr,
-			 CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
+		write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
 			 CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
-			 CCSR_SSI_SRCR_RSCKP);
+			 CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
 
 		/*
 		 * The DC and PM bits are only used if the SSI is the clock
@@ -324,7 +353,7 @@
 		 */
 
 		/* Enable the interrupts and DMA requests */
-		out_be32(&ssi->sier, SIER_FLAGS);
+		write_ssi(SIER_FLAGS, &ssi->sier);
 
 		/*
 		 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
@@ -339,9 +368,9 @@
 		 * 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(ssi_private->fifo_depth - 2) |
-			CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2));
+		write_ssi(CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
+			CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2),
+			&ssi->sfcsr);
 
 		/*
 		 * We keep the SSI disabled because if we enable it, then the
@@ -393,6 +422,12 @@
 		ssi_private->second_stream = substream;
 	}
 
+	if (ssi_private->ssi_on_imx)
+		snd_soc_dai_set_dma_data(dai, substream,
+			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+				&ssi_private->dma_params_tx :
+				&ssi_private->dma_params_rx);
+
 	return 0;
 }
 
@@ -417,7 +452,7 @@
 	unsigned int sample_size =
 		snd_pcm_format_width(params_format(hw_params));
 	u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
-	int enabled = in_be32(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
+	int enabled = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
 
 	/*
 	 * If we're in synchronous mode, and the SSI is already enabled,
@@ -439,9 +474,9 @@
 	/* In synchronous mode, the SSI uses STCCR for capture */
 	if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
 	    ssi_private->cpu_dai_drv.symmetric_rates)
-		clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+		write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
 	else
-		clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+		write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
 
 	return 0;
 }
@@ -466,19 +501,19 @@
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			setbits32(&ssi->scr,
+			write_ssi_mask(&ssi->scr, 0,
 				CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
 		else
-			setbits32(&ssi->scr,
+			write_ssi_mask(&ssi->scr, 0,
 				CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
+			write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0);
 		else
-			clrbits32(&ssi->scr, CCSR_SSI_SCR_RE);
+			write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
 		break;
 
 	default:
@@ -510,7 +545,7 @@
 	if (!ssi_private->first_stream) {
 		struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
 
-		clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+		write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
 	}
 }
 
@@ -622,12 +657,6 @@
 	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;
-	}
-
 	/* We only support the SSI in "I2S Slave" mode */
 	sprop = of_get_property(np, "fsl,mode", NULL);
 	if (!sprop || strcmp(sprop, "i2s-slave")) {
@@ -692,6 +721,50 @@
                 /* Older 8610 DTs didn't have the fifo-depth property */
 		ssi_private->fifo_depth = 8;
 
+	if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
+		u32 dma_events[2];
+		ssi_private->ssi_on_imx = true;
+
+		ssi_private->clk = clk_get(&pdev->dev, NULL);
+		if (IS_ERR(ssi_private->clk)) {
+			ret = PTR_ERR(ssi_private->clk);
+			dev_err(&pdev->dev, "could not get clock: %d\n", ret);
+			goto error_irq;
+		}
+		clk_prepare_enable(ssi_private->clk);
+
+		/*
+		 * We have burstsize be "fifo_depth - 2" to match the SSI
+		 * watermark setting in fsl_ssi_startup().
+		 */
+		ssi_private->dma_params_tx.burstsize =
+			ssi_private->fifo_depth - 2;
+		ssi_private->dma_params_rx.burstsize =
+			ssi_private->fifo_depth - 2;
+		ssi_private->dma_params_tx.dma_addr =
+			ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
+		ssi_private->dma_params_rx.dma_addr =
+			ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
+		/*
+		 * TODO: This is a temporary solution and should be changed
+		 * to use generic DMA binding later when the helplers get in.
+		 */
+		ret = of_property_read_u32_array(pdev->dev.of_node,
+					"fsl,ssi-dma-events", dma_events, 2);
+		if (ret) {
+			dev_err(&pdev->dev, "could not get dma events\n");
+			goto error_clk;
+		}
+		ssi_private->dma_params_tx.dma = dma_events[0];
+		ssi_private->dma_params_rx.dma = dma_events[1];
+
+		ssi_private->dma_params_tx.shared_peripheral =
+				of_device_is_compatible(of_get_parent(np),
+							"fsl,spba-bus");
+		ssi_private->dma_params_rx.shared_peripheral =
+				ssi_private->dma_params_tx.shared_peripheral;
+	}
+
 	/* Initialize the the device_attribute structure */
 	dev_attr = &ssi_private->dev_attr;
 	sysfs_attr_init(&dev_attr->attr);
@@ -715,6 +788,26 @@
 		goto error_dev;
 	}
 
+	if (ssi_private->ssi_on_imx) {
+		ssi_private->imx_pcm_pdev =
+			platform_device_register_simple("imx-pcm-audio",
+							-1, NULL, 0);
+		if (IS_ERR(ssi_private->imx_pcm_pdev)) {
+			ret = PTR_ERR(ssi_private->imx_pcm_pdev);
+			goto error_dev;
+		}
+	}
+
+	/*
+	 * If codec-handle property is missing from SSI node, we assume
+	 * that the machine driver uses new binding which does not require
+	 * SSI driver to trigger machine driver's probe.
+	 */
+	if (!of_get_property(np, "codec-handle", NULL)) {
+		ssi_private->new_binding = true;
+		goto done;
+	}
+
 	/* Trigger the machine driver's probe function.  The platform driver
 	 * name of the machine driver is taken from /compatible property of the
 	 * device tree.  We also pass the address of the CPU DAI driver
@@ -736,15 +829,24 @@
 		goto error_dai;
 	}
 
+done:
 	return 0;
 
 error_dai:
+	if (ssi_private->ssi_on_imx)
+		platform_device_unregister(ssi_private->imx_pcm_pdev);
 	snd_soc_unregister_dai(&pdev->dev);
 
 error_dev:
 	dev_set_drvdata(&pdev->dev, NULL);
 	device_remove_file(&pdev->dev, dev_attr);
 
+error_clk:
+	if (ssi_private->ssi_on_imx) {
+		clk_disable_unprepare(ssi_private->clk);
+		clk_put(ssi_private->clk);
+	}
+
 error_irq:
 	free_irq(ssi_private->irq, ssi_private);
 
@@ -764,7 +866,13 @@
 {
 	struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
 
-	platform_device_unregister(ssi_private->pdev);
+	if (!ssi_private->new_binding)
+		platform_device_unregister(ssi_private->pdev);
+	if (ssi_private->ssi_on_imx) {
+		platform_device_unregister(ssi_private->imx_pcm_pdev);
+		clk_disable_unprepare(ssi_private->clk);
+		clk_put(ssi_private->clk);
+	}
 	snd_soc_unregister_dai(&pdev->dev);
 	device_remove_file(&pdev->dev, &ssi_private->dev_attr);
 
@@ -779,6 +887,7 @@
 
 static const struct of_device_id fsl_ssi_ids[] = {
 	{ .compatible = "fsl,mpc8610-ssi", },
+	{ .compatible = "fsl,imx21-ssi", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
new file mode 100644
index 0000000..b9e42b5
--- /dev/null
+++ b/sound/soc/fsl/fsl_utils.c
@@ -0,0 +1,91 @@
+/**
+ * Freescale ALSA SoC Machine driver utility
+ *
+ * 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/of_address.h>
+#include <sound/soc.h>
+
+#include "fsl_utils.h"
+
+/**
+ * fsl_asoc_get_dma_channel - determine the dma channel for a SSI node
+ *
+ * @ssi_np: pointer to the SSI device tree node
+ * @name: name of the phandle pointing to the dma channel
+ * @dai: ASoC DAI link pointer to be filled with platform_name
+ * @dma_channel_id: dma channel id to be returned
+ * @dma_id: dma id to be returned
+ *
+ * This function determines the dma and channel id for given SSI node.  It
+ * also discovers the platform_name for the ASoC DAI link.
+ */
+int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
+			     const char *name,
+			     struct snd_soc_dai_link *dai,
+			     unsigned int *dma_channel_id,
+			     unsigned int *dma_id)
+{
+	struct resource res;
+	struct device_node *dma_channel_np, *dma_np;
+	const u32 *iprop;
+	int ret;
+
+	dma_channel_np = of_parse_phandle(ssi_np, name, 0);
+	if (!dma_channel_np)
+		return -EINVAL;
+
+	if (!of_device_is_compatible(dma_channel_np, "fsl,ssi-dma-channel")) {
+		of_node_put(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) {
+		of_node_put(dma_channel_np);
+		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 = be32_to_cpup(iprop);
+
+	dma_np = of_get_parent(dma_channel_np);
+	iprop = of_get_property(dma_np, "cell-index", NULL);
+	if (!iprop) {
+		of_node_put(dma_np);
+		return -EINVAL;
+	}
+	*dma_id = be32_to_cpup(iprop);
+
+	of_node_put(dma_np);
+	of_node_put(dma_channel_np);
+
+	return 0;
+}
+EXPORT_SYMBOL(fsl_asoc_get_dma_channel);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale ASoC utility code");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h
new file mode 100644
index 0000000..b295112
--- /dev/null
+++ b/sound/soc/fsl/fsl_utils.h
@@ -0,0 +1,26 @@
+/**
+ * Freescale ALSA SoC Machine driver utility
+ *
+ * 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.
+ */
+
+#ifndef _FSL_UTILS_H
+#define _FSL_UTILS_H
+
+#define DAI_NAME_SIZE	32
+
+struct snd_soc_dai_link;
+struct device_node;
+
+int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name,
+			     struct snd_soc_dai_link *dai,
+			     unsigned int *dma_channel_id,
+			     unsigned int *dma_id);
+
+#endif /* _FSL_UTILS_H */
diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
similarity index 100%
rename from sound/soc/imx/imx-audmux.c
rename to sound/soc/fsl/imx-audmux.c
diff --git a/sound/soc/imx/imx-audmux.h b/sound/soc/fsl/imx-audmux.h
similarity index 100%
rename from sound/soc/imx/imx-audmux.h
rename to sound/soc/fsl/imx-audmux.h
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
new file mode 100644
index 0000000..f59c349
--- /dev/null
+++ b/sound/soc/fsl/imx-mc13783.c
@@ -0,0 +1,156 @@
+/*
+ * imx-mc13783.c  --  SoC audio for imx based boards with mc13783 codec
+ *
+ * Copyright 2012 Philippe Retornaz, <philippe.retornaz@epfl.ch>
+ *
+ * Heavly based on phycore-mc13783:
+ * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ *  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/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
+#include "../codecs/mc13783.h"
+#include "imx-ssi.h"
+#include "imx-audmux.h"
+
+#define FMT_SSI (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
+		SND_SOC_DAIFMT_CBM_CFM)
+
+static int imx_mc13783_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 *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xfffffffc, 0xfffffffc,
+					4, 16);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, MC13783_CLK_CLIA, 26000000, 0);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x0, 0xfffffffc, 2, 16);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops imx_mc13783_hifi_ops = {
+	.hw_params = imx_mc13783_hifi_hw_params,
+};
+
+static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = {
+	{
+		.name = "MC13783",
+		.stream_name	 = "Sound",
+		.codec_dai_name	 = "mc13783-hifi",
+		.codec_name	 = "mc13783-codec",
+		.cpu_dai_name	 = "imx-ssi.0",
+		.platform_name	 = "imx-pcm-audio.0",
+		.ops		 = &imx_mc13783_hifi_ops,
+		.symmetric_rates = 1,
+		.dai_fmt 	 = FMT_SSI,
+	},
+};
+
+static const struct snd_soc_dapm_widget imx_mc13783_widget[] = {
+	SND_SOC_DAPM_MIC("Mic", NULL),
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route imx_mc13783_routes[] = {
+	{"Speaker", NULL, "LSP"},
+	{"Headphone", NULL, "HSL"},
+	{"Headphone", NULL, "HSR"},
+
+	{"MC1LIN", NULL, "MC1 Bias"},
+	{"MC2IN", NULL, "MC2 Bias"},
+	{"MC1 Bias", NULL, "Mic"},
+	{"MC2 Bias", NULL, "Mic"},
+};
+
+static struct snd_soc_card imx_mc13783 = {
+	.name		= "imx_mc13783",
+	.dai_link	= imx_mc13783_dai_mc13783,
+	.num_links	= ARRAY_SIZE(imx_mc13783_dai_mc13783),
+	.dapm_widgets	= imx_mc13783_widget,
+	.num_dapm_widgets = ARRAY_SIZE(imx_mc13783_widget),
+	.dapm_routes	= imx_mc13783_routes,
+	.num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes),
+};
+
+static int __devinit imx_mc13783_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	imx_mc13783.dev = &pdev->dev;
+
+	ret = snd_soc_register_card(&imx_mc13783);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		return ret;
+	}
+
+	imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
+		IMX_AUDMUX_V2_PTCR_SYN,
+		IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
+		IMX_AUDMUX_V2_PDCR_MODE(1) |
+		IMX_AUDMUX_V2_PDCR_INMMASK(0xfc));
+	imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
+		IMX_AUDMUX_V2_PTCR_SYN |
+		IMX_AUDMUX_V2_PTCR_TFSDIR |
+		IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
+		IMX_AUDMUX_V2_PTCR_TCLKDIR |
+		IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
+		IMX_AUDMUX_V2_PTCR_RFSDIR |
+		IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
+		IMX_AUDMUX_V2_PTCR_RCLKDIR |
+		IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4),
+		IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4));
+
+	return ret;
+}
+
+static int __devexit imx_mc13783_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_card(&imx_mc13783);
+
+	return 0;
+}
+
+static struct platform_driver imx_mc13783_audio_driver = {
+	.driver = {
+		.name = "imx_mc13783",
+		.owner = THIS_MODULE,
+	},
+	.probe = imx_mc13783_probe,
+	.remove = __devexit_p(imx_mc13783_remove)
+};
+
+module_platform_driver(imx_mc13783_audio_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch");
+MODULE_DESCRIPTION("imx with mc13783 codec ALSA SoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx_mc13783");
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
new file mode 100644
index 0000000..f3c0a5e
--- /dev/null
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -0,0 +1,176 @@
+/*
+ * imx-pcm-dma-mx2.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This code is based on code copyrighted by Freescale,
+ * Liam Girdwood, Javier Martin and probably others.
+ *
+ *  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/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/types.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include <mach/dma.h>
+
+#include "imx-pcm.h"
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+	if (!imx_dma_is_general_purpose(chan))
+		return false;
+
+	chan->private = param;
+
+	return true;
+}
+
+static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+	struct imx_pcm_dma_params *dma_params;
+	struct dma_slave_config slave_config;
+	int ret;
+
+	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+	ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
+	if (ret)
+		return ret;
+
+	slave_config.device_fc = false;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config.dst_addr = dma_params->dma_addr;
+		slave_config.dst_maxburst = dma_params->burstsize;
+	} else {
+		slave_config.src_addr = dma_params->dma_addr;
+		slave_config.src_maxburst = dma_params->burstsize;
+	}
+
+	ret = dmaengine_slave_config(chan, &slave_config);
+	if (ret)
+		return ret;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static struct snd_pcm_hardware snd_imx_hardware = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID |
+		SNDRV_PCM_INFO_PAUSE |
+		SNDRV_PCM_INFO_RESUME,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rate_min = 8000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
+	.period_bytes_min = 128,
+	.period_bytes_max = 65535, /* Limited by SDMA engine */
+	.periods_min = 2,
+	.periods_max = 255,
+	.fifo_size = 0,
+};
+
+static int snd_imx_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct imx_pcm_dma_params *dma_params;
+	struct imx_dma_data *dma_data;
+	int ret;
+
+	snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
+
+	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+	dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
+	dma_data->peripheral_type = dma_params->shared_peripheral ?
+					IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
+	dma_data->priority = DMA_PRIO_HIGH;
+	dma_data->dma_request = dma_params->dma;
+
+	ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
+	if (ret) {
+		kfree(dma_data);
+		return 0;
+	}
+
+	snd_dmaengine_pcm_set_data(substream, dma_data);
+
+	return 0;
+}
+
+static int snd_imx_close(struct snd_pcm_substream *substream)
+{
+	struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
+
+	snd_dmaengine_pcm_close(substream);
+	kfree(dma_data);
+
+	return 0;
+}
+
+static struct snd_pcm_ops imx_pcm_ops = {
+	.open		= snd_imx_open,
+	.close		= snd_imx_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= snd_imx_pcm_hw_params,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer,
+	.mmap		= snd_imx_pcm_mmap,
+};
+
+static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
+	.ops		= &imx_pcm_ops,
+	.pcm_new	= imx_pcm_new,
+	.pcm_free	= imx_pcm_free,
+};
+
+static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
+{
+	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),
+};
+
+module_platform_driver(imx_pcm_driver);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-pcm-audio");
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
similarity index 100%
rename from sound/soc/imx/imx-pcm-fiq.c
rename to sound/soc/fsl/imx-pcm-fiq.c
diff --git a/sound/soc/imx/imx-pcm.c b/sound/soc/fsl/imx-pcm.c
similarity index 100%
rename from sound/soc/imx/imx-pcm.c
rename to sound/soc/fsl/imx-pcm.c
diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
new file mode 100644
index 0000000..83c0ed7
--- /dev/null
+++ b/sound/soc/fsl/imx-pcm.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This code is based on code copyrighted by Freescale,
+ * Liam Girdwood, Javier Martin and probably others.
+ *
+ * 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 _IMX_PCM_H
+#define _IMX_PCM_H
+
+/*
+ * Do not change this as the FIQ handler depends on this size
+ */
+#define IMX_SSI_DMABUF_SIZE	(64 * 1024)
+
+struct imx_pcm_dma_params {
+	int dma;
+	unsigned long dma_addr;
+	int burstsize;
+	bool shared_peripheral;	/* The peripheral is on SPBA bus */
+};
+
+int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
+		     struct vm_area_struct *vma);
+int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
+void imx_pcm_free(struct snd_pcm *pcm);
+
+#endif /* _IMX_PCM_H */
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
new file mode 100644
index 0000000..3a729ca
--- /dev/null
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+#include <linux/clk.h>
+#include <sound/soc.h>
+
+#include "../codecs/sgtl5000.h"
+#include "imx-audmux.h"
+
+#define DAI_NAME_SIZE	32
+
+struct imx_sgtl5000_data {
+	struct snd_soc_dai_link dai;
+	struct snd_soc_card card;
+	char codec_dai_name[DAI_NAME_SIZE];
+	char platform_name[DAI_NAME_SIZE];
+	struct clk *codec_clk;
+	unsigned int clk_frequency;
+};
+
+static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct imx_sgtl5000_data *data = container_of(rtd->card,
+					struct imx_sgtl5000_data, card);
+	struct device *dev = rtd->card->dev;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(rtd->codec_dai, SGTL5000_SYSCLK,
+				     data->clk_frequency, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(dev, "could not set codec driver clock params\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget imx_sgtl5000_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In Jack", NULL),
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Line Out Jack", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static int __devinit imx_sgtl5000_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *ssi_np, *codec_np;
+	struct platform_device *ssi_pdev;
+	struct i2c_client *codec_dev;
+	struct imx_sgtl5000_data *data;
+	int int_port, ext_port;
+	int ret;
+
+	ret = of_property_read_u32(np, "mux-int-port", &int_port);
+	if (ret) {
+		dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+	if (ret) {
+		dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
+		return ret;
+	}
+
+	/*
+	 * The port numbering in the hardware manual starts at 1, while
+	 * the audmux API expects it starts at 0.
+	 */
+	int_port--;
+	ext_port--;
+	ret = imx_audmux_v2_configure_port(int_port,
+			IMX_AUDMUX_V2_PTCR_SYN |
+			IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+			IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+			IMX_AUDMUX_V2_PTCR_TFSDIR |
+			IMX_AUDMUX_V2_PTCR_TCLKDIR,
+			IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+	if (ret) {
+		dev_err(&pdev->dev, "audmux internal port setup failed\n");
+		return ret;
+	}
+	imx_audmux_v2_configure_port(ext_port,
+			IMX_AUDMUX_V2_PTCR_SYN |
+			IMX_AUDMUX_V2_PTCR_TCSEL(int_port),
+			IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+	if (ret) {
+		dev_err(&pdev->dev, "audmux external port setup failed\n");
+		return ret;
+	}
+
+	ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
+	codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
+	if (!ssi_np || !codec_np) {
+		dev_err(&pdev->dev, "phandle missing or invalid\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	ssi_pdev = of_find_device_by_node(ssi_np);
+	if (!ssi_pdev) {
+		dev_err(&pdev->dev, "failed to find SSI platform device\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+	codec_dev = of_find_i2c_device_by_node(codec_np);
+	if (!codec_dev) {
+		dev_err(&pdev->dev, "failed to find codec platform device\n");
+		return -EINVAL;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	data->codec_clk = clk_get(&codec_dev->dev, NULL);
+	if (IS_ERR(data->codec_clk)) {
+		/* assuming clock enabled by default */
+		data->codec_clk = NULL;
+		ret = of_property_read_u32(codec_np, "clock-frequency",
+					&data->clk_frequency);
+		if (ret) {
+			dev_err(&codec_dev->dev,
+				"clock-frequency missing or invalid\n");
+			goto fail;
+		}
+	} else {
+		data->clk_frequency = clk_get_rate(data->codec_clk);
+		clk_prepare_enable(data->codec_clk);
+	}
+
+	data->dai.name = "HiFi";
+	data->dai.stream_name = "HiFi";
+	data->dai.codec_dai_name = "sgtl5000";
+	data->dai.codec_of_node = codec_np;
+	data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev);
+	data->dai.platform_name = "imx-pcm-audio";
+	data->dai.init = &imx_sgtl5000_dai_init;
+	data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			    SND_SOC_DAIFMT_CBM_CFM;
+
+	data->card.dev = &pdev->dev;
+	ret = snd_soc_of_parse_card_name(&data->card, "model");
+	if (ret)
+		goto clk_fail;
+	ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
+	if (ret)
+		goto clk_fail;
+	data->card.num_links = 1;
+	data->card.dai_link = &data->dai;
+	data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
+	data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
+
+	ret = snd_soc_register_card(&data->card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+		goto clk_fail;
+	}
+
+	platform_set_drvdata(pdev, data);
+clk_fail:
+	clk_put(data->codec_clk);
+fail:
+	if (ssi_np)
+		of_node_put(ssi_np);
+	if (codec_np)
+		of_node_put(codec_np);
+
+	return ret;
+}
+
+static int __devexit imx_sgtl5000_remove(struct platform_device *pdev)
+{
+	struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
+
+	if (data->codec_clk) {
+		clk_disable_unprepare(data->codec_clk);
+		clk_put(data->codec_clk);
+	}
+	snd_soc_unregister_card(&data->card);
+
+	return 0;
+}
+
+static const struct of_device_id imx_sgtl5000_dt_ids[] = {
+	{ .compatible = "fsl,imx-audio-sgtl5000", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sgtl5000_dt_ids);
+
+static struct platform_driver imx_sgtl5000_driver = {
+	.driver = {
+		.name = "imx-sgtl5000",
+		.owner = THIS_MODULE,
+		.of_match_table = imx_sgtl5000_dt_ids,
+	},
+	.probe = imx_sgtl5000_probe,
+	.remove = __devexit_p(imx_sgtl5000_remove),
+};
+module_platform_driver(imx_sgtl5000_driver);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale i.MX SGTL5000 ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-sgtl5000");
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
new file mode 100644
index 0000000..cf3ed03
--- /dev/null
+++ b/sound/soc/fsl/imx-ssi.c
@@ -0,0 +1,690 @@
+/*
+ * imx-ssi.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This code is based on code copyrighted by Freescale,
+ * Liam Girdwood, Javier Martin and probably others.
+ *
+ *  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.
+ *
+ *
+ * The i.MX SSI core has some nasty limitations in AC97 mode. While most
+ * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
+ * one FIFO which combines all valid receive slots. We cannot even select
+ * which slots we want to receive. The WM9712 with which this driver
+ * was developed with always sends GPIO status data in slot 12 which
+ * we receive in our (PCM-) data stream. The only chance we have is to
+ * manually skip this data in the FIQ handler. With sampling rates different
+ * from 48000Hz not every frame has valid receive data, so the ratio
+ * between pcm data and GPIO status data changes. Our FIQ handler is not
+ * able to handle this, hence this driver only works with 48000Hz sampling
+ * rate.
+ * Reading and writing AC97 registers is another challenge. The core
+ * provides us status bits when the read register is updated with *another*
+ * value. When we read the same register two times (and the register still
+ * contains the same value) these status bits are not set. We work
+ * around this by not polling these bits but only wait a fixed delay.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/ssi.h>
+#include <mach/hardware.h>
+
+#include "imx-ssi.h"
+
+#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
+
+/*
+ * SSI Network Mode or TDM slots configuration.
+ * Should only be called when port is inactive (i.e. SSIEN = 0).
+ */
+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 = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 sccr;
+
+	sccr = readl(ssi->base + SSI_STCCR);
+	sccr &= ~SSI_STCCR_DC_MASK;
+	sccr |= SSI_STCCR_DC(slots - 1);
+	writel(sccr, ssi->base + SSI_STCCR);
+
+	sccr = readl(ssi->base + SSI_SRCCR);
+	sccr &= ~SSI_STCCR_DC_MASK;
+	sccr |= SSI_STCCR_DC(slots - 1);
+	writel(sccr, ssi->base + SSI_SRCCR);
+
+	writel(tx_mask, ssi->base + SSI_STMSK);
+	writel(rx_mask, ssi->base + SSI_SRMSK);
+
+	return 0;
+}
+
+/*
+ * SSI DAI format configuration.
+ * Should only be called when port is inactive (i.e. SSIEN = 0).
+ */
+static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+	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);
+
+	/* DAI mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		/* data on rising edge of bclk, frame low 1clk before data */
+		strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
+		scr |= SSI_SCR_NET;
+		if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
+			scr &= ~SSI_I2S_MODE_MASK;
+			scr |= SSI_SCR_I2S_MODE_SLAVE;
+		}
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		/* data on rising edge of bclk, frame high with data */
+		strcr |= SSI_STCR_TXBIT0;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		/* data on rising edge of bclk, frame high with data */
+		strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		/* data on rising edge of bclk, frame high 1clk before data */
+		strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
+		break;
+	}
+
+	/* DAI clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_IF:
+		strcr |= SSI_STCR_TFSI;
+		strcr &= ~SSI_STCR_TSCKP;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		strcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+		strcr &= ~SSI_STCR_TFSI;
+		strcr |= SSI_STCR_TSCKP;
+		break;
+	}
+
+	/* DAI clock master masks */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	default:
+		/* Master mode not implemented, needs handling of clocks. */
+		return -EINVAL;
+	}
+
+	strcr |= SSI_STCR_TFEN0;
+
+	if (ssi->flags & IMX_SSI_NET)
+		scr |= SSI_SCR_NET;
+	if (ssi->flags & IMX_SSI_SYN)
+		scr |= SSI_SCR_SYN;
+
+	writel(strcr, ssi->base + SSI_STCR);
+	writel(strcr, ssi->base + SSI_SRCR);
+	writel(scr, ssi->base + SSI_SCR);
+
+	return 0;
+}
+
+/*
+ * SSI system clock configuration.
+ * Should only be called when port is inactive (i.e. SSIEN = 0).
+ */
+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 = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 scr;
+
+	scr = readl(ssi->base + SSI_SCR);
+
+	switch (clk_id) {
+	case IMX_SSP_SYS_CLK:
+		if (dir == SND_SOC_CLOCK_OUT)
+			scr |= SSI_SCR_SYS_CLK_EN;
+		else
+			scr &= ~SSI_SCR_SYS_CLK_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	writel(scr, ssi->base + SSI_SCR);
+
+	return 0;
+}
+
+/*
+ * SSI Clock dividers
+ * Should only be called when port is inactive (i.e. SSIEN = 0).
+ */
+static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+				  int div_id, int div)
+{
+	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 stccr, srccr;
+
+	stccr = readl(ssi->base + SSI_STCCR);
+	srccr = readl(ssi->base + SSI_SRCCR);
+
+	switch (div_id) {
+	case IMX_SSI_TX_DIV_2:
+		stccr &= ~SSI_STCCR_DIV2;
+		stccr |= div;
+		break;
+	case IMX_SSI_TX_DIV_PSR:
+		stccr &= ~SSI_STCCR_PSR;
+		stccr |= div;
+		break;
+	case IMX_SSI_TX_DIV_PM:
+		stccr &= ~0xff;
+		stccr |= SSI_STCCR_PM(div);
+		break;
+	case IMX_SSI_RX_DIV_2:
+		stccr &= ~SSI_STCCR_DIV2;
+		stccr |= div;
+		break;
+	case IMX_SSI_RX_DIV_PSR:
+		stccr &= ~SSI_STCCR_PSR;
+		stccr |= div;
+		break;
+	case IMX_SSI_RX_DIV_PM:
+		stccr &= ~0xff;
+		stccr |= SSI_STCCR_PM(div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	writel(stccr, ssi->base + SSI_STCCR);
+	writel(srccr, ssi->base + SSI_SRCCR);
+
+	return 0;
+}
+
+static int imx_ssi_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *cpu_dai)
+{
+	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
+	struct imx_pcm_dma_params *dma_data;
+
+	/* Tx/Rx config */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_data = &ssi->dma_params_tx;
+	else
+		dma_data = &ssi->dma_params_rx;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+	return 0;
+}
+
+/*
+ * Should only be called when port is inactive (i.e. SSIEN = 0),
+ * although can be called multiple times by upper layers.
+ */
+static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *cpu_dai)
+{
+	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 reg, sccr;
+
+	/* Tx/Rx config */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = SSI_STCCR;
+	else
+		reg = SSI_SRCCR;
+
+	if (ssi->flags & IMX_SSI_SYN)
+		reg = SSI_STCCR;
+
+	sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
+
+	/* DAI data (word) size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		sccr |= SSI_SRCCR_WL(16);
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		sccr |= SSI_SRCCR_WL(20);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		sccr |= SSI_SRCCR_WL(24);
+		break;
+	}
+
+	writel(sccr, ssi->base + reg);
+
+	return 0;
+}
+
+static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
+	unsigned int sier_bits, sier;
+	unsigned int scr;
+
+	scr = readl(ssi->base + SSI_SCR);
+	sier = readl(ssi->base + SSI_SIER);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (ssi->flags & IMX_SSI_DMA)
+			sier_bits = SSI_SIER_TDMAE;
+		else
+			sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
+	} else {
+		if (ssi->flags & IMX_SSI_DMA)
+			sier_bits = SSI_SIER_RDMAE;
+		else
+			sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
+	}
+
+	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)
+			scr |= SSI_SCR_TE;
+		else
+			scr |= SSI_SCR_RE;
+		sier |= sier_bits;
+
+		if (++ssi->enabled == 1)
+			scr |= SSI_SCR_SSIEN;
+
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			scr &= ~SSI_SCR_TE;
+		else
+			scr &= ~SSI_SCR_RE;
+		sier &= ~sier_bits;
+
+		if (--ssi->enabled == 0)
+			scr &= ~SSI_SCR_SSIEN;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!(ssi->flags & IMX_SSI_USE_AC97))
+		/* rx/tx are always enabled to access ac97 registers */
+		writel(scr, ssi->base + SSI_SCR);
+
+	writel(sier, ssi->base + SSI_SIER);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
+	.startup	= imx_ssi_startup,
+	.hw_params	= imx_ssi_hw_params,
+	.set_fmt	= imx_ssi_set_dai_fmt,
+	.set_clkdiv	= imx_ssi_set_dai_clkdiv,
+	.set_sysclk	= imx_ssi_set_dai_sysclk,
+	.set_tdm_slot	= imx_ssi_set_dai_tdm_slot,
+	.trigger	= imx_ssi_trigger,
+};
+
+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_ssi_dai = {
+	.probe = imx_ssi_dai_probe,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &imx_ssi_pcm_dai_ops,
+};
+
+static struct snd_soc_dai_driver imx_ac97_dai = {
+	.probe = imx_ssi_dai_probe,
+	.ac97_control = 1,
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &imx_ssi_pcm_dai_ops,
+};
+
+static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
+{
+	void __iomem *base = imx_ssi->base;
+
+	writel(0x0, base + SSI_SCR);
+	writel(0x0, base + SSI_STCR);
+	writel(0x0, base + SSI_SRCR);
+
+	writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
+
+	writel(SSI_SFCSR_RFWM0(8) |
+		SSI_SFCSR_TFWM0(8) |
+		SSI_SFCSR_RFWM1(8) |
+		SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
+
+	writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
+	writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
+
+	writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
+	writel(SSI_SOR_WAIT(3), base + SSI_SOR);
+
+	writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
+			SSI_SCR_TE | SSI_SCR_RE,
+			base + SSI_SCR);
+
+	writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
+	writel(0xff, base + SSI_SACCDIS);
+	writel(0x300, base + SSI_SACCEN);
+}
+
+static struct imx_ssi *ac97_ssi;
+
+static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+		unsigned short val)
+{
+	struct imx_ssi *imx_ssi = ac97_ssi;
+	void __iomem *base = imx_ssi->base;
+	unsigned int lreg;
+	unsigned int lval;
+
+	if (reg > 0x7f)
+		return;
+
+	pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
+
+	lreg = reg <<  12;
+	writel(lreg, base + SSI_SACADD);
+
+	lval = val << 4;
+	writel(lval , base + SSI_SACDAT);
+
+	writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
+	udelay(100);
+}
+
+static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
+		unsigned short reg)
+{
+	struct imx_ssi *imx_ssi = ac97_ssi;
+	void __iomem *base = imx_ssi->base;
+
+	unsigned short val = -1;
+	unsigned int lreg;
+
+	lreg = (reg & 0x7f) <<  12 ;
+	writel(lreg, base + SSI_SACADD);
+	writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
+
+	udelay(100);
+
+	val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
+
+	pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
+
+	return val;
+}
+
+static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
+{
+	struct imx_ssi *imx_ssi = ac97_ssi;
+
+	if (imx_ssi->ac97_reset)
+		imx_ssi->ac97_reset(ac97);
+}
+
+static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	struct imx_ssi *imx_ssi = ac97_ssi;
+
+	if (imx_ssi->ac97_warm_reset)
+		imx_ssi->ac97_warm_reset(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read		= imx_ssi_ac97_read,
+	.write		= imx_ssi_ac97_write,
+	.reset		= imx_ssi_ac97_reset,
+	.warm_reset	= imx_ssi_ac97_warm_reset
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+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;
+	int ret = 0;
+	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;
+		ssi->ac97_warm_reset = pdata->ac97_warm_reset;
+		ssi->flags = pdata->flags;
+	}
+
+	ssi->irq = platform_get_irq(pdev, 0);
+
+	ssi->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(ssi->clk)) {
+		ret = PTR_ERR(ssi->clk);
+		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
+			ret);
+		goto failed_clk;
+	}
+	clk_enable(ssi->clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		goto failed_get_resource;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
+		dev_err(&pdev->dev, "request_mem_region failed\n");
+		ret = -EBUSY;
+		goto failed_get_resource;
+	}
+
+	ssi->base = ioremap(res->start, resource_size(res));
+	if (!ssi->base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENODEV;
+		goto failed_ioremap;
+	}
+
+	if (ssi->flags & IMX_SSI_USE_AC97) {
+		if (ac97_ssi) {
+			ret = -EBUSY;
+			goto failed_ac97;
+		}
+		ac97_ssi = ssi;
+		setup_channel_to_ac97(ssi);
+		dai = &imx_ac97_dai;
+	} else
+		dai = &imx_ssi_dai;
+
+	writel(0x0, ssi->base + SSI_SIER);
+
+	ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
+	ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
+
+	ssi->dma_params_tx.burstsize = 6;
+	ssi->dma_params_rx.burstsize = 4;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
+	if (res)
+		ssi->dma_params_tx.dma = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
+	if (res)
+		ssi->dma_params_rx.dma = res->start;
+
+	platform_set_drvdata(pdev, ssi);
+
+	ret = snd_soc_register_dai(&pdev->dev, dai);
+	if (ret) {
+		dev_err(&pdev->dev, "register DAI failed\n");
+		goto failed_register;
+	}
+
+	ssi->soc_platform_pdev_fiq = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
+	if (!ssi->soc_platform_pdev_fiq) {
+		ret = -ENOMEM;
+		goto failed_pdev_fiq_alloc;
+	}
+
+	platform_set_drvdata(ssi->soc_platform_pdev_fiq, ssi);
+	ret = platform_device_add(ssi->soc_platform_pdev_fiq);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add platform device\n");
+		goto failed_pdev_fiq_add;
+	}
+
+	ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", pdev->id);
+	if (!ssi->soc_platform_pdev) {
+		ret = -ENOMEM;
+		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:
+	platform_device_del(ssi->soc_platform_pdev_fiq);
+failed_pdev_fiq_add:
+	platform_device_put(ssi->soc_platform_pdev_fiq);
+failed_pdev_fiq_alloc:
+	snd_soc_unregister_dai(&pdev->dev);
+failed_register:
+failed_ac97:
+	iounmap(ssi->base);
+failed_ioremap:
+	release_mem_region(res->start, resource_size(res));
+failed_get_resource:
+	clk_disable(ssi->clk);
+	clk_put(ssi->clk);
+failed_clk:
+	kfree(ssi);
+
+	return ret;
+}
+
+static int __devexit imx_ssi_remove(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct imx_ssi *ssi = platform_get_drvdata(pdev);
+
+	platform_device_unregister(ssi->soc_platform_pdev);
+	platform_device_unregister(ssi->soc_platform_pdev_fiq);
+
+	snd_soc_unregister_dai(&pdev->dev);
+
+	if (ssi->flags & IMX_SSI_USE_AC97)
+		ac97_ssi = NULL;
+
+	iounmap(ssi->base);
+	release_mem_region(res->start, resource_size(res));
+	clk_disable(ssi->clk);
+	clk_put(ssi->clk);
+	kfree(ssi);
+
+	return 0;
+}
+
+static struct platform_driver imx_ssi_driver = {
+	.probe = imx_ssi_probe,
+	.remove = __devexit_p(imx_ssi_remove),
+
+	.driver = {
+		.name = "imx-ssi",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(imx_ssi_driver);
+
+/* Module information */
+MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-ssi");
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/fsl/imx-ssi.h
similarity index 100%
rename from sound/soc/imx/imx-ssi.h
rename to sound/soc/fsl/imx-ssi.h
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 3fea5a1..60bcba1 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -14,18 +14,16 @@
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
-#include <linux/of_i2c.h>
 #include <sound/soc.h>
 #include <asm/fsl_guts.h>
 
 #include "fsl_dma.h"
 #include "fsl_ssi.h"
+#include "fsl_utils.h"
 
 /* There's only one global utilities register */
 static phys_addr_t guts_phys;
 
-#define DAI_NAME_SIZE	32
-
 /**
  * mpc8610_hpcd_data: machine-specific ASoC device data
  *
@@ -43,7 +41,6 @@
 	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 */
 };
 
@@ -181,141 +178,6 @@
 };
 
 /**
- * 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)
-{
-	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 be32_to_cpup(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.0-004f".
- */
-static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
-{
-	const u32 *iprop;
-	int addr;
-	char temp[DAI_NAME_SIZE];
-	struct i2c_client *i2c;
-
-	of_modalias_node(np, temp, DAI_NAME_SIZE);
-
-	iprop = of_get_property(np, "reg", NULL);
-	if (!iprop)
-		return -EINVAL;
-
-	addr = be32_to_cpup(iprop);
-
-	/* We need the adapter number */
-	i2c = of_find_i2c_device_by_node(np);
-	if (!i2c)
-		return -ENODEV;
-
-	snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
-
-	return 0;
-}
-
-static int get_dma_channel(struct device_node *ssi_np,
-			   const char *name,
-			   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, name,
-						  "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 = be32_to_cpup(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
@@ -352,16 +214,8 @@
 	machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
 	machine_data->dai[0].ops = &mpc8610_hpcd_ops;
 
-	/* 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;
+	/* ASoC core can match codec with device node */
+	machine_data->dai[0].codec_of_node = codec_np;
 
 	/* The DAI name from the codec (snd_soc_dai_driver.name) */
 	machine_data->dai[0].codec_dai_name = "cs4270-hifi";
@@ -458,9 +312,10 @@
 
 	/* 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]);
+	ret = fsl_asoc_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(&pdev->dev, "missing/invalid playback DMA phandle\n");
 		goto error;
@@ -468,9 +323,10 @@
 
 	/* 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]);
+	ret = fsl_asoc_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;
diff --git a/sound/soc/imx/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c
similarity index 100%
rename from sound/soc/imx/mx27vis-aic32x4.c
rename to sound/soc/fsl/mx27vis-aic32x4.c
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 982a1c9..50adf40 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -14,12 +14,12 @@
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
-#include <linux/of_i2c.h>
 #include <sound/soc.h>
 #include <asm/fsl_guts.h>
 
 #include "fsl_dma.h"
 #include "fsl_ssi.h"
+#include "fsl_utils.h"
 
 /* P1022-specific PMUXCR and DMUXCR bit definitions */
 
@@ -57,8 +57,6 @@
 /* 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
  *
@@ -75,7 +73,6 @@
 	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 */
 };
 
@@ -191,136 +188,6 @@
 };
 
 /**
- * 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 = be32_to_cpup(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 addr;
-	char temp[DAI_NAME_SIZE];
-	struct i2c_client *i2c;
-
-	of_modalias_node(np, temp, DAI_NAME_SIZE);
-
-	iprop = of_get_property(np, "reg", NULL);
-	if (!iprop)
-		return -EINVAL;
-
-	addr = be32_to_cpup(iprop);
-
-	/* We need the adapter number */
-	i2c = of_find_i2c_device_by_node(np);
-	if (!i2c)
-		return -ENODEV;
-
-	snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
-
-	return 0;
-}
-
-static int get_dma_channel(struct device_node *ssi_np,
-			   const char *name,
-			   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, name,
-						  "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) {
-		of_node_put(dma_channel_np);
-		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 = be32_to_cpup(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
@@ -357,15 +224,8 @@
 	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;
+	/* ASoC core can match codec with device node */
+	mdata->dai[0].codec_of_node = codec_np;
 
 	/* We register two DAIs per SSI, one for playback and the other for
 	 * capture.  We support codecs that have separate DAIs for both playback
@@ -462,9 +322,9 @@
 
 	/* 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]);
+	ret = fsl_asoc_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;
@@ -472,9 +332,9 @@
 
 	/* 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]);
+	ret = fsl_asoc_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;
diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c
similarity index 100%
rename from sound/soc/imx/phycore-ac97.c
rename to sound/soc/fsl/phycore-ac97.c
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
similarity index 100%
rename from sound/soc/imx/wm1133-ev1.c
rename to sound/soc/fsl/wm1133-ev1.c
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
new file mode 100644
index 0000000..610f612
--- /dev/null
+++ b/sound/soc/generic/Kconfig
@@ -0,0 +1,4 @@
+config SND_SIMPLE_CARD
+	tristate "ASoC Simple sound card support"
+	help
+	  This option enables generic simple sound card support
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile
new file mode 100644
index 0000000..9c3b246
--- /dev/null
+++ b/sound/soc/generic/Makefile
@@ -0,0 +1,3 @@
+snd-soc-simple-card-objs	:= simple-card.o
+
+obj-$(CONFIG_SND_SIMPLE_CARD)	+= snd-soc-simple-card.o
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
new file mode 100644
index 0000000..b4b4cab
--- /dev/null
+++ b/sound/soc/generic/simple-card.c
@@ -0,0 +1,114 @@
+/*
+ * ASoC simple sound card support
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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/platform_device.h>
+#include <linux/module.h>
+#include <sound/simple_card.h>
+
+#define asoc_simple_get_card_info(p) \
+	container_of(p->dai_link, struct asoc_simple_card_info, snd_link)
+
+static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct asoc_simple_card_info *cinfo = asoc_simple_get_card_info(rtd);
+	struct asoc_simple_dai_init_info *iinfo = cinfo->init;
+	struct snd_soc_dai *codec = rtd->codec_dai;
+	struct snd_soc_dai *cpu = rtd->cpu_dai;
+	unsigned int cpu_daifmt = iinfo->fmt | iinfo->cpu_daifmt;
+	unsigned int codec_daifmt = iinfo->fmt | iinfo->codec_daifmt;
+	int ret;
+
+	if (codec_daifmt) {
+		ret = snd_soc_dai_set_fmt(codec, codec_daifmt);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (iinfo->sysclk) {
+		ret = snd_soc_dai_set_sysclk(codec, 0, iinfo->sysclk, 0);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (cpu_daifmt) {
+		ret = snd_soc_dai_set_fmt(cpu, cpu_daifmt);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int asoc_simple_card_probe(struct platform_device *pdev)
+{
+	struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
+
+	if (!cinfo) {
+		dev_err(&pdev->dev, "no info for asoc-simple-card\n");
+		return -EINVAL;
+	}
+
+	if (!cinfo->name	||
+	    !cinfo->card	||
+	    !cinfo->cpu_dai	||
+	    !cinfo->codec	||
+	    !cinfo->platform	||
+	    !cinfo->codec_dai) {
+		dev_err(&pdev->dev, "insufficient asoc_simple_card_info settings\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * init snd_soc_dai_link
+	 */
+	cinfo->snd_link.name		= cinfo->name;
+	cinfo->snd_link.stream_name	= cinfo->name;
+	cinfo->snd_link.cpu_dai_name	= cinfo->cpu_dai;
+	cinfo->snd_link.platform_name	= cinfo->platform;
+	cinfo->snd_link.codec_name	= cinfo->codec;
+	cinfo->snd_link.codec_dai_name	= cinfo->codec_dai;
+
+	/* enable snd_link.init if cinfo has settings */
+	if (cinfo->init)
+		cinfo->snd_link.init	= asoc_simple_card_dai_init;
+
+	/*
+	 * init snd_soc_card
+	 */
+	cinfo->snd_card.name		= cinfo->card;
+	cinfo->snd_card.owner		= THIS_MODULE;
+	cinfo->snd_card.dai_link	= &cinfo->snd_link;
+	cinfo->snd_card.num_links	= 1;
+	cinfo->snd_card.dev		= &pdev->dev;
+
+	return snd_soc_register_card(&cinfo->snd_card);
+}
+
+static int asoc_simple_card_remove(struct platform_device *pdev)
+{
+	struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
+
+	return snd_soc_unregister_card(&cinfo->snd_card);
+}
+
+static struct platform_driver asoc_simple_card = {
+	.driver = {
+		.name	= "asoc-simple-card",
+	},
+	.probe		= asoc_simple_card_probe,
+	.remove		= asoc_simple_card_remove,
+};
+
+module_platform_driver(asoc_simple_card);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ASoC Simple Sound Card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
deleted file mode 100644
index 810acaa..0000000
--- a/sound/soc/imx/Kconfig
+++ /dev/null
@@ -1,79 +0,0 @@
-menuconfig SND_IMX_SOC
-	tristate "SoC Audio for Freescale i.MX CPUs"
-	depends on ARCH_MXC
-	help
-	  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_SOC_IMX_SSI
-	tristate
-
-config SND_SOC_IMX_PCM
-	tristate
-
-config SND_MXC_SOC_FIQ
-	tristate
-	select FIQ
-	select SND_SOC_IMX_PCM
-
-config SND_MXC_SOC_MX2
-	select SND_SOC_DMAENGINE_PCM
-	tristate
-	select SND_SOC_IMX_PCM
-
-config SND_SOC_IMX_AUDMUX
-	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_FIQ
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Enable support for audio on the i.MX31ADS with the WM1133-EV1
-	  PMIC board with WM8835x fitted.
-
-config SND_SOC_MX27VIS_AIC32X4
-	tristate "SoC audio support for Visstrim M10 boards"
-	depends on MACH_IMX27_VISSTRIM_M10 && I2C
-	select SND_SOC_TLV320AIC32X4
-	select SND_MXC_SOC_MX2
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Say Y if you want to add support for SoC audio on Visstrim SM10
-	  board with TLV320AIC32X4 codec.
-
-config SND_SOC_PHYCORE_AC97
-	tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
-	depends on MACH_PCM043 || MACH_PCA100
-	select SND_SOC_AC97_BUS
-	select SND_SOC_WM9712
-	select SND_MXC_SOC_FIQ
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Say Y if you want to add support for SoC audio on Phytec phyCORE
-	  and phyCARD boards in AC97 mode
-
-config SND_SOC_EUKREA_TLV320
-	tristate "Eukrea TLV320"
-	depends on MACH_EUKREA_MBIMX27_BASEBOARD \
-		|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
-		|| MACH_EUKREA_MBIMXSD35_BASEBOARD \
-		|| MACH_EUKREA_MBIMXSD51_BASEBOARD
-	depends on I2C
-	select SND_SOC_TLV320AIC23
-	select SND_MXC_SOC_FIQ
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Enable I2S based access to the TLV320AIC23B codec attached
-	  to the SSI interface
-
-endif	# SND_IMX_SOC
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
deleted file mode 100644
index f5db3e9..0000000
--- a/sound/soc/imx/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-# i.MX Platform Support
-snd-soc-imx-ssi-objs := imx-ssi.o
-snd-soc-imx-audmux-objs := imx-audmux.o
-
-obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
-obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
-
-obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
-snd-soc-imx-pcm-y := imx-pcm.o
-snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_FIQ) += imx-pcm-fiq.o
-snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_MX2) += imx-pcm-dma-mx2.o
-
-# i.MX Machine Support
-snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
-snd-soc-phycore-ac97-objs := phycore-ac97.o
-snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
-snd-soc-wm1133-ev1-objs := wm1133-ev1.o
-
-obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
-obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
-obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
-obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c
deleted file mode 100644
index 7d4475c..0000000
--- a/sound/soc/imx/eukrea-tlv320.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * eukrea-tlv320.c  --  SoC audio for eukrea_cpuimxXX in I2S mode
- *
- * Copyright 2010 Eric Bénard, Eukréa Electromatique <eric@eukrea.com>
- *
- * based on sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
- * which is Copyright 2009 Simtec Electronics
- * and on sound/soc/imx/phycore-ac97.c which is
- * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- * 
- *  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/device.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/mach-types.h>
-
-#include "../codecs/tlv320aic23.h"
-#include "imx-ssi.h"
-#include "imx-audmux.h"
-
-#define CODEC_CLOCK 12000000
-
-static int eukrea_tlv320_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 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) {
-		pr_err("%s: failed set cpu dai format\n", __func__);
-		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) {
-		pr_err("%s: failed set codec dai format\n", __func__);
-		return ret;
-	}
-
-	ret = snd_soc_dai_set_sysclk(codec_dai, 0,
-				     CODEC_CLOCK, SND_SOC_CLOCK_OUT);
-	if (ret) {
-		pr_err("%s: failed setting codec sysclk\n", __func__);
-		return ret;
-	}
-	snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
-
-	ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
-				SND_SOC_CLOCK_IN);
-	if (ret) {
-		pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static struct snd_soc_ops eukrea_tlv320_snd_ops = {
-	.hw_params	= eukrea_tlv320_hw_params,
-};
-
-static struct snd_soc_dai_link eukrea_tlv320_dai = {
-	.name		= "tlv320aic23",
-	.stream_name	= "TLV320AIC23",
-	.codec_dai_name	= "tlv320aic23-hifi",
-	.platform_name	= "imx-fiq-pcm-audio.0",
-	.codec_name	= "tlv320aic23-codec.0-001a",
-	.cpu_dai_name	= "imx-ssi.0",
-	.ops		= &eukrea_tlv320_snd_ops,
-};
-
-static struct snd_soc_card eukrea_tlv320 = {
-	.name		= "cpuimx-audio",
-	.owner		= THIS_MODULE,
-	.dai_link	= &eukrea_tlv320_dai,
-	.num_links	= 1,
-};
-
-static struct platform_device *eukrea_tlv320_snd_device;
-
-static int __init eukrea_tlv320_init(void)
-{
-	int ret;
-	int int_port = 0, ext_port;
-
-	if (machine_is_eukrea_cpuimx27()) {
-		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-			IMX_AUDMUX_V1_PCR_SYN |
-			IMX_AUDMUX_V1_PCR_TFSDIR |
-			IMX_AUDMUX_V1_PCR_TCLKDIR |
-			IMX_AUDMUX_V1_PCR_RFSDIR |
-			IMX_AUDMUX_V1_PCR_RCLKDIR |
-			IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
-			IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
-			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
-		);
-		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
-			IMX_AUDMUX_V1_PCR_SYN |
-			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
-		);
-	} else if (machine_is_eukrea_cpuimx25sd() ||
-		   machine_is_eukrea_cpuimx35sd() ||
-		   machine_is_eukrea_cpuimx51sd()) {
-		ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3;
-		imx_audmux_v2_configure_port(int_port,
-			IMX_AUDMUX_V2_PTCR_SYN |
-			IMX_AUDMUX_V2_PTCR_TFSDIR |
-			IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
-			IMX_AUDMUX_V2_PTCR_TCLKDIR |
-			IMX_AUDMUX_V2_PTCR_TCSEL(ext_port),
-			IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)
-		);
-		imx_audmux_v2_configure_port(ext_port,
-			IMX_AUDMUX_V2_PTCR_SYN,
-			IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)
-		);
-	} else {
-		/* return happy. We might run on a totally different machine */
-		return 0;
-	}
-
-	eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!eukrea_tlv320_snd_device)
-		return -ENOMEM;
-
-	platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320);
-	ret = platform_device_add(eukrea_tlv320_snd_device);
-
-	if (ret) {
-		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-		platform_device_put(eukrea_tlv320_snd_device);
-	}
-
-	return ret;
-}
-
-static void __exit eukrea_tlv320_exit(void)
-{
-	platform_device_unregister(eukrea_tlv320_snd_device);
-}
-
-module_init(eukrea_tlv320_init);
-module_exit(eukrea_tlv320_exit);
-
-MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");
-MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
deleted file mode 100644
index 6b818de..0000000
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * imx-pcm-dma-mx2.c  --  ALSA Soc Audio Layer
- *
- * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This code is based on code copyrighted by Freescale,
- * Liam Girdwood, Javier Martin and probably others.
- *
- *  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/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dmaengine.h>
-#include <linux/types.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-#include <mach/dma.h>
-
-#include "imx-pcm.h"
-
-static bool filter(struct dma_chan *chan, void *param)
-{
-	if (!imx_dma_is_general_purpose(chan))
-		return false;
-
-	chan->private = param;
-
-	return true;
-}
-
-static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
-	struct imx_pcm_dma_params *dma_params;
-	struct dma_slave_config slave_config;
-	int ret;
-
-	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
-	if (ret)
-		return ret;
-
-	slave_config.device_fc = false;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		slave_config.dst_addr = dma_params->dma_addr;
-		slave_config.dst_maxburst = dma_params->burstsize;
-	} else {
-		slave_config.src_addr = dma_params->dma_addr;
-		slave_config.src_maxburst = dma_params->burstsize;
-	}
-
-	ret = dmaengine_slave_config(chan, &slave_config);
-	if (ret)
-		return ret;
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-	return 0;
-}
-
-static struct snd_pcm_hardware snd_imx_hardware = {
-	.info = SNDRV_PCM_INFO_INTERLEAVED |
-		SNDRV_PCM_INFO_BLOCK_TRANSFER |
-		SNDRV_PCM_INFO_MMAP |
-		SNDRV_PCM_INFO_MMAP_VALID |
-		SNDRV_PCM_INFO_PAUSE |
-		SNDRV_PCM_INFO_RESUME,
-	.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	.rate_min = 8000,
-	.channels_min = 2,
-	.channels_max = 2,
-	.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
-	.period_bytes_min = 128,
-	.period_bytes_max = 65535, /* Limited by SDMA engine */
-	.periods_min = 2,
-	.periods_max = 255,
-	.fifo_size = 0,
-};
-
-static int snd_imx_open(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct imx_pcm_dma_params *dma_params;
-	struct imx_dma_data *dma_data;
-	int ret;
-
-	snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
-
-	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
-	dma_data->peripheral_type = IMX_DMATYPE_SSI;
-	dma_data->priority = DMA_PRIO_HIGH;
-	dma_data->dma_request = dma_params->dma;
-
-	ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
-	if (ret) {
-		kfree(dma_data);
-		return 0;
-	}
-
-	snd_dmaengine_pcm_set_data(substream, dma_data);
-
-	return 0;
-}
-
-static int snd_imx_close(struct snd_pcm_substream *substream)
-{
-	struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
-
-	snd_dmaengine_pcm_close(substream);
-	kfree(dma_data);
-
-	return 0;
-}
-
-static struct snd_pcm_ops imx_pcm_ops = {
-	.open		= snd_imx_open,
-	.close		= snd_imx_close,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= snd_imx_pcm_hw_params,
-	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= snd_dmaengine_pcm_pointer,
-	.mmap		= snd_imx_pcm_mmap,
-};
-
-static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
-	.ops		= &imx_pcm_ops,
-	.pcm_new	= imx_pcm_new,
-	.pcm_free	= imx_pcm_free,
-};
-
-static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
-{
-	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),
-};
-
-module_platform_driver(imx_pcm_driver);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-pcm-audio");
diff --git a/sound/soc/imx/imx-pcm.h b/sound/soc/imx/imx-pcm.h
deleted file mode 100644
index b5f5c3a..0000000
--- a/sound/soc/imx/imx-pcm.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This code is based on code copyrighted by Freescale,
- * Liam Girdwood, Javier Martin and probably others.
- *
- * 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 _IMX_PCM_H
-#define _IMX_PCM_H
-
-/*
- * Do not change this as the FIQ handler depends on this size
- */
-#define IMX_SSI_DMABUF_SIZE	(64 * 1024)
-
-struct imx_pcm_dma_params {
-	int dma;
-	unsigned long dma_addr;
-	int burstsize;
-};
-
-int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
-		     struct vm_area_struct *vma);
-int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
-void imx_pcm_free(struct snd_pcm *pcm);
-
-#endif /* _IMX_PCM_H */
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
deleted file mode 100644
index 4f81ed4..0000000
--- a/sound/soc/imx/imx-ssi.c
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- * imx-ssi.c  --  ALSA Soc Audio Layer
- *
- * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This code is based on code copyrighted by Freescale,
- * Liam Girdwood, Javier Martin and probably others.
- *
- *  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.
- *
- *
- * The i.MX SSI core has some nasty limitations in AC97 mode. While most
- * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
- * one FIFO which combines all valid receive slots. We cannot even select
- * which slots we want to receive. The WM9712 with which this driver
- * was developed with always sends GPIO status data in slot 12 which
- * we receive in our (PCM-) data stream. The only chance we have is to
- * manually skip this data in the FIQ handler. With sampling rates different
- * from 48000Hz not every frame has valid receive data, so the ratio
- * between pcm data and GPIO status data changes. Our FIQ handler is not
- * able to handle this, hence this driver only works with 48000Hz sampling
- * rate.
- * Reading and writing AC97 registers is another challenge. The core
- * provides us status bits when the read register is updated with *another*
- * value. When we read the same register two times (and the register still
- * contains the same value) these status bits are not set. We work
- * around this by not polling these bits but only wait a fixed delay.
- * 
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <mach/ssi.h>
-#include <mach/hardware.h>
-
-#include "imx-ssi.h"
-
-#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
-
-/*
- * SSI Network Mode or TDM slots configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-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 = snd_soc_dai_get_drvdata(cpu_dai);
-	u32 sccr;
-
-	sccr = readl(ssi->base + SSI_STCCR);
-	sccr &= ~SSI_STCCR_DC_MASK;
-	sccr |= SSI_STCCR_DC(slots - 1);
-	writel(sccr, ssi->base + SSI_STCCR);
-
-	sccr = readl(ssi->base + SSI_SRCCR);
-	sccr &= ~SSI_STCCR_DC_MASK;
-	sccr |= SSI_STCCR_DC(slots - 1);
-	writel(sccr, ssi->base + SSI_SRCCR);
-
-	writel(tx_mask, ssi->base + SSI_STMSK);
-	writel(rx_mask, ssi->base + SSI_SRMSK);
-
-	return 0;
-}
-
-/*
- * SSI DAI format configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
-{
-	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);
-
-	/* DAI mode */
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-		/* data on rising edge of bclk, frame low 1clk before data */
-		strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
-		scr |= SSI_SCR_NET;
-		if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
-			scr &= ~SSI_I2S_MODE_MASK;
-			scr |= SSI_SCR_I2S_MODE_SLAVE;
-		}
-		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		/* data on rising edge of bclk, frame high with data */
-		strcr |= SSI_STCR_TXBIT0;
-		break;
-	case SND_SOC_DAIFMT_DSP_B:
-		/* data on rising edge of bclk, frame high with data */
-		strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0;
-		break;
-	case SND_SOC_DAIFMT_DSP_A:
-		/* data on rising edge of bclk, frame high 1clk before data */
-		strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
-		break;
-	}
-
-	/* DAI clock inversion */
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_IB_IF:
-		strcr |= SSI_STCR_TFSI;
-		strcr &= ~SSI_STCR_TSCKP;
-		break;
-	case SND_SOC_DAIFMT_IB_NF:
-		strcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
-		break;
-	case SND_SOC_DAIFMT_NB_IF:
-		strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
-		break;
-	case SND_SOC_DAIFMT_NB_NF:
-		strcr &= ~SSI_STCR_TFSI;
-		strcr |= SSI_STCR_TSCKP;
-		break;
-	}
-
-	/* DAI clock master masks */
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBM_CFM:
-		break;
-	default:
-		/* Master mode not implemented, needs handling of clocks. */
-		return -EINVAL;
-	}
-
-	strcr |= SSI_STCR_TFEN0;
-
-	if (ssi->flags & IMX_SSI_NET)
-		scr |= SSI_SCR_NET;
-	if (ssi->flags & IMX_SSI_SYN)
-		scr |= SSI_SCR_SYN;
-
-	writel(strcr, ssi->base + SSI_STCR);
-	writel(strcr, ssi->base + SSI_SRCR);
-	writel(scr, ssi->base + SSI_SCR);
-
-	return 0;
-}
-
-/*
- * SSI system clock configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-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 = snd_soc_dai_get_drvdata(cpu_dai);
-	u32 scr;
-
-	scr = readl(ssi->base + SSI_SCR);
-
-	switch (clk_id) {
-	case IMX_SSP_SYS_CLK:
-		if (dir == SND_SOC_CLOCK_OUT)
-			scr |= SSI_SCR_SYS_CLK_EN;
-		else
-			scr &= ~SSI_SCR_SYS_CLK_EN;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	writel(scr, ssi->base + SSI_SCR);
-
-	return 0;
-}
-
-/*
- * SSI Clock dividers
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-				  int div_id, int div)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	u32 stccr, srccr;
-
-	stccr = readl(ssi->base + SSI_STCCR);
-	srccr = readl(ssi->base + SSI_SRCCR);
-
-	switch (div_id) {
-	case IMX_SSI_TX_DIV_2:
-		stccr &= ~SSI_STCCR_DIV2;
-		stccr |= div;
-		break;
-	case IMX_SSI_TX_DIV_PSR:
-		stccr &= ~SSI_STCCR_PSR;
-		stccr |= div;
-		break;
-	case IMX_SSI_TX_DIV_PM:
-		stccr &= ~0xff;
-		stccr |= SSI_STCCR_PM(div);
-		break;
-	case IMX_SSI_RX_DIV_2:
-		stccr &= ~SSI_STCCR_DIV2;
-		stccr |= div;
-		break;
-	case IMX_SSI_RX_DIV_PSR:
-		stccr &= ~SSI_STCCR_PSR;
-		stccr |= div;
-		break;
-	case IMX_SSI_RX_DIV_PM:
-		stccr &= ~0xff;
-		stccr |= SSI_STCCR_PM(div);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	writel(stccr, ssi->base + SSI_STCCR);
-	writel(srccr, ssi->base + SSI_SRCCR);
-
-	return 0;
-}
-
-static int imx_ssi_startup(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *cpu_dai)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	struct imx_pcm_dma_params *dma_data;
-
-	/* Tx/Rx config */
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		dma_data = &ssi->dma_params_tx;
-	else
-		dma_data = &ssi->dma_params_rx;
-
-	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
-	return 0;
-}
-
-/*
- * Should only be called when port is inactive (i.e. SSIEN = 0),
- * although can be called multiple times by upper layers.
- */
-static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
-			     struct snd_pcm_hw_params *params,
-			     struct snd_soc_dai *cpu_dai)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	u32 reg, sccr;
-
-	/* Tx/Rx config */
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		reg = SSI_STCCR;
-	else
-		reg = SSI_SRCCR;
-
-	if (ssi->flags & IMX_SSI_SYN)
-		reg = SSI_STCCR;
-
-	sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
-
-	/* DAI data (word) size */
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		sccr |= SSI_SRCCR_WL(16);
-		break;
-	case SNDRV_PCM_FORMAT_S20_3LE:
-		sccr |= SSI_SRCCR_WL(20);
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		sccr |= SSI_SRCCR_WL(24);
-		break;
-	}
-
-	writel(sccr, ssi->base + reg);
-
-	return 0;
-}
-
-static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
-		struct snd_soc_dai *dai)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
-	unsigned int sier_bits, sier;
-	unsigned int scr;
-
-	scr = readl(ssi->base + SSI_SCR);
-	sier = readl(ssi->base + SSI_SIER);
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if (ssi->flags & IMX_SSI_DMA)
-			sier_bits = SSI_SIER_TDMAE;
-		else
-			sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
-	} else {
-		if (ssi->flags & IMX_SSI_DMA)
-			sier_bits = SSI_SIER_RDMAE;
-		else
-			sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
-	}
-
-	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)
-			scr |= SSI_SCR_TE;
-		else
-			scr |= SSI_SCR_RE;
-		sier |= sier_bits;
-
-		if (++ssi->enabled == 1)
-			scr |= SSI_SCR_SSIEN;
-
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			scr &= ~SSI_SCR_TE;
-		else
-			scr &= ~SSI_SCR_RE;
-		sier &= ~sier_bits;
-
-		if (--ssi->enabled == 0)
-			scr &= ~SSI_SCR_SSIEN;
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (!(ssi->flags & IMX_SSI_USE_AC97))
-		/* rx/tx are always enabled to access ac97 registers */
-		writel(scr, ssi->base + SSI_SCR);
-
-	writel(sier, ssi->base + SSI_SIER);
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
-	.startup	= imx_ssi_startup,
-	.hw_params	= imx_ssi_hw_params,
-	.set_fmt	= imx_ssi_set_dai_fmt,
-	.set_clkdiv	= imx_ssi_set_dai_clkdiv,
-	.set_sysclk	= imx_ssi_set_dai_sysclk,
-	.set_tdm_slot	= imx_ssi_set_dai_tdm_slot,
-	.trigger	= imx_ssi_trigger,
-};
-
-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_ssi_dai = {
-	.probe = imx_ssi_dai_probe,
-	.playback = {
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_96000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_96000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = &imx_ssi_pcm_dai_ops,
-};
-
-static struct snd_soc_dai_driver imx_ac97_dai = {
-	.probe = imx_ssi_dai_probe,
-	.ac97_control = 1,
-	.playback = {
-		.stream_name = "AC97 Playback",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		.stream_name = "AC97 Capture",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = &imx_ssi_pcm_dai_ops,
-};
-
-static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
-{
-	void __iomem *base = imx_ssi->base;
-
-	writel(0x0, base + SSI_SCR);
-	writel(0x0, base + SSI_STCR);
-	writel(0x0, base + SSI_SRCR);
-
-	writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
-
-	writel(SSI_SFCSR_RFWM0(8) |
-		SSI_SFCSR_TFWM0(8) |
-		SSI_SFCSR_RFWM1(8) |
-		SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
-
-	writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
-	writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
-
-	writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
-	writel(SSI_SOR_WAIT(3), base + SSI_SOR);
-
-	writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
-			SSI_SCR_TE | SSI_SCR_RE,
-			base + SSI_SCR);
-
-	writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
-	writel(0xff, base + SSI_SACCDIS);
-	writel(0x300, base + SSI_SACCEN);
-}
-
-static struct imx_ssi *ac97_ssi;
-
-static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-		unsigned short val)
-{
-	struct imx_ssi *imx_ssi = ac97_ssi;
-	void __iomem *base = imx_ssi->base;
-	unsigned int lreg;
-	unsigned int lval;
-
-	if (reg > 0x7f)
-		return;
-
-	pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
-
-	lreg = reg <<  12;
-	writel(lreg, base + SSI_SACADD);
-
-	lval = val << 4;
-	writel(lval , base + SSI_SACDAT);
-
-	writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
-	udelay(100);
-}
-
-static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
-		unsigned short reg)
-{
-	struct imx_ssi *imx_ssi = ac97_ssi;
-	void __iomem *base = imx_ssi->base;
-
-	unsigned short val = -1;
-	unsigned int lreg;
-
-	lreg = (reg & 0x7f) <<  12 ;
-	writel(lreg, base + SSI_SACADD);
-	writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
-
-	udelay(100);
-
-	val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
-
-	pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
-
-	return val;
-}
-
-static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
-{
-	struct imx_ssi *imx_ssi = ac97_ssi;
-
-	if (imx_ssi->ac97_reset)
-		imx_ssi->ac97_reset(ac97);
-}
-
-static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
-{
-	struct imx_ssi *imx_ssi = ac97_ssi;
-
-	if (imx_ssi->ac97_warm_reset)
-		imx_ssi->ac97_warm_reset(ac97);
-}
-
-struct snd_ac97_bus_ops soc_ac97_ops = {
-	.read		= imx_ssi_ac97_read,
-	.write		= imx_ssi_ac97_write,
-	.reset		= imx_ssi_ac97_reset,
-	.warm_reset	= imx_ssi_ac97_warm_reset
-};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
-
-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;
-	int ret = 0;
-	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;
-		ssi->ac97_warm_reset = pdata->ac97_warm_reset;
-		ssi->flags = pdata->flags;
-	}
-
-	ssi->irq = platform_get_irq(pdev, 0);
-
-	ssi->clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(ssi->clk)) {
-		ret = PTR_ERR(ssi->clk);
-		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
-			ret);
-		goto failed_clk;
-	}
-	clk_enable(ssi->clk);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -ENODEV;
-		goto failed_get_resource;
-	}
-
-	if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
-		dev_err(&pdev->dev, "request_mem_region failed\n");
-		ret = -EBUSY;
-		goto failed_get_resource;
-	}
-
-	ssi->base = ioremap(res->start, resource_size(res));
-	if (!ssi->base) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENODEV;
-		goto failed_ioremap;
-	}
-
-	if (ssi->flags & IMX_SSI_USE_AC97) {
-		if (ac97_ssi) {
-			ret = -EBUSY;
-			goto failed_ac97;
-		}
-		ac97_ssi = ssi;
-		setup_channel_to_ac97(ssi);
-		dai = &imx_ac97_dai;
-	} else
-		dai = &imx_ssi_dai;
-
-	writel(0x0, ssi->base + SSI_SIER);
-
-	ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
-	ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
-
-	ssi->dma_params_tx.burstsize = 6;
-	ssi->dma_params_rx.burstsize = 4;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
-	if (res)
-		ssi->dma_params_tx.dma = res->start;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
-	if (res)
-		ssi->dma_params_rx.dma = res->start;
-
-	platform_set_drvdata(pdev, ssi);
-
-	ret = snd_soc_register_dai(&pdev->dev, dai);
-	if (ret) {
-		dev_err(&pdev->dev, "register DAI failed\n");
-		goto failed_register;
-	}
-
-	ssi->soc_platform_pdev_fiq = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
-	if (!ssi->soc_platform_pdev_fiq) {
-		ret = -ENOMEM;
-		goto failed_pdev_fiq_alloc;
-	}
-
-	platform_set_drvdata(ssi->soc_platform_pdev_fiq, ssi);
-	ret = platform_device_add(ssi->soc_platform_pdev_fiq);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to add platform device\n");
-		goto failed_pdev_fiq_add;
-	}
-
-	ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", pdev->id);
-	if (!ssi->soc_platform_pdev) {
-		ret = -ENOMEM;
-		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:
-	platform_device_del(ssi->soc_platform_pdev_fiq);
-failed_pdev_fiq_add:
-	platform_device_put(ssi->soc_platform_pdev_fiq);
-failed_pdev_fiq_alloc:
-	snd_soc_unregister_dai(&pdev->dev);
-failed_register:
-failed_ac97:
-	iounmap(ssi->base);
-failed_ioremap:
-	release_mem_region(res->start, resource_size(res));
-failed_get_resource:
-	clk_disable(ssi->clk);
-	clk_put(ssi->clk);
-failed_clk:
-	kfree(ssi);
-
-	return ret;
-}
-
-static int __devexit imx_ssi_remove(struct platform_device *pdev)
-{
-	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	struct imx_ssi *ssi = platform_get_drvdata(pdev);
-
-	platform_device_unregister(ssi->soc_platform_pdev);
-	platform_device_unregister(ssi->soc_platform_pdev_fiq);
-
-	snd_soc_unregister_dai(&pdev->dev);
-
-	if (ssi->flags & IMX_SSI_USE_AC97)
-		ac97_ssi = NULL;
-
-	iounmap(ssi->base);
-	release_mem_region(res->start, resource_size(res));
-	clk_disable(ssi->clk);
-	clk_put(ssi->clk);
-	kfree(ssi);
-
-	return 0;
-}
-
-static struct platform_driver imx_ssi_driver = {
-	.probe = imx_ssi_probe,
-	.remove = __devexit_p(imx_ssi_remove),
-
-	.driver = {
-		.name = "imx-ssi",
-		.owner = THIS_MODULE,
-	},
-};
-
-module_platform_driver(imx_ssi_driver);
-
-/* Module information */
-MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-ssi");
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index a5af7c4..41349670 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -346,7 +346,7 @@
 
 	/* Playback */
 	dma_config = &i2s->pcm_config_playback.dma_config;
-	dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
+	dma_config->src_width = JZ4740_DMA_WIDTH_32BIT;
 	dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
 	dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
 	dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
@@ -355,7 +355,7 @@
 
 	/* Capture */
 	dma_config = &i2s->pcm_config_capture.dma_config;
-	dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
+	dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT;
 	dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
 	dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
 	dma_config->flags = JZ4740_DMA_DST_AUTOINC;
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index e373fbb..373dec9 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -220,28 +220,16 @@
 	.pcm_free	= mxs_pcm_free,
 };
 
-static int __devinit mxs_soc_platform_probe(struct platform_device *pdev)
+int __devinit mxs_pcm_platform_register(struct device *dev)
 {
-	return snd_soc_register_platform(&pdev->dev, &mxs_soc_platform);
+	return snd_soc_register_platform(dev, &mxs_soc_platform);
 }
+EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
 
-static int __devexit mxs_soc_platform_remove(struct platform_device *pdev)
+void __devexit mxs_pcm_platform_unregister(struct device *dev)
 {
-	snd_soc_unregister_platform(&pdev->dev);
-
-	return 0;
+	snd_soc_unregister_platform(dev);
 }
-
-static struct platform_driver mxs_pcm_driver = {
-	.driver = {
-		.name = "mxs-pcm-audio",
-		.owner = THIS_MODULE,
-	},
-	.probe = mxs_soc_platform_probe,
-	.remove = __devexit_p(mxs_soc_platform_remove),
-};
-
-module_platform_driver(mxs_pcm_driver);
+EXPORT_SYMBOL_GPL(mxs_pcm_platform_unregister);
 
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mxs-pcm-audio");
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
index 5f01a91..35ba2ca 100644
--- a/sound/soc/mxs/mxs-pcm.h
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -24,4 +24,7 @@
 	int chan_num;
 };
 
+int mxs_pcm_platform_register(struct device *dev);
+void mxs_pcm_platform_unregister(struct device *dev);
+
 #endif
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 53f4fd8..aba71bf 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -18,6 +18,8 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
@@ -25,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/fsl/mxs-dma.h>
+#include <linux/pinctrl/consumer.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -620,34 +623,61 @@
 	return IRQ_HANDLED;
 }
 
-static int mxs_saif_probe(struct platform_device *pdev)
+static int __devinit mxs_saif_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct resource *iores, *dmares;
 	struct mxs_saif *saif;
 	struct mxs_saif_platform_data *pdata;
+	struct pinctrl *pinctrl;
 	int ret = 0;
 
-	if (pdev->id >= ARRAY_SIZE(mxs_saif))
+
+	if (!np && pdev->id >= ARRAY_SIZE(mxs_saif))
 		return -EINVAL;
 
 	saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL);
 	if (!saif)
 		return -ENOMEM;
 
-	mxs_saif[pdev->id] = saif;
-	saif->id = pdev->id;
-
-	pdata = pdev->dev.platform_data;
-	if (pdata && !pdata->master_mode) {
-		saif->master_id = pdata->master_id;
-		if (saif->master_id < 0 ||
-			saif->master_id >= ARRAY_SIZE(mxs_saif) ||
-			saif->master_id == saif->id) {
-			dev_err(&pdev->dev, "get wrong master id\n");
-			return -EINVAL;
+	if (np) {
+		struct device_node *master;
+		saif->id = of_alias_get_id(np, "saif");
+		if (saif->id < 0)
+			return saif->id;
+		/*
+		 * If there is no "fsl,saif-master" phandle, it's a saif
+		 * master.  Otherwise, it's a slave and its phandle points
+		 * to the master.
+		 */
+		master = of_parse_phandle(np, "fsl,saif-master", 0);
+		if (!master) {
+			saif->master_id = saif->id;
+		} else {
+			saif->master_id = of_alias_get_id(master, "saif");
+			if (saif->master_id < 0)
+				return saif->master_id;
 		}
 	} else {
-		saif->master_id = saif->id;
+		saif->id = pdev->id;
+		pdata = pdev->dev.platform_data;
+		if (pdata && !pdata->master_mode)
+			saif->master_id = pdata->master_id;
+		else
+			saif->master_id = saif->id;
+	}
+
+	if (saif->master_id < 0 || saif->master_id >= ARRAY_SIZE(mxs_saif)) {
+		dev_err(&pdev->dev, "get wrong master id\n");
+		return -EINVAL;
+	}
+
+	mxs_saif[saif->id] = saif;
+
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		ret = PTR_ERR(pinctrl);
+		return ret;
 	}
 
 	saif->clk = clk_get(&pdev->dev, NULL);
@@ -669,12 +699,19 @@
 
 	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
 	if (!dmares) {
-		ret = -ENODEV;
-		dev_err(&pdev->dev, "failed to get dma resource: %d\n",
-			ret);
-		goto failed_get_resource;
+		/*
+		 * TODO: This is a temporary solution and should be changed
+		 * to use generic DMA binding later when the helplers get in.
+		 */
+		ret = of_property_read_u32(np, "fsl,saif-dma-channel",
+					   &saif->dma_param.chan_num);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to get dma channel\n");
+			goto failed_get_resource;
+		}
+	} else {
+		saif->dma_param.chan_num = dmares->start;
 	}
-	saif->dma_param.chan_num = dmares->start;
 
 	saif->irq = platform_get_irq(pdev, 0);
 	if (saif->irq < 0) {
@@ -708,24 +745,14 @@
 		goto failed_get_resource;
 	}
 
-	saif->soc_platform_pdev = platform_device_alloc(
-					"mxs-pcm-audio", pdev->id);
-	if (!saif->soc_platform_pdev) {
-		ret = -ENOMEM;
-		goto failed_pdev_alloc;
-	}
-
-	platform_set_drvdata(saif->soc_platform_pdev, saif);
-	ret = platform_device_add(saif->soc_platform_pdev);
+	ret = mxs_pcm_platform_register(&pdev->dev);
 	if (ret) {
-		dev_err(&pdev->dev, "failed to add soc platform device\n");
-		goto failed_pdev_add;
+		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+		goto failed_pdev_alloc;
 	}
 
 	return 0;
 
-failed_pdev_add:
-	platform_device_put(saif->soc_platform_pdev);
 failed_pdev_alloc:
 	snd_soc_unregister_dai(&pdev->dev);
 failed_get_resource:
@@ -738,13 +765,19 @@
 {
 	struct mxs_saif *saif = platform_get_drvdata(pdev);
 
-	platform_device_unregister(saif->soc_platform_pdev);
+	mxs_pcm_platform_unregister(&pdev->dev);
 	snd_soc_unregister_dai(&pdev->dev);
 	clk_put(saif->clk);
 
 	return 0;
 }
 
+static const struct of_device_id mxs_saif_dt_ids[] = {
+	{ .compatible = "fsl,imx28-saif", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_saif_dt_ids);
+
 static struct platform_driver mxs_saif_driver = {
 	.probe = mxs_saif_probe,
 	.remove = __devexit_p(mxs_saif_remove),
@@ -752,6 +785,7 @@
 	.driver = {
 		.name = "mxs-saif",
 		.owner = THIS_MODULE,
+		.of_match_table = mxs_saif_dt_ids,
 	},
 };
 
diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
index 12c91e4..3cb342e 100644
--- a/sound/soc/mxs/mxs-saif.h
+++ b/sound/soc/mxs/mxs-saif.h
@@ -123,7 +123,6 @@
 	unsigned int cur_rate;
 	unsigned int ongoing;
 
-	struct platform_device *soc_platform_pdev;
 	u32 fifo_underrun;
 	u32 fifo_overrun;
 };
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 60f052b..3e6e876 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -18,6 +18,8 @@
 
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
@@ -90,7 +92,7 @@
 		.codec_dai_name	= "sgtl5000",
 		.codec_name	= "sgtl5000.0-000a",
 		.cpu_dai_name	= "mxs-saif.0",
-		.platform_name	= "mxs-pcm-audio.0",
+		.platform_name	= "mxs-saif.0",
 		.ops		= &mxs_sgtl5000_hifi_ops,
 	}, {
 		.name		= "HiFi Rx",
@@ -98,7 +100,7 @@
 		.codec_dai_name	= "sgtl5000",
 		.codec_name	= "sgtl5000.0-000a",
 		.cpu_dai_name	= "mxs-saif.1",
-		.platform_name	= "mxs-pcm-audio.1",
+		.platform_name	= "mxs-saif.1",
 		.ops		= &mxs_sgtl5000_hifi_ops,
 	},
 };
@@ -110,11 +112,48 @@
 	.num_links	= ARRAY_SIZE(mxs_sgtl5000_dai),
 };
 
+static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *saif_np[2], *codec_np;
+	int i, ret = 0;
+
+	if (!np)
+		return 1; /* no device tree */
+
+	saif_np[0] = of_parse_phandle(np, "saif-controllers", 0);
+	saif_np[1] = of_parse_phandle(np, "saif-controllers", 1);
+	codec_np = of_parse_phandle(np, "audio-codec", 0);
+	if (!saif_np[0] || !saif_np[1] || !codec_np) {
+		dev_err(&pdev->dev, "phandle missing or invalid\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 2; i++) {
+		mxs_sgtl5000_dai[i].codec_name = NULL;
+		mxs_sgtl5000_dai[i].codec_of_node = codec_np;
+		mxs_sgtl5000_dai[i].cpu_dai_name = NULL;
+		mxs_sgtl5000_dai[i].cpu_dai_of_node = saif_np[i];
+		mxs_sgtl5000_dai[i].platform_name = NULL;
+		mxs_sgtl5000_dai[i].platform_of_node = saif_np[i];
+	}
+
+	of_node_put(codec_np);
+	of_node_put(saif_np[0]);
+	of_node_put(saif_np[1]);
+
+	return ret;
+}
+
 static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = &mxs_sgtl5000;
 	int ret;
 
+	ret = mxs_sgtl5000_probe_dt(pdev);
+	if (ret < 0)
+		return ret;
+
 	/*
 	 * Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w).
 	 * The Sgtl5000 sysclk is derived from saif0 mclk and it's range
@@ -148,10 +187,17 @@
 	return 0;
 }
 
+static const struct of_device_id mxs_sgtl5000_dt_ids[] = {
+	{ .compatible = "fsl,mxs-audio-sgtl5000", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_sgtl5000_dt_ids);
+
 static struct platform_driver mxs_sgtl5000_audio_driver = {
 	.driver = {
 		.name = "mxs-sgtl5000",
 		.owner = THIS_MODULE,
+		.of_match_table = mxs_sgtl5000_dt_ids,
 	},
 	.probe = mxs_sgtl5000_probe,
 	.remove = __devexit_p(mxs_sgtl5000_remove),
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index deafbfa..9ccfa5e 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -113,6 +113,7 @@
 	tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
 	depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4
 	select SND_OMAP_SOC_HDMI
+	select SND_SOC_OMAP_HDMI_CODEC
 	help
 	  Say Y if you want to add support for SoC HDMI audio on Texas Instruments
 	  OMAP4 chips
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index fd04ce1..1c2aa7f 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -85,14 +85,12 @@
 	char name[20];
 };
 
-static struct pxa2xx_pcm_dma_params *
-pxa_ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
+static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4,
+			int out, struct pxa2xx_pcm_dma_params *dma_data)
 {
 	struct pxa2xx_pcm_dma_data *dma;
 
-	dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
-	if (dma == NULL)
-		return NULL;
+	dma = container_of(dma_data, struct pxa2xx_pcm_dma_data, params);
 
 	snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id,
 			width4 ? "32-bit" : "16-bit", out ? "out" : "in");
@@ -103,8 +101,6 @@
 				  (DCMD_INCTRGADDR | DCMD_FLOWSRC)) |
 			(width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16;
 	dma->params.dev_addr = ssp->phys_base + SSDR;
-
-	return &dma->params;
 }
 
 static int pxa_ssp_startup(struct snd_pcm_substream *substream,
@@ -112,6 +108,7 @@
 {
 	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
 	struct ssp_device *ssp = priv->ssp;
+	struct pxa2xx_pcm_dma_data *dma;
 	int ret = 0;
 
 	if (!cpu_dai->active) {
@@ -119,8 +116,10 @@
 		pxa_ssp_disable(ssp);
 	}
 
-	kfree(snd_soc_dai_get_dma_data(cpu_dai, substream));
-	snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
+	dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
+	if (!dma)
+		return -ENOMEM;
+	snd_soc_dai_set_dma_data(cpu_dai, substream, &dma->params);
 
 	return ret;
 }
@@ -573,18 +572,13 @@
 
 	dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
 
-	/* generate correct DMA params */
-	kfree(dma_data);
-
 	/* Network mode with one active slot (ttsa == 1) can be used
 	 * to force 16-bit frame width on the wire (for S16_LE), even
 	 * with two channels. Use 16-bit DMA transfers for this case.
 	 */
-	dma_data = pxa_ssp_get_dma_params(ssp,
-			((chn == 2) && (ttsa != 1)) || (width == 32),
-			substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-
-	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+	pxa_ssp_set_dma_params(ssp,
+		((chn == 2) && (ttsa != 1)) || (width == 32),
+		substream->stream == SNDRV_PCM_STREAM_PLAYBACK, dma_data);
 
 	/* we can only change the settings if the port is not in use */
 	if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index d085837..3075a42 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -166,7 +166,7 @@
 	struct pxa2xx_pcm_dma_params *dma_data;
 
 	BUG_ON(IS_ERR(clk_i2s));
-	clk_enable(clk_i2s);
+	clk_prepare_enable(clk_i2s);
 	clk_ena = 1;
 	pxa_i2s_wait();
 
@@ -259,7 +259,7 @@
 		SACR0 &= ~SACR0_ENB;
 		pxa_i2s_wait();
 		if (clk_ena) {
-			clk_disable(clk_i2s);
+			clk_disable_unprepare(clk_i2s);
 			clk_ena = 0;
 		}
 	}
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index e741685..c82c646 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -23,10 +23,10 @@
 					  struct snd_soc_dapm_context *dapm,
 					  enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
 	int ret;
 
-	if (dapm->dev != codec_dai->dev)
+	if (dapm->dev != aif1_dai->dev)
 		return 0;
 
 	switch (level) {
@@ -36,7 +36,7 @@
 		 * then do so now, otherwise these are noops.
 		 */
 		if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
-			ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
+			ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1,
 						  WM8994_FLL_SRC_MCLK2, 32768,
 						  sample_rate * 512);
 			if (ret < 0) {
@@ -44,7 +44,7 @@
 				return ret;
 			}
 
-			ret = snd_soc_dai_set_sysclk(codec_dai,
+			ret = snd_soc_dai_set_sysclk(aif1_dai,
 						     WM8994_SYSCLK_FLL1,
 						     sample_rate * 512,
 						     SND_SOC_CLOCK_IN);
@@ -66,25 +66,25 @@
 					       struct snd_soc_dapm_context *dapm,
 					       enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
 	int ret;
 
-	if (dapm->dev != codec_dai->dev)
+	if (dapm->dev != aif1_dai->dev)
 		return 0;
 
 	switch (level) {
 	case SND_SOC_BIAS_STANDBY:
-		ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
+		ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
 					     32768, SND_SOC_CLOCK_IN);
 		if (ret < 0) {
-			pr_err("Failed to switch away from FLL: %d\n", ret);
+			pr_err("Failed to switch away from FLL1: %d\n", ret);
 			return ret;
 		}
 
-		ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
+		ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1,
 					  0, 0, 0);
 		if (ret < 0) {
-			pr_err("Failed to stop FLL: %d\n", ret);
+			pr_err("Failed to stop FLL1: %d\n", ret);
 			return ret;
 		}
 		break;
@@ -131,6 +131,14 @@
 	.hw_params = littlemill_hw_params,
 };
 
+static const struct snd_soc_pcm_stream baseband_params = {
+	.formats = SNDRV_PCM_FMTBIT_S32_LE,
+	.rate_min = 8000,
+	.rate_max = 8000,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
 static struct snd_soc_dai_link littlemill_dai[] = {
 	{
 		.name = "CPU",
@@ -143,13 +151,75 @@
 				| SND_SOC_DAIFMT_CBM_CFM,
 		.ops = &littlemill_ops,
 	},
+	{
+		.name = "Baseband",
+		.stream_name = "Baseband",
+		.cpu_dai_name = "wm8994-aif2",
+		.codec_dai_name = "wm1250-ev1",
+		.codec_name = "wm1250-ev1.1-0027",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+		.ignore_suspend = 1,
+		.params = &baseband_params,
+	},
 };
 
+static int bbclk_ev(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_card *card = w->dapm->card;
+	struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+	int ret;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2,
+					  WM8994_FLL_SRC_BCLK, 64 * 8000,
+					  8000 * 256);
+		if (ret < 0) {
+			pr_err("Failed to start FLL: %d\n", ret);
+			return ret;
+		}
+
+		ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_FLL2,
+					     8000 * 256,
+					     SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			pr_err("Failed to set SYSCLK: %d\n", ret);
+			return ret;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2,
+					     32768, SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			pr_err("Failed to switch away from FLL2: %d\n", ret);
+			return ret;
+		}
+
+		ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2,
+					  0, 0, 0);
+		if (ret < 0) {
+			pr_err("Failed to stop FLL2: %d\n", ret);
+			return ret;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static struct snd_soc_dapm_widget widgets[] = {
 	SND_SOC_DAPM_HP("Headphone", NULL),
 
 	SND_SOC_DAPM_MIC("AMIC", NULL),
 	SND_SOC_DAPM_MIC("DMIC", NULL),
+
+	SND_SOC_DAPM_SUPPLY_S("Baseband Clock", -1, SND_SOC_NOPM, 0, 0,
+			      bbclk_ev,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static struct snd_soc_dapm_route audio_paths[] = {
@@ -162,6 +232,8 @@
 	{ "DMIC", NULL, "MICBIAS2" },   /* Default for DMICBIAS jumper */
 	{ "DMIC1DAT", NULL, "DMIC" },
 	{ "DMIC2DAT", NULL, "DMIC" },
+
+	{ "AIF2CLK", NULL, "Baseband Clock" },
 };
 
 static struct snd_soc_jack littlemill_headset;
@@ -169,10 +241,16 @@
 static int littlemill_late_probe(struct snd_soc_card *card)
 {
 	struct snd_soc_codec *codec = card->rtd[0].codec;
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+	struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
 	int ret;
 
-	ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
+	ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
+				     32768, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2,
 				     32768, SND_SOC_CLOCK_IN);
 	if (ret < 0)
 		return ret;
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
index 4adff93..6abf341 100644
--- a/sound/soc/samsung/lowland.c
+++ b/sound/soc/samsung/lowland.c
@@ -21,33 +21,6 @@
 #define MCLK1_RATE (44100 * 512)
 #define CLKOUT_RATE (44100 * 256)
 
-static int lowland_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 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_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-					 | SND_SOC_DAIFMT_NB_NF
-					 | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static struct snd_soc_ops lowland_ops = {
-	.hw_params = lowland_hw_params,
-};
-
 static struct snd_soc_jack lowland_headset;
 
 /* Headset jack detection DAPM pins */
@@ -101,6 +74,25 @@
 	return 0;
 }
 
+static int lowland_wm9081_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+
+	snd_soc_dapm_nc_pin(&codec->dapm, "LINEOUT");
+
+	/* At any time the WM9081 is active it will have this clock */
+	return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0,
+					CLKOUT_RATE, 0);
+}
+
+static const struct snd_soc_pcm_stream sub_params = {
+	.formats = SNDRV_PCM_FMTBIT_S32_LE,
+	.rate_min = 44100,
+	.rate_max = 44100,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
 static struct snd_soc_dai_link lowland_dai[] = {
 	{
 		.name = "CPU",
@@ -109,7 +101,8 @@
 		.codec_dai_name = "wm5100-aif1",
 		.platform_name = "samsung-audio",
 		.codec_name = "wm5100.1-001a",
-		.ops = &lowland_ops,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				SND_SOC_DAIFMT_CBM_CFM,
 		.init = lowland_wm5100_init,
 	},
 	{
@@ -118,24 +111,20 @@
 		.cpu_dai_name = "wm5100-aif2",
 		.codec_dai_name = "wm1250-ev1",
 		.codec_name = "wm1250-ev1.1-0027",
-		.ops = &lowland_ops,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				SND_SOC_DAIFMT_CBM_CFM,
 		.ignore_suspend = 1,
 	},
-};
-
-static int lowland_wm9081_init(struct snd_soc_dapm_context *dapm)
-{
-	snd_soc_dapm_nc_pin(dapm, "LINEOUT");
-
-	/* At any time the WM9081 is active it will have this clock */
-	return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0,
-					CLKOUT_RATE, 0);
-}
-
-static struct snd_soc_aux_dev lowland_aux_dev[] = {
 	{
-		.name = "wm9081",
+		.name = "Sub Speaker",
+		.stream_name = "Sub Speaker",
+		.cpu_dai_name = "wm5100-aif3",
+		.codec_dai_name = "wm9081-hifi",
 		.codec_name = "wm9081.1-006c",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				SND_SOC_DAIFMT_CBM_CFM,
+		.ignore_suspend = 1,
+		.params = &sub_params,
 		.init = lowland_wm9081_init,
 	},
 };
@@ -180,8 +169,6 @@
 	.owner = THIS_MODULE,
 	.dai_link = lowland_dai,
 	.num_links = ARRAY_SIZE(lowland_dai),
-	.aux_dev = lowland_aux_dev,
-	.num_aux_devs = ARRAY_SIZE(lowland_aux_dev),
 	.codec_conf = lowland_codec_conf,
 	.num_configs = ARRAY_SIZE(lowland_codec_conf),
 
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index f9ab770..a4a9fc7 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -92,33 +92,6 @@
 	return 0;
 }
 
-static int speyside_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 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_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-					 | SND_SOC_DAIFMT_NB_NF
-					 | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static struct snd_soc_ops speyside_ops = {
-	.hw_params = speyside_hw_params,
-};
-
 static struct snd_soc_jack speyside_headset;
 
 /* Headset jack detection DAPM pins */
@@ -208,7 +181,8 @@
 		.platform_name = "samsung-audio",
 		.codec_name = "wm8996.1-001a",
 		.init = speyside_wm8996_init,
-		.ops = &speyside_ops,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
 	},
 	{
 		.name = "Baseband",
@@ -216,7 +190,8 @@
 		.cpu_dai_name = "wm8996-aif2",
 		.codec_dai_name = "wm1250-ev1",
 		.codec_name = "wm1250-ev1.1-0027",
-		.ops = &speyside_ops,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
 		.ignore_suspend = 1,
 	},
 };
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index d8e06a6..6bcb116 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -22,6 +22,7 @@
 
 config SND_SOC_SH4_FSI
 	tristate "SH4 FSI support"
+	select SND_SIMPLE_CARD
 	help
 	  This option enables FSI sound support
 
@@ -46,29 +47,6 @@
 	  This option enables generic sound support for the first
 	  AC97 unit of the SH7760.
 
-config SND_FSI_AK4642
-	tristate "FSI-AK4642 sound support"
-	depends on SND_SOC_SH4_FSI && I2C
-	select SND_SOC_AK4642
-	help
-	  This option enables generic sound support for the
-	  FSI - AK4642 unit
-
-config SND_FSI_DA7210
-	tristate "FSI-DA7210 sound support"
-	depends on SND_SOC_SH4_FSI && I2C
-	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 94476d4..849b387 100644
--- a/sound/soc/sh/Makefile
+++ b/sound/soc/sh/Makefile
@@ -14,13 +14,7 @@
 
 ## boards
 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/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c
deleted file mode 100644
index 97f540a..0000000
--- a/sound/soc/sh/fsi-ak4642.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * FSI-AK464x sound support for ms7724se
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@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 <linux/module.h>
-#include <sound/sh_fsi.h>
-
-struct fsi_ak4642_data {
-	const char *name;
-	const char *card;
-	const char *cpu_dai;
-	const char *codec;
-	const char *platform;
-	int id;
-};
-
-static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_dai *codec = rtd->codec_dai;
-	struct snd_soc_dai *cpu = rtd->cpu_dai;
-	int ret;
-
-	ret = snd_soc_dai_set_fmt(codec, SND_SOC_DAIFMT_LEFT_J |
-					 SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	ret = snd_soc_dai_set_sysclk(codec, 0, 11289600, 0);
-	if (ret < 0)
-		return ret;
-
-	ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_LEFT_J |
-				       SND_SOC_DAIFMT_CBS_CFS);
-
-	return ret;
-}
-
-static struct snd_soc_dai_link fsi_dai_link = {
-	.codec_dai_name	= "ak4642-hifi",
-	.init		= fsi_ak4642_dai_init,
-};
-
-static struct snd_soc_card fsi_soc_card  = {
-	.owner		= THIS_MODULE,
-	.dai_link	= &fsi_dai_link,
-	.num_links	= 1,
-};
-
-static struct platform_device *fsi_snd_device;
-
-static int fsi_ak4642_probe(struct platform_device *pdev)
-{
-	int ret = -ENOMEM;
-	struct fsi_ak4642_info *pinfo = pdev->dev.platform_data;
-
-	if (!pinfo) {
-		dev_err(&pdev->dev, "no info for fsi ak4642\n");
-		goto out;
-	}
-
-	fsi_snd_device = platform_device_alloc("soc-audio", pinfo->id);
-	if (!fsi_snd_device)
-		goto out;
-
-	fsi_dai_link.name		= pinfo->name;
-	fsi_dai_link.stream_name	= pinfo->name;
-	fsi_dai_link.cpu_dai_name	= pinfo->cpu_dai;
-	fsi_dai_link.platform_name	= pinfo->platform;
-	fsi_dai_link.codec_name		= pinfo->codec;
-	fsi_soc_card.name		= pinfo->card;
-
-	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 int fsi_ak4642_remove(struct platform_device *pdev)
-{
-	platform_device_unregister(fsi_snd_device);
-	return 0;
-}
-
-static struct platform_driver fsi_ak4642 = {
-	.driver = {
-		.name	= "fsi-ak4642-audio",
-	},
-	.probe		= fsi_ak4642_probe,
-	.remove		= fsi_ak4642_remove,
-};
-
-module_platform_driver(fsi_ak4642);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic SH4 FSI-AK4642 sound card");
-MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
deleted file mode 100644
index 1dd3354..0000000
--- a/sound/soc/sh/fsi-da7210.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * fsi-da7210.c
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * 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.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/sh_fsi.h>
-
-static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_dai *codec = rtd->codec_dai;
-	struct snd_soc_dai *cpu = rtd->cpu_dai;
-	int ret;
-
-	ret = snd_soc_dai_set_fmt(codec,
-				   SND_SOC_DAIFMT_I2S |
-				   SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_I2S |
-				       SND_SOC_DAIFMT_CBS_CFS);
-
-	return ret;
-}
-
-static struct snd_soc_dai_link fsi_da7210_dai = {
-	.name		= "DA7210",
-	.stream_name	= "DA7210",
-	.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-DA7210",
-	.owner		= THIS_MODULE,
-	.dai_link	= &fsi_da7210_dai,
-	.num_links	= 1,
-};
-
-static struct platform_device *fsi_da7210_snd_device;
-
-static int __init fsi_da7210_sound_init(void)
-{
-	int ret;
-
-	fsi_da7210_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
-	if (!fsi_da7210_snd_device)
-		return -ENOMEM;
-
-	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);
-
-	return ret;
-}
-
-static void __exit fsi_da7210_sound_exit(void)
-{
-	platform_device_unregister(fsi_da7210_snd_device);
-}
-
-module_init(fsi_da7210_sound_init);
-module_exit(fsi_da7210_sound_exit);
-
-/* Module information */
-MODULE_DESCRIPTION("ALSA SoC FSI DA2710");
-MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c
deleted file mode 100644
index 6e41908..0000000
--- a/sound/soc/sh/fsi-hdmi.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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 <linux/module.h>
-#include <sound/sh_fsi.h>
-
-struct fsi_hdmi_data {
-	const char *cpu_dai;
-	const char *card;
-	int id;
-};
-
-static int fsi_hdmi_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_dai *cpu = rtd->cpu_dai;
-	int ret;
-
-	ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_CBM_CFM);
-
-	return ret;
-}
-
-static struct snd_soc_dai_link fsi_dai_link = {
-	.name		= "HDMI",
-	.stream_name	= "HDMI",
-	.codec_dai_name	= "sh_mobile_hdmi-hifi",
-	.platform_name	= "sh_fsi2",
-	.codec_name	= "sh-mobile-hdmi",
-	.init		= fsi_hdmi_dai_init,
-};
-
-static struct snd_soc_card fsi_soc_card  = {
-	.owner		= THIS_MODULE,
-	.dai_link	= &fsi_dai_link,
-	.num_links	= 1,
-};
-
-static struct platform_device *fsi_snd_device;
-
-static int fsi_hdmi_probe(struct platform_device *pdev)
-{
-	int ret = -ENOMEM;
-	const struct platform_device_id	*id_entry;
-	struct fsi_hdmi_data *pdata;
-
-	id_entry = pdev->id_entry;
-	if (!id_entry) {
-		dev_err(&pdev->dev, "unknown fsi hdmi\n");
-		return -ENODEV;
-	}
-
-	pdata = (struct fsi_hdmi_data *)id_entry->driver_data;
-
-	fsi_snd_device = platform_device_alloc("soc-audio", pdata->id);
-	if (!fsi_snd_device)
-		goto out;
-
-	fsi_dai_link.cpu_dai_name	= pdata->cpu_dai;
-	fsi_soc_card.name		= pdata->card;
-
-	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 int fsi_hdmi_remove(struct platform_device *pdev)
-{
-	platform_device_unregister(fsi_snd_device);
-	return 0;
-}
-
-static struct fsi_hdmi_data fsi2_a_hdmi = {
-	.cpu_dai	= "fsia-dai",
-	.card		= "FSI2A-HDMI",
-	.id		= FSI_PORT_A,
-};
-
-static struct fsi_hdmi_data fsi2_b_hdmi = {
-	.cpu_dai	= "fsib-dai",
-	.card		= "FSI2B-HDMI",
-	.id		= FSI_PORT_B,
-};
-
-static struct platform_device_id fsi_id_table[] = {
-	/* FSI 2 */
-	{ "sh_fsi2_a_hdmi",	(kernel_ulong_t)&fsi2_a_hdmi },
-	{ "sh_fsi2_b_hdmi",	(kernel_ulong_t)&fsi2_b_hdmi },
-	{},
-};
-
-static struct platform_driver fsi_hdmi = {
-	.driver = {
-		.name	= "fsi-hdmi-audio",
-	},
-	.probe		= fsi_hdmi_probe,
-	.remove		= fsi_hdmi_remove,
-	.id_table	= fsi_id_table,
-};
-
-module_platform_driver(fsi_hdmi);
-
-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 74ed2df..7cee225 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -132,6 +132,25 @@
 typedef int (*set_rate_func)(struct device *dev, int rate, int enable);
 
 /*
+ * bus options
+ *
+ * 0x000000BA
+ *
+ * A : sample widtht 16bit setting
+ * B : sample widtht 24bit setting
+ */
+
+#define SHIFT_16DATA		0
+#define SHIFT_24DATA		4
+
+#define PACKAGE_24BITBUS_BACK		0
+#define PACKAGE_24BITBUS_FRONT		1
+#define PACKAGE_16BITBUS_STREAM		2
+
+#define BUSOP_SET(s, a)	((a) << SHIFT_ ## s ## DATA)
+#define BUSOP_GET(s, a)	(((a) >> SHIFT_ ## s ## DATA) & 0xF)
+
+/*
  * FSI driver use below type name for variable
  *
  * xxx_num	: number of data
@@ -189,6 +208,11 @@
 	int oerr_num;
 
 	/*
+	 * bus options
+	 */
+	u32 bus_option;
+
+	/*
 	 * thse are initialized by fsi_handler_init()
 	 */
 	struct fsi_stream_handler *handler;
@@ -211,8 +235,7 @@
 	struct fsi_stream playback;
 	struct fsi_stream capture;
 
-	u32 do_fmt;
-	u32 di_fmt;
+	u32 fmt;
 
 	int chan_num:16;
 	int clk_master:1;
@@ -321,6 +344,10 @@
 /*
  *		basic function
  */
+static int fsi_version(struct fsi_master *master)
+{
+	return master->core->ver;
+}
 
 static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
 {
@@ -495,6 +522,7 @@
 	io->period_samples	= fsi_frame2sample(fsi, runtime->period_size);
 	io->period_pos		= 0;
 	io->sample_width	= samples_to_bytes(runtime, 1);
+	io->bus_option		= 0;
 	io->oerr_num	= -1; /* ignore 1st err */
 	io->uerr_num	= -1; /* ignore 1st err */
 	fsi_stream_handler_call(io, init, fsi, io);
@@ -522,6 +550,7 @@
 	io->period_samples	= 0;
 	io->period_pos		= 0;
 	io->sample_width	= 0;
+	io->bus_option		= 0;
 	io->oerr_num	= 0;
 	io->uerr_num	= 0;
 	spin_unlock_irqrestore(&master->lock, flags);
@@ -581,6 +610,53 @@
 }
 
 /*
+ *	format/bus/dma setting
+ */
+static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io,
+				 u32 bus, struct device *dev)
+{
+	struct fsi_master *master = fsi_get_master(fsi);
+	int is_play = fsi_stream_is_play(fsi, io);
+	u32 fmt = fsi->fmt;
+
+	if (fsi_version(master) >= 2) {
+		u32 dma = 0;
+
+		/*
+		 * FSI2 needs DMA/Bus setting
+		 */
+		switch (bus) {
+		case PACKAGE_24BITBUS_FRONT:
+			fmt |= CR_BWS_24;
+			dma |= VDMD_FRONT;
+			dev_dbg(dev, "24bit bus / package in front\n");
+			break;
+		case PACKAGE_16BITBUS_STREAM:
+			fmt |= CR_BWS_16;
+			dma |= VDMD_STREAM;
+			dev_dbg(dev, "16bit bus / stream mode\n");
+			break;
+		case PACKAGE_24BITBUS_BACK:
+		default:
+			fmt |= CR_BWS_24;
+			dma |= VDMD_BACK;
+			dev_dbg(dev, "24bit bus / package in back\n");
+			break;
+		}
+
+		if (is_play)
+			fsi_reg_write(fsi, OUT_DMAC,	dma);
+		else
+			fsi_reg_write(fsi, IN_DMAC,	dma);
+	}
+
+	if (is_play)
+		fsi_reg_write(fsi, DO_FMT, fmt);
+	else
+		fsi_reg_write(fsi, DI_FMT, fmt);
+}
+
+/*
  *		irq function
  */
 
@@ -629,11 +705,6 @@
 	struct fsi_master *master = fsi_get_master(fsi);
 	u32 mask, val;
 
-	if (master->core->ver < 2) {
-		pr_err("fsi: register access err (%s)\n", __func__);
-		return;
-	}
-
 	mask = BP | SE;
 	val = enable ? mask : 0;
 
@@ -648,9 +719,7 @@
 static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
 			      long rate, int enable)
 {
-	struct fsi_master *master = fsi_get_master(fsi);
 	set_rate_func set_rate = fsi_get_info_set_rate(fsi);
-	int fsi_ver = master->core->ver;
 	int ret;
 
 	if (!set_rate)
@@ -682,10 +751,7 @@
 			data |= (0x3 << 12);
 			break;
 		case SH_FSI_ACKMD_32:
-			if (fsi_ver < 2)
-				dev_err(dev, "unsupported ACKMD\n");
-			else
-				data |= (0x4 << 12);
+			data |= (0x4 << 12);
 			break;
 		}
 
@@ -708,10 +774,7 @@
 			data |= (0x4 << 8);
 			break;
 		case SH_FSI_BPFMD_16:
-			if (fsi_ver < 2)
-				dev_err(dev, "unsupported ACKMD\n");
-			else
-				data |= (0x7 << 8);
+			data |= (0x7 << 8);
 			break;
 		}
 
@@ -728,11 +791,26 @@
  */
 static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples)
 {
-	u16 *buf = (u16 *)_buf;
+	u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE;
 	int i;
 
-	for (i = 0; i < samples; i++)
-		fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
+	if (enable_stream) {
+		/*
+		 * stream mode
+		 * see
+		 *	fsi_pio_push_init()
+		 */
+		u32 *buf = (u32 *)_buf;
+
+		for (i = 0; i < samples / 2; i++)
+			fsi_reg_write(fsi, DODT, buf[i]);
+	} else {
+		/* normal mode */
+		u16 *buf = (u16 *)_buf;
+
+		for (i = 0; i < samples; i++)
+			fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
+	}
 }
 
 static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples)
@@ -872,12 +950,44 @@
 		fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
+static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE;
+
+	/*
+	 * we can use 16bit stream mode
+	 * when "playback" and "16bit data"
+	 * and platform allows "stream mode"
+	 * see
+	 *	fsi_pio_push16()
+	 */
+	if (enable_stream)
+		io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+				 BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
+	else
+		io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+				 BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
+	return 0;
+}
+
+static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	/*
+	 * always 24bit bus, package back when "capture"
+	 */
+	io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+			 BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
+	return 0;
+}
+
 static struct fsi_stream_handler fsi_pio_push_handler = {
+	.init		= fsi_pio_push_init,
 	.transfer	= fsi_pio_push,
 	.start_stop	= fsi_pio_start_stop,
 };
 
 static struct fsi_stream_handler fsi_pio_pop_handler = {
+	.init		= fsi_pio_pop_init,
 	.transfer	= fsi_pio_pop,
 	.start_stop	= fsi_pio_start_stop,
 };
@@ -919,6 +1029,13 @@
 	enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
 				DMA_TO_DEVICE : DMA_FROM_DEVICE;
 
+	/*
+	 * 24bit data : 24bit bus / package in back
+	 * 16bit data : 16bit bus / stream mode
+	 */
+	io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+			 BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
+
 	io->dma = dma_map_single(dai->dev, runtime->dma_area,
 				 snd_pcm_lib_buffer_bytes(io->substream), dir);
 	return 0;
@@ -1055,25 +1172,9 @@
 static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
 				 int start)
 {
-	u32 bws;
-	u32 dma;
+	u32 enable = start ? DMA_ON : 0;
 
-	switch (io->sample_width * start) {
-	case 2:
-		bws = CR_BWS_16;
-		dma = VDMD_STREAM | DMA_ON;
-		break;
-	case 4:
-		bws = CR_BWS_24;
-		dma = VDMD_BACK | DMA_ON;
-		break;
-	default:
-		bws = 0;
-		dma = 0;
-	}
-
-	fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws);
-	fsi_reg_write(fsi, OUT_DMAC, dma);
+	fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable);
 }
 
 static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
@@ -1176,8 +1277,6 @@
 			  struct fsi_stream *io,
 			  struct device *dev)
 {
-	struct fsi_master *master = fsi_get_master(fsi);
-	int fsi_ver = master->core->ver;
 	u32 flags = fsi_get_info_flags(fsi);
 	u32 data = 0;
 
@@ -1200,10 +1299,6 @@
 
 	fsi_reg_write(fsi, CKG2, data);
 
-	/* set format */
-	fsi_reg_write(fsi, DO_FMT, fsi->do_fmt);
-	fsi_reg_write(fsi, DI_FMT, fsi->di_fmt);
-
 	/* spdif ? */
 	if (fsi_is_spdif(fsi)) {
 		fsi_spdif_clk_ctrl(fsi, 1);
@@ -1211,15 +1306,18 @@
 	}
 
 	/*
-	 * FIXME
-	 *
-	 * FSI driver assumed that data package is in-back.
-	 * FSI2 chip can select it.
+	 * get bus settings
 	 */
-	if (fsi_ver >= 2) {
-		fsi_reg_write(fsi, OUT_DMAC,	(1 << 4));
-		fsi_reg_write(fsi, IN_DMAC,	(1 << 4));
+	data = 0;
+	switch (io->sample_width) {
+	case 2:
+		data = BUSOP_GET(16, io->bus_option);
+		break;
+	case 4:
+		data = BUSOP_GET(24, io->bus_option);
+		break;
 	}
+	fsi_format_bus_setup(fsi, io, data, dev);
 
 	/* irq clear */
 	fsi_irq_disable(fsi, io);
@@ -1243,7 +1341,9 @@
 {
 	struct fsi_priv *fsi = fsi_get_priv(substream);
 
-	return fsi_hw_startup(fsi, fsi_stream_get(fsi, substream), dai->dev);
+	fsi->rate = 0;
+
+	return 0;
 }
 
 static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
@@ -1251,7 +1351,6 @@
 {
 	struct fsi_priv *fsi = fsi_get_priv(substream);
 
-	fsi_hw_shutdown(fsi, dai->dev);
 	fsi->rate = 0;
 }
 
@@ -1265,11 +1364,13 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		fsi_stream_init(fsi, io, substream);
+		fsi_hw_startup(fsi, io, dai->dev);
 		ret = fsi_stream_transfer(io);
 		if (0 == ret)
 			fsi_stream_start(fsi, io);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
+		fsi_hw_shutdown(fsi, dai->dev);
 		fsi_stream_stop(fsi, io);
 		fsi_stream_quit(fsi, io);
 		break;
@@ -1280,42 +1381,33 @@
 
 static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
 {
-	u32 data = 0;
-
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
-		data = CR_I2S;
+		fsi->fmt = CR_I2S;
 		fsi->chan_num = 2;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		data = CR_PCM;
+		fsi->fmt = CR_PCM;
 		fsi->chan_num = 2;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	fsi->do_fmt = data;
-	fsi->di_fmt = data;
-
 	return 0;
 }
 
 static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
 {
 	struct fsi_master *master = fsi_get_master(fsi);
-	u32 data = 0;
 
-	if (master->core->ver < 2)
+	if (fsi_version(master) < 2)
 		return -EINVAL;
 
-	data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
+	fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM;
 	fsi->chan_num = 2;
 	fsi->spdif = 1;
 
-	fsi->do_fmt = data;
-	fsi->di_fmt = data;
-
 	return 0;
 }
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c88d974..b37ee80 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -39,6 +39,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/soc-dpcm.h>
 #include <sound/initval.h>
 
 #define CREATE_TRACE_POINTS
@@ -54,7 +55,6 @@
 #endif
 
 static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(card_list);
 static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
@@ -465,6 +465,35 @@
 }
 #endif
 
+struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
+		const char *dai_link, int stream)
+{
+	int i;
+
+	for (i = 0; i < card->num_links; i++) {
+		if (card->rtd[i].dai_link->no_pcm &&
+			!strcmp(card->rtd[i].dai_link->name, dai_link))
+			return card->rtd[i].pcm->streams[stream].substream;
+	}
+	dev_dbg(card->dev, "failed to find dai link %s\n", dai_link);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
+
+struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
+		const char *dai_link)
+{
+	int i;
+
+	for (i = 0; i < card->num_links; i++) {
+		if (!strcmp(card->rtd[i].dai_link->name, dai_link))
+			return &card->rtd[i];
+	}
+	dev_dbg(card->dev, "failed to find rtd %s\n", dai_link);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
+
 #ifdef CONFIG_SND_SOC_AC97_BUS
 /* unregister ac97 codec */
 static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
@@ -567,19 +596,16 @@
 	}
 
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
 		if (card->rtd[i].dai_link->ignore_suspend)
 			continue;
 
 		snd_soc_dapm_stream_event(&card->rtd[i],
 					  SNDRV_PCM_STREAM_PLAYBACK,
-					  codec_dai,
 					  SND_SOC_DAPM_STREAM_SUSPEND);
 
 		snd_soc_dapm_stream_event(&card->rtd[i],
 					  SNDRV_PCM_STREAM_CAPTURE,
-					  codec_dai,
 					  SND_SOC_DAPM_STREAM_SUSPEND);
 	}
 
@@ -683,17 +709,16 @@
 	}
 
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
 		if (card->rtd[i].dai_link->ignore_suspend)
 			continue;
 
 		snd_soc_dapm_stream_event(&card->rtd[i],
-					  SNDRV_PCM_STREAM_PLAYBACK, codec_dai,
+					  SNDRV_PCM_STREAM_PLAYBACK,
 					  SND_SOC_DAPM_STREAM_RESUME);
 
 		snd_soc_dapm_stream_event(&card->rtd[i],
-					  SNDRV_PCM_STREAM_CAPTURE, codec_dai,
+					  SNDRV_PCM_STREAM_CAPTURE,
 					  SND_SOC_DAPM_STREAM_RESUME);
 	}
 
@@ -783,15 +808,9 @@
 	struct snd_soc_dai *codec_dai, *cpu_dai;
 	const char *platform_name;
 
-	if (rtd->complete)
-		return 1;
 	dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
 
-	/* 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*/
+	/* Find CPU DAI from registered DAIs*/
 	list_for_each_entry(cpu_dai, &dai_list, list) {
 		if (dai_link->cpu_dai_of_node) {
 			if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
@@ -802,18 +821,15 @@
 		}
 
 		rtd->cpu_dai = cpu_dai;
-		goto find_codec;
 	}
-	dev_dbg(card->dev, "CPU DAI %s not registered\n",
+
+	if (!rtd->cpu_dai) {
+		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;
+		return -EPROBE_DEFER;
 	}
 
-	/* no, then find CODEC from registered CODECs*/
+	/* Find CODEC from registered CODECs */
 	list_for_each_entry(codec, &codec_list, list) {
 		if (dai_link->codec_of_node) {
 			if (codec->dev->of_node != dai_link->codec_of_node)
@@ -835,28 +851,28 @@
 					dai_link->codec_dai_name)) {
 
 				rtd->codec_dai = codec_dai;
-				goto find_platform;
 			}
 		}
-		dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+
+		if (!rtd->codec_dai) {
+			dev_dbg(card->dev, "CODEC DAI %s not registered\n",
 				dai_link->codec_dai_name);
-
-		goto find_platform;
+			return -EPROBE_DEFER;
+		}
 	}
-	dev_dbg(card->dev, "CODEC %s not registered\n",
-			dai_link->codec_name);
 
-find_platform:
-	/* do we need a platform? */
-	if (rtd->platform)
-		goto out;
+	if (!rtd->codec) {
+		dev_dbg(card->dev, "CODEC %s not registered\n",
+			dai_link->codec_name);
+		return -EPROBE_DEFER;
+	}
 
 	/* if there's no platform we match on the empty platform */
 	platform_name = dai_link->platform_name;
 	if (!platform_name && !dai_link->platform_of_node)
 		platform_name = "snd-soc-dummy";
 
-	/* no, then find one from the set of registered platforms */
+	/* find one from the set of registered platforms */
 	list_for_each_entry(platform, &platform_list, list) {
 		if (dai_link->platform_of_node) {
 			if (platform->dev->of_node !=
@@ -868,20 +884,16 @@
 		}
 
 		rtd->platform = platform;
-		goto out;
 	}
-
-	dev_dbg(card->dev, "platform %s not registered\n",
+	if (!rtd->platform) {
+		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 -EPROBE_DEFER;
 	}
-	return 1;
+
+	card->num_rtd++;
+
+	return 0;
 }
 
 static void soc_remove_codec(struct snd_soc_codec *codec)
@@ -1068,6 +1080,7 @@
 {
 	int ret = 0;
 	const struct snd_soc_platform_driver *driver = platform->driver;
+	struct snd_soc_dai *dai;
 
 	platform->card = card;
 	platform->dapm.card = card;
@@ -1081,6 +1094,14 @@
 		snd_soc_dapm_new_controls(&platform->dapm,
 			driver->dapm_widgets, driver->num_dapm_widgets);
 
+	/* Create DAPM widgets for each DAI stream */
+	list_for_each_entry(dai, &dai_list, list) {
+		if (dai->dev != platform->dev)
+			continue;
+
+		snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
+	}
+
 	platform->dapm.idle_bias_off = 1;
 
 	if (driver->probe) {
@@ -1170,6 +1191,10 @@
 	rtd->dev->init_name = name;
 	dev_set_drvdata(rtd->dev, rtd);
 	mutex_init(&rtd->pcm_mutex);
+	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
+	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients);
+	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients);
+	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
 	ret = device_add(rtd->dev);
 	if (ret < 0) {
 		dev_err(card->dev,
@@ -1191,6 +1216,17 @@
 		dev_err(codec->dev,
 			"asoc: failed to add codec sysfs files: %d\n", ret);
 
+#ifdef CONFIG_DEBUG_FS
+	/* add DPCM sysfs entries */
+	if (!dailess && !dai_link->dynamic)
+		goto out;
+
+	ret = soc_dpcm_debugfs_add(rtd);
+	if (ret < 0)
+		dev_err(rtd->dev, "asoc: failed to add dpcm sysfs entries: %d\n", ret);
+
+out:
+#endif
 	return 0;
 }
 
@@ -1200,14 +1236,15 @@
 	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;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dapm_widget *play_w, *capture_w;
 	int ret;
 
 	dev_dbg(card->dev, "probe %s dai link %d late %d\n",
 			card->name, num, order);
 
 	/* config components */
-	codec_dai->codec = codec;
 	cpu_dai->platform = platform;
 	codec_dai->card = card;
 	cpu_dai->card = card;
@@ -1218,9 +1255,12 @@
 	/* probe the cpu_dai */
 	if (!cpu_dai->probed &&
 			cpu_dai->driver->probe_order == order) {
+		cpu_dai->dapm.card = card;
 		if (!try_module_get(cpu_dai->dev->driver->owner))
 			return -ENODEV;
 
+		snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
+
 		if (cpu_dai->driver->probe) {
 			ret = cpu_dai->driver->probe(cpu_dai);
 			if (ret < 0) {
@@ -1279,12 +1319,39 @@
 	if (ret < 0)
 		pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret);
 
-	/* create the pcm */
-	ret = soc_new_pcm(rtd, num);
-	if (ret < 0) {
-		pr_err("asoc: can't create pcm %s :%d\n",
-				dai_link->stream_name, ret);
-		return ret;
+	if (!dai_link->params) {
+		/* create the pcm */
+		ret = soc_new_pcm(rtd, num);
+		if (ret < 0) {
+			pr_err("asoc: can't create pcm %s :%d\n",
+			       dai_link->stream_name, ret);
+			return ret;
+		}
+	} else {
+		/* link the DAI widgets */
+		play_w = codec_dai->playback_widget;
+		capture_w = cpu_dai->capture_widget;
+		if (play_w && capture_w) {
+			ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+						   capture_w, play_w);
+			if (ret != 0) {
+				dev_err(card->dev, "Can't link %s to %s: %d\n",
+					play_w->name, capture_w->name, ret);
+				return ret;
+			}
+		}
+
+		play_w = cpu_dai->playback_widget;
+		capture_w = codec_dai->capture_widget;
+		if (play_w && capture_w) {
+			ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+						   capture_w, play_w);
+			if (ret != 0) {
+				dev_err(card->dev, "Can't link %s to %s: %d\n",
+					play_w->name, capture_w->name, ret);
+				return ret;
+			}
+		}
 	}
 
 	/* add platform data for AC97 devices */
@@ -1334,6 +1401,20 @@
 }
 #endif
 
+static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+{
+	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+	struct snd_soc_codec *codec;
+
+	/* find CODEC from registered CODECs*/
+	list_for_each_entry(codec, &codec_list, list) {
+		if (!strcmp(codec->name, aux_dev->codec_name))
+			return 0;
+	}
+
+	return -EPROBE_DEFER;
+}
+
 static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
 {
 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
@@ -1354,7 +1435,7 @@
 	}
 	/* codec not found */
 	dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
-	goto out;
+	return -EPROBE_DEFER;
 
 found:
 	ret = soc_probe_codec(card, codec);
@@ -1404,29 +1485,28 @@
 	return 0;
 }
 
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
 	struct snd_soc_codec *codec;
 	struct snd_soc_codec_conf *codec_conf;
 	enum snd_soc_compress_type compress_type;
 	struct snd_soc_dai_link *dai_link;
-	int ret, i, order;
+	int ret, i, order, dai_fmt;
 
-	mutex_lock(&card->mutex);
-
-	if (card->instantiated) {
-		mutex_unlock(&card->mutex);
-		return;
-	}
+	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
 	/* bind DAIs */
-	for (i = 0; i < card->num_links; i++)
-		soc_bind_dai_link(card, i);
+	for (i = 0; i < card->num_links; i++) {
+		ret = soc_bind_dai_link(card, i);
+		if (ret != 0)
+			goto base_error;
+	}
 
-	/* bind completed ? */
-	if (card->num_rtd != card->num_links) {
-		mutex_unlock(&card->mutex);
-		return;
+	/* check aux_devs too */
+	for (i = 0; i < card->num_aux_devs; i++) {
+		ret = soc_check_aux_dev(card, i);
+		if (ret != 0)
+			goto base_error;
 	}
 
 	/* initialize the register cache for each available codec */
@@ -1446,10 +1526,8 @@
 			}
 		}
 		ret = snd_soc_init_codec_cache(codec, compress_type);
-		if (ret < 0) {
-			mutex_unlock(&card->mutex);
-			return;
-		}
+		if (ret < 0)
+			goto base_error;
 	}
 
 	/* card bind complete so register a sound card */
@@ -1458,8 +1536,7 @@
 	if (ret < 0) {
 		pr_err("asoc: can't create sound card for card %s: %d\n",
 			card->name, ret);
-		mutex_unlock(&card->mutex);
-		return;
+		goto base_error;
 	}
 	card->snd_card->dev = card->dev;
 
@@ -1523,17 +1600,47 @@
 
 	for (i = 0; i < card->num_links; i++) {
 		dai_link = &card->dai_link[i];
+		dai_fmt = dai_link->dai_fmt;
 
-		if (dai_link->dai_fmt) {
+		if (dai_fmt) {
 			ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai,
-						  dai_link->dai_fmt);
+						  dai_fmt);
 			if (ret != 0 && ret != -ENOTSUPP)
 				dev_warn(card->rtd[i].codec_dai->dev,
 					 "Failed to set DAI format: %d\n",
 					 ret);
+		}
+
+		/* If this is a regular CPU link there will be a platform */
+		if (dai_fmt &&
+		    (dai_link->platform_name || dai_link->platform_of_node)) {
+			ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
+						  dai_fmt);
+			if (ret != 0 && ret != -ENOTSUPP)
+				dev_warn(card->rtd[i].cpu_dai->dev,
+					 "Failed to set DAI format: %d\n",
+					 ret);
+		} else if (dai_fmt) {
+			/* Flip the polarity for the "CPU" end */
+			dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+			switch (dai_link->dai_fmt &
+				SND_SOC_DAIFMT_MASTER_MASK) {
+			case SND_SOC_DAIFMT_CBM_CFM:
+				dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+				break;
+			case SND_SOC_DAIFMT_CBM_CFS:
+				dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
+				break;
+			case SND_SOC_DAIFMT_CBS_CFM:
+				dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
+				break;
+			case SND_SOC_DAIFMT_CBS_CFS:
+				dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+				break;
+			}
 
 			ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
-						  dai_link->dai_fmt);
+						  dai_fmt);
 			if (ret != 0 && ret != -ENOTSUPP)
 				dev_warn(card->rtd[i].cpu_dai->dev,
 					 "Failed to set DAI format: %d\n",
@@ -1599,7 +1706,8 @@
 	card->instantiated = 1;
 	snd_soc_dapm_sync(&card->dapm);
 	mutex_unlock(&card->mutex);
-	return;
+
+	return 0;
 
 probe_aux_dev_err:
 	for (i = 0; i < card->num_aux_devs; i++)
@@ -1614,18 +1722,10 @@
 
 	snd_card_free(card->snd_card);
 
+base_error:
 	mutex_unlock(&card->mutex);
-}
 
-/*
- * Attempt to initialise any uninitialised cards.  Must be called with
- * client_mutex.
- */
-static void snd_soc_instantiate_cards(void)
-{
-	struct snd_soc_card *card;
-	list_for_each_entry(card, &card_list, list)
-		snd_soc_instantiate_card(card);
+	return ret;
 }
 
 /* probes a new socdev */
@@ -2527,6 +2627,87 @@
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 
 /**
+ * snd_soc_get_volsw_sx - single mixer get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a single mixer control, or a double mixer
+ * control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct soc_mixer_control *mc =
+	    (struct soc_mixer_control *)kcontrol->private_value;
+
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	int min = mc->min;
+	int mask = (1 << (fls(min + max) - 1)) - 1;
+
+	ucontrol->value.integer.value[0] =
+	    ((snd_soc_read(codec, reg) >> shift) - min) & mask;
+
+	if (snd_soc_volsw_is_stereo(mc))
+		ucontrol->value.integer.value[1] =
+			((snd_soc_read(codec, reg2) >> rshift) - min) & mask;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
+
+/**
+ * snd_soc_put_volsw_sx - double mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct soc_mixer_control *mc =
+	    (struct soc_mixer_control *)kcontrol->private_value;
+
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	int min = mc->min;
+	int mask = (1 << (fls(min + max) - 1)) - 1;
+	int err = 0;
+	unsigned short val, val_mask, val2 = 0;
+
+	val_mask = mask << shift;
+	val = (ucontrol->value.integer.value[0] + min) & mask;
+	val = val << shift;
+
+	if (snd_soc_update_bits_locked(codec, reg, val_mask, val))
+			return err;
+
+	if (snd_soc_volsw_is_stereo(mc)) {
+		val_mask = mask << rshift;
+		val2 = (ucontrol->value.integer.value[1] + min) & mask;
+		val2 = val2 << rshift;
+
+		if (snd_soc_update_bits_locked(codec, reg2, val_mask, val2))
+			return err;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
+
+/**
  * snd_soc_info_volsw_s8 - signed mixer info callback
  * @kcontrol: mixer control
  * @uinfo: control element information
@@ -2647,99 +2828,6 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
 
-/**
- * snd_soc_info_volsw_2r_sx - double with tlv and variable data size
- *  mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-			struct snd_ctl_elem_info *uinfo)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	int max = mc->max;
-	int min = mc->min;
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 2;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = max-min;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
-
-/**
- * snd_soc_get_volsw_2r_sx - double with tlv and variable data size
- *  mixer get callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw_2r_sx(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 mask = (1<<mc->shift)-1;
-	int min = mc->min;
-	int val = snd_soc_read(codec, mc->reg) & mask;
-	int valr = snd_soc_read(codec, mc->rreg) & mask;
-
-	ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask;
-	ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
-
-/**
- * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
- *  mixer put callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw_2r_sx(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 mask = (1<<mc->shift)-1;
-	int min = mc->min;
-	int ret;
-	unsigned int val, valr, oval, ovalr;
-
-	val = ((ucontrol->value.integer.value[0]+min) & 0xff);
-	val &= mask;
-	valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
-	valr &= mask;
-
-	oval = snd_soc_read(codec, mc->reg) & mask;
-	ovalr = snd_soc_read(codec, mc->rreg) & mask;
-
-	ret = 0;
-	if (oval != val) {
-		ret = snd_soc_write(codec, mc->reg, val);
-		if (ret < 0)
-			return ret;
-	}
-	if (ovalr != valr) {
-		ret = snd_soc_write(codec, mc->rreg, valr);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
-
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_info *uinfo)
 {
@@ -2850,6 +2938,186 @@
 EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
 
 /**
+ * snd_soc_info_xr_sx - signed multi register info callback
+ * @kcontrol: mreg control
+ * @uinfo: control element information
+ *
+ * Callback to provide information of a control that can
+ * span multiple codec registers which together
+ * forms a single signed value in a MSB/LSB manner.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_mreg_control *mc =
+		(struct soc_mreg_control *)kcontrol->private_value;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = mc->min;
+	uinfo->value.integer.max = mc->max;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx);
+
+/**
+ * snd_soc_get_xr_sx - signed multi register get callback
+ * @kcontrol: mreg control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a control that can span
+ * multiple codec registers which together forms a single
+ * signed value in a MSB/LSB manner. The control supports
+ * specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mreg_control *mc =
+		(struct soc_mreg_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int regbase = mc->regbase;
+	unsigned int regcount = mc->regcount;
+	unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+	unsigned int regwmask = (1<<regwshift)-1;
+	unsigned int invert = mc->invert;
+	unsigned long mask = (1UL<<mc->nbits)-1;
+	long min = mc->min;
+	long max = mc->max;
+	long val = 0;
+	unsigned long regval;
+	unsigned int i;
+
+	for (i = 0; i < regcount; i++) {
+		regval = snd_soc_read(codec, regbase+i) & regwmask;
+		val |= regval << (regwshift*(regcount-i-1));
+	}
+	val &= mask;
+	if (min < 0 && val > max)
+		val |= ~mask;
+	if (invert)
+		val = max - val;
+	ucontrol->value.integer.value[0] = val;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx);
+
+/**
+ * snd_soc_put_xr_sx - signed multi register get callback
+ * @kcontrol: mreg control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value of a control that can span
+ * multiple codec registers which together forms a single
+ * signed value in a MSB/LSB manner. The control supports
+ * specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mreg_control *mc =
+		(struct soc_mreg_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int regbase = mc->regbase;
+	unsigned int regcount = mc->regcount;
+	unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+	unsigned int regwmask = (1<<regwshift)-1;
+	unsigned int invert = mc->invert;
+	unsigned long mask = (1UL<<mc->nbits)-1;
+	long max = mc->max;
+	long val = ucontrol->value.integer.value[0];
+	unsigned int i, regval, regmask;
+	int err;
+
+	if (invert)
+		val = max - val;
+	val &= mask;
+	for (i = 0; i < regcount; i++) {
+		regval = (val >> (regwshift*(regcount-i-1))) & regwmask;
+		regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask;
+		err = snd_soc_update_bits_locked(codec, regbase+i,
+				regmask, regval);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);
+
+/**
+ * snd_soc_get_strobe - strobe get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback get the value of a strobe mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_strobe(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 shift = mc->shift;
+	unsigned int mask = 1 << shift;
+	unsigned int invert = mc->invert != 0;
+	unsigned int val = snd_soc_read(codec, reg) & mask;
+
+	if (shift != 0 && val != 0)
+		val = val >> shift;
+	ucontrol->value.enumerated.item[0] = val ^ invert;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_strobe);
+
+/**
+ * snd_soc_put_strobe - strobe put callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback strobe a register bit to high then low (or the inverse)
+ * in one pass of a single mixer enum control.
+ *
+ * Returns 1 for success.
+ */
+int snd_soc_put_strobe(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 shift = mc->shift;
+	unsigned int mask = 1 << shift;
+	unsigned int invert = mc->invert != 0;
+	unsigned int strobe = ucontrol->value.enumerated.item[0] != 0;
+	unsigned int val1 = (strobe ^ invert) ? mask : 0;
+	unsigned int val2 = (strobe ^ invert) ? 0 : mask;
+	int err;
+
+	err = snd_soc_update_bits_locked(codec, reg, mask, val1);
+	if (err < 0)
+		return err;
+
+	err = snd_soc_update_bits_locked(codec, reg, mask, val2);
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_strobe);
+
+/**
  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
  * @dai: DAI
  * @clk_id: DAI specific clock ID
@@ -3048,7 +3316,7 @@
 	if (dai->driver && dai->driver->ops->digital_mute)
 		return dai->driver->ops->digital_mute(dai, mute);
 	else
-		return -EINVAL;
+		return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
 
@@ -3060,7 +3328,7 @@
  */
 int snd_soc_register_card(struct snd_soc_card *card)
 {
-	int i;
+	int i, ret;
 
 	if (!card->name || !card->dev)
 		return -EINVAL;
@@ -3123,15 +3391,13 @@
 	INIT_LIST_HEAD(&card->dapm_dirty);
 	card->instantiated = 0;
 	mutex_init(&card->mutex);
+	mutex_init(&card->dapm_mutex);
 
-	mutex_lock(&client_mutex);
-	list_add(&card->list, &card_list);
-	snd_soc_instantiate_cards();
-	mutex_unlock(&client_mutex);
+	ret = snd_soc_instantiate_card(card);
+	if (ret != 0)
+		soc_cleanup_card_debugfs(card);
 
-	dev_dbg(card->dev, "Registered card '%s'\n", card->name);
-
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_register_card);
 
@@ -3145,9 +3411,6 @@
 {
 	if (card->instantiated)
 		soc_cleanup_card_resources(card);
-	mutex_lock(&client_mutex);
-	list_del(&card->list);
-	mutex_unlock(&client_mutex);
 	dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
 
 	return 0;
@@ -3221,6 +3484,7 @@
 int snd_soc_register_dai(struct device *dev,
 		struct snd_soc_dai_driver *dai_drv)
 {
+	struct snd_soc_codec *codec;
 	struct snd_soc_dai *dai;
 
 	dev_dbg(dev, "dai register %s\n", dev_name(dev));
@@ -3238,12 +3502,23 @@
 
 	dai->dev = dev;
 	dai->driver = dai_drv;
+	dai->dapm.dev = dev;
 	if (!dai->driver->ops)
 		dai->driver->ops = &null_dai_ops;
 
 	mutex_lock(&client_mutex);
+
+	list_for_each_entry(codec, &codec_list, list) {
+		if (codec->dev == dev) {
+			dev_dbg(dev, "Mapped DAI %s to CODEC %s\n",
+				dai->name, codec->name);
+			dai->codec = codec;
+			break;
+		}
+	}
+
 	list_add(&dai->list, &dai_list);
-	snd_soc_instantiate_cards();
+
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered DAI '%s'\n", dai->name);
@@ -3287,6 +3562,7 @@
 int snd_soc_register_dais(struct device *dev,
 		struct snd_soc_dai_driver *dai_drv, size_t count)
 {
+	struct snd_soc_codec *codec;
 	struct snd_soc_dai *dai;
 	int i, ret = 0;
 
@@ -3314,19 +3590,28 @@
 			dai->id = dai->driver->id;
 		else
 			dai->id = i;
+		dai->dapm.dev = dev;
 		if (!dai->driver->ops)
 			dai->driver->ops = &null_dai_ops;
 
 		mutex_lock(&client_mutex);
+
+		list_for_each_entry(codec, &codec_list, list) {
+			if (codec->dev == dev) {
+				dev_dbg(dev, "Mapped DAI %s to CODEC %s\n",
+					dai->name, codec->name);
+				dai->codec = codec;
+				break;
+			}
+		}
+
 		list_add(&dai->list, &dai_list);
+
 		mutex_unlock(&client_mutex);
 
 		pr_debug("Registered DAI '%s'\n", dai->name);
 	}
 
-	mutex_lock(&client_mutex);
-	snd_soc_instantiate_cards();
-	mutex_unlock(&client_mutex);
 	return 0;
 
 err:
@@ -3384,7 +3669,6 @@
 
 	mutex_lock(&client_mutex);
 	list_add(&platform->list, &platform_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered platform '%s'\n", platform->name);
@@ -3534,18 +3818,18 @@
 		fixup_codec_formats(&dai_drv[i].capture);
 	}
 
+	mutex_lock(&client_mutex);
+	list_add(&codec->list, &codec_list);
+	mutex_unlock(&client_mutex);
+
 	/* register any DAIs */
 	if (num_dai) {
 		ret = snd_soc_register_dais(dev, dai_drv, num_dai);
 		if (ret < 0)
-			goto fail;
+			dev_err(codec->dev, "Failed to regster DAIs: %d\n",
+				ret);
 	}
 
-	mutex_lock(&client_mutex);
-	list_add(&codec->list, &codec_list);
-	snd_soc_instantiate_cards();
-	mutex_unlock(&client_mutex);
-
 	pr_debug("Registered codec '%s'\n", codec->name);
 	return 0;
 
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1bb6d4a..90ee77d 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -52,6 +52,7 @@
 	[snd_soc_dapm_supply] = 1,
 	[snd_soc_dapm_regulator_supply] = 1,
 	[snd_soc_dapm_micbias] = 2,
+	[snd_soc_dapm_dai_link] = 2,
 	[snd_soc_dapm_dai] = 3,
 	[snd_soc_dapm_aif_in] = 3,
 	[snd_soc_dapm_aif_out] = 3,
@@ -90,9 +91,10 @@
 	[snd_soc_dapm_aif_in] = 10,
 	[snd_soc_dapm_aif_out] = 10,
 	[snd_soc_dapm_dai] = 10,
-	[snd_soc_dapm_regulator_supply] = 11,
-	[snd_soc_dapm_supply] = 11,
-	[snd_soc_dapm_post] = 12,
+	[snd_soc_dapm_dai_link] = 11,
+	[snd_soc_dapm_regulator_supply] = 12,
+	[snd_soc_dapm_supply] = 12,
+	[snd_soc_dapm_post] = 13,
 };
 
 static void pop_wait(u32 pop_time)
@@ -208,7 +210,23 @@
 	return -1;
 }
 
-static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
+static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
+{
+	if (w->codec && !w->codec->using_regmap)
+		mutex_lock(&w->codec->mutex);
+	else if (w->platform)
+		mutex_lock(&w->platform->mutex);
+}
+
+static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
+{
+	if (w->codec && !w->codec->using_regmap)
+		mutex_unlock(&w->codec->mutex);
+	else if (w->platform)
+		mutex_unlock(&w->platform->mutex);
+}
+
+static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
 	unsigned short reg, unsigned int mask, unsigned int value)
 {
 	bool change;
@@ -221,18 +239,24 @@
 		if (ret != 0)
 			return ret;
 	} else {
+		soc_widget_lock(w);
 		ret = soc_widget_read(w, reg);
-		if (ret < 0)
+		if (ret < 0) {
+			soc_widget_unlock(w);
 			return ret;
+		}
 
 		old = ret;
 		new = (old & ~mask) | (value & mask);
 		change = old != new;
 		if (change) {
 			ret = soc_widget_write(w, reg, new);
-			if (ret < 0)
+			if (ret < 0) {
+				soc_widget_unlock(w);
 				return ret;
+			}
 		}
+		soc_widget_unlock(w);
 	}
 
 	return change;
@@ -374,6 +398,7 @@
 	case snd_soc_dapm_mic:
 	case snd_soc_dapm_spk:
 	case snd_soc_dapm_line:
+	case snd_soc_dapm_dai_link:
 		p->connect = 1;
 	break;
 	/* does affect routing - dynamically connected */
@@ -682,11 +707,51 @@
 	}
 }
 
+/* add widget to list if it's not already in the list */
+static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
+	struct snd_soc_dapm_widget *w)
+{
+	struct snd_soc_dapm_widget_list *wlist;
+	int wlistsize, wlistentries, i;
+
+	if (*list == NULL)
+		return -EINVAL;
+
+	wlist = *list;
+
+	/* is this widget already in the list */
+	for (i = 0; i < wlist->num_widgets; i++) {
+		if (wlist->widgets[i] == w)
+			return 0;
+	}
+
+	/* allocate some new space */
+	wlistentries = wlist->num_widgets + 1;
+	wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+			wlistentries * sizeof(struct snd_soc_dapm_widget *);
+	*list = krealloc(wlist, wlistsize, GFP_KERNEL);
+	if (*list == NULL) {
+		dev_err(w->dapm->dev, "can't allocate widget list for %s\n",
+			w->name);
+		return -ENOMEM;
+	}
+	wlist = *list;
+
+	/* insert the widget */
+	dev_dbg(w->dapm->dev, "added %s in widget list pos %d\n",
+			w->name, wlist->num_widgets);
+
+	wlist->widgets[wlist->num_widgets] = w;
+	wlist->num_widgets++;
+	return 1;
+}
+
 /*
  * Recursively check for a completed path to an active or physically connected
  * output widget. Returns number of complete paths.
  */
-static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
+static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
+	struct snd_soc_dapm_widget_list **list)
 {
 	struct snd_soc_dapm_path *path;
 	int con = 0;
@@ -742,9 +807,23 @@
 		if (path->walked)
 			continue;
 
+		trace_snd_soc_dapm_output_path(widget, path);
+
 		if (path->sink && path->connect) {
 			path->walked = 1;
-			con += is_connected_output_ep(path->sink);
+
+			/* do we need to add this widget to the list ? */
+			if (list) {
+				int err;
+				err = dapm_list_add_widget(list, path->sink);
+				if (err < 0) {
+					dev_err(widget->dapm->dev, "could not add widget %s\n",
+						widget->name);
+					return con;
+				}
+			}
+
+			con += is_connected_output_ep(path->sink, list);
 		}
 	}
 
@@ -757,7 +836,8 @@
  * Recursively check for a completed path to an active or physically connected
  * input widget. Returns number of complete paths.
  */
-static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
+static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
+	struct snd_soc_dapm_widget_list **list)
 {
 	struct snd_soc_dapm_path *path;
 	int con = 0;
@@ -825,9 +905,23 @@
 		if (path->walked)
 			continue;
 
+		trace_snd_soc_dapm_input_path(widget, path);
+
 		if (path->source && path->connect) {
 			path->walked = 1;
-			con += is_connected_input_ep(path->source);
+
+			/* do we need to add this widget to the list ? */
+			if (list) {
+				int err;
+				err = dapm_list_add_widget(list, path->sink);
+				if (err < 0) {
+					dev_err(widget->dapm->dev, "could not add widget %s\n",
+						widget->name);
+					return con;
+				}
+			}
+
+			con += is_connected_input_ep(path->source, list);
 		}
 	}
 
@@ -836,6 +930,39 @@
 	return con;
 }
 
+/**
+ * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
+ * @dai: the soc DAI.
+ * @stream: stream direction.
+ * @list: list of active widgets for this stream.
+ *
+ * Queries DAPM graph as to whether an valid audio stream path exists for
+ * the initial stream specified by name. This takes into account
+ * current mixer and mux kcontrol settings. Creates list of valid widgets.
+ *
+ * Returns the number of valid paths or negative error.
+ */
+int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
+	struct snd_soc_dapm_widget_list **list)
+{
+	struct snd_soc_card *card = dai->card;
+	int paths;
+
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	dapm_reset(card);
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		paths = is_connected_output_ep(dai->playback_widget, list);
+	else
+		paths = is_connected_input_ep(dai->playback_widget, list);
+
+	trace_snd_soc_dapm_connected(paths, stream);
+	dapm_clear_walk(&card->dapm);
+	mutex_unlock(&card->dapm_mutex);
+
+	return paths;
+}
+
 /*
  * Handler for generic register modifier widget.
  */
@@ -849,7 +976,7 @@
 	else
 		val = w->off_val;
 
-	soc_widget_update_bits(w, -(w->reg + 1),
+	soc_widget_update_bits_locked(w, -(w->reg + 1),
 			    w->mask << w->shift, val << w->shift);
 
 	return 0;
@@ -863,9 +990,9 @@
 		   struct snd_kcontrol *kcontrol, int event)
 {
 	if (SND_SOC_DAPM_EVENT_ON(event))
-		return regulator_enable(w->priv);
+		return regulator_enable(w->regulator);
 	else
-		return regulator_disable_deferred(w->priv, w->shift);
+		return regulator_disable_deferred(w->regulator, w->shift);
 }
 EXPORT_SYMBOL_GPL(dapm_regulator_event);
 
@@ -892,9 +1019,9 @@
 
 	DAPM_UPDATE_STAT(w, power_checks);
 
-	in = is_connected_input_ep(w);
+	in = is_connected_input_ep(w, NULL);
 	dapm_clear_walk(w->dapm);
-	out = is_connected_output_ep(w);
+	out = is_connected_output_ep(w, NULL);
 	dapm_clear_walk(w->dapm);
 	return out != 0 && in != 0;
 }
@@ -903,7 +1030,10 @@
 {
 	DAPM_UPDATE_STAT(w, power_checks);
 
-	return w->active;
+	if (w->active)
+		return w->active;
+
+	return dapm_generic_check_power(w);
 }
 
 /* Check to see if an ADC has power */
@@ -914,7 +1044,7 @@
 	DAPM_UPDATE_STAT(w, power_checks);
 
 	if (w->active) {
-		in = is_connected_input_ep(w);
+		in = is_connected_input_ep(w, NULL);
 		dapm_clear_walk(w->dapm);
 		return in != 0;
 	} else {
@@ -930,7 +1060,7 @@
 	DAPM_UPDATE_STAT(w, power_checks);
 
 	if (w->active) {
-		out = is_connected_output_ep(w);
+		out = is_connected_output_ep(w, NULL);
 		dapm_clear_walk(w->dapm);
 		return out != 0;
 	} else {
@@ -1107,7 +1237,7 @@
 			"pop test : Applying 0x%x/0x%x to %x in %dms\n",
 			value, mask, reg, card->pop_time);
 		pop_wait(card->pop_time);
-		soc_widget_update_bits(w, reg, mask, value);
+		soc_widget_update_bits_locked(w, reg, mask, value);
 	}
 
 	list_for_each_entry(w, pending, power_list) {
@@ -1237,7 +1367,7 @@
 			       w->name, ret);
 	}
 
-	ret = snd_soc_update_bits(w->codec, update->reg, update->mask,
+	ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
 				  update->val);
 	if (ret < 0)
 		pr_err("%s DAPM update failed: %d\n", w->name, ret);
@@ -1421,12 +1551,10 @@
 	trace_snd_soc_dapm_start(card);
 
 	list_for_each_entry(d, &card->dapm_list, list) {
-		if (d->n_widgets || d->codec == NULL) {
-			if (d->idle_bias_off)
-				d->target_bias_level = SND_SOC_BIAS_OFF;
-			else
-				d->target_bias_level = SND_SOC_BIAS_STANDBY;
-		}
+		if (d->idle_bias_off)
+			d->target_bias_level = SND_SOC_BIAS_OFF;
+		else
+			d->target_bias_level = SND_SOC_BIAS_STANDBY;
 	}
 
 	dapm_reset(card);
@@ -1471,32 +1599,6 @@
 
 	}
 
-	/* If there are no DAPM widgets then try to figure out power from the
-	 * event type.
-	 */
-	if (!dapm->n_widgets) {
-		switch (event) {
-		case SND_SOC_DAPM_STREAM_START:
-		case SND_SOC_DAPM_STREAM_RESUME:
-			dapm->target_bias_level = SND_SOC_BIAS_ON;
-			break;
-		case SND_SOC_DAPM_STREAM_STOP:
-			if (dapm->codec && dapm->codec->active)
-				dapm->target_bias_level = SND_SOC_BIAS_ON;
-			else
-				dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
-			break;
-		case SND_SOC_DAPM_STREAM_SUSPEND:
-			dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
-			break;
-		case SND_SOC_DAPM_STREAM_NOP:
-			dapm->target_bias_level = dapm->bias_level;
-			break;
-		default:
-			break;
-		}
-	}
-
 	/* Force all contexts in the card to the same bias state if
 	 * they're not ground referenced.
 	 */
@@ -1560,9 +1662,9 @@
 	if (!buf)
 		return -ENOMEM;
 
-	in = is_connected_input_ep(w);
+	in = is_connected_input_ep(w, NULL);
 	dapm_clear_walk(w->dapm);
-	out = is_connected_output_ep(w);
+	out = is_connected_output_ep(w, NULL);
 	dapm_clear_walk(w->dapm);
 
 	ret = snprintf(buf, PAGE_SIZE, "%s: %s%s  in %d out %d",
@@ -1709,7 +1811,7 @@
 #endif
 
 /* test and update the power status of a mux widget */
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
 				 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
 {
 	struct snd_soc_dapm_path *path;
@@ -1746,12 +1848,26 @@
 		dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
 	}
 
-	return 0;
+	return found;
+}
+
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+		struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
+{
+	struct snd_soc_card *card = widget->dapm->card;
+	int ret;
+
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+	mutex_unlock(&card->dapm_mutex);
+	if (ret > 0)
+		soc_dpcm_runtime_update(widget);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
 
 /* test and update the power status of a mixer or switch widget */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 				   struct snd_kcontrol *kcontrol, int connect)
 {
 	struct snd_soc_dapm_path *path;
@@ -1778,7 +1894,21 @@
 		dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
 	}
 
-	return 0;
+	return found;
+}
+
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+				struct snd_kcontrol *kcontrol, int connect)
+{
+	struct snd_soc_card *card = widget->dapm->card;
+	int ret;
+
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+	mutex_unlock(&card->dapm_mutex);
+	if (ret > 0)
+		soc_dpcm_runtime_update(widget);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
 
@@ -1939,6 +2069,8 @@
  */
 int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
 {
+	int ret;
+
 	/*
 	 * Suppress early reports (eg, jacks syncing their state) to avoid
 	 * silly DAPM runs during card startup.
@@ -1946,7 +2078,10 @@
 	if (!dapm->card || !dapm->card->instantiated)
 		return 0;
 
-	return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	mutex_unlock(&dapm->card->dapm_mutex);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
@@ -2055,6 +2190,7 @@
 	case snd_soc_dapm_aif_in:
 	case snd_soc_dapm_aif_out:
 	case snd_soc_dapm_dai:
+	case snd_soc_dapm_dai_link:
 		list_add(&path->list, &dapm->card->paths);
 		list_add(&path->list_sink, &wsink->sources);
 		list_add(&path->list_source, &wsource->sinks);
@@ -2110,19 +2246,21 @@
 int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
 			    const struct snd_soc_dapm_route *route, int num)
 {
-	int i, ret;
+	int i, ret = 0;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
 		ret = snd_soc_dapm_add_route(dapm, route);
 		if (ret < 0) {
 			dev_err(dapm->dev, "Failed to add route %s->%s\n",
 				route->source, route->sink);
-			return ret;
+			break;
 		}
 		route++;
 	}
+	mutex_unlock(&dapm->card->dapm_mutex);
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
 
@@ -2193,12 +2331,14 @@
 	int i, err;
 	int ret = 0;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
 		err = snd_soc_dapm_weak_route(dapm, route);
 		if (err)
 			ret = err;
 		route++;
 	}
+	mutex_unlock(&dapm->card->dapm_mutex);
 
 	return ret;
 }
@@ -2217,6 +2357,8 @@
 	struct snd_soc_dapm_widget *w;
 	unsigned int val;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+
 	list_for_each_entry(w, &dapm->card->widgets, list)
 	{
 		if (w->new)
@@ -2226,8 +2368,10 @@
 			w->kcontrols = kzalloc(w->num_kcontrols *
 						sizeof(struct snd_kcontrol *),
 						GFP_KERNEL);
-			if (!w->kcontrols)
+			if (!w->kcontrols) {
+				mutex_unlock(&dapm->card->dapm_mutex);
 				return -ENOMEM;
+			}
 		}
 
 		switch(w->id) {
@@ -2267,6 +2411,7 @@
 	}
 
 	dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	mutex_unlock(&dapm->card->dapm_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2326,6 +2471,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
@@ -2352,7 +2498,7 @@
 		/* old connection must be powered down */
 		connect = invert ? 1 : 0;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	change = snd_soc_test_bits(widget->codec, reg, mask, val);
 	if (change) {
@@ -2368,13 +2514,13 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
+			soc_dapm_mixer_update_power(widget, kcontrol, connect);
 
 			widget->dapm->update = NULL;
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -2423,6 +2569,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask, bitmask;
@@ -2443,7 +2590,7 @@
 		mask |= (bitmask - 1) << e->shift_r;
 	}
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
 	if (change) {
@@ -2459,13 +2606,13 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+			soc_dapm_mux_update_power(widget, kcontrol, mux, e);
 
 			widget->dapm->update = NULL;
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -2502,6 +2649,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e =
 		(struct soc_enum *)kcontrol->private_value;
 	int change;
@@ -2511,7 +2659,7 @@
 	if (ucontrol->value.enumerated.item[0] >= e->max)
 		return -EINVAL;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	change = widget->value != ucontrol->value.enumerated.item[0];
 	if (change) {
@@ -2520,11 +2668,11 @@
 
 			widget->value = ucontrol->value.enumerated.item[0];
 
-			snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
+			soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2589,6 +2737,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask;
@@ -2607,7 +2756,7 @@
 		mask |= e->mask << e->shift_r;
 	}
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
 	if (change) {
@@ -2623,13 +2772,13 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+			soc_dapm_mux_update_power(widget, kcontrol, mux, e);
 
 			widget->dapm->update = NULL;
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2666,12 +2815,12 @@
 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 	const char *pin = (const char *)kcontrol->private_value;
 
-	mutex_lock(&card->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	ucontrol->value.integer.value[0] =
 		snd_soc_dapm_get_pin_status(&card->dapm, pin);
 
-	mutex_unlock(&card->mutex);
+	mutex_unlock(&card->dapm_mutex);
 
 	return 0;
 }
@@ -2689,17 +2838,16 @@
 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 	const char *pin = (const char *)kcontrol->private_value;
 
-	mutex_lock(&card->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	if (ucontrol->value.integer.value[0])
 		snd_soc_dapm_enable_pin(&card->dapm, pin);
 	else
 		snd_soc_dapm_disable_pin(&card->dapm, pin);
 
+	mutex_unlock(&card->dapm_mutex);
+
 	snd_soc_dapm_sync(&card->dapm);
-
-	mutex_unlock(&card->mutex);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
@@ -2717,9 +2865,9 @@
 
 	switch (w->id) {
 	case snd_soc_dapm_regulator_supply:
-		w->priv = devm_regulator_get(dapm->dev, w->name);
-		if (IS_ERR(w->priv)) {
-			ret = PTR_ERR(w->priv);
+		w->regulator = devm_regulator_get(dapm->dev, w->name);
+		if (IS_ERR(w->regulator)) {
+			ret = PTR_ERR(w->regulator);
 			dev_err(dapm->dev, "Failed to request %s: %d\n",
 				w->name, ret);
 			return NULL;
@@ -2771,6 +2919,7 @@
 	case snd_soc_dapm_hp:
 	case snd_soc_dapm_mic:
 	case snd_soc_dapm_line:
+	case snd_soc_dapm_dai_link:
 		w->power_check = dapm_generic_check_power;
 		break;
 	case snd_soc_dapm_supply:
@@ -2816,21 +2965,177 @@
 {
 	struct snd_soc_dapm_widget *w;
 	int i;
+	int ret = 0;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
 		w = snd_soc_dapm_new_control(dapm, widget);
 		if (!w) {
 			dev_err(dapm->dev,
 				"ASoC: Failed to create DAPM control %s\n",
 				widget->name);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			break;
 		}
 		widget++;
 	}
-	return 0;
+	mutex_unlock(&dapm->card->dapm_mutex);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
 
+static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_dapm_path *source_p, *sink_p;
+	struct snd_soc_dai *source, *sink;
+	const struct snd_soc_pcm_stream *config = w->params;
+	struct snd_pcm_substream substream;
+	struct snd_pcm_hw_params *params = NULL;
+	u64 fmt;
+	int ret;
+
+	BUG_ON(!config);
+	BUG_ON(list_empty(&w->sources) || list_empty(&w->sinks));
+
+	/* We only support a single source and sink, pick the first */
+	source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
+				    list_sink);
+	sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
+				  list_source);
+
+	BUG_ON(!source_p || !sink_p);
+	BUG_ON(!sink_p->source || !source_p->sink);
+	BUG_ON(!source_p->source || !sink_p->sink);
+
+	source = source_p->source->priv;
+	sink = sink_p->sink->priv;
+
+	/* Be a little careful as we don't want to overflow the mask array */
+	if (config->formats) {
+		fmt = ffs(config->formats) - 1;
+	} else {
+		dev_warn(w->dapm->dev, "Invalid format %llx specified\n",
+			 config->formats);
+		fmt = 0;
+	}
+
+	/* Currently very limited parameter selection */
+	params = kzalloc(sizeof(*params), GFP_KERNEL);
+	if (!params) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
+
+	hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
+		config->rate_min;
+	hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
+		config->rate_max;
+
+	hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
+		= config->channels_min;
+	hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
+		= config->channels_max;
+
+	memset(&substream, 0, sizeof(substream));
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (source->driver->ops && source->driver->ops->hw_params) {
+			substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+			ret = source->driver->ops->hw_params(&substream,
+							     params, source);
+			if (ret != 0) {
+				dev_err(source->dev,
+					"hw_params() failed: %d\n", ret);
+				goto out;
+			}
+		}
+
+		if (sink->driver->ops && sink->driver->ops->hw_params) {
+			substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+			ret = sink->driver->ops->hw_params(&substream, params,
+							   sink);
+			if (ret != 0) {
+				dev_err(sink->dev,
+					"hw_params() failed: %d\n", ret);
+				goto out;
+			}
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		ret = snd_soc_dai_digital_mute(sink, 0);
+		if (ret != 0 && ret != -ENOTSUPP)
+			dev_warn(sink->dev, "Failed to unmute: %d\n", ret);
+		ret = 0;
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		ret = snd_soc_dai_digital_mute(sink, 1);
+		if (ret != 0 && ret != -ENOTSUPP)
+			dev_warn(sink->dev, "Failed to mute: %d\n", ret);
+		ret = 0;
+		break;
+
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+out:
+	kfree(params);
+	return ret;
+}
+
+int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
+			 const struct snd_soc_pcm_stream *params,
+			 struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_dapm_route routes[2];
+	struct snd_soc_dapm_widget template;
+	struct snd_soc_dapm_widget *w;
+	size_t len;
+	char *link_name;
+
+	len = strlen(source->name) + strlen(sink->name) + 2;
+	link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
+	if (!link_name)
+		return -ENOMEM;
+	snprintf(link_name, len, "%s-%s", source->name, sink->name);
+
+	memset(&template, 0, sizeof(template));
+	template.reg = SND_SOC_NOPM;
+	template.id = snd_soc_dapm_dai_link;
+	template.name = link_name;
+	template.event = snd_soc_dai_link_event;
+	template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD;
+
+	dev_dbg(card->dev, "adding %s widget\n", link_name);
+
+	w = snd_soc_dapm_new_control(&card->dapm, &template);
+	if (!w) {
+		dev_err(card->dev, "Failed to create %s widget\n",
+			link_name);
+		return -ENOMEM;
+	}
+
+	w->params = params;
+
+	memset(&routes, 0, sizeof(routes));
+
+	routes[0].source = source->name;
+	routes[0].sink = link_name;
+	routes[1].source = link_name;
+	routes[1].sink = sink->name;
+
+	return snd_soc_dapm_add_routes(&card->dapm, routes,
+				       ARRAY_SIZE(routes));
+}
+
 int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
 				 struct snd_soc_dai *dai)
 {
@@ -2934,37 +3239,61 @@
 	return 0;
 }
 
-static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
-				  int stream, struct snd_soc_dai *dai,
-				  int event)
+static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+	int event)
 {
-	struct snd_soc_dapm_widget *w;
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		w = dai->playback_widget;
-	else
-		w = dai->capture_widget;
+	struct snd_soc_dapm_widget *w_cpu, *w_codec;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
-	if (!w)
-		return;
-
-	dapm_mark_dirty(w, "stream event");
-
-	switch (event) {
-	case SND_SOC_DAPM_STREAM_START:
-		w->active = 1;
-		break;
-	case SND_SOC_DAPM_STREAM_STOP:
-		w->active = 0;
-		break;
-	case SND_SOC_DAPM_STREAM_SUSPEND:
-	case SND_SOC_DAPM_STREAM_RESUME:
-	case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
-	case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
-		break;
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		w_cpu = cpu_dai->playback_widget;
+		w_codec = codec_dai->playback_widget;
+	} else {
+		w_cpu = cpu_dai->capture_widget;
+		w_codec = codec_dai->capture_widget;
 	}
 
-	dapm_power_widgets(dapm, event);
+	if (w_cpu) {
+
+		dapm_mark_dirty(w_cpu, "stream event");
+
+		switch (event) {
+		case SND_SOC_DAPM_STREAM_START:
+			w_cpu->active = 1;
+			break;
+		case SND_SOC_DAPM_STREAM_STOP:
+			w_cpu->active = 0;
+			break;
+		case SND_SOC_DAPM_STREAM_SUSPEND:
+		case SND_SOC_DAPM_STREAM_RESUME:
+		case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+		case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+			break;
+		}
+	}
+
+	if (w_codec) {
+
+		dapm_mark_dirty(w_codec, "stream event");
+
+		switch (event) {
+		case SND_SOC_DAPM_STREAM_START:
+			w_codec->active = 1;
+			break;
+		case SND_SOC_DAPM_STREAM_STOP:
+			w_codec->active = 0;
+			break;
+		case SND_SOC_DAPM_STREAM_SUSPEND:
+		case SND_SOC_DAPM_STREAM_RESUME:
+		case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+		case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+			break;
+		}
+	}
+
+	dapm_power_widgets(&rtd->card->dapm, event);
 }
 
 /**
@@ -2978,15 +3307,14 @@
  *
  * Returns 0 for success else error.
  */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
-			      struct snd_soc_dai *dai, int event)
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+			      int event)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = rtd->card;
 
-	mutex_lock(&codec->mutex);
-	soc_dapm_stream_event(&codec->dapm, stream, dai, event);
-	mutex_unlock(&codec->mutex);
-	return 0;
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	soc_dapm_stream_event(rtd, stream, event);
+	mutex_unlock(&card->dapm_mutex);
 }
 
 /**
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index ee4353f..7f8b3b7 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -36,6 +36,7 @@
 int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
 		     struct snd_soc_jack *jack)
 {
+	mutex_init(&jack->mutex);
 	jack->codec = codec;
 	INIT_LIST_HEAD(&jack->pins);
 	INIT_LIST_HEAD(&jack->jack_zones);
@@ -75,7 +76,7 @@
 	codec = jack->codec;
 	dapm =  &codec->dapm;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&jack->mutex);
 
 	oldstatus = jack->status;
 
@@ -109,7 +110,7 @@
 	snd_jack_report(jack->jack, jack->status);
 
 out:
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&jack->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_report);
 
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 0ad8dca..bedd171 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -22,12 +22,38 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/debugfs.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/soc-dpcm.h>
 #include <sound/initval.h>
 
+#define DPCM_MAX_BE_USERS	8
+
+/* DPCM stream event, send event to FE and all active BEs. */
+static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
+	int event)
+{
+	struct snd_soc_dpcm *dpcm;
+
+	list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) {
+
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+
+		dev_dbg(be->dev, "pm: BE %s event %d dir %d\n",
+				be->dai_link->name, event, dir);
+
+		snd_soc_dapm_stream_event(be, dir, event);
+	}
+
+	snd_soc_dapm_stream_event(fe, dir, event);
+
+	return 0;
+}
+
 static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
 					struct snd_soc_dai *soc_dai)
 {
@@ -156,6 +182,10 @@
 		}
 	}
 
+	/* Dynamic PCM DAI links compat checks use dynamic capabilities */
+	if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
+		goto dynamic;
+
 	/* Check that the codec and cpu DAIs are compatible */
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		runtime->hw.rate_min =
@@ -248,6 +278,7 @@
 	pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
 		 runtime->hw.rate_max);
 
+dynamic:
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		cpu_dai->playback_active++;
 		codec_dai->playback_active++;
@@ -308,7 +339,7 @@
 	if (codec_dai->pop_wait == 1) {
 		codec_dai->pop_wait = 0;
 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
-					  codec_dai, SND_SOC_DAPM_STREAM_STOP);
+					  SND_SOC_DAPM_STREAM_STOP);
 	}
 
 	mutex_unlock(&rtd->pcm_mutex);
@@ -373,7 +404,6 @@
 			/* powered down playback stream now */
 			snd_soc_dapm_stream_event(rtd,
 						  SNDRV_PCM_STREAM_PLAYBACK,
-						  codec_dai,
 						  SND_SOC_DAPM_STREAM_STOP);
 		} else {
 			/* start delayed pop wq here for playback streams */
@@ -384,7 +414,7 @@
 	} else {
 		/* capture streams can be powered down now */
 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
-					  codec_dai, SND_SOC_DAPM_STREAM_STOP);
+					  SND_SOC_DAPM_STREAM_STOP);
 	}
 
 	mutex_unlock(&rtd->pcm_mutex);
@@ -453,8 +483,8 @@
 		cancel_delayed_work(&rtd->delayed_work);
 	}
 
-	snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai,
-				  SND_SOC_DAPM_STREAM_START);
+	snd_soc_dapm_stream_event(rtd, substream->stream,
+			SND_SOC_DAPM_STREAM_START);
 
 	snd_soc_dai_digital_mute(codec_dai, 0);
 
@@ -602,6 +632,34 @@
 	return 0;
 }
 
+static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
+				   int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	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->driver->ops->bespoke_trigger) {
+		ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (platform->driver->bespoke_trigger) {
+		ret = platform->driver->bespoke_trigger(substream, cmd);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (cpu_dai->driver->ops->bespoke_trigger) {
+		ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
 /*
  * soc level wrapper for pointer callback
  * If cpu_dai, codec_dai, platform driver has the delay callback, than
@@ -634,6 +692,1308 @@
 	return offset;
 }
 
+/* connect a FE and BE */
+static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
+		struct snd_soc_pcm_runtime *be, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+
+	/* only add new dpcms */
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+		if (dpcm->be == be && dpcm->fe == fe)
+			return 0;
+	}
+
+	dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
+	if (!dpcm)
+		return -ENOMEM;
+
+	dpcm->be = be;
+	dpcm->fe = fe;
+	be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
+	dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
+	list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
+	list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
+
+	dev_dbg(fe->dev, "  connected new DPCM %s path %s %s %s\n",
+			stream ? "capture" : "playback",  fe->dai_link->name,
+			stream ? "<-" : "->", be->dai_link->name);
+
+#ifdef CONFIG_DEBUG_FS
+	dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
+			fe->debugfs_dpcm_root, &dpcm->state);
+#endif
+	return 1;
+}
+
+/* reparent a BE onto another FE */
+static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
+			struct snd_soc_pcm_runtime *be, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+	struct snd_pcm_substream *fe_substream, *be_substream;
+
+	/* reparent if BE is connected to other FEs */
+	if (!be->dpcm[stream].users)
+		return;
+
+	be_substream = snd_soc_dpcm_get_substream(be, stream);
+
+	list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
+		if (dpcm->fe == fe)
+			continue;
+
+		dev_dbg(fe->dev, "  reparent %s path %s %s %s\n",
+			stream ? "capture" : "playback",
+			dpcm->fe->dai_link->name,
+			stream ? "<-" : "->", dpcm->be->dai_link->name);
+
+		fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
+		be_substream->runtime = fe_substream->runtime;
+		break;
+	}
+}
+
+/* disconnect a BE and FE */
+static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_soc_dpcm *dpcm, *d;
+
+	list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) {
+		dev_dbg(fe->dev, "BE %s disconnect check for %s\n",
+				stream ? "capture" : "playback",
+				dpcm->be->dai_link->name);
+
+		if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
+			continue;
+
+		dev_dbg(fe->dev, "  freed DSP %s path %s %s %s\n",
+			stream ? "capture" : "playback", fe->dai_link->name,
+			stream ? "<-" : "->", dpcm->be->dai_link->name);
+
+		/* BEs still alive need new FE */
+		dpcm_be_reparent(fe, dpcm->be, stream);
+
+#ifdef CONFIG_DEBUG_FS
+		debugfs_remove(dpcm->debugfs_state);
+#endif
+		list_del(&dpcm->list_be);
+		list_del(&dpcm->list_fe);
+		kfree(dpcm);
+	}
+}
+
+/* get BE for DAI widget and stream */
+static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
+		struct snd_soc_dapm_widget *widget, int stream)
+{
+	struct snd_soc_pcm_runtime *be;
+	int i;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		for (i = 0; i < card->num_links; i++) {
+			be = &card->rtd[i];
+
+			if (be->cpu_dai->playback_widget == widget ||
+				be->codec_dai->playback_widget == widget)
+				return be;
+		}
+	} else {
+
+		for (i = 0; i < card->num_links; i++) {
+			be = &card->rtd[i];
+
+			if (be->cpu_dai->capture_widget == widget ||
+				be->codec_dai->capture_widget == widget)
+				return be;
+		}
+	}
+
+	dev_err(card->dev, "can't get %s BE for %s\n",
+		stream ? "capture" : "playback", widget->name);
+	return NULL;
+}
+
+static inline struct snd_soc_dapm_widget *
+	rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return rtd->cpu_dai->playback_widget;
+	else
+		return rtd->cpu_dai->capture_widget;
+}
+
+static inline struct snd_soc_dapm_widget *
+	rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return rtd->codec_dai->playback_widget;
+	else
+		return rtd->codec_dai->capture_widget;
+}
+
+static int widget_in_list(struct snd_soc_dapm_widget_list *list,
+		struct snd_soc_dapm_widget *widget)
+{
+	int i;
+
+	for (i = 0; i < list->num_widgets; i++) {
+		if (widget == list->widgets[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+static int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
+	int stream, struct snd_soc_dapm_widget_list **list_)
+{
+	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+	struct snd_soc_dapm_widget_list *list;
+	int paths;
+
+	list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) +
+			sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL);
+	if (list == NULL)
+		return -ENOMEM;
+
+	/* get number of valid DAI paths and their widgets */
+	paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list);
+
+	dev_dbg(fe->dev, "found %d audio %s paths\n", paths,
+			stream ? "capture" : "playback");
+
+	*list_ = list;
+	return paths;
+}
+
+static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
+{
+	kfree(*list);
+}
+
+static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
+	struct snd_soc_dapm_widget_list **list_)
+{
+	struct snd_soc_dpcm *dpcm;
+	struct snd_soc_dapm_widget_list *list = *list_;
+	struct snd_soc_dapm_widget *widget;
+	int prune = 0;
+
+	/* Destroy any old FE <--> BE connections */
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+		/* is there a valid CPU DAI widget for this BE */
+		widget = rtd_get_cpu_widget(dpcm->be, stream);
+
+		/* prune the BE if it's no longer in our active list */
+		if (widget && widget_in_list(list, widget))
+			continue;
+
+		/* is there a valid CODEC DAI widget for this BE */
+		widget = rtd_get_codec_widget(dpcm->be, stream);
+
+		/* prune the BE if it's no longer in our active list */
+		if (widget && widget_in_list(list, widget))
+			continue;
+
+		dev_dbg(fe->dev, "pruning %s BE %s for %s\n",
+			stream ? "capture" : "playback",
+			dpcm->be->dai_link->name, fe->dai_link->name);
+		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+		dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+		prune++;
+	}
+
+	dev_dbg(fe->dev, "found %d old BE paths for pruning\n", prune);
+	return prune;
+}
+
+static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
+	struct snd_soc_dapm_widget_list **list_)
+{
+	struct snd_soc_card *card = fe->card;
+	struct snd_soc_dapm_widget_list *list = *list_;
+	struct snd_soc_pcm_runtime *be;
+	int i, new = 0, err;
+
+	/* Create any new FE <--> BE connections */
+	for (i = 0; i < list->num_widgets; i++) {
+
+		if (list->widgets[i]->id != snd_soc_dapm_dai)
+			continue;
+
+		/* is there a valid BE rtd for this widget */
+		be = dpcm_get_be(card, list->widgets[i], stream);
+		if (!be) {
+			dev_err(fe->dev, "no BE found for %s\n",
+					list->widgets[i]->name);
+			continue;
+		}
+
+		/* make sure BE is a real BE */
+		if (!be->dai_link->no_pcm)
+			continue;
+
+		/* don't connect if FE is not running */
+		if (!fe->dpcm[stream].runtime)
+			continue;
+
+		/* newly connected FE and BE */
+		err = dpcm_be_connect(fe, be, stream);
+		if (err < 0) {
+			dev_err(fe->dev, "can't connect %s\n",
+				list->widgets[i]->name);
+			break;
+		} else if (err == 0) /* already connected */
+			continue;
+
+		/* new */
+		be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+		new++;
+	}
+
+	dev_dbg(fe->dev, "found %d new BE paths\n", new);
+	return new;
+}
+
+/*
+ * Find the corresponding BE DAIs that source or sink audio to this
+ * FE substream.
+ */
+static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
+	int stream, struct snd_soc_dapm_widget_list **list, int new)
+{
+	if (new)
+		return dpcm_add_paths(fe, stream, list);
+	else
+		return dpcm_prune_paths(fe, stream, list);
+}
+
+static void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+		dpcm->be->dpcm[stream].runtime_update =
+						SND_SOC_DPCM_UPDATE_NO;
+}
+
+static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
+	int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+
+	/* disable any enabled and non active backends */
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+
+		if (be->dpcm[stream].users == 0)
+			dev_err(be->dev, "no users %s at close - state %d\n",
+				stream ? "capture" : "playback",
+				be->dpcm[stream].state);
+
+		if (--be->dpcm[stream].users != 0)
+			continue;
+
+		if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
+			continue;
+
+		soc_pcm_close(be_substream);
+		be_substream->runtime = NULL;
+		be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+	}
+}
+
+static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+	int err, count = 0;
+
+	/* only startup BE DAIs that are either sinks or sources to this FE DAI */
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+
+		/* is this op for this BE ? */
+		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+			continue;
+
+		/* first time the dpcm is open ? */
+		if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
+			dev_err(be->dev, "too many users %s at open %d\n",
+				stream ? "capture" : "playback",
+				be->dpcm[stream].state);
+
+		if (be->dpcm[stream].users++ != 0)
+			continue;
+
+		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
+			continue;
+
+		dev_dbg(be->dev, "dpcm: open BE %s\n", be->dai_link->name);
+
+		be_substream->runtime = be->dpcm[stream].runtime;
+		err = soc_pcm_open(be_substream);
+		if (err < 0) {
+			dev_err(be->dev, "BE open failed %d\n", err);
+			be->dpcm[stream].users--;
+			if (be->dpcm[stream].users < 0)
+				dev_err(be->dev, "no users %s at unwind %d\n",
+					stream ? "capture" : "playback",
+					be->dpcm[stream].state);
+
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+			goto unwind;
+		}
+
+		be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
+		count++;
+	}
+
+	return count;
+
+unwind:
+	/* disable any enabled and non active backends */
+	list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+
+		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+			continue;
+
+		if (be->dpcm[stream].users == 0)
+			dev_err(be->dev, "no users %s at close %d\n",
+				stream ? "capture" : "playback",
+				be->dpcm[stream].state);
+
+		if (--be->dpcm[stream].users != 0)
+			continue;
+
+		if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
+			continue;
+
+		soc_pcm_close(be_substream);
+		be_substream->runtime = NULL;
+		be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+	}
+
+	return err;
+}
+
+static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->hw.rate_min = cpu_dai_drv->playback.rate_min;
+		runtime->hw.rate_max = cpu_dai_drv->playback.rate_max;
+		runtime->hw.channels_min = cpu_dai_drv->playback.channels_min;
+		runtime->hw.channels_max = cpu_dai_drv->playback.channels_max;
+		runtime->hw.formats &= cpu_dai_drv->playback.formats;
+		runtime->hw.rates = cpu_dai_drv->playback.rates;
+	} else {
+		runtime->hw.rate_min = cpu_dai_drv->capture.rate_min;
+		runtime->hw.rate_max = cpu_dai_drv->capture.rate_max;
+		runtime->hw.channels_min = cpu_dai_drv->capture.channels_min;
+		runtime->hw.channels_max = cpu_dai_drv->capture.channels_max;
+		runtime->hw.formats &= cpu_dai_drv->capture.formats;
+		runtime->hw.rates = cpu_dai_drv->capture.rates;
+	}
+}
+
+static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
+{
+	struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+	struct snd_pcm_runtime *runtime = fe_substream->runtime;
+	int stream = fe_substream->stream, ret = 0;
+
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+	ret = dpcm_be_dai_startup(fe, fe_substream->stream);
+	if (ret < 0) {
+		dev_err(fe->dev,"dpcm: failed to start some BEs %d\n", ret);
+		goto be_err;
+	}
+
+	dev_dbg(fe->dev, "dpcm: open FE %s\n", fe->dai_link->name);
+
+	/* start the DAI frontend */
+	ret = soc_pcm_open(fe_substream);
+	if (ret < 0) {
+		dev_err(fe->dev,"dpcm: failed to start FE %d\n", ret);
+		goto unwind;
+	}
+
+	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
+
+	dpcm_set_fe_runtime(fe_substream);
+	snd_pcm_limit_hw_rates(runtime);
+
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+	return 0;
+
+unwind:
+	dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
+be_err:
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+	return ret;
+}
+
+static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+
+	/* only shutdown BEs that are either sinks or sources to this FE DAI */
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+
+		/* is this op for this BE ? */
+		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+			continue;
+
+		if (be->dpcm[stream].users == 0)
+			dev_err(be->dev, "no users %s at close - state %d\n",
+				stream ? "capture" : "playback",
+				be->dpcm[stream].state);
+
+		if (--be->dpcm[stream].users != 0)
+			continue;
+
+		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN))
+			continue;
+
+		dev_dbg(be->dev, "dpcm: close BE %s\n",
+			dpcm->fe->dai_link->name);
+
+		soc_pcm_close(be_substream);
+		be_substream->runtime = NULL;
+
+		be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+	}
+	return 0;
+}
+
+static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *fe = substream->private_data;
+	int stream = substream->stream;
+
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+	/* shutdown the BEs */
+	dpcm_be_dai_shutdown(fe, substream->stream);
+
+	dev_dbg(fe->dev, "dpcm: close FE %s\n", fe->dai_link->name);
+
+	/* now shutdown the frontend */
+	soc_pcm_close(substream);
+
+	/* run the stream event for each BE */
+	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
+
+	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+	return 0;
+}
+
+static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+
+	/* only hw_params backends that are either sinks or sources
+	 * to this frontend DAI */
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+
+		/* is this op for this BE ? */
+		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+			continue;
+
+		/* only free hw when no longer used - check all FEs */
+		if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+				continue;
+
+		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+			continue;
+
+		dev_dbg(be->dev, "dpcm: hw_free BE %s\n",
+			dpcm->fe->dai_link->name);
+
+		soc_pcm_hw_free(be_substream);
+
+		be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
+	}
+
+	return 0;
+}
+
+static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *fe = substream->private_data;
+	int err, stream = substream->stream;
+
+	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+	dev_dbg(fe->dev, "dpcm: hw_free FE %s\n", fe->dai_link->name);
+
+	/* call hw_free on the frontend */
+	err = soc_pcm_hw_free(substream);
+	if (err < 0)
+		dev_err(fe->dev,"dpcm: hw_free FE %s failed\n",
+			fe->dai_link->name);
+
+	/* only hw_params backends that are either sinks or sources
+	 * to this frontend DAI */
+	err = dpcm_be_dai_hw_free(fe, stream);
+
+	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+	mutex_unlock(&fe->card->mutex);
+	return 0;
+}
+
+static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+	int ret;
+
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+
+		/* is this op for this BE ? */
+		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+			continue;
+
+		/* only allow hw_params() if no connected FEs are running */
+		if (!snd_soc_dpcm_can_be_params(fe, be, stream))
+			continue;
+
+		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
+			continue;
+
+		dev_dbg(be->dev, "dpcm: hw_params BE %s\n",
+			dpcm->fe->dai_link->name);
+
+		/* copy params for each dpcm */
+		memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
+				sizeof(struct snd_pcm_hw_params));
+
+		/* perform any hw_params fixups */
+		if (be->dai_link->be_hw_params_fixup) {
+			ret = be->dai_link->be_hw_params_fixup(be,
+					&dpcm->hw_params);
+			if (ret < 0) {
+				dev_err(be->dev,
+					"dpcm: hw_params BE fixup failed %d\n",
+					ret);
+				goto unwind;
+			}
+		}
+
+		ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
+		if (ret < 0) {
+			dev_err(dpcm->be->dev,
+				"dpcm: hw_params BE failed %d\n", ret);
+			goto unwind;
+		}
+
+		be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
+	}
+	return 0;
+
+unwind:
+	/* disable any enabled and non active backends */
+	list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+
+		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+			continue;
+
+		/* only allow hw_free() if no connected FEs are running */
+		if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+			continue;
+
+		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
+		   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+		   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+		   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+			continue;
+
+		soc_pcm_hw_free(be_substream);
+	}
+
+	return ret;
+}
+
+static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *fe = substream->private_data;
+	int ret, stream = substream->stream;
+
+	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+	memcpy(&fe->dpcm[substream->stream].hw_params, params,
+			sizeof(struct snd_pcm_hw_params));
+	ret = dpcm_be_dai_hw_params(fe, substream->stream);
+	if (ret < 0) {
+		dev_err(fe->dev,"dpcm: hw_params BE failed %d\n", ret);
+		goto out;
+	}
+
+	dev_dbg(fe->dev, "dpcm: hw_params FE %s rate %d chan %x fmt %d\n",
+			fe->dai_link->name, params_rate(params),
+			params_channels(params), params_format(params));
+
+	/* call hw_params on the frontend */
+	ret = soc_pcm_hw_params(substream, params);
+	if (ret < 0) {
+		dev_err(fe->dev,"dpcm: hw_params FE failed %d\n", ret);
+		dpcm_be_dai_hw_free(fe, stream);
+	 } else
+		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
+
+out:
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+	mutex_unlock(&fe->card->mutex);
+	return ret;
+}
+
+static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
+		struct snd_pcm_substream *substream, int cmd)
+{
+	int ret;
+
+	dev_dbg(dpcm->be->dev, "dpcm: trigger BE %s cmd %d\n",
+			dpcm->fe->dai_link->name, cmd);
+
+	ret = soc_pcm_trigger(substream, cmd);
+	if (ret < 0)
+		dev_err(dpcm->be->dev,"dpcm: trigger BE failed %d\n", ret);
+
+	return ret;
+}
+
+static int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
+			       int cmd)
+{
+	struct snd_soc_dpcm *dpcm;
+	int ret = 0;
+
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+
+		/* is this op for this BE ? */
+		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+			continue;
+
+		switch (cmd) {
+		case SNDRV_PCM_TRIGGER_START:
+			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
+			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+				continue;
+
+			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			if (ret)
+				return ret;
+
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+			break;
+		case SNDRV_PCM_TRIGGER_RESUME:
+			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
+				continue;
+
+			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			if (ret)
+				return ret;
+
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+			break;
+		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
+				continue;
+
+			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			if (ret)
+				return ret;
+
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+			break;
+		case SNDRV_PCM_TRIGGER_STOP:
+			if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+				continue;
+
+			if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+				continue;
+
+			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			if (ret)
+				return ret;
+
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
+			break;
+		case SNDRV_PCM_TRIGGER_SUSPEND:
+			if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)
+				continue;
+
+			if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+				continue;
+
+			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			if (ret)
+				return ret;
+
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
+			break;
+		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+			if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+				continue;
+
+			if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+				continue;
+
+			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			if (ret)
+				return ret;
+
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
+			break;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
+
+static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *fe = substream->private_data;
+	int stream = substream->stream, ret;
+	enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
+
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+	switch (trigger) {
+	case SND_SOC_DPCM_TRIGGER_PRE:
+		/* call trigger on the frontend before the backend. */
+
+		dev_dbg(fe->dev, "dpcm: pre trigger FE %s cmd %d\n",
+				fe->dai_link->name, cmd);
+
+		ret = soc_pcm_trigger(substream, cmd);
+		if (ret < 0) {
+			dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+			goto out;
+		}
+
+		ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
+		break;
+	case SND_SOC_DPCM_TRIGGER_POST:
+		/* call trigger on the frontend after the backend. */
+
+		ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
+		if (ret < 0) {
+			dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+			goto out;
+		}
+
+		dev_dbg(fe->dev, "dpcm: post trigger FE %s cmd %d\n",
+				fe->dai_link->name, cmd);
+
+		ret = soc_pcm_trigger(substream, cmd);
+		break;
+	case SND_SOC_DPCM_TRIGGER_BESPOKE:
+		/* bespoke trigger() - handles both FE and BEs */
+
+		dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n",
+				fe->dai_link->name, cmd);
+
+		ret = soc_pcm_bespoke_trigger(substream, cmd);
+		if (ret < 0) {
+			dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+			goto out;
+		}
+		break;
+	default:
+		dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd,
+				fe->dai_link->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
+		break;
+	}
+
+out:
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+	return ret;
+}
+
+static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+	int ret = 0;
+
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+
+		/* is this op for this BE ? */
+		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+			continue;
+
+		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+			continue;
+
+		dev_dbg(be->dev, "dpcm: prepare BE %s\n",
+			dpcm->fe->dai_link->name);
+
+		ret = soc_pcm_prepare(be_substream);
+		if (ret < 0) {
+			dev_err(be->dev, "dpcm: backend prepare failed %d\n",
+				ret);
+			break;
+		}
+
+		be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
+	}
+	return ret;
+}
+
+static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *fe = substream->private_data;
+	int stream = substream->stream, ret = 0;
+
+	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+
+	dev_dbg(fe->dev, "dpcm: prepare FE %s\n", fe->dai_link->name);
+
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+	/* there is no point preparing this FE if there are no BEs */
+	if (list_empty(&fe->dpcm[stream].be_clients)) {
+		dev_err(fe->dev, "dpcm: no backend DAIs enabled for %s\n",
+				fe->dai_link->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = dpcm_be_dai_prepare(fe, substream->stream);
+	if (ret < 0)
+		goto out;
+
+	/* call prepare on the frontend */
+	ret = soc_pcm_prepare(substream);
+	if (ret < 0) {
+		dev_err(fe->dev,"dpcm: prepare FE %s failed\n",
+			fe->dai_link->name);
+		goto out;
+	}
+
+	/* run the stream event for each BE */
+	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
+	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
+
+out:
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+	mutex_unlock(&fe->card->mutex);
+
+	return ret;
+}
+
+static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
+		     unsigned int cmd, void *arg)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+
+	if (platform->driver->ops->ioctl)
+		return platform->driver->ops->ioctl(substream, cmd, arg);
+	return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_pcm_substream *substream =
+		snd_soc_dpcm_get_substream(fe, stream);
+	enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
+	int err;
+
+	dev_dbg(fe->dev, "runtime %s close on FE %s\n",
+			stream ? "capture" : "playback", fe->dai_link->name);
+
+	if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
+		/* call bespoke trigger - FE takes care of all BE triggers */
+		dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n",
+				fe->dai_link->name);
+
+		err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
+		if (err < 0)
+			dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err);
+	} else {
+		dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n",
+			fe->dai_link->name);
+
+		err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
+		if (err < 0)
+			dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err);
+	}
+
+	err = dpcm_be_dai_hw_free(fe, stream);
+	if (err < 0)
+		dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err);
+
+	err = dpcm_be_dai_shutdown(fe, stream);
+	if (err < 0)
+		dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err);
+
+	/* run the stream event for each BE */
+	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
+
+	return 0;
+}
+
+static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_pcm_substream *substream =
+		snd_soc_dpcm_get_substream(fe, stream);
+	struct snd_soc_dpcm *dpcm;
+	enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
+	int ret;
+
+	dev_dbg(fe->dev, "runtime %s open on FE %s\n",
+			stream ? "capture" : "playback", fe->dai_link->name);
+
+	/* Only start the BE if the FE is ready */
+	if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
+		fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
+		return -EINVAL;
+
+	/* startup must always be called for new BEs */
+	ret = dpcm_be_dai_startup(fe, stream);
+	if (ret < 0) {
+		goto disconnect;
+		return ret;
+	}
+
+	/* keep going if FE state is > open */
+	if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
+		return 0;
+
+	ret = dpcm_be_dai_hw_params(fe, stream);
+	if (ret < 0) {
+		goto close;
+		return ret;
+	}
+
+	/* keep going if FE state is > hw_params */
+	if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
+		return 0;
+
+
+	ret = dpcm_be_dai_prepare(fe, stream);
+	if (ret < 0) {
+		goto hw_free;
+		return ret;
+	}
+
+	/* run the stream event for each BE */
+	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
+
+	/* keep going if FE state is > prepare */
+	if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
+		fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
+		return 0;
+
+	if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
+		/* call trigger on the frontend - FE takes care of all BE triggers */
+		dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n",
+				fe->dai_link->name);
+
+		ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
+		if (ret < 0) {
+			dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret);
+			goto hw_free;
+		}
+	} else {
+		dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n",
+			fe->dai_link->name);
+
+		ret = dpcm_be_dai_trigger(fe, stream,
+					SNDRV_PCM_TRIGGER_START);
+		if (ret < 0) {
+			dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+			goto hw_free;
+		}
+	}
+
+	return 0;
+
+hw_free:
+	dpcm_be_dai_hw_free(fe, stream);
+close:
+	dpcm_be_dai_shutdown(fe, stream);
+disconnect:
+	/* disconnect any non started BEs */
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+				dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+	}
+
+	return ret;
+}
+
+static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	int ret;
+
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+	ret = dpcm_run_update_startup(fe, stream);
+	if (ret < 0)
+		dev_err(fe->dev, "failed to startup some BEs\n");
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+	return ret;
+}
+
+static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	int ret;
+
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+	ret = dpcm_run_update_shutdown(fe, stream);
+	if (ret < 0)
+		dev_err(fe->dev, "failed to shutdown some BEs\n");
+	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+	return ret;
+}
+
+/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
+ * any DAI links.
+ */
+int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget)
+{
+	struct snd_soc_card *card;
+	int i, old, new, paths;
+
+	if (widget->codec)
+		card = widget->codec->card;
+	else if (widget->platform)
+		card = widget->platform->card;
+	else
+		return -EINVAL;
+
+	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+	for (i = 0; i < card->num_rtd; i++) {
+		struct snd_soc_dapm_widget_list *list;
+		struct snd_soc_pcm_runtime *fe = &card->rtd[i];
+
+		/* make sure link is FE */
+		if (!fe->dai_link->dynamic)
+			continue;
+
+		/* only check active links */
+		if (!fe->cpu_dai->active)
+			continue;
+
+		/* DAPM sync will call this to update DSP paths */
+		dev_dbg(fe->dev, "DPCM runtime update for FE %s\n",
+			fe->dai_link->name);
+
+		/* skip if FE doesn't have playback capability */
+		if (!fe->cpu_dai->driver->playback.channels_min)
+			goto capture;
+
+		paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
+		if (paths < 0) {
+			dev_warn(fe->dev, "%s no valid %s path\n",
+					fe->dai_link->name,  "playback");
+			mutex_unlock(&card->mutex);
+			return paths;
+		}
+
+		/* update any new playback paths */
+		new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
+		if (new) {
+			dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
+			dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
+			dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
+		}
+
+		/* update any old playback paths */
+		old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
+		if (old) {
+			dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
+			dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
+			dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
+		}
+
+capture:
+		/* skip if FE doesn't have capture capability */
+		if (!fe->cpu_dai->driver->capture.channels_min)
+			continue;
+
+		paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
+		if (paths < 0) {
+			dev_warn(fe->dev, "%s no valid %s path\n",
+					fe->dai_link->name,  "capture");
+			mutex_unlock(&card->mutex);
+			return paths;
+		}
+
+		/* update any new capture paths */
+		new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
+		if (new) {
+			dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
+			dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
+			dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
+		}
+
+		/* update any old capture paths */
+		old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
+		if (old) {
+			dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
+			dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
+			dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
+		}
+
+		dpcm_path_put(&list);
+	}
+
+	mutex_unlock(&card->mutex);
+	return 0;
+}
+int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
+{
+	struct snd_soc_dpcm *dpcm;
+	struct list_head *clients =
+		&fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients;
+
+	list_for_each_entry(dpcm, clients, list_be) {
+
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_soc_dai *dai = be->codec_dai;
+		struct snd_soc_dai_driver *drv = dai->driver;
+
+		if (be->dai_link->ignore_suspend)
+			continue;
+
+		dev_dbg(be->dev, "BE digital mute %s\n", be->dai_link->name);
+
+		if (drv->ops->digital_mute && dai->playback_active)
+				drv->ops->digital_mute(dai, mute);
+	}
+
+	return 0;
+}
+
+static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
+{
+	struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+	struct snd_soc_dpcm *dpcm;
+	struct snd_soc_dapm_widget_list *list;
+	int ret;
+	int stream = fe_substream->stream;
+
+	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+	fe->dpcm[stream].runtime = fe_substream->runtime;
+
+	if (dpcm_path_get(fe, stream, &list) <= 0) {
+		dev_warn(fe->dev, "asoc: %s no valid %s route\n",
+			fe->dai_link->name, stream ? "capture" : "playback");
+			mutex_unlock(&fe->card->mutex);
+			return -EINVAL;
+	}
+
+	/* calculate valid and active FE <-> BE dpcms */
+	dpcm_process_paths(fe, stream, &list, 1);
+
+	ret = dpcm_fe_dai_startup(fe_substream);
+	if (ret < 0) {
+		/* clean up all links */
+		list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+			dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+		dpcm_be_disconnect(fe, stream);
+		fe->dpcm[stream].runtime = NULL;
+	}
+
+	dpcm_clear_pending_state(fe, stream);
+	dpcm_path_put(&list);
+	mutex_unlock(&fe->card->mutex);
+	return ret;
+}
+
+static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
+{
+	struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+	struct snd_soc_dpcm *dpcm;
+	int stream = fe_substream->stream, ret;
+
+	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+	ret = dpcm_fe_dai_shutdown(fe_substream);
+
+	/* mark FE's links ready to prune */
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+	dpcm_be_disconnect(fe, stream);
+
+	fe->dpcm[stream].runtime = NULL;
+	mutex_unlock(&fe->card->mutex);
+	return ret;
+}
+
 /* create a new pcm */
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 {
@@ -641,56 +2001,94 @@
 	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_ops *soc_pcm_ops = &rtd->ops;
 	struct snd_pcm *pcm;
 	char new_name[64];
 	int ret = 0, playback = 0, capture = 0;
 
-	soc_pcm_ops->open	= soc_pcm_open;
-	soc_pcm_ops->close	= soc_pcm_close;
-	soc_pcm_ops->hw_params	= soc_pcm_hw_params;
-	soc_pcm_ops->hw_free	= soc_pcm_hw_free;
-	soc_pcm_ops->prepare	= soc_pcm_prepare;
-	soc_pcm_ops->trigger	= soc_pcm_trigger;
-	soc_pcm_ops->pointer	= soc_pcm_pointer;
+	if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
+		if (cpu_dai->driver->playback.channels_min)
+			playback = 1;
+		if (cpu_dai->driver->capture.channels_min)
+			capture = 1;
+	} else {
+		if (codec_dai->driver->playback.channels_min)
+			playback = 1;
+		if (codec_dai->driver->capture.channels_min)
+			capture = 1;
+	}
 
-	/* check client and interface hw capabilities */
-	snprintf(new_name, sizeof(new_name), "%s %s-%d",
-			rtd->dai_link->stream_name, codec_dai->name, num);
+	/* create the PCM */
+	if (rtd->dai_link->no_pcm) {
+		snprintf(new_name, sizeof(new_name), "(%s)",
+			rtd->dai_link->stream_name);
 
-	if (codec_dai->driver->playback.channels_min)
-		playback = 1;
-	if (codec_dai->driver->capture.channels_min)
-		capture = 1;
+		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
+				playback, capture, &pcm);
+	} else {
+		if (rtd->dai_link->dynamic)
+			snprintf(new_name, sizeof(new_name), "%s (*)",
+				rtd->dai_link->stream_name);
+		else
+			snprintf(new_name, sizeof(new_name), "%s %s-%d",
+				rtd->dai_link->stream_name, codec_dai->name, num);
 
-	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);
+		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);
 		return ret;
 	}
+	dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name);
 
 	/* DAPM dai link stream work */
 	INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
 
 	rtd->pcm = pcm;
 	pcm->private_data = rtd;
+
+	if (rtd->dai_link->no_pcm) {
+		if (playback)
+			pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
+		if (capture)
+			pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
+		goto out;
+	}
+
+	/* ASoC PCM operations */
+	if (rtd->dai_link->dynamic) {
+		rtd->ops.open		= dpcm_fe_dai_open;
+		rtd->ops.hw_params	= dpcm_fe_dai_hw_params;
+		rtd->ops.prepare	= dpcm_fe_dai_prepare;
+		rtd->ops.trigger	= dpcm_fe_dai_trigger;
+		rtd->ops.hw_free	= dpcm_fe_dai_hw_free;
+		rtd->ops.close		= dpcm_fe_dai_close;
+		rtd->ops.pointer	= soc_pcm_pointer;
+		rtd->ops.ioctl		= soc_pcm_ioctl;
+	} else {
+		rtd->ops.open		= soc_pcm_open;
+		rtd->ops.hw_params	= soc_pcm_hw_params;
+		rtd->ops.prepare	= soc_pcm_prepare;
+		rtd->ops.trigger	= soc_pcm_trigger;
+		rtd->ops.hw_free	= soc_pcm_hw_free;
+		rtd->ops.close		= soc_pcm_close;
+		rtd->ops.pointer	= soc_pcm_pointer;
+		rtd->ops.ioctl		= soc_pcm_ioctl;
+	}
+
 	if (platform->driver->ops) {
-		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;
+		rtd->ops.ack		= platform->driver->ops->ack;
+		rtd->ops.copy		= platform->driver->ops->copy;
+		rtd->ops.silence	= platform->driver->ops->silence;
+		rtd->ops.page		= platform->driver->ops->page;
+		rtd->ops.mmap		= platform->driver->ops->mmap;
 	}
 
 	if (playback)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, soc_pcm_ops);
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
 
 	if (capture)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, soc_pcm_ops);
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
 
 	if (platform->driver->pcm_new) {
 		ret = platform->driver->pcm_new(rtd);
@@ -701,7 +2099,257 @@
 	}
 
 	pcm->private_free = platform->driver->pcm_free;
+out:
 	printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
 		cpu_dai->name);
 	return ret;
 }
+
+/* is the current PCM operation for this FE ? */
+int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
+
+/* is the current PCM operation for this BE ? */
+int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
+		struct snd_soc_pcm_runtime *be, int stream)
+{
+	if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
+	   ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
+		  be->dpcm[stream].runtime_update))
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
+
+/* get the substream for this BE */
+struct snd_pcm_substream *
+	snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
+{
+	return be->pcm->streams[stream].substream;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
+
+/* get the BE runtime state */
+enum snd_soc_dpcm_state
+	snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
+{
+	return be->dpcm[stream].state;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
+
+/* set the BE runtime state */
+void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
+		int stream, enum snd_soc_dpcm_state state)
+{
+	be->dpcm[stream].state = state;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
+
+/*
+ * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
+ * are not running, paused or suspended for the specified stream direction.
+ */
+int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
+		struct snd_soc_pcm_runtime *be, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+	int state;
+
+	list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
+
+		if (dpcm->fe == fe)
+			continue;
+
+		state = dpcm->fe->dpcm[stream].state;
+		if (state == SND_SOC_DPCM_STATE_START ||
+			state == SND_SOC_DPCM_STATE_PAUSED ||
+			state == SND_SOC_DPCM_STATE_SUSPEND)
+			return 0;
+	}
+
+	/* it's safe to free/stop this BE DAI */
+	return 1;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
+
+/*
+ * We can only change hw params a BE DAI if any of it's FE are not prepared,
+ * running, paused or suspended for the specified stream direction.
+ */
+int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
+		struct snd_soc_pcm_runtime *be, int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+	int state;
+
+	list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
+
+		if (dpcm->fe == fe)
+			continue;
+
+		state = dpcm->fe->dpcm[stream].state;
+		if (state == SND_SOC_DPCM_STATE_START ||
+			state == SND_SOC_DPCM_STATE_PAUSED ||
+			state == SND_SOC_DPCM_STATE_SUSPEND ||
+			state == SND_SOC_DPCM_STATE_PREPARE)
+			return 0;
+	}
+
+	/* it's safe to change hw_params */
+	return 1;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
+
+int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
+		int cmd, struct snd_soc_platform *platform)
+{
+	if (platform->driver->ops->trigger)
+		return platform->driver->ops->trigger(substream, cmd);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_platform_trigger);
+
+#ifdef CONFIG_DEBUG_FS
+static char *dpcm_state_string(enum snd_soc_dpcm_state state)
+{
+	switch (state) {
+	case SND_SOC_DPCM_STATE_NEW:
+		return "new";
+	case SND_SOC_DPCM_STATE_OPEN:
+		return "open";
+	case SND_SOC_DPCM_STATE_HW_PARAMS:
+		return "hw_params";
+	case SND_SOC_DPCM_STATE_PREPARE:
+		return "prepare";
+	case SND_SOC_DPCM_STATE_START:
+		return "start";
+	case SND_SOC_DPCM_STATE_STOP:
+		return "stop";
+	case SND_SOC_DPCM_STATE_SUSPEND:
+		return "suspend";
+	case SND_SOC_DPCM_STATE_PAUSED:
+		return "paused";
+	case SND_SOC_DPCM_STATE_HW_FREE:
+		return "hw_free";
+	case SND_SOC_DPCM_STATE_CLOSE:
+		return "close";
+	}
+
+	return "unknown";
+}
+
+static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
+				int stream, char *buf, size_t size)
+{
+	struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
+	struct snd_soc_dpcm *dpcm;
+	ssize_t offset = 0;
+
+	/* FE state */
+	offset += snprintf(buf + offset, size - offset,
+			"[%s - %s]\n", fe->dai_link->name,
+			stream ? "Capture" : "Playback");
+
+	offset += snprintf(buf + offset, size - offset, "State: %s\n",
+	                dpcm_state_string(fe->dpcm[stream].state));
+
+	if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
+	    (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
+		offset += snprintf(buf + offset, size - offset,
+				"Hardware Params: "
+				"Format = %s, Channels = %d, Rate = %d\n",
+				snd_pcm_format_name(params_format(params)),
+				params_channels(params),
+				params_rate(params));
+
+	/* BEs state */
+	offset += snprintf(buf + offset, size - offset, "Backends:\n");
+
+	if (list_empty(&fe->dpcm[stream].be_clients)) {
+		offset += snprintf(buf + offset, size - offset,
+				" No active DSP links\n");
+		goto out;
+	}
+
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		params = &dpcm->hw_params;
+
+		offset += snprintf(buf + offset, size - offset,
+				"- %s\n", be->dai_link->name);
+
+		offset += snprintf(buf + offset, size - offset,
+				"   State: %s\n",
+				dpcm_state_string(be->dpcm[stream].state));
+
+		if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
+		    (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
+			offset += snprintf(buf + offset, size - offset,
+				"   Hardware Params: "
+				"Format = %s, Channels = %d, Rate = %d\n",
+				snd_pcm_format_name(params_format(params)),
+				params_channels(params),
+				params_rate(params));
+	}
+
+out:
+	return offset;
+}
+
+static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	struct snd_soc_pcm_runtime *fe = file->private_data;
+	ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
+	char *buf;
+
+	buf = kmalloc(out_count, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (fe->cpu_dai->driver->playback.channels_min)
+		offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
+					buf + offset, out_count - offset);
+
+	if (fe->cpu_dai->driver->capture.channels_min)
+		offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
+					buf + offset, out_count - offset);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
+
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations dpcm_state_fops = {
+	.open = simple_open,
+	.read = dpcm_state_read_file,
+	.llseek = default_llseek,
+};
+
+int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
+{
+	if (!rtd->dai_link)
+		return 0;
+
+	rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
+			rtd->card->debugfs_card_root);
+	if (!rtd->debugfs_dpcm_root) {
+		dev_dbg(rtd->dev,
+			 "ASoC: Failed to create dpcm debugfs directory %s\n",
+			 rtd->dai_link->name);
+		return -EINVAL;
+	}
+
+	rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444,
+						rtd->debugfs_dpcm_root,
+						rtd, &dpcm_state_fops);
+
+	return 0;
+}
+#endif
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index ce1b773..c1c8e95 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -1,26 +1,63 @@
 config SND_SOC_TEGRA
 	tristate "SoC Audio for the Tegra System-on-Chip"
 	depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA
+	select REGMAP_MMIO
 	help
 	  Say Y or M here if you want support for SoC audio on Tegra.
 
-config SND_SOC_TEGRA_I2S
+config SND_SOC_TEGRA20_DAS
 	tristate
-	depends on SND_SOC_TEGRA
+	depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+	help
+	  Say Y or M if you want to add support for the Tegra20 DAS module.
+	  You will also need to select the individual machine drivers to
+	  support below.
+
+config SND_SOC_TEGRA20_I2S
+	tristate
+	depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+	select SND_SOC_TEGRA20_DAS
 	help
 	  Say Y or M if you want to add support for codecs attached to the
-	  Tegra I2S interface. You will also need to select the individual
+	  Tegra20 I2S interface. You will also need to select the individual
 	  machine drivers to support below.
 
-config SND_SOC_TEGRA_SPDIF
+config SND_SOC_TEGRA20_SPDIF
 	tristate
-	depends on SND_SOC_TEGRA
+	depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
 	default m
 	help
-	  Say Y or M if you want to add support for the SPDIF interface.
+	  Say Y or M if you want to add support for the Tegra20 SPDIF interface.
 	  You will also need to select the individual machine drivers to support
 	  below.
 
+config SND_SOC_TEGRA30_AHUB
+	tristate
+	depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC
+	help
+	  Say Y or M if you want to add support for the Tegra20 AHUB module.
+	  You will also need to select the individual machine drivers to
+	  support below.
+
+config SND_SOC_TEGRA30_I2S
+	tristate
+	depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC
+	select SND_SOC_TEGRA30_AHUB
+	help
+	  Say Y or M if you want to add support for codecs attached to the
+	  Tegra30 I2S interface. You will also need to select the individual
+	  machine drivers to support below.
+
+config SND_SOC_TEGRA_WM8753
+	tristate "SoC Audio support for Tegra boards using a WM8753 codec"
+	depends on SND_SOC_TEGRA && I2C
+	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+	select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+	select SND_SOC_WM8753
+	help
+	  Say Y or M here if you want to add support for SoC audio on Tegra
+	  boards using the WM8753 codec, such as Whistler.
+
 config MACH_HAS_SND_SOC_TEGRA_WM8903
 	bool
 	help
@@ -32,7 +69,8 @@
 	tristate "SoC Audio support for Tegra boards using a WM8903 codec"
 	depends on SND_SOC_TEGRA && I2C
 	depends on MACH_HAS_SND_SOC_TEGRA_WM8903
-	select SND_SOC_TEGRA_I2S
+	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+	select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
 	select SND_SOC_WM8903
 	help
 	  Say Y or M here if you want to add support for SoC audio on Tegra
@@ -42,17 +80,17 @@
 config SND_SOC_TEGRA_TRIMSLICE
 	tristate "SoC Audio support for TrimSlice board"
 	depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C
-	select SND_SOC_TEGRA_I2S
+	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
 	select SND_SOC_TLV320AIC23
 	help
 	  Say Y or M here if you want to add support for SoC audio on the
 	  TrimSlice platform.
 
 config SND_SOC_TEGRA_ALC5632
-       tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
-       depends on SND_SOC_TEGRA && I2C
-       select SND_SOC_TEGRA_I2S
-       select SND_SOC_ALC5632
-       help
-         Say Y or M here if you want to add support for SoC audio on the
-         Toshiba AC100 netbook.
+	tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
+	depends on SND_SOC_TEGRA && I2C
+	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+	select SND_SOC_ALC5632
+	help
+	  Say Y or M here if you want to add support for SoC audio on the
+	  Toshiba AC100 netbook.
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 8e584b8..391e78a 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -1,21 +1,27 @@
 # Tegra platform Support
-snd-soc-tegra-das-objs := tegra_das.o
 snd-soc-tegra-pcm-objs := tegra_pcm.o
-snd-soc-tegra-i2s-objs := tegra_i2s.o
-snd-soc-tegra-spdif-objs := tegra_spdif.o
 snd-soc-tegra-utils-objs += tegra_asoc_utils.o
+snd-soc-tegra20-das-objs := tegra20_das.o
+snd-soc-tegra20-i2s-objs := tegra20_i2s.o
+snd-soc-tegra20-spdif-objs := tegra20_spdif.o
+snd-soc-tegra30-ahub-objs := tegra30_ahub.o
+snd-soc-tegra30-i2s-objs := tegra30_i2s.o
 
-obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
-obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
-obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o
-obj-$(CONFIG_SND_SOC_TEGRA_SPDIF) += snd-soc-tegra-spdif.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
+obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o
+obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
+obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
+obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 
 # Tegra machine Support
+snd-soc-tegra-wm8753-objs := tegra_wm8753.o
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
 snd-soc-tegra-trimslice-objs := trimslice.o
 snd-soc-tegra-alc5632-objs := tegra_alc5632.o
 
+obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
 obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
 obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
new file mode 100644
index 0000000..bf99296
--- /dev/null
+++ b/sound/soc/tegra/tegra20_das.c
@@ -0,0 +1,233 @@
+/*
+ * tegra20_das.c - Tegra20 DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, 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.
+ *
+ * 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/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include "tegra20_das.h"
+
+#define DRV_NAME "tegra20-das"
+
+static struct tegra20_das *das;
+
+static inline void tegra20_das_write(u32 reg, u32 val)
+{
+	regmap_write(das->regmap, reg, val);
+}
+
+static inline u32 tegra20_das_read(u32 reg)
+{
+	u32 val;
+	regmap_read(das->regmap, reg, &val);
+	return val;
+}
+
+int tegra20_das_connect_dap_to_dac(int dap, int dac)
+{
+	u32 addr;
+	u32 reg;
+
+	if (!das)
+		return -ENODEV;
+
+	addr = TEGRA20_DAS_DAP_CTRL_SEL +
+		(dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
+	reg = dac << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
+
+	tegra20_das_write(addr, reg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dac);
+
+int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master,
+				   int sdata1rx, int sdata2rx)
+{
+	u32 addr;
+	u32 reg;
+
+	if (!das)
+		return -ENODEV;
+
+	addr = TEGRA20_DAS_DAP_CTRL_SEL +
+		(dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
+	reg = otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
+		!!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
+		!!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
+		!!master << TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
+
+	tegra20_das_write(addr, reg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dap);
+
+int tegra20_das_connect_dac_to_dap(int dac, int dap)
+{
+	u32 addr;
+	u32 reg;
+
+	if (!das)
+		return -ENODEV;
+
+	addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL +
+		(dac * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
+	reg = dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
+		dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
+		dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
+
+	tegra20_das_write(addr, reg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dac_to_dap);
+
+#define LAST_REG(name) \
+	(TEGRA20_DAS_##name + \
+	 (TEGRA20_DAS_##name##_STRIDE * (TEGRA20_DAS_##name##_COUNT - 1)))
+
+static bool tegra20_das_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+	if ((reg >= TEGRA20_DAS_DAP_CTRL_SEL) &&
+	    (reg <= LAST_REG(DAP_CTRL_SEL)))
+		return true;
+	if ((reg >= TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL) &&
+	    (reg <= LAST_REG(DAC_INPUT_DATA_CLK_SEL)))
+		return true;
+
+	return false;
+}
+
+static const struct regmap_config tegra20_das_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = LAST_REG(DAC_INPUT_DATA_CLK_SEL),
+	.writeable_reg = tegra20_das_wr_rd_reg,
+	.readable_reg = tegra20_das_wr_rd_reg,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit tegra20_das_probe(struct platform_device *pdev)
+{
+	struct resource *res, *region;
+	void __iomem *regs;
+	int ret = 0;
+
+	if (das)
+		return -ENODEV;
+
+	das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL);
+	if (!das) {
+		dev_err(&pdev->dev, "Can't allocate tegra20_das\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	das->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "No memory resource\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	region = devm_request_mem_region(&pdev->dev, res->start,
+					 resource_size(res), pdev->name);
+	if (!region) {
+		dev_err(&pdev->dev, "Memory region already claimed\n");
+		ret = -EBUSY;
+		goto err;
+	}
+
+	regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	das->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					    &tegra20_das_regmap_config);
+	if (IS_ERR(das->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		ret = PTR_ERR(das->regmap);
+		goto err;
+	}
+
+	ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1,
+					     TEGRA20_DAS_DAP_SEL_DAC1);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
+		goto err;
+	}
+	ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_1,
+					     TEGRA20_DAS_DAC_SEL_DAP1);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, das);
+
+	return 0;
+
+err:
+	das = NULL;
+	return ret;
+}
+
+static int __devexit tegra20_das_remove(struct platform_device *pdev)
+{
+	if (!das)
+		return -ENODEV;
+
+	das = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id tegra20_das_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra20-das", },
+	{},
+};
+
+static struct platform_driver tegra20_das_driver = {
+	.probe = tegra20_das_probe,
+	.remove = __devexit_p(tegra20_das_remove),
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = tegra20_das_of_match,
+	},
+};
+module_platform_driver(tegra20_das_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 DAS driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra20_das_of_match);
diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h
new file mode 100644
index 0000000..be217f3
--- /dev/null
+++ b/sound/soc/tegra/tegra20_das.h
@@ -0,0 +1,134 @@
+/*
+ * tegra20_das.h - Definitions for Tegra20 DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, 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.
+ *
+ * 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 __TEGRA20_DAS_H__
+#define __TEGRA20_DAS_H__
+
+/* Register TEGRA20_DAS_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_CTRL_SEL			0x00
+#define TEGRA20_DAS_DAP_CTRL_SEL_COUNT			5
+#define TEGRA20_DAS_DAP_CTRL_SEL_STRIDE			4
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P		31
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S		1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P	30
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S	1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P	29
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S	1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P		0
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S		5
+
+/* Values for field TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_SEL_DAC1	0
+#define TEGRA20_DAS_DAP_SEL_DAC2	1
+#define TEGRA20_DAS_DAP_SEL_DAC3	2
+#define TEGRA20_DAS_DAP_SEL_DAP1	16
+#define TEGRA20_DAS_DAP_SEL_DAP2	17
+#define TEGRA20_DAS_DAP_SEL_DAP3	18
+#define TEGRA20_DAS_DAP_SEL_DAP4	19
+#define TEGRA20_DAS_DAP_SEL_DAP5	20
+
+/* Register TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL */
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL			0x40
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT		3
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE		4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P	28
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S	4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P	24
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S	4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P	0
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S	4
+
+/*
+ * Values for:
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
+ */
+#define TEGRA20_DAS_DAC_SEL_DAP1	0
+#define TEGRA20_DAS_DAC_SEL_DAP2	1
+#define TEGRA20_DAS_DAC_SEL_DAP3	2
+#define TEGRA20_DAS_DAC_SEL_DAP4	3
+#define TEGRA20_DAS_DAC_SEL_DAP5	4
+
+/*
+ * Names/IDs of the DACs/DAPs.
+ */
+
+#define TEGRA20_DAS_DAP_ID_1 0
+#define TEGRA20_DAS_DAP_ID_2 1
+#define TEGRA20_DAS_DAP_ID_3 2
+#define TEGRA20_DAS_DAP_ID_4 3
+#define TEGRA20_DAS_DAP_ID_5 4
+
+#define TEGRA20_DAS_DAC_ID_1 0
+#define TEGRA20_DAS_DAC_ID_2 1
+#define TEGRA20_DAS_DAC_ID_3 2
+
+struct tegra20_das {
+	struct device *dev;
+	struct regmap *regmap;
+};
+
+/*
+ * Terminology:
+ * DAS: Digital audio switch (HW module controlled by this driver)
+ * DAP: Digital audio port (port/pins on Tegra device)
+ * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
+ *
+ * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
+ * DAC, or another DAP. When DAPs are connected, one must be the master and
+ * one the slave. Each DAC allows selection of a specific DAP for input, to
+ * cater for the case where N DAPs are connected to 1 DAC for broadcast
+ * output.
+ *
+ * This driver is dumb; no attempt is made to ensure that a valid routing
+ * configuration is programmed.
+ */
+
+/*
+ * Connect a DAP to to a DAC
+ * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
+ * dac_sel: DAC to connect to: TEGRA20_DAS_DAP_SEL_DAC*
+ */
+extern int tegra20_das_connect_dap_to_dac(int dap_id, int dac_sel);
+
+/*
+ * Connect a DAP to to another DAP
+ * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
+ * other_dap_sel: DAP to connect to: TEGRA20_DAS_DAP_SEL_DAP*
+ * master: Is this DAP the master (1) or slave (0)
+ * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
+ * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
+ */
+extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
+					  int master, int sdata1rx,
+					  int sdata2rx);
+
+/*
+ * Connect a DAC's input to a DAP
+ * (DAC outputs are selected by the DAP)
+ * dac_id: DAC ID to connect: TEGRA20_DAS_DAC_ID_*
+ * dap_sel: DAP to receive input from: TEGRA20_DAS_DAC_SEL_DAP*
+ */
+extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel);
+
+#endif
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
new file mode 100644
index 0000000..0c7af63
--- /dev/null
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -0,0 +1,494 @@
+/*
+ * tegra20_i2s.c - Tegra20 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.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
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra20_i2s.h"
+
+#define DRV_NAME "tegra20-i2s"
+
+static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val)
+{
+	regmap_write(i2s->regmap, reg, val);
+}
+
+static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg)
+{
+	u32 val;
+	regmap_read(i2s->regmap, reg, &val);
+	return val;
+}
+
+static int tegra20_i2s_runtime_suspend(struct device *dev)
+{
+	struct tegra20_i2s *i2s = dev_get_drvdata(dev);
+
+	clk_disable(i2s->clk_i2s);
+
+	return 0;
+}
+
+static int tegra20_i2s_runtime_resume(struct device *dev)
+{
+	struct tegra20_i2s *i2s = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_enable(i2s->clk_i2s);
+	if (ret) {
+		dev_err(dev, "clk_enable failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
+				unsigned int fmt)
+{
+	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE;
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	i2s->reg_ctrl &= ~(TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
+			   TEGRA20_I2S_CTRL_LRCK_MASK);
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct device *dev = substream->pcm->card->dev;
+	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	u32 reg;
+	int ret, sample_size, srate, i2sclock, bitcnt;
+
+	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16;
+		sample_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24;
+		sample_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32;
+		sample_size = 32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	srate = params_rate(params);
+
+	/* Final "* 2" required by Tegra hardware */
+	i2sclock = srate * params_channels(params) * sample_size * 2;
+
+	ret = clk_set_rate(i2s->clk_i2s, i2sclock);
+	if (ret) {
+		dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+		return ret;
+	}
+
+	bitcnt = (i2sclock / (2 * srate)) - 1;
+	if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
+		return -EINVAL;
+	reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+
+	if (i2sclock % (2 * srate))
+		reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
+
+	tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg);
+
+	tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR,
+		TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
+		TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
+
+	return 0;
+}
+
+static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
+{
+	i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO1_ENABLE;
+	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
+{
+	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO1_ENABLE;
+	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
+{
+	i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO2_ENABLE;
+	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
+{
+	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO2_ENABLE;
+	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
+{
+	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			tegra20_i2s_start_playback(i2s);
+		else
+			tegra20_i2s_start_capture(i2s);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			tegra20_i2s_stop_playback(i2s);
+		else
+			tegra20_i2s_stop_capture(i2s);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra20_i2s_probe(struct snd_soc_dai *dai)
+{
+	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	dai->capture_dma_data = &i2s->capture_dma_data;
+	dai->playback_dma_data = &i2s->playback_dma_data;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
+	.set_fmt	= tegra20_i2s_set_fmt,
+	.hw_params	= tegra20_i2s_hw_params,
+	.trigger	= tegra20_i2s_trigger,
+};
+
+static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
+	.probe = tegra20_i2s_probe,
+	.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 = &tegra20_i2s_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA20_I2S_CTRL:
+	case TEGRA20_I2S_STATUS:
+	case TEGRA20_I2S_TIMING:
+	case TEGRA20_I2S_FIFO_SCR:
+	case TEGRA20_I2S_PCM_CTRL:
+	case TEGRA20_I2S_NW_CTRL:
+	case TEGRA20_I2S_TDM_CTRL:
+	case TEGRA20_I2S_TDM_TX_RX_CTRL:
+	case TEGRA20_I2S_FIFO1:
+	case TEGRA20_I2S_FIFO2:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA20_I2S_STATUS:
+	case TEGRA20_I2S_FIFO_SCR:
+	case TEGRA20_I2S_FIFO1:
+	case TEGRA20_I2S_FIFO2:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA20_I2S_FIFO1:
+	case TEGRA20_I2S_FIFO2:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra20_i2s_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = TEGRA20_I2S_FIFO2,
+	.writeable_reg = tegra20_i2s_wr_rd_reg,
+	.readable_reg = tegra20_i2s_wr_rd_reg,
+	.volatile_reg = tegra20_i2s_volatile_reg,
+	.precious_reg = tegra20_i2s_precious_reg,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
+{
+	struct tegra20_i2s *i2s;
+	struct resource *mem, *memregion, *dmareq;
+	u32 of_dma[2];
+	u32 dma_ch;
+	void __iomem *regs;
+	int ret;
+
+	i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_i2s), GFP_KERNEL);
+	if (!i2s) {
+		dev_err(&pdev->dev, "Can't allocate tegra20_i2s\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	dev_set_drvdata(&pdev->dev, i2s);
+
+	i2s->dai = tegra20_i2s_dai_template;
+	i2s->dai.name = dev_name(&pdev->dev);
+
+	i2s->clk_i2s = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(i2s->clk_i2s)) {
+		dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
+		ret = PTR_ERR(i2s->clk_i2s);
+		goto err;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "No memory resource\n");
+		ret = -ENODEV;
+		goto err_clk_put;
+	}
+
+	dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!dmareq) {
+		if (of_property_read_u32_array(pdev->dev.of_node,
+					"nvidia,dma-request-selector",
+					of_dma, 2) < 0) {
+			dev_err(&pdev->dev, "No DMA resource\n");
+			ret = -ENODEV;
+			goto err_clk_put;
+		}
+		dma_ch = of_dma[1];
+	} else {
+		dma_ch = dmareq->start;
+	}
+
+	memregion = devm_request_mem_region(&pdev->dev, mem->start,
+					    resource_size(mem), DRV_NAME);
+	if (!memregion) {
+		dev_err(&pdev->dev, "Memory region already claimed\n");
+		ret = -EBUSY;
+		goto err_clk_put;
+	}
+
+	regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+	if (!regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto err_clk_put;
+	}
+
+	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					    &tegra20_i2s_regmap_config);
+	if (IS_ERR(i2s->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		ret = PTR_ERR(i2s->regmap);
+		goto err_clk_put;
+	}
+
+	i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
+	i2s->capture_dma_data.wrap = 4;
+	i2s->capture_dma_data.width = 32;
+	i2s->capture_dma_data.req_sel = dma_ch;
+
+	i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
+	i2s->playback_dma_data.wrap = 4;
+	i2s->playback_dma_data.width = 32;
+	i2s->playback_dma_data.req_sel = dma_ch;
+
+	i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = tegra20_i2s_runtime_resume(&pdev->dev);
+		if (ret)
+			goto err_pm_disable;
+	}
+
+	ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+		ret = -ENOMEM;
+		goto err_suspend;
+	}
+
+	ret = tegra_pcm_platform_register(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+		goto err_unregister_dai;
+	}
+
+	return 0;
+
+err_unregister_dai:
+	snd_soc_unregister_dai(&pdev->dev);
+err_suspend:
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra20_i2s_runtime_suspend(&pdev->dev);
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+err_clk_put:
+	clk_put(i2s->clk_i2s);
+err:
+	return ret;
+}
+
+static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev)
+{
+	struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra20_i2s_runtime_suspend(&pdev->dev);
+
+	tegra_pcm_platform_unregister(&pdev->dev);
+	snd_soc_unregister_dai(&pdev->dev);
+
+	clk_put(i2s->clk_i2s);
+
+	return 0;
+}
+
+static const struct of_device_id tegra20_i2s_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra20-i2s", },
+	{},
+};
+
+static const struct dev_pm_ops tegra20_i2s_pm_ops __devinitconst = {
+	SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
+			   tegra20_i2s_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra20_i2s_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = tegra20_i2s_of_match,
+		.pm = &tegra20_i2s_pm_ops,
+	},
+	.probe = tegra20_i2s_platform_probe,
+	.remove = __devexit_p(tegra20_i2s_platform_remove),
+};
+module_platform_driver(tegra20_i2s_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 I2S ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra20_i2s_of_match);
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h
new file mode 100644
index 0000000..a57efc6
--- /dev/null
+++ b/sound/soc/tegra/tegra20_i2s.h
@@ -0,0 +1,164 @@
+/*
+ * tegra20_i2s.h - Definitions for Tegra20 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.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 __TEGRA20_I2S_H__
+#define __TEGRA20_I2S_H__
+
+#include "tegra_pcm.h"
+
+/* Register offsets from TEGRA20_I2S1_BASE and TEGRA20_I2S2_BASE */
+
+#define TEGRA20_I2S_CTRL				0x00
+#define TEGRA20_I2S_STATUS				0x04
+#define TEGRA20_I2S_TIMING				0x08
+#define TEGRA20_I2S_FIFO_SCR				0x0c
+#define TEGRA20_I2S_PCM_CTRL				0x10
+#define TEGRA20_I2S_NW_CTRL				0x14
+#define TEGRA20_I2S_TDM_CTRL				0x20
+#define TEGRA20_I2S_TDM_TX_RX_CTRL			0x24
+#define TEGRA20_I2S_FIFO1				0x40
+#define TEGRA20_I2S_FIFO2				0x80
+
+/* Fields in TEGRA20_I2S_CTRL */
+
+#define TEGRA20_I2S_CTRL_FIFO2_TX_ENABLE		(1 << 30)
+#define TEGRA20_I2S_CTRL_FIFO1_ENABLE			(1 << 29)
+#define TEGRA20_I2S_CTRL_FIFO2_ENABLE			(1 << 28)
+#define TEGRA20_I2S_CTRL_FIFO1_RX_ENABLE		(1 << 27)
+#define TEGRA20_I2S_CTRL_FIFO_LPBK_ENABLE		(1 << 26)
+#define TEGRA20_I2S_CTRL_MASTER_ENABLE			(1 << 25)
+
+#define TEGRA20_I2S_LRCK_LEFT_LOW				0
+#define TEGRA20_I2S_LRCK_RIGHT_LOW			1
+
+#define TEGRA20_I2S_CTRL_LRCK_SHIFT			24
+#define TEGRA20_I2S_CTRL_LRCK_MASK			(1                          << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA20_I2S_CTRL_LRCK_L_LOW			(TEGRA20_I2S_LRCK_LEFT_LOW  << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA20_I2S_CTRL_LRCK_R_LOW			(TEGRA20_I2S_LRCK_RIGHT_LOW << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+
+#define TEGRA20_I2S_BIT_FORMAT_I2S			0
+#define TEGRA20_I2S_BIT_FORMAT_RJM			1
+#define TEGRA20_I2S_BIT_FORMAT_LJM			2
+#define TEGRA20_I2S_BIT_FORMAT_DSP			3
+
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT		10
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_MASK		(3                          << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_I2S			(TEGRA20_I2S_BIT_FORMAT_I2S << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_RJM			(TEGRA20_I2S_BIT_FORMAT_RJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_LJM			(TEGRA20_I2S_BIT_FORMAT_LJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_DSP			(TEGRA20_I2S_BIT_FORMAT_DSP << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+
+#define TEGRA20_I2S_BIT_SIZE_16				0
+#define TEGRA20_I2S_BIT_SIZE_20				1
+#define TEGRA20_I2S_BIT_SIZE_24				2
+#define TEGRA20_I2S_BIT_SIZE_32				3
+
+#define TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT			8
+#define TEGRA20_I2S_CTRL_BIT_SIZE_MASK			(3                       << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_16			(TEGRA20_I2S_BIT_SIZE_16 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_20			(TEGRA20_I2S_BIT_SIZE_20 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_24			(TEGRA20_I2S_BIT_SIZE_24 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_32			(TEGRA20_I2S_BIT_SIZE_32 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+
+#define TEGRA20_I2S_FIFO_16_LSB				0
+#define TEGRA20_I2S_FIFO_20_LSB				1
+#define TEGRA20_I2S_FIFO_24_LSB				2
+#define TEGRA20_I2S_FIFO_32				3
+#define TEGRA20_I2S_FIFO_PACKED				7
+
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT		4
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK		(7                       << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_16_LSB		(TEGRA20_I2S_FIFO_16_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_20_LSB		(TEGRA20_I2S_FIFO_20_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_24_LSB		(TEGRA20_I2S_FIFO_24_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_32			(TEGRA20_I2S_FIFO_32     << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED		(TEGRA20_I2S_FIFO_PACKED << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+
+#define TEGRA20_I2S_CTRL_IE_FIFO1_ERR			(1 << 3)
+#define TEGRA20_I2S_CTRL_IE_FIFO2_ERR			(1 << 2)
+#define TEGRA20_I2S_CTRL_QE_FIFO1			(1 << 1)
+#define TEGRA20_I2S_CTRL_QE_FIFO2			(1 << 0)
+
+/* Fields in TEGRA20_I2S_STATUS */
+
+#define TEGRA20_I2S_STATUS_FIFO1_RDY			(1 << 31)
+#define TEGRA20_I2S_STATUS_FIFO2_RDY			(1 << 30)
+#define TEGRA20_I2S_STATUS_FIFO1_BSY			(1 << 29)
+#define TEGRA20_I2S_STATUS_FIFO2_BSY			(1 << 28)
+#define TEGRA20_I2S_STATUS_FIFO1_ERR			(1 << 3)
+#define TEGRA20_I2S_STATUS_FIFO2_ERR			(1 << 2)
+#define TEGRA20_I2S_STATUS_QS_FIFO1			(1 << 1)
+#define TEGRA20_I2S_STATUS_QS_FIFO2			(1 << 0)
+
+/* Fields in TEGRA20_I2S_TIMING */
+
+#define TEGRA20_I2S_TIMING_NON_SYM_ENABLE		(1 << 12)
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT	0
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US	0x7fff
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK	(TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
+
+/* Fields in TEGRA20_I2S_FIFO_SCR */
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT	24
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT	16
+#define TEGRA20_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK		0x3f
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_CLR			(1 << 12)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_CLR			(1 << 8)
+
+#define TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT		0
+#define TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS		1
+#define TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS		2
+#define TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS		3
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT	4
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK		(3 << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT	(TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT	0
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK		(3 << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT	(TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+
+struct tegra20_i2s {
+	struct snd_soc_dai_driver dai;
+	struct clk *clk_i2s;
+	struct tegra_pcm_dma_params capture_dma_data;
+	struct tegra_pcm_dma_params playback_dma_data;
+	struct regmap *regmap;
+	u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
new file mode 100644
index 0000000..f9b5741
--- /dev/null
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -0,0 +1,404 @@
+/*
+ * tegra20_spdif.c - Tegra20 SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011-2012 - NVIDIA, 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.
+ *
+ * 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/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra20_spdif.h"
+
+#define DRV_NAME "tegra20-spdif"
+
+static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg,
+					u32 val)
+{
+	regmap_write(spdif->regmap, reg, val);
+}
+
+static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg)
+{
+	u32 val;
+	regmap_read(spdif->regmap, reg, &val);
+	return val;
+}
+
+static int tegra20_spdif_runtime_suspend(struct device *dev)
+{
+	struct tegra20_spdif *spdif = dev_get_drvdata(dev);
+
+	clk_disable(spdif->clk_spdif_out);
+
+	return 0;
+}
+
+static int tegra20_spdif_runtime_resume(struct device *dev)
+{
+	struct tegra20_spdif *spdif = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_enable(spdif->clk_spdif_out);
+	if (ret) {
+		dev_err(dev, "clk_enable failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct device *dev = substream->pcm->card->dev;
+	struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+	int ret, spdifclock;
+
+	spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_PACK;
+	spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_PACK;
+		spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_rate(params)) {
+	case 32000:
+		spdifclock = 4096000;
+		break;
+	case 44100:
+		spdifclock = 5644800;
+		break;
+	case 48000:
+		spdifclock = 6144000;
+		break;
+	case 88200:
+		spdifclock = 11289600;
+		break;
+	case 96000:
+		spdifclock = 12288000;
+		break;
+	case 176400:
+		spdifclock = 22579200;
+		break;
+	case 192000:
+		spdifclock = 24576000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
+	if (ret) {
+		dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif)
+{
+	spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_TX_EN;
+	tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif)
+{
+	spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_TX_EN;
+	tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		tegra20_spdif_start_playback(spdif);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		tegra20_spdif_stop_playback(spdif);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra20_spdif_probe(struct snd_soc_dai *dai)
+{
+	struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+	dai->capture_dma_data = NULL;
+	dai->playback_dma_data = &spdif->playback_dma_data;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
+	.hw_params	= tegra20_spdif_hw_params,
+	.trigger	= tegra20_spdif_trigger,
+};
+
+static struct snd_soc_dai_driver tegra20_spdif_dai = {
+	.name = DRV_NAME,
+	.probe = tegra20_spdif_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &tegra20_spdif_dai_ops,
+};
+
+static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA20_SPDIF_CTRL:
+	case TEGRA20_SPDIF_STATUS:
+	case TEGRA20_SPDIF_STROBE_CTRL:
+	case TEGRA20_SPDIF_DATA_FIFO_CSR:
+	case TEGRA20_SPDIF_DATA_OUT:
+	case TEGRA20_SPDIF_DATA_IN:
+	case TEGRA20_SPDIF_CH_STA_RX_A:
+	case TEGRA20_SPDIF_CH_STA_RX_B:
+	case TEGRA20_SPDIF_CH_STA_RX_C:
+	case TEGRA20_SPDIF_CH_STA_RX_D:
+	case TEGRA20_SPDIF_CH_STA_RX_E:
+	case TEGRA20_SPDIF_CH_STA_RX_F:
+	case TEGRA20_SPDIF_CH_STA_TX_A:
+	case TEGRA20_SPDIF_CH_STA_TX_B:
+	case TEGRA20_SPDIF_CH_STA_TX_C:
+	case TEGRA20_SPDIF_CH_STA_TX_D:
+	case TEGRA20_SPDIF_CH_STA_TX_E:
+	case TEGRA20_SPDIF_CH_STA_TX_F:
+	case TEGRA20_SPDIF_USR_STA_RX_A:
+	case TEGRA20_SPDIF_USR_DAT_TX_A:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra20_spdif_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA20_SPDIF_STATUS:
+	case TEGRA20_SPDIF_DATA_FIFO_CSR:
+	case TEGRA20_SPDIF_DATA_OUT:
+	case TEGRA20_SPDIF_DATA_IN:
+	case TEGRA20_SPDIF_CH_STA_RX_A:
+	case TEGRA20_SPDIF_CH_STA_RX_B:
+	case TEGRA20_SPDIF_CH_STA_RX_C:
+	case TEGRA20_SPDIF_CH_STA_RX_D:
+	case TEGRA20_SPDIF_CH_STA_RX_E:
+	case TEGRA20_SPDIF_CH_STA_RX_F:
+	case TEGRA20_SPDIF_USR_STA_RX_A:
+	case TEGRA20_SPDIF_USR_DAT_TX_A:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra20_spdif_precious_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA20_SPDIF_DATA_OUT:
+	case TEGRA20_SPDIF_DATA_IN:
+	case TEGRA20_SPDIF_USR_STA_RX_A:
+	case TEGRA20_SPDIF_USR_DAT_TX_A:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra20_spdif_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = TEGRA20_SPDIF_USR_DAT_TX_A,
+	.writeable_reg = tegra20_spdif_wr_rd_reg,
+	.readable_reg = tegra20_spdif_wr_rd_reg,
+	.volatile_reg = tegra20_spdif_volatile_reg,
+	.precious_reg = tegra20_spdif_precious_reg,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev)
+{
+	struct tegra20_spdif *spdif;
+	struct resource *mem, *memregion, *dmareq;
+	void __iomem *regs;
+	int ret;
+
+	spdif = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_spdif),
+			     GFP_KERNEL);
+	if (!spdif) {
+		dev_err(&pdev->dev, "Can't allocate tegra20_spdif\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	dev_set_drvdata(&pdev->dev, spdif);
+
+	spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
+	if (IS_ERR(spdif->clk_spdif_out)) {
+		pr_err("Can't retrieve spdif clock\n");
+		ret = PTR_ERR(spdif->clk_spdif_out);
+		goto err;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "No memory resource\n");
+		ret = -ENODEV;
+		goto err_clk_put;
+	}
+
+	dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!dmareq) {
+		dev_err(&pdev->dev, "No DMA resource\n");
+		ret = -ENODEV;
+		goto err_clk_put;
+	}
+
+	memregion = devm_request_mem_region(&pdev->dev, mem->start,
+					    resource_size(mem), DRV_NAME);
+	if (!memregion) {
+		dev_err(&pdev->dev, "Memory region already claimed\n");
+		ret = -EBUSY;
+		goto err_clk_put;
+	}
+
+	regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+	if (!regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto err_clk_put;
+	}
+
+	spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					    &tegra20_spdif_regmap_config);
+	if (IS_ERR(spdif->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		ret = PTR_ERR(spdif->regmap);
+		goto err_clk_put;
+	}
+
+	spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
+	spdif->playback_dma_data.wrap = 4;
+	spdif->playback_dma_data.width = 32;
+	spdif->playback_dma_data.req_sel = dmareq->start;
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = tegra20_spdif_runtime_resume(&pdev->dev);
+		if (ret)
+			goto err_pm_disable;
+	}
+
+	ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+		ret = -ENOMEM;
+		goto err_suspend;
+	}
+
+	ret = tegra_pcm_platform_register(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+		goto err_unregister_dai;
+	}
+
+	return 0;
+
+err_unregister_dai:
+	snd_soc_unregister_dai(&pdev->dev);
+err_suspend:
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra20_spdif_runtime_suspend(&pdev->dev);
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+err_clk_put:
+	clk_put(spdif->clk_spdif_out);
+err:
+	return ret;
+}
+
+static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev)
+{
+	struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra20_spdif_runtime_suspend(&pdev->dev);
+
+	tegra_pcm_platform_unregister(&pdev->dev);
+	snd_soc_unregister_dai(&pdev->dev);
+
+	clk_put(spdif->clk_spdif_out);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra20_spdif_pm_ops __devinitconst = {
+	SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend,
+			   tegra20_spdif_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra20_spdif_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &tegra20_spdif_pm_ops,
+	},
+	.probe = tegra20_spdif_platform_probe,
+	.remove = __devexit_p(tegra20_spdif_platform_remove),
+};
+
+module_platform_driver(tegra20_spdif_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 SPDIF ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h
new file mode 100644
index 0000000..ed75652
--- /dev/null
+++ b/sound/soc/tegra/tegra20_spdif.h
@@ -0,0 +1,471 @@
+/*
+ * tegra20_spdif.h - Definitions for Tegra20 SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ * Copyright (c) 2008-2009, NVIDIA 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
+ *
+ */
+
+#ifndef __TEGRA20_SPDIF_H__
+#define __TEGRA20_SPDIF_H__
+
+#include "tegra_pcm.h"
+
+/* Offsets from TEGRA20_SPDIF_BASE */
+
+#define TEGRA20_SPDIF_CTRL					0x0
+#define TEGRA20_SPDIF_STATUS					0x4
+#define TEGRA20_SPDIF_STROBE_CTRL				0x8
+#define TEGRA20_SPDIF_DATA_FIFO_CSR				0x0C
+#define TEGRA20_SPDIF_DATA_OUT					0x40
+#define TEGRA20_SPDIF_DATA_IN					0x80
+#define TEGRA20_SPDIF_CH_STA_RX_A				0x100
+#define TEGRA20_SPDIF_CH_STA_RX_B				0x104
+#define TEGRA20_SPDIF_CH_STA_RX_C				0x108
+#define TEGRA20_SPDIF_CH_STA_RX_D				0x10C
+#define TEGRA20_SPDIF_CH_STA_RX_E				0x110
+#define TEGRA20_SPDIF_CH_STA_RX_F				0x114
+#define TEGRA20_SPDIF_CH_STA_TX_A				0x140
+#define TEGRA20_SPDIF_CH_STA_TX_B				0x144
+#define TEGRA20_SPDIF_CH_STA_TX_C				0x148
+#define TEGRA20_SPDIF_CH_STA_TX_D				0x14C
+#define TEGRA20_SPDIF_CH_STA_TX_E				0x150
+#define TEGRA20_SPDIF_CH_STA_TX_F				0x154
+#define TEGRA20_SPDIF_USR_STA_RX_A				0x180
+#define TEGRA20_SPDIF_USR_DAT_TX_A				0x1C0
+
+/* Fields in TEGRA20_SPDIF_CTRL */
+
+/* Start capturing from 0=right, 1=left channel */
+#define TEGRA20_SPDIF_CTRL_CAP_LC				(1 << 30)
+
+/* SPDIF receiver(RX) enable */
+#define TEGRA20_SPDIF_CTRL_RX_EN				(1 << 29)
+
+/* SPDIF Transmitter(TX) enable */
+#define TEGRA20_SPDIF_CTRL_TX_EN				(1 << 28)
+
+/* Transmit Channel status */
+#define TEGRA20_SPDIF_CTRL_TC_EN				(1 << 27)
+
+/* Transmit user Data */
+#define TEGRA20_SPDIF_CTRL_TU_EN				(1 << 26)
+
+/* Interrupt on transmit error */
+#define TEGRA20_SPDIF_CTRL_IE_TXE				(1 << 25)
+
+/* Interrupt on receive error */
+#define TEGRA20_SPDIF_CTRL_IE_RXE				(1 << 24)
+
+/* Interrupt on invalid preamble */
+#define TEGRA20_SPDIF_CTRL_IE_P					(1 << 23)
+
+/* Interrupt on "B" preamble */
+#define TEGRA20_SPDIF_CTRL_IE_B					(1 << 22)
+
+/* Interrupt when block of channel status received */
+#define TEGRA20_SPDIF_CTRL_IE_C					(1 << 21)
+
+/* Interrupt when a valid information unit (IU) is received */
+#define TEGRA20_SPDIF_CTRL_IE_U					(1 << 20)
+
+/* Interrupt when RX user FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_RU				(1 << 19)
+
+/* Interrupt when TX user FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_TU				(1 << 18)
+
+/* Interrupt when RX data FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_RX				(1 << 17)
+
+/* Interrupt when TX data FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_TX				(1 << 16)
+
+/* Loopback test mode enable */
+#define TEGRA20_SPDIF_CTRL_LBK_EN				(1 << 15)
+
+/*
+ * Pack data mode:
+ * 0 = Single data (16 bit needs to be  padded to match the
+ *     interface data bit size).
+ * 1 = Packeted left/right channel data into a single word.
+ */
+#define TEGRA20_SPDIF_CTRL_PACK					(1 << 14)
+
+/*
+ * 00 = 16bit data
+ * 01 = 20bit data
+ * 10 = 24bit data
+ * 11 = raw data
+ */
+#define TEGRA20_SPDIF_BIT_MODE_16BIT				0
+#define TEGRA20_SPDIF_BIT_MODE_20BIT				1
+#define TEGRA20_SPDIF_BIT_MODE_24BIT				2
+#define TEGRA20_SPDIF_BIT_MODE_RAW				3
+
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT			12
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_MASK			(3                            << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT			(TEGRA20_SPDIF_BIT_MODE_16BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_20BIT			(TEGRA20_SPDIF_BIT_MODE_20BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_24BIT			(TEGRA20_SPDIF_BIT_MODE_24BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_RAW				(TEGRA20_SPDIF_BIT_MODE_RAW   << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_STATUS */
+
+/*
+ * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
+ * write a 1 to the corresponding bit location to clear the status.
+ */
+
+/*
+ * Receiver(RX) shifter is busy receiving data.
+ * This bit is asserted when the receiver first locked onto the
+ * preamble of the data stream after RX_EN is asserted. This bit is
+ * deasserted when either,
+ * (a) the end of a frame is reached after RX_EN is deeasserted, or
+ * (b) the SPDIF data stream becomes inactive.
+ */
+#define TEGRA20_SPDIF_STATUS_RX_BSY				(1 << 29)
+
+/*
+ * Transmitter(TX) shifter is busy transmitting data.
+ * This bit is asserted when TX_EN is asserted.
+ * This bit is deasserted when the end of a frame is reached after
+ * TX_EN is deasserted.
+ */
+#define TEGRA20_SPDIF_STATUS_TX_BSY				(1 << 28)
+
+/*
+ * TX is busy shifting out channel status.
+ * This bit is asserted when both TX_EN and TC_EN are asserted and
+ * data from CH_STA_TX_A register is loaded into the internal shifter.
+ * This bit is deasserted when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) CH_STA_TX_F register is loaded into the internal shifter.
+ */
+#define TEGRA20_SPDIF_STATUS_TC_BSY				(1 << 27)
+
+/*
+ * TX User data FIFO busy.
+ * This bit is asserted when TX_EN and TXU_EN are asserted and
+ * there's data in the TX user FIFO.  This bit is deassert when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) there's no data left in the TX user FIFO.
+ */
+#define TEGRA20_SPDIF_STATUS_TU_BSY				(1 << 26)
+
+/* TX FIFO Underrun error status */
+#define TEGRA20_SPDIF_STATUS_TX_ERR				(1 << 25)
+
+/* RX FIFO Overrun error status */
+#define TEGRA20_SPDIF_STATUS_RX_ERR				(1 << 24)
+
+/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
+#define TEGRA20_SPDIF_STATUS_IS_P				(1 << 23)
+
+/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
+#define TEGRA20_SPDIF_STATUS_IS_B				(1 << 22)
+
+/*
+ * RX channel block data receive status:
+ * 0=entire block not recieved yet.
+ * 1=received entire block of channel status,
+ */
+#define TEGRA20_SPDIF_STATUS_IS_C				(1 << 21)
+
+/* RX User Data Valid flag:  1=valid IU detected, 0 = no IU detected. */
+#define TEGRA20_SPDIF_STATUS_IS_U				(1 << 20)
+
+/*
+ * RX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_RU				(1 << 19)
+
+/*
+ * TX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_TU				(1 << 18)
+
+/*
+ * RX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_RX				(1 << 17)
+
+/*
+ * TX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_TX				(1 << 16)
+
+/* Fields in TEGRA20_SPDIF_STROBE_CTRL */
+
+/*
+ * Indicates the approximate number of detected SPDIFIN clocks within a
+ * bi-phase period.
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT			16
+#define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_MASK			(0xff << TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
+
+/* Data strobe mode: 0=Auto-locked 1=Manual locked */
+#define TEGRA20_SPDIF_STROBE_CTRL_STROBE			(1 << 15)
+
+/*
+ * Manual data strobe time within the bi-phase clock period (in terms of
+ * the number of over-sampling clocks).
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT		8
+#define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_MASK		(0x1f << TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
+
+/*
+ * Manual SPDIFIN bi-phase clock period (in terms of the number of
+ * over-sampling clocks).
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT		0
+#define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK		(0x3f << TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
+
+/* Fields in SPDIF_DATA_FIFO_CSR */
+
+/* Clear Receiver User FIFO (RX USR.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_CLR			(1 << 31)
+
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT			0
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS			1
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS		2
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS			3
+
+/* RU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT		29
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK		\
+		(0x3                                      << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+
+/* Number of RX USR.FIFO levels with valid data. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT		24
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK		(0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter User FIFO (TX USR.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_CLR			(1 << 23)
+
+/* TU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT		21
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK		\
+		(0x3                                      << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+
+/* Number of TX USR.FIFO levels that could be filled. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT	16
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK		(0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
+
+/* Clear Receiver Data FIFO (RX DATA.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_CLR			(1 << 15)
+
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT			0
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS			1
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS		2
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS		3
+
+/* RU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT		13
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK		\
+		(0x3                                       << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+
+/* Number of RX DATA.FIFO levels with valid data. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT		8
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK		(0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_CLR			(1 << 7)
+
+/* TU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT		5
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK		\
+		(0x3                                       << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+
+/* Number of TX DATA.FIFO levels that could be filled. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT	0
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK		(0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_DATA_OUT */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit        (BIT_MODE=00, PACK=0)
+ * 20-bit        (BIT_MODE=01, PACK=0)
+ * 24-bit        (BIT_MODE=10, PACK=0)
+ * raw           (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ */
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT			0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_MASK			(0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT			0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_20_MASK			(0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT			0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_24_MASK			(0xffffff << TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_P			(1 << 31)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_C			(1 << 30)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_U			(1 << 29)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_V			(1 << 28)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT		8
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK		(0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT		4
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK		(0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT		0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK		(0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT	16
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK	(0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT	0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK		(0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_DATA_IN */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit        (BIT_MODE=00, PACK=0)
+ * 20-bit        (BIT_MODE=01, PACK=0)
+ * 24-bit        (BIT_MODE=10, PACK=0)
+ * raw           (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ *
+ * Bits 31:24 are common to all modes except 16-bit packed
+ */
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_P				(1 << 31)
+#define TEGRA20_SPDIF_DATA_IN_DATA_C				(1 << 30)
+#define TEGRA20_SPDIF_DATA_IN_DATA_U				(1 << 29)
+#define TEGRA20_SPDIF_DATA_IN_DATA_V				(1 << 28)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT		24
+#define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_MASK		(0xf << TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT			0
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_MASK			(0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT			0
+#define TEGRA20_SPDIF_DATA_IN_DATA_20_MASK			(0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT			0
+#define TEGRA20_SPDIF_DATA_IN_DATA_24_MASK			(0xffffff << TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT		8
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_MASK		(0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT		4
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_MASK			(0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT		0
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK		(0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT	16
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK		(0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT		0
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK		(0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_A */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_B */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_C */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_D */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_E */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_F */
+
+/*
+ * The 6-word receive channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of receive is from LSB to MSB
+ * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
+ */
+
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_A */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_B */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_C */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_D */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_E */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_F */
+
+/*
+ * The 6-word transmit channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of transmission is from LSB to MSB
+ * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
+ */
+
+/* Fields in TEGRA20_SPDIF_USR_STA_RX_A */
+
+/*
+ * This 4-word deep FIFO receives user FIFO field information. The order of
+ * receive is from LSB to MSB bit.
+ */
+
+/* Fields in TEGRA20_SPDIF_USR_DAT_TX_A */
+
+/*
+ * This 4-word deep FIFO transmits user FIFO field information. The order of
+ * transmission is from LSB to MSB bit.
+ */
+
+struct tegra20_spdif {
+	struct clk *clk_spdif_out;
+	struct tegra_pcm_dma_params capture_dma_data;
+	struct tegra_pcm_dma_params playback_dma_data;
+	struct regmap *regmap;
+	u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
new file mode 100644
index 0000000..57cd419
--- /dev/null
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -0,0 +1,631 @@
+/*
+ * tegra30_ahub.c - Tegra30 AHUB driver
+ *
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <mach/clk.h>
+#include <mach/dma.h>
+#include <sound/soc.h>
+#include "tegra30_ahub.h"
+
+#define DRV_NAME "tegra30-ahub"
+
+static struct tegra30_ahub *ahub;
+
+static inline void tegra30_apbif_write(u32 reg, u32 val)
+{
+	regmap_write(ahub->regmap_apbif, reg, val);
+}
+
+static inline u32 tegra30_apbif_read(u32 reg)
+{
+	u32 val;
+	regmap_read(ahub->regmap_apbif, reg, &val);
+	return val;
+}
+
+static inline void tegra30_audio_write(u32 reg, u32 val)
+{
+	regmap_write(ahub->regmap_ahub, reg, val);
+}
+
+static int tegra30_ahub_runtime_suspend(struct device *dev)
+{
+	regcache_cache_only(ahub->regmap_apbif, true);
+	regcache_cache_only(ahub->regmap_ahub, true);
+
+	clk_disable(ahub->clk_apbif);
+	clk_disable(ahub->clk_d_audio);
+
+	return 0;
+}
+
+/*
+ * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data
+ * is read from or sent to memory. However, that's not something the rest of
+ * the driver supports right now, so we'll just treat the two clocks as one
+ * for now.
+ *
+ * These functions should not be a plain ref-count. Instead, each active stream
+ * contributes some requirement to the minimum clock rate, so starting or
+ * stopping streams should dynamically adjust the clock as required.  However,
+ * this is not yet implemented.
+ */
+static int tegra30_ahub_runtime_resume(struct device *dev)
+{
+	int ret;
+
+	ret = clk_enable(ahub->clk_d_audio);
+	if (ret) {
+		dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
+		return ret;
+	}
+	ret = clk_enable(ahub->clk_apbif);
+	if (ret) {
+		dev_err(dev, "clk_enable apbif failed: %d\n", ret);
+		clk_disable(ahub->clk_d_audio);
+		return ret;
+	}
+
+	regcache_cache_only(ahub->regmap_apbif, false);
+	regcache_cache_only(ahub->regmap_ahub, false);
+
+	return 0;
+}
+
+int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
+				  unsigned long *fiforeg,
+				  unsigned long *reqsel)
+{
+	int channel;
+	u32 reg, val;
+
+	channel = find_first_zero_bit(ahub->rx_usage,
+				      TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+	if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
+		return -EBUSY;
+
+	__set_bit(channel, ahub->rx_usage);
+
+	*rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
+	*fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
+		   (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
+	*reqsel = ahub->dma_sel + channel;
+
+	reg = TEGRA30_AHUB_CHANNEL_CTRL +
+	      (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+	val = tegra30_apbif_read(reg);
+	val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK |
+		 TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK);
+	val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) |
+	       TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN |
+	       TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
+	tegra30_apbif_write(reg, val);
+
+	reg = TEGRA30_AHUB_CIF_RX_CTRL +
+	      (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
+	val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+	      (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+	      (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+	      TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
+	      TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
+	      TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
+	tegra30_apbif_write(reg, val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
+
+int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
+{
+	int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+	int reg, val;
+
+	reg = TEGRA30_AHUB_CHANNEL_CTRL +
+	      (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+	val = tegra30_apbif_read(reg);
+	val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
+	tegra30_apbif_write(reg, val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
+
+int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
+{
+	int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+	int reg, val;
+
+	reg = TEGRA30_AHUB_CHANNEL_CTRL +
+	      (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+	val = tegra30_apbif_read(reg);
+	val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
+	tegra30_apbif_write(reg, val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
+
+int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
+{
+	int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+
+	__clear_bit(channel, ahub->rx_usage);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
+
+int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
+				  unsigned long *fiforeg,
+				  unsigned long *reqsel)
+{
+	int channel;
+	u32 reg, val;
+
+	channel = find_first_zero_bit(ahub->tx_usage,
+				      TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+	if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
+		return -EBUSY;
+
+	__set_bit(channel, ahub->tx_usage);
+
+	*txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
+	*fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
+		   (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
+	*reqsel = ahub->dma_sel + channel;
+
+	reg = TEGRA30_AHUB_CHANNEL_CTRL +
+	      (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+	val = tegra30_apbif_read(reg);
+	val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK |
+		 TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK);
+	val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) |
+	       TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN |
+	       TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
+	tegra30_apbif_write(reg, val);
+
+	reg = TEGRA30_AHUB_CIF_TX_CTRL +
+	      (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
+	val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+	      (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+	      (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+	      TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
+	      TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
+	      TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
+	tegra30_apbif_write(reg, val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
+
+int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
+{
+	int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+	int reg, val;
+
+	reg = TEGRA30_AHUB_CHANNEL_CTRL +
+	      (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+	val = tegra30_apbif_read(reg);
+	val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
+	tegra30_apbif_write(reg, val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
+
+int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
+{
+	int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+	int reg, val;
+
+	reg = TEGRA30_AHUB_CHANNEL_CTRL +
+	      (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+	val = tegra30_apbif_read(reg);
+	val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
+	tegra30_apbif_write(reg, val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
+
+int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif)
+{
+	int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+
+	__clear_bit(channel, ahub->tx_usage);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo);
+
+int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
+				   enum tegra30_ahub_txcif txcif)
+{
+	int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+	int reg;
+
+	reg = TEGRA30_AHUB_AUDIO_RX +
+	      (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
+	tegra30_audio_write(reg, 1 << txcif);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
+
+int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
+{
+	int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+	int reg;
+
+	reg = TEGRA30_AHUB_AUDIO_RX +
+	      (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
+	tegra30_audio_write(reg, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
+
+static const char * const configlink_clocks[] __devinitconst = {
+	"i2s0",
+	"i2s1",
+	"i2s2",
+	"i2s3",
+	"i2s4",
+	"dam0",
+	"dam1",
+	"dam2",
+	"spdif_in",
+};
+
+struct of_dev_auxdata ahub_auxdata[] __devinitdata = {
+	OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080300, "tegra30-i2s.0", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080400, "tegra30-i2s.1", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080500, "tegra30-i2s.2", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080600, "tegra30-i2s.3", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080700, "tegra30-i2s.4", NULL),
+	{}
+};
+
+#define LAST_REG(name) \
+	(TEGRA30_AHUB_##name + \
+	 (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4)
+
+#define REG_IN_ARRAY(reg, name) \
+	((reg >= TEGRA30_AHUB_##name) && \
+	 (reg <= LAST_REG(name) && \
+	 (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE))))
+
+static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA30_AHUB_CONFIG_LINK_CTRL:
+	case TEGRA30_AHUB_MISC_CTRL:
+	case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
+	case TEGRA30_AHUB_I2S_LIVE_STATUS:
+	case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
+	case TEGRA30_AHUB_I2S_INT_MASK:
+	case TEGRA30_AHUB_DAM_INT_MASK:
+	case TEGRA30_AHUB_SPDIF_INT_MASK:
+	case TEGRA30_AHUB_APBIF_INT_MASK:
+	case TEGRA30_AHUB_I2S_INT_STATUS:
+	case TEGRA30_AHUB_DAM_INT_STATUS:
+	case TEGRA30_AHUB_SPDIF_INT_STATUS:
+	case TEGRA30_AHUB_APBIF_INT_STATUS:
+	case TEGRA30_AHUB_I2S_INT_SOURCE:
+	case TEGRA30_AHUB_DAM_INT_SOURCE:
+	case TEGRA30_AHUB_SPDIF_INT_SOURCE:
+	case TEGRA30_AHUB_APBIF_INT_SOURCE:
+	case TEGRA30_AHUB_I2S_INT_SET:
+	case TEGRA30_AHUB_DAM_INT_SET:
+	case TEGRA30_AHUB_SPDIF_INT_SET:
+	case TEGRA30_AHUB_APBIF_INT_SET:
+		return true;
+	default:
+		break;
+	};
+
+	if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
+	    REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
+	    REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
+	    REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
+	    REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
+	    REG_IN_ARRAY(reg, CIF_TX_CTRL) ||
+	    REG_IN_ARRAY(reg, CIF_RX_CTRL) ||
+	    REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
+		return true;
+
+	return false;
+}
+
+static bool tegra30_ahub_apbif_volatile_reg(struct device *dev,
+					    unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA30_AHUB_CONFIG_LINK_CTRL:
+	case TEGRA30_AHUB_MISC_CTRL:
+	case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
+	case TEGRA30_AHUB_I2S_LIVE_STATUS:
+	case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
+	case TEGRA30_AHUB_I2S_INT_STATUS:
+	case TEGRA30_AHUB_DAM_INT_STATUS:
+	case TEGRA30_AHUB_SPDIF_INT_STATUS:
+	case TEGRA30_AHUB_APBIF_INT_STATUS:
+	case TEGRA30_AHUB_I2S_INT_SET:
+	case TEGRA30_AHUB_DAM_INT_SET:
+	case TEGRA30_AHUB_SPDIF_INT_SET:
+	case TEGRA30_AHUB_APBIF_INT_SET:
+		return true;
+	default:
+		break;
+	};
+
+	if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
+	    REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
+	    REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
+	    REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
+	    REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
+		return true;
+
+	return false;
+}
+
+static bool tegra30_ahub_apbif_precious_reg(struct device *dev,
+					    unsigned int reg)
+{
+	if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
+	    REG_IN_ARRAY(reg, CHANNEL_RXFIFO))
+		return true;
+
+	return false;
+}
+
+static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
+	.name = "apbif",
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = TEGRA30_AHUB_APBIF_INT_SET,
+	.writeable_reg = tegra30_ahub_apbif_wr_rd_reg,
+	.readable_reg = tegra30_ahub_apbif_wr_rd_reg,
+	.volatile_reg = tegra30_ahub_apbif_volatile_reg,
+	.precious_reg = tegra30_ahub_apbif_precious_reg,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (REG_IN_ARRAY(reg, AUDIO_RX))
+		return true;
+
+	return false;
+}
+
+static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
+	.name = "ahub",
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = LAST_REG(AUDIO_RX),
+	.writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
+	.readable_reg = tegra30_ahub_ahub_wr_rd_reg,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit tegra30_ahub_probe(struct platform_device *pdev)
+{
+	struct clk *clk;
+	int i;
+	struct resource *res0, *res1, *region;
+	u32 of_dma[2];
+	void __iomem *regs_apbif, *regs_ahub;
+	int ret = 0;
+
+	if (ahub)
+		return -ENODEV;
+
+	/*
+	 * The AHUB hosts a register bus: the "configlink". For this to
+	 * operate correctly, all devices on this bus must be out of reset.
+	 * Ensure that here.
+	 */
+	for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
+		clk = clk_get_sys(NULL, configlink_clocks[i]);
+		if (IS_ERR(clk)) {
+			dev_err(&pdev->dev, "Can't get clock %s\n",
+				configlink_clocks[i]);
+			ret = PTR_ERR(clk);
+			goto err;
+		}
+		tegra_periph_reset_deassert(clk);
+		clk_put(clk);
+	}
+
+	ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
+			    GFP_KERNEL);
+	if (!ahub) {
+		dev_err(&pdev->dev, "Can't allocate tegra30_ahub\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	dev_set_drvdata(&pdev->dev, ahub);
+
+	ahub->dev = &pdev->dev;
+
+	ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio");
+	if (IS_ERR(ahub->clk_d_audio)) {
+		dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
+		ret = PTR_ERR(ahub->clk_d_audio);
+		goto err;
+	}
+
+	ahub->clk_apbif = clk_get(&pdev->dev, "apbif");
+	if (IS_ERR(ahub->clk_apbif)) {
+		dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
+		ret = PTR_ERR(ahub->clk_apbif);
+		goto err_clk_put_d_audio;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node,
+				"nvidia,dma-request-selector",
+				of_dma, 2) < 0) {
+		dev_err(&pdev->dev,
+			"Missing property nvidia,dma-request-selector\n");
+		ret = -ENODEV;
+		goto err_clk_put_d_audio;
+	}
+	ahub->dma_sel = of_dma[1];
+
+	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res0) {
+		dev_err(&pdev->dev, "No apbif memory resource\n");
+		ret = -ENODEV;
+		goto err_clk_put_apbif;
+	}
+
+	region = devm_request_mem_region(&pdev->dev, res0->start,
+					 resource_size(res0), DRV_NAME);
+	if (!region) {
+		dev_err(&pdev->dev, "request region apbif failed\n");
+		ret = -EBUSY;
+		goto err_clk_put_apbif;
+	}
+	ahub->apbif_addr = res0->start;
+
+	regs_apbif = devm_ioremap(&pdev->dev, res0->start,
+				  resource_size(res0));
+	if (!regs_apbif) {
+		dev_err(&pdev->dev, "ioremap apbif failed\n");
+		ret = -ENOMEM;
+		goto err_clk_put_apbif;
+	}
+
+	ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
+					&tegra30_ahub_apbif_regmap_config);
+	if (IS_ERR(ahub->regmap_apbif)) {
+		dev_err(&pdev->dev, "apbif regmap init failed\n");
+		ret = PTR_ERR(ahub->regmap_apbif);
+		goto err_clk_put_apbif;
+	}
+	regcache_cache_only(ahub->regmap_apbif, true);
+
+	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res1) {
+		dev_err(&pdev->dev, "No ahub memory resource\n");
+		ret = -ENODEV;
+		goto err_clk_put_apbif;
+	}
+
+	region = devm_request_mem_region(&pdev->dev, res1->start,
+					 resource_size(res1), DRV_NAME);
+	if (!region) {
+		dev_err(&pdev->dev, "request region ahub failed\n");
+		ret = -EBUSY;
+		goto err_clk_put_apbif;
+	}
+
+	regs_ahub = devm_ioremap(&pdev->dev, res1->start,
+				 resource_size(res1));
+	if (!regs_ahub) {
+		dev_err(&pdev->dev, "ioremap ahub failed\n");
+		ret = -ENOMEM;
+		goto err_clk_put_apbif;
+	}
+
+	ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
+					&tegra30_ahub_ahub_regmap_config);
+	if (IS_ERR(ahub->regmap_ahub)) {
+		dev_err(&pdev->dev, "ahub regmap init failed\n");
+		ret = PTR_ERR(ahub->regmap_ahub);
+		goto err_clk_put_apbif;
+	}
+	regcache_cache_only(ahub->regmap_ahub, true);
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = tegra30_ahub_runtime_resume(&pdev->dev);
+		if (ret)
+			goto err_pm_disable;
+	}
+
+	of_platform_populate(pdev->dev.of_node, NULL, ahub_auxdata,
+			     &pdev->dev);
+
+	return 0;
+
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+err_clk_put_apbif:
+	clk_put(ahub->clk_apbif);
+err_clk_put_d_audio:
+	clk_put(ahub->clk_d_audio);
+	ahub = 0;
+err:
+	return ret;
+}
+
+static int __devexit tegra30_ahub_remove(struct platform_device *pdev)
+{
+	if (!ahub)
+		return -ENODEV;
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra30_ahub_runtime_suspend(&pdev->dev);
+
+	clk_put(ahub->clk_apbif);
+	clk_put(ahub->clk_d_audio);
+
+	ahub = 0;
+
+	return 0;
+}
+
+static const struct of_device_id tegra30_ahub_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra30-ahub", },
+	{},
+};
+
+static const struct dev_pm_ops tegra30_ahub_pm_ops __devinitconst = {
+	SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
+			   tegra30_ahub_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra30_ahub_driver = {
+	.probe = tegra30_ahub_probe,
+	.remove = __devexit_p(tegra30_ahub_remove),
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = tegra30_ahub_of_match,
+		.pm = &tegra30_ahub_pm_ops,
+	},
+};
+module_platform_driver(tegra30_ahub_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 AHUB driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
new file mode 100644
index 0000000..e690e2e
--- /dev/null
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -0,0 +1,483 @@
+/*
+ * tegra30_ahub.h - Definitions for Tegra30 AHUB driver
+ *
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TEGRA30_AHUB_H__
+#define __TEGRA30_AHUB_H__
+
+/* Fields in *_CIF_RX/TX_CTRL; used by AHUB FIFOs, and all other audio modules */
+
+#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT	28
+#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US	0xf
+#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK	(TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT)
+
+/* Channel count minus 1 */
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT	24
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US	7
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK	(TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT)
+
+/* Channel count minus 1 */
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT	16
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US	7
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK	(TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT)
+
+#define TEGRA30_AUDIOCIF_BITS_4				0
+#define TEGRA30_AUDIOCIF_BITS_8				1
+#define TEGRA30_AUDIOCIF_BITS_12			2
+#define TEGRA30_AUDIOCIF_BITS_16			3
+#define TEGRA30_AUDIOCIF_BITS_20			4
+#define TEGRA30_AUDIOCIF_BITS_24			5
+#define TEGRA30_AUDIOCIF_BITS_28			6
+#define TEGRA30_AUDIOCIF_BITS_32			7
+
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT		12
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK		(7                        << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_4		(TEGRA30_AUDIOCIF_BITS_4  << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_8		(TEGRA30_AUDIOCIF_BITS_8  << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_12		(TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16		(TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_20		(TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_24		(TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_28		(TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_32		(TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT		8
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK		(7                        << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_4		(TEGRA30_AUDIOCIF_BITS_4  << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_8		(TEGRA30_AUDIOCIF_BITS_8  << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_12		(TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16		(TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_20		(TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_24		(TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_28		(TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_32		(TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+
+#define TEGRA30_AUDIOCIF_EXPAND_ZERO			0
+#define TEGRA30_AUDIOCIF_EXPAND_ONE			1
+#define TEGRA30_AUDIOCIF_EXPAND_LFSR			2
+
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT		6
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_MASK		(3                            << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_ZERO		(TEGRA30_AUDIOCIF_EXPAND_ZERO << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_ONE		(TEGRA30_AUDIOCIF_EXPAND_ONE  << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_LFSR		(TEGRA30_AUDIOCIF_EXPAND_LFSR << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+
+#define TEGRA30_AUDIOCIF_STEREO_CONV_CH0		0
+#define TEGRA30_AUDIOCIF_STEREO_CONV_CH1		1
+#define TEGRA30_AUDIOCIF_STEREO_CONV_AVG		2
+
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT		4
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_MASK		(3                                << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH0		(TEGRA30_AUDIOCIF_STEREO_CONV_CH0 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH1		(TEGRA30_AUDIOCIF_STEREO_CONV_CH1 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_AVG		(TEGRA30_AUDIOCIF_STEREO_CONV_AVG << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+
+#define TEGRA30_AUDIOCIF_CTRL_REPLICATE			3
+
+#define TEGRA30_AUDIOCIF_DIRECTION_TX			0
+#define TEGRA30_AUDIOCIF_DIRECTION_RX			1
+
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT		2
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_MASK		(1                             << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX		(TEGRA30_AUDIOCIF_DIRECTION_TX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX		(TEGRA30_AUDIOCIF_DIRECTION_RX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
+
+#define TEGRA30_AUDIOCIF_TRUNCATE_ROUND			0
+#define TEGRA30_AUDIOCIF_TRUNCATE_CHOP			1
+
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT		1
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_MASK		(1                               << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_ROUND		(TEGRA30_AUDIOCIF_TRUNCATE_ROUND << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_CHOP		(TEGRA30_AUDIOCIF_TRUNCATE_CHOP  << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
+
+#define TEGRA30_AUDIOCIF_MONO_CONV_ZERO			0
+#define TEGRA30_AUDIOCIF_MONO_CONV_COPY			1
+
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT		0
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_MASK		(1                               << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_ZERO		(TEGRA30_AUDIOCIF_MONO_CONV_ZERO << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_COPY		(TEGRA30_AUDIOCIF_MONO_CONV_COPY << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
+
+/* Registers within TEGRA30_AUDIO_CLUSTER_BASE */
+
+/* TEGRA30_AHUB_CHANNEL_CTRL */
+
+#define TEGRA30_AHUB_CHANNEL_CTRL			0x0
+#define TEGRA30_AHUB_CHANNEL_CTRL_STRIDE		0x20
+#define TEGRA30_AHUB_CHANNEL_CTRL_COUNT			4
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_EN			(1 << 31)
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_EN			(1 << 30)
+#define TEGRA30_AHUB_CHANNEL_CTRL_LOOPBACK		(1 << 29)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT	16
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US	0xff
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK	(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT	8
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US	0xff
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK	(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN		(1 << 6)
+
+#define TEGRA30_PACK_8_4				2
+#define TEGRA30_PACK_16					3
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT		4
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US	3
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK		(TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4		(TEGRA30_PACK_8_4                          << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16		(TEGRA30_PACK_16                           << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN		(1 << 2)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT		0
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US	3
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK		(TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4		(TEGRA30_PACK_8_4                          << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16		(TEGRA30_PACK_16                           << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
+
+/* TEGRA30_AHUB_CHANNEL_CLEAR */
+
+#define TEGRA30_AHUB_CHANNEL_CLEAR			0x4
+#define TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE		0x20
+#define TEGRA30_AHUB_CHANNEL_CLEAR_COUNT		4
+#define TEGRA30_AHUB_CHANNEL_CLEAR_TX_SOFT_RESET	(1 << 31)
+#define TEGRA30_AHUB_CHANNEL_CLEAR_RX_SOFT_RESET	(1 << 30)
+
+/* TEGRA30_AHUB_CHANNEL_STATUS */
+
+#define TEGRA30_AHUB_CHANNEL_STATUS			0x8
+#define TEGRA30_AHUB_CHANNEL_STATUS_STRIDE		0x20
+#define TEGRA30_AHUB_CHANNEL_STATUS_COUNT		4
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT	24
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US	0xff
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK	(TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT	16
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US	0xff
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK	(TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_TRIG		(1 << 1)
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_TRIG		(1 << 0)
+
+/* TEGRA30_AHUB_CHANNEL_TXFIFO */
+
+#define TEGRA30_AHUB_CHANNEL_TXFIFO			0xc
+#define TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE		0x20
+#define TEGRA30_AHUB_CHANNEL_TXFIFO_COUNT		4
+
+/* TEGRA30_AHUB_CHANNEL_RXFIFO */
+
+#define TEGRA30_AHUB_CHANNEL_RXFIFO			0x10
+#define TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE		0x20
+#define TEGRA30_AHUB_CHANNEL_RXFIFO_COUNT		4
+
+/* TEGRA30_AHUB_CIF_TX_CTRL */
+
+#define TEGRA30_AHUB_CIF_TX_CTRL			0x14
+#define TEGRA30_AHUB_CIF_TX_CTRL_STRIDE			0x20
+#define TEGRA30_AHUB_CIF_TX_CTRL_COUNT			4
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* */
+
+/* TEGRA30_AHUB_CIF_RX_CTRL */
+
+#define TEGRA30_AHUB_CIF_RX_CTRL			0x18
+#define TEGRA30_AHUB_CIF_RX_CTRL_STRIDE			0x20
+#define TEGRA30_AHUB_CIF_RX_CTRL_COUNT			4
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* */
+
+/* TEGRA30_AHUB_CONFIG_LINK_CTRL */
+
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL					0x80
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT	28
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US	0xf
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK		(TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT			16
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US		0xfff
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK			(TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT			4
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US			0xfff
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK			(TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_CG_EN				(1 << 2)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_CLEAR_TIMEOUT_CNTR		(1 << 1)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_SOFT_RESET			(1 << 0)
+
+/* TEGRA30_AHUB_MISC_CTRL */
+
+#define TEGRA30_AHUB_MISC_CTRL				0x84
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_ACTIVE		(1 << 31)
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_CG_EN		(1 << 8)
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT	0
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_MASK	(0x1f << TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT)
+
+/* TEGRA30_AHUB_APBDMA_LIVE_STATUS */
+
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS				0x88
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_FULL	(1 << 31)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_FULL	(1 << 30)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_FULL	(1 << 29)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_FULL	(1 << 28)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_FULL	(1 << 27)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_FULL	(1 << 26)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_FULL	(1 << 25)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_FULL	(1 << 24)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_EMPTY	(1 << 23)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_EMPTY	(1 << 22)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_EMPTY	(1 << 21)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_EMPTY	(1 << 20)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_EMPTY	(1 << 19)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_EMPTY	(1 << 18)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_EMPTY	(1 << 17)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_EMPTY	(1 << 16)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_FULL	(1 << 15)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_FULL	(1 << 14)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_FULL	(1 << 13)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_FULL	(1 << 12)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_FULL	(1 << 11)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_FULL	(1 << 10)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_FULL	(1 << 9)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_FULL	(1 << 8)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_EMPTY	(1 << 7)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_EMPTY	(1 << 6)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_EMPTY	(1 << 5)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_EMPTY	(1 << 4)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_EMPTY	(1 << 3)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_EMPTY	(1 << 2)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_EMPTY	(1 << 1)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_EMPTY	(1 << 0)
+
+/* TEGRA30_AHUB_I2S_LIVE_STATUS */
+
+#define TEGRA30_AHUB_I2S_LIVE_STATUS				0x8c
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_FULL		(1 << 29)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_FULL		(1 << 28)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_FULL		(1 << 27)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_FULL		(1 << 26)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_FULL		(1 << 25)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_FULL		(1 << 24)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_FULL		(1 << 23)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_FULL		(1 << 22)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_FULL		(1 << 21)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_FULL		(1 << 20)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_ENABLED	(1 << 19)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_ENABLED	(1 << 18)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_ENABLED	(1 << 17)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_ENABLED	(1 << 16)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_ENABLED	(1 << 15)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_ENABLED	(1 << 14)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_ENABLED	(1 << 13)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_ENABLED	(1 << 12)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED	(1 << 11)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED	(1 << 10)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_EMPTY		(1 << 9)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_EMPTY		(1 << 8)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_EMPTY		(1 << 7)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_EMPTY		(1 << 6)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_EMPTY		(1 << 5)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_EMPTY		(1 << 4)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_EMPTY		(1 << 3)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_EMPTY		(1 << 2)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_EMPTY		(1 << 1)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_EMPTY		(1 << 0)
+
+/* TEGRA30_AHUB_DAM0_LIVE_STATUS */
+
+#define TEGRA30_AHUB_DAM_LIVE_STATUS				0x90
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE			0x8
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_COUNT			3
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_TX_ENABLED			(1 << 26)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1_ENABLED		(1 << 25)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0_ENABLED		(1 << 24)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_FULL		(1 << 15)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_FULL		(1 << 9)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_FULL		(1 << 8)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_EMPTY		(1 << 7)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_EMPTY		(1 << 1)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_EMPTY		(1 << 0)
+
+/* TEGRA30_AHUB_SPDIF_LIVE_STATUS */
+
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS				0xa8
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TX_ENABLED		(1 << 11)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RX_ENABLED		(1 << 10)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TX_ENABLED		(1 << 9)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RX_ENABLED		(1 << 8)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_FULL		(1 << 7)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_FULL		(1 << 6)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_FULL		(1 << 5)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_FULL		(1 << 4)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_EMPTY	(1 << 3)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_EMPTY	(1 << 2)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_EMPTY	(1 << 1)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_EMPTY	(1 << 0)
+
+/* TEGRA30_AHUB_I2S_INT_MASK */
+
+#define TEGRA30_AHUB_I2S_INT_MASK				0xb0
+
+/* TEGRA30_AHUB_DAM_INT_MASK */
+
+#define TEGRA30_AHUB_DAM_INT_MASK				0xb4
+
+/* TEGRA30_AHUB_SPDIF_INT_MASK */
+
+#define TEGRA30_AHUB_SPDIF_INT_MASK				0xbc
+
+/* TEGRA30_AHUB_APBIF_INT_MASK */
+
+#define TEGRA30_AHUB_APBIF_INT_MASK				0xc0
+
+/* TEGRA30_AHUB_I2S_INT_STATUS */
+
+#define TEGRA30_AHUB_I2S_INT_STATUS				0xc8
+
+/* TEGRA30_AHUB_DAM_INT_STATUS */
+
+#define TEGRA30_AHUB_DAM_INT_STATUS				0xcc
+
+/* TEGRA30_AHUB_SPDIF_INT_STATUS */
+
+#define TEGRA30_AHUB_SPDIF_INT_STATUS				0xd4
+
+/* TEGRA30_AHUB_APBIF_INT_STATUS */
+
+#define TEGRA30_AHUB_APBIF_INT_STATUS				0xd8
+
+/* TEGRA30_AHUB_I2S_INT_SOURCE */
+
+#define TEGRA30_AHUB_I2S_INT_SOURCE				0xe0
+
+/* TEGRA30_AHUB_DAM_INT_SOURCE */
+
+#define TEGRA30_AHUB_DAM_INT_SOURCE				0xe4
+
+/* TEGRA30_AHUB_SPDIF_INT_SOURCE */
+
+#define TEGRA30_AHUB_SPDIF_INT_SOURCE				0xec
+
+/* TEGRA30_AHUB_APBIF_INT_SOURCE */
+
+#define TEGRA30_AHUB_APBIF_INT_SOURCE				0xf0
+
+/* TEGRA30_AHUB_I2S_INT_SET */
+
+#define TEGRA30_AHUB_I2S_INT_SET				0xf8
+
+/* TEGRA30_AHUB_DAM_INT_SET */
+
+#define TEGRA30_AHUB_DAM_INT_SET				0xfc
+
+/* TEGRA30_AHUB_SPDIF_INT_SET */
+
+#define TEGRA30_AHUB_SPDIF_INT_SET				0x100
+
+/* TEGRA30_AHUB_APBIF_INT_SET */
+
+#define TEGRA30_AHUB_APBIF_INT_SET				0x104
+
+/* Registers within TEGRA30_AHUB_BASE */
+
+#define TEGRA30_AHUB_AUDIO_RX					0x0
+#define TEGRA30_AHUB_AUDIO_RX_STRIDE				0x4
+#define TEGRA30_AHUB_AUDIO_RX_COUNT				17
+/* This register repeats once for each entry in enum tegra30_ahub_rxcif */
+/* The fields in this register are 1 bit per entry in tegra30_ahub_txcif */
+
+/*
+ * Terminology:
+ * AHUB: Audio Hub; a cross-bar switch between the audio devices: DMA FIFOs,
+ *       I2S controllers, SPDIF controllers, and DAMs.
+ * XBAR: The core cross-bar component of the AHUB.
+ * CIF:  Client Interface; the HW module connecting an audio device to the
+ *       XBAR.
+ * DAM:  Digital Audio Mixer: A HW module that mixes multiple audio streams,
+ *       possibly including sample-rate conversion.
+ *
+ * Each TX CIF transmits data into the XBAR. Each RX CIF can receive audio
+ * transmitted by a particular TX CIF.
+ *
+ * This driver is currently very simplistic; many HW features are not
+ * exposed; DAMs are not supported, only 16-bit stereo audio is supported,
+ * etc.
+ */
+
+enum tegra30_ahub_txcif {
+	TEGRA30_AHUB_TXCIF_APBIF_TX0,
+	TEGRA30_AHUB_TXCIF_APBIF_TX1,
+	TEGRA30_AHUB_TXCIF_APBIF_TX2,
+	TEGRA30_AHUB_TXCIF_APBIF_TX3,
+	TEGRA30_AHUB_TXCIF_I2S0_TX0,
+	TEGRA30_AHUB_TXCIF_I2S1_TX0,
+	TEGRA30_AHUB_TXCIF_I2S2_TX0,
+	TEGRA30_AHUB_TXCIF_I2S3_TX0,
+	TEGRA30_AHUB_TXCIF_I2S4_TX0,
+	TEGRA30_AHUB_TXCIF_DAM0_TX0,
+	TEGRA30_AHUB_TXCIF_DAM1_TX0,
+	TEGRA30_AHUB_TXCIF_DAM2_TX0,
+	TEGRA30_AHUB_TXCIF_SPDIF_TX0,
+	TEGRA30_AHUB_TXCIF_SPDIF_TX1,
+};
+
+enum tegra30_ahub_rxcif {
+	TEGRA30_AHUB_RXCIF_APBIF_RX0,
+	TEGRA30_AHUB_RXCIF_APBIF_RX1,
+	TEGRA30_AHUB_RXcIF_APBIF_RX2,
+	TEGRA30_AHUB_RXCIF_APBIF_RX3,
+	TEGRA30_AHUB_RXCIF_I2S0_RX0,
+	TEGRA30_AHUB_RXCIF_I2S1_RX0,
+	TEGRA30_AHUB_RXCIF_I2S2_RX0,
+	TEGRA30_AHUB_RXCIF_I2S3_RX0,
+	TEGRA30_AHUB_RXCIF_I2S4_RX0,
+	TEGRA30_AHUB_RXCIF_DAM0_RX0,
+	TEGRA30_AHUB_RXCIF_DAM0_RX1,
+	TEGRA30_AHUB_RXCIF_DAM1_RX0,
+	TEGRA30_AHUB_RXCIF_DAM2_RX1,
+	TEGRA30_AHUB_RXCIF_DAM3_RX0,
+	TEGRA30_AHUB_RXCIF_DAM3_RX1,
+	TEGRA30_AHUB_RXCIF_SPDIF_RX0,
+	TEGRA30_AHUB_RXCIF_SPDIF_RX1,
+};
+
+extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
+					 unsigned long *fiforeg,
+					 unsigned long *reqsel);
+extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+
+extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
+					 unsigned long *fiforeg,
+					 unsigned long *reqsel);
+extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
+
+extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
+					  enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
+
+struct tegra30_ahub {
+	struct device *dev;
+	struct clk *clk_d_audio;
+	struct clk *clk_apbif;
+	int dma_sel;
+	resource_size_t apbif_addr;
+	struct regmap *regmap_apbif;
+	struct regmap *regmap_ahub;
+	DECLARE_BITMAP(rx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+	DECLARE_BITMAP(tx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
new file mode 100644
index 0000000..8596032
--- /dev/null
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -0,0 +1,536 @@
+/*
+ * tegra30_i2s.c - Tegra30 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra30_ahub.h"
+#include "tegra30_i2s.h"
+
+#define DRV_NAME "tegra30-i2s"
+
+static inline void tegra30_i2s_write(struct tegra30_i2s *i2s, u32 reg, u32 val)
+{
+	regmap_write(i2s->regmap, reg, val);
+}
+
+static inline u32 tegra30_i2s_read(struct tegra30_i2s *i2s, u32 reg)
+{
+	u32 val;
+	regmap_read(i2s->regmap, reg, &val);
+	return val;
+}
+
+static int tegra30_i2s_runtime_suspend(struct device *dev)
+{
+	struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+
+	regcache_cache_only(i2s->regmap, true);
+
+	clk_disable(i2s->clk_i2s);
+
+	return 0;
+}
+
+static int tegra30_i2s_runtime_resume(struct device *dev)
+{
+	struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_enable(i2s->clk_i2s);
+	if (ret) {
+		dev_err(dev, "clk_enable failed: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(i2s->regmap, false);
+
+	return 0;
+}
+
+int tegra30_i2s_startup(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	int ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
+					&i2s->playback_dma_data.addr,
+					&i2s->playback_dma_data.req_sel);
+		i2s->playback_dma_data.wrap = 4;
+		i2s->playback_dma_data.width = 32;
+		tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
+					       i2s->playback_fifo_cif);
+	} else {
+		ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
+					&i2s->capture_dma_data.addr,
+					&i2s->capture_dma_data.req_sel);
+		i2s->capture_dma_data.wrap = 4;
+		i2s->capture_dma_data.width = 32;
+		tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
+					       i2s->capture_i2s_cif);
+	}
+
+	return ret;
+}
+
+void tegra30_i2s_shutdown(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
+		tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
+	} else {
+		tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif);
+		tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif);
+	}
+}
+
+static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
+				unsigned int fmt)
+{
+	struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_MASTER_ENABLE;
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
+			   TEGRA30_I2S_CTRL_LRCK_MASK);
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct device *dev = substream->pcm->card->dev;
+	struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	u32 val;
+	int ret, sample_size, srate, i2sclock, bitcnt;
+
+	if (params_channels(params) != 2)
+		return -EINVAL;
+
+	i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16;
+		sample_size = 16;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	srate = params_rate(params);
+
+	/* Final "* 2" required by Tegra hardware */
+	i2sclock = srate * params_channels(params) * sample_size * 2;
+
+	bitcnt = (i2sclock / (2 * srate)) - 1;
+	if (bitcnt < 0 || bitcnt > TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
+		return -EINVAL;
+
+	ret = clk_set_rate(i2s->clk_i2s, i2sclock);
+	if (ret) {
+		dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+		return ret;
+	}
+
+	val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+
+	if (i2sclock % (2 * srate))
+		val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE;
+
+	tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val);
+
+	val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+	      (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+	      (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+	      TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
+	      TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
+		tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val);
+	} else {
+		val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
+		tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val);
+	}
+
+	val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
+	      (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
+	tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val);
+
+	return 0;
+}
+
+static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s)
+{
+	tegra30_ahub_enable_tx_fifo(i2s->playback_fifo_cif);
+	i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
+	tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s)
+{
+	tegra30_ahub_disable_tx_fifo(i2s->playback_fifo_cif);
+	i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
+	tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
+{
+	tegra30_ahub_enable_rx_fifo(i2s->capture_fifo_cif);
+	i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX;
+	tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s)
+{
+	tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif);
+	i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
+	tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			tegra30_i2s_start_playback(i2s);
+		else
+			tegra30_i2s_start_capture(i2s);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			tegra30_i2s_stop_playback(i2s);
+		else
+			tegra30_i2s_stop_capture(i2s);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra30_i2s_probe(struct snd_soc_dai *dai)
+{
+	struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	dai->capture_dma_data = &i2s->capture_dma_data;
+	dai->playback_dma_data = &i2s->playback_dma_data;
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
+	.startup	= tegra30_i2s_startup,
+	.shutdown	= tegra30_i2s_shutdown,
+	.set_fmt	= tegra30_i2s_set_fmt,
+	.hw_params	= tegra30_i2s_hw_params,
+	.trigger	= tegra30_i2s_trigger,
+};
+
+static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
+	.probe = tegra30_i2s_probe,
+	.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 = &tegra30_i2s_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA30_I2S_CTRL:
+	case TEGRA30_I2S_TIMING:
+	case TEGRA30_I2S_OFFSET:
+	case TEGRA30_I2S_CH_CTRL:
+	case TEGRA30_I2S_SLOT_CTRL:
+	case TEGRA30_I2S_CIF_RX_CTRL:
+	case TEGRA30_I2S_CIF_TX_CTRL:
+	case TEGRA30_I2S_FLOWCTL:
+	case TEGRA30_I2S_TX_STEP:
+	case TEGRA30_I2S_FLOW_STATUS:
+	case TEGRA30_I2S_FLOW_TOTAL:
+	case TEGRA30_I2S_FLOW_OVER:
+	case TEGRA30_I2S_FLOW_UNDER:
+	case TEGRA30_I2S_LCOEF_1_4_0:
+	case TEGRA30_I2S_LCOEF_1_4_1:
+	case TEGRA30_I2S_LCOEF_1_4_2:
+	case TEGRA30_I2S_LCOEF_1_4_3:
+	case TEGRA30_I2S_LCOEF_1_4_4:
+	case TEGRA30_I2S_LCOEF_1_4_5:
+	case TEGRA30_I2S_LCOEF_2_4_0:
+	case TEGRA30_I2S_LCOEF_2_4_1:
+	case TEGRA30_I2S_LCOEF_2_4_2:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra30_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA30_I2S_FLOW_STATUS:
+	case TEGRA30_I2S_FLOW_TOTAL:
+	case TEGRA30_I2S_FLOW_OVER:
+	case TEGRA30_I2S_FLOW_UNDER:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra30_i2s_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = TEGRA30_I2S_LCOEF_2_4_2,
+	.writeable_reg = tegra30_i2s_wr_rd_reg,
+	.readable_reg = tegra30_i2s_wr_rd_reg,
+	.volatile_reg = tegra30_i2s_volatile_reg,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev)
+{
+	struct tegra30_i2s *i2s;
+	u32 cif_ids[2];
+	struct resource *mem, *memregion;
+	void __iomem *regs;
+	int ret;
+
+	i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_i2s), GFP_KERNEL);
+	if (!i2s) {
+		dev_err(&pdev->dev, "Can't allocate tegra30_i2s\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	dev_set_drvdata(&pdev->dev, i2s);
+
+	i2s->dai = tegra30_i2s_dai_template;
+	i2s->dai.name = dev_name(&pdev->dev);
+
+	ret = of_property_read_u32_array(pdev->dev.of_node,
+					 "nvidia,ahub-cif-ids", cif_ids,
+					 ARRAY_SIZE(cif_ids));
+	if (ret < 0)
+		goto err;
+
+	i2s->playback_i2s_cif = cif_ids[0];
+	i2s->capture_i2s_cif = cif_ids[1];
+
+	i2s->clk_i2s = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(i2s->clk_i2s)) {
+		dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
+		ret = PTR_ERR(i2s->clk_i2s);
+		goto err;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "No memory resource\n");
+		ret = -ENODEV;
+		goto err_clk_put;
+	}
+
+	memregion = devm_request_mem_region(&pdev->dev, mem->start,
+					    resource_size(mem), DRV_NAME);
+	if (!memregion) {
+		dev_err(&pdev->dev, "Memory region already claimed\n");
+		ret = -EBUSY;
+		goto err_clk_put;
+	}
+
+	regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+	if (!regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto err_clk_put;
+	}
+
+	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					    &tegra30_i2s_regmap_config);
+	if (IS_ERR(i2s->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		ret = PTR_ERR(i2s->regmap);
+		goto err_clk_put;
+	}
+	regcache_cache_only(i2s->regmap, true);
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = tegra30_i2s_runtime_resume(&pdev->dev);
+		if (ret)
+			goto err_pm_disable;
+	}
+
+	ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+		ret = -ENOMEM;
+		goto err_suspend;
+	}
+
+	ret = tegra_pcm_platform_register(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+		goto err_unregister_dai;
+	}
+
+	return 0;
+
+err_unregister_dai:
+	snd_soc_unregister_dai(&pdev->dev);
+err_suspend:
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra30_i2s_runtime_suspend(&pdev->dev);
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+err_clk_put:
+	clk_put(i2s->clk_i2s);
+err:
+	return ret;
+}
+
+static int __devexit tegra30_i2s_platform_remove(struct platform_device *pdev)
+{
+	struct tegra30_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra30_i2s_runtime_suspend(&pdev->dev);
+
+	tegra_pcm_platform_unregister(&pdev->dev);
+	snd_soc_unregister_dai(&pdev->dev);
+
+	clk_put(i2s->clk_i2s);
+
+	return 0;
+}
+
+static const struct of_device_id tegra30_i2s_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra30-i2s", },
+	{},
+};
+
+static const struct dev_pm_ops tegra30_i2s_pm_ops __devinitconst = {
+	SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
+			   tegra30_i2s_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra30_i2s_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = tegra30_i2s_of_match,
+		.pm = &tegra30_i2s_pm_ops,
+	},
+	.probe = tegra30_i2s_platform_probe,
+	.remove = __devexit_p(tegra30_i2s_platform_remove),
+};
+module_platform_driver(tegra30_i2s_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 I2S ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra30_i2s_of_match);
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
new file mode 100644
index 0000000..91adf29
--- /dev/null
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -0,0 +1,242 @@
+/*
+ * tegra30_i2s.h - Definitions for Tegra30 I2S driver
+ *
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TEGRA30_I2S_H__
+#define __TEGRA30_I2S_H__
+
+#include "tegra_pcm.h"
+
+/* Register offsets from TEGRA30_I2S*_BASE */
+
+#define TEGRA30_I2S_CTRL				0x0
+#define TEGRA30_I2S_TIMING				0x4
+#define TEGRA30_I2S_OFFSET				0x08
+#define TEGRA30_I2S_CH_CTRL				0x0c
+#define TEGRA30_I2S_SLOT_CTRL				0x10
+#define TEGRA30_I2S_CIF_RX_CTRL				0x14
+#define TEGRA30_I2S_CIF_TX_CTRL				0x18
+#define TEGRA30_I2S_FLOWCTL				0x1c
+#define TEGRA30_I2S_TX_STEP				0x20
+#define TEGRA30_I2S_FLOW_STATUS				0x24
+#define TEGRA30_I2S_FLOW_TOTAL				0x28
+#define TEGRA30_I2S_FLOW_OVER				0x2c
+#define TEGRA30_I2S_FLOW_UNDER				0x30
+#define TEGRA30_I2S_LCOEF_1_4_0				0x34
+#define TEGRA30_I2S_LCOEF_1_4_1				0x38
+#define TEGRA30_I2S_LCOEF_1_4_2				0x3c
+#define TEGRA30_I2S_LCOEF_1_4_3				0x40
+#define TEGRA30_I2S_LCOEF_1_4_4				0x44
+#define TEGRA30_I2S_LCOEF_1_4_5				0x48
+#define TEGRA30_I2S_LCOEF_2_4_0				0x4c
+#define TEGRA30_I2S_LCOEF_2_4_1				0x50
+#define TEGRA30_I2S_LCOEF_2_4_2				0x54
+
+/* Fields in TEGRA30_I2S_CTRL */
+
+#define TEGRA30_I2S_CTRL_XFER_EN_TX			(1 << 31)
+#define TEGRA30_I2S_CTRL_XFER_EN_RX			(1 << 30)
+#define TEGRA30_I2S_CTRL_CG_EN				(1 << 29)
+#define TEGRA30_I2S_CTRL_SOFT_RESET			(1 << 28)
+#define TEGRA30_I2S_CTRL_TX_FLOWCTL_EN			(1 << 27)
+
+#define TEGRA30_I2S_CTRL_OBS_SEL_SHIFT			24
+#define TEGRA30_I2S_CTRL_OBS_SEL_MASK			(7 << TEGRA30_I2S_CTRL_OBS_SEL_SHIFT)
+
+#define TEGRA30_I2S_FRAME_FORMAT_LRCK			0
+#define TEGRA30_I2S_FRAME_FORMAT_FSYNC			1
+
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT		12
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK		(7                              << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT)
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK		(TEGRA30_I2S_FRAME_FORMAT_LRCK  << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT)
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC		(TEGRA30_I2S_FRAME_FORMAT_FSYNC << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT)
+
+#define TEGRA30_I2S_CTRL_MASTER_ENABLE			(1 << 10)
+
+#define TEGRA30_I2S_LRCK_LEFT_LOW			0
+#define TEGRA30_I2S_LRCK_RIGHT_LOW			1
+
+#define TEGRA30_I2S_CTRL_LRCK_SHIFT			9
+#define TEGRA30_I2S_CTRL_LRCK_MASK			(1                          << TEGRA30_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA30_I2S_CTRL_LRCK_L_LOW			(TEGRA30_I2S_LRCK_LEFT_LOW  << TEGRA30_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA30_I2S_CTRL_LRCK_R_LOW			(TEGRA30_I2S_LRCK_RIGHT_LOW << TEGRA30_I2S_CTRL_LRCK_SHIFT)
+
+#define TEGRA30_I2S_CTRL_LPBK_ENABLE			(1 << 8)
+
+#define TEGRA30_I2S_BIT_CODE_LINEAR			0
+#define TEGRA30_I2S_BIT_CODE_ULAW			1
+#define TEGRA30_I2S_BIT_CODE_ALAW			2
+
+#define TEGRA30_I2S_CTRL_BIT_CODE_SHIFT			4
+#define TEGRA30_I2S_CTRL_BIT_CODE_MASK			(3                           << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_CODE_LINEAR		(TEGRA30_I2S_BIT_CODE_LINEAR << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_CODE_ULAW			(TEGRA30_I2S_BIT_CODE_ULAW   << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_CODE_ALAW			(TEGRA30_I2S_BIT_CODE_ALAW   << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+
+#define TEGRA30_I2S_BITS_8				1
+#define TEGRA30_I2S_BITS_12				2
+#define TEGRA30_I2S_BITS_16				3
+#define TEGRA30_I2S_BITS_20				4
+#define TEGRA30_I2S_BITS_24				5
+#define TEGRA30_I2S_BITS_28				6
+#define TEGRA30_I2S_BITS_32				7
+
+/* Sample container size; see {RX,TX}_MASK field in CH_CTRL below */
+#define TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT			0
+#define TEGRA30_I2S_CTRL_BIT_SIZE_MASK			(7                   << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_8			(TEGRA30_I2S_BITS_8  << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_12			(TEGRA30_I2S_BITS_12 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_16			(TEGRA30_I2S_BITS_16 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_20			(TEGRA30_I2S_BITS_20 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_24			(TEGRA30_I2S_BITS_24 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_28			(TEGRA30_I2S_BITS_28 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_32			(TEGRA30_I2S_BITS_32 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+
+/* Fields in TEGRA30_I2S_TIMING */
+
+#define TEGRA30_I2S_TIMING_NON_SYM_ENABLE		(1 << 12)
+#define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT	0
+#define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US	0x7fff
+#define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK	(TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
+
+/* Fields in TEGRA30_I2S_OFFSET */
+
+#define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT		16
+#define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK_US	0x7ff
+#define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK		(TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK_US << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT)
+#define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT		0
+#define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK_US	0x7ff
+#define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK		(TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK_US << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT)
+
+/* Fields in TEGRA30_I2S_CH_CTRL */
+
+/* (FSYNC width - 1) in bit clocks */
+#define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT		24
+#define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK_US		0xff
+#define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK		(TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK_US << TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT)
+
+#define TEGRA30_I2S_HIGHZ_NO				0
+#define TEGRA30_I2S_HIGHZ_YES				1
+#define TEGRA30_I2S_HIGHZ_ON_HALF_BIT_CLK		2
+
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT		12
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_MASK		(3                                 << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_NO		(TEGRA30_I2S_HIGHZ_NO              << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_YES		(TEGRA30_I2S_HIGHZ_YES             << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_ON_HALF_BIT_CLK	(TEGRA30_I2S_HIGHZ_ON_HALF_BIT_CLK << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+
+#define TEGRA30_I2S_MSB_FIRST				0
+#define TEGRA30_I2S_LSB_FIRST				1
+
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT		10
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_MASK		(1                     << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_MSB_FIRST	(TEGRA30_I2S_MSB_FIRST << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_LSB_FIRST	(TEGRA30_I2S_LSB_FIRST << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT		9
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_MASK		(1                     << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_MSB_FIRST	(TEGRA30_I2S_MSB_FIRST << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_LSB_FIRST	(TEGRA30_I2S_LSB_FIRST << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT)
+
+#define TEGRA30_I2S_POS_EDGE				0
+#define TEGRA30_I2S_NEG_EDGE				1
+
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT		8
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK		(1                    << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE		(TEGRA30_I2S_POS_EDGE << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE		(TEGRA30_I2S_NEG_EDGE << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT)
+
+/* Sample size is # bits from BIT_SIZE minus this field */
+#define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_SHIFT		4
+#define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK_US	7
+#define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK		(TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK_US << TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_SHIFT)
+
+#define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_SHIFT		0
+#define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK_US	7
+#define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK		(TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK_US << TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_SHIFT)
+
+/* Fields in TEGRA30_I2S_SLOT_CTRL */
+
+/* Number of slots in frame, minus 1 */
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT		16
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US	7
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK		(TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT)
+
+/* TDM mode slot enable bitmask */
+#define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT	8
+#define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK	(0xff << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT)
+
+#define TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT	0
+#define TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK	(0xff << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT)
+
+/* Fields in TEGRA30_I2S_CIF_RX_CTRL */
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* in tegra30_ahub.h */
+
+/* Fields in TEGRA30_I2S_CIF_TX_CTRL */
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* in tegra30_ahub.h */
+
+/* Fields in TEGRA30_I2S_FLOWCTL */
+
+#define TEGRA30_I2S_FILTER_LINEAR			0
+#define TEGRA30_I2S_FILTER_QUAD				1
+
+#define TEGRA30_I2S_FLOWCTL_FILTER_SHIFT		31
+#define TEGRA30_I2S_FLOWCTL_FILTER_MASK			(1                         << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT)
+#define TEGRA30_I2S_FLOWCTL_FILTER_LINEAR		(TEGRA30_I2S_FILTER_LINEAR << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT)
+#define TEGRA30_I2S_FLOWCTL_FILTER_QUAD			(TEGRA30_I2S_FILTER_QUAD   << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT)
+
+/* Fields in TEGRA30_I2S_TX_STEP */
+
+#define TEGRA30_I2S_TX_STEP_SHIFT			0
+#define TEGRA30_I2S_TX_STEP_MASK_US			0xffff
+#define TEGRA30_I2S_TX_STEP_MASK			(TEGRA30_I2S_TX_STEP_MASK_US << TEGRA30_I2S_TX_STEP_SHIFT)
+
+/* Fields in TEGRA30_I2S_FLOW_STATUS */
+
+#define TEGRA30_I2S_FLOW_STATUS_UNDERFLOW		(1 << 31)
+#define TEGRA30_I2S_FLOW_STATUS_OVERFLOW		(1 << 30)
+#define TEGRA30_I2S_FLOW_STATUS_MONITOR_INT_EN		(1 << 4)
+#define TEGRA30_I2S_FLOW_STATUS_COUNTER_CLR		(1 << 3)
+#define TEGRA30_I2S_FLOW_STATUS_MONITOR_CLR		(1 << 2)
+#define TEGRA30_I2S_FLOW_STATUS_COUNTER_EN		(1 << 1)
+#define TEGRA30_I2S_FLOW_STATUS_MONITOR_EN		(1 << 0)
+
+/*
+ * There are no fields in TEGRA30_I2S_FLOW_TOTAL, TEGRA30_I2S_FLOW_OVER,
+ * TEGRA30_I2S_FLOW_UNDER; they are counters taking the whole register.
+ */
+
+/* Fields in TEGRA30_I2S_LCOEF_* */
+
+#define TEGRA30_I2S_LCOEF_COEF_SHIFT			0
+#define TEGRA30_I2S_LCOEF_COEF_MASK_US			0xffff
+#define TEGRA30_I2S_LCOEF_COEF_MASK			(TEGRA30_I2S_LCOEF_COEF_MASK_US << TEGRA30_I2S_LCOEF_COEF_SHIFT)
+
+struct tegra30_i2s {
+	struct snd_soc_dai_driver dai;
+	int cif_id;
+	struct clk *clk_i2s;
+	enum tegra30_ahub_txcif capture_i2s_cif;
+	enum tegra30_ahub_rxcif capture_fifo_cif;
+	struct tegra_pcm_dma_params capture_dma_data;
+	enum tegra30_ahub_rxcif playback_i2s_cif;
+	enum tegra30_ahub_txcif playback_fifo_cif;
+	struct tegra_pcm_dma_params playback_dma_data;
+	struct regmap *regmap;
+	u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index e45ccd8..32de700 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -1,16 +1,17 @@
 /*
-* tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
-*
-* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
-*
-* Authors:  Leon Romanovsky <leon@leon.nu>
-*           Andrey Danin <danindrey@mail.ru>
-*           Marc Dietrich <marvin24@gmx.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.
-*/
+ * tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
+ *
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * Copyright (C) 2012 - NVIDIA, Inc.
+ *
+ * Authors:  Leon Romanovsky <leon@leon.nu>
+ *           Andrey Danin <danindrey@mail.ru>
+ *           Marc Dietrich <marvin24@gmx.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.
+ */
 
 #include <asm/mach-types.h>
 
@@ -28,9 +29,6 @@
 
 #include "../codecs/alc5632.h"
 
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
 
 #define DRV_NAME "tegra-alc5632"
@@ -39,7 +37,6 @@
 
 struct tegra_alc5632 {
 	struct tegra_asoc_utils_data util_data;
-	struct platform_device *pcm_dev;
 	int gpio_requested;
 	int gpio_hp_det;
 };
@@ -140,7 +137,6 @@
 static struct snd_soc_dai_link tegra_alc5632_dai = {
 	.name = "ALC5632",
 	.stream_name = "ALC5632 PCM",
-	.platform_name = "tegra-pcm-audio",
 	.codec_dai_name = "alc5632-hifi",
 	.init = tegra_alc5632_asoc_init,
 	.ops = &tegra_alc5632_asoc_ops,
@@ -179,8 +175,6 @@
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, alc5632);
 
-	alc5632->pcm_dev = ERR_PTR(-EINVAL);
-
 	if (!(pdev->dev.of_node)) {
 		dev_err(&pdev->dev, "Must be instantiated using device tree\n");
 		ret = -EINVAL;
@@ -214,18 +208,11 @@
 		goto err;
 	}
 
-	alc5632->pcm_dev = platform_device_register_simple(
-		"tegra-pcm-audio", -1, NULL, 0);
-	if (IS_ERR(alc5632->pcm_dev)) {
-		dev_err(&pdev->dev,
-			"Can't instantiate tegra-pcm-audio\n");
-		ret = PTR_ERR(alc5632->pcm_dev);
-		goto err;
-	}
+	tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_dai_of_node;
 
 	ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
 	if (ret)
-		goto err_unregister;
+		goto err;
 
 	ret = snd_soc_register_card(card);
 	if (ret) {
@@ -238,9 +225,6 @@
 
 err_fini_utils:
 	tegra_asoc_utils_fini(&alc5632->util_data);
-err_unregister:
-	if (!IS_ERR(alc5632->pcm_dev))
-		platform_device_unregister(alc5632->pcm_dev);
 err:
 	return ret;
 }
@@ -259,8 +243,6 @@
 	snd_soc_unregister_card(card);
 
 	tegra_asoc_utils_fini(&machine->util_data);
-	if (!IS_ERR(machine->pcm_dev))
-		platform_device_unregister(machine->pcm_dev);
 
 	return 0;
 }
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index f8428e4..9515ce5 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -2,7 +2,7 @@
  * tegra_asoc_utils.c - Harmony machine ASoC driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -25,6 +25,7 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #include "tegra_asoc_utils.h"
 
@@ -40,7 +41,10 @@
 	case 22050:
 	case 44100:
 	case 88200:
-		new_baseclock = 56448000;
+		if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+			new_baseclock = 56448000;
+		else
+			new_baseclock = 564480000;
 		break;
 	case 8000:
 	case 16000:
@@ -48,7 +52,10 @@
 	case 48000:
 	case 64000:
 	case 96000:
-		new_baseclock = 73728000;
+		if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+			new_baseclock = 73728000;
+		else
+			new_baseclock = 552960000;
 		break;
 	default:
 		return -EINVAL;
@@ -78,7 +85,7 @@
 		return err;
 	}
 
-	/* Don't set cdev1 rate; its locked to pll_a_out0 */
+	/* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
 
 	err = clk_enable(data->clk_pll_a);
 	if (err) {
@@ -112,6 +119,17 @@
 
 	data->dev = dev;
 
+	if (of_machine_is_compatible("nvidia,tegra20"))
+		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
+	else if (of_machine_is_compatible("nvidia,tegra30"))
+		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
+	else if (!dev->of_node)
+		/* non-DT is always Tegra20 */
+		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
+	else
+		/* DT boot, but unknown SoC */
+		return -EINVAL;
+
 	data->clk_pll_a = clk_get_sys(NULL, "pll_a");
 	if (IS_ERR(data->clk_pll_a)) {
 		dev_err(data->dev, "Can't retrieve clk pll_a\n");
@@ -126,15 +144,24 @@
 		goto err_put_pll_a;
 	}
 
-	data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
+	if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+		data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
+	else
+		data->clk_cdev1 = clk_get_sys("extern1", NULL);
 	if (IS_ERR(data->clk_cdev1)) {
 		dev_err(data->dev, "Can't retrieve clk cdev1\n");
 		ret = PTR_ERR(data->clk_cdev1);
 		goto err_put_pll_a_out0;
 	}
 
+	ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
+	if (ret)
+		goto err_put_cdev1;
+
 	return 0;
 
+err_put_cdev1:
+	clk_put(data->clk_cdev1);
 err_put_pll_a_out0:
 	clk_put(data->clk_pll_a_out0);
 err_put_pll_a:
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 4818195..44db1db 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -2,7 +2,7 @@
  * tegra_asoc_utils.h - Definitions for Tegra DAS driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -26,8 +26,14 @@
 struct clk;
 struct device;
 
+enum tegra_asoc_utils_soc {
+	TEGRA_ASOC_UTILS_SOC_TEGRA20,
+	TEGRA_ASOC_UTILS_SOC_TEGRA30,
+};
+
 struct tegra_asoc_utils_data {
 	struct device *dev;
+	enum tegra_asoc_utils_soc soc;
 	struct clk *clk_pll_a;
 	struct clk *clk_pll_a_out0;
 	struct clk *clk_cdev1;
@@ -42,4 +48,3 @@
 void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
 
 #endif
-
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c
deleted file mode 100644
index 3b3c1ba..0000000
--- a/sound/soc/tegra/tegra_das.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * tegra_das.c - Tegra DAS driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, 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.
- *
- * 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/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <mach/iomap.h>
-#include <sound/soc.h>
-#include "tegra_das.h"
-
-#define DRV_NAME "tegra-das"
-
-static struct tegra_das *das;
-
-static inline void tegra_das_write(u32 reg, u32 val)
-{
-	__raw_writel(val, das->regs + reg);
-}
-
-static inline u32 tegra_das_read(u32 reg)
-{
-	return __raw_readl(das->regs + reg);
-}
-
-int tegra_das_connect_dap_to_dac(int dap, int dac)
-{
-	u32 addr;
-	u32 reg;
-
-	if (!das)
-		return -ENODEV;
-
-	addr = TEGRA_DAS_DAP_CTRL_SEL +
-		(dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
-	reg = dac << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
-
-	tegra_das_write(addr, reg);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dac);
-
-int tegra_das_connect_dap_to_dap(int dap, int otherdap, int master,
-					int sdata1rx, int sdata2rx)
-{
-	u32 addr;
-	u32 reg;
-
-	if (!das)
-		return -ENODEV;
-
-	addr = TEGRA_DAS_DAP_CTRL_SEL +
-		(dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
-	reg = otherdap << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
-		!!sdata2rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
-		!!sdata1rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
-		!!master << TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
-
-	tegra_das_write(addr, reg);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dap);
-
-int tegra_das_connect_dac_to_dap(int dac, int dap)
-{
-	u32 addr;
-	u32 reg;
-
-	if (!das)
-		return -ENODEV;
-
-	addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
-		(dac * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
-	reg = dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
-		dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
-		dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
-
-	tegra_das_write(addr, reg);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dac_to_dap);
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_das_show(struct seq_file *s, void *unused)
-{
-	int i;
-	u32 addr;
-	u32 reg;
-
-	for (i = 0; i < TEGRA_DAS_DAP_CTRL_SEL_COUNT; i++) {
-		addr = TEGRA_DAS_DAP_CTRL_SEL +
-			(i * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
-		reg = tegra_das_read(addr);
-		seq_printf(s, "TEGRA_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg);
-	}
-
-	for (i = 0; i < TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) {
-		addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
-			(i * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
-		reg = tegra_das_read(addr);
-		seq_printf(s, "TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n",
-				 i, reg);
-	}
-
-	return 0;
-}
-
-static int tegra_das_debug_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, tegra_das_show, inode->i_private);
-}
-
-static const struct file_operations tegra_das_debug_fops = {
-	.open    = tegra_das_debug_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = single_release,
-};
-
-static void tegra_das_debug_add(struct tegra_das *das)
-{
-	das->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
-					 snd_soc_debugfs_root, das,
-					 &tegra_das_debug_fops);
-}
-
-static void tegra_das_debug_remove(struct tegra_das *das)
-{
-	if (das->debug)
-		debugfs_remove(das->debug);
-}
-#else
-static inline void tegra_das_debug_add(struct tegra_das *das)
-{
-}
-
-static inline void tegra_das_debug_remove(struct tegra_das *das)
-{
-}
-#endif
-
-static int __devinit tegra_das_probe(struct platform_device *pdev)
-{
-	struct resource *res, *region;
-	int ret = 0;
-
-	if (das)
-		return -ENODEV;
-
-	das = devm_kzalloc(&pdev->dev, sizeof(struct tegra_das), GFP_KERNEL);
-	if (!das) {
-		dev_err(&pdev->dev, "Can't allocate tegra_das\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-	das->dev = &pdev->dev;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "No memory resource\n");
-		ret = -ENODEV;
-		goto err;
-	}
-
-	region = devm_request_mem_region(&pdev->dev, res->start,
-					 resource_size(res), pdev->name);
-	if (!region) {
-		dev_err(&pdev->dev, "Memory region already claimed\n");
-		ret = -EBUSY;
-		goto err;
-	}
-
-	das->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-	if (!das->regs) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1,
-					   TEGRA_DAS_DAP_SEL_DAC1);
-	if (ret) {
-		dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
-		goto err;
-	}
-	ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1,
-					   TEGRA_DAS_DAC_SEL_DAP1);
-	if (ret) {
-		dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
-		goto err;
-	}
-
-	tegra_das_debug_add(das);
-
-	platform_set_drvdata(pdev, das);
-
-	return 0;
-
-err:
-	das = NULL;
-	return ret;
-}
-
-static int __devexit tegra_das_remove(struct platform_device *pdev)
-{
-	if (!das)
-		return -ENODEV;
-
-	tegra_das_debug_remove(das);
-
-	das = NULL;
-
-	return 0;
-}
-
-static const struct of_device_id tegra_das_of_match[] __devinitconst = {
-	{ .compatible = "nvidia,tegra20-das", },
-	{},
-};
-
-static struct platform_driver tegra_das_driver = {
-	.probe = tegra_das_probe,
-	.remove = __devexit_p(tegra_das_remove),
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-		.of_match_table = tegra_das_of_match,
-	},
-};
-module_platform_driver(tegra_das_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra DAS driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra_das_of_match);
diff --git a/sound/soc/tegra/tegra_das.h b/sound/soc/tegra/tegra_das.h
deleted file mode 100644
index 2c96c7b..0000000
--- a/sound/soc/tegra/tegra_das.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * tegra_das.h - Definitions for Tegra DAS driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, 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.
- *
- * 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 __TEGRA_DAS_H__
-#define __TEGRA_DAS_H__
-
-/* Register TEGRA_DAS_DAP_CTRL_SEL */
-#define TEGRA_DAS_DAP_CTRL_SEL				0x00
-#define TEGRA_DAS_DAP_CTRL_SEL_COUNT			5
-#define TEGRA_DAS_DAP_CTRL_SEL_STRIDE			4
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P		31
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S		1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P	30
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S	1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P	29
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S	1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P		0
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S		5
-
-/* Values for field TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
-#define TEGRA_DAS_DAP_SEL_DAC1	0
-#define TEGRA_DAS_DAP_SEL_DAC2	1
-#define TEGRA_DAS_DAP_SEL_DAC3	2
-#define TEGRA_DAS_DAP_SEL_DAP1	16
-#define TEGRA_DAS_DAP_SEL_DAP2	17
-#define TEGRA_DAS_DAP_SEL_DAP3	18
-#define TEGRA_DAS_DAP_SEL_DAP4	19
-#define TEGRA_DAS_DAP_SEL_DAP5	20
-
-/* Register TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL */
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL			0x40
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT			3
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE			4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P	28
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S	4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P	24
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S	4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P		0
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S		4
-
-/*
- * Values for:
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
- */
-#define TEGRA_DAS_DAC_SEL_DAP1	0
-#define TEGRA_DAS_DAC_SEL_DAP2	1
-#define TEGRA_DAS_DAC_SEL_DAP3	2
-#define TEGRA_DAS_DAC_SEL_DAP4	3
-#define TEGRA_DAS_DAC_SEL_DAP5	4
-
-/*
- * Names/IDs of the DACs/DAPs.
- */
-
-#define TEGRA_DAS_DAP_ID_1 0
-#define TEGRA_DAS_DAP_ID_2 1
-#define TEGRA_DAS_DAP_ID_3 2
-#define TEGRA_DAS_DAP_ID_4 3
-#define TEGRA_DAS_DAP_ID_5 4
-
-#define TEGRA_DAS_DAC_ID_1 0
-#define TEGRA_DAS_DAC_ID_2 1
-#define TEGRA_DAS_DAC_ID_3 2
-
-struct tegra_das {
-	struct device *dev;
-	void __iomem *regs;
-	struct dentry *debug;
-};
-
-/*
- * Terminology:
- * DAS: Digital audio switch (HW module controlled by this driver)
- * DAP: Digital audio port (port/pins on Tegra device)
- * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
- * 
- * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
- * DAC, or another DAP. When DAPs are connected, one must be the master and
- * one the slave. Each DAC allows selection of a specific DAP for input, to
- * cater for the case where N DAPs are connected to 1 DAC for broadcast
- * output.
- *
- * This driver is dumb; no attempt is made to ensure that a valid routing
- * configuration is programmed.
- */
-
-/*
- * Connect a DAP to to a DAC
- * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
- * dac_sel: DAC to connect to: TEGRA_DAS_DAP_SEL_DAC*
- */
-extern int tegra_das_connect_dap_to_dac(int dap_id, int dac_sel);
-
-/*
- * Connect a DAP to to another DAP
- * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
- * other_dap_sel: DAP to connect to: TEGRA_DAS_DAP_SEL_DAP*
- * master: Is this DAP the master (1) or slave (0)
- * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
- * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
- */
-extern int tegra_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
-					int master, int sdata1rx,
-					int sdata2rx);
-
-/*
- * Connect a DAC's input to a DAP
- * (DAC outputs are selected by the DAP)
- * dac_id: DAC ID to connect: TEGRA_DAS_DAC_ID_*
- * dap_sel: DAP to receive input from: TEGRA_DAS_DAC_SEL_DAP*
- */
-extern int tegra_das_connect_dac_to_dap(int dac_id, int dap_sel);
-
-#endif
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
deleted file mode 100644
index e533499..0000000
--- a/sound/soc/tegra/tegra_i2s.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * tegra_i2s.c - Tegra I2S driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * Copyright (c) 2009-2010, NVIDIA Corporation.
- * Scott Peterson <speterson@nvidia.com>
- *
- * Copyright (C) 2010 Google, Inc.
- * Iliyan Malchev <malchev@google.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
- *
- */
-
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <mach/iomap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "tegra_i2s.h"
-
-#define DRV_NAME "tegra-i2s"
-
-static inline void tegra_i2s_write(struct tegra_i2s *i2s, u32 reg, u32 val)
-{
-	__raw_writel(val, i2s->regs + reg);
-}
-
-static inline u32 tegra_i2s_read(struct tegra_i2s *i2s, u32 reg)
-{
-	return __raw_readl(i2s->regs + reg);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_i2s_show(struct seq_file *s, void *unused)
-{
-#define REG(r) { r, #r }
-	static const struct {
-		int offset;
-		const char *name;
-	} regs[] = {
-		REG(TEGRA_I2S_CTRL),
-		REG(TEGRA_I2S_STATUS),
-		REG(TEGRA_I2S_TIMING),
-		REG(TEGRA_I2S_FIFO_SCR),
-		REG(TEGRA_I2S_PCM_CTRL),
-		REG(TEGRA_I2S_NW_CTRL),
-		REG(TEGRA_I2S_TDM_CTRL),
-		REG(TEGRA_I2S_TDM_TX_RX_CTRL),
-	};
-#undef REG
-
-	struct tegra_i2s *i2s = s->private;
-	int i;
-
-	clk_enable(i2s->clk_i2s);
-
-	for (i = 0; i < ARRAY_SIZE(regs); i++) {
-		u32 val = tegra_i2s_read(i2s, regs[i].offset);
-		seq_printf(s, "%s = %08x\n", regs[i].name, val);
-	}
-
-	clk_disable(i2s->clk_i2s);
-
-	return 0;
-}
-
-static int tegra_i2s_debug_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, tegra_i2s_show, inode->i_private);
-}
-
-static const struct file_operations tegra_i2s_debug_fops = {
-	.open    = tegra_i2s_debug_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = single_release,
-};
-
-static void tegra_i2s_debug_add(struct tegra_i2s *i2s)
-{
-	i2s->debug = debugfs_create_file(i2s->dai.name, S_IRUGO,
-					 snd_soc_debugfs_root, i2s,
-					 &tegra_i2s_debug_fops);
-}
-
-static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
-{
-	if (i2s->debug)
-		debugfs_remove(i2s->debug);
-}
-#else
-static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s)
-{
-}
-
-static inline void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
-{
-}
-#endif
-
-static int tegra_i2s_set_fmt(struct snd_soc_dai *dai,
-				unsigned int fmt)
-{
-	struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_NF:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_MASTER_ENABLE;
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBS_CFS:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_MASTER_ENABLE;
-		break;
-	case SND_SOC_DAIFMT_CBM_CFM:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	i2s->reg_ctrl &= ~(TEGRA_I2S_CTRL_BIT_FORMAT_MASK | 
-				TEGRA_I2S_CTRL_LRCK_MASK);
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_DSP_A:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-		break;
-	case SND_SOC_DAIFMT_DSP_B:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_R_LOW;
-		break;
-	case SND_SOC_DAIFMT_I2S:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_I2S;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-		break;
-	case SND_SOC_DAIFMT_RIGHT_J:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_RJM;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_LJM;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params,
-				struct snd_soc_dai *dai)
-{
-        struct device *dev = substream->pcm->card->dev;
-	struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-	u32 reg;
-	int ret, sample_size, srate, i2sclock, bitcnt;
-
-	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_BIT_SIZE_MASK;
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_16;
-		sample_size = 16;
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_24;
-		sample_size = 24;
-		break;
-	case SNDRV_PCM_FORMAT_S32_LE:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_32;
-		sample_size = 32;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	srate = params_rate(params);
-
-	/* Final "* 2" required by Tegra hardware */
-	i2sclock = srate * params_channels(params) * sample_size * 2;
-
-	ret = clk_set_rate(i2s->clk_i2s, i2sclock);
-	if (ret) {
-		dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
-		return ret;
-	}
-
-	bitcnt = (i2sclock / (2 * srate)) - 1;
-	if (bitcnt < 0 || bitcnt > TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
-		return -EINVAL;
-	reg = bitcnt << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
-
-	if (i2sclock % (2 * srate))
-		reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE;
-
-	if (!i2s->clk_refs)
-		clk_enable(i2s->clk_i2s);
-
-	tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg);
-
-	tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR,
-		TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
-		TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
-
-	if (!i2s->clk_refs)
-		clk_disable(i2s->clk_i2s);
-
-	return 0;
-}
-
-static void tegra_i2s_start_playback(struct tegra_i2s *i2s)
-{
-	i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO1_ENABLE;
-	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_stop_playback(struct tegra_i2s *i2s)
-{
-	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO1_ENABLE;
-	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_start_capture(struct tegra_i2s *i2s)
-{
-	i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO2_ENABLE;
-	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_stop_capture(struct tegra_i2s *i2s)
-{
-	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO2_ENABLE;
-	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-				struct snd_soc_dai *dai)
-{
-	struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-	case SNDRV_PCM_TRIGGER_RESUME:
-		if (!i2s->clk_refs)
-			clk_enable(i2s->clk_i2s);
-		i2s->clk_refs++;
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			tegra_i2s_start_playback(i2s);
-		else
-			tegra_i2s_start_capture(i2s);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			tegra_i2s_stop_playback(i2s);
-		else
-			tegra_i2s_stop_capture(i2s);
-		i2s->clk_refs--;
-		if (!i2s->clk_refs)
-			clk_disable(i2s->clk_i2s);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int tegra_i2s_probe(struct snd_soc_dai *dai)
-{
-	struct tegra_i2s * i2s = snd_soc_dai_get_drvdata(dai);
-
-	dai->capture_dma_data = &i2s->capture_dma_data;
-	dai->playback_dma_data = &i2s->playback_dma_data;
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops tegra_i2s_dai_ops = {
-	.set_fmt	= tegra_i2s_set_fmt,
-	.hw_params	= tegra_i2s_hw_params,
-	.trigger	= tegra_i2s_trigger,
-};
-
-static const struct snd_soc_dai_driver tegra_i2s_dai_template = {
-	.probe = tegra_i2s_probe,
-	.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 = &tegra_i2s_dai_ops,
-	.symmetric_rates = 1,
-};
-
-static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
-{
-	struct tegra_i2s * i2s;
-	struct resource *mem, *memregion, *dmareq;
-	u32 of_dma[2];
-	u32 dma_ch;
-	int ret;
-
-	i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL);
-	if (!i2s) {
-		dev_err(&pdev->dev, "Can't allocate tegra_i2s\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-	dev_set_drvdata(&pdev->dev, i2s);
-
-	i2s->dai = tegra_i2s_dai_template;
-	i2s->dai.name = dev_name(&pdev->dev);
-
-	i2s->clk_i2s = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(i2s->clk_i2s)) {
-		dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
-		ret = PTR_ERR(i2s->clk_i2s);
-		goto err;
-	}
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(&pdev->dev, "No memory resource\n");
-		ret = -ENODEV;
-		goto err_clk_put;
-	}
-
-	dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!dmareq) {
-		if (of_property_read_u32_array(pdev->dev.of_node,
-					"nvidia,dma-request-selector",
-					of_dma, 2) < 0) {
-			dev_err(&pdev->dev, "No DMA resource\n");
-			ret = -ENODEV;
-			goto err_clk_put;
-		}
-		dma_ch = of_dma[1];
-	} else {
-		dma_ch = dmareq->start;
-	}
-
-	memregion = devm_request_mem_region(&pdev->dev, mem->start,
-					    resource_size(mem), DRV_NAME);
-	if (!memregion) {
-		dev_err(&pdev->dev, "Memory region already claimed\n");
-		ret = -EBUSY;
-		goto err_clk_put;
-	}
-
-	i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
-	if (!i2s->regs) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENOMEM;
-		goto err_clk_put;
-	}
-
-	i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2;
-	i2s->capture_dma_data.wrap = 4;
-	i2s->capture_dma_data.width = 32;
-	i2s->capture_dma_data.req_sel = dma_ch;
-
-	i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1;
-	i2s->playback_dma_data.wrap = 4;
-	i2s->playback_dma_data.width = 32;
-	i2s->playback_dma_data.req_sel = dma_ch;
-
-	i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
-
-	ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
-	if (ret) {
-		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
-		ret = -ENOMEM;
-		goto err_clk_put;
-	}
-
-	tegra_i2s_debug_add(i2s);
-
-	return 0;
-
-err_clk_put:
-	clk_put(i2s->clk_i2s);
-err:
-	return ret;
-}
-
-static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev)
-{
-	struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev);
-
-	snd_soc_unregister_dai(&pdev->dev);
-
-	tegra_i2s_debug_remove(i2s);
-
-	clk_put(i2s->clk_i2s);
-
-	return 0;
-}
-
-static const struct of_device_id tegra_i2s_of_match[] __devinitconst = {
-	{ .compatible = "nvidia,tegra20-i2s", },
-	{},
-};
-
-static struct platform_driver tegra_i2s_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-		.of_match_table = tegra_i2s_of_match,
-	},
-	.probe = tegra_i2s_platform_probe,
-	.remove = __devexit_p(tegra_i2s_platform_remove),
-};
-module_platform_driver(tegra_i2s_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra I2S ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra_i2s_of_match);
diff --git a/sound/soc/tegra/tegra_i2s.h b/sound/soc/tegra/tegra_i2s.h
deleted file mode 100644
index 15ce1e2..0000000
--- a/sound/soc/tegra/tegra_i2s.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * tegra_i2s.h - Definitions for Tegra I2S driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * Copyright (c) 2009-2010, NVIDIA Corporation.
- * Scott Peterson <speterson@nvidia.com>
- *
- * Copyright (C) 2010 Google, Inc.
- * Iliyan Malchev <malchev@google.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 __TEGRA_I2S_H__
-#define __TEGRA_I2S_H__
-
-#include "tegra_pcm.h"
-
-/* Register offsets from TEGRA_I2S1_BASE and TEGRA_I2S2_BASE */
-
-#define TEGRA_I2S_CTRL					0x00
-#define TEGRA_I2S_STATUS				0x04
-#define TEGRA_I2S_TIMING				0x08
-#define TEGRA_I2S_FIFO_SCR				0x0c
-#define TEGRA_I2S_PCM_CTRL				0x10
-#define TEGRA_I2S_NW_CTRL				0x14
-#define TEGRA_I2S_TDM_CTRL				0x20
-#define TEGRA_I2S_TDM_TX_RX_CTRL			0x24
-#define TEGRA_I2S_FIFO1					0x40
-#define TEGRA_I2S_FIFO2					0x80
-
-/* Fields in TEGRA_I2S_CTRL */
-
-#define TEGRA_I2S_CTRL_FIFO2_TX_ENABLE			(1 << 30)
-#define TEGRA_I2S_CTRL_FIFO1_ENABLE			(1 << 29)
-#define TEGRA_I2S_CTRL_FIFO2_ENABLE			(1 << 28)
-#define TEGRA_I2S_CTRL_FIFO1_RX_ENABLE			(1 << 27)
-#define TEGRA_I2S_CTRL_FIFO_LPBK_ENABLE			(1 << 26)
-#define TEGRA_I2S_CTRL_MASTER_ENABLE			(1 << 25)
-
-#define TEGRA_I2S_LRCK_LEFT_LOW				0
-#define TEGRA_I2S_LRCK_RIGHT_LOW			1
-
-#define TEGRA_I2S_CTRL_LRCK_SHIFT			24
-#define TEGRA_I2S_CTRL_LRCK_MASK			(1                        << TEGRA_I2S_CTRL_LRCK_SHIFT)
-#define TEGRA_I2S_CTRL_LRCK_L_LOW			(TEGRA_I2S_LRCK_LEFT_LOW  << TEGRA_I2S_CTRL_LRCK_SHIFT)
-#define TEGRA_I2S_CTRL_LRCK_R_LOW			(TEGRA_I2S_LRCK_RIGHT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT)
-
-#define TEGRA_I2S_BIT_FORMAT_I2S			0
-#define TEGRA_I2S_BIT_FORMAT_RJM			1
-#define TEGRA_I2S_BIT_FORMAT_LJM			2
-#define TEGRA_I2S_BIT_FORMAT_DSP			3
-
-#define TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT			10
-#define TEGRA_I2S_CTRL_BIT_FORMAT_MASK			(3                        << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_I2S			(TEGRA_I2S_BIT_FORMAT_I2S << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_RJM			(TEGRA_I2S_BIT_FORMAT_RJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_LJM			(TEGRA_I2S_BIT_FORMAT_LJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_DSP			(TEGRA_I2S_BIT_FORMAT_DSP << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-
-#define TEGRA_I2S_BIT_SIZE_16				0
-#define TEGRA_I2S_BIT_SIZE_20				1
-#define TEGRA_I2S_BIT_SIZE_24				2
-#define TEGRA_I2S_BIT_SIZE_32				3
-
-#define TEGRA_I2S_CTRL_BIT_SIZE_SHIFT			8
-#define TEGRA_I2S_CTRL_BIT_SIZE_MASK			(3                     << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_16			(TEGRA_I2S_BIT_SIZE_16 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_20			(TEGRA_I2S_BIT_SIZE_20 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_24			(TEGRA_I2S_BIT_SIZE_24 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_32			(TEGRA_I2S_BIT_SIZE_32 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-
-#define TEGRA_I2S_FIFO_16_LSB				0
-#define TEGRA_I2S_FIFO_20_LSB				1
-#define TEGRA_I2S_FIFO_24_LSB				2
-#define TEGRA_I2S_FIFO_32				3
-#define TEGRA_I2S_FIFO_PACKED				7
-
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT		4
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_MASK			(7                     << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_16_LSB		(TEGRA_I2S_FIFO_16_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_20_LSB		(TEGRA_I2S_FIFO_20_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_24_LSB		(TEGRA_I2S_FIFO_24_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_32			(TEGRA_I2S_FIFO_32     << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED		(TEGRA_I2S_FIFO_PACKED << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-
-#define TEGRA_I2S_CTRL_IE_FIFO1_ERR			(1 << 3)
-#define TEGRA_I2S_CTRL_IE_FIFO2_ERR			(1 << 2)
-#define TEGRA_I2S_CTRL_QE_FIFO1				(1 << 1)
-#define TEGRA_I2S_CTRL_QE_FIFO2				(1 << 0)
-
-/* Fields in TEGRA_I2S_STATUS */
-
-#define TEGRA_I2S_STATUS_FIFO1_RDY			(1 << 31)
-#define TEGRA_I2S_STATUS_FIFO2_RDY			(1 << 30)
-#define TEGRA_I2S_STATUS_FIFO1_BSY			(1 << 29)
-#define TEGRA_I2S_STATUS_FIFO2_BSY			(1 << 28)
-#define TEGRA_I2S_STATUS_FIFO1_ERR			(1 << 3)
-#define TEGRA_I2S_STATUS_FIFO2_ERR			(1 << 2)
-#define TEGRA_I2S_STATUS_QS_FIFO1			(1 << 1)
-#define TEGRA_I2S_STATUS_QS_FIFO2			(1 << 0)
-
-/* Fields in TEGRA_I2S_TIMING */
-
-#define TEGRA_I2S_TIMING_NON_SYM_ENABLE			(1 << 12)
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT	0
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US	0x7fff
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK		(TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
-
-/* Fields in TEGRA_I2S_FIFO_SCR */
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT	24
-#define TEGRA_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT	16
-#define TEGRA_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK	0x3f
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_CLR			(1 << 12)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_CLR			(1 << 8)
-
-#define TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT			0
-#define TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS		1
-#define TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS		2
-#define TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS		3
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT		4
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK		(3 << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT	(TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT		0
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK		(3 << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT	(TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-
-struct tegra_i2s {
-	struct snd_soc_dai_driver dai;
-	struct clk *clk_i2s;
-	int clk_refs;
-	struct tegra_pcm_dma_params capture_dma_data;
-	struct tegra_pcm_dma_params playback_dma_data;
-	void __iomem *regs;
-	struct dentry *debug;
-	u32 reg_ctrl;
-};
-
-#endif
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 8b44571..127348d 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -2,7 +2,7 @@
  * tegra_pcm.c - Tegra PCM driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * Based on code copyright/by:
  *
@@ -29,8 +29,8 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -39,8 +39,6 @@
 
 #include "tegra_pcm.h"
 
-#define DRV_NAME "tegra-pcm-audio"
-
 static const struct snd_pcm_hardware tegra_pcm_hardware = {
 	.info			= SNDRV_PCM_INFO_MMAP |
 				  SNDRV_PCM_INFO_MMAP_VALID |
@@ -372,28 +370,18 @@
 	.pcm_free	= tegra_pcm_free,
 };
 
-static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev)
+int __devinit tegra_pcm_platform_register(struct device *dev)
 {
-	return snd_soc_register_platform(&pdev->dev, &tegra_pcm_platform);
+	return snd_soc_register_platform(dev, &tegra_pcm_platform);
 }
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
 
-static int __devexit tegra_pcm_platform_remove(struct platform_device *pdev)
+void __devexit tegra_pcm_platform_unregister(struct device *dev)
 {
-	snd_soc_unregister_platform(&pdev->dev);
-	return 0;
+	snd_soc_unregister_platform(dev);
 }
-
-static struct platform_driver tegra_pcm_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = tegra_pcm_platform_probe,
-	.remove = __devexit_p(tegra_pcm_platform_remove),
-};
-module_platform_driver(tegra_pcm_driver);
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra PCM ASoC driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index dbb9033..985d418 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -2,7 +2,7 @@
  * tegra_pcm.h - Definitions for Tegra PCM driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * Based on code copyright/by:
  *
@@ -52,4 +52,7 @@
 	struct tegra_dma_channel *dma_chan;
 };
 
+int tegra_pcm_platform_register(struct device *dev);
+void tegra_pcm_platform_unregister(struct device *dev);
+
 #endif
diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c
deleted file mode 100644
index 9ff2c60..0000000
--- a/sound/soc/tegra/tegra_spdif.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * tegra_spdif.c - Tegra SPDIF driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2011 - NVIDIA, 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.
- *
- * 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/clk.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <mach/iomap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "tegra_spdif.h"
-
-#define DRV_NAME "tegra-spdif"
-
-static inline void tegra_spdif_write(struct tegra_spdif *spdif, u32 reg,
-					u32 val)
-{
-	__raw_writel(val, spdif->regs + reg);
-}
-
-static inline u32 tegra_spdif_read(struct tegra_spdif *spdif, u32 reg)
-{
-	return __raw_readl(spdif->regs + reg);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_spdif_show(struct seq_file *s, void *unused)
-{
-#define REG(r) { r, #r }
-	static const struct {
-		int offset;
-		const char *name;
-	} regs[] = {
-		REG(TEGRA_SPDIF_CTRL),
-		REG(TEGRA_SPDIF_STATUS),
-		REG(TEGRA_SPDIF_STROBE_CTRL),
-		REG(TEGRA_SPDIF_DATA_FIFO_CSR),
-		REG(TEGRA_SPDIF_CH_STA_RX_A),
-		REG(TEGRA_SPDIF_CH_STA_RX_B),
-		REG(TEGRA_SPDIF_CH_STA_RX_C),
-		REG(TEGRA_SPDIF_CH_STA_RX_D),
-		REG(TEGRA_SPDIF_CH_STA_RX_E),
-		REG(TEGRA_SPDIF_CH_STA_RX_F),
-		REG(TEGRA_SPDIF_CH_STA_TX_A),
-		REG(TEGRA_SPDIF_CH_STA_TX_B),
-		REG(TEGRA_SPDIF_CH_STA_TX_C),
-		REG(TEGRA_SPDIF_CH_STA_TX_D),
-		REG(TEGRA_SPDIF_CH_STA_TX_E),
-		REG(TEGRA_SPDIF_CH_STA_TX_F),
-	};
-#undef REG
-
-	struct tegra_spdif *spdif = s->private;
-	int i;
-
-	clk_enable(spdif->clk_spdif_out);
-
-	for (i = 0; i < ARRAY_SIZE(regs); i++) {
-		u32 val = tegra_spdif_read(spdif, regs[i].offset);
-		seq_printf(s, "%s = %08x\n", regs[i].name, val);
-	}
-
-	clk_disable(spdif->clk_spdif_out);
-
-	return 0;
-}
-
-static int tegra_spdif_debug_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, tegra_spdif_show, inode->i_private);
-}
-
-static const struct file_operations tegra_spdif_debug_fops = {
-	.open    = tegra_spdif_debug_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = single_release,
-};
-
-static void tegra_spdif_debug_add(struct tegra_spdif *spdif)
-{
-	spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
-						snd_soc_debugfs_root, spdif,
-						&tegra_spdif_debug_fops);
-}
-
-static void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
-{
-	if (spdif->debug)
-		debugfs_remove(spdif->debug);
-}
-#else
-static inline void tegra_spdif_debug_add(struct tegra_spdif *spdif)
-{
-}
-
-static inline void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
-{
-}
-#endif
-
-static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params,
-				struct snd_soc_dai *dai)
-{
-	struct device *dev = substream->pcm->card->dev;
-	struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-	int ret, spdifclock;
-
-	spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_PACK;
-	spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_BIT_MODE_MASK;
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_PACK;
-		spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_BIT_MODE_16BIT;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (params_rate(params)) {
-	case 32000:
-		spdifclock = 4096000;
-		break;
-	case 44100:
-		spdifclock = 5644800;
-		break;
-	case 48000:
-		spdifclock = 6144000;
-		break;
-	case 88200:
-		spdifclock = 11289600;
-		break;
-	case 96000:
-		spdifclock = 12288000;
-		break;
-	case 176400:
-		spdifclock = 22579200;
-		break;
-	case 192000:
-		spdifclock = 24576000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
-	if (ret) {
-		dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-static void tegra_spdif_start_playback(struct tegra_spdif *spdif)
-{
-	spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_TX_EN;
-	tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
-}
-
-static void tegra_spdif_stop_playback(struct tegra_spdif *spdif)
-{
-	spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_TX_EN;
-	tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
-}
-
-static int tegra_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
-				struct snd_soc_dai *dai)
-{
-	struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-	case SNDRV_PCM_TRIGGER_RESUME:
-		if (!spdif->clk_refs)
-			clk_enable(spdif->clk_spdif_out);
-		spdif->clk_refs++;
-		tegra_spdif_start_playback(spdif);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-		tegra_spdif_stop_playback(spdif);
-		spdif->clk_refs--;
-		if (!spdif->clk_refs)
-			clk_disable(spdif->clk_spdif_out);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int tegra_spdif_probe(struct snd_soc_dai *dai)
-{
-	struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-
-	dai->capture_dma_data = NULL;
-	dai->playback_dma_data = &spdif->playback_dma_data;
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops tegra_spdif_dai_ops = {
-	.hw_params	= tegra_spdif_hw_params,
-	.trigger	= tegra_spdif_trigger,
-};
-
-static struct snd_soc_dai_driver tegra_spdif_dai = {
-	.name = DRV_NAME,
-	.probe = tegra_spdif_probe,
-	.playback = {
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
-				SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = &tegra_spdif_dai_ops,
-};
-
-static __devinit int tegra_spdif_platform_probe(struct platform_device *pdev)
-{
-	struct tegra_spdif *spdif;
-	struct resource *mem, *memregion, *dmareq;
-	int ret;
-
-	spdif = kzalloc(sizeof(struct tegra_spdif), GFP_KERNEL);
-	if (!spdif) {
-		dev_err(&pdev->dev, "Can't allocate tegra_spdif\n");
-		ret = -ENOMEM;
-		goto exit;
-	}
-	dev_set_drvdata(&pdev->dev, spdif);
-
-	spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
-	if (IS_ERR(spdif->clk_spdif_out)) {
-		pr_err("Can't retrieve spdif clock\n");
-		ret = PTR_ERR(spdif->clk_spdif_out);
-		goto err_free;
-	}
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(&pdev->dev, "No memory resource\n");
-		ret = -ENODEV;
-		goto err_clk_put;
-	}
-
-	dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!dmareq) {
-		dev_err(&pdev->dev, "No DMA resource\n");
-		ret = -ENODEV;
-		goto err_clk_put;
-	}
-
-	memregion = request_mem_region(mem->start, resource_size(mem),
-					DRV_NAME);
-	if (!memregion) {
-		dev_err(&pdev->dev, "Memory region already claimed\n");
-		ret = -EBUSY;
-		goto err_clk_put;
-	}
-
-	spdif->regs = ioremap(mem->start, resource_size(mem));
-	if (!spdif->regs) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENOMEM;
-		goto err_release;
-	}
-
-	spdif->playback_dma_data.addr = mem->start + TEGRA_SPDIF_DATA_OUT;
-	spdif->playback_dma_data.wrap = 4;
-	spdif->playback_dma_data.width = 32;
-	spdif->playback_dma_data.req_sel = dmareq->start;
-
-	ret = snd_soc_register_dai(&pdev->dev, &tegra_spdif_dai);
-	if (ret) {
-		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
-		ret = -ENOMEM;
-		goto err_unmap;
-	}
-
-	tegra_spdif_debug_add(spdif);
-
-	return 0;
-
-err_unmap:
-	iounmap(spdif->regs);
-err_release:
-	release_mem_region(mem->start, resource_size(mem));
-err_clk_put:
-	clk_put(spdif->clk_spdif_out);
-err_free:
-	kfree(spdif);
-exit:
-	return ret;
-}
-
-static int __devexit tegra_spdif_platform_remove(struct platform_device *pdev)
-{
-	struct tegra_spdif *spdif = dev_get_drvdata(&pdev->dev);
-	struct resource *res;
-
-	snd_soc_unregister_dai(&pdev->dev);
-
-	tegra_spdif_debug_remove(spdif);
-
-	iounmap(spdif->regs);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, resource_size(res));
-
-	clk_put(spdif->clk_spdif_out);
-
-	kfree(spdif);
-
-	return 0;
-}
-
-static struct platform_driver tegra_spdif_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = tegra_spdif_platform_probe,
-	.remove = __devexit_p(tegra_spdif_platform_remove),
-};
-
-module_platform_driver(tegra_spdif_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra SPDIF ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_spdif.h b/sound/soc/tegra/tegra_spdif.h
deleted file mode 100644
index 2e03db4..0000000
--- a/sound/soc/tegra/tegra_spdif.h
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * tegra_spdif.h - Definitions for Tegra SPDIF driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2011 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- * Copyright (c) 2008-2009, NVIDIA 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
- *
- */
-
-#ifndef __TEGRA_SPDIF_H__
-#define __TEGRA_SPDIF_H__
-
-#include "tegra_pcm.h"
-
-/* Offsets from TEGRA_SPDIF_BASE */
-
-#define TEGRA_SPDIF_CTRL					0x0
-#define TEGRA_SPDIF_STATUS					0x4
-#define TEGRA_SPDIF_STROBE_CTRL					0x8
-#define TEGRA_SPDIF_DATA_FIFO_CSR				0x0C
-#define TEGRA_SPDIF_DATA_OUT					0x40
-#define TEGRA_SPDIF_DATA_IN					0x80
-#define TEGRA_SPDIF_CH_STA_RX_A					0x100
-#define TEGRA_SPDIF_CH_STA_RX_B					0x104
-#define TEGRA_SPDIF_CH_STA_RX_C					0x108
-#define TEGRA_SPDIF_CH_STA_RX_D					0x10C
-#define TEGRA_SPDIF_CH_STA_RX_E					0x110
-#define TEGRA_SPDIF_CH_STA_RX_F					0x114
-#define TEGRA_SPDIF_CH_STA_TX_A					0x140
-#define TEGRA_SPDIF_CH_STA_TX_B					0x144
-#define TEGRA_SPDIF_CH_STA_TX_C					0x148
-#define TEGRA_SPDIF_CH_STA_TX_D					0x14C
-#define TEGRA_SPDIF_CH_STA_TX_E					0x150
-#define TEGRA_SPDIF_CH_STA_TX_F					0x154
-#define TEGRA_SPDIF_USR_STA_RX_A				0x180
-#define TEGRA_SPDIF_USR_DAT_TX_A				0x1C0
-
-/* Fields in TEGRA_SPDIF_CTRL */
-
-/* Start capturing from 0=right, 1=left channel */
-#define TEGRA_SPDIF_CTRL_CAP_LC					(1 << 30)
-
-/* SPDIF receiver(RX) enable */
-#define TEGRA_SPDIF_CTRL_RX_EN					(1 << 29)
-
-/* SPDIF Transmitter(TX) enable */
-#define TEGRA_SPDIF_CTRL_TX_EN					(1 << 28)
-
-/* Transmit Channel status */
-#define TEGRA_SPDIF_CTRL_TC_EN					(1 << 27)
-
-/* Transmit user Data */
-#define TEGRA_SPDIF_CTRL_TU_EN					(1 << 26)
-
-/* Interrupt on transmit error */
-#define TEGRA_SPDIF_CTRL_IE_TXE					(1 << 25)
-
-/* Interrupt on receive error */
-#define TEGRA_SPDIF_CTRL_IE_RXE					(1 << 24)
-
-/* Interrupt on invalid preamble */
-#define TEGRA_SPDIF_CTRL_IE_P					(1 << 23)
-
-/* Interrupt on "B" preamble */
-#define TEGRA_SPDIF_CTRL_IE_B					(1 << 22)
-
-/* Interrupt when block of channel status received */
-#define TEGRA_SPDIF_CTRL_IE_C					(1 << 21)
-
-/* Interrupt when a valid information unit (IU) is received */
-#define TEGRA_SPDIF_CTRL_IE_U					(1 << 20)
-
-/* Interrupt when RX user FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_RU					(1 << 19)
-
-/* Interrupt when TX user FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_TU					(1 << 18)
-
-/* Interrupt when RX data FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_RX					(1 << 17)
-
-/* Interrupt when TX data FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_TX					(1 << 16)
-
-/* Loopback test mode enable */
-#define TEGRA_SPDIF_CTRL_LBK_EN					(1 << 15)
-
-/*
- * Pack data mode:
- * 0 = Single data (16 bit needs to be  padded to match the
- *     interface data bit size).
- * 1 = Packeted left/right channel data into a single word.
- */
-#define TEGRA_SPDIF_CTRL_PACK					(1 << 14)
-
-/*
- * 00 = 16bit data
- * 01 = 20bit data
- * 10 = 24bit data
- * 11 = raw data
- */
-#define TEGRA_SPDIF_BIT_MODE_16BIT				0
-#define TEGRA_SPDIF_BIT_MODE_20BIT				1
-#define TEGRA_SPDIF_BIT_MODE_24BIT				2
-#define TEGRA_SPDIF_BIT_MODE_RAW				3
-
-#define TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT				12
-#define TEGRA_SPDIF_CTRL_BIT_MODE_MASK				(3                          << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_16BIT				(TEGRA_SPDIF_BIT_MODE_16BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_20BIT				(TEGRA_SPDIF_BIT_MODE_20BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_24BIT				(TEGRA_SPDIF_BIT_MODE_24BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_RAW				(TEGRA_SPDIF_BIT_MODE_RAW   << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-
-/* Fields in TEGRA_SPDIF_STATUS */
-
-/*
- * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
- * write a 1 to the corresponding bit location to clear the status.
- */
-
-/*
- * Receiver(RX) shifter is busy receiving data.
- * This bit is asserted when the receiver first locked onto the
- * preamble of the data stream after RX_EN is asserted. This bit is
- * deasserted when either,
- * (a) the end of a frame is reached after RX_EN is deeasserted, or
- * (b) the SPDIF data stream becomes inactive.
- */
-#define TEGRA_SPDIF_STATUS_RX_BSY				(1 << 29)
-
-/*
- * Transmitter(TX) shifter is busy transmitting data.
- * This bit is asserted when TX_EN is asserted.
- * This bit is deasserted when the end of a frame is reached after
- * TX_EN is deasserted.
- */
-#define TEGRA_SPDIF_STATUS_TX_BSY				(1 << 28)
-
-/*
- * TX is busy shifting out channel status.
- * This bit is asserted when both TX_EN and TC_EN are asserted and
- * data from CH_STA_TX_A register is loaded into the internal shifter.
- * This bit is deasserted when either,
- * (a) the end of a frame is reached after TX_EN is deasserted, or
- * (b) CH_STA_TX_F register is loaded into the internal shifter.
- */
-#define TEGRA_SPDIF_STATUS_TC_BSY				(1 << 27)
-
-/*
- * TX User data FIFO busy.
- * This bit is asserted when TX_EN and TXU_EN are asserted and
- * there's data in the TX user FIFO.  This bit is deassert when either,
- * (a) the end of a frame is reached after TX_EN is deasserted, or
- * (b) there's no data left in the TX user FIFO.
- */
-#define TEGRA_SPDIF_STATUS_TU_BSY				(1 << 26)
-
-/* TX FIFO Underrun error status */
-#define TEGRA_SPDIF_STATUS_TX_ERR				(1 << 25)
-
-/* RX FIFO Overrun error status */
-#define TEGRA_SPDIF_STATUS_RX_ERR				(1 << 24)
-
-/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
-#define TEGRA_SPDIF_STATUS_IS_P					(1 << 23)
-
-/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
-#define TEGRA_SPDIF_STATUS_IS_B					(1 << 22)
-
-/*
- * RX channel block data receive status:
- * 0=entire block not recieved yet.
- * 1=received entire block of channel status,
- */
-#define TEGRA_SPDIF_STATUS_IS_C					(1 << 21)
-
-/* RX User Data Valid flag:  1=valid IU detected, 0 = no IU detected. */
-#define TEGRA_SPDIF_STATUS_IS_U					(1 << 20)
-
-/*
- * RX User FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_RU				(1 << 19)
-
-/*
- * TX User FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_TU				(1 << 18)
-
-/*
- * RX Data FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_RX				(1 << 17)
-
-/*
- * TX Data FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_TX				(1 << 16)
-
-/* Fields in TEGRA_SPDIF_STROBE_CTRL */
-
-/*
- * Indicates the approximate number of detected SPDIFIN clocks within a
- * bi-phase period.
- */
-#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT			16
-#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_MASK			(0xff << TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
-
-/* Data strobe mode: 0=Auto-locked 1=Manual locked */
-#define TEGRA_SPDIF_STROBE_CTRL_STROBE				(1 << 15)
-
-/*
- * Manual data strobe time within the bi-phase clock period (in terms of
- * the number of over-sampling clocks).
- */
-#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT		8
-#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_MASK		(0x1f << TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
-
-/*
- * Manual SPDIFIN bi-phase clock period (in terms of the number of
- * over-sampling clocks).
- */
-#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT		0
-#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK		(0x3f << TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
-
-/* Fields in SPDIF_DATA_FIFO_CSR */
-
-/* Clear Receiver User FIFO (RX USR.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_CLR			(1 << 31)
-
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT			0
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS			1
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS			2
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS			3
-
-/* RU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT		29
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK		\
-		(0x3                                    << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-
-/* Number of RX USR.FIFO levels with valid data. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT		24
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK		(0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
-
-/* Clear Transmitter User FIFO (TX USR.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_CLR			(1 << 23)
-
-/* TU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT		21
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK		\
-		(0x3                                   << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-
-/* Number of TX USR.FIFO levels that could be filled. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT		16
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK		(0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
-
-/* Clear Receiver Data FIFO (RX DATA.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_CLR			(1 << 15)
-
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT			0
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS			1
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS			2
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS			3
-
-/* RU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT		13
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK		\
-		(0x3                                     << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-
-/* Number of RX DATA.FIFO levels with valid data. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT		8
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK		(0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
-
-/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_CLR			(1 << 7)
-
-/* TU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT		5
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK		\
-		(0x3                                     << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-
-/* Number of TX DATA.FIFO levels that could be filled. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT		0
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK		(0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_DATA_OUT */
-
-/*
- * This register has 5 different formats:
- * 16-bit        (BIT_MODE=00, PACK=0)
- * 20-bit        (BIT_MODE=01, PACK=0)
- * 24-bit        (BIT_MODE=10, PACK=0)
- * raw           (BIT_MODE=11, PACK=0)
- * 16-bit packed (BIT_MODE=00, PACK=1)
- */
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT			0
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_MASK			(0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT			0
-#define TEGRA_SPDIF_DATA_OUT_DATA_20_MASK			(0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT			0
-#define TEGRA_SPDIF_DATA_OUT_DATA_24_MASK			(0xffffff << TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_P				(1 << 31)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_C				(1 << 30)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_U				(1 << 29)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_V				(1 << 28)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT		8
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK			(0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT			4
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK			(0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT		0
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK		(0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT		16
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK		(0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT		0
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK		(0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_DATA_IN */
-
-/*
- * This register has 5 different formats:
- * 16-bit        (BIT_MODE=00, PACK=0)
- * 20-bit        (BIT_MODE=01, PACK=0)
- * 24-bit        (BIT_MODE=10, PACK=0)
- * raw           (BIT_MODE=11, PACK=0)
- * 16-bit packed (BIT_MODE=00, PACK=1)
- *
- * Bits 31:24 are common to all modes except 16-bit packed
- */
-
-#define TEGRA_SPDIF_DATA_IN_DATA_P				(1 << 31)
-#define TEGRA_SPDIF_DATA_IN_DATA_C				(1 << 30)
-#define TEGRA_SPDIF_DATA_IN_DATA_U				(1 << 29)
-#define TEGRA_SPDIF_DATA_IN_DATA_V				(1 << 28)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT			24
-#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_MASK			(0xf << TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT			0
-#define TEGRA_SPDIF_DATA_IN_DATA_16_MASK			(0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT			0
-#define TEGRA_SPDIF_DATA_IN_DATA_20_MASK			(0xfffff << TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT			0
-#define TEGRA_SPDIF_DATA_IN_DATA_24_MASK			(0xffffff << TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT			8
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_MASK			(0xfffff << TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT			4
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_MASK			(0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT		0
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK		(0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT		16
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK		(0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT		0
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK		(0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_CH_STA_RX_A */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_B */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_C */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_D */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_E */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_F */
-
-/*
- * The 6-word receive channel data page buffer holds a block (192 frames) of
- * channel status information. The order of receive is from LSB to MSB
- * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
- */
-
-/* Fields in TEGRA_SPDIF_CH_STA_TX_A */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_B */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_C */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_D */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_E */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_F */
-
-/*
- * The 6-word transmit channel data page buffer holds a block (192 frames) of
- * channel status information. The order of transmission is from LSB to MSB
- * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
- */
-
-/* Fields in TEGRA_SPDIF_USR_STA_RX_A */
-
-/*
- * This 4-word deep FIFO receives user FIFO field information. The order of
- * receive is from LSB to MSB bit.
- */
-
-/* Fields in TEGRA_SPDIF_USR_DAT_TX_A */
-
-/*
- * This 4-word deep FIFO transmits user FIFO field information. The order of
- * transmission is from LSB to MSB bit.
- */
-
-struct tegra_spdif {
-	struct clk *clk_spdif_out;
-	int clk_refs;
-	struct tegra_pcm_dma_params capture_dma_data;
-	struct tegra_pcm_dma_params playback_dma_data;
-	void __iomem *regs;
-	struct dentry *debug;
-	u32 reg_ctrl;
-};
-
-#endif
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
new file mode 100644
index 0000000..4e77026
--- /dev/null
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -0,0 +1,224 @@
+/*
+ * tegra_wm8753.c - Tegra machine ASoC driver for boards using WM8753 codec.
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@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.
+ *
+ * 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 <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm8753.h"
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-wm8753"
+
+struct tegra_wm8753 {
+	struct tegra_asoc_utils_data util_data;
+};
+
+static int tegra_wm8753_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_codec *codec = rtd->codec;
+	struct snd_soc_card *card = codec->card;
+	struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
+	int srate, mclk;
+	int err;
+
+	srate = params_rate(params);
+	switch (srate) {
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+		mclk = 11289600;
+		break;
+	default:
+		mclk = 12288000;
+		break;
+	}
+
+	err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+	if (err < 0) {
+		dev_err(card->dev, "Can't configure clocks\n");
+		return err;
+	}
+
+	err = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, mclk,
+					SND_SOC_CLOCK_IN);
+	if (err < 0) {
+		dev_err(card->dev, "codec_dai clock not set\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops tegra_wm8753_ops = {
+	.hw_params = tegra_wm8753_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tegra_wm8753_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static struct snd_soc_dai_link tegra_wm8753_dai = {
+	.name = "WM8753",
+	.stream_name = "WM8753 PCM",
+	.codec_dai_name = "wm8753-hifi",
+	.ops = &tegra_wm8753_ops,
+	.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_wm8753 = {
+	.name = "tegra-wm8753",
+	.owner = THIS_MODULE,
+	.dai_link = &tegra_wm8753_dai,
+	.num_links = 1,
+
+	.dapm_widgets = tegra_wm8753_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra_wm8753_dapm_widgets),
+	.fully_routed = true,
+};
+
+static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &snd_soc_tegra_wm8753;
+	struct tegra_wm8753 *machine;
+	int ret;
+
+	machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8753),
+			       GFP_KERNEL);
+	if (!machine) {
+		dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+	snd_soc_card_set_drvdata(card, machine);
+
+	ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+	if (ret)
+		goto err;
+
+	ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+	if (ret)
+		goto err;
+
+	tegra_wm8753_dai.codec_of_node = of_parse_phandle(
+			pdev->dev.of_node, "nvidia,audio-codec", 0);
+	if (!tegra_wm8753_dai.codec_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'nvidia,audio-codec' missing or invalid\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	tegra_wm8753_dai.cpu_dai_of_node = of_parse_phandle(
+			pdev->dev.of_node, "nvidia,i2s-controller", 0);
+	if (!tegra_wm8753_dai.cpu_dai_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'nvidia,i2s-controller' missing or invalid\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	tegra_wm8753_dai.platform_of_node =
+				tegra_wm8753_dai.cpu_dai_of_node;
+
+	ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+	if (ret)
+		goto err;
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err_fini_utils;
+	}
+
+	return 0;
+
+err_fini_utils:
+	tegra_asoc_utils_fini(&machine->util_data);
+err:
+	return ret;
+}
+
+static int __devexit tegra_wm8753_driver_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
+
+	snd_soc_unregister_card(card);
+
+	tegra_asoc_utils_fini(&machine->util_data);
+
+	return 0;
+}
+
+static const struct of_device_id tegra_wm8753_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra-audio-wm8753", },
+	{},
+};
+
+static struct platform_driver tegra_wm8753_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = tegra_wm8753_of_match,
+	},
+	.probe = tegra_wm8753_driver_probe,
+	.remove = __devexit_p(tegra_wm8753_driver_remove),
+};
+module_platform_driver(tegra_wm8753_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra+WM8753 machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_wm8753_of_match);
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 566655e..0b0df49 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -2,7 +2,7 @@
  * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec.
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
  *
  * Based on code copyright/by:
  *
@@ -46,9 +46,6 @@
 
 #include "../codecs/wm8903.h"
 
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
 
 #define DRV_NAME "tegra-snd-wm8903"
@@ -61,7 +58,6 @@
 
 struct tegra_wm8903 {
 	struct tegra_wm8903_platform_data pdata;
-	struct platform_device *pcm_dev;
 	struct tegra_asoc_utils_data util_data;
 	int gpio_requested;
 };
@@ -354,8 +350,8 @@
 	.name = "WM8903",
 	.stream_name = "WM8903 PCM",
 	.codec_name = "wm8903.0-001a",
-	.platform_name = "tegra-pcm-audio",
-	.cpu_dai_name = "tegra-i2s.0",
+	.platform_name = "tegra20-i2s.0",
+	.cpu_dai_name = "tegra20-i2s.0",
 	.codec_dai_name = "wm8903-hifi",
 	.init = tegra_wm8903_init,
 	.ops = &tegra_wm8903_ops,
@@ -392,7 +388,6 @@
 		ret = -ENOMEM;
 		goto err;
 	}
-	machine->pcm_dev = ERR_PTR(-EINVAL);
 
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
@@ -428,14 +423,9 @@
 			goto err;
 		}
 
-		machine->pcm_dev = platform_device_register_simple(
-					"tegra-pcm-audio", -1, NULL, 0);
-		if (IS_ERR(machine->pcm_dev)) {
-			dev_err(&pdev->dev,
-				"Can't instantiate tegra-pcm-audio\n");
-			ret = PTR_ERR(machine->pcm_dev);
-			goto err;
-		}
+		tegra_wm8903_dai.platform_name = NULL;
+		tegra_wm8903_dai.platform_of_node =
+					tegra_wm8903_dai.cpu_dai_of_node;
 	} else {
 		if (machine_is_harmony()) {
 			card->dapm_routes = harmony_audio_map;
@@ -454,7 +444,7 @@
 
 	ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
 	if (ret)
-		goto err_unregister;
+		goto err;
 
 	ret = snd_soc_register_card(card);
 	if (ret) {
@@ -467,9 +457,6 @@
 
 err_fini_utils:
 	tegra_asoc_utils_fini(&machine->util_data);
-err_unregister:
-	if (!IS_ERR(machine->pcm_dev))
-		platform_device_unregister(machine->pcm_dev);
 err:
 	return ret;
 }
@@ -497,8 +484,6 @@
 	snd_soc_unregister_card(card);
 
 	tegra_asoc_utils_fini(&machine->util_data);
-	if (!IS_ERR(machine->pcm_dev))
-		platform_device_unregister(machine->pcm_dev);
 
 	return 0;
 }
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index 2bdfc550..4a8d5b6 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -27,6 +27,7 @@
 #include <asm/mach-types.h>
 
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
@@ -38,9 +39,6 @@
 
 #include "../codecs/tlv320aic23.h"
 
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
 
 #define DRV_NAME "tegra-snd-trimslice"
@@ -119,8 +117,8 @@
 	.name = "TLV320AIC23",
 	.stream_name = "AIC23",
 	.codec_name = "tlv320aic23-codec.2-001a",
-	.platform_name = "tegra-pcm-audio",
-	.cpu_dai_name = "tegra-i2s.0",
+	.platform_name = "tegra20-i2s.0",
+	.cpu_dai_name = "tegra20-i2s.0",
 	.codec_dai_name = "tlv320aic23-hifi",
 	.ops = &trimslice_asoc_ops,
 };
@@ -152,6 +150,32 @@
 		goto err;
 	}
 
+	if (pdev->dev.of_node) {
+		trimslice_tlv320aic23_dai.codec_name = NULL;
+		trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(
+				pdev->dev.of_node, "nvidia,audio-codec", 0);
+		if (!trimslice_tlv320aic23_dai.codec_of_node) {
+			dev_err(&pdev->dev,
+				"Property 'nvidia,audio-codec' missing or invalid\n");
+			ret = -EINVAL;
+			goto err;
+		}
+
+		trimslice_tlv320aic23_dai.cpu_dai_name = NULL;
+		trimslice_tlv320aic23_dai.cpu_dai_of_node = of_parse_phandle(
+				pdev->dev.of_node, "nvidia,i2s-controller", 0);
+		if (!trimslice_tlv320aic23_dai.cpu_dai_of_node) {
+			dev_err(&pdev->dev,
+				"Property 'nvidia,i2s-controller' missing or invalid\n");
+			ret = -EINVAL;
+			goto err;
+		}
+
+		trimslice_tlv320aic23_dai.platform_name = NULL;
+		trimslice_tlv320aic23_dai.platform_of_node =
+				trimslice_tlv320aic23_dai.cpu_dai_of_node;
+	}
+
 	ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
 	if (ret)
 		goto err;
@@ -187,10 +211,17 @@
 	return 0;
 }
 
+static const struct of_device_id trimslice_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra-audio-trimslice", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, trimslice_of_match);
+
 static struct platform_driver tegra_snd_trimslice_driver = {
 	.driver = {
 		.name = DRV_NAME,
 		.owner = THIS_MODULE,
+		.of_match_table = trimslice_of_match,
 	},
 	.probe = tegra_snd_trimslice_probe,
 	.remove = __devexit_p(tegra_snd_trimslice_remove),
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig
new file mode 100644
index 0000000..44cf434
--- /dev/null
+++ b/sound/soc/ux500/Kconfig
@@ -0,0 +1,14 @@
+#
+# Ux500 SoC audio configuration
+#
+menuconfig SND_SOC_UX500
+	tristate "SoC Audio support for Ux500 platform"
+	depends on SND_SOC
+	depends on MFD_DB8500_PRCMU
+	help
+		Say Y if you want to enable ASoC-support for
+		any of the Ux500 platforms (e.g. U8500).
+
+config SND_SOC_UX500_PLAT_MSP_I2S
+	tristate
+	depends on SND_SOC_UX500
diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile
new file mode 100644
index 0000000..19974c5
--- /dev/null
+++ b/sound/soc/ux500/Makefile
@@ -0,0 +1,4 @@
+# Ux500 Platform Support
+
+snd-soc-ux500-plat-msp-i2s-objs := ux500_msp_dai.o ux500_msp_i2s.o
+obj-$(CONFIG_SND_SOC_UX500_PLAT_MSP_I2S) += snd-soc-ux500-plat-msp-i2s.o
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
new file mode 100644
index 0000000..93c6c40
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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/slab.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/dbx500-prcmu.h>
+
+#include <mach/hardware.h>
+#include <mach/board-mop500-msp.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "ux500_msp_i2s.h"
+#include "ux500_msp_dai.h"
+
+static int setup_pcm_multichan(struct snd_soc_dai *dai,
+			struct ux500_msp_config *msp_config)
+{
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+	struct msp_multichannel_config *multi =
+					&msp_config->multichannel_config;
+
+	if (drvdata->slots > 1) {
+		msp_config->multichannel_configured = 1;
+
+		multi->tx_multichannel_enable = true;
+		multi->rx_multichannel_enable = true;
+		multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED;
+
+		multi->tx_channel_0_enable = drvdata->tx_mask;
+		multi->tx_channel_1_enable = 0;
+		multi->tx_channel_2_enable = 0;
+		multi->tx_channel_3_enable = 0;
+
+		multi->rx_channel_0_enable = drvdata->rx_mask;
+		multi->rx_channel_1_enable = 0;
+		multi->rx_channel_2_enable = 0;
+		multi->rx_channel_3_enable = 0;
+
+		dev_dbg(dai->dev,
+			"%s: Multichannel enabled. Slots: %d, TX: %u, RX: %u\n",
+			__func__, drvdata->slots, multi->tx_channel_0_enable,
+			multi->rx_channel_0_enable);
+	}
+
+	return 0;
+}
+
+static int setup_frameper(struct snd_soc_dai *dai, unsigned int rate,
+			struct msp_protdesc *prot_desc)
+{
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+	switch (drvdata->slots) {
+	case 1:
+		switch (rate) {
+		case 8000:
+			prot_desc->frame_period =
+				FRAME_PER_SINGLE_SLOT_8_KHZ;
+			break;
+
+		case 16000:
+			prot_desc->frame_period =
+				FRAME_PER_SINGLE_SLOT_16_KHZ;
+			break;
+
+		case 44100:
+			prot_desc->frame_period =
+				FRAME_PER_SINGLE_SLOT_44_1_KHZ;
+			break;
+
+		case 48000:
+			prot_desc->frame_period =
+				FRAME_PER_SINGLE_SLOT_48_KHZ;
+			break;
+
+		default:
+			dev_err(dai->dev,
+				"%s: Error: Unsupported sample-rate (freq = %d)!\n",
+				__func__, rate);
+			return -EINVAL;
+		}
+		break;
+
+	case 2:
+		prot_desc->frame_period = FRAME_PER_2_SLOTS;
+		break;
+
+	case 8:
+		prot_desc->frame_period = FRAME_PER_8_SLOTS;
+		break;
+
+	case 16:
+		prot_desc->frame_period = FRAME_PER_16_SLOTS;
+		break;
+	default:
+		dev_err(dai->dev,
+			"%s: Error: Unsupported slot-count (slots = %d)!\n",
+			__func__, drvdata->slots);
+		return -EINVAL;
+	}
+
+	prot_desc->clocks_per_frame =
+			prot_desc->frame_period+1;
+
+	dev_dbg(dai->dev, "%s: Clocks per frame: %u\n",
+		__func__,
+		prot_desc->clocks_per_frame);
+
+	return 0;
+}
+
+static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate,
+			struct msp_protdesc *prot_desc)
+{
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+	u32 frame_length = MSP_FRAME_LEN_1;
+	prot_desc->frame_width = 0;
+
+	switch (drvdata->slots) {
+	case 1:
+		frame_length = MSP_FRAME_LEN_1;
+		break;
+
+	case 2:
+		frame_length = MSP_FRAME_LEN_2;
+		break;
+
+	case 8:
+		frame_length = MSP_FRAME_LEN_8;
+		break;
+
+	case 16:
+		frame_length = MSP_FRAME_LEN_16;
+		break;
+	default:
+		dev_err(dai->dev,
+			"%s: Error: Unsupported slot-count (slots = %d)!\n",
+			__func__, drvdata->slots);
+		return -EINVAL;
+	}
+
+	prot_desc->tx_frame_len_1 = frame_length;
+	prot_desc->rx_frame_len_1 = frame_length;
+	prot_desc->tx_frame_len_2 = frame_length;
+	prot_desc->rx_frame_len_2 = frame_length;
+
+	prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;
+	prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;
+	prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
+	prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
+
+	return setup_frameper(dai, rate, prot_desc);
+}
+
+static int setup_clocking(struct snd_soc_dai *dai,
+			unsigned int fmt,
+			struct ux500_msp_config *msp_config)
+{
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+
+	case SND_SOC_DAIFMT_NB_IF:
+		msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT;
+		msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT;
+
+		break;
+
+	default:
+		dev_err(dai->dev,
+			"%s: Error: Unsopported inversion (fmt = 0x%x)!\n",
+			__func__, fmt);
+
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		dev_dbg(dai->dev, "%s: Codec is master.\n", __func__);
+
+		msp_config->iodelay = 0x20;
+		msp_config->rx_fsync_sel = 0;
+		msp_config->tx_fsync_sel = 1 << TFSSEL_SHIFT;
+		msp_config->tx_clk_sel = 0;
+		msp_config->rx_clk_sel = 0;
+		msp_config->srg_clk_sel = 0x2 << SCKSEL_SHIFT;
+
+		break;
+
+	case SND_SOC_DAIFMT_CBS_CFS:
+		dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__);
+
+		msp_config->tx_clk_sel = TX_CLK_SEL_SRG;
+		msp_config->tx_fsync_sel = TX_SYNC_SRG_PROG;
+		msp_config->rx_clk_sel = RX_CLK_SEL_SRG;
+		msp_config->rx_fsync_sel = RX_SYNC_SRG;
+		msp_config->srg_clk_sel = 1 << SCKSEL_SHIFT;
+
+		break;
+
+	default:
+		dev_err(dai->dev, "%s: Error: Unsopported master (fmt = 0x%x)!\n",
+			__func__, fmt);
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int setup_pcm_protdesc(struct snd_soc_dai *dai,
+				unsigned int fmt,
+				struct msp_protdesc *prot_desc)
+{
+	prot_desc->rx_phase_mode = MSP_SINGLE_PHASE;
+	prot_desc->tx_phase_mode = MSP_SINGLE_PHASE;
+	prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
+	prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
+	prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;
+	prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;
+	prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_HI);
+	prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_HI << RFSPOL_SHIFT;
+
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) {
+		dev_dbg(dai->dev, "%s: DSP_A.\n", __func__);
+		prot_desc->rx_clk_pol = MSP_RISING_EDGE;
+		prot_desc->tx_clk_pol = MSP_FALLING_EDGE;
+
+		prot_desc->rx_data_delay = MSP_DELAY_1;
+		prot_desc->tx_data_delay = MSP_DELAY_1;
+	} else {
+		dev_dbg(dai->dev, "%s: DSP_B.\n", __func__);
+		prot_desc->rx_clk_pol = MSP_FALLING_EDGE;
+		prot_desc->tx_clk_pol = MSP_RISING_EDGE;
+
+		prot_desc->rx_data_delay = MSP_DELAY_0;
+		prot_desc->tx_data_delay = MSP_DELAY_0;
+	}
+
+	prot_desc->rx_half_word_swap = MSP_SWAP_NONE;
+	prot_desc->tx_half_word_swap = MSP_SWAP_NONE;
+	prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
+	prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
+	prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;
+
+	return 0;
+}
+
+static int setup_i2s_protdesc(struct msp_protdesc *prot_desc)
+{
+	prot_desc->rx_phase_mode = MSP_DUAL_PHASE;
+	prot_desc->tx_phase_mode = MSP_DUAL_PHASE;
+	prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;
+	prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;
+	prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;
+	prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;
+	prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_LO);
+	prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_LO << RFSPOL_SHIFT;
+
+	prot_desc->rx_frame_len_1 = MSP_FRAME_LEN_1;
+	prot_desc->rx_frame_len_2 = MSP_FRAME_LEN_1;
+	prot_desc->tx_frame_len_1 = MSP_FRAME_LEN_1;
+	prot_desc->tx_frame_len_2 = MSP_FRAME_LEN_1;
+	prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;
+	prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
+	prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;
+	prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
+
+	prot_desc->rx_clk_pol = MSP_RISING_EDGE;
+	prot_desc->tx_clk_pol = MSP_FALLING_EDGE;
+
+	prot_desc->rx_data_delay = MSP_DELAY_0;
+	prot_desc->tx_data_delay = MSP_DELAY_0;
+
+	prot_desc->tx_half_word_swap = MSP_SWAP_NONE;
+	prot_desc->rx_half_word_swap = MSP_SWAP_NONE;
+	prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
+	prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
+	prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;
+
+	return 0;
+}
+
+static int setup_msp_config(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai,
+			struct ux500_msp_config *msp_config)
+{
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+	struct msp_protdesc *prot_desc = &msp_config->protdesc;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned int fmt = drvdata->fmt;
+	int ret;
+
+	memset(msp_config, 0, sizeof(*msp_config));
+
+	msp_config->f_inputclk = drvdata->master_clk;
+
+	msp_config->tx_fifo_config = TX_FIFO_ENABLE;
+	msp_config->rx_fifo_config = RX_FIFO_ENABLE;
+	msp_config->def_elem_len = 1;
+	msp_config->direction = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+				MSP_DIR_TX : MSP_DIR_RX;
+	msp_config->data_size = MSP_DATA_BITS_32;
+	msp_config->frame_freq = runtime->rate;
+
+	dev_dbg(dai->dev, "%s: f_inputclk = %u, frame_freq = %u.\n",
+	       __func__, msp_config->f_inputclk, msp_config->frame_freq);
+	/* To avoid division by zero */
+	prot_desc->clocks_per_frame = 1;
+
+	dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__,
+		runtime->rate, runtime->channels);
+	switch (fmt &
+		(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
+	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+		dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
+
+		msp_config->default_protdesc = 1;
+		msp_config->protocol = MSP_I2S_PROTOCOL;
+		break;
+
+	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+		dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
+
+		msp_config->data_size = MSP_DATA_BITS_16;
+		msp_config->protocol = MSP_I2S_PROTOCOL;
+
+		ret = setup_i2s_protdesc(prot_desc);
+		if (ret < 0)
+			return ret;
+
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+		dev_dbg(dai->dev, "%s: PCM format.\n", __func__);
+
+		msp_config->data_size = MSP_DATA_BITS_16;
+		msp_config->protocol = MSP_PCM_PROTOCOL;
+
+		ret = setup_pcm_protdesc(dai, fmt, prot_desc);
+		if (ret < 0)
+			return ret;
+
+		ret = setup_pcm_multichan(dai, msp_config);
+		if (ret < 0)
+			return ret;
+
+		ret = setup_pcm_framing(dai, runtime->rate, prot_desc);
+		if (ret < 0)
+			return ret;
+
+		break;
+
+	default:
+		dev_err(dai->dev, "%s: Error: Unsopported format (%d)!\n",
+			__func__, fmt);
+		return -EINVAL;
+	}
+
+	return setup_clocking(dai, fmt, msp_config);
+}
+
+static int ux500_msp_dai_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	int ret = 0;
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
+		snd_pcm_stream_str(substream));
+
+	/* Enable regulator */
+	ret = regulator_enable(drvdata->reg_vape);
+	if (ret != 0) {
+		dev_err(drvdata->msp->dev,
+			"%s: Failed to enable regulator!\n", __func__);
+		return ret;
+	}
+
+	/* Enable clock */
+	dev_dbg(dai->dev, "%s: Enabling MSP-clock.\n", __func__);
+	clk_enable(drvdata->clk);
+
+	return 0;
+}
+
+static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	int ret;
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+	bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
+		snd_pcm_stream_str(substream));
+
+	if (drvdata->vape_opp_constraint == 1) {
+		prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
+					"ux500_msp_i2s", 50);
+		drvdata->vape_opp_constraint = 0;
+	}
+
+	if (ux500_msp_i2s_close(drvdata->msp,
+				is_playback ? MSP_DIR_TX : MSP_DIR_RX)) {
+		dev_err(dai->dev,
+			"%s: Error: MSP %d (%s): Unable to close i2s.\n",
+			__func__, dai->id, snd_pcm_stream_str(substream));
+	}
+
+	/* Disable clock */
+	clk_disable(drvdata->clk);
+
+	/* Disable regulator */
+	ret = regulator_disable(drvdata->reg_vape);
+	if (ret < 0)
+		dev_err(dai->dev,
+			"%s: ERROR: Failed to disable regulator (%d)!\n",
+			__func__, ret);
+}
+
+static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	int ret = 0;
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ux500_msp_config msp_config;
+
+	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (rate = %d).\n", __func__,
+		dai->id, snd_pcm_stream_str(substream), runtime->rate);
+
+	setup_msp_config(substream, dai, &msp_config);
+
+	ret = ux500_msp_i2s_open(drvdata->msp, &msp_config);
+	if (ret < 0) {
+		dev_err(dai->dev, "%s: Error: msp_setup failed (ret = %d)!\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/* Set OPP-level */
+	if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) &&
+		(drvdata->msp->f_bitclk > 19200000)) {
+		/* If the bit-clock is higher than 19.2MHz, Vape should be
+		 * run in 100% OPP. Only when bit-clock is used (MSP master) */
+		prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
+					"ux500-msp-i2s", 100);
+		drvdata->vape_opp_constraint = 1;
+	} else {
+		prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
+					"ux500-msp-i2s", 50);
+		drvdata->vape_opp_constraint = 0;
+	}
+
+	return ret;
+}
+
+static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	unsigned int mask, slots_active;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n",
+			__func__, dai->id, snd_pcm_stream_str(substream));
+
+	switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		snd_pcm_hw_constraint_minmax(runtime,
+				SNDRV_PCM_HW_PARAM_CHANNELS,
+				1, 2);
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B:
+	case SND_SOC_DAIFMT_DSP_A:
+		mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+			drvdata->tx_mask :
+			drvdata->rx_mask;
+
+		slots_active = hweight32(mask);
+		dev_dbg(dai->dev, "TDM-slots active: %d", slots_active);
+
+		snd_pcm_hw_constraint_minmax(runtime,
+				SNDRV_PCM_HW_PARAM_CHANNELS,
+				slots_active, slots_active);
+		break;
+
+	default:
+		dev_err(dai->dev,
+			"%s: Error: Unsupported protocol (fmt = 0x%x)!\n",
+			__func__, drvdata->fmt);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai,
+				unsigned int fmt)
+{
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+	dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id);
+
+	switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+		SND_SOC_DAIFMT_MASTER_MASK)) {
+	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+		break;
+
+	default:
+		dev_err(dai->dev,
+			"%s: Error: Unsupported protocol/master (fmt = 0x%x)!\n",
+			__func__, drvdata->fmt);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+	case SND_SOC_DAIFMT_NB_IF:
+	case SND_SOC_DAIFMT_IB_IF:
+		break;
+
+	default:
+		dev_err(dai->dev,
+			"%s: Error: Unsupported inversion (fmt = 0x%x)!\n",
+			__func__, drvdata->fmt);
+		return -EINVAL;
+	}
+
+	drvdata->fmt = fmt;
+	return 0;
+}
+
+static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai,
+				unsigned int tx_mask,
+				unsigned int rx_mask,
+				int slots, int slot_width)
+{
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+	unsigned int cap;
+
+	switch (slots) {
+	case 1:
+		cap = 0x01;
+		break;
+	case 2:
+		cap = 0x03;
+		break;
+	case 8:
+		cap = 0xFF;
+		break;
+	case 16:
+		cap = 0xFFFF;
+		break;
+	default:
+		dev_err(dai->dev, "%s: Error: Unsupported slot-count (%d)!\n",
+			__func__, slots);
+		return -EINVAL;
+	}
+	drvdata->slots = slots;
+
+	if (!(slot_width == 16)) {
+		dev_err(dai->dev, "%s: Error: Unsupported slot-width (%d)!\n",
+			__func__, slot_width);
+		return -EINVAL;
+	}
+	drvdata->slot_width = slot_width;
+
+	drvdata->tx_mask = tx_mask & cap;
+	drvdata->rx_mask = rx_mask & cap;
+
+	return 0;
+}
+
+static int ux500_msp_dai_set_dai_sysclk(struct snd_soc_dai *dai,
+					int clk_id, unsigned int freq, int dir)
+{
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+	dev_dbg(dai->dev, "%s: MSP %d: Enter. clk-id: %d, freq: %u.\n",
+		__func__, dai->id, clk_id, freq);
+
+	switch (clk_id) {
+	case UX500_MSP_MASTER_CLOCK:
+		drvdata->master_clk = freq;
+		break;
+
+	default:
+		dev_err(dai->dev, "%s: MSP %d: Invalid clk-id (%d)!\n",
+			__func__, dai->id, clk_id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	int ret = 0;
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (msp->id = %d, cmd = %d).\n",
+		__func__, dai->id, snd_pcm_stream_str(substream),
+		(int)drvdata->msp->id, cmd);
+
+	ret = ux500_msp_i2s_trigger(drvdata->msp, cmd, substream->stream);
+
+	return ret;
+}
+
+static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
+{
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+	drvdata->playback_dma_data.dma_cfg = drvdata->msp->dma_cfg_tx;
+	drvdata->capture_dma_data.dma_cfg = drvdata->msp->dma_cfg_rx;
+
+	dai->playback_dma_data = &drvdata->playback_dma_data;
+	dai->capture_dma_data = &drvdata->capture_dma_data;
+
+	drvdata->playback_dma_data.data_size = drvdata->slot_width;
+	drvdata->capture_dma_data.data_size = drvdata->slot_width;
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
+	{
+		.set_sysclk = ux500_msp_dai_set_dai_sysclk,
+		.set_fmt = ux500_msp_dai_set_dai_fmt,
+		.set_tdm_slot = ux500_msp_dai_set_tdm_slot,
+		.startup = ux500_msp_dai_startup,
+		.shutdown = ux500_msp_dai_shutdown,
+		.prepare = ux500_msp_dai_prepare,
+		.trigger = ux500_msp_dai_trigger,
+		.hw_params = ux500_msp_dai_hw_params,
+	}
+};
+
+static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
+	{
+		.name = "ux500-msp-i2s.0",
+		.probe = ux500_msp_dai_probe,
+		.id = 0,
+		.suspend = NULL,
+		.resume = NULL,
+		.playback = {
+			.channels_min = UX500_MSP_MIN_CHANNELS,
+			.channels_max = UX500_MSP_MAX_CHANNELS,
+			.rates = UX500_I2S_RATES,
+			.formats = UX500_I2S_FORMATS,
+		},
+		.capture = {
+			.channels_min = UX500_MSP_MIN_CHANNELS,
+			.channels_max = UX500_MSP_MAX_CHANNELS,
+			.rates = UX500_I2S_RATES,
+			.formats = UX500_I2S_FORMATS,
+		},
+		.ops = ux500_msp_dai_ops,
+	},
+	{
+		.name = "ux500-msp-i2s.1",
+		.probe = ux500_msp_dai_probe,
+		.id = 1,
+		.suspend = NULL,
+		.resume = NULL,
+		.playback = {
+			.channels_min = UX500_MSP_MIN_CHANNELS,
+			.channels_max = UX500_MSP_MAX_CHANNELS,
+			.rates = UX500_I2S_RATES,
+			.formats = UX500_I2S_FORMATS,
+		},
+		.capture = {
+			.channels_min = UX500_MSP_MIN_CHANNELS,
+			.channels_max = UX500_MSP_MAX_CHANNELS,
+			.rates = UX500_I2S_RATES,
+			.formats = UX500_I2S_FORMATS,
+		},
+		.ops = ux500_msp_dai_ops,
+	},
+	{
+		.name = "ux500-msp-i2s.2",
+		.id = 2,
+		.probe = ux500_msp_dai_probe,
+		.suspend = NULL,
+		.resume = NULL,
+		.playback = {
+			.channels_min = UX500_MSP_MIN_CHANNELS,
+			.channels_max = UX500_MSP_MAX_CHANNELS,
+			.rates = UX500_I2S_RATES,
+			.formats = UX500_I2S_FORMATS,
+		},
+		.capture = {
+			.channels_min = UX500_MSP_MIN_CHANNELS,
+			.channels_max = UX500_MSP_MAX_CHANNELS,
+			.rates = UX500_I2S_RATES,
+			.formats = UX500_I2S_FORMATS,
+		},
+		.ops = ux500_msp_dai_ops,
+	},
+	{
+		.name = "ux500-msp-i2s.3",
+		.probe = ux500_msp_dai_probe,
+		.id = 3,
+		.suspend = NULL,
+		.resume = NULL,
+		.playback = {
+			.channels_min = UX500_MSP_MIN_CHANNELS,
+			.channels_max = UX500_MSP_MAX_CHANNELS,
+			.rates = UX500_I2S_RATES,
+			.formats = UX500_I2S_FORMATS,
+		},
+		.capture = {
+			.channels_min = UX500_MSP_MIN_CHANNELS,
+			.channels_max = UX500_MSP_MAX_CHANNELS,
+			.rates = UX500_I2S_RATES,
+			.formats = UX500_I2S_FORMATS,
+		},
+		.ops = ux500_msp_dai_ops,
+	},
+};
+
+static int __devinit ux500_msp_drv_probe(struct platform_device *pdev)
+{
+	struct ux500_msp_i2s_drvdata *drvdata;
+	int ret = 0;
+
+	dev_dbg(&pdev->dev, "%s: Enter (pdev->name = %s).\n", __func__,
+		pdev->name);
+
+	drvdata = devm_kzalloc(&pdev->dev,
+				sizeof(struct ux500_msp_i2s_drvdata),
+				GFP_KERNEL);
+	drvdata->fmt = 0;
+	drvdata->slots = 1;
+	drvdata->tx_mask = 0x01;
+	drvdata->rx_mask = 0x01;
+	drvdata->slot_width = 16;
+	drvdata->master_clk = MSP_INPUT_FREQ_APB;
+
+	drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape");
+	if (IS_ERR(drvdata->reg_vape)) {
+		ret = (int)PTR_ERR(drvdata->reg_vape);
+		dev_err(&pdev->dev,
+			"%s: ERROR: Failed to get Vape supply (%d)!\n",
+			__func__, ret);
+		return ret;
+	}
+	prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);
+
+	drvdata->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(drvdata->clk)) {
+		ret = (int)PTR_ERR(drvdata->clk);
+		dev_err(&pdev->dev, "%s: ERROR: clk_get failed (%d)!\n",
+			__func__, ret);
+		goto err_clk;
+	}
+
+	ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp,
+				pdev->dev.platform_data);
+	if (!drvdata->msp) {
+		dev_err(&pdev->dev,
+			"%s: ERROR: Failed to init MSP-struct (%d)!",
+			__func__, ret);
+		goto err_init_msp;
+	}
+	dev_set_drvdata(&pdev->dev, drvdata);
+
+	ret = snd_soc_register_dai(&pdev->dev,
+				&ux500_msp_dai_drv[drvdata->msp->id]);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
+			__func__, drvdata->msp->id);
+		goto err_init_msp;
+	}
+
+	return 0;
+
+err_init_msp:
+	clk_put(drvdata->clk);
+
+err_clk:
+	devm_regulator_put(drvdata->reg_vape);
+
+	return ret;
+}
+
+static int __devexit ux500_msp_drv_remove(struct platform_device *pdev)
+{
+	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
+
+	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+
+	devm_regulator_put(drvdata->reg_vape);
+	prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
+
+	clk_put(drvdata->clk);
+
+	ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp);
+
+	return 0;
+}
+
+static struct platform_driver msp_i2s_driver = {
+	.driver = {
+		.name = "ux500-msp-i2s",
+		.owner = THIS_MODULE,
+	},
+	.probe = ux500_msp_drv_probe,
+	.remove = ux500_msp_drv_remove,
+};
+module_platform_driver(msp_i2s_driver);
+
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h
new file mode 100644
index 0000000..98202a3
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_dai.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 UX500_msp_dai_H
+#define UX500_msp_dai_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+#include "ux500_msp_i2s.h"
+
+#define UX500_NBR_OF_DAI	4
+
+#define UX500_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |	\
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define UX500_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+#define FRAME_PER_SINGLE_SLOT_8_KHZ		31
+#define FRAME_PER_SINGLE_SLOT_16_KHZ	124
+#define FRAME_PER_SINGLE_SLOT_44_1_KHZ	63
+#define FRAME_PER_SINGLE_SLOT_48_KHZ	49
+#define FRAME_PER_2_SLOTS				31
+#define FRAME_PER_8_SLOTS				138
+#define FRAME_PER_16_SLOTS				277
+
+#ifndef CONFIG_SND_SOC_UX500_AB5500
+#define UX500_MSP_INTERNAL_CLOCK_FREQ  40000000
+#define UX500_MSP1_INTERNAL_CLOCK_FREQ UX500_MSP_INTERNAL_CLOCK_FREQ
+#else
+#define UX500_MSP_INTERNAL_CLOCK_FREQ 13000000
+#define UX500_MSP1_INTERNAL_CLOCK_FREQ (UX500_MSP_INTERNAL_CLOCK_FREQ * 2)
+#endif
+
+#define UX500_MSP_MIN_CHANNELS		1
+#define UX500_MSP_MAX_CHANNELS		8
+
+#define PLAYBACK_CONFIGURED		1
+#define CAPTURE_CONFIGURED		2
+
+enum ux500_msp_clock_id {
+	UX500_MSP_MASTER_CLOCK,
+};
+
+struct ux500_msp_i2s_drvdata {
+	struct ux500_msp *msp;
+	struct regulator *reg_vape;
+	struct ux500_msp_dma_params playback_dma_data;
+	struct ux500_msp_dma_params capture_dma_data;
+	unsigned int fmt;
+	unsigned int tx_mask;
+	unsigned int rx_mask;
+	int slots;
+	int slot_width;
+	u8 configured;
+	int data_delay;
+
+	/* Clocks */
+	unsigned int master_clk;
+	struct clk *clk;
+
+	/* Regulators */
+	int vape_opp_constraint;
+};
+
+int ux500_msp_dai_set_data_delay(struct snd_soc_dai *dai, int delay);
+
+#endif
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
new file mode 100644
index 0000000..496dec1
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
+ *         Sandeep Kaushik <sandeep.kaushik@st.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/board-mop500-msp.h>
+
+#include <sound/soc.h>
+
+#include "ux500_msp_i2s.h"
+
+ /* Protocol desciptors */
+static const struct msp_protdesc prot_descs[] = {
+	{ /* I2S */
+		MSP_SINGLE_PHASE,
+		MSP_SINGLE_PHASE,
+		MSP_PHASE2_START_MODE_IMEDIATE,
+		MSP_PHASE2_START_MODE_IMEDIATE,
+		MSP_BTF_MS_BIT_FIRST,
+		MSP_BTF_MS_BIT_FIRST,
+		MSP_FRAME_LEN_1,
+		MSP_FRAME_LEN_1,
+		MSP_FRAME_LEN_1,
+		MSP_FRAME_LEN_1,
+		MSP_ELEM_LEN_32,
+		MSP_ELEM_LEN_32,
+		MSP_ELEM_LEN_32,
+		MSP_ELEM_LEN_32,
+		MSP_DELAY_1,
+		MSP_DELAY_1,
+		MSP_RISING_EDGE,
+		MSP_FALLING_EDGE,
+		MSP_FSYNC_POL_ACT_LO,
+		MSP_FSYNC_POL_ACT_LO,
+		MSP_SWAP_NONE,
+		MSP_SWAP_NONE,
+		MSP_COMPRESS_MODE_LINEAR,
+		MSP_EXPAND_MODE_LINEAR,
+		MSP_FSYNC_IGNORE,
+		31,
+		15,
+		32,
+	}, { /* PCM */
+		MSP_DUAL_PHASE,
+		MSP_DUAL_PHASE,
+		MSP_PHASE2_START_MODE_FSYNC,
+		MSP_PHASE2_START_MODE_FSYNC,
+		MSP_BTF_MS_BIT_FIRST,
+		MSP_BTF_MS_BIT_FIRST,
+		MSP_FRAME_LEN_1,
+		MSP_FRAME_LEN_1,
+		MSP_FRAME_LEN_1,
+		MSP_FRAME_LEN_1,
+		MSP_ELEM_LEN_16,
+		MSP_ELEM_LEN_16,
+		MSP_ELEM_LEN_16,
+		MSP_ELEM_LEN_16,
+		MSP_DELAY_0,
+		MSP_DELAY_0,
+		MSP_RISING_EDGE,
+		MSP_FALLING_EDGE,
+		MSP_FSYNC_POL_ACT_HI,
+		MSP_FSYNC_POL_ACT_HI,
+		MSP_SWAP_NONE,
+		MSP_SWAP_NONE,
+		MSP_COMPRESS_MODE_LINEAR,
+		MSP_EXPAND_MODE_LINEAR,
+		MSP_FSYNC_IGNORE,
+		255,
+		0,
+		256,
+	}, { /* Companded PCM */
+		MSP_SINGLE_PHASE,
+		MSP_SINGLE_PHASE,
+		MSP_PHASE2_START_MODE_FSYNC,
+		MSP_PHASE2_START_MODE_FSYNC,
+		MSP_BTF_MS_BIT_FIRST,
+		MSP_BTF_MS_BIT_FIRST,
+		MSP_FRAME_LEN_1,
+		MSP_FRAME_LEN_1,
+		MSP_FRAME_LEN_1,
+		MSP_FRAME_LEN_1,
+		MSP_ELEM_LEN_8,
+		MSP_ELEM_LEN_8,
+		MSP_ELEM_LEN_8,
+		MSP_ELEM_LEN_8,
+		MSP_DELAY_0,
+		MSP_DELAY_0,
+		MSP_RISING_EDGE,
+		MSP_RISING_EDGE,
+		MSP_FSYNC_POL_ACT_HI,
+		MSP_FSYNC_POL_ACT_HI,
+		MSP_SWAP_NONE,
+		MSP_SWAP_NONE,
+		MSP_COMPRESS_MODE_LINEAR,
+		MSP_EXPAND_MODE_LINEAR,
+		MSP_FSYNC_IGNORE,
+		255,
+		0,
+		256,
+	},
+};
+
+static void set_prot_desc_tx(struct ux500_msp *msp,
+			struct msp_protdesc *protdesc,
+			enum msp_data_size data_size)
+{
+	u32 temp_reg = 0;
+
+	temp_reg |= MSP_P2_ENABLE_BIT(protdesc->tx_phase_mode);
+	temp_reg |= MSP_P2_START_MODE_BIT(protdesc->tx_phase2_start_mode);
+	temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->tx_frame_len_1);
+	temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->tx_frame_len_2);
+	if (msp->def_elem_len) {
+		temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->tx_elem_len_1);
+		temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->tx_elem_len_2);
+	} else {
+		temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+		temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+	}
+	temp_reg |= MSP_DATA_DELAY_BITS(protdesc->tx_data_delay);
+	temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->tx_byte_order);
+	temp_reg |= MSP_FSYNC_POL(protdesc->tx_fsync_pol);
+	temp_reg |= MSP_DATA_WORD_SWAP(protdesc->tx_half_word_swap);
+	temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->compression_mode);
+	temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);
+
+	writel(temp_reg, msp->registers + MSP_TCF);
+}
+
+static void set_prot_desc_rx(struct ux500_msp *msp,
+			struct msp_protdesc *protdesc,
+			enum msp_data_size data_size)
+{
+	u32 temp_reg = 0;
+
+	temp_reg |= MSP_P2_ENABLE_BIT(protdesc->rx_phase_mode);
+	temp_reg |= MSP_P2_START_MODE_BIT(protdesc->rx_phase2_start_mode);
+	temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->rx_frame_len_1);
+	temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->rx_frame_len_2);
+	if (msp->def_elem_len) {
+		temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->rx_elem_len_1);
+		temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->rx_elem_len_2);
+	} else {
+		temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+		temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+	}
+
+	temp_reg |= MSP_DATA_DELAY_BITS(protdesc->rx_data_delay);
+	temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->rx_byte_order);
+	temp_reg |= MSP_FSYNC_POL(protdesc->rx_fsync_pol);
+	temp_reg |= MSP_DATA_WORD_SWAP(protdesc->rx_half_word_swap);
+	temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->expansion_mode);
+	temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);
+
+	writel(temp_reg, msp->registers + MSP_RCF);
+}
+
+static int configure_protocol(struct ux500_msp *msp,
+			struct ux500_msp_config *config)
+{
+	struct msp_protdesc *protdesc;
+	enum msp_data_size data_size;
+	u32 temp_reg = 0;
+
+	data_size = config->data_size;
+	msp->def_elem_len = config->def_elem_len;
+	if (config->default_protdesc == 1) {
+		if (config->protocol >= MSP_INVALID_PROTOCOL) {
+			dev_err(msp->dev, "%s: ERROR: Invalid protocol!\n",
+				__func__);
+			return -EINVAL;
+		}
+		protdesc =
+		    (struct msp_protdesc *)&prot_descs[config->protocol];
+	} else {
+		protdesc = (struct msp_protdesc *)&config->protdesc;
+	}
+
+	if (data_size < MSP_DATA_BITS_DEFAULT || data_size > MSP_DATA_BITS_32) {
+		dev_err(msp->dev,
+			"%s: ERROR: Invalid data-size requested (data_size = %d)!\n",
+			__func__, data_size);
+		return -EINVAL;
+	}
+
+	if (config->direction & MSP_DIR_TX)
+		set_prot_desc_tx(msp, protdesc, data_size);
+	if (config->direction & MSP_DIR_RX)
+		set_prot_desc_rx(msp, protdesc, data_size);
+
+	/* The code below should not be separated. */
+	temp_reg = readl(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;
+	temp_reg |= MSP_TX_CLKPOL_BIT(~protdesc->tx_clk_pol);
+	writel(temp_reg, msp->registers + MSP_GCR);
+	temp_reg = readl(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;
+	temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol);
+	writel(temp_reg, msp->registers + MSP_GCR);
+
+	return 0;
+}
+
+static int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config)
+{
+	u32 reg_val_GCR;
+	u32 frame_per = 0;
+	u32 sck_div = 0;
+	u32 frame_width = 0;
+	u32 temp_reg = 0;
+	struct msp_protdesc *protdesc = NULL;
+
+	reg_val_GCR = readl(msp->registers + MSP_GCR);
+	writel(reg_val_GCR & ~SRG_ENABLE, msp->registers + MSP_GCR);
+
+	if (config->default_protdesc)
+		protdesc =
+			(struct msp_protdesc *)&prot_descs[config->protocol];
+	else
+		protdesc = (struct msp_protdesc *)&config->protdesc;
+
+	switch (config->protocol) {
+	case MSP_PCM_PROTOCOL:
+	case MSP_PCM_COMPAND_PROTOCOL:
+		frame_width = protdesc->frame_width;
+		sck_div = config->f_inputclk / (config->frame_freq *
+			(protdesc->clocks_per_frame));
+		frame_per = protdesc->frame_period;
+		break;
+	case MSP_I2S_PROTOCOL:
+		frame_width = protdesc->frame_width;
+		sck_div = config->f_inputclk / (config->frame_freq *
+			(protdesc->clocks_per_frame));
+		frame_per = protdesc->frame_period;
+		break;
+	default:
+		dev_err(msp->dev, "%s: ERROR: Unknown protocol (%d)!\n",
+			__func__,
+			config->protocol);
+		return -EINVAL;
+	}
+
+	temp_reg = (sck_div - 1) & SCK_DIV_MASK;
+	temp_reg |= FRAME_WIDTH_BITS(frame_width);
+	temp_reg |= FRAME_PERIOD_BITS(frame_per);
+	writel(temp_reg, msp->registers + MSP_SRG);
+
+	msp->f_bitclk = (config->f_inputclk)/(sck_div + 1);
+
+	/* Enable bit-clock */
+	udelay(100);
+	reg_val_GCR = readl(msp->registers + MSP_GCR);
+	writel(reg_val_GCR | SRG_ENABLE, msp->registers + MSP_GCR);
+	udelay(100);
+
+	return 0;
+}
+
+static int configure_multichannel(struct ux500_msp *msp,
+				struct ux500_msp_config *config)
+{
+	struct msp_protdesc *protdesc;
+	struct msp_multichannel_config *mcfg;
+	u32 reg_val_MCR;
+
+	if (config->default_protdesc == 1) {
+		if (config->protocol >= MSP_INVALID_PROTOCOL) {
+			dev_err(msp->dev,
+				"%s: ERROR: Invalid protocol (%d)!\n",
+				__func__, config->protocol);
+			return -EINVAL;
+		}
+		protdesc = (struct msp_protdesc *)
+				&prot_descs[config->protocol];
+	} else {
+		protdesc = (struct msp_protdesc *)&config->protdesc;
+	}
+
+	mcfg = &config->multichannel_config;
+	if (mcfg->tx_multichannel_enable) {
+		if (protdesc->tx_phase_mode == MSP_SINGLE_PHASE) {
+			reg_val_MCR = readl(msp->registers + MSP_MCR);
+			writel(reg_val_MCR | (mcfg->tx_multichannel_enable ?
+						1 << TMCEN_BIT : 0),
+				msp->registers + MSP_MCR);
+			writel(mcfg->tx_channel_0_enable,
+				msp->registers + MSP_TCE0);
+			writel(mcfg->tx_channel_1_enable,
+				msp->registers + MSP_TCE1);
+			writel(mcfg->tx_channel_2_enable,
+				msp->registers + MSP_TCE2);
+			writel(mcfg->tx_channel_3_enable,
+				msp->registers + MSP_TCE3);
+		} else {
+			dev_err(msp->dev,
+				"%s: ERROR: Only single-phase supported (TX-mode: %d)!\n",
+				__func__, protdesc->tx_phase_mode);
+			return -EINVAL;
+		}
+	}
+	if (mcfg->rx_multichannel_enable) {
+		if (protdesc->rx_phase_mode == MSP_SINGLE_PHASE) {
+			reg_val_MCR = readl(msp->registers + MSP_MCR);
+			writel(reg_val_MCR | (mcfg->rx_multichannel_enable ?
+						1 << RMCEN_BIT : 0),
+				msp->registers + MSP_MCR);
+			writel(mcfg->rx_channel_0_enable,
+					msp->registers + MSP_RCE0);
+			writel(mcfg->rx_channel_1_enable,
+					msp->registers + MSP_RCE1);
+			writel(mcfg->rx_channel_2_enable,
+					msp->registers + MSP_RCE2);
+			writel(mcfg->rx_channel_3_enable,
+					msp->registers + MSP_RCE3);
+		} else {
+			dev_err(msp->dev,
+				"%s: ERROR: Only single-phase supported (RX-mode: %d)!\n",
+				__func__, protdesc->rx_phase_mode);
+			return -EINVAL;
+		}
+		if (mcfg->rx_comparison_enable_mode) {
+			reg_val_MCR = readl(msp->registers + MSP_MCR);
+			writel(reg_val_MCR |
+				(mcfg->rx_comparison_enable_mode << RCMPM_BIT),
+				msp->registers + MSP_MCR);
+
+			writel(mcfg->comparison_mask,
+					msp->registers + MSP_RCM);
+			writel(mcfg->comparison_value,
+					msp->registers + MSP_RCV);
+
+		}
+	}
+
+	return 0;
+}
+
+static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
+{
+	int status = 0;
+	u32 reg_val_DMACR, reg_val_GCR;
+
+	/* Check msp state whether in RUN or CONFIGURED Mode */
+	if ((msp->msp_state == MSP_STATE_IDLE) && (msp->plat_init)) {
+		status = msp->plat_init();
+		if (status) {
+			dev_err(msp->dev, "%s: ERROR: Failed to init MSP (%d)!\n",
+				__func__, status);
+			return status;
+		}
+	}
+
+	/* Configure msp with protocol dependent settings */
+	configure_protocol(msp, config);
+	setup_bitclk(msp, config);
+	if (config->multichannel_configured == 1) {
+		status = configure_multichannel(msp, config);
+		if (status)
+			dev_warn(msp->dev,
+				"%s: WARN: configure_multichannel failed (%d)!\n",
+				__func__, status);
+	}
+
+	/* Make sure the correct DMA-directions are configured */
+	if ((config->direction & MSP_DIR_RX) && (!msp->dma_cfg_rx)) {
+		dev_err(msp->dev, "%s: ERROR: MSP RX-mode is not configured!",
+			__func__);
+		return -EINVAL;
+	}
+	if ((config->direction == MSP_DIR_TX) && (!msp->dma_cfg_tx)) {
+		dev_err(msp->dev, "%s: ERROR: MSP TX-mode is not configured!",
+			__func__);
+		return -EINVAL;
+	}
+
+	reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+	if (config->direction & MSP_DIR_RX)
+		reg_val_DMACR |= RX_DMA_ENABLE;
+	if (config->direction & MSP_DIR_TX)
+		reg_val_DMACR |= TX_DMA_ENABLE;
+	writel(reg_val_DMACR, msp->registers + MSP_DMACR);
+
+	writel(config->iodelay, msp->registers + MSP_IODLY);
+
+	/* Enable frame generation logic */
+	reg_val_GCR = readl(msp->registers + MSP_GCR);
+	writel(reg_val_GCR | FRAME_GEN_ENABLE, msp->registers + MSP_GCR);
+
+	return status;
+}
+
+static void flush_fifo_rx(struct ux500_msp *msp)
+{
+	u32 reg_val_DR, reg_val_GCR, reg_val_FLR;
+	u32 limit = 32;
+
+	reg_val_GCR = readl(msp->registers + MSP_GCR);
+	writel(reg_val_GCR | RX_ENABLE, msp->registers + MSP_GCR);
+
+	reg_val_FLR = readl(msp->registers + MSP_FLR);
+	while (!(reg_val_FLR & RX_FIFO_EMPTY) && limit--) {
+		reg_val_DR = readl(msp->registers + MSP_DR);
+		reg_val_FLR = readl(msp->registers + MSP_FLR);
+	}
+
+	writel(reg_val_GCR, msp->registers + MSP_GCR);
+}
+
+static void flush_fifo_tx(struct ux500_msp *msp)
+{
+	u32 reg_val_TSTDR, reg_val_GCR, reg_val_FLR;
+	u32 limit = 32;
+
+	reg_val_GCR = readl(msp->registers + MSP_GCR);
+	writel(reg_val_GCR | TX_ENABLE, msp->registers + MSP_GCR);
+	writel(MSP_ITCR_ITEN | MSP_ITCR_TESTFIFO, msp->registers + MSP_ITCR);
+
+	reg_val_FLR = readl(msp->registers + MSP_FLR);
+	while (!(reg_val_FLR & TX_FIFO_EMPTY) && limit--) {
+		reg_val_TSTDR = readl(msp->registers + MSP_TSTDR);
+		reg_val_FLR = readl(msp->registers + MSP_FLR);
+	}
+	writel(0x0, msp->registers + MSP_ITCR);
+	writel(reg_val_GCR, msp->registers + MSP_GCR);
+}
+
+int ux500_msp_i2s_open(struct ux500_msp *msp,
+		struct ux500_msp_config *config)
+{
+	u32 old_reg, new_reg, mask;
+	int res;
+	unsigned int tx_sel, rx_sel, tx_busy, rx_busy;
+
+	if (in_interrupt()) {
+		dev_err(msp->dev,
+			"%s: ERROR: Open called in interrupt context!\n",
+			__func__);
+		return -1;
+	}
+
+	tx_sel = (config->direction & MSP_DIR_TX) > 0;
+	rx_sel = (config->direction & MSP_DIR_RX) > 0;
+	if (!tx_sel && !rx_sel) {
+		dev_err(msp->dev, "%s: Error: No direction selected!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	tx_busy = (msp->dir_busy & MSP_DIR_TX) > 0;
+	rx_busy = (msp->dir_busy & MSP_DIR_RX) > 0;
+	if (tx_busy && tx_sel) {
+		dev_err(msp->dev, "%s: Error: TX is in use!\n", __func__);
+		return -EBUSY;
+	}
+	if (rx_busy && rx_sel) {
+		dev_err(msp->dev, "%s: Error: RX is in use!\n", __func__);
+		return -EBUSY;
+	}
+
+	msp->dir_busy |= (tx_sel ? MSP_DIR_TX : 0) | (rx_sel ? MSP_DIR_RX : 0);
+
+	/* First do the global config register */
+	mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK |
+	    TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
+	    RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |
+	    LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
+
+	new_reg = (config->tx_clk_sel | config->rx_clk_sel |
+		config->rx_fsync_pol | config->tx_fsync_pol |
+		config->rx_fsync_sel | config->tx_fsync_sel |
+		config->rx_fifo_config | config->tx_fifo_config |
+		config->srg_clk_sel | config->loopback_enable |
+		config->tx_data_enable);
+
+	old_reg = readl(msp->registers + MSP_GCR);
+	old_reg &= ~mask;
+	new_reg |= old_reg;
+	writel(new_reg, msp->registers + MSP_GCR);
+
+	res = enable_msp(msp, config);
+	if (res < 0) {
+		dev_err(msp->dev, "%s: ERROR: enable_msp failed (%d)!\n",
+			__func__, res);
+		return -EBUSY;
+	}
+	if (config->loopback_enable & 0x80)
+		msp->loopback_enable = 1;
+
+	/* Flush FIFOs */
+	flush_fifo_tx(msp);
+	flush_fifo_rx(msp);
+
+	msp->msp_state = MSP_STATE_CONFIGURED;
+	return 0;
+}
+
+static void disable_msp_rx(struct ux500_msp *msp)
+{
+	u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
+
+	reg_val_GCR = readl(msp->registers + MSP_GCR);
+	writel(reg_val_GCR & ~RX_ENABLE, msp->registers + MSP_GCR);
+	reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+	writel(reg_val_DMACR & ~RX_DMA_ENABLE, msp->registers + MSP_DMACR);
+	reg_val_IMSC = readl(msp->registers + MSP_IMSC);
+	writel(reg_val_IMSC &
+			~(RX_SERVICE_INT | RX_OVERRUN_ERROR_INT),
+			msp->registers + MSP_IMSC);
+
+	msp->dir_busy &= ~MSP_DIR_RX;
+}
+
+static void disable_msp_tx(struct ux500_msp *msp)
+{
+	u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
+
+	reg_val_GCR = readl(msp->registers + MSP_GCR);
+	writel(reg_val_GCR & ~TX_ENABLE, msp->registers + MSP_GCR);
+	reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+	writel(reg_val_DMACR & ~TX_DMA_ENABLE, msp->registers + MSP_DMACR);
+	reg_val_IMSC = readl(msp->registers + MSP_IMSC);
+	writel(reg_val_IMSC &
+			~(TX_SERVICE_INT | TX_UNDERRUN_ERR_INT),
+			msp->registers + MSP_IMSC);
+
+	msp->dir_busy &= ~MSP_DIR_TX;
+}
+
+static int disable_msp(struct ux500_msp *msp, unsigned int dir)
+{
+	u32 reg_val_GCR;
+	int status = 0;
+	unsigned int disable_tx, disable_rx;
+
+	reg_val_GCR = readl(msp->registers + MSP_GCR);
+	disable_tx = dir & MSP_DIR_TX;
+	disable_rx = dir & MSP_DIR_TX;
+	if (disable_tx && disable_rx) {
+		reg_val_GCR = readl(msp->registers + MSP_GCR);
+		writel(reg_val_GCR | LOOPBACK_MASK,
+				msp->registers + MSP_GCR);
+
+		/* Flush TX-FIFO */
+		flush_fifo_tx(msp);
+
+		/* Disable TX-channel */
+		writel((readl(msp->registers + MSP_GCR) &
+			       (~TX_ENABLE)), msp->registers + MSP_GCR);
+
+		/* Flush RX-FIFO */
+		flush_fifo_rx(msp);
+
+		/* Disable Loopback and Receive channel */
+		writel((readl(msp->registers + MSP_GCR) &
+				(~(RX_ENABLE | LOOPBACK_MASK))),
+				msp->registers + MSP_GCR);
+
+		disable_msp_tx(msp);
+		disable_msp_rx(msp);
+	} else if (disable_tx)
+		disable_msp_tx(msp);
+	else if (disable_rx)
+		disable_msp_rx(msp);
+
+	return status;
+}
+
+int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
+{
+	u32 reg_val_GCR, enable_bit;
+
+	if (msp->msp_state == MSP_STATE_IDLE) {
+		dev_err(msp->dev, "%s: ERROR: MSP is not configured!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+			enable_bit = TX_ENABLE;
+		else
+			enable_bit = RX_ENABLE;
+		reg_val_GCR = readl(msp->registers + MSP_GCR);
+		writel(reg_val_GCR | enable_bit, msp->registers + MSP_GCR);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+			disable_msp_tx(msp);
+		else
+			disable_msp_rx(msp);
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
+{
+	int status = 0;
+
+	dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
+
+	status = disable_msp(msp, dir);
+	if (msp->dir_busy == 0) {
+		/* disable sample rate and frame generators */
+		msp->msp_state = MSP_STATE_IDLE;
+		writel((readl(msp->registers + MSP_GCR) &
+			       (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
+			      msp->registers + MSP_GCR);
+		if (msp->plat_exit)
+			status = msp->plat_exit();
+			if (status)
+				dev_warn(msp->dev,
+					"%s: WARN: ux500_msp_i2s_exit failed (%d)!\n",
+					__func__, status);
+		writel(0, msp->registers + MSP_GCR);
+		writel(0, msp->registers + MSP_TCF);
+		writel(0, msp->registers + MSP_RCF);
+		writel(0, msp->registers + MSP_DMACR);
+		writel(0, msp->registers + MSP_SRG);
+		writel(0, msp->registers + MSP_MCR);
+		writel(0, msp->registers + MSP_RCM);
+		writel(0, msp->registers + MSP_RCV);
+		writel(0, msp->registers + MSP_TCE0);
+		writel(0, msp->registers + MSP_TCE1);
+		writel(0, msp->registers + MSP_TCE2);
+		writel(0, msp->registers + MSP_TCE3);
+		writel(0, msp->registers + MSP_RCE0);
+		writel(0, msp->registers + MSP_RCE1);
+		writel(0, msp->registers + MSP_RCE2);
+		writel(0, msp->registers + MSP_RCE3);
+	}
+
+	return status;
+
+}
+
+int ux500_msp_i2s_init_msp(struct platform_device *pdev,
+			struct ux500_msp **msp_p,
+			struct msp_i2s_platform_data *platform_data)
+{
+	int ret = 0;
+	struct resource *res = NULL;
+	struct i2s_controller *i2s_cont;
+	struct ux500_msp *msp;
+
+	dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
+		pdev->name, platform_data->id);
+
+	*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
+	msp = *msp_p;
+
+	msp->id = platform_data->id;
+	msp->dev = &pdev->dev;
+	msp->plat_init = platform_data->msp_i2s_init;
+	msp->plat_exit = platform_data->msp_i2s_exit;
+	msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
+	msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "%s: ERROR: Unable to get resource!\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_res;
+	}
+
+	msp->registers = ioremap(res->start, (res->end - res->start + 1));
+	if (msp->registers == NULL) {
+		dev_err(&pdev->dev, "%s: ERROR: ioremap failed!\n", __func__);
+		ret = -ENOMEM;
+		goto err_res;
+	}
+
+	msp->msp_state = MSP_STATE_IDLE;
+	msp->loopback_enable = 0;
+
+	/* I2S-controller is allocated and added in I2S controller class. */
+	i2s_cont = devm_kzalloc(&pdev->dev, sizeof(*i2s_cont), GFP_KERNEL);
+	if (!i2s_cont) {
+		dev_err(&pdev->dev,
+			"%s: ERROR: Failed to allocate I2S-controller!\n",
+			__func__);
+		goto err_i2s_cont;
+	}
+	i2s_cont->dev.parent = &pdev->dev;
+	i2s_cont->data = (void *)msp;
+	i2s_cont->id = (s16)msp->id;
+	snprintf(i2s_cont->name, sizeof(i2s_cont->name), "ux500-msp-i2s.%04x",
+		msp->id);
+	dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
+	msp->i2s_cont = i2s_cont;
+
+	return 0;
+
+err_i2s_cont:
+	iounmap(msp->registers);
+
+err_res:
+	devm_kfree(&pdev->dev, msp);
+
+	return ret;
+}
+
+void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
+			struct ux500_msp *msp)
+{
+	dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id);
+
+	device_unregister(&msp->i2s_cont->dev);
+	devm_kfree(&pdev->dev, msp->i2s_cont);
+
+	iounmap(msp->registers);
+
+	devm_kfree(&pdev->dev, msp);
+}
+
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h
new file mode 100644
index 0000000..7f71b4a
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_i2s.h
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 UX500_MSP_I2S_H
+#define UX500_MSP_I2S_H
+
+#include <linux/platform_device.h>
+
+#include <mach/board-mop500-msp.h>
+
+#define MSP_INPUT_FREQ_APB 48000000
+
+/*** Stereo mode. Used for APB data accesses as 16 bits accesses (mono),
+ *   32 bits accesses (stereo).
+ ***/
+enum msp_stereo_mode {
+	MSP_MONO,
+	MSP_STEREO
+};
+
+/* Direction (Transmit/Receive mode) */
+enum msp_direction {
+	MSP_TX = 1,
+	MSP_RX = 2
+};
+
+/* Transmit and receive configuration register */
+#define MSP_BIG_ENDIAN           0x00000000
+#define MSP_LITTLE_ENDIAN        0x00001000
+#define MSP_UNEXPECTED_FS_ABORT  0x00000000
+#define MSP_UNEXPECTED_FS_IGNORE 0x00008000
+#define MSP_NON_MODE_BIT_MASK    0x00009000
+
+/* Global configuration register */
+#define RX_ENABLE             0x00000001
+#define RX_FIFO_ENABLE        0x00000002
+#define RX_SYNC_SRG           0x00000010
+#define RX_CLK_POL_RISING     0x00000020
+#define RX_CLK_SEL_SRG        0x00000040
+#define TX_ENABLE             0x00000100
+#define TX_FIFO_ENABLE        0x00000200
+#define TX_SYNC_SRG_PROG      0x00001800
+#define TX_SYNC_SRG_AUTO      0x00001000
+#define TX_CLK_POL_RISING     0x00002000
+#define TX_CLK_SEL_SRG        0x00004000
+#define TX_EXTRA_DELAY_ENABLE 0x00008000
+#define SRG_ENABLE            0x00010000
+#define FRAME_GEN_ENABLE      0x00100000
+#define SRG_CLK_SEL_APB       0x00000000
+#define RX_FIFO_SYNC_HI       0x00000000
+#define TX_FIFO_SYNC_HI       0x00000000
+#define SPI_CLK_MODE_NORMAL   0x00000000
+
+#define MSP_FRAME_SIZE_AUTO -1
+
+#define MSP_DR		0x00
+#define MSP_GCR		0x04
+#define MSP_TCF		0x08
+#define MSP_RCF		0x0c
+#define MSP_SRG		0x10
+#define MSP_FLR		0x14
+#define MSP_DMACR	0x18
+
+#define MSP_IMSC	0x20
+#define MSP_RIS		0x24
+#define MSP_MIS		0x28
+#define MSP_ICR		0x2c
+#define MSP_MCR		0x30
+#define MSP_RCV		0x34
+#define MSP_RCM		0x38
+
+#define MSP_TCE0	0x40
+#define MSP_TCE1	0x44
+#define MSP_TCE2	0x48
+#define MSP_TCE3	0x4c
+
+#define MSP_RCE0	0x60
+#define MSP_RCE1	0x64
+#define MSP_RCE2	0x68
+#define MSP_RCE3	0x6c
+#define MSP_IODLY	0x70
+
+#define MSP_ITCR	0x80
+#define MSP_ITIP	0x84
+#define MSP_ITOP	0x88
+#define MSP_TSTDR	0x8c
+
+#define MSP_PID0	0xfe0
+#define MSP_PID1	0xfe4
+#define MSP_PID2	0xfe8
+#define MSP_PID3	0xfec
+
+#define MSP_CID0	0xff0
+#define MSP_CID1	0xff4
+#define MSP_CID2	0xff8
+#define MSP_CID3	0xffc
+
+/* Protocol dependant parameters list */
+#define RX_ENABLE_MASK		BIT(0)
+#define RX_FIFO_ENABLE_MASK	BIT(1)
+#define RX_FSYNC_MASK		BIT(2)
+#define DIRECT_COMPANDING_MASK	BIT(3)
+#define RX_SYNC_SEL_MASK	BIT(4)
+#define RX_CLK_POL_MASK		BIT(5)
+#define RX_CLK_SEL_MASK		BIT(6)
+#define LOOPBACK_MASK		BIT(7)
+#define TX_ENABLE_MASK		BIT(8)
+#define TX_FIFO_ENABLE_MASK	BIT(9)
+#define TX_FSYNC_MASK		BIT(10)
+#define TX_MSP_TDR_TSR		BIT(11)
+#define TX_SYNC_SEL_MASK	(BIT(12) | BIT(11))
+#define TX_CLK_POL_MASK		BIT(13)
+#define TX_CLK_SEL_MASK		BIT(14)
+#define TX_EXTRA_DELAY_MASK	BIT(15)
+#define SRG_ENABLE_MASK		BIT(16)
+#define SRG_CLK_POL_MASK	BIT(17)
+#define SRG_CLK_SEL_MASK	(BIT(19) | BIT(18))
+#define FRAME_GEN_EN_MASK	BIT(20)
+#define SPI_CLK_MODE_MASK	(BIT(22) | BIT(21))
+#define SPI_BURST_MODE_MASK	BIT(23)
+
+#define RXEN_SHIFT		0
+#define RFFEN_SHIFT		1
+#define RFSPOL_SHIFT		2
+#define DCM_SHIFT		3
+#define RFSSEL_SHIFT		4
+#define RCKPOL_SHIFT		5
+#define RCKSEL_SHIFT		6
+#define LBM_SHIFT		7
+#define TXEN_SHIFT		8
+#define TFFEN_SHIFT		9
+#define TFSPOL_SHIFT		10
+#define TFSSEL_SHIFT		11
+#define TCKPOL_SHIFT		13
+#define TCKSEL_SHIFT		14
+#define TXDDL_SHIFT		15
+#define SGEN_SHIFT		16
+#define SCKPOL_SHIFT		17
+#define SCKSEL_SHIFT		18
+#define FGEN_SHIFT		20
+#define SPICKM_SHIFT		21
+#define TBSWAP_SHIFT		28
+
+#define RCKPOL_MASK		BIT(0)
+#define TCKPOL_MASK		BIT(0)
+#define SPICKM_MASK		(BIT(1) | BIT(0))
+#define MSP_RX_CLKPOL_BIT(n)     ((n & RCKPOL_MASK) << RCKPOL_SHIFT)
+#define MSP_TX_CLKPOL_BIT(n)     ((n & TCKPOL_MASK) << TCKPOL_SHIFT)
+
+#define P1ELEN_SHIFT		0
+#define P1FLEN_SHIFT		3
+#define DTYP_SHIFT		10
+#define ENDN_SHIFT		12
+#define DDLY_SHIFT		13
+#define FSIG_SHIFT		15
+#define P2ELEN_SHIFT		16
+#define P2FLEN_SHIFT		19
+#define P2SM_SHIFT		26
+#define P2EN_SHIFT		27
+#define FSYNC_SHIFT		15
+
+#define P1ELEN_MASK		0x00000007
+#define P2ELEN_MASK		0x00070000
+#define P1FLEN_MASK		0x00000378
+#define P2FLEN_MASK		0x03780000
+#define DDLY_MASK		0x00003000
+#define DTYP_MASK		0x00000600
+#define P2SM_MASK		0x04000000
+#define P2EN_MASK		0x08000000
+#define ENDN_MASK		0x00001000
+#define TFSPOL_MASK		0x00000400
+#define TBSWAP_MASK		0x30000000
+#define COMPANDING_MODE_MASK	0x00000c00
+#define FSYNC_MASK		0x00008000
+
+#define MSP_P1_ELEM_LEN_BITS(n)		(n & P1ELEN_MASK)
+#define MSP_P2_ELEM_LEN_BITS(n)		(((n) << P2ELEN_SHIFT) & P2ELEN_MASK)
+#define MSP_P1_FRAME_LEN_BITS(n)	(((n) << P1FLEN_SHIFT) & P1FLEN_MASK)
+#define MSP_P2_FRAME_LEN_BITS(n)	(((n) << P2FLEN_SHIFT) & P2FLEN_MASK)
+#define MSP_DATA_DELAY_BITS(n)		(((n) << DDLY_SHIFT) & DDLY_MASK)
+#define MSP_DATA_TYPE_BITS(n)		(((n) << DTYP_SHIFT) & DTYP_MASK)
+#define MSP_P2_START_MODE_BIT(n)	((n << P2SM_SHIFT) & P2SM_MASK)
+#define MSP_P2_ENABLE_BIT(n)		((n << P2EN_SHIFT) & P2EN_MASK)
+#define MSP_SET_ENDIANNES_BIT(n)	((n << ENDN_SHIFT) & ENDN_MASK)
+#define MSP_FSYNC_POL(n)		((n << TFSPOL_SHIFT) & TFSPOL_MASK)
+#define MSP_DATA_WORD_SWAP(n)		((n << TBSWAP_SHIFT) & TBSWAP_MASK)
+#define MSP_SET_COMPANDING_MODE(n)	((n << DTYP_SHIFT) & \
+						COMPANDING_MODE_MASK)
+#define MSP_SET_FSYNC_IGNORE(n)		((n << FSYNC_SHIFT) & FSYNC_MASK)
+
+/* Flag register */
+#define RX_BUSY			BIT(0)
+#define RX_FIFO_EMPTY		BIT(1)
+#define RX_FIFO_FULL		BIT(2)
+#define TX_BUSY			BIT(3)
+#define TX_FIFO_EMPTY		BIT(4)
+#define TX_FIFO_FULL		BIT(5)
+
+#define RBUSY_SHIFT		0
+#define RFE_SHIFT		1
+#define RFU_SHIFT		2
+#define TBUSY_SHIFT		3
+#define TFE_SHIFT		4
+#define TFU_SHIFT		5
+
+/* Multichannel control register */
+#define RMCEN_SHIFT		0
+#define RMCSF_SHIFT		1
+#define RCMPM_SHIFT		3
+#define TMCEN_SHIFT		5
+#define TNCSF_SHIFT		6
+
+/* Sample rate generator register */
+#define SCKDIV_SHIFT		0
+#define FRWID_SHIFT		10
+#define FRPER_SHIFT		16
+
+#define SCK_DIV_MASK		0x0000003FF
+#define FRAME_WIDTH_BITS(n)	(((n) << FRWID_SHIFT)  & 0x0000FC00)
+#define FRAME_PERIOD_BITS(n)	(((n) << FRPER_SHIFT) & 0x1FFF0000)
+
+/* DMA controller register */
+#define RX_DMA_ENABLE		BIT(0)
+#define TX_DMA_ENABLE		BIT(1)
+
+#define RDMAE_SHIFT		0
+#define TDMAE_SHIFT		1
+
+/* Interrupt Register */
+#define RX_SERVICE_INT		BIT(0)
+#define RX_OVERRUN_ERROR_INT	BIT(1)
+#define RX_FSYNC_ERR_INT	BIT(2)
+#define RX_FSYNC_INT		BIT(3)
+#define TX_SERVICE_INT		BIT(4)
+#define TX_UNDERRUN_ERR_INT	BIT(5)
+#define TX_FSYNC_ERR_INT	BIT(6)
+#define TX_FSYNC_INT		BIT(7)
+#define ALL_INT			0x000000ff
+
+/* MSP test control register */
+#define MSP_ITCR_ITEN		BIT(0)
+#define MSP_ITCR_TESTFIFO	BIT(1)
+
+#define RMCEN_BIT   0
+#define RMCSF_BIT   1
+#define RCMPM_BIT   3
+#define TMCEN_BIT   5
+#define TNCSF_BIT   6
+
+/* Single or dual phase mode */
+enum msp_phase_mode {
+	MSP_SINGLE_PHASE,
+	MSP_DUAL_PHASE
+};
+
+/* Frame length */
+enum msp_frame_length {
+	MSP_FRAME_LEN_1 = 0,
+	MSP_FRAME_LEN_2 = 1,
+	MSP_FRAME_LEN_4 = 3,
+	MSP_FRAME_LEN_8 = 7,
+	MSP_FRAME_LEN_12 = 11,
+	MSP_FRAME_LEN_16 = 15,
+	MSP_FRAME_LEN_20 = 19,
+	MSP_FRAME_LEN_32 = 31,
+	MSP_FRAME_LEN_48 = 47,
+	MSP_FRAME_LEN_64 = 63
+};
+
+/* Element length */
+enum msp_elem_length {
+	MSP_ELEM_LEN_8 = 0,
+	MSP_ELEM_LEN_10 = 1,
+	MSP_ELEM_LEN_12 = 2,
+	MSP_ELEM_LEN_14 = 3,
+	MSP_ELEM_LEN_16 = 4,
+	MSP_ELEM_LEN_20 = 5,
+	MSP_ELEM_LEN_24 = 6,
+	MSP_ELEM_LEN_32 = 7
+};
+
+enum msp_data_xfer_width {
+	MSP_DATA_TRANSFER_WIDTH_BYTE,
+	MSP_DATA_TRANSFER_WIDTH_HALFWORD,
+	MSP_DATA_TRANSFER_WIDTH_WORD
+};
+
+enum msp_frame_sync {
+	MSP_FSYNC_UNIGNORE = 0,
+	MSP_FSYNC_IGNORE = 1,
+};
+
+enum msp_phase2_start_mode {
+	MSP_PHASE2_START_MODE_IMEDIATE,
+	MSP_PHASE2_START_MODE_FSYNC
+};
+
+enum msp_btf {
+	MSP_BTF_MS_BIT_FIRST = 0,
+	MSP_BTF_LS_BIT_FIRST = 1
+};
+
+enum msp_fsync_pol {
+	MSP_FSYNC_POL_ACT_HI = 0,
+	MSP_FSYNC_POL_ACT_LO = 1
+};
+
+/* Data delay (in bit clock cycles) */
+enum msp_delay {
+	MSP_DELAY_0 = 0,
+	MSP_DELAY_1 = 1,
+	MSP_DELAY_2 = 2,
+	MSP_DELAY_3 = 3
+};
+
+/* Configurations of clocks (transmit, receive or sample rate generator) */
+enum msp_edge {
+	MSP_FALLING_EDGE = 0,
+	MSP_RISING_EDGE = 1,
+};
+
+enum msp_hws {
+	MSP_SWAP_NONE = 0,
+	MSP_SWAP_BYTE_PER_WORD = 1,
+	MSP_SWAP_BYTE_PER_HALF_WORD = 2,
+	MSP_SWAP_HALF_WORD_PER_WORD = 3
+};
+
+enum msp_compress_mode {
+	MSP_COMPRESS_MODE_LINEAR = 0,
+	MSP_COMPRESS_MODE_MU_LAW = 2,
+	MSP_COMPRESS_MODE_A_LAW = 3
+};
+
+enum msp_spi_burst_mode {
+	MSP_SPI_BURST_MODE_DISABLE = 0,
+	MSP_SPI_BURST_MODE_ENABLE = 1
+};
+
+enum msp_expand_mode {
+	MSP_EXPAND_MODE_LINEAR = 0,
+	MSP_EXPAND_MODE_LINEAR_SIGNED = 1,
+	MSP_EXPAND_MODE_MU_LAW = 2,
+	MSP_EXPAND_MODE_A_LAW = 3
+};
+
+#define MSP_FRAME_PERIOD_IN_MONO_MODE 256
+#define MSP_FRAME_PERIOD_IN_STEREO_MODE 32
+#define MSP_FRAME_WIDTH_IN_STEREO_MODE 16
+
+enum msp_protocol {
+	MSP_I2S_PROTOCOL,
+	MSP_PCM_PROTOCOL,
+	MSP_PCM_COMPAND_PROTOCOL,
+	MSP_INVALID_PROTOCOL
+};
+
+/*
+ * No of registers to backup during
+ * suspend resume
+ */
+#define MAX_MSP_BACKUP_REGS 36
+
+enum enum_i2s_controller {
+	MSP_0_I2S_CONTROLLER = 0,
+	MSP_1_I2S_CONTROLLER,
+	MSP_2_I2S_CONTROLLER,
+	MSP_3_I2S_CONTROLLER,
+};
+
+enum i2s_direction_t {
+	MSP_DIR_TX = 0x01,
+	MSP_DIR_RX = 0x02,
+};
+
+enum msp_data_size {
+	MSP_DATA_BITS_DEFAULT = -1,
+	MSP_DATA_BITS_8 = 0x00,
+	MSP_DATA_BITS_10,
+	MSP_DATA_BITS_12,
+	MSP_DATA_BITS_14,
+	MSP_DATA_BITS_16,
+	MSP_DATA_BITS_20,
+	MSP_DATA_BITS_24,
+	MSP_DATA_BITS_32,
+};
+
+enum msp_state {
+	MSP_STATE_IDLE = 0,
+	MSP_STATE_CONFIGURED = 1,
+	MSP_STATE_RUNNING = 2,
+};
+
+enum msp_rx_comparison_enable_mode {
+	MSP_COMPARISON_DISABLED = 0,
+	MSP_COMPARISON_NONEQUAL_ENABLED = 2,
+	MSP_COMPARISON_EQUAL_ENABLED = 3
+};
+
+struct msp_multichannel_config {
+	bool rx_multichannel_enable;
+	bool tx_multichannel_enable;
+	enum msp_rx_comparison_enable_mode rx_comparison_enable_mode;
+	u8 padding;
+	u32 comparison_value;
+	u32 comparison_mask;
+	u32 rx_channel_0_enable;
+	u32 rx_channel_1_enable;
+	u32 rx_channel_2_enable;
+	u32 rx_channel_3_enable;
+	u32 tx_channel_0_enable;
+	u32 tx_channel_1_enable;
+	u32 tx_channel_2_enable;
+	u32 tx_channel_3_enable;
+};
+
+struct msp_protdesc {
+	u32 rx_phase_mode;
+	u32 tx_phase_mode;
+	u32 rx_phase2_start_mode;
+	u32 tx_phase2_start_mode;
+	u32 rx_byte_order;
+	u32 tx_byte_order;
+	u32 rx_frame_len_1;
+	u32 rx_frame_len_2;
+	u32 tx_frame_len_1;
+	u32 tx_frame_len_2;
+	u32 rx_elem_len_1;
+	u32 rx_elem_len_2;
+	u32 tx_elem_len_1;
+	u32 tx_elem_len_2;
+	u32 rx_data_delay;
+	u32 tx_data_delay;
+	u32 rx_clk_pol;
+	u32 tx_clk_pol;
+	u32 rx_fsync_pol;
+	u32 tx_fsync_pol;
+	u32 rx_half_word_swap;
+	u32 tx_half_word_swap;
+	u32 compression_mode;
+	u32 expansion_mode;
+	u32 frame_sync_ignore;
+	u32 frame_period;
+	u32 frame_width;
+	u32 clocks_per_frame;
+};
+
+struct i2s_message {
+	enum i2s_direction_t i2s_direction;
+	void *txdata;
+	void *rxdata;
+	size_t txbytes;
+	size_t rxbytes;
+	int dma_flag;
+	int tx_offset;
+	int rx_offset;
+	bool cyclic_dma;
+	dma_addr_t buf_addr;
+	size_t buf_len;
+	size_t period_len;
+};
+
+struct i2s_controller {
+	struct module *owner;
+	unsigned int id;
+	unsigned int class;
+	const struct i2s_algorithm *algo; /* the algorithm to access the bus */
+	void *data;
+	struct mutex bus_lock;
+	struct device dev; /* the controller device */
+	char name[48];
+};
+
+struct ux500_msp_config {
+	unsigned int f_inputclk;
+	unsigned int rx_clk_sel;
+	unsigned int tx_clk_sel;
+	unsigned int srg_clk_sel;
+	unsigned int rx_fsync_pol;
+	unsigned int tx_fsync_pol;
+	unsigned int rx_fsync_sel;
+	unsigned int tx_fsync_sel;
+	unsigned int rx_fifo_config;
+	unsigned int tx_fifo_config;
+	unsigned int spi_clk_mode;
+	unsigned int spi_burst_mode;
+	unsigned int loopback_enable;
+	unsigned int tx_data_enable;
+	unsigned int default_protdesc;
+	struct msp_protdesc protdesc;
+	int multichannel_configured;
+	struct msp_multichannel_config multichannel_config;
+	unsigned int direction;
+	unsigned int protocol;
+	unsigned int frame_freq;
+	unsigned int frame_size;
+	enum msp_data_size data_size;
+	unsigned int def_elem_len;
+	unsigned int iodelay;
+	void (*handler) (void *data);
+	void *tx_callback_data;
+	void *rx_callback_data;
+};
+
+struct ux500_msp {
+	enum enum_i2s_controller id;
+	void __iomem *registers;
+	struct device *dev;
+	struct i2s_controller *i2s_cont;
+	struct stedma40_chan_cfg *dma_cfg_rx;
+	struct stedma40_chan_cfg *dma_cfg_tx;
+	struct dma_chan *tx_pipeid;
+	struct dma_chan *rx_pipeid;
+	enum msp_state msp_state;
+	int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
+	int (*plat_init) (void);
+	int (*plat_exit) (void);
+	struct timer_list notify_timer;
+	int def_elem_len;
+	unsigned int dir_busy;
+	int loopback_enable;
+	u32 backup_regs[MAX_MSP_BACKUP_REGS];
+	unsigned int f_bitclk;
+};
+
+struct ux500_msp_dma_params {
+	unsigned int data_size;
+	struct stedma40_chan_cfg *dma_cfg;
+};
+
+int ux500_msp_i2s_init_msp(struct platform_device *pdev,
+			struct ux500_msp **msp_p,
+			struct msp_i2s_platform_data *platform_data);
+void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
+			struct ux500_msp *msp);
+int ux500_msp_i2s_open(struct ux500_msp *msp, struct ux500_msp_config *config);
+int ux500_msp_i2s_close(struct ux500_msp *msp,
+			unsigned int dir);
+int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd,
+			int direction);
+
+#endif
diff --git a/sound/sound_core.c b/sound/sound_core.c
index c6e81fb..fb9255c 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -361,7 +361,7 @@
 				  struct device *dev)
 {
 	const int chain = unit % SOUND_STEP;
-	int max_unit = 128 + chain;
+	int max_unit = 256;
 	const char *name;
 	char _name[16];
 
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4a7be7b..d5b5c33 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -131,8 +131,9 @@
 		subs = &as->substream[idx];
 		if (!subs->num_formats)
 			continue;
-		snd_usb_release_substream_urbs(subs, 1);
 		subs->interface = -1;
+		subs->data_endpoint = NULL;
+		subs->sync_endpoint = NULL;
 	}
 }
 
@@ -276,6 +277,7 @@
 
 static int snd_usb_audio_free(struct snd_usb_audio *chip)
 {
+	mutex_destroy(&chip->mutex);
 	kfree(chip);
 	return 0;
 }
@@ -336,6 +338,7 @@
 		return -ENOMEM;
 	}
 
+	mutex_init(&chip->mutex);
 	mutex_init(&chip->shutdown_mutex);
 	chip->index = idx;
 	chip->dev = dev;
@@ -348,6 +351,7 @@
 	chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
 			      le16_to_cpu(dev->descriptor.idProduct));
 	INIT_LIST_HEAD(&chip->pcm_list);
+	INIT_LIST_HEAD(&chip->ep_list);
 	INIT_LIST_HEAD(&chip->midi_list);
 	INIT_LIST_HEAD(&chip->mixer_list);
 
@@ -565,6 +569,10 @@
 		list_for_each(p, &chip->pcm_list) {
 			snd_usb_stream_disconnect(p);
 		}
+		/* release the endpoint resources */
+		list_for_each(p, &chip->ep_list) {
+			snd_usb_endpoint_free(p);
+		}
 		/* release the midi resources */
 		list_for_each(p, &chip->midi_list) {
 			snd_usbmidi_disconnect(p);
diff --git a/sound/usb/card.h b/sound/usb/card.h
index da5fa1a..0d37238 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -30,20 +30,71 @@
 };
 
 struct snd_usb_substream;
+struct snd_usb_endpoint;
 
 struct snd_urb_ctx {
 	struct urb *urb;
 	unsigned int buffer_size;	/* size of data buffer, if data URB */
 	struct snd_usb_substream *subs;
+	struct snd_usb_endpoint *ep;
 	int index;	/* index for urb array */
 	int packets;	/* number of packets per urb */
+	int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */
+	struct list_head ready_list;
 };
 
-struct snd_urb_ops {
-	int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
-	int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
-	int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
-	int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
+struct snd_usb_endpoint {
+	struct snd_usb_audio *chip;
+
+	int use_count;
+	int ep_num;		/* the referenced endpoint number */
+	int type;		/* SND_USB_ENDPOINT_TYPE_* */
+	unsigned long flags;
+
+	void (*prepare_data_urb) (struct snd_usb_substream *subs,
+				  struct urb *urb);
+	void (*retire_data_urb) (struct snd_usb_substream *subs,
+				 struct urb *urb);
+
+	struct snd_usb_substream *data_subs;
+	struct snd_usb_endpoint *sync_master;
+	struct snd_usb_endpoint *sync_slave;
+
+	struct snd_urb_ctx urb[MAX_URBS];
+
+	struct snd_usb_packet_info {
+		uint32_t packet_size[MAX_PACKS_HS];
+		int packets;
+	} next_packet[MAX_URBS];
+	int next_packet_read_pos, next_packet_write_pos;
+	struct list_head ready_playback_urbs;
+
+	unsigned int nurbs;		/* # urbs */
+	unsigned long active_mask;	/* bitmask of active urbs */
+	unsigned long unlink_mask;	/* bitmask of unlinked urbs */
+	char *syncbuf;			/* sync buffer for all sync URBs */
+	dma_addr_t sync_dma;		/* DMA address of syncbuf */
+
+	unsigned int pipe;		/* the data i/o pipe */
+	unsigned int freqn;		/* nominal sampling rate in fs/fps in Q16.16 format */
+	unsigned int freqm;		/* momentary sampling rate in fs/fps in Q16.16 format */
+	int	   freqshift;		/* how much to shift the feedback value to get Q16.16 */
+	unsigned int freqmax;		/* maximum sampling rate, used for buffer management */
+	unsigned int phase;		/* phase accumulator */
+	unsigned int maxpacksize;	/* max packet size in bytes */
+	unsigned int maxframesize;      /* max packet size in frames */
+	unsigned int curpacksize;	/* current packet size in bytes (for capture) */
+	unsigned int curframesize;      /* current packet size in frames (for capture) */
+	unsigned int syncmaxsize;	/* sync endpoint packet size */
+	unsigned int fill_max:1;	/* fill max packet size always */
+	unsigned int datainterval;      /* log_2 of data packet interval */
+	unsigned int syncinterval;	/* P for adaptive mode, 0 otherwise */
+	unsigned char silence_value;
+	unsigned int stride;
+	int iface, alt_idx;
+
+	spinlock_t lock;
+	struct list_head list;
 };
 
 struct snd_usb_substream {
@@ -57,21 +108,6 @@
 	unsigned int cur_rate;		/* current rate (for hw_params callback) */
 	unsigned int period_bytes;	/* current period bytes (for hw_params callback) */
 	unsigned int altset_idx;     /* USB data format: index of alternate setting */
-	unsigned int datapipe;   /* the data i/o pipe */
-	unsigned int syncpipe;   /* 1 - async out or adaptive in */
-	unsigned int datainterval;	/* log_2 of data packet interval */
-	unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */
-	unsigned int freqn;      /* nominal sampling rate in fs/fps in Q16.16 format */
-	unsigned int freqm;      /* momentary sampling rate in fs/fps in Q16.16 format */
-	int          freqshift;  /* how much to shift the feedback value to get Q16.16 */
-	unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
-	unsigned int phase;      /* phase accumulator */
-	unsigned int maxpacksize;	/* max packet size in bytes */
-	unsigned int maxframesize;	/* max packet size in frames */
-	unsigned int curpacksize;	/* current packet size in bytes (for capture) */
-	unsigned int curframesize;	/* current packet size in frames (for capture) */
-	unsigned int syncmaxsize;	/* sync endpoint packet size */
-	unsigned int fill_max: 1;	/* fill max packet size always */
 	unsigned int txfr_quirk:1;	/* allow sub-frame alignment */
 	unsigned int fmt_type;		/* USB audio format type (1-3) */
 
@@ -82,11 +118,10 @@
 	unsigned long active_mask;	/* bitmask of active urbs */
 	unsigned long unlink_mask;	/* bitmask of unlinked urbs */
 
-	unsigned int nurbs;			/* # urbs */
-	struct snd_urb_ctx dataurb[MAX_URBS];	/* data urb table */
-	struct snd_urb_ctx syncurb[SYNC_URBS];	/* sync urb table */
-	char *syncbuf;				/* sync buffer for all sync URBs */
-	dma_addr_t sync_dma;			/* DMA address of syncbuf */
+	/* data and sync endpoints for this stream */
+	struct snd_usb_endpoint *data_endpoint;
+	struct snd_usb_endpoint *sync_endpoint;
+	unsigned long flags;
 
 	u64 formats;			/* format bitmasks (all or'ed) */
 	unsigned int num_formats;		/* number of supported audio formats (list) */
@@ -94,7 +129,6 @@
 	struct snd_pcm_hw_constraint_list rate_list;	/* limited rates */
 	spinlock_t lock;
 
-	struct snd_urb_ops ops;		/* callbacks (must be filled at init) */
 	int last_frame_number;          /* stored frame number */
 	int last_delay;                 /* stored delay */
 };
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 08dcce5..e690690 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -20,9 +20,11 @@
 #include <linux/ratelimit.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
+#include <linux/slab.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 
 #include "usbaudio.h"
 #include "helper.h"
@@ -30,6 +32,36 @@
 #include "endpoint.h"
 #include "pcm.h"
 
+#define EP_FLAG_ACTIVATED	0
+#define EP_FLAG_RUNNING		1
+
+/*
+ * snd_usb_endpoint is a model that abstracts everything related to an
+ * USB endpoint and its streaming.
+ *
+ * There are functions to activate and deactivate the streaming URBs and
+ * optional callbacks to let the pcm logic handle the actual content of the
+ * packets for playback and record. Thus, the bus streaming and the audio
+ * handlers are fully decoupled.
+ *
+ * There are two different types of endpoints in audio applications.
+ *
+ * SND_USB_ENDPOINT_TYPE_DATA handles full audio data payload for both
+ * inbound and outbound traffic.
+ *
+ * SND_USB_ENDPOINT_TYPE_SYNC endpoints are for inbound traffic only and
+ * expect the payload to carry Q10.14 / Q16.16 formatted sync information
+ * (3 or 4 bytes).
+ *
+ * Each endpoint has to be configured prior to being used by calling
+ * snd_usb_endpoint_set_params().
+ *
+ * The model incorporates a reference counting, so that multiple users
+ * can call snd_usb_endpoint_start() and snd_usb_endpoint_stop(), and
+ * only the first user will effectively start the URBs, and only the last
+ * one to stop it will tear the URBs down again.
+ */
+
 /*
  * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
  * this will overflow at approx 524 kHz
@@ -49,727 +81,16 @@
 }
 
 /*
- * unlink active urbs.
- */
-static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep)
-{
-	struct snd_usb_audio *chip = subs->stream->chip;
-	unsigned int i;
-	int async;
-
-	subs->running = 0;
-
-	if (!force && subs->stream->chip->shutdown) /* to be sure... */
-		return -EBADFD;
-
-	async = !can_sleep && chip->async_unlink;
-
-	if (!async && in_interrupt())
-		return 0;
-
-	for (i = 0; i < subs->nurbs; i++) {
-		if (test_bit(i, &subs->active_mask)) {
-			if (!test_and_set_bit(i, &subs->unlink_mask)) {
-				struct urb *u = subs->dataurb[i].urb;
-				if (async)
-					usb_unlink_urb(u);
-				else
-					usb_kill_urb(u);
-			}
-		}
-	}
-	if (subs->syncpipe) {
-		for (i = 0; i < SYNC_URBS; i++) {
-			if (test_bit(i+16, &subs->active_mask)) {
-				if (!test_and_set_bit(i+16, &subs->unlink_mask)) {
-					struct urb *u = subs->syncurb[i].urb;
-					if (async)
-						usb_unlink_urb(u);
-					else
-						usb_kill_urb(u);
-				}
-			}
-		}
-	}
-	return 0;
-}
-
-
-/*
  * release a urb data
  */
 static void release_urb_ctx(struct snd_urb_ctx *u)
 {
-	if (u->urb) {
-		if (u->buffer_size)
-			usb_free_coherent(u->subs->dev, u->buffer_size,
-					u->urb->transfer_buffer,
-					u->urb->transfer_dma);
-		usb_free_urb(u->urb);
-		u->urb = NULL;
-	}
-}
-
-/*
- *  wait until all urbs are processed.
- */
-static int wait_clear_urbs(struct snd_usb_substream *subs)
-{
-	unsigned long end_time = jiffies + msecs_to_jiffies(1000);
-	unsigned int i;
-	int alive;
-
-	do {
-		alive = 0;
-		for (i = 0; i < subs->nurbs; i++) {
-			if (test_bit(i, &subs->active_mask))
-				alive++;
-		}
-		if (subs->syncpipe) {
-			for (i = 0; i < SYNC_URBS; i++) {
-				if (test_bit(i + 16, &subs->active_mask))
-					alive++;
-			}
-		}
-		if (! alive)
-			break;
-		schedule_timeout_uninterruptible(1);
-	} while (time_before(jiffies, end_time));
-	if (alive)
-		snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-	return 0;
-}
-
-/*
- * release a substream
- */
-void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
-{
-	int i;
-
-	/* stop urbs (to be sure) */
-	deactivate_urbs(subs, force, 1);
-	wait_clear_urbs(subs);
-
-	for (i = 0; i < MAX_URBS; i++)
-		release_urb_ctx(&subs->dataurb[i]);
-	for (i = 0; i < SYNC_URBS; i++)
-		release_urb_ctx(&subs->syncurb[i]);
-	usb_free_coherent(subs->dev, SYNC_URBS * 4,
-			subs->syncbuf, subs->sync_dma);
-	subs->syncbuf = NULL;
-	subs->nurbs = 0;
-}
-
-/*
- * complete callback from data urb
- */
-static void snd_complete_urb(struct urb *urb)
-{
-	struct snd_urb_ctx *ctx = urb->context;
-	struct snd_usb_substream *subs = ctx->subs;
-	struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
-	int err = 0;
-
-	if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
-	    !subs->running || /* can be stopped during retire callback */
-	    (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
-	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
-		clear_bit(ctx->index, &subs->active_mask);
-		if (err < 0) {
-			snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
-			snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-		}
-	}
-}
-
-
-/*
- * complete callback from sync urb
- */
-static void snd_complete_sync_urb(struct urb *urb)
-{
-	struct snd_urb_ctx *ctx = urb->context;
-	struct snd_usb_substream *subs = ctx->subs;
-	struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
-	int err = 0;
-
-	if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) ||
-	    !subs->running || /* can be stopped during retire callback */
-	    (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 ||
-	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
-		clear_bit(ctx->index + 16, &subs->active_mask);
-		if (err < 0) {
-			snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err);
-			snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-		}
-	}
-}
-
-
-/*
- * initialize a substream for plaback/capture
- */
-int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
-				unsigned int period_bytes,
-				unsigned int rate,
-				unsigned int frame_bits)
-{
-	unsigned int maxsize, i;
-	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-	unsigned int urb_packs, total_packs, packs_per_ms;
-	struct snd_usb_audio *chip = subs->stream->chip;
-
-	/* calculate the frequency in 16.16 format */
-	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
-		subs->freqn = get_usb_full_speed_rate(rate);
-	else
-		subs->freqn = get_usb_high_speed_rate(rate);
-	subs->freqm = subs->freqn;
-	subs->freqshift = INT_MIN;
-	/* calculate max. frequency */
-	if (subs->maxpacksize) {
-		/* whatever fits into a max. size packet */
-		maxsize = subs->maxpacksize;
-		subs->freqmax = (maxsize / (frame_bits >> 3))
-				<< (16 - subs->datainterval);
-	} else {
-		/* no max. packet size: just take 25% higher than nominal */
-		subs->freqmax = subs->freqn + (subs->freqn >> 2);
-		maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3))
-				>> (16 - subs->datainterval);
-	}
-	subs->phase = 0;
-
-	if (subs->fill_max)
-		subs->curpacksize = subs->maxpacksize;
-	else
-		subs->curpacksize = maxsize;
-
-	if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
-		packs_per_ms = 8 >> subs->datainterval;
-	else
-		packs_per_ms = 1;
-
-	if (is_playback) {
-		urb_packs = max(chip->nrpacks, 1);
-		urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
-	} else
-		urb_packs = 1;
-	urb_packs *= packs_per_ms;
-	if (subs->syncpipe)
-		urb_packs = min(urb_packs, 1U << subs->syncinterval);
-
-	/* decide how many packets to be used */
-	if (is_playback) {
-		unsigned int minsize, maxpacks;
-		/* determine how small a packet can be */
-		minsize = (subs->freqn >> (16 - subs->datainterval))
-			  * (frame_bits >> 3);
-		/* with sync from device, assume it can be 12% lower */
-		if (subs->syncpipe)
-			minsize -= minsize >> 3;
-		minsize = max(minsize, 1u);
-		total_packs = (period_bytes + minsize - 1) / minsize;
-		/* we need at least two URBs for queueing */
-		if (total_packs < 2) {
-			total_packs = 2;
-		} else {
-			/* and we don't want too long a queue either */
-			maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
-			total_packs = min(total_packs, maxpacks);
-		}
-	} else {
-		while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
-			urb_packs >>= 1;
-		total_packs = MAX_URBS * urb_packs;
-	}
-	subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
-	if (subs->nurbs > MAX_URBS) {
-		/* too much... */
-		subs->nurbs = MAX_URBS;
-		total_packs = MAX_URBS * urb_packs;
-	} else if (subs->nurbs < 2) {
-		/* too little - we need at least two packets
-		 * to ensure contiguous playback/capture
-		 */
-		subs->nurbs = 2;
-	}
-
-	/* allocate and initialize data urbs */
-	for (i = 0; i < subs->nurbs; i++) {
-		struct snd_urb_ctx *u = &subs->dataurb[i];
-		u->index = i;
-		u->subs = subs;
-		u->packets = (i + 1) * total_packs / subs->nurbs
-			- i * total_packs / subs->nurbs;
-		u->buffer_size = maxsize * u->packets;
-		if (subs->fmt_type == UAC_FORMAT_TYPE_II)
-			u->packets++; /* for transfer delimiter */
-		u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
-		if (!u->urb)
-			goto out_of_memory;
-		u->urb->transfer_buffer =
-			usb_alloc_coherent(subs->dev, u->buffer_size,
-					   GFP_KERNEL, &u->urb->transfer_dma);
-		if (!u->urb->transfer_buffer)
-			goto out_of_memory;
-		u->urb->pipe = subs->datapipe;
-		u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-		u->urb->interval = 1 << subs->datainterval;
-		u->urb->context = u;
-		u->urb->complete = snd_complete_urb;
-	}
-
-	if (subs->syncpipe) {
-		/* allocate and initialize sync urbs */
-		subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4,
-						 GFP_KERNEL, &subs->sync_dma);
-		if (!subs->syncbuf)
-			goto out_of_memory;
-		for (i = 0; i < SYNC_URBS; i++) {
-			struct snd_urb_ctx *u = &subs->syncurb[i];
-			u->index = i;
-			u->subs = subs;
-			u->packets = 1;
-			u->urb = usb_alloc_urb(1, GFP_KERNEL);
-			if (!u->urb)
-				goto out_of_memory;
-			u->urb->transfer_buffer = subs->syncbuf + i * 4;
-			u->urb->transfer_dma = subs->sync_dma + i * 4;
-			u->urb->transfer_buffer_length = 4;
-			u->urb->pipe = subs->syncpipe;
-			u->urb->transfer_flags = URB_ISO_ASAP |
-						 URB_NO_TRANSFER_DMA_MAP;
-			u->urb->number_of_packets = 1;
-			u->urb->interval = 1 << subs->syncinterval;
-			u->urb->context = u;
-			u->urb->complete = snd_complete_sync_urb;
-		}
-	}
-	return 0;
-
-out_of_memory:
-	snd_usb_release_substream_urbs(subs, 0);
-	return -ENOMEM;
-}
-
-/*
- * prepare urb for full speed capture sync pipe
- *
- * fill the length and offset of each urb descriptor.
- * the fixed 10.14 frequency is passed through the pipe.
- */
-static int prepare_capture_sync_urb(struct snd_usb_substream *subs,
-				    struct snd_pcm_runtime *runtime,
-				    struct urb *urb)
-{
-	unsigned char *cp = urb->transfer_buffer;
-	struct snd_urb_ctx *ctx = urb->context;
-
-	urb->dev = ctx->subs->dev; /* we need to set this at each time */
-	urb->iso_frame_desc[0].length = 3;
-	urb->iso_frame_desc[0].offset = 0;
-	cp[0] = subs->freqn >> 2;
-	cp[1] = subs->freqn >> 10;
-	cp[2] = subs->freqn >> 18;
-	return 0;
-}
-
-/*
- * prepare urb for high speed capture sync pipe
- *
- * fill the length and offset of each urb descriptor.
- * the fixed 12.13 frequency is passed as 16.16 through the pipe.
- */
-static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs,
-				       struct snd_pcm_runtime *runtime,
-				       struct urb *urb)
-{
-	unsigned char *cp = urb->transfer_buffer;
-	struct snd_urb_ctx *ctx = urb->context;
-
-	urb->dev = ctx->subs->dev; /* we need to set this at each time */
-	urb->iso_frame_desc[0].length = 4;
-	urb->iso_frame_desc[0].offset = 0;
-	cp[0] = subs->freqn;
-	cp[1] = subs->freqn >> 8;
-	cp[2] = subs->freqn >> 16;
-	cp[3] = subs->freqn >> 24;
-	return 0;
-}
-
-/*
- * process after capture sync complete
- * - nothing to do
- */
-static int retire_capture_sync_urb(struct snd_usb_substream *subs,
-				   struct snd_pcm_runtime *runtime,
-				   struct urb *urb)
-{
-	return 0;
-}
-
-/*
- * prepare urb for capture data pipe
- *
- * fill the offset and length of each descriptor.
- *
- * we use a temporary buffer to write the captured data.
- * since the length of written data is determined by host, we cannot
- * write onto the pcm buffer directly...  the data is thus copied
- * later at complete callback to the global buffer.
- */
-static int prepare_capture_urb(struct snd_usb_substream *subs,
-			       struct snd_pcm_runtime *runtime,
-			       struct urb *urb)
-{
-	int i, offs;
-	struct snd_urb_ctx *ctx = urb->context;
-
-	offs = 0;
-	urb->dev = ctx->subs->dev; /* we need to set this at each time */
-	for (i = 0; i < ctx->packets; i++) {
-		urb->iso_frame_desc[i].offset = offs;
-		urb->iso_frame_desc[i].length = subs->curpacksize;
-		offs += subs->curpacksize;
-	}
-	urb->transfer_buffer_length = offs;
-	urb->number_of_packets = ctx->packets;
-	return 0;
-}
-
-/*
- * process after capture complete
- *
- * copy the data from each desctiptor to the pcm buffer, and
- * update the current position.
- */
-static int retire_capture_urb(struct snd_usb_substream *subs,
-			      struct snd_pcm_runtime *runtime,
-			      struct urb *urb)
-{
-	unsigned long flags;
-	unsigned char *cp;
-	int i;
-	unsigned int stride, frames, bytes, oldptr;
-	int period_elapsed = 0;
-
-	stride = runtime->frame_bits >> 3;
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-		if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
-			snd_printdd("frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
-			// continue;
-		}
-		bytes = urb->iso_frame_desc[i].actual_length;
-		frames = bytes / stride;
-		if (!subs->txfr_quirk)
-			bytes = frames * stride;
-		if (bytes % (runtime->sample_bits >> 3) != 0) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-			int oldbytes = bytes;
-#endif
-			bytes = frames * stride;
-			snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
-							oldbytes, bytes);
-		}
-		/* update the current pointer */
-		spin_lock_irqsave(&subs->lock, flags);
-		oldptr = subs->hwptr_done;
-		subs->hwptr_done += bytes;
-		if (subs->hwptr_done >= runtime->buffer_size * stride)
-			subs->hwptr_done -= runtime->buffer_size * stride;
-		frames = (bytes + (oldptr % stride)) / stride;
-		subs->transfer_done += frames;
-		if (subs->transfer_done >= runtime->period_size) {
-			subs->transfer_done -= runtime->period_size;
-			period_elapsed = 1;
-		}
-		spin_unlock_irqrestore(&subs->lock, flags);
-		/* copy a data chunk */
-		if (oldptr + bytes > runtime->buffer_size * stride) {
-			unsigned int bytes1 =
-					runtime->buffer_size * stride - oldptr;
-			memcpy(runtime->dma_area + oldptr, cp, bytes1);
-			memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
-		} else {
-			memcpy(runtime->dma_area + oldptr, cp, bytes);
-		}
-	}
-	if (period_elapsed)
-		snd_pcm_period_elapsed(subs->pcm_substream);
-	return 0;
-}
-
-/*
- * Process after capture complete when paused.  Nothing to do.
- */
-static int retire_paused_capture_urb(struct snd_usb_substream *subs,
-				     struct snd_pcm_runtime *runtime,
-				     struct urb *urb)
-{
-	return 0;
-}
-
-
-/*
- * prepare urb for playback sync pipe
- *
- * set up the offset and length to receive the current frequency.
- */
-static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
-				     struct snd_pcm_runtime *runtime,
-				     struct urb *urb)
-{
-	struct snd_urb_ctx *ctx = urb->context;
-
-	urb->dev = ctx->subs->dev; /* we need to set this at each time */
-	urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize);
-	urb->iso_frame_desc[0].offset = 0;
-	return 0;
-}
-
-/*
- * process after playback sync complete
- *
- * Full speed devices report feedback values in 10.14 format as samples per
- * frame, high speed devices in 16.16 format as samples per microframe.
- * Because the Audio Class 1 spec was written before USB 2.0, many high speed
- * devices use a wrong interpretation, some others use an entirely different
- * format.  Therefore, we cannot predict what format any particular device uses
- * and must detect it automatically.
- */
-static int retire_playback_sync_urb(struct snd_usb_substream *subs,
-				    struct snd_pcm_runtime *runtime,
-				    struct urb *urb)
-{
-	unsigned int f;
-	int shift;
-	unsigned long flags;
-
-	if (urb->iso_frame_desc[0].status != 0 ||
-	    urb->iso_frame_desc[0].actual_length < 3)
-		return 0;
-
-	f = le32_to_cpup(urb->transfer_buffer);
-	if (urb->iso_frame_desc[0].actual_length == 3)
-		f &= 0x00ffffff;
-	else
-		f &= 0x0fffffff;
-	if (f == 0)
-		return 0;
-
-	if (unlikely(subs->freqshift == INT_MIN)) {
-		/*
-		 * The first time we see a feedback value, determine its format
-		 * by shifting it left or right until it matches the nominal
-		 * frequency value.  This assumes that the feedback does not
-		 * differ from the nominal value more than +50% or -25%.
-		 */
-		shift = 0;
-		while (f < subs->freqn - subs->freqn / 4) {
-			f <<= 1;
-			shift++;
-		}
-		while (f > subs->freqn + subs->freqn / 2) {
-			f >>= 1;
-			shift--;
-		}
-		subs->freqshift = shift;
-	}
-	else if (subs->freqshift >= 0)
-		f <<= subs->freqshift;
-	else
-		f >>= -subs->freqshift;
-
-	if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) {
-		/*
-		 * If the frequency looks valid, set it.
-		 * This value is referred to in prepare_playback_urb().
-		 */
-		spin_lock_irqsave(&subs->lock, flags);
-		subs->freqm = f;
-		spin_unlock_irqrestore(&subs->lock, flags);
-	} else {
-		/*
-		 * Out of range; maybe the shift value is wrong.
-		 * Reset it so that we autodetect again the next time.
-		 */
-		subs->freqshift = INT_MIN;
-	}
-
-	return 0;
-}
-
-/* determine the number of frames in the next packet */
-static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
-{
-	if (subs->fill_max)
-		return subs->maxframesize;
-	else {
-		subs->phase = (subs->phase & 0xffff)
-			+ (subs->freqm << subs->datainterval);
-		return min(subs->phase >> 16, subs->maxframesize);
-	}
-}
-
-/*
- * Prepare urb for streaming before playback starts or when paused.
- *
- * We don't have any data, so we send silence.
- */
-static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
-				       struct snd_pcm_runtime *runtime,
-				       struct urb *urb)
-{
-	unsigned int i, offs, counts;
-	struct snd_urb_ctx *ctx = urb->context;
-	int stride = runtime->frame_bits >> 3;
-
-	offs = 0;
-	urb->dev = ctx->subs->dev;
-	for (i = 0; i < ctx->packets; ++i) {
-		counts = snd_usb_audio_next_packet_size(subs);
-		urb->iso_frame_desc[i].offset = offs * stride;
-		urb->iso_frame_desc[i].length = counts * stride;
-		offs += counts;
-	}
-	urb->number_of_packets = ctx->packets;
-	urb->transfer_buffer_length = offs * stride;
-	memset(urb->transfer_buffer,
-	       runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
-	       offs * stride);
-	return 0;
-}
-
-/*
- * prepare urb for playback data pipe
- *
- * Since a URB can handle only a single linear buffer, we must use double
- * buffering when the data to be transferred overflows the buffer boundary.
- * To avoid inconsistencies when updating hwptr_done, we use double buffering
- * for all URBs.
- */
-static int prepare_playback_urb(struct snd_usb_substream *subs,
-				struct snd_pcm_runtime *runtime,
-				struct urb *urb)
-{
-	int i, stride;
-	unsigned int counts, frames, bytes;
-	unsigned long flags;
-	int period_elapsed = 0;
-	struct snd_urb_ctx *ctx = urb->context;
-
-	stride = runtime->frame_bits >> 3;
-
-	frames = 0;
-	urb->dev = ctx->subs->dev; /* we need to set this at each time */
-	urb->number_of_packets = 0;
-	spin_lock_irqsave(&subs->lock, flags);
-	for (i = 0; i < ctx->packets; i++) {
-		counts = snd_usb_audio_next_packet_size(subs);
-		/* set up descriptor */
-		urb->iso_frame_desc[i].offset = frames * stride;
-		urb->iso_frame_desc[i].length = counts * stride;
-		frames += counts;
-		urb->number_of_packets++;
-		subs->transfer_done += counts;
-		if (subs->transfer_done >= runtime->period_size) {
-			subs->transfer_done -= runtime->period_size;
-			period_elapsed = 1;
-			if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
-				if (subs->transfer_done > 0) {
-					/* FIXME: fill-max mode is not
-					 * supported yet */
-					frames -= subs->transfer_done;
-					counts -= subs->transfer_done;
-					urb->iso_frame_desc[i].length =
-						counts * stride;
-					subs->transfer_done = 0;
-				}
-				i++;
-				if (i < ctx->packets) {
-					/* add a transfer delimiter */
-					urb->iso_frame_desc[i].offset =
-						frames * stride;
-					urb->iso_frame_desc[i].length = 0;
-					urb->number_of_packets++;
-				}
-				break;
-			}
-		}
-		if (period_elapsed) /* finish at the period boundary */
-			break;
-	}
-	bytes = frames * stride;
-	if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
-		/* err, the transferred area goes over buffer boundary. */
-		unsigned int bytes1 =
-			runtime->buffer_size * stride - subs->hwptr_done;
-		memcpy(urb->transfer_buffer,
-		       runtime->dma_area + subs->hwptr_done, bytes1);
-		memcpy(urb->transfer_buffer + bytes1,
-		       runtime->dma_area, bytes - bytes1);
-	} else {
-		memcpy(urb->transfer_buffer,
-		       runtime->dma_area + subs->hwptr_done, bytes);
-	}
-	subs->hwptr_done += bytes;
-	if (subs->hwptr_done >= runtime->buffer_size * stride)
-		subs->hwptr_done -= runtime->buffer_size * stride;
-
-	/* update delay with exact number of samples queued */
-	runtime->delay = subs->last_delay;
-	runtime->delay += frames;
-	subs->last_delay = runtime->delay;
-
-	/* realign last_frame_number */
-	subs->last_frame_number = usb_get_current_frame_number(subs->dev);
-	subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
-
-	spin_unlock_irqrestore(&subs->lock, flags);
-	urb->transfer_buffer_length = bytes;
-	if (period_elapsed)
-		snd_pcm_period_elapsed(subs->pcm_substream);
-	return 0;
-}
-
-/*
- * process after playback data complete
- * - decrease the delay count again
- */
-static int retire_playback_urb(struct snd_usb_substream *subs,
-			       struct snd_pcm_runtime *runtime,
-			       struct urb *urb)
-{
-	unsigned long flags;
-	int stride = runtime->frame_bits >> 3;
-	int processed = urb->transfer_buffer_length / stride;
-	int est_delay;
-
-	spin_lock_irqsave(&subs->lock, flags);
-
-	est_delay = snd_usb_pcm_delay(subs, runtime->rate);
-	/* update delay with exact number of samples played */
-	if (processed > subs->last_delay)
-		subs->last_delay = 0;
-	else
-		subs->last_delay -= processed;
-	runtime->delay = subs->last_delay;
-
-	/*
-	 * Report when delay estimate is off by more than 2ms.
-	 * The error should be lower than 2ms since the estimate relies
-	 * on two reads of a counter updated every ms.
-	 */
-	if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
-		snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
-			est_delay, subs->last_delay);
-
-	spin_unlock_irqrestore(&subs->lock, flags);
-	return 0;
+	if (u->buffer_size)
+		usb_free_coherent(u->ep->chip->dev, u->buffer_size,
+				  u->urb->transfer_buffer,
+				  u->urb->transfer_dma);
+	usb_free_urb(u->urb);
+	u->urb = NULL;
 }
 
 static const char *usb_error_string(int err)
@@ -797,170 +118,1044 @@
 	}
 }
 
-/*
- * set up and start data/sync urbs
+/**
+ * snd_usb_endpoint_implicit_feedback_sink: Report endpoint usage type
+ *
+ * @ep: The snd_usb_endpoint
+ *
+ * Determine whether an endpoint is driven by an implicit feedback
+ * data endpoint source.
  */
-static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime)
+int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep)
 {
-	unsigned int i;
+	return  ep->sync_master &&
+		ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA &&
+		ep->type == SND_USB_ENDPOINT_TYPE_DATA &&
+		usb_pipeout(ep->pipe);
+}
+
+/*
+ * For streaming based on information derived from sync endpoints,
+ * prepare_outbound_urb_sizes() will call next_packet_size() to
+ * determine the number of samples to be sent in the next packet.
+ *
+ * For implicit feedback, next_packet_size() is unused.
+ */
+static int next_packet_size(struct snd_usb_endpoint *ep)
+{
+	unsigned long flags;
+	int ret;
+
+	if (ep->fill_max)
+		return ep->maxframesize;
+
+	spin_lock_irqsave(&ep->lock, flags);
+	ep->phase = (ep->phase & 0xffff)
+		+ (ep->freqm << ep->datainterval);
+	ret = min(ep->phase >> 16, ep->maxframesize);
+	spin_unlock_irqrestore(&ep->lock, flags);
+
+	return ret;
+}
+
+static void retire_outbound_urb(struct snd_usb_endpoint *ep,
+				struct snd_urb_ctx *urb_ctx)
+{
+	if (ep->retire_data_urb)
+		ep->retire_data_urb(ep->data_subs, urb_ctx->urb);
+}
+
+static void retire_inbound_urb(struct snd_usb_endpoint *ep,
+			       struct snd_urb_ctx *urb_ctx)
+{
+	struct urb *urb = urb_ctx->urb;
+
+	if (ep->sync_slave)
+		snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
+
+	if (ep->retire_data_urb)
+		ep->retire_data_urb(ep->data_subs, urb);
+}
+
+static void prepare_outbound_urb_sizes(struct snd_usb_endpoint *ep,
+				       struct snd_urb_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < ctx->packets; ++i)
+		ctx->packet_size[i] = next_packet_size(ep);
+}
+
+/*
+ * Prepare a PLAYBACK urb for submission to the bus.
+ */
+static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
+				 struct snd_urb_ctx *ctx)
+{
+	int i;
+	struct urb *urb = ctx->urb;
+	unsigned char *cp = urb->transfer_buffer;
+
+	urb->dev = ep->chip->dev; /* we need to set this at each time */
+
+	switch (ep->type) {
+	case SND_USB_ENDPOINT_TYPE_DATA:
+		if (ep->prepare_data_urb) {
+			ep->prepare_data_urb(ep->data_subs, urb);
+		} else {
+			/* no data provider, so send silence */
+			unsigned int offs = 0;
+			for (i = 0; i < ctx->packets; ++i) {
+				int counts = ctx->packet_size[i];
+				urb->iso_frame_desc[i].offset = offs * ep->stride;
+				urb->iso_frame_desc[i].length = counts * ep->stride;
+				offs += counts;
+			}
+
+			urb->number_of_packets = ctx->packets;
+			urb->transfer_buffer_length = offs * ep->stride;
+			memset(urb->transfer_buffer, ep->silence_value,
+			       offs * ep->stride);
+		}
+		break;
+
+	case SND_USB_ENDPOINT_TYPE_SYNC:
+		if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) {
+			/*
+			 * fill the length and offset of each urb descriptor.
+			 * the fixed 12.13 frequency is passed as 16.16 through the pipe.
+			 */
+			urb->iso_frame_desc[0].length = 4;
+			urb->iso_frame_desc[0].offset = 0;
+			cp[0] = ep->freqn;
+			cp[1] = ep->freqn >> 8;
+			cp[2] = ep->freqn >> 16;
+			cp[3] = ep->freqn >> 24;
+		} else {
+			/*
+			 * fill the length and offset of each urb descriptor.
+			 * the fixed 10.14 frequency is passed through the pipe.
+			 */
+			urb->iso_frame_desc[0].length = 3;
+			urb->iso_frame_desc[0].offset = 0;
+			cp[0] = ep->freqn >> 2;
+			cp[1] = ep->freqn >> 10;
+			cp[2] = ep->freqn >> 18;
+		}
+
+		break;
+	}
+}
+
+/*
+ * Prepare a CAPTURE or SYNC urb for submission to the bus.
+ */
+static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep,
+				       struct snd_urb_ctx *urb_ctx)
+{
+	int i, offs;
+	struct urb *urb = urb_ctx->urb;
+
+	urb->dev = ep->chip->dev; /* we need to set this at each time */
+
+	switch (ep->type) {
+	case SND_USB_ENDPOINT_TYPE_DATA:
+		offs = 0;
+		for (i = 0; i < urb_ctx->packets; i++) {
+			urb->iso_frame_desc[i].offset = offs;
+			urb->iso_frame_desc[i].length = ep->curpacksize;
+			offs += ep->curpacksize;
+		}
+
+		urb->transfer_buffer_length = offs;
+		urb->number_of_packets = urb_ctx->packets;
+		break;
+
+	case SND_USB_ENDPOINT_TYPE_SYNC:
+		urb->iso_frame_desc[0].length = min(4u, ep->syncmaxsize);
+		urb->iso_frame_desc[0].offset = 0;
+		break;
+	}
+}
+
+/*
+ * Send output urbs that have been prepared previously. URBs are dequeued
+ * from ep->ready_playback_urbs and in case there there aren't any available
+ * or there are no packets that have been prepared, this function does
+ * nothing.
+ *
+ * The reason why the functionality of sending and preparing URBs is separated
+ * is that host controllers don't guarantee the order in which they return
+ * inbound and outbound packets to their submitters.
+ *
+ * This function is only used for implicit feedback endpoints. For endpoints
+ * driven by dedicated sync endpoints, URBs are immediately re-submitted
+ * from their completion handler.
+ */
+static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
+{
+	while (test_bit(EP_FLAG_RUNNING, &ep->flags)) {
+
+		unsigned long flags;
+		struct snd_usb_packet_info *uninitialized_var(packet);
+		struct snd_urb_ctx *ctx = NULL;
+		struct urb *urb;
+		int err, i;
+
+		spin_lock_irqsave(&ep->lock, flags);
+		if (ep->next_packet_read_pos != ep->next_packet_write_pos) {
+			packet = ep->next_packet + ep->next_packet_read_pos;
+			ep->next_packet_read_pos++;
+			ep->next_packet_read_pos %= MAX_URBS;
+
+			/* take URB out of FIFO */
+			if (!list_empty(&ep->ready_playback_urbs))
+				ctx = list_first_entry(&ep->ready_playback_urbs,
+					       struct snd_urb_ctx, ready_list);
+		}
+		spin_unlock_irqrestore(&ep->lock, flags);
+
+		if (ctx == NULL)
+			return;
+
+		list_del_init(&ctx->ready_list);
+		urb = ctx->urb;
+
+		/* copy over the length information */
+		for (i = 0; i < packet->packets; i++)
+			ctx->packet_size[i] = packet->packet_size[i];
+
+		/* call the data handler to fill in playback data */
+		prepare_outbound_urb(ep, ctx);
+
+		err = usb_submit_urb(ctx->urb, GFP_ATOMIC);
+		if (err < 0)
+			snd_printk(KERN_ERR "Unable to submit urb #%d: %d (urb %p)\n",
+				   ctx->index, err, ctx->urb);
+		else
+			set_bit(ctx->index, &ep->active_mask);
+	}
+}
+
+/*
+ * complete callback for urbs
+ */
+static void snd_complete_urb(struct urb *urb)
+{
+	struct snd_urb_ctx *ctx = urb->context;
+	struct snd_usb_endpoint *ep = ctx->ep;
 	int err;
 
-	if (subs->stream->chip->shutdown)
-		return -EBADFD;
+	if (unlikely(urb->status == -ENOENT ||		/* unlinked */
+		     urb->status == -ENODEV ||		/* device removed */
+		     urb->status == -ECONNRESET ||	/* unlinked */
+		     urb->status == -ESHUTDOWN ||	/* device disabled */
+		     ep->chip->shutdown))		/* device disconnected */
+		goto exit_clear;
 
-	for (i = 0; i < subs->nurbs; i++) {
-		if (snd_BUG_ON(!subs->dataurb[i].urb))
-			return -EINVAL;
-		if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
-			snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
-			goto __error;
+	if (usb_pipeout(ep->pipe)) {
+		retire_outbound_urb(ep, ctx);
+		/* can be stopped during retire callback */
+		if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+			goto exit_clear;
+
+		if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&ep->lock, flags);
+			list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
+			spin_unlock_irqrestore(&ep->lock, flags);
+			queue_pending_output_urbs(ep);
+
+			goto exit_clear;
+		}
+
+		prepare_outbound_urb_sizes(ep, ctx);
+		prepare_outbound_urb(ep, ctx);
+	} else {
+		retire_inbound_urb(ep, ctx);
+		/* can be stopped during retire callback */
+		if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+			goto exit_clear;
+
+		prepare_inbound_urb(ep, ctx);
+	}
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err == 0)
+		return;
+
+	snd_printk(KERN_ERR "cannot submit urb (err = %d)\n", err);
+	//snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+
+exit_clear:
+	clear_bit(ctx->index, &ep->active_mask);
+}
+
+/**
+ * snd_usb_add_endpoint: Add an endpoint to an USB audio chip
+ *
+ * @chip: The chip
+ * @alts: The USB host interface
+ * @ep_num: The number of the endpoint to use
+ * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE
+ * @type: SND_USB_ENDPOINT_TYPE_DATA or SND_USB_ENDPOINT_TYPE_SYNC
+ *
+ * If the requested endpoint has not been added to the given chip before,
+ * a new instance is created. Otherwise, a pointer to the previoulsy
+ * created instance is returned. In case of any error, NULL is returned.
+ *
+ * New endpoints will be added to chip->ep_list and must be freed by
+ * calling snd_usb_endpoint_free().
+ */
+struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
+					      struct usb_host_interface *alts,
+					      int ep_num, int direction, int type)
+{
+	struct list_head *p;
+	struct snd_usb_endpoint *ep;
+	int ret, is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
+
+	mutex_lock(&chip->mutex);
+
+	list_for_each(p, &chip->ep_list) {
+		ep = list_entry(p, struct snd_usb_endpoint, list);
+		if (ep->ep_num == ep_num &&
+		    ep->iface == alts->desc.bInterfaceNumber &&
+		    ep->alt_idx == alts->desc.bAlternateSetting) {
+			snd_printdd(KERN_DEBUG "Re-using EP %x in iface %d,%d @%p\n",
+					ep_num, ep->iface, ep->alt_idx, ep);
+			goto __exit_unlock;
 		}
 	}
-	if (subs->syncpipe) {
-		for (i = 0; i < SYNC_URBS; i++) {
-			if (snd_BUG_ON(!subs->syncurb[i].urb))
-				return -EINVAL;
-			if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) {
-				snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
-				goto __error;
+
+	snd_printdd(KERN_DEBUG "Creating new %s %s endpoint #%x\n",
+		    is_playback ? "playback" : "capture",
+		    type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
+		    ep_num);
+
+	/* select the alt setting once so the endpoints become valid */
+	ret = usb_set_interface(chip->dev, alts->desc.bInterfaceNumber,
+				alts->desc.bAlternateSetting);
+	if (ret < 0) {
+		snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
+					__func__, ret);
+		ep = NULL;
+		goto __exit_unlock;
+	}
+
+	ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+	if (!ep)
+		goto __exit_unlock;
+
+	ep->chip = chip;
+	spin_lock_init(&ep->lock);
+	ep->type = type;
+	ep->ep_num = ep_num;
+	ep->iface = alts->desc.bInterfaceNumber;
+	ep->alt_idx = alts->desc.bAlternateSetting;
+	INIT_LIST_HEAD(&ep->ready_playback_urbs);
+	ep_num &= USB_ENDPOINT_NUMBER_MASK;
+
+	if (is_playback)
+		ep->pipe = usb_sndisocpipe(chip->dev, ep_num);
+	else
+		ep->pipe = usb_rcvisocpipe(chip->dev, ep_num);
+
+	if (type == SND_USB_ENDPOINT_TYPE_SYNC) {
+		if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+		    get_endpoint(alts, 1)->bRefresh >= 1 &&
+		    get_endpoint(alts, 1)->bRefresh <= 9)
+			ep->syncinterval = get_endpoint(alts, 1)->bRefresh;
+		else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL)
+			ep->syncinterval = 1;
+		else if (get_endpoint(alts, 1)->bInterval >= 1 &&
+			 get_endpoint(alts, 1)->bInterval <= 16)
+			ep->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
+		else
+			ep->syncinterval = 3;
+
+		ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
+	}
+
+	list_add_tail(&ep->list, &chip->ep_list);
+
+__exit_unlock:
+	mutex_unlock(&chip->mutex);
+
+	return ep;
+}
+
+/*
+ *  wait until all urbs are processed.
+ */
+static int wait_clear_urbs(struct snd_usb_endpoint *ep)
+{
+	unsigned long end_time = jiffies + msecs_to_jiffies(1000);
+	unsigned int i;
+	int alive;
+
+	do {
+		alive = 0;
+		for (i = 0; i < ep->nurbs; i++)
+			if (test_bit(i, &ep->active_mask))
+				alive++;
+
+		if (!alive)
+			break;
+
+		schedule_timeout_uninterruptible(1);
+	} while (time_before(jiffies, end_time));
+
+	if (alive)
+		snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n",
+					alive, ep->ep_num);
+
+	return 0;
+}
+
+/*
+ * unlink active urbs.
+ */
+static int deactivate_urbs(struct snd_usb_endpoint *ep, int force, int can_sleep)
+{
+	unsigned int i;
+	int async;
+
+	if (!force && ep->chip->shutdown) /* to be sure... */
+		return -EBADFD;
+
+	async = !can_sleep && ep->chip->async_unlink;
+
+	clear_bit(EP_FLAG_RUNNING, &ep->flags);
+
+	INIT_LIST_HEAD(&ep->ready_playback_urbs);
+	ep->next_packet_read_pos = 0;
+	ep->next_packet_write_pos = 0;
+
+	if (!async && in_interrupt())
+		return 0;
+
+	for (i = 0; i < ep->nurbs; i++) {
+		if (test_bit(i, &ep->active_mask)) {
+			if (!test_and_set_bit(i, &ep->unlink_mask)) {
+				struct urb *u = ep->urb[i].urb;
+				if (async)
+					usb_unlink_urb(u);
+				else
+					usb_kill_urb(u);
 			}
 		}
 	}
 
-	subs->active_mask = 0;
-	subs->unlink_mask = 0;
-	subs->running = 1;
-	for (i = 0; i < subs->nurbs; i++) {
-		err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
+	return 0;
+}
+
+/*
+ * release an endpoint's urbs
+ */
+static void release_urbs(struct snd_usb_endpoint *ep, int force)
+{
+	int i;
+
+	/* route incoming urbs to nirvana */
+	ep->retire_data_urb = NULL;
+	ep->prepare_data_urb = NULL;
+
+	/* stop urbs */
+	deactivate_urbs(ep, force, 1);
+	wait_clear_urbs(ep);
+
+	for (i = 0; i < ep->nurbs; i++)
+		release_urb_ctx(&ep->urb[i]);
+
+	if (ep->syncbuf)
+		usb_free_coherent(ep->chip->dev, SYNC_URBS * 4,
+				  ep->syncbuf, ep->sync_dma);
+
+	ep->syncbuf = NULL;
+	ep->nurbs = 0;
+}
+
+/*
+ * configure a data endpoint
+ */
+static int data_ep_set_params(struct snd_usb_endpoint *ep,
+			      struct snd_pcm_hw_params *hw_params,
+			      struct audioformat *fmt,
+			      struct snd_usb_endpoint *sync_ep)
+{
+	unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
+	int period_bytes = params_period_bytes(hw_params);
+	int format = params_format(hw_params);
+	int is_playback = usb_pipeout(ep->pipe);
+	int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) *
+							params_channels(hw_params);
+
+	ep->datainterval = fmt->datainterval;
+	ep->stride = frame_bits >> 3;
+	ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
+
+	/* calculate max. frequency */
+	if (ep->maxpacksize) {
+		/* whatever fits into a max. size packet */
+		maxsize = ep->maxpacksize;
+		ep->freqmax = (maxsize / (frame_bits >> 3))
+				<< (16 - ep->datainterval);
+	} else {
+		/* no max. packet size: just take 25% higher than nominal */
+		ep->freqmax = ep->freqn + (ep->freqn >> 2);
+		maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3))
+				>> (16 - ep->datainterval);
+	}
+
+	if (ep->fill_max)
+		ep->curpacksize = ep->maxpacksize;
+	else
+		ep->curpacksize = maxsize;
+
+	if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL)
+		packs_per_ms = 8 >> ep->datainterval;
+	else
+		packs_per_ms = 1;
+
+	if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+		urb_packs = max(ep->chip->nrpacks, 1);
+		urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
+	} else {
+		urb_packs = 1;
+	}
+
+	urb_packs *= packs_per_ms;
+
+	if (sync_ep && !snd_usb_endpoint_implict_feedback_sink(ep))
+		urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
+
+	/* decide how many packets to be used */
+	if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+		unsigned int minsize, maxpacks;
+		/* determine how small a packet can be */
+		minsize = (ep->freqn >> (16 - ep->datainterval))
+			  * (frame_bits >> 3);
+		/* with sync from device, assume it can be 12% lower */
+		if (sync_ep)
+			minsize -= minsize >> 3;
+		minsize = max(minsize, 1u);
+		total_packs = (period_bytes + minsize - 1) / minsize;
+		/* we need at least two URBs for queueing */
+		if (total_packs < 2) {
+			total_packs = 2;
+		} else {
+			/* and we don't want too long a queue either */
+			maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
+			total_packs = min(total_packs, maxpacks);
+		}
+	} else {
+		while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
+			urb_packs >>= 1;
+		total_packs = MAX_URBS * urb_packs;
+	}
+
+	ep->nurbs = (total_packs + urb_packs - 1) / urb_packs;
+	if (ep->nurbs > MAX_URBS) {
+		/* too much... */
+		ep->nurbs = MAX_URBS;
+		total_packs = MAX_URBS * urb_packs;
+	} else if (ep->nurbs < 2) {
+		/* too little - we need at least two packets
+		 * to ensure contiguous playback/capture
+		 */
+		ep->nurbs = 2;
+	}
+
+	/* allocate and initialize data urbs */
+	for (i = 0; i < ep->nurbs; i++) {
+		struct snd_urb_ctx *u = &ep->urb[i];
+		u->index = i;
+		u->ep = ep;
+		u->packets = (i + 1) * total_packs / ep->nurbs
+			- i * total_packs / ep->nurbs;
+		u->buffer_size = maxsize * u->packets;
+
+		if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
+			u->packets++; /* for transfer delimiter */
+		u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
+		if (!u->urb)
+			goto out_of_memory;
+
+		u->urb->transfer_buffer =
+			usb_alloc_coherent(ep->chip->dev, u->buffer_size,
+					   GFP_KERNEL, &u->urb->transfer_dma);
+		if (!u->urb->transfer_buffer)
+			goto out_of_memory;
+		u->urb->pipe = ep->pipe;
+		u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		u->urb->interval = 1 << ep->datainterval;
+		u->urb->context = u;
+		u->urb->complete = snd_complete_urb;
+		INIT_LIST_HEAD(&u->ready_list);
+	}
+
+	return 0;
+
+out_of_memory:
+	release_urbs(ep, 0);
+	return -ENOMEM;
+}
+
+/*
+ * configure a sync endpoint
+ */
+static int sync_ep_set_params(struct snd_usb_endpoint *ep,
+			      struct snd_pcm_hw_params *hw_params,
+			      struct audioformat *fmt)
+{
+	int i;
+
+	ep->syncbuf = usb_alloc_coherent(ep->chip->dev, SYNC_URBS * 4,
+					 GFP_KERNEL, &ep->sync_dma);
+	if (!ep->syncbuf)
+		return -ENOMEM;
+
+	for (i = 0; i < SYNC_URBS; i++) {
+		struct snd_urb_ctx *u = &ep->urb[i];
+		u->index = i;
+		u->ep = ep;
+		u->packets = 1;
+		u->urb = usb_alloc_urb(1, GFP_KERNEL);
+		if (!u->urb)
+			goto out_of_memory;
+		u->urb->transfer_buffer = ep->syncbuf + i * 4;
+		u->urb->transfer_dma = ep->sync_dma + i * 4;
+		u->urb->transfer_buffer_length = 4;
+		u->urb->pipe = ep->pipe;
+		u->urb->transfer_flags = URB_ISO_ASAP |
+					 URB_NO_TRANSFER_DMA_MAP;
+		u->urb->number_of_packets = 1;
+		u->urb->interval = 1 << ep->syncinterval;
+		u->urb->context = u;
+		u->urb->complete = snd_complete_urb;
+	}
+
+	ep->nurbs = SYNC_URBS;
+
+	return 0;
+
+out_of_memory:
+	release_urbs(ep, 0);
+	return -ENOMEM;
+}
+
+/**
+ * snd_usb_endpoint_set_params: configure an snd_usb_endpoint
+ *
+ * @ep: the snd_usb_endpoint to configure
+ * @hw_params: the hardware parameters
+ * @fmt: the USB audio format information
+ * @sync_ep: the sync endpoint to use, if any
+ *
+ * Determine the number of URBs to be used on this endpoint.
+ * An endpoint must be configured before it can be started.
+ * An endpoint that is already running can not be reconfigured.
+ */
+int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
+				struct snd_pcm_hw_params *hw_params,
+				struct audioformat *fmt,
+				struct snd_usb_endpoint *sync_ep)
+{
+	int err;
+
+	if (ep->use_count != 0) {
+		snd_printk(KERN_WARNING "Unable to change format on ep #%x: already in use\n",
+			   ep->ep_num);
+		return -EBUSY;
+	}
+
+	/* release old buffers, if any */
+	release_urbs(ep, 0);
+
+	ep->datainterval = fmt->datainterval;
+	ep->maxpacksize = fmt->maxpacksize;
+	ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX);
+
+	if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL)
+		ep->freqn = get_usb_full_speed_rate(params_rate(hw_params));
+	else
+		ep->freqn = get_usb_high_speed_rate(params_rate(hw_params));
+
+	/* calculate the frequency in 16.16 format */
+	ep->freqm = ep->freqn;
+	ep->freqshift = INT_MIN;
+
+	ep->phase = 0;
+
+	switch (ep->type) {
+	case  SND_USB_ENDPOINT_TYPE_DATA:
+		err = data_ep_set_params(ep, hw_params, fmt, sync_ep);
+		break;
+	case  SND_USB_ENDPOINT_TYPE_SYNC:
+		err = sync_ep_set_params(ep, hw_params, fmt);
+		break;
+	default:
+		err = -EINVAL;
+	}
+
+	snd_printdd(KERN_DEBUG "Setting params for ep #%x (type %d, %d urbs), ret=%d\n",
+		   ep->ep_num, ep->type, ep->nurbs, err);
+
+	return err;
+}
+
+/**
+ * snd_usb_endpoint_start: start an snd_usb_endpoint
+ *
+ * @ep: the endpoint to start
+ *
+ * A call to this function will increment the use count of the endpoint.
+ * In case it is not already running, the URBs for this endpoint will be
+ * submitted. Otherwise, this function does nothing.
+ *
+ * Must be balanced to calls of snd_usb_endpoint_stop().
+ *
+ * Returns an error if the URB submission failed, 0 in all other cases.
+ */
+int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
+{
+	int err;
+	unsigned int i;
+
+	if (ep->chip->shutdown)
+		return -EBADFD;
+
+	/* already running? */
+	if (++ep->use_count != 1)
+		return 0;
+
+	if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
+		return -EINVAL;
+
+	/* just to be sure */
+	deactivate_urbs(ep, 0, 1);
+	wait_clear_urbs(ep);
+
+	ep->active_mask = 0;
+	ep->unlink_mask = 0;
+	ep->phase = 0;
+
+	/*
+	 * If this endpoint has a data endpoint as implicit feedback source,
+	 * don't start the urbs here. Instead, mark them all as available,
+	 * wait for the record urbs to return and queue the playback urbs
+	 * from that context.
+	 */
+
+	set_bit(EP_FLAG_RUNNING, &ep->flags);
+
+	if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+		for (i = 0; i < ep->nurbs; i++) {
+			struct snd_urb_ctx *ctx = ep->urb + i;
+			list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
+		}
+
+		return 0;
+	}
+
+	for (i = 0; i < ep->nurbs; i++) {
+		struct urb *urb = ep->urb[i].urb;
+
+		if (snd_BUG_ON(!urb))
+			goto __error;
+
+		if (usb_pipeout(ep->pipe)) {
+			prepare_outbound_urb_sizes(ep, urb->context);
+			prepare_outbound_urb(ep, urb->context);
+		} else {
+			prepare_inbound_urb(ep, urb->context);
+		}
+
+		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (err < 0) {
-			snd_printk(KERN_ERR "cannot submit datapipe "
-				   "for urb %d, error %d: %s\n",
+			snd_printk(KERN_ERR "cannot submit urb %d, error %d: %s\n",
 				   i, err, usb_error_string(err));
 			goto __error;
 		}
-		set_bit(i, &subs->active_mask);
+		set_bit(i, &ep->active_mask);
 	}
-	if (subs->syncpipe) {
-		for (i = 0; i < SYNC_URBS; i++) {
-			err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC);
-			if (err < 0) {
-				snd_printk(KERN_ERR "cannot submit syncpipe "
-					   "for urb %d, error %d: %s\n",
-					   i, err, usb_error_string(err));
-				goto __error;
-			}
-			set_bit(i + 16, &subs->active_mask);
-		}
-	}
+
 	return 0;
 
- __error:
-	// snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
-	deactivate_urbs(subs, 0, 0);
+__error:
+	clear_bit(EP_FLAG_RUNNING, &ep->flags);
+	ep->use_count--;
+	deactivate_urbs(ep, 0, 0);
 	return -EPIPE;
 }
 
-
-/*
+/**
+ * snd_usb_endpoint_stop: stop an snd_usb_endpoint
+ *
+ * @ep: the endpoint to stop (may be NULL)
+ *
+ * A call to this function will decrement the use count of the endpoint.
+ * In case the last user has requested the endpoint stop, the URBs will
+ * actually be deactivated.
+ *
+ * Must be balanced to calls of snd_usb_endpoint_start().
  */
-static struct snd_urb_ops audio_urb_ops[2] = {
-	{
-		.prepare =	prepare_nodata_playback_urb,
-		.retire =	retire_playback_urb,
-		.prepare_sync =	prepare_playback_sync_urb,
-		.retire_sync =	retire_playback_sync_urb,
-	},
-	{
-		.prepare =	prepare_capture_urb,
-		.retire =	retire_capture_urb,
-		.prepare_sync =	prepare_capture_sync_urb,
-		.retire_sync =	retire_capture_sync_urb,
-	},
-};
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
+			   int force, int can_sleep, int wait)
+{
+	if (!ep)
+		return;
 
-/*
- * initialize the substream instance.
+	if (snd_BUG_ON(ep->use_count == 0))
+		return;
+
+	if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
+		return;
+
+	if (--ep->use_count == 0) {
+		deactivate_urbs(ep, force, can_sleep);
+		ep->data_subs = NULL;
+		ep->sync_slave = NULL;
+		ep->retire_data_urb = NULL;
+		ep->prepare_data_urb = NULL;
+
+		if (wait)
+			wait_clear_urbs(ep);
+	}
+}
+
+/**
+ * snd_usb_endpoint_activate: activate an snd_usb_endpoint
+ *
+ * @ep: the endpoint to activate
+ *
+ * If the endpoint is not currently in use, this functions will select the
+ * correct alternate interface setting for the interface of this endpoint.
+ *
+ * In case of any active users, this functions does nothing.
+ *
+ * Returns an error if usb_set_interface() failed, 0 in all other
+ * cases.
  */
-
-void snd_usb_init_substream(struct snd_usb_stream *as,
-			    int stream, struct audioformat *fp)
+int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep)
 {
-	struct snd_usb_substream *subs = &as->substream[stream];
-
-	INIT_LIST_HEAD(&subs->fmt_list);
-	spin_lock_init(&subs->lock);
-
-	subs->stream = as;
-	subs->direction = stream;
-	subs->dev = as->chip->dev;
-	subs->txfr_quirk = as->chip->txfr_quirk;
-	subs->ops = audio_urb_ops[stream];
-	if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH)
-		subs->ops.prepare_sync = prepare_capture_sync_urb_hs;
-
-	snd_usb_set_pcm_ops(as->pcm, stream);
-
-	list_add_tail(&fp->list, &subs->fmt_list);
-	subs->formats |= fp->formats;
-	subs->endpoint = fp->endpoint;
-	subs->num_formats++;
-	subs->fmt_type = fp->fmt_type;
-}
-
-int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct snd_usb_substream *subs = substream->runtime->private_data;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		subs->ops.prepare = prepare_playback_urb;
+	if (ep->use_count != 0)
 		return 0;
-	case SNDRV_PCM_TRIGGER_STOP:
-		return deactivate_urbs(subs, 0, 0);
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		subs->ops.prepare = prepare_nodata_playback_urb;
+
+	if (!ep->chip->shutdown &&
+	    !test_and_set_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
+		int ret;
+
+		ret = usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx);
+		if (ret < 0) {
+			snd_printk(KERN_ERR "%s() usb_set_interface() failed, ret = %d\n",
+						__func__, ret);
+			clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
+			return ret;
+		}
+
 		return 0;
 	}
 
-	return -EINVAL;
+	return -EBUSY;
 }
 
-int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+/**
+ * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint
+ *
+ * @ep: the endpoint to deactivate
+ *
+ * If the endpoint is not currently in use, this functions will select the
+ * alternate interface setting 0 for the interface of this endpoint.
+ *
+ * In case of any active users, this functions does nothing.
+ *
+ * Returns an error if usb_set_interface() failed, 0 in all other
+ * cases.
+ */
+int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
 {
-	struct snd_usb_substream *subs = substream->runtime->private_data;
+	if (!ep)
+		return -EINVAL;
 
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		subs->ops.retire = retire_capture_urb;
-		return start_urbs(subs, substream->runtime);
-	case SNDRV_PCM_TRIGGER_STOP:
-		return deactivate_urbs(subs, 0, 0);
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		subs->ops.retire = retire_paused_capture_urb;
+	if (ep->use_count != 0)
 		return 0;
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		subs->ops.retire = retire_capture_urb;
+
+	if (!ep->chip->shutdown &&
+	    test_and_clear_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
+		int ret;
+
+		ret = usb_set_interface(ep->chip->dev, ep->iface, 0);
+		if (ret < 0) {
+			snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
+						__func__, ret);
+			return ret;
+		}
+
 		return 0;
 	}
 
-	return -EINVAL;
+	return -EBUSY;
 }
 
-int snd_usb_substream_prepare(struct snd_usb_substream *subs,
-			      struct snd_pcm_runtime *runtime)
+/**
+ * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
+ *
+ * @ep: the list header of the endpoint to free
+ *
+ * This function does not care for the endpoint's use count but will tear
+ * down all the streaming URBs immediately and free all resources.
+ */
+void snd_usb_endpoint_free(struct list_head *head)
 {
-	/* clear urbs (to be sure) */
-	deactivate_urbs(subs, 0, 1);
-	wait_clear_urbs(subs);
+	struct snd_usb_endpoint *ep;
 
-	/* for playback, submit the URBs now; otherwise, the first hwptr_done
-	 * updates for all URBs would happen at the same time when starting */
-	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
-		subs->ops.prepare = prepare_nodata_playback_urb;
-		return start_urbs(subs, runtime);
+	ep = list_entry(head, struct snd_usb_endpoint, list);
+	release_urbs(ep, 1);
+	kfree(ep);
+}
+
+/**
+ * snd_usb_handle_sync_urb: parse an USB sync packet
+ *
+ * @ep: the endpoint to handle the packet
+ * @sender: the sending endpoint
+ * @urb: the received packet
+ *
+ * This function is called from the context of an endpoint that received
+ * the packet and is used to let another endpoint object handle the payload.
+ */
+void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
+			     struct snd_usb_endpoint *sender,
+			     const struct urb *urb)
+{
+	int shift;
+	unsigned int f;
+	unsigned long flags;
+
+	snd_BUG_ON(ep == sender);
+
+	/*
+	 * In case the endpoint is operating in implicit feedback mode, prepare
+	 * a new outbound URB that has the same layout as the received packet
+	 * and add it to the list of pending urbs. queue_pending_output_urbs()
+	 * will take care of them later.
+	 */
+	if (snd_usb_endpoint_implict_feedback_sink(ep) &&
+	    ep->use_count != 0) {
+
+		/* implicit feedback case */
+		int i, bytes = 0;
+		struct snd_urb_ctx *in_ctx;
+		struct snd_usb_packet_info *out_packet;
+
+		in_ctx = urb->context;
+
+		/* Count overall packet size */
+		for (i = 0; i < in_ctx->packets; i++)
+			if (urb->iso_frame_desc[i].status == 0)
+				bytes += urb->iso_frame_desc[i].actual_length;
+
+		/*
+		 * skip empty packets. At least M-Audio's Fast Track Ultra stops
+		 * streaming once it received a 0-byte OUT URB
+		 */
+		if (bytes == 0)
+			return;
+
+		spin_lock_irqsave(&ep->lock, flags);
+		out_packet = ep->next_packet + ep->next_packet_write_pos;
+
+		/*
+		 * Iterate through the inbound packet and prepare the lengths
+		 * for the output packet. The OUT packet we are about to send
+		 * will have the same amount of payload bytes than the IN
+		 * packet we just received.
+		 */
+
+		out_packet->packets = in_ctx->packets;
+		for (i = 0; i < in_ctx->packets; i++) {
+			if (urb->iso_frame_desc[i].status == 0)
+				out_packet->packet_size[i] =
+					urb->iso_frame_desc[i].actual_length / ep->stride;
+			else
+				out_packet->packet_size[i] = 0;
+		}
+
+		ep->next_packet_write_pos++;
+		ep->next_packet_write_pos %= MAX_URBS;
+		spin_unlock_irqrestore(&ep->lock, flags);
+		queue_pending_output_urbs(ep);
+
+		return;
 	}
 
-	return 0;
+	/*
+	 * process after playback sync complete
+	 *
+	 * Full speed devices report feedback values in 10.14 format as samples
+	 * per frame, high speed devices in 16.16 format as samples per
+	 * microframe.
+	 *
+	 * Because the Audio Class 1 spec was written before USB 2.0, many high
+	 * speed devices use a wrong interpretation, some others use an
+	 * entirely different format.
+	 *
+	 * Therefore, we cannot predict what format any particular device uses
+	 * and must detect it automatically.
+	 */
+
+	if (urb->iso_frame_desc[0].status != 0 ||
+	    urb->iso_frame_desc[0].actual_length < 3)
+		return;
+
+	f = le32_to_cpup(urb->transfer_buffer);
+	if (urb->iso_frame_desc[0].actual_length == 3)
+		f &= 0x00ffffff;
+	else
+		f &= 0x0fffffff;
+
+	if (f == 0)
+		return;
+
+	if (unlikely(ep->freqshift == INT_MIN)) {
+		/*
+		 * The first time we see a feedback value, determine its format
+		 * by shifting it left or right until it matches the nominal
+		 * frequency value.  This assumes that the feedback does not
+		 * differ from the nominal value more than +50% or -25%.
+		 */
+		shift = 0;
+		while (f < ep->freqn - ep->freqn / 4) {
+			f <<= 1;
+			shift++;
+		}
+		while (f > ep->freqn + ep->freqn / 2) {
+			f >>= 1;
+			shift--;
+		}
+		ep->freqshift = shift;
+	} else if (ep->freqshift >= 0)
+		f <<= ep->freqshift;
+	else
+		f >>= -ep->freqshift;
+
+	if (likely(f >= ep->freqn - ep->freqn / 8 && f <= ep->freqmax)) {
+		/*
+		 * If the frequency looks valid, set it.
+		 * This value is referred to in prepare_playback_urb().
+		 */
+		spin_lock_irqsave(&ep->lock, flags);
+		ep->freqm = f;
+		spin_unlock_irqrestore(&ep->lock, flags);
+	} else {
+		/*
+		 * Out of range; maybe the shift value is wrong.
+		 * Reset it so that we autodetect again the next time.
+		 */
+		ep->freqshift = INT_MIN;
+	}
 }
 
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 88eb63a..ee2723f 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -1,21 +1,29 @@
 #ifndef __USBAUDIO_ENDPOINT_H
 #define __USBAUDIO_ENDPOINT_H
 
-void snd_usb_init_substream(struct snd_usb_stream *as,
-			    int stream,
-			    struct audioformat *fp);
+#define SND_USB_ENDPOINT_TYPE_DATA     0
+#define SND_USB_ENDPOINT_TYPE_SYNC     1
 
-int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
-				unsigned int period_bytes,
-				unsigned int rate,
-				unsigned int frame_bits);
+struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
+					      struct usb_host_interface *alts,
+					      int ep_num, int direction, int type);
 
-void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force);
+int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
+				struct snd_pcm_hw_params *hw_params,
+				struct audioformat *fmt,
+				struct snd_usb_endpoint *sync_ep);
 
-int snd_usb_substream_prepare(struct snd_usb_substream *subs,
-			      struct snd_pcm_runtime *runtime);
+int  snd_usb_endpoint_start(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
+			   int force, int can_sleep, int wait);
+int  snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
+int  snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_free(struct list_head *head);
 
-int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
-int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
+int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
+
+void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
+			     struct snd_usb_endpoint *sender,
+			     const struct urb *urb);
 
 #endif /* __USBAUDIO_ENDPOINT_H */
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index ab23869..4f40ba8 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -486,7 +486,7 @@
 /*
  * TLV callback for mixer volume controls
  */
-static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 			 unsigned int size, unsigned int __user *_tlv)
 {
 	struct usb_mixer_elem_info *cval = kcontrol->private_data;
@@ -770,6 +770,26 @@
 				  struct snd_kcontrol *kctl)
 {
 	switch (cval->mixer->chip->usb_id) {
+	case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
+	case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
+		if (strcmp(kctl->id.name, "Effect Duration") == 0) {
+			snd_printk(KERN_INFO
+				"usb-audio: set quirk for FTU Effect Duration\n");
+			cval->min = 0x0000;
+			cval->max = 0x7f00;
+			cval->res = 0x0100;
+			break;
+		}
+		if (strcmp(kctl->id.name, "Effect Volume") == 0 ||
+		    strcmp(kctl->id.name, "Effect Feedback Volume") == 0) {
+			snd_printk(KERN_INFO
+				"usb-audio: set quirks for FTU Effect Feedback/Volume\n");
+			cval->min = 0x00;
+			cval->max = 0x7f;
+			break;
+		}
+		break;
+
 	case USB_ID(0x0471, 0x0101):
 	case USB_ID(0x0471, 0x0104):
 	case USB_ID(0x0471, 0x0105):
@@ -1121,9 +1141,6 @@
 		len = snd_usb_copy_string_desc(state, nameid,
 				kctl->id.name, sizeof(kctl->id.name));
 
-	/* get min/max values */
-	get_min_max_with_quirks(cval, 0, kctl);
-
 	switch (control) {
 	case UAC_FU_MUTE:
 	case UAC_FU_VOLUME:
@@ -1155,17 +1172,7 @@
 		}
 		append_ctl_name(kctl, control == UAC_FU_MUTE ?
 				" Switch" : " Volume");
-		if (control == UAC_FU_VOLUME) {
-			check_mapped_dB(map, cval);
-			if (cval->dBmin < cval->dBmax || !cval->initialized) {
-				kctl->tlv.c = mixer_vol_tlv;
-				kctl->vd[0].access |= 
-					SNDRV_CTL_ELEM_ACCESS_TLV_READ |
-					SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
-			}
-		}
 		break;
-
 	default:
 		if (! len)
 			strlcpy(kctl->id.name, audio_feature_info[control-1].name,
@@ -1173,6 +1180,19 @@
 		break;
 	}
 
+	/* get min/max values */
+	get_min_max_with_quirks(cval, 0, kctl);
+
+	if (control == UAC_FU_VOLUME) {
+		check_mapped_dB(map, cval);
+		if (cval->dBmin < cval->dBmax || !cval->initialized) {
+			kctl->tlv.c = snd_usb_mixer_vol_tlv;
+			kctl->vd[0].access |=
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+				SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+		}
+	}
+
 	range = (cval->max - cval->min) / cval->res;
 	/* Are there devices with volume range more than 255? I use a bit more
 	 * to be sure. 384 is a resolution magic number found on Logitech
@@ -1388,7 +1408,7 @@
 	for (pin = 0; pin < input_pins; pin++) {
 		err = parse_audio_unit(state, desc->baSourceID[pin]);
 		if (err < 0)
-			return err;
+			continue;
 		err = check_input_term(state, desc->baSourceID[pin], &iterm);
 		if (err < 0)
 			return err;
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 81b2d8a..a7f3d45 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -68,4 +68,7 @@
 int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
 			      struct snd_kcontrol *kctl);
 
+int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+			  unsigned int size, unsigned int __user *_tlv);
+
 #endif /* __USBMIXER_H */
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index f1324c4..41daaa2 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -288,6 +288,15 @@
 	{ 0 } /* terminator */
 };
 
+static struct usbmix_name_map ebox44_map[] = {
+	{ 4, NULL }, /* FU */
+	{ 6, NULL }, /* MU */
+	{ 7, NULL }, /* FU */
+	{ 10, NULL }, /* FU */
+	{ 11, NULL }, /* MU */
+	{ 0 }
+};
+
 /* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+"
  *  most importand difference is SU[8], it should be set to "Capture Source"
  *  to make alsamixer and PA working properly.
@@ -371,6 +380,10 @@
 		.map = scratch_live_map,
 		.ignore_ctl_error = 1,
 	},
+	{
+		.id = USB_ID(0x200c, 0x1018),
+		.map = ebox44_map,
+	},
 	{ 0 } /* terminator */
 };
 
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index ab125ee..41f4b69 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -42,6 +42,77 @@
 
 extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
 
+/* private_free callback */
+static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
+{
+	kfree(kctl->private_data);
+	kctl->private_data = NULL;
+}
+
+/* This function allows for the creation of standard UAC controls.
+ * See the quirks for M-Audio FTUs or Ebox-44.
+ * If you don't want to set a TLV callback pass NULL.
+ *
+ * Since there doesn't seem to be a devices that needs a multichannel
+ * version, we keep it mono for simplicity.
+ */
+static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
+				unsigned int unitid,
+				unsigned int control,
+				unsigned int cmask,
+				int val_type,
+				const char *name,
+				snd_kcontrol_tlv_rw_t *tlv_callback)
+{
+	int err;
+	struct usb_mixer_elem_info *cval;
+	struct snd_kcontrol *kctl;
+
+	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
+	if (!cval)
+		return -ENOMEM;
+
+	cval->id = unitid;
+	cval->mixer = mixer;
+	cval->val_type = val_type;
+	cval->channels = 1;
+	cval->control = control;
+	cval->cmask = cmask;
+
+	/* get_min_max() is called only for integer volumes later,
+	 * so provide a short-cut for booleans */
+	cval->min = 0;
+	cval->max = 1;
+	cval->res = 0;
+	cval->dBmin = 0;
+	cval->dBmax = 0;
+
+	/* Create control */
+	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
+	if (!kctl) {
+		kfree(cval);
+		return -ENOMEM;
+	}
+
+	/* Set name */
+	snprintf(kctl->id.name, sizeof(kctl->id.name), name);
+	kctl->private_free = usb_mixer_elem_free;
+
+	/* set TLV */
+	if (tlv_callback) {
+		kctl->tlv.c = tlv_callback;
+		kctl->vd[0].access |=
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+	}
+	/* Add control to mixer */
+	err = snd_usb_mixer_add_control(mixer, kctl);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
 /*
  * Sound Blaster remote control configuration
  *
@@ -495,60 +566,218 @@
 }
 
 /* M-Audio FastTrack Ultra quirks */
+/* FTU Effect switch */
+struct snd_ftu_eff_switch_priv_val {
+	struct usb_mixer_interface *mixer;
+	int cached_value;
+	int is_cached;
+};
 
-/* private_free callback */
-static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
+static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
 {
-	kfree(kctl->private_data);
-	kctl->private_data = NULL;
+	static const char *texts[8] = {"Room 1",
+				       "Room 2",
+				       "Room 3",
+				       "Hall 1",
+				       "Hall 2",
+				       "Plate",
+				       "Delay",
+				       "Echo"
+	};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 8;
+	if (uinfo->value.enumerated.item > 7)
+		uinfo->value.enumerated.item = 7;
+	strcpy(uinfo->value.enumerated.name,
+		texts[uinfo->value.enumerated.item]);
+
+	return 0;
 }
 
-static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
-				     int in, int out, const char *name)
+static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
+					struct snd_ctl_elem_value *ucontrol)
 {
-	struct usb_mixer_elem_info *cval;
-	struct snd_kcontrol *kctl;
+	struct snd_usb_audio *chip;
+	struct usb_mixer_interface *mixer;
+	struct snd_ftu_eff_switch_priv_val *pval;
+	int err;
+	unsigned char value[2];
 
-	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
-	if (!cval)
+	const int id = 6;
+	const int validx = 1;
+	const int val_len = 2;
+
+	value[0] = 0x00;
+	value[1] = 0x00;
+
+	pval = (struct snd_ftu_eff_switch_priv_val *)
+		kctl->private_value;
+
+	if (pval->is_cached) {
+		ucontrol->value.enumerated.item[0] = pval->cached_value;
+		return 0;
+	}
+
+	mixer = (struct usb_mixer_interface *) pval->mixer;
+	if (snd_BUG_ON(!mixer))
+		return -EINVAL;
+
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (snd_BUG_ON(!chip))
+		return -EINVAL;
+
+
+	err = snd_usb_ctl_msg(chip->dev,
+			usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
+			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+			validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+			value, val_len);
+	if (err < 0)
+		return err;
+
+	ucontrol->value.enumerated.item[0] = value[0];
+	pval->cached_value = value[0];
+	pval->is_cached = 1;
+
+	return 0;
+}
+
+static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_usb_audio *chip;
+	struct snd_ftu_eff_switch_priv_val *pval;
+
+	struct usb_mixer_interface *mixer;
+	int changed, cur_val, err, new_val;
+	unsigned char value[2];
+
+
+	const int id = 6;
+	const int validx = 1;
+	const int val_len = 2;
+
+	changed = 0;
+
+	pval = (struct snd_ftu_eff_switch_priv_val *)
+		kctl->private_value;
+	cur_val = pval->cached_value;
+	new_val = ucontrol->value.enumerated.item[0];
+
+	mixer = (struct usb_mixer_interface *) pval->mixer;
+	if (snd_BUG_ON(!mixer))
+		return -EINVAL;
+
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (snd_BUG_ON(!chip))
+		return -EINVAL;
+
+	if (!pval->is_cached) {
+		/* Read current value */
+		err = snd_usb_ctl_msg(chip->dev,
+				usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
+				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+				value, val_len);
+		if (err < 0)
+			return err;
+
+		cur_val = value[0];
+		pval->cached_value = cur_val;
+		pval->is_cached = 1;
+	}
+	/* update value if needed */
+	if (cur_val != new_val) {
+		value[0] = new_val;
+		value[1] = 0;
+		err = snd_usb_ctl_msg(chip->dev,
+				usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
+				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+				value, val_len);
+		if (err < 0)
+			return err;
+
+		pval->cached_value = new_val;
+		pval->is_cached = 1;
+		changed = 1;
+	}
+
+	return changed;
+}
+
+static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer)
+{
+	static struct snd_kcontrol_new template = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Effect Program Switch",
+		.index = 0,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = snd_ftu_eff_switch_info,
+		.get = snd_ftu_eff_switch_get,
+		.put = snd_ftu_eff_switch_put
+	};
+
+	int err;
+	struct snd_kcontrol *kctl;
+	struct snd_ftu_eff_switch_priv_val *pval;
+
+	pval = kzalloc(sizeof(*pval), GFP_KERNEL);
+	if (!pval)
 		return -ENOMEM;
 
-	cval->id = 5;
-	cval->mixer = mixer;
-	cval->val_type = USB_MIXER_S16;
-	cval->channels = 1;
-	cval->control = out + 1;
-	cval->cmask = 1 << in;
+	pval->cached_value = 0;
+	pval->is_cached = 0;
+	pval->mixer = mixer;
 
-	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
+	template.private_value = (unsigned long) pval;
+	kctl = snd_ctl_new1(&template, mixer->chip);
 	if (!kctl) {
-		kfree(cval);
+		kfree(pval);
 		return -ENOMEM;
 	}
 
-	snprintf(kctl->id.name, sizeof(kctl->id.name), name);
-	kctl->private_free = usb_mixer_elem_free;
-	return snd_usb_mixer_add_control(mixer, kctl);
+	err = snd_ctl_add(mixer->chip->card, kctl);
+	if (err < 0)
+		return err;
+
+	return 0;
 }
 
-static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+/* Create volume controls for FTU devices*/
+static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
 {
 	char name[64];
+	unsigned int control, cmask;
 	int in, out, err;
 
+	const unsigned int id = 5;
+	const int val_type = USB_MIXER_S16;
+
 	for (out = 0; out < 8; out++) {
+		control = out + 1;
 		for (in = 0; in < 8; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
-				 "AIn%d - Out%d Capture Volume", in  + 1, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+				"AIn%d - Out%d Capture Volume",
+				in  + 1, out + 1);
+			err = snd_create_std_mono_ctl(mixer, id, control,
+							cmask, val_type, name,
+							&snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
-
 		for (in = 8; in < 16; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
-				 "DIn%d - Out%d Playback Volume", in - 7, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+				"DIn%d - Out%d Playback Volume",
+				in - 7, out + 1);
+			err = snd_create_std_mono_ctl(mixer, id, control,
+							cmask, val_type, name,
+							&snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
@@ -557,6 +786,191 @@
 	return 0;
 }
 
+/* This control needs a volume quirk, see mixer.c */
+static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
+{
+	static const char name[] = "Effect Volume";
+	const unsigned int id = 6;
+	const int val_type = USB_MIXER_U8;
+	const unsigned int control = 2;
+	const unsigned int cmask = 0;
+
+	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
+					name, snd_usb_mixer_vol_tlv);
+}
+
+/* This control needs a volume quirk, see mixer.c */
+static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
+{
+	static const char name[] = "Effect Duration";
+	const unsigned int id = 6;
+	const int val_type = USB_MIXER_S16;
+	const unsigned int control = 3;
+	const unsigned int cmask = 0;
+
+	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
+					name, snd_usb_mixer_vol_tlv);
+}
+
+/* This control needs a volume quirk, see mixer.c */
+static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
+{
+	static const char name[] = "Effect Feedback Volume";
+	const unsigned int id = 6;
+	const int val_type = USB_MIXER_U8;
+	const unsigned int control = 4;
+	const unsigned int cmask = 0;
+
+	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
+					name, NULL);
+}
+
+static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int cmask;
+	int err, ch;
+	char name[48];
+
+	const unsigned int id = 7;
+	const int val_type = USB_MIXER_S16;
+	const unsigned int control = 7;
+
+	for (ch = 0; ch < 4; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Return %d Volume", ch + 1);
+		err = snd_create_std_mono_ctl(mixer, id, control,
+						cmask, val_type, name,
+						snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int  cmask;
+	int err, ch;
+	char name[48];
+
+	const unsigned int id = 5;
+	const int val_type = USB_MIXER_S16;
+	const unsigned int control = 9;
+
+	for (ch = 0; ch < 8; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Send AIn%d Volume", ch + 1);
+		err = snd_create_std_mono_ctl(mixer, id, control, cmask,
+						val_type, name,
+						snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+	for (ch = 8; ch < 16; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Send DIn%d Volume", ch - 7);
+		err = snd_create_std_mono_ctl(mixer, id, control, cmask,
+						val_type, name,
+						snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer)
+{
+	int err;
+
+	err = snd_ftu_create_volume_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_ftu_create_effect_switch(mixer);
+	if (err < 0)
+		return err;
+	err = snd_ftu_create_effect_volume_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_ftu_create_effect_duration_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_ftu_create_effect_feedback_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_ftu_create_effect_return_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_ftu_create_effect_send_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+
+/*
+ * Create mixer for Electrix Ebox-44
+ *
+ * The mixer units from this device are corrupt, and even where they
+ * are valid they presents mono controls as L and R channels of
+ * stereo. So we create a good mixer in code.
+ */
+
+static int snd_ebox44_create_mixer(struct usb_mixer_interface *mixer)
+{
+	int err;
+
+	err = snd_create_std_mono_ctl(mixer, 4, 1, 0x0, USB_MIXER_INV_BOOLEAN,
+				"Headphone Playback Switch", NULL);
+	if (err < 0)
+		return err;
+	err = snd_create_std_mono_ctl(mixer, 4, 2, 0x1, USB_MIXER_S16,
+				"Headphone A Mix Playback Volume", NULL);
+	if (err < 0)
+		return err;
+	err = snd_create_std_mono_ctl(mixer, 4, 2, 0x2, USB_MIXER_S16,
+				"Headphone B Mix Playback Volume", NULL);
+	if (err < 0)
+		return err;
+
+	err = snd_create_std_mono_ctl(mixer, 7, 1, 0x0, USB_MIXER_INV_BOOLEAN,
+				"Output Playback Switch", NULL);
+	if (err < 0)
+		return err;
+	err = snd_create_std_mono_ctl(mixer, 7, 2, 0x1, USB_MIXER_S16,
+				"Output A Playback Volume", NULL);
+	if (err < 0)
+		return err;
+	err = snd_create_std_mono_ctl(mixer, 7, 2, 0x2, USB_MIXER_S16,
+				"Output B Playback Volume", NULL);
+	if (err < 0)
+		return err;
+
+	err = snd_create_std_mono_ctl(mixer, 10, 1, 0x0, USB_MIXER_INV_BOOLEAN,
+				"Input Capture Switch", NULL);
+	if (err < 0)
+		return err;
+	err = snd_create_std_mono_ctl(mixer, 10, 2, 0x1, USB_MIXER_S16,
+				"Input A Capture Volume", NULL);
+	if (err < 0)
+		return err;
+	err = snd_create_std_mono_ctl(mixer, 10, 2, 0x2, USB_MIXER_S16,
+				"Input B Capture Volume", NULL);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
 void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
 			       unsigned char samplerate_id)
 {
@@ -600,7 +1014,7 @@
 
 	case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
 	case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
-		err = snd_maudio_ftu_create_mixer(mixer);
+		err = snd_ftu_create_mixer(mixer);
 		break;
 
 	case USB_ID(0x0b05, 0x1739):
@@ -619,6 +1033,10 @@
 				snd_nativeinstruments_ta10_mixers,
 				ARRAY_SIZE(snd_nativeinstruments_ta10_mixers));
 		break;
+
+	case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */
+		err = snd_ebox44_create_mixer(mixer);
+		break;
 	}
 
 	return err;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 0eed611..24839d9 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/audio-v2.h>
@@ -34,6 +35,9 @@
 #include "clock.h"
 #include "power.h"
 
+#define SUBSTREAM_FLAG_DATA_EP_STARTED	0
+#define SUBSTREAM_FLAG_SYNC_EP_STARTED	1
+
 /* return the estimated delay based on USB frame counters */
 snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
 				    unsigned int rate)
@@ -208,6 +212,84 @@
 	}
 }
 
+static int start_endpoints(struct snd_usb_substream *subs)
+{
+	int err;
+
+	if (!subs->data_endpoint)
+		return -EINVAL;
+
+	if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
+		struct snd_usb_endpoint *ep = subs->data_endpoint;
+
+		snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep);
+
+		ep->data_subs = subs;
+		err = snd_usb_endpoint_start(ep);
+		if (err < 0) {
+			clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags);
+			return err;
+		}
+	}
+
+	if (subs->sync_endpoint &&
+	    !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
+		struct snd_usb_endpoint *ep = subs->sync_endpoint;
+
+		snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep);
+
+		ep->sync_slave = subs->data_endpoint;
+		err = snd_usb_endpoint_start(ep);
+		if (err < 0) {
+			clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static void stop_endpoints(struct snd_usb_substream *subs,
+			   int force, int can_sleep, int wait)
+{
+	if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags))
+		snd_usb_endpoint_stop(subs->sync_endpoint,
+				      force, can_sleep, wait);
+
+	if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags))
+		snd_usb_endpoint_stop(subs->data_endpoint,
+				      force, can_sleep, wait);
+}
+
+static int activate_endpoints(struct snd_usb_substream *subs)
+{
+	if (subs->sync_endpoint) {
+		int ret;
+
+		ret = snd_usb_endpoint_activate(subs->sync_endpoint);
+		if (ret < 0)
+			return ret;
+	}
+
+	return snd_usb_endpoint_activate(subs->data_endpoint);
+}
+
+static int deactivate_endpoints(struct snd_usb_substream *subs)
+{
+	int reta, retb;
+
+	reta = snd_usb_endpoint_deactivate(subs->sync_endpoint);
+	retb = snd_usb_endpoint_deactivate(subs->data_endpoint);
+
+	if (reta < 0)
+		return reta;
+
+	if (retb < 0)
+		return retb;
+
+	return 0;
+}
+
 /*
  * find a matching format and set up the interface
  */
@@ -219,7 +301,7 @@
 	struct usb_interface *iface;
 	unsigned int ep, attr;
 	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-	int err;
+	int err, implicit_fb = 0;
 
 	iface = usb_ifnum_to_if(dev, fmt->iface);
 	if (WARN_ON(!iface))
@@ -232,40 +314,11 @@
 	if (fmt == subs->cur_audiofmt)
 		return 0;
 
-	/* close the old interface */
-	if (subs->interface >= 0 && subs->interface != fmt->iface) {
-		if (usb_set_interface(subs->dev, subs->interface, 0) < 0) {
-			snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n",
-				dev->devnum, fmt->iface, fmt->altsetting);
-			return -EIO;
-		}
-		subs->interface = -1;
-		subs->altset_idx = 0;
-	}
-
-	/* set interface */
-	if (subs->interface != fmt->iface || subs->altset_idx != fmt->altset_idx) {
-		if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) {
-			snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
-				   dev->devnum, fmt->iface, fmt->altsetting);
-			return -EIO;
-		}
-		snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting);
-		subs->interface = fmt->iface;
-		subs->altset_idx = fmt->altset_idx;
-	}
-
-	/* create a data pipe */
-	ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK;
-	if (is_playback)
-		subs->datapipe = usb_sndisocpipe(dev, ep);
-	else
-		subs->datapipe = usb_rcvisocpipe(dev, ep);
-	subs->datainterval = fmt->datainterval;
-	subs->syncpipe = subs->syncinterval = 0;
-	subs->maxpacksize = fmt->maxpacksize;
-	subs->syncmaxsize = 0;
-	subs->fill_max = 0;
+	subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+						   alts, fmt->endpoint, subs->direction,
+						   SND_USB_ENDPOINT_TYPE_DATA);
+	if (!subs->data_endpoint)
+		return -EINVAL;
 
 	/* we need a sync pipe in async OUT or adaptive IN mode */
 	/* check the number of EP, since some devices have broken
@@ -273,8 +326,25 @@
 	 * assume it as adaptive-out or sync-in.
 	 */
 	attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
+
+	switch (subs->stream->chip->usb_id) {
+	case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
+	case USB_ID(0x0763, 0x2081):
+		if (is_playback) {
+			implicit_fb = 1;
+			ep = 0x81;
+			iface = usb_ifnum_to_if(dev, 2);
+
+			if (!iface || iface->num_altsetting == 0)
+				return -EINVAL;
+
+			alts = &iface->altsetting[1];
+			goto add_sync_ep;
+		}
+	}
+
 	if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
-	     (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
+	     (!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
 	    altsd->bNumEndpoints >= 2) {
 		/* check sync-pipe endpoint */
 		/* ... and check descriptor size before accessing bSynchAddress
@@ -282,7 +352,8 @@
 		   the audio fields in the endpoint descriptors */
 		if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 ||
 		    (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
-		     get_endpoint(alts, 1)->bSynchAddress != 0)) {
+		     get_endpoint(alts, 1)->bSynchAddress != 0 &&
+		     !implicit_fb)) {
 			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
 				   dev->devnum, fmt->iface, fmt->altsetting);
 			return -EINVAL;
@@ -290,33 +361,27 @@
 		ep = get_endpoint(alts, 1)->bEndpointAddress;
 		if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
 		    (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
-		     (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
+		     (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)) ||
+		     ( is_playback && !implicit_fb))) {
 			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
 				   dev->devnum, fmt->iface, fmt->altsetting);
 			return -EINVAL;
 		}
-		ep &= USB_ENDPOINT_NUMBER_MASK;
-		if (is_playback)
-			subs->syncpipe = usb_rcvisocpipe(dev, ep);
-		else
-			subs->syncpipe = usb_sndisocpipe(dev, ep);
-		if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
-		    get_endpoint(alts, 1)->bRefresh >= 1 &&
-		    get_endpoint(alts, 1)->bRefresh <= 9)
-			subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
-		else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
-			subs->syncinterval = 1;
-		else if (get_endpoint(alts, 1)->bInterval >= 1 &&
-			 get_endpoint(alts, 1)->bInterval <= 16)
-			subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
-		else
-			subs->syncinterval = 3;
-		subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
-	}
 
-	/* always fill max packet size */
-	if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)
-		subs->fill_max = 1;
+		implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
+				== USB_ENDPOINT_USAGE_IMPLICIT_FB;
+
+add_sync_ep:
+		subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+							   alts, ep, !subs->direction,
+							   implicit_fb ?
+								SND_USB_ENDPOINT_TYPE_DATA :
+								SND_USB_ENDPOINT_TYPE_SYNC);
+		if (!subs->sync_endpoint)
+			return -EINVAL;
+
+		subs->data_endpoint->sync_master = subs->sync_endpoint;
+	}
 
 	if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
 		return err;
@@ -390,15 +455,30 @@
 	if (changed) {
 		mutex_lock(&subs->stream->chip->shutdown_mutex);
 		/* format changed */
-		snd_usb_release_substream_urbs(subs, 0);
-		/* influenced: period_bytes, channels, rate, format, */
-		ret = snd_usb_init_substream_urbs(subs, params_period_bytes(hw_params),
-						  params_rate(hw_params),
-						  snd_pcm_format_physical_width(params_format(hw_params)) *
-							params_channels(hw_params));
+		stop_endpoints(subs, 0, 0, 0);
+		deactivate_endpoints(subs);
+
+		ret = activate_endpoints(subs);
+		if (ret < 0)
+			goto unlock;
+
+		ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
+						  subs->sync_endpoint);
+		if (ret < 0)
+			goto unlock;
+
+		if (subs->sync_endpoint)
+			ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
+							  hw_params, fmt, NULL);
+unlock:
 		mutex_unlock(&subs->stream->chip->shutdown_mutex);
 	}
 
+	if (ret == 0) {
+		subs->interface = fmt->iface;
+		subs->altset_idx = fmt->altset_idx;
+	}
+
 	return ret;
 }
 
@@ -415,7 +495,7 @@
 	subs->cur_rate = 0;
 	subs->period_bytes = 0;
 	mutex_lock(&subs->stream->chip->shutdown_mutex);
-	snd_usb_release_substream_urbs(subs, 0);
+	stop_endpoints(subs, 0, 1, 1);
 	mutex_unlock(&subs->stream->chip->shutdown_mutex);
 	return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
@@ -435,19 +515,28 @@
 		return -ENXIO;
 	}
 
+	if (snd_BUG_ON(!subs->data_endpoint))
+		return -EIO;
+
 	/* some unit conversions in runtime */
-	subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
-	subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
+	subs->data_endpoint->maxframesize =
+		bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);
+	subs->data_endpoint->curframesize =
+		bytes_to_frames(runtime, subs->data_endpoint->curpacksize);
 
 	/* reset the pointer */
 	subs->hwptr_done = 0;
 	subs->transfer_done = 0;
-	subs->phase = 0;
 	subs->last_delay = 0;
 	subs->last_frame_number = 0;
 	runtime->delay = 0;
 
-	return snd_usb_substream_prepare(subs, runtime);
+	/* for playback, submit the URBs now; otherwise, the first hwptr_done
+	 * updates for all URBs would happen at the same time when starting */
+	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
+		return start_endpoints(subs);
+
+	return 0;
 }
 
 static struct snd_pcm_hardware snd_usb_hardware =
@@ -842,16 +931,171 @@
 
 static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
 {
+	int ret;
 	struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
 	struct snd_usb_substream *subs = &as->substream[direction];
 
-	if (!as->chip->shutdown && subs->interface >= 0) {
-		usb_set_interface(subs->dev, subs->interface, 0);
-		subs->interface = -1;
-	}
+	stop_endpoints(subs, 0, 0, 0);
+	ret = deactivate_endpoints(subs);
 	subs->pcm_substream = NULL;
 	snd_usb_autosuspend(subs->stream->chip);
-	return 0;
+
+	return ret;
+}
+
+/* Since a URB can handle only a single linear buffer, we must use double
+ * buffering when the data to be transferred overflows the buffer boundary.
+ * To avoid inconsistencies when updating hwptr_done, we use double buffering
+ * for all URBs.
+ */
+static void retire_capture_urb(struct snd_usb_substream *subs,
+			       struct urb *urb)
+{
+	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+	unsigned int stride, frames, bytes, oldptr;
+	int i, period_elapsed = 0;
+	unsigned long flags;
+	unsigned char *cp;
+
+	stride = runtime->frame_bits >> 3;
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
+			snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
+			// continue;
+		}
+		bytes = urb->iso_frame_desc[i].actual_length;
+		frames = bytes / stride;
+		if (!subs->txfr_quirk)
+			bytes = frames * stride;
+		if (bytes % (runtime->sample_bits >> 3) != 0) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+			int oldbytes = bytes;
+#endif
+			bytes = frames * stride;
+			snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
+							oldbytes, bytes);
+		}
+		/* update the current pointer */
+		spin_lock_irqsave(&subs->lock, flags);
+		oldptr = subs->hwptr_done;
+		subs->hwptr_done += bytes;
+		if (subs->hwptr_done >= runtime->buffer_size * stride)
+			subs->hwptr_done -= runtime->buffer_size * stride;
+		frames = (bytes + (oldptr % stride)) / stride;
+		subs->transfer_done += frames;
+		if (subs->transfer_done >= runtime->period_size) {
+			subs->transfer_done -= runtime->period_size;
+			period_elapsed = 1;
+		}
+		spin_unlock_irqrestore(&subs->lock, flags);
+		/* copy a data chunk */
+		if (oldptr + bytes > runtime->buffer_size * stride) {
+			unsigned int bytes1 =
+					runtime->buffer_size * stride - oldptr;
+			memcpy(runtime->dma_area + oldptr, cp, bytes1);
+			memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
+		} else {
+			memcpy(runtime->dma_area + oldptr, cp, bytes);
+		}
+	}
+
+	if (period_elapsed)
+		snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
+static void prepare_playback_urb(struct snd_usb_substream *subs,
+				 struct urb *urb)
+{
+	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+	struct snd_urb_ctx *ctx = urb->context;
+	unsigned int counts, frames, bytes;
+	int i, stride, period_elapsed = 0;
+	unsigned long flags;
+
+	stride = runtime->frame_bits >> 3;
+
+	frames = 0;
+	urb->number_of_packets = 0;
+	spin_lock_irqsave(&subs->lock, flags);
+	for (i = 0; i < ctx->packets; i++) {
+		counts = ctx->packet_size[i];
+		/* set up descriptor */
+		urb->iso_frame_desc[i].offset = frames * stride;
+		urb->iso_frame_desc[i].length = counts * stride;
+		frames += counts;
+		urb->number_of_packets++;
+		subs->transfer_done += counts;
+		if (subs->transfer_done >= runtime->period_size) {
+			subs->transfer_done -= runtime->period_size;
+			period_elapsed = 1;
+			if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
+				if (subs->transfer_done > 0) {
+					/* FIXME: fill-max mode is not
+					 * supported yet */
+					frames -= subs->transfer_done;
+					counts -= subs->transfer_done;
+					urb->iso_frame_desc[i].length =
+						counts * stride;
+					subs->transfer_done = 0;
+				}
+				i++;
+				if (i < ctx->packets) {
+					/* add a transfer delimiter */
+					urb->iso_frame_desc[i].offset =
+						frames * stride;
+					urb->iso_frame_desc[i].length = 0;
+					urb->number_of_packets++;
+				}
+				break;
+			}
+		}
+		if (period_elapsed &&
+		    !snd_usb_endpoint_implict_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
+			break;
+	}
+	bytes = frames * stride;
+	if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
+		/* err, the transferred area goes over buffer boundary. */
+		unsigned int bytes1 =
+			runtime->buffer_size * stride - subs->hwptr_done;
+		memcpy(urb->transfer_buffer,
+		       runtime->dma_area + subs->hwptr_done, bytes1);
+		memcpy(urb->transfer_buffer + bytes1,
+		       runtime->dma_area, bytes - bytes1);
+	} else {
+		memcpy(urb->transfer_buffer,
+		       runtime->dma_area + subs->hwptr_done, bytes);
+	}
+	subs->hwptr_done += bytes;
+	if (subs->hwptr_done >= runtime->buffer_size * stride)
+		subs->hwptr_done -= runtime->buffer_size * stride;
+	runtime->delay += frames;
+	spin_unlock_irqrestore(&subs->lock, flags);
+	urb->transfer_buffer_length = bytes;
+	if (period_elapsed)
+		snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
+/*
+ * process after playback data complete
+ * - decrease the delay count again
+ */
+static void retire_playback_urb(struct snd_usb_substream *subs,
+			       struct urb *urb)
+{
+	unsigned long flags;
+	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+	int stride = runtime->frame_bits >> 3;
+	int processed = urb->transfer_buffer_length / stride;
+
+	spin_lock_irqsave(&subs->lock, flags);
+	if (processed > runtime->delay)
+		runtime->delay = 0;
+	else
+		runtime->delay -= processed;
+	spin_unlock_irqrestore(&subs->lock, flags);
 }
 
 static int snd_usb_playback_open(struct snd_pcm_substream *substream)
@@ -874,6 +1118,63 @@
 	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE);
 }
 
+static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream,
+					      int cmd)
+{
+	struct snd_usb_substream *subs = substream->runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
+		subs->data_endpoint->retire_data_urb = retire_playback_urb;
+		subs->running = 1;
+		return 0;
+	case SNDRV_PCM_TRIGGER_STOP:
+		stop_endpoints(subs, 0, 0, 0);
+		subs->running = 0;
+		return 0;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		subs->data_endpoint->prepare_data_urb = NULL;
+		subs->data_endpoint->retire_data_urb = NULL;
+		subs->running = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int err;
+	struct snd_usb_substream *subs = substream->runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err = start_endpoints(subs);
+		if (err < 0)
+			return err;
+
+		subs->data_endpoint->retire_data_urb = retire_capture_urb;
+		subs->running = 1;
+		return 0;
+	case SNDRV_PCM_TRIGGER_STOP:
+		stop_endpoints(subs, 0, 0, 0);
+		subs->running = 0;
+		return 0;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		subs->data_endpoint->retire_data_urb = NULL;
+		subs->running = 0;
+		return 0;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		subs->data_endpoint->retire_data_urb = retire_capture_urb;
+		subs->running = 1;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static struct snd_pcm_ops snd_usb_playback_ops = {
 	.open =		snd_usb_playback_open,
 	.close =	snd_usb_playback_close,
diff --git a/sound/usb/proc.c b/sound/usb/proc.c
index 961c9a2..ebc1a5b 100644
--- a/sound/usb/proc.c
+++ b/sound/usb/proc.c
@@ -25,6 +25,7 @@
 #include "usbaudio.h"
 #include "helper.h"
 #include "card.h"
+#include "endpoint.h"
 #include "proc.h"
 
 /* convert our full speed USB rate into sampling rate in Hz */
@@ -115,28 +116,33 @@
 	}
 }
 
+static void proc_dump_ep_status(struct snd_usb_substream *subs,
+				struct snd_usb_endpoint *ep,
+				struct snd_info_buffer *buffer)
+{
+	if (!ep)
+		return;
+	snd_iprintf(buffer, "    Packet Size = %d\n", ep->curpacksize);
+	snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n",
+		    snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
+		    ? get_full_speed_hz(ep->freqm)
+		    : get_high_speed_hz(ep->freqm),
+		    ep->freqm >> 16, ep->freqm & 0xffff);
+	if (ep->freqshift != INT_MIN) {
+		int res = 16 - ep->freqshift;
+		snd_iprintf(buffer, "    Feedback Format = %d.%d\n",
+			    (ep->syncmaxsize > 3 ? 32 : 24) - res, res);
+	}
+}
+
 static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
 {
 	if (subs->running) {
-		unsigned int i;
 		snd_iprintf(buffer, "  Status: Running\n");
 		snd_iprintf(buffer, "    Interface = %d\n", subs->interface);
 		snd_iprintf(buffer, "    Altset = %d\n", subs->altset_idx);
-		snd_iprintf(buffer, "    URBs = %d [ ", subs->nurbs);
-		for (i = 0; i < subs->nurbs; i++)
-			snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
-		snd_iprintf(buffer, "]\n");
-		snd_iprintf(buffer, "    Packet Size = %d\n", subs->curpacksize);
-		snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n",
-			    snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
-			    ? get_full_speed_hz(subs->freqm)
-			    : get_high_speed_hz(subs->freqm),
-			    subs->freqm >> 16, subs->freqm & 0xffff);
-		if (subs->freqshift != INT_MIN)
-			snd_iprintf(buffer, "    Feedback Format = %d.%d\n",
-				    (subs->syncmaxsize > 3 ? 32 : 24)
-						- (16 - subs->freqshift),
-				    16 - subs->freqshift);
+		proc_dump_ep_status(subs, subs->data_endpoint, buffer);
+		proc_dump_ep_status(subs, subs->sync_endpoint, buffer);
 	} else {
 		snd_iprintf(buffer, "  Status: Stop\n");
 	}
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 5ff8010..6b7d7a2 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -73,6 +73,31 @@
 	}
 }
 
+/*
+ * initialize the substream instance.
+ */
+
+static void snd_usb_init_substream(struct snd_usb_stream *as,
+				   int stream,
+				   struct audioformat *fp)
+{
+	struct snd_usb_substream *subs = &as->substream[stream];
+
+	INIT_LIST_HEAD(&subs->fmt_list);
+	spin_lock_init(&subs->lock);
+
+	subs->stream = as;
+	subs->direction = stream;
+	subs->dev = as->chip->dev;
+	subs->txfr_quirk = as->chip->txfr_quirk;
+
+	snd_usb_set_pcm_ops(as->pcm, stream);
+
+	list_add_tail(&fp->list, &subs->fmt_list);
+	subs->formats |= fp->formats;
+	subs->num_formats++;
+	subs->fmt_type = fp->fmt_type;
+}
 
 /*
  * add this endpoint to the chip instance.
@@ -94,9 +119,9 @@
 		if (as->fmt_type != fp->fmt_type)
 			continue;
 		subs = &as->substream[stream];
-		if (!subs->endpoint)
+		if (!subs->data_endpoint)
 			continue;
-		if (subs->endpoint == fp->endpoint) {
+		if (subs->data_endpoint->ep_num == fp->endpoint) {
 			list_add_tail(&fp->list, &subs->fmt_list);
 			subs->num_formats++;
 			subs->formats |= fp->formats;
@@ -109,7 +134,7 @@
 		if (as->fmt_type != fp->fmt_type)
 			continue;
 		subs = &as->substream[stream];
-		if (subs->endpoint)
+		if (subs->data_endpoint)
 			continue;
 		err = snd_pcm_new_stream(as->pcm, stream, 1);
 		if (err < 0)
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 3e2b035..b8233eb 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -36,6 +36,7 @@
 	struct snd_card *card;
 	struct usb_interface *pm_intf;
 	u32 usb_id;
+	struct mutex mutex;
 	struct mutex shutdown_mutex;
 	unsigned int shutdown:1;
 	unsigned int probing:1;
@@ -46,6 +47,7 @@
 	int num_suspended_intf;
 
 	struct list_head pcm_list;	/* list of pcm streams */
+	struct list_head ep_list;	/* list of audio-related endpoints */
 	int pcm_devs;
 
 	struct list_head midi_list;	/* list of midi interfaces */
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 0000000..3ae4394
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,77 @@
+include scripts/Makefile.include
+
+help:
+	@echo 'Possible targets:'
+	@echo ''
+	@echo '  cpupower   - a tool for all things x86 CPU power'
+	@echo '  firewire   - the userspace part of nosy, an IEEE-1394 traffic sniffer'
+	@echo '  lguest     - a minimal 32-bit x86 hypervisor'
+	@echo '  perf       - Linux performance measurement and analysis tool'
+	@echo '  selftests  - various kernel selftests'
+	@echo '  turbostat  - Intel CPU idle stats and freq reporting tool'
+	@echo '  usb        - USB testing tools'
+	@echo '  virtio     - vhost test module'
+	@echo '  vm         - misc vm tools'
+	@echo '  x86_energy_perf_policy - Intel energy policy tool'
+	@echo ''
+	@echo 'You can do:'
+	@echo ' $$ make -C tools/<tool>_install'
+	@echo ''
+	@echo '  from the kernel command line to build and install one of'
+	@echo '  the tools above'
+	@echo ''
+	@echo '  $$ make tools/install'
+	@echo ''
+	@echo '  installs all tools.'
+	@echo ''
+	@echo 'Cleaning targets:'
+	@echo ''
+	@echo '  all of the above with the "_clean" string appended cleans'
+	@echo '    the respective build directory.'
+	@echo '  clean: a summary clean target to clean _all_ folders'
+
+cpupower: FORCE
+	$(QUIET_SUBDIR0)power/$@/ $(QUIET_SUBDIR1)
+
+firewire lguest perf usb virtio vm: FORCE
+	$(QUIET_SUBDIR0)$@/ $(QUIET_SUBDIR1)
+
+selftests: FORCE
+	$(QUIET_SUBDIR0)testing/$@/ $(QUIET_SUBDIR1)
+
+turbostat x86_energy_perf_policy: FORCE
+	$(QUIET_SUBDIR0)power/x86/$@/ $(QUIET_SUBDIR1)
+
+cpupower_install:
+	$(QUIET_SUBDIR0)power/$(@:_install=)/ $(QUIET_SUBDIR1) install
+
+firewire_install lguest_install perf_install usb_install virtio_install vm_install:
+	$(QUIET_SUBDIR0)$(@:_install=)/ $(QUIET_SUBDIR1) install
+
+selftests_install:
+	$(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) install
+
+turbostat_install x86_energy_perf_policy_install:
+	$(QUIET_SUBDIR0)power/x86/$(@:_install=)/ $(QUIET_SUBDIR1) install
+
+install: cpupower_install firewire_install lguest_install perf_install \
+		selftests_install turbostat_install usb_install virtio_install \
+		vm_install x86_energy_perf_policy_install
+
+cpupower_clean:
+	$(QUIET_SUBDIR0)power/cpupower/ $(QUIET_SUBDIR1) clean
+
+firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean:
+	$(QUIET_SUBDIR0)$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+
+selftests_clean:
+	$(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+
+turbostat_clean x86_energy_perf_policy_clean:
+	$(QUIET_SUBDIR0)power/x86/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+
+clean: cpupower_clean firewire_clean lguest_clean perf_clean selftests_clean \
+		turbostat_clean usb_clean virtio_clean vm_clean \
+		x86_energy_perf_policy_clean
+
+.PHONY: FORCE
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
new file mode 100644
index 0000000..3d69aa9
--- /dev/null
+++ b/tools/lib/traceevent/Makefile
@@ -0,0 +1,303 @@
+# trace-cmd version
+EP_VERSION = 1
+EP_PATCHLEVEL = 1
+EP_EXTRAVERSION = 0
+
+# file format version
+FILE_VERSION = 6
+
+MAKEFLAGS += --no-print-directory
+
+
+# Makefiles suck: This macro sets a default value of $(2) for the
+# variable named by $(1), unless the variable has been set by
+# environment or command line. This is necessary for CC and AR
+# because make sets default values, so the simpler ?= approach
+# won't work as expected.
+define allow-override
+  $(if $(or $(findstring environment,$(origin $(1))),\
+            $(findstring command line,$(origin $(1)))),,\
+    $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+
+EXT = -std=gnu99
+INSTALL = install
+
+# Use DESTDIR for installing into a different root directory.
+# This is useful for building a package. The program will be
+# installed in this directory as if it was the root directory.
+# Then the build tool can move it later.
+DESTDIR ?=
+DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
+
+prefix ?= /usr/local
+bindir_relative = bin
+bindir = $(prefix)/$(bindir_relative)
+man_dir = $(prefix)/share/man
+man_dir_SQ = '$(subst ','\'',$(man_dir))'
+html_install = $(prefix)/share/kernelshark/html
+html_install_SQ = '$(subst ','\'',$(html_install))'
+img_install = $(prefix)/share/kernelshark/html/images
+img_install_SQ = '$(subst ','\'',$(img_install))'
+
+export man_dir man_dir_SQ html_install html_install_SQ INSTALL
+export img_install img_install_SQ
+export DESTDIR DESTDIR_SQ
+
+# copy a bit from Linux kbuild
+
+ifeq ("$(origin V)", "command line")
+  VERBOSE = $(V)
+endif
+ifndef VERBOSE
+  VERBOSE = 0
+endif
+
+ifeq ("$(origin O)", "command line")
+  BUILD_OUTPUT := $(O)
+endif
+
+ifeq ($(BUILD_SRC),)
+ifneq ($(BUILD_OUTPUT),)
+
+define build_output
+	$(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) 	\
+	BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
+endef
+
+saved-output := $(BUILD_OUTPUT)
+BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
+$(if $(BUILD_OUTPUT),, \
+     $(error output directory "$(saved-output)" does not exist))
+
+all: sub-make
+
+gui: force
+	$(call build_output, all_cmd)
+
+$(filter-out gui,$(MAKECMDGOALS)): sub-make
+
+sub-make: force
+	$(call build_output, $(MAKECMDGOALS))
+
+
+# Leave processing to above invocation of make
+skip-makefile := 1
+
+endif # BUILD_OUTPUT
+endif # BUILD_SRC
+
+# We process the rest of the Makefile if this is the final invocation of make
+ifeq ($(skip-makefile),)
+
+srctree		:= $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
+objtree		:= $(CURDIR)
+src		:= $(srctree)
+obj		:= $(objtree)
+
+export prefix bindir src obj
+
+# Shell quotes
+bindir_SQ = $(subst ','\'',$(bindir))
+bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
+
+LIB_FILE = libtraceevent.a libtraceevent.so
+
+CONFIG_INCLUDES = 
+CONFIG_LIBS	=
+CONFIG_FLAGS	=
+
+VERSION		= $(EP_VERSION)
+PATCHLEVEL	= $(EP_PATCHLEVEL)
+EXTRAVERSION	= $(EP_EXTRAVERSION)
+
+OBJ		= $@
+N		=
+
+export Q VERBOSE
+
+EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
+
+INCLUDES = -I. -I/usr/local/include $(CONFIG_INCLUDES)
+
+# Set compile option CFLAGS if not set elsewhere
+CFLAGS ?= -g -Wall
+
+# Append required CFLAGS
+override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
+override CFLAGS += $(udis86-flags)
+
+ifeq ($(VERBOSE),1)
+  Q =
+  print_compile =
+  print_app_build =
+  print_fpic_compile =
+  print_shared_lib_compile =
+  print_plugin_obj_compile =
+  print_plugin_build =
+  print_install =
+else
+  Q = @
+  print_compile =		echo '  CC                 '$(OBJ);
+  print_app_build =		echo '  BUILD              '$(OBJ);
+  print_fpic_compile =		echo '  CC FPIC            '$(OBJ);
+  print_shared_lib_compile =	echo '  BUILD SHARED LIB   '$(OBJ);
+  print_plugin_obj_compile =	echo '  CC PLUGIN OBJ      '$(OBJ);
+  print_plugin_build =		echo '  CC PLUGI           '$(OBJ);
+  print_static_lib_build =	echo '  BUILD STATIC LIB   '$(OBJ);
+  print_install =		echo '  INSTALL     '$1'	to	$(DESTDIR_SQ)$2';
+endif
+
+do_fpic_compile =					\
+	($(print_fpic_compile)				\
+	$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
+
+do_app_build =						\
+	($(print_app_build)				\
+	$(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
+
+do_compile_shared_library =			\
+	($(print_shared_lib_compile)		\
+	$(CC) --shared $^ -o $@)
+
+do_compile_plugin_obj =				\
+	($(print_plugin_obj_compile)		\
+	$(CC) -c $(CFLAGS) -fPIC -o $@ $<)
+
+do_plugin_build =				\
+	($(print_plugin_build)			\
+	$(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<)
+
+do_build_static_lib =				\
+	($(print_static_lib_build)		\
+	$(RM) $@;  $(AR) rcs $@ $^)
+
+
+define do_compile
+	$(print_compile)						\
+	$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
+endef
+
+$(obj)/%.o: $(src)/%.c
+	$(Q)$(call do_compile)
+
+%.o: $(src)/%.c
+	$(Q)$(call do_compile)
+
+PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
+
+ALL_OBJS = $(PEVENT_LIB_OBJS)
+
+CMD_TARGETS = $(LIB_FILE)
+
+TARGETS = $(CMD_TARGETS)
+
+
+all: all_cmd
+
+all_cmd: $(CMD_TARGETS)
+
+libtraceevent.so: $(PEVENT_LIB_OBJS)
+	$(Q)$(do_compile_shared_library)
+
+libtraceevent.a: $(PEVENT_LIB_OBJS)
+	$(Q)$(do_build_static_lib)
+
+$(PEVENT_LIB_OBJS): %.o: $(src)/%.c
+	$(Q)$(do_fpic_compile)
+
+define make_version.h
+	(echo '/* This file is automatically generated. Do not modify. */';		\
+	echo \#define VERSION_CODE $(shell						\
+	expr $(VERSION) \* 256 + $(PATCHLEVEL));					\
+	echo '#define EXTRAVERSION ' $(EXTRAVERSION);					\
+	echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"';	\
+	echo '#define FILE_VERSION '$(FILE_VERSION);					\
+	) > $1
+endef
+
+define update_version.h
+	($(call make_version.h, $@.tmp);		\
+	if [ -r $@ ] && cmp -s $@ $@.tmp; then		\
+		rm -f $@.tmp;				\
+	else						\
+		echo '  UPDATE                 $@';	\
+		mv -f $@.tmp $@;			\
+	fi);
+endef
+
+ep_version.h: force
+	$(Q)$(N)$(call update_version.h)
+
+VERSION_FILES = ep_version.h
+
+define update_dir
+	(echo $1 > $@.tmp;	\
+	if [ -r $@ ] && cmp -s $@ $@.tmp; then		\
+		rm -f $@.tmp;				\
+	else						\
+		echo '  UPDATE                 $@';	\
+		mv -f $@.tmp $@;			\
+	fi);
+endef
+
+## make deps
+
+all_objs := $(sort $(ALL_OBJS))
+all_deps := $(all_objs:%.o=.%.d)
+
+define check_deps
+		$(CC) -M $(CFLAGS) $< > $@;
+endef
+
+$(gui_deps): ks_version.h
+$(non_gui_deps): tc_version.h
+
+$(all_deps): .%.d: $(src)/%.c
+	$(Q)$(call check_deps)
+
+$(all_objs) : %.o : .%.d
+
+dep_includes := $(wildcard $(all_deps))
+
+ifneq ($(dep_includes),)
+ include $(dep_includes)
+endif
+
+tags:	force
+	$(RM) tags
+	find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px
+
+TAGS:	force
+	$(RM) TAGS
+	find . -name '*.[ch]' | xargs etags
+
+define do_install
+	$(print_install)				\
+	if [ ! -d '$(DESTDIR_SQ)$2' ]; then		\
+		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2';	\
+	fi;						\
+	$(INSTALL) $1 '$(DESTDIR_SQ)$2'
+endef
+
+install_lib: all_cmd install_plugins install_python
+	$(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
+
+install: install_lib
+
+clean:
+	$(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES).*.d
+	$(RM) tags TAGS
+
+endif # skip-makefile
+
+PHONY += force
+force:
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable so we can use it in if_changed and friends.
+.PHONY: $(PHONY)
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
new file mode 100644
index 0000000..9985349
--- /dev/null
+++ b/tools/lib/traceevent/event-parse.c
@@ -0,0 +1,5065 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  The parts for function graph printing was taken and modified from the
+ *  Linux Kernel that were written by
+ *    - Copyright (C) 2009  Frederic Weisbecker,
+ *  Frederic Weisbecker gave his permission to relicense the code to
+ *  the Lesser General Public License.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+static const char *input_buf;
+static unsigned long long input_buf_ptr;
+static unsigned long long input_buf_siz;
+
+static int is_flag_field;
+static int is_symbolic_field;
+
+static int show_warning = 1;
+
+#define do_warning(fmt, ...)				\
+	do {						\
+		if (show_warning)			\
+			warning(fmt, ##__VA_ARGS__);	\
+	} while (0)
+
+static void init_input_buf(const char *buf, unsigned long long size)
+{
+	input_buf = buf;
+	input_buf_siz = size;
+	input_buf_ptr = 0;
+}
+
+const char *pevent_get_input_buf(void)
+{
+	return input_buf;
+}
+
+unsigned long long pevent_get_input_buf_ptr(void)
+{
+	return input_buf_ptr;
+}
+
+struct event_handler {
+	struct event_handler		*next;
+	int				id;
+	const char			*sys_name;
+	const char			*event_name;
+	pevent_event_handler_func	func;
+	void				*context;
+};
+
+struct pevent_func_params {
+	struct pevent_func_params	*next;
+	enum pevent_func_arg_type	type;
+};
+
+struct pevent_function_handler {
+	struct pevent_function_handler	*next;
+	enum pevent_func_arg_type	ret_type;
+	char				*name;
+	pevent_func_handler		func;
+	struct pevent_func_params	*params;
+	int				nr_args;
+};
+
+static unsigned long long
+process_defined_func(struct trace_seq *s, void *data, int size,
+		     struct event_format *event, struct print_arg *arg);
+
+static void free_func_handle(struct pevent_function_handler *func);
+
+/**
+ * pevent_buffer_init - init buffer for parsing
+ * @buf: buffer to parse
+ * @size: the size of the buffer
+ *
+ * For use with pevent_read_token(), this initializes the internal
+ * buffer that pevent_read_token() will parse.
+ */
+void pevent_buffer_init(const char *buf, unsigned long long size)
+{
+	init_input_buf(buf, size);
+}
+
+void breakpoint(void)
+{
+	static int x;
+	x++;
+}
+
+struct print_arg *alloc_arg(void)
+{
+	struct print_arg *arg;
+
+	arg = malloc_or_die(sizeof(*arg));
+	if (!arg)
+		return NULL;
+	memset(arg, 0, sizeof(*arg));
+
+	return arg;
+}
+
+struct cmdline {
+	char *comm;
+	int pid;
+};
+
+static int cmdline_cmp(const void *a, const void *b)
+{
+	const struct cmdline *ca = a;
+	const struct cmdline *cb = b;
+
+	if (ca->pid < cb->pid)
+		return -1;
+	if (ca->pid > cb->pid)
+		return 1;
+
+	return 0;
+}
+
+struct cmdline_list {
+	struct cmdline_list	*next;
+	char			*comm;
+	int			pid;
+};
+
+static int cmdline_init(struct pevent *pevent)
+{
+	struct cmdline_list *cmdlist = pevent->cmdlist;
+	struct cmdline_list *item;
+	struct cmdline *cmdlines;
+	int i;
+
+	cmdlines = malloc_or_die(sizeof(*cmdlines) * pevent->cmdline_count);
+
+	i = 0;
+	while (cmdlist) {
+		cmdlines[i].pid = cmdlist->pid;
+		cmdlines[i].comm = cmdlist->comm;
+		i++;
+		item = cmdlist;
+		cmdlist = cmdlist->next;
+		free(item);
+	}
+
+	qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
+
+	pevent->cmdlines = cmdlines;
+	pevent->cmdlist = NULL;
+
+	return 0;
+}
+
+static char *find_cmdline(struct pevent *pevent, int pid)
+{
+	const struct cmdline *comm;
+	struct cmdline key;
+
+	if (!pid)
+		return "<idle>";
+
+	if (!pevent->cmdlines)
+		cmdline_init(pevent);
+
+	key.pid = pid;
+
+	comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+		       sizeof(*pevent->cmdlines), cmdline_cmp);
+
+	if (comm)
+		return comm->comm;
+	return "<...>";
+}
+
+/**
+ * pevent_pid_is_registered - return if a pid has a cmdline registered
+ * @pevent: handle for the pevent
+ * @pid: The pid to check if it has a cmdline registered with.
+ *
+ * Returns 1 if the pid has a cmdline mapped to it
+ * 0 otherwise.
+ */
+int pevent_pid_is_registered(struct pevent *pevent, int pid)
+{
+	const struct cmdline *comm;
+	struct cmdline key;
+
+	if (!pid)
+		return 1;
+
+	if (!pevent->cmdlines)
+		cmdline_init(pevent);
+
+	key.pid = pid;
+
+	comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+		       sizeof(*pevent->cmdlines), cmdline_cmp);
+
+	if (comm)
+		return 1;
+	return 0;
+}
+
+/*
+ * If the command lines have been converted to an array, then
+ * we must add this pid. This is much slower than when cmdlines
+ * are added before the array is initialized.
+ */
+static int add_new_comm(struct pevent *pevent, const char *comm, int pid)
+{
+	struct cmdline *cmdlines = pevent->cmdlines;
+	const struct cmdline *cmdline;
+	struct cmdline key;
+
+	if (!pid)
+		return 0;
+
+	/* avoid duplicates */
+	key.pid = pid;
+
+	cmdline = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+		       sizeof(*pevent->cmdlines), cmdline_cmp);
+	if (cmdline) {
+		errno = EEXIST;
+		return -1;
+	}
+
+	cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (pevent->cmdline_count + 1));
+	if (!cmdlines) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	cmdlines[pevent->cmdline_count].pid = pid;
+	cmdlines[pevent->cmdline_count].comm = strdup(comm);
+	if (!cmdlines[pevent->cmdline_count].comm)
+		die("malloc comm");
+		
+	if (cmdlines[pevent->cmdline_count].comm)
+		pevent->cmdline_count++;
+
+	qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
+	pevent->cmdlines = cmdlines;
+
+	return 0;
+}
+
+/**
+ * pevent_register_comm - register a pid / comm mapping
+ * @pevent: handle for the pevent
+ * @comm: the command line to register
+ * @pid: the pid to map the command line to
+ *
+ * This adds a mapping to search for command line names with
+ * a given pid. The comm is duplicated.
+ */
+int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
+{
+	struct cmdline_list *item;
+
+	if (pevent->cmdlines)
+		return add_new_comm(pevent, comm, pid);
+
+	item = malloc_or_die(sizeof(*item));
+	item->comm = strdup(comm);
+	if (!item->comm)
+		die("malloc comm");
+	item->pid = pid;
+	item->next = pevent->cmdlist;
+
+	pevent->cmdlist = item;
+	pevent->cmdline_count++;
+
+	return 0;
+}
+
+struct func_map {
+	unsigned long long		addr;
+	char				*func;
+	char				*mod;
+};
+
+struct func_list {
+	struct func_list	*next;
+	unsigned long long	addr;
+	char			*func;
+	char			*mod;
+};
+
+static int func_cmp(const void *a, const void *b)
+{
+	const struct func_map *fa = a;
+	const struct func_map *fb = b;
+
+	if (fa->addr < fb->addr)
+		return -1;
+	if (fa->addr > fb->addr)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * We are searching for a record in between, not an exact
+ * match.
+ */
+static int func_bcmp(const void *a, const void *b)
+{
+	const struct func_map *fa = a;
+	const struct func_map *fb = b;
+
+	if ((fa->addr == fb->addr) ||
+
+	    (fa->addr > fb->addr &&
+	     fa->addr < (fb+1)->addr))
+		return 0;
+
+	if (fa->addr < fb->addr)
+		return -1;
+
+	return 1;
+}
+
+static int func_map_init(struct pevent *pevent)
+{
+	struct func_list *funclist;
+	struct func_list *item;
+	struct func_map *func_map;
+	int i;
+
+	func_map = malloc_or_die(sizeof(*func_map) * (pevent->func_count + 1));
+	funclist = pevent->funclist;
+
+	i = 0;
+	while (funclist) {
+		func_map[i].func = funclist->func;
+		func_map[i].addr = funclist->addr;
+		func_map[i].mod = funclist->mod;
+		i++;
+		item = funclist;
+		funclist = funclist->next;
+		free(item);
+	}
+
+	qsort(func_map, pevent->func_count, sizeof(*func_map), func_cmp);
+
+	/*
+	 * Add a special record at the end.
+	 */
+	func_map[pevent->func_count].func = NULL;
+	func_map[pevent->func_count].addr = 0;
+	func_map[pevent->func_count].mod = NULL;
+
+	pevent->func_map = func_map;
+	pevent->funclist = NULL;
+
+	return 0;
+}
+
+static struct func_map *
+find_func(struct pevent *pevent, unsigned long long addr)
+{
+	struct func_map *func;
+	struct func_map key;
+
+	if (!pevent->func_map)
+		func_map_init(pevent);
+
+	key.addr = addr;
+
+	func = bsearch(&key, pevent->func_map, pevent->func_count,
+		       sizeof(*pevent->func_map), func_bcmp);
+
+	return func;
+}
+
+/**
+ * pevent_find_function - find a function by a given address
+ * @pevent: handle for the pevent
+ * @addr: the address to find the function with
+ *
+ * Returns a pointer to the function stored that has the given
+ * address. Note, the address does not have to be exact, it
+ * will select the function that would contain the address.
+ */
+const char *pevent_find_function(struct pevent *pevent, unsigned long long addr)
+{
+	struct func_map *map;
+
+	map = find_func(pevent, addr);
+	if (!map)
+		return NULL;
+
+	return map->func;
+}
+
+/**
+ * pevent_find_function_address - find a function address by a given address
+ * @pevent: handle for the pevent
+ * @addr: the address to find the function with
+ *
+ * Returns the address the function starts at. This can be used in
+ * conjunction with pevent_find_function to print both the function
+ * name and the function offset.
+ */
+unsigned long long
+pevent_find_function_address(struct pevent *pevent, unsigned long long addr)
+{
+	struct func_map *map;
+
+	map = find_func(pevent, addr);
+	if (!map)
+		return 0;
+
+	return map->addr;
+}
+
+/**
+ * pevent_register_function - register a function with a given address
+ * @pevent: handle for the pevent
+ * @function: the function name to register
+ * @addr: the address the function starts at
+ * @mod: the kernel module the function may be in (NULL for none)
+ *
+ * This registers a function name with an address and module.
+ * The @func passed in is duplicated.
+ */
+int pevent_register_function(struct pevent *pevent, char *func,
+			     unsigned long long addr, char *mod)
+{
+	struct func_list *item;
+
+	item = malloc_or_die(sizeof(*item));
+
+	item->next = pevent->funclist;
+	item->func = strdup(func);
+	if (mod)
+		item->mod = strdup(mod);
+	else
+		item->mod = NULL;
+	item->addr = addr;
+
+	pevent->funclist = item;
+
+	pevent->func_count++;
+
+	return 0;
+}
+
+/**
+ * pevent_print_funcs - print out the stored functions
+ * @pevent: handle for the pevent
+ *
+ * This prints out the stored functions.
+ */
+void pevent_print_funcs(struct pevent *pevent)
+{
+	int i;
+
+	if (!pevent->func_map)
+		func_map_init(pevent);
+
+	for (i = 0; i < (int)pevent->func_count; i++) {
+		printf("%016llx %s",
+		       pevent->func_map[i].addr,
+		       pevent->func_map[i].func);
+		if (pevent->func_map[i].mod)
+			printf(" [%s]\n", pevent->func_map[i].mod);
+		else
+			printf("\n");
+	}
+}
+
+struct printk_map {
+	unsigned long long		addr;
+	char				*printk;
+};
+
+struct printk_list {
+	struct printk_list	*next;
+	unsigned long long	addr;
+	char			*printk;
+};
+
+static int printk_cmp(const void *a, const void *b)
+{
+	const struct func_map *fa = a;
+	const struct func_map *fb = b;
+
+	if (fa->addr < fb->addr)
+		return -1;
+	if (fa->addr > fb->addr)
+		return 1;
+
+	return 0;
+}
+
+static void printk_map_init(struct pevent *pevent)
+{
+	struct printk_list *printklist;
+	struct printk_list *item;
+	struct printk_map *printk_map;
+	int i;
+
+	printk_map = malloc_or_die(sizeof(*printk_map) * (pevent->printk_count + 1));
+
+	printklist = pevent->printklist;
+
+	i = 0;
+	while (printklist) {
+		printk_map[i].printk = printklist->printk;
+		printk_map[i].addr = printklist->addr;
+		i++;
+		item = printklist;
+		printklist = printklist->next;
+		free(item);
+	}
+
+	qsort(printk_map, pevent->printk_count, sizeof(*printk_map), printk_cmp);
+
+	pevent->printk_map = printk_map;
+	pevent->printklist = NULL;
+}
+
+static struct printk_map *
+find_printk(struct pevent *pevent, unsigned long long addr)
+{
+	struct printk_map *printk;
+	struct printk_map key;
+
+	if (!pevent->printk_map)
+		printk_map_init(pevent);
+
+	key.addr = addr;
+
+	printk = bsearch(&key, pevent->printk_map, pevent->printk_count,
+			 sizeof(*pevent->printk_map), printk_cmp);
+
+	return printk;
+}
+
+/**
+ * pevent_register_print_string - register a string by its address
+ * @pevent: handle for the pevent
+ * @fmt: the string format to register
+ * @addr: the address the string was located at
+ *
+ * This registers a string by the address it was stored in the kernel.
+ * The @fmt passed in is duplicated.
+ */
+int pevent_register_print_string(struct pevent *pevent, char *fmt,
+				 unsigned long long addr)
+{
+	struct printk_list *item;
+
+	item = malloc_or_die(sizeof(*item));
+
+	item->next = pevent->printklist;
+	pevent->printklist = item;
+	item->printk = strdup(fmt);
+	item->addr = addr;
+
+	pevent->printk_count++;
+
+	return 0;
+}
+
+/**
+ * pevent_print_printk - print out the stored strings
+ * @pevent: handle for the pevent
+ *
+ * This prints the string formats that were stored.
+ */
+void pevent_print_printk(struct pevent *pevent)
+{
+	int i;
+
+	if (!pevent->printk_map)
+		printk_map_init(pevent);
+
+	for (i = 0; i < (int)pevent->printk_count; i++) {
+		printf("%016llx %s\n",
+		       pevent->printk_map[i].addr,
+		       pevent->printk_map[i].printk);
+	}
+}
+
+static struct event_format *alloc_event(void)
+{
+	struct event_format *event;
+
+	event = malloc_or_die(sizeof(*event));
+	memset(event, 0, sizeof(*event));
+
+	return event;
+}
+
+static void add_event(struct pevent *pevent, struct event_format *event)
+{
+	int i;
+
+	if (!pevent->events)
+		pevent->events = malloc_or_die(sizeof(event));
+	else
+		pevent->events =
+			realloc(pevent->events, sizeof(event) *
+				(pevent->nr_events + 1));
+	if (!pevent->events)
+		die("Can not allocate events");
+
+	for (i = 0; i < pevent->nr_events; i++) {
+		if (pevent->events[i]->id > event->id)
+			break;
+	}
+	if (i < pevent->nr_events)
+		memmove(&pevent->events[i + 1],
+			&pevent->events[i],
+			sizeof(event) * (pevent->nr_events - i));
+
+	pevent->events[i] = event;
+	pevent->nr_events++;
+
+	event->pevent = pevent;
+}
+
+static int event_item_type(enum event_type type)
+{
+	switch (type) {
+	case EVENT_ITEM ... EVENT_SQUOTE:
+		return 1;
+	case EVENT_ERROR ... EVENT_DELIM:
+	default:
+		return 0;
+	}
+}
+
+static void free_flag_sym(struct print_flag_sym *fsym)
+{
+	struct print_flag_sym *next;
+
+	while (fsym) {
+		next = fsym->next;
+		free(fsym->value);
+		free(fsym->str);
+		free(fsym);
+		fsym = next;
+	}
+}
+
+static void free_arg(struct print_arg *arg)
+{
+	struct print_arg *farg;
+
+	if (!arg)
+		return;
+
+	switch (arg->type) {
+	case PRINT_ATOM:
+		free(arg->atom.atom);
+		break;
+	case PRINT_FIELD:
+		free(arg->field.name);
+		break;
+	case PRINT_FLAGS:
+		free_arg(arg->flags.field);
+		free(arg->flags.delim);
+		free_flag_sym(arg->flags.flags);
+		break;
+	case PRINT_SYMBOL:
+		free_arg(arg->symbol.field);
+		free_flag_sym(arg->symbol.symbols);
+		break;
+	case PRINT_TYPE:
+		free(arg->typecast.type);
+		free_arg(arg->typecast.item);
+		break;
+	case PRINT_STRING:
+	case PRINT_BSTRING:
+		free(arg->string.string);
+		break;
+	case PRINT_DYNAMIC_ARRAY:
+		free(arg->dynarray.index);
+		break;
+	case PRINT_OP:
+		free(arg->op.op);
+		free_arg(arg->op.left);
+		free_arg(arg->op.right);
+		break;
+	case PRINT_FUNC:
+		while (arg->func.args) {
+			farg = arg->func.args;
+			arg->func.args = farg->next;
+			free_arg(farg);
+		}
+		break;
+
+	case PRINT_NULL:
+	default:
+		break;
+	}
+
+	free(arg);
+}
+
+static enum event_type get_type(int ch)
+{
+	if (ch == '\n')
+		return EVENT_NEWLINE;
+	if (isspace(ch))
+		return EVENT_SPACE;
+	if (isalnum(ch) || ch == '_')
+		return EVENT_ITEM;
+	if (ch == '\'')
+		return EVENT_SQUOTE;
+	if (ch == '"')
+		return EVENT_DQUOTE;
+	if (!isprint(ch))
+		return EVENT_NONE;
+	if (ch == '(' || ch == ')' || ch == ',')
+		return EVENT_DELIM;
+
+	return EVENT_OP;
+}
+
+static int __read_char(void)
+{
+	if (input_buf_ptr >= input_buf_siz)
+		return -1;
+
+	return input_buf[input_buf_ptr++];
+}
+
+static int __peek_char(void)
+{
+	if (input_buf_ptr >= input_buf_siz)
+		return -1;
+
+	return input_buf[input_buf_ptr];
+}
+
+/**
+ * pevent_peek_char - peek at the next character that will be read
+ *
+ * Returns the next character read, or -1 if end of buffer.
+ */
+int pevent_peek_char(void)
+{
+	return __peek_char();
+}
+
+static enum event_type force_token(const char *str, char **tok);
+
+static enum event_type __read_token(char **tok)
+{
+	char buf[BUFSIZ];
+	int ch, last_ch, quote_ch, next_ch;
+	int i = 0;
+	int tok_size = 0;
+	enum event_type type;
+
+	*tok = NULL;
+
+
+	ch = __read_char();
+	if (ch < 0)
+		return EVENT_NONE;
+
+	type = get_type(ch);
+	if (type == EVENT_NONE)
+		return type;
+
+	buf[i++] = ch;
+
+	switch (type) {
+	case EVENT_NEWLINE:
+	case EVENT_DELIM:
+		*tok = malloc_or_die(2);
+		(*tok)[0] = ch;
+		(*tok)[1] = 0;
+		return type;
+
+	case EVENT_OP:
+		switch (ch) {
+		case '-':
+			next_ch = __peek_char();
+			if (next_ch == '>') {
+				buf[i++] = __read_char();
+				break;
+			}
+			/* fall through */
+		case '+':
+		case '|':
+		case '&':
+		case '>':
+		case '<':
+			last_ch = ch;
+			ch = __peek_char();
+			if (ch != last_ch)
+				goto test_equal;
+			buf[i++] = __read_char();
+			switch (last_ch) {
+			case '>':
+			case '<':
+				goto test_equal;
+			default:
+				break;
+			}
+			break;
+		case '!':
+		case '=':
+			goto test_equal;
+		default: /* what should we do instead? */
+			break;
+		}
+		buf[i] = 0;
+		*tok = strdup(buf);
+		return type;
+
+ test_equal:
+		ch = __peek_char();
+		if (ch == '=')
+			buf[i++] = __read_char();
+		goto out;
+
+	case EVENT_DQUOTE:
+	case EVENT_SQUOTE:
+		/* don't keep quotes */
+		i--;
+		quote_ch = ch;
+		last_ch = 0;
+ concat:
+		do {
+			if (i == (BUFSIZ - 1)) {
+				buf[i] = 0;
+				if (*tok) {
+					*tok = realloc(*tok, tok_size + BUFSIZ);
+					if (!*tok)
+						return EVENT_NONE;
+					strcat(*tok, buf);
+				} else
+					*tok = strdup(buf);
+
+				if (!*tok)
+					return EVENT_NONE;
+				tok_size += BUFSIZ;
+				i = 0;
+			}
+			last_ch = ch;
+			ch = __read_char();
+			buf[i++] = ch;
+			/* the '\' '\' will cancel itself */
+			if (ch == '\\' && last_ch == '\\')
+				last_ch = 0;
+		} while (ch != quote_ch || last_ch == '\\');
+		/* remove the last quote */
+		i--;
+
+		/*
+		 * For strings (double quotes) check the next token.
+		 * If it is another string, concatinate the two.
+		 */
+		if (type == EVENT_DQUOTE) {
+			unsigned long long save_input_buf_ptr = input_buf_ptr;
+
+			do {
+				ch = __read_char();
+			} while (isspace(ch));
+			if (ch == '"')
+				goto concat;
+			input_buf_ptr = save_input_buf_ptr;
+		}
+
+		goto out;
+
+	case EVENT_ERROR ... EVENT_SPACE:
+	case EVENT_ITEM:
+	default:
+		break;
+	}
+
+	while (get_type(__peek_char()) == type) {
+		if (i == (BUFSIZ - 1)) {
+			buf[i] = 0;
+			if (*tok) {
+				*tok = realloc(*tok, tok_size + BUFSIZ);
+				if (!*tok)
+					return EVENT_NONE;
+				strcat(*tok, buf);
+			} else
+				*tok = strdup(buf);
+
+			if (!*tok)
+				return EVENT_NONE;
+			tok_size += BUFSIZ;
+			i = 0;
+		}
+		ch = __read_char();
+		buf[i++] = ch;
+	}
+
+ out:
+	buf[i] = 0;
+	if (*tok) {
+		*tok = realloc(*tok, tok_size + i);
+		if (!*tok)
+			return EVENT_NONE;
+		strcat(*tok, buf);
+	} else
+		*tok = strdup(buf);
+	if (!*tok)
+		return EVENT_NONE;
+
+	if (type == EVENT_ITEM) {
+		/*
+		 * Older versions of the kernel has a bug that
+		 * creates invalid symbols and will break the mac80211
+		 * parsing. This is a work around to that bug.
+		 *
+		 * See Linux kernel commit:
+		 *  811cb50baf63461ce0bdb234927046131fc7fa8b
+		 */
+		if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
+			free(*tok);
+			*tok = NULL;
+			return force_token("\"\%s\" ", tok);
+		} else if (strcmp(*tok, "STA_PR_FMT") == 0) {
+			free(*tok);
+			*tok = NULL;
+			return force_token("\" sta:%pM\" ", tok);
+		} else if (strcmp(*tok, "VIF_PR_FMT") == 0) {
+			free(*tok);
+			*tok = NULL;
+			return force_token("\" vif:%p(%d)\" ", tok);
+		}
+	}
+
+	return type;
+}
+
+static enum event_type force_token(const char *str, char **tok)
+{
+	const char *save_input_buf;
+	unsigned long long save_input_buf_ptr;
+	unsigned long long save_input_buf_siz;
+	enum event_type type;
+	
+	/* save off the current input pointers */
+	save_input_buf = input_buf;
+	save_input_buf_ptr = input_buf_ptr;
+	save_input_buf_siz = input_buf_siz;
+
+	init_input_buf(str, strlen(str));
+
+	type = __read_token(tok);
+
+	/* reset back to original token */
+	input_buf = save_input_buf;
+	input_buf_ptr = save_input_buf_ptr;
+	input_buf_siz = save_input_buf_siz;
+
+	return type;
+}
+
+static void free_token(char *tok)
+{
+	if (tok)
+		free(tok);
+}
+
+static enum event_type read_token(char **tok)
+{
+	enum event_type type;
+
+	for (;;) {
+		type = __read_token(tok);
+		if (type != EVENT_SPACE)
+			return type;
+
+		free_token(*tok);
+	}
+
+	/* not reached */
+	*tok = NULL;
+	return EVENT_NONE;
+}
+
+/**
+ * pevent_read_token - access to utilites to use the pevent parser
+ * @tok: The token to return
+ *
+ * This will parse tokens from the string given by
+ * pevent_init_data().
+ *
+ * Returns the token type.
+ */
+enum event_type pevent_read_token(char **tok)
+{
+	return read_token(tok);
+}
+
+/**
+ * pevent_free_token - free a token returned by pevent_read_token
+ * @token: the token to free
+ */
+void pevent_free_token(char *token)
+{
+	free_token(token);
+}
+
+/* no newline */
+static enum event_type read_token_item(char **tok)
+{
+	enum event_type type;
+
+	for (;;) {
+		type = __read_token(tok);
+		if (type != EVENT_SPACE && type != EVENT_NEWLINE)
+			return type;
+		free_token(*tok);
+		*tok = NULL;
+	}
+
+	/* not reached */
+	*tok = NULL;
+	return EVENT_NONE;
+}
+
+static int test_type(enum event_type type, enum event_type expect)
+{
+	if (type != expect) {
+		do_warning("Error: expected type %d but read %d",
+		    expect, type);
+		return -1;
+	}
+	return 0;
+}
+
+static int test_type_token(enum event_type type, const char *token,
+		    enum event_type expect, const char *expect_tok)
+{
+	if (type != expect) {
+		do_warning("Error: expected type %d but read %d",
+		    expect, type);
+		return -1;
+	}
+
+	if (strcmp(token, expect_tok) != 0) {
+		do_warning("Error: expected '%s' but read '%s'",
+		    expect_tok, token);
+		return -1;
+	}
+	return 0;
+}
+
+static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
+{
+	enum event_type type;
+
+	if (newline_ok)
+		type = read_token(tok);
+	else
+		type = read_token_item(tok);
+	return test_type(type, expect);
+}
+
+static int read_expect_type(enum event_type expect, char **tok)
+{
+	return __read_expect_type(expect, tok, 1);
+}
+
+static int __read_expected(enum event_type expect, const char *str,
+			   int newline_ok)
+{
+	enum event_type type;
+	char *token;
+	int ret;
+
+	if (newline_ok)
+		type = read_token(&token);
+	else
+		type = read_token_item(&token);
+
+	ret = test_type_token(type, token, expect, str);
+
+	free_token(token);
+
+	return ret;
+}
+
+static int read_expected(enum event_type expect, const char *str)
+{
+	return __read_expected(expect, str, 1);
+}
+
+static int read_expected_item(enum event_type expect, const char *str)
+{
+	return __read_expected(expect, str, 0);
+}
+
+static char *event_read_name(void)
+{
+	char *token;
+
+	if (read_expected(EVENT_ITEM, "name") < 0)
+		return NULL;
+
+	if (read_expected(EVENT_OP, ":") < 0)
+		return NULL;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+
+	return token;
+
+ fail:
+	free_token(token);
+	return NULL;
+}
+
+static int event_read_id(void)
+{
+	char *token;
+	int id;
+
+	if (read_expected_item(EVENT_ITEM, "ID") < 0)
+		return -1;
+
+	if (read_expected(EVENT_OP, ":") < 0)
+		return -1;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+
+	id = strtoul(token, NULL, 0);
+	free_token(token);
+	return id;
+
+ fail:
+	free_token(token);
+	return -1;
+}
+
+static int field_is_string(struct format_field *field)
+{
+	if ((field->flags & FIELD_IS_ARRAY) &&
+	    (strstr(field->type, "char") || strstr(field->type, "u8") ||
+	     strstr(field->type, "s8")))
+		return 1;
+
+	return 0;
+}
+
+static int field_is_dynamic(struct format_field *field)
+{
+	if (strncmp(field->type, "__data_loc", 10) == 0)
+		return 1;
+
+	return 0;
+}
+
+static int field_is_long(struct format_field *field)
+{
+	/* includes long long */
+	if (strstr(field->type, "long"))
+		return 1;
+
+	return 0;
+}
+
+static int event_read_fields(struct event_format *event, struct format_field **fields)
+{
+	struct format_field *field = NULL;
+	enum event_type type;
+	char *token;
+	char *last_token;
+	int count = 0;
+
+	do {
+		type = read_token(&token);
+		if (type == EVENT_NEWLINE) {
+			free_token(token);
+			return count;
+		}
+
+		count++;
+
+		if (test_type_token(type, token, EVENT_ITEM, "field"))
+			goto fail;
+		free_token(token);
+
+		type = read_token(&token);
+		/*
+		 * The ftrace fields may still use the "special" name.
+		 * Just ignore it.
+		 */
+		if (event->flags & EVENT_FL_ISFTRACE &&
+		    type == EVENT_ITEM && strcmp(token, "special") == 0) {
+			free_token(token);
+			type = read_token(&token);
+		}
+
+		if (test_type_token(type, token, EVENT_OP, ":") < 0)
+			goto fail;
+
+		free_token(token);
+		if (read_expect_type(EVENT_ITEM, &token) < 0)
+			goto fail;
+
+		last_token = token;
+
+		field = malloc_or_die(sizeof(*field));
+		memset(field, 0, sizeof(*field));
+		field->event = event;
+
+		/* read the rest of the type */
+		for (;;) {
+			type = read_token(&token);
+			if (type == EVENT_ITEM ||
+			    (type == EVENT_OP && strcmp(token, "*") == 0) ||
+			    /*
+			     * Some of the ftrace fields are broken and have
+			     * an illegal "." in them.
+			     */
+			    (event->flags & EVENT_FL_ISFTRACE &&
+			     type == EVENT_OP && strcmp(token, ".") == 0)) {
+
+				if (strcmp(token, "*") == 0)
+					field->flags |= FIELD_IS_POINTER;
+
+				if (field->type) {
+					field->type = realloc(field->type,
+							      strlen(field->type) +
+							      strlen(last_token) + 2);
+					strcat(field->type, " ");
+					strcat(field->type, last_token);
+					free(last_token);
+				} else
+					field->type = last_token;
+				last_token = token;
+				continue;
+			}
+
+			break;
+		}
+
+		if (!field->type) {
+			die("no type found");
+			goto fail;
+		}
+		field->name = last_token;
+
+		if (test_type(type, EVENT_OP))
+			goto fail;
+
+		if (strcmp(token, "[") == 0) {
+			enum event_type last_type = type;
+			char *brackets = token;
+			int len;
+
+			field->flags |= FIELD_IS_ARRAY;
+
+			type = read_token(&token);
+
+			if (type == EVENT_ITEM)
+				field->arraylen = strtoul(token, NULL, 0);
+			else
+				field->arraylen = 0;
+
+		        while (strcmp(token, "]") != 0) {
+				if (last_type == EVENT_ITEM &&
+				    type == EVENT_ITEM)
+					len = 2;
+				else
+					len = 1;
+				last_type = type;
+
+				brackets = realloc(brackets,
+						   strlen(brackets) +
+						   strlen(token) + len);
+				if (len == 2)
+					strcat(brackets, " ");
+				strcat(brackets, token);
+				/* We only care about the last token */
+				field->arraylen = strtoul(token, NULL, 0);
+				free_token(token);
+				type = read_token(&token);
+				if (type == EVENT_NONE) {
+					die("failed to find token");
+					goto fail;
+				}
+			}
+
+			free_token(token);
+
+			brackets = realloc(brackets, strlen(brackets) + 2);
+			strcat(brackets, "]");
+
+			/* add brackets to type */
+
+			type = read_token(&token);
+			/*
+			 * If the next token is not an OP, then it is of
+			 * the format: type [] item;
+			 */
+			if (type == EVENT_ITEM) {
+				field->type = realloc(field->type,
+						      strlen(field->type) +
+						      strlen(field->name) +
+						      strlen(brackets) + 2);
+				strcat(field->type, " ");
+				strcat(field->type, field->name);
+				free_token(field->name);
+				strcat(field->type, brackets);
+				field->name = token;
+				type = read_token(&token);
+			} else {
+				field->type = realloc(field->type,
+						      strlen(field->type) +
+						      strlen(brackets) + 1);
+				strcat(field->type, brackets);
+			}
+			free(brackets);
+		}
+
+		if (field_is_string(field))
+			field->flags |= FIELD_IS_STRING;
+		if (field_is_dynamic(field))
+			field->flags |= FIELD_IS_DYNAMIC;
+		if (field_is_long(field))
+			field->flags |= FIELD_IS_LONG;
+
+		if (test_type_token(type, token,  EVENT_OP, ";"))
+			goto fail;
+		free_token(token);
+
+		if (read_expected(EVENT_ITEM, "offset") < 0)
+			goto fail_expect;
+
+		if (read_expected(EVENT_OP, ":") < 0)
+			goto fail_expect;
+
+		if (read_expect_type(EVENT_ITEM, &token))
+			goto fail;
+		field->offset = strtoul(token, NULL, 0);
+		free_token(token);
+
+		if (read_expected(EVENT_OP, ";") < 0)
+			goto fail_expect;
+
+		if (read_expected(EVENT_ITEM, "size") < 0)
+			goto fail_expect;
+
+		if (read_expected(EVENT_OP, ":") < 0)
+			goto fail_expect;
+
+		if (read_expect_type(EVENT_ITEM, &token))
+			goto fail;
+		field->size = strtoul(token, NULL, 0);
+		free_token(token);
+
+		if (read_expected(EVENT_OP, ";") < 0)
+			goto fail_expect;
+
+		type = read_token(&token);
+		if (type != EVENT_NEWLINE) {
+			/* newer versions of the kernel have a "signed" type */
+			if (test_type_token(type, token, EVENT_ITEM, "signed"))
+				goto fail;
+
+			free_token(token);
+
+			if (read_expected(EVENT_OP, ":") < 0)
+				goto fail_expect;
+
+			if (read_expect_type(EVENT_ITEM, &token))
+				goto fail;
+
+			/* add signed type */
+
+			free_token(token);
+			if (read_expected(EVENT_OP, ";") < 0)
+				goto fail_expect;
+
+			if (read_expect_type(EVENT_NEWLINE, &token))
+				goto fail;
+		}
+
+		free_token(token);
+
+		if (field->flags & FIELD_IS_ARRAY) {
+			if (field->arraylen)
+				field->elementsize = field->size / field->arraylen;
+			else if (field->flags & FIELD_IS_STRING)
+				field->elementsize = 1;
+			else
+				field->elementsize = event->pevent->long_size;
+		} else
+			field->elementsize = field->size;
+
+		*fields = field;
+		fields = &field->next;
+
+	} while (1);
+
+	return 0;
+
+fail:
+	free_token(token);
+fail_expect:
+	if (field)
+		free(field);
+	return -1;
+}
+
+static int event_read_format(struct event_format *event)
+{
+	char *token;
+	int ret;
+
+	if (read_expected_item(EVENT_ITEM, "format") < 0)
+		return -1;
+
+	if (read_expected(EVENT_OP, ":") < 0)
+		return -1;
+
+	if (read_expect_type(EVENT_NEWLINE, &token))
+		goto fail;
+	free_token(token);
+
+	ret = event_read_fields(event, &event->format.common_fields);
+	if (ret < 0)
+		return ret;
+	event->format.nr_common = ret;
+
+	ret = event_read_fields(event, &event->format.fields);
+	if (ret < 0)
+		return ret;
+	event->format.nr_fields = ret;
+
+	return 0;
+
+ fail:
+	free_token(token);
+	return -1;
+}
+
+static enum event_type
+process_arg_token(struct event_format *event, struct print_arg *arg,
+		  char **tok, enum event_type type);
+
+static enum event_type
+process_arg(struct event_format *event, struct print_arg *arg, char **tok)
+{
+	enum event_type type;
+	char *token;
+
+	type = read_token(&token);
+	*tok = token;
+
+	return process_arg_token(event, arg, tok, type);
+}
+
+static enum event_type
+process_op(struct event_format *event, struct print_arg *arg, char **tok);
+
+static enum event_type
+process_cond(struct event_format *event, struct print_arg *top, char **tok)
+{
+	struct print_arg *arg, *left, *right;
+	enum event_type type;
+	char *token = NULL;
+
+	arg = alloc_arg();
+	left = alloc_arg();
+	right = alloc_arg();
+
+	arg->type = PRINT_OP;
+	arg->op.left = left;
+	arg->op.right = right;
+
+	*tok = NULL;
+	type = process_arg(event, left, &token);
+
+ again:
+	/* Handle other operations in the arguments */
+	if (type == EVENT_OP && strcmp(token, ":") != 0) {
+		type = process_op(event, left, &token);
+		goto again;
+	}
+
+	if (test_type_token(type, token, EVENT_OP, ":"))
+		goto out_free;
+
+	arg->op.op = token;
+
+	type = process_arg(event, right, &token);
+
+	top->op.right = arg;
+
+	*tok = token;
+	return type;
+
+out_free:
+	/* Top may point to itself */
+	top->op.right = NULL;
+	free_token(token);
+	free_arg(arg);
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_array(struct event_format *event, struct print_arg *top, char **tok)
+{
+	struct print_arg *arg;
+	enum event_type type;
+	char *token = NULL;
+
+	arg = alloc_arg();
+
+	*tok = NULL;
+	type = process_arg(event, arg, &token);
+	if (test_type_token(type, token, EVENT_OP, "]"))
+		goto out_free;
+
+	top->op.right = arg;
+
+	free_token(token);
+	type = read_token_item(&token);
+	*tok = token;
+
+	return type;
+
+out_free:
+	free_token(*tok);
+	*tok = NULL;
+	free_arg(arg);
+	return EVENT_ERROR;
+}
+
+static int get_op_prio(char *op)
+{
+	if (!op[1]) {
+		switch (op[0]) {
+		case '~':
+		case '!':
+			return 4;
+		case '*':
+		case '/':
+		case '%':
+			return 6;
+		case '+':
+		case '-':
+			return 7;
+			/* '>>' and '<<' are 8 */
+		case '<':
+		case '>':
+			return 9;
+			/* '==' and '!=' are 10 */
+		case '&':
+			return 11;
+		case '^':
+			return 12;
+		case '|':
+			return 13;
+		case '?':
+			return 16;
+		default:
+			do_warning("unknown op '%c'", op[0]);
+			return -1;
+		}
+	} else {
+		if (strcmp(op, "++") == 0 ||
+		    strcmp(op, "--") == 0) {
+			return 3;
+		} else if (strcmp(op, ">>") == 0 ||
+			   strcmp(op, "<<") == 0) {
+			return 8;
+		} else if (strcmp(op, ">=") == 0 ||
+			   strcmp(op, "<=") == 0) {
+			return 9;
+		} else if (strcmp(op, "==") == 0 ||
+			   strcmp(op, "!=") == 0) {
+			return 10;
+		} else if (strcmp(op, "&&") == 0) {
+			return 14;
+		} else if (strcmp(op, "||") == 0) {
+			return 15;
+		} else {
+			do_warning("unknown op '%s'", op);
+			return -1;
+		}
+	}
+}
+
+static int set_op_prio(struct print_arg *arg)
+{
+
+	/* single ops are the greatest */
+	if (!arg->op.left || arg->op.left->type == PRINT_NULL)
+		arg->op.prio = 0;
+	else
+		arg->op.prio = get_op_prio(arg->op.op);
+
+	return arg->op.prio;
+}
+
+/* Note, *tok does not get freed, but will most likely be saved */
+static enum event_type
+process_op(struct event_format *event, struct print_arg *arg, char **tok)
+{
+	struct print_arg *left, *right = NULL;
+	enum event_type type;
+	char *token;
+
+	/* the op is passed in via tok */
+	token = *tok;
+
+	if (arg->type == PRINT_OP && !arg->op.left) {
+		/* handle single op */
+		if (token[1]) {
+			die("bad op token %s", token);
+			goto out_free;
+		}
+		switch (token[0]) {
+		case '~':
+		case '!':
+		case '+':
+		case '-':
+			break;
+		default:
+			do_warning("bad op token %s", token);
+			goto out_free;
+
+		}
+
+		/* make an empty left */
+		left = alloc_arg();
+		left->type = PRINT_NULL;
+		arg->op.left = left;
+
+		right = alloc_arg();
+		arg->op.right = right;
+
+		/* do not free the token, it belongs to an op */
+		*tok = NULL;
+		type = process_arg(event, right, tok);
+
+	} else if (strcmp(token, "?") == 0) {
+
+		left = alloc_arg();
+		/* copy the top arg to the left */
+		*left = *arg;
+
+		arg->type = PRINT_OP;
+		arg->op.op = token;
+		arg->op.left = left;
+		arg->op.prio = 0;
+
+		type = process_cond(event, arg, tok);
+
+	} else if (strcmp(token, ">>") == 0 ||
+		   strcmp(token, "<<") == 0 ||
+		   strcmp(token, "&") == 0 ||
+		   strcmp(token, "|") == 0 ||
+		   strcmp(token, "&&") == 0 ||
+		   strcmp(token, "||") == 0 ||
+		   strcmp(token, "-") == 0 ||
+		   strcmp(token, "+") == 0 ||
+		   strcmp(token, "*") == 0 ||
+		   strcmp(token, "^") == 0 ||
+		   strcmp(token, "/") == 0 ||
+		   strcmp(token, "<") == 0 ||
+		   strcmp(token, ">") == 0 ||
+		   strcmp(token, "==") == 0 ||
+		   strcmp(token, "!=") == 0) {
+
+		left = alloc_arg();
+
+		/* copy the top arg to the left */
+		*left = *arg;
+
+		arg->type = PRINT_OP;
+		arg->op.op = token;
+		arg->op.left = left;
+
+		if (set_op_prio(arg) == -1) {
+			event->flags |= EVENT_FL_FAILED;
+			goto out_free;
+		}
+
+		type = read_token_item(&token);
+		*tok = token;
+
+		/* could just be a type pointer */
+		if ((strcmp(arg->op.op, "*") == 0) &&
+		    type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
+			if (left->type != PRINT_ATOM)
+				die("bad pointer type");
+			left->atom.atom = realloc(left->atom.atom,
+					    strlen(left->atom.atom) + 3);
+			strcat(left->atom.atom, " *");
+			free(arg->op.op);
+			*arg = *left;
+			free(left);
+
+			return type;
+		}
+
+		right = alloc_arg();
+		type = process_arg_token(event, right, tok, type);
+		arg->op.right = right;
+
+	} else if (strcmp(token, "[") == 0) {
+
+		left = alloc_arg();
+		*left = *arg;
+
+		arg->type = PRINT_OP;
+		arg->op.op = token;
+		arg->op.left = left;
+
+		arg->op.prio = 0;
+
+		type = process_array(event, arg, tok);
+
+	} else {
+		do_warning("unknown op '%s'", token);
+		event->flags |= EVENT_FL_FAILED;
+		/* the arg is now the left side */
+		goto out_free;
+	}
+
+	if (type == EVENT_OP && strcmp(*tok, ":") != 0) {
+		int prio;
+
+		/* higher prios need to be closer to the root */
+		prio = get_op_prio(*tok);
+
+		if (prio > arg->op.prio)
+			return process_op(event, arg, tok);
+
+		return process_op(event, right, tok);
+	}
+
+	return type;
+
+ out_free:
+	free_token(token);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_entry(struct event_format *event __unused, struct print_arg *arg,
+	      char **tok)
+{
+	enum event_type type;
+	char *field;
+	char *token;
+
+	if (read_expected(EVENT_OP, "->") < 0)
+		goto out_err;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto out_free;
+	field = token;
+
+	arg->type = PRINT_FIELD;
+	arg->field.name = field;
+
+	if (is_flag_field) {
+		arg->field.field = pevent_find_any_field(event, arg->field.name);
+		arg->field.field->flags |= FIELD_IS_FLAG;
+		is_flag_field = 0;
+	} else if (is_symbolic_field) {
+		arg->field.field = pevent_find_any_field(event, arg->field.name);
+		arg->field.field->flags |= FIELD_IS_SYMBOLIC;
+		is_symbolic_field = 0;
+	}
+
+	type = read_token(&token);
+	*tok = token;
+
+	return type;
+
+ out_free:
+	free_token(token);
+ out_err:
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static char *arg_eval (struct print_arg *arg);
+
+static unsigned long long
+eval_type_str(unsigned long long val, const char *type, int pointer)
+{
+	int sign = 0;
+	char *ref;
+	int len;
+
+	len = strlen(type);
+
+	if (pointer) {
+
+		if (type[len-1] != '*') {
+			do_warning("pointer expected with non pointer type");
+			return val;
+		}
+
+		ref = malloc_or_die(len);
+		memcpy(ref, type, len);
+
+		/* chop off the " *" */
+		ref[len - 2] = 0;
+
+		val = eval_type_str(val, ref, 0);
+		free(ref);
+		return val;
+	}
+
+	/* check if this is a pointer */
+	if (type[len - 1] == '*')
+		return val;
+
+	/* Try to figure out the arg size*/
+	if (strncmp(type, "struct", 6) == 0)
+		/* all bets off */
+		return val;
+
+	if (strcmp(type, "u8") == 0)
+		return val & 0xff;
+
+	if (strcmp(type, "u16") == 0)
+		return val & 0xffff;
+
+	if (strcmp(type, "u32") == 0)
+		return val & 0xffffffff;
+
+	if (strcmp(type, "u64") == 0 ||
+	    strcmp(type, "s64"))
+		return val;
+
+	if (strcmp(type, "s8") == 0)
+		return (unsigned long long)(char)val & 0xff;
+
+	if (strcmp(type, "s16") == 0)
+		return (unsigned long long)(short)val & 0xffff;
+
+	if (strcmp(type, "s32") == 0)
+		return (unsigned long long)(int)val & 0xffffffff;
+
+	if (strncmp(type, "unsigned ", 9) == 0) {
+		sign = 0;
+		type += 9;
+	}
+
+	if (strcmp(type, "char") == 0) {
+		if (sign)
+			return (unsigned long long)(char)val & 0xff;
+		else
+			return val & 0xff;
+	}
+
+	if (strcmp(type, "short") == 0) {
+		if (sign)
+			return (unsigned long long)(short)val & 0xffff;
+		else
+			return val & 0xffff;
+	}
+
+	if (strcmp(type, "int") == 0) {
+		if (sign)
+			return (unsigned long long)(int)val & 0xffffffff;
+		else
+			return val & 0xffffffff;
+	}
+
+	return val;
+}
+
+/*
+ * Try to figure out the type.
+ */
+static unsigned long long
+eval_type(unsigned long long val, struct print_arg *arg, int pointer)
+{
+	if (arg->type != PRINT_TYPE)
+		die("expected type argument");
+
+	return eval_type_str(val, arg->typecast.type, pointer);
+}
+
+static int arg_num_eval(struct print_arg *arg, long long *val)
+{
+	long long left, right;
+	int ret = 1;
+
+	switch (arg->type) {
+	case PRINT_ATOM:
+		*val = strtoll(arg->atom.atom, NULL, 0);
+		break;
+	case PRINT_TYPE:
+		ret = arg_num_eval(arg->typecast.item, val);
+		if (!ret)
+			break;
+		*val = eval_type(*val, arg, 0);
+		break;
+	case PRINT_OP:
+		switch (arg->op.op[0]) {
+		case '|':
+			ret = arg_num_eval(arg->op.left, &left);
+			if (!ret)
+				break;
+			ret = arg_num_eval(arg->op.right, &right);
+			if (!ret)
+				break;
+			if (arg->op.op[1])
+				*val = left || right;
+			else
+				*val = left | right;
+			break;
+		case '&':
+			ret = arg_num_eval(arg->op.left, &left);
+			if (!ret)
+				break;
+			ret = arg_num_eval(arg->op.right, &right);
+			if (!ret)
+				break;
+			if (arg->op.op[1])
+				*val = left && right;
+			else
+				*val = left & right;
+			break;
+		case '<':
+			ret = arg_num_eval(arg->op.left, &left);
+			if (!ret)
+				break;
+			ret = arg_num_eval(arg->op.right, &right);
+			if (!ret)
+				break;
+			switch (arg->op.op[1]) {
+			case 0:
+				*val = left < right;
+				break;
+			case '<':
+				*val = left << right;
+				break;
+			case '=':
+				*val = left <= right;
+				break;
+			default:
+				do_warning("unknown op '%s'", arg->op.op);
+				ret = 0;
+			}
+			break;
+		case '>':
+			ret = arg_num_eval(arg->op.left, &left);
+			if (!ret)
+				break;
+			ret = arg_num_eval(arg->op.right, &right);
+			if (!ret)
+				break;
+			switch (arg->op.op[1]) {
+			case 0:
+				*val = left > right;
+				break;
+			case '>':
+				*val = left >> right;
+				break;
+			case '=':
+				*val = left >= right;
+				break;
+			default:
+				do_warning("unknown op '%s'", arg->op.op);
+				ret = 0;
+			}
+			break;
+		case '=':
+			ret = arg_num_eval(arg->op.left, &left);
+			if (!ret)
+				break;
+			ret = arg_num_eval(arg->op.right, &right);
+			if (!ret)
+				break;
+
+			if (arg->op.op[1] != '=') {
+				do_warning("unknown op '%s'", arg->op.op);
+				ret = 0;
+			} else
+				*val = left == right;
+			break;
+		case '!':
+			ret = arg_num_eval(arg->op.left, &left);
+			if (!ret)
+				break;
+			ret = arg_num_eval(arg->op.right, &right);
+			if (!ret)
+				break;
+
+			switch (arg->op.op[1]) {
+			case '=':
+				*val = left != right;
+				break;
+			default:
+				do_warning("unknown op '%s'", arg->op.op);
+				ret = 0;
+			}
+			break;
+		case '-':
+			/* check for negative */
+			if (arg->op.left->type == PRINT_NULL)
+				left = 0;
+			else
+				ret = arg_num_eval(arg->op.left, &left);
+			if (!ret)
+				break;
+			ret = arg_num_eval(arg->op.right, &right);
+			if (!ret)
+				break;
+			*val = left - right;
+			break;
+		case '+':
+			if (arg->op.left->type == PRINT_NULL)
+				left = 0;
+			else
+				ret = arg_num_eval(arg->op.left, &left);
+			if (!ret)
+				break;
+			ret = arg_num_eval(arg->op.right, &right);
+			if (!ret)
+				break;
+			*val = left + right;
+			break;
+		default:
+			do_warning("unknown op '%s'", arg->op.op);
+			ret = 0;
+		}
+		break;
+
+	case PRINT_NULL:
+	case PRINT_FIELD ... PRINT_SYMBOL:
+	case PRINT_STRING:
+	case PRINT_BSTRING:
+	default:
+		do_warning("invalid eval type %d", arg->type);
+		ret = 0;
+
+	}
+	return ret;
+}
+
+static char *arg_eval (struct print_arg *arg)
+{
+	long long val;
+	static char buf[20];
+
+	switch (arg->type) {
+	case PRINT_ATOM:
+		return arg->atom.atom;
+	case PRINT_TYPE:
+		return arg_eval(arg->typecast.item);
+	case PRINT_OP:
+		if (!arg_num_eval(arg, &val))
+			break;
+		sprintf(buf, "%lld", val);
+		return buf;
+
+	case PRINT_NULL:
+	case PRINT_FIELD ... PRINT_SYMBOL:
+	case PRINT_STRING:
+	case PRINT_BSTRING:
+	default:
+		die("invalid eval type %d", arg->type);
+		break;
+	}
+
+	return NULL;
+}
+
+static enum event_type
+process_fields(struct event_format *event, struct print_flag_sym **list, char **tok)
+{
+	enum event_type type;
+	struct print_arg *arg = NULL;
+	struct print_flag_sym *field;
+	char *token = *tok;
+	char *value;
+
+	do {
+		free_token(token);
+		type = read_token_item(&token);
+		if (test_type_token(type, token, EVENT_OP, "{"))
+			break;
+
+		arg = alloc_arg();
+
+		free_token(token);
+		type = process_arg(event, arg, &token);
+		if (test_type_token(type, token, EVENT_DELIM, ","))
+			goto out_free;
+
+		field = malloc_or_die(sizeof(*field));
+		memset(field, 0, sizeof(*field));
+
+		value = arg_eval(arg);
+		if (value == NULL)
+			goto out_free;
+		field->value = strdup(value);
+
+		free_arg(arg);
+		arg = alloc_arg();
+
+		free_token(token);
+		type = process_arg(event, arg, &token);
+		if (test_type_token(type, token, EVENT_OP, "}"))
+			goto out_free;
+
+		value = arg_eval(arg);
+		if (value == NULL)
+			goto out_free;
+		field->str = strdup(value);
+		free_arg(arg);
+		arg = NULL;
+
+		*list = field;
+		list = &field->next;
+
+		free_token(token);
+		type = read_token_item(&token);
+	} while (type == EVENT_DELIM && strcmp(token, ",") == 0);
+
+	*tok = token;
+	return type;
+
+out_free:
+	free_arg(arg);
+	free_token(token);
+	*tok = NULL;
+
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_flags(struct event_format *event, struct print_arg *arg, char **tok)
+{
+	struct print_arg *field;
+	enum event_type type;
+	char *token;
+
+	memset(arg, 0, sizeof(*arg));
+	arg->type = PRINT_FLAGS;
+
+	field = alloc_arg();
+
+	type = process_arg(event, field, &token);
+
+	/* Handle operations in the first argument */
+	while (type == EVENT_OP)
+		type = process_op(event, field, &token);
+
+	if (test_type_token(type, token, EVENT_DELIM, ","))
+		goto out_free;
+	free_token(token);
+
+	arg->flags.field = field;
+
+	type = read_token_item(&token);
+	if (event_item_type(type)) {
+		arg->flags.delim = token;
+		type = read_token_item(&token);
+	}
+
+	if (test_type_token(type, token, EVENT_DELIM, ","))
+		goto out_free;
+
+	type = process_fields(event, &arg->flags.flags, &token);
+	if (test_type_token(type, token, EVENT_DELIM, ")"))
+		goto out_free;
+
+	free_token(token);
+	type = read_token_item(tok);
+	return type;
+
+ out_free:
+	free_token(token);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_symbols(struct event_format *event, struct print_arg *arg, char **tok)
+{
+	struct print_arg *field;
+	enum event_type type;
+	char *token;
+
+	memset(arg, 0, sizeof(*arg));
+	arg->type = PRINT_SYMBOL;
+
+	field = alloc_arg();
+
+	type = process_arg(event, field, &token);
+	if (test_type_token(type, token, EVENT_DELIM, ","))
+		goto out_free;
+
+	arg->symbol.field = field;
+
+	type = process_fields(event, &arg->symbol.symbols, &token);
+	if (test_type_token(type, token, EVENT_DELIM, ")"))
+		goto out_free;
+
+	free_token(token);
+	type = read_token_item(tok);
+	return type;
+
+ out_free:
+	free_token(token);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
+{
+	struct format_field *field;
+	enum event_type type;
+	char *token;
+
+	memset(arg, 0, sizeof(*arg));
+	arg->type = PRINT_DYNAMIC_ARRAY;
+
+	/*
+	 * The item within the parenthesis is another field that holds
+	 * the index into where the array starts.
+	 */
+	type = read_token(&token);
+	*tok = token;
+	if (type != EVENT_ITEM)
+		goto out_free;
+
+	/* Find the field */
+
+	field = pevent_find_field(event, token);
+	if (!field)
+		goto out_free;
+
+	arg->dynarray.field = field;
+	arg->dynarray.index = 0;
+
+	if (read_expected(EVENT_DELIM, ")") < 0)
+		goto out_free;
+
+	free_token(token);
+	type = read_token_item(&token);
+	*tok = token;
+	if (type != EVENT_OP || strcmp(token, "[") != 0)
+		return type;
+
+	free_token(token);
+	arg = alloc_arg();
+	type = process_arg(event, arg, &token);
+	if (type == EVENT_ERROR)
+		goto out_free;
+
+	if (!test_type_token(type, token, EVENT_OP, "]"))
+		goto out_free;
+
+	free_token(token);
+	type = read_token_item(tok);
+	return type;
+
+ out_free:
+	free(arg);
+	free_token(token);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_paren(struct event_format *event, struct print_arg *arg, char **tok)
+{
+	struct print_arg *item_arg;
+	enum event_type type;
+	char *token;
+
+	type = process_arg(event, arg, &token);
+
+	if (type == EVENT_ERROR)
+		goto out_free;
+
+	if (type == EVENT_OP)
+		type = process_op(event, arg, &token);
+
+	if (type == EVENT_ERROR)
+		goto out_free;
+
+	if (test_type_token(type, token, EVENT_DELIM, ")"))
+		goto out_free;
+
+	free_token(token);
+	type = read_token_item(&token);
+
+	/*
+	 * If the next token is an item or another open paren, then
+	 * this was a typecast.
+	 */
+	if (event_item_type(type) ||
+	    (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
+
+		/* make this a typecast and contine */
+
+		/* prevous must be an atom */
+		if (arg->type != PRINT_ATOM)
+			die("previous needed to be PRINT_ATOM");
+
+		item_arg = alloc_arg();
+
+		arg->type = PRINT_TYPE;
+		arg->typecast.type = arg->atom.atom;
+		arg->typecast.item = item_arg;
+		type = process_arg_token(event, item_arg, &token, type);
+
+	}
+
+	*tok = token;
+	return type;
+
+ out_free:
+	free_token(token);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+
+static enum event_type
+process_str(struct event_format *event __unused, struct print_arg *arg, char **tok)
+{
+	enum event_type type;
+	char *token;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto out_free;
+
+	arg->type = PRINT_STRING;
+	arg->string.string = token;
+	arg->string.offset = -1;
+
+	if (read_expected(EVENT_DELIM, ")") < 0)
+		goto out_err;
+
+	type = read_token(&token);
+	*tok = token;
+
+	return type;
+
+ out_free:
+	free_token(token);
+ out_err:
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static struct pevent_function_handler *
+find_func_handler(struct pevent *pevent, char *func_name)
+{
+	struct pevent_function_handler *func;
+
+	for (func = pevent->func_handlers; func; func = func->next) {
+		if (strcmp(func->name, func_name) == 0)
+			break;
+	}
+
+	return func;
+}
+
+static void remove_func_handler(struct pevent *pevent, char *func_name)
+{
+	struct pevent_function_handler *func;
+	struct pevent_function_handler **next;
+
+	next = &pevent->func_handlers;
+	while ((func = *next)) {
+		if (strcmp(func->name, func_name) == 0) {
+			*next = func->next;
+			free_func_handle(func);
+			break;
+		}
+		next = &func->next;
+	}
+}
+
+static enum event_type
+process_func_handler(struct event_format *event, struct pevent_function_handler *func,
+		     struct print_arg *arg, char **tok)
+{
+	struct print_arg **next_arg;
+	struct print_arg *farg;
+	enum event_type type;
+	char *token;
+	char *test;
+	int i;
+
+	arg->type = PRINT_FUNC;
+	arg->func.func = func;
+
+	*tok = NULL;
+
+	next_arg = &(arg->func.args);
+	for (i = 0; i < func->nr_args; i++) {
+		farg = alloc_arg();
+		type = process_arg(event, farg, &token);
+		if (i < (func->nr_args - 1))
+			test = ",";
+		else
+			test = ")";
+
+		if (test_type_token(type, token, EVENT_DELIM, test)) {
+			free_arg(farg);
+			free_token(token);
+			return EVENT_ERROR;
+		}
+
+		*next_arg = farg;
+		next_arg = &(farg->next);
+		free_token(token);
+	}
+
+	type = read_token(&token);
+	*tok = token;
+
+	return type;
+}
+
+static enum event_type
+process_function(struct event_format *event, struct print_arg *arg,
+		 char *token, char **tok)
+{
+	struct pevent_function_handler *func;
+
+	if (strcmp(token, "__print_flags") == 0) {
+		free_token(token);
+		is_flag_field = 1;
+		return process_flags(event, arg, tok);
+	}
+	if (strcmp(token, "__print_symbolic") == 0) {
+		free_token(token);
+		is_symbolic_field = 1;
+		return process_symbols(event, arg, tok);
+	}
+	if (strcmp(token, "__get_str") == 0) {
+		free_token(token);
+		return process_str(event, arg, tok);
+	}
+	if (strcmp(token, "__get_dynamic_array") == 0) {
+		free_token(token);
+		return process_dynamic_array(event, arg, tok);
+	}
+
+	func = find_func_handler(event->pevent, token);
+	if (func) {
+		free_token(token);
+		return process_func_handler(event, func, arg, tok);
+	}
+
+	do_warning("function %s not defined", token);
+	free_token(token);
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_arg_token(struct event_format *event, struct print_arg *arg,
+		  char **tok, enum event_type type)
+{
+	char *token;
+	char *atom;
+
+	token = *tok;
+
+	switch (type) {
+	case EVENT_ITEM:
+		if (strcmp(token, "REC") == 0) {
+			free_token(token);
+			type = process_entry(event, arg, &token);
+			break;
+		}
+		atom = token;
+		/* test the next token */
+		type = read_token_item(&token);
+
+		/*
+		 * If the next token is a parenthesis, then this
+		 * is a function.
+		 */
+		if (type == EVENT_DELIM && strcmp(token, "(") == 0) {
+			free_token(token);
+			token = NULL;
+			/* this will free atom. */
+			type = process_function(event, arg, atom, &token);
+			break;
+		}
+		/* atoms can be more than one token long */
+		while (type == EVENT_ITEM) {
+			atom = realloc(atom, strlen(atom) + strlen(token) + 2);
+			strcat(atom, " ");
+			strcat(atom, token);
+			free_token(token);
+			type = read_token_item(&token);
+		}
+
+		arg->type = PRINT_ATOM;
+		arg->atom.atom = atom;
+		break;
+
+	case EVENT_DQUOTE:
+	case EVENT_SQUOTE:
+		arg->type = PRINT_ATOM;
+		arg->atom.atom = token;
+		type = read_token_item(&token);
+		break;
+	case EVENT_DELIM:
+		if (strcmp(token, "(") == 0) {
+			free_token(token);
+			type = process_paren(event, arg, &token);
+			break;
+		}
+	case EVENT_OP:
+		/* handle single ops */
+		arg->type = PRINT_OP;
+		arg->op.op = token;
+		arg->op.left = NULL;
+		type = process_op(event, arg, &token);
+
+		/* On error, the op is freed */
+		if (type == EVENT_ERROR)
+			arg->op.op = NULL;
+
+		/* return error type if errored */
+		break;
+
+	case EVENT_ERROR ... EVENT_NEWLINE:
+	default:
+		die("unexpected type %d", type);
+	}
+	*tok = token;
+
+	return type;
+}
+
+static int event_read_print_args(struct event_format *event, struct print_arg **list)
+{
+	enum event_type type = EVENT_ERROR;
+	struct print_arg *arg;
+	char *token;
+	int args = 0;
+
+	do {
+		if (type == EVENT_NEWLINE) {
+			type = read_token_item(&token);
+			continue;
+		}
+
+		arg = alloc_arg();
+
+		type = process_arg(event, arg, &token);
+
+		if (type == EVENT_ERROR) {
+			free_token(token);
+			free_arg(arg);
+			return -1;
+		}
+
+		*list = arg;
+		args++;
+
+		if (type == EVENT_OP) {
+			type = process_op(event, arg, &token);
+			free_token(token);
+			if (type == EVENT_ERROR) {
+				*list = NULL;
+				free_arg(arg);
+				return -1;
+			}
+			list = &arg->next;
+			continue;
+		}
+
+		if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
+			free_token(token);
+			*list = arg;
+			list = &arg->next;
+			continue;
+		}
+		break;
+	} while (type != EVENT_NONE);
+
+	if (type != EVENT_NONE && type != EVENT_ERROR)
+		free_token(token);
+
+	return args;
+}
+
+static int event_read_print(struct event_format *event)
+{
+	enum event_type type;
+	char *token;
+	int ret;
+
+	if (read_expected_item(EVENT_ITEM, "print") < 0)
+		return -1;
+
+	if (read_expected(EVENT_ITEM, "fmt") < 0)
+		return -1;
+
+	if (read_expected(EVENT_OP, ":") < 0)
+		return -1;
+
+	if (read_expect_type(EVENT_DQUOTE, &token) < 0)
+		goto fail;
+
+ concat:
+	event->print_fmt.format = token;
+	event->print_fmt.args = NULL;
+
+	/* ok to have no arg */
+	type = read_token_item(&token);
+
+	if (type == EVENT_NONE)
+		return 0;
+
+	/* Handle concatenation of print lines */
+	if (type == EVENT_DQUOTE) {
+		char *cat;
+
+		cat = malloc_or_die(strlen(event->print_fmt.format) +
+				    strlen(token) + 1);
+		strcpy(cat, event->print_fmt.format);
+		strcat(cat, token);
+		free_token(token);
+		free_token(event->print_fmt.format);
+		event->print_fmt.format = NULL;
+		token = cat;
+		goto concat;
+	}
+			     
+	if (test_type_token(type, token, EVENT_DELIM, ","))
+		goto fail;
+
+	free_token(token);
+
+	ret = event_read_print_args(event, &event->print_fmt.args);
+	if (ret < 0)
+		return -1;
+
+	return ret;
+
+ fail:
+	free_token(token);
+	return -1;
+}
+
+/**
+ * pevent_find_common_field - return a common field by event
+ * @event: handle for the event
+ * @name: the name of the common field to return
+ *
+ * Returns a common field from the event by the given @name.
+ * This only searchs the common fields and not all field.
+ */
+struct format_field *
+pevent_find_common_field(struct event_format *event, const char *name)
+{
+	struct format_field *format;
+
+	for (format = event->format.common_fields;
+	     format; format = format->next) {
+		if (strcmp(format->name, name) == 0)
+			break;
+	}
+
+	return format;
+}
+
+/**
+ * pevent_find_field - find a non-common field
+ * @event: handle for the event
+ * @name: the name of the non-common field
+ *
+ * Returns a non-common field by the given @name.
+ * This does not search common fields.
+ */
+struct format_field *
+pevent_find_field(struct event_format *event, const char *name)
+{
+	struct format_field *format;
+
+	for (format = event->format.fields;
+	     format; format = format->next) {
+		if (strcmp(format->name, name) == 0)
+			break;
+	}
+
+	return format;
+}
+
+/**
+ * pevent_find_any_field - find any field by name
+ * @event: handle for the event
+ * @name: the name of the field
+ *
+ * Returns a field by the given @name.
+ * This searchs the common field names first, then
+ * the non-common ones if a common one was not found.
+ */
+struct format_field *
+pevent_find_any_field(struct event_format *event, const char *name)
+{
+	struct format_field *format;
+
+	format = pevent_find_common_field(event, name);
+	if (format)
+		return format;
+	return pevent_find_field(event, name);
+}
+
+/**
+ * pevent_read_number - read a number from data
+ * @pevent: handle for the pevent
+ * @ptr: the raw data
+ * @size: the size of the data that holds the number
+ *
+ * Returns the number (converted to host) from the
+ * raw data.
+ */
+unsigned long long pevent_read_number(struct pevent *pevent,
+				      const void *ptr, int size)
+{
+	switch (size) {
+	case 1:
+		return *(unsigned char *)ptr;
+	case 2:
+		return data2host2(pevent, ptr);
+	case 4:
+		return data2host4(pevent, ptr);
+	case 8:
+		return data2host8(pevent, ptr);
+	default:
+		/* BUG! */
+		return 0;
+	}
+}
+
+/**
+ * pevent_read_number_field - read a number from data
+ * @field: a handle to the field
+ * @data: the raw data to read
+ * @value: the value to place the number in
+ *
+ * Reads raw data according to a field offset and size,
+ * and translates it into @value.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int pevent_read_number_field(struct format_field *field, const void *data,
+			     unsigned long long *value)
+{
+	if (!field)
+		return -1;
+	switch (field->size) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		*value = pevent_read_number(field->event->pevent,
+					    data + field->offset, field->size);
+		return 0;
+	default:
+		return -1;
+	}
+}
+
+static int get_common_info(struct pevent *pevent,
+			   const char *type, int *offset, int *size)
+{
+	struct event_format *event;
+	struct format_field *field;
+
+	/*
+	 * All events should have the same common elements.
+	 * Pick any event to find where the type is;
+	 */
+	if (!pevent->events)
+		die("no event_list!");
+
+	event = pevent->events[0];
+	field = pevent_find_common_field(event, type);
+	if (!field)
+		die("field '%s' not found", type);
+
+	*offset = field->offset;
+	*size = field->size;
+
+	return 0;
+}
+
+static int __parse_common(struct pevent *pevent, void *data,
+			  int *size, int *offset, const char *name)
+{
+	int ret;
+
+	if (!*size) {
+		ret = get_common_info(pevent, name, offset, size);
+		if (ret < 0)
+			return ret;
+	}
+	return pevent_read_number(pevent, data + *offset, *size);
+}
+
+static int trace_parse_common_type(struct pevent *pevent, void *data)
+{
+	return __parse_common(pevent, data,
+			      &pevent->type_size, &pevent->type_offset,
+			      "common_type");
+}
+
+static int parse_common_pid(struct pevent *pevent, void *data)
+{
+	return __parse_common(pevent, data,
+			      &pevent->pid_size, &pevent->pid_offset,
+			      "common_pid");
+}
+
+static int parse_common_pc(struct pevent *pevent, void *data)
+{
+	return __parse_common(pevent, data,
+			      &pevent->pc_size, &pevent->pc_offset,
+			      "common_preempt_count");
+}
+
+static int parse_common_flags(struct pevent *pevent, void *data)
+{
+	return __parse_common(pevent, data,
+			      &pevent->flags_size, &pevent->flags_offset,
+			      "common_flags");
+}
+
+static int parse_common_lock_depth(struct pevent *pevent, void *data)
+{
+	int ret;
+
+	ret = __parse_common(pevent, data,
+			     &pevent->ld_size, &pevent->ld_offset,
+			     "common_lock_depth");
+	if (ret < 0)
+		return -1;
+
+	return ret;
+}
+
+static int events_id_cmp(const void *a, const void *b);
+
+/**
+ * pevent_find_event - find an event by given id
+ * @pevent: a handle to the pevent
+ * @id: the id of the event
+ *
+ * Returns an event that has a given @id.
+ */
+struct event_format *pevent_find_event(struct pevent *pevent, int id)
+{
+	struct event_format **eventptr;
+	struct event_format key;
+	struct event_format *pkey = &key;
+
+	/* Check cache first */
+	if (pevent->last_event && pevent->last_event->id == id)
+		return pevent->last_event;
+
+	key.id = id;
+
+	eventptr = bsearch(&pkey, pevent->events, pevent->nr_events,
+			   sizeof(*pevent->events), events_id_cmp);
+
+	if (eventptr) {
+		pevent->last_event = *eventptr;
+		return *eventptr;
+	}
+
+	return NULL;
+}
+
+/**
+ * pevent_find_event_by_name - find an event by given name
+ * @pevent: a handle to the pevent
+ * @sys: the system name to search for
+ * @name: the name of the event to search for
+ *
+ * This returns an event with a given @name and under the system
+ * @sys. If @sys is NULL the first event with @name is returned.
+ */
+struct event_format *
+pevent_find_event_by_name(struct pevent *pevent,
+			  const char *sys, const char *name)
+{
+	struct event_format *event;
+	int i;
+
+	if (pevent->last_event &&
+	    strcmp(pevent->last_event->name, name) == 0 &&
+	    (!sys || strcmp(pevent->last_event->system, sys) == 0))
+		return pevent->last_event;
+
+	for (i = 0; i < pevent->nr_events; i++) {
+		event = pevent->events[i];
+		if (strcmp(event->name, name) == 0) {
+			if (!sys)
+				break;
+			if (strcmp(event->system, sys) == 0)
+				break;
+		}
+	}
+	if (i == pevent->nr_events)
+		event = NULL;
+
+	pevent->last_event = event;
+	return event;
+}
+
+static unsigned long long
+eval_num_arg(void *data, int size, struct event_format *event, struct print_arg *arg)
+{
+	struct pevent *pevent = event->pevent;
+	unsigned long long val = 0;
+	unsigned long long left, right;
+	struct print_arg *typearg = NULL;
+	struct print_arg *larg;
+	unsigned long offset;
+	unsigned int field_size;
+
+	switch (arg->type) {
+	case PRINT_NULL:
+		/* ?? */
+		return 0;
+	case PRINT_ATOM:
+		return strtoull(arg->atom.atom, NULL, 0);
+	case PRINT_FIELD:
+		if (!arg->field.field) {
+			arg->field.field = pevent_find_any_field(event, arg->field.name);
+			if (!arg->field.field)
+				die("field %s not found", arg->field.name);
+		}
+		/* must be a number */
+		val = pevent_read_number(pevent, data + arg->field.field->offset,
+				arg->field.field->size);
+		break;
+	case PRINT_FLAGS:
+	case PRINT_SYMBOL:
+		break;
+	case PRINT_TYPE:
+		val = eval_num_arg(data, size, event, arg->typecast.item);
+		return eval_type(val, arg, 0);
+	case PRINT_STRING:
+	case PRINT_BSTRING:
+		return 0;
+	case PRINT_FUNC: {
+		struct trace_seq s;
+		trace_seq_init(&s);
+		val = process_defined_func(&s, data, size, event, arg);
+		trace_seq_destroy(&s);
+		return val;
+	}
+	case PRINT_OP:
+		if (strcmp(arg->op.op, "[") == 0) {
+			/*
+			 * Arrays are special, since we don't want
+			 * to read the arg as is.
+			 */
+			right = eval_num_arg(data, size, event, arg->op.right);
+
+			/* handle typecasts */
+			larg = arg->op.left;
+			while (larg->type == PRINT_TYPE) {
+				if (!typearg)
+					typearg = larg;
+				larg = larg->typecast.item;
+			}
+
+			/* Default to long size */
+			field_size = pevent->long_size;
+
+			switch (larg->type) {
+			case PRINT_DYNAMIC_ARRAY:
+				offset = pevent_read_number(pevent,
+						   data + larg->dynarray.field->offset,
+						   larg->dynarray.field->size);
+				if (larg->dynarray.field->elementsize)
+					field_size = larg->dynarray.field->elementsize;
+				/*
+				 * The actual length of the dynamic array is stored
+				 * in the top half of the field, and the offset
+				 * is in the bottom half of the 32 bit field.
+				 */
+				offset &= 0xffff;
+				offset += right;
+				break;
+			case PRINT_FIELD:
+				if (!larg->field.field) {
+					larg->field.field =
+						pevent_find_any_field(event, larg->field.name);
+					if (!larg->field.field)
+						die("field %s not found", larg->field.name);
+				}
+				field_size = larg->field.field->elementsize;
+				offset = larg->field.field->offset +
+					right * larg->field.field->elementsize;
+				break;
+			default:
+				goto default_op; /* oops, all bets off */
+			}
+			val = pevent_read_number(pevent,
+						 data + offset, field_size);
+			if (typearg)
+				val = eval_type(val, typearg, 1);
+			break;
+		} else if (strcmp(arg->op.op, "?") == 0) {
+			left = eval_num_arg(data, size, event, arg->op.left);
+			arg = arg->op.right;
+			if (left)
+				val = eval_num_arg(data, size, event, arg->op.left);
+			else
+				val = eval_num_arg(data, size, event, arg->op.right);
+			break;
+		}
+ default_op:
+		left = eval_num_arg(data, size, event, arg->op.left);
+		right = eval_num_arg(data, size, event, arg->op.right);
+		switch (arg->op.op[0]) {
+		case '!':
+			switch (arg->op.op[1]) {
+			case 0:
+				val = !right;
+				break;
+			case '=':
+				val = left != right;
+				break;
+			default:
+				die("unknown op '%s'", arg->op.op);
+			}
+			break;
+		case '~':
+			val = ~right;
+			break;
+		case '|':
+			if (arg->op.op[1])
+				val = left || right;
+			else
+				val = left | right;
+			break;
+		case '&':
+			if (arg->op.op[1])
+				val = left && right;
+			else
+				val = left & right;
+			break;
+		case '<':
+			switch (arg->op.op[1]) {
+			case 0:
+				val = left < right;
+				break;
+			case '<':
+				val = left << right;
+				break;
+			case '=':
+				val = left <= right;
+				break;
+			default:
+				die("unknown op '%s'", arg->op.op);
+			}
+			break;
+		case '>':
+			switch (arg->op.op[1]) {
+			case 0:
+				val = left > right;
+				break;
+			case '>':
+				val = left >> right;
+				break;
+			case '=':
+				val = left >= right;
+				break;
+			default:
+				die("unknown op '%s'", arg->op.op);
+			}
+			break;
+		case '=':
+			if (arg->op.op[1] != '=')
+				die("unknown op '%s'", arg->op.op);
+			val = left == right;
+			break;
+		case '-':
+			val = left - right;
+			break;
+		case '+':
+			val = left + right;
+			break;
+		case '/':
+			val = left / right;
+			break;
+		case '*':
+			val = left * right;
+			break;
+		default:
+			die("unknown op '%s'", arg->op.op);
+		}
+		break;
+	default: /* not sure what to do there */
+		return 0;
+	}
+	return val;
+}
+
+struct flag {
+	const char *name;
+	unsigned long long value;
+};
+
+static const struct flag flags[] = {
+	{ "HI_SOFTIRQ", 0 },
+	{ "TIMER_SOFTIRQ", 1 },
+	{ "NET_TX_SOFTIRQ", 2 },
+	{ "NET_RX_SOFTIRQ", 3 },
+	{ "BLOCK_SOFTIRQ", 4 },
+	{ "BLOCK_IOPOLL_SOFTIRQ", 5 },
+	{ "TASKLET_SOFTIRQ", 6 },
+	{ "SCHED_SOFTIRQ", 7 },
+	{ "HRTIMER_SOFTIRQ", 8 },
+	{ "RCU_SOFTIRQ", 9 },
+
+	{ "HRTIMER_NORESTART", 0 },
+	{ "HRTIMER_RESTART", 1 },
+};
+
+static unsigned long long eval_flag(const char *flag)
+{
+	int i;
+
+	/*
+	 * Some flags in the format files do not get converted.
+	 * If the flag is not numeric, see if it is something that
+	 * we already know about.
+	 */
+	if (isdigit(flag[0]))
+		return strtoull(flag, NULL, 0);
+
+	for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
+		if (strcmp(flags[i].name, flag) == 0)
+			return flags[i].value;
+
+	return 0;
+}
+
+static void print_str_to_seq(struct trace_seq *s, const char *format,
+			     int len_arg, const char *str)
+{
+	if (len_arg >= 0)
+		trace_seq_printf(s, format, len_arg, str);
+	else
+		trace_seq_printf(s, format, str);
+}
+
+static void print_str_arg(struct trace_seq *s, void *data, int size,
+			  struct event_format *event, const char *format,
+			  int len_arg, struct print_arg *arg)
+{
+	struct pevent *pevent = event->pevent;
+	struct print_flag_sym *flag;
+	unsigned long long val, fval;
+	unsigned long addr;
+	char *str;
+	int print;
+	int len;
+
+	switch (arg->type) {
+	case PRINT_NULL:
+		/* ?? */
+		return;
+	case PRINT_ATOM:
+		print_str_to_seq(s, format, len_arg, arg->atom.atom);
+		return;
+	case PRINT_FIELD:
+		if (!arg->field.field) {
+			arg->field.field = pevent_find_any_field(event, arg->field.name);
+			if (!arg->field.field)
+				die("field %s not found", arg->field.name);
+		}
+		/* Zero sized fields, mean the rest of the data */
+		len = arg->field.field->size ? : size - arg->field.field->offset;
+
+		/*
+		 * Some events pass in pointers. If this is not an array
+		 * and the size is the same as long_size, assume that it
+		 * is a pointer.
+		 */
+		if (!(arg->field.field->flags & FIELD_IS_ARRAY) &&
+		    arg->field.field->size == pevent->long_size) {
+			addr = *(unsigned long *)(data + arg->field.field->offset);
+			trace_seq_printf(s, "%lx", addr);
+			break;
+		}
+		str = malloc_or_die(len + 1);
+		memcpy(str, data + arg->field.field->offset, len);
+		str[len] = 0;
+		print_str_to_seq(s, format, len_arg, str);
+		free(str);
+		break;
+	case PRINT_FLAGS:
+		val = eval_num_arg(data, size, event, arg->flags.field);
+		print = 0;
+		for (flag = arg->flags.flags; flag; flag = flag->next) {
+			fval = eval_flag(flag->value);
+			if (!val && !fval) {
+				print_str_to_seq(s, format, len_arg, flag->str);
+				break;
+			}
+			if (fval && (val & fval) == fval) {
+				if (print && arg->flags.delim)
+					trace_seq_puts(s, arg->flags.delim);
+				print_str_to_seq(s, format, len_arg, flag->str);
+				print = 1;
+				val &= ~fval;
+			}
+		}
+		break;
+	case PRINT_SYMBOL:
+		val = eval_num_arg(data, size, event, arg->symbol.field);
+		for (flag = arg->symbol.symbols; flag; flag = flag->next) {
+			fval = eval_flag(flag->value);
+			if (val == fval) {
+				print_str_to_seq(s, format, len_arg, flag->str);
+				break;
+			}
+		}
+		break;
+
+	case PRINT_TYPE:
+		break;
+	case PRINT_STRING: {
+		int str_offset;
+
+		if (arg->string.offset == -1) {
+			struct format_field *f;
+
+			f = pevent_find_any_field(event, arg->string.string);
+			arg->string.offset = f->offset;
+		}
+		str_offset = data2host4(pevent, data + arg->string.offset);
+		str_offset &= 0xffff;
+		print_str_to_seq(s, format, len_arg, ((char *)data) + str_offset);
+		break;
+	}
+	case PRINT_BSTRING:
+		trace_seq_printf(s, format, arg->string.string);
+		break;
+	case PRINT_OP:
+		/*
+		 * The only op for string should be ? :
+		 */
+		if (arg->op.op[0] != '?')
+			return;
+		val = eval_num_arg(data, size, event, arg->op.left);
+		if (val)
+			print_str_arg(s, data, size, event,
+				      format, len_arg, arg->op.right->op.left);
+		else
+			print_str_arg(s, data, size, event,
+				      format, len_arg, arg->op.right->op.right);
+		break;
+	case PRINT_FUNC:
+		process_defined_func(s, data, size, event, arg);
+		break;
+	default:
+		/* well... */
+		break;
+	}
+}
+
+static unsigned long long
+process_defined_func(struct trace_seq *s, void *data, int size,
+		     struct event_format *event, struct print_arg *arg)
+{
+	struct pevent_function_handler *func_handle = arg->func.func;
+	struct pevent_func_params *param;
+	unsigned long long *args;
+	unsigned long long ret;
+	struct print_arg *farg;
+	struct trace_seq str;
+	struct save_str {
+		struct save_str *next;
+		char *str;
+	} *strings = NULL, *string;
+	int i;
+
+	if (!func_handle->nr_args) {
+		ret = (*func_handle->func)(s, NULL);
+		goto out;
+	}
+
+	farg = arg->func.args;
+	param = func_handle->params;
+
+	args = malloc_or_die(sizeof(*args) * func_handle->nr_args);
+	for (i = 0; i < func_handle->nr_args; i++) {
+		switch (param->type) {
+		case PEVENT_FUNC_ARG_INT:
+		case PEVENT_FUNC_ARG_LONG:
+		case PEVENT_FUNC_ARG_PTR:
+			args[i] = eval_num_arg(data, size, event, farg);
+			break;
+		case PEVENT_FUNC_ARG_STRING:
+			trace_seq_init(&str);
+			print_str_arg(&str, data, size, event, "%s", -1, farg);
+			trace_seq_terminate(&str);
+			string = malloc_or_die(sizeof(*string));
+			string->next = strings;
+			string->str = strdup(str.buffer);
+			strings = string;
+			trace_seq_destroy(&str);
+			break;
+		default:
+			/*
+			 * Something went totally wrong, this is not
+			 * an input error, something in this code broke.
+			 */
+			die("Unexpected end of arguments\n");
+			break;
+		}
+		farg = farg->next;
+	}
+
+	ret = (*func_handle->func)(s, args);
+	free(args);
+	while (strings) {
+		string = strings;
+		strings = string->next;
+		free(string->str);
+		free(string);
+	}
+
+ out:
+	/* TBD : handle return type here */
+	return ret;
+}
+
+static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event)
+{
+	struct pevent *pevent = event->pevent;
+	struct format_field *field, *ip_field;
+	struct print_arg *args, *arg, **next;
+	unsigned long long ip, val;
+	char *ptr;
+	void *bptr;
+
+	field = pevent->bprint_buf_field;
+	ip_field = pevent->bprint_ip_field;
+
+	if (!field) {
+		field = pevent_find_field(event, "buf");
+		if (!field)
+			die("can't find buffer field for binary printk");
+		ip_field = pevent_find_field(event, "ip");
+		if (!ip_field)
+			die("can't find ip field for binary printk");
+		pevent->bprint_buf_field = field;
+		pevent->bprint_ip_field = ip_field;
+	}
+
+	ip = pevent_read_number(pevent, data + ip_field->offset, ip_field->size);
+
+	/*
+	 * The first arg is the IP pointer.
+	 */
+	args = alloc_arg();
+	arg = args;
+	arg->next = NULL;
+	next = &arg->next;
+
+	arg->type = PRINT_ATOM;
+	arg->atom.atom = malloc_or_die(32);
+	sprintf(arg->atom.atom, "%lld", ip);
+
+	/* skip the first "%pf : " */
+	for (ptr = fmt + 6, bptr = data + field->offset;
+	     bptr < data + size && *ptr; ptr++) {
+		int ls = 0;
+
+		if (*ptr == '%') {
+ process_again:
+			ptr++;
+			switch (*ptr) {
+			case '%':
+				break;
+			case 'l':
+				ls++;
+				goto process_again;
+			case 'L':
+				ls = 2;
+				goto process_again;
+			case '0' ... '9':
+				goto process_again;
+			case 'p':
+				ls = 1;
+				/* fall through */
+			case 'd':
+			case 'u':
+			case 'x':
+			case 'i':
+				/* the pointers are always 4 bytes aligned */
+				bptr = (void *)(((unsigned long)bptr + 3) &
+						~3);
+				switch (ls) {
+				case 0:
+					ls = 4;
+					break;
+				case 1:
+					ls = pevent->long_size;
+					break;
+				case 2:
+					ls = 8;
+				default:
+					break;
+				}
+				val = pevent_read_number(pevent, bptr, ls);
+				bptr += ls;
+				arg = alloc_arg();
+				arg->next = NULL;
+				arg->type = PRINT_ATOM;
+				arg->atom.atom = malloc_or_die(32);
+				sprintf(arg->atom.atom, "%lld", val);
+				*next = arg;
+				next = &arg->next;
+				break;
+			case 's':
+				arg = alloc_arg();
+				arg->next = NULL;
+				arg->type = PRINT_BSTRING;
+				arg->string.string = strdup(bptr);
+				bptr += strlen(bptr) + 1;
+				*next = arg;
+				next = &arg->next;
+			default:
+				break;
+			}
+		}
+	}
+
+	return args;
+}
+
+static void free_args(struct print_arg *args)
+{
+	struct print_arg *next;
+
+	while (args) {
+		next = args->next;
+
+		free_arg(args);
+		args = next;
+	}
+}
+
+static char *
+get_bprint_format(void *data, int size __unused, struct event_format *event)
+{
+	struct pevent *pevent = event->pevent;
+	unsigned long long addr;
+	struct format_field *field;
+	struct printk_map *printk;
+	char *format;
+	char *p;
+
+	field = pevent->bprint_fmt_field;
+
+	if (!field) {
+		field = pevent_find_field(event, "fmt");
+		if (!field)
+			die("can't find format field for binary printk");
+		pevent->bprint_fmt_field = field;
+	}
+
+	addr = pevent_read_number(pevent, data + field->offset, field->size);
+
+	printk = find_printk(pevent, addr);
+	if (!printk) {
+		format = malloc_or_die(45);
+		sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
+			addr);
+		return format;
+	}
+
+	p = printk->printk;
+	/* Remove any quotes. */
+	if (*p == '"')
+		p++;
+	format = malloc_or_die(strlen(p) + 10);
+	sprintf(format, "%s : %s", "%pf", p);
+	/* remove ending quotes and new line since we will add one too */
+	p = format + strlen(format) - 1;
+	if (*p == '"')
+		*p = 0;
+
+	p -= 2;
+	if (strcmp(p, "\\n") == 0)
+		*p = 0;
+
+	return format;
+}
+
+static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
+			  struct event_format *event, struct print_arg *arg)
+{
+	unsigned char *buf;
+	char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x";
+
+	if (arg->type == PRINT_FUNC) {
+		process_defined_func(s, data, size, event, arg);
+		return;
+	}
+
+	if (arg->type != PRINT_FIELD) {
+		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d",
+				 arg->type);
+		return;
+	}
+
+	if (mac == 'm')
+		fmt = "%.2x%.2x%.2x%.2x%.2x%.2x";
+	if (!arg->field.field) {
+		arg->field.field =
+			pevent_find_any_field(event, arg->field.name);
+		if (!arg->field.field)
+			die("field %s not found", arg->field.name);
+	}
+	if (arg->field.field->size != 6) {
+		trace_seq_printf(s, "INVALIDMAC");
+		return;
+	}
+	buf = data + arg->field.field->offset;
+	trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+}
+
+static void print_event_fields(struct trace_seq *s, void *data, int size,
+			       struct event_format *event)
+{
+	struct format_field *field;
+	unsigned long long val;
+	unsigned int offset, len, i;
+
+	field = event->format.fields;
+	while (field) {
+		trace_seq_printf(s, " %s=", field->name);
+		if (field->flags & FIELD_IS_ARRAY) {
+			offset = field->offset;
+			len = field->size;
+			if (field->flags & FIELD_IS_DYNAMIC) {
+				val = pevent_read_number(event->pevent, data + offset, len);
+				offset = val;
+				len = offset >> 16;
+				offset &= 0xffff;
+			}
+			if (field->flags & FIELD_IS_STRING) {
+				trace_seq_printf(s, "%s", (char *)data + offset);
+			} else {
+				trace_seq_puts(s, "ARRAY[");
+				for (i = 0; i < len; i++) {
+					if (i)
+						trace_seq_puts(s, ", ");
+					trace_seq_printf(s, "%02x",
+							 *((unsigned char *)data + offset + i));
+				}
+				trace_seq_putc(s, ']');
+			}
+		} else {
+			val = pevent_read_number(event->pevent, data + field->offset,
+						 field->size);
+			if (field->flags & FIELD_IS_POINTER) {
+				trace_seq_printf(s, "0x%llx", val);
+			} else if (field->flags & FIELD_IS_SIGNED) {
+				switch (field->size) {
+				case 4:
+					/*
+					 * If field is long then print it in hex.
+					 * A long usually stores pointers.
+					 */
+					if (field->flags & FIELD_IS_LONG)
+						trace_seq_printf(s, "0x%x", (int)val);
+					else
+						trace_seq_printf(s, "%d", (int)val);
+					break;
+				case 2:
+					trace_seq_printf(s, "%2d", (short)val);
+					break;
+				case 1:
+					trace_seq_printf(s, "%1d", (char)val);
+					break;
+				default:
+					trace_seq_printf(s, "%lld", val);
+				}
+			} else {
+				if (field->flags & FIELD_IS_LONG)
+					trace_seq_printf(s, "0x%llx", val);
+				else
+					trace_seq_printf(s, "%llu", val);
+			}
+		}
+		field = field->next;
+	}
+}
+
+static void pretty_print(struct trace_seq *s, void *data, int size, struct event_format *event)
+{
+	struct pevent *pevent = event->pevent;
+	struct print_fmt *print_fmt = &event->print_fmt;
+	struct print_arg *arg = print_fmt->args;
+	struct print_arg *args = NULL;
+	const char *ptr = print_fmt->format;
+	unsigned long long val;
+	struct func_map *func;
+	const char *saveptr;
+	char *bprint_fmt = NULL;
+	char format[32];
+	int show_func;
+	int len_as_arg;
+	int len_arg;
+	int len;
+	int ls;
+
+	if (event->flags & EVENT_FL_FAILED) {
+		trace_seq_printf(s, "[FAILED TO PARSE]");
+		print_event_fields(s, data, size, event);
+		return;
+	}
+
+	if (event->flags & EVENT_FL_ISBPRINT) {
+		bprint_fmt = get_bprint_format(data, size, event);
+		args = make_bprint_args(bprint_fmt, data, size, event);
+		arg = args;
+		ptr = bprint_fmt;
+	}
+
+	for (; *ptr; ptr++) {
+		ls = 0;
+		if (*ptr == '\\') {
+			ptr++;
+			switch (*ptr) {
+			case 'n':
+				trace_seq_putc(s, '\n');
+				break;
+			case 't':
+				trace_seq_putc(s, '\t');
+				break;
+			case 'r':
+				trace_seq_putc(s, '\r');
+				break;
+			case '\\':
+				trace_seq_putc(s, '\\');
+				break;
+			default:
+				trace_seq_putc(s, *ptr);
+				break;
+			}
+
+		} else if (*ptr == '%') {
+			saveptr = ptr;
+			show_func = 0;
+			len_as_arg = 0;
+ cont_process:
+			ptr++;
+			switch (*ptr) {
+			case '%':
+				trace_seq_putc(s, '%');
+				break;
+			case '#':
+				/* FIXME: need to handle properly */
+				goto cont_process;
+			case 'h':
+				ls--;
+				goto cont_process;
+			case 'l':
+				ls++;
+				goto cont_process;
+			case 'L':
+				ls = 2;
+				goto cont_process;
+			case '*':
+				/* The argument is the length. */
+				if (!arg)
+					die("no argument match");
+				len_arg = eval_num_arg(data, size, event, arg);
+				len_as_arg = 1;
+				arg = arg->next;
+				goto cont_process;
+			case '.':
+			case 'z':
+			case 'Z':
+			case '0' ... '9':
+				goto cont_process;
+			case 'p':
+				if (pevent->long_size == 4)
+					ls = 1;
+				else
+					ls = 2;
+
+				if (*(ptr+1) == 'F' ||
+				    *(ptr+1) == 'f') {
+					ptr++;
+					show_func = *ptr;
+				} else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
+					print_mac_arg(s, *(ptr+1), data, size, event, arg);
+					ptr++;
+					break;
+				}
+
+				/* fall through */
+			case 'd':
+			case 'i':
+			case 'x':
+			case 'X':
+			case 'u':
+				if (!arg)
+					die("no argument match");
+
+				len = ((unsigned long)ptr + 1) -
+					(unsigned long)saveptr;
+
+				/* should never happen */
+				if (len > 31)
+					die("bad format!");
+
+				memcpy(format, saveptr, len);
+				format[len] = 0;
+
+				val = eval_num_arg(data, size, event, arg);
+				arg = arg->next;
+
+				if (show_func) {
+					func = find_func(pevent, val);
+					if (func) {
+						trace_seq_puts(s, func->func);
+						if (show_func == 'F')
+							trace_seq_printf(s,
+							       "+0x%llx",
+							       val - func->addr);
+						break;
+					}
+				}
+				if (pevent->long_size == 8 && ls) {
+					char *p;
+
+					ls = 2;
+					/* make %l into %ll */
+					p = strchr(format, 'l');
+					if (p)
+						memmove(p, p+1, strlen(p)+1);
+					else if (strcmp(format, "%p") == 0)
+						strcpy(format, "0x%llx");
+				}
+				switch (ls) {
+				case -2:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg, (char)val);
+					else
+						trace_seq_printf(s, format, (char)val);
+					break;
+				case -1:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg, (short)val);
+					else
+						trace_seq_printf(s, format, (short)val);
+					break;
+				case 0:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg, (int)val);
+					else
+						trace_seq_printf(s, format, (int)val);
+					break;
+				case 1:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg, (long)val);
+					else
+						trace_seq_printf(s, format, (long)val);
+					break;
+				case 2:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg,
+								 (long long)val);
+					else
+						trace_seq_printf(s, format, (long long)val);
+					break;
+				default:
+					die("bad count (%d)", ls);
+				}
+				break;
+			case 's':
+				if (!arg)
+					die("no matching argument");
+
+				len = ((unsigned long)ptr + 1) -
+					(unsigned long)saveptr;
+
+				/* should never happen */
+				if (len > 31)
+					die("bad format!");
+
+				memcpy(format, saveptr, len);
+				format[len] = 0;
+				if (!len_as_arg)
+					len_arg = -1;
+				print_str_arg(s, data, size, event,
+					      format, len_arg, arg);
+				arg = arg->next;
+				break;
+			default:
+				trace_seq_printf(s, ">%c<", *ptr);
+
+			}
+		} else
+			trace_seq_putc(s, *ptr);
+	}
+
+	if (args) {
+		free_args(args);
+		free(bprint_fmt);
+	}
+}
+
+/**
+ * pevent_data_lat_fmt - parse the data for the latency format
+ * @pevent: a handle to the pevent
+ * @s: the trace_seq to write to
+ * @data: the raw data to read from
+ * @size: currently unused.
+ *
+ * This parses out the Latency format (interrupts disabled,
+ * need rescheduling, in hard/soft interrupt, preempt count
+ * and lock depth) and places it into the trace_seq.
+ */
+void pevent_data_lat_fmt(struct pevent *pevent,
+			 struct trace_seq *s, struct pevent_record *record)
+{
+	static int check_lock_depth = 1;
+	static int lock_depth_exists;
+	unsigned int lat_flags;
+	unsigned int pc;
+	int lock_depth;
+	int hardirq;
+	int softirq;
+	void *data = record->data;
+
+	lat_flags = parse_common_flags(pevent, data);
+	pc = parse_common_pc(pevent, data);
+	/* lock_depth may not always exist */
+	if (check_lock_depth) {
+		struct format_field *field;
+		struct event_format *event;
+
+		check_lock_depth = 0;
+		event = pevent->events[0];
+		field = pevent_find_common_field(event, "common_lock_depth");
+		if (field)
+			lock_depth_exists = 1;
+	}
+	if (lock_depth_exists)
+		lock_depth = parse_common_lock_depth(pevent, data);
+
+	hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
+	softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
+
+	trace_seq_printf(s, "%c%c%c",
+	       (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
+	       (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
+	       'X' : '.',
+	       (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
+	       'N' : '.',
+	       (hardirq && softirq) ? 'H' :
+	       hardirq ? 'h' : softirq ? 's' : '.');
+
+	if (pc)
+		trace_seq_printf(s, "%x", pc);
+	else
+		trace_seq_putc(s, '.');
+
+	if (lock_depth_exists) {
+		if (lock_depth < 0)
+			trace_seq_putc(s, '.');
+		else
+			trace_seq_printf(s, "%d", lock_depth);
+	}
+
+	trace_seq_terminate(s);
+}
+
+/**
+ * pevent_data_type - parse out the given event type
+ * @pevent: a handle to the pevent
+ * @rec: the record to read from
+ *
+ * This returns the event id from the @rec.
+ */
+int pevent_data_type(struct pevent *pevent, struct pevent_record *rec)
+{
+	return trace_parse_common_type(pevent, rec->data);
+}
+
+/**
+ * pevent_data_event_from_type - find the event by a given type
+ * @pevent: a handle to the pevent
+ * @type: the type of the event.
+ *
+ * This returns the event form a given @type;
+ */
+struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type)
+{
+	return pevent_find_event(pevent, type);
+}
+
+/**
+ * pevent_data_pid - parse the PID from raw data
+ * @pevent: a handle to the pevent
+ * @rec: the record to parse
+ *
+ * This returns the PID from a raw data.
+ */
+int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec)
+{
+	return parse_common_pid(pevent, rec->data);
+}
+
+/**
+ * pevent_data_comm_from_pid - return the command line from PID
+ * @pevent: a handle to the pevent
+ * @pid: the PID of the task to search for
+ *
+ * This returns a pointer to the command line that has the given
+ * @pid.
+ */
+const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
+{
+	const char *comm;
+
+	comm = find_cmdline(pevent, pid);
+	return comm;
+}
+
+/**
+ * pevent_data_comm_from_pid - parse the data into the print format
+ * @s: the trace_seq to write to
+ * @event: the handle to the event
+ * @cpu: the cpu the event was recorded on
+ * @data: the raw data
+ * @size: the size of the raw data
+ * @nsecs: the timestamp of the event
+ *
+ * This parses the raw @data using the given @event information and
+ * writes the print format into the trace_seq.
+ */
+void pevent_event_info(struct trace_seq *s, struct event_format *event,
+		       struct pevent_record *record)
+{
+	int print_pretty = 1;
+
+	if (event->pevent->print_raw)
+		print_event_fields(s, record->data, record->size, event);
+	else {
+
+		if (event->handler)
+			print_pretty = event->handler(s, record, event,
+						      event->context);
+
+		if (print_pretty)
+			pretty_print(s, record->data, record->size, event);
+	}
+
+	trace_seq_terminate(s);
+}
+
+void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
+			struct pevent_record *record)
+{
+	static char *spaces = "                    "; /* 20 spaces */
+	struct event_format *event;
+	unsigned long secs;
+	unsigned long usecs;
+	unsigned long nsecs;
+	const char *comm;
+	void *data = record->data;
+	int type;
+	int pid;
+	int len;
+	int p;
+
+	secs = record->ts / NSECS_PER_SEC;
+	nsecs = record->ts - secs * NSECS_PER_SEC;
+
+	if (record->size < 0) {
+		do_warning("ug! negative record size %d", record->size);
+		return;
+	}
+
+	type = trace_parse_common_type(pevent, data);
+
+	event = pevent_find_event(pevent, type);
+	if (!event) {
+		do_warning("ug! no event found for type %d", type);
+		return;
+	}
+
+	pid = parse_common_pid(pevent, data);
+	comm = find_cmdline(pevent, pid);
+
+	if (pevent->latency_format) {
+		trace_seq_printf(s, "%8.8s-%-5d %3d",
+		       comm, pid, record->cpu);
+		pevent_data_lat_fmt(pevent, s, record);
+	} else
+		trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
+
+	if (pevent->flags & PEVENT_NSEC_OUTPUT) {
+		usecs = nsecs;
+		p = 9;
+	} else {
+		usecs = (nsecs + 500) / NSECS_PER_USEC;
+		p = 6;
+	}
+
+	trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name);
+
+	/* Space out the event names evenly. */
+	len = strlen(event->name);
+	if (len < 20)
+		trace_seq_printf(s, "%.*s", 20 - len, spaces);
+
+	pevent_event_info(s, event, record);
+}
+
+static int events_id_cmp(const void *a, const void *b)
+{
+	struct event_format * const * ea = a;
+	struct event_format * const * eb = b;
+
+	if ((*ea)->id < (*eb)->id)
+		return -1;
+
+	if ((*ea)->id > (*eb)->id)
+		return 1;
+
+	return 0;
+}
+
+static int events_name_cmp(const void *a, const void *b)
+{
+	struct event_format * const * ea = a;
+	struct event_format * const * eb = b;
+	int res;
+
+	res = strcmp((*ea)->name, (*eb)->name);
+	if (res)
+		return res;
+
+	res = strcmp((*ea)->system, (*eb)->system);
+	if (res)
+		return res;
+
+	return events_id_cmp(a, b);
+}
+
+static int events_system_cmp(const void *a, const void *b)
+{
+	struct event_format * const * ea = a;
+	struct event_format * const * eb = b;
+	int res;
+
+	res = strcmp((*ea)->system, (*eb)->system);
+	if (res)
+		return res;
+
+	res = strcmp((*ea)->name, (*eb)->name);
+	if (res)
+		return res;
+
+	return events_id_cmp(a, b);
+}
+
+struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type sort_type)
+{
+	struct event_format **events;
+	int (*sort)(const void *a, const void *b);
+
+	events = pevent->sort_events;
+
+	if (events && pevent->last_type == sort_type)
+		return events;
+
+	if (!events) {
+		events = malloc(sizeof(*events) * (pevent->nr_events + 1));
+		if (!events)
+			return NULL;
+
+		memcpy(events, pevent->events, sizeof(*events) * pevent->nr_events);
+		events[pevent->nr_events] = NULL;
+
+		pevent->sort_events = events;
+
+		/* the internal events are sorted by id */
+		if (sort_type == EVENT_SORT_ID) {
+			pevent->last_type = sort_type;
+			return events;
+		}
+	}
+
+	switch (sort_type) {
+	case EVENT_SORT_ID:
+		sort = events_id_cmp;
+		break;
+	case EVENT_SORT_NAME:
+		sort = events_name_cmp;
+		break;
+	case EVENT_SORT_SYSTEM:
+		sort = events_system_cmp;
+		break;
+	default:
+		return events;
+	}
+
+	qsort(events, pevent->nr_events, sizeof(*events), sort);
+	pevent->last_type = sort_type;
+
+	return events;
+}
+
+static struct format_field **
+get_event_fields(const char *type, const char *name,
+		 int count, struct format_field *list)
+{
+	struct format_field **fields;
+	struct format_field *field;
+	int i = 0;
+
+	fields = malloc_or_die(sizeof(*fields) * (count + 1));
+	for (field = list; field; field = field->next) {
+		fields[i++] = field;
+		if (i == count + 1) {
+			do_warning("event %s has more %s fields than specified",
+				name, type);
+			i--;
+			break;
+		}
+	}
+
+	if (i != count)
+		do_warning("event %s has less %s fields than specified",
+			name, type);
+
+	fields[i] = NULL;
+
+	return fields;
+}
+
+/**
+ * pevent_event_common_fields - return a list of common fields for an event
+ * @event: the event to return the common fields of.
+ *
+ * Returns an allocated array of fields. The last item in the array is NULL.
+ * The array must be freed with free().
+ */
+struct format_field **pevent_event_common_fields(struct event_format *event)
+{
+	return get_event_fields("common", event->name,
+				event->format.nr_common,
+				event->format.common_fields);
+}
+
+/**
+ * pevent_event_fields - return a list of event specific fields for an event
+ * @event: the event to return the fields of.
+ *
+ * Returns an allocated array of fields. The last item in the array is NULL.
+ * The array must be freed with free().
+ */
+struct format_field **pevent_event_fields(struct event_format *event)
+{
+	return get_event_fields("event", event->name,
+				event->format.nr_fields,
+				event->format.fields);
+}
+
+static void print_fields(struct trace_seq *s, struct print_flag_sym *field)
+{
+	trace_seq_printf(s, "{ %s, %s }", field->value, field->str);
+	if (field->next) {
+		trace_seq_puts(s, ", ");
+		print_fields(s, field->next);
+	}
+}
+
+/* for debugging */
+static void print_args(struct print_arg *args)
+{
+	int print_paren = 1;
+	struct trace_seq s;
+
+	switch (args->type) {
+	case PRINT_NULL:
+		printf("null");
+		break;
+	case PRINT_ATOM:
+		printf("%s", args->atom.atom);
+		break;
+	case PRINT_FIELD:
+		printf("REC->%s", args->field.name);
+		break;
+	case PRINT_FLAGS:
+		printf("__print_flags(");
+		print_args(args->flags.field);
+		printf(", %s, ", args->flags.delim);
+		trace_seq_init(&s);
+		print_fields(&s, args->flags.flags);
+		trace_seq_do_printf(&s);
+		trace_seq_destroy(&s);
+		printf(")");
+		break;
+	case PRINT_SYMBOL:
+		printf("__print_symbolic(");
+		print_args(args->symbol.field);
+		printf(", ");
+		trace_seq_init(&s);
+		print_fields(&s, args->symbol.symbols);
+		trace_seq_do_printf(&s);
+		trace_seq_destroy(&s);
+		printf(")");
+		break;
+	case PRINT_STRING:
+	case PRINT_BSTRING:
+		printf("__get_str(%s)", args->string.string);
+		break;
+	case PRINT_TYPE:
+		printf("(%s)", args->typecast.type);
+		print_args(args->typecast.item);
+		break;
+	case PRINT_OP:
+		if (strcmp(args->op.op, ":") == 0)
+			print_paren = 0;
+		if (print_paren)
+			printf("(");
+		print_args(args->op.left);
+		printf(" %s ", args->op.op);
+		print_args(args->op.right);
+		if (print_paren)
+			printf(")");
+		break;
+	default:
+		/* we should warn... */
+		return;
+	}
+	if (args->next) {
+		printf("\n");
+		print_args(args->next);
+	}
+}
+
+static void parse_header_field(const char *field,
+			       int *offset, int *size, int mandatory)
+{
+	unsigned long long save_input_buf_ptr;
+	unsigned long long save_input_buf_siz;
+	char *token;
+	int type;
+
+	save_input_buf_ptr = input_buf_ptr;
+	save_input_buf_siz = input_buf_siz;
+
+	if (read_expected(EVENT_ITEM, "field") < 0)
+		return;
+	if (read_expected(EVENT_OP, ":") < 0)
+		return;
+
+	/* type */
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+	free_token(token);
+
+	/*
+	 * If this is not a mandatory field, then test it first.
+	 */
+	if (mandatory) {
+		if (read_expected(EVENT_ITEM, field) < 0)
+			return;
+	} else {
+		if (read_expect_type(EVENT_ITEM, &token) < 0)
+			goto fail;
+		if (strcmp(token, field) != 0)
+			goto discard;
+		free_token(token);
+	}
+
+	if (read_expected(EVENT_OP, ";") < 0)
+		return;
+	if (read_expected(EVENT_ITEM, "offset") < 0)
+		return;
+	if (read_expected(EVENT_OP, ":") < 0)
+		return;
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+	*offset = atoi(token);
+	free_token(token);
+	if (read_expected(EVENT_OP, ";") < 0)
+		return;
+	if (read_expected(EVENT_ITEM, "size") < 0)
+		return;
+	if (read_expected(EVENT_OP, ":") < 0)
+		return;
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+	*size = atoi(token);
+	free_token(token);
+	if (read_expected(EVENT_OP, ";") < 0)
+		return;
+	type = read_token(&token);
+	if (type != EVENT_NEWLINE) {
+		/* newer versions of the kernel have a "signed" type */
+		if (type != EVENT_ITEM)
+			goto fail;
+
+		if (strcmp(token, "signed") != 0)
+			goto fail;
+
+		free_token(token);
+
+		if (read_expected(EVENT_OP, ":") < 0)
+			return;
+
+		if (read_expect_type(EVENT_ITEM, &token))
+			goto fail;
+
+		free_token(token);
+		if (read_expected(EVENT_OP, ";") < 0)
+			return;
+
+		if (read_expect_type(EVENT_NEWLINE, &token))
+			goto fail;
+	}
+ fail:
+	free_token(token);
+	return;
+
+ discard:
+	input_buf_ptr = save_input_buf_ptr;
+	input_buf_siz = save_input_buf_siz;
+	*offset = 0;
+	*size = 0;
+	free_token(token);
+}
+
+/**
+ * pevent_parse_header_page - parse the data stored in the header page
+ * @pevent: the handle to the pevent
+ * @buf: the buffer storing the header page format string
+ * @size: the size of @buf
+ * @long_size: the long size to use if there is no header
+ *
+ * This parses the header page format for information on the
+ * ring buffer used. The @buf should be copied from
+ *
+ * /sys/kernel/debug/tracing/events/header_page
+ */
+int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
+			     int long_size)
+{
+	int ignore;
+
+	if (!size) {
+		/*
+		 * Old kernels did not have header page info.
+		 * Sorry but we just use what we find here in user space.
+		 */
+		pevent->header_page_ts_size = sizeof(long long);
+		pevent->header_page_size_size = long_size;
+		pevent->header_page_data_offset = sizeof(long long) + long_size;
+		pevent->old_format = 1;
+		return -1;
+	}
+	init_input_buf(buf, size);
+
+	parse_header_field("timestamp", &pevent->header_page_ts_offset,
+			   &pevent->header_page_ts_size, 1);
+	parse_header_field("commit", &pevent->header_page_size_offset,
+			   &pevent->header_page_size_size, 1);
+	parse_header_field("overwrite", &pevent->header_page_overwrite,
+			   &ignore, 0);
+	parse_header_field("data", &pevent->header_page_data_offset,
+			   &pevent->header_page_data_size, 1);
+
+	return 0;
+}
+
+static int event_matches(struct event_format *event,
+			 int id, const char *sys_name,
+			 const char *event_name)
+{
+	if (id >= 0 && id != event->id)
+		return 0;
+
+	if (event_name && (strcmp(event_name, event->name) != 0))
+		return 0;
+
+	if (sys_name && (strcmp(sys_name, event->system) != 0))
+		return 0;
+
+	return 1;
+}
+
+static void free_handler(struct event_handler *handle)
+{
+	free((void *)handle->sys_name);
+	free((void *)handle->event_name);
+	free(handle);
+}
+
+static int find_event_handle(struct pevent *pevent, struct event_format *event)
+{
+	struct event_handler *handle, **next;
+
+	for (next = &pevent->handlers; *next;
+	     next = &(*next)->next) {
+		handle = *next;
+		if (event_matches(event, handle->id,
+				  handle->sys_name,
+				  handle->event_name))
+			break;
+	}
+
+	if (!(*next))
+		return 0;
+
+	pr_stat("overriding event (%d) %s:%s with new print handler",
+		event->id, event->system, event->name);
+
+	event->handler = handle->func;
+	event->context = handle->context;
+
+	*next = handle->next;
+	free_handler(handle);
+
+	return 1;
+}
+
+/**
+ * pevent_parse_event - parse the event format
+ * @pevent: the handle to the pevent
+ * @buf: the buffer storing the event format string
+ * @size: the size of @buf
+ * @sys: the system the event belongs to
+ *
+ * This parses the event format and creates an event structure
+ * to quickly parse raw data for a given event.
+ *
+ * These files currently come from:
+ *
+ * /sys/kernel/debug/tracing/events/.../.../format
+ */
+int pevent_parse_event(struct pevent *pevent,
+		       const char *buf, unsigned long size,
+		       const char *sys)
+{
+	struct event_format *event;
+	int ret;
+
+	init_input_buf(buf, size);
+
+	event = alloc_event();
+	if (!event)
+		return -ENOMEM;
+
+	event->name = event_read_name();
+	if (!event->name) {
+		/* Bad event? */
+		free(event);
+		return -1;
+	}
+
+	if (strcmp(sys, "ftrace") == 0) {
+
+		event->flags |= EVENT_FL_ISFTRACE;
+
+		if (strcmp(event->name, "bprint") == 0)
+			event->flags |= EVENT_FL_ISBPRINT;
+	}
+		
+	event->id = event_read_id();
+	if (event->id < 0)
+		die("failed to read event id");
+
+	event->system = strdup(sys);
+
+	/* Add pevent to event so that it can be referenced */
+	event->pevent = pevent;
+
+	ret = event_read_format(event);
+	if (ret < 0) {
+		do_warning("failed to read event format for %s", event->name);
+		goto event_failed;
+	}
+
+	/*
+	 * If the event has an override, don't print warnings if the event
+	 * print format fails to parse.
+	 */
+	if (find_event_handle(pevent, event))
+		show_warning = 0;
+
+	ret = event_read_print(event);
+	if (ret < 0) {
+		do_warning("failed to read event print fmt for %s",
+			   event->name);
+		show_warning = 1;
+		goto event_failed;
+	}
+	show_warning = 1;
+
+	add_event(pevent, event);
+
+	if (!ret && (event->flags & EVENT_FL_ISFTRACE)) {
+		struct format_field *field;
+		struct print_arg *arg, **list;
+
+		/* old ftrace had no args */
+
+		list = &event->print_fmt.args;
+		for (field = event->format.fields; field; field = field->next) {
+			arg = alloc_arg();
+			*list = arg;
+			list = &arg->next;
+			arg->type = PRINT_FIELD;
+			arg->field.name = strdup(field->name);
+			arg->field.field = field;
+		}
+		return 0;
+	}
+
+#define PRINT_ARGS 0
+	if (PRINT_ARGS && event->print_fmt.args)
+		print_args(event->print_fmt.args);
+
+	return 0;
+
+ event_failed:
+	event->flags |= EVENT_FL_FAILED;
+	/* still add it even if it failed */
+	add_event(pevent, event);
+	return -1;
+}
+
+int get_field_val(struct trace_seq *s, struct format_field *field,
+		  const char *name, struct pevent_record *record,
+		  unsigned long long *val, int err)
+{
+	if (!field) {
+		if (err)
+			trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
+		return -1;
+	}
+
+	if (pevent_read_number_field(field, record->data, val)) {
+		if (err)
+			trace_seq_printf(s, " %s=INVALID", name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * pevent_get_field_raw - return the raw pointer into the data field
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @len: place to store the field length.
+ * @err: print default error if failed.
+ *
+ * Returns a pointer into record->data of the field and places
+ * the length of the field in @len.
+ *
+ * On failure, it returns NULL.
+ */
+void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
+			   const char *name, struct pevent_record *record,
+			   int *len, int err)
+{
+	struct format_field *field;
+	void *data = record->data;
+	unsigned offset;
+	int dummy;
+
+	if (!event)
+		return NULL;
+
+	field = pevent_find_field(event, name);
+
+	if (!field) {
+		if (err)
+			trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
+		return NULL;
+	}
+
+	/* Allow @len to be NULL */
+	if (!len)
+		len = &dummy;
+
+	offset = field->offset;
+	if (field->flags & FIELD_IS_DYNAMIC) {
+		offset = pevent_read_number(event->pevent,
+					    data + offset, field->size);
+		*len = offset >> 16;
+		offset &= 0xffff;
+	} else
+		*len = field->size;
+
+	return data + offset;
+}
+
+/**
+ * pevent_get_field_val - find a field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
+			 const char *name, struct pevent_record *record,
+			 unsigned long long *val, int err)
+{
+	struct format_field *field;
+
+	if (!event)
+		return -1;
+
+	field = pevent_find_field(event, name);
+
+	return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_get_common_field_val - find a common field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
+				const char *name, struct pevent_record *record,
+				unsigned long long *val, int err)
+{
+	struct format_field *field;
+
+	if (!event)
+		return -1;
+
+	field = pevent_find_common_field(event, name);
+
+	return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_get_any_field_val - find a any field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
+			     const char *name, struct pevent_record *record,
+			     unsigned long long *val, int err)
+{
+	struct format_field *field;
+
+	if (!event)
+		return -1;
+
+	field = pevent_find_any_field(event, name);
+
+	return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_print_num_field - print a field and a format
+ * @s: The seq to print to
+ * @fmt: The printf format to print the field with.
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @err: print default error if failed.
+ *
+ * Returns: 0 on success, -1 field not fould, or 1 if buffer is full.
+ */
+int pevent_print_num_field(struct trace_seq *s, const char *fmt,
+			   struct event_format *event, const char *name,
+			   struct pevent_record *record, int err)
+{
+	struct format_field *field = pevent_find_field(event, name);
+	unsigned long long val;
+
+	if (!field)
+		goto failed;
+
+	if (pevent_read_number_field(field, record->data, &val))
+		goto failed;
+
+	return trace_seq_printf(s, fmt, val);
+
+ failed:
+	if (err)
+		trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
+	return -1;
+}
+
+static void free_func_handle(struct pevent_function_handler *func)
+{
+	struct pevent_func_params *params;
+
+	free(func->name);
+
+	while (func->params) {
+		params = func->params;
+		func->params = params->next;
+		free(params);
+	}
+
+	free(func);
+}
+
+/**
+ * pevent_register_print_function - register a helper function
+ * @pevent: the handle to the pevent
+ * @func: the function to process the helper function
+ * @name: the name of the helper function
+ * @parameters: A list of enum pevent_func_arg_type
+ *
+ * Some events may have helper functions in the print format arguments.
+ * This allows a plugin to dynmically create a way to process one
+ * of these functions.
+ *
+ * The @parameters is a variable list of pevent_func_arg_type enums that
+ * must end with PEVENT_FUNC_ARG_VOID.
+ */
+int pevent_register_print_function(struct pevent *pevent,
+				   pevent_func_handler func,
+				   enum pevent_func_arg_type ret_type,
+				   char *name, ...)
+{
+	struct pevent_function_handler *func_handle;
+	struct pevent_func_params **next_param;
+	struct pevent_func_params *param;
+	enum pevent_func_arg_type type;
+	va_list ap;
+
+	func_handle = find_func_handler(pevent, name);
+	if (func_handle) {
+		/*
+		 * This is most like caused by the users own
+		 * plugins updating the function. This overrides the
+		 * system defaults.
+		 */
+		pr_stat("override of function helper '%s'", name);
+		remove_func_handler(pevent, name);
+	}
+
+	func_handle = malloc_or_die(sizeof(*func_handle));
+	memset(func_handle, 0, sizeof(*func_handle));
+
+	func_handle->ret_type = ret_type;
+	func_handle->name = strdup(name);
+	func_handle->func = func;
+	if (!func_handle->name)
+		die("Failed to allocate function name");
+
+	next_param = &(func_handle->params);
+	va_start(ap, name);
+	for (;;) {
+		type = va_arg(ap, enum pevent_func_arg_type);
+		if (type == PEVENT_FUNC_ARG_VOID)
+			break;
+
+		if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) {
+			warning("Invalid argument type %d", type);
+			goto out_free;
+		}
+
+		param = malloc_or_die(sizeof(*param));
+		param->type = type;
+		param->next = NULL;
+
+		*next_param = param;
+		next_param = &(param->next);
+
+		func_handle->nr_args++;
+	}
+	va_end(ap);
+
+	func_handle->next = pevent->func_handlers;
+	pevent->func_handlers = func_handle;
+
+	return 0;
+ out_free:
+	va_end(ap);
+	free_func_handle(func_handle);
+	return -1;
+}
+
+/**
+ * pevent_register_event_handle - register a way to parse an event
+ * @pevent: the handle to the pevent
+ * @id: the id of the event to register
+ * @sys_name: the system name the event belongs to
+ * @event_name: the name of the event
+ * @func: the function to call to parse the event information
+ *
+ * This function allows a developer to override the parsing of
+ * a given event. If for some reason the default print format
+ * is not sufficient, this function will register a function
+ * for an event to be used to parse the data instead.
+ *
+ * If @id is >= 0, then it is used to find the event.
+ * else @sys_name and @event_name are used.
+ */
+int pevent_register_event_handler(struct pevent *pevent,
+				  int id, char *sys_name, char *event_name,
+				  pevent_event_handler_func func,
+				  void *context)
+{
+	struct event_format *event;
+	struct event_handler *handle;
+
+	if (id >= 0) {
+		/* search by id */
+		event = pevent_find_event(pevent, id);
+		if (!event)
+			goto not_found;
+		if (event_name && (strcmp(event_name, event->name) != 0))
+			goto not_found;
+		if (sys_name && (strcmp(sys_name, event->system) != 0))
+			goto not_found;
+	} else {
+		event = pevent_find_event_by_name(pevent, sys_name, event_name);
+		if (!event)
+			goto not_found;
+	}
+
+	pr_stat("overriding event (%d) %s:%s with new print handler",
+		event->id, event->system, event->name);
+
+	event->handler = func;
+	event->context = context;
+	return 0;
+
+ not_found:
+	/* Save for later use. */
+	handle = malloc_or_die(sizeof(*handle));
+	memset(handle, 0, sizeof(*handle));
+	handle->id = id;
+	if (event_name)
+		handle->event_name = strdup(event_name);
+	if (sys_name)
+		handle->sys_name = strdup(sys_name);
+
+	handle->func = func;
+	handle->next = pevent->handlers;
+	pevent->handlers = handle;
+	handle->context = context;
+
+	return -1;
+}
+
+/**
+ * pevent_alloc - create a pevent handle
+ */
+struct pevent *pevent_alloc(void)
+{
+	struct pevent *pevent;
+
+	pevent = malloc(sizeof(*pevent));
+	if (!pevent)
+		return NULL;
+	memset(pevent, 0, sizeof(*pevent));
+	pevent->ref_count = 1;
+
+	return pevent;
+}
+
+void pevent_ref(struct pevent *pevent)
+{
+	pevent->ref_count++;
+}
+
+static void free_format_fields(struct format_field *field)
+{
+	struct format_field *next;
+
+	while (field) {
+		next = field->next;
+		free(field->type);
+		free(field->name);
+		free(field);
+		field = next;
+	}
+}
+
+static void free_formats(struct format *format)
+{
+	free_format_fields(format->common_fields);
+	free_format_fields(format->fields);
+}
+
+static void free_event(struct event_format *event)
+{
+	free(event->name);
+	free(event->system);
+
+	free_formats(&event->format);
+
+	free(event->print_fmt.format);
+	free_args(event->print_fmt.args);
+
+	free(event);
+}
+
+/**
+ * pevent_free - free a pevent handle
+ * @pevent: the pevent handle to free
+ */
+void pevent_free(struct pevent *pevent)
+{
+	struct cmdline_list *cmdlist, *cmdnext;
+	struct func_list *funclist, *funcnext;
+	struct printk_list *printklist, *printknext;
+	struct pevent_function_handler *func_handler;
+	struct event_handler *handle;
+	int i;
+
+	if (!pevent)
+		return;
+
+	cmdlist = pevent->cmdlist;
+	funclist = pevent->funclist;
+	printklist = pevent->printklist;
+
+	pevent->ref_count--;
+	if (pevent->ref_count)
+		return;
+
+	if (pevent->cmdlines) {
+		for (i = 0; i < pevent->cmdline_count; i++)
+			free(pevent->cmdlines[i].comm);
+		free(pevent->cmdlines);
+	}
+
+	while (cmdlist) {
+		cmdnext = cmdlist->next;
+		free(cmdlist->comm);
+		free(cmdlist);
+		cmdlist = cmdnext;
+	}
+
+	if (pevent->func_map) {
+		for (i = 0; i < pevent->func_count; i++) {
+			free(pevent->func_map[i].func);
+			free(pevent->func_map[i].mod);
+		}
+		free(pevent->func_map);
+	}
+
+	while (funclist) {
+		funcnext = funclist->next;
+		free(funclist->func);
+		free(funclist->mod);
+		free(funclist);
+		funclist = funcnext;
+	}
+
+	while (pevent->func_handlers) {
+		func_handler = pevent->func_handlers;
+		pevent->func_handlers = func_handler->next;
+		free_func_handle(func_handler);
+	}
+
+	if (pevent->printk_map) {
+		for (i = 0; i < pevent->printk_count; i++)
+			free(pevent->printk_map[i].printk);
+		free(pevent->printk_map);
+	}
+
+	while (printklist) {
+		printknext = printklist->next;
+		free(printklist->printk);
+		free(printklist);
+		printklist = printknext;
+	}
+
+	for (i = 0; i < pevent->nr_events; i++)
+		free_event(pevent->events[i]);
+
+	while (pevent->handlers) {
+		handle = pevent->handlers;
+		pevent->handlers = handle->next;
+		free_handler(handle);
+	}
+
+	free(pevent->events);
+	free(pevent->sort_events);
+
+	free(pevent);
+}
+
+void pevent_unref(struct pevent *pevent)
+{
+	pevent_free(pevent);
+}
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
new file mode 100644
index 0000000..ac997bc
--- /dev/null
+++ b/tools/lib/traceevent/event-parse.h
@@ -0,0 +1,804 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _PARSE_EVENTS_H
+#define _PARSE_EVENTS_H
+
+#include <stdarg.h>
+#include <regex.h>
+
+#ifndef __unused
+#define __unused __attribute__ ((unused))
+#endif
+
+/* ----------------------- trace_seq ----------------------- */
+
+
+#ifndef TRACE_SEQ_BUF_SIZE
+#define TRACE_SEQ_BUF_SIZE 4096
+#endif
+
+#ifndef DEBUG_RECORD
+#define DEBUG_RECORD 0
+#endif
+
+struct pevent_record {
+	unsigned long long	ts;
+	unsigned long long	offset;
+	long long		missed_events;	/* buffer dropped events before */
+	int			record_size;	/* size of binary record */
+	int			size;		/* size of data */
+	void			*data;
+	int			cpu;
+	int			ref_count;
+	int			locked;		/* Do not free, even if ref_count is zero */
+	void			*private;
+#if DEBUG_RECORD
+	struct pevent_record	*prev;
+	struct pevent_record	*next;
+	long			alloc_addr;
+#endif
+};
+
+/*
+ * Trace sequences are used to allow a function to call several other functions
+ * to create a string of data to use (up to a max of PAGE_SIZE).
+ */
+
+struct trace_seq {
+	char			*buffer;
+	unsigned int		buffer_size;
+	unsigned int		len;
+	unsigned int		readpos;
+};
+
+void trace_seq_init(struct trace_seq *s);
+void trace_seq_destroy(struct trace_seq *s);
+
+extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+	__attribute__ ((format (printf, 2, 0)));
+
+extern int trace_seq_puts(struct trace_seq *s, const char *str);
+extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
+
+extern void trace_seq_terminate(struct trace_seq *s);
+
+extern int trace_seq_do_printf(struct trace_seq *s);
+
+
+/* ----------------------- pevent ----------------------- */
+
+struct pevent;
+struct event_format;
+
+typedef int (*pevent_event_handler_func)(struct trace_seq *s,
+					 struct pevent_record *record,
+					 struct event_format *event,
+					 void *context);
+
+typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
+typedef int (*pevent_plugin_unload_func)(void);
+
+struct plugin_option {
+	struct plugin_option		*next;
+	void				*handle;
+	char				*file;
+	char				*name;
+	char				*plugin_alias;
+	char				*description;
+	char				*value;
+	void				*private;
+	int				set;
+};
+
+/*
+ * Plugin hooks that can be called:
+ *
+ * PEVENT_PLUGIN_LOADER:  (required)
+ *   The function name to initialized the plugin.
+ *
+ *   int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
+ *
+ * PEVENT_PLUGIN_UNLOADER:  (optional)
+ *   The function called just before unloading
+ *
+ *   int PEVENT_PLUGIN_UNLOADER(void)
+ *
+ * PEVENT_PLUGIN_OPTIONS:  (optional)
+ *   Plugin options that can be set before loading
+ *
+ *   struct plugin_option PEVENT_PLUGIN_OPTIONS[] = {
+ *	{
+ *		.name = "option-name",
+ *		.plugin_alias = "overide-file-name", (optional)
+ *		.description = "description of option to show users",
+ *	},
+ *	{
+ *		.name = NULL,
+ *	},
+ *   };
+ *
+ *   Array must end with .name = NULL;
+ *
+ *
+ *   .plugin_alias is used to give a shorter name to access
+ *   the vairable. Useful if a plugin handles more than one event.
+ *
+ * PEVENT_PLUGIN_ALIAS: (optional)
+ *   The name to use for finding options (uses filename if not defined)
+ */
+#define PEVENT_PLUGIN_LOADER pevent_plugin_loader
+#define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader
+#define PEVENT_PLUGIN_OPTIONS pevent_plugin_options
+#define PEVENT_PLUGIN_ALIAS pevent_plugin_alias
+#define _MAKE_STR(x)	#x
+#define MAKE_STR(x)	_MAKE_STR(x)
+#define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER)
+#define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER)
+#define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS)
+#define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS)
+
+#define NSECS_PER_SEC		1000000000ULL
+#define NSECS_PER_USEC		1000ULL
+
+enum format_flags {
+	FIELD_IS_ARRAY		= 1,
+	FIELD_IS_POINTER	= 2,
+	FIELD_IS_SIGNED		= 4,
+	FIELD_IS_STRING		= 8,
+	FIELD_IS_DYNAMIC	= 16,
+	FIELD_IS_LONG		= 32,
+	FIELD_IS_FLAG		= 64,
+	FIELD_IS_SYMBOLIC	= 128,
+};
+
+struct format_field {
+	struct format_field	*next;
+	struct event_format	*event;
+	char			*type;
+	char			*name;
+	int			offset;
+	int			size;
+	unsigned int		arraylen;
+	unsigned int		elementsize;
+	unsigned long		flags;
+};
+
+struct format {
+	int			nr_common;
+	int			nr_fields;
+	struct format_field	*common_fields;
+	struct format_field	*fields;
+};
+
+struct print_arg_atom {
+	char			*atom;
+};
+
+struct print_arg_string {
+	char			*string;
+	int			offset;
+};
+
+struct print_arg_field {
+	char			*name;
+	struct format_field	*field;
+};
+
+struct print_flag_sym {
+	struct print_flag_sym	*next;
+	char			*value;
+	char			*str;
+};
+
+struct print_arg_typecast {
+	char 			*type;
+	struct print_arg	*item;
+};
+
+struct print_arg_flags {
+	struct print_arg	*field;
+	char			*delim;
+	struct print_flag_sym	*flags;
+};
+
+struct print_arg_symbol {
+	struct print_arg	*field;
+	struct print_flag_sym	*symbols;
+};
+
+struct print_arg_dynarray {
+	struct format_field	*field;
+	struct print_arg	*index;
+};
+
+struct print_arg;
+
+struct print_arg_op {
+	char			*op;
+	int			prio;
+	struct print_arg	*left;
+	struct print_arg	*right;
+};
+
+struct pevent_function_handler;
+
+struct print_arg_func {
+	struct pevent_function_handler	*func;
+	struct print_arg		*args;
+};
+
+enum print_arg_type {
+	PRINT_NULL,
+	PRINT_ATOM,
+	PRINT_FIELD,
+	PRINT_FLAGS,
+	PRINT_SYMBOL,
+	PRINT_TYPE,
+	PRINT_STRING,
+	PRINT_BSTRING,
+	PRINT_DYNAMIC_ARRAY,
+	PRINT_OP,
+	PRINT_FUNC,
+};
+
+struct print_arg {
+	struct print_arg		*next;
+	enum print_arg_type		type;
+	union {
+		struct print_arg_atom		atom;
+		struct print_arg_field		field;
+		struct print_arg_typecast	typecast;
+		struct print_arg_flags		flags;
+		struct print_arg_symbol		symbol;
+		struct print_arg_func		func;
+		struct print_arg_string		string;
+		struct print_arg_op		op;
+		struct print_arg_dynarray	dynarray;
+	};
+};
+
+struct print_fmt {
+	char			*format;
+	struct print_arg	*args;
+};
+
+struct event_format {
+	struct pevent		*pevent;
+	char			*name;
+	int			id;
+	int			flags;
+	struct format		format;
+	struct print_fmt	print_fmt;
+	char			*system;
+	pevent_event_handler_func handler;
+	void			*context;
+};
+
+enum {
+	EVENT_FL_ISFTRACE	= 0x01,
+	EVENT_FL_ISPRINT	= 0x02,
+	EVENT_FL_ISBPRINT	= 0x04,
+	EVENT_FL_ISFUNCENT	= 0x10,
+	EVENT_FL_ISFUNCRET	= 0x20,
+
+	EVENT_FL_FAILED		= 0x80000000
+};
+
+enum event_sort_type {
+	EVENT_SORT_ID,
+	EVENT_SORT_NAME,
+	EVENT_SORT_SYSTEM,
+};
+
+enum event_type {
+	EVENT_ERROR,
+	EVENT_NONE,
+	EVENT_SPACE,
+	EVENT_NEWLINE,
+	EVENT_OP,
+	EVENT_DELIM,
+	EVENT_ITEM,
+	EVENT_DQUOTE,
+	EVENT_SQUOTE,
+};
+
+typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s,
+					     unsigned long long *args);
+
+enum pevent_func_arg_type {
+	PEVENT_FUNC_ARG_VOID,
+	PEVENT_FUNC_ARG_INT,
+	PEVENT_FUNC_ARG_LONG,
+	PEVENT_FUNC_ARG_STRING,
+	PEVENT_FUNC_ARG_PTR,
+	PEVENT_FUNC_ARG_MAX_TYPES
+};
+
+enum pevent_flag {
+	PEVENT_NSEC_OUTPUT		= 1,	/* output in NSECS */
+};
+
+struct cmdline;
+struct cmdline_list;
+struct func_map;
+struct func_list;
+struct event_handler;
+
+struct pevent {
+	int ref_count;
+
+	int header_page_ts_offset;
+	int header_page_ts_size;
+	int header_page_size_offset;
+	int header_page_size_size;
+	int header_page_data_offset;
+	int header_page_data_size;
+	int header_page_overwrite;
+
+	int file_bigendian;
+	int host_bigendian;
+
+	int latency_format;
+
+	int old_format;
+
+	int cpus;
+	int long_size;
+
+	struct cmdline *cmdlines;
+	struct cmdline_list *cmdlist;
+	int cmdline_count;
+
+	struct func_map *func_map;
+	struct func_list *funclist;
+	unsigned int func_count;
+
+	struct printk_map *printk_map;
+	struct printk_list *printklist;
+	unsigned int printk_count;
+
+
+	struct event_format **events;
+	int nr_events;
+	struct event_format **sort_events;
+	enum event_sort_type last_type;
+
+	int type_offset;
+	int type_size;
+
+	int pid_offset;
+	int pid_size;
+
+ 	int pc_offset;
+	int pc_size;
+
+	int flags_offset;
+	int flags_size;
+
+	int ld_offset;
+	int ld_size;
+
+	int print_raw;
+
+	int test_filters;
+
+	int flags;
+
+	struct format_field *bprint_ip_field;
+	struct format_field *bprint_fmt_field;
+	struct format_field *bprint_buf_field;
+
+	struct event_handler *handlers;
+	struct pevent_function_handler *func_handlers;
+
+	/* cache */
+	struct event_format *last_event;
+};
+
+static inline void pevent_set_flag(struct pevent *pevent, int flag)
+{
+	pevent->flags |= flag;
+}
+
+static inline unsigned short
+__data2host2(struct pevent *pevent, unsigned short data)
+{
+	unsigned short swap;
+
+	if (pevent->host_bigendian == pevent->file_bigendian)
+		return data;
+
+	swap = ((data & 0xffULL) << 8) |
+		((data & (0xffULL << 8)) >> 8);
+
+	return swap;
+}
+
+static inline unsigned int
+__data2host4(struct pevent *pevent, unsigned int data)
+{
+	unsigned int swap;
+
+	if (pevent->host_bigendian == pevent->file_bigendian)
+		return data;
+
+	swap = ((data & 0xffULL) << 24) |
+		((data & (0xffULL << 8)) << 8) |
+		((data & (0xffULL << 16)) >> 8) |
+		((data & (0xffULL << 24)) >> 24);
+
+	return swap;
+}
+
+static inline unsigned long long
+__data2host8(struct pevent *pevent, unsigned long long data)
+{
+	unsigned long long swap;
+
+	if (pevent->host_bigendian == pevent->file_bigendian)
+		return data;
+
+	swap = ((data & 0xffULL) << 56) |
+		((data & (0xffULL << 8)) << 40) |
+		((data & (0xffULL << 16)) << 24) |
+		((data & (0xffULL << 24)) << 8) |
+		((data & (0xffULL << 32)) >> 8) |
+		((data & (0xffULL << 40)) >> 24) |
+		((data & (0xffULL << 48)) >> 40) |
+		((data & (0xffULL << 56)) >> 56);
+
+	return swap;
+}
+
+#define data2host2(pevent, ptr)		__data2host2(pevent, *(unsigned short *)(ptr))
+#define data2host4(pevent, ptr)		__data2host4(pevent, *(unsigned int *)(ptr))
+#define data2host8(pevent, ptr)					\
+({								\
+	unsigned long long __val;				\
+								\
+	memcpy(&__val, (ptr), sizeof(unsigned long long));	\
+	__data2host8(pevent, __val);				\
+})
+
+/* taken from kernel/trace/trace.h */
+enum trace_flag_type {
+	TRACE_FLAG_IRQS_OFF		= 0x01,
+	TRACE_FLAG_IRQS_NOSUPPORT	= 0x02,
+	TRACE_FLAG_NEED_RESCHED		= 0x04,
+	TRACE_FLAG_HARDIRQ		= 0x08,
+	TRACE_FLAG_SOFTIRQ		= 0x10,
+};
+
+int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
+int pevent_register_function(struct pevent *pevent, char *name,
+			     unsigned long long addr, char *mod);
+int pevent_register_print_string(struct pevent *pevent, char *fmt,
+				 unsigned long long addr);
+int pevent_pid_is_registered(struct pevent *pevent, int pid);
+
+void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
+			struct pevent_record *record);
+
+int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
+			     int long_size);
+
+int pevent_parse_event(struct pevent *pevent, const char *buf,
+		       unsigned long size, const char *sys);
+
+void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
+			   const char *name, struct pevent_record *record,
+			   int *len, int err);
+
+int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
+			 const char *name, struct pevent_record *record,
+			 unsigned long long *val, int err);
+int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
+				const char *name, struct pevent_record *record,
+				unsigned long long *val, int err);
+int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
+			     const char *name, struct pevent_record *record,
+			     unsigned long long *val, int err);
+
+int pevent_print_num_field(struct trace_seq *s, const char *fmt,
+			   struct event_format *event, const char *name,
+			   struct pevent_record *record, int err);
+
+int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
+				  pevent_event_handler_func func, void *context);
+int pevent_register_print_function(struct pevent *pevent,
+				   pevent_func_handler func,
+				   enum pevent_func_arg_type ret_type,
+				   char *name, ...);
+
+struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
+struct format_field *pevent_find_field(struct event_format *event, const char *name);
+struct format_field *pevent_find_any_field(struct event_format *event, const char *name);
+
+const char *pevent_find_function(struct pevent *pevent, unsigned long long addr);
+unsigned long long
+pevent_find_function_address(struct pevent *pevent, unsigned long long addr);
+unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size);
+int pevent_read_number_field(struct format_field *field, const void *data,
+			     unsigned long long *value);
+
+struct event_format *pevent_find_event(struct pevent *pevent, int id);
+
+struct event_format *
+pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
+
+void pevent_data_lat_fmt(struct pevent *pevent,
+			 struct trace_seq *s, struct pevent_record *record);
+int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
+struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
+int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec);
+const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
+void pevent_event_info(struct trace_seq *s, struct event_format *event,
+		       struct pevent_record *record);
+
+struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
+struct format_field **pevent_event_common_fields(struct event_format *event);
+struct format_field **pevent_event_fields(struct event_format *event);
+
+static inline int pevent_get_cpus(struct pevent *pevent)
+{
+	return pevent->cpus;
+}
+
+static inline void pevent_set_cpus(struct pevent *pevent, int cpus)
+{
+	pevent->cpus = cpus;
+}
+
+static inline int pevent_get_long_size(struct pevent *pevent)
+{
+	return pevent->long_size;
+}
+
+static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
+{
+	pevent->long_size = long_size;
+}
+
+static inline int pevent_is_file_bigendian(struct pevent *pevent)
+{
+	return pevent->file_bigendian;
+}
+
+static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian)
+{
+	pevent->file_bigendian = endian;
+}
+
+static inline int pevent_is_host_bigendian(struct pevent *pevent)
+{
+	return pevent->host_bigendian;
+}
+
+static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian)
+{
+	pevent->host_bigendian = endian;
+}
+
+static inline int pevent_is_latency_format(struct pevent *pevent)
+{
+	return pevent->latency_format;
+}
+
+static inline void pevent_set_latency_format(struct pevent *pevent, int lat)
+{
+	pevent->latency_format = lat;
+}
+
+struct pevent *pevent_alloc(void);
+void pevent_free(struct pevent *pevent);
+void pevent_ref(struct pevent *pevent);
+void pevent_unref(struct pevent *pevent);
+
+/* access to the internal parser */
+void pevent_buffer_init(const char *buf, unsigned long long size);
+enum event_type pevent_read_token(char **tok);
+void pevent_free_token(char *token);
+int pevent_peek_char(void);
+const char *pevent_get_input_buf(void);
+unsigned long long pevent_get_input_buf_ptr(void);
+
+/* for debugging */
+void pevent_print_funcs(struct pevent *pevent);
+void pevent_print_printk(struct pevent *pevent);
+
+/* ----------------------- filtering ----------------------- */
+
+enum filter_boolean_type {
+	FILTER_FALSE,
+	FILTER_TRUE,
+};
+
+enum filter_op_type {
+	FILTER_OP_AND = 1,
+	FILTER_OP_OR,
+	FILTER_OP_NOT,
+};
+
+enum filter_cmp_type {
+	FILTER_CMP_NONE,
+	FILTER_CMP_EQ,
+	FILTER_CMP_NE,
+	FILTER_CMP_GT,
+	FILTER_CMP_LT,
+	FILTER_CMP_GE,
+	FILTER_CMP_LE,
+	FILTER_CMP_MATCH,
+	FILTER_CMP_NOT_MATCH,
+	FILTER_CMP_REGEX,
+	FILTER_CMP_NOT_REGEX,
+};
+
+enum filter_exp_type {
+	FILTER_EXP_NONE,
+	FILTER_EXP_ADD,
+	FILTER_EXP_SUB,
+	FILTER_EXP_MUL,
+	FILTER_EXP_DIV,
+	FILTER_EXP_MOD,
+	FILTER_EXP_RSHIFT,
+	FILTER_EXP_LSHIFT,
+	FILTER_EXP_AND,
+	FILTER_EXP_OR,
+	FILTER_EXP_XOR,
+	FILTER_EXP_NOT,
+};
+
+enum filter_arg_type {
+	FILTER_ARG_NONE,
+	FILTER_ARG_BOOLEAN,
+	FILTER_ARG_VALUE,
+	FILTER_ARG_FIELD,
+	FILTER_ARG_EXP,
+	FILTER_ARG_OP,
+	FILTER_ARG_NUM,
+	FILTER_ARG_STR,
+};
+
+enum filter_value_type {
+	FILTER_NUMBER,
+	FILTER_STRING,
+	FILTER_CHAR
+};
+
+struct fliter_arg;
+
+struct filter_arg_boolean {
+	enum filter_boolean_type	value;
+};
+
+struct filter_arg_field {
+	struct format_field	*field;
+};
+
+struct filter_arg_value {
+	enum filter_value_type	type;
+	union {
+		char			*str;
+		unsigned long long	val;
+	};
+};
+
+struct filter_arg_op {
+	enum filter_op_type	type;
+	struct filter_arg	*left;
+	struct filter_arg	*right;
+};
+
+struct filter_arg_exp {
+	enum filter_exp_type	type;
+	struct filter_arg	*left;
+	struct filter_arg	*right;
+};
+
+struct filter_arg_num {
+	enum filter_cmp_type	type;
+	struct filter_arg	*left;
+	struct filter_arg	*right;
+};
+
+struct filter_arg_str {
+	enum filter_cmp_type	type;
+	struct format_field	*field;
+	char			*val;
+	char			*buffer;
+	regex_t			reg;
+};
+
+struct filter_arg {
+	enum filter_arg_type	type;
+	union {
+		struct filter_arg_boolean	boolean;
+		struct filter_arg_field		field;
+		struct filter_arg_value		value;
+		struct filter_arg_op		op;
+		struct filter_arg_exp		exp;
+		struct filter_arg_num		num;
+		struct filter_arg_str		str;
+	};
+};
+
+struct filter_type {
+	int			event_id;
+	struct event_format	*event;
+	struct filter_arg	*filter;
+};
+
+struct event_filter {
+	struct pevent		*pevent;
+	int			filters;
+	struct filter_type	*event_filters;
+};
+
+struct event_filter *pevent_filter_alloc(struct pevent *pevent);
+
+#define FILTER_NONE		-2
+#define FILTER_NOEXIST		-1
+#define FILTER_MISS		0
+#define FILTER_MATCH		1
+
+enum filter_trivial_type {
+	FILTER_TRIVIAL_FALSE,
+	FILTER_TRIVIAL_TRUE,
+	FILTER_TRIVIAL_BOTH,
+};
+
+int pevent_filter_add_filter_str(struct event_filter *filter,
+				 const char *filter_str,
+				 char **error_str);
+
+
+int pevent_filter_match(struct event_filter *filter,
+			struct pevent_record *record);
+
+int pevent_event_filtered(struct event_filter *filter,
+			  int event_id);
+
+void pevent_filter_reset(struct event_filter *filter);
+
+void pevent_filter_clear_trivial(struct event_filter *filter,
+				 enum filter_trivial_type type);
+
+void pevent_filter_free(struct event_filter *filter);
+
+char *pevent_filter_make_string(struct event_filter *filter, int event_id);
+
+int pevent_filter_remove_event(struct event_filter *filter,
+			       int event_id);
+
+int pevent_filter_event_has_trivial(struct event_filter *filter,
+				    int event_id,
+				    enum filter_trivial_type type);
+
+int pevent_filter_copy(struct event_filter *dest, struct event_filter *source);
+
+int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
+			  enum filter_trivial_type type);
+
+int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2);
+
+#endif /* _PARSE_EVENTS_H */
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h
new file mode 100644
index 0000000..0829638
--- /dev/null
+++ b/tools/lib/traceevent/event-utils.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#include <ctype.h>
+
+/* Can be overridden */
+void die(const char *fmt, ...);
+void *malloc_or_die(unsigned int size);
+void warning(const char *fmt, ...);
+void pr_stat(const char *fmt, ...);
+void vpr_stat(const char *fmt, va_list ap);
+
+/* Always available */
+void __die(const char *fmt, ...);
+void __warning(const char *fmt, ...);
+void __pr_stat(const char *fmt, ...);
+
+void __vdie(const char *fmt, ...);
+void __vwarning(const char *fmt, ...);
+void __vpr_stat(const char *fmt, ...);
+
+static inline char *strim(char *string)
+{
+	char *ret;
+
+	if (!string)
+		return NULL;
+	while (*string) {
+		if (!isspace(*string))
+			break;
+		string++;
+	}
+	ret = string;
+
+	string = ret + strlen(ret) - 1;
+	while (string > ret) {
+		if (!isspace(*string))
+			break;
+		string--;
+	}
+	string[1] = 0;
+
+	return ret;
+}
+
+static inline int has_text(const char *text)
+{
+	if (!text)
+		return 0;
+
+	while (*text) {
+		if (!isspace(*text))
+			return 1;
+		text++;
+	}
+
+	return 0;
+}
+
+#endif
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
new file mode 100644
index 0000000..2d40c5e
--- /dev/null
+++ b/tools/lib/traceevent/parse-filter.c
@@ -0,0 +1,2262 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+#define COMM "COMM"
+
+static struct format_field comm = {
+	.name = "COMM",
+};
+
+struct event_list {
+	struct event_list	*next;
+	struct event_format	*event;
+};
+
+#define MAX_ERR_STR_SIZE 256
+
+static void show_error(char **error_str, const char *fmt, ...)
+{
+	unsigned long long index;
+	const char *input;
+	char *error;
+	va_list ap;
+	int len;
+	int i;
+
+	if (!error_str)
+		return;
+
+	input = pevent_get_input_buf();
+	index = pevent_get_input_buf_ptr();
+	len = input ? strlen(input) : 0;
+
+	error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3);
+
+	if (len) {
+		strcpy(error, input);
+		error[len] = '\n';
+		for (i = 1; i < len && i < index; i++)
+			error[len+i] = ' ';
+		error[len + i] = '^';
+		error[len + i + 1] = '\n';
+		len += i+2;
+	}
+
+	va_start(ap, fmt);
+	vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap);
+	va_end(ap);
+
+	*error_str = error;
+}
+
+static void free_token(char *token)
+{
+	pevent_free_token(token);
+}
+
+static enum event_type read_token(char **tok)
+{
+	enum event_type type;
+	char *token = NULL;
+
+	do {
+		free_token(token);
+		type = pevent_read_token(&token);
+	} while (type == EVENT_NEWLINE || type == EVENT_SPACE);
+
+	/* If token is = or ! check to see if the next char is ~ */
+	if (token &&
+	    (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
+	    pevent_peek_char() == '~') {
+		/* append it */
+		*tok = malloc(3);
+		sprintf(*tok, "%c%c", *token, '~');
+		free_token(token);
+		/* Now remove the '~' from the buffer */
+		pevent_read_token(&token);
+		free_token(token);
+	} else
+		*tok = token;
+
+	return type;
+}
+
+static int filter_cmp(const void *a, const void *b)
+{
+	const struct filter_type *ea = a;
+	const struct filter_type *eb = b;
+
+	if (ea->event_id < eb->event_id)
+		return -1;
+
+	if (ea->event_id > eb->event_id)
+		return 1;
+
+	return 0;
+}
+
+static struct filter_type *
+find_filter_type(struct event_filter *filter, int id)
+{
+	struct filter_type *filter_type;
+	struct filter_type key;
+
+	key.event_id = id;
+
+	filter_type = bsearch(&key, filter->event_filters,
+			      filter->filters,
+			      sizeof(*filter->event_filters),
+			      filter_cmp);
+
+	return filter_type;
+}
+
+static struct filter_type *
+add_filter_type(struct event_filter *filter, int id)
+{
+	struct filter_type *filter_type;
+	int i;
+
+	filter_type = find_filter_type(filter, id);
+	if (filter_type)
+		return filter_type;
+
+	if (!filter->filters)
+		filter->event_filters =
+			malloc_or_die(sizeof(*filter->event_filters));
+	else {
+		filter->event_filters =
+			realloc(filter->event_filters,
+				sizeof(*filter->event_filters) *
+				(filter->filters + 1));
+		if (!filter->event_filters)
+			die("Could not allocate filter");
+	}
+
+	for (i = 0; i < filter->filters; i++) {
+		if (filter->event_filters[i].event_id > id)
+			break;
+	}
+
+	if (i < filter->filters)
+		memmove(&filter->event_filters[i+1],
+			&filter->event_filters[i],
+			sizeof(*filter->event_filters) *
+			(filter->filters - i));
+
+	filter_type = &filter->event_filters[i];
+	filter_type->event_id = id;
+	filter_type->event = pevent_find_event(filter->pevent, id);
+	filter_type->filter = NULL;
+
+	filter->filters++;
+
+	return filter_type;
+}
+
+/**
+ * pevent_filter_alloc - create a new event filter
+ * @pevent: The pevent that this filter is associated with
+ */
+struct event_filter *pevent_filter_alloc(struct pevent *pevent)
+{
+	struct event_filter *filter;
+
+	filter = malloc_or_die(sizeof(*filter));
+	memset(filter, 0, sizeof(*filter));
+	filter->pevent = pevent;
+	pevent_ref(pevent);
+
+	return filter;
+}
+
+static struct filter_arg *allocate_arg(void)
+{
+	struct filter_arg *arg;
+
+	arg = malloc_or_die(sizeof(*arg));
+	memset(arg, 0, sizeof(*arg));
+
+	return arg;
+}
+
+static void free_arg(struct filter_arg *arg)
+{
+	if (!arg)
+		return;
+
+	switch (arg->type) {
+	case FILTER_ARG_NONE:
+	case FILTER_ARG_BOOLEAN:
+	case FILTER_ARG_NUM:
+		break;
+
+	case FILTER_ARG_STR:
+		free(arg->str.val);
+		regfree(&arg->str.reg);
+		free(arg->str.buffer);
+		break;
+
+	case FILTER_ARG_OP:
+		free_arg(arg->op.left);
+		free_arg(arg->op.right);
+	default:
+		break;
+	}
+
+	free(arg);
+}
+
+static void add_event(struct event_list **events,
+		      struct event_format *event)
+{
+	struct event_list *list;
+
+	list = malloc_or_die(sizeof(*list));
+	list->next = *events;
+	*events = list;
+	list->event = event;
+}
+
+static int event_match(struct event_format *event,
+		       regex_t *sreg, regex_t *ereg)
+{
+	if (sreg) {
+		return !regexec(sreg, event->system, 0, NULL, 0) &&
+			!regexec(ereg, event->name, 0, NULL, 0);
+	}
+
+	return !regexec(ereg, event->system, 0, NULL, 0) ||
+		!regexec(ereg, event->name, 0, NULL, 0);
+}
+
+static int
+find_event(struct pevent *pevent, struct event_list **events,
+	   char *sys_name, char *event_name)
+{
+	struct event_format *event;
+	regex_t ereg;
+	regex_t sreg;
+	int match = 0;
+	char *reg;
+	int ret;
+	int i;
+
+	if (!event_name) {
+		/* if no name is given, then swap sys and name */
+		event_name = sys_name;
+		sys_name = NULL;
+	}
+
+	reg = malloc_or_die(strlen(event_name) + 3);
+	sprintf(reg, "^%s$", event_name);
+
+	ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
+	free(reg);
+
+	if (ret)
+		return -1;
+
+	if (sys_name) {
+		reg = malloc_or_die(strlen(sys_name) + 3);
+		sprintf(reg, "^%s$", sys_name);
+		ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
+		free(reg);
+		if (ret) {
+			regfree(&ereg);
+			return -1;
+		}
+	}
+
+	for (i = 0; i < pevent->nr_events; i++) {
+		event = pevent->events[i];
+		if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
+			match = 1;
+			add_event(events, event);
+		}
+	}
+
+	regfree(&ereg);
+	if (sys_name)
+		regfree(&sreg);
+
+	if (!match)
+		return -1;
+
+	return 0;
+}
+
+static void free_events(struct event_list *events)
+{
+	struct event_list *event;
+
+	while (events) {
+		event = events;
+		events = events->next;
+		free(event);
+	}
+}
+
+static struct filter_arg *
+create_arg_item(struct event_format *event,
+		const char *token, enum filter_arg_type type,
+		char **error_str)
+{
+	struct format_field *field;
+	struct filter_arg *arg;
+
+	arg = allocate_arg();
+
+	switch (type) {
+
+	case EVENT_SQUOTE:
+	case EVENT_DQUOTE:
+		arg->type = FILTER_ARG_VALUE;
+		arg->value.type =
+			type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
+		arg->value.str = strdup(token);
+		if (!arg->value.str)
+			die("malloc string");
+		break;
+	case EVENT_ITEM:
+		/* if it is a number, then convert it */
+		if (isdigit(token[0])) {
+			arg->type = FILTER_ARG_VALUE;
+			arg->value.type = FILTER_NUMBER;
+			arg->value.val = strtoull(token, NULL, 0);
+			break;
+		}
+		/* Consider this a field */
+		field = pevent_find_any_field(event, token);
+		if (!field) {
+			if (strcmp(token, COMM) != 0) {
+				/* not a field, Make it false */
+				arg->type = FILTER_ARG_BOOLEAN;
+				arg->boolean.value = FILTER_FALSE;
+				break;
+			}
+			/* If token is 'COMM' then it is special */
+			field = &comm;
+		}
+		arg->type = FILTER_ARG_FIELD;
+		arg->field.field = field;
+		break;
+	default:
+		free_arg(arg);
+		show_error(error_str, "expected a value but found %s",
+			   token);
+		return NULL;
+	}
+	return arg;
+}
+
+static struct filter_arg *
+create_arg_op(enum filter_op_type btype)
+{
+	struct filter_arg *arg;
+
+	arg = allocate_arg();
+	arg->type = FILTER_ARG_OP;
+	arg->op.type = btype;
+
+	return arg;
+}
+
+static struct filter_arg *
+create_arg_exp(enum filter_exp_type etype)
+{
+	struct filter_arg *arg;
+
+	arg = allocate_arg();
+	arg->type = FILTER_ARG_EXP;
+	arg->op.type = etype;
+
+	return arg;
+}
+
+static struct filter_arg *
+create_arg_cmp(enum filter_exp_type etype)
+{
+	struct filter_arg *arg;
+
+	arg = allocate_arg();
+	/* Use NUM and change if necessary */
+	arg->type = FILTER_ARG_NUM;
+	arg->op.type = etype;
+
+	return arg;
+}
+
+static int add_right(struct filter_arg *op, struct filter_arg *arg,
+		     char **error_str)
+{
+	struct filter_arg *left;
+	char *str;
+	int op_type;
+	int ret;
+
+	switch (op->type) {
+	case FILTER_ARG_EXP:
+		if (op->exp.right)
+			goto out_fail;
+		op->exp.right = arg;
+		break;
+
+	case FILTER_ARG_OP:
+		if (op->op.right)
+			goto out_fail;
+		op->op.right = arg;
+		break;
+
+	case FILTER_ARG_NUM:
+		if (op->op.right)
+			goto out_fail;
+		/*
+		 * The arg must be num, str, or field
+		 */
+		switch (arg->type) {
+		case FILTER_ARG_VALUE:
+		case FILTER_ARG_FIELD:
+			break;
+		default:
+			show_error(error_str,
+				   "Illegal rvalue");
+			return -1;
+		}
+
+		/*
+		 * Depending on the type, we may need to
+		 * convert this to a string or regex.
+		 */
+		switch (arg->value.type) {
+		case FILTER_CHAR:
+			/*
+			 * A char should be converted to number if
+			 * the string is 1 byte, and the compare
+			 * is not a REGEX.
+			 */
+			if (strlen(arg->value.str) == 1 &&
+			    op->num.type != FILTER_CMP_REGEX &&
+			    op->num.type != FILTER_CMP_NOT_REGEX) {
+				arg->value.type = FILTER_NUMBER;
+				goto do_int;
+			}
+			/* fall through */
+		case FILTER_STRING:
+
+			/* convert op to a string arg */
+			op_type = op->num.type;
+			left = op->num.left;
+			str = arg->value.str;
+
+			/* reset the op for the new field */
+			memset(op, 0, sizeof(*op));
+
+			/*
+			 * If left arg was a field not found then
+			 * NULL the entire op.
+			 */
+			if (left->type == FILTER_ARG_BOOLEAN) {
+				free_arg(left);
+				free_arg(arg);
+				op->type = FILTER_ARG_BOOLEAN;
+				op->boolean.value = FILTER_FALSE;
+				break;
+			}
+
+			/* Left arg must be a field */
+			if (left->type != FILTER_ARG_FIELD) {
+				show_error(error_str,
+					   "Illegal lvalue for string comparison");
+				return -1;
+			}
+
+			/* Make sure this is a valid string compare */
+			switch (op_type) {
+			case FILTER_CMP_EQ:
+				op_type = FILTER_CMP_MATCH;
+				break;
+			case FILTER_CMP_NE:
+				op_type = FILTER_CMP_NOT_MATCH;
+				break;
+
+			case FILTER_CMP_REGEX:
+			case FILTER_CMP_NOT_REGEX:
+				ret = regcomp(&op->str.reg, str, REG_ICASE|REG_NOSUB);
+				if (ret) {
+					show_error(error_str,
+						   "RegEx '%s' did not compute",
+						   str);
+					return -1;
+				}
+				break;
+			default:
+				show_error(error_str,
+					   "Illegal comparison for string");
+				return -1;
+			}
+
+			op->type = FILTER_ARG_STR;
+			op->str.type = op_type;
+			op->str.field = left->field.field;
+			op->str.val = strdup(str);
+			if (!op->str.val)
+				die("malloc string");
+			/*
+			 * Need a buffer to copy data for tests
+			 */
+			op->str.buffer = malloc_or_die(op->str.field->size + 1);
+			/* Null terminate this buffer */
+			op->str.buffer[op->str.field->size] = 0;
+
+			/* We no longer have left or right args */
+			free_arg(arg);
+			free_arg(left);
+
+			break;
+
+		case FILTER_NUMBER:
+
+ do_int:
+			switch (op->num.type) {
+			case FILTER_CMP_REGEX:
+			case FILTER_CMP_NOT_REGEX:
+				show_error(error_str,
+					   "Op not allowed with integers");
+				return -1;
+
+			default:
+				break;
+			}
+
+			/* numeric compare */
+			op->num.right = arg;
+			break;
+		default:
+			goto out_fail;
+		}
+		break;
+	default:
+		goto out_fail;
+	}
+
+	return 0;
+
+ out_fail:
+	show_error(error_str,
+		   "Syntax error");
+	return -1;
+}
+
+static struct filter_arg *
+rotate_op_right(struct filter_arg *a, struct filter_arg *b)
+{
+	struct filter_arg *arg;
+
+	arg = a->op.right;
+	a->op.right = b;
+	return arg;
+}
+
+static int add_left(struct filter_arg *op, struct filter_arg *arg)
+{
+	switch (op->type) {
+	case FILTER_ARG_EXP:
+		if (arg->type == FILTER_ARG_OP)
+			arg = rotate_op_right(arg, op);
+		op->exp.left = arg;
+		break;
+
+	case FILTER_ARG_OP:
+		op->op.left = arg;
+		break;
+	case FILTER_ARG_NUM:
+		if (arg->type == FILTER_ARG_OP)
+			arg = rotate_op_right(arg, op);
+
+		/* left arg of compares must be a field */
+		if (arg->type != FILTER_ARG_FIELD &&
+		    arg->type != FILTER_ARG_BOOLEAN)
+			return -1;
+		op->num.left = arg;
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+enum op_type {
+	OP_NONE,
+	OP_BOOL,
+	OP_NOT,
+	OP_EXP,
+	OP_CMP,
+};
+
+static enum op_type process_op(const char *token,
+			       enum filter_op_type *btype,
+			       enum filter_cmp_type *ctype,
+			       enum filter_exp_type *etype)
+{
+	*btype = FILTER_OP_NOT;
+	*etype = FILTER_EXP_NONE;
+	*ctype = FILTER_CMP_NONE;
+
+	if (strcmp(token, "&&") == 0)
+		*btype = FILTER_OP_AND;
+	else if (strcmp(token, "||") == 0)
+		*btype = FILTER_OP_OR;
+	else if (strcmp(token, "!") == 0)
+		return OP_NOT;
+
+	if (*btype != FILTER_OP_NOT)
+		return OP_BOOL;
+
+	/* Check for value expressions */
+	if (strcmp(token, "+") == 0) {
+		*etype = FILTER_EXP_ADD;
+	} else if (strcmp(token, "-") == 0) {
+		*etype = FILTER_EXP_SUB;
+	} else if (strcmp(token, "*") == 0) {
+		*etype = FILTER_EXP_MUL;
+	} else if (strcmp(token, "/") == 0) {
+		*etype = FILTER_EXP_DIV;
+	} else if (strcmp(token, "%") == 0) {
+		*etype = FILTER_EXP_MOD;
+	} else if (strcmp(token, ">>") == 0) {
+		*etype = FILTER_EXP_RSHIFT;
+	} else if (strcmp(token, "<<") == 0) {
+		*etype = FILTER_EXP_LSHIFT;
+	} else if (strcmp(token, "&") == 0) {
+		*etype = FILTER_EXP_AND;
+	} else if (strcmp(token, "|") == 0) {
+		*etype = FILTER_EXP_OR;
+	} else if (strcmp(token, "^") == 0) {
+		*etype = FILTER_EXP_XOR;
+	} else if (strcmp(token, "~") == 0)
+		*etype = FILTER_EXP_NOT;
+
+	if (*etype != FILTER_EXP_NONE)
+		return OP_EXP;
+
+	/* Check for compares */
+	if (strcmp(token, "==") == 0)
+		*ctype = FILTER_CMP_EQ;
+	else if (strcmp(token, "!=") == 0)
+		*ctype = FILTER_CMP_NE;
+	else if (strcmp(token, "<") == 0)
+		*ctype = FILTER_CMP_LT;
+	else if (strcmp(token, ">") == 0)
+		*ctype = FILTER_CMP_GT;
+	else if (strcmp(token, "<=") == 0)
+		*ctype = FILTER_CMP_LE;
+	else if (strcmp(token, ">=") == 0)
+		*ctype = FILTER_CMP_GE;
+	else if (strcmp(token, "=~") == 0)
+		*ctype = FILTER_CMP_REGEX;
+	else if (strcmp(token, "!~") == 0)
+		*ctype = FILTER_CMP_NOT_REGEX;
+	else
+		return OP_NONE;
+
+	return OP_CMP;
+}
+
+static int check_op_done(struct filter_arg *arg)
+{
+	switch (arg->type) {
+	case FILTER_ARG_EXP:
+		return arg->exp.right != NULL;
+
+	case FILTER_ARG_OP:
+		return arg->op.right != NULL;
+
+	case FILTER_ARG_NUM:
+		return arg->num.right != NULL;
+
+	case FILTER_ARG_STR:
+		/* A string conversion is always done */
+		return 1;
+
+	case FILTER_ARG_BOOLEAN:
+		/* field not found, is ok */
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+enum filter_vals {
+	FILTER_VAL_NORM,
+	FILTER_VAL_FALSE,
+	FILTER_VAL_TRUE,
+};
+
+void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
+		  struct filter_arg *arg)
+{
+	struct filter_arg *other_child;
+	struct filter_arg **ptr;
+
+	if (parent->type != FILTER_ARG_OP &&
+	    arg->type != FILTER_ARG_OP)
+		die("can not reparent other than OP");
+
+	/* Get the sibling */
+	if (old_child->op.right == arg) {
+		ptr = &old_child->op.right;
+		other_child = old_child->op.left;
+	} else if (old_child->op.left == arg) {
+		ptr = &old_child->op.left;
+		other_child = old_child->op.right;
+	} else
+		die("Error in reparent op, find other child");
+
+	/* Detach arg from old_child */
+	*ptr = NULL;
+
+	/* Check for root */
+	if (parent == old_child) {
+		free_arg(other_child);
+		*parent = *arg;
+		/* Free arg without recussion */
+		free(arg);
+		return;
+	}
+
+	if (parent->op.right == old_child)
+		ptr = &parent->op.right;
+	else if (parent->op.left == old_child)
+		ptr = &parent->op.left;
+	else
+		die("Error in reparent op");
+	*ptr = arg;
+
+	free_arg(old_child);
+}
+
+enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
+{
+	enum filter_vals lval, rval;
+
+	switch (arg->type) {
+
+		/* bad case */
+	case FILTER_ARG_BOOLEAN:
+		return FILTER_VAL_FALSE + arg->boolean.value;
+
+		/* good cases: */
+	case FILTER_ARG_STR:
+	case FILTER_ARG_VALUE:
+	case FILTER_ARG_FIELD:
+		return FILTER_VAL_NORM;
+
+	case FILTER_ARG_EXP:
+		lval = test_arg(arg, arg->exp.left);
+		if (lval != FILTER_VAL_NORM)
+			return lval;
+		rval = test_arg(arg, arg->exp.right);
+		if (rval != FILTER_VAL_NORM)
+			return rval;
+		return FILTER_VAL_NORM;
+
+	case FILTER_ARG_NUM:
+		lval = test_arg(arg, arg->num.left);
+		if (lval != FILTER_VAL_NORM)
+			return lval;
+		rval = test_arg(arg, arg->num.right);
+		if (rval != FILTER_VAL_NORM)
+			return rval;
+		return FILTER_VAL_NORM;
+
+	case FILTER_ARG_OP:
+		if (arg->op.type != FILTER_OP_NOT) {
+			lval = test_arg(arg, arg->op.left);
+			switch (lval) {
+			case FILTER_VAL_NORM:
+				break;
+			case FILTER_VAL_TRUE:
+				if (arg->op.type == FILTER_OP_OR)
+					return FILTER_VAL_TRUE;
+				rval = test_arg(arg, arg->op.right);
+				if (rval != FILTER_VAL_NORM)
+					return rval;
+
+				reparent_op_arg(parent, arg, arg->op.right);
+				return FILTER_VAL_NORM;
+
+			case FILTER_VAL_FALSE:
+				if (arg->op.type == FILTER_OP_AND)
+					return FILTER_VAL_FALSE;
+				rval = test_arg(arg, arg->op.right);
+				if (rval != FILTER_VAL_NORM)
+					return rval;
+
+				reparent_op_arg(parent, arg, arg->op.right);
+				return FILTER_VAL_NORM;
+			}
+		}
+
+		rval = test_arg(arg, arg->op.right);
+		switch (rval) {
+		case FILTER_VAL_NORM:
+			break;
+		case FILTER_VAL_TRUE:
+			if (arg->op.type == FILTER_OP_OR)
+				return FILTER_VAL_TRUE;
+			if (arg->op.type == FILTER_OP_NOT)
+				return FILTER_VAL_FALSE;
+
+			reparent_op_arg(parent, arg, arg->op.left);
+			return FILTER_VAL_NORM;
+
+		case FILTER_VAL_FALSE:
+			if (arg->op.type == FILTER_OP_AND)
+				return FILTER_VAL_FALSE;
+			if (arg->op.type == FILTER_OP_NOT)
+				return FILTER_VAL_TRUE;
+
+			reparent_op_arg(parent, arg, arg->op.left);
+			return FILTER_VAL_NORM;
+		}
+
+		return FILTER_VAL_NORM;
+	default:
+		die("bad arg in filter tree");
+	}
+	return FILTER_VAL_NORM;
+}
+
+/* Remove any unknown event fields */
+static struct filter_arg *collapse_tree(struct filter_arg *arg)
+{
+	enum filter_vals ret;
+
+	ret = test_arg(arg, arg);
+	switch (ret) {
+	case FILTER_VAL_NORM:
+		return arg;
+
+	case FILTER_VAL_TRUE:
+	case FILTER_VAL_FALSE:
+		free_arg(arg);
+		arg = allocate_arg();
+		arg->type = FILTER_ARG_BOOLEAN;
+		arg->boolean.value = ret == FILTER_VAL_TRUE;
+	}
+
+	return arg;
+}
+
+static int
+process_filter(struct event_format *event, struct filter_arg **parg,
+	       char **error_str, int not)
+{
+	enum event_type type;
+	char *token = NULL;
+	struct filter_arg *current_op = NULL;
+	struct filter_arg *current_exp = NULL;
+	struct filter_arg *left_item = NULL;
+	struct filter_arg *arg = NULL;
+	enum op_type op_type;
+	enum filter_op_type btype;
+	enum filter_exp_type etype;
+	enum filter_cmp_type ctype;
+	int ret;
+
+	*parg = NULL;
+
+	do {
+		free(token);
+		type = read_token(&token);
+		switch (type) {
+		case EVENT_SQUOTE:
+		case EVENT_DQUOTE:
+		case EVENT_ITEM:
+			arg = create_arg_item(event, token, type, error_str);
+			if (!arg)
+				goto fail;
+			if (!left_item)
+				left_item = arg;
+			else if (current_exp) {
+				ret = add_right(current_exp, arg, error_str);
+				if (ret < 0)
+					goto fail;
+				left_item = NULL;
+				/* Not's only one one expression */
+				if (not) {
+					arg = NULL;
+					if (current_op)
+						goto fail_print;
+					free(token);
+					*parg = current_exp;
+					return 0;
+				}
+			} else
+				goto fail_print;
+			arg = NULL;
+			break;
+
+		case EVENT_DELIM:
+			if (*token == ',') {
+				show_error(error_str,
+					   "Illegal token ','");
+				goto fail;
+			}
+
+			if (*token == '(') {
+				if (left_item) {
+					show_error(error_str,
+						   "Open paren can not come after item");
+					goto fail;
+				}
+				if (current_exp) {
+					show_error(error_str,
+						   "Open paren can not come after expression");
+					goto fail;
+				}
+
+				ret = process_filter(event, &arg, error_str, 0);
+				if (ret != 1) {
+					if (ret == 0)
+						show_error(error_str,
+							   "Unbalanced number of '('");
+					goto fail;
+				}
+				ret = 0;
+
+				/* A not wants just one expression */
+				if (not) {
+					if (current_op)
+						goto fail_print;
+					*parg = arg;
+					return 0;
+				}
+
+				if (current_op)
+					ret = add_right(current_op, arg, error_str);
+				else
+					current_exp = arg;
+
+				if (ret < 0)
+					goto fail;
+
+			} else { /* ')' */
+				if (!current_op && !current_exp)
+					goto fail_print;
+
+				/* Make sure everything is finished at this level */
+				if (current_exp && !check_op_done(current_exp))
+					goto fail_print;
+				if (current_op && !check_op_done(current_op))
+					goto fail_print;
+
+				if (current_op)
+					*parg = current_op;
+				else
+					*parg = current_exp;
+				return 1;
+			}
+			break;
+
+		case EVENT_OP:
+			op_type = process_op(token, &btype, &ctype, &etype);
+
+			/* All expect a left arg except for NOT */
+			switch (op_type) {
+			case OP_BOOL:
+				/* Logic ops need a left expression */
+				if (!current_exp && !current_op)
+					goto fail_print;
+				/* fall through */
+			case OP_NOT:
+				/* logic only processes ops and exp */
+				if (left_item)
+					goto fail_print;
+				break;
+			case OP_EXP:
+			case OP_CMP:
+				if (!left_item)
+					goto fail_print;
+				break;
+			case OP_NONE:
+				show_error(error_str,
+					   "Unknown op token %s", token);
+				goto fail;
+			}
+
+			ret = 0;
+			switch (op_type) {
+			case OP_BOOL:
+				arg = create_arg_op(btype);
+				if (current_op)
+					ret = add_left(arg, current_op);
+				else
+					ret = add_left(arg, current_exp);
+				current_op = arg;
+				current_exp = NULL;
+				break;
+
+			case OP_NOT:
+				arg = create_arg_op(btype);
+				if (current_op)
+					ret = add_right(current_op, arg, error_str);
+				if (ret < 0)
+					goto fail;
+				current_exp = arg;
+				ret = process_filter(event, &arg, error_str, 1);
+				if (ret < 0)
+					goto fail;
+				ret = add_right(current_exp, arg, error_str);
+				if (ret < 0)
+					goto fail;
+				break;
+
+			case OP_EXP:
+			case OP_CMP:
+				if (op_type == OP_EXP)
+					arg = create_arg_exp(etype);
+				else
+					arg = create_arg_cmp(ctype);
+
+				if (current_op)
+					ret = add_right(current_op, arg, error_str);
+				if (ret < 0)
+					goto fail;
+				ret = add_left(arg, left_item);
+				if (ret < 0) {
+					arg = NULL;
+					goto fail_print;
+				}
+				current_exp = arg;
+				break;
+			default:
+				break;
+			}
+			arg = NULL;
+			if (ret < 0)
+				goto fail_print;
+			break;
+		case EVENT_NONE:
+			break;
+		default:
+			goto fail_print;
+		}
+	} while (type != EVENT_NONE);
+
+	if (!current_op && !current_exp)
+		goto fail_print;
+
+	if (!current_op)
+		current_op = current_exp;
+
+	current_op = collapse_tree(current_op);
+
+	*parg = current_op;
+
+	return 0;
+
+ fail_print:
+	show_error(error_str, "Syntax error");
+ fail:
+	free_arg(current_op);
+	free_arg(current_exp);
+	free_arg(arg);
+	free(token);
+	return -1;
+}
+
+static int
+process_event(struct event_format *event, const char *filter_str,
+	      struct filter_arg **parg, char **error_str)
+{
+	int ret;
+
+	pevent_buffer_init(filter_str, strlen(filter_str));
+
+	ret = process_filter(event, parg, error_str, 0);
+	if (ret == 1) {
+		show_error(error_str,
+			   "Unbalanced number of ')'");
+		return -1;
+	}
+	if (ret < 0)
+		return ret;
+
+	/* If parg is NULL, then make it into FALSE */
+	if (!*parg) {
+		*parg = allocate_arg();
+		(*parg)->type = FILTER_ARG_BOOLEAN;
+		(*parg)->boolean.value = FILTER_FALSE;
+	}
+
+	return 0;
+}
+
+static int filter_event(struct event_filter *filter,
+			struct event_format *event,
+			const char *filter_str, char **error_str)
+{
+	struct filter_type *filter_type;
+	struct filter_arg *arg;
+	int ret;
+
+	if (filter_str) {
+		ret = process_event(event, filter_str, &arg, error_str);
+		if (ret < 0)
+			return ret;
+
+	} else {
+		/* just add a TRUE arg */
+		arg = allocate_arg();
+		arg->type = FILTER_ARG_BOOLEAN;
+		arg->boolean.value = FILTER_TRUE;
+	}
+
+	filter_type = add_filter_type(filter, event->id);
+	if (filter_type->filter)
+		free_arg(filter_type->filter);
+	filter_type->filter = arg;
+
+	return 0;
+}
+
+/**
+ * pevent_filter_add_filter_str - add a new filter
+ * @filter: the event filter to add to
+ * @filter_str: the filter string that contains the filter
+ * @error_str: string containing reason for failed filter
+ *
+ * Returns 0 if the filter was successfully added
+ *   -1 if there was an error.
+ *
+ * On error, if @error_str points to a string pointer,
+ * it is set to the reason that the filter failed.
+ * This string must be freed with "free".
+ */
+int pevent_filter_add_filter_str(struct event_filter *filter,
+				 const char *filter_str,
+				 char **error_str)
+{
+	struct pevent *pevent = filter->pevent;
+	struct event_list *event;
+	struct event_list *events = NULL;
+	const char *filter_start;
+	const char *next_event;
+	char *this_event;
+	char *event_name = NULL;
+	char *sys_name = NULL;
+	char *sp;
+	int rtn = 0;
+	int len;
+	int ret;
+
+	/* clear buffer to reset show error */
+	pevent_buffer_init("", 0);
+
+	if (error_str)
+		*error_str = NULL;
+
+	filter_start = strchr(filter_str, ':');
+	if (filter_start)
+		len = filter_start - filter_str;
+	else
+		len = strlen(filter_str);
+
+
+	do {
+		next_event = strchr(filter_str, ',');
+		if (next_event &&
+		    (!filter_start || next_event < filter_start))
+			len = next_event - filter_str;
+		else if (filter_start)
+			len = filter_start - filter_str;
+		else
+			len = strlen(filter_str);
+
+		this_event = malloc_or_die(len + 1);
+		memcpy(this_event, filter_str, len);
+		this_event[len] = 0;
+
+		if (next_event)
+			next_event++;
+
+		filter_str = next_event;
+
+		sys_name = strtok_r(this_event, "/", &sp);
+		event_name = strtok_r(NULL, "/", &sp);
+
+		if (!sys_name) {
+			show_error(error_str, "No filter found");
+			/* This can only happen when events is NULL, but still */
+			free_events(events);
+			free(this_event);
+			return -1;
+		}
+
+		/* Find this event */
+		ret = find_event(pevent, &events, strim(sys_name), strim(event_name));
+		if (ret < 0) {
+			if (event_name)
+				show_error(error_str,
+					   "No event found under '%s.%s'",
+					   sys_name, event_name);
+			else
+				show_error(error_str,
+					   "No event found under '%s'",
+					   sys_name);
+			free_events(events);
+			free(this_event);
+			return -1;
+		}
+		free(this_event);
+	} while (filter_str);
+
+	/* Skip the ':' */
+	if (filter_start)
+		filter_start++;
+
+	/* filter starts here */
+	for (event = events; event; event = event->next) {
+		ret = filter_event(filter, event->event, filter_start,
+				   error_str);
+		/* Failures are returned if a parse error happened */
+		if (ret < 0)
+			rtn = ret;
+
+		if (ret >= 0 && pevent->test_filters) {
+			char *test;
+			test = pevent_filter_make_string(filter, event->event->id);
+			printf(" '%s: %s'\n", event->event->name, test);
+			free(test);
+		}
+	}
+
+	free_events(events);
+
+	if (rtn >= 0 && pevent->test_filters)
+		exit(0);
+
+	return rtn;
+}
+
+static void free_filter_type(struct filter_type *filter_type)
+{
+	free_arg(filter_type->filter);
+}
+
+/**
+ * pevent_filter_remove_event - remove a filter for an event
+ * @filter: the event filter to remove from
+ * @event_id: the event to remove a filter for
+ *
+ * Removes the filter saved for an event defined by @event_id
+ * from the @filter.
+ *
+ * Returns 1: if an event was removed
+ *   0: if the event was not found
+ */
+int pevent_filter_remove_event(struct event_filter *filter,
+			       int event_id)
+{
+	struct filter_type *filter_type;
+	unsigned long len;
+
+	if (!filter->filters)
+		return 0;
+
+	filter_type = find_filter_type(filter, event_id);
+
+	if (!filter_type)
+		return 0;
+
+	free_filter_type(filter_type);
+
+	/* The filter_type points into the event_filters array */
+	len = (unsigned long)(filter->event_filters + filter->filters) -
+		(unsigned long)(filter_type + 1);
+
+	memmove(filter_type, filter_type + 1, len);
+	filter->filters--;
+
+	memset(&filter->event_filters[filter->filters], 0,
+	       sizeof(*filter_type));
+
+	return 1;
+}
+
+/**
+ * pevent_filter_reset - clear all filters in a filter
+ * @filter: the event filter to reset
+ *
+ * Removes all filters from a filter and resets it.
+ */
+void pevent_filter_reset(struct event_filter *filter)
+{
+	int i;
+
+	for (i = 0; i < filter->filters; i++)
+		free_filter_type(&filter->event_filters[i]);
+
+	free(filter->event_filters);
+	filter->filters = 0;
+	filter->event_filters = NULL;
+}
+
+void pevent_filter_free(struct event_filter *filter)
+{
+	pevent_unref(filter->pevent);
+
+	pevent_filter_reset(filter);
+
+	free(filter);
+}
+
+static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg);
+
+static int copy_filter_type(struct event_filter *filter,
+			     struct event_filter *source,
+			     struct filter_type *filter_type)
+{
+	struct filter_arg *arg;
+	struct event_format *event;
+	const char *sys;
+	const char *name;
+	char *str;
+
+	/* Can't assume that the pevent's are the same */
+	sys = filter_type->event->system;
+	name = filter_type->event->name;
+	event = pevent_find_event_by_name(filter->pevent, sys, name);
+	if (!event)
+		return -1;
+
+	str = arg_to_str(source, filter_type->filter);
+	if (!str)
+		return -1;
+
+	if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
+		/* Add trivial event */
+		arg = allocate_arg();
+		arg->type = FILTER_ARG_BOOLEAN;
+		if (strcmp(str, "TRUE") == 0)
+			arg->boolean.value = 1;
+		else
+			arg->boolean.value = 0;
+
+		filter_type = add_filter_type(filter, event->id);
+		filter_type->filter = arg;
+
+		free(str);
+		return 0;
+	}
+
+	filter_event(filter, event, str, NULL);
+	free(str);
+
+	return 0;
+}
+
+/**
+ * pevent_filter_copy - copy a filter using another filter
+ * @dest - the filter to copy to
+ * @source - the filter to copy from
+ *
+ * Returns 0 on success and -1 if not all filters were copied
+ */
+int pevent_filter_copy(struct event_filter *dest, struct event_filter *source)
+{
+	int ret = 0;
+	int i;
+
+	pevent_filter_reset(dest);
+
+	for (i = 0; i < source->filters; i++) {
+		if (copy_filter_type(dest, source, &source->event_filters[i]))
+			ret = -1;
+	}
+	return ret;
+}
+
+
+/**
+ * pevent_update_trivial - update the trivial filters with the given filter
+ * @dest - the filter to update
+ * @source - the filter as the source of the update
+ * @type - the type of trivial filter to update.
+ *
+ * Scan dest for trivial events matching @type to replace with the source.
+ *
+ * Returns 0 on success and -1 if there was a problem updating, but
+ *   events may have still been updated on error.
+ */
+int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
+			  enum filter_trivial_type type)
+{
+	struct pevent *src_pevent;
+	struct pevent *dest_pevent;
+	struct event_format *event;
+	struct filter_type *filter_type;
+	struct filter_arg *arg;
+	char *str;
+	int i;
+
+	src_pevent = source->pevent;
+	dest_pevent = dest->pevent;
+
+	/* Do nothing if either of the filters has nothing to filter */
+	if (!dest->filters || !source->filters)
+		return 0;
+
+	for (i = 0; i < dest->filters; i++) {
+		filter_type = &dest->event_filters[i];
+		arg = filter_type->filter;
+		if (arg->type != FILTER_ARG_BOOLEAN)
+			continue;
+		if ((arg->boolean.value && type == FILTER_TRIVIAL_FALSE) ||
+		    (!arg->boolean.value && type == FILTER_TRIVIAL_TRUE))
+			continue;
+
+		event = filter_type->event;
+
+		if (src_pevent != dest_pevent) {
+			/* do a look up */
+			event = pevent_find_event_by_name(src_pevent,
+							  event->system,
+							  event->name);
+			if (!event)
+				return -1;
+		}
+
+		str = pevent_filter_make_string(source, event->id);
+		if (!str)
+			continue;
+
+		/* Don't bother if the filter is trivial too */
+		if (strcmp(str, "TRUE") != 0 && strcmp(str, "FALSE") != 0)
+			filter_event(dest, event, str, NULL);
+		free(str);
+	}
+	return 0;
+}
+
+/**
+ * pevent_filter_clear_trivial - clear TRUE and FALSE filters
+ * @filter: the filter to remove trivial filters from
+ * @type: remove only true, false, or both
+ *
+ * Removes filters that only contain a TRUE or FALES boolean arg.
+ */
+void pevent_filter_clear_trivial(struct event_filter *filter,
+				 enum filter_trivial_type type)
+{
+	struct filter_type *filter_type;
+	int count = 0;
+	int *ids;
+	int i;
+
+	if (!filter->filters)
+		return;
+
+	/*
+	 * Two steps, first get all ids with trivial filters.
+	 *  then remove those ids.
+	 */
+	for (i = 0; i < filter->filters; i++) {
+		filter_type = &filter->event_filters[i];
+		if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
+			continue;
+		switch (type) {
+		case FILTER_TRIVIAL_FALSE:
+			if (filter_type->filter->boolean.value)
+				continue;
+		case FILTER_TRIVIAL_TRUE:
+			if (!filter_type->filter->boolean.value)
+				continue;
+		default:
+			break;
+		}
+		if (count)
+			ids = realloc(ids, sizeof(*ids) * (count + 1));
+		else
+			ids = malloc(sizeof(*ids));
+		if (!ids)
+			die("Can't allocate ids");
+		ids[count++] = filter_type->event_id;
+	}
+
+	if (!count)
+		return;
+
+	for (i = 0; i < count; i++)
+		pevent_filter_remove_event(filter, ids[i]);
+
+	free(ids);
+}
+
+/**
+ * pevent_filter_event_has_trivial - return true event contains trivial filter
+ * @filter: the filter with the information
+ * @event_id: the id of the event to test
+ * @type: trivial type to test for (TRUE, FALSE, EITHER)
+ *
+ * Returns 1 if the event contains a matching trivial type
+ *  otherwise 0.
+ */
+int pevent_filter_event_has_trivial(struct event_filter *filter,
+				    int event_id,
+				    enum filter_trivial_type type)
+{
+	struct filter_type *filter_type;
+
+	if (!filter->filters)
+		return 0;
+
+	filter_type = find_filter_type(filter, event_id);
+
+	if (!filter_type)
+		return 0;
+
+	if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
+		return 0;
+
+	switch (type) {
+	case FILTER_TRIVIAL_FALSE:
+		return !filter_type->filter->boolean.value;
+
+	case FILTER_TRIVIAL_TRUE:
+		return filter_type->filter->boolean.value;
+	default:
+		return 1;
+	}
+}
+
+static int test_filter(struct event_format *event,
+		       struct filter_arg *arg, struct pevent_record *record);
+
+static const char *
+get_comm(struct event_format *event, struct pevent_record *record)
+{
+	const char *comm;
+	int pid;
+
+	pid = pevent_data_pid(event->pevent, record);
+	comm = pevent_data_comm_from_pid(event->pevent, pid);
+	return comm;
+}
+
+static unsigned long long
+get_value(struct event_format *event,
+	  struct format_field *field, struct pevent_record *record)
+{
+	unsigned long long val;
+
+	/* Handle our dummy "comm" field */
+	if (field == &comm) {
+		const char *name;
+
+		name = get_comm(event, record);
+		return (unsigned long long)name;
+	}
+
+	pevent_read_number_field(field, record->data, &val);
+
+	if (!(field->flags & FIELD_IS_SIGNED))
+		return val;
+
+	switch (field->size) {
+	case 1:
+		return (char)val;
+	case 2:
+		return (short)val;
+	case 4:
+		return (int)val;
+	case 8:
+		return (long long)val;
+	}
+	return val;
+}
+
+static unsigned long long
+get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record);
+
+static unsigned long long
+get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
+{
+	unsigned long long lval, rval;
+
+	lval = get_arg_value(event, arg->exp.left, record);
+	rval = get_arg_value(event, arg->exp.right, record);
+
+	switch (arg->exp.type) {
+	case FILTER_EXP_ADD:
+		return lval + rval;
+
+	case FILTER_EXP_SUB:
+		return lval - rval;
+
+	case FILTER_EXP_MUL:
+		return lval * rval;
+
+	case FILTER_EXP_DIV:
+		return lval / rval;
+
+	case FILTER_EXP_MOD:
+		return lval % rval;
+
+	case FILTER_EXP_RSHIFT:
+		return lval >> rval;
+
+	case FILTER_EXP_LSHIFT:
+		return lval << rval;
+
+	case FILTER_EXP_AND:
+		return lval & rval;
+
+	case FILTER_EXP_OR:
+		return lval | rval;
+
+	case FILTER_EXP_XOR:
+		return lval ^ rval;
+
+	case FILTER_EXP_NOT:
+	default:
+		die("error in exp");
+	}
+	return 0;
+}
+
+static unsigned long long
+get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
+{
+	switch (arg->type) {
+	case FILTER_ARG_FIELD:
+		return get_value(event, arg->field.field, record);
+
+	case FILTER_ARG_VALUE:
+		if (arg->value.type != FILTER_NUMBER)
+			die("must have number field!");
+		return arg->value.val;
+
+	case FILTER_ARG_EXP:
+		return get_exp_value(event, arg, record);
+
+	default:
+		die("oops in filter");
+	}
+	return 0;
+}
+
+static int test_num(struct event_format *event,
+		    struct filter_arg *arg, struct pevent_record *record)
+{
+	unsigned long long lval, rval;
+
+	lval = get_arg_value(event, arg->num.left, record);
+	rval = get_arg_value(event, arg->num.right, record);
+
+	switch (arg->num.type) {
+	case FILTER_CMP_EQ:
+		return lval == rval;
+
+	case FILTER_CMP_NE:
+		return lval != rval;
+
+	case FILTER_CMP_GT:
+		return lval > rval;
+
+	case FILTER_CMP_LT:
+		return lval < rval;
+
+	case FILTER_CMP_GE:
+		return lval >= rval;
+
+	case FILTER_CMP_LE:
+		return lval <= rval;
+
+	default:
+		/* ?? */
+		return 0;
+	}
+}
+
+static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record)
+{
+	const char *val = record->data + arg->str.field->offset;
+
+	/*
+	 * We need to copy the data since we can't be sure the field
+	 * is null terminated.
+	 */
+	if (*(val + arg->str.field->size - 1)) {
+		/* copy it */
+		memcpy(arg->str.buffer, val, arg->str.field->size);
+		/* the buffer is already NULL terminated */
+		val = arg->str.buffer;
+	}
+	return val;
+}
+
+static int test_str(struct event_format *event,
+		    struct filter_arg *arg, struct pevent_record *record)
+{
+	const char *val;
+
+	if (arg->str.field == &comm)
+		val = get_comm(event, record);
+	else
+		val = get_field_str(arg, record);
+
+	switch (arg->str.type) {
+	case FILTER_CMP_MATCH:
+		return strcmp(val, arg->str.val) == 0;
+
+	case FILTER_CMP_NOT_MATCH:
+		return strcmp(val, arg->str.val) != 0;
+
+	case FILTER_CMP_REGEX:
+		/* Returns zero on match */
+		return !regexec(&arg->str.reg, val, 0, NULL, 0);
+
+	case FILTER_CMP_NOT_REGEX:
+		return regexec(&arg->str.reg, val, 0, NULL, 0);
+
+	default:
+		/* ?? */
+		return 0;
+	}
+}
+
+static int test_op(struct event_format *event,
+		   struct filter_arg *arg, struct pevent_record *record)
+{
+	switch (arg->op.type) {
+	case FILTER_OP_AND:
+		return test_filter(event, arg->op.left, record) &&
+			test_filter(event, arg->op.right, record);
+
+	case FILTER_OP_OR:
+		return test_filter(event, arg->op.left, record) ||
+			test_filter(event, arg->op.right, record);
+
+	case FILTER_OP_NOT:
+		return !test_filter(event, arg->op.right, record);
+
+	default:
+		/* ?? */
+		return 0;
+	}
+}
+
+static int test_filter(struct event_format *event,
+		       struct filter_arg *arg, struct pevent_record *record)
+{
+	switch (arg->type) {
+	case FILTER_ARG_BOOLEAN:
+		/* easy case */
+		return arg->boolean.value;
+
+	case FILTER_ARG_OP:
+		return test_op(event, arg, record);
+
+	case FILTER_ARG_NUM:
+		return test_num(event, arg, record);
+
+	case FILTER_ARG_STR:
+		return test_str(event, arg, record);
+
+	case FILTER_ARG_EXP:
+	case FILTER_ARG_VALUE:
+	case FILTER_ARG_FIELD:
+		/*
+		 * Expressions, fields and values evaluate
+		 * to true if they return non zero
+		 */
+		return !!get_arg_value(event, arg, record);
+
+	default:
+		die("oops!");
+		/* ?? */
+		return 0;
+	}
+}
+
+/**
+ * pevent_event_filtered - return true if event has filter
+ * @filter: filter struct with filter information
+ * @event_id: event id to test if filter exists
+ *
+ * Returns 1 if filter found for @event_id
+ *   otherwise 0;
+ */
+int pevent_event_filtered(struct event_filter *filter,
+			  int event_id)
+{
+	struct filter_type *filter_type;
+
+	if (!filter->filters)
+		return 0;
+
+	filter_type = find_filter_type(filter, event_id);
+
+	return filter_type ? 1 : 0;
+}
+
+/**
+ * pevent_filter_match - test if a record matches a filter
+ * @filter: filter struct with filter information
+ * @record: the record to test against the filter
+ *
+ * Returns:
+ *  1 - filter found for event and @record matches
+ *  0 - filter found for event and @record does not match
+ * -1 - no filter found for @record's event
+ * -2 - if no filters exist
+ */
+int pevent_filter_match(struct event_filter *filter,
+			struct pevent_record *record)
+{
+	struct pevent *pevent = filter->pevent;
+	struct filter_type *filter_type;
+	int event_id;
+
+	if (!filter->filters)
+		return FILTER_NONE;
+
+	event_id = pevent_data_type(pevent, record);
+
+	filter_type = find_filter_type(filter, event_id);
+
+	if (!filter_type)
+		return FILTER_NOEXIST;
+
+	return test_filter(filter_type->event, filter_type->filter, record) ?
+		FILTER_MATCH : FILTER_MISS;
+}
+
+static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *str = NULL;
+	char *left = NULL;
+	char *right = NULL;
+	char *op = NULL;
+	int left_val = -1;
+	int right_val = -1;
+	int val;
+	int len;
+
+	switch (arg->op.type) {
+	case FILTER_OP_AND:
+		op = "&&";
+		/* fall through */
+	case FILTER_OP_OR:
+		if (!op)
+			op = "||";
+
+		left = arg_to_str(filter, arg->op.left);
+		right = arg_to_str(filter, arg->op.right);
+		if (!left || !right)
+			break;
+
+		/* Try to consolidate boolean values */
+		if (strcmp(left, "TRUE") == 0)
+			left_val = 1;
+		else if (strcmp(left, "FALSE") == 0)
+			left_val = 0;
+
+		if (strcmp(right, "TRUE") == 0)
+			right_val = 1;
+		else if (strcmp(right, "FALSE") == 0)
+			right_val = 0;
+
+		if (left_val >= 0) {
+			if ((arg->op.type == FILTER_OP_AND && !left_val) ||
+			    (arg->op.type == FILTER_OP_OR && left_val)) {
+				/* Just return left value */
+				str = left;
+				left = NULL;
+				break;
+			}
+			if (right_val >= 0) {
+				/* just evaluate this. */
+				val = 0;
+				switch (arg->op.type) {
+				case FILTER_OP_AND:
+					val = left_val && right_val;
+					break;
+				case FILTER_OP_OR:
+					val = left_val || right_val;
+					break;
+				default:
+					break;
+				}
+				str = malloc_or_die(6);
+				if (val)
+					strcpy(str, "TRUE");
+				else
+					strcpy(str, "FALSE");
+				break;
+			}
+		}
+		if (right_val >= 0) {
+			if ((arg->op.type == FILTER_OP_AND && !right_val) ||
+			    (arg->op.type == FILTER_OP_OR && right_val)) {
+				/* Just return right value */
+				str = right;
+				right = NULL;
+				break;
+			}
+			/* The right value is meaningless */
+			str = left;
+			left = NULL;
+			break;
+		}
+
+		len = strlen(left) + strlen(right) + strlen(op) + 10;
+		str = malloc_or_die(len);
+		snprintf(str, len, "(%s) %s (%s)",
+			 left, op, right);
+		break;
+
+	case FILTER_OP_NOT:
+		op = "!";
+		right = arg_to_str(filter, arg->op.right);
+		if (!right)
+			break;
+
+		/* See if we can consolidate */
+		if (strcmp(right, "TRUE") == 0)
+			right_val = 1;
+		else if (strcmp(right, "FALSE") == 0)
+			right_val = 0;
+		if (right_val >= 0) {
+			/* just return the opposite */
+			str = malloc_or_die(6);
+			if (right_val)
+				strcpy(str, "FALSE");
+			else
+				strcpy(str, "TRUE");
+			break;
+		}
+		len = strlen(right) + strlen(op) + 3;
+		str = malloc_or_die(len);
+		snprintf(str, len, "%s(%s)", op, right);
+		break;
+
+	default:
+		/* ?? */
+		break;
+	}
+	free(left);
+	free(right);
+	return str;
+}
+
+static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *str;
+
+	str = malloc_or_die(30);
+
+	snprintf(str, 30, "%lld", arg->value.val);
+
+	return str;
+}
+
+static char *field_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	return strdup(arg->field.field->name);
+}
+
+static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *lstr;
+	char *rstr;
+	char *op;
+	char *str;
+	int len;
+
+	lstr = arg_to_str(filter, arg->exp.left);
+	rstr = arg_to_str(filter, arg->exp.right);
+
+	switch (arg->exp.type) {
+	case FILTER_EXP_ADD:
+		op = "+";
+		break;
+	case FILTER_EXP_SUB:
+		op = "-";
+		break;
+	case FILTER_EXP_MUL:
+		op = "*";
+		break;
+	case FILTER_EXP_DIV:
+		op = "/";
+		break;
+	case FILTER_EXP_MOD:
+		op = "%";
+		break;
+	case FILTER_EXP_RSHIFT:
+		op = ">>";
+		break;
+	case FILTER_EXP_LSHIFT:
+		op = "<<";
+		break;
+	case FILTER_EXP_AND:
+		op = "&";
+		break;
+	case FILTER_EXP_OR:
+		op = "|";
+		break;
+	case FILTER_EXP_XOR:
+		op = "^";
+		break;
+	default:
+		die("oops in exp");
+	}
+
+	len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
+	str = malloc_or_die(len);
+	snprintf(str, len, "%s %s %s", lstr, op, rstr);
+	free(lstr);
+	free(rstr);
+
+	return str;
+}
+
+static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *lstr;
+	char *rstr;
+	char *str = NULL;
+	char *op = NULL;
+	int len;
+
+	lstr = arg_to_str(filter, arg->num.left);
+	rstr = arg_to_str(filter, arg->num.right);
+
+	switch (arg->num.type) {
+	case FILTER_CMP_EQ:
+		op = "==";
+		/* fall through */
+	case FILTER_CMP_NE:
+		if (!op)
+			op = "!=";
+		/* fall through */
+	case FILTER_CMP_GT:
+		if (!op)
+			op = ">";
+		/* fall through */
+	case FILTER_CMP_LT:
+		if (!op)
+			op = "<";
+		/* fall through */
+	case FILTER_CMP_GE:
+		if (!op)
+			op = ">=";
+		/* fall through */
+	case FILTER_CMP_LE:
+		if (!op)
+			op = "<=";
+
+		len = strlen(lstr) + strlen(op) + strlen(rstr) + 4;
+		str = malloc_or_die(len);
+		sprintf(str, "%s %s %s", lstr, op, rstr);
+
+		break;
+
+	default:
+		/* ?? */
+		break;
+	}
+
+	free(lstr);
+	free(rstr);
+	return str;
+}
+
+static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *str = NULL;
+	char *op = NULL;
+	int len;
+
+	switch (arg->str.type) {
+	case FILTER_CMP_MATCH:
+		op = "==";
+		/* fall through */
+	case FILTER_CMP_NOT_MATCH:
+		if (!op)
+			op = "!=";
+		/* fall through */
+	case FILTER_CMP_REGEX:
+		if (!op)
+			op = "=~";
+		/* fall through */
+	case FILTER_CMP_NOT_REGEX:
+		if (!op)
+			op = "!~";
+
+		len = strlen(arg->str.field->name) + strlen(op) +
+			strlen(arg->str.val) + 6;
+		str = malloc_or_die(len);
+		snprintf(str, len, "%s %s \"%s\"",
+			 arg->str.field->name,
+			 op, arg->str.val);
+		break;
+
+	default:
+		/* ?? */
+		break;
+	}
+	return str;
+}
+
+static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *str;
+
+	switch (arg->type) {
+	case FILTER_ARG_BOOLEAN:
+		str = malloc_or_die(6);
+		if (arg->boolean.value)
+			strcpy(str, "TRUE");
+		else
+			strcpy(str, "FALSE");
+		return str;
+
+	case FILTER_ARG_OP:
+		return op_to_str(filter, arg);
+
+	case FILTER_ARG_NUM:
+		return num_to_str(filter, arg);
+
+	case FILTER_ARG_STR:
+		return str_to_str(filter, arg);
+
+	case FILTER_ARG_VALUE:
+		return val_to_str(filter, arg);
+
+	case FILTER_ARG_FIELD:
+		return field_to_str(filter, arg);
+
+	case FILTER_ARG_EXP:
+		return exp_to_str(filter, arg);
+
+	default:
+		/* ?? */
+		return NULL;
+	}
+
+}
+
+/**
+ * pevent_filter_make_string - return a string showing the filter
+ * @filter: filter struct with filter information
+ * @event_id: the event id to return the filter string with
+ *
+ * Returns a string that displays the filter contents.
+ *  This string must be freed with free(str).
+ *  NULL is returned if no filter is found.
+ */
+char *
+pevent_filter_make_string(struct event_filter *filter, int event_id)
+{
+	struct filter_type *filter_type;
+
+	if (!filter->filters)
+		return NULL;
+
+	filter_type = find_filter_type(filter, event_id);
+
+	if (!filter_type)
+		return NULL;
+
+	return arg_to_str(filter, filter_type->filter);
+}
+
+/**
+ * pevent_filter_compare - compare two filters and return if they are the same
+ * @filter1: Filter to compare with @filter2
+ * @filter2: Filter to compare with @filter1
+ *
+ * Returns:
+ *  1 if the two filters hold the same content.
+ *  0 if they do not.
+ */
+int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2)
+{
+	struct filter_type *filter_type1;
+	struct filter_type *filter_type2;
+	char *str1, *str2;
+	int result;
+	int i;
+
+	/* Do the easy checks first */
+	if (filter1->filters != filter2->filters)
+		return 0;
+	if (!filter1->filters && !filter2->filters)
+		return 1;
+
+	/*
+	 * Now take a look at each of the events to see if they have the same
+	 * filters to them.
+	 */
+	for (i = 0; i < filter1->filters; i++) {
+		filter_type1 = &filter1->event_filters[i];
+		filter_type2 = find_filter_type(filter2, filter_type1->event_id);
+		if (!filter_type2)
+			break;
+		if (filter_type1->filter->type != filter_type2->filter->type)
+			break;
+		switch (filter_type1->filter->type) {
+		case FILTER_TRIVIAL_FALSE:
+		case FILTER_TRIVIAL_TRUE:
+			/* trivial types just need the type compared */
+			continue;
+		default:
+			break;
+		}
+		/* The best way to compare complex filters is with strings */
+		str1 = arg_to_str(filter1, filter_type1->filter);
+		str2 = arg_to_str(filter2, filter_type2->filter);
+		result = strcmp(str1, str2) != 0;
+		free(str1);
+		free(str2);
+		if (result)
+			break;
+	}
+
+	if (i < filter1->filters)
+		return 0;
+	return 1;
+}
+
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c
new file mode 100644
index 0000000..f023a13
--- /dev/null
+++ b/tools/lib/traceevent/parse-utils.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#define __weak __attribute__((weak))
+
+void __vdie(const char *fmt, va_list ap)
+{
+	int ret = errno;
+
+	if (errno)
+		perror("trace-cmd");
+	else
+		ret = -1;
+
+	fprintf(stderr, "  ");
+	vfprintf(stderr, fmt, ap);
+
+	fprintf(stderr, "\n");
+	exit(ret);
+}
+
+void __die(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vdie(fmt, ap);
+	va_end(ap);
+}
+
+void __weak die(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vdie(fmt, ap);
+	va_end(ap);
+}
+
+void __vwarning(const char *fmt, va_list ap)
+{
+	if (errno)
+		perror("trace-cmd");
+	errno = 0;
+
+	fprintf(stderr, "  ");
+	vfprintf(stderr, fmt, ap);
+
+	fprintf(stderr, "\n");
+}
+
+void __warning(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vwarning(fmt, ap);
+	va_end(ap);
+}
+
+void __weak warning(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vwarning(fmt, ap);
+	va_end(ap);
+}
+
+void __vpr_stat(const char *fmt, va_list ap)
+{
+	vprintf(fmt, ap);
+	printf("\n");
+}
+
+void __pr_stat(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vpr_stat(fmt, ap);
+	va_end(ap);
+}
+
+void __weak vpr_stat(const char *fmt, va_list ap)
+{
+	__vpr_stat(fmt, ap);
+}
+
+void __weak pr_stat(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vpr_stat(fmt, ap);
+	va_end(ap);
+}
+
+void __weak *malloc_or_die(unsigned int size)
+{
+	void *data;
+
+	data = malloc(size);
+	if (!data)
+		die("malloc");
+	return data;
+}
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
new file mode 100644
index 0000000..b1ccc92
--- /dev/null
+++ b/tools/lib/traceevent/trace-seq.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+/*
+ * The TRACE_SEQ_POISON is to catch the use of using
+ * a trace_seq structure after it was destroyed.
+ */
+#define TRACE_SEQ_POISON	((void *)0xdeadbeef)
+#define TRACE_SEQ_CHECK(s)						\
+do {									\
+	if ((s)->buffer == TRACE_SEQ_POISON)			\
+		die("Usage of trace_seq after it was destroyed");	\
+} while (0)
+
+/**
+ * trace_seq_init - initialize the trace_seq structure
+ * @s: a pointer to the trace_seq structure to initialize
+ */
+void trace_seq_init(struct trace_seq *s)
+{
+	s->len = 0;
+	s->readpos = 0;
+	s->buffer_size = TRACE_SEQ_BUF_SIZE;
+	s->buffer = malloc_or_die(s->buffer_size);
+}
+
+/**
+ * trace_seq_destroy - free up memory of a trace_seq
+ * @s: a pointer to the trace_seq to free the buffer
+ *
+ * Only frees the buffer, not the trace_seq struct itself.
+ */
+void trace_seq_destroy(struct trace_seq *s)
+{
+	if (!s)
+		return;
+	TRACE_SEQ_CHECK(s);
+	free(s->buffer);
+	s->buffer = TRACE_SEQ_POISON;
+}
+
+static void expand_buffer(struct trace_seq *s)
+{
+	s->buffer_size += TRACE_SEQ_BUF_SIZE;
+	s->buffer = realloc(s->buffer, s->buffer_size);
+	if (!s->buffer)
+		die("Can't allocate trace_seq buffer memory");
+}
+
+/**
+ * trace_seq_printf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * It returns 0 if the trace oversizes the buffer's free
+ * space, 1 otherwise.
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+{
+	va_list ap;
+	int len;
+	int ret;
+
+	TRACE_SEQ_CHECK(s);
+
+ try_again:
+	len = (s->buffer_size - 1) - s->len;
+
+	va_start(ap, fmt);
+	ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
+	va_end(ap);
+
+	if (ret >= len) {
+		expand_buffer(s);
+		goto try_again;
+	}
+
+	s->len += ret;
+
+	return 1;
+}
+
+/**
+ * trace_seq_vprintf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+{
+	int len;
+	int ret;
+
+	TRACE_SEQ_CHECK(s);
+
+ try_again:
+	len = (s->buffer_size - 1) - s->len;
+
+	ret = vsnprintf(s->buffer + s->len, len, fmt, args);
+
+	if (ret >= len) {
+		expand_buffer(s);
+		goto try_again;
+	}
+
+	s->len += ret;
+
+	return len;
+}
+
+/**
+ * trace_seq_puts - trace sequence printing of simple string
+ * @s: trace sequence descriptor
+ * @str: simple string to record
+ *
+ * The tracer may use either the sequence operations or its own
+ * copy to user routines. This function records a simple string
+ * into a special buffer (@s) for later retrieval by a sequencer
+ * or other mechanism.
+ */
+int trace_seq_puts(struct trace_seq *s, const char *str)
+{
+	int len;
+
+	TRACE_SEQ_CHECK(s);
+
+	len = strlen(str);
+
+	while (len > ((s->buffer_size - 1) - s->len))
+		expand_buffer(s);
+
+	memcpy(s->buffer + s->len, str, len);
+	s->len += len;
+
+	return len;
+}
+
+int trace_seq_putc(struct trace_seq *s, unsigned char c)
+{
+	TRACE_SEQ_CHECK(s);
+
+	while (s->len >= (s->buffer_size - 1))
+		expand_buffer(s);
+
+	s->buffer[s->len++] = c;
+
+	return 1;
+}
+
+void trace_seq_terminate(struct trace_seq *s)
+{
+	TRACE_SEQ_CHECK(s);
+
+	/* There's always one character left on the buffer */
+	s->buffer[s->len] = 0;
+}
+
+int trace_seq_do_printf(struct trace_seq *s)
+{
+	TRACE_SEQ_CHECK(s);
+	return printf("%.*s", s->len, s->buffer);
+}
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 0507ec7..1521734 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -20,6 +20,14 @@
 --input=::
         Input file name. (default: perf.data unless stdin is a fifo)
 
+-F::
+--freq=::
+	Show just the sample frequency used for each event.
+
+-v::
+--verbose=::
+	Show all fields.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-list[1],
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 2780d9c..b715cb7 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -77,7 +77,8 @@
 
 -F::
 --funcs::
-	Show available functions in given module or kernel.
+	Show available functions in given module or kernel. With -x/--exec,
+	can also list functions in a user space executable / shared library.
 
 --filter=FILTER::
 	(Only for --vars and --funcs) Set filter. FILTER is a combination of glob
@@ -98,6 +99,15 @@
 --max-probes::
 	Set the maximum number of probe points for an event. Default is 128.
 
+-x::
+--exec=PATH::
+	Specify path to the executable or shared library file for user
+	space tracing. Can also be used with --funcs option.
+
+In absence of -m/-x options, perf probe checks if the first argument after
+the options is an absolute path name. If its an absolute path, perf probe
+uses it as a target module/target user space binary to probe.
+
 PROBE SYNTAX
 ------------
 Probe points are defined by following syntax.
@@ -182,6 +192,13 @@
 
  ./perf probe --del='schedule*'
 
+Add probes at zfree() function on /bin/zsh
+
+ ./perf probe -x /bin/zsh zfree or ./perf probe /bin/zsh zfree
+
+Add probes at malloc() function on libc
+
+ ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc
 
 SEE ALSO
 --------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index a1386b2..b38a1f9 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -168,7 +168,7 @@
         - any:  any type of branches
         - any_call: any function call or system call
         - any_ret: any function return or system call return
-        - any_ind: any indirect branch
+        - ind_call: any indirect branch
         - u:  only when the branch target is at the user level
         - k: only when the branch target is in the kernel
         - hv: only when the target is at the hypervisor level
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
index d144866..42c6fd2 100644
--- a/tools/perf/Documentation/perfconfig.example
+++ b/tools/perf/Documentation/perfconfig.example
@@ -6,6 +6,7 @@
 	normal = black, lightgray
 	selected = lightgray, magenta
 	code = blue, lightgray
+	addr = magenta, lightgray
 
 [tui]
 
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 92271d3..1d3d513 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1,18 +1,10 @@
-ifeq ("$(origin O)", "command line")
-	OUTPUT := $(O)/
-endif
+include ../scripts/Makefile.include
 
 # The default target of this Makefile is...
 all:
 
 include config/utilities.mak
 
-ifneq ($(OUTPUT),)
-# check that the output directory actually exists
-OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
-$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
-endif
-
 # Define V to have a more verbose compile.
 #
 # Define O to save output files in a separate directory.
@@ -84,31 +76,6 @@
 	CFLAGS_WERROR := -Werror
 endif
 
-#
-# Include saner warnings here, which can catch bugs:
-#
-
-EXTRA_WARNINGS := -Wformat
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
-
 ifeq ("$(origin DEBUG)", "command line")
   PERF_DEBUG = $(DEBUG)
 endif
@@ -116,7 +83,13 @@
   CFLAGS_OPTIMIZE = -O6
 endif
 
-CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
+ifdef PARSER_DEBUG
+	PARSER_DEBUG_BISON  := -t
+	PARSER_DEBUG_FLEX   := -d
+	PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
+endif
+
+CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
 EXTLIBS = -lpthread -lrt -lelf -lm
 ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 ALL_LDFLAGS = $(LDFLAGS)
@@ -182,7 +155,7 @@
 
 ### --- END CONFIGURATION SECTION ---
 
-BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 BASIC_LDFLAGS =
 
 # Guard against environment variables
@@ -211,6 +184,17 @@
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
 
+TRACE_EVENT_DIR = ../lib/traceevent/
+
+ifeq ("$(origin O)", "command line")
+	TE_PATH=$(OUTPUT)/
+else
+	TE_PATH=$(TRACE_EVENT_DIR)/
+endif
+
+LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
+TE_LIB := -L$(TE_PATH) -ltraceevent
+
 #
 # Single 'perf' binary right now:
 #
@@ -238,10 +222,10 @@
 BISON= bison
 
 $(OUTPUT)util/parse-events-flex.c: util/parse-events.l
-	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
+	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
 
 $(OUTPUT)util/parse-events-bison.c: util/parse-events.y
-	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c
+	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c
 
 $(OUTPUT)util/pmu-flex.c: util/pmu.l
 	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
@@ -333,6 +317,8 @@
 LIB_H += util/top.h
 LIB_H += $(ARCH_INCLUDE)
 LIB_H += util/cgroup.h
+LIB_H += $(TRACE_EVENT_DIR)event-parse.h
+LIB_H += util/target.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -352,6 +338,7 @@
 LIB_OBJS += $(OUTPUT)util/levenshtein.o
 LIB_OBJS += $(OUTPUT)util/parse-options.o
 LIB_OBJS += $(OUTPUT)util/parse-events.o
+LIB_OBJS += $(OUTPUT)util/parse-events-test.o
 LIB_OBJS += $(OUTPUT)util/path.o
 LIB_OBJS += $(OUTPUT)util/rbtree.o
 LIB_OBJS += $(OUTPUT)util/bitmap.o
@@ -394,6 +381,7 @@
 LIB_OBJS += $(OUTPUT)util/xyarray.o
 LIB_OBJS += $(OUTPUT)util/cpumap.o
 LIB_OBJS += $(OUTPUT)util/cgroup.o
+LIB_OBJS += $(OUTPUT)util/target.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 
@@ -429,7 +417,7 @@
 BUILTIN_OBJS += $(OUTPUT)builtin-test.o
 BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
 
-PERFLIBS = $(LIB_FILE)
+PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
 
 # Files needed for the python binding, perf.so
 # pyrf is just an internal name needed for all those wrappers.
@@ -506,22 +494,23 @@
 		# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
 		BASIC_CFLAGS += -I/usr/include/slang
 		EXTLIBS += -lnewt -lslang
-		LIB_OBJS += $(OUTPUT)util/ui/setup.o
-		LIB_OBJS += $(OUTPUT)util/ui/browser.o
-		LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
-		LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
-		LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
-		LIB_OBJS += $(OUTPUT)util/ui/helpline.o
-		LIB_OBJS += $(OUTPUT)util/ui/progress.o
-		LIB_OBJS += $(OUTPUT)util/ui/util.o
-		LIB_H += util/ui/browser.h
-		LIB_H += util/ui/browsers/map.h
-		LIB_H += util/ui/helpline.h
-		LIB_H += util/ui/keysyms.h
-		LIB_H += util/ui/libslang.h
-		LIB_H += util/ui/progress.h
-		LIB_H += util/ui/util.h
-		LIB_H += util/ui/ui.h
+		LIB_OBJS += $(OUTPUT)ui/setup.o
+		LIB_OBJS += $(OUTPUT)ui/browser.o
+		LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
+		LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
+		LIB_OBJS += $(OUTPUT)ui/browsers/map.o
+		LIB_OBJS += $(OUTPUT)ui/helpline.o
+		LIB_OBJS += $(OUTPUT)ui/progress.o
+		LIB_OBJS += $(OUTPUT)ui/util.o
+		LIB_OBJS += $(OUTPUT)ui/tui/setup.o
+		LIB_H += ui/browser.h
+		LIB_H += ui/browsers/map.h
+		LIB_H += ui/helpline.h
+		LIB_H += ui/keysyms.h
+		LIB_H += ui/libslang.h
+		LIB_H += ui/progress.h
+		LIB_H += ui/util.h
+		LIB_H += ui/ui.h
 	endif
 endif
 
@@ -535,7 +524,12 @@
 	else
 		BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
 		EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
-		LIB_OBJS += $(OUTPUT)util/gtk/browser.o
+		LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
+		LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
+		# Make sure that it'd be included only once.
+		ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
+			LIB_OBJS += $(OUTPUT)ui/setup.o
+		endif
 	endif
 endif
 
@@ -678,18 +672,6 @@
 	endif
 endif
 
-ifneq ($(findstring $(MAKEFLAGS),s),s)
-ifndef V
-	QUIET_CC       = @echo '   ' CC $@;
-	QUIET_AR       = @echo '   ' AR $@;
-	QUIET_LINK     = @echo '   ' LINK $@;
-	QUIET_MKDIR    = @echo '   ' MKDIR $@;
-	QUIET_GEN      = @echo '   ' GEN $@;
-	QUIET_FLEX     = @echo '   ' FLEX $@;
-	QUIET_BISON    = @echo '   ' BISON $@;
-endif
-endif
-
 ifdef ASCIIDOC8
 	export ASCIIDOC8
 endif
@@ -800,16 +782,16 @@
 $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
-$(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
-$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
-$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
-$(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
@@ -844,6 +826,10 @@
 $(LIB_FILE): $(LIB_OBJS)
 	$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
 
+# libtraceevent.a
+$(LIBTRACEEVENT):
+	$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) $(COMMAND_O) libtraceevent.a
+
 help:
 	@echo 'Perf make targets:'
 	@echo '  doc		- make *all* documentation (see below)'
@@ -990,6 +976,6 @@
 	$(RM) $(OUTPUT)util/*-{bison,flex}*
 	$(python-clean)
 
-.PHONY: all install clean strip
+.PHONY: all install clean strip $(LIBTRACEEVENT)
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
 .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 5248046..6b2bcfb 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -84,7 +84,11 @@
 	if (filename__fprintf_build_id(session->filename, stdout))
 		goto out;
 
-	if (with_hits)
+	/*
+	 * in pipe-mode, the only way to get the buildids is to parse
+	 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
+	 */
+	if (with_hits || session->fd_pipe)
 		perf_session__process_events(session, &build_id__mark_dso_hit_ops);
 
 	perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 2676032..e52d77e 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,9 +15,40 @@
 #include "util/parse-options.h"
 #include "util/session.h"
 
-static const char *input_name;
+struct perf_attr_details {
+	bool freq;
+	bool verbose;
+};
 
-static int __cmd_evlist(void)
+static int comma_printf(bool *first, const char *fmt, ...)
+{
+	va_list args;
+	int ret = 0;
+
+	if (!*first) {
+		ret += printf(",");
+	} else {
+		ret += printf(":");
+		*first = false;
+	}
+
+	va_start(args, fmt);
+	ret += vprintf(fmt, args);
+	va_end(args);
+	return ret;
+}
+
+static int __if_print(bool *first, const char *field, u64 value)
+{
+	if (value == 0)
+		return 0;
+
+	return comma_printf(first, " %s: %" PRIu64, field, value);
+}
+
+#define if_print(field) __if_print(&first, #field, pos->attr.field)
+
+static int __cmd_evlist(const char *input_name, struct perf_attr_details *details)
 {
 	struct perf_session *session;
 	struct perf_evsel *pos;
@@ -26,8 +57,52 @@
 	if (session == NULL)
 		return -ENOMEM;
 
-	list_for_each_entry(pos, &session->evlist->entries, node)
-		printf("%s\n", event_name(pos));
+	list_for_each_entry(pos, &session->evlist->entries, node) {
+		bool first = true;
+
+		printf("%s", event_name(pos));
+
+		if (details->verbose || details->freq) {
+			comma_printf(&first, " sample_freq=%" PRIu64,
+				     (u64)pos->attr.sample_freq);
+		}
+
+		if (details->verbose) {
+			if_print(type);
+			if_print(config);
+			if_print(config1);
+			if_print(config2);
+			if_print(size);
+			if_print(sample_type);
+			if_print(read_format);
+			if_print(disabled);
+			if_print(inherit);
+			if_print(pinned);
+			if_print(exclusive);
+			if_print(exclude_user);
+			if_print(exclude_kernel);
+			if_print(exclude_hv);
+			if_print(exclude_idle);
+			if_print(mmap);
+			if_print(comm);
+			if_print(freq);
+			if_print(inherit_stat);
+			if_print(enable_on_exec);
+			if_print(task);
+			if_print(watermark);
+			if_print(precise_ip);
+			if_print(mmap_data);
+			if_print(sample_id_all);
+			if_print(exclude_host);
+			if_print(exclude_guest);
+			if_print(__reserved_1);
+			if_print(wakeup_events);
+			if_print(bp_type);
+			if_print(branch_sample_type);
+		}
+
+		putchar('\n');
+	}
 
 	perf_session__delete(session);
 	return 0;
@@ -38,17 +113,23 @@
 	NULL
 };
 
-static const struct option options[] = {
-	OPT_STRING('i', "input", &input_name, "file",
-		    "input file name"),
-	OPT_END()
-};
-
 int cmd_evlist(int argc, const char **argv, const char *prefix __used)
 {
+	struct perf_attr_details details = { .verbose = false, };
+	const char *input_name;
+	const struct option options[] = {
+		OPT_STRING('i', "input", &input_name, "file",
+			    "Input file name"),
+		OPT_BOOLEAN('F', "freq", &details.freq,
+			    "Show the sample frequency"),
+		OPT_BOOLEAN('v', "verbose", &details.verbose,
+			    "Show all event attr details"),
+		OPT_END()
+	};
+
 	argc = parse_options(argc, argv, options, evlist_usage, 0);
 	if (argc)
 		usage_with_options(evlist_usage, options);
 
-	return __cmd_evlist();
+	return __cmd_evlist(input_name, &details);
 }
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 09c1061..3beab48 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -60,6 +60,11 @@
 static int perf_event__repipe_attr(union perf_event *event,
 				   struct perf_evlist **pevlist __used)
 {
+	int ret;
+	ret = perf_event__process_attr(event, pevlist);
+	if (ret)
+		return ret;
+
 	return perf_event__repipe_synth(NULL, event, NULL);
 }
 
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 39104c0..547af48 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -192,7 +192,7 @@
 }
 
 static void process_alloc_event(void *data,
-				struct event *event,
+				struct event_format *event,
 				int cpu,
 				u64 timestamp __used,
 				struct thread *thread __used,
@@ -253,7 +253,7 @@
 }
 
 static void process_free_event(void *data,
-			       struct event *event,
+			       struct event_format *event,
 			       int cpu,
 			       u64 timestamp __used,
 			       struct thread *thread __used)
@@ -281,7 +281,7 @@
 static void process_raw_event(union perf_event *raw_event __used, void *data,
 			      int cpu, u64 timestamp, struct thread *thread)
 {
-	struct event *event;
+	struct event_format *event;
 	int type;
 
 	type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 12c8148..fd53319 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -356,25 +356,25 @@
 
 struct trace_lock_handler {
 	void (*acquire_event)(struct trace_acquire_event *,
-			      struct event *,
+			      struct event_format *,
 			      int cpu,
 			      u64 timestamp,
 			      struct thread *thread);
 
 	void (*acquired_event)(struct trace_acquired_event *,
-			       struct event *,
+			       struct event_format *,
 			       int cpu,
 			       u64 timestamp,
 			       struct thread *thread);
 
 	void (*contended_event)(struct trace_contended_event *,
-				struct event *,
+				struct event_format *,
 				int cpu,
 				u64 timestamp,
 				struct thread *thread);
 
 	void (*release_event)(struct trace_release_event *,
-			      struct event *,
+			      struct event_format *,
 			      int cpu,
 			      u64 timestamp,
 			      struct thread *thread);
@@ -416,7 +416,7 @@
 
 static void
 report_lock_acquire_event(struct trace_acquire_event *acquire_event,
-			struct event *__event __used,
+			struct event_format *__event __used,
 			int cpu __used,
 			u64 timestamp __used,
 			struct thread *thread __used)
@@ -480,7 +480,7 @@
 
 static void
 report_lock_acquired_event(struct trace_acquired_event *acquired_event,
-			 struct event *__event __used,
+			 struct event_format *__event __used,
 			 int cpu __used,
 			 u64 timestamp __used,
 			 struct thread *thread __used)
@@ -536,7 +536,7 @@
 
 static void
 report_lock_contended_event(struct trace_contended_event *contended_event,
-			  struct event *__event __used,
+			  struct event_format *__event __used,
 			  int cpu __used,
 			  u64 timestamp __used,
 			  struct thread *thread __used)
@@ -583,7 +583,7 @@
 
 static void
 report_lock_release_event(struct trace_release_event *release_event,
-			struct event *__event __used,
+			struct event_format *__event __used,
 			int cpu __used,
 			u64 timestamp __used,
 			struct thread *thread __used)
@@ -647,7 +647,7 @@
 
 static void
 process_lock_acquire_event(void *data,
-			   struct event *event __used,
+			   struct event_format *event __used,
 			   int cpu __used,
 			   u64 timestamp __used,
 			   struct thread *thread __used)
@@ -666,7 +666,7 @@
 
 static void
 process_lock_acquired_event(void *data,
-			    struct event *event __used,
+			    struct event_format *event __used,
 			    int cpu __used,
 			    u64 timestamp __used,
 			    struct thread *thread __used)
@@ -684,7 +684,7 @@
 
 static void
 process_lock_contended_event(void *data,
-			     struct event *event __used,
+			     struct event_format *event __used,
 			     int cpu __used,
 			     u64 timestamp __used,
 			     struct thread *thread __used)
@@ -702,7 +702,7 @@
 
 static void
 process_lock_release_event(void *data,
-			   struct event *event __used,
+			   struct event_format *event __used,
 			   int cpu __used,
 			   u64 timestamp __used,
 			   struct thread *thread __used)
@@ -721,7 +721,7 @@
 static void
 process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
 {
-	struct event *event;
+	struct event_format *event;
 	int type;
 
 	type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 4935c09..e215ae6 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -54,6 +54,7 @@
 	bool show_ext_vars;
 	bool show_funcs;
 	bool mod_events;
+	bool uprobes;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
@@ -75,6 +76,8 @@
 		return -1;
 	}
 
+	pev->uprobes = params.uprobes;
+
 	/* Parse a perf-probe command into event */
 	ret = parse_perf_probe_command(str, pev);
 	pr_debug("%d arguments\n", pev->nargs);
@@ -82,21 +85,58 @@
 	return ret;
 }
 
+static int set_target(const char *ptr)
+{
+	int found = 0;
+	const char *buf;
+
+	/*
+	 * The first argument after options can be an absolute path
+	 * to an executable / library or kernel module.
+	 *
+	 * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH,
+	 * short module name.
+	 */
+	if (!params.target && ptr && *ptr == '/') {
+		params.target = ptr;
+		found = 1;
+		buf = ptr + (strlen(ptr) - 3);
+
+		if (strcmp(buf, ".ko"))
+			params.uprobes = true;
+
+	}
+
+	return found;
+}
+
 static int parse_probe_event_argv(int argc, const char **argv)
 {
-	int i, len, ret;
+	int i, len, ret, found_target;
 	char *buf;
 
+	found_target = set_target(argv[0]);
+	if (found_target && argc == 1)
+		return 0;
+
 	/* Bind up rest arguments */
 	len = 0;
-	for (i = 0; i < argc; i++)
+	for (i = 0; i < argc; i++) {
+		if (i == 0 && found_target)
+			continue;
+
 		len += strlen(argv[i]) + 1;
+	}
 	buf = zalloc(len + 1);
 	if (buf == NULL)
 		return -ENOMEM;
 	len = 0;
-	for (i = 0; i < argc; i++)
+	for (i = 0; i < argc; i++) {
+		if (i == 0 && found_target)
+			continue;
+
 		len += sprintf(&buf[len], "%s ", argv[i]);
+	}
 	params.mod_events = true;
 	ret = parse_probe_event(buf);
 	free(buf);
@@ -125,6 +165,28 @@
 	return 0;
 }
 
+static int opt_set_target(const struct option *opt, const char *str,
+			int unset __used)
+{
+	int ret = -ENOENT;
+
+	if  (str && !params.target) {
+		if (!strcmp(opt->long_name, "exec"))
+			params.uprobes = true;
+#ifdef DWARF_SUPPORT
+		else if (!strcmp(opt->long_name, "module"))
+			params.uprobes = false;
+#endif
+		else
+			return ret;
+
+		params.target = str;
+		ret = 0;
+	}
+
+	return ret;
+}
+
 #ifdef DWARF_SUPPORT
 static int opt_show_lines(const struct option *opt __used,
 			  const char *str, int unset __used)
@@ -246,9 +308,9 @@
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
 		   "directory", "path to kernel source"),
-	OPT_STRING('m', "module", &params.target,
-		   "modname|path",
-		   "target module name (for online) or path (for offline)"),
+	OPT_CALLBACK('m', "module", NULL, "modname|path",
+		"target module name (for online) or path (for offline)",
+		opt_set_target),
 #endif
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -260,6 +322,8 @@
 		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
 		     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
 		     opt_set_filter),
+	OPT_CALLBACK('x', "exec", NULL, "executable|path",
+			"target executable name or path", opt_set_target),
 	OPT_END()
 };
 
@@ -310,6 +374,10 @@
 			pr_err("  Error: Don't use --list with --funcs.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (params.uprobes) {
+			pr_warning("  Error: Don't use --list with --exec.\n");
+			usage_with_options(probe_usage, options);
+		}
 		ret = show_perf_probe_events();
 		if (ret < 0)
 			pr_err("  Error: Failed to show event list. (%d)\n",
@@ -333,8 +401,8 @@
 		if (!params.filter)
 			params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
 						       NULL);
-		ret = show_available_funcs(params.target,
-					   params.filter);
+		ret = show_available_funcs(params.target, params.filter,
+					params.uprobes);
 		strfilter__delete(params.filter);
 		if (ret < 0)
 			pr_err("  Error: Failed to show functions."
@@ -343,7 +411,7 @@
 	}
 
 #ifdef DWARF_SUPPORT
-	if (params.show_lines) {
+	if (params.show_lines && !params.uprobes) {
 		if (params.mod_events) {
 			pr_err("  Error: Don't use --line with"
 			       " --add/--del.\n");
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index be4e1ee..e5cb084 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -44,7 +44,6 @@
 	struct perf_evlist	*evlist;
 	struct perf_session	*session;
 	const char		*progname;
-	const char		*uid_str;
 	int			output;
 	unsigned int		page_size;
 	int			realtime_prio;
@@ -218,7 +217,7 @@
 			if (err == EPERM || err == EACCES) {
 				ui__error_paranoid();
 				exit(EXIT_FAILURE);
-			} else if (err ==  ENODEV && opts->cpu_list) {
+			} else if (err ==  ENODEV && opts->target.cpu_list) {
 				die("No such device - did you specify"
 					" an out-of-range profile CPU?\n");
 			} else if (err == EINVAL) {
@@ -243,9 +242,13 @@
 			/*
 			 * If it's cycles then fall back to hrtimer
 			 * based cpu-clock-tick sw counter, which
-			 * is always available even if no PMU support:
+			 * is always available even if no PMU support.
+			 *
+			 * PPC returns ENXIO until 2.6.37 (behavior changed
+			 * with commit b0a873e).
 			 */
-			if (attr->type == PERF_TYPE_HARDWARE
+			if ((err == ENOENT || err == ENXIO)
+					&& attr->type == PERF_TYPE_HARDWARE
 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
 
 				if (verbose)
@@ -253,6 +256,10 @@
 						    "trying to fall back to cpu-clock-ticks\n");
 				attr->type = PERF_TYPE_SOFTWARE;
 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
+				if (pos->name) {
+					free(pos->name);
+					pos->name = NULL;
+				}
 				goto try_again;
 			}
 
@@ -389,7 +396,7 @@
 			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
 	}
 
-	if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
+	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
 		write_output(rec, &finished_round_event, sizeof(finished_round_event));
 }
 
@@ -471,7 +478,7 @@
 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
 
 	if (!have_tracepoints(&evsel_list->entries))
-		perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
+		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
 
 	if (!rec->opts.branch_stack)
 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
@@ -578,7 +585,7 @@
 		perf_session__process_machines(session, tool,
 					       perf_event__synthesize_guest_os);
 
-	if (!opts->system_wide)
+	if (!opts->target.system_wide)
 		perf_event__synthesize_thread_map(tool, evsel_list->threads,
 						  process_synthesized_event,
 						  machine);
@@ -746,7 +753,10 @@
 		.mmap_pages	     = UINT_MAX,
 		.user_freq	     = UINT_MAX,
 		.user_interval	     = ULLONG_MAX,
-		.freq		     = 1000,
+		.freq		     = 4000,
+		.target		     = {
+			.uses_mmap   = true,
+		},
 	},
 	.write_mode = WRITE_FORCE,
 	.file_new   = true,
@@ -765,9 +775,9 @@
 		     parse_events_option),
 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
 		     "event filter", parse_filter),
-	OPT_STRING('p', "pid", &record.opts.target_pid, "pid",
+	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
 		    "record events on existing process id"),
-	OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
+	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
 		    "record events on existing thread id"),
 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
 		    "collect data with this RT SCHED_FIFO priority"),
@@ -775,11 +785,11 @@
 		    "collect data without buffering"),
 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
 		    "collect raw sample records from all opened counters"),
-	OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
+	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
 			    "system-wide collection from all CPUs"),
 	OPT_BOOLEAN('A', "append", &record.append_file,
 			    "append to the output file to do incremental profiling"),
-	OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
+	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
 		    "list of cpus to monitor"),
 	OPT_BOOLEAN('f', "force", &record.force,
 			"overwrite existing data file (deprecated)"),
@@ -813,7 +823,8 @@
 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
 		     "monitor event in cgroup name only",
 		     parse_cgroups),
-	OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
+	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
+		   "user to profile"),
 
 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
 		     "branch any", "sample any taken branches",
@@ -831,6 +842,7 @@
 	struct perf_evsel *pos;
 	struct perf_evlist *evsel_list;
 	struct perf_record *rec = &record;
+	char errbuf[BUFSIZ];
 
 	perf_header__set_cmdline(argc, argv);
 
@@ -842,8 +854,7 @@
 
 	argc = parse_options(argc, argv, record_options, record_usage,
 			    PARSE_OPT_STOP_AT_NON_OPTION);
-	if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
-		!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
+	if (!argc && perf_target__none(&rec->opts.target))
 		usage_with_options(record_usage, record_options);
 
 	if (rec->force && rec->append_file) {
@@ -856,7 +867,7 @@
 		rec->write_mode = WRITE_FORCE;
 	}
 
-	if (nr_cgroups && !rec->opts.system_wide) {
+	if (nr_cgroups && !rec->opts.target.system_wide) {
 		fprintf(stderr, "cgroup monitoring only available in"
 			" system-wide mode\n");
 		usage_with_options(record_usage, record_options);
@@ -883,17 +894,25 @@
 		goto out_symbol_exit;
 	}
 
-	rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
-					 rec->opts.target_pid);
-	if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
+	err = perf_target__validate(&rec->opts.target);
+	if (err) {
+		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
+		ui__warning("%s", errbuf);
+	}
+
+	err = perf_target__parse_uid(&rec->opts.target);
+	if (err) {
+		int saved_errno = errno;
+
+		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
+		ui__warning("%s", errbuf);
+
+		err = -saved_errno;
 		goto out_free_fd;
+	}
 
-	if (rec->opts.target_pid)
-		rec->opts.target_tid = rec->opts.target_pid;
-
-	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
-				     rec->opts.target_tid, rec->opts.uid,
-				     rec->opts.cpu_list) < 0)
+	err = -ENOMEM;
+	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
 		usage_with_options(record_usage, record_options);
 
 	list_for_each_entry(pos, &evsel_list->entries, node) {
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index cdae9b2..d58e414 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -296,12 +296,15 @@
 {
 	size_t ret;
 	char unit;
-	unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
+	unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
+	u64 nr_events = self->stats.total_period;
 
-	nr_events = convert_unit(nr_events, &unit);
-	ret = fprintf(fp, "# Events: %lu%c", nr_events, unit);
+	nr_samples = convert_unit(nr_samples, &unit);
+	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
 	if (evname != NULL)
-		ret += fprintf(fp, " %s", evname);
+		ret += fprintf(fp, " of event '%s'", evname);
+
+	ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
 	return ret + fprintf(fp, "\n#\n");
 }
 
@@ -680,14 +683,10 @@
 
 	}
 
-	if (strcmp(report.input_name, "-") != 0) {
-		if (report.use_gtk)
-			perf_gtk_setup_browser(argc, argv, true);
-		else
-			setup_browser(true);
-	} else {
+	if (strcmp(report.input_name, "-") != 0)
+		setup_browser(true);
+	else
 		use_browser = 0;
-	}
 
 	/*
 	 * Only in the newt browser we are doing integrated annotation,
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 1cad3af..b125e07 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -728,34 +728,34 @@
 struct trace_sched_handler {
 	void (*switch_event)(struct trace_switch_event *,
 			     struct machine *,
-			     struct event *,
+			     struct event_format *,
 			     int cpu,
 			     u64 timestamp,
 			     struct thread *thread);
 
 	void (*runtime_event)(struct trace_runtime_event *,
 			      struct machine *,
-			      struct event *,
+			      struct event_format *,
 			      int cpu,
 			      u64 timestamp,
 			      struct thread *thread);
 
 	void (*wakeup_event)(struct trace_wakeup_event *,
 			     struct machine *,
-			     struct event *,
+			     struct event_format *,
 			     int cpu,
 			     u64 timestamp,
 			     struct thread *thread);
 
 	void (*fork_event)(struct trace_fork_event *,
-			   struct event *,
+			   struct event_format *,
 			   int cpu,
 			   u64 timestamp,
 			   struct thread *thread);
 
 	void (*migrate_task_event)(struct trace_migrate_task_event *,
 			   struct machine *machine,
-			   struct event *,
+			   struct event_format *,
 			   int cpu,
 			   u64 timestamp,
 			   struct thread *thread);
@@ -765,7 +765,7 @@
 static void
 replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
 		    struct machine *machine __used,
-		    struct event *event,
+		    struct event_format *event,
 		    int cpu __used,
 		    u64 timestamp __used,
 		    struct thread *thread __used)
@@ -792,7 +792,7 @@
 static void
 replay_switch_event(struct trace_switch_event *switch_event,
 		    struct machine *machine __used,
-		    struct event *event,
+		    struct event_format *event,
 		    int cpu,
 		    u64 timestamp,
 		    struct thread *thread __used)
@@ -835,7 +835,7 @@
 
 static void
 replay_fork_event(struct trace_fork_event *fork_event,
-		  struct event *event,
+		  struct event_format *event,
 		  int cpu __used,
 		  u64 timestamp __used,
 		  struct thread *thread __used)
@@ -944,7 +944,7 @@
 
 static void
 latency_fork_event(struct trace_fork_event *fork_event __used,
-		   struct event *event __used,
+		   struct event_format *event __used,
 		   int cpu __used,
 		   u64 timestamp __used,
 		   struct thread *thread __used)
@@ -1026,7 +1026,7 @@
 static void
 latency_switch_event(struct trace_switch_event *switch_event,
 		     struct machine *machine,
-		     struct event *event __used,
+		     struct event_format *event __used,
 		     int cpu,
 		     u64 timestamp,
 		     struct thread *thread __used)
@@ -1079,7 +1079,7 @@
 static void
 latency_runtime_event(struct trace_runtime_event *runtime_event,
 		     struct machine *machine,
-		     struct event *event __used,
+		     struct event_format *event __used,
 		     int cpu,
 		     u64 timestamp,
 		     struct thread *this_thread __used)
@@ -1102,7 +1102,7 @@
 static void
 latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
 		     struct machine *machine,
-		     struct event *__event __used,
+		     struct event_format *__event __used,
 		     int cpu __used,
 		     u64 timestamp,
 		     struct thread *thread __used)
@@ -1150,7 +1150,7 @@
 static void
 latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
 		     struct machine *machine,
-		     struct event *__event __used,
+		     struct event_format *__event __used,
 		     int cpu __used,
 		     u64 timestamp,
 		     struct thread *thread __used)
@@ -1361,7 +1361,7 @@
 
 static void
 process_sched_wakeup_event(struct perf_tool *tool __used,
-			   struct event *event,
+			   struct event_format *event,
 			   struct perf_sample *sample,
 			   struct machine *machine,
 			   struct thread *thread)
@@ -1398,7 +1398,7 @@
 static void
 map_switch_event(struct trace_switch_event *switch_event,
 		 struct machine *machine,
-		 struct event *event __used,
+		 struct event_format *event __used,
 		 int this_cpu,
 		 u64 timestamp,
 		 struct thread *thread __used)
@@ -1476,7 +1476,7 @@
 
 static void
 process_sched_switch_event(struct perf_tool *tool __used,
-			   struct event *event,
+			   struct event_format *event,
 			   struct perf_sample *sample,
 			   struct machine *machine,
 			   struct thread *thread)
@@ -1512,7 +1512,7 @@
 
 static void
 process_sched_runtime_event(struct perf_tool *tool __used,
-			    struct event *event,
+			    struct event_format *event,
 			    struct perf_sample *sample,
 			    struct machine *machine,
 			    struct thread *thread)
@@ -1532,7 +1532,7 @@
 
 static void
 process_sched_fork_event(struct perf_tool *tool __used,
-			 struct event *event,
+			 struct event_format *event,
 			 struct perf_sample *sample,
 			 struct machine *machine __used,
 			 struct thread *thread)
@@ -1554,7 +1554,7 @@
 
 static void
 process_sched_exit_event(struct perf_tool *tool __used,
-			 struct event *event,
+			 struct event_format *event,
 			 struct perf_sample *sample __used,
 			 struct machine *machine __used,
 			 struct thread *thread __used)
@@ -1565,7 +1565,7 @@
 
 static void
 process_sched_migrate_task_event(struct perf_tool *tool __used,
-				 struct event *event,
+				 struct event_format *event,
 				 struct perf_sample *sample,
 				 struct machine *machine,
 				 struct thread *thread)
@@ -1586,7 +1586,7 @@
 						  sample->time, thread);
 }
 
-typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event,
+typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event_format *event,
 				   struct perf_sample *sample,
 				   struct machine *machine,
 				   struct thread *thread);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index d4ce733..8e395a5 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -261,7 +261,7 @@
 			       struct perf_event_attr *attr)
 {
 	int type;
-	struct event *event;
+	struct event_format *event;
 	const char *evname = NULL;
 	unsigned long secs;
 	unsigned long usecs;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1e5e9b2..62ae30d 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -173,24 +173,23 @@
 
 
 
-struct perf_evlist		*evsel_list;
+static struct perf_evlist	*evsel_list;
 
-static bool			system_wide			=  false;
+static struct perf_target	target = {
+	.uid	= UINT_MAX,
+};
+
 static int			run_idx				=  0;
-
 static int			run_count			=  1;
 static bool			no_inherit			= false;
 static bool			scale				=  true;
 static bool			no_aggr				= false;
-static const char		*target_pid;
-static const char		*target_tid;
 static pid_t			child_pid			= -1;
 static bool			null_run			=  false;
 static int			detailed_run			=  0;
 static bool			sync_run			=  false;
 static bool			big_num				=  true;
 static int			big_num_opt			=  -1;
-static const char		*cpu_list;
 static const char		*csv_sep			= NULL;
 static bool			csv_output			= false;
 static bool			group				= false;
@@ -265,18 +264,18 @@
 	return sqrt(variance_mean);
 }
 
-struct stats			runtime_nsecs_stats[MAX_NR_CPUS];
-struct stats			runtime_cycles_stats[MAX_NR_CPUS];
-struct stats			runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
-struct stats			runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
-struct stats			runtime_branches_stats[MAX_NR_CPUS];
-struct stats			runtime_cacherefs_stats[MAX_NR_CPUS];
-struct stats			runtime_l1_dcache_stats[MAX_NR_CPUS];
-struct stats			runtime_l1_icache_stats[MAX_NR_CPUS];
-struct stats			runtime_ll_cache_stats[MAX_NR_CPUS];
-struct stats			runtime_itlb_cache_stats[MAX_NR_CPUS];
-struct stats			runtime_dtlb_cache_stats[MAX_NR_CPUS];
-struct stats			walltime_nsecs_stats;
+static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
+static struct stats runtime_cycles_stats[MAX_NR_CPUS];
+static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
+static struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
+static struct stats runtime_branches_stats[MAX_NR_CPUS];
+static struct stats runtime_cacherefs_stats[MAX_NR_CPUS];
+static struct stats runtime_l1_dcache_stats[MAX_NR_CPUS];
+static struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
+static struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
+static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
+static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
+static struct stats walltime_nsecs_stats;
 
 static int create_perf_stat_counter(struct perf_evsel *evsel,
 				    struct perf_evsel *first)
@@ -299,15 +298,15 @@
 	if (exclude_guest_missing)
 		evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
 
-	if (system_wide) {
+	if (perf_target__has_cpu(&target)) {
 		ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
-						group, group_fd);
+					       group, group_fd);
 		if (ret)
 			goto check_ret;
 		return 0;
 	}
 
-	if (!target_pid && !target_tid && (!group || evsel == first)) {
+	if (!perf_target__has_task(&target) && (!group || evsel == first)) {
 		attr->disabled = 1;
 		attr->enable_on_exec = 1;
 	}
@@ -471,7 +470,7 @@
 			exit(-1);
 		}
 
-		if (!target_tid && !target_pid && !system_wide)
+		if (perf_target__none(&target))
 			evsel_list->threads->map[0] = child_pid;
 
 		/*
@@ -506,7 +505,7 @@
 				error("You may not have permission to collect %sstats.\n"
 				      "\t Consider tweaking"
 				      " /proc/sys/kernel/perf_event_paranoid or running as root.",
-				      system_wide ? "system-wide " : "");
+				      target.system_wide ? "system-wide " : "");
 			} else {
 				error("open_counter returned with %d (%s). "
 				      "/bin/dmesg may provide additional information.\n",
@@ -998,14 +997,14 @@
 	if (!csv_output) {
 		fprintf(output, "\n");
 		fprintf(output, " Performance counter stats for ");
-		if (!target_pid && !target_tid) {
+		if (!perf_target__has_task(&target)) {
 			fprintf(output, "\'%s", argv[0]);
 			for (i = 1; i < argc; i++)
 				fprintf(output, " %s", argv[i]);
-		} else if (target_pid)
-			fprintf(output, "process id \'%s", target_pid);
+		} else if (target.pid)
+			fprintf(output, "process id \'%s", target.pid);
 		else
-			fprintf(output, "thread id \'%s", target_tid);
+			fprintf(output, "thread id \'%s", target.tid);
 
 		fprintf(output, "\'");
 		if (run_count > 1)
@@ -1079,11 +1078,11 @@
 		     "event filter", parse_filter),
 	OPT_BOOLEAN('i', "no-inherit", &no_inherit,
 		    "child tasks do not inherit counters"),
-	OPT_STRING('p', "pid", &target_pid, "pid",
+	OPT_STRING('p', "pid", &target.pid, "pid",
 		   "stat events on existing process id"),
-	OPT_STRING('t', "tid", &target_tid, "tid",
+	OPT_STRING('t', "tid", &target.tid, "tid",
 		   "stat events on existing thread id"),
-	OPT_BOOLEAN('a', "all-cpus", &system_wide,
+	OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
 		    "system-wide collection from all CPUs"),
 	OPT_BOOLEAN('g', "group", &group,
 		    "put the counters into a counter group"),
@@ -1102,7 +1101,7 @@
 	OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, 
 			   "print large numbers with thousands\' separators",
 			   stat__set_big_num),
-	OPT_STRING('C', "cpu", &cpu_list, "cpu",
+	OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
 		    "list of cpus to monitor in system-wide"),
 	OPT_BOOLEAN('A', "no-aggr", &no_aggr,
 		    "disable CPU count aggregation"),
@@ -1220,13 +1219,13 @@
 	} else if (big_num_opt == 0) /* User passed --no-big-num */
 		big_num = false;
 
-	if (!argc && !target_pid && !target_tid)
+	if (!argc && !perf_target__has_task(&target))
 		usage_with_options(stat_usage, options);
 	if (run_count <= 0)
 		usage_with_options(stat_usage, options);
 
 	/* no_aggr, cgroup are for system-wide only */
-	if ((no_aggr || nr_cgroups) && !system_wide) {
+	if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) {
 		fprintf(stderr, "both cgroup and no-aggregation "
 			"modes only available in system-wide mode\n");
 
@@ -1236,23 +1235,14 @@
 	if (add_default_attributes())
 		goto out;
 
-	if (target_pid)
-		target_tid = target_pid;
+	perf_target__validate(&target);
 
-	evsel_list->threads = thread_map__new_str(target_pid,
-						  target_tid, UINT_MAX);
-	if (evsel_list->threads == NULL) {
-		pr_err("Problems finding threads of monitor\n");
-		usage_with_options(stat_usage, options);
-	}
+	if (perf_evlist__create_maps(evsel_list, &target) < 0) {
+		if (perf_target__has_task(&target))
+			pr_err("Problems finding threads of monitor\n");
+		if (perf_target__has_cpu(&target))
+			perror("failed to parse CPUs map");
 
-	if (system_wide)
-		evsel_list->cpus = cpu_map__new(cpu_list);
-	else
-		evsel_list->cpus = cpu_map__dummy_new();
-
-	if (evsel_list->cpus == NULL) {
-		perror("failed to parse CPUs map");
 		usage_with_options(stat_usage, options);
 		return -1;
 	}
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 223ffdc..5a8727c 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -604,556 +604,6 @@
 #undef nsyscalls
 }
 
-#define TEST_ASSERT_VAL(text, cond) \
-do { \
-	if (!(cond)) { \
-		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
-		return -1; \
-	} \
-} while (0)
-
-static int test__checkevent_tracepoint(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong sample_type",
-		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-		evsel->attr.sample_type);
-	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
-	return 0;
-}
-
-static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-
-	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
-
-	list_for_each_entry(evsel, &evlist->entries, node) {
-		TEST_ASSERT_VAL("wrong type",
-			PERF_TYPE_TRACEPOINT == evsel->attr.type);
-		TEST_ASSERT_VAL("wrong sample_type",
-			(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
-			== evsel->attr.sample_type);
-		TEST_ASSERT_VAL("wrong sample_period",
-			1 == evsel->attr.sample_period);
-	}
-	return 0;
-}
-
-static int test__checkevent_raw(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_numeric(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",
-			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",
-			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong period",
-			100000 == evsel->attr.sample_period);
-	TEST_ASSERT_VAL("wrong config1",
-			0 == evsel->attr.config1);
-	TEST_ASSERT_VAL("wrong config2",
-			1 == evsel->attr.config2);
-	return 0;
-}
-
-static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",
-			PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_genhw(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_breakpoint(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
-					 evsel->attr.bp_type);
-	TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
-					evsel->attr.bp_len);
-	return 0;
-}
-
-static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong bp_type",
-			HW_BREAKPOINT_X == evsel->attr.bp_type);
-	TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
-	return 0;
-}
-
-static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type",
-			PERF_TYPE_BREAKPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong bp_type",
-			HW_BREAKPOINT_R == evsel->attr.bp_type);
-	TEST_ASSERT_VAL("wrong bp_len",
-			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
-	return 0;
-}
-
-static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type",
-			PERF_TYPE_BREAKPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong bp_type",
-			HW_BREAKPOINT_W == evsel->attr.bp_type);
-	TEST_ASSERT_VAL("wrong bp_len",
-			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
-	return 0;
-}
-
-static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_tracepoint(evlist);
-}
-
-static int
-test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-
-	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
-
-	list_for_each_entry(evsel, &evlist->entries, node) {
-		TEST_ASSERT_VAL("wrong exclude_user",
-				!evsel->attr.exclude_user);
-		TEST_ASSERT_VAL("wrong exclude_kernel",
-				evsel->attr.exclude_kernel);
-		TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-		TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-	}
-
-	return test__checkevent_tracepoint_multi(evlist);
-}
-
-static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_raw(evlist);
-}
-
-static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_numeric(evlist);
-}
-
-static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
-	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
-
-	return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
-	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
-
-	return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_symbolic_alias(evlist);
-}
-
-static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_genhw(evlist);
-}
-
-static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_breakpoint(evlist);
-}
-
-static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_breakpoint_x(evlist);
-}
-
-static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_breakpoint_r(evlist);
-}
-
-static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_breakpoint_w(evlist);
-}
-
-static int test__checkevent_pmu(struct perf_evlist *evlist)
-{
-
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",    10 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong config1",    1 == evsel->attr.config1);
-	TEST_ASSERT_VAL("wrong config2",    3 == evsel->attr.config2);
-	TEST_ASSERT_VAL("wrong period",  1000 == evsel->attr.sample_period);
-
-	return 0;
-}
-
-static int test__checkevent_list(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-
-	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
-
-	/* r1 */
-	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
-	TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
-	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	/* syscalls:sys_enter_open:k */
-	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong sample_type",
-		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-		evsel->attr.sample_type);
-	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	/* 1:1:hp */
-	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
-	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return 0;
-}
-
-static struct test__event_st {
-	const char *name;
-	__u32 type;
-	int (*check)(struct perf_evlist *evlist);
-} test__events[] = {
-	{
-		.name  = "syscalls:sys_enter_open",
-		.check = test__checkevent_tracepoint,
-	},
-	{
-		.name  = "syscalls:*",
-		.check = test__checkevent_tracepoint_multi,
-	},
-	{
-		.name  = "r1a",
-		.check = test__checkevent_raw,
-	},
-	{
-		.name  = "1:1",
-		.check = test__checkevent_numeric,
-	},
-	{
-		.name  = "instructions",
-		.check = test__checkevent_symbolic_name,
-	},
-	{
-		.name  = "cycles/period=100000,config2/",
-		.check = test__checkevent_symbolic_name_config,
-	},
-	{
-		.name  = "faults",
-		.check = test__checkevent_symbolic_alias,
-	},
-	{
-		.name  = "L1-dcache-load-miss",
-		.check = test__checkevent_genhw,
-	},
-	{
-		.name  = "mem:0",
-		.check = test__checkevent_breakpoint,
-	},
-	{
-		.name  = "mem:0:x",
-		.check = test__checkevent_breakpoint_x,
-	},
-	{
-		.name  = "mem:0:r",
-		.check = test__checkevent_breakpoint_r,
-	},
-	{
-		.name  = "mem:0:w",
-		.check = test__checkevent_breakpoint_w,
-	},
-	{
-		.name  = "syscalls:sys_enter_open:k",
-		.check = test__checkevent_tracepoint_modifier,
-	},
-	{
-		.name  = "syscalls:*:u",
-		.check = test__checkevent_tracepoint_multi_modifier,
-	},
-	{
-		.name  = "r1a:kp",
-		.check = test__checkevent_raw_modifier,
-	},
-	{
-		.name  = "1:1:hp",
-		.check = test__checkevent_numeric_modifier,
-	},
-	{
-		.name  = "instructions:h",
-		.check = test__checkevent_symbolic_name_modifier,
-	},
-	{
-		.name  = "faults:u",
-		.check = test__checkevent_symbolic_alias_modifier,
-	},
-	{
-		.name  = "L1-dcache-load-miss:kp",
-		.check = test__checkevent_genhw_modifier,
-	},
-	{
-		.name  = "mem:0:u",
-		.check = test__checkevent_breakpoint_modifier,
-	},
-	{
-		.name  = "mem:0:x:k",
-		.check = test__checkevent_breakpoint_x_modifier,
-	},
-	{
-		.name  = "mem:0:r:hp",
-		.check = test__checkevent_breakpoint_r_modifier,
-	},
-	{
-		.name  = "mem:0:w:up",
-		.check = test__checkevent_breakpoint_w_modifier,
-	},
-	{
-		.name  = "cpu/config=10,config1,config2=3,period=1000/u",
-		.check = test__checkevent_pmu,
-	},
-	{
-		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
-		.check = test__checkevent_list,
-	},
-	{
-		.name  = "instructions:G",
-		.check = test__checkevent_exclude_host_modifier,
-	},
-	{
-		.name  = "instructions:H",
-		.check = test__checkevent_exclude_guest_modifier,
-	},
-};
-
-#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
-
-static int test__parse_events(void)
-{
-	struct perf_evlist *evlist;
-	u_int i;
-	int ret = 0;
-
-	for (i = 0; i < TEST__EVENTS_CNT; i++) {
-		struct test__event_st *e = &test__events[i];
-
-		evlist = perf_evlist__new(NULL, NULL);
-		if (evlist == NULL)
-			break;
-
-		ret = parse_events(evlist, e->name, 0);
-		if (ret) {
-			pr_debug("failed to parse event '%s', err %d\n",
-				 e->name, ret);
-			break;
-		}
-
-		ret = e->check(evlist);
-		perf_evlist__delete(evlist);
-		if (ret)
-			break;
-	}
-
-	return ret;
-}
-
 static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
 					 size_t *sizep)
 {
@@ -1195,6 +645,10 @@
 static int test__PERF_RECORD(void)
 {
 	struct perf_record_opts opts = {
+		.target = {
+			.uid = UINT_MAX,
+			.uses_mmap = true,
+		},
 		.no_delay   = true,
 		.freq	    = 10,
 		.mmap_pages = 256,
@@ -1237,8 +691,7 @@
 	 * perf_evlist__prepare_workload we'll fill in the only thread
 	 * we're monitoring, the one forked there.
 	 */
-	err = perf_evlist__create_maps(evlist, opts.target_pid,
-				       opts.target_tid, UINT_MAX, opts.cpu_list);
+	err = perf_evlist__create_maps(evlist, &opts.target);
 	if (err < 0) {
 		pr_debug("Not enough memory to create thread/cpu maps\n");
 		goto out_delete_evlist;
@@ -1579,8 +1032,6 @@
 	sa.sa_sigaction = segfault_handler;
 	sigaction(SIGSEGV, &sa, NULL);
 
-	fprintf(stderr, "\n\n");
-
 	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
 	if (fd < 0) {
 		die("Error: sys_perf_event_open() syscall returned "
@@ -1605,7 +1056,7 @@
 		loops *= 10;
 
 		delta = now - stamp;
-		fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta);
+		pr_debug("%14d: %14Lu\n", n, (long long)delta);
 
 		delta_sum += delta;
 	}
@@ -1613,7 +1064,7 @@
 	munmap(addr, page_size);
 	close(fd);
 
-	fprintf(stderr, "   ");
+	pr_debug("   ");
 
 	if (!delta_sum)
 		return -1;
@@ -1674,7 +1125,7 @@
 	},
 	{
 		.desc = "parse events tests",
-		.func = test__parse_events,
+		.func = parse_events__test,
 	},
 #if defined(__x86_64__) || defined(__i386__)
 	{
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8ef59f8..6031dce 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -588,7 +588,7 @@
 	 * via --uid.
 	 */
 	list_for_each_entry(pos, &top->evlist->entries, node)
-		pos->hists.uid_filter_str = top->uid_str;
+		pos->hists.uid_filter_str = top->target.uid_str;
 
 	perf_evlist__tui_browse_hists(top->evlist, help,
 				      perf_top__sort_new_samples,
@@ -900,6 +900,9 @@
 			attr->read_format |= PERF_FORMAT_ID;
 		}
 
+		if (perf_target__has_cpu(&top->target))
+			attr->sample_type |= PERF_SAMPLE_CPU;
+
 		if (symbol_conf.use_callchain)
 			attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
 
@@ -948,6 +951,10 @@
 
 				attr->type = PERF_TYPE_SOFTWARE;
 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
+				if (counter->name) {
+					free(counter->name);
+					counter->name = strdup(event_name(counter));
+				}
 				goto try_again;
 			}
 
@@ -1016,7 +1023,7 @@
 	if (ret)
 		goto out_delete;
 
-	if (top->target_tid || top->uid != UINT_MAX)
+	if (perf_target__has_task(&top->target))
 		perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
 						  perf_event__process,
 						  &top->session->host_machine);
@@ -1150,14 +1157,17 @@
 int cmd_top(int argc, const char **argv, const char *prefix __used)
 {
 	struct perf_evsel *pos;
-	int status = -ENOMEM;
+	int status;
+	char errbuf[BUFSIZ];
 	struct perf_top top = {
 		.count_filter	     = 5,
 		.delay_secs	     = 2,
-		.uid		     = UINT_MAX,
-		.freq		     = 1000, /* 1 KHz */
+		.freq		     = 4000, /* 4 KHz */
 		.mmap_pages	     = 128,
 		.sym_pcnt_filter     = 5,
+		.target		     = {
+			.uses_mmap   = true,
+		},
 	};
 	char callchain_default_opt[] = "fractal,0.5,callee";
 	const struct option options[] = {
@@ -1166,13 +1176,13 @@
 		     parse_events_option),
 	OPT_INTEGER('c', "count", &top.default_interval,
 		    "event period to sample"),
-	OPT_STRING('p', "pid", &top.target_pid, "pid",
+	OPT_STRING('p', "pid", &top.target.pid, "pid",
 		    "profile events on existing process id"),
-	OPT_STRING('t', "tid", &top.target_tid, "tid",
+	OPT_STRING('t', "tid", &top.target.tid, "tid",
 		    "profile events on existing thread id"),
-	OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
+	OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide,
 			    "system-wide collection from all CPUs"),
-	OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
+	OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu",
 		    "list of cpus to monitor"),
 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 		   "file", "vmlinux pathname"),
@@ -1227,7 +1237,7 @@
 		    "Display raw encoding of assembly instructions (default)"),
 	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
 		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
-	OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
+	OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),
 	OPT_END()
 	};
 
@@ -1253,22 +1263,27 @@
 
 	setup_browser(false);
 
-	top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
-	if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
-		goto out_delete_evlist;
-
-	/* CPU and PID are mutually exclusive */
-	if (top.target_tid && top.cpu_list) {
-		printf("WARNING: PID switch overriding CPU\n");
-		sleep(1);
-		top.cpu_list = NULL;
+	status = perf_target__validate(&top.target);
+	if (status) {
+		perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
+		ui__warning("%s", errbuf);
 	}
 
-	if (top.target_pid)
-		top.target_tid = top.target_pid;
+	status = perf_target__parse_uid(&top.target);
+	if (status) {
+		int saved_errno = errno;
 
-	if (perf_evlist__create_maps(top.evlist, top.target_pid,
-				     top.target_tid, top.uid, top.cpu_list) < 0)
+		perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
+		ui__warning("%s", errbuf);
+
+		status = -saved_errno;
+		goto out_delete_evlist;
+	}
+
+	if (perf_target__none(&top.target))
+		top.target.system_wide = true;
+
+	if (perf_evlist__create_maps(top.evlist, &top.target) < 0)
 		usage_with_options(top_usage, options);
 
 	if (!top.evlist->nr_entries &&
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 89e3355..14f1034 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -207,10 +207,10 @@
 
 void pthread__unblock_sigwinch(void);
 
+#include "util/target.h"
+
 struct perf_record_opts {
-	const char   *target_pid;
-	const char   *target_tid;
-	uid_t	     uid;
+	struct perf_target target;
 	bool	     call_graph;
 	bool	     group;
 	bool	     inherit_stat;
@@ -223,7 +223,6 @@
 	bool	     sample_time;
 	bool	     sample_id_all_missing;
 	bool	     exclude_guest_missing;
-	bool	     system_wide;
 	bool	     period;
 	unsigned int freq;
 	unsigned int mmap_pages;
@@ -231,7 +230,6 @@
 	int	     branch_stack;
 	u64	     default_interval;
 	u64	     user_interval;
-	const char   *cpu_list;
 };
 
 #endif
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
new file mode 100644
index 0000000..cde4d0f
--- /dev/null
+++ b/tools/perf/ui/browser.c
@@ -0,0 +1,711 @@
+#include "../util.h"
+#include "../cache.h"
+#include "../../perf.h"
+#include "libslang.h"
+#include <newt.h>
+#include "ui.h"
+#include "util.h"
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <stdlib.h>
+#include <sys/ttydefaults.h>
+#include "browser.h"
+#include "helpline.h"
+#include "keysyms.h"
+#include "../color.h"
+
+static int ui_browser__percent_color(struct ui_browser *browser,
+				     double percent, bool current)
+{
+	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
+		return HE_COLORSET_SELECTED;
+	if (percent >= MIN_RED)
+		return HE_COLORSET_TOP;
+	if (percent >= MIN_GREEN)
+		return HE_COLORSET_MEDIUM;
+	return HE_COLORSET_NORMAL;
+}
+
+int ui_browser__set_color(struct ui_browser *browser, int color)
+{
+	int ret = browser->current_color;
+	browser->current_color = color;
+	SLsmg_set_color(color);
+	return ret;
+}
+
+void ui_browser__set_percent_color(struct ui_browser *self,
+				   double percent, bool current)
+{
+	 int color = ui_browser__percent_color(self, percent, current);
+	 ui_browser__set_color(self, color);
+}
+
+void ui_browser__gotorc(struct ui_browser *self, int y, int x)
+{
+	SLsmg_gotorc(self->y + y, self->x + x);
+}
+
+static struct list_head *
+ui_browser__list_head_filter_entries(struct ui_browser *browser,
+				     struct list_head *pos)
+{
+	do {
+		if (!browser->filter || !browser->filter(browser, pos))
+			return pos;
+		pos = pos->next;
+	} while (pos != browser->entries);
+
+	return NULL;
+}
+
+static struct list_head *
+ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
+					  struct list_head *pos)
+{
+	do {
+		if (!browser->filter || !browser->filter(browser, pos))
+			return pos;
+		pos = pos->prev;
+	} while (pos != browser->entries);
+
+	return NULL;
+}
+
+void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
+{
+	struct list_head *head = self->entries;
+	struct list_head *pos;
+
+	if (self->nr_entries == 0)
+		return;
+
+	switch (whence) {
+	case SEEK_SET:
+		pos = ui_browser__list_head_filter_entries(self, head->next);
+		break;
+	case SEEK_CUR:
+		pos = self->top;
+		break;
+	case SEEK_END:
+		pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
+		break;
+	default:
+		return;
+	}
+
+	assert(pos != NULL);
+
+	if (offset > 0) {
+		while (offset-- != 0)
+			pos = ui_browser__list_head_filter_entries(self, pos->next);
+	} else {
+		while (offset++ != 0)
+			pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
+	}
+
+	self->top = pos;
+}
+
+void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
+{
+	struct rb_root *root = self->entries;
+	struct rb_node *nd;
+
+	switch (whence) {
+	case SEEK_SET:
+		nd = rb_first(root);
+		break;
+	case SEEK_CUR:
+		nd = self->top;
+		break;
+	case SEEK_END:
+		nd = rb_last(root);
+		break;
+	default:
+		return;
+	}
+
+	if (offset > 0) {
+		while (offset-- != 0)
+			nd = rb_next(nd);
+	} else {
+		while (offset++ != 0)
+			nd = rb_prev(nd);
+	}
+
+	self->top = nd;
+}
+
+unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
+{
+	struct rb_node *nd;
+	int row = 0;
+
+	if (self->top == NULL)
+                self->top = rb_first(self->entries);
+
+	nd = self->top;
+
+	while (nd != NULL) {
+		ui_browser__gotorc(self, row, 0);
+		self->write(self, nd, row);
+		if (++row == self->height)
+			break;
+		nd = rb_next(nd);
+	}
+
+	return row;
+}
+
+bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
+{
+	return self->top_idx + row == self->index;
+}
+
+void ui_browser__refresh_dimensions(struct ui_browser *self)
+{
+	self->width = SLtt_Screen_Cols - 1;
+	self->height = SLtt_Screen_Rows - 2;
+	self->y = 1;
+	self->x = 0;
+}
+
+void ui_browser__handle_resize(struct ui_browser *browser)
+{
+	ui__refresh_dimensions(false);
+	ui_browser__show(browser, browser->title, ui_helpline__current);
+	ui_browser__refresh(browser);
+}
+
+int ui_browser__warning(struct ui_browser *browser, int timeout,
+			const char *format, ...)
+{
+	va_list args;
+	char *text;
+	int key = 0, err;
+
+	va_start(args, format);
+	err = vasprintf(&text, format, args);
+	va_end(args);
+
+	if (err < 0) {
+		va_start(args, format);
+		ui_helpline__vpush(format, args);
+		va_end(args);
+	} else {
+		while ((key == ui__question_window("Warning!", text,
+						   "Press any key...",
+						   timeout)) == K_RESIZE)
+			ui_browser__handle_resize(browser);
+		free(text);
+	}
+
+	return key;
+}
+
+int ui_browser__help_window(struct ui_browser *browser, const char *text)
+{
+	int key;
+
+	while ((key = ui__help_window(text)) == K_RESIZE)
+		ui_browser__handle_resize(browser);
+
+	return key;
+}
+
+bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
+{
+	int key;
+
+	while ((key = ui__dialog_yesno(text)) == K_RESIZE)
+		ui_browser__handle_resize(browser);
+
+	return key == K_ENTER || toupper(key) == 'Y';
+}
+
+void ui_browser__reset_index(struct ui_browser *self)
+{
+	self->index = self->top_idx = 0;
+	self->seek(self, 0, SEEK_SET);
+}
+
+void __ui_browser__show_title(struct ui_browser *browser, const char *title)
+{
+	SLsmg_gotorc(0, 0);
+	ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
+	slsmg_write_nstring(title, browser->width + 1);
+}
+
+void ui_browser__show_title(struct ui_browser *browser, const char *title)
+{
+	pthread_mutex_lock(&ui__lock);
+	__ui_browser__show_title(browser, title);
+	pthread_mutex_unlock(&ui__lock);
+}
+
+int ui_browser__show(struct ui_browser *self, const char *title,
+		     const char *helpline, ...)
+{
+	int err;
+	va_list ap;
+
+	ui_browser__refresh_dimensions(self);
+
+	pthread_mutex_lock(&ui__lock);
+	__ui_browser__show_title(self, title);
+
+	self->title = title;
+	free(self->helpline);
+	self->helpline = NULL;
+
+	va_start(ap, helpline);
+	err = vasprintf(&self->helpline, helpline, ap);
+	va_end(ap);
+	if (err > 0)
+		ui_helpline__push(self->helpline);
+	pthread_mutex_unlock(&ui__lock);
+	return err ? 0 : -1;
+}
+
+void ui_browser__hide(struct ui_browser *browser __used)
+{
+	pthread_mutex_lock(&ui__lock);
+	ui_helpline__pop();
+	pthread_mutex_unlock(&ui__lock);
+}
+
+static void ui_browser__scrollbar_set(struct ui_browser *browser)
+{
+	int height = browser->height, h = 0, pct = 0,
+	    col = browser->width,
+	    row = browser->y - 1;
+
+	if (browser->nr_entries > 1) {
+		pct = ((browser->index * (browser->height - 1)) /
+		       (browser->nr_entries - 1));
+	}
+
+	SLsmg_set_char_set(1);
+
+	while (h < height) {
+	        ui_browser__gotorc(browser, row++, col);
+		SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
+		++h;
+	}
+
+	SLsmg_set_char_set(0);
+}
+
+static int __ui_browser__refresh(struct ui_browser *browser)
+{
+	int row;
+	int width = browser->width;
+
+	row = browser->refresh(browser);
+	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
+
+	if (!browser->use_navkeypressed || browser->navkeypressed)
+		ui_browser__scrollbar_set(browser);
+	else
+		width += 1;
+
+	SLsmg_fill_region(browser->y + row, browser->x,
+			  browser->height - row, width, ' ');
+
+	return 0;
+}
+
+int ui_browser__refresh(struct ui_browser *browser)
+{
+	pthread_mutex_lock(&ui__lock);
+	__ui_browser__refresh(browser);
+	pthread_mutex_unlock(&ui__lock);
+
+	return 0;
+}
+
+/*
+ * Here we're updating nr_entries _after_ we started browsing, i.e.  we have to
+ * forget about any reference to any entry in the underlying data structure,
+ * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
+ * after an output_resort and hist decay.
+ */
+void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
+{
+	off_t offset = nr_entries - browser->nr_entries;
+
+	browser->nr_entries = nr_entries;
+
+	if (offset < 0) {
+		if (browser->top_idx < (u64)-offset)
+			offset = -browser->top_idx;
+
+		browser->index += offset;
+		browser->top_idx += offset;
+	}
+
+	browser->top = NULL;
+	browser->seek(browser, browser->top_idx, SEEK_SET);
+}
+
+int ui_browser__run(struct ui_browser *self, int delay_secs)
+{
+	int err, key;
+
+	while (1) {
+		off_t offset;
+
+		pthread_mutex_lock(&ui__lock);
+		err = __ui_browser__refresh(self);
+		SLsmg_refresh();
+		pthread_mutex_unlock(&ui__lock);
+		if (err < 0)
+			break;
+
+		key = ui__getch(delay_secs);
+
+		if (key == K_RESIZE) {
+			ui__refresh_dimensions(false);
+			ui_browser__refresh_dimensions(self);
+			__ui_browser__show_title(self, self->title);
+			ui_helpline__puts(self->helpline);
+			continue;
+		}
+
+		if (self->use_navkeypressed && !self->navkeypressed) {
+			if (key == K_DOWN || key == K_UP ||
+			    key == K_PGDN || key == K_PGUP ||
+			    key == K_HOME || key == K_END ||
+			    key == ' ') {
+				self->navkeypressed = true;
+				continue;
+			} else
+				return key;
+		}
+
+		switch (key) {
+		case K_DOWN:
+			if (self->index == self->nr_entries - 1)
+				break;
+			++self->index;
+			if (self->index == self->top_idx + self->height) {
+				++self->top_idx;
+				self->seek(self, +1, SEEK_CUR);
+			}
+			break;
+		case K_UP:
+			if (self->index == 0)
+				break;
+			--self->index;
+			if (self->index < self->top_idx) {
+				--self->top_idx;
+				self->seek(self, -1, SEEK_CUR);
+			}
+			break;
+		case K_PGDN:
+		case ' ':
+			if (self->top_idx + self->height > self->nr_entries - 1)
+				break;
+
+			offset = self->height;
+			if (self->index + offset > self->nr_entries - 1)
+				offset = self->nr_entries - 1 - self->index;
+			self->index += offset;
+			self->top_idx += offset;
+			self->seek(self, +offset, SEEK_CUR);
+			break;
+		case K_PGUP:
+			if (self->top_idx == 0)
+				break;
+
+			if (self->top_idx < self->height)
+				offset = self->top_idx;
+			else
+				offset = self->height;
+
+			self->index -= offset;
+			self->top_idx -= offset;
+			self->seek(self, -offset, SEEK_CUR);
+			break;
+		case K_HOME:
+			ui_browser__reset_index(self);
+			break;
+		case K_END:
+			offset = self->height - 1;
+			if (offset >= self->nr_entries)
+				offset = self->nr_entries - 1;
+
+			self->index = self->nr_entries - 1;
+			self->top_idx = self->index - offset;
+			self->seek(self, -offset, SEEK_END);
+			break;
+		default:
+			return key;
+		}
+	}
+	return -1;
+}
+
+unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
+{
+	struct list_head *pos;
+	struct list_head *head = self->entries;
+	int row = 0;
+
+	if (self->top == NULL || self->top == self->entries)
+                self->top = ui_browser__list_head_filter_entries(self, head->next);
+
+	pos = self->top;
+
+	list_for_each_from(pos, head) {
+		if (!self->filter || !self->filter(self, pos)) {
+			ui_browser__gotorc(self, row, 0);
+			self->write(self, pos, row);
+			if (++row == self->height)
+				break;
+		}
+	}
+
+	return row;
+}
+
+static struct ui_browser__colorset {
+	const char *name, *fg, *bg;
+	int colorset;
+} ui_browser__colorsets[] = {
+	{
+		.colorset = HE_COLORSET_TOP,
+		.name	  = "top",
+		.fg	  = "red",
+		.bg	  = "default",
+	},
+	{
+		.colorset = HE_COLORSET_MEDIUM,
+		.name	  = "medium",
+		.fg	  = "green",
+		.bg	  = "default",
+	},
+	{
+		.colorset = HE_COLORSET_NORMAL,
+		.name	  = "normal",
+		.fg	  = "default",
+		.bg	  = "default",
+	},
+	{
+		.colorset = HE_COLORSET_SELECTED,
+		.name	  = "selected",
+		.fg	  = "black",
+		.bg	  = "lightgray",
+	},
+	{
+		.colorset = HE_COLORSET_CODE,
+		.name	  = "code",
+		.fg	  = "blue",
+		.bg	  = "default",
+	},
+	{
+		.colorset = HE_COLORSET_ADDR,
+		.name	  = "addr",
+		.fg	  = "magenta",
+		.bg	  = "default",
+	},
+	{
+		.name = NULL,
+	}
+};
+
+
+static int ui_browser__color_config(const char *var, const char *value,
+				    void *data __used)
+{
+	char *fg = NULL, *bg;
+	int i;
+
+	/* same dir for all commands */
+	if (prefixcmp(var, "colors.") != 0)
+		return 0;
+
+	for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
+		const char *name = var + 7;
+
+		if (strcmp(ui_browser__colorsets[i].name, name) != 0)
+			continue;
+
+		fg = strdup(value);
+		if (fg == NULL)
+			break;
+
+		bg = strchr(fg, ',');
+		if (bg == NULL)
+			break;
+
+		*bg = '\0';
+		while (isspace(*++bg));
+		ui_browser__colorsets[i].bg = bg;
+		ui_browser__colorsets[i].fg = fg;
+		return 0;
+	}
+
+	free(fg);
+	return -1;
+}
+
+void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
+{
+	switch (whence) {
+	case SEEK_SET:
+		browser->top = browser->entries;
+		break;
+	case SEEK_CUR:
+		browser->top = browser->top + browser->top_idx + offset;
+		break;
+	case SEEK_END:
+		browser->top = browser->top + browser->nr_entries + offset;
+		break;
+	default:
+		return;
+	}
+}
+
+unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
+{
+	unsigned int row = 0, idx = browser->top_idx;
+	char **pos;
+
+	if (browser->top == NULL)
+		browser->top = browser->entries;
+
+	pos = (char **)browser->top;
+	while (idx < browser->nr_entries) {
+		if (!browser->filter || !browser->filter(browser, *pos)) {
+			ui_browser__gotorc(browser, row, 0);
+			browser->write(browser, pos, row);
+			if (++row == browser->height)
+				break;
+		}
+
+		++idx;
+		++pos;
+	}
+
+	return row;
+}
+
+void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
+			 u16 start, u16 end)
+{
+	SLsmg_set_char_set(1);
+	ui_browser__gotorc(browser, start, column);
+	SLsmg_draw_vline(end - start + 1);
+	SLsmg_set_char_set(0);
+}
+
+void ui_browser__write_graph(struct ui_browser *browser __used, int graph)
+{
+	SLsmg_set_char_set(1);
+	SLsmg_write_char(graph);
+	SLsmg_set_char_set(0);
+}
+
+static void __ui_browser__line_arrow_up(struct ui_browser *browser,
+					unsigned int column,
+					u64 start, u64 end)
+{
+	unsigned int row, end_row;
+
+	SLsmg_set_char_set(1);
+
+	if (start < browser->top_idx + browser->height) {
+		row = start - browser->top_idx;
+		ui_browser__gotorc(browser, row, column);
+		SLsmg_write_char(SLSMG_LLCORN_CHAR);
+		ui_browser__gotorc(browser, row, column + 1);
+		SLsmg_draw_hline(2);
+
+		if (row-- == 0)
+			goto out;
+	} else
+		row = browser->height - 1;
+
+	if (end > browser->top_idx)
+		end_row = end - browser->top_idx;
+	else
+		end_row = 0;
+
+	ui_browser__gotorc(browser, end_row, column);
+	SLsmg_draw_vline(row - end_row + 1);
+
+	ui_browser__gotorc(browser, end_row, column);
+	if (end >= browser->top_idx) {
+		SLsmg_write_char(SLSMG_ULCORN_CHAR);
+		ui_browser__gotorc(browser, end_row, column + 1);
+		SLsmg_write_char(SLSMG_HLINE_CHAR);
+		ui_browser__gotorc(browser, end_row, column + 2);
+		SLsmg_write_char(SLSMG_RARROW_CHAR);
+	}
+out:
+	SLsmg_set_char_set(0);
+}
+
+static void __ui_browser__line_arrow_down(struct ui_browser *browser,
+					  unsigned int column,
+					  u64 start, u64 end)
+{
+	unsigned int row, end_row;
+
+	SLsmg_set_char_set(1);
+
+	if (start >= browser->top_idx) {
+		row = start - browser->top_idx;
+		ui_browser__gotorc(browser, row, column);
+		SLsmg_write_char(SLSMG_ULCORN_CHAR);
+		ui_browser__gotorc(browser, row, column + 1);
+		SLsmg_draw_hline(2);
+
+		if (row++ == 0)
+			goto out;
+	} else
+		row = 0;
+
+	if (end >= browser->top_idx + browser->height)
+		end_row = browser->height - 1;
+	else
+		end_row = end - browser->top_idx;;
+
+	ui_browser__gotorc(browser, row, column);
+	SLsmg_draw_vline(end_row - row + 1);
+
+	ui_browser__gotorc(browser, end_row, column);
+	if (end < browser->top_idx + browser->height) {
+		SLsmg_write_char(SLSMG_LLCORN_CHAR);
+		ui_browser__gotorc(browser, end_row, column + 1);
+		SLsmg_write_char(SLSMG_HLINE_CHAR);
+		ui_browser__gotorc(browser, end_row, column + 2);
+		SLsmg_write_char(SLSMG_RARROW_CHAR);
+	}
+out:
+	SLsmg_set_char_set(0);
+}
+
+void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
+			      u64 start, u64 end)
+{
+	if (start > end)
+		__ui_browser__line_arrow_up(browser, column, start, end);
+	else
+		__ui_browser__line_arrow_down(browser, column, start, end);
+}
+
+void ui_browser__init(void)
+{
+	int i = 0;
+
+	perf_config(ui_browser__color_config, NULL);
+
+	while (ui_browser__colorsets[i].name) {
+		struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
+		sltt_set_color(c->colorset, c->name, c->fg, c->bg);
+	}
+}
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
new file mode 100644
index 0000000..dd96d82
--- /dev/null
+++ b/tools/perf/ui/browser.h
@@ -0,0 +1,72 @@
+#ifndef _PERF_UI_BROWSER_H_
+#define _PERF_UI_BROWSER_H_ 1
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include "../types.h"
+
+#define HE_COLORSET_TOP		50
+#define HE_COLORSET_MEDIUM	51
+#define HE_COLORSET_NORMAL	52
+#define HE_COLORSET_SELECTED	53
+#define HE_COLORSET_CODE	54
+#define HE_COLORSET_ADDR	55
+
+struct ui_browser {
+	u64	      index, top_idx;
+	void	      *top, *entries;
+	u16	      y, x, width, height;
+	int	      current_color;
+	void	      *priv;
+	const char    *title;
+	char	      *helpline;
+	unsigned int  (*refresh)(struct ui_browser *self);
+	void	      (*write)(struct ui_browser *self, void *entry, int row);
+	void	      (*seek)(struct ui_browser *self, off_t offset, int whence);
+	bool	      (*filter)(struct ui_browser *self, void *entry);
+	u32	      nr_entries;
+	bool	      navkeypressed;
+	bool	      use_navkeypressed;
+};
+
+int  ui_browser__set_color(struct ui_browser *browser, int color);
+void ui_browser__set_percent_color(struct ui_browser *self,
+				   double percent, bool current);
+bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
+void ui_browser__refresh_dimensions(struct ui_browser *self);
+void ui_browser__reset_index(struct ui_browser *self);
+
+void ui_browser__gotorc(struct ui_browser *self, int y, int x);
+void ui_browser__write_graph(struct ui_browser *browser, int graph);
+void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
+			      u64 start, u64 end);
+void __ui_browser__show_title(struct ui_browser *browser, const char *title);
+void ui_browser__show_title(struct ui_browser *browser, const char *title);
+int ui_browser__show(struct ui_browser *self, const char *title,
+		     const char *helpline, ...);
+void ui_browser__hide(struct ui_browser *self);
+int ui_browser__refresh(struct ui_browser *self);
+int ui_browser__run(struct ui_browser *browser, int delay_secs);
+void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
+void ui_browser__handle_resize(struct ui_browser *browser);
+void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
+			 u16 start, u16 end);
+
+int ui_browser__warning(struct ui_browser *browser, int timeout,
+			const char *format, ...);
+int ui_browser__help_window(struct ui_browser *browser, const char *text);
+bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
+int ui_browser__input_window(const char *title, const char *text, char *input,
+			     const char *exit_msg, int delay_sec);
+
+void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
+unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
+
+void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
+unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
+
+void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence);
+unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
+
+void ui_browser__init(void);
+#endif /* _PERF_UI_BROWSER_H_ */
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
new file mode 100644
index 0000000..6e0ef79
--- /dev/null
+++ b/tools/perf/ui/browsers/annotate.c
@@ -0,0 +1,867 @@
+#include "../../util/util.h"
+#include "../browser.h"
+#include "../helpline.h"
+#include "../libslang.h"
+#include "../ui.h"
+#include "../util.h"
+#include "../../util/annotate.h"
+#include "../../util/hist.h"
+#include "../../util/sort.h"
+#include "../../util/symbol.h"
+#include <pthread.h>
+#include <newt.h>
+
+struct browser_disasm_line {
+	struct rb_node	rb_node;
+	double		percent;
+	u32		idx;
+	int		idx_asm;
+	int		jump_sources;
+};
+
+struct annotate_browser {
+	struct ui_browser b;
+	struct rb_root	  entries;
+	struct rb_node	  *curr_hot;
+	struct disasm_line	  *selection;
+	struct disasm_line  **offsets;
+	u64		    start;
+	int		    nr_asm_entries;
+	int		    nr_entries;
+	int		    max_jump_sources;
+	int		    nr_jumps;
+	bool		    hide_src_code;
+	bool		    use_offset;
+	bool		    jump_arrows;
+	bool		    show_nr_jumps;
+	bool		    searching_backwards;
+	u8		    addr_width;
+	u8		    jumps_width;
+	u8		    target_width;
+	u8		    min_addr_width;
+	u8		    max_addr_width;
+	char		    search_bf[128];
+};
+
+static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
+{
+	return (struct browser_disasm_line *)(dl + 1);
+}
+
+static bool disasm_line__filter(struct ui_browser *browser, void *entry)
+{
+	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
+
+	if (ab->hide_src_code) {
+		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
+		return dl->offset == -1;
+	}
+
+	return false;
+}
+
+static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
+						 int nr, bool current)
+{
+	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
+		return HE_COLORSET_SELECTED;
+	if (nr == browser->max_jump_sources)
+		return HE_COLORSET_TOP;
+	if (nr > 1)
+		return HE_COLORSET_MEDIUM;
+	return HE_COLORSET_NORMAL;
+}
+
+static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
+						     int nr, bool current)
+{
+	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
+	 return ui_browser__set_color(&browser->b, color);
+}
+
+static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
+{
+	struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
+	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
+	struct browser_disasm_line *bdl = disasm_line__browser(dl);
+	bool current_entry = ui_browser__is_current_entry(self, row);
+	bool change_color = (!ab->hide_src_code &&
+			     (!current_entry || (self->use_navkeypressed &&
+					         !self->navkeypressed)));
+	int width = self->width, printed;
+	char bf[256];
+
+	if (dl->offset != -1 && bdl->percent != 0.0) {
+		ui_browser__set_percent_color(self, bdl->percent, current_entry);
+		slsmg_printf("%6.2f ", bdl->percent);
+	} else {
+		ui_browser__set_percent_color(self, 0, current_entry);
+		slsmg_write_nstring(" ", 7);
+	}
+
+	SLsmg_write_char(' ');
+
+	/* The scroll bar isn't being used */
+	if (!self->navkeypressed)
+		width += 1;
+
+	if (!*dl->line)
+		slsmg_write_nstring(" ", width - 7);
+	else if (dl->offset == -1) {
+		printed = scnprintf(bf, sizeof(bf), "%*s  ",
+				    ab->addr_width, " ");
+		slsmg_write_nstring(bf, printed);
+		slsmg_write_nstring(dl->line, width - printed - 6);
+	} else {
+		u64 addr = dl->offset;
+		int color = -1;
+
+		if (!ab->use_offset)
+			addr += ab->start;
+
+		if (!ab->use_offset) {
+			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
+		} else {
+			if (bdl->jump_sources) {
+				if (ab->show_nr_jumps) {
+					int prev;
+					printed = scnprintf(bf, sizeof(bf), "%*d ",
+							    ab->jumps_width,
+							    bdl->jump_sources);
+					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
+											 current_entry);
+					slsmg_write_nstring(bf, printed);
+					ui_browser__set_color(self, prev);
+				}
+
+				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
+						    ab->target_width, addr);
+			} else {
+				printed = scnprintf(bf, sizeof(bf), "%*s  ",
+						    ab->addr_width, " ");
+			}
+		}
+
+		if (change_color)
+			color = ui_browser__set_color(self, HE_COLORSET_ADDR);
+		slsmg_write_nstring(bf, printed);
+		if (change_color)
+			ui_browser__set_color(self, color);
+		if (dl->ins && dl->ins->ops->scnprintf) {
+			if (ins__is_jump(dl->ins)) {
+				bool fwd = dl->ops.target.offset > (u64)dl->offset;
+
+				ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR :
+								    SLSMG_UARROW_CHAR);
+				SLsmg_write_char(' ');
+			} else if (ins__is_call(dl->ins)) {
+				ui_browser__write_graph(self, SLSMG_RARROW_CHAR);
+				SLsmg_write_char(' ');
+			} else {
+				slsmg_write_nstring(" ", 2);
+			}
+		} else {
+			if (strcmp(dl->name, "retq")) {
+				slsmg_write_nstring(" ", 2);
+			} else {
+				ui_browser__write_graph(self, SLSMG_LARROW_CHAR);
+				SLsmg_write_char(' ');
+			}
+		}
+
+		disasm_line__scnprintf(dl, bf, sizeof(bf), !ab->use_offset);
+		slsmg_write_nstring(bf, width - 10 - printed);
+	}
+
+	if (current_entry)
+		ab->selection = dl;
+}
+
+static void annotate_browser__draw_current_jump(struct ui_browser *browser)
+{
+	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
+	struct disasm_line *cursor = ab->selection, *target;
+	struct browser_disasm_line *btarget, *bcursor;
+	unsigned int from, to;
+
+	if (!cursor->ins || !ins__is_jump(cursor->ins) ||
+	    !disasm_line__has_offset(cursor))
+		return;
+
+	target = ab->offsets[cursor->ops.target.offset];
+	if (!target)
+		return;
+
+	bcursor = disasm_line__browser(cursor);
+	btarget = disasm_line__browser(target);
+
+	if (ab->hide_src_code) {
+		from = bcursor->idx_asm;
+		to = btarget->idx_asm;
+	} else {
+		from = (u64)bcursor->idx;
+		to = (u64)btarget->idx;
+	}
+
+	ui_browser__set_color(browser, HE_COLORSET_CODE);
+	__ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
+}
+
+static unsigned int annotate_browser__refresh(struct ui_browser *browser)
+{
+	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
+	int ret = ui_browser__list_head_refresh(browser);
+
+	if (ab->jump_arrows)
+		annotate_browser__draw_current_jump(browser);
+
+	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
+	__ui_browser__vline(browser, 7, 0, browser->height - 1);
+	return ret;
+}
+
+static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
+{
+	double percent = 0.0;
+
+	if (dl->offset != -1) {
+		int len = sym->end - sym->start;
+		unsigned int hits = 0;
+		struct annotation *notes = symbol__annotation(sym);
+		struct source_line *src_line = notes->src->lines;
+		struct sym_hist *h = annotation__histogram(notes, evidx);
+		s64 offset = dl->offset;
+		struct disasm_line *next;
+
+		next = disasm__get_next_ip_line(&notes->src->source, dl);
+		while (offset < (s64)len &&
+		       (next == NULL || offset < next->offset)) {
+			if (src_line) {
+				percent += src_line[offset].percent;
+			} else
+				hits += h->addr[offset];
+
+			++offset;
+		}
+		/*
+ 		 * If the percentage wasn't already calculated in
+ 		 * symbol__get_source_line, do it now:
+ 		 */
+		if (src_line == NULL && h->sum)
+			percent = 100.0 * hits / h->sum;
+	}
+
+	return percent;
+}
+
+static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
+{
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct browser_disasm_line *l;
+
+	while (*p != NULL) {
+		parent = *p;
+		l = rb_entry(parent, struct browser_disasm_line, rb_node);
+		if (bdl->percent < l->percent)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+	rb_link_node(&bdl->rb_node, parent, p);
+	rb_insert_color(&bdl->rb_node, root);
+}
+
+static void annotate_browser__set_top(struct annotate_browser *self,
+				      struct disasm_line *pos, u32 idx)
+{
+	unsigned back;
+
+	ui_browser__refresh_dimensions(&self->b);
+	back = self->b.height / 2;
+	self->b.top_idx = self->b.index = idx;
+
+	while (self->b.top_idx != 0 && back != 0) {
+		pos = list_entry(pos->node.prev, struct disasm_line, node);
+
+		if (disasm_line__filter(&self->b, &pos->node))
+			continue;
+
+		--self->b.top_idx;
+		--back;
+	}
+
+	self->b.top = pos;
+	self->b.navkeypressed = true;
+}
+
+static void annotate_browser__set_rb_top(struct annotate_browser *browser,
+					 struct rb_node *nd)
+{
+	struct browser_disasm_line *bpos;
+	struct disasm_line *pos;
+
+	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
+	pos = ((struct disasm_line *)bpos) - 1;
+	annotate_browser__set_top(browser, pos, bpos->idx);
+	browser->curr_hot = nd;
+}
+
+static void annotate_browser__calc_percent(struct annotate_browser *browser,
+					   int evidx)
+{
+	struct map_symbol *ms = browser->b.priv;
+	struct symbol *sym = ms->sym;
+	struct annotation *notes = symbol__annotation(sym);
+	struct disasm_line *pos;
+
+	browser->entries = RB_ROOT;
+
+	pthread_mutex_lock(&notes->lock);
+
+	list_for_each_entry(pos, &notes->src->source, node) {
+		struct browser_disasm_line *bpos = disasm_line__browser(pos);
+		bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
+		if (bpos->percent < 0.01) {
+			RB_CLEAR_NODE(&bpos->rb_node);
+			continue;
+		}
+		disasm_rb_tree__insert(&browser->entries, bpos);
+	}
+	pthread_mutex_unlock(&notes->lock);
+
+	browser->curr_hot = rb_last(&browser->entries);
+}
+
+static bool annotate_browser__toggle_source(struct annotate_browser *browser)
+{
+	struct disasm_line *dl;
+	struct browser_disasm_line *bdl;
+	off_t offset = browser->b.index - browser->b.top_idx;
+
+	browser->b.seek(&browser->b, offset, SEEK_CUR);
+	dl = list_entry(browser->b.top, struct disasm_line, node);
+	bdl = disasm_line__browser(dl);
+
+	if (browser->hide_src_code) {
+		if (bdl->idx_asm < offset)
+			offset = bdl->idx;
+
+		browser->b.nr_entries = browser->nr_entries;
+		browser->hide_src_code = false;
+		browser->b.seek(&browser->b, -offset, SEEK_CUR);
+		browser->b.top_idx = bdl->idx - offset;
+		browser->b.index = bdl->idx;
+	} else {
+		if (bdl->idx_asm < 0) {
+			ui_helpline__puts("Only available for assembly lines.");
+			browser->b.seek(&browser->b, -offset, SEEK_CUR);
+			return false;
+		}
+
+		if (bdl->idx_asm < offset)
+			offset = bdl->idx_asm;
+
+		browser->b.nr_entries = browser->nr_asm_entries;
+		browser->hide_src_code = true;
+		browser->b.seek(&browser->b, -offset, SEEK_CUR);
+		browser->b.top_idx = bdl->idx_asm - offset;
+		browser->b.index = bdl->idx_asm;
+	}
+
+	return true;
+}
+
+static bool annotate_browser__callq(struct annotate_browser *browser,
+				    int evidx, void (*timer)(void *arg),
+				    void *arg, int delay_secs)
+{
+	struct map_symbol *ms = browser->b.priv;
+	struct disasm_line *dl = browser->selection;
+	struct symbol *sym = ms->sym;
+	struct annotation *notes;
+	struct symbol *target;
+	u64 ip;
+
+	if (!ins__is_call(dl->ins))
+		return false;
+
+	ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
+	target = map__find_symbol(ms->map, ip, NULL);
+	if (target == NULL) {
+		ui_helpline__puts("The called function was not found.");
+		return true;
+	}
+
+	notes = symbol__annotation(target);
+	pthread_mutex_lock(&notes->lock);
+
+	if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
+		pthread_mutex_unlock(&notes->lock);
+		ui__warning("Not enough memory for annotating '%s' symbol!\n",
+			    target->name);
+		return true;
+	}
+
+	pthread_mutex_unlock(&notes->lock);
+	symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
+	ui_browser__show_title(&browser->b, sym->name);
+	return true;
+}
+
+static
+struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
+					  s64 offset, s64 *idx)
+{
+	struct map_symbol *ms = browser->b.priv;
+	struct symbol *sym = ms->sym;
+	struct annotation *notes = symbol__annotation(sym);
+	struct disasm_line *pos;
+
+	*idx = 0;
+	list_for_each_entry(pos, &notes->src->source, node) {
+		if (pos->offset == offset)
+			return pos;
+		if (!disasm_line__filter(&browser->b, &pos->node))
+			++*idx;
+	}
+
+	return NULL;
+}
+
+static bool annotate_browser__jump(struct annotate_browser *browser)
+{
+	struct disasm_line *dl = browser->selection;
+	s64 idx;
+
+	if (!ins__is_jump(dl->ins))
+		return false;
+
+	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
+	if (dl == NULL) {
+		ui_helpline__puts("Invallid jump offset");
+		return true;
+	}
+
+	annotate_browser__set_top(browser, dl, idx);
+	
+	return true;
+}
+
+static
+struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
+					  char *s, s64 *idx)
+{
+	struct map_symbol *ms = browser->b.priv;
+	struct symbol *sym = ms->sym;
+	struct annotation *notes = symbol__annotation(sym);
+	struct disasm_line *pos = browser->selection;
+
+	*idx = browser->b.index;
+	list_for_each_entry_continue(pos, &notes->src->source, node) {
+		if (disasm_line__filter(&browser->b, &pos->node))
+			continue;
+
+		++*idx;
+
+		if (pos->line && strstr(pos->line, s) != NULL)
+			return pos;
+	}
+
+	return NULL;
+}
+
+static bool __annotate_browser__search(struct annotate_browser *browser)
+{
+	struct disasm_line *dl;
+	s64 idx;
+
+	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
+	if (dl == NULL) {
+		ui_helpline__puts("String not found!");
+		return false;
+	}
+
+	annotate_browser__set_top(browser, dl, idx);
+	browser->searching_backwards = false;
+	return true;
+}
+
+static
+struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
+						  char *s, s64 *idx)
+{
+	struct map_symbol *ms = browser->b.priv;
+	struct symbol *sym = ms->sym;
+	struct annotation *notes = symbol__annotation(sym);
+	struct disasm_line *pos = browser->selection;
+
+	*idx = browser->b.index;
+	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
+		if (disasm_line__filter(&browser->b, &pos->node))
+			continue;
+
+		--*idx;
+
+		if (pos->line && strstr(pos->line, s) != NULL)
+			return pos;
+	}
+
+	return NULL;
+}
+
+static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
+{
+	struct disasm_line *dl;
+	s64 idx;
+
+	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
+	if (dl == NULL) {
+		ui_helpline__puts("String not found!");
+		return false;
+	}
+
+	annotate_browser__set_top(browser, dl, idx);
+	browser->searching_backwards = true;
+	return true;
+}
+
+static bool annotate_browser__search_window(struct annotate_browser *browser,
+					    int delay_secs)
+{
+	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
+				     "ENTER: OK, ESC: Cancel",
+				     delay_secs * 2) != K_ENTER ||
+	    !*browser->search_bf)
+		return false;
+
+	return true;
+}
+
+static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
+{
+	if (annotate_browser__search_window(browser, delay_secs))
+		return __annotate_browser__search(browser);
+
+	return false;
+}
+
+static bool annotate_browser__continue_search(struct annotate_browser *browser,
+					      int delay_secs)
+{
+	if (!*browser->search_bf)
+		return annotate_browser__search(browser, delay_secs);
+
+	return __annotate_browser__search(browser);
+}
+
+static bool annotate_browser__search_reverse(struct annotate_browser *browser,
+					   int delay_secs)
+{
+	if (annotate_browser__search_window(browser, delay_secs))
+		return __annotate_browser__search_reverse(browser);
+
+	return false;
+}
+
+static
+bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
+					       int delay_secs)
+{
+	if (!*browser->search_bf)
+		return annotate_browser__search_reverse(browser, delay_secs);
+
+	return __annotate_browser__search_reverse(browser);
+}
+
+static int annotate_browser__run(struct annotate_browser *self, int evidx,
+				 void(*timer)(void *arg),
+				 void *arg, int delay_secs)
+{
+	struct rb_node *nd = NULL;
+	struct map_symbol *ms = self->b.priv;
+	struct symbol *sym = ms->sym;
+	const char *help = "Press 'h' for help on key bindings";
+	int key;
+
+	if (ui_browser__show(&self->b, sym->name, help) < 0)
+		return -1;
+
+	annotate_browser__calc_percent(self, evidx);
+
+	if (self->curr_hot) {
+		annotate_browser__set_rb_top(self, self->curr_hot);
+		self->b.navkeypressed = false;
+	}
+
+	nd = self->curr_hot;
+
+	while (1) {
+		key = ui_browser__run(&self->b, delay_secs);
+
+		if (delay_secs != 0) {
+			annotate_browser__calc_percent(self, evidx);
+			/*
+			 * Current line focus got out of the list of most active
+			 * lines, NULL it so that if TAB|UNTAB is pressed, we
+			 * move to curr_hot (current hottest line).
+			 */
+			if (nd != NULL && RB_EMPTY_NODE(nd))
+				nd = NULL;
+		}
+
+		switch (key) {
+		case K_TIMER:
+			if (timer != NULL)
+				timer(arg);
+
+			if (delay_secs != 0)
+				symbol__annotate_decay_histogram(sym, evidx);
+			continue;
+		case K_TAB:
+			if (nd != NULL) {
+				nd = rb_prev(nd);
+				if (nd == NULL)
+					nd = rb_last(&self->entries);
+			} else
+				nd = self->curr_hot;
+			break;
+		case K_UNTAB:
+			if (nd != NULL)
+				nd = rb_next(nd);
+				if (nd == NULL)
+					nd = rb_first(&self->entries);
+			else
+				nd = self->curr_hot;
+			break;
+		case K_F1:
+		case 'h':
+			ui_browser__help_window(&self->b,
+		"UP/DOWN/PGUP\n"
+		"PGDN/SPACE    Navigate\n"
+		"q/ESC/CTRL+C  Exit\n\n"
+		"->            Go to target\n"
+		"<-            Exit\n"
+		"h             Cycle thru hottest instructions\n"
+		"j             Toggle showing jump to target arrows\n"
+		"J             Toggle showing number of jump sources on targets\n"
+		"n             Search next string\n"
+		"o             Toggle disassembler output/simplified view\n"
+		"s             Toggle source code view\n"
+		"/             Search string\n"
+		"?             Search previous string\n");
+			continue;
+		case 'H':
+			nd = self->curr_hot;
+			break;
+		case 's':
+			if (annotate_browser__toggle_source(self))
+				ui_helpline__puts(help);
+			continue;
+		case 'o':
+			self->use_offset = !self->use_offset;
+			if (self->use_offset)
+				self->target_width = self->min_addr_width;
+			else
+				self->target_width = self->max_addr_width;
+update_addr_width:
+			self->addr_width = self->target_width;
+			if (self->show_nr_jumps)
+				self->addr_width += self->jumps_width + 1;
+			continue;
+		case 'j':
+			self->jump_arrows = !self->jump_arrows;
+			continue;
+		case 'J':
+			self->show_nr_jumps = !self->show_nr_jumps;
+			goto update_addr_width;
+		case '/':
+			if (annotate_browser__search(self, delay_secs)) {
+show_help:
+				ui_helpline__puts(help);
+			}
+			continue;
+		case 'n':
+			if (self->searching_backwards ?
+			    annotate_browser__continue_search_reverse(self, delay_secs) :
+			    annotate_browser__continue_search(self, delay_secs))
+				goto show_help;
+			continue;
+		case '?':
+			if (annotate_browser__search_reverse(self, delay_secs))
+				goto show_help;
+			continue;
+		case K_ENTER:
+		case K_RIGHT:
+			if (self->selection == NULL)
+				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
+			else if (self->selection->offset == -1)
+				ui_helpline__puts("Actions are only available for assembly lines.");
+			else if (!self->selection->ins) {
+				if (strcmp(self->selection->name, "retq"))
+					goto show_sup_ins;
+				goto out;
+			} else if (!(annotate_browser__jump(self) ||
+				     annotate_browser__callq(self, evidx, timer, arg, delay_secs))) {
+show_sup_ins:
+				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
+			}
+			continue;
+		case K_LEFT:
+		case K_ESC:
+		case 'q':
+		case CTRL('c'):
+			goto out;
+		default:
+			continue;
+		}
+
+		if (nd != NULL)
+			annotate_browser__set_rb_top(self, nd);
+	}
+out:
+	ui_browser__hide(&self->b);
+	return key;
+}
+
+int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
+			     void(*timer)(void *arg), void *arg, int delay_secs)
+{
+	return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
+				    timer, arg, delay_secs);
+}
+
+static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
+						size_t size)
+{
+	u64 offset;
+
+	for (offset = 0; offset < size; ++offset) {
+		struct disasm_line *dl = browser->offsets[offset], *dlt;
+		struct browser_disasm_line *bdlt;
+
+		if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
+		    !disasm_line__has_offset(dl))
+			continue;
+
+		if (dl->ops.target.offset >= size) {
+			ui__error("jump to after symbol!\n"
+				  "size: %zx, jump target: %" PRIx64,
+				  size, dl->ops.target.offset);
+			continue;
+		}
+
+		dlt = browser->offsets[dl->ops.target.offset];
+		/*
+ 		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
+ 		 * have to adjust to the previous offset?
+ 		 */
+		if (dlt == NULL)
+			continue;
+
+		bdlt = disasm_line__browser(dlt);
+		if (++bdlt->jump_sources > browser->max_jump_sources)
+			browser->max_jump_sources = bdlt->jump_sources;
+
+		++browser->nr_jumps;
+	}
+		
+}
+
+static inline int width_jumps(int n)
+{
+	if (n >= 100)
+		return 5;
+	if (n / 10)
+		return 2;
+	return 1;
+}
+
+int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
+			 void(*timer)(void *arg), void *arg,
+			 int delay_secs)
+{
+	struct disasm_line *pos, *n;
+	struct annotation *notes;
+	const size_t size = symbol__size(sym);
+	struct map_symbol ms = {
+		.map = map,
+		.sym = sym,
+	};
+	struct annotate_browser browser = {
+		.b = {
+			.refresh = annotate_browser__refresh,
+			.seek	 = ui_browser__list_head_seek,
+			.write	 = annotate_browser__write,
+			.filter  = disasm_line__filter,
+			.priv	 = &ms,
+			.use_navkeypressed = true,
+		},
+		.use_offset = true,
+		.jump_arrows = true,
+	};
+	int ret = -1;
+
+	if (sym == NULL)
+		return -1;
+
+	if (map->dso->annotate_warned)
+		return -1;
+
+	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
+	if (browser.offsets == NULL) {
+		ui__error("Not enough memory!");
+		return -1;
+	}
+
+	if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
+		ui__error("%s", ui_helpline__last_msg);
+		goto out_free_offsets;
+	}
+
+	ui_helpline__push("Press <- or ESC to exit");
+
+	notes = symbol__annotation(sym);
+	browser.start = map__rip_2objdump(map, sym->start);
+
+	list_for_each_entry(pos, &notes->src->source, node) {
+		struct browser_disasm_line *bpos;
+		size_t line_len = strlen(pos->line);
+
+		if (browser.b.width < line_len)
+			browser.b.width = line_len;
+		bpos = disasm_line__browser(pos);
+		bpos->idx = browser.nr_entries++;
+		if (pos->offset != -1) {
+			bpos->idx_asm = browser.nr_asm_entries++;
+			/*
+			 * FIXME: short term bandaid to cope with assembly
+			 * routines that comes with labels in the same column
+			 * as the address in objdump, sigh.
+			 *
+			 * E.g. copy_user_generic_unrolled
+ 			 */
+			if (pos->offset < (s64)size)
+				browser.offsets[pos->offset] = pos;
+		} else
+			bpos->idx_asm = -1;
+	}
+
+	annotate_browser__mark_jump_targets(&browser, size);
+
+	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
+	browser.max_addr_width = hex_width(sym->end);
+	browser.jumps_width = width_jumps(browser.max_jump_sources);
+	browser.b.nr_entries = browser.nr_entries;
+	browser.b.entries = &notes->src->source,
+	browser.b.width += 18; /* Percentage */
+	ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
+	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
+		list_del(&pos->node);
+		disasm_line__free(pos);
+	}
+
+out_free_offsets:
+	free(browser.offsets);
+	return ret;
+}
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
new file mode 100644
index 0000000..a372a4b
--- /dev/null
+++ b/tools/perf/ui/browsers/hists.c
@@ -0,0 +1,1345 @@
+#include <stdio.h>
+#include "../libslang.h"
+#include <stdlib.h>
+#include <string.h>
+#include <newt.h>
+#include <linux/rbtree.h>
+
+#include "../../util/evsel.h"
+#include "../../util/evlist.h"
+#include "../../util/hist.h"
+#include "../../util/pstack.h"
+#include "../../util/sort.h"
+#include "../../util/util.h"
+
+#include "../browser.h"
+#include "../helpline.h"
+#include "../util.h"
+#include "../ui.h"
+#include "map.h"
+
+struct hist_browser {
+	struct ui_browser   b;
+	struct hists	    *hists;
+	struct hist_entry   *he_selection;
+	struct map_symbol   *selection;
+	bool		     has_symbols;
+};
+
+static int hists__browser_title(struct hists *self, char *bf, size_t size,
+				const char *ev_name);
+
+static void hist_browser__refresh_dimensions(struct hist_browser *self)
+{
+	/* 3 == +/- toggle symbol before actual hist_entry rendering */
+	self->b.width = 3 + (hists__sort_list_width(self->hists) +
+			     sizeof("[k]"));
+}
+
+static void hist_browser__reset(struct hist_browser *self)
+{
+	self->b.nr_entries = self->hists->nr_entries;
+	hist_browser__refresh_dimensions(self);
+	ui_browser__reset_index(&self->b);
+}
+
+static char tree__folded_sign(bool unfolded)
+{
+	return unfolded ? '-' : '+';
+}
+
+static char map_symbol__folded(const struct map_symbol *self)
+{
+	return self->has_children ? tree__folded_sign(self->unfolded) : ' ';
+}
+
+static char hist_entry__folded(const struct hist_entry *self)
+{
+	return map_symbol__folded(&self->ms);
+}
+
+static char callchain_list__folded(const struct callchain_list *self)
+{
+	return map_symbol__folded(&self->ms);
+}
+
+static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
+{
+	self->unfolded = unfold ? self->has_children : false;
+}
+
+static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
+{
+	int n = 0;
+	struct rb_node *nd;
+
+	for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
+		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
+		struct callchain_list *chain;
+		char folded_sign = ' '; /* No children */
+
+		list_for_each_entry(chain, &child->val, list) {
+			++n;
+			/* We need this because we may not have children */
+			folded_sign = callchain_list__folded(chain);
+			if (folded_sign == '+')
+				break;
+		}
+
+		if (folded_sign == '-') /* Have children and they're unfolded */
+			n += callchain_node__count_rows_rb_tree(child);
+	}
+
+	return n;
+}
+
+static int callchain_node__count_rows(struct callchain_node *node)
+{
+	struct callchain_list *chain;
+	bool unfolded = false;
+	int n = 0;
+
+	list_for_each_entry(chain, &node->val, list) {
+		++n;
+		unfolded = chain->ms.unfolded;
+	}
+
+	if (unfolded)
+		n += callchain_node__count_rows_rb_tree(node);
+
+	return n;
+}
+
+static int callchain__count_rows(struct rb_root *chain)
+{
+	struct rb_node *nd;
+	int n = 0;
+
+	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+		n += callchain_node__count_rows(node);
+	}
+
+	return n;
+}
+
+static bool map_symbol__toggle_fold(struct map_symbol *self)
+{
+	if (!self)
+		return false;
+
+	if (!self->has_children)
+		return false;
+
+	self->unfolded = !self->unfolded;
+	return true;
+}
+
+static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
+{
+	struct rb_node *nd = rb_first(&self->rb_root);
+
+	for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
+		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
+		struct callchain_list *chain;
+		bool first = true;
+
+		list_for_each_entry(chain, &child->val, list) {
+			if (first) {
+				first = false;
+				chain->ms.has_children = chain->list.next != &child->val ||
+							 !RB_EMPTY_ROOT(&child->rb_root);
+			} else
+				chain->ms.has_children = chain->list.next == &child->val &&
+							 !RB_EMPTY_ROOT(&child->rb_root);
+		}
+
+		callchain_node__init_have_children_rb_tree(child);
+	}
+}
+
+static void callchain_node__init_have_children(struct callchain_node *self)
+{
+	struct callchain_list *chain;
+
+	list_for_each_entry(chain, &self->val, list)
+		chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root);
+
+	callchain_node__init_have_children_rb_tree(self);
+}
+
+static void callchain__init_have_children(struct rb_root *self)
+{
+	struct rb_node *nd;
+
+	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
+		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+		callchain_node__init_have_children(node);
+	}
+}
+
+static void hist_entry__init_have_children(struct hist_entry *self)
+{
+	if (!self->init_have_children) {
+		self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain);
+		callchain__init_have_children(&self->sorted_chain);
+		self->init_have_children = true;
+	}
+}
+
+static bool hist_browser__toggle_fold(struct hist_browser *self)
+{
+	if (map_symbol__toggle_fold(self->selection)) {
+		struct hist_entry *he = self->he_selection;
+
+		hist_entry__init_have_children(he);
+		self->hists->nr_entries -= he->nr_rows;
+
+		if (he->ms.unfolded)
+			he->nr_rows = callchain__count_rows(&he->sorted_chain);
+		else
+			he->nr_rows = 0;
+		self->hists->nr_entries += he->nr_rows;
+		self->b.nr_entries = self->hists->nr_entries;
+
+		return true;
+	}
+
+	/* If it doesn't have children, no toggling performed */
+	return false;
+}
+
+static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold)
+{
+	int n = 0;
+	struct rb_node *nd;
+
+	for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
+		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
+		struct callchain_list *chain;
+		bool has_children = false;
+
+		list_for_each_entry(chain, &child->val, list) {
+			++n;
+			map_symbol__set_folding(&chain->ms, unfold);
+			has_children = chain->ms.has_children;
+		}
+
+		if (has_children)
+			n += callchain_node__set_folding_rb_tree(child, unfold);
+	}
+
+	return n;
+}
+
+static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
+{
+	struct callchain_list *chain;
+	bool has_children = false;
+	int n = 0;
+
+	list_for_each_entry(chain, &node->val, list) {
+		++n;
+		map_symbol__set_folding(&chain->ms, unfold);
+		has_children = chain->ms.has_children;
+	}
+
+	if (has_children)
+		n += callchain_node__set_folding_rb_tree(node, unfold);
+
+	return n;
+}
+
+static int callchain__set_folding(struct rb_root *chain, bool unfold)
+{
+	struct rb_node *nd;
+	int n = 0;
+
+	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+		n += callchain_node__set_folding(node, unfold);
+	}
+
+	return n;
+}
+
+static void hist_entry__set_folding(struct hist_entry *self, bool unfold)
+{
+	hist_entry__init_have_children(self);
+	map_symbol__set_folding(&self->ms, unfold);
+
+	if (self->ms.has_children) {
+		int n = callchain__set_folding(&self->sorted_chain, unfold);
+		self->nr_rows = unfold ? n : 0;
+	} else
+		self->nr_rows = 0;
+}
+
+static void hists__set_folding(struct hists *self, bool unfold)
+{
+	struct rb_node *nd;
+
+	self->nr_entries = 0;
+
+	for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
+		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
+		hist_entry__set_folding(he, unfold);
+		self->nr_entries += 1 + he->nr_rows;
+	}
+}
+
+static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
+{
+	hists__set_folding(self->hists, unfold);
+	self->b.nr_entries = self->hists->nr_entries;
+	/* Go to the start, we may be way after valid entries after a collapse */
+	ui_browser__reset_index(&self->b);
+}
+
+static void ui_browser__warn_lost_events(struct ui_browser *browser)
+{
+	ui_browser__warning(browser, 4,
+		"Events are being lost, check IO/CPU overload!\n\n"
+		"You may want to run 'perf' using a RT scheduler policy:\n\n"
+		" perf top -r 80\n\n"
+		"Or reduce the sampling frequency.");
+}
+
+static int hist_browser__run(struct hist_browser *self, const char *ev_name,
+			     void(*timer)(void *arg), void *arg, int delay_secs)
+{
+	int key;
+	char title[160];
+
+	self->b.entries = &self->hists->entries;
+	self->b.nr_entries = self->hists->nr_entries;
+
+	hist_browser__refresh_dimensions(self);
+	hists__browser_title(self->hists, title, sizeof(title), ev_name);
+
+	if (ui_browser__show(&self->b, title,
+			     "Press '?' for help on key bindings") < 0)
+		return -1;
+
+	while (1) {
+		key = ui_browser__run(&self->b, delay_secs);
+
+		switch (key) {
+		case K_TIMER:
+			timer(arg);
+			ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
+
+			if (self->hists->stats.nr_lost_warned !=
+			    self->hists->stats.nr_events[PERF_RECORD_LOST]) {
+				self->hists->stats.nr_lost_warned =
+					self->hists->stats.nr_events[PERF_RECORD_LOST];
+				ui_browser__warn_lost_events(&self->b);
+			}
+
+			hists__browser_title(self->hists, title, sizeof(title), ev_name);
+			ui_browser__show_title(&self->b, title);
+			continue;
+		case 'D': { /* Debug */
+			static int seq;
+			struct hist_entry *h = rb_entry(self->b.top,
+							struct hist_entry, rb_node);
+			ui_helpline__pop();
+			ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
+					   seq++, self->b.nr_entries,
+					   self->hists->nr_entries,
+					   self->b.height,
+					   self->b.index,
+					   self->b.top_idx,
+					   h->row_offset, h->nr_rows);
+		}
+			break;
+		case 'C':
+			/* Collapse the whole world. */
+			hist_browser__set_folding(self, false);
+			break;
+		case 'E':
+			/* Expand the whole world. */
+			hist_browser__set_folding(self, true);
+			break;
+		case K_ENTER:
+			if (hist_browser__toggle_fold(self))
+				break;
+			/* fall thru */
+		default:
+			goto out;
+		}
+	}
+out:
+	ui_browser__hide(&self->b);
+	return key;
+}
+
+static char *callchain_list__sym_name(struct callchain_list *self,
+				      char *bf, size_t bfsize)
+{
+	if (self->ms.sym)
+		return self->ms.sym->name;
+
+	snprintf(bf, bfsize, "%#" PRIx64, self->ip);
+	return bf;
+}
+
+#define LEVEL_OFFSET_STEP 3
+
+static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
+						     struct callchain_node *chain_node,
+						     u64 total, int level,
+						     unsigned short row,
+						     off_t *row_offset,
+						     bool *is_current_entry)
+{
+	struct rb_node *node;
+	int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
+	u64 new_total, remaining;
+
+	if (callchain_param.mode == CHAIN_GRAPH_REL)
+		new_total = chain_node->children_hit;
+	else
+		new_total = total;
+
+	remaining = new_total;
+	node = rb_first(&chain_node->rb_root);
+	while (node) {
+		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+		struct rb_node *next = rb_next(node);
+		u64 cumul = callchain_cumul_hits(child);
+		struct callchain_list *chain;
+		char folded_sign = ' ';
+		int first = true;
+		int extra_offset = 0;
+
+		remaining -= cumul;
+
+		list_for_each_entry(chain, &child->val, list) {
+			char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
+			const char *str;
+			int color;
+			bool was_first = first;
+
+			if (first)
+				first = false;
+			else
+				extra_offset = LEVEL_OFFSET_STEP;
+
+			folded_sign = callchain_list__folded(chain);
+			if (*row_offset != 0) {
+				--*row_offset;
+				goto do_next;
+			}
+
+			alloc_str = NULL;
+			str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+			if (was_first) {
+				double percent = cumul * 100.0 / new_total;
+
+				if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
+					str = "Not enough memory!";
+				else
+					str = alloc_str;
+			}
+
+			color = HE_COLORSET_NORMAL;
+			width = self->b.width - (offset + extra_offset + 2);
+			if (ui_browser__is_current_entry(&self->b, row)) {
+				self->selection = &chain->ms;
+				color = HE_COLORSET_SELECTED;
+				*is_current_entry = true;
+			}
+
+			ui_browser__set_color(&self->b, color);
+			ui_browser__gotorc(&self->b, row, 0);
+			slsmg_write_nstring(" ", offset + extra_offset);
+			slsmg_printf("%c ", folded_sign);
+			slsmg_write_nstring(str, width);
+			free(alloc_str);
+
+			if (++row == self->b.height)
+				goto out;
+do_next:
+			if (folded_sign == '+')
+				break;
+		}
+
+		if (folded_sign == '-') {
+			const int new_level = level + (extra_offset ? 2 : 1);
+			row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
+									 new_level, row, row_offset,
+									 is_current_entry);
+		}
+		if (row == self->b.height)
+			goto out;
+		node = next;
+	}
+out:
+	return row - first_row;
+}
+
+static int hist_browser__show_callchain_node(struct hist_browser *self,
+					     struct callchain_node *node,
+					     int level, unsigned short row,
+					     off_t *row_offset,
+					     bool *is_current_entry)
+{
+	struct callchain_list *chain;
+	int first_row = row,
+	     offset = level * LEVEL_OFFSET_STEP,
+	     width = self->b.width - offset;
+	char folded_sign = ' ';
+
+	list_for_each_entry(chain, &node->val, list) {
+		char ipstr[BITS_PER_LONG / 4 + 1], *s;
+		int color;
+
+		folded_sign = callchain_list__folded(chain);
+
+		if (*row_offset != 0) {
+			--*row_offset;
+			continue;
+		}
+
+		color = HE_COLORSET_NORMAL;
+		if (ui_browser__is_current_entry(&self->b, row)) {
+			self->selection = &chain->ms;
+			color = HE_COLORSET_SELECTED;
+			*is_current_entry = true;
+		}
+
+		s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+		ui_browser__gotorc(&self->b, row, 0);
+		ui_browser__set_color(&self->b, color);
+		slsmg_write_nstring(" ", offset);
+		slsmg_printf("%c ", folded_sign);
+		slsmg_write_nstring(s, width - 2);
+
+		if (++row == self->b.height)
+			goto out;
+	}
+
+	if (folded_sign == '-')
+		row += hist_browser__show_callchain_node_rb_tree(self, node,
+								 self->hists->stats.total_period,
+								 level + 1, row,
+								 row_offset,
+								 is_current_entry);
+out:
+	return row - first_row;
+}
+
+static int hist_browser__show_callchain(struct hist_browser *self,
+					struct rb_root *chain,
+					int level, unsigned short row,
+					off_t *row_offset,
+					bool *is_current_entry)
+{
+	struct rb_node *nd;
+	int first_row = row;
+
+	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+
+		row += hist_browser__show_callchain_node(self, node, level,
+							 row, row_offset,
+							 is_current_entry);
+		if (row == self->b.height)
+			break;
+	}
+
+	return row - first_row;
+}
+
+static int hist_browser__show_entry(struct hist_browser *self,
+				    struct hist_entry *entry,
+				    unsigned short row)
+{
+	char s[256];
+	double percent;
+	int printed = 0;
+	int width = self->b.width - 6; /* The percentage */
+	char folded_sign = ' ';
+	bool current_entry = ui_browser__is_current_entry(&self->b, row);
+	off_t row_offset = entry->row_offset;
+
+	if (current_entry) {
+		self->he_selection = entry;
+		self->selection = &entry->ms;
+	}
+
+	if (symbol_conf.use_callchain) {
+		hist_entry__init_have_children(entry);
+		folded_sign = hist_entry__folded(entry);
+	}
+
+	if (row_offset == 0) {
+		hist_entry__snprintf(entry, s, sizeof(s), self->hists);
+		percent = (entry->period * 100.0) / self->hists->stats.total_period;
+
+		ui_browser__set_percent_color(&self->b, percent, current_entry);
+		ui_browser__gotorc(&self->b, row, 0);
+		if (symbol_conf.use_callchain) {
+			slsmg_printf("%c ", folded_sign);
+			width -= 2;
+		}
+
+		slsmg_printf(" %5.2f%%", percent);
+
+		/* The scroll bar isn't being used */
+		if (!self->b.navkeypressed)
+			width += 1;
+
+		if (!current_entry || !self->b.navkeypressed)
+			ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
+
+		if (symbol_conf.show_nr_samples) {
+			slsmg_printf(" %11u", entry->nr_events);
+			width -= 12;
+		}
+
+		if (symbol_conf.show_total_period) {
+			slsmg_printf(" %12" PRIu64, entry->period);
+			width -= 13;
+		}
+
+		slsmg_write_nstring(s, width);
+		++row;
+		++printed;
+	} else
+		--row_offset;
+
+	if (folded_sign == '-' && row != self->b.height) {
+		printed += hist_browser__show_callchain(self, &entry->sorted_chain,
+							1, row, &row_offset,
+							&current_entry);
+		if (current_entry)
+			self->he_selection = entry;
+	}
+
+	return printed;
+}
+
+static void ui_browser__hists_init_top(struct ui_browser *browser)
+{
+	if (browser->top == NULL) {
+		struct hist_browser *hb;
+
+		hb = container_of(browser, struct hist_browser, b);
+		browser->top = rb_first(&hb->hists->entries);
+	}
+}
+
+static unsigned int hist_browser__refresh(struct ui_browser *self)
+{
+	unsigned row = 0;
+	struct rb_node *nd;
+	struct hist_browser *hb = container_of(self, struct hist_browser, b);
+
+	ui_browser__hists_init_top(self);
+
+	for (nd = self->top; nd; nd = rb_next(nd)) {
+		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+
+		if (h->filtered)
+			continue;
+
+		row += hist_browser__show_entry(hb, h, row);
+		if (row == self->height)
+			break;
+	}
+
+	return row;
+}
+
+static struct rb_node *hists__filter_entries(struct rb_node *nd)
+{
+	while (nd != NULL) {
+		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+		if (!h->filtered)
+			return nd;
+
+		nd = rb_next(nd);
+	}
+
+	return NULL;
+}
+
+static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
+{
+	while (nd != NULL) {
+		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+		if (!h->filtered)
+			return nd;
+
+		nd = rb_prev(nd);
+	}
+
+	return NULL;
+}
+
+static void ui_browser__hists_seek(struct ui_browser *self,
+				   off_t offset, int whence)
+{
+	struct hist_entry *h;
+	struct rb_node *nd;
+	bool first = true;
+
+	if (self->nr_entries == 0)
+		return;
+
+	ui_browser__hists_init_top(self);
+
+	switch (whence) {
+	case SEEK_SET:
+		nd = hists__filter_entries(rb_first(self->entries));
+		break;
+	case SEEK_CUR:
+		nd = self->top;
+		goto do_offset;
+	case SEEK_END:
+		nd = hists__filter_prev_entries(rb_last(self->entries));
+		first = false;
+		break;
+	default:
+		return;
+	}
+
+	/*
+	 * Moves not relative to the first visible entry invalidates its
+	 * row_offset:
+	 */
+	h = rb_entry(self->top, struct hist_entry, rb_node);
+	h->row_offset = 0;
+
+	/*
+	 * Here we have to check if nd is expanded (+), if it is we can't go
+	 * the next top level hist_entry, instead we must compute an offset of
+	 * what _not_ to show and not change the first visible entry.
+	 *
+	 * This offset increments when we are going from top to bottom and
+	 * decreases when we're going from bottom to top.
+	 *
+	 * As we don't have backpointers to the top level in the callchains
+	 * structure, we need to always print the whole hist_entry callchain,
+	 * skipping the first ones that are before the first visible entry
+	 * and stop when we printed enough lines to fill the screen.
+	 */
+do_offset:
+	if (offset > 0) {
+		do {
+			h = rb_entry(nd, struct hist_entry, rb_node);
+			if (h->ms.unfolded) {
+				u16 remaining = h->nr_rows - h->row_offset;
+				if (offset > remaining) {
+					offset -= remaining;
+					h->row_offset = 0;
+				} else {
+					h->row_offset += offset;
+					offset = 0;
+					self->top = nd;
+					break;
+				}
+			}
+			nd = hists__filter_entries(rb_next(nd));
+			if (nd == NULL)
+				break;
+			--offset;
+			self->top = nd;
+		} while (offset != 0);
+	} else if (offset < 0) {
+		while (1) {
+			h = rb_entry(nd, struct hist_entry, rb_node);
+			if (h->ms.unfolded) {
+				if (first) {
+					if (-offset > h->row_offset) {
+						offset += h->row_offset;
+						h->row_offset = 0;
+					} else {
+						h->row_offset += offset;
+						offset = 0;
+						self->top = nd;
+						break;
+					}
+				} else {
+					if (-offset > h->nr_rows) {
+						offset += h->nr_rows;
+						h->row_offset = 0;
+					} else {
+						h->row_offset = h->nr_rows + offset;
+						offset = 0;
+						self->top = nd;
+						break;
+					}
+				}
+			}
+
+			nd = hists__filter_prev_entries(rb_prev(nd));
+			if (nd == NULL)
+				break;
+			++offset;
+			self->top = nd;
+			if (offset == 0) {
+				/*
+				 * Last unfiltered hist_entry, check if it is
+				 * unfolded, if it is then we should have
+				 * row_offset at its last entry.
+				 */
+				h = rb_entry(nd, struct hist_entry, rb_node);
+				if (h->ms.unfolded)
+					h->row_offset = h->nr_rows;
+				break;
+			}
+			first = false;
+		}
+	} else {
+		self->top = nd;
+		h = rb_entry(nd, struct hist_entry, rb_node);
+		h->row_offset = 0;
+	}
+}
+
+static struct hist_browser *hist_browser__new(struct hists *hists)
+{
+	struct hist_browser *self = zalloc(sizeof(*self));
+
+	if (self) {
+		self->hists = hists;
+		self->b.refresh = hist_browser__refresh;
+		self->b.seek = ui_browser__hists_seek;
+		self->b.use_navkeypressed = true;
+		if (sort__branch_mode == 1)
+			self->has_symbols = sort_sym_from.list.next != NULL;
+		else
+			self->has_symbols = sort_sym.list.next != NULL;
+	}
+
+	return self;
+}
+
+static void hist_browser__delete(struct hist_browser *self)
+{
+	free(self);
+}
+
+static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
+{
+	return self->he_selection;
+}
+
+static struct thread *hist_browser__selected_thread(struct hist_browser *self)
+{
+	return self->he_selection->thread;
+}
+
+static int hists__browser_title(struct hists *self, char *bf, size_t size,
+				const char *ev_name)
+{
+	char unit;
+	int printed;
+	const struct dso *dso = self->dso_filter;
+	const struct thread *thread = self->thread_filter;
+	unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
+	u64 nr_events = self->stats.total_period;
+
+	nr_samples = convert_unit(nr_samples, &unit);
+	printed = scnprintf(bf, size,
+			   "Samples: %lu%c of event '%s', Event count (approx.): %lu",
+			   nr_samples, unit, ev_name, nr_events);
+
+
+	if (self->uid_filter_str)
+		printed += snprintf(bf + printed, size - printed,
+				    ", UID: %s", self->uid_filter_str);
+	if (thread)
+		printed += scnprintf(bf + printed, size - printed,
+				    ", Thread: %s(%d)",
+				    (thread->comm_set ? thread->comm : ""),
+				    thread->pid);
+	if (dso)
+		printed += scnprintf(bf + printed, size - printed,
+				    ", DSO: %s", dso->short_name);
+	return printed;
+}
+
+static inline void free_popup_options(char **options, int n)
+{
+	int i;
+
+	for (i = 0; i < n; ++i) {
+		free(options[i]);
+		options[i] = NULL;
+	}
+}
+
+static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
+				    const char *helpline, const char *ev_name,
+				    bool left_exits,
+				    void(*timer)(void *arg), void *arg,
+				    int delay_secs)
+{
+	struct hists *self = &evsel->hists;
+	struct hist_browser *browser = hist_browser__new(self);
+	struct branch_info *bi;
+	struct pstack *fstack;
+	char *options[16];
+	int nr_options = 0;
+	int key = -1;
+	char buf[64];
+
+	if (browser == NULL)
+		return -1;
+
+	fstack = pstack__new(2);
+	if (fstack == NULL)
+		goto out;
+
+	ui_helpline__push(helpline);
+
+	memset(options, 0, sizeof(options));
+
+	while (1) {
+		const struct thread *thread = NULL;
+		const struct dso *dso = NULL;
+		int choice = 0,
+		    annotate = -2, zoom_dso = -2, zoom_thread = -2,
+		    annotate_f = -2, annotate_t = -2, browse_map = -2;
+
+		nr_options = 0;
+
+		key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
+
+		if (browser->he_selection != NULL) {
+			thread = hist_browser__selected_thread(browser);
+			dso = browser->selection->map ? browser->selection->map->dso : NULL;
+		}
+		switch (key) {
+		case K_TAB:
+		case K_UNTAB:
+			if (nr_events == 1)
+				continue;
+			/*
+			 * Exit the browser, let hists__browser_tree
+			 * go to the next or previous
+			 */
+			goto out_free_stack;
+		case 'a':
+			if (!browser->has_symbols) {
+				ui_browser__warning(&browser->b, delay_secs * 2,
+			"Annotation is only available for symbolic views, "
+			"include \"sym*\" in --sort to use it.");
+				continue;
+			}
+
+			if (browser->selection == NULL ||
+			    browser->selection->sym == NULL ||
+			    browser->selection->map->dso->annotate_warned)
+				continue;
+			goto do_annotate;
+		case 'd':
+			goto zoom_dso;
+		case 't':
+			goto zoom_thread;
+		case '/':
+			if (ui_browser__input_window("Symbol to show",
+					"Please enter the name of symbol you want to see",
+					buf, "ENTER: OK, ESC: Cancel",
+					delay_secs * 2) == K_ENTER) {
+				self->symbol_filter_str = *buf ? buf : NULL;
+				hists__filter_by_symbol(self);
+				hist_browser__reset(browser);
+			}
+			continue;
+		case K_F1:
+		case 'h':
+		case '?':
+			ui_browser__help_window(&browser->b,
+					"h/?/F1        Show this window\n"
+					"UP/DOWN/PGUP\n"
+					"PGDN/SPACE    Navigate\n"
+					"q/ESC/CTRL+C  Exit browser\n\n"
+					"For multiple event sessions:\n\n"
+					"TAB/UNTAB Switch events\n\n"
+					"For symbolic views (--sort has sym):\n\n"
+					"->            Zoom into DSO/Threads & Annotate current symbol\n"
+					"<-            Zoom out\n"
+					"a             Annotate current symbol\n"
+					"C             Collapse all callchains\n"
+					"E             Expand all callchains\n"
+					"d             Zoom into current DSO\n"
+					"t             Zoom into current Thread\n"
+					"/             Filter symbol by name");
+			continue;
+		case K_ENTER:
+		case K_RIGHT:
+			/* menu */
+			break;
+		case K_LEFT: {
+			const void *top;
+
+			if (pstack__empty(fstack)) {
+				/*
+				 * Go back to the perf_evsel_menu__run or other user
+				 */
+				if (left_exits)
+					goto out_free_stack;
+				continue;
+			}
+			top = pstack__pop(fstack);
+			if (top == &browser->hists->dso_filter)
+				goto zoom_out_dso;
+			if (top == &browser->hists->thread_filter)
+				goto zoom_out_thread;
+			continue;
+		}
+		case K_ESC:
+			if (!left_exits &&
+			    !ui_browser__dialog_yesno(&browser->b,
+					       "Do you really want to exit?"))
+				continue;
+			/* Fall thru */
+		case 'q':
+		case CTRL('c'):
+			goto out_free_stack;
+		default:
+			continue;
+		}
+
+		if (!browser->has_symbols)
+			goto add_exit_option;
+
+		if (sort__branch_mode == 1) {
+			bi = browser->he_selection->branch_info;
+			if (browser->selection != NULL &&
+			    bi &&
+			    bi->from.sym != NULL &&
+			    !bi->from.map->dso->annotate_warned &&
+				asprintf(&options[nr_options], "Annotate %s",
+					 bi->from.sym->name) > 0)
+				annotate_f = nr_options++;
+
+			if (browser->selection != NULL &&
+			    bi &&
+			    bi->to.sym != NULL &&
+			    !bi->to.map->dso->annotate_warned &&
+			    (bi->to.sym != bi->from.sym ||
+			     bi->to.map->dso != bi->from.map->dso) &&
+				asprintf(&options[nr_options], "Annotate %s",
+					 bi->to.sym->name) > 0)
+				annotate_t = nr_options++;
+		} else {
+
+			if (browser->selection != NULL &&
+			    browser->selection->sym != NULL &&
+			    !browser->selection->map->dso->annotate_warned &&
+				asprintf(&options[nr_options], "Annotate %s",
+					 browser->selection->sym->name) > 0)
+				annotate = nr_options++;
+		}
+
+		if (thread != NULL &&
+		    asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
+			     (browser->hists->thread_filter ? "out of" : "into"),
+			     (thread->comm_set ? thread->comm : ""),
+			     thread->pid) > 0)
+			zoom_thread = nr_options++;
+
+		if (dso != NULL &&
+		    asprintf(&options[nr_options], "Zoom %s %s DSO",
+			     (browser->hists->dso_filter ? "out of" : "into"),
+			     (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
+			zoom_dso = nr_options++;
+
+		if (browser->selection != NULL &&
+		    browser->selection->map != NULL &&
+		    asprintf(&options[nr_options], "Browse map details") > 0)
+			browse_map = nr_options++;
+add_exit_option:
+		options[nr_options++] = (char *)"Exit";
+retry_popup_menu:
+		choice = ui__popup_menu(nr_options, options);
+
+		if (choice == nr_options - 1)
+			break;
+
+		if (choice == -1) {
+			free_popup_options(options, nr_options - 1);
+			continue;
+		}
+
+		if (choice == annotate || choice == annotate_t || choice == annotate_f) {
+			struct hist_entry *he;
+			int err;
+do_annotate:
+			he = hist_browser__selected_entry(browser);
+			if (he == NULL)
+				continue;
+
+			/*
+			 * we stash the branch_info symbol + map into the
+			 * the ms so we don't have to rewrite all the annotation
+			 * code to use branch_info.
+			 * in branch mode, the ms struct is not used
+			 */
+			if (choice == annotate_f) {
+				he->ms.sym = he->branch_info->from.sym;
+				he->ms.map = he->branch_info->from.map;
+			}  else if (choice == annotate_t) {
+				he->ms.sym = he->branch_info->to.sym;
+				he->ms.map = he->branch_info->to.map;
+			}
+
+			/*
+			 * Don't let this be freed, say, by hists__decay_entry.
+			 */
+			he->used = true;
+			err = hist_entry__tui_annotate(he, evsel->idx,
+						       timer, arg, delay_secs);
+			he->used = false;
+			/*
+			 * offer option to annotate the other branch source or target
+			 * (if they exists) when returning from annotate
+			 */
+			if ((err == 'q' || err == CTRL('c'))
+			    && annotate_t != -2 && annotate_f != -2)
+				goto retry_popup_menu;
+
+			ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
+			if (err)
+				ui_browser__handle_resize(&browser->b);
+
+		} else if (choice == browse_map)
+			map__browse(browser->selection->map);
+		else if (choice == zoom_dso) {
+zoom_dso:
+			if (browser->hists->dso_filter) {
+				pstack__remove(fstack, &browser->hists->dso_filter);
+zoom_out_dso:
+				ui_helpline__pop();
+				browser->hists->dso_filter = NULL;
+				sort_dso.elide = false;
+			} else {
+				if (dso == NULL)
+					continue;
+				ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
+						   dso->kernel ? "the Kernel" : dso->short_name);
+				browser->hists->dso_filter = dso;
+				sort_dso.elide = true;
+				pstack__push(fstack, &browser->hists->dso_filter);
+			}
+			hists__filter_by_dso(self);
+			hist_browser__reset(browser);
+		} else if (choice == zoom_thread) {
+zoom_thread:
+			if (browser->hists->thread_filter) {
+				pstack__remove(fstack, &browser->hists->thread_filter);
+zoom_out_thread:
+				ui_helpline__pop();
+				browser->hists->thread_filter = NULL;
+				sort_thread.elide = false;
+			} else {
+				ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
+						   thread->comm_set ? thread->comm : "",
+						   thread->pid);
+				browser->hists->thread_filter = thread;
+				sort_thread.elide = true;
+				pstack__push(fstack, &browser->hists->thread_filter);
+			}
+			hists__filter_by_thread(self);
+			hist_browser__reset(browser);
+		}
+	}
+out_free_stack:
+	pstack__delete(fstack);
+out:
+	hist_browser__delete(browser);
+	free_popup_options(options, nr_options - 1);
+	return key;
+}
+
+struct perf_evsel_menu {
+	struct ui_browser b;
+	struct perf_evsel *selection;
+	bool lost_events, lost_events_warned;
+};
+
+static void perf_evsel_menu__write(struct ui_browser *browser,
+				   void *entry, int row)
+{
+	struct perf_evsel_menu *menu = container_of(browser,
+						    struct perf_evsel_menu, b);
+	struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
+	bool current_entry = ui_browser__is_current_entry(browser, row);
+	unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+	const char *ev_name = event_name(evsel);
+	char bf[256], unit;
+	const char *warn = " ";
+	size_t printed;
+
+	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
+						       HE_COLORSET_NORMAL);
+
+	nr_events = convert_unit(nr_events, &unit);
+	printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
+			   unit, unit == ' ' ? "" : " ", ev_name);
+	slsmg_printf("%s", bf);
+
+	nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
+	if (nr_events != 0) {
+		menu->lost_events = true;
+		if (!current_entry)
+			ui_browser__set_color(browser, HE_COLORSET_TOP);
+		nr_events = convert_unit(nr_events, &unit);
+		printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
+				     nr_events, unit, unit == ' ' ? "" : " ");
+		warn = bf;
+	}
+
+	slsmg_write_nstring(warn, browser->width - printed);
+
+	if (current_entry)
+		menu->selection = evsel;
+}
+
+static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
+				int nr_events, const char *help,
+				void(*timer)(void *arg), void *arg, int delay_secs)
+{
+	struct perf_evlist *evlist = menu->b.priv;
+	struct perf_evsel *pos;
+	const char *ev_name, *title = "Available samples";
+	int key;
+
+	if (ui_browser__show(&menu->b, title,
+			     "ESC: exit, ENTER|->: Browse histograms") < 0)
+		return -1;
+
+	while (1) {
+		key = ui_browser__run(&menu->b, delay_secs);
+
+		switch (key) {
+		case K_TIMER:
+			timer(arg);
+
+			if (!menu->lost_events_warned && menu->lost_events) {
+				ui_browser__warn_lost_events(&menu->b);
+				menu->lost_events_warned = true;
+			}
+			continue;
+		case K_RIGHT:
+		case K_ENTER:
+			if (!menu->selection)
+				continue;
+			pos = menu->selection;
+browse_hists:
+			perf_evlist__set_selected(evlist, pos);
+			/*
+			 * Give the calling tool a chance to populate the non
+			 * default evsel resorted hists tree.
+			 */
+			if (timer)
+				timer(arg);
+			ev_name = event_name(pos);
+			key = perf_evsel__hists_browse(pos, nr_events, help,
+						       ev_name, true, timer,
+						       arg, delay_secs);
+			ui_browser__show_title(&menu->b, title);
+			switch (key) {
+			case K_TAB:
+				if (pos->node.next == &evlist->entries)
+					pos = list_entry(evlist->entries.next, struct perf_evsel, node);
+				else
+					pos = list_entry(pos->node.next, struct perf_evsel, node);
+				goto browse_hists;
+			case K_UNTAB:
+				if (pos->node.prev == &evlist->entries)
+					pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
+				else
+					pos = list_entry(pos->node.prev, struct perf_evsel, node);
+				goto browse_hists;
+			case K_ESC:
+				if (!ui_browser__dialog_yesno(&menu->b,
+						"Do you really want to exit?"))
+					continue;
+				/* Fall thru */
+			case 'q':
+			case CTRL('c'):
+				goto out;
+			default:
+				continue;
+			}
+		case K_LEFT:
+			continue;
+		case K_ESC:
+			if (!ui_browser__dialog_yesno(&menu->b,
+					       "Do you really want to exit?"))
+				continue;
+			/* Fall thru */
+		case 'q':
+		case CTRL('c'):
+			goto out;
+		default:
+			continue;
+		}
+	}
+
+out:
+	ui_browser__hide(&menu->b);
+	return key;
+}
+
+static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
+					   const char *help,
+					   void(*timer)(void *arg), void *arg,
+					   int delay_secs)
+{
+	struct perf_evsel *pos;
+	struct perf_evsel_menu menu = {
+		.b = {
+			.entries    = &evlist->entries,
+			.refresh    = ui_browser__list_head_refresh,
+			.seek	    = ui_browser__list_head_seek,
+			.write	    = perf_evsel_menu__write,
+			.nr_entries = evlist->nr_entries,
+			.priv	    = evlist,
+		},
+	};
+
+	ui_helpline__push("Press ESC to exit");
+
+	list_for_each_entry(pos, &evlist->entries, node) {
+		const char *ev_name = event_name(pos);
+		size_t line_len = strlen(ev_name) + 7;
+
+		if (menu.b.width < line_len)
+			menu.b.width = line_len;
+		/*
+		 * Cache the evsel name, tracepoints have a _high_ cost per
+		 * event_name() call.
+		 */
+		if (pos->name == NULL)
+			pos->name = strdup(ev_name);
+	}
+
+	return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
+				    arg, delay_secs);
+}
+
+int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
+				  void(*timer)(void *arg), void *arg,
+				  int delay_secs)
+{
+
+	if (evlist->nr_entries == 1) {
+		struct perf_evsel *first = list_entry(evlist->entries.next,
+						      struct perf_evsel, node);
+		const char *ev_name = event_name(first);
+		return perf_evsel__hists_browse(first, evlist->nr_entries, help,
+						ev_name, false, timer, arg,
+						delay_secs);
+	}
+
+	return __perf_evlist__tui_browse_hists(evlist, help,
+					       timer, arg, delay_secs);
+}
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
new file mode 100644
index 0000000..98851d5
--- /dev/null
+++ b/tools/perf/ui/browsers/map.c
@@ -0,0 +1,154 @@
+#include "../libslang.h"
+#include <elf.h>
+#include <newt.h>
+#include <inttypes.h>
+#include <sys/ttydefaults.h>
+#include <string.h>
+#include <linux/bitops.h>
+#include "../../util/util.h"
+#include "../../util/debug.h"
+#include "../../util/symbol.h"
+#include "../browser.h"
+#include "../helpline.h"
+#include "map.h"
+
+static int ui_entry__read(const char *title, char *bf, size_t size, int width)
+{
+	struct newtExitStruct es;
+	newtComponent form, entry;
+	const char *result;
+	int err = -1;
+
+	newtCenteredWindow(width, 1, title);
+	form = newtForm(NULL, NULL, 0);
+	if (form == NULL)
+		return -1;
+
+	entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
+	if (entry == NULL)
+		goto out_free_form;
+
+	newtFormAddComponent(form, entry);
+	newtFormAddHotKey(form, NEWT_KEY_ENTER);
+	newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
+	newtFormAddHotKey(form, NEWT_KEY_LEFT);
+	newtFormAddHotKey(form, CTRL('c'));
+	newtFormRun(form, &es);
+
+	if (result != NULL) {
+		strncpy(bf, result, size);
+		err = 0;
+	}
+out_free_form:
+	newtPopWindow();
+	newtFormDestroy(form);
+	return err;
+}
+
+struct map_browser {
+	struct ui_browser b;
+	struct map	  *map;
+	u8		  addrlen;
+};
+
+static void map_browser__write(struct ui_browser *self, void *nd, int row)
+{
+	struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+	struct map_browser *mb = container_of(self, struct map_browser, b);
+	bool current_entry = ui_browser__is_current_entry(self, row);
+	int width;
+
+	ui_browser__set_percent_color(self, 0, current_entry);
+	slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
+		     mb->addrlen, sym->start, mb->addrlen, sym->end,
+		     sym->binding == STB_GLOBAL ? 'g' :
+		     sym->binding == STB_LOCAL  ? 'l' : 'w');
+	width = self->width - ((mb->addrlen * 2) + 4);
+	if (width > 0)
+		slsmg_write_nstring(sym->name, width);
+}
+
+/* FIXME uber-kludgy, see comment on cmd_report... */
+static u32 *symbol__browser_index(struct symbol *self)
+{
+	return ((void *)self) - sizeof(struct rb_node) - sizeof(u32);
+}
+
+static int map_browser__search(struct map_browser *self)
+{
+	char target[512];
+	struct symbol *sym;
+	int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40);
+
+	if (err)
+		return err;
+
+	if (target[0] == '0' && tolower(target[1]) == 'x') {
+		u64 addr = strtoull(target, NULL, 16);
+		sym = map__find_symbol(self->map, addr, NULL);
+	} else
+		sym = map__find_symbol_by_name(self->map, target, NULL);
+
+	if (sym != NULL) {
+		u32 *idx = symbol__browser_index(sym);
+
+		self->b.top = &sym->rb_node;
+		self->b.index = self->b.top_idx = *idx;
+	} else
+		ui_helpline__fpush("%s not found!", target);
+
+	return 0;
+}
+
+static int map_browser__run(struct map_browser *self)
+{
+	int key;
+
+	if (ui_browser__show(&self->b, self->map->dso->long_name,
+			     "Press <- or ESC to exit, %s / to search",
+			     verbose ? "" : "restart with -v to use") < 0)
+		return -1;
+
+	while (1) {
+		key = ui_browser__run(&self->b, 0);
+
+		if (verbose && key == '/')
+			map_browser__search(self);
+		else
+			break;
+	}
+
+	ui_browser__hide(&self->b);
+	return key;
+}
+
+int map__browse(struct map *self)
+{
+	struct map_browser mb = {
+		.b = {
+			.entries = &self->dso->symbols[self->type],
+			.refresh = ui_browser__rb_tree_refresh,
+			.seek	 = ui_browser__rb_tree_seek,
+			.write	 = map_browser__write,
+		},
+		.map = self,
+	};
+	struct rb_node *nd;
+	char tmp[BITS_PER_LONG / 4];
+	u64 maxaddr = 0;
+
+	for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
+		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+
+		if (maxaddr < pos->end)
+			maxaddr = pos->end;
+		if (verbose) {
+			u32 *idx = symbol__browser_index(pos);
+			*idx = mb.b.nr_entries;
+		}
+		++mb.b.nr_entries;
+	}
+
+	mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
+	return map_browser__run(&mb);
+}
diff --git a/tools/perf/util/ui/browsers/map.h b/tools/perf/ui/browsers/map.h
similarity index 100%
rename from tools/perf/util/ui/browsers/map.h
rename to tools/perf/ui/browsers/map.h
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
new file mode 100644
index 0000000..0656c38
--- /dev/null
+++ b/tools/perf/ui/gtk/browser.c
@@ -0,0 +1,178 @@
+#include "../evlist.h"
+#include "../cache.h"
+#include "../evsel.h"
+#include "../sort.h"
+#include "../hist.h"
+#include "gtk.h"
+
+#include <signal.h>
+
+#define MAX_COLUMNS			32
+
+static void perf_gtk__signal(int sig)
+{
+	psignal(sig, "perf");
+	gtk_main_quit();
+}
+
+static void perf_gtk__resize_window(GtkWidget *window)
+{
+	GdkRectangle rect;
+	GdkScreen *screen;
+	int monitor;
+	int height;
+	int width;
+
+	screen = gtk_widget_get_screen(window);
+
+	monitor = gdk_screen_get_monitor_at_window(screen, window->window);
+
+	gdk_screen_get_monitor_geometry(screen, monitor, &rect);
+
+	width	= rect.width * 3 / 4;
+	height	= rect.height * 3 / 4;
+
+	gtk_window_resize(GTK_WINDOW(window), width, height);
+}
+
+static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
+{
+	GType col_types[MAX_COLUMNS];
+	GtkCellRenderer *renderer;
+	struct sort_entry *se;
+	GtkListStore *store;
+	struct rb_node *nd;
+	u64 total_period;
+	GtkWidget *view;
+	int col_idx;
+	int nr_cols;
+
+	nr_cols = 0;
+
+	/* The percentage column */
+	col_types[nr_cols++] = G_TYPE_STRING;
+
+	list_for_each_entry(se, &hist_entry__sort_list, list) {
+		if (se->elide)
+			continue;
+
+		col_types[nr_cols++] = G_TYPE_STRING;
+	}
+
+	store = gtk_list_store_newv(nr_cols, col_types);
+
+	view = gtk_tree_view_new();
+
+	renderer = gtk_cell_renderer_text_new();
+
+	col_idx = 0;
+
+	/* The percentage column */
+	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+						    -1, "Overhead (%)",
+						    renderer, "text",
+						    col_idx++, NULL);
+
+	list_for_each_entry(se, &hist_entry__sort_list, list) {
+		if (se->elide)
+			continue;
+
+		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+							    -1, se->se_header,
+							    renderer, "text",
+							    col_idx++, NULL);
+	}
+
+	gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
+
+	g_object_unref(GTK_TREE_MODEL(store));
+
+	total_period = hists->stats.total_period;
+
+	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
+		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+		GtkTreeIter iter;
+		double percent;
+		char s[512];
+
+		if (h->filtered)
+			continue;
+
+		gtk_list_store_append(store, &iter);
+
+		col_idx = 0;
+
+		percent = (h->period * 100.0) / total_period;
+
+		snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
+
+		gtk_list_store_set(store, &iter, col_idx++, s, -1);
+
+		list_for_each_entry(se, &hist_entry__sort_list, list) {
+			if (se->elide)
+				continue;
+
+			se->se_snprintf(h, s, ARRAY_SIZE(s),
+					hists__col_len(hists, se->se_width_idx));
+
+			gtk_list_store_set(store, &iter, col_idx++, s, -1);
+		}
+	}
+
+	gtk_container_add(GTK_CONTAINER(window), view);
+}
+
+int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
+				  const char *help __used,
+				  void (*timer) (void *arg)__used,
+				  void *arg __used, int delay_secs __used)
+{
+	struct perf_evsel *pos;
+	GtkWidget *notebook;
+	GtkWidget *window;
+
+	signal(SIGSEGV, perf_gtk__signal);
+	signal(SIGFPE,  perf_gtk__signal);
+	signal(SIGINT,  perf_gtk__signal);
+	signal(SIGQUIT, perf_gtk__signal);
+	signal(SIGTERM, perf_gtk__signal);
+
+	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+	gtk_window_set_title(GTK_WINDOW(window), "perf report");
+
+	g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
+
+	notebook = gtk_notebook_new();
+
+	list_for_each_entry(pos, &evlist->entries, node) {
+		struct hists *hists = &pos->hists;
+		const char *evname = event_name(pos);
+		GtkWidget *scrolled_window;
+		GtkWidget *tab_label;
+
+		scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+
+		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+							GTK_POLICY_AUTOMATIC,
+							GTK_POLICY_AUTOMATIC);
+
+		perf_gtk__show_hists(scrolled_window, hists);
+
+		tab_label = gtk_label_new(evname);
+
+		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
+	}
+
+	gtk_container_add(GTK_CONTAINER(window), notebook);
+
+	gtk_widget_show_all(window);
+
+	perf_gtk__resize_window(window);
+
+	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+
+	gtk_main();
+
+	return 0;
+}
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
similarity index 100%
rename from tools/perf/util/gtk/gtk.h
rename to tools/perf/ui/gtk/gtk.h
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
new file mode 100644
index 0000000..8295299
--- /dev/null
+++ b/tools/perf/ui/gtk/setup.c
@@ -0,0 +1,12 @@
+#include "gtk.h"
+#include "../../util/cache.h"
+
+int perf_gtk__init(void)
+{
+	return gtk_init_check(NULL, NULL) ? 0 : -1;
+}
+
+void perf_gtk__exit(bool wait_for_ok __used)
+{
+	gtk_main_quit();
+}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/ui/helpline.c
similarity index 100%
rename from tools/perf/util/ui/helpline.c
rename to tools/perf/ui/helpline.c
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/ui/helpline.h
similarity index 100%
rename from tools/perf/util/ui/helpline.h
rename to tools/perf/ui/helpline.h
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/ui/keysyms.h
similarity index 100%
rename from tools/perf/util/ui/keysyms.h
rename to tools/perf/ui/keysyms.h
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/ui/libslang.h
similarity index 100%
rename from tools/perf/util/ui/libslang.h
rename to tools/perf/ui/libslang.h
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/ui/progress.c
similarity index 100%
rename from tools/perf/util/ui/progress.c
rename to tools/perf/ui/progress.c
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/ui/progress.h
similarity index 100%
rename from tools/perf/util/ui/progress.h
rename to tools/perf/ui/progress.h
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
new file mode 100644
index 0000000..9f5f888
--- /dev/null
+++ b/tools/perf/ui/setup.c
@@ -0,0 +1,45 @@
+#include "../cache.h"
+#include "../debug.h"
+
+
+void setup_browser(bool fallback_to_pager)
+{
+	if (!isatty(1) || dump_trace)
+		use_browser = 0;
+
+	/* default to TUI */
+	if (use_browser < 0)
+		use_browser = 1;
+
+	switch (use_browser) {
+	case 2:
+		if (perf_gtk__init() == 0)
+			break;
+		/* fall through */
+	case 1:
+		use_browser = 1;
+		if (ui__init() == 0)
+			break;
+		/* fall through */
+	default:
+		if (fallback_to_pager)
+			setup_pager();
+		break;
+	}
+}
+
+void exit_browser(bool wait_for_ok)
+{
+	switch (use_browser) {
+	case 2:
+		perf_gtk__exit(wait_for_ok);
+		break;
+
+	case 1:
+		ui__exit(wait_for_ok);
+		break;
+
+	default:
+		break;
+	}
+}
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
new file mode 100644
index 0000000..d33e943
--- /dev/null
+++ b/tools/perf/ui/tui/setup.c
@@ -0,0 +1,140 @@
+#include <newt.h>
+#include <signal.h>
+#include <stdbool.h>
+
+#include "../../util/cache.h"
+#include "../../util/debug.h"
+#include "../browser.h"
+#include "../helpline.h"
+#include "../ui.h"
+#include "../util.h"
+#include "../libslang.h"
+#include "../keysyms.h"
+
+pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
+
+static volatile int ui__need_resize;
+
+void ui__refresh_dimensions(bool force)
+{
+	if (force || ui__need_resize) {
+		ui__need_resize = 0;
+		pthread_mutex_lock(&ui__lock);
+		SLtt_get_screen_size();
+		SLsmg_reinit_smg();
+		pthread_mutex_unlock(&ui__lock);
+	}
+}
+
+static void ui__sigwinch(int sig __used)
+{
+	ui__need_resize = 1;
+}
+
+static void ui__setup_sigwinch(void)
+{
+	static bool done;
+
+	if (done)
+		return;
+
+	done = true;
+	pthread__unblock_sigwinch();
+	signal(SIGWINCH, ui__sigwinch);
+}
+
+int ui__getch(int delay_secs)
+{
+	struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
+	fd_set read_set;
+	int err, key;
+
+	ui__setup_sigwinch();
+
+	FD_ZERO(&read_set);
+	FD_SET(0, &read_set);
+
+	if (delay_secs) {
+		timeout.tv_sec = delay_secs;
+		timeout.tv_usec = 0;
+	}
+
+        err = select(1, &read_set, NULL, NULL, ptimeout);
+
+	if (err == 0)
+		return K_TIMER;
+
+	if (err == -1) {
+		if (errno == EINTR)
+			return K_RESIZE;
+		return K_ERROR;
+	}
+
+	key = SLang_getkey();
+	if (key != K_ESC)
+		return key;
+
+	FD_ZERO(&read_set);
+	FD_SET(0, &read_set);
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 20;
+        err = select(1, &read_set, NULL, NULL, &timeout);
+	if (err == 0)
+		return K_ESC;
+
+	SLang_ungetkey(key);
+	return SLkp_getkey();
+}
+
+static void newt_suspend(void *d __used)
+{
+	newtSuspend();
+	raise(SIGTSTP);
+	newtResume();
+}
+
+static void ui__signal(int sig)
+{
+	ui__exit(false);
+	psignal(sig, "perf");
+	exit(0);
+}
+
+int ui__init(void)
+{
+	int err;
+
+	newtInit();
+	err = SLkp_init();
+	if (err < 0) {
+		pr_err("TUI initialization failed.\n");
+		goto out;
+	}
+
+	SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
+
+	newtSetSuspendCallback(newt_suspend, NULL);
+	ui_helpline__init();
+	ui_browser__init();
+
+	signal(SIGSEGV, ui__signal);
+	signal(SIGFPE, ui__signal);
+	signal(SIGINT, ui__signal);
+	signal(SIGQUIT, ui__signal);
+	signal(SIGTERM, ui__signal);
+out:
+	return err;
+}
+
+void ui__exit(bool wait_for_ok)
+{
+	if (wait_for_ok)
+		ui__question_window("Fatal Error",
+				    ui_helpline__last_msg,
+				    "Press any key...", 0);
+
+	SLtt_set_cursor_visibility(1);
+	SLsmg_refresh();
+	SLsmg_reset_smg();
+	SLang_reset_tty();
+}
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/ui/ui.h
similarity index 100%
rename from tools/perf/util/ui/ui.h
rename to tools/perf/ui/ui.h
diff --git a/tools/perf/util/ui/util.c b/tools/perf/ui/util.c
similarity index 100%
rename from tools/perf/util/ui/util.c
rename to tools/perf/ui/util.c
diff --git a/tools/perf/util/ui/util.h b/tools/perf/ui/util.h
similarity index 100%
rename from tools/perf/util/ui/util.h
rename to tools/perf/ui/util.h
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 08c6d13..8069dfb 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -18,6 +18,403 @@
 
 const char 	*disassembler_style;
 
+static struct ins *ins__find(const char *name);
+static int disasm_line__parse(char *line, char **namep, char **rawp);
+
+static void ins__delete(struct ins_operands *ops)
+{
+	free(ops->source.raw);
+	free(ops->source.name);
+	free(ops->target.raw);
+	free(ops->target.name);
+}
+
+static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
+			      struct ins_operands *ops)
+{
+	return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
+}
+
+int ins__scnprintf(struct ins *ins, char *bf, size_t size,
+		  struct ins_operands *ops)
+{
+	if (ins->ops->scnprintf)
+		return ins->ops->scnprintf(ins, bf, size, ops);
+
+	return ins__raw_scnprintf(ins, bf, size, ops);
+}
+
+static int call__parse(struct ins_operands *ops)
+{
+	char *endptr, *tok, *name;
+
+	ops->target.addr = strtoull(ops->raw, &endptr, 16);
+
+	name = strchr(endptr, '<');
+	if (name == NULL)
+		goto indirect_call;
+
+	name++;
+
+	tok = strchr(name, '>');
+	if (tok == NULL)
+		return -1;
+
+	*tok = '\0';
+	ops->target.name = strdup(name);
+	*tok = '>';
+
+	return ops->target.name == NULL ? -1 : 0;
+
+indirect_call:
+	tok = strchr(endptr, '(');
+	if (tok != NULL) {
+		ops->target.addr = 0;
+		return 0;
+	}
+
+	tok = strchr(endptr, '*');
+	if (tok == NULL)
+		return -1;
+
+	ops->target.addr = strtoull(tok + 1, NULL, 16);
+	return 0;
+}
+
+static int call__scnprintf(struct ins *ins, char *bf, size_t size,
+			   struct ins_operands *ops)
+{
+	if (ops->target.name)
+		return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
+
+	if (ops->target.addr == 0)
+		return ins__raw_scnprintf(ins, bf, size, ops);
+
+	return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
+}
+
+static struct ins_ops call_ops = {
+	.parse	   = call__parse,
+	.scnprintf = call__scnprintf,
+};
+
+bool ins__is_call(const struct ins *ins)
+{
+	return ins->ops == &call_ops;
+}
+
+static int jump__parse(struct ins_operands *ops)
+{
+	const char *s = strchr(ops->raw, '+');
+
+	ops->target.addr = strtoll(ops->raw, NULL, 16);
+
+	if (s++ != NULL)
+		ops->target.offset = strtoll(s, NULL, 16);
+	else
+		ops->target.offset = UINT64_MAX;
+
+	return 0;
+}
+
+static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
+			   struct ins_operands *ops)
+{
+	return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
+}
+
+static struct ins_ops jump_ops = {
+	.parse	   = jump__parse,
+	.scnprintf = jump__scnprintf,
+};
+
+bool ins__is_jump(const struct ins *ins)
+{
+	return ins->ops == &jump_ops;
+}
+
+static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
+{
+	char *endptr, *name, *t;
+
+	if (strstr(raw, "(%rip)") == NULL)
+		return 0;
+
+	*addrp = strtoull(comment, &endptr, 16);
+	name = strchr(endptr, '<');
+	if (name == NULL)
+		return -1;
+
+	name++;
+
+	t = strchr(name, '>');
+	if (t == NULL)
+		return 0;
+
+	*t = '\0';
+	*namep = strdup(name);
+	*t = '>';
+
+	return 0;
+}
+
+static int lock__parse(struct ins_operands *ops)
+{
+	char *name;
+
+	ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
+	if (ops->locked.ops == NULL)
+		return 0;
+
+	if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
+		goto out_free_ops;
+
+        ops->locked.ins = ins__find(name);
+        if (ops->locked.ins == NULL)
+                goto out_free_ops;
+
+        if (!ops->locked.ins->ops)
+                return 0;
+
+        if (ops->locked.ins->ops->parse)
+                ops->locked.ins->ops->parse(ops->locked.ops);
+
+	return 0;
+
+out_free_ops:
+	free(ops->locked.ops);
+	ops->locked.ops = NULL;
+	return 0;
+}
+
+static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
+			   struct ins_operands *ops)
+{
+	int printed;
+
+	if (ops->locked.ins == NULL)
+		return ins__raw_scnprintf(ins, bf, size, ops);
+
+	printed = scnprintf(bf, size, "%-6.6s ", ins->name);
+	return printed + ins__scnprintf(ops->locked.ins, bf + printed,
+					size - printed, ops->locked.ops);
+}
+
+static void lock__delete(struct ins_operands *ops)
+{
+	free(ops->locked.ops);
+	free(ops->target.raw);
+	free(ops->target.name);
+}
+
+static struct ins_ops lock_ops = {
+	.free	   = lock__delete,
+	.parse	   = lock__parse,
+	.scnprintf = lock__scnprintf,
+};
+
+static int mov__parse(struct ins_operands *ops)
+{
+	char *s = strchr(ops->raw, ','), *target, *comment, prev;
+
+	if (s == NULL)
+		return -1;
+
+	*s = '\0';
+	ops->source.raw = strdup(ops->raw);
+	*s = ',';
+	
+	if (ops->source.raw == NULL)
+		return -1;
+
+	target = ++s;
+
+	while (s[0] != '\0' && !isspace(s[0]))
+		++s;
+	prev = *s;
+	*s = '\0';
+
+	ops->target.raw = strdup(target);
+	*s = prev;
+
+	if (ops->target.raw == NULL)
+		goto out_free_source;
+
+	comment = strchr(s, '#');
+	if (comment == NULL)
+		return 0;
+
+	while (comment[0] != '\0' && isspace(comment[0]))
+		++comment;
+
+	comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
+	comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
+
+	return 0;
+
+out_free_source:
+	free(ops->source.raw);
+	ops->source.raw = NULL;
+	return -1;
+}
+
+static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
+			   struct ins_operands *ops)
+{
+	return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
+			 ops->source.name ?: ops->source.raw,
+			 ops->target.name ?: ops->target.raw);
+}
+
+static struct ins_ops mov_ops = {
+	.parse	   = mov__parse,
+	.scnprintf = mov__scnprintf,
+};
+
+static int dec__parse(struct ins_operands *ops)
+{
+	char *target, *comment, *s, prev;
+
+	target = s = ops->raw;
+
+	while (s[0] != '\0' && !isspace(s[0]))
+		++s;
+	prev = *s;
+	*s = '\0';
+
+	ops->target.raw = strdup(target);
+	*s = prev;
+
+	if (ops->target.raw == NULL)
+		return -1;
+
+	comment = strchr(s, '#');
+	if (comment == NULL)
+		return 0;
+
+	while (comment[0] != '\0' && isspace(comment[0]))
+		++comment;
+
+	comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
+
+	return 0;
+}
+
+static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
+			   struct ins_operands *ops)
+{
+	return scnprintf(bf, size, "%-6.6s %s", ins->name,
+			 ops->target.name ?: ops->target.raw);
+}
+
+static struct ins_ops dec_ops = {
+	.parse	   = dec__parse,
+	.scnprintf = dec__scnprintf,
+};
+
+static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
+			  struct ins_operands *ops __used)
+{
+	return scnprintf(bf, size, "%-6.6s", "nop");
+}
+
+static struct ins_ops nop_ops = {
+	.scnprintf = nop__scnprintf,
+};
+
+/*
+ * Must be sorted by name!
+ */
+static struct ins instructions[] = {
+	{ .name = "add",   .ops  = &mov_ops, },
+	{ .name = "addl",  .ops  = &mov_ops, },
+	{ .name = "addq",  .ops  = &mov_ops, },
+	{ .name = "addw",  .ops  = &mov_ops, },
+	{ .name = "and",   .ops  = &mov_ops, },
+	{ .name = "bts",   .ops  = &mov_ops, },
+	{ .name = "call",  .ops  = &call_ops, },
+	{ .name = "callq", .ops  = &call_ops, },
+	{ .name = "cmp",   .ops  = &mov_ops, },
+	{ .name = "cmpb",  .ops  = &mov_ops, },
+	{ .name = "cmpl",  .ops  = &mov_ops, },
+	{ .name = "cmpq",  .ops  = &mov_ops, },
+	{ .name = "cmpw",  .ops  = &mov_ops, },
+	{ .name = "cmpxch", .ops  = &mov_ops, },
+	{ .name = "dec",   .ops  = &dec_ops, },
+	{ .name = "decl",  .ops  = &dec_ops, },
+	{ .name = "imul",  .ops  = &mov_ops, },
+	{ .name = "inc",   .ops  = &dec_ops, },
+	{ .name = "incl",  .ops  = &dec_ops, },
+	{ .name = "ja",	   .ops  = &jump_ops, },
+	{ .name = "jae",   .ops  = &jump_ops, },
+	{ .name = "jb",	   .ops  = &jump_ops, },
+	{ .name = "jbe",   .ops  = &jump_ops, },
+	{ .name = "jc",	   .ops  = &jump_ops, },
+	{ .name = "jcxz",  .ops  = &jump_ops, },
+	{ .name = "je",	   .ops  = &jump_ops, },
+	{ .name = "jecxz", .ops  = &jump_ops, },
+	{ .name = "jg",	   .ops  = &jump_ops, },
+	{ .name = "jge",   .ops  = &jump_ops, },
+	{ .name = "jl",    .ops  = &jump_ops, },
+	{ .name = "jle",   .ops  = &jump_ops, },
+	{ .name = "jmp",   .ops  = &jump_ops, },
+	{ .name = "jmpq",  .ops  = &jump_ops, },
+	{ .name = "jna",   .ops  = &jump_ops, },
+	{ .name = "jnae",  .ops  = &jump_ops, },
+	{ .name = "jnb",   .ops  = &jump_ops, },
+	{ .name = "jnbe",  .ops  = &jump_ops, },
+	{ .name = "jnc",   .ops  = &jump_ops, },
+	{ .name = "jne",   .ops  = &jump_ops, },
+	{ .name = "jng",   .ops  = &jump_ops, },
+	{ .name = "jnge",  .ops  = &jump_ops, },
+	{ .name = "jnl",   .ops  = &jump_ops, },
+	{ .name = "jnle",  .ops  = &jump_ops, },
+	{ .name = "jno",   .ops  = &jump_ops, },
+	{ .name = "jnp",   .ops  = &jump_ops, },
+	{ .name = "jns",   .ops  = &jump_ops, },
+	{ .name = "jnz",   .ops  = &jump_ops, },
+	{ .name = "jo",	   .ops  = &jump_ops, },
+	{ .name = "jp",	   .ops  = &jump_ops, },
+	{ .name = "jpe",   .ops  = &jump_ops, },
+	{ .name = "jpo",   .ops  = &jump_ops, },
+	{ .name = "jrcxz", .ops  = &jump_ops, },
+	{ .name = "js",	   .ops  = &jump_ops, },
+	{ .name = "jz",	   .ops  = &jump_ops, },
+	{ .name = "lea",   .ops  = &mov_ops, },
+	{ .name = "lock",  .ops  = &lock_ops, },
+	{ .name = "mov",   .ops  = &mov_ops, },
+	{ .name = "movb",  .ops  = &mov_ops, },
+	{ .name = "movdqa",.ops  = &mov_ops, },
+	{ .name = "movl",  .ops  = &mov_ops, },
+	{ .name = "movq",  .ops  = &mov_ops, },
+	{ .name = "movslq", .ops  = &mov_ops, },
+	{ .name = "movzbl", .ops  = &mov_ops, },
+	{ .name = "movzwl", .ops  = &mov_ops, },
+	{ .name = "nop",   .ops  = &nop_ops, },
+	{ .name = "nopl",  .ops  = &nop_ops, },
+	{ .name = "nopw",  .ops  = &nop_ops, },
+	{ .name = "or",    .ops  = &mov_ops, },
+	{ .name = "orl",   .ops  = &mov_ops, },
+	{ .name = "test",  .ops  = &mov_ops, },
+	{ .name = "testb", .ops  = &mov_ops, },
+	{ .name = "testl", .ops  = &mov_ops, },
+	{ .name = "xadd",  .ops  = &mov_ops, },
+};
+
+static int ins__cmp(const void *name, const void *insp)
+{
+	const struct ins *ins = insp;
+
+	return strcmp(name, ins->name);
+}
+
+static struct ins *ins__find(const char *name)
+{
+	const int nmemb = ARRAY_SIZE(instructions);
+
+	return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
+}
+
 int symbol__annotate_init(struct map *map __used, struct symbol *sym)
 {
 	struct annotation *notes = symbol__annotation(sym);
@@ -28,7 +425,7 @@
 int symbol__alloc_hist(struct symbol *sym)
 {
 	struct annotation *notes = symbol__annotation(sym);
-	const size_t size = sym->end - sym->start + 1;
+	const size_t size = symbol__size(sym);
 	size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
 
 	notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
@@ -78,31 +475,110 @@
 	return 0;
 }
 
-static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
+static void disasm_line__init_ins(struct disasm_line *dl)
 {
-	struct objdump_line *self = malloc(sizeof(*self) + privsize);
+	dl->ins = ins__find(dl->name);
 
-	if (self != NULL) {
-		self->offset = offset;
-		self->line = line;
+	if (dl->ins == NULL)
+		return;
+
+	if (!dl->ins->ops)
+		return;
+
+	if (dl->ins->ops->parse)
+		dl->ins->ops->parse(&dl->ops);
+}
+
+static int disasm_line__parse(char *line, char **namep, char **rawp)
+{
+	char *name = line, tmp;
+
+	while (isspace(name[0]))
+		++name;
+
+	if (name[0] == '\0')
+		return -1;
+
+	*rawp = name + 1;
+
+	while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
+		++*rawp;
+
+	tmp = (*rawp)[0];
+	(*rawp)[0] = '\0';
+	*namep = strdup(name);
+
+	if (*namep == NULL)
+		goto out_free_name;
+
+	(*rawp)[0] = tmp;
+
+	if ((*rawp)[0] != '\0') {
+		(*rawp)++;
+		while (isspace((*rawp)[0]))
+			++(*rawp);
 	}
 
-	return self;
+	return 0;
+
+out_free_name:
+	free(*namep);
+	*namep = NULL;
+	return -1;
 }
 
-void objdump_line__free(struct objdump_line *self)
+static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
 {
-	free(self->line);
-	free(self);
+	struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
+
+	if (dl != NULL) {
+		dl->offset = offset;
+		dl->line = strdup(line);
+		if (dl->line == NULL)
+			goto out_delete;
+
+		if (offset != -1) {
+			if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
+				goto out_free_line;
+
+			disasm_line__init_ins(dl);
+		}
+	}
+
+	return dl;
+
+out_free_line:
+	free(dl->line);
+out_delete:
+	free(dl);
+	return NULL;
 }
 
-static void objdump__add_line(struct list_head *head, struct objdump_line *line)
+void disasm_line__free(struct disasm_line *dl)
+{
+	free(dl->line);
+	free(dl->name);
+	if (dl->ins && dl->ins->ops->free)
+		dl->ins->ops->free(&dl->ops);
+	else
+		ins__delete(&dl->ops);
+	free(dl);
+}
+
+int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
+{
+	if (raw || !dl->ins)
+		return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);
+
+	return ins__scnprintf(dl->ins, bf, size, &dl->ops);
+}
+
+static void disasm__add(struct list_head *head, struct disasm_line *line)
 {
 	list_add_tail(&line->node, head);
 }
 
-struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
-					       struct objdump_line *pos)
+struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
 {
 	list_for_each_entry_continue(pos, head, node)
 		if (pos->offset >= 0)
@@ -111,15 +587,14 @@
 	return NULL;
 }
 
-static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
-			       int evidx, u64 len, int min_pcnt,
-			       int printed, int max_lines,
-			       struct objdump_line *queue)
+static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
+		      int evidx, u64 len, int min_pcnt, int printed,
+		      int max_lines, struct disasm_line *queue)
 {
 	static const char *prev_line;
 	static const char *prev_color;
 
-	if (oline->offset != -1) {
+	if (dl->offset != -1) {
 		const char *path = NULL;
 		unsigned int hits = 0;
 		double percent = 0.0;
@@ -127,10 +602,11 @@
 		struct annotation *notes = symbol__annotation(sym);
 		struct source_line *src_line = notes->src->lines;
 		struct sym_hist *h = annotation__histogram(notes, evidx);
-		s64 offset = oline->offset;
-		struct objdump_line *next;
+		s64 offset = dl->offset;
+		const u64 addr = start + offset;
+		struct disasm_line *next;
 
-		next = objdump__get_next_ip_line(&notes->src->source, oline);
+		next = disasm__get_next_ip_line(&notes->src->source, dl);
 
 		while (offset < (s64)len &&
 		       (next == NULL || offset < next->offset)) {
@@ -155,9 +631,9 @@
 
 		if (queue != NULL) {
 			list_for_each_entry_from(queue, &notes->src->source, node) {
-				if (queue == oline)
+				if (queue == dl)
 					break;
-				objdump_line__print(queue, sym, evidx, len,
+				disasm_line__print(queue, sym, start, evidx, len,
 						    0, 0, 1, NULL);
 			}
 		}
@@ -180,17 +656,18 @@
 
 		color_fprintf(stdout, color, " %7.2f", percent);
 		printf(" :	");
-		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line);
+		color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);
+		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
 	} else if (max_lines && printed >= max_lines)
 		return 1;
 	else {
 		if (queue)
 			return -1;
 
-		if (!*oline->line)
+		if (!*dl->line)
 			printf("         :\n");
 		else
-			printf("         :	%s\n", oline->line);
+			printf("         :	%s\n", dl->line);
 	}
 
 	return 0;
@@ -200,8 +677,8 @@
 				      FILE *file, size_t privsize)
 {
 	struct annotation *notes = symbol__annotation(sym);
-	struct objdump_line *objdump_line;
-	char *line = NULL, *tmp, *tmp2, *c;
+	struct disasm_line *dl;
+	char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
 	size_t line_len;
 	s64 line_ip, offset = -1;
 
@@ -219,6 +696,7 @@
 		*c = 0;
 
 	line_ip = -1;
+	parsed_line = line;
 
 	/*
 	 * Strip leading spaces:
@@ -246,14 +724,17 @@
 		offset = line_ip - start;
 		if (offset < 0 || (u64)line_ip > end)
 			offset = -1;
+		else
+			parsed_line = tmp2 + 1;
 	}
 
-	objdump_line = objdump_line__new(offset, line, privsize);
-	if (objdump_line == NULL) {
-		free(line);
+	dl = disasm_line__new(offset, parsed_line, privsize);
+	free(line);
+
+	if (dl == NULL)
 		return -1;
-	}
-	objdump__add_line(&notes->src->source, objdump_line);
+
+	disasm__add(&notes->src->source, dl);
 
 	return 0;
 }
@@ -476,7 +957,7 @@
 {
 	struct annotation *notes = symbol__annotation(sym);
 	struct sym_hist *h = annotation__histogram(notes, evidx);
-	u64 len = sym->end - sym->start, offset;
+	u64 len = symbol__size(sym), offset;
 
 	for (offset = 0; offset < len; ++offset)
 		if (h->addr[offset] != 0)
@@ -492,7 +973,8 @@
 	struct dso *dso = map->dso;
 	const char *filename = dso->long_name, *d_filename;
 	struct annotation *notes = symbol__annotation(sym);
-	struct objdump_line *pos, *queue = NULL;
+	struct disasm_line *pos, *queue = NULL;
+	u64 start = map__rip_2objdump(map, sym->start);
 	int printed = 2, queue_len = 0;
 	int more = 0;
 	u64 len;
@@ -502,7 +984,7 @@
 	else
 		d_filename = basename(filename);
 
-	len = sym->end - sym->start;
+	len = symbol__size(sym);
 
 	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);
 	printf("------------------------------------------------\n");
@@ -516,8 +998,9 @@
 			queue_len = 0;
 		}
 
-		switch (objdump_line__print(pos, sym, evidx, len, min_pcnt,
-					    printed, max_lines, queue)) {
+		switch (disasm_line__print(pos, sym, start, evidx, len,
+					    min_pcnt, printed, max_lines,
+					    queue)) {
 		case 0:
 			++printed;
 			if (context) {
@@ -561,7 +1044,7 @@
 {
 	struct annotation *notes = symbol__annotation(sym);
 	struct sym_hist *h = annotation__histogram(notes, evidx);
-	int len = sym->end - sym->start, offset;
+	int len = symbol__size(sym), offset;
 
 	h->sum = 0;
 	for (offset = 0; offset < len; ++offset) {
@@ -570,16 +1053,44 @@
 	}
 }
 
-void objdump_line_list__purge(struct list_head *head)
+void disasm__purge(struct list_head *head)
 {
-	struct objdump_line *pos, *n;
+	struct disasm_line *pos, *n;
 
 	list_for_each_entry_safe(pos, n, head, node) {
 		list_del(&pos->node);
-		objdump_line__free(pos);
+		disasm_line__free(pos);
 	}
 }
 
+static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
+{
+	size_t printed;
+
+	if (dl->offset == -1)
+		return fprintf(fp, "%s\n", dl->line);
+
+	printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
+
+	if (dl->ops.raw[0] != '\0') {
+		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
+				   dl->ops.raw);
+	}
+
+	return printed + fprintf(fp, "\n");
+}
+
+size_t disasm__fprintf(struct list_head *head, FILE *fp)
+{
+	struct disasm_line *pos;
+	size_t printed = 0;
+
+	list_for_each_entry(pos, head, node)
+		printed += disasm_line__fprintf(pos, fp);
+
+	return printed;
+}
+
 int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
 			 bool print_lines, bool full_paths, int min_pcnt,
 			 int max_lines)
@@ -592,7 +1103,7 @@
 	if (symbol__annotate(sym, map, 0) < 0)
 		return -1;
 
-	len = sym->end - sym->start;
+	len = symbol__size(sym);
 
 	if (print_lines) {
 		symbol__get_source_line(sym, map, evidx, &source_line,
@@ -605,7 +1116,7 @@
 	if (print_lines)
 		symbol__free_source_line(sym, len);
 
-	objdump_line_list__purge(&symbol__annotation(sym)->src->source);
+	disasm__purge(&symbol__annotation(sym)->src->source);
 
 	return 0;
 }
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index efa5dc8..78a5692 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -2,20 +2,69 @@
 #define __PERF_ANNOTATE_H
 
 #include <stdbool.h>
+#include <stdint.h>
 #include "types.h"
 #include "symbol.h"
 #include <linux/list.h>
 #include <linux/rbtree.h>
 
-struct objdump_line {
-	struct list_head node;
-	s64		 offset;
-	char		 *line;
+struct ins;
+
+struct ins_operands {
+	char	*raw;
+	struct {
+		char	*raw;
+		char	*name;
+		u64	addr;
+		u64	offset;
+	} target;
+	union {
+		struct {
+			char	*raw;
+			char	*name;
+			u64	addr;
+		} source;
+		struct {
+			struct ins *ins;
+			struct ins_operands *ops;
+		} locked;
+	};
 };
 
-void objdump_line__free(struct objdump_line *self);
-struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
-					       struct objdump_line *pos);
+struct ins_ops {
+	void (*free)(struct ins_operands *ops);
+	int (*parse)(struct ins_operands *ops);
+	int (*scnprintf)(struct ins *ins, char *bf, size_t size,
+			 struct ins_operands *ops);
+};
+
+struct ins {
+	const char     *name;
+	struct ins_ops *ops;
+};
+
+bool ins__is_jump(const struct ins *ins);
+bool ins__is_call(const struct ins *ins);
+int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
+
+struct disasm_line {
+	struct list_head    node;
+	s64		    offset;
+	char		    *line;
+	char		    *name;
+	struct ins	    *ins;
+	struct ins_operands ops;
+};
+
+static inline bool disasm_line__has_offset(const struct disasm_line *dl)
+{
+	return dl->ops.target.offset != UINT64_MAX;
+}
+
+void disasm_line__free(struct disasm_line *dl);
+struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
+int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
+size_t disasm__fprintf(struct list_head *head, FILE *fp);
 
 struct sym_hist {
 	u64		sum;
@@ -32,7 +81,7 @@
  *
  * @histogram: Array of addr hit histograms per event being monitored
  * @lines: If 'print_lines' is specified, per source code line percentages
- * @source: source parsed from objdump -dS
+ * @source: source parsed from a disassembler like objdump -dS
  *
  * lines is allocated, percentages calculated and all sorted by percentage
  * when the annotation is about to be presented, so the percentages are for
@@ -82,7 +131,7 @@
 			    int context);
 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
-void objdump_line_list__purge(struct list_head *head);
+void disasm__purge(struct list_head *head);
 
 int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
 			 bool print_lines, bool full_paths, int min_pcnt,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index dff9c7a..fd9a594 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -65,6 +65,8 @@
 	.mmap	= perf_event__process_mmap,
 	.fork	= perf_event__process_task,
 	.exit	= perf_event__exit_del_thread,
+	.attr		 = perf_event__process_attr,
+	.build_id	 = perf_event__process_build_id,
 };
 
 char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 8dd224d..cff18c6 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -33,7 +33,7 @@
 
 extern int use_browser;
 
-#ifdef NO_NEWT_SUPPORT
+#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
 static inline void setup_browser(bool fallback_to_pager)
 {
 	if (fallback_to_pager)
@@ -43,19 +43,29 @@
 #else
 void setup_browser(bool fallback_to_pager);
 void exit_browser(bool wait_for_ok);
+
+#ifdef NO_NEWT_SUPPORT
+static inline int ui__init(void)
+{
+	return -1;
+}
+static inline void ui__exit(bool wait_for_ok __used) {}
+#else
+int ui__init(void);
+void ui__exit(bool wait_for_ok);
 #endif
 
 #ifdef NO_GTK2_SUPPORT
-static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager)
+static inline int perf_gtk__init(void)
 {
-	if (fallback_to_pager)
-		setup_pager();
+	return -1;
 }
-static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {}
+static inline void perf_gtk__exit(bool wait_for_ok __used) {}
 #else
-void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager);
-void perf_gtk_exit_browser(bool wait_for_ok);
+int perf_gtk__init(void);
+void perf_gtk__exit(bool wait_for_ok);
 #endif
+#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
 
 char *alias_lookup(const char *alias);
 int split_cmdline(char *cmdline, const char ***argv);
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 26817da..efb1fce 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -11,6 +11,7 @@
 #include "event.h"
 #include "debug.h"
 #include "util.h"
+#include "target.h"
 
 int verbose;
 bool dump_trace = false, quiet = false;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index f2ce88d0..6bebe7f 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -26,7 +26,7 @@
 #else
 extern char ui_helpline__last_msg[];
 int ui_helpline__show_help(const char *format, va_list ap);
-#include "ui/progress.h"
+#include "../ui/progress.h"
 int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
 #endif
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 1986d80..4ac5f5a 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -11,6 +11,7 @@
 #include <poll.h>
 #include "cpumap.h"
 #include "thread_map.h"
+#include "target.h"
 #include "evlist.h"
 #include "evsel.h"
 #include <unistd.h>
@@ -599,18 +600,21 @@
 	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
 }
 
-int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
-			     const char *target_tid, uid_t uid, const char *cpu_list)
+int perf_evlist__create_maps(struct perf_evlist *evlist,
+			     struct perf_target *target)
 {
-	evlist->threads = thread_map__new_str(target_pid, target_tid, uid);
+	evlist->threads = thread_map__new_str(target->pid, target->tid,
+					      target->uid);
 
 	if (evlist->threads == NULL)
 		return -1;
 
-	if (uid != UINT_MAX || (cpu_list == NULL && target_tid))
+	if (perf_target__has_task(target))
+		evlist->cpus = cpu_map__dummy_new();
+	else if (!perf_target__has_cpu(target) && !target->uses_mmap)
 		evlist->cpus = cpu_map__dummy_new();
 	else
-		evlist->cpus = cpu_map__new(cpu_list);
+		evlist->cpus = cpu_map__new(target->cpu_list);
 
 	if (evlist->cpus == NULL)
 		goto out_delete_threads;
@@ -827,7 +831,7 @@
 		exit(-1);
 	}
 
-	if (!opts->system_wide && !opts->target_tid && !opts->target_pid)
+	if (perf_target__none(&opts->target))
 		evlist->threads->map[0] = evlist->workload.pid;
 
 	close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 21f1c9e..58abb63 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -106,8 +106,8 @@
 	evlist->threads	= threads;
 }
 
-int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
-			     const char *tid, uid_t uid, const char *cpu_list);
+int perf_evlist__create_maps(struct perf_evlist *evlist,
+			     struct perf_target *target);
 void perf_evlist__delete_maps(struct perf_evlist *evlist);
 int perf_evlist__set_filters(struct perf_evlist *evlist);
 
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8c13dbc..57e4ce5 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -14,6 +14,7 @@
 #include "util.h"
 #include "cpumap.h"
 #include "thread_map.h"
+#include "target.h"
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
@@ -69,6 +70,7 @@
 	struct perf_event_attr *attr = &evsel->attr;
 	int track = !evsel->idx; /* only the first counter needs these */
 
+	attr->disabled = 1;
 	attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
 	attr->inherit	    = !opts->no_inherit;
 	attr->read_format   = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -106,15 +108,15 @@
 	if (opts->call_graph)
 		attr->sample_type	|= PERF_SAMPLE_CALLCHAIN;
 
-	if (opts->system_wide)
+	if (perf_target__has_cpu(&opts->target))
 		attr->sample_type	|= PERF_SAMPLE_CPU;
 
 	if (opts->period)
 		attr->sample_type	|= PERF_SAMPLE_PERIOD;
 
 	if (!opts->sample_id_all_missing &&
-	    (opts->sample_time || opts->system_wide ||
-	     !opts->no_inherit || opts->cpu_list))
+	    (opts->sample_time || !opts->no_inherit ||
+	     perf_target__has_cpu(&opts->target)))
 		attr->sample_type	|= PERF_SAMPLE_TIME;
 
 	if (opts->raw_samples) {
@@ -135,9 +137,8 @@
 	attr->mmap = track;
 	attr->comm = track;
 
-	if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
+	if (perf_target__none(&opts->target) &&
 	    (!opts->group || evsel == first)) {
-		attr->disabled = 1;
 		attr->enable_on_exec = 1;
 	}
 }
@@ -461,10 +462,7 @@
 	 * used for cross-endian analysis. See git commit 65014ab3
 	 * for why this goofiness is needed.
 	 */
-	union {
-		u64 val64;
-		u32 val32[2];
-	} u;
+	union u64_swap u;
 
 	memset(data, 0, sizeof(*data));
 	data->cpu = data->pid = data->tid = -1;
@@ -607,10 +605,7 @@
 	 * used for cross-endian analysis. See git commit 65014ab3
 	 * for why this goofiness is needed.
 	 */
-	union {
-		u64 val64;
-		u32 val32[2];
-	} u;
+	union u64_swap u;
 
 	array = event->sample.array;
 
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/util/gtk/browser.c
deleted file mode 100644
index 258352a..0000000
--- a/tools/perf/util/gtk/browser.c
+++ /dev/null
@@ -1,189 +0,0 @@
-#include "../evlist.h"
-#include "../cache.h"
-#include "../evsel.h"
-#include "../sort.h"
-#include "../hist.h"
-#include "gtk.h"
-
-#include <signal.h>
-
-#define MAX_COLUMNS			32
-
-void perf_gtk_setup_browser(int argc, const char *argv[],
-			    bool fallback_to_pager __used)
-{
-	gtk_init(&argc, (char ***)&argv);
-}
-
-void perf_gtk_exit_browser(bool wait_for_ok __used)
-{
-	gtk_main_quit();
-}
-
-static void perf_gtk_signal(int sig)
-{
-	psignal(sig, "perf");
-	gtk_main_quit();
-}
-
-static void perf_gtk_resize_window(GtkWidget *window)
-{
-	GdkRectangle rect;
-	GdkScreen *screen;
-	int monitor;
-	int height;
-	int width;
-
-	screen = gtk_widget_get_screen(window);
-
-	monitor = gdk_screen_get_monitor_at_window(screen, window->window);
-
-	gdk_screen_get_monitor_geometry(screen, monitor, &rect);
-
-	width	= rect.width * 3 / 4;
-	height	= rect.height * 3 / 4;
-
-	gtk_window_resize(GTK_WINDOW(window), width, height);
-}
-
-static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists)
-{
-	GType col_types[MAX_COLUMNS];
-	GtkCellRenderer *renderer;
-	struct sort_entry *se;
-	GtkListStore *store;
-	struct rb_node *nd;
-	u64 total_period;
-	GtkWidget *view;
-	int col_idx;
-	int nr_cols;
-
-	nr_cols = 0;
-
-	/* The percentage column */
-	col_types[nr_cols++] = G_TYPE_STRING;
-
-	list_for_each_entry(se, &hist_entry__sort_list, list) {
-		if (se->elide)
-			continue;
-
-		col_types[nr_cols++] = G_TYPE_STRING;
-	}
-
-	store = gtk_list_store_newv(nr_cols, col_types);
-
-	view = gtk_tree_view_new();
-
-	renderer = gtk_cell_renderer_text_new();
-
-	col_idx = 0;
-
-	/* The percentage column */
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-						    -1, "Overhead (%)",
-						    renderer, "text",
-						    col_idx++, NULL);
-
-	list_for_each_entry(se, &hist_entry__sort_list, list) {
-		if (se->elide)
-			continue;
-
-		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-							    -1, se->se_header,
-							    renderer, "text",
-							    col_idx++, NULL);
-	}
-
-	gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
-
-	g_object_unref(GTK_TREE_MODEL(store));
-
-	total_period = hists->stats.total_period;
-
-	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
-		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-		GtkTreeIter iter;
-		double percent;
-		char s[512];
-
-		if (h->filtered)
-			continue;
-
-		gtk_list_store_append(store, &iter);
-
-		col_idx = 0;
-
-		percent = (h->period * 100.0) / total_period;
-
-		snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
-
-		gtk_list_store_set(store, &iter, col_idx++, s, -1);
-
-		list_for_each_entry(se, &hist_entry__sort_list, list) {
-			if (se->elide)
-				continue;
-
-			se->se_snprintf(h, s, ARRAY_SIZE(s),
-					hists__col_len(hists, se->se_width_idx));
-
-			gtk_list_store_set(store, &iter, col_idx++, s, -1);
-		}
-	}
-
-	gtk_container_add(GTK_CONTAINER(window), view);
-}
-
-int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
-				  const char *help __used,
-				  void (*timer) (void *arg)__used,
-				  void *arg __used, int delay_secs __used)
-{
-	struct perf_evsel *pos;
-	GtkWidget *notebook;
-	GtkWidget *window;
-
-	signal(SIGSEGV, perf_gtk_signal);
-	signal(SIGFPE,  perf_gtk_signal);
-	signal(SIGINT,  perf_gtk_signal);
-	signal(SIGQUIT, perf_gtk_signal);
-	signal(SIGTERM, perf_gtk_signal);
-
-	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
-	gtk_window_set_title(GTK_WINDOW(window), "perf report");
-
-	g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
-
-	notebook = gtk_notebook_new();
-
-	list_for_each_entry(pos, &evlist->entries, node) {
-		struct hists *hists = &pos->hists;
-		const char *evname = event_name(pos);
-		GtkWidget *scrolled_window;
-		GtkWidget *tab_label;
-
-		scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-
-		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
-							GTK_POLICY_AUTOMATIC,
-							GTK_POLICY_AUTOMATIC);
-
-		perf_gtk_show_hists(scrolled_window, hists);
-
-		tab_label = gtk_label_new(evname);
-
-		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
-	}
-
-	gtk_container_add(GTK_CONTAINER(window), notebook);
-
-	gtk_widget_show_all(window);
-
-	perf_gtk_resize_window(window);
-
-	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
-
-	gtk_main();
-
-	return 0;
-}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index c0b70c6..2dd5edf 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -31,21 +31,16 @@
 
 int perf_header__push_event(u64 id, const char *name)
 {
+	struct perf_trace_event_type *nevents;
+
 	if (strlen(name) > MAX_EVENT_NAME)
 		pr_warning("Event %s will be truncated\n", name);
 
-	if (!events) {
-		events = malloc(sizeof(struct perf_trace_event_type));
-		if (events == NULL)
-			return -ENOMEM;
-	} else {
-		struct perf_trace_event_type *nevents;
+	nevents = realloc(events, (event_count + 1) * sizeof(*events));
+	if (nevents == NULL)
+		return -ENOMEM;
+	events = nevents;
 
-		nevents = realloc(events, (event_count + 1) * sizeof(*events));
-		if (nevents == NULL)
-			return -ENOMEM;
-		events = nevents;
-	}
 	memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
 	events[event_count].event_id = id;
 	strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
@@ -442,7 +437,7 @@
 	return ret;
 }
 
-static int write_trace_info(int fd, struct perf_header *h __used,
+static int write_tracing_data(int fd, struct perf_header *h __used,
 			    struct perf_evlist *evlist)
 {
 	return read_tracing_data(fd, &evlist->entries);
@@ -1477,7 +1472,7 @@
 	return err;
 }
 
-static int process_trace_info(struct perf_file_section *section __unused,
+static int process_tracing_data(struct perf_file_section *section __unused,
 			      struct perf_header *ph __unused,
 			      int feat __unused, int fd)
 {
@@ -1513,11 +1508,11 @@
 		.full_only = true }
 
 /* feature_ops not implemented: */
-#define print_trace_info		NULL
-#define print_build_id			NULL
+#define print_tracing_data	NULL
+#define print_build_id		NULL
 
 static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
-	FEAT_OPP(HEADER_TRACE_INFO,	trace_info),
+	FEAT_OPP(HEADER_TRACING_DATA,	tracing_data),
 	FEAT_OPP(HEADER_BUILD_ID,	build_id),
 	FEAT_OPA(HEADER_HOSTNAME,	hostname),
 	FEAT_OPA(HEADER_OSRELEASE,	osrelease),
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 21a6be0..2d42b3e 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -12,7 +12,7 @@
 enum {
 	HEADER_RESERVED		= 0,	/* always cleared */
 	HEADER_FIRST_FEATURE	= 1,
-	HEADER_TRACE_INFO	= 1,
+	HEADER_TRACING_DATA	= 1,
 	HEADER_BUILD_ID,
 
 	HEADER_HOSTNAME,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 9f6d630..1293b5e 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -599,7 +599,7 @@
 	if (chain->ms.sym)
 		ret += fprintf(fp, "%s\n", chain->ms.sym->name);
 	else
-		ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
+		ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
 
 	return ret;
 }
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 2cae9df..cfc64e2 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -138,7 +138,7 @@
 #define K_LEFT -1
 #define K_RIGHT -2
 #else
-#include "ui/keysyms.h"
+#include "../ui/keysyms.h"
 int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
 			     void(*timer)(void *arg), void *arg, int delay_secs);
 
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
new file mode 100644
index 0000000..76b98e2
--- /dev/null
+++ b/tools/perf/util/parse-events-test.c
@@ -0,0 +1,625 @@
+
+#include "parse-events.h"
+#include "evsel.h"
+#include "evlist.h"
+#include "sysfs.h"
+#include "../../../include/linux/hw_breakpoint.h"
+
+#define TEST_ASSERT_VAL(text, cond) \
+do { \
+	if (!(cond)) { \
+		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
+		return -1; \
+	} \
+} while (0)
+
+static int test__checkevent_tracepoint(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong sample_type",
+		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+		evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+	return 0;
+}
+
+static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		TEST_ASSERT_VAL("wrong type",
+			PERF_TYPE_TRACEPOINT == evsel->attr.type);
+		TEST_ASSERT_VAL("wrong sample_type",
+			(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
+			== evsel->attr.sample_type);
+		TEST_ASSERT_VAL("wrong sample_period",
+			1 == evsel->attr.sample_period);
+	}
+	return 0;
+}
+
+static int test__checkevent_raw(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_numeric(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong period",
+			100000 == evsel->attr.sample_period);
+	TEST_ASSERT_VAL("wrong config1",
+			0 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2",
+			1 == evsel->attr.config2);
+	return 0;
+}
+
+static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_genhw(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_breakpoint(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
+					 evsel->attr.bp_type);
+	TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
+					evsel->attr.bp_len);
+	return 0;
+}
+
+static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong bp_type",
+			HW_BREAKPOINT_X == evsel->attr.bp_type);
+	TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
+	return 0;
+}
+
+static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type",
+			PERF_TYPE_BREAKPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong bp_type",
+			HW_BREAKPOINT_R == evsel->attr.bp_type);
+	TEST_ASSERT_VAL("wrong bp_len",
+			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
+	return 0;
+}
+
+static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type",
+			PERF_TYPE_BREAKPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong bp_type",
+			HW_BREAKPOINT_W == evsel->attr.bp_type);
+	TEST_ASSERT_VAL("wrong bp_len",
+			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
+	return 0;
+}
+
+static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_tracepoint(evlist);
+}
+
+static int
+test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		TEST_ASSERT_VAL("wrong exclude_user",
+				!evsel->attr.exclude_user);
+		TEST_ASSERT_VAL("wrong exclude_kernel",
+				evsel->attr.exclude_kernel);
+		TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+		TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	}
+
+	return test__checkevent_tracepoint_multi(evlist);
+}
+
+static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_raw(evlist);
+}
+
+static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_numeric(evlist);
+}
+
+static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+
+	return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+
+	return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_symbolic_alias(evlist);
+}
+
+static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_genhw(evlist);
+}
+
+static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint(evlist);
+}
+
+static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_x(evlist);
+}
+
+static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_r(evlist);
+}
+
+static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_w(evlist);
+}
+
+static int test__checkevent_pmu(struct perf_evlist *evlist)
+{
+
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",    10 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config1",    1 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2",    3 == evsel->attr.config2);
+	TEST_ASSERT_VAL("wrong period",  1000 == evsel->attr.sample_period);
+
+	return 0;
+}
+
+static int test__checkevent_list(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+	/* r1 */
+	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	/* syscalls:sys_enter_open:k */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong sample_type",
+		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+		evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	/* 1:1:hp */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return 0;
+}
+
+static int test__checkevent_pmu_name(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	/* cpu/config=1,name=krava1/u */
+	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
+
+	/* cpu/config=2/" */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",  2 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2"));
+
+	return 0;
+}
+
+struct test__event_st {
+	const char *name;
+	__u32 type;
+	int (*check)(struct perf_evlist *evlist);
+};
+
+static struct test__event_st test__events[] = {
+	[0] = {
+		.name  = "syscalls:sys_enter_open",
+		.check = test__checkevent_tracepoint,
+	},
+	[1] = {
+		.name  = "syscalls:*",
+		.check = test__checkevent_tracepoint_multi,
+	},
+	[2] = {
+		.name  = "r1a",
+		.check = test__checkevent_raw,
+	},
+	[3] = {
+		.name  = "1:1",
+		.check = test__checkevent_numeric,
+	},
+	[4] = {
+		.name  = "instructions",
+		.check = test__checkevent_symbolic_name,
+	},
+	[5] = {
+		.name  = "cycles/period=100000,config2/",
+		.check = test__checkevent_symbolic_name_config,
+	},
+	[6] = {
+		.name  = "faults",
+		.check = test__checkevent_symbolic_alias,
+	},
+	[7] = {
+		.name  = "L1-dcache-load-miss",
+		.check = test__checkevent_genhw,
+	},
+	[8] = {
+		.name  = "mem:0",
+		.check = test__checkevent_breakpoint,
+	},
+	[9] = {
+		.name  = "mem:0:x",
+		.check = test__checkevent_breakpoint_x,
+	},
+	[10] = {
+		.name  = "mem:0:r",
+		.check = test__checkevent_breakpoint_r,
+	},
+	[11] = {
+		.name  = "mem:0:w",
+		.check = test__checkevent_breakpoint_w,
+	},
+	[12] = {
+		.name  = "syscalls:sys_enter_open:k",
+		.check = test__checkevent_tracepoint_modifier,
+	},
+	[13] = {
+		.name  = "syscalls:*:u",
+		.check = test__checkevent_tracepoint_multi_modifier,
+	},
+	[14] = {
+		.name  = "r1a:kp",
+		.check = test__checkevent_raw_modifier,
+	},
+	[15] = {
+		.name  = "1:1:hp",
+		.check = test__checkevent_numeric_modifier,
+	},
+	[16] = {
+		.name  = "instructions:h",
+		.check = test__checkevent_symbolic_name_modifier,
+	},
+	[17] = {
+		.name  = "faults:u",
+		.check = test__checkevent_symbolic_alias_modifier,
+	},
+	[18] = {
+		.name  = "L1-dcache-load-miss:kp",
+		.check = test__checkevent_genhw_modifier,
+	},
+	[19] = {
+		.name  = "mem:0:u",
+		.check = test__checkevent_breakpoint_modifier,
+	},
+	[20] = {
+		.name  = "mem:0:x:k",
+		.check = test__checkevent_breakpoint_x_modifier,
+	},
+	[21] = {
+		.name  = "mem:0:r:hp",
+		.check = test__checkevent_breakpoint_r_modifier,
+	},
+	[22] = {
+		.name  = "mem:0:w:up",
+		.check = test__checkevent_breakpoint_w_modifier,
+	},
+	[23] = {
+		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
+		.check = test__checkevent_list,
+	},
+	[24] = {
+		.name  = "instructions:G",
+		.check = test__checkevent_exclude_host_modifier,
+	},
+	[25] = {
+		.name  = "instructions:H",
+		.check = test__checkevent_exclude_guest_modifier,
+	},
+};
+
+#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
+
+static struct test__event_st test__events_pmu[] = {
+	[0] = {
+		.name  = "cpu/config=10,config1,config2=3,period=1000/u",
+		.check = test__checkevent_pmu,
+	},
+	[1] = {
+		.name  = "cpu/config=1,name=krava/u,cpu/config=2/u",
+		.check = test__checkevent_pmu_name,
+	},
+};
+
+#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \
+			      sizeof(struct test__event_st))
+
+static int test(struct test__event_st *e)
+{
+	struct perf_evlist *evlist;
+	int ret;
+
+	evlist = perf_evlist__new(NULL, NULL);
+	if (evlist == NULL)
+		return -ENOMEM;
+
+	ret = parse_events(evlist, e->name, 0);
+	if (ret) {
+		pr_debug("failed to parse event '%s', err %d\n",
+			 e->name, ret);
+		return ret;
+	}
+
+	ret = e->check(evlist);
+	perf_evlist__delete(evlist);
+
+	return ret;
+}
+
+static int test_events(struct test__event_st *events, unsigned cnt)
+{
+	int ret = 0;
+	unsigned i;
+
+	for (i = 0; i < cnt; i++) {
+		struct test__event_st *e = &events[i];
+
+		pr_debug("running test %d '%s'\n", i, e->name);
+		ret = test(e);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static int test_pmu(void)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	int ret;
+
+	snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/",
+		 sysfs_find_mountpoint());
+
+	ret = stat(path, &st);
+	if (ret)
+		pr_debug("ommiting PMU cpu tests\n");
+	return !ret;
+}
+
+int parse_events__test(void)
+{
+	int ret;
+
+	ret = test_events(test__events, TEST__EVENTS_CNT);
+	if (!ret && test_pmu())
+		ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT);
+
+	return ret;
+}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5b3a0ef..fac7d59 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -23,8 +23,10 @@
 	const char	*alias;
 };
 
-int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
-		       int *idx);
+#ifdef PARSER_DEBUG
+extern int parse_events_debug;
+#endif
+int parse_events_parse(struct list_head *list, int *idx);
 
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -355,20 +357,30 @@
 	return "unknown";
 }
 
-static int add_event(struct list_head *list, int *idx,
+static int add_event(struct list_head **_list, int *idx,
 		     struct perf_event_attr *attr, char *name)
 {
 	struct perf_evsel *evsel;
+	struct list_head *list = *_list;
+
+	if (!list) {
+		list = malloc(sizeof(*list));
+		if (!list)
+			return -ENOMEM;
+		INIT_LIST_HEAD(list);
+	}
 
 	event_attr_init(attr);
 
 	evsel = perf_evsel__new(attr, (*idx)++);
-	if (!evsel)
+	if (!evsel) {
+		free(list);
 		return -ENOMEM;
-
-	list_add_tail(&evsel->node, list);
+	}
 
 	evsel->name = strdup(name);
+	list_add_tail(&evsel->node, list);
+	*_list = list;
 	return 0;
 }
 
@@ -390,7 +402,7 @@
 	return -1;
 }
 
-int parse_events_add_cache(struct list_head *list, int *idx,
+int parse_events_add_cache(struct list_head **list, int *idx,
 			   char *type, char *op_result1, char *op_result2)
 {
 	struct perf_event_attr attr;
@@ -451,7 +463,7 @@
 	return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint(struct list_head *list, int *idx,
+static int add_tracepoint(struct list_head **list, int *idx,
 			  char *sys_name, char *evt_name)
 {
 	struct perf_event_attr attr;
@@ -488,7 +500,7 @@
 	return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint_multi(struct list_head *list, int *idx,
+static int add_tracepoint_multi(struct list_head **list, int *idx,
 				char *sys_name, char *evt_name)
 {
 	char evt_path[MAXPATHLEN];
@@ -519,7 +531,7 @@
 	return ret;
 }
 
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
+int parse_events_add_tracepoint(struct list_head **list, int *idx,
 				char *sys, char *event)
 {
 	int ret;
@@ -563,7 +575,7 @@
 	return 0;
 }
 
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
+int parse_events_add_breakpoint(struct list_head **list, int *idx,
 				void *ptr, char *type)
 {
 	struct perf_event_attr attr;
@@ -593,17 +605,27 @@
 static int config_term(struct perf_event_attr *attr,
 		       struct parse_events__term *term)
 {
-	switch (term->type) {
+#define CHECK_TYPE_VAL(type)					\
+do {								\
+	if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val)	\
+		return -EINVAL;					\
+} while (0)
+
+	switch (term->type_term) {
 	case PARSE_EVENTS__TERM_TYPE_CONFIG:
+		CHECK_TYPE_VAL(NUM);
 		attr->config = term->val.num;
 		break;
 	case PARSE_EVENTS__TERM_TYPE_CONFIG1:
+		CHECK_TYPE_VAL(NUM);
 		attr->config1 = term->val.num;
 		break;
 	case PARSE_EVENTS__TERM_TYPE_CONFIG2:
+		CHECK_TYPE_VAL(NUM);
 		attr->config2 = term->val.num;
 		break;
 	case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
+		CHECK_TYPE_VAL(NUM);
 		attr->sample_period = term->val.num;
 		break;
 	case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
@@ -612,10 +634,15 @@
 		 * attr->branch_sample_type = term->val.num;
 		 */
 		break;
+	case PARSE_EVENTS__TERM_TYPE_NAME:
+		CHECK_TYPE_VAL(STR);
+		break;
 	default:
 		return -EINVAL;
 	}
+
 	return 0;
+#undef CHECK_TYPE_VAL
 }
 
 static int config_attr(struct perf_event_attr *attr,
@@ -630,7 +657,7 @@
 	return 0;
 }
 
-int parse_events_add_numeric(struct list_head *list, int *idx,
+int parse_events_add_numeric(struct list_head **list, int *idx,
 			     unsigned long type, unsigned long config,
 			     struct list_head *head_config)
 {
@@ -648,7 +675,24 @@
 			 (char *) __event_name(type, config));
 }
 
-int parse_events_add_pmu(struct list_head *list, int *idx,
+static int parse_events__is_name_term(struct parse_events__term *term)
+{
+	return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
+}
+
+static char *pmu_event_name(struct perf_event_attr *attr,
+			    struct list_head *head_terms)
+{
+	struct parse_events__term *term;
+
+	list_for_each_entry(term, head_terms, list)
+		if (parse_events__is_name_term(term))
+			return term->val.str;
+
+	return (char *) __event_name(PERF_TYPE_RAW, attr->config);
+}
+
+int parse_events_add_pmu(struct list_head **list, int *idx,
 			 char *name, struct list_head *head_config)
 {
 	struct perf_event_attr attr;
@@ -669,7 +713,8 @@
 	if (perf_pmu__config(pmu, &attr, head_config))
 		return -EINVAL;
 
-	return add_event(list, idx, &attr, (char *) "pmu");
+	return add_event(list, idx, &attr,
+			 pmu_event_name(&attr, head_config));
 }
 
 void parse_events_update_lists(struct list_head *list_event,
@@ -681,7 +726,7 @@
 	 * list, for next event definition.
 	 */
 	list_splice_tail(list_event, list_all);
-	INIT_LIST_HEAD(list_event);
+	free(list_event);
 }
 
 int parse_events_modifier(struct list_head *list, char *str)
@@ -756,10 +801,14 @@
 
 	buffer = parse_events__scan_string(str);
 
-	ret = parse_events_parse(&list, &list_tmp, &idx);
+#ifdef PARSER_DEBUG
+	parse_events_debug = 1;
+#endif
+	ret = parse_events_parse(&list, &idx);
 
 	parse_events__flush_buffer(buffer);
 	parse_events__delete_buffer(buffer);
+	parse_events_lex_destroy();
 
 	if (!ret) {
 		int entries = idx - evlist->nr_entries;
@@ -1015,11 +1064,12 @@
 
 int parse_events__is_hardcoded_term(struct parse_events__term *term)
 {
-	return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX;
+	return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
 }
 
-int parse_events__new_term(struct parse_events__term **_term, int type,
-			   char *config, char *str, long num)
+static int new_term(struct parse_events__term **_term, int type_val,
+		    int type_term, char *config,
+		    char *str, long num)
 {
 	struct parse_events__term *term;
 
@@ -1028,15 +1078,11 @@
 		return -ENOMEM;
 
 	INIT_LIST_HEAD(&term->list);
-	term->type = type;
+	term->type_val  = type_val;
+	term->type_term = type_term;
 	term->config = config;
 
-	switch (type) {
-	case PARSE_EVENTS__TERM_TYPE_CONFIG:
-	case PARSE_EVENTS__TERM_TYPE_CONFIG1:
-	case PARSE_EVENTS__TERM_TYPE_CONFIG2:
-	case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-	case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
+	switch (type_val) {
 	case PARSE_EVENTS__TERM_TYPE_NUM:
 		term->val.num = num;
 		break;
@@ -1051,6 +1097,20 @@
 	return 0;
 }
 
+int parse_events__term_num(struct parse_events__term **term,
+			   int type_term, char *config, long num)
+{
+	return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
+			config, NULL, num);
+}
+
+int parse_events__term_str(struct parse_events__term **term,
+			   int type_term, char *config, char *str)
+{
+	return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
+			config, str, 0);
+}
+
 void parse_events__free_terms(struct list_head *terms)
 {
 	struct parse_events__term *term, *h;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ca069f8..8cac57a 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,7 +4,11 @@
  * Parse symbolic events/counts passed in as options:
  */
 
+#include <linux/list.h>
+#include <stdbool.h>
+#include "types.h"
 #include "../../../include/linux/perf_event.h"
+#include "types.h"
 
 struct list_head;
 struct perf_evsel;
@@ -34,16 +38,18 @@
 #define EVENTS_HELP_MAX (128*1024)
 
 enum {
+	PARSE_EVENTS__TERM_TYPE_NUM,
+	PARSE_EVENTS__TERM_TYPE_STR,
+};
+
+enum {
+	PARSE_EVENTS__TERM_TYPE_USER,
 	PARSE_EVENTS__TERM_TYPE_CONFIG,
 	PARSE_EVENTS__TERM_TYPE_CONFIG1,
 	PARSE_EVENTS__TERM_TYPE_CONFIG2,
+	PARSE_EVENTS__TERM_TYPE_NAME,
 	PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
 	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
-	PARSE_EVENTS__TERM_TYPE_NUM,
-	PARSE_EVENTS__TERM_TYPE_STR,
-
-	PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
-		PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
 };
 
 struct parse_events__term {
@@ -52,35 +58,34 @@
 		char *str;
 		long  num;
 	} val;
-	int type;
-
+	int type_val;
+	int type_term;
 	struct list_head list;
 };
 
 int parse_events__is_hardcoded_term(struct parse_events__term *term);
-int parse_events__new_term(struct parse_events__term **term, int type,
-			   char *config, char *str, long num);
+int parse_events__term_num(struct parse_events__term **_term,
+			   int type_term, char *config, long num);
+int parse_events__term_str(struct parse_events__term **_term,
+			   int type_term, char *config, char *str);
 void parse_events__free_terms(struct list_head *terms);
-int parse_events_modifier(struct list_head *list __used, char *str __used);
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
+int parse_events_modifier(struct list_head *list, char *str);
+int parse_events_add_tracepoint(struct list_head **list, int *idx,
 				char *sys, char *event);
-int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config,
-			 unsigned long config1, unsigned long config2,
-			 char *mod);
-int parse_events_add_numeric(struct list_head *list, int *idx,
+int parse_events_add_numeric(struct list_head **list, int *idx,
 			     unsigned long type, unsigned long config,
 			     struct list_head *head_config);
-int parse_events_add_cache(struct list_head *list, int *idx,
+int parse_events_add_cache(struct list_head **list, int *idx,
 			   char *type, char *op_result1, char *op_result2);
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
+int parse_events_add_breakpoint(struct list_head **list, int *idx,
 				void *ptr, char *type);
-int parse_events_add_pmu(struct list_head *list, int *idx,
+int parse_events_add_pmu(struct list_head **list, int *idx,
 			 char *pmu , struct list_head *head_config);
 void parse_events_update_lists(struct list_head *list_event,
 			       struct list_head *list_all);
 void parse_events_error(struct list_head *list_all,
-			struct list_head *list_event,
 			int *idx, char const *msg);
+int parse_events__test(void);
 
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 1fcf1bb..618a8e7 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -1,5 +1,6 @@
 
 %option prefix="parse_events_"
+%option stack
 
 %{
 #include <errno.h>
@@ -50,6 +51,8 @@
 
 %}
 
+%x mem
+
 num_dec		[0-9]+
 num_hex		0x[a-fA-F0-9]+
 num_raw_hex	[a-fA-F0-9]+
@@ -102,16 +105,16 @@
 config			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
 config1			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
 config2			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
+name			{ return term(PARSE_EVENTS__TERM_TYPE_NAME); }
 period			{ return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
 branch_type		{ return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
 
-mem:			{ return PE_PREFIX_MEM; }
+mem:			{ BEGIN(mem); return PE_PREFIX_MEM; }
 r{num_raw_hex}		{ return raw(); }
 {num_dec}		{ return value(10); }
 {num_hex}		{ return value(16); }
 
 {modifier_event}	{ return str(PE_MODIFIER_EVENT); }
-{modifier_bp}		{ return str(PE_MODIFIER_BP); }
 {name}			{ return str(PE_NAME); }
 "/"			{ return '/'; }
 -			{ return '-'; }
@@ -119,6 +122,25 @@
 :			{ return ':'; }
 =			{ return '='; }
 
+<mem>{
+{modifier_bp}		{ return str(PE_MODIFIER_BP); }
+:			{ return ':'; }
+{num_dec}		{ return value(10); }
+{num_hex}		{ return value(16); }
+	/*
+	 * We need to separate 'mem:' scanner part, in order to get specific
+	 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
+	 * and we'd need to parse it manually. During the escape from <mem>
+	 * state we need to put the escaping char back, so we dont miss it.
+	 */
+.			{ unput(*parse_events_text); BEGIN(INITIAL); }
+	/*
+	 * We destroy the scanner after reaching EOF,
+	 * but anyway just to be sure get back to INIT state.
+	 */
+<<EOF>>			{ BEGIN(INITIAL); }
+}
+
 %%
 
 int parse_events_wrap(void)
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d9637da..362cc59 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,7 +1,6 @@
 
 %name-prefix "parse_events_"
 %parse-param {struct list_head *list_all}
-%parse-param {struct list_head *list_event}
 %parse-param {int *idx}
 
 %{
@@ -41,6 +40,14 @@
 %type <str> PE_MODIFIER_BP
 %type <head> event_config
 %type <term> event_term
+%type <head> event_pmu
+%type <head> event_legacy_symbol
+%type <head> event_legacy_cache
+%type <head> event_legacy_mem
+%type <head> event_legacy_tracepoint
+%type <head> event_legacy_numeric
+%type <head> event_legacy_raw
+%type <head> event_def
 
 %union
 {
@@ -62,13 +69,13 @@
 	 * (there could be more events added for multiple tracepoint
 	 * definitions via '*?'.
 	 */
-	ABORT_ON(parse_events_modifier(list_event, $2));
-	parse_events_update_lists(list_event, list_all);
+	ABORT_ON(parse_events_modifier($1, $2));
+	parse_events_update_lists($1, list_all);
 }
 |
 event_def
 {
-	parse_events_update_lists(list_event, list_all);
+	parse_events_update_lists($1, list_all);
 }
 
 event_def: event_pmu |
@@ -82,71 +89,102 @@
 event_pmu:
 PE_NAME '/' event_config '/'
 {
-	ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));
 	parse_events__free_terms($3);
+	$$ = list;
 }
 
 event_legacy_symbol:
 PE_VALUE_SYM '/' event_config '/'
 {
+	struct list_head *list = NULL;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
+	ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));
 	parse_events__free_terms($3);
+	$$ = list;
 }
 |
 PE_VALUE_SYM sep_slash_dc
 {
+	struct list_head *list = NULL;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
+	ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL));
+	$$ = list;
 }
 
 event_legacy_cache:
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 {
-	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5));
+	$$ = list;
 }
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
-	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL));
+	$$ = list;
 }
 |
 PE_NAME_CACHE_TYPE
 {
-	ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL));
+	$$ = list;
 }
 
 event_legacy_mem:
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 {
-	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4));
+	$$ = list;
 }
 |
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
-	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL));
+	$$ = list;
 }
 
 event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 {
-	ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3));
+	$$ = list;
 }
 
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
-	ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL));
+	$$ = list;
 }
 
 event_legacy_raw:
 PE_RAW
 {
-	ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL));
+	$$ = list;
 }
 
 event_config:
@@ -176,8 +214,8 @@
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
-		 $1, $3, 0));
+	ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER,
+					$1, $3));
 	$$ = term;
 }
 |
@@ -185,8 +223,8 @@
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
-		 $1, NULL, $3));
+	ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+					$1, $3));
 	$$ = term;
 }
 |
@@ -194,8 +232,16 @@
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
-		 $1, NULL, 1));
+	ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+					$1, 1));
+	$$ = term;
+}
+|
+PE_TERM '=' PE_NAME
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__term_str(&term, $1, NULL, $3));
 	$$ = term;
 }
 |
@@ -203,7 +249,7 @@
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3));
+	ABORT_ON(parse_events__term_num(&term, $1, NULL, $3));
 	$$ = term;
 }
 |
@@ -211,7 +257,7 @@
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1));
+	ABORT_ON(parse_events__term_num(&term, $1, NULL, 1));
 	$$ = term;
 }
 
@@ -222,7 +268,6 @@
 %%
 
 void parse_events_error(struct list_head *list_all __used,
-			struct list_head *list_event __used,
 			int *idx __used,
 			char const *msg __used)
 {
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index cb08a11..a119a53 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -225,7 +225,7 @@
 	if (parse_events__is_hardcoded_term(term))
 		return 0;
 
-	if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
+	if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
 		return -EINVAL;
 
 	format = pmu_find_format(formats, term->config);
@@ -246,6 +246,11 @@
 		return -EINVAL;
 	}
 
+	/*
+	 * XXX If we ever decide to go with string values for
+	 * non-hardcoded terms, here's the place to translate
+	 * them into value.
+	 */
 	*vp |= pmu_format_value(format->bits, term->val.num);
 	return 0;
 }
@@ -253,9 +258,9 @@
 static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
 		      struct list_head *head_terms)
 {
-	struct parse_events__term *term, *h;
+	struct parse_events__term *term;
 
-	list_for_each_entry_safe(term, h, head_terms, list)
+	list_for_each_entry(term, head_terms, list)
 		if (pmu_config_term(formats, attr, term))
 			return -EINVAL;
 
@@ -324,49 +329,58 @@
 /* Simulated users input. */
 static struct parse_events__term test_terms[] = {
 	{
-		.config  = (char *) "krava01",
-		.val.num = 15,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava01",
+		.val.num   = 15,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava02",
-		.val.num = 170,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava02",
+		.val.num   = 170,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava03",
-		.val.num = 1,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava03",
+		.val.num   = 1,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava11",
-		.val.num = 27,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava11",
+		.val.num   = 27,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava12",
-		.val.num = 1,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava12",
+		.val.num   = 1,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava13",
-		.val.num = 2,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava13",
+		.val.num   = 2,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava21",
-		.val.num = 119,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava21",
+		.val.num   = 119,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava22",
-		.val.num = 11,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava22",
+		.val.num   = 11,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava23",
-		.val.num = 2,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava23",
+		.val.num   = 2,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 };
 #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8a8ee64..59dccc9 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -44,6 +44,7 @@
 #include "trace-event.h"	/* For __unused */
 #include "probe-event.h"
 #include "probe-finder.h"
+#include "session.h"
 
 #define MAX_CMDLEN 256
 #define MAX_PROBE_ARGS 128
@@ -70,6 +71,8 @@
 }
 
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
+static int convert_name_to_addr(struct perf_probe_event *pev,
+				const char *exec);
 static struct machine machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
@@ -170,6 +173,34 @@
 	return (dso) ? dso->long_name : NULL;
 }
 
+static int init_user_exec(void)
+{
+	int ret = 0;
+
+	symbol_conf.try_vmlinux_path = false;
+	symbol_conf.sort_by_name = true;
+	ret = symbol__init();
+
+	if (ret < 0)
+		pr_debug("Failed to init symbol map.\n");
+
+	return ret;
+}
+
+static int convert_to_perf_probe_point(struct probe_trace_point *tp,
+					struct perf_probe_point *pp)
+{
+	pp->function = strdup(tp->symbol);
+
+	if (pp->function == NULL)
+		return -ENOMEM;
+
+	pp->offset = tp->offset;
+	pp->retprobe = tp->retprobe;
+
+	return 0;
+}
+
 #ifdef DWARF_SUPPORT
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
@@ -224,10 +255,7 @@
 	if (ret <= 0) {
 		pr_debug("Failed to find corresponding probes from "
 			 "debuginfo. Use kprobe event information.\n");
-		pp->function = strdup(tp->symbol);
-		if (pp->function == NULL)
-			return -ENOMEM;
-		pp->offset = tp->offset;
+		return convert_to_perf_probe_point(tp, pp);
 	}
 	pp->retprobe = tp->retprobe;
 
@@ -275,9 +303,20 @@
 					  int max_tevs, const char *target)
 {
 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
-	struct debuginfo *dinfo = open_debuginfo(target);
+	struct debuginfo *dinfo;
 	int ntevs, ret = 0;
 
+	if (pev->uprobes) {
+		if (need_dwarf) {
+			pr_warning("Debuginfo-analysis is not yet supported"
+					" with -x/--exec option.\n");
+			return -ENOSYS;
+		}
+		return convert_name_to_addr(pev, target);
+	}
+
+	dinfo = open_debuginfo(target);
+
 	if (!dinfo) {
 		if (need_dwarf) {
 			pr_warning("Failed to open debuginfo file.\n");
@@ -603,23 +642,22 @@
 		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
 		return -ENOENT;
 	}
-	pp->function = strdup(tp->symbol);
-	if (pp->function == NULL)
-		return -ENOMEM;
-	pp->offset = tp->offset;
-	pp->retprobe = tp->retprobe;
 
-	return 0;
+	return convert_to_perf_probe_point(tp, pp);
 }
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 				struct probe_trace_event **tevs __unused,
-				int max_tevs __unused, const char *mod __unused)
+				int max_tevs __unused, const char *target)
 {
 	if (perf_probe_event_need_dwarf(pev)) {
 		pr_warning("Debuginfo-analysis is not supported.\n");
 		return -ENOSYS;
 	}
+
+	if (pev->uprobes)
+		return convert_name_to_addr(pev, target);
+
 	return 0;
 }
 
@@ -1341,11 +1379,18 @@
 	if (buf == NULL)
 		return NULL;
 
-	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
-			 tp->retprobe ? 'r' : 'p',
-			 tev->group, tev->event,
-			 tp->module ?: "", tp->module ? ":" : "",
-			 tp->symbol, tp->offset);
+	if (tev->uprobes)
+		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
+				 tp->retprobe ? 'r' : 'p',
+				 tev->group, tev->event,
+				 tp->module, tp->symbol);
+	else
+		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
+				 tp->retprobe ? 'r' : 'p',
+				 tev->group, tev->event,
+				 tp->module ?: "", tp->module ? ":" : "",
+				 tp->symbol, tp->offset);
+
 	if (len <= 0)
 		goto error;
 
@@ -1364,7 +1409,7 @@
 }
 
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
-				       struct perf_probe_event *pev)
+			       struct perf_probe_event *pev, bool is_kprobe)
 {
 	char buf[64] = "";
 	int i, ret;
@@ -1376,7 +1421,11 @@
 		return -ENOMEM;
 
 	/* Convert trace_point to probe_point */
-	ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
+	if (is_kprobe)
+		ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
+	else
+		ret = convert_to_perf_probe_point(&tev->point, &pev->point);
+
 	if (ret < 0)
 		return ret;
 
@@ -1472,7 +1521,26 @@
 	memset(tev, 0, sizeof(*tev));
 }
 
-static int open_kprobe_events(bool readwrite)
+static void print_warn_msg(const char *file, bool is_kprobe)
+{
+
+	if (errno == ENOENT) {
+		const char *config;
+
+		if (!is_kprobe)
+			config = "CONFIG_UPROBE_EVENTS";
+		else
+			config = "CONFIG_KPROBE_EVENTS";
+
+		pr_warning("%s file does not exist - please rebuild kernel"
+				" with %s.\n", file, config);
+	} else
+		pr_warning("Failed to open %s file: %s\n", file,
+				strerror(errno));
+}
+
+static int open_probe_events(const char *trace_file, bool readwrite,
+				bool is_kprobe)
 {
 	char buf[PATH_MAX];
 	const char *__debugfs;
@@ -1484,27 +1552,31 @@
 		return -ENOENT;
 	}
 
-	ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
+	ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
 	if (ret >= 0) {
 		pr_debug("Opening %s write=%d\n", buf, readwrite);
 		if (readwrite && !probe_event_dry_run)
 			ret = open(buf, O_RDWR, O_APPEND);
 		else
 			ret = open(buf, O_RDONLY, 0);
-	}
 
-	if (ret < 0) {
-		if (errno == ENOENT)
-			pr_warning("kprobe_events file does not exist - please"
-				 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
-		else
-			pr_warning("Failed to open kprobe_events file: %s\n",
-				   strerror(errno));
+		if (ret < 0)
+			print_warn_msg(buf, is_kprobe);
 	}
 	return ret;
 }
 
-/* Get raw string list of current kprobe_events */
+static int open_kprobe_events(bool readwrite)
+{
+	return open_probe_events("tracing/kprobe_events", readwrite, true);
+}
+
+static int open_uprobe_events(bool readwrite)
+{
+	return open_probe_events("tracing/uprobe_events", readwrite, false);
+}
+
+/* Get raw string list of current kprobe_events  or uprobe_events */
 static struct strlist *get_probe_trace_command_rawlist(int fd)
 {
 	int ret, idx;
@@ -1569,36 +1641,26 @@
 	return ret;
 }
 
-/* List up current perf-probe events */
-int show_perf_probe_events(void)
+static int __show_perf_probe_events(int fd, bool is_kprobe)
 {
-	int fd, ret;
+	int ret = 0;
 	struct probe_trace_event tev;
 	struct perf_probe_event pev;
 	struct strlist *rawlist;
 	struct str_node *ent;
 
-	setup_pager();
-	ret = init_vmlinux();
-	if (ret < 0)
-		return ret;
-
 	memset(&tev, 0, sizeof(tev));
 	memset(&pev, 0, sizeof(pev));
 
-	fd = open_kprobe_events(false);
-	if (fd < 0)
-		return fd;
-
 	rawlist = get_probe_trace_command_rawlist(fd);
-	close(fd);
 	if (!rawlist)
 		return -ENOENT;
 
 	strlist__for_each(ent, rawlist) {
 		ret = parse_probe_trace_command(ent->s, &tev);
 		if (ret >= 0) {
-			ret = convert_to_perf_probe_event(&tev, &pev);
+			ret = convert_to_perf_probe_event(&tev, &pev,
+								is_kprobe);
 			if (ret >= 0)
 				ret = show_perf_probe_event(&pev);
 		}
@@ -1612,6 +1674,33 @@
 	return ret;
 }
 
+/* List up current perf-probe events */
+int show_perf_probe_events(void)
+{
+	int fd, ret;
+
+	setup_pager();
+	fd = open_kprobe_events(false);
+
+	if (fd < 0)
+		return fd;
+
+	ret = init_vmlinux();
+	if (ret < 0)
+		return ret;
+
+	ret = __show_perf_probe_events(fd, true);
+	close(fd);
+
+	fd = open_uprobe_events(false);
+	if (fd >= 0) {
+		ret = __show_perf_probe_events(fd, false);
+		close(fd);
+	}
+
+	return ret;
+}
+
 /* Get current perf-probe event names */
 static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
 {
@@ -1717,7 +1806,11 @@
 	const char *event, *group;
 	struct strlist *namelist;
 
-	fd = open_kprobe_events(true);
+	if (pev->uprobes)
+		fd = open_uprobe_events(true);
+	else
+		fd = open_kprobe_events(true);
+
 	if (fd < 0)
 		return fd;
 	/* Get current event names */
@@ -1829,6 +1922,8 @@
 	tev->point.offset = pev->point.offset;
 	tev->point.retprobe = pev->point.retprobe;
 	tev->nargs = pev->nargs;
+	tev->uprobes = pev->uprobes;
+
 	if (tev->nargs) {
 		tev->args = zalloc(sizeof(struct probe_trace_arg)
 				   * tev->nargs);
@@ -1859,6 +1954,9 @@
 		}
 	}
 
+	if (pev->uprobes)
+		return 1;
+
 	/* Currently just checking function name from symbol map */
 	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
 	if (!sym) {
@@ -1894,12 +1992,18 @@
 	int i, j, ret;
 	struct __event_package *pkgs;
 
+	ret = 0;
 	pkgs = zalloc(sizeof(struct __event_package) * npevs);
+
 	if (pkgs == NULL)
 		return -ENOMEM;
 
-	/* Init vmlinux path */
-	ret = init_vmlinux();
+	if (!pevs->uprobes)
+		/* Init vmlinux path */
+		ret = init_vmlinux();
+	else
+		ret = init_user_exec();
+
 	if (ret < 0) {
 		free(pkgs);
 		return ret;
@@ -1971,23 +2075,15 @@
 	return ret;
 }
 
-static int del_trace_probe_event(int fd, const char *group,
-				  const char *event, struct strlist *namelist)
+static int del_trace_probe_event(int fd, const char *buf,
+						  struct strlist *namelist)
 {
-	char buf[128];
 	struct str_node *ent, *n;
-	int found = 0, ret = 0;
-
-	ret = e_snprintf(buf, 128, "%s:%s", group, event);
-	if (ret < 0) {
-		pr_err("Failed to copy event.\n");
-		return ret;
-	}
+	int ret = -1;
 
 	if (strpbrk(buf, "*?")) { /* Glob-exp */
 		strlist__for_each_safe(ent, n, namelist)
 			if (strglobmatch(ent->s, buf)) {
-				found++;
 				ret = __del_trace_probe_event(fd, ent);
 				if (ret < 0)
 					break;
@@ -1996,40 +2092,43 @@
 	} else {
 		ent = strlist__find(namelist, buf);
 		if (ent) {
-			found++;
 			ret = __del_trace_probe_event(fd, ent);
 			if (ret >= 0)
 				strlist__remove(namelist, ent);
 		}
 	}
-	if (found == 0 && ret >= 0)
-		pr_info("Info: Event \"%s\" does not exist.\n", buf);
 
 	return ret;
 }
 
 int del_perf_probe_events(struct strlist *dellist)
 {
-	int fd, ret = 0;
+	int ret = -1, ufd = -1, kfd = -1;
+	char buf[128];
 	const char *group, *event;
 	char *p, *str;
 	struct str_node *ent;
-	struct strlist *namelist;
-
-	fd = open_kprobe_events(true);
-	if (fd < 0)
-		return fd;
+	struct strlist *namelist = NULL, *unamelist = NULL;
 
 	/* Get current event names */
-	namelist = get_probe_trace_event_names(fd, true);
-	if (namelist == NULL)
-		return -EINVAL;
+	kfd = open_kprobe_events(true);
+	if (kfd < 0)
+		return kfd;
+
+	namelist = get_probe_trace_event_names(kfd, true);
+	ufd = open_uprobe_events(true);
+
+	if (ufd >= 0)
+		unamelist = get_probe_trace_event_names(ufd, true);
+
+	if (namelist == NULL && unamelist == NULL)
+		goto error;
 
 	strlist__for_each(ent, dellist) {
 		str = strdup(ent->s);
 		if (str == NULL) {
 			ret = -ENOMEM;
-			break;
+			goto error;
 		}
 		pr_debug("Parsing: %s\n", str);
 		p = strchr(str, ':');
@@ -2041,17 +2140,46 @@
 			group = "*";
 			event = str;
 		}
+
+		ret = e_snprintf(buf, 128, "%s:%s", group, event);
+		if (ret < 0) {
+			pr_err("Failed to copy event.");
+			free(str);
+			goto error;
+		}
+
 		pr_debug("Group: %s, Event: %s\n", group, event);
-		ret = del_trace_probe_event(fd, group, event, namelist);
+
+		if (namelist)
+			ret = del_trace_probe_event(kfd, buf, namelist);
+
+		if (unamelist && ret != 0)
+			ret = del_trace_probe_event(ufd, buf, unamelist);
+
+		if (ret != 0)
+			pr_info("Info: Event \"%s\" does not exist.\n", buf);
+
 		free(str);
-		if (ret < 0)
-			break;
 	}
-	strlist__delete(namelist);
-	close(fd);
+
+error:
+	if (kfd >= 0) {
+		if (namelist)
+			strlist__delete(namelist);
+
+		close(kfd);
+	}
+
+	if (ufd >= 0) {
+		if (unamelist)
+			strlist__delete(unamelist);
+
+		close(ufd);
+	}
 
 	return ret;
 }
+
 /* TODO: don't use a global variable for filter ... */
 static struct strfilter *available_func_filter;
 
@@ -2068,23 +2196,8 @@
 	return 1;
 }
 
-int show_available_funcs(const char *target, struct strfilter *_filter)
+static int __show_available_funcs(struct map *map)
 {
-	struct map *map;
-	int ret;
-
-	setup_pager();
-
-	ret = init_vmlinux();
-	if (ret < 0)
-		return ret;
-
-	map = kernel_get_module_map(target);
-	if (!map) {
-		pr_err("Failed to find %s map.\n", (target) ? : "kernel");
-		return -EINVAL;
-	}
-	available_func_filter = _filter;
 	if (map__load(map, filter_available_functions)) {
 		pr_err("Failed to load map.\n");
 		return -EINVAL;
@@ -2095,3 +2208,140 @@
 	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
 	return 0;
 }
+
+static int available_kernel_funcs(const char *module)
+{
+	struct map *map;
+	int ret;
+
+	ret = init_vmlinux();
+	if (ret < 0)
+		return ret;
+
+	map = kernel_get_module_map(module);
+	if (!map) {
+		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+		return -EINVAL;
+	}
+	return __show_available_funcs(map);
+}
+
+static int available_user_funcs(const char *target)
+{
+	struct map *map;
+	int ret;
+
+	ret = init_user_exec();
+	if (ret < 0)
+		return ret;
+
+	map = dso__new_map(target);
+	ret = __show_available_funcs(map);
+	dso__delete(map->dso);
+	map__delete(map);
+	return ret;
+}
+
+int show_available_funcs(const char *target, struct strfilter *_filter,
+					bool user)
+{
+	setup_pager();
+	available_func_filter = _filter;
+
+	if (!user)
+		return available_kernel_funcs(target);
+
+	return available_user_funcs(target);
+}
+
+/*
+ * uprobe_events only accepts address:
+ * Convert function and any offset to address
+ */
+static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
+{
+	struct perf_probe_point *pp = &pev->point;
+	struct symbol *sym;
+	struct map *map = NULL;
+	char *function = NULL, *name = NULL;
+	int ret = -EINVAL;
+	unsigned long long vaddr = 0;
+
+	if (!pp->function) {
+		pr_warning("No function specified for uprobes");
+		goto out;
+	}
+
+	function = strdup(pp->function);
+	if (!function) {
+		pr_warning("Failed to allocate memory by strdup.\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	name = realpath(exec, NULL);
+	if (!name) {
+		pr_warning("Cannot find realpath for %s.\n", exec);
+		goto out;
+	}
+	map = dso__new_map(name);
+	if (!map) {
+		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
+		goto out;
+	}
+	available_func_filter = strfilter__new(function, NULL);
+	if (map__load(map, filter_available_functions)) {
+		pr_err("Failed to load map.\n");
+		goto out;
+	}
+
+	sym = map__find_symbol_by_name(map, function, NULL);
+	if (!sym) {
+		pr_warning("Cannot find %s in DSO %s\n", function, exec);
+		goto out;
+	}
+
+	if (map->start > sym->start)
+		vaddr = map->start;
+	vaddr += sym->start + pp->offset + map->pgoff;
+	pp->offset = 0;
+
+	if (!pev->event) {
+		pev->event = function;
+		function = NULL;
+	}
+	if (!pev->group) {
+		char *ptr1, *ptr2;
+
+		pev->group = zalloc(sizeof(char *) * 64);
+		ptr1 = strdup(basename(exec));
+		if (ptr1) {
+			ptr2 = strpbrk(ptr1, "-._");
+			if (ptr2)
+				*ptr2 = '\0';
+			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
+					ptr1);
+			free(ptr1);
+		}
+	}
+	free(pp->function);
+	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
+	if (!pp->function) {
+		ret = -ENOMEM;
+		pr_warning("Failed to allocate memory by zalloc.\n");
+		goto out;
+	}
+	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
+	ret = 0;
+
+out:
+	if (map) {
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+	if (function)
+		free(function);
+	if (name)
+		free(name);
+	return ret;
+}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index a7dee83..f9f3de8 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,7 +7,7 @@
 
 extern bool probe_event_dry_run;
 
-/* kprobe-tracer tracing point */
+/* kprobe-tracer and uprobe-tracer tracing point */
 struct probe_trace_point {
 	char		*symbol;	/* Base symbol */
 	char		*module;	/* Module name */
@@ -21,7 +21,7 @@
 	long				offset;	/* Offset value */
 };
 
-/* kprobe-tracer tracing argument */
+/* kprobe-tracer and uprobe-tracer tracing argument */
 struct probe_trace_arg {
 	char				*name;	/* Argument name */
 	char				*value;	/* Base value */
@@ -29,12 +29,13 @@
 	struct probe_trace_arg_ref	*ref;	/* Referencing offset */
 };
 
-/* kprobe-tracer tracing event (point + arg) */
+/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
 struct probe_trace_event {
 	char				*event;	/* Event name */
 	char				*group;	/* Group name */
 	struct probe_trace_point	point;	/* Trace point */
 	int				nargs;	/* Number of args */
+	bool				uprobes;	/* uprobes only */
 	struct probe_trace_arg		*args;	/* Arguments */
 };
 
@@ -70,6 +71,7 @@
 	char			*group;	/* Group name */
 	struct perf_probe_point	point;	/* Probe point */
 	int			nargs;	/* Number of arguments */
+	bool			uprobes;
 	struct perf_probe_arg	*args;	/* Arguments */
 };
 
@@ -129,8 +131,8 @@
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
 			       int max_probe_points, const char *module,
 			       struct strfilter *filter, bool externs);
-extern int show_available_funcs(const char *module, struct strfilter *filter);
-
+extern int show_available_funcs(const char *module, struct strfilter *filter,
+				bool user);
 
 /* Maximum index number of event-name postfix */
 #define MAX_EVENT_INDEX	1024
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e30749e..4c1b3d7 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -56,7 +56,7 @@
 #define FTRACE_MAX_EVENT				\
 	((1 << (sizeof(unsigned short) * 8)) - 1)
 
-struct event *events[FTRACE_MAX_EVENT];
+struct event_format *events[FTRACE_MAX_EVENT];
 
 extern struct scripting_context *scripting_context;
 
@@ -181,7 +181,7 @@
 	LEAVE;
 }
 
-static void define_event_symbols(struct event *event,
+static void define_event_symbols(struct event_format *event,
 				 const char *ev_name,
 				 struct print_arg *args)
 {
@@ -209,6 +209,8 @@
 		define_symbolic_values(args->symbol.symbols, ev_name,
 				       cur_field_name);
 		break;
+	case PRINT_BSTRING:
+	case PRINT_DYNAMIC_ARRAY:
 	case PRINT_STRING:
 		break;
 	case PRINT_TYPE:
@@ -220,7 +222,9 @@
 		define_event_symbols(event, ev_name, args->op.left);
 		define_event_symbols(event, ev_name, args->op.right);
 		break;
+	case PRINT_FUNC:
 	default:
+		pr_err("Unsupported print arg type\n");
 		/* we should warn... */
 		return;
 	}
@@ -229,10 +233,10 @@
 		define_event_symbols(event, ev_name, args->next);
 }
 
-static inline struct event *find_cache_event(int type)
+static inline struct event_format *find_cache_event(int type)
 {
 	static char ev_name[256];
-	struct event *event;
+	struct event_format *event;
 
 	if (events[type])
 		return events[type];
@@ -258,7 +262,7 @@
 	static char handler[256];
 	unsigned long long val;
 	unsigned long s, ns;
-	struct event *event;
+	struct event_format *event;
 	int type;
 	int pid;
 	int cpu = sample->cpu;
@@ -446,7 +450,7 @@
 
 static int perl_generate_script(const char *outfile)
 {
-	struct event *event = NULL;
+	struct event_format *event = NULL;
 	struct format_field *f;
 	char fname[PATH_MAX];
 	int not_first, count;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index c2623c6..acb9795 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -37,7 +37,7 @@
 #define FTRACE_MAX_EVENT				\
 	((1 << (sizeof(unsigned short) * 8)) - 1)
 
-struct event *events[FTRACE_MAX_EVENT];
+struct event_format *events[FTRACE_MAX_EVENT];
 
 #define MAX_FIELDS	64
 #define N_COMMON_FIELDS	7
@@ -136,7 +136,7 @@
 	Py_DECREF(t);
 }
 
-static void define_event_symbols(struct event *event,
+static void define_event_symbols(struct event_format *event,
 				 const char *ev_name,
 				 struct print_arg *args)
 {
@@ -178,6 +178,10 @@
 		define_event_symbols(event, ev_name, args->op.right);
 		break;
 	default:
+		/* gcc warns for these? */
+	case PRINT_BSTRING:
+	case PRINT_DYNAMIC_ARRAY:
+	case PRINT_FUNC:
 		/* we should warn... */
 		return;
 	}
@@ -186,10 +190,10 @@
 		define_event_symbols(event, ev_name, args->next);
 }
 
-static inline struct event *find_cache_event(int type)
+static inline struct event_format *find_cache_event(int type)
 {
 	static char ev_name[256];
-	struct event *event;
+	struct event_format *event;
 
 	if (events[type])
 		return events[type];
@@ -216,7 +220,7 @@
 	struct format_field *field;
 	unsigned long long val;
 	unsigned long s, ns;
-	struct event *event;
+	struct event_format *event;
 	unsigned n = 0;
 	int type;
 	int pid;
@@ -436,7 +440,7 @@
 
 static int python_generate_script(const char *outfile)
 {
-	struct event *event = NULL;
+	struct event_format *event = NULL;
 	struct format_field *f;
 	char fname[PATH_MAX];
 	int not_first, count;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1efd3be..93d355d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -481,6 +481,38 @@
 	event->read.id		 = bswap_64(event->read.id);
 }
 
+static u8 revbyte(u8 b)
+{
+	int rev = (b >> 4) | ((b & 0xf) << 4);
+	rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2);
+	rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1);
+	return (u8) rev;
+}
+
+/*
+ * XXX this is hack in attempt to carry flags bitfield
+ * throught endian village. ABI says:
+ *
+ * Bit-fields are allocated from right to left (least to most significant)
+ * on little-endian implementations and from left to right (most to least
+ * significant) on big-endian implementations.
+ *
+ * The above seems to be byte specific, so we need to reverse each
+ * byte of the bitfield. 'Internet' also says this might be implementation
+ * specific and we probably need proper fix and carry perf_event_attr
+ * bitfield flags in separate data file FEAT_ section. Thought this seems
+ * to work for now.
+ */
+static void swap_bitfield(u8 *p, unsigned len)
+{
+	unsigned i;
+
+	for (i = 0; i < len; i++) {
+		*p = revbyte(*p);
+		p++;
+	}
+}
+
 /* exported for swapping attributes in file header */
 void perf_event__attr_swap(struct perf_event_attr *attr)
 {
@@ -494,6 +526,8 @@
 	attr->bp_type		= bswap_32(attr->bp_type);
 	attr->bp_addr		= bswap_64(attr->bp_addr);
 	attr->bp_len		= bswap_64(attr->bp_len);
+
+	swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
 }
 
 static void perf_event__hdr_attr_swap(union perf_event *event)
@@ -1064,8 +1098,9 @@
 static int __perf_session__process_pipe_events(struct perf_session *self,
 					       struct perf_tool *tool)
 {
-	union perf_event event;
-	uint32_t size;
+	union perf_event *event;
+	uint32_t size, cur_size = 0;
+	void *buf = NULL;
 	int skip = 0;
 	u64 head;
 	int err;
@@ -1074,8 +1109,14 @@
 	perf_tool__fill_defaults(tool);
 
 	head = 0;
+	cur_size = sizeof(union perf_event);
+
+	buf = malloc(cur_size);
+	if (!buf)
+		return -errno;
 more:
-	err = readn(self->fd, &event, sizeof(struct perf_event_header));
+	event = buf;
+	err = readn(self->fd, event, sizeof(struct perf_event_header));
 	if (err <= 0) {
 		if (err == 0)
 			goto done;
@@ -1085,13 +1126,23 @@
 	}
 
 	if (self->header.needs_swap)
-		perf_event_header__bswap(&event.header);
+		perf_event_header__bswap(&event->header);
 
-	size = event.header.size;
+	size = event->header.size;
 	if (size == 0)
 		size = 8;
 
-	p = &event;
+	if (size > cur_size) {
+		void *new = realloc(buf, size);
+		if (!new) {
+			pr_err("failed to allocate memory to read event\n");
+			goto out_err;
+		}
+		buf = new;
+		cur_size = size;
+		event = buf;
+	}
+	p = event;
 	p += sizeof(struct perf_event_header);
 
 	if (size - sizeof(struct perf_event_header)) {
@@ -1107,17 +1158,11 @@
 		}
 	}
 
-	if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) {
-		dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
-			    head, event.header.size, event.header.type);
-		/*
-		 * assume we lost track of the stream, check alignment, and
-		 * increment a single u64 in the hope to catch on again 'soon'.
-		 */
-		if (unlikely(head & 7))
-			head &= ~7ULL;
-
-		size = 8;
+	if ((skip = perf_session__process_event(self, event, tool, head)) < 0) {
+		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
+		       head, event->header.size, event->header.type);
+		err = -EINVAL;
+		goto out_err;
 	}
 
 	head += size;
@@ -1130,6 +1175,7 @@
 done:
 	err = 0;
 out_err:
+	free(buf);
 	perf_session__warn_about_errors(self, tool);
 	perf_session_free_sample_buffers(self);
 	return err;
@@ -1226,17 +1272,11 @@
 
 	if (size == 0 ||
 	    perf_session__process_event(session, event, tool, file_pos) < 0) {
-		dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
-			    file_offset + head, event->header.size,
-			    event->header.type);
-		/*
-		 * assume we lost track of the stream, check alignment, and
-		 * increment a single u64 in the hope to catch on again 'soon'.
-		 */
-		if (unlikely(head & 7))
-			head &= ~7ULL;
-
-		size = 8;
+		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
+		       file_offset + head, event->header.size,
+		       event->header.type);
+		err = -EINVAL;
+		goto out_err;
 	}
 
 	head += size;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab9867b..e2ba885 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2783,3 +2783,11 @@
 
 	return ret;
 }
+
+struct map *dso__new_map(const char *name)
+{
+	struct dso *dso = dso__new(name);
+	struct map *map = map__new2(0, dso, MAP__FUNCTION);
+
+	return map;
+}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ac49ef2..5649d63 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -65,6 +65,11 @@
 
 void symbol__delete(struct symbol *sym);
 
+static inline size_t symbol__size(const struct symbol *sym)
+{
+	return sym->end - sym->start + 1;
+}
+
 struct strlist;
 
 struct symbol_conf {
@@ -237,6 +242,7 @@
 void dso__set_build_id(struct dso *dso, void *build_id);
 void dso__read_running_kernel_build_id(struct dso *dso,
 				       struct machine *machine);
+struct map *dso__new_map(const char *name);
 struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
 				u64 addr);
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
new file mode 100644
index 0000000..1064d5b
--- /dev/null
+++ b/tools/perf/util/target.c
@@ -0,0 +1,142 @@
+/*
+ * Helper functions for handling target threads/cpus
+ *
+ * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@lge.com>
+ *
+ * Released under the GPL v2.
+ */
+
+#include "target.h"
+#include "debug.h"
+
+#include <pwd.h>
+#include <string.h>
+
+
+enum perf_target_errno perf_target__validate(struct perf_target *target)
+{
+	enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS;
+
+	if (target->pid)
+		target->tid = target->pid;
+
+	/* CPU and PID are mutually exclusive */
+	if (target->tid && target->cpu_list) {
+		target->cpu_list = NULL;
+		if (ret == PERF_ERRNO_TARGET__SUCCESS)
+			ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU;
+	}
+
+	/* UID and PID are mutually exclusive */
+	if (target->tid && target->uid_str) {
+		target->uid_str = NULL;
+		if (ret == PERF_ERRNO_TARGET__SUCCESS)
+			ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID;
+	}
+
+	/* UID and CPU are mutually exclusive */
+	if (target->uid_str && target->cpu_list) {
+		target->cpu_list = NULL;
+		if (ret == PERF_ERRNO_TARGET__SUCCESS)
+			ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU;
+	}
+
+	/* PID and SYSTEM are mutually exclusive */
+	if (target->tid && target->system_wide) {
+		target->system_wide = false;
+		if (ret == PERF_ERRNO_TARGET__SUCCESS)
+			ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM;
+	}
+
+	/* UID and SYSTEM are mutually exclusive */
+	if (target->uid_str && target->system_wide) {
+		target->system_wide = false;
+		if (ret == PERF_ERRNO_TARGET__SUCCESS)
+			ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM;
+	}
+
+	return ret;
+}
+
+enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
+{
+	struct passwd pwd, *result;
+	char buf[1024];
+	const char *str = target->uid_str;
+
+	target->uid = UINT_MAX;
+	if (str == NULL)
+		return PERF_ERRNO_TARGET__SUCCESS;
+
+	/* Try user name first */
+	getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
+
+	if (result == NULL) {
+		/*
+		 * The user name not found. Maybe it's a UID number.
+		 */
+		char *endptr;
+		int uid = strtol(str, &endptr, 10);
+
+		if (*endptr != '\0')
+			return PERF_ERRNO_TARGET__INVALID_UID;
+
+		getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
+
+		if (result == NULL)
+			return PERF_ERRNO_TARGET__USER_NOT_FOUND;
+	}
+
+	target->uid = result->pw_uid;
+	return PERF_ERRNO_TARGET__SUCCESS;
+}
+
+/*
+ * This must have a same ordering as the enum perf_target_errno.
+ */
+static const char *perf_target__error_str[] = {
+	"PID/TID switch overriding CPU",
+	"PID/TID switch overriding UID",
+	"UID switch overriding CPU",
+	"PID/TID switch overriding SYSTEM",
+	"UID switch overriding SYSTEM",
+	"Invalid User: %s",
+	"Problems obtaining information for user %s",
+};
+
+int perf_target__strerror(struct perf_target *target, int errnum,
+			  char *buf, size_t buflen)
+{
+	int idx;
+	const char *msg;
+
+	if (errnum >= 0) {
+		strerror_r(errnum, buf, buflen);
+		return 0;
+	}
+
+	if (errnum <  __PERF_ERRNO_TARGET__START ||
+	    errnum >= __PERF_ERRNO_TARGET__END)
+		return -1;
+
+	idx = errnum - __PERF_ERRNO_TARGET__START;
+	msg = perf_target__error_str[idx];
+
+	switch (errnum) {
+	case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU
+	 ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
+		snprintf(buf, buflen, "%s", msg);
+		break;
+
+	case PERF_ERRNO_TARGET__INVALID_UID:
+	case PERF_ERRNO_TARGET__USER_NOT_FOUND:
+		snprintf(buf, buflen, msg, target->uid_str);
+		break;
+
+	default:
+		/* cannot reach here */
+		break;
+	}
+
+	return 0;
+}
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
new file mode 100644
index 0000000..a4be857
--- /dev/null
+++ b/tools/perf/util/target.h
@@ -0,0 +1,65 @@
+#ifndef _PERF_TARGET_H
+#define _PERF_TARGET_H
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+struct perf_target {
+	const char   *pid;
+	const char   *tid;
+	const char   *cpu_list;
+	const char   *uid_str;
+	uid_t	     uid;
+	bool	     system_wide;
+	bool	     uses_mmap;
+};
+
+enum perf_target_errno {
+	PERF_ERRNO_TARGET__SUCCESS		= 0,
+
+	/*
+	 * Choose an arbitrary negative big number not to clash with standard
+	 * errno since SUS requires the errno has distinct positive values.
+	 * See 'Issue 6' in the link below.
+	 *
+	 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
+	 */
+	__PERF_ERRNO_TARGET__START		= -10000,
+
+
+	/* for perf_target__validate() */
+	PERF_ERRNO_TARGET__PID_OVERRIDE_CPU	= __PERF_ERRNO_TARGET__START,
+	PERF_ERRNO_TARGET__PID_OVERRIDE_UID,
+	PERF_ERRNO_TARGET__UID_OVERRIDE_CPU,
+	PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM,
+	PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM,
+
+	/* for perf_target__parse_uid() */
+	PERF_ERRNO_TARGET__INVALID_UID,
+	PERF_ERRNO_TARGET__USER_NOT_FOUND,
+
+	__PERF_ERRNO_TARGET__END,
+};
+
+enum perf_target_errno perf_target__validate(struct perf_target *target);
+enum perf_target_errno perf_target__parse_uid(struct perf_target *target);
+
+int perf_target__strerror(struct perf_target *target, int errnum, char *buf,
+			  size_t buflen);
+
+static inline bool perf_target__has_task(struct perf_target *target)
+{
+	return target->tid || target->pid || target->uid_str;
+}
+
+static inline bool perf_target__has_cpu(struct perf_target *target)
+{
+	return target->system_wide || target->cpu_list;
+}
+
+static inline bool perf_target__none(struct perf_target *target)
+{
+	return !perf_target__has_task(target) && !perf_target__has_cpu(target);
+}
+
+#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 7da80f1..f718df8 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -6,7 +6,7 @@
 
 struct thread_map {
 	int nr;
-	int map[];
+	pid_t map[];
 };
 
 struct thread_map *thread_map__new_by_pid(pid_t pid);
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 09fe579..abe0e8e 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -69,23 +69,24 @@
 
 	ret += SNPRINTF(bf + ret, size - ret, "], ");
 
-	if (top->target_pid)
+	if (top->target.pid)
 		ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
-				top->target_pid);
-	else if (top->target_tid)
+				top->target.pid);
+	else if (top->target.tid)
 		ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
-				top->target_tid);
-	else if (top->uid_str != NULL)
+				top->target.tid);
+	else if (top->target.uid_str != NULL)
 		ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
-				top->uid_str);
+				top->target.uid_str);
 	else
 		ret += SNPRINTF(bf + ret, size - ret, " (all");
 
-	if (top->cpu_list)
+	if (top->target.cpu_list)
 		ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
-				top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
+				top->evlist->cpus->nr > 1 ? "s" : "",
+				top->target.cpu_list);
 	else {
-		if (top->target_tid)
+		if (top->target.tid)
 			ret += SNPRINTF(bf + ret, size - ret, ")");
 		else
 			ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index ce61cb2..33347ca 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -13,6 +13,7 @@
 struct perf_top {
 	struct perf_tool   tool;
 	struct perf_evlist *evlist;
+	struct perf_target target;
 	/*
 	 * Symbols will be added here in perf_event__process_sample and will
 	 * get out after decayed.
@@ -23,10 +24,7 @@
 	u64		   guest_us_samples, guest_kernel_samples;
 	int		   print_entries, count_filter, delay_secs;
 	int		   freq;
-	const char	   *target_pid, *target_tid;
-	uid_t		   uid;
 	bool		   hide_kernel_symbols, hide_user_symbols, zero;
-	bool		   system_wide;
 	bool		   use_tui, use_stdio;
 	bool		   sort_has_symbols;
 	bool		   dont_use_callchains;
@@ -37,7 +35,6 @@
 	bool		   sample_id_all_missing;
 	bool		   exclude_guest_missing;
 	bool		   dump_symtab;
-	const char	   *cpu_list;
 	struct hist_entry  *sym_filter_entry;
 	struct perf_evsel  *sym_evsel;
 	struct perf_session *session;
@@ -47,7 +44,6 @@
 	int		   realtime_prio;
 	int		   sym_pcnt_filter;
 	const char	   *sym_filter;
-	const char	   *uid_str;
 };
 
 size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index fc22cf5..a8d81c3 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -68,7 +68,7 @@
 };
 
 
-void *malloc_or_die(unsigned int size)
+static void *malloc_or_die(unsigned int size)
 {
 	void *data;
 
@@ -448,6 +448,8 @@
 	else
 		buf[0] = 0;
 
+	read_trace_init(buf[0], buf[0]);
+
 	write_or_die(buf, 1);
 
 	/* save size of long */
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index dfd1bd8..df2fddb 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -17,1933 +17,124 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  The parts for function graph printing was taken and modified from the
- *  Linux Kernel that were written by Frederic Weisbecker.
  */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <errno.h>
 
 #include "../perf.h"
 #include "util.h"
 #include "trace-event.h"
 
-int header_page_ts_offset;
-int header_page_ts_size;
-int header_page_size_offset;
 int header_page_size_size;
-int header_page_overwrite_offset;
-int header_page_overwrite_size;
+int header_page_ts_size;
 int header_page_data_offset;
-int header_page_data_size;
+
+struct pevent *perf_pevent;
+static struct pevent *pevent;
 
 bool latency_format;
 
-static char *input_buf;
-static unsigned long long input_buf_ptr;
-static unsigned long long input_buf_siz;
-
-static int cpus;
-static int long_size;
-static int is_flag_field;
-static int is_symbolic_field;
-
-static struct format_field *
-find_any_field(struct event *event, const char *name);
-
-static void init_input_buf(char *buf, unsigned long long size)
+int read_trace_init(int file_bigendian, int host_bigendian)
 {
-	input_buf = buf;
-	input_buf_siz = size;
-	input_buf_ptr = 0;
-}
-
-struct cmdline {
-	char *comm;
-	int pid;
-};
-
-static struct cmdline *cmdlines;
-static int cmdline_count;
-
-static int cmdline_cmp(const void *a, const void *b)
-{
-	const struct cmdline *ca = a;
-	const struct cmdline *cb = b;
-
-	if (ca->pid < cb->pid)
-		return -1;
-	if (ca->pid > cb->pid)
-		return 1;
-
-	return 0;
-}
-
-void parse_cmdlines(char *file, int size __unused)
-{
-	struct cmdline_list {
-		struct cmdline_list	*next;
-		char			*comm;
-		int			pid;
-	} *list = NULL, *item;
-	char *line;
-	char *next = NULL;
-	int i;
-
-	line = strtok_r(file, "\n", &next);
-	while (line) {
-		item = malloc_or_die(sizeof(*item));
-		sscanf(line, "%d %as", &item->pid,
-		       (float *)(void *)&item->comm); /* workaround gcc warning */
-		item->next = list;
-		list = item;
-		line = strtok_r(NULL, "\n", &next);
-		cmdline_count++;
-	}
-
-	cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
-
-	i = 0;
-	while (list) {
-		cmdlines[i].pid = list->pid;
-		cmdlines[i].comm = list->comm;
-		i++;
-		item = list;
-		list = list->next;
-		free(item);
-	}
-
-	qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
-}
-
-static struct func_map {
-	unsigned long long		addr;
-	char				*func;
-	char				*mod;
-} *func_list;
-static unsigned int func_count;
-
-static int func_cmp(const void *a, const void *b)
-{
-	const struct func_map *fa = a;
-	const struct func_map *fb = b;
-
-	if (fa->addr < fb->addr)
-		return -1;
-	if (fa->addr > fb->addr)
-		return 1;
-
-	return 0;
-}
-
-void parse_proc_kallsyms(char *file, unsigned int size __unused)
-{
-	struct func_list {
-		struct func_list	*next;
-		unsigned long long	addr;
-		char			*func;
-		char			*mod;
-	} *list = NULL, *item;
-	char *line;
-	char *next = NULL;
-	char *addr_str;
-	char ch;
-	int ret __used;
-	int i;
-
-	line = strtok_r(file, "\n", &next);
-	while (line) {
-		item = malloc_or_die(sizeof(*item));
-		item->mod = NULL;
-		ret = sscanf(line, "%as %c %as\t[%as",
-			     (float *)(void *)&addr_str, /* workaround gcc warning */
-			     &ch,
-			     (float *)(void *)&item->func,
-			     (float *)(void *)&item->mod);
-		item->addr = strtoull(addr_str, NULL, 16);
-		free(addr_str);
-
-		/* truncate the extra ']' */
-		if (item->mod)
-			item->mod[strlen(item->mod) - 1] = 0;
-
-
-		item->next = list;
-		list = item;
-		line = strtok_r(NULL, "\n", &next);
-		func_count++;
-	}
-
-	func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
-
-	i = 0;
-	while (list) {
-		func_list[i].func = list->func;
-		func_list[i].addr = list->addr;
-		func_list[i].mod = list->mod;
-		i++;
-		item = list;
-		list = list->next;
-		free(item);
-	}
-
-	qsort(func_list, func_count, sizeof(*func_list), func_cmp);
-
-	/*
-	 * Add a special record at the end.
-	 */
-	func_list[func_count].func = NULL;
-	func_list[func_count].addr = 0;
-	func_list[func_count].mod = NULL;
-}
-
-/*
- * We are searching for a record in between, not an exact
- * match.
- */
-static int func_bcmp(const void *a, const void *b)
-{
-	const struct func_map *fa = a;
-	const struct func_map *fb = b;
-
-	if ((fa->addr == fb->addr) ||
-
-	    (fa->addr > fb->addr &&
-	     fa->addr < (fb+1)->addr))
+	if (pevent)
 		return 0;
 
-	if (fa->addr < fb->addr)
-		return -1;
+	perf_pevent = pevent_alloc();
+	pevent = perf_pevent;
 
-	return 1;
-}
-
-static struct func_map *find_func(unsigned long long addr)
-{
-	struct func_map *func;
-	struct func_map key;
-
-	key.addr = addr;
-
-	func = bsearch(&key, func_list, func_count, sizeof(*func_list),
-		       func_bcmp);
-
-	return func;
-}
-
-void print_funcs(void)
-{
-	int i;
-
-	for (i = 0; i < (int)func_count; i++) {
-		printf("%016llx %s",
-		       func_list[i].addr,
-		       func_list[i].func);
-		if (func_list[i].mod)
-			printf(" [%s]\n", func_list[i].mod);
-		else
-			printf("\n");
-	}
-}
-
-static struct printk_map {
-	unsigned long long		addr;
-	char				*printk;
-} *printk_list;
-static unsigned int printk_count;
-
-static int printk_cmp(const void *a, const void *b)
-{
-	const struct func_map *fa = a;
-	const struct func_map *fb = b;
-
-	if (fa->addr < fb->addr)
-		return -1;
-	if (fa->addr > fb->addr)
-		return 1;
+	pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
+	pevent_set_file_bigendian(pevent, file_bigendian);
+	pevent_set_host_bigendian(pevent, host_bigendian);
 
 	return 0;
 }
 
-static struct printk_map *find_printk(unsigned long long addr)
+static int get_common_field(struct scripting_context *context,
+			    int *offset, int *size, const char *type)
 {
-	struct printk_map *printk;
-	struct printk_map key;
+	struct event_format *event;
+	struct format_field *field;
 
-	key.addr = addr;
+	if (!*size) {
+		if (!pevent->events)
+			return 0;
 
-	printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
-			 printk_cmp);
-
-	return printk;
-}
-
-void parse_ftrace_printk(char *file, unsigned int size __unused)
-{
-	struct printk_list {
-		struct printk_list	*next;
-		unsigned long long	addr;
-		char			*printk;
-	} *list = NULL, *item;
-	char *line;
-	char *next = NULL;
-	char *addr_str;
-	int i;
-
-	line = strtok_r(file, "\n", &next);
-	while (line) {
-		addr_str = strsep(&line, ":");
-		if (!line) {
-			warning("error parsing print strings");
-			break;
-		}
-		item = malloc_or_die(sizeof(*item));
-		item->addr = strtoull(addr_str, NULL, 16);
-		/* fmt still has a space, skip it */
-		item->printk = strdup(line+1);
-		item->next = list;
-		list = item;
-		line = strtok_r(NULL, "\n", &next);
-		printk_count++;
+		event = pevent->events[0];
+		field = pevent_find_common_field(event, type);
+		if (!field)
+			return 0;
+		*offset = field->offset;
+		*size = field->size;
 	}
 
-	printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
-
-	i = 0;
-	while (list) {
-		printk_list[i].printk = list->printk;
-		printk_list[i].addr = list->addr;
-		i++;
-		item = list;
-		list = list->next;
-		free(item);
-	}
-
-	qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
+	return pevent_read_number(pevent, context->event_data + *offset, *size);
 }
 
-void print_printk(void)
+int common_lock_depth(struct scripting_context *context)
 {
-	int i;
-
-	for (i = 0; i < (int)printk_count; i++) {
-		printf("%016llx %s\n",
-		       printk_list[i].addr,
-		       printk_list[i].printk);
-	}
-}
-
-static struct event *alloc_event(void)
-{
-	struct event *event;
-
-	event = malloc_or_die(sizeof(*event));
-	memset(event, 0, sizeof(*event));
-
-	return event;
-}
-
-enum event_type {
-	EVENT_ERROR,
-	EVENT_NONE,
-	EVENT_SPACE,
-	EVENT_NEWLINE,
-	EVENT_OP,
-	EVENT_DELIM,
-	EVENT_ITEM,
-	EVENT_DQUOTE,
-	EVENT_SQUOTE,
-};
-
-static struct event *event_list;
-
-static void add_event(struct event *event)
-{
-	event->next = event_list;
-	event_list = event;
-}
-
-static int event_item_type(enum event_type type)
-{
-	switch (type) {
-	case EVENT_ITEM ... EVENT_SQUOTE:
-		return 1;
-	case EVENT_ERROR ... EVENT_DELIM:
-	default:
-		return 0;
-	}
-}
-
-static void free_arg(struct print_arg *arg)
-{
-	if (!arg)
-		return;
-
-	switch (arg->type) {
-	case PRINT_ATOM:
-		if (arg->atom.atom)
-			free(arg->atom.atom);
-		break;
-	case PRINT_NULL:
-	case PRINT_FIELD ... PRINT_OP:
-	default:
-		/* todo */
-		break;
-	}
-
-	free(arg);
-}
-
-static enum event_type get_type(int ch)
-{
-	if (ch == '\n')
-		return EVENT_NEWLINE;
-	if (isspace(ch))
-		return EVENT_SPACE;
-	if (isalnum(ch) || ch == '_')
-		return EVENT_ITEM;
-	if (ch == '\'')
-		return EVENT_SQUOTE;
-	if (ch == '"')
-		return EVENT_DQUOTE;
-	if (!isprint(ch))
-		return EVENT_NONE;
-	if (ch == '(' || ch == ')' || ch == ',')
-		return EVENT_DELIM;
-
-	return EVENT_OP;
-}
-
-static int __read_char(void)
-{
-	if (input_buf_ptr >= input_buf_siz)
-		return -1;
-
-	return input_buf[input_buf_ptr++];
-}
-
-static int __peek_char(void)
-{
-	if (input_buf_ptr >= input_buf_siz)
-		return -1;
-
-	return input_buf[input_buf_ptr];
-}
-
-static enum event_type __read_token(char **tok)
-{
-	char buf[BUFSIZ];
-	int ch, last_ch, quote_ch, next_ch;
-	int i = 0;
-	int tok_size = 0;
-	enum event_type type;
-
-	*tok = NULL;
-
-
-	ch = __read_char();
-	if (ch < 0)
-		return EVENT_NONE;
-
-	type = get_type(ch);
-	if (type == EVENT_NONE)
-		return type;
-
-	buf[i++] = ch;
-
-	switch (type) {
-	case EVENT_NEWLINE:
-	case EVENT_DELIM:
-		*tok = malloc_or_die(2);
-		(*tok)[0] = ch;
-		(*tok)[1] = 0;
-		return type;
-
-	case EVENT_OP:
-		switch (ch) {
-		case '-':
-			next_ch = __peek_char();
-			if (next_ch == '>') {
-				buf[i++] = __read_char();
-				break;
-			}
-			/* fall through */
-		case '+':
-		case '|':
-		case '&':
-		case '>':
-		case '<':
-			last_ch = ch;
-			ch = __peek_char();
-			if (ch != last_ch)
-				goto test_equal;
-			buf[i++] = __read_char();
-			switch (last_ch) {
-			case '>':
-			case '<':
-				goto test_equal;
-			default:
-				break;
-			}
-			break;
-		case '!':
-		case '=':
-			goto test_equal;
-		default: /* what should we do instead? */
-			break;
-		}
-		buf[i] = 0;
-		*tok = strdup(buf);
-		return type;
-
- test_equal:
-		ch = __peek_char();
-		if (ch == '=')
-			buf[i++] = __read_char();
-		break;
-
-	case EVENT_DQUOTE:
-	case EVENT_SQUOTE:
-		/* don't keep quotes */
-		i--;
-		quote_ch = ch;
-		last_ch = 0;
-		do {
-			if (i == (BUFSIZ - 1)) {
-				buf[i] = 0;
-				if (*tok) {
-					*tok = realloc(*tok, tok_size + BUFSIZ);
-					if (!*tok)
-						return EVENT_NONE;
-					strcat(*tok, buf);
-				} else
-					*tok = strdup(buf);
-
-				if (!*tok)
-					return EVENT_NONE;
-				tok_size += BUFSIZ;
-				i = 0;
-			}
-			last_ch = ch;
-			ch = __read_char();
-			buf[i++] = ch;
-			/* the '\' '\' will cancel itself */
-			if (ch == '\\' && last_ch == '\\')
-				last_ch = 0;
-		} while (ch != quote_ch || last_ch == '\\');
-		/* remove the last quote */
-		i--;
-		goto out;
-
-	case EVENT_ERROR ... EVENT_SPACE:
-	case EVENT_ITEM:
-	default:
-		break;
-	}
-
-	while (get_type(__peek_char()) == type) {
-		if (i == (BUFSIZ - 1)) {
-			buf[i] = 0;
-			if (*tok) {
-				*tok = realloc(*tok, tok_size + BUFSIZ);
-				if (!*tok)
-					return EVENT_NONE;
-				strcat(*tok, buf);
-			} else
-				*tok = strdup(buf);
-
-			if (!*tok)
-				return EVENT_NONE;
-			tok_size += BUFSIZ;
-			i = 0;
-		}
-		ch = __read_char();
-		buf[i++] = ch;
-	}
-
- out:
-	buf[i] = 0;
-	if (*tok) {
-		*tok = realloc(*tok, tok_size + i);
-		if (!*tok)
-			return EVENT_NONE;
-		strcat(*tok, buf);
-	} else
-		*tok = strdup(buf);
-	if (!*tok)
-		return EVENT_NONE;
-
-	return type;
-}
-
-static void free_token(char *tok)
-{
-	if (tok)
-		free(tok);
-}
-
-static enum event_type read_token(char **tok)
-{
-	enum event_type type;
-
-	for (;;) {
-		type = __read_token(tok);
-		if (type != EVENT_SPACE)
-			return type;
-
-		free_token(*tok);
-	}
-
-	/* not reached */
-	return EVENT_NONE;
-}
-
-/* no newline */
-static enum event_type read_token_item(char **tok)
-{
-	enum event_type type;
-
-	for (;;) {
-		type = __read_token(tok);
-		if (type != EVENT_SPACE && type != EVENT_NEWLINE)
-			return type;
-
-		free_token(*tok);
-	}
-
-	/* not reached */
-	return EVENT_NONE;
-}
-
-static int test_type(enum event_type type, enum event_type expect)
-{
-	if (type != expect) {
-		warning("Error: expected type %d but read %d",
-		    expect, type);
-		return -1;
-	}
-	return 0;
-}
-
-static int __test_type_token(enum event_type type, char *token,
-			     enum event_type expect, const char *expect_tok,
-			     bool warn)
-{
-	if (type != expect) {
-		if (warn)
-			warning("Error: expected type %d but read %d",
-				expect, type);
-		return -1;
-	}
-
-	if (strcmp(token, expect_tok) != 0) {
-		if (warn)
-			warning("Error: expected '%s' but read '%s'",
-				expect_tok, token);
-		return -1;
-	}
-	return 0;
-}
-
-static int test_type_token(enum event_type type, char *token,
-			   enum event_type expect, const char *expect_tok)
-{
-	return __test_type_token(type, token, expect, expect_tok, true);
-}
-
-static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
-{
-	enum event_type type;
-
-	if (newline_ok)
-		type = read_token(tok);
-	else
-		type = read_token_item(tok);
-	return test_type(type, expect);
-}
-
-static int read_expect_type(enum event_type expect, char **tok)
-{
-	return __read_expect_type(expect, tok, 1);
-}
-
-static int __read_expected(enum event_type expect, const char *str,
-			   int newline_ok, bool warn)
-{
-	enum event_type type;
-	char *token;
+	static int offset;
+	static int size;
 	int ret;
 
-	if (newline_ok)
-		type = read_token(&token);
-	else
-		type = read_token_item(&token);
-
-	ret = __test_type_token(type, token, expect, str, warn);
-
-	free_token(token);
-
-	return ret;
-}
-
-static int read_expected(enum event_type expect, const char *str)
-{
-	return __read_expected(expect, str, 1, true);
-}
-
-static int read_expected_item(enum event_type expect, const char *str)
-{
-	return __read_expected(expect, str, 0, true);
-}
-
-static char *event_read_name(void)
-{
-	char *token;
-
-	if (read_expected(EVENT_ITEM, "name") < 0)
-		return NULL;
-
-	if (read_expected(EVENT_OP, ":") < 0)
-		return NULL;
-
-	if (read_expect_type(EVENT_ITEM, &token) < 0)
-		goto fail;
-
-	return token;
-
- fail:
-	free_token(token);
-	return NULL;
-}
-
-static int event_read_id(void)
-{
-	char *token;
-	int id = -1;
-
-	if (read_expected_item(EVENT_ITEM, "ID") < 0)
-		return -1;
-
-	if (read_expected(EVENT_OP, ":") < 0)
-		return -1;
-
-	if (read_expect_type(EVENT_ITEM, &token) < 0)
-		goto free;
-
-	id = strtoul(token, NULL, 0);
-
- free:
-	free_token(token);
-	return id;
-}
-
-static int field_is_string(struct format_field *field)
-{
-	if ((field->flags & FIELD_IS_ARRAY) &&
-	    (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
-	     !strstr(field->type, "s8")))
-		return 1;
-
-	return 0;
-}
-
-static int field_is_dynamic(struct format_field *field)
-{
-	if (!strncmp(field->type, "__data_loc", 10))
-		return 1;
-
-	return 0;
-}
-
-static int event_read_fields(struct event *event, struct format_field **fields)
-{
-	struct format_field *field = NULL;
-	enum event_type type;
-	char *token;
-	char *last_token;
-	int count = 0;
-
-	do {
-		type = read_token(&token);
-		if (type == EVENT_NEWLINE) {
-			free_token(token);
-			return count;
-		}
-
-		count++;
-
-		if (test_type_token(type, token, EVENT_ITEM, "field"))
-			goto fail;
-		free_token(token);
-
-		type = read_token(&token);
-		/*
-		 * The ftrace fields may still use the "special" name.
-		 * Just ignore it.
-		 */
-		if (event->flags & EVENT_FL_ISFTRACE &&
-		    type == EVENT_ITEM && strcmp(token, "special") == 0) {
-			free_token(token);
-			type = read_token(&token);
-		}
-
-		if (test_type_token(type, token, EVENT_OP, ":") < 0)
-			return -1;
-
-		if (read_expect_type(EVENT_ITEM, &token) < 0)
-			goto fail;
-
-		last_token = token;
-
-		field = malloc_or_die(sizeof(*field));
-		memset(field, 0, sizeof(*field));
-
-		/* read the rest of the type */
-		for (;;) {
-			type = read_token(&token);
-			if (type == EVENT_ITEM ||
-			    (type == EVENT_OP && strcmp(token, "*") == 0) ||
-			    /*
-			     * Some of the ftrace fields are broken and have
-			     * an illegal "." in them.
-			     */
-			    (event->flags & EVENT_FL_ISFTRACE &&
-			     type == EVENT_OP && strcmp(token, ".") == 0)) {
-
-				if (strcmp(token, "*") == 0)
-					field->flags |= FIELD_IS_POINTER;
-
-				if (field->type) {
-					field->type = realloc(field->type,
-							      strlen(field->type) +
-							      strlen(last_token) + 2);
-					strcat(field->type, " ");
-					strcat(field->type, last_token);
-				} else
-					field->type = last_token;
-				last_token = token;
-				continue;
-			}
-
-			break;
-		}
-
-		if (!field->type) {
-			die("no type found");
-			goto fail;
-		}
-		field->name = last_token;
-
-		if (test_type(type, EVENT_OP))
-			goto fail;
-
-		if (strcmp(token, "[") == 0) {
-			enum event_type last_type = type;
-			char *brackets = token;
-			int len;
-
-			field->flags |= FIELD_IS_ARRAY;
-
-			type = read_token(&token);
-		        while (strcmp(token, "]") != 0) {
-				if (last_type == EVENT_ITEM &&
-				    type == EVENT_ITEM)
-					len = 2;
-				else
-					len = 1;
-				last_type = type;
-
-				brackets = realloc(brackets,
-						   strlen(brackets) +
-						   strlen(token) + len);
-				if (len == 2)
-					strcat(brackets, " ");
-				strcat(brackets, token);
-				free_token(token);
-				type = read_token(&token);
-				if (type == EVENT_NONE) {
-					die("failed to find token");
-					goto fail;
-				}
-			}
-
-			free_token(token);
-
-			brackets = realloc(brackets, strlen(brackets) + 2);
-			strcat(brackets, "]");
-
-			/* add brackets to type */
-
-			type = read_token(&token);
-			/*
-			 * If the next token is not an OP, then it is of
-			 * the format: type [] item;
-			 */
-			if (type == EVENT_ITEM) {
-				field->type = realloc(field->type,
-						      strlen(field->type) +
-						      strlen(field->name) +
-						      strlen(brackets) + 2);
-				strcat(field->type, " ");
-				strcat(field->type, field->name);
-				free_token(field->name);
-				strcat(field->type, brackets);
-				field->name = token;
-				type = read_token(&token);
-			} else {
-				field->type = realloc(field->type,
-						      strlen(field->type) +
-						      strlen(brackets) + 1);
-				strcat(field->type, brackets);
-			}
-			free(brackets);
-		}
-
-		if (field_is_string(field)) {
-			field->flags |= FIELD_IS_STRING;
-			if (field_is_dynamic(field))
-				field->flags |= FIELD_IS_DYNAMIC;
-		}
-
-		if (test_type_token(type, token,  EVENT_OP, ";"))
-			goto fail;
-		free_token(token);
-
-		if (read_expected(EVENT_ITEM, "offset") < 0)
-			goto fail_expect;
-
-		if (read_expected(EVENT_OP, ":") < 0)
-			goto fail_expect;
-
-		if (read_expect_type(EVENT_ITEM, &token))
-			goto fail;
-		field->offset = strtoul(token, NULL, 0);
-		free_token(token);
-
-		if (read_expected(EVENT_OP, ";") < 0)
-			goto fail_expect;
-
-		if (read_expected(EVENT_ITEM, "size") < 0)
-			goto fail_expect;
-
-		if (read_expected(EVENT_OP, ":") < 0)
-			goto fail_expect;
-
-		if (read_expect_type(EVENT_ITEM, &token))
-			goto fail;
-		field->size = strtoul(token, NULL, 0);
-		free_token(token);
-
-		if (read_expected(EVENT_OP, ";") < 0)
-			goto fail_expect;
-
-		type = read_token(&token);
-		if (type != EVENT_NEWLINE) {
-			/* newer versions of the kernel have a "signed" type */
-			if (test_type_token(type, token, EVENT_ITEM, "signed"))
-				goto fail;
-
-			free_token(token);
-
-			if (read_expected(EVENT_OP, ":") < 0)
-				goto fail_expect;
-
-			if (read_expect_type(EVENT_ITEM, &token))
-				goto fail;
-
-			if (strtoul(token, NULL, 0))
-				field->flags |= FIELD_IS_SIGNED;
-
-			free_token(token);
-			if (read_expected(EVENT_OP, ";") < 0)
-				goto fail_expect;
-
-			if (read_expect_type(EVENT_NEWLINE, &token))
-				goto fail;
-		}
-
-		free_token(token);
-
-		*fields = field;
-		fields = &field->next;
-
-	} while (1);
-
-	return 0;
-
-fail:
-	free_token(token);
-fail_expect:
-	if (field)
-		free(field);
-	return -1;
-}
-
-static int event_read_format(struct event *event)
-{
-	char *token;
-	int ret;
-
-	if (read_expected_item(EVENT_ITEM, "format") < 0)
-		return -1;
-
-	if (read_expected(EVENT_OP, ":") < 0)
-		return -1;
-
-	if (read_expect_type(EVENT_NEWLINE, &token))
-		goto fail;
-	free_token(token);
-
-	ret = event_read_fields(event, &event->format.common_fields);
-	if (ret < 0)
-		return ret;
-	event->format.nr_common = ret;
-
-	ret = event_read_fields(event, &event->format.fields);
-	if (ret < 0)
-		return ret;
-	event->format.nr_fields = ret;
-
-	return 0;
-
- fail:
-	free_token(token);
-	return -1;
-}
-
-enum event_type
-process_arg_token(struct event *event, struct print_arg *arg,
-		  char **tok, enum event_type type);
-
-static enum event_type
-process_arg(struct event *event, struct print_arg *arg, char **tok)
-{
-	enum event_type type;
-	char *token;
-
-	type = read_token(&token);
-	*tok = token;
-
-	return process_arg_token(event, arg, tok, type);
-}
-
-static enum event_type
-process_cond(struct event *event, struct print_arg *top, char **tok)
-{
-	struct print_arg *arg, *left, *right;
-	enum event_type type;
-	char *token = NULL;
-
-	arg = malloc_or_die(sizeof(*arg));
-	memset(arg, 0, sizeof(*arg));
-
-	left = malloc_or_die(sizeof(*left));
-
-	right = malloc_or_die(sizeof(*right));
-
-	arg->type = PRINT_OP;
-	arg->op.left = left;
-	arg->op.right = right;
-
-	*tok = NULL;
-	type = process_arg(event, left, &token);
-	if (test_type_token(type, token, EVENT_OP, ":"))
-		goto out_free;
-
-	arg->op.op = token;
-
-	type = process_arg(event, right, &token);
-
-	top->op.right = arg;
-
-	*tok = token;
-	return type;
-
-out_free:
-	free_token(*tok);
-	free(right);
-	free(left);
-	free_arg(arg);
-	return EVENT_ERROR;
-}
-
-static enum event_type
-process_array(struct event *event, struct print_arg *top, char **tok)
-{
-	struct print_arg *arg;
-	enum event_type type;
-	char *token = NULL;
-
-	arg = malloc_or_die(sizeof(*arg));
-	memset(arg, 0, sizeof(*arg));
-
-	*tok = NULL;
-	type = process_arg(event, arg, &token);
-	if (test_type_token(type, token, EVENT_OP, "]"))
-		goto out_free;
-
-	top->op.right = arg;
-
-	free_token(token);
-	type = read_token_item(&token);
-	*tok = token;
-
-	return type;
-
-out_free:
-	free_token(*tok);
-	free_arg(arg);
-	return EVENT_ERROR;
-}
-
-static int get_op_prio(char *op)
-{
-	if (!op[1]) {
-		switch (op[0]) {
-		case '*':
-		case '/':
-		case '%':
-			return 6;
-		case '+':
-		case '-':
-			return 7;
-			/* '>>' and '<<' are 8 */
-		case '<':
-		case '>':
-			return 9;
-			/* '==' and '!=' are 10 */
-		case '&':
-			return 11;
-		case '^':
-			return 12;
-		case '|':
-			return 13;
-		case '?':
-			return 16;
-		default:
-			die("unknown op '%c'", op[0]);
-			return -1;
-		}
-	} else {
-		if (strcmp(op, "++") == 0 ||
-		    strcmp(op, "--") == 0) {
-			return 3;
-		} else if (strcmp(op, ">>") == 0 ||
-			   strcmp(op, "<<") == 0) {
-			return 8;
-		} else if (strcmp(op, ">=") == 0 ||
-			   strcmp(op, "<=") == 0) {
-			return 9;
-		} else if (strcmp(op, "==") == 0 ||
-			   strcmp(op, "!=") == 0) {
-			return 10;
-		} else if (strcmp(op, "&&") == 0) {
-			return 14;
-		} else if (strcmp(op, "||") == 0) {
-			return 15;
-		} else {
-			die("unknown op '%s'", op);
-			return -1;
-		}
-	}
-}
-
-static void set_op_prio(struct print_arg *arg)
-{
-
-	/* single ops are the greatest */
-	if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
-		arg->op.prio = 0;
-		return;
-	}
-
-	arg->op.prio = get_op_prio(arg->op.op);
-}
-
-static enum event_type
-process_op(struct event *event, struct print_arg *arg, char **tok)
-{
-	struct print_arg *left, *right = NULL;
-	enum event_type type;
-	char *token;
-
-	/* the op is passed in via tok */
-	token = *tok;
-
-	if (arg->type == PRINT_OP && !arg->op.left) {
-		/* handle single op */
-		if (token[1]) {
-			die("bad op token %s", token);
-			return EVENT_ERROR;
-		}
-		switch (token[0]) {
-		case '!':
-		case '+':
-		case '-':
-			break;
-		default:
-			die("bad op token %s", token);
-			return EVENT_ERROR;
-		}
-
-		/* make an empty left */
-		left = malloc_or_die(sizeof(*left));
-		left->type = PRINT_NULL;
-		arg->op.left = left;
-
-		right = malloc_or_die(sizeof(*right));
-		arg->op.right = right;
-
-		type = process_arg(event, right, tok);
-
-	} else if (strcmp(token, "?") == 0) {
-
-		left = malloc_or_die(sizeof(*left));
-		/* copy the top arg to the left */
-		*left = *arg;
-
-		arg->type = PRINT_OP;
-		arg->op.op = token;
-		arg->op.left = left;
-		arg->op.prio = 0;
-
-		type = process_cond(event, arg, tok);
-
-	} else if (strcmp(token, ">>") == 0 ||
-		   strcmp(token, "<<") == 0 ||
-		   strcmp(token, "&") == 0 ||
-		   strcmp(token, "|") == 0 ||
-		   strcmp(token, "&&") == 0 ||
-		   strcmp(token, "||") == 0 ||
-		   strcmp(token, "-") == 0 ||
-		   strcmp(token, "+") == 0 ||
-		   strcmp(token, "*") == 0 ||
-		   strcmp(token, "^") == 0 ||
-		   strcmp(token, "/") == 0 ||
-		   strcmp(token, "<") == 0 ||
-		   strcmp(token, ">") == 0 ||
-		   strcmp(token, "==") == 0 ||
-		   strcmp(token, "!=") == 0) {
-
-		left = malloc_or_die(sizeof(*left));
-
-		/* copy the top arg to the left */
-		*left = *arg;
-
-		arg->type = PRINT_OP;
-		arg->op.op = token;
-		arg->op.left = left;
-
-		set_op_prio(arg);
-
-		right = malloc_or_die(sizeof(*right));
-
-		type = read_token_item(&token);
-		*tok = token;
-
-		/* could just be a type pointer */
-		if ((strcmp(arg->op.op, "*") == 0) &&
-		    type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
-			if (left->type != PRINT_ATOM)
-				die("bad pointer type");
-			left->atom.atom = realloc(left->atom.atom,
-					    sizeof(left->atom.atom) + 3);
-			strcat(left->atom.atom, " *");
-			*arg = *left;
-			free(arg);
-
-			return type;
-		}
-
-		type = process_arg_token(event, right, tok, type);
-
-		arg->op.right = right;
-
-	} else if (strcmp(token, "[") == 0) {
-
-		left = malloc_or_die(sizeof(*left));
-		*left = *arg;
-
-		arg->type = PRINT_OP;
-		arg->op.op = token;
-		arg->op.left = left;
-
-		arg->op.prio = 0;
-		type = process_array(event, arg, tok);
-
-	} else {
-		warning("unknown op '%s'", token);
-		event->flags |= EVENT_FL_FAILED;
-		/* the arg is now the left side */
-		return EVENT_NONE;
-	}
-
-	if (type == EVENT_OP) {
-		int prio;
-
-		/* higher prios need to be closer to the root */
-		prio = get_op_prio(*tok);
-
-		if (prio > arg->op.prio)
-			return process_op(event, arg, tok);
-
-		return process_op(event, right, tok);
-	}
-
-	return type;
-}
-
-static enum event_type
-process_entry(struct event *event __unused, struct print_arg *arg,
-	      char **tok)
-{
-	enum event_type type;
-	char *field;
-	char *token;
-
-	if (read_expected(EVENT_OP, "->") < 0)
-		return EVENT_ERROR;
-
-	if (read_expect_type(EVENT_ITEM, &token) < 0)
-		goto fail;
-	field = token;
-
-	arg->type = PRINT_FIELD;
-	arg->field.name = field;
-
-	if (is_flag_field) {
-		arg->field.field = find_any_field(event, arg->field.name);
-		arg->field.field->flags |= FIELD_IS_FLAG;
-		is_flag_field = 0;
-	} else if (is_symbolic_field) {
-		arg->field.field = find_any_field(event, arg->field.name);
-		arg->field.field->flags |= FIELD_IS_SYMBOLIC;
-		is_symbolic_field = 0;
-	}
-
-	type = read_token(&token);
-	*tok = token;
-
-	return type;
-
-fail:
-	free_token(token);
-	return EVENT_ERROR;
-}
-
-static char *arg_eval (struct print_arg *arg);
-
-static long long arg_num_eval(struct print_arg *arg)
-{
-	long long left, right;
-	long long val = 0;
-
-	switch (arg->type) {
-	case PRINT_ATOM:
-		val = strtoll(arg->atom.atom, NULL, 0);
-		break;
-	case PRINT_TYPE:
-		val = arg_num_eval(arg->typecast.item);
-		break;
-	case PRINT_OP:
-		switch (arg->op.op[0]) {
-		case '|':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			if (arg->op.op[1])
-				val = left || right;
-			else
-				val = left | right;
-			break;
-		case '&':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			if (arg->op.op[1])
-				val = left && right;
-			else
-				val = left & right;
-			break;
-		case '<':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			switch (arg->op.op[1]) {
-			case 0:
-				val = left < right;
-				break;
-			case '<':
-				val = left << right;
-				break;
-			case '=':
-				val = left <= right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '>':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			switch (arg->op.op[1]) {
-			case 0:
-				val = left > right;
-				break;
-			case '>':
-				val = left >> right;
-				break;
-			case '=':
-				val = left >= right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '=':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-
-			if (arg->op.op[1] != '=')
-				die("unknown op '%s'", arg->op.op);
-
-			val = left == right;
-			break;
-		case '!':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-
-			switch (arg->op.op[1]) {
-			case '=':
-				val = left != right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '+':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			val = left + right;
-			break;
-		default:
-			die("unknown op '%s'", arg->op.op);
-		}
-		break;
-
-	case PRINT_NULL:
-	case PRINT_FIELD ... PRINT_SYMBOL:
-	case PRINT_STRING:
-	default:
-		die("invalid eval type %d", arg->type);
-
-	}
-	return val;
-}
-
-static char *arg_eval (struct print_arg *arg)
-{
-	long long val;
-	static char buf[20];
-
-	switch (arg->type) {
-	case PRINT_ATOM:
-		return arg->atom.atom;
-	case PRINT_TYPE:
-		return arg_eval(arg->typecast.item);
-	case PRINT_OP:
-		val = arg_num_eval(arg);
-		sprintf(buf, "%lld", val);
-		return buf;
-
-	case PRINT_NULL:
-	case PRINT_FIELD ... PRINT_SYMBOL:
-	case PRINT_STRING:
-	default:
-		die("invalid eval type %d", arg->type);
-		break;
-	}
-
-	return NULL;
-}
-
-static enum event_type
-process_fields(struct event *event, struct print_flag_sym **list, char **tok)
-{
-	enum event_type type;
-	struct print_arg *arg = NULL;
-	struct print_flag_sym *field;
-	char *token = NULL;
-	char *value;
-
-	do {
-		free_token(token);
-		type = read_token_item(&token);
-		if (test_type_token(type, token, EVENT_OP, "{"))
-			break;
-
-		arg = malloc_or_die(sizeof(*arg));
-
-		free_token(token);
-		type = process_arg(event, arg, &token);
-
-		if (type == EVENT_OP)
-			type = process_op(event, arg, &token);
-
-		if (type == EVENT_ERROR)
-			goto out_free;
-
-		if (test_type_token(type, token, EVENT_DELIM, ","))
-			goto out_free;
-
-		field = malloc_or_die(sizeof(*field));
-		memset(field, 0, sizeof(*field));
-
-		value = arg_eval(arg);
-		field->value = strdup(value);
-
-		free_token(token);
-		type = process_arg(event, arg, &token);
-		if (test_type_token(type, token, EVENT_OP, "}"))
-			goto out_free;
-
-		value = arg_eval(arg);
-		field->str = strdup(value);
-		free_arg(arg);
-		arg = NULL;
-
-		*list = field;
-		list = &field->next;
-
-		free_token(token);
-		type = read_token_item(&token);
-	} while (type == EVENT_DELIM && strcmp(token, ",") == 0);
-
-	*tok = token;
-	return type;
-
-out_free:
-	free_arg(arg);
-	free_token(token);
-
-	return EVENT_ERROR;
-}
-
-static enum event_type
-process_flags(struct event *event, struct print_arg *arg, char **tok)
-{
-	struct print_arg *field;
-	enum event_type type;
-	char *token;
-
-	memset(arg, 0, sizeof(*arg));
-	arg->type = PRINT_FLAGS;
-
-	if (read_expected_item(EVENT_DELIM, "(") < 0)
-		return EVENT_ERROR;
-
-	field = malloc_or_die(sizeof(*field));
-
-	type = process_arg(event, field, &token);
-	while (type == EVENT_OP)
-		type = process_op(event, field, &token);
-	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto out_free;
-
-	arg->flags.field = field;
-
-	type = read_token_item(&token);
-	if (event_item_type(type)) {
-		arg->flags.delim = token;
-		type = read_token_item(&token);
-	}
-
-	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto out_free;
-
-	type = process_fields(event, &arg->flags.flags, &token);
-	if (test_type_token(type, token, EVENT_DELIM, ")"))
-		goto out_free;
-
-	free_token(token);
-	type = read_token_item(tok);
-	return type;
-
-out_free:
-	free_token(token);
-	return EVENT_ERROR;
-}
-
-static enum event_type
-process_symbols(struct event *event, struct print_arg *arg, char **tok)
-{
-	struct print_arg *field;
-	enum event_type type;
-	char *token;
-
-	memset(arg, 0, sizeof(*arg));
-	arg->type = PRINT_SYMBOL;
-
-	if (read_expected_item(EVENT_DELIM, "(") < 0)
-		return EVENT_ERROR;
-
-	field = malloc_or_die(sizeof(*field));
-
-	type = process_arg(event, field, &token);
-	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto out_free;
-
-	arg->symbol.field = field;
-
-	type = process_fields(event, &arg->symbol.symbols, &token);
-	if (test_type_token(type, token, EVENT_DELIM, ")"))
-		goto out_free;
-
-	free_token(token);
-	type = read_token_item(tok);
-	return type;
-
-out_free:
-	free_token(token);
-	return EVENT_ERROR;
-}
-
-static enum event_type
-process_paren(struct event *event, struct print_arg *arg, char **tok)
-{
-	struct print_arg *item_arg;
-	enum event_type type;
-	char *token;
-
-	type = process_arg(event, arg, &token);
-
-	if (type == EVENT_ERROR)
-		return EVENT_ERROR;
-
-	if (type == EVENT_OP)
-		type = process_op(event, arg, &token);
-
-	if (type == EVENT_ERROR)
-		return EVENT_ERROR;
-
-	if (test_type_token(type, token, EVENT_DELIM, ")")) {
-		free_token(token);
-		return EVENT_ERROR;
-	}
-
-	free_token(token);
-	type = read_token_item(&token);
-
-	/*
-	 * If the next token is an item or another open paren, then
-	 * this was a typecast.
-	 */
-	if (event_item_type(type) ||
-	    (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
-
-		/* make this a typecast and contine */
-
-		/* prevous must be an atom */
-		if (arg->type != PRINT_ATOM)
-			die("previous needed to be PRINT_ATOM");
-
-		item_arg = malloc_or_die(sizeof(*item_arg));
-
-		arg->type = PRINT_TYPE;
-		arg->typecast.type = arg->atom.atom;
-		arg->typecast.item = item_arg;
-		type = process_arg_token(event, item_arg, &token, type);
-
-	}
-
-	*tok = token;
-	return type;
-}
-
-
-static enum event_type
-process_str(struct event *event __unused, struct print_arg *arg, char **tok)
-{
-	enum event_type type;
-	char *token;
-
-	if (read_expected(EVENT_DELIM, "(") < 0)
-		return EVENT_ERROR;
-
-	if (read_expect_type(EVENT_ITEM, &token) < 0)
-		goto fail;
-
-	arg->type = PRINT_STRING;
-	arg->string.string = token;
-	arg->string.offset = -1;
-
-	if (read_expected(EVENT_DELIM, ")") < 0)
-		return EVENT_ERROR;
-
-	type = read_token(&token);
-	*tok = token;
-
-	return type;
-fail:
-	free_token(token);
-	return EVENT_ERROR;
-}
-
-enum event_type
-process_arg_token(struct event *event, struct print_arg *arg,
-		  char **tok, enum event_type type)
-{
-	char *token;
-	char *atom;
-
-	token = *tok;
-
-	switch (type) {
-	case EVENT_ITEM:
-		if (strcmp(token, "REC") == 0) {
-			free_token(token);
-			type = process_entry(event, arg, &token);
-		} else if (strcmp(token, "__print_flags") == 0) {
-			free_token(token);
-			is_flag_field = 1;
-			type = process_flags(event, arg, &token);
-		} else if (strcmp(token, "__print_symbolic") == 0) {
-			free_token(token);
-			is_symbolic_field = 1;
-			type = process_symbols(event, arg, &token);
-		} else if (strcmp(token, "__get_str") == 0) {
-			free_token(token);
-			type = process_str(event, arg, &token);
-		} else {
-			atom = token;
-			/* test the next token */
-			type = read_token_item(&token);
-
-			/* atoms can be more than one token long */
-			while (type == EVENT_ITEM) {
-				atom = realloc(atom, strlen(atom) + strlen(token) + 2);
-				strcat(atom, " ");
-				strcat(atom, token);
-				free_token(token);
-				type = read_token_item(&token);
-			}
-
-			/* todo, test for function */
-
-			arg->type = PRINT_ATOM;
-			arg->atom.atom = atom;
-		}
-		break;
-	case EVENT_DQUOTE:
-	case EVENT_SQUOTE:
-		arg->type = PRINT_ATOM;
-		arg->atom.atom = token;
-		type = read_token_item(&token);
-		break;
-	case EVENT_DELIM:
-		if (strcmp(token, "(") == 0) {
-			free_token(token);
-			type = process_paren(event, arg, &token);
-			break;
-		}
-	case EVENT_OP:
-		/* handle single ops */
-		arg->type = PRINT_OP;
-		arg->op.op = token;
-		arg->op.left = NULL;
-		type = process_op(event, arg, &token);
-
-		break;
-
-	case EVENT_ERROR ... EVENT_NEWLINE:
-	default:
-		die("unexpected type %d", type);
-	}
-	*tok = token;
-
-	return type;
-}
-
-static int event_read_print_args(struct event *event, struct print_arg **list)
-{
-	enum event_type type = EVENT_ERROR;
-	struct print_arg *arg;
-	char *token;
-	int args = 0;
-
-	do {
-		if (type == EVENT_NEWLINE) {
-			free_token(token);
-			type = read_token_item(&token);
-			continue;
-		}
-
-		arg = malloc_or_die(sizeof(*arg));
-		memset(arg, 0, sizeof(*arg));
-
-		type = process_arg(event, arg, &token);
-
-		if (type == EVENT_ERROR) {
-			free_arg(arg);
-			return -1;
-		}
-
-		*list = arg;
-		args++;
-
-		if (type == EVENT_OP) {
-			type = process_op(event, arg, &token);
-			list = &arg->next;
-			continue;
-		}
-
-		if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
-			free_token(token);
-			*list = arg;
-			list = &arg->next;
-			continue;
-		}
-		break;
-	} while (type != EVENT_NONE);
-
-	if (type != EVENT_NONE)
-		free_token(token);
-
-	return args;
-}
-
-static int event_read_print(struct event *event)
-{
-	enum event_type type;
-	char *token;
-	int ret;
-
-	if (read_expected_item(EVENT_ITEM, "print") < 0)
-		return -1;
-
-	if (read_expected(EVENT_ITEM, "fmt") < 0)
-		return -1;
-
-	if (read_expected(EVENT_OP, ":") < 0)
-		return -1;
-
-	if (read_expect_type(EVENT_DQUOTE, &token) < 0)
-		goto fail;
-
- concat:
-	event->print_fmt.format = token;
-	event->print_fmt.args = NULL;
-
-	/* ok to have no arg */
-	type = read_token_item(&token);
-
-	if (type == EVENT_NONE)
-		return 0;
-
-	/* Handle concatination of print lines */
-	if (type == EVENT_DQUOTE) {
-		char *cat;
-
-		cat = malloc_or_die(strlen(event->print_fmt.format) +
-				    strlen(token) + 1);
-		strcpy(cat, event->print_fmt.format);
-		strcat(cat, token);
-		free_token(token);
-		free_token(event->print_fmt.format);
-		event->print_fmt.format = NULL;
-		token = cat;
-		goto concat;
-	}
-
-	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto fail;
-
-	free_token(token);
-
-	ret = event_read_print_args(event, &event->print_fmt.args);
+	ret = get_common_field(context, &size, &offset,
+			       "common_lock_depth");
 	if (ret < 0)
 		return -1;
 
 	return ret;
-
- fail:
-	free_token(token);
-	return -1;
 }
 
-static struct format_field *
-find_common_field(struct event *event, const char *name)
+int common_flags(struct scripting_context *context)
 {
-	struct format_field *format;
+	static int offset;
+	static int size;
+	int ret;
 
-	for (format = event->format.common_fields;
-	     format; format = format->next) {
-		if (strcmp(format->name, name) == 0)
-			break;
-	}
+	ret = get_common_field(context, &size, &offset,
+			       "common_flags");
+	if (ret < 0)
+		return -1;
 
-	return format;
+	return ret;
 }
 
-static struct format_field *
-find_field(struct event *event, const char *name)
+int common_pc(struct scripting_context *context)
 {
-	struct format_field *format;
+	static int offset;
+	static int size;
+	int ret;
 
-	for (format = event->format.fields;
-	     format; format = format->next) {
-		if (strcmp(format->name, name) == 0)
-			break;
-	}
+	ret = get_common_field(context, &size, &offset,
+			       "common_preempt_count");
+	if (ret < 0)
+		return -1;
 
-	return format;
-}
-
-static struct format_field *
-find_any_field(struct event *event, const char *name)
-{
-	struct format_field *format;
-
-	format = find_common_field(event, name);
-	if (format)
-		return format;
-	return find_field(event, name);
-}
-
-unsigned long long read_size(void *ptr, int size)
-{
-	switch (size) {
-	case 1:
-		return *(unsigned char *)ptr;
-	case 2:
-		return data2host2(ptr);
-	case 4:
-		return data2host4(ptr);
-	case 8:
-		return data2host8(ptr);
-	default:
-		/* BUG! */
-		return 0;
-	}
+	return ret;
 }
 
 unsigned long long
-raw_field_value(struct event *event, const char *name, void *data)
+raw_field_value(struct event_format *event, const char *name, void *data)
 {
 	struct format_field *field;
+	unsigned long long val;
 
-	field = find_any_field(event, name);
+	field = pevent_find_any_field(event, name);
 	if (!field)
 		return 0ULL;
 
-	return read_size(data + field->offset, field->size);
+	pevent_read_number_field(field, data, &val);
+
+	return val;
 }
 
-void *raw_field_ptr(struct event *event, const char *name, void *data)
+void *raw_field_ptr(struct event_format *event, const char *name, void *data)
 {
 	struct format_field *field;
 
-	field = find_any_field(event, name);
+	field = pevent_find_any_field(event, name);
 	if (!field)
 		return NULL;
 
@@ -1959,227 +150,172 @@
 	return data + field->offset;
 }
 
-static int get_common_info(const char *type, int *offset, int *size)
-{
-	struct event *event;
-	struct format_field *field;
-
-	/*
-	 * All events should have the same common elements.
-	 * Pick any event to find where the type is;
-	 */
-	if (!event_list)
-		die("no event_list!");
-
-	event = event_list;
-	field = find_common_field(event, type);
-	if (!field)
-		die("field '%s' not found", type);
-
-	*offset = field->offset;
-	*size = field->size;
-
-	return 0;
-}
-
-static int __parse_common(void *data, int *size, int *offset,
-			  const char *name)
-{
-	int ret;
-
-	if (!*size) {
-		ret = get_common_info(name, offset, size);
-		if (ret < 0)
-			return ret;
-	}
-	return read_size(data + *offset, *size);
-}
-
 int trace_parse_common_type(void *data)
 {
-	static int type_offset;
-	static int type_size;
+	struct pevent_record record;
 
-	return __parse_common(data, &type_size, &type_offset,
-			      "common_type");
+	record.data = data;
+	return pevent_data_type(pevent, &record);
 }
 
 int trace_parse_common_pid(void *data)
 {
-	static int pid_offset;
-	static int pid_size;
+	struct pevent_record record;
 
-	return __parse_common(data, &pid_size, &pid_offset,
-			      "common_pid");
+	record.data = data;
+	return pevent_data_pid(pevent, &record);
 }
 
-int parse_common_pc(void *data)
+unsigned long long read_size(void *ptr, int size)
 {
-	static int pc_offset;
-	static int pc_size;
-
-	return __parse_common(data, &pc_size, &pc_offset,
-			      "common_preempt_count");
+	return pevent_read_number(pevent, ptr, size);
 }
 
-int parse_common_flags(void *data)
+struct event_format *trace_find_event(int type)
 {
-	static int flags_offset;
-	static int flags_size;
-
-	return __parse_common(data, &flags_size, &flags_offset,
-			      "common_flags");
+	return pevent_find_event(pevent, type);
 }
 
-int parse_common_lock_depth(void *data)
+
+void print_trace_event(int cpu, void *data, int size)
 {
-	static int ld_offset;
-	static int ld_size;
-	int ret;
+	struct event_format *event;
+	struct pevent_record record;
+	struct trace_seq s;
+	int type;
 
-	ret = __parse_common(data, &ld_size, &ld_offset,
-			     "common_lock_depth");
-	if (ret < 0)
-		return -1;
+	type = trace_parse_common_type(data);
 
-	return ret;
-}
-
-struct event *trace_find_event(int id)
-{
-	struct event *event;
-
-	for (event = event_list; event; event = event->next) {
-		if (event->id == id)
-			break;
+	event = trace_find_event(type);
+	if (!event) {
+		warning("ug! no event found for type %d", type);
+		return;
 	}
-	return event;
+
+	memset(&record, 0, sizeof(record));
+	record.cpu = cpu;
+	record.size = size;
+	record.data = data;
+
+	trace_seq_init(&s);
+	pevent_print_event(pevent, &s, &record);
+	trace_seq_do_printf(&s);
+	printf("\n");
 }
 
-struct event *trace_find_next_event(struct event *event)
+void print_event(int cpu, void *data, int size, unsigned long long nsecs,
+		  char *comm)
 {
-	if (!event)
-		return event_list;
+	struct pevent_record record;
+	struct trace_seq s;
+	int pid;
 
-	return event->next;
+	pevent->latency_format = latency_format;
+
+	record.ts = nsecs;
+	record.cpu = cpu;
+	record.size = size;
+	record.data = data;
+	pid = pevent_data_pid(pevent, &record);
+
+	if (!pevent_pid_is_registered(pevent, pid))
+		pevent_register_comm(pevent, comm, pid);
+
+	trace_seq_init(&s);
+	pevent_print_event(pevent, &s, &record);
+	trace_seq_do_printf(&s);
+	printf("\n");
 }
 
-static unsigned long long eval_num_arg(void *data, int size,
-				   struct event *event, struct print_arg *arg)
+void parse_proc_kallsyms(char *file, unsigned int size __unused)
 {
-	unsigned long long val = 0;
-	unsigned long long left, right;
-	struct print_arg *larg;
+	unsigned long long addr;
+	char *func;
+	char *line;
+	char *next = NULL;
+	char *addr_str;
+	char *mod;
+	char ch;
 
-	switch (arg->type) {
-	case PRINT_NULL:
-		/* ?? */
-		return 0;
-	case PRINT_ATOM:
-		return strtoull(arg->atom.atom, NULL, 0);
-	case PRINT_FIELD:
-		if (!arg->field.field) {
-			arg->field.field = find_any_field(event, arg->field.name);
-			if (!arg->field.field)
-				die("field %s not found", arg->field.name);
-		}
-		/* must be a number */
-		val = read_size(data + arg->field.field->offset,
-				arg->field.field->size);
-		break;
-	case PRINT_FLAGS:
-	case PRINT_SYMBOL:
-		break;
-	case PRINT_TYPE:
-		return eval_num_arg(data, size, event, arg->typecast.item);
-	case PRINT_STRING:
-		return 0;
-		break;
-	case PRINT_OP:
-		if (strcmp(arg->op.op, "[") == 0) {
-			/*
-			 * Arrays are special, since we don't want
-			 * to read the arg as is.
-			 */
-			if (arg->op.left->type != PRINT_FIELD)
-				goto default_op; /* oops, all bets off */
-			larg = arg->op.left;
-			if (!larg->field.field) {
-				larg->field.field =
-					find_any_field(event, larg->field.name);
-				if (!larg->field.field)
-					die("field %s not found", larg->field.name);
-			}
-			right = eval_num_arg(data, size, event, arg->op.right);
-			val = read_size(data + larg->field.field->offset +
-					right * long_size, long_size);
-			break;
-		}
- default_op:
-		left = eval_num_arg(data, size, event, arg->op.left);
-		right = eval_num_arg(data, size, event, arg->op.right);
-		switch (arg->op.op[0]) {
-		case '|':
-			if (arg->op.op[1])
-				val = left || right;
-			else
-				val = left | right;
-			break;
-		case '&':
-			if (arg->op.op[1])
-				val = left && right;
-			else
-				val = left & right;
-			break;
-		case '<':
-			switch (arg->op.op[1]) {
-			case 0:
-				val = left < right;
-				break;
-			case '<':
-				val = left << right;
-				break;
-			case '=':
-				val = left <= right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '>':
-			switch (arg->op.op[1]) {
-			case 0:
-				val = left > right;
-				break;
-			case '>':
-				val = left >> right;
-				break;
-			case '=':
-				val = left >= right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '=':
-			if (arg->op.op[1] != '=')
-				die("unknown op '%s'", arg->op.op);
-			val = left == right;
-			break;
-		case '-':
-			val = left - right;
-			break;
-		case '+':
-			val = left + right;
-			break;
-		default:
-			die("unknown op '%s'", arg->op.op);
-		}
-		break;
-	default: /* not sure what to do there */
-		return 0;
+	line = strtok_r(file, "\n", &next);
+	while (line) {
+		mod = NULL;
+		sscanf(line, "%as %c %as\t[%as",
+		       (float *)(void *)&addr_str, /* workaround gcc warning */
+		       &ch, (float *)(void *)&func, (float *)(void *)&mod);
+		addr = strtoull(addr_str, NULL, 16);
+		free(addr_str);
+
+		/* truncate the extra ']' */
+		if (mod)
+			mod[strlen(mod) - 1] = 0;
+
+		pevent_register_function(pevent, func, addr, mod);
+		free(func);
+		free(mod);
+
+		line = strtok_r(NULL, "\n", &next);
 	}
-	return val;
+}
+
+void parse_ftrace_printk(char *file, unsigned int size __unused)
+{
+	unsigned long long addr;
+	char *printk;
+	char *line;
+	char *next = NULL;
+	char *addr_str;
+	char *fmt;
+
+	line = strtok_r(file, "\n", &next);
+	while (line) {
+		addr_str = strtok_r(line, ":", &fmt);
+		if (!addr_str) {
+			warning("printk format with empty entry");
+			break;
+		}
+		addr = strtoull(addr_str, NULL, 16);
+		/* fmt still has a space, skip it */
+		printk = strdup(fmt+1);
+		line = strtok_r(NULL, "\n", &next);
+		pevent_register_print_string(pevent, printk, addr);
+	}
+}
+
+int parse_ftrace_file(char *buf, unsigned long size)
+{
+	return pevent_parse_event(pevent, buf, size, "ftrace");
+}
+
+int parse_event_file(char *buf, unsigned long size, char *sys)
+{
+	return pevent_parse_event(pevent, buf, size, sys);
+}
+
+struct event_format *trace_find_next_event(struct event_format *event)
+{
+	static int idx;
+
+	if (!pevent->events)
+		return NULL;
+
+	if (!event) {
+		idx = 0;
+		return pevent->events[0];
+	}
+
+	if (idx < pevent->nr_events && event == pevent->events[idx]) {
+		idx++;
+		if (idx == pevent->nr_events)
+			return NULL;
+		return pevent->events[idx];
+	}
+
+	for (idx = 1; idx < pevent->nr_events; idx++) {
+		if (event == pevent->events[idx - 1])
+			return pevent->events[idx];
+	}
+	return NULL;
 }
 
 struct flag {
@@ -2221,933 +357,3 @@
 
 	return 0;
 }
-
-static void print_str_arg(void *data, int size,
-			  struct event *event, struct print_arg *arg)
-{
-	struct print_flag_sym *flag;
-	unsigned long long val, fval;
-	char *str;
-	int print;
-
-	switch (arg->type) {
-	case PRINT_NULL:
-		/* ?? */
-		return;
-	case PRINT_ATOM:
-		printf("%s", arg->atom.atom);
-		return;
-	case PRINT_FIELD:
-		if (!arg->field.field) {
-			arg->field.field = find_any_field(event, arg->field.name);
-			if (!arg->field.field)
-				die("field %s not found", arg->field.name);
-		}
-		str = malloc_or_die(arg->field.field->size + 1);
-		memcpy(str, data + arg->field.field->offset,
-		       arg->field.field->size);
-		str[arg->field.field->size] = 0;
-		printf("%s", str);
-		free(str);
-		break;
-	case PRINT_FLAGS:
-		val = eval_num_arg(data, size, event, arg->flags.field);
-		print = 0;
-		for (flag = arg->flags.flags; flag; flag = flag->next) {
-			fval = eval_flag(flag->value);
-			if (!val && !fval) {
-				printf("%s", flag->str);
-				break;
-			}
-			if (fval && (val & fval) == fval) {
-				if (print && arg->flags.delim)
-					printf("%s", arg->flags.delim);
-				printf("%s", flag->str);
-				print = 1;
-				val &= ~fval;
-			}
-		}
-		break;
-	case PRINT_SYMBOL:
-		val = eval_num_arg(data, size, event, arg->symbol.field);
-		for (flag = arg->symbol.symbols; flag; flag = flag->next) {
-			fval = eval_flag(flag->value);
-			if (val == fval) {
-				printf("%s", flag->str);
-				break;
-			}
-		}
-		break;
-
-	case PRINT_TYPE:
-		break;
-	case PRINT_STRING: {
-		int str_offset;
-
-		if (arg->string.offset == -1) {
-			struct format_field *f;
-
-			f = find_any_field(event, arg->string.string);
-			arg->string.offset = f->offset;
-		}
-		str_offset = *(int *)(data + arg->string.offset);
-		str_offset &= 0xffff;
-		printf("%s", ((char *)data) + str_offset);
-		break;
-	}
-	case PRINT_OP:
-		/*
-		 * The only op for string should be ? :
-		 */
-		if (arg->op.op[0] != '?')
-			return;
-		val = eval_num_arg(data, size, event, arg->op.left);
-		if (val)
-			print_str_arg(data, size, event, arg->op.right->op.left);
-		else
-			print_str_arg(data, size, event, arg->op.right->op.right);
-		break;
-	default:
-		/* well... */
-		break;
-	}
-}
-
-static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
-{
-	static struct format_field *field, *ip_field;
-	struct print_arg *args, *arg, **next;
-	unsigned long long ip, val;
-	char *ptr;
-	void *bptr;
-
-	if (!field) {
-		field = find_field(event, "buf");
-		if (!field)
-			die("can't find buffer field for binary printk");
-		ip_field = find_field(event, "ip");
-		if (!ip_field)
-			die("can't find ip field for binary printk");
-	}
-
-	ip = read_size(data + ip_field->offset, ip_field->size);
-
-	/*
-	 * The first arg is the IP pointer.
-	 */
-	args = malloc_or_die(sizeof(*args));
-	arg = args;
-	arg->next = NULL;
-	next = &arg->next;
-
-	arg->type = PRINT_ATOM;
-	arg->atom.atom = malloc_or_die(32);
-	sprintf(arg->atom.atom, "%lld", ip);
-
-	/* skip the first "%pf : " */
-	for (ptr = fmt + 6, bptr = data + field->offset;
-	     bptr < data + size && *ptr; ptr++) {
-		int ls = 0;
-
-		if (*ptr == '%') {
- process_again:
-			ptr++;
-			switch (*ptr) {
-			case '%':
-				break;
-			case 'l':
-				ls++;
-				goto process_again;
-			case 'L':
-				ls = 2;
-				goto process_again;
-			case '0' ... '9':
-				goto process_again;
-			case 'p':
-				ls = 1;
-				/* fall through */
-			case 'd':
-			case 'u':
-			case 'x':
-			case 'i':
-				/* the pointers are always 4 bytes aligned */
-				bptr = (void *)(((unsigned long)bptr + 3) &
-						~3);
-				switch (ls) {
-				case 0:
-				case 1:
-					ls = long_size;
-					break;
-				case 2:
-					ls = 8;
-				default:
-					break;
-				}
-				val = read_size(bptr, ls);
-				bptr += ls;
-				arg = malloc_or_die(sizeof(*arg));
-				arg->next = NULL;
-				arg->type = PRINT_ATOM;
-				arg->atom.atom = malloc_or_die(32);
-				sprintf(arg->atom.atom, "%lld", val);
-				*next = arg;
-				next = &arg->next;
-				break;
-			case 's':
-				arg = malloc_or_die(sizeof(*arg));
-				arg->next = NULL;
-				arg->type = PRINT_STRING;
-				arg->string.string = strdup(bptr);
-				bptr += strlen(bptr) + 1;
-				*next = arg;
-				next = &arg->next;
-			default:
-				break;
-			}
-		}
-	}
-
-	return args;
-}
-
-static void free_args(struct print_arg *args)
-{
-	struct print_arg *next;
-
-	while (args) {
-		next = args->next;
-
-		if (args->type == PRINT_ATOM)
-			free(args->atom.atom);
-		else
-			free(args->string.string);
-		free(args);
-		args = next;
-	}
-}
-
-static char *get_bprint_format(void *data, int size __unused, struct event *event)
-{
-	unsigned long long addr;
-	static struct format_field *field;
-	struct printk_map *printk;
-	char *format;
-	char *p;
-
-	if (!field) {
-		field = find_field(event, "fmt");
-		if (!field)
-			die("can't find format field for binary printk");
-		printf("field->offset = %d size=%d\n", field->offset, field->size);
-	}
-
-	addr = read_size(data + field->offset, field->size);
-
-	printk = find_printk(addr);
-	if (!printk) {
-		format = malloc_or_die(45);
-		sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
-			addr);
-		return format;
-	}
-
-	p = printk->printk;
-	/* Remove any quotes. */
-	if (*p == '"')
-		p++;
-	format = malloc_or_die(strlen(p) + 10);
-	sprintf(format, "%s : %s", "%pf", p);
-	/* remove ending quotes and new line since we will add one too */
-	p = format + strlen(format) - 1;
-	if (*p == '"')
-		*p = 0;
-
-	p -= 2;
-	if (strcmp(p, "\\n") == 0)
-		*p = 0;
-
-	return format;
-}
-
-static void pretty_print(void *data, int size, struct event *event)
-{
-	struct print_fmt *print_fmt = &event->print_fmt;
-	struct print_arg *arg = print_fmt->args;
-	struct print_arg *args = NULL;
-	const char *ptr = print_fmt->format;
-	unsigned long long val;
-	struct func_map *func;
-	const char *saveptr;
-	char *bprint_fmt = NULL;
-	char format[32];
-	int show_func;
-	int len;
-	int ls;
-
-	if (event->flags & EVENT_FL_ISFUNC)
-		ptr = " %pF <-- %pF";
-
-	if (event->flags & EVENT_FL_ISBPRINT) {
-		bprint_fmt = get_bprint_format(data, size, event);
-		args = make_bprint_args(bprint_fmt, data, size, event);
-		arg = args;
-		ptr = bprint_fmt;
-	}
-
-	for (; *ptr; ptr++) {
-		ls = 0;
-		if (*ptr == '\\') {
-			ptr++;
-			switch (*ptr) {
-			case 'n':
-				printf("\n");
-				break;
-			case 't':
-				printf("\t");
-				break;
-			case 'r':
-				printf("\r");
-				break;
-			case '\\':
-				printf("\\");
-				break;
-			default:
-				printf("%c", *ptr);
-				break;
-			}
-
-		} else if (*ptr == '%') {
-			saveptr = ptr;
-			show_func = 0;
- cont_process:
-			ptr++;
-			switch (*ptr) {
-			case '%':
-				printf("%%");
-				break;
-			case 'l':
-				ls++;
-				goto cont_process;
-			case 'L':
-				ls = 2;
-				goto cont_process;
-			case 'z':
-			case 'Z':
-			case '0' ... '9':
-				goto cont_process;
-			case 'p':
-				if (long_size == 4)
-					ls = 1;
-				else
-					ls = 2;
-
-				if (*(ptr+1) == 'F' ||
-				    *(ptr+1) == 'f') {
-					ptr++;
-					show_func = *ptr;
-				}
-
-				/* fall through */
-			case 'd':
-			case 'i':
-			case 'x':
-			case 'X':
-			case 'u':
-				if (!arg)
-					die("no argument match");
-
-				len = ((unsigned long)ptr + 1) -
-					(unsigned long)saveptr;
-
-				/* should never happen */
-				if (len > 32)
-					die("bad format!");
-
-				memcpy(format, saveptr, len);
-				format[len] = 0;
-
-				val = eval_num_arg(data, size, event, arg);
-				arg = arg->next;
-
-				if (show_func) {
-					func = find_func(val);
-					if (func) {
-						printf("%s", func->func);
-						if (show_func == 'F')
-							printf("+0x%llx",
-							       val - func->addr);
-						break;
-					}
-				}
-				switch (ls) {
-				case 0:
-					printf(format, (int)val);
-					break;
-				case 1:
-					printf(format, (long)val);
-					break;
-				case 2:
-					printf(format, (long long)val);
-					break;
-				default:
-					die("bad count (%d)", ls);
-				}
-				break;
-			case 's':
-				if (!arg)
-					die("no matching argument");
-
-				print_str_arg(data, size, event, arg);
-				arg = arg->next;
-				break;
-			default:
-				printf(">%c<", *ptr);
-
-			}
-		} else
-			printf("%c", *ptr);
-	}
-
-	if (args) {
-		free_args(args);
-		free(bprint_fmt);
-	}
-}
-
-static inline int log10_cpu(int nb)
-{
-	if (nb / 100)
-		return 3;
-	if (nb / 10)
-		return 2;
-	return 1;
-}
-
-static void print_lat_fmt(void *data, int size __unused)
-{
-	unsigned int lat_flags;
-	unsigned int pc;
-	int lock_depth;
-	int hardirq;
-	int softirq;
-
-	lat_flags = parse_common_flags(data);
-	pc = parse_common_pc(data);
-	lock_depth = parse_common_lock_depth(data);
-
-	hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
-	softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
-
-	printf("%c%c%c",
-	       (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
-	       (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
-	       'X' : '.',
-	       (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
-	       'N' : '.',
-	       (hardirq && softirq) ? 'H' :
-	       hardirq ? 'h' : softirq ? 's' : '.');
-
-	if (pc)
-		printf("%x", pc);
-	else
-		printf(".");
-
-	if (lock_depth < 0)
-		printf(". ");
-	else
-		printf("%d ", lock_depth);
-}
-
-#define TRACE_GRAPH_INDENT	2
-
-static struct record *
-get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
-		    struct record *next)
-{
-	struct format_field *field;
-	struct event *event;
-	unsigned long val;
-	int type;
-	int pid;
-
-	type = trace_parse_common_type(next->data);
-	event = trace_find_event(type);
-	if (!event)
-		return NULL;
-
-	if (!(event->flags & EVENT_FL_ISFUNCRET))
-		return NULL;
-
-	pid = trace_parse_common_pid(next->data);
-	field = find_field(event, "func");
-	if (!field)
-		die("function return does not have field func");
-
-	val = read_size(next->data + field->offset, field->size);
-
-	if (cur_pid != pid || cur_func != val)
-		return NULL;
-
-	/* this is a leaf, now advance the iterator */
-	return trace_read_data(cpu);
-}
-
-/* Signal a overhead of time execution to the output */
-static void print_graph_overhead(unsigned long long duration)
-{
-	/* Non nested entry or return */
-	if (duration == ~0ULL)
-		return (void)printf("  ");
-
-	/* Duration exceeded 100 msecs */
-	if (duration > 100000ULL)
-		return (void)printf("! ");
-
-	/* Duration exceeded 10 msecs */
-	if (duration > 10000ULL)
-		return (void)printf("+ ");
-
-	printf("  ");
-}
-
-static void print_graph_duration(unsigned long long duration)
-{
-	unsigned long usecs = duration / 1000;
-	unsigned long nsecs_rem = duration % 1000;
-	/* log10(ULONG_MAX) + '\0' */
-	char msecs_str[21];
-	char nsecs_str[5];
-	int len;
-	int i;
-
-	sprintf(msecs_str, "%lu", usecs);
-
-	/* Print msecs */
-	len = printf("%lu", usecs);
-
-	/* Print nsecs (we don't want to exceed 7 numbers) */
-	if (len < 7) {
-		snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
-		len += printf(".%s", nsecs_str);
-	}
-
-	printf(" us ");
-
-	/* Print remaining spaces to fit the row's width */
-	for (i = len; i < 7; i++)
-		printf(" ");
-
-	printf("|  ");
-}
-
-static void
-print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
-{
-	unsigned long long rettime, calltime;
-	unsigned long long duration, depth;
-	unsigned long long val;
-	struct format_field *field;
-	struct func_map *func;
-	struct event *ret_event;
-	int type;
-	int i;
-
-	type = trace_parse_common_type(ret_rec->data);
-	ret_event = trace_find_event(type);
-
-	field = find_field(ret_event, "rettime");
-	if (!field)
-		die("can't find rettime in return graph");
-	rettime = read_size(ret_rec->data + field->offset, field->size);
-
-	field = find_field(ret_event, "calltime");
-	if (!field)
-		die("can't find rettime in return graph");
-	calltime = read_size(ret_rec->data + field->offset, field->size);
-
-	duration = rettime - calltime;
-
-	/* Overhead */
-	print_graph_overhead(duration);
-
-	/* Duration */
-	print_graph_duration(duration);
-
-	field = find_field(event, "depth");
-	if (!field)
-		die("can't find depth in entry graph");
-	depth = read_size(data + field->offset, field->size);
-
-	/* Function */
-	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
-		printf(" ");
-
-	field = find_field(event, "func");
-	if (!field)
-		die("can't find func in entry graph");
-	val = read_size(data + field->offset, field->size);
-	func = find_func(val);
-
-	if (func)
-		printf("%s();", func->func);
-	else
-		printf("%llx();", val);
-}
-
-static void print_graph_nested(struct event *event, void *data)
-{
-	struct format_field *field;
-	unsigned long long depth;
-	unsigned long long val;
-	struct func_map *func;
-	int i;
-
-	/* No overhead */
-	print_graph_overhead(-1);
-
-	/* No time */
-	printf("           |  ");
-
-	field = find_field(event, "depth");
-	if (!field)
-		die("can't find depth in entry graph");
-	depth = read_size(data + field->offset, field->size);
-
-	/* Function */
-	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
-		printf(" ");
-
-	field = find_field(event, "func");
-	if (!field)
-		die("can't find func in entry graph");
-	val = read_size(data + field->offset, field->size);
-	func = find_func(val);
-
-	if (func)
-		printf("%s() {", func->func);
-	else
-		printf("%llx() {", val);
-}
-
-static void
-pretty_print_func_ent(void *data, int size, struct event *event,
-		      int cpu, int pid)
-{
-	struct format_field *field;
-	struct record *rec;
-	void *copy_data;
-	unsigned long val;
-
-	if (latency_format) {
-		print_lat_fmt(data, size);
-		printf(" | ");
-	}
-
-	field = find_field(event, "func");
-	if (!field)
-		die("function entry does not have func field");
-
-	val = read_size(data + field->offset, field->size);
-
-	/*
-	 * peek_data may unmap the data pointer. Copy it first.
-	 */
-	copy_data = malloc_or_die(size);
-	memcpy(copy_data, data, size);
-	data = copy_data;
-
-	rec = trace_peek_data(cpu);
-	if (rec) {
-		rec = get_return_for_leaf(cpu, pid, val, rec);
-		if (rec) {
-			print_graph_entry_leaf(event, data, rec);
-			goto out_free;
-		}
-	}
-	print_graph_nested(event, data);
-out_free:
-	free(data);
-}
-
-static void
-pretty_print_func_ret(void *data, int size __unused, struct event *event)
-{
-	unsigned long long rettime, calltime;
-	unsigned long long duration, depth;
-	struct format_field *field;
-	int i;
-
-	if (latency_format) {
-		print_lat_fmt(data, size);
-		printf(" | ");
-	}
-
-	field = find_field(event, "rettime");
-	if (!field)
-		die("can't find rettime in return graph");
-	rettime = read_size(data + field->offset, field->size);
-
-	field = find_field(event, "calltime");
-	if (!field)
-		die("can't find calltime in return graph");
-	calltime = read_size(data + field->offset, field->size);
-
-	duration = rettime - calltime;
-
-	/* Overhead */
-	print_graph_overhead(duration);
-
-	/* Duration */
-	print_graph_duration(duration);
-
-	field = find_field(event, "depth");
-	if (!field)
-		die("can't find depth in entry graph");
-	depth = read_size(data + field->offset, field->size);
-
-	/* Function */
-	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
-		printf(" ");
-
-	printf("}");
-}
-
-static void
-pretty_print_func_graph(void *data, int size, struct event *event,
-			int cpu, int pid)
-{
-	if (event->flags & EVENT_FL_ISFUNCENT)
-		pretty_print_func_ent(data, size, event, cpu, pid);
-	else if (event->flags & EVENT_FL_ISFUNCRET)
-		pretty_print_func_ret(data, size, event);
-	printf("\n");
-}
-
-void print_trace_event(int cpu, void *data, int size)
-{
-	struct event *event;
-	int type;
-	int pid;
-
-	type = trace_parse_common_type(data);
-
-	event = trace_find_event(type);
-	if (!event) {
-		warning("ug! no event found for type %d", type);
-		return;
-	}
-
-	pid = trace_parse_common_pid(data);
-
-	if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
-		return pretty_print_func_graph(data, size, event, cpu, pid);
-
-	if (latency_format)
-		print_lat_fmt(data, size);
-
-	if (event->flags & EVENT_FL_FAILED) {
-		printf("EVENT '%s' FAILED TO PARSE\n",
-		       event->name);
-		return;
-	}
-
-	pretty_print(data, size, event);
-}
-
-static void print_fields(struct print_flag_sym *field)
-{
-	printf("{ %s, %s }", field->value, field->str);
-	if (field->next) {
-		printf(", ");
-		print_fields(field->next);
-	}
-}
-
-static void print_args(struct print_arg *args)
-{
-	int print_paren = 1;
-
-	switch (args->type) {
-	case PRINT_NULL:
-		printf("null");
-		break;
-	case PRINT_ATOM:
-		printf("%s", args->atom.atom);
-		break;
-	case PRINT_FIELD:
-		printf("REC->%s", args->field.name);
-		break;
-	case PRINT_FLAGS:
-		printf("__print_flags(");
-		print_args(args->flags.field);
-		printf(", %s, ", args->flags.delim);
-		print_fields(args->flags.flags);
-		printf(")");
-		break;
-	case PRINT_SYMBOL:
-		printf("__print_symbolic(");
-		print_args(args->symbol.field);
-		printf(", ");
-		print_fields(args->symbol.symbols);
-		printf(")");
-		break;
-	case PRINT_STRING:
-		printf("__get_str(%s)", args->string.string);
-		break;
-	case PRINT_TYPE:
-		printf("(%s)", args->typecast.type);
-		print_args(args->typecast.item);
-		break;
-	case PRINT_OP:
-		if (strcmp(args->op.op, ":") == 0)
-			print_paren = 0;
-		if (print_paren)
-			printf("(");
-		print_args(args->op.left);
-		printf(" %s ", args->op.op);
-		print_args(args->op.right);
-		if (print_paren)
-			printf(")");
-		break;
-	default:
-		/* we should warn... */
-		return;
-	}
-	if (args->next) {
-		printf("\n");
-		print_args(args->next);
-	}
-}
-
-int parse_ftrace_file(char *buf, unsigned long size)
-{
-	struct format_field *field;
-	struct print_arg *arg, **list;
-	struct event *event;
-	int ret;
-
-	init_input_buf(buf, size);
-
-	event = alloc_event();
-	if (!event)
-		return -ENOMEM;
-
-	event->flags |= EVENT_FL_ISFTRACE;
-
-	event->name = event_read_name();
-	if (!event->name)
-		die("failed to read ftrace event name");
-
-	if (strcmp(event->name, "function") == 0)
-		event->flags |= EVENT_FL_ISFUNC;
-
-	else if (strcmp(event->name, "funcgraph_entry") == 0)
-		event->flags |= EVENT_FL_ISFUNCENT;
-
-	else if (strcmp(event->name, "funcgraph_exit") == 0)
-		event->flags |= EVENT_FL_ISFUNCRET;
-
-	else if (strcmp(event->name, "bprint") == 0)
-		event->flags |= EVENT_FL_ISBPRINT;
-
-	event->id = event_read_id();
-	if (event->id < 0)
-		die("failed to read ftrace event id");
-
-	add_event(event);
-
-	ret = event_read_format(event);
-	if (ret < 0)
-		die("failed to read ftrace event format");
-
-	ret = event_read_print(event);
-	if (ret < 0)
-		die("failed to read ftrace event print fmt");
-
-	/* New ftrace handles args */
-	if (ret > 0)
-		return 0;
-	/*
-	 * The arguments for ftrace files are parsed by the fields.
-	 * Set up the fields as their arguments.
-	 */
-	list = &event->print_fmt.args;
-	for (field = event->format.fields; field; field = field->next) {
-		arg = malloc_or_die(sizeof(*arg));
-		memset(arg, 0, sizeof(*arg));
-		*list = arg;
-		list = &arg->next;
-		arg->type = PRINT_FIELD;
-		arg->field.name = field->name;
-		arg->field.field = field;
-	}
-	return 0;
-}
-
-int parse_event_file(char *buf, unsigned long size, char *sys)
-{
-	struct event *event;
-	int ret;
-
-	init_input_buf(buf, size);
-
-	event = alloc_event();
-	if (!event)
-		return -ENOMEM;
-
-	event->name = event_read_name();
-	if (!event->name)
-		die("failed to read event name");
-
-	event->id = event_read_id();
-	if (event->id < 0)
-		die("failed to read event id");
-
-	ret = event_read_format(event);
-	if (ret < 0) {
-		warning("failed to read event format for %s", event->name);
-		goto event_failed;
-	}
-
-	ret = event_read_print(event);
-	if (ret < 0) {
-		warning("failed to read event print fmt for %s", event->name);
-		goto event_failed;
-	}
-
-	event->system = strdup(sys);
-
-#define PRINT_ARGS 0
-	if (PRINT_ARGS && event->print_fmt.args)
-		print_args(event->print_fmt.args);
-
-	add_event(event);
-	return 0;
-
- event_failed:
-	event->flags |= EVENT_FL_FAILED;
-	/* still add it even if it failed */
-	add_event(event);
-	return -1;
-}
-
-void parse_set_info(int nr_cpus, int long_sz)
-{
-	cpus = nr_cpus;
-	long_size = long_sz;
-}
-
-int common_pc(struct scripting_context *context)
-{
-	return parse_common_pc(context->event_data);
-}
-
-int common_flags(struct scripting_context *context)
-{
-	return parse_common_flags(context->event_data);
-}
-
-int common_lock_depth(struct scripting_context *context)
-{
-	return parse_common_lock_depth(context->event_data);
-}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index b9592e0..f097e0d 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -52,6 +52,16 @@
 static ssize_t calc_data_size;
 static bool repipe;
 
+static void *malloc_or_die(int size)
+{
+	void *ret;
+
+	ret = malloc(size);
+	if (!ret)
+		die("malloc");
+	return ret;
+}
+
 static int do_read(int fd, void *buf, int size)
 {
 	int rsize = size;
@@ -109,7 +119,7 @@
 	unsigned int data;
 
 	read_or_die(&data, 4);
-	return __data2host4(data);
+	return __data2host4(perf_pevent, data);
 }
 
 static unsigned long long read8(void)
@@ -117,7 +127,7 @@
 	unsigned long long data;
 
 	read_or_die(&data, 8);
-	return __data2host8(data);
+	return __data2host8(perf_pevent, data);
 }
 
 static char *read_string(void)
@@ -282,7 +292,7 @@
 	unsigned long long	offset;
 	unsigned long long	size;
 	unsigned long long	timestamp;
-	struct record		*next;
+	struct pevent_record	*next;
 	char			*page;
 	int			cpu;
 	int			index;
@@ -367,9 +377,9 @@
 	return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
 }
 
-struct record *trace_peek_data(int cpu)
+struct pevent_record *trace_peek_data(int cpu)
 {
-	struct record *data;
+	struct pevent_record *data;
 	void *page = cpu_data[cpu].page;
 	int idx = cpu_data[cpu].index;
 	void *ptr = page + idx;
@@ -389,15 +399,15 @@
 		/* FIXME: handle header page */
 		if (header_page_ts_size != 8)
 			die("expected a long long type for timestamp");
-		cpu_data[cpu].timestamp = data2host8(ptr);
+		cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr);
 		ptr += 8;
 		switch (header_page_size_size) {
 		case 4:
-			cpu_data[cpu].page_size = data2host4(ptr);
+			cpu_data[cpu].page_size = data2host4(perf_pevent, ptr);
 			ptr += 4;
 			break;
 		case 8:
-			cpu_data[cpu].page_size = data2host8(ptr);
+			cpu_data[cpu].page_size = data2host8(perf_pevent, ptr);
 			ptr += 8;
 			break;
 		default:
@@ -414,7 +424,7 @@
 		return trace_peek_data(cpu);
 	}
 
-	type_len_ts = data2host4(ptr);
+	type_len_ts = data2host4(perf_pevent, ptr);
 	ptr += 4;
 
 	type_len = type_len4host(type_len_ts);
@@ -424,14 +434,14 @@
 	case RINGBUF_TYPE_PADDING:
 		if (!delta)
 			die("error, hit unexpected end of page");
-		length = data2host4(ptr);
+		length = data2host4(perf_pevent, ptr);
 		ptr += 4;
 		length *= 4;
 		ptr += length;
 		goto read_again;
 
 	case RINGBUF_TYPE_TIME_EXTEND:
-		extend = data2host4(ptr);
+		extend = data2host4(perf_pevent, ptr);
 		ptr += 4;
 		extend <<= TS_SHIFT;
 		extend += delta;
@@ -442,7 +452,7 @@
 		ptr += 12;
 		break;
 	case 0:
-		length = data2host4(ptr);
+		length = data2host4(perf_pevent, ptr);
 		ptr += 4;
 		die("here! length=%d", length);
 		break;
@@ -467,9 +477,9 @@
 	return data;
 }
 
-struct record *trace_read_data(int cpu)
+struct pevent_record *trace_read_data(int cpu)
 {
-	struct record *data;
+	struct pevent_record *data;
 
 	data = trace_peek_data(cpu);
 	cpu_data[cpu].next = NULL;
@@ -509,6 +519,8 @@
 	file_bigendian = buf[0];
 	host_bigendian = bigendian();
 
+	read_trace_init(file_bigendian, host_bigendian);
+
 	read_or_die(buf, 1);
 	long_size = buf[0];
 
@@ -526,11 +538,11 @@
 	repipe = false;
 
 	if (show_funcs) {
-		print_funcs();
+		pevent_print_funcs(perf_pevent);
 		return size;
 	}
 	if (show_printk) {
-		print_printk();
+		pevent_print_printk(perf_pevent);
 		return size;
 	}
 
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 58ae14c..639852a 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,20 +1,21 @@
-#ifndef __PERF_TRACE_EVENTS_H
-#define __PERF_TRACE_EVENTS_H
+#ifndef _PERF_UTIL_TRACE_EVENT_H
+#define _PERF_UTIL_TRACE_EVENT_H
 
-#include <stdbool.h>
 #include "parse-events.h"
+#include "event-parse.h"
+#include "session.h"
 
 struct machine;
 struct perf_sample;
 union perf_event;
 struct thread;
 
-#define __unused __attribute__((unused))
+extern int header_page_size_size;
+extern int header_page_ts_size;
+extern int header_page_data_offset;
 
-
-#ifndef PAGE_MASK
-#define PAGE_MASK (page_size - 1)
-#endif
+extern bool latency_format;
+extern struct pevent *perf_pevent;
 
 enum {
 	RINGBUF_TYPE_PADDING		= 29,
@@ -26,246 +27,37 @@
 #define TS_SHIFT		27
 #endif
 
-#define NSECS_PER_SEC		1000000000ULL
-#define NSECS_PER_USEC		1000ULL
+int bigendian(void);
 
-enum format_flags {
-	FIELD_IS_ARRAY		= 1,
-	FIELD_IS_POINTER	= 2,
-	FIELD_IS_SIGNED		= 4,
-	FIELD_IS_STRING		= 8,
-	FIELD_IS_DYNAMIC	= 16,
-	FIELD_IS_FLAG		= 32,
-	FIELD_IS_SYMBOLIC	= 64,
-};
+int read_trace_init(int file_bigendian, int host_bigendian);
+void print_trace_event(int cpu, void *data, int size);
 
-struct format_field {
-	struct format_field	*next;
-	char			*type;
-	char			*name;
-	int			offset;
-	int			size;
-	unsigned long		flags;
-};
-
-struct format {
-	int			nr_common;
-	int			nr_fields;
-	struct format_field	*common_fields;
-	struct format_field	*fields;
-};
-
-struct print_arg_atom {
-	char			*atom;
-};
-
-struct print_arg_string {
-	char			*string;
-	int			offset;
-};
-
-struct print_arg_field {
-	char			*name;
-	struct format_field	*field;
-};
-
-struct print_flag_sym {
-	struct print_flag_sym	*next;
-	char			*value;
-	char			*str;
-};
-
-struct print_arg_typecast {
-	char 			*type;
-	struct print_arg	*item;
-};
-
-struct print_arg_flags {
-	struct print_arg	*field;
-	char			*delim;
-	struct print_flag_sym	*flags;
-};
-
-struct print_arg_symbol {
-	struct print_arg	*field;
-	struct print_flag_sym	*symbols;
-};
-
-struct print_arg;
-
-struct print_arg_op {
-	char			*op;
-	int			prio;
-	struct print_arg	*left;
-	struct print_arg	*right;
-};
-
-struct print_arg_func {
-	char			*name;
-	struct print_arg	*args;
-};
-
-enum print_arg_type {
-	PRINT_NULL,
-	PRINT_ATOM,
-	PRINT_FIELD,
-	PRINT_FLAGS,
-	PRINT_SYMBOL,
-	PRINT_TYPE,
-	PRINT_STRING,
-	PRINT_OP,
-};
-
-struct print_arg {
-	struct print_arg		*next;
-	enum print_arg_type		type;
-	union {
-		struct print_arg_atom		atom;
-		struct print_arg_field		field;
-		struct print_arg_typecast	typecast;
-		struct print_arg_flags		flags;
-		struct print_arg_symbol		symbol;
-		struct print_arg_func		func;
-		struct print_arg_string		string;
-		struct print_arg_op		op;
-	};
-};
-
-struct print_fmt {
-	char			*format;
-	struct print_arg	*args;
-};
-
-struct event {
-	struct event		*next;
-	char			*name;
-	int			id;
-	int			flags;
-	struct format		format;
-	struct print_fmt	print_fmt;
-	char			*system;
-};
-
-enum {
-	EVENT_FL_ISFTRACE	= 0x01,
-	EVENT_FL_ISPRINT	= 0x02,
-	EVENT_FL_ISBPRINT	= 0x04,
-	EVENT_FL_ISFUNC		= 0x08,
-	EVENT_FL_ISFUNCENT	= 0x10,
-	EVENT_FL_ISFUNCRET	= 0x20,
-
-	EVENT_FL_FAILED		= 0x80000000
-};
-
-struct record {
-	unsigned long long ts;
-	int size;
-	void *data;
-};
-
-struct record *trace_peek_data(int cpu);
-struct record *trace_read_data(int cpu);
-
-void parse_set_info(int nr_cpus, int long_sz);
-
-ssize_t trace_report(int fd, bool repipe);
-
-void *malloc_or_die(unsigned int size);
-
-void parse_cmdlines(char *file, int size);
-void parse_proc_kallsyms(char *file, unsigned int size);
-void parse_ftrace_printk(char *file, unsigned int size);
-
-void print_funcs(void);
-void print_printk(void);
+void print_event(int cpu, void *data, int size, unsigned long long nsecs,
+		  char *comm);
 
 int parse_ftrace_file(char *buf, unsigned long size);
 int parse_event_file(char *buf, unsigned long size, char *sys);
-void print_trace_event(int cpu, void *data, int size);
 
-extern int file_bigendian;
-extern int host_bigendian;
+struct pevent_record *trace_peek_data(int cpu);
+struct event_format *trace_find_event(int type);
 
-int bigendian(void);
+unsigned long long
+raw_field_value(struct event_format *event, const char *name, void *data);
+void *raw_field_ptr(struct event_format *event, const char *name, void *data);
 
-static inline unsigned short __data2host2(unsigned short data)
-{
-	unsigned short swap;
+void parse_proc_kallsyms(char *file, unsigned int size __unused);
+void parse_ftrace_printk(char *file, unsigned int size __unused);
 
-	if (host_bigendian == file_bigendian)
-		return data;
-
-	swap = ((data & 0xffULL) << 8) |
-		((data & (0xffULL << 8)) >> 8);
-
-	return swap;
-}
-
-static inline unsigned int __data2host4(unsigned int data)
-{
-	unsigned int swap;
-
-	if (host_bigendian == file_bigendian)
-		return data;
-
-	swap = ((data & 0xffULL) << 24) |
-		((data & (0xffULL << 8)) << 8) |
-		((data & (0xffULL << 16)) >> 8) |
-		((data & (0xffULL << 24)) >> 24);
-
-	return swap;
-}
-
-static inline unsigned long long __data2host8(unsigned long long data)
-{
-	unsigned long long swap;
-
-	if (host_bigendian == file_bigendian)
-		return data;
-
-	swap = ((data & 0xffULL) << 56) |
-		((data & (0xffULL << 8)) << 40) |
-		((data & (0xffULL << 16)) << 24) |
-		((data & (0xffULL << 24)) << 8) |
-		((data & (0xffULL << 32)) >> 8) |
-		((data & (0xffULL << 40)) >> 24) |
-		((data & (0xffULL << 48)) >> 40) |
-		((data & (0xffULL << 56)) >> 56);
-
-	return swap;
-}
-
-#define data2host2(ptr)		__data2host2(*(unsigned short *)ptr)
-#define data2host4(ptr)		__data2host4(*(unsigned int *)ptr)
-#define data2host8(ptr)		({				\
-	unsigned long long __val;				\
-								\
-	memcpy(&__val, (ptr), sizeof(unsigned long long));	\
-	__data2host8(__val);					\
-})
-
-extern int header_page_ts_offset;
-extern int header_page_ts_size;
-extern int header_page_size_offset;
-extern int header_page_size_size;
-extern int header_page_data_offset;
-extern int header_page_data_size;
-
-extern bool latency_format;
+ssize_t trace_report(int fd, bool repipe);
 
 int trace_parse_common_type(void *data);
 int trace_parse_common_pid(void *data);
-int parse_common_pc(void *data);
-int parse_common_flags(void *data);
-int parse_common_lock_depth(void *data);
-struct event *trace_find_event(int id);
-struct event *trace_find_next_event(struct event *event);
+
+struct event_format *trace_find_next_event(struct event_format *event);
 unsigned long long read_size(void *ptr, int size);
-unsigned long long
-raw_field_value(struct event *event, const char *name, void *data);
-void *raw_field_ptr(struct event *event, const char *name, void *data);
 unsigned long long eval_flag(const char *flag);
 
+struct pevent_record *trace_read_data(int cpu);
 int read_tracing_data(int fd, struct list_head *pattrs);
 
 struct tracing_data {
@@ -280,15 +72,6 @@
 void tracing_data_put(struct tracing_data *tdata);
 
 
-/* taken from kernel/trace/trace.h */
-enum trace_flag_type {
-	TRACE_FLAG_IRQS_OFF		= 0x01,
-	TRACE_FLAG_IRQS_NOSUPPORT	= 0x02,
-	TRACE_FLAG_NEED_RESCHED		= 0x04,
-	TRACE_FLAG_HARDIRQ		= 0x08,
-	TRACE_FLAG_SOFTIRQ		= 0x10,
-};
-
 struct scripting_ops {
 	const char *name;
 	int (*start_script) (const char *script, int argc, const char **argv);
@@ -314,4 +97,4 @@
 int common_flags(struct scripting_context *context);
 int common_lock_depth(struct scripting_context *context);
 
-#endif /* __PERF_TRACE_EVENTS_H */
+#endif /* _PERF_UTIL_TRACE_EVENT_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5f3689a..c51fa6b 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -16,4 +16,9 @@
 typedef unsigned char	   u8;
 typedef signed char	   s8;
 
+union u64_swap {
+	u64 val64;
+	u32 val32[2];
+};
+
 #endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
deleted file mode 100644
index 5568291..0000000
--- a/tools/perf/util/ui/browser.c
+++ /dev/null
@@ -1,597 +0,0 @@
-#include "../util.h"
-#include "../cache.h"
-#include "../../perf.h"
-#include "libslang.h"
-#include <newt.h>
-#include "ui.h"
-#include "util.h"
-#include <linux/compiler.h>
-#include <linux/list.h>
-#include <linux/rbtree.h>
-#include <stdlib.h>
-#include <sys/ttydefaults.h>
-#include "browser.h"
-#include "helpline.h"
-#include "keysyms.h"
-#include "../color.h"
-
-static int ui_browser__percent_color(struct ui_browser *browser,
-				     double percent, bool current)
-{
-	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
-		return HE_COLORSET_SELECTED;
-	if (percent >= MIN_RED)
-		return HE_COLORSET_TOP;
-	if (percent >= MIN_GREEN)
-		return HE_COLORSET_MEDIUM;
-	return HE_COLORSET_NORMAL;
-}
-
-void ui_browser__set_color(struct ui_browser *self __used, int color)
-{
-	SLsmg_set_color(color);
-}
-
-void ui_browser__set_percent_color(struct ui_browser *self,
-				   double percent, bool current)
-{
-	 int color = ui_browser__percent_color(self, percent, current);
-	 ui_browser__set_color(self, color);
-}
-
-void ui_browser__gotorc(struct ui_browser *self, int y, int x)
-{
-	SLsmg_gotorc(self->y + y, self->x + x);
-}
-
-static struct list_head *
-ui_browser__list_head_filter_entries(struct ui_browser *browser,
-				     struct list_head *pos)
-{
-	do {
-		if (!browser->filter || !browser->filter(browser, pos))
-			return pos;
-		pos = pos->next;
-	} while (pos != browser->entries);
-
-	return NULL;
-}
-
-static struct list_head *
-ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
-					  struct list_head *pos)
-{
-	do {
-		if (!browser->filter || !browser->filter(browser, pos))
-			return pos;
-		pos = pos->prev;
-	} while (pos != browser->entries);
-
-	return NULL;
-}
-
-void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
-{
-	struct list_head *head = self->entries;
-	struct list_head *pos;
-
-	if (self->nr_entries == 0)
-		return;
-
-	switch (whence) {
-	case SEEK_SET:
-		pos = ui_browser__list_head_filter_entries(self, head->next);
-		break;
-	case SEEK_CUR:
-		pos = self->top;
-		break;
-	case SEEK_END:
-		pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
-		break;
-	default:
-		return;
-	}
-
-	assert(pos != NULL);
-
-	if (offset > 0) {
-		while (offset-- != 0)
-			pos = ui_browser__list_head_filter_entries(self, pos->next);
-	} else {
-		while (offset++ != 0)
-			pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
-	}
-
-	self->top = pos;
-}
-
-void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
-{
-	struct rb_root *root = self->entries;
-	struct rb_node *nd;
-
-	switch (whence) {
-	case SEEK_SET:
-		nd = rb_first(root);
-		break;
-	case SEEK_CUR:
-		nd = self->top;
-		break;
-	case SEEK_END:
-		nd = rb_last(root);
-		break;
-	default:
-		return;
-	}
-
-	if (offset > 0) {
-		while (offset-- != 0)
-			nd = rb_next(nd);
-	} else {
-		while (offset++ != 0)
-			nd = rb_prev(nd);
-	}
-
-	self->top = nd;
-}
-
-unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
-{
-	struct rb_node *nd;
-	int row = 0;
-
-	if (self->top == NULL)
-                self->top = rb_first(self->entries);
-
-	nd = self->top;
-
-	while (nd != NULL) {
-		ui_browser__gotorc(self, row, 0);
-		self->write(self, nd, row);
-		if (++row == self->height)
-			break;
-		nd = rb_next(nd);
-	}
-
-	return row;
-}
-
-bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
-{
-	return self->top_idx + row == self->index;
-}
-
-void ui_browser__refresh_dimensions(struct ui_browser *self)
-{
-	self->width = SLtt_Screen_Cols - 1;
-	self->height = SLtt_Screen_Rows - 2;
-	self->y = 1;
-	self->x = 0;
-}
-
-void ui_browser__handle_resize(struct ui_browser *browser)
-{
-	ui__refresh_dimensions(false);
-	ui_browser__show(browser, browser->title, ui_helpline__current);
-	ui_browser__refresh(browser);
-}
-
-int ui_browser__warning(struct ui_browser *browser, int timeout,
-			const char *format, ...)
-{
-	va_list args;
-	char *text;
-	int key = 0, err;
-
-	va_start(args, format);
-	err = vasprintf(&text, format, args);
-	va_end(args);
-
-	if (err < 0) {
-		va_start(args, format);
-		ui_helpline__vpush(format, args);
-		va_end(args);
-	} else {
-		while ((key == ui__question_window("Warning!", text,
-						   "Press any key...",
-						   timeout)) == K_RESIZE)
-			ui_browser__handle_resize(browser);
-		free(text);
-	}
-
-	return key;
-}
-
-int ui_browser__help_window(struct ui_browser *browser, const char *text)
-{
-	int key;
-
-	while ((key = ui__help_window(text)) == K_RESIZE)
-		ui_browser__handle_resize(browser);
-
-	return key;
-}
-
-bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
-{
-	int key;
-
-	while ((key = ui__dialog_yesno(text)) == K_RESIZE)
-		ui_browser__handle_resize(browser);
-
-	return key == K_ENTER || toupper(key) == 'Y';
-}
-
-void ui_browser__reset_index(struct ui_browser *self)
-{
-	self->index = self->top_idx = 0;
-	self->seek(self, 0, SEEK_SET);
-}
-
-void __ui_browser__show_title(struct ui_browser *browser, const char *title)
-{
-	SLsmg_gotorc(0, 0);
-	ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
-	slsmg_write_nstring(title, browser->width + 1);
-}
-
-void ui_browser__show_title(struct ui_browser *browser, const char *title)
-{
-	pthread_mutex_lock(&ui__lock);
-	__ui_browser__show_title(browser, title);
-	pthread_mutex_unlock(&ui__lock);
-}
-
-int ui_browser__show(struct ui_browser *self, const char *title,
-		     const char *helpline, ...)
-{
-	int err;
-	va_list ap;
-
-	ui_browser__refresh_dimensions(self);
-
-	pthread_mutex_lock(&ui__lock);
-	__ui_browser__show_title(self, title);
-
-	self->title = title;
-	free(self->helpline);
-	self->helpline = NULL;
-
-	va_start(ap, helpline);
-	err = vasprintf(&self->helpline, helpline, ap);
-	va_end(ap);
-	if (err > 0)
-		ui_helpline__push(self->helpline);
-	pthread_mutex_unlock(&ui__lock);
-	return err ? 0 : -1;
-}
-
-void ui_browser__hide(struct ui_browser *browser __used)
-{
-	pthread_mutex_lock(&ui__lock);
-	ui_helpline__pop();
-	pthread_mutex_unlock(&ui__lock);
-}
-
-static void ui_browser__scrollbar_set(struct ui_browser *browser)
-{
-	int height = browser->height, h = 0, pct = 0,
-	    col = browser->width,
-	    row = browser->y - 1;
-
-	if (browser->nr_entries > 1) {
-		pct = ((browser->index * (browser->height - 1)) /
-		       (browser->nr_entries - 1));
-	}
-
-	SLsmg_set_char_set(1);
-
-	while (h < height) {
-	        ui_browser__gotorc(browser, row++, col);
-		SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
-		++h;
-	}
-
-	SLsmg_set_char_set(0);
-}
-
-static int __ui_browser__refresh(struct ui_browser *browser)
-{
-	int row;
-	int width = browser->width;
-
-	row = browser->refresh(browser);
-	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
-
-	if (!browser->use_navkeypressed || browser->navkeypressed)
-		ui_browser__scrollbar_set(browser);
-	else
-		width += 1;
-
-	SLsmg_fill_region(browser->y + row, browser->x,
-			  browser->height - row, width, ' ');
-
-	return 0;
-}
-
-int ui_browser__refresh(struct ui_browser *browser)
-{
-	pthread_mutex_lock(&ui__lock);
-	__ui_browser__refresh(browser);
-	pthread_mutex_unlock(&ui__lock);
-
-	return 0;
-}
-
-/*
- * Here we're updating nr_entries _after_ we started browsing, i.e.  we have to
- * forget about any reference to any entry in the underlying data structure,
- * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
- * after an output_resort and hist decay.
- */
-void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
-{
-	off_t offset = nr_entries - browser->nr_entries;
-
-	browser->nr_entries = nr_entries;
-
-	if (offset < 0) {
-		if (browser->top_idx < (u64)-offset)
-			offset = -browser->top_idx;
-
-		browser->index += offset;
-		browser->top_idx += offset;
-	}
-
-	browser->top = NULL;
-	browser->seek(browser, browser->top_idx, SEEK_SET);
-}
-
-int ui_browser__run(struct ui_browser *self, int delay_secs)
-{
-	int err, key;
-
-	while (1) {
-		off_t offset;
-
-		pthread_mutex_lock(&ui__lock);
-		err = __ui_browser__refresh(self);
-		SLsmg_refresh();
-		pthread_mutex_unlock(&ui__lock);
-		if (err < 0)
-			break;
-
-		key = ui__getch(delay_secs);
-
-		if (key == K_RESIZE) {
-			ui__refresh_dimensions(false);
-			ui_browser__refresh_dimensions(self);
-			__ui_browser__show_title(self, self->title);
-			ui_helpline__puts(self->helpline);
-			continue;
-		}
-
-		if (self->use_navkeypressed && !self->navkeypressed) {
-			if (key == K_DOWN || key == K_UP ||
-			    key == K_PGDN || key == K_PGUP ||
-			    key == K_HOME || key == K_END ||
-			    key == ' ') {
-				self->navkeypressed = true;
-				continue;
-			} else
-				return key;
-		}
-
-		switch (key) {
-		case K_DOWN:
-			if (self->index == self->nr_entries - 1)
-				break;
-			++self->index;
-			if (self->index == self->top_idx + self->height) {
-				++self->top_idx;
-				self->seek(self, +1, SEEK_CUR);
-			}
-			break;
-		case K_UP:
-			if (self->index == 0)
-				break;
-			--self->index;
-			if (self->index < self->top_idx) {
-				--self->top_idx;
-				self->seek(self, -1, SEEK_CUR);
-			}
-			break;
-		case K_PGDN:
-		case ' ':
-			if (self->top_idx + self->height > self->nr_entries - 1)
-				break;
-
-			offset = self->height;
-			if (self->index + offset > self->nr_entries - 1)
-				offset = self->nr_entries - 1 - self->index;
-			self->index += offset;
-			self->top_idx += offset;
-			self->seek(self, +offset, SEEK_CUR);
-			break;
-		case K_PGUP:
-			if (self->top_idx == 0)
-				break;
-
-			if (self->top_idx < self->height)
-				offset = self->top_idx;
-			else
-				offset = self->height;
-
-			self->index -= offset;
-			self->top_idx -= offset;
-			self->seek(self, -offset, SEEK_CUR);
-			break;
-		case K_HOME:
-			ui_browser__reset_index(self);
-			break;
-		case K_END:
-			offset = self->height - 1;
-			if (offset >= self->nr_entries)
-				offset = self->nr_entries - 1;
-
-			self->index = self->nr_entries - 1;
-			self->top_idx = self->index - offset;
-			self->seek(self, -offset, SEEK_END);
-			break;
-		default:
-			return key;
-		}
-	}
-	return -1;
-}
-
-unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
-{
-	struct list_head *pos;
-	struct list_head *head = self->entries;
-	int row = 0;
-
-	if (self->top == NULL || self->top == self->entries)
-                self->top = ui_browser__list_head_filter_entries(self, head->next);
-
-	pos = self->top;
-
-	list_for_each_from(pos, head) {
-		if (!self->filter || !self->filter(self, pos)) {
-			ui_browser__gotorc(self, row, 0);
-			self->write(self, pos, row);
-			if (++row == self->height)
-				break;
-		}
-	}
-
-	return row;
-}
-
-static struct ui_browser__colorset {
-	const char *name, *fg, *bg;
-	int colorset;
-} ui_browser__colorsets[] = {
-	{
-		.colorset = HE_COLORSET_TOP,
-		.name	  = "top",
-		.fg	  = "red",
-		.bg	  = "default",
-	},
-	{
-		.colorset = HE_COLORSET_MEDIUM,
-		.name	  = "medium",
-		.fg	  = "green",
-		.bg	  = "default",
-	},
-	{
-		.colorset = HE_COLORSET_NORMAL,
-		.name	  = "normal",
-		.fg	  = "default",
-		.bg	  = "default",
-	},
-	{
-		.colorset = HE_COLORSET_SELECTED,
-		.name	  = "selected",
-		.fg	  = "black",
-		.bg	  = "lightgray",
-	},
-	{
-		.colorset = HE_COLORSET_CODE,
-		.name	  = "code",
-		.fg	  = "blue",
-		.bg	  = "default",
-	},
-	{
-		.name = NULL,
-	}
-};
-
-
-static int ui_browser__color_config(const char *var, const char *value,
-				    void *data __used)
-{
-	char *fg = NULL, *bg;
-	int i;
-
-	/* same dir for all commands */
-	if (prefixcmp(var, "colors.") != 0)
-		return 0;
-
-	for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
-		const char *name = var + 7;
-
-		if (strcmp(ui_browser__colorsets[i].name, name) != 0)
-			continue;
-
-		fg = strdup(value);
-		if (fg == NULL)
-			break;
-
-		bg = strchr(fg, ',');
-		if (bg == NULL)
-			break;
-
-		*bg = '\0';
-		while (isspace(*++bg));
-		ui_browser__colorsets[i].bg = bg;
-		ui_browser__colorsets[i].fg = fg;
-		return 0;
-	}
-
-	free(fg);
-	return -1;
-}
-
-void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
-{
-	switch (whence) {
-	case SEEK_SET:
-		browser->top = browser->entries;
-		break;
-	case SEEK_CUR:
-		browser->top = browser->top + browser->top_idx + offset;
-		break;
-	case SEEK_END:
-		browser->top = browser->top + browser->nr_entries + offset;
-		break;
-	default:
-		return;
-	}
-}
-
-unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
-{
-	unsigned int row = 0, idx = browser->top_idx;
-	char **pos;
-
-	if (browser->top == NULL)
-		browser->top = browser->entries;
-
-	pos = (char **)browser->top;
-	while (idx < browser->nr_entries) {
-		if (!browser->filter || !browser->filter(browser, *pos)) {
-			ui_browser__gotorc(browser, row, 0);
-			browser->write(browser, pos, row);
-			if (++row == browser->height)
-				break;
-		}
-
-		++idx;
-		++pos;
-	}
-
-	return row;
-}
-
-void ui_browser__init(void)
-{
-	int i = 0;
-
-	perf_config(ui_browser__color_config, NULL);
-
-	while (ui_browser__colorsets[i].name) {
-		struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
-		sltt_set_color(c->colorset, c->name, c->fg, c->bg);
-	}
-}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
deleted file mode 100644
index 6ee82f6..0000000
--- a/tools/perf/util/ui/browser.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef _PERF_UI_BROWSER_H_
-#define _PERF_UI_BROWSER_H_ 1
-
-#include <stdbool.h>
-#include <sys/types.h>
-#include "../types.h"
-
-#define HE_COLORSET_TOP		50
-#define HE_COLORSET_MEDIUM	51
-#define HE_COLORSET_NORMAL	52
-#define HE_COLORSET_SELECTED	53
-#define HE_COLORSET_CODE	54
-
-struct ui_browser {
-	u64	      index, top_idx;
-	void	      *top, *entries;
-	u16	      y, x, width, height;
-	void	      *priv;
-	const char    *title;
-	char	      *helpline;
-	unsigned int  (*refresh)(struct ui_browser *self);
-	void	      (*write)(struct ui_browser *self, void *entry, int row);
-	void	      (*seek)(struct ui_browser *self, off_t offset, int whence);
-	bool	      (*filter)(struct ui_browser *self, void *entry);
-	u32	      nr_entries;
-	bool	      navkeypressed;
-	bool	      use_navkeypressed;
-};
-
-void ui_browser__set_color(struct ui_browser *self, int color);
-void ui_browser__set_percent_color(struct ui_browser *self,
-				   double percent, bool current);
-bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
-void ui_browser__refresh_dimensions(struct ui_browser *self);
-void ui_browser__reset_index(struct ui_browser *self);
-
-void ui_browser__gotorc(struct ui_browser *self, int y, int x);
-void __ui_browser__show_title(struct ui_browser *browser, const char *title);
-void ui_browser__show_title(struct ui_browser *browser, const char *title);
-int ui_browser__show(struct ui_browser *self, const char *title,
-		     const char *helpline, ...);
-void ui_browser__hide(struct ui_browser *self);
-int ui_browser__refresh(struct ui_browser *self);
-int ui_browser__run(struct ui_browser *browser, int delay_secs);
-void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
-void ui_browser__handle_resize(struct ui_browser *browser);
-
-int ui_browser__warning(struct ui_browser *browser, int timeout,
-			const char *format, ...);
-int ui_browser__help_window(struct ui_browser *browser, const char *text);
-bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
-int ui_browser__input_window(const char *title, const char *text, char *input,
-			     const char *exit_msg, int delay_sec);
-
-void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
-unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
-
-void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
-unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
-
-void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence);
-unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
-
-void ui_browser__init(void);
-#endif /* _PERF_UI_BROWSER_H_ */
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
deleted file mode 100644
index 57a4c6e..0000000
--- a/tools/perf/util/ui/browsers/annotate.c
+++ /dev/null
@@ -1,433 +0,0 @@
-#include "../../util.h"
-#include "../browser.h"
-#include "../helpline.h"
-#include "../libslang.h"
-#include "../ui.h"
-#include "../util.h"
-#include "../../annotate.h"
-#include "../../hist.h"
-#include "../../sort.h"
-#include "../../symbol.h"
-#include <pthread.h>
-#include <newt.h>
-
-struct annotate_browser {
-	struct ui_browser b;
-	struct rb_root	  entries;
-	struct rb_node	  *curr_hot;
-	struct objdump_line *selection;
-	int		    nr_asm_entries;
-	int		    nr_entries;
-	bool		    hide_src_code;
-};
-
-struct objdump_line_rb_node {
-	struct rb_node	rb_node;
-	double		percent;
-	u32		idx;
-	int		idx_asm;
-};
-
-static inline
-struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
-{
-	return (struct objdump_line_rb_node *)(self + 1);
-}
-
-static bool objdump_line__filter(struct ui_browser *browser, void *entry)
-{
-	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
-
-	if (ab->hide_src_code) {
-		struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
-		return ol->offset == -1;
-	}
-
-	return false;
-}
-
-static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
-{
-	struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
-	struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
-	bool current_entry = ui_browser__is_current_entry(self, row);
-	int width = self->width;
-
-	if (ol->offset != -1) {
-		struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
-		ui_browser__set_percent_color(self, olrb->percent, current_entry);
-		slsmg_printf(" %7.2f ", olrb->percent);
-	} else {
-		ui_browser__set_percent_color(self, 0, current_entry);
-		slsmg_write_nstring(" ", 9);
-	}
-
-	SLsmg_write_char(':');
-	slsmg_write_nstring(" ", 8);
-
-	/* The scroll bar isn't being used */
-	if (!self->navkeypressed)
-		width += 1;
-
-	if (!ab->hide_src_code && ol->offset != -1)
-		if (!current_entry || (self->use_navkeypressed &&
-				       !self->navkeypressed))
-			ui_browser__set_color(self, HE_COLORSET_CODE);
-
-	if (!*ol->line)
-		slsmg_write_nstring(" ", width - 18);
-	else
-		slsmg_write_nstring(ol->line, width - 18);
-
-	if (current_entry)
-		ab->selection = ol;
-}
-
-static double objdump_line__calc_percent(struct objdump_line *self,
-					 struct symbol *sym, int evidx)
-{
-	double percent = 0.0;
-
-	if (self->offset != -1) {
-		int len = sym->end - sym->start;
-		unsigned int hits = 0;
-		struct annotation *notes = symbol__annotation(sym);
-		struct source_line *src_line = notes->src->lines;
-		struct sym_hist *h = annotation__histogram(notes, evidx);
-		s64 offset = self->offset;
-		struct objdump_line *next;
-
-		next = objdump__get_next_ip_line(&notes->src->source, self);
-		while (offset < (s64)len &&
-		       (next == NULL || offset < next->offset)) {
-			if (src_line) {
-				percent += src_line[offset].percent;
-			} else
-				hits += h->addr[offset];
-
-			++offset;
-		}
-		/*
- 		 * If the percentage wasn't already calculated in
- 		 * symbol__get_source_line, do it now:
- 		 */
-		if (src_line == NULL && h->sum)
-			percent = 100.0 * hits / h->sum;
-	}
-
-	return percent;
-}
-
-static void objdump__insert_line(struct rb_root *self,
-				 struct objdump_line_rb_node *line)
-{
-	struct rb_node **p = &self->rb_node;
-	struct rb_node *parent = NULL;
-	struct objdump_line_rb_node *l;
-
-	while (*p != NULL) {
-		parent = *p;
-		l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
-		if (line->percent < l->percent)
-			p = &(*p)->rb_left;
-		else
-			p = &(*p)->rb_right;
-	}
-	rb_link_node(&line->rb_node, parent, p);
-	rb_insert_color(&line->rb_node, self);
-}
-
-static void annotate_browser__set_top(struct annotate_browser *self,
-				      struct rb_node *nd)
-{
-	struct objdump_line_rb_node *rbpos;
-	struct objdump_line *pos;
-	unsigned back;
-
-	ui_browser__refresh_dimensions(&self->b);
-	back = self->b.height / 2;
-	rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
-	pos = ((struct objdump_line *)rbpos) - 1;
-	self->b.top_idx = self->b.index = rbpos->idx;
-
-	while (self->b.top_idx != 0 && back != 0) {
-		pos = list_entry(pos->node.prev, struct objdump_line, node);
-
-		--self->b.top_idx;
-		--back;
-	}
-
-	self->b.top = pos;
-	self->curr_hot = nd;
-}
-
-static void annotate_browser__calc_percent(struct annotate_browser *browser,
-					   int evidx)
-{
-	struct map_symbol *ms = browser->b.priv;
-	struct symbol *sym = ms->sym;
-	struct annotation *notes = symbol__annotation(sym);
-	struct objdump_line *pos;
-
-	browser->entries = RB_ROOT;
-
-	pthread_mutex_lock(&notes->lock);
-
-	list_for_each_entry(pos, &notes->src->source, node) {
-		struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
-		rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
-		if (rbpos->percent < 0.01) {
-			RB_CLEAR_NODE(&rbpos->rb_node);
-			continue;
-		}
-		objdump__insert_line(&browser->entries, rbpos);
-	}
-	pthread_mutex_unlock(&notes->lock);
-
-	browser->curr_hot = rb_last(&browser->entries);
-}
-
-static bool annotate_browser__toggle_source(struct annotate_browser *browser)
-{
-	struct objdump_line *ol;
-	struct objdump_line_rb_node *olrb;
-	off_t offset = browser->b.index - browser->b.top_idx;
-
-	browser->b.seek(&browser->b, offset, SEEK_CUR);
-	ol = list_entry(browser->b.top, struct objdump_line, node);
-	olrb = objdump_line__rb(ol);
-
-	if (browser->hide_src_code) {
-		if (olrb->idx_asm < offset)
-			offset = olrb->idx;
-
-		browser->b.nr_entries = browser->nr_entries;
-		browser->hide_src_code = false;
-		browser->b.seek(&browser->b, -offset, SEEK_CUR);
-		browser->b.top_idx = olrb->idx - offset;
-		browser->b.index = olrb->idx;
-	} else {
-		if (olrb->idx_asm < 0) {
-			ui_helpline__puts("Only available for assembly lines.");
-			browser->b.seek(&browser->b, -offset, SEEK_CUR);
-			return false;
-		}
-
-		if (olrb->idx_asm < offset)
-			offset = olrb->idx_asm;
-
-		browser->b.nr_entries = browser->nr_asm_entries;
-		browser->hide_src_code = true;
-		browser->b.seek(&browser->b, -offset, SEEK_CUR);
-		browser->b.top_idx = olrb->idx_asm - offset;
-		browser->b.index = olrb->idx_asm;
-	}
-
-	return true;
-}
-
-static int annotate_browser__run(struct annotate_browser *self, int evidx,
-				 void(*timer)(void *arg),
-				 void *arg, int delay_secs)
-{
-	struct rb_node *nd = NULL;
-	struct map_symbol *ms = self->b.priv;
-	struct symbol *sym = ms->sym;
-	const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
-			   "H: Go to hottest line, ->/ENTER: Line action, "
-			   "S: Toggle source code view";
-	int key;
-
-	if (ui_browser__show(&self->b, sym->name, help) < 0)
-		return -1;
-
-	annotate_browser__calc_percent(self, evidx);
-
-	if (self->curr_hot)
-		annotate_browser__set_top(self, self->curr_hot);
-
-	nd = self->curr_hot;
-
-	while (1) {
-		key = ui_browser__run(&self->b, delay_secs);
-
-		if (delay_secs != 0) {
-			annotate_browser__calc_percent(self, evidx);
-			/*
-			 * Current line focus got out of the list of most active
-			 * lines, NULL it so that if TAB|UNTAB is pressed, we
-			 * move to curr_hot (current hottest line).
-			 */
-			if (nd != NULL && RB_EMPTY_NODE(nd))
-				nd = NULL;
-		}
-
-		switch (key) {
-		case K_TIMER:
-			if (timer != NULL)
-				timer(arg);
-
-			if (delay_secs != 0)
-				symbol__annotate_decay_histogram(sym, evidx);
-			continue;
-		case K_TAB:
-			if (nd != NULL) {
-				nd = rb_prev(nd);
-				if (nd == NULL)
-					nd = rb_last(&self->entries);
-			} else
-				nd = self->curr_hot;
-			break;
-		case K_UNTAB:
-			if (nd != NULL)
-				nd = rb_next(nd);
-				if (nd == NULL)
-					nd = rb_first(&self->entries);
-			else
-				nd = self->curr_hot;
-			break;
-		case 'H':
-		case 'h':
-			nd = self->curr_hot;
-			break;
-		case 'S':
-		case 's':
-			if (annotate_browser__toggle_source(self))
-				ui_helpline__puts(help);
-			continue;
-		case K_ENTER:
-		case K_RIGHT:
-			if (self->selection == NULL) {
-				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
-				continue;
-			}
-
-			if (self->selection->offset == -1) {
-				ui_helpline__puts("Actions are only available for assembly lines.");
-				continue;
-			} else {
-				char *s = strstr(self->selection->line, "callq ");
-				struct annotation *notes;
-				struct symbol *target;
-				u64 ip;
-
-				if (s == NULL) {
-					ui_helpline__puts("Actions are only available for the 'callq' instruction.");
-					continue;
-				}
-
-				s = strchr(s, ' ');
-				if (s++ == NULL) {
-					ui_helpline__puts("Invallid callq instruction.");
-					continue;
-				}
-
-				ip = strtoull(s, NULL, 16);
-				ip = ms->map->map_ip(ms->map, ip);
-				target = map__find_symbol(ms->map, ip, NULL);
-				if (target == NULL) {
-					ui_helpline__puts("The called function was not found.");
-					continue;
-				}
-
-				notes = symbol__annotation(target);
-				pthread_mutex_lock(&notes->lock);
-
-				if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
-					pthread_mutex_unlock(&notes->lock);
-					ui__warning("Not enough memory for annotating '%s' symbol!\n",
-						    target->name);
-					continue;
-				}
-
-				pthread_mutex_unlock(&notes->lock);
-				symbol__tui_annotate(target, ms->map, evidx,
-						     timer, arg, delay_secs);
-				ui_browser__show_title(&self->b, sym->name);
-			}
-			continue;
-		case K_LEFT:
-		case K_ESC:
-		case 'q':
-		case CTRL('c'):
-			goto out;
-		default:
-			continue;
-		}
-
-		if (nd != NULL)
-			annotate_browser__set_top(self, nd);
-	}
-out:
-	ui_browser__hide(&self->b);
-	return key;
-}
-
-int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
-			     void(*timer)(void *arg), void *arg, int delay_secs)
-{
-	return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
-				    timer, arg, delay_secs);
-}
-
-int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
-			 void(*timer)(void *arg), void *arg,
-			 int delay_secs)
-{
-	struct objdump_line *pos, *n;
-	struct annotation *notes;
-	struct map_symbol ms = {
-		.map = map,
-		.sym = sym,
-	};
-	struct annotate_browser browser = {
-		.b = {
-			.refresh = ui_browser__list_head_refresh,
-			.seek	 = ui_browser__list_head_seek,
-			.write	 = annotate_browser__write,
-			.filter  = objdump_line__filter,
-			.priv	 = &ms,
-			.use_navkeypressed = true,
-		},
-	};
-	int ret;
-
-	if (sym == NULL)
-		return -1;
-
-	if (map->dso->annotate_warned)
-		return -1;
-
-	if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
-		ui__error("%s", ui_helpline__last_msg);
-		return -1;
-	}
-
-	ui_helpline__push("Press <- or ESC to exit");
-
-	notes = symbol__annotation(sym);
-
-	list_for_each_entry(pos, &notes->src->source, node) {
-		struct objdump_line_rb_node *rbpos;
-		size_t line_len = strlen(pos->line);
-
-		if (browser.b.width < line_len)
-			browser.b.width = line_len;
-		rbpos = objdump_line__rb(pos);
-		rbpos->idx = browser.nr_entries++;
-		if (pos->offset != -1)
-			rbpos->idx_asm = browser.nr_asm_entries++;
-		else
-			rbpos->idx_asm = -1;
-	}
-
-	browser.b.nr_entries = browser.nr_entries;
-	browser.b.entries = &notes->src->source,
-	browser.b.width += 18; /* Percentage */
-	ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
-	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
-		list_del(&pos->node);
-		objdump_line__free(pos);
-	}
-	return ret;
-}
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
deleted file mode 100644
index 2f83e5d..0000000
--- a/tools/perf/util/ui/browsers/hists.c
+++ /dev/null
@@ -1,1341 +0,0 @@
-#include <stdio.h>
-#include "../libslang.h"
-#include <stdlib.h>
-#include <string.h>
-#include <newt.h>
-#include <linux/rbtree.h>
-
-#include "../../evsel.h"
-#include "../../evlist.h"
-#include "../../hist.h"
-#include "../../pstack.h"
-#include "../../sort.h"
-#include "../../util.h"
-
-#include "../browser.h"
-#include "../helpline.h"
-#include "../util.h"
-#include "../ui.h"
-#include "map.h"
-
-struct hist_browser {
-	struct ui_browser   b;
-	struct hists	    *hists;
-	struct hist_entry   *he_selection;
-	struct map_symbol   *selection;
-	bool		     has_symbols;
-};
-
-static int hists__browser_title(struct hists *self, char *bf, size_t size,
-				const char *ev_name);
-
-static void hist_browser__refresh_dimensions(struct hist_browser *self)
-{
-	/* 3 == +/- toggle symbol before actual hist_entry rendering */
-	self->b.width = 3 + (hists__sort_list_width(self->hists) +
-			     sizeof("[k]"));
-}
-
-static void hist_browser__reset(struct hist_browser *self)
-{
-	self->b.nr_entries = self->hists->nr_entries;
-	hist_browser__refresh_dimensions(self);
-	ui_browser__reset_index(&self->b);
-}
-
-static char tree__folded_sign(bool unfolded)
-{
-	return unfolded ? '-' : '+';
-}
-
-static char map_symbol__folded(const struct map_symbol *self)
-{
-	return self->has_children ? tree__folded_sign(self->unfolded) : ' ';
-}
-
-static char hist_entry__folded(const struct hist_entry *self)
-{
-	return map_symbol__folded(&self->ms);
-}
-
-static char callchain_list__folded(const struct callchain_list *self)
-{
-	return map_symbol__folded(&self->ms);
-}
-
-static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
-{
-	self->unfolded = unfold ? self->has_children : false;
-}
-
-static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
-{
-	int n = 0;
-	struct rb_node *nd;
-
-	for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
-		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
-		struct callchain_list *chain;
-		char folded_sign = ' '; /* No children */
-
-		list_for_each_entry(chain, &child->val, list) {
-			++n;
-			/* We need this because we may not have children */
-			folded_sign = callchain_list__folded(chain);
-			if (folded_sign == '+')
-				break;
-		}
-
-		if (folded_sign == '-') /* Have children and they're unfolded */
-			n += callchain_node__count_rows_rb_tree(child);
-	}
-
-	return n;
-}
-
-static int callchain_node__count_rows(struct callchain_node *node)
-{
-	struct callchain_list *chain;
-	bool unfolded = false;
-	int n = 0;
-
-	list_for_each_entry(chain, &node->val, list) {
-		++n;
-		unfolded = chain->ms.unfolded;
-	}
-
-	if (unfolded)
-		n += callchain_node__count_rows_rb_tree(node);
-
-	return n;
-}
-
-static int callchain__count_rows(struct rb_root *chain)
-{
-	struct rb_node *nd;
-	int n = 0;
-
-	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-		n += callchain_node__count_rows(node);
-	}
-
-	return n;
-}
-
-static bool map_symbol__toggle_fold(struct map_symbol *self)
-{
-	if (!self)
-		return false;
-
-	if (!self->has_children)
-		return false;
-
-	self->unfolded = !self->unfolded;
-	return true;
-}
-
-static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
-{
-	struct rb_node *nd = rb_first(&self->rb_root);
-
-	for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
-		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
-		struct callchain_list *chain;
-		bool first = true;
-
-		list_for_each_entry(chain, &child->val, list) {
-			if (first) {
-				first = false;
-				chain->ms.has_children = chain->list.next != &child->val ||
-							 !RB_EMPTY_ROOT(&child->rb_root);
-			} else
-				chain->ms.has_children = chain->list.next == &child->val &&
-							 !RB_EMPTY_ROOT(&child->rb_root);
-		}
-
-		callchain_node__init_have_children_rb_tree(child);
-	}
-}
-
-static void callchain_node__init_have_children(struct callchain_node *self)
-{
-	struct callchain_list *chain;
-
-	list_for_each_entry(chain, &self->val, list)
-		chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root);
-
-	callchain_node__init_have_children_rb_tree(self);
-}
-
-static void callchain__init_have_children(struct rb_root *self)
-{
-	struct rb_node *nd;
-
-	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
-		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-		callchain_node__init_have_children(node);
-	}
-}
-
-static void hist_entry__init_have_children(struct hist_entry *self)
-{
-	if (!self->init_have_children) {
-		self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain);
-		callchain__init_have_children(&self->sorted_chain);
-		self->init_have_children = true;
-	}
-}
-
-static bool hist_browser__toggle_fold(struct hist_browser *self)
-{
-	if (map_symbol__toggle_fold(self->selection)) {
-		struct hist_entry *he = self->he_selection;
-
-		hist_entry__init_have_children(he);
-		self->hists->nr_entries -= he->nr_rows;
-
-		if (he->ms.unfolded)
-			he->nr_rows = callchain__count_rows(&he->sorted_chain);
-		else
-			he->nr_rows = 0;
-		self->hists->nr_entries += he->nr_rows;
-		self->b.nr_entries = self->hists->nr_entries;
-
-		return true;
-	}
-
-	/* If it doesn't have children, no toggling performed */
-	return false;
-}
-
-static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold)
-{
-	int n = 0;
-	struct rb_node *nd;
-
-	for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
-		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
-		struct callchain_list *chain;
-		bool has_children = false;
-
-		list_for_each_entry(chain, &child->val, list) {
-			++n;
-			map_symbol__set_folding(&chain->ms, unfold);
-			has_children = chain->ms.has_children;
-		}
-
-		if (has_children)
-			n += callchain_node__set_folding_rb_tree(child, unfold);
-	}
-
-	return n;
-}
-
-static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
-{
-	struct callchain_list *chain;
-	bool has_children = false;
-	int n = 0;
-
-	list_for_each_entry(chain, &node->val, list) {
-		++n;
-		map_symbol__set_folding(&chain->ms, unfold);
-		has_children = chain->ms.has_children;
-	}
-
-	if (has_children)
-		n += callchain_node__set_folding_rb_tree(node, unfold);
-
-	return n;
-}
-
-static int callchain__set_folding(struct rb_root *chain, bool unfold)
-{
-	struct rb_node *nd;
-	int n = 0;
-
-	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-		n += callchain_node__set_folding(node, unfold);
-	}
-
-	return n;
-}
-
-static void hist_entry__set_folding(struct hist_entry *self, bool unfold)
-{
-	hist_entry__init_have_children(self);
-	map_symbol__set_folding(&self->ms, unfold);
-
-	if (self->ms.has_children) {
-		int n = callchain__set_folding(&self->sorted_chain, unfold);
-		self->nr_rows = unfold ? n : 0;
-	} else
-		self->nr_rows = 0;
-}
-
-static void hists__set_folding(struct hists *self, bool unfold)
-{
-	struct rb_node *nd;
-
-	self->nr_entries = 0;
-
-	for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
-		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
-		hist_entry__set_folding(he, unfold);
-		self->nr_entries += 1 + he->nr_rows;
-	}
-}
-
-static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
-{
-	hists__set_folding(self->hists, unfold);
-	self->b.nr_entries = self->hists->nr_entries;
-	/* Go to the start, we may be way after valid entries after a collapse */
-	ui_browser__reset_index(&self->b);
-}
-
-static void ui_browser__warn_lost_events(struct ui_browser *browser)
-{
-	ui_browser__warning(browser, 4,
-		"Events are being lost, check IO/CPU overload!\n\n"
-		"You may want to run 'perf' using a RT scheduler policy:\n\n"
-		" perf top -r 80\n\n"
-		"Or reduce the sampling frequency.");
-}
-
-static int hist_browser__run(struct hist_browser *self, const char *ev_name,
-			     void(*timer)(void *arg), void *arg, int delay_secs)
-{
-	int key;
-	char title[160];
-
-	self->b.entries = &self->hists->entries;
-	self->b.nr_entries = self->hists->nr_entries;
-
-	hist_browser__refresh_dimensions(self);
-	hists__browser_title(self->hists, title, sizeof(title), ev_name);
-
-	if (ui_browser__show(&self->b, title,
-			     "Press '?' for help on key bindings") < 0)
-		return -1;
-
-	while (1) {
-		key = ui_browser__run(&self->b, delay_secs);
-
-		switch (key) {
-		case K_TIMER:
-			timer(arg);
-			ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
-
-			if (self->hists->stats.nr_lost_warned !=
-			    self->hists->stats.nr_events[PERF_RECORD_LOST]) {
-				self->hists->stats.nr_lost_warned =
-					self->hists->stats.nr_events[PERF_RECORD_LOST];
-				ui_browser__warn_lost_events(&self->b);
-			}
-
-			hists__browser_title(self->hists, title, sizeof(title), ev_name);
-			ui_browser__show_title(&self->b, title);
-			continue;
-		case 'D': { /* Debug */
-			static int seq;
-			struct hist_entry *h = rb_entry(self->b.top,
-							struct hist_entry, rb_node);
-			ui_helpline__pop();
-			ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
-					   seq++, self->b.nr_entries,
-					   self->hists->nr_entries,
-					   self->b.height,
-					   self->b.index,
-					   self->b.top_idx,
-					   h->row_offset, h->nr_rows);
-		}
-			break;
-		case 'C':
-			/* Collapse the whole world. */
-			hist_browser__set_folding(self, false);
-			break;
-		case 'E':
-			/* Expand the whole world. */
-			hist_browser__set_folding(self, true);
-			break;
-		case K_ENTER:
-			if (hist_browser__toggle_fold(self))
-				break;
-			/* fall thru */
-		default:
-			goto out;
-		}
-	}
-out:
-	ui_browser__hide(&self->b);
-	return key;
-}
-
-static char *callchain_list__sym_name(struct callchain_list *self,
-				      char *bf, size_t bfsize)
-{
-	if (self->ms.sym)
-		return self->ms.sym->name;
-
-	snprintf(bf, bfsize, "%#" PRIx64, self->ip);
-	return bf;
-}
-
-#define LEVEL_OFFSET_STEP 3
-
-static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
-						     struct callchain_node *chain_node,
-						     u64 total, int level,
-						     unsigned short row,
-						     off_t *row_offset,
-						     bool *is_current_entry)
-{
-	struct rb_node *node;
-	int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
-	u64 new_total, remaining;
-
-	if (callchain_param.mode == CHAIN_GRAPH_REL)
-		new_total = chain_node->children_hit;
-	else
-		new_total = total;
-
-	remaining = new_total;
-	node = rb_first(&chain_node->rb_root);
-	while (node) {
-		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
-		struct rb_node *next = rb_next(node);
-		u64 cumul = callchain_cumul_hits(child);
-		struct callchain_list *chain;
-		char folded_sign = ' ';
-		int first = true;
-		int extra_offset = 0;
-
-		remaining -= cumul;
-
-		list_for_each_entry(chain, &child->val, list) {
-			char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
-			const char *str;
-			int color;
-			bool was_first = first;
-
-			if (first)
-				first = false;
-			else
-				extra_offset = LEVEL_OFFSET_STEP;
-
-			folded_sign = callchain_list__folded(chain);
-			if (*row_offset != 0) {
-				--*row_offset;
-				goto do_next;
-			}
-
-			alloc_str = NULL;
-			str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
-			if (was_first) {
-				double percent = cumul * 100.0 / new_total;
-
-				if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
-					str = "Not enough memory!";
-				else
-					str = alloc_str;
-			}
-
-			color = HE_COLORSET_NORMAL;
-			width = self->b.width - (offset + extra_offset + 2);
-			if (ui_browser__is_current_entry(&self->b, row)) {
-				self->selection = &chain->ms;
-				color = HE_COLORSET_SELECTED;
-				*is_current_entry = true;
-			}
-
-			ui_browser__set_color(&self->b, color);
-			ui_browser__gotorc(&self->b, row, 0);
-			slsmg_write_nstring(" ", offset + extra_offset);
-			slsmg_printf("%c ", folded_sign);
-			slsmg_write_nstring(str, width);
-			free(alloc_str);
-
-			if (++row == self->b.height)
-				goto out;
-do_next:
-			if (folded_sign == '+')
-				break;
-		}
-
-		if (folded_sign == '-') {
-			const int new_level = level + (extra_offset ? 2 : 1);
-			row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
-									 new_level, row, row_offset,
-									 is_current_entry);
-		}
-		if (row == self->b.height)
-			goto out;
-		node = next;
-	}
-out:
-	return row - first_row;
-}
-
-static int hist_browser__show_callchain_node(struct hist_browser *self,
-					     struct callchain_node *node,
-					     int level, unsigned short row,
-					     off_t *row_offset,
-					     bool *is_current_entry)
-{
-	struct callchain_list *chain;
-	int first_row = row,
-	     offset = level * LEVEL_OFFSET_STEP,
-	     width = self->b.width - offset;
-	char folded_sign = ' ';
-
-	list_for_each_entry(chain, &node->val, list) {
-		char ipstr[BITS_PER_LONG / 4 + 1], *s;
-		int color;
-
-		folded_sign = callchain_list__folded(chain);
-
-		if (*row_offset != 0) {
-			--*row_offset;
-			continue;
-		}
-
-		color = HE_COLORSET_NORMAL;
-		if (ui_browser__is_current_entry(&self->b, row)) {
-			self->selection = &chain->ms;
-			color = HE_COLORSET_SELECTED;
-			*is_current_entry = true;
-		}
-
-		s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
-		ui_browser__gotorc(&self->b, row, 0);
-		ui_browser__set_color(&self->b, color);
-		slsmg_write_nstring(" ", offset);
-		slsmg_printf("%c ", folded_sign);
-		slsmg_write_nstring(s, width - 2);
-
-		if (++row == self->b.height)
-			goto out;
-	}
-
-	if (folded_sign == '-')
-		row += hist_browser__show_callchain_node_rb_tree(self, node,
-								 self->hists->stats.total_period,
-								 level + 1, row,
-								 row_offset,
-								 is_current_entry);
-out:
-	return row - first_row;
-}
-
-static int hist_browser__show_callchain(struct hist_browser *self,
-					struct rb_root *chain,
-					int level, unsigned short row,
-					off_t *row_offset,
-					bool *is_current_entry)
-{
-	struct rb_node *nd;
-	int first_row = row;
-
-	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-
-		row += hist_browser__show_callchain_node(self, node, level,
-							 row, row_offset,
-							 is_current_entry);
-		if (row == self->b.height)
-			break;
-	}
-
-	return row - first_row;
-}
-
-static int hist_browser__show_entry(struct hist_browser *self,
-				    struct hist_entry *entry,
-				    unsigned short row)
-{
-	char s[256];
-	double percent;
-	int printed = 0;
-	int width = self->b.width - 6; /* The percentage */
-	char folded_sign = ' ';
-	bool current_entry = ui_browser__is_current_entry(&self->b, row);
-	off_t row_offset = entry->row_offset;
-
-	if (current_entry) {
-		self->he_selection = entry;
-		self->selection = &entry->ms;
-	}
-
-	if (symbol_conf.use_callchain) {
-		hist_entry__init_have_children(entry);
-		folded_sign = hist_entry__folded(entry);
-	}
-
-	if (row_offset == 0) {
-		hist_entry__snprintf(entry, s, sizeof(s), self->hists);
-		percent = (entry->period * 100.0) / self->hists->stats.total_period;
-
-		ui_browser__set_percent_color(&self->b, percent, current_entry);
-		ui_browser__gotorc(&self->b, row, 0);
-		if (symbol_conf.use_callchain) {
-			slsmg_printf("%c ", folded_sign);
-			width -= 2;
-		}
-
-		slsmg_printf(" %5.2f%%", percent);
-
-		/* The scroll bar isn't being used */
-		if (!self->b.navkeypressed)
-			width += 1;
-
-		if (!current_entry || !self->b.navkeypressed)
-			ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
-
-		if (symbol_conf.show_nr_samples) {
-			slsmg_printf(" %11u", entry->nr_events);
-			width -= 12;
-		}
-
-		if (symbol_conf.show_total_period) {
-			slsmg_printf(" %12" PRIu64, entry->period);
-			width -= 13;
-		}
-
-		slsmg_write_nstring(s, width);
-		++row;
-		++printed;
-	} else
-		--row_offset;
-
-	if (folded_sign == '-' && row != self->b.height) {
-		printed += hist_browser__show_callchain(self, &entry->sorted_chain,
-							1, row, &row_offset,
-							&current_entry);
-		if (current_entry)
-			self->he_selection = entry;
-	}
-
-	return printed;
-}
-
-static void ui_browser__hists_init_top(struct ui_browser *browser)
-{
-	if (browser->top == NULL) {
-		struct hist_browser *hb;
-
-		hb = container_of(browser, struct hist_browser, b);
-		browser->top = rb_first(&hb->hists->entries);
-	}
-}
-
-static unsigned int hist_browser__refresh(struct ui_browser *self)
-{
-	unsigned row = 0;
-	struct rb_node *nd;
-	struct hist_browser *hb = container_of(self, struct hist_browser, b);
-
-	ui_browser__hists_init_top(self);
-
-	for (nd = self->top; nd; nd = rb_next(nd)) {
-		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-
-		if (h->filtered)
-			continue;
-
-		row += hist_browser__show_entry(hb, h, row);
-		if (row == self->height)
-			break;
-	}
-
-	return row;
-}
-
-static struct rb_node *hists__filter_entries(struct rb_node *nd)
-{
-	while (nd != NULL) {
-		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-		if (!h->filtered)
-			return nd;
-
-		nd = rb_next(nd);
-	}
-
-	return NULL;
-}
-
-static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
-{
-	while (nd != NULL) {
-		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-		if (!h->filtered)
-			return nd;
-
-		nd = rb_prev(nd);
-	}
-
-	return NULL;
-}
-
-static void ui_browser__hists_seek(struct ui_browser *self,
-				   off_t offset, int whence)
-{
-	struct hist_entry *h;
-	struct rb_node *nd;
-	bool first = true;
-
-	if (self->nr_entries == 0)
-		return;
-
-	ui_browser__hists_init_top(self);
-
-	switch (whence) {
-	case SEEK_SET:
-		nd = hists__filter_entries(rb_first(self->entries));
-		break;
-	case SEEK_CUR:
-		nd = self->top;
-		goto do_offset;
-	case SEEK_END:
-		nd = hists__filter_prev_entries(rb_last(self->entries));
-		first = false;
-		break;
-	default:
-		return;
-	}
-
-	/*
-	 * Moves not relative to the first visible entry invalidates its
-	 * row_offset:
-	 */
-	h = rb_entry(self->top, struct hist_entry, rb_node);
-	h->row_offset = 0;
-
-	/*
-	 * Here we have to check if nd is expanded (+), if it is we can't go
-	 * the next top level hist_entry, instead we must compute an offset of
-	 * what _not_ to show and not change the first visible entry.
-	 *
-	 * This offset increments when we are going from top to bottom and
-	 * decreases when we're going from bottom to top.
-	 *
-	 * As we don't have backpointers to the top level in the callchains
-	 * structure, we need to always print the whole hist_entry callchain,
-	 * skipping the first ones that are before the first visible entry
-	 * and stop when we printed enough lines to fill the screen.
-	 */
-do_offset:
-	if (offset > 0) {
-		do {
-			h = rb_entry(nd, struct hist_entry, rb_node);
-			if (h->ms.unfolded) {
-				u16 remaining = h->nr_rows - h->row_offset;
-				if (offset > remaining) {
-					offset -= remaining;
-					h->row_offset = 0;
-				} else {
-					h->row_offset += offset;
-					offset = 0;
-					self->top = nd;
-					break;
-				}
-			}
-			nd = hists__filter_entries(rb_next(nd));
-			if (nd == NULL)
-				break;
-			--offset;
-			self->top = nd;
-		} while (offset != 0);
-	} else if (offset < 0) {
-		while (1) {
-			h = rb_entry(nd, struct hist_entry, rb_node);
-			if (h->ms.unfolded) {
-				if (first) {
-					if (-offset > h->row_offset) {
-						offset += h->row_offset;
-						h->row_offset = 0;
-					} else {
-						h->row_offset += offset;
-						offset = 0;
-						self->top = nd;
-						break;
-					}
-				} else {
-					if (-offset > h->nr_rows) {
-						offset += h->nr_rows;
-						h->row_offset = 0;
-					} else {
-						h->row_offset = h->nr_rows + offset;
-						offset = 0;
-						self->top = nd;
-						break;
-					}
-				}
-			}
-
-			nd = hists__filter_prev_entries(rb_prev(nd));
-			if (nd == NULL)
-				break;
-			++offset;
-			self->top = nd;
-			if (offset == 0) {
-				/*
-				 * Last unfiltered hist_entry, check if it is
-				 * unfolded, if it is then we should have
-				 * row_offset at its last entry.
-				 */
-				h = rb_entry(nd, struct hist_entry, rb_node);
-				if (h->ms.unfolded)
-					h->row_offset = h->nr_rows;
-				break;
-			}
-			first = false;
-		}
-	} else {
-		self->top = nd;
-		h = rb_entry(nd, struct hist_entry, rb_node);
-		h->row_offset = 0;
-	}
-}
-
-static struct hist_browser *hist_browser__new(struct hists *hists)
-{
-	struct hist_browser *self = zalloc(sizeof(*self));
-
-	if (self) {
-		self->hists = hists;
-		self->b.refresh = hist_browser__refresh;
-		self->b.seek = ui_browser__hists_seek;
-		self->b.use_navkeypressed = true;
-		if (sort__branch_mode == 1)
-			self->has_symbols = sort_sym_from.list.next != NULL;
-		else
-			self->has_symbols = sort_sym.list.next != NULL;
-	}
-
-	return self;
-}
-
-static void hist_browser__delete(struct hist_browser *self)
-{
-	free(self);
-}
-
-static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
-{
-	return self->he_selection;
-}
-
-static struct thread *hist_browser__selected_thread(struct hist_browser *self)
-{
-	return self->he_selection->thread;
-}
-
-static int hists__browser_title(struct hists *self, char *bf, size_t size,
-				const char *ev_name)
-{
-	char unit;
-	int printed;
-	const struct dso *dso = self->dso_filter;
-	const struct thread *thread = self->thread_filter;
-	unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
-
-	nr_events = convert_unit(nr_events, &unit);
-	printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
-
-	if (self->uid_filter_str)
-		printed += snprintf(bf + printed, size - printed,
-				    ", UID: %s", self->uid_filter_str);
-	if (thread)
-		printed += scnprintf(bf + printed, size - printed,
-				    ", Thread: %s(%d)",
-				    (thread->comm_set ? thread->comm : ""),
-				    thread->pid);
-	if (dso)
-		printed += scnprintf(bf + printed, size - printed,
-				    ", DSO: %s", dso->short_name);
-	return printed;
-}
-
-static inline void free_popup_options(char **options, int n)
-{
-	int i;
-
-	for (i = 0; i < n; ++i) {
-		free(options[i]);
-		options[i] = NULL;
-	}
-}
-
-static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
-				    const char *helpline, const char *ev_name,
-				    bool left_exits,
-				    void(*timer)(void *arg), void *arg,
-				    int delay_secs)
-{
-	struct hists *self = &evsel->hists;
-	struct hist_browser *browser = hist_browser__new(self);
-	struct branch_info *bi;
-	struct pstack *fstack;
-	char *options[16];
-	int nr_options = 0;
-	int key = -1;
-	char buf[64];
-
-	if (browser == NULL)
-		return -1;
-
-	fstack = pstack__new(2);
-	if (fstack == NULL)
-		goto out;
-
-	ui_helpline__push(helpline);
-
-	memset(options, 0, sizeof(options));
-
-	while (1) {
-		const struct thread *thread = NULL;
-		const struct dso *dso = NULL;
-		int choice = 0,
-		    annotate = -2, zoom_dso = -2, zoom_thread = -2,
-		    annotate_f = -2, annotate_t = -2, browse_map = -2;
-
-		nr_options = 0;
-
-		key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
-
-		if (browser->he_selection != NULL) {
-			thread = hist_browser__selected_thread(browser);
-			dso = browser->selection->map ? browser->selection->map->dso : NULL;
-		}
-		switch (key) {
-		case K_TAB:
-		case K_UNTAB:
-			if (nr_events == 1)
-				continue;
-			/*
-			 * Exit the browser, let hists__browser_tree
-			 * go to the next or previous
-			 */
-			goto out_free_stack;
-		case 'a':
-			if (!browser->has_symbols) {
-				ui_browser__warning(&browser->b, delay_secs * 2,
-			"Annotation is only available for symbolic views, "
-			"include \"sym*\" in --sort to use it.");
-				continue;
-			}
-
-			if (browser->selection == NULL ||
-			    browser->selection->sym == NULL ||
-			    browser->selection->map->dso->annotate_warned)
-				continue;
-			goto do_annotate;
-		case 'd':
-			goto zoom_dso;
-		case 't':
-			goto zoom_thread;
-		case 's':
-			if (ui_browser__input_window("Symbol to show",
-					"Please enter the name of symbol you want to see",
-					buf, "ENTER: OK, ESC: Cancel",
-					delay_secs * 2) == K_ENTER) {
-				self->symbol_filter_str = *buf ? buf : NULL;
-				hists__filter_by_symbol(self);
-				hist_browser__reset(browser);
-			}
-			continue;
-		case K_F1:
-		case 'h':
-		case '?':
-			ui_browser__help_window(&browser->b,
-					"h/?/F1        Show this window\n"
-					"UP/DOWN/PGUP\n"
-					"PGDN/SPACE    Navigate\n"
-					"q/ESC/CTRL+C  Exit browser\n\n"
-					"For multiple event sessions:\n\n"
-					"TAB/UNTAB Switch events\n\n"
-					"For symbolic views (--sort has sym):\n\n"
-					"->            Zoom into DSO/Threads & Annotate current symbol\n"
-					"<-            Zoom out\n"
-					"a             Annotate current symbol\n"
-					"C             Collapse all callchains\n"
-					"E             Expand all callchains\n"
-					"d             Zoom into current DSO\n"
-					"t             Zoom into current Thread\n"
-					"s             Filter symbol by name");
-			continue;
-		case K_ENTER:
-		case K_RIGHT:
-			/* menu */
-			break;
-		case K_LEFT: {
-			const void *top;
-
-			if (pstack__empty(fstack)) {
-				/*
-				 * Go back to the perf_evsel_menu__run or other user
-				 */
-				if (left_exits)
-					goto out_free_stack;
-				continue;
-			}
-			top = pstack__pop(fstack);
-			if (top == &browser->hists->dso_filter)
-				goto zoom_out_dso;
-			if (top == &browser->hists->thread_filter)
-				goto zoom_out_thread;
-			continue;
-		}
-		case K_ESC:
-			if (!left_exits &&
-			    !ui_browser__dialog_yesno(&browser->b,
-					       "Do you really want to exit?"))
-				continue;
-			/* Fall thru */
-		case 'q':
-		case CTRL('c'):
-			goto out_free_stack;
-		default:
-			continue;
-		}
-
-		if (!browser->has_symbols)
-			goto add_exit_option;
-
-		if (sort__branch_mode == 1) {
-			bi = browser->he_selection->branch_info;
-			if (browser->selection != NULL &&
-			    bi &&
-			    bi->from.sym != NULL &&
-			    !bi->from.map->dso->annotate_warned &&
-				asprintf(&options[nr_options], "Annotate %s",
-					 bi->from.sym->name) > 0)
-				annotate_f = nr_options++;
-
-			if (browser->selection != NULL &&
-			    bi &&
-			    bi->to.sym != NULL &&
-			    !bi->to.map->dso->annotate_warned &&
-			    (bi->to.sym != bi->from.sym ||
-			     bi->to.map->dso != bi->from.map->dso) &&
-				asprintf(&options[nr_options], "Annotate %s",
-					 bi->to.sym->name) > 0)
-				annotate_t = nr_options++;
-		} else {
-
-			if (browser->selection != NULL &&
-			    browser->selection->sym != NULL &&
-			    !browser->selection->map->dso->annotate_warned &&
-				asprintf(&options[nr_options], "Annotate %s",
-					 browser->selection->sym->name) > 0)
-				annotate = nr_options++;
-		}
-
-		if (thread != NULL &&
-		    asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
-			     (browser->hists->thread_filter ? "out of" : "into"),
-			     (thread->comm_set ? thread->comm : ""),
-			     thread->pid) > 0)
-			zoom_thread = nr_options++;
-
-		if (dso != NULL &&
-		    asprintf(&options[nr_options], "Zoom %s %s DSO",
-			     (browser->hists->dso_filter ? "out of" : "into"),
-			     (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
-			zoom_dso = nr_options++;
-
-		if (browser->selection != NULL &&
-		    browser->selection->map != NULL &&
-		    asprintf(&options[nr_options], "Browse map details") > 0)
-			browse_map = nr_options++;
-add_exit_option:
-		options[nr_options++] = (char *)"Exit";
-retry_popup_menu:
-		choice = ui__popup_menu(nr_options, options);
-
-		if (choice == nr_options - 1)
-			break;
-
-		if (choice == -1) {
-			free_popup_options(options, nr_options - 1);
-			continue;
-		}
-
-		if (choice == annotate || choice == annotate_t || choice == annotate_f) {
-			struct hist_entry *he;
-			int err;
-do_annotate:
-			he = hist_browser__selected_entry(browser);
-			if (he == NULL)
-				continue;
-
-			/*
-			 * we stash the branch_info symbol + map into the
-			 * the ms so we don't have to rewrite all the annotation
-			 * code to use branch_info.
-			 * in branch mode, the ms struct is not used
-			 */
-			if (choice == annotate_f) {
-				he->ms.sym = he->branch_info->from.sym;
-				he->ms.map = he->branch_info->from.map;
-			}  else if (choice == annotate_t) {
-				he->ms.sym = he->branch_info->to.sym;
-				he->ms.map = he->branch_info->to.map;
-			}
-
-			/*
-			 * Don't let this be freed, say, by hists__decay_entry.
-			 */
-			he->used = true;
-			err = hist_entry__tui_annotate(he, evsel->idx,
-						       timer, arg, delay_secs);
-			he->used = false;
-			/*
-			 * offer option to annotate the other branch source or target
-			 * (if they exists) when returning from annotate
-			 */
-			if ((err == 'q' || err == CTRL('c'))
-			    && annotate_t != -2 && annotate_f != -2)
-				goto retry_popup_menu;
-
-			ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
-			if (err)
-				ui_browser__handle_resize(&browser->b);
-
-		} else if (choice == browse_map)
-			map__browse(browser->selection->map);
-		else if (choice == zoom_dso) {
-zoom_dso:
-			if (browser->hists->dso_filter) {
-				pstack__remove(fstack, &browser->hists->dso_filter);
-zoom_out_dso:
-				ui_helpline__pop();
-				browser->hists->dso_filter = NULL;
-				sort_dso.elide = false;
-			} else {
-				if (dso == NULL)
-					continue;
-				ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
-						   dso->kernel ? "the Kernel" : dso->short_name);
-				browser->hists->dso_filter = dso;
-				sort_dso.elide = true;
-				pstack__push(fstack, &browser->hists->dso_filter);
-			}
-			hists__filter_by_dso(self);
-			hist_browser__reset(browser);
-		} else if (choice == zoom_thread) {
-zoom_thread:
-			if (browser->hists->thread_filter) {
-				pstack__remove(fstack, &browser->hists->thread_filter);
-zoom_out_thread:
-				ui_helpline__pop();
-				browser->hists->thread_filter = NULL;
-				sort_thread.elide = false;
-			} else {
-				ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
-						   thread->comm_set ? thread->comm : "",
-						   thread->pid);
-				browser->hists->thread_filter = thread;
-				sort_thread.elide = true;
-				pstack__push(fstack, &browser->hists->thread_filter);
-			}
-			hists__filter_by_thread(self);
-			hist_browser__reset(browser);
-		}
-	}
-out_free_stack:
-	pstack__delete(fstack);
-out:
-	hist_browser__delete(browser);
-	free_popup_options(options, nr_options - 1);
-	return key;
-}
-
-struct perf_evsel_menu {
-	struct ui_browser b;
-	struct perf_evsel *selection;
-	bool lost_events, lost_events_warned;
-};
-
-static void perf_evsel_menu__write(struct ui_browser *browser,
-				   void *entry, int row)
-{
-	struct perf_evsel_menu *menu = container_of(browser,
-						    struct perf_evsel_menu, b);
-	struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
-	bool current_entry = ui_browser__is_current_entry(browser, row);
-	unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
-	const char *ev_name = event_name(evsel);
-	char bf[256], unit;
-	const char *warn = " ";
-	size_t printed;
-
-	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
-						       HE_COLORSET_NORMAL);
-
-	nr_events = convert_unit(nr_events, &unit);
-	printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
-			   unit, unit == ' ' ? "" : " ", ev_name);
-	slsmg_printf("%s", bf);
-
-	nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
-	if (nr_events != 0) {
-		menu->lost_events = true;
-		if (!current_entry)
-			ui_browser__set_color(browser, HE_COLORSET_TOP);
-		nr_events = convert_unit(nr_events, &unit);
-		printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
-				     nr_events, unit, unit == ' ' ? "" : " ");
-		warn = bf;
-	}
-
-	slsmg_write_nstring(warn, browser->width - printed);
-
-	if (current_entry)
-		menu->selection = evsel;
-}
-
-static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
-				int nr_events, const char *help,
-				void(*timer)(void *arg), void *arg, int delay_secs)
-{
-	struct perf_evlist *evlist = menu->b.priv;
-	struct perf_evsel *pos;
-	const char *ev_name, *title = "Available samples";
-	int key;
-
-	if (ui_browser__show(&menu->b, title,
-			     "ESC: exit, ENTER|->: Browse histograms") < 0)
-		return -1;
-
-	while (1) {
-		key = ui_browser__run(&menu->b, delay_secs);
-
-		switch (key) {
-		case K_TIMER:
-			timer(arg);
-
-			if (!menu->lost_events_warned && menu->lost_events) {
-				ui_browser__warn_lost_events(&menu->b);
-				menu->lost_events_warned = true;
-			}
-			continue;
-		case K_RIGHT:
-		case K_ENTER:
-			if (!menu->selection)
-				continue;
-			pos = menu->selection;
-browse_hists:
-			perf_evlist__set_selected(evlist, pos);
-			/*
-			 * Give the calling tool a chance to populate the non
-			 * default evsel resorted hists tree.
-			 */
-			if (timer)
-				timer(arg);
-			ev_name = event_name(pos);
-			key = perf_evsel__hists_browse(pos, nr_events, help,
-						       ev_name, true, timer,
-						       arg, delay_secs);
-			ui_browser__show_title(&menu->b, title);
-			switch (key) {
-			case K_TAB:
-				if (pos->node.next == &evlist->entries)
-					pos = list_entry(evlist->entries.next, struct perf_evsel, node);
-				else
-					pos = list_entry(pos->node.next, struct perf_evsel, node);
-				goto browse_hists;
-			case K_UNTAB:
-				if (pos->node.prev == &evlist->entries)
-					pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
-				else
-					pos = list_entry(pos->node.prev, struct perf_evsel, node);
-				goto browse_hists;
-			case K_ESC:
-				if (!ui_browser__dialog_yesno(&menu->b,
-						"Do you really want to exit?"))
-					continue;
-				/* Fall thru */
-			case 'q':
-			case CTRL('c'):
-				goto out;
-			default:
-				continue;
-			}
-		case K_LEFT:
-			continue;
-		case K_ESC:
-			if (!ui_browser__dialog_yesno(&menu->b,
-					       "Do you really want to exit?"))
-				continue;
-			/* Fall thru */
-		case 'q':
-		case CTRL('c'):
-			goto out;
-		default:
-			continue;
-		}
-	}
-
-out:
-	ui_browser__hide(&menu->b);
-	return key;
-}
-
-static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
-					   const char *help,
-					   void(*timer)(void *arg), void *arg,
-					   int delay_secs)
-{
-	struct perf_evsel *pos;
-	struct perf_evsel_menu menu = {
-		.b = {
-			.entries    = &evlist->entries,
-			.refresh    = ui_browser__list_head_refresh,
-			.seek	    = ui_browser__list_head_seek,
-			.write	    = perf_evsel_menu__write,
-			.nr_entries = evlist->nr_entries,
-			.priv	    = evlist,
-		},
-	};
-
-	ui_helpline__push("Press ESC to exit");
-
-	list_for_each_entry(pos, &evlist->entries, node) {
-		const char *ev_name = event_name(pos);
-		size_t line_len = strlen(ev_name) + 7;
-
-		if (menu.b.width < line_len)
-			menu.b.width = line_len;
-		/*
-		 * Cache the evsel name, tracepoints have a _high_ cost per
-		 * event_name() call.
-		 */
-		if (pos->name == NULL)
-			pos->name = strdup(ev_name);
-	}
-
-	return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
-				    arg, delay_secs);
-}
-
-int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
-				  void(*timer)(void *arg), void *arg,
-				  int delay_secs)
-{
-
-	if (evlist->nr_entries == 1) {
-		struct perf_evsel *first = list_entry(evlist->entries.next,
-						      struct perf_evsel, node);
-		const char *ev_name = event_name(first);
-		return perf_evsel__hists_browse(first, evlist->nr_entries, help,
-						ev_name, false, timer, arg,
-						delay_secs);
-	}
-
-	return __perf_evlist__tui_browse_hists(evlist, help,
-					       timer, arg, delay_secs);
-}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
deleted file mode 100644
index eca6575..0000000
--- a/tools/perf/util/ui/browsers/map.c
+++ /dev/null
@@ -1,154 +0,0 @@
-#include "../libslang.h"
-#include <elf.h>
-#include <newt.h>
-#include <inttypes.h>
-#include <sys/ttydefaults.h>
-#include <string.h>
-#include <linux/bitops.h>
-#include "../../util.h"
-#include "../../debug.h"
-#include "../../symbol.h"
-#include "../browser.h"
-#include "../helpline.h"
-#include "map.h"
-
-static int ui_entry__read(const char *title, char *bf, size_t size, int width)
-{
-	struct newtExitStruct es;
-	newtComponent form, entry;
-	const char *result;
-	int err = -1;
-
-	newtCenteredWindow(width, 1, title);
-	form = newtForm(NULL, NULL, 0);
-	if (form == NULL)
-		return -1;
-
-	entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
-	if (entry == NULL)
-		goto out_free_form;
-
-	newtFormAddComponent(form, entry);
-	newtFormAddHotKey(form, NEWT_KEY_ENTER);
-	newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
-	newtFormAddHotKey(form, NEWT_KEY_LEFT);
-	newtFormAddHotKey(form, CTRL('c'));
-	newtFormRun(form, &es);
-
-	if (result != NULL) {
-		strncpy(bf, result, size);
-		err = 0;
-	}
-out_free_form:
-	newtPopWindow();
-	newtFormDestroy(form);
-	return err;
-}
-
-struct map_browser {
-	struct ui_browser b;
-	struct map	  *map;
-	u8		  addrlen;
-};
-
-static void map_browser__write(struct ui_browser *self, void *nd, int row)
-{
-	struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
-	struct map_browser *mb = container_of(self, struct map_browser, b);
-	bool current_entry = ui_browser__is_current_entry(self, row);
-	int width;
-
-	ui_browser__set_percent_color(self, 0, current_entry);
-	slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
-		     mb->addrlen, sym->start, mb->addrlen, sym->end,
-		     sym->binding == STB_GLOBAL ? 'g' :
-		     sym->binding == STB_LOCAL  ? 'l' : 'w');
-	width = self->width - ((mb->addrlen * 2) + 4);
-	if (width > 0)
-		slsmg_write_nstring(sym->name, width);
-}
-
-/* FIXME uber-kludgy, see comment on cmd_report... */
-static u32 *symbol__browser_index(struct symbol *self)
-{
-	return ((void *)self) - sizeof(struct rb_node) - sizeof(u32);
-}
-
-static int map_browser__search(struct map_browser *self)
-{
-	char target[512];
-	struct symbol *sym;
-	int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40);
-
-	if (err)
-		return err;
-
-	if (target[0] == '0' && tolower(target[1]) == 'x') {
-		u64 addr = strtoull(target, NULL, 16);
-		sym = map__find_symbol(self->map, addr, NULL);
-	} else
-		sym = map__find_symbol_by_name(self->map, target, NULL);
-
-	if (sym != NULL) {
-		u32 *idx = symbol__browser_index(sym);
-
-		self->b.top = &sym->rb_node;
-		self->b.index = self->b.top_idx = *idx;
-	} else
-		ui_helpline__fpush("%s not found!", target);
-
-	return 0;
-}
-
-static int map_browser__run(struct map_browser *self)
-{
-	int key;
-
-	if (ui_browser__show(&self->b, self->map->dso->long_name,
-			     "Press <- or ESC to exit, %s / to search",
-			     verbose ? "" : "restart with -v to use") < 0)
-		return -1;
-
-	while (1) {
-		key = ui_browser__run(&self->b, 0);
-
-		if (verbose && key == '/')
-			map_browser__search(self);
-		else
-			break;
-	}
-
-	ui_browser__hide(&self->b);
-	return key;
-}
-
-int map__browse(struct map *self)
-{
-	struct map_browser mb = {
-		.b = {
-			.entries = &self->dso->symbols[self->type],
-			.refresh = ui_browser__rb_tree_refresh,
-			.seek	 = ui_browser__rb_tree_seek,
-			.write	 = map_browser__write,
-		},
-		.map = self,
-	};
-	struct rb_node *nd;
-	char tmp[BITS_PER_LONG / 4];
-	u64 maxaddr = 0;
-
-	for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
-		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
-
-		if (maxaddr < pos->end)
-			maxaddr = pos->end;
-		if (verbose) {
-			u32 *idx = symbol__browser_index(pos);
-			*idx = mb.b.nr_entries;
-		}
-		++mb.b.nr_entries;
-	}
-
-	mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
-	return map_browser__run(&mb);
-}
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
deleted file mode 100644
index 85a69fa..0000000
--- a/tools/perf/util/ui/setup.c
+++ /dev/null
@@ -1,155 +0,0 @@
-#include <newt.h>
-#include <signal.h>
-#include <stdbool.h>
-
-#include "../cache.h"
-#include "../debug.h"
-#include "browser.h"
-#include "helpline.h"
-#include "ui.h"
-#include "util.h"
-#include "libslang.h"
-#include "keysyms.h"
-
-pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
-
-static volatile int ui__need_resize;
-
-void ui__refresh_dimensions(bool force)
-{
-	if (force || ui__need_resize) {
-		ui__need_resize = 0;
-		pthread_mutex_lock(&ui__lock);
-		SLtt_get_screen_size();
-		SLsmg_reinit_smg();
-		pthread_mutex_unlock(&ui__lock);
-	}
-}
-
-static void ui__sigwinch(int sig __used)
-{
-	ui__need_resize = 1;
-}
-
-static void ui__setup_sigwinch(void)
-{
-	static bool done;
-
-	if (done)
-		return;
-
-	done = true;
-	pthread__unblock_sigwinch();
-	signal(SIGWINCH, ui__sigwinch);
-}
-
-int ui__getch(int delay_secs)
-{
-	struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
-	fd_set read_set;
-	int err, key;
-
-	ui__setup_sigwinch();
-
-	FD_ZERO(&read_set);
-	FD_SET(0, &read_set);
-
-	if (delay_secs) {
-		timeout.tv_sec = delay_secs;
-		timeout.tv_usec = 0;
-	}
-
-        err = select(1, &read_set, NULL, NULL, ptimeout);
-
-	if (err == 0)
-		return K_TIMER;
-
-	if (err == -1) {
-		if (errno == EINTR)
-			return K_RESIZE;
-		return K_ERROR;
-	}
-
-	key = SLang_getkey();
-	if (key != K_ESC)
-		return key;
-
-	FD_ZERO(&read_set);
-	FD_SET(0, &read_set);
-	timeout.tv_sec = 0;
-	timeout.tv_usec = 20;
-        err = select(1, &read_set, NULL, NULL, &timeout);
-	if (err == 0)
-		return K_ESC;
-
-	SLang_ungetkey(key);
-	return SLkp_getkey();
-}
-
-static void newt_suspend(void *d __used)
-{
-	newtSuspend();
-	raise(SIGTSTP);
-	newtResume();
-}
-
-static int ui__init(void)
-{
-	int err = SLkp_init();
-
-	if (err < 0)
-		goto out;
-
-	SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
-out:
-	return err;
-}
-
-static void ui__exit(void)
-{
-	SLtt_set_cursor_visibility(1);
-	SLsmg_refresh();
-	SLsmg_reset_smg();
-	SLang_reset_tty();
-}
-
-static void ui__signal(int sig)
-{
-	ui__exit();
-	psignal(sig, "perf");
-	exit(0);
-}
-
-void setup_browser(bool fallback_to_pager)
-{
-	if (!isatty(1) || !use_browser || dump_trace) {
-		use_browser = 0;
-		if (fallback_to_pager)
-			setup_pager();
-		return;
-	}
-
-	use_browser = 1;
-	newtInit();
-	ui__init();
-	newtSetSuspendCallback(newt_suspend, NULL);
-	ui_helpline__init();
-	ui_browser__init();
-
-	signal(SIGSEGV, ui__signal);
-	signal(SIGFPE, ui__signal);
-	signal(SIGINT, ui__signal);
-	signal(SIGQUIT, ui__signal);
-	signal(SIGTERM, ui__signal);
-}
-
-void exit_browser(bool wait_for_ok)
-{
-	if (use_browser > 0) {
-		if (wait_for_ok)
-			ui__question_window("Fatal Error",
-					    ui_helpline__last_msg,
-					    "Press any key...", 0);
-		ui__exit();
-	}
-}
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index 52bb07c..4007aca 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -82,41 +82,3 @@
 	warn_routine(warn, params);
 	va_end(params);
 }
-
-uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
-{
-	struct passwd pwd, *result;
-	char buf[1024];
-
-	if (str == NULL)
-		return UINT_MAX;
-
-	/* UID and PID are mutually exclusive */
-	if (tid || pid) {
-		ui__warning("PID/TID switch overriding UID\n");
-		sleep(1);
-		return UINT_MAX;
-	}
-
-	getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
-
-	if (result == NULL) {
-		char *endptr;
-		int uid = strtol(str, &endptr, 10);
-
-		if (*endptr != '\0') {
-			ui__error("Invalid user %s\n", str);
-			return UINT_MAX - 1;
-		}
-
-		getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
-
-		if (result == NULL) {
-			ui__error("Problems obtaining information for user %s\n",
-				  str);
-			return UINT_MAX - 1;
-		}
-	}
-
-	return result->pw_uid;
-}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 8109a90..d03599f 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -148,3 +148,13 @@
 
 	return buf - buf_start;
 }
+
+size_t hex_width(u64 v)
+{
+	size_t n = 1;
+
+	while ((v >>= 4))
+		++n;
+
+	return n;
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0f99f39..2daaedb 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -74,7 +74,6 @@
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include <netdb.h>
-#include <pwd.h>
 #include <inttypes.h>
 #include "../../../include/linux/magic.h"
 #include "types.h"
@@ -249,8 +248,6 @@
 
 void event_attr_init(struct perf_event_attr *attr);
 
-uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
-
 #define _STR(x) #x
 #define STR(x) _STR(x)
 
@@ -265,4 +262,6 @@
 	return (n != 0 && ((n & (n - 1)) == 0));
 }
 
+size_t hex_width(u64 v);
+
 #endif
diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1
index c4954a9..9dbd536 100644
--- a/tools/power/cpupower/man/cpupower-set.1
+++ b/tools/power/cpupower/man/cpupower-set.1
@@ -85,15 +85,6 @@
 savings
 .RE
 
-sched_mc_power_savings is dependent upon SCHED_MC, which is
-itself architecture dependent.
-
-sched_smt_power_savings is dependent upon SCHED_SMT, which
-is itself architecture dependent.
-
-The two files are independent of each other. It is possible
-that one file may be present without the other.
-
 .SH "SEE ALSO"
 cpupower-info(1), cpupower-monitor(1), powertop(1)
 .PP
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index c634302..96e28c1 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -362,22 +362,7 @@
  */
 int sysfs_get_sched(const char *smt_mc)
 {
-	unsigned long value;
-	char linebuf[MAX_LINE_LEN];
-	char *endp;
-	char path[SYSFS_PATH_MAX];
-
-	if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
-		return -EINVAL;
-
-	snprintf(path, sizeof(path),
-		PATH_TO_CPU "sched_%s_power_savings", smt_mc);
-	if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
-		return -1;
-	value = strtoul(linebuf, &endp, 0);
-	if (endp == linebuf || errno == ERANGE)
-		return -1;
-	return value;
+	return -ENODEV;
 }
 
 /*
@@ -388,21 +373,5 @@
  */
 int sysfs_set_sched(const char *smt_mc, int val)
 {
-	char linebuf[MAX_LINE_LEN];
-	char path[SYSFS_PATH_MAX];
-	struct stat statbuf;
-
-	if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
-		return -EINVAL;
-
-	snprintf(path, sizeof(path),
-		PATH_TO_CPU "sched_%s_power_savings", smt_mc);
-	sprintf(linebuf, "%d", val);
-
-	if (stat(path, &statbuf) != 0)
-		return -ENODEV;
-
-	if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0)
-		return -1;
-	return 0;
+	return -ENODEV;
 }
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
new file mode 100644
index 0000000..bde8521
--- /dev/null
+++ b/tools/scripts/Makefile.include
@@ -0,0 +1,58 @@
+ifeq ("$(origin O)", "command line")
+	OUTPUT := $(O)/
+	COMMAND_O := O=$(O)
+endif
+
+ifneq ($(OUTPUT),)
+# check that the output directory actually exists
+OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
+$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
+endif
+
+#
+# Include saner warnings here, which can catch bugs:
+#
+EXTRA_WARNINGS := -Wbad-function-cast
+EXTRA_WARNINGS += -Wdeclaration-after-statement
+EXTRA_WARNINGS += -Wformat-security
+EXTRA_WARNINGS += -Wformat-y2k
+EXTRA_WARNINGS += -Winit-self
+EXTRA_WARNINGS += -Wmissing-declarations
+EXTRA_WARNINGS += -Wmissing-prototypes
+EXTRA_WARNINGS += -Wnested-externs
+EXTRA_WARNINGS += -Wno-system-headers
+EXTRA_WARNINGS += -Wold-style-definition
+EXTRA_WARNINGS += -Wpacked
+EXTRA_WARNINGS += -Wredundant-decls
+EXTRA_WARNINGS += -Wshadow
+EXTRA_WARNINGS += -Wstrict-aliasing=3
+EXTRA_WARNINGS += -Wstrict-prototypes
+EXTRA_WARNINGS += -Wswitch-default
+EXTRA_WARNINGS += -Wswitch-enum
+EXTRA_WARNINGS += -Wundef
+EXTRA_WARNINGS += -Wwrite-strings
+EXTRA_WARNINGS += -Wformat
+
+ifneq ($(findstring $(MAKEFLAGS), w),w)
+PRINT_DIR = --no-print-directory
+else
+NO_SUBDIR = :
+endif
+
+QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
+QUIET_SUBDIR1  =
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+	QUIET_CC       = @echo '   ' CC $@;
+	QUIET_AR       = @echo '   ' AR $@;
+	QUIET_LINK     = @echo '   ' LINK $@;
+	QUIET_MKDIR    = @echo '   ' MKDIR $@;
+	QUIET_GEN      = @echo '   ' GEN $@;
+	QUIET_SUBDIR0  = +@subdir=
+	QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
+			 $(MAKE) $(PRINT_DIR) -C $$subdir
+	QUIET_FLEX     = @echo '   ' FLEX $@;
+	QUIET_BISON    = @echo '   ' BISON $@;
+endif
+endif
diff --git a/tools/testing/ktest/examples/README b/tools/testing/ktest/examples/README
new file mode 100644
index 0000000..a12d295
--- /dev/null
+++ b/tools/testing/ktest/examples/README
@@ -0,0 +1,32 @@
+This directory contains example configs to use ktest for various tasks.
+The configs still need to be customized for your environment, but it
+is broken up by task which makes it easier to understand how to set up
+ktest.
+
+The configs are based off of real working configs but have been modified
+and commented to show more generic use cases that are more helpful for
+developers.
+
+crosstests.conf - this config shows an example of testing a git repo against
+    lots of different architectures. It only does build tests, but makes
+    it easy to compile test different archs. You can download the arch
+    cross compilers from:
+  http://kernel.org/pub/tools/crosstool/files/bin/x86_64/
+
+test.conf - A generic example of a config. This is based on an actual config
+     used to perform real testing.
+
+kvm.conf - A example of a config that is used to test a virtual guest running
+     on a host.
+
+snowball.conf - An example config that was used to demo ktest.pl against
+     a snowball ARM board.
+
+include/  -  The include directory holds default configs that can be
+    included into other configs. This is a real use example that shows how
+    to reuse configs for various machines or set ups. The files here
+    are included by other config files, where the other config files define
+    options and variables that will make the included config work for the
+    given environment.
+
+
diff --git a/tools/testing/ktest/examples/crosstests.conf b/tools/testing/ktest/examples/crosstests.conf
new file mode 100644
index 0000000..4673660
--- /dev/null
+++ b/tools/testing/ktest/examples/crosstests.conf
@@ -0,0 +1,260 @@
+#
+# Example config for cross compiling
+#
+# In this config, it is expected that the tool chains from:
+#
+#   http://kernel.org/pub/tools/crosstool/files/bin/x86_64/
+#
+# running on a x86_64 system have been downloaded and installed into:
+#
+#   /usr/local/
+#
+# such that the compiler binaries are something like:
+#
+#   /usr/local/gcc-4.5.2-nolibc/mips-linux/bin/mips-linux-gcc
+#
+# Some of the archs will use gcc-4.5.1 instead of gcc-4.5.2
+# this config uses variables to differentiate them.
+# 
+# Comments describe some of the options, but full descriptions of
+# options are described in the samples.conf file.
+
+# ${PWD} is defined by ktest.pl to be the directory that the user
+# was in when they executed ktest.pl. It may be better to hardcode the
+# path name here. THIS_DIR is the variable used through out the config file
+# in case you want to change it.
+
+THIS_DIR := ${PWD}
+
+# Update the BUILD_DIR option to the location of your git repo you want to test.
+BUILD_DIR = ${THIS_DIR}/linux.git
+
+# The build will go into this directory. It will be created when you run the test.
+OUTPUT_DIR = ${THIS_DIR}/cross-compile
+
+# The build will be compiled with -j8
+BUILD_OPTIONS = -j8
+
+# The test will not stop when it hits a failure.
+DIE_ON_FAILURE = 0
+
+# If you want to have ktest.pl store the failure somewhere, uncomment this option
+# and change the directory where ktest should store the failures.
+#STORE_FAILURES = ${THIS_DIR}/failures
+
+# The log file is stored in the OUTPUT_DIR called cross.log
+# If you enable this, you need to create the OUTPUT_DIR. It wont be created for you.
+LOG_FILE = ${OUTPUT_DIR}/cross.log
+
+# The log file will be cleared each time you run ktest.
+CLEAR_LOG = 1
+
+# As some archs do not build with the defconfig, they have been marked
+# to be ignored. If you want to test them anyway, change DO_FAILED to 1.
+# If a test that has been marked as DO_FAILED passes, then you should change
+# that test to be DO_DEFAULT
+
+DO_FAILED := 0
+DO_DEFAULT := 1
+
+# By setting both DO_FAILED and DO_DEFAULT to zero, you can pick a single
+# arch that you want to test. (uncomment RUN and chose your arch)
+#RUN := m32r
+
+# At the bottom of the config file exists a bisect test. You can update that
+# test and set DO_FAILED and DO_DEFAULT to zero, and uncomment this variable
+# to run the bisect on the arch.
+#RUN := bisect
+
+# By default all tests will be running gcc 4.5.2. Some tests are using 4.5.1
+# and they select that in the test.
+# Note: GCC_VER is declared as on option and not a variable ('=' instead of ':=')
+# This is important. A variable is used only in the config file and if it is set
+# it stays that way for the rest of the config file until it is change again.
+# Here we want GCC_VER to remain persistent and change for each test, as it is used in
+# the MAKE_CMD. By using '=' instead of ':=' we achieve our goal.
+
+GCC_VER = 4.5.2
+MAKE_CMD = PATH=/usr/local/gcc-${GCC_VER}-nolibc/${CROSS}/bin:$PATH CROSS_COMPILE=${CROSS}- make ARCH=${ARCH}
+
+# all tests are only doing builds.
+TEST_TYPE = build
+
+# If you want to add configs on top of the defconfig, you can add those configs into
+# the add-config file and uncomment this option. This is useful if you want to test
+# all cross compiles with PREEMPT set, or TRACING on, etc.
+#ADD_CONFIG = ${THIS_DIR}/add-config
+
+# All tests are using defconfig
+BUILD_TYPE = defconfig
+
+# The test names will have the arch and cross compiler used. This will be shown in
+# the results.
+TEST_NAME = ${ARCH} ${CROSS}
+
+# alpha
+TEST_START IF ${RUN} == alpha || ${DO_DEFAULT}
+# Notice that CROSS and ARCH are also options and not variables (again '=' instead
+# of ':='). This is because TEST_NAME and MAKE_CMD wil use them for each test.
+# Only options are available during runs. Variables are only present in parsing the
+# config file.
+CROSS = alpha-linux
+ARCH = alpha
+
+# arm
+TEST_START IF ${RUN} == arm || ${DO_DEFAULT}
+CROSS = arm-unknown-linux-gnueabi
+ARCH = arm
+
+# black fin
+TEST_START IF ${RUN} == bfin || ${DO_DEFAULT}
+CROSS = bfin-uclinux
+ARCH = blackfin
+BUILD_OPTIONS = -j8 vmlinux
+
+# cris - FAILS?
+TEST_START IF ${RUN} == cris || ${RUN} == cris64 || ${DO_FAILED}
+CROSS = cris-linux
+ARCH = cris
+
+# cris32 - not right arch?
+TEST_START IF ${RUN} == cris || ${RUN} == cris32 || ${DO_FAILED}
+CROSS = crisv32-linux
+ARCH = cris
+
+# ia64
+TEST_START IF ${RUN} == ia64 || ${DO_DEFAULT}
+CROSS = ia64-linux
+ARCH = ia64
+
+# frv
+TEST_START IF ${RUN} == frv || ${DO_FAILED}
+CROSS = frv-linux
+ARCH = frv
+GCC_VER = 4.5.1
+
+# h8300 - failed make defconfig??
+TEST_START IF ${RUN} == h8300 || ${DO_FAILED}
+CROSS = h8300-elf
+ARCH = h8300
+GCC_VER = 4.5.1
+
+# m68k fails with error?
+TEST_START IF ${RUN} == m68k || ${DO_DEFAULT}
+CROSS = m68k-linux
+ARCH = m68k
+
+# mips64
+TEST_START IF ${RUN} == mips || ${RUN} == mips64 || ${DO_DEFAULT}
+CROSS = mips64-linux
+ARCH = mips
+
+# mips32
+TEST_START IF ${RUN} == mips || ${RUN} == mips32 || ${DO_DEFAULT}
+CROSS = mips-linux
+ARCH = mips
+
+# m32r
+TEST_START IF ${RUN} == m32r || ${DO_FAILED}
+CROSS = m32r-linux
+ARCH = m32r
+GCC_VER = 4.5.1
+BUILD_OPTIONS = -j8 vmlinux
+
+# parisc64 failed?
+TEST_START IF ${RUN} == hppa || ${RUN} == hppa64 || ${DO_FAILED}
+CROSS = hppa64-linux
+ARCH = parisc
+
+# parisc
+TEST_START IF ${RUN} == hppa || ${RUN} == hppa32 || ${DO_FAILED}
+CROSS = hppa-linux
+ARCH = parisc
+
+# ppc
+TEST_START IF ${RUN} == ppc || ${RUN} == ppc32 || ${DO_DEFAULT}
+CROSS = powerpc-linux
+ARCH = powerpc
+
+# ppc64
+TEST_START IF ${RUN} == ppc || ${RUN} == ppc64 || ${DO_DEFAULT}
+CROSS = powerpc64-linux
+ARCH = powerpc
+
+# s390
+TEST_START IF ${RUN} == s390 || ${DO_DEFAULT}
+CROSS = s390x-linux
+ARCH = s390
+
+# sh
+TEST_START IF ${RUN} == sh || ${DO_DEFAULT}
+CROSS = sh4-linux
+ARCH = sh
+
+# sparc64
+TEST_START IF ${RUN} == sparc || ${RUN} == sparc64 || ${DO_DEFAULT}
+CROSS = sparc64-linux
+ARCH = sparc64
+
+# sparc
+TEST_START IF ${RUN} == sparc || ${RUN} == sparc32 || ${DO_DEFAULT}
+CROSS = sparc-linux
+ARCH = sparc
+
+# xtensa failed
+TEST_START IF ${RUN} == xtensa || ${DO_FAILED}
+CROSS = xtensa-linux
+ARCH = xtensa
+
+# UML
+TEST_START IF ${RUN} == uml || ${DO_DEFAULT}
+MAKE_CMD = make ARCH=um SUBARCH=x86_64
+ARCH = uml
+CROSS =
+
+TEST_START IF ${RUN} == x86 || ${RUN} == i386 || ${DO_DEFAULT}
+MAKE_CMD = make ARCH=i386
+ARCH = i386
+CROSS = 
+
+TEST_START IF ${RUN} == x86 || ${RUN} == x86_64 || ${DO_DEFAULT}
+MAKE_CMD = make ARCH=x86_64
+ARCH = x86_64
+CROSS = 
+
+#################################
+
+# This is a bisect if needed. You need to give it a MIN_CONFIG that
+# will be the config file it uses. Basically, just copy the created defconfig
+# for the arch someplace and point MIN_CONFIG to it.
+TEST_START IF ${RUN} == bisect
+MIN_CONFIG = ${THIS_DIR}/min-config
+CROSS = s390x-linux
+ARCH = s390
+TEST_TYPE = bisect
+BISECT_TYPE = build
+BISECT_GOOD = v3.1
+BISECT_BAD = v3.2
+CHECKOUT = v3.2
+
+#################################
+
+# These defaults are needed to keep ktest.pl from complaining. They are
+# ignored because the test does not go pass the build. No install or
+# booting of the target images.
+
+DEFAULTS
+MACHINE = crosstest
+SSH_USER = root
+BUILD_TARGET = cross
+TARGET_IMAGE = image
+POWER_CYCLE = cycle
+CONSOLE = console
+LOCALVERSION = version
+GRUB_MENU = grub
+
+REBOOT_ON_ERROR = 0
+POWEROFF_ON_ERROR = 0
+POWEROFF_ON_SUCCESS = 0
+REBOOT_ON_SUCCESS = 0
+
diff --git a/tools/testing/ktest/examples/include/bisect.conf b/tools/testing/ktest/examples/include/bisect.conf
new file mode 100644
index 0000000..009bea6
--- /dev/null
+++ b/tools/testing/ktest/examples/include/bisect.conf
@@ -0,0 +1,90 @@
+#
+# This example shows the bisect tests (git bisect and config bisect)
+#
+
+
+# The config that includes this file may define a RUN_TEST
+# variable that will tell this config what test to run.
+# (what to set the TEST option to).
+#
+DEFAULTS IF NOT DEFINED RUN_TEST
+# Requires that hackbench is in the PATH
+RUN_TEST := ${SSH} hackbench 50
+
+
+# Set TEST to 'bisect' to do a normal git bisect. You need
+# to modify the options below to make it bisect the exact
+# commits you are interested in.
+#
+TEST_START IF ${TEST} == bisect
+TEST_TYPE = bisect
+# You must set the commit that was considered good (git bisect good)
+BISECT_GOOD = v3.3
+# You must set the commit that was considered bad (git bisect bad)
+BISECT_BAD = HEAD
+# It's best to specify the branch to checkout before starting the bisect.
+CHECKOUT = origin/master
+# This can be build, boot, or test. Here we are doing a bisect
+# that requires to run a test to know if the bisect was good or bad.
+# The test should exit with 0 on good, non-zero for bad. But see
+# the BISECT_RET_* options in samples.conf to override this.
+BISECT_TYPE = test
+TEST = ${RUN_TEST}
+# It is usually a good idea to confirm that the GOOD and the BAD
+# commits are truly good and bad respectively. Having BISECT_CHECK
+# set to 1 will check both that the good commit works and the bad
+# commit fails. If you only want to check one or the other,
+# set BISECT_CHECK to 'good' or to 'bad'.
+BISECT_CHECK = 1
+#BISECT_CHECK = good
+#BISECT_CHECK = bad
+
+# Usually it's a good idea to specify the exact config you
+# want to use throughout the entire bisect. Here we placed
+# it in the directory we called ktest.pl from and named it
+# 'config-bisect'.
+MIN_CONFIG = ${THIS_DIR}/config-bisect
+# By default, if we are doing a BISECT_TYPE = test run but the
+# build or boot fails, ktest.pl will do a 'git bisect skip'.
+# Uncomment the below option to make ktest stop testing on such
+# an error.
+#BISECT_SKIP = 0
+# Now if you had BISECT_SKIP = 0 and the test fails, you can
+# examine what happened and then do 'git bisect log > /tmp/replay'
+# Set BISECT_REPLAY to /tmp/replay and ktest.pl will run the
+# 'git bisect replay /tmp/replay' before continuing the bisect test.
+#BISECT_REPLAY = /tmp/replay
+# If you used BISECT_REPLAY after the bisect test failed, you may
+# not want to continue the bisect on that commit that failed.
+# By setting BISECT_START to a new commit. ktest.pl will checkout
+# that commit after it has performed the 'git bisect replay' but
+# before it continues running the bisect test.
+#BISECT_START = 2545eb6198e7e1ec50daa0cfc64a4cdfecf24ec9
+
+# Now if you don't trust ktest.pl to make the decisions for you, then
+# set BISECT_MANUAL to 1. This will cause ktest.pl not to decide
+# if the commit was good or bad. Instead, it will ask you to tell
+# it if the current commit was good. In the mean time, you could
+# take the result, load it on any machine you want. Run several tests,
+# or whatever you feel like. Then, when you are happy, you can tell
+# ktest if you think it was good or not and ktest.pl will continue
+# the git bisect. You can even change what commit it is currently at.
+#BISECT_MANUAL = 1
+
+
+# One of the unique tests that ktest does is the config bisect.
+# Currently (which hopefully will be fixed soon), the bad config
+# must be a superset of the good config. This is because it only
+# searches for a config that causes the target to fail. If the
+# good config is not a subset of the bad config, or if the target
+# fails because of a lack of a config, then it will not find
+# the config for you.
+TEST_START IF ${TEST} == config-bisect
+TEST_TYPE = config_bisect
+# set to build, boot, test
+CONFIG_BISECT_TYPE = boot
+# Set the config that is considered bad.
+CONFIG_BISECT = ${THIS_DIR}/config-bad
+# This config is optional. By default it uses the
+# MIN_CONFIG as the good config.
+CONFIG_BISECT_GOOD = ${THIS_DIR}/config-good
diff --git a/tools/testing/ktest/examples/include/defaults.conf b/tools/testing/ktest/examples/include/defaults.conf
new file mode 100644
index 0000000..323a552c
--- /dev/null
+++ b/tools/testing/ktest/examples/include/defaults.conf
@@ -0,0 +1,157 @@
+# This file holds defaults for most the tests. It defines the options that
+# are most common to tests that are likely to be shared.
+#
+# Note, after including this file, a config file may override any option
+# with a DEFAULTS OVERRIDE section.
+#
+
+# For those cases that use the same machine to boot a 64 bit
+# and a 32 bit version. The MACHINE is the DNS name to get to the
+# box (usually different if it was 64 bit or 32 bit) but the
+# BOX here is defined as a variable that will be the name of the box
+# itself. It is useful for calling scripts that will power cycle
+# the box, as only one script needs to be created to power cycle
+# even though the box itself has multiple operating systems on it.
+# By default, BOX and MACHINE are the same.
+
+DEFAULTS IF NOT DEFINED BOX
+BOX := ${MACHINE}
+
+
+# Consider each box as 64 bit box, unless the config including this file
+# has defined BITS = 32
+
+DEFAULTS IF NOT DEFINED BITS
+BITS := 64
+
+
+DEFAULTS
+
+# THIS_DIR is used through out the configs and defaults to ${PWD} which
+# is the directory that ktest.pl was called from.
+
+THIS_DIR := ${PWD}
+
+
+# to orginize your configs, having each machine save their configs
+# into a separate directly is useful.
+CONFIG_DIR := ${THIS_DIR}/configs/${MACHINE}
+
+# Reset the log before running each test.
+CLEAR_LOG = 1
+
+# As installing kernels usually requires root privilege, default the
+# user on the target as root. It is also required that the target
+# allows ssh to root from the host without asking for a password.
+
+SSH_USER = root
+
+# For accesing the machine, we will ssh to root@machine.
+SSH := ssh ${SSH_USER}@${MACHINE}
+
+# Update this. The default here is ktest will ssh to the target box
+# and run a script called 'run-test' located on that box.
+TEST = ${SSH} run-test
+
+# Point build dir to the git repo you use
+BUILD_DIR = ${THIS_DIR}/linux.git
+
+# Each machine will have its own output build directory.
+OUTPUT_DIR = ${THIS_DIR}/build/${MACHINE}
+
+# Yes this config is focused on x86 (but ktest works for other archs too)
+BUILD_TARGET = arch/x86/boot/bzImage
+TARGET_IMAGE = /boot/vmlinuz-test
+
+# have directory for the scripts to reboot and power cycle the boxes
+SCRIPTS_DIR := ${THIS_DIR}/scripts
+
+# You can have each box/machine have a script to power cycle it.
+# Name your script <box>-cycle.
+POWER_CYCLE = ${SCRIPTS_DIR}/${BOX}-cycle
+
+# This script is used to power off the box.
+POWER_OFF = ${SCRIPTS_DIR}/${BOX}-poweroff
+
+# Keep your test kernels separate from your other kernels.
+LOCALVERSION = -test
+
+# The /boot/grub/menu.lst is searched for the line:
+#  title Test Kernel
+# and ktest will use that kernel to reboot into.
+# For grub2 or other boot loaders, you need to set BOOT_TYPE
+# to 'script' and define other ways to load the kernel.
+# See snowball.conf example.
+#
+GRUB_MENU = Test Kernel
+
+# The kernel build will use this option.
+BUILD_OPTIONS = -j8
+
+# Keeping the log file with the output dir is convenient.
+LOG_FILE = ${OUTPUT_DIR}/${MACHINE}.log
+
+# Each box should have their own minum configuration
+# See min-config.conf
+MIN_CONFIG = ${CONFIG_DIR}/config-min
+
+# For things like randconfigs, there may be configs you find that
+# are already broken, or there may be some configs that you always
+# want set. Uncomment ADD_CONFIG and point it to the make config files
+# that set the configs you want to keep on (or off) in your build.
+# ADD_CONFIG is usually something to add configs to all machines,
+# where as, MIN_CONFIG is specific per machine.
+#ADD_CONFIG = ${THIS_DIR}/config-broken ${THIS_DIR}/config-general
+
+# To speed up reboots for bisects and patchcheck, instead of
+# waiting 60 seconds for the console to be idle, if this line is
+# seen in the console output, ktest will know the good kernel has
+# finished rebooting and it will be able to continue the tests.
+REBOOT_SUCCESS_LINE = ${MACHINE} login:
+
+# The following is different ways to end the test.
+# by setting the variable REBOOT to: none, error, fail or
+# something else, ktest will power cycle or reboot the target box
+# at the end of the tests.
+#
+# REBOOT := none
+#   Don't do anything at the end of the test.
+#
+# REBOOT := error
+#   Reboot the box if ktest detects an error
+#
+# REBOOT := fail
+#   Do not stop on failure, and after all tests are complete
+#   power off the box (for both success and error)
+#   This is good to run over a weekend and you don't want to waste
+#   electricity.
+#
+
+DEFAULTS IF ${REBOOT} == none
+REBOOT_ON_SUCCESS = 0
+REBOOT_ON_ERROR = 0
+POWEROFF_ON_ERROR = 0
+POWEROFF_ON_SUCCESS = 0
+
+DEFAULTS ELSE IF ${REBOOT} == error
+REBOOT_ON_SUCCESS = 0
+REBOOT_ON_ERROR = 1
+POWEROFF_ON_ERROR = 0
+POWEROFF_ON_SUCCESS = 0
+
+DEFAULTS ELSE IF ${REBOOT} == fail
+REBOOT_ON_SUCCESS = 0
+POWEROFF_ON_ERROR = 1
+POWEROFF_ON_SUCCESS = 1
+POWEROFF_AFTER_HALT = 120
+DIE_ON_FAILURE = 0
+
+# Store the failure information into this directory
+# such as the .config, dmesg, and build log.
+STORE_FAILURES = ${THIS_DIR}/failures
+
+DEFAULTS ELSE
+REBOOT_ON_SUCCESS = 1
+REBOOT_ON_ERROR = 1
+POWEROFF_ON_ERROR = 0
+POWEROFF_ON_SUCCESS = 0
diff --git a/tools/testing/ktest/examples/include/min-config.conf b/tools/testing/ktest/examples/include/min-config.conf
new file mode 100644
index 0000000..c703cc4
--- /dev/null
+++ b/tools/testing/ktest/examples/include/min-config.conf
@@ -0,0 +1,60 @@
+#
+# This file has some examples for creating a MIN_CONFIG.
+# (A .config file that is the minimum for a machine to boot, or
+#  to boot and make a network connection.)
+#
+# A MIN_CONFIG is very useful as it is the minimum configuration
+# needed to boot a given machine. You can debug someone else's
+# .config by only setting the configs in your MIN_CONFIG. The closer
+# your MIN_CONFIG is to the true minimum set of configs needed to
+# boot your machine, the closer the config you test with will be
+# to the users config that had the failure.
+#
+# The make_min_config test allows you to create a MIN_CONFIG that
+# is truly the minimum set of configs needed to boot a box.
+#
+# In this example, the final config will reside in
+# ${CONFIG_DIR}/config-new-min and ${CONFIG_DIR}/config-new-min-net.
+# Just move one to the location you have set for MIN_CONFIG.
+#
+# The first test creates a MIN_CONFIG that will be the minimum
+# configuration to boot ${MACHINE} and be able to ssh to it.
+#
+# The second test creates a MIN_CONFIG that will only boot
+# the target and most likely will not let you ssh to it. (Notice
+# how the second test uses the first test's result to continue with.
+# This is because the second test config is a subset of the first).
+#
+# The ${CONFIG_DIR}/config-skip (and -net) will hold the configs
+# that ktest.pl found would not boot the target without them set.
+# The config-new-min holds configs that ktest.pl could not test
+# directly because another config that was needed to boot the box
+# selected them. Sometimes it is possible that this file will hold
+# the true minimum configuration. You can test to see if this is
+# the case by running the boot test with BOOT_TYPE = allnoconfig and
+# setting setting the MIN_CONFIG to ${CONFIG_DIR}/config-skip. If the
+# machine still boots, then you can use the config-skip as your MIN_CONFIG.
+#
+# These tests can run for several hours (and perhaps days).
+# It's OK to kill the test with a Ctrl^C. By restarting without
+# modifying this config, ktest.pl will notice that the config-new-min(-net)
+# exists, and will use that instead as the starting point.
+# The USE_OUTPUT_MIN_CONFIG is set to 1 to keep ktest.pl from asking
+# you if you want to use the OUTPUT_MIN_CONFIG as the starting point.
+# By using the OUTPUT_MIN_CONFIG as the starting point will allow ktest.pl to
+# start almost where it left off.
+#
+TEST_START IF ${TEST} == min-config
+TEST_TYPE = make_min_config
+OUTPUT_MIN_CONFIG = ${CONFIG_DIR}/config-new-min-net
+IGNORE_CONFIG = ${CONFIG_DIR}/config-skip-net
+MIN_CONFIG_TYPE = test
+TEST = ${SSH} echo hi
+USE_OUTPUT_MIN_CONFIG = 1
+
+TEST_START IF ${TEST} == min-config && ${MULTI}
+TEST_TYPE = make_min_config
+OUTPUT_MIN_CONFIG = ${CONFIG_DIR}/config-new-min
+IGNORE_CONFIG = ${CONFIG_DIR}/config-skip
+MIN_CONFIG = ${CONFIG_DIR}/config-new-min-net
+USE_OUTPUT_MIN_CONFIG = 1
diff --git a/tools/testing/ktest/examples/include/patchcheck.conf b/tools/testing/ktest/examples/include/patchcheck.conf
new file mode 100644
index 0000000..339d3e1
--- /dev/null
+++ b/tools/testing/ktest/examples/include/patchcheck.conf
@@ -0,0 +1,74 @@
+# patchcheck.conf
+#
+# This contains a test that takes two git commits and will test each
+# commit between the two. The build test will look at what files the
+# commit has touched, and if any of those files produce a warning, then
+# the build will fail.
+
+
+# PATCH_START is the commit to begin with and PATCH_END is the commit
+# to end with (inclusive). This is similar to doing a git rebase -i PATCH_START~1
+# and then testing each commit and doing a git rebase --continue.
+# You can use a SHA1, a git tag, or anything that git will accept for a checkout
+
+PATCH_START := HEAD~3
+PATCH_END := HEAD
+
+# Change PATCH_CHECKOUT to be the branch you want to test. The test will
+# do a git checkout of this branch before starting. Obviously both
+# PATCH_START and PATCH_END must be in this branch (and PATCH_START must
+# be contained by PATCH_END).
+
+PATCH_CHECKOUT := test/branch
+
+# Usually it's a good idea to have a set config to use for testing individual
+# patches.
+PATCH_CONFIG := ${CONFIG_DIR}/config-patchcheck
+
+# Change PATCH_TEST to run some test for each patch. Each commit that is
+# tested, after it is built and installed on the test machine, this command
+# will be executed. Usually what is done is to ssh to the target box and
+# run some test scripts. If you just want to boot test your patches
+# comment PATCH_TEST out.
+PATCH_TEST := ${SSH} "/usr/local/bin/ktest-test-script"
+
+DEFAULTS IF DEFINED PATCH_TEST
+PATCH_TEST_TYPE := test
+
+DEFAULTS ELSE
+PATCH_TEST_TYPE := boot
+
+# If for some reason a file has a warning that one of your patches touch
+# but you do not care about it, set IGNORE_WARNINGS to that commit(s)
+# (space delimited)
+#IGNORE_WARNINGS = 39eaf7ef884dcc44f7ff1bac803ca2a1dcf43544 6edb2a8a385f0cdef51dae37ff23e74d76d8a6ce
+
+# If you are running a multi test, and the test failed on the first
+# test but on, say the 5th patch. If you want to restart on the
+# fifth patch, set PATCH_START1. This will make the first test start
+# from this commit instead of the PATCH_START commit.
+# Note, do not change this option. Just define PATCH_START1 in the
+# top config (the one you pass to ktest.pl), and this will use it,
+# otherwise it will just use PATCH_START if PATCH_START1 is not defined.
+DEFAULTS IF NOT DEFINED PATCH_START1
+PATCH_START1 := ${PATCH_START}
+
+TEST_START IF ${TEST} == patchcheck
+TEST_TYPE = patchcheck
+MIN_CONFIG = ${PATCH_CONFIG}
+TEST = ${PATCH_TEST}
+PATCHCHECK_TYPE = ${PATCH_TEST_TYPE}
+PATCHCHECK_START = ${PATCH_START1}
+PATCHCHECK_END = ${PATCH_END}
+CHECKOUT = ${PATCH_CHECKOUT}
+
+TEST_START IF ${TEST} == patchcheck && ${MULTI}
+TEST_TYPE = patchcheck
+MIN_CONFIG = ${PATCH_CONFIG}
+TEST = ${PATCH_TEST}
+PATCHCHECK_TYPE = ${PATCH_TEST_TYPE}
+PATCHCHECK_START = ${PATCH_START}
+PATCHCHECK_END = ${PATCH_END}
+CHECKOUT = ${PATCH_CHECKOUT}
+# Use multi to test different compilers?
+MAKE_CMD = CC=gcc-4.5.1 make
diff --git a/tools/testing/ktest/examples/include/tests.conf b/tools/testing/ktest/examples/include/tests.conf
new file mode 100644
index 0000000..4fdb811
--- /dev/null
+++ b/tools/testing/ktest/examples/include/tests.conf
@@ -0,0 +1,74 @@
+#
+# This is an example of various tests that you can run
+#
+# The variable TEST can be of boot, build, randconfig, or test.
+#
+# Note that TEST is a variable created with ':=' and only exists
+# throughout the config processing (not during the tests itself).
+#
+# The TEST option (defined with '=') is used to tell ktest.pl
+# what test to run after a successful boot. The TEST option is
+# persistent into the test runs.
+#
+
+# The config that includes this file may define a BOOT_TYPE
+# variable that tells this config what type of boot test to run.
+# If it's not defined, the below DEFAULTS will set the default
+# to 'oldconfig'.
+#
+DEFAULTS IF NOT DEFINED BOOT_TYPE
+BOOT_TYPE := oldconfig
+
+# The config that includes this file may define a RUN_TEST
+# variable that will tell this config what test to run.
+# (what to set the TEST option to).
+#
+DEFAULTS IF NOT DEFINED RUN_TEST
+# Requires that hackbench is in the PATH
+RUN_TEST := ${SSH} hackbench 50
+
+
+# If TEST is set to 'boot' then just build a kernel and boot
+# the target.
+TEST_START IF ${TEST} == boot
+TEST_TYPE = boot
+# Notice how we set the BUILD_TYPE option to the BOOT_TYPE variable.
+BUILD_TYPE = ${BOOT_TYPE}
+# Do not do a make mrproper.
+BUILD_NOCLEAN = 1
+
+# If you only want to build the kernel, and perhaps install
+# and test it yourself, then just set TEST to build.
+TEST_START IF ${TEST} == build
+TEST_TYPE = build
+BUILD_TYPE = ${BOOT_TYPE}
+BUILD_NOCLEAN = 1
+
+# Build, install, boot and test with a randconfg 10 times.
+# It is important that you have set MIN_CONFIG in the config
+# that includes this file otherwise it is likely that the
+# randconfig will not have the neccessary configs needed to
+# boot your box. This version of the test requires a min
+# config that has enough to make sure the target has network
+# working.
+TEST_START ITERATE 10 IF ${TEST} == randconfig
+MIN_CONFIG = ${CONFIG_DIR}/config-min-net
+TEST_TYPE = test
+BUILD_TYPE = randconfig
+TEST = ${RUN_TEST}
+
+# This is the same as above, but only tests to a boot prompt.
+# The MIN_CONFIG used here does not need to have networking
+# working.
+TEST_START ITERATE 10 IF ${TEST} == randconfig && ${MULTI}
+TEST_TYPE = boot
+BUILD_TYPE = randconfig
+MIN_CONFIG = ${CONFIG_DIR}/config-min
+MAKE_CMD = make
+
+# This builds, installs, boots and tests the target.
+TEST_START IF ${TEST} == test
+TEST_TYPE = test
+BUILD_TYPE = ${BOOT_TYPE}
+TEST = ${RUN_TEST}
+BUILD_NOCLEAN = 1
diff --git a/tools/testing/ktest/examples/kvm.conf b/tools/testing/ktest/examples/kvm.conf
new file mode 100644
index 0000000..831c7c5
--- /dev/null
+++ b/tools/testing/ktest/examples/kvm.conf
@@ -0,0 +1,88 @@
+#
+# This config is an example usage of ktest.pl with a kvm guest
+#
+# The guest is called 'Guest' and this would be something that
+# could be run on the host to test a virtual machine target.
+
+MACHINE = Guest
+
+
+# Use virsh to read the serial console of the guest
+CONSOLE =  virsh console ${MACHINE}
+
+#*************************************#
+# This part is the same as test.conf  #
+#*************************************#
+
+# The include files will set up the type of test to run. Just set TEST to
+# which test you want to run.
+#
+# TESTS = patchcheck, randconfig, boot, test, config-bisect, bisect, min-config
+#
+# See the include/*.conf files that define these tests
+#
+TEST := patchcheck
+
+# Some tests may have more than one test to run. Define MULTI := 1 to run
+# the extra tests.
+MULTI := 0
+
+# In case you want to differentiate which type of system you are testing
+BITS := 64
+
+# REBOOT = none, error, fail, empty
+#  See include/defaults.conf
+REBOOT := empty
+
+
+# The defaults file will set up various settings that can be used by all
+# machine configs.
+INCLUDE include/defaults.conf
+
+
+#*************************************#
+# Now we are different from test.conf #
+#*************************************#
+
+
+# The example here assumes that Guest is running a Fedora release
+# that uses dracut for its initfs. The POST_INSTALL will be executed
+# after the install of the kernel and modules are complete.
+#
+POST_INSTALL = ${SSH} /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
+
+# Guests sometimes get stuck on reboot. We wait 3 seconds after running
+# the reboot command and then  do a full power-cycle of the guest.
+# This forces the guest to restart.
+#
+POWERCYCLE_AFTER_REBOOT = 3
+
+# We do the same after the halt command, but this time we wait 20 seconds.
+POWEROFF_AFTER_HALT = 20
+
+
+# As the defaults.conf file has a POWER_CYCLE option already defined,
+# and options can not be defined in the same section more than once
+# (all DEFAULTS sections are considered the same). We use the
+# DEFAULTS OVERRIDE to tell ktest.pl to ignore the previous defined
+# options, for the options set in the OVERRIDE section.
+#
+DEFAULTS OVERRIDE
+
+# Instead of using the default POWER_CYCLE option defined in
+# defaults.conf, we use virsh to cycle it. To do so, we destroy
+# the guest, wait 5 seconds, and then start it up again.
+# Crude, but effective.
+#
+POWER_CYCLE = virsh destroy ${MACHINE}; sleep 5; virsh start ${MACHINE}
+
+
+DEFAULTS
+
+# The following files each handle a different test case.
+# Having them included allows you to set up more than one machine and share
+# the same tests.
+INCLUDE include/patchcheck.conf
+INCLUDE include/tests.conf
+INCLUDE include/bisect.conf
+INCLUDE include/min-config.conf
diff --git a/tools/testing/ktest/examples/snowball.conf b/tools/testing/ktest/examples/snowball.conf
new file mode 100644
index 0000000..a82a3c5
--- /dev/null
+++ b/tools/testing/ktest/examples/snowball.conf
@@ -0,0 +1,53 @@
+# This example was used to boot the snowball ARM board.
+# See http://people.redhat.com/srostedt/ktest-embedded-2012/
+
+# PWD is a ktest.pl variable that will result in the process working
+# directory that ktest.pl is executed in.
+
+# THIS_DIR is automatically assigned the PWD of the path that generated
+# the config file. It is best to use this variable when assigning other
+# directory paths within this directory. This allows you to easily
+# move the test cases to other locations or to other machines.
+#
+THIS_DIR := /home/rostedt/work/demo/ktest-embed
+LOG_FILE = ${OUTPUT_DIR}/snowball.log
+CLEAR_LOG = 1
+MAKE_CMD = PATH=/usr/local/gcc-4.5.2-nolibc/arm-unknown-linux-gnueabi/bin:$PATH CROSS_COMPILE=arm-unknown-linux-gnueabi- make ARCH=arm
+ADD_CONFIG = ${THIS_DIR}/addconfig
+
+SCP_TO_TARGET = echo "don't do scp"
+
+TFTPBOOT := /var/lib/tftpboot
+TFTPDEF := ${TFTPBOOT}/snowball-default
+TFTPTEST := ${OUTPUT_DIR}/${BUILD_TARGET}
+
+SWITCH_TO_GOOD = cp ${TFTPDEF} ${TARGET_IMAGE}
+SWITCH_TO_TEST = cp ${TFTPTEST} ${TARGET_IMAGE}
+
+# Define each test with TEST_START
+# The config options below it will override the defaults
+TEST_START SKIP
+TEST_TYPE = boot
+BUILD_TYPE = u8500_defconfig
+BUILD_NOCLEAN = 1
+
+TEST_START
+TEST_TYPE = make_min_config
+OUTPUT_MIN_CONFIG = ${THIS_DIR}/config.newmin
+START_MIN_CONFIG = ${THIS_DIR}/config.orig
+IGNORE_CONFIG = ${THIS_DIR}/config.ignore
+BUILD_NOCLEAN = 1
+
+
+DEFAULTS
+LOCALVERSION = -test
+POWER_CYCLE = echo use the thumb luke; read a
+CONSOLE = cat ${THIS_DIR}/snowball-cat
+REBOOT_TYPE = script
+SSH_USER = root
+BUILD_OPTIONS = -j8 uImage
+BUILD_DIR = ${THIS_DIR}/linux.git
+OUTPUT_DIR = ${THIS_DIR}/snowball-build
+MACHINE = snowball
+TARGET_IMAGE = /var/lib/tftpboot/snowball-image
+BUILD_TARGET = arch/arm/boot/uImage
diff --git a/tools/testing/ktest/examples/test.conf b/tools/testing/ktest/examples/test.conf
new file mode 100644
index 0000000..b725210
--- /dev/null
+++ b/tools/testing/ktest/examples/test.conf
@@ -0,0 +1,62 @@
+#
+# Generic config for a machine
+#
+
+# Name your machine (the DNS name, what you ssh to)
+MACHINE = foo
+
+# BOX can be different than foo, if the machine BOX has
+# multiple partitions with different systems installed. For example,
+# you may have a i386 and x86_64 installation on a test box.
+# If this is the case, MACHINE defines the way to connect to the
+# machine, which may be different between which system the machine
+# is booting into. BOX is used for the scripts to reboot and power cycle
+# the machine, where it does not matter which system the machine boots into.
+#
+#BOX := bar
+
+# Define a way to read the console
+CONSOLE = stty -F /dev/ttyS0 115200 parodd; cat /dev/ttyS0
+
+# The include files will set up the type of test to run. Just set TEST to
+# which test you want to run.
+#
+# TESTS = patchcheck, randconfig, boot, test, config-bisect, bisect, min-config
+#
+# See the include/*.conf files that define these tests
+#
+TEST := patchcheck
+
+# Some tests may have more than one test to run. Define MULTI := 1 to run
+# the extra tests.
+MULTI := 0
+
+# In case you want to differentiate which type of system you are testing
+BITS := 64
+
+# REBOOT = none, error, fail, empty
+#  See include/defaults.conf
+REBOOT := empty
+
+# The defaults file will set up various settings that can be used by all
+# machine configs.
+INCLUDE include/defaults.conf
+
+# In case you need to add a patch for a bisect or something
+#PRE_BUILD = patch -p1 < ${THIS_DIR}/fix.patch
+
+# Reset the repo after the build and remove all 'test' modules from the target
+# Notice that DO_POST_BUILD is a variable (defined by ':=') and POST_BUILD
+# is the option (defined by '=')
+
+DO_POST_BUILD := git reset --hard
+POST_BUILD = ${SSH} 'rm -rf /lib/modules/*-test*'; ${DO_POST_BUILD}
+
+# The following files each handle a different test case.
+# Having them included allows you to set up more than one machine and share
+# the same tests.
+INCLUDE include/patchcheck.conf
+INCLUDE include/tests.conf
+INCLUDE include/bisect.conf
+INCLUDE include/min-config.conf
+
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 4915408..292b13a 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -39,6 +39,7 @@
     "CLEAR_LOG"			=> 0,
     "BISECT_MANUAL"		=> 0,
     "BISECT_SKIP"		=> 1,
+    "MIN_CONFIG_TYPE"		=> "boot",
     "SUCCESS_LINE"		=> "login:",
     "DETECT_TRIPLE_FAULT"	=> 1,
     "NO_INSTALL"		=> 0,
@@ -66,6 +67,7 @@
 
 my $ktest_config;
 my $version;
+my $have_version = 0;
 my $machine;
 my $ssh_user;
 my $tmpdir;
@@ -106,6 +108,8 @@
 my $start_minconfig;
 my $start_minconfig_defined;
 my $output_minconfig;
+my $minconfig_type;
+my $use_output_minconfig;
 my $ignore_config;
 my $ignore_errors;
 my $addconfig;
@@ -205,6 +209,8 @@
     "MIN_CONFIG"		=> \$minconfig,
     "OUTPUT_MIN_CONFIG"		=> \$output_minconfig,
     "START_MIN_CONFIG"		=> \$start_minconfig,
+    "MIN_CONFIG_TYPE"		=> \$minconfig_type,
+    "USE_OUTPUT_MIN_CONFIG"	=> \$use_output_minconfig,
     "IGNORE_CONFIG"		=> \$ignore_config,
     "TEST"			=> \$run_test,
     "ADD_CONFIG"		=> \$addconfig,
@@ -1702,10 +1708,12 @@
 
 sub get_version {
     # get the release name
+    return if ($have_version);
     doprint "$make kernelrelease ... ";
     $version = `$make kernelrelease | tail -1`;
     chomp($version);
     doprint "$version\n";
+    $have_version = 1;
 }
 
 sub start_monitor_and_boot {
@@ -1828,6 +1836,9 @@
     my $save_no_reboot = $no_reboot;
     $no_reboot = 1;
 
+    # Calculate a new version from here.
+    $have_version = 0;
+
     if (defined($pre_build)) {
 	my $ret = run_command $pre_build;
 	if (!$ret && defined($pre_build_die) &&
@@ -1887,6 +1898,9 @@
     undef $redirect;
 
     if (defined($post_build)) {
+	# Because a post build may change the kernel version
+	# do it now.
+	get_version;
 	my $ret = run_command $post_build;
 	if (!$ret && defined($post_build_die) &&
 	    $post_build_die) {
@@ -3119,6 +3133,12 @@
 sub make_min_config {
     my ($i) = @_;
 
+    my $type = $minconfig_type;
+    if ($type ne "boot" && $type ne "test") {
+	fail "Invalid MIN_CONFIG_TYPE '$minconfig_type'\n" .
+	    " make_min_config works only with 'boot' and 'test'\n" and return;
+    }
+
     if (!defined($output_minconfig)) {
 	fail "OUTPUT_MIN_CONFIG not defined" and return;
     }
@@ -3128,8 +3148,15 @@
     # that instead.
     if (-f $output_minconfig && !$start_minconfig_defined) {
 	print "$output_minconfig exists\n";
-	if (read_yn " Use it as minconfig?") {
+	if (!defined($use_output_minconfig)) {
+	    if (read_yn " Use it as minconfig?") {
+		$start_minconfig = $output_minconfig;
+	    }
+	} elsif ($use_output_minconfig > 0) {
+	    doprint "Using $output_minconfig as MIN_CONFIG\n";
 	    $start_minconfig = $output_minconfig;
+	} else {
+	    doprint "Set to still use MIN_CONFIG as starting point\n";
 	}
     }
 
@@ -3278,6 +3305,11 @@
 	build "oldconfig" or $failed = 1;
 	if (!$failed) {
 		start_monitor_and_boot or $failed = 1;
+
+		if ($type eq "test" && !$failed) {
+		    do_run_test or $failed = 1;
+		}
+
 		end_monitor;
 	}
 
@@ -3474,6 +3506,8 @@
     $no_reboot = 1;
     $reboot_success = 0;
 
+    $have_version = 0;
+
     $iteration = $i;
 
     my $makecmd = set_test_option("MAKE_CMD", $i);
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index b682456..cf362b3 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -158,7 +158,7 @@
 #
 # TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf
 #
-# Notice the use of paranthesis. Without any paranthesis the above would be
+# Notice the use of parentheses. Without any parentheses the above would be
 # processed the same as:
 #
 # TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf)
@@ -1105,10 +1105,26 @@
 #   and will not be tested again in later runs.
 #   (optional)
 #
+#  MIN_CONFIG_TYPE can be either 'boot' or 'test'. With 'boot' it will
+#   test if the created config can just boot the machine. If this is
+#   set to 'test', then the TEST option must be defined and the created
+#   config will not only boot the target, but also make sure that the
+#   config lets the test succeed. This is useful to make sure the final
+#   config that is generated allows network activity (ssh).
+#   (optional)
+#
+#  USE_OUTPUT_MIN_CONFIG set this to 1 if you do not want to be prompted
+#   about using the OUTPUT_MIN_CONFIG as the MIN_CONFIG as the starting
+#   point. Set it to 0 if you want to always just use the given MIN_CONFIG.
+#   If it is not defined, it will prompt you to pick which config
+#   to start with (MIN_CONFIG or OUTPUT_MIN_CONFIG).
+#
 # Example:
 #
 #  TEST_TYPE = make_min_config
 #  OUTPUT_MIN_CONFIG = /path/to/config-new-min
 #  START_MIN_CONFIG = /path/to/config-min
 #  IGNORE_CONFIG = /path/to/config-tested
+#  MIN_CONFIG_TYPE = test
+#  TEST = ssh ${USER}@${MACHINE} echo hi
 #
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index 4b107b5..8674b9e 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -297,7 +297,7 @@
 
 		ret = t->in(t, t->buf, t->buf_size);
 		if (ret > 0) {
-			ret = t->out(t, t->buf, t->buf_size);
+			ret = t->out(t, t->buf, ret);
 			name = out_name;
 			op = "write";
 		} else {
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index 6e0f567..82d7c59 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -358,6 +358,7 @@
 {
 	static char usbfs_path_0[] = "/dev/usb/devices";
 	static char usbfs_path_1[] = "/proc/bus/usb/devices";
+	static char udev_usb_path[] = "/dev/bus/usb";
 
 	static char *const usbfs_paths[] = {
 		usbfs_path_0, usbfs_path_1
@@ -376,6 +377,10 @@
 		}
 	} while (++it != end);
 
+	/* real device-nodes managed by udev */
+	if (access(udev_usb_path, F_OK) == 0)
+		return udev_usb_path;
+
 	return NULL;
 }